From 88c687ea7e1807a9f6376c0246890023b7cd8fb4 Mon Sep 17 00:00:00 2001 From: Denis Rouzaud Date: Fri, 29 Nov 2024 14:26:30 +0100 Subject: [PATCH] run pre-commit on all files --- .ci/ctest2ci.py | 96 +- .ci/pr_has_label.py | 29 +- .../test_runner/qgis_startup.py | 10 +- .../test_runner/qgis_testrunner.py | 61 +- .../actions/vcpkg_update_report/vcpkg-diff.py | 2 +- cmake/FindPyQt5.py | 16 +- cmake/FindPyQt6.py | 14 +- cmake/FindQsci.py | 13 +- cmake/FindSIP.py | 2 +- cmake/PythonCompile.py | 3 +- python/PyQt6/core/additions/edit.py | 6 +- python/PyQt6/core/additions/fromfunction.py | 52 +- python/PyQt6/core/additions/metaenum.py | 8 +- .../core/additions/projectdirtyblocker.py | 5 +- .../PyQt6/core/additions/providermetadata.py | 12 +- python/PyQt6/core/additions/qgsfeature.py | 10 +- python/PyQt6/core/additions/qgsfunction.py | 21 +- python/PyQt6/core/additions/qgsgeometry.py | 2 - python/PyQt6/core/additions/qgssettings.py | 37 +- .../PyQt6/core/additions/qgssettingsentry.py | 55 +- python/PyQt6/core/additions/qgstaskwrapper.py | 5 +- .../readwritecontextentercategory.py | 4 +- .../PyQt6/core/additions/runtimeprofiler.py | 5 +- python/PyQt6/core/additions/validitycheck.py | 7 +- python/PyQt6/core/contextmanagers.py | 8 +- .../qgssettingsenumflageditorwrapper.py | 21 +- python/__init__.py | 26 +- python/console/__init__.py | 8 +- python/console/console.py | 250 +- python/console/console_compile_apis.py | 23 +- python/console/console_editor.py | 556 +- python/console/console_output.py | 139 +- python/console/console_sci.py | 159 +- python/console/console_settings.py | 238 +- python/console/process_wrapper.py | 30 +- python/core/additions/edit.py | 6 +- python/core/additions/fromfunction.py | 52 +- python/core/additions/metaenum.py | 8 +- python/core/additions/projectdirtyblocker.py | 5 +- python/core/additions/providermetadata.py | 12 +- python/core/additions/qgsfeature.py | 16 +- python/core/additions/qgsfunction.py | 21 +- python/core/additions/qgsgeometry.py | 2 - python/core/additions/qgssettings.py | 37 +- python/core/additions/qgssettingsentry.py | 55 +- python/core/additions/qgstaskwrapper.py | 5 +- .../readwritecontextentercategory.py | 4 +- python/core/additions/runtimeprofiler.py | 5 +- python/core/additions/validitycheck.py | 7 +- python/core/contextmanagers.py | 8 +- python/custom_widgets/qgis_customwidgets.py | 5 +- .../qgssettingsenumflageditorwrapper.py | 21 +- python/plugins/MetaSearch/__init__.py | 1 + .../plugins/MetaSearch/dialogs/apidialog.py | 14 +- .../plugins/MetaSearch/dialogs/maindialog.py | 601 +- .../dialogs/manageconnectionsdialog.py | 102 +- .../MetaSearch/dialogs/newconnectiondialog.py | 54 +- .../MetaSearch/dialogs/recorddialog.py | 2 +- python/plugins/MetaSearch/link_types.py | 57 +- python/plugins/MetaSearch/pavement.py | 144 +- python/plugins/MetaSearch/plugin.py | 33 +- python/plugins/MetaSearch/search_backend.py | 205 +- python/plugins/MetaSearch/util.py | 59 +- python/plugins/db_manager/db_manager.py | 143 +- .../plugins/db_manager/db_manager_plugin.py | 40 +- python/plugins/db_manager/db_model.py | 115 +- .../plugins/db_manager/db_plugins/__init__.py | 11 +- .../db_manager/db_plugins/connector.py | 53 +- .../db_manager/db_plugins/data_model.py | 145 +- .../db_manager/db_plugins/gpkg/connector.py | 320 +- .../db_manager/db_plugins/gpkg/data_model.py | 10 +- .../db_manager/db_plugins/gpkg/info_model.py | 5 +- .../db_manager/db_plugins/gpkg/plugin.py | 109 +- .../db_plugins/gpkg/sql_dictionary.py | 2 + .../db_manager/db_plugins/html_elems.py | 42 +- .../db_manager/db_plugins/info_model.py | 368 +- .../db_manager/db_plugins/oracle/QtSqlDB.py | 31 +- .../db_manager/db_plugins/oracle/connector.py | 599 +- .../db_plugins/oracle/data_model.py | 46 +- .../db_plugins/oracle/info_model.py | 566 +- .../db_manager/db_plugins/oracle/plugin.py | 388 +- .../db_plugins/oracle/sql_dictionary.py | 922 +- .../plugins/db_manager/db_plugins/plugin.py | 679 +- .../db_plugins/postgis/connector.py | 783 +- .../db_plugins/postgis/connector_test.py | 16 +- .../db_plugins/postgis/data_model.py | 26 +- .../db_plugins/postgis/info_model.py | 283 +- .../db_manager/db_plugins/postgis/plugin.py | 219 +- .../db_plugins/postgis/plugin_test.py | 60 +- .../db_plugins/postgis/plugins/__init__.py | 4 +- .../postgis/plugins/qgis_topoview/__init__.py | 193 +- .../postgis/plugins/versioning/__init__.py | 8 +- .../plugins/versioning/dlg_versioning.py | 164 +- .../db_plugins/postgis/sql_dictionary.py | 1002 +- .../db_plugins/spatialite/connector.py | 312 +- .../db_plugins/spatialite/data_model.py | 14 +- .../db_plugins/spatialite/info_model.py | 23 +- .../db_plugins/spatialite/plugin.py | 83 +- .../db_plugins/spatialite/sql_dictionary.py | 414 +- .../db_plugins/vlayers/connector.py | 92 +- .../db_plugins/vlayers/data_model.py | 28 +- .../db_plugins/vlayers/info_model.py | 7 +- .../db_manager/db_plugins/vlayers/plugin.py | 57 +- .../db_plugins/vlayers/sql_dictionary.py | 556 +- python/plugins/db_manager/db_tree.py | 45 +- .../db_manager/dlg_add_geometry_column.py | 23 +- .../db_manager/dlg_create_constraint.py | 8 +- python/plugins/db_manager/dlg_create_index.py | 8 +- python/plugins/db_manager/dlg_create_table.py | 109 +- python/plugins/db_manager/dlg_db_error.py | 4 +- .../plugins/db_manager/dlg_export_vector.py | 72 +- .../db_manager/dlg_field_properties.py | 18 +- .../plugins/db_manager/dlg_import_vector.py | 132 +- .../plugins/db_manager/dlg_query_builder.py | 108 +- .../db_manager/dlg_sql_layer_window.py | 218 +- python/plugins/db_manager/dlg_sql_window.py | 237 +- .../db_manager/dlg_table_properties.py | 122 +- python/plugins/db_manager/gui_utils.py | 29 +- python/plugins/db_manager/info_viewer.py | 44 +- python/plugins/db_manager/layer_preview.py | 30 +- python/plugins/db_manager/sql_dictionary.py | 161 +- python/plugins/db_manager/sqledit.py | 63 +- python/plugins/grassprovider/__init__.py | 7 +- .../grassprovider/description_to_json.py | 24 +- .../grassprovider/ext/g_extension_list.py | 22 +- .../grassprovider/ext/g_extension_manage.py | 6 +- python/plugins/grassprovider/ext/g_version.py | 10 +- python/plugins/grassprovider/ext/i.py | 115 +- python/plugins/grassprovider/ext/i_albedo.py | 21 +- python/plugins/grassprovider/ext/i_cca.py | 17 +- python/plugins/grassprovider/ext/i_cluster.py | 20 +- .../grassprovider/ext/i_colors_enhance.py | 8 +- .../plugins/grassprovider/ext/i_evapo_mh.py | 24 +- python/plugins/grassprovider/ext/i_gensig.py | 18 +- .../plugins/grassprovider/ext/i_gensigset.py | 20 +- python/plugins/grassprovider/ext/i_group.py | 8 +- .../plugins/grassprovider/ext/i_in_spotvgt.py | 8 +- .../grassprovider/ext/i_landsat_acca.py | 11 +- .../grassprovider/ext/i_landsat_toar.py | 13 +- python/plugins/grassprovider/ext/i_maxlik.py | 15 +- python/plugins/grassprovider/ext/i_oif.py | 8 +- .../plugins/grassprovider/ext/i_pansharpen.py | 21 +- python/plugins/grassprovider/ext/i_pca.py | 8 +- python/plugins/grassprovider/ext/i_segment.py | 8 +- python/plugins/grassprovider/ext/i_smap.py | 16 +- python/plugins/grassprovider/ext/i_tasscap.py | 8 +- .../grassprovider/ext/r_blend_combine.py | 12 +- .../plugins/grassprovider/ext/r_blend_rgb.py | 20 +- .../plugins/grassprovider/ext/r_category.py | 43 +- python/plugins/grassprovider/ext/r_colors.py | 54 +- .../grassprovider/ext/r_colors_stddev.py | 17 +- python/plugins/grassprovider/ext/r_drain.py | 31 +- python/plugins/grassprovider/ext/r_horizon.py | 32 +- python/plugins/grassprovider/ext/r_li.py | 91 +- python/plugins/grassprovider/ext/r_li_cwed.py | 6 +- .../grassprovider/ext/r_li_cwed_ascii.py | 6 +- .../grassprovider/ext/r_li_dominance.py | 6 +- .../grassprovider/ext/r_li_dominance_ascii.py | 6 +- .../grassprovider/ext/r_li_edgedensity.py | 6 +- .../ext/r_li_edgedensity_ascii.py | 6 +- python/plugins/grassprovider/ext/r_li_mpa.py | 6 +- .../grassprovider/ext/r_li_mpa_ascii.py | 6 +- python/plugins/grassprovider/ext/r_li_mps.py | 6 +- .../grassprovider/ext/r_li_mps_ascii.py | 6 +- .../plugins/grassprovider/ext/r_li_padcv.py | 6 +- .../grassprovider/ext/r_li_padcv_ascii.py | 6 +- .../grassprovider/ext/r_li_padrange.py | 6 +- .../grassprovider/ext/r_li_padrange_ascii.py | 6 +- .../plugins/grassprovider/ext/r_li_padsd.py | 6 +- .../grassprovider/ext/r_li_padsd_ascii.py | 6 +- .../grassprovider/ext/r_li_patchdensity.py | 6 +- .../ext/r_li_patchdensity_ascii.py | 6 +- .../grassprovider/ext/r_li_patchnum.py | 6 +- .../grassprovider/ext/r_li_patchnum_ascii.py | 6 +- .../plugins/grassprovider/ext/r_li_pielou.py | 6 +- .../grassprovider/ext/r_li_pielou_ascii.py | 6 +- .../plugins/grassprovider/ext/r_li_renyi.py | 6 +- .../grassprovider/ext/r_li_renyi_ascii.py | 6 +- .../grassprovider/ext/r_li_richness.py | 6 +- .../grassprovider/ext/r_li_richness_ascii.py | 6 +- .../plugins/grassprovider/ext/r_li_shannon.py | 6 +- .../grassprovider/ext/r_li_shannon_ascii.py | 6 +- .../plugins/grassprovider/ext/r_li_shape.py | 6 +- .../grassprovider/ext/r_li_shape_ascii.py | 6 +- .../plugins/grassprovider/ext/r_li_simpson.py | 6 +- .../grassprovider/ext/r_li_simpson_ascii.py | 6 +- .../plugins/grassprovider/ext/r_mask_rast.py | 15 +- .../plugins/grassprovider/ext/r_mask_vect.py | 15 +- .../plugins/grassprovider/ext/r_neighbors.py | 10 +- python/plugins/grassprovider/ext/r_null.py | 25 +- python/plugins/grassprovider/ext/r_proj.py | 51 +- python/plugins/grassprovider/ext/r_reclass.py | 25 +- .../grassprovider/ext/r_resamp_filter.py | 18 +- python/plugins/grassprovider/ext/r_rgb.py | 38 +- .../grassprovider/ext/r_series_interp.py | 43 +- python/plugins/grassprovider/ext/r_shade.py | 14 +- .../plugins/grassprovider/ext/r_statistics.py | 23 +- .../ext/r_stats_quantile_rast.py | 23 +- python/plugins/grassprovider/ext/r_tileset.py | 10 +- .../plugins/grassprovider/ext/r_what_color.py | 8 +- .../plugins/grassprovider/ext/v_distance.py | 32 +- python/plugins/grassprovider/ext/v_edit.py | 29 +- python/plugins/grassprovider/ext/v_extrude.py | 16 +- .../grassprovider/ext/v_in_geonames.py | 8 +- python/plugins/grassprovider/ext/v_net.py | 65 +- .../plugins/grassprovider/ext/v_net_alloc.py | 8 +- .../grassprovider/ext/v_net_allpairs.py | 8 +- .../plugins/grassprovider/ext/v_net_bridge.py | 18 +- .../grassprovider/ext/v_net_centrality.py | 8 +- .../grassprovider/ext/v_net_components.py | 22 +- .../grassprovider/ext/v_net_connectivity.py | 24 +- .../grassprovider/ext/v_net_distance.py | 48 +- .../plugins/grassprovider/ext/v_net_flow.py | 30 +- python/plugins/grassprovider/ext/v_net_iso.py | 8 +- .../plugins/grassprovider/ext/v_net_path.py | 8 +- .../grassprovider/ext/v_net_salesman.py | 8 +- .../grassprovider/ext/v_net_spanningtree.py | 8 +- .../grassprovider/ext/v_net_steiner.py | 8 +- .../grassprovider/ext/v_net_visibility.py | 8 +- python/plugins/grassprovider/ext/v_proj.py | 31 +- .../plugins/grassprovider/ext/v_rast_stats.py | 12 +- python/plugins/grassprovider/ext/v_reclass.py | 12 +- python/plugins/grassprovider/ext/v_rectify.py | 23 +- python/plugins/grassprovider/ext/v_sample.py | 12 +- python/plugins/grassprovider/ext/v_to_3d.py | 20 +- .../plugins/grassprovider/ext/v_transform.py | 18 +- .../plugins/grassprovider/ext/v_vect_stats.py | 12 +- python/plugins/grassprovider/ext/v_voronoi.py | 20 +- .../plugins/grassprovider/ext/v_what_rast.py | 12 +- .../plugins/grassprovider/ext/v_what_vect.py | 10 +- .../plugins/grassprovider/grass_algorithm.py | 904 +- python/plugins/grassprovider/grass_plugin.py | 8 +- .../plugins/grassprovider/grass_provider.py | 164 +- python/plugins/grassprovider/grass_utils.py | 393 +- .../grassprovider/parsed_description.py | 99 +- .../grassprovider/tests/AlgorithmsTestBase.py | 278 +- .../tests/grass_algorithms_imagery_test.py | 15 +- .../tests/grass_algorithms_raster_test_pt1.py | 16 +- .../tests/grass_algorithms_raster_test_pt2.py | 63 +- .../tests/grass_algorithms_vector_test.py | 310 +- python/plugins/processing/ProcessingPlugin.py | 280 +- python/plugins/processing/__init__.py | 9 +- .../processing/algs/gdal/AssignProjection.py | 68 +- python/plugins/processing/algs/gdal/Buffer.py | 168 +- .../algs/gdal/ClipRasterByExtent.py | 201 +- .../processing/algs/gdal/ClipRasterByMask.py | 355 +- .../algs/gdal/ClipVectorByExtent.py | 98 +- .../processing/algs/gdal/ClipVectorByMask.py | 98 +- .../processing/algs/gdal/ColorRelief.py | 164 +- .../processing/algs/gdal/Datasources2Vrt.py | 111 +- .../plugins/processing/algs/gdal/Dissolve.py | 228 +- .../processing/algs/gdal/ExecuteSql.py | 119 +- .../processing/algs/gdal/GdalAlgorithm.py | 145 +- .../algs/gdal/GdalAlgorithmDialog.py | 74 +- .../algs/gdal/GdalAlgorithmProvider.py | 46 +- .../plugins/processing/algs/gdal/GdalUtils.py | 327 +- .../processing/algs/gdal/GridAverage.py | 288 +- .../processing/algs/gdal/GridDataMetrics.py | 323 +- .../algs/gdal/GridInverseDistance.py | 353 +- .../GridInverseDistanceNearestNeighbor.py | 309 +- .../processing/algs/gdal/GridLinear.py | 227 +- .../algs/gdal/GridNearestNeighbor.py | 269 +- .../processing/algs/gdal/OffsetCurve.py | 127 +- .../processing/algs/gdal/OgrToPostGis.py | 584 +- .../processing/algs/gdal/OneSideBuffer.py | 195 +- .../processing/algs/gdal/PointsAlongLines.py | 136 +- python/plugins/processing/algs/gdal/aspect.py | 166 +- .../plugins/processing/algs/gdal/buildvrt.py | 282 +- .../plugins/processing/algs/gdal/contour.py | 275 +- .../processing/algs/gdal/extractprojection.py | 115 +- .../processing/algs/gdal/fillnodata.py | 185 +- .../processing/algs/gdal/gdal2tiles.py | 310 +- .../plugins/processing/algs/gdal/gdal2xyz.py | 162 +- .../plugins/processing/algs/gdal/gdaladdo.py | 187 +- .../plugins/processing/algs/gdal/gdalcalc.py | 426 +- .../plugins/processing/algs/gdal/gdalinfo.py | 139 +- .../processing/algs/gdal/gdaltindex.py | 188 +- .../plugins/processing/algs/gdal/hillshade.py | 263 +- python/plugins/processing/algs/gdal/merge.py | 248 +- .../plugins/processing/algs/gdal/nearblack.py | 130 +- .../plugins/processing/algs/gdal/ogr2ogr.py | 121 +- .../algs/gdal/ogr2ogrtopostgislist.py | 546 +- .../plugins/processing/algs/gdal/ogrinfo.py | 173 +- .../plugins/processing/algs/gdal/pansharp.py | 160 +- .../plugins/processing/algs/gdal/pct2rgb.py | 90 +- .../processing/algs/gdal/polygonize.py | 128 +- .../plugins/processing/algs/gdal/proximity.py | 272 +- .../plugins/processing/algs/gdal/rasterize.py | 336 +- .../processing/algs/gdal/rasterize_over.py | 134 +- .../algs/gdal/rasterize_over_fixed_value.py | 126 +- .../processing/algs/gdal/rearrange_bands.py | 151 +- python/plugins/processing/algs/gdal/retile.py | 332 +- .../plugins/processing/algs/gdal/rgb2pct.py | 84 +- .../plugins/processing/algs/gdal/roughness.py | 109 +- python/plugins/processing/algs/gdal/sieve.py | 147 +- python/plugins/processing/algs/gdal/slope.py | 175 +- python/plugins/processing/algs/gdal/tpi.py | 103 +- .../plugins/processing/algs/gdal/translate.py | 194 +- python/plugins/processing/algs/gdal/tri.py | 103 +- .../plugins/processing/algs/gdal/viewshed.py | 195 +- python/plugins/processing/algs/gdal/warp.py | 314 +- .../plugins/processing/algs/help/__init__.py | 20 +- .../plugins/processing/algs/qgis/BarPlot.py | 133 +- .../plugins/processing/algs/qgis/BoxPlot.py | 164 +- python/plugins/processing/algs/qgis/Buffer.py | 50 +- .../processing/algs/qgis/CheckValidity.py | 239 +- python/plugins/processing/algs/qgis/Climb.py | 182 +- .../processing/algs/qgis/DefineProjection.py | 70 +- .../algs/qgis/EliminateSelection.py | 130 +- .../processing/algs/qgis/ExecuteSQL.py | 200 +- .../algs/qgis/ExportGeometryInfo.py | 170 +- .../processing/algs/qgis/FieldPyculator.py | 221 +- .../processing/algs/qgis/FindProjection.py | 111 +- .../processing/algs/qgis/GeometryConvert.py | 142 +- .../plugins/processing/algs/qgis/Heatmap.py | 304 +- .../processing/algs/qgis/HubDistanceLines.py | 179 +- .../processing/algs/qgis/HubDistancePoints.py | 177 +- .../processing/algs/qgis/HypsometricCurves.py | 175 +- .../processing/algs/qgis/IdwInterpolation.py | 171 +- .../algs/qgis/ImportIntoSpatialite.py | 245 +- .../algs/qgis/KNearestConcaveHull.py | 203 +- .../processing/algs/qgis/LinesToPolygons.py | 62 +- .../processing/algs/qgis/MeanAndStdDevPlot.py | 86 +- .../algs/qgis/MinimumBoundingGeometry.py | 190 +- .../processing/algs/qgis/PointDistance.py | 345 +- .../algs/qgis/PointsDisplacement.py | 123 +- .../processing/algs/qgis/PointsFromLines.py | 124 +- .../plugins/processing/algs/qgis/PolarPlot.py | 98 +- .../algs/qgis/PostGISExecuteAndLoadSQL.py | 141 +- .../processing/algs/qgis/QgisAlgorithm.py | 22 +- .../algs/qgis/QgisAlgorithmProvider.py | 129 +- .../algs/qgis/RandomExtractWithinSubsets.py | 140 +- .../algs/qgis/RandomPointsAlongLines.py | 146 +- .../processing/algs/qgis/RandomPointsLayer.py | 153 +- .../algs/qgis/RandomPointsPolygons.py | 227 +- .../processing/algs/qgis/RandomSelection.py | 101 +- .../algs/qgis/RandomSelectionWithinSubsets.py | 131 +- .../processing/algs/qgis/RasterCalculator.py | 196 +- .../algs/qgis/RasterLayerHistogram.py | 77 +- .../qgis/RectanglesOvalsDiamondsVariable.py | 301 +- .../processing/algs/qgis/RegularPoints.py | 138 +- python/plugins/processing/algs/qgis/Relief.py | 180 +- .../processing/algs/qgis/SelectByAttribute.py | 206 +- .../algs/qgis/SelectByExpression.py | 97 +- .../processing/algs/qgis/SetRasterStyle.py | 51 +- .../processing/algs/qgis/SetVectorStyle.py | 52 +- .../algs/qgis/StatisticsByCategories.py | 312 +- .../processing/algs/qgis/TextToFloat.py | 49 +- .../processing/algs/qgis/TinInterpolation.py | 204 +- .../processing/algs/qgis/TopoColors.py | 195 +- .../processing/algs/qgis/UniqueValues.py | 163 +- .../algs/qgis/VariableDistanceBuffer.py | 180 +- .../algs/qgis/VectorLayerHistogram.py | 79 +- .../algs/qgis/VectorLayerScatterplot.py | 154 +- .../algs/qgis/VectorLayerScatterplot3D.py | 150 +- .../algs/qgis/ui/ExecuteSQLWidget.py | 46 +- .../processing/algs/qgis/ui/HeatmapWidgets.py | 16 +- .../algs/qgis/ui/InterpolationWidgets.py | 152 +- .../algs/qgis/ui/RasterCalculatorWidgets.py | 129 +- .../algs/qgis/ui/ReliefColorsWidget.py | 172 +- python/plugins/processing/core/Processing.py | 150 +- .../processing/core/ProcessingConfig.py | 450 +- .../processing/core/ProcessingResults.py | 6 +- .../processing/core/defaultproviders.py | 6 +- python/plugins/processing/core/outputs.py | 70 +- python/plugins/processing/core/parameters.py | 317 +- .../plugins/processing/gui/AlgorithmDialog.py | 320 +- .../processing/gui/AlgorithmDialogBase.py | 6 +- .../processing/gui/AlgorithmExecutor.py | 251 +- .../processing/gui/AlgorithmLocatorFilter.py | 90 +- .../plugins/processing/gui/AutofillDialog.py | 9 +- .../processing/gui/BatchAlgorithmDialog.py | 113 +- .../gui/BatchInputSelectionPanel.py | 155 +- .../gui/BatchOutputSelectionPanel.py | 135 +- python/plugins/processing/gui/BatchPanel.py | 422 +- .../plugins/processing/gui/CheckboxesPanel.py | 31 +- python/plugins/processing/gui/ConfigDialog.py | 136 +- .../plugins/processing/gui/ContextAction.py | 10 +- .../processing/gui/DirectorySelectorDialog.py | 58 +- .../gui/EditRenderingStylesDialog.py | 33 +- .../processing/gui/ExtentSelectionPanel.py | 102 +- .../processing/gui/FileSelectionPanel.py | 45 +- .../processing/gui/FixedTableDialog.py | 39 +- .../plugins/processing/gui/FixedTablePanel.py | 23 +- python/plugins/processing/gui/Help2Html.py | 68 +- .../processing/gui/ListMultiselectWidget.py | 52 +- .../processing/gui/MessageBarProgress.py | 32 +- .../plugins/processing/gui/MessageDialog.py | 11 +- .../processing/gui/MultipleFileInputDialog.py | 62 +- .../processing/gui/MultipleInputDialog.py | 122 +- .../processing/gui/MultipleInputPanel.py | 27 +- .../processing/gui/NumberInputPanel.py | 92 +- .../plugins/processing/gui/ParametersPanel.py | 86 +- python/plugins/processing/gui/PointMapTool.py | 6 +- .../processing/gui/PointSelectionPanel.py | 21 +- .../plugins/processing/gui/Postprocessing.py | 151 +- .../processing/gui/ProcessingToolbox.py | 124 +- .../plugins/processing/gui/ProviderActions.py | 14 +- python/plugins/processing/gui/RangePanel.py | 15 +- .../processing/gui/RectangleMapTool.py | 16 +- .../processing/gui/RenderingStyleFilePanel.py | 20 +- .../plugins/processing/gui/RenderingStyles.py | 23 +- python/plugins/processing/gui/ResultsDock.py | 20 +- python/plugins/processing/gui/TestTools.py | 221 +- .../plugins/processing/gui/ToolboxAction.py | 10 +- python/plugins/processing/gui/__init__.py | 6 +- python/plugins/processing/gui/menus.py | 309 +- python/plugins/processing/gui/wrappers.py | 1241 +- .../modeler/AddModelFromFileAction.py | 69 +- .../modeler/CreateNewModelAction.py | 14 +- .../processing/modeler/DeleteModelAction.py | 38 +- .../processing/modeler/EditModelAction.py | 14 +- .../ExportModelAsPythonScriptAction.py | 25 +- .../modeler/ModelerAlgorithmProvider.py | 79 +- .../processing/modeler/ModelerDialog.py | 221 +- .../processing/modeler/ModelerGraphicItem.py | 91 +- .../ModelerParameterDefinitionDialog.py | 205 +- .../modeler/ModelerParametersDialog.py | 271 +- .../processing/modeler/ModelerScene.py | 8 +- .../processing/modeler/ModelerUtils.py | 12 +- .../processing/modeler/MultilineTextPanel.py | 21 +- .../modeler/OpenModelFromFileAction.py | 29 +- .../processing/modeler/ProjectProvider.py | 48 +- .../script/AddScriptFromFileAction.py | 32 +- .../script/AddScriptFromTemplateAction.py | 15 +- .../script/CreateNewScriptAction.py | 10 +- .../processing/script/DeleteScriptAction.py | 36 +- .../processing/script/EditScriptAction.py | 20 +- .../script/OpenScriptFromFileAction.py | 29 +- .../script/ScriptAlgorithmProvider.py | 59 +- .../plugins/processing/script/ScriptEdit.py | 20 +- .../processing/script/ScriptEditorDialog.py | 149 +- .../processing/script/ScriptTemplate.py | 76 +- .../plugins/processing/script/ScriptUtils.py | 65 +- .../processing/tests/AlgorithmsTestBase.py | 356 +- .../tests/CheckValidityAlgorithm.py | 74 +- .../tests/GdalAlgorithmsGeneralTest.py | 331 +- .../tests/GdalAlgorithmsRasterTest.py | 7405 ++++++--- .../tests/GdalAlgorithmsVectorTest.py | 2369 ++- python/plugins/processing/tests/GuiTest.py | 248 +- .../plugins/processing/tests/ModelerTest.py | 92 +- .../processing/tests/ParametersTest.py | 950 +- .../processing/tests/ProcessingGeneralTest.py | 100 +- .../processing/tests/ProjectProvider.py | 44 +- .../processing/tests/QgisAlgorithmsTest1.py | 38 +- .../processing/tests/QgisAlgorithmsTest2.py | 17 +- .../processing/tests/QgisAlgorithmsTest3.py | 17 +- .../processing/tests/QgisAlgorithmsTest4.py | 30 +- .../processing/tests/QgisAlgorithmsTest5.py | 12 +- .../processing/tests/ScriptUtilsTest.py | 22 +- python/plugins/processing/tests/TestData.py | 14 +- python/plugins/processing/tests/ToolsTest.py | 34 +- python/plugins/processing/tools/__init__.py | 6 +- .../plugins/processing/tools/dataobjects.py | 116 +- python/plugins/processing/tools/general.py | 116 +- python/plugins/processing/tools/raster.py | 42 +- python/plugins/processing/tools/system.py | 43 +- python/plugins/processing/tools/vector.py | 17 +- python/processing/__init__.py | 67 +- python/processing/algfactory.py | 340 +- python/pyplugin_installer/__init__.py | 8 +- python/pyplugin_installer/installer.py | 529 +- python/pyplugin_installer/installer_data.py | 785 +- .../pyplugin_installer/plugindependencies.py | 103 +- .../qgsplugindependenciesdialog.py | 48 +- .../qgsplugininstallerfetchingdialog.py | 32 +- .../qgsplugininstallerinstallingdialog.py | 95 +- .../qgsplugininstallerpluginerrordialog.py | 9 +- .../qgsplugininstallerrepositorydialog.py | 15 +- python/pyplugin_installer/unzip.py | 17 +- python/pyplugin_installer/version_compare.py | 87 +- python/testing/__init__.py | 483 +- python/testing/mocked.py | 10 +- python/user.py | 22 +- python/utils.py | 437 +- scripts/2to3 | 5 +- scripts/appinfo2ui.py | 19 +- scripts/doxygen_space.py | 120 +- scripts/dump_babel_formats.py | 77 +- scripts/generate_test_mask_image.py | 92 +- scripts/includemocs.py | 16 +- scripts/mkuidefaults.py | 57 +- scripts/parse_dash_results.py | 298 +- scripts/process_function_template.py | 136 +- scripts/process_google_fonts.py | 3148 ++-- scripts/pyqt5_to_pyqt6/pyqt5_to_pyqt6.py | 567 +- scripts/pyuic_wrapper.py | 6 +- scripts/qgis_fixes/fix_absolute_import.py | 4 +- .../fix_future_standard_library_urllib.py | 4 +- scripts/qgis_fixes/fix_print_with_import.py | 11 +- scripts/qgis_fixes/fix_pyqt.py | 797 +- scripts/qgis_fixes/fix_qfiledialog.py | 13 +- scripts/qgis_fixes/fix_signals.py | 37 +- scripts/qgis_fixes/fix_uiimport.py | 6 +- scripts/qstringfixup.py | 67 +- scripts/random_vector.py | 59 +- scripts/sipify.py | 2005 ++- scripts/symbol_xml2db.py | 69 +- scripts/widgets_tree.py | 121 +- src/plugins/grass/qgis_grass_test.py | 104 +- .../grass/scripts/db.connect-login.pg.py | 169 +- .../grass/scripts/qgis.v.kernel.rast.py | 76 +- src/plugins/grass/scripts/qgis.v.upgrade.py | 37 +- src/plugins/grass/scripts/r.external.all.py | 102 +- src/plugins/grass/scripts/t.rast.what.qgis.py | 427 +- .../grass/scripts/v.class.mlpy.qgis.py | 181 +- src/plugins/grass/scripts/v.out.ogr.pg.py | 211 +- tests/code_layout/acceptable_missing_doc.py | 2761 +++- tests/code_layout/doxygen_parser.py | 448 +- tests/code_layout/test_qgsdoccoverage.py | 139 +- tests/code_layout/test_qgssipcoverage.py | 65 +- tests/src/python/featuresourcetestbase.py | 1561 +- tests/src/python/mockedwebserver.py | 119 +- tests/src/python/offlineditingtestbase.py | 196 +- tests/src/python/provider_python.py | 149 +- tests/src/python/providertestbase.py | 1185 +- tests/src/python/qgis_interface.py | 16 +- tests/src/python/qgis_wrapped_server.py | 264 +- .../qgsauthconfigurationcustomstorage.py | 39 +- .../qgslayermetadataprovidertestbase.py | 81 +- tests/src/python/stylestoragebase.py | 55 +- .../src/python/test_authmanager_oauth2_ows.py | 166 +- tests/src/python/test_authmanager_ogr.py | 74 +- .../python/test_authmanager_ogr_postgres.py | 171 +- .../python/test_authmanager_password_ows.py | 234 +- .../test_authmanager_password_postgres.py | 73 +- tests/src/python/test_authmanager_pki_ows.py | 119 +- .../python/test_authmanager_pki_postgres.py | 69 +- tests/src/python/test_authmanager_proxy.py | 37 +- .../python/test_authmanager_storage_base.py | 790 +- .../python/test_authmanager_storage_custom.py | 17 +- .../python/test_authmanager_storage_psql.py | 69 +- .../python/test_authmanager_storage_sqlite.py | 21 +- tests/src/python/test_authsettingswidget.py | 91 +- tests/src/python/test_console.py | 11 +- tests/src/python/test_core_additions.py | 11 +- tests/src/python/test_db_manager_gpkg.py | 267 +- tests/src/python/test_db_manager_postgis.py | 187 +- .../src/python/test_db_manager_spatialite.py | 173 +- .../src/python/test_db_manager_sql_window.py | 17 +- tests/src/python/test_disabled_tests.py | 47 +- tests/src/python/test_hana_utils.py | 166 +- tests/src/python/test_layer_dependencies.py | 137 +- tests/src/python/test_offline_editing_wfs.py | 80 +- tests/src/python/test_plugindependencies.py | 207 +- .../python/test_processing_alg_decorator.py | 69 +- .../test_processing_algs_gdal_gdalutils.py | 51 +- .../test_processing_importintopostgis.py | 52 +- .../python/test_processing_packagelayers.py | 154 +- tests/src/python/test_project_storage_base.py | 26 +- .../src/python/test_project_storage_oracle.py | 60 +- .../python/test_project_storage_postgres.py | 45 +- tests/src/python/test_provider_afs.py | 1563 +- tests/src/python/test_provider_gdal.py | 468 +- tests/src/python/test_provider_gpx.py | 162 +- tests/src/python/test_provider_hana.py | 1029 +- tests/src/python/test_provider_memory.py | 984 +- tests/src/python/test_provider_mssql.py | 1063 +- tests/src/python/test_provider_oapif.py | 2623 ++- tests/src/python/test_provider_ogr.py | 3980 +++-- tests/src/python/test_provider_ogr_gpkg.py | 2625 +-- tests/src/python/test_provider_ogr_sqlite.py | 590 +- tests/src/python/test_provider_oracle.py | 1614 +- tests/src/python/test_provider_postgres.py | 4083 +++-- .../python/test_provider_postgres_latency.py | 84 +- .../python/test_provider_postgresraster.py | 689 +- tests/src/python/test_provider_python.py | 474 +- .../src/python/test_provider_sensorthings.py | 1590 +- tests/src/python/test_provider_shapefile.py | 1114 +- tests/src/python/test_provider_spatialite.py | 1563 +- tests/src/python/test_provider_tabfile.py | 81 +- tests/src/python/test_provider_virtual.py | 1094 +- tests/src/python/test_provider_wfs.py | 5013 ++++-- tests/src/python/test_provider_wfs_gui.py | 109 +- tests/src/python/test_python_repr.py | 372 +- tests/src/python/test_python_utils.py | 32 +- tests/src/python/test_qgs3dmaterials.py | 56 +- tests/src/python/test_qgsaction.py | 29 +- tests/src/python/test_qgsactionmanager.py | 158 +- .../src/python/test_qgsactionwidgetwrapper.py | 57 +- .../src/python/test_qgsaggregatecalculator.py | 529 +- .../python/test_qgsaggregatemappingwidget.py | 309 +- tests/src/python/test_qgsalignmentcombobox.py | 25 +- .../test_qgsanimatedmarkersymbollayer.py | 34 +- tests/src/python/test_qgsannotation.py | 164 +- .../test_qgsannotationitemeditoperation.py | 29 +- .../src/python/test_qgsannotationitemnode.py | 47 +- tests/src/python/test_qgsannotationlayer.py | 899 +- .../src/python/test_qgsannotationlineitem.py | 311 +- .../python/test_qgsannotationlinetextitem.py | 319 +- .../python/test_qgsannotationmarkeritem.py | 140 +- .../python/test_qgsannotationpictureitem.py | 917 +- .../python/test_qgsannotationpointtextitem.py | 243 +- .../python/test_qgsannotationpolygonitem.py | 488 +- .../python/test_qgsannotationrecttextitem.py | 671 +- tests/src/python/test_qgsapplication.py | 15 +- tests/src/python/test_qgsappstartup.py | 125 +- tests/src/python/test_qgsarcgisportalutils.py | 225 +- tests/src/python/test_qgsarcgisrestutils.py | 1046 +- tests/src/python/test_qgsarrowsymbollayer.py | 224 +- .../python/test_qgsattributeeditoraction.py | 49 +- tests/src/python/test_qgsattributeform.py | 247 +- .../test_qgsattributeformeditorwidget.py | 101 +- .../python/test_qgsattributetableconfig.py | 58 +- .../src/python/test_qgsattributetablemodel.py | 123 +- tests/src/python/test_qgsauthbasicmethod.py | 45 +- ...est_qgsauthconfigurationstorageregistry.py | 20 +- tests/src/python/test_qgsauthsystem.py | 810 +- tests/src/python/test_qgsauxiliarystorage.py | 309 +- tests/src/python/test_qgsbabelgpsformat.py | 511 +- tests/src/python/test_qgsbearingutils.py | 78 +- tests/src/python/test_qgsbinarywidget.py | 24 +- tests/src/python/test_qgsblendmodes.py | 100 +- .../python/test_qgsblockingnetworkrequest.py | 135 +- tests/src/python/test_qgsblockingprocess.py | 104 +- tests/src/python/test_qgsbookmarkmanager.py | 633 +- tests/src/python/test_qgsbookmarkmodel.py | 277 +- tests/src/python/test_qgsbox3d.py | 94 +- .../src/python/test_qgscalloutpanelwidget.py | 17 +- .../test_qgscategorizedsymbolrenderer.py | 715 +- .../src/python/test_qgscesium3dtileslayer.py | 110 +- tests/src/python/test_qgscesiumutils.py | 24 +- tests/src/python/test_qgscheckablecombobox.py | 35 +- tests/src/python/test_qgscircularstring.py | 72 +- .../python/test_qgsclassificationmethod.py | 128 +- tests/src/python/test_qgscodeeditor.py | 124 +- .../python/test_qgscodeeditorcolorscheme.py | 61 +- tests/src/python/test_qgscodeeditorpython.py | 44 +- tests/src/python/test_qgscolorbutton.py | 39 +- tests/src/python/test_qgscolorramp.py | 350 +- .../src/python/test_qgscolorramplegendnode.py | 226 +- tests/src/python/test_qgscolorscheme.py | 43 +- .../src/python/test_qgscolorschemeregistry.py | 14 +- tests/src/python/test_qgscolorutils.py | 51 +- tests/src/python/test_qgscolorwidget.py | 9 +- .../src/python/test_qgscombinedstylemodel.py | 118 +- tests/src/python/test_qgscompoundcurve.py | 154 +- .../test_qgsconditionalformatwidgets.py | 19 +- tests/src/python/test_qgsconditionalstyle.py | 81 +- .../src/python/test_qgsconnectionregistry.py | 37 +- .../src/python/test_qgscoordinateformatter.py | 1655 +- .../test_qgscoordinateoperationwidget.py | 155 +- .../test_qgscoordinatereferencesystem.py | 19 +- .../test_qgscoordinatereferencesystemmodel.py | 766 +- .../test_qgscoordinatereferencesystemutils.py | 63 +- .../src/python/test_qgscoordinatetransform.py | 302 +- .../test_qgscoordinatetransformcontext.py | 694 +- tests/src/python/test_qgscore.py | 26 +- .../src/python/test_qgscrsdefinitionwidget.py | 45 +- .../src/python/test_qgscrsselectionwidget.py | 13 +- .../python/test_qgsdatabaseschemacombobox.py | 131 +- .../src/python/test_qgsdatabaseschemamodel.py | 345 +- .../python/test_qgsdatabasetablecombobox.py | 296 +- .../src/python/test_qgsdatabasetablemodel.py | 676 +- tests/src/python/test_qgsdataitem.py | 23 +- .../test_qgsdataitemguiproviderregistry.py | 19 +- .../test_qgsdataitemproviderregistry.py | 27 +- tests/src/python/test_qgsdatetimeedit.py | 27 +- .../test_qgsdatetimestatisticalsummary.py | 225 +- tests/src/python/test_qgsdatumtransforms.py | 400 +- tests/src/python/test_qgsdefaultvalue.py | 24 +- .../python/test_qgsdelimitedtextprovider.py | 1394 +- .../test_qgsdelimitedtextprovider_wanted.py | 3776 ++--- tests/src/python/test_qgsdistancearea.py | 2122 ++- tests/src/python/test_qgseditformconfig.py | 59 +- tests/src/python/test_qgseditwidgets.py | 229 +- .../test_qgselevationcontrollerwidget.py | 70 +- .../python/test_qgselevationprofilecanvas.py | 78 +- tests/src/python/test_qgselevationutils.py | 117 +- tests/src/python/test_qgsellipsoidutils.py | 266 +- .../python/test_qgsencodingselectiondialog.py | 23 +- tests/src/python/test_qgsexiftools.py | 69 +- tests/src/python/test_qgsexpression.py | 192 +- .../python/test_qgsexpressionbuilderwidget.py | 283 +- .../src/python/test_qgsexpressionlineedit.py | 40 +- .../python/test_qgsexpressionpreviewwidget.py | 34 +- tests/src/python/test_qgsextentgroupbox.py | 147 +- tests/src/python/test_qgsextentwidget.py | 158 +- .../python/test_qgsexternalstorage_base.py | 3 +- .../test_qgsexternalstorage_simplecopy.py | 16 +- .../python/test_qgsexternalstorage_webdav.py | 12 +- tests/src/python/test_qgsfeature.py | 154 +- tests/src/python/test_qgsfeatureiterator.py | 701 +- tests/src/python/test_qgsfeaturepicker.py | 23 +- tests/src/python/test_qgsfeaturerequest.py | 292 +- tests/src/python/test_qgsfeaturesink.py | 132 +- tests/src/python/test_qgsfeaturesource.py | 47 +- tests/src/python/test_qgsfeedback.py | 9 +- tests/src/python/test_qgsfield.py | 80 +- tests/src/python/test_qgsfieldcombobox.py | 52 +- tests/src/python/test_qgsfielddomain.py | 155 +- tests/src/python/test_qgsfielddomainwidget.py | 53 +- tests/src/python/test_qgsfieldformatters.py | 1228 +- .../src/python/test_qgsfieldmappingwidget.py | 326 +- tests/src/python/test_qgsfieldmodel.py | 639 +- tests/src/python/test_qgsfields.py | 100 +- tests/src/python/test_qgsfieldvalidator.py | 95 +- tests/src/python/test_qgsfiledownloader.py | 102 +- tests/src/python/test_qgsfileutils.py | 623 +- .../python/test_qgsfilledlinesymbollayer.py | 36 +- tests/src/python/test_qgsfillsymbollayers.py | 19 +- tests/src/python/test_qgsfilterlineedit.py | 79 +- tests/src/python/test_qgsfloatingwidget.py | 146 +- tests/src/python/test_qgsfontbutton.py | 29 +- tests/src/python/test_qgsfontmanager.py | 472 +- tests/src/python/test_qgsfontutils.py | 132 +- tests/src/python/test_qgsgeocoderalgorithm.py | 188 +- .../python/test_qgsgeocoderlocatorfilter.py | 101 +- tests/src/python/test_qgsgeometry.py | 13685 +++++++++++----- .../test_qgsgeometry_avoid_intersections.py | 13 +- .../src/python/test_qgsgeometrycollection.py | 462 +- .../test_qgsgeometrygeneratorsymbollayer.py | 305 +- .../src/python/test_qgsgeometrypaintdevice.py | 555 +- tests/src/python/test_qgsgeometryvalidator.py | 113 +- tests/src/python/test_qgsgeometrywidget.py | 91 +- .../src/python/test_qgsgooglemapsgeocoder.py | 208 +- tests/src/python/test_qgsgpslogger.py | 429 +- .../python/test_qgsgraduatedsymbolrenderer.py | 352 +- tests/src/python/test_qgsgraph.py | 13 +- tests/src/python/test_qgsgrouplayer.py | 124 +- .../src/python/test_qgshashlinesymbollayer.py | 221 +- tests/src/python/test_qgsheatmaprenderer.py | 106 +- tests/src/python/test_qgshelp.py | 41 +- tests/src/python/test_qgshighlight.py | 5 +- tests/src/python/test_qgshillshaderenderer.py | 13 +- .../python/test_qgshistoryproviderregistry.py | 342 +- tests/src/python/test_qgsimagecache.py | 99 +- .../src/python/test_qgsimagesourcelineedit.py | 49 +- tests/src/python/test_qgsinputcontroller.py | 33 +- .../test_qgsinterpolatedlinesymbollayers.py | 211 +- tests/src/python/test_qgsinterval.py | 88 +- tests/src/python/test_qgsissue7244.py | 33 +- tests/src/python/test_qgsjsonedit.py | 11 +- tests/src/python/test_qgsjsonutils.py | 274 +- .../src/python/test_qgslabelingenginerule.py | 170 +- tests/src/python/test_qgslabellinesettings.py | 138 +- .../python/test_qgslabelobstaclesettings.py | 33 +- .../python/test_qgslabelplacementsettings.py | 21 +- .../src/python/test_qgslabelsettingswidget.py | 37 +- .../python/test_qgslabelthinningsettings.py | 9 +- tests/src/python/test_qgslayerdefinition.py | 59 +- tests/src/python/test_qgslayermetadata.py | 598 +- .../test_qgslayermetadataprovider_ogr.py | 28 +- .../test_qgslayermetadataprovider_postgres.py | 42 +- ...qgslayermetadataprovider_postgresraster.py | 44 +- .../test_qgslayermetadataprovider_python.py | 60 +- .../test_qgslayermetadataresultsmodel.py | 132 +- tests/src/python/test_qgslayertree.py | 285 +- .../test_qgslayertreefilterproxymodel.py | 31 +- .../test_qgslayertreemapcanvasbridge.py | 87 +- tests/src/python/test_qgslayertreeview.py | 575 +- tests/src/python/test_qgslayout.py | 440 +- tests/src/python/test_qgslayoutaligner.py | 662 +- tests/src/python/test_qgslayoutatlas.py | 328 +- .../test_qgslayoutatlasclippingsettings.py | 55 +- tests/src/python/test_qgslayoutcombobox.py | 43 +- .../python/test_qgslayoutelevationprofile.py | 451 +- tests/src/python/test_qgslayoutexporter.py | 1037 +- tests/src/python/test_qgslayoutframe.py | 11 +- .../src/python/test_qgslayoutgridsettings.py | 13 +- tests/src/python/test_qgslayoutguides.py | 337 +- tests/src/python/test_qgslayouthtml.py | 42 +- tests/src/python/test_qgslayoutitem.py | 177 +- .../src/python/test_qgslayoutitemcombobox.py | 75 +- .../test_qgslayoutitempropertiesdialog.py | 29 +- tests/src/python/test_qgslayoutlabel.py | 35 +- tests/src/python/test_qgslayoutlegend.py | 1047 +- tests/src/python/test_qgslayoutmanager.py | 130 +- .../src/python/test_qgslayoutmanagermodel.py | 659 +- tests/src/python/test_qgslayoutmap.py | 408 +- tests/src/python/test_qgslayoutmapgrid.py | 311 +- .../test_qgslayoutmapitemclippingsettings.py | 55 +- tests/src/python/test_qgslayoutmapoverview.py | 307 +- tests/src/python/test_qgslayoutmarker.py | 66 +- .../python/test_qgslayoutnortharrowhandler.py | 17 +- tests/src/python/test_qgslayoutpage.py | 51 +- .../python/test_qgslayoutpagecollection.py | 418 +- tests/src/python/test_qgslayoutpicture.py | 48 +- tests/src/python/test_qgslayoutpolygon.py | 116 +- tests/src/python/test_qgslayoutpolyline.py | 112 +- tests/src/python/test_qgslayoutscalebar.py | 11 +- tests/src/python/test_qgslayoutshape.py | 67 +- tests/src/python/test_qgslayoutsnapper.py | 159 +- tests/src/python/test_qgslayouttable.py | 19 +- .../src/python/test_qgslayoutunitscombobox.py | 20 +- tests/src/python/test_qgslayoutview.py | 571 +- tests/src/python/test_qgslegendpatchshape.py | 649 +- .../python/test_qgslegendpatchshapebutton.py | 61 +- .../python/test_qgslegendpatchshapewidget.py | 71 +- tests/src/python/test_qgslegendrenderer.py | 20 +- .../test_qgslinearreferencingsymbollayer.py | 480 +- .../python/test_qgslineburstsymbollayer.py | 136 +- tests/src/python/test_qgslinesegment.py | 9 +- tests/src/python/test_qgslinestring.py | 363 +- tests/src/python/test_qgslinesymbollayers.py | 39 +- .../python/test_qgslocaldefaultsettings.py | 55 +- .../test_qgslocalizeddatapathregistry.py | 54 +- tests/src/python/test_qgslocator.py | 505 +- tests/src/python/test_qgslogger.py | 35 +- tests/src/python/test_qgsmapboxglconverter.py | 2596 +-- tests/src/python/test_qgsmapcanvas.py | 597 +- .../python/test_qgsmapcanvasannotationitem.py | 47 +- tests/src/python/test_qgsmapclippingregion.py | 72 +- tests/src/python/test_qgsmapclippingutils.py | 286 +- tests/src/python/test_qgsmaphittest.py | 132 +- tests/src/python/test_qgsmaplayer.py | 375 +- tests/src/python/test_qgsmaplayeraction.py | 79 +- tests/src/python/test_qgsmaplayercombobox.py | 237 +- tests/src/python/test_qgsmaplayerfactory.py | 161 +- tests/src/python/test_qgsmaplayermodel.py | 643 +- .../src/python/test_qgsmaplayerproxymodel.py | 199 +- .../test_qgsmaplayerserverproperties.py | 54 +- tests/src/python/test_qgsmaplayerstore.py | 222 +- tests/src/python/test_qgsmaplayerutils.py | 301 +- tests/src/python/test_qgsmaprenderer.py | 125 +- tests/src/python/test_qgsmaprenderercache.py | 267 +- .../src/python/test_qgsmapthemecollection.py | 219 +- tests/src/python/test_qgsmapunitscale.py | 11 +- tests/src/python/test_qgsmargins.py | 30 +- .../python/test_qgsmarkerlinesymbollayer.py | 794 +- .../src/python/test_qgsmaskrendersettings.py | 9 +- tests/src/python/test_qgsmatrix4x4.py | 128 +- tests/src/python/test_qgsmediawidget.py | 15 +- .../python/test_qgsmergedfeaturerenderer.py | 113 +- tests/src/python/test_qgsmesh3dsymbol.py | 40 +- tests/src/python/test_qgsmeshlayer.py | 56 +- .../test_qgsmeshlayerelevationproperties.py | 180 +- tests/src/python/test_qgsmeshlayerlabeling.py | 47 +- .../test_qgsmeshlayerprofilegenerator.py | 129 +- tests/src/python/test_qgsmeshlayerrenderer.py | 85 +- tests/src/python/test_qgsmessagelog.py | 45 +- tests/src/python/test_qgsmetadatabase.py | 750 +- tests/src/python/test_qgsmetadatautils.py | 240 +- tests/src/python/test_qgsmetadatawidget.py | 484 +- .../python/test_qgsmssqlsqlquerybuilder.py | 33 +- .../src/python/test_qgsmultiedittoolbutton.py | 9 +- tests/src/python/test_qgsmultilinestring.py | 170 +- tests/src/python/test_qgsmultipoint.py | 56 +- tests/src/python/test_qgsmultipolygon.py | 348 +- .../python/test_qgsnetworkaccessmanager.py | 31 +- .../python/test_qgsnetworkcontentfetcher.py | 52 +- .../test_qgsnetworkcontentfetcherregistry.py | 45 +- .../test_qgsnetworkcontentfetchertask.py | 18 +- tests/src/python/test_qgsnetworkreply.py | 35 +- .../test_qgsnewgeopackagelayerdialog.py | 111 +- .../python/test_qgsnewvectortabledialog.py | 44 +- tests/src/python/test_qgsnoapplication.py | 11 +- tests/src/python/test_qgsnominatimgeocoder.py | 129 +- .../src/python/test_qgsnullsymbolrenderer.py | 22 +- tests/src/python/test_qgsnumericformat.py | 1248 +- tests/src/python/test_qgsnumericformatgui.py | 57 +- .../python/test_qgsobjectcustomproperties.py | 97 +- tests/src/python/test_qgsogcutils.py | 257 +- tests/src/python/test_qgsopacitywidget.py | 13 +- tests/src/python/test_qgsoptional.py | 21 +- tests/src/python/test_qgsorientedbox3d.py | 336 +- .../src/python/test_qgsoverlaywidgetlayout.py | 177 +- tests/src/python/test_qgsowsconnection.py | 101 +- .../python/test_qgspalettedrasterrenderer.py | 461 +- tests/src/python/test_qgspallabeling_base.py | 114 +- .../src/python/test_qgspallabeling_canvas.py | 22 +- .../src/python/test_qgspallabeling_layout.py | 168 +- .../python/test_qgspallabeling_placement.py | 580 +- .../src/python/test_qgspallabeling_server.py | 95 +- tests/src/python/test_qgspallabeling_tests.py | 103 +- tests/src/python/test_qgspanelwidget.py | 11 +- tests/src/python/test_qgspanelwidgetstack.py | 21 +- tests/src/python/test_qgspathresolver.py | 110 +- tests/src/python/test_qgspdfrenderer.py | 53 +- tests/src/python/test_qgspercentagewidget.py | 7 +- tests/src/python/test_qgsplot.py | 390 +- tests/src/python/test_qgspoint.py | 79 +- ...st_qgspointcloudattributebyramprenderer.py | 262 +- .../test_qgspointcloudattributecombobox.py | 112 +- .../test_qgspointcloudattributemodel.py | 966 +- .../test_qgspointcloudclassifiedrenderer.py | 298 +- .../test_qgspointcloudelevationproperties.py | 53 +- .../test_qgspointcloudextentrenderer.py | 77 +- ...test_qgspointcloudlayerprofilegenerator.py | 1241 +- .../src/python/test_qgspointcloudprovider.py | 264 +- .../python/test_qgspointcloudrgbrenderer.py | 344 +- .../python/test_qgspointclusterrenderer.py | 118 +- .../test_qgspointdisplacementrenderer.py | 289 +- tests/src/python/test_qgspolygon.py | 155 +- tests/src/python/test_qgspolyhedralsurface.py | 118 +- .../src/python/test_qgspolymorphicrelation.py | 176 +- tests/src/python/test_qgspostgresdomain.py | 32 +- .../src/python/test_qgspostgrestransaction.py | 48 +- .../python/test_qgsprocessexecutable_pt1.py | 430 +- .../python/test_qgsprocessexecutable_pt2.py | 440 +- .../src/python/test_qgsprocessingalgrunner.py | 199 +- tests/src/python/test_qgsprocessingbatch.py | 15 +- ...t_qgsprocessingfavoritealgorithmmanager.py | 71 +- tests/src/python/test_qgsprocessinginplace.py | 841 +- .../python/test_qgsprocessingparameters.py | 21 +- .../test_qgsprocessingrecentalgorithmslog.py | 65 +- tests/src/python/test_qgsprocessingutils.py | 85 +- tests/src/python/test_qgsprofileexporter.py | 368 +- tests/src/python/test_qgsprofilepoint.py | 13 +- tests/src/python/test_qgsprofilerequest.py | 67 +- .../python/test_qgsprofilesourceregistry.py | 145 +- tests/src/python/test_qgsproject.py | 916 +- tests/src/python/test_qgsprojectbadlayers.py | 266 +- .../python/test_qgsprojectdisplaysettings.py | 107 +- .../test_qgsprojectelevationproperties.py | 20 +- .../src/python/test_qgsprojectgpssettings.py | 88 +- .../test_qgsprojectionselectionwidgets.py | 352 +- tests/src/python/test_qgsprojectmetadata.py | 400 +- .../python/test_qgsprojectrelationmanager.py | 39 +- .../python/test_qgsprojectservervalidator.py | 66 +- .../python/test_qgsprojectstylesettings.py | 834 +- .../src/python/test_qgsprojecttimesettings.py | 15 +- tests/src/python/test_qgsprojectutils.py | 162 +- .../src/python/test_qgsprojectviewsettings.py | 157 +- tests/src/python/test_qgsproperty.py | 11 +- .../python/test_qgspropertyoverridebutton.py | 116 +- .../python/test_qgsproviderconnection_base.py | 470 +- .../python/test_qgsproviderconnection_hana.py | 132 +- .../test_qgsproviderconnection_mssql.py | 162 +- .../test_qgsproviderconnection_ogr_gpkg.py | 393 +- .../test_qgsproviderconnection_oracle.py | 267 +- .../test_qgsproviderconnection_postgres.py | 554 +- .../test_qgsproviderconnection_spatialite.py | 171 +- .../test_qgsproviderconnectioncombobox.py | 109 +- .../python/test_qgsproviderconnectionmodel.py | 414 +- .../src/python/test_qgsproviderguiregistry.py | 37 +- tests/src/python/test_qgsproviderregistry.py | 249 +- .../python/test_qgsprovidersqlquerybuilder.py | 25 +- .../python/test_qgsprovidersublayerdetails.py | 105 +- .../python/test_qgsprovidersublayermodel.py | 1474 +- .../python/test_qgsprovidersublayertask.py | 33 +- tests/src/python/test_qgsproviderutils.py | 202 +- tests/src/python/test_qgsqueryresultmodel.py | 78 +- .../python/test_qgsrandommarkersymbollayer.py | 140 +- tests/src/python/test_qgsrange.py | 307 +- tests/src/python/test_qgsrangeslider.py | 9 +- tests/src/python/test_qgsrangewidgets.py | 20 +- .../python/test_qgsrasterattributetable.py | 1214 +- .../test_qgsrasterattributetablemodel.py | 229 +- .../test_qgsrasterattributetablewidget.py | 140 +- .../src/python/test_qgsrasterbandcombobox.py | 41 +- tests/src/python/test_qgsrasterblock.py | 8 +- .../python/test_qgsrastercolorrampshader.py | 17 +- .../python/test_qgsrastercontourrenderer.py | 7 +- tests/src/python/test_qgsrasterfilewriter.py | 331 +- .../python/test_qgsrasterfilewritertask.py | 49 +- tests/src/python/test_qgsrasterlayer.py | 848 +- .../test_qgsrasterlayerelevationproperties.py | 444 +- .../test_qgsrasterlayerprofilegenerator.py | 125 +- .../python/test_qgsrasterlayerproperties.py | 50 +- .../src/python/test_qgsrasterlayerrenderer.py | 409 +- .../test_qgsrasterlayertemporalproperties.py | 545 +- tests/src/python/test_qgsrasterlayerutils.py | 270 +- .../python/test_qgsrasterlinesymbollayer.py | 88 +- tests/src/python/test_qgsrasterpipe.py | 20 +- tests/src/python/test_qgsrasterrange.py | 380 +- .../python/test_qgsrasterrendererregistry.py | 40 +- .../src/python/test_qgsrasterrendererutils.py | 64 +- .../test_qgsrasterrerderer_createsld.py | 458 +- tests/src/python/test_qgsrasterresampler.py | 725 +- .../test_qgsrastersinglecolorrenderer.py | 18 +- .../src/python/test_qgsrastertransparency.py | 211 +- .../test_qgsrastertransparencywidget.py | 33 +- tests/src/python/test_qgsratiolockbutton.py | 15 +- tests/src/python/test_qgsreadwritecontext.py | 74 +- ...gsrecentcoordinatereferencesystemsmodel.py | 214 +- tests/src/python/test_qgsrectangle.py | 46 +- .../src/python/test_qgsreferencedgeometry.py | 157 +- tests/src/python/test_qgsrelation.py | 117 +- .../test_qgsrelationeditorwidgetregistry.py | 67 +- .../src/python/test_qgsrelationeditwidget.py | 211 +- tests/src/python/test_qgsrelationmanager.py | 210 +- tests/src/python/test_qgsrelationpostgres.py | 68 +- tests/src/python/test_qgsrendercontext.py | 556 +- .../src/python/test_qgsrendereditemresults.py | 286 +- tests/src/python/test_qgsrenderer.py | 170 +- .../test_qgsrendererrasterpropertieswidget.py | 7 +- tests/src/python/test_qgsreport.py | 844 +- tests/src/python/test_qgsrubberband.py | 5 +- tests/src/python/test_qgsrulebasedrenderer.py | 40 +- .../test_qgsscalebarrendererregistry.py | 43 +- tests/src/python/test_qgsscalebarrenderers.py | 2 +- tests/src/python/test_qgsscalecalculator.py | 15 +- tests/src/python/test_qgsscalewidget.py | 69 +- tests/src/python/test_qgsscreenproperties.py | 24 +- .../python/test_qgssearchwidgettoolbutton.py | 112 +- .../src/python/test_qgssearchwidgetwrapper.py | 755 +- tests/src/python/test_qgsselectioncontext.py | 3 +- tests/src/python/test_qgssensormanager.py | 54 +- tests/src/python/test_qgssensormodel.py | 84 +- tests/src/python/test_qgssensorregistry.py | 40 +- tests/src/python/test_qgsserialportsensor.py | 41 +- tests/src/python/test_qgsserver.py | 479 +- .../python/test_qgsserver_accesscontrol.py | 121 +- ...est_qgsserver_accesscontrol_fix_filters.py | 67 +- .../test_qgsserver_accesscontrol_wcs.py | 206 +- .../test_qgsserver_accesscontrol_wfs.py | 927 +- ...sserver_accesscontrol_wfs_transactional.py | 158 +- .../test_qgsserver_accesscontrol_wms.py | 1543 +- ...rver_accesscontrol_wms_getlegendgraphic.py | 144 +- ...erver_accesscontrol_wms_getmap_postgres.py | 330 +- ...ver_accesscontrol_wms_getprint_postgres.py | 264 +- tests/src/python/test_qgsserver_api.py | 2805 ++-- tests/src/python/test_qgsserver_apicontext.py | 21 +- .../src/python/test_qgsserver_cachemanager.py | 492 +- .../src/python/test_qgsserver_configcache.py | 45 +- .../src/python/test_qgsserver_landingpage.py | 200 +- .../python/test_qgsserver_locale_override.py | 33 +- tests/src/python/test_qgsserver_modules.py | 17 +- tests/src/python/test_qgsserver_plugins.py | 149 +- .../src/python/test_qgsserver_projectutils.py | 51 +- tests/src/python/test_qgsserver_request.py | 349 +- tests/src/python/test_qgsserver_response.py | 35 +- tests/src/python/test_qgsserver_security.py | 135 +- .../python/test_qgsserver_service_url_env.py | 51 +- tests/src/python/test_qgsserver_services.py | 11 +- tests/src/python/test_qgsserver_settings.py | 9 +- tests/src/python/test_qgsserver_wfs.py | 1243 +- tests/src/python/test_qgsserver_wfst.py | 206 +- tests/src/python/test_qgsserver_wms.py | 529 +- .../python/test_qgsserver_wms_dimension.py | 687 +- tests/src/python/test_qgsserver_wms_dxf.py | 59 +- ...gsserver_wms_getcapabilities_group_name.py | 83 +- .../test_qgsserver_wms_getfeatureinfo.py | 1833 ++- ...t_qgsserver_wms_getfeatureinfo_postgres.py | 486 +- .../test_qgsserver_wms_getlegendgraphic.py | 2594 +-- tests/src/python/test_qgsserver_wms_getmap.py | 4092 +++-- ..._qgsserver_wms_getmap_ignore_bad_layers.py | 66 +- .../test_qgsserver_wms_getmap_size_project.py | 48 +- .../test_qgsserver_wms_getmap_size_server.py | 19 +- .../src/python/test_qgsserver_wms_getprint.py | 633 +- .../test_qgsserver_wms_getprint_atlas.py | 73 +- .../test_qgsserver_wms_getprint_extra.py | 280 +- .../test_qgsserver_wms_getprint_legend.py | 97 +- .../test_qgsserver_wms_getprint_maptheme.py | 169 +- .../test_qgsserver_wms_getprint_outputs.py | 200 +- tests/src/python/test_qgsserver_wmts.py | 544 +- tests/src/python/test_qgsserverlogger.py | 13 +- tests/src/python/test_qgssettings.py | 689 +- .../python/test_qgssettingseditorregistry.py | 20 +- tests/src/python/test_qgssettingsentry.py | 262 +- tests/src/python/test_qgssettingsregistry.py | 19 +- tests/src/python/test_qgssettingstreenode.py | 138 +- tests/src/python/test_qgsshortcutsmanager.py | 411 +- .../python/test_qgssimplefillsymbollayer.py | 86 +- .../python/test_qgssimplelinesymbollayer.py | 339 +- .../test_qgssinglebandcolordatarenderer.py | 7 +- .../python/test_qgssinglebandgrayrenderer.py | 13 +- .../test_qgssinglebandpseudocolorrenderer.py | 13 +- tests/src/python/test_qgssingleitemmodel.py | 95 +- .../python/test_qgssinglesymbolrenderer.py | 46 +- .../python/test_qgssourceselectprovider.py | 127 +- .../test_qgssourcewidgetproviderregistry.py | 43 +- tests/src/python/test_qgsspatialindex.py | 21 +- tests/src/python/test_qgssphere.py | 20 +- tests/src/python/test_qgssqlstatement.py | 220 +- .../test_qgsstringstatisticalsummary.py | 142 +- tests/src/python/test_qgsstringutils.py | 419 +- tests/src/python/test_qgsstylemodel.py | 4956 ++++-- ...t_qgssubsetstringeditorproviderregistry.py | 58 +- tests/src/python/test_qgssvgcache.py | 219 +- tests/src/python/test_qgssvgsourcelineedit.py | 49 +- tests/src/python/test_qgssymbol.py | 1456 +- .../test_qgssymbolbuffersettingswidget.py | 12 +- tests/src/python/test_qgssymbolbutton.py | 13 +- .../test_qgssymbolexpressionvariables.py | 65 +- tests/src/python/test_qgssymbollayer.py | 346 +- .../python/test_qgssymbollayer_createsld.py | 827 +- .../src/python/test_qgssymbollayer_readsld.py | 169 +- .../src/python/test_qgssymbollayerregistry.py | 20 +- tests/src/python/test_qgssymbollayerutils.py | 1204 +- tests/src/python/test_qgstablecell.py | 27 +- tests/src/python/test_qgstabwidget.py | 22 +- tests/src/python/test_qgstaskmanager.py | 151 +- tests/src/python/test_qgstemporalutils.py | 568 +- tests/src/python/test_qgsterrainprovider.py | 37 +- tests/src/python/test_qgstextblock.py | 107 +- tests/src/python/test_qgstextblockformat.py | 21 +- .../src/python/test_qgstextcharacterformat.py | 54 +- tests/src/python/test_qgstextdocument.py | 571 +- tests/src/python/test_qgstextformat.py | 731 +- tests/src/python/test_qgstextformatwidget.py | 112 +- tests/src/python/test_qgstextfragment.py | 43 +- tests/src/python/test_qgstextrenderer.py | 3746 +++-- .../test_qgstiledsceneboundingvolume.py | 1 + .../test_qgstiledsceneelevationproperties.py | 24 +- tests/src/python/test_qgstiledscenelayer.py | 107 +- tests/src/python/test_qgstiledscenerender.py | 1 + tests/src/python/test_qgstiledscenerequest.py | 33 +- tests/src/python/test_qgstiledscenetile.py | 25 +- tests/src/python/test_qgstiles.py | 720 +- tests/src/python/test_qgstreewidgetitem.py | 68 +- .../src/python/test_qgstriangulatedsurface.py | 23 +- tests/src/python/test_qgsunittypes.py | 2036 ++- .../src/python/test_qgsunsetattributevalue.py | 54 +- tests/src/python/test_qgsvaliditychecks.py | 95 +- .../python/test_qgsvalidityresultswidget.py | 97 +- tests/src/python/test_qgsvariantutils.py | 10 +- .../test_qgsvectorfieldmarkersymbollayer.py | 136 +- tests/src/python/test_qgsvectorfilewriter.py | 1773 +- .../test_qgsvectorfilewriter_postgres.py | 38 +- .../python/test_qgsvectorfilewritertask.py | 40 +- tests/src/python/test_qgsvectorlayer.py | 2627 ++- .../python/test_qgsvectorlayer_namedstyle.py | 32 +- tests/src/python/test_qgsvectorlayercache.py | 97 +- .../python/test_qgsvectorlayereditbuffer.py | 204 +- .../test_qgsvectorlayereditbuffergroup.py | 191 +- .../python/test_qgsvectorlayereditutils.py | 396 +- .../test_qgsvectorlayerelevationproperties.py | 106 +- .../test_qgsvectorlayerfeaturecounter.py | 96 +- .../test_qgsvectorlayerprofilegenerator.py | 2273 ++- .../src/python/test_qgsvectorlayerrenderer.py | 592 +- .../python/test_qgsvectorlayersaveasdialog.py | 17 +- ...est_qgsvectorlayerselectedfeaturesource.py | 114 +- .../python/test_qgsvectorlayershapefile.py | 19 +- .../test_qgsvectorlayertemporalproperties.py | 1188 +- tests/src/python/test_qgsvectorlayertools.py | 39 +- tests/src/python/test_qgsvectorlayerutils.py | 571 +- .../test_qgsvectorlayerutils_postgres.py | 32 +- tests/src/python/test_qgsvectortile.py | 385 +- tests/src/python/test_qgsvectorwarper.py | 90 +- .../python/test_qgsvirtuallayerdefinition.py | 108 +- tests/src/python/test_qgsvirtuallayertask.py | 24 +- tests/src/python/test_qgsvtpk.py | 288 +- tests/src/python/test_qgswebenginepage.py | 70 +- tests/src/python/test_qgsxmlutils.py | 104 +- tests/src/python/test_qgsziputils.py | 59 +- tests/src/python/test_qgszonalstatistics.py | 93 +- tests/src/python/test_selective_masking.py | 1035 +- tests/src/python/test_stylestorage_gpkg.py | 12 +- tests/src/python/test_stylestorage_mssql.py | 22 +- tests/src/python/test_stylestorage_oracle.py | 28 +- .../src/python/test_stylestorage_postgres.py | 22 +- .../python/test_stylestorage_spatialite.py | 21 +- tests/src/python/test_syntactic_sugar.py | 34 +- tests/src/python/test_testrunner.py | 20 +- tests/src/python/test_versioncompare.py | 31 +- tests/src/python/utilities.py | 185 +- tests/testdata/complex_names.py | 43 +- tests/testdata/convert_to_upper.py | 28 +- tests/testdata/not_a_processing_script.py | 2 +- .../qgis_local_server/layer_attribute_form.py | 6 +- .../report_style_initialization_status.py | 19 +- .../PluginPathTest/__init__.py | 8 +- .../ProcessingPluginTest/__init__.py | 6 +- .../ProcessingPluginTest2/__init__.py | 6 +- .../dependent_plugin_1/__init__.py | 2 +- .../dependent_plugin_2/__init__.py | 2 +- .../default/python/expressions/test.py | 2 +- .../default/python/expressions/test2.py | 2 +- 1150 files changed, 183280 insertions(+), 97511 deletions(-) diff --git a/.ci/ctest2ci.py b/.ci/ctest2ci.py index 9a6ee626ef7a..4ccd9f94e1b6 100755 --- a/.ci/ctest2ci.py +++ b/.ci/ctest2ci.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- """ *************************************************************************** @@ -18,42 +17,47 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'March 2017' -__copyright__ = '(C) 2017, Matthias Kuhn' +__author__ = "Matthias Kuhn" +__date__ = "March 2017" +__copyright__ = "(C) 2017, Matthias Kuhn" # This script parses output from ctest and injects # # - Colors for failing unit tests and test cases # - Group control sequences to hide uninteresting output by default -import sys import re +import string import subprocess +import sys + from termcolor import colored -import string fold_stack = list() printable = set(string.printable) def start_fold(tag): - sys.stdout.write('::group::{}\n'.format(tag)) + sys.stdout.write(f"::group::{tag}\n") fold_stack.append(tag) def end_fold(): try: tag = fold_stack.pop() - sys.stdout.write('::endgroup::\n') + sys.stdout.write("::endgroup::\n") except IndexError: - updated_line = colored("======================", 'magenta') - updated_line += colored("ctest2ci error when processing the following line:", 'magenta') - updated_line += colored("----------------------", 'magenta') - updated_line += colored(updated_line, 'magenta') - updated_line += colored("----------------------", 'magenta') - updated_line += colored("Tried to end fold, but fold was never started.", 'magenta') - updated_line += colored("======================", 'magenta') + updated_line = colored("======================", "magenta") + updated_line += colored( + "ctest2ci error when processing the following line:", "magenta" + ) + updated_line += colored("----------------------", "magenta") + updated_line += colored(updated_line, "magenta") + updated_line += colored("----------------------", "magenta") + updated_line += colored( + "Tried to end fold, but fold was never started.", "magenta" + ) + updated_line += colored("======================", "magenta") test_count = 0 @@ -61,8 +65,8 @@ def end_fold(): def start_test_fold(): global test_count - sys.stdout.write('Running tests\n') - start_fold('test.{}'.format(test_count)) + sys.stdout.write("Running tests\n") + start_fold(f"test.{test_count}") test_count += 1 @@ -72,55 +76,61 @@ def start_test_fold(): p = subprocess.Popen(sys.argv[1:], stdout=subprocess.PIPE) for line in p.stdout: - updated_line = line.decode('utf-8') + updated_line = line.decode("utf-8") # remove non printable characters https://stackoverflow.com/a/8689826/1548052 filter(lambda x: x in printable, updated_line) - if re.match('Run dashboard with model Experimental', updated_line): - start_fold('Run tests') - updated_line = '{title}\n{line}'.format(title=colored('Running tests...', 'yellow', attrs=['bold']), - line=updated_line) - - elif re.match('Test project /home/runner/QGIS/QGIS/build', updated_line): + if re.match("Run dashboard with model Experimental", updated_line): + start_fold("Run tests") + updated_line = "{title}\n{line}".format( + title=colored("Running tests...", "yellow", attrs=["bold"]), + line=updated_line, + ) + + elif re.match("Test project /home/runner/QGIS/QGIS/build", updated_line): end_fold() # tag=Run tests start_test_fold() - if re.search(r'\*\*\*Failed', updated_line) or re.search(r'\*\*\*Timeout', updated_line): + if re.search(r"\*\*\*Failed", updated_line) or re.search( + r"\*\*\*Timeout", updated_line + ): end_fold() - updated_line = colored(updated_line, 'red') + updated_line = colored(updated_line, "red") in_failing_test = True if in_failing_test: - if re.match(' Start', updated_line): + if re.match(" Start", updated_line): start_test_fold() in_failing_test = False elif in_failure: - if re.match('PASS', updated_line) or re.match('Ran', updated_line): + if re.match("PASS", updated_line) or re.match("Ran", updated_line): in_failure = False else: - updated_line = colored(updated_line, 'yellow') - elif re.search(r'\*\*\* Segmentation fault', updated_line): - start_fold('segfault') - updated_line = colored(updated_line, 'magenta') - elif re.match(' Test failed: Segmentation fault', updated_line): + updated_line = colored(updated_line, "yellow") + elif re.search(r"\*\*\* Segmentation fault", updated_line): + start_fold("segfault") + updated_line = colored(updated_line, "magenta") + elif re.match(" Test failed: Segmentation fault", updated_line): end_fold() else: - if re.match(r'(FAIL|ERROR)[:\!].*', updated_line): - updated_line = colored(updated_line, 'yellow') + if re.match(r"(FAIL|ERROR)[:\!].*", updated_line): + updated_line = colored(updated_line, "yellow") in_failure = True - if not in_failing_test and re.search('[0-9]+% tests passed, [0-9]+ tests failed out of', updated_line): - tests_failing = re.match(r'.* ([0-9]+) tests failed', updated_line).group(1) + if not in_failing_test and re.search( + "[0-9]+% tests passed, [0-9]+ tests failed out of", updated_line + ): + tests_failing = re.match(r".* ([0-9]+) tests failed", updated_line).group(1) # updated_line += '\n::set-output name=TESTS_FAILING::{}'.format(tests_failing) end_fold() - if re.search('100% tests passed', updated_line): - updated_line = colored(updated_line, 'green') + if re.search("100% tests passed", updated_line): + updated_line = colored(updated_line, "green") - if re.match('Submit files', updated_line): - start_fold('submit') - elif re.search('Test results submitted to', updated_line): - cdash_url = re.match(r'.*(http.*)$', updated_line).group(1) + if re.match("Submit files", updated_line): + start_fold("submit") + elif re.search("Test results submitted to", updated_line): + cdash_url = re.match(r".*(http.*)$", updated_line).group(1) # updated_line += '\n::set-output name=CDASH_URL::{}'.format(cdash_url) end_fold() diff --git a/.ci/pr_has_label.py b/.ci/pr_has_label.py index c2475e8d2620..d2a8aca7a98f 100755 --- a/.ci/pr_has_label.py +++ b/.ci/pr_has_label.py @@ -1,34 +1,37 @@ #!/usr/bin/env python3 -import sys +import argparse import json -from urllib.request import urlopen # using urllib since it is a standard module (vs. requests) +import sys + from urllib.error import URLError -import argparse +from urllib.request import ( # using urllib since it is a standard module (vs. requests) + urlopen, +) -parser = argparse.ArgumentParser(description='Determines if a pull request has a defined label') -parser.add_argument('pull_request', type=str, - help='pull request id') -parser.add_argument('label', type=int, - help='label ID') +parser = argparse.ArgumentParser( + description="Determines if a pull request has a defined label" +) +parser.add_argument("pull_request", type=str, help="pull request id") +parser.add_argument("label", type=int, help="label ID") args = parser.parse_args() -if args.pull_request == 'false': +if args.pull_request == "false": print("false") sys.exit(1) -url = "https://api.github.com/repos/qgis/QGIS/pulls/{}".format(args.pull_request) +url = f"https://api.github.com/repos/qgis/QGIS/pulls/{args.pull_request}" try: - data = urlopen(url).read().decode('utf-8') + data = urlopen(url).read().decode("utf-8") except URLError as err: - print("URLError: {}".format(err.reason)) + print(f"URLError: {err.reason}") sys.exit(1) obj = json.loads(data) -for label in obj['labels']: +for label in obj["labels"]: if label["id"] == args.label: print("true") sys.exit(0) diff --git a/.docker/qgis_resources/test_runner/qgis_startup.py b/.docker/qgis_resources/test_runner/qgis_startup.py index 94c07906f0e4..6475604e883a 100644 --- a/.docker/qgis_resources/test_runner/qgis_startup.py +++ b/.docker/qgis_resources/test_runner/qgis_startup.py @@ -6,16 +6,18 @@ ~/.qgis3/python/startup.py """ -from qgis.core import Qgis -from qgis import utils + import traceback +from qgis import utils +from qgis.core import Qgis + def _showException(type, value, tb, msg, messagebar=False, level=Qgis.Warning): print(msg) - logmessage = '' + logmessage = "" for s in traceback.format_exception(type, value, tb): - logmessage += s.decode('utf-8', 'replace') if hasattr(s, 'decode') else s + logmessage += s.decode("utf-8", "replace") if hasattr(s, "decode") else s print(logmessage) diff --git a/.docker/qgis_resources/test_runner/qgis_testrunner.py b/.docker/qgis_resources/test_runner/qgis_testrunner.py index a04b9295ea35..7173a93c1da0 100755 --- a/.docker/qgis_resources/test_runner/qgis_testrunner.py +++ b/.docker/qgis_resources/test_runner/qgis_testrunner.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ *************************************************************************** @@ -42,18 +41,19 @@ *************************************************************************** """ -__author__ = 'Alessandro Pasotti' -__date__ = 'May 2016' +__author__ = "Alessandro Pasotti" +__date__ = "May 2016" +import importlib import os import re +import signal import sys import traceback -import signal -import importlib -from pexpect import run -from pipes import quote +from shlex import quote + +from pexpect import run from qgis.utils import iface @@ -68,14 +68,17 @@ def __get_test_function(test_module_name): print("QGIS Test Runner - Trying to import %s" % test_module_name) try: test_module = importlib.import_module(test_module_name) - function_name = 'run_all' + function_name = "run_all" except ImportError as e: # traceback.print_exc(file=sys.stdout) # Strip latest name - pos = test_module_name.rfind('.') + pos = test_module_name.rfind(".") if pos <= 0: raise e - test_module_name, function_name = test_module_name[:pos], test_module_name[pos + 1:] + test_module_name, function_name = ( + test_module_name[:pos], + test_module_name[pos + 1 :], + ) print("QGIS Test Runner - Trying to import %s" % test_module_name) sys.stdout.flush() try: @@ -93,47 +96,55 @@ def __get_test_function(test_module_name): sys.path.append(os.getcwd()) test_module_name = sys.argv[-1] if __get_test_function(test_module_name) is None: - print("QGIS Test Runner - [ERROR] cannot load test function from %s" % test_module_name) + print( + "QGIS Test Runner - [ERROR] cannot load test function from %s" + % test_module_name + ) sys.exit(1) try: me = __file__ except NameError: me = sys.argv[0] - os.environ['QGIS_DEBUG'] = '1' + os.environ["QGIS_DEBUG"] = "1" args = [ - 'qgis', - os.environ.get('QGIS_EXTRA_OPTIONS', ''), - '--nologo', - '--noversioncheck', - '--code', + "qgis", + os.environ.get("QGIS_EXTRA_OPTIONS", ""), + "--nologo", + "--noversioncheck", + "--code", me, test_module_name, # Must be the last one! ] - command_line = ' '.join(args) + command_line = " ".join(args) print("QGIS Test Runner - launching QGIS as %s ..." % command_line) out, returncode = run("sh -c " + quote(command_line), withexitstatus=1) if isinstance(out, bytes): out = out.decode("utf-8") assert returncode is not None print("QGIS Test Runner - QGIS exited.") - ok = out.find('(failures=') < 0 and \ - len(re.findall(r'Ran \d+ tests in\s', - out, re.MULTILINE)) > 0 - print('=' * 60) + ok = ( + out.find("(failures=") < 0 + and len(re.findall(r"Ran \d+ tests in\s", out, re.MULTILINE)) > 0 + ) + print("=" * 60) if not ok: print(out) else: eprint(out) if len(out) == 0: print("QGIS Test Runner - [WARNING] subprocess returned no output") - print('=' * 60) + print("=" * 60) - print("QGIS Test Runner - %s bytes returned and finished with exit code: %s" % (len(out), 0 if ok else 1)) + print( + "QGIS Test Runner - {} bytes returned and finished with exit code: {}".format( + len(out), 0 if ok else 1 + ) + ) sys.exit(0 if ok else 1) else: # We are inside QGIS! # Start as soon as the initializationCompleted signal is fired - from qgis.core import QgsApplication, QgsProjectBadLayerHandler, QgsProject + from qgis.core import QgsApplication, QgsProject, QgsProjectBadLayerHandler from qgis.PyQt.QtCore import QDir from qgis.utils import iface diff --git a/.github/actions/vcpkg_update_report/vcpkg-diff.py b/.github/actions/vcpkg_update_report/vcpkg-diff.py index bc895b038b6c..21ff42ef772f 100644 --- a/.github/actions/vcpkg_update_report/vcpkg-diff.py +++ b/.github/actions/vcpkg_update_report/vcpkg-diff.py @@ -89,7 +89,7 @@ def read_file(file_path): """ Read the content of a file. """ - with open(file_path, "r") as file: + with open(file_path) as file: return file.read() diff --git a/cmake/FindPyQt5.py b/cmake/FindPyQt5.py index fe029af9faca..39d3b246c43d 100644 --- a/cmake/FindPyQt5.py +++ b/cmake/FindPyQt5.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # Copyright (c) 2007, Simon Edwards # All rights reserved. @@ -31,16 +30,19 @@ # For details see the accompanying COPYING-CMAKE-SCRIPTS file. import os.path +import sys + import PyQt5.QtCore import sipconfig -import sys cfg = sipconfig.Configuration() sip_dir = cfg.default_sip_dir -for p in (os.path.join(sip_dir, "PyQt5"), - os.path.join(sip_dir, "PyQt5-3"), - sip_dir, - os.path.join(cfg.default_mod_dir, "PyQt5", "bindings")): +for p in ( + os.path.join(sip_dir, "PyQt5"), + os.path.join(sip_dir, "PyQt5-3"), + sip_dir, + os.path.join(cfg.default_mod_dir, "PyQt5", "bindings"), +): if os.path.exists(os.path.join(p, "QtCore", "QtCoremod.sip")): sip_dir = p break @@ -48,7 +50,7 @@ print("pyqt_version_str:%s" % PyQt5.QtCore.PYQT_VERSION_STR) print("pyqt_mod_dir:%s" % os.path.join(cfg.default_mod_dir, "PyQt5")) print("pyqt_sip_dir:%s" % sip_dir) -print("pyqt_sip_flags:%s" % PyQt5.QtCore.PYQT_CONFIGURATION['sip_flags']) +print("pyqt_sip_flags:%s" % PyQt5.QtCore.PYQT_CONFIGURATION["sip_flags"]) print("pyqt_bin_dir:%s" % cfg.default_bin_dir) try: diff --git a/cmake/FindPyQt6.py b/cmake/FindPyQt6.py index de735d467a18..8a149f4f1aba 100644 --- a/cmake/FindPyQt6.py +++ b/cmake/FindPyQt6.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # Copyright (c) 2007, Simon Edwards # All rights reserved. @@ -31,16 +30,19 @@ # For details see the accompanying COPYING-CMAKE-SCRIPTS file. import os.path +import sys + import PyQt6.QtCore import sipconfig -import sys cfg = sipconfig.Configuration() sip_dir = cfg.default_sip_dir -for p in (os.path.join(sip_dir, "PyQt6"), - os.path.join(sip_dir, "PyQt6-3"), - sip_dir, - os.path.join(cfg.default_mod_dir, "PyQt6", "bindings")): +for p in ( + os.path.join(sip_dir, "PyQt6"), + os.path.join(sip_dir, "PyQt6-3"), + sip_dir, + os.path.join(cfg.default_mod_dir, "PyQt6", "bindings"), +): if os.path.exists(os.path.join(p, "QtCore", "QtCoremod.sip")): sip_dir = p break diff --git a/cmake/FindQsci.py b/cmake/FindQsci.py index f74f7c5201e9..de104ba5b105 100644 --- a/cmake/FindQsci.py +++ b/cmake/FindQsci.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # Copyright (c) 2012, Larry Shaffer # All rights reserved. @@ -30,9 +29,9 @@ .. note:: Redistribution and use is allowed according to the terms of the BSD license. For details see the accompanying COPYING-CMAKE-SCRIPTS file. """ -__author__ = 'Larry Shaffer (larry@dakotacarto.com)' -__date__ = '22/10/2012' -__copyright__ = 'Copyright 2012, The QGIS Project' +__author__ = "Larry Shaffer (larry@dakotacarto.com)" +__date__ = "22/10/2012" +__copyright__ = "Copyright 2012, The QGIS Project" import sys @@ -40,24 +39,30 @@ if len(sys.argv) > 0: if sys.argv[1] == "4": from PyQt4.Qsci import QSCINTILLA_VERSION_STR + VER = QSCINTILLA_VERSION_STR if sys.argv[1] == "5": from PyQt5.Qsci import QSCINTILLA_VERSION_STR + VER = QSCINTILLA_VERSION_STR else: from PyQt6.Qsci import QSCINTILLA_VERSION_STR + VER = QSCINTILLA_VERSION_STR else: try: from PyQt4.Qsci import QSCINTILLA_VERSION_STR + VER = QSCINTILLA_VERSION_STR except ImportError: try: from PyQt5.Qsci import QSCINTILLA_VERSION_STR + VER = QSCINTILLA_VERSION_STR except ImportError: try: from PyQt6.Qsci import QSCINTILLA_VERSION_STR + VER = QSCINTILLA_VERSION_STR except ImportError: pass diff --git a/cmake/FindSIP.py b/cmake/FindSIP.py index 2e8eea04bb56..01ff1469528e 100644 --- a/cmake/FindSIP.py +++ b/cmake/FindSIP.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # Copyright (c) 2007, Simon Edwards # All rights reserved. @@ -38,6 +37,7 @@ print("sip_version_str:%s" % sipbuild.version.SIP_VERSION_STR) import sysconfig + if "deb_system" in sysconfig.get_scheme_names(): python_modules_dir = sysconfig.get_path("purelib", "deb_system") else: diff --git a/cmake/PythonCompile.py b/cmake/PythonCompile.py index 4117aa77065b..a20e9f7c187b 100644 --- a/cmake/PythonCompile.py +++ b/cmake/PythonCompile.py @@ -1,6 +1,5 @@ -# -*- coding: utf-8 -*- - # By Simon Edwards # This file is in the public domain. import py_compile + py_compile.main() diff --git a/python/PyQt6/core/additions/edit.py b/python/PyQt6/core/additions/edit.py index 92756d1e8953..b82f268ea0a9 100644 --- a/python/PyQt6/core/additions/edit.py +++ b/python/PyQt6/core/additions/edit.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** edit.py @@ -17,8 +15,6 @@ *************************************************************************** """ -from builtins import object - class QgsEditError(Exception): @@ -29,7 +25,7 @@ def __str__(self): return repr(self.value) -class edit(object): +class edit: def __init__(self, layer): self.layer = layer diff --git a/python/PyQt6/core/additions/fromfunction.py b/python/PyQt6/core/additions/fromfunction.py index 92c3647449b5..7bbe1761a975 100644 --- a/python/PyQt6/core/additions/fromfunction.py +++ b/python/PyQt6/core/additions/fromfunction.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** fromfunction.py @@ -23,36 +21,38 @@ @staticmethod -def _fromFunction(description: str, - function: _typing.Callable, - *args, - on_finished: _typing.Optional[_typing.Callable] = None, - flags=QgsTask.Flag.AllFlags, - **kwargs) -> QgsTask: +def _fromFunction( + description: str, + function: _typing.Callable, + *args, + on_finished: _typing.Optional[_typing.Callable] = None, + flags=QgsTask.Flag.AllFlags, + **kwargs +) -> QgsTask: """ -Creates a new QgsTask task from a python function. + Creates a new QgsTask task from a python function. -Example -------- + Example + ------- -.. code-block:: python + .. code-block:: python - def calculate(task): - # pretend this is some complex maths and stuff we want - # to run in the background - return 5*6 + def calculate(task): + # pretend this is some complex maths and stuff we want + # to run in the background + return 5*6 - def calculation_finished(exception, value=None): - if not exception: - iface.messageBar().pushMessage( - 'the magic number is {}'.format(value)) - else: - iface.messageBar().pushMessage( - str(exception)) + def calculation_finished(exception, value=None): + if not exception: + iface.messageBar().pushMessage( + 'the magic number is {}'.format(value)) + else: + iface.messageBar().pushMessage( + str(exception)) - task = QgsTask.fromFunction('my task', calculate, - on_finished=calculation_finished) - QgsApplication.taskManager().addTask(task) + task = QgsTask.fromFunction('my task', calculate, + on_finished=calculation_finished) + QgsApplication.taskManager().addTask(task) """ diff --git a/python/PyQt6/core/additions/metaenum.py b/python/PyQt6/core/additions/metaenum.py index dac7b1b1c464..0d1fb6b39683 100644 --- a/python/PyQt6/core/additions/metaenum.py +++ b/python/PyQt6/core/additions/metaenum.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** metaenum.py @@ -61,7 +59,9 @@ def metaEnumFromType(enumClass, baseClass=None, raiseException=True): return metaEnumFromType(enumClass, baseClass, raiseException) except AttributeError: if raiseException: - raise ValueError("Enum type does not implement baseClass method. Provide the base class as argument.") + raise ValueError( + "Enum type does not implement baseClass method. Provide the base class as argument." + ) try: meta_object = baseClass.staticMetaObject @@ -71,7 +71,7 @@ def metaEnumFromType(enumClass, baseClass=None, raiseException=True): META_ENUM_BY_ENUM_CLASS[enumClass] = meta_enum except AttributeError: if raiseException: - raise TypeError("could not get the metaEnum for {}".format(enumClass.__name__)) + raise TypeError(f"could not get the metaEnum for {enumClass.__name__}") meta_enum = None return meta_enum diff --git a/python/PyQt6/core/additions/projectdirtyblocker.py b/python/PyQt6/core/additions/projectdirtyblocker.py index 7f06bd0a8412..95cec0432a79 100644 --- a/python/PyQt6/core/additions/projectdirtyblocker.py +++ b/python/PyQt6/core/additions/projectdirtyblocker.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** projectdirtyblocker.py @@ -17,11 +15,10 @@ *************************************************************************** """ - from qgis._core import QgsProjectDirtyBlocker -class ProjectDirtyBlocker(): +class ProjectDirtyBlocker: """ Context manager used to block project setDirty calls. diff --git a/python/PyQt6/core/additions/providermetadata.py b/python/PyQt6/core/additions/providermetadata.py index d188f6e26fde..b1a676c37386 100644 --- a/python/PyQt6/core/additions/providermetadata.py +++ b/python/PyQt6/core/additions/providermetadata.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** providermetadata.py @@ -21,12 +19,12 @@ class PyProviderMetadata(QgsProviderMetadata): - """ wrapper around QgsProviderMetadata to keep the existing Python code running which registers - data providers by passing a custom python createProvider() function to QgsProviderMetadata - constructor. The proper new way of doing it is to subclass QgsProviderMetadata and implement - its virtual functions. + """wrapper around QgsProviderMetadata to keep the existing Python code running which registers + data providers by passing a custom python createProvider() function to QgsProviderMetadata + constructor. The proper new way of doing it is to subclass QgsProviderMetadata and implement + its virtual functions. - TODO: QGIS 4 - remove this wrapper (only subclassing of QgsProviderMetadata should be used) + TODO: QGIS 4 - remove this wrapper (only subclassing of QgsProviderMetadata should be used) """ # this is a workaround to keep references to metadata classes diff --git a/python/PyQt6/core/additions/qgsfeature.py b/python/PyQt6/core/additions/qgsfeature.py index 252a89fc010e..b3dcef297db1 100644 --- a/python/PyQt6/core/additions/qgsfeature.py +++ b/python/PyQt6/core/additions/qgsfeature.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** qgsfeature.py @@ -22,6 +20,8 @@ def _mapping_feature(feature): geom = feature.geometry() fields = [field.name() for field in feature.fields()] properties = dict(list(zip(fields, feature.attributes()))) - return {'type': 'Feature', - 'properties': properties, - 'geometry': geom.__geo_interface__} + return { + "type": "Feature", + "properties": properties, + "geometry": geom.__geo_interface__, + } diff --git a/python/PyQt6/core/additions/qgsfunction.py b/python/PyQt6/core/additions/qgsfunction.py index e91e25a7fc0b..32a338dac291 100644 --- a/python/PyQt6/core/additions/qgsfunction.py +++ b/python/PyQt6/core/additions/qgsfunction.py @@ -15,13 +15,18 @@ *************************************************************************** """ - import inspect import string import traceback from qgis.PyQt.QtCore import QCoreApplication -from qgis._core import QgsExpressionFunction, QgsExpression, QgsMessageLog, QgsFeatureRequest, Qgis +from qgis._core import ( + QgsExpressionFunction, + QgsExpression, + QgsMessageLog, + QgsFeatureRequest, + Qgis, +) class QgsPyExpressionFunction(QgsExpressionFunction): @@ -143,7 +148,8 @@ def register_function( if not QgsExpression.unregisterFunction(name): msgtitle = QCoreApplication.translate("UserExpressions", "User expressions") msg = QCoreApplication.translate( - "UserExpressions", "The user expression {0} already exists and could not be unregistered." + "UserExpressions", + "The user expression {0} already exists and could not be unregistered.", ).format(name) QgsMessageLog.logMessage(msg + "\n", msgtitle, Qgis.MessageLevel.Warning) return None @@ -154,7 +160,14 @@ def register_function( # Legacy: if args was not 'auto', parameters were passed as a list params_as_list = params_as_list or args != "auto" f = QgsPyExpressionFunction( - function, name, group, helptext, usesgeometry, referenced_columns, handlesnull, params_as_list + function, + name, + group, + helptext, + usesgeometry, + referenced_columns, + handlesnull, + params_as_list, ) if register: diff --git a/python/PyQt6/core/additions/qgsgeometry.py b/python/PyQt6/core/additions/qgsgeometry.py index 6d2babfe1f03..63dbdeb5ccd7 100644 --- a/python/PyQt6/core/additions/qgsgeometry.py +++ b/python/PyQt6/core/additions/qgsgeometry.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** qgsgeometry.py diff --git a/python/PyQt6/core/additions/qgssettings.py b/python/PyQt6/core/additions/qgssettings.py index a8190a31c7c9..8140211df44c 100644 --- a/python/PyQt6/core/additions/qgssettings.py +++ b/python/PyQt6/core/additions/qgssettings.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** qgssettings.py @@ -22,7 +20,9 @@ import qgis # required to get base class of enums -def _qgssettings_enum_value(self, key, enumDefaultValue, section=QgsSettings.Section.NoSection): +def _qgssettings_enum_value( + self, key, enumDefaultValue, section=QgsSettings.Section.NoSection +): """ Return the setting value for a setting based on an enum. This forces the output to be a valid and existing entry of the enum. @@ -41,8 +41,11 @@ def _qgssettings_enum_value(self, key, enumDefaultValue, section=QgsSettings.Sec meta_enum = metaEnumFromValue(enumDefaultValue) if meta_enum is None or not meta_enum.isValid(): # this should not happen - raise ValueError("could not get the meta enum for given enum default value (type: {})" - .format(enumDefaultValue.__class__)) + raise ValueError( + "could not get the meta enum for given enum default value (type: {})".format( + enumDefaultValue.__class__ + ) + ) str_val = self.value(key, meta_enum.valueToKey(enumDefaultValue), str, section) # need a new meta enum as QgsSettings.value is making a copy and leads to seg fault (probably a PyQt issue) @@ -58,7 +61,9 @@ def _qgssettings_enum_value(self, key, enumDefaultValue, section=QgsSettings.Sec return enu_val -def _qgssettings_set_enum_value(self, key, enumValue, section=QgsSettings.Section.NoSection): +def _qgssettings_set_enum_value( + self, key, enumValue, section=QgsSettings.Section.NoSection +): """ Save the setting value for a setting based on an enum. This forces the output to be a valid and existing entry of the enum. @@ -76,12 +81,16 @@ def _qgssettings_set_enum_value(self, key, enumValue, section=QgsSettings.Sectio meta_enum = metaEnumFromValue(enumValue) if meta_enum is None or not meta_enum.isValid(): # this should not happen - raise ValueError("could not get the meta enum for given enum default value (type: {})".format(type(enumValue))) + raise ValueError( + f"could not get the meta enum for given enum default value (type: {type(enumValue)})" + ) self.setValue(key, meta_enum.valueToKey(enumValue), section) -def _qgssettings_flag_value(self, key, flagDefaultValue, section=QgsSettings.Section.NoSection): +def _qgssettings_flag_value( + self, key, flagDefaultValue, section=QgsSettings.Section.NoSection +): """ Return the setting value for a setting based on a flag. This forces the output to be a valid and existing entry of the enum. @@ -102,13 +111,19 @@ def _qgssettings_flag_value(self, key, flagDefaultValue, section=QgsSettings.Sec # dirty hack to get the parent class __import__(flagDefaultValue.__module__) baseClass = None - exec("baseClass={module}.{flag_class}".format(module=flagDefaultValue.__module__.replace('_', ''), - flag_class=flagDefaultValue.__class__.__name__)) + exec( + "baseClass={module}.{flag_class}".format( + module=flagDefaultValue.__module__.replace("_", ""), + flag_class=flagDefaultValue.__class__.__name__, + ) + ) meta_enum = metaEnumFromValue(flagDefaultValue, baseClass) if meta_enum is None or not meta_enum.isValid(): # this should not happen - raise ValueError("could not get the meta enum for given enum default value (type: {})".format(type(flagDefaultValue))) + raise ValueError( + f"could not get the meta enum for given enum default value (type: {type(flagDefaultValue)})" + ) str_val = self.value(key, meta_enum.valueToKeys(flagDefaultValue), str, section) # need a new meta enum as QgsSettings.value is making a copy and leads to seg fault (probably a PyQt issue) diff --git a/python/PyQt6/core/additions/qgssettingsentry.py b/python/PyQt6/core/additions/qgssettingsentry.py index ca55c90e4f66..d07797c0d55c 100644 --- a/python/PyQt6/core/additions/qgssettingsentry.py +++ b/python/PyQt6/core/additions/qgssettingsentry.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** qgssettingsentry.py @@ -18,7 +16,13 @@ """ from .metaenum import metaEnumFromValue -from qgis.core import QgsSettings, QgsSettingsTree, QgsSettingsEntryBase, QgsLogger, Qgis +from qgis.core import ( + QgsSettings, + QgsSettingsTree, + QgsSettingsEntryBase, + QgsLogger, + Qgis, +) import qgis # required to get base class of enums @@ -29,7 +33,14 @@ class PyQgsSettingsEntryEnumFlag since QGIS 3.20 """ - def __init__(self, key, pluginName, defaultValue, description=str(), options=Qgis.SettingsOptions()): + def __init__( + self, + key, + pluginName, + defaultValue, + description="", + options=Qgis.SettingsOptions(), + ): """ Constructor for PyQgsSettingsEntryEnumFlag. @@ -42,10 +53,12 @@ def __init__(self, key, pluginName, defaultValue, description=str(), options=Qgi # TODO QGIS 4: rename pluginName arg to parent and key to name self.options = options - defaultValueStr = str() + defaultValueStr = "" self.__metaEnum = metaEnumFromValue(defaultValue) if self.__metaEnum is None or not self.__metaEnum.isValid(): - QgsLogger.debug("Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{0}'".format(self.key())) + QgsLogger.debug( + f"Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{self.key()}'" + ) else: if self.__metaEnum.isFlag(): defaultValueStr = self.__metaEnum.valueToKeys(defaultValue) @@ -75,9 +88,13 @@ def value(self, dynamicKeyPart=None): :param dynamicKeyPart: argument specifies the dynamic part of the settings key. """ if self.__metaEnum.isFlag(): - return QgsSettings().flagValue(self.key(dynamicKeyPart), self.defaultValue()) + return QgsSettings().flagValue( + self.key(dynamicKeyPart), self.defaultValue() + ) else: - return QgsSettings().enumValue(self.key(dynamicKeyPart), self.defaultValue()) + return QgsSettings().enumValue( + self.key(dynamicKeyPart), self.defaultValue() + ) def valueWithDefaultOverride(self, defaultValueOverride, dynamicKeyPart=None): """ @@ -87,9 +104,13 @@ def valueWithDefaultOverride(self, defaultValueOverride, dynamicKeyPart=None): :param dynamicKeyPart: argument specifies the dynamic part of the settings key. """ if self.__metaEnum.isFlag(): - return QgsSettings().flagValue(self.key(dynamicKeyPart), defaultValueOverride) + return QgsSettings().flagValue( + self.key(dynamicKeyPart), defaultValueOverride + ) else: - return QgsSettings().enumValue(self.key(dynamicKeyPart), defaultValueOverride) + return QgsSettings().enumValue( + self.key(dynamicKeyPart), defaultValueOverride + ) def defaultValue(self): """ @@ -97,7 +118,9 @@ def defaultValue(self): """ if self.__metaEnum is None or not self.__metaEnum.isValid(): - QgsLogger.debug("Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{0}'".format(self.key())) + QgsLogger.debug( + f"Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{self.key()}'" + ) return -1 defaultValueString = self.defaultValueAsVariant() @@ -106,7 +129,9 @@ def defaultValue(self): else: (defaultValue, ok) = self.__metaEnum.keyToValue(defaultValueString) if not ok: - QgsLogger.debug("Invalid enum/flag key/s '{0}'.".format(self.defaultValueAsVariant())) + QgsLogger.debug( + f"Invalid enum/flag key/s '{self.defaultValueAsVariant()}'." + ) return -1 # cast to the enum class @@ -122,7 +147,9 @@ def setValue(self, value, dynamicKeyPart: (list, str) = None): """ if self.__metaEnum is None or not self.__metaEnum.isValid(): - QgsLogger.debug("Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{0}'".format(self.key())) + QgsLogger.debug( + f"Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{self.key()}'" + ) return False if self.options & Qgis.SettingsOption.SaveEnumFlagAsInt: @@ -133,7 +160,7 @@ def setValue(self, value, dynamicKeyPart: (list, str) = None): else: enum_flag_key = self.__metaEnum.valueToKey(value) if not enum_flag_key: - QgsLogger.debug("Invalid enum/flag value '{0}'.".format(value)) + QgsLogger.debug(f"Invalid enum/flag value '{value}'.") return False if type(dynamicKeyPart) is str: diff --git a/python/PyQt6/core/additions/qgstaskwrapper.py b/python/PyQt6/core/additions/qgstaskwrapper.py index 6c2b7560d812..a3a7d8c347bf 100644 --- a/python/PyQt6/core/additions/qgstaskwrapper.py +++ b/python/PyQt6/core/additions/qgstaskwrapper.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** qgstaskwrapper.py @@ -17,7 +15,6 @@ *************************************************************************** """ - from qgis._core import QgsTask @@ -47,7 +44,7 @@ def finished(self, result): return if not result and self.exception is None: - self.exception = Exception('Task canceled') + self.exception = Exception("Task canceled") try: if self.returned_values: diff --git a/python/PyQt6/core/additions/readwritecontextentercategory.py b/python/PyQt6/core/additions/readwritecontextentercategory.py index af9c509342cd..79a9c44e8bac 100644 --- a/python/PyQt6/core/additions/readwritecontextentercategory.py +++ b/python/PyQt6/core/additions/readwritecontextentercategory.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** readwritecontextentercategory.py @@ -18,7 +16,7 @@ """ -class ReadWriteContextEnterCategory(): +class ReadWriteContextEnterCategory: """ Push a category to the stack diff --git a/python/PyQt6/core/additions/runtimeprofiler.py b/python/PyQt6/core/additions/runtimeprofiler.py index 2216f5609e9d..95758a1ce899 100644 --- a/python/PyQt6/core/additions/runtimeprofiler.py +++ b/python/PyQt6/core/additions/runtimeprofiler.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** runtimeprofiler.py @@ -17,11 +15,10 @@ *************************************************************************** """ - from qgis._core import QgsScopedRuntimeProfile -class ScopedRuntimeProfileContextManager(): +class ScopedRuntimeProfileContextManager: """ Context manager used to profile blocks of code in the QgsApplication.profiler() registry. diff --git a/python/PyQt6/core/additions/validitycheck.py b/python/PyQt6/core/additions/validitycheck.py index 25fdd1586f09..37a32b9cf5e1 100644 --- a/python/PyQt6/core/additions/validitycheck.py +++ b/python/PyQt6/core/additions/validitycheck.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** validitycheck.py @@ -16,9 +14,8 @@ * * *************************************************************************** """ -from qgis._core import ( - QgsAbstractValidityCheck, - QgsApplication) + +from qgis._core import QgsAbstractValidityCheck, QgsApplication class CheckFactory: diff --git a/python/PyQt6/core/contextmanagers.py b/python/PyQt6/core/contextmanagers.py index 62e0c624659d..72be360097e6 100644 --- a/python/PyQt6/core/contextmanagers.py +++ b/python/PyQt6/core/contextmanagers.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** contextmanagers.py @@ -17,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nathan Woodrow' -__date__ = 'May 2014' -__copyright__ = '(C) 2014, Nathan Woodrow' +__author__ = "Nathan Woodrow" +__date__ = "May 2014" +__copyright__ = "(C) 2014, Nathan Woodrow" import sys from contextlib import contextmanager diff --git a/python/PyQt6/gui/additions/qgssettingsenumflageditorwrapper.py b/python/PyQt6/gui/additions/qgssettingsenumflageditorwrapper.py index 245b0470a35f..528adb8192a2 100644 --- a/python/PyQt6/gui/additions/qgssettingsenumflageditorwrapper.py +++ b/python/PyQt6/gui/additions/qgssettingsenumflageditorwrapper.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** qgssettingsenumflageditorwrapper.py @@ -28,7 +26,9 @@ class PyQgsSettingsEnumEditorWidgetWrapper(QgsSettingsEditorWidgetWrapper): A settings editor widget wrapper for enum settings as PyQgsSettingsEntryEnumFlag """ - def __init__(self, parent=None, editor=None, setting=None, displayStrings: dict = None): + def __init__( + self, parent=None, editor=None, setting=None, displayStrings: dict = None + ): self.setting = setting self.editor = editor self.displayStrings = {} @@ -39,19 +39,23 @@ def __init__(self, parent=None, editor=None, setting=None, displayStrings: dict self.configureEditor(editor, setting) def id(self): - return 'py-enum' + return "py-enum" def createWrapper(self, parent=None): return PyQgsSettingsEnumEditorWidgetWrapper(parent) def setWidgetFromSetting(self): if self.setting: - return self.setWidgetFromVariant(self.setting.valueAsVariant(self.dynamicKeyPartList())) + return self.setWidgetFromVariant( + self.setting.valueAsVariant(self.dynamicKeyPartList()) + ) return False def setSettingFromWidget(self): if self.editor: - self.setting.setVariantValue(self.variantValueFromWidget(), self.dynamicKeyPartList()) + self.setting.setVariantValue( + self.variantValueFromWidget(), self.dynamicKeyPartList() + ) return True else: return False @@ -88,4 +92,7 @@ def configureEditorPrivate(self, editor: QComboBox, setting: QgsSettingsEntryBas def enableAutomaticUpdatePrivate(self): self.editor.currentIndexChanged.connect( - lambda: self.setting.setValue(self.editor.currentData(), self.dynamicKeyPartList())) + lambda: self.setting.setValue( + self.editor.currentData(), self.dynamicKeyPartList() + ) + ) diff --git a/python/__init__.py b/python/__init__.py index bee060f91a58..35fdfd666538 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** __init__.py @@ -17,11 +15,10 @@ *************************************************************************** """ -__author__ = 'Martin Dobias' -__date__ = 'January 2007' -__copyright__ = '(C) 2007, Martin Dobias' +__author__ = "Martin Dobias" +__date__ = "January 2007" +__copyright__ = "(C) 2007, Martin Dobias" -from builtins import zip import os import sys @@ -32,7 +29,7 @@ def setupenv(): OSGeo4W package format. """ # If the prefix path is already set then we don't do any more path setup. - if os.getenv('QGIS_PREFIX_PATH'): + if os.getenv("QGIS_PREFIX_PATH"): return # Setup the paths based on the .vars file. @@ -41,13 +38,13 @@ def setupenv(): path_split = PurePath(os.path.dirname(os.path.realpath(__file__))).parts try: - appname = os.environ['QGIS_ENVNAME'] + appname = os.environ["QGIS_ENVNAME"] except KeyError: appname = path_split[-3] envfile = list(path_split[:-4]) envfile.append("bin") - envfile.append("{0}-bin.env".format(appname)) + envfile.append(f"{appname}-bin.env") envfile = os.path.join(*envfile) if not os.path.exists(envfile): @@ -65,12 +62,14 @@ def setupenv(): pass -if os.name == 'nt': +if os.name == "nt": # On Windows we need to setup the paths before we can import # any of the QGIS modules or else it will error. setupenv() - if sys.version_info[0] > 3 or (sys.version_info[0] == 3 and sys.version_info[1] >= 9): + if sys.version_info[0] > 3 or ( + sys.version_info[0] == 3 and sys.version_info[1] >= 9 + ): for p in os.getenv("PATH").split(";"): if os.path.exists(p): os.add_dll_directory(p) @@ -84,11 +83,12 @@ def setupenv(): # (thanks to uic/widget-plugins/qgis_customwidgets.py) try: import qgis.gui + widget_list = dir(qgis.gui) # remove widgets that are not allowed as custom widgets (they need to be manually promoted) - skip_list = ['QgsScrollArea'] + skip_list = ["QgsScrollArea"] for widget in widget_list: - if widget.startswith('Qgs') and widget not in skip_list: + if widget.startswith("Qgs") and widget not in skip_list: sys.modules[widget.lower()] = qgis.gui except ImportError: # gui might not be built diff --git a/python/console/__init__.py b/python/console/__init__.py index f9477a90b37f..e2f7bf4cd4ad 100644 --- a/python/console/__init__.py +++ b/python/console/__init__.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** __init__.py @@ -17,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Salvatore Larosa' -__date__ = 'September 2012' -__copyright__ = '(C) 2012, Salvatore Larosa' +__author__ = "Salvatore Larosa" +__date__ = "September 2012" +__copyright__ = "(C) 2012, Salvatore Larosa" from .console import show_console # NOQA from .console import init_options_widget diff --git a/python/console/console.py b/python/console/console.py index 9da2f97273e7..ba15c4460f1a 100644 --- a/python/console/console.py +++ b/python/console/console.py @@ -17,34 +17,50 @@ ***************************************************************************/ Some portions of code were taken from https://code.google.com/p/pydee/ """ + import os import subprocess -from qgis.PyQt.QtCore import Qt, QTimer, QCoreApplication, QSize, QByteArray, QFileInfo, QUrl, QDir -from qgis.PyQt.QtWidgets import QToolBar, QToolButton, QWidget, QSplitter, QTreeWidget, QAction, QFileDialog, QCheckBox, QSizePolicy, QMenu, QGridLayout, QApplication, QShortcut -from qgis.PyQt.QtGui import QDesktopServices, QKeySequence +from qgis.PyQt.QtCore import ( + Qt, + QTimer, + QCoreApplication, + QSize, + QByteArray, + QFileInfo, + QUrl, + QDir, +) from qgis.PyQt.QtWidgets import ( - QVBoxLayout, - QMessageBox + QToolBar, + QToolButton, + QWidget, + QSplitter, + QTreeWidget, + QAction, + QFileDialog, + QCheckBox, + QSizePolicy, + QMenu, + QGridLayout, + QApplication, + QShortcut, ) +from qgis.PyQt.QtGui import QDesktopServices, QKeySequence +from qgis.PyQt.QtWidgets import QVBoxLayout, QMessageBox from qgis.utils import iface from .console_sci import ShellScintilla from .console_output import ShellOutputScintilla from .console_editor import EditorTabWidget from .console_settings import ConsoleOptionsFactory -from qgis.core import ( - Qgis, - QgsApplication, - QgsSettings, - QgsFileUtils -) +from qgis.core import Qgis, QgsApplication, QgsSettings, QgsFileUtils from qgis.gui import ( QgsFilterLineEdit, QgsHelp, QgsDockWidget, QgsGui, QgsApplicationExitBlockerInterface, - QgsCodeEditorDockWidget + QgsCodeEditorDockWidget, ) from functools import partial @@ -56,13 +72,15 @@ def show_console(): - """ called from QGIS to open the console """ + """called from QGIS to open the console""" global _console if _console is None: parent = iface.mainWindow() if iface else None _console = PythonConsole(parent) if iface: - _console.visibilityChanged.connect(iface.actionShowPythonDialog().setChecked) + _console.visibilityChanged.connect( + iface.actionShowPythonDialog().setChecked + ) _console.show() # force show even if it was restored as hidden # set focus to the console so the user can start typing @@ -89,7 +107,7 @@ def console_displayhook(obj): def init_options_widget(): - """ called from QGIS to add the console options widget """ + """called from QGIS to add the console options widget""" global _options_factory _options_factory.setTitle(QCoreApplication.translate("PythonConsole", "Python")) iface.registerOptionsWidgetFactory(_options_factory) @@ -143,13 +161,14 @@ class PythonConsoleWidget(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) - self.setWindowTitle(QCoreApplication.translate("PythonConsole", "Python Console")) + self.setWindowTitle( + QCoreApplication.translate("PythonConsole", "Python Console") + ) self.shell = ShellScintilla(console_widget=self) self.setFocusProxy(self.shell) self.shell_output = ShellOutputScintilla( - console_widget=self, - shell_editor=self.shell + console_widget=self, shell_editor=self.shell ) self.tabEditorWidget = EditorTabWidget(console_widget=self) @@ -181,7 +200,7 @@ def __init__(self, parent=None): self.listClassMethod = QTreeWidget(self.splitterObj) self.listClassMethod.setColumnCount(2) objInspLabel = QCoreApplication.translate("PythonConsole", "Object Inspector") - self.listClassMethod.setHeaderLabels([objInspLabel, '']) + self.listClassMethod.setHeaderLabels([objInspLabel, ""]) self.listClassMethod.setColumnHidden(1, True) self.listClassMethod.setAlternatingRowColors(True) @@ -205,17 +224,23 @@ def __init__(self, parent=None): self.openFileButton = QAction(self) self.openFileButton.setCheckable(False) self.openFileButton.setEnabled(True) - self.openFileButton.setIcon(QgsApplication.getThemeIcon("mActionScriptOpen.svg")) + self.openFileButton.setIcon( + QgsApplication.getThemeIcon("mActionScriptOpen.svg") + ) self.openFileButton.setMenuRole(QAction.MenuRole.PreferencesRole) self.openFileButton.setIconVisibleInMenu(True) self.openFileButton.setToolTip(openFileBt) self.openFileButton.setText(openFileBt) - openExtEditorBt = QCoreApplication.translate("PythonConsole", "Open in External Editor") + openExtEditorBt = QCoreApplication.translate( + "PythonConsole", "Open in External Editor" + ) self.openInEditorButton = QAction(self) self.openInEditorButton.setCheckable(False) self.openInEditorButton.setEnabled(True) - self.openInEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconShowEditorConsole.svg")) + self.openInEditorButton.setIcon( + QgsApplication.getThemeIcon("console/iconShowEditorConsole.svg") + ) self.openInEditorButton.setMenuRole(QAction.MenuRole.PreferencesRole) self.openInEditorButton.setIconVisibleInMenu(True) self.openInEditorButton.setToolTip(openExtEditorBt) @@ -235,7 +260,9 @@ def __init__(self, parent=None): self.saveAsFileButton = QAction(self) self.saveAsFileButton.setCheckable(False) self.saveAsFileButton.setEnabled(True) - self.saveAsFileButton.setIcon(QgsApplication.getThemeIcon("mActionFileSaveAs.svg")) + self.saveAsFileButton.setIcon( + QgsApplication.getThemeIcon("mActionFileSaveAs.svg") + ) self.saveAsFileButton.setMenuRole(QAction.MenuRole.PreferencesRole) self.saveAsFileButton.setIconVisibleInMenu(True) self.saveAsFileButton.setToolTip(saveAsFileBt) @@ -255,7 +282,9 @@ def __init__(self, parent=None): self.copyEditorButton = QAction(self) self.copyEditorButton.setCheckable(False) self.copyEditorButton.setEnabled(True) - self.copyEditorButton.setIcon(QgsApplication.getThemeIcon("mActionEditCopy.svg")) + self.copyEditorButton.setIcon( + QgsApplication.getThemeIcon("mActionEditCopy.svg") + ) self.copyEditorButton.setMenuRole(QAction.MenuRole.PreferencesRole) self.copyEditorButton.setIconVisibleInMenu(True) self.copyEditorButton.setToolTip(copyEditorBt) @@ -265,7 +294,9 @@ def __init__(self, parent=None): self.pasteEditorButton = QAction(self) self.pasteEditorButton.setCheckable(False) self.pasteEditorButton.setEnabled(True) - self.pasteEditorButton.setIcon(QgsApplication.getThemeIcon("mActionEditPaste.svg")) + self.pasteEditorButton.setIcon( + QgsApplication.getThemeIcon("mActionEditPaste.svg") + ) self.pasteEditorButton.setMenuRole(QAction.MenuRole.PreferencesRole) self.pasteEditorButton.setIconVisibleInMenu(True) self.pasteEditorButton.setToolTip(pasteEditorBt) @@ -275,7 +306,9 @@ def __init__(self, parent=None): self.runScriptEditorButton = QAction(self) self.runScriptEditorButton.setCheckable(False) self.runScriptEditorButton.setEnabled(True) - self.runScriptEditorButton.setIcon(QgsApplication.getThemeIcon("mActionStart.svg")) + self.runScriptEditorButton.setIcon( + QgsApplication.getThemeIcon("mActionStart.svg") + ) self.runScriptEditorButton.setMenuRole(QAction.MenuRole.PreferencesRole) self.runScriptEditorButton.setIconVisibleInMenu(True) self.runScriptEditorButton.setToolTip(runScriptEditorBt) @@ -286,7 +319,9 @@ def __init__(self, parent=None): self.toggleCommentEditorButton = QAction(self) self.toggleCommentEditorButton.setCheckable(False) self.toggleCommentEditorButton.setEnabled(True) - self.toggleCommentEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconCommentEditorConsole.svg")) + self.toggleCommentEditorButton.setIcon( + QgsApplication.getThemeIcon("console/iconCommentEditorConsole.svg") + ) self.toggleCommentEditorButton.setMenuRole(QAction.MenuRole.PreferencesRole) self.toggleCommentEditorButton.setIconVisibleInMenu(True) self.toggleCommentEditorButton.setToolTip(toggleText + " Ctrl+:") @@ -297,10 +332,14 @@ def __init__(self, parent=None): self.reformatCodeEditorButton = QAction(self) self.reformatCodeEditorButton.setCheckable(False) self.reformatCodeEditorButton.setEnabled(True) - self.reformatCodeEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconFormatCode.svg")) + self.reformatCodeEditorButton.setIcon( + QgsApplication.getThemeIcon("console/iconFormatCode.svg") + ) self.reformatCodeEditorButton.setMenuRole(QAction.MenuRole.PreferencesRole) self.reformatCodeEditorButton.setIconVisibleInMenu(True) - self.reformatCodeEditorButton.setToolTip(reformatCodeText + " Ctrl+Alt+F") + self.reformatCodeEditorButton.setToolTip( + reformatCodeText + " Ctrl+Alt+F" + ) self.reformatCodeEditorButton.setShortcut("Ctrl+Alt+F") self.reformatCodeEditorButton.setText(reformatCodeText) @@ -308,9 +347,12 @@ def __init__(self, parent=None): objList = QCoreApplication.translate("PythonConsole", "Object Inspector…") self.objectListButton = QAction(self) self.objectListButton.setCheckable(True) - self.objectListButton.setEnabled(QgsSettings().value("pythonConsole/enableObjectInsp", - False, type=bool)) - self.objectListButton.setIcon(QgsApplication.getThemeIcon("console/iconClassBrowserConsole.svg")) + self.objectListButton.setEnabled( + QgsSettings().value("pythonConsole/enableObjectInsp", False, type=bool) + ) + self.objectListButton.setIcon( + QgsApplication.getThemeIcon("console/iconClassBrowserConsole.svg") + ) self.objectListButton.setMenuRole(QAction.MenuRole.PreferencesRole) self.objectListButton.setIconVisibleInMenu(True) self.objectListButton.setToolTip(objList) @@ -321,7 +363,9 @@ def __init__(self, parent=None): self.find_text_action = QAction(self) self.find_text_action.setCheckable(True) self.find_text_action.setEnabled(True) - self.find_text_action.setIcon(QgsApplication.getThemeIcon("console/iconSearchEditorConsole.svg")) + self.find_text_action.setIcon( + QgsApplication.getThemeIcon("console/iconSearchEditorConsole.svg") + ) self.find_text_action.setMenuRole(QAction.MenuRole.PreferencesRole) self.find_text_action.setIconVisibleInMenu(True) self.find_text_action.setToolTip(findText) @@ -330,9 +374,7 @@ def __init__(self, parent=None): self.tabEditorWidget.search_bar_toggled.connect( self.find_text_action.setChecked ) - self.find_text_action.toggled.connect( - self.tabEditorWidget.toggle_search_bar - ) + self.find_text_action.toggled.connect(self.tabEditorWidget.toggle_search_bar) # ----------------Toolbar Console------------------------------------- @@ -341,7 +383,9 @@ def __init__(self, parent=None): self.showEditorButton = QAction(self) self.showEditorButton.setEnabled(True) self.showEditorButton.setCheckable(True) - self.showEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconShowEditorConsole.svg")) + self.showEditorButton.setIcon( + QgsApplication.getThemeIcon("console/iconShowEditorConsole.svg") + ) self.showEditorButton.setMenuRole(QAction.MenuRole.PreferencesRole) self.showEditorButton.setIconVisibleInMenu(True) self.showEditorButton.setToolTip(showEditor) @@ -351,7 +395,9 @@ def __init__(self, parent=None): self.clearButton = QAction(self) self.clearButton.setCheckable(False) self.clearButton.setEnabled(True) - self.clearButton.setIcon(QgsApplication.getThemeIcon("console/iconClearConsole.svg")) + self.clearButton.setIcon( + QgsApplication.getThemeIcon("console/iconClearConsole.svg") + ) self.clearButton.setMenuRole(QAction.MenuRole.PreferencesRole) self.clearButton.setIconVisibleInMenu(True) self.clearButton.setToolTip(clearBt) @@ -361,7 +407,9 @@ def __init__(self, parent=None): self.optionsButton = QAction(self) self.optionsButton.setCheckable(False) self.optionsButton.setEnabled(True) - self.optionsButton.setIcon(QgsApplication.getThemeIcon("console/iconSettingsConsole.svg")) + self.optionsButton.setIcon( + QgsApplication.getThemeIcon("console/iconSettingsConsole.svg") + ) self.optionsButton.setMenuRole(QAction.MenuRole.PreferencesRole) self.optionsButton.setIconVisibleInMenu(True) self.optionsButton.setToolTip(optionsBt) @@ -380,13 +428,19 @@ def __init__(self, parent=None): # Help button self.helpConsoleAction = QAction(self) self.helpConsoleAction.setEnabled(True) - self.helpConsoleAction.setText(QCoreApplication.translate("PythonConsole", "Python Console Help")) + self.helpConsoleAction.setText( + QCoreApplication.translate("PythonConsole", "Python Console Help") + ) self.helpAPIAction = QAction(self) self.helpAPIAction.setEnabled(True) - self.helpAPIAction.setText(QCoreApplication.translate("PythonConsole", "PyQGIS API Documentation")) + self.helpAPIAction.setText( + QCoreApplication.translate("PythonConsole", "PyQGIS API Documentation") + ) self.helpCookbookAction = QAction(self) self.helpCookbookAction.setEnabled(True) - self.helpCookbookAction.setText(QCoreApplication.translate("PythonConsole", "PyQGIS Cookbook")) + self.helpCookbookAction.setText( + QCoreApplication.translate("PythonConsole", "PyQGIS Cookbook") + ) self.helpMenu = QMenu(self) self.helpMenu.addAction(self.helpConsoleAction) @@ -397,7 +451,9 @@ def __init__(self, parent=None): self.helpButton = QToolButton(self) self.helpButton.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup) self.helpButton.setEnabled(True) - self.helpButton.setIcon(QgsApplication.getThemeIcon("console/iconHelpConsole.svg")) + self.helpButton.setIcon( + QgsApplication.getThemeIcon("console/iconHelpConsole.svg") + ) self.helpButton.setToolTip(helpBt) self.helpButton.setMenu(self.helpMenu) @@ -457,16 +513,22 @@ def __init__(self, parent=None): sizePolicy = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.widgetButtonEditor.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.widgetButtonEditor.sizePolicy().hasHeightForWidth() + ) self.widgetButtonEditor.setSizePolicy(sizePolicy) - sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + sizePolicy = QSizePolicy( + QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.shell_output.sizePolicy().hasHeightForWidth()) self.shell_output.setSizePolicy(sizePolicy) - self.shell_output.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded) + self.shell_output.setVerticalScrollBarPolicy( + Qt.ScrollBarPolicy.ScrollBarAsNeeded + ) self.shell.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded) # ------------ Layout ------------------------------- @@ -523,9 +585,17 @@ def allowExit(self): tab_index = tab_count - i - 1 tab_widget = self.tabEditorWidget.widget(tab_index) if tab_widget.isModified(): - ret = QMessageBox.question(self, self.tr("Save {}").format(self.tabEditorWidget.tabText(tab_index)), - self.tr("There are unsaved changes in this script. Do you want to keep those?"), - QMessageBox.StandardButton.Save | QMessageBox.StandardButton.Cancel | QMessageBox.StandardButton.Discard, QMessageBox.StandardButton.Cancel) + ret = QMessageBox.question( + self, + self.tr("Save {}").format(self.tabEditorWidget.tabText(tab_index)), + self.tr( + "There are unsaved changes in this script. Do you want to keep those?" + ), + QMessageBox.StandardButton.Save + | QMessageBox.StandardButton.Cancel + | QMessageBox.StandardButton.Discard, + QMessageBox.StandardButton.Cancel, + ) if ret == QMessageBox.StandardButton.Save: tab_widget.save() if tab_widget.isModified(): @@ -545,14 +615,14 @@ def _toggleFind(self): def onClickGoToLine(self, item, column): tabEditor = self.tabEditorWidget.currentWidget() - if item.text(1) == 'syntaxError': + if item.text(1) == "syntaxError": check = tabEditor.syntaxCheck() if check and not tabEditor.isReadOnly(): self.tabEditorWidget.currentWidget().save() return linenr = int(item.text(1)) itemName = str(item.text(0)) - charPos = itemName.find(' ') + charPos = itemName.find(" ") if charPos != -1: objName = itemName[0:charPos] else: @@ -595,7 +665,8 @@ def openScriptFile(self): lastDirPath = settings.value("pythonConsole/lastDirPath", QDir.homePath()) openFileTr = QCoreApplication.translate("PythonConsole", "Open File") fileList, selected_filter = QFileDialog.getOpenFileNames( - self, openFileTr, lastDirPath, "Script file (*.py)") + self, openFileTr, lastDirPath, "Script file (*.py)" + ) if fileList: for pyFile in fileList: for i in range(self.tabEditorWidget.count()): @@ -609,16 +680,16 @@ def openScriptFile(self): lastDirPath = QFileInfo(pyFile).path() settings.setValue("pythonConsole/lastDirPath", pyFile) - self.updateTabListScript(pyFile, action='append') + self.updateTabListScript(pyFile, action="append") def saveScriptFile(self): tabWidget = self.tabEditorWidget.currentWidget() try: tabWidget.save() - except (IOError, OSError) as error: - msgText = QCoreApplication.translate('PythonConsole', - 'The file {0} could not be saved. Error: {1}').format(tabWidget.file_path(), - error.strerror) + except OSError as error: + msgText = QCoreApplication.translate( + "PythonConsole", "The file {0} could not be saved. Error: {1}" + ).format(tabWidget.file_path(), error.strerror) self.callWidgetMessageBarEditor(msgText, Qgis.MessageLevel.Critical) def saveAsScriptFile(self, index=None): @@ -626,9 +697,8 @@ def saveAsScriptFile(self, index=None): if not index: index = self.tabEditorWidget.currentIndex() if not tabWidget.file_path(): - fileName = self.tabEditorWidget.tabText(index).replace('*', '') - fileName = QgsFileUtils.ensureFileNameHasExtension(fileName, - ['py']) + fileName = self.tabEditorWidget.tabText(index).replace("*", "") + fileName = QgsFileUtils.ensureFileNameHasExtension(fileName, ["py"]) folder = QgsSettings().value("pythonConsole/lastDirPath", QDir.homePath()) pathFileName = os.path.join(folder, fileName) fileNone = True @@ -636,18 +706,19 @@ def saveAsScriptFile(self, index=None): pathFileName = tabWidget.file_path() fileNone = False saveAsFileTr = QCoreApplication.translate("PythonConsole", "Save File As") - filename, filter = QFileDialog.getSaveFileName(self, - saveAsFileTr, - pathFileName, "Script file (*.py)") + filename, filter = QFileDialog.getSaveFileName( + self, saveAsFileTr, pathFileName, "Script file (*.py)" + ) if filename: - filename = QgsFileUtils.ensureFileNameHasExtension(filename, ['py']) + filename = QgsFileUtils.ensureFileNameHasExtension(filename, ["py"]) try: tabWidget.save(filename) - except (IOError, OSError) as error: - msgText = QCoreApplication.translate('PythonConsole', - 'The file {0} could not be saved. Error: {1}').format(tabWidget.file_path(), - error.strerror) + except OSError as error: + msgText = QCoreApplication.translate( + "PythonConsole", + "The file {0} could not be saved. Error: {1}", + ).format(tabWidget.file_path(), error.strerror) self.callWidgetMessageBarEditor(msgText, Qgis.MessageLevel.Critical) if fileNone: tabWidget.set_file_path(None) @@ -656,23 +727,29 @@ def saveAsScriptFile(self, index=None): return if not fileNone: - self.updateTabListScript(pathFileName, action='remove') + self.updateTabListScript(pathFileName, action="remove") def openHelpConsole(self): QgsHelp.openHelp("plugins/python_console.html") def openHelpAPI(self): - m = re.search(r'^([0-9]+)\.([0-9]+)\.', Qgis.QGIS_VERSION) + m = re.search(r"^([0-9]+)\.([0-9]+)\.", Qgis.QGIS_VERSION) if m: - QDesktopServices.openUrl(QUrl('https://qgis.org/pyqgis/{}.{}/'.format(m.group(1), m.group(2)))) + QDesktopServices.openUrl( + QUrl(f"https://qgis.org/pyqgis/{m.group(1)}.{m.group(2)}/") + ) def openHelpCookbook(self): - m = re.search(r'^([0-9]+)\.([0-9]+)\.', Qgis.QGIS_VERSION) + m = re.search(r"^([0-9]+)\.([0-9]+)\.", Qgis.QGIS_VERSION) if m: - QDesktopServices.openUrl(QUrl('https://docs.qgis.org/{}.{}/en/docs/pyqgis_developer_cookbook/index.html'.format(m.group(1), m.group(2)))) + QDesktopServices.openUrl( + QUrl( + f"https://docs.qgis.org/{m.group(1)}.{m.group(2)}/en/docs/pyqgis_developer_cookbook/index.html" + ) + ) def openSettings(self): - iface.showOptionsDialog(iface.mainWindow(), currentPage='consoleOptions') + iface.showOptionsDialog(iface.mainWindow(), currentPage="consoleOptions") def updateSettings(self): self.shell.refreshSettingsShell() @@ -686,23 +763,24 @@ def callWidgetMessageBarEditor(self, text, level): self.tabEditorWidget.showMessage(text, level) def updateTabListScript(self, script, action=None): - if action == 'remove': + if action == "remove": self.tabListScript.remove(script) - elif action == 'append': + elif action == "append": if not self.tabListScript: self.tabListScript = [] if script not in self.tabListScript: self.tabListScript.append(script) else: self.tabListScript = [] - QgsSettings().setValue("pythonConsole/tabScripts", - self.tabListScript) + QgsSettings().setValue("pythonConsole/tabScripts", self.tabListScript) def saveSettingsConsole(self): settings = QgsSettings() settings.setValue("pythonConsole/splitterConsole", self.splitter.saveState()) settings.setValue("pythonConsole/splitterObj", self.splitterObj.saveState()) - settings.setValue("pythonConsole/splitterEditor", self.splitterEditor.saveState()) + settings.setValue( + "pythonConsole/splitterEditor", self.splitterEditor.saveState() + ) self.shell.writeHistoryFile() @@ -710,12 +788,18 @@ def restoreSettingsConsole(self): settings = QgsSettings() storedTabScripts = settings.value("pythonConsole/tabScripts", []) self.tabListScript = storedTabScripts - self.splitter.restoreState(settings.value("pythonConsole/splitterConsole", QByteArray())) - self.splitterEditor.restoreState(settings.value("pythonConsole/splitterEditor", QByteArray())) - self.splitterObj.restoreState(settings.value("pythonConsole/splitterObj", QByteArray())) + self.splitter.restoreState( + settings.value("pythonConsole/splitterConsole", QByteArray()) + ) + self.splitterEditor.restoreState( + settings.value("pythonConsole/splitterEditor", QByteArray()) + ) + self.splitterObj.restoreState( + settings.value("pythonConsole/splitterObj", QByteArray()) + ) -if __name__ == '__main__': +if __name__ == "__main__": a = QApplication(sys.argv) console = PythonConsoleWidget() console.show() diff --git a/python/console/console_compile_apis.py b/python/console/console_compile_apis.py index 9ea869646b34..3b112270b54c 100644 --- a/python/console/console_compile_apis.py +++ b/python/console/console_compile_apis.py @@ -27,7 +27,9 @@ from qgis.PyQt.QtWidgets import QDialog, QDialogButtonBox from qgis.PyQt.QtCore import QCoreApplication -Ui_APIsDialogPythonConsole, _ = uic.loadUiType(Path(__file__).parent / 'console_compile_apis.ui') +Ui_APIsDialogPythonConsole, _ = uic.loadUiType( + Path(__file__).parent / "console_compile_apis.ui" +) class PrepareAPIDialog(QDialog): @@ -61,21 +63,24 @@ def _preparationFinished(self): self._clearLexer() if os.path.exists(self._pap_file): os.remove(self._pap_file) - self.ui.label.setText(QCoreApplication.translate("PythonConsole", "Saving prepared file…")) + self.ui.label.setText( + QCoreApplication.translate("PythonConsole", "Saving prepared file…") + ) prepd = self._api.savePrepared(self._pap_file) rslt = self.tr("Error") if prepd: rslt = QCoreApplication.translate("PythonConsole", "Saved") - self.ui.label.setText('{0} {1}'.format(self.ui.label.text(), rslt)) + self.ui.label.setText(f"{self.ui.label.text()} {rslt}") self._api = None self.ui.progressBar.setVisible(False) self.ui.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setText( - QCoreApplication.translate("PythonConsole", "Done")) + QCoreApplication.translate("PythonConsole", "Done") + ) self.adjustSize() def prepareAPI(self): # self.ui.textEdit_Qsci.setLexer(0) - exec('self.qlexer = {0}(self.ui.textEdit_Qsci)'.format(self._api_lexer)) + exec(f"self.qlexer = {self._api_lexer}(self.ui.textEdit_Qsci)") # self.ui.textEdit_Qsci.setLexer(self.qlexer) self._api = QsciAPIs(self.qlexer) self._api.apiPreparationFinished.connect(self._preparationFinished) @@ -86,9 +91,13 @@ def prepareAPI(self): except Exception as err: self._api = None self._clearLexer() - self.ui.label.setText(QCoreApplication.translate("PythonConsole", "Error preparing file…")) + self.ui.label.setText( + QCoreApplication.translate("PythonConsole", "Error preparing file…") + ) self.ui.progressBar.setVisible(False) self.ui.plainTextEdit.setVisible(True) self.ui.plainTextEdit.insertPlainText(err) - self.ui.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setText(self.tr("Done")) + self.ui.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setText( + self.tr("Done") + ) self.adjustSize() diff --git a/python/console/console_editor.py b/python/console/console_editor.py index b1929e1478ed..c7e868372c52 100644 --- a/python/console/console_editor.py +++ b/python/console/console_editor.py @@ -17,6 +17,7 @@ ***************************************************************************/ Some portions of code were taken from https://code.google.com/p/pydee/ """ + from __future__ import annotations import codecs @@ -26,20 +27,13 @@ import re import sys import tempfile -from typing import ( - Optional, - TYPE_CHECKING -) +from typing import Optional, TYPE_CHECKING from functools import partial from operator import itemgetter from pathlib import Path from qgis.core import Qgis, QgsApplication, QgsBlockingNetworkRequest, QgsSettings -from qgis.gui import ( - QgsCodeEditorPython, - QgsCodeEditorWidget, - QgsMessageBar -) +from qgis.gui import QgsCodeEditorPython, QgsCodeEditorWidget, QgsMessageBar from qgis.PyQt.Qsci import QsciScintilla from qgis.PyQt.QtCore import ( @@ -52,7 +46,7 @@ QJsonDocument, QSize, Qt, - QUrl + QUrl, ) from qgis.PyQt.QtGui import QKeySequence from qgis.PyQt.QtNetwork import QNetworkRequest @@ -83,41 +77,57 @@ class Editor(QgsCodeEditorPython): trigger_find = pyqtSignal() - def __init__(self, - editor_tab: EditorTab, - console_widget: PythonConsoleWidget, - tab_widget: EditorTabWidget): + def __init__( + self, + editor_tab: EditorTab, + console_widget: PythonConsoleWidget, + tab_widget: EditorTabWidget, + ): super().__init__(editor_tab) self.editor_tab: EditorTab = editor_tab self.console_widget: PythonConsoleWidget = console_widget self.tab_widget: EditorTabWidget = tab_widget - self.code_editor_widget: Optional[QgsCodeEditorWidget] = None + self.code_editor_widget: QgsCodeEditorWidget | None = None self.setMinimumHeight(120) self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded) # Disable default scintilla shortcuts ctrl, shift = self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16 - self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl) # Switch current line with the next one - self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl) # Duplicate current line / selection - self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl) # Delete current line - self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl + shift) + self.SendScintilla( + QsciScintilla.SCI_CLEARCMDKEY, ord("T") + ctrl + ) # Switch current line with the next one + self.SendScintilla( + QsciScintilla.SCI_CLEARCMDKEY, ord("D") + ctrl + ) # Duplicate current line / selection + self.SendScintilla( + QsciScintilla.SCI_CLEARCMDKEY, ord("L") + ctrl + ) # Delete current line + self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("L") + ctrl + shift) # New QShortcut = ctrl+space/ctrl+alt+space for Autocomplete - self.newShortcutCS = QShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_Space), self) + self.newShortcutCS = QShortcut( + QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_Space), self + ) self.newShortcutCS.setContext(Qt.ShortcutContext.WidgetShortcut) - self.redoScut = QShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Modifier.SHIFT | Qt.Key.Key_Z), self) + self.redoScut = QShortcut( + QKeySequence(Qt.Modifier.CTRL | Qt.Modifier.SHIFT | Qt.Key.Key_Z), self + ) self.redoScut.setContext(Qt.ShortcutContext.WidgetShortcut) self.redoScut.activated.connect(self.redo) self.newShortcutCS.activated.connect(self.autoComplete) self.runScut = QShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_E), self) self.runScut.setContext(Qt.ShortcutContext.WidgetShortcut) self.runScut.activated.connect(self.runSelectedCode) # spellok - self.runScriptScut = QShortcut(QKeySequence(Qt.Modifier.SHIFT | Qt.Modifier.CTRL | Qt.Key.Key_E), self) + self.runScriptScut = QShortcut( + QKeySequence(Qt.Modifier.SHIFT | Qt.Modifier.CTRL | Qt.Key.Key_E), self + ) self.runScriptScut.setContext(Qt.ShortcutContext.WidgetShortcut) self.runScriptScut.activated.connect(self.runScriptCode) - self.syntaxCheckScut = QShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_4), self) + self.syntaxCheckScut = QShortcut( + QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_4), self + ) self.syntaxCheckScut.setContext(Qt.ShortcutContext.WidgetShortcut) self.syntaxCheckScut.activated.connect(self.syntaxCheck) self.modificationChanged.connect(self.editor_tab.modified) @@ -139,22 +149,26 @@ def settingsEditor(self): def contextMenuEvent(self, e): menu = QMenu(self) menu.addAction( - QCoreApplication.translate("PythonConsole", "Hide Editor"), - self.hideEditor) + QCoreApplication.translate("PythonConsole", "Hide Editor"), self.hideEditor + ) menu.addSeparator() - syntaxCheckAction = QAction(QgsApplication.getThemeIcon("console/iconSyntaxErrorConsole.svg"), - QCoreApplication.translate("PythonConsole", "Check Syntax"), - menu) + syntaxCheckAction = QAction( + QgsApplication.getThemeIcon("console/iconSyntaxErrorConsole.svg"), + QCoreApplication.translate("PythonConsole", "Check Syntax"), + menu, + ) syntaxCheckAction.triggered.connect(self.syntaxCheck) - syntaxCheckAction.setShortcut('Ctrl+4') + syntaxCheckAction.setShortcut("Ctrl+4") menu.addAction(syntaxCheckAction) - runSelected = QAction(QgsApplication.getThemeIcon("console/mIconRunConsole.svg"), # spellok - QCoreApplication.translate("PythonConsole", "Run Selected"), - menu) + runSelected = QAction( + QgsApplication.getThemeIcon("console/mIconRunConsole.svg"), # spellok + QCoreApplication.translate("PythonConsole", "Run Selected"), + menu, + ) runSelected.triggered.connect(self.runSelectedCode) # spellok - runSelected.setShortcut('Ctrl+E') # spellok + runSelected.setShortcut("Ctrl+E") # spellok menu.addAction(runSelected) # spellok word = self.selectedText() or self.wordAtPoint(e.pos()) @@ -162,66 +176,85 @@ def contextMenuEvent(self, e): context_help_action = QAction( QgsApplication.getThemeIcon("mActionHelpContents.svg"), QCoreApplication.translate("PythonConsole", "Context Help"), - menu) - context_help_action.triggered.connect(partial(self.console_widget.shell.showApiDocumentation, word, force_search=True)) - context_help_action.setShortcut('F1') + menu, + ) + context_help_action.triggered.connect( + partial( + self.console_widget.shell.showApiDocumentation, + word, + force_search=True, + ) + ) + context_help_action.setShortcut("F1") menu.addAction(context_help_action) - start_action = QAction(QgsApplication.getThemeIcon("mActionStart.svg"), - QCoreApplication.translate("PythonConsole", "Run Script"), - menu) + start_action = QAction( + QgsApplication.getThemeIcon("mActionStart.svg"), + QCoreApplication.translate("PythonConsole", "Run Script"), + menu, + ) start_action.triggered.connect(self.runScriptCode) - start_action.setShortcut('Ctrl+Shift+E') + start_action.setShortcut("Ctrl+Shift+E") menu.addAction(start_action) menu.addSeparator() - undoAction = QAction(QgsApplication.getThemeIcon("mActionUndo.svg"), - QCoreApplication.translate("PythonConsole", "Undo"), - menu) + undoAction = QAction( + QgsApplication.getThemeIcon("mActionUndo.svg"), + QCoreApplication.translate("PythonConsole", "Undo"), + menu, + ) undoAction.triggered.connect(self.undo) undoAction.setShortcut(QKeySequence.StandardKey.Undo) menu.addAction(undoAction) - redoAction = QAction(QgsApplication.getThemeIcon("mActionRedo.svg"), - QCoreApplication.translate("PythonConsole", "Redo"), - menu) + redoAction = QAction( + QgsApplication.getThemeIcon("mActionRedo.svg"), + QCoreApplication.translate("PythonConsole", "Redo"), + menu, + ) redoAction.triggered.connect(self.redo) - redoAction.setShortcut('Ctrl+Shift+Z') + redoAction.setShortcut("Ctrl+Shift+Z") menu.addAction(redoAction) menu.addSeparator() find_action = QAction( QgsApplication.getThemeIcon("console/iconSearchEditorConsole.svg"), QCoreApplication.translate("PythonConsole", "Find Text"), - menu) + menu, + ) find_action.triggered.connect(self.trigger_find) menu.addAction(find_action) cutAction = QAction( QgsApplication.getThemeIcon("mActionEditCut.svg"), QCoreApplication.translate("PythonConsole", "Cut"), - menu) + menu, + ) cutAction.triggered.connect(self.cut) cutAction.setShortcut(QKeySequence.StandardKey.Cut) menu.addAction(cutAction) - copyAction = QAction(QgsApplication.getThemeIcon("mActionEditCopy.svg"), - QCoreApplication.translate("PythonConsole", "Copy"), - menu) + copyAction = QAction( + QgsApplication.getThemeIcon("mActionEditCopy.svg"), + QCoreApplication.translate("PythonConsole", "Copy"), + menu, + ) copyAction.triggered.connect(self.copy) copyAction.setShortcut(QKeySequence.StandardKey.Copy) menu.addAction(copyAction) - pasteAction = QAction(QgsApplication.getThemeIcon("mActionEditPaste.svg"), - QCoreApplication.translate("PythonConsole", "Paste"), - menu) + pasteAction = QAction( + QgsApplication.getThemeIcon("mActionEditPaste.svg"), + QCoreApplication.translate("PythonConsole", "Paste"), + menu, + ) pasteAction.triggered.connect(self.paste) pasteAction.setShortcut(QKeySequence.StandardKey.Paste) menu.addAction(pasteAction) selectAllAction = QAction( - QCoreApplication.translate("PythonConsole", "Select All"), - menu) + QCoreApplication.translate("PythonConsole", "Select All"), menu + ) selectAllAction.triggered.connect(self.selectAll) selectAllAction.setShortcut(QKeySequence.StandardKey.SelectAll) menu.addAction(selectAllAction) @@ -230,27 +263,38 @@ def contextMenuEvent(self, e): toggle_comment_action = QAction( QgsApplication.getThemeIcon("console/iconCommentEditorConsole.svg"), QCoreApplication.translate("PythonConsole", "Toggle Comment"), - menu) + menu, + ) toggle_comment_action.triggered.connect(self.toggleComment) - toggle_comment_action.setShortcut('Ctrl+:') + toggle_comment_action.setShortcut("Ctrl+:") menu.addAction(toggle_comment_action) menu.addSeparator() gist_menu = QMenu(self) - gist_menu.setTitle(QCoreApplication.translate("PythonConsole", "Share on GitHub")) + gist_menu.setTitle( + QCoreApplication.translate("PythonConsole", "Share on GitHub") + ) gist_menu.setIcon(QgsApplication.getThemeIcon("console/iconCodepadConsole.svg")) - gist_menu.addAction(QCoreApplication.translate("PythonConsole", "Secret Gist"), - partial(self.shareOnGist, False)) - gist_menu.addAction(QCoreApplication.translate("PythonConsole", "Public Gist"), - partial(self.shareOnGist, True)) + gist_menu.addAction( + QCoreApplication.translate("PythonConsole", "Secret Gist"), + partial(self.shareOnGist, False), + ) + gist_menu.addAction( + QCoreApplication.translate("PythonConsole", "Public Gist"), + partial(self.shareOnGist, True), + ) menu.addMenu(gist_menu) - showCodeInspection = menu.addAction(QgsApplication.getThemeIcon("console/iconClassBrowserConsole.svg"), - QCoreApplication.translate("PythonConsole", "Hide/Show Object Inspector"), - self.objectListEditor) + showCodeInspection = menu.addAction( + QgsApplication.getThemeIcon("console/iconClassBrowserConsole.svg"), + QCoreApplication.translate("PythonConsole", "Hide/Show Object Inspector"), + self.objectListEditor, + ) menu.addSeparator() - menu.addAction(QgsApplication.getThemeIcon("console/iconSettingsConsole.svg"), - QCoreApplication.translate("PythonConsole", "Options…"), - self.console_widget.openSettings) + menu.addAction( + QgsApplication.getThemeIcon("console/iconSettingsConsole.svg"), + QCoreApplication.translate("PythonConsole", "Options…"), + self.console_widget.openSettings, + ) syntaxCheckAction.setEnabled(False) pasteAction.setEnabled(False) cutAction.setEnabled(False) @@ -264,7 +308,7 @@ def contextMenuEvent(self, e): runSelected.setEnabled(True) # spellok copyAction.setEnabled(True) cutAction.setEnabled(True) - if not self.text() == '': + if not self.text() == "": selectAllAction.setEnabled(True) syntaxCheckAction.setEnabled(True) if self.isUndoAvailable(): @@ -273,8 +317,7 @@ def contextMenuEvent(self, e): redoAction.setEnabled(True) if QApplication.clipboard().text(): pasteAction.setEnabled(True) - if QgsSettings().value("pythonConsole/enableObjectInsp", - False, type=bool): + if QgsSettings().value("pythonConsole/enableObjectInsp", False, type=bool): showCodeInspection.setEnabled(True) menu.exec(self.mapToGlobal(e.pos())) @@ -297,7 +340,7 @@ def hideEditor(self): def createTempFile(self): name = tempfile.NamedTemporaryFile(delete=False).name # Need to use newline='' to avoid adding extra \r characters on Windows - with open(name, 'w', encoding='utf-8', newline='') as f: + with open(name, "w", encoding="utf-8", newline="") as f: f.write(self.text()) return name @@ -305,8 +348,9 @@ def runScriptCode(self): autoSave = QgsSettings().value("pythonConsole/autoSaveScript", False, type=bool) filename = self.code_editor_widget.filePath() filename_override = None - msgEditorBlank = QCoreApplication.translate('PythonConsole', - 'Hey, type something to run!') + msgEditorBlank = QCoreApplication.translate( + "PythonConsole", "Hey, type something to run!" + ) if filename is None: if not self.isModified(): self.showMessage(msgEditorBlank) @@ -319,8 +363,10 @@ def runScriptCode(self): elif not filename or self.isModified(): # Create a new temp file if the file isn't already saved. filename = self.createTempFile() - filename_override = self.tab_widget.tabText(self.tab_widget.currentIndex()) - if filename_override.startswith('*'): + filename_override = self.tab_widget.tabText( + self.tab_widget.currentIndex() + ) + if filename_override.startswith("*"): filename_override = filename_override[1:] deleteTempFile = True @@ -342,10 +388,14 @@ def getTextFromEditor(self): def goToLine(self, objName, linenr): self.SendScintilla(QsciScintilla.SCI_GOTOLINE, linenr - 1) - self.SendScintilla(QsciScintilla.SCI_SETTARGETSTART, - self.SendScintilla(QsciScintilla.SCI_GETCURRENTPOS)) + self.SendScintilla( + QsciScintilla.SCI_SETTARGETSTART, + self.SendScintilla(QsciScintilla.SCI_GETCURRENTPOS), + ) self.SendScintilla(QsciScintilla.SCI_SETTARGETEND, len(self.text())) - pos = self.SendScintilla(QsciScintilla.SCI_SEARCHINTARGET, len(objName), objName) + pos = self.SendScintilla( + QsciScintilla.SCI_SEARCHINTARGET, len(objName), objName + ) index = pos - self.SendScintilla(QsciScintilla.SCI_GETCURRENTPOS) # line, _ = self.getCursorPosition() self.setSelection(linenr - 1, index, linenr - 1, index + len(objName)) @@ -373,11 +423,13 @@ def loaded_external_changes(self): self.tab_widget.listObject(self.tab_widget.currentWidget()) def fileReadOnly(self): - msgText = QCoreApplication.translate('PythonConsole', - 'The file "{0}" is read only, please save to different file first.').format(self.code_editor_widget.filePath()) + msgText = QCoreApplication.translate( + "PythonConsole", + 'The file "{0}" is read only, please save to different file first.', + ).format(self.code_editor_widget.filePath()) self.showMessage(msgText) - def save(self, filename: Optional[str] = None): + def save(self, filename: str | None = None): if self.isReadOnly(): return @@ -386,13 +438,18 @@ def save(self, filename: Optional[str] = None): index = self.tab_widget.indexOf(self.editor_tab) if not filename and not self.code_editor_widget.filePath(): - saveTr = QCoreApplication.translate('PythonConsole', - 'Python Console: Save file') + saveTr = QCoreApplication.translate( + "PythonConsole", "Python Console: Save file" + ) folder = QgsSettings().value("pythonConsole/lastDirPath", QDir.homePath()) - path, filter = QFileDialog().getSaveFileName(self, - saveTr, - os.path.join(folder, self.tab_widget.tabText(index).replace('*', '') + '.py'), - "Script file (*.py)") + path, filter = QFileDialog().getSaveFileName( + self, + saveTr, + os.path.join( + folder, self.tab_widget.tabText(index).replace("*", "") + ".py" + ), + "Script file (*.py)", + ) # If the user didn't select a file, abort the save operation if not path: self.code_editor_widget.setFilePath(None) @@ -401,29 +458,40 @@ def save(self, filename: Optional[str] = None): self.code_editor_widget.save(filename) - msgText = QCoreApplication.translate('PythonConsole', - 'Script was correctly saved.') + msgText = QCoreApplication.translate( + "PythonConsole", "Script was correctly saved." + ) self.showMessage(msgText) # Save the new contents # Need to use newline='' to avoid adding extra \r characters on Windows - with open(self.code_editor_widget.filePath(), 'w', encoding='utf-8', newline='') as f: + with open( + self.code_editor_widget.filePath(), "w", encoding="utf-8", newline="" + ) as f: f.write(self.text()) - self.tab_widget.setTabTitle(index, Path(self.code_editor_widget.filePath()).name) + self.tab_widget.setTabTitle( + index, Path(self.code_editor_widget.filePath()).name + ) self.tab_widget.setTabToolTip(index, self.code_editor_widget.filePath()) self.setModified(False) self.console_widget.saveFileButton.setEnabled(False) - self.console_widget.updateTabListScript(self.code_editor_widget.filePath(), action='append') + self.console_widget.updateTabListScript( + self.code_editor_widget.filePath(), action="append" + ) self.tab_widget.listObject(self.editor_tab) - QgsSettings().setValue("pythonConsole/lastDirPath", - Path(self.code_editor_widget.filePath()).parent.as_posix()) + QgsSettings().setValue( + "pythonConsole/lastDirPath", + Path(self.code_editor_widget.filePath()).parent.as_posix(), + ) def event(self, e): - """ Used to override the Application shortcuts when the editor has focus """ + """Used to override the Application shortcuts when the editor has focus""" if e.type() == QEvent.Type.ShortcutOverride: ctrl = e.modifiers() == Qt.KeyboardModifier.ControlModifier - ctrl_shift = e.modifiers() == (Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.ShiftModifier) + ctrl_shift = e.modifiers() == ( + Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.ShiftModifier + ) if ( (ctrl and e.key() == Qt.Key.Key_W) or (ctrl_shift and e.key() == Qt.Key.Key_W) @@ -439,7 +507,9 @@ def event(self, e): def keyPressEvent(self, e): ctrl = e.modifiers() == Qt.KeyboardModifier.ControlModifier - ctrl_shift = e.modifiers() == (Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.ShiftModifier) + ctrl_shift = e.modifiers() == ( + Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.ShiftModifier + ) # Ctrl+W: close current tab if ctrl and e.key() == Qt.Key.Key_W: @@ -463,10 +533,9 @@ def keyPressEvent(self, e): super().keyPressEvent(e) - def showMessage(self, - text: str, - title: Optional[str] = None, - level=Qgis.MessageLevel.Info): + def showMessage( + self, text: str, title: str | None = None, level=Qgis.MessageLevel.Info + ): self.editor_tab.showMessage(text, level, title=title) @@ -474,29 +543,25 @@ class EditorTab(QWidget): search_bar_toggled = pyqtSignal(bool) - def __init__(self, - tab_widget: EditorTabWidget, - console_widget: PythonConsoleWidget, - filename: Optional[str], - read_only: bool): + def __init__( + self, + tab_widget: EditorTabWidget, + console_widget: PythonConsoleWidget, + filename: str | None, + read_only: bool, + ): super().__init__(tab_widget) self.tab_widget: EditorTabWidget = tab_widget - self._editor = Editor(editor_tab=self, - console_widget=console_widget, - tab_widget=tab_widget) - - self._editor_code_widget = QgsCodeEditorWidget( - self._editor + self._editor = Editor( + editor_tab=self, console_widget=console_widget, tab_widget=tab_widget ) + + self._editor_code_widget = QgsCodeEditorWidget(self._editor) self._editor.set_code_editor_widget(self._editor_code_widget) - self._editor_code_widget.searchBarToggled.connect( - self.search_bar_toggled - ) + self._editor_code_widget.searchBarToggled.connect(self.search_bar_toggled) - self._editor.trigger_find.connect( - self._editor_code_widget.triggerFind - ) + self._editor.trigger_find.connect(self._editor_code_widget.triggerFind) if filename: if QFileInfo(filename).exists(): @@ -511,7 +576,7 @@ def __init__(self, def set_file_path(self, path: str): self._editor_code_widget.setFilePath(path) - def file_path(self) -> Optional[str]: + def file_path(self) -> str | None: return self._editor_code_widget.filePath() def open_in_external_editor(self): @@ -542,14 +607,14 @@ def close(self): self.tab_widget._removeTab(self, tab2index=True) def __getattr__(self, name): - """ Forward all missing attribute requests to the editor.""" + """Forward all missing attribute requests to the editor.""" try: return super().__getattr__(name) except AttributeError: return getattr(self._editor, name) def __setattr__(self, name, value): - """ Forward all missing attribute requests to the editor.""" + """Forward all missing attribute requests to the editor.""" try: return super().__setattr__(name, value) except AttributeError: @@ -571,38 +636,45 @@ def __init__(self, console_widget: PythonConsoleWidget): # Layout for top frame (restore tabs) self.layoutTopFrame = QGridLayout(self) self.layoutTopFrame.setContentsMargins(0, 0, 0, 0) - spacerItem = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + spacerItem = QSpacerItem( + 20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding + ) self.layoutTopFrame.addItem(spacerItem, 1, 0, 1, 1) self.topFrame = QFrame(self) - self.topFrame.setStyleSheet('background-color: rgb(255, 255, 230);') + self.topFrame.setStyleSheet("background-color: rgb(255, 255, 230);") self.topFrame.setFrameShape(QFrame.Shape.StyledPanel) self.topFrame.setMinimumHeight(24) self.layoutTopFrame2 = QGridLayout(self.topFrame) self.layoutTopFrame2.setContentsMargins(0, 0, 0, 0) - label = QCoreApplication.translate("PythonConsole", - "Click on button to restore all tabs from last session.") + label = QCoreApplication.translate( + "PythonConsole", "Click on button to restore all tabs from last session." + ) self.label = QLabel(label) self.restoreTabsButton = QToolButton() - toolTipRestore = QCoreApplication.translate("PythonConsole", - "Restore tabs") + toolTipRestore = QCoreApplication.translate("PythonConsole", "Restore tabs") self.restoreTabsButton.setToolTip(toolTipRestore) - self.restoreTabsButton.setIcon(QgsApplication.getThemeIcon("console/iconRestoreTabsConsole.svg")) + self.restoreTabsButton.setIcon( + QgsApplication.getThemeIcon("console/iconRestoreTabsConsole.svg") + ) self.restoreTabsButton.setIconSize(QSize(24, 24)) self.restoreTabsButton.setAutoRaise(True) self.restoreTabsButton.setCursor(Qt.CursorShape.PointingHandCursor) - self.restoreTabsButton.setStyleSheet('QToolButton:hover{border: none } \ - QToolButton:pressed{border: none}') + self.restoreTabsButton.setStyleSheet( + "QToolButton:hover{border: none } \ + QToolButton:pressed{border: none}" + ) self.clButton = QToolButton() - toolTipClose = QCoreApplication.translate("PythonConsole", - "Close") + toolTipClose = QCoreApplication.translate("PythonConsole", "Close") self.clButton.setToolTip(toolTipClose) self.clButton.setIcon(QgsApplication.getThemeIcon("/mIconClose.svg")) self.clButton.setIconSize(QSize(18, 18)) self.clButton.setCursor(Qt.CursorShape.PointingHandCursor) - self.clButton.setStyleSheet('QToolButton:hover{border: none } \ - QToolButton:pressed{border: none}') + self.clButton.setStyleSheet( + "QToolButton:hover{border: none } \ + QToolButton:pressed{border: none}" + ) self.clButton.setAutoRaise(True) sizePolicy = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed) @@ -617,7 +689,7 @@ def __init__(self, console_widget: PythonConsoleWidget): self.clButton.clicked.connect(self.closeRestore) # Fixes #7653 - if sys.platform != 'darwin': + if sys.platform != "darwin": self.setDocumentMode(True) self.setMovable(True) @@ -629,10 +701,13 @@ def __init__(self, console_widget: PythonConsoleWidget): self.fileTabMenu.aboutToShow.connect(self.showFileTabMenu) self.fileTabMenu.triggered.connect(self.showFileTabMenuTriggered) self.fileTabButton = QToolButton() - txtToolTipMenuFile = QCoreApplication.translate("PythonConsole", - "List all tabs") + txtToolTipMenuFile = QCoreApplication.translate( + "PythonConsole", "List all tabs" + ) self.fileTabButton.setToolTip(txtToolTipMenuFile) - self.fileTabButton.setIcon(QgsApplication.getThemeIcon("console/iconFileTabsMenuConsole.svg")) + self.fileTabButton.setIcon( + QgsApplication.getThemeIcon("console/iconFileTabsMenuConsole.svg") + ) self.fileTabButton.setIconSize(QSize(24, 24)) self.fileTabButton.setAutoRaise(True) self.fileTabButton.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup) @@ -643,26 +718,24 @@ def __init__(self, console_widget: PythonConsoleWidget): # New Editor button self.newTabButton = QToolButton() - txtToolTipNewTab = QCoreApplication.translate("PythonConsole", - "New Editor") + txtToolTipNewTab = QCoreApplication.translate("PythonConsole", "New Editor") self.newTabButton.setToolTip(txtToolTipNewTab) self.newTabButton.setAutoRaise(True) - self.newTabButton.setIcon(QgsApplication.getThemeIcon("console/iconNewTabEditorConsole.svg")) + self.newTabButton.setIcon( + QgsApplication.getThemeIcon("console/iconNewTabEditorConsole.svg") + ) self.newTabButton.setIconSize(QSize(24, 24)) self.setCornerWidget(self.newTabButton, Qt.Corner.TopLeftCorner) self.newTabButton.clicked.connect(self.newTabEditor) def _currentWidgetChanged(self, tab): - if QgsSettings().value("pythonConsole/enableObjectInsp", - False, type=bool): + if QgsSettings().value("pythonConsole/enableObjectInsp", False, type=bool): self.listObject(tab) self.changeLastDirPath(tab) self.enableSaveIfModified(tab) if self.currentWidget(): - self.search_bar_toggled.emit( - self.currentWidget().search_bar_visible() - ) + self.search_bar_toggled.emit(self.currentWidget().search_bar_visible()) def toggle_search_bar(self, visible: bool): """ @@ -682,24 +755,26 @@ def contextMenuEvent(self, e): menu.addSeparator() menu.addAction( QCoreApplication.translate("PythonConsole", "New Editor"), - self.newTabEditor) + self.newTabEditor, + ) menu.addSeparator() closeTabAction = menu.addAction( - QCoreApplication.translate("PythonConsole", "Close Tab"), - cW.close) + QCoreApplication.translate("PythonConsole", "Close Tab"), cW.close + ) closeAllTabAction = menu.addAction( - QCoreApplication.translate("PythonConsole", "Close All"), - self.closeAll) + QCoreApplication.translate("PythonConsole", "Close All"), self.closeAll + ) closeOthersTabAction = menu.addAction( QCoreApplication.translate("PythonConsole", "Close Others"), - self.closeOthers) + self.closeOthers, + ) menu.addSeparator() saveAction = menu.addAction( - QCoreApplication.translate("PythonConsole", "Save"), - cW.save) + QCoreApplication.translate("PythonConsole", "Save"), cW.save + ) menu.addAction( - QCoreApplication.translate("PythonConsole", "Save As"), - self.saveAs) + QCoreApplication.translate("PythonConsole", "Save As"), self.saveAs + ) closeTabAction.setEnabled(False) closeAllTabAction.setEnabled(False) closeOthersTabAction.setEnabled(False) @@ -723,7 +798,9 @@ def closeAll(self): for i in range(countTab - 1, 0, -1): self._removeTab(i) - self.newTabEditor(tabName=QCoreApplication.translate("PythonConsole", "Untitled-0")) + self.newTabEditor( + tabName=QCoreApplication.translate("PythonConsole", "Untitled-0") + ) self._removeTab(0) def saveAs(self): @@ -739,31 +816,35 @@ def enableToolBarEditor(self, enable): enable = False self.console_widget.toolBarEditor.setEnabled(enable) - def newTabEditor(self, tabName=None, filename: Optional[str] = None): + def newTabEditor(self, tabName=None, filename: str | None = None): read_only = False if filename: read_only = not QFileInfo(filename).isWritable() try: - fn = codecs.open(filename, "rb", encoding='utf-8') + fn = codecs.open(filename, "rb", encoding="utf-8") fn.read() fn.close() - except IOError as error: - IOErrorTr = QCoreApplication.translate('PythonConsole', - 'The file {0} could not be opened. Error: {1}\n').format(filename, - error.strerror) - print('## Error: ') + except OSError as error: + IOErrorTr = QCoreApplication.translate( + "PythonConsole", "The file {0} could not be opened. Error: {1}\n" + ).format(filename, error.strerror) + print("## Error: ") sys.stderr.write(IOErrorTr) return nr = self.count() if not tabName: - tabName = QCoreApplication.translate('PythonConsole', 'Untitled-{0}').format(nr) - tab = EditorTab(tab_widget=self, - console_widget=self.console_widget, - filename=filename, - read_only=read_only) - self.iconTab = QgsApplication.getThemeIcon('console/iconTabEditorConsole.svg') - self.addTab(tab, self.iconTab, tabName + ' (ro)' if read_only else tabName) + tabName = QCoreApplication.translate( + "PythonConsole", "Untitled-{0}" + ).format(nr) + tab = EditorTab( + tab_widget=self, + console_widget=self.console_widget, + filename=filename, + read_only=read_only, + ) + self.iconTab = QgsApplication.getThemeIcon("console/iconTabEditorConsole.svg") + self.addTab(tab, self.iconTab, tabName + " (ro)" if read_only else tabName) self.setCurrentWidget(tab) if filename: self.setTabToolTip(self.currentIndex(), filename) @@ -781,7 +862,7 @@ def _tab_search_bar_toggled(self, visible: bool): def tabModified(self, tab, modified): index = self.indexOf(tab) s = self.tabText(index) - self.setTabTitle(index, '*{}'.format(s) if modified else re.sub(r'^(\*)', '', s)) + self.setTabTitle(index, f"*{s}" if modified else re.sub(r"^(\*)", "", s)) self.console_widget.saveFileButton.setEnabled(modified) def setTabTitle(self, tab, title): @@ -792,25 +873,37 @@ def _removeTab(self, tab, tab2index=False): tab = self.indexOf(tab) editorTab = self.widget(tab) if editorTab.isModified(): - txtSaveOnRemove = QCoreApplication.translate("PythonConsole", - "Python Console: Save File") - txtMsgSaveOnRemove = QCoreApplication.translate("PythonConsole", - "The file '{0}' has been modified, save changes?").format(self.tabText(tab)) - res = QMessageBox.question(self, txtSaveOnRemove, - txtMsgSaveOnRemove, - QMessageBox.StandardButton.Save | QMessageBox.StandardButton.Discard | QMessageBox.StandardButton.Cancel) + txtSaveOnRemove = QCoreApplication.translate( + "PythonConsole", "Python Console: Save File" + ) + txtMsgSaveOnRemove = QCoreApplication.translate( + "PythonConsole", + "The file '{0}' has been modified, save changes?", + ).format(self.tabText(tab)) + res = QMessageBox.question( + self, + txtSaveOnRemove, + txtMsgSaveOnRemove, + QMessageBox.StandardButton.Save + | QMessageBox.StandardButton.Discard + | QMessageBox.StandardButton.Cancel, + ) if res == QMessageBox.StandardButton.Cancel: return if res == QMessageBox.StandardButton.Save: editorTab.save() if editorTab.code_editor_widget.filePath(): - self.console_widget.updateTabListScript(editorTab.code_editor_widget.filePath(), action='remove') + self.console_widget.updateTabListScript( + editorTab.code_editor_widget.filePath(), action="remove" + ) self.removeTab(tab) if self.count() < 1: self.newTabEditor() else: if editorTab.code_editor_widget.filePath(): - self.console_widget.updateTabListScript(editorTab.code_editor_widget.filePath(), action='remove') + self.console_widget.updateTabListScript( + editorTab.code_editor_widget.filePath(), action="remove" + ) if self.count() <= 1: self.removeTab(tab) self.newTabEditor() @@ -837,15 +930,16 @@ def restoreTabs(self): for script in self.restoreTabList: pathFile = script if QFileInfo(pathFile).exists(): - tabName = pathFile.split('/')[-1] + tabName = pathFile.split("/")[-1] self.newTabEditor(tabName, pathFile) else: - errOnRestore = QCoreApplication.translate("PythonConsole", - "Unable to restore the file: \n{0}\n").format(pathFile) - print('## Error: ') + errOnRestore = QCoreApplication.translate( + "PythonConsole", "Unable to restore the file: \n{0}\n" + ).format(pathFile) + print("## Error: ") s = errOnRestore sys.stderr.write(s) - self.console_widget.updateTabListScript(pathFile, action='remove') + self.console_widget.updateTabListScript(pathFile, action="remove") if self.count() < 1: self.newTabEditor(filename=None) self.topFrame.close() @@ -861,7 +955,9 @@ def closeRestore(self): def showFileTabMenu(self): self.fileTabMenu.clear() for index in range(self.count()): - action = self.fileTabMenu.addAction(self.tabIcon(index), self.tabText(index)) + action = self.fileTabMenu.addAction( + self.tabIcon(index), self.tabText(index) + ) action.setData(index) def showFileTabMenuTriggered(self, action): @@ -888,11 +984,15 @@ def listObject(self, tab): dictObject = {} readModule = pyclbr.readmodule(module) readModuleFunction = pyclbr.readmodule_ex(module) - for name, class_data in sorted(list(readModule.items()), key=lambda x: x[1].lineno): - if os.path.normpath(class_data.file) == os.path.normpath(tabWidget.file_path()): + for name, class_data in sorted( + list(readModule.items()), key=lambda x: x[1].lineno + ): + if os.path.normpath(class_data.file) == os.path.normpath( + tabWidget.file_path() + ): superClassName = [] for superClass in class_data.super: - if superClass == 'object': + if superClass == "object": continue if isinstance(superClass, str): superClassName.append(superClass) @@ -900,56 +1000,76 @@ def listObject(self, tab): superClassName.append(superClass.name) classItem = QTreeWidgetItem() if superClassName: - super = ', '.join([i for i in superClassName]) - classItem.setText(0, name + ' [' + super + ']') - classItem.setToolTip(0, name + ' [' + super + ']') + super = ", ".join([i for i in superClassName]) + classItem.setText(0, name + " [" + super + "]") + classItem.setToolTip(0, name + " [" + super + "]") else: classItem.setText(0, name) classItem.setToolTip(0, name) - if sys.platform.startswith('win'): + if sys.platform.startswith("win"): classItem.setSizeHint(0, QSize(18, 18)) classItem.setText(1, str(class_data.lineno)) - iconClass = QgsApplication.getThemeIcon("console/iconClassTreeWidgetConsole.svg") + iconClass = QgsApplication.getThemeIcon( + "console/iconClassTreeWidgetConsole.svg" + ) classItem.setIcon(0, iconClass) dictObject[name] = class_data.lineno - for meth, lineno in sorted(list(class_data.methods.items()), key=itemgetter(1)): + for meth, lineno in sorted( + list(class_data.methods.items()), key=itemgetter(1) + ): methodItem = QTreeWidgetItem() - methodItem.setText(0, meth + ' ') + methodItem.setText(0, meth + " ") methodItem.setText(1, str(lineno)) methodItem.setToolTip(0, meth) - iconMeth = QgsApplication.getThemeIcon("console/iconMethodTreeWidgetConsole.svg") + iconMeth = QgsApplication.getThemeIcon( + "console/iconMethodTreeWidgetConsole.svg" + ) methodItem.setIcon(0, iconMeth) - if sys.platform.startswith('win'): + if sys.platform.startswith("win"): methodItem.setSizeHint(0, QSize(18, 18)) classItem.addChild(methodItem) dictObject[meth] = lineno - self.console_widget.listClassMethod.addTopLevelItem(classItem) - for func_name, data in sorted(list(readModuleFunction.items()), key=lambda x: x[1].lineno): - if isinstance(data, pyclbr.Function) and \ - os.path.normpath(data.file) == os.path.normpath(tabWidget.file_path()): + self.console_widget.listClassMethod.addTopLevelItem( + classItem + ) + for func_name, data in sorted( + list(readModuleFunction.items()), key=lambda x: x[1].lineno + ): + if isinstance(data, pyclbr.Function) and os.path.normpath( + data.file + ) == os.path.normpath(tabWidget.file_path()): funcItem = QTreeWidgetItem() - funcItem.setText(0, func_name + ' ') + funcItem.setText(0, func_name + " ") funcItem.setText(1, str(data.lineno)) funcItem.setToolTip(0, func_name) - iconFunc = QgsApplication.getThemeIcon("console/iconFunctionTreeWidgetConsole.svg") + iconFunc = QgsApplication.getThemeIcon( + "console/iconFunctionTreeWidgetConsole.svg" + ) funcItem.setIcon(0, iconFunc) - if sys.platform.startswith('win'): + if sys.platform.startswith("win"): funcItem.setSizeHint(0, QSize(18, 18)) dictObject[func_name] = data.lineno - self.console_widget.listClassMethod.addTopLevelItem(funcItem) + self.console_widget.listClassMethod.addTopLevelItem( + funcItem + ) if found: sys.path.remove(pathFile) except: msgItem = QTreeWidgetItem() - msgItem.setText(0, QCoreApplication.translate("PythonConsole", "Check Syntax")) - msgItem.setText(1, 'syntaxError') - iconWarning = QgsApplication.getThemeIcon("console/iconSyntaxErrorConsole.svg") + msgItem.setText( + 0, QCoreApplication.translate("PythonConsole", "Check Syntax") + ) + msgItem.setText(1, "syntaxError") + iconWarning = QgsApplication.getThemeIcon( + "console/iconSyntaxErrorConsole.svg" + ) msgItem.setIcon(0, iconWarning) self.console_widget.listClassMethod.addTopLevelItem(msgItem) def refreshSettingsEditor(self): - objInspectorEnabled = QgsSettings().value("pythonConsole/enableObjectInsp", - False, type=bool) + objInspectorEnabled = QgsSettings().value( + "pythonConsole/enableObjectInsp", False, type=bool + ) listObj = self.console_widget.objectListButton if self.console_widget.listClassMethod.isVisible(): listObj.setChecked(objInspectorEnabled) @@ -963,8 +1083,10 @@ def refreshSettingsEditor(self): def changeLastDirPath(self, tab): tabWidget = self.widget(tab) if tabWidget and tabWidget.file_path(): - QgsSettings().setValue("pythonConsole/lastDirPath", - Path(tabWidget.file_path()).parent.as_posix()) + QgsSettings().setValue( + "pythonConsole/lastDirPath", + Path(tabWidget.file_path()).parent.as_posix(), + ) def showMessage(self, text, level=Qgis.MessageLevel.Info, timeout=-1, title=""): currWidget = self.currentWidget() diff --git a/python/console/console_output.py b/python/console/console_output.py index b1544c687e65..9fab7c043704 100644 --- a/python/console/console_output.py +++ b/python/console/console_output.py @@ -17,6 +17,7 @@ ***************************************************************************/ Some portions of code were taken from https://code.google.com/p/pydee/ """ + from __future__ import annotations import sys @@ -24,9 +25,25 @@ from typing import TYPE_CHECKING from qgis.PyQt import sip -from qgis.PyQt.QtCore import Qt, QCoreApplication, QThread, QMetaObject, Q_ARG, QObject, pyqtSlot +from qgis.PyQt.QtCore import ( + Qt, + QCoreApplication, + QThread, + QMetaObject, + Q_ARG, + QObject, + pyqtSlot, +) from qgis.PyQt.QtGui import QColor, QKeySequence -from qgis.PyQt.QtWidgets import QAction, QGridLayout, QSpacerItem, QSizePolicy, QShortcut, QMenu, QApplication +from qgis.PyQt.QtWidgets import ( + QAction, + QGridLayout, + QSpacerItem, + QSizePolicy, + QShortcut, + QMenu, + QApplication, +) from qgis.PyQt.Qsci import QsciScintilla from qgis.core import Qgis, QgsApplication, QgsSettings from qgis.gui import QgsMessageBar, QgsCodeEditorPython @@ -58,19 +75,33 @@ def write(self, m): # This manage the case when console is called from another thread if QThread.currentThread() != QCoreApplication.instance().thread(): - QMetaObject.invokeMethod(self, "write", Qt.ConnectionType.QueuedConnection, Q_ARG(str, m)) + QMetaObject.invokeMethod( + self, "write", Qt.ConnectionType.QueuedConnection, Q_ARG(str, m) + ) return if self.style == "_traceback": # Show errors in red - stderrColor = QColor(QgsSettings().value("pythonConsole/stderrFontColor", QColor(self.ERROR_COLOR))) - self.sO.SendScintilla(QsciScintilla.SCI_STYLESETFORE, self.ERROR_STYLE_INDEX, stderrColor) - self.sO.SendScintilla(QsciScintilla.SCI_STYLESETITALIC, self.ERROR_STYLE_INDEX, True) - self.sO.SendScintilla(QsciScintilla.SCI_STYLESETBOLD, self.ERROR_STYLE_INDEX, True) + stderrColor = QColor( + QgsSettings().value( + "pythonConsole/stderrFontColor", QColor(self.ERROR_COLOR) + ) + ) + self.sO.SendScintilla( + QsciScintilla.SCI_STYLESETFORE, self.ERROR_STYLE_INDEX, stderrColor + ) + self.sO.SendScintilla( + QsciScintilla.SCI_STYLESETITALIC, self.ERROR_STYLE_INDEX, True + ) + self.sO.SendScintilla( + QsciScintilla.SCI_STYLESETBOLD, self.ERROR_STYLE_INDEX, True + ) pos = self.sO.linearPosition() self.sO.SendScintilla(QsciScintilla.SCI_STARTSTYLING, pos, 0) self.sO.append(m) - self.sO.SendScintilla(QsciScintilla.SCI_SETSTYLING, len(m), self.ERROR_STYLE_INDEX) + self.sO.SendScintilla( + QsciScintilla.SCI_SETSTYLING, len(m), self.ERROR_STYLE_INDEX + ) else: self.sO.append(m) @@ -94,7 +125,9 @@ def isatty(self): return False -FULL_HELP_TEXT = QCoreApplication.translate("PythonConsole", """QGIS Python Console +FULL_HELP_TEXT = QCoreApplication.translate( + "PythonConsole", + """QGIS Python Console ====================================== The console is a Python interpreter that allows you to execute python commands. @@ -122,14 +155,15 @@ def isatty(self): !ping www.qgis.org: Ping the QGIS website !pip install black: install black python formatter using pip (if available) - ?: Show this help -""") +""", +) class ShellOutputScintilla(QgsCodeEditorPython): - def __init__(self, - console_widget: PythonConsoleWidget, - shell_editor: ShellScintilla): + def __init__( + self, console_widget: PythonConsoleWidget, shell_editor: ShellScintilla + ): super().__init__(console_widget) self.console_widget: PythonConsoleWidget = console_widget self.shell_editor: ShellScintilla = shell_editor @@ -137,7 +171,9 @@ def __init__(self, # Creates layout for message bar self.layout = QGridLayout(self) self.layout.setContentsMargins(0, 0, 0, 0) - spacerItem = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + spacerItem = QSpacerItem( + 20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding + ) self.layout.addItem(spacerItem, 1, 0, 1, 1) # messageBar instance self.infoBar = QgsMessageBar() @@ -180,20 +216,22 @@ def on_app_exit(self): sys.stderr = self._old_stderr def insertInitText(self): - txtInit = QCoreApplication.translate("PythonConsole", - "Python Console\n" - "Use iface to access QGIS API interface or type '?' for more info\n" - "Security warning: typing commands from an untrusted source can harm your computer") + txtInit = QCoreApplication.translate( + "PythonConsole", + "Python Console\n" + "Use iface to access QGIS API interface or type '?' for more info\n" + "Security warning: typing commands from an untrusted source can harm your computer", + ) - txtInit = '\n'.join(['# ' + line for line in txtInit.split('\n')]) + txtInit = "\n".join(["# " + line for line in txtInit.split("\n")]) # some translation string for the console header ends without '\n' # and the first command in console will be appended at the header text. # The following code add a '\n' at the end of the string if not present. - if txtInit.endswith('\n'): + if txtInit.endswith("\n"): self.setText(txtInit) else: - self.setText(txtInit + '\n') + self.setText(txtInit + "\n") def insertHelp(self): self.append(FULL_HELP_TEXT) @@ -212,31 +250,38 @@ def refreshSettingsOutput(self): self.setCaretWidth(0) # NO (blinking) caret in the output def clearConsole(self): - self.setText('') + self.setText("") self.insertInitText() self.shell_editor.setFocus() def contextMenuEvent(self, e): menu = QMenu(self) - menu.addAction(QgsApplication.getThemeIcon("console/iconHideToolConsole.svg"), - QCoreApplication.translate("PythonConsole", "Hide/Show Toolbar"), - self.hideToolBar) + menu.addAction( + QgsApplication.getThemeIcon("console/iconHideToolConsole.svg"), + QCoreApplication.translate("PythonConsole", "Hide/Show Toolbar"), + self.hideToolBar, + ) menu.addSeparator() showEditorAction = menu.addAction( QgsApplication.getThemeIcon("console/iconShowEditorConsole.svg"), QCoreApplication.translate("PythonConsole", "Show Editor"), - self.showEditor) + self.showEditor, + ) menu.addSeparator() - runAction = QAction(QgsApplication.getThemeIcon("console/mIconRunConsole.svg"), - QCoreApplication.translate("PythonConsole", "Enter Selected"), - menu) + runAction = QAction( + QgsApplication.getThemeIcon("console/mIconRunConsole.svg"), + QCoreApplication.translate("PythonConsole", "Enter Selected"), + menu, + ) runAction.triggered.connect(self.enteredSelected) runAction.setShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_E)) menu.addAction(runAction) - clearAction = QAction(QgsApplication.getThemeIcon("console/iconClearConsole.svg"), - QCoreApplication.translate("PythonConsole", "Clear Console"), - menu) + clearAction = QAction( + QgsApplication.getThemeIcon("console/iconClearConsole.svg"), + QCoreApplication.translate("PythonConsole", "Clear Console"), + menu, + ) clearAction.triggered.connect(self.clearConsole) menu.addAction(clearAction) @@ -245,31 +290,37 @@ def contextMenuEvent(self, e): context_help_action = QAction( QgsApplication.getThemeIcon("mActionHelpContents.svg"), QCoreApplication.translate("PythonConsole", "Context Help"), - menu) - context_help_action.triggered.connect(partial(self.shell_editor.showApiDocumentation, word, force_search=True)) - context_help_action.setShortcut('F1') + menu, + ) + context_help_action.triggered.connect( + partial(self.shell_editor.showApiDocumentation, word, force_search=True) + ) + context_help_action.setShortcut("F1") menu.addAction(context_help_action) menu.addSeparator() copyAction = QAction( QgsApplication.getThemeIcon("mActionEditCopy.svg"), QCoreApplication.translate("PythonConsole", "Copy"), - menu) + menu, + ) copyAction.triggered.connect(self.copy) copyAction.setShortcut(QKeySequence.StandardKey.Copy) menu.addAction(copyAction) selectAllAction = QAction( - QCoreApplication.translate("PythonConsole", "Select All"), - menu) + QCoreApplication.translate("PythonConsole", "Select All"), menu + ) selectAllAction.triggered.connect(self.selectAll) selectAllAction.setShortcut(QKeySequence.StandardKey.SelectAll) menu.addAction(selectAllAction) menu.addSeparator() - settings_action = QAction(QgsApplication.getThemeIcon("console/iconSettingsConsole.svg"), - QCoreApplication.translate("PythonConsole", "Options…"), - menu) + settings_action = QAction( + QgsApplication.getThemeIcon("console/iconSettingsConsole.svg"), + QCoreApplication.translate("PythonConsole", "Options…"), + menu, + ) settings_action.triggered.connect(self.console_widget.openSettings) menu.addAction(settings_action) @@ -281,7 +332,7 @@ def contextMenuEvent(self, e): if self.hasSelectedText(): runAction.setEnabled(True) copyAction.setEnabled(True) - if not self.text(3) == '': + if not self.text(3) == "": selectAllAction.setEnabled(True) clearAction.setEnabled(True) if self.console_widget.tabEditorWidget.isVisible(): @@ -304,7 +355,9 @@ def copy(self): """Copy text to clipboard... or keyboard interrupt""" if self.hasSelectedText(): text = self.selectedText() - text = text.replace('>>> ', '').replace('... ', '').strip() # removing prompts + text = ( + text.replace(">>> ", "").replace("... ", "").strip() + ) # removing prompts QApplication.clipboard().setText(text) else: raise KeyboardInterrupt diff --git a/python/console/console_sci.py b/python/console/console_sci.py index 5b0d9d8d270b..2895e6c1db5c 100644 --- a/python/console/console_sci.py +++ b/python/console/console_sci.py @@ -17,6 +17,7 @@ ***************************************************************************/ Some portions of code were taken from https://code.google.com/p/pydee/ """ + from __future__ import annotations import code @@ -25,10 +26,7 @@ import sys import traceback from functools import partial -from typing import ( - Optional, - TYPE_CHECKING -) +from typing import Optional, TYPE_CHECKING from pathlib import Path from tempfile import NamedTemporaryFile @@ -42,13 +40,10 @@ QgsProcessingUtils, QgsSettingsTree, ) -from qgis.gui import ( - QgsCodeEditorPython, - QgsCodeEditor, - QgsCodeInterpreter -) +from qgis.gui import QgsCodeEditorPython, QgsCodeEditor, QgsCodeInterpreter from .process_wrapper import ProcessWrapper + if TYPE_CHECKING: from .console import PythonConsoleWidget @@ -79,7 +74,6 @@ "from qgis.PyQt.QtWidgets import *", "from qgis.PyQt.QtNetwork import *", "from qgis.PyQt.QtXml import *", - r""" def __parse_object(object=None): if not object: @@ -167,7 +161,7 @@ def _pyqgis(object=None): If the object is not part of the QGIS API but is a Qt object the Qt documentation is opened. ''' return _help(object, api=Qgis.DocumentationApi.PyQgis) -""" +""", ] @@ -225,7 +219,9 @@ def execCommandImpl(self, cmd, show_input=True): # Use a temporary file to communicate the result to the inner interpreter tmp = Path(NamedTemporaryFile(delete=False).name) tmp.write_text(res, encoding="utf-8") - self.runsource(f'{varname} = Path("{tmp}").read_text(encoding="utf-8").split("\\n")') + self.runsource( + f'{varname} = Path("{tmp}").read_text(encoding="utf-8").split("\\n")' + ) tmp.unlink() self.sub_process = None return 0 @@ -244,19 +240,25 @@ def execCommandImpl(self, cmd, show_input=True): res = 0 import webbrowser - version = 'master' if 'master' in Qgis.QGIS_VERSION.lower() else \ - re.findall(r'^\d.[0-9]*', Qgis.QGIS_VERSION)[0] + + version = ( + "master" + if "master" in Qgis.QGIS_VERSION.lower() + else re.findall(r"^\d.[0-9]*", Qgis.QGIS_VERSION)[0] + ) if cmd == "?": self.shell.console_widget.shell_output.insertHelp() - elif cmd == '_pyqgis': + elif cmd == "_pyqgis": self.shell.showApi(Qgis.DocumentationApi.PyQgis) - elif cmd == '_api': + elif cmd == "_api": self.shell.showApi(Qgis.DocumentationApi.CppQgis) - elif cmd == '_cookbook': + elif cmd == "_cookbook": webbrowser.open( "https://docs.qgis.org/{}/en/docs/pyqgis_developer_cookbook/".format( - 'testing' if version == 'master' else version)) + "testing" if version == "master" else version + ) + ) else: self.buffer.append(cmd) src = "\n".join(self.buffer) @@ -270,20 +272,21 @@ def writeCMD(self, txt): if sys.stdout: sys.stdout.fire_keyboard_interrupt = False if len(txt) > 0: - sys.stdout.write(f'{self.promptForState()} {txt}\n') + sys.stdout.write(f"{self.promptForState()} {txt}\n") - def runsource(self, source, filename='', symbol='single'): + def runsource(self, source, filename="", symbol="single"): if sys.stdout: sys.stdout.fire_keyboard_interrupt = False hook = sys.excepthook try: + def excepthook(etype, value, tb): self.write("".join(traceback.format_exception(etype, value, tb))) sys.excepthook = excepthook - return super(PythonInterpreter, self).runsource(source, filename, symbol) + return super().runsource(source, filename, symbol) finally: sys.excepthook = hook @@ -313,33 +316,45 @@ def __init__(self, console_widget: PythonConsoleWidget): # We set the ImmediatelyUpdateHistory flag here, as users can easily # crash QGIS by entering a Python command, and we don't want the # history leading to the crash lost... - super().__init__(console_widget, [], QgsCodeEditor.Mode.CommandInput, - flags=QgsCodeEditor.Flags(QgsCodeEditor.Flag.CodeFolding | QgsCodeEditor.Flag.ImmediatelyUpdateHistory)) + super().__init__( + console_widget, + [], + QgsCodeEditor.Mode.CommandInput, + flags=QgsCodeEditor.Flags( + QgsCodeEditor.Flag.CodeFolding + | QgsCodeEditor.Flag.ImmediatelyUpdateHistory + ), + ) self.console_widget: PythonConsoleWidget = console_widget self._interpreter = PythonInterpreter(shell=self) self.setInterpreter(self._interpreter) - self.opening = ['(', '{', '[', "'", '"'] - self.closing = [')', '}', ']', "'", '"'] + self.opening = ["(", "{", "[", "'", '"'] + self.closing = [")", "}", "]", "'", '"'] self.setHistoryFilePath( - os.path.join(QgsApplication.qgisSettingsDirPath(), "console_history.txt")) + os.path.join(QgsApplication.qgisSettingsDirPath(), "console_history.txt") + ) self.refreshSettingsShell() # Disable command key ctrl, shift = self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16 - self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl) - self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl) - self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl) - self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('Z') + ctrl) - self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('Y') + ctrl) - self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl + shift) + self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("L") + ctrl) + self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("T") + ctrl) + self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("D") + ctrl) + self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Z") + ctrl) + self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Y") + ctrl) + self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("L") + ctrl + shift) # New QShortcut = ctrl+space/ctrl+alt+space for Autocomplete - self.newShortcutCSS = QShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Modifier.SHIFT | Qt.Key.Key_Space), self) - self.newShortcutCAS = QShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Modifier.ALT | Qt.Key.Key_Space), self) + self.newShortcutCSS = QShortcut( + QKeySequence(Qt.Modifier.CTRL | Qt.Modifier.SHIFT | Qt.Key.Key_Space), self + ) + self.newShortcutCAS = QShortcut( + QKeySequence(Qt.Modifier.CTRL | Qt.Modifier.ALT | Qt.Key.Key_Space), self + ) self.newShortcutCSS.setContext(Qt.ShortcutContext.WidgetShortcut) self.newShortcutCAS.setContext(Qt.ShortcutContext.WidgetShortcut) self.newShortcutCAS.activated.connect(self.autoComplete) @@ -362,18 +377,25 @@ def refreshSettingsShell(self): self._setMinimumHeight() def on_session_history_cleared(self): - msgText = QCoreApplication.translate('PythonConsole', - 'Session history cleared successfully.') + msgText = QCoreApplication.translate( + "PythonConsole", "Session history cleared successfully." + ) self.console_widget.callWidgetMessageBar(msgText) def on_persistent_history_cleared(self): - msgText = QCoreApplication.translate('PythonConsole', - 'History cleared successfully.') + msgText = QCoreApplication.translate( + "PythonConsole", "History cleared successfully." + ) self.console_widget.callWidgetMessageBar(msgText) def keyPressEvent(self, e): - if e.modifiers() & (Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.MetaModifier) and e.key() == Qt.Key.Key_C and not self.hasSelectedText(): + if ( + e.modifiers() + & (Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.MetaModifier) + and e.key() == Qt.Key.Key_C + and not self.hasSelectedText() + ): if self._interpreter.sub_process: sys.stderr.write("Terminate child process\n") self._interpreter.sub_process.kill() @@ -462,43 +484,68 @@ def write(self, txt): if sys.stderr: sys.stderr.write(txt) - def runFile(self, filename, override_file_name: Optional[str] = None): + def runFile(self, filename, override_file_name: str | None = None): filename = filename.replace("\\", "/") dirname = os.path.dirname(filename) # Append the directory of the file to the path and set __file__ to the filename - self._interpreter.execCommandImpl("sys.path.append({0})".format( - QgsProcessingUtils.stringToPythonLiteral(dirname)), False) - self._interpreter.execCommandImpl("__file__ = {0}".format( - QgsProcessingUtils.stringToPythonLiteral(filename)), False) + self._interpreter.execCommandImpl( + "sys.path.append({})".format( + QgsProcessingUtils.stringToPythonLiteral(dirname) + ), + False, + ) + self._interpreter.execCommandImpl( + f"__file__ = {QgsProcessingUtils.stringToPythonLiteral(filename)}", + False, + ) try: # Run the file - self.runCommand("exec(compile(Path({0}).read_text(), {1}, 'exec'))".format( - QgsProcessingUtils.stringToPythonLiteral(filename), - QgsProcessingUtils.stringToPythonLiteral(override_file_name or filename)), - skipHistory=True) + self.runCommand( + "exec(compile(Path({}).read_text(), {}, 'exec'))".format( + QgsProcessingUtils.stringToPythonLiteral(filename), + QgsProcessingUtils.stringToPythonLiteral( + override_file_name or filename + ), + ), + skipHistory=True, + ) finally: # Remove the directory from the path and delete the __file__ variable self._interpreter.execCommandImpl("del __file__", False) - self._interpreter.execCommandImpl("sys.path.remove({0})".format( - QgsProcessingUtils.stringToPythonLiteral(dirname)), False) + self._interpreter.execCommandImpl( + "sys.path.remove({})".format( + QgsProcessingUtils.stringToPythonLiteral(dirname) + ), + False, + ) def showApiDocumentation(self, text, force_search=False): - self._interpreter.execCommandImpl(f'_help({repr(text)}, api=Qgis.DocumentationApi.PyQgis, force_search={force_search})', show_input=False) + self._interpreter.execCommandImpl( + f"_help({repr(text)}, api=Qgis.DocumentationApi.PyQgis, force_search={force_search})", + show_input=False, + ) def showApi(self, api: Qgis.DocumentationApi): - self._interpreter.execCommandImpl(f'_help(api=Qgis.DocumentationApi.{api.name})', show_input=False) + self._interpreter.execCommandImpl( + f"_help(api=Qgis.DocumentationApi.{api.name})", show_input=False + ) def populateContextMenu(self, menu): - word = self.selectedText() or self.wordAtPoint(self.mapFromGlobal(QCursor.pos())) + word = self.selectedText() or self.wordAtPoint( + self.mapFromGlobal(QCursor.pos()) + ) if word: context_help_action = QAction( QgsApplication.getThemeIcon("mActionHelpContents.svg"), QCoreApplication.translate("PythonConsole", "Context Help"), - menu) - context_help_action.triggered.connect(partial(self.showApiDocumentation, word, force_search=True)) - context_help_action.setShortcut('F1') + menu, + ) + context_help_action.triggered.connect( + partial(self.showApiDocumentation, word, force_search=True) + ) + context_help_action.setShortcut("F1") menu.addAction(context_help_action) diff --git a/python/console/console_settings.py b/python/console/console_settings.py index dafa29931eee..ef7c6d575d8c 100644 --- a/python/console/console_settings.py +++ b/python/console/console_settings.py @@ -22,7 +22,13 @@ from qgis.PyQt import uic from qgis.PyQt.QtCore import QCoreApplication, QUrl -from qgis.PyQt.QtWidgets import QWidget, QFileDialog, QMessageBox, QTableWidgetItem, QHBoxLayout +from qgis.PyQt.QtWidgets import ( + QWidget, + QFileDialog, + QMessageBox, + QTableWidgetItem, + QHBoxLayout, +) from qgis.PyQt.QtGui import QIcon, QDesktopServices from qgis.core import QgsSettings, QgsApplication, QgsSettingsTree, Qgis @@ -30,7 +36,9 @@ from .console_compile_apis import PrepareAPIDialog -Ui_SettingsDialogPythonConsole, _ = uic.loadUiType(Path(__file__).parent / 'console_settings.ui') +Ui_SettingsDialogPythonConsole, _ = uic.loadUiType( + Path(__file__).parent / "console_settings.ui" +) class ConsoleOptionsFactory(QgsOptionsWidgetFactory): @@ -39,10 +47,10 @@ def __init__(self): super(QgsOptionsWidgetFactory, self).__init__() def icon(self): - return QgsApplication.getThemeIcon('/console/mIconRunConsole.svg') + return QgsApplication.getThemeIcon("/console/mIconRunConsole.svg") def path(self): - return ['ide'] + return ["ide"] def createWidget(self, parent): return ConsoleOptionsPage(parent) @@ -51,34 +59,45 @@ def createWidget(self, parent): class ConsoleOptionsPage(QgsOptionsPageWidget): def __init__(self, parent): - super(ConsoleOptionsPage, self).__init__(parent) + super().__init__(parent) self.options_widget = ConsoleOptionsWidget(parent) layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setMargin(0) self.setLayout(layout) layout.addWidget(self.options_widget) - self.setObjectName('consoleOptions') + self.setObjectName("consoleOptions") def apply(self): self.options_widget.accept() def helpKey(self): - return 'plugins/python_console.html' + return "plugins/python_console.html" class ConsoleOptionsWidget(QWidget, Ui_SettingsDialogPythonConsole): def __init__(self, parent): super().__init__(parent) - self.setWindowTitle(QCoreApplication.translate( - "SettingsDialogPythonConsole", "Python Console Settings")) + self.setWindowTitle( + QCoreApplication.translate( + "SettingsDialogPythonConsole", "Python Console Settings" + ) + ) self.parent = parent self.setupUi(self) # Populate the documentation Browser combobox - self.contextHelpBrowser.addItem(QCoreApplication.translate("PythonConsole", "Embedded Webview (developer tools)"), Qgis.DocumentationBrowser.DeveloperToolsPanel) - self.contextHelpBrowser.addItem(QCoreApplication.translate("PythonConsole", "Default System Web Browser"), Qgis.DocumentationBrowser.SystemWebBrowser) + self.contextHelpBrowser.addItem( + QCoreApplication.translate( + "PythonConsole", "Embedded Webview (developer tools)" + ), + Qgis.DocumentationBrowser.DeveloperToolsPanel, + ) + self.contextHelpBrowser.addItem( + QCoreApplication.translate("PythonConsole", "Default System Web Browser"), + Qgis.DocumentationBrowser.SystemWebBrowser, + ) self.autopep8Level.setClearValue(1) self.maxLineLength.setClearValue(80) @@ -93,9 +112,13 @@ def __init__(self, parent): self.initialCheck() self.addAPIpath.setIcon(QIcon(":/images/themes/default/symbologyAdd.svg")) - self.addAPIpath.setToolTip(QCoreApplication.translate("PythonConsole", "Add API path")) + self.addAPIpath.setToolTip( + QCoreApplication.translate("PythonConsole", "Add API path") + ) self.removeAPIpath.setIcon(QIcon(":/images/themes/default/symbologyRemove.svg")) - self.removeAPIpath.setToolTip(QCoreApplication.translate("PythonConsole", "Remove API path")) + self.removeAPIpath.setToolTip( + QCoreApplication.translate("PythonConsole", "Remove API path") + ) self.preloadAPI.stateChanged.connect(self.initialCheck) self.addAPIpath.clicked.connect(self.loadAPIFile) @@ -121,7 +144,8 @@ def loadAPIFile(self): settings = QgsSettings() lastDirPath = settings.value("pythonConsole/lastDirAPIPath", "", type=str) fileAPI, selected_filter = QFileDialog.getOpenFileName( - self, "Open API File", lastDirPath, "API file (*.api)") + self, "Open API File", lastDirPath, "API file (*.api)" + ) if fileAPI: self.addAPI(fileAPI) settings.setValue("pythonConsole/lastDirAPIPath", fileAPI) @@ -129,17 +153,17 @@ def loadAPIFile(self): def _prepareAPI(self): if self.tableWidget.rowCount() != 0: pap_file, filter = QFileDialog().getSaveFileName( - self, - "", - '*.pap', - "Prepared APIs file (*.pap)") + self, "", "*.pap", "Prepared APIs file (*.pap)" + ) else: QMessageBox.information( - self, self.tr("Warning!"), - self.tr('You need to add some APIs file in order to compile')) + self, + self.tr("Warning!"), + self.tr("You need to add some APIs file in order to compile"), + ) return if pap_file: - api_lexer = 'QsciLexerPython' + api_lexer = "QsciLexerPython" api_files = [] count = self.tableWidget.rowCount() for i in range(0, count): @@ -152,18 +176,24 @@ def _prepareAPI(self): self.lineEdit.setText(pap_file) def accept(self): - if not self.preloadAPI.isChecked() and \ - not self.groupBoxPreparedAPI.isChecked(): + if not self.preloadAPI.isChecked() and not self.groupBoxPreparedAPI.isChecked(): if self.tableWidget.rowCount() == 0: QMessageBox.information( - self, self.tr("Warning!"), - self.tr('Please specify API file or check "Use preloaded API files"')) + self, + self.tr("Warning!"), + self.tr( + 'Please specify API file or check "Use preloaded API files"' + ), + ) return - if self.groupBoxPreparedAPI.isChecked() and \ - not self.lineEdit.text(): + if self.groupBoxPreparedAPI.isChecked() and not self.lineEdit.text(): QMessageBox.information( - self, self.tr("Warning!"), - QCoreApplication.translate('optionsDialog', 'The APIs file was not compiled, click on "Compile APIs…"') + self, + self.tr("Warning!"), + QCoreApplication.translate( + "optionsDialog", + 'The APIs file was not compiled, click on "Compile APIs…"', + ), ) return self.saveSettings() @@ -188,49 +218,83 @@ def removeAPI(self): def saveSettings(self): settings = QgsSettings() settings.setValue("pythonConsole/preloadAPI", self.preloadAPI.isChecked()) - settings.setValue("pythonConsole/autoSaveScript", self.autoSaveScript.isChecked()) + settings.setValue( + "pythonConsole/autoSaveScript", self.autoSaveScript.isChecked() + ) for i in range(0, self.tableWidget.rowCount()): text = self.tableWidget.item(i, 1).text() self.listPath.append(text) settings.setValue("pythonConsole/userAPI", self.listPath) - settings.setValue("pythonConsole/autoCompThreshold", self.autoCompThreshold.value()) - settings.setValue("pythonConsole/autoCompleteEnabled", self.groupBoxAutoCompletion.isChecked()) + settings.setValue( + "pythonConsole/autoCompThreshold", self.autoCompThreshold.value() + ) + settings.setValue( + "pythonConsole/autoCompleteEnabled", self.groupBoxAutoCompletion.isChecked() + ) - settings.setValue("pythonConsole/usePreparedAPIFile", self.groupBoxPreparedAPI.isChecked()) + settings.setValue( + "pythonConsole/usePreparedAPIFile", self.groupBoxPreparedAPI.isChecked() + ) settings.setValue("pythonConsole/preparedAPIFile", self.lineEdit.text()) if self.autoCompFromAPI.isChecked(): - settings.setValue("pythonConsole/autoCompleteSource", 'fromAPI') + settings.setValue("pythonConsole/autoCompleteSource", "fromAPI") elif self.autoCompFromDoc.isChecked(): - settings.setValue("pythonConsole/autoCompleteSource", 'fromDoc') + settings.setValue("pythonConsole/autoCompleteSource", "fromDoc") elif self.autoCompFromDocAPI.isChecked(): - settings.setValue("pythonConsole/autoCompleteSource", 'fromDocAPI') + settings.setValue("pythonConsole/autoCompleteSource", "fromDocAPI") - settings.setValue("pythonConsole/enableObjectInsp", self.enableObjectInspector.isChecked()) - settings.setValue("pythonConsole/autoCloseBracket", self.autoCloseBracket.isChecked()) + settings.setValue( + "pythonConsole/enableObjectInsp", self.enableObjectInspector.isChecked() + ) + settings.setValue( + "pythonConsole/autoCloseBracket", self.autoCloseBracket.isChecked() + ) settings.setValue("pythonConsole/autoSurround", self.autoSurround.isChecked()) - settings.setValue("pythonConsole/autoInsertImport", self.autoInsertImport.isChecked()) + settings.setValue( + "pythonConsole/autoInsertImport", self.autoInsertImport.isChecked() + ) settings.setValue("pythonConsole/formatOnSave", self.formatOnSave.isChecked()) codeEditorTreeNode = QgsSettingsTree.node("gui").childNode("code-editor") pythonSettingsTreeNode = codeEditorTreeNode.childNode("python") - pythonSettingsTreeNode.childSetting("sort-imports").setValue(self.sortImports.isChecked()) - pythonSettingsTreeNode.childSetting("formatter").setValue(self.formatter.currentText()) - pythonSettingsTreeNode.childSetting("autopep8-level").setValue(self.autopep8Level.value()) - pythonSettingsTreeNode.childSetting("black-normalize-quotes").setValue(self.blackNormalizeQuotes.isChecked()) - pythonSettingsTreeNode.childSetting("max-line-length").setValue(self.maxLineLength.value()) - pythonSettingsTreeNode.childSetting('external-editor').setValue(self.externalEditor.text()) - pythonSettingsTreeNode.childSetting('context-help-browser').setVariantValue(self.contextHelpBrowser.currentData().name) + pythonSettingsTreeNode.childSetting("sort-imports").setValue( + self.sortImports.isChecked() + ) + pythonSettingsTreeNode.childSetting("formatter").setValue( + self.formatter.currentText() + ) + pythonSettingsTreeNode.childSetting("autopep8-level").setValue( + self.autopep8Level.value() + ) + pythonSettingsTreeNode.childSetting("black-normalize-quotes").setValue( + self.blackNormalizeQuotes.isChecked() + ) + pythonSettingsTreeNode.childSetting("max-line-length").setValue( + self.maxLineLength.value() + ) + pythonSettingsTreeNode.childSetting("external-editor").setValue( + self.externalEditor.text() + ) + pythonSettingsTreeNode.childSetting("context-help-browser").setVariantValue( + self.contextHelpBrowser.currentData().name + ) - codeEditorTreeNode.childSetting('context-help-hover').setValue(self.contextHelpHover.isChecked()) + codeEditorTreeNode.childSetting("context-help-hover").setValue( + self.contextHelpHover.isChecked() + ) def restoreSettings(self): settings = QgsSettings() - self.preloadAPI.setChecked(settings.value("pythonConsole/preloadAPI", True, type=bool)) - self.lineEdit.setText(settings.value("pythonConsole/preparedAPIFile", "", type=str)) + self.preloadAPI.setChecked( + settings.value("pythonConsole/preloadAPI", True, type=bool) + ) + self.lineEdit.setText( + settings.value("pythonConsole/preparedAPIFile", "", type=str) + ) itemTable = settings.value("pythonConsole/userAPI", []) if itemTable: self.tableWidget.setRowCount(0) @@ -241,49 +305,81 @@ def restoreSettings(self): apiName = pathSplit[-1][0:-4] self.tableWidget.setItem(i, 0, QTableWidgetItem(apiName)) self.tableWidget.setItem(i, 1, QTableWidgetItem(itemTable[i])) - self.autoSaveScript.setChecked(settings.value("pythonConsole/autoSaveScript", False, type=bool)) + self.autoSaveScript.setChecked( + settings.value("pythonConsole/autoSaveScript", False, type=bool) + ) - self.autoCompThreshold.setValue(settings.value("pythonConsole/autoCompThreshold", 2, type=int)) - self.groupBoxAutoCompletion.setChecked(settings.value("pythonConsole/autoCompleteEnabled", True, type=bool)) + self.autoCompThreshold.setValue( + settings.value("pythonConsole/autoCompThreshold", 2, type=int) + ) + self.groupBoxAutoCompletion.setChecked( + settings.value("pythonConsole/autoCompleteEnabled", True, type=bool) + ) - self.enableObjectInspector.setChecked(settings.value("pythonConsole/enableObjectInsp", False, type=bool)) - self.autoCloseBracket.setChecked(settings.value("pythonConsole/autoCloseBracket", True, type=bool)) - self.autoSurround.setChecked(settings.value("pythonConsole/autoSurround", True, type=bool)) - self.autoInsertImport.setChecked(settings.value("pythonConsole/autoInsertImport", False, type=bool)) + self.enableObjectInspector.setChecked( + settings.value("pythonConsole/enableObjectInsp", False, type=bool) + ) + self.autoCloseBracket.setChecked( + settings.value("pythonConsole/autoCloseBracket", True, type=bool) + ) + self.autoSurround.setChecked( + settings.value("pythonConsole/autoSurround", True, type=bool) + ) + self.autoInsertImport.setChecked( + settings.value("pythonConsole/autoInsertImport", False, type=bool) + ) codeEditorTreeNode = QgsSettingsTree.node("gui").childNode("code-editor") pythonSettingsTreeNode = codeEditorTreeNode.childNode("python") - self.formatOnSave.setChecked(settings.value("pythonConsole/formatOnSave", False, type=bool)) - self.sortImports.setChecked(pythonSettingsTreeNode.childSetting("sort-imports").value()) - self.formatter.setCurrentText(pythonSettingsTreeNode.childSetting("formatter").value()) - self.autopep8Level.setValue(pythonSettingsTreeNode.childSetting("autopep8-level").value()) - self.blackNormalizeQuotes.setChecked(pythonSettingsTreeNode.childSetting("black-normalize-quotes").value()) - self.maxLineLength.setValue(pythonSettingsTreeNode.childSetting("max-line-length").value()) + self.formatOnSave.setChecked( + settings.value("pythonConsole/formatOnSave", False, type=bool) + ) + self.sortImports.setChecked( + pythonSettingsTreeNode.childSetting("sort-imports").value() + ) + self.formatter.setCurrentText( + pythonSettingsTreeNode.childSetting("formatter").value() + ) + self.autopep8Level.setValue( + pythonSettingsTreeNode.childSetting("autopep8-level").value() + ) + self.blackNormalizeQuotes.setChecked( + pythonSettingsTreeNode.childSetting("black-normalize-quotes").value() + ) + self.maxLineLength.setValue( + pythonSettingsTreeNode.childSetting("max-line-length").value() + ) - browserName = pythonSettingsTreeNode.childSetting('context-help-browser').valueAsVariant() + browserName = pythonSettingsTreeNode.childSetting( + "context-help-browser" + ).valueAsVariant() try: browser = Qgis.DocumentationBrowser[browserName] except KeyError: browser = Qgis.DocumentationBrowser.DeveloperToolsPanel - self.contextHelpBrowser.setCurrentIndex(self.contextHelpBrowser.findData(browser)) - self.contextHelpHover.setChecked(codeEditorTreeNode.childSetting('context-help-hover').value()) + self.contextHelpBrowser.setCurrentIndex( + self.contextHelpBrowser.findData(browser) + ) + self.contextHelpHover.setChecked( + codeEditorTreeNode.childSetting("context-help-hover").value() + ) - if settings.value("pythonConsole/autoCompleteSource") == 'fromDoc': + if settings.value("pythonConsole/autoCompleteSource") == "fromDoc": self.autoCompFromDoc.setChecked(True) - elif settings.value("pythonConsole/autoCompleteSource") == 'fromAPI': + elif settings.value("pythonConsole/autoCompleteSource") == "fromAPI": self.autoCompFromAPI.setChecked(True) - elif settings.value("pythonConsole/autoCompleteSource") == 'fromDocAPI': + elif settings.value("pythonConsole/autoCompleteSource") == "fromDocAPI": self.autoCompFromDocAPI.setChecked(True) self.externalEditor.setText( - pythonSettingsTreeNode.childSetting('external-editor').value() + pythonSettingsTreeNode.childSetting("external-editor").value() ) def onFormatterChanged(self): - """ Toggle formatter-specific options visibility when the formatter is changed """ - if self.formatter.currentText() == 'autopep8': + """Toggle formatter-specific options visibility when the formatter is changed""" + if self.formatter.currentText() == "autopep8": self.autopep8Level.setVisible(True) self.autopep8LevelLabel.setVisible(True) self.blackNormalizeQuotes.setVisible(False) diff --git a/python/console/process_wrapper.py b/python/console/process_wrapper.py index b59d8a6ead92..4d9acbd83606 100644 --- a/python/console/process_wrapper.py +++ b/python/console/process_wrapper.py @@ -15,7 +15,6 @@ *************************************************************************** """ - import locale import os import subprocess @@ -43,7 +42,7 @@ def __init__(self, command, interactive=True, parent=None): "stdout": subprocess.PIPE, "stdin": subprocess.PIPE, "stderr": subprocess.PIPE, - "shell": True + "shell": True, } # On Unix, we can use os.setsid @@ -64,12 +63,16 @@ def __init__(self, command, interactive=True, parent=None): # Read process stdout and push to out queue self.q_out = Queue() - self.t_out = Thread(daemon=True, target=self.enqueue_output, args=[self.p.stdout, self.q_out]) + self.t_out = Thread( + daemon=True, target=self.enqueue_output, args=[self.p.stdout, self.q_out] + ) self.t_out.start() # Read process stderr and push to err queue self.q_err = Queue() - self.t_err = Thread(daemon=True, target=self.enqueue_output, args=[self.p.stderr, self.q_err]) + self.t_err = Thread( + daemon=True, target=self.enqueue_output, args=[self.p.stderr, self.q_err] + ) self.t_err.start() # Polls process and output both queues content to sys.stdout and sys.stderr @@ -89,8 +92,10 @@ def enqueue_output(self, stream, queue): stream.close() def __repr__(self): - """ Helpful representation of the maanaged process """ - status = "Running" if self.returncode is None else f"Completed ({self.returncode})" + """Helpful representation of the maanaged process""" + status = ( + "Running" if self.returncode is None else f"Completed ({self.returncode})" + ) repr = f"ProcessWrapper object at {hex(id(self))}" repr += f"\n - Status: {status}" repr += f"\n - stdout: {self.stdout}" @@ -111,7 +116,7 @@ def decode(self, bytes): return text def read_content(self, queue, stream, is_stderr): - """ Write queue content to the standard stream and append it to the internal buffer """ + """Write queue content to the standard stream and append it to the internal buffer""" content = b"" while True: try: @@ -130,7 +135,7 @@ def read_content(self, queue, stream, is_stderr): return def dequeue_output(self): - """ Check process every 0.1s and forward its outputs to stdout and stderr """ + """Check process every 0.1s and forward its outputs to stdout and stderr""" # Poll process and forward its outputs to stdout and stderr while self.p.poll() is None: @@ -151,11 +156,11 @@ def dequeue_output(self): self.finished.emit(self.returncode) def wait(self, timeout=1): - """ Wait for the managed process to finish. If timeout=-1, waits indefinitely (and freeze the GUI) """ + """Wait for the managed process to finish. If timeout=-1, waits indefinitely (and freeze the GUI)""" self.p.wait(timeout) def write(self, data): - """ Send data to the managed process""" + """Send data to the managed process""" try: self.p.stdin.write((data + "\n").encode("utf8")) self.p.stdin.flush() @@ -165,7 +170,7 @@ def write(self, data): self.finished.emit(self.p.poll()) def kill(self): - """ Kill the managed process """ + """Kill the managed process""" # Process in run with shell=True, so calling self.p.kill() would only kill the shell # (i.e a text editor launched with !gedit would not close) so we need to iterate @@ -173,6 +178,7 @@ def kill(self): try: import psutil + if self.p.returncode is None: process = psutil.Process(self.p.pid) for child_process in process.children(recursive=True): @@ -187,7 +193,7 @@ def kill(self): self.p.kill() def __del__(self): - """ Ensure streams are closed when the process is destroyed """ + """Ensure streams are closed when the process is destroyed""" self.p.stdout.close() self.p.stderr.close() self.p.stdin.close() diff --git a/python/core/additions/edit.py b/python/core/additions/edit.py index 92756d1e8953..b82f268ea0a9 100644 --- a/python/core/additions/edit.py +++ b/python/core/additions/edit.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** edit.py @@ -17,8 +15,6 @@ *************************************************************************** """ -from builtins import object - class QgsEditError(Exception): @@ -29,7 +25,7 @@ def __str__(self): return repr(self.value) -class edit(object): +class edit: def __init__(self, layer): self.layer = layer diff --git a/python/core/additions/fromfunction.py b/python/core/additions/fromfunction.py index 92c3647449b5..7bbe1761a975 100644 --- a/python/core/additions/fromfunction.py +++ b/python/core/additions/fromfunction.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** fromfunction.py @@ -23,36 +21,38 @@ @staticmethod -def _fromFunction(description: str, - function: _typing.Callable, - *args, - on_finished: _typing.Optional[_typing.Callable] = None, - flags=QgsTask.Flag.AllFlags, - **kwargs) -> QgsTask: +def _fromFunction( + description: str, + function: _typing.Callable, + *args, + on_finished: _typing.Optional[_typing.Callable] = None, + flags=QgsTask.Flag.AllFlags, + **kwargs +) -> QgsTask: """ -Creates a new QgsTask task from a python function. + Creates a new QgsTask task from a python function. -Example -------- + Example + ------- -.. code-block:: python + .. code-block:: python - def calculate(task): - # pretend this is some complex maths and stuff we want - # to run in the background - return 5*6 + def calculate(task): + # pretend this is some complex maths and stuff we want + # to run in the background + return 5*6 - def calculation_finished(exception, value=None): - if not exception: - iface.messageBar().pushMessage( - 'the magic number is {}'.format(value)) - else: - iface.messageBar().pushMessage( - str(exception)) + def calculation_finished(exception, value=None): + if not exception: + iface.messageBar().pushMessage( + 'the magic number is {}'.format(value)) + else: + iface.messageBar().pushMessage( + str(exception)) - task = QgsTask.fromFunction('my task', calculate, - on_finished=calculation_finished) - QgsApplication.taskManager().addTask(task) + task = QgsTask.fromFunction('my task', calculate, + on_finished=calculation_finished) + QgsApplication.taskManager().addTask(task) """ diff --git a/python/core/additions/metaenum.py b/python/core/additions/metaenum.py index dac7b1b1c464..0d1fb6b39683 100644 --- a/python/core/additions/metaenum.py +++ b/python/core/additions/metaenum.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** metaenum.py @@ -61,7 +59,9 @@ def metaEnumFromType(enumClass, baseClass=None, raiseException=True): return metaEnumFromType(enumClass, baseClass, raiseException) except AttributeError: if raiseException: - raise ValueError("Enum type does not implement baseClass method. Provide the base class as argument.") + raise ValueError( + "Enum type does not implement baseClass method. Provide the base class as argument." + ) try: meta_object = baseClass.staticMetaObject @@ -71,7 +71,7 @@ def metaEnumFromType(enumClass, baseClass=None, raiseException=True): META_ENUM_BY_ENUM_CLASS[enumClass] = meta_enum except AttributeError: if raiseException: - raise TypeError("could not get the metaEnum for {}".format(enumClass.__name__)) + raise TypeError(f"could not get the metaEnum for {enumClass.__name__}") meta_enum = None return meta_enum diff --git a/python/core/additions/projectdirtyblocker.py b/python/core/additions/projectdirtyblocker.py index 7f06bd0a8412..95cec0432a79 100644 --- a/python/core/additions/projectdirtyblocker.py +++ b/python/core/additions/projectdirtyblocker.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** projectdirtyblocker.py @@ -17,11 +15,10 @@ *************************************************************************** """ - from qgis._core import QgsProjectDirtyBlocker -class ProjectDirtyBlocker(): +class ProjectDirtyBlocker: """ Context manager used to block project setDirty calls. diff --git a/python/core/additions/providermetadata.py b/python/core/additions/providermetadata.py index d188f6e26fde..b1a676c37386 100644 --- a/python/core/additions/providermetadata.py +++ b/python/core/additions/providermetadata.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** providermetadata.py @@ -21,12 +19,12 @@ class PyProviderMetadata(QgsProviderMetadata): - """ wrapper around QgsProviderMetadata to keep the existing Python code running which registers - data providers by passing a custom python createProvider() function to QgsProviderMetadata - constructor. The proper new way of doing it is to subclass QgsProviderMetadata and implement - its virtual functions. + """wrapper around QgsProviderMetadata to keep the existing Python code running which registers + data providers by passing a custom python createProvider() function to QgsProviderMetadata + constructor. The proper new way of doing it is to subclass QgsProviderMetadata and implement + its virtual functions. - TODO: QGIS 4 - remove this wrapper (only subclassing of QgsProviderMetadata should be used) + TODO: QGIS 4 - remove this wrapper (only subclassing of QgsProviderMetadata should be used) """ # this is a workaround to keep references to metadata classes diff --git a/python/core/additions/qgsfeature.py b/python/core/additions/qgsfeature.py index 4de498f766f8..0bd2a5a23695 100644 --- a/python/core/additions/qgsfeature.py +++ b/python/core/additions/qgsfeature.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** qgsfeature.py @@ -16,12 +14,18 @@ * * *************************************************************************** """ + from PyQt5.QtCore import QVariant def _mapping_feature(feature): geom = feature.geometry() - properties = {k: None if (v is None or (isinstance(v, QVariant) and v.isNull())) else v for k, v in feature.attributeMap().items()} - return {'type': 'Feature', - 'properties': properties, - 'geometry': geom.__geo_interface__} + properties = { + k: None if (v is None or (isinstance(v, QVariant) and v.isNull())) else v + for k, v in feature.attributeMap().items() + } + return { + "type": "Feature", + "properties": properties, + "geometry": geom.__geo_interface__, + } diff --git a/python/core/additions/qgsfunction.py b/python/core/additions/qgsfunction.py index e91e25a7fc0b..32a338dac291 100644 --- a/python/core/additions/qgsfunction.py +++ b/python/core/additions/qgsfunction.py @@ -15,13 +15,18 @@ *************************************************************************** """ - import inspect import string import traceback from qgis.PyQt.QtCore import QCoreApplication -from qgis._core import QgsExpressionFunction, QgsExpression, QgsMessageLog, QgsFeatureRequest, Qgis +from qgis._core import ( + QgsExpressionFunction, + QgsExpression, + QgsMessageLog, + QgsFeatureRequest, + Qgis, +) class QgsPyExpressionFunction(QgsExpressionFunction): @@ -143,7 +148,8 @@ def register_function( if not QgsExpression.unregisterFunction(name): msgtitle = QCoreApplication.translate("UserExpressions", "User expressions") msg = QCoreApplication.translate( - "UserExpressions", "The user expression {0} already exists and could not be unregistered." + "UserExpressions", + "The user expression {0} already exists and could not be unregistered.", ).format(name) QgsMessageLog.logMessage(msg + "\n", msgtitle, Qgis.MessageLevel.Warning) return None @@ -154,7 +160,14 @@ def register_function( # Legacy: if args was not 'auto', parameters were passed as a list params_as_list = params_as_list or args != "auto" f = QgsPyExpressionFunction( - function, name, group, helptext, usesgeometry, referenced_columns, handlesnull, params_as_list + function, + name, + group, + helptext, + usesgeometry, + referenced_columns, + handlesnull, + params_as_list, ) if register: diff --git a/python/core/additions/qgsgeometry.py b/python/core/additions/qgsgeometry.py index 6d2babfe1f03..63dbdeb5ccd7 100644 --- a/python/core/additions/qgsgeometry.py +++ b/python/core/additions/qgsgeometry.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** qgsgeometry.py diff --git a/python/core/additions/qgssettings.py b/python/core/additions/qgssettings.py index a8190a31c7c9..8140211df44c 100644 --- a/python/core/additions/qgssettings.py +++ b/python/core/additions/qgssettings.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** qgssettings.py @@ -22,7 +20,9 @@ import qgis # required to get base class of enums -def _qgssettings_enum_value(self, key, enumDefaultValue, section=QgsSettings.Section.NoSection): +def _qgssettings_enum_value( + self, key, enumDefaultValue, section=QgsSettings.Section.NoSection +): """ Return the setting value for a setting based on an enum. This forces the output to be a valid and existing entry of the enum. @@ -41,8 +41,11 @@ def _qgssettings_enum_value(self, key, enumDefaultValue, section=QgsSettings.Sec meta_enum = metaEnumFromValue(enumDefaultValue) if meta_enum is None or not meta_enum.isValid(): # this should not happen - raise ValueError("could not get the meta enum for given enum default value (type: {})" - .format(enumDefaultValue.__class__)) + raise ValueError( + "could not get the meta enum for given enum default value (type: {})".format( + enumDefaultValue.__class__ + ) + ) str_val = self.value(key, meta_enum.valueToKey(enumDefaultValue), str, section) # need a new meta enum as QgsSettings.value is making a copy and leads to seg fault (probably a PyQt issue) @@ -58,7 +61,9 @@ def _qgssettings_enum_value(self, key, enumDefaultValue, section=QgsSettings.Sec return enu_val -def _qgssettings_set_enum_value(self, key, enumValue, section=QgsSettings.Section.NoSection): +def _qgssettings_set_enum_value( + self, key, enumValue, section=QgsSettings.Section.NoSection +): """ Save the setting value for a setting based on an enum. This forces the output to be a valid and existing entry of the enum. @@ -76,12 +81,16 @@ def _qgssettings_set_enum_value(self, key, enumValue, section=QgsSettings.Sectio meta_enum = metaEnumFromValue(enumValue) if meta_enum is None or not meta_enum.isValid(): # this should not happen - raise ValueError("could not get the meta enum for given enum default value (type: {})".format(type(enumValue))) + raise ValueError( + f"could not get the meta enum for given enum default value (type: {type(enumValue)})" + ) self.setValue(key, meta_enum.valueToKey(enumValue), section) -def _qgssettings_flag_value(self, key, flagDefaultValue, section=QgsSettings.Section.NoSection): +def _qgssettings_flag_value( + self, key, flagDefaultValue, section=QgsSettings.Section.NoSection +): """ Return the setting value for a setting based on a flag. This forces the output to be a valid and existing entry of the enum. @@ -102,13 +111,19 @@ def _qgssettings_flag_value(self, key, flagDefaultValue, section=QgsSettings.Sec # dirty hack to get the parent class __import__(flagDefaultValue.__module__) baseClass = None - exec("baseClass={module}.{flag_class}".format(module=flagDefaultValue.__module__.replace('_', ''), - flag_class=flagDefaultValue.__class__.__name__)) + exec( + "baseClass={module}.{flag_class}".format( + module=flagDefaultValue.__module__.replace("_", ""), + flag_class=flagDefaultValue.__class__.__name__, + ) + ) meta_enum = metaEnumFromValue(flagDefaultValue, baseClass) if meta_enum is None or not meta_enum.isValid(): # this should not happen - raise ValueError("could not get the meta enum for given enum default value (type: {})".format(type(flagDefaultValue))) + raise ValueError( + f"could not get the meta enum for given enum default value (type: {type(flagDefaultValue)})" + ) str_val = self.value(key, meta_enum.valueToKeys(flagDefaultValue), str, section) # need a new meta enum as QgsSettings.value is making a copy and leads to seg fault (probably a PyQt issue) diff --git a/python/core/additions/qgssettingsentry.py b/python/core/additions/qgssettingsentry.py index ca55c90e4f66..d07797c0d55c 100644 --- a/python/core/additions/qgssettingsentry.py +++ b/python/core/additions/qgssettingsentry.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** qgssettingsentry.py @@ -18,7 +16,13 @@ """ from .metaenum import metaEnumFromValue -from qgis.core import QgsSettings, QgsSettingsTree, QgsSettingsEntryBase, QgsLogger, Qgis +from qgis.core import ( + QgsSettings, + QgsSettingsTree, + QgsSettingsEntryBase, + QgsLogger, + Qgis, +) import qgis # required to get base class of enums @@ -29,7 +33,14 @@ class PyQgsSettingsEntryEnumFlag since QGIS 3.20 """ - def __init__(self, key, pluginName, defaultValue, description=str(), options=Qgis.SettingsOptions()): + def __init__( + self, + key, + pluginName, + defaultValue, + description="", + options=Qgis.SettingsOptions(), + ): """ Constructor for PyQgsSettingsEntryEnumFlag. @@ -42,10 +53,12 @@ def __init__(self, key, pluginName, defaultValue, description=str(), options=Qgi # TODO QGIS 4: rename pluginName arg to parent and key to name self.options = options - defaultValueStr = str() + defaultValueStr = "" self.__metaEnum = metaEnumFromValue(defaultValue) if self.__metaEnum is None or not self.__metaEnum.isValid(): - QgsLogger.debug("Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{0}'".format(self.key())) + QgsLogger.debug( + f"Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{self.key()}'" + ) else: if self.__metaEnum.isFlag(): defaultValueStr = self.__metaEnum.valueToKeys(defaultValue) @@ -75,9 +88,13 @@ def value(self, dynamicKeyPart=None): :param dynamicKeyPart: argument specifies the dynamic part of the settings key. """ if self.__metaEnum.isFlag(): - return QgsSettings().flagValue(self.key(dynamicKeyPart), self.defaultValue()) + return QgsSettings().flagValue( + self.key(dynamicKeyPart), self.defaultValue() + ) else: - return QgsSettings().enumValue(self.key(dynamicKeyPart), self.defaultValue()) + return QgsSettings().enumValue( + self.key(dynamicKeyPart), self.defaultValue() + ) def valueWithDefaultOverride(self, defaultValueOverride, dynamicKeyPart=None): """ @@ -87,9 +104,13 @@ def valueWithDefaultOverride(self, defaultValueOverride, dynamicKeyPart=None): :param dynamicKeyPart: argument specifies the dynamic part of the settings key. """ if self.__metaEnum.isFlag(): - return QgsSettings().flagValue(self.key(dynamicKeyPart), defaultValueOverride) + return QgsSettings().flagValue( + self.key(dynamicKeyPart), defaultValueOverride + ) else: - return QgsSettings().enumValue(self.key(dynamicKeyPart), defaultValueOverride) + return QgsSettings().enumValue( + self.key(dynamicKeyPart), defaultValueOverride + ) def defaultValue(self): """ @@ -97,7 +118,9 @@ def defaultValue(self): """ if self.__metaEnum is None or not self.__metaEnum.isValid(): - QgsLogger.debug("Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{0}'".format(self.key())) + QgsLogger.debug( + f"Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{self.key()}'" + ) return -1 defaultValueString = self.defaultValueAsVariant() @@ -106,7 +129,9 @@ def defaultValue(self): else: (defaultValue, ok) = self.__metaEnum.keyToValue(defaultValueString) if not ok: - QgsLogger.debug("Invalid enum/flag key/s '{0}'.".format(self.defaultValueAsVariant())) + QgsLogger.debug( + f"Invalid enum/flag key/s '{self.defaultValueAsVariant()}'." + ) return -1 # cast to the enum class @@ -122,7 +147,9 @@ def setValue(self, value, dynamicKeyPart: (list, str) = None): """ if self.__metaEnum is None or not self.__metaEnum.isValid(): - QgsLogger.debug("Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{0}'".format(self.key())) + QgsLogger.debug( + f"Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{self.key()}'" + ) return False if self.options & Qgis.SettingsOption.SaveEnumFlagAsInt: @@ -133,7 +160,7 @@ def setValue(self, value, dynamicKeyPart: (list, str) = None): else: enum_flag_key = self.__metaEnum.valueToKey(value) if not enum_flag_key: - QgsLogger.debug("Invalid enum/flag value '{0}'.".format(value)) + QgsLogger.debug(f"Invalid enum/flag value '{value}'.") return False if type(dynamicKeyPart) is str: diff --git a/python/core/additions/qgstaskwrapper.py b/python/core/additions/qgstaskwrapper.py index 6c2b7560d812..a3a7d8c347bf 100644 --- a/python/core/additions/qgstaskwrapper.py +++ b/python/core/additions/qgstaskwrapper.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** qgstaskwrapper.py @@ -17,7 +15,6 @@ *************************************************************************** """ - from qgis._core import QgsTask @@ -47,7 +44,7 @@ def finished(self, result): return if not result and self.exception is None: - self.exception = Exception('Task canceled') + self.exception = Exception("Task canceled") try: if self.returned_values: diff --git a/python/core/additions/readwritecontextentercategory.py b/python/core/additions/readwritecontextentercategory.py index af9c509342cd..79a9c44e8bac 100644 --- a/python/core/additions/readwritecontextentercategory.py +++ b/python/core/additions/readwritecontextentercategory.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** readwritecontextentercategory.py @@ -18,7 +16,7 @@ """ -class ReadWriteContextEnterCategory(): +class ReadWriteContextEnterCategory: """ Push a category to the stack diff --git a/python/core/additions/runtimeprofiler.py b/python/core/additions/runtimeprofiler.py index 2216f5609e9d..95758a1ce899 100644 --- a/python/core/additions/runtimeprofiler.py +++ b/python/core/additions/runtimeprofiler.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** runtimeprofiler.py @@ -17,11 +15,10 @@ *************************************************************************** """ - from qgis._core import QgsScopedRuntimeProfile -class ScopedRuntimeProfileContextManager(): +class ScopedRuntimeProfileContextManager: """ Context manager used to profile blocks of code in the QgsApplication.profiler() registry. diff --git a/python/core/additions/validitycheck.py b/python/core/additions/validitycheck.py index 25fdd1586f09..37a32b9cf5e1 100644 --- a/python/core/additions/validitycheck.py +++ b/python/core/additions/validitycheck.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** validitycheck.py @@ -16,9 +14,8 @@ * * *************************************************************************** """ -from qgis._core import ( - QgsAbstractValidityCheck, - QgsApplication) + +from qgis._core import QgsAbstractValidityCheck, QgsApplication class CheckFactory: diff --git a/python/core/contextmanagers.py b/python/core/contextmanagers.py index 62e0c624659d..72be360097e6 100644 --- a/python/core/contextmanagers.py +++ b/python/core/contextmanagers.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** contextmanagers.py @@ -17,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nathan Woodrow' -__date__ = 'May 2014' -__copyright__ = '(C) 2014, Nathan Woodrow' +__author__ = "Nathan Woodrow" +__date__ = "May 2014" +__copyright__ = "(C) 2014, Nathan Woodrow" import sys from contextlib import contextmanager diff --git a/python/custom_widgets/qgis_customwidgets.py b/python/custom_widgets/qgis_customwidgets.py index ade5d47bec89..90ca5579a479 100644 --- a/python/custom_widgets/qgis_customwidgets.py +++ b/python/custom_widgets/qgis_customwidgets.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** customwidgets.py @@ -50,8 +48,9 @@ def moduleInformation(): try: import qgis.gui + widget_list = dir(qgis.gui) - widget_list.remove('QgsScrollArea') + widget_list.remove("QgsScrollArea") return "qgis.gui", widget_list except ImportError: return "", [] diff --git a/python/gui/additions/qgssettingsenumflageditorwrapper.py b/python/gui/additions/qgssettingsenumflageditorwrapper.py index 245b0470a35f..528adb8192a2 100644 --- a/python/gui/additions/qgssettingsenumflageditorwrapper.py +++ b/python/gui/additions/qgssettingsenumflageditorwrapper.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** qgssettingsenumflageditorwrapper.py @@ -28,7 +26,9 @@ class PyQgsSettingsEnumEditorWidgetWrapper(QgsSettingsEditorWidgetWrapper): A settings editor widget wrapper for enum settings as PyQgsSettingsEntryEnumFlag """ - def __init__(self, parent=None, editor=None, setting=None, displayStrings: dict = None): + def __init__( + self, parent=None, editor=None, setting=None, displayStrings: dict = None + ): self.setting = setting self.editor = editor self.displayStrings = {} @@ -39,19 +39,23 @@ def __init__(self, parent=None, editor=None, setting=None, displayStrings: dict self.configureEditor(editor, setting) def id(self): - return 'py-enum' + return "py-enum" def createWrapper(self, parent=None): return PyQgsSettingsEnumEditorWidgetWrapper(parent) def setWidgetFromSetting(self): if self.setting: - return self.setWidgetFromVariant(self.setting.valueAsVariant(self.dynamicKeyPartList())) + return self.setWidgetFromVariant( + self.setting.valueAsVariant(self.dynamicKeyPartList()) + ) return False def setSettingFromWidget(self): if self.editor: - self.setting.setVariantValue(self.variantValueFromWidget(), self.dynamicKeyPartList()) + self.setting.setVariantValue( + self.variantValueFromWidget(), self.dynamicKeyPartList() + ) return True else: return False @@ -88,4 +92,7 @@ def configureEditorPrivate(self, editor: QComboBox, setting: QgsSettingsEntryBas def enableAutomaticUpdatePrivate(self): self.editor.currentIndexChanged.connect( - lambda: self.setting.setValue(self.editor.currentData(), self.dynamicKeyPartList())) + lambda: self.setting.setValue( + self.editor.currentData(), self.dynamicKeyPartList() + ) + ) diff --git a/python/plugins/MetaSearch/__init__.py b/python/plugins/MetaSearch/__init__.py index ae8a29158156..069a287012c2 100644 --- a/python/plugins/MetaSearch/__init__.py +++ b/python/plugins/MetaSearch/__init__.py @@ -26,4 +26,5 @@ def classFactory(iface): """invoke plugin""" from MetaSearch.plugin import MetaSearchPlugin + return MetaSearchPlugin(iface) diff --git a/python/plugins/MetaSearch/dialogs/apidialog.py b/python/plugins/MetaSearch/dialogs/apidialog.py index 03edfe8af3ff..a774f8af899a 100644 --- a/python/plugins/MetaSearch/dialogs/apidialog.py +++ b/python/plugins/MetaSearch/dialogs/apidialog.py @@ -24,17 +24,11 @@ import json -from qgis.PyQt.QtWidgets import ( - QDialog, - QVBoxLayout -) -from qgis.gui import ( - QgsCodeEditorJson, - QgsCodeEditorHTML -) +from qgis.PyQt.QtWidgets import QDialog, QVBoxLayout +from qgis.gui import QgsCodeEditorJson, QgsCodeEditorHTML from MetaSearch.util import get_ui_class, prettify_xml -BASE_CLASS = get_ui_class('apidialog.ui') +BASE_CLASS = get_ui_class("apidialog.ui") class APIRequestResponseDialog(QDialog, BASE_CLASS): @@ -46,7 +40,7 @@ def __init__(self, request, response, mime_type: str): self.setupUi(self) - if mime_type == 'json': + if mime_type == "json": self.txtbrAPIRequest = QgsCodeEditorJson() self.txtbrAPIResponse = QgsCodeEditorJson() self.txtbrAPIRequest.setText(json.dumps(request, indent=4)) diff --git a/python/plugins/MetaSearch/dialogs/maindialog.py b/python/plugins/MetaSearch/dialogs/maindialog.py index 96419750c4f3..36ece1f5c57b 100644 --- a/python/plugins/MetaSearch/dialogs/maindialog.py +++ b/python/plugins/MetaSearch/dialogs/maindialog.py @@ -31,15 +31,29 @@ from urllib.request import build_opener, install_opener, ProxyHandler from qgis.PyQt.QtCore import Qt -from qgis.PyQt.QtWidgets import (QDialog, QComboBox, - QDialogButtonBox, QMessageBox, - QTreeWidgetItem, QWidget) +from qgis.PyQt.QtWidgets import ( + QDialog, + QComboBox, + QDialogButtonBox, + QMessageBox, + QTreeWidgetItem, + QWidget, +) from qgis.PyQt.QtGui import QColor -from qgis.core import (Qgis, QgsApplication, QgsCoordinateReferenceSystem, - QgsCoordinateTransform, QgsGeometry, QgsPointXY, - QgsProviderRegistry, QgsSettings, QgsProject, - QgsRectangle, QgsSettingsTree) +from qgis.core import ( + Qgis, + QgsApplication, + QgsCoordinateReferenceSystem, + QgsCoordinateTransform, + QgsGeometry, + QgsPointXY, + QgsProviderRegistry, + QgsSettings, + QgsProject, + QgsRectangle, + QgsSettingsTree, +) from qgis.gui import QgsRubberBand, QgsGui from qgis.utils import OverrideCursor @@ -54,12 +68,19 @@ from MetaSearch.dialogs.recorddialog import RecordDialog from MetaSearch.dialogs.apidialog import APIRequestResponseDialog from MetaSearch.search_backend import get_catalog_service -from MetaSearch.util import (clean_ows_url, get_connections_from_file, - get_ui_class, get_help_url, - normalize_text, open_url, render_template, - serialize_string, StaticContext) +from MetaSearch.util import ( + clean_ows_url, + get_connections_from_file, + get_ui_class, + get_help_url, + normalize_text, + open_url, + render_template, + serialize_string, + StaticContext, +) -BASE_CLASS = get_ui_class('maindialog.ui') +BASE_CLASS = get_ui_class("maindialog.ui") class MetaSearchDialog(QDialog, BASE_CLASS): @@ -82,9 +103,9 @@ def __init__(self, iface): self.context = StaticContext() self.leKeywords.setShowSearchIcon(True) - self.leKeywords.setPlaceholderText(self.tr('Search keywords')) + self.leKeywords.setPlaceholderText(self.tr("Search keywords")) - self.setWindowTitle(self.tr('MetaSearch')) + self.setWindowTitle(self.tr("MetaSearch")) self.rubber_band = QgsRubberBand(self.map, Qgis.GeometryType.Polygon) self.rubber_band.setColor(QColor(255, 0, 0, 75)) @@ -93,10 +114,11 @@ def __init__(self, iface): # form inputs self.startfrom = 1 self.constraints = [] - self.maxrecords = int(self.settings.value('/MetaSearch/returnRecords', 10)) - self.timeout = int(self.settings.value('/MetaSearch/timeout', 10)) + self.maxrecords = int(self.settings.value("/MetaSearch/returnRecords", 10)) + self.timeout = int(self.settings.value("/MetaSearch/timeout", 10)) self.disable_ssl_verification = self.settings.value( - '/MetaSearch/disableSSL', False, bool) + "/MetaSearch/disableSSL", False, bool + ) # Services tab self.cmbConnectionsServices.activated.connect(self.save_connection) @@ -119,7 +141,9 @@ def __init__(self, iface): self.btnSearch.clicked.connect(self.search) self.leKeywords.returnPressed.connect(self.search) # prevent dialog from closing upon pressing enter - self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setAutoDefault(False) + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setAutoDefault( + False + ) # launch help from button self.buttonBox.helpRequested.connect(self.help) self.btnCanvasBbox.setAutoDefault(False) @@ -144,16 +168,17 @@ def __init__(self, iface): def manageGui(self): """open window""" + def _on_timeout_change(value): - self.settings.setValue('/MetaSearch/timeout', value) + self.settings.setValue("/MetaSearch/timeout", value) self.timeout = value def _on_records_change(value): - self.settings.setValue('/MetaSearch/returnRecords', value) + self.settings.setValue("/MetaSearch/returnRecords", value) self.maxrecords = value def _on_ssl_state_change(state): - self.settings.setValue('/MetaSearch/disableSSL', bool(state)) + self.settings.setValue("/MetaSearch/disableSSL", bool(state)) self.disable_ssl_verification = bool(state) self.tabWidget.setCurrentIndex(0) @@ -168,11 +193,11 @@ def _on_ssl_state_change(state): self.disableSSLVerification.setChecked(self.disable_ssl_verification) self.disableSSLVerification.stateChanged.connect(_on_ssl_state_change) - key = '/MetaSearch/%s' % self.cmbConnectionsSearch.currentText() - self.catalog_url = self.settings.value('%s/url' % key) - self.catalog_username = self.settings.value('%s/username' % key) - self.catalog_password = self.settings.value('%s/password' % key) - self.catalog_type = self.settings.value('%s/catalog-type' % key) + key = "/MetaSearch/%s" % self.cmbConnectionsSearch.currentText() + self.catalog_url = self.settings.value("%s/url" % key) + self.catalog_username = self.settings.value("%s/username" % key) + self.catalog_password = self.settings.value("%s/password" % key) + self.catalog_type = self.settings.value("%s/catalog-type" % key) self.set_bbox_global() @@ -186,7 +211,7 @@ def _on_ssl_state_change(state): def populate_connection_list(self): """populate select box with connections""" - self.settings.beginGroup('/MetaSearch/') + self.settings.beginGroup("/MetaSearch/") self.cmbConnectionsServices.clear() self.cmbConnectionsServices.addItems(self.settings.childGroups()) self.cmbConnectionsSearch.clear() @@ -202,11 +227,13 @@ def populate_connection_list(self): # and start with connection tab open self.tabWidget.setCurrentIndex(1) # tell the user to add services - msg = self.tr('No services/connections defined. To get ' - 'started with MetaSearch, create a new ' - 'connection by clicking \'New\' or click ' - '\'Add default services\'.') - self.textMetadata.setHtml('

%s

' % msg) + msg = self.tr( + "No services/connections defined. To get " + "started with MetaSearch, create a new " + "connection by clicking 'New' or click " + "'Add default services'." + ) + self.textMetadata.setHtml("

%s

" % msg) else: # connections - enable various buttons state_disabled = True @@ -217,7 +244,7 @@ def populate_connection_list(self): def set_connection_list_position(self): """set the current index to the selected connection""" - to_select = self.settings.value('/MetaSearch/selected') + to_select = self.settings.value("/MetaSearch/selected") conn_count = self.cmbConnectionsServices.count() if conn_count == 0: @@ -256,21 +283,21 @@ def save_connection(self): caller = self.sender().objectName() - if caller == 'cmbConnectionsServices': # servers tab + if caller == "cmbConnectionsServices": # servers tab current_text = self.cmbConnectionsServices.currentText() - elif caller == 'cmbConnectionsSearch': # search tab + elif caller == "cmbConnectionsSearch": # search tab current_text = self.cmbConnectionsSearch.currentText() - self.settings.setValue('/MetaSearch/selected', current_text) - key = '/MetaSearch/%s' % current_text + self.settings.setValue("/MetaSearch/selected", current_text) + key = "/MetaSearch/%s" % current_text - if caller == 'cmbConnectionsSearch': # bind to service in search tab - self.catalog_url = self.settings.value('%s/url' % key) - self.catalog_username = self.settings.value('%s/username' % key) - self.catalog_password = self.settings.value('%s/password' % key) - self.catalog_type = self.settings.value('%s/catalog-type' % key) + if caller == "cmbConnectionsSearch": # bind to service in search tab + self.catalog_url = self.settings.value("%s/url" % key) + self.catalog_username = self.settings.value("%s/username" % key) + self.catalog_password = self.settings.value("%s/password" % key) + self.catalog_type = self.settings.value("%s/catalog-type" % key) - if caller == 'cmbConnectionsServices': # clear server metadata + if caller == "cmbConnectionsServices": # clear server metadata self.textMetadata.clear() self.btnRawAPIResponse.setEnabled(False) @@ -279,11 +306,11 @@ def connection_info(self): """show connection info""" current_text = self.cmbConnectionsServices.currentText() - key = '/MetaSearch/%s' % current_text - self.catalog_url = self.settings.value('%s/url' % key) - self.catalog_username = self.settings.value('%s/username' % key) - self.catalog_password = self.settings.value('%s/password' % key) - self.catalog_type = self.settings.value('%s/catalog-type' % key) + key = "/MetaSearch/%s" % current_text + self.catalog_url = self.settings.value("%s/url" % key) + self.catalog_username = self.settings.value("%s/username" % key) + self.catalog_password = self.settings.value("%s/password" % key) + self.catalog_type = self.settings.value("%s/catalog-type" % key) # connect to the server if not self._get_catalog(): @@ -291,9 +318,12 @@ def connection_info(self): if self.catalog: # display service metadata self.btnRawAPIResponse.setEnabled(True) - metadata = render_template('en', self.context, - self.catalog.conn, - self.catalog.service_info_template) + metadata = render_template( + "en", + self.context, + self.catalog.conn, + self.catalog.service_info_template, + ) style = QgsApplication.reportStyleSheet() self.textMetadata.clear() self.textMetadata.document().setDefaultStyleSheet(style) @@ -306,7 +336,7 @@ def add_connection(self): """add new service""" conn_new = NewConnectionDialog() - conn_new.setWindowTitle(self.tr('New Catalog Service')) + conn_new.setWindowTitle(self.tr("New Catalog Service")) if conn_new.exec() == QDialog.DialogCode.Accepted: # add to service list self.populate_connection_list() self.textMetadata.clear() @@ -316,19 +346,22 @@ def edit_connection(self): current_text = self.cmbConnectionsServices.currentText() - url = self.settings.value('/MetaSearch/%s/url' % current_text) + url = self.settings.value("/MetaSearch/%s/url" % current_text) conn_edit = NewConnectionDialog(current_text) - conn_edit.setWindowTitle(self.tr('Edit Catalog Service')) + conn_edit.setWindowTitle(self.tr("Edit Catalog Service")) conn_edit.leName.setText(current_text) conn_edit.leURL.setText(url) conn_edit.leUsername.setText( - self.settings.value('/MetaSearch/%s/username' % current_text)) + self.settings.value("/MetaSearch/%s/username" % current_text) + ) conn_edit.lePassword.setText( - self.settings.value('/MetaSearch/%s/password' % current_text)) + self.settings.value("/MetaSearch/%s/password" % current_text) + ) conn_edit.cmbCatalogType.setCurrentText( - self.settings.value('/MetaSearch/%s/catalog-type' % current_text)) + self.settings.value("/MetaSearch/%s/catalog-type" % current_text) + ) if conn_edit.exec() == QDialog.DialogCode.Accepted: # update service list self.populate_connection_list() @@ -338,13 +371,17 @@ def delete_connection(self): current_text = self.cmbConnectionsServices.currentText() - key = '/MetaSearch/%s' % current_text + key = "/MetaSearch/%s" % current_text - msg = self.tr('Remove service {0}?').format(current_text) + msg = self.tr("Remove service {0}?").format(current_text) result = QMessageBox.question( - self, self.tr('Delete Service'), msg, - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.No) + self, + self.tr("Delete Service"), + msg, + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + QMessageBox.StandardButton.No, + ) if result == QMessageBox.StandardButton.Yes: # remove service from list self.settings.remove(key) index_to_delete = self.cmbConnectionsServices.currentIndex() @@ -361,32 +398,39 @@ def load_connections(self): def add_default_connections(self): """add default connections""" - filename = os.path.join(self.context.ppath, - 'resources', 'connections-default.xml') + filename = os.path.join( + self.context.ppath, "resources", "connections-default.xml" + ) doc = get_connections_from_file(self, filename) if doc is None: return - self.settings.beginGroup('/MetaSearch/') + self.settings.beginGroup("/MetaSearch/") keys = self.settings.childGroups() self.settings.endGroup() - for server in doc.findall('csw'): - name = server.attrib.get('name') + for server in doc.findall("csw"): + name = server.attrib.get("name") # check for duplicates if name in keys: - msg = self.tr('{0} exists. Overwrite?').format(name) - res = QMessageBox.warning(self, - self.tr('Loading connections'), msg, - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) + msg = self.tr("{0} exists. Overwrite?").format(name) + res = QMessageBox.warning( + self, + self.tr("Loading connections"), + msg, + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + ) if res != QMessageBox.StandardButton.Yes: continue # no dups detected or overwrite is allowed - key = '/MetaSearch/%s' % name - self.settings.setValue('%s/url' % key, server.attrib.get('url')) - self.settings.setValue('%s/catalog-type' % key, server.attrib.get('catalog-type', 'OGC CSW 2.0.2')) + key = "/MetaSearch/%s" % name + self.settings.setValue("%s/url" % key, server.attrib.get("url")) + self.settings.setValue( + "%s/catalog-type" % key, + server.attrib.get("catalog-type", "OGC CSW 2.0.2"), + ) self.populate_connection_list() @@ -395,17 +439,17 @@ def add_default_connections(self): def set_ows_save_title_ask(self): """save ows save strategy as save ows title, ask if duplicate""" - self.settings.setValue('/MetaSearch/ows_save_strategy', 'title_ask') + self.settings.setValue("/MetaSearch/ows_save_strategy", "title_ask") def set_ows_save_title_no_ask(self): """save ows save strategy as save ows title, do NOT ask if duplicate""" - self.settings.setValue('/MetaSearch/ows_save_strategy', 'title_no_ask') + self.settings.setValue("/MetaSearch/ows_save_strategy", "title_no_ask") def set_ows_save_temp_name(self): """save ows save strategy as save with a temporary name""" - self.settings.setValue('/MetaSearch/ows_save_strategy', 'temp_name') + self.settings.setValue("/MetaSearch/ows_save_strategy", "temp_name") # Search tab @@ -417,14 +461,12 @@ def set_bbox_from_map(self): extent = self.map.extent() - if crsid != 'EPSG:4326': # reproject to EPSG:4326 + if crsid != "EPSG:4326": # reproject to EPSG:4326 src = QgsCoordinateReferenceSystem(crsid) dest = QgsCoordinateReferenceSystem("EPSG:4326") xform = QgsCoordinateTransform(src, dest, QgsProject.instance()) - minxy = xform.transform(QgsPointXY(extent.xMinimum(), - extent.yMinimum())) - maxxy = xform.transform(QgsPointXY(extent.xMaximum(), - extent.yMaximum())) + minxy = xform.transform(QgsPointXY(extent.xMinimum(), extent.yMinimum())) + maxxy = xform.transform(QgsPointXY(extent.xMaximum(), extent.yMaximum())) minx, miny = minxy maxx, maxy = maxxy else: # EPSG:4326 @@ -440,10 +482,10 @@ def set_bbox_from_map(self): def set_bbox_global(self): """set global bounding box""" - self.leNorth.setText('90') - self.leSouth.setText('-90') - self.leWest.setText('-180') - self.leEast.setText('180') + self.leNorth.setText("90") + self.leSouth.setText("-90") + self.leWest.setText("-180") + self.leEast.setText("180") def search(self): """execute search""" @@ -456,11 +498,11 @@ def search(self): # set current catalog current_text = self.cmbConnectionsSearch.currentText() - key = '/MetaSearch/%s' % current_text - self.catalog_url = self.settings.value('%s/url' % key) - self.catalog_username = self.settings.value('%s/username' % key) - self.catalog_password = self.settings.value('%s/password' % key) - self.catalog_type = self.settings.value('%s/catalog-type' % key) + key = "/MetaSearch/%s" % current_text + self.catalog_url = self.settings.value("%s/url" % key) + self.catalog_username = self.settings.value("%s/username" % key) + self.catalog_password = self.settings.value("%s/password" % key) + self.catalog_type = self.settings.value("%s/catalog-type" % key) # start position and number of records to return self.startfrom = 1 @@ -483,16 +525,18 @@ def search(self): # to find ('service', 'dataset', etc.) try: with OverrideCursor(Qt.CursorShape.WaitCursor): - self.catalog.query_records(bbox, keywords, self.maxrecords, - self.startfrom) + self.catalog.query_records( + bbox, keywords, self.maxrecords, self.startfrom + ) except Exception as err: - QMessageBox.warning(self, self.tr('Search error'), - self.tr('Search error: {0}').format(err)) + QMessageBox.warning( + self, self.tr("Search error"), self.tr("Search error: {0}").format(err) + ) return if self.catalog.matches == 0: - self.lblResults.setText(self.tr('0 results')) + self.lblResults.setText(self.tr("0 results")) return self.display_results() @@ -504,21 +548,24 @@ def display_results(self): position = self.catalog.returned + self.startfrom - 1 - msg = self.tr('Showing {0} - {1} of %n result(s)', 'number of results', - self.catalog.matches).format(self.startfrom, position) + msg = self.tr( + "Showing {0} - {1} of %n result(s)", + "number of results", + self.catalog.matches, + ).format(self.startfrom, position) self.lblResults.setText(msg) for rec in self.catalog.records(): item = QTreeWidgetItem(self.treeRecords) - if rec['type']: - item.setText(0, normalize_text(rec['type'])) + if rec["type"]: + item.setText(0, normalize_text(rec["type"])) else: - item.setText(0, 'unknown') - if rec['title']: - item.setText(1, normalize_text(rec['title'])) - if rec['identifier']: - set_item_data(item, 'identifier', rec['identifier']) + item.setText(0, "unknown") + if rec["title"]: + item.setText(1, normalize_text(rec["title"])) + if rec["identifier"]: + set_item_data(item, "identifier", rec["identifier"]) self.btnViewRawAPIResponse.setEnabled(True) @@ -555,36 +602,43 @@ def record_clicked(self): if not item: return - identifier = get_item_data(item, 'identifier') + identifier = get_item_data(item, "identifier") try: - record = next(item for item in self.catalog.records() - if item['identifier'] == identifier) + record = next( + item + for item in self.catalog.records() + if item["identifier"] == identifier + ) except KeyError: - QMessageBox.warning(self, - self.tr('Record parsing error'), - 'Unable to locate record identifier') + QMessageBox.warning( + self, + self.tr("Record parsing error"), + "Unable to locate record identifier", + ) return # if the record has a bbox, show a footprint on the map - if record['bbox'] is not None: - bx = record['bbox'] - rt = QgsRectangle(float(bx['minx']), float(bx['miny']), - float(bx['maxx']), float(bx['maxy'])) + if record["bbox"] is not None: + bx = record["bbox"] + rt = QgsRectangle( + float(bx["minx"]), + float(bx["miny"]), + float(bx["maxx"]), + float(bx["maxy"]), + ) geom = QgsGeometry.fromRect(rt) if geom is not None: src = QgsCoordinateReferenceSystem("EPSG:4326") dst = self.map.mapSettings().destinationCrs() if src.postgisSrid() != dst.postgisSrid(): - ctr = QgsCoordinateTransform( - src, dst, QgsProject.instance()) + ctr = QgsCoordinateTransform(src, dst, QgsProject.instance()) try: geom.transform(ctr) except Exception as err: QMessageBox.warning( - self, - self.tr('Coordinate Transformation Error'), - str(err)) + self, self.tr("Coordinate Transformation Error"), str(err) + ) self.rubber_band.setToGeometry(geom, None) # figure out if the data is interactive and can be operated on @@ -594,73 +648,78 @@ def find_services(self, record, item): """scan record for WMS/WMTS|WFS|WCS endpoints""" services = {} - for link in record['links']: + for link in record["links"]: link = self.catalog.parse_link(link) - if 'scheme' in link: - link_type = link['scheme'] - elif 'protocol' in link: - link_type = link['protocol'] + if "scheme" in link: + link_type = link["scheme"] + elif "protocol" in link: + link_type = link["protocol"] else: link_type = None if link_type is not None: link_type = link_type.upper() - wmswmst_link_types = list( - map(str.upper, link_types.WMSWMST_LINK_TYPES)) + wmswmst_link_types = list(map(str.upper, link_types.WMSWMST_LINK_TYPES)) wfs_link_types = list(map(str.upper, link_types.WFS_LINK_TYPES)) wcs_link_types = list(map(str.upper, link_types.WCS_LINK_TYPES)) ams_link_types = list(map(str.upper, link_types.AMS_LINK_TYPES)) afs_link_types = list(map(str.upper, link_types.AFS_LINK_TYPES)) - gis_file_link_types = list( - map(str.upper, link_types.GIS_FILE_LINK_TYPES)) + gis_file_link_types = list(map(str.upper, link_types.GIS_FILE_LINK_TYPES)) # if the link type exists, and it is one of the acceptable # interactive link types, then set - all_link_types = (wmswmst_link_types + wfs_link_types + - wcs_link_types + ams_link_types + - afs_link_types + gis_file_link_types) + all_link_types = ( + wmswmst_link_types + + wfs_link_types + + wcs_link_types + + ams_link_types + + afs_link_types + + gis_file_link_types + ) if all([link_type is not None, link_type in all_link_types]): if link_type in wmswmst_link_types: - services['wms'] = link['url'] + services["wms"] = link["url"] self.mActionAddWms.setEnabled(True) if link_type in wfs_link_types: - services['wfs'] = link['url'] + services["wfs"] = link["url"] self.mActionAddWfs.setEnabled(True) if link_type in wcs_link_types: - services['wcs'] = link['url'] + services["wcs"] = link["url"] self.mActionAddWcs.setEnabled(True) if link_type in ams_link_types: - services['ams'] = link['url'] + services["ams"] = link["url"] self.mActionAddAms.setEnabled(True) if link_type in afs_link_types: - services['afs'] = link['url'] + services["afs"] = link["url"] self.mActionAddAfs.setEnabled(True) if link_type in gis_file_link_types: - services['gis_file'] = link['url'] - services['title'] = record.get('title', '') + services["gis_file"] = link["url"] + services["title"] = record.get("title", "") self.mActionAddGisFile.setEnabled(True) self.tbAddData.setEnabled(True) - set_item_data(item, 'link', json.dumps(services)) + set_item_data(item, "link", json.dumps(services)) def navigate(self): """manage navigation / paging""" caller = self.sender().objectName() - if caller == 'btnFirst': + if caller == "btnFirst": self.startfrom = 1 - elif caller == 'btnLast': + elif caller == "btnLast": self.startfrom = self.catalog.matches - self.maxrecords + 1 - elif caller == 'btnNext': + elif caller == "btnNext": if self.startfrom > self.catalog.matches - self.maxrecords: - msg = self.tr('End of results. Go to start?') - res = QMessageBox.information(self, self.tr('Navigation'), - msg, - (QMessageBox.StandardButton.Ok | - QMessageBox.StandardButton.Cancel)) + msg = self.tr("End of results. Go to start?") + res = QMessageBox.information( + self, + self.tr("Navigation"), + msg, + (QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel), + ) if res == QMessageBox.StandardButton.Ok: self.startfrom = 1 else: @@ -669,14 +728,15 @@ def navigate(self): self.startfrom += self.maxrecords elif caller == "btnPrev": if self.startfrom == 1: - msg = self.tr('Start of results. Go to end?') - res = QMessageBox.information(self, self.tr('Navigation'), - msg, - (QMessageBox.StandardButton.Ok | - QMessageBox.StandardButton.Cancel)) + msg = self.tr("Start of results. Go to end?") + res = QMessageBox.information( + self, + self.tr("Navigation"), + msg, + (QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel), + ) if res == QMessageBox.StandardButton.Ok: - self.startfrom = (self.catalog.matches - - self.maxrecords + 1) + self.startfrom = self.catalog.matches - self.maxrecords + 1 else: return elif self.startfrom <= self.maxrecords: @@ -696,12 +756,13 @@ def navigate(self): try: with OverrideCursor(Qt.CursorShape.WaitCursor): - self.catalog.query_records(bbox, keywords, - limit=self.maxrecords, - offset=self.startfrom) + self.catalog.query_records( + bbox, keywords, limit=self.maxrecords, offset=self.startfrom + ) except Exception as err: - QMessageBox.warning(self, self.tr('Search error'), - self.tr('Search error: {0}').format(err)) + QMessageBox.warning( + self, self.tr("Search error"), self.tr("Search error: {0}").format(err) + ) return self.display_results() @@ -716,42 +777,56 @@ def add_to_ows(self): if not item: return - item_data = json.loads(get_item_data(item, 'link')) + item_data = json.loads(get_item_data(item, "link")) caller = self.sender().objectName() - if caller == 'mActionAddWms': - service_type = 'OGC:WMS/OGC:WMTS' - sname = 'WMS' - dyn_param = ['wms'] - provider_name = 'wms' - setting_node = QgsSettingsTree.node('connections').childNode('ows').childNode('connections') - data_url = item_data['wms'] - elif caller == 'mActionAddWfs': - service_type = 'OGC:WFS' - sname = 'WFS' - dyn_param = ['wfs'] - provider_name = 'WFS' - setting_node = QgsSettingsTree.node('connections').childNode('ows').childNode('connections') - data_url = item_data['wfs'] - elif caller == 'mActionAddWcs': - service_type = 'OGC:WCS' - sname = 'WCS' - dyn_param = ['wcs'] - provider_name = 'wcs' - setting_node = QgsSettingsTree.node('connections').childNode('ows').childNode('connections') - data_url = item_data['wcs'] - elif caller == 'mActionAddAfs': - service_type = 'ESRI:ArcGIS:FeatureServer' - sname = 'AFS' + if caller == "mActionAddWms": + service_type = "OGC:WMS/OGC:WMTS" + sname = "WMS" + dyn_param = ["wms"] + provider_name = "wms" + setting_node = ( + QgsSettingsTree.node("connections") + .childNode("ows") + .childNode("connections") + ) + data_url = item_data["wms"] + elif caller == "mActionAddWfs": + service_type = "OGC:WFS" + sname = "WFS" + dyn_param = ["wfs"] + provider_name = "WFS" + setting_node = ( + QgsSettingsTree.node("connections") + .childNode("ows") + .childNode("connections") + ) + data_url = item_data["wfs"] + elif caller == "mActionAddWcs": + service_type = "OGC:WCS" + sname = "WCS" + dyn_param = ["wcs"] + provider_name = "wcs" + setting_node = ( + QgsSettingsTree.node("connections") + .childNode("ows") + .childNode("connections") + ) + data_url = item_data["wcs"] + elif caller == "mActionAddAfs": + service_type = "ESRI:ArcGIS:FeatureServer" + sname = "AFS" dyn_param = [] - provider_name = 'arcgisfeatureserver' - setting_node = QgsSettingsTree.node('connections').childNode('arcgisfeatureserver') - data_url = (item_data['afs'].split('FeatureServer')[0] + 'FeatureServer') + provider_name = "arcgisfeatureserver" + setting_node = QgsSettingsTree.node("connections").childNode( + "arcgisfeatureserver" + ) + data_url = item_data["afs"].split("FeatureServer")[0] + "FeatureServer" keys = setting_node.items(dyn_param) - sname = '%s from MetaSearch' % sname + sname = "%s from MetaSearch" % sname for key in keys: if key.startswith(sname): conn_name_matches.append(key) @@ -760,10 +835,15 @@ def add_to_ows(self): # check for duplicates if sname in keys: # duplicate found - msg = self.tr('Connection {0} exists. Overwrite?').format(sname) + msg = self.tr("Connection {0} exists. Overwrite?").format(sname) res = QMessageBox.warning( - self, self.tr('Saving server'), msg, - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No | QMessageBox.StandardButton.Cancel) + self, + self.tr("Saving server"), + msg, + QMessageBox.StandardButton.Yes + | QMessageBox.StandardButton.No + | QMessageBox.StandardButton.Cancel, + ) if res == QMessageBox.StandardButton.No: # assign new name with serial sname = serialize_string(sname) elif res == QMessageBox.StandardButton.Cancel: @@ -771,37 +851,41 @@ def add_to_ows(self): # no dups detected or overwrite is allowed dyn_param.append(sname) - setting_node.childSetting('url').setValue(clean_ows_url(data_url), dyn_param) + setting_node.childSetting("url").setValue(clean_ows_url(data_url), dyn_param) # open provider window - ows_provider = QgsGui.sourceSelectProviderRegistry().\ - createSelectionWidget( - provider_name, self, Qt.WindowType.Widget, - QgsProviderRegistry.WidgetMode.Embedded) + ows_provider = QgsGui.sourceSelectProviderRegistry().createSelectionWidget( + provider_name, + self, + Qt.WindowType.Widget, + QgsProviderRegistry.WidgetMode.Embedded, + ) # connect dialog signals to iface slots - if service_type == 'OGC:WMS/OGC:WMTS': + if service_type == "OGC:WMS/OGC:WMTS": ows_provider.addRasterLayer.connect(self.iface.addRasterLayer) - conn_cmb = ows_provider.findChild(QWidget, 'cmbConnections') - connect = 'btnConnect_clicked' - elif service_type == 'OGC:WFS': + conn_cmb = ows_provider.findChild(QWidget, "cmbConnections") + connect = "btnConnect_clicked" + elif service_type == "OGC:WFS": + def addVectorLayer(path, name): - self.iface.addVectorLayer(path, name, 'WFS') + self.iface.addVectorLayer(path, name, "WFS") ows_provider.addVectorLayer.connect(addVectorLayer) - conn_cmb = ows_provider.findChild(QWidget, 'cmbConnections') - connect = 'connectToServer' - elif service_type == 'OGC:WCS': + conn_cmb = ows_provider.findChild(QWidget, "cmbConnections") + connect = "connectToServer" + elif service_type == "OGC:WCS": ows_provider.addRasterLayer.connect(self.iface.addRasterLayer) - conn_cmb = ows_provider.findChild(QWidget, 'mConnectionsComboBox') - connect = 'mConnectButton_clicked' - elif service_type == 'ESRI:ArcGIS:FeatureServer': + conn_cmb = ows_provider.findChild(QWidget, "mConnectionsComboBox") + connect = "mConnectButton_clicked" + elif service_type == "ESRI:ArcGIS:FeatureServer": + def addAfsLayer(path, name): - self.iface.addVectorLayer(path, name, 'afs') + self.iface.addVectorLayer(path, name, "afs") ows_provider.addVectorLayer.connect(addAfsLayer) conn_cmb = ows_provider.findChild(QComboBox) - connect = 'connectToServer' + connect = "connectToServer" ows_provider.setModal(False) ows_provider.show() @@ -811,9 +895,9 @@ def addAfsLayer(path, name): if index > -1: conn_cmb.setCurrentIndex(index) # only for wfs - if service_type == 'OGC:WFS': + if service_type == "OGC:WFS": ows_provider.cmbConnections_activated(index) - elif service_type == 'ESRI:ArcGIS:FeatureServer': + elif service_type == "ESRI:ArcGIS:FeatureServer": ows_provider.cmbConnections_activated(index) getattr(ows_provider, connect)() @@ -824,10 +908,10 @@ def add_gis_file(self): if not item: return - item_data = json.loads(get_item_data(item, 'link')) - gis_file = item_data['gis_file'] + item_data = json.loads(get_item_data(item, "link")) + gis_file = item_data["gis_file"] - title = item_data['title'] + title = item_data["title"] layer = self.iface.addVectorLayer(gis_file, title, "ogr") if not layer: @@ -843,7 +927,7 @@ def show_metadata(self): if not item: return - identifier = get_item_data(item, 'identifier') + identifier = get_item_data(item, "identifier") auth = None @@ -855,32 +939,39 @@ def show_metadata(self): try: with OverrideCursor(Qt.CursorShape.WaitCursor): - cat = get_catalog_service(self.catalog_url, # spellok - catalog_type=self.catalog_type, - timeout=self.timeout, - username=self.catalog_username or None, - password=self.catalog_password or None, - auth=auth) + cat = get_catalog_service( + self.catalog_url, # spellok + catalog_type=self.catalog_type, + timeout=self.timeout, + username=self.catalog_username or None, + password=self.catalog_password or None, + auth=auth, + ) record = cat.get_record(identifier) - if cat.type == 'OGC API - Records': - record['url'] = cat.conn.request - elif cat.type == 'OGC CSW 2.0.2': + if cat.type == "OGC API - Records": + record["url"] = cat.conn.request + elif cat.type == "OGC CSW 2.0.2": record.url = cat.conn.request except Exception as err: QMessageBox.warning( - self, self.tr('GetRecords error'), - self.tr('Error getting response: {0}').format(err)) + self, + self.tr("GetRecords error"), + self.tr("Error getting response: {0}").format(err), + ) return except KeyError as err: QMessageBox.warning( - self, self.tr('Record parsing error'), - self.tr('Unable to locate record identifier: {0}').format(err)) + self, + self.tr("Record parsing error"), + self.tr("Unable to locate record identifier: {0}").format(err), + ) return crd = RecordDialog() - metadata = render_template('en', self.context, - record, self.catalog.record_info_template) + metadata = render_template( + "en", self.context, record, self.catalog.record_info_template + ) style = QgsApplication.reportStyleSheet() crd.textMetadata.document().setDefaultStyleSheet(style) @@ -891,9 +982,7 @@ def show_api(self): """show API request / response""" crd = APIRequestResponseDialog( - self.catalog.request, - self.catalog.response, - self.catalog.format + self.catalog.request, self.catalog.response, self.catalog.format ) crd.exec() @@ -944,41 +1033,45 @@ def _get_catalog(self): with OverrideCursor(Qt.CursorShape.WaitCursor): try: self.catalog = get_catalog_service( - self.catalog_url, catalog_type=self.catalog_type, - timeout=self.timeout, username=self.catalog_username or None, - password=self.catalog_password or None, auth=auth) + self.catalog_url, + catalog_type=self.catalog_type, + timeout=self.timeout, + username=self.catalog_username or None, + password=self.catalog_password or None, + auth=auth, + ) return True except Exception as err: - msg = self.tr('Error connecting to service: {0}').format(err) + msg = self.tr("Error connecting to service: {0}").format(err) - QMessageBox.warning(self, self.tr('CSW Connection error'), msg) + QMessageBox.warning(self, self.tr("CSW Connection error"), msg) return False def install_proxy(self): """set proxy if one is set in QGIS network settings""" # initially support HTTP for now - if self.settings.value('/proxy/proxyEnabled') == 'true': - if self.settings.value('/proxy/proxyType') == 'HttpProxy': - ptype = 'http' + if self.settings.value("/proxy/proxyEnabled") == "true": + if self.settings.value("/proxy/proxyType") == "HttpProxy": + ptype = "http" else: return - user = self.settings.value('/proxy/proxyUser') - password = self.settings.value('/proxy/proxyPassword') - host = self.settings.value('/proxy/proxyHost') - port = self.settings.value('/proxy/proxyPort') + user = self.settings.value("/proxy/proxyUser") + password = self.settings.value("/proxy/proxyPassword") + host = self.settings.value("/proxy/proxyHost") + port = self.settings.value("/proxy/proxyPort") - proxy_up = '' - proxy_port = '' + proxy_up = "" + proxy_port = "" - if all([user != '', password != '']): - proxy_up = f'{user}:{password}@' + if all([user != "", password != ""]): + proxy_up = f"{user}:{password}@" - if port != '': - proxy_port = ':%s' % port + if port != "": + proxy_port = ":%s" % port - conn = f'{ptype}://{proxy_up}{host}{proxy_port}' + conn = f"{ptype}://{proxy_up}{host}{proxy_port}" install_opener(build_opener(ProxyHandler({ptype: conn}))) @@ -1005,9 +1098,9 @@ def _get_field_value(field): value = 0 - if field == 'identifier': + if field == "identifier": value = 0 - if field == 'link': + if field == "link": value = 1 return value diff --git a/python/plugins/MetaSearch/dialogs/manageconnectionsdialog.py b/python/plugins/MetaSearch/dialogs/manageconnectionsdialog.py index a34b8ba7a82f..22110dd51e26 100644 --- a/python/plugins/MetaSearch/dialogs/manageconnectionsdialog.py +++ b/python/plugins/MetaSearch/dialogs/manageconnectionsdialog.py @@ -29,12 +29,17 @@ import xml.etree.ElementTree as etree from qgis.core import QgsSettings -from qgis.PyQt.QtWidgets import QDialog, QDialogButtonBox, QFileDialog, QListWidgetItem, QMessageBox # noqa +from qgis.PyQt.QtWidgets import ( + QDialog, + QDialogButtonBox, + QFileDialog, + QListWidgetItem, + QMessageBox, +) # noqa -from MetaSearch.util import (get_connections_from_file, get_ui_class, - prettify_xml) +from MetaSearch.util import get_connections_from_file, get_ui_class, prettify_xml -BASE_CLASS = get_ui_class('manageconnectionsdialog.ui') +BASE_CLASS = get_ui_class("manageconnectionsdialog.ui") class ManageConnectionsDialog(QDialog, BASE_CLASS): @@ -55,11 +60,15 @@ def manage_gui(self): """manage interface""" if self.mode == 1: - self.label.setText(self.tr('Load from file')) - self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText(self.tr('Load')) + self.label.setText(self.tr("Load from file")) + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText( + self.tr("Load") + ) else: - self.label.setText(self.tr('Save to file')) - self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText(self.tr('Save')) + self.label.setText(self.tr("Save to file")) + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText( + self.tr("Save") + ) self.populate() self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(False) @@ -67,23 +76,25 @@ def manage_gui(self): def select_file(self): """select file ops""" - label = self.tr('eXtensible Markup Language (*.xml *.XML)') + label = self.tr("eXtensible Markup Language (*.xml *.XML)") if self.mode == 0: - slabel = self.tr('Save Connections') - self.filename, filter = QFileDialog.getSaveFileName(self, slabel, - '.', label) + slabel = self.tr("Save Connections") + self.filename, filter = QFileDialog.getSaveFileName( + self, slabel, ".", label + ) else: - slabel = self.tr('Load Connections') + slabel = self.tr("Load Connections") self.filename, selected_filter = QFileDialog.getOpenFileName( - self, slabel, '.', label) + self, slabel, ".", label + ) if not self.filename: return # ensure the user never omitted the extension from the file name - if not self.filename.lower().endswith('.xml'): - self.filename = '%s.xml' % self.filename + if not self.filename.lower().endswith(".xml"): + self.filename = "%s.xml" % self.filename self.leFileName.setText(self.filename) @@ -96,7 +107,7 @@ def populate(self): """populate connections list from settings""" if self.mode == 0: - self.settings.beginGroup('/MetaSearch/') + self.settings.beginGroup("/MetaSearch/") keys = self.settings.childGroups() for key in keys: item = QListWidgetItem(self.listConnections) @@ -111,43 +122,46 @@ def populate(self): self.listConnections.clear() return - for catalog in doc.findall('csw'): + for catalog in doc.findall("csw"): item = QListWidgetItem(self.listConnections) - item.setText(catalog.attrib.get('name')) + item.setText(catalog.attrib.get("name")) def save(self, connections): """save connections ops""" - doc = etree.Element('qgsCSWConnections') - doc.attrib['version'] = '1.0' + doc = etree.Element("qgsCSWConnections") + doc.attrib["version"] = "1.0" for conn in connections: - url = self.settings.value('/MetaSearch/%s/url' % conn) - type_ = self.settings.value('/MetaSearch/%s/catalog-type' % conn) + url = self.settings.value("/MetaSearch/%s/url" % conn) + type_ = self.settings.value("/MetaSearch/%s/catalog-type" % conn) if url is not None: - connection = etree.SubElement(doc, 'csw') - connection.attrib['name'] = conn - connection.attrib['type'] = type_ or 'OGC CSW 2.0.2' - connection.attrib['url'] = url + connection = etree.SubElement(doc, "csw") + connection.attrib["name"] = conn + connection.attrib["type"] = type_ or "OGC CSW 2.0.2" + connection.attrib["url"] = url # write to disk - with open(self.filename, 'w') as fileobj: + with open(self.filename, "w") as fileobj: fileobj.write(prettify_xml(etree.tostring(doc))) - QMessageBox.information(self, self.tr('Save Connections'), - self.tr('Saved to {0}.').format(self.filename)) + QMessageBox.information( + self, + self.tr("Save Connections"), + self.tr("Saved to {0}.").format(self.filename), + ) self.reject() def load(self, items): """load connections""" - self.settings.beginGroup('/MetaSearch/') + self.settings.beginGroup("/MetaSearch/") keys = self.settings.childGroups() self.settings.endGroup() exml = etree.parse(self.filename).getroot() - for catalog in exml.findall('csw'): - conn_name = catalog.attrib.get('name') + for catalog in exml.findall("csw"): + conn_name = catalog.attrib.get("name") # process only selected connections if conn_name not in items: @@ -155,19 +169,23 @@ def load(self, items): # check for duplicates if conn_name in keys: - label = self.tr('File {0} exists. Overwrite?').format( - conn_name) - res = QMessageBox.warning(self, self.tr('Loading Connections'), - label, - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) + label = self.tr("File {0} exists. Overwrite?").format(conn_name) + res = QMessageBox.warning( + self, + self.tr("Loading Connections"), + label, + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + ) if res != QMessageBox.StandardButton.Yes: continue # no dups detected or overwrite is allowed - url = '/MetaSearch/%s/url' % conn_name - type_ = '/MetaSearch/%s/catalog-type' % conn_name - self.settings.setValue(url, catalog.attrib.get('url')) - self.settings.setValue(type_, catalog.attrib.get('catalog-type', 'OGC CSW 2.0.2')) + url = "/MetaSearch/%s/url" % conn_name + type_ = "/MetaSearch/%s/catalog-type" % conn_name + self.settings.setValue(url, catalog.attrib.get("url")) + self.settings.setValue( + type_, catalog.attrib.get("catalog-type", "OGC CSW 2.0.2") + ) def accept(self): """accept connections""" diff --git a/python/plugins/MetaSearch/dialogs/newconnectiondialog.py b/python/plugins/MetaSearch/dialogs/newconnectiondialog.py index fee10ccaeee4..f4eb8e5d90cd 100644 --- a/python/plugins/MetaSearch/dialogs/newconnectiondialog.py +++ b/python/plugins/MetaSearch/dialogs/newconnectiondialog.py @@ -32,7 +32,7 @@ from MetaSearch.util import get_ui_class from MetaSearch.search_backend import CATALOG_TYPES -BASE_CLASS = get_ui_class('newconnectiondialog.ui') +BASE_CLASS = get_ui_class("newconnectiondialog.ui") class NewConnectionDialog(QDialog, BASE_CLASS): @@ -60,49 +60,53 @@ def accept(self): conn_password = self.lePassword.text().strip() conn_catalog_type = self.cmbCatalogType.currentText() - if any([conn_name == '', conn_url == '']): - QMessageBox.warning(self, self.tr('Save Connection'), - self.tr('Both Name and URL must be provided.')) + if any([conn_name == "", conn_url == ""]): + QMessageBox.warning( + self, + self.tr("Save Connection"), + self.tr("Both Name and URL must be provided."), + ) return - if '/' in conn_name: - QMessageBox.warning(self, self.tr('Save Connection'), - self.tr('Name cannot contain \'/\'.')) + if "/" in conn_name: + QMessageBox.warning( + self, self.tr("Save Connection"), self.tr("Name cannot contain '/'.") + ) return if conn_name is not None: - key = '/MetaSearch/%s' % conn_name - keyurl = '%s/url' % key - key_orig = '/MetaSearch/%s' % self.conn_name_orig + key = "/MetaSearch/%s" % conn_name + keyurl = "%s/url" % key + key_orig = "/MetaSearch/%s" % self.conn_name_orig # warn if entry was renamed to an existing connection - if all([self.conn_name_orig != conn_name, - self.settings.contains(keyurl)]): + if all([self.conn_name_orig != conn_name, self.settings.contains(keyurl)]): res = QMessageBox.warning( - self, self.tr('Save Connection'), - self.tr('Overwrite {0}?').format(conn_name), - QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel) + self, + self.tr("Save Connection"), + self.tr("Overwrite {0}?").format(conn_name), + QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel, + ) if res == QMessageBox.StandardButton.Cancel: return # on rename delete original entry first - if all([self.conn_name_orig is not None, - self.conn_name_orig != conn_name]): + if all([self.conn_name_orig is not None, self.conn_name_orig != conn_name]): self.settings.remove(key_orig) self.settings.setValue(keyurl, conn_url) - self.settings.setValue('/MetaSearch/selected', conn_name) + self.settings.setValue("/MetaSearch/selected", conn_name) - if conn_username != '': - self.settings.setValue('%s/username' % key, conn_username) + if conn_username != "": + self.settings.setValue("%s/username" % key, conn_username) else: - self.settings.remove('%s/username' % key) - if conn_password != '': - self.settings.setValue('%s/password' % key, conn_password) + self.settings.remove("%s/username" % key) + if conn_password != "": + self.settings.setValue("%s/password" % key, conn_password) else: - self.settings.remove('%s/password' % key) + self.settings.remove("%s/password" % key) - self.settings.setValue('%s/catalog-type' % key, conn_catalog_type) + self.settings.setValue("%s/catalog-type" % key, conn_catalog_type) QDialog.accept(self) diff --git a/python/plugins/MetaSearch/dialogs/recorddialog.py b/python/plugins/MetaSearch/dialogs/recorddialog.py index 9c9f9b9e00b5..89bfe9f00a7f 100644 --- a/python/plugins/MetaSearch/dialogs/recorddialog.py +++ b/python/plugins/MetaSearch/dialogs/recorddialog.py @@ -30,7 +30,7 @@ from MetaSearch.util import get_ui_class -BASE_CLASS = get_ui_class('recorddialog.ui') +BASE_CLASS = get_ui_class("recorddialog.ui") class RecordDialog(QDialog, BASE_CLASS): diff --git a/python/plugins/MetaSearch/link_types.py b/python/plugins/MetaSearch/link_types.py index 66dce8d983ec..2a0647dc2ce6 100644 --- a/python/plugins/MetaSearch/link_types.py +++ b/python/plugins/MetaSearch/link_types.py @@ -21,46 +21,37 @@ ############################################################################### WMSWMST_LINK_TYPES = [ - 'WMS', - 'WMTS', - 'OGC:WMS', - 'OGC:WMTS', - 'OGC:WMS-1.1.1-http-get-map', - 'OGC:WMS-1.1.1-http-get-capabilities', - 'OGC:WMS-1.3.0-http-get-map', - 'OGC:WMS-1.3.0-http-get-capabilities', - 'urn:x-esri:specification:ServiceType:wms:url', - 'urn:x-esri:specification:ServiceType:Gmd:URL.wms' + "WMS", + "WMTS", + "OGC:WMS", + "OGC:WMTS", + "OGC:WMS-1.1.1-http-get-map", + "OGC:WMS-1.1.1-http-get-capabilities", + "OGC:WMS-1.3.0-http-get-map", + "OGC:WMS-1.3.0-http-get-capabilities", + "urn:x-esri:specification:ServiceType:wms:url", + "urn:x-esri:specification:ServiceType:Gmd:URL.wms", ] WFS_LINK_TYPES = [ - 'WFS', - 'OGC:WFS', - 'OGC:WFS-1.0.0-http-get-capabilities', - 'OGC:WFS-1.1.0-http-get-capabilities', - 'urn:x-esri:specification:ServiceType:wfs:url', - 'urn:x-esri:specification:ServiceType:Gmd:URL.wfs' + "WFS", + "OGC:WFS", + "OGC:WFS-1.0.0-http-get-capabilities", + "OGC:WFS-1.1.0-http-get-capabilities", + "urn:x-esri:specification:ServiceType:wfs:url", + "urn:x-esri:specification:ServiceType:Gmd:URL.wfs", ] WCS_LINK_TYPES = [ - 'WCS', - 'OGC:WCS', - 'OGC:WCS-1.1.0-http-get-capabilities', - 'urn:x-esri:specification:ServiceType:wcs:url', - 'urn:x-esri:specification:ServiceType:Gmd:URL.wcs' + "WCS", + "OGC:WCS", + "OGC:WCS-1.1.0-http-get-capabilities", + "urn:x-esri:specification:ServiceType:wcs:url", + "urn:x-esri:specification:ServiceType:Gmd:URL.wcs", ] -AMS_LINK_TYPES = [ - 'ESRI:ArcGIS:MapServer', - 'Esri REST: Map Service', - 'ESRI REST' -] +AMS_LINK_TYPES = ["ESRI:ArcGIS:MapServer", "Esri REST: Map Service", "ESRI REST"] -AFS_LINK_TYPES = [ - 'ESRI:ArcGIS:FeatureServer', - 'Esri REST: Feature Service' -] +AFS_LINK_TYPES = ["ESRI:ArcGIS:FeatureServer", "Esri REST: Feature Service"] -GIS_FILE_LINK_TYPES = [ - 'FILE:GEO' -] +GIS_FILE_LINK_TYPES = ["FILE:GEO"] diff --git a/python/plugins/MetaSearch/pavement.py b/python/plugins/MetaSearch/pavement.py index 2fc7476ceafb..6cfeed6f83b6 100644 --- a/python/plugins/MetaSearch/pavement.py +++ b/python/plugins/MetaSearch/pavement.py @@ -26,35 +26,30 @@ import xmlrpc.client import zipfile -from paver.easy import (call_task, cmdopts, error, info, options, path, - sh, task, Bunch) +from paver.easy import call_task, cmdopts, error, info, options, path, sh, task, Bunch from owslib.csw import CatalogueServiceWeb # spellok -PLUGIN_NAME = 'MetaSearch' +PLUGIN_NAME = "MetaSearch" BASEDIR = os.path.abspath(os.path.dirname(__file__)) -USERDIR = os.path.expanduser('~') +USERDIR = os.path.expanduser("~") -with open('metadata.txt') as mf: +with open("metadata.txt") as mf: cp = ConfigParser() cp.readfp(mf) - VERSION = cp.get('general', 'version') + VERSION = cp.get("general", "version") options( base=Bunch( home=BASEDIR, plugin=path(BASEDIR), - ui=path(BASEDIR) / 'plugin' / PLUGIN_NAME / 'ui', - install=path('%s/.qgis3/python/plugins/MetaSearch' % USERDIR), - ext_libs=path('plugin/MetaSearch/ext-libs'), - tmp=path(path('%s/MetaSearch-dist' % USERDIR)), - version=VERSION + ui=path(BASEDIR) / "plugin" / PLUGIN_NAME / "ui", + install=path("%s/.qgis3/python/plugins/MetaSearch" % USERDIR), + ext_libs=path("plugin/MetaSearch/ext-libs"), + tmp=path(path("%s/MetaSearch-dist" % USERDIR)), + version=VERSION, ), - upload=Bunch( - host='plugins.qgis.org', - port=80, - endpoint='plugins/RPC2/' - ) + upload=Bunch(host="plugins.qgis.org", port=80, endpoint="plugins/RPC2/"), ) @@ -72,17 +67,17 @@ def clean(): if os.path.exists(options.base.ext_libs): shutil.rmtree(options.base.ext_libs) for ui_file in os.listdir(options.base.ui): - if ui_file.endswith('.py') and ui_file != '__init__.py': - os.remove(options.base.plugin / 'ui' / ui_file) - os.remove(path(options.base.home) / '%s.pro' % PLUGIN_NAME) - sh('git clean -dxf') + if ui_file.endswith(".py") and ui_file != "__init__.py": + os.remove(options.base.plugin / "ui" / ui_file) + os.remove(path(options.base.home) / "%s.pro" % PLUGIN_NAME) + sh("git clean -dxf") @task def install(): """install plugin into user QGIS environment""" - plugins_dir = path(USERDIR) / '.qgis3/python/plugins' + plugins_dir = path(USERDIR) / ".qgis3/python/plugins" if os.path.exists(options.base.install): if os.path.islink(options.base.install): @@ -91,8 +86,8 @@ def install(): shutil.rmtree(options.base.install) if not os.path.exists(plugins_dir): - raise OSError('The directory %s does not exist.' % plugins_dir) - if not hasattr(os, 'symlink'): + raise OSError("The directory %s does not exist." % plugins_dir) + if not hasattr(os, "symlink"): shutil.copytree(options.base.plugin, options.base.install) elif not os.path.exists(options.base.install): os.symlink(options.base.plugin, options.base.install) @@ -103,11 +98,11 @@ def package(): """create zip file of plugin""" skip_files = [ - 'AUTHORS.txt', - 'CMakeLists.txt', - 'requirements.txt', - 'requirements-dev.txt', - 'pavement.txt' + "AUTHORS.txt", + "CMakeLists.txt", + "requirements.txt", + "requirements-dev.txt", + "pavement.txt", ] package_file = get_package_filename() @@ -116,10 +111,10 @@ def package(): options.base.tmp.mkdir() if os.path.exists(package_file): os.unlink(package_file) - with zipfile.ZipFile(package_file, 'w', zipfile.ZIP_DEFLATED) as zipf: + with zipfile.ZipFile(package_file, "w", zipfile.ZIP_DEFLATED) as zipf: for root, dirs, files in os.walk(options.base.plugin): for file_add in files: - if file_add.endswith('.pyc') or file_add in skip_files: + if file_add.endswith(".pyc") or file_add in skip_files: continue filepath = os.path.join(root, file_add) relpath = os.path.join(PLUGIN_NAME, os.path.relpath(filepath)) @@ -128,81 +123,90 @@ def package(): @task -@cmdopts([ - ('user=', 'u', 'OSGeo userid'), -]) +@cmdopts( + [ + ("user=", "u", "OSGeo userid"), + ] +) def upload(): """upload package zipfile to server""" - user = options.get('user', False) + user = options.get("user", False) if not user: - raise ValueError('OSGeo userid required') + raise ValueError("OSGeo userid required") - password = getpass.getpass('Enter your password: ') - if password.strip() == '': - raise ValueError('password required') + password = getpass.getpass("Enter your password: ") + if password.strip() == "": + raise ValueError("password required") - call_task('package') + call_task("package") zipf = get_package_filename() - url = 'http://%s:%s@%s:%d/%s' % (user, password, options.upload.host, - options.upload.port, - options.upload.endpoint) + url = "http://%s:%s@%s:%d/%s" % ( + user, + password, + options.upload.host, + options.upload.port, + options.upload.endpoint, + ) - info('Uploading to http://{}/{}'.format(options.upload.host, options.upload.endpoint)) + info(f"Uploading to http://{options.upload.host}/{options.upload.endpoint}") server = xmlrpc.client.ServerProxy(url, verbose=False) try: with open(zipf) as zfile: - plugin_id, version_id = \ - server.plugin.upload(xmlrpc.client.Binary(zfile.read())) - info('Plugin ID: %s', plugin_id) - info('Version ID: %s', version_id) + plugin_id, version_id = server.plugin.upload( + xmlrpc.client.Binary(zfile.read()) + ) + info("Plugin ID: %s", plugin_id) + info("Version ID: %s", version_id) except xmlrpc.client.Fault as err: - error('ERROR: fault error') - error('Fault code: %d', err.faultCode) - error('Fault string: %s', err.faultString) + error("ERROR: fault error") + error("Fault code: %d", err.faultCode) + error("Fault string: %s", err.faultString) except xmlrpc.client.ProtocolError as err: - error('Error: Protocol error') + error("Error: Protocol error") error("%s : %s", err.errcode, err.errmsg) if err.errcode == 403: - error('Invalid name and password') + error("Invalid name and password") @task def test_default_csw_connections(): """test that the default CSW connections work""" - relpath = 'resources%sconnections-default.xml' % os.sep + relpath = "resources%sconnections-default.xml" % os.sep csw_connections_xml = options.base.plugin / relpath conns = etree.parse(csw_connections_xml) - for conn in conns.findall('csw'): + for conn in conns.findall("csw"): try: - csw = CatalogueServiceWeb(conn.attrib.get('url')) # spellok - info('Success: %s', csw.identification.title) + csw = CatalogueServiceWeb(conn.attrib.get("url")) # spellok + info("Success: %s", csw.identification.title) csw.getrecords2() except Exception as err: - raise ValueError('ERROR: %s', err) + raise ValueError("ERROR: %s", err) @task -@cmdopts([ - ('filename=', 'f', 'Path to file of CSW URLs'), -]) +@cmdopts( + [ + ("filename=", "f", "Path to file of CSW URLs"), + ] +) def generate_csw_connections_file(): """generate a CSW connections file from a flat file of CSW URLs""" - filename = options.get('filename', False) + filename = options.get("filename", False) if not filename: - raise ValueError('path to file of CSW URLs required') + raise ValueError("path to file of CSW URLs required") - conns = etree.Element('qgsCSWConnections') - conns.attrib['version'] = '1.0' + conns = etree.Element("qgsCSWConnections") + conns.attrib["version"] = "1.0" with open(filename) as connsfh: for line in connsfh: @@ -212,17 +216,17 @@ def generate_csw_connections_file(): try: csw = CatalogueServiceWeb(url) # spellok title = str(csw.identification.title) - etree.SubElement(conns, 'csw', name=title, url=url) + etree.SubElement(conns, "csw", name=title, url=url) except Exception as err: - error('ERROR on CSW %s: %s', url, err) + error("ERROR on CSW %s: %s", url, err) - with open('%s.xml' % filename, 'w') as connsxmlfh: - connsxmlfh.write(etree.tostring(conns, encoding='utf-8')) + with open("%s.xml" % filename, "w") as connsxmlfh: + connsxmlfh.write(etree.tostring(conns, encoding="utf-8")) def get_package_filename(): """return filepath of plugin zipfile""" - filename = f'{PLUGIN_NAME}-{options.base.version}.zip' - package_file = f'{options.base.tmp}/{filename}' + filename = f"{PLUGIN_NAME}-{options.base.version}.zip" + package_file = f"{options.base.tmp}/{filename}" return package_file diff --git a/python/plugins/MetaSearch/plugin.py b/python/plugins/MetaSearch/plugin.py index d131c4b7cc96..7e4c0c0db528 100644 --- a/python/plugins/MetaSearch/plugin.py +++ b/python/plugins/MetaSearch/plugin.py @@ -44,21 +44,22 @@ def __init__(self, iface): self.action_run = None self.action_help = None self.dialog = None - self.web_menu = '&MetaSearch' + self.web_menu = "&MetaSearch" def initGui(self): """startup""" # run - log_message('Initializing plugin', Qgis.MessageLevel.Info) + log_message("Initializing plugin", Qgis.MessageLevel.Info) - run_icon = QIcon('{}/{}'.format(self.context.ppath, 'images/MetaSearch.svg')) - self.action_run = QAction(run_icon, 'MetaSearch', - self.iface.mainWindow()) + run_icon = QIcon("{}/{}".format(self.context.ppath, "images/MetaSearch.svg")) + self.action_run = QAction(run_icon, "MetaSearch", self.iface.mainWindow()) self.action_run.setWhatsThis( - QCoreApplication.translate('MetaSearch', 'MetaSearch plugin')) - self.action_run.setStatusTip(QCoreApplication.translate( - 'MetaSearch', 'Search Metadata Catalogs')) + QCoreApplication.translate("MetaSearch", "MetaSearch plugin") + ) + self.action_run.setStatusTip( + QCoreApplication.translate("MetaSearch", "Search Metadata Catalogs") + ) self.action_run.triggered.connect(self.run) @@ -66,12 +67,14 @@ def initGui(self): self.iface.addPluginToWebMenu(self.web_menu, self.action_run) # help - help_icon = QgsApplication.getThemeIcon('/mActionHelpContents.svg') - self.action_help = QAction(help_icon, 'Help', self.iface.mainWindow()) + help_icon = QgsApplication.getThemeIcon("/mActionHelpContents.svg") + self.action_help = QAction(help_icon, "Help", self.iface.mainWindow()) self.action_help.setWhatsThis( - QCoreApplication.translate('MetaSearch', 'MetaSearch plugin help')) - self.action_help.setStatusTip(QCoreApplication.translate( - 'MetaSearch', 'Get Help on MetaSearch')) + QCoreApplication.translate("MetaSearch", "MetaSearch plugin help") + ) + self.action_help.setStatusTip( + QCoreApplication.translate("MetaSearch", "Get Help on MetaSearch") + ) self.action_help.triggered.connect(self.help) self.iface.addPluginToWebMenu(self.web_menu, self.action_help) @@ -82,7 +85,7 @@ def initGui(self): def unload(self): """teardown""" - log_message('Unloading plugin', Qgis.MessageLevel.Info) + log_message("Unloading plugin", Qgis.MessageLevel.Info) # remove the plugin menu item and icon self.iface.removePluginWebMenu(self.web_menu, self.action_run) @@ -92,7 +95,7 @@ def unload(self): def run(self): """open MetaSearch""" - log_message('Running plugin', Qgis.MessageLevel.Info) + log_message("Running plugin", Qgis.MessageLevel.Info) self.dialog.exec() diff --git a/python/plugins/MetaSearch/search_backend.py b/python/plugins/MetaSearch/search_backend.py index 1b461fec19bb..99ba387e8307 100644 --- a/python/plugins/MetaSearch/search_backend.py +++ b/python/plugins/MetaSearch/search_backend.py @@ -36,15 +36,12 @@ from qgis.core import Qgis -if owslib.__version__ < '0.25': +if owslib.__version__ < "0.25": OWSLIB_OAREC_SUPPORTED = False else: OWSLIB_OAREC_SUPPORTED = True -CATALOG_TYPES = [ - 'OGC CSW 2.0.2', - 'OGC API - Records' -] +CATALOG_TYPES = ["OGC CSW 2.0.2", "OGC API - Records"] class SearchBase: @@ -83,17 +80,19 @@ def __init__(self, url, timeout, username, password, auth): super().__init__(url, timeout, username, password, auth) self.type = CATALOG_TYPES[0] - self.format = 'xml' - self.service_info_template = 'csw_service_metadata.html' - self.record_info_template = 'record_metadata_dc.html' + self.format = "xml" + self.service_info_template = "csw_service_metadata.html" + self.record_info_template = "record_metadata_dc.html" self.constraints = [] - log_message(f'Connecting to CSW: {self.url}', Qgis.MessageLevel.Info) - self.conn = CatalogueServiceWeb(self.url, # spellok - timeout=self.timeout, - username=self.username, - password=self.password, - auth=self.auth) + log_message(f"Connecting to CSW: {self.url}", Qgis.MessageLevel.Info) + self.conn = CatalogueServiceWeb( + self.url, # spellok + timeout=self.timeout, + username=self.username, + password=self.password, + auth=self.auth, + ) self.request = self.conn.request self.response = self.conn.response @@ -105,29 +104,36 @@ def query_records(self, bbox=[], keywords=None, limit=10, offset=1): # only apply spatial filter if bbox is not global # even for a global bbox, if a spatial filter is applied, then # the CSW server will skip records without a bbox - if bbox and bbox != ['-180', '-90', '180', '90']: - log_message(f'Setting bbox filter ({bbox})', Qgis.MessageLevel.Info) + if bbox and bbox != ["-180", "-90", "180", "90"]: + log_message(f"Setting bbox filter ({bbox})", Qgis.MessageLevel.Info) minx, miny, maxx, maxy = bbox - self.constraints.append(BBox([miny, minx, maxy, maxx], - crs='urn:ogc:def:crs:EPSG::4326')) + self.constraints.append( + BBox([miny, minx, maxy, maxx], crs="urn:ogc:def:crs:EPSG::4326") + ) # keywords if keywords: # TODO: handle multiple word searches - log_message(f'Setting csw:AnyText filter {keywords}', Qgis.MessageLevel.Info) - self.constraints.append(PropertyIsLike('csw:AnyText', keywords)) + log_message( + f"Setting csw:AnyText filter {keywords}", Qgis.MessageLevel.Info + ) + self.constraints.append(PropertyIsLike("csw:AnyText", keywords)) if len(self.constraints) > 1: # exclusive search (a && b) self.constraints = [self.constraints] - log_message('Searching CSW: {self.url}', Qgis.MessageLevel.Info) - self.conn.getrecords2(constraints=self.constraints, maxrecords=limit, - startposition=offset, esn='full') + log_message("Searching CSW: {self.url}", Qgis.MessageLevel.Info) + self.conn.getrecords2( + constraints=self.constraints, + maxrecords=limit, + startposition=offset, + esn="full", + ) - self.matches = self.conn.results['matches'] - self.returned = self.conn.results['returned'] - log_message(f'Matches: {self.matches}', Qgis.MessageLevel.Info) - log_message(f'Returned: {self.returned}', Qgis.MessageLevel.Info) + self.matches = self.conn.results["matches"] + self.returned = self.conn.results["returned"] + log_message(f"Matches: {self.matches}", Qgis.MessageLevel.Info) + log_message(f"Returned: {self.returned}", Qgis.MessageLevel.Info) self.request = self.conn.request self.response = self.conn.response @@ -136,32 +142,27 @@ def records(self): recs = [] for record in self.conn.records: - rec = { - 'identifier': None, - 'type': None, - 'title': None, - 'bbox': None - } + rec = {"identifier": None, "type": None, "title": None, "bbox": None} if self.conn.records[record].identifier: - rec['identifier'] = self.conn.records[record].identifier + rec["identifier"] = self.conn.records[record].identifier if self.conn.records[record].type: - rec['type'] = self.conn.records[record].type + rec["type"] = self.conn.records[record].type if self.conn.records[record].title: - rec['title'] = self.conn.records[record].title + rec["title"] = self.conn.records[record].title if self.conn.records[record].bbox: - rec['bbox'] = bbox_list_to_dict( - self.conn.records[record].bbox) + rec["bbox"] = bbox_list_to_dict(self.conn.records[record].bbox) - rec['links'] = (self.conn.records[record].uris + - self.conn.records[record].references) + rec["links"] = ( + self.conn.records[record].uris + self.conn.records[record].references + ) recs.append(rec) return recs def get_record(self, identifier): - log_message(f'Searching CSW for record: {identifier}', Qgis.MessageLevel.Info) + log_message(f"Searching CSW for record: {identifier}", Qgis.MessageLevel.Info) self.conn.getrecordbyid([identifier]) return self.conn.records[identifier] @@ -178,27 +179,28 @@ def __init__(self, url, timeout, auth): super().__init__(url, timeout, auth) self.type = CATALOG_TYPES[1] - self.format = 'json' - self.service_info_template = 'oarec_service_metadata.html' - self.record_info_template = 'record_metadata_oarec.html' + self.format = "json" + self.service_info_template = "oarec_service_metadata.html" + self.record_info_template = "record_metadata_oarec.html" self.base_url = None self.record_collection = None - if '/collections/' in self.url: # catalog is a collection - log_message('OARec endpoint is a collection', Qgis.MessageLevel.Info) - self.base_url, self.record_collection = self.url.split('/collections/') # noqa - self.conn = Records( - self.base_url, timeout=self.timeout, auth=self.auth) + if "/collections/" in self.url: # catalog is a collection + log_message("OARec endpoint is a collection", Qgis.MessageLevel.Info) + self.base_url, self.record_collection = self.url.split( + "/collections/" + ) # noqa + self.conn = Records(self.base_url, timeout=self.timeout, auth=self.auth) c = self.conn.collection(self.record_collection) try: - self.conn.links = c['links'] - self.conn.title = c['title'] - self.conn.description = c['description'] + self.conn.links = c["links"] + self.conn.title = c["title"] + self.conn.description = c["description"] except KeyError: pass self.request = self.conn.request else: - log_message('OARec endpoint is not a collection', Qgis.MessageLevel.Info) + log_message("OARec endpoint is not a collection", Qgis.MessageLevel.Info) self.conn = Records(self.url, timeout=self.timeout, auth=self.auth) self.request = None @@ -210,47 +212,49 @@ def query_records(self, bbox=[], keywords=None, limit=10, offset=1): offset2 = offset - 1 params = { - 'collection_id': self.record_collection, - 'limit': limit, - 'offset': offset2 + "collection_id": self.record_collection, + "limit": limit, + "offset": offset2, } if keywords: - log_message(f'Setting keyword search {keywords}', Qgis.MessageLevel.Info) - params['q'] = keywords - if bbox and bbox != ['-180', '-90', '180', '90']: - log_message(f'Setting bbox search {bbox}', Qgis.MessageLevel.Info) - params['bbox'] = bbox + log_message(f"Setting keyword search {keywords}", Qgis.MessageLevel.Info) + params["q"] = keywords + if bbox and bbox != ["-180", "-90", "180", "90"]: + log_message(f"Setting bbox search {bbox}", Qgis.MessageLevel.Info) + params["bbox"] = bbox - log_message(f'Searching OARec: {self.url}', Qgis.MessageLevel.Info) + log_message(f"Searching OARec: {self.url}", Qgis.MessageLevel.Info) self.response = self.conn.collection_items(**params) - self.matches = self.response.get('numberMatched', 0) - self.returned = self.response.get('numberReturned', 0) + self.matches = self.response.get("numberMatched", 0) + self.returned = self.response.get("numberReturned", 0) self.request = self.conn.request - log_message(f'Matches: {self.matches}', Qgis.MessageLevel.Info) - log_message(f'Returned: {self.returned}', Qgis.MessageLevel.Info) + log_message(f"Matches: {self.matches}", Qgis.MessageLevel.Info) + log_message(f"Returned: {self.returned}", Qgis.MessageLevel.Info) def records(self): recs = [] - for rec in self.response['features']: + for rec in self.response["features"]: rec1 = { - 'identifier': rec['id'], - 'type': rec['properties']['type'], - 'bbox': None, - 'title': rec['properties']['title'], - 'links': rec.get('links', []) + "identifier": rec["id"], + "type": rec["properties"]["type"], + "bbox": None, + "title": rec["properties"]["title"], + "links": rec.get("links", []), } try: - if rec.get('geometry') is not None: - rec1['bbox'] = bbox_list_to_dict([ - rec['geometry']['coordinates'][0][0][0], - rec['geometry']['coordinates'][0][0][1], - rec['geometry']['coordinates'][0][2][0], - rec['geometry']['coordinates'][0][2][1] - ]) + if rec.get("geometry") is not None: + rec1["bbox"] = bbox_list_to_dict( + [ + rec["geometry"]["coordinates"][0][0][0], + rec["geometry"]["coordinates"][0][0][1], + rec["geometry"]["coordinates"][0][2][0], + rec["geometry"]["coordinates"][0][2][1], + ] + ) except KeyError: pass @@ -259,30 +263,30 @@ def records(self): return recs def get_record(self, identifier): - log_message(f'Searching OARec endpoint for item {identifier}', - Qgis.MessageLevel.Info) + log_message( + f"Searching OARec endpoint for item {identifier}", Qgis.MessageLevel.Info + ) return self.conn.collection_item(self.record_collection, identifier) def parse_link(self, link): link2 = {} - if 'href' in link: - link2['url'] = link['href'] - if 'type' in link: - link2['protocol'] = link['type'] - if 'title' in link: - link2['title'] = link['title'] - if 'id' in link: - link2['name'] = link['id'] + if "href" in link: + link2["url"] = link["href"] + if "type" in link: + link2["protocol"] = link["type"] + if "title" in link: + link2["title"] = link["title"] + if "id" in link: + link2["name"] = link["id"] return link2 -def get_catalog_service(url, catalog_type, timeout, username, password, - auth=None): +def get_catalog_service(url, catalog_type, timeout, username, password, auth=None): if catalog_type in [None, CATALOG_TYPES[0]]: - log_message('CSW endpoint detected', Qgis.MessageLevel.Info) + log_message("CSW endpoint detected", Qgis.MessageLevel.Info) return CSW202Search(url, timeout, username, password, auth) elif catalog_type == CATALOG_TYPES[1]: - log_message('OARec endpoint detected', Qgis.MessageLevel.Info) + log_message("OARec endpoint detected", Qgis.MessageLevel.Info) if not OWSLIB_OAREC_SUPPORTED: raise ValueError("OGC API - Records requires OWSLib 0.25 or above") return OARecSearch(url, timeout, auth) @@ -290,17 +294,12 @@ def get_catalog_service(url, catalog_type, timeout, username, password, def bbox_list_to_dict(bbox): if isinstance(bbox, list): - dict_ = { - 'minx': bbox[0], - 'maxx': bbox[2], - 'miny': bbox[1], - 'maxy': bbox[3] - } + dict_ = {"minx": bbox[0], "maxx": bbox[2], "miny": bbox[1], "maxy": bbox[3]} else: dict_ = { - 'minx': bbox.minx, - 'maxx': bbox.maxx, - 'miny': bbox.miny, - 'maxy': bbox.maxy + "minx": bbox.minx, + "maxx": bbox.maxx, + "miny": bbox.miny, + "maxy": bbox.maxy, } return dict_ diff --git a/python/plugins/MetaSearch/util.py b/python/plugins/MetaSearch/util.py index 7f6345baf06a..a939604f5809 100644 --- a/python/plugins/MetaSearch/util.py +++ b/python/plugins/MetaSearch/util.py @@ -53,18 +53,21 @@ def __init__(self): def get_ui_class(ui_file): """return class object of a uifile""" - ui_file_full = '{}{}ui{}{}'.format(os.path.dirname(os.path.abspath(__file__)), os.sep, os.sep, ui_file) + ui_file_full = ( + f"{os.path.dirname(os.path.abspath(__file__))}{os.sep}ui{os.sep}{ui_file}" + ) return loadUiType(ui_file_full)[0] def render_template(language, context, data, template): """Renders HTML display of raw API request/response/content""" - env = Environment(extensions=['jinja2.ext.i18n'], - loader=FileSystemLoader(context.ppath)) + env = Environment( + extensions=["jinja2.ext.i18n"], loader=FileSystemLoader(context.ppath) + ) env.install_gettext_callables(gettext, ngettext, newstyle=True) - template_file = 'resources/templates/%s' % template + template_file = "resources/templates/%s" % template template = env.get_template(template_file) return template.render(language=language, obj=data) @@ -75,18 +78,18 @@ def get_connections_from_file(parent, filename): error = 0 try: doc = etree.parse(filename).getroot() - if doc.tag != 'qgsCSWConnections': + if doc.tag != "qgsCSWConnections": error = 1 - msg = parent.tr('Invalid Catalog connections XML.') + msg = parent.tr("Invalid Catalog connections XML.") except etree.ParseError as err: error = 1 - msg = parent.tr('Cannot parse XML file: {0}').format(err) + msg = parent.tr("Cannot parse XML file: {0}").format(err) except OSError as err: error = 1 - msg = parent.tr('Cannot open file: {0}').format(err) + msg = parent.tr("Cannot open file: {0}").format(err) if error == 1: - QMessageBox.information(parent, parent.tr('Loading Connections'), msg) + QMessageBox.information(parent, parent.tr("Loading Connections"), msg) return return doc @@ -95,13 +98,13 @@ def prettify_xml(xml): """convenience function to prettify XML""" if isinstance(xml, bytes): - xml = xml.decode('utf-8') + xml = xml.decode("utf-8") - if xml.count('\n') > 20: # likely already pretty printed + if xml.count("\n") > 20: # likely already pretty printed return xml # check if it's a GET request - if xml.startswith('http'): + if xml.startswith("http"): return xml else: return parseString(xml).toprettyxml() @@ -110,17 +113,17 @@ def prettify_xml(xml): def get_help_url(): """return QGIS MetaSearch help documentation link""" - locale_name = QgsSettings().value('locale/userLocale')[0:2] - major, minor = Qgis.QGIS_VERSION.split('.')[:2] + locale_name = QgsSettings().value("locale/userLocale")[0:2] + major, minor = Qgis.QGIS_VERSION.split(".")[:2] - if minor == '99': # master - version = 'testing' + if minor == "99": # master + version = "testing" else: - version = '.'.join([major, minor]) + version = ".".join([major, minor]) - path = f'{version}/{locale_name}/docs/user_manual/plugins/core_plugins/plugins_metasearch.html' # noqa + path = f"{version}/{locale_name}/docs/user_manual/plugins/core_plugins/plugins_metasearch.html" # noqa - return '/'.join(['https://docs.qgis.org', path]) + return "/".join(["https://docs.qgis.org", path]) def open_url(url): @@ -132,7 +135,7 @@ def open_url(url): def normalize_text(text): """tidy up string""" - return text.replace('\n', '') + return text.replace("\n", "") def serialize_string(input_string): @@ -141,12 +144,12 @@ def serialize_string(input_string): s = input_string.strip().split() last_token = s[-1] - all_other_tokens_as_string = input_string.replace(last_token, '') + all_other_tokens_as_string = input_string.replace(last_token, "") if last_token.isdigit(): - value = f'{all_other_tokens_as_string}{int(last_token) + 1}' + value = f"{all_other_tokens_as_string}{int(last_token) + 1}" else: - value = '%s 1' % input_string + value = "%s 1" % input_string return value @@ -159,10 +162,10 @@ def clean_ows_url(url): if query_string: query_string = QUrlQuery(query_string) - query_string.removeQueryItem('service') - query_string.removeQueryItem('SERVICE') - query_string.removeQueryItem('request') - query_string.removeQueryItem('REQUEST') + query_string.removeQueryItem("service") + query_string.removeQueryItem("SERVICE") + query_string.removeQueryItem("request") + query_string.removeQueryItem("REQUEST") url.setQuery(query_string) return url.toString() @@ -171,4 +174,4 @@ def clean_ows_url(url): def log_message(message, level=Qgis.MessageLevel.Info): """helper function to emit logging messages""" - LOGGER.logMessage(message, 'MetaSearch', level) + LOGGER.logMessage(message, "MetaSearch", level) diff --git a/python/plugins/db_manager/db_manager.py b/python/plugins/db_manager/db_manager.py index 5562d023b8e0..cbae74596beb 100644 --- a/python/plugins/db_manager/db_manager.py +++ b/python/plugins/db_manager/db_manager.py @@ -23,16 +23,25 @@ import functools from qgis.PyQt.QtCore import Qt, QByteArray, QSize -from qgis.PyQt.QtWidgets import QAction, QMainWindow, QApplication, QMenu, QTabWidget, QGridLayout, QSpacerItem, QSizePolicy, QDockWidget, QStatusBar, QMenuBar, QToolBar, QTabBar +from qgis.PyQt.QtWidgets import ( + QAction, + QMainWindow, + QApplication, + QMenu, + QTabWidget, + QGridLayout, + QSpacerItem, + QSizePolicy, + QDockWidget, + QStatusBar, + QMenuBar, + QToolBar, + QTabBar, +) from qgis.PyQt.QtGui import QIcon, QKeySequence from qgis.gui import QgsMessageBar -from qgis.core import ( - Qgis, - QgsApplication, - QgsSettings, - QgsMapLayerType -) +from qgis.core import Qgis, QgsApplication, QgsSettings, QgsMapLayerType from qgis.utils import OverrideCursor from .info_viewer import InfoViewer @@ -56,8 +65,16 @@ def __init__(self, iface, parent=None): # restore the window state settings = QgsSettings() - self.restoreGeometry(settings.value("/DB_Manager/mainWindow/geometry", QByteArray(), type=QByteArray)) - self.restoreState(settings.value("/DB_Manager/mainWindow/windowState", QByteArray(), type=QByteArray)) + self.restoreGeometry( + settings.value( + "/DB_Manager/mainWindow/geometry", QByteArray(), type=QByteArray + ) + ) + self.restoreState( + settings.value( + "/DB_Manager/mainWindow/windowState", QByteArray(), type=QByteArray + ) + ) self.toolBar.setIconSize(self.iface.iconSize()) self.toolBarOrientation() @@ -102,7 +119,7 @@ def itemChanged(self, item): def reloadButtons(self): db = self.tree.currentDatabase() - if not hasattr(self, '_lastDb'): + if not hasattr(self, "_lastDb"): self._lastDb = db elif db == self._lastDb: @@ -131,8 +148,12 @@ def refreshTabs(self): # enable/disable tabs self.tabs.setTabEnabled(self.tabs.indexOf(self.table), table is not None) - self.tabs.setTabEnabled(self.tabs.indexOf(self.preview), table is not None and table.type in [table.VectorType, - table.RasterType] and table.geomColumn is not None) + self.tabs.setTabEnabled( + self.tabs.indexOf(self.preview), + table is not None + and table.type in [table.VectorType, table.RasterType] + and table.geomColumn is not None, + ) # show the info tab if the current tab is disabled if not self.tabs.isTabEnabled(index): self.tabs.setCurrentWidget(self.info) @@ -154,8 +175,11 @@ def refreshActionSlot(self): def importActionSlot(self): db = self.tree.currentDatabase() if db is None: - self.infoBar.pushMessage(self.tr("No database selected or you are not connected to it."), - Qgis.MessageLevel.Info, self.iface.messageTimeout()) + self.infoBar.pushMessage( + self.tr("No database selected or you are not connected to it."), + Qgis.MessageLevel.Info, + self.iface.messageTimeout(), + ) return outUri = db.uri() @@ -171,15 +195,20 @@ def importActionSlot(self): def exportActionSlot(self): table = self.tree.currentTable() if table is None: - self.infoBar.pushMessage(self.tr("Select the table you want export to file."), Qgis.MessageLevel.Info, - self.iface.messageTimeout()) + self.infoBar.pushMessage( + self.tr("Select the table you want export to file."), + Qgis.MessageLevel.Info, + self.iface.messageTimeout(), + ) return inLayer = table.toMapLayer() if inLayer.type() != QgsMapLayerType.VectorLayer: self.infoBar.pushMessage( self.tr("Select a vector or a tabular layer you want export."), - Qgis.MessageLevel.Warning, self.iface.messageTimeout()) + Qgis.MessageLevel.Warning, + self.iface.messageTimeout(), + ) return from .dlg_export_vector import DlgExportVector @@ -192,8 +221,11 @@ def exportActionSlot(self): def runSqlWindow(self): db = self.tree.currentDatabase() if db is None: - self.infoBar.pushMessage(self.tr("No database selected or you are not connected to it."), - Qgis.MessageLevel.Info, self.iface.messageTimeout()) + self.infoBar.pushMessage( + self.tr("No database selected or you are not connected to it."), + Qgis.MessageLevel.Info, + self.iface.messageTimeout(), + ) # force displaying of the message, it appears on the first tab (i.e. Info) self.tabs.setCurrentIndex(0) return @@ -206,10 +238,13 @@ def runSqlWindow(self): index = self.tabs.addTab(query, tabname) self.tabs.setTabIcon(index, db.connection().icon()) self.tabs.setCurrentIndex(index) - query.nameChanged.connect(functools.partial(self.update_query_tab_name, index, dbname)) + query.nameChanged.connect( + functools.partial(self.update_query_tab_name, index, dbname) + ) def runSqlLayerWindow(self, layer): from .dlg_sql_layer_window import DlgSqlLayerWindow + query = DlgSqlLayerWindow(self.iface, layer, self) lname = layer.name() tabname = self.tr("Layer ({0})").format(lname) @@ -220,18 +255,19 @@ def runSqlLayerWindow(self, layer): def update_query_tab_name(self, index, dbname, queryname): if not queryname: queryname = self.tr("Query") - tabname = "%s (%s)" % (queryname, dbname) + tabname = f"{queryname} ({dbname})" self.tabs.setTabText(index, tabname) def showSystemTables(self): self.tree.showSystemTables(self.actionShowSystemTables.isChecked()) def registerAction(self, action, menuName, callback=None): - """ register an action to the manager's main menu """ - if not hasattr(self, '_registeredDbActions'): + """register an action to the manager's main menu""" + if not hasattr(self, "_registeredDbActions"): self._registeredDbActions = {} if callback is not None: + def invoke_callback(x): return self.invokeCallback(callback) @@ -272,7 +308,9 @@ def invoke_callback(x): # get the placeholder's position to insert before it pos = 0 for pos in range(len(menuActions)): - if menuActions[pos].isSeparator() and menuActions[pos].objectName().endswith("_placeholder"): + if menuActions[pos].isSeparator() and menuActions[ + pos + ].objectName().endswith("_placeholder"): menuActions[pos].setVisible(True) break @@ -294,12 +332,12 @@ def invoke_callback(x): return True def invokeCallback(self, callback, *params): - """ Call a method passing the selected item in the database tree, - the sender (usually a QAction), the plugin mainWindow and - optionally additional parameters. + """Call a method passing the selected item in the database tree, + the sender (usually a QAction), the plugin mainWindow and + optionally additional parameters. - This method takes care to override and restore the cursor, - but also catches exceptions and displays the error dialog. + This method takes care to override and restore the cursor, + but also catches exceptions and displays the error dialog. """ with OverrideCursor(Qt.CursorShape.WaitCursor): try: @@ -309,7 +347,7 @@ def invokeCallback(self, callback, *params): DlgDbError.showError(e, self) def unregisterAction(self, action, menuName): - if not hasattr(self, '_registeredDbActions'): + if not hasattr(self, "_registeredDbActions"): return if menuName is None or menuName == "": @@ -340,7 +378,9 @@ def unregisterAction(self, action, menuName): # hide the placeholder if there're no other registered actions if len(self._registeredDbActions[menuName]) <= 0: for i in range(len(menuActions)): - if menuActions[i].isSeparator() and menuActions[i].objectName().endswith("_placeholder"): + if menuActions[i].isSeparator() and menuActions[ + i + ].objectName().endswith("_placeholder"): menuActions[i].setVisible(False) break @@ -350,7 +390,7 @@ def unregisterAction(self, action, menuName): return False def unregisterAllActions(self): - if not hasattr(self, '_registeredDbActions'): + if not hasattr(self, "_registeredDbActions"): return for menuName in self._registeredDbActions: @@ -400,14 +440,20 @@ def setupUi(self): self.tabs.tabCloseRequested.connect(self.close_tab) tabbar = self.tabs.tabBar() for i in range(3): - btn = tabbar.tabButton(i, QTabBar.ButtonPosition.RightSide) if tabbar.tabButton(i, QTabBar.ButtonPosition.RightSide) else tabbar.tabButton(i, QTabBar.ButtonPosition.LeftSide) + btn = ( + tabbar.tabButton(i, QTabBar.ButtonPosition.RightSide) + if tabbar.tabButton(i, QTabBar.ButtonPosition.RightSide) + else tabbar.tabButton(i, QTabBar.ButtonPosition.LeftSide) + ) btn.resize(0, 0) btn.hide() # Creates layout for message bar self.layout = QGridLayout(self.info) self.layout.setContentsMargins(0, 0, 0, 0) - spacerItem = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + spacerItem = QSpacerItem( + 20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding + ) self.layout.addItem(spacerItem, 1, 0, 1, 1) # init messageBar instance self.infoBar = QgsMessageBar(self.info) @@ -452,15 +498,18 @@ def setupUi(self): sep.setObjectName("DB_Manager_DbMenu_placeholder") sep.setVisible(False) - self.actionRefresh = QAction(QgsApplication.getThemeIcon("/mActionRefresh.svg"), self.tr("&Refresh"), - self.menuDb) + self.actionRefresh = QAction( + QgsApplication.getThemeIcon("/mActionRefresh.svg"), + self.tr("&Refresh"), + self.menuDb, + ) self.actionRefresh.triggered.connect(self.refreshActionSlot) self.actionRefresh.setShortcut(QKeySequence("F5")) self.menuDb.addAction(self.actionRefresh) - self.actionSqlWindow = QAction(GuiUtils.get_icon('mActionSQLWindow'), - self.tr("&SQL Window"), - self.menuDb) + self.actionSqlWindow = QAction( + GuiUtils.get_icon("mActionSQLWindow"), self.tr("&SQL Window"), self.menuDb + ) self.actionSqlWindow.triggered.connect(self.runSqlWindow) self.actionSqlWindow.setShortcut(QKeySequence("F2")) self.menuDb.addAction(self.actionSqlWindow) @@ -484,12 +533,16 @@ def setupUi(self): sep.setObjectName("DB_Manager_TableMenu_placeholder") sep.setVisible(False) - self.actionImport = self.menuTable.addAction(GuiUtils.get_icon("mActionDBImport"), - QApplication.translate("DBManager", "&Import Layer/File…"), - self.importActionSlot) - self.actionExport = self.menuTable.addAction(GuiUtils.get_icon("mActionDBExport"), - QApplication.translate("DBManager", "&Export to File…"), - self.exportActionSlot) + self.actionImport = self.menuTable.addAction( + GuiUtils.get_icon("mActionDBImport"), + QApplication.translate("DBManager", "&Import Layer/File…"), + self.importActionSlot, + ) + self.actionExport = self.menuTable.addAction( + GuiUtils.get_icon("mActionDBExport"), + QApplication.translate("DBManager", "&Export to File…"), + self.exportActionSlot, + ) self.menuTable.addSeparator() # self.actionShowSystemTables = self.menuTable.addAction(self.tr("Show system tables/views"), self.showSystemTables) # self.actionShowSystemTables.setCheckable(True) diff --git a/python/plugins/db_manager/db_manager_plugin.py b/python/plugins/db_manager/db_manager_plugin.py index cd0ea9318e05..78d996c5a867 100644 --- a/python/plugins/db_manager/db_manager_plugin.py +++ b/python/plugins/db_manager/db_manager_plugin.py @@ -22,12 +22,7 @@ from qgis.PyQt.QtWidgets import QAction, QApplication from qgis.PyQt.QtGui import QIcon -from qgis.core import ( - QgsProject, - QgsMapLayerType, - QgsDataSourceUri, - QgsApplication -) +from qgis.core import QgsProject, QgsMapLayerType, QgsDataSourceUri, QgsApplication class DBManagerPlugin: @@ -37,28 +32,37 @@ def __init__(self, iface): self.dlg = None def initGui(self): - self.action = QAction(QgsApplication.getThemeIcon('dbmanager.svg'), QApplication.translate("DBManagerPlugin", "DB Manager…"), - self.iface.mainWindow()) + self.action = QAction( + QgsApplication.getThemeIcon("dbmanager.svg"), + QApplication.translate("DBManagerPlugin", "DB Manager…"), + self.iface.mainWindow(), + ) self.action.setObjectName("dbManager") self.action.triggered.connect(self.run) # Add toolbar button and menu item - if hasattr(self.iface, 'addDatabaseToolBarIcon'): + if hasattr(self.iface, "addDatabaseToolBarIcon"): self.iface.addDatabaseToolBarIcon(self.action) else: self.iface.addToolBarIcon(self.action) - if hasattr(self.iface, 'addPluginToDatabaseMenu'): - self.iface.addPluginToDatabaseMenu(QApplication.translate("DBManagerPlugin", None), self.action) + if hasattr(self.iface, "addPluginToDatabaseMenu"): + self.iface.addPluginToDatabaseMenu( + QApplication.translate("DBManagerPlugin", None), self.action + ) else: - self.iface.addPluginToMenu(QApplication.translate("DBManagerPlugin", "DB Manager"), self.action) + self.iface.addPluginToMenu( + QApplication.translate("DBManagerPlugin", "DB Manager"), self.action + ) def unload(self): # Remove the plugin menu item and icon - if hasattr(self.iface, 'databaseMenu'): + if hasattr(self.iface, "databaseMenu"): self.iface.databaseMenu().removeAction(self.action) else: - self.iface.removePluginMenu(QApplication.translate("DBManagerPlugin", "DB Manager"), self.action) - if hasattr(self.iface, 'removeDatabaseToolBarIcon'): + self.iface.removePluginMenu( + QApplication.translate("DBManagerPlugin", "DB Manager"), self.action + ) + if hasattr(self.iface, "removeDatabaseToolBarIcon"): self.iface.removeDatabaseToolBarIcon(self.action) else: self.iface.removeToolBarIcon(self.action) @@ -69,7 +73,7 @@ def unload(self): def onUpdateSqlLayer(self): # Be able to update every Db layer from Postgres, Spatialite and Oracle l = self.iface.activeLayer() - if l.dataProvider().name() in ['postgres', 'spatialite', 'oracle']: + if l.dataProvider().name() in ["postgres", "spatialite", "oracle"]: self.run() self.dlg.runSqlLayerWindow(l) # virtual has QUrl source @@ -87,7 +91,9 @@ def run(self): self.dlg.destroyed.connect(self.onDestroyed) self.dlg.show() self.dlg.raise_() - self.dlg.setWindowState(self.dlg.windowState() & ~Qt.WindowState.WindowMinimized) + self.dlg.setWindowState( + self.dlg.windowState() & ~Qt.WindowState.WindowMinimized + ) self.dlg.activateWindow() def onDestroyed(self, obj): diff --git a/python/plugins/db_manager/db_model.py b/python/plugins/db_manager/db_model.py index 14d30472bfd3..191aaed1e40d 100644 --- a/python/plugins/db_manager/db_model.py +++ b/python/plugins/db_manager/db_model.py @@ -19,7 +19,19 @@ """ from functools import partial -from qgis.PyQt.QtCore import Qt, QObject, qDebug, QByteArray, QMimeData, QDataStream, QIODevice, QFileInfo, QAbstractItemModel, QModelIndex, pyqtSignal +from qgis.PyQt.QtCore import ( + Qt, + QObject, + qDebug, + QByteArray, + QMimeData, + QDataStream, + QIODevice, + QFileInfo, + QAbstractItemModel, + QModelIndex, + pyqtSignal, +) from qgis.PyQt.QtWidgets import QApplication, QMessageBox from qgis.PyQt.QtGui import QIcon @@ -156,7 +168,7 @@ def __init__(self, connection, parent=None): connection.deleted.connect(self.itemDeleted) # load (shared) icon with first instance of table item - if not hasattr(ConnectionItem, 'connectedIcon'): + if not hasattr(ConnectionItem, "connectedIcon"): ConnectionItem.connectedIcon = GuiUtils.get_icon("plugged") ConnectionItem.disconnectedIcon = GuiUtils.get_icon("unplugged") @@ -214,7 +226,7 @@ def __init__(self, schema, parent): schema.deleted.connect(self.itemDeleted) # load (shared) icon with first instance of schema item - if not hasattr(SchemaItem, 'schemaIcon'): + if not hasattr(SchemaItem, "schemaIcon"): SchemaItem.schemaIcon = GuiUtils.get_icon("namespace") def data(self, column): @@ -245,14 +257,20 @@ def __init__(self, table, parent): self.populate() # load (shared) icon with first instance of table item - if not hasattr(TableItem, 'tableIcon'): + if not hasattr(TableItem, "tableIcon"): TableItem.tableIcon = QgsApplication.getThemeIcon("/mIconTableLayer.svg") TableItem.viewIcon = GuiUtils.get_icon("view") TableItem.viewMaterializedIcon = GuiUtils.get_icon("view_materialized") - TableItem.layerPointIcon = QgsApplication.getThemeIcon("/mIconPointLayer.svg") + TableItem.layerPointIcon = QgsApplication.getThemeIcon( + "/mIconPointLayer.svg" + ) TableItem.layerLineIcon = QgsApplication.getThemeIcon("/mIconLineLayer.svg") - TableItem.layerPolygonIcon = QgsApplication.getThemeIcon("/mIconPolygonLayer.svg") - TableItem.layerRasterIcon = QgsApplication.getThemeIcon("/mIconRasterLayer.svg") + TableItem.layerPolygonIcon = QgsApplication.getThemeIcon( + "/mIconPolygonLayer.svg" + ) + TableItem.layerRasterIcon = QgsApplication.getThemeIcon( + "/mIconRasterLayer.svg" + ) TableItem.layerUnknownIcon = GuiUtils.get_icon("layer_unknown") def data(self, column): @@ -267,11 +285,15 @@ def icon(self): if self.getItemData().type == Table.VectorType: geom_type = self.getItemData().geomType if geom_type is not None: - if geom_type.find('POINT') != -1: + if geom_type.find("POINT") != -1: return self.layerPointIcon - elif geom_type.find('LINESTRING') != -1 or geom_type in ('CIRCULARSTRING', 'COMPOUNDCURVE', 'MULTICURVE'): + elif geom_type.find("LINESTRING") != -1 or geom_type in ( + "CIRCULARSTRING", + "COMPOUNDCURVE", + "MULTICURVE", + ): return self.layerLineIcon - elif geom_type.find('POLYGON') != -1 or geom_type == 'MULTISURFACE': + elif geom_type.find("POLYGON") != -1 or geom_type == "MULTISURFACE": return self.layerPolygonIcon return self.layerUnknownIcon @@ -279,7 +301,10 @@ def icon(self): return self.layerRasterIcon if self.getItemData().isView: - if hasattr(self.getItemData(), '_relationType') and self.getItemData()._relationType == 'm': + if ( + hasattr(self.getItemData(), "_relationType") + and self.getItemData()._relationType == "m" + ): return self.viewMaterializedIcon else: return self.viewIcon @@ -291,7 +316,7 @@ def path(self): pathList.extend(self.parent().path()) if self.getItemData().type == Table.VectorType: - pathList.append("%s::%s" % (self.data(0), self.getItemData().geomColumn)) + pathList.append(f"{self.data(0)}::{self.getItemData().geomColumn}") else: pathList.append(self.data(0)) @@ -307,7 +332,7 @@ def __init__(self, parent=None): QAbstractItemModel.__init__(self, parent) self.treeView = parent - self.header = [self.tr('Databases')] + self.header = [self.tr("Databases")] if isImportVectorAvail: self.importVector.connect(self.vectorImport) @@ -400,10 +425,14 @@ def flags(self, index): if index.column() == 0: item = index.internalPointer() - if isinstance(item, SchemaItem) \ - or (isinstance(item, TableItem) - and not (self.hasGPKGSupport and item.getItemData().type == Table.RasterType - and int(gdal.VersionInfo()) < 3100000)): + if isinstance(item, SchemaItem) or ( + isinstance(item, TableItem) + and not ( + self.hasGPKGSupport + and item.getItemData().type == Table.RasterType + and int(gdal.VersionInfo()) < 3100000 + ) + ): flags |= Qt.ItemFlag.ItemIsEditable if isinstance(item, TableItem): @@ -424,7 +453,11 @@ def flags(self, index): return flags def headerData(self, section, orientation, role): - if orientation == Qt.Orientation.Horizontal and role == Qt.ItemDataRole.DisplayRole and section < len(self.header): + if ( + orientation == Qt.Orientation.Horizontal + and role == Qt.ItemDataRole.DisplayRole + and section < len(self.header) + ): return self.header[section] return None @@ -546,9 +579,17 @@ def dropMimeData(self, data, action, row, column, parent): return True # vectors/tables to be imported must be dropped on connected db, schema or table - canImportLayer = isImportVectorAvail and parent.isValid() and \ - (isinstance(parent.internalPointer(), (SchemaItem, TableItem)) or - (isinstance(parent.internalPointer(), ConnectionItem) and parent.internalPointer().populated)) + canImportLayer = ( + isImportVectorAvail + and parent.isValid() + and ( + isinstance(parent.internalPointer(), (SchemaItem, TableItem)) + or ( + isinstance(parent.internalPointer(), ConnectionItem) + and parent.internalPointer().populated + ) + ) + ) added = 0 @@ -578,20 +619,24 @@ def dropMimeData(self, data, action, row, column, parent): if canImportLayer: if QgsRasterLayer.isValidRasterFileName(filename): - layerType = 'raster' - providerKey = 'gdal' + layerType = "raster" + providerKey = "gdal" else: - layerType = 'vector' - providerKey = 'ogr' + layerType = "vector" + providerKey = "ogr" layerName = QFileInfo(filename).completeBaseName() - if self.importLayer(layerType, providerKey, layerName, filename, parent): + if self.importLayer( + layerType, providerKey, layerName, filename, parent + ): added += 1 if data.hasFormat(self.QGIS_URI_MIME): for uri in QgsMimeDataUtils.decodeUriList(data): if canImportLayer: - if self.importLayer(uri.layerType, uri.providerKey, uri.name, uri.uri, parent): + if self.importLayer( + uri.layerType, uri.providerKey, uri.name, uri.uri, parent + ): added += 1 return added > 0 @@ -602,7 +647,7 @@ def importLayer(self, layerType, providerKey, layerName, uriString, parent): if not isImportVectorAvail: return False - if layerType == 'raster': + if layerType == "raster": return False # not implemented yet inLayer = QgsRasterLayer(uriString, layerName, providerKey) else: @@ -610,7 +655,11 @@ def importLayer(self, layerType, providerKey, layerName, uriString, parent): if not inLayer.isValid(): # invalid layer - QMessageBox.warning(None, self.tr("Invalid layer"), self.tr("Unable to load the layer {0}").format(inLayer.name())) + QMessageBox.warning( + None, + self.tr("Invalid layer"), + self.tr("Unable to load the layer {0}").format(inLayer.name()), + ) return False # retrieve information about the new table's db and schema @@ -630,11 +679,15 @@ def importLayer(self, layerType, providerKey, layerName, uriString, parent): if inLayer.type() == inLayer.VectorLayer: # create the output uri - schema = outSchema.name if outDb.schemas() is not None and outSchema is not None else "" + schema = ( + outSchema.name + if outDb.schemas() is not None and outSchema is not None + else "" + ) pkCol = geomCol = "" # default pk and geom field name value - if providerKey in ['postgres', 'spatialite']: + if providerKey in ["postgres", "spatialite"]: inUri = QgsDataSourceUri(inLayer.source()) pkCol = inUri.keyColumn() geomCol = inUri.geometryColumn() diff --git a/python/plugins/db_manager/db_plugins/__init__.py b/python/plugins/db_manager/db_plugins/__init__.py index 41f61c7bb5c9..e35b113dcf9c 100644 --- a/python/plugins/db_manager/db_plugins/__init__.py +++ b/python/plugins/db_manager/db_plugins/__init__.py @@ -23,11 +23,14 @@ class NotSupportedDbType(Exception): def __init__(self, dbtype): from qgis.PyQt.QtWidgets import QApplication - self.msg = QApplication.translate("DBManagerPlugin", "{0} is not supported yet").format(dbtype) + + self.msg = QApplication.translate( + "DBManagerPlugin", "{0} is not supported yet" + ).format(dbtype) Exception(self, self.msg) def __str__(self): - return self.msg.encode('utf-8') + return self.msg.encode("utf-8") def initDbPluginList(): @@ -35,7 +38,7 @@ def initDbPluginList(): current_dir = os.path.dirname(__file__) for name in os.listdir(current_dir): - if name == '__pycache__': + if name == "__pycache__": continue if not os.path.isdir(os.path.join(current_dir, name)): continue @@ -43,7 +46,7 @@ def initDbPluginList(): try: exec("from .%s import plugin as mod" % name, globals()) except ImportError as e: - DBPLUGIN_ERRORS.append("%s: %s" % (name, str(e))) + DBPLUGIN_ERRORS.append(f"{name}: {str(e)}") continue pluginclass = mod.classFactory() # NOQA diff --git a/python/plugins/db_manager/db_plugins/connector.py b/python/plugins/db_manager/db_plugins/connector.py index 4cda39e1992b..49ec950e57ba 100644 --- a/python/plugins/db_manager/db_plugins/connector.py +++ b/python/plugins/db_manager/db_plugins/connector.py @@ -26,8 +26,7 @@ class DBConnector: def __init__(self, uri): - """Creates a new DB connector - """ + """Creates a new DB connector""" self.connection = None self._uri = uri @@ -95,17 +94,22 @@ def _execute(self, cursor, sql): return cursor def _execute_and_commit(self, sql): - """ tries to execute and commit some action, on error it rolls back the change """ + """tries to execute and commit some action, on error it rolls back the change""" self._execute(None, sql) self._commit() def _get_cursor(self, name=None): try: if name is not None: - name = str(name).encode('ascii', 'replace').replace('?', "_") - self._last_cursor_named_id = 0 if not hasattr(self, - '_last_cursor_named_id') else self._last_cursor_named_id + 1 - return self.connection.cursor("%s_%d" % (name, self._last_cursor_named_id)) + name = str(name).encode("ascii", "replace").replace("?", "_") + self._last_cursor_named_id = ( + 0 + if not hasattr(self, "_last_cursor_named_id") + else self._last_cursor_named_id + 1 + ) + return self.connection.cursor( + "%s_%d" % (name, self._last_cursor_named_id) + ) return self.connection.cursor() @@ -183,36 +187,33 @@ def _get_cursor_columns(self, c): @classmethod def quoteId(self, identifier): - if hasattr(identifier, '__iter__') and not isinstance(identifier, str): - return '.'.join( - self.quoteId(i) - for i in identifier - if i is not None and i != "" + if hasattr(identifier, "__iter__") and not isinstance(identifier, str): + return ".".join( + self.quoteId(i) for i in identifier if i is not None and i != "" ) - identifier = str( - identifier) if identifier is not None else '' # make sure it's python unicode string + identifier = ( + str(identifier) if identifier is not None else "" + ) # make sure it's python unicode string return '"%s"' % identifier.replace('"', '""') @classmethod def quoteString(self, txt): - """ make the string safe - replace ' with '' """ - if hasattr(txt, '__iter__') and not isinstance(txt, str): - return '.'.join( - self.quoteString(i) - for i in txt - if i is not None - ) + """make the string safe - replace ' with ''""" + if hasattr(txt, "__iter__") and not isinstance(txt, str): + return ".".join(self.quoteString(i) for i in txt if i is not None) - txt = str(txt) if txt is not None else '' # make sure it's python unicode string + txt = ( + str(txt) if txt is not None else "" + ) # make sure it's python unicode string return "'%s'" % txt.replace("'", "''") @classmethod def getSchemaTableName(self, table): - if not hasattr(table, '__iter__') and not isinstance(table, str): + if not hasattr(table, "__iter__") and not isinstance(table, str): return (None, table) if isinstance(table, str): - table = table.split('.') + table = table.split(".") if len(table) < 2: return (None, table[0]) else: @@ -220,7 +221,7 @@ def getSchemaTableName(self, table): @classmethod def getSqlDictionary(self): - """ return a generic SQL dictionary """ + """return a generic SQL dictionary""" try: from ..sql_dictionary import getSqlDictionary @@ -230,7 +231,7 @@ def getSqlDictionary(self): def getComment(self, tablename, field): """Returns the comment for a field""" - return '' + return "" def commentTable(self, schema, tablename, comment=None): """Comment the table""" diff --git a/python/plugins/db_manager/db_plugins/data_model.py b/python/plugins/db_manager/db_plugins/data_model.py index 1087035fe8ba..a8e9b9ae918f 100644 --- a/python/plugins/db_manager/db_plugins/data_model.py +++ b/python/plugins/db_manager/db_plugins/data_model.py @@ -18,15 +18,15 @@ ***************************************************************************/ """ -from qgis.PyQt.QtCore import (Qt, - QElapsedTimer, - QRegularExpression, - QAbstractTableModel, - pyqtSignal, - QObject) -from qgis.PyQt.QtGui import (QFont, - QStandardItemModel, - QStandardItem) +from qgis.PyQt.QtCore import ( + Qt, + QElapsedTimer, + QRegularExpression, + QAbstractTableModel, + pyqtSignal, + QObject, +) +from qgis.PyQt.QtGui import QFont, QStandardItemModel, QStandardItem from qgis.PyQt.QtWidgets import QApplication from qgis.core import QgsTask @@ -47,8 +47,7 @@ def headerToString(self, sep="\t"): def rowToString(self, row, sep="\t"): return sep.join( - str(self.getData(row, col)) - for col in range(self.columnCount()) + str(self.getData(row, col)) for col in range(self.columnCount()) ) def getData(self, row, col): @@ -64,9 +63,11 @@ def columnCount(self, parent=None): return len(self._header) def data(self, index, role): - if role not in [Qt.ItemDataRole.DisplayRole, - Qt.ItemDataRole.EditRole, - Qt.ItemDataRole.FontRole]: + if role not in [ + Qt.ItemDataRole.DisplayRole, + Qt.ItemDataRole.EditRole, + Qt.ItemDataRole.FontRole, + ]: return None val = self.getData(index.row(), index.column()) @@ -92,7 +93,9 @@ def data(self, index, role): try: return str(val) # convert to Unicode except UnicodeDecodeError: - return str(val, 'utf-8', 'replace') # convert from utf8 and replace errors (if any) + return str( + val, "utf-8", "replace" + ) # convert from utf8 and replace errors (if any) def headerData(self, section, orientation, role): if role != Qt.ItemDataRole.DisplayRole: @@ -121,16 +124,22 @@ def __init__(self, table, parent=None): self.fields.append(self._sanitizeTableField(fld)) self.fetchedCount = 201 - self.fetchedFrom = -self.fetchedCount - 1 # so the first call to getData will exec fetchMoreData(0) + self.fetchedFrom = ( + -self.fetchedCount - 1 + ) # so the first call to getData will exec fetchMoreData(0) def _sanitizeTableField(self, field): - """ quote column names to avoid some problems (e.g. columns with upper case) """ + """quote column names to avoid some problems (e.g. columns with upper case)""" return self.db.quoteId(field) def getData(self, row, col): if row < self.fetchedFrom or row >= self.fetchedFrom + self.fetchedCount: margin = self.fetchedCount / 2 - start = int(self.rowCount() - margin if row + margin >= self.rowCount() else row - margin) + start = int( + self.rowCount() - margin + if row + margin >= self.rowCount() + else row - margin + ) if start < 0: start = 0 self.fetchMoreData(start) @@ -141,7 +150,11 @@ def fetchMoreData(self, row_start): def rowCount(self, index=None): # case for tables with no columns ... any reason to use them? :-) - return self.table.rowCount if self.table.rowCount is not None and self.columnCount(index) > 0 else 0 + return ( + self.table.rowCount + if self.table.rowCount is not None and self.columnCount(index) > 0 + else 0 + ) class SqlResultModelAsync(QObject): @@ -149,7 +162,7 @@ class SqlResultModelAsync(QObject): def __init__(self): super().__init__() - self.error = BaseError('') + self.error = BaseError("") self.status = None self.model = None self.task = None @@ -172,11 +185,13 @@ def modelDone(self): class SqlResultModelTask(QgsTask): def __init__(self, db, sql, parent): - super().__init__(description=QApplication.translate("DBManagerPlugin", "Executing SQL")) + super().__init__( + description=QApplication.translate("DBManagerPlugin", "Executing SQL") + ) self.db = db self.sql = sql self.parent = parent - self.error = BaseError('') + self.error = BaseError("") self.model = None @@ -231,12 +246,19 @@ def rowFromData(self, data): row = [] for c in data: item = QStandardItem(str(c)) - item.setFlags((item.flags() | Qt.ItemFlag.ItemIsEditable) if self.editable else (item.flags() & ~Qt.ItemFlag.ItemIsEditable)) + item.setFlags( + (item.flags() | Qt.ItemFlag.ItemIsEditable) + if self.editable + else (item.flags() & ~Qt.ItemFlag.ItemIsEditable) + ) row.append(item) return row def headerData(self, section, orientation, role): - if orientation == Qt.Orientation.Horizontal and role == Qt.ItemDataRole.DisplayRole: + if ( + orientation == Qt.Orientation.Horizontal + and role == Qt.ItemDataRole.DisplayRole + ): return self.header[section] return None @@ -254,27 +276,46 @@ def getObjectIter(self): class TableFieldsModel(SimpleTableModel): def __init__(self, parent, editable=False): - SimpleTableModel.__init__(self, ['Name', 'Type', 'Null', 'Default', 'Comment'], editable, parent) + SimpleTableModel.__init__( + self, ["Name", "Type", "Null", "Default", "Comment"], editable, parent + ) def headerData(self, section, orientation, role): - if orientation == Qt.Orientation.Vertical and role == Qt.ItemDataRole.DisplayRole: + if ( + orientation == Qt.Orientation.Vertical + and role == Qt.ItemDataRole.DisplayRole + ): return section + 1 return SimpleTableModel.headerData(self, section, orientation, role) def flags(self, index): flags = SimpleTableModel.flags(self, index) - if index.column() == 2 and flags & Qt.ItemFlag.ItemIsEditable: # set Null column as checkable instead of editable - flags = flags & ~Qt.ItemFlag.ItemIsEditable | Qt.ItemFlag.ItemIsUserCheckable + if ( + index.column() == 2 and flags & Qt.ItemFlag.ItemIsEditable + ): # set Null column as checkable instead of editable + flags = ( + flags & ~Qt.ItemFlag.ItemIsEditable | Qt.ItemFlag.ItemIsUserCheckable + ) return flags def append(self, fld): - data = [fld.name, fld.type2String(), not fld.notNull, fld.default2String(), fld.getComment()] + data = [ + fld.name, + fld.type2String(), + not fld.notNull, + fld.default2String(), + fld.getComment(), + ] self.appendRow(self.rowFromData(data)) row = self.rowCount() - 1 self.setData(self.index(row, 0), fld, Qt.ItemDataRole.UserRole) self.setData(self.index(row, 1), fld.primaryKey, Qt.ItemDataRole.UserRole) self.setData(self.index(row, 2), None, Qt.ItemDataRole.DisplayRole) - self.setData(self.index(row, 2), Qt.CheckState.Unchecked if fld.notNull else Qt.CheckState.Checked, Qt.ItemDataRole.CheckStateRole) + self.setData( + self.index(row, 2), + Qt.CheckState.Unchecked if fld.notNull else Qt.CheckState.Checked, + Qt.ItemDataRole.CheckStateRole, + ) def _getNewObject(self): from .plugin import TableField @@ -295,24 +336,31 @@ def getObject(self, row): fld.modifier = None fld.dataType = typestr - fld.notNull = self.data(self.index(row, 2), Qt.ItemDataRole.CheckStateRole) == Qt.CheckState.Unchecked + fld.notNull = ( + self.data(self.index(row, 2), Qt.ItemDataRole.CheckStateRole) + == Qt.CheckState.Unchecked + ) fld.primaryKey = self.data(self.index(row, 1), Qt.ItemDataRole.UserRole) fld.comment = self.data(self.index(row, 4)) return fld def getFields(self): - return [ - fld - for fld in self.getObjectIter() - ] + return [fld for fld in self.getObjectIter()] class TableConstraintsModel(SimpleTableModel): def __init__(self, parent, editable=False): - SimpleTableModel.__init__(self, [QApplication.translate("DBManagerPlugin", 'Name'), - QApplication.translate("DBManagerPlugin", 'Type'), - QApplication.translate("DBManagerPlugin", 'Column(s)')], editable, parent) + SimpleTableModel.__init__( + self, + [ + QApplication.translate("DBManagerPlugin", "Name"), + QApplication.translate("DBManagerPlugin", "Type"), + QApplication.translate("DBManagerPlugin", "Column(s)"), + ], + editable, + parent, + ) def append(self, constr): field_names = [str(k_v[1].name) for k_v in iter(list(constr.fields().items()))] @@ -338,17 +386,21 @@ def getObject(self, row): return constr def getConstraints(self): - return [ - constr - for constr in self.getObjectIter() - ] + return [constr for constr in self.getObjectIter()] class TableIndexesModel(SimpleTableModel): def __init__(self, parent, editable=False): - SimpleTableModel.__init__(self, [QApplication.translate("DBManagerPlugin", 'Name'), - QApplication.translate("DBManagerPlugin", 'Column(s)')], editable, parent) + SimpleTableModel.__init__( + self, + [ + QApplication.translate("DBManagerPlugin", "Name"), + QApplication.translate("DBManagerPlugin", "Column(s)"), + ], + editable, + parent, + ) def append(self, idx): field_names = [str(k_v1[1].name) for k_v1 in iter(list(idx.fields().items()))] @@ -372,7 +424,4 @@ def getObject(self, row): return idx def getIndexes(self): - return [ - idx - for idx in self.getObjectIter() - ] + return [idx for idx in self.getObjectIter()] diff --git a/python/plugins/db_manager/db_plugins/gpkg/connector.py b/python/plugins/db_manager/db_plugins/gpkg/connector.py index 77de9a3f7606..a7091a0f6ed7 100644 --- a/python/plugins/db_manager/db_plugins/gpkg/connector.py +++ b/python/plugins/db_manager/db_plugins/gpkg/connector.py @@ -39,6 +39,7 @@ import sqlite3 from osgeo import gdal, ogr, osr + gdal.UseExceptions() ogr.UseExceptions() @@ -83,10 +84,24 @@ def _opendb(self): try: self.gdal_ds = gdal.OpenEx(self.dbname) except Exception: - raise ConnectionError(QApplication.translate("DBManagerPlugin", '"{0}" not found').format(self.dbname)) - if self.gdal_ds.GetDriver().ShortName != 'GPKG': - raise ConnectionError(QApplication.translate("DBManagerPlugin", '"{dbname}" not recognized as GPKG ({shortname} reported instead.)').format(dbname=self.dbname, shortname=self.gdal_ds.GetDriver().ShortName)) - self.has_raster = self.gdal_ds.RasterCount != 0 or self.gdal_ds.GetMetadata('SUBDATASETS') is not None + raise ConnectionError( + QApplication.translate("DBManagerPlugin", '"{0}" not found').format( + self.dbname + ) + ) + if self.gdal_ds.GetDriver().ShortName != "GPKG": + raise ConnectionError( + QApplication.translate( + "DBManagerPlugin", + '"{dbname}" not recognized as GPKG ({shortname} reported instead.)', + ).format( + dbname=self.dbname, shortname=self.gdal_ds.GetDriver().ShortName + ) + ) + self.has_raster = ( + self.gdal_ds.RasterCount != 0 + or self.gdal_ds.GetMetadata("SUBDATASETS") is not None + ) self.connection = None self._current_thread = None @@ -97,7 +112,9 @@ def connection(self): invalidates it and create a new one. """ - if self._connection is None or self._current_thread != int(QThread.currentThreadId()): + if self._connection is None or self._current_thread != int( + QThread.currentThreadId() + ): self._current_thread = int(QThread.currentThreadId()) try: self._connection = spatialite_connect(str(self.dbname)) @@ -110,9 +127,13 @@ def connection(self, conn): self._connection = conn def unquoteId(self, quotedId): - if len(quotedId) <= 2 or quotedId[0] != '"' or quotedId[len(quotedId) - 1] != '"': + if ( + len(quotedId) <= 2 + or quotedId[0] != '"' + or quotedId[len(quotedId) - 1] != '"' + ): return quotedId - unquoted = '' + unquoted = "" i = 1 while i < len(quotedId) - 1: if quotedId[i] == '"' and quotedId[i + 1] == '"': @@ -194,7 +215,7 @@ def isValidDatabase(cls, path): ds = gdal.OpenEx(path) except Exception: return False - return ds.GetDriver().ShortName == 'GPKG' + return ds.GetDriver().ShortName == "GPKG" def getInfo(self): return None @@ -217,10 +238,9 @@ def canAddGeometryColumn(self, table): def canAddSpatialIndex(self, table): _, tablename = self.getSchemaTableName(table) lyr = self.gdal_ds.GetLayerByName(tablename) - if lyr is None or lyr.GetGeometryColumn() == '': + if lyr is None or lyr.GetGeometryColumn() == "": return False - return not self.hasSpatialIndex(table, - lyr.GetGeometryColumn()) + return not self.hasSpatialIndex(table, lyr.GetGeometryColumn()) def hasRasterSupport(self): return self.has_raster @@ -243,8 +263,7 @@ def fieldTypes(self): "TINYINT", "SMALLINT", "DOUBLE", - "FLOAT" - "DATE", + "FLOAT" "DATE", "DATETIME", "BOOLEAN", ] @@ -253,7 +272,7 @@ def getSchemas(self): return None def getTables(self, schema=None, add_sys_tables=False): - """ get list of tables """ + """get list of tables""" items = [] try: @@ -276,62 +295,73 @@ def getTables(self, schema=None, add_sys_tables=False): return sorted(items, key=cmp_to_key(lambda x, y: (x[1] > y[1]) - (x[1] < y[1]))) def getVectorTables(self, schema=None): - """Returns a list of vector table information - """ + """Returns a list of vector table information""" items = [] - for table in self.core_connection.tables(schema, QgsAbstractDatabaseProviderConnection.TableFlag.Vector | QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial): - if not (table.flags() & QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial): + for table in self.core_connection.tables( + schema, + QgsAbstractDatabaseProviderConnection.TableFlag.Vector + | QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial, + ): + if not ( + table.flags() & QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial + ): geom_type = table.geometryColumnTypes()[0] # Use integer PG code for SRID srid = geom_type.crs.postgisSrid() geomtype_flatten = QgsWkbTypes.flatType(geom_type.wkbType) - geomname = 'GEOMETRY' + geomname = "GEOMETRY" if geomtype_flatten == QgsWkbTypes.Type.Point: - geomname = 'POINT' + geomname = "POINT" elif geomtype_flatten == QgsWkbTypes.Type.LineString: - geomname = 'LINESTRING' + geomname = "LINESTRING" elif geomtype_flatten == QgsWkbTypes.Type.Polygon: - geomname = 'POLYGON' + geomname = "POLYGON" elif geomtype_flatten == QgsWkbTypes.Type.MultiPoint: - geomname = 'MULTIPOINT' + geomname = "MULTIPOINT" elif geomtype_flatten == QgsWkbTypes.Type.MultiLineString: - geomname = 'MULTILINESTRING' + geomname = "MULTILINESTRING" elif geomtype_flatten == QgsWkbTypes.Type.MultiPolygon: - geomname = 'MULTIPOLYGON' + geomname = "MULTIPOLYGON" elif geomtype_flatten == QgsWkbTypes.Type.GeometryCollection: - geomname = 'GEOMETRYCOLLECTION' + geomname = "GEOMETRYCOLLECTION" elif geomtype_flatten == QgsWkbTypes.Type.CircularString: - geomname = 'CIRCULARSTRING' + geomname = "CIRCULARSTRING" elif geomtype_flatten == QgsWkbTypes.Type.CompoundCurve: - geomname = 'COMPOUNDCURVE' + geomname = "COMPOUNDCURVE" elif geomtype_flatten == QgsWkbTypes.Type.CurvePolygon: - geomname = 'CURVEPOLYGON' + geomname = "CURVEPOLYGON" elif geomtype_flatten == QgsWkbTypes.Type.MultiCurve: - geomname = 'MULTICURVE' + geomname = "MULTICURVE" elif geomtype_flatten == QgsWkbTypes.Type.MultiSurface: - geomname = 'MULTISURFACE' - geomdim = 'XY' + geomname = "MULTISURFACE" + geomdim = "XY" if QgsWkbTypes.hasZ(geom_type.wkbType): - geomdim += 'Z' + geomdim += "Z" if QgsWkbTypes.hasM(geom_type.wkbType): - geomdim += 'M' + geomdim += "M" item = [ Table.VectorType, table.tableName(), - bool(table.flags() & QgsAbstractDatabaseProviderConnection.TableFlag.View), # is_view + bool( + table.flags() + & QgsAbstractDatabaseProviderConnection.TableFlag.View + ), # is_view table.tableName(), table.geometryColumn(), geomname, geomdim, - srid + srid, ] self.mapSridToName[srid] = geom_type.crs.description() else: item = [ Table.TableType, table.tableName(), - bool(table.flags() & QgsAbstractDatabaseProviderConnection.TableFlag.View), + bool( + table.flags() + & QgsAbstractDatabaseProviderConnection.TableFlag.View + ), ] items.append(item) @@ -339,25 +369,29 @@ def getVectorTables(self, schema=None): return items def getRasterTables(self, schema=None): - """ get list of table with a geometry column - it returns: - name (table name) - type = 'view' (is a view?) - geometry_column: - r.table_name (the prefix table name, use this to load the layer) - r.geometry_column - srid + """get list of table with a geometry column + it returns: + name (table name) + type = 'view' (is a view?) + geometry_column: + r.table_name (the prefix table name, use this to load the layer) + r.geometry_column + srid """ items = [] - for table in self.core_connection.tables(schema, QgsAbstractDatabaseProviderConnection.TableFlag.Raster): + for table in self.core_connection.tables( + schema, QgsAbstractDatabaseProviderConnection.TableFlag.Raster + ): geom_type = table.geometryColumnTypes()[0] # Use integer PG code for SRID srid = geom_type.crs.postgisSrid() item = [ Table.RasterType, table.tableName(), - bool(table.flags() & QgsAbstractDatabaseProviderConnection.TableFlag.View), + bool( + table.flags() & QgsAbstractDatabaseProviderConnection.TableFlag.View + ), table.tableName(), table.geometryColumn(), srid, @@ -372,7 +406,7 @@ def getTableRowCount(self, table): return lyr.GetFeatureCount() if lyr is not None else None def getTableFields(self, table): - """ return list of columns in table """ + """return list of columns in table""" sql = "PRAGMA table_info(%s)" % (self.quoteId(table)) ret = self._fetchAll(sql) if ret is None: @@ -380,7 +414,7 @@ def getTableFields(self, table): return ret def getTableIndexes(self, table): - """ get info about table's indexes """ + """get info about table's indexes""" sql = "PRAGMA index_list(%s)" % (self.quoteId(table)) indexes = self._fetchAll(sql) if indexes is None: @@ -398,10 +432,7 @@ def getTableIndexes(self, table): sql = "PRAGMA index_info(%s)" % (self.quoteId(name)) idx = [num, name, unique] - cols = [ - cid - for seq, cid, cname in self._fetchAll(sql) - ] + cols = [cid for seq, cid, cname in self._fetchAll(sql)] idx.append(cols) indexes[i] = idx @@ -414,7 +445,10 @@ def getTableTriggers(self, table): _, tablename = self.getSchemaTableName(table) # Do not list rtree related triggers as we don't want them to be dropped - sql = "SELECT name, sql FROM sqlite_master WHERE tbl_name = %s AND type = 'trigger'" % (self.quoteString(tablename)) + sql = ( + "SELECT name, sql FROM sqlite_master WHERE tbl_name = %s AND type = 'trigger'" + % (self.quoteString(tablename)) + ) if self.isVectorTable(table): sql += " AND name NOT LIKE 'rtree_%%'" elif self.isRasterTable(table): @@ -427,21 +461,23 @@ def getTableTriggers(self, table): return self._fetchAll(sql) def deleteTableTrigger(self, trigger, table=None): - """Deletes trigger """ + """Deletes trigger""" sql = "DROP TRIGGER %s" % self.quoteId(trigger) self._execute_and_commit(sql) def getTableExtent(self, table, geom, force=False): - """ find out table extent """ + """find out table extent""" _, tablename = self.getSchemaTableName(table) if self.isRasterTable(table): - md = self.gdal_ds.GetMetadata('SUBDATASETS') + md = self.gdal_ds.GetMetadata("SUBDATASETS") if md is None or len(md) == 0: ds = self.gdal_ds else: - subdataset_name = 'GPKG:%s:%s' % (self.gdal_ds.GetDescription(), tablename) + subdataset_name = "GPKG:{}:{}".format( + self.gdal_ds.GetDescription(), tablename + ) try: ds = gdal.Open(subdataset_name) except Exception: @@ -466,14 +502,17 @@ def getTableExtent(self, table, geom, force=False): return (minx, miny, maxx, maxy) def getViewDefinition(self, view): - """ returns definition of the view """ + """returns definition of the view""" return None def getSpatialRefInfo(self, srid): if srid in self.mapSridToName: return self.mapSridToName[srid] - sql = "SELECT srs_name FROM gpkg_spatial_ref_sys WHERE srs_id = %s" % self.quoteString(srid) + sql = ( + "SELECT srs_name FROM gpkg_spatial_ref_sys WHERE srs_id = %s" + % self.quoteString(srid) + ) res = self._fetchOne(sql) if res is not None and len(res) > 0: res = res[0] @@ -488,13 +527,18 @@ def isVectorTable(self, table): def isRasterTable(self, table): if self.has_raster and not self.isVectorTable(table): _, tablename = self.getSchemaTableName(table) - md = self.gdal_ds.GetMetadata('SUBDATASETS') + md = self.gdal_ds.GetMetadata("SUBDATASETS") if md is None or len(md) == 0: - sql = "SELECT COUNT(*) FROM gpkg_contents WHERE data_type = 'tiles' AND table_name = %s" % self.quoteString(tablename) + sql = ( + "SELECT COUNT(*) FROM gpkg_contents WHERE data_type = 'tiles' AND table_name = %s" + % self.quoteString(tablename) + ) ret = self._fetchOne(sql) return ret != [] and ret[0][0] == 1 else: - subdataset_name = 'GPKG:%s:%s' % (self.gdal_ds.GetDescription(), tablename) + subdataset_name = "GPKG:{}:{}".format( + self.gdal_ds.GetDescription(), tablename + ) for key in md: if md[key] == subdataset_name: return True @@ -505,37 +549,41 @@ def getOGRFieldTypeFromSQL(self, sql_type): ogr_type = ogr.OFTString ogr_subtype = ogr.OFSTNone width = 0 - if not sql_type.startswith('TEXT ('): - pos = sql_type.find(' (') + if not sql_type.startswith("TEXT ("): + pos = sql_type.find(" (") if pos >= 0: sql_type = sql_type[0:pos] - if sql_type == 'BOOLEAN': + if sql_type == "BOOLEAN": ogr_type = ogr.OFTInteger ogr_subtype = ogr.OFSTBoolean - elif sql_type in ('TINYINT', 'SMALLINT', 'MEDIUMINT'): + elif sql_type in ("TINYINT", "SMALLINT", "MEDIUMINT"): ogr_type = ogr.OFTInteger - elif sql_type == 'INTEGER': + elif sql_type == "INTEGER": ogr_type = ogr.OFTInteger64 - elif sql_type == 'FLOAT': + elif sql_type == "FLOAT": ogr_type = ogr.OFTReal ogr_subtype = ogr.OFSTFloat32 - elif sql_type == 'DOUBLE': + elif sql_type == "DOUBLE": ogr_type = ogr.OFTReal - elif sql_type == 'DATE': + elif sql_type == "DATE": ogr_type = ogr.OFTDate - elif sql_type == 'DATETIME': + elif sql_type == "DATETIME": ogr_type = ogr.OFTDateTime - elif sql_type.startswith('TEXT (') and sql_type.endswith(')'): - width = int(sql_type[len('TEXT ('):-1]) + elif sql_type.startswith("TEXT (") and sql_type.endswith(")"): + width = int(sql_type[len("TEXT (") : -1]) return (ogr_type, ogr_subtype, width) def createOGRFieldDefnFromSQL(self, sql_fielddef): - f_split = sql_fielddef.split(' ') + f_split = sql_fielddef.split(" ") quoted_name = f_split[0] name = self.unquoteId(quoted_name) sql_type = f_split[1].upper() - if len(f_split) >= 3 and f_split[2].startswith('(') and f_split[2].endswith(')'): - sql_type += ' ' + f_split[2] + if ( + len(f_split) >= 3 + and f_split[2].startswith("(") + and f_split[2].endswith(")") + ): + sql_type += " " + f_split[2] f_split = [f for f in f_split[3:]] else: f_split = [f for f in f_split[2:]] @@ -543,16 +591,16 @@ def createOGRFieldDefnFromSQL(self, sql_fielddef): fld_defn = ogr.FieldDefn(name, ogr_type) fld_defn.SetSubType(ogr_subtype) fld_defn.SetWidth(width) - if len(f_split) >= 2 and f_split[0] == 'NOT' and f_split[1] == 'NULL': + if len(f_split) >= 2 and f_split[0] == "NOT" and f_split[1] == "NULL": fld_defn.SetNullable(False) f_split = [f for f in f_split[2:]] elif len(f_split) >= 1: f_split = [f for f in f_split[1:]] - if len(f_split) >= 2 and f_split[0] == 'DEFAULT': + if len(f_split) >= 2 and f_split[0] == "DEFAULT": new_default = f_split[1] - if new_default == '': + if new_default == "": fld_defn.SetDefault(None) - elif new_default == 'NULL' or ogr_type in (ogr.OFTInteger, ogr.OFTReal): + elif new_default == "NULL" or ogr_type in (ogr.OFTInteger, ogr.OFTReal): fld_defn.SetDefault(new_default) elif new_default.startswith("'") and new_default.endswith("'"): fld_defn.SetDefault(new_default) @@ -562,17 +610,19 @@ def createOGRFieldDefnFromSQL(self, sql_fielddef): def createTable(self, table, field_defs, pkey): """Creates ordinary table - 'fields' is array containing field definitions - 'pkey' is the primary key name + 'fields' is array containing field definitions + 'pkey' is the primary key name """ if len(field_defs) == 0: return False options = [] if pkey is not None and pkey != "": - options += ['FID=' + pkey] + options += ["FID=" + pkey] _, tablename = self.getSchemaTableName(table) - lyr = self.gdal_ds.CreateLayer(tablename, geom_type=ogr.wkbNone, options=options) + lyr = self.gdal_ds.CreateLayer( + tablename, geom_type=ogr.wkbNone, options=options + ) if lyr is None: return False for field_def in field_defs: @@ -585,9 +635,9 @@ def createTable(self, table, field_defs, pkey): return True def deleteTable(self, table): - """Deletes table from the database """ + """Deletes table from the database""" if self.isRasterTable(table): - sql = "DROP TABLE {}".format(self.quoteId(table)) + sql = f"DROP TABLE {self.quoteId(table)}" self._execute_and_commit(sql) return True @@ -598,7 +648,7 @@ def deleteTable(self, table): return False def emptyTable(self, table): - """Deletes all rows from table """ + """Deletes all rows from table""" if self.isRasterTable(table): return False @@ -617,11 +667,16 @@ def renameTable(self, table, new_table): """ try: name = table[1] # 0 is schema - vector_table_names = [t.tableName() for t in self.core_connection.tables('', QgsAbstractDatabaseProviderConnection.TableFlag.Vector)] + vector_table_names = [ + t.tableName() + for t in self.core_connection.tables( + "", QgsAbstractDatabaseProviderConnection.TableFlag.Vector + ) + ] if name in vector_table_names: - self.core_connection.renameVectorTable('', name, new_table) + self.core_connection.renameVectorTable("", name, new_table) else: - self.core_connection.renameRasterTable('', name, new_table) + self.core_connection.renameRasterTable("", name, new_table) return True except QgsProviderConnectionException: return False @@ -630,11 +685,11 @@ def moveTable(self, table, new_table, new_schema=None): return self.renameTable(table, new_table) def runVacuum(self): - """ run vacuum on the db """ + """run vacuum on the db""" self._execute_and_commit("VACUUM") def addTableColumn(self, table, field_def): - """Adds a column to table """ + """Adds a column to table""" _, tablename = self.getSchemaTableName(table) lyr = self.gdal_ds.GetLayerByName(tablename) @@ -644,7 +699,7 @@ def addTableColumn(self, table, field_def): return lyr.CreateField(fld_defn) == 0 def deleteTableColumn(self, table, column): - """Deletes column from a table """ + """Deletes column from a table""" if self.isGeometryColumn(table, column): return False @@ -657,7 +712,16 @@ def deleteTableColumn(self, table, column): return lyr.DeleteField(idx) == 0 return False - def updateTableColumn(self, table, column, new_name, new_data_type=None, new_not_null=None, new_default=None, comment=None): + def updateTableColumn( + self, + table, + column, + new_name, + new_data_type=None, + new_not_null=None, + new_default=None, + comment=None, + ): if self.isGeometryColumn(table, column): return False @@ -682,15 +746,17 @@ def updateTableColumn(self, table, column, new_name, new_data_type=None, new_not else: flag |= ogr.ALTER_TYPE_FLAG flag |= ogr.ALTER_WIDTH_PRECISION_FLAG - ogr_type, ogr_subtype, width = self.getOGRFieldTypeFromSQL(new_data_type) + ogr_type, ogr_subtype, width = self.getOGRFieldTypeFromSQL( + new_data_type + ) new_fielddefn = ogr.FieldDefn(new_name, ogr_type) new_fielddefn.SetSubType(ogr_subtype) new_fielddefn.SetWidth(width) if new_default is not None: flag |= ogr.ALTER_DEFAULT_FLAG - if new_default == '': + if new_default == "": new_fielddefn.SetDefault(None) - elif new_default == 'NULL' or ogr_type in (ogr.OFTInteger, ogr.OFTReal): + elif new_default == "NULL" or ogr_type in (ogr.OFTInteger, ogr.OFTReal): new_fielddefn.SetDefault(str(new_default)) elif new_default.startswith("'") and new_default.endswith("'"): new_fielddefn.SetDefault(str(new_default)) @@ -715,36 +781,38 @@ def isGeometryColumn(self, table, column): return False return column == lyr.GetGeometryColumn() - def addGeometryColumn(self, table, geom_column='geometry', geom_type='POINT', srid=-1, dim=2): + def addGeometryColumn( + self, table, geom_column="geometry", geom_type="POINT", srid=-1, dim=2 + ): _, tablename = self.getSchemaTableName(table) lyr = self.gdal_ds.GetLayerByName(tablename) if lyr is None: return False ogr_type = ogr.wkbUnknown - if geom_type == 'POINT': + if geom_type == "POINT": ogr_type = ogr.wkbPoint - elif geom_type == 'LINESTRING': + elif geom_type == "LINESTRING": ogr_type = ogr.wkbLineString - elif geom_type == 'POLYGON': + elif geom_type == "POLYGON": ogr_type = ogr.wkbPolygon - elif geom_type == 'MULTIPOINT': + elif geom_type == "MULTIPOINT": ogr_type = ogr.wkbMultiPoint - elif geom_type == 'MULTILINESTRING': + elif geom_type == "MULTILINESTRING": ogr_type = ogr.wkbMultiLineString - elif geom_type == 'MULTIPOLYGON': + elif geom_type == "MULTIPOLYGON": ogr_type = ogr.wkbMultiPolygon - elif geom_type == 'GEOMETRYCOLLECTION': + elif geom_type == "GEOMETRYCOLLECTION": ogr_type = ogr.wkbGeometryCollection if dim == 3: ogr_type = ogr_type | ogr.wkb25DBit elif dim == 4: - if hasattr(ogr, 'GT_HasZ'): + if hasattr(ogr, "GT_HasZ"): ogr_type = ogr.GT_SetZ(ogr_type) else: ogr_type = ogr_type | ogr.wkb25DBit - if hasattr(ogr, 'GT_HasM'): + if hasattr(ogr, "GT_HasM"): ogr_type = ogr.GT_SetM(ogr_type) geom_field_defn = ogr.GeomFieldDefn(self.unquoteId(geom_column), ogr_type) @@ -762,23 +830,26 @@ def deleteGeometryColumn(self, table, geom_column): return False # not supported def addTableUniqueConstraint(self, table, column): - """Adds a unique constraint to a table """ + """Adds a unique constraint to a table""" return False # constraints not supported def deleteTableConstraint(self, table, constraint): - """Deletes constraint in a table """ + """Deletes constraint in a table""" return False # constraints not supported def addTablePrimaryKey(self, table, column): - """Adds a primery key (with one column) to a table """ - sql = "ALTER TABLE %s ADD PRIMARY KEY (%s)" % (self.quoteId(table), self.quoteId(column)) + """Adds a primery key (with one column) to a table""" + sql = "ALTER TABLE {} ADD PRIMARY KEY ({})".format( + self.quoteId(table), self.quoteId(column) + ) self._execute_and_commit(sql) def createTableIndex(self, table, name, column, unique=False): - """Creates index on one column using default options """ + """Creates index on one column using default options""" unique_str = "UNIQUE" if unique else "" - sql = "CREATE %s INDEX %s ON %s (%s)" % ( - unique_str, self.quoteId(name), self.quoteId(table), self.quoteId(column)) + sql = "CREATE {} INDEX {} ON {} ({})".format( + unique_str, self.quoteId(name), self.quoteId(table), self.quoteId(column) + ) self._execute_and_commit(sql) def deleteTableIndex(self, table, name): @@ -790,8 +861,9 @@ def createSpatialIndex(self, table, geom_column): if self.isRasterTable(table): return False _, tablename = self.getSchemaTableName(table) - sql = "SELECT CreateSpatialIndex(%s, %s)" % ( - self.quoteId(tablename), self.quoteId(geom_column)) + sql = "SELECT CreateSpatialIndex({}, {})".format( + self.quoteId(tablename), self.quoteId(geom_column) + ) try: res = self._fetchOne(sql) except QgsProviderConnectionException: @@ -802,8 +874,9 @@ def deleteSpatialIndex(self, table, geom_column): if self.isRasterTable(table): return False _, tablename = self.getSchemaTableName(table) - sql = "SELECT DisableSpatialIndex(%s, %s)" % ( - self.quoteId(tablename), self.quoteId(geom_column)) + sql = "SELECT DisableSpatialIndex({}, {})".format( + self.quoteId(tablename), self.quoteId(geom_column) + ) res = self._fetchOne(sql) return len(res) > 0 and len(res[0]) > 0 and res[0][0] == 1 @@ -813,14 +886,19 @@ def hasSpatialIndex(self, table, geom_column): _, tablename = self.getSchemaTableName(table) # (only available in >= 2.1.2) - sql = "SELECT HasSpatialIndex(%s, %s)" % (self.quoteString(tablename), self.quoteString(geom_column)) + sql = "SELECT HasSpatialIndex({}, {})".format( + self.quoteString(tablename), self.quoteString(geom_column) + ) gdal.PushErrorHandler() ret = self._fetchOne(sql) gdal.PopErrorHandler() if len(ret) == 0: # might be the case for GDAL < 2.1.2 - sql = "SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name LIKE %s" % self.quoteString("%%rtree_" + tablename + "_%%") + sql = ( + "SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name LIKE %s" + % self.quoteString("%%rtree_" + tablename + "_%%") + ) ret = self._fetchOne(sql) if len(ret) == 0: return False diff --git a/python/plugins/db_manager/db_plugins/gpkg/data_model.py b/python/plugins/db_manager/db_plugins/gpkg/data_model.py index dd692703e927..a1a79a11ec1b 100644 --- a/python/plugins/db_manager/db_plugins/gpkg/data_model.py +++ b/python/plugins/db_manager/db_plugins/gpkg/data_model.py @@ -20,10 +20,12 @@ from qgis.core import QgsMessageLog -from ..data_model import (TableDataModel, - SqlResultModel, - SqlResultModelAsync, - SqlResultModelTask) +from ..data_model import ( + TableDataModel, + SqlResultModel, + SqlResultModelAsync, + SqlResultModelTask, +) from ..plugin import BaseError diff --git a/python/plugins/db_manager/db_plugins/gpkg/info_model.py b/python/plugins/db_manager/db_plugins/gpkg/info_model.py index cd346e5f8237..d0f2c31dca9b 100644 --- a/python/plugins/db_manager/db_plugins/gpkg/info_model.py +++ b/python/plugins/db_manager/db_plugins/gpkg/info_model.py @@ -31,7 +31,10 @@ def __init__(self, db): def connectionDetails(self): tbl = [ - (QApplication.translate("DBManagerPlugin", "Filename:"), self.db.connector.dbname) + ( + QApplication.translate("DBManagerPlugin", "Filename:"), + self.db.connector.dbname, + ) ] return HtmlTable(tbl) diff --git a/python/plugins/db_manager/db_plugins/gpkg/plugin.py b/python/plugins/db_manager/db_plugins/gpkg/plugin.py index d6f63e8b3579..7fd5ee9ad904 100644 --- a/python/plugins/db_manager/db_plugins/gpkg/plugin.py +++ b/python/plugins/db_manager/db_plugins/gpkg/plugin.py @@ -33,8 +33,17 @@ ) from qgis.gui import QgsMessageBar -from ..plugin import DBPlugin, Database, Table, VectorTable, RasterTable, TableField, TableIndex, TableTrigger, \ - InvalidDataException +from ..plugin import ( + DBPlugin, + Database, + Table, + VectorTable, + RasterTable, + TableField, + TableIndex, + TableTrigger, + InvalidDataException, +) def classFactory(): @@ -49,19 +58,19 @@ def icon(self): @classmethod def typeName(self): - return 'gpkg' + return "gpkg" @classmethod def typeNameString(self): - return QCoreApplication.translate('db_manager', 'GeoPackage') + return QCoreApplication.translate("db_manager", "GeoPackage") @classmethod def providerName(self): - return 'ogr' + return "ogr" @classmethod def connectionSettingsKey(self): - return 'providers/ogr/GPKG/connections' + return "providers/ogr/GPKG/connections" def databasesFactory(self, connection, uri): return GPKGDatabase(connection, uri) @@ -73,7 +82,11 @@ def connect(self, parent=None): conn = md.findConnection(conn_name) if conn is None: # non-existent entry? - raise InvalidDataException(self.tr('There is no defined database connection "{0}".').format(conn_name)) + raise InvalidDataException( + self.tr('There is no defined database connection "{0}".').format( + conn_name + ) + ) uri = QgsDataSourceUri() uri.setDatabase(conn.uri()) @@ -90,8 +103,9 @@ def addConnection(self, conn_name, uri): def addConnectionActionSlot(self, item, action, parent, index): QApplication.restoreOverrideCursor() try: - filename, selected_filter = QFileDialog.getOpenFileName(parent, - parent.tr("Choose GeoPackage file"), None, "GeoPackage (*.gpkg)") + filename, selected_filter = QFileDialog.getOpenFileName( + parent, parent.tr("Choose GeoPackage file"), None, "GeoPackage (*.gpkg)" + ) if not filename: return finally: @@ -138,7 +152,9 @@ def sqlResultModelAsync(self, sql, parent): def registerDatabaseActions(self, mainWindow): action = QAction(self.tr("Run &Vacuum"), self) - mainWindow.registerAction(action, self.tr("&Database"), self.runVacuumActionSlot) + mainWindow.registerAction( + action, self.tr("&Database"), self.runVacuumActionSlot + ) Database.registerDatabaseActions(self, mainWindow) @@ -146,8 +162,11 @@ def runVacuumActionSlot(self, item, action, parent): QApplication.restoreOverrideCursor() try: if not isinstance(item, (DBPlugin, Table)) or item.database() is None: - parent.infoBar.pushMessage(self.tr("No database selected or you are not connected to it."), - Qgis.MessageLevel.Info, parent.iface.messageTimeout()) + parent.infoBar.pushMessage( + self.tr("No database selected or you are not connected to it."), + Qgis.MessageLevel.Info, + parent.iface.messageTimeout(), + ) return finally: QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) @@ -172,10 +191,19 @@ def runAction(self, action): def uniqueIdFunction(self): return None - def toSqlLayer(self, sql, geomCol, uniqueCol, layerName="QueryLayer", layerType=None, avoidSelectById=False, filter=""): + def toSqlLayer( + self, + sql, + geomCol, + uniqueCol, + layerName="QueryLayer", + layerType=None, + avoidSelectById=False, + filter="", + ): from qgis.core import QgsVectorLayer - vl = QgsVectorLayer(self.uri().database() + '|subset=' + sql, layerName, 'ogr') + vl = QgsVectorLayer(self.uri().database() + "|subset=" + sql, layerName, "ogr") return vl def supportsComment(self): @@ -199,12 +227,12 @@ def __init__(self, row, db, schema=None): self.name, self.isView, self.isSysTable = row def ogrUri(self): - ogrUri = "%s|layername=%s" % (self.uri().database(), self.name) + ogrUri = f"{self.uri().database()}|layername={self.name}" return ogrUri def mimeUri(self): # QGIS has no provider to load Geopackage vectors, let's use OGR - return "vector:ogr:%s:%s" % (self.name, self.ogrUri()) + return f"vector:ogr:{self.name}:{self.ogrUri()}" def toMapLayer(self, geometryType=None, crs=None): from qgis.core import QgsVectorLayer @@ -214,12 +242,12 @@ def toMapLayer(self, geometryType=None, crs=None): if geometryType: geom_mapping = { - 'POINT': 'Point', - 'LINESTRING': 'LineString', - 'POLYGON': 'Polygon', + "POINT": "Point", + "LINESTRING": "LineString", + "POLYGON": "Polygon", } geometryType = geom_mapping[geometryType] - uri = "{}|geometrytype={}".format(uri, geometryType) + uri = f"{uri}|geometrytype={geometryType}" return QgsVectorLayer(uri, self.name, provider) @@ -246,17 +274,23 @@ def __init__(self, row, db, schema=None): # GPKG does case-insensitive checks for table names, but the # GPKG provider didn't do the same in QGIS < 1.9, so self.geomTableName # stores the table name like stored in the geometry_columns table - self.geomTableName, self.geomColumn, self.geomType, self.geomDim, self.srid = row[-5:] - self.extent = self.database().connector.getTableExtent((self.schemaName(), self.name), self.geomColumn, force=False) + self.geomTableName, self.geomColumn, self.geomType, self.geomDim, self.srid = ( + row[-5:] + ) + self.extent = self.database().connector.getTableExtent( + (self.schemaName(), self.name), self.geomColumn, force=False + ) def uri(self): uri = self.database().uri() - uri.setDataSource('', self.geomTableName, self.geomColumn) + uri.setDataSource("", self.geomTableName, self.geomColumn) return uri def hasSpatialIndex(self, geom_column=None): geom_column = geom_column if geom_column is not None else self.geomColumn - return self.database().connector.hasSpatialIndex((self.schemaName(), self.name), geom_column) + return self.database().connector.hasSpatialIndex( + (self.schemaName(), self.name), geom_column + ) def createSpatialIndex(self, geom_column=None): self.aboutToChange.emit() @@ -277,7 +311,9 @@ def refreshTableEstimatedExtent(self): def refreshTableExtent(self): prevExtent = self.extent - self.extent = self.database().connector.getTableExtent((self.schemaName(), self.name), self.geomColumn, force=True) + self.extent = self.database().connector.getTableExtent( + (self.schemaName(), self.name), self.geomColumn, force=True + ) if self.extent != prevExtent: self.refresh() @@ -293,16 +329,18 @@ def __init__(self, row, db, schema=None): GPKGTable.__init__(self, row[:-3], db, schema) RasterTable.__init__(self, db, schema) self.prefixName, self.geomColumn, self.srid = row[-3:] - self.geomType = 'RASTER' - self.extent = self.database().connector.getTableExtent((self.schemaName(), self.name), self.geomColumn) + self.geomType = "RASTER" + self.extent = self.database().connector.getTableExtent( + (self.schemaName(), self.name), self.geomColumn + ) def gpkgGdalUri(self): - gdalUri = 'GPKG:%s:%s' % (self.uri().database(), self.prefixName) + gdalUri = f"GPKG:{self.uri().database()}:{self.prefixName}" return gdalUri def mimeUri(self): # QGIS has no provider to load rasters, let's use GDAL - uri = "raster:gdal:%s:%s" % (self.name, self.uri().database()) + uri = f"raster:gdal:{self.name}:{self.uri().database()}" return uri def toMapLayer(self, geometryType=None, crs=None): @@ -312,7 +350,9 @@ def toMapLayer(self, geometryType=None, crs=None): uri = self.gpkgGdalUri() rl = QgsRasterLayer(uri, self.name) if rl.isValid(): - rl.setContrastEnhancement(QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum) + rl.setContrastEnhancement( + QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum + ) return rl @@ -320,7 +360,14 @@ class GPKGTableField(TableField): def __init__(self, row, table): TableField.__init__(self, table) - self.num, self.name, self.dataType, self.notNull, self.default, self.primaryKey = row + ( + self.num, + self.name, + self.dataType, + self.notNull, + self.default, + self.primaryKey, + ) = row self.hasDefault = self.default diff --git a/python/plugins/db_manager/db_plugins/gpkg/sql_dictionary.py b/python/plugins/db_manager/db_plugins/gpkg/sql_dictionary.py index 514c804bb494..439a4645f1ed 100644 --- a/python/plugins/db_manager/db_plugins/gpkg/sql_dictionary.py +++ b/python/plugins/db_manager/db_plugins/gpkg/sql_dictionary.py @@ -18,9 +18,11 @@ def getSqlDictionary(spatial=True): from ..spatialite.sql_dictionary import getSqlDictionary + return getSqlDictionary(spatial) def getQueryBuilderDictionary(): from ..spatialite.sql_dictionary import getQueryBuilderDictionary + return getQueryBuilderDictionary() diff --git a/python/plugins/db_manager/db_plugins/html_elems.py b/python/plugins/db_manager/db_plugins/html_elems.py index 96b47f4c301e..69ab9fc6c91b 100644 --- a/python/plugins/db_manager/db_plugins/html_elems.py +++ b/python/plugins/db_manager/db_plugins/html_elems.py @@ -26,12 +26,12 @@ def __init__(self, data): def toHtml(self): if isinstance(self.data, list) or isinstance(self.data, tuple): - html = '' + html = "" for item in self.data: html += HtmlContent(item).toHtml() return html - if hasattr(self.data, 'toHtml'): + if hasattr(self.data, "toHtml"): return self.data.toHtml() html = str(self.data).replace("\n", "
") @@ -46,7 +46,7 @@ def hasContents(self): break return not empty - if hasattr(self.data, 'hasContents'): + if hasattr(self.data, "hasContents"): return self.data.hasContents() return len(self.data) > 0 @@ -58,9 +58,9 @@ def __init__(self, tag, data, attrs=None): self.tag = tag self.data = data if isinstance(data, HtmlContent) else HtmlContent(data) self.attrs = attrs if attrs is not None else dict() - if 'tag' in self.attrs: - self.setTag(self.attrs['tag']) - del self.attrs['tag'] + if "tag" in self.attrs: + self.setTag(self.attrs["tag"]) + del self.attrs["tag"] def setTag(self, tag): self.tag = tag @@ -72,19 +72,21 @@ def setAttr(self, name, value): self.attrs[name] = value def getAttrsHtml(self): - html = '' + html = "" for k, v in self.attrs.items(): - html += ' %s="%s"' % (k, v) + html += f' {k}="{v}"' return html def openTagHtml(self): - return "<%s%s>" % (self.tag, self.getAttrsHtml()) + return f"<{self.tag}{self.getAttrsHtml()}>" def closeTagHtml(self): return "" % self.tag def toHtml(self): - return "%s%s%s" % (self.openTagHtml(), self.data.toHtml(), self.closeTagHtml()) + return "{}{}{}".format( + self.openTagHtml(), self.data.toHtml(), self.closeTagHtml() + ) def hasContents(self): return self.data.toHtml() != "" @@ -93,13 +95,13 @@ def hasContents(self): class HtmlParagraph(HtmlElem): def __init__(self, data, attrs=None): - HtmlElem.__init__(self, 'p', data, attrs) + HtmlElem.__init__(self, "p", data, attrs) class HtmlListItem(HtmlElem): def __init__(self, data, attrs=None): - HtmlElem.__init__(self, 'li', data, attrs) + HtmlElem.__init__(self, "li", data, attrs) class HtmlList(HtmlElem): @@ -110,13 +112,13 @@ def __init__(self, items, attrs=None): for i, item in enumerate(items): if not isinstance(item, HtmlListItem): items[i] = HtmlListItem(item) - HtmlElem.__init__(self, 'ul', items, attrs) + HtmlElem.__init__(self, "ul", items, attrs) class HtmlTableCol(HtmlElem): def __init__(self, data, attrs=None): - HtmlElem.__init__(self, 'td', data, attrs) + HtmlElem.__init__(self, "td", data, attrs) def closeTagHtml(self): # FIX INVALID BEHAVIOR: an empty cell as last table's cell break margins @@ -131,7 +133,7 @@ def __init__(self, cols, attrs=None): for i, c in enumerate(cols): if not isinstance(c, HtmlTableCol): cols[i] = HtmlTableCol(c) - HtmlElem.__init__(self, 'tr', cols, attrs) + HtmlElem.__init__(self, "tr", cols, attrs) class HtmlTableHeader(HtmlTableRow): @@ -139,7 +141,7 @@ class HtmlTableHeader(HtmlTableRow): def __init__(self, cols, attrs=None): HtmlTableRow.__init__(self, cols, attrs) for c in self.getOriginalData(): - c.setTag('th') + c.setTag("th") class HtmlTable(HtmlElem): @@ -150,14 +152,14 @@ def __init__(self, rows, attrs=None): for i, r in enumerate(rows): if not isinstance(r, HtmlTableRow): rows[i] = HtmlTableRow(r) - HtmlElem.__init__(self, 'table', rows, attrs) + HtmlElem.__init__(self, "table", rows, attrs) class HtmlSection(HtmlContent): def __init__(self, title, content=None): - data = ['

', title, '

'] + data = ['

', title, "

"] if content is not None: - data.extend(['
', content, '
']) - data.append('
') + data.extend(["
", content, "
"]) + data.append("
") HtmlContent.__init__(self, data) diff --git a/python/plugins/db_manager/db_plugins/info_model.py b/python/plugins/db_manager/db_plugins/info_model.py index c27d77b521b3..cf3af0c1753a 100644 --- a/python/plugins/db_manager/db_plugins/info_model.py +++ b/python/plugins/db_manager/db_plugins/info_model.py @@ -20,7 +20,15 @@ from qgis.PyQt.QtWidgets import QApplication -from .html_elems import HtmlContent, HtmlSection, HtmlParagraph, HtmlList, HtmlTable, HtmlTableHeader, HtmlTableCol +from .html_elems import ( + HtmlContent, + HtmlSection, + HtmlParagraph, + HtmlList, + HtmlTable, + HtmlTableHeader, + HtmlTableCol, +) class DatabaseInfo: @@ -33,15 +41,19 @@ def __del__(self): def generalInfo(self): info = self.db.connector.getInfo() - tbl = [ - (QApplication.translate("DBManagerPlugin", "Server version: "), info[0]) - ] + tbl = [(QApplication.translate("DBManagerPlugin", "Server version: "), info[0])] return HtmlTable(tbl) def connectionDetails(self): tbl = [ - (QApplication.translate("DBManagerPlugin", "Host:"), self.db.connector.host), - (QApplication.translate("DBManagerPlugin", "User:"), self.db.connector.user) + ( + QApplication.translate("DBManagerPlugin", "Host:"), + self.db.connector.host, + ), + ( + QApplication.translate("DBManagerPlugin", "User:"), + self.db.connector.user, + ), ] return HtmlTable(tbl) @@ -55,14 +67,20 @@ def spatialInfo(self): tbl = [ (QApplication.translate("DBManagerPlugin", "Library:"), info[0]), ("GEOS:", info[1]), - ("Proj:", info[2]) + ("Proj:", info[2]), ] ret.append(HtmlTable(tbl)) if not self.db.connector.has_geometry_columns: - ret.append(HtmlParagraph( - QApplication.translate("DBManagerPlugin", " geometry_columns table doesn't exist!\n" - "This table is essential for many GIS applications for enumeration of tables."))) + ret.append( + HtmlParagraph( + QApplication.translate( + "DBManagerPlugin", + " geometry_columns table doesn't exist!\n" + "This table is essential for many GIS applications for enumeration of tables.", + ) + ) + ) return ret @@ -72,12 +90,16 @@ def privilegesDetails(self): if details[0]: lst.append(QApplication.translate("DBManagerPlugin", "create new schemas")) if details[1]: - lst.append(QApplication.translate("DBManagerPlugin", "create temporary tables")) + lst.append( + QApplication.translate("DBManagerPlugin", "create temporary tables") + ) return HtmlList(lst) def toHtml(self): if self.db is None: - return HtmlSection(QApplication.translate("DBManagerPlugin", ' Not connected')).toHtml() + return HtmlSection( + QApplication.translate("DBManagerPlugin", " Not connected") + ).toHtml() ret = [] @@ -86,14 +108,24 @@ def toHtml(self): if conn_details is None: pass else: - ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'Connection details'), conn_details)) + ret.append( + HtmlSection( + QApplication.translate("DBManagerPlugin", "Connection details"), + conn_details, + ) + ) # database information general_info = self.generalInfo() if general_info is None: pass else: - ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'General info'), general_info)) + ret.append( + HtmlSection( + QApplication.translate("DBManagerPlugin", "General info"), + general_info, + ) + ) # has spatial enabled? spatial_info = self.spatialInfo() @@ -103,7 +135,9 @@ def toHtml(self): typename = self.db.connection().typeNameString() spatial_info = HtmlContent(spatial_info) if not spatial_info.hasContents(): - spatial_info = QApplication.translate("DBManagerPlugin", ' {0} support not enabled!').format(typename) + spatial_info = QApplication.translate( + "DBManagerPlugin", " {0} support not enabled!" + ).format(typename) ret.append(HtmlSection(typename, spatial_info)) # privileges @@ -113,10 +147,20 @@ def toHtml(self): else: priv_details = HtmlContent(priv_details) if not priv_details.hasContents(): - priv_details = QApplication.translate("DBManagerPlugin", ' This user has no privileges!') + priv_details = QApplication.translate( + "DBManagerPlugin", " This user has no privileges!" + ) else: - priv_details = [QApplication.translate("DBManagerPlugin", "User has privileges:"), priv_details] - ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'Privileges'), priv_details)) + priv_details = [ + QApplication.translate("DBManagerPlugin", "User has privileges:"), + priv_details, + ] + ret.append( + HtmlSection( + QApplication.translate("DBManagerPlugin", "Privileges"), + priv_details, + ) + ) return HtmlContent(ret).toHtml() @@ -134,9 +178,16 @@ def generalInfo(self): # ("Tables:", self.schema.tableCount) ] if self.schema.owner: - tbl.append((QApplication.translate("DBManagerPlugin", "Owner:"), self.schema.owner)) + tbl.append( + (QApplication.translate("DBManagerPlugin", "Owner:"), self.schema.owner) + ) if self.schema.comment: - tbl.append((QApplication.translate("DBManagerPlugin", "Comment:"), self.schema.comment)) + tbl.append( + ( + QApplication.translate("DBManagerPlugin", "Comment:"), + self.schema.comment, + ) + ) return HtmlTable(tbl) def privilegesDetails(self): @@ -155,7 +206,12 @@ def toHtml(self): if general_info is None: pass else: - ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'Schema details'), general_info)) + ret.append( + HtmlSection( + QApplication.translate("DBManagerPlugin", "Schema details"), + general_info, + ) + ) priv_details = self.privilegesDetails() if priv_details is None: @@ -163,11 +219,21 @@ def toHtml(self): else: priv_details = HtmlContent(priv_details) if not priv_details.hasContents(): - priv_details = QApplication.translate("DBManagerPlugin", - ' This user has no privileges to access this schema!') + priv_details = QApplication.translate( + "DBManagerPlugin", + " This user has no privileges to access this schema!", + ) else: - priv_details = [QApplication.translate("DBManagerPlugin", "User has privileges:"), priv_details] - ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'Privileges'), priv_details)) + priv_details = [ + QApplication.translate("DBManagerPlugin", "User has privileges:"), + priv_details, + ] + ret.append( + HtmlSection( + QApplication.translate("DBManagerPlugin", "Privileges"), + priv_details, + ) + ) return HtmlContent(ret).toHtml() @@ -189,15 +255,33 @@ def generalInfo(self): self.table.blockSignals(False) tbl = [ - (QApplication.translate("DBManagerPlugin", "Relation type:"), - QApplication.translate("DBManagerPlugin", "View") if self.table.isView else QApplication.translate( - "DBManagerPlugin", "Table")), - (QApplication.translate("DBManagerPlugin", "Rows:"), - self.table.rowCount if self.table.rowCount is not None else QApplication.translate("DBManagerPlugin", - 'Unknown (find out)')) + ( + QApplication.translate("DBManagerPlugin", "Relation type:"), + ( + QApplication.translate("DBManagerPlugin", "View") + if self.table.isView + else QApplication.translate("DBManagerPlugin", "Table") + ), + ), + ( + QApplication.translate("DBManagerPlugin", "Rows:"), + ( + self.table.rowCount + if self.table.rowCount is not None + else QApplication.translate( + "DBManagerPlugin", + 'Unknown (find out)', + ) + ), + ), ] if self.table.comment: - tbl.append((QApplication.translate("DBManagerPlugin", "Comment:"), self.table.comment)) + tbl.append( + ( + QApplication.translate("DBManagerPlugin", "Comment:"), + self.table.comment, + ) + ) return HtmlTable(tbl) @@ -209,8 +293,12 @@ def fieldsDetails(self): # define the table header header = ( - "#", QApplication.translate("DBManagerPlugin", "Name"), QApplication.translate("DBManagerPlugin", "Type"), - QApplication.translate("DBManagerPlugin", "Null"), QApplication.translate("DBManagerPlugin", "Default")) + "#", + QApplication.translate("DBManagerPlugin", "Name"), + QApplication.translate("DBManagerPlugin", "Type"), + QApplication.translate("DBManagerPlugin", "Null"), + QApplication.translate("DBManagerPlugin", "Default"), + ) tbl.append(HtmlTableHeader(header)) # add table contents @@ -221,7 +309,9 @@ def fieldsDetails(self): attrs = {"class": "underline"} if fld.primaryKey else None name = HtmlTableCol(fld.name, attrs) - tbl.append((fld.num, name, fld.type2String(), is_null_txt, fld.default2String())) + tbl.append( + (fld.num, name, fld.type2String(), is_null_txt, fld.default2String()) + ) return HtmlTable(tbl, {"class": "header"}) @@ -232,15 +322,21 @@ def constraintsDetails(self): tbl = [] # define the table header - header = (QApplication.translate("DBManagerPlugin", "Name"), QApplication.translate("DBManagerPlugin", "Type"), - QApplication.translate("DBManagerPlugin", "Column(s)")) + header = ( + QApplication.translate("DBManagerPlugin", "Name"), + QApplication.translate("DBManagerPlugin", "Type"), + QApplication.translate("DBManagerPlugin", "Column(s)"), + ) tbl.append(HtmlTableHeader(header)) # add table contents for con in self.table.constraints(): # get the fields the constraint is defined on - cols = [p[1].name if p[1] is not None else "??? (#%d)" % p[0] for p in iter(list(con.fields().items()))] - tbl.append((con.name, con.type2String(), '\n'.join(cols))) + cols = [ + p[1].name if p[1] is not None else "??? (#%d)" % p[0] + for p in iter(list(con.fields().items())) + ] + tbl.append((con.name, con.type2String(), "\n".join(cols))) return HtmlTable(tbl, {"class": "header"}) @@ -252,14 +348,19 @@ def indexesDetails(self): # define the table header header = ( - QApplication.translate("DBManagerPlugin", "Name"), QApplication.translate("DBManagerPlugin", "Column(s)")) + QApplication.translate("DBManagerPlugin", "Name"), + QApplication.translate("DBManagerPlugin", "Column(s)"), + ) tbl.append(HtmlTableHeader(header)) # add table contents for idx in self.table.indexes(): # get the fields the index is defined on - cols = [p[1].name if p[1] is not None else "??? (#%d)" % p[0] for p in iter(list(idx.fields().items()))] - tbl.append((idx.name, '\n'.join(cols))) + cols = [ + p[1].name if p[1] is not None else "??? (#%d)" % p[0] + for p in iter(list(idx.fields().items())) + ] + tbl.append((idx.name, "\n".join(cols))) return HtmlTable(tbl, {"class": "header"}) @@ -271,21 +372,28 @@ def triggersDetails(self): # define the table header header = ( - QApplication.translate("DBManagerPlugin", "Name"), QApplication.translate("DBManagerPlugin", "Function")) + QApplication.translate("DBManagerPlugin", "Name"), + QApplication.translate("DBManagerPlugin", "Function"), + ) tbl.append(HtmlTableHeader(header)) # add table contents for trig in self.table.triggers(): - name = '%(name)s (%(action)s)' % {"name": trig.name, - "action": "delete"} - tbl.append((name, trig.function.replace('<', '<'))) + name = ( + '{name} ({action})'.format( + name=trig.name, action="delete" + ) + ) + tbl.append((name, trig.function.replace("<", "<"))) return HtmlTable(tbl, {"class": "header"}) def getViewDefinition(self): if not self.table.isView: return None - return self.table.database().connector.getViewDefinition((self.table.schemaName(), self.table.name)) + return self.table.database().connector.getViewDefinition( + (self.table.schemaName(), self.table.name) + ) def getTableInfo(self): ret = [] @@ -294,7 +402,12 @@ def getTableInfo(self): if general_info is None: pass else: - ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'General info'), general_info)) + ret.append( + HtmlSection( + QApplication.translate("DBManagerPlugin", "General info"), + general_info, + ) + ) # spatial info spatial_info = self.spatialInfo() @@ -303,36 +416,61 @@ def getTableInfo(self): else: spatial_info = HtmlContent(spatial_info) if not spatial_info.hasContents(): - spatial_info = QApplication.translate("DBManagerPlugin", ' This is not a spatial table.') - ret.append(HtmlSection(self.table.database().connection().typeNameString(), spatial_info)) + spatial_info = QApplication.translate( + "DBManagerPlugin", " This is not a spatial table." + ) + ret.append( + HtmlSection( + self.table.database().connection().typeNameString(), spatial_info + ) + ) # fields fields_details = self.fieldsDetails() if fields_details is None: pass else: - ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'Fields'), fields_details)) + ret.append( + HtmlSection( + QApplication.translate("DBManagerPlugin", "Fields"), fields_details + ) + ) # constraints constraints_details = self.constraintsDetails() if constraints_details is None: pass else: - ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'Constraints'), constraints_details)) + ret.append( + HtmlSection( + QApplication.translate("DBManagerPlugin", "Constraints"), + constraints_details, + ) + ) # indexes indexes_details = self.indexesDetails() if indexes_details is None: pass else: - ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'Indexes'), indexes_details)) + ret.append( + HtmlSection( + QApplication.translate("DBManagerPlugin", "Indexes"), + indexes_details, + ) + ) # triggers triggers_details = self.triggersDetails() if triggers_details is None: pass else: - ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'Triggers'), triggers_details)) + ret.append( + HtmlSection( + QApplication.translate("DBManagerPlugin", "Triggers"), + triggers_details, + ) + ) return ret @@ -347,7 +485,12 @@ def getViewInfo(self): if view_def is None: pass else: - ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'View definition'), view_def)) + ret.append( + HtmlSection( + QApplication.translate("DBManagerPlugin", "View definition"), + view_def, + ) + ) return ret @@ -370,19 +513,38 @@ def spatialInfo(self): return ret tbl = [ - (QApplication.translate("DBManagerPlugin", "Column:"), self.table.geomColumn), - (QApplication.translate("DBManagerPlugin", "Geometry:"), self.table.geomType) + ( + QApplication.translate("DBManagerPlugin", "Column:"), + self.table.geomColumn, + ), + ( + QApplication.translate("DBManagerPlugin", "Geometry:"), + self.table.geomType, + ), ] # only if we have info from geometry_columns if self.table.geomDim: - tbl.append((QApplication.translate("DBManagerPlugin", "Dimension:"), self.table.geomDim)) + tbl.append( + ( + QApplication.translate("DBManagerPlugin", "Dimension:"), + self.table.geomDim, + ) + ) srid = self.table.srid if self.table.srid not in (None, 0) else -1 - sr_info = self.table.database().connector.getSpatialRefInfo(srid) if srid != -1 else QApplication.translate( - "DBManagerPlugin", "Undefined") + sr_info = ( + self.table.database().connector.getSpatialRefInfo(srid) + if srid != -1 + else QApplication.translate("DBManagerPlugin", "Undefined") + ) if sr_info: - tbl.append((QApplication.translate("DBManagerPlugin", "Spatial ref:"), "%s (%d)" % (sr_info, srid))) + tbl.append( + ( + QApplication.translate("DBManagerPlugin", "Spatial ref:"), + "%s (%d)" % (sr_info, srid), + ) + ) # estimated extent if not self.table.isView: @@ -393,36 +555,62 @@ def spatialInfo(self): self.table.refreshTableEstimatedExtent() self.table.blockSignals(False) - if self.table.estimatedExtent is not None and self.table.estimatedExtent[0] is not None: + if ( + self.table.estimatedExtent is not None + and self.table.estimatedExtent[0] is not None + ): if isinstance(self.table.estimatedExtent, list): - estimated_extent_str = ', '.join('%.5f' % e for e in self.table.estimatedExtent) + estimated_extent_str = ", ".join( + "%.5f" % e for e in self.table.estimatedExtent + ) else: - estimated_extent_str = '%.5f, %.5f - %.5f, %.5f' % self.table.estimatedExtent - tbl.append((QApplication.translate("DBManagerPlugin", "Estimated extent:"), estimated_extent_str)) + estimated_extent_str = ( + "%.5f, %.5f - %.5f, %.5f" % self.table.estimatedExtent + ) + tbl.append( + ( + QApplication.translate("DBManagerPlugin", "Estimated extent:"), + estimated_extent_str, + ) + ) # extent if self.table.extent is not None and self.table.extent[0] is not None: if isinstance(self.table.extent, list): - extent_str = ', '.join('%.5f' % e for e in self.table.extent) + extent_str = ", ".join("%.5f" % e for e in self.table.extent) else: - extent_str = '%.5f, %.5f - %.5f, %.5f' % self.table.extent + extent_str = "%.5f, %.5f - %.5f, %.5f" % self.table.extent else: - extent_str = QApplication.translate("DBManagerPlugin", - '(unknown) (find out)') + extent_str = QApplication.translate( + "DBManagerPlugin", + '(unknown) (find out)', + ) tbl.append((QApplication.translate("DBManagerPlugin", "Extent:"), extent_str)) ret.append(HtmlTable(tbl)) # is there an entry in geometry_columns? - if self.table.geomType.lower() == 'geometry': - ret.append(HtmlParagraph( - QApplication.translate("DBManagerPlugin", " There is no entry in geometry_columns!"))) + if self.table.geomType.lower() == "geometry": + ret.append( + HtmlParagraph( + QApplication.translate( + "DBManagerPlugin", + " There is no entry in geometry_columns!", + ) + ) + ) # find out whether the geometry column has spatial index on it if not self.table.isView: if not self.table.hasSpatialIndex(): - ret.append(HtmlParagraph(QApplication.translate("DBManagerPlugin", - ' No spatial index defined (create it)'))) + ret.append( + HtmlParagraph( + QApplication.translate( + "DBManagerPlugin", + ' No spatial index defined (create it)', + ) + ) + ) return ret @@ -438,23 +626,39 @@ def spatialInfo(self): return ret tbl = [ - (QApplication.translate("DBManagerPlugin", "Column:"), self.table.geomColumn), - (QApplication.translate("DBManagerPlugin", "Geometry:"), self.table.geomType) + ( + QApplication.translate("DBManagerPlugin", "Column:"), + self.table.geomColumn, + ), + ( + QApplication.translate("DBManagerPlugin", "Geometry:"), + self.table.geomType, + ), ] # only if we have info from geometry_columns srid = self.table.srid if self.table.srid is not None else -1 - sr_info = self.table.database().connector.getSpatialRefInfo(srid) if srid != -1 else QApplication.translate( - "DBManagerPlugin", "Undefined") + sr_info = ( + self.table.database().connector.getSpatialRefInfo(srid) + if srid != -1 + else QApplication.translate("DBManagerPlugin", "Undefined") + ) if sr_info: - tbl.append((QApplication.translate("DBManagerPlugin", "Spatial ref:"), "%s (%d)" % (sr_info, srid))) + tbl.append( + ( + QApplication.translate("DBManagerPlugin", "Spatial ref:"), + "%s (%d)" % (sr_info, srid), + ) + ) # extent if self.table.extent is not None and self.table.extent[0] is not None: - extent_str = '%.5f, %.5f - %.5f, %.5f' % self.table.extent + extent_str = "%.5f, %.5f - %.5f, %.5f" % self.table.extent else: - extent_str = QApplication.translate("DBManagerPlugin", - '(unknown) (find out)') + extent_str = QApplication.translate( + "DBManagerPlugin", + '(unknown) (find out)', + ) tbl.append((QApplication.translate("DBManagerPlugin", "Extent:"), extent_str)) ret.append(HtmlTable(tbl)) diff --git a/python/plugins/db_manager/db_plugins/oracle/QtSqlDB.py b/python/plugins/db_manager/db_plugins/oracle/QtSqlDB.py index 9e37ce98946c..0f96119e3751 100644 --- a/python/plugins/db_manager/db_plugins/oracle/QtSqlDB.py +++ b/python/plugins/db_manager/db_plugins/oracle/QtSqlDB.py @@ -112,15 +112,17 @@ def execute(self, operation, parameters=[]): else: continue - self.description.append([ - f.name(), # name - t, # type_code - f.length(), # display_size - f.length(), # internal_size - f.precision(), # precision - None, # scale - f.requiredStatus() != QSqlField.RequiredStatus.Required # null_ok - ]) + self.description.append( + [ + f.name(), # name + t, # type_code + f.length(), # display_size + f.length(), # internal_size + f.precision(), # precision + None, # scale + f.requiredStatus() != QSqlField.RequiredStatus.Required, # null_ok + ] + ) def executemany(self, operation, seq_of_parameters): if len(seq_of_parameters) == 0: @@ -146,9 +148,11 @@ def fetchone(self): row = [] for i in range(len(self.description)): value = self.qry.value(i) - if (isinstance(value, QDate) or - isinstance(value, QTime) or - isinstance(value, QDateTime)): + if ( + isinstance(value, QDate) + or isinstance(value, QTime) + or isinstance(value, QDateTime) + ): value = value.toString() elif isinstance(value, QByteArray): value = "GEOMETRY" @@ -190,7 +194,8 @@ class QtSqlDBConnection: def __init__(self, driver, dbname, user, passwd): self.conn = QSqlDatabase.addDatabase( - driver, "qtsql_%d" % QtSqlDBConnection.connections) + driver, "qtsql_%d" % QtSqlDBConnection.connections + ) QtSqlDBConnection.connections += 1 self.conn.setDatabaseName(dbname) self.conn.setUserName(user) diff --git a/python/plugins/db_manager/db_plugins/oracle/connector.py b/python/plugins/db_manager/db_plugins/oracle/connector.py index 0055fac61ef5..ba2c61e31176 100644 --- a/python/plugins/db_manager/db_plugins/oracle/connector.py +++ b/python/plugins/db_manager/db_plugins/oracle/connector.py @@ -54,14 +54,14 @@ class OracleDBConnector(DBConnector): 3003: QgsWkbTypes.Type.Polygon25D, 3005: QgsWkbTypes.Type.MultiPoint25D, 3006: QgsWkbTypes.Type.MultiLineString25D, - 3007: QgsWkbTypes.Type.MultiPolygon25D + 3007: QgsWkbTypes.Type.MultiPolygon25D, } def __init__(self, uri, connName): DBConnector.__init__(self, uri) self.connName = connName - self.user = uri.username() or os.environ.get('USER') + self.user = uri.username() or os.environ.get("USER") self.passwd = uri.password() self.host = uri.host() @@ -76,29 +76,29 @@ def __init__(self, uri, connName): # Connection options self.useEstimatedMetadata = uri.useEstimatedMetadata() - self.userTablesOnly = uri.param('userTablesOnly').lower() == "true" - self.geometryColumnsOnly = uri.param( - 'geometryColumnsOnly').lower() == "true" - self.allowGeometrylessTables = uri.param( - 'allowGeometrylessTables').lower() == "true" - self.onlyExistingTypes = uri.param( - 'onlyExistingTypes').lower() == "true" - self.includeGeoAttributes = uri.param( - 'includeGeoAttributes').lower() == "true" + self.userTablesOnly = uri.param("userTablesOnly").lower() == "true" + self.geometryColumnsOnly = uri.param("geometryColumnsOnly").lower() == "true" + self.allowGeometrylessTables = ( + uri.param("allowGeometrylessTables").lower() == "true" + ) + self.onlyExistingTypes = uri.param("onlyExistingTypes").lower() == "true" + self.includeGeoAttributes = uri.param("includeGeoAttributes").lower() == "true" # For refreshing self.populated = False try: self.connection = QtSqlDB.connect( - "QOCISPATIAL", self.dbname, self.user, self.passwd) + "QOCISPATIAL", self.dbname, self.user, self.passwd + ) except self.connection_error_types() as e: raise ConnectionError(e) # Find if we can connect to data_sources_cache.db sqlite_cache_file = os.path.join( - QgsApplication.qgisSettingsDirPath(), "data_sources_cache.db") - if (os.path.isfile(sqlite_cache_file)): + QgsApplication.qgisSettingsDirPath(), "data_sources_cache.db" + ) + if os.path.isfile(sqlite_cache_file): try: self.cache_connection = sqlite3.connect(sqlite_cache_file) except sqlite3.Error: @@ -110,8 +110,9 @@ def __init__(self, uri, connName): if self.cache_connection: try: cache_c = self.cache_connection.cursor() - query = ("SELECT COUNT(*) FROM meta_oracle WHERE" - " conn = '{}'".format(self.connName)) + query = "SELECT COUNT(*) FROM meta_oracle WHERE" " conn = '{}'".format( + self.connName + ) cache_c.execute(query) has_cached = cache_c.fetchone()[0] cache_c.close() @@ -129,8 +130,10 @@ def _connectionInfo(self): def _checkSpatial(self): """Check whether Oracle Spatial is present in catalog.""" - query = ("SELECT count(*) FROM v$option WHERE parameter = " - " 'Spatial' AND value = 'TRUE'") + query = ( + "SELECT count(*) FROM v$option WHERE parameter = " + " 'Spatial' AND value = 'TRUE'" + ) c = self._execute(None, query) self.has_spatial = self._fetchone(c)[0] > 0 c.close() @@ -140,12 +143,12 @@ def _checkSpatial(self): def _checkGeometryColumnsTable(self): """Check if user can read *_SDO_GEOM_METADATA view.""" # First check if user can read ALL_SDO_GEOM_METADATA - privs = self.getRawTablePrivileges('ALL_SDO_GEOM_METADATA', - 'MDSYS', 'PUBLIC') + privs = self.getRawTablePrivileges("ALL_SDO_GEOM_METADATA", "MDSYS", "PUBLIC") # Otherwise, try with USER_SDO_GEOM_METADATA if not privs[0]: - privs = self.getRawTablePrivileges('USER_SDO_GEOM_METADATA', - 'MDSYS', 'PUBLIC') + privs = self.getRawTablePrivileges( + "USER_SDO_GEOM_METADATA", "MDSYS", "PUBLIC" + ) if privs[0]: self.has_geometry_columns = True @@ -211,12 +214,18 @@ def fieldTypes(self): http://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype.htm#CNCPT1828 """ return [ - "number", "number(9)", # integers - "number(9,2)", "number(*,4)", "binary_float", + "number", + "number(9)", # integers + "number(9,2)", + "number(*,4)", + "binary_float", "binary_double", # floats - "varchar2(255)", "char(20)", "nvarchar2(255)", + "varchar2(255)", + "char(20)", + "nvarchar2(255)", "nchar(20)", # strings - "date", "timestamp" # date/time + "date", + "timestamp", # date/time ] def getSchemaPrivileges(self, schema): @@ -248,10 +257,12 @@ def getRawTablePrivileges(self, table, owner, grantee): AND TABLE_NAME = {} AND OWNER = {} AND GRANTEE IN ({}, {}) - """.format(self.quoteString(table), - self.quoteString(owner), - self.quoteString(grantee), - self.quoteString(grantee.upper())) + """.format( + self.quoteString(table), + self.quoteString(owner), + self.quoteString(grantee), + self.quoteString(grantee.upper()), + ) c = self._execute(None, sql) res = self._fetchall(c) @@ -284,7 +295,9 @@ def getSchemasCache(self): SELECT DISTINCT ownername FROM "oracle_{}" ORDER BY ownername - """.format(self.connName) + """.format( + self.connName + ) c = self.cache_connection.cursor() c.execute(sql) res = c.fetchall() @@ -303,13 +316,11 @@ def getSchemas(self): return self.getSchemasCache() # Use cache if available: - metatable = ("all_objects WHERE object_type IN " - "('TABLE','VIEW','SYNONYM')") + metatable = "all_objects WHERE object_type IN " "('TABLE','VIEW','SYNONYM')" if self.geometryColumnsOnly: metatable = "all_sdo_geom_metadata" - sql = """SELECT DISTINCT owner FROM {} ORDER BY owner""".format( - metatable) + sql = f"""SELECT DISTINCT owner FROM {metatable} ORDER BY owner""" c = self._execute(None, sql) res = self._fetchall(c) @@ -343,8 +354,7 @@ def getTables(self, schema=None, add_sys_tables=False): prefix = "USER" owner = "user As OWNER" if schema and not self.userTablesOnly: - where = "AND o.owner = {} ".format( - self.quoteString(schema)) + where = f"AND o.owner = {self.quoteString(schema)} " sql = """ SELECT o.OBJECT_NAME, {}, @@ -355,9 +365,12 @@ def getTables(self, schema=None, add_sys_tables=False): WHERE o.object_type IN ('TABLE','VIEW','SYNONYM') {} {} ORDER BY o.OBJECT_NAME - """.format(owner, prefix, where, - "" if add_sys_tables - else "AND o.OBJECT_NAME NOT LIKE 'MDRT_%'") + """.format( + owner, + prefix, + where, + "" if add_sys_tables else "AND o.OBJECT_NAME NOT LIKE 'MDRT_%'", + ) c = self._execute(None, sql) for tbl in self._fetchall(c): @@ -370,7 +383,9 @@ def getTables(self, schema=None, add_sys_tables=False): self.populated = True - listTables = sorted(items, key=cmp_to_key(lambda x, y: (x[1] > y[1]) - (x[1] < y[1]))) + listTables = sorted( + items, key=cmp_to_key(lambda x, y: (x[1] > y[1]) - (x[1] < y[1])) + ) if self.hasCache(): self.updateCache(listTables, schema) @@ -393,23 +408,25 @@ def getTablesCache(self, schema=None): pass if not self.allowGeometrylessTables: - return sorted(items, key=cmp_to_key(lambda x, y: (x[1] > y[1]) - (x[1] < y[1]))) + return sorted( + items, key=cmp_to_key(lambda x, y: (x[1] > y[1]) - (x[1] < y[1])) + ) # get all non geographic tables and views schema_where = "" if self.userTablesOnly: - schema_where = "AND ownername = '{}'".format( - self.user) + schema_where = f"AND ownername = '{self.user}'" if schema and not self.userTablesOnly: - schema_where = "AND ownername = '{}'".format( - schema) + schema_where = f"AND ownername = '{schema}'" sql = """ SELECT tablename, ownername, isview FROM "oracle_{}" WHERE geometrycolname IS '' {} ORDER BY tablename - """.format(self.connName, schema_where) + """.format( + self.connName, schema_where + ) c = self.cache_connection.cursor() c.execute(sql) @@ -435,18 +452,28 @@ def updateCache(self, tableList, schema=None): pkCols = self.pkCols((schema, table[1])) # Deals with non-geographic tables if table[0] == Table.TableType: - line = (table[1], table[2], int(table[3]), - "", - ",".join(pkCols) if pkCols else "", - 100, 0, "") + line = ( + table[1], + table[2], + int(table[3]), + "", + ",".join(pkCols) if pkCols else "", + 100, + 0, + "", + ) # Deals with vector tables elif table[0] == Table.VectorType: - line = (table[1], table[2], int(table[3]), - table[4], - ",".join(pkCols) if pkCols else "", - table[9], - table[8] if table[10] == "-1" else table[10], - "") + line = ( + table[1], + table[2], + int(table[3]), + table[4], + ",".join(pkCols) if pkCols else "", + table[9], + table[8] if table[10] == "-1" else table[10], + "", + ) else: continue data.append(line) @@ -454,8 +481,9 @@ def updateCache(self, tableList, schema=None): # Then, empty the cache list sql = """ DELETE FROM "oracle_{}" {} - """.format(self.connName, - "WHERE ownername = '{}'".format(schema) if schema else "") + """.format( + self.connName, f"WHERE ownername = '{schema}'" if schema else "" + ) self.cache_connection.execute(sql) self.cache_connection.commit() @@ -464,7 +492,9 @@ def updateCache(self, tableList, schema=None): INSERT INTO "oracle_{}"(tablename, ownername, isview, geometrycolname, pkcols, geomtypes, geomsrids, sql) VALUES (?, ?, ?, ?, ?, ?, ?, ?) - """.format(self.connName) + """.format( + self.connName + ) c = self.cache_connection.cursor() c.executemany(sql, data) c.close() @@ -472,16 +502,22 @@ def updateCache(self, tableList, schema=None): def singleGeomTypes(self, geomtypes, srids): """Intelligent wkbtype grouping (multi with non multi)""" - if (QgsWkbTypes.Type.Polygon in geomtypes - and QgsWkbTypes.Type.MultiPolygon in geomtypes): + if ( + QgsWkbTypes.Type.Polygon in geomtypes + and QgsWkbTypes.Type.MultiPolygon in geomtypes + ): srids.pop(geomtypes.index(QgsWkbTypes.Type.Polygon)) geomtypes.pop(geomtypes.index(QgsWkbTypes.Type.Polygon)) - if (QgsWkbTypes.Type.Point in geomtypes - and QgsWkbTypes.Type.MultiPoint in geomtypes): + if ( + QgsWkbTypes.Type.Point in geomtypes + and QgsWkbTypes.Type.MultiPoint in geomtypes + ): srids.pop(geomtypes.index(QgsWkbTypes.Type.Point)) geomtypes.pop(geomtypes.index(QgsWkbTypes.Type.Point)) - if (QgsWkbTypes.Type.LineString in geomtypes - and QgsWkbTypes.Type.MultiLineString in geomtypes): + if ( + QgsWkbTypes.Type.LineString in geomtypes + and QgsWkbTypes.Type.MultiLineString in geomtypes + ): srids.pop(geomtypes.index(QgsWkbTypes.Type.LineString)) geomtypes.pop(geomtypes.index(QgsWkbTypes.Type.LineString)) if QgsWkbTypes.Type.Unknown in geomtypes and len(geomtypes) > 1: @@ -502,11 +538,9 @@ def getVectorTablesCache(self, schema=None): """ schema_where = "" if self.userTablesOnly: - schema_where = "AND ownername = '{}'".format( - self.user) + schema_where = f"AND ownername = '{self.user}'" if schema and not self.userTablesOnly: - schema_where = "AND ownername = '{}'".format( - schema) + schema_where = f"AND ownername = '{schema}'" sql = """ SELECT tablename, ownername, isview, @@ -515,7 +549,9 @@ def getVectorTablesCache(self, schema=None): FROM "oracle_{}" WHERE geometrycolname IS NOT '' {} ORDER BY tablename - """.format(self.connName, schema_where) + """.format( + self.connName, schema_where + ) items = [] @@ -538,7 +574,9 @@ def getVectorTablesCache(self, schema=None): buf = list(item) geomtype = geomtypes[j] srid = srids[j] - datatype = QgsWkbTypes.displayString(QgsWkbTypes.flatType(QgsWkbTypes.singleType(geomtype))) + datatype = QgsWkbTypes.displayString( + QgsWkbTypes.flatType(QgsWkbTypes.singleType(geomtype)) + ) geo = datatype.upper() buf.append(geo) buf.append(geomtype) @@ -571,8 +609,8 @@ def getVectorTables(self, schema=None): where = "WHERE c.data_type = 'SDO_GEOMETRY'" if schema and not self.userTablesOnly: where = "{} c.owner = {}".format( - "{} AND".format(where) if where else "WHERE", - self.quoteString(schema)) + f"{where} AND" if where else "WHERE", self.quoteString(schema) + ) if self.userTablesOnly: prefix = "user" @@ -591,15 +629,14 @@ def getVectorTables(self, schema=None): JOIN {2}_objects o ON c.table_name = o.object_name AND o.object_type IN ('TABLE','VIEW','SYNONYM') {4} {5} ORDER BY TABLE_NAME - """.format(owner, - "c.srid" if self.geometryColumnsOnly - else "NULL as srid", - prefix, - "sdo_geom_metadata" if self.geometryColumnsOnly - else "tab_columns", - "" if self.userTablesOnly - else "AND c.owner = o.owner", - where) + """.format( + owner, + "c.srid" if self.geometryColumnsOnly else "NULL as srid", + prefix, + "sdo_geom_metadata" if self.geometryColumnsOnly else "tab_columns", + "" if self.userTablesOnly else "AND c.owner = o.owner", + where, + ) # For each table, get all of the details items = [] @@ -617,12 +654,11 @@ def getVectorTables(self, schema=None): detectedSrid = int(detectedSrid) if schema: - table_name = "{}.{}".format(self.quoteId(schema), self.quoteId(item[0])) + table_name = f"{self.quoteId(schema)}.{self.quoteId(item[0])}" else: table_name = self.quoteId(item[0]) geocol = self.quoteId(item[3]) - geomMultiTypes, multiSrids = self.getTableGeomTypes( - table_name, geocol) + geomMultiTypes, multiSrids = self.getTableGeomTypes(table_name, geocol) geomtypes = list(geomMultiTypes) srids = list(multiSrids) item.insert(0, Table.VectorType) @@ -632,7 +668,9 @@ def getVectorTables(self, schema=None): for j in range(len(geomtypes)): buf = list(item) geomtype = geomtypes[j] - datatype = QgsWkbTypes.displayString(QgsWkbTypes.flatType(QgsWkbTypes.singleType(geomtype))) + datatype = QgsWkbTypes.displayString( + QgsWkbTypes.flatType(QgsWkbTypes.singleType(geomtype)) + ) geo = datatype.upper() buf.append(geo) # Geometry type as String buf.append(geomtype) # Qgis.WkbType @@ -641,8 +679,7 @@ def getVectorTables(self, schema=None): if not self.onlyExistingTypes: geomMultiTypes.append(0) multiSrids.append(multiSrids[0]) - buf.append(",".join([str(x) for x in - geomMultiTypes])) + buf.append(",".join([str(x) for x in geomMultiTypes])) buf.append(",".join([str(x) for x in multiSrids])) items.append(buf) @@ -662,8 +699,7 @@ def getTableComment(self, table, objectType): schema, tablename = self.getSchemaTableName(table) data_prefix = "ALL" if schema else "USER" - where = "AND OWNER = {}".format( - self.quoteString(schema)) if schema else "" + where = f"AND OWNER = {self.quoteString(schema)}" if schema else "" if objectType in ["TABLE", "VIEW"]: data_table = "{}_TAB_COMMENTS" table = "TABLE" @@ -677,9 +713,9 @@ def getTableComment(self, table, objectType): sql = """ SELECT COMMENTS FROM {} WHERE {}_NAME = {} {} - """.format(data_table, table, - self.quoteString(tablename), - where) + """.format( + data_table, table, self.quoteString(tablename), where + ) c = self._execute(None, sql) res = self._fetchone(c) @@ -702,14 +738,13 @@ def getTableType(self, table): SELECT OBJECT_TYPE FROM {0} WHERE OBJECT_NAME = {1} {2} """ if schema: - sql = sql.format("ALL_OBJECTS", - self.quoteString(tablename), - "AND OWNER = {}".format( - self.quoteString(schema))) + sql = sql.format( + "ALL_OBJECTS", + self.quoteString(tablename), + f"AND OWNER = {self.quoteString(schema)}", + ) else: - sql = sql.format("USER_OBJECTS", - self.quoteString(tablename), - "") + sql = sql.format("USER_OBJECTS", self.quoteString(tablename), "") c = self._execute(None, sql) res = self._fetchall(c) @@ -736,8 +771,10 @@ def pkCols(self, table): WHERE owner={} AND table_name={} ORDER BY column_id - """.format(self.quoteString(schema) if schema else self.user, - self.quoteString(tablename)) + """.format( + self.quoteString(schema) if schema else self.user, + self.quoteString(tablename), + ) c = self._execute(None, sql) res = self._fetchall(c) c.close() @@ -760,7 +797,9 @@ def getTableGeomTypes(self, table, geomCol): FROM {1} a WHERE a.{0} IS NOT NULL {2} ORDER BY a.{0}.SDO_GTYPE - """.format(geomCol, table, estimated) + """.format( + geomCol, table, estimated + ) try: c = self._execute(None, query) @@ -799,12 +838,20 @@ def getTableMainGeomType(self, table, geomCol): # Make the decision: wkbType = QgsWkbTypes.Type.Unknown srid = -1 - order = [QgsWkbTypes.Type.MultiPolygon25D, QgsWkbTypes.Type.Polygon25D, - QgsWkbTypes.Type.MultiPolygon, QgsWkbTypes.Type.Polygon, - QgsWkbTypes.Type.MultiLineString25D, QgsWkbTypes.Type.LineString25D, - QgsWkbTypes.Type.MultiLineString, QgsWkbTypes.Type.LineString, - QgsWkbTypes.Type.MultiPoint25D, QgsWkbTypes.Type.Point25D, - QgsWkbTypes.Type.MultiPoint, QgsWkbTypes.Type.Point] + order = [ + QgsWkbTypes.Type.MultiPolygon25D, + QgsWkbTypes.Type.Polygon25D, + QgsWkbTypes.Type.MultiPolygon, + QgsWkbTypes.Type.Polygon, + QgsWkbTypes.Type.MultiLineString25D, + QgsWkbTypes.Type.LineString25D, + QgsWkbTypes.Type.MultiLineString, + QgsWkbTypes.Type.LineString, + QgsWkbTypes.Type.MultiPoint25D, + QgsWkbTypes.Type.Point25D, + QgsWkbTypes.Type.MultiPoint, + QgsWkbTypes.Type.Point, + ] for geomType in order: if geomType in geomTypes: wkbType = geomType @@ -814,17 +861,18 @@ def getTableMainGeomType(self, table, geomCol): return wkbType, srid def getTableRowEstimation(self, table): - """ Find the estimated number of rows of a table. """ + """Find the estimated number of rows of a table.""" schema, tablename = self.getSchemaTableName(table) prefix = "ALL" if schema else "USER" - where = "AND OWNER = {}".format( - self.quoteString(schema)) if schema else "" + where = f"AND OWNER = {self.quoteString(schema)}" if schema else "" sql = """ SELECT NUM_ROWS FROM {}_ALL_TABLES WHERE TABLE_NAME = {} {} - """.format(prefix, self.quoteString(tablename), where) + """.format( + prefix, self.quoteString(tablename), where + ) c = self._execute(None, sql) res = self._fetchone(c) @@ -836,17 +884,18 @@ def getTableRowEstimation(self, table): return int(res[0]) def getTableDates(self, table): - """ Returns the modification/creation dates of an object""" + """Returns the modification/creation dates of an object""" schema, tablename = self.getSchemaTableName(table) prefix = "ALL" if schema else "USER" - where = "AND OWNER = {}".format( - self.quoteString(schema)) if schema else "" + where = f"AND OWNER = {self.quoteString(schema)}" if schema else "" sql = """ SELECT CREATED, LAST_DDL_TIME FROM {}_OBJECTS WHERE OBJECT_NAME = {} {} - """.format(prefix, self.quoteString(tablename), where) + """.format( + prefix, self.quoteString(tablename), where + ) c = self._execute(None, sql) res = self._fetchone(c) @@ -859,8 +908,7 @@ def getTableDates(self, table): def getTableRowCount(self, table): """Returns the number of rows of the table.""" - c = self._execute( - None, "SELECT COUNT(*) FROM {}".format(self.quoteId(table))) + c = self._execute(None, f"SELECT COUNT(*) FROM {self.quoteId(table)}") res = self._fetchone(c)[0] c.close() @@ -871,7 +919,8 @@ def getTableFields(self, table): schema, tablename = self.getSchemaTableName(table) schema_where = " AND a.OWNER={}".format( - self.quoteString(schema) if schema else "") + self.quoteString(schema) if schema else "" + ) sql = """ SELECT a.COLUMN_ID As ordinal_position, a.COLUMN_NAME As column_name, @@ -892,7 +941,9 @@ def getTableFields(self, table): AND a.OWNER = c.OWNER WHERE a.TABLE_NAME = {} {} ORDER BY a.COLUMN_ID - """.format(self.quoteString(tablename), schema_where) + """.format( + self.quoteString(tablename), schema_where + ) c = self._execute(None, sql) res = self._fetchall(c) @@ -913,7 +964,8 @@ def getTableIndexes(self, table): """Get info about table's indexes.""" schema, tablename = self.getSchemaTableName(table) schema_where = " AND i.OWNER = {} ".format( - self.quoteString(schema) if schema else "") + self.quoteString(schema) if schema else "" + ) sql = """ SELECT i.INDEX_NAME, c.COLUMN_NAME, i.ITYP_NAME, @@ -922,7 +974,9 @@ def getTableIndexes(self, table): FROM ALL_INDEXES i INNER JOIN ALL_IND_COLUMNS c ON i.index_name = c.index_name WHERE i.table_name = {} {} - """.format(self.quoteString(tablename), schema_where) + """.format( + self.quoteString(tablename), schema_where + ) c = self._execute(None, sql) res = self._fetchall(c) @@ -933,8 +987,7 @@ def getTableIndexes(self, table): def getMViewInfo(self, table): """Find some information about materialized views""" schema, tablename = self.getSchemaTableName(table) - where = " AND a.OWNER = {} ".format( - self.quoteString(schema)) if schema else "" + where = f" AND a.OWNER = {self.quoteString(schema)} " if schema else "" prefix = "ALL" if schema else "USER" sql = """ SELECT a.REFRESH_MODE, @@ -944,7 +997,9 @@ def getMViewInfo(self, table): FROM {}_MVIEWS a WHERE MVIEW_NAME = {} {} - """.format(prefix, self.quoteString(tablename), where) + """.format( + prefix, self.quoteString(tablename), where + ) c = self._execute(None, sql) res = self._fetchone(c) @@ -955,8 +1010,7 @@ def getMViewInfo(self, table): def getTableConstraints(self, table): """Find all the constraints for a table.""" schema, tablename = self.getSchemaTableName(table) - schema_where = " AND c.OWNER={} ".format( - self.quoteString(schema)) if schema else "" + schema_where = f" AND c.OWNER={self.quoteString(schema)} " if schema else "" sql = """ SELECT a.CONSTRAINT_NAME, a.CONSTRAINT_TYPE, @@ -973,7 +1027,9 @@ def getTableConstraints(self, table): AND a.R_OWNER = b.OWNER AND b.POSITION = c.POSITION WHERE c.TABLE_NAME = {} {} - """.format(self.quoteString(tablename), schema_where) + """.format( + self.quoteString(tablename), schema_where + ) c = self._execute(None, sql) res = self._fetchall(c) @@ -990,7 +1046,9 @@ def getTableTriggers(self, table): FROM ALL_TRIGGERS WHERE TABLE_OWNER = {} AND TABLE_NAME = {} - """.format(self.quoteString(schema), self.quoteString(tablename)) + """.format( + self.quoteString(schema), self.quoteString(tablename) + ) c = self._execute(None, sql) res = self._fetchall(c) @@ -1015,7 +1073,7 @@ def deleteTableTrigger(self, trigger, table): """Deletes the trigger on a table.""" schema, tablename = self.getSchemaTableName(table) trigger = ".".join([self.quoteId(schema), self.quoteId(trigger)]) - sql = "DROP TRIGGER {}".format(trigger) + sql = f"DROP TRIGGER {trigger}" self._execute_and_commit(sql) def canUpdateMetadata(self, table): @@ -1025,12 +1083,13 @@ def canUpdateMetadata(self, table): schema, tablename = self.getSchemaTableName(table) metadata = False # User can only update in USER_SDO_GEOM_METADATA - if self.getRawTablePrivileges('USER_SDO_GEOM_METADATA', 'MDSYS', - 'PUBLIC')[2]: + if self.getRawTablePrivileges("USER_SDO_GEOM_METADATA", "MDSYS", "PUBLIC")[2]: tbQuery = """ SELECT COUNT(*) FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = {} - """.format(self.quoteString(tablename)) + """.format( + self.quoteString(tablename) + ) c = self._execute(None, tbQuery) res = self._fetchone(c) c.close() @@ -1044,17 +1103,18 @@ def canUpdateMetadata(self, table): def getTableExtent(self, table, geom): """Calculate the real table extent.""" schema, tablename = self.getSchemaTableName(table) - tableQuote = "'{}.{}'".format(schema, tablename) + tableQuote = f"'{schema}.{tablename}'" # Extent calculation without spatial index - extentFunction = """SDO_AGGR_MBR("{}")""".format(geom) - fromTable = '"{}"."{}"'.format(schema, tablename) + extentFunction = f"""SDO_AGGR_MBR("{geom}")""" + fromTable = f'"{schema}"."{tablename}"' # if table as spatial index: indexes = self.getTableIndexes(table) if indexes: if "SPATIAL_INDEX" in [f[2] for f in indexes]: extentFunction = "SDO_TUNE.EXTENT_OF({}, {})".format( - tableQuote, self.quoteString(geom)) + tableQuote, self.quoteString(geom) + ) fromTable = "DUAL" sql = """ @@ -1064,7 +1124,9 @@ def getTableExtent(self, table, geom): SDO_GEOM.SDO_MAX_MBR_ORDINATE({0}, 1), SDO_GEOM.SDO_MAX_MBR_ORDINATE({0}, 2) FROM {1} - """.format(extentFunction, fromTable) + """.format( + extentFunction, fromTable + ) try: c = self._execute(None, sql) @@ -1086,11 +1148,11 @@ def getTableEstimatedExtent(self, table, geom): where = """ WHERE TABLE_NAME = {} AND COLUMN_NAME = {} - """.format(self.quoteString(tablename), - self.quoteString(geom)) + """.format( + self.quoteString(tablename), self.quoteString(geom) + ) if schema: - where = "{} AND OWNER = {}".format( - where, self.quoteString(schema)) + where = f"{where} AND OWNER = {self.quoteString(schema)}" request = """ SELECT SDO_LB, SDO_UB @@ -1124,18 +1186,21 @@ def getDefinition(self, view, objectType): schema, tablename = self.getSchemaTableName(view) where = "" if schema: - where = " AND OWNER={} ".format( - self.quoteString(schema)) + where = f" AND OWNER={self.quoteString(schema)} " # Query to grab a view definition if objectType == "VIEW": sql = """ SELECT TEXT FROM ALL_VIEWS WHERE VIEW_NAME = {} {} - """.format(self.quoteString(tablename), where) + """.format( + self.quoteString(tablename), where + ) elif objectType == "MATERIALIZED VIEW": sql = """ SELECT QUERY FROM ALL_MVIEWS WHERE MVIEW_NAME = {} {} - """.format(self.quoteString(tablename), where) + """.format( + self.quoteString(tablename), where + ) else: return None @@ -1155,8 +1220,8 @@ def getSpatialRefInfo(self, srid): try: c = self._execute( None, - ("SELECT CS_NAME FROM MDSYS.CS_SRS WHERE" - " SRID = {}".format(srid))) + ("SELECT CS_NAME FROM MDSYS.CS_SRS WHERE" " SRID = {}".format(srid)), + ) except DbError: return sr = self._fetchone(c) @@ -1170,16 +1235,16 @@ def isVectorTable(self, table): """ if self.has_geometry_columns and self.has_geometry_columns_access: schema, tablename = self.getSchemaTableName(table) - where = "WHERE TABLE_NAME = {}".format( - self.quoteString(tablename)) + where = f"WHERE TABLE_NAME = {self.quoteString(tablename)}" if schema: - where = "{} AND OWNER = {}".format(where, - self.quoteString(schema)) + where = f"{where} AND OWNER = {self.quoteString(schema)}" sql = """ SELECT COUNT(*) FROM ALL_SDO_GEOM_METADATA {} - """.format(where) + """.format( + where + ) c = self._execute(None, sql) res = self._fetchone(c) @@ -1196,10 +1261,10 @@ def createTable(self, table, field_defs, pkey): if len(field_defs) == 0: return False - sql = "CREATE TABLE {} (".format(self.quoteId(table)) + sql = f"CREATE TABLE {self.quoteId(table)} (" sql += ", ".join(field_defs) if pkey: - sql += ", PRIMARY KEY ({})".format(self.quoteId(pkey)) + sql += f", PRIMARY KEY ({self.quoteId(pkey)})" sql += ")" self._execute_and_commit(sql) @@ -1213,13 +1278,13 @@ def deleteTable(self, table): if self.isVectorTable(table): self.deleteMetadata(table) - sql = "DROP TABLE {}".format(self.quoteId(table)) + sql = f"DROP TABLE {self.quoteId(table)}" self._execute_and_commit(sql) def emptyTable(self, table): """Deletes all the rows of a table.""" - sql = "TRUNCATE TABLE {}".format(self.quoteId(table)) + sql = f"TRUNCATE TABLE {self.quoteId(table)}" self._execute_and_commit(sql) def renameTable(self, table, new_table): @@ -1234,15 +1299,14 @@ def renameTable(self, table, new_table): if self.isVectorTable(table): self.updateMetadata(table, None, new_table=new_table) - sql = "RENAME {} TO {}".format( - self.quoteId(tablename), self.quoteId(new_table)) + sql = f"RENAME {self.quoteId(tablename)} TO {self.quoteId(new_table)}" self._execute(c, sql) self._commit() def createView(self, view, query): """Creates a view as defined.""" - sql = "CREATE VIEW {} AS {}".format(self.quoteId(view), query) + sql = f"CREATE VIEW {self.quoteId(view)} AS {query}" self._execute_and_commit(sql) def createSpatialView(self, view, query): @@ -1281,19 +1345,18 @@ def deleteView(self, view): if self.isVectorTable(view): self.deleteMetadata(view) - sql = "DROP VIEW {}".format(self.quoteId(view)) + sql = f"DROP VIEW {self.quoteId(view)}" self._execute_and_commit(sql) def createSchema(self, schema): """Creates a new empty schema in database.""" # Not tested - sql = "CREATE SCHEMA AUTHORIZATION {}".format( - self.quoteId(schema)) + sql = f"CREATE SCHEMA AUTHORIZATION {self.quoteId(schema)}" self._execute_and_commit(sql) def deleteSchema(self, schema): """Drops (empty) schema from database.""" - sql = "DROP USER {} CASCADE".format(self.quoteId(schema)) + sql = f"DROP USER {self.quoteId(schema)} CASCADE" self._execute_and_commit(sql) def renameSchema(self, schema, new_schema): @@ -1303,14 +1366,13 @@ def renameSchema(self, schema, new_schema): def addTableColumn(self, table, field_def): """Adds a column to a table.""" - sql = "ALTER TABLE {} ADD {}".format(self.quoteId(table), field_def) + sql = f"ALTER TABLE {self.quoteId(table)} ADD {field_def}" self._execute_and_commit(sql) def deleteTableColumn(self, table, column): """Deletes column from a table.""" # Delete all the constraints for this column - constraints = [f[0] for f in self.getTableConstraints(table) - if f[2] == column] + constraints = [f[0] for f in self.getTableConstraints(table) if f[2] == column] for constraint in constraints: self.deleteTableConstraint(table, constraint) @@ -1324,12 +1386,20 @@ def deleteTableColumn(self, table, column): self.deleteMetadata(table, column) sql = "ALTER TABLE {} DROP COLUMN {}".format( - self.quoteId(table), self.quoteId(column)) + self.quoteId(table), self.quoteId(column) + ) self._execute_and_commit(sql) - def updateTableColumn(self, table, column, new_name=None, - data_type=None, not_null=None, - default=None, comment=None): + def updateTableColumn( + self, + table, + column, + new_name=None, + data_type=None, + not_null=None, + default=None, + comment=None, + ): """Updates properties of a column in a table.""" schema, tablename = self.getSchemaTableName(table) @@ -1339,9 +1409,9 @@ def updateTableColumn(self, table, column, new_name=None, # update column definition col_actions = [] if data_type: - col_actions.append("{}".format(data_type)) + col_actions.append(f"{data_type}") if default: - col_actions.append("DEFAULT {}".format(default)) + col_actions.append(f"DEFAULT {default}") else: col_actions.append("DEFAULT NULL") @@ -1352,16 +1422,16 @@ def updateTableColumn(self, table, column, new_name=None, if col_actions: sql = "ALTER TABLE {} MODIFY ( {} {} )".format( - self.quoteId(table), self.quoteId(column), - " ".join(col_actions)) + self.quoteId(table), self.quoteId(column), " ".join(col_actions) + ) self._execute(c, sql) # rename the column if new_name and new_name != column: isGeo = self.isGeometryColumn(table, column) sql = "ALTER TABLE {} RENAME COLUMN {} TO {}".format( - self.quoteId(table), self.quoteId(column), - self.quoteId(new_name)) + self.quoteId(table), self.quoteId(column), self.quoteId(new_name) + ) self._execute(c, sql) # update geometry_columns if Spatial is enabled @@ -1392,16 +1462,16 @@ def isGeometryColumn(self, table, column): """Find if a column is geometric.""" schema, tablename = self.getSchemaTableName(table) prefix = "ALL" if schema else "USER" - where = "AND owner = {} ".format( - self.quoteString(schema)) if schema else "" + where = f"AND owner = {self.quoteString(schema)} " if schema else "" sql = """ SELECT COUNT(*) FROM {}_SDO_GEOM_METADATA WHERE TABLE_NAME = {} AND COLUMN_NAME = {} {} - """.format(prefix, self.quoteString(tablename), - self.quoteString(column.upper()), where) + """.format( + prefix, self.quoteString(tablename), self.quoteString(column.upper()), where + ) c = self._execute(None, sql) res = self._fetchone(c)[0] > 0 @@ -1412,92 +1482,100 @@ def isGeometryColumn(self, table, column): def refreshMView(self, table): """Refreshes an MVIEW""" schema, tablename = self.getSchemaTableName(table) - mview = "{}.{}".format(schema, tablename) if schema else tablename + mview = f"{schema}.{tablename}" if schema else tablename sql = """ BEGIN DBMS_MVIEW.REFRESH({},'?'); END; - """.format(self.quoteString(mview)) + """.format( + self.quoteString(mview) + ) self._execute_and_commit(sql) def deleteMetadata(self, table, geom_column=None): """Deletes the metadata entry for a table""" schema, tablename = self.getSchemaTableName(table) - if not (self.getRawTablePrivileges('USER_SDO_GEOM_METADATA', - 'MDSYS', - 'PUBLIC')[3] and - schema == self.user): + if not ( + self.getRawTablePrivileges("USER_SDO_GEOM_METADATA", "MDSYS", "PUBLIC")[3] + and schema == self.user + ): return False - where = "WHERE TABLE_NAME = {}".format(self.quoteString(tablename)) + where = f"WHERE TABLE_NAME = {self.quoteString(tablename)}" if geom_column: - where = ("{} AND COLUMN_NAME = " - "{}".format(where, - self.quoteString(geom_column))) - sql = "DELETE FROM USER_SDO_GEOM_METADATA {}".format(where) + where = "{} AND COLUMN_NAME = " "{}".format( + where, self.quoteString(geom_column) + ) + sql = f"DELETE FROM USER_SDO_GEOM_METADATA {where}" self._execute_and_commit(sql) - def updateMetadata(self, table, geom_column, new_geom_column=None, - new_table=None, extent=None, srid=None): + def updateMetadata( + self, + table, + geom_column, + new_geom_column=None, + new_table=None, + extent=None, + srid=None, + ): """Updates the metadata table with the new information""" schema, tablename = self.getSchemaTableName(table) - if not (self.getRawTablePrivileges('USER_SDO_GEOM_METADATA', - 'MDSYS', - 'PUBLIC')[2] and - schema == self.user): + if not ( + self.getRawTablePrivileges("USER_SDO_GEOM_METADATA", "MDSYS", "PUBLIC")[2] + and schema == self.user + ): return False - where = "WHERE TABLE_NAME = {}".format(self.quoteString(tablename)) + where = f"WHERE TABLE_NAME = {self.quoteString(tablename)}" if geom_column: # in Metadata view, geographic column is always in uppercase - where = ("{} AND COLUMN_NAME = " - "{}".format(where, - self.quoteString(geom_column.upper()))) + where = "{} AND COLUMN_NAME = " "{}".format( + where, self.quoteString(geom_column.upper()) + ) update = "SET" if srid == 0: srid = -1 if srid: - update = "{} SRID = {}".format(update, srid) + update = f"{update} SRID = {srid}" if extent: if len(extent) == 4: if update != "SET": - update = "{},".format(update) + update = f"{update}," update = """{4} DIMINFO = MDSYS.SDO_DIM_ARRAY( MDSYS.SDO_DIM_ELEMENT('X', {0:.9f}, {1:.9f}, 0.005), MDSYS.SDO_DIM_ELEMENT('Y', {2:.9f}, {3:.9f}, 0.005)) - """.format(extent[0], extent[2], extent[1], - extent[3], update) + """.format( + extent[0], extent[2], extent[1], extent[3], update + ) if new_geom_column: if update != "SET": - update = "{},".format(update) + update = f"{update}," # in Metadata view, geographic column is always in uppercase - update = ("{} COLUMN_NAME = " - "{}".format(update, - self.quoteString(new_geom_column.upper()))) + update = "{} COLUMN_NAME = " "{}".format( + update, self.quoteString(new_geom_column.upper()) + ) if new_table: if update != "SET": - update = "{},".format(update) - update = ("{} TABLE_NAME = " - "{}".format(update, - self.quoteString(new_table))) + update = f"{update}," + update = "{} TABLE_NAME = " "{}".format(update, self.quoteString(new_table)) - sql = "UPDATE USER_SDO_GEOM_METADATA {} {}".format(update, where) + sql = f"UPDATE USER_SDO_GEOM_METADATA {update} {where}" self._execute_and_commit(sql) def insertMetadata(self, table, geom_column, extent, srid, dim=2): """Inserts a line for the table in Oracle Metadata table.""" schema, tablename = self.getSchemaTableName(table) - if not (self.getRawTablePrivileges('USER_SDO_GEOM_METADATA', - 'MDSYS', - 'PUBLIC')[1] and - schema == self.user): + if not ( + self.getRawTablePrivileges("USER_SDO_GEOM_METADATA", "MDSYS", "PUBLIC")[1] + and schema == self.user + ): return False # in Metadata view, geographic column is always in uppercase @@ -1507,16 +1585,21 @@ def insertMetadata(self, table, geom_column, extent, srid, dim=2): if len(extent) != 4: return False - dims = ['X', 'Y', 'Z', 'T'] + dims = ["X", "Y", "Z", "T"] extentParts = [] for i in range(dim): extentParts.append( """MDSYS.SDO_DIM_ELEMENT( - '{}', {:.9f}, {:.9f}, 0.005)""".format(dims[i], extent[i], extent[i + 1])) + '{}', {:.9f}, {:.9f}, 0.005)""".format( + dims[i], extent[i], extent[i + 1] + ) + ) extentParts = ",".join(extentParts) sqlExtent = """MDSYS.SDO_DIM_ARRAY( {}) - """.format(extentParts) + """.format( + extentParts + ) sql = """ INSERT INTO USER_SDO_GEOM_METADATA (TABLE_NAME, @@ -1525,14 +1608,18 @@ def insertMetadata(self, table, geom_column, extent, srid, dim=2): VALUES({}, {}, {}, {}) - """.format(self.quoteString(tablename), - self.quoteString(geom_column), - sqlExtent, str(srid)) + """.format( + self.quoteString(tablename), + self.quoteString(geom_column), + sqlExtent, + str(srid), + ) self._execute_and_commit(sql) - def addGeometryColumn(self, table, geom_column='GEOM', - geom_type=None, srid=-1, dim=2): + def addGeometryColumn( + self, table, geom_column="GEOM", geom_type=None, srid=-1, dim=2 + ): """Adds a geometry column and update Oracle Spatial metadata. """ @@ -1543,7 +1630,8 @@ def addGeometryColumn(self, table, geom_column='GEOM', # Add the column to the table sql = "ALTER TABLE {} ADD {} SDO_GEOMETRY".format( - self.quoteId(table), self.quoteId(geom_column)) + self.quoteId(table), self.quoteId(geom_column) + ) self._execute_and_commit(sql) @@ -1551,9 +1639,9 @@ def addGeometryColumn(self, table, geom_column='GEOM', extent = [] for i in range(dim): extent.extend([-100000, 10000]) - self.insertMetadata(table, geom_column, - [-100000, 100000, -10000, 10000], - srid, dim) + self.insertMetadata( + table, geom_column, [-100000, 100000, -10000, 10000], srid, dim + ) def deleteGeometryColumn(self, table, geom_column): """Deletes a geometric column.""" @@ -1562,57 +1650,61 @@ def deleteGeometryColumn(self, table, geom_column): def addTableUniqueConstraint(self, table, column): """Adds a unique constraint to a table.""" sql = "ALTER TABLE {} ADD UNIQUE ({})".format( - self.quoteId(table), self.quoteId(column)) + self.quoteId(table), self.quoteId(column) + ) self._execute_and_commit(sql) def deleteTableConstraint(self, table, constraint): """Deletes constraint in a table.""" sql = "ALTER TABLE {} DROP CONSTRAINT {}".format( - self.quoteId(table), self.quoteId(constraint)) + self.quoteId(table), self.quoteId(constraint) + ) self._execute_and_commit(sql) def addTablePrimaryKey(self, table, column): """Adds a primary key (with one column) to a table.""" sql = "ALTER TABLE {} ADD PRIMARY KEY ({})".format( - self.quoteId(table), self.quoteId(column)) + self.quoteId(table), self.quoteId(column) + ) self._execute_and_commit(sql) def createTableIndex(self, table, name, column): """Creates index on one column using default options.""" sql = "CREATE INDEX {} ON {} ({})".format( - self.quoteId(name), self.quoteId(table), - self.quoteId(column)) + self.quoteId(name), self.quoteId(table), self.quoteId(column) + ) self._execute_and_commit(sql) def rebuildTableIndex(self, table, name): """Rebuilds a table index""" schema, tablename = self.getSchemaTableName(table) - sql = "ALTER INDEX {} REBUILD".format(self.quoteId((schema, name))) + sql = f"ALTER INDEX {self.quoteId((schema, name))} REBUILD" self._execute_and_commit(sql) def deleteTableIndex(self, table, name): """Deletes an index on a table.""" schema, tablename = self.getSchemaTableName(table) - sql = "DROP INDEX {}".format(self.quoteId((schema, name))) + sql = f"DROP INDEX {self.quoteId((schema, name))}" self._execute_and_commit(sql) - def createSpatialIndex(self, table, geom_column='GEOM'): + def createSpatialIndex(self, table, geom_column="GEOM"): """Creates a spatial index on a geometric column.""" geom_column = geom_column.upper() schema, tablename = self.getSchemaTableName(table) - idx_name = self.quoteId("sidx_{}_{}".format(tablename, geom_column)) + idx_name = self.quoteId(f"sidx_{tablename}_{geom_column}") sql = """ CREATE INDEX {} ON {}({}) INDEXTYPE IS MDSYS.SPATIAL_INDEX - """.format(idx_name, self.quoteId(table), - self.quoteId(geom_column)) + """.format( + idx_name, self.quoteId(table), self.quoteId(geom_column) + ) self._execute_and_commit(sql) - def deleteSpatialIndex(self, table, geom_column='GEOM'): + def deleteSpatialIndex(self, table, geom_column="GEOM"): """Deletes a spatial index of a geometric column.""" schema, tablename = self.getSchemaTableName(table) - idx_name = self.quoteId("sidx_{}_{}".format(tablename, geom_column)) + idx_name = self.quoteId(f"sidx_{tablename}_{geom_column}") return self.deleteTableIndex(table, idx_name) def execution_error_types(self): @@ -1672,6 +1764,7 @@ def _close_cursor(self, c): def getSqlDictionary(self): """Returns the dictionary for SQL dialog.""" from .sql_dictionary import getSqlDictionary + sql_dict = getSqlDictionary() # get schemas, tables and field names @@ -1683,7 +1776,9 @@ def getSqlDictionary(self): SELECT DISTINCT tablename FROM "oracle_{0}" UNION SELECT DISTINCT ownername FROM "oracle_{0}" - """.format(self.connName) + """.format( + self.connName + ) if self.userTablesOnly: sql = """ SELECT DISTINCT tablename @@ -1691,7 +1786,9 @@ def getSqlDictionary(self): UNION SELECT DISTINCT ownername FROM "oracle_{conn}" WHERE ownername = '{user}' - """.format(conn=self.connName, user=self.user) + """.format( + conn=self.connName, user=self.user + ) c = self.cache_connection.cursor() c.execute(sql) @@ -1702,8 +1799,9 @@ def getSqlDictionary(self): if self.hasCache(): sql = """ SELECT DISTINCT COLUMN_NAME FROM {}_TAB_COLUMNS - """.format("USER" if self.userTablesOnly else - "ALL") + """.format( + "USER" if self.userTablesOnly else "ALL" + ) elif self.userTablesOnly: sql = """ SELECT DISTINCT TABLE_NAME FROM USER_ALL_TABLES @@ -1731,6 +1829,7 @@ def getSqlDictionary(self): def getQueryBuilderDictionary(self): from .sql_dictionary import getQueryBuilderDictionary + return getQueryBuilderDictionary() def cancel(self): diff --git a/python/plugins/db_manager/db_plugins/oracle/data_model.py b/python/plugins/db_manager/db_plugins/oracle/data_model.py index 0fc8f6512932..f86336c2154a 100644 --- a/python/plugins/db_manager/db_plugins/oracle/data_model.py +++ b/python/plugins/db_manager/db_plugins/oracle/data_model.py @@ -23,11 +23,13 @@ from qgis.PyQt.QtCore import QElapsedTimer from qgis.core import QgsMessageLog -from ..data_model import (TableDataModel, - SqlResultModel, - SqlResultModelAsync, - SqlResultModelTask, - BaseTableModel) +from ..data_model import ( + TableDataModel, + SqlResultModel, + SqlResultModelAsync, + SqlResultModelTask, + BaseTableModel, +) from ..plugin import DbError from ..plugin import BaseError @@ -46,39 +48,38 @@ def __init__(self, table, parent=None): def _createCursor(self): fields_txt = ", ".join(self.fields) - table_txt = self.db.quoteId( - (self.table.schemaName(), self.table.name)) + table_txt = self.db.quoteId((self.table.schemaName(), self.table.name)) self.cursor = self.db._get_cursor() - sql = "SELECT {} FROM {}".format(fields_txt, table_txt) + sql = f"SELECT {fields_txt} FROM {table_txt}" self.db._execute(self.cursor, sql) def _sanitizeTableField(self, field): # get fields, ignore geometry columns if field.dataType.upper() == "SDO_GEOMETRY": - return ("CASE WHEN {0} IS NULL THEN NULL ELSE 'GEOMETRY'" - "END AS {0}".format( - self.db.quoteId(field.name))) + return ( + "CASE WHEN {0} IS NULL THEN NULL ELSE 'GEOMETRY'" + "END AS {0}".format(self.db.quoteId(field.name)) + ) if field.dataType.upper() == "DATE": - return "CAST({} AS VARCHAR2(8))".format( - self.db.quoteId(field.name)) + return f"CAST({self.db.quoteId(field.name)} AS VARCHAR2(8))" if "TIMESTAMP" in field.dataType.upper(): return "TO_CHAR({}, 'YYYY-MM-DD HH:MI:SS.FF')".format( - self.db.quoteId(field.name)) + self.db.quoteId(field.name) + ) if field.dataType.upper() == "NUMBER": if not field.charMaxLen: - return "CAST({} AS VARCHAR2(135))".format( - self.db.quoteId(field.name)) + return f"CAST({self.db.quoteId(field.name)} AS VARCHAR2(135))" elif field.modifier: - nbChars = 2 + int(field.charMaxLen) + \ - int(field.modifier) + nbChars = 2 + int(field.charMaxLen) + int(field.modifier) return "CAST({} AS VARCHAR2({}))".format( - self.db.quoteId(field.name), - str(nbChars)) + self.db.quoteId(field.name), str(nbChars) + ) return "CAST({} As VARCHAR2({}))".format( - self.db.quoteId(field.name), field.charMaxLen) + self.db.quoteId(field.name), field.charMaxLen + ) def _deleteCursor(self): self.db._close_cursor(self.cursor) @@ -89,8 +90,7 @@ def __del__(self): self._deleteCursor() def getData(self, row, col): - if (row < self.fetchedFrom or - row >= self.fetchedFrom + self.fetchedCount): + if row < self.fetchedFrom or row >= self.fetchedFrom + self.fetchedCount: margin = self.fetchedCount / 2 if row + margin >= self.rowCount(): start = int(self.rowCount() - margin) diff --git a/python/plugins/db_manager/db_plugins/oracle/info_model.py b/python/plugins/db_manager/db_plugins/oracle/info_model.py index c8d531ab06eb..08805225e07a 100644 --- a/python/plugins/db_manager/db_plugins/oracle/info_model.py +++ b/python/plugins/db_manager/db_plugins/oracle/info_model.py @@ -25,8 +25,14 @@ from qgis.core import QgsWkbTypes from ..info_model import TableInfo, VectorTableInfo, DatabaseInfo -from ..html_elems import HtmlContent, HtmlSection, HtmlParagraph, \ - HtmlTable, HtmlTableHeader, HtmlTableCol +from ..html_elems import ( + HtmlContent, + HtmlSection, + HtmlParagraph, + HtmlTable, + HtmlTableHeader, + HtmlTableCol, +) # Syntax Highlight for VIEWS/MVIEWS from pygments import highlight @@ -43,16 +49,27 @@ def connectionDetails(self): tbl = [] if self.db.connector.host != "": - tbl.append((QApplication.translate("DBManagerPlugin", "Host:"), - self.db.connector.host)) - tbl.append((QApplication.translate("DBManagerPlugin", "Database:"), - self.db.connector.dbname)) - tbl.append((QApplication.translate("DBManagerPlugin", "User:"), - self.db.connector.user)) - tbl.append((QApplication.translate("DBManagerPlugin", - "SQLite list tables cache:"), - "Enabled" if self.db.connector.hasCache else - "Unavailable")) + tbl.append( + ( + QApplication.translate("DBManagerPlugin", "Host:"), + self.db.connector.host, + ) + ) + tbl.append( + ( + QApplication.translate("DBManagerPlugin", "Database:"), + self.db.connector.dbname, + ) + ) + tbl.append( + (QApplication.translate("DBManagerPlugin", "User:"), self.db.connector.user) + ) + tbl.append( + ( + QApplication.translate("DBManagerPlugin", "SQLite list tables cache:"), + "Enabled" if self.db.connector.hasCache else "Unavailable", + ) + ) return HtmlTable(tbl) @@ -63,10 +80,7 @@ def spatialInfo(self): if not info: return - tbl = [ - (QApplication.translate("DBManagerPlugin", "Oracle Spatial:"), - info[0]) - ] + tbl = [(QApplication.translate("DBManagerPlugin", "Oracle Spatial:"), info[0])] ret.append(HtmlTable(tbl)) if not self.db.connector.has_geometry_columns: @@ -77,12 +91,15 @@ def spatialInfo(self): " ALL_SDO_GEOM_METADATA" " view doesn't exist!\n" "This view is essential for many" - " GIS applications for enumeration of tables."))) + " GIS applications for enumeration of tables.", + ) + ) + ) return ret def privilegesDetails(self): - """ find if user can create schemas (CREATE ANY TABLE or something)""" + """find if user can create schemas (CREATE ANY TABLE or something)""" # TODO return None @@ -105,9 +122,11 @@ def generalInfo(self): # if the estimation is less than 100 rows, try to count them - it # shouldn't take long time - if (not self.table.isView and - not self.table.rowCount and - self.table.estimatedRowCount < 100): + if ( + not self.table.isView + and not self.table.rowCount + and self.table.estimatedRowCount < 100 + ): # row count information is not displayed yet, so just block # table signals to avoid double refreshing # (infoViewer->refreshRowCount->tableChanged->infoViewer) @@ -115,70 +134,92 @@ def generalInfo(self): self.table.refreshRowCount() self.table.blockSignals(False) - relation_type = QApplication.translate( - "DBManagerPlugin", self.table.objectType) if isinstance(self.table.objectType, str) else QApplication.translate("DBManagerPlugin", "Unknown") + relation_type = ( + QApplication.translate("DBManagerPlugin", self.table.objectType) + if isinstance(self.table.objectType, str) + else QApplication.translate("DBManagerPlugin", "Unknown") + ) tbl = [ - (QApplication.translate("DBManagerPlugin", "Object type:"), - relation_type), - (QApplication.translate("DBManagerPlugin", "Owner:"), - self.table.owner) + (QApplication.translate("DBManagerPlugin", "Object type:"), relation_type), + (QApplication.translate("DBManagerPlugin", "Owner:"), self.table.owner), ] if self.table.comment: tbl.append( - (QApplication.translate( - "DBManagerPlugin", - "Comment:"), - self.table.comment)) + ( + QApplication.translate("DBManagerPlugin", "Comment:"), + self.table.comment, + ) + ) # Estimated rows if not self.table.isView: tbl.append( - (QApplication.translate( - "DBManagerPlugin", "Rows (estimation):"), - self.table.estimatedRowCount) + ( + QApplication.translate("DBManagerPlugin", "Rows (estimation):"), + self.table.estimatedRowCount, + ) ) if self.table.rowCount is not None and self.table.rowCount >= 0: # Add a real count of rows tbl.append( - (QApplication.translate("DBManagerPlugin", "Rows (counted):"), - self.table.rowCount) + ( + QApplication.translate("DBManagerPlugin", "Rows (counted):"), + self.table.rowCount, + ) ) else: tbl.append( - (QApplication.translate("DBManagerPlugin", "Rows (counted):"), - 'Unknown (find out)') + ( + QApplication.translate("DBManagerPlugin", "Rows (counted):"), + 'Unknown (find out)', + ) ) # Add creation and modification dates if self.table.creationDate: tbl.append( - (QApplication.translate("DBManagerPlugin", "Creation Date:"), - self.table.creationDate)) + ( + QApplication.translate("DBManagerPlugin", "Creation Date:"), + self.table.creationDate, + ) + ) if self.table.modificationDate: tbl.append( - (QApplication.translate( - "DBManagerPlugin", "Last Modification Date:"), - self.table.modificationDate)) + ( + QApplication.translate( + "DBManagerPlugin", "Last Modification Date:" + ), + self.table.modificationDate, + ) + ) # privileges # has the user access to this schema? - schema_priv = self.table.database().connector.getSchemaPrivileges( - self.table.schemaName()) if self.table.schema() else None + schema_priv = ( + self.table.database().connector.getSchemaPrivileges(self.table.schemaName()) + if self.table.schema() + else None + ) if not schema_priv: pass elif schema_priv[1] is False: # no usage privileges on the schema - tbl.append((QApplication.translate( - "DBManagerPlugin", "Privileges:"), - QApplication.translate( - "DBManagerPlugin", - " This user doesn't have usage privileges" - " for this schema!"))) + tbl.append( + ( + QApplication.translate("DBManagerPlugin", "Privileges:"), + QApplication.translate( + "DBManagerPlugin", + " This user doesn't have usage privileges" + " for this schema!", + ), + ) + ) else: table_priv = self.table.database().connector.getTablePrivileges( - (self.table.schemaName(), self.table.name)) + (self.table.schemaName(), self.table.name) + ) privileges = [] if table_priv[0]: privileges.append("select") @@ -193,35 +234,43 @@ def generalInfo(self): priv_string = ", ".join(privileges) else: priv_string = QApplication.translate( - "DBManagerPlugin", - ' This user has no privileges!') + "DBManagerPlugin", " This user has no privileges!" + ) tbl.append( - (QApplication.translate( - "DBManagerPlugin", "Privileges:"), - priv_string)) + (QApplication.translate("DBManagerPlugin", "Privileges:"), priv_string) + ) ret.append(HtmlTable(tbl)) if schema_priv and schema_priv[1]: - if (table_priv[0] and - not table_priv[1] and - not table_priv[2] and - not table_priv[3]): + if ( + table_priv[0] + and not table_priv[1] + and not table_priv[2] + and not table_priv[3] + ): ret.append( - HtmlParagraph(QApplication.translate( - "DBManagerPlugin", - " This user has read-only privileges."))) + HtmlParagraph( + QApplication.translate( + "DBManagerPlugin", + " This user has read-only privileges.", + ) + ) + ) # primary key defined? - if (not self.table.isView and - self.table.objectType != "MATERIALIZED VIEW"): + if not self.table.isView and self.table.objectType != "MATERIALIZED VIEW": pk = [fld for fld in self.table.fields() if fld.primaryKey] if len(pk) <= 0: ret.append( - HtmlParagraph(QApplication.translate( - "DBManagerPlugin", - " No primary key defined for this table!"))) + HtmlParagraph( + QApplication.translate( + "DBManagerPlugin", + " No primary key defined for this table!", + ) + ) + ) return ret @@ -232,19 +281,20 @@ def getSpatialInfo(self): if not info: return - tbl = [ - (QApplication.translate( - "DBManagerPlugin", "Library:"), info[0]) # , - ] + tbl = [(QApplication.translate("DBManagerPlugin", "Library:"), info[0])] # , ret.append(HtmlTable(tbl)) if not self.db.connector.has_geometry_columns: - ret.append(HtmlParagraph( - QApplication.translate( - "DBManagerPlugin", - " ALL_SDO_GEOM_METADATA table doesn't exist!\n" - "This table is essential for many GIS" - " applications for enumeration of tables."))) + ret.append( + HtmlParagraph( + QApplication.translate( + "DBManagerPlugin", + " ALL_SDO_GEOM_METADATA table doesn't exist!\n" + "This table is essential for many GIS" + " applications for enumeration of tables.", + ) + ) + ) return ret @@ -259,14 +309,15 @@ def fieldsDetails(self): QApplication.translate("DBManagerPlugin", "Length"), QApplication.translate("DBManagerPlugin", "Null"), QApplication.translate("DBManagerPlugin", "Default"), - QApplication.translate("DBManagerPlugin", "Comment")) + QApplication.translate("DBManagerPlugin", "Comment"), + ) tbl.append(HtmlTableHeader(header)) # add table contents for fld in self.table.fields(): char_max_len = fld.charMaxLen if fld.charMaxLen else "" if fld.modifier: - char_max_len = "{},{}".format(char_max_len, fld.modifier) + char_max_len = f"{char_max_len},{fld.modifier}" is_null_txt = "N" if fld.notNull else "Y" # make primary key field underlined @@ -274,8 +325,16 @@ def fieldsDetails(self): name = HtmlTableCol(fld.name, attrs) tbl.append( - (fld.num, name, fld.type2String(), char_max_len, - is_null_txt, fld.default2String(), fld.comment)) + ( + fld.num, + name, + fld.type2String(), + char_max_len, + is_null_txt, + fld.default2String(), + fld.comment, + ) + ) return HtmlTable(tbl, {"class": "header"}) @@ -286,24 +345,36 @@ def constraintsDetails(self): tbl = [] # define the table header - header = (QApplication.translate("DBManagerPlugin", "Name"), - QApplication.translate("DBManagerPlugin", "Type"), - QApplication.translate("DBManagerPlugin", "Column"), - QApplication.translate("DBManagerPlugin", "Status"), - QApplication.translate("DBManagerPlugin", "Validated"), - QApplication.translate("DBManagerPlugin", "Generated"), - QApplication.translate("DBManagerPlugin", "Check condition"), - QApplication.translate("DBManagerPlugin", "Foreign Table"), - QApplication.translate("DBManagerPlugin", "Foreign column"), - QApplication.translate("DBManagerPlugin", "On Delete")) + header = ( + QApplication.translate("DBManagerPlugin", "Name"), + QApplication.translate("DBManagerPlugin", "Type"), + QApplication.translate("DBManagerPlugin", "Column"), + QApplication.translate("DBManagerPlugin", "Status"), + QApplication.translate("DBManagerPlugin", "Validated"), + QApplication.translate("DBManagerPlugin", "Generated"), + QApplication.translate("DBManagerPlugin", "Check condition"), + QApplication.translate("DBManagerPlugin", "Foreign Table"), + QApplication.translate("DBManagerPlugin", "Foreign column"), + QApplication.translate("DBManagerPlugin", "On Delete"), + ) tbl.append(HtmlTableHeader(header)) # add table contents for con in self.table.constraints(): - tbl.append((con.name, con.type2String(), con.column, - con.status, con.validated, con.generated, - con.checkSource, con.foreignTable, - con.foreignKey, con.foreignOnDelete)) + tbl.append( + ( + con.name, + con.type2String(), + con.column, + con.status, + con.validated, + con.generated, + con.checkSource, + con.foreignTable, + con.foreignKey, + con.foreignOnDelete, + ) + ) return HtmlTable(tbl, {"class": "header"}) @@ -314,24 +385,36 @@ def indexesDetails(self): tbl = [] # define the table header - header = (QApplication.translate("DBManagerPlugin", "Name"), - QApplication.translate("DBManagerPlugin", "Column(s)"), - QApplication.translate("DBManagerPlugin", "Index Type"), - QApplication.translate("DBManagerPlugin", "Status"), - QApplication.translate("DBManagerPlugin", "Last analyzed"), - QApplication.translate("DBManagerPlugin", "Compression"), - QApplication.translate("DBManagerPlugin", "Uniqueness"), - QApplication.translate("DBManagerPlugin", "Action")) + header = ( + QApplication.translate("DBManagerPlugin", "Name"), + QApplication.translate("DBManagerPlugin", "Column(s)"), + QApplication.translate("DBManagerPlugin", "Index Type"), + QApplication.translate("DBManagerPlugin", "Status"), + QApplication.translate("DBManagerPlugin", "Last analyzed"), + QApplication.translate("DBManagerPlugin", "Compression"), + QApplication.translate("DBManagerPlugin", "Uniqueness"), + QApplication.translate("DBManagerPlugin", "Action"), + ) tbl.append(HtmlTableHeader(header)) # add table contents for idx in self.table.indexes(): # get the fields the index is defined on - tbl.append((idx.name, idx.column, idx.indexType, - idx.status, idx.analyzed, idx.compression, - idx.isUnique, - ('Rebuild' - """""".format(idx.name)))) + tbl.append( + ( + idx.name, + idx.column, + idx.indexType, + idx.status, + idx.analyzed, + idx.compression, + idx.isUnique, + ( + 'Rebuild' + """""".format(idx.name) + ), + ) + ) return HtmlTable(tbl, {"class": "header"}) @@ -347,26 +430,31 @@ def triggersDetails(self): QApplication.translate("DBManagerPlugin", "Name"), QApplication.translate("DBManagerPlugin", "Event"), QApplication.translate("DBManagerPlugin", "Type"), - QApplication.translate("DBManagerPlugin", "Enabled")) + QApplication.translate("DBManagerPlugin", "Enabled"), + ) tbl.append(HtmlTableHeader(header)) # add table contents for trig in self.table.triggers(): - name = ("""{0} ({1})""".format(trig.name, "delete")) + name = """{0} ({1})""".format( + trig.name, "delete" + ) if trig.enabled == "ENABLED": enabled, action = ( QApplication.translate("DBManagerPlugin", "Yes"), - "disable") + "disable", + ) else: enabled, action = ( QApplication.translate("DBManagerPlugin", "No"), - "enable") + "enable", + ) - txt_enabled = ("""{0} ({2})""".format( - enabled, trig.name, action)) + txt_enabled = ( + """{0} ({2})""".format(enabled, trig.name, action) + ) tbl.append((name, trig.event, trig.type, txt_enabled)) @@ -377,9 +465,12 @@ def triggersDetails(self): QApplication.translate( "DBManagerPlugin", '' - 'Enable all triggers / ' + "Enable all triggers / " '' - 'Disable all triggers'))) + "Disable all triggers", + ) + ) + ) return ret @@ -392,9 +483,10 @@ def getTableInfo(self): else: ret.append( HtmlSection( - QApplication.translate( - "DBManagerPlugin", 'General info'), - general_info)) + QApplication.translate("DBManagerPlugin", "General info"), + general_info, + ) + ) # spatial info spatial_info = self.spatialInfo() @@ -404,12 +496,13 @@ def getTableInfo(self): spatial_info = HtmlContent(spatial_info) if not spatial_info.hasContents(): spatial_info = QApplication.translate( - "DBManagerPlugin", - ' This is not a spatial table.') + "DBManagerPlugin", " This is not a spatial table." + ) ret.append( HtmlSection( - self.table.database().connection().typeNameString(), - spatial_info)) + self.table.database().connection().typeNameString(), spatial_info + ) + ) # fields fields_details = self.fieldsDetails() @@ -418,10 +511,9 @@ def getTableInfo(self): else: ret.append( HtmlSection( - QApplication.translate( - "DBManagerPlugin", - 'Fields'), - fields_details)) + QApplication.translate("DBManagerPlugin", "Fields"), fields_details + ) + ) # constraints constraints_details = self.constraintsDetails() @@ -430,10 +522,10 @@ def getTableInfo(self): else: ret.append( HtmlSection( - QApplication.translate( - "DBManagerPlugin", - 'Constraints'), - constraints_details)) + QApplication.translate("DBManagerPlugin", "Constraints"), + constraints_details, + ) + ) # indexes indexes_details = self.indexesDetails() @@ -442,10 +534,10 @@ def getTableInfo(self): else: ret.append( HtmlSection( - QApplication.translate( - "DBManagerPlugin", - 'Indexes'), - indexes_details)) + QApplication.translate("DBManagerPlugin", "Indexes"), + indexes_details, + ) + ) # triggers triggers_details = self.triggersDetails() @@ -454,19 +546,21 @@ def getTableInfo(self): else: ret.append( HtmlSection( - QApplication.translate( - "DBManagerPlugin", - 'Triggers'), - triggers_details)) + QApplication.translate("DBManagerPlugin", "Triggers"), + triggers_details, + ) + ) if self.table.objectType == "MATERIALIZED VIEW": mview_info = self.getMViewInfo() ret.append( HtmlSection( QApplication.translate( - "DBManagerPlugin", - 'Materialized View information'), - mview_info)) + "DBManagerPlugin", "Materialized View information" + ), + mview_info, + ) + ) return ret @@ -477,39 +571,44 @@ def getMViewInfo(self): ret = [] tbl = [] values = self.table.getMViewInfo() - tbl.append((QApplication.translate("DBManagerPlugin", - "Refresh Mode:"), - values[0])) - tbl.append((QApplication.translate("DBManagerPlugin", - "Refresh Method:"), - values[1])) - tbl.append((QApplication.translate("DBManagerPlugin", - "Build Mode:"), - values[2])) - tbl.append((QApplication.translate("DBManagerPlugin", - "Last Refresh Date:"), - values[5])) - tbl.append((QApplication.translate("DBManagerPlugin", - "Last Refresh Type:"), - values[4])) - tbl.append((QApplication.translate("DBManagerPlugin", - "Fast Refreshable:"), - values[3])) - tbl.append((QApplication.translate("DBManagerPlugin", - "Staleness:"), - values[6])) - tbl.append((QApplication.translate("DBManagerPlugin", - "Stale since:"), - values[7])) - tbl.append((QApplication.translate("DBManagerPlugin", - "Compile State:"), - values[8])) - tbl.append((QApplication.translate("DBManagerPlugin", - "Use no index:"), - values[9])) - tbl.append(('{}'.format( - QApplication.translate("DBManagerPlugin", "Refresh the materialized view")), - "")) + tbl.append( + (QApplication.translate("DBManagerPlugin", "Refresh Mode:"), values[0]) + ) + tbl.append( + (QApplication.translate("DBManagerPlugin", "Refresh Method:"), values[1]) + ) + tbl.append( + (QApplication.translate("DBManagerPlugin", "Build Mode:"), values[2]) + ) + tbl.append( + (QApplication.translate("DBManagerPlugin", "Last Refresh Date:"), values[5]) + ) + tbl.append( + (QApplication.translate("DBManagerPlugin", "Last Refresh Type:"), values[4]) + ) + tbl.append( + (QApplication.translate("DBManagerPlugin", "Fast Refreshable:"), values[3]) + ) + tbl.append((QApplication.translate("DBManagerPlugin", "Staleness:"), values[6])) + tbl.append( + (QApplication.translate("DBManagerPlugin", "Stale since:"), values[7]) + ) + tbl.append( + (QApplication.translate("DBManagerPlugin", "Compile State:"), values[8]) + ) + tbl.append( + (QApplication.translate("DBManagerPlugin", "Use no index:"), values[9]) + ) + tbl.append( + ( + '{}'.format( + QApplication.translate( + "DBManagerPlugin", "Refresh the materialized view" + ) + ), + "", + ) + ) ret.append(HtmlTable(tbl)) return ret @@ -529,8 +628,7 @@ def getViewInfo(self): # Syntax highlight lexer = get_lexer_by_name("sql") - formatter = HtmlFormatter( - linenos=True, cssclass="source", noclasses=True) + formatter = HtmlFormatter(linenos=True, cssclass="source", noclasses=True) result = highlight(view_def, lexer, formatter) if view_def: @@ -539,9 +637,8 @@ def getViewInfo(self): else: title = "Materialized View Definition" ret.append( - HtmlSection( - QApplication.translate("DBManagerPlugin", title), - result)) + HtmlSection(QApplication.translate("DBManagerPlugin", title), result) + ) return ret @@ -565,35 +662,41 @@ def spatialInfo(self): return ret tbl = [ - (QApplication.translate("DBManagerPlugin", "Column:"), - self.table.geomColumn), - (QApplication.translate("DBManagerPlugin", "Geometry:"), - self.table.geomType), - (QApplication.translate("DBManagerPlugin", - "QGIS Geometry type:"), - QgsWkbTypes.displayString(self.table.wkbType)) + ( + QApplication.translate("DBManagerPlugin", "Column:"), + self.table.geomColumn, + ), + ( + QApplication.translate("DBManagerPlugin", "Geometry:"), + self.table.geomType, + ), + ( + QApplication.translate("DBManagerPlugin", "QGIS Geometry type:"), + QgsWkbTypes.displayString(self.table.wkbType), + ), ] # only if we have info from geometry_columns if self.table.geomDim: tbl.append( - (QApplication.translate( - "DBManagerPlugin", - "Dimension:"), - self.table.geomDim)) + ( + QApplication.translate("DBManagerPlugin", "Dimension:"), + self.table.geomDim, + ) + ) srid = self.table.srid if self.table.srid else -1 if srid != -1: - sr_info = ( - self.table.database().connector.getSpatialRefInfo(srid)) + sr_info = self.table.database().connector.getSpatialRefInfo(srid) else: - sr_info = QApplication.translate("DBManagerPlugin", - "Undefined") + sr_info = QApplication.translate("DBManagerPlugin", "Undefined") if sr_info: tbl.append( - (QApplication.translate( - "DBManagerPlugin", "Spatial ref:"), - "{} ({})".format(sr_info, srid))) + ( + QApplication.translate("DBManagerPlugin", "Spatial ref:"), + f"{sr_info} ({srid})", + ) + ) # estimated extent if not self.table.estimatedExtent: @@ -605,53 +708,65 @@ def spatialInfo(self): self.table.blockSignals(False) if self.table.estimatedExtent: - estimated_extent_str = ("{:.9f}, {:.9f} - {:.9f}, " - "{:.9f}".format( - *self.table.estimatedExtent)) + estimated_extent_str = "{:.9f}, {:.9f} - {:.9f}, " "{:.9f}".format( + *self.table.estimatedExtent + ) tbl.append( - (QApplication.translate( - "DBManagerPlugin", "Estimated extent:"), - estimated_extent_str)) + ( + QApplication.translate("DBManagerPlugin", "Estimated extent:"), + estimated_extent_str, + ) + ) # extent extent_str = None if self.table.extent and len(self.table.extent) == 4: - extent_str = ("{:.9f}, {:.9f} - {:.9f}, " - "{:.9f}".format(*self.table.extent)) - elif (self.table.rowCount is not None and self.table.rowCount > 0) or (self.table.estimatedRowCount is not None and self.table.estimatedRowCount > 0): + extent_str = "{:.9f}, {:.9f} - {:.9f}, " "{:.9f}".format(*self.table.extent) + elif (self.table.rowCount is not None and self.table.rowCount > 0) or ( + self.table.estimatedRowCount is not None + and self.table.estimatedRowCount > 0 + ): # Can't calculate an extent on empty layer extent_str = QApplication.translate( "DBManagerPlugin", - '(unknown) (find out)') + '(unknown) (find out)', + ) if extent_str: tbl.append( - (QApplication.translate( - "DBManagerPlugin", "Extent:"), - extent_str)) + (QApplication.translate("DBManagerPlugin", "Extent:"), extent_str) + ) ret.append(HtmlTable(tbl)) # Handle extent update metadata - if (self.table.extent and - self.table.extent != self.table.estimatedExtent and - self.table.canUpdateMetadata()): + if ( + self.table.extent + and self.table.extent != self.table.estimatedExtent + and self.table.canUpdateMetadata() + ): ret.append( HtmlParagraph( QApplication.translate( "DBManagerPlugin", - ' Metadata extent is different from' + " Metadata extent is different from" ' real extent. You should update it!'))) + '/update">update it!', + ) + ) + ) # is there an entry in geometry_columns? - if self.table.geomType.lower() == 'geometry': + if self.table.geomType.lower() == "geometry": ret.append( HtmlParagraph( QApplication.translate( "DBManagerPlugin", - " There is no entry in geometry_columns!"))) + " There is no entry in geometry_columns!", + ) + ) + ) # find out whether the geometry column has spatial index on it if not self.table.isView: @@ -660,8 +775,11 @@ def spatialInfo(self): HtmlParagraph( QApplication.translate( "DBManagerPlugin", - ' No spatial index defined (' - 'create it).'))) + "create it).", + ) + ) + ) return ret diff --git a/python/plugins/db_manager/db_plugins/oracle/plugin.py b/python/plugins/db_manager/db_plugins/oracle/plugin.py index 2c19063065ca..d3de0e4c70fe 100644 --- a/python/plugins/db_manager/db_plugins/oracle/plugin.py +++ b/python/plugins/db_manager/db_plugins/oracle/plugin.py @@ -22,10 +22,7 @@ """ # this will disable the dbplugin if the connector raise an ImportError -from typing import ( - Optional, - Union -) +from typing import Optional, Union from .connector import OracleDBConnector @@ -35,9 +32,19 @@ from qgis.core import QgsApplication, QgsVectorLayer, NULL, QgsSettings -from ..plugin import ConnectionError, InvalidDataException, DBPlugin, \ - Database, Schema, Table, VectorTable, TableField, TableConstraint, \ - TableIndex, TableTrigger +from ..plugin import ( + ConnectionError, + InvalidDataException, + DBPlugin, + Database, + Schema, + Table, + VectorTable, + TableField, + TableConstraint, + TableIndex, + TableTrigger, +) from qgis.core import QgsCredentials @@ -54,19 +61,19 @@ def icon(self): @classmethod def typeName(self): - return 'oracle' + return "oracle" @classmethod def typeNameString(self): - return QCoreApplication.translate('db_manager', 'Oracle Spatial') + return QCoreApplication.translate("db_manager", "Oracle Spatial") @classmethod def providerName(self): - return 'oracle' + return "oracle" @classmethod def connectionSettingsKey(self): - return '/Oracle/connections' + return "/Oracle/connections" def connectToUri(self, uri): self.db = self.databasesFactory(self, uri) @@ -80,35 +87,44 @@ def databasesFactory(self, connection, uri): def connect(self, parent=None): conn_name = self.connectionName() settings = QgsSettings() - settings.beginGroup("/{}/{}".format( - self.connectionSettingsKey(), conn_name)) + settings.beginGroup(f"/{self.connectionSettingsKey()}/{conn_name}") if not settings.contains("database"): # non-existent entry? raise InvalidDataException( - self.tr('There is no defined database connection "{}".'.format( - conn_name))) + self.tr(f'There is no defined database connection "{conn_name}".') + ) from qgis.core import QgsDataSourceUri + uri = QgsDataSourceUri() settingsList = ["host", "port", "database", "username", "password"] host, port, database, username, password = ( - settings.value(x, "", type=str) for x in settingsList) + settings.value(x, "", type=str) for x in settingsList + ) # get all of the connection options - useEstimatedMetadata = settings.value( - "estimatedMetadata", False, type=bool) - uri.setParam('userTablesOnly', str( - settings.value("userTablesOnly", False, type=bool))) - uri.setParam('geometryColumnsOnly', str( - settings.value("geometryColumnsOnly", False, type=bool))) - uri.setParam('allowGeometrylessTables', str( - settings.value("allowGeometrylessTables", False, type=bool))) - uri.setParam('onlyExistingTypes', str( - settings.value("onlyExistingTypes", False, type=bool))) - uri.setParam('includeGeoAttributes', str( - settings.value("includeGeoAttributes", False, type=bool))) + useEstimatedMetadata = settings.value("estimatedMetadata", False, type=bool) + uri.setParam( + "userTablesOnly", str(settings.value("userTablesOnly", False, type=bool)) + ) + uri.setParam( + "geometryColumnsOnly", + str(settings.value("geometryColumnsOnly", False, type=bool)), + ) + uri.setParam( + "allowGeometrylessTables", + str(settings.value("allowGeometrylessTables", False, type=bool)), + ) + uri.setParam( + "onlyExistingTypes", + str(settings.value("onlyExistingTypes", False, type=bool)), + ) + uri.setParam( + "includeGeoAttributes", + str(settings.value("includeGeoAttributes", False, type=bool)), + ) settings.endGroup() @@ -126,7 +142,8 @@ def connect(self, parent=None): max_attempts = 3 for i in range(max_attempts): (ok, username, password) = QgsCredentials.instance().get( - uri.connectionInfo(False), username, password, err) + uri.connectionInfo(False), username, password, err + ) if not ok: return False @@ -141,8 +158,7 @@ def connect(self, parent=None): err = str(e) continue - QgsCredentials.instance().put( - uri.connectionInfo(False), username, password) + QgsCredentials.instance().put(uri.connectionInfo(False), username, password) return True @@ -166,6 +182,7 @@ def vectorTablesFactory(self, row, db, schema=None): def info(self): from .info_model import ORDatabaseInfo + return ORDatabaseInfo(self) def schemasFactory(self, row, db): @@ -174,7 +191,7 @@ def schemasFactory(self, row, db): def columnUniqueValuesModel(self, col, table, limit=10): l = "" if limit: - l = "WHERE ROWNUM < {:d}".format(limit) + l = f"WHERE ROWNUM < {limit:d}" con = self.database().connector # Prevent geometry column show tableName = table.replace('"', "").split(".") @@ -185,11 +202,12 @@ def columnUniqueValuesModel(self, col, table, limit=10): if con.isGeometryColumn(tableName, colName): return None - query = "SELECT DISTINCT {} FROM {} {}".format(col, table, l) + query = f"SELECT DISTINCT {col} FROM {table} {l}" return self.sqlResultModel(query, self) def sqlResultModel(self, sql, parent): from .data_model import ORSqlResultModel + return ORSqlResultModel(self, sql, parent) def sqlResultModelAsync(self, sql, parent): @@ -197,9 +215,16 @@ def sqlResultModelAsync(self, sql, parent): return ORSqlResultModelAsync(self, sql, parent) - def toSqlLayer(self, sql, geomCol, uniqueCol, - layerName="QueryLayer", layerType=None, - avoidSelectById=False, filter=""): + def toSqlLayer( + self, + sql, + geomCol, + uniqueCol, + layerName="QueryLayer", + layerType=None, + avoidSelectById=False, + filter="", + ): uri = self.uri() con = self.database().connector @@ -207,8 +232,7 @@ def toSqlLayer(self, sql, geomCol, uniqueCol, if uniqueCol is not None: uniqueCol = uniqueCol.strip('"').replace('""', '"') - uri.setDataSource("", "({}\n)".format( - sql), geomCol, filter, uniqueCol) + uri.setDataSource("", f"({sql}\n)", geomCol, filter, uniqueCol) if avoidSelectById: uri.disableSelectAtId(True) @@ -218,8 +242,7 @@ def toSqlLayer(self, sql, geomCol, uniqueCol, # handling undetermined geometry type if not vlayer.isValid(): - wkbType, srid = con.getTableMainGeomType( - "({}\n)".format(sql), geomCol) + wkbType, srid = con.getTableMainGeomType(f"({sql}\n)", geomCol) uri.setWkbType(wkbType) if srid: uri.setSrid(str(srid)) @@ -228,45 +251,76 @@ def toSqlLayer(self, sql, geomCol, uniqueCol, return vlayer def registerDatabaseActions(self, mainWindow): - action = QAction(QApplication.translate( - "DBManagerPlugin", "&Re-connect"), self) - mainWindow.registerAction(action, QApplication.translate( - "DBManagerPlugin", "&Database"), self.reconnectActionSlot) + action = QAction(QApplication.translate("DBManagerPlugin", "&Re-connect"), self) + mainWindow.registerAction( + action, + QApplication.translate("DBManagerPlugin", "&Database"), + self.reconnectActionSlot, + ) if self.schemas(): - action = QAction(QApplication.translate( - "DBManagerPlugin", "&Create Schema…"), self) - mainWindow.registerAction(action, QApplication.translate( - "DBManagerPlugin", "&Schema"), self.createSchemaActionSlot) - action = QAction(QApplication.translate( - "DBManagerPlugin", "&Delete (Empty) Schema…"), self) - mainWindow.registerAction(action, QApplication.translate( - "DBManagerPlugin", "&Schema"), self.deleteSchemaActionSlot) - - action = QAction(QApplication.translate( - "DBManagerPlugin", "Delete Selected Item"), self) + action = QAction( + QApplication.translate("DBManagerPlugin", "&Create Schema…"), self + ) + mainWindow.registerAction( + action, + QApplication.translate("DBManagerPlugin", "&Schema"), + self.createSchemaActionSlot, + ) + action = QAction( + QApplication.translate("DBManagerPlugin", "&Delete (Empty) Schema…"), + self, + ) + mainWindow.registerAction( + action, + QApplication.translate("DBManagerPlugin", "&Schema"), + self.deleteSchemaActionSlot, + ) + + action = QAction( + QApplication.translate("DBManagerPlugin", "Delete Selected Item"), self + ) mainWindow.registerAction(action, None, self.deleteActionSlot) action.setShortcuts(QKeySequence.StandardKey.Delete) - action = QAction(QgsApplication.getThemeIcon("/mActionCreateTable.svg"), - QApplication.translate( - "DBManagerPlugin", "&Create Table…"), self) - mainWindow.registerAction(action, QApplication.translate( - "DBManagerPlugin", "&Table"), self.createTableActionSlot) - action = QAction(QgsApplication.getThemeIcon("/mActionEditTable.svg"), - QApplication.translate( - "DBManagerPlugin", "&Edit Table…"), self) - mainWindow.registerAction(action, QApplication.translate( - "DBManagerPlugin", "&Table"), self.editTableActionSlot) - action = QAction(QgsApplication.getThemeIcon("/mActionDeleteTable.svg"), - QApplication.translate( - "DBManagerPlugin", "&Delete Table/View…"), self) - mainWindow.registerAction(action, QApplication.translate( - "DBManagerPlugin", "&Table"), self.deleteTableActionSlot) - action = QAction(QApplication.translate( - "DBManagerPlugin", "&Empty Table…"), self) - mainWindow.registerAction(action, QApplication.translate( - "DBManagerPlugin", "&Table"), self.emptyTableActionSlot) + action = QAction( + QgsApplication.getThemeIcon("/mActionCreateTable.svg"), + QApplication.translate("DBManagerPlugin", "&Create Table…"), + self, + ) + mainWindow.registerAction( + action, + QApplication.translate("DBManagerPlugin", "&Table"), + self.createTableActionSlot, + ) + action = QAction( + QgsApplication.getThemeIcon("/mActionEditTable.svg"), + QApplication.translate("DBManagerPlugin", "&Edit Table…"), + self, + ) + mainWindow.registerAction( + action, + QApplication.translate("DBManagerPlugin", "&Table"), + self.editTableActionSlot, + ) + action = QAction( + QgsApplication.getThemeIcon("/mActionDeleteTable.svg"), + QApplication.translate("DBManagerPlugin", "&Delete Table/View…"), + self, + ) + mainWindow.registerAction( + action, + QApplication.translate("DBManagerPlugin", "&Table"), + self.deleteTableActionSlot, + ) + action = QAction( + QApplication.translate("DBManagerPlugin", "&Empty Table…"), self + ) + mainWindow.registerAction( + action, + QApplication.translate("DBManagerPlugin", "&Table"), + self.emptyTableActionSlot, + ) def supportsComment(self): return False @@ -298,36 +352,40 @@ def __init__(self, row, db, schema=None): def getDates(self): """Grab the creation/modification dates of the table""" self.creationDate, self.modificationDate = ( - self.database().connector.getTableDates((self.schemaName(), - self.name))) + self.database().connector.getTableDates((self.schemaName(), self.name)) + ) def refreshRowEstimation(self): """Use ALL_ALL_TABLE to get an estimation of rows""" if self.isView: self.estimatedRowCount = 0 - self.estimatedRowCount = ( - self.database().connector.getTableRowEstimation( - (self.schemaName(), self.name))) + self.estimatedRowCount = self.database().connector.getTableRowEstimation( + (self.schemaName(), self.name) + ) def getType(self): """Grab the type of object for the table""" self.objectType = self.database().connector.getTableType( - (self.schemaName(), self.name)) + (self.schemaName(), self.name) + ) def getComment(self): """Grab the general comment of the table/view""" self.comment = self.database().connector.getTableComment( - (self.schemaName(), self.name), self.objectType) + (self.schemaName(), self.name), self.objectType + ) def getDefinition(self): return self.database().connector.getDefinition( - (self.schemaName(), self.name), self.objectType) + (self.schemaName(), self.name), self.objectType + ) def getMViewInfo(self): if self.objectType == "MATERIALIZED VIEW": return self.database().connector.getMViewInfo( - (self.schemaName(), self.name)) + (self.schemaName(), self.name) + ) else: return None @@ -339,22 +397,25 @@ def runAction(self, action): self.refreshRowCount() return True elif action.startswith("index/"): - parts = action.split('/') + parts = action.split("/") index_name = parts[1] index_action = parts[2] msg = QApplication.translate( "DBManagerPlugin", - "Do you want to {} index {}?".format( - index_action, index_name)) + f"Do you want to {index_action} index {index_name}?", + ) QApplication.restoreOverrideCursor() try: - if QMessageBox.question( + if ( + QMessageBox.question( None, - QApplication.translate( - "DBManagerPlugin", "Table Index"), + QApplication.translate("DBManagerPlugin", "Table Index"), msg, - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) == QMessageBox.StandardButton.No: + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + ) + == QMessageBox.StandardButton.No + ): return False finally: QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) @@ -362,14 +423,14 @@ def runAction(self, action): if index_action == "rebuild": self.aboutToChange.emit() self.database().connector.rebuildTableIndex( - (self.schemaName(), self.name), index_name) + (self.schemaName(), self.name), index_name + ) self.refreshIndexes() return True elif action.startswith("mview/"): if action == "mview/refresh": self.aboutToChange.emit() - self.database().connector.refreshMView( - (self.schemaName(), self.name)) + self.database().connector.refreshMView((self.schemaName(), self.name)) return True return Table.runAction(self, action) @@ -388,14 +449,16 @@ def tableTriggersFactory(self, row, table): def info(self): from .info_model import ORTableInfo + return ORTableInfo(self) def tableDataModel(self, parent): from .data_model import ORTableDataModel + return ORTableDataModel(self, parent) def getValidQgisUniqueFields(self, onlyOne=False): - """ list of fields valid to load the table as layer in QGIS canvas. + """list of fields valid to load the table as layer in QGIS canvas. QGIS automatically search for a valid unique field, so it's needed only for queries and views. """ @@ -413,12 +476,22 @@ def getValidQgisUniqueFields(self, onlyOne=False): for idx in indexes: if idx.isUnique and len(idx.columns) == 1: fld = idx.fields()[idx.columns[0]] - if (fld.dataType == "NUMBER" and not fld.modifier and fld.notNull and fld not in ret): + if ( + fld.dataType == "NUMBER" + and not fld.modifier + and fld.notNull + and fld not in ret + ): ret.append(fld) # and finally append the other suitable fields for fld in self.fields(): - if (fld.dataType == "NUMBER" and not fld.modifier and fld.notNull and fld not in ret): + if ( + fld.dataType == "NUMBER" + and not fld.modifier + and fld.notNull + and fld not in ret + ): ret.append(fld) if onlyOne: @@ -427,13 +500,18 @@ def getValidQgisUniqueFields(self, onlyOne=False): def uri(self): uri = self.database().uri() - schema = self.schemaName() if self.schemaName() else '' - geomCol = self.geomColumn if self.type in [ - Table.VectorType, Table.RasterType] else "" - uniqueCol = self.getValidQgisUniqueFields( - True) if self.isView else None - uri.setDataSource(schema, self.name, geomCol if geomCol else None, - None, uniqueCol.name if uniqueCol else "") + schema = self.schemaName() if self.schemaName() else "" + geomCol = ( + self.geomColumn if self.type in [Table.VectorType, Table.RasterType] else "" + ) + uniqueCol = self.getValidQgisUniqueFields(True) if self.isView else None + uri.setDataSource( + schema, + self.name, + geomCol if geomCol else None, + None, + uniqueCol.name if uniqueCol else "", + ) # Handle geographic table if geomCol: @@ -448,11 +526,13 @@ class ORVectorTable(ORTable, VectorTable): def __init__(self, row, db, schema=None): ORTable.__init__(self, row[0:3], db, schema) VectorTable.__init__(self, db, schema) - self.geomColumn, self.geomType, self.wkbType, self.geomDim, \ - self.srid = row[-7:-2] + self.geomColumn, self.geomType, self.wkbType, self.geomDim, self.srid = row[ + -7:-2 + ] def info(self): from .info_model import ORVectorTableInfo + return ORVectorTableInfo(self) def runAction(self, action): @@ -468,13 +548,14 @@ def runAction(self, action): return VectorTable.runAction(self, action) def canUpdateMetadata(self): - return self.database().connector.canUpdateMetadata((self.schemaName(), - self.name)) + return self.database().connector.canUpdateMetadata( + (self.schemaName(), self.name) + ) def updateExtent(self): self.database().connector.updateMetadata( - (self.schemaName(), self.name), - self.geomColumn, extent=self.extent) + (self.schemaName(), self.name), self.geomColumn, extent=self.extent + ) self.refreshTableEstimatedExtent() self.refresh() @@ -490,11 +571,20 @@ def hasSpatialIndex(self, geom_column=None): class ORTableField(TableField): def __init__(self, row, table): - """ build fields information from query and find primary key """ + """build fields information from query and find primary key""" TableField.__init__(self, table) - self.num, self.name, self.dataType, self.charMaxLen, \ - self.modifier, self.notNull, self.hasDefault, \ - self.default, typeStr, self.comment = row + ( + self.num, + self.name, + self.dataType, + self.charMaxLen, + self.modifier, + self.notNull, + self.hasDefault, + self.default, + typeStr, + self.comment, + ) = row self.primaryKey = False self.num = int(self.num) @@ -523,18 +613,23 @@ def __init__(self, row, table): break def type2String(self): - if ("TIMESTAMP" in self.dataType or self.dataType in ["DATE", "SDO_GEOMETRY", "BINARY_FLOAT", "BINARY_DOUBLE"]): - return "{}".format(self.dataType) + if "TIMESTAMP" in self.dataType or self.dataType in [ + "DATE", + "SDO_GEOMETRY", + "BINARY_FLOAT", + "BINARY_DOUBLE", + ]: + return f"{self.dataType}" if self.charMaxLen in [None, -1]: - return "{}".format(self.dataType) + return f"{self.dataType}" elif self.modifier in [None, -1, 0]: - return "{}({})".format(self.dataType, self.charMaxLen) + return f"{self.dataType}({self.charMaxLen})" - return "{}({},{})".format(self.dataType, self.charMaxLen, - self.modifier) + return f"{self.dataType}({self.charMaxLen},{self.modifier})" - def update(self, new_name, new_type_str=None, new_not_null=None, - new_default_str=None): + def update( + self, new_name, new_type_str=None, new_not_null=None, new_default_str=None + ): self.table().aboutToChange.emit() if self.name == new_name: new_name = None @@ -545,10 +640,18 @@ def update(self, new_name, new_type_str=None, new_not_null=None, if self.default2String() == new_default_str: new_default_str = None - ret = self.table().database().connector.updateTableColumn( - (self.table().schemaName(), self.table().name), - self.name, new_name, new_type_str, - new_not_null, new_default_str) + ret = ( + self.table() + .database() + .connector.updateTableColumn( + (self.table().schemaName(), self.table().name), + self.name, + new_name, + new_type_str, + new_not_null, + new_default_str, + ) + ) # When changing a field, refresh also constraints and # indexes. @@ -560,17 +663,21 @@ def update(self, new_name, new_type_str=None, new_not_null=None, class ORTableConstraint(TableConstraint): - TypeCheck, TypeForeignKey, TypePrimaryKey, \ - TypeUnique, TypeUnknown = list(range(5)) + TypeCheck, TypeForeignKey, TypePrimaryKey, TypeUnique, TypeUnknown = list(range(5)) - types = {"c": TypeCheck, "r": TypeForeignKey, - "p": TypePrimaryKey, "u": TypeUnique} + types = {"c": TypeCheck, "r": TypeForeignKey, "p": TypePrimaryKey, "u": TypeUnique} def __init__(self, row, table): - """ build constraints info from query """ + """build constraints info from query""" TableConstraint.__init__(self, table) - self.name, constr_type_str, self.column, self.validated, \ - self.generated, self.status = row[0:6] + ( + self.name, + constr_type_str, + self.column, + self.validated, + self.generated, + self.status, + ) = row[0:6] constr_type_str = constr_type_str.lower() if constr_type_str in ORTableConstraint.types: @@ -608,10 +715,10 @@ def type2String(self): if self.type == ORTableConstraint.TypeUnique: return QApplication.translate("DBManagerPlugin", "Unique") - return QApplication.translate("DBManagerPlugin", 'Unknown') + return QApplication.translate("DBManagerPlugin", "Unknown") def fields(self): - """ Hack to make edit dialog box work """ + """Hack to make edit dialog box work""" fields = self.table().fields() field = None for fld in fields: @@ -627,11 +734,18 @@ class ORTableIndex(TableIndex): def __init__(self, row, table): TableIndex.__init__(self, table) - self.name, self.column, self.indexType, self.status, \ - self.analyzed, self.compression, self.isUnique = row + ( + self.name, + self.column, + self.indexType, + self.status, + self.analyzed, + self.compression, + self.isUnique, + ) = row def fields(self): - """ Hack to make edit dialog box work """ + """Hack to make edit dialog box work""" self.table().refreshFields() fields = self.table().fields() diff --git a/python/plugins/db_manager/db_plugins/oracle/sql_dictionary.py b/python/plugins/db_manager/db_plugins/oracle/sql_dictionary.py index 46e7e4211d37..4632abe69378 100644 --- a/python/plugins/db_manager/db_plugins/oracle/sql_dictionary.py +++ b/python/plugins/db_manager/db_plugins/oracle/sql_dictionary.py @@ -21,91 +21,481 @@ ***************************************************************************/ """ -__author__ = 'Médéric RIBREUX' -__date__ = 'August 2014' -__copyright__ = '(C) 2014, Médéric RIBREUX' +__author__ = "Médéric RIBREUX" +__date__ = "August 2014" +__copyright__ = "(C) 2014, Médéric RIBREUX" # keywords keywords = [ # From: # http://docs.oracle.com/cd/B19306_01/server.102/b14200/ap_keywd.htm - "ACCESS", "ADD", "ALL", "ALTER", "AND", "ANY", "AS", "ASC", - "AUDIT", "BETWEEN", "BY", "CHAR", "CHECK", "CLUSTER", "COLUMN", - "COMMENT", "COMPRESS", "CONNECT", "CREATE", "CURRENT", "DATE", - "DECIMAL", "DEFAULT", "DELETE", "DESC", "DISTINCT", "DROP", - "ELSE", "EXCLUSIVE", "EXISTS", "FILE", "FLOAT", "FOR", "FROM", - "GRANT", "GROUP", "HAVING", "IDENTIFIED", "IMMEDIATE", "IN", - "INCREMENT", "INDEX", "INITIAL", "INSERT", "INTEGER", "INTERSECT", - "INTO", "IS", "LEVEL", "LIKE", "LOCK", "LONG", "MAXEXTENTS", - "MINUS", "MLSLABEL", "MODE", "MODIFY", "NOAUDIT", "NOCOMPRESS", - "NOT", "NOWAIT", "NULL", "NUMBER", "OF", "OFFLINE", "ON", - "ONLINE", "OPTION", "OR", "ORDER", "PCTFREE", "PRIOR", - "PRIVILEGES", "PUBLIC", "RAW", "RENAME", "RESOURCE", "REVOKE", - "ROW", "ROWID", "ROWNUM", "ROWS", "SELECT", "SESSION", "SET", - "SHARE", "SIZE", "SMALLINT", "START", "SUCCESSFUL", "SYNONYM", - "SYSDATE", "TABLE", "THEN", "TO", "TRIGGER", "UID", "UNION", - "UNIQUE", "UPDATE", "USER", "VALIDATE", "VALUES", "VARCHAR", - "VARCHAR2", "VIEW", "WHENEVER", "WHERE", "WITH", + "ACCESS", + "ADD", + "ALL", + "ALTER", + "AND", + "ANY", + "AS", + "ASC", + "AUDIT", + "BETWEEN", + "BY", + "CHAR", + "CHECK", + "CLUSTER", + "COLUMN", + "COMMENT", + "COMPRESS", + "CONNECT", + "CREATE", + "CURRENT", + "DATE", + "DECIMAL", + "DEFAULT", + "DELETE", + "DESC", + "DISTINCT", + "DROP", + "ELSE", + "EXCLUSIVE", + "EXISTS", + "FILE", + "FLOAT", + "FOR", + "FROM", + "GRANT", + "GROUP", + "HAVING", + "IDENTIFIED", + "IMMEDIATE", + "IN", + "INCREMENT", + "INDEX", + "INITIAL", + "INSERT", + "INTEGER", + "INTERSECT", + "INTO", + "IS", + "LEVEL", + "LIKE", + "LOCK", + "LONG", + "MAXEXTENTS", + "MINUS", + "MLSLABEL", + "MODE", + "MODIFY", + "NOAUDIT", + "NOCOMPRESS", + "NOT", + "NOWAIT", + "NULL", + "NUMBER", + "OF", + "OFFLINE", + "ON", + "ONLINE", + "OPTION", + "OR", + "ORDER", + "PCTFREE", + "PRIOR", + "PRIVILEGES", + "PUBLIC", + "RAW", + "RENAME", + "RESOURCE", + "REVOKE", + "ROW", + "ROWID", + "ROWNUM", + "ROWS", + "SELECT", + "SESSION", + "SET", + "SHARE", + "SIZE", + "SMALLINT", + "START", + "SUCCESSFUL", + "SYNONYM", + "SYSDATE", + "TABLE", + "THEN", + "TO", + "TRIGGER", + "UID", + "UNION", + "UNIQUE", + "UPDATE", + "USER", + "VALIDATE", + "VALUES", + "VARCHAR", + "VARCHAR2", + "VIEW", + "WHENEVER", + "WHERE", + "WITH", # From http://docs.oracle.com/cd/B13789_01/appdev.101/a42525/apb.htm - "ADMIN", "CURSOR", "FOUND", "MOUNT", "AFTER", "CYCLE", "FUNCTION", - "NEXT", "ALLOCATE", "DATABASE", "GO", "NEW", "ANALYZE", - "DATAFILE", "GOTO", "NOARCHIVELOG", "ARCHIVE", "DBA", "GROUPS", - "NOCACHE", "ARCHIVELOG", "DEC", "INCLUDING", "NOCYCLE", - "AUTHORIZATION", "DECLARE", "INDICATOR", "NOMAXVALUE", "AVG", - "DISABLE", "INITRANS", "NOMINVALUE", "BACKUP", "DISMOUNT", - "INSTANCE", "NONE", "BEGIN", "DOUBLE", "INT", "NOORDER", "BECOME", - "DUMP", "KEY", "NORESETLOGS", "BEFORE", "EACH", "LANGUAGE", - "NORMAL", "BLOCK", "ENABLE", "LAYER", "NOSORT", "BODY", "END", - "LINK", "NUMERIC", "CACHE", "ESCAPE", "LISTS", "OFF", "CANCEL", - "EVENTS", "LOGFILE", "OLD", "CASCADE", "EXCEPT", "MANAGE", "ONLY", - "CHANGE", "EXCEPTIONS", "MANUAL", "OPEN", "CHARACTER", "EXEC", - "MAX", "OPTIMAL", "CHECKPOINT", "EXPLAIN", "MAXDATAFILES", "OWN", - "CLOSE", "EXECUTE", "MAXINSTANCES", "PACKAGE", "COBOL", "EXTENT", - "MAXLOGFILES", "PARALLEL", "COMMIT", "EXTERNALLY", - "MAXLOGHISTORY", "PCTINCREASE", "COMPILE", "FETCH", - "MAXLOGMEMBERS", "PCTUSED", "CONSTRAINT", "FLUSH", "MAXTRANS", - "PLAN", "CONSTRAINTS", "FREELIST", "MAXVALUE", "PLI", "CONTENTS", - "FREELISTS", "MIN", "PRECISION", "CONTINUE", "FORCE", - "MINEXTENTS", "PRIMARY", "CONTROLFILE", "FOREIGN", "MINVALUE", - "PRIVATE", "COUNT", "FORTRAN", "MODULE", "PROCEDURE", "PROFILE", - "SAVEPOINT", "SQLSTATE", "TRACING", "QUOTA", "SCHEMA", - "STATEMENT_ID", "TRANSACTION", "READ", "SCN", "STATISTICS", - "TRIGGERS", "REAL", "SECTION", "STOP", "TRUNCATE", "RECOVER", - "SEGMENT", "STORAGE", "UNDER", "REFERENCES", "SEQUENCE", "SUM", - "UNLIMITED", "REFERENCING", "SHARED", "SWITCH", "UNTIL", - "RESETLOGS", "SNAPSHOT", "SYSTEM", "USE", "RESTRICTED", "SOME", - "TABLES", "USING", "REUSE", "SORT", "TABLESPACE", "WHEN", "ROLE", - "SQL", "TEMPORARY", "WRITE", "ROLES", "SQLCODE", "THREAD", "WORK", - "ROLLBACK", "SQLERROR", "TIME", "ABORT", "BETWEEN", "CRASH", - "DIGITS", "ACCEPT", "BINARY_INTEGER", "CREATE", "DISPOSE", - "ACCESS", "BODY", "CURRENT", "DISTINCT", "ADD", "BOOLEAN", - "CURRVAL", "DO", "ALL", "BY", "CURSOR", "DROP", "ALTER", "CASE", - "DATABASE", "ELSE", "AND", "CHAR", "DATA_BASE", "ELSIF", "ANY", - "CHAR_BASE", "DATE", "END", "ARRAY", "CHECK", "DBA", "ENTRY", - "ARRAYLEN", "CLOSE", "DEBUGOFF", "EXCEPTION", "AS", "CLUSTER", - "DEBUGON", "EXCEPTION_INIT", "ASC", "CLUSTERS", "DECLARE", - "EXISTS", "ASSERT", "COLAUTH", "DECIMAL", "EXIT", "ASSIGN", - "COLUMNS", "DEFAULT", "FALSE", "AT", "COMMIT", "DEFINITION", - "FETCH", "AUTHORIZATION", "COMPRESS", "DELAY", "FLOAT", "AVG", - "CONNECT", "DELETE", "FOR", "BASE_TABLE", "CONSTANT", "DELTA", - "FORM", "BEGIN", "COUNT", "DESC", "FROM", "FUNCTION", "NEW", - "RELEASE", "SUM", "GENERIC", "NEXTVAL", "REMR", "TABAUTH", "GOTO", - "NOCOMPRESS", "RENAME", "TABLE", "GRANT", "NOT", "RESOURCE", - "TABLES", "GROUP", "NULL", "RETURN", "TASK", "HAVING", "NUMBER", - "REVERSE", "TERMINATE", "IDENTIFIED", "NUMBER_BASE", "REVOKE", - "THEN", "IF", "OF", "ROLLBACK", "TO", "IN", "ON", "ROWID", "TRUE", - "INDEX", "OPEN", "ROWLABEL", "TYPE", "INDEXES", "OPTION", - "ROWNUM", "UNION", "INDICATOR", "OR", "ROWTYPE", "UNIQUE", - "INSERT", "ORDER", "RUN", "UPDATE", "INTEGER", "OTHERS", - "SAVEPOINT", "USE", "INTERSECT", "OUT", "SCHEMA", "VALUES", - "INTO", "PACKAGE", "SELECT", "VARCHAR", "IS", "PARTITION", - "SEPARATE", "VARCHAR2", "LEVEL", "PCTFREE", "SET", "VARIANCE", - "LIKE", "POSITIVE", "SIZE", "VIEW", "LIMITED", "PRAGMA", - "SMALLINT", "VIEWS", "LOOP", "PRIOR", "SPACE", "WHEN", "MAX", - "PRIVATE", "SQL", "WHERE", "MIN", "PROCEDURE", "SQLCODE", "WHILE", - "MINUS", "PUBLIC", "SQLERRM", "WITH", "MLSLABEL", "RAISE", - "START", "WORK", "MOD", "RANGE", "STATEMENT", "XOR", "MODE", - "REAL", "STDDEV", "NATURAL", "RECORD", "SUBTYPE" + "ADMIN", + "CURSOR", + "FOUND", + "MOUNT", + "AFTER", + "CYCLE", + "FUNCTION", + "NEXT", + "ALLOCATE", + "DATABASE", + "GO", + "NEW", + "ANALYZE", + "DATAFILE", + "GOTO", + "NOARCHIVELOG", + "ARCHIVE", + "DBA", + "GROUPS", + "NOCACHE", + "ARCHIVELOG", + "DEC", + "INCLUDING", + "NOCYCLE", + "AUTHORIZATION", + "DECLARE", + "INDICATOR", + "NOMAXVALUE", + "AVG", + "DISABLE", + "INITRANS", + "NOMINVALUE", + "BACKUP", + "DISMOUNT", + "INSTANCE", + "NONE", + "BEGIN", + "DOUBLE", + "INT", + "NOORDER", + "BECOME", + "DUMP", + "KEY", + "NORESETLOGS", + "BEFORE", + "EACH", + "LANGUAGE", + "NORMAL", + "BLOCK", + "ENABLE", + "LAYER", + "NOSORT", + "BODY", + "END", + "LINK", + "NUMERIC", + "CACHE", + "ESCAPE", + "LISTS", + "OFF", + "CANCEL", + "EVENTS", + "LOGFILE", + "OLD", + "CASCADE", + "EXCEPT", + "MANAGE", + "ONLY", + "CHANGE", + "EXCEPTIONS", + "MANUAL", + "OPEN", + "CHARACTER", + "EXEC", + "MAX", + "OPTIMAL", + "CHECKPOINT", + "EXPLAIN", + "MAXDATAFILES", + "OWN", + "CLOSE", + "EXECUTE", + "MAXINSTANCES", + "PACKAGE", + "COBOL", + "EXTENT", + "MAXLOGFILES", + "PARALLEL", + "COMMIT", + "EXTERNALLY", + "MAXLOGHISTORY", + "PCTINCREASE", + "COMPILE", + "FETCH", + "MAXLOGMEMBERS", + "PCTUSED", + "CONSTRAINT", + "FLUSH", + "MAXTRANS", + "PLAN", + "CONSTRAINTS", + "FREELIST", + "MAXVALUE", + "PLI", + "CONTENTS", + "FREELISTS", + "MIN", + "PRECISION", + "CONTINUE", + "FORCE", + "MINEXTENTS", + "PRIMARY", + "CONTROLFILE", + "FOREIGN", + "MINVALUE", + "PRIVATE", + "COUNT", + "FORTRAN", + "MODULE", + "PROCEDURE", + "PROFILE", + "SAVEPOINT", + "SQLSTATE", + "TRACING", + "QUOTA", + "SCHEMA", + "STATEMENT_ID", + "TRANSACTION", + "READ", + "SCN", + "STATISTICS", + "TRIGGERS", + "REAL", + "SECTION", + "STOP", + "TRUNCATE", + "RECOVER", + "SEGMENT", + "STORAGE", + "UNDER", + "REFERENCES", + "SEQUENCE", + "SUM", + "UNLIMITED", + "REFERENCING", + "SHARED", + "SWITCH", + "UNTIL", + "RESETLOGS", + "SNAPSHOT", + "SYSTEM", + "USE", + "RESTRICTED", + "SOME", + "TABLES", + "USING", + "REUSE", + "SORT", + "TABLESPACE", + "WHEN", + "ROLE", + "SQL", + "TEMPORARY", + "WRITE", + "ROLES", + "SQLCODE", + "THREAD", + "WORK", + "ROLLBACK", + "SQLERROR", + "TIME", + "ABORT", + "BETWEEN", + "CRASH", + "DIGITS", + "ACCEPT", + "BINARY_INTEGER", + "CREATE", + "DISPOSE", + "ACCESS", + "BODY", + "CURRENT", + "DISTINCT", + "ADD", + "BOOLEAN", + "CURRVAL", + "DO", + "ALL", + "BY", + "CURSOR", + "DROP", + "ALTER", + "CASE", + "DATABASE", + "ELSE", + "AND", + "CHAR", + "DATA_BASE", + "ELSIF", + "ANY", + "CHAR_BASE", + "DATE", + "END", + "ARRAY", + "CHECK", + "DBA", + "ENTRY", + "ARRAYLEN", + "CLOSE", + "DEBUGOFF", + "EXCEPTION", + "AS", + "CLUSTER", + "DEBUGON", + "EXCEPTION_INIT", + "ASC", + "CLUSTERS", + "DECLARE", + "EXISTS", + "ASSERT", + "COLAUTH", + "DECIMAL", + "EXIT", + "ASSIGN", + "COLUMNS", + "DEFAULT", + "FALSE", + "AT", + "COMMIT", + "DEFINITION", + "FETCH", + "AUTHORIZATION", + "COMPRESS", + "DELAY", + "FLOAT", + "AVG", + "CONNECT", + "DELETE", + "FOR", + "BASE_TABLE", + "CONSTANT", + "DELTA", + "FORM", + "BEGIN", + "COUNT", + "DESC", + "FROM", + "FUNCTION", + "NEW", + "RELEASE", + "SUM", + "GENERIC", + "NEXTVAL", + "REMR", + "TABAUTH", + "GOTO", + "NOCOMPRESS", + "RENAME", + "TABLE", + "GRANT", + "NOT", + "RESOURCE", + "TABLES", + "GROUP", + "NULL", + "RETURN", + "TASK", + "HAVING", + "NUMBER", + "REVERSE", + "TERMINATE", + "IDENTIFIED", + "NUMBER_BASE", + "REVOKE", + "THEN", + "IF", + "OF", + "ROLLBACK", + "TO", + "IN", + "ON", + "ROWID", + "TRUE", + "INDEX", + "OPEN", + "ROWLABEL", + "TYPE", + "INDEXES", + "OPTION", + "ROWNUM", + "UNION", + "INDICATOR", + "OR", + "ROWTYPE", + "UNIQUE", + "INSERT", + "ORDER", + "RUN", + "UPDATE", + "INTEGER", + "OTHERS", + "SAVEPOINT", + "USE", + "INTERSECT", + "OUT", + "SCHEMA", + "VALUES", + "INTO", + "PACKAGE", + "SELECT", + "VARCHAR", + "IS", + "PARTITION", + "SEPARATE", + "VARCHAR2", + "LEVEL", + "PCTFREE", + "SET", + "VARIANCE", + "LIKE", + "POSITIVE", + "SIZE", + "VIEW", + "LIMITED", + "PRAGMA", + "SMALLINT", + "VIEWS", + "LOOP", + "PRIOR", + "SPACE", + "WHEN", + "MAX", + "PRIVATE", + "SQL", + "WHERE", + "MIN", + "PROCEDURE", + "SQLCODE", + "WHILE", + "MINUS", + "PUBLIC", + "SQLERRM", + "WITH", + "MLSLABEL", + "RAISE", + "START", + "WORK", + "MOD", + "RANGE", + "STATEMENT", + "XOR", + "MODE", + "REAL", + "STDDEV", + "NATURAL", + "RECORD", + "SUBTYPE", ] oracle_spatial_keywords = [] @@ -115,154 +505,332 @@ functions = [ # FROM # https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions001.htm - "CAST", "COALESCE", "DECODE", "GREATEST", "LEAST", "LNNVL", - "NULLIF", "NVL", "NVL2", "SET", "UID", "USER", "USERENV" + "CAST", + "COALESCE", + "DECODE", + "GREATEST", + "LEAST", + "LNNVL", + "NULLIF", + "NVL", + "NVL2", + "SET", + "UID", + "USER", + "USERENV", ] # SQL math functions math_functions = [ - 'ABS', 'ACOS', 'ASIN', 'ATAN', 'ATAN2', 'BITAND', 'CEIL', 'COS', - 'COSH', 'EXP', 'FLOOR', 'LN', 'LOG', 'MOD', 'NANVL', 'POWER', - 'REMAINDER', 'ROUND', 'SIGN', 'SIN', 'SINH', 'SQRT', 'TAN', - 'TANH', 'TRUNC', 'WIDTH_BUCKET' + "ABS", + "ACOS", + "ASIN", + "ATAN", + "ATAN2", + "BITAND", + "CEIL", + "COS", + "COSH", + "EXP", + "FLOOR", + "LN", + "LOG", + "MOD", + "NANVL", + "POWER", + "REMAINDER", + "ROUND", + "SIGN", + "SIN", + "SINH", + "SQRT", + "TAN", + "TANH", + "TRUNC", + "WIDTH_BUCKET", ] # Strings functions string_functions = [ - 'CHR', 'CONCAT', 'INITCAP', 'LOWER', 'LPAD', 'LTRIM', 'NLS_INITCAP', - 'NLS_LOWER', 'NLSSORT', 'NLS_UPPER', 'REGEXP_REPLACE', 'REGEXP_SUBSTR', - 'REPLACE', 'RPAD', 'RTRIM', 'SOUNDEX', 'SUBSTR', 'TRANSLATE', 'TREAT', - 'TRIM', 'UPPER', 'ASCII', 'INSTR', 'LENGTH', 'REGEXP_INSTR' + "CHR", + "CONCAT", + "INITCAP", + "LOWER", + "LPAD", + "LTRIM", + "NLS_INITCAP", + "NLS_LOWER", + "NLSSORT", + "NLS_UPPER", + "REGEXP_REPLACE", + "REGEXP_SUBSTR", + "REPLACE", + "RPAD", + "RTRIM", + "SOUNDEX", + "SUBSTR", + "TRANSLATE", + "TREAT", + "TRIM", + "UPPER", + "ASCII", + "INSTR", + "LENGTH", + "REGEXP_INSTR", ] # Aggregate functions aggregate_functions = [ - 'AVG', 'COLLECT', 'CORR', 'COUNT', 'COVAR_POP', 'COVAR_SAMP', 'CUME_DIST', - 'DENSE_RANK', 'FIRST', 'GROUP_ID', 'GROUPING', 'GROUPING_ID', - 'LAST', 'MAX', 'MEDIAN', 'MIN', 'PERCENTILE_CONT', - 'PERCENTILE_DISC', 'PERCENT_RANK', 'RANK', - 'STATS_BINOMIAL_TEST', 'STATS_CROSSTAB', 'STATS_F_TEST', - 'STATS_KS_TEST', 'STATS_MODE', 'STATS_MW_TEST', - 'STATS_ONE_WAY_ANOVA', 'STATS_WSR_TEST', 'STDDEV', - 'STDDEV_POP', 'STDDEV_SAMP', 'SUM', 'SYS_XMLAGG', 'VAR_POP', - 'VAR_SAMP', 'VARIANCE', 'XMLAGG' + "AVG", + "COLLECT", + "CORR", + "COUNT", + "COVAR_POP", + "COVAR_SAMP", + "CUME_DIST", + "DENSE_RANK", + "FIRST", + "GROUP_ID", + "GROUPING", + "GROUPING_ID", + "LAST", + "MAX", + "MEDIAN", + "MIN", + "PERCENTILE_CONT", + "PERCENTILE_DISC", + "PERCENT_RANK", + "RANK", + "STATS_BINOMIAL_TEST", + "STATS_CROSSTAB", + "STATS_F_TEST", + "STATS_KS_TEST", + "STATS_MODE", + "STATS_MW_TEST", + "STATS_ONE_WAY_ANOVA", + "STATS_WSR_TEST", + "STDDEV", + "STDDEV_POP", + "STDDEV_SAMP", + "SUM", + "SYS_XMLAGG", + "VAR_POP", + "VAR_SAMP", + "VARIANCE", + "XMLAGG", ] oracle_spatial_functions = [ # From http://docs.oracle.com/cd/B19306_01/appdev.102/b14255/toc.htm # Spatial operators - "SDO_ANYINTERACT", "SDO_CONTAINS", "SDO_COVEREDBY", "SDO_COVERS", - "SDO_EQUAL", "SDO_FILTER", "SDO_INSIDE", "SDO_JOIN", "SDO_NN", - "SDO_NN_DISTANCE", "SDO_ON", "SDO_OVERLAPBDYDISJOINT", - "SDO_OVERLAPBDYINTERSECT", "SDO_OVERLAPS", "SDO_RELATE", - "SDO_TOUCH", "SDO_WITHIN_DISTANCE", + "SDO_ANYINTERACT", + "SDO_CONTAINS", + "SDO_COVEREDBY", + "SDO_COVERS", + "SDO_EQUAL", + "SDO_FILTER", + "SDO_INSIDE", + "SDO_JOIN", + "SDO_NN", + "SDO_NN_DISTANCE", + "SDO_ON", + "SDO_OVERLAPBDYDISJOINT", + "SDO_OVERLAPBDYINTERSECT", + "SDO_OVERLAPS", + "SDO_RELATE", + "SDO_TOUCH", + "SDO_WITHIN_DISTANCE", # SPATIAL AGGREGATE FUNCTIONS - "SDO_AGGR_CENTROID", "SDO_AGGR_CONCAT_LINES", - "SDO_AGGR_CONVEXHULL", "SDO_AGGR_LRS_CONCAT", "SDO_AGGR_MBR", + "SDO_AGGR_CENTROID", + "SDO_AGGR_CONCAT_LINES", + "SDO_AGGR_CONVEXHULL", + "SDO_AGGR_LRS_CONCAT", + "SDO_AGGR_MBR", "SDO_AGGR_UNION", # COORDINATE SYSTEM TRANSFORMATION (SDO_CS) - "SDO_CS.ADD_PREFERENCE_FOR_OP", "SDO_CS.CONVERT_NADCON_TO_XML", - "SDO_CS.CONVERT_NTV2_TO_XML", "SDO_CS.CONVERT_XML_TO_NADCON", - "SDO_CS.CONVERT_XML_TO_NTV2", "SDO_CS.CREATE_CONCATENATED_OP", + "SDO_CS.ADD_PREFERENCE_FOR_OP", + "SDO_CS.CONVERT_NADCON_TO_XML", + "SDO_CS.CONVERT_NTV2_TO_XML", + "SDO_CS.CONVERT_XML_TO_NADCON", + "SDO_CS.CONVERT_XML_TO_NTV2", + "SDO_CS.CREATE_CONCATENATED_OP", "SDO_CS.CREATE_OBVIOUS_EPSG_RULES", "SDO_CS.CREATE_PREF_CONCATENATED_OP", - "SDO_CS.DELETE_ALL_EPSG_RULES", "SDO_CS.DELETE_OP", - "SDO_CS.DETERMINE_CHAIN", "SDO_CS.DETERMINE_DEFAULT_CHAIN", - "SDO_CS.FIND_GEOG_CRS", "SDO_CS.FIND_PROJ_CRS", - "SDO_CS.FROM_OGC_SIMPLEFEATURE_SRS", "SDO_CS.FROM_USNG", + "SDO_CS.DELETE_ALL_EPSG_RULES", + "SDO_CS.DELETE_OP", + "SDO_CS.DETERMINE_CHAIN", + "SDO_CS.DETERMINE_DEFAULT_CHAIN", + "SDO_CS.FIND_GEOG_CRS", + "SDO_CS.FIND_PROJ_CRS", + "SDO_CS.FROM_OGC_SIMPLEFEATURE_SRS", + "SDO_CS.FROM_USNG", "SDO_CS.MAP_EPSG_SRID_TO_ORACLE", "SDO_CS.MAP_ORACLE_SRID_TO_EPSG", "SDO_CS.REVOKE_PREFERENCE_FOR_OP", - "SDO_CS.TO_OGC_SIMPLEFEATURE_SRS", "SDO_CS.TO_USNG", - "SDO_CS.TRANSFORM", "SDO_CS.TRANSFORM_LAYER", + "SDO_CS.TO_OGC_SIMPLEFEATURE_SRS", + "SDO_CS.TO_USNG", + "SDO_CS.TRANSFORM", + "SDO_CS.TRANSFORM_LAYER", "SDO_CS.UPDATE_WKTS_FOR_ALL_EPSG_CRS", "SDO_CS.UPDATE_WKTS_FOR_EPSG_CRS", "SDO_CS.UPDATE_WKTS_FOR_EPSG_DATUM", "SDO_CS.UPDATE_WKTS_FOR_EPSG_ELLIPS", "SDO_CS.UPDATE_WKTS_FOR_EPSG_OP", "SDO_CS.UPDATE_WKTS_FOR_EPSG_PARAM", - "SDO_CS.UPDATE_WKTS_FOR_EPSG_PM", "SDO_CS.VALIDATE_WKT", + "SDO_CS.UPDATE_WKTS_FOR_EPSG_PM", + "SDO_CS.VALIDATE_WKT", "SDO_CS.VIEWPORT_TRANSFORM", # GEOCODING (SDO_GCDR) - "SDO_GCDR.GEOCODE", "SDO_GCDR.GEOCODE_ADDR", - "SDO_GCDR.GEOCODE_ADDR_ALL", "SDO_GCDR.GEOCODE_ALL", - "SDO_GCDR.GEOCODE_AS_GEOMETRY", "SDO_GCDR.REVERSE_GEOCODE", + "SDO_GCDR.GEOCODE", + "SDO_GCDR.GEOCODE_ADDR", + "SDO_GCDR.GEOCODE_ADDR_ALL", + "SDO_GCDR.GEOCODE_ALL", + "SDO_GCDR.GEOCODE_AS_GEOMETRY", + "SDO_GCDR.REVERSE_GEOCODE", # GEOMETRY (SDO_GEOM) - "SDO_GEOM.RELATE", "SDO_GEOM.SDO_ARC_DENSIFY", - "SDO_GEOM.SDO_AREA", "SDO_GEOM.SDO_BUFFER", - "SDO_GEOM.SDO_CENTROID", "SDO_GEOM.SDO_CONVEXHULL", - "SDO_GEOM.SDO_DIFFERENCE", "SDO_GEOM.SDO_DISTANCE", - "SDO_GEOM.SDO_INTERSECTION", "SDO_GEOM.SDO_LENGTH", - "SDO_GEOM.SDO_MAX_MBR_ORDINATE", "SDO_GEOM.SDO_MBR", - "SDO_GEOM.SDO_MIN_MBR_ORDINATE", "SDO_GEOM.SDO_POINTONSURFACE", - "SDO_GEOM.SDO_UNION", "SDO_GEOM.SDO_XOR", + "SDO_GEOM.RELATE", + "SDO_GEOM.SDO_ARC_DENSIFY", + "SDO_GEOM.SDO_AREA", + "SDO_GEOM.SDO_BUFFER", + "SDO_GEOM.SDO_CENTROID", + "SDO_GEOM.SDO_CONVEXHULL", + "SDO_GEOM.SDO_DIFFERENCE", + "SDO_GEOM.SDO_DISTANCE", + "SDO_GEOM.SDO_INTERSECTION", + "SDO_GEOM.SDO_LENGTH", + "SDO_GEOM.SDO_MAX_MBR_ORDINATE", + "SDO_GEOM.SDO_MBR", + "SDO_GEOM.SDO_MIN_MBR_ORDINATE", + "SDO_GEOM.SDO_POINTONSURFACE", + "SDO_GEOM.SDO_UNION", + "SDO_GEOM.SDO_XOR", "SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT", "SDO_GEOM.VALIDATE_LAYER_WITH_CONTEXT", "SDO_GEOM.WITHIN_DISTANCE", # LINEAR REFERENCING SYSTEM (SDO_LRS) - "SDO_LRS.CLIP_GEOM_SEGMENT", "SDO_LRS.CONCATENATE_GEOM_SEGMENTS", + "SDO_LRS.CLIP_GEOM_SEGMENT", + "SDO_LRS.CONCATENATE_GEOM_SEGMENTS", "SDO_LRS.CONNECTED_GEOM_SEGMENTS", - "SDO_LRS.CONVERT_TO_LRS_DIM_ARRAY", "SDO_LRS.CONVERT_TO_LRS_GEOM", + "SDO_LRS.CONVERT_TO_LRS_DIM_ARRAY", + "SDO_LRS.CONVERT_TO_LRS_GEOM", "SDO_LRS.CONVERT_TO_LRS_LAYER", - "SDO_LRS.CONVERT_TO_STD_DIM_ARRAY", "SDO_LRS.CONVERT_TO_STD_GEOM", - "SDO_LRS.CONVERT_TO_STD_LAYER", "SDO_LRS.DEFINE_GEOM_SEGMENT", - "SDO_LRS.DYNAMIC_SEGMENT", "SDO_LRS.FIND_LRS_DIM_POS", - "SDO_LRS.FIND_MEASURE", "SDO_LRS.FIND_OFFSET", - "SDO_LRS.GEOM_SEGMENT_END_MEASURE", "SDO_LRS.GEOM_SEGMENT_END_PT", + "SDO_LRS.CONVERT_TO_STD_DIM_ARRAY", + "SDO_LRS.CONVERT_TO_STD_GEOM", + "SDO_LRS.CONVERT_TO_STD_LAYER", + "SDO_LRS.DEFINE_GEOM_SEGMENT", + "SDO_LRS.DYNAMIC_SEGMENT", + "SDO_LRS.FIND_LRS_DIM_POS", + "SDO_LRS.FIND_MEASURE", + "SDO_LRS.FIND_OFFSET", + "SDO_LRS.GEOM_SEGMENT_END_MEASURE", + "SDO_LRS.GEOM_SEGMENT_END_PT", "SDO_LRS.GEOM_SEGMENT_LENGTH", "SDO_LRS.GEOM_SEGMENT_START_MEASURE", - "SDO_LRS.GEOM_SEGMENT_START_PT", "SDO_LRS.GET_MEASURE", - "SDO_LRS.GET_NEXT_SHAPE_PT", "SDO_LRS.GET_NEXT_SHAPE_PT_MEASURE", - "SDO_LRS.GET_PREV_SHAPE_PT", "SDO_LRS.GET_PREV_SHAPE_PT_MEASURE", + "SDO_LRS.GEOM_SEGMENT_START_PT", + "SDO_LRS.GET_MEASURE", + "SDO_LRS.GET_NEXT_SHAPE_PT", + "SDO_LRS.GET_NEXT_SHAPE_PT_MEASURE", + "SDO_LRS.GET_PREV_SHAPE_PT", + "SDO_LRS.GET_PREV_SHAPE_PT_MEASURE", "SDO_LRS.IS_GEOM_SEGMENT_DEFINED", - "SDO_LRS.IS_MEASURE_DECREASING", "SDO_LRS.IS_MEASURE_INCREASING", - "SDO_LRS.IS_SHAPE_PT_MEASURE", "SDO_LRS.LOCATE_PT", - "SDO_LRS.LRS_INTERSECTION", "SDO_LRS.MEASURE_RANGE", - "SDO_LRS.MEASURE_TO_PERCENTAGE", "SDO_LRS.OFFSET_GEOM_SEGMENT", - "SDO_LRS.PERCENTAGE_TO_MEASURE", "SDO_LRS.PROJECT_PT", - "SDO_LRS.REDEFINE_GEOM_SEGMENT", "SDO_LRS.RESET_MEASURE", - "SDO_LRS.REVERSE_GEOMETRY", "SDO_LRS.REVERSE_MEASURE", - "SDO_LRS.SET_PT_MEASURE", "SDO_LRS.SPLIT_GEOM_SEGMENT", - "SDO_LRS.TRANSLATE_MEASURE", "SDO_LRS.VALID_GEOM_SEGMENT", - "SDO_LRS.VALID_LRS_PT", "SDO_LRS.VALID_MEASURE", + "SDO_LRS.IS_MEASURE_DECREASING", + "SDO_LRS.IS_MEASURE_INCREASING", + "SDO_LRS.IS_SHAPE_PT_MEASURE", + "SDO_LRS.LOCATE_PT", + "SDO_LRS.LRS_INTERSECTION", + "SDO_LRS.MEASURE_RANGE", + "SDO_LRS.MEASURE_TO_PERCENTAGE", + "SDO_LRS.OFFSET_GEOM_SEGMENT", + "SDO_LRS.PERCENTAGE_TO_MEASURE", + "SDO_LRS.PROJECT_PT", + "SDO_LRS.REDEFINE_GEOM_SEGMENT", + "SDO_LRS.RESET_MEASURE", + "SDO_LRS.REVERSE_GEOMETRY", + "SDO_LRS.REVERSE_MEASURE", + "SDO_LRS.SET_PT_MEASURE", + "SDO_LRS.SPLIT_GEOM_SEGMENT", + "SDO_LRS.TRANSLATE_MEASURE", + "SDO_LRS.VALID_GEOM_SEGMENT", + "SDO_LRS.VALID_LRS_PT", + "SDO_LRS.VALID_MEASURE", "SDO_LRS.VALIDATE_LRS_GEOMETRY", # SDO_MIGRATE "SDO_MIGRATE.TO_CURRENT", # SPATIAL ANALYSIS AND MINING (SDO_SAM) - "SDO_SAM.AGGREGATES_FOR_GEOMETRY", "SDO_SAM.AGGREGATES_FOR_LAYER", - "SDO_SAM.BIN_GEOMETRY", "SDO_SAM.BIN_LAYER", + "SDO_SAM.AGGREGATES_FOR_GEOMETRY", + "SDO_SAM.AGGREGATES_FOR_LAYER", + "SDO_SAM.BIN_GEOMETRY", + "SDO_SAM.BIN_LAYER", "SDO_SAM.COLOCATED_REFERENCE_FEATURES", - "SDO_SAM.SIMPLIFY_GEOMETRY", "SDO_SAM.SIMPLIFY_LAYER", - "SDO_SAM.SPATIAL_CLUSTERS", "SDO_SAM.TILED_AGGREGATES", + "SDO_SAM.SIMPLIFY_GEOMETRY", + "SDO_SAM.SIMPLIFY_LAYER", + "SDO_SAM.SPATIAL_CLUSTERS", + "SDO_SAM.TILED_AGGREGATES", "SDO_SAM.TILED_BINS", # TUNING (SDO_TUNE) - "SDO_TUNE.AVERAGE_MBR", "SDO_TUNE.ESTIMATE_RTREE_INDEX_SIZE", - "SDO_TUNE.EXTENT_OF", "SDO_TUNE.MIX_INFO", + "SDO_TUNE.AVERAGE_MBR", + "SDO_TUNE.ESTIMATE_RTREE_INDEX_SIZE", + "SDO_TUNE.EXTENT_OF", + "SDO_TUNE.MIX_INFO", "SDO_TUNE.QUALITY_DEGRADATION", # UTILITY (SDO_UTIL) - "SDO_UTIL.APPEND", "SDO_UTIL.CIRCLE_POLYGON", - "SDO_UTIL.CONCAT_LINES", "SDO_UTIL.CONVERT_UNIT", - "SDO_UTIL.ELLIPSE_POLYGON", "SDO_UTIL.EXTRACT", - "SDO_UTIL.FROM_WKBGEOMETRY", "SDO_UTIL.FROM_WKTGEOMETRY", - "SDO_UTIL.GETNUMELEM", "SDO_UTIL.GETNUMVERTICES", - "SDO_UTIL.GETVERTICES", "SDO_UTIL.INITIALIZE_INDEXES_FOR_TTS", - "SDO_UTIL.POINT_AT_BEARING", "SDO_UTIL.POLYGONTOLINE", - "SDO_UTIL.PREPARE_FOR_TTS", "SDO_UTIL.RECTIFY_GEOMETRY", + "SDO_UTIL.APPEND", + "SDO_UTIL.CIRCLE_POLYGON", + "SDO_UTIL.CONCAT_LINES", + "SDO_UTIL.CONVERT_UNIT", + "SDO_UTIL.ELLIPSE_POLYGON", + "SDO_UTIL.EXTRACT", + "SDO_UTIL.FROM_WKBGEOMETRY", + "SDO_UTIL.FROM_WKTGEOMETRY", + "SDO_UTIL.GETNUMELEM", + "SDO_UTIL.GETNUMVERTICES", + "SDO_UTIL.GETVERTICES", + "SDO_UTIL.INITIALIZE_INDEXES_FOR_TTS", + "SDO_UTIL.POINT_AT_BEARING", + "SDO_UTIL.POLYGONTOLINE", + "SDO_UTIL.PREPARE_FOR_TTS", + "SDO_UTIL.RECTIFY_GEOMETRY", "SDO_UTIL.REMOVE_DUPLICATE_VERTICES", - "SDO_UTIL.REVERSE_LINESTRING", "SDO_UTIL.SIMPLIFY", - "SDO_UTIL.TO_GMLGEOMETRY", "SDO_UTIL.TO_WKBGEOMETRY", - "SDO_UTIL.TO_WKTGEOMETRY", "SDO_UTIL.VALIDATE_WKBGEOMETRY", - "SDO_UTIL.VALIDATE_WKTGEOMETRY" + "SDO_UTIL.REVERSE_LINESTRING", + "SDO_UTIL.SIMPLIFY", + "SDO_UTIL.TO_GMLGEOMETRY", + "SDO_UTIL.TO_WKBGEOMETRY", + "SDO_UTIL.TO_WKTGEOMETRY", + "SDO_UTIL.VALIDATE_WKBGEOMETRY", + "SDO_UTIL.VALIDATE_WKTGEOMETRY", ] # Oracle Operators operators = [ - ' AND ', ' OR ', '||', ' < ', ' <= ', ' > ', ' >= ', ' = ', - ' <> ', '!=', '^=', ' IS ', ' IS NOT ', ' IN ', ' ANY ', ' SOME ', - ' NOT IN ', ' LIKE ', ' GLOB ', ' MATCH ', ' REGEXP ', - ' BETWEEN x AND y ', ' NOT BETWEEN x AND y ', ' EXISTS ', - ' IS NULL ', ' IS NOT NULL', ' ALL ', ' NOT ', - ' CASE {column} WHEN {value} THEN {value} ' + " AND ", + " OR ", + "||", + " < ", + " <= ", + " > ", + " >= ", + " = ", + " <> ", + "!=", + "^=", + " IS ", + " IS NOT ", + " IN ", + " ANY ", + " SOME ", + " NOT IN ", + " LIKE ", + " GLOB ", + " MATCH ", + " REGEXP ", + " BETWEEN x AND y ", + " NOT BETWEEN x AND y ", + " EXISTS ", + " IS NULL ", + " IS NOT NULL", + " ALL ", + " NOT ", + " CASE {column} WHEN {value} THEN {value} ", ] # constants @@ -278,26 +846,22 @@ def getSqlDictionary(spatial=True): f += oracle_spatial_functions c += oracle_spatial_constants - return {'keyword': k, 'constant': c, 'function': f} + return {"keyword": k, "constant": c, "function": f} def getQueryBuilderDictionary(): # concat functions def ff(l): - return [s for s in l if s[0] != '*'] + return [s for s in l if s[0] != "*"] def add_paren(l): return [s + "(" for s in l] foo = sorted( - add_paren( - ff( - list( - set.union(set(functions), - set(oracle_spatial_functions)))))) + add_paren(ff(list(set.union(set(functions), set(oracle_spatial_functions))))) + ) m = sorted(add_paren(ff(math_functions))) agg = sorted(add_paren(ff(aggregate_functions))) op = ff(operators) s = sorted(add_paren(ff(string_functions))) - return {'function': foo, 'math': m, 'aggregate': agg, - 'operator': op, 'string': s} + return {"function": foo, "math": m, "aggregate": agg, "operator": op, "string": s} diff --git a/python/plugins/db_manager/db_plugins/plugin.py b/python/plugins/db_manager/db_plugins/plugin.py index 00d31a23119c..e5f39cd8bd3f 100644 --- a/python/plugins/db_manager/db_plugins/plugin.py +++ b/python/plugins/db_manager/db_plugins/plugin.py @@ -33,7 +33,7 @@ QInputDialog, QMessageBox, QDialog, - QWidget + QWidget, ) from qgis.PyQt.QtGui import QKeySequence @@ -50,13 +50,10 @@ QgsRasterLayer, QgsProject, QgsMessageLog, - QgsCoordinateReferenceSystem + QgsCoordinateReferenceSystem, ) -from qgis.gui import ( - QgsMessageBarItem, - QgsProjectionSelectionWidget -) +from qgis.gui import QgsMessageBarItem, QgsProjectionSelectionWidget from ..db_plugins import createDbPlugin @@ -66,12 +63,14 @@ class BaseError(Exception): def __init__(self, e): if isinstance(e, Exception): - msg = e.args[0] if len(e.args) > 0 else '' + msg = e.args[0] if len(e.args) > 0 else "" else: msg = e if not isinstance(msg, str): - msg = str(msg, 'utf-8', 'replace') # convert from utf8 and replace errors (if any) + msg = str( + msg, "utf-8", "replace" + ) # convert from utf8 and replace errors (if any) self.msg = msg Exception.__init__(self, msg) @@ -98,9 +97,13 @@ def __unicode__(self): if self.query is None: return BaseError.__unicode__(self) - msg = QApplication.translate("DBManagerPlugin", "Error:\n{0}").format(BaseError.__unicode__(self)) + msg = QApplication.translate("DBManagerPlugin", "Error:\n{0}").format( + BaseError.__unicode__(self) + ) if self.query: - msg += QApplication.translate("DBManagerPlugin", "\n\nQuery:\n{0}").format(self.query) + msg += QApplication.translate("DBManagerPlugin", "\n\nQuery:\n{0}").format( + self.query + ) return msg @@ -132,7 +135,7 @@ def info(self): return DatabaseInfo(None) def connect(self, parent=None): - raise NotImplementedError('Needs to be implemented by subclasses') + raise NotImplementedError("Needs to be implemented by subclasses") def connectToUri(self, uri): self.db = self.databasesFactory(self, uri) @@ -156,7 +159,9 @@ def remove(self): md.deleteConnection(self.connectionName()) except (AttributeError, QgsProviderConnectionException): settings = QgsSettings() - settings.beginGroup("/%s/%s" % (self.connectionSettingsKey(), self.connectionName())) + settings.beginGroup( + f"/{self.connectionSettingsKey()}/{self.connectionName()}" + ) settings.remove("") self.deleted.emit() @@ -164,7 +169,7 @@ def remove(self): @classmethod def addConnection(self, conn_name, uri): - raise NotImplementedError('Needs to be implemented by subclasses') + raise NotImplementedError("Needs to be implemented by subclasses") @classmethod def icon(self): @@ -215,15 +220,19 @@ def databasesFactory(self, connection, uri): @classmethod def addConnectionActionSlot(self, item, action, parent): - raise NotImplementedError('Needs to be implemented by subclasses') + raise NotImplementedError("Needs to be implemented by subclasses") def removeActionSlot(self, item, action, parent): QApplication.restoreOverrideCursor() try: - res = QMessageBox.question(parent, QApplication.translate("DBManagerPlugin", "DB Manager"), - QApplication.translate("DBManagerPlugin", - "Really remove connection to {0}?").format(item.connectionName()), - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) + res = QMessageBox.question( + parent, + QApplication.translate("DBManagerPlugin", "DB Manager"), + QApplication.translate( + "DBManagerPlugin", "Really remove connection to {0}?" + ).format(item.connectionName()), + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + ) if res != QMessageBox.StandardButton.Yes: return finally: @@ -310,22 +319,35 @@ def columnUniqueValuesModel(self, col, table, limit=10): l = "" if limit is not None: l = "LIMIT %d" % limit - return self.sqlResultModel("SELECT DISTINCT %s FROM %s %s" % (col, table, l), self) + return self.sqlResultModel(f"SELECT DISTINCT {col} FROM {table} {l}", self) def uniqueIdFunction(self): """Return a SQL function used to generate a unique id for rows of a query""" # may be overloaded by derived classes return "row_number() over ()" - def toSqlLayer(self, sql, geomCol, uniqueCol, layerName="QueryLayer", layerType=None, avoidSelectById=False, filter=""): + def toSqlLayer( + self, + sql, + geomCol, + uniqueCol, + layerName="QueryLayer", + layerType=None, + avoidSelectById=False, + filter="", + ): if uniqueCol is None: - if hasattr(self, 'uniqueIdFunction'): + if hasattr(self, "uniqueIdFunction"): uniqueFct = self.uniqueIdFunction() if uniqueFct is not None: q = 1 while "_subq_%d_" % q in sql: q += 1 - sql = "SELECT %s AS _uid_,* FROM (%s\n) AS _subq_%d_" % (uniqueFct, sql, q) + sql = "SELECT %s AS _uid_,* FROM (%s\n) AS _subq_%d_" % ( + uniqueFct, + sql, + q, + ) uniqueCol = "_uid_" uri = self.uri() @@ -352,45 +374,91 @@ def registerSubPluginActions(self, mainWindow): def registerDatabaseActions(self, mainWindow): action = QAction(QApplication.translate("DBManagerPlugin", "&Re-connect"), self) - mainWindow.registerAction(action, QApplication.translate("DBManagerPlugin", "&Database"), - self.reconnectActionSlot) + mainWindow.registerAction( + action, + QApplication.translate("DBManagerPlugin", "&Database"), + self.reconnectActionSlot, + ) if self.schemas() is not None: - action = QAction(QApplication.translate("DBManagerPlugin", "&Create Schema…"), self) - mainWindow.registerAction(action, QApplication.translate("DBManagerPlugin", "&Schema"), - self.createSchemaActionSlot) - action = QAction(QApplication.translate("DBManagerPlugin", "&Delete (Empty) Schema"), self) - mainWindow.registerAction(action, QApplication.translate("DBManagerPlugin", "&Schema"), - self.deleteSchemaActionSlot) - - action = QAction(QApplication.translate("DBManagerPlugin", "Delete Selected Item"), self) + action = QAction( + QApplication.translate("DBManagerPlugin", "&Create Schema…"), self + ) + mainWindow.registerAction( + action, + QApplication.translate("DBManagerPlugin", "&Schema"), + self.createSchemaActionSlot, + ) + action = QAction( + QApplication.translate("DBManagerPlugin", "&Delete (Empty) Schema"), + self, + ) + mainWindow.registerAction( + action, + QApplication.translate("DBManagerPlugin", "&Schema"), + self.deleteSchemaActionSlot, + ) + + action = QAction( + QApplication.translate("DBManagerPlugin", "Delete Selected Item"), self + ) mainWindow.registerAction(action, None, self.deleteActionSlot) action.setShortcuts(QKeySequence.StandardKey.Delete) - action = QAction(QgsApplication.getThemeIcon("/mActionCreateTable.svg"), - QApplication.translate("DBManagerPlugin", "&Create Table…"), self) - mainWindow.registerAction(action, QApplication.translate("DBManagerPlugin", "&Table"), - self.createTableActionSlot) - action = QAction(QgsApplication.getThemeIcon("/mActionEditTable.svg"), - QApplication.translate("DBManagerPlugin", "&Edit Table…"), self) - mainWindow.registerAction(action, QApplication.translate("DBManagerPlugin", "&Table"), self.editTableActionSlot) - action = QAction(QgsApplication.getThemeIcon("/mActionDeleteTable.svg"), - QApplication.translate("DBManagerPlugin", "&Delete Table/View…"), self) - mainWindow.registerAction(action, QApplication.translate("DBManagerPlugin", "&Table"), - self.deleteTableActionSlot) - action = QAction(QApplication.translate("DBManagerPlugin", "&Empty Table…"), self) - mainWindow.registerAction(action, QApplication.translate("DBManagerPlugin", "&Table"), - self.emptyTableActionSlot) + action = QAction( + QgsApplication.getThemeIcon("/mActionCreateTable.svg"), + QApplication.translate("DBManagerPlugin", "&Create Table…"), + self, + ) + mainWindow.registerAction( + action, + QApplication.translate("DBManagerPlugin", "&Table"), + self.createTableActionSlot, + ) + action = QAction( + QgsApplication.getThemeIcon("/mActionEditTable.svg"), + QApplication.translate("DBManagerPlugin", "&Edit Table…"), + self, + ) + mainWindow.registerAction( + action, + QApplication.translate("DBManagerPlugin", "&Table"), + self.editTableActionSlot, + ) + action = QAction( + QgsApplication.getThemeIcon("/mActionDeleteTable.svg"), + QApplication.translate("DBManagerPlugin", "&Delete Table/View…"), + self, + ) + mainWindow.registerAction( + action, + QApplication.translate("DBManagerPlugin", "&Table"), + self.deleteTableActionSlot, + ) + action = QAction( + QApplication.translate("DBManagerPlugin", "&Empty Table…"), self + ) + mainWindow.registerAction( + action, + QApplication.translate("DBManagerPlugin", "&Table"), + self.emptyTableActionSlot, + ) if self.schemas() is not None: - action = QAction(QApplication.translate("DBManagerPlugin", "&Move to Schema"), self) + action = QAction( + QApplication.translate("DBManagerPlugin", "&Move to Schema"), self + ) action.setMenu(QMenu(mainWindow)) def invoke_callback(): - return mainWindow.invokeCallback(self.prepareMenuMoveTableToSchemaActionSlot) + return mainWindow.invokeCallback( + self.prepareMenuMoveTableToSchemaActionSlot + ) action.menu().aboutToShow.connect(invoke_callback) - mainWindow.registerAction(action, QApplication.translate("DBManagerPlugin", "&Table")) + mainWindow.registerAction( + action, QApplication.translate("DBManagerPlugin", "&Table") + ) def reconnectActionSlot(self, item, action, parent): db = item.database() @@ -404,20 +472,36 @@ def deleteActionSlot(self, item, action, parent): self.deleteTableActionSlot(item, action, parent) else: QApplication.restoreOverrideCursor() - parent.infoBar.pushMessage(QApplication.translate("DBManagerPlugin", "Cannot delete the selected item."), - Qgis.MessageLevel.Info, parent.iface.messageTimeout()) + parent.infoBar.pushMessage( + QApplication.translate( + "DBManagerPlugin", "Cannot delete the selected item." + ), + Qgis.MessageLevel.Info, + parent.iface.messageTimeout(), + ) QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) def createSchemaActionSlot(self, item, action, parent): QApplication.restoreOverrideCursor() try: - if not isinstance(item, (DBPlugin, Schema, Table)) or item.database() is None: + if ( + not isinstance(item, (DBPlugin, Schema, Table)) + or item.database() is None + ): parent.infoBar.pushMessage( - QApplication.translate("DBManagerPlugin", "No database selected or you are not connected to it."), - Qgis.MessageLevel.Info, parent.iface.messageTimeout()) + QApplication.translate( + "DBManagerPlugin", + "No database selected or you are not connected to it.", + ), + Qgis.MessageLevel.Info, + parent.iface.messageTimeout(), + ) return - (schema, ok) = QInputDialog.getText(parent, QApplication.translate("DBManagerPlugin", "New schema"), - QApplication.translate("DBManagerPlugin", "Enter new schema name")) + (schema, ok) = QInputDialog.getText( + parent, + QApplication.translate("DBManagerPlugin", "New schema"), + QApplication.translate("DBManagerPlugin", "Enter new schema name"), + ) if not ok: return finally: @@ -430,13 +514,21 @@ def deleteSchemaActionSlot(self, item, action, parent): try: if not isinstance(item, Schema): parent.infoBar.pushMessage( - QApplication.translate("DBManagerPlugin", "Select an empty schema for deletion."), - Qgis.MessageLevel.Info, parent.iface.messageTimeout()) + QApplication.translate( + "DBManagerPlugin", "Select an empty schema for deletion." + ), + Qgis.MessageLevel.Info, + parent.iface.messageTimeout(), + ) return - res = QMessageBox.question(parent, QApplication.translate("DBManagerPlugin", "DB Manager"), - QApplication.translate("DBManagerPlugin", - "Really delete schema {0}?").format(item.name), - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) + res = QMessageBox.question( + parent, + QApplication.translate("DBManagerPlugin", "DB Manager"), + QApplication.translate( + "DBManagerPlugin", "Really delete schema {0}?" + ).format(item.name), + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + ) if res != QMessageBox.StandardButton.Yes: return finally: @@ -459,10 +551,15 @@ def createSchema(self, name): def createTableActionSlot(self, item, action, parent): QApplication.restoreOverrideCursor() - if not hasattr(item, 'database') or item.database() is None: + if not hasattr(item, "database") or item.database() is None: parent.infoBar.pushMessage( - QApplication.translate("DBManagerPlugin", "No database selected or you are not connected to it."), - Qgis.MessageLevel.Info, parent.iface.messageTimeout()) + QApplication.translate( + "DBManagerPlugin", + "No database selected or you are not connected to it.", + ), + Qgis.MessageLevel.Info, + parent.iface.messageTimeout(), + ) return from ..dlg_create_table import DlgCreateTable @@ -473,13 +570,23 @@ def editTableActionSlot(self, item, action, parent): QApplication.restoreOverrideCursor() try: if not isinstance(item, Table) or item.isView: - parent.infoBar.pushMessage(QApplication.translate("DBManagerPlugin", "Select a table to edit."), - Qgis.MessageLevel.Info, parent.iface.messageTimeout()) + parent.infoBar.pushMessage( + QApplication.translate( + "DBManagerPlugin", "Select a table to edit." + ), + Qgis.MessageLevel.Info, + parent.iface.messageTimeout(), + ) return if isinstance(item, RasterTable): - parent.infoBar.pushMessage(QApplication.translate("DBManagerPlugin", "Editing of raster tables is not supported."), - Qgis.MessageLevel.Info, parent.iface.messageTimeout()) + parent.infoBar.pushMessage( + QApplication.translate( + "DBManagerPlugin", "Editing of raster tables is not supported." + ), + Qgis.MessageLevel.Info, + parent.iface.messageTimeout(), + ) return from ..dlg_table_properties import DlgTableProperties @@ -493,13 +600,21 @@ def deleteTableActionSlot(self, item, action, parent): try: if not isinstance(item, Table): parent.infoBar.pushMessage( - QApplication.translate("DBManagerPlugin", "Select a table/view for deletion."), - Qgis.MessageLevel.Info, parent.iface.messageTimeout()) + QApplication.translate( + "DBManagerPlugin", "Select a table/view for deletion." + ), + Qgis.MessageLevel.Info, + parent.iface.messageTimeout(), + ) return - res = QMessageBox.question(parent, QApplication.translate("DBManagerPlugin", "DB Manager"), - QApplication.translate("DBManagerPlugin", - "Really delete table/view {0}?").format(item.name), - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) + res = QMessageBox.question( + parent, + QApplication.translate("DBManagerPlugin", "DB Manager"), + QApplication.translate( + "DBManagerPlugin", "Really delete table/view {0}?" + ).format(item.name), + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + ) if res != QMessageBox.StandardButton.Yes: return finally: @@ -511,13 +626,22 @@ def emptyTableActionSlot(self, item, action, parent): QApplication.restoreOverrideCursor() try: if not isinstance(item, Table) or item.isView: - parent.infoBar.pushMessage(QApplication.translate("DBManagerPlugin", "Select a table to empty it."), - Qgis.MessageLevel.Info, parent.iface.messageTimeout()) + parent.infoBar.pushMessage( + QApplication.translate( + "DBManagerPlugin", "Select a table to empty it." + ), + Qgis.MessageLevel.Info, + parent.iface.messageTimeout(), + ) return - res = QMessageBox.question(parent, QApplication.translate("DBManagerPlugin", "DB Manager"), - QApplication.translate("DBManagerPlugin", - "Really delete all items from table {0}?").format(item.name), - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) + res = QMessageBox.question( + parent, + QApplication.translate("DBManagerPlugin", "DB Manager"), + QApplication.translate( + "DBManagerPlugin", "Really delete all items from table {0}?" + ).format(item.name), + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + ) if res != QMessageBox.StandardButton.Yes: return finally: @@ -526,10 +650,12 @@ def emptyTableActionSlot(self, item, action, parent): item.empty() def prepareMenuMoveTableToSchemaActionSlot(self, item, menu, mainWindow): - """ populate menu with schemas """ + """populate menu with schemas""" def slot(x): - return lambda: mainWindow.invokeCallback(self.moveTableToSchemaActionSlot, x) + return lambda: mainWindow.invokeCallback( + self.moveTableToSchemaActionSlot, x + ) menu.clear() for schema in self.schemas(): @@ -539,8 +665,11 @@ def moveTableToSchemaActionSlot(self, item, action, parent, new_schema): QApplication.restoreOverrideCursor() try: if not isinstance(item, Table): - parent.infoBar.pushMessage(QApplication.translate("DBManagerPlugin", "Select a table/view."), - Qgis.MessageLevel.Info, parent.iface.messageTimeout()) + parent.infoBar.pushMessage( + QApplication.translate("DBManagerPlugin", "Select a table/view."), + Qgis.MessageLevel.Info, + parent.iface.messageTimeout(), + ) return finally: QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) @@ -567,10 +696,7 @@ def rasterTablesFactory(self, row, db, schema=None): def tables(self, schema=None, sys_tables=False): tables = self.connector.getTables(schema.name if schema else None, sys_tables) if tables is not None: - ret = [ - self.tablesFactory(t, self, schema) - for t in tables - ] + ret = [self.tablesFactory(t, self, schema) for t in tables] return ret def createTable(self, table, fields, schema=None): @@ -601,7 +727,9 @@ def createVectorTable(self, table, fields, geom, schema=None): geomCol, geomType, geomSrid, geomDim = geom[:4] createSpatialIndex = geom[4] if len(geom) > 4 else False - self.connector.addGeometryColumn((schema, table), geomCol, geomType, geomSrid, geomDim) + self.connector.addGeometryColumn( + (schema, table), geomCol, geomType, geomSrid, geomDim + ) if createSpatialIndex: # commit data definition changes, otherwise index can't be built @@ -670,7 +798,7 @@ class Table(DbItemObject): def __init__(self, db, schema=None, parent=None): DbItemObject.__init__(self, db) self._schema = schema - if hasattr(self, 'type'): + if hasattr(self, "type"): return self.type = Table.TableType @@ -678,7 +806,9 @@ def __init__(self, db, schema=None, parent=None): self.comment = None self.rowCount = None - self._fields = self._indexes = self._constraints = self._triggers = self._rules = None + self._fields = self._indexes = self._constraints = self._triggers = ( + self._rules + ) = None def __del__(self): pass # print "Table.__del__", self @@ -710,7 +840,9 @@ def delete(self): def rename(self, new_name): self.aboutToChange.emit() - ret = self.database().connector.renameTable((self.schemaName(), self.name), new_name) + ret = self.database().connector.renameTable( + (self.schemaName(), self.name), new_name + ) if ret is not False: self.name = new_name self._triggers = None @@ -730,7 +862,9 @@ def moveToSchema(self, schema): self.aboutToChange.emit() if self.schema() == schema: return True - ret = self.database().connector.moveTableToSchema((self.schemaName(), self.name), schema.name) + ret = self.database().connector.moveTableToSchema( + (self.schemaName(), self.name), schema.name + ) if ret is not False: self.schema().refresh() schema.refresh() @@ -743,10 +877,18 @@ def info(self): def uri(self): uri = self.database().uri() - schema = self.schemaName() if self.schemaName() else '' - geomCol = self.geomColumn if self.type in [Table.VectorType, Table.RasterType] else "" + schema = self.schemaName() if self.schemaName() else "" + geomCol = ( + self.geomColumn if self.type in [Table.VectorType, Table.RasterType] else "" + ) uniqueCol = self.getValidQgisUniqueFields(True) if self.isView else None - uri.setDataSource(schema, self.name, geomCol if geomCol else None, None, uniqueCol.name if uniqueCol else "") + uri.setDataSource( + schema, + self.name, + geomCol if geomCol else None, + None, + uniqueCol.name if uniqueCol else "", + ) return uri def crs(self): @@ -756,7 +898,12 @@ def crs(self): def mimeUri(self): layerType = "raster" if self.type == Table.RasterType else "vector" - return "%s:%s:%s:%s" % (layerType, self.database().dbplugin().providerName(), self.name, self.uri().uri(False)) + return "{}:{}:{}:{}".format( + layerType, + self.database().dbplugin().providerName(), + self.name, + self.uri().uri(False), + ) def toMapLayer(self, geometryType=None, crs=None): provider = self.database().dbplugin().providerName() @@ -776,9 +923,9 @@ def geometryType(self): pass def getValidQgisUniqueFields(self, onlyOne=False): - """ list of fields valid to load the table as layer in QGIS canvas. - QGIS automatically search for a valid unique field, so it's - needed only for queries and views """ + """list of fields valid to load the table as layer in QGIS canvas. + QGIS automatically search for a valid unique field, so it's + needed only for queries and views""" ret = [] @@ -793,7 +940,10 @@ def getValidQgisUniqueFields(self, onlyOne=False): for idx in indexes: if idx.isUnique and len(idx.columns) == 1: fld = idx.fields()[idx.columns[0]] - if fld.dataType in ["oid", "serial", "int4", "int8"] and fld not in ret: + if ( + fld.dataType in ["oid", "serial", "int4", "int8"] + and fld not in ret + ): ret.append(fld) # and finally append the other suitable fields @@ -809,11 +959,13 @@ def tableDataModel(self, parent): pass def tableFieldsFactory(self, row, table): - raise NotImplementedError('Needs to be implemented by subclasses') + raise NotImplementedError("Needs to be implemented by subclasses") def fields(self): if self._fields is None: - fields = self.database().connector.getTableFields((self.schemaName(), self.name)) + fields = self.database().connector.getTableFields( + (self.schemaName(), self.name) + ) if fields is not None: self._fields = [self.tableFieldsFactory(x, self) for x in fields] return self._fields @@ -824,14 +976,18 @@ def refreshFields(self): def addField(self, fld): self.aboutToChange.emit() - ret = self.database().connector.addTableColumn((self.schemaName(), self.name), fld.definition()) + ret = self.database().connector.addTableColumn( + (self.schemaName(), self.name), fld.definition() + ) if ret is not False: self.refreshFields() return ret def deleteField(self, fld): self.aboutToChange.emit() - ret = self.database().connector.deleteTableColumn((self.schemaName(), self.name), fld.name) + ret = self.database().connector.deleteTableColumn( + (self.schemaName(), self.name), fld.name + ) if ret is not False: self.refreshFields() self.refreshConstraints() @@ -840,7 +996,9 @@ def deleteField(self, fld): def addGeometryColumn(self, geomCol, geomType, srid, dim, createSpatialIndex=False): self.aboutToChange.emit() - ret = self.database().connector.addGeometryColumn((self.schemaName(), self.name), geomCol, geomType, srid, dim) + ret = self.database().connector.addGeometryColumn( + (self.schemaName(), self.name), geomCol, geomType, srid, dim + ) if not ret: return False @@ -848,10 +1006,14 @@ def addGeometryColumn(self, geomCol, geomType, srid, dim, createSpatialIndex=Fal if createSpatialIndex: # commit data definition changes, otherwise index can't be built self.database().connector._commit() - self.database().connector.createSpatialIndex((self.schemaName(), self.name), geomCol) + self.database().connector.createSpatialIndex( + (self.schemaName(), self.name), geomCol + ) finally: - self.schema().refresh() if self.schema() else self.database().refresh() # another table was added + ( + self.schema().refresh() if self.schema() else self.database().refresh() + ) # another table was added return True def tableConstraintsFactory(self): @@ -859,9 +1021,13 @@ def tableConstraintsFactory(self): def constraints(self): if self._constraints is None: - constraints = self.database().connector.getTableConstraints((self.schemaName(), self.name)) + constraints = self.database().connector.getTableConstraints( + (self.schemaName(), self.name) + ) if constraints is not None: - self._constraints = [self.tableConstraintsFactory(x, self) for x in constraints] + self._constraints = [ + self.tableConstraintsFactory(x, self) for x in constraints + ] return self._constraints def refreshConstraints(self): @@ -871,11 +1037,13 @@ def refreshConstraints(self): def addConstraint(self, constr): self.aboutToChange.emit() if constr.type == TableConstraint.TypePrimaryKey: - ret = self.database().connector.addTablePrimaryKey((self.schemaName(), self.name), - constr.fields()[constr.columns[0]].name) + ret = self.database().connector.addTablePrimaryKey( + (self.schemaName(), self.name), constr.fields()[constr.columns[0]].name + ) elif constr.type == TableConstraint.TypeUnique: - ret = self.database().connector.addTableUniqueConstraint((self.schemaName(), self.name), - constr.fields()[constr.columns[0]].name) + ret = self.database().connector.addTableUniqueConstraint( + (self.schemaName(), self.name), constr.fields()[constr.columns[0]].name + ) else: return False if ret is not False: @@ -884,7 +1052,9 @@ def addConstraint(self, constr): def deleteConstraint(self, constr): self.aboutToChange.emit() - ret = self.database().connector.deleteTableConstraint((self.schemaName(), self.name), constr.name) + ret = self.database().connector.deleteTableConstraint( + (self.schemaName(), self.name), constr.name + ) if ret is not False: self.refreshConstraints() return ret @@ -894,7 +1064,9 @@ def tableIndexesFactory(self): def indexes(self): if self._indexes is None: - indexes = self.database().connector.getTableIndexes((self.schemaName(), self.name)) + indexes = self.database().connector.getTableIndexes( + (self.schemaName(), self.name) + ) if indexes is not None: self._indexes = [self.tableIndexesFactory(x, self) for x in indexes] return self._indexes @@ -905,15 +1077,18 @@ def refreshIndexes(self): def addIndex(self, idx): self.aboutToChange.emit() - ret = self.database().connector.createTableIndex((self.schemaName(), self.name), idx.name, - idx.fields()[idx.columns[0]].name) + ret = self.database().connector.createTableIndex( + (self.schemaName(), self.name), idx.name, idx.fields()[idx.columns[0]].name + ) if ret is not False: self.refreshIndexes() return ret def deleteIndex(self, idx): self.aboutToChange.emit() - ret = self.database().connector.deleteTableIndex((self.schemaName(), self.name), idx.name) + ret = self.database().connector.deleteTableIndex( + (self.schemaName(), self.name), idx.name + ) if ret is not False: self.refreshIndexes() return ret @@ -923,7 +1098,9 @@ def tableTriggersFactory(self, row, table): def triggers(self): if self._triggers is None: - triggers = self.database().connector.getTableTriggers((self.schemaName(), self.name)) + triggers = self.database().connector.getTableTriggers( + (self.schemaName(), self.name) + ) if triggers is not None: self._triggers = [self.tableTriggersFactory(x, self) for x in triggers] return self._triggers @@ -937,7 +1114,9 @@ def tableRulesFactory(self, row, table): def rules(self): if self._rules is None: - rules = self.database().connector.getTableRules((self.schemaName(), self.name)) + rules = self.database().connector.getTableRules( + (self.schemaName(), self.name) + ) if rules is not None: self._rules = [self.tableRulesFactory(x, self) for x in rules] return self._rules @@ -950,7 +1129,9 @@ def refreshRowCount(self): self.aboutToChange.emit() prevRowCount = self.rowCount try: - self.rowCount = self.database().connector.getTableRowCount((self.schemaName(), self.name)) + self.rowCount = self.database().connector.getTableRowCount( + (self.schemaName(), self.name) + ) self.rowCount = int(self.rowCount) if self.rowCount is not None else None except DbError: self.rowCount = None @@ -966,14 +1147,23 @@ def runAction(self, action): return True elif action.startswith("triggers/"): - parts = action.split('/') + parts = action.split("/") trigger_action = parts[1] - msg = QApplication.translate("DBManagerPlugin", "Do you want to {0} all triggers?").format(trigger_action) + msg = QApplication.translate( + "DBManagerPlugin", "Do you want to {0} all triggers?" + ).format(trigger_action) QApplication.restoreOverrideCursor() try: - if QMessageBox.question(None, QApplication.translate("DBManagerPlugin", "Table triggers"), msg, - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) == QMessageBox.StandardButton.No: + if ( + QMessageBox.question( + None, + QApplication.translate("DBManagerPlugin", "Table triggers"), + msg, + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + ) + == QMessageBox.StandardButton.No + ): return False finally: QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) @@ -981,35 +1171,49 @@ def runAction(self, action): if trigger_action == "enable" or trigger_action == "disable": enable = trigger_action == "enable" self.aboutToChange.emit() - self.database().connector.enableAllTableTriggers(enable, (self.schemaName(), self.name)) + self.database().connector.enableAllTableTriggers( + enable, (self.schemaName(), self.name) + ) self.refreshTriggers() return True elif action.startswith("trigger/"): - parts = action.split('/') + parts = action.split("/") trigger_name = parts[1] trigger_action = parts[2] - msg = QApplication.translate("DBManagerPlugin", "Do you want to {0} trigger {1}?").format( - trigger_action, trigger_name) + msg = QApplication.translate( + "DBManagerPlugin", "Do you want to {0} trigger {1}?" + ).format(trigger_action, trigger_name) QApplication.restoreOverrideCursor() try: - if QMessageBox.question(None, QApplication.translate("DBManagerPlugin", "Table trigger"), msg, - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) == QMessageBox.StandardButton.No: + if ( + QMessageBox.question( + None, + QApplication.translate("DBManagerPlugin", "Table trigger"), + msg, + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + ) + == QMessageBox.StandardButton.No + ): return False finally: QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) if trigger_action == "delete": self.aboutToChange.emit() - self.database().connector.deleteTableTrigger(trigger_name, (self.schemaName(), self.name)) + self.database().connector.deleteTableTrigger( + trigger_name, (self.schemaName(), self.name) + ) self.refreshTriggers() return True elif trigger_action == "enable" or trigger_action == "disable": enable = trigger_action == "enable" self.aboutToChange.emit() - self.database().connector.enableTableTrigger(trigger_name, enable, (self.schemaName(), self.name)) + self.database().connector.enableTableTrigger( + trigger_name, enable, (self.schemaName(), self.name) + ) self.refreshTriggers() return True @@ -1023,7 +1227,9 @@ def addExtraContextMenuEntries(self, menu): class VectorTable(Table): def __init__(self, db, schema=None, parent=None): - if not hasattr(self, 'type'): # check if the superclass constructor was called yet! + if not hasattr( + self, "type" + ): # check if the superclass constructor was called yet! Table.__init__(self, db, schema, parent) self.type = Table.VectorType self.geomColumn = self.geomType = self.geomDim = self.srid = None @@ -1060,7 +1266,9 @@ def hasSpatialIndex(self, geom_column=None): def createSpatialIndex(self, geom_column=None): self.aboutToChange.emit() geom_column = geom_column if geom_column is not None else self.geomColumn - ret = self.database().connector.createSpatialIndex((self.schemaName(), self.name), geom_column) + ret = self.database().connector.createSpatialIndex( + (self.schemaName(), self.name), geom_column + ) if ret is not False: self.refreshIndexes() return ret @@ -1068,7 +1276,9 @@ def createSpatialIndex(self, geom_column=None): def deleteSpatialIndex(self, geom_column=None): self.aboutToChange.emit() geom_column = geom_column if geom_column is not None else self.geomColumn - ret = self.database().connector.deleteSpatialIndex((self.schemaName(), self.name), geom_column) + ret = self.database().connector.deleteSpatialIndex( + (self.schemaName(), self.name), geom_column + ) if ret is not False: self.refreshIndexes() return ret @@ -1076,7 +1286,9 @@ def deleteSpatialIndex(self, geom_column=None): def refreshTableExtent(self): prevExtent = self.extent try: - self.extent = self.database().connector.getTableExtent((self.schemaName(), self.name), self.geomColumn) + self.extent = self.database().connector.getTableExtent( + (self.schemaName(), self.name), self.geomColumn + ) except DbError: self.extent = None if self.extent != prevExtent: @@ -1085,8 +1297,9 @@ def refreshTableExtent(self): def refreshTableEstimatedExtent(self): prevEstimatedExtent = self.estimatedExtent try: - self.estimatedExtent = self.database().connector.getTableEstimatedExtent((self.schemaName(), self.name), - self.geomColumn) + self.estimatedExtent = self.database().connector.getTableEstimatedExtent( + (self.schemaName(), self.name), self.geomColumn + ) except DbError: self.estimatedExtent = None if self.estimatedExtent != prevEstimatedExtent: @@ -1096,15 +1309,23 @@ def runAction(self, action): action = str(action) if action.startswith("spatialindex/"): - parts = action.split('/') + parts = action.split("/") spatialIndex_action = parts[1] - msg = QApplication.translate("DBManagerPlugin", "Do you want to {0} spatial index for field {1}?").format( - spatialIndex_action, self.geomColumn) + msg = QApplication.translate( + "DBManagerPlugin", "Do you want to {0} spatial index for field {1}?" + ).format(spatialIndex_action, self.geomColumn) QApplication.restoreOverrideCursor() try: - if QMessageBox.question(None, QApplication.translate("DBManagerPlugin", "Spatial Index"), msg, - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) == QMessageBox.StandardButton.No: + if ( + QMessageBox.question( + None, + QApplication.translate("DBManagerPlugin", "Spatial Index"), + msg, + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + ) + == QMessageBox.StandardButton.No + ): return False finally: QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) @@ -1131,48 +1352,67 @@ def addLayer(self, geometryType=None, crs=None): layer = self.toMapLayer(geometryType, crs) layers = QgsProject.instance().addMapLayers([layer]) if len(layers) != 1: - QgsMessageLog.logMessage(self.tr("{layer} is an invalid layer - not loaded").format(layer=layer.publicSource())) - msgLabel = QLabel(self.tr("{layer} is an invalid layer and cannot be loaded. Please check the message log for further info.").format(layer=layer.publicSource()), self.mainWindow.infoBar) + QgsMessageLog.logMessage( + self.tr("{layer} is an invalid layer - not loaded").format( + layer=layer.publicSource() + ) + ) + msgLabel = QLabel( + self.tr( + '{layer} is an invalid layer and cannot be loaded. Please check the message log for further info.' + ).format(layer=layer.publicSource()), + self.mainWindow.infoBar, + ) msgLabel.setWordWrap(True) - msgLabel.linkActivated.connect(self.mainWindow.iface.mainWindow().findChild(QWidget, "MessageLog").show) + msgLabel.linkActivated.connect( + self.mainWindow.iface.mainWindow().findChild(QWidget, "MessageLog").show + ) msgLabel.linkActivated.connect(self.mainWindow.iface.mainWindow().raise_) - self.mainWindow.infoBar.pushItem(QgsMessageBarItem(msgLabel, Qgis.MessageLevel.Warning)) + self.mainWindow.infoBar.pushItem( + QgsMessageBarItem(msgLabel, Qgis.MessageLevel.Warning) + ) def showAdvancedVectorDialog(self): dlg = QDialog() - dlg.setObjectName('dbManagerAdvancedVectorDialog') + dlg.setObjectName("dbManagerAdvancedVectorDialog") settings = QgsSettings() - dlg.restoreGeometry(settings.value("/DB_Manager/advancedAddDialog/geometry", QByteArray(), type=QByteArray)) + dlg.restoreGeometry( + settings.value( + "/DB_Manager/advancedAddDialog/geometry", QByteArray(), type=QByteArray + ) + ) layout = QFormLayout() dlg.setLayout(layout) - dlg.setWindowTitle(self.tr('Add Layer {}').format(self.name)) + dlg.setWindowTitle(self.tr("Add Layer {}").format(self.name)) geometryTypeComboBox = QComboBox() - geometryTypeComboBox.addItem(self.tr('Point'), 'POINT') - geometryTypeComboBox.addItem(self.tr('Line'), 'LINESTRING') - geometryTypeComboBox.addItem(self.tr('Polygon'), 'POLYGON') - layout.addRow(self.tr('Geometry Type'), geometryTypeComboBox) - zCheckBox = QCheckBox(self.tr('With Z')) - mCheckBox = QCheckBox(self.tr('With M')) + geometryTypeComboBox.addItem(self.tr("Point"), "POINT") + geometryTypeComboBox.addItem(self.tr("Line"), "LINESTRING") + geometryTypeComboBox.addItem(self.tr("Polygon"), "POLYGON") + layout.addRow(self.tr("Geometry Type"), geometryTypeComboBox) + zCheckBox = QCheckBox(self.tr("With Z")) + mCheckBox = QCheckBox(self.tr("With M")) layout.addRow(zCheckBox) layout.addRow(mCheckBox) crsSelector = QgsProjectionSelectionWidget() crsSelector.setCrs(self.crs()) - layout.addRow(self.tr('CRS'), crsSelector) + layout.addRow(self.tr("CRS"), crsSelector) def selectedGeometryType(): geomType = geometryTypeComboBox.currentData() if zCheckBox.isChecked(): - geomType += 'Z' + geomType += "Z" if mCheckBox.isChecked(): - geomType += 'M' + geomType += "M" return geomType def selectedCrs(): return crsSelector.crs() - addButton = QPushButton(self.tr('Load Layer')) - addButton.clicked.connect(lambda: self.addLayer(selectedGeometryType(), selectedCrs())) + addButton = QPushButton(self.tr("Load Layer")) + addButton.clicked.connect( + lambda: self.addLayer(selectedGeometryType(), selectedCrs()) + ) btns = QDialogButtonBox(QDialogButtonBox.StandardButton.Cancel) btns.addButton(addButton, QDialogButtonBox.ButtonRole.ActionRole) @@ -1190,17 +1430,24 @@ def selectedCrs(): def addExtraContextMenuEntries(self, menu): """Called whenever a context menu is shown for this table. Can be used to add additional actions to the menu.""" - if self.geomType == 'GEOMETRY': - menu.addAction(QApplication.translate("DBManagerPlugin", "Add Layer (Advanced)…"), self.showAdvancedVectorDialog) + if self.geomType == "GEOMETRY": + menu.addAction( + QApplication.translate("DBManagerPlugin", "Add Layer (Advanced)…"), + self.showAdvancedVectorDialog, + ) class RasterTable(Table): def __init__(self, db, schema=None, parent=None): - if not hasattr(self, 'type'): # check if the superclass constructor was called yet! + if not hasattr( + self, "type" + ): # check if the superclass constructor was called yet! Table.__init__(self, db, schema, parent) self.type = Table.RasterType - self.geomColumn = self.geomType = self.pixelSizeX = self.pixelSizeY = self.pixelType = self.isExternal = self.srid = None + self.geomColumn = self.geomType = self.pixelSizeX = self.pixelSizeY = ( + self.pixelType + ) = self.isExternal = self.srid = None self.extent = None def info(self): @@ -1225,35 +1472,41 @@ class TableField(TableSubItemObject): def __init__(self, table): TableSubItemObject.__init__(self, table) - self.num = self.name = self.dataType = self.modifier = self.notNull = self.default = self.hasDefault = self.primaryKey = None + self.num = self.name = self.dataType = self.modifier = self.notNull = ( + self.default + ) = self.hasDefault = self.primaryKey = None self.comment = None def type2String(self): if self.modifier is None or self.modifier == -1: return "%s" % self.dataType - return "%s (%s)" % (self.dataType, self.modifier) + return f"{self.dataType} ({self.modifier})" def default2String(self): if not self.hasDefault: - return '' + return "" return self.default if self.default is not None else "NULL" def definition(self): from .connector import DBConnector - quoteIdFunc = self.database().connector.quoteId if self.database() else DBConnector.quoteId + quoteIdFunc = ( + self.database().connector.quoteId + if self.database() + else DBConnector.quoteId + ) name = quoteIdFunc(self.name) not_null = "NOT NULL" if self.notNull else "" - txt = "%s %s %s" % (name, self.type2String(), not_null) + txt = f"{name} {self.type2String()} {not_null}" if self.hasDefault: txt += " DEFAULT %s" % self.default2String() return txt def getComment(self): """Returns the comment for a field""" - return '' + return "" def delete(self): return self.table().deleteField(self) @@ -1261,7 +1514,14 @@ def delete(self): def rename(self, new_name): return self.update(new_name) - def update(self, new_name, new_type_str=None, new_not_null=None, new_default_str=None, new_comment=None): + def update( + self, + new_name, + new_type_str=None, + new_not_null=None, + new_default_str=None, + new_comment=None, + ): self.table().aboutToChange.emit() if self.name == new_name: new_name = None @@ -1273,21 +1533,50 @@ def update(self, new_name, new_type_str=None, new_not_null=None, new_default_str new_default_str = None if self.comment == new_comment: new_comment = None - ret = self.table().database().connector.updateTableColumn((self.table().schemaName(), self.table().name), - self.name, new_name, new_type_str, - new_not_null, new_default_str, new_comment) + ret = ( + self.table() + .database() + .connector.updateTableColumn( + (self.table().schemaName(), self.table().name), + self.name, + new_name, + new_type_str, + new_not_null, + new_default_str, + new_comment, + ) + ) if ret is not False: self.table().refreshFields() return ret class TableConstraint(TableSubItemObject): - """ class that represents a constraint of a table (relation) """ - - TypeCheck, TypeForeignKey, TypePrimaryKey, TypeUnique, TypeExclusion, TypeUnknown = list(range(6)) - types = {"c": TypeCheck, "f": TypeForeignKey, "p": TypePrimaryKey, "u": TypeUnique, "x": TypeExclusion} - - onAction = {"a": "NO ACTION", "r": "RESTRICT", "c": "CASCADE", "n": "SET NULL", "d": "SET DEFAULT"} + """class that represents a constraint of a table (relation)""" + + ( + TypeCheck, + TypeForeignKey, + TypePrimaryKey, + TypeUnique, + TypeExclusion, + TypeUnknown, + ) = list(range(6)) + types = { + "c": TypeCheck, + "f": TypeForeignKey, + "p": TypePrimaryKey, + "u": TypeUnique, + "x": TypeExclusion, + } + + onAction = { + "a": "NO ACTION", + "r": "RESTRICT", + "c": "CASCADE", + "n": "SET NULL", + "d": "SET DEFAULT", + } matchTypes = {"u": "UNSPECIFIED", "f": "FULL", "p": "PARTIAL", "s": "SIMPLE"} def __init__(self, table): @@ -1305,11 +1594,11 @@ def type2String(self): return QApplication.translate("DBManagerPlugin", "Unique") if self.type == TableConstraint.TypeExclusion: return QApplication.translate("DBManagerPlugin", "Exclusion") - return QApplication.translate("DBManagerPlugin", 'Unknown') + return QApplication.translate("DBManagerPlugin", "Unknown") def fields(self): def fieldFromNum(num, fields): - """ return field specified by its number or None if doesn't exist """ + """return field specified by its number or None if doesn't exist""" for fld in fields: if fld.num == num: return fld @@ -1333,7 +1622,7 @@ def __init__(self, table): def fields(self): def fieldFromNum(num, fields): - """ return field specified by its number or None if doesn't exist """ + """return field specified by its number or None if doesn't exist""" for fld in fields: if fld.num == num: return fld @@ -1350,23 +1639,23 @@ def delete(self): class TableTrigger(TableSubItemObject): - """ class that represents a trigger """ + """class that represents a trigger""" # Bits within tgtype (pg_trigger.h) - TypeRow = (1 << 0) # row or statement - TypeBefore = (1 << 1) # before or after + TypeRow = 1 << 0 # row or statement + TypeBefore = 1 << 1 # before or after # events: one or more - TypeInsert = (1 << 2) - TypeDelete = (1 << 3) - TypeUpdate = (1 << 4) - TypeTruncate = (1 << 5) + TypeInsert = 1 << 2 + TypeDelete = 1 << 3 + TypeUpdate = 1 << 4 + TypeTruncate = 1 << 5 def __init__(self, table): TableSubItemObject.__init__(self, table) self.name = self.function = None def type2String(self): - trig_type = '' + trig_type = "" trig_type += "Before " if self.type & TableTrigger.TypeBefore else "After " if self.type & TableTrigger.TypeInsert: trig_type += "INSERT " diff --git a/python/plugins/db_manager/db_plugins/postgis/connector.py b/python/plugins/db_manager/db_plugins/postgis/connector.py index afe4ae3fc3f6..af63f10dff09 100644 --- a/python/plugins/db_manager/db_plugins/postgis/connector.py +++ b/python/plugins/db_manager/db_plugins/postgis/connector.py @@ -52,7 +52,7 @@ def classFactory(): return PostGisDBConnector -class CursorAdapter(): +class CursorAdapter: def _debug(self, msg): pass @@ -66,7 +66,7 @@ def __init__(self, connection, sql=None, feedback=None): self.cursor = 0 self.feedback = feedback self.closed = False - if (self.sql is not None): + if self.sql is not None: self._execute() def _toStrResultSet(self, res): @@ -75,11 +75,15 @@ def _toStrResultSet(self, res): newrec = [] for col in rec: if type(col) == type(QVariant(None)): # noqa - if (str(col) == 'NULL'): + if str(col) == "NULL": col = None else: col = str(col) # force to string - if isinstance(col, QDateTime) or isinstance(col, QDate) or isinstance(col, QTime): + if ( + isinstance(col, QDateTime) + or isinstance(col, QDate) + or isinstance(col, QTime) + ): col = col.toString(Qt.DateFormat.ISODate) newrec.append(col) newres.append(newrec) @@ -88,9 +92,9 @@ def _toStrResultSet(self, res): def _execute(self, sql=None): if (sql is None or self.sql == sql) and self.result is not None: return - if (sql is not None): + if sql is not None: self.sql = sql - if (self.sql is None): + if self.sql is None: return self._debug("execute called with sql " + self.sql) try: @@ -98,15 +102,17 @@ def _execute(self, sql=None): self._description = [] # reset description self.result = self._toStrResultSet(result.rows()) for c in result.columns(): - self._description.append([ - c, # name - '', # type_code - -1, # display_size - -1, # internal_size - -1, # precision - None, # scale - True # null_ok - ]) + self._description.append( + [ + c, # name + "", # type_code + -1, # display_size + -1, # internal_size + -1, # precision + None, # scale + True, # null_ok + ] + ) except QgsProviderConnectionException as e: self._description = None @@ -122,48 +128,62 @@ def description(self): self._description = [] - if re.match('^SHOW', self.sql.strip().upper()): + if re.match("^SHOW", self.sql.strip().upper()): try: count = len(self.connection.executeSql(self.sql)[0]) except QgsProviderConnectionException: count = 1 for i in range(count): - self._description.append([ - '', # name - '', # type_code - -1, # display_size - -1, # internal_size - -1, # precision - None, # scale - True # null_ok - ]) + self._description.append( + [ + "", # name + "", # type_code + -1, # display_size + -1, # internal_size + -1, # precision + None, # scale + True, # null_ok + ] + ) else: uri = QgsDataSourceUri(self.connection.uri()) # TODO: make this part provider-agnostic - sql = self.sql if self.sql.upper().find(' LIMIT ') >= 0 else self.sql + ' LIMIT 1 ' - uri.setTable('(SELECT row_number() OVER () AS __rid__, * FROM (' + sql + ') as foo)') - uri.setKeyColumn('__rid__') - uri.setParam('checkPrimaryKeyUnicity', '0') + sql = ( + self.sql + if self.sql.upper().find(" LIMIT ") >= 0 + else self.sql + " LIMIT 1 " + ) + uri.setTable( + "(SELECT row_number() OVER () AS __rid__, * FROM (" + + sql + + ") as foo)" + ) + uri.setKeyColumn("__rid__") + uri.setParam("checkPrimaryKeyUnicity", "0") # TODO: fetch provider name from connection (QgsAbstractConnectionProvider) # TODO: re-use the VectorLayer for fetching rows in batch mode - vl = QgsVectorLayer(uri.uri(False), 'dbmanager_cursor', 'postgres') + vl = QgsVectorLayer(uri.uri(False), "dbmanager_cursor", "postgres") fields = vl.fields() for i in range(1, len(fields)): # skip first field (__rid__) f = fields[i] - self._description.append([ - f.name(), # name - f.type(), # type_code - f.length(), # display_size - f.length(), # internal_size - f.precision(), # precision - None, # scale - True # null_ok - ]) - - self._debug("get_description returned " + str(len(self._description)) + " cols") + self._description.append( + [ + f.name(), # name + f.type(), # type_code + f.length(), # display_size + f.length(), # internal_size + f.precision(), # precision + None, # scale + True, # null_ok + ] + ) + + self._debug( + "get_description returned " + str(len(self._description)) + " cols" + ) return self._description @@ -178,33 +198,49 @@ def fetchone(self): def fetchmany(self, size): self._execute() if self.result is None: - self._debug("fetchmany: none result after _execute (self.sql is " + str(self.sql) + ", returning []") + self._debug( + "fetchmany: none result after _execute (self.sql is " + + str(self.sql) + + ", returning []" + ) return [] leftover = len(self.result) - self.cursor - self._debug("fetchmany: cursor: " + str(self.cursor) + " leftover: " + str(leftover) + " requested: " + str(size)) + self._debug( + "fetchmany: cursor: " + + str(self.cursor) + + " leftover: " + + str(leftover) + + " requested: " + + str(size) + ) if leftover < 1: return [] if size > leftover: size = leftover stop = self.cursor + size - res = self.result[self.cursor:stop] + res = self.result[self.cursor : stop] self.cursor = stop - self._debug("fetchmany: new cursor: " + str(self.cursor) + " reslen: " + str(len(self.result))) + self._debug( + "fetchmany: new cursor: " + + str(self.cursor) + + " reslen: " + + str(len(self.result)) + ) return res def fetchall(self): self._execute() - res = self.result[self.cursor:] + res = self.result[self.cursor :] self.cursor = len(self.result) return res - def scroll(self, pos, mode='relative'): + def scroll(self, pos, mode="relative"): self._execute() if pos < 0: self._debug("scroll pos is negative: " + str(pos)) - if mode == 'relative': + if mode == "relative": self.cursor = self.cursor + pos - elif mode == 'absolute': + elif mode == "absolute": self.cursor = pos def close(self): @@ -224,13 +260,13 @@ def __init__(self, uri, connection): """ DBConnector.__init__(self, uri) - username = uri.username() or os.environ.get('PGUSER') + username = uri.username() or os.environ.get("PGUSER") # Do not get db and user names from the env if service is used if not uri.service(): if username is None: - username = os.environ.get('USER') - self.dbname = uri.database() or os.environ.get('PGDATABASE') or username + username = os.environ.get("USER") + self.dbname = uri.database() or os.environ.get("PGDATABASE") or username uri.setDatabase(self.dbname) # self.connName = connName @@ -269,9 +305,13 @@ def removeCert(certFile): # On linux and Mac if file is set with QFile::>ReadUser # does not create problem removing certs if not file.setPermissions(QFile.Permission.WriteOwner): - raise Exception('Cannot change permissions on {}: error code: {}'.format(file.fileName(), file.error())) + raise Exception( + f"Cannot change permissions on {file.fileName()}: error code: {file.error()}" + ) if not file.remove(): - raise Exception('Cannot remove {}: error code: {}'.format(file.fileName(), file.error())) + raise Exception( + f"Cannot remove {file.fileName()}: error code: {file.error()}" + ) sslCertFile = expandedUri.param("sslcert") if sslCertFile: @@ -286,48 +326,59 @@ def removeCert(certFile): removeCert(sslCAFile) def _checkSpatial(self): - """ check whether postgis_version is present in catalog """ - c = self._execute(None, "SELECT COUNT(*) FROM pg_proc WHERE proname = 'postgis_version'") + """check whether postgis_version is present in catalog""" + c = self._execute( + None, "SELECT COUNT(*) FROM pg_proc WHERE proname = 'postgis_version'" + ) self.has_spatial = self._fetchone(c)[0] > 0 self._close_cursor(c) return self.has_spatial def _checkRaster(self): - """ check whether postgis_version is present in catalog """ - c = self._execute(None, "SELECT COUNT(*) FROM pg_proc WHERE proname = 'postgis_raster_lib_version'") + """check whether postgis_version is present in catalog""" + c = self._execute( + None, + "SELECT COUNT(*) FROM pg_proc WHERE proname = 'postgis_raster_lib_version'", + ) self.has_raster = self._fetchone(c)[0] > 0 self._close_cursor(c) return self.has_raster def _checkGeometryColumnsTable(self): - c = self._execute(None, - "SELECT relkind = 'v' OR relkind = 'm' FROM pg_class WHERE relname = 'geometry_columns' AND relkind IN ('v', 'r', 'm', 'p')") + c = self._execute( + None, + "SELECT relkind = 'v' OR relkind = 'm' FROM pg_class WHERE relname = 'geometry_columns' AND relkind IN ('v', 'r', 'm', 'p')", + ) res = self._fetchone(c) self._close_cursor(c) - self.has_geometry_columns = (res is not None and len(res) != 0) + self.has_geometry_columns = res is not None and len(res) != 0 if not self.has_geometry_columns: self.has_geometry_columns_access = self.is_geometry_columns_view = False else: self.is_geometry_columns_view = res[0] # find out whether has privileges to access geometry_columns table - priv = self.getTablePrivileges('geometry_columns') + priv = self.getTablePrivileges("geometry_columns") self.has_geometry_columns_access = priv[0] return self.has_geometry_columns def _checkRasterColumnsTable(self): - c = self._execute(None, - "SELECT relkind = 'v' OR relkind = 'm' FROM pg_class WHERE relname = 'raster_columns' AND relkind IN ('v', 'r', 'm', 'p')") + c = self._execute( + None, + "SELECT relkind = 'v' OR relkind = 'm' FROM pg_class WHERE relname = 'raster_columns' AND relkind IN ('v', 'r', 'm', 'p')", + ) res = self._fetchone(c) self._close_cursor(c) - self.has_raster_columns = (res is not None and len(res) != 0) + self.has_raster_columns = res is not None and len(res) != 0 if not self.has_raster_columns: self.has_raster_columns_access = self.is_raster_columns_view = False else: self.is_raster_columns_view = res[0] # find out whether has privileges to access geometry_columns table - self.has_raster_columns_access = self.getTablePrivileges('raster_columns')[0] + self.has_raster_columns_access = self.getTablePrivileges("raster_columns")[ + 0 + ] return self.has_raster_columns def cancel(self): @@ -350,19 +401,21 @@ def getPsqlVersion(self): raise DbError(f"Unknown PostgreSQL version: {self.getInfo()[0]}") def getSpatialInfo(self): - """ returns tuple about PostGIS support: - - lib version - - geos version - - proj version - - installed scripts version - - released scripts version + """returns tuple about PostGIS support: + - lib version + - geos version + - proj version + - installed scripts version + - released scripts version """ if not self.has_spatial: return try: - c = self._execute(None, - "SELECT postgis_lib_version(), postgis_geos_version(), postgis_proj_version(), postgis_scripts_installed(), postgis_scripts_released()") + c = self._execute( + None, + "SELECT postgis_lib_version(), postgis_geos_version(), postgis_proj_version(), postgis_scripts_installed(), postgis_scripts_released()", + ) except DbError: return res = self._fetchone(c) @@ -386,16 +439,26 @@ def hasCreateSpatialViewSupport(self): def fieldTypes(self): return [ - "integer", "bigint", "smallint", # integers - "serial", "bigserial", # auto-incrementing ints - "real", "double precision", "numeric", # floats - "varchar", "varchar(255)", "char(20)", "text", # strings - "date", "time", "timestamp", # date/time - "boolean" # bool + "integer", + "bigint", + "smallint", # integers + "serial", + "bigserial", # auto-incrementing ints + "real", + "double precision", + "numeric", # floats + "varchar", + "varchar(255)", + "char(20)", + "text", # strings + "date", + "time", + "timestamp", # date/time + "boolean", # bool ] def getDatabasePrivileges(self): - """ db privileges: (can create schemas, can create temp. tables) """ + """db privileges: (can create schemas, can create temp. tables)""" sql = "SELECT has_database_privilege(current_database(), 'CREATE'), has_database_privilege(current_database(), 'TEMP')" c = self._execute(None, sql) res = self._fetchone(c) @@ -403,16 +466,18 @@ def getDatabasePrivileges(self): return res def getSchemaPrivileges(self, schema): - """ schema privileges: (can create new objects, can access objects in schema) """ - schema = 'current_schema()' if schema is None else self.quoteString(schema) - sql = "SELECT has_schema_privilege(%(s)s, 'CREATE'), has_schema_privilege(%(s)s, 'USAGE')" % {'s': schema} + """schema privileges: (can create new objects, can access objects in schema)""" + schema = "current_schema()" if schema is None else self.quoteString(schema) + sql = "SELECT has_schema_privilege({s}, 'CREATE'), has_schema_privilege({s}, 'USAGE')".format( + s=schema + ) c = self._execute(None, sql) res = self._fetchone(c) self._close_cursor(c) return res def getTablePrivileges(self, table): - """ table privileges: (select, insert, update, delete) """ + """table privileges: (select, insert, update, delete)""" schema, tablename = self.getSchemaTableName(table) schema_priv = self.getSchemaPrivileges(schema) @@ -420,16 +485,17 @@ def getTablePrivileges(self, table): return t = self.quoteId(table) - sql = """SELECT has_table_privilege(%(t)s, 'SELECT'), has_table_privilege(%(t)s, 'INSERT'), - has_table_privilege(%(t)s, 'UPDATE'), has_table_privilege(%(t)s, 'DELETE')""" % { - 't': self.quoteString(t)} + sql = """SELECT has_table_privilege({t}, 'SELECT'), has_table_privilege({t}, 'INSERT'), + has_table_privilege({t}, 'UPDATE'), has_table_privilege({t}, 'DELETE')""".format( + t=self.quoteString(t) + ) c = self._execute(None, sql) res = self._fetchone(c) self._close_cursor(c) return res def getSchemas(self): - """ get list of schemas in tuples: (oid, name, owner, perms) """ + """get list of schemas in tuples: (oid, name, owner, perms)""" sql = "SELECT oid, nspname, pg_get_userbyid(nspowner), nspacl, pg_catalog.obj_description(oid) FROM pg_namespace WHERE nspname !~ '^pg_' AND nspname != 'information_schema' ORDER BY nspname" c = self._execute(None, sql) @@ -438,17 +504,26 @@ def getSchemas(self): return res def getTables(self, schema=None, add_sys_tables=False): - """ get list of tables """ + """get list of tables""" tablenames = [] items = [] - sys_tables = ["spatial_ref_sys", "geography_columns", "geometry_columns", - "raster_columns", "raster_overviews"] + sys_tables = [ + "spatial_ref_sys", + "geography_columns", + "geometry_columns", + "raster_columns", + "raster_overviews", + ] try: vectors = self.getVectorTables(schema) for tbl in vectors: - if not add_sys_tables and tbl[1] in sys_tables and tbl[2] in ['', 'public']: + if ( + not add_sys_tables + and tbl[1] in sys_tables + and tbl[2] in ["", "public"] + ): continue tablenames.append((tbl[2], tbl[1])) items.append(tbl) @@ -458,30 +533,45 @@ def getTables(self, schema=None, add_sys_tables=False): try: rasters = self.getRasterTables(schema) for tbl in rasters: - if not add_sys_tables and tbl[1] in sys_tables and tbl[2] in ['', 'public']: + if ( + not add_sys_tables + and tbl[1] in sys_tables + and tbl[2] in ["", "public"] + ): continue tablenames.append((tbl[2], tbl[1])) items.append(tbl) except DbError: pass - sys_tables = ["spatial_ref_sys", "geography_columns", "geometry_columns", - "raster_columns", "raster_overviews"] + sys_tables = [ + "spatial_ref_sys", + "geography_columns", + "geometry_columns", + "raster_columns", + "raster_overviews", + ] if schema: schema_where = " AND nspname = %s " % self.quoteString(schema) else: - schema_where = " AND (nspname != 'information_schema' AND nspname !~ 'pg_') " + schema_where = ( + " AND (nspname != 'information_schema' AND nspname !~ 'pg_') " + ) # get all tables and views - sql = """SELECT + sql = ( + """SELECT cla.relname, nsp.nspname, cla.relkind, pg_get_userbyid(relowner), reltuples, relpages, pg_catalog.obj_description(cla.oid) FROM pg_class AS cla JOIN pg_namespace AS nsp ON nsp.oid = cla.relnamespace - WHERE cla.relkind IN ('v', 'r', 'm', 'p') """ + schema_where + """ + WHERE cla.relkind IN ('v', 'r', 'm', 'p') """ + + schema_where + + """ ORDER BY nsp.nspname, cla.relname""" + ) c = self._execute(None, sql) for tbl in self._fetchall(c): @@ -494,19 +584,19 @@ def getTables(self, schema=None, add_sys_tables=False): return sorted(items, key=cmp_to_key(lambda x, y: (x[1] > y[1]) - (x[1] < y[1]))) def getVectorTables(self, schema=None): - """ get list of table with a geometry column - it returns: - name (table name) - namespace (schema) - type = 'view' (is a view?) - owner - tuples - pages - geometry_column: - f_geometry_column (or pg_attribute.attname, the geometry column name) - type (or pg_attribute.atttypid::regtype, the geometry column type name) - coord_dimension - srid + """get list of table with a geometry column + it returns: + name (table name) + namespace (schema) + type = 'view' (is a view?) + owner + tuples + pages + geometry_column: + f_geometry_column (or pg_attribute.attname, the geometry column name) + type (or pg_attribute.atttypid::regtype, the geometry column type name) + coord_dimension + srid """ if not self.has_spatial: @@ -515,7 +605,9 @@ def getVectorTables(self, schema=None): if schema: schema_where = " AND nspname = %s " % self.quoteString(schema) else: - schema_where = " AND (nspname != 'information_schema' AND nspname !~ 'pg_') " + schema_where = ( + " AND (nspname != 'information_schema' AND nspname !~ 'pg_') " + ) geometry_column_from = "" geometry_fields_select = """att.attname, @@ -530,11 +622,14 @@ def getVectorTables(self, schema=None): geo.coord_dimension, geo.srid""" # discovery of all tables and whether they contain a geometry column - sql = """SELECT + sql = ( + """SELECT cla.relname, nsp.nspname, cla.relkind, pg_get_userbyid(relowner), cla.reltuples, cla.relpages, pg_catalog.obj_description(cla.oid), - """ + geometry_fields_select + """ + """ + + geometry_fields_select + + """ FROM pg_class AS cla JOIN pg_namespace AS nsp ON @@ -545,10 +640,15 @@ def getVectorTables(self, schema=None): att.atttypid = 'geometry'::regtype OR att.atttypid IN (SELECT oid FROM pg_type WHERE typbasetype='geometry'::regtype ) - """ + geometry_column_from + """ + """ + + geometry_column_from + + """ - WHERE cla.relkind IN ('v', 'r', 'm', 'p') """ + schema_where + """ + WHERE cla.relkind IN ('v', 'r', 'm', 'p') """ + + schema_where + + """ ORDER BY nsp.nspname, cla.relname, att.attname""" + ) items = [] @@ -562,20 +662,20 @@ def getVectorTables(self, schema=None): return items def getRasterTables(self, schema=None): - """ get list of table with a raster column - it returns: - name (table name) - namespace (schema) - type = 'view' (is a view?) - owner - tuples - pages - raster_column: - r_raster_column (or pg_attribute.attname, the raster column name) - pixel type - block size - internal or external - srid + """get list of table with a raster column + it returns: + name (table name) + namespace (schema) + type = 'view' (is a view?) + owner + tuples + pages + raster_column: + r_raster_column (or pg_attribute.attname, the raster column name) + pixel type + block size + internal or external + srid """ if not self.has_spatial: @@ -586,7 +686,9 @@ def getRasterTables(self, schema=None): if schema: schema_where = " AND nspname = %s " % self.quoteString(schema) else: - schema_where = " AND (nspname != 'information_schema' AND nspname !~ 'pg_') " + schema_where = ( + " AND (nspname != 'information_schema' AND nspname !~ 'pg_') " + ) raster_column_from = "" raster_fields_select = """att.attname, NULL, NULL, NULL, NULL, NULL""" @@ -602,11 +704,14 @@ def getRasterTables(self, schema=None): rast.srid""" # discovery of all tables and whether they contain a raster column - sql = """SELECT + sql = ( + """SELECT cla.relname, nsp.nspname, cla.relkind, pg_get_userbyid(relowner), cla.reltuples, cla.relpages, pg_catalog.obj_description(cla.oid), - """ + raster_fields_select + """ + """ + + raster_fields_select + + """ FROM pg_class AS cla JOIN pg_namespace AS nsp ON @@ -617,10 +722,15 @@ def getRasterTables(self, schema=None): att.atttypid = 'raster'::regtype OR att.atttypid IN (SELECT oid FROM pg_type WHERE typbasetype='raster'::regtype ) - """ + raster_column_from + """ + """ + + raster_column_from + + """ - WHERE cla.relkind IN ('v', 'r', 'm', 'p') """ + schema_where + """ + WHERE cla.relkind IN ('v', 'r', 'm', 'p') """ + + schema_where + + """ ORDER BY nsp.nspname, cla.relname, att.attname""" + ) items = [] @@ -640,13 +750,15 @@ def getTableRowCount(self, table): return res def getTableFields(self, table): - """ return list of columns in table """ + """return list of columns in table""" schema, tablename = self.getSchemaTableName(table) - schema_where = " AND nspname=%s " % self.quoteString(schema) if schema is not None else "" + schema_where = ( + " AND nspname=%s " % self.quoteString(schema) if schema is not None else "" + ) version_number = self.getPsqlVersion() - ad_col_name = 'adsrc' if version_number < 12 else 'adbin' + ad_col_name = "adsrc" if version_number < 12 else "adbin" sql = """SELECT a.attnum AS ordinal_position, a.attname AS column_name, @@ -655,7 +767,7 @@ def getTableFields(self, table): a.atttypmod AS modifier, a.attnotnull AS notnull, a.atthasdef AS hasdefault, - adef.%s AS default_value, + adef.{} AS default_value, pg_catalog.format_type(a.atttypid,a.atttypmod) AS formatted_type FROM pg_class c JOIN pg_attribute a ON a.attrelid = c.oid @@ -663,8 +775,10 @@ def getTableFields(self, table): JOIN pg_namespace nsp ON c.relnamespace = nsp.oid LEFT JOIN pg_attrdef adef ON adef.adrelid = a.attrelid AND adef.adnum = a.attnum WHERE - a.attnum > 0 AND c.relname=%s %s - ORDER BY a.attnum""" % (ad_col_name, self.quoteString(tablename), schema_where) + a.attnum > 0 AND c.relname={} {} + ORDER BY a.attnum""".format( + ad_col_name, self.quoteString(tablename), schema_where + ) c = self._execute(None, sql) res = self._fetchall(c) @@ -672,17 +786,20 @@ def getTableFields(self, table): return res def getTableIndexes(self, table): - """ get info about table's indexes. ignore primary key constraint index, they get listed in constraints """ + """get info about table's indexes. ignore primary key constraint index, they get listed in constraints""" schema, tablename = self.getSchemaTableName(table) - schema_where = " AND nspname=%s " % self.quoteString(schema) if schema is not None else "" + schema_where = ( + " AND nspname=%s " % self.quoteString(schema) if schema is not None else "" + ) sql = """SELECT idxcls.relname, indkey, indisunique = 't' FROM pg_index JOIN pg_class ON pg_index.indrelid=pg_class.oid JOIN pg_class AS idxcls ON pg_index.indexrelid=idxcls.oid JOIN pg_namespace nsp ON pg_class.relnamespace = nsp.oid - WHERE pg_class.relname=%s %s - AND indisprimary != 't' """ % ( - self.quoteString(tablename), schema_where) + WHERE pg_class.relname={} {} + AND indisprimary != 't' """.format( + self.quoteString(tablename), schema_where + ) c = self._execute(None, sql) res = self._fetchall(c) self._close_cursor(c) @@ -691,20 +808,24 @@ def getTableIndexes(self, table): def getTableConstraints(self, table): schema, tablename = self.getSchemaTableName(table) - schema_where = " AND nspname=%s " % self.quoteString(schema) if schema is not None else "" + schema_where = ( + " AND nspname=%s " % self.quoteString(schema) if schema is not None else "" + ) version_number = self.getPsqlVersion() - con_col_name = 'consrc' if version_number < 12 else 'conbin' + con_col_name = "consrc" if version_number < 12 else "conbin" # In the query below, we exclude rows where pg_constraint.contype whose values are equal to 't' # because 't' describes a CONSTRAINT TRIGGER, which is not really a constraint in the traditional # sense, but a special type of trigger, and an extension to the SQL standard. - sql = """SELECT c.conname, c.contype, c.condeferrable, c.condeferred, array_to_string(c.conkey, ' '), c.%s, + sql = """SELECT c.conname, c.contype, c.condeferrable, c.condeferred, array_to_string(c.conkey, ' '), c.{}, t2.relname, c.confupdtype, c.confdeltype, c.confmatchtype, array_to_string(c.confkey, ' ') FROM pg_constraint c LEFT JOIN pg_class t ON c.conrelid = t.oid LEFT JOIN pg_class t2 ON c.confrelid = t2.oid JOIN pg_namespace nsp ON t.relnamespace = nsp.oid - WHERE c.contype <> 't' AND t.relname = %s %s """ % (con_col_name, self.quoteString(tablename), schema_where) + WHERE c.contype <> 't' AND t.relname = {} {} """.format( + con_col_name, self.quoteString(tablename), schema_where + ) c = self._execute(None, sql) res = self._fetchall(c) @@ -714,14 +835,17 @@ def getTableConstraints(self, table): def getTableTriggers(self, table): schema, tablename = self.getSchemaTableName(table) - schema_where = " AND nspname=%s " % self.quoteString(schema) if schema is not None else "" + schema_where = ( + " AND nspname=%s " % self.quoteString(schema) if schema is not None else "" + ) sql = """SELECT tgname, proname, tgtype, tgenabled NOT IN ('f', 'D') FROM pg_trigger trig LEFT JOIN pg_class t ON trig.tgrelid = t.oid LEFT JOIN pg_proc p ON trig.tgfoid = p.oid JOIN pg_namespace nsp ON t.relnamespace = nsp.oid - WHERE t.relname = %s %s """ % ( - self.quoteString(tablename), schema_where) + WHERE t.relname = {} {} """.format( + self.quoteString(tablename), schema_where + ) c = self._execute(None, sql) res = self._fetchall(c) @@ -729,27 +853,35 @@ def getTableTriggers(self, table): return res def enableAllTableTriggers(self, enable, table): - """ enable or disable all triggers on table """ + """enable or disable all triggers on table""" self.enableTableTrigger(None, enable, table) def enableTableTrigger(self, trigger, enable, table): - """ enable or disable one trigger on table """ + """enable or disable one trigger on table""" trigger = self.quoteId(trigger) if trigger is not None else "ALL" - sql = "ALTER TABLE %s %s TRIGGER %s" % (self.quoteId(table), "ENABLE" if enable else "DISABLE", trigger) + sql = "ALTER TABLE {} {} TRIGGER {}".format( + self.quoteId(table), "ENABLE" if enable else "DISABLE", trigger + ) self._execute_and_commit(sql) def deleteTableTrigger(self, trigger, table): - """Deletes trigger on table """ - sql = "DROP TRIGGER %s ON %s" % (self.quoteId(trigger), self.quoteId(table)) + """Deletes trigger on table""" + sql = f"DROP TRIGGER {self.quoteId(trigger)} ON {self.quoteId(table)}" self._execute_and_commit(sql) def getTableRules(self, table): schema, tablename = self.getSchemaTableName(table) - schema_where = " AND schemaname=%s " % self.quoteString(schema) if schema is not None else "" + schema_where = ( + " AND schemaname=%s " % self.quoteString(schema) + if schema is not None + else "" + ) sql = """SELECT rulename, definition FROM pg_rules - WHERE tablename=%s %s """ % (self.quoteString(tablename), schema_where) + WHERE tablename={} {} """.format( + self.quoteString(tablename), schema_where + ) c = self._execute(None, sql) res = self._fetchall(c) @@ -757,14 +889,19 @@ def getTableRules(self, table): return res def deleteTableRule(self, rule, table): - """Deletes rule on table """ - sql = "DROP RULE %s ON %s" % (self.quoteId(rule), self.quoteId(table)) + """Deletes rule on table""" + sql = f"DROP RULE {self.quoteId(rule)} ON {self.quoteId(table)}" self._execute_and_commit(sql) def getTableExtent(self, table, geom): - """ find out table extent """ - subquery = "SELECT st_extent(%s) AS extent FROM %s" % (self.quoteId(geom), self.quoteId(table)) - sql = "SELECT st_xmin(extent), st_ymin(extent), st_xmax(extent), st_ymax(extent) FROM (%s) AS subquery" % subquery + """find out table extent""" + subquery = "SELECT st_extent({}) AS extent FROM {}".format( + self.quoteId(geom), self.quoteId(table) + ) + sql = ( + "SELECT st_xmin(extent), st_ymin(extent), st_xmax(extent), st_ymax(extent) FROM (%s) AS subquery" + % subquery + ) c = self._execute(None, sql) res = self._fetchone(c) @@ -772,14 +909,14 @@ def getTableExtent(self, table, geom): return res def getTableEstimatedExtent(self, table, geom): - """ find out estimated extent (from the statistics) """ + """find out estimated extent (from the statistics)""" if self.isRasterTable(table): return schema, tablename = self.getSchemaTableName(table) schema_part = "%s," % self.quoteString(schema) if schema is not None else "" - pgis_versions = self.getSpatialInfo()[0].split('.') + pgis_versions = self.getSpatialInfo()[0].split(".") pgis_major_version = int(pgis_versions[0]) pgis_minor_version = int(pgis_versions[1]) pgis_old = False @@ -787,10 +924,16 @@ def getTableEstimatedExtent(self, table, geom): pgis_old = True elif pgis_major_version == 2 and pgis_minor_version < 1: pgis_old = True - subquery = "SELECT %s(%s%s,%s) AS extent" % ( - 'st_estimated_extent' if pgis_old else 'st_estimatedextent', - schema_part, self.quoteString(tablename), self.quoteString(geom)) - sql = """SELECT st_xmin(extent), st_ymin(extent), st_xmax(extent), st_ymax(extent) FROM (%s) AS subquery """ % subquery + subquery = "SELECT {}({}{},{}) AS extent".format( + "st_estimated_extent" if pgis_old else "st_estimatedextent", + schema_part, + self.quoteString(tablename), + self.quoteString(geom), + ) + sql = ( + """SELECT st_xmin(extent), st_ymin(extent), st_xmax(extent), st_ymax(extent) FROM (%s) AS subquery """ + % subquery + ) try: c = self._execute(None, sql) @@ -801,15 +944,18 @@ def getTableEstimatedExtent(self, table, geom): return res def getViewDefinition(self, view): - """ returns definition of the view """ + """returns definition of the view""" schema, tablename = self.getSchemaTableName(view) - schema_where = " AND nspname=%s " % self.quoteString(schema) if schema is not None else "" + schema_where = ( + " AND nspname=%s " % self.quoteString(schema) if schema is not None else "" + ) sql = """SELECT pg_get_viewdef(c.oid) FROM pg_class c JOIN pg_namespace nsp ON c.relnamespace = nsp.oid - WHERE relname=%s %s AND (relkind='v' OR relkind='m') """ % ( - self.quoteString(tablename), schema_where) + WHERE relname={} {} AND (relkind='v' OR relkind='m') """.format( + self.quoteString(tablename), schema_where + ) c = self._execute(None, sql) res = self._fetchone(c) @@ -821,7 +967,9 @@ def getCrs(self, srid): return QgsCoordinateReferenceSystem() try: - c = self._execute(None, "SELECT proj4text FROM spatial_ref_sys WHERE srid = '%d'" % srid) + c = self._execute( + None, "SELECT proj4text FROM spatial_ref_sys WHERE srid = '%d'" % srid + ) except DbError: return QgsCoordinateReferenceSystem() res = self._fetchone(c) @@ -838,7 +986,9 @@ def getSpatialRefInfo(self, srid): return try: - c = self._execute(None, "SELECT srtext FROM spatial_ref_sys WHERE srid = '%d'" % srid) + c = self._execute( + None, "SELECT srtext FROM spatial_ref_sys WHERE srid = '%d'" % srid + ) except DbError: return sr = self._fetchone(c) @@ -857,8 +1007,9 @@ def getSpatialRefInfo(self, srid): def isVectorTable(self, table): if self.has_geometry_columns and self.has_geometry_columns_access: schema, tablename = self.getSchemaTableName(table) - sql = "SELECT count(*) FROM geometry_columns WHERE f_table_schema = %s AND f_table_name = %s" % ( - self.quoteString(schema), self.quoteString(tablename)) + sql = "SELECT count(*) FROM geometry_columns WHERE f_table_schema = {} AND f_table_name = {}".format( + self.quoteString(schema), self.quoteString(tablename) + ) c = self._execute(None, sql) res = self._fetchone(c) @@ -870,8 +1021,9 @@ def isVectorTable(self, table): def isRasterTable(self, table): if self.has_raster_columns and self.has_raster_columns_access: schema, tablename = self.getSchemaTableName(table) - sql = "SELECT count(*) FROM raster_columns WHERE r_table_schema = %s AND r_table_name = %s" % ( - self.quoteString(schema), self.quoteString(tablename)) + sql = "SELECT count(*) FROM raster_columns WHERE r_table_schema = {} AND r_table_name = {}".format( + self.quoteString(schema), self.quoteString(tablename) + ) c = self._execute(None, sql) res = self._fetchone(c) @@ -882,8 +1034,8 @@ def isRasterTable(self, table): def createTable(self, table, field_defs, pkey): """Creates ordinary table - 'fields' is array containing field definitions - 'pkey' is the primary key name + 'fields' is array containing field definitions + 'pkey' is the primary key name """ if len(field_defs) == 0: return False @@ -898,11 +1050,13 @@ def createTable(self, table, field_defs, pkey): return True def deleteTable(self, table): - """Deletes table and its reference in either geometry_columns or raster_columns """ + """Deletes table and its reference in either geometry_columns or raster_columns""" schema, tablename = self.getSchemaTableName(table) schema_part = "%s, " % self.quoteString(schema) if schema is not None else "" if self.isVectorTable(table): - sql = "SELECT DropGeometryTable(%s%s)" % (schema_part, self.quoteString(tablename)) + sql = "SELECT DropGeometryTable({}{})".format( + schema_part, self.quoteString(tablename) + ) elif self.isRasterTable(table): # Fix #8521: delete raster table and references from raster_columns table sql = "DROP TABLE %s" % self.quoteId(table) @@ -911,24 +1065,31 @@ def deleteTable(self, table): self._execute_and_commit(sql) def emptyTable(self, table): - """Deletes all rows from table """ + """Deletes all rows from table""" sql = "TRUNCATE %s" % self.quoteId(table) self._execute_and_commit(sql) def renameTable(self, table, new_table): - """Renames a table in database """ + """Renames a table in database""" schema, tablename = self.getSchemaTableName(table) if new_table == tablename: return - sql = "ALTER TABLE %s RENAME TO %s" % (self.quoteId(table), self.quoteId(new_table)) + sql = "ALTER TABLE {} RENAME TO {}".format( + self.quoteId(table), self.quoteId(new_table) + ) self._executeSql(sql) # update geometry_columns if PostGIS is enabled if self.has_geometry_columns and not self.is_geometry_columns_view: - schema_where = " AND f_table_schema=%s " % self.quoteString(schema) if schema is not None else "" - sql = "UPDATE geometry_columns SET f_table_name=%s WHERE f_table_name=%s %s" % ( - self.quoteString(new_table), self.quoteString(tablename), schema_where) + schema_where = ( + " AND f_table_schema=%s " % self.quoteString(schema) + if schema is not None + else "" + ) + sql = "UPDATE geometry_columns SET f_table_name={} WHERE f_table_name={} {}".format( + self.quoteString(new_table), self.quoteString(tablename), schema_where + ) self._executeSql(sql) def renameSchema(self, schema, new_schema): @@ -940,16 +1101,23 @@ def renameSchema(self, schema, new_schema): def commentTable(self, schema, tablename, comment=None): if comment is None: - self._execute(None, 'COMMENT ON TABLE "{}"."{}" IS NULL;'.format(schema, tablename)) + self._execute(None, f'COMMENT ON TABLE "{schema}"."{tablename}" IS NULL;') else: - self._execute(None, 'COMMENT ON TABLE "{}"."{}" IS $escape${}$escape$;'.format(schema, tablename, comment)) + self._execute( + None, + f'COMMENT ON TABLE "{schema}"."{tablename}" IS $escape${comment}$escape$;', + ) def getComment(self, tablename, field): """Returns the comment for a field""" # SQL Query checking if a comment exists for the field - sql_cpt = "Select count(*) from pg_description pd, pg_class pc, pg_attribute pa where relname = '%s' and attname = '%s' and pa.attrelid = pc.oid and pd.objoid = pc.oid and pd.objsubid = pa.attnum" % (tablename, field) + sql_cpt = "Select count(*) from pg_description pd, pg_class pc, pg_attribute pa where relname = '{}' and attname = '{}' and pa.attrelid = pc.oid and pd.objoid = pc.oid and pd.objsubid = pa.attnum".format( + tablename, field + ) # SQL Query that return the comment of the field - sql = "Select pd.description from pg_description pd, pg_class pc, pg_attribute pa where relname = '%s' and attname = '%s' and pa.attrelid = pc.oid and pd.objoid = pc.oid and pd.objsubid = pa.attnum" % (tablename, field) + sql = "Select pd.description from pg_description pd, pg_class pc, pg_attribute pa where relname = '{}' and attname = '{}' and pa.attrelid = pc.oid and pd.objoid = pc.oid and pd.objsubid = pa.attnum".format( + tablename, field + ) c = self._execute(None, sql_cpt) # Execute Check query res = self._fetchone(c)[0] # Store result if res == 1: @@ -959,7 +1127,7 @@ def getComment(self, tablename, field): self._close_cursor(c) # Close cursor return res # Return comment else: - return '' + return "" def moveTableToSchema(self, table, new_schema): schema, tablename = self.getSchemaTableName(table) @@ -968,15 +1136,22 @@ def moveTableToSchema(self, table, new_schema): c = self._get_cursor() - sql = "ALTER TABLE %s SET SCHEMA %s" % (self.quoteId(table), self.quoteId(new_schema)) + sql = "ALTER TABLE {} SET SCHEMA {}".format( + self.quoteId(table), self.quoteId(new_schema) + ) self._execute(c, sql) # update geometry_columns if PostGIS is enabled if self.has_geometry_columns and not self.is_geometry_columns_view: schema, tablename = self.getSchemaTableName(table) - schema_where = " AND f_table_schema=%s " % self.quoteString(schema) if schema is not None else "" - sql = "UPDATE geometry_columns SET f_table_schema=%s WHERE f_table_name=%s %s" % ( - self.quoteString(new_schema), self.quoteString(tablename), schema_where) + schema_where = ( + " AND f_table_schema=%s " % self.quoteString(schema) + if schema is not None + else "" + ) + sql = "UPDATE geometry_columns SET f_table_schema={} WHERE f_table_name={} {}".format( + self.quoteString(new_schema), self.quoteString(tablename), schema_where + ) self._execute(c, sql) self._commit() @@ -993,100 +1168,145 @@ def moveTable(self, table, new_table, new_schema=None): c = self._get_cursor() t = "__new_table__" - sql = "ALTER TABLE %s RENAME TO %s" % (self.quoteId(table), self.quoteId(t)) + sql = "ALTER TABLE {} RENAME TO {}".format( + self.quoteId(table), self.quoteId(t) + ) self._execute(c, sql) - sql = "ALTER TABLE %s SET SCHEMA %s" % (self.quoteId((schema, t)), self.quoteId(new_schema)) + sql = "ALTER TABLE {} SET SCHEMA {}".format( + self.quoteId((schema, t)), self.quoteId(new_schema) + ) self._execute(c, sql) - sql = "ALTER TABLE %s RENAME TO %s" % (self.quoteId((new_schema, t)), self.quoteId(table)) + sql = "ALTER TABLE {} RENAME TO {}".format( + self.quoteId((new_schema, t)), self.quoteId(table) + ) self._execute(c, sql) # update geometry_columns if PostGIS is enabled if self.has_geometry_columns and not self.is_geometry_columns_view: schema, tablename = self.getSchemaTableName(table) - schema_where = " f_table_schema=%s AND " % self.quoteString(schema) if schema is not None else "" - schema_part = " f_table_schema=%s, " % self.quoteString(new_schema) if schema is not None else "" - sql = "UPDATE geometry_columns SET %s f_table_name=%s WHERE %s f_table_name=%s" % ( - schema_part, self.quoteString(new_table), schema_where, self.quoteString(tablename)) + schema_where = ( + " f_table_schema=%s AND " % self.quoteString(schema) + if schema is not None + else "" + ) + schema_part = ( + " f_table_schema=%s, " % self.quoteString(new_schema) + if schema is not None + else "" + ) + sql = "UPDATE geometry_columns SET {} f_table_name={} WHERE {} f_table_name={}".format( + schema_part, + self.quoteString(new_table), + schema_where, + self.quoteString(tablename), + ) self._execute(c, sql) self._commit() def createView(self, view, query): - view_name_parts = view.split('.') + view_name_parts = view.split(".") if len(view_name_parts) > 2: # Raise an error when more than one period is used. - raise DbError("Invalid view name: Please use the format 'schema.viewname', or enter only the viewname for the public schema.") + raise DbError( + "Invalid view name: Please use the format 'schema.viewname', or enter only the viewname for the public schema." + ) elif len(view_name_parts) == 2: # To allow view creation into specified schema schema, view_name = view_name_parts - sql = "CREATE VIEW %s AS %s" % (self.quoteId([schema, view_name]), query) + sql = "CREATE VIEW {} AS {}".format( + self.quoteId([schema, view_name]), query + ) else: # No specific schema specified - sql = "CREATE VIEW %s AS %s" % (self.quoteId(view), query) + sql = f"CREATE VIEW {self.quoteId(view)} AS {query}" self._execute_and_commit(sql) def createSpatialView(self, view, query): self.createView(view, query) def deleteView(self, view, isMaterialized=False): - sql = "DROP %s VIEW %s" % ('MATERIALIZED' if isMaterialized else '', self.quoteId(view)) + sql = "DROP {} VIEW {}".format( + "MATERIALIZED" if isMaterialized else "", self.quoteId(view) + ) self._execute_and_commit(sql) def renameView(self, view, new_name): - """Renames view in database """ + """Renames view in database""" self.renameTable(view, new_name) def createSchema(self, schema): - """Creates a new empty schema in database """ + """Creates a new empty schema in database""" sql = "CREATE SCHEMA %s" % self.quoteId(schema) self._execute_and_commit(sql) def deleteSchema(self, schema): - """Drops (empty) schema from database """ + """Drops (empty) schema from database""" sql = "DROP SCHEMA %s" % self.quoteId(schema) self._execute_and_commit(sql) def renamesSchema(self, schema, new_schema): - """Renames a schema in database """ - sql = "ALTER SCHEMA %s RENAME TO %s" % (self.quoteId(schema), self.quoteId(new_schema)) + """Renames a schema in database""" + sql = "ALTER SCHEMA {} RENAME TO {}".format( + self.quoteId(schema), self.quoteId(new_schema) + ) self._execute_and_commit(sql) def runVacuum(self): - """Runs vacuum on the db """ + """Runs vacuum on the db""" self._execute_and_commit("VACUUM") def runVacuumAnalyze(self, table): - """Runs vacuum analyze on a table """ + """Runs vacuum analyze on a table""" sql = "VACUUM ANALYZE %s" % self.quoteId(table) self._execute(None, sql) self._commit() def runRefreshMaterializedView(self, table): - """Runs refresh materialized view on a table """ + """Runs refresh materialized view on a table""" sql = "REFRESH MATERIALIZED VIEW %s" % self.quoteId(table) self._execute(None, sql) self._commit() def addTableColumn(self, table, field_def): - """Adds a column to table """ - sql = "ALTER TABLE %s ADD %s" % (self.quoteId(table), field_def) + """Adds a column to table""" + sql = f"ALTER TABLE {self.quoteId(table)} ADD {field_def}" self._execute_and_commit(sql) def deleteTableColumn(self, table, column): - """Deletes column from a table """ + """Deletes column from a table""" if self.isGeometryColumn(table, column): # use PostGIS function to delete geometry column correctly schema, tablename = self.getSchemaTableName(table) schema_part = "%s, " % self.quoteString(schema) if schema else "" - sql = "SELECT DropGeometryColumn(%s%s, %s)" % ( - schema_part, self.quoteString(tablename), self.quoteString(column)) + sql = "SELECT DropGeometryColumn({}{}, {})".format( + schema_part, self.quoteString(tablename), self.quoteString(column) + ) else: - sql = "ALTER TABLE %s DROP %s" % (self.quoteId(table), self.quoteId(column)) + sql = "ALTER TABLE {} DROP {}".format( + self.quoteId(table), self.quoteId(column) + ) self._execute_and_commit(sql) - def updateTableColumn(self, table, column, new_name=None, data_type=None, not_null=None, default=None, comment=None, test=None): - if new_name is None and data_type is None and not_null is None and default is None and comment is None: + def updateTableColumn( + self, + table, + column, + new_name=None, + data_type=None, + not_null=None, + default=None, + comment=None, + test=None, + ): + if ( + new_name is None + and data_type is None + and not_null is None + and default is None + and comment is None + ): return c = self._get_cursor() @@ -1098,7 +1318,7 @@ def updateTableColumn(self, table, column, new_name=None, data_type=None, not_nu if not_null is not None: col_actions.append("SET NOT NULL" if not_null else "DROP NOT NULL") if default is not None: - if default and default != '': + if default and default != "": col_actions.append("SET DEFAULT %s" % default) else: col_actions.append("DROP DEFAULT") @@ -1106,91 +1326,125 @@ def updateTableColumn(self, table, column, new_name=None, data_type=None, not_nu sql = "ALTER TABLE %s" % self.quoteId(table) alter_col_str = "ALTER %s" % self.quoteId(column) for a in col_actions: - sql += " %s %s," % (alter_col_str, a) + sql += f" {alter_col_str} {a}," self._execute(c, sql[:-1]) # Renames the column if new_name is not None and new_name != column: - sql = "ALTER TABLE %s RENAME %s TO %s" % ( - self.quoteId(table), self.quoteId(column), self.quoteId(new_name)) + sql = "ALTER TABLE {} RENAME {} TO {}".format( + self.quoteId(table), self.quoteId(column), self.quoteId(new_name) + ) self._execute(c, sql) # update geometry_columns if PostGIS is enabled if self.has_geometry_columns and not self.is_geometry_columns_view: schema, tablename = self.getSchemaTableName(table) - schema_where = " f_table_schema=%s AND " % self.quoteString(schema) if schema is not None else "" - sql = "UPDATE geometry_columns SET f_geometry_column=%s WHERE %s f_table_name=%s AND f_geometry_column=%s" % ( - self.quoteString(new_name), schema_where, self.quoteString(tablename), self.quoteString(column)) + schema_where = ( + " f_table_schema=%s AND " % self.quoteString(schema) + if schema is not None + else "" + ) + sql = "UPDATE geometry_columns SET f_geometry_column={} WHERE {} f_table_name={} AND f_geometry_column={}".format( + self.quoteString(new_name), + schema_where, + self.quoteString(tablename), + self.quoteString(column), + ) self._execute(c, sql) # comment the column if comment is not None: schema, tablename = self.getSchemaTableName(table) - column_name = new_name if new_name is not None and new_name != column else column - sql = "COMMENT ON COLUMN %s.%s.%s IS '%s'" % (schema, tablename, column_name, comment) + column_name = ( + new_name if new_name is not None and new_name != column else column + ) + sql = "COMMENT ON COLUMN {}.{}.{} IS '{}'".format( + schema, tablename, column_name, comment + ) self._execute(c, sql) self._commit() def renamesTableColumn(self, table, column, new_name): - """Renames column in a table """ + """Renames column in a table""" return self.updateTableColumn(table, column, new_name) def setTableColumnType(self, table, column, data_type): - """Changes column type """ + """Changes column type""" return self.updateTableColumn(table, column, None, data_type) def setTableColumnNull(self, table, column, is_null): - """Changes whether column can contain null values """ + """Changes whether column can contain null values""" return self.updateTableColumn(table, column, None, None, not is_null) def setTableColumnDefault(self, table, column, default): """Changes column's default value. - If default=None or an empty string drop default value """ + If default=None or an empty string drop default value""" return self.updateTableColumn(table, column, None, None, None, default) def isGeometryColumn(self, table, column): schema, tablename = self.getSchemaTableName(table) - schema_where = " f_table_schema=%s AND " % self.quoteString(schema) if schema is not None else "" + schema_where = ( + " f_table_schema=%s AND " % self.quoteString(schema) + if schema is not None + else "" + ) - sql = "SELECT count(*) > 0 FROM geometry_columns WHERE %s f_table_name=%s AND f_geometry_column=%s" % ( - schema_where, self.quoteString(tablename), self.quoteString(column)) + sql = "SELECT count(*) > 0 FROM geometry_columns WHERE {} f_table_name={} AND f_geometry_column={}".format( + schema_where, self.quoteString(tablename), self.quoteString(column) + ) c = self._execute(None, sql) - res = self._fetchone(c)[0] == 't' + res = self._fetchone(c)[0] == "t" self._close_cursor(c) return res - def addGeometryColumn(self, table, geom_column='geom', geom_type='POINT', srid=-1, dim=2): + def addGeometryColumn( + self, table, geom_column="geom", geom_type="POINT", srid=-1, dim=2 + ): schema, tablename = self.getSchemaTableName(table) schema_part = "%s, " % self.quoteString(schema) if schema else "" sql = "SELECT AddGeometryColumn(%s%s, %s, %d, %s, %d)" % ( - schema_part, self.quoteString(tablename), self.quoteString(geom_column), srid, self.quoteString(geom_type), dim) + schema_part, + self.quoteString(tablename), + self.quoteString(geom_column), + srid, + self.quoteString(geom_type), + dim, + ) self._execute_and_commit(sql) def deleteGeometryColumn(self, table, geom_column): return self.deleteTableColumn(table, geom_column) def addTableUniqueConstraint(self, table, column): - """Adds a unique constraint to a table """ - sql = "ALTER TABLE %s ADD UNIQUE (%s)" % (self.quoteId(table), self.quoteId(column)) + """Adds a unique constraint to a table""" + sql = "ALTER TABLE {} ADD UNIQUE ({})".format( + self.quoteId(table), self.quoteId(column) + ) self._execute_and_commit(sql) def deleteTableConstraint(self, table, constraint): - """Deletes constraint in a table """ - sql = "ALTER TABLE %s DROP CONSTRAINT %s" % (self.quoteId(table), self.quoteId(constraint)) + """Deletes constraint in a table""" + sql = "ALTER TABLE {} DROP CONSTRAINT {}".format( + self.quoteId(table), self.quoteId(constraint) + ) self._execute_and_commit(sql) def addTablePrimaryKey(self, table, column): - """Adds a primery key (with one column) to a table """ - sql = "ALTER TABLE %s ADD PRIMARY KEY (%s)" % (self.quoteId(table), self.quoteId(column)) + """Adds a primery key (with one column) to a table""" + sql = "ALTER TABLE {} ADD PRIMARY KEY ({})".format( + self.quoteId(table), self.quoteId(column) + ) self._execute_and_commit(sql) def createTableIndex(self, table, name, column): - """Creates index on one column using default options """ - sql = "CREATE INDEX %s ON %s (%s)" % (self.quoteId(name), self.quoteId(table), self.quoteId(column)) + """Creates index on one column using default options""" + sql = "CREATE INDEX {} ON {} ({})".format( + self.quoteId(name), self.quoteId(table), self.quoteId(column) + ) self._execute_and_commit(sql) def deleteTableIndex(self, table, name): @@ -1198,15 +1452,17 @@ def deleteTableIndex(self, table, name): sql = "DROP INDEX %s" % self.quoteId((schema, name)) self._execute_and_commit(sql) - def createSpatialIndex(self, table, geom_column='geom'): + def createSpatialIndex(self, table, geom_column="geom"): schema, tablename = self.getSchemaTableName(table) - idx_name = self.quoteId("sidx_%s_%s" % (tablename, geom_column)) - sql = "CREATE INDEX %s ON %s USING GIST(%s)" % (idx_name, self.quoteId(table), self.quoteId(geom_column)) + idx_name = self.quoteId(f"sidx_{tablename}_{geom_column}") + sql = "CREATE INDEX {} ON {} USING GIST({})".format( + idx_name, self.quoteId(table), self.quoteId(geom_column) + ) self._execute_and_commit(sql) - def deleteSpatialIndex(self, table, geom_column='geom'): + def deleteSpatialIndex(self, table, geom_column="geom"): schema, tablename = self.getSchemaTableName(table) - idx_name = self.quoteId("sidx_%s_%s" % (tablename, geom_column)) + idx_name = self.quoteId(f"sidx_{tablename}_{geom_column}") return self.deleteTableIndex(table, idx_name) def _execute(self, cursor, sql): @@ -1245,10 +1501,7 @@ def getSqlDictionary(self): UNION SELECT relname FROM pg_class WHERE relkind IN ('v', 'r', 'm', 'p') UNION SELECT attname FROM pg_attribute WHERE attnum > 0""" c = self._execute(None, sql) - items = [ - row[0] - for row in self._fetchall(c) - ] + items = [row[0] for row in self._fetchall(c)] self._close_cursor(c) sql_dict["identifier"] = items diff --git a/python/plugins/db_manager/db_plugins/postgis/connector_test.py b/python/plugins/db_manager/db_plugins/postgis/connector_test.py index b8be72f5a3f3..e943fe8929a5 100644 --- a/python/plugins/db_manager/db_plugins/postgis/connector_test.py +++ b/python/plugins/db_manager/db_plugins/postgis/connector_test.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Sandro Santilli' -__date__ = 'May 2017' -__copyright__ = '(C) 2017, Sandro Santilli' +__author__ = "Sandro Santilli" +__date__ = "May 2017" +__copyright__ = "(C) 2017, Sandro Santilli" import os import unittest @@ -51,8 +51,8 @@ def _getDatabase(self, connector): # and https://github.com/qgis/QGIS/issues/19005 def test_dbnameLessURI(self): obj = QObject() # needs to be kept alive - obj.connectionName = lambda: 'fake' - obj.providerName = lambda: 'postgres' + obj.connectionName = lambda: "fake" + obj.providerName = lambda: "postgres" c = PostGisDBConnector(QgsDataSourceUri(), obj) self.assertIsInstance(c, PostGisDBConnector) @@ -60,18 +60,18 @@ def test_dbnameLessURI(self): # No username was passed, so we expect it to be taken # from PGUSER or USER environment variables - expected_user = os.environ.get('PGUSER') or os.environ.get('USER') + expected_user = os.environ.get("PGUSER") or os.environ.get("USER") actual_user = self._getUser(c) self.assertEqual(actual_user, expected_user) # No database was passed, so we expect it to be taken # from PGDATABASE or expected user - expected_db = os.environ.get('PGDATABASE') or expected_user + expected_db = os.environ.get("PGDATABASE") or expected_user actual_db = self._getDatabase(c) self.assertEqual(actual_db, expected_db) # TODO: add service-only test (requires a ~/.pg_service.conf file) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/python/plugins/db_manager/db_plugins/postgis/data_model.py b/python/plugins/db_manager/db_plugins/postgis/data_model.py index be3f7b00667d..269e9713b5f6 100644 --- a/python/plugins/db_manager/db_plugins/postgis/data_model.py +++ b/python/plugins/db_manager/db_plugins/postgis/data_model.py @@ -20,10 +20,12 @@ from qgis.core import QgsMessageLog from ..plugin import BaseError -from ..data_model import (TableDataModel, - SqlResultModel, - SqlResultModelAsync, - SqlResultModelTask) +from ..data_model import ( + TableDataModel, + SqlResultModel, + SqlResultModelAsync, + SqlResultModelTask, +) class PGTableDataModel(TableDataModel): @@ -45,17 +47,21 @@ def _createCursor(self): table_txt = self.db.quoteId((self.table.schemaName(), self.table.name)) self.cursor = self.db._get_cursor() - sql = "SELECT %s FROM %s" % (fields_txt, table_txt) + sql = f"SELECT {fields_txt} FROM {table_txt}" self.db._execute(self.cursor, sql) def _sanitizeTableField(self, field): # get fields, ignore geometry columns if field.dataType.lower() == "geometry": - return "CASE WHEN %(fld)s IS NULL THEN NULL ELSE GeometryType(%(fld)s) END AS %(fld)s" % { - 'fld': self.db.quoteId(field.name)} + return "CASE WHEN {fld} IS NULL THEN NULL ELSE GeometryType({fld}) END AS {fld}".format( + fld=self.db.quoteId(field.name) + ) elif field.dataType.lower() == "raster": - return "CASE WHEN %(fld)s IS NULL THEN NULL ELSE 'RASTER' END AS %(fld)s" % { - 'fld': self.db.quoteId(field.name)} + return ( + "CASE WHEN {fld} IS NULL THEN NULL ELSE 'RASTER' END AS {fld}".format( + fld=self.db.quoteId(field.name) + ) + ) return "%s::text" % self.db.quoteId(field.name) def _deleteCursor(self): @@ -72,7 +78,7 @@ def fetchMoreData(self, row_start): self._createCursor() try: - self.cursor.scroll(row_start, mode='absolute') + self.cursor.scroll(row_start, mode="absolute") except self.db.error_types(): self._deleteCursor() return self.fetchMoreData(row_start) diff --git a/python/plugins/db_manager/db_plugins/postgis/info_model.py b/python/plugins/db_manager/db_plugins/postgis/info_model.py index fa9dc3abb2e2..c5dda0b3e2fc 100644 --- a/python/plugins/db_manager/db_plugins/postgis/info_model.py +++ b/python/plugins/db_manager/db_plugins/postgis/info_model.py @@ -21,16 +21,31 @@ from qgis.PyQt.QtWidgets import QApplication from ..info_model import TableInfo, VectorTableInfo, RasterTableInfo, DatabaseInfo -from ..html_elems import HtmlSection, HtmlParagraph, HtmlTable, HtmlTableHeader, HtmlTableCol +from ..html_elems import ( + HtmlSection, + HtmlParagraph, + HtmlTable, + HtmlTableHeader, + HtmlTableCol, +) class PGDatabaseInfo(DatabaseInfo): def connectionDetails(self): tbl = [ - (QApplication.translate("DBManagerPlugin", "Host:"), self.db.connector.host), - (QApplication.translate("DBManagerPlugin", "User:"), self.db.connector.user), - (QApplication.translate("DBManagerPlugin", "Database:"), self.db.connector.dbname) + ( + QApplication.translate("DBManagerPlugin", "Host:"), + self.db.connector.host, + ), + ( + QApplication.translate("DBManagerPlugin", "User:"), + self.db.connector.user, + ), + ( + QApplication.translate("DBManagerPlugin", "Database:"), + self.db.connector.dbname, + ), ] return HtmlTable(tbl) @@ -53,40 +68,81 @@ def generalInfo(self): self.table.blockSignals(False) tbl = [ - (QApplication.translate("DBManagerPlugin", "Relation type:"), - QApplication.translate("DBManagerPlugin", "View") if self.table._relationType == 'v' else - QApplication.translate("DBManagerPlugin", "Materialized view") if self.table._relationType == 'm' else - QApplication.translate("DBManagerPlugin", "Table")), - (QApplication.translate("DBManagerPlugin", "Owner:"), self.table.owner) + ( + QApplication.translate("DBManagerPlugin", "Relation type:"), + ( + QApplication.translate("DBManagerPlugin", "View") + if self.table._relationType == "v" + else ( + QApplication.translate("DBManagerPlugin", "Materialized view") + if self.table._relationType == "m" + else QApplication.translate("DBManagerPlugin", "Table") + ) + ), + ), + (QApplication.translate("DBManagerPlugin", "Owner:"), self.table.owner), ] if self.table.comment: - tbl.append((QApplication.translate("DBManagerPlugin", "Comment:"), self.table.comment)) - - tbl.extend([ - (QApplication.translate("DBManagerPlugin", "Pages:"), self.table.pages), - (QApplication.translate("DBManagerPlugin", "Rows (estimation):"), self.table.estimatedRowCount) - ]) + tbl.append( + ( + QApplication.translate("DBManagerPlugin", "Comment:"), + self.table.comment, + ) + ) + + tbl.extend( + [ + (QApplication.translate("DBManagerPlugin", "Pages:"), self.table.pages), + ( + QApplication.translate("DBManagerPlugin", "Rows (estimation):"), + self.table.estimatedRowCount, + ), + ] + ) # privileges # has the user access to this schema? - schema_priv = self.table.database().connector.getSchemaPrivileges( - self.table.schemaName()) if self.table.schema() else None + schema_priv = ( + self.table.database().connector.getSchemaPrivileges(self.table.schemaName()) + if self.table.schema() + else None + ) if schema_priv is None: pass elif not schema_priv[1]: # no usage privileges on the schema - tbl.append((QApplication.translate("DBManagerPlugin", "Privileges:"), - QApplication.translate("DBManagerPlugin", - " This user doesn't have usage privileges for this schema!"))) + tbl.append( + ( + QApplication.translate("DBManagerPlugin", "Privileges:"), + QApplication.translate( + "DBManagerPlugin", + " This user doesn't have usage privileges for this schema!", + ), + ) + ) else: - table_priv = self.table.database().connector.getTablePrivileges((self.table.schemaName(), self.table.name)) + table_priv = self.table.database().connector.getTablePrivileges( + (self.table.schemaName(), self.table.name) + ) privileges = [] if table_priv[0]: privileges.append("select") if self.table.rowCount is not None and self.table.rowCount >= 0: - tbl.append((QApplication.translate("DBManagerPlugin", "Rows (counted):"), - self.table.rowCount if self.table.rowCount is not None else QApplication.translate( - "DBManagerPlugin", 'Unknown (find out)'))) + tbl.append( + ( + QApplication.translate( + "DBManagerPlugin", "Rows (counted):" + ), + ( + self.table.rowCount + if self.table.rowCount is not None + else QApplication.translate( + "DBManagerPlugin", + 'Unknown (find out)', + ) + ), + ) + ) if table_priv[1]: privileges.append("insert") @@ -94,31 +150,62 @@ def generalInfo(self): privileges.append("update") if table_priv[3]: privileges.append("delete") - priv_string = ", ".join(privileges) if len(privileges) > 0 else QApplication.translate("DBManagerPlugin", - ' This user has no privileges!') - tbl.append((QApplication.translate("DBManagerPlugin", "Privileges:"), priv_string)) + priv_string = ( + ", ".join(privileges) + if len(privileges) > 0 + else QApplication.translate( + "DBManagerPlugin", " This user has no privileges!" + ) + ) + tbl.append( + (QApplication.translate("DBManagerPlugin", "Privileges:"), priv_string) + ) ret.append(HtmlTable(tbl)) if schema_priv is not None and schema_priv[1]: - if table_priv[0] and not table_priv[1] and not table_priv[2] and not table_priv[3]: - ret.append(HtmlParagraph( - QApplication.translate("DBManagerPlugin", " This user has read-only privileges."))) + if ( + table_priv[0] + and not table_priv[1] + and not table_priv[2] + and not table_priv[3] + ): + ret.append( + HtmlParagraph( + QApplication.translate( + "DBManagerPlugin", + " This user has read-only privileges.", + ) + ) + ) if not self.table.isView: if self.table.rowCount is not None: - if abs(self.table.estimatedRowCount - self.table.rowCount) > 1 and \ - (self.table.estimatedRowCount > 2 * self.table.rowCount - or self.table.rowCount > 2 * self.table.estimatedRowCount): - ret.append(HtmlParagraph(QApplication.translate("DBManagerPlugin", - " There's a significant difference between estimated and real row count. " - 'Consider running VACUUM ANALYZE.'))) + if abs(self.table.estimatedRowCount - self.table.rowCount) > 1 and ( + self.table.estimatedRowCount > 2 * self.table.rowCount + or self.table.rowCount > 2 * self.table.estimatedRowCount + ): + ret.append( + HtmlParagraph( + QApplication.translate( + "DBManagerPlugin", + " There's a significant difference between estimated and real row count. " + 'Consider running VACUUM ANALYZE.', + ) + ) + ) # primary key defined? if not self.table.isView: if len([fld for fld in self.table.fields() if fld.primaryKey]) <= 0: - ret.append(HtmlParagraph( - QApplication.translate("DBManagerPlugin", " No primary key defined for this table!"))) + ret.append( + HtmlParagraph( + QApplication.translate( + "DBManagerPlugin", + " No primary key defined for this table!", + ) + ) + ) return ret @@ -133,23 +220,41 @@ def getSpatialInfo(self): (QApplication.translate("DBManagerPlugin", "Library:"), info[0]), (QApplication.translate("DBManagerPlugin", "Scripts:"), info[3]), ("GEOS:", info[1]), - ("Proj:", info[2]) + ("Proj:", info[2]), ] ret.append(HtmlTable(tbl)) if info[1] is not None and info[1] != info[2]: - ret.append(HtmlParagraph(QApplication.translate("DBManagerPlugin", - " Version of installed scripts doesn't match version of released scripts!\n" - "This is probably a result of incorrect PostGIS upgrade."))) + ret.append( + HtmlParagraph( + QApplication.translate( + "DBManagerPlugin", + " Version of installed scripts doesn't match version of released scripts!\n" + "This is probably a result of incorrect PostGIS upgrade.", + ) + ) + ) if not self.db.connector.has_geometry_columns: - ret.append(HtmlParagraph( - QApplication.translate("DBManagerPlugin", " geometry_columns table doesn't exist!\n" - "This table is essential for many GIS applications for enumeration of tables."))) + ret.append( + HtmlParagraph( + QApplication.translate( + "DBManagerPlugin", + " geometry_columns table doesn't exist!\n" + "This table is essential for many GIS applications for enumeration of tables.", + ) + ) + ) elif not self.db.connector.has_geometry_columns_access: - ret.append(HtmlParagraph(QApplication.translate("DBManagerPlugin", - " This user doesn't have privileges to read contents of geometry_columns table!\n" - "This table is essential for many GIS applications for enumeration of tables."))) + ret.append( + HtmlParagraph( + QApplication.translate( + "DBManagerPlugin", + " This user doesn't have privileges to read contents of geometry_columns table!\n" + "This table is essential for many GIS applications for enumeration of tables.", + ) + ) + ) return ret @@ -158,21 +263,40 @@ def fieldsDetails(self): # define the table header header = ( - "#", QApplication.translate("DBManagerPlugin", "Name"), QApplication.translate("DBManagerPlugin", "Type"), - QApplication.translate("DBManagerPlugin", "Length"), QApplication.translate("DBManagerPlugin", "Null"), - QApplication.translate("DBManagerPlugin", "Default"), QApplication.translate("DBManagerPlugin", "Comment")) + "#", + QApplication.translate("DBManagerPlugin", "Name"), + QApplication.translate("DBManagerPlugin", "Type"), + QApplication.translate("DBManagerPlugin", "Length"), + QApplication.translate("DBManagerPlugin", "Null"), + QApplication.translate("DBManagerPlugin", "Default"), + QApplication.translate("DBManagerPlugin", "Comment"), + ) tbl.append(HtmlTableHeader(header)) # add table contents for fld in self.table.fields(): - char_max_len = fld.charMaxLen if fld.charMaxLen is not None and fld.charMaxLen != -1 else "" + char_max_len = ( + fld.charMaxLen + if fld.charMaxLen is not None and fld.charMaxLen != -1 + else "" + ) is_null_txt = "N" if fld.notNull else "Y" # make primary key field underlined attrs = {"class": "underline"} if fld.primaryKey else None name = HtmlTableCol(fld.name, attrs) - tbl.append((fld.num, name, fld.type2String(), char_max_len, is_null_txt, fld.default2String(), fld.getComment())) + tbl.append( + ( + fld.num, + name, + fld.type2String(), + char_max_len, + is_null_txt, + fld.default2String(), + fld.getComment(), + ) + ) return HtmlTable(tbl, {"class": "header"}) @@ -185,26 +309,42 @@ def triggersDetails(self): tbl = [] # define the table header header = ( - QApplication.translate("DBManagerPlugin", "Name"), QApplication.translate("DBManagerPlugin", "Function"), - QApplication.translate("DBManagerPlugin", "Type"), QApplication.translate("DBManagerPlugin", "Enabled")) + QApplication.translate("DBManagerPlugin", "Name"), + QApplication.translate("DBManagerPlugin", "Function"), + QApplication.translate("DBManagerPlugin", "Type"), + QApplication.translate("DBManagerPlugin", "Enabled"), + ) tbl.append(HtmlTableHeader(header)) # add table contents for trig in self.table.triggers(): - name = '%(name)s (%(action)s)' % {"name": trig.name, - "action": "delete"} - - (enabled, action) = (QApplication.translate("DBManagerPlugin", "Yes"), "disable") if trig.enabled else ( - QApplication.translate("DBManagerPlugin", "No"), "enable") - txt_enabled = '%(enabled)s (%(action)s)' % { - "name": trig.name, "action": action, "enabled": enabled} + name = ( + '{name} ({action})'.format( + name=trig.name, action="delete" + ) + ) + + (enabled, action) = ( + (QApplication.translate("DBManagerPlugin", "Yes"), "disable") + if trig.enabled + else (QApplication.translate("DBManagerPlugin", "No"), "enable") + ) + txt_enabled = '{enabled} ({action})'.format( + name=trig.name, action=action, enabled=enabled + ) tbl.append((name, trig.function, trig.type2String(), txt_enabled)) ret.append(HtmlTable(tbl, {"class": "header"})) - ret.append(HtmlParagraph(QApplication.translate("DBManagerPlugin", - 'Enable all triggers / Disable all triggers'))) + ret.append( + HtmlParagraph( + QApplication.translate( + "DBManagerPlugin", + 'Enable all triggers / Disable all triggers', + ) + ) + ) return ret def rulesDetails(self): @@ -214,13 +354,16 @@ def rulesDetails(self): tbl = [] # define the table header header = ( - QApplication.translate("DBManagerPlugin", "Name"), QApplication.translate("DBManagerPlugin", "Definition")) + QApplication.translate("DBManagerPlugin", "Name"), + QApplication.translate("DBManagerPlugin", "Definition"), + ) tbl.append(HtmlTableHeader(header)) # add table contents for rule in self.table.rules(): - name = '%(name)s (%(action)s)' % {"name": rule.name, - "action": "delete"} + name = '{name} ({action})'.format( + name=rule.name, action="delete" + ) tbl.append((name, rule.definition)) return HtmlTable(tbl, {"class": "header"}) @@ -233,7 +376,11 @@ def getTableInfo(self): if rules_details is None: pass else: - ret.append(HtmlSection(QApplication.translate("DBManagerPlugin", 'Rules'), rules_details)) + ret.append( + HtmlSection( + QApplication.translate("DBManagerPlugin", "Rules"), rules_details + ) + ) return ret diff --git a/python/plugins/db_manager/db_plugins/postgis/plugin.py b/python/plugins/db_manager/db_plugins/postgis/plugin.py index 7e276251bacd..f294c7d579bd 100644 --- a/python/plugins/db_manager/db_plugins/postgis/plugin.py +++ b/python/plugins/db_manager/db_plugins/postgis/plugin.py @@ -21,18 +21,27 @@ # this will disable the dbplugin if the connector raise an ImportError from .connector import PostGisDBConnector -from qgis.PyQt.QtCore import ( - Qt, - QRegularExpression, - QCoreApplication -) +from qgis.PyQt.QtCore import Qt, QRegularExpression, QCoreApplication from qgis.PyQt.QtGui import QIcon from qgis.PyQt.QtWidgets import QAction, QApplication, QMessageBox from qgis.core import Qgis, QgsApplication, QgsSettings from qgis.gui import QgsMessageBar -from ..plugin import ConnectionError, InvalidDataException, DBPlugin, Database, Schema, Table, VectorTable, RasterTable, \ - TableField, TableConstraint, TableIndex, TableTrigger, TableRule +from ..plugin import ( + ConnectionError, + InvalidDataException, + DBPlugin, + Database, + Schema, + Table, + VectorTable, + RasterTable, + TableField, + TableConstraint, + TableIndex, + TableTrigger, + TableRule, +) import re @@ -49,19 +58,19 @@ def icon(self): @classmethod def typeName(self): - return 'postgis' + return "postgis" @classmethod def typeNameString(self): - return QCoreApplication.translate('db_manager', 'PostGIS') + return QCoreApplication.translate("db_manager", "PostGIS") @classmethod def providerName(self): - return 'postgres' + return "postgres" @classmethod def connectionSettingsKey(self): - return '/PostgreSQL/connections' + return "/PostgreSQL/connections" def databasesFactory(self, connection, uri): return PGDatabase(connection, uri) @@ -69,17 +78,31 @@ def databasesFactory(self, connection, uri): def connect(self, parent=None): conn_name = self.connectionName() settings = QgsSettings() - settings.beginGroup("/%s/%s" % (self.connectionSettingsKey(), conn_name)) + settings.beginGroup(f"/{self.connectionSettingsKey()}/{conn_name}") if not settings.contains("database"): # non-existent entry? - raise InvalidDataException(self.tr('There is no defined database connection "{0}".').format(conn_name)) + raise InvalidDataException( + self.tr('There is no defined database connection "{0}".').format( + conn_name + ) + ) from qgis.core import QgsDataSourceUri uri = QgsDataSourceUri() - settingsList = ["service", "host", "port", "database", "username", "password", "authcfg"] - service, host, port, database, username, password, authcfg = (settings.value(x, "", type=str) for x in settingsList) + settingsList = [ + "service", + "host", + "port", + "database", + "username", + "password", + "authcfg", + ] + service, host, port, database, username, password, authcfg = ( + settings.value(x, "", type=str) for x in settingsList + ) useEstimatedMetadata = settings.value("estimatedMetadata", False, type=bool) try: @@ -89,13 +112,15 @@ def connect(self, parent=None): settings.endGroup() - if hasattr(authcfg, 'isNull') and authcfg.isNull(): - authcfg = '' + if hasattr(authcfg, "isNull") and authcfg.isNull(): + authcfg = "" if service: uri.setConnection(service, database, username, password, sslmode, authcfg) else: - uri.setConnection(host, port, database, username, password, sslmode, authcfg) + uri.setConnection( + host, port, database, username, password, sslmode, authcfg + ) uri.setUseEstimatedMetadata(useEstimatedMetadata) @@ -118,6 +143,7 @@ def dataTablesFactory(self, row, db, schema=None): def info(self): from .info_model import PGDatabaseInfo + return PGDatabaseInfo(self) def vectorTablesFactory(self, row, db, schema=None): @@ -148,17 +174,24 @@ def registerDatabaseActions(self, mainWindow): mainWindow.registerAction(separator, self.tr("&Table")) action = QAction(self.tr("Run &Vacuum Analyze"), self) - mainWindow.registerAction(action, self.tr("&Table"), self.runVacuumAnalyzeActionSlot) + mainWindow.registerAction( + action, self.tr("&Table"), self.runVacuumAnalyzeActionSlot + ) action = QAction(self.tr("Run &Refresh Materialized View"), self) - mainWindow.registerAction(action, self.tr("&Table"), self.runRefreshMaterializedViewSlot) + mainWindow.registerAction( + action, self.tr("&Table"), self.runRefreshMaterializedViewSlot + ) def runVacuumAnalyzeActionSlot(self, item, action, parent): QApplication.restoreOverrideCursor() try: if not isinstance(item, Table) or item.isView: - parent.infoBar.pushMessage(self.tr("Select a table for vacuum analyze."), Qgis.MessageLevel.Info, - parent.iface.messageTimeout()) + parent.infoBar.pushMessage( + self.tr("Select a table for vacuum analyze."), + Qgis.MessageLevel.Info, + parent.iface.messageTimeout(), + ) return finally: QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) @@ -168,9 +201,12 @@ def runVacuumAnalyzeActionSlot(self, item, action, parent): def runRefreshMaterializedViewSlot(self, item, action, parent): QApplication.restoreOverrideCursor() try: - if not isinstance(item, PGTable) or item._relationType != 'm': - parent.infoBar.pushMessage(self.tr("Select a materialized view for refresh."), Qgis.MessageLevel.Info, - parent.iface.messageTimeout()) + if not isinstance(item, PGTable) or item._relationType != "m": + parent.infoBar.pushMessage( + self.tr("Select a materialized view for refresh."), + Qgis.MessageLevel.Info, + parent.iface.messageTimeout(), + ) return finally: QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) @@ -198,8 +234,16 @@ class PGTable(Table): def __init__(self, row, db, schema=None): Table.__init__(self, db, schema) - self.name, schema_name, self._relationType, self.owner, self.estimatedRowCount, self.pages, self.comment = row - self.isView = self._relationType in {'v', 'm'} + ( + self.name, + schema_name, + self._relationType, + self.owner, + self.estimatedRowCount, + self.pages, + self.comment, + ) = row + self.isView = self._relationType in {"v", "m"} self.estimatedRowCount = int(self.estimatedRowCount) def runVacuumAnalyze(self): @@ -210,7 +254,9 @@ def runVacuumAnalyze(self): def runRefreshMaterializedView(self): self.aboutToChange.emit() - self.database().connector.runRefreshMaterializedView((self.schemaName(), self.name)) + self.database().connector.runRefreshMaterializedView( + (self.schemaName(), self.name) + ) # TODO: change only this item, not re-create all the tables in the schema/database self.schema().refresh() if self.schema() else self.database().refresh() @@ -223,7 +269,7 @@ def runAction(self, action): return True elif action.startswith("rule/"): - parts = action.split('/') + parts = action.split("/") rule_name = parts[1] rule_action = parts[2] @@ -232,15 +278,24 @@ def runAction(self, action): QApplication.restoreOverrideCursor() try: - if QMessageBox.question(None, self.tr("Table rule"), msg, - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) == QMessageBox.StandardButton.No: + if ( + QMessageBox.question( + None, + self.tr("Table rule"), + msg, + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + ) + == QMessageBox.StandardButton.No + ): return False finally: QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) if rule_action == "delete": self.aboutToChange.emit() - self.database().connector.deleteTableRule(rule_name, (self.schemaName(), self.name)) + self.database().connector.deleteTableRule( + rule_name, (self.schemaName(), self.name) + ) self.refreshRules() return True @@ -282,7 +337,9 @@ def tableDataModel(self, parent): def delete(self): self.aboutToChange.emit() if self.isView: - ret = self.database().connector.deleteView((self.schemaName(), self.name), self._relationType == 'm') + ret = self.database().connector.deleteView( + (self.schemaName(), self.name), self._relationType == "m" + ) else: ret = self.database().connector.deleteTable((self.schemaName(), self.name)) if not ret: @@ -308,7 +365,7 @@ def runAction(self, action): return VectorTable.runAction(self, action) def geometryType(self): - """ Returns the proper WKT type. + """Returns the proper WKT type. PostGIS records type like this: | WKT Type | geomType | geomDim | |--------------|-------------|---------| @@ -331,8 +388,15 @@ class PGRasterTable(PGTable, RasterTable): def __init__(self, row, db, schema=None): PGTable.__init__(self, row[:-6], db, schema) RasterTable.__init__(self, db, schema) - self.geomColumn, self.pixelType, self.pixelSizeX, self.pixelSizeY, self.isExternal, self.srid = row[-6:] - self.geomType = 'RASTER' + ( + self.geomColumn, + self.pixelType, + self.pixelSizeX, + self.pixelSizeY, + self.isExternal, + self.srid, + ) = row[-6:] + self.geomType = "RASTER" def info(self): from .info_model import PGRasterTableInfo @@ -344,41 +408,56 @@ def uri(self, uri=None): if not uri: uri = self.database().uri() - service = ('service=\'%s\'' % uri.service()) if uri.service() else '' - dbname = ('dbname=\'%s\'' % uri.database()) if uri.database() else '' - host = ('host=%s' % uri.host()) if uri.host() else '' - user = ('user=%s' % uri.username()) if uri.username() else '' - passw = ('password=%s' % uri.password()) if uri.password() else '' - port = ('port=%s' % uri.port()) if uri.port() else '' + service = ("service='%s'" % uri.service()) if uri.service() else "" + dbname = ("dbname='%s'" % uri.database()) if uri.database() else "" + host = ("host=%s" % uri.host()) if uri.host() else "" + user = ("user=%s" % uri.username()) if uri.username() else "" + passw = ("password=%s" % uri.password()) if uri.password() else "" + port = ("port=%s" % uri.port()) if uri.port() else "" - schema = self.schemaName() if self.schemaName() else 'public' - table = '"%s"."%s"' % (schema, self.name) + schema = self.schemaName() if self.schemaName() else "public" + table = f'"{schema}"."{self.name}"' if not dbname: # postgresraster provider *requires* a dbname connector = self.database().connector r = connector._execute(None, "SELECT current_database()") - dbname = ('dbname=\'%s\'' % connector._fetchone(r)[0]) + dbname = "dbname='%s'" % connector._fetchone(r)[0] connector._close_cursor(r) # Find first raster field - col = '' + col = "" for fld in self.fields(): if fld.dataType == "raster": - col = 'column=\'%s\'' % fld.name + col = "column='%s'" % fld.name break - uri = '%s %s %s %s %s %s %s table=%s' % \ - (service, dbname, host, user, passw, port, col, table) + uri = "{} {} {} {} {} {} {} table={}".format( + service, + dbname, + host, + user, + passw, + port, + col, + table, + ) return uri def mimeUri(self): - uri = "raster:postgresraster:{}:{}".format(self.name, re.sub(":", r"\:", self.uri())) + uri = "raster:postgresraster:{}:{}".format( + self.name, re.sub(":", r"\:", self.uri()) + ) return uri def toMapLayer(self, geometryType=None, crs=None): - from qgis.core import QgsRasterLayer, QgsContrastEnhancement, QgsDataSourceUri, QgsCredentials + from qgis.core import ( + QgsRasterLayer, + QgsContrastEnhancement, + QgsDataSourceUri, + QgsCredentials, + ) rl = QgsRasterLayer(self.uri(), self.name, "postgresraster") if not rl.isValid(): @@ -389,7 +468,9 @@ def toMapLayer(self, geometryType=None, crs=None): password = uri.password() for i in range(3): - (ok, username, password) = QgsCredentials.instance().get(conninfo, username, password, err) + (ok, username, password) = QgsCredentials.instance().get( + conninfo, username, password, err + ) if ok: uri.setUsername(username) uri.setPassword(password) @@ -398,7 +479,9 @@ def toMapLayer(self, geometryType=None, crs=None): break if rl.isValid(): - rl.setContrastEnhancement(QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum) + rl.setContrastEnhancement( + QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum + ) return rl @@ -406,7 +489,17 @@ class PGTableField(TableField): def __init__(self, row, table): TableField.__init__(self, table) - self.num, self.name, self.dataType, self.charMaxLen, self.modifier, self.notNull, self.hasDefault, self.default, typeStr = row + ( + self.num, + self.name, + self.dataType, + self.charMaxLen, + self.modifier, + self.notNull, + self.hasDefault, + self.default, + typeStr, + ) = row self.primaryKey = False # get modifier (e.g. "precision,scale") from formatted type string @@ -428,9 +521,13 @@ def getComment(self): """Returns the comment for a field""" tab = self.table() # SQL Query checking if a comment exists for the field - sql_cpt = "Select count(*) from pg_description pd, pg_class pc, pg_attribute pa where relname = '%s' and attname = '%s' and pa.attrelid = pc.oid and pd.objoid = pc.oid and pd.objsubid = pa.attnum" % (tab.name, self.name) + sql_cpt = "Select count(*) from pg_description pd, pg_class pc, pg_attribute pa where relname = '{}' and attname = '{}' and pa.attrelid = pc.oid and pd.objoid = pc.oid and pd.objsubid = pa.attnum".format( + tab.name, self.name + ) # SQL Query that return the comment of the field - sql = "Select pd.description from pg_description pd, pg_class pc, pg_attribute pa where relname = '%s' and attname = '%s' and pa.attrelid = pc.oid and pd.objoid = pc.oid and pd.objsubid = pa.attnum" % (tab.name, self.name) + sql = "Select pd.description from pg_description pd, pg_class pc, pg_attribute pa where relname = '{}' and attname = '{}' and pa.attrelid = pc.oid and pd.objoid = pc.oid and pd.objsubid = pa.attnum".format( + tab.name, self.name + ) c = tab.database().connector._execute(None, sql_cpt) # Execute Check query res = tab.database().connector._fetchone(c)[0] # Store result if res == 1: @@ -440,15 +537,17 @@ def getComment(self): tab.database().connector._close_cursor(c) # Close cursor return res # Return comment else: - return '' + return "" class PGTableConstraint(TableConstraint): def __init__(self, row, table): TableConstraint.__init__(self, table) - self.name, constr_type_str, self.isDefferable, self.isDeffered, columns = row[:5] - self.columns = list(map(int, columns.split(' '))) + self.name, constr_type_str, self.isDefferable, self.isDeffered, columns = row[ + :5 + ] + self.columns = list(map(int, columns.split(" "))) if constr_type_str in TableConstraint.types: self.type = TableConstraint.types[constr_type_str] @@ -470,7 +569,7 @@ class PGTableIndex(TableIndex): def __init__(self, row, table): TableIndex.__init__(self, table) self.name, columns, self.isUnique = row - self.columns = list(map(int, columns.split(' '))) + self.columns = list(map(int, columns.split(" "))) class PGTableTrigger(TableTrigger): diff --git a/python/plugins/db_manager/db_plugins/postgis/plugin_test.py b/python/plugins/db_manager/db_plugins/postgis/plugin_test.py index 9f57ff047080..f202b1354af2 100644 --- a/python/plugins/db_manager/db_plugins/postgis/plugin_test.py +++ b/python/plugins/db_manager/db_plugins/postgis/plugin_test.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Sandro Santilli' -__date__ = 'May 2017' -__copyright__ = '(C) 2017, Sandro Santilli' +__author__ = "Sandro Santilli" +__date__ = "May 2017" +__copyright__ = "(C) 2017, Sandro Santilli" import os import re @@ -40,23 +40,23 @@ class TestDBManagerPostgisPlugin(QgisTestCase): @classmethod def setUpClass(self): - self.old_pgdatabase_env = os.environ.get('PGDATABASE') + self.old_pgdatabase_env = os.environ.get("PGDATABASE") # QGIS_PGTEST_DB contains the full connection string and not only the DB name! - QGIS_PGTEST_DB = os.environ.get('QGIS_PGTEST_DB') + QGIS_PGTEST_DB = os.environ.get("QGIS_PGTEST_DB") if QGIS_PGTEST_DB is not None: test_uri = QgsDataSourceUri(QGIS_PGTEST_DB) self.testdb = test_uri.database() else: - self.testdb = 'qgis_test' - os.environ['PGDATABASE'] = self.testdb + self.testdb = "qgis_test" + os.environ["PGDATABASE"] = self.testdb # Create temporary service file - self.old_pgservicefile_env = os.environ.get('PGSERVICEFILE') - self.tmpservicefile = '/tmp/qgis-test-{}-pg_service.conf'.format(os.getpid()) - os.environ['PGSERVICEFILE'] = self.tmpservicefile + self.old_pgservicefile_env = os.environ.get("PGSERVICEFILE") + self.tmpservicefile = f"/tmp/qgis-test-{os.getpid()}-pg_service.conf" + os.environ["PGSERVICEFILE"] = self.tmpservicefile f = open(self.tmpservicefile, "w") - f.write("[dbmanager]\ndbname={}\n".format(self.testdb)) + f.write(f"[dbmanager]\ndbname={self.testdb}\n") # TODO: add more things if PGSERVICEFILE was already set ? f.close() @@ -64,9 +64,9 @@ def setUpClass(self): def tearDownClass(self): # Restore previous env variables if needed if self.old_pgdatabase_env: - os.environ['PGDATABASE'] = self.old_pgdatabase_env + os.environ["PGDATABASE"] = self.old_pgdatabase_env if self.old_pgservicefile_env: - os.environ['PGSERVICEFILE'] = self.old_pgservicefile_env + os.environ["PGSERVICEFILE"] = self.old_pgservicefile_env # Remove temporary service file os.unlink(self.tmpservicefile) @@ -81,7 +81,7 @@ def check_rasterTableURI(expected_dbname): if tab.type == Table.RasterType: raster_tables_count += 1 uri = tab.uri() - m = re.search(' dbname=\'([^ ]*)\' ', uri) + m = re.search(" dbname='([^ ]*)' ", uri) self.assertTrue(m) actual_dbname = m.group(1) self.assertEqual(actual_dbname, expected_dbname) @@ -94,48 +94,48 @@ def check_rasterTableURI(expected_dbname): self.assertGreaterEqual(raster_tables_count, 1) obj = QObject() # needs to be kept alive - obj.connectionName = lambda: 'fake' - obj.providerName = lambda: 'postgres' + obj.connectionName = lambda: "fake" + obj.providerName = lambda: "postgres" # Test for empty URI # See https://github.com/qgis/QGIS/issues/24525 # and https://github.com/qgis/QGIS/issues/19005 expected_dbname = self.testdb - os.environ['PGDATABASE'] = expected_dbname + os.environ["PGDATABASE"] = expected_dbname database = PGDatabase(obj, QgsDataSourceUri()) self.assertIsInstance(database, PGDatabase) uri = database.uri() - self.assertEqual(uri.host(), '') - self.assertEqual(uri.username(), '') + self.assertEqual(uri.host(), "") + self.assertEqual(uri.username(), "") self.assertEqual(uri.database(), expected_dbname) - self.assertEqual(uri.service(), '') + self.assertEqual(uri.service(), "") check_rasterTableURI(expected_dbname) # Test for service-only URI # See https://github.com/qgis/QGIS/issues/24526 - os.environ['PGDATABASE'] = 'fake' - database = PGDatabase(obj, QgsDataSourceUri('service=dbmanager')) + os.environ["PGDATABASE"] = "fake" + database = PGDatabase(obj, QgsDataSourceUri("service=dbmanager")) self.assertIsInstance(database, PGDatabase) uri = database.uri() - self.assertEqual(uri.host(), '') - self.assertEqual(uri.username(), '') - self.assertEqual(uri.database(), '') - self.assertEqual(uri.service(), 'dbmanager') + self.assertEqual(uri.host(), "") + self.assertEqual(uri.username(), "") + self.assertEqual(uri.database(), "") + self.assertEqual(uri.service(), "dbmanager") check_rasterTableURI(expected_dbname) # See https://github.com/qgis/QGIS/issues/24732 def test_unicodeInQuery(self): - os.environ['PGDATABASE'] = self.testdb + os.environ["PGDATABASE"] = self.testdb obj = QObject() # needs to be kept alive - obj.connectionName = lambda: 'fake' - obj.providerName = lambda: 'postgres' + obj.connectionName = lambda: "fake" + obj.providerName = lambda: "postgres" database = PGDatabase(obj, QgsDataSourceUri()) self.assertIsInstance(database, PGDatabase) # SQL as string literal @@ -150,5 +150,5 @@ def test_unicodeInQuery(self): self.assertEqual(dat, "é") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/python/plugins/db_manager/db_plugins/postgis/plugins/__init__.py b/python/plugins/db_manager/db_plugins/postgis/plugins/__init__.py index aa526e4a9fcb..a881b28d1a71 100644 --- a/python/plugins/db_manager/db_plugins/postgis/plugins/__init__.py +++ b/python/plugins/db_manager/db_plugins/postgis/plugins/__init__.py @@ -28,10 +28,10 @@ def load(db, mainwindow): for name in os.listdir(current_dir): if not os.path.isdir(os.path.join(current_dir, name)): continue - if name in ('__pycache__'): + if name in ("__pycache__"): continue try: - plugin_module = import_module('.'.join((__package__, name))) + plugin_module = import_module(".".join((__package__, name))) except ImportError: continue plugin_module.load(db, mainwindow) diff --git a/python/plugins/db_manager/db_plugins/postgis/plugins/qgis_topoview/__init__.py b/python/plugins/db_manager/db_plugins/postgis/plugins/qgis_topoview/__init__.py index 80c038df01b0..3b66aa9716e8 100644 --- a/python/plugins/db_manager/db_plugins/postgis/plugins/qgis_topoview/__init__.py +++ b/python/plugins/db_manager/db_plugins/postgis/plugins/qgis_topoview/__init__.py @@ -68,32 +68,47 @@ def run(item, action, mainwindow): # check if the selected item is a topology schema isTopoSchema = False - if not hasattr(item, 'schema'): - mainwindow.infoBar.pushMessage("Invalid topology", 'Select a topology schema to continue.', Qgis.MessageLevel.Info, - mainwindow.iface.messageTimeout()) + if not hasattr(item, "schema"): + mainwindow.infoBar.pushMessage( + "Invalid topology", + "Select a topology schema to continue.", + Qgis.MessageLevel.Info, + mainwindow.iface.messageTimeout(), + ) return False if item.schema() is not None: - sql = "SELECT srid FROM topology.topology WHERE name = %s" % quoteStr(item.schema().name) + sql = "SELECT srid FROM topology.topology WHERE name = %s" % quoteStr( + item.schema().name + ) res = db.executeSql(sql) isTopoSchema = len(res) > 0 if not isTopoSchema: - mainwindow.infoBar.pushMessage("Invalid topology", - 'Schema "{}" is not registered in topology.topology.'.format( - item.schema().name), Qgis.MessageLevel.Warning, - mainwindow.iface.messageTimeout()) + mainwindow.infoBar.pushMessage( + "Invalid topology", + 'Schema "{}" is not registered in topology.topology.'.format( + item.schema().name + ), + Qgis.MessageLevel.Warning, + mainwindow.iface.messageTimeout(), + ) return False - if (res[0][0] < 0): - mainwindow.infoBar.pushMessage("WARNING", 'Topology "{}" is registered as having a srid of {} in topology.topology, we will assume 0 (for unknown)'.format(item.schema().name, res[0]), Qgis.MessageLevel.Warning, mainwindow.iface.messageTimeout()) - toposrid = '0' + if res[0][0] < 0: + mainwindow.infoBar.pushMessage( + "WARNING", + f'Topology "{item.schema().name}" is registered as having a srid of {res[0]} in topology.topology, we will assume 0 (for unknown)', + Qgis.MessageLevel.Warning, + mainwindow.iface.messageTimeout(), + ) + toposrid = "0" else: toposrid = str(res[0][0]) # load layers into the current project toponame = item.schema().name - template_dir = os.path.join(current_path, 'templates') + template_dir = os.path.join(current_path, "templates") # do not refresh the canvas until all the layers are added wasFrozen = iface.mapCanvas().isFrozen() @@ -108,134 +123,164 @@ def run(item, action, mainwindow): # FACES # face mbr - uri.setDataSource(toponame, 'face', 'mbr', '', 'face_id') + uri.setDataSource(toponame, "face", "mbr", "", "face_id") uri.setSrid(toposrid) uri.setWkbType(QgsWkbTypes.Type.Polygon) - layerFaceMbr = QgsVectorLayer(uri.uri(False), '%s.face_mbr' % toponame, provider) - layerFaceMbr.loadNamedStyle(os.path.join(template_dir, 'face_mbr.qml')) + layerFaceMbr = QgsVectorLayer( + uri.uri(False), "%s.face_mbr" % toponame, provider + ) + layerFaceMbr.loadNamedStyle(os.path.join(template_dir, "face_mbr.qml")) face_extent = layerFaceMbr.extent() # face geometry - sql = 'SELECT face_id, mbr, topology.ST_GetFaceGeometry(%s,' \ - 'face_id)::geometry(polygon, %s) as geom ' \ - 'FROM %s.face WHERE face_id > 0' % \ - (quoteStr(toponame), toposrid, quoteId(toponame)) - uri.setDataSource('', '(%s\n)' % sql, 'geom', '', 'face_id') - uri.setParam('bbox', 'mbr') - uri.setParam('checkPrimaryKeyUnicity', '0') + sql = ( + "SELECT face_id, mbr, topology.ST_GetFaceGeometry(%s," + "face_id)::geometry(polygon, %s) as geom " + "FROM %s.face WHERE face_id > 0" + % (quoteStr(toponame), toposrid, quoteId(toponame)) + ) + uri.setDataSource("", "(%s\n)" % sql, "geom", "", "face_id") + uri.setParam("bbox", "mbr") + uri.setParam("checkPrimaryKeyUnicity", "0") uri.setSrid(toposrid) uri.setWkbType(QgsWkbTypes.Type.Polygon) - layerFaceGeom = QgsVectorLayer(uri.uri(False), '%s.face' % toponame, provider) + layerFaceGeom = QgsVectorLayer(uri.uri(False), "%s.face" % toponame, provider) layerFaceGeom.setExtent(face_extent) - layerFaceGeom.loadNamedStyle(os.path.join(template_dir, 'face.qml')) + layerFaceGeom.loadNamedStyle(os.path.join(template_dir, "face.qml")) # face_seed - sql = 'SELECT face_id, mbr, ST_PointOnSurface(' \ - 'topology.ST_GetFaceGeometry(%s,' \ - 'face_id))::geometry(point, %s) as geom ' \ - 'FROM %s.face WHERE face_id > 0' % \ - (quoteStr(toponame), toposrid, quoteId(toponame)) - uri.setDataSource('', '(%s)' % sql, 'geom', '', 'face_id') - uri.setParam('bbox', 'mbr') - uri.setParam('checkPrimaryKeyUnicity', '0') + sql = ( + "SELECT face_id, mbr, ST_PointOnSurface(" + "topology.ST_GetFaceGeometry(%s," + "face_id))::geometry(point, %s) as geom " + "FROM %s.face WHERE face_id > 0" + % (quoteStr(toponame), toposrid, quoteId(toponame)) + ) + uri.setDataSource("", "(%s)" % sql, "geom", "", "face_id") + uri.setParam("bbox", "mbr") + uri.setParam("checkPrimaryKeyUnicity", "0") uri.setSrid(toposrid) uri.setWkbType(QgsWkbTypes.Type.Point) - layerFaceSeed = QgsVectorLayer(uri.uri(False), '%s.face_seed' % toponame, provider) + layerFaceSeed = QgsVectorLayer( + uri.uri(False), "%s.face_seed" % toponame, provider + ) layerFaceSeed.setExtent(face_extent) - layerFaceSeed.loadNamedStyle(os.path.join(template_dir, 'face_seed.qml')) + layerFaceSeed.loadNamedStyle(os.path.join(template_dir, "face_seed.qml")) # TODO: add polygon0, polygon1 and polygon2 ? # NODES # node - uri.setDataSource(toponame, 'node', 'geom', '', 'node_id') - uri.removeParam('bbox') + uri.setDataSource(toponame, "node", "geom", "", "node_id") + uri.removeParam("bbox") uri.setSrid(toposrid) uri.setWkbType(QgsWkbTypes.Type.Point) - layerNode = QgsVectorLayer(uri.uri(False), '%s.node' % toponame, provider) - layerNode.loadNamedStyle(os.path.join(template_dir, 'node.qml')) + layerNode = QgsVectorLayer(uri.uri(False), "%s.node" % toponame, provider) + layerNode.loadNamedStyle(os.path.join(template_dir, "node.qml")) node_extent = layerNode.extent() # node labels - uri.setDataSource(toponame, 'node', 'geom', '', 'node_id') + uri.setDataSource(toponame, "node", "geom", "", "node_id") uri.setSrid(toposrid) uri.setWkbType(QgsWkbTypes.Type.Point) - uri.removeParam('bbox') - layerNodeLabel = QgsVectorLayer(uri.uri(False), '%s.node_id' % toponame, provider) + uri.removeParam("bbox") + layerNodeLabel = QgsVectorLayer( + uri.uri(False), "%s.node_id" % toponame, provider + ) layerNodeLabel.setExtent(node_extent) - layerNodeLabel.loadNamedStyle(os.path.join(template_dir, 'node_label.qml')) + layerNodeLabel.loadNamedStyle(os.path.join(template_dir, "node_label.qml")) # EDGES # edge - uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id') + uri.setDataSource(toponame, "edge_data", "geom", "", "edge_id") uri.setSrid(toposrid) uri.setWkbType(QgsWkbTypes.Type.LineString) - uri.removeParam('bbox') - layerEdge = QgsVectorLayer(uri.uri(False), '%s.edge' % toponame, provider) + uri.removeParam("bbox") + layerEdge = QgsVectorLayer(uri.uri(False), "%s.edge" % toponame, provider) edge_extent = layerEdge.extent() # directed edge - uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id') + uri.setDataSource(toponame, "edge_data", "geom", "", "edge_id") uri.setSrid(toposrid) uri.setWkbType(QgsWkbTypes.Type.LineString) - uri.removeParam('bbox') - layerDirectedEdge = QgsVectorLayer(uri.uri(False), '%s.directed_edge' % toponame, provider) + uri.removeParam("bbox") + layerDirectedEdge = QgsVectorLayer( + uri.uri(False), "%s.directed_edge" % toponame, provider + ) layerDirectedEdge.setExtent(edge_extent) - layerDirectedEdge.loadNamedStyle(os.path.join(template_dir, 'edge.qml')) + layerDirectedEdge.loadNamedStyle(os.path.join(template_dir, "edge.qml")) # edge labels - uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id') + uri.setDataSource(toponame, "edge_data", "geom", "", "edge_id") uri.setSrid(toposrid) uri.setWkbType(QgsWkbTypes.Type.LineString) - uri.removeParam('bbox') - layerEdgeLabel = QgsVectorLayer(uri.uri(False), '%s.edge_id' % toponame, provider) + uri.removeParam("bbox") + layerEdgeLabel = QgsVectorLayer( + uri.uri(False), "%s.edge_id" % toponame, provider + ) layerEdgeLabel.setExtent(edge_extent) - layerEdgeLabel.loadNamedStyle(os.path.join(template_dir, 'edge_label.qml')) + layerEdgeLabel.loadNamedStyle(os.path.join(template_dir, "edge_label.qml")) # face_left - uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id') + uri.setDataSource(toponame, "edge_data", "geom", "", "edge_id") uri.setSrid(toposrid) uri.setWkbType(QgsWkbTypes.Type.LineString) - uri.removeParam('bbox') - layerFaceLeft = QgsVectorLayer(uri.uri(False), '%s.face_left' % toponame, provider) + uri.removeParam("bbox") + layerFaceLeft = QgsVectorLayer( + uri.uri(False), "%s.face_left" % toponame, provider + ) layerFaceLeft.setExtent(edge_extent) - layerFaceLeft.loadNamedStyle(os.path.join(template_dir, 'face_left.qml')) + layerFaceLeft.loadNamedStyle(os.path.join(template_dir, "face_left.qml")) # face_right - uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id') + uri.setDataSource(toponame, "edge_data", "geom", "", "edge_id") uri.setSrid(toposrid) uri.setWkbType(QgsWkbTypes.Type.LineString) - uri.removeParam('bbox') - layerFaceRight = QgsVectorLayer(uri.uri(False), '%s.face_right' % toponame, provider) + uri.removeParam("bbox") + layerFaceRight = QgsVectorLayer( + uri.uri(False), "%s.face_right" % toponame, provider + ) layerFaceRight.setExtent(edge_extent) - layerFaceRight.loadNamedStyle(os.path.join(template_dir, 'face_right.qml')) + layerFaceRight.loadNamedStyle(os.path.join(template_dir, "face_right.qml")) # next_left - uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id') + uri.setDataSource(toponame, "edge_data", "geom", "", "edge_id") uri.setSrid(toposrid) uri.setWkbType(QgsWkbTypes.Type.LineString) - uri.removeParam('bbox') - layerNextLeft = QgsVectorLayer(uri.uri(False), '%s.next_left' % toponame, provider) + uri.removeParam("bbox") + layerNextLeft = QgsVectorLayer( + uri.uri(False), "%s.next_left" % toponame, provider + ) layerNextLeft.setExtent(edge_extent) - layerNextLeft.loadNamedStyle(os.path.join(template_dir, 'next_left.qml')) + layerNextLeft.loadNamedStyle(os.path.join(template_dir, "next_left.qml")) # next_right - uri.setDataSource(toponame, 'edge_data', 'geom', '', 'edge_id') + uri.setDataSource(toponame, "edge_data", "geom", "", "edge_id") uri.setSrid(toposrid) uri.setWkbType(QgsWkbTypes.Type.LineString) - uri.removeParam('bbox') - layerNextRight = QgsVectorLayer(uri.uri(False), '%s.next_right' % toponame, provider) + uri.removeParam("bbox") + layerNextRight = QgsVectorLayer( + uri.uri(False), "%s.next_right" % toponame, provider + ) layerNextRight.setExtent(edge_extent) - layerNextRight.loadNamedStyle(os.path.join(template_dir, 'next_right.qml')) + layerNextRight.loadNamedStyle(os.path.join(template_dir, "next_right.qml")) # Add layers to the layer tree faceLayers = [layerFaceMbr, layerFaceGeom, layerFaceSeed] nodeLayers = [layerNode, layerNodeLabel] - edgeLayers = [layerEdge, layerDirectedEdge, layerEdgeLabel, layerFaceLeft, layerFaceRight, layerNextLeft, layerNextRight] + edgeLayers = [ + layerEdge, + layerDirectedEdge, + layerEdgeLabel, + layerFaceLeft, + layerFaceRight, + layerNextLeft, + layerNextRight, + ] QgsProject.instance().addMapLayers(faceLayers, False) QgsProject.instance().addMapLayers(nodeLayers, False) @@ -243,19 +288,19 @@ def run(item, action, mainwindow): # Organize layers in groups - groupFaces = QgsLayerTreeGroup('Faces') + groupFaces = QgsLayerTreeGroup("Faces") for layer in faceLayers: nodeLayer = groupFaces.addLayer(layer) nodeLayer.setItemVisibilityChecked(False) nodeLayer.setExpanded(False) - groupNodes = QgsLayerTreeGroup('Nodes') + groupNodes = QgsLayerTreeGroup("Nodes") for layer in nodeLayers: nodeLayer = groupNodes.addLayer(layer) nodeLayer.setItemVisibilityChecked(False) nodeLayer.setExpanded(False) - groupEdges = QgsLayerTreeGroup('Edges') + groupEdges = QgsLayerTreeGroup("Edges") for layer in edgeLayers: nodeLayer = groupEdges.addLayer(layer) nodeLayer.setItemVisibilityChecked(False) @@ -295,7 +340,7 @@ def run(item, action, mainwindow): # Set canvas extent to topology extent, if not yet initialized canvas = iface.mapCanvas() - if (canvas.fullExtent().isNull()): + if canvas.fullExtent().isNull(): ext = node_extent ext.combineExtentWith(edge_extent) # Grow by 1/20 of largest side diff --git a/python/plugins/db_manager/db_plugins/postgis/plugins/versioning/__init__.py b/python/plugins/db_manager/db_plugins/postgis/plugins/versioning/__init__.py index 4320453779b4..556ce859bcdc 100644 --- a/python/plugins/db_manager/db_plugins/postgis/plugins/versioning/__init__.py +++ b/python/plugins/db_manager/db_plugins/postgis/plugins/versioning/__init__.py @@ -30,8 +30,12 @@ def load(db, mainwindow): # add the action to the DBManager menu - action = QAction(QIcon(), QApplication.translate("DBManagerPlugin", "&Change Logging…"), db) - mainwindow.registerAction(action, QApplication.translate("DBManagerPlugin", "&Table"), run) + action = QAction( + QIcon(), QApplication.translate("DBManagerPlugin", "&Change Logging…"), db + ) + mainwindow.registerAction( + action, QApplication.translate("DBManagerPlugin", "&Table"), run + ) # The run function is called once the user clicks on the action TopoViewer diff --git a/python/plugins/db_manager/db_plugins/postgis/plugins/versioning/dlg_versioning.py b/python/plugins/db_manager/db_plugins/postgis/plugins/versioning/dlg_versioning.py index 41813bcb35a1..068ba08503b9 100644 --- a/python/plugins/db_manager/db_plugins/postgis/plugins/versioning/dlg_versioning.py +++ b/python/plugins/db_manager/db_plugins/postgis/plugins/versioning/dlg_versioning.py @@ -28,7 +28,7 @@ from .....dlg_db_error import DlgDbError from ....plugin import BaseError, Table -Ui_DlgVersioning, _ = uic.loadUiType(Path(__file__).parent / 'DlgVersioining.ui') +Ui_DlgVersioning, _ = uic.loadUiType(Path(__file__).parent / "DlgVersioining.ui") class DlgVersioning(QDialog, Ui_DlgVersioning): @@ -75,7 +75,7 @@ def populateSchemas(self): index = -1 for schema in self.schemas: self.cboSchema.addItem(schema.name) - if hasattr(self.item, 'schema') and schema.name == self.item.schema().name: + if hasattr(self.item, "schema") and schema.name == self.item.schema().name: index = self.cboSchema.count() - 1 self.cboSchema.setCurrentIndex(index) @@ -100,12 +100,15 @@ def populateTables(self): self.cboTable.addItem(table.name) def get_escaped_name(self, schema, table, suffix): - name = self.db.connector.quoteId("%s%s" % (table, suffix)) + name = self.db.connector.quoteId(f"{table}{suffix}") schema_name = self.db.connector.quoteId(schema) if schema else None - return "%s.%s" % (schema_name, name) if schema_name else name + return f"{schema_name}.{name}" if schema_name else name def updateSql(self): - if self.cboTable.currentIndex() < 0 or len(self.tables) < self.cboTable.currentIndex(): + if ( + self.cboTable.currentIndex() < 0 + or len(self.tables) < self.cboTable.currentIndex() + ): return self.table = self.tables[self.cboTable.currentIndex()] @@ -124,7 +127,10 @@ def updateSql(self): for constr in self.table.constraints(): if constr.type == constr.TypePrimaryKey: self.origPkeyName = self.db.connector.quoteId(constr.name) - self.colOrigPkey = [self.db.connector.quoteId(x_y[1].name) for x_y in iter(list(constr.fields().items()))] + self.colOrigPkey = [ + self.db.connector.quoteId(x_y[1].name) + for x_y in iter(list(constr.fields().items())) + ] break if self.colOrigPkey is None: @@ -140,11 +146,19 @@ def updateSql(self): self.colOrigPkey = self.colOrigPkey[0] # define view, function, rule and trigger names - self.view = self.get_escaped_name(self.table.schemaName(), self.table.name, "_current") - - self.func_at_time = self.get_escaped_name(self.table.schemaName(), self.table.name, "_at_time") - self.func_update = self.get_escaped_name(self.table.schemaName(), self.table.name, "_update") - self.func_insert = self.get_escaped_name(self.table.schemaName(), self.table.name, "_insert") + self.view = self.get_escaped_name( + self.table.schemaName(), self.table.name, "_current" + ) + + self.func_at_time = self.get_escaped_name( + self.table.schemaName(), self.table.name, "_at_time" + ) + self.func_update = self.get_escaped_name( + self.table.schemaName(), self.table.name, "_update" + ) + self.func_insert = self.get_escaped_name( + self.table.schemaName(), self.table.name, "_insert" + ) self.rule_del = self.get_escaped_name(None, self.table.name, "_del") self.trigger_update = self.get_escaped_name(None, self.table.name, "_update") @@ -166,7 +180,7 @@ def updateSql(self): # if self.current: sql.append(self.sql_updatesView()) - self.txtSql.setPlainText('\n\n'.join(sql)) + self.txtSql.setPlainText("\n\n".join(sql)) self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(True) return sql @@ -176,18 +190,27 @@ def showHelp(self): QMessageBox.information(self, "Help", helpText) def sql_alterTable(self): - return "ALTER TABLE %s ADD %s serial, ADD %s timestamp default '-infinity', ADD %s timestamp, ADD %s varchar;" % ( - self.schematable, self.colPkey, self.colStart, self.colEnd, self.colUser) + return "ALTER TABLE {} ADD {} serial, ADD {} timestamp default '-infinity', ADD {} timestamp, ADD {} varchar;".format( + self.schematable, self.colPkey, self.colStart, self.colEnd, self.colUser + ) def sql_setPkey(self): - return "ALTER TABLE %s DROP CONSTRAINT %s, ADD PRIMARY KEY (%s);" % ( - self.schematable, self.origPkeyName, self.colPkey) + return "ALTER TABLE {} DROP CONSTRAINT {}, ADD PRIMARY KEY ({});".format( + self.schematable, self.origPkeyName, self.colPkey + ) def sql_currentView(self): cols = self.colPkey + "," + ",".join(self.columns) - return "CREATE VIEW %(view)s AS SELECT %(cols)s FROM %(schematable)s WHERE %(end)s IS NULL;" % \ - {'view': self.view, 'cols': cols, 'schematable': self.schematable, 'end': self.colEnd} + return ( + "CREATE VIEW %(view)s AS SELECT %(cols)s FROM %(schematable)s WHERE %(end)s IS NULL;" + % { + "view": self.view, + "cols": cols, + "schematable": self.schematable, + "end": self.colEnd, + } + ) def sql_functions(self): cols = ",".join(self.columns) @@ -195,80 +218,99 @@ def sql_functions(self): old_cols = ",".join("OLD." + x for x in self.columns) sql = """ -CREATE OR REPLACE FUNCTION %(func_at_time)s(timestamp) -RETURNS SETOF %(view)s AS +CREATE OR REPLACE FUNCTION {func_at_time}(timestamp) +RETURNS SETOF {view} AS $$ -SELECT %(all_cols)s FROM %(schematable)s WHERE - ( SELECT CASE WHEN %(end)s IS NULL THEN (%(start)s <= $1) ELSE (%(start)s <= $1 AND %(end)s > $1) END ); +SELECT {all_cols} FROM {schematable} WHERE + ( SELECT CASE WHEN {end} IS NULL THEN ({start} <= $1) ELSE ({start} <= $1 AND {end} > $1) END ); $$ LANGUAGE 'sql'; -CREATE OR REPLACE FUNCTION %(func_update)s() +CREATE OR REPLACE FUNCTION {func_update}() RETURNS TRIGGER AS $$ BEGIN - IF OLD.%(end)s IS NOT NULL THEN + IF OLD.{end} IS NOT NULL THEN RETURN NULL; END IF; - IF NEW.%(end)s IS NULL THEN - INSERT INTO %(schematable)s (%(cols)s, %(start)s, %(end)s) VALUES (%(oldcols)s, OLD.%(start)s, current_timestamp); - NEW.%(start)s = current_timestamp; - NEW.%(user)s = current_user; + IF NEW.{end} IS NULL THEN + INSERT INTO {schematable} ({cols}, {start}, {end}) VALUES ({oldcols}, OLD.{start}, current_timestamp); + NEW.{start} = current_timestamp; + NEW.{user} = current_user; END IF; RETURN NEW; END; $$ LANGUAGE 'plpgsql'; -CREATE OR REPLACE FUNCTION %(func_insert)s() +CREATE OR REPLACE FUNCTION {func_insert}() RETURNS trigger AS $$ BEGIN - if NEW.%(start)s IS NULL then - NEW.%(start)s = now(); - NEW.%(end)s = null; - NEW.%(user)s = current_user; + if NEW.{start} IS NULL then + NEW.{start} = now(); + NEW.{end} = null; + NEW.{user} = current_user; end if; RETURN NEW; END; $$ -LANGUAGE 'plpgsql';""" % {'view': self.view, 'schematable': self.schematable, 'cols': cols, 'oldcols': old_cols, - 'start': self.colStart, 'end': self.colEnd, 'user': self.colUser, 'func_at_time': self.func_at_time, - 'all_cols': all_cols, 'func_update': self.func_update, 'func_insert': self.func_insert} +LANGUAGE 'plpgsql';""".format( + view=self.view, + schematable=self.schematable, + cols=cols, + oldcols=old_cols, + start=self.colStart, + end=self.colEnd, + user=self.colUser, + func_at_time=self.func_at_time, + all_cols=all_cols, + func_update=self.func_update, + func_insert=self.func_insert, + ) return sql def sql_triggers(self): return """ -CREATE RULE %(rule_del)s AS ON DELETE TO %(schematable)s -DO INSTEAD UPDATE %(schematable)s SET %(end)s = current_timestamp WHERE %(pkey)s = OLD.%(pkey)s AND %(end)s IS NULL; - -CREATE TRIGGER %(trigger_update)s BEFORE UPDATE ON %(schematable)s -FOR EACH ROW EXECUTE PROCEDURE %(func_update)s(); - -CREATE TRIGGER %(trigger_insert)s BEFORE INSERT ON %(schematable)s -FOR EACH ROW EXECUTE PROCEDURE %(func_insert)s();""" % \ - {'rule_del': self.rule_del, 'trigger_update': self.trigger_update, 'trigger_insert': self.trigger_insert, - 'func_update': self.func_update, 'func_insert': self.func_insert, 'schematable': self.schematable, - 'pkey': self.colPkey, 'end': self.colEnd} +CREATE RULE {rule_del} AS ON DELETE TO {schematable} +DO INSTEAD UPDATE {schematable} SET {end} = current_timestamp WHERE {pkey} = OLD.{pkey} AND {end} IS NULL; + +CREATE TRIGGER {trigger_update} BEFORE UPDATE ON {schematable} +FOR EACH ROW EXECUTE PROCEDURE {func_update}(); + +CREATE TRIGGER {trigger_insert} BEFORE INSERT ON {schematable} +FOR EACH ROW EXECUTE PROCEDURE {func_insert}();""".format( + rule_del=self.rule_del, + trigger_update=self.trigger_update, + trigger_insert=self.trigger_insert, + func_update=self.func_update, + func_insert=self.func_insert, + schematable=self.schematable, + pkey=self.colPkey, + end=self.colEnd, + ) def sql_updatesView(self): cols = ",".join(self.columns) return_cols = self.colPkey + "," + ",".join(self.columns) new_cols = ",".join("NEW." + x for x in self.columns) - assign_cols = ",".join("%s = NEW.%s" % (x, x) for x in self.columns) + assign_cols = ",".join(f"{x} = NEW.{x}" for x in self.columns) return """ -CREATE OR REPLACE RULE "_DELETE" AS ON DELETE TO %(view)s DO INSTEAD - DELETE FROM %(schematable)s WHERE %(origpkey)s = old.%(origpkey)s; -CREATE OR REPLACE RULE "_INSERT" AS ON INSERT TO %(view)s DO INSTEAD - INSERT INTO %(schematable)s (%(cols)s) VALUES (%(newcols)s) RETURNING %(return_cols)s; -CREATE OR REPLACE RULE "_UPDATE" AS ON UPDATE TO %(view)s DO INSTEAD - UPDATE %(schematable)s SET %(assign)s WHERE %(origpkey)s = NEW.%(origpkey)s;""" % {'view': self.view, - 'schematable': self.schematable, - 'cols': cols, 'newcols': new_cols, - 'return_cols': return_cols, - 'assign': assign_cols, - 'origpkey': self.colOrigPkey} +CREATE OR REPLACE RULE "_DELETE" AS ON DELETE TO {view} DO INSTEAD + DELETE FROM {schematable} WHERE {origpkey} = old.{origpkey}; +CREATE OR REPLACE RULE "_INSERT" AS ON INSERT TO {view} DO INSTEAD + INSERT INTO {schematable} ({cols}) VALUES ({newcols}) RETURNING {return_cols}; +CREATE OR REPLACE RULE "_UPDATE" AS ON UPDATE TO {view} DO INSTEAD + UPDATE {schematable} SET {assign} WHERE {origpkey} = NEW.{origpkey};""".format( + view=self.view, + schematable=self.schematable, + cols=cols, + newcols=new_cols, + return_cols=return_cols, + assign=assign_cols, + origpkey=self.colOrigPkey, + ) def onOK(self): # execute and commit the code @@ -284,5 +326,7 @@ def onOK(self): finally: QApplication.restoreOverrideCursor() - QMessageBox.information(self, "DB Manager", "Versioning was successfully created.") + QMessageBox.information( + self, "DB Manager", "Versioning was successfully created." + ) self.accept() diff --git a/python/plugins/db_manager/db_plugins/postgis/sql_dictionary.py b/python/plugins/db_manager/db_plugins/postgis/sql_dictionary.py index ea7c6de97a11..9b8f1f19a485 100644 --- a/python/plugins/db_manager/db_plugins/postgis/sql_dictionary.py +++ b/python/plugins/db_manager/db_plugins/postgis/sql_dictionary.py @@ -15,185 +15,855 @@ *************************************************************************** """ -__author__ = 'Giuseppe Sucameli' -__date__ = 'April 2012' -__copyright__ = '(C) 2012, Giuseppe Sucameli' +__author__ = "Giuseppe Sucameli" +__date__ = "April 2012" +__copyright__ = "(C) 2012, Giuseppe Sucameli" # keywords keywords = [ # TODO get them from a reference page - "action", "add", "after", "all", "alter", "analyze", "and", "as", "asc", - "before", "begin", "between", "by", "cascade", "case", "cast", "check", - "collate", "column", "commit", "constraint", "create", "cross", "current_date", - "current_time", "current_timestamp", "default", "deferrable", "deferred", - "delete", "desc", "distinct", "drop", "each", "else", "end", "escape", - "except", "exists", "for", "foreign", "from", "full", "group", "having", - "ignore", "immediate", "in", "initially", "inner", "insert", "intersect", - "into", "is", "isnull", "join", "key", "left", "like", "limit", "match", - "natural", "no", "not", "notnull", "null", "of", "offset", "on", "or", "order", - "outer", "primary", "references", "release", "restrict", "right", "rollback", - "row", "savepoint", "select", "set", "table", "temporary", "then", "to", - "transaction", "trigger", "union", "unique", "update", "using", "values", - "view", "when", "where", - - "absolute", "admin", "aggregate", "alias", "allocate", "analyse", "any", "are", - "array", "asensitive", "assertion", "asymmetric", "at", "atomic", - "authorization", "avg", "bigint", "binary", "bit", "bit_length", "blob", - "boolean", "both", "breadth", "call", "called", "cardinality", "cascaded", - "catalog", "ceil", "ceiling", "char", "character", "character_length", - "char_length", "class", "clob", "close", "coalesce", "collation", "collect", - "completion", "condition", "connect", "connection", "constraints", - "constructor", "continue", "convert", "corr", "corresponding", "count", - "covar_pop", "covar_samp", "cube", "cume_dist", "current", - "current_default_transform_group", "current_path", "current_role", - "current_transform_group_for_type", "current_user", "cursor", "cycle", "data", - "date", "day", "deallocate", "dec", "decimal", "declare", "dense_rank", - "depth", "deref", "describe", "descriptor", "destroy", "destructor", - "deterministic", "diagnostics", "dictionary", "disconnect", "do", "domain", - "double", "dynamic", "element", "end-exec", "equals", "every", "exception", - "exec", "execute", "exp", "external", "extract", "false", "fetch", "filter", - "first", "float", "floor", "found", "free", "freeze", "function", "fusion", - "general", "get", "global", "go", "goto", "grant", "grouping", "hold", "host", - "hour", "identity", "ilike", "indicator", "initialize", "inout", "input", - "insensitive", "int", "integer", "intersection", "interval", "isolation", - "iterate", "language", "large", "last", "lateral", "leading", "less", "level", - "ln", "local", "localtime", "localtimestamp", "locator", "lower", "map", "max", - "member", "merge", "method", "min", "minute", "mod", "modifies", "modify", - "module", "month", "multiset", "names", "national", "nchar", "nclob", "new", - "next", "none", "normalize", "nullif", "numeric", "object", "octet_length", - "off", "old", "only", "open", "operation", "option", "ordinality", "out", - "output", "over", "overlaps", "overlay", "pad", "parameter", "parameters", - "partial", "partition", "path", "percentile_cont", "percentile_disc", - "percent_rank", "placing", "position", "postfix", "power", "precision", - "prefix", "preorder", "prepare", "preserve", "prior", "privileges", - "procedure", "public", "range", "rank", "read", "reads", "real", "recursive", - "ref", "referencing", "regr_avgx", "regr_avgy", "regr_count", "regr_intercept", - "regr_r2", "regr_slope", "regr_sxx", "regr_sxy", "regr_syy", "relative", - "result", "return", "returning", "returns", "revoke", "role", "rollup", - "routine", "rows", "row_number", "schema", "scope", "scroll", "search", - "second", "section", "sensitive", "sequence", "session", "session_user", - "sets", "similar", "size", "smallint", "some", "space", "specific", - "specifictype", "sql", "sqlcode", "sqlerror", "sqlexception", "sqlstate", - "sqlwarning", "sqrt", "start", "state", "statement", "static", "stddev_pop", - "stddev_samp", "structure", "submultiset", "substring", "sum", "symmetric", - "system", "system_user", "tablesample", "terminate", "than", "time", - "timestamp", "timezone_hour", "timezone_minute", "trailing", "translate", - "translation", "treat", "trim", "true", "uescape", "under", "unknown", - "unnest", "upper", "usage", "user", "value", "varchar", "variable", "varying", - "var_pop", "var_samp", "verbose", "whenever", "width_bucket", "window", "with", - "within", "without", "work", "write", "xml", "xmlagg", "xmlattributes", - "xmlbinary", "xmlcomment", "xmlconcat", "xmlelement", "xmlforest", - "xmlnamespaces", "xmlparse", "xmlpi", "xmlroot", "xmlserialize", "year", "zone" + "action", + "add", + "after", + "all", + "alter", + "analyze", + "and", + "as", + "asc", + "before", + "begin", + "between", + "by", + "cascade", + "case", + "cast", + "check", + "collate", + "column", + "commit", + "constraint", + "create", + "cross", + "current_date", + "current_time", + "current_timestamp", + "default", + "deferrable", + "deferred", + "delete", + "desc", + "distinct", + "drop", + "each", + "else", + "end", + "escape", + "except", + "exists", + "for", + "foreign", + "from", + "full", + "group", + "having", + "ignore", + "immediate", + "in", + "initially", + "inner", + "insert", + "intersect", + "into", + "is", + "isnull", + "join", + "key", + "left", + "like", + "limit", + "match", + "natural", + "no", + "not", + "notnull", + "null", + "of", + "offset", + "on", + "or", + "order", + "outer", + "primary", + "references", + "release", + "restrict", + "right", + "rollback", + "row", + "savepoint", + "select", + "set", + "table", + "temporary", + "then", + "to", + "transaction", + "trigger", + "union", + "unique", + "update", + "using", + "values", + "view", + "when", + "where", + "absolute", + "admin", + "aggregate", + "alias", + "allocate", + "analyse", + "any", + "are", + "array", + "asensitive", + "assertion", + "asymmetric", + "at", + "atomic", + "authorization", + "avg", + "bigint", + "binary", + "bit", + "bit_length", + "blob", + "boolean", + "both", + "breadth", + "call", + "called", + "cardinality", + "cascaded", + "catalog", + "ceil", + "ceiling", + "char", + "character", + "character_length", + "char_length", + "class", + "clob", + "close", + "coalesce", + "collation", + "collect", + "completion", + "condition", + "connect", + "connection", + "constraints", + "constructor", + "continue", + "convert", + "corr", + "corresponding", + "count", + "covar_pop", + "covar_samp", + "cube", + "cume_dist", + "current", + "current_default_transform_group", + "current_path", + "current_role", + "current_transform_group_for_type", + "current_user", + "cursor", + "cycle", + "data", + "date", + "day", + "deallocate", + "dec", + "decimal", + "declare", + "dense_rank", + "depth", + "deref", + "describe", + "descriptor", + "destroy", + "destructor", + "deterministic", + "diagnostics", + "dictionary", + "disconnect", + "do", + "domain", + "double", + "dynamic", + "element", + "end-exec", + "equals", + "every", + "exception", + "exec", + "execute", + "exp", + "external", + "extract", + "false", + "fetch", + "filter", + "first", + "float", + "floor", + "found", + "free", + "freeze", + "function", + "fusion", + "general", + "get", + "global", + "go", + "goto", + "grant", + "grouping", + "hold", + "host", + "hour", + "identity", + "ilike", + "indicator", + "initialize", + "inout", + "input", + "insensitive", + "int", + "integer", + "intersection", + "interval", + "isolation", + "iterate", + "language", + "large", + "last", + "lateral", + "leading", + "less", + "level", + "ln", + "local", + "localtime", + "localtimestamp", + "locator", + "lower", + "map", + "max", + "member", + "merge", + "method", + "min", + "minute", + "mod", + "modifies", + "modify", + "module", + "month", + "multiset", + "names", + "national", + "nchar", + "nclob", + "new", + "next", + "none", + "normalize", + "nullif", + "numeric", + "object", + "octet_length", + "off", + "old", + "only", + "open", + "operation", + "option", + "ordinality", + "out", + "output", + "over", + "overlaps", + "overlay", + "pad", + "parameter", + "parameters", + "partial", + "partition", + "path", + "percentile_cont", + "percentile_disc", + "percent_rank", + "placing", + "position", + "postfix", + "power", + "precision", + "prefix", + "preorder", + "prepare", + "preserve", + "prior", + "privileges", + "procedure", + "public", + "range", + "rank", + "read", + "reads", + "real", + "recursive", + "ref", + "referencing", + "regr_avgx", + "regr_avgy", + "regr_count", + "regr_intercept", + "regr_r2", + "regr_slope", + "regr_sxx", + "regr_sxy", + "regr_syy", + "relative", + "result", + "return", + "returning", + "returns", + "revoke", + "role", + "rollup", + "routine", + "rows", + "row_number", + "schema", + "scope", + "scroll", + "search", + "second", + "section", + "sensitive", + "sequence", + "session", + "session_user", + "sets", + "similar", + "size", + "smallint", + "some", + "space", + "specific", + "specifictype", + "sql", + "sqlcode", + "sqlerror", + "sqlexception", + "sqlstate", + "sqlwarning", + "sqrt", + "start", + "state", + "statement", + "static", + "stddev_pop", + "stddev_samp", + "structure", + "submultiset", + "substring", + "sum", + "symmetric", + "system", + "system_user", + "tablesample", + "terminate", + "than", + "time", + "timestamp", + "timezone_hour", + "timezone_minute", + "trailing", + "translate", + "translation", + "treat", + "trim", + "true", + "uescape", + "under", + "unknown", + "unnest", + "upper", + "usage", + "user", + "value", + "varchar", + "variable", + "varying", + "var_pop", + "var_samp", + "verbose", + "whenever", + "width_bucket", + "window", + "with", + "within", + "without", + "work", + "write", + "xml", + "xmlagg", + "xmlattributes", + "xmlbinary", + "xmlcomment", + "xmlconcat", + "xmlelement", + "xmlforest", + "xmlnamespaces", + "xmlparse", + "xmlpi", + "xmlroot", + "xmlserialize", + "year", + "zone", ] postgis_keywords = [] # functions -functions = [ - "coalesce", - "nullif", "quote", "random", - "replace", "soundex" -] +functions = ["coalesce", "nullif", "quote", "random", "replace", "soundex"] operators = [ - ' AND ', ' OR ', '||', ' < ', ' <= ', ' > ', ' >= ', ' = ', ' <> ', ' IS ', ' IS NOT ', ' IN ', ' LIKE ', ' GLOB ', ' MATCH ', ' REGEXP ' + " AND ", + " OR ", + "||", + " < ", + " <= ", + " > ", + " >= ", + " = ", + " <> ", + " IS ", + " IS NOT ", + " IN ", + " LIKE ", + " GLOB ", + " MATCH ", + " REGEXP ", ] math_functions = [ # SQL math functions - "Abs", "ACos", "ASin", "ATan", "Cos", "Cot", "Degrees", "Exp", "Floor", "Log", "Log2", - "Log10", "Pi", "Radians", "Round", "Sign", "Sin", "Sqrt", "StdDev_Pop", "StdDev_Samp", "Tan", - "Var_Pop", "Var_Samp"] + "Abs", + "ACos", + "ASin", + "ATan", + "Cos", + "Cot", + "Degrees", + "Exp", + "Floor", + "Log", + "Log2", + "Log10", + "Pi", + "Radians", + "Round", + "Sign", + "Sin", + "Sqrt", + "StdDev_Pop", + "StdDev_Samp", + "Tan", + "Var_Pop", + "Var_Samp", +] -string_functions = ["Length", "Lower", "Upper", "Like", "Trim", "LTrim", "RTrim", "Replace", "Substr"] +string_functions = [ + "Length", + "Lower", + "Upper", + "Like", + "Trim", + "LTrim", + "RTrim", + "Replace", + "Substr", +] aggregate_functions = [ - "Max", "Min", "Avg", "Count", "Sum", "Group_Concat", "Total", "Var_Pop", "Var_Samp", "StdDev_Pop", "StdDev_Samp" + "Max", + "Min", + "Avg", + "Count", + "Sum", + "Group_Concat", + "Total", + "Var_Pop", + "Var_Samp", + "StdDev_Pop", + "StdDev_Samp", ] postgis_functions = [ # from http://www.postgis.org/docs/reference.html - # 7.1. PostgreSQL PostGIS Types - "*box2d", "*box3d", "*box3d_extent", "*geometry", "*geometry_dump", "*geography", - # 7.2. Management Functions - "*addgeometrycolumn", "*dropgeometrycolumn", "*dropgeometrytable", "*postgis_full_version", - "*postgis_geos_version", "*postgis_libxml_version", "*postgis_lib_build_date", - "*postgis_lib_version", "*postgis_proj_version", "*postgis_scripts_build_date", - "*postgis_scripts_installed", "*postgis_scripts_released", "*postgis_uses_stats", "*postgis_version", - "*populate_geometry_columns", "*probe_geometry_columns", "*updategeometrysrid", - # 7.3. Geometry Constructors - "*ST_bdpolyfromtext", "*ST_bdmpolyfromtext", "*ST_geogfromtext", "*ST_geographyfromtext", - "*ST_geogfromwkb", "*ST_geomcollfromtext", "*ST_geomfromewkb", "*ST_geomfromewkt", - "*ST_geometryfromtext", "*ST_geomfromgml", "*ST_geomfromkml", "*ST_gmltosql", "*ST_geomfromtext", - "*ST_geomfromwkb", "*ST_linefrommultipoint", "*ST_linefromtext", "*ST_linefromwkb", - "*ST_linestringfromwkb", "*ST_makebox2d", "*ST_makebox3d", "ST_MakeLine", "*ST_makeenvelope", - "ST_MakePolygon", "ST_MakePoint", "ST_MakePointM", "*ST_MLinefromtext", "*ST_mpointfromtext", - "*ST_mpolyfromtext", "ST_Point", "*ST_pointfromtext", "*ST_pointfromwkb", "ST_Polygon", - "*ST_polygonfromtext", "*ST_wkbtosql", "*ST_wkttosql", - # 7.4. Geometry Accessors - "GeometryType", "ST_Boundary", "*ST_coorddim", "ST_Dimension", "ST_EndPoint", "ST_Envelope", - "ST_ExteriorRing", "ST_GeometryN", "ST_GeometryType", "ST_InteriorRingN", "ST_isClosed", - "ST_isEmpty", "ST_isRing", "ST_isSimple", "ST_isValid", "ST_isValidReason", "ST_M", "ST_NDims", - "ST_NPoints", "ST_NRings", "ST_NumGeometries", "ST_NumInteriorrings", "ST_NumInteriorring", - "ST_NumPoints", "ST_PointN", "ST_Srid", "ST_StartPoint", "ST_Summary", "ST_X", "ST_Y", "ST_Z", - "*ST_zmflag", - # 7.5. Geometry Editors - "ST_AddPoint", "ST_Affine", "ST_Force2D", "*ST_Force3D", "*ST_Force3dZ", "*ST_Force3DM", - "*ST_Force_4d", "*ST_force_collection", "*ST_forcerhr", "*ST_linemerge", "*ST_collectionextract", - "ST_Multi", "*ST_removepoint", "*ST_reverse", "*ST_rotate", "*ST_rotatex", "*ST_rotatey", - "*ST_rotatez", "*ST_scale", "*ST_segmentize", "*ST_setpoint", "ST_SetSrid", "ST_SnapToGrid", - "ST_Transform", "ST_Translate", "*ST_transscale", - # 7.6. Geometry Outputs - "*ST_asbinary", "*ST_asewkb", "*ST_asewkt", "*ST_asgeojson", "*ST_asgml", "*ST_ashexewkb", "*ST_askml", - "*ST_assvg", "*ST_geohash", "ST_Astext", - # 7.7. Operators - # 7.8. Spatial Relationships and Measurements - "ST_Area", "ST_Azimuth", "ST_Centroid", "ST_ClosestPoint", "ST_Contains", "ST_ContainsProperly", - "ST_Covers", "ST_CoveredBy", "ST_Crosses", "*ST_linecrossingdirection", "ST_Cisjoint", - "ST_Distance", "*ST_hausdorffdistance", "*ST_maxdistance", "ST_Distance_Sphere", - "ST_Distance_Spheroid", "*ST_DFullyWithin", "ST_DWithin", "ST_Equals", "*ST_hasarc", - "ST_Intersects", "ST_Length", "*ST_Length2d", "*ST_length3d", "ST_Length_Spheroid", - "*ST_length2d_spheroid", "*ST_length3d_spheroid", "*ST_longestline", "*ST_orderingequals", - "ST_Overlaps", "*ST_perimeter", "*ST_perimeter2d", "*ST_perimeter3d", "ST_PointOnSurface", - "ST_Relate", "ST_ShortestLine", "ST_Touches", "ST_Within", - # 7.9. Geometry Processing Functions - "ST_Buffer", "ST_BuildArea", "ST_Collect", "ST_ConvexHull", "*ST_curvetoline", "ST_Difference", - "ST_Dump", "*ST_dumppoints", "*ST_dumprings", "ST_Intersection", "*ST_linetocurve", "*ST_memunion", - "*ST_minimumboundingcircle", "*ST_polygonize", "*ST_shift_longitude", "ST_Simplify", - "ST_SimplifyPreserveTopology", "ST_SymDifference", "ST_Union", - # 7.10. Linear Referencing - "ST_Line_Interpolate_Point", "ST_Line_Locate_Point", "ST_Line_Substring", - "*ST_locate_along_measure", "*ST_locate_between_measures", "*ST_locatebetweenelevations", - "*ST_addmeasure", - # 7.11. Long Transactions Support - "*addauth", "*checkauth", "*disablelongtransactions", "*enablelongtransactions", "*lockrow", - "*unlockrows", - # 7.12. Miscellaneous Functions - "*ST_accum", "*box2d", "*box3d", "*ST_estimated_extent", "*ST_expand", "ST_Extent", "*ST_extent3d", - "*find_srid", "*ST_mem_size", "*ST_point_inside_circle", "ST_XMax", "ST_XMin", "ST_YMax", "ST_YMin", - "ST_ZMax", "ST_ZMin", - # 7.13. Exceptional Functions - "*postgis_addbbox", "*postgis_dropbbox", "*postgis_hasbbox", - # Raster functions - "AddRasterConstraints", "DropRasterConstraints", "AddOverviewConstraints", "DropOverviewConstraints", - "PostGIS_GDAL_Version", "PostGIS_Raster_Lib_Build_Date", "PostGIS_Raster_Lib_Version", "ST_GDALDrivers", - "UpdateRasterSRID", "ST_CreateOverview", "ST_AddBand", "ST_AsRaster", "ST_Band", "ST_MakeEmptyCoverage", - "ST_MakeEmptyRaster", "ST_Tile", "ST_Retile", "ST_FromGDALRaster", "ST_GeoReference", "ST_Height", - "ST_IsEmpty", "ST_MemSize", "ST_MetaData", "ST_NumBands", "ST_PixelHeight", "ST_PixelWidth", "ST_ScaleX", - "ST_ScaleY", "ST_RasterToWorldCoord", "ST_RasterToWorldCoordX", "ST_RasterToWorldCoordY", "ST_Rotation", - "ST_SkewX", "ST_SkewY", "ST_SRID", "ST_Summary", "ST_UpperLeftX", "ST_UpperLeftY", "ST_Width", - "ST_WorldToRasterCoord", "ST_WorldToRasterCoordX", "ST_WorldToRasterCoordY", "ST_BandMetaData", - "ST_BandNoDataValue", "ST_BandIsNoData", "ST_BandPath", "ST_BandFileSize", "ST_BandFileTimestamp", - "ST_BandPixelType", "ST_MinPossibleValue", "ST_HasNoBand", "ST_PixelAsPolygon", "ST_PixelAsPolygons", - "ST_PixelAsPoint", "ST_PixelAsPoints", "ST_PixelAsCentroid", "ST_PixelAsCentroids", "ST_Value", - "ST_NearestValue", "ST_Neighborhood", "ST_SetValue", "ST_SetValues", "ST_DumpValues", "ST_PixelOfValue", - "ST_SetGeoReference", "ST_SetRotation", "ST_SetScale", "ST_SetSkew", "ST_SetSRID", "ST_SetUpperLeft", - "ST_Resample", "ST_Rescale", "ST_Reskew", "ST_SnapToGrid", "ST_Resize", "ST_Transform", - "ST_SetBandNoDataValue", "ST_SetBandIsNoData", "ST_SetBandPath", "ST_SetBandIndex", "ST_Count", - "ST_CountAgg", "ST_Histogram", "ST_Quantile", "ST_SummaryStats", "ST_SummaryStatsAgg", "ST_ValueCount", - "ST_RastFromWKB", "ST_RastFromHexWKB", "ST_AsBinary", "ST_AsWKB", "ST_AsHexWKB", "ST_AsGDALRaster", - "ST_AsJPEG", "ST_AsPNG", "ST_AsTIFF", "ST_Clip", "ST_ColorMap", "ST_Grayscale", "ST_Intersection", - "ST_MapAlgebra", "ST_MapAlgebraExpr", "ST_MapAlgebraFct", "ST_MapAlgebraFctNgb", "ST_Reclass", "ST_Union", - "ST_Distinct4ma", "ST_InvDistWeight4ma", "ST_Max4ma", "ST_Mean4ma", "ST_Min4ma", "ST_MinDist4ma", - "ST_Range4ma", "ST_StdDev4ma", "ST_Sum4ma", "ST_Aspect", "ST_HillShade", "ST_Roughness", "ST_Slope", - "ST_TPI", "ST_TRI", + # 7.1. PostgreSQL PostGIS Types + "*box2d", + "*box3d", + "*box3d_extent", + "*geometry", + "*geometry_dump", + "*geography", + # 7.2. Management Functions + "*addgeometrycolumn", + "*dropgeometrycolumn", + "*dropgeometrytable", + "*postgis_full_version", + "*postgis_geos_version", + "*postgis_libxml_version", + "*postgis_lib_build_date", + "*postgis_lib_version", + "*postgis_proj_version", + "*postgis_scripts_build_date", + "*postgis_scripts_installed", + "*postgis_scripts_released", + "*postgis_uses_stats", + "*postgis_version", + "*populate_geometry_columns", + "*probe_geometry_columns", + "*updategeometrysrid", + # 7.3. Geometry Constructors + "*ST_bdpolyfromtext", + "*ST_bdmpolyfromtext", + "*ST_geogfromtext", + "*ST_geographyfromtext", + "*ST_geogfromwkb", + "*ST_geomcollfromtext", + "*ST_geomfromewkb", + "*ST_geomfromewkt", + "*ST_geometryfromtext", + "*ST_geomfromgml", + "*ST_geomfromkml", + "*ST_gmltosql", + "*ST_geomfromtext", + "*ST_geomfromwkb", + "*ST_linefrommultipoint", + "*ST_linefromtext", + "*ST_linefromwkb", + "*ST_linestringfromwkb", + "*ST_makebox2d", + "*ST_makebox3d", + "ST_MakeLine", + "*ST_makeenvelope", + "ST_MakePolygon", + "ST_MakePoint", + "ST_MakePointM", + "*ST_MLinefromtext", + "*ST_mpointfromtext", + "*ST_mpolyfromtext", + "ST_Point", + "*ST_pointfromtext", + "*ST_pointfromwkb", + "ST_Polygon", + "*ST_polygonfromtext", + "*ST_wkbtosql", + "*ST_wkttosql", + # 7.4. Geometry Accessors + "GeometryType", + "ST_Boundary", + "*ST_coorddim", + "ST_Dimension", + "ST_EndPoint", + "ST_Envelope", + "ST_ExteriorRing", + "ST_GeometryN", + "ST_GeometryType", + "ST_InteriorRingN", + "ST_isClosed", + "ST_isEmpty", + "ST_isRing", + "ST_isSimple", + "ST_isValid", + "ST_isValidReason", + "ST_M", + "ST_NDims", + "ST_NPoints", + "ST_NRings", + "ST_NumGeometries", + "ST_NumInteriorrings", + "ST_NumInteriorring", + "ST_NumPoints", + "ST_PointN", + "ST_Srid", + "ST_StartPoint", + "ST_Summary", + "ST_X", + "ST_Y", + "ST_Z", + "*ST_zmflag", + # 7.5. Geometry Editors + "ST_AddPoint", + "ST_Affine", + "ST_Force2D", + "*ST_Force3D", + "*ST_Force3dZ", + "*ST_Force3DM", + "*ST_Force_4d", + "*ST_force_collection", + "*ST_forcerhr", + "*ST_linemerge", + "*ST_collectionextract", + "ST_Multi", + "*ST_removepoint", + "*ST_reverse", + "*ST_rotate", + "*ST_rotatex", + "*ST_rotatey", + "*ST_rotatez", + "*ST_scale", + "*ST_segmentize", + "*ST_setpoint", + "ST_SetSrid", + "ST_SnapToGrid", + "ST_Transform", + "ST_Translate", + "*ST_transscale", + # 7.6. Geometry Outputs + "*ST_asbinary", + "*ST_asewkb", + "*ST_asewkt", + "*ST_asgeojson", + "*ST_asgml", + "*ST_ashexewkb", + "*ST_askml", + "*ST_assvg", + "*ST_geohash", + "ST_Astext", + # 7.7. Operators + # 7.8. Spatial Relationships and Measurements + "ST_Area", + "ST_Azimuth", + "ST_Centroid", + "ST_ClosestPoint", + "ST_Contains", + "ST_ContainsProperly", + "ST_Covers", + "ST_CoveredBy", + "ST_Crosses", + "*ST_linecrossingdirection", + "ST_Cisjoint", + "ST_Distance", + "*ST_hausdorffdistance", + "*ST_maxdistance", + "ST_Distance_Sphere", + "ST_Distance_Spheroid", + "*ST_DFullyWithin", + "ST_DWithin", + "ST_Equals", + "*ST_hasarc", + "ST_Intersects", + "ST_Length", + "*ST_Length2d", + "*ST_length3d", + "ST_Length_Spheroid", + "*ST_length2d_spheroid", + "*ST_length3d_spheroid", + "*ST_longestline", + "*ST_orderingequals", + "ST_Overlaps", + "*ST_perimeter", + "*ST_perimeter2d", + "*ST_perimeter3d", + "ST_PointOnSurface", + "ST_Relate", + "ST_ShortestLine", + "ST_Touches", + "ST_Within", + # 7.9. Geometry Processing Functions + "ST_Buffer", + "ST_BuildArea", + "ST_Collect", + "ST_ConvexHull", + "*ST_curvetoline", + "ST_Difference", + "ST_Dump", + "*ST_dumppoints", + "*ST_dumprings", + "ST_Intersection", + "*ST_linetocurve", + "*ST_memunion", + "*ST_minimumboundingcircle", + "*ST_polygonize", + "*ST_shift_longitude", + "ST_Simplify", + "ST_SimplifyPreserveTopology", + "ST_SymDifference", + "ST_Union", + # 7.10. Linear Referencing + "ST_Line_Interpolate_Point", + "ST_Line_Locate_Point", + "ST_Line_Substring", + "*ST_locate_along_measure", + "*ST_locate_between_measures", + "*ST_locatebetweenelevations", + "*ST_addmeasure", + # 7.11. Long Transactions Support + "*addauth", + "*checkauth", + "*disablelongtransactions", + "*enablelongtransactions", + "*lockrow", + "*unlockrows", + # 7.12. Miscellaneous Functions + "*ST_accum", + "*box2d", + "*box3d", + "*ST_estimated_extent", + "*ST_expand", + "ST_Extent", + "*ST_extent3d", + "*find_srid", + "*ST_mem_size", + "*ST_point_inside_circle", + "ST_XMax", + "ST_XMin", + "ST_YMax", + "ST_YMin", + "ST_ZMax", + "ST_ZMin", + # 7.13. Exceptional Functions + "*postgis_addbbox", + "*postgis_dropbbox", + "*postgis_hasbbox", + # Raster functions + "AddRasterConstraints", + "DropRasterConstraints", + "AddOverviewConstraints", + "DropOverviewConstraints", + "PostGIS_GDAL_Version", + "PostGIS_Raster_Lib_Build_Date", + "PostGIS_Raster_Lib_Version", + "ST_GDALDrivers", + "UpdateRasterSRID", + "ST_CreateOverview", + "ST_AddBand", + "ST_AsRaster", + "ST_Band", + "ST_MakeEmptyCoverage", + "ST_MakeEmptyRaster", + "ST_Tile", + "ST_Retile", + "ST_FromGDALRaster", + "ST_GeoReference", + "ST_Height", + "ST_IsEmpty", + "ST_MemSize", + "ST_MetaData", + "ST_NumBands", + "ST_PixelHeight", + "ST_PixelWidth", + "ST_ScaleX", + "ST_ScaleY", + "ST_RasterToWorldCoord", + "ST_RasterToWorldCoordX", + "ST_RasterToWorldCoordY", + "ST_Rotation", + "ST_SkewX", + "ST_SkewY", + "ST_SRID", + "ST_Summary", + "ST_UpperLeftX", + "ST_UpperLeftY", + "ST_Width", + "ST_WorldToRasterCoord", + "ST_WorldToRasterCoordX", + "ST_WorldToRasterCoordY", + "ST_BandMetaData", + "ST_BandNoDataValue", + "ST_BandIsNoData", + "ST_BandPath", + "ST_BandFileSize", + "ST_BandFileTimestamp", + "ST_BandPixelType", + "ST_MinPossibleValue", + "ST_HasNoBand", + "ST_PixelAsPolygon", + "ST_PixelAsPolygons", + "ST_PixelAsPoint", + "ST_PixelAsPoints", + "ST_PixelAsCentroid", + "ST_PixelAsCentroids", + "ST_Value", + "ST_NearestValue", + "ST_Neighborhood", + "ST_SetValue", + "ST_SetValues", + "ST_DumpValues", + "ST_PixelOfValue", + "ST_SetGeoReference", + "ST_SetRotation", + "ST_SetScale", + "ST_SetSkew", + "ST_SetSRID", + "ST_SetUpperLeft", + "ST_Resample", + "ST_Rescale", + "ST_Reskew", + "ST_SnapToGrid", + "ST_Resize", + "ST_Transform", + "ST_SetBandNoDataValue", + "ST_SetBandIsNoData", + "ST_SetBandPath", + "ST_SetBandIndex", + "ST_Count", + "ST_CountAgg", + "ST_Histogram", + "ST_Quantile", + "ST_SummaryStats", + "ST_SummaryStatsAgg", + "ST_ValueCount", + "ST_RastFromWKB", + "ST_RastFromHexWKB", + "ST_AsBinary", + "ST_AsWKB", + "ST_AsHexWKB", + "ST_AsGDALRaster", + "ST_AsJPEG", + "ST_AsPNG", + "ST_AsTIFF", + "ST_Clip", + "ST_ColorMap", + "ST_Grayscale", + "ST_Intersection", + "ST_MapAlgebra", + "ST_MapAlgebraExpr", + "ST_MapAlgebraFct", + "ST_MapAlgebraFctNgb", + "ST_Reclass", + "ST_Union", + "ST_Distinct4ma", + "ST_InvDistWeight4ma", + "ST_Max4ma", + "ST_Mean4ma", + "ST_Min4ma", + "ST_MinDist4ma", + "ST_Range4ma", + "ST_StdDev4ma", + "ST_Sum4ma", + "ST_Aspect", + "ST_HillShade", + "ST_Roughness", + "ST_Slope", + "ST_TPI", + "ST_TRI", ] # constants @@ -203,7 +873,7 @@ def getSqlDictionary(spatial=True): def strip_star(s): - if s[0] == '*': + if s[0] == "*": return s.lower()[1:] else: return s.lower() @@ -215,13 +885,17 @@ def strip_star(s): f += postgis_functions c += postgis_constants - return {'keyword': list(map(strip_star, k)), 'constant': list(map(strip_star, c)), 'function': list(map(strip_star, f))} + return { + "keyword": list(map(strip_star, k)), + "constant": list(map(strip_star, c)), + "function": list(map(strip_star, f)), + } def getQueryBuilderDictionary(): # concat functions def ff(l): - return [s for s in l if s[0] != '*'] + return [s for s in l if s[0] != "*"] def add_paren(l): return [s + "(" for s in l] @@ -231,4 +905,4 @@ def add_paren(l): agg = sorted(add_paren(ff(aggregate_functions))) op = ff(operators) s = sorted(add_paren(ff(string_functions))) - return {'function': foo, 'math': m, 'aggregate': agg, 'operator': op, 'string': s} + return {"function": foo, "math": m, "aggregate": agg, "operator": op, "string": s} diff --git a/python/plugins/db_manager/db_plugins/spatialite/connector.py b/python/plugins/db_manager/db_plugins/spatialite/connector.py index 3956f52e8015..ca1b9732fe48 100644 --- a/python/plugins/db_manager/db_plugins/spatialite/connector.py +++ b/python/plugins/db_manager/db_plugins/spatialite/connector.py @@ -42,7 +42,11 @@ def __init__(self, uri): self.dbname = uri.database() if not QFile.exists(self.dbname): - raise ConnectionError(QApplication.translate("DBManagerPlugin", '"{0}" not found').format(self.dbname)) + raise ConnectionError( + QApplication.translate("DBManagerPlugin", '"{0}" not found').format( + self.dbname + ) + ) try: self.connection = spatialite_connect(self._connectionInfo()) @@ -85,12 +89,12 @@ def isValidDatabase(self, path): return isValid def _checkSpatial(self): - """ check if it's a valid SpatiaLite db """ + """check if it's a valid SpatiaLite db""" self.has_spatial = self._checkGeometryColumnsTable() return self.has_spatial def _checkRaster(self): - """ check if it's a rasterite db """ + """check if it's a rasterite db""" self.has_raster = self._checkRasterTables() return self.has_raster @@ -121,17 +125,19 @@ def getInfo(self): return c.fetchone() def getSpatialInfo(self): - """ returns tuple about SpatiaLite support: - - lib version - - geos version - - proj version + """returns tuple about SpatiaLite support: + - lib version + - geos version + - proj version """ if not self.has_spatial: return c = self._get_cursor() try: - self._execute(c, "SELECT spatialite_version(), geos_version(), proj4_version()") + self._execute( + c, "SELECT spatialite_version(), geos_version(), proj4_version()" + ) except DbError: return @@ -154,17 +160,26 @@ def hasCreateSpatialViewSupport(self): def fieldTypes(self): return [ - "integer", "bigint", "smallint", # integers - "real", "double", "float", "numeric", # floats - "varchar", "varchar(255)", "character(20)", "text", # strings - "date", "datetime" # date/time + "integer", + "bigint", + "smallint", # integers + "real", + "double", + "float", + "numeric", # floats + "varchar", + "varchar(255)", + "character(20)", + "text", # strings + "date", + "datetime", # date/time ] def getSchemas(self): return None def getTables(self, schema=None, add_sys_tables=False): - """ get list of tables """ + """get list of tables""" tablenames = [] items = [] @@ -197,16 +212,16 @@ def getTables(self, schema=None, add_sys_tables=False): sql = "SELECT f_table_name, f_geometry_column FROM geometry_columns WHERE spatial_index_enabled = 1" self._execute(c, sql) for idx_item in c.fetchall(): - sys_tables.append('idx_%s_%s' % idx_item) - sys_tables.append('idx_%s_%s_node' % idx_item) - sys_tables.append('idx_%s_%s_parent' % idx_item) - sys_tables.append('idx_%s_%s_rowid' % idx_item) + sys_tables.append("idx_%s_%s" % idx_item) + sys_tables.append("idx_%s_%s_node" % idx_item) + sys_tables.append("idx_%s_%s_parent" % idx_item) + sys_tables.append("idx_%s_%s_rowid" % idx_item) sql = "SELECT name, type = 'view' FROM sqlite_master WHERE type IN ('table', 'view')" self._execute(c, sql) for tbl in c.fetchall(): - if tablenames.count(tbl[0]) <= 0 and not tbl[0].startswith('idx_'): + if tablenames.count(tbl[0]) <= 0 and not tbl[0].startswith("idx_"): if not add_sys_tables and tbl[0] in sys_tables: continue item = list(tbl) @@ -219,16 +234,16 @@ def getTables(self, schema=None, add_sys_tables=False): return sorted(items, key=cmp_to_key(lambda x, y: (x[1] > y[1]) - (x[1] < y[1]))) def getVectorTables(self, schema=None): - """ get list of table with a geometry column - it returns: - name (table name) - type = 'view' (is a view?) - geometry_column: - f_table_name (the table name in geometry_columns may be in a wrong case, use this to load the layer) - f_geometry_column - type - coord_dimension - srid + """get list of table with a geometry column + it returns: + name (table name) + type = 'view' (is a view?) + geometry_column: + f_table_name (the table name in geometry_columns may be in a wrong case, use this to load the layer) + f_geometry_column + type + coord_dimension + srid """ if self.has_geometry_columns: @@ -253,10 +268,13 @@ def getVectorTables(self, schema=None): cols = "g.type,g.coord_dimension" # get geometry info from geometry_columns if exists - sql = """SELECT m.name, m.type = 'view', g.f_table_name, g.f_geometry_column, %s, g.srid + sql = ( + """SELECT m.name, m.type = 'view', g.f_table_name, g.f_geometry_column, %s, g.srid FROM sqlite_master AS m JOIN geometry_columns AS g ON upper(m.name) = upper(g.f_table_name) WHERE m.type in ('table', 'view') - ORDER BY m.name, g.f_geometry_column""" % cols + ORDER BY m.name, g.f_geometry_column""" + % cols + ) else: return [] @@ -273,14 +291,14 @@ def getVectorTables(self, schema=None): return items def getRasterTables(self, schema=None): - """ get list of table with a geometry column - it returns: - name (table name) - type = 'view' (is a view?) - geometry_column: - r.table_name (the prefix table name, use this to load the layer) - r.geometry_column - srid + """get list of table with a geometry column + it returns: + name (table name) + type = 'view' (is a view?) + geometry_column: + r.table_name (the prefix table name, use this to load the layer) + r.geometry_column + srid """ if not self.has_geometry_columns: @@ -314,14 +332,14 @@ def getTableRowCount(self, table): return ret[0] if ret is not None else None def getTableFields(self, table): - """ return list of columns in table """ + """return list of columns in table""" c = self._get_cursor() sql = "PRAGMA table_info(%s)" % (self.quoteId(table)) self._execute(c, sql) return c.fetchall() def getTableIndexes(self, table): - """ get info about table's indexes """ + """get info about table's indexes""" c = self._get_cursor() sql = "PRAGMA index_list(%s)" % (self.quoteId(table)) self._execute(c, sql) @@ -340,10 +358,7 @@ def getTableIndexes(self, table): self._execute(c, sql) idx = [num, name, unique] - cols = [ - cid - for seq, cid, cname in c.fetchall() - ] + cols = [cid for seq, cid, cname in c.fetchall()] idx.append(cols) indexes[i] = idx @@ -355,41 +370,50 @@ def getTableConstraints(self, table): def getTableTriggers(self, table): c = self._get_cursor() schema, tablename = self.getSchemaTableName(table) - sql = "SELECT name, sql FROM sqlite_master WHERE tbl_name = %s AND type = 'trigger'" % ( - self.quoteString(tablename)) + sql = ( + "SELECT name, sql FROM sqlite_master WHERE tbl_name = %s AND type = 'trigger'" + % (self.quoteString(tablename)) + ) self._execute(c, sql) return c.fetchall() def deleteTableTrigger(self, trigger, table=None): - """Deletes trigger """ + """Deletes trigger""" sql = "DROP TRIGGER %s" % self.quoteId(trigger) self._execute_and_commit(sql) def getTableExtent(self, table, geom): - """ find out table extent """ + """find out table extent""" schema, tablename = self.getSchemaTableName(table) c = self._get_cursor() if self.isRasterTable(table): - tablename = tablename.replace('_rasters', '_metadata') - geom = 'geometry' + tablename = tablename.replace("_rasters", "_metadata") + geom = "geometry" - sql = """SELECT Min(MbrMinX(%(geom)s)), Min(MbrMinY(%(geom)s)), Max(MbrMaxX(%(geom)s)), Max(MbrMaxY(%(geom)s)) - FROM %(table)s """ % {'geom': self.quoteId(geom), - 'table': self.quoteId(tablename)} + sql = """SELECT Min(MbrMinX({geom})), Min(MbrMinY({geom})), Max(MbrMaxX({geom})), Max(MbrMaxY({geom})) + FROM {table} """.format( + geom=self.quoteId(geom), table=self.quoteId(tablename) + ) self._execute(c, sql) return c.fetchone() def getViewDefinition(self, view): - """ returns definition of the view """ + """returns definition of the view""" schema, tablename = self.getSchemaTableName(view) - sql = "SELECT sql FROM sqlite_master WHERE type = 'view' AND name = %s" % self.quoteString(tablename) + sql = ( + "SELECT sql FROM sqlite_master WHERE type = 'view' AND name = %s" + % self.quoteString(tablename) + ) c = self._execute(None, sql) ret = c.fetchone() return ret[0] if ret is not None else None def getSpatialRefInfo(self, srid): - sql = "SELECT ref_sys_name FROM spatial_ref_sys WHERE srid = %s" % self.quoteString(srid) + sql = ( + "SELECT ref_sys_name FROM spatial_ref_sys WHERE srid = %s" + % self.quoteString(srid) + ) c = self._execute(None, sql) ret = c.fetchone() return ret[0] if ret is not None else None @@ -397,8 +421,10 @@ def getSpatialRefInfo(self, srid): def isVectorTable(self, table): if self.has_geometry_columns: schema, tablename = self.getSchemaTableName(table) - sql = "SELECT count(*) FROM geometry_columns WHERE upper(f_table_name) = upper(%s)" % self.quoteString( - tablename) + sql = ( + "SELECT count(*) FROM geometry_columns WHERE upper(f_table_name) = upper(%s)" + % self.quoteString(tablename) + ) c = self._execute(None, sql) ret = c.fetchone() return ret is not None and ret[0] > 0 @@ -414,7 +440,8 @@ def isRasterTable(self, table): FROM layer_params AS r JOIN geometry_columns AS g ON upper(r.table_name||'_metadata') = upper(g.f_table_name) WHERE upper(r.table_name) = upper(REPLACE(%s, '_rasters', ''))""" % self.quoteString( - tablename) + tablename + ) c = self._execute(None, sql) ret = c.fetchone() return ret is not None and ret[0] > 0 @@ -423,8 +450,8 @@ def isRasterTable(self, table): def createTable(self, table, field_defs, pkey): """Creates ordinary table - 'fields' is array containing field definitions - 'pkey' is the primary key name + 'fields' is array containing field definitions + 'pkey' is the primary key name """ if len(field_defs) == 0: return False @@ -439,7 +466,7 @@ def createTable(self, table, field_defs, pkey): return True def deleteTable(self, table): - """Deletes table from the database """ + """Deletes table from the database""" if self.isRasterTable(table): return False @@ -447,14 +474,17 @@ def deleteTable(self, table): sql = "DROP TABLE %s" % self.quoteId(table) self._execute(c, sql) schema, tablename = self.getSchemaTableName(table) - sql = "DELETE FROM geometry_columns WHERE upper(f_table_name) = upper(%s)" % self.quoteString(tablename) + sql = ( + "DELETE FROM geometry_columns WHERE upper(f_table_name) = upper(%s)" + % self.quoteString(tablename) + ) self._execute(c, sql) self._commit() return True def emptyTable(self, table): - """Deletes all rows from table """ + """Deletes all rows from table""" if self.isRasterTable(table): return False @@ -462,7 +492,7 @@ def emptyTable(self, table): self._execute_and_commit(sql) def renameTable(self, table, new_table): - """ rename a table """ + """rename a table""" schema, tablename = self.getSchemaTableName(table) if new_table == tablename: return @@ -472,13 +502,16 @@ def renameTable(self, table, new_table): c = self._get_cursor() - sql = "ALTER TABLE %s RENAME TO %s" % (self.quoteId(table), self.quoteId(new_table)) + sql = "ALTER TABLE {} RENAME TO {}".format( + self.quoteId(table), self.quoteId(new_table) + ) self._execute(c, sql) # update geometry_columns if self.has_geometry_columns: - sql = "UPDATE geometry_columns SET f_table_name = %s WHERE upper(f_table_name) = upper(%s)" % ( - self.quoteString(new_table), self.quoteString(tablename)) + sql = "UPDATE geometry_columns SET f_table_name = {} WHERE upper(f_table_name) = upper({})".format( + self.quoteString(new_table), self.quoteString(tablename) + ) self._execute(c, sql) self._commit() @@ -488,7 +521,7 @@ def moveTable(self, table, new_table, new_schema=None): return self.renameTable(table, new_table) def createView(self, view, query): - sql = "CREATE VIEW %s AS %s" % (self.quoteId(view), query) + sql = f"CREATE VIEW {self.quoteId(view)} AS {query}" self._execute_and_commit(sql) def deleteView(self, view): @@ -499,13 +532,16 @@ def deleteView(self, view): # update geometry_columns if self.has_geometry_columns: - sql = "DELETE FROM geometry_columns WHERE f_table_name = %s" % self.quoteString(view) + sql = ( + "DELETE FROM geometry_columns WHERE f_table_name = %s" + % self.quoteString(view) + ) self._execute(c, sql) self._commit() def renameView(self, view, new_name): - """ rename view """ + """rename view""" return self.renameTable(view, new_name) def createSpatialView(self, view, query): @@ -516,50 +552,67 @@ def createSpatialView(self, view, query): c = self._execute(None, sql) geom_col = None for r in c.fetchall(): - if r[2].upper() in ('POINT', 'LINESTRING', 'POLYGON', - 'MULTIPOINT', 'MULTILINESTRING', 'MULTIPOLYGON'): + if r[2].upper() in ( + "POINT", + "LINESTRING", + "POLYGON", + "MULTIPOINT", + "MULTILINESTRING", + "MULTIPOLYGON", + ): geom_col = r[1] break if geom_col is None: return # get geometry type and srid - sql = "SELECT geometrytype(%s), srid(%s) FROM %s LIMIT 1" % (self.quoteId(geom_col), self.quoteId(geom_col), self.quoteId(view)) + sql = "SELECT geometrytype({}), srid({}) FROM {} LIMIT 1".format( + self.quoteId(geom_col), self.quoteId(geom_col), self.quoteId(view) + ) c = self._execute(None, sql) r = c.fetchone() if r is None: return gtype, gsrid = r - gdim = 'XY' - if ' ' in gtype: - zm = gtype.split(' ')[1] - gtype = gtype.split(' ')[0] + gdim = "XY" + if " " in gtype: + zm = gtype.split(" ")[1] + gtype = gtype.split(" ")[0] gdim += zm try: - wkbType = ('POINT', 'LINESTRING', 'POLYGON', 'MULTIPOINT', 'MULTILINESTRING', 'MULTIPOLYGON').index(gtype) + 1 + wkbType = ( + "POINT", + "LINESTRING", + "POLYGON", + "MULTIPOINT", + "MULTILINESTRING", + "MULTIPOLYGON", + ).index(gtype) + 1 except: wkbType = 0 - if 'Z' in gdim: + if "Z" in gdim: wkbType += 1000 - if 'M' in gdim: + if "M" in gdim: wkbType += 2000 sql = """INSERT INTO geometry_columns (f_table_name, f_geometry_column, geometry_type, coord_dimension, srid, spatial_index_enabled) - VALUES (%s, %s, %s, %s, %s, 0)""" % (self.quoteId(view), self.quoteId(geom_col), wkbType, len(gdim), gsrid) + VALUES ({}, {}, {}, {}, {}, 0)""".format( + self.quoteId(view), self.quoteId(geom_col), wkbType, len(gdim), gsrid + ) self._execute_and_commit(sql) def runVacuum(self): - """ run vacuum on the db """ + """run vacuum on the db""" # Workaround http://bugs.python.org/issue28518 self.connection.isolation_level = None c = self._get_cursor() - c.execute('VACUUM') - self.connection.isolation_level = '' # reset to default isolation + c.execute("VACUUM") + self.connection.isolation_level = "" # reset to default isolation def addTableColumn(self, table, field_def): - """Adds a column to table """ - sql = "ALTER TABLE %s ADD %s" % (self.quoteId(table), field_def) + """Adds a column to table""" + sql = f"ALTER TABLE {self.quoteId(table)} ADD {field_def}" self._execute(None, sql) sql = "SELECT InvalidateLayerStatistics(%s)" % (self.quoteId(table)) @@ -572,71 +625,93 @@ def addTableColumn(self, table, field_def): return True def deleteTableColumn(self, table, column): - """Deletes column from a table """ + """Deletes column from a table""" if not self.isGeometryColumn(table, column): return False # column editing not supported # delete geometry column correctly schema, tablename = self.getSchemaTableName(table) - sql = "SELECT DiscardGeometryColumn(%s, %s)" % (self.quoteString(tablename), self.quoteString(column)) + sql = "SELECT DiscardGeometryColumn({}, {})".format( + self.quoteString(tablename), self.quoteString(column) + ) self._execute_and_commit(sql) - def updateTableColumn(self, table, column, new_name, new_data_type=None, new_not_null=None, new_default=None, comment=None): + def updateTableColumn( + self, + table, + column, + new_name, + new_data_type=None, + new_not_null=None, + new_default=None, + comment=None, + ): return False # column editing not supported def renameTableColumn(self, table, column, new_name): - """ rename column in a table """ + """rename column in a table""" return False # column editing not supported def setColumnType(self, table, column, data_type): - """Changes column type """ + """Changes column type""" return False # column editing not supported def setColumnDefault(self, table, column, default): - """Changes column's default value. If default=None drop default value """ + """Changes column's default value. If default=None drop default value""" return False # column editing not supported def setColumnNull(self, table, column, is_null): - """Changes whether column can contain null values """ + """Changes whether column can contain null values""" return False # column editing not supported def isGeometryColumn(self, table, column): c = self._get_cursor() schema, tablename = self.getSchemaTableName(table) - sql = "SELECT count(*) > 0 FROM geometry_columns WHERE upper(f_table_name) = upper(%s) AND upper(f_geometry_column) = upper(%s)" % ( - self.quoteString(tablename), self.quoteString(column)) + sql = "SELECT count(*) > 0 FROM geometry_columns WHERE upper(f_table_name) = upper({}) AND upper(f_geometry_column) = upper({})".format( + self.quoteString(tablename), self.quoteString(column) + ) self._execute(c, sql) - return c.fetchone()[0] == 't' + return c.fetchone()[0] == "t" - def addGeometryColumn(self, table, geom_column='geometry', geom_type='POINT', srid=-1, dim=2): + def addGeometryColumn( + self, table, geom_column="geometry", geom_type="POINT", srid=-1, dim=2 + ): schema, tablename = self.getSchemaTableName(table) sql = "SELECT AddGeometryColumn(%s, %s, %d, %s, %s)" % ( - self.quoteString(tablename), self.quoteString(geom_column), srid, self.quoteString(geom_type), dim) + self.quoteString(tablename), + self.quoteString(geom_column), + srid, + self.quoteString(geom_type), + dim, + ) self._execute_and_commit(sql) def deleteGeometryColumn(self, table, geom_column): return self.deleteTableColumn(table, geom_column) def addTableUniqueConstraint(self, table, column): - """Adds a unique constraint to a table """ + """Adds a unique constraint to a table""" return False # constraints not supported def deleteTableConstraint(self, table, constraint): - """Deletes constraint in a table """ + """Deletes constraint in a table""" return False # constraints not supported def addTablePrimaryKey(self, table, column): - """Adds a primery key (with one column) to a table """ - sql = "ALTER TABLE %s ADD PRIMARY KEY (%s)" % (self.quoteId(table), self.quoteId(column)) + """Adds a primery key (with one column) to a table""" + sql = "ALTER TABLE {} ADD PRIMARY KEY ({})".format( + self.quoteId(table), self.quoteId(column) + ) self._execute_and_commit(sql) def createTableIndex(self, table, name, column, unique=False): - """Creates index on one column using default options """ + """Creates index on one column using default options""" unique_str = "UNIQUE" if unique else "" - sql = "CREATE %s INDEX %s ON %s (%s)" % ( - unique_str, self.quoteId(name), self.quoteId(table), self.quoteId(column)) + sql = "CREATE {} INDEX {} ON {} ({})".format( + unique_str, self.quoteId(name), self.quoteId(table), self.quoteId(column) + ) self._execute_and_commit(sql) def deleteTableIndex(self, table, name): @@ -644,36 +719,43 @@ def deleteTableIndex(self, table, name): sql = "DROP INDEX %s" % self.quoteId((schema, name)) self._execute_and_commit(sql) - def createSpatialIndex(self, table, geom_column='geometry'): + def createSpatialIndex(self, table, geom_column="geometry"): if self.isRasterTable(table): return False schema, tablename = self.getSchemaTableName(table) - sql = "SELECT CreateSpatialIndex(%s, %s)" % (self.quoteString(tablename), self.quoteString(geom_column)) + sql = "SELECT CreateSpatialIndex({}, {})".format( + self.quoteString(tablename), self.quoteString(geom_column) + ) self._execute_and_commit(sql) - def deleteSpatialIndex(self, table, geom_column='geometry'): + def deleteSpatialIndex(self, table, geom_column="geometry"): if self.isRasterTable(table): return False schema, tablename = self.getSchemaTableName(table) try: - sql = "SELECT DiscardSpatialIndex(%s, %s)" % (self.quoteString(tablename), self.quoteString(geom_column)) + sql = "SELECT DiscardSpatialIndex({}, {})".format( + self.quoteString(tablename), self.quoteString(geom_column) + ) self._execute_and_commit(sql) except DbError: - sql = "SELECT DeleteSpatialIndex(%s, %s)" % (self.quoteString(tablename), self.quoteString(geom_column)) + sql = "SELECT DeleteSpatialIndex({}, {})".format( + self.quoteString(tablename), self.quoteString(geom_column) + ) self._execute_and_commit(sql) # delete the index table - idx_table_name = "idx_%s_%s" % (tablename, geom_column) + idx_table_name = f"idx_{tablename}_{geom_column}" self.deleteTable(idx_table_name) - def hasSpatialIndex(self, table, geom_column='geometry'): + def hasSpatialIndex(self, table, geom_column="geometry"): if not self.has_geometry_columns or self.isRasterTable(table): return False c = self._get_cursor() schema, tablename = self.getSchemaTableName(table) - sql = "SELECT spatial_index_enabled FROM geometry_columns WHERE upper(f_table_name) = upper(%s) AND upper(f_geometry_column) = upper(%s)" % ( - self.quoteString(tablename), self.quoteString(geom_column)) + sql = "SELECT spatial_index_enabled FROM geometry_columns WHERE upper(f_table_name) = upper({}) AND upper(f_geometry_column) = upper({})".format( + self.quoteString(tablename), self.quoteString(geom_column) + ) self._execute(c, sql) row = c.fetchone() return row is not None and row[0] == 1 diff --git a/python/plugins/db_manager/db_plugins/spatialite/data_model.py b/python/plugins/db_manager/db_plugins/spatialite/data_model.py index ceaf0b2b8a14..4eb7b519ceab 100644 --- a/python/plugins/db_manager/db_plugins/spatialite/data_model.py +++ b/python/plugins/db_manager/db_plugins/spatialite/data_model.py @@ -20,10 +20,12 @@ from qgis.core import QgsMessageLog from ..plugin import BaseError -from ..data_model import (TableDataModel, - SqlResultModel, - SqlResultModelAsync, - SqlResultModelTask) +from ..data_model import ( + TableDataModel, + SqlResultModel, + SqlResultModelAsync, + SqlResultModelTask, +) from .plugin import SLDatabase @@ -36,7 +38,7 @@ def __init__(self, table, parent=None): table_txt = self.db.quoteId((self.table.schemaName(), self.table.name)) # run query and get results - sql = "SELECT %s FROM %s" % (fields_txt, table_txt) + sql = f"SELECT {fields_txt} FROM {table_txt}" c = self.db._get_cursor() self.db._execute(c, sql) @@ -57,7 +59,7 @@ def _sanitizeTableField(self, field): if dataType[-10:] == "COLLECTION": dataType = dataType[:-10] if dataType in ["POINT", "LINESTRING", "POLYGON", "GEOMETRY"]: - return 'GeometryType(%s)' % self.db.quoteId(field.name) + return "GeometryType(%s)" % self.db.quoteId(field.name) return self.db.quoteId(field.name) def rowCount(self, index=None): diff --git a/python/plugins/db_manager/db_plugins/spatialite/info_model.py b/python/plugins/db_manager/db_plugins/spatialite/info_model.py index c33314a5a053..4e326af51737 100644 --- a/python/plugins/db_manager/db_plugins/spatialite/info_model.py +++ b/python/plugins/db_manager/db_plugins/spatialite/info_model.py @@ -31,15 +31,16 @@ def __init__(self, db): def connectionDetails(self): tbl = [ - (QApplication.translate("DBManagerPlugin", "Filename:"), self.db.connector.dbname) + ( + QApplication.translate("DBManagerPlugin", "Filename:"), + self.db.connector.dbname, + ) ] return HtmlTable(tbl) def generalInfo(self): info = self.db.connector.getInfo() - tbl = [ - (QApplication.translate("DBManagerPlugin", "SQLite version:"), info[0]) - ] + tbl = [(QApplication.translate("DBManagerPlugin", "SQLite version:"), info[0])] return HtmlTable(tbl) def spatialInfo(self): @@ -52,14 +53,20 @@ def spatialInfo(self): tbl = [ (QApplication.translate("DBManagerPlugin", "Library:"), info[0]), ("GEOS:", info[1]), - ("Proj:", info[2]) + ("Proj:", info[2]), ] ret.append(HtmlTable(tbl)) if not self.db.connector.has_geometry_columns: - ret.append(HtmlParagraph( - QApplication.translate("DBManagerPlugin", " geometry_columns table doesn't exist!\n" - "This table is essential for many GIS applications for enumeration of tables."))) + ret.append( + HtmlParagraph( + QApplication.translate( + "DBManagerPlugin", + " geometry_columns table doesn't exist!\n" + "This table is essential for many GIS applications for enumeration of tables.", + ) + ) + ) return ret diff --git a/python/plugins/db_manager/db_plugins/spatialite/plugin.py b/python/plugins/db_manager/db_plugins/spatialite/plugin.py index f4a203755973..4cf7d90daf7d 100644 --- a/python/plugins/db_manager/db_plugins/spatialite/plugin.py +++ b/python/plugins/db_manager/db_plugins/spatialite/plugin.py @@ -27,8 +27,17 @@ from qgis.core import Qgis, QgsApplication, QgsDataSourceUri, QgsSettings from qgis.gui import QgsMessageBar -from ..plugin import DBPlugin, Database, Table, VectorTable, RasterTable, TableField, TableIndex, TableTrigger, \ - InvalidDataException +from ..plugin import ( + DBPlugin, + Database, + Table, + VectorTable, + RasterTable, + TableField, + TableIndex, + TableTrigger, + InvalidDataException, +) def classFactory(): @@ -43,19 +52,19 @@ def icon(self): @classmethod def typeName(self): - return 'spatialite' + return "spatialite" @classmethod def typeNameString(self): - return QCoreApplication.translate('db_manager', 'SpatiaLite') + return QCoreApplication.translate("db_manager", "SpatiaLite") @classmethod def providerName(self): - return 'spatialite' + return "spatialite" @classmethod def connectionSettingsKey(self): - return '/SpatiaLite/connections' + return "/SpatiaLite/connections" def databasesFactory(self, connection, uri): return SLDatabase(connection, uri) @@ -63,10 +72,14 @@ def databasesFactory(self, connection, uri): def connect(self, parent=None): conn_name = self.connectionName() settings = QgsSettings() - settings.beginGroup("/%s/%s" % (self.connectionSettingsKey(), conn_name)) + settings.beginGroup(f"/{self.connectionSettingsKey()}/{conn_name}") if not settings.contains("sqlitepath"): # non-existent entry? - raise InvalidDataException(self.tr('There is no defined database connection "{0}".').format(conn_name)) + raise InvalidDataException( + self.tr('There is no defined database connection "{0}".').format( + conn_name + ) + ) database = settings.value("sqlitepath") @@ -77,7 +90,7 @@ def connect(self, parent=None): @classmethod def addConnection(self, conn_name, uri): settings = QgsSettings() - settings.beginGroup("/%s/%s" % (self.connectionSettingsKey(), conn_name)) + settings.beginGroup(f"/{self.connectionSettingsKey()}/{conn_name}") settings.setValue("sqlitepath", uri.database()) return True @@ -85,7 +98,9 @@ def addConnection(self, conn_name, uri): def addConnectionActionSlot(self, item, action, parent, index): QApplication.restoreOverrideCursor() try: - filename, selected_filter = QFileDialog.getOpenFileName(parent, "Choose SQLite/SpatiaLite file") + filename, selected_filter = QFileDialog.getOpenFileName( + parent, "Choose SQLite/SpatiaLite file" + ) if not filename: return finally: @@ -132,7 +147,9 @@ def sqlResultModelAsync(self, sql, parent): def registerDatabaseActions(self, mainWindow): action = QAction(self.tr("Run &Vacuum"), self) - mainWindow.registerAction(action, self.tr("&Database"), self.runVacuumActionSlot) + mainWindow.registerAction( + action, self.tr("&Database"), self.runVacuumActionSlot + ) Database.registerDatabaseActions(self, mainWindow) @@ -140,8 +157,11 @@ def runVacuumActionSlot(self, item, action, parent): QApplication.restoreOverrideCursor() try: if not isinstance(item, (DBPlugin, Table)) or item.database() is None: - parent.infoBar.pushMessage(self.tr("No database selected or you are not connected to it."), - Qgis.MessageLevel.Info, parent.iface.messageTimeout()) + parent.infoBar.pushMessage( + self.tr("No database selected or you are not connected to it."), + Qgis.MessageLevel.Info, + parent.iface.messageTimeout(), + ) return finally: QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) @@ -170,7 +190,9 @@ def explicitSpatialIndex(self): return True def spatialIndexClause(self, src_table, src_column, dest_table, dest_column): - return """ "%s".ROWID IN (\nSELECT ROWID FROM SpatialIndex WHERE f_table_name='%s' AND search_frame="%s"."%s") """ % (src_table, src_table, dest_table, dest_column) + return """ "{}".ROWID IN (\nSELECT ROWID FROM SpatialIndex WHERE f_table_name='{}' AND search_frame="{}"."{}") """.format( + src_table, src_table, dest_table, dest_column + ) def supportsComment(self): return False @@ -183,7 +205,7 @@ def __init__(self, row, db, schema=None): self.name, self.isView, self.isSysTable = row def ogrUri(self): - ogrUri = "%s|layername=%s" % (self.uri().database(), self.name) + ogrUri = f"{self.uri().database()}|layername={self.name}" return ogrUri def mimeUri(self): @@ -220,16 +242,20 @@ def __init__(self, row, db, schema=None): # SpatiaLite does case-insensitive checks for table names, but the # SL provider didn't do the same in QGIS < 1.9, so self.geomTableName # stores the table name like stored in the geometry_columns table - self.geomTableName, self.geomColumn, self.geomType, self.geomDim, self.srid = row[-5:] + self.geomTableName, self.geomColumn, self.geomType, self.geomDim, self.srid = ( + row[-5:] + ) def uri(self): uri = self.database().uri() - uri.setDataSource('', self.geomTableName, self.geomColumn) + uri.setDataSource("", self.geomTableName, self.geomColumn) return uri def hasSpatialIndex(self, geom_column=None): geom_column = geom_column if geom_column is not None else self.geomColumn - return self.database().connector.hasSpatialIndex((self.schemaName(), self.name), geom_column) + return self.database().connector.hasSpatialIndex( + (self.schemaName(), self.name), geom_column + ) def createSpatialIndex(self, geom_column=None): self.aboutToChange.emit() @@ -260,19 +286,21 @@ def __init__(self, row, db, schema=None): SLTable.__init__(self, row[:-3], db, schema) RasterTable.__init__(self, db, schema) self.prefixName, self.geomColumn, self.srid = row[-3:] - self.geomType = 'RASTER' + self.geomType = "RASTER" # def info(self): # from .info_model import SLRasterTableInfo # return SLRasterTableInfo(self) def rasterliteGdalUri(self): - gdalUri = 'RASTERLITE:%s,table=%s' % (self.uri().database(), self.prefixName) + gdalUri = "RASTERLITE:{},table={}".format( + self.uri().database(), self.prefixName + ) return gdalUri def mimeUri(self): # QGIS has no provider to load rasters, let's use GDAL - uri = "raster:gdal:%s:%s" % (self.name, self.uri().database()) + uri = f"raster:gdal:{self.name}:{self.uri().database()}" return uri def toMapLayer(self, geometryType=None, crs=None): @@ -283,7 +311,9 @@ def toMapLayer(self, geometryType=None, crs=None): rl = QgsRasterLayer(uri, self.name) if rl.isValid(): - rl.setContrastEnhancement(QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum) + rl.setContrastEnhancement( + QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum + ) return rl @@ -291,7 +321,14 @@ class SLTableField(TableField): def __init__(self, row, table): TableField.__init__(self, table) - self.num, self.name, self.dataType, self.notNull, self.default, self.primaryKey = row + ( + self.num, + self.name, + self.dataType, + self.notNull, + self.default, + self.primaryKey, + ) = row self.hasDefault = self.default diff --git a/python/plugins/db_manager/db_plugins/spatialite/sql_dictionary.py b/python/plugins/db_manager/db_plugins/spatialite/sql_dictionary.py index 9fb8b253d109..8b2feb51feec 100644 --- a/python/plugins/db_manager/db_plugins/spatialite/sql_dictionary.py +++ b/python/plugins/db_manager/db_plugins/spatialite/sql_dictionary.py @@ -15,107 +15,347 @@ *************************************************************************** """ -__author__ = 'Giuseppe Sucameli' -__date__ = 'April 2012' -__copyright__ = '(C) 2012, Giuseppe Sucameli' +__author__ = "Giuseppe Sucameli" +__date__ = "April 2012" +__copyright__ = "(C) 2012, Giuseppe Sucameli" # keywords keywords = [ # TODO get them from a reference page - "action", "add", "after", "all", "alter", "analyze", "and", "as", "asc", - "before", "begin", "between", "by", "cascade", "case", "cast", "check", - "collate", "column", "commit", "constraint", "create", "cross", "current_date", - "current_time", "current_timestamp", "default", "deferrable", "deferred", - "delete", "desc", "distinct", "drop", "each", "else", "end", "escape", - "except", "exists", "for", "foreign", "from", "full", "group", "having", - "ignore", "immediate", "in", "initially", "inner", "insert", "intersect", - "into", "is", "isnull", "join", "key", "left", "like", "limit", "match", - "natural", "no", "not", "notnull", "null", "of", "offset", "on", "or", "order", - "outer", "primary", "references", "release", "restrict", "right", "rollback", - "row", "savepoint", "select", "set", "table", "temporary", "then", "to", - "transaction", "trigger", "union", "unique", "update", "using", "values", - "view", "when", "where", - - "abort", "attach", "autoincrement", "conflict", "database", "detach", - "exclusive", "explain", "fail", "glob", "if", "index", "indexed", "instead", - "plan", "pragma", "query", "raise", "regexp", "reindex", "rename", "replace", - "temp", "vacuum", "virtual" + "action", + "add", + "after", + "all", + "alter", + "analyze", + "and", + "as", + "asc", + "before", + "begin", + "between", + "by", + "cascade", + "case", + "cast", + "check", + "collate", + "column", + "commit", + "constraint", + "create", + "cross", + "current_date", + "current_time", + "current_timestamp", + "default", + "deferrable", + "deferred", + "delete", + "desc", + "distinct", + "drop", + "each", + "else", + "end", + "escape", + "except", + "exists", + "for", + "foreign", + "from", + "full", + "group", + "having", + "ignore", + "immediate", + "in", + "initially", + "inner", + "insert", + "intersect", + "into", + "is", + "isnull", + "join", + "key", + "left", + "like", + "limit", + "match", + "natural", + "no", + "not", + "notnull", + "null", + "of", + "offset", + "on", + "or", + "order", + "outer", + "primary", + "references", + "release", + "restrict", + "right", + "rollback", + "row", + "savepoint", + "select", + "set", + "table", + "temporary", + "then", + "to", + "transaction", + "trigger", + "union", + "unique", + "update", + "using", + "values", + "view", + "when", + "where", + "abort", + "attach", + "autoincrement", + "conflict", + "database", + "detach", + "exclusive", + "explain", + "fail", + "glob", + "if", + "index", + "indexed", + "instead", + "plan", + "pragma", + "query", + "raise", + "regexp", + "reindex", + "rename", + "replace", + "temp", + "vacuum", + "virtual", ] spatialite_keywords = [] # functions functions = [ # TODO get them from a reference page - "changes", "coalesce", "glob", "ifnull", "hex", "last_insert_rowid", - "nullif", "quote", "random", - "randomblob", "replace", "round", "soundex", "total_change", - "typeof", "zeroblob", "date", "datetime", "julianday", "strftime" + "changes", + "coalesce", + "glob", + "ifnull", + "hex", + "last_insert_rowid", + "nullif", + "quote", + "random", + "randomblob", + "replace", + "round", + "soundex", + "total_change", + "typeof", + "zeroblob", + "date", + "datetime", + "julianday", + "strftime", ] operators = [ - ' AND ', ' OR ', '||', ' < ', ' <= ', ' > ', ' >= ', ' = ', ' <> ', ' IS ', ' IS NOT ', ' IN ', ' LIKE ', ' GLOB ', ' MATCH ', ' REGEXP ' + " AND ", + " OR ", + "||", + " < ", + " <= ", + " > ", + " >= ", + " = ", + " <> ", + " IS ", + " IS NOT ", + " IN ", + " LIKE ", + " GLOB ", + " MATCH ", + " REGEXP ", ] math_functions = [ # SQL math functions - "Abs", "ACos", "ASin", "ATan", "Cos", "Cot", "Degrees", "Exp", "Floor", "Log", "Log2", - "Log10", "Pi", "Radians", "Round", "Sign", "Sin", "Sqrt", "StdDev_Pop", "StdDev_Samp", "Tan", - "Var_Pop", "Var_Samp"] + "Abs", + "ACos", + "ASin", + "ATan", + "Cos", + "Cot", + "Degrees", + "Exp", + "Floor", + "Log", + "Log2", + "Log10", + "Pi", + "Radians", + "Round", + "Sign", + "Sin", + "Sqrt", + "StdDev_Pop", + "StdDev_Samp", + "Tan", + "Var_Pop", + "Var_Samp", +] -string_functions = ["Length", "Lower", "Upper", "Like", "Trim", "LTrim", "RTrim", "Replace", "Substr"] +string_functions = [ + "Length", + "Lower", + "Upper", + "Like", + "Trim", + "LTrim", + "RTrim", + "Replace", + "Substr", +] aggregate_functions = [ - "Max", "Min", "Avg", "Count", "Sum", "Group_Concat", "Total", "Var_Pop", "Var_Samp", "StdDev_Pop", "StdDev_Samp" + "Max", + "Min", + "Avg", + "Count", + "Sum", + "Group_Concat", + "Total", + "Var_Pop", + "Var_Samp", + "StdDev_Pop", + "StdDev_Samp", ] spatialite_functions = [ # from www.gaia-gis.it/spatialite-2.3.0/spatialite-sql-2.3.0.html - # SQL utility functions for BLOB objects - "*iszipblob", "*ispdfblob", "*isgifblob", "*ispngblob", "*isjpegblob", "*isexifblob", - "*isexifgpsblob", "*geomfromexifgpsblob", "MakePoint", "BuildMbr", "*buildcirclembr", "ST_MinX", - "ST_MinY", "ST_MaxX", "ST_MaxY", - # SQL functions for constructing a geometric object given its Well-known Text Representation - "ST_GeomFromText", "*pointfromtext", - # SQL functions for constructing a geometric object given its Well-known Binary Representation - "*geomfromwkb", "*pointfromwkb", - # SQL functions for obtaining the Well-known Text / Well-known Binary Representation of a geometric object - "ST_AsText", "ST_AsBinary", - # SQL functions supporting exotic geometric formats - "*assvg", "*asfgf", "*geomfromfgf", - # SQL functions on type Geometry - "ST_Dimension", "ST_GeometryType", "ST_Srid", "ST_SetSrid", "ST_isEmpty", "ST_isSimple", "ST_isValid", "ST_Boundary", - "ST_Envelope", - # SQL functions on type Point - "ST_X", "ST_Y", - # SQL functions on type Curve [Linestring or Ring] - "ST_StartPoint", "ST_EndPoint", "ST_Length", "ST_isClosed", "ST_isRing", "ST_Simplify", - "*simplifypreservetopology", - # SQL functions on type LineString - "ST_NumPoints", "ST_PointN", - # SQL functions on type Surface [Polygon or Ring] - "ST_Centroid", "ST_PointOnSurface", "ST_Area", - # SQL functions on type Polygon - "ST_ExteriorRing", "ST_InteriorRingN", - # SQL functions on type GeomCollection - "ST_NumGeometries", "ST_GeometryN", - # SQL functions that test approximative spatial relationships via MBRs - "MbrEqual", "MbrDisjoint", "MbrTouches", "MbrWithin", "MbrOverlaps", "MbrIntersects", - "MbrContains", - # SQL functions that test spatial relationships - "ST_Equals", "ST_Disjoint", "ST_Touches", "ST_Within", "ST_Overlaps", "ST_Crosses", "ST_Intersects", "ST_Contains", - "ST_Relate", - # SQL functions for distance relationships - "ST_Distance", - # SQL functions that implement spatial operators - "ST_Intersection", "ST_Difference", "ST_Union", "ST_SymDifference", "ST_Buffer", "ST_ConvexHull", - # SQL functions for coordinate transformations - "ST_Transform", - # SQL functions for Spatial-MetaData and Spatial-Index handling - "*initspatialmetadata", "*addgeometrycolumn", "*recovergeometrycolumn", "*discardgeometrycolumn", - "*createspatialindex", "*creatembrcache", "*disablespatialindex", - # SQL functions implementing FDO/OGR compatibility - "*checkspatialmetadata", "*autofdostart", "*autofdostop", "*initfdospatialmetadata", - "*addfdogeometrycolumn", "*recoverfdogeometrycolumn", "*discardfdogeometrycolumn", - # SQL functions for MbrCache-based queries - "*filtermbrwithin", "*filtermbrcontains", "*filtermbrintersects", "*buildmbrfilter" + # SQL utility functions for BLOB objects + "*iszipblob", + "*ispdfblob", + "*isgifblob", + "*ispngblob", + "*isjpegblob", + "*isexifblob", + "*isexifgpsblob", + "*geomfromexifgpsblob", + "MakePoint", + "BuildMbr", + "*buildcirclembr", + "ST_MinX", + "ST_MinY", + "ST_MaxX", + "ST_MaxY", + # SQL functions for constructing a geometric object given its Well-known Text Representation + "ST_GeomFromText", + "*pointfromtext", + # SQL functions for constructing a geometric object given its Well-known Binary Representation + "*geomfromwkb", + "*pointfromwkb", + # SQL functions for obtaining the Well-known Text / Well-known Binary Representation of a geometric object + "ST_AsText", + "ST_AsBinary", + # SQL functions supporting exotic geometric formats + "*assvg", + "*asfgf", + "*geomfromfgf", + # SQL functions on type Geometry + "ST_Dimension", + "ST_GeometryType", + "ST_Srid", + "ST_SetSrid", + "ST_isEmpty", + "ST_isSimple", + "ST_isValid", + "ST_Boundary", + "ST_Envelope", + # SQL functions on type Point + "ST_X", + "ST_Y", + # SQL functions on type Curve [Linestring or Ring] + "ST_StartPoint", + "ST_EndPoint", + "ST_Length", + "ST_isClosed", + "ST_isRing", + "ST_Simplify", + "*simplifypreservetopology", + # SQL functions on type LineString + "ST_NumPoints", + "ST_PointN", + # SQL functions on type Surface [Polygon or Ring] + "ST_Centroid", + "ST_PointOnSurface", + "ST_Area", + # SQL functions on type Polygon + "ST_ExteriorRing", + "ST_InteriorRingN", + # SQL functions on type GeomCollection + "ST_NumGeometries", + "ST_GeometryN", + # SQL functions that test approximative spatial relationships via MBRs + "MbrEqual", + "MbrDisjoint", + "MbrTouches", + "MbrWithin", + "MbrOverlaps", + "MbrIntersects", + "MbrContains", + # SQL functions that test spatial relationships + "ST_Equals", + "ST_Disjoint", + "ST_Touches", + "ST_Within", + "ST_Overlaps", + "ST_Crosses", + "ST_Intersects", + "ST_Contains", + "ST_Relate", + # SQL functions for distance relationships + "ST_Distance", + # SQL functions that implement spatial operators + "ST_Intersection", + "ST_Difference", + "ST_Union", + "ST_SymDifference", + "ST_Buffer", + "ST_ConvexHull", + # SQL functions for coordinate transformations + "ST_Transform", + # SQL functions for Spatial-MetaData and Spatial-Index handling + "*initspatialmetadata", + "*addgeometrycolumn", + "*recovergeometrycolumn", + "*discardgeometrycolumn", + "*createspatialindex", + "*creatembrcache", + "*disablespatialindex", + # SQL functions implementing FDO/OGR compatibility + "*checkspatialmetadata", + "*autofdostart", + "*autofdostop", + "*initfdospatialmetadata", + "*addfdogeometrycolumn", + "*recoverfdogeometrycolumn", + "*discardfdogeometrycolumn", + # SQL functions for MbrCache-based queries + "*filtermbrwithin", + "*filtermbrcontains", + "*filtermbrintersects", + "*buildmbrfilter", ] # constants @@ -125,7 +365,7 @@ def getSqlDictionary(spatial=True): def strip_star(s): - if s[0] == '*': + if s[0] == "*": return s.lower()[1:] else: return s.lower() @@ -137,20 +377,26 @@ def strip_star(s): f += spatialite_functions c += spatialite_constants - return {'keyword': list(map(strip_star, k)), 'constant': list(map(strip_star, c)), 'function': list(map(strip_star, f))} + return { + "keyword": list(map(strip_star, k)), + "constant": list(map(strip_star, c)), + "function": list(map(strip_star, f)), + } def getQueryBuilderDictionary(): # concat functions def ff(l): - return [s for s in l if s[0] != '*'] + return [s for s in l if s[0] != "*"] def add_paren(l): return [s + "(" for s in l] - foo = sorted(add_paren(ff(list(set.union(set(functions), set(spatialite_functions)))))) + foo = sorted( + add_paren(ff(list(set.union(set(functions), set(spatialite_functions))))) + ) m = sorted(add_paren(ff(math_functions))) agg = sorted(add_paren(ff(aggregate_functions))) op = ff(operators) s = sorted(add_paren(ff(string_functions))) - return {'function': foo, 'math': m, 'aggregate': agg, 'operator': op, 'string': s} + return {"function": foo, "math": m, "aggregate": agg, "operator": op, "string": s} diff --git a/python/plugins/db_manager/db_plugins/vlayers/connector.py b/python/plugins/db_manager/db_plugins/vlayers/connector.py index 13bc9c505ce7..29e117c04fde 100644 --- a/python/plugins/db_manager/db_plugins/vlayers/connector.py +++ b/python/plugins/db_manager/db_plugins/vlayers/connector.py @@ -29,7 +29,7 @@ QgsMapLayerType, QgsVectorLayer, QgsCoordinateReferenceSystem, - QgsWkbTypes + QgsWkbTypes, ) import sqlite3 @@ -172,31 +172,40 @@ def hasTableColumnEditingSupport(self): def fieldTypes(self): return [ - "integer", "bigint", "smallint", # integers - "real", "double", "float", "numeric", # floats - "varchar", "varchar(255)", "character(20)", "text", # strings - "date", "datetime" # date/time + "integer", + "bigint", + "smallint", # integers + "real", + "double", + "float", + "numeric", # floats + "varchar", + "varchar(255)", + "character(20)", + "text", # strings + "date", + "datetime", # date/time ] def getSchemas(self): return None def getTables(self, schema=None, add_sys_tables=False): - """ get list of tables """ + """get list of tables""" return self.getVectorTables() def getVectorTables(self, schema=None): - """ get list of table with a geometry column - it returns: - name (table name) - is_system_table - type = 'view' (is a view?) - geometry_column: - f_table_name (the table name in geometry_columns may be in a wrong case, use this to load the layer) - f_geometry_column - type - coord_dimension - srid + """get list of table with a geometry column + it returns: + name (table name) + is_system_table + type = 'view' (is a view?) + geometry_column: + f_table_name (the table name in geometry_columns may be in a wrong case, use this to load the layer) + f_geometry_column + type + coord_dimension + srid """ reg = VLayerRegistry.instance() VLayerRegistry.instance().reset() @@ -218,16 +227,27 @@ def getVectorTables(self, schema=None): g_flat = QgsWkbTypes.flatType(g) geomType = QgsWkbTypes.displayString(g_flat).upper() if geomType: - dim = 'XY' + dim = "XY" if QgsWkbTypes.hasZ(g): - dim += 'Z' + dim += "Z" if QgsWkbTypes.hasM(g): - dim += 'M' + dim += "M" srid = l.crs().postgisSrid() if srid not in self.mapSridToName: self.mapSridToName[srid] = l.crs().description() lst.append( - (Table.VectorType, lname, False, False, l.id(), 'geometry', geomType, dim, srid)) + ( + Table.VectorType, + lname, + False, + False, + l.id(), + "geometry", + geomType, + dim, + srid, + ) + ) else: lst.append((Table.TableType, lname, False, False)) return lst @@ -243,15 +263,17 @@ def getTableRowCount(self, table): return l.featureCount() def getTableFields(self, table): - """ return list of columns in table """ + """return list of columns in table""" t = table[1] l = VLayerRegistry.instance().getLayer(t) if not l or not l.isValid(): return [] # id, name, type, nonnull, default, pk n = l.dataProvider().fields().size() - f = [(i, f.name(), f.typeName(), False, None, False) - for i, f in enumerate(l.dataProvider().fields())] + f = [ + (i, f.name(), f.typeName(), False, None, False) + for i, f in enumerate(l.dataProvider().fields()) + ] if l.isSpatial(): f += [(n, "geometry", "geometry", False, None, False)] return f @@ -335,7 +357,16 @@ def addTableColumn(self, table, field_def): def deleteTableColumn(self, table, column): print("**unimplemented** deleteTableColumn") - def updateTableColumn(self, table, column, new_name, new_data_type=None, new_not_null=None, new_default=None, comment=None): + def updateTableColumn( + self, + table, + column, + new_name, + new_data_type=None, + new_not_null=None, + new_default=None, + comment=None, + ): print("**unimplemented** updateTableColumn") def renameTableColumn(self, table, column, new_name): @@ -358,7 +389,9 @@ def isGeometryColumn(self, table, column): print("**unimplemented** isGeometryColumn") return False - def addGeometryColumn(self, table, geom_column='geometry', geom_type='POINT', srid=-1, dim=2): + def addGeometryColumn( + self, table, geom_column="geometry", geom_type="POINT", srid=-1, dim=2 + ): print("**unimplemented** addGeometryColumn") return False @@ -386,15 +419,15 @@ def deleteTableIndex(self, table, name): print("**unimplemented** deleteTableIndex") return False - def createSpatialIndex(self, table, geom_column='geometry'): + def createSpatialIndex(self, table, geom_column="geometry"): print("**unimplemented** createSpatialIndex") return False - def deleteSpatialIndex(self, table, geom_column='geometry'): + def deleteSpatialIndex(self, table, geom_column="geometry"): print("**unimplemented** deleteSpatialIndex") return False - def hasSpatialIndex(self, table, geom_column='geometry'): + def hasSpatialIndex(self, table, geom_column="geometry"): print("**unimplemented** hasSpatialIndex") return False @@ -408,6 +441,7 @@ def connection_error_types(self): def getSqlDictionary(self): from .sql_dictionary import getSqlDictionary + sql_dict = getSqlDictionary() items = [] diff --git a/python/plugins/db_manager/db_plugins/vlayers/data_model.py b/python/plugins/db_manager/db_plugins/vlayers/data_model.py index 22b28d1686ff..4195f69778c9 100644 --- a/python/plugins/db_manager/db_plugins/vlayers/data_model.py +++ b/python/plugins/db_manager/db_plugins/vlayers/data_model.py @@ -17,21 +17,25 @@ ***************************************************************************/ """ -from ..data_model import (TableDataModel, - BaseTableModel, - SqlResultModelAsync, - SqlResultModelTask) +from ..data_model import ( + TableDataModel, + BaseTableModel, + SqlResultModelAsync, + SqlResultModelTask, +) from .connector import VLayerRegistry, getQueryGeometryName from .plugin import LVectorTable from ..plugin import DbError, BaseError from qgis.PyQt.QtCore import QElapsedTimer, QTemporaryFile -from qgis.core import (QgsVectorLayer, - QgsWkbTypes, - QgsVirtualLayerDefinition, - QgsVirtualLayerTask, - QgsTask) +from qgis.core import ( + QgsVectorLayer, + QgsWkbTypes, + QgsVirtualLayerDefinition, + QgsVirtualLayerTask, + QgsTask, +) class LTableDataModel(TableDataModel): @@ -56,7 +60,7 @@ def __init__(self, table, parent=None): if f.hasGeometry(): a.append(QgsWkbTypes.displayString(f.geometry().wkbType())) else: - a.append('None') + a.append("None") self.resdata.append(a) self.fetchedFrom = 0 @@ -83,7 +87,9 @@ def __init__(self, db, sql, parent): df.setQuery(sql) self.subtask = QgsVirtualLayerTask(df) - self.addSubTask(self.subtask, [], QgsTask.SubTaskDependency.ParentDependsOnSubTask) + self.addSubTask( + self.subtask, [], QgsTask.SubTaskDependency.ParentDependsOnSubTask + ) def run(self): try: diff --git a/python/plugins/db_manager/db_plugins/vlayers/info_model.py b/python/plugins/db_manager/db_plugins/vlayers/info_model.py index 473caab0cff1..e5e4346c741f 100644 --- a/python/plugins/db_manager/db_plugins/vlayers/info_model.py +++ b/python/plugins/db_manager/db_plugins/vlayers/info_model.py @@ -29,15 +29,12 @@ def __init__(self, db): self.db = db def connectionDetails(self): - tbl = [ - ] + tbl = [] return HtmlTable(tbl) def generalInfo(self): self.db.connector.getInfo() - tbl = [ - (QApplication.translate("DBManagerPlugin", "SQLite version:"), "3") - ] + tbl = [(QApplication.translate("DBManagerPlugin", "SQLite version:"), "3")] return HtmlTable(tbl) def privilegesDetails(self): diff --git a/python/plugins/db_manager/db_plugins/vlayers/plugin.py b/python/plugins/db_manager/db_plugins/vlayers/plugin.py index 19ba23fdd1d8..f9109008f1d4 100644 --- a/python/plugins/db_manager/db_plugins/vlayers/plugin.py +++ b/python/plugins/db_manager/db_plugins/vlayers/plugin.py @@ -22,7 +22,12 @@ from qgis.PyQt.QtCore import QCoreApplication from qgis.PyQt.QtGui import QIcon -from qgis.core import QgsApplication, QgsVectorLayer, QgsProject, QgsVirtualLayerDefinition +from qgis.core import ( + QgsApplication, + QgsVectorLayer, + QgsProject, + QgsVirtualLayerDefinition, +) from ..plugin import DBPlugin, Database, Table, VectorTable, TableField @@ -42,23 +47,25 @@ def connectionIcon(self): @classmethod def typeName(self): - return 'vlayers' + return "vlayers" @classmethod def typeNameString(self): - return QCoreApplication.translate('db_manager', 'Virtual Layers') + return QCoreApplication.translate("db_manager", "Virtual Layers") @classmethod def providerName(self): - return 'virtual' + return "virtual" @classmethod def connectionSettingsKey(self): - return 'vlayers' + return "vlayers" @classmethod def connections(self): - return [VLayerDBPlugin(QCoreApplication.translate('db_manager', 'Project layers'))] + return [ + VLayerDBPlugin(QCoreApplication.translate("db_manager", "Project layers")) + ] def databasesFactory(self, connection, uri): return FakeDatabase(connection, uri) @@ -92,17 +99,29 @@ def rasterTablesFactory(self, row, db, schema=None): def info(self): from .info_model import LDatabaseInfo + return LDatabaseInfo(self) def sqlResultModel(self, sql, parent): from .data_model import LSqlResultModel + return LSqlResultModel(self, sql, parent) def sqlResultModelAsync(self, sql, parent): from .data_model import LSqlResultModelAsync + return LSqlResultModelAsync(self, sql, parent) - def toSqlLayer(self, sql, geomCol, uniqueCol, layerName="QueryLayer", layerType=None, avoidSelectById=False, _filter=""): + def toSqlLayer( + self, + sql, + geomCol, + uniqueCol, + layerName="QueryLayer", + layerType=None, + avoidSelectById=False, + _filter="", + ): df = QgsVirtualLayerDefinition() df.setQuery(sql) if uniqueCol is not None: @@ -128,7 +147,9 @@ def explicitSpatialIndex(self): return True def spatialIndexClause(self, src_table, src_column, dest_table, dest_column): - return '"%s"._search_frame_ = "%s"."%s"' % (src_table, dest_table, dest_column) + return '"{}"._search_frame_ = "{}"."{}"'.format( + src_table, dest_table, dest_column + ) def supportsComment(self): return False @@ -145,6 +166,7 @@ def tableFieldsFactory(self, row, table): def tableDataModel(self, parent): from .data_model import LTableDataModel + return LTableDataModel(self, parent) def canBeAddedToCanvas(self): @@ -159,12 +181,13 @@ def __init__(self, row, db, schema=None): # SpatiaLite does case-insensitive checks for table names, but the # SL provider didn't do the same in QGIS < 1.9, so self.geomTableName # stores the table name like stored in the geometry_columns table - self.geomTableName, self.geomColumn, self.geomType, self.geomDim, self.srid = row[ - -5:] + self.geomTableName, self.geomColumn, self.geomType, self.geomDim, self.srid = ( + row[-5:] + ) def uri(self): uri = self.database().uri() - uri.setDataSource('', self.geomTableName, self.geomColumn) + uri.setDataSource("", self.geomTableName, self.geomColumn) return uri def hasSpatialIndex(self, geom_column=None): @@ -178,7 +201,8 @@ def deleteSpatialIndex(self, geom_column=None): def refreshTableEstimatedExtent(self): self.extent = self.database().connector.getTableExtent( - ("id", self.geomTableName), None) + ("id", self.geomTableName), None + ) def runAction(self, action): return @@ -191,5 +215,12 @@ class LTableField(TableField): def __init__(self, row, table): TableField.__init__(self, table) - self.num, self.name, self.dataType, self.notNull, self.default, self.primaryKey = row + ( + self.num, + self.name, + self.dataType, + self.notNull, + self.default, + self.primaryKey, + ) = row self.hasDefault = self.default diff --git a/python/plugins/db_manager/db_plugins/vlayers/sql_dictionary.py b/python/plugins/db_manager/db_plugins/vlayers/sql_dictionary.py index 0b177b52ce9e..6103273f9945 100644 --- a/python/plugins/db_manager/db_plugins/vlayers/sql_dictionary.py +++ b/python/plugins/db_manager/db_plugins/vlayers/sql_dictionary.py @@ -15,122 +15,472 @@ *************************************************************************** """ -__author__ = 'Hugo Mercier' -__date__ = 'December 2015' -__copyright__ = '(C) 2015, Hugo Mercier' +__author__ = "Hugo Mercier" +__date__ = "December 2015" +__copyright__ = "(C) 2015, Hugo Mercier" # keywords keywords = [ # TODO get them from a reference page - "action", "add", "after", "all", "alter", "analyze", "and", "as", "asc", - "before", "begin", "between", "by", "cascade", "case", "cast", "check", - "collate", "column", "commit", "constraint", "create", "cross", "current_date", - "current_time", "current_timestamp", "default", "deferrable", "deferred", - "delete", "desc", "distinct", "drop", "each", "else", "end", "escape", - "except", "exists", "for", "foreign", "from", "full", "group", "having", - "ignore", "immediate", "in", "initially", "inner", "insert", "intersect", - "into", "is", "isnull", "join", "key", "left", "like", "limit", "match", - "natural", "no", "not", "notnull", "null", "of", "offset", "on", "or", "order", - "outer", "primary", "references", "release", "restrict", "right", "rollback", - "row", "savepoint", "select", "set", "table", "temporary", "then", "to", - "transaction", "trigger", "union", "unique", "update", "using", "values", - "view", "when", "where", - - "abort", "attach", "autoincrement", "conflict", "database", "detach", - "exclusive", "explain", "fail", "glob", "if", "index", "indexed", "instead", - "plan", "pragma", "query", "raise", "regexp", "reindex", "rename", "replace", - "temp", "vacuum", "virtual" + "action", + "add", + "after", + "all", + "alter", + "analyze", + "and", + "as", + "asc", + "before", + "begin", + "between", + "by", + "cascade", + "case", + "cast", + "check", + "collate", + "column", + "commit", + "constraint", + "create", + "cross", + "current_date", + "current_time", + "current_timestamp", + "default", + "deferrable", + "deferred", + "delete", + "desc", + "distinct", + "drop", + "each", + "else", + "end", + "escape", + "except", + "exists", + "for", + "foreign", + "from", + "full", + "group", + "having", + "ignore", + "immediate", + "in", + "initially", + "inner", + "insert", + "intersect", + "into", + "is", + "isnull", + "join", + "key", + "left", + "like", + "limit", + "match", + "natural", + "no", + "not", + "notnull", + "null", + "of", + "offset", + "on", + "or", + "order", + "outer", + "primary", + "references", + "release", + "restrict", + "right", + "rollback", + "row", + "savepoint", + "select", + "set", + "table", + "temporary", + "then", + "to", + "transaction", + "trigger", + "union", + "unique", + "update", + "using", + "values", + "view", + "when", + "where", + "abort", + "attach", + "autoincrement", + "conflict", + "database", + "detach", + "exclusive", + "explain", + "fail", + "glob", + "if", + "index", + "indexed", + "instead", + "plan", + "pragma", + "query", + "raise", + "regexp", + "reindex", + "rename", + "replace", + "temp", + "vacuum", + "virtual", ] spatialite_keywords = [] # functions functions = [ # TODO get them from a reference page - "changes", "coalesce", "glob", "ifnull", "hex", "last_insert_rowid", - "nullif", "quote", "random", - "randomblob", "replace", "round", "soundex", "total_change", - "typeof", "zeroblob", "date", "datetime", "julianday", "strftime" + "changes", + "coalesce", + "glob", + "ifnull", + "hex", + "last_insert_rowid", + "nullif", + "quote", + "random", + "randomblob", + "replace", + "round", + "soundex", + "total_change", + "typeof", + "zeroblob", + "date", + "datetime", + "julianday", + "strftime", ] operators = [ - ' AND ', ' OR ', '||', ' < ', ' <= ', ' > ', ' >= ', ' = ', ' <> ', ' IS ', ' IS NOT ', ' IN ', ' LIKE ', ' GLOB ', ' MATCH ', ' REGEXP ' + " AND ", + " OR ", + "||", + " < ", + " <= ", + " > ", + " >= ", + " = ", + " <> ", + " IS ", + " IS NOT ", + " IN ", + " LIKE ", + " GLOB ", + " MATCH ", + " REGEXP ", ] math_functions = [ # SQL math functions - "Abs", "ACos", "ASin", "ATan", "Cos", "Cot", "Degrees", "Exp", "Floor", "Log", "Log2", - "Log10", "Pi", "Radians", "Round", "Sign", "Sin", "Sqrt", "StdDev_Pop", "StdDev_Samp", "Tan", - "Var_Pop", "Var_Samp"] + "Abs", + "ACos", + "ASin", + "ATan", + "Cos", + "Cot", + "Degrees", + "Exp", + "Floor", + "Log", + "Log2", + "Log10", + "Pi", + "Radians", + "Round", + "Sign", + "Sin", + "Sqrt", + "StdDev_Pop", + "StdDev_Samp", + "Tan", + "Var_Pop", + "Var_Samp", +] -string_functions = ["Length", "Lower", "Upper", "Like", "Trim", "LTrim", "RTrim", "Replace", "Substr"] +string_functions = [ + "Length", + "Lower", + "Upper", + "Like", + "Trim", + "LTrim", + "RTrim", + "Replace", + "Substr", +] aggregate_functions = [ - "Max", "Min", "Avg", "Count", "Sum", "Group_Concat", "Total", "Var_Pop", "Var_Samp", "StdDev_Pop", "StdDev_Samp" + "Max", + "Min", + "Avg", + "Count", + "Sum", + "Group_Concat", + "Total", + "Var_Pop", + "Var_Samp", + "StdDev_Pop", + "StdDev_Samp", ] spatialite_functions = [ # from www.gaia-gis.it/spatialite-2.3.0/spatialite-sql-2.3.0.html - # SQL utility functions for BLOB objects - "*iszipblob", "*ispdfblob", "*isgifblob", "*ispngblob", "*isjpegblob", "*isexifblob", - "*isexifgpsblob", "*geomfromexifgpsblob", "MakePoint", "BuildMbr", "*buildcirclembr", "ST_MinX", - "ST_MinY", "ST_MaxX", "ST_MaxY", - # SQL functions for constructing a geometric object given its Well-known Text Representation - "ST_GeomFromText", "*pointfromtext", - # SQL functions for constructing a geometric object given its Well-known Binary Representation - "*geomfromwkb", "*pointfromwkb", - # SQL functions for obtaining the Well-known Text / Well-known Binary Representation of a geometric object - "ST_AsText", "ST_AsBinary", - # SQL functions supporting exotic geometric formats - "*assvg", "*asfgf", "*geomfromfgf", - # SQL functions on type Geometry - "ST_Dimension", "ST_GeometryType", "ST_Srid", "ST_SetSrid", "ST_isEmpty", "ST_isSimple", "ST_isValid", "ST_Boundary", - "ST_Envelope", - # SQL functions on type Point - "ST_X", "ST_Y", - # SQL functions on type Curve [Linestring or Ring] - "ST_StartPoint", "ST_EndPoint", "ST_Length", "ST_isClosed", "ST_isRing", "ST_Simplify", - "*simplifypreservetopology", - # SQL functions on type LineString - "ST_NumPoints", "ST_PointN", - # SQL functions on type Surface [Polygon or Ring] - "ST_Centroid", "ST_PointOnSurface", "ST_Area", - # SQL functions on type Polygon - "ST_ExteriorRing", "ST_InteriorRingN", - # SQL functions on type GeomCollection - "ST_NumGeometries", "ST_GeometryN", - # SQL functions that test approximative spatial relationships via MBRs - "MbrEqual", "MbrDisjoint", "MbrTouches", "MbrWithin", "MbrOverlaps", "MbrIntersects", - "MbrContains", - # SQL functions that test spatial relationships - "ST_Equals", "ST_Disjoint", "ST_Touches", "ST_Within", "ST_Overlaps", "ST_Crosses", "ST_Intersects", "ST_Contains", - "ST_Relate", - # SQL functions for distance relationships - "ST_Distance", - # SQL functions that implement spatial operators - "ST_Intersection", "ST_Difference", "ST_Union", "ST_SymDifference", "ST_Buffer", "ST_ConvexHull", - # SQL functions for coordinate transformations - "ST_Transform", - # SQL functions for Spatial-MetaData and Spatial-Index handling - "*initspatialmetadata", "*addgeometrycolumn", "*recovergeometrycolumn", "*discardgeometrycolumn", - "*createspatialindex", "*creatembrcache", "*disablespatialindex", - # SQL functions implementing FDO/OGR compatibility - "*checkspatialmetadata", "*autofdostart", "*autofdostop", "*initfdospatialmetadata", - "*addfdogeometrycolumn", "*recoverfdogeometrycolumn", "*discardfdogeometrycolumn", - # SQL functions for MbrCache-based queries - "*filtermbrwithin", "*filtermbrcontains", "*filtermbrintersects", "*buildmbrfilter" + # SQL utility functions for BLOB objects + "*iszipblob", + "*ispdfblob", + "*isgifblob", + "*ispngblob", + "*isjpegblob", + "*isexifblob", + "*isexifgpsblob", + "*geomfromexifgpsblob", + "MakePoint", + "BuildMbr", + "*buildcirclembr", + "ST_MinX", + "ST_MinY", + "ST_MaxX", + "ST_MaxY", + # SQL functions for constructing a geometric object given its Well-known Text Representation + "ST_GeomFromText", + "*pointfromtext", + # SQL functions for constructing a geometric object given its Well-known Binary Representation + "*geomfromwkb", + "*pointfromwkb", + # SQL functions for obtaining the Well-known Text / Well-known Binary Representation of a geometric object + "ST_AsText", + "ST_AsBinary", + # SQL functions supporting exotic geometric formats + "*assvg", + "*asfgf", + "*geomfromfgf", + # SQL functions on type Geometry + "ST_Dimension", + "ST_GeometryType", + "ST_Srid", + "ST_SetSrid", + "ST_isEmpty", + "ST_isSimple", + "ST_isValid", + "ST_Boundary", + "ST_Envelope", + # SQL functions on type Point + "ST_X", + "ST_Y", + # SQL functions on type Curve [Linestring or Ring] + "ST_StartPoint", + "ST_EndPoint", + "ST_Length", + "ST_isClosed", + "ST_isRing", + "ST_Simplify", + "*simplifypreservetopology", + # SQL functions on type LineString + "ST_NumPoints", + "ST_PointN", + # SQL functions on type Surface [Polygon or Ring] + "ST_Centroid", + "ST_PointOnSurface", + "ST_Area", + # SQL functions on type Polygon + "ST_ExteriorRing", + "ST_InteriorRingN", + # SQL functions on type GeomCollection + "ST_NumGeometries", + "ST_GeometryN", + # SQL functions that test approximative spatial relationships via MBRs + "MbrEqual", + "MbrDisjoint", + "MbrTouches", + "MbrWithin", + "MbrOverlaps", + "MbrIntersects", + "MbrContains", + # SQL functions that test spatial relationships + "ST_Equals", + "ST_Disjoint", + "ST_Touches", + "ST_Within", + "ST_Overlaps", + "ST_Crosses", + "ST_Intersects", + "ST_Contains", + "ST_Relate", + # SQL functions for distance relationships + "ST_Distance", + # SQL functions that implement spatial operators + "ST_Intersection", + "ST_Difference", + "ST_Union", + "ST_SymDifference", + "ST_Buffer", + "ST_ConvexHull", + # SQL functions for coordinate transformations + "ST_Transform", + # SQL functions for Spatial-MetaData and Spatial-Index handling + "*initspatialmetadata", + "*addgeometrycolumn", + "*recovergeometrycolumn", + "*discardgeometrycolumn", + "*createspatialindex", + "*creatembrcache", + "*disablespatialindex", + # SQL functions implementing FDO/OGR compatibility + "*checkspatialmetadata", + "*autofdostart", + "*autofdostop", + "*initfdospatialmetadata", + "*addfdogeometrycolumn", + "*recoverfdogeometrycolumn", + "*discardfdogeometrycolumn", + # SQL functions for MbrCache-based queries + "*filtermbrwithin", + "*filtermbrcontains", + "*filtermbrintersects", + "*buildmbrfilter", ] qgis_functions = [ - "atan2", "round", "rand", "randf", "clamp", "scale_linear", "scale_polynomial", "scale_exponential", "_pi", "to_int", "toint", "to_real", "toreal", - "to_string", "tostring", "to_datetime", "todatetime", "to_date", "todate", "to_time", "totime", "to_interval", "tointerval", - "regexp_match", "now", "_now", "age", "year", "month", "week", "day", "hour", "minute", "second", "day_of_week", "title", - "levenshtein", "longest_common_substring", "hamming_distance", "wordwrap", "regexp_replace", "regexp_substr", "concat", - "strpos", "_left", "_right", "rpad", "lpad", "format", "format_number", "format_date", "color_rgb", "color_rgba", "color_rgbf", "ramp_color", "ramp_color_object", - "color_hsl", "color_hsla", "color_hslf", "color_hsv", "color_hsva", "color_hsvf", "color_cmyk", "color_cmyka", "color_cmykf", "color_part", "darker", "lighter", - "set_color_part", "point_n", "start_point", "end_point", "nodes_to_points", "segments_to_lines", "make_point", - "make_point_m", "make_line", "make_polygon", "x_min", "xmin", "x_max", "xmax", "y_min", "ymin", "y_max", "ymax", "geom_from_wkt", - "geomFromWKT", "geom_from_gml", "relate", "intersects_bbox", "bbox", "translate", "buffer", "point_on_surface", "reverse", - "exterior_ring", "interior_ring_n", "geometry_n", "bounds", "num_points", "num_interior_rings", "num_rings", "num_geometries", - "bounds_width", "bounds_height", "is_closed", "convex_hull", "sym_difference", "combine", "_union", "geom_to_wkt", "geomToWKT", - "transform", "uuid", "_uuid", "layer_property", "var", "_specialcol_", "project_color", "project_color_object"] + "atan2", + "round", + "rand", + "randf", + "clamp", + "scale_linear", + "scale_polynomial", + "scale_exponential", + "_pi", + "to_int", + "toint", + "to_real", + "toreal", + "to_string", + "tostring", + "to_datetime", + "todatetime", + "to_date", + "todate", + "to_time", + "totime", + "to_interval", + "tointerval", + "regexp_match", + "now", + "_now", + "age", + "year", + "month", + "week", + "day", + "hour", + "minute", + "second", + "day_of_week", + "title", + "levenshtein", + "longest_common_substring", + "hamming_distance", + "wordwrap", + "regexp_replace", + "regexp_substr", + "concat", + "strpos", + "_left", + "_right", + "rpad", + "lpad", + "format", + "format_number", + "format_date", + "color_rgb", + "color_rgba", + "color_rgbf", + "ramp_color", + "ramp_color_object", + "color_hsl", + "color_hsla", + "color_hslf", + "color_hsv", + "color_hsva", + "color_hsvf", + "color_cmyk", + "color_cmyka", + "color_cmykf", + "color_part", + "darker", + "lighter", + "set_color_part", + "point_n", + "start_point", + "end_point", + "nodes_to_points", + "segments_to_lines", + "make_point", + "make_point_m", + "make_line", + "make_polygon", + "x_min", + "xmin", + "x_max", + "xmax", + "y_min", + "ymin", + "y_max", + "ymax", + "geom_from_wkt", + "geomFromWKT", + "geom_from_gml", + "relate", + "intersects_bbox", + "bbox", + "translate", + "buffer", + "point_on_surface", + "reverse", + "exterior_ring", + "interior_ring_n", + "geometry_n", + "bounds", + "num_points", + "num_interior_rings", + "num_rings", + "num_geometries", + "bounds_width", + "bounds_height", + "is_closed", + "convex_hull", + "sym_difference", + "combine", + "_union", + "geom_to_wkt", + "geomToWKT", + "transform", + "uuid", + "_uuid", + "layer_property", + "var", + "_specialcol_", + "project_color", + "project_color_object", +] # constants @@ -140,7 +490,7 @@ def getSqlDictionary(spatial=True): def strip_star(s): - if s[0] == '*': + if s[0] == "*": return s.lower()[1:] else: return s.lower() @@ -153,20 +503,34 @@ def strip_star(s): f += qgis_functions c += spatialite_constants - return {'keyword': list(map(strip_star, k)), 'constant': list(map(strip_star, c)), 'function': list(map(strip_star, f))} + return { + "keyword": list(map(strip_star, k)), + "constant": list(map(strip_star, c)), + "function": list(map(strip_star, f)), + } def getQueryBuilderDictionary(): # concat functions def ff(l): - return [s for s in l if s[0] != '*'] + return [s for s in l if s[0] != "*"] def add_paren(l): return [s + "(" for s in l] - foo = sorted(add_paren(ff(list(set.union(set(functions), set(spatialite_functions), set(qgis_functions)))))) + foo = sorted( + add_paren( + ff( + list( + set.union( + set(functions), set(spatialite_functions), set(qgis_functions) + ) + ) + ) + ) + ) m = sorted(add_paren(ff(math_functions))) agg = sorted(add_paren(ff(aggregate_functions))) op = ff(operators) s = sorted(add_paren(ff(string_functions))) - return {'function': foo, 'math': m, 'aggregate': agg, 'operator': op, 'string': s} + return {"function": foo, "math": m, "aggregate": agg, "operator": op, "string": s} diff --git a/python/plugins/db_manager/db_tree.py b/python/plugins/db_manager/db_tree.py index c40d2f42f2bf..2a080cbdaecd 100644 --- a/python/plugins/db_manager/db_tree.py +++ b/python/plugins/db_manager/db_tree.py @@ -41,7 +41,9 @@ def __init__(self, mainWindow): self.setModel(DBModel(self)) self.setHeaderHidden(True) - self.setEditTriggers(QTreeView.EditTrigger.EditKeyPressed | QTreeView.EditTrigger.SelectedClicked) + self.setEditTriggers( + QTreeView.EditTrigger.EditKeyPressed | QTreeView.EditTrigger.SelectedClicked + ) self.setDragEnabled(True) self.setAcceptDrops(True) @@ -125,8 +127,12 @@ def contextMenuEvent(self, ev): menu = QMenu(self) if isinstance(item, (Table, Schema)) and not isinstance(item, LTable): - if not (isinstance(item, GPKGRasterTable) and int(gdal.VersionInfo()) < 3100000): - menu.addAction(QCoreApplication.translate("DBTree", "Rename…"), self.rename) + if not ( + isinstance(item, GPKGRasterTable) and int(gdal.VersionInfo()) < 3100000 + ): + menu.addAction( + QCoreApplication.translate("DBTree", "Rename…"), self.rename + ) menu.addAction(QCoreApplication.translate("DBTree", "Delete…"), self.delete) if isinstance(item, Table) and item.canBeAddedToCanvas(): @@ -140,7 +146,10 @@ def contextMenuEvent(self, ev): menu.addAction(self.tr("Remove"), self.delete) elif not index.parent().isValid() and item.typeName() in ("spatialite", "gpkg"): - menu.addAction(QCoreApplication.translate("DBTree", "New Connection…"), self.newConnection) + menu.addAction( + QCoreApplication.translate("DBTree", "New Connection…"), + self.newConnection, + ) if not menu.isEmpty(): menu.exec(ev.globalPos()) @@ -166,14 +175,28 @@ def addLayer(self): layers = QgsProject.instance().addMapLayers([layer]) if len(layers) != 1: QgsMessageLog.logMessage( - self.tr("%1 is an invalid layer - not loaded").replace("%1", layer.publicSource())) - msgLabel = QLabel(self.tr( - "%1 is an invalid layer and cannot be loaded. Please check the message log for further info.").replace( - "%1", layer.publicSource()), self.mainWindow.infoBar) + self.tr("%1 is an invalid layer - not loaded").replace( + "%1", layer.publicSource() + ) + ) + msgLabel = QLabel( + self.tr( + '%1 is an invalid layer and cannot be loaded. Please check the message log for further info.' + ).replace("%1", layer.publicSource()), + self.mainWindow.infoBar, + ) msgLabel.setWordWrap(True) - msgLabel.linkActivated.connect(self.mainWindow.iface.mainWindow().findChild(QWidget, "MessageLog").show) - msgLabel.linkActivated.connect(self.mainWindow.iface.mainWindow().raise_) - self.mainWindow.infoBar.pushItem(QgsMessageBarItem(msgLabel, Qgis.MessageLevel.Warning)) + msgLabel.linkActivated.connect( + self.mainWindow.iface.mainWindow() + .findChild(QWidget, "MessageLog") + .show + ) + msgLabel.linkActivated.connect( + self.mainWindow.iface.mainWindow().raise_ + ) + self.mainWindow.infoBar.pushItem( + QgsMessageBarItem(msgLabel, Qgis.MessageLevel.Warning) + ) def reconnect(self): db = self.currentDatabase() diff --git a/python/plugins/db_manager/dlg_add_geometry_column.py b/python/plugins/db_manager/dlg_add_geometry_column.py index 559fae0ca76d..3a22e86a16d8 100644 --- a/python/plugins/db_manager/dlg_add_geometry_column.py +++ b/python/plugins/db_manager/dlg_add_geometry_column.py @@ -29,12 +29,19 @@ from .dlg_db_error import DlgDbError from .gui_utils import GuiUtils -Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgAddGeometryColumn.ui')) +Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgAddGeometryColumn.ui")) class DlgAddGeometryColumn(QDialog, Ui_Dialog): - GEOM_TYPES = ["POINT", "LINESTRING", "POLYGON", "MULTIPOINT", "MULTILINESTRING", "MULTIPOLYGON", - "GEOMETRYCOLLECTION"] + GEOM_TYPES = [ + "POINT", + "LINESTRING", + "POLYGON", + "MULTIPOINT", + "MULTILINESTRING", + "MULTIPOLYGON", + "GEOMETRYCOLLECTION", + ] def __init__(self, parent=None, table=None, db=None): QDialog.__init__(self, parent) @@ -45,9 +52,11 @@ def __init__(self, parent=None, table=None, db=None): self.buttonBox.accepted.connect(self.createGeomColumn) def createGeomColumn(self): - """ first check whether everything's fine """ + """first check whether everything's fine""" if self.editName.text() == "": - QMessageBox.critical(self, self.tr("DB Manager"), self.tr("Field name must not be empty.")) + QMessageBox.critical( + self, self.tr("DB Manager"), self.tr("Field name must not be empty.") + ) return name = self.editName.text() @@ -62,7 +71,9 @@ def createGeomColumn(self): # now create the geometry column with OverrideCursor(Qt.CursorShape.WaitCursor): try: - self.table.addGeometryColumn(name, geom_type, srid, dim, createSpatialIndex) + self.table.addGeometryColumn( + name, geom_type, srid, dim, createSpatialIndex + ) except DbError as e: DlgDbError.showError(e, self) return diff --git a/python/plugins/db_manager/dlg_create_constraint.py b/python/plugins/db_manager/dlg_create_constraint.py index b2c571494fec..aeb0e62e163e 100644 --- a/python/plugins/db_manager/dlg_create_constraint.py +++ b/python/plugins/db_manager/dlg_create_constraint.py @@ -30,7 +30,7 @@ from .db_plugins.plugin import TableConstraint from .gui_utils import GuiUtils -Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgCreateConstraint.ui')) +Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgCreateConstraint.ui")) class DlgCreateConstraint(QDialog, Ui_Dialog): @@ -65,7 +65,11 @@ def createConstraint(self): def getConstraint(self): constr = TableConstraint(self.table) constr.name = "" - constr.type = TableConstraint.TypePrimaryKey if self.radPrimaryKey.isChecked() else TableConstraint.TypeUnique + constr.type = ( + TableConstraint.TypePrimaryKey + if self.radPrimaryKey.isChecked() + else TableConstraint.TypeUnique + ) constr.columns = [] column = self.cboColumn.currentText() for fld in self.table.fields(): diff --git a/python/plugins/db_manager/dlg_create_index.py b/python/plugins/db_manager/dlg_create_index.py index 40e3b4c1611a..2a6452edeee2 100644 --- a/python/plugins/db_manager/dlg_create_index.py +++ b/python/plugins/db_manager/dlg_create_index.py @@ -30,7 +30,7 @@ from .db_plugins.plugin import TableIndex from .gui_utils import GuiUtils -Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgCreateIndex.ui')) +Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgCreateIndex.ui")) class DlgCreateIndex(QDialog, Ui_Dialog): @@ -52,12 +52,14 @@ def populateColumns(self): self.cboColumn.addItem(fld.name) def columnChanged(self): - self.editName.setText("idx_%s_%s" % (self.table.name, self.cboColumn.currentText())) + self.editName.setText(f"idx_{self.table.name}_{self.cboColumn.currentText()}") def createIndex(self): idx = self.getIndex() if idx.name == "": - QMessageBox.critical(self, self.tr("Error"), self.tr("Please enter a name for the index.")) + QMessageBox.critical( + self, self.tr("Error"), self.tr("Please enter a name for the index.") + ) return # now create the index diff --git a/python/plugins/db_manager/dlg_create_table.py b/python/plugins/db_manager/dlg_create_table.py index c7b36d6e6d4d..7e617a8a3707 100644 --- a/python/plugins/db_manager/dlg_create_table.py +++ b/python/plugins/db_manager/dlg_create_table.py @@ -22,7 +22,15 @@ from qgis.PyQt import uic from qgis.PyQt.QtCore import Qt, QModelIndex -from qgis.PyQt.QtWidgets import QItemDelegate, QComboBox, QDialog, QPushButton, QDialogButtonBox, QMessageBox, QApplication +from qgis.PyQt.QtWidgets import ( + QItemDelegate, + QComboBox, + QDialog, + QPushButton, + QDialogButtonBox, + QMessageBox, + QApplication, +) from qgis.PyQt.QtCore import QItemSelectionModel, pyqtSignal from qgis.utils import OverrideCursor @@ -32,11 +40,11 @@ from .dlg_db_error import DlgDbError from .gui_utils import GuiUtils -Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgCreateTable.ui')) +Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgCreateTable.ui")) class TableFieldsDelegate(QItemDelegate): - """ delegate with some special item editors """ + """delegate with some special item editors""" columnNameChanged = pyqtSignal() @@ -56,7 +64,7 @@ def createEditor(self, parent, option, index): return QItemDelegate.createEditor(self, parent, option, index) def setEditorData(self, editor, index): - """ load data from model to editor """ + """load data from model to editor""" m = index.model() if index.column() == 1: txt = m.data(index, Qt.ItemDataRole.DisplayRole) @@ -66,7 +74,7 @@ def setEditorData(self, editor, index): QItemDelegate.setEditorData(self, editor, index) def setModelData(self, editor, model, index): - """ save data from editor back to model """ + """save data from editor back to model""" if index.column() == 1: model.setData(index, editor.currentText()) else: @@ -77,8 +85,15 @@ def setModelData(self, editor, model, index): class DlgCreateTable(QDialog, Ui_Dialog): - GEOM_TYPES = ["POINT", "LINESTRING", "POLYGON", "MULTIPOINT", "MULTILINESTRING", "MULTIPOLYGON", - "GEOMETRYCOLLECTION"] + GEOM_TYPES = [ + "POINT", + "LINESTRING", + "POLYGON", + "MULTIPOINT", + "MULTILINESTRING", + "MULTIPOLYGON", + "GEOMETRYCOLLECTION", + ] def __init__(self, item, parent=None): QDialog.__init__(self, parent) @@ -128,7 +143,7 @@ def populateSchemas(self): index = -1 for schema in self.schemas: self.cboSchema.addItem(schema.name) - if hasattr(self.item, 'schema') and schema.name == self.item.schema().name: + if hasattr(self.item, "schema") and schema.name == self.item.schema().name: index = self.cboSchema.count() - 1 self.cboSchema.setCurrentIndex(index) @@ -146,8 +161,8 @@ def updateUi(self): def updateUiFields(self): fld = self.selectedField() if fld is not None: - up_enabled = (fld != 0) - down_enabled = (fld != self.fields.model().rowCount() - 1) + up_enabled = fld != 0 + down_enabled = fld != self.fields.model().rowCount() - 1 del_enabled = True else: up_enabled, down_enabled, del_enabled = False, False, False @@ -156,7 +171,7 @@ def updateUiFields(self): self.btnDeleteField.setEnabled(del_enabled) def updatePkeyCombo(self, selRow=None): - """ called when list of columns changes. if 'sel' is None, it keeps current index """ + """called when list of columns changes. if 'sel' is None, it keeps current index""" if selRow is None: selRow = self.cboPrimaryKey.currentIndex() @@ -171,7 +186,7 @@ def updatePkeyCombo(self, selRow=None): self.cboPrimaryKey.setCurrentIndex(selRow) def addField(self): - """Adds new field to the end of field table """ + """Adds new field to the end of field table""" m = self.fields.model() newRow = m.rowCount() m.insertRows(newRow, 1) @@ -192,7 +207,11 @@ def addField(self): # selects the new row sel = self.fields.selectionModel() - sel.select(indexName, QItemSelectionModel.SelectionFlag.Rows | QItemSelectionModel.SelectionFlag.ClearAndSelect) + sel.select( + indexName, + QItemSelectionModel.SelectionFlag.Rows + | QItemSelectionModel.SelectionFlag.ClearAndSelect, + ) # starts editing self.fields.edit(indexName) @@ -206,23 +225,29 @@ def selectedField(self): return sel[0].row() def deleteField(self): - """Deletes selected field """ + """Deletes selected field""" row = self.selectedField() if row is None: - QMessageBox.information(self, self.tr("DB Manager"), self.tr("No field selected.")) + QMessageBox.information( + self, self.tr("DB Manager"), self.tr("No field selected.") + ) else: self.fields.model().removeRows(row, 1) self.updatePkeyCombo() def fieldUp(self): - """ move selected field up """ + """move selected field up""" row = self.selectedField() if row is None: - QMessageBox.information(self, self.tr("DB Manager"), self.tr("No field selected.")) + QMessageBox.information( + self, self.tr("DB Manager"), self.tr("No field selected.") + ) return if row == 0: - QMessageBox.information(self, self.tr("DB Manager"), self.tr("Field is already at the top.")) + QMessageBox.information( + self, self.tr("DB Manager"), self.tr("Field is already at the top.") + ) return # take row and reinsert it @@ -231,18 +256,26 @@ def fieldUp(self): # set selection again index = self.fields.model().index(row - 1, 0, QModelIndex()) - self.fields.selectionModel().select(index, QItemSelectionModel.SelectionFlag.Rows | QItemSelectionModel.SelectionFlag.ClearAndSelect) + self.fields.selectionModel().select( + index, + QItemSelectionModel.SelectionFlag.Rows + | QItemSelectionModel.SelectionFlag.ClearAndSelect, + ) self.updatePkeyCombo() def fieldDown(self): - """ move selected field down """ + """move selected field down""" row = self.selectedField() if row is None: - QMessageBox.information(self, self.tr("DB Manager"), self.tr("No field selected.")) + QMessageBox.information( + self, self.tr("DB Manager"), self.tr("No field selected.") + ) return if row == self.fields.model().rowCount() - 1: - QMessageBox.information(self, self.tr("DB Manager"), self.tr("Field is already at the bottom.")) + QMessageBox.information( + self, self.tr("DB Manager"), self.tr("Field is already at the bottom.") + ) return # take row and reinsert it @@ -251,35 +284,51 @@ def fieldDown(self): # set selection again index = self.fields.model().index(row + 1, 0, QModelIndex()) - self.fields.selectionModel().select(index, QItemSelectionModel.SelectionFlag.Rows | QItemSelectionModel.SelectionFlag.ClearAndSelect) + self.fields.selectionModel().select( + index, + QItemSelectionModel.SelectionFlag.Rows + | QItemSelectionModel.SelectionFlag.ClearAndSelect, + ) self.updatePkeyCombo() def createTable(self): - """Creates table with chosen fields, optionally add a geometry column """ + """Creates table with chosen fields, optionally add a geometry column""" if not self.hasSchemas: schema = None else: schema = str(self.cboSchema.currentText()) if len(schema) == 0: - QMessageBox.information(self, self.tr("DB Manager"), self.tr("A valid schema must be selected first.")) + QMessageBox.information( + self, + self.tr("DB Manager"), + self.tr("A valid schema must be selected first."), + ) return table = str(self.editName.text()) if len(table) == 0: - QMessageBox.information(self, self.tr("DB Manager"), self.tr("A valid table name is required.")) + QMessageBox.information( + self, self.tr("DB Manager"), self.tr("A valid table name is required.") + ) return m = self.fields.model() if m.rowCount() == 0: - QMessageBox.information(self, self.tr("DB Manager"), self.tr("At least one field is required.")) + QMessageBox.information( + self, self.tr("DB Manager"), self.tr("At least one field is required.") + ) return useGeomColumn = self.chkGeomColumn.isChecked() if useGeomColumn: geomColumn = str(self.editGeomColumn.text()) if len(geomColumn) == 0: - QMessageBox.information(self, self.tr("DB Manager"), self.tr("A name is required for the geometry column.")) + QMessageBox.information( + self, + self.tr("DB Manager"), + self.tr("A name is required for the geometry column."), + ) return geomType = self.GEOM_TYPES[self.cboGeomType.currentIndex()] @@ -321,4 +370,6 @@ def createTable(self): self.editGeomSrid.setEnabled(False) self.chkSpatialIndex.setEnabled(False) - QMessageBox.information(self, self.tr("DB Manager"), self.tr("Table created successfully.")) + QMessageBox.information( + self, self.tr("DB Manager"), self.tr("Table created successfully.") + ) diff --git a/python/plugins/db_manager/dlg_db_error.py b/python/plugins/db_manager/dlg_db_error.py index 3da3daa55cda..87cef96f0012 100644 --- a/python/plugins/db_manager/dlg_db_error.py +++ b/python/plugins/db_manager/dlg_db_error.py @@ -26,7 +26,7 @@ from .gui_utils import GuiUtils from .db_plugins.plugin import DbError -Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgDbError.ui')) +Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgDbError.ui")) class DlgDbError(QDialog, Ui_Dialog): @@ -36,7 +36,7 @@ def __init__(self, e, parent=None): self.setupUi(self) def sanitize(txt): - return "" if txt is None else "
" + txt.replace('<', '<') + "
" + return "" if txt is None else "
" + txt.replace("<", "<") + "
" if isinstance(e, DbError): self.setQueryMessage(sanitize(e.msg), sanitize(e.query)) diff --git a/python/plugins/db_manager/dlg_export_vector.py b/python/plugins/db_manager/dlg_export_vector.py index 232b821e3d0d..26282c364134 100644 --- a/python/plugins/db_manager/dlg_export_vector.py +++ b/python/plugins/db_manager/dlg_export_vector.py @@ -25,16 +25,18 @@ from qgis.PyQt.QtWidgets import QDialog, QFileDialog, QMessageBox, QApplication from qgis.PyQt.QtGui import QCursor -from qgis.core import (QgsVectorFileWriter, - QgsVectorDataProvider, - QgsCoordinateReferenceSystem, - QgsVectorLayerExporter, - QgsSettings) +from qgis.core import ( + QgsVectorFileWriter, + QgsVectorDataProvider, + QgsCoordinateReferenceSystem, + QgsVectorLayerExporter, + QgsSettings, +) from qgis.utils import OverrideCursor from .gui_utils import GuiUtils -Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgExportVector.ui')) +Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgExportVector.ui")) class DlgExportVector(QDialog, Ui_Dialog): @@ -46,8 +48,8 @@ def __init__(self, inLayer, inDb, parent=None): self.setupUi(self) vectorFilterName = "lastVectorFileFilter" # "lastRasterFileFilter" - self.lastUsedVectorFilterSettingsKey = "/UI/{}".format(vectorFilterName) - self.lastUsedVectorDirSettingsKey = "/UI/{}Dir".format(vectorFilterName) + self.lastUsedVectorFilterSettingsKey = f"/UI/{vectorFilterName}" + self.lastUsedVectorDirSettingsKey = f"/UI/{vectorFilterName}Dir" # update UI self.setupWorkingMode() @@ -65,7 +67,7 @@ def setupWorkingMode(self): self.checkSupports() def checkSupports(self): - """ update options available for the current input layer """ + """update options available for the current input layer""" allowSpatial = self.db.connector.hasSpatialSupport() hasGeomType = self.inLayer and self.inLayer.isSpatial() self.chkSourceSrid.setEnabled(allowSpatial and hasGeomType) @@ -82,19 +84,22 @@ def chooseOutputFile(self): selected_filter = QgsVectorFileWriter.filterForDriver(selected_driver) # ask for a filename - filename, filter = QFileDialog.getSaveFileName(self, self.tr("Choose where to save the file"), lastUsedDir, - selected_filter) + filename, filter = QFileDialog.getSaveFileName( + self, self.tr("Choose where to save the file"), lastUsedDir, selected_filter + ) if filename == "": return - ext = selected_filter[selected_filter.find('.'):] - ext = ext[:ext.find(' ')] + ext = selected_filter[selected_filter.find(".") :] + ext = ext[: ext.find(" ")] if not filename.lower().endswith(ext): filename += ext # store the last used dir - settings.setValue(self.lastUsedVectorDirSettingsKey, QFileInfo(filename).filePath()) + settings.setValue( + self.lastUsedVectorDirSettingsKey, QFileInfo(filename).filePath() + ) self.editOutputFile.setText(filename) @@ -127,23 +132,31 @@ def populateFileFilters(self): def accept(self): # sanity checks if self.editOutputFile.text() == "": - QMessageBox.information(self, self.tr("Export to file"), self.tr("Output file name is required")) + QMessageBox.information( + self, self.tr("Export to file"), self.tr("Output file name is required") + ) return if self.chkSourceSrid.isEnabled() and self.chkSourceSrid.isChecked(): try: sourceSrid = int(self.editSourceSrid.text()) except ValueError: - QMessageBox.information(self, self.tr("Export to file"), - self.tr("Invalid source srid: must be an integer")) + QMessageBox.information( + self, + self.tr("Export to file"), + self.tr("Invalid source srid: must be an integer"), + ) return if self.chkTargetSrid.isEnabled() and self.chkTargetSrid.isChecked(): try: targetSrid = int(self.editTargetSrid.text()) except ValueError: - QMessageBox.information(self, self.tr("Export to file"), - self.tr("Invalid target srid: must be an integer")) + QMessageBox.information( + self, + self.tr("Export to file"), + self.tr("Invalid target srid: must be an integer"), + ) return with OverrideCursor(Qt.CursorShape.WaitCursor): @@ -157,15 +170,15 @@ def accept(self): # set the OGR driver will be used driverName = self.cboFileFormat.currentData() - options['driverName'] = driverName + options["driverName"] = driverName # set the output file encoding if self.chkEncoding.isEnabled() and self.chkEncoding.isChecked(): enc = self.cboEncoding.currentText() - options['fileEncoding'] = enc + options["fileEncoding"] = enc if self.chkDropTable.isChecked(): - options['overwrite'] = True + options["overwrite"] = True outCrs = QgsCoordinateReferenceSystem() if self.chkTargetSrid.isEnabled() and self.chkTargetSrid.isChecked(): @@ -179,8 +192,9 @@ def accept(self): self.inLayer.setCrs(inCrs) # do the export! - ret, errMsg = QgsVectorLayerExporter.exportLayer(self.inLayer, uri, providerName, outCrs, - False, options) + ret, errMsg = QgsVectorLayerExporter.exportLayer( + self.inLayer, uri, providerName, outCrs, False, options + ) except Exception as e: ret = -1 errMsg = str(e) @@ -190,12 +204,18 @@ def accept(self): self.inLayer.setCrs(prevInCrs) if ret != 0: - QMessageBox.warning(self, self.tr("Export to file"), self.tr("Error {0}\n{1}").format(ret, errMsg)) + QMessageBox.warning( + self, + self.tr("Export to file"), + self.tr("Error {0}\n{1}").format(ret, errMsg), + ) return # create spatial index # if self.chkSpatialIndex.isEnabled() and self.chkSpatialIndex.isChecked(): # self.db.connector.createSpatialIndex( (schema, table), geom ) - QMessageBox.information(self, self.tr("Export to file"), self.tr("Export finished.")) + QMessageBox.information( + self, self.tr("Export to file"), self.tr("Export finished.") + ) return QDialog.accept(self) diff --git a/python/plugins/db_manager/dlg_field_properties.py b/python/plugins/db_manager/dlg_field_properties.py index c4fb29b5c356..1548569605e9 100644 --- a/python/plugins/db_manager/dlg_field_properties.py +++ b/python/plugins/db_manager/dlg_field_properties.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Giuseppe Sucameli' -__date__ = 'April 2012' -__copyright__ = '(C) 2012, Giuseppe Sucameli' +__author__ = "Giuseppe Sucameli" +__date__ = "April 2012" +__copyright__ = "(C) 2012, Giuseppe Sucameli" from qgis.PyQt import uic from qgis.PyQt.QtWidgets import QDialog, QMessageBox @@ -25,7 +25,7 @@ from .db_plugins.plugin import TableField from .gui_utils import GuiUtils -Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgFieldProperties.ui')) +Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgFieldProperties.ui")) class DlgFieldProperties(QDialog, Ui_Dialog): @@ -81,13 +81,17 @@ def getField(self, newCopy=False): return fld def onOK(self): - """ first check whether everything's fine """ + """first check whether everything's fine""" fld = self.getField(True) # don't change the original copy if fld.name == "": - QMessageBox.critical(self, self.tr("DB Manager"), self.tr("Field name must not be empty.")) + QMessageBox.critical( + self, self.tr("DB Manager"), self.tr("Field name must not be empty.") + ) return if fld.dataType == "": - QMessageBox.critical(self, self.tr("DB Manager"), self.tr("Field type must not be empty.")) + QMessageBox.critical( + self, self.tr("DB Manager"), self.tr("Field type must not be empty.") + ) return self.accept() diff --git a/python/plugins/db_manager/dlg_import_vector.py b/python/plugins/db_manager/dlg_import_vector.py index ebc2140a468c..d0cdbf0552f6 100644 --- a/python/plugins/db_manager/dlg_import_vector.py +++ b/python/plugins/db_manager/dlg_import_vector.py @@ -24,21 +24,23 @@ from qgis.PyQt.QtCore import Qt, QFileInfo from qgis.PyQt.QtWidgets import QDialog, QFileDialog, QMessageBox -from qgis.core import (QgsDataSourceUri, - QgsVectorDataProvider, - QgsVectorLayer, - QgsMapLayerType, - QgsProviderRegistry, - QgsCoordinateReferenceSystem, - QgsVectorLayerExporter, - QgsProject, - QgsSettings) +from qgis.core import ( + QgsDataSourceUri, + QgsVectorDataProvider, + QgsVectorLayer, + QgsMapLayerType, + QgsProviderRegistry, + QgsCoordinateReferenceSystem, + QgsVectorLayerExporter, + QgsProject, + QgsSettings, +) from qgis.gui import QgsMessageViewer from qgis.utils import OverrideCursor, iface from .gui_utils import GuiUtils -Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgImportVector.ui')) +Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgImportVector.ui")) class DlgImportVector(QDialog, Ui_Dialog): @@ -59,7 +61,9 @@ def __init__(self, inLayer, outDb, outUri, parent=None): self.default_pk = "id" self.default_geom = "geom" - self.mode = self.ASK_FOR_INPUT_MODE if self.inLayer is None else self.HAS_INPUT_MODE + self.mode = ( + self.ASK_FOR_INPUT_MODE if self.inLayer is None else self.HAS_INPUT_MODE + ) # used to delete the inlayer whether created inside this dialog self.inLayerMustBeDestroyed = False @@ -77,7 +81,7 @@ def __init__(self, inLayer, outDb, outUri, parent=None): self.updateInputLayer() def setupWorkingMode(self, mode): - """ hide the widget to select a layer/file if the input layer is already set """ + """hide the widget to select a layer/file if the input layer is already set""" self.wdgInput.setVisible(mode == self.ASK_FOR_INPUT_MODE) self.resize(450, 350) @@ -90,7 +94,9 @@ def setupWorkingMode(self, mode): self.editPrimaryKey.setText(self.default_pk) self.editGeomColumn.setText(self.default_geom) - self.chkLowercaseFieldNames.setEnabled(self.db.hasLowercaseFieldNamesOption()) + self.chkLowercaseFieldNames.setEnabled( + self.db.hasLowercaseFieldNamesOption() + ) if not self.chkLowercaseFieldNames.isEnabled(): self.chkLowercaseFieldNames.setChecked(False) else: @@ -99,10 +105,14 @@ def setupWorkingMode(self, mode): self.updateInputLayer() def checkSupports(self): - """ update options available for the current input layer """ + """update options available for the current input layer""" allowSpatial = self.db.connector.hasSpatialSupport() hasGeomType = self.inLayer and self.inLayer.isSpatial() - isShapefile = self.inLayer and self.inLayer.providerType() == "ogr" and self.inLayer.storageType() == "ESRI Shapefile" + isShapefile = ( + self.inLayer + and self.inLayer.providerType() == "ogr" + and self.inLayer.storageType() == "ESRI Shapefile" + ) self.chkGeomColumn.setEnabled(allowSpatial and hasGeomType) if not self.chkGeomColumn.isEnabled(): @@ -142,7 +152,7 @@ def populateLayers(self): self.cboInputLayer.setCurrentIndex(index) def deleteInputLayer(self): - """ unset the input layer, then destroy it but only if it was created from this dialog """ + """unset the input layer, then destroy it but only if it was created from this dialog""" if self.mode == self.ASK_FOR_INPUT_MODE and self.inLayer: if self.inLayerMustBeDestroyed: self.inLayer.deleteLater() @@ -158,8 +168,13 @@ def chooseInputFile(self): lastDir = settings.value("/db_manager/lastUsedDir", "") lastVectorFormat = settings.value("/UI/lastVectorFileFilter", "") # ask for a filename - filename, lastVectorFormat = QFileDialog.getOpenFileName(self, self.tr("Choose the file to import"), - lastDir, vectorFormats, lastVectorFormat) + filename, lastVectorFormat = QFileDialog.getOpenFileName( + self, + self.tr("Choose the file to import"), + lastDir, + vectorFormats, + lastVectorFormat, + ) if filename == "": return # store the last used dir and format @@ -170,7 +185,7 @@ def chooseInputFile(self): self.cboInputLayer.setEditText(filename) def reloadInputLayer(self): - """Creates the input layer and update available options """ + """Creates the input layer and update available options""" if self.mode != self.ASK_FOR_INPUT_MODE: return True @@ -264,7 +279,7 @@ def populateEncodings(self): # populate the combo with supported encodings self.cboEncoding.addItems(QgsVectorDataProvider.availableEncodings()) - self.cboEncoding.insertItem(0, self.tr('Automatic'), "") + self.cboEncoding.insertItem(0, self.tr("Automatic"), "") self.cboEncoding.setCurrentIndex(0) def accept(self): @@ -275,23 +290,37 @@ def accept(self): # sanity checks if self.inLayer is None: - QMessageBox.critical(self, self.tr("Import to Database"), self.tr("Input layer missing or not valid.")) + QMessageBox.critical( + self, + self.tr("Import to Database"), + self.tr("Input layer missing or not valid."), + ) return if self.cboTable.currentText() == "": - QMessageBox.critical(self, self.tr("Import to Database"), self.tr("Output table name is required.")) + QMessageBox.critical( + self, + self.tr("Import to Database"), + self.tr("Output table name is required."), + ) return if self.chkSourceSrid.isEnabled() and self.chkSourceSrid.isChecked(): if not self.widgetSourceSrid.crs().isValid(): - QMessageBox.critical(self, self.tr("Import to Database"), - self.tr("Invalid source srid: must be a valid crs.")) + QMessageBox.critical( + self, + self.tr("Import to Database"), + self.tr("Invalid source srid: must be a valid crs."), + ) return if self.chkTargetSrid.isEnabled() and self.chkTargetSrid.isChecked(): if not self.widgetTargetSrid.crs().isValid(): - QMessageBox.critical(self, self.tr("Import to Database"), - self.tr("Invalid target srid: must be a valid crs.")) + QMessageBox.critical( + self, + self.tr("Import to Database"), + self.tr("Invalid target srid: must be a valid crs."), + ) return with OverrideCursor(Qt.CursorShape.WaitCursor): @@ -300,48 +329,63 @@ def accept(self): prevInEncoding = self.inLayer.dataProvider().encoding() try: - schema = self.outUri.schema() if not self.cboSchema.isEnabled() else self.cboSchema.currentText() + schema = ( + self.outUri.schema() + if not self.cboSchema.isEnabled() + else self.cboSchema.currentText() + ) table = self.cboTable.currentText() # get pk and geom field names from the source layer or use the # ones defined by the user srcUri = QgsDataSourceUri(self.inLayer.source()) - pk = srcUri.keyColumn() if not self.chkPrimaryKey.isChecked() else self.editPrimaryKey.text() + pk = ( + srcUri.keyColumn() + if not self.chkPrimaryKey.isChecked() + else self.editPrimaryKey.text() + ) if not pk: pk = self.default_pk if self.inLayer.isSpatial() and self.chkGeomColumn.isEnabled(): - geom = srcUri.geometryColumn() if not self.chkGeomColumn.isChecked() else self.editGeomColumn.text() + geom = ( + srcUri.geometryColumn() + if not self.chkGeomColumn.isChecked() + else self.editGeomColumn.text() + ) if not geom: geom = self.default_geom else: geom = None options = {} - if self.chkLowercaseFieldNames.isEnabled() and self.chkLowercaseFieldNames.isChecked(): + if ( + self.chkLowercaseFieldNames.isEnabled() + and self.chkLowercaseFieldNames.isChecked() + ): pk = pk.lower() if geom: geom = geom.lower() - options['lowercaseFieldNames'] = True + options["lowercaseFieldNames"] = True # get output params, update output URI self.outUri.setDataSource(schema, table, geom, "", pk) typeName = self.db.dbplugin().typeName() providerName = self.db.dbplugin().providerName() - if typeName == 'gpkg': + if typeName == "gpkg": uri = self.outUri.database() - options['update'] = True - options['driverName'] = 'GPKG' - options['layerName'] = table + options["update"] = True + options["driverName"] = "GPKG" + options["layerName"] = table else: uri = self.outUri.uri(False) if self.chkDropTable.isChecked(): - options['overwrite'] = True + options["overwrite"] = True if self.chkSinglePart.isEnabled() and self.chkSinglePart.isChecked(): - options['forceSinglePartGeometryType'] = True + options["forceSinglePartGeometryType"] = True outCrs = QgsCoordinateReferenceSystem() if self.chkTargetSrid.isEnabled() and self.chkTargetSrid.isChecked(): @@ -352,14 +396,20 @@ def accept(self): inCrs = self.widgetSourceSrid.crs() self.inLayer.setCrs(inCrs) - if self.chkEncoding.isEnabled() and self.chkEncoding.isChecked() and self.cboEncoding.currentData() is None: + if ( + self.chkEncoding.isEnabled() + and self.chkEncoding.isChecked() + and self.cboEncoding.currentData() is None + ): enc = self.cboEncoding.currentText() self.inLayer.setProviderEncoding(enc) onlySelected = self.chkSelectedFeatures.isChecked() # do the import! - ret, errMsg = QgsVectorLayerExporter.exportLayer(self.inLayer, uri, providerName, outCrs, onlySelected, options) + ret, errMsg = QgsVectorLayerExporter.exportLayer( + self.inLayer, uri, providerName, outCrs, onlySelected, options + ) except Exception as e: ret = -1 errMsg = str(e) @@ -389,7 +439,9 @@ def accept(self): self.db.connection().reconnect() self.db.refresh() - QMessageBox.information(self, self.tr("Import to Database"), self.tr("Import was successful.")) + QMessageBox.information( + self, self.tr("Import to Database"), self.tr("Import was successful.") + ) return QDialog.accept(self) def closeEvent(self, event): diff --git a/python/plugins/db_manager/dlg_query_builder.py b/python/plugins/db_manager/dlg_query_builder.py index 33998530d23b..fb893cf3ac21 100644 --- a/python/plugins/db_manager/dlg_query_builder.py +++ b/python/plugins/db_manager/dlg_query_builder.py @@ -26,14 +26,14 @@ from .db_plugins.plugin import VectorTable from .gui_utils import GuiUtils -Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgQueryBuilder.ui')) +Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgQueryBuilder.ui")) class FocusEventFilter(QObject): def __init__(self, parent): QObject.__init__(self, parent) - self.focus = '' + self.focus = "" def eventFilter(self, obj, event): if event.type() == QEvent.Type.FocusIn: @@ -63,7 +63,7 @@ def __init__(self, iface, db, parent=None, reset=False): QDialog.__init__(self, parent) self.iface = iface self.db = db - self.query = '' + self.query = "" self.ui = Ui_Dialog() self.ui.setupUi(self) self.ui.group.setMaximumHeight(self.ui.tab.sizeHint().height()) @@ -83,11 +83,11 @@ def __init__(self, iface, db, parent=None, reset=False): self.coltables = [] self.ui.extract.setChecked(True) # ComboBox default values - self.ui.functions.insertItems(1, d['function']) - self.ui.math.insertItems(1, d['math']) - self.ui.aggregates.insertItems(1, d['aggregate']) - self.ui.operators.insertItems(1, d['operator']) - self.ui.stringfct.insertItems(1, d['string']) + self.ui.functions.insertItems(1, d["function"]) + self.ui.math.insertItems(1, d["math"]) + self.ui.aggregates.insertItems(1, d["aggregate"]) + self.ui.operators.insertItems(1, d["operator"]) + self.ui.stringfct.insertItems(1, d["string"]) # self.ui.Rtree.insertItems(1,rtreecommand) # restore last query if needed @@ -116,11 +116,19 @@ def __init__(self, iface, db, parent=None, reset=False): self.ui.checkBox.stateChanged.connect(self.show_tables) if self.db.explicitSpatialIndex(): - self.tablesGeo = [table for table in self.tables if isinstance(table, VectorTable)] - tablesGeo = ['"%s"."%s"' % (table.name, table.geomColumn) for table in self.tablesGeo] + self.tablesGeo = [ + table for table in self.tables if isinstance(table, VectorTable) + ] + tablesGeo = [ + f'"{table.name}"."{table.geomColumn}"' for table in self.tablesGeo + ] self.ui.table_target.insertItems(1, tablesGeo) - self.idxTables = [table for table in self.tablesGeo if table.hasSpatialIndex()] - idxTables = ['"%s"."%s"' % (table.name, table.geomColumn) for table in self.idxTables] + self.idxTables = [ + table for table in self.tablesGeo if table.hasSpatialIndex() + ] + idxTables = [ + f'"{table.name}"."{table.geomColumn}"' for table in self.idxTables + ] self.ui.table_idx.insertItems(1, idxTables) self.ui.usertree.clicked.connect(self.use_rtree) @@ -199,16 +207,21 @@ def add_tables(self): if len(tableObj) != 1: return # No object with this name self.table = tableObj[0] - if (ag in self.coltables): # table already use - response = QMessageBox.question(self, "Table already used", "Do you want to add table %s again?" % ag, QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) + if ag in self.coltables: # table already use + response = QMessageBox.question( + self, + "Table already used", + "Do you want to add table %s again?" % ag, + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + ) if response == QMessageBox.StandardButton.No: return ag = self.table.quotedName() txt = self.ui.tab.text() if (txt is None) or (txt in ("", " ")): - self.ui.tab.setText('%s' % ag) + self.ui.tab.setText("%s" % ag) else: - self.ui.tab.setText('%s, %s' % (txt, ag)) + self.ui.tab.setText(f"{txt}, {ag}") self.ui.tables.setCurrentIndex(0) def add_columns(self): @@ -217,7 +230,12 @@ def add_columns(self): ag = self.ui.columns.currentText() if self.evt.focus == "where": # in where section if ag in self.col_where: # column already called in where section - response = QMessageBox.question(self, "Column already used in WHERE clause", "Do you want to add column %s again?" % ag, QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) + response = QMessageBox.question( + self, + "Column already used in WHERE clause", + "Do you want to add column %s again?" % ag, + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + ) if response == QMessageBox.StandardButton.No: self.ui.columns.setCurrentIndex(0) return @@ -225,7 +243,12 @@ def add_columns(self): self.col_where.append(ag) elif self.evt.focus == "col": if ag in self.col_col: # column already called in col section - response = QMessageBox.question(self, "Column already used in COLUMNS section", "Do you want to add column %s again?" % ag, QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) + response = QMessageBox.question( + self, + "Column already used in COLUMNS section", + "Do you want to add column %s again?" % ag, + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + ) if response == QMessageBox.StandardButton.No: self.ui.columns.setCurrentIndex(0) return @@ -249,12 +272,12 @@ def add_columns(self): def list_cols(self): table = self.table - if (table is None): + if table is None: return - if (table.name in self.coltables): + if table.name in self.coltables: return - columns = ['"%s"."%s"' % (table.name, col.name) for col in table.fields()] + columns = [f'"{table.name}"."{col.name}"' for col in table.fields()] # add special '*' column: columns = ['"%s".*' % table.name] + columns self.coltables.append(table.name) # table columns have been listed @@ -273,11 +296,13 @@ def list_values(self): # recover column and table: column = item.split(".") # "table".'column' table = column[0] - if column[1] == '*': + if column[1] == "*": return table = table[1:-1] - qtable = [t for t in self.tables if t.name.lower() == table.lower()][0].quotedName() + qtable = [t for t in self.tables if t.name.lower() == table.lower()][ + 0 + ].quotedName() if self.ui.extract.isChecked(): limit = 10 @@ -290,14 +315,14 @@ def query_item(self, index): value = index.data(Qt.ItemDataRole.EditRole) if value is None: - queryWord = 'NULL' + queryWord = "NULL" elif isinstance(value, (int, float)): queryWord = str(value) else: queryWord = self.db.connector.quoteString(value) - if queryWord.strip() != '': - self.ui.where.insertPlainText(' ' + queryWord) + if queryWord.strip() != "": + self.ui.where.insertPlainText(" " + queryWord) self.ui.where.setFocus() def use_rtree(self): @@ -308,12 +333,17 @@ def use_rtree(self): tab_idx = idx.split(".")[0][1:-1] # remove " col_idx = idx.split(".")[1][1:-1] # remove ' except: - QMessageBox.warning(self, "Use R-Tree", "All fields are necessary", QMessageBox.StandardButton.Cancel) + QMessageBox.warning( + self, + "Use R-Tree", + "All fields are necessary", + QMessageBox.StandardButton.Cancel, + ) tgt = self.ui.table_target.currentText() if tgt in (None, "", " ", "Table (Target)"): return - tgt_tab = tgt.split('.')[0][1:-1] - tgt_col = tgt.split('.')[1][1:-1] + tgt_tab = tgt.split(".")[0][1:-1] + tgt_col = tgt.split(".")[1][1:-1] sql = "" if self.ui.where.toPlainText() not in (None, "", " "): sql += "\nAND" @@ -337,15 +367,15 @@ def validate(self): query_group = str(self.ui.group.toPlainText()) query_order = str(self.ui.order.toPlainText()) query = "" - if query_col.strip() != '': - query += "SELECT %s \nFROM %s" % (query_col, query_table) - if query_where.strip() != '': + if query_col.strip() != "": + query += f"SELECT {query_col} \nFROM {query_table}" + if query_where.strip() != "": query += "\nWHERE %s" % query_where - if query_group.strip() != '': + if query_group.strip() != "": query += "\nGROUP BY %s" % query_group - if query_order.strip() != '': + if query_order.strip() != "": query += "\nORDER BY %s" % query_order - if query == '': + if query == "": return self.query = query @@ -377,11 +407,15 @@ def restoreLastQuery(self): # list previous colist: for tablename in self.coltables: # Retrieve table object from table name: - table = [table for table in self.tables if table.name.upper() == tablename.upper()] + table = [ + table + for table in self.tables + if table.name.upper() == tablename.upper() + ] if len(table) != 1: break table = table[0] - columns = ['"%s"."%s"' % (table.name, col.name) for col in table.fields()] + columns = [f'"{table.name}"."{col.name}"' for col in table.fields()] # first and second col combobox end = self.ui.columns.count() self.ui.columns.insertItems(end, columns) diff --git a/python/plugins/db_manager/dlg_sql_layer_window.py b/python/plugins/db_manager/dlg_sql_layer_window.py index 25bd49a1b204..6d3b6fb07b36 100644 --- a/python/plugins/db_manager/dlg_sql_layer_window.py +++ b/python/plugins/db_manager/dlg_sql_layer_window.py @@ -19,33 +19,31 @@ * * ***************************************************************************/ """ + from hashlib import md5 from qgis.PyQt import uic from qgis.PyQt.QtCore import Qt, pyqtSignal -from qgis.PyQt.QtWidgets import (QDialog, - QWidget, - QAction, - QApplication, - QStyledItemDelegate, - QMessageBox - ) -from qgis.PyQt.QtGui import (QKeySequence, - QCursor, - QClipboard, - QIcon, - QStandardItemModel, - QStandardItem - ) +from qgis.PyQt.QtWidgets import ( + QDialog, + QWidget, + QAction, + QApplication, + QStyledItemDelegate, + QMessageBox, +) +from qgis.PyQt.QtGui import ( + QKeySequence, + QCursor, + QClipboard, + QIcon, + QStandardItemModel, + QStandardItem, +) from qgis.PyQt.Qsci import QsciAPIs from qgis.PyQt.QtXml import QDomDocument -from qgis.core import ( - QgsProject, - QgsDataSourceUri, - QgsReadWriteContext, - QgsMapLayerType -) +from qgis.core import QgsProject, QgsDataSourceUri, QgsReadWriteContext, QgsMapLayerType from qgis.utils import OverrideCursor from .db_plugins import createDbPlugin @@ -63,7 +61,7 @@ gui.QgsCodeEditorSQL = SqlEdit -Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgSqlLayerWindow.ui')) +Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgSqlLayerWindow.ui")) import re @@ -80,16 +78,16 @@ def __init__(self, iface, layer, parent=None): uri = QgsDataSourceUri(layer.source()) dbplugin = None db = None - if layer.dataProvider().name() == 'postgres': - dbplugin = createDbPlugin('postgis', 'postgres') - elif layer.dataProvider().name() == 'spatialite': - dbplugin = createDbPlugin('spatialite', 'spatialite') - elif layer.dataProvider().name() == 'oracle': - dbplugin = createDbPlugin('oracle', 'oracle') - elif layer.dataProvider().name() == 'virtual': - dbplugin = createDbPlugin('vlayers', 'virtual') - elif layer.dataProvider().name() == 'ogr': - dbplugin = createDbPlugin('gpkg', 'gpkg') + if layer.dataProvider().name() == "postgres": + dbplugin = createDbPlugin("postgis", "postgres") + elif layer.dataProvider().name() == "spatialite": + dbplugin = createDbPlugin("spatialite", "spatialite") + elif layer.dataProvider().name() == "oracle": + dbplugin = createDbPlugin("oracle", "oracle") + elif layer.dataProvider().name() == "virtual": + dbplugin = createDbPlugin("vlayers", "virtual") + elif layer.dataProvider().name() == "ogr": + dbplugin = createDbPlugin("gpkg", "gpkg") if dbplugin: dbplugin.connectToUri(uri) db = dbplugin.db @@ -97,13 +95,22 @@ def __init__(self, iface, layer, parent=None): self.dbplugin = dbplugin self.db = db self.filter = "" - self.allowMultiColumnPk = isinstance(db, PGDatabase) # at the moment only PostgreSQL allows a primary key to span multiple columns, SpatiaLite doesn't - self.aliasSubQuery = isinstance(db, PGDatabase) # only PostgreSQL requires subqueries to be aliases + self.allowMultiColumnPk = isinstance( + db, PGDatabase + ) # at the moment only PostgreSQL allows a primary key to span multiple columns, SpatiaLite doesn't + self.aliasSubQuery = isinstance( + db, PGDatabase + ) # only PostgreSQL requires subqueries to be aliases self.setupUi(self) self.setWindowTitle( - "%s - %s [%s]" % (self.windowTitle(), db.connection().connectionName(), db.connection().typeNameString())) + "{} - {} [{}]".format( + self.windowTitle(), + db.connection().connectionName(), + db.connection().typeNameString(), + ) + ) - self.defaultLayerName = self.tr('QueryLayer') + self.defaultLayerName = self.tr("QueryLayer") if self.allowMultiColumnPk: self.uniqueColumnCheck.setText(self.tr("Column(s) with unique values")) @@ -147,9 +154,12 @@ def __init__(self, iface, layer, parent=None): self.uniqueCombo.setModel(self.uniqueModel) if self.allowMultiColumnPk: self.uniqueCombo.setItemDelegate(QStyledItemDelegate()) - self.uniqueModel.itemChanged.connect(self.uniqueChanged) # react to the (un)checking of an item + self.uniqueModel.itemChanged.connect( + self.uniqueChanged + ) # react to the (un)checking of an item self.uniqueCombo.lineEdit().textChanged.connect( - self.uniqueTextChanged) # there are other events that change the displayed text and some of them can not be caught directly + self.uniqueTextChanged + ) # there are other events that change the displayed text and some of them can not be caught directly self.layerTypeWidget.hide() # show if load as raster is supported # self.loadLayerBtn.clicked.connect(self.loadSqlLayer) @@ -164,28 +174,36 @@ def __init__(self, iface, layer, parent=None): # Update from layer # First the SQL from QgsDataSourceUri table - sql = uri.table().replace('\n', ' ').strip() - if uri.keyColumn() == '_uid_': - match = re.search(r'^\(SELECT .+ AS _uid_,\* FROM \((.*)\) AS _subq_.+_\s*\)$', sql, re.S | re.X | re.IGNORECASE) + sql = uri.table().replace("\n", " ").strip() + if uri.keyColumn() == "_uid_": + match = re.search( + r"^\(SELECT .+ AS _uid_,\* FROM \((.*)\) AS _subq_.+_\s*\)$", + sql, + re.S | re.X | re.IGNORECASE, + ) if match: sql = match.group(1) else: - match = re.search(r'^\((SELECT .+ FROM .+)\)$', sql, re.S | re.X | re.IGNORECASE) + match = re.search( + r"^\((SELECT .+ FROM .+)\)$", sql, re.S | re.X | re.IGNORECASE + ) if match: sql = match.group(1) # Need to check on table() since the parentheses were removed by the regexp - if not uri.table().startswith('(') and not uri.table().endswith(')'): + if not uri.table().startswith("(") and not uri.table().endswith(")"): schema = uri.schema() - if schema and schema.upper() != 'PUBLIC': - sql = 'SELECT * FROM {}.{}'.format(self.db.connector.quoteId(schema), self.db.connector.quoteId(sql)) + if schema and schema.upper() != "PUBLIC": + sql = f"SELECT * FROM {self.db.connector.quoteId(schema)}.{self.db.connector.quoteId(sql)}" else: - sql = 'SELECT * FROM {}'.format(self.db.connector.quoteId(sql)) + sql = f"SELECT * FROM {self.db.connector.quoteId(sql)}" self.editSql.setText(sql) self.executeSql() # Then the columns - self.geomCombo.setCurrentIndex(self.geomCombo.findText(uri.geometryColumn(), Qt.MatchFlag.MatchExactly)) - if uri.keyColumn() != '_uid_': + self.geomCombo.setCurrentIndex( + self.geomCombo.findText(uri.geometryColumn(), Qt.MatchFlag.MatchExactly) + ) + if uri.keyColumn() != "_uid_": self.uniqueColumnCheck.setCheckState(Qt.CheckState.Checked) if self.allowMultiColumnPk: # Unchecked default values @@ -193,7 +211,7 @@ def __init__(self, iface, layer, parent=None): if item.checkState() == Qt.CheckState.Checked: item.setCheckState(Qt.CheckState.Unchecked) # Get key columns - itemsData = uri.keyColumn().split(',') + itemsData = uri.keyColumn().split(",") # Checked key columns for keyColumn in itemsData: for item in self.uniqueModel.findItems(keyColumn): @@ -201,7 +219,9 @@ def __init__(self, iface, layer, parent=None): else: keyColumn = uri.keyColumn() if self.uniqueModel.findItems(keyColumn): - self.uniqueCombo.setCurrentIndex(self.uniqueCombo.findText(keyColumn, Qt.MatchFlag.MatchExactly)) + self.uniqueCombo.setCurrentIndex( + self.uniqueCombo.findText(keyColumn, Qt.MatchFlag.MatchExactly) + ) # Finally layer name, filter and selectAtId self.layerNameEdit.setText(layer.name()) @@ -210,21 +230,25 @@ def __init__(self, iface, layer, parent=None): self.avoidSelectById.setCheckState(Qt.CheckState.Checked) def getQueryHash(self, name): - return 'q%s' % md5(name.encode('utf8')).hexdigest() + return "q%s" % md5(name.encode("utf8")).hexdigest() def updatePresetButtonsState(self, *args): """Slot called when the combo box or the sql or the query name have changed: - sets store button state""" - self.presetStore.setEnabled(bool(self._getSqlQuery() and self.presetName.text())) + sets store button state""" + self.presetStore.setEnabled( + bool(self._getSqlQuery() and self.presetName.text()) + ) self.presetDelete.setEnabled(bool(self.presetCombo.currentIndex() != -1)) def updatePresetsCombobox(self): self.presetCombo.clear() names = [] - entries = QgsProject.instance().subkeyList('DBManager', 'savedQueries') + entries = QgsProject.instance().subkeyList("DBManager", "savedQueries") for entry in entries: - name = QgsProject.instance().readEntry('DBManager', 'savedQueries/' + entry + '/name')[0] + name = QgsProject.instance().readEntry( + "DBManager", "savedQueries/" + entry + "/name" + )[0] names.append(name) for name in sorted(names): @@ -236,8 +260,12 @@ def storePreset(self): if query == "": return name = self.presetName.text() - QgsProject.instance().writeEntry('DBManager', 'savedQueries/' + self.getQueryHash(name) + '/name', name) - QgsProject.instance().writeEntry('DBManager', 'savedQueries/' + self.getQueryHash(name) + '/query', query) + QgsProject.instance().writeEntry( + "DBManager", "savedQueries/" + self.getQueryHash(name) + "/name", name + ) + QgsProject.instance().writeEntry( + "DBManager", "savedQueries/" + self.getQueryHash(name) + "/query", query + ) index = self.presetCombo.findText(name) if index == -1: self.presetCombo.addItem(name) @@ -247,12 +275,16 @@ def storePreset(self): def deletePreset(self): name = self.presetCombo.currentText() - QgsProject.instance().removeEntry('DBManager', 'savedQueries/q' + self.getQueryHash(name)) + QgsProject.instance().removeEntry( + "DBManager", "savedQueries/q" + self.getQueryHash(name) + ) self.presetCombo.removeItem(self.presetCombo.findText(name)) self.presetCombo.setCurrentIndex(-1) def loadPreset(self, name): - query = QgsProject.instance().readEntry('DBManager', 'savedQueries/' + self.getQueryHash(name) + '/query')[0] + query = QgsProject.instance().readEntry( + "DBManager", "savedQueries/" + self.getQueryHash(name) + "/query" + )[0] self.editSql.setText(query) def clearSql(self): @@ -280,7 +312,11 @@ def executeSql(self): # set the new model model = self.db.sqlResultModel(sql, self) self.viewResult.setModel(model) - self.lblResult.setText(self.tr("{0} rows, {1:.3f} seconds").format(model.affectedRows(), model.secs())) + self.lblResult.setText( + self.tr("{0} rows, {1:.3f} seconds").format( + model.affectedRows(), model.secs() + ) + ) cols = self.viewResult.model().columnNames() for col in cols: quotedCols.append(self.db.connector.quoteId(col)) @@ -310,7 +346,9 @@ def _getSqlLayer(self, _filter): and not self.allowMultiColumnPk and self.uniqueCombo.currentIndex() >= 0 ): - uniqueFieldName = self.uniqueModel.item(self.uniqueCombo.currentIndex()).data() + uniqueFieldName = self.uniqueModel.item( + self.uniqueCombo.currentIndex() + ).data() else: uniqueFieldName = None hasGeomCol = self.hasGeometryCol.checkState() == Qt.CheckState.Checked @@ -324,10 +362,14 @@ def _getSqlLayer(self, _filter): return None # remove a trailing ';' from query if present - if query.strip().endswith(';'): + if query.strip().endswith(";"): query = query.strip()[:-1] - layerType = QgsMapLayerType.VectorLayer if self.vectorRadio.isChecked() else QgsMapLayerType.RasterLayer + layerType = ( + QgsMapLayerType.VectorLayer + if self.vectorRadio.isChecked() + else QgsMapLayerType.RasterLayer + ) # get a new layer name names = [] @@ -344,8 +386,15 @@ def _getSqlLayer(self, _filter): newLayerName = "%s_%d" % (layerName, index) # create the layer - layer = self.db.toSqlLayer(query, geomFieldName, uniqueFieldName, newLayerName, layerType, - self.avoidSelectById.isChecked(), _filter) + layer = self.db.toSqlLayer( + query, + geomFieldName, + uniqueFieldName, + newLayerName, + layerType, + self.avoidSelectById.isChecked(), + _filter, + ) if layer.isValid(): return layer else: @@ -371,7 +420,9 @@ def updateSqlLayer(self): XMLMapLayers = XMLDocument.createElement("maplayers") XMLMapLayer = XMLDocument.createElement("maplayer") self.layer.writeLayerXml(XMLMapLayer, XMLDocument, QgsReadWriteContext()) - XMLMapLayer.firstChildElement("datasource").firstChild().setNodeValue(layer.source()) + XMLMapLayer.firstChildElement("datasource").firstChild().setNodeValue( + layer.source() + ) XMLMapLayers.appendChild(XMLMapLayer) XMLDocument.appendChild(XMLMapLayers) self.layer.readLayerXml(XMLMapLayer, QgsReadWriteContext()) @@ -386,7 +437,7 @@ def fillColumnCombos(self): with OverrideCursor(Qt.CursorShape.WaitCursor): # remove a trailing ';' from query if present - if query.strip().endswith(';'): + if query.strip().endswith(";"): query = query.strip()[:-1] # get all the columns @@ -397,12 +448,14 @@ def fillColumnCombos(self): aliasIndex = 0 while True: alias = "_subQuery__%d" % aliasIndex - escaped = re.compile('\\b("?)' + re.escape(alias) + '\\1\\b') + escaped = re.compile('\\b("?)' + re.escape(alias) + "\\1\\b") if not escaped.search(query): break aliasIndex += 1 - sql = "SELECT * FROM (%s\n) AS %s LIMIT 0" % (str(query), connector.quoteId(alias)) + sql = "SELECT * FROM ({}\n) AS {} LIMIT 0".format( + str(query), connector.quoteId(alias) + ) else: sql = "SELECT * FROM (%s\n) WHERE 1=0" % str(query) @@ -429,18 +482,20 @@ def fillColumnCombos(self): def setColumnCombos(self, cols, quotedCols): # get sensible default columns. do this before sorting in case there's hints in the column order (e.g., id is more likely to be first) try: - defaultGeomCol = next(col for col in cols if col in ['geom', 'geometry', 'the_geom', 'way']) + defaultGeomCol = next( + col for col in cols if col in ["geom", "geometry", "the_geom", "way"] + ) except: defaultGeomCol = None try: - defaultUniqueCol = [col for col in cols if 'id' in col][0] + defaultUniqueCol = [col for col in cols if "id" in col][0] except: defaultUniqueCol = None colNames = sorted(zip(cols, quotedCols)) newItems = [] uniqueIsFilled = False - for (col, quotedCol) in colNames: + for col, quotedCol in colNames: item = QStandardItem(col) item.setData(quotedCol) item.setEnabled(True) @@ -450,7 +505,10 @@ def setColumnCombos(self, cols, quotedCols): matchingItems = self.uniqueModel.findItems(col) if matchingItems: item.setCheckState(matchingItems[0].checkState()) - uniqueIsFilled = uniqueIsFilled or matchingItems[0].checkState() == Qt.CheckState.Checked + uniqueIsFilled = ( + uniqueIsFilled + or matchingItems[0].checkState() == Qt.CheckState.Checked + ) else: item.setCheckState(Qt.CheckState.Unchecked) newItems.append(item) @@ -469,7 +527,9 @@ def setColumnCombos(self, cols, quotedCols): oldGeometryColumn = self.geomCombo.currentText() self.geomCombo.clear() self.geomCombo.addItems(cols) - self.geomCombo.setCurrentIndex(self.geomCombo.findText(oldGeometryColumn, Qt.MatchFlag.MatchExactly)) + self.geomCombo.setCurrentIndex( + self.geomCombo.findText(oldGeometryColumn, Qt.MatchFlag.MatchExactly) + ) # set sensible default columns if the columns are not already set try: @@ -550,6 +610,7 @@ def uniqueTextChanged(self, text): def setFilter(self): from qgis.gui import QgsQueryBuilder + layer = self._getSqlLayer("") if not layer: return @@ -566,9 +627,14 @@ def setHasChanged(self, hasChanged): def close(self): if self.hasChanged: ret = QMessageBox.question( - self, self.tr('Unsaved Changes?'), - self.tr('There are unsaved changes. Do you want to keep them?'), - QMessageBox.StandardButton.Save | QMessageBox.StandardButton.Cancel | QMessageBox.StandardButton.Discard, QMessageBox.StandardButton.Cancel) + self, + self.tr("Unsaved Changes?"), + self.tr("There are unsaved changes. Do you want to keep them?"), + QMessageBox.StandardButton.Save + | QMessageBox.StandardButton.Cancel + | QMessageBox.StandardButton.Discard, + QMessageBox.StandardButton.Cancel, + ) if ret == QMessageBox.StandardButton.Save: self.saveAsFilePreset() diff --git a/python/plugins/db_manager/dlg_sql_window.py b/python/plugins/db_manager/dlg_sql_window.py index 8109fa731ce3..fbf0f4c9fcb1 100644 --- a/python/plugins/db_manager/dlg_sql_window.py +++ b/python/plugins/db_manager/dlg_sql_window.py @@ -19,38 +19,35 @@ * * ***************************************************************************/ """ + from hashlib import md5 import os from qgis.PyQt import uic from qgis.PyQt.QtCore import Qt, pyqtSignal, QDir, QCoreApplication -from qgis.PyQt.QtWidgets import (QDialog, - QWidget, - QAction, - QApplication, - QInputDialog, - QStyledItemDelegate, - QTableWidgetItem, - QFileDialog, - QMessageBox - ) -from qgis.PyQt.QtGui import (QKeySequence, - QCursor, - QClipboard, - QIcon, - QStandardItemModel, - QStandardItem - ) +from qgis.PyQt.QtWidgets import ( + QDialog, + QWidget, + QAction, + QApplication, + QInputDialog, + QStyledItemDelegate, + QTableWidgetItem, + QFileDialog, + QMessageBox, +) +from qgis.PyQt.QtGui import ( + QKeySequence, + QCursor, + QClipboard, + QIcon, + QStandardItemModel, + QStandardItem, +) from qgis.PyQt.Qsci import QsciAPIs, QsciScintilla -from qgis.core import ( - QgsProject, - QgsApplication, - QgsTask, - QgsSettings, - QgsMapLayerType -) +from qgis.core import QgsProject, QgsApplication, QgsTask, QgsSettings, QgsMapLayerType from qgis.utils import OverrideCursor from .db_plugins.plugin import BaseError @@ -67,7 +64,7 @@ gui.QgsCodeEditorSQL = SqlEdit -Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgSqlWindow.ui')) +Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgSqlWindow.ui")) import re @@ -76,13 +73,10 @@ def check_comments_in_sql(raw_sql_input): lines = [] for line in raw_sql_input.splitlines(): - if not line.strip().startswith('--'): - if '--' in line: - comments = re.finditer(r'--', line) - comment_positions = [ - match.start() - for match in comments - ] + if not line.strip().startswith("--"): + if "--" in line: + comments = re.finditer(r"--", line) + comment_positions = [match.start() for match in comments] identifiers = re.finditer(r'"(?:[^"]|"")*"', line) quotes = re.finditer(r"'(?:[^']|'')*'", line) quote_positions = [] @@ -96,12 +90,12 @@ def check_comments_in_sql(raw_sql_input): if comment >= quote_position[0] and comment < quote_position[1]: unquoted_comments.remove(comment) if len(unquoted_comments) > 0: - lines.append(line[:unquoted_comments[0]]) + lines.append(line[: unquoted_comments[0]]) else: lines.append(line) else: lines.append(line) - sql = ' '.join(lines) + sql = " ".join(lines) return sql.strip() @@ -119,14 +113,20 @@ def __init__(self, iface, db, parent=None): self.connectionName = db.connection().connectionName() self.filter = "" self.modelAsync = None - self.allowMultiColumnPk = isinstance(db, - PGDatabase) # at the moment only PostgreSQL allows a primary key to span multiple columns, SpatiaLite doesn't - self.aliasSubQuery = isinstance(db, PGDatabase) # only PostgreSQL requires subqueries to be aliases + self.allowMultiColumnPk = isinstance( + db, PGDatabase + ) # at the moment only PostgreSQL allows a primary key to span multiple columns, SpatiaLite doesn't + self.aliasSubQuery = isinstance( + db, PGDatabase + ) # only PostgreSQL requires subqueries to be aliases self.setupUi(self) self.setWindowTitle( - self.tr("{0} - {1} [{2}]").format(self.windowTitle(), self.connectionName, self.dbType)) + self.tr("{0} - {1} [{2}]").format( + self.windowTitle(), self.connectionName, self.dbType + ) + ) - self.defaultLayerName = self.tr('QueryLayer') + self.defaultLayerName = self.tr("QueryLayer") if self.allowMultiColumnPk: self.uniqueColumnCheck.setText(self.tr("Column(s) with unique values")) @@ -140,7 +140,9 @@ def __init__(self, iface, db, parent=None): self.editSql.textChanged.connect(lambda: self.setHasChanged(True)) settings = QgsSettings() - self.history = settings.value('DB_Manager/queryHistory/' + self.dbType, {self.connectionName: []}) + self.history = settings.value( + "DB_Manager/queryHistory/" + self.dbType, {self.connectionName: []} + ) if self.connectionName not in self.history: self.history[self.connectionName] = [] @@ -188,9 +190,12 @@ def __init__(self, iface, db, parent=None): self.uniqueCombo.setModel(self.uniqueModel) if self.allowMultiColumnPk: self.uniqueCombo.setItemDelegate(QStyledItemDelegate()) - self.uniqueModel.itemChanged.connect(self.uniqueChanged) # react to the (un)checking of an item + self.uniqueModel.itemChanged.connect( + self.uniqueChanged + ) # react to the (un)checking of an item self.uniqueCombo.lineEdit().textChanged.connect( - self.uniqueTextChanged) # there are other events that change the displayed text and some of them can not be caught directly + self.uniqueTextChanged + ) # there are other events that change the displayed text and some of them can not be caught directly # hide the load query as layer if feature is not supported self._loadAsLayerAvailable = self.db.connector.hasCustomQuerySupport() @@ -230,9 +235,9 @@ def populateQueryHistory(self): for i in range(len(dictlist)): self.queryHistoryTableWidget.insertRow(0) - queryItem = QTableWidgetItem(dictlist[i]['query']) - rowsItem = QTableWidgetItem(str(dictlist[i]['rows'])) - durationItem = QTableWidgetItem(str(dictlist[i]['secs'])) + queryItem = QTableWidgetItem(dictlist[i]["query"]) + rowsItem = QTableWidgetItem(str(dictlist[i]["rows"])) + durationItem = QTableWidgetItem(str(dictlist[i]["secs"])) self.queryHistoryTableWidget.setItem(0, 0, queryItem) self.queryHistoryTableWidget.setItem(0, 1, rowsItem) self.queryHistoryTableWidget.setItem(0, 2, durationItem) @@ -245,23 +250,25 @@ def writeQueryHistory(self, sql, affectedRows, secs): self.history[self.connectionName].pop(0) settings = QgsSettings() - self.history[self.connectionName].append({'query': sql, - 'rows': affectedRows, - 'secs': secs}) - settings.setValue('DB_Manager/queryHistory/' + self.dbType, self.history) + self.history[self.connectionName].append( + {"query": sql, "rows": affectedRows, "secs": secs} + ) + settings.setValue("DB_Manager/queryHistory/" + self.dbType, self.history) self.populateQueryHistory() def getQueryHash(self, name): - return 'q%s' % md5(name.encode('utf8')).hexdigest() + return "q%s" % md5(name.encode("utf8")).hexdigest() def updatePresetsCombobox(self): self.presetCombo.clear() names = [] - entries = QgsProject.instance().subkeyList('DBManager', 'savedQueries') + entries = QgsProject.instance().subkeyList("DBManager", "savedQueries") for entry in entries: - name = QgsProject.instance().readEntry('DBManager', 'savedQueries/' + entry + '/name')[0] + name = QgsProject.instance().readEntry( + "DBManager", "savedQueries/" + entry + "/name" + )[0] names.append(name) for name in sorted(names): @@ -273,8 +280,12 @@ def storePreset(self): if query == "": return name = str(self.presetName.text()) - QgsProject.instance().writeEntry('DBManager', 'savedQueries/' + self.getQueryHash(name) + '/name', name) - QgsProject.instance().writeEntry('DBManager', 'savedQueries/' + self.getQueryHash(name) + '/query', query) + QgsProject.instance().writeEntry( + "DBManager", "savedQueries/" + self.getQueryHash(name) + "/name", name + ) + QgsProject.instance().writeEntry( + "DBManager", "savedQueries/" + self.getQueryHash(name) + "/query", query + ) index = self.presetCombo.findText(name) if index == -1: self.presetCombo.addItem(name) @@ -284,36 +295,35 @@ def storePreset(self): def saveAsFilePreset(self): settings = QgsSettings() - lastDir = settings.value('DB_Manager/lastDirSQLFIle', "") + lastDir = settings.value("DB_Manager/lastDirSQLFIle", "") query = self.editSql.text() if query == "": return filename, _ = QFileDialog.getSaveFileName( - self, - self.tr('Save SQL Query'), - lastDir, - self.tr("SQL File (*.sql *.SQL)")) + self, self.tr("Save SQL Query"), lastDir, self.tr("SQL File (*.sql *.SQL)") + ) if filename: - if not filename.lower().endswith('.sql'): + if not filename.lower().endswith(".sql"): filename += ".sql" - with open(filename, 'w') as f: + with open(filename, "w") as f: f.write(query) lastDir = os.path.dirname(filename) - settings.setValue('DB_Manager/lastDirSQLFile', lastDir) + settings.setValue("DB_Manager/lastDirSQLFile", lastDir) def loadFilePreset(self): settings = QgsSettings() - lastDir = settings.value('DB_Manager/lastDirSQLFIle', "") + lastDir = settings.value("DB_Manager/lastDirSQLFIle", "") filename, _ = QFileDialog.getOpenFileName( self, self.tr("Load SQL Query"), lastDir, - self.tr("SQL File (*.sql *.SQL);;All Files (*)")) + self.tr("SQL File (*.sql *.SQL);;All Files (*)"), + ) if filename: with open(filename) as f: @@ -321,16 +331,20 @@ def loadFilePreset(self): for line in f: self.editSql.insertText(line) lastDir = os.path.dirname(filename) - settings.setValue('DB_Manager/lastDirSQLFile', lastDir) + settings.setValue("DB_Manager/lastDirSQLFile", lastDir) def deletePreset(self): name = self.presetCombo.currentText() - QgsProject.instance().removeEntry('DBManager', 'savedQueries/' + self.getQueryHash(name)) + QgsProject.instance().removeEntry( + "DBManager", "savedQueries/" + self.getQueryHash(name) + ) self.presetCombo.removeItem(self.presetCombo.findText(name)) self.presetCombo.setCurrentIndex(-1) def loadPreset(self, name): - query = QgsProject.instance().readEntry('DBManager', 'savedQueries/' + self.getQueryHash(name) + '/query')[0] + query = QgsProject.instance().readEntry( + "DBManager", "savedQueries/" + self.getQueryHash(name) + "/query" + )[0] self.editSql.setText(query) def loadAsLayerToggled(self, checked): @@ -391,16 +405,19 @@ def executeSqlCompleted(self): model = self.modelAsync.model self.showError(None) self.viewResult.setModel(model) - self.lblResult.setText(self.tr("{0} rows, {1:.3f} seconds").format(model.affectedRows(), model.secs())) + self.lblResult.setText( + self.tr("{0} rows, {1:.3f} seconds").format( + model.affectedRows(), model.secs() + ) + ) cols = self.viewResult.model().columnNames() - quotedCols = [ - self.db.connector.quoteId(col) - for col in cols - ] + quotedCols = [self.db.connector.quoteId(col) for col in cols] self.setColumnCombos(cols, quotedCols) - self.writeQueryHistory(self.modelAsync.task.sql, model.affectedRows(), model.secs()) + self.writeQueryHistory( + self.modelAsync.task.sql, model.affectedRows(), model.secs() + ) self.update() elif not self.modelAsync.canceled: self.showError(self.modelAsync.error) @@ -433,7 +450,7 @@ def executeSql(self): return def showError(self, error): - '''Shows the error or hides it if error is None''' + """Shows the error or hides it if error is None""" if error: self.viewResult.setVisible(False) self.errorText.setVisible(True) @@ -456,7 +473,9 @@ def _getSqlLayer(self, _filter): and not self.allowMultiColumnPk and self.uniqueCombo.currentIndex() >= 0 ): - uniqueFieldName = self.uniqueModel.item(self.uniqueCombo.currentIndex()).data() + uniqueFieldName = self.uniqueModel.item( + self.uniqueCombo.currentIndex() + ).data() else: uniqueFieldName = None hasGeomCol = self.hasGeometryCol.checkState() == Qt.CheckState.Checked @@ -470,10 +489,14 @@ def _getSqlLayer(self, _filter): return None # remove a trailing ';' from query if present - if query.strip().endswith(';'): + if query.strip().endswith(";"): query = query.strip()[:-1] - layerType = QgsMapLayerType.VectorLayer if self.vectorRadio.isChecked() else QgsMapLayerType.RasterLayer + layerType = ( + QgsMapLayerType.VectorLayer + if self.vectorRadio.isChecked() + else QgsMapLayerType.RasterLayer + ) # get a new layer name names = [] @@ -490,12 +513,23 @@ def _getSqlLayer(self, _filter): newLayerName = "%s_%d" % (layerName, index) # create the layer - layer = self.db.toSqlLayer(query, geomFieldName, uniqueFieldName, newLayerName, layerType, - self.avoidSelectById.isChecked(), _filter) + layer = self.db.toSqlLayer( + query, + geomFieldName, + uniqueFieldName, + newLayerName, + layerType, + self.avoidSelectById.isChecked(), + _filter, + ) if layer.isValid(): return layer else: - e = BaseError(self.tr("There was an error creating the SQL layer, please check the logs for further information.")) + e = BaseError( + self.tr( + "There was an error creating the SQL layer, please check the logs for further information." + ) + ) DlgDbError.showError(e, self) return None @@ -514,7 +548,7 @@ def fillColumnCombos(self): with OverrideCursor(Qt.CursorShape.WaitCursor): # remove a trailing ';' from query if present - if query.strip().endswith(';'): + if query.strip().endswith(";"): query = query.strip()[:-1] # get all the columns @@ -525,12 +559,14 @@ def fillColumnCombos(self): aliasIndex = 0 while True: alias = "_subQuery__%d" % aliasIndex - escaped = re.compile('\\b("?)' + re.escape(alias) + '\\1\\b') + escaped = re.compile('\\b("?)' + re.escape(alias) + "\\1\\b") if not escaped.search(query): break aliasIndex += 1 - sql = "SELECT * FROM (%s\n) AS %s LIMIT 0" % (str(query), connector.quoteId(alias)) + sql = "SELECT * FROM ({}\n) AS {} LIMIT 0".format( + str(query), connector.quoteId(alias) + ) else: sql = "SELECT * FROM (%s\n) WHERE 1=0" % str(query) @@ -557,18 +593,20 @@ def fillColumnCombos(self): def setColumnCombos(self, cols, quotedCols): # get sensible default columns. do this before sorting in case there's hints in the column order (e.g., id is more likely to be first) try: - defaultGeomCol = next(col for col in cols if col in ['geom', 'geometry', 'the_geom', 'way']) + defaultGeomCol = next( + col for col in cols if col in ["geom", "geometry", "the_geom", "way"] + ) except: defaultGeomCol = None try: - defaultUniqueCol = [col for col in cols if 'id' in col][0] + defaultUniqueCol = [col for col in cols if "id" in col][0] except: defaultUniqueCol = None colNames = sorted(zip(cols, quotedCols)) newItems = [] uniqueIsFilled = False - for (col, quotedCol) in colNames: + for col, quotedCol in colNames: item = QStandardItem(col) item.setData(quotedCol) item.setEnabled(True) @@ -578,7 +616,10 @@ def setColumnCombos(self, cols, quotedCols): matchingItems = self.uniqueModel.findItems(col) if matchingItems: item.setCheckState(matchingItems[0].checkState()) - uniqueIsFilled = uniqueIsFilled or matchingItems[0].checkState() == Qt.CheckState.Checked + uniqueIsFilled = ( + uniqueIsFilled + or matchingItems[0].checkState() == Qt.CheckState.Checked + ) else: item.setCheckState(Qt.CheckState.Unchecked) newItems.append(item) @@ -597,7 +638,9 @@ def setColumnCombos(self, cols, quotedCols): oldGeometryColumn = self.geomCombo.currentText() self.geomCombo.clear() self.geomCombo.addItems(cols) - self.geomCombo.setCurrentIndex(self.geomCombo.findText(oldGeometryColumn, Qt.MatchFlag.MatchExactly)) + self.geomCombo.setCurrentIndex( + self.geomCombo.findText(oldGeometryColumn, Qt.MatchFlag.MatchExactly) + ) # set sensible default columns if the columns are not already set try: @@ -655,7 +698,9 @@ def displayQueryBuilder(self): self.editSql.setText(dlg.query) def createView(self): - name, ok = QInputDialog.getText(None, self.tr("View Name"), self.tr("View name")) + name, ok = QInputDialog.getText( + None, self.tr("View Name"), self.tr("View name") + ) if ok: try: self.db.connector.createSpatialView(name, self._getExecutableSqlQuery()) @@ -672,7 +717,7 @@ def _getExecutableSqlQuery(self): sql = self._getSqlQuery().strip() uncommented_sql = check_comments_in_sql(sql) - uncommented_sql = uncommented_sql.rstrip(';') + uncommented_sql = uncommented_sql.rstrip(";") return uncommented_sql def uniqueChanged(self): @@ -691,6 +736,7 @@ def uniqueTextChanged(self, text): def setFilter(self): from qgis.gui import QgsQueryBuilder + layer = self._getSqlLayer("") if not layer: return @@ -707,9 +753,14 @@ def setHasChanged(self, hasChanged): def close(self): if self.hasChanged: ret = QMessageBox.question( - self, self.tr('Unsaved Changes?'), - self.tr('There are unsaved changes. Do you want to keep them?'), - QMessageBox.StandardButton.Save | QMessageBox.StandardButton.Cancel | QMessageBox.StandardButton.Discard, QMessageBox.StandardButton.Cancel) + self, + self.tr("Unsaved Changes?"), + self.tr("There are unsaved changes. Do you want to keep them?"), + QMessageBox.StandardButton.Save + | QMessageBox.StandardButton.Cancel + | QMessageBox.StandardButton.Discard, + QMessageBox.StandardButton.Cancel, + ) if ret == QMessageBox.StandardButton.Save: self.saveAsFilePreset() diff --git a/python/plugins/db_manager/dlg_table_properties.py b/python/plugins/db_manager/dlg_table_properties.py index 36b9d7357162..879d712ac99e 100644 --- a/python/plugins/db_manager/dlg_table_properties.py +++ b/python/plugins/db_manager/dlg_table_properties.py @@ -26,7 +26,11 @@ from qgis.utils import OverrideCursor -from .db_plugins.data_model import TableFieldsModel, TableConstraintsModel, TableIndexesModel +from .db_plugins.data_model import ( + TableFieldsModel, + TableConstraintsModel, + TableIndexesModel, +) from .db_plugins.plugin import BaseError, DbError from .dlg_db_error import DlgDbError @@ -37,7 +41,7 @@ from .gui_utils import GuiUtils -Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path('DlgTableProperties.ui')) +Ui_Dialog, _ = uic.loadUiType(GuiUtils.get_ui_file_path("DlgTableProperties.ui")) class DlgTableProperties(QDialog, Ui_Dialog): @@ -95,8 +99,16 @@ def checkSupports(self): self.btnEditColumn.setEnabled(allowEditColumns) self.btnDeleteColumn.setEnabled(allowEditColumns) - self.btnAddGeometryColumn.setEnabled(self.db.connector.canAddGeometryColumn((self.table.schemaName(), self.table.name))) - self.btnAddSpatialIndex.setEnabled(self.db.connector.canAddSpatialIndex((self.table.schemaName(), self.table.name))) + self.btnAddGeometryColumn.setEnabled( + self.db.connector.canAddGeometryColumn( + (self.table.schemaName(), self.table.name) + ) + ) + self.btnAddSpatialIndex.setEnabled( + self.db.connector.canAddSpatialIndex( + (self.table.schemaName(), self.table.name) + ) + ) def populateViews(self): self.populateFields() @@ -104,7 +116,7 @@ def populateViews(self): self.populateIndexes() def populateFields(self): - """ load field information from database """ + """load field information from database""" m = self.viewFields.model() m.clear() @@ -115,16 +127,18 @@ def populateFields(self): self.viewFields.resizeColumnToContents(col) def currentColumn(self): - """ returns row index of selected column """ + """returns row index of selected column""" sel = self.viewFields.selectionModel() indexes = sel.selectedRows() if len(indexes) == 0: - QMessageBox.information(self, self.tr("DB Manager"), self.tr("No columns were selected.")) + QMessageBox.information( + self, self.tr("DB Manager"), self.tr("No columns were selected.") + ) return -1 return indexes[0].row() def addColumn(self): - """ open dialog to set column info and add column to table """ + """open dialog to set column info and add column to table""" dlg = DlgFieldProperties(self, None, self.table) if not dlg.exec(): return @@ -140,14 +154,14 @@ def addColumn(self): DlgDbError.showError(e, self) def addGeometryColumn(self): - """ open dialog to add geometry column """ + """open dialog to add geometry column""" dlg = DlgAddGeometryColumn(self, self.table) if not dlg.exec(): return self.refresh() def editColumn(self): - """ open dialog to change column info and alter table appropriately """ + """open dialog to change column info and alter table appropriately""" index = self.currentColumn() if index == -1: return @@ -165,13 +179,19 @@ def editColumn(self): with OverrideCursor(Qt.CursorShape.WaitCursor): self.aboutToChangeTable.emit() try: - fld.update(new_fld.name, new_fld.type2String(), new_fld.notNull, new_fld.default2String(), new_fld.comment) + fld.update( + new_fld.name, + new_fld.type2String(), + new_fld.notNull, + new_fld.default2String(), + new_fld.comment, + ) self.refresh() except BaseError as e: DlgDbError.showError(e, self) def deleteColumn(self): - """Deletes currently selected column """ + """Deletes currently selected column""" index = self.currentColumn() if index == -1: return @@ -179,9 +199,12 @@ def deleteColumn(self): m = self.viewFields.model() fld = m.getObject(index) - res = QMessageBox.question(self, self.tr("Delete Column"), - self.tr("Are you sure you want to delete column '{0}'?").format(fld.name), - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) + res = QMessageBox.question( + self, + self.tr("Delete Column"), + self.tr("Are you sure you want to delete column '{0}'?").format(fld.name), + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + ) if res != QMessageBox.StandardButton.Yes: return @@ -214,7 +237,7 @@ def hideConstraints(self): self.tabs.setTabEnabled(index, False) def addConstraint(self): - """Adds primary key or unique constraint """ + """Adds primary key or unique constraint""" dlg = DlgCreateConstraint(self, self.table) if not dlg.exec(): @@ -222,7 +245,7 @@ def addConstraint(self): self.refresh() def deleteConstraint(self): - """Deletes a constraint """ + """Deletes a constraint""" index = self.currentConstraint() if index == -1: @@ -231,9 +254,14 @@ def deleteConstraint(self): m = self.viewConstraints.model() constr = m.getObject(index) - res = QMessageBox.question(self, self.tr("Delete Constraint"), - self.tr("Are you sure you want to delete constraint '{0}'?").format(constr.name), - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) + res = QMessageBox.question( + self, + self.tr("Delete Constraint"), + self.tr("Are you sure you want to delete constraint '{0}'?").format( + constr.name + ), + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + ) if res != QMessageBox.StandardButton.Yes: return @@ -246,11 +274,13 @@ def deleteConstraint(self): DlgDbError.showError(e, self) def currentConstraint(self): - """ returns row index of selected index """ + """returns row index of selected index""" sel = self.viewConstraints.selectionModel() indexes = sel.selectedRows() if len(indexes) == 0: - QMessageBox.information(self, self.tr("DB Manager"), self.tr("No constraints were selected.")) + QMessageBox.information( + self, self.tr("DB Manager"), self.tr("No constraints were selected.") + ) return -1 return indexes[0].row() @@ -275,21 +305,30 @@ def hideIndexes(self): self.tabs.setTabEnabled(index, False) def createIndex(self): - """Creates an index """ + """Creates an index""" dlg = DlgCreateIndex(self, self.table) if not dlg.exec(): return self.refresh() def createSpatialIndex(self): - """Creates spatial index for the geometry column """ + """Creates spatial index for the geometry column""" if self.table.type != self.table.VectorType: - QMessageBox.information(self, self.tr("DB Manager"), self.tr("The selected table has no geometry.")) + QMessageBox.information( + self, + self.tr("DB Manager"), + self.tr("The selected table has no geometry."), + ) return - res = QMessageBox.question(self, self.tr("Create Spatial Index"), - self.tr("Create spatial index for field {0}?").format(self.table.geomColumn), - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) + res = QMessageBox.question( + self, + self.tr("Create Spatial Index"), + self.tr("Create spatial index for field {0}?").format( + self.table.geomColumn + ), + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + ) if res != QMessageBox.StandardButton.Yes: return @@ -304,16 +343,18 @@ def createSpatialIndex(self): DlgDbError.showError(e, self) def currentIndex(self): - """ returns row index of selected index """ + """returns row index of selected index""" sel = self.viewIndexes.selectionModel() indexes = sel.selectedRows() if len(indexes) == 0: - QMessageBox.information(self, self.tr("DB Manager"), self.tr("No indices were selected.")) + QMessageBox.information( + self, self.tr("DB Manager"), self.tr("No indices were selected.") + ) return -1 return indexes[0].row() def deleteIndex(self): - """Deletes currently selected index """ + """Deletes currently selected index""" index = self.currentIndex() if index == -1: return @@ -321,9 +362,12 @@ def deleteIndex(self): m = self.viewIndexes.model() idx = m.getObject(index) - res = QMessageBox.question(self, self.tr("Delete Index"), - self.tr("Are you sure you want to delete index '{0}'?").format(idx.name), - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) + res = QMessageBox.question( + self, + self.tr("Delete Index"), + self.tr("Are you sure you want to delete index '{0}'?").format(idx.name), + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + ) if res != QMessageBox.StandardButton.Yes: return @@ -347,7 +391,9 @@ def createComment(self): return self.refresh() # Display successful message - QMessageBox.information(self, self.tr("Add comment"), self.tr("Table successfully commented")) + QMessageBox.information( + self, self.tr("Add comment"), self.tr("Table successfully commented") + ) def deleteComment(self): """Drops the comment on the selected table""" @@ -360,6 +406,8 @@ def deleteComment(self): return self.refresh() # Refresh line edit, put a void comment - self.viewComment.setText('') + self.viewComment.setText("") # Display successful message - QMessageBox.information(self, self.tr("Delete comment"), self.tr("Comment deleted")) + QMessageBox.information( + self, self.tr("Delete comment"), self.tr("Comment deleted") + ) diff --git a/python/plugins/db_manager/gui_utils.py b/python/plugins/db_manager/gui_utils.py index 2d9994538568..b0b169f4a0a4 100644 --- a/python/plugins/db_manager/gui_utils.py +++ b/python/plugins/db_manager/gui_utils.py @@ -14,11 +14,7 @@ import os from typing import Optional, Dict -from qgis.PyQt.QtGui import ( - QIcon, - QImage, - QPixmap -) +from qgis.PyQt.QtGui import QIcon, QImage, QPixmap class GuiUtils: @@ -26,7 +22,7 @@ class GuiUtils: Utilities for GUI plugin components """ - ICON_CACHE: Dict[str, QIcon] = {} + ICON_CACHE: dict[str, QIcon] = {} @staticmethod def get_icon(icon: str) -> QIcon: @@ -62,12 +58,9 @@ def get_icon_svg(icon: str) -> str: :param icon: icon name (base part of file name) :return: icon svg path """ - path = os.path.join( - os.path.dirname(__file__), - 'icons', - icon + '.svg') + path = os.path.join(os.path.dirname(__file__), "icons", icon + ".svg") if not os.path.exists(path): - return '' + return "" return path @@ -76,11 +69,8 @@ def get_pixmap_path(icon: str) -> Optional[str]: """ Returns the path to a pixmap icon """ - for suffix in ('.png', '.gif', '.xpm'): - path = os.path.join( - os.path.dirname(__file__), - 'icons', - icon + suffix) + for suffix in (".png", ".gif", ".xpm"): + path = os.path.join(os.path.dirname(__file__), "icons", icon + suffix) if os.path.exists(path): return path @@ -107,11 +97,8 @@ def get_ui_file_path(file: str) -> str: :param file: file name (uifile name) :return: ui file path """ - path = os.path.join( - os.path.dirname(__file__), - 'ui', - file) + path = os.path.join(os.path.dirname(__file__), "ui", file) if not os.path.exists(path): - return '' + return "" return path diff --git a/python/plugins/db_manager/info_viewer.py b/python/plugins/db_manager/info_viewer.py index 67d0c6730974..567c959a9b2c 100644 --- a/python/plugins/db_manager/info_viewer.py +++ b/python/plugins/db_manager/info_viewer.py @@ -95,14 +95,21 @@ def _clear(self): def _showPluginInfo(self): from .db_plugins import getDbPluginErrors - html = '

 ' + self.tr("DB Manager") + '

' + html = ( + '

 ' + + self.tr("DB Manager") + + "

" + ) html += '
' for msg in getDbPluginErrors(): html += "

%s" % msg self.setHtml(html) def _showDatabaseInfo(self, connection): - html = '

 %s

' % connection.connectionName() + html = ( + '

 %s

' + % connection.connectionName() + ) html += '
' try: if connection.database() is None: @@ -110,38 +117,47 @@ def _showDatabaseInfo(self, connection): else: html += connection.database().info().toHtml() except DbError as e: - html += '

%s

' % str(e).replace('\n', '
') - html += '
' + html += '

%s

' % str(e).replace("\n", "
") + html += "
" self.setHtml(html) def _showSchemaInfo(self, schema): - html = '

 %s

' % schema.name + html = ( + '

 %s

' + % schema.name + ) html += '
' try: html += schema.info().toHtml() except DbError as e: - html += '

%s

' % str(e).replace('\n', '
') + html += '

%s

' % str(e).replace("\n", "
") html += "
" self.setHtml(html) def _showTableInfo(self, table): - html = '

 %s

' % table.name + html = ( + '

 %s

' + % table.name + ) html += '
' try: html += table.info().toHtml() except DbError as e: - html += '

%s

' % str(e).replace('\n', '
') - html += '
' + html += '

%s

' % str(e).replace("\n", "
") + html += "" self.setHtml(html) return True def setHtml(self, html): # convert special tags - warning_icon_path = GuiUtils.get_pixmap_path('warning-20px') - html = str(html).replace('', f'   ') + warning_icon_path = GuiUtils.get_pixmap_path("warning-20px") + html = str(html).replace( + "", f'   ' + ) # add default style - html = """ + html = ( + """ @@ -158,7 +174,9 @@ def setHtml(self, html): %s
-""" % html +""" + % html + ) # print(">>>>>\n", html, "\n<<<<<<") return QTextBrowser.setHtml(self, html) diff --git a/python/plugins/db_manager/layer_preview.py b/python/plugins/db_manager/layer_preview.py index 04ddcff975d9..02afb303331b 100644 --- a/python/plugins/db_manager/layer_preview.py +++ b/python/plugins/db_manager/layer_preview.py @@ -42,7 +42,9 @@ def __init__(self, parent=None): # reuse settings from QGIS settings = QgsSettings() - self.enableAntiAliasing(settings.value("/qgis/enable_anti_aliasing", False, type=bool)) + self.enableAntiAliasing( + settings.value("/qgis/enable_anti_aliasing", False, type=bool) + ) zoomFactor = settings.value("/qgis/zoom_factor", 2, type=float) self.setWheelFactor(zoomFactor) @@ -59,7 +61,10 @@ def loadPreview(self, item): self._clear() - if isinstance(item, Table) and item.type in [Table.VectorType, Table.RasterType]: + if isinstance(item, Table) and item.type in [ + Table.VectorType, + Table.RasterType, + ]: # update the preview, but first let the manager chance to show the canvas def runPrev(): return self._loadTablePreview(item) @@ -75,7 +80,7 @@ def setDirty(self, val=True): self.dirty = val def _clear(self): - """ remove any layers from preview canvas """ + """remove any layers from preview canvas""" if self.item is not None: # skip exception on RuntimeError fixes #6892 try: @@ -88,7 +93,7 @@ def _clear(self): self._loadTablePreview(None) def _loadTablePreview(self, table, limit=False): - """ if has geometry column load to map canvas """ + """if has geometry column load to map canvas""" with OverrideCursor(Qt.CursorShape.WaitCursor): self.freeze() vl = None @@ -100,13 +105,22 @@ def _loadTablePreview(self, table, limit=False): if uniqueField is None: self.parent.tabs.setCurrentWidget(self.parent.info) self.parent.infoBar.pushMessage( - QApplication.translate("DBManagerPlugin", "Unable to find a valid unique field"), - Qgis.MessageLevel.Warning, self.parent.iface.messageTimeout()) + QApplication.translate( + "DBManagerPlugin", "Unable to find a valid unique field" + ), + Qgis.MessageLevel.Warning, + self.parent.iface.messageTimeout(), + ) return uri = table.database().uri() - uri.setDataSource("", "(SELECT * FROM %s LIMIT 1000)" % table.quotedName(), table.geomColumn, "", - uniqueField.name) + uri.setDataSource( + "", + "(SELECT * FROM %s LIMIT 1000)" % table.quotedName(), + table.geomColumn, + "", + uniqueField.name, + ) provider = table.database().dbplugin().providerName() vl = QgsVectorLayer(uri.uri(False), table.name, provider) else: diff --git a/python/plugins/db_manager/sql_dictionary.py b/python/plugins/db_manager/sql_dictionary.py index e22449dffa21..3bdf96e93b9c 100644 --- a/python/plugins/db_manager/sql_dictionary.py +++ b/python/plugins/db_manager/sql_dictionary.py @@ -15,36 +15,149 @@ *************************************************************************** """ -__author__ = 'Giuseppe Sucameli' -__date__ = 'April 2012' -__copyright__ = '(C) 2012, Giuseppe Sucameli' +__author__ = "Giuseppe Sucameli" +__date__ = "April 2012" +__copyright__ = "(C) 2012, Giuseppe Sucameli" # GENERIC SQL DICTIONARY # keywords keywords = [ - "action", "add", "after", "all", "alter", "analyze", "and", "as", "asc", - "before", "begin", "between", "by", "cascade", "case", "cast", "check", - "collate", "column", "commit", "constraint", "create", "cross", "current_date", - "current_time", "current_timestamp", "default", "deferrable", "deferred", - "delete", "desc", "distinct", "drop", "each", "else", "end", "escape", - "except", "exists", "for", "foreign", "from", "full", "group", "having", - "ignore", "immediate", "in", "initially", "inner", "insert", "intersect", - "into", "is", "isnull", "join", "key", "left", "like", "limit", "match", - "natural", "no", "not", "notnull", "null", "of", "offset", "on", "or", "order", - "outer", "primary", "references", "release", "restrict", "right", "rollback", - "row", "savepoint", "select", "set", "table", "temporary", "then", "to", - "transaction", "trigger", "union", "unique", "update", "using", "values", - "view", "when", "where" + "action", + "add", + "after", + "all", + "alter", + "analyze", + "and", + "as", + "asc", + "before", + "begin", + "between", + "by", + "cascade", + "case", + "cast", + "check", + "collate", + "column", + "commit", + "constraint", + "create", + "cross", + "current_date", + "current_time", + "current_timestamp", + "default", + "deferrable", + "deferred", + "delete", + "desc", + "distinct", + "drop", + "each", + "else", + "end", + "escape", + "except", + "exists", + "for", + "foreign", + "from", + "full", + "group", + "having", + "ignore", + "immediate", + "in", + "initially", + "inner", + "insert", + "intersect", + "into", + "is", + "isnull", + "join", + "key", + "left", + "like", + "limit", + "match", + "natural", + "no", + "not", + "notnull", + "null", + "of", + "offset", + "on", + "or", + "order", + "outer", + "primary", + "references", + "release", + "restrict", + "right", + "rollback", + "row", + "savepoint", + "select", + "set", + "table", + "temporary", + "then", + "to", + "transaction", + "trigger", + "union", + "unique", + "update", + "using", + "values", + "view", + "when", + "where", ] # functions functions = [ - "abs", "changes", "coalesce", "glob", "ifnull", "hex", "last_insert_rowid", - "length", "like", "lower", "ltrim", "max", "min", "nullif", "quote", "random", - "randomblob", "replace", "round", "rtrim", "soundex", "total_change", "trim", - "typeof", "upper", "zeroblob", "date", "datetime", "julianday", "strftime", - "avg", "count", "group_concat", "sum", "total" + "abs", + "changes", + "coalesce", + "glob", + "ifnull", + "hex", + "last_insert_rowid", + "length", + "like", + "lower", + "ltrim", + "max", + "min", + "nullif", + "quote", + "random", + "randomblob", + "replace", + "round", + "rtrim", + "soundex", + "total_change", + "trim", + "typeof", + "upper", + "zeroblob", + "date", + "datetime", + "julianday", + "strftime", + "avg", + "count", + "group_concat", + "sum", + "total", ] # constants @@ -52,4 +165,8 @@ def getSqlDictionary(): - return {'keyword': list(keywords), 'constant': list(constants), 'function': list(functions)} + return { + "keyword": list(keywords), + "constant": list(constants), + "function": list(functions), + } diff --git a/python/plugins/db_manager/sqledit.py b/python/plugins/db_manager/sqledit.py index 9b9067d6e4c1..deb78274ff77 100644 --- a/python/plugins/db_manager/sqledit.py +++ b/python/plugins/db_manager/sqledit.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'February 2014' -__copyright__ = '(C) 2014, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "February 2014" +__copyright__ = "(C) 2014, Alexander Bruy" from qgis.PyQt.QtCore import Qt from qgis.PyQt.QtGui import QColor, QFont, QKeySequence @@ -45,7 +45,7 @@ def setCommonOptions(self): # Default font font = QFont() - font.setFamily('Courier') + font.setFamily("Courier") font.setFixedPitch(True) font.setPointSize(10) self.setFont(font) @@ -54,30 +54,33 @@ def setCommonOptions(self): self.setBraceMatching(QsciScintilla.BraceMatch.SloppyBraceMatch) self.setWrapMode(QsciScintilla.WrapMode.WrapWord) - self.setWrapVisualFlags(QsciScintilla.WrapVisualFlag.WrapFlagByText, - QsciScintilla.WrapVisualFlag.WrapFlagNone, 4) + self.setWrapVisualFlags( + QsciScintilla.WrapVisualFlag.WrapFlagByText, + QsciScintilla.WrapVisualFlag.WrapFlagNone, + 4, + ) - self.setSelectionForegroundColor(QColor('#2e3436')) - self.setSelectionBackgroundColor(QColor('#babdb6')) + self.setSelectionForegroundColor(QColor("#2e3436")) + self.setSelectionBackgroundColor(QColor("#babdb6")) # Show line numbers - self.setMarginWidth(1, '000') + self.setMarginWidth(1, "000") self.setMarginLineNumbers(1, True) - self.setMarginsForegroundColor(QColor('#2e3436')) - self.setMarginsBackgroundColor(QColor('#babdb6')) + self.setMarginsForegroundColor(QColor("#2e3436")) + self.setMarginsBackgroundColor(QColor("#babdb6")) # Highlight current line self.setCaretLineVisible(True) - self.setCaretLineBackgroundColor(QColor('#d3d7cf')) + self.setCaretLineBackgroundColor(QColor("#d3d7cf")) # Folding self.setFolding(QsciScintilla.FoldStyle.BoxedTreeFoldStyle) - self.setFoldMarginColors(QColor('#d3d7cf'), QColor('#d3d7cf')) + self.setFoldMarginColors(QColor("#d3d7cf"), QColor("#d3d7cf")) # Mark column 80 with vertical line self.setEdgeMode(QsciScintilla.EdgeMode.EdgeLine) self.setEdgeColumn(80) - self.setEdgeColor(QColor('#eeeeec')) + self.setEdgeColor(QColor("#eeeeec")) # Indentation self.setAutoIndent(True) @@ -94,8 +97,8 @@ def setCommonOptions(self): # Load font from Python console settings settings = QgsSettings() - fontName = settings.value('pythonConsole/fontfamilytext', 'Monospace') - fontSize = int(settings.value('pythonConsole/fontsize', 10)) + fontName = settings.value("pythonConsole/fontfamilytext", "Monospace") + fontSize = int(settings.value("pythonConsole/fontsize", 10)) self.defaultFont = QFont(fontName) self.defaultFont.setFixedPitch(True) @@ -118,18 +121,18 @@ def initShortcuts(self): (ctrl, shift) = (self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16) # Disable some shortcuts - self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl) - self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl) - self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl + - shift) - self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl) + self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("D") + ctrl) + self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("L") + ctrl) + self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("L") + ctrl + shift) + self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("T") + ctrl) # self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Z") + ctrl) # self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Y") + ctrl) # Use Ctrl+Space for autocompletion - self.shortcutAutocomplete = QShortcut(QKeySequence(Qt.Modifier.CTRL + - Qt.Key.Key_Space), self) + self.shortcutAutocomplete = QShortcut( + QKeySequence(Qt.Modifier.CTRL + Qt.Key.Key_Space), self + ) self.shortcutAutocomplete.setContext(Qt.ShortcutContext.WidgetShortcut) self.shortcutAutocomplete.activated.connect(self.autoComplete) @@ -139,13 +142,13 @@ def autoComplete(self): def initLexer(self): self.mylexer = QsciLexerSQL() - colorDefault = QColor('#2e3436') - colorComment = QColor('#c00') - colorCommentBlock = QColor('#3465a4') - colorNumber = QColor('#4e9a06') - colorType = QColor('#4e9a06') - colorKeyword = QColor('#204a87') - colorString = QColor('#ce5c00') + colorDefault = QColor("#2e3436") + colorComment = QColor("#c00") + colorCommentBlock = QColor("#3465a4") + colorNumber = QColor("#4e9a06") + colorType = QColor("#4e9a06") + colorKeyword = QColor("#204a87") + colorString = QColor("#ce5c00") self.mylexer.setDefaultFont(self.defaultFont) self.mylexer.setDefaultColor(colorDefault) diff --git a/python/plugins/grassprovider/__init__.py b/python/plugins/grassprovider/__init__.py index 9af45507fb6d..42e27a6b6e70 100644 --- a/python/plugins/grassprovider/__init__.py +++ b/python/plugins/grassprovider/__init__.py @@ -15,11 +15,12 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'June 2021' -__copyright__ = '(C) 2021, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "June 2021" +__copyright__ = "(C) 2021, Alexander Bruy" def classFactory(iface): from grassprovider.grass_plugin import GrassProviderPlugin + return GrassProviderPlugin() diff --git a/python/plugins/grassprovider/description_to_json.py b/python/plugins/grassprovider/description_to_json.py index 08038d600c62..d90067f0b0d6 100644 --- a/python/plugins/grassprovider/description_to_json.py +++ b/python/plugins/grassprovider/description_to_json.py @@ -19,32 +19,34 @@ def main(description_folder: str, output_file: str): - from .parsed_description import ( - ParsedDescription - ) + from .parsed_description import ParsedDescription algorithms = [] folder = Path(description_folder) - for description_file in folder.glob('*.txt'): + for description_file in folder.glob("*.txt"): description = ParsedDescription.parse_description_file( - description_file, translate=False) + description_file, translate=False + ) ext_path = description_file.parents[1].joinpath( - 'ext', description.name.replace('.', '_') + '.py') + "ext", description.name.replace(".", "_") + ".py" + ) if ext_path.exists(): - description.ext_path = description.name.replace('.', '_') + description.ext_path = description.name.replace(".", "_") algorithms.append(description.as_dict()) Path(output_file).parent.mkdir(parents=True, exist_ok=True) - with open(output_file, 'wt', encoding='utf8') as f_out: + with open(output_file, "w", encoding="utf8") as f_out: f_out.write(json.dumps(algorithms, indent=2)) -parser = argparse.ArgumentParser(description="Parses GRASS .txt algorithm " - "description files and builds " - "aggregated .json description") +parser = argparse.ArgumentParser( + description="Parses GRASS .txt algorithm " + "description files and builds " + "aggregated .json description" +) parser.add_argument("input", help="Path to the description directory") parser.add_argument("output", help="Path to the output algorithms.json file") diff --git a/python/plugins/grassprovider/ext/g_extension_list.py b/python/plugins/grassprovider/ext/g_extension_list.py index 263a173d9b47..9024e98c4d88 100644 --- a/python/plugins/grassprovider/ext/g_extension_list.py +++ b/python/plugins/grassprovider/ext/g_extension_list.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Alister Hood' -__date__ = 'May 2023' -__copyright__ = '(C) 2023, Alister Hood' +__author__ = "Alister Hood" +__date__ = "May 2023" +__copyright__ = "(C) 2023, Alister Hood" from qgis.core import QgsProcessingParameterBoolean @@ -25,26 +25,26 @@ def processInputs(alg, parameters, context, feedback): # get the option we want to run # we would need to update the if statements below if the order in the description file is changed - selectedOption = alg.parameterAsInt(parameters, 'list', context) + selectedOption = alg.parameterAsInt(parameters, "list", context) # Locally installed extensions if selectedOption == 0: - optionString = '-a' + optionString = "-a" # Extensions available in the official GRASS GIS Addons repository elif selectedOption == 1: - optionString = '-l' + optionString = "-l" # Extensions available in the official GRASS GIS Addons repository including module description else: - optionString = '-c' - param = QgsProcessingParameterBoolean(optionString, '', True) + optionString = "-c" + param = QgsProcessingParameterBoolean(optionString, "", True) alg.addParameter(param) # Don't forget to remove the old input parameter - alg.removeParameter('list') + alg.removeParameter("list") def convertToHtml(alg, fileName, outputs): # don't copy this for something that will have lots of data like r.stats # it will be very slow - with open(fileName, 'r') as f: - outputs['GRASS_ADDONS'] = f.read() + with open(fileName) as f: + outputs["GRASS_ADDONS"] = f.read() # this will read the file a second time, but calling it saves us duplicating the code here alg.convertToHtml(fileName) diff --git a/python/plugins/grassprovider/ext/g_extension_manage.py b/python/plugins/grassprovider/ext/g_extension_manage.py index 51893b1de21d..d69cd49d7dfe 100644 --- a/python/plugins/grassprovider/ext/g_extension_manage.py +++ b/python/plugins/grassprovider/ext/g_extension_manage.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Alister Hood' -__date__ = 'May 2023' -__copyright__ = '(C) 2023, Alister Hood' +__author__ = "Alister Hood" +__date__ = "May 2023" +__copyright__ = "(C) 2023, Alister Hood" def processInputs(alg, parameters, context, feedback): diff --git a/python/plugins/grassprovider/ext/g_version.py b/python/plugins/grassprovider/ext/g_version.py index 6fbd09ffc1f2..3d44d5102e04 100644 --- a/python/plugins/grassprovider/ext/g_version.py +++ b/python/plugins/grassprovider/ext/g_version.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Alister Hood' -__date__ = 'May 2023' -__copyright__ = '(C) 2023, Alister Hood' +__author__ = "Alister Hood" +__date__ = "May 2023" +__copyright__ = "(C) 2023, Alister Hood" def processInputs(alg, parameters, context, feedback): @@ -27,7 +27,7 @@ def processInputs(alg, parameters, context, feedback): def convertToHtml(alg, fileName, outputs): # don't copy this for something that will have lots of data like r.stats # it will be very slow - with open(fileName, 'r') as f: - outputs['GRASS_VERSIONINFO'] = f.read() + with open(fileName) as f: + outputs["GRASS_VERSIONINFO"] = f.read() # this will read the file a second time, but calling it saves us duplicating the code here alg.convertToHtml(fileName) diff --git a/python/plugins/grassprovider/ext/i.py b/python/plugins/grassprovider/ext/i.py index 226eda04fc1d..51225470445f 100644 --- a/python/plugins/grassprovider/ext/i.py +++ b/python/plugins/grassprovider/ext/i.py @@ -15,12 +15,12 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'April 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "April 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" import os -from processing.tools.system import (isWindows, getTempFilename) +from processing.tools.system import isWindows, getTempFilename from grassprovider.grass_utils import GrassUtils from qgis.PyQt.QtCore import QDir from qgis.core import QgsProcessingParameterString @@ -36,10 +36,11 @@ def orderedInput(alg, parameters, context, src, tgt, numSeq=None): :param tgt: Name of a new input parameter. :param numSeq: List of a sequence for naming layers. """ - rootFilename = 'rast_{}.'.format(os.path.basename(getTempFilename(context=context))) + rootFilename = f"rast_{os.path.basename(getTempFilename(context=context))}." # parameters[tgt] = rootFilename - param = QgsProcessingParameterString(tgt, 'virtual input', - rootFilename, False, False) + param = QgsProcessingParameterString( + tgt, "virtual input", rootFilename, False, False + ) alg.addParameter(param) rasters = alg.parameterAsLayerList(parameters, src, context) @@ -48,7 +49,7 @@ def orderedInput(alg, parameters, context, src, tgt, numSeq=None): numSeq = list(range(1, len(rasters) + 1)) for idx, raster in enumerate(rasters): - rasterName = '{}{}'.format(rootFilename, numSeq[idx]) + rasterName = f"{rootFilename}{numSeq[idx]}" alg.loadRasterLayer(rasterName, raster, context, False, None, rasterName) # Don't forget to remove the old input parameter @@ -69,32 +70,35 @@ def regroupRasters(alg, parameters, context, src, group, subgroup=None, extFile= :param extFile: dict : parameterName:directory name """ # Create a group parameter - groupName = 'group_{}'.format(os.path.basename(getTempFilename(context=context))) - param = QgsProcessingParameterString(group, 'virtual group', - groupName, False, False) + groupName = f"group_{os.path.basename(getTempFilename(context=context))}" + param = QgsProcessingParameterString( + group, "virtual group", groupName, False, False + ) alg.addParameter(param) # Create a subgroup subgroupName = None if subgroup: - subgroupName = 'subgroup_{}'.format(os.path.basename(getTempFilename(context=context))) - param = QgsProcessingParameterString(subgroup, 'virtual subgroup', - subgroupName, False, False) + subgroupName = f"subgroup_{os.path.basename(getTempFilename(context=context))}" + param = QgsProcessingParameterString( + subgroup, "virtual subgroup", subgroupName, False, False + ) alg.addParameter(param) # Compute raster names rasters = alg.parameterAsLayerList(parameters, src, context) rasterNames = [] for idx, raster in enumerate(rasters): - name = '{}_{}'.format(src, idx) + name = f"{src}_{idx}" if name in alg.exportedLayers: rasterNames.append(alg.exportedLayers[name]) # Insert a i.group command - command = 'i.group group={}{} input={}'.format( + command = "i.group group={}{} input={}".format( groupName, - ' subgroup={}'.format(subgroupName) if subgroup else '', - ','.join(rasterNames)) + f" subgroup={subgroupName}" if subgroup else "", + ",".join(rasterNames), + ) alg.commands.append(command) # Handle external files @@ -115,35 +119,54 @@ def regroupRasters(alg, parameters, context, src, group, subgroup=None, extFile= return groupName, subgroupName -def importSigFile(alg, group, subgroup, src, sigDir='sig'): +def importSigFile(alg, group, subgroup, src, sigDir="sig"): """ Import a signature file into an internal GRASSDB folder """ shortSigFile = os.path.basename(src) - interSig = os.path.join(GrassUtils.grassMapsetFolder(), - 'PERMANENT', 'group', group, 'subgroup', - subgroup, sigDir, shortSigFile) + interSig = os.path.join( + GrassUtils.grassMapsetFolder(), + "PERMANENT", + "group", + group, + "subgroup", + subgroup, + sigDir, + shortSigFile, + ) copyFile(alg, src, interSig) return shortSigFile -def exportSigFile(alg, group, subgroup, dest, sigDir='sig'): +def exportSigFile(alg, group, subgroup, dest, sigDir="sig"): """ Export a signature file from internal GRASSDB to final destination """ shortSigFile = os.path.basename(dest) - grass_version = int(GrassUtils.installedVersion().split('.')[0]) + grass_version = int(GrassUtils.installedVersion().split(".")[0]) if grass_version >= 8: - interSig = os.path.join(GrassUtils.grassMapsetFolder(), - 'PERMANENT', 'signatures', - sigDir, shortSigFile, 'sig') + interSig = os.path.join( + GrassUtils.grassMapsetFolder(), + "PERMANENT", + "signatures", + sigDir, + shortSigFile, + "sig", + ) else: - interSig = os.path.join(GrassUtils.grassMapsetFolder(), - 'PERMANENT', 'group', group, 'subgroup', - subgroup, sigDir, shortSigFile) + interSig = os.path.join( + GrassUtils.grassMapsetFolder(), + "PERMANENT", + "group", + group, + "subgroup", + subgroup, + sigDir, + shortSigFile, + ) moveFile(alg, interSig, dest) return interSig @@ -160,7 +183,8 @@ def exportInputRasters(alg, parameters, context, rasterDic): # Get inputs and outputs for inputName, outputName in rasterDic.items(): fileName = os.path.normpath( - alg.parameterAsOutputLayer(parameters, outputName, context)) + alg.parameterAsOutputLayer(parameters, outputName, context) + ) grassName = alg.exportedLayers[inputName] outFormat = GrassUtils.getRasterFormatFromFilename(fileName) alg.exportRasterLayer(grassName, fileName, True, outFormat, createOpt, metaOpt) @@ -170,9 +194,15 @@ def verifyRasterNum(alg, parameters, context, rasters, mini, maxi=None): """Verify that we have at least n rasters in multipleInput""" num = len(alg.parameterAsLayerList(parameters, rasters, context)) if num < mini: - return False, 'You need to set at least {} input rasters for this algorithm!'.format(mini) + return ( + False, + f"You need to set at least {mini} input rasters for this algorithm!", + ) if maxi and num > maxi: - return False, 'You need to set a maximum of {} input rasters for this algorithm!'.format(maxi) + return ( + False, + f"You need to set a maximum of {maxi} input rasters for this algorithm!", + ) return True, None @@ -191,31 +221,32 @@ def verifyRasterNum(alg, parameters, context, rasters, mini, maxi=None): def createDestDir(alg, toFile): - """ Generates an mkdir command for GRASS script """ + """Generates an mkdir command for GRASS script""" # Creates the destination directory - command = "{} \"{}\"".format( + command = '{} "{}"'.format( "MD" if isWindows() else "mkdir -p", - QDir.toNativeSeparators(os.path.dirname(toFile)) + QDir.toNativeSeparators(os.path.dirname(toFile)), ) alg.commands.append(command) def moveFile(alg, fromFile, toFile): - """ Generates a move command for GRASS script """ + """Generates a move command for GRASS script""" createDestDir(alg, toFile) - command = "{} \"{}\" \"{}\"".format( + command = '{} "{}" "{}"'.format( "MOVE /Y" if isWindows() else "mv -f", QDir.toNativeSeparators(fromFile), - QDir.toNativeSeparators(toFile) + QDir.toNativeSeparators(toFile), ) alg.commands.append(command) def copyFile(alg, fromFile, toFile): - """ Generates a copy command for GRASS script """ + """Generates a copy command for GRASS script""" createDestDir(alg, toFile) - command = "{} \"{}\" \"{}\"".format( + command = '{} "{}" "{}"'.format( "COPY /Y" if isWindows() else "cp -f", QDir.toNativeSeparators(fromFile), - QDir.toNativeSeparators(toFile)) + QDir.toNativeSeparators(toFile), + ) alg.commands.append(command) diff --git a/python/plugins/grassprovider/ext/i_albedo.py b/python/plugins/grassprovider/ext/i_albedo.py index ab418d15a01f..2dda8d334e5c 100644 --- a/python/plugins/grassprovider/ext/i_albedo.py +++ b/python/plugins/grassprovider/ext/i_albedo.py @@ -15,19 +15,20 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .i import verifyRasterNum def checkParameterValuesBeforeExecuting(alg, parameters, context): - if alg.parameterAsBoolean(parameters, '-m', context): - return verifyRasterNum(alg, parameters, context, 'input', 7) - elif alg.parameterAsBoolean(parameters, '-n', context): - return verifyRasterNum(alg, parameters, context, 'input', 2) - elif (alg.parameterAsBoolean(parameters, '-l', context) - or alg.parameterAsBoolean(parameters, '-a', context)): - return verifyRasterNum(alg, parameters, context, 'input', 6) + if alg.parameterAsBoolean(parameters, "-m", context): + return verifyRasterNum(alg, parameters, context, "input", 7) + elif alg.parameterAsBoolean(parameters, "-n", context): + return verifyRasterNum(alg, parameters, context, "input", 2) + elif alg.parameterAsBoolean(parameters, "-l", context) or alg.parameterAsBoolean( + parameters, "-a", context + ): + return verifyRasterNum(alg, parameters, context, "input", 6) return True, None diff --git a/python/plugins/grassprovider/ext/i_cca.py b/python/plugins/grassprovider/ext/i_cca.py index 97e3acd99f31..61afff682146 100644 --- a/python/plugins/grassprovider/ext/i_cca.py +++ b/python/plugins/grassprovider/ext/i_cca.py @@ -15,25 +15,26 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .i import verifyRasterNum, regroupRasters, importSigFile def checkParameterValuesBeforeExecuting(alg, parameters, context): - return verifyRasterNum(alg, parameters, context, 'input', 2, 8) + return verifyRasterNum(alg, parameters, context, "input", 2, 8) def processCommand(alg, parameters, context, feedback): # Regroup rasters - group, subgroup = regroupRasters(alg, parameters, context, - 'input', 'group', 'subgroup') + group, subgroup = regroupRasters( + alg, parameters, context, "input", "group", "subgroup" + ) - signatureFile = alg.parameterAsString(parameters, 'signature', context) + signatureFile = alg.parameterAsString(parameters, "signature", context) shortSigFile = importSigFile(alg, group, subgroup, signatureFile) - parameters['signature'] = shortSigFile + parameters["signature"] = shortSigFile # Handle other parameters alg.processCommand(parameters, context, feedback) diff --git a/python/plugins/grassprovider/ext/i_cluster.py b/python/plugins/grassprovider/ext/i_cluster.py index ac7e1cbdb7e3..950e14d3e7f7 100644 --- a/python/plugins/grassprovider/ext/i_cluster.py +++ b/python/plugins/grassprovider/ext/i_cluster.py @@ -15,31 +15,33 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" import os from .i import regroupRasters, verifyRasterNum, exportSigFile def checkParameterValuesBeforeExecuting(alg, parameters, context): - return verifyRasterNum(alg, parameters, context, 'input', 2) + return verifyRasterNum(alg, parameters, context, "input", 2) def processCommand(alg, parameters, context, feedback): # We need to extract the basename of the signature file - signatureFile = alg.parameterAsString(parameters, 'signaturefile', context) + signatureFile = alg.parameterAsString(parameters, "signaturefile", context) shortSigFile = os.path.basename(signatureFile) - parameters['signaturefile'] = shortSigFile + parameters["signaturefile"] = shortSigFile # Regroup rasters - group, subgroup = regroupRasters(alg, parameters, context, 'input', 'group', 'subgroup') + group, subgroup = regroupRasters( + alg, parameters, context, "input", "group", "subgroup" + ) alg.processCommand(parameters, context, feedback) # Re-add signature files - parameters['signaturefile'] = signatureFile - alg.fileOutputs['signaturefile'] = signatureFile + parameters["signaturefile"] = signatureFile + alg.fileOutputs["signaturefile"] = signatureFile # Export signature file exportSigFile(alg, group, subgroup, signatureFile) diff --git a/python/plugins/grassprovider/ext/i_colors_enhance.py b/python/plugins/grassprovider/ext/i_colors_enhance.py index 9fd9df1beedf..15c3d7a3ec57 100644 --- a/python/plugins/grassprovider/ext/i_colors_enhance.py +++ b/python/plugins/grassprovider/ext/i_colors_enhance.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .i import exportInputRasters @@ -29,5 +29,5 @@ def processCommand(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback): # Input rasters are output rasters - rasterDic = {'red': 'redoutput', 'green': 'greenoutput', 'blue': 'blueoutput'} + rasterDic = {"red": "redoutput", "green": "greenoutput", "blue": "blueoutput"} exportInputRasters(alg, parameters, context, rasterDic) diff --git a/python/plugins/grassprovider/ext/i_evapo_mh.py b/python/plugins/grassprovider/ext/i_evapo_mh.py index 101f796d0047..761eebcae038 100644 --- a/python/plugins/grassprovider/ext/i_evapo_mh.py +++ b/python/plugins/grassprovider/ext/i_evapo_mh.py @@ -15,16 +15,22 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" def checkParameterValuesBeforeExecuting(alg, parameters, context): - if (alg.parameterAsBoolean(parameters, '-h', context) - and alg.parameterAsLayer(parameters, 'precipitation', context)): - return False, alg.tr('You can\'t use original Hargreaves flag and precipitation parameter together!') - if (not alg.parameterAsBoolean(parameters, '-h', context) - and not alg.parameterAsLayer(parameters, 'precipitation', context)): - return False, alg.tr('If you don\'t use original Hargreaves flag, you must set the precipitation raster parameter!') + if alg.parameterAsBoolean(parameters, "-h", context) and alg.parameterAsLayer( + parameters, "precipitation", context + ): + return False, alg.tr( + "You can't use original Hargreaves flag and precipitation parameter together!" + ) + if not alg.parameterAsBoolean( + parameters, "-h", context + ) and not alg.parameterAsLayer(parameters, "precipitation", context): + return False, alg.tr( + "If you don't use original Hargreaves flag, you must set the precipitation raster parameter!" + ) return True, None diff --git a/python/plugins/grassprovider/ext/i_gensig.py b/python/plugins/grassprovider/ext/i_gensig.py index db67d2da4781..02ab5d6b5cba 100644 --- a/python/plugins/grassprovider/ext/i_gensig.py +++ b/python/plugins/grassprovider/ext/i_gensig.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" import os from .i import regroupRasters, exportSigFile @@ -25,17 +25,19 @@ def processCommand(alg, parameters, context, feedback): # We need to extract the basename of the signature file - signatureFile = alg.parameterAsString(parameters, 'signaturefile', context) + signatureFile = alg.parameterAsString(parameters, "signaturefile", context) shortSigFile = os.path.basename(signatureFile) - parameters['signaturefile'] = shortSigFile + parameters["signaturefile"] = shortSigFile # Regroup rasters - group, subgroup = regroupRasters(alg, parameters, context, 'input', 'group', 'subgroup') + group, subgroup = regroupRasters( + alg, parameters, context, "input", "group", "subgroup" + ) alg.processCommand(parameters, context, feedback) # Re-add signature files - parameters['signaturefile'] = signatureFile - alg.fileOutputs['signaturefile'] = signatureFile + parameters["signaturefile"] = signatureFile + alg.fileOutputs["signaturefile"] = signatureFile # Export signature file exportSigFile(alg, group, subgroup, signatureFile) diff --git a/python/plugins/grassprovider/ext/i_gensigset.py b/python/plugins/grassprovider/ext/i_gensigset.py index c378f3550d2b..e233d30484cd 100644 --- a/python/plugins/grassprovider/ext/i_gensigset.py +++ b/python/plugins/grassprovider/ext/i_gensigset.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" import os from .i import regroupRasters, exportSigFile @@ -25,17 +25,19 @@ def processCommand(alg, parameters, context, feedback): # We need to extract the basename of the signature file - signatureFile = alg.parameterAsString(parameters, 'signaturefile', context) + signatureFile = alg.parameterAsString(parameters, "signaturefile", context) shortSigFile = os.path.basename(signatureFile) - parameters['signaturefile'] = shortSigFile + parameters["signaturefile"] = shortSigFile # Regroup rasters - group, subgroup = regroupRasters(alg, parameters, context, 'input', 'group', 'subgroup') + group, subgroup = regroupRasters( + alg, parameters, context, "input", "group", "subgroup" + ) alg.processCommand(parameters, context, feedback) # Re-add signature files - parameters['signaturefile'] = signatureFile - alg.fileOutputs['signaturefile'] = signatureFile + parameters["signaturefile"] = signatureFile + alg.fileOutputs["signaturefile"] = signatureFile # Export signature file - exportSigFile(alg, group, subgroup, signatureFile, 'sigset') + exportSigFile(alg, group, subgroup, signatureFile, "sigset") diff --git a/python/plugins/grassprovider/ext/i_group.py b/python/plugins/grassprovider/ext/i_group.py index ff52ac71aebf..325039ed80e3 100644 --- a/python/plugins/grassprovider/ext/i_group.py +++ b/python/plugins/grassprovider/ext/i_group.py @@ -15,12 +15,12 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .i import verifyRasterNum def checkParameterValuesBeforeExecuting(alg, parameters, context): - return verifyRasterNum(alg, parameters, context, 'input', 2) + return verifyRasterNum(alg, parameters, context, "input", 2) diff --git a/python/plugins/grassprovider/ext/i_in_spotvgt.py b/python/plugins/grassprovider/ext/i_in_spotvgt.py index 0c6accf7f414..32b028e1271f 100644 --- a/python/plugins/grassprovider/ext/i_in_spotvgt.py +++ b/python/plugins/grassprovider/ext/i_in_spotvgt.py @@ -15,13 +15,13 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'April 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "April 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" def processInputs(alg, parameters, context, feedback): # Here, we apply directly the algorithm # So we just need to get the projection of the layer ! - layer = alg.parameterAsRasterLayer(parameters, 'input', context) + layer = alg.parameterAsRasterLayer(parameters, "input", context) alg.setSessionProjectionFromLayer(layer, context) diff --git a/python/plugins/grassprovider/ext/i_landsat_acca.py b/python/plugins/grassprovider/ext/i_landsat_acca.py index 1b1729e07e9f..da74d16f7495 100644 --- a/python/plugins/grassprovider/ext/i_landsat_acca.py +++ b/python/plugins/grassprovider/ext/i_landsat_acca.py @@ -15,20 +15,19 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .i import verifyRasterNum, orderedInput def checkParameterValuesBeforeExecuting(alg, parameters, context): - return verifyRasterNum(alg, parameters, context, 'rasters', 5, 5) + return verifyRasterNum(alg, parameters, context, "rasters", 5, 5) def processInputs(alg, parameters, context, feedback): - orderedInput(alg, parameters, context, 'rasters', 'input', - [2, 3, 4, 5, 61]) + orderedInput(alg, parameters, context, "rasters", "input", [2, 3, 4, 5, 61]) def processCommand(alg, parameters, context, feedback): diff --git a/python/plugins/grassprovider/ext/i_landsat_toar.py b/python/plugins/grassprovider/ext/i_landsat_toar.py index d4b1509dc9f1..9b231091761a 100644 --- a/python/plugins/grassprovider/ext/i_landsat_toar.py +++ b/python/plugins/grassprovider/ext/i_landsat_toar.py @@ -15,20 +15,21 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .i import verifyRasterNum, orderedInput def checkParameterValuesBeforeExecuting(alg, parameters, context): - return verifyRasterNum(alg, parameters, context, 'rasters', 5, 12) + return verifyRasterNum(alg, parameters, context, "rasters", 5, 12) def processInputs(alg, parameters, context, feedback): - orderedInput(alg, parameters, context, 'rasters', 'input', - [1, 2, 3, 4, 5, 61, 62, 7, 8]) + orderedInput( + alg, parameters, context, "rasters", "input", [1, 2, 3, 4, 5, 61, 62, 7, 8] + ) def processCommand(alg, parameters, context, feedback): diff --git a/python/plugins/grassprovider/ext/i_maxlik.py b/python/plugins/grassprovider/ext/i_maxlik.py index 9e134d5f85c8..a2043eafa183 100644 --- a/python/plugins/grassprovider/ext/i_maxlik.py +++ b/python/plugins/grassprovider/ext/i_maxlik.py @@ -15,21 +15,22 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .i import regroupRasters, importSigFile def processCommand(alg, parameters, context, feedback): - group, subgroup = regroupRasters(alg, parameters, context, - 'input', 'group', 'subgroup') + group, subgroup = regroupRasters( + alg, parameters, context, "input", "group", "subgroup" + ) # import signature - signatureFile = alg.parameterAsString(parameters, 'signaturefile', context) + signatureFile = alg.parameterAsString(parameters, "signaturefile", context) shortSigFile = importSigFile(alg, group, subgroup, signatureFile) - parameters['signaturefile'] = shortSigFile + parameters["signaturefile"] = shortSigFile # Handle other parameters alg.processCommand(parameters, context, feedback) diff --git a/python/plugins/grassprovider/ext/i_oif.py b/python/plugins/grassprovider/ext/i_oif.py index 6249a931e1bc..e99925ef513d 100644 --- a/python/plugins/grassprovider/ext/i_oif.py +++ b/python/plugins/grassprovider/ext/i_oif.py @@ -15,12 +15,12 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .i import verifyRasterNum def checkParameterValuesBeforeExecuting(alg, parameters, context): - return verifyRasterNum(alg, parameters, context, 'input', 4) + return verifyRasterNum(alg, parameters, context, "input", 4) diff --git a/python/plugins/grassprovider/ext/i_pansharpen.py b/python/plugins/grassprovider/ext/i_pansharpen.py index 056d3e32361f..05e436e2805b 100644 --- a/python/plugins/grassprovider/ext/i_pansharpen.py +++ b/python/plugins/grassprovider/ext/i_pansharpen.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" import os from qgis.core import QgsProcessingParameterString @@ -27,19 +27,20 @@ def processCommand(alg, parameters, context, feedback): # Temporary remove outputs and add a virtual output parameter - outputName = 'output_{}'.format(os.path.basename(getTempFilename(context=context))) - param = QgsProcessingParameterString('output', 'virtual output', - outputName, False, False) + outputName = f"output_{os.path.basename(getTempFilename(context=context))}" + param = QgsProcessingParameterString( + "output", "virtual output", outputName, False, False + ) alg.addParameter(param) alg.processCommand(parameters, context, feedback, True) def processOutputs(alg, parameters, context, feedback): - outputName = alg.parameterAsString(parameters, 'output', context) + outputName = alg.parameterAsString(parameters, "output", context) createOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_OPT, context) metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context) - for channel in ['red', 'green', 'blue']: - fileName = alg.parameterAsOutputLayer(parameters, '{}output'.format(channel), context) - grassName = '{}_{}'.format(outputName, channel) + for channel in ["red", "green", "blue"]: + fileName = alg.parameterAsOutputLayer(parameters, f"{channel}output", context) + grassName = f"{outputName}_{channel}" outFormat = GrassUtils.getRasterFormatFromFilename(fileName) alg.exportRasterLayer(grassName, fileName, True, outFormat, createOpt, metaOpt) diff --git a/python/plugins/grassprovider/ext/i_pca.py b/python/plugins/grassprovider/ext/i_pca.py index 89af12f8a34f..6a4b55586f2b 100644 --- a/python/plugins/grassprovider/ext/i_pca.py +++ b/python/plugins/grassprovider/ext/i_pca.py @@ -15,12 +15,12 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .i import verifyRasterNum def checkParameterValuesBeforeExecuting(alg, parameters, context): - return verifyRasterNum(alg, parameters, context, 'input', 2) + return verifyRasterNum(alg, parameters, context, "input", 2) diff --git a/python/plugins/grassprovider/ext/i_segment.py b/python/plugins/grassprovider/ext/i_segment.py index 19f676ee236a..c19c6cf9f358 100644 --- a/python/plugins/grassprovider/ext/i_segment.py +++ b/python/plugins/grassprovider/ext/i_segment.py @@ -15,14 +15,14 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .i import regroupRasters def processCommand(alg, parameters, context, feedback): # Regroup rasters - regroupRasters(alg, parameters, context, 'input', 'group') + regroupRasters(alg, parameters, context, "input", "group") alg.processCommand(parameters, context, feedback) diff --git a/python/plugins/grassprovider/ext/i_smap.py b/python/plugins/grassprovider/ext/i_smap.py index 310d234d66a0..e14535e411c3 100644 --- a/python/plugins/grassprovider/ext/i_smap.py +++ b/python/plugins/grassprovider/ext/i_smap.py @@ -15,21 +15,23 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .i import regroupRasters, importSigFile def processCommand(alg, parameters, context, feedback): # Regroup rasters - group, subgroup = regroupRasters(alg, parameters, context, 'input', 'group', 'subgroup') + group, subgroup = regroupRasters( + alg, parameters, context, "input", "group", "subgroup" + ) # import signature - signatureFile = alg.parameterAsString(parameters, 'signaturefile', context) - shortSigFile = importSigFile(alg, group, subgroup, signatureFile, 'sigset') - parameters['signaturefile'] = shortSigFile + signatureFile = alg.parameterAsString(parameters, "signaturefile", context) + shortSigFile = importSigFile(alg, group, subgroup, signatureFile, "sigset") + parameters["signaturefile"] = shortSigFile # Handle other parameters alg.processCommand(parameters, context, feedback) diff --git a/python/plugins/grassprovider/ext/i_tasscap.py b/python/plugins/grassprovider/ext/i_tasscap.py index eda544125acf..831fd959396f 100644 --- a/python/plugins/grassprovider/ext/i_tasscap.py +++ b/python/plugins/grassprovider/ext/i_tasscap.py @@ -15,12 +15,12 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .i import verifyRasterNum def checkParameterValuesBeforeExecuting(alg, parameters, context): - return verifyRasterNum(alg, parameters, context, 'input', 6, 8) + return verifyRasterNum(alg, parameters, context, "input", 6, 8) diff --git a/python/plugins/grassprovider/ext/r_blend_combine.py b/python/plugins/grassprovider/ext/r_blend_combine.py index 4608a8360594..5d7628256bb7 100644 --- a/python/plugins/grassprovider/ext/r_blend_combine.py +++ b/python/plugins/grassprovider/ext/r_blend_combine.py @@ -15,21 +15,21 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" def processInputs(alg, parameters, context, feedback): - if 'first' and 'second' in alg.exportedLayers: + if "first" and "second" in alg.exportedLayers: return # Use v.in.ogr - for name in ['first', 'second']: + for name in ["first", "second"]: alg.loadRasterLayerFromParameter(name, parameters, context, False, None) alg.postInputs(context) def processOutputs(alg, parameters, context, feedback): # Keep color table - alg.exportRasterLayerFromParameter('output', parameters, context) + alg.exportRasterLayerFromParameter("output", parameters, context) diff --git a/python/plugins/grassprovider/ext/r_blend_rgb.py b/python/plugins/grassprovider/ext/r_blend_rgb.py index 2e763d5412c1..9cfe11ce7f5b 100644 --- a/python/plugins/grassprovider/ext/r_blend_rgb.py +++ b/python/plugins/grassprovider/ext/r_blend_rgb.py @@ -15,20 +15,20 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" import os from grassprovider.grass_utils import GrassUtils def processInputs(alg, parameters, context, feedback): - if 'first' and 'second' in alg.exportedLayers: + if "first" and "second" in alg.exportedLayers: return # Use v.in.ogr - for name in ['first', 'second']: + for name in ["first", "second"]: alg.loadRasterLayerFromParameter(name, parameters, context, False, None) alg.postInputs(context) @@ -43,10 +43,12 @@ def processOutputs(alg, parameters, context, feedback): metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context) # Export each color raster - colors = ['red', 'green', 'blue'] + colors = ["red", "green", "blue"] for color in colors: fileName = os.path.normpath( - alg.parameterAsOutputLayer(parameters, 'output_{}'.format(color), context)) + alg.parameterAsOutputLayer(parameters, f"output_{color}", context) + ) outFormat = GrassUtils.getRasterFormatFromFilename(fileName) - alg.exportRasterLayer('blended.{}'.format(color[0]), - fileName, True, outFormat, createOpt, metaOpt) + alg.exportRasterLayer( + f"blended.{color[0]}", fileName, True, outFormat, createOpt, metaOpt + ) diff --git a/python/plugins/grassprovider/ext/r_category.py b/python/plugins/grassprovider/ext/r_category.py index 1f9e0476468e..06c35e68be90 100644 --- a/python/plugins/grassprovider/ext/r_category.py +++ b/python/plugins/grassprovider/ext/r_category.py @@ -15,24 +15,28 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from processing.tools.system import getTempFilename from grassprovider.grass_utils import GrassUtils def checkParameterValuesBeforeExecuting(alg, parameters, context): - """ Verify if we have the right parameters """ - rules = alg.parameterAsString(parameters, 'rules', context) - txtrules = alg.parameterAsString(parameters, 'txtrules', context) - raster = alg.parameterAsString(parameters, 'raster', context) + """Verify if we have the right parameters""" + rules = alg.parameterAsString(parameters, "rules", context) + txtrules = alg.parameterAsString(parameters, "txtrules", context) + raster = alg.parameterAsString(parameters, "raster", context) if rules and txtrules: - return False, alg.tr("You need to set either a rules file or write directly the rules!") + return False, alg.tr( + "You need to set either a rules file or write directly the rules!" + ) elif (rules and raster) or (txtrules and raster): - return False, alg.tr("You need to set either rules or a raster from which to copy categories!") + return False, alg.tr( + "You need to set either rules or a raster from which to copy categories!" + ) return True, None @@ -40,18 +44,16 @@ def checkParameterValuesBeforeExecuting(alg, parameters, context): def processInputs(alg, parameters, context, feedback): # If there is another raster to copy categories from # we need to import it with r.in.gdal rather than r.external - raster = alg.parameterAsString(parameters, 'raster', context) + raster = alg.parameterAsString(parameters, "raster", context) if raster: - alg.loadRasterLayerFromParameter('raster', - parameters, context, - False, None) - alg.loadRasterLayerFromParameter('map', parameters, context) + alg.loadRasterLayerFromParameter("raster", parameters, context, False, None) + alg.loadRasterLayerFromParameter("map", parameters, context) alg.postInputs(context) def processCommand(alg, parameters, context, feedback): # Handle inline rules - txtRules = alg.parameterAsString(parameters, 'txtrules', context) + txtRules = alg.parameterAsString(parameters, "txtrules", context) if txtRules: # Creates a temporary txt file tempRulesName = getTempFilename(context=context) @@ -59,8 +61,8 @@ def processCommand(alg, parameters, context, feedback): # Inject rules into temporary txt file with open(tempRulesName, "w") as tempRules: tempRules.write(txtRules) - alg.removeParameter('txtrules') - parameters['rules'] = tempRulesName + alg.removeParameter("txtrules") + parameters["rules"] = tempRulesName alg.processCommand(parameters, context, feedback, True) @@ -71,8 +73,7 @@ def processOutputs(alg, parameters, context, feedback): metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context) # We need to export the raster with all its bands and its color table - fileName = alg.parameterAsOutputLayer(parameters, 'output', context) + fileName = alg.parameterAsOutputLayer(parameters, "output", context) outFormat = GrassUtils.getRasterFormatFromFilename(fileName) - grassName = alg.exportedLayers['map'] - alg.exportRasterLayer(grassName, fileName, True, - outFormat, createOpt, metaOpt) + grassName = alg.exportedLayers["map"] + alg.exportRasterLayer(grassName, fileName, True, outFormat, createOpt, metaOpt) diff --git a/python/plugins/grassprovider/ext/r_colors.py b/python/plugins/grassprovider/ext/r_colors.py index 3ec6f0ea9abc..3df349d6b99c 100644 --- a/python/plugins/grassprovider/ext/r_colors.py +++ b/python/plugins/grassprovider/ext/r_colors.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" import os from grassprovider.grass_utils import GrassUtils @@ -25,17 +25,19 @@ def checkParameterValuesBeforeExecuting(alg, parameters, context): - """ Verify if we have the right parameters """ - txtRules = alg.parameterAsString(parameters, 'rules_txt', context) - rules = alg.parameterAsString(parameters, 'rules', context) + """Verify if we have the right parameters""" + txtRules = alg.parameterAsString(parameters, "rules_txt", context) + rules = alg.parameterAsString(parameters, "rules", context) if txtRules and rules: return False, alg.tr("You need to set either inline rules or a rules file!") rules_or_txtRules = bool(txtRules or rules) - color = bool(alg.parameterAsEnum(parameters, 'color', context)) - raster = bool(alg.parameterAsString(parameters, 'raster', context)) + color = bool(alg.parameterAsEnum(parameters, "color", context)) + raster = bool(alg.parameterAsString(parameters, "raster", context)) if not sum([rules_or_txtRules, color, raster]) == 1: - return False, alg.tr("The color table, color rules and raster map parameters are mutually exclusive. You need to set one and only one of them!") + return False, alg.tr( + "The color table, color rules and raster map parameters are mutually exclusive. You need to set one and only one of them!" + ) return True, None @@ -43,23 +45,23 @@ def checkParameterValuesBeforeExecuting(alg, parameters, context): def processInputs(alg, parameters, context, feedback): # import all rasters with their color tables (and their bands) # We need to import all the bands and color tables of the input rasters - rasters = alg.parameterAsLayerList(parameters, 'map', context) + rasters = alg.parameterAsLayerList(parameters, "map", context) for idx, layer in enumerate(rasters): - layerName = 'map_{}'.format(idx) + layerName = f"map_{idx}" # Add a raster layer alg.loadRasterLayer(layerName, layer, context, False, None) # Optional raster layer to copy from - raster = alg.parameterAsString(parameters, 'raster', context) + raster = alg.parameterAsString(parameters, "raster", context) if raster: - alg.loadRasterLayerFromParameter('raster', parameters, context, False, None) + alg.loadRasterLayerFromParameter("raster", parameters, context, False, None) alg.postInputs(context) def processCommand(alg, parameters, context, feedback): # Handle inline rules - txtRules = alg.parameterAsString(parameters, 'txtrules', context) + txtRules = alg.parameterAsString(parameters, "txtrules", context) if txtRules: # Creates a temporary txt file tempRulesName = getTempFilename(context=context) @@ -67,11 +69,11 @@ def processCommand(alg, parameters, context, feedback): # Inject rules into temporary txt file with open(tempRulesName, "w") as tempRules: tempRules.write(txtRules) - alg.removeParameter('txtrules') - parameters['rules'] = tempRulesName + alg.removeParameter("txtrules") + parameters["rules"] = tempRulesName - if alg.parameterAsEnum(parameters, 'color', context) == 0: - alg.removeParameter('color') + if alg.parameterAsEnum(parameters, "color", context) == 0: + alg.removeParameter("color") alg.processCommand(parameters, context, feedback, True) @@ -81,11 +83,17 @@ def processOutputs(alg, parameters, context, feedback): metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context) # Export all rasters with their color tables (and their bands) - rasters = alg.parameterAsLayerList(parameters, 'map', context) - outputDir = alg.parameterAsString(parameters, 'output_dir', context) + rasters = alg.parameterAsLayerList(parameters, "map", context) + outputDir = alg.parameterAsString(parameters, "output_dir", context) for idx, raster in enumerate(rasters): - rasterName = 'map_{}'.format(idx) + rasterName = f"map_{idx}" fileName = os.path.join(outputDir, rasterName) outFormat = GrassUtils.getRasterFormatFromFilename(fileName) - alg.exportRasterLayer(alg.exportedLayers[rasterName], fileName, True, - outFormat, createOpt, metaOpt) + alg.exportRasterLayer( + alg.exportedLayers[rasterName], + fileName, + True, + outFormat, + createOpt, + metaOpt, + ) diff --git a/python/plugins/grassprovider/ext/r_colors_stddev.py b/python/plugins/grassprovider/ext/r_colors_stddev.py index fd3602af5397..e65e8f36e807 100644 --- a/python/plugins/grassprovider/ext/r_colors_stddev.py +++ b/python/plugins/grassprovider/ext/r_colors_stddev.py @@ -15,20 +15,20 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from grassprovider.grass_utils import GrassUtils def processInputs(alg, parameters, context, feedback): # We need to import all the bands and to preserve color table - if 'map' in alg.exportedLayers: + if "map" in alg.exportedLayers: return # We need to import all the bands and color tables of the input raster - alg.loadRasterLayerFromParameter('map', parameters, context, False, None) + alg.loadRasterLayerFromParameter("map", parameters, context, False, None) alg.postInputs(context) @@ -42,8 +42,7 @@ def processOutputs(alg, parameters, context, feedback): metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context) # We need to export the raster with all its bands and its color table - fileName = alg.parameterAsOutputLayer(parameters, 'output', context) + fileName = alg.parameterAsOutputLayer(parameters, "output", context) outFormat = GrassUtils.getRasterFormatFromFilename(fileName) - grassName = alg.exportedLayers['map'] - alg.exportRasterLayer(grassName, fileName, True, - outFormat, createOpt, metaOpt) + grassName = alg.exportedLayers["map"] + alg.exportRasterLayer(grassName, fileName, True, outFormat, createOpt, metaOpt) diff --git a/python/plugins/grassprovider/ext/r_drain.py b/python/plugins/grassprovider/ext/r_drain.py index 383ce86b82f5..6a2ee0b65636 100644 --- a/python/plugins/grassprovider/ext/r_drain.py +++ b/python/plugins/grassprovider/ext/r_drain.py @@ -15,25 +15,32 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" def checkParameterValuesBeforeExecuting(alg, parameters, context): - """ Verify if we have the right parameters """ + """Verify if we have the right parameters""" # start_coordinates and start_points are mutually exclusives - if (alg.parameterAsString(parameters, 'start_coordinates', context) - and alg.parameterAsVectorLayer(parameters, 'start_points', context)): - return False, alg.tr("You need to set either start coordinates OR a start points vector layer!") + if alg.parameterAsString( + parameters, "start_coordinates", context + ) and alg.parameterAsVectorLayer(parameters, "start_points", context): + return False, alg.tr( + "You need to set either start coordinates OR a start points vector layer!" + ) # You need to set at least one parameter - if (not alg.parameterAsString(parameters, 'start_coordinates', context) - and not alg.parameterAsVectorLayer(parameters, 'start_points', context)): - return False, alg.tr("You need to set either start coordinates OR a start points vector layer!") + if not alg.parameterAsString( + parameters, "start_coordinates", context + ) and not alg.parameterAsVectorLayer(parameters, "start_points", context): + return False, alg.tr( + "You need to set either start coordinates OR a start points vector layer!" + ) - paramscore = [f for f in ['-c', '-a', '-n'] - if alg.parameterAsBoolean(parameters, f, context)] + paramscore = [ + f for f in ["-c", "-a", "-n"] if alg.parameterAsBoolean(parameters, f, context) + ] if len(paramscore) > 1: return False, alg.tr("-c, -a, -n parameters are mutually exclusive!") return True, None diff --git a/python/plugins/grassprovider/ext/r_horizon.py b/python/plugins/grassprovider/ext/r_horizon.py index b287352c8c82..36a4b024d646 100644 --- a/python/plugins/grassprovider/ext/r_horizon.py +++ b/python/plugins/grassprovider/ext/r_horizon.py @@ -15,19 +15,19 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'September 2017' -__copyright__ = '(C) 2017, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "September 2017" +__copyright__ = "(C) 2017, Médéric Ribreux" import os import math def checkParameterValuesBeforeExecuting(alg, parameters, context): - """ Verify if we have the right parameters """ - start = alg.parameterAsDouble(parameters, 'start', context) - end = alg.parameterAsDouble(parameters, 'end', context) - step = alg.parameterAsDouble(parameters, 'step', context) + """Verify if we have the right parameters""" + start = alg.parameterAsDouble(parameters, "start", context) + end = alg.parameterAsDouble(parameters, "end", context) + step = alg.parameterAsDouble(parameters, "step", context) if start >= end: return False, alg.tr("The start position must be inferior to the end position!") @@ -39,7 +39,7 @@ def checkParameterValuesBeforeExecuting(alg, parameters, context): def processOutputs(alg, parameters, context, feedback): # Inspired from GRASS implementation def getNumberDecimals(number): - """ Return the number of decimals of a number (int or float) """ + """Return the number of decimals of a number (int or float)""" if int(number) == number: return 0 return len(str(number).split(".")[-1]) @@ -52,28 +52,28 @@ def doubleToBaseName(number, nDecimals): number += 0.0001 # adapted from GRASS https://github.com/OSGeo/grass/blob/6253da1bd6ce48d23419e99e8b503edf46178490/lib/gis/basename.c#L97-L101 if nDecimals == 0: - return f'{int(number):03}' + return f"{int(number):03}" int_part = int(number) dec_part = int((number - int_part) * pow(10, nDecimals)) return f'{int_part:03}_{str(dec_part).rjust(nDecimals, "0")}' # There will be as many outputs as the difference between start and end divided by steps - start = alg.parameterAsDouble(parameters, 'start', context) - end = alg.parameterAsDouble(parameters, 'end', context) - step = alg.parameterAsDouble(parameters, 'step', context) - direction = alg.parameterAsDouble(parameters, 'direction', context) + start = alg.parameterAsDouble(parameters, "start", context) + end = alg.parameterAsDouble(parameters, "end", context) + step = alg.parameterAsDouble(parameters, "step", context) + direction = alg.parameterAsDouble(parameters, "direction", context) first_rad = math.radians(start + direction) nDecimals = getNumberDecimals(step) dfr_rad = math.radians(step) arrayNumInt = int((end - start) / abs(step)) - directory = alg.parameterAsString(parameters, 'output', context) + directory = alg.parameterAsString(parameters, "output", context) # Needed if output to a temporary directory os.makedirs(directory, exist_ok=True) for k in range(arrayNumInt): angle_deg = math.degrees(first_rad + dfr_rad * k) baseName = doubleToBaseName(angle_deg, nDecimals) - grassName = f'output{alg.uniqueSuffix}_{baseName}' - fileName = f'{os.path.join(directory, baseName)}.tif' + grassName = f"output{alg.uniqueSuffix}_{baseName}" + fileName = f"{os.path.join(directory, baseName)}.tif" alg.exportRasterLayer(grassName, fileName) diff --git a/python/plugins/grassprovider/ext/r_li.py b/python/plugins/grassprovider/ext/r_li.py index 351414bc7c5d..4d8fad728606 100644 --- a/python/plugins/grassprovider/ext/r_li.py +++ b/python/plugins/grassprovider/ext/r_li.py @@ -15,68 +15,75 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" import shutil from qgis.core import QgsProcessingParameterString -from processing.tools.system import (isWindows, mkdir, - getTempFilename) +from processing.tools.system import isWindows, mkdir, getTempFilename from grassprovider.grass_utils import GrassUtils import os # for MS-Windows users who have MBCS chars in their name: -if os.name == 'nt': +if os.name == "nt": import win32api def rliPath(): """Return r.li GRASS user dir""" - grass_version = GrassUtils.installedVersion().split('.')[0] + grass_version = GrassUtils.installedVersion().split(".")[0] if isWindows(): - homeDir = win32api.GetShortPathName(os.path.expanduser('~')) - return os.path.join(homeDir, 'AppData', 'Roaming', f'GRASS{grass_version}', 'r.li') + homeDir = win32api.GetShortPathName(os.path.expanduser("~")) + return os.path.join( + homeDir, "AppData", "Roaming", f"GRASS{grass_version}", "r.li" + ) else: - return os.path.join(os.path.expanduser("~"), f'.grass{grass_version}', 'r.li') + return os.path.join(os.path.expanduser("~"), f".grass{grass_version}", "r.li") def removeConfigFile(alg, parameters, context): - """ Remove the r.li user dir config file """ - configPath = alg.parameterAsString(parameters, 'config', context) + """Remove the r.li user dir config file""" + configPath = alg.parameterAsString(parameters, "config", context) if isWindows(): - command = "DEL {}".format(os.path.join(rliPath(), configPath)) + command = f"DEL {os.path.join(rliPath(), configPath)}" else: - command = "rm {}".format(os.path.join(rliPath(), configPath)) + command = f"rm {os.path.join(rliPath(), configPath)}" alg.commands.append(command) def checkMovingWindow(alg, parameters, context, outputTxt=False): - """ Verify if we have the right parameters """ - configTxt = alg.parameterAsString(parameters, 'config_txt', context) - config = alg.parameterAsString(parameters, 'config', context) + """Verify if we have the right parameters""" + configTxt = alg.parameterAsString(parameters, "config_txt", context) + config = alg.parameterAsString(parameters, "config", context) if configTxt and config: - return False, alg.tr("You need to set either inline configuration or a configuration file!") + return False, alg.tr( + "You need to set either inline configuration or a configuration file!" + ) # Verify that configuration is in moving window movingWindow = False if configTxt: - if 'MOVINGWINDOW' in configTxt: + if "MOVINGWINDOW" in configTxt: movingWindow = True # Read config file: if config: with open(config) as f: for line in f: - if 'MOVINGWINDOW' in line: + if "MOVINGWINDOW" in line: movingWindow = True if not movingWindow and not outputTxt: - return False, alg.tr('Your configuration needs to be a "moving window" configuration!') + return False, alg.tr( + 'Your configuration needs to be a "moving window" configuration!' + ) if movingWindow and outputTxt: - return False, alg.tr('Your configuration needs to be a non "moving window" configuration!') + return False, alg.tr( + 'Your configuration needs to be a non "moving window" configuration!' + ) return True, None @@ -89,37 +96,40 @@ def configFile(alg, parameters, context, feedback, outputTxt=False): user_grass_path = rliPath() if not os.path.isdir(user_grass_path): mkdir(user_grass_path) - if not os.path.isdir(os.path.join(user_grass_path, 'output')): - mkdir(os.path.join(user_grass_path, 'output')) + if not os.path.isdir(os.path.join(user_grass_path, "output")): + mkdir(os.path.join(user_grass_path, "output")) # If we have a configuration file, we need to copy it into user dir - if parameters['config']: - fileName = alg.parameterAsString(parameters, 'config', context) + if parameters["config"]: + fileName = alg.parameterAsString(parameters, "config", context) configFilePath = os.path.join(user_grass_path, os.path.basename(fileName)) # Copy the file - shutil.copy(parameters['config'], configFilePath) + shutil.copy(parameters["config"], configFilePath) # Change the parameter value - parameters['config'] = os.path.basename(configFilePath) + parameters["config"] = os.path.basename(configFilePath) # Handle inline configuration - elif parameters['config_txt']: + elif parameters["config_txt"]: # Creates a temporary txt file in user r.li directory tempConfig = os.path.basename(getTempFilename(context=context)) configFilePath = os.path.join(user_grass_path, tempConfig) # Inject rules into temporary txt file with open(configFilePath, "w") as f: - f.write(alg.parameterAsString(parameters, 'config_txt', context)) + f.write(alg.parameterAsString(parameters, "config_txt", context)) f.write("\n") # Use temporary file as rules file - parameters['config'] = os.path.basename(configFilePath) - alg.removeParameter('config_txt') + parameters["config"] = os.path.basename(configFilePath) + alg.removeParameter("config_txt") # For ascii output, we need a virtual output if outputTxt: param = QgsProcessingParameterString( - 'output', 'virtual output', - 'a' + os.path.basename(getTempFilename(context=context)), - False, False) + "output", + "virtual output", + "a" + os.path.basename(getTempFilename(context=context)), + False, + False, + ) alg.addParameter(param) alg.processCommand(parameters, context, feedback, outputTxt) @@ -130,14 +140,15 @@ def configFile(alg, parameters, context, feedback, outputTxt=False): def moveOutputTxtFile(alg, parameters, context): # Find output file name: - txtPath = alg.parameterAsString(parameters, 'output_txt', context) + txtPath = alg.parameterAsString(parameters, "output_txt", context) user_grass_path = rliPath() - output = os.path.join(user_grass_path, 'output', - alg.parameterAsString(parameters, 'output', context)) + output = os.path.join( + user_grass_path, "output", alg.parameterAsString(parameters, "output", context) + ) # move the file if isWindows(): - command = "MOVE /Y {} {}".format(output, txtPath) + command = f"MOVE /Y {output} {txtPath}" else: - command = "mv -f {} {}".format(output, txtPath) + command = f"mv -f {output} {txtPath}" alg.commands.append(command) diff --git a/python/plugins/grassprovider/ext/r_li_cwed.py b/python/plugins/grassprovider/ext/r_li_cwed.py index 50e80c989b81..185746668b3d 100644 --- a/python/plugins/grassprovider/ext/r_li_cwed.py +++ b/python/plugins/grassprovider/ext/r_li_cwed.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile diff --git a/python/plugins/grassprovider/ext/r_li_cwed_ascii.py b/python/plugins/grassprovider/ext/r_li_cwed_ascii.py index 497a882d4245..8052ce48e699 100644 --- a/python/plugins/grassprovider/ext/r_li_cwed_ascii.py +++ b/python/plugins/grassprovider/ext/r_li_cwed_ascii.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile, moveOutputTxtFile diff --git a/python/plugins/grassprovider/ext/r_li_dominance.py b/python/plugins/grassprovider/ext/r_li_dominance.py index 6e3a0a3eefd9..c869f3efc300 100644 --- a/python/plugins/grassprovider/ext/r_li_dominance.py +++ b/python/plugins/grassprovider/ext/r_li_dominance.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile diff --git a/python/plugins/grassprovider/ext/r_li_dominance_ascii.py b/python/plugins/grassprovider/ext/r_li_dominance_ascii.py index eb6b77f96340..a8aed9fa2ca2 100644 --- a/python/plugins/grassprovider/ext/r_li_dominance_ascii.py +++ b/python/plugins/grassprovider/ext/r_li_dominance_ascii.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile, moveOutputTxtFile diff --git a/python/plugins/grassprovider/ext/r_li_edgedensity.py b/python/plugins/grassprovider/ext/r_li_edgedensity.py index 5beac0885069..165c6f4030ca 100644 --- a/python/plugins/grassprovider/ext/r_li_edgedensity.py +++ b/python/plugins/grassprovider/ext/r_li_edgedensity.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile diff --git a/python/plugins/grassprovider/ext/r_li_edgedensity_ascii.py b/python/plugins/grassprovider/ext/r_li_edgedensity_ascii.py index a416d6ed68d4..2c4c4ed3c48f 100644 --- a/python/plugins/grassprovider/ext/r_li_edgedensity_ascii.py +++ b/python/plugins/grassprovider/ext/r_li_edgedensity_ascii.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile, moveOutputTxtFile diff --git a/python/plugins/grassprovider/ext/r_li_mpa.py b/python/plugins/grassprovider/ext/r_li_mpa.py index 1fd13334eccd..e2a481a8cc06 100644 --- a/python/plugins/grassprovider/ext/r_li_mpa.py +++ b/python/plugins/grassprovider/ext/r_li_mpa.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile diff --git a/python/plugins/grassprovider/ext/r_li_mpa_ascii.py b/python/plugins/grassprovider/ext/r_li_mpa_ascii.py index 90597643824f..22504a71c849 100644 --- a/python/plugins/grassprovider/ext/r_li_mpa_ascii.py +++ b/python/plugins/grassprovider/ext/r_li_mpa_ascii.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile, moveOutputTxtFile diff --git a/python/plugins/grassprovider/ext/r_li_mps.py b/python/plugins/grassprovider/ext/r_li_mps.py index f7de0f61977d..cdeed825ea57 100644 --- a/python/plugins/grassprovider/ext/r_li_mps.py +++ b/python/plugins/grassprovider/ext/r_li_mps.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile diff --git a/python/plugins/grassprovider/ext/r_li_mps_ascii.py b/python/plugins/grassprovider/ext/r_li_mps_ascii.py index eac3c41b64b8..b36396ac788b 100644 --- a/python/plugins/grassprovider/ext/r_li_mps_ascii.py +++ b/python/plugins/grassprovider/ext/r_li_mps_ascii.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile, moveOutputTxtFile diff --git a/python/plugins/grassprovider/ext/r_li_padcv.py b/python/plugins/grassprovider/ext/r_li_padcv.py index cfb4310e8b5c..1f90af63f38d 100644 --- a/python/plugins/grassprovider/ext/r_li_padcv.py +++ b/python/plugins/grassprovider/ext/r_li_padcv.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile diff --git a/python/plugins/grassprovider/ext/r_li_padcv_ascii.py b/python/plugins/grassprovider/ext/r_li_padcv_ascii.py index 0e045ec1471d..63d2cca7151f 100644 --- a/python/plugins/grassprovider/ext/r_li_padcv_ascii.py +++ b/python/plugins/grassprovider/ext/r_li_padcv_ascii.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile, moveOutputTxtFile diff --git a/python/plugins/grassprovider/ext/r_li_padrange.py b/python/plugins/grassprovider/ext/r_li_padrange.py index 24db8ae167d1..f520a0de8b97 100644 --- a/python/plugins/grassprovider/ext/r_li_padrange.py +++ b/python/plugins/grassprovider/ext/r_li_padrange.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile diff --git a/python/plugins/grassprovider/ext/r_li_padrange_ascii.py b/python/plugins/grassprovider/ext/r_li_padrange_ascii.py index 0d7d61f1a87c..57856b40ae49 100644 --- a/python/plugins/grassprovider/ext/r_li_padrange_ascii.py +++ b/python/plugins/grassprovider/ext/r_li_padrange_ascii.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile, moveOutputTxtFile diff --git a/python/plugins/grassprovider/ext/r_li_padsd.py b/python/plugins/grassprovider/ext/r_li_padsd.py index 17b29fc05885..f6bce09eb436 100644 --- a/python/plugins/grassprovider/ext/r_li_padsd.py +++ b/python/plugins/grassprovider/ext/r_li_padsd.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile diff --git a/python/plugins/grassprovider/ext/r_li_padsd_ascii.py b/python/plugins/grassprovider/ext/r_li_padsd_ascii.py index 8c7e7c22c5ee..c5a700daa7d1 100644 --- a/python/plugins/grassprovider/ext/r_li_padsd_ascii.py +++ b/python/plugins/grassprovider/ext/r_li_padsd_ascii.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile, moveOutputTxtFile diff --git a/python/plugins/grassprovider/ext/r_li_patchdensity.py b/python/plugins/grassprovider/ext/r_li_patchdensity.py index acc305aa828d..d658f4a3145c 100644 --- a/python/plugins/grassprovider/ext/r_li_patchdensity.py +++ b/python/plugins/grassprovider/ext/r_li_patchdensity.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile diff --git a/python/plugins/grassprovider/ext/r_li_patchdensity_ascii.py b/python/plugins/grassprovider/ext/r_li_patchdensity_ascii.py index 111efcbb18d7..620c33db1649 100644 --- a/python/plugins/grassprovider/ext/r_li_patchdensity_ascii.py +++ b/python/plugins/grassprovider/ext/r_li_patchdensity_ascii.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile, moveOutputTxtFile diff --git a/python/plugins/grassprovider/ext/r_li_patchnum.py b/python/plugins/grassprovider/ext/r_li_patchnum.py index 90f4ad460913..925b50620102 100644 --- a/python/plugins/grassprovider/ext/r_li_patchnum.py +++ b/python/plugins/grassprovider/ext/r_li_patchnum.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile diff --git a/python/plugins/grassprovider/ext/r_li_patchnum_ascii.py b/python/plugins/grassprovider/ext/r_li_patchnum_ascii.py index ec2da01d8cf1..0ba1cd84e424 100644 --- a/python/plugins/grassprovider/ext/r_li_patchnum_ascii.py +++ b/python/plugins/grassprovider/ext/r_li_patchnum_ascii.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile, moveOutputTxtFile diff --git a/python/plugins/grassprovider/ext/r_li_pielou.py b/python/plugins/grassprovider/ext/r_li_pielou.py index f1a636527ad4..52af65e5efc4 100644 --- a/python/plugins/grassprovider/ext/r_li_pielou.py +++ b/python/plugins/grassprovider/ext/r_li_pielou.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile diff --git a/python/plugins/grassprovider/ext/r_li_pielou_ascii.py b/python/plugins/grassprovider/ext/r_li_pielou_ascii.py index 4ce58b91c42a..87162f84723e 100644 --- a/python/plugins/grassprovider/ext/r_li_pielou_ascii.py +++ b/python/plugins/grassprovider/ext/r_li_pielou_ascii.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile, moveOutputTxtFile diff --git a/python/plugins/grassprovider/ext/r_li_renyi.py b/python/plugins/grassprovider/ext/r_li_renyi.py index 5e34cad1df1c..8bacea15cf8c 100644 --- a/python/plugins/grassprovider/ext/r_li_renyi.py +++ b/python/plugins/grassprovider/ext/r_li_renyi.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile diff --git a/python/plugins/grassprovider/ext/r_li_renyi_ascii.py b/python/plugins/grassprovider/ext/r_li_renyi_ascii.py index 0d9925d9326d..2daea6fd3251 100644 --- a/python/plugins/grassprovider/ext/r_li_renyi_ascii.py +++ b/python/plugins/grassprovider/ext/r_li_renyi_ascii.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile, moveOutputTxtFile diff --git a/python/plugins/grassprovider/ext/r_li_richness.py b/python/plugins/grassprovider/ext/r_li_richness.py index fcfdcb2ad357..dc1c3c00908f 100644 --- a/python/plugins/grassprovider/ext/r_li_richness.py +++ b/python/plugins/grassprovider/ext/r_li_richness.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile diff --git a/python/plugins/grassprovider/ext/r_li_richness_ascii.py b/python/plugins/grassprovider/ext/r_li_richness_ascii.py index 2061d7a31be8..0eb2e6f85d76 100644 --- a/python/plugins/grassprovider/ext/r_li_richness_ascii.py +++ b/python/plugins/grassprovider/ext/r_li_richness_ascii.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile, moveOutputTxtFile diff --git a/python/plugins/grassprovider/ext/r_li_shannon.py b/python/plugins/grassprovider/ext/r_li_shannon.py index cb9d29700299..4d1ac79ab3de 100644 --- a/python/plugins/grassprovider/ext/r_li_shannon.py +++ b/python/plugins/grassprovider/ext/r_li_shannon.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile diff --git a/python/plugins/grassprovider/ext/r_li_shannon_ascii.py b/python/plugins/grassprovider/ext/r_li_shannon_ascii.py index 5614f5b92390..694cd1b3acaa 100644 --- a/python/plugins/grassprovider/ext/r_li_shannon_ascii.py +++ b/python/plugins/grassprovider/ext/r_li_shannon_ascii.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile, moveOutputTxtFile diff --git a/python/plugins/grassprovider/ext/r_li_shape.py b/python/plugins/grassprovider/ext/r_li_shape.py index 2c2a47a6e7c7..5f389425145e 100644 --- a/python/plugins/grassprovider/ext/r_li_shape.py +++ b/python/plugins/grassprovider/ext/r_li_shape.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile diff --git a/python/plugins/grassprovider/ext/r_li_shape_ascii.py b/python/plugins/grassprovider/ext/r_li_shape_ascii.py index fc6a99a00005..681426c94186 100644 --- a/python/plugins/grassprovider/ext/r_li_shape_ascii.py +++ b/python/plugins/grassprovider/ext/r_li_shape_ascii.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile, moveOutputTxtFile diff --git a/python/plugins/grassprovider/ext/r_li_simpson.py b/python/plugins/grassprovider/ext/r_li_simpson.py index b6486085d4df..6d54abfd0d2d 100644 --- a/python/plugins/grassprovider/ext/r_li_simpson.py +++ b/python/plugins/grassprovider/ext/r_li_simpson.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile diff --git a/python/plugins/grassprovider/ext/r_li_simpson_ascii.py b/python/plugins/grassprovider/ext/r_li_simpson_ascii.py index 8baf6755b15c..9d92f8c46a6c 100644 --- a/python/plugins/grassprovider/ext/r_li_simpson_ascii.py +++ b/python/plugins/grassprovider/ext/r_li_simpson_ascii.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from .r_li import checkMovingWindow, configFile, moveOutputTxtFile diff --git a/python/plugins/grassprovider/ext/r_mask_rast.py b/python/plugins/grassprovider/ext/r_mask_rast.py index 6d36a2eede9e..6adc80915266 100644 --- a/python/plugins/grassprovider/ext/r_mask_rast.py +++ b/python/plugins/grassprovider/ext/r_mask_rast.py @@ -15,16 +15,16 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from grassprovider.grass_utils import GrassUtils def processCommand(alg, parameters, context, feedback): # Remove input - alg.removeParameter('input') + alg.removeParameter("input") alg.processCommand(parameters, context, feedback, True) @@ -33,8 +33,7 @@ def processOutputs(alg, parameters, context, feedback): metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context) # We need to export the raster with all its bands and its color table - fileName = alg.parameterAsOutputLayer(parameters, 'output', context) + fileName = alg.parameterAsOutputLayer(parameters, "output", context) outFormat = GrassUtils.getRasterFormatFromFilename(fileName) - grassName = alg.exportedLayers['input'] - alg.exportRasterLayer(grassName, fileName, True, - outFormat, createOpt, metaOpt) + grassName = alg.exportedLayers["input"] + alg.exportRasterLayer(grassName, fileName, True, outFormat, createOpt, metaOpt) diff --git a/python/plugins/grassprovider/ext/r_mask_vect.py b/python/plugins/grassprovider/ext/r_mask_vect.py index 40e5fb2c3f73..f0a768fcb3b9 100644 --- a/python/plugins/grassprovider/ext/r_mask_vect.py +++ b/python/plugins/grassprovider/ext/r_mask_vect.py @@ -15,16 +15,16 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from grassprovider.grass_utils import GrassUtils def processCommand(alg, parameters, context, feedback): # Remove input - alg.removeParameter('input') + alg.removeParameter("input") alg.processCommand(parameters, context, feedback, True) @@ -33,8 +33,7 @@ def processOutputs(alg, parameters, context, feedback): metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context) # We need to export the raster with all its bands and its color table - fileName = alg.parameterAsOutputLayer(parameters, 'output', context) + fileName = alg.parameterAsOutputLayer(parameters, "output", context) outFormat = GrassUtils.getRasterFormatFromFilename(fileName) - grassName = alg.exportedLayers['input'] - alg.exportRasterLayer(grassName, fileName, True, - outFormat, createOpt, metaOpt) + grassName = alg.exportedLayers["input"] + alg.exportRasterLayer(grassName, fileName, True, outFormat, createOpt, metaOpt) diff --git a/python/plugins/grassprovider/ext/r_neighbors.py b/python/plugins/grassprovider/ext/r_neighbors.py index 256b0313912c..d01f3c45a2dc 100644 --- a/python/plugins/grassprovider/ext/r_neighbors.py +++ b/python/plugins/grassprovider/ext/r_neighbors.py @@ -15,15 +15,15 @@ *************************************************************************** """ -__author__ = 'Nicolas Godet' -__date__ = 'June 2021' -__copyright__ = '(C) 2021, Nicolas Godet' +__author__ = "Nicolas Godet" +__date__ = "June 2021" +__copyright__ = "(C) 2021, Nicolas Godet" def checkParameterValuesBeforeExecuting(alg, parameters, context): - """ Verify if we have the right parameters """ + """Verify if we have the right parameters""" # Verifiy that neighborhood size is odd - if (alg.parameterAsInt(parameters, 'size', context) % 2) == 0: + if (alg.parameterAsInt(parameters, "size", context) % 2) == 0: return False, alg.tr("The neighborhood size must be odd!") return True, None diff --git a/python/plugins/grassprovider/ext/r_null.py b/python/plugins/grassprovider/ext/r_null.py index a3a1d0e82e71..1df7db79d716 100644 --- a/python/plugins/grassprovider/ext/r_null.py +++ b/python/plugins/grassprovider/ext/r_null.py @@ -15,27 +15,30 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" def checkParameterValuesBeforeExecuting(alg, parameters, context): - """ Verify if we have the right parameters """ - if (alg.parameterAsString(parameters, 'setnull', context) - or alg.parameterAsString(parameters, 'null', context)): + """Verify if we have the right parameters""" + if alg.parameterAsString(parameters, "setnull", context) or alg.parameterAsString( + parameters, "null", context + ): return True, None - return False, alg.tr("You need to set at least 'setnull' or 'null' parameters for this algorithm!") + return False, alg.tr( + "You need to set at least 'setnull' or 'null' parameters for this algorithm!" + ) def processInputs(alg, parameters, context, feedback): """Prepare the GRASS import commands""" - if 'map' in alg.exportedLayers: + if "map" in alg.exportedLayers: return # We need to import without r.external - alg.loadRasterLayerFromParameter('map', parameters, context, False) + alg.loadRasterLayerFromParameter("map", parameters, context, False) alg.postInputs(context) @@ -45,6 +48,6 @@ def processCommand(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback): - fileName = alg.parameterAsOutputLayer(parameters, 'output', context) - grassName = alg.exportedLayers['map'] + fileName = alg.parameterAsOutputLayer(parameters, "output", context) + grassName = alg.exportedLayers["map"] alg.exportRasterLayer(grassName, fileName, False) diff --git a/python/plugins/grassprovider/ext/r_proj.py b/python/plugins/grassprovider/ext/r_proj.py index 46d0f7549308..5899948ed329 100644 --- a/python/plugins/grassprovider/ext/r_proj.py +++ b/python/plugins/grassprovider/ext/r_proj.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'October 2017' -__copyright__ = '(C) 2017, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "October 2017" +__copyright__ = "(C) 2017, Médéric Ribreux" from qgis.core import QgsProcessingParameterString from processing.tools.system import isWindows @@ -26,50 +26,51 @@ def processInputs(alg, parameters, context, feedback): # Grab the projection from the input vector layer - layer = alg.parameterAsLayer(parameters, 'input', context) + layer = alg.parameterAsLayer(parameters, "input", context) # Creates a new location with this Crs wkt_file_name = GrassUtils.exportCrsWktToFile(layer.crs(), context) - newLocation = 'newProj{}'.format(alg.uniqueSuffix) - alg.commands.append('g.proj wkt="{}" location={}'.format( - wkt_file_name, newLocation)) + newLocation = f"newProj{alg.uniqueSuffix}" + alg.commands.append(f'g.proj wkt="{wkt_file_name}" location={newLocation}') # Go to the newly created location - alg.commands.append('g.mapset mapset=PERMANENT location={}'.format( - newLocation)) + alg.commands.append(f"g.mapset mapset=PERMANENT location={newLocation}") # Import the layer - alg.loadRasterLayerFromParameter( - 'input', parameters, context, False) + alg.loadRasterLayerFromParameter("input", parameters, context, False) # Go back to default location - alg.commands.append('g.mapset mapset=PERMANENT location=temp_location') + alg.commands.append("g.mapset mapset=PERMANENT location=temp_location") # Grab the projected Crs - crs = alg.parameterAsCrs(parameters, 'crs', context) + crs = alg.parameterAsCrs(parameters, "crs", context) wkt_file_name = GrassUtils.exportCrsWktToFile(crs, context) - alg.commands.append('g.proj -c wkt="{}"'.format(wkt_file_name)) + alg.commands.append(f'g.proj -c wkt="{wkt_file_name}"') # Remove crs parameter - alg.removeParameter('crs') + alg.removeParameter("crs") # Add the location parameter with proper value location = QgsProcessingParameterString( - 'location', - 'new location', - 'newProj{}'.format(alg.uniqueSuffix) + "location", "new location", f"newProj{alg.uniqueSuffix}" ) alg.addParameter(location) # And set the region - grassName = alg.exportedLayers['input'] + grassName = alg.exportedLayers["input"] # We use the shell to capture the results from r.proj -g if isWindows(): # TODO: make some tests under a non POSIX shell - alg.commands.append('set regVar=') - alg.commands.append('for /f "delims=" %%a in (\'r.proj -g input^="{}" location^="{}"\') do @set regVar=%%a'.format( - grassName, newLocation)) - alg.commands.append('g.region -a %regVar%') + alg.commands.append("set regVar=") + alg.commands.append( + 'for /f "delims=" %%a in (\'r.proj -g input^="{}" location^="{}"\') do @set regVar=%%a'.format( + grassName, newLocation + ) + ) + alg.commands.append("g.region -a %regVar%") else: - alg.commands.append('g.region -a $(r.proj -g input="{}" location="{}")'.format( - grassName, newLocation)) + alg.commands.append( + 'g.region -a $(r.proj -g input="{}" location="{}")'.format( + grassName, newLocation + ) + ) diff --git a/python/plugins/grassprovider/ext/r_reclass.py b/python/plugins/grassprovider/ext/r_reclass.py index f29bf528b127..13cfb74f5793 100644 --- a/python/plugins/grassprovider/ext/r_reclass.py +++ b/python/plugins/grassprovider/ext/r_reclass.py @@ -15,25 +15,28 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from processing.tools.system import getTempFilename def checkParameterValuesBeforeExecuting(alg, parameters, context): - """ Verify if we have the right parameters """ - if (alg.parameterAsString(parameters, 'rules', context) - and alg.parameterAsString(parameters, 'txtrules', context)): - return False, alg.tr("You need to set either a rules file or write directly the rules!") + """Verify if we have the right parameters""" + if alg.parameterAsString(parameters, "rules", context) and alg.parameterAsString( + parameters, "txtrules", context + ): + return False, alg.tr( + "You need to set either a rules file or write directly the rules!" + ) return True, None def processCommand(alg, parameters, context, feedback): - """ Handle inline rules """ - txtRules = alg.parameterAsString(parameters, 'txtrules', context) + """Handle inline rules""" + txtRules = alg.parameterAsString(parameters, "txtrules", context) if txtRules: # Creates a temporary txt file tempRulesName = getTempFilename(context=context) @@ -41,7 +44,7 @@ def processCommand(alg, parameters, context, feedback): # Inject rules into temporary txt file with open(tempRulesName, "w") as tempRules: tempRules.write(txtRules) - alg.removeParameter('txtrules') - parameters['rules'] = tempRulesName + alg.removeParameter("txtrules") + parameters["rules"] = tempRulesName alg.processCommand(parameters, context, feedback) diff --git a/python/plugins/grassprovider/ext/r_resamp_filter.py b/python/plugins/grassprovider/ext/r_resamp_filter.py index df57b247b771..7b0453c9bb38 100644 --- a/python/plugins/grassprovider/ext/r_resamp_filter.py +++ b/python/plugins/grassprovider/ext/r_resamp_filter.py @@ -15,18 +15,20 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" def checkParameterValuesBeforeExecuting(alg, parameters, context): - """ Verify if we have the right parameters """ - radius = alg.parameterAsString(parameters, 'radius', context) - x_radius = alg.parameterAsString(parameters, 'x_radius', context) - y_radius = alg.parameterAsString(parameters, 'y_radius', context) + """Verify if we have the right parameters""" + radius = alg.parameterAsString(parameters, "radius", context) + x_radius = alg.parameterAsString(parameters, "x_radius", context) + y_radius = alg.parameterAsString(parameters, "y_radius", context) - if (not radius and not x_radius and not y_radius) or (radius and (x_radius or y_radius)): + if (not radius and not x_radius and not y_radius) or ( + radius and (x_radius or y_radius) + ): return False, alg.tr("You need to set either radius or x_radius and y_radius!") elif (x_radius and not y_radius) or (y_radius and not x_radius): return False, alg.tr("You need to set x_radius and y_radius!") diff --git a/python/plugins/grassprovider/ext/r_rgb.py b/python/plugins/grassprovider/ext/r_rgb.py index bc8d3e7b3daf..257912a7539a 100644 --- a/python/plugins/grassprovider/ext/r_rgb.py +++ b/python/plugins/grassprovider/ext/r_rgb.py @@ -15,45 +15,47 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" def processInputs(alg, parameters, context, feedback): - if 'input' in alg.exportedLayers: + if "input" in alg.exportedLayers: return # We need to import all the bands and color tables of the input raster - alg.loadRasterLayerFromParameter('input', parameters, context, False, None) + alg.loadRasterLayerFromParameter("input", parameters, context, False, None) alg.postInputs(context) def processCommand(alg, parameters, context, feedback): # if the input raster is multiband: export each component directly - rasterInput = alg.exportedLayers['input'] - raster = alg.parameterAsRasterLayer(parameters, 'input', context) - for color in ['red', 'green', 'blue']: + rasterInput = alg.exportedLayers["input"] + raster = alg.parameterAsRasterLayer(parameters, "input", context) + for color in ["red", "green", "blue"]: alg.exportedLayers[color] = color + alg.uniqueSuffix # If the raster is not multiband, really do r.rgb if raster.bandCount() == 1: - alg.commands.append(" r.rgb input={} red={} green={} blue={} --overwrite".format( - rasterInput, - alg.exportedLayers['red'], - alg.exportedLayers['green'], - alg.exportedLayers['blue'] - )) + alg.commands.append( + " r.rgb input={} red={} green={} blue={} --overwrite".format( + rasterInput, + alg.exportedLayers["red"], + alg.exportedLayers["green"], + alg.exportedLayers["blue"], + ) + ) def processOutputs(alg, parameters, context, feedback): - raster = alg.parameterAsRasterLayer(parameters, 'input', context) + raster = alg.parameterAsRasterLayer(parameters, "input", context) # if the raster was monoband, export from r.rgb - for color in ['red', 'green', 'blue']: + for color in ["red", "green", "blue"]: fileName = alg.parameterAsOutputLayer(parameters, color, context) if raster.bandCount() == 1: - grassName = '{}{}'.format(color, alg.uniqueSuffix) + grassName = f"{color}{alg.uniqueSuffix}" else: - grassName = '{}.{}'.format(alg.exportedLayers['input'], color) + grassName = "{}.{}".format(alg.exportedLayers["input"], color) alg.exportRasterLayer(grassName, fileName, True) diff --git a/python/plugins/grassprovider/ext/r_series_interp.py b/python/plugins/grassprovider/ext/r_series_interp.py index 0135c46d3f5b..4a4cd6462d50 100644 --- a/python/plugins/grassprovider/ext/r_series_interp.py +++ b/python/plugins/grassprovider/ext/r_series_interp.py @@ -15,27 +15,33 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" import os from grassprovider.grass_utils import GrassUtils def checkParameterValuesBeforeExecuting(alg, parameters, context): - """ Verify if we have the right parameters """ - datapos = alg.parameterAsDouble(parameters, 'datapos', context) - infile = alg.parameterAsString(parameters, 'infile', context) - output = alg.parameterAsString(parameters, 'output', context) - outfile = alg.parameterAsString(parameters, 'outfile', context) + """Verify if we have the right parameters""" + datapos = alg.parameterAsDouble(parameters, "datapos", context) + infile = alg.parameterAsString(parameters, "infile", context) + output = alg.parameterAsString(parameters, "output", context) + outfile = alg.parameterAsString(parameters, "outfile", context) if datapos and infile: - return False, alg.tr("You need to set either inline data positions or an input data positions file!") + return False, alg.tr( + "You need to set either inline data positions or an input data positions file!" + ) if output and outfile: - return False, alg.tr("You need to set either sampling data positions or an output sampling data positions file!") + return False, alg.tr( + "You need to set either sampling data positions or an output sampling data positions file!" + ) if not (datapos or infile or output or outfile): - return False, alg.tr("You need to set input and output data positions parameters!") + return False, alg.tr( + "You need to set input and output data positions parameters!" + ) return True, None @@ -46,18 +52,18 @@ def processCommand(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback): # We take all the outputs and we export them to the output directory - outputDir = alg.parameterAsString(parameters, 'output_dir', context) - output = alg.parameterAsString(parameters, 'output', context) - outfile = alg.parameterAsString(parameters, 'outfile', context) + outputDir = alg.parameterAsString(parameters, "output_dir", context) + output = alg.parameterAsString(parameters, "output", context) + outfile = alg.parameterAsString(parameters, "outfile", context) outs = [] if output: - outs = output.split(',') + outs = output.split(",") elif outfile: # Handle file manually to find the name of the layers with open(outfile) as f: for line in f: - if '|' in line: - outs.append(line.split('|')[0]) + if "|" in line: + outs.append(line.split("|")[0]) createOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_OPT, context) metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context) @@ -66,5 +72,4 @@ def processOutputs(alg, parameters, context, feedback): # We need to export the raster with all its bands and its color table fileName = os.path.join(outputDir, out) outFormat = GrassUtils.getRasterFormatFromFilename(fileName) - alg.exportRasterLayer(out, fileName, True, - outFormat, createOpt, metaOpt) + alg.exportRasterLayer(out, fileName, True, outFormat, createOpt, metaOpt) diff --git a/python/plugins/grassprovider/ext/r_shade.py b/python/plugins/grassprovider/ext/r_shade.py index bcd6d7aa5a20..2e5588a56733 100644 --- a/python/plugins/grassprovider/ext/r_shade.py +++ b/python/plugins/grassprovider/ext/r_shade.py @@ -15,19 +15,17 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" def processInputs(alg, parameters, context, feedback): # We need to import all the bands and color tables of the input rasters - alg.loadRasterLayerFromParameter('shade', parameters, context, - False, None) - alg.loadRasterLayerFromParameter('color', parameters, context, - False, None) + alg.loadRasterLayerFromParameter("shade", parameters, context, False, None) + alg.loadRasterLayerFromParameter("color", parameters, context, False, None) def processOutputs(alg, parameters, context, feedback): # Keep color table - alg.exportRasterLayerFromParameter('output', parameters, context, True) + alg.exportRasterLayerFromParameter("output", parameters, context, True) diff --git a/python/plugins/grassprovider/ext/r_statistics.py b/python/plugins/grassprovider/ext/r_statistics.py index 11f403c70782..b822eaa3bc62 100644 --- a/python/plugins/grassprovider/ext/r_statistics.py +++ b/python/plugins/grassprovider/ext/r_statistics.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'September 2017' -__copyright__ = '(C) 2017, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "September 2017" +__copyright__ = "(C) 2017, Médéric Ribreux" from qgis.core import QgsProcessingParameterString from grassprovider.grass_utils import GrassUtils @@ -25,17 +25,16 @@ def processCommand(alg, parameters, context, feedback): # We had a new "output" parameter - out = 'output{}'.format(alg.uniqueSuffix) - p = QgsProcessingParameterString('~output', None, out, False, False) + out = f"output{alg.uniqueSuffix}" + p = QgsProcessingParameterString("~output", None, out, False, False) alg.addParameter(p) # We need to remove all outputs alg.processCommand(parameters, context, feedback, True) # Then we add a new command for treating results - calcExpression = 'correctedoutput{}=@{}'.format( - alg.uniqueSuffix, out) - command = 'r.mapcalc expression="{}"'.format(calcExpression) + calcExpression = f"correctedoutput{alg.uniqueSuffix}=@{out}" + command = f'r.mapcalc expression="{calcExpression}"' alg.commands.append(command) @@ -44,9 +43,7 @@ def processOutputs(alg, parameters, context, feedback): metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context) # Export the results from correctedoutput - grassName = 'correctedoutput{}'.format(alg.uniqueSuffix) - fileName = alg.parameterAsOutputLayer( - parameters, 'routput', context) + grassName = f"correctedoutput{alg.uniqueSuffix}" + fileName = alg.parameterAsOutputLayer(parameters, "routput", context) outFormat = GrassUtils.getRasterFormatFromFilename(fileName) - alg.exportRasterLayer(grassName, fileName, True, - outFormat, createOpt, metaOpt) + alg.exportRasterLayer(grassName, fileName, True, outFormat, createOpt, metaOpt) diff --git a/python/plugins/grassprovider/ext/r_stats_quantile_rast.py b/python/plugins/grassprovider/ext/r_stats_quantile_rast.py index ccd8e4ca6316..d66490ba1350 100644 --- a/python/plugins/grassprovider/ext/r_stats_quantile_rast.py +++ b/python/plugins/grassprovider/ext/r_stats_quantile_rast.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" import os from qgis.core import QgsProcessingParameterString @@ -26,13 +26,13 @@ def processCommand(alg, parameters, context, feedback): # We create the output sequence according to percentiles number - quantiles = alg.parameterAsInt(parameters, 'quantiles', context) - 1 + quantiles = alg.parameterAsInt(parameters, "quantiles", context) - 1 outputs = [] for i in range(0, int(quantiles)): - outputs.append('output_{}'.format(i)) + outputs.append(f"output_{i}") param = QgsProcessingParameterString( - 'output', 'virtual output', - ','.join(outputs), False, False) + "output", "virtual output", ",".join(outputs), False, False + ) alg.addParameter(param) # Removes outputs @@ -42,13 +42,12 @@ def processCommand(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback): createOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_OPT, context) metaOpt = alg.parameterAsString(parameters, alg.GRASS_RASTER_FORMAT_META, context) - outputDir = alg.parameterAsString(parameters, 'output_dir', context) - outputParam = alg.parameterAsString(parameters, 'output', context) - outputs = outputParam.split(',') + outputDir = alg.parameterAsString(parameters, "output_dir", context) + outputParam = alg.parameterAsString(parameters, "output", context) + outputs = outputParam.split(",") # We need to export each of the output for output in outputs: fileName = os.path.join(outputDir, output) outFormat = GrassUtils.getRasterFormatFromFilename(fileName) - alg.exportRasterLayer(output, fileName, True, - outFormat, createOpt, metaOpt) + alg.exportRasterLayer(output, fileName, True, outFormat, createOpt, metaOpt) diff --git a/python/plugins/grassprovider/ext/r_tileset.py b/python/plugins/grassprovider/ext/r_tileset.py index 15d8c8deb904..54de52025936 100644 --- a/python/plugins/grassprovider/ext/r_tileset.py +++ b/python/plugins/grassprovider/ext/r_tileset.py @@ -15,15 +15,15 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'October 2017' -__copyright__ = '(C) 2017, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "October 2017" +__copyright__ = "(C) 2017, Médéric Ribreux" from grassprovider.grass_utils import GrassUtils def processOutputs(alg, parameters, context, feedback): - crs = alg.parameterAsCrs(parameters, 'sourceproj', context) + crs = alg.parameterAsCrs(parameters, "sourceproj", context) wkt_file_name = GrassUtils.exportCrsWktToFile(crs, context) - alg.commands.insert(0, 'g.proj -c wkt="{}"'.format(wkt_file_name)) + alg.commands.insert(0, f'g.proj -c wkt="{wkt_file_name}"') diff --git a/python/plugins/grassprovider/ext/r_what_color.py b/python/plugins/grassprovider/ext/r_what_color.py index 9995e55922e4..ecf352a7935f 100644 --- a/python/plugins/grassprovider/ext/r_what_color.py +++ b/python/plugins/grassprovider/ext/r_what_color.py @@ -15,11 +15,11 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" def processInputs(alg, parameters, context, feedback): # We need to import all the bands and color tables of the input rasters - alg.loadRasterLayerFromParameter('input', parameters, context, False, None) + alg.loadRasterLayerFromParameter("input", parameters, context, False, None) diff --git a/python/plugins/grassprovider/ext/v_distance.py b/python/plugins/grassprovider/ext/v_distance.py index 7f1768d299cf..bf4ba6bf4d19 100644 --- a/python/plugins/grassprovider/ext/v_distance.py +++ b/python/plugins/grassprovider/ext/v_distance.py @@ -15,36 +15,42 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" from qgis.core import QgsProcessingParameterDefinition def checkParameterValuesBeforeExecuting(alg, parameters, context): - """ Verify if we have the right parameters """ + """Verify if we have the right parameters""" # Verifiy that we have the good number of columns - uploads = alg.parameterAsEnums(parameters, 'upload', context) - columns = alg.parameterAsFields(parameters, 'column', context) + uploads = alg.parameterAsEnums(parameters, "upload", context) + columns = alg.parameterAsFields(parameters, "column", context) if len(columns) != len(uploads): - return False, alg.tr("The number of columns and the number of upload parameters should be equal!") + return False, alg.tr( + "The number of columns and the number of upload parameters should be equal!" + ) return True, None def processCommand(alg, parameters, context, feedback): # We need to disable only from_output parameter - fromOutput = alg.parameterDefinition('from_output') - fromOutput.setFlags(fromOutput.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden) + fromOutput = alg.parameterDefinition("from_output") + fromOutput.setFlags( + fromOutput.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden + ) alg.processCommand(parameters, context, feedback, False) - fromOutput.setFlags(fromOutput.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden) + fromOutput.setFlags( + fromOutput.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden + ) def processOutputs(alg, parameters, context, feedback): alg.vectorOutputType(parameters, context) - alg.exportVectorLayerFromParameter('output', parameters, context) + alg.exportVectorLayerFromParameter("output", parameters, context) # for from_output, we export the initial layer - fileName = alg.parameterAsOutputLayer(parameters, 'from_output', context) - grassName = alg.exportedLayers['from'] + fileName = alg.parameterAsOutputLayer(parameters, "from_output", context) + grassName = alg.exportedLayers["from"] alg.exportVectorLayer(grassName, fileName) diff --git a/python/plugins/grassprovider/ext/v_edit.py b/python/plugins/grassprovider/ext/v_edit.py index 3091044ebd21..222741e13954 100644 --- a/python/plugins/grassprovider/ext/v_edit.py +++ b/python/plugins/grassprovider/ext/v_edit.py @@ -15,26 +15,29 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" import os from processing.tools.system import getTempFilename def checkParameterValuesBeforeExecuting(alg, parameters, context): - """ Verify if we have the right parameters """ - if (alg.parameterAsString(parameters, 'input_txt', context) - and alg.parameterAsString(parameters, 'input', context)): - return False, alg.tr("You need to set either an input ASCII file or inline data!") + """Verify if we have the right parameters""" + if alg.parameterAsString( + parameters, "input_txt", context + ) and alg.parameterAsString(parameters, "input", context): + return False, alg.tr( + "You need to set either an input ASCII file or inline data!" + ) return True, None def processCommand(alg, parameters, context, feedback): # Handle inline rules - txtRules = alg.parameterAsString(parameters, 'input_txt', context) + txtRules = alg.parameterAsString(parameters, "input_txt", context) if txtRules: # Creates a temporary txt file tempRulesName = getTempFilename(context=context) @@ -42,15 +45,15 @@ def processCommand(alg, parameters, context, feedback): # Inject rules into temporary txt file with open(tempRulesName, "w") as tempRules: tempRules.write(txtRules) - alg.removeParameter('input_txt') - parameters['input'] = tempRulesName + alg.removeParameter("input_txt") + parameters["input"] = tempRulesName alg.processCommand(parameters, context, feedback, True) def processOutputs(alg, parameters, context, feedback): # We need to add the from layer to outputs: - fileName = alg.parameterAsOutputLayer(parameters, 'output', context) - grassName = alg.exportedLayers['map'] - dataType = 'auto' + fileName = alg.parameterAsOutputLayer(parameters, "output", context) + grassName = alg.exportedLayers["map"] + dataType = "auto" alg.exportVectorLayer(grassName, fileName, dataType=dataType) diff --git a/python/plugins/grassprovider/ext/v_extrude.py b/python/plugins/grassprovider/ext/v_extrude.py index 487eb451769f..8ceb33b50293 100644 --- a/python/plugins/grassprovider/ext/v_extrude.py +++ b/python/plugins/grassprovider/ext/v_extrude.py @@ -15,16 +15,18 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" def checkParameterValuesBeforeExecuting(alg, parameters, context): - """ Verify if we have the right parameters """ - height = alg.parameterAsDouble(parameters, 'height', context) - height_column = alg.parameterAsString(parameters, 'height_column', context) + """Verify if we have the right parameters""" + height = alg.parameterAsDouble(parameters, "height", context) + height_column = alg.parameterAsString(parameters, "height_column", context) if (height and height_column) or (not height and not height_column): - return False, alg.tr("You need to set either a fixed height value or the height column!") + return False, alg.tr( + "You need to set either a fixed height value or the height column!" + ) return True, None diff --git a/python/plugins/grassprovider/ext/v_in_geonames.py b/python/plugins/grassprovider/ext/v_in_geonames.py index 569628f9b5e9..bd7ab4d38413 100644 --- a/python/plugins/grassprovider/ext/v_in_geonames.py +++ b/python/plugins/grassprovider/ext/v_in_geonames.py @@ -15,14 +15,14 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" def processCommand(alg, parameters, context, feedback): # v.in.geonames needs to use WGS84 projection - alg.commands.append('g.proj -c epsg=4326') + alg.commands.append("g.proj -c epsg=4326") # Launch the algorithm alg.processCommand(parameters, context, feedback) diff --git a/python/plugins/grassprovider/ext/v_net.py b/python/plugins/grassprovider/ext/v_net.py index 35d056a7dd2b..db4ac2513c4a 100644 --- a/python/plugins/grassprovider/ext/v_net.py +++ b/python/plugins/grassprovider/ext/v_net.py @@ -19,16 +19,23 @@ the network vector map. """ -__author__ = 'Médéric Ribreux' -__date__ = 'December 2015' -__copyright__ = '(C) 2015, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "December 2015" +__copyright__ = "(C) 2015, Médéric Ribreux" import os from qgis.core import QgsProcessingException from processing.tools.system import getTempFilename -def incorporatePoints(alg, parameters, context, feedback, pointLayerName='points', networkLayerName='input'): +def incorporatePoints( + alg, + parameters, + context, + feedback, + pointLayerName="points", + networkLayerName="input", +): """ incorporate points with lines to form a GRASS network """ @@ -37,7 +44,7 @@ def incorporatePoints(alg, parameters, context, feedback, pointLayerName='points pointLayer = alg.parameterAsVectorLayer(parameters, pointLayerName, context) if pointLayer: # Create an intermediate GRASS layer which is the combination of network + centers - intLayer = 'net' + os.path.basename(getTempFilename(context=context)) + intLayer = "net" + os.path.basename(getTempFilename(context=context)) pointLayer = alg.exportedLayers[pointLayerName] @@ -47,17 +54,19 @@ def incorporatePoints(alg, parameters, context, feedback, pointLayerName='points lineLayer = alg.exportedLayers[networkLayerName] else: raise QgsProcessingException( - alg.tr('GRASS GIS v.net requires a lines layer!')) + alg.tr("GRASS GIS v.net requires a lines layer!") + ) - threshold = alg.parameterAsDouble(parameters, 'threshold', context) + threshold = alg.parameterAsDouble(parameters, "threshold", context) # Create the v.net connect command for point layer integration - command = 'v.net -s input={} points={} output={} operation=connect threshold={}'.format( - lineLayer, pointLayer, intLayer, threshold) + command = "v.net -s input={} points={} output={} operation=connect threshold={}".format( + lineLayer, pointLayer, intLayer, threshold + ) alg.commands.append(command) # Connect the point layer database to the layer 2 of the network - command = 'v.db.connect -o map={} table={} layer=2'.format(intLayer, pointLayer) + command = f"v.db.connect -o map={intLayer} table={pointLayer} layer=2" alg.commands.append(command) # remove undesired parameters @@ -67,14 +76,14 @@ def incorporatePoints(alg, parameters, context, feedback, pointLayerName='points alg.exportedLayers[networkLayerName] = intLayer # Process the command - if 'threshold' in parameters: - alg.removeParameter('threshold') + if "threshold" in parameters: + alg.removeParameter("threshold") alg.processCommand(parameters, context, feedback) def variableOutput(alg, layers, parameters, context, nocats=True): - """ Handle variable data output for v.net modules: + """Handle variable data output for v.net modules: :param layers: layers is a dict of outputs: { 'outputName': ['srcLayer', 'output_type', output_layer_number, nocats], @@ -101,23 +110,25 @@ def variableOutput(alg, layers, parameters, context, nocats=True): output_layer_number = typeList[2] no_cats = typeList[3] - grass_name = '{}{}'.format(src_layer, alg.uniqueSuffix) - alg.exportVectorLayer(grassName=grass_name, - fileName=file_name, - layer=output_layer_number, - exportnocat=no_cats, - dataType=output_type) + grass_name = f"{src_layer}{alg.uniqueSuffix}" + alg.exportVectorLayer( + grassName=grass_name, + fileName=file_name, + layer=output_layer_number, + exportnocat=no_cats, + dataType=output_type, + ) def processOutputs(alg, parameters, context, feedback): - idx = alg.parameterAsInt(parameters, 'operation', context) - operations = alg.parameterDefinition('operation').options() + idx = alg.parameterAsInt(parameters, "operation", context) + operations = alg.parameterDefinition("operation").options() operation = operations[idx] - if operation == 'nodes': - outputParameter = {'output': ['output', 'point', 2, True]} - elif operation == 'connect': - outputParameter = {'output': ['output', 'line', 1, False]} - elif operation == 'arcs': - outputParameter = {'output': ['output', 'line', 1, True]} + if operation == "nodes": + outputParameter = {"output": ["output", "point", 2, True]} + elif operation == "connect": + outputParameter = {"output": ["output", "line", 1, False]} + elif operation == "arcs": + outputParameter = {"output": ["output", "line", 1, True]} variableOutput(alg, outputParameter, parameters, context) diff --git a/python/plugins/grassprovider/ext/v_net_alloc.py b/python/plugins/grassprovider/ext/v_net_alloc.py index 10f0844a8767..0b4d6aa13ed4 100644 --- a/python/plugins/grassprovider/ext/v_net_alloc.py +++ b/python/plugins/grassprovider/ext/v_net_alloc.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'December 2015' -__copyright__ = '(C) 2015, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "December 2015" +__copyright__ = "(C) 2015, Médéric Ribreux" from .v_net import incorporatePoints, variableOutput @@ -27,5 +27,5 @@ def processCommand(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback): - outputParameter = {'output': ['output', 'line', 1, False]} + outputParameter = {"output": ["output", "line", 1, False]} variableOutput(alg, outputParameter, parameters, context) diff --git a/python/plugins/grassprovider/ext/v_net_allpairs.py b/python/plugins/grassprovider/ext/v_net_allpairs.py index 43d23a668321..9823f7103442 100644 --- a/python/plugins/grassprovider/ext/v_net_allpairs.py +++ b/python/plugins/grassprovider/ext/v_net_allpairs.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'December 2015' -__copyright__ = '(C) 2015, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "December 2015" +__copyright__ = "(C) 2015, Médéric Ribreux" from .v_net import incorporatePoints, variableOutput @@ -27,5 +27,5 @@ def processCommand(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback): - outputParameter = {'output': ['output', 'line', 1, True]} + outputParameter = {"output": ["output", "line", 1, True]} variableOutput(alg, outputParameter, parameters, context) diff --git a/python/plugins/grassprovider/ext/v_net_bridge.py b/python/plugins/grassprovider/ext/v_net_bridge.py index 6a8ac8f35114..4a418d8d0ba3 100644 --- a/python/plugins/grassprovider/ext/v_net_bridge.py +++ b/python/plugins/grassprovider/ext/v_net_bridge.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'December 2015' -__copyright__ = '(C) 2015, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "December 2015" +__copyright__ = "(C) 2015, Médéric Ribreux" from .v_net import incorporatePoints, variableOutput @@ -27,12 +27,12 @@ def processCommand(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback): - idx = alg.parameterAsInt(parameters, 'method', context) - operations = alg.parameterDefinition('method').options() + idx = alg.parameterAsInt(parameters, "method", context) + operations = alg.parameterDefinition("method").options() operation = operations[idx] - if operation == 'articulation': - outputParameter = {'output': ['output', 'point', 2, True]} - elif operation == 'bridge': - outputParameter = {'output': ['output', 'line', 1, False]} + if operation == "articulation": + outputParameter = {"output": ["output", "point", 2, True]} + elif operation == "bridge": + outputParameter = {"output": ["output", "line", 1, False]} variableOutput(alg, outputParameter, parameters, context) diff --git a/python/plugins/grassprovider/ext/v_net_centrality.py b/python/plugins/grassprovider/ext/v_net_centrality.py index c3dfd92287ed..8f74e96e2c0b 100644 --- a/python/plugins/grassprovider/ext/v_net_centrality.py +++ b/python/plugins/grassprovider/ext/v_net_centrality.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'December 2017' -__copyright__ = '(C) 2017, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "December 2017" +__copyright__ = "(C) 2017, Médéric Ribreux" from .v_net import incorporatePoints, variableOutput @@ -27,5 +27,5 @@ def processCommand(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback): - outputParameter = {'output': ['output', 'point', 1, False]} + outputParameter = {"output": ["output", "point", 1, False]} variableOutput(alg, outputParameter, parameters, context) diff --git a/python/plugins/grassprovider/ext/v_net_components.py b/python/plugins/grassprovider/ext/v_net_components.py index a6c28f712cb2..d3580f4bc4b0 100644 --- a/python/plugins/grassprovider/ext/v_net_components.py +++ b/python/plugins/grassprovider/ext/v_net_components.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'December 2015' -__copyright__ = '(C) 2015, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "December 2015" +__copyright__ = "(C) 2015, Médéric Ribreux" from .v_net import incorporatePoints, variableOutput from qgis.core import QgsProcessingParameterDefinition @@ -25,13 +25,19 @@ def processCommand(alg, parameters, context, feedback): # We need to disable only output_point parameter - outPoint = alg.parameterDefinition('output_point') - outPoint.setFlags(outPoint.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden) + outPoint = alg.parameterDefinition("output_point") + outPoint.setFlags( + outPoint.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden + ) incorporatePoints(alg, parameters, context, feedback) - outPoint.setFlags(outPoint.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden) + outPoint.setFlags( + outPoint.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden + ) def processOutputs(alg, parameters, context, feedback): - outputParameter = {'output': ['output', 'line', 1, True], - 'output_point': ['output', 'point', 2, True]} + outputParameter = { + "output": ["output", "line", 1, True], + "output_point": ["output", "point", 2, True], + } variableOutput(alg, outputParameter, parameters, context) diff --git a/python/plugins/grassprovider/ext/v_net_connectivity.py b/python/plugins/grassprovider/ext/v_net_connectivity.py index 72e6d7494681..cf66bce732da 100644 --- a/python/plugins/grassprovider/ext/v_net_connectivity.py +++ b/python/plugins/grassprovider/ext/v_net_connectivity.py @@ -15,31 +15,27 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'December 2015' -__copyright__ = '(C) 2015, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "December 2015" +__copyright__ = "(C) 2015, Médéric Ribreux" from .v_net import incorporatePoints, variableOutput def checkParameterValuesBeforeExecuting(alg, parameters, context): - """ Verify if we have the right parameters """ - params = ['where', 'cats'] + """Verify if we have the right parameters""" + params = ["where", "cats"] values = [] for param in params: for i in range(1, 3): - values.append( - alg.parameterAsString( - parameters, - 'set{}_{}'.format(i, param), - context - ) - ) + values.append(alg.parameterAsString(parameters, f"set{i}_{param}", context)) if (values[0] or values[2]) and (values[1] or values[3]): return True, None - return False, alg.tr('You need to set at least setX_where or setX_cats parameters for each set!') + return False, alg.tr( + "You need to set at least setX_where or setX_cats parameters for each set!" + ) def processCommand(alg, parameters, context, feedback): @@ -47,5 +43,5 @@ def processCommand(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback): - outputParameter = {'output': ['output', 'point', 2, True]} + outputParameter = {"output": ["output", "point", 2, True]} variableOutput(alg, outputParameter, parameters, context) diff --git a/python/plugins/grassprovider/ext/v_net_distance.py b/python/plugins/grassprovider/ext/v_net_distance.py index 574365fdab09..2ec7be3cacc6 100644 --- a/python/plugins/grassprovider/ext/v_net_distance.py +++ b/python/plugins/grassprovider/ext/v_net_distance.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'December 2015' -__copyright__ = '(C) 2015, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "December 2015" +__copyright__ = "(C) 2015, Médéric Ribreux" import os from .v_net import variableOutput @@ -26,51 +26,53 @@ def processCommand(alg, parameters, context, feedback): - """ Handle data preparation for v.net.distance: + """Handle data preparation for v.net.distance: * Integrate point layers into network vector map. * Make v.net.distance use those layers. * Delete the threshold parameter. * If where statement, connect to the db """ # Grab the point layer and delete this parameter - lineLayer = alg.exportedLayers['input'] - fromLayer = alg.exportedLayers['flayer'] - toLayer = alg.exportedLayers['tlayer'] - intLayer = 'bufnet' + os.path.basename(getTempFilename(context=context)) - netLayer = 'net' + os.path.basename(getTempFilename(context=context)) - threshold = alg.parameterAsDouble(parameters, 'threshold', context) + lineLayer = alg.exportedLayers["input"] + fromLayer = alg.exportedLayers["flayer"] + toLayer = alg.exportedLayers["tlayer"] + intLayer = "bufnet" + os.path.basename(getTempFilename(context=context)) + netLayer = "net" + os.path.basename(getTempFilename(context=context)) + threshold = alg.parameterAsDouble(parameters, "threshold", context) # Create the v.net connect command for from_layer integration - command = 'v.net -s input={} points={} output={} operation=connect threshold={} arc_layer=1 node_layer=2'.format( - lineLayer, fromLayer, intLayer, threshold) + command = "v.net -s input={} points={} output={} operation=connect threshold={} arc_layer=1 node_layer=2".format( + lineLayer, fromLayer, intLayer, threshold + ) alg.commands.append(command) # Do it again with to_layer - command = 'v.net -s input={} points={} output={} operation=connect threshold={} arc_layer=1 node_layer=3'.format( - intLayer, toLayer, netLayer, threshold) + command = "v.net -s input={} points={} output={} operation=connect threshold={} arc_layer=1 node_layer=3".format( + intLayer, toLayer, netLayer, threshold + ) alg.commands.append(command) # Connect the point layer database to the layer 2 of the network - command = 'v.db.connect -o map={} table={} layer=2'.format(netLayer, fromLayer) + command = f"v.db.connect -o map={netLayer} table={fromLayer} layer=2" alg.commands.append(command) - command = 'v.db.connect -o map={} table={} layer=3'.format(netLayer, toLayer) + command = f"v.db.connect -o map={netLayer} table={toLayer} layer=3" alg.commands.append(command) # remove undesired parameters - alg.removeParameter('flayer') - alg.removeParameter('tlayer') - alg.removeParameter('threshold') - alg.exportedLayers['input'] = netLayer + alg.removeParameter("flayer") + alg.removeParameter("tlayer") + alg.removeParameter("threshold") + alg.exportedLayers["input"] = netLayer # Add the two new parameters - fLayer = QgsProcessingParameterString('from_layer', None, 2, False, False) + fLayer = QgsProcessingParameterString("from_layer", None, 2, False, False) alg.addParameter(fLayer) - tLayer = QgsProcessingParameterString('to_layer', None, 3, False, False) + tLayer = QgsProcessingParameterString("to_layer", None, 3, False, False) alg.addParameter(tLayer) alg.processCommand(parameters, context, feedback) def processOutputs(alg, parameters, context, feedback): - outputParameter = {'output': ['output', 'line', 1, True]} + outputParameter = {"output": ["output", "line", 1, True]} variableOutput(alg, outputParameter, parameters, context) diff --git a/python/plugins/grassprovider/ext/v_net_flow.py b/python/plugins/grassprovider/ext/v_net_flow.py index a0ada0fba081..efdf95f9374d 100644 --- a/python/plugins/grassprovider/ext/v_net_flow.py +++ b/python/plugins/grassprovider/ext/v_net_flow.py @@ -15,31 +15,27 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'December 2015' -__copyright__ = '(C) 2015, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "December 2015" +__copyright__ = "(C) 2015, Médéric Ribreux" from .v_net import incorporatePoints, variableOutput def checkParameterValuesBeforeExecuting(alg, parameters, context): - """ Verify if we have the right parameters """ - params = ['where', 'cats'] + """Verify if we have the right parameters""" + params = ["where", "cats"] values = [] for param in params: - for i in ['source', 'sink']: - values.append( - alg.parameterAsString( - parameters, - '{}_{}'.format(i, param), - context - ) - ) + for i in ["source", "sink"]: + values.append(alg.parameterAsString(parameters, f"{i}_{param}", context)) if (values[0] or values[2]) and (values[1] or values[3]): return True, None - return False, alg.tr('You need to set at least source/sink_where or source/sink_cats parameters for each set!') + return False, alg.tr( + "You need to set at least source/sink_where or source/sink_cats parameters for each set!" + ) def processCommand(alg, parameters, context, feedback): @@ -47,6 +43,8 @@ def processCommand(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback): - outputParameter = {'output': ['output', 'line', 1, True], - 'cut': ['cut', 'line', 1, True]} + outputParameter = { + "output": ["output", "line", 1, True], + "cut": ["cut", "line", 1, True], + } variableOutput(alg, outputParameter, parameters, context) diff --git a/python/plugins/grassprovider/ext/v_net_iso.py b/python/plugins/grassprovider/ext/v_net_iso.py index 3cc81b80a63a..1bb2277334b5 100644 --- a/python/plugins/grassprovider/ext/v_net_iso.py +++ b/python/plugins/grassprovider/ext/v_net_iso.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'December 2015' -__copyright__ = '(C) 2015, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "December 2015" +__copyright__ = "(C) 2015, Médéric Ribreux" from .v_net import incorporatePoints, variableOutput @@ -27,5 +27,5 @@ def processCommand(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback): - outputParameter = {'output': ['output', 'line', 1, True]} + outputParameter = {"output": ["output", "line", 1, True]} variableOutput(alg, outputParameter, parameters, context) diff --git a/python/plugins/grassprovider/ext/v_net_path.py b/python/plugins/grassprovider/ext/v_net_path.py index eee13dae330f..6f9f3f19def2 100644 --- a/python/plugins/grassprovider/ext/v_net_path.py +++ b/python/plugins/grassprovider/ext/v_net_path.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'December 2015' -__copyright__ = '(C) 2015, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "December 2015" +__copyright__ = "(C) 2015, Médéric Ribreux" from .v_net import incorporatePoints, variableOutput @@ -27,5 +27,5 @@ def processCommand(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback): - outputParameter = {'output': ['output', 'line', 1, False]} + outputParameter = {"output": ["output", "line", 1, False]} variableOutput(alg, outputParameter, parameters, context) diff --git a/python/plugins/grassprovider/ext/v_net_salesman.py b/python/plugins/grassprovider/ext/v_net_salesman.py index 9f802eb4b292..a774ccef4ec5 100644 --- a/python/plugins/grassprovider/ext/v_net_salesman.py +++ b/python/plugins/grassprovider/ext/v_net_salesman.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'December 2015' -__copyright__ = '(C) 2015, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "December 2015" +__copyright__ = "(C) 2015, Médéric Ribreux" from .v_net import incorporatePoints, variableOutput from qgis.core import QgsProcessingParameterDefinition @@ -28,5 +28,5 @@ def processCommand(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback): - outputParameter = {'output': ['output', 'line', 1, True]} + outputParameter = {"output": ["output", "line", 1, True]} variableOutput(alg, outputParameter, parameters, context) diff --git a/python/plugins/grassprovider/ext/v_net_spanningtree.py b/python/plugins/grassprovider/ext/v_net_spanningtree.py index 20cd537dca95..2e9bee20ad42 100644 --- a/python/plugins/grassprovider/ext/v_net_spanningtree.py +++ b/python/plugins/grassprovider/ext/v_net_spanningtree.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'December 2017' -__copyright__ = '(C) 2017, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "December 2017" +__copyright__ = "(C) 2017, Médéric Ribreux" from .v_net import incorporatePoints, variableOutput @@ -27,5 +27,5 @@ def processCommand(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback): - outputParameter = {'output': ['output', 'line', 1, True]} + outputParameter = {"output": ["output", "line", 1, True]} variableOutput(alg, outputParameter, parameters, context) diff --git a/python/plugins/grassprovider/ext/v_net_steiner.py b/python/plugins/grassprovider/ext/v_net_steiner.py index bcf524200831..1dab232b8417 100644 --- a/python/plugins/grassprovider/ext/v_net_steiner.py +++ b/python/plugins/grassprovider/ext/v_net_steiner.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'December 2015' -__copyright__ = '(C) 2015, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "December 2015" +__copyright__ = "(C) 2015, Médéric Ribreux" from .v_net import incorporatePoints, variableOutput @@ -27,5 +27,5 @@ def processCommand(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback): - outputParameter = {'output': ['output', 'line', 1, False]} + outputParameter = {"output": ["output", "line", 1, False]} variableOutput(alg, outputParameter, parameters, context) diff --git a/python/plugins/grassprovider/ext/v_net_visibility.py b/python/plugins/grassprovider/ext/v_net_visibility.py index 93eeb4836261..bb278002c480 100644 --- a/python/plugins/grassprovider/ext/v_net_visibility.py +++ b/python/plugins/grassprovider/ext/v_net_visibility.py @@ -15,13 +15,13 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'December 2015' -__copyright__ = '(C) 2015, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "December 2015" +__copyright__ = "(C) 2015, Médéric Ribreux" from .v_net import variableOutput def processOutputs(alg, parameters, context, feedback): - outputParameter = {'output': ['output', 'line', 1, True]} + outputParameter = {"output": ["output", "line", 1, True]} variableOutput(alg, outputParameter, parameters, context) diff --git a/python/plugins/grassprovider/ext/v_proj.py b/python/plugins/grassprovider/ext/v_proj.py index deb72bd93352..ce9b20134d1e 100644 --- a/python/plugins/grassprovider/ext/v_proj.py +++ b/python/plugins/grassprovider/ext/v_proj.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'November 2017' -__copyright__ = '(C) 2017, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "November 2017" +__copyright__ = "(C) 2017, Médéric Ribreux" from qgis.core import QgsProcessingParameterString from grassprovider.grass_utils import GrassUtils @@ -25,39 +25,34 @@ def processInputs(alg, parameters, context, feedback): # Grab the projection from the input vector layer - layer = alg.parameterAsLayer(parameters, 'input', context) + layer = alg.parameterAsLayer(parameters, "input", context) alg.setSessionProjectionFromLayer(layer, context) layerCrs = layer.crs().toProj() # Creates a new location with this Crs wkt_file_name = GrassUtils.exportCrsWktToFile(layer.crs(), context) - newLocation = 'newProj{}'.format(alg.uniqueSuffix) - alg.commands.append('g.proj wkt="{}" location={}'.format( - wkt_file_name, newLocation)) + newLocation = f"newProj{alg.uniqueSuffix}" + alg.commands.append(f'g.proj wkt="{wkt_file_name}" location={newLocation}') # Go to the newly created location - alg.commands.append('g.mapset mapset=PERMANENT location={}'.format( - newLocation)) + alg.commands.append(f"g.mapset mapset=PERMANENT location={newLocation}") # Import the layer - alg.loadVectorLayerFromParameter( - 'input', parameters, context, feedback, False) + alg.loadVectorLayerFromParameter("input", parameters, context, feedback, False) # Go back to default location - alg.commands.append('g.mapset mapset=PERMANENT location=temp_location') + alg.commands.append("g.mapset mapset=PERMANENT location=temp_location") # Grab the projected Crs - crs = alg.parameterAsCrs(parameters, 'crs', context) + crs = alg.parameterAsCrs(parameters, "crs", context) wkt_file_name = GrassUtils.exportCrsWktToFile(crs, context) - alg.commands.append('g.proj -c wkt="{}"'.format(wkt_file_name)) + alg.commands.append(f'g.proj -c wkt="{wkt_file_name}"') # Remove crs parameter - alg.removeParameter('crs') + alg.removeParameter("crs") # Add the location parameter with proper value location = QgsProcessingParameterString( - 'location', - 'new location', - 'newProj{}'.format(alg.uniqueSuffix) + "location", "new location", f"newProj{alg.uniqueSuffix}" ) alg.addParameter(location) diff --git a/python/plugins/grassprovider/ext/v_rast_stats.py b/python/plugins/grassprovider/ext/v_rast_stats.py index 2f55a8f1e50a..f495979f4f57 100644 --- a/python/plugins/grassprovider/ext/v_rast_stats.py +++ b/python/plugins/grassprovider/ext/v_rast_stats.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" def processCommand(alg, parameters, context, feedback): @@ -27,7 +27,7 @@ def processCommand(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback): # We need to add the initial vector layer to outputs: - fileName = alg.parameterAsOutputLayer(parameters, 'output', context) - grassName = alg.exportedLayers['map'] - dataType = 'auto' + fileName = alg.parameterAsOutputLayer(parameters, "output", context) + grassName = alg.exportedLayers["map"] + dataType = "auto" alg.exportVectorLayer(grassName, fileName, dataType=dataType) diff --git a/python/plugins/grassprovider/ext/v_reclass.py b/python/plugins/grassprovider/ext/v_reclass.py index 80bda61e43b1..f7d6996ca0a6 100644 --- a/python/plugins/grassprovider/ext/v_reclass.py +++ b/python/plugins/grassprovider/ext/v_reclass.py @@ -15,16 +15,16 @@ *************************************************************************** """ -__author__ = 'Andrea Giudiceandrea' -__date__ = 'June 2023' -__copyright__ = '(C) 2023, Andrea Giudiceandrea' +__author__ = "Andrea Giudiceandrea" +__date__ = "June 2023" +__copyright__ = "(C) 2023, Andrea Giudiceandrea" def checkParameterValuesBeforeExecuting(alg, parameters, context): - """ Verify if we have the right parameters """ + """Verify if we have the right parameters""" # rules and column parameters are mutually exclusive - rules = alg.parameterAsString(parameters, 'rules', context) - column = alg.parameterAsString(parameters, 'column', context) + rules = alg.parameterAsString(parameters, "rules", context) + column = alg.parameterAsString(parameters, "column", context) if (rules and column) or (not rules and not column): return False, alg.tr("You need to set either a rules file or a column!") diff --git a/python/plugins/grassprovider/ext/v_rectify.py b/python/plugins/grassprovider/ext/v_rectify.py index ada7bbf1bcf1..fcaac2242856 100644 --- a/python/plugins/grassprovider/ext/v_rectify.py +++ b/python/plugins/grassprovider/ext/v_rectify.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" import os from grassprovider.grass_utils import GrassUtils @@ -25,17 +25,20 @@ def checkParameterValuesBeforeExecuting(alg, parameters, context): - """ Verify if we have the right parameters """ - if (alg.parameterAsString(parameters, 'inline_points', context) - and alg.parameterAsString(parameters, 'points', context)): - return False, alg.tr("You need to set either an input control point file or inline control points!") + """Verify if we have the right parameters""" + if alg.parameterAsString( + parameters, "inline_points", context + ) and alg.parameterAsString(parameters, "points", context): + return False, alg.tr( + "You need to set either an input control point file or inline control points!" + ) return True, None def processCommand(alg, parameters, context, feedback): # handle inline points - inlinePoints = alg.parameterAsString(parameters, 'inline_points', context) + inlinePoints = alg.parameterAsString(parameters, "inline_points", context) if inlinePoints: # Creates a temporary txt file pointsName = getTempFilename(context=context) @@ -43,7 +46,7 @@ def processCommand(alg, parameters, context, feedback): # Inject rules into temporary txt file with open(pointsName, "w") as tempPoints: tempPoints.write(inlinePoints) - alg.removeParameter('inline_points') - parameters['points'] = pointsName + alg.removeParameter("inline_points") + parameters["points"] = pointsName alg.processCommand(parameters, context, feedback) diff --git a/python/plugins/grassprovider/ext/v_sample.py b/python/plugins/grassprovider/ext/v_sample.py index dfa5f98fdf06..69758c784318 100644 --- a/python/plugins/grassprovider/ext/v_sample.py +++ b/python/plugins/grassprovider/ext/v_sample.py @@ -15,17 +15,17 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" def processInputs(alg, parameters, context, feedback): - if 'input' in alg.exportedLayers: + if "input" in alg.exportedLayers: return # We need to import the vector with v.in.ogr # and we can use r.external for the raster - alg.loadVectorLayerFromParameter('input', parameters, context, feedback, False) - alg.loadRasterLayerFromParameter('raster', parameters, context, True) + alg.loadVectorLayerFromParameter("input", parameters, context, feedback, False) + alg.loadRasterLayerFromParameter("raster", parameters, context, True) alg.postInputs(context) diff --git a/python/plugins/grassprovider/ext/v_to_3d.py b/python/plugins/grassprovider/ext/v_to_3d.py index fd13399993a6..fd8c4727e55f 100644 --- a/python/plugins/grassprovider/ext/v_to_3d.py +++ b/python/plugins/grassprovider/ext/v_to_3d.py @@ -15,25 +15,27 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" def checkParameterValuesBeforeExecuting(alg, parameters, context): - """ Verify if we have the right parameters """ - height = alg.parameterAsDouble(parameters, 'height', context) - column = alg.parameterAsString(parameters, 'column', context) + """Verify if we have the right parameters""" + height = alg.parameterAsDouble(parameters, "height", context) + column = alg.parameterAsString(parameters, "column", context) if (height and column) or (not height and not column): - return False, alg.tr("You need to set either a fixed height value or the height column!") + return False, alg.tr( + "You need to set either a fixed height value or the height column!" + ) return True, None def processInputs(alg, parameters, context, feedback): - if 'input' in alg.exportedLayers: + if "input" in alg.exportedLayers: return # We need to import the vector layer with v.in.ogr - alg.loadVectorLayerFromParameter('input', parameters, context, feedback, False) + alg.loadVectorLayerFromParameter("input", parameters, context, feedback, False) alg.postInputs(context) diff --git a/python/plugins/grassprovider/ext/v_transform.py b/python/plugins/grassprovider/ext/v_transform.py index e24b78e56407..f6287f73a12e 100644 --- a/python/plugins/grassprovider/ext/v_transform.py +++ b/python/plugins/grassprovider/ext/v_transform.py @@ -15,18 +15,20 @@ *************************************************************************** """ -__author__ = 'Andrea Giudiceandrea' -__date__ = 'February 2024' -__copyright__ = '(C) 2024, Andrea Giudiceandrea' +__author__ = "Andrea Giudiceandrea" +__date__ = "February 2024" +__copyright__ = "(C) 2024, Andrea Giudiceandrea" def checkParameterValuesBeforeExecuting(alg, parameters, context): - """ Verify if we have the right parameters """ + """Verify if we have the right parameters""" # -w, -x and -y parameters are mutually exclusive - w = alg.parameterAsBoolean(parameters, '-w', context) - x = alg.parameterAsBoolean(parameters, '-x', context) - y = alg.parameterAsBoolean(parameters, '-y', context) + w = alg.parameterAsBoolean(parameters, "-w", context) + x = alg.parameterAsBoolean(parameters, "-x", context) + y = alg.parameterAsBoolean(parameters, "-y", context) if sum([w, x, y]) > 1: - return False, alg.tr("The 'Swap coordinates' parameters -w, -x and -y are mutually exclusive. You need to set either none or only one of them!") + return False, alg.tr( + "The 'Swap coordinates' parameters -w, -x and -y are mutually exclusive. You need to set either none or only one of them!" + ) return True, None diff --git a/python/plugins/grassprovider/ext/v_vect_stats.py b/python/plugins/grassprovider/ext/v_vect_stats.py index bc73f5bc80a5..2d3476849289 100644 --- a/python/plugins/grassprovider/ext/v_vect_stats.py +++ b/python/plugins/grassprovider/ext/v_vect_stats.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" def processCommand(alg, parameters, context, feedback): @@ -27,7 +27,7 @@ def processCommand(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback): # We need to add the initial vector layer to outputs: - fileName = alg.parameterAsOutputLayer(parameters, 'output', context) - grassName = alg.exportedLayers['areas'] - dataType = 'auto' + fileName = alg.parameterAsOutputLayer(parameters, "output", context) + grassName = alg.exportedLayers["areas"] + dataType = "auto" alg.exportVectorLayer(grassName, fileName, dataType=dataType) diff --git a/python/plugins/grassprovider/ext/v_voronoi.py b/python/plugins/grassprovider/ext/v_voronoi.py index c57bea145744..8b0ac2ea60e3 100644 --- a/python/plugins/grassprovider/ext/v_voronoi.py +++ b/python/plugins/grassprovider/ext/v_voronoi.py @@ -15,26 +15,26 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" def processInputs(alg, parameters, context, feedback): - if 'input' in alg.exportedLayers: + if "input" in alg.exportedLayers: return # We need to use v.in.ogr instead of v.external - alg.loadVectorLayerFromParameter('input', parameters, context, feedback, False) + alg.loadVectorLayerFromParameter("input", parameters, context, feedback, False) alg.processInputs(parameters, context, feedback) def processOutputs(alg, parameters, context, feedback): - fileName = alg.parameterAsOutputLayer(parameters, 'output', context) - grassName = '{}{}'.format('output', alg.uniqueSuffix) - dataType = 'auto' + fileName = alg.parameterAsOutputLayer(parameters, "output", context) + grassName = "{}{}".format("output", alg.uniqueSuffix) + dataType = "auto" # if we export a graph, output type will be a line - if alg.parameterAsBoolean(parameters, '-l', context): - dataType = 'line' + if alg.parameterAsBoolean(parameters, "-l", context): + dataType = "line" alg.exportVectorLayer(grassName, fileName, dataType=dataType) diff --git a/python/plugins/grassprovider/ext/v_what_rast.py b/python/plugins/grassprovider/ext/v_what_rast.py index 170f7341adc1..d898bd556906 100644 --- a/python/plugins/grassprovider/ext/v_what_rast.py +++ b/python/plugins/grassprovider/ext/v_what_rast.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'December 2017' -__copyright__ = '(C) 2017, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "December 2017" +__copyright__ = "(C) 2017, Médéric Ribreux" def processCommand(alg, parameters, context, feedback): @@ -27,7 +27,7 @@ def processCommand(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback): # We need to add the initial vector layer to outputs: - fileName = alg.parameterAsOutputLayer(parameters, 'output', context) - grassName = alg.exportedLayers['map'] - dataType = 'auto' + fileName = alg.parameterAsOutputLayer(parameters, "output", context) + grassName = alg.exportedLayers["map"] + dataType = "auto" alg.exportVectorLayer(grassName, fileName, dataType=dataType) diff --git a/python/plugins/grassprovider/ext/v_what_vect.py b/python/plugins/grassprovider/ext/v_what_vect.py index 242ae9844639..18ca0224d420 100644 --- a/python/plugins/grassprovider/ext/v_what_vect.py +++ b/python/plugins/grassprovider/ext/v_what_vect.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" def processCommand(alg, parameters, context, feedback): @@ -27,6 +27,6 @@ def processCommand(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback): # We need to add the initial vector layer to outputs: - fileName = alg.parameterAsOutputLayer(parameters, 'output', context) - grassName = alg.exportedLayers['map'] + fileName = alg.parameterAsOutputLayer(parameters, "output", context) + grassName = alg.exportedLayers["map"] alg.exportVectorLayer(grassName, fileName) diff --git a/python/plugins/grassprovider/grass_algorithm.py b/python/plugins/grassprovider/grass_algorithm.py index 0556335b05e2..1f2eb3aec09d 100644 --- a/python/plugins/grassprovider/grass_algorithm.py +++ b/python/plugins/grassprovider/grass_algorithm.py @@ -15,14 +15,11 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'February 2015' -__copyright__ = '(C) 2012-2015, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "February 2015" +__copyright__ = "(C) 2012-2015, Victor Olaya" -from typing import ( - Dict, - Optional -) +from typing import Dict, Optional import sys import os import uuid @@ -32,41 +29,43 @@ from qgis.PyQt.QtCore import QCoreApplication, QUrl -from qgis.core import (Qgis, - QgsMapLayer, - QgsRasterLayer, - QgsApplication, - QgsMapLayerType, - QgsCoordinateReferenceSystem, - QgsProcessingUtils, - QgsProcessing, - QgsMessageLog, - QgsVectorFileWriter, - QgsProcessingContext, - QgsProcessingAlgorithm, - QgsProcessingParameterDefinition, - QgsProcessingException, - QgsProcessingParameterCrs, - QgsProcessingParameterExtent, - QgsProcessingParameterEnum, - QgsProcessingParameterNumber, - QgsProcessingParameterString, - QgsProcessingParameterField, - QgsProcessingParameterPoint, - QgsProcessingParameterBoolean, - QgsProcessingParameterRange, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterMultipleLayers, - QgsProcessingParameterVectorDestination, - QgsProcessingParameterRasterDestination, - QgsProcessingParameterFileDestination, - QgsProcessingParameterFile, - QgsProcessingParameterFolderDestination, - QgsProcessingOutputHtml, - QgsVectorLayer, - QgsProviderRegistry) +from qgis.core import ( + Qgis, + QgsMapLayer, + QgsRasterLayer, + QgsApplication, + QgsMapLayerType, + QgsCoordinateReferenceSystem, + QgsProcessingUtils, + QgsProcessing, + QgsMessageLog, + QgsVectorFileWriter, + QgsProcessingContext, + QgsProcessingAlgorithm, + QgsProcessingParameterDefinition, + QgsProcessingException, + QgsProcessingParameterCrs, + QgsProcessingParameterExtent, + QgsProcessingParameterEnum, + QgsProcessingParameterNumber, + QgsProcessingParameterString, + QgsProcessingParameterField, + QgsProcessingParameterPoint, + QgsProcessingParameterBoolean, + QgsProcessingParameterRange, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterMultipleLayers, + QgsProcessingParameterVectorDestination, + QgsProcessingParameterRasterDestination, + QgsProcessingParameterFileDestination, + QgsProcessingParameterFile, + QgsProcessingParameterFolderDestination, + QgsProcessingOutputHtml, + QgsVectorLayer, + QgsProviderRegistry, +) from qgis.utils import iface import warnings @@ -83,41 +82,45 @@ from processing.tools.system import isWindows, getTempFilename -pluginPath = os.path.normpath(os.path.join( - os.path.split(os.path.dirname(__file__))[0], os.pardir)) +pluginPath = os.path.normpath( + os.path.join(os.path.split(os.path.dirname(__file__))[0], os.pardir) +) class GrassAlgorithm(QgsProcessingAlgorithm): - GRASS_OUTPUT_TYPE_PARAMETER = 'GRASS_OUTPUT_TYPE_PARAMETER' - GRASS_MIN_AREA_PARAMETER = 'GRASS_MIN_AREA_PARAMETER' - GRASS_SNAP_TOLERANCE_PARAMETER = 'GRASS_SNAP_TOLERANCE_PARAMETER' - GRASS_REGION_EXTENT_PARAMETER = 'GRASS_REGION_PARAMETER' - GRASS_REGION_CELLSIZE_PARAMETER = 'GRASS_REGION_CELLSIZE_PARAMETER' - GRASS_REGION_ALIGN_TO_RESOLUTION = 'GRASS_REGION_ALIGN_TO_RESOLUTION' - GRASS_RASTER_FORMAT_OPT = 'GRASS_RASTER_FORMAT_OPT' - GRASS_RASTER_FORMAT_META = 'GRASS_RASTER_FORMAT_META' - GRASS_VECTOR_DSCO = 'GRASS_VECTOR_DSCO' - GRASS_VECTOR_LCO = 'GRASS_VECTOR_LCO' - GRASS_VECTOR_EXPORT_NOCAT = 'GRASS_VECTOR_EXPORT_NOCAT' - - OUTPUT_TYPES = ['auto', 'point', 'line', 'area'] - QGIS_OUTPUT_TYPES = {QgsProcessing.SourceType.TypeVectorAnyGeometry: 'auto', - QgsProcessing.SourceType.TypeVectorPoint: 'point', - QgsProcessing.SourceType.TypeVectorLine: 'line', - QgsProcessing.SourceType.TypeVectorPolygon: 'area'} - - def __init__(self, - description_file: Optional[Path] = None, - json_definition: Optional[Dict] = None, - description_folder: Optional[Path] = None - ): + GRASS_OUTPUT_TYPE_PARAMETER = "GRASS_OUTPUT_TYPE_PARAMETER" + GRASS_MIN_AREA_PARAMETER = "GRASS_MIN_AREA_PARAMETER" + GRASS_SNAP_TOLERANCE_PARAMETER = "GRASS_SNAP_TOLERANCE_PARAMETER" + GRASS_REGION_EXTENT_PARAMETER = "GRASS_REGION_PARAMETER" + GRASS_REGION_CELLSIZE_PARAMETER = "GRASS_REGION_CELLSIZE_PARAMETER" + GRASS_REGION_ALIGN_TO_RESOLUTION = "GRASS_REGION_ALIGN_TO_RESOLUTION" + GRASS_RASTER_FORMAT_OPT = "GRASS_RASTER_FORMAT_OPT" + GRASS_RASTER_FORMAT_META = "GRASS_RASTER_FORMAT_META" + GRASS_VECTOR_DSCO = "GRASS_VECTOR_DSCO" + GRASS_VECTOR_LCO = "GRASS_VECTOR_LCO" + GRASS_VECTOR_EXPORT_NOCAT = "GRASS_VECTOR_EXPORT_NOCAT" + + OUTPUT_TYPES = ["auto", "point", "line", "area"] + QGIS_OUTPUT_TYPES = { + QgsProcessing.SourceType.TypeVectorAnyGeometry: "auto", + QgsProcessing.SourceType.TypeVectorPoint: "point", + QgsProcessing.SourceType.TypeVectorLine: "line", + QgsProcessing.SourceType.TypeVectorPolygon: "area", + } + + def __init__( + self, + description_file: Optional[Path] = None, + json_definition: Optional[dict] = None, + description_folder: Optional[Path] = None, + ): super().__init__() - self._name = '' - self._display_name = '' - self._short_description = '' - self._group = '' - self._groupId = '' - self.grass_name = '' + self._name = "" + self._display_name = "" + self._short_description = "" + self._group = "" + self._groupId = "" + self.grass_name = "" self.params = [] self.hardcodedStrings = [] self.inputLayers = [] @@ -126,7 +129,7 @@ def __init__(self, self.exportedLayers = {} self.fileOutputs = {} self._description_file: Optional[Path] = description_file - self._json_definition: Optional[Dict] = json_definition + self._json_definition: Optional[dict] = json_definition self._description_folder: Optional[Path] = description_folder # Default GRASS parameters @@ -148,7 +151,7 @@ def __init__(self, self.numExportedLayers = 0 # Do we need this anymore? - self.uniqueSuffix = str(uuid.uuid4()).replace('-', '') + self.uniqueSuffix = str(uuid.uuid4()).replace("-", "") # Use the ext mechanism self.module = None @@ -156,29 +159,38 @@ def __init__(self, extpath = None ext_name = None if self._description_file: - ext_name = self.name().replace('.', '_') - extpath = self._description_file.parents[1].joinpath('ext', ext_name + '.py') - elif self._json_definition.get('ext_path'): - ext_name = self._json_definition['ext_path'] + ext_name = self.name().replace(".", "_") + extpath = self._description_file.parents[1].joinpath( + "ext", ext_name + ".py" + ) + elif self._json_definition.get("ext_path"): + ext_name = self._json_definition["ext_path"] extpath = self._description_folder.parents[0].joinpath( - 'ext', ext_name + '.py') + "ext", ext_name + ".py" + ) # this check makes it a bit faster if extpath and extpath.exists(): spec = importlib.util.spec_from_file_location( - 'grassprovider.ext.' + ext_name, extpath) + "grassprovider.ext." + ext_name, extpath + ) self.module = importlib.util.module_from_spec(spec) spec.loader.exec_module(self.module) except Exception as e: - QgsMessageLog.logMessage(self.tr('Failed to load: {0}\n{1}').format(extpath, e), 'Processing', Qgis.MessageLevel.Critical) + QgsMessageLog.logMessage( + self.tr("Failed to load: {0}\n{1}").format(extpath, e), + "Processing", + Qgis.MessageLevel.Critical, + ) pass def createInstance(self): return self.__class__( description_file=self._description_file, json_definition=self._json_definition, - description_folder=self._description_folder) + description_folder=self._description_folder, + ) def name(self): return self._name @@ -203,22 +215,28 @@ def svgIconPath(self): def flags(self): # TODO - maybe it's safe to background thread this? - return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading | QgsProcessingAlgorithm.Flag.FlagDisplayNameIsLiteral + return ( + super().flags() + | QgsProcessingAlgorithm.Flag.FlagNoThreading + | QgsProcessingAlgorithm.Flag.FlagDisplayNameIsLiteral + ) - def tr(self, string, context=''): - if context == '': + def tr(self, string, context=""): + if context == "": context = self.__class__.__name__ return QCoreApplication.translate(context, string) def helpUrl(self): helpPath = GrassUtils.grassHelpPath() - if helpPath == '': + if helpPath == "": return None if os.path.exists(helpPath): - return QUrl.fromLocalFile(os.path.join(helpPath, '{}.html'.format(self.grass_name))).toString() + return QUrl.fromLocalFile( + os.path.join(helpPath, f"{self.grass_name}.html") + ).toString() else: - return helpPath + '{}.html'.format(self.grass_name) + return helpPath + f"{self.grass_name}.html" def initAlgorithm(self, config=None): """ @@ -232,25 +250,19 @@ def _define_characteristics_from_file(self): """ Create algorithm parameters and outputs from a text file. """ - results = ParsedDescription.parse_description_file( - self._description_file) - self._define_characteristics_from_parsed_description( - results - ) + results = ParsedDescription.parse_description_file(self._description_file) + self._define_characteristics_from_parsed_description(results) def _define_characteristics_from_json(self): """ Create algorithm parameters and outputs from JSON definition. """ - results = ParsedDescription.from_dict( - self._json_definition) - self._define_characteristics_from_parsed_description( - results - ) + results = ParsedDescription.from_dict(self._json_definition) + self._define_characteristics_from_parsed_description(results) def _define_characteristics_from_parsed_description( - self, - description: ParsedDescription): + self, description: ParsedDescription + ): """ Create algorithm parameters and outputs from parsed description """ @@ -275,128 +287,164 @@ def _define_characteristics_from_parsed_description( parameter = getParameterFromString(param_string, "GrassAlgorithm") except Exception as e: QgsMessageLog.logMessage( - QCoreApplication.translate("GrassAlgorithm", - 'Could not open GRASS GIS algorithm: {0}').format( - self._name), - QCoreApplication.translate("GrassAlgorithm", - 'Processing'), - Qgis.MessageLevel.Critical) + QCoreApplication.translate( + "GrassAlgorithm", "Could not open GRASS GIS algorithm: {0}" + ).format(self._name), + QCoreApplication.translate("GrassAlgorithm", "Processing"), + Qgis.MessageLevel.Critical, + ) raise e if parameter is None: continue self.params.append(parameter) - if isinstance(parameter, ( + if isinstance( + parameter, + ( QgsProcessingParameterVectorLayer, - QgsProcessingParameterFeatureSource)): + QgsProcessingParameterFeatureSource, + ), + ): has_vector_input = True - elif isinstance(parameter, - QgsProcessingParameterRasterLayer): + elif isinstance(parameter, QgsProcessingParameterRasterLayer): has_raster_input = True - elif isinstance(parameter, - QgsProcessingParameterMultipleLayers): + elif isinstance(parameter, QgsProcessingParameterMultipleLayers): if parameter.layerType() < 3 or parameter.layerType() == 5: has_vector_input = True elif parameter.layerType() == 3: has_raster_input = True - elif isinstance(parameter, - QgsProcessingParameterVectorDestination): + elif isinstance(parameter, QgsProcessingParameterVectorDestination): has_vector_outputs = True - elif isinstance(parameter, - QgsProcessingParameterRasterDestination): + elif isinstance(parameter, QgsProcessingParameterRasterDestination): has_raster_output = True param = QgsProcessingParameterExtent( self.GRASS_REGION_EXTENT_PARAMETER, - self.tr('GRASS GIS region extent'), - optional=True + self.tr("GRASS GIS region extent"), + optional=True, + ) + param.setFlags( + param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced ) - param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) self.params.append(param) if has_raster_output or has_raster_input: # Add a cellsize parameter param = QgsProcessingParameterNumber( self.GRASS_REGION_CELLSIZE_PARAMETER, - self.tr('GRASS GIS region cellsize (leave 0 for default)'), + self.tr("GRASS GIS region cellsize (leave 0 for default)"), type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, maxValue=sys.float_info.max + 1, defaultValue=0.0 + minValue=0.0, + maxValue=sys.float_info.max + 1, + defaultValue=0.0, + ) + param.setFlags( + param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced ) - param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) self.params.append(param) if has_raster_output: # Add a createopt parameter for format export param = QgsProcessingParameterString( self.GRASS_RASTER_FORMAT_OPT, - self.tr('Output Rasters format options (createopt)'), - multiLine=True, optional=True + self.tr("Output Rasters format options (createopt)"), + multiLine=True, + optional=True, + ) + param.setFlags( + param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced ) - param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - param.setHelp(self.tr('Creation options should be comma separated')) + param.setHelp(self.tr("Creation options should be comma separated")) self.params.append(param) # Add a metadata parameter for format export param = QgsProcessingParameterString( self.GRASS_RASTER_FORMAT_META, - self.tr('Output Rasters format metadata options (metaopt)'), - multiLine=True, optional=True + self.tr("Output Rasters format metadata options (metaopt)"), + multiLine=True, + optional=True, ) - param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - param.setHelp(self.tr('Metadata options should be comma separated')) + param.setFlags( + param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + param.setHelp(self.tr("Metadata options should be comma separated")) self.params.append(param) if has_vector_input: - param = QgsProcessingParameterNumber(self.GRASS_SNAP_TOLERANCE_PARAMETER, - self.tr('v.in.ogr snap tolerance (-1 = no snap)'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=-1.0, maxValue=sys.float_info.max + 1, - defaultValue=-1.0) - param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + param = QgsProcessingParameterNumber( + self.GRASS_SNAP_TOLERANCE_PARAMETER, + self.tr("v.in.ogr snap tolerance (-1 = no snap)"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=-1.0, + maxValue=sys.float_info.max + 1, + defaultValue=-1.0, + ) + param.setFlags( + param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.params.append(param) - param = QgsProcessingParameterNumber(self.GRASS_MIN_AREA_PARAMETER, - self.tr('v.in.ogr min area'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, maxValue=sys.float_info.max + 1, - defaultValue=0.0001) - param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + param = QgsProcessingParameterNumber( + self.GRASS_MIN_AREA_PARAMETER, + self.tr("v.in.ogr min area"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + maxValue=sys.float_info.max + 1, + defaultValue=0.0001, + ) + param.setFlags( + param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.params.append(param) if has_vector_outputs: # Add an optional output type - param = QgsProcessingParameterEnum(self.GRASS_OUTPUT_TYPE_PARAMETER, - self.tr('v.out.ogr output type'), - self.OUTPUT_TYPES, - defaultValue=0) - param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + param = QgsProcessingParameterEnum( + self.GRASS_OUTPUT_TYPE_PARAMETER, + self.tr("v.out.ogr output type"), + self.OUTPUT_TYPES, + defaultValue=0, + ) + param.setFlags( + param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.params.append(param) # Add a DSCO parameter for format export param = QgsProcessingParameterString( self.GRASS_VECTOR_DSCO, - self.tr('v.out.ogr output data source options (dsco)'), - multiLine=True, optional=True + self.tr("v.out.ogr output data source options (dsco)"), + multiLine=True, + optional=True, + ) + param.setFlags( + param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced ) - param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) self.params.append(param) # Add a LCO parameter for format export param = QgsProcessingParameterString( self.GRASS_VECTOR_LCO, - self.tr('v.out.ogr output layer options (lco)'), - multiLine=True, optional=True + self.tr("v.out.ogr output layer options (lco)"), + multiLine=True, + optional=True, + ) + param.setFlags( + param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced ) - param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) self.params.append(param) # Add a -c flag for export param = QgsProcessingParameterBoolean( self.GRASS_VECTOR_EXPORT_NOCAT, - self.tr('Also export features without category (not labeled). Otherwise only features with category are exported'), - False + self.tr( + "Also export features without category (not labeled). Otherwise only features with category are exported" + ), + False, + ) + param.setFlags( + param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced ) - param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) self.params.append(param) def getDefaultCellSize(self): @@ -420,38 +468,41 @@ def grabDefaultGrassParameters(self, parameters, context): object attributes for faster retrieving. """ # GRASS region extent - self.region = self.parameterAsExtent(parameters, - self.GRASS_REGION_EXTENT_PARAMETER, - context) + self.region = self.parameterAsExtent( + parameters, self.GRASS_REGION_EXTENT_PARAMETER, context + ) # GRASS cell size if self.parameterDefinition(self.GRASS_REGION_CELLSIZE_PARAMETER): - self.cellSize = self.parameterAsDouble(parameters, - self.GRASS_REGION_CELLSIZE_PARAMETER, - context) + self.cellSize = self.parameterAsDouble( + parameters, self.GRASS_REGION_CELLSIZE_PARAMETER, context + ) # GRASS snap tolerance - self.snapTolerance = self.parameterAsDouble(parameters, - self.GRASS_SNAP_TOLERANCE_PARAMETER, - context) + self.snapTolerance = self.parameterAsDouble( + parameters, self.GRASS_SNAP_TOLERANCE_PARAMETER, context + ) # GRASS min area - self.minArea = self.parameterAsDouble(parameters, - self.GRASS_MIN_AREA_PARAMETER, - context) + self.minArea = self.parameterAsDouble( + parameters, self.GRASS_MIN_AREA_PARAMETER, context + ) # GRASS output type - self.outputType = self.parameterAsString(parameters, - self.GRASS_OUTPUT_TYPE_PARAMETER, - context) + self.outputType = self.parameterAsString( + parameters, self.GRASS_OUTPUT_TYPE_PARAMETER, context + ) # GRASS align to resolution - self.alignToResolution = self.parameterAsBoolean(parameters, - self.GRASS_REGION_ALIGN_TO_RESOLUTION, - context) + self.alignToResolution = self.parameterAsBoolean( + parameters, self.GRASS_REGION_ALIGN_TO_RESOLUTION, context + ) def processAlgorithm(self, original_parameters, context, feedback): if isWindows(): path = GrassUtils.grassPath() - if path == '': + if path == "": raise QgsProcessingException( - self.tr('GRASS GIS folder is not configured. Please ' - 'configure it before running GRASS GIS algorithms.')) + self.tr( + "GRASS GIS folder is not configured. Please " + "configure it before running GRASS GIS algorithms." + ) + ) # make a copy of the original parameters dictionary - it gets modified by grass algorithms parameters = {k: v for k, v in original_parameters.items()} @@ -475,20 +526,22 @@ def processAlgorithm(self, original_parameters, context, feedback): self.grabDefaultGrassParameters(parameters, context) # Handle ext functions for inputs/command/outputs - for fName in ['Inputs', 'Command', 'Outputs']: - fullName = 'process{}'.format(fName) + for fName in ["Inputs", "Command", "Outputs"]: + fullName = f"process{fName}" if self.module and hasattr(self.module, fullName): getattr(self.module, fullName)(self, parameters, context, feedback) else: getattr(self, fullName)(parameters, context, feedback) # Run GRASS - loglines = [self.tr('GRASS GIS execution commands')] + loglines = [self.tr("GRASS GIS execution commands")] for line in self.commands: feedback.pushCommandInfo(line) loglines.append(line) if ProcessingConfig.getSetting(GrassUtils.GRASS_LOG_COMMANDS): - QgsMessageLog.logMessage("\n".join(loglines), self.tr('Processing'), Qgis.MessageLevel.Info) + QgsMessageLog.logMessage( + "\n".join(loglines), self.tr("Processing"), Qgis.MessageLevel.Info + ) GrassUtils.executeGrass(self.commands, feedback, self.outputCommands) @@ -509,8 +562,8 @@ def processAlgorithm(self, original_parameters, context, feedback): else: outputs[outName] = parameters[outName] if isinstance(out, QgsProcessingOutputHtml): - if self.module and hasattr(self.module, 'convertToHtml'): - func = getattr(self.module, 'convertToHtml') + if self.module and hasattr(self.module, "convertToHtml"): + func = getattr(self.module, "convertToHtml") func(self, self.fileOutputs[outName], outputs) else: self.convertToHtml(self.fileOutputs[outName]) @@ -518,11 +571,19 @@ def processAlgorithm(self, original_parameters, context, feedback): def processInputs(self, parameters, context, feedback): """Prepare the GRASS import commands""" - inputs = [p for p in self.parameterDefinitions() - if isinstance(p, (QgsProcessingParameterVectorLayer, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterMultipleLayers))] + inputs = [ + p + for p in self.parameterDefinitions() + if isinstance( + p, + ( + QgsProcessingParameterVectorLayer, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterMultipleLayers, + ), + ) + ] for param in inputs: paramName = param.name() if paramName not in parameters: @@ -530,35 +591,51 @@ def processInputs(self, parameters, context, feedback): # Handle Null parameter if parameters[paramName] is None: continue - elif isinstance(parameters[paramName], str) and len(parameters[paramName]) == 0: + elif ( + isinstance(parameters[paramName], str) + and len(parameters[paramName]) == 0 + ): continue # Raster inputs needs to be imported into temp GRASS DB if isinstance(param, QgsProcessingParameterRasterLayer): if paramName not in self.exportedLayers: - self.loadRasterLayerFromParameter( - paramName, parameters, context) + self.loadRasterLayerFromParameter(paramName, parameters, context) # Vector inputs needs to be imported into temp GRASS DB - elif isinstance(param, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)): + elif isinstance( + param, + ( + QgsProcessingParameterFeatureSource, + QgsProcessingParameterVectorLayer, + ), + ): if paramName not in self.exportedLayers: # Attribute tables are also vector inputs if QgsProcessing.SourceType.TypeFile in param.dataTypes(): self.loadAttributeTableFromParameter( - paramName, parameters, context) + paramName, parameters, context + ) else: self.loadVectorLayerFromParameter( - paramName, parameters, context, external=None, feedback=feedback) + paramName, + parameters, + context, + external=None, + feedback=feedback, + ) # For multiple inputs, process each layer elif isinstance(param, QgsProcessingParameterMultipleLayers): layers = self.parameterAsLayerList(parameters, paramName, context) for idx, layer in enumerate(layers): - layerName = '{}_{}'.format(paramName, idx) + layerName = f"{paramName}_{idx}" # Add a raster layer if layer.type() == QgsMapLayerType.RasterLayer: self.loadRasterLayer(layerName, layer, context) # Add a vector layer elif layer.type() == QgsMapLayerType.VectorLayer: - self.loadVectorLayer(layerName, layer, context, external=None, feedback=feedback) + self.loadVectorLayer( + layerName, layer, context, external=None, feedback=feedback + ) self.postInputs(context) @@ -571,10 +648,14 @@ def postInputs(self, context: QgsProcessingContext): # Build GRASS region if self.region.isEmpty(): - self.region = QgsProcessingUtils.combineLayerExtents(self.inputLayers, self.destination_crs, context) - command = 'g.region n={} s={} e={} w={}'.format( - self.region.yMaximum(), self.region.yMinimum(), - self.region.xMaximum(), self.region.xMinimum() + self.region = QgsProcessingUtils.combineLayerExtents( + self.inputLayers, self.destination_crs, context + ) + command = "g.region n={} s={} e={} w={}".format( + self.region.yMaximum(), + self.region.yMinimum(), + self.region.xMaximum(), + self.region.xMinimum(), ) # Handle cell size if self.parameterDefinition(self.GRASS_REGION_CELLSIZE_PARAMETER): @@ -582,16 +663,20 @@ def postInputs(self, context: QgsProcessingContext): cellSize = self.cellSize else: cellSize = self.getDefaultCellSize() - command += ' res={}'.format(cellSize) + command += f" res={cellSize}" # Handle align to resolution if self.alignToResolution: - command += ' -a' + command += " -a" # Add the default parameters commands self.commands.append(command) - QgsMessageLog.logMessage(self.tr('processInputs end. Commands: {}').format(self.commands), 'Grass', Qgis.MessageLevel.Info) + QgsMessageLog.logMessage( + self.tr("processInputs end. Commands: {}").format(self.commands), + "Grass", + Qgis.MessageLevel.Info, + ) def processCommand(self, parameters, context, feedback, delOutputs=False): """ @@ -600,9 +685,13 @@ def processCommand(self, parameters, context, feedback, delOutputs=False): :param context: :param delOutputs: do not add outputs to commands. """ - noOutputs = [o for o in self.parameterDefinitions() if o not in self.destinationParameterDefinitions()] - command = '{} '.format(self.grass_name) - command += '{}'.join(self.hardcodedStrings) + noOutputs = [ + o + for o in self.parameterDefinitions() + if o not in self.destinationParameterDefinitions() + ] + command = f"{self.grass_name} " + command += "{}".join(self.hardcodedStrings) # Add algorithm command for param in noOutputs: @@ -610,42 +699,51 @@ def processCommand(self, parameters, context, feedback, delOutputs=False): value = None # Exclude default GRASS parameters - if paramName in [self.GRASS_REGION_CELLSIZE_PARAMETER, - self.GRASS_REGION_EXTENT_PARAMETER, - self.GRASS_MIN_AREA_PARAMETER, - self.GRASS_SNAP_TOLERANCE_PARAMETER, - self.GRASS_OUTPUT_TYPE_PARAMETER, - self.GRASS_REGION_ALIGN_TO_RESOLUTION, - self.GRASS_RASTER_FORMAT_OPT, - self.GRASS_RASTER_FORMAT_META, - self.GRASS_VECTOR_DSCO, - self.GRASS_VECTOR_LCO, - self.GRASS_VECTOR_EXPORT_NOCAT]: + if paramName in [ + self.GRASS_REGION_CELLSIZE_PARAMETER, + self.GRASS_REGION_EXTENT_PARAMETER, + self.GRASS_MIN_AREA_PARAMETER, + self.GRASS_SNAP_TOLERANCE_PARAMETER, + self.GRASS_OUTPUT_TYPE_PARAMETER, + self.GRASS_REGION_ALIGN_TO_RESOLUTION, + self.GRASS_RASTER_FORMAT_OPT, + self.GRASS_RASTER_FORMAT_META, + self.GRASS_VECTOR_DSCO, + self.GRASS_VECTOR_LCO, + self.GRASS_VECTOR_EXPORT_NOCAT, + ]: continue # Raster and vector layers - if isinstance(param, (QgsProcessingParameterRasterLayer, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterFeatureSource)): + if isinstance( + param, + ( + QgsProcessingParameterRasterLayer, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterFeatureSource, + ), + ): if paramName in self.exportedLayers: value = self.exportedLayers[paramName] else: value = self.parameterAsCompatibleSourceLayerPath( - parameters, paramName, context, - QgsVectorFileWriter.supportedFormatExtensions() + parameters, + paramName, + context, + QgsVectorFileWriter.supportedFormatExtensions(), ) # MultipleLayers elif isinstance(param, QgsProcessingParameterMultipleLayers): layers = self.parameterAsLayerList(parameters, paramName, context) values = [] for idx in range(len(layers)): - layerName = '{}_{}'.format(paramName, idx) + layerName = f"{paramName}_{idx}" values.append(self.exportedLayers[layerName]) - value = ','.join(values) + value = ",".join(values) # For booleans, we just add the parameter name elif isinstance(param, QgsProcessingParameterBoolean): if self.parameterAsBoolean(parameters, paramName, context): - command += ' {}'.format(paramName) + command += f" {paramName}" # For Extents, remove if the value is null elif isinstance(param, QgsProcessingParameterExtent): if self.parameterAsExtent(parameters, paramName, context): @@ -658,7 +756,9 @@ def processCommand(self, parameters, context, feedback, delOutputs=False): else: indexes = [self.parameterAsEnum(parameters, paramName, context)] if indexes: - value = '"{}"'.format(','.join([param.options()[i] for i in indexes])) + value = '"{}"'.format( + ",".join([param.options()[i] for i in indexes]) + ) # For strings, we just translate as string elif isinstance(param, QgsProcessingParameterString): data = self.parameterAsString(parameters, paramName, context) @@ -669,9 +769,7 @@ def processCommand(self, parameters, context, feedback, delOutputs=False): ) # For fields, we just translate as string elif isinstance(param, QgsProcessingParameterField): - value = ','.join( - self.parameterAsFields(parameters, paramName, context) - ) + value = ",".join(self.parameterAsFields(parameters, paramName, context)) elif isinstance(param, QgsProcessingParameterFile): if self.parameterAsString(parameters, paramName, context): value = '"{}"'.format( @@ -682,29 +780,32 @@ def processCommand(self, parameters, context, feedback, delOutputs=False): # parameter specified, evaluate as point # TODO - handle CRS transform point = self.parameterAsPoint(parameters, paramName, context) - value = '{},{}'.format(point.x(), point.y()) + value = f"{point.x()},{point.y()}" # For numbers, we translate as a string - elif isinstance(param, (QgsProcessingParameterNumber, - QgsProcessingParameterPoint)): + elif isinstance( + param, (QgsProcessingParameterNumber, QgsProcessingParameterPoint) + ): value = self.parameterAsString(parameters, paramName, context) elif isinstance(param, QgsProcessingParameterRange): v = self.parameterAsRange(parameters, paramName, context) - if (param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) and (math.isnan(v[0]) or math.isnan(v[1])): + if ( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) and (math.isnan(v[0]) or math.isnan(v[1])): continue else: - value = '{},{}'.format(v[0], v[1]) + value = f"{v[0]},{v[1]}" elif isinstance(param, QgsProcessingParameterCrs): if self.parameterAsCrs(parameters, paramName, context): # TODO: ideally we should be exporting to WKT here, but it seems not all grass algorithms # will accept a wkt string for a crs value (e.g. r.tileset) - value = '"{}"'.format(self.parameterAsCrs(parameters, paramName, context).toProj()) + value = f'"{self.parameterAsCrs(parameters, paramName, context).toProj()}"' # For everything else, we assume that it is a string else: value = '"{}"'.format( self.parameterAsString(parameters, paramName, context) ) if value: - command += ' {}={}'.format(paramName.replace('~', ''), value) + command += " {}={}".format(paramName.replace("~", ""), value) # Handle outputs if not delOutputs: @@ -716,47 +817,52 @@ def processCommand(self, parameters, context, feedback, delOutputs=False): # For File destination if isinstance(out, QgsProcessingParameterFileDestination): if outName in parameters and parameters[outName] is not None: - outPath = self.parameterAsFileOutput(parameters, outName, context) + outPath = self.parameterAsFileOutput( + parameters, outName, context + ) self.fileOutputs[outName] = outPath # for HTML reports, we need to redirect stdout - if out.defaultFileExtension().lower() == 'html': - if outName == 'html': + if out.defaultFileExtension().lower() == "html": + if outName == "html": # for "fake" outputs redirect command stdout - command += ' > "{}"'.format(outPath) + command += f' > "{outPath}"' else: # for real outputs only output itself should be redirected - command += ' {}=- > "{}"'.format(outName, outPath) + command += f' {outName}=- > "{outPath}"' else: - command += ' {}="{}"'.format(outName, outPath) + command += f' {outName}="{outPath}"' # For folders destination elif isinstance(out, QgsProcessingParameterFolderDestination): # We need to add a unique temporary basename uniqueBasename = outName + self.uniqueSuffix - command += ' {}={}'.format(outName, uniqueBasename) + command += f" {outName}={uniqueBasename}" else: if outName in parameters and parameters[outName] is not None: # We add an output name to make sure it is unique if the session # uses this algorithm several times. uniqueOutputName = outName + self.uniqueSuffix - command += ' {}={}'.format(outName, uniqueOutputName) + command += f" {outName}={uniqueOutputName}" # Add output file to exported layers, to indicate that # they are present in GRASS self.exportedLayers[outName] = uniqueOutputName - command += ' --overwrite' + command += " --overwrite" self.commands.append(command) - QgsMessageLog.logMessage(self.tr('processCommands end. Commands: {}').format(self.commands), 'Grass', Qgis.MessageLevel.Info) + QgsMessageLog.logMessage( + self.tr("processCommands end. Commands: {}").format(self.commands), + "Grass", + Qgis.MessageLevel.Info, + ) def vectorOutputType(self, parameters, context): """Determine vector output types for outputs""" - self.outType = 'auto' + self.outType = "auto" if self.parameterDefinition(self.GRASS_OUTPUT_TYPE_PARAMETER): - typeidx = self.parameterAsEnum(parameters, - self.GRASS_OUTPUT_TYPE_PARAMETER, - context) - self.outType = ('auto' if typeidx - is None else self.OUTPUT_TYPES[typeidx]) + typeidx = self.parameterAsEnum( + parameters, self.GRASS_OUTPUT_TYPE_PARAMETER, context + ) + self.outType = "auto" if typeidx is None else self.OUTPUT_TYPES[typeidx] def processOutputs(self, parameters, context, feedback): """Prepare the GRASS v.out.ogr commands""" @@ -776,9 +882,9 @@ def processOutputs(self, parameters, context, feedback): elif isinstance(out, QgsProcessingParameterFolderDestination): self.exportRasterLayersIntoDirectory(outName, parameters, context) - def loadRasterLayerFromParameter(self, name, parameters, - context: QgsProcessingContext, - external=None, band=1): + def loadRasterLayerFromParameter( + self, name, parameters, context: QgsProcessingContext, external=None, band=1 + ): """ Creates a dedicated command to load a raster into the temporary GRASS DB. @@ -791,8 +897,15 @@ def loadRasterLayerFromParameter(self, name, parameters, layer = self.parameterAsRasterLayer(parameters, name, context) self.loadRasterLayer(name, layer, context, external, band) - def loadRasterLayer(self, name, layer, context: QgsProcessingContext, - external=None, band=1, destName=None): + def loadRasterLayer( + self, + name, + layer, + context: QgsProcessingContext, + external=None, + band=1, + destName=None, + ): """ Creates a dedicated command to load a raster into the temporary GRASS DB. @@ -808,16 +921,19 @@ def loadRasterLayer(self, name, layer, context: QgsProcessingContext, self.inputLayers.append(layer) self.setSessionProjectionFromLayer(layer, context) if not destName: - destName = 'rast_{}'.format(os.path.basename(getTempFilename(context=context))) + destName = f"rast_{os.path.basename(getTempFilename(context=context))}" self.exportedLayers[name] = destName command = '{} input="{}" {}output="{}" --overwrite -o'.format( - 'r.external' if external else 'r.in.gdal', + "r.external" if external else "r.in.gdal", os.path.normpath(layer.source()), - 'band={} '.format(band) if band else '', - destName) + f"band={band} " if band else "", + destName, + ) self.commands.append(command) - def exportRasterLayerFromParameter(self, name, parameters, context, colorTable=True): + def exportRasterLayerFromParameter( + self, name, parameters, context, colorTable=True + ): """ Creates a dedicated command to export a raster from temporary GRASS DB into a file via gdal. @@ -831,18 +947,29 @@ def exportRasterLayerFromParameter(self, name, parameters, context, colorTable=T return fileName = os.path.normpath(fileName) - grassName = '{}{}'.format(name, self.uniqueSuffix) + grassName = f"{name}{self.uniqueSuffix}" outFormat = GrassUtils.getRasterFormatFromFilename(fileName) - createOpt = self.parameterAsString(parameters, self.GRASS_RASTER_FORMAT_OPT, context) - metaOpt = self.parameterAsString(parameters, self.GRASS_RASTER_FORMAT_META, context) - self.exportRasterLayer(grassName, fileName, colorTable, outFormat, createOpt, metaOpt) + createOpt = self.parameterAsString( + parameters, self.GRASS_RASTER_FORMAT_OPT, context + ) + metaOpt = self.parameterAsString( + parameters, self.GRASS_RASTER_FORMAT_META, context + ) + self.exportRasterLayer( + grassName, fileName, colorTable, outFormat, createOpt, metaOpt + ) self.fileOutputs[name] = fileName - def exportRasterLayer(self, grassName, fileName, - colorTable=True, outFormat='GTiff', - createOpt=None, - metaOpt=None): + def exportRasterLayer( + self, + grassName, + fileName, + colorTable=True, + outFormat="GTiff", + createOpt=None, + metaOpt=None, + ): """ Creates a dedicated command to export a raster from temporary GRASS DB into a file via gdal. @@ -853,22 +980,27 @@ def exportRasterLayer(self, grassName, fileName, :param createOpt: creation options for format. :param metaOpt: metadata options for export. """ - createOpt = createOpt or GrassUtils.GRASS_RASTER_FORMATS_CREATEOPTS.get(outFormat) + createOpt = createOpt or GrassUtils.GRASS_RASTER_FORMATS_CREATEOPTS.get( + outFormat + ) for cmd in [self.commands, self.outputCommands]: # Adjust region to layer before exporting - cmd.append('g.region raster={}'.format(grassName)) + cmd.append(f"g.region raster={grassName}") cmd.append( 'r.out.gdal -t -m{} input="{}" output="{}" format="{}" {}{} --overwrite'.format( - '' if colorTable else ' -c', - grassName, fileName, + "" if colorTable else " -c", + grassName, + fileName, outFormat, - ' createopt="{}"'.format(createOpt) if createOpt else '', - ' metaopt="{}"'.format(metaOpt) if metaOpt else '' + f' createopt="{createOpt}"' if createOpt else "", + f' metaopt="{metaOpt}"' if metaOpt else "", ) ) - def exportRasterLayersIntoDirectory(self, name, parameters, context, colorTable=True, wholeDB=False): + def exportRasterLayersIntoDirectory( + self, name, parameters, context, colorTable=True, wholeDB=False + ): """ Creates a dedicated loop command to export rasters from temporary GRASS DB into a directory via gdal. @@ -879,9 +1011,8 @@ def exportRasterLayersIntoDirectory(self, name, parameters, context, colorTable= :param wholeDB: export every raster layer from the GRASSDB """ # Grab directory name and temporary basename - outDir = os.path.normpath( - self.parameterAsString(parameters, name, context)) - basename = '' + outDir = os.path.normpath(self.parameterAsString(parameters, name, context)) + basename = "" if not wholeDB: basename = name + self.uniqueSuffix @@ -890,21 +1021,28 @@ def exportRasterLayersIntoDirectory(self, name, parameters, context, colorTable= # TODO Format/options support if isWindows(): cmd.append("if not exist {0} mkdir {0}".format(outDir)) - cmd.append("for /F %%r IN ('g.list type^=rast pattern^=\"{}*\"') do r.out.gdal -m{} input=%%r output={}/%%r.tif {}".format( - basename, - ' -t' if colorTable else '', - outDir, - '--overwrite -c createopt="TFW=YES,COMPRESS=LZW"' - )) + cmd.append( + "for /F %%r IN ('g.list type^=rast pattern^=\"{}*\"') do r.out.gdal -m{} input=%%r output={}/%%r.tif {}".format( + basename, + " -t" if colorTable else "", + outDir, + '--overwrite -c createopt="TFW=YES,COMPRESS=LZW"', + ) + ) else: - cmd.append("for r in $(g.list type=rast pattern='{}*'); do".format(basename)) - cmd.append(" r.out.gdal -m{0} input=${{r}} output={1}/${{r}}.tif {2}".format( - ' -t' if colorTable else '', outDir, - '--overwrite -c createopt="TFW=YES,COMPRESS=LZW"' - )) + cmd.append(f"for r in $(g.list type=rast pattern='{basename}*'); do") + cmd.append( + " r.out.gdal -m{0} input=${{r}} output={1}/${{r}}.tif {2}".format( + " -t" if colorTable else "", + outDir, + '--overwrite -c createopt="TFW=YES,COMPRESS=LZW"', + ) + ) cmd.append("done") - def loadVectorLayerFromParameter(self, name, parameters, context, feedback, external=False): + def loadVectorLayerFromParameter( + self, name, parameters, context, feedback, external=False + ): """ Creates a dedicated command to load a vector into the temporary GRASS DB. @@ -915,31 +1053,43 @@ def loadVectorLayerFromParameter(self, name, parameters, context, feedback, exte """ layer = self.parameterAsVectorLayer(parameters, name, context) - is_ogr_disk_based_layer = layer is not None and layer.dataProvider().name() == 'ogr' + is_ogr_disk_based_layer = ( + layer is not None and layer.dataProvider().name() == "ogr" + ) if is_ogr_disk_based_layer: # we only support direct reading of disk based ogr layers -- not ogr postgres layers, etc - source_parts = QgsProviderRegistry.instance().decodeUri('ogr', layer.source()) - if not source_parts.get('path'): + source_parts = QgsProviderRegistry.instance().decodeUri( + "ogr", layer.source() + ) + if not source_parts.get("path"): is_ogr_disk_based_layer = False - elif source_parts.get('layerId'): + elif source_parts.get("layerId"): # no support for directly reading layers by id in grass is_ogr_disk_based_layer = False if not is_ogr_disk_based_layer: # 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, context, external=external, feedback=feedback) + path = self.parameterAsCompatibleSourceLayerPath( + parameters, + name, + context, + QgsVectorFileWriter.supportedFormatExtensions(), + feedback=feedback, + ) + ogr_layer = QgsVectorLayer(path, "", "ogr") + self.loadVectorLayer( + name, ogr_layer, context, external=external, feedback=feedback + ) else: # already an ogr disk based layer source - self.loadVectorLayer(name, layer, context, external=external, feedback=feedback) + self.loadVectorLayer( + name, layer, context, external=external, feedback=feedback + ) - def loadVectorLayer(self, name, layer, - context: QgsProcessingContext, - external=False, feedback=None): + def loadVectorLayer( + self, name, layer, context: QgsProcessingContext, external=False, feedback=None + ): """ Creates a dedicated command to load a vector into temporary GRASS DB. @@ -951,47 +1101,57 @@ def loadVectorLayer(self, name, layer, """ # TODO: support multiple input formats if external is None: - external = ProcessingConfig.getSetting( - GrassUtils.GRASS_USE_VEXTERNAL) + external = ProcessingConfig.getSetting(GrassUtils.GRASS_USE_VEXTERNAL) - source_parts = QgsProviderRegistry.instance().decodeUri('ogr', layer.source()) - file_path = source_parts.get('path') - layer_name = source_parts.get('layerName') + source_parts = QgsProviderRegistry.instance().decodeUri("ogr", layer.source()) + file_path = source_parts.get("path") + layer_name = source_parts.get("layerName") # safety check: we can only use external for ogr layers which support random read if external: if feedback is not None: - feedback.pushInfo(self.tr('Attempting to use v.external for direct layer read')) + feedback.pushInfo( + self.tr("Attempting to use v.external for direct layer read") + ) ds = ogr.Open(file_path) if ds is not None: ogr_layer = ds.GetLayer() if ogr_layer is None or not ogr_layer.TestCapability(ogr.OLCRandomRead): if feedback is not None: - feedback.reportError(self.tr('Cannot use v.external: layer does not support random read')) + feedback.reportError( + self.tr( + "Cannot use v.external: layer does not support random read" + ) + ) external = False else: if feedback is not None: - feedback.reportError(self.tr('Cannot use v.external: error reading layer')) + feedback.reportError( + self.tr("Cannot use v.external: error reading layer") + ) external = False self.inputLayers.append(layer) self.setSessionProjectionFromLayer(layer, context) - destFilename = 'vector_{}'.format(os.path.basename(getTempFilename(context=context))) + destFilename = f"vector_{os.path.basename(getTempFilename(context=context))}" self.exportedLayers[name] = destFilename command = '{}{}{} input="{}"{} output="{}" --overwrite -o'.format( - 'v.external' if external else 'v.in.ogr', - ' min_area={}'.format(self.minArea) if not external else '', - ' snap={}'.format(self.snapTolerance) if not external else '', + "v.external" if external else "v.in.ogr", + f" min_area={self.minArea}" if not external else "", + f" snap={self.snapTolerance}" if not external else "", os.path.normpath(file_path), - ' layer="{}"'.format(layer_name) if layer_name else '', - destFilename) + f' layer="{layer_name}"' if layer_name else "", + destFilename, + ) if layer.subsetString(): escaped_subset = layer.subsetString().replace('"', '\\"') command += f' where="{escaped_subset}"' self.commands.append(command) - def exportVectorLayerFromParameter(self, name, parameters, context, layer=None, nocats=False): + def exportVectorLayerFromParameter( + self, name, parameters, context, layer=None, nocats=False + ): """ Creates a dedicated command to export a vector from a QgsProcessingParameter. @@ -1001,28 +1161,53 @@ def exportVectorLayerFromParameter(self, name, parameters, context, layer=None, :param nocats: do not export GRASS categories. """ fileName = os.path.normpath( - self.parameterAsOutputLayer(parameters, name, context)) - grassName = '{}{}'.format(name, self.uniqueSuffix) + self.parameterAsOutputLayer(parameters, name, context) + ) + grassName = f"{name}{self.uniqueSuffix}" # Find if there is a dataType dataType = self.outType - if self.outType == 'auto': + if self.outType == "auto": parameter = self.parameterDefinition(name) if parameter: layerType = parameter.dataType() if layerType in self.QGIS_OUTPUT_TYPES: dataType = self.QGIS_OUTPUT_TYPES[layerType] - outFormat = QgsVectorFileWriter.driverForExtension(os.path.splitext(fileName)[1]).replace(' ', '_') + outFormat = QgsVectorFileWriter.driverForExtension( + os.path.splitext(fileName)[1] + ).replace(" ", "_") dsco = self.parameterAsString(parameters, self.GRASS_VECTOR_DSCO, context) lco = self.parameterAsString(parameters, self.GRASS_VECTOR_LCO, context) - exportnocat = self.parameterAsBoolean(parameters, self.GRASS_VECTOR_EXPORT_NOCAT, context) - self.exportVectorLayer(grassName, fileName, layer, nocats, dataType, outFormat, dsco, lco, exportnocat) + exportnocat = self.parameterAsBoolean( + parameters, self.GRASS_VECTOR_EXPORT_NOCAT, context + ) + self.exportVectorLayer( + grassName, + fileName, + layer, + nocats, + dataType, + outFormat, + dsco, + lco, + exportnocat, + ) self.fileOutputs[name] = fileName - def exportVectorLayer(self, grassName, fileName, layer=None, nocats=False, dataType='auto', - outFormat=None, dsco=None, lco=None, exportnocat=False): + def exportVectorLayer( + self, + grassName, + fileName, + layer=None, + nocats=False, + dataType="auto", + outFormat=None, + dsco=None, + lco=None, + exportnocat=False, + ): """ Creates a dedicated command to export a vector from temporary GRASS DB into a file via OGR. @@ -1037,18 +1222,22 @@ def exportVectorLayer(self, grassName, fileName, layer=None, nocats=False, dataT :param exportnocat: do not export features without categories. """ if outFormat is None: - outFormat = QgsVectorFileWriter.driverForExtension(os.path.splitext(fileName)[1]).replace(' ', '_') + outFormat = QgsVectorFileWriter.driverForExtension( + os.path.splitext(fileName)[1] + ).replace(" ", "_") for cmd in [self.commands, self.outputCommands]: cmd.append( 'v.out.ogr{} type="{}" input="{}" output="{}" format="{}" {}{}{}{} --overwrite'.format( - '' if nocats else '', - dataType, grassName, fileName, + "" if nocats else "", + dataType, + grassName, + fileName, outFormat, - 'layer={}'.format(layer) if layer else '', - ' dsco="{}"'.format(dsco) if dsco else '', - ' lco="{}"'.format(lco) if lco else '', - ' -c' if exportnocat else '' + f"layer={layer}" if layer else "", + f' dsco="{dsco}"' if dsco else "", + f' lco="{lco}"' if lco else "", + " -c" if exportnocat else "", ) ) @@ -1063,8 +1252,9 @@ def loadAttributeTableFromParameter(self, name, parameters, context): table = self.parameterAsVectorLayer(parameters, name, context) self.loadAttributeTable(name, table, context) - def loadAttributeTable(self, name, layer, context: QgsProcessingContext, - destName=None): + def loadAttributeTable( + self, name, layer, context: QgsProcessingContext, destName=None + ): """ Creates a dedicated command to load an attribute table into the temporary GRASS DB. @@ -1075,13 +1265,14 @@ def loadAttributeTable(self, name, layer, context: QgsProcessingContext, """ self.inputLayers.append(layer) if not destName: - destName = 'table_{}'.format(os.path.basename(getTempFilename(context=context))) + destName = f"table_{os.path.basename(getTempFilename(context=context))}" self.exportedLayers[name] = destName command = 'db.in.ogr --overwrite input="{}" output="{}"'.format( - os.path.normpath(layer.source()), destName) + os.path.normpath(layer.source()), destName + ) self.commands.append(command) - def exportAttributeTable(self, grassName, fileName, outFormat='CSV', layer=1): + def exportAttributeTable(self, grassName, fileName, outFormat="CSV", layer=1): """ Creates a dedicated command to export an attribute table from the temporary GRASS DB into a file via ogr. @@ -1104,11 +1295,12 @@ def setSessionProjectionFromProject(self, context: QgsProcessingContext): """ if not GrassUtils.projectionSet and iface: self.setSessionProjection( - iface.mapCanvas().mapSettings().destinationCrs(), - context + iface.mapCanvas().mapSettings().destinationCrs(), context ) - def setSessionProjectionFromLayer(self, layer: QgsMapLayer, context: QgsProcessingContext): + def setSessionProjectionFromLayer( + self, layer: QgsMapLayer, context: QgsProcessingContext + ): """ Set the projection from a QgsVectorLayer. We create a WKT definition which is transmitted to Grass @@ -1122,25 +1314,27 @@ def setSessionProjection(self, crs, context: QgsProcessingContext): """ self.destination_crs = crs file_name = GrassUtils.exportCrsWktToFile(crs, context) - command = 'g.proj -c wkt="{}"'.format(file_name) + command = f'g.proj -c wkt="{file_name}"' self.commands.append(command) GrassUtils.projectionSet = True def convertToHtml(self, fileName): # Read HTML contents lines = [] - with open(fileName, encoding='utf-8') as f: + with open(fileName, encoding="utf-8") as f: lines = f.readlines() - if len(lines) > 1 and '' not in lines[0]: + if len(lines) > 1 and "" not in lines[0]: # Then write into the HTML file - with open(fileName, 'w', encoding='utf-8') as f: - f.write('') - f.write('') - f.write('

') + with open(fileName, "w", encoding="utf-8") as f: + f.write("") + f.write( + '' + ) + f.write("

") for line in lines: - f.write('{}
'.format(line)) - f.write('

') + f.write(f"{line}
") + f.write("

") def canExecute(self): message = GrassUtils.checkGrassIsInstalled() @@ -1149,7 +1343,7 @@ def canExecute(self): def checkParameterValues(self, parameters, context): grass_parameters = {k: v for k, v in parameters.items()} if self.module: - if hasattr(self.module, 'checkParameterValuesBeforeExecuting'): - func = getattr(self.module, 'checkParameterValuesBeforeExecuting') + if hasattr(self.module, "checkParameterValuesBeforeExecuting"): + func = getattr(self.module, "checkParameterValuesBeforeExecuting") return func(self, grass_parameters, context) return super().checkParameterValues(grass_parameters, context) diff --git a/python/plugins/grassprovider/grass_plugin.py b/python/plugins/grassprovider/grass_plugin.py index 1f82de63e7f9..7bf0c99f75b7 100644 --- a/python/plugins/grassprovider/grass_plugin.py +++ b/python/plugins/grassprovider/grass_plugin.py @@ -15,14 +15,14 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'June 2021' -__copyright__ = '(C) 2021, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "June 2021" +__copyright__ = "(C) 2021, Alexander Bruy" from qgis.core import QgsApplication, QgsRuntimeProfiler -with QgsRuntimeProfiler.profile('Import GRASS Provider'): +with QgsRuntimeProfiler.profile("Import GRASS Provider"): from grassprovider.grass_provider import GrassProvider diff --git a/python/plugins/grassprovider/grass_provider.py b/python/plugins/grassprovider/grass_provider.py index a71769397659..19022c0d08cc 100644 --- a/python/plugins/grassprovider/grass_provider.py +++ b/python/plugins/grassprovider/grass_provider.py @@ -15,21 +15,23 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'April 2014' -__copyright__ = '(C) 2014, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "April 2014" +__copyright__ = "(C) 2014, Victor Olaya" import json from typing import List from qgis.PyQt.QtCore import QCoreApplication -from qgis.core import (Qgis, - QgsApplication, - QgsProcessingAlgorithm, - QgsProcessingProvider, - QgsVectorFileWriter, - QgsMessageLog, - QgsRuntimeProfiler) -from processing.core.ProcessingConfig import (ProcessingConfig, Setting) +from qgis.core import ( + Qgis, + QgsApplication, + QgsProcessingAlgorithm, + QgsProcessingProvider, + QgsVectorFileWriter, + QgsMessageLog, + QgsRuntimeProfiler, +) +from processing.core.ProcessingConfig import ProcessingConfig, Setting from grassprovider.grass_utils import GrassUtils from grassprovider.grass_algorithm import GrassAlgorithm @@ -40,35 +42,57 @@ def __init__(self): super().__init__() def load(self): - with QgsRuntimeProfiler.profile('Grass Provider'): + with QgsRuntimeProfiler.profile("Grass Provider"): ProcessingConfig.settingIcons[self.name()] = self.icon() - ProcessingConfig.addSetting(Setting( - self.name(), - GrassUtils.GRASS_LOG_COMMANDS, - self.tr('Log execution commands'), False)) - ProcessingConfig.addSetting(Setting( - self.name(), - GrassUtils.GRASS_LOG_CONSOLE, - self.tr('Log console output'), False)) - ProcessingConfig.addSetting(Setting( - self.name(), - GrassUtils.GRASS_HELP_URL, - self.tr('Location of GRASS docs'), '')) + ProcessingConfig.addSetting( + Setting( + self.name(), + GrassUtils.GRASS_LOG_COMMANDS, + self.tr("Log execution commands"), + False, + ) + ) + ProcessingConfig.addSetting( + Setting( + self.name(), + GrassUtils.GRASS_LOG_CONSOLE, + self.tr("Log console output"), + False, + ) + ) + ProcessingConfig.addSetting( + Setting( + self.name(), + GrassUtils.GRASS_HELP_URL, + self.tr("Location of GRASS docs"), + "", + ) + ) # Add settings for using r.external/v.external instead of r.in.gdal/v.in.ogr # but set them to False by default because the {r,v}.external implementations # have some bugs on windows + there are algorithms that can't be used with # external data (need a solid r.in.gdal/v.in.ogr). # For more info have a look at e.g. https://trac.osgeo.org/grass/ticket/3927 - ProcessingConfig.addSetting(Setting( - self.name(), - GrassUtils.GRASS_USE_REXTERNAL, - self.tr('For raster layers, use r.external (faster) instead of r.in.gdal'), - False)) - ProcessingConfig.addSetting(Setting( - self.name(), - GrassUtils.GRASS_USE_VEXTERNAL, - self.tr('For vector layers, use v.external (faster) instead of v.in.ogr'), - False)) + ProcessingConfig.addSetting( + Setting( + self.name(), + GrassUtils.GRASS_USE_REXTERNAL, + self.tr( + "For raster layers, use r.external (faster) instead of r.in.gdal" + ), + False, + ) + ) + ProcessingConfig.addSetting( + Setting( + self.name(), + GrassUtils.GRASS_USE_VEXTERNAL, + self.tr( + "For vector layers, use v.external (faster) instead of v.in.ogr" + ), + False, + ) + ) ProcessingConfig.readSettings() self.refreshAlgorithms() @@ -81,68 +105,94 @@ def unload(self): ProcessingConfig.removeSetting(GrassUtils.GRASS_USE_REXTERNAL) ProcessingConfig.removeSetting(GrassUtils.GRASS_USE_VEXTERNAL) - def parse_algorithms(self) -> List[QgsProcessingAlgorithm]: + def parse_algorithms(self) -> list[QgsProcessingAlgorithm]: """ Parses all algorithm sources and returns a list of all GRASS algorithms. """ algs = [] for folder in GrassUtils.grassDescriptionFolders(): - if (folder / 'algorithms.json').exists(): + if (folder / "algorithms.json").exists(): # fast approach -- use aggregated JSON summary of algorithms - with open(folder / 'algorithms.json', 'rt', encoding='utf8') as f_in: + with open(folder / "algorithms.json", encoding="utf8") as f_in: algorithm_strings = f_in.read() algorithms_json = json.loads(algorithm_strings) for algorithm_json in algorithms_json: try: alg = GrassAlgorithm( - json_definition=algorithm_json, - description_folder=folder) - if alg.name().strip() != '': + json_definition=algorithm_json, description_folder=folder + ) + if alg.name().strip() != "": algs.append(alg) else: - QgsMessageLog.logMessage(self.tr('Could not open GRASS GIS algorithm: {0}').format(algorithm_json.get('name')), self.tr('Processing'), Qgis.MessageLevel.Critical) + QgsMessageLog.logMessage( + self.tr( + "Could not open GRASS GIS algorithm: {0}" + ).format(algorithm_json.get("name")), + self.tr("Processing"), + Qgis.MessageLevel.Critical, + ) except Exception as e: QgsMessageLog.logMessage( - self.tr('Could not open GRASS GIS algorithm: {0}\n{1}').format(algorithm_json.get('name'), e), self.tr('Processing'), Qgis.MessageLevel.Critical) + self.tr( + "Could not open GRASS GIS algorithm: {0}\n{1}" + ).format(algorithm_json.get("name"), e), + self.tr("Processing"), + Qgis.MessageLevel.Critical, + ) else: # slow approach - pass txt files one by one - for descriptionFile in folder.glob('*.txt'): + for descriptionFile in folder.glob("*.txt"): try: - alg = GrassAlgorithm( - description_file=descriptionFile) - if alg.name().strip() != '': + alg = GrassAlgorithm(description_file=descriptionFile) + if alg.name().strip() != "": algs.append(alg) else: - QgsMessageLog.logMessage(self.tr('Could not open GRASS GIS algorithm: {0}').format(descriptionFile), self.tr('Processing'), Qgis.MessageLevel.Critical) + QgsMessageLog.logMessage( + self.tr( + "Could not open GRASS GIS algorithm: {0}" + ).format(descriptionFile), + self.tr("Processing"), + Qgis.MessageLevel.Critical, + ) except Exception as e: QgsMessageLog.logMessage( - self.tr('Could not open GRASS GIS algorithm: {0}\n{1}').format(descriptionFile, e), self.tr('Processing'), Qgis.MessageLevel.Critical) + self.tr( + "Could not open GRASS GIS algorithm: {0}\n{1}" + ).format(descriptionFile, e), + self.tr("Processing"), + Qgis.MessageLevel.Critical, + ) return algs def loadAlgorithms(self): version = GrassUtils.installedVersion(True) if version is None: - QgsMessageLog.logMessage(self.tr('Problem with GRASS installation: GRASS was not found or is not correctly installed'), - self.tr('Processing'), Qgis.MessageLevel.Critical) + QgsMessageLog.logMessage( + self.tr( + "Problem with GRASS installation: GRASS was not found or is not correctly installed" + ), + self.tr("Processing"), + Qgis.MessageLevel.Critical, + ) return for a in self.parse_algorithms(): self.addAlgorithm(a) def name(self): - return 'GRASS' + return "GRASS" def longName(self): version = GrassUtils.installedVersion() - return 'GRASS GIS ({})'.format(version) if version is not None else "GRASS GIS" + return f"GRASS GIS ({version})" if version is not None else "GRASS GIS" def id(self): - return 'grass' + return "grass" def helpId(self): - return 'grass7' + return "grass7" def icon(self): return QgsApplication.getThemeIcon("/providerGrass.svg") @@ -172,7 +222,7 @@ def supportedOutputRasterLayerExtensions(self): def canBeActivated(self): return not bool(GrassUtils.checkGrassIsInstalled()) - def tr(self, string, context=''): - if context == '': - context = 'Grass7AlgorithmProvider' + def tr(self, string, context=""): + if context == "": + context = "Grass7AlgorithmProvider" return QCoreApplication.translate(context, string) diff --git a/python/plugins/grassprovider/grass_utils.py b/python/plugins/grassprovider/grass_utils.py index 37c784c09d7d..0818efed030d 100644 --- a/python/plugins/grassprovider/grass_utils.py +++ b/python/plugins/grassprovider/grass_utils.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'February 2015' -__copyright__ = '(C) 2014-2015, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "February 2015" +__copyright__ = "(C) 2014-2015, Victor Olaya" import os import re @@ -25,16 +25,9 @@ import stat import subprocess import sys -from dataclasses import ( - dataclass, - field -) +from dataclasses import dataclass, field from pathlib import Path -from typing import ( - Optional, - List, - Dict -) +from typing import Optional, List, Dict from qgis.PyQt.QtCore import QCoreApplication from qgis.core import ( @@ -52,22 +45,22 @@ class GrassUtils: - GRASS_REGION_XMIN = 'GRASS7_REGION_XMIN' - GRASS_REGION_YMIN = 'GRASS7_REGION_YMIN' - GRASS_REGION_XMAX = 'GRASS7_REGION_XMAX' - GRASS_REGION_YMAX = 'GRASS7_REGION_YMAX' - GRASS_REGION_CELLSIZE = 'GRASS7_REGION_CELLSIZE' - GRASS_LOG_COMMANDS = 'GRASS7_LOG_COMMANDS' - GRASS_LOG_CONSOLE = 'GRASS7_LOG_CONSOLE' - GRASS_HELP_URL = 'GRASS_HELP_URL' - GRASS_USE_REXTERNAL = 'GRASS_USE_REXTERNAL' - GRASS_USE_VEXTERNAL = 'GRASS_USE_VEXTERNAL' + GRASS_REGION_XMIN = "GRASS7_REGION_XMIN" + GRASS_REGION_YMIN = "GRASS7_REGION_YMIN" + GRASS_REGION_XMAX = "GRASS7_REGION_XMAX" + GRASS_REGION_YMAX = "GRASS7_REGION_YMAX" + GRASS_REGION_CELLSIZE = "GRASS7_REGION_CELLSIZE" + GRASS_LOG_COMMANDS = "GRASS7_LOG_COMMANDS" + GRASS_LOG_CONSOLE = "GRASS7_LOG_CONSOLE" + GRASS_HELP_URL = "GRASS_HELP_URL" + GRASS_USE_REXTERNAL = "GRASS_USE_REXTERNAL" + GRASS_USE_VEXTERNAL = "GRASS_USE_VEXTERNAL" # TODO Review all default options formats GRASS_RASTER_FORMATS_CREATEOPTS = { - 'GTiff': 'TFW=YES,COMPRESS=LZW', - 'PNG': 'ZLEVEL=9', - 'WEBP': 'QUALITY=85' + "GTiff": "TFW=YES,COMPRESS=LZW", + "PNG": "ZLEVEL=9", + "WEBP": "QUALITY=85", } sessionRunning = False @@ -89,9 +82,9 @@ def grassBatchJobFilename(): """ gisdbase = GrassUtils.grassDataFolder() if isWindows(): - batchFile = os.path.join(gisdbase, 'grass_batch_job.cmd') + batchFile = os.path.join(gisdbase, "grass_batch_job.cmd") else: - batchFile = os.path.join(gisdbase, 'grass_batch_job.sh') + batchFile = os.path.join(gisdbase, "grass_batch_job.sh") return batchFile @staticmethod @@ -101,8 +94,8 @@ def exportCrsWktToFile(crs, context: QgsProcessingContext): to this file """ wkt = crs.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED) - wkt_file = QgsProcessingUtils.generateTempFilename('crs.prj', context) - with open(wkt_file, 'w', encoding='utf-8') as f: + wkt_file = QgsProcessingUtils.generateTempFilename("crs.prj", context) + with open(wkt_file, "w", encoding="utf-8") as f: f.write(wkt) return wkt_file @@ -125,13 +118,13 @@ def installedVersion(run=False): si.dwFlags |= subprocess.STARTF_USESHOWWINDOW si.wShowWindow = subprocess.SW_HIDE with subprocess.Popen( - [GrassUtils.command, '-v'], + [GrassUtils.command, "-v"], shell=False, stdout=subprocess.PIPE, stdin=subprocess.DEVNULL, stderr=subprocess.STDOUT, universal_newlines=True, - startupinfo=si if isWindows() else None + startupinfo=si if isWindows() else None, ) as proc: try: lines = proc.stdout.readlines() @@ -174,31 +167,39 @@ def searchFolder(folder): vn = os.path.join(path, "etc", "VERSIONNUMBER") if os.path.isfile(vn): with open(vn) as f: - major, minor, patch = f.readlines()[0].split(' ')[0].split('.') - if patch != 'svn': - patch = '' + major, minor, patch = f.readlines()[0].split(" ")[0].split(".") + if patch != "svn": + patch = "" cmdList = [ - "grass{}{}{}".format(major, minor, patch), + f"grass{major}{minor}{patch}", "grass", - "grass{}{}{}.{}".format(major, minor, patch, - "bat" if isWindows() else "sh"), - "grass.{}".format("bat" if isWindows() else "sh") + "grass{}{}{}.{}".format( + major, minor, patch, "bat" if isWindows() else "sh" + ), + "grass.{}".format("bat" if isWindows() else "sh"), ] else: - cmdList = ["grass80", "grass78", "grass76", "grass74", "grass72", - "grass70", "grass"] + cmdList = [ + "grass80", + "grass78", + "grass76", + "grass74", + "grass72", + "grass70", + "grass", + ] cmdList.extend( - ["{}.{}".format(b, "bat" if isWindows() else "sh") for b in - cmdList]) + ["{}.{}".format(b, "bat" if isWindows() else "sh") for b in cmdList] + ) # For MS-Windows there is a difference between GRASS Path and GRASS binary if isWindows(): # If nothing found, use OSGEO4W or QgsPrefix: if "OSGEO4W_ROOT" in os.environ: - testFolder = str(os.environ['OSGEO4W_ROOT']) + testFolder = str(os.environ["OSGEO4W_ROOT"]) else: testFolder = str(QgsApplication.prefixPath()) - testFolder = os.path.join(testFolder, 'bin') + testFolder = os.path.join(testFolder, "bin") command = searchFolder(testFolder) elif isMac(): # Search in grassPath @@ -214,7 +215,7 @@ def searchFolder(folder): if command: GrassUtils.command = command - if path == '': + if path == "": GrassUtils.path = os.path.dirname(command) return command @@ -229,7 +230,7 @@ def grassPath(): return GrassUtils.path if not isWindows() and not isMac(): - return '' + return "" folder = None # Under MS-Windows, we use GISBASE or QGIS Path for folder @@ -238,16 +239,21 @@ def grassPath(): folder = os.environ["GISBASE"] else: testfolder = os.path.join( - os.path.dirname(QgsApplication.prefixPath()), 'grass') + os.path.dirname(QgsApplication.prefixPath()), "grass" + ) if os.path.isdir(testfolder): - grassfolders = sorted([f for f in os.listdir(testfolder) if - f.startswith( - "grass-7.") and os.path.isdir( - os.path.join(testfolder, f))], - reverse=True, - key=lambda x: [int(v) for v in x[ - len("grass-"):].split( - '.') if v != 'svn']) + grassfolders = sorted( + [ + f + for f in os.listdir(testfolder) + if f.startswith("grass-7.") + and os.path.isdir(os.path.join(testfolder, f)) + ], + reverse=True, + key=lambda x: [ + int(v) for v in x[len("grass-") :].split(".") if v != "svn" + ], + ) if grassfolders: folder = os.path.join(testfolder, grassfolders[0]) elif isMac(): @@ -256,18 +262,21 @@ def grassPath(): folder = os.environ["GISBASE"] else: # Find grass folder if it exists inside QGIS bundle - for version in ['', '8', '7', '80', '78', '76', '74', '72', - '71', '70']: - testfolder = os.path.join(str(QgsApplication.prefixPath()), - 'grass{}'.format(version)) + for version in ["", "8", "7", "80", "78", "76", "74", "72", "71", "70"]: + testfolder = os.path.join( + str(QgsApplication.prefixPath()), f"grass{version}" + ) if os.path.isdir(testfolder): folder = testfolder break # If nothing found, try standalone GRASS installation if folder is None: - for version in ['8', '6', '4', '2', '1', '0']: - testfolder = '/Applications/GRASS-7.{}.app/Contents/MacOS'.format( - version) + for version in ["8", "6", "4", "2", "1", "0"]: + testfolder = ( + "/Applications/GRASS-7.{}.app/Contents/MacOS".format( + version + ) + ) if os.path.isdir(testfolder): folder = testfolder break @@ -275,7 +284,7 @@ def grassPath(): if folder is not None: GrassUtils.path = folder - return folder or '' + return folder or "" @staticmethod def userDescriptionFolder(): @@ -283,7 +292,7 @@ def userDescriptionFolder(): Creates and returns a directory for users to create additional algorithm descriptions. Or modified versions of stock algorithm descriptions shipped with QGIS. """ - folder = Path(userFolder(), 'grassaddons', 'description') + folder = Path(userFolder(), "grassaddons", "description") folder.mkdir(parents=True, exist_ok=True) return folder @@ -294,8 +303,10 @@ def grassDescriptionFolders(): Note that the provider will load from these in sequence, so we put the userDescriptionFolder first to allow users to create modified versions of stock algorithms shipped with QGIS. """ - return [GrassUtils.userDescriptionFolder(), - Path(__file__).parent.joinpath('description')] + return [ + GrassUtils.userDescriptionFolder(), + Path(__file__).parent.joinpath("description"), + ] @staticmethod def getWindowsCodePage(): @@ -304,26 +315,26 @@ def getWindowsCodePage(): Used into GRASS exec script under MS-Windows. """ from ctypes import cdll + return str(cdll.kernel32.GetACP()) @staticmethod def createGrassBatchJobFileFromGrassCommands(commands): - with open(GrassUtils.grassBatchJobFilename(), 'w') as fout: + with open(GrassUtils.grassBatchJobFilename(), "w") as fout: if not isWindows(): - fout.write('#!/bin/sh\n') + fout.write("#!/bin/sh\n") else: - fout.write( - 'chcp {}>NUL\n'.format(GrassUtils.getWindowsCodePage())) + fout.write(f"chcp {GrassUtils.getWindowsCodePage()}>NUL\n") for command in commands: GrassUtils.writeCommand(fout, command) - fout.write('exit') + fout.write("exit") @staticmethod def grassMapsetFolder(): """ Creates and returns the GRASS temporary DB LOCATION directory. """ - folder = os.path.join(GrassUtils.grassDataFolder(), 'temp_location') + folder = os.path.join(GrassUtils.grassDataFolder(), "temp_location") mkdir(folder) return folder @@ -333,7 +344,8 @@ def grassDataFolder(): Creates and returns the GRASS temporary DB directory. """ tempfolder = os.path.normpath( - os.path.join(QgsProcessingUtils.tempFolder(), 'grassdata')) + os.path.join(QgsProcessingUtils.tempFolder(), "grassdata") + ) mkdir(tempfolder) return tempfolder @@ -348,45 +360,46 @@ def createTempMapset(): input image or vector """ folder = GrassUtils.grassMapsetFolder() - mkdir(os.path.join(folder, 'PERMANENT')) - mkdir(os.path.join(folder, 'PERMANENT', '.tmp')) - GrassUtils.writeGrassWindow( - os.path.join(folder, 'PERMANENT', 'DEFAULT_WIND')) - with open(os.path.join(folder, 'PERMANENT', 'MYNAME'), 'w') as outfile: + mkdir(os.path.join(folder, "PERMANENT")) + mkdir(os.path.join(folder, "PERMANENT", ".tmp")) + GrassUtils.writeGrassWindow(os.path.join(folder, "PERMANENT", "DEFAULT_WIND")) + with open(os.path.join(folder, "PERMANENT", "MYNAME"), "w") as outfile: outfile.write( - 'QGIS GRASS GIS interface: temporary data processing location.\n') + "QGIS GRASS GIS interface: temporary data processing location.\n" + ) - GrassUtils.writeGrassWindow(os.path.join(folder, 'PERMANENT', 'WIND')) - mkdir(os.path.join(folder, 'PERMANENT', 'sqlite')) - with open(os.path.join(folder, 'PERMANENT', 'VAR'), 'w') as outfile: - outfile.write('DB_DRIVER: sqlite\n') + GrassUtils.writeGrassWindow(os.path.join(folder, "PERMANENT", "WIND")) + mkdir(os.path.join(folder, "PERMANENT", "sqlite")) + with open(os.path.join(folder, "PERMANENT", "VAR"), "w") as outfile: + outfile.write("DB_DRIVER: sqlite\n") outfile.write( - 'DB_DATABASE: $GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db\n') + "DB_DATABASE: $GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db\n" + ) @staticmethod def writeGrassWindow(filename): """ Creates the GRASS Window file """ - with open(filename, 'w') as out: - out.write('proj: 0\n') - out.write('zone: 0\n') - out.write('north: 1\n') - out.write('south: 0\n') - out.write('east: 1\n') - out.write('west: 0\n') - out.write('cols: 1\n') - out.write('rows: 1\n') - out.write('e-w resol: 1\n') - out.write('n-s resol: 1\n') - out.write('top: 1\n') - out.write('bottom: 0\n') - out.write('cols3: 1\n') - out.write('rows3: 1\n') - out.write('depths: 1\n') - out.write('e-w resol3: 1\n') - out.write('n-s resol3: 1\n') - out.write('t-b resol: 1\n') + with open(filename, "w") as out: + out.write("proj: 0\n") + out.write("zone: 0\n") + out.write("north: 1\n") + out.write("south: 0\n") + out.write("east: 1\n") + out.write("west: 0\n") + out.write("cols: 1\n") + out.write("rows: 1\n") + out.write("e-w resol: 1\n") + out.write("n-s resol: 1\n") + out.write("top: 1\n") + out.write("bottom: 0\n") + out.write("cols3: 1\n") + out.write("rows3: 1\n") + out.write("depths: 1\n") + out.write("e-w resol3: 1\n") + out.write("n-s resol3: 1\n") + out.write("t-b resol: 1\n") @staticmethod def prepareGrassExecution(commands): @@ -398,21 +411,26 @@ def prepareGrassExecution(commands): GrassUtils.grassBin() env = os.environ.copy() - env['GRASS_MESSAGE_FORMAT'] = 'plain' - if 'GISBASE' in env: - del env['GISBASE'] + env["GRASS_MESSAGE_FORMAT"] = "plain" + if "GISBASE" in env: + del env["GISBASE"] GrassUtils.createGrassBatchJobFileFromGrassCommands(commands) - os.chmod(GrassUtils.grassBatchJobFilename(), - stat.S_IEXEC | stat.S_IREAD | stat.S_IWRITE) - command = [GrassUtils.command, - os.path.join(GrassUtils.grassMapsetFolder(), 'PERMANENT'), - '--exec', GrassUtils.grassBatchJobFilename()] + os.chmod( + GrassUtils.grassBatchJobFilename(), + stat.S_IEXEC | stat.S_IREAD | stat.S_IWRITE, + ) + command = [ + GrassUtils.command, + os.path.join(GrassUtils.grassMapsetFolder(), "PERMANENT"), + "--exec", + GrassUtils.grassBatchJobFilename(), + ] return command, env @staticmethod def executeGrass(commands, feedback, outputCommands=None): - loglines = [GrassUtils.tr('GRASS GIS execution console output')] + loglines = [GrassUtils.tr("GRASS GIS execution console output")] grassOutDone = False command, grassenv = GrassUtils.prepareGrassExecution(commands) # QgsMessageLog.logMessage('exec: {}'.format(command), 'DEBUG', Qgis.Info) @@ -423,10 +441,8 @@ def executeGrass(commands, feedback, outputCommands=None): si = subprocess.STARTUPINFO() si.dwFlags |= subprocess.STARTF_USESHOWWINDOW si.wShowWindow = subprocess.SW_HIDE - kw['startupinfo'] = si - if sys.version_info >= (3, 6): - kw['encoding'] = "cp{}".format( - GrassUtils.getWindowsCodePage()) + kw["startupinfo"] = si + kw["encoding"] = f"cp{GrassUtils.getWindowsCodePage()}" def readline_with_recover(stdout): """A method wrapping stdout.readline() with try-except recovering. @@ -440,7 +456,7 @@ def readline_with_recover(stdout): try: return stdout.readline() except UnicodeDecodeError: - return '' # replaced-text + return "" # replaced-text with subprocess.Popen( command, @@ -450,35 +466,45 @@ def readline_with_recover(stdout): stderr=subprocess.STDOUT, universal_newlines=True, env=grassenv, - **kw + **kw, ) as proc: - for line in iter(lambda: readline_with_recover(proc.stdout), ''): - if 'GRASS_INFO_PERCENT' in line: + for line in iter(lambda: readline_with_recover(proc.stdout), ""): + if "GRASS_INFO_PERCENT" in line: try: - feedback.setProgress( - int(line[len('GRASS_INFO_PERCENT') + 2:])) + feedback.setProgress(int(line[len("GRASS_INFO_PERCENT") + 2 :])) except Exception: pass else: - if 'r.out' in line or 'v.out' in line: + if "r.out" in line or "v.out" in line: grassOutDone = True loglines.append(line) - if any([l in line for l in ['WARNING', GrassUtils.tr('WARNING')]]): + if any([l in line for l in ["WARNING", GrassUtils.tr("WARNING")]]): feedback.pushWarning(line.strip()) - elif any([l in line for l in ['ERROR', GrassUtils.tr('ERROR')]]): + elif any([l in line for l in ["ERROR", GrassUtils.tr("ERROR")]]): feedback.reportError(line.strip()) - elif 'Segmentation fault' in line: + elif "Segmentation fault" in line: feedback.reportError(line.strip()) - feedback.reportError('\n' + GrassUtils.tr( - 'GRASS command crashed :( Try a different set of input parameters and consult the GRASS algorithm manual for more information.') + '\n') - if ProcessingConfig.getSetting( - GrassUtils.GRASS_USE_REXTERNAL): - feedback.reportError(GrassUtils.tr( - 'Suggest disabling the experimental "use r.external" option from the Processing GRASS Provider options.') + '\n') - if ProcessingConfig.getSetting( - GrassUtils.GRASS_USE_VEXTERNAL): - feedback.reportError(GrassUtils.tr( - 'Suggest disabling the experimental "use v.external" option from the Processing GRASS Provider options.') + '\n') + feedback.reportError( + "\n" + + GrassUtils.tr( + "GRASS command crashed :( Try a different set of input parameters and consult the GRASS algorithm manual for more information." + ) + + "\n" + ) + if ProcessingConfig.getSetting(GrassUtils.GRASS_USE_REXTERNAL): + feedback.reportError( + GrassUtils.tr( + 'Suggest disabling the experimental "use r.external" option from the Processing GRASS Provider options.' + ) + + "\n" + ) + if ProcessingConfig.getSetting(GrassUtils.GRASS_USE_VEXTERNAL): + feedback.reportError( + GrassUtils.tr( + 'Suggest disabling the experimental "use v.external" option from the Processing GRASS Provider options.' + ) + + "\n" + ) elif line.strip(): feedback.pushConsoleInfo(line.strip()) @@ -488,18 +514,15 @@ def readline_with_recover(stdout): # are usually the output ones. If that is the case runs the output # commands again. if not grassOutDone and outputCommands: - command, grassenv = GrassUtils.prepareGrassExecution( - outputCommands) + command, grassenv = GrassUtils.prepareGrassExecution(outputCommands) # For MS-Windows, we need to hide the console window. kw = {} if isWindows(): si = subprocess.STARTUPINFO() si.dwFlags |= subprocess.STARTF_USESHOWWINDOW si.wShowWindow = subprocess.SW_HIDE - kw['startupinfo'] = si - if sys.version_info >= (3, 6): - kw['encoding'] = "cp{}".format( - GrassUtils.getWindowsCodePage()) + kw["startupinfo"] = si + kw["encoding"] = f"cp{GrassUtils.getWindowsCodePage()}" with subprocess.Popen( command, shell=False, @@ -508,17 +531,17 @@ def readline_with_recover(stdout): stderr=subprocess.STDOUT, universal_newlines=True, env=grassenv, - **kw + **kw, ) as proc: - for line in iter(lambda: readline_with_recover(proc.stdout), - ''): - if 'GRASS_INFO_PERCENT' in line: + for line in iter(lambda: readline_with_recover(proc.stdout), ""): + if "GRASS_INFO_PERCENT" in line: try: - feedback.setProgress(int( - line[len('GRASS_INFO_PERCENT') + 2:])) + feedback.setProgress( + int(line[len("GRASS_INFO_PERCENT") + 2 :]) + ) except Exception: pass - if any(l in line for l in ['WARNING', 'ERROR']): + if any(l in line for l in ["WARNING", "ERROR"]): loglines.append(line.strip()) feedback.reportError(line.strip()) elif line.strip(): @@ -526,8 +549,9 @@ def readline_with_recover(stdout): feedback.pushConsoleInfo(line.strip()) if ProcessingConfig.getSetting(GrassUtils.GRASS_LOG_CONSOLE): - QgsMessageLog.logMessage('\n'.join(loglines), 'Processing', - Qgis.MessageLevel.Info) + QgsMessageLog.logMessage( + "\n".join(loglines), "Processing", Qgis.MessageLevel.Info + ) # GRASS session is used to hold the layers already exported or # produced in GRASS between multiple calls to GRASS algorithms. @@ -557,8 +581,8 @@ def getSessionLayers(): @staticmethod def addSessionLayers(exportedLayers): GrassUtils.sessionLayers = dict( - list(GrassUtils.sessionLayers.items()) + - list(exportedLayers.items())) + list(GrassUtils.sessionLayers.items()) + list(exportedLayers.items()) + ) @staticmethod def checkGrassIsInstalled(ignorePreviousState=False): @@ -570,14 +594,15 @@ def checkGrassIsInstalled(ignorePreviousState=False): if GrassUtils.installedVersion() is not None: # For Ms-Windows, we check GRASS binaries if isWindows(): - cmdpath = os.path.join(GrassUtils.path, 'bin', - 'r.out.gdal.exe') + cmdpath = os.path.join(GrassUtils.path, "bin", "r.out.gdal.exe") if not os.path.exists(cmdpath): return GrassUtils.tr( 'The GRASS GIS folder "{}" does not contain a valid set ' - 'of GRASS modules.\nPlease, check that GRASS is correctly ' - 'installed and available on your system.'.format( - os.path.join(GrassUtils.path, 'bin'))) + "of GRASS modules.\nPlease, check that GRASS is correctly " + "installed and available on your system.".format( + os.path.join(GrassUtils.path, "bin") + ) + ) GrassUtils.isGrassInstalled = True return # Return error messages @@ -586,35 +611,39 @@ def checkGrassIsInstalled(ignorePreviousState=False): if isWindows() or isMac(): if GrassUtils.path is None: return GrassUtils.tr( - 'Could not locate GRASS GIS folder. Please make ' - 'sure that GRASS GIS is correctly installed before ' - 'running GRASS algorithms.') + "Could not locate GRASS GIS folder. Please make " + "sure that GRASS GIS is correctly installed before " + "running GRASS algorithms." + ) if GrassUtils.command is None: return GrassUtils.tr( - 'GRASS GIS binary {} can\'t be found on this system from a shell. ' - 'Please install it or configure your PATH {} environment variable.'.format( - '(grass.bat)' if isWindows() else '(grass.sh)', - 'or OSGEO4W_ROOT' if isWindows() else '')) + "GRASS GIS binary {} can't be found on this system from a shell. " + "Please install it or configure your PATH {} environment variable.".format( + "(grass.bat)" if isWindows() else "(grass.sh)", + "or OSGEO4W_ROOT" if isWindows() else "", + ) + ) # GNU/Linux else: return GrassUtils.tr( - 'GRASS can\'t be found on this system from a shell. ' - 'Please install it or configure your PATH environment variable.') + "GRASS can't be found on this system from a shell. " + "Please install it or configure your PATH environment variable." + ) @staticmethod - def tr(string, context=''): - if context == '': - context = 'Grass7Utils' + def tr(string, context=""): + if context == "": + context = "Grass7Utils" return QCoreApplication.translate(context, string) @staticmethod def writeCommand(output, command): try: # Python 2 - output.write(command.encode('utf8') + '\n') + output.write(command.encode("utf8") + "\n") except TypeError: # Python 3 - output.write(command + '\n') + output.write(command + "\n") @staticmethod def grassHelpPath(): @@ -623,13 +652,15 @@ def grassHelpPath(): if not helpPath: if isWindows() or isMac(): if GrassUtils.path is not None: - localPath = os.path.join(GrassUtils.path, 'docs/html') + localPath = os.path.join(GrassUtils.path, "docs/html") if os.path.exists(localPath): helpPath = os.path.abspath(localPath) else: - searchPaths = ['/usr/share/doc/grass-doc/html', - '/opt/grass/docs/html', - '/usr/share/doc/grass/docs/html'] + searchPaths = [ + "/usr/share/doc/grass-doc/html", + "/opt/grass/docs/html", + "/usr/share/doc/grass/docs/html", + ] for path in searchPaths: if os.path.exists(path): helpPath = os.path.abspath(path) @@ -638,11 +669,11 @@ def grassHelpPath(): if helpPath: return helpPath elif GrassUtils.version: - version = GrassUtils.version.replace('.', '')[:2] - return 'https://grass.osgeo.org/grass{}/manuals/'.format(version) + version = GrassUtils.version.replace(".", "")[:2] + return f"https://grass.osgeo.org/grass{version}/manuals/" else: # GRASS not available! - return 'https://grass.osgeo.org/grass-stable/manuals/' + return "https://grass.osgeo.org/grass-stable/manuals/" @staticmethod def getSupportedOutputRasterExtensions(): @@ -660,11 +691,11 @@ def getRasterFormatFromFilename(filename): :return: The Gdal short format name for extension. """ ext = os.path.splitext(filename)[1].lower() - ext = ext.lstrip('.') + ext = ext.lstrip(".") if ext: supported = GdalUtils.getSupportedRasters() for name in list(supported.keys()): exts = supported[name] if ext in exts: return name - return 'GTiff' + return "GTiff" diff --git a/python/plugins/grassprovider/parsed_description.py b/python/plugins/grassprovider/parsed_description.py index 0b031936317e..675860eb0178 100644 --- a/python/plugins/grassprovider/parsed_description.py +++ b/python/plugins/grassprovider/parsed_description.py @@ -10,16 +10,9 @@ """ import re -from dataclasses import ( - dataclass, - field -) +from dataclasses import dataclass, field from pathlib import Path -from typing import ( - Optional, - List, - Dict -) +from typing import Optional, List, Dict @dataclass @@ -28,7 +21,7 @@ class ParsedDescription: Results of parsing a description file """ - GROUP_ID_REGEX = re.compile(r'^[^\s(]+') + GROUP_ID_REGEX = re.compile(r"^[^\s(]+") grass_command: Optional[str] = None short_description: Optional[str] = None @@ -39,28 +32,28 @@ class ParsedDescription: ext_path: Optional[str] = None - hardcoded_strings: List[str] = field(default_factory=list) - param_strings: List[str] = field(default_factory=list) + hardcoded_strings: list[str] = field(default_factory=list) + param_strings: list[str] = field(default_factory=list) - def as_dict(self) -> Dict: + def as_dict(self) -> dict: """ Returns a JSON serializable dictionary representing the parsed description """ return { - 'name': self.name, - 'display_name': self.display_name, - 'command': self.grass_command, - 'short_description': self.short_description, - 'group': self.group, - 'group_id': self.group_id, - 'ext_path': self.ext_path, - 'hardcoded_strings': self.hardcoded_strings, - 'parameters': self.param_strings + "name": self.name, + "display_name": self.display_name, + "command": self.grass_command, + "short_description": self.short_description, + "group": self.group, + "group_id": self.group_id, + "ext_path": self.ext_path, + "hardcoded_strings": self.hardcoded_strings, + "parameters": self.param_strings, } @staticmethod - def from_dict(description: Dict) -> 'ParsedDescription': + def from_dict(description: dict) -> "ParsedDescription": """ Parses a dictionary as a description and returns the result """ @@ -68,26 +61,26 @@ def from_dict(description: Dict) -> 'ParsedDescription': from qgis.PyQt.QtCore import QCoreApplication result = ParsedDescription() - result.name = description.get('name') - result.display_name = description.get('display_name') - result.grass_command = description.get('command') + result.name = description.get("name") + result.display_name = description.get("display_name") + result.grass_command = description.get("command") result.short_description = QCoreApplication.translate( - "GrassAlgorithm", - description.get('short_description') + "GrassAlgorithm", description.get("short_description") ) - result.group = QCoreApplication.translate("GrassAlgorithm", - description.get('group')) - result.group_id = description.get('group_id') - result.ext_path = description.get('ext_path') - result.hardcoded_strings = description.get('hardcoded_strings', []) - result.param_strings = description.get('parameters', []) + result.group = QCoreApplication.translate( + "GrassAlgorithm", description.get("group") + ) + result.group_id = description.get("group_id") + result.ext_path = description.get("ext_path") + result.hardcoded_strings = description.get("hardcoded_strings", []) + result.param_strings = description.get("parameters", []) return result @staticmethod def parse_description_file( - description_file: Path, - translate: bool = True) -> 'ParsedDescription': + description_file: Path, translate: bool = True + ) -> "ParsedDescription": """ Parses a description file and returns the result """ @@ -96,42 +89,44 @@ def parse_description_file( with description_file.open() as lines: # First line of the file is the Grass algorithm name - line = lines.readline().strip('\n').strip() + line = lines.readline().strip("\n").strip() result.grass_command = line # Second line if the algorithm name in Processing - line = lines.readline().strip('\n').strip() + line = lines.readline().strip("\n").strip() result.short_description = line if " - " not in line: result.name = result.grass_command else: - result.name = line[:line.find(' ')].lower() + result.name = line[: line.find(" ")].lower() if translate: from qgis.PyQt.QtCore import QCoreApplication + result.short_description = QCoreApplication.translate( - "GrassAlgorithm", line) + "GrassAlgorithm", line + ) else: result.short_description = line result.display_name = result.name # Read the grass group - line = lines.readline().strip('\n').strip() + line = lines.readline().strip("\n").strip() if translate: from qgis.PyQt.QtCore import QCoreApplication - result.group = QCoreApplication.translate("GrassAlgorithm", - line) + + result.group = QCoreApplication.translate("GrassAlgorithm", line) else: result.group = line - result.group_id = ParsedDescription.GROUP_ID_REGEX.search( - line).group(0).lower() + result.group_id = ( + ParsedDescription.GROUP_ID_REGEX.search(line).group(0).lower() + ) # Then you have parameters/output definition - line = lines.readline().strip('\n').strip() - while line != '': - line = line.strip('\n').strip() - if line.startswith('Hardcoded'): - result.hardcoded_strings.append( - line[len('Hardcoded|'):]) + line = lines.readline().strip("\n").strip() + while line != "": + line = line.strip("\n").strip() + if line.startswith("Hardcoded"): + result.hardcoded_strings.append(line[len("Hardcoded|") :]) result.param_strings.append(line) - line = lines.readline().strip('\n').strip() + line = lines.readline().strip("\n").strip() return result diff --git a/python/plugins/grassprovider/tests/AlgorithmsTestBase.py b/python/plugins/grassprovider/tests/AlgorithmsTestBase.py index 9076368fedf2..353b44384623 100644 --- a/python/plugins/grassprovider/tests/AlgorithmsTestBase.py +++ b/python/plugins/grassprovider/tests/AlgorithmsTestBase.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'January 2016' -__copyright__ = '(C) 2016, Matthias Kuhn' +__author__ = "Matthias Kuhn" +__date__ = "January 2016" +__copyright__ = "(C) 2016, Matthias Kuhn" import os @@ -34,20 +34,20 @@ from numpy import nan_to_num from copy import deepcopy -from qgis.core import (QgsVectorLayer, - QgsRasterLayer, - QgsCoordinateReferenceSystem, - QgsFeatureRequest, - QgsMapLayer, - QgsProject, - QgsApplication, - QgsProcessingContext, - QgsProcessingUtils, - QgsProcessingFeedback) -from qgis.analysis import (QgsNativeAlgorithms) -from qgis.testing import (_UnexpectedSuccess, - QgisTestCase, - start_app) +from qgis.core import ( + QgsVectorLayer, + QgsRasterLayer, + QgsCoordinateReferenceSystem, + QgsFeatureRequest, + QgsMapLayer, + QgsProject, + QgsApplication, + QgsProcessingContext, + QgsProcessingUtils, + QgsProcessingFeedback, +) +from qgis.analysis import QgsNativeAlgorithms +from qgis.testing import _UnexpectedSuccess, QgisTestCase, start_app from utilities import unitTestDataPath @@ -57,7 +57,7 @@ def processingTestDataPath(): - return os.path.join(os.path.dirname(__file__), 'testdata') + return os.path.join(os.path.dirname(__file__), "testdata") class AlgorithmsTest: @@ -66,13 +66,19 @@ def test_algorithms(self): """ This is the main test function. All others will be executed based on the definitions in testdata/algorithm_tests.yaml """ - with open(os.path.join(processingTestDataPath(), self.definition_file())) as stream: + with open( + os.path.join(processingTestDataPath(), self.definition_file()) + ) as stream: algorithm_tests = yaml.load(stream, Loader=yaml.SafeLoader) - if 'tests' in algorithm_tests and algorithm_tests['tests'] is not None: - for idx, algtest in enumerate(algorithm_tests['tests']): - print('About to start {} of {}: "{}"'.format(idx, len(algorithm_tests['tests']), algtest['name'])) - yield self.check_algorithm, algtest['name'], algtest + if "tests" in algorithm_tests and algorithm_tests["tests"] is not None: + for idx, algtest in enumerate(algorithm_tests["tests"]): + print( + 'About to start {} of {}: "{}"'.format( + idx, len(algorithm_tests["tests"]), algtest["name"] + ) + ) + yield self.check_algorithm, algtest["name"], algtest def check_algorithm(self, name, defs): """ @@ -83,25 +89,29 @@ def check_algorithm(self, name, defs): self.vector_layer_params = {} QgsProject.instance().clear() - if 'project' in defs: - full_project_path = os.path.join(processingTestDataPath(), defs['project']) + if "project" in defs: + full_project_path = os.path.join(processingTestDataPath(), defs["project"]) project_read_success = QgsProject.instance().read(full_project_path) - self.assertTrue(project_read_success, 'Failed to load project file: ' + defs['project']) - - if 'project_crs' in defs: - QgsProject.instance().setCrs(QgsCoordinateReferenceSystem(defs['project_crs'])) + self.assertTrue( + project_read_success, "Failed to load project file: " + defs["project"] + ) + + if "project_crs" in defs: + QgsProject.instance().setCrs( + QgsCoordinateReferenceSystem(defs["project_crs"]) + ) else: QgsProject.instance().setCrs(QgsCoordinateReferenceSystem()) - if 'ellipsoid' in defs: - QgsProject.instance().setEllipsoid(defs['ellipsoid']) + if "ellipsoid" in defs: + QgsProject.instance().setEllipsoid(defs["ellipsoid"]) else: - QgsProject.instance().setEllipsoid('') + QgsProject.instance().setEllipsoid("") - params = self.load_params(defs['params']) + params = self.load_params(defs["params"]) - print('Running alg: "{}"'.format(defs['algorithm'])) - alg = QgsApplication.processingRegistry().createAlgorithmById(defs['algorithm']) + print('Running alg: "{}"'.format(defs["algorithm"])) + alg = QgsApplication.processingRegistry().createAlgorithmById(defs["algorithm"]) parameters = {} if isinstance(params, list): @@ -111,45 +121,47 @@ def check_algorithm(self, name, defs): for k, p in params.items(): parameters[k] = p - for r, p in list(defs['results'].items()): - if 'in_place_result' not in p or not p['in_place_result']: + for r, p in list(defs["results"].items()): + if "in_place_result" not in p or not p["in_place_result"]: parameters[r] = self.load_result_param(p) expectFailure = False - if 'expectedFailure' in defs: - exec(('\n'.join(defs['expectedFailure'][:-1])), globals(), locals()) - expectFailure = eval(defs['expectedFailure'][-1]) + if "expectedFailure" in defs: + exec(("\n".join(defs["expectedFailure"][:-1])), globals(), locals()) + expectFailure = eval(defs["expectedFailure"][-1]) - if 'expectedException' in defs: + if "expectedException" in defs: expectFailure = True # ignore user setting for invalid geometry handling context = QgsProcessingContext() context.setProject(QgsProject.instance()) - if 'skipInvalid' in defs and defs['skipInvalid']: - context.setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid) + if "skipInvalid" in defs and defs["skipInvalid"]: + context.setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid + ) feedback = QgsProcessingFeedback() - print('Algorithm parameters are {}'.format(parameters)) + print(f"Algorithm parameters are {parameters}") # first check that algorithm accepts the parameters we pass... ok, msg = alg.checkParameterValues(parameters, context) - self.assertTrue(ok, 'Algorithm failed checkParameterValues with result {}'.format(msg)) + self.assertTrue(ok, f"Algorithm failed checkParameterValues with result {msg}") if expectFailure: try: results, ok = alg.run(parameters, context, feedback) - self.check_results(results, context, parameters, defs['results']) + self.check_results(results, context, parameters, defs["results"]) if ok: raise _UnexpectedSuccess except Exception: pass else: results, ok = alg.run(parameters, context, feedback) - self.assertTrue(ok, 'params: {}, results: {}'.format(parameters, results)) - self.check_results(results, context, parameters, defs['results']) + self.assertTrue(ok, f"params: {parameters}, results: {results}") + self.check_results(results, context, parameters, defs["results"]) def load_params(self, params): """ @@ -168,68 +180,75 @@ def load_param(self, param, id=None): parameter based on its key `type` and return the appropriate parameter to pass to the algorithm. """ try: - if param['type'] in ('vector', 'raster', 'table'): + if param["type"] in ("vector", "raster", "table"): return self.load_layer(id, param).id() - elif param['type'] == 'vrtlayers': + elif param["type"] == "vrtlayers": vals = [] - for p in param['params']: - p['layer'] = self.load_layer(None, {'type': 'vector', 'name': p['layer']}) + for p in param["params"]: + p["layer"] = self.load_layer( + None, {"type": "vector", "name": p["layer"]} + ) vals.append(p) return vals - elif param['type'] == 'multi': - return [self.load_param(p) for p in param['params']] - elif param['type'] == 'file': + elif param["type"] == "multi": + return [self.load_param(p) for p in param["params"]] + elif param["type"] == "file": return self.filepath_from_param(param) - elif param['type'] == 'interpolation': + elif param["type"] == "interpolation": prefix = processingTestDataPath() - tmp = '' - for r in param['name'].split('::|::'): - v = r.split('::~::') - tmp += '{}::~::{}::~::{}::~::{};'.format(os.path.join(prefix, v[0]), - v[1], v[2], v[3]) + tmp = "" + for r in param["name"].split("::|::"): + v = r.split("::~::") + tmp += "{}::~::{}::~::{}::~::{};".format( + os.path.join(prefix, v[0]), v[1], v[2], v[3] + ) return tmp[:-1] except TypeError: # No type specified, use whatever is there return param - raise KeyError("Unknown type '{}' specified for parameter".format(param['type'])) + raise KeyError( + "Unknown type '{}' specified for parameter".format(param["type"]) + ) def load_result_param(self, param): """ Loads a result parameter. Creates a temporary destination where the result should go to and returns this location so it can be sent to the algorithm as parameter. """ - if param['type'] in ['vector', 'file', 'table', 'regex']: + if param["type"] in ["vector", "file", "table", "regex"]: outdir = tempfile.mkdtemp() self.cleanup_paths.append(outdir) - if isinstance(param['name'], str): - basename = os.path.basename(param['name']) + if isinstance(param["name"], str): + basename = os.path.basename(param["name"]) else: - basename = os.path.basename(param['name'][0]) + basename = os.path.basename(param["name"][0]) filepath = self.uri_path_join(outdir, basename) return filepath - elif param['type'] == 'rasterhash': + elif param["type"] == "rasterhash": outdir = tempfile.mkdtemp() self.cleanup_paths.append(outdir) - basename = 'raster.tif' + basename = "raster.tif" filepath = os.path.join(outdir, basename) return filepath - elif param['type'] == 'directory': + elif param["type"] == "directory": outdir = tempfile.mkdtemp() return outdir - raise KeyError("Unknown type '{}' specified for parameter".format(param['type'])) + raise KeyError( + "Unknown type '{}' specified for parameter".format(param["type"]) + ) def load_layers(self, id, param): layers = [] - if param['type'] in ('vector', 'table'): - if isinstance(param['name'], str) or 'uri' in param: + if param["type"] in ("vector", "table"): + if isinstance(param["name"], str) or "uri" in param: layers.append(self.load_layer(id, param)) else: - for n in param['name']: + for n in param["name"]: layer_param = deepcopy(param) - layer_param['name'] = n + layer_param["name"] = n layers.append(self.load_layer(id, layer_param)) else: layers.append(self.load_layer(id, param)) @@ -242,37 +261,39 @@ def load_layer(self, id, param): filepath = self.filepath_from_param(param) - if 'in_place' in param and param['in_place']: + if "in_place" in param and param["in_place"]: # check if alg modifies layer in place tmpdir = tempfile.mkdtemp() self.cleanup_paths.append(tmpdir) path, file_name = os.path.split(filepath) base, ext = os.path.splitext(file_name) - for file in glob.glob(os.path.join(path, '{}.*'.format(base))): + for file in glob.glob(os.path.join(path, f"{base}.*")): shutil.copy(os.path.join(path, file), tmpdir) filepath = os.path.join(tmpdir, file_name) self.in_place_layers[id] = filepath - if param['type'] in ('vector', 'table'): - gmlrex = r'\.gml\b' + if param["type"] in ("vector", "table"): + gmlrex = r"\.gml\b" if re.search(gmlrex, filepath, re.IGNORECASE): # ewwwww - we have to force SRS detection for GML files, otherwise they'll be loaded # with no srs - filepath += '|option:FORCE_SRS_DETECTION=YES' + filepath += "|option:FORCE_SRS_DETECTION=YES" if filepath in self.vector_layer_params: return self.vector_layer_params[filepath] options = QgsVectorLayer.LayerOptions() options.loadDefaultStyle = False - lyr = QgsVectorLayer(filepath, param['name'], 'ogr', options) + lyr = QgsVectorLayer(filepath, param["name"], "ogr", options) self.vector_layer_params[filepath] = lyr - elif param['type'] == 'raster': + elif param["type"] == "raster": options = QgsRasterLayer.LayerOptions() options.loadDefaultStyle = False - lyr = QgsRasterLayer(filepath, param['name'], 'gdal', options) + lyr = QgsRasterLayer(filepath, param["name"], "gdal", options) - self.assertTrue(lyr.isValid(), 'Could not load layer "{}" from param {}'.format(filepath, param)) + self.assertTrue( + lyr.isValid(), f'Could not load layer "{filepath}" from param {param}' + ) QgsProject.instance().addMapLayer(lyr) return lyr @@ -281,13 +302,13 @@ def filepath_from_param(self, param): Creates a filepath from a param """ prefix = processingTestDataPath() - if 'location' in param and param['location'] == 'qgs': + if "location" in param and param["location"] == "qgs": prefix = unitTestDataPath() - if 'uri' in param: - path = param['uri'] + if "uri" in param: + path = param["uri"] else: - path = param['name'] + path = param["name"] if not path: return None @@ -295,10 +316,10 @@ def filepath_from_param(self, param): return self.uri_path_join(prefix, path) def uri_path_join(self, prefix, filepath): - if filepath.startswith('ogr:'): + if filepath.startswith("ogr:"): if not prefix[-1] == os.path.sep: prefix += os.path.sep - filepath = re.sub(r"dbname='", "dbname='{}".format(prefix), filepath) + filepath = re.sub(r"dbname='", f"dbname='{prefix}", filepath) else: filepath = os.path.join(prefix, filepath) @@ -309,88 +330,105 @@ def check_results(self, results, context, params, expected): Checks if result produced by an algorithm matches with the expected specification. """ for id, expected_result in expected.items(): - if expected_result['type'] in ('vector', 'table'): - if 'compare' in expected_result and not expected_result['compare']: + if expected_result["type"] in ("vector", "table"): + if "compare" in expected_result and not expected_result["compare"]: # skipping the comparison, so just make sure output is valid if isinstance(results[id], QgsMapLayer): result_lyr = results[id] else: - result_lyr = QgsProcessingUtils.mapLayerFromString(results[id], context) + result_lyr = QgsProcessingUtils.mapLayerFromString( + results[id], context + ) self.assertTrue(result_lyr.isValid()) continue expected_lyrs = self.load_layers(id, expected_result) - if 'in_place_result' in expected_result: - result_lyr = QgsProcessingUtils.mapLayerFromString(self.in_place_layers[id], context) + if "in_place_result" in expected_result: + result_lyr = QgsProcessingUtils.mapLayerFromString( + self.in_place_layers[id], context + ) self.assertTrue(result_lyr.isValid(), self.in_place_layers[id]) else: try: results[id] except KeyError as e: - raise KeyError('Expected result {} does not exist in {}'.format(str(e), list(results.keys()))) + raise KeyError( + f"Expected result {str(e)} does not exist in {list(results.keys())}" + ) if isinstance(results[id], QgsMapLayer): result_lyr = results[id] else: string = results[id] - gmlrex = r'\.gml\b' + gmlrex = r"\.gml\b" if re.search(gmlrex, string, re.IGNORECASE): # ewwwww - we have to force SRS detection for GML files, otherwise they'll be loaded # with no srs - string += '|option:FORCE_SRS_DETECTION=YES' + string += "|option:FORCE_SRS_DETECTION=YES" - result_lyr = QgsProcessingUtils.mapLayerFromString(string, context) + result_lyr = QgsProcessingUtils.mapLayerFromString( + string, context + ) self.assertTrue(result_lyr, results[id]) - compare = expected_result.get('compare', {}) - pk = expected_result.get('pk', None) + compare = expected_result.get("compare", {}) + pk = expected_result.get("pk", None) if len(expected_lyrs) == 1: - self.assertLayersEqual(expected_lyrs[0], result_lyr, compare=compare, pk=pk) + self.assertLayersEqual( + expected_lyrs[0], result_lyr, compare=compare, pk=pk + ) else: res = False for l in expected_lyrs: if self.checkLayersEqual(l, result_lyr, compare=compare, pk=pk): res = True break - self.assertTrue(res, 'Could not find matching layer in expected results') - - elif 'rasterhash' == expected_result['type']: - print("id:{} result:{}".format(id, results[id])) - self.assertTrue(os.path.exists(results[id]), 'File does not exist: {}, {}'.format(results[id], params)) + self.assertTrue( + res, "Could not find matching layer in expected results" + ) + + elif "rasterhash" == expected_result["type"]: + print(f"id:{id} result:{results[id]}") + self.assertTrue( + os.path.exists(results[id]), + f"File does not exist: {results[id]}, {params}", + ) dataset = gdal.Open(results[id], GA_ReadOnly) dataArray = nan_to_num(dataset.ReadAsArray(0)) strhash = hashlib.sha224(dataArray.data).hexdigest() - if not isinstance(expected_result['hash'], str): - self.assertIn(strhash, expected_result['hash']) + if not isinstance(expected_result["hash"], str): + self.assertIn(strhash, expected_result["hash"]) else: - self.assertEqual(strhash, expected_result['hash']) - elif 'file' == expected_result['type']: + self.assertEqual(strhash, expected_result["hash"]) + elif "file" == expected_result["type"]: result_filepath = results[id] - if isinstance(expected_result.get('name'), list): + if isinstance(expected_result.get("name"), list): # test to see if any match expected - for path in expected_result['name']: - expected_filepath = self.filepath_from_param({'name': path}) + for path in expected_result["name"]: + expected_filepath = self.filepath_from_param({"name": path}) if self.checkFilesEqual(expected_filepath, result_filepath): break else: - expected_filepath = self.filepath_from_param({'name': expected_result['name'][0]}) + expected_filepath = self.filepath_from_param( + {"name": expected_result["name"][0]} + ) else: expected_filepath = self.filepath_from_param(expected_result) self.assertFilesEqual(expected_filepath, result_filepath) - elif 'directory' == expected_result['type']: + elif "directory" == expected_result["type"]: expected_dirpath = self.filepath_from_param(expected_result) result_dirpath = results[id] self.assertDirectoriesEqual(expected_dirpath, result_dirpath) - elif 'regex' == expected_result['type']: + elif "regex" == expected_result["type"]: with open(results[id]) as file: data = file.read() - for rule in expected_result.get('rules', []): + for rule in expected_result.get("rules", []): self.assertRegex(data, rule) @@ -411,9 +449,9 @@ def tearDownClass(cls): def testAlgorithmCompliance(self): for p in QgsApplication.processingRegistry().providers(): - print('testing provider {}'.format(p.id())) + print(f"testing provider {p.id()}") for a in p.algorithms(): - print('testing algorithm {}'.format(a.id())) + print(f"testing algorithm {a.id()}") self.check_algorithm(a) def check_algorithm(self, alg): @@ -421,5 +459,5 @@ def check_algorithm(self, alg): alg.helpUrl() -if __name__ == '__main__': +if __name__ == "__main__": nose2.main() diff --git a/python/plugins/grassprovider/tests/grass_algorithms_imagery_test.py b/python/plugins/grassprovider/tests/grass_algorithms_imagery_test.py index 7e2baa9b6914..84bd78e4e510 100644 --- a/python/plugins/grassprovider/tests/grass_algorithms_imagery_test.py +++ b/python/plugins/grassprovider/tests/grass_algorithms_imagery_test.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'May 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "May 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" import AlgorithmsTestBase @@ -25,10 +25,7 @@ import shutil from qgis.core import QgsApplication -from qgis.testing import ( - QgisTestCase, - start_app -) +from qgis.testing import QgisTestCase, start_app from grassprovider.grass_provider import GrassProvider from grassprovider.grass_utils import GrassUtils @@ -51,8 +48,8 @@ def tearDownClass(cls): shutil.rmtree(path) def definition_file(self): - return 'grass_algorithms_imagery_tests.yaml' + return "grass_algorithms_imagery_tests.yaml" -if __name__ == '__main__': +if __name__ == "__main__": nose2.main() diff --git a/python/plugins/grassprovider/tests/grass_algorithms_raster_test_pt1.py b/python/plugins/grassprovider/tests/grass_algorithms_raster_test_pt1.py index b26a79ef9522..36ef165d006f 100644 --- a/python/plugins/grassprovider/tests/grass_algorithms_raster_test_pt1.py +++ b/python/plugins/grassprovider/tests/grass_algorithms_raster_test_pt1.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'May 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "May 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" import AlgorithmsTestBase @@ -25,11 +25,7 @@ import shutil from qgis.core import QgsApplication -from qgis.testing import ( - QgisTestCase, - start_app - -) +from qgis.testing import QgisTestCase, start_app from grassprovider.grass_provider import GrassProvider from grassprovider.grass_utils import GrassUtils @@ -52,8 +48,8 @@ def tearDownClass(cls): shutil.rmtree(path) def definition_file(self): - return 'grass_algorithms_raster_tests1.yaml' + return "grass_algorithms_raster_tests1.yaml" -if __name__ == '__main__': +if __name__ == "__main__": nose2.main() diff --git a/python/plugins/grassprovider/tests/grass_algorithms_raster_test_pt2.py b/python/plugins/grassprovider/tests/grass_algorithms_raster_test_pt2.py index 9870ba662f2e..bd75ff27849e 100644 --- a/python/plugins/grassprovider/tests/grass_algorithms_raster_test_pt2.py +++ b/python/plugins/grassprovider/tests/grass_algorithms_raster_test_pt2.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'May 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' +__author__ = "Médéric Ribreux" +__date__ = "May 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" import AlgorithmsTestBase @@ -26,20 +26,13 @@ import os import tempfile -from qgis.core import ( - QgsApplication, - QgsProcessingContext, - QgsProcessingFeedback -) -from qgis.testing import ( - QgisTestCase, - start_app -) +from qgis.core import QgsApplication, QgsProcessingContext, QgsProcessingFeedback +from qgis.testing import QgisTestCase, start_app from grassprovider.grass_provider import GrassProvider from grassprovider.grass_utils import GrassUtils -testDataPath = os.path.join(os.path.dirname(__file__), 'testdata') +testDataPath = os.path.join(os.path.dirname(__file__), "testdata") class TestGrassAlgorithmsRasterTest(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest): @@ -63,36 +56,42 @@ def tearDownClass(cls): shutil.rmtree(path) def definition_file(self): - return 'grass_algorithms_raster_tests2.yaml' + return "grass_algorithms_raster_tests2.yaml" def testNeighbors(self): context = QgsProcessingContext() - input_raster = os.path.join(testDataPath, 'custom', 'grass7', 'float_raster.tif') + input_raster = os.path.join( + testDataPath, "custom", "grass7", "float_raster.tif" + ) - alg = QgsApplication.processingRegistry().createAlgorithmById('grass:r.neighbors') + alg = QgsApplication.processingRegistry().createAlgorithmById( + "grass:r.neighbors" + ) self.assertIsNotNone(alg) - temp_file = os.path.join(self.temp_dir, 'grass_output.tif') + temp_file = os.path.join(self.temp_dir, "grass_output.tif") # Test an even integer for neighborhood size - parameters = {'input': input_raster, - 'selection': None, - 'method': 0, - 'size': 4, - 'gauss': None, - 'quantile': '', - '-c': False, - '-a': False, - 'weight': '', - 'output': temp_file, - 'GRASS_REGION_PARAMETER': None, - 'GRASS_REGION_CELLSIZE_PARAMETER': 0, - 'GRASS_RASTER_FORMAT_OPT': '', - 'GRASS_RASTER_FORMAT_META': ''} + parameters = { + "input": input_raster, + "selection": None, + "method": 0, + "size": 4, + "gauss": None, + "quantile": "", + "-c": False, + "-a": False, + "weight": "", + "output": temp_file, + "GRASS_REGION_PARAMETER": None, + "GRASS_REGION_CELLSIZE_PARAMETER": 0, + "GRASS_RASTER_FORMAT_OPT": "", + "GRASS_RASTER_FORMAT_META": "", + } ok, msg = alg.checkParameterValues(parameters, context) self.assertFalse(ok) -if __name__ == '__main__': +if __name__ == "__main__": nose2.main() diff --git a/python/plugins/grassprovider/tests/grass_algorithms_vector_test.py b/python/plugins/grassprovider/tests/grass_algorithms_vector_test.py index d324df1e89eb..dd660f412542 100644 --- a/python/plugins/grassprovider/tests/grass_algorithms_vector_test.py +++ b/python/plugins/grassprovider/tests/grass_algorithms_vector_test.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'March 2018' -__copyright__ = '(C) 2018, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "March 2018" +__copyright__ = "(C) 2018, Nyall Dawson" import AlgorithmsTestBase @@ -27,24 +27,23 @@ import tempfile import re -from qgis.core import (QgsVectorLayer, - QgsApplication, - QgsFeature, - QgsGeometry, - QgsPointXY, - QgsProcessingContext, - QgsProject, - QgsProcessingFeedback, - QgsProcessingFeatureSourceDefinition) -from qgis.testing import ( - QgisTestCase, - start_app +from qgis.core import ( + QgsVectorLayer, + QgsApplication, + QgsFeature, + QgsGeometry, + QgsPointXY, + QgsProcessingContext, + QgsProject, + QgsProcessingFeedback, + QgsProcessingFeatureSourceDefinition, ) +from qgis.testing import QgisTestCase, start_app from grassprovider.grass_provider import GrassProvider from grassprovider.grass_utils import GrassUtils -testDataPath = os.path.join(os.path.dirname(__file__), 'testdata') +testDataPath = os.path.join(os.path.dirname(__file__), "testdata") class TestGrassAlgorithmsVectorTest(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest): @@ -68,12 +67,15 @@ def tearDownClass(cls): shutil.rmtree(path) def definition_file(self): - return 'grass_algorithms_vector_tests.yaml' + return "grass_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") + layer = QgsVectorLayer( + "Point?crs=epsg:3857&field=fldtxt:string&field=fldint:integer", + "testmem", + "memory", + ) self.assertTrue(layer.isValid()) pr = layer.dataProvider() f = QgsFeature() @@ -88,30 +90,32 @@ def testMemoryLayerInput(self): context = QgsProcessingContext() context.setProject(QgsProject.instance()) - alg = QgsApplication.processingRegistry().createAlgorithmById('grass:v.buffer') + alg = QgsApplication.processingRegistry().createAlgorithmById("grass:v.buffer") self.assertIsNotNone(alg) - temp_file = os.path.join(self.temp_dir, 'grass_output.shp') - parameters = {'input': 'testmem', - 'cats': '', - 'where': '', - 'type': [0, 1, 4], - 'distance': 1, - 'minordistance': None, - 'angle': 0, - 'column': None, - 'scale': 1, - 'tolerance': 0.01, - '-s': False, - '-c': False, - '-t': False, - 'output': temp_file, - 'GRASS_REGION_PARAMETER': None, - 'GRASS_SNAP_TOLERANCE_PARAMETER': -1, - 'GRASS_MIN_AREA_PARAMETER': 0.0001, - 'GRASS_OUTPUT_TYPE_PARAMETER': 0, - 'GRASS_VECTOR_DSCO': '', - 'GRASS_VECTOR_LCO': ''} + temp_file = os.path.join(self.temp_dir, "grass_output.shp") + parameters = { + "input": "testmem", + "cats": "", + "where": "", + "type": [0, 1, 4], + "distance": 1, + "minordistance": None, + "angle": 0, + "column": None, + "scale": 1, + "tolerance": 0.01, + "-s": False, + "-c": False, + "-t": False, + "output": temp_file, + "GRASS_REGION_PARAMETER": None, + "GRASS_SNAP_TOLERANCE_PARAMETER": -1, + "GRASS_MIN_AREA_PARAMETER": 0.0001, + "GRASS_OUTPUT_TYPE_PARAMETER": 0, + "GRASS_VECTOR_DSCO": "", + "GRASS_VECTOR_LCO": "", + } feedback = QgsProcessingFeedback() results, ok = alg.run(parameters, context, feedback) @@ -119,7 +123,7 @@ def testMemoryLayerInput(self): self.assertTrue(os.path.exists(temp_file)) # make sure that layer has correct features - res = QgsVectorLayer(temp_file, 'res') + res = QgsVectorLayer(temp_file, "res") self.assertTrue(res.isValid()) self.assertEqual(res.featureCount(), 2) @@ -127,8 +131,11 @@ def testMemoryLayerInput(self): 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") + layer = QgsVectorLayer( + "Point?crs=epsg:3857&field=fldtxt:string&field=fldint:integer", + "testmem", + "memory", + ) self.assertTrue(layer.isValid()) pr = layer.dataProvider() f = QgsFeature() @@ -148,29 +155,31 @@ def testFeatureSourceInput(self): context = QgsProcessingContext() context.setProject(QgsProject.instance()) - alg = QgsApplication.processingRegistry().createAlgorithmById('grass:v.buffer') + alg = QgsApplication.processingRegistry().createAlgorithmById("grass:v.buffer") self.assertIsNotNone(alg) - temp_file = os.path.join(self.temp_dir, 'grass_output_sel.shp') - parameters = {'input': QgsProcessingFeatureSourceDefinition('testmem', True), - 'cats': '', - 'where': '', - 'type': [0, 1, 4], - 'distance': 1, - 'minordistance': None, - 'angle': 0, - 'column': None, - 'scale': 1, - 'tolerance': 0.01, - '-s': False, - '-c': False, - '-t': False, - 'output': temp_file, - 'GRASS_REGION_PARAMETER': None, - 'GRASS_SNAP_TOLERANCE_PARAMETER': -1, - 'GRASS_MIN_AREA_PARAMETER': 0.0001, - 'GRASS_OUTPUT_TYPE_PARAMETER': 0, - 'GRASS_VECTOR_DSCO': '', - 'GRASS_VECTOR_LCO': ''} + temp_file = os.path.join(self.temp_dir, "grass_output_sel.shp") + parameters = { + "input": QgsProcessingFeatureSourceDefinition("testmem", True), + "cats": "", + "where": "", + "type": [0, 1, 4], + "distance": 1, + "minordistance": None, + "angle": 0, + "column": None, + "scale": 1, + "tolerance": 0.01, + "-s": False, + "-c": False, + "-t": False, + "output": temp_file, + "GRASS_REGION_PARAMETER": None, + "GRASS_SNAP_TOLERANCE_PARAMETER": -1, + "GRASS_MIN_AREA_PARAMETER": 0.0001, + "GRASS_OUTPUT_TYPE_PARAMETER": 0, + "GRASS_VECTOR_DSCO": "", + "GRASS_VECTOR_LCO": "", + } feedback = QgsProcessingFeedback() results, ok = alg.run(parameters, context, feedback) @@ -178,7 +187,7 @@ def testFeatureSourceInput(self): self.assertTrue(os.path.exists(temp_file)) # make sure that layer has correct features - res = QgsVectorLayer(temp_file, 'res') + res = QgsVectorLayer(temp_file, "res") self.assertTrue(res.isValid()) self.assertEqual(res.featureCount(), 1) @@ -186,8 +195,11 @@ def testFeatureSourceInput(self): def testOutputToGeopackage(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") + layer = QgsVectorLayer( + "Point?crs=epsg:3857&field=fldtxt:string&field=fldint:integer", + "testmem", + "memory", + ) self.assertTrue(layer.isValid()) pr = layer.dataProvider() f = QgsFeature() @@ -202,30 +214,32 @@ def testOutputToGeopackage(self): context = QgsProcessingContext() context.setProject(QgsProject.instance()) - alg = QgsApplication.processingRegistry().createAlgorithmById('grass:v.buffer') + alg = QgsApplication.processingRegistry().createAlgorithmById("grass:v.buffer") self.assertIsNotNone(alg) - temp_file = os.path.join(self.temp_dir, 'grass_output.gpkg') - parameters = {'input': 'testmem', - 'cats': '', - 'where': '', - 'type': [0, 1, 4], - 'distance': 1, - 'minordistance': None, - 'angle': 0, - 'column': None, - 'scale': 1, - 'tolerance': 0.01, - '-s': False, - '-c': False, - '-t': False, - 'output': temp_file, - 'GRASS_REGION_PARAMETER': None, - 'GRASS_SNAP_TOLERANCE_PARAMETER': -1, - 'GRASS_MIN_AREA_PARAMETER': 0.0001, - 'GRASS_OUTPUT_TYPE_PARAMETER': 0, - 'GRASS_VECTOR_DSCO': '', - 'GRASS_VECTOR_LCO': ''} + temp_file = os.path.join(self.temp_dir, "grass_output.gpkg") + parameters = { + "input": "testmem", + "cats": "", + "where": "", + "type": [0, 1, 4], + "distance": 1, + "minordistance": None, + "angle": 0, + "column": None, + "scale": 1, + "tolerance": 0.01, + "-s": False, + "-c": False, + "-t": False, + "output": temp_file, + "GRASS_REGION_PARAMETER": None, + "GRASS_SNAP_TOLERANCE_PARAMETER": -1, + "GRASS_MIN_AREA_PARAMETER": 0.0001, + "GRASS_OUTPUT_TYPE_PARAMETER": 0, + "GRASS_VECTOR_DSCO": "", + "GRASS_VECTOR_LCO": "", + } feedback = QgsProcessingFeedback() results, ok = alg.run(parameters, context, feedback) @@ -233,7 +247,7 @@ def testOutputToGeopackage(self): self.assertTrue(os.path.exists(temp_file)) # make sure that layer has correct features - res = QgsVectorLayer(temp_file, 'res') + res = QgsVectorLayer(temp_file, "res") self.assertTrue(res.isValid()) self.assertEqual(res.featureCount(), 2) @@ -241,73 +255,109 @@ def testOutputToGeopackage(self): def testVectorLayerInput(self): context = QgsProcessingContext() - alg = QgsApplication.processingRegistry().createAlgorithmById('grass7:v.buffer') + alg = QgsApplication.processingRegistry().createAlgorithmById("grass7:v.buffer") self.assertIsNotNone(alg) self.assertFalse(alg.commands) def get_command(alg): command = alg.commands[-1] command = re.sub(r'output=".*?"', 'output="###"', command) - command = command.replace(testDataPath, 'testdata') + command = command.replace(testDataPath, "testdata") return command # GML source - source = os.path.join(testDataPath, 'points.gml') + source = os.path.join(testDataPath, "points.gml") vl = QgsVectorLayer(source) self.assertTrue(vl.isValid()) - alg.loadVectorLayer('test_layer', vl, context, external=False) - self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/points.gml" output="###" --overwrite -o') + alg.loadVectorLayer("test_layer", vl, context, external=False) + self.assertEqual( + get_command(alg), + 'v.in.ogr min_area=None snap=None input="testdata/points.gml" output="###" --overwrite -o', + ) # try with external -- not support for GML, so should fall back to v.in.ogr - alg.loadVectorLayer('test_layer', vl, context, external=True) - self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/points.gml" output="###" --overwrite -o') + alg.loadVectorLayer("test_layer", vl, context, external=True) + self.assertEqual( + get_command(alg), + 'v.in.ogr min_area=None snap=None input="testdata/points.gml" output="###" --overwrite -o', + ) # SHP source - source = os.path.join(testDataPath, 'lines_z.shp') + source = os.path.join(testDataPath, "lines_z.shp") vl = QgsVectorLayer(source) self.assertTrue(vl.isValid()) - alg.loadVectorLayer('test_layer', vl, context, external=False) - self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/lines_z.shp" output="###" --overwrite -o') + alg.loadVectorLayer("test_layer", vl, context, external=False) + self.assertEqual( + get_command(alg), + 'v.in.ogr min_area=None snap=None input="testdata/lines_z.shp" output="###" --overwrite -o', + ) # try with external -- should work for shapefile - alg.loadVectorLayer('test_layer', vl, context, external=True) - self.assertEqual(get_command(alg), 'v.external input="testdata/lines_z.shp" output="###" --overwrite -o') + alg.loadVectorLayer("test_layer", vl, context, external=True) + self.assertEqual( + get_command(alg), + 'v.external input="testdata/lines_z.shp" output="###" --overwrite -o', + ) # GPKG source - source = os.path.join(testDataPath, 'pol.gpkg') - vl = QgsVectorLayer(source + '|layername=pol2') + source = os.path.join(testDataPath, "pol.gpkg") + vl = QgsVectorLayer(source + "|layername=pol2") self.assertTrue(vl.isValid()) - alg.loadVectorLayer('test_layer', vl, context, external=False) - self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/pol.gpkg" layer="pol2" output="###" --overwrite -o') + alg.loadVectorLayer("test_layer", vl, context, external=False) + self.assertEqual( + get_command(alg), + 'v.in.ogr min_area=None snap=None input="testdata/pol.gpkg" layer="pol2" output="###" --overwrite -o', + ) # try with external -- should work for Geopackage (although grass itself tends to crash here!) - alg.loadVectorLayer('test_layer', vl, context, external=True) - self.assertEqual(get_command(alg), 'v.external input="testdata/pol.gpkg" layer="pol2" output="###" --overwrite -o') + alg.loadVectorLayer("test_layer", vl, context, external=True) + self.assertEqual( + get_command(alg), + 'v.external input="testdata/pol.gpkg" layer="pol2" output="###" --overwrite -o', + ) # different layer - source = os.path.join(testDataPath, 'pol.gpkg') - vl = QgsVectorLayer(source + '|layername=pol3') + source = os.path.join(testDataPath, "pol.gpkg") + vl = QgsVectorLayer(source + "|layername=pol3") self.assertTrue(vl.isValid()) - alg.loadVectorLayer('test_layer', vl, context, external=False) - self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/pol.gpkg" layer="pol3" output="###" --overwrite -o') - alg.loadVectorLayer('test_layer', vl, context, external=True) - self.assertEqual(get_command(alg), 'v.external input="testdata/pol.gpkg" layer="pol3" output="###" --overwrite -o') + alg.loadVectorLayer("test_layer", vl, context, external=False) + self.assertEqual( + get_command(alg), + 'v.in.ogr min_area=None snap=None input="testdata/pol.gpkg" layer="pol3" output="###" --overwrite -o', + ) + alg.loadVectorLayer("test_layer", vl, context, external=True) + self.assertEqual( + get_command(alg), + 'v.external input="testdata/pol.gpkg" layer="pol3" output="###" --overwrite -o', + ) # GPKG no layer: you get what you get and you don't get upset - source = os.path.join(testDataPath, 'pol.gpkg') + source = os.path.join(testDataPath, "pol.gpkg") vl = QgsVectorLayer(source) self.assertTrue(vl.isValid()) - alg.loadVectorLayer('test_layer', vl, context, external=False) - self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/pol.gpkg" output="###" --overwrite -o') - alg.loadVectorLayer('test_layer', vl, context, external=True) - self.assertEqual(get_command(alg), 'v.external input="testdata/pol.gpkg" output="###" --overwrite -o') + alg.loadVectorLayer("test_layer", vl, context, external=False) + self.assertEqual( + get_command(alg), + 'v.in.ogr min_area=None snap=None input="testdata/pol.gpkg" output="###" --overwrite -o', + ) + alg.loadVectorLayer("test_layer", vl, context, external=True) + self.assertEqual( + get_command(alg), + 'v.external input="testdata/pol.gpkg" output="###" --overwrite -o', + ) # layer with filter - vl = QgsVectorLayer(source + '|layername=pol3') + vl = QgsVectorLayer(source + "|layername=pol3") self.assertTrue(vl.isValid()) - vl.setSubsetString('"field"=\'value\'') - alg.loadVectorLayer('test_layer', vl, context, external=False) - self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/pol.gpkg" layer="pol3" output="###" --overwrite -o where="\\"field\\"=\'value\'"') - alg.loadVectorLayer('test_layer', vl, context, external=True) - self.assertEqual(get_command(alg), 'v.external input="testdata/pol.gpkg" layer="pol3" output="###" --overwrite -o where="\\"field\\"=\'value\'"') - - -if __name__ == '__main__': + vl.setSubsetString("\"field\"='value'") + alg.loadVectorLayer("test_layer", vl, context, external=False) + self.assertEqual( + get_command(alg), + 'v.in.ogr min_area=None snap=None input="testdata/pol.gpkg" layer="pol3" output="###" --overwrite -o where="\\"field\\"=\'value\'"', + ) + alg.loadVectorLayer("test_layer", vl, context, external=True) + self.assertEqual( + get_command(alg), + 'v.external input="testdata/pol.gpkg" layer="pol3" output="###" --overwrite -o where="\\"field\\"=\'value\'"', + ) + + +if __name__ == "__main__": nose2.main() diff --git a/python/plugins/processing/ProcessingPlugin.py b/python/plugins/processing/ProcessingPlugin.py index 0b3452b638d9..07a743785087 100644 --- a/python/plugins/processing/ProcessingPlugin.py +++ b/python/plugins/processing/ProcessingPlugin.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import shutil import os @@ -25,20 +25,24 @@ from typing import List from functools import partial -from qgis.core import (QgsApplication, - QgsProcessingUtils, - QgsProcessingModelAlgorithm, - QgsProcessingAlgorithm, - QgsDataItemProvider, - QgsDataProvider, - QgsDataItem, - QgsMapLayerType, - QgsMimeDataUtils, - QgsSettings) -from qgis.gui import (QgsGui, - QgsOptionsWidgetFactory, - QgsCustomDropHandler, - QgsProcessingHistoryDialog) +from qgis.core import ( + QgsApplication, + QgsProcessingUtils, + QgsProcessingModelAlgorithm, + QgsProcessingAlgorithm, + QgsDataItemProvider, + QgsDataProvider, + QgsDataItem, + QgsMapLayerType, + QgsMimeDataUtils, + QgsSettings, +) +from qgis.gui import ( + QgsGui, + QgsOptionsWidgetFactory, + QgsCustomDropHandler, + QgsProcessingHistoryDialog, +) from qgis.PyQt.QtCore import ( QObject, Qt, @@ -47,17 +51,10 @@ QDir, QFileInfo, pyqtSlot, - QMetaObject -) -from qgis.PyQt.QtWidgets import ( - QWidget, - QMenu, - QAction -) -from qgis.PyQt.QtGui import ( - QIcon, - QKeySequence + QMetaObject, ) +from qgis.PyQt.QtWidgets import QWidget, QMenu, QAction +from qgis.PyQt.QtGui import QIcon, QKeySequence from qgis.utils import iface from processing.core.Processing import Processing @@ -66,8 +63,10 @@ from processing.gui.ResultsDock import ResultsDock from processing.gui.MessageDialog import MessageDialog from processing.gui.MessageBarProgress import MessageBarProgress -from processing.gui.AlgorithmLocatorFilter import (AlgorithmLocatorFilter, - InPlaceAlgorithmLocatorFilter) +from processing.gui.AlgorithmLocatorFilter import ( + AlgorithmLocatorFilter, + InPlaceAlgorithmLocatorFilter, +) from processing.gui.Postprocessing import handleAlgorithmResults from processing.gui.AlgorithmExecutor import execute, execute_in_place from processing.gui.AlgorithmDialog import AlgorithmDialog @@ -76,7 +75,13 @@ from processing.modeler.ModelerDialog import ModelerDialog from processing.tools.system import tempHelpFolder from processing.tools import dataobjects -from processing.gui.menus import removeMenus, initializeMenus, createMenus, createButtons, removeButtons +from processing.gui.menus import ( + removeMenus, + initializeMenus, + createMenus, + createButtons, + removeButtons, +) from processing.core.ProcessingResults import resultsList pluginPath = os.path.dirname(__file__) @@ -88,7 +93,7 @@ def __init__(self): super(QgsOptionsWidgetFactory, self).__init__() def icon(self): - return QgsApplication.getThemeIcon('/processingAlgorithm.svg') + return QgsApplication.getThemeIcon("/processingAlgorithm.svg") def createWidget(self, parent): return ConfigOptionsPage(parent) @@ -97,7 +102,7 @@ def createWidget(self, parent): class ProcessingDropHandler(QgsCustomDropHandler): def handleFileDrop(self, file): - if not file.lower().endswith('.model3'): + if not file.lower().endswith(".model3"): return False return self.runAlg(file) @@ -107,7 +112,7 @@ def runAlg(file): if not alg.fromFile(file): return False - alg.setProvider(QgsApplication.processingRegistry().providerById('model')) + alg.setProvider(QgsApplication.processingRegistry().providerById("model")) dlg = AlgorithmDialog(alg, parent=iface.mainWindow()) dlg.show() # do NOT remove!!!! if you do then sip forgets the python subclass of AlgorithmDialog and you get a broken @@ -116,7 +121,7 @@ def runAlg(file): return True def customUriProviderKey(self): - return 'processing' + return "processing" def handleCustomUriDrop(self, uri): path = uri.uri @@ -155,9 +160,13 @@ def editModel(self): dlg.show() def actions(self, parent): - run_model_action = QAction(QCoreApplication.translate('ProcessingPlugin', '&Run Model…'), parent) + run_model_action = QAction( + QCoreApplication.translate("ProcessingPlugin", "&Run Model…"), parent + ) run_model_action.triggered.connect(self.runModel) - edit_model_action = QAction(QCoreApplication.translate('ProcessingPlugin', '&Edit Model…'), parent) + edit_model_action = QAction( + QCoreApplication.translate("ProcessingPlugin", "&Edit Model…"), parent + ) edit_model_action.triggered.connect(self.editModel) return [run_model_action, edit_model_action] @@ -168,7 +177,7 @@ def __init__(self): super().__init__() def name(self): - return 'processing' + return "processing" def capabilities(self): return QgsDataProvider.DataCapability.File @@ -176,7 +185,7 @@ def capabilities(self): def createDataItem(self, path, parentItem): file_info = QFileInfo(path) - if file_info.suffix().lower() == 'model3': + if file_info.suffix().lower() == "model3": alg = QgsProcessingModelAlgorithm() if alg.fromFile(path): return ProcessingModelItem(parentItem, alg.name(), path) @@ -194,7 +203,7 @@ def __init__(self, iface): self.locator_filter = None self.edit_features_locator_filter = None self.initialized = False - self._gui_connections: List[QMetaObject.Connection] = [] + self._gui_connections: list[QMetaObject.Connection] = [] self.initProcessing() def initProcessing(self): @@ -209,13 +218,15 @@ def initGui(self): # port old log, ONCE ONLY! settings = QgsSettings() if not settings.value("/Processing/hasPortedOldLog", False, bool): - processing_history_provider = QgsGui.historyProviderRegistry().providerById('processing') + processing_history_provider = QgsGui.historyProviderRegistry().providerById( + "processing" + ) if processing_history_provider: processing_history_provider.portOldLog() settings.setValue("/Processing/hasPortedOldLog", True) self.options_factory = ProcessingOptionsFactory() - self.options_factory.setTitle(self.tr('Processing')) + self.options_factory.setTitle(self.tr("Processing")) iface.registerOptionsWidgetFactory(self.options_factory) self.drop_handler = ProcessingDropHandler() iface.registerCustomDropHandler(self.drop_handler) @@ -225,15 +236,17 @@ def initGui(self): iface.registerLocatorFilter(self.locator_filter) # Invalidate the locator filter for in-place when active layer changes self._gui_connections.append( - iface.currentLayerChanged.connect(lambda _: self.iface.invalidateLocatorResults()) + iface.currentLayerChanged.connect( + lambda _: self.iface.invalidateLocatorResults() + ) ) self.edit_features_locator_filter = InPlaceAlgorithmLocatorFilter() iface.registerLocatorFilter(self.edit_features_locator_filter) - QgsGui.historyProviderRegistry().providerById('processing').executePython.connect( - self._execute_history_commands - ) - QgsGui.historyProviderRegistry().providerById('processing').createTest.connect( + QgsGui.historyProviderRegistry().providerById( + "processing" + ).executePython.connect(self._execute_history_commands) + QgsGui.historyProviderRegistry().providerById("processing").createTest.connect( self.create_test ) @@ -245,50 +258,69 @@ def initGui(self): self.toolbox.executeWithGui.connect(self.executeAlgorithm) self.resultsDock = ResultsDock() - self.iface.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.resultsDock) + self.iface.addDockWidget( + Qt.DockWidgetArea.RightDockWidgetArea, self.resultsDock + ) self.resultsDock.hide() self.menu = QMenu(self.iface.mainWindow().menuBar()) - self.menu.setObjectName('processing') - self.menu.setTitle(self.tr('Pro&cessing')) + self.menu.setObjectName("processing") + self.menu.setTitle(self.tr("Pro&cessing")) - self.toolboxAction = QAction(self.tr('&Toolbox'), self.iface.mainWindow()) + self.toolboxAction = QAction(self.tr("&Toolbox"), self.iface.mainWindow()) self.toolboxAction.setCheckable(True) - self.toolboxAction.setObjectName('toolboxAction') + self.toolboxAction.setObjectName("toolboxAction") self.toolboxAction.setIcon( - QgsApplication.getThemeIcon("/processingAlgorithm.svg")) - self.iface.registerMainWindowAction(self.toolboxAction, - QKeySequence('Ctrl+Alt+T').toString(QKeySequence.SequenceFormat.NativeText)) + QgsApplication.getThemeIcon("/processingAlgorithm.svg") + ) + self.iface.registerMainWindowAction( + self.toolboxAction, + QKeySequence("Ctrl+Alt+T").toString(QKeySequence.SequenceFormat.NativeText), + ) self.toolboxAction.toggled.connect(self.openToolbox) - self.iface.attributesToolBar().insertAction(self.iface.actionOpenStatisticalSummary(), self.toolboxAction) + self.iface.attributesToolBar().insertAction( + self.iface.actionOpenStatisticalSummary(), self.toolboxAction + ) self.menu.addAction(self.toolboxAction) self.modelerAction = QAction( QgsApplication.getThemeIcon("/processingModel.svg"), - QCoreApplication.translate('ProcessingPlugin', '&Model Designer…'), self.iface.mainWindow()) - self.modelerAction.setObjectName('modelerAction') + QCoreApplication.translate("ProcessingPlugin", "&Model Designer…"), + self.iface.mainWindow(), + ) + self.modelerAction.setObjectName("modelerAction") self.modelerAction.triggered.connect(self.openModeler) - self.iface.registerMainWindowAction(self.modelerAction, - QKeySequence('Ctrl+Alt+G').toString(QKeySequence.SequenceFormat.NativeText)) + self.iface.registerMainWindowAction( + self.modelerAction, + QKeySequence("Ctrl+Alt+G").toString(QKeySequence.SequenceFormat.NativeText), + ) self.menu.addAction(self.modelerAction) self.historyAction = QAction( QgsApplication.getThemeIcon("/mIconHistory.svg"), - QCoreApplication.translate('ProcessingPlugin', '&History…'), self.iface.mainWindow()) - self.historyAction.setObjectName('historyAction') + QCoreApplication.translate("ProcessingPlugin", "&History…"), + self.iface.mainWindow(), + ) + self.historyAction.setObjectName("historyAction") self.historyAction.triggered.connect(self.openHistory) - self.iface.registerMainWindowAction(self.historyAction, - QKeySequence('Ctrl+Alt+H').toString(QKeySequence.SequenceFormat.NativeText)) + self.iface.registerMainWindowAction( + self.historyAction, + QKeySequence("Ctrl+Alt+H").toString(QKeySequence.SequenceFormat.NativeText), + ) self.menu.addAction(self.historyAction) self.toolbox.processingToolbar.addAction(self.historyAction) self.resultsAction = QAction( QgsApplication.getThemeIcon("/processingResult.svg"), - self.tr('&Results Viewer'), self.iface.mainWindow()) - self.resultsAction.setObjectName('resultsViewer') + self.tr("&Results Viewer"), + self.iface.mainWindow(), + ) + self.resultsAction.setObjectName("resultsViewer") self.resultsAction.setCheckable(True) - self.iface.registerMainWindowAction(self.resultsAction, - QKeySequence('Ctrl+Alt+R').toString(QKeySequence.SequenceFormat.NativeText)) + self.iface.registerMainWindowAction( + self.resultsAction, + QKeySequence("Ctrl+Alt+R").toString(QKeySequence.SequenceFormat.NativeText), + ) self.menu.addAction(self.resultsAction) self.toolbox.processingToolbar.addAction(self.resultsAction) @@ -299,8 +331,10 @@ def initGui(self): self.editInPlaceAction = QAction( QgsApplication.getThemeIcon("/mActionProcessSelected.svg"), - self.tr('Edit Features In-Place'), self.iface.mainWindow()) - self.editInPlaceAction.setObjectName('editInPlaceFeatures') + self.tr("Edit Features In-Place"), + self.iface.mainWindow(), + ) + self.editInPlaceAction.setObjectName("editInPlaceFeatures") self.editInPlaceAction.setCheckable(True) self.editInPlaceAction.toggled.connect(self.editSelected) self.menu.addAction(self.editInPlaceAction) @@ -310,14 +344,15 @@ def initGui(self): self.optionsAction = QAction( QgsApplication.getThemeIcon("/mActionOptions.svg"), - self.tr('Options'), self.iface.mainWindow()) - self.optionsAction.setObjectName('optionsAction') + self.tr("Options"), + self.iface.mainWindow(), + ) + self.optionsAction.setObjectName("optionsAction") self.optionsAction.triggered.connect(self.openProcessingOptions) self.toolbox.processingToolbar.addAction(self.optionsAction) menuBar = self.iface.mainWindow().menuBar() - menuBar.insertMenu( - self.iface.firstRightStandardMenu().menuAction(), self.menu) + menuBar.insertMenu(self.iface.firstRightStandardMenu().menuAction(), self.menu) self.menu.addSeparator() @@ -334,10 +369,14 @@ def initGui(self): self.iface.currentLayerChanged.connect(self.sync_in_place_button_state) ) self._gui_connections.append( - self.iface.mapCanvas().selectionChanged.connect(self.sync_in_place_button_state) + self.iface.mapCanvas().selectionChanged.connect( + self.sync_in_place_button_state + ) ) self._gui_connections.append( - self.iface.actionToggleEditing().triggered.connect(partial(self.sync_in_place_button_state, None)) + self.iface.actionToggleEditing().triggered.connect( + partial(self.sync_in_place_button_state, None) + ) ) self.sync_in_place_button_state() @@ -346,7 +385,9 @@ def initGui(self): self.projectMenuAction = None self.projectMenuSeparator = None - self.projectProvider = QgsApplication.instance().processingRegistry().providerById("project") + self.projectProvider = ( + QgsApplication.instance().processingRegistry().providerById("project") + ) self._gui_connections.append( self.projectProvider.algorithmsLoaded.connect(self.updateProjectModelMenu) ) @@ -356,7 +397,9 @@ def updateProjectModelMenu(self): if self.projectMenuAction is None: self.projectModelsMenu = QMenu(self.tr("Models")) - self.projectMenuAction = self.iface.projectMenu().insertMenu(self.iface.projectMenu().children()[-1], self.projectModelsMenu) + self.projectMenuAction = self.iface.projectMenu().insertMenu( + self.iface.projectMenu().children()[-1], self.projectModelsMenu + ) self.projectMenuAction.setParent(self.projectModelsMenu) self.iface.projectMenu().insertSeparator(self.projectMenuAction) @@ -366,12 +409,27 @@ def updateProjectModelMenu(self): modelSubMenu = self.projectModelsMenu.addMenu(model.name()) modelSubMenu.setParent(self.projectModelsMenu) action = QAction(self.tr("Execute…"), modelSubMenu) - action.triggered.connect(partial(self.executeAlgorithm, model.id(), self.projectModelsMenu, self.toolbox.in_place_mode)) + action.triggered.connect( + partial( + self.executeAlgorithm, + model.id(), + self.projectModelsMenu, + self.toolbox.in_place_mode, + ) + ) modelSubMenu.addAction(action) if model.flags() & QgsProcessingAlgorithm.Flag.FlagSupportsBatch: action = QAction(self.tr("Execute as Batch Process…"), modelSubMenu) modelSubMenu.addAction(action) - action.triggered.connect(partial(self.executeAlgorithm, model.id(), self.projectModelsMenu, self.toolbox.in_place_mode, True)) + action.triggered.connect( + partial( + self.executeAlgorithm, + model.id(), + self.projectModelsMenu, + self.toolbox.in_place_mode, + True, + ) + ) @pyqtSlot(str, QWidget, bool, bool) def executeAlgorithm(self, alg_id, parent, in_place=False, as_batch=False): @@ -389,19 +447,25 @@ def executeAlgorithm(self, alg_id, parent, in_place=False, as_batch=False): config = {} if in_place: - config['IN_PLACE'] = True + config["IN_PLACE"] = True - alg = QgsApplication.instance().processingRegistry().createAlgorithmById(alg_id, config) + alg = ( + QgsApplication.instance() + .processingRegistry() + .createAlgorithmById(alg_id, config) + ) if alg is not None: ok, message = alg.canExecute() if not ok: dlg = MessageDialog() - dlg.setTitle(self.tr('Error executing algorithm')) + dlg.setTitle(self.tr("Error executing algorithm")) dlg.setMessage( - self.tr('

This algorithm cannot ' - 'be run :-(

\n{0}').format(message)) + self.tr( + "

This algorithm cannot " "be run :-(

\n{0}" + ).format(message) + ) dlg.exec() return @@ -410,16 +474,26 @@ def executeAlgorithm(self, alg_id, parent, in_place=False, as_batch=False): dlg.show() dlg.exec() else: - in_place_input_parameter_name = 'INPUT' - if hasattr(alg, 'inputParameterName'): + in_place_input_parameter_name = "INPUT" + if hasattr(alg, "inputParameterName"): in_place_input_parameter_name = alg.inputParameterName() - if in_place and not [d for d in alg.parameterDefinitions() if d.name() not in (in_place_input_parameter_name, 'OUTPUT')]: + if in_place and not [ + d + for d in alg.parameterDefinitions() + if d.name() not in (in_place_input_parameter_name, "OUTPUT") + ]: parameters = {} feedback = MessageBarProgress(algname=alg.displayName()) ok, results = execute_in_place(alg, parameters, feedback=feedback) if ok: - iface.messageBar().pushSuccess('', self.tr('{algname} completed. %n feature(s) processed.', n=results['__count']).format(algname=alg.displayName())) + iface.messageBar().pushSuccess( + "", + self.tr( + "{algname} completed. %n feature(s) processed.", + n=results["__count"], + ).format(algname=alg.displayName()), + ) feedback.close() # MessageBarProgress handles errors return @@ -458,14 +532,20 @@ def sync_in_place_button_state(self, layer=None): old_enabled_state = self.editInPlaceAction.isEnabled() - new_enabled_state = layer is not None and layer.type() == QgsMapLayerType.VectorLayer + new_enabled_state = ( + layer is not None and layer.type() == QgsMapLayerType.VectorLayer + ) self.editInPlaceAction.setEnabled(new_enabled_state) if new_enabled_state != old_enabled_state: - self.toolbox.set_in_place_edit_mode(new_enabled_state and self.editInPlaceAction.isChecked()) + self.toolbox.set_in_place_edit_mode( + new_enabled_state and self.editInPlaceAction.isChecked() + ) def openProcessingOptions(self): - self.iface.showOptionsDialog(self.iface.mainWindow(), currentPage='processingOptions') + self.iface.showOptionsDialog( + self.iface.mainWindow(), currentPage="processingOptions" + ) def unload(self): for connection in self._gui_connections: @@ -507,12 +587,12 @@ def unload(self): self.iface.projectMenu().removeAction(self.projectMenuSeparator) self.projectMenuSeparator = None - QgsGui.historyProviderRegistry().providerById('processing').executePython.disconnect( - self._execute_history_commands - ) - QgsGui.historyProviderRegistry().providerById('processing').createTest.disconnect( - self.create_test - ) + QgsGui.historyProviderRegistry().providerById( + "processing" + ).executePython.disconnect(self._execute_history_commands) + QgsGui.historyProviderRegistry().providerById( + "processing" + ).createTest.disconnect(self.create_test) Processing.deinitialize() @@ -528,7 +608,7 @@ def openModeler(self): dlg.show() def updateModel(self): - model_provider = QgsApplication.processingRegistry().providerById('model') + model_provider = QgsApplication.processingRegistry().providerById("model") model_provider.refreshAlgorithms() def openResults(self): @@ -543,7 +623,9 @@ def openHistory(self): dlg.show() def tr(self, message, disambiguation=None, n=-1): - return QCoreApplication.translate('ProcessingPlugin', message, disambiguation=disambiguation, n=n) + return QCoreApplication.translate( + "ProcessingPlugin", message, disambiguation=disambiguation, n=n + ) def editSelected(self, enabled): self.toolbox.set_in_place_edit_mode(enabled) diff --git a/python/plugins/processing/__init__.py b/python/plugins/processing/__init__.py index 672241adf36b..a343cfe84204 100644 --- a/python/plugins/processing/__init__.py +++ b/python/plugins/processing/__init__.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" from processing.tools.dataobjects import * # NOQA from processing.tools.dataobjects import createContext @@ -27,7 +27,7 @@ run, runAndLoadResults, createAlgorithmDialog, - execAlgorithmDialog + execAlgorithmDialog, ) from processing.tools.vector import * # NOQA from processing.tools.raster import * # NOQA @@ -52,4 +52,5 @@ def classFactory(iface): from processing.ProcessingPlugin import ProcessingPlugin + return ProcessingPlugin(iface) diff --git a/python/plugins/processing/algs/gdal/AssignProjection.py b/python/plugins/processing/algs/gdal/AssignProjection.py index c827e074dcf0..837b3b0c6b4f 100644 --- a/python/plugins/processing/algs/gdal/AssignProjection.py +++ b/python/plugins/processing/algs/gdal/AssignProjection.py @@ -15,19 +15,21 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'January 2016' -__copyright__ = '(C) 2016, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "January 2016" +__copyright__ = "(C) 2016, Alexander Bruy" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsProcessingException, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterCrs, - QgsProcessingOutputRasterLayer, - QgsProcessingContext) +from qgis.core import ( + QgsProcessingException, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterCrs, + QgsProcessingOutputRasterLayer, + QgsProcessingContext, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -37,49 +39,56 @@ class AssignProjection(GdalAlgorithm): - INPUT = 'INPUT' - CRS = 'CRS' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + CRS = "CRS" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterCrs(self.CRS, - self.tr('Desired CRS'))) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter(QgsProcessingParameterCrs(self.CRS, self.tr("Desired CRS"))) - self.addOutput(QgsProcessingOutputRasterLayer(self.OUTPUT, - self.tr('Layer with projection'))) + self.addOutput( + QgsProcessingOutputRasterLayer( + self.OUTPUT, self.tr("Layer with projection") + ) + ) def name(self): - return 'assignprojection' + return "assignprojection" def displayName(self): - return self.tr('Assign projection') + return self.tr("Assign projection") def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'projection-add.png')) + return QIcon( + os.path.join(pluginPath, "images", "gdaltools", "projection-add.png") + ) def tags(self): - tags = self.tr('assign,set,transform,reproject,crs,srs').split(',') + tags = self.tr("assign,set,transform,reproject,crs,srs").split(",") tags.extend(super().tags()) return tags def group(self): - return self.tr('Raster projections') + return self.tr("Raster projections") def groupId(self): - return 'rasterprojections' + return "rasterprojections" def commandName(self): - return 'gdal_edit' + return "gdal_edit" def getConsoleCommands(self, parameters, context, feedback, executing=True): inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) fileName = inLayer.source() @@ -87,9 +96,9 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): crs = self.parameterAsCrs(parameters, self.CRS, context) arguments = [ - '-a_srs', + "-a_srs", GdalUtils.gdal_crs_string(crs), - input_details.connection_string + input_details.connection_string, ] if input_details.open_options: @@ -100,7 +109,10 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): self.setOutputValue(self.OUTPUT, fileName) - return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)] + return [ + self.commandName() + (".bat" if isWindows() else ".py"), + GdalUtils.escapeAndJoin(arguments), + ] def postProcessAlgorithm(self, context, feedback): # get output value diff --git a/python/plugins/processing/algs/gdal/Buffer.py b/python/plugins/processing/algs/gdal/Buffer.py index d3f23497bf44..63a97eec98fd 100644 --- a/python/plugins/processing/algs/gdal/Buffer.py +++ b/python/plugins/processing/algs/gdal/Buffer.py @@ -15,92 +15,125 @@ *************************************************************************** """ -__author__ = 'Giovanni Manghi' -__date__ = 'January 2015' -__copyright__ = '(C) 2015, Giovanni Manghi' - -from qgis.core import (QgsProcessing, - QgsProcessingParameterDistance, - QgsProcessingParameterDefinition, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterField, - QgsProcessingParameterString, - QgsProcessingParameterNumber, - QgsProcessingException, - QgsProcessingParameterBoolean, - QgsProcessingParameterVectorDestination) +__author__ = "Giovanni Manghi" +__date__ = "January 2015" +__copyright__ = "(C) 2015, Giovanni Manghi" + +from qgis.core import ( + QgsProcessing, + QgsProcessingParameterDistance, + QgsProcessingParameterDefinition, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingParameterString, + QgsProcessingParameterNumber, + QgsProcessingException, + QgsProcessingParameterBoolean, + QgsProcessingParameterVectorDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils class Buffer(GdalAlgorithm): - INPUT = 'INPUT' - FIELD = 'FIELD' - GEOMETRY = 'GEOMETRY' - DISTANCE = 'DISTANCE' - DISSOLVE = 'DISSOLVE' - EXPLODE_COLLECTIONS = 'EXPLODE_COLLECTIONS' - OPTIONS = 'OPTIONS' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + FIELD = "FIELD" + GEOMETRY = "GEOMETRY" + DISTANCE = "DISTANCE" + DISSOLVE = "DISSOLVE" + EXPLODE_COLLECTIONS = "EXPLODE_COLLECTIONS" + OPTIONS = "OPTIONS" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterString(self.GEOMETRY, - self.tr('Geometry column name'), - defaultValue='geometry')) - self.addParameter(QgsProcessingParameterDistance(self.DISTANCE, - self.tr('Buffer distance'), - parentParameterName=self.INPUT, - defaultValue=10.0)) - self.addParameter(QgsProcessingParameterField(self.FIELD, - self.tr('Dissolve by attribute'), - None, - self.INPUT, - QgsProcessingParameterField.DataType.Any, - optional=True)) - self.addParameter(QgsProcessingParameterBoolean(self.DISSOLVE, - self.tr('Dissolve all results'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.EXPLODE_COLLECTIONS, - self.tr('Produce one feature for each geometry in any kind of geometry collection in the source file'), - defaultValue=False)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterString( + self.GEOMETRY, self.tr("Geometry column name"), defaultValue="geometry" + ) + ) + self.addParameter( + QgsProcessingParameterDistance( + self.DISTANCE, + self.tr("Buffer distance"), + parentParameterName=self.INPUT, + defaultValue=10.0, + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.FIELD, + self.tr("Dissolve by attribute"), + None, + self.INPUT, + QgsProcessingParameterField.DataType.Any, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.DISSOLVE, self.tr("Dissolve all results"), defaultValue=False + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.EXPLODE_COLLECTIONS, + self.tr( + "Produce one feature for each geometry in any kind of geometry collection in the source file" + ), + defaultValue=False, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(options_param) - self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT, - self.tr('Buffer'), - QgsProcessing.SourceType.TypeVectorPolygon)) + self.addParameter( + QgsProcessingParameterVectorDestination( + self.OUTPUT, + self.tr("Buffer"), + QgsProcessing.SourceType.TypeVectorPolygon, + ) + ) def name(self): - return 'buffervectors' + return "buffervectors" def displayName(self): - return self.tr('Buffer vectors') + return self.tr("Buffer vectors") def group(self): - return self.tr('Vector geoprocessing') + return self.tr("Vector geoprocessing") def groupId(self): - return 'vectorgeoprocessing' + return "vectorgeoprocessing" def commandName(self): - return 'ogr2ogr' + return "ogr2ogr" def getConsoleCommands(self, parameters, context, feedback, executing=True): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) fields = source.fields() - source_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing) + source_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) geometry = self.parameterAsString(parameters, self.GEOMETRY, context) distance = self.parameterAsDouble(parameters, self.DISTANCE, context) @@ -112,19 +145,16 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context) - other_fields_exist = any( - True for f in fields - if f.name() != geometry - ) + other_fields_exist = any(True for f in fields if f.name() != geometry) - other_fields = ',*' if other_fields_exist else '' + other_fields = ",*" if other_fields_exist else "" arguments = [ output_details.connection_string, source_details.connection_string, - '-dialect', - 'sqlite', - '-sql' + "-dialect", + "sqlite", + "-sql", ] if dissolve or fieldName: @@ -138,7 +168,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments.append(sql) if self.parameterAsBoolean(parameters, self.EXPLODE_COLLECTIONS, context): - arguments.append('-explodecollections') + arguments.append("-explodecollections") if source_details.open_options: arguments.extend(source_details.open_options_as_arguments()) @@ -150,6 +180,6 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments.append(options) if output_details.format: - arguments.append(f'-f {output_details.format}') + arguments.append(f"-f {output_details.format}") return [self.commandName(), GdalUtils.escapeAndJoin(arguments)] diff --git a/python/plugins/processing/algs/gdal/ClipRasterByExtent.py b/python/plugins/processing/algs/gdal/ClipRasterByExtent.py index 399db17a5c60..73db5af85939 100644 --- a/python/plugins/processing/algs/gdal/ClipRasterByExtent.py +++ b/python/plugins/processing/algs/gdal/ClipRasterByExtent.py @@ -15,24 +15,26 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'September 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "September 2013" +__copyright__ = "(C) 2013, Alexander Bruy" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsRasterFileWriter, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterEnum, - QgsProcessingParameterExtent, - QgsProcessingParameterString, - QgsProcessingParameterNumber, - QgsProcessingParameterBoolean, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterEnum, + QgsProcessingParameterExtent, + QgsProcessingParameterString, + QgsProcessingParameterNumber, + QgsProcessingParameterBoolean, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -40,75 +42,114 @@ class ClipRasterByExtent(GdalAlgorithm): - INPUT = 'INPUT' - EXTENT = 'PROJWIN' - OVERCRS = 'OVERCRS' - NODATA = 'NODATA' - OPTIONS = 'OPTIONS' - DATA_TYPE = 'DATA_TYPE' - EXTRA = 'EXTRA' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + EXTENT = "PROJWIN" + OVERCRS = "OVERCRS" + NODATA = "NODATA" + OPTIONS = "OPTIONS" + DATA_TYPE = "DATA_TYPE" + EXTRA = "EXTRA" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.TYPES = [self.tr('Use Input Layer Data Type'), 'Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8'] - - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterExtent(self.EXTENT, - self.tr('Clipping extent'))) - self.addParameter(QgsProcessingParameterBoolean(self.OVERCRS, - self.tr('Override the projection for the output file'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterNumber(self.NODATA, - self.tr('Assign a specified NoData value to output bands'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=None, - optional=True)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.TYPES = [ + self.tr("Use Input Layer Data Type"), + "Byte", + "Int16", + "UInt16", + "UInt32", + "Int32", + "Float32", + "Float64", + "CInt16", + "CInt32", + "CFloat32", + "CFloat64", + "Int8", + ] + + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterExtent(self.EXTENT, self.tr("Clipping extent")) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.OVERCRS, + self.tr("Override the projection for the output file"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.NODATA, + self.tr("Assign a specified NoData value to output bands"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=None, + optional=True, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE, - self.tr('Output data type'), - self.TYPES, - allowMultiple=False, - defaultValue=0) - dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + dataType_param = QgsProcessingParameterEnum( + self.DATA_TYPE, + self.tr("Output data type"), + self.TYPES, + allowMultiple=False, + defaultValue=0, + ) + dataType_param.setFlags( + dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(dataType_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, - self.tr('Clipped (extent)'))) + self.addParameter( + QgsProcessingParameterRasterDestination( + self.OUTPUT, self.tr("Clipped (extent)") + ) + ) def name(self): - return 'cliprasterbyextent' + return "cliprasterbyextent" def displayName(self): - return self.tr('Clip raster by extent') + return self.tr("Clip raster by extent") def group(self): - return self.tr('Raster extraction') + return self.tr("Raster extraction") def groupId(self): - return 'rasterextraction' + return "rasterextraction" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'raster-clip.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "raster-clip.png")) def commandName(self): return "gdal_translate" @@ -116,7 +157,11 @@ def commandName(self): def getConsoleCommands(self, parameters, context, feedback, executing=True): inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException('Invalid input layer {}'.format(parameters[self.INPUT] if self.INPUT in parameters else 'INPUT')) + raise QgsProcessingException( + "Invalid input layer {}".format( + parameters[self.INPUT] if self.INPUT in parameters else "INPUT" + ) + ) input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) bbox = self.parameterAsExtent(parameters, self.EXTENT, context, inLayer.crs()) @@ -132,39 +177,43 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments = [] if not bbox.isNull(): - arguments.extend([ - '-projwin', - str(bbox.xMinimum()), - str(bbox.yMaximum()), - str(bbox.xMaximum()), - str(bbox.yMinimum()), - ]) + arguments.extend( + [ + "-projwin", + str(bbox.xMinimum()), + str(bbox.yMaximum()), + str(bbox.xMaximum()), + str(bbox.yMinimum()), + ] + ) crs = inLayer.crs() if override_crs and crs.isValid(): - arguments.append(f'-a_srs {GdalUtils.gdal_crs_string(crs)}') + arguments.append(f"-a_srs {GdalUtils.gdal_crs_string(crs)}") if nodata is not None: - arguments.append(f'-a_nodata {nodata}') + arguments.append(f"-a_nodata {nodata}") data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context) if data_type: - if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later')) + if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000: + raise QgsProcessingException( + self.tr("Int8 data type requires GDAL version 3.7 or later") + ) - arguments.append('-ot ' + self.TYPES[data_type]) + arguments.append("-ot " + self.TYPES[data_type]) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) - arguments.append('-of') + arguments.append("-of") arguments.append(output_format) if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) diff --git a/python/plugins/processing/algs/gdal/ClipRasterByMask.py b/python/plugins/processing/algs/gdal/ClipRasterByMask.py index ba2ec1f4aab7..a05c22ed5f81 100644 --- a/python/plugins/processing/algs/gdal/ClipRasterByMask.py +++ b/python/plugins/processing/algs/gdal/ClipRasterByMask.py @@ -15,27 +15,29 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'September 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "September 2013" +__copyright__ = "(C) 2013, Alexander Bruy" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsRasterFileWriter, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterCrs, - QgsProcessingParameterEnum, - QgsProcessingParameterExtent, - QgsProcessingParameterString, - QgsProcessingParameterNumber, - QgsProcessingParameterBoolean, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterCrs, + QgsProcessingParameterEnum, + QgsProcessingParameterExtent, + QgsProcessingParameterString, + QgsProcessingParameterNumber, + QgsProcessingParameterBoolean, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -43,130 +45,209 @@ class ClipRasterByMask(GdalAlgorithm): - INPUT = 'INPUT' - MASK = 'MASK' - SOURCE_CRS = 'SOURCE_CRS' - TARGET_CRS = 'TARGET_CRS' - EXTENT = 'TARGET_EXTENT' - NODATA = 'NODATA' - ALPHA_BAND = 'ALPHA_BAND' - CROP_TO_CUTLINE = 'CROP_TO_CUTLINE' - KEEP_RESOLUTION = 'KEEP_RESOLUTION' - SET_RESOLUTION = 'SET_RESOLUTION' - X_RESOLUTION = 'X_RESOLUTION' - Y_RESOLUTION = 'Y_RESOLUTION' - OPTIONS = 'OPTIONS' - DATA_TYPE = 'DATA_TYPE' - MULTITHREADING = 'MULTITHREADING' - EXTRA = 'EXTRA' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + MASK = "MASK" + SOURCE_CRS = "SOURCE_CRS" + TARGET_CRS = "TARGET_CRS" + EXTENT = "TARGET_EXTENT" + NODATA = "NODATA" + ALPHA_BAND = "ALPHA_BAND" + CROP_TO_CUTLINE = "CROP_TO_CUTLINE" + KEEP_RESOLUTION = "KEEP_RESOLUTION" + SET_RESOLUTION = "SET_RESOLUTION" + X_RESOLUTION = "X_RESOLUTION" + Y_RESOLUTION = "Y_RESOLUTION" + OPTIONS = "OPTIONS" + DATA_TYPE = "DATA_TYPE" + MULTITHREADING = "MULTITHREADING" + EXTRA = "EXTRA" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.TYPES = [self.tr('Use Input Layer Data Type'), 'Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8'] - - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterFeatureSource(self.MASK, - self.tr('Mask layer'), - [QgsProcessing.SourceType.TypeVectorPolygon])) - self.addParameter(QgsProcessingParameterCrs(self.SOURCE_CRS, - self.tr('Source CRS'), - optional=True)) - self.addParameter(QgsProcessingParameterCrs(self.TARGET_CRS, - self.tr('Target CRS'), - optional=True)) - self.addParameter(QgsProcessingParameterExtent(self.EXTENT, - self.tr('Target extent'), - optional=True)) - self.addParameter(QgsProcessingParameterNumber(self.NODATA, - self.tr('Assign a specified NoData value to output bands'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=None, - optional=True)) - self.addParameter(QgsProcessingParameterBoolean(self.ALPHA_BAND, - self.tr('Create an output alpha band'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.CROP_TO_CUTLINE, - self.tr('Match the extent of the clipped raster to the extent of the mask layer'), - defaultValue=True)) - self.addParameter(QgsProcessingParameterBoolean(self.KEEP_RESOLUTION, - self.tr('Keep resolution of input raster'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.SET_RESOLUTION, - self.tr('Set output file resolution'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterNumber(self.X_RESOLUTION, - self.tr('X Resolution to output bands'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=None, - optional=True)) - self.addParameter(QgsProcessingParameterNumber(self.Y_RESOLUTION, - self.tr('Y Resolution to output bands'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=None, - optional=True)) - - multithreading_param = QgsProcessingParameterBoolean(self.MULTITHREADING, - self.tr('Use multithreaded warping implementation'), - defaultValue=False) - multithreading_param.setFlags(multithreading_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.TYPES = [ + self.tr("Use Input Layer Data Type"), + "Byte", + "Int16", + "UInt16", + "UInt32", + "Int32", + "Float32", + "Float64", + "CInt16", + "CInt32", + "CFloat32", + "CFloat64", + "Int8", + ] + + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.MASK, + self.tr("Mask layer"), + [QgsProcessing.SourceType.TypeVectorPolygon], + ) + ) + self.addParameter( + QgsProcessingParameterCrs( + self.SOURCE_CRS, self.tr("Source CRS"), optional=True + ) + ) + self.addParameter( + QgsProcessingParameterCrs( + self.TARGET_CRS, self.tr("Target CRS"), optional=True + ) + ) + self.addParameter( + QgsProcessingParameterExtent( + self.EXTENT, self.tr("Target extent"), optional=True + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.NODATA, + self.tr("Assign a specified NoData value to output bands"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=None, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.ALPHA_BAND, + self.tr("Create an output alpha band"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.CROP_TO_CUTLINE, + self.tr( + "Match the extent of the clipped raster to the extent of the mask layer" + ), + defaultValue=True, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.KEEP_RESOLUTION, + self.tr("Keep resolution of input raster"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.SET_RESOLUTION, + self.tr("Set output file resolution"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.X_RESOLUTION, + self.tr("X Resolution to output bands"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=None, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.Y_RESOLUTION, + self.tr("Y Resolution to output bands"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=None, + optional=True, + ) + ) + + multithreading_param = QgsProcessingParameterBoolean( + self.MULTITHREADING, + self.tr("Use multithreaded warping implementation"), + defaultValue=False, + ) + multithreading_param.setFlags( + multithreading_param.flags() + | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(multithreading_param) - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE, - self.tr('Output data type'), - self.TYPES, - allowMultiple=False, - defaultValue=0) - dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + dataType_param = QgsProcessingParameterEnum( + self.DATA_TYPE, + self.tr("Output data type"), + self.TYPES, + allowMultiple=False, + defaultValue=0, + ) + dataType_param.setFlags( + dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(dataType_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, - self.tr('Clipped (mask)'))) + self.addParameter( + QgsProcessingParameterRasterDestination( + self.OUTPUT, self.tr("Clipped (mask)") + ) + ) def name(self): - return 'cliprasterbymasklayer' + return "cliprasterbymasklayer" def displayName(self): - return self.tr('Clip raster by mask layer') + return self.tr("Clip raster by mask layer") def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'raster-clip.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "raster-clip.png")) def group(self): - return self.tr('Raster extraction') + return self.tr("Raster extraction") def groupId(self): - return 'rasterextraction' + return "rasterextraction" def commandName(self): - return 'gdalwarp' + return "gdalwarp" def getConsoleCommands(self, parameters, context, feedback, executing=True): inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) - mask_details = self.getOgrCompatibleSource(self.MASK, parameters, context, feedback, executing) + mask_details = self.getOgrCompatibleSource( + self.MASK, parameters, context, feedback, executing + ) sourceCrs = self.parameterAsCrs(parameters, self.SOURCE_CRS, context) targetCrs = self.parameterAsCrs(parameters, self.TARGET_CRS, context) @@ -182,80 +263,88 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, out) - arguments = ['-overwrite'] + arguments = ["-overwrite"] if sourceCrs.isValid(): - arguments.append('-s_srs') + arguments.append("-s_srs") arguments.append(GdalUtils.gdal_crs_string(sourceCrs)) if targetCrs.isValid(): - arguments.append('-t_srs') + arguments.append("-t_srs") arguments.append(GdalUtils.gdal_crs_string(targetCrs)) if not bbox.isNull(): - arguments.append('-te') + arguments.append("-te") arguments.append(str(bbox.xMinimum())) arguments.append(str(bbox.yMinimum())) arguments.append(str(bbox.xMaximum())) arguments.append(str(bbox.yMaximum())) - arguments.append('-te_srs') + arguments.append("-te_srs") arguments.append(GdalUtils.gdal_crs_string(bboxCrs)) data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context) if data_type: - if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later')) + if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000: + raise QgsProcessingException( + self.tr("Int8 data type requires GDAL version 3.7 or later") + ) - arguments.append('-ot ' + self.TYPES[data_type]) + arguments.append("-ot " + self.TYPES[data_type]) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) - arguments.append('-of') + arguments.append("-of") arguments.append(output_format) if self.parameterAsBoolean(parameters, self.KEEP_RESOLUTION, context): - arguments.append('-tr') + arguments.append("-tr") arguments.append(str(inLayer.rasterUnitsPerPixelX())) arguments.append(str(-inLayer.rasterUnitsPerPixelY())) - arguments.append('-tap') + arguments.append("-tap") if self.parameterAsBoolean(parameters, self.SET_RESOLUTION, context): - arguments.append('-tr') - if self.X_RESOLUTION in parameters and parameters[self.X_RESOLUTION] is not None: + arguments.append("-tr") + if ( + self.X_RESOLUTION in parameters + and parameters[self.X_RESOLUTION] is not None + ): xres = self.parameterAsDouble(parameters, self.X_RESOLUTION, context) - arguments.append(f'{xres}') + arguments.append(f"{xres}") else: arguments.append(str(inLayer.rasterUnitsPerPixelX())) - if self.Y_RESOLUTION in parameters and parameters[self.Y_RESOLUTION] is not None: + if ( + self.Y_RESOLUTION in parameters + and parameters[self.Y_RESOLUTION] is not None + ): yres = self.parameterAsDouble(parameters, self.Y_RESOLUTION, context) - arguments.append(f'{yres}') + arguments.append(f"{yres}") else: arguments.append(str(-inLayer.rasterUnitsPerPixelY())) - arguments.append('-tap') + arguments.append("-tap") - arguments.append('-cutline') + arguments.append("-cutline") arguments.append(mask_details.connection_string) - arguments.append('-cl') + arguments.append("-cl") arguments.append(mask_details.layer_name) if self.parameterAsBoolean(parameters, self.CROP_TO_CUTLINE, context): - arguments.append('-crop_to_cutline') + arguments.append("-crop_to_cutline") if self.parameterAsBoolean(parameters, self.ALPHA_BAND, context): - arguments.append('-dstalpha') + arguments.append("-dstalpha") if nodata is not None: - arguments.append(f'-dstnodata {nodata}') + arguments.append(f"-dstnodata {nodata}") if self.parameterAsBoolean(parameters, self.MULTITHREADING, context): - arguments.append('-multi') + arguments.append("-multi") if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) diff --git a/python/plugins/processing/algs/gdal/ClipVectorByExtent.py b/python/plugins/processing/algs/gdal/ClipVectorByExtent.py index 6d739ed3ded4..5676a92ae0c0 100644 --- a/python/plugins/processing/algs/gdal/ClipVectorByExtent.py +++ b/python/plugins/processing/algs/gdal/ClipVectorByExtent.py @@ -15,86 +15,100 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'November 2012' -__copyright__ = '(C) 2012, Victor Olaya' - -from qgis.core import (QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterExtent, - QgsProcessingParameterString, - QgsProcessingParameterVectorDestination) +__author__ = "Victor Olaya" +__date__ = "November 2012" +__copyright__ = "(C) 2012, Victor Olaya" + +from qgis.core import ( + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterExtent, + QgsProcessingParameterString, + QgsProcessingParameterVectorDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils class ClipVectorByExtent(GdalAlgorithm): - INPUT = 'INPUT' - EXTENT = 'EXTENT' - OPTIONS = 'OPTIONS' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + EXTENT = "EXTENT" + OPTIONS = "OPTIONS" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterExtent(self.EXTENT, - self.tr('Clipping extent'))) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterExtent(self.EXTENT, self.tr("Clipping extent")) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(options_param) - self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT, - self.tr('Clipped (extent)'))) + self.addParameter( + QgsProcessingParameterVectorDestination( + self.OUTPUT, self.tr("Clipped (extent)") + ) + ) def name(self): - return 'clipvectorbyextent' + return "clipvectorbyextent" def displayName(self): - return self.tr('Clip vector by extent') + return self.tr("Clip vector by extent") def group(self): - return self.tr('Vector geoprocessing') + return self.tr("Vector geoprocessing") def groupId(self): - return 'vectorgeoprocessing' + return "vectorgeoprocessing" def commandName(self): - return 'ogr2ogr' + return "ogr2ogr" def getConsoleCommands(self, parameters, context, feedback, executing=True): - input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing) + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) - extent = self.parameterAsExtent(parameters, self.EXTENT, context, source.sourceCrs()) + extent = self.parameterAsExtent( + parameters, self.EXTENT, context, source.sourceCrs() + ) options = self.parameterAsString(parameters, self.OPTIONS, context) outFile = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, outFile) - output_details = GdalUtils.gdal_connection_details_from_uri( - outFile, - context) + output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context) arguments = [ - '-spat', + "-spat", str(extent.xMinimum()), str(extent.yMaximum()), str(extent.xMaximum()), str(extent.yMinimum()), - '-clipsrc spat_extent', - + "-clipsrc spat_extent", output_details.connection_string, input_details.connection_string, - input_details.layer_name + input_details.layer_name, ] if input_details.open_options: @@ -107,6 +121,6 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments.append(options) if output_details.format: - arguments.append(f'-f {output_details.format}') + arguments.append(f"-f {output_details.format}") return [self.commandName(), GdalUtils.escapeAndJoin(arguments)] diff --git a/python/plugins/processing/algs/gdal/ClipVectorByMask.py b/python/plugins/processing/algs/gdal/ClipVectorByMask.py index 8401d640ddc4..cdf4793c8cc0 100644 --- a/python/plugins/processing/algs/gdal/ClipVectorByMask.py +++ b/python/plugins/processing/algs/gdal/ClipVectorByMask.py @@ -15,67 +15,88 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'November 2012' -__copyright__ = '(C) 2012, Victor Olaya' - -from qgis.core import (QgsProcessing, - QgsProcessingAlgorithm, - QgsProcessingParameterDefinition, - QgsProcessingParameterString, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterVectorDestination) +__author__ = "Victor Olaya" +__date__ = "November 2012" +__copyright__ = "(C) 2012, Victor Olaya" + +from qgis.core import ( + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingParameterDefinition, + QgsProcessingParameterString, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterVectorDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils class ClipVectorByMask(GdalAlgorithm): - INPUT = 'INPUT' - MASK = 'MASK' - OPTIONS = 'OPTIONS' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + MASK = "MASK" + OPTIONS = "OPTIONS" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def flags(self): - return QgsProcessingAlgorithm.Flag.FlagSupportsBatch | QgsProcessingAlgorithm.Flag.FlagRequiresMatchingCrs # cannot cancel! + return ( + QgsProcessingAlgorithm.Flag.FlagSupportsBatch + | QgsProcessingAlgorithm.Flag.FlagRequiresMatchingCrs + ) # cannot cancel! def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterFeatureSource(self.MASK, - self.tr('Mask layer'), - [QgsProcessing.SourceType.TypeVectorPolygon])) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.MASK, + self.tr("Mask layer"), + [QgsProcessing.SourceType.TypeVectorPolygon], + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(options_param) - self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT, - self.tr('Clipped (mask)'))) + self.addParameter( + QgsProcessingParameterVectorDestination( + self.OUTPUT, self.tr("Clipped (mask)") + ) + ) def name(self): - return 'clipvectorbypolygon' + return "clipvectorbypolygon" def displayName(self): - return self.tr('Clip vector by mask layer') + return self.tr("Clip vector by mask layer") def group(self): - return self.tr('Vector geoprocessing') + return self.tr("Vector geoprocessing") def groupId(self): - return 'vectorgeoprocessing' + return "vectorgeoprocessing" def commandName(self): - return 'ogr2ogr' + return "ogr2ogr" def getConsoleCommands(self, parameters, context, feedback, executing=True): - input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing) - mask_details = self.getOgrCompatibleSource(self.MASK, parameters, context, feedback, executing) + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) + mask_details = self.getOgrCompatibleSource( + self.MASK, parameters, context, feedback, executing + ) options = self.parameterAsString(parameters, self.OPTIONS, context) outFile = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, outFile) @@ -83,11 +104,10 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context) arguments = [ - '-clipsrc', + "-clipsrc", mask_details.connection_string, - '-clipsrclayer', + "-clipsrclayer", mask_details.layer_name, - output_details.connection_string, input_details.connection_string, input_details.layer_name, @@ -103,6 +123,6 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments.append(options) if output_details.format: - arguments.append(f'-f {output_details.format}') + arguments.append(f"-f {output_details.format}") return [self.commandName(), GdalUtils.escapeAndJoin(arguments)] diff --git a/python/plugins/processing/algs/gdal/ColorRelief.py b/python/plugins/processing/algs/gdal/ColorRelief.py index e8f5f93fc905..4a1c2303f527 100644 --- a/python/plugins/processing/algs/gdal/ColorRelief.py +++ b/python/plugins/processing/algs/gdal/ColorRelief.py @@ -15,96 +15,128 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'October 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "October 2013" +__copyright__ = "(C) 2013, Alexander Bruy" import os -from qgis.core import (QgsRasterFileWriter, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterBand, - QgsProcessingParameterBoolean, - QgsProcessingParameterEnum, - QgsProcessingParameterFile, - QgsProcessingParameterString, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBand, + QgsProcessingParameterBoolean, + QgsProcessingParameterEnum, + QgsProcessingParameterFile, + QgsProcessingParameterString, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils class ColorRelief(GdalAlgorithm): - INPUT = 'INPUT' - BAND = 'BAND' - COMPUTE_EDGES = 'COMPUTE_EDGES' - COLOR_TABLE = 'COLOR_TABLE' - MATCH_MODE = 'MATCH_MODE' - OPTIONS = 'OPTIONS' - EXTRA = 'EXTRA' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + BAND = "BAND" + COMPUTE_EDGES = "COMPUTE_EDGES" + COLOR_TABLE = "COLOR_TABLE" + MATCH_MODE = "MATCH_MODE" + OPTIONS = "OPTIONS" + EXTRA = "EXTRA" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.modes = ((self.tr('Use strict color matching'), '-exact_color_entry'), - (self.tr('Use closest RGBA quadruplet'), '-nearest_color_entry'), - (self.tr('Use smoothly blended colors'), '')) - - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterBand(self.BAND, - self.tr('Band number'), - 1, - parentLayerParameterName=self.INPUT)) - self.addParameter(QgsProcessingParameterBoolean(self.COMPUTE_EDGES, - self.tr('Compute edges'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterFile(self.COLOR_TABLE, - self.tr('Color configuration file'))) - self.addParameter(QgsProcessingParameterEnum(self.MATCH_MODE, - self.tr('Matching mode'), - options=[i[0] for i in self.modes], - defaultValue=2)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.modes = ( + (self.tr("Use strict color matching"), "-exact_color_entry"), + (self.tr("Use closest RGBA quadruplet"), "-nearest_color_entry"), + (self.tr("Use smoothly blended colors"), ""), + ) + + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterBand( + self.BAND, + self.tr("Band number"), + 1, + parentLayerParameterName=self.INPUT, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.COMPUTE_EDGES, self.tr("Compute edges"), defaultValue=False + ) + ) + self.addParameter( + QgsProcessingParameterFile( + self.COLOR_TABLE, self.tr("Color configuration file") + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.MATCH_MODE, + self.tr("Matching mode"), + options=[i[0] for i in self.modes], + defaultValue=2, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Color relief'))) + self.addParameter( + QgsProcessingParameterRasterDestination( + self.OUTPUT, self.tr("Color relief") + ) + ) def name(self): - return 'colorrelief' + return "colorrelief" def displayName(self): - return self.tr('Color relief') + return self.tr("Color relief") def group(self): - return self.tr('Raster analysis') + return self.tr("Raster analysis") def groupId(self): - return 'rasteranalysis' + return "rasteranalysis" def commandName(self): - return 'gdaldem' + return "gdaldem" def getConsoleCommands(self, parameters, context, feedback, executing=True): - arguments = ['color-relief'] + arguments = ["color-relief"] inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) arguments.append(input_details.connection_string) @@ -116,19 +148,19 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) - arguments.append('-of') + arguments.append("-of") arguments.append(output_format) - arguments.append('-b') + arguments.append("-b") arguments.append(str(self.parameterAsInt(parameters, self.BAND, context))) if self.parameterAsBoolean(parameters, self.COMPUTE_EDGES, context): - arguments.append('-compute_edges') + arguments.append("-compute_edges") mode = self.modes[self.parameterAsEnum(parameters, self.MATCH_MODE, context)][1] - if mode != '': + if mode != "": arguments.append(mode) options = self.parameterAsString(parameters, self.OPTIONS, context) @@ -138,7 +170,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if input_details.credential_options: arguments.extend(input_details.credential_options_as_arguments()) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) diff --git a/python/plugins/processing/algs/gdal/Datasources2Vrt.py b/python/plugins/processing/algs/gdal/Datasources2Vrt.py index b8a90f561609..7ea5b8f0092d 100644 --- a/python/plugins/processing/algs/gdal/Datasources2Vrt.py +++ b/python/plugins/processing/algs/gdal/Datasources2Vrt.py @@ -15,63 +15,72 @@ *************************************************************************** """ -__author__ = 'Luigi Pirelli' -__date__ = 'May 2015' -__copyright__ = '(C) 2015, Luigi Pirelli' +__author__ = "Luigi Pirelli" +__date__ = "May 2015" +__copyright__ = "(C) 2015, Luigi Pirelli" import html import pathlib from qgis.PyQt.QtCore import QCoreApplication -from qgis.core import (QgsProcessing, - QgsProcessingException, - QgsProcessingParameterMultipleLayers, - QgsProcessingParameterBoolean, - QgsProcessingParameterVectorDestination, - QgsProcessingOutputString, - QgsProcessingParameters - ) +from qgis.core import ( + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterMultipleLayers, + QgsProcessingParameterBoolean, + QgsProcessingParameterVectorDestination, + QgsProcessingOutputString, + QgsProcessingParameters, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils class Datasources2Vrt(GdalAlgorithm): - INPUT = 'INPUT' - UNIONED = 'UNIONED' - OUTPUT = 'OUTPUT' - VRT_STRING = 'VRT_STRING' + INPUT = "INPUT" + UNIONED = "UNIONED" + OUTPUT = "OUTPUT" + VRT_STRING = "VRT_STRING" def createCustomParametersWidget(self, parent): return None def group(self): - return self.tr('Vector miscellaneous') + return self.tr("Vector miscellaneous") def groupId(self): - return 'vectormiscellaneous' + return "vectormiscellaneous" def name(self): - return 'buildvirtualvector' + return "buildvirtualvector" def displayName(self): - return self.tr('Build virtual vector') + return self.tr("Build virtual vector") def tags(self): - return ['ogr', 'gdal', 'vrt', 'create'] + return ["ogr", "gdal", "vrt", "create"] def shortHelpString(self): - return self.tr("This algorithm creates a virtual layer that contains a set of vector layers.") + return self.tr( + "This algorithm creates a virtual layer that contains a set of vector layers." + ) def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterMultipleLayers(self.INPUT, - self.tr('Input datasources'), - QgsProcessing.SourceType.TypeVector)) - self.addParameter(QgsProcessingParameterBoolean(self.UNIONED, - self.tr('Create "unioned" VRT'), - defaultValue=False)) + self.addParameter( + QgsProcessingParameterMultipleLayers( + self.INPUT, + self.tr("Input datasources"), + QgsProcessing.SourceType.TypeVector, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.UNIONED, self.tr('Create "unioned" VRT'), defaultValue=False + ) + ) class ParameterVectorVrtDestination(QgsProcessingParameterVectorDestination): @@ -83,31 +92,39 @@ def clone(self): return copy def defaultFileExtension(self): - return 'vrt' + return "vrt" def createFileFilter(self): - return '{} (*.vrt *.VRT)'.format(QCoreApplication.translate("GdalAlgorithm", 'VRT files')) + return "{} (*.vrt *.VRT)".format( + QCoreApplication.translate("GdalAlgorithm", "VRT files") + ) def supportedOutputRasterLayerExtensions(self): - return ['vrt'] + return ["vrt"] def isSupportedOutputValue(self, value, context): - output_path = QgsProcessingParameters.parameterAsOutputLayer(self, value, context, testOnly=True) - if pathlib.Path(output_path).suffix.lower() != '.vrt': - return False, QCoreApplication.translate("GdalAlgorithm", 'Output filename must use a .vrt extension') - return True, '' - - self.addParameter(ParameterVectorVrtDestination(self.OUTPUT, - self.tr('Virtual vector'))) - self.addOutput(QgsProcessingOutputString(self.VRT_STRING, - self.tr('Virtual string'))) + output_path = QgsProcessingParameters.parameterAsOutputLayer( + self, value, context, testOnly=True + ) + if pathlib.Path(output_path).suffix.lower() != ".vrt": + return False, QCoreApplication.translate( + "GdalAlgorithm", "Output filename must use a .vrt extension" + ) + return True, "" + + self.addParameter( + ParameterVectorVrtDestination(self.OUTPUT, self.tr("Virtual vector")) + ) + self.addOutput( + QgsProcessingOutputString(self.VRT_STRING, self.tr("Virtual string")) + ) def processAlgorithm(self, parameters, context, feedback): input_layers = self.parameterAsLayerList(parameters, self.INPUT, context) unioned = self.parameterAsBoolean(parameters, self.UNIONED, context) vrtPath = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) - vrt = '' + vrt = "" if unioned: vrt += '' @@ -121,20 +138,20 @@ def processAlgorithm(self, parameters, context, feedback): layerName = GdalUtils.ogrLayerName(layer.source()) vrt += f'' - vrt += f'{html.escape(basePath, True)}' - vrt += f'{html.escape(layerName, True)}' - vrt += '' + vrt += f"{html.escape(basePath, True)}" + vrt += f"{html.escape(layerName, True)}" + vrt += "" feedback.setProgress(int(current * total)) if unioned: - vrt += '' - vrt += '' + vrt += "" + vrt += "" - with open(vrtPath, 'w', encoding='utf-8') as f: + with open(vrtPath, "w", encoding="utf-8") as f: f.write(vrt) return {self.OUTPUT: vrtPath, self.VRT_STRING: vrt} def commandName(self): - return '' + return "" diff --git a/python/plugins/processing/algs/gdal/Dissolve.py b/python/plugins/processing/algs/gdal/Dissolve.py index 8430a5142778..133dca5e585c 100644 --- a/python/plugins/processing/algs/gdal/Dissolve.py +++ b/python/plugins/processing/algs/gdal/Dissolve.py @@ -15,104 +15,137 @@ *************************************************************************** """ -__author__ = 'Giovanni Manghi' -__date__ = 'January 2015' -__copyright__ = '(C) 2015, Giovanni Manghi' - -from qgis.core import (QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterField, - QgsProcessingParameterString, - QgsProcessingParameterBoolean, - QgsProcessingParameterVectorDestination) +__author__ = "Giovanni Manghi" +__date__ = "January 2015" +__copyright__ = "(C) 2015, Giovanni Manghi" + +from qgis.core import ( + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingParameterString, + QgsProcessingParameterBoolean, + QgsProcessingParameterVectorDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils class Dissolve(GdalAlgorithm): - INPUT = 'INPUT' - FIELD = 'FIELD' - GEOMETRY = 'GEOMETRY' - EXPLODE_COLLECTIONS = 'EXPLODE_COLLECTIONS' - KEEP_ATTRIBUTES = 'KEEP_ATTRIBUTES' - COUNT_FEATURES = 'COUNT_FEATURES' - COMPUTE_AREA = 'COMPUTE_AREA' - COMPUTE_STATISTICS = 'COMPUTE_STATISTICS' - STATISTICS_ATTRIBUTE = 'STATISTICS_ATTRIBUTE' - OPTIONS = 'OPTIONS' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + FIELD = "FIELD" + GEOMETRY = "GEOMETRY" + EXPLODE_COLLECTIONS = "EXPLODE_COLLECTIONS" + KEEP_ATTRIBUTES = "KEEP_ATTRIBUTES" + COUNT_FEATURES = "COUNT_FEATURES" + COMPUTE_AREA = "COMPUTE_AREA" + COMPUTE_STATISTICS = "COMPUTE_STATISTICS" + STATISTICS_ATTRIBUTE = "STATISTICS_ATTRIBUTE" + OPTIONS = "OPTIONS" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterField(self.FIELD, - self.tr('Dissolve field'), - None, - self.INPUT, - QgsProcessingParameterField.DataType.Any, optional=True)) - self.addParameter(QgsProcessingParameterString(self.GEOMETRY, - self.tr('Geometry column name'), - defaultValue='geometry')) + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterField( + self.FIELD, + self.tr("Dissolve field"), + None, + self.INPUT, + QgsProcessingParameterField.DataType.Any, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.GEOMETRY, self.tr("Geometry column name"), defaultValue="geometry" + ) + ) params = [ - QgsProcessingParameterBoolean(self.EXPLODE_COLLECTIONS, - self.tr('Produce one feature for each geometry in any kind of geometry collection in the source file'), - defaultValue=False,), - QgsProcessingParameterBoolean(self.KEEP_ATTRIBUTES, - self.tr('Keep input attributes'), - defaultValue=False), - QgsProcessingParameterBoolean(self.COUNT_FEATURES, - self.tr('Count dissolved features'), - defaultValue=False), - QgsProcessingParameterBoolean(self.COMPUTE_AREA, - self.tr('Compute area and perimeter of dissolved features'), - defaultValue=False), - QgsProcessingParameterBoolean(self.COMPUTE_STATISTICS, - self.tr('Compute min/max/sum/mean for attribute'), - defaultValue=False), - QgsProcessingParameterField(self.STATISTICS_ATTRIBUTE, - self.tr('Numeric attribute to calculate statistics on'), - None, - self.INPUT, - QgsProcessingParameterField.DataType.Numeric, - optional=True), - QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) + QgsProcessingParameterBoolean( + self.EXPLODE_COLLECTIONS, + self.tr( + "Produce one feature for each geometry in any kind of geometry collection in the source file" + ), + defaultValue=False, + ), + QgsProcessingParameterBoolean( + self.KEEP_ATTRIBUTES, + self.tr("Keep input attributes"), + defaultValue=False, + ), + QgsProcessingParameterBoolean( + self.COUNT_FEATURES, + self.tr("Count dissolved features"), + defaultValue=False, + ), + QgsProcessingParameterBoolean( + self.COMPUTE_AREA, + self.tr("Compute area and perimeter of dissolved features"), + defaultValue=False, + ), + QgsProcessingParameterBoolean( + self.COMPUTE_STATISTICS, + self.tr("Compute min/max/sum/mean for attribute"), + defaultValue=False, + ), + QgsProcessingParameterField( + self.STATISTICS_ATTRIBUTE, + self.tr("Numeric attribute to calculate statistics on"), + None, + self.INPUT, + QgsProcessingParameterField.DataType.Numeric, + optional=True, + ), + QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ), ] for param in params: - param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + param.setFlags( + param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(param) - self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT, - self.tr('Dissolved'))) + self.addParameter( + QgsProcessingParameterVectorDestination(self.OUTPUT, self.tr("Dissolved")) + ) def name(self): - return 'dissolve' + return "dissolve" def displayName(self): - return self.tr('Dissolve') + return self.tr("Dissolve") def group(self): - return self.tr('Vector geoprocessing') + return self.tr("Vector geoprocessing") def groupId(self): - return 'vectorgeoprocessing' + return "vectorgeoprocessing" def commandName(self): - return 'ogr2ogr' + return "ogr2ogr" def getConsoleCommands(self, parameters, context, feedback, executing=True): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) fields = source.fields() - input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing) + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) geometry = self.parameterAsString(parameters, self.GEOMETRY, context) fieldName = self.parameterAsString(parameters, self.FIELD, context) @@ -122,51 +155,66 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context) - other_fields_exist = any( - True for f in fields - if f.name() != geometry - ) + other_fields_exist = any(True for f in fields if f.name() != geometry) - other_fields = ',*' if other_fields_exist else '' + other_fields = ",*" if other_fields_exist else "" arguments = [ output_details.connection_string, input_details.connection_string, - '-nlt PROMOTE_TO_MULTI', - '-dialect', - 'sqlite', - '-sql', + "-nlt PROMOTE_TO_MULTI", + "-dialect", + "sqlite", + "-sql", ] tokens = [] if self.parameterAsBoolean(parameters, self.COUNT_FEATURES, context): - tokens.append(f'COUNT({geometry}) AS count') + tokens.append(f"COUNT({geometry}) AS count") if self.parameterAsBoolean(parameters, self.COMPUTE_AREA, context): - tokens.append('SUM(ST_Area({0})) AS area, ST_Perimeter(ST_Union({0})) AS perimeter'.format(geometry)) - - statsField = self.parameterAsString(parameters, self.STATISTICS_ATTRIBUTE, context) - if statsField and self.parameterAsBoolean(parameters, self.COMPUTE_STATISTICS, context): - tokens.append('SUM("{0}") AS sum, MIN("{0}") AS min, MAX("{0}") AS max, AVG("{0}") AS avg'.format(statsField)) - - params = ','.join(tokens) + tokens.append( + "SUM(ST_Area({0})) AS area, ST_Perimeter(ST_Union({0})) AS perimeter".format( + geometry + ) + ) + + statsField = self.parameterAsString( + parameters, self.STATISTICS_ATTRIBUTE, context + ) + if statsField and self.parameterAsBoolean( + parameters, self.COMPUTE_STATISTICS, context + ): + tokens.append( + 'SUM("{0}") AS sum, MIN("{0}") AS min, MAX("{0}") AS max, AVG("{0}") AS avg'.format( + statsField + ) + ) + + params = ",".join(tokens) if params: - params = ', ' + params + params = ", " + params - group_by = '' + group_by = "" if fieldName: group_by = f' GROUP BY "{fieldName}"' if self.parameterAsBoolean(parameters, self.KEEP_ATTRIBUTES, context): sql = f'SELECT ST_Union({geometry}) AS {geometry}{other_fields}{params} FROM "{input_details.layer_name}"{group_by}' else: - sql = 'SELECT ST_Union({}) AS {}{}{} FROM "{}"{}'.format(geometry, geometry, f', "{fieldName}"' if fieldName else '', - params, input_details.layer_name, group_by) + sql = 'SELECT ST_Union({}) AS {}{}{} FROM "{}"{}'.format( + geometry, + geometry, + f', "{fieldName}"' if fieldName else "", + params, + input_details.layer_name, + group_by, + ) arguments.append(sql) if self.parameterAsBoolean(parameters, self.EXPLODE_COLLECTIONS, context): - arguments.append('-explodecollections') + arguments.append("-explodecollections") if input_details.open_options: arguments.extend(input_details.open_options_as_arguments()) @@ -178,6 +226,6 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments.append(options) if output_details.format: - arguments.append(f'-f {output_details.format}') + arguments.append(f"-f {output_details.format}") return [self.commandName(), GdalUtils.escapeAndJoin(arguments)] diff --git a/python/plugins/processing/algs/gdal/ExecuteSql.py b/python/plugins/processing/algs/gdal/ExecuteSql.py index 3f30867b353b..e866395a1620 100644 --- a/python/plugins/processing/algs/gdal/ExecuteSql.py +++ b/python/plugins/processing/algs/gdal/ExecuteSql.py @@ -15,75 +15,91 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'November 2012' -__copyright__ = '(C) 2012, Victor Olaya' - -from qgis.core import (QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterEnum, - QgsProcessingParameterString, - QgsProcessingParameterVectorDestination) +__author__ = "Victor Olaya" +__date__ = "November 2012" +__copyright__ = "(C) 2012, Victor Olaya" + +from qgis.core import ( + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterEnum, + QgsProcessingParameterString, + QgsProcessingParameterVectorDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils class ExecuteSql(GdalAlgorithm): - INPUT = 'INPUT' - SQL = 'SQL' - DIALECT = 'DIALECT' - OPTIONS = 'OPTIONS' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + SQL = "SQL" + DIALECT = "DIALECT" + OPTIONS = "OPTIONS" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.dialects = ((self.tr('None'), ''), - (self.tr('OGR SQL'), 'ogrsql'), - (self.tr('SQLite'), 'sqlite')) - - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterString(self.SQL, - self.tr('SQL expression'), - defaultValue='')) - self.addParameter(QgsProcessingParameterEnum(self.DIALECT, - self.tr('SQL dialect'), - options=[i[0] for i in self.dialects], - allowMultiple=False, - defaultValue=0)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.dialects = ( + (self.tr("None"), ""), + (self.tr("OGR SQL"), "ogrsql"), + (self.tr("SQLite"), "sqlite"), + ) + + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterString( + self.SQL, self.tr("SQL expression"), defaultValue="" + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.DIALECT, + self.tr("SQL dialect"), + options=[i[0] for i in self.dialects], + allowMultiple=False, + defaultValue=0, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(options_param) - self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT, - self.tr('SQL result'))) + self.addParameter( + QgsProcessingParameterVectorDestination(self.OUTPUT, self.tr("SQL result")) + ) def name(self): - return 'executesql' + return "executesql" def displayName(self): - return self.tr('Execute SQL') + return self.tr("Execute SQL") def group(self): - return self.tr('Vector miscellaneous') + return self.tr("Vector miscellaneous") def groupId(self): - return 'vectormiscellaneous' + return "vectormiscellaneous" def commandName(self): return "ogr2ogr" def getConsoleCommands(self, parameters, context, feedback, executing=True): - input_details = self.getOgrCompatibleSource(self.INPUT, - parameters, context, - feedback, executing) + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) sql = self.parameterAsString(parameters, self.SQL, context) options = self.parameterAsString(parameters, self.OPTIONS, context) outFile = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) @@ -93,17 +109,20 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if not sql: raise QgsProcessingException( - self.tr('Empty SQL. Please enter valid SQL expression and try again.')) + self.tr("Empty SQL. Please enter valid SQL expression and try again.") + ) arguments = [ output_details.connection_string, input_details.connection_string, - '-sql', - sql + "-sql", + sql, ] - dialect = self.dialects[self.parameterAsEnum(parameters, self.DIALECT, context)][1] + dialect = self.dialects[ + self.parameterAsEnum(parameters, self.DIALECT, context) + ][1] if dialect: - arguments.append('-dialect') + arguments.append("-dialect") arguments.append(dialect) if input_details.open_options: @@ -116,6 +135,6 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments.append(options) if output_details.format: - arguments.append(f'-f {output_details.format}') + arguments.append(f"-f {output_details.format}") return [self.commandName(), GdalUtils.escapeAndJoin(arguments)] diff --git a/python/plugins/processing/algs/gdal/GdalAlgorithm.py b/python/plugins/processing/algs/gdal/GdalAlgorithm.py index d896673a45ca..6ce5279ba254 100644 --- a/python/plugins/processing/algs/gdal/GdalAlgorithm.py +++ b/python/plugins/processing/algs/gdal/GdalAlgorithm.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import re @@ -25,23 +25,23 @@ from qgis.PyQt.QtCore import QUrl, QCoreApplication -from qgis.core import (QgsApplication, - QgsVectorFileWriter, - QgsProcessingFeatureSourceDefinition, - QgsProcessingAlgorithm, - QgsProcessingContext, - QgsProcessingFeedback, - QgsProviderRegistry, - QgsDataSourceUri) +from qgis.core import ( + QgsApplication, + QgsVectorFileWriter, + QgsProcessingFeatureSourceDefinition, + QgsProcessingAlgorithm, + QgsProcessingContext, + QgsProcessingFeedback, + QgsProviderRegistry, + QgsDataSourceUri, +) from processing.algs.gdal.GdalAlgorithmDialog import GdalAlgorithmDialog -from processing.algs.gdal.GdalUtils import ( - GdalUtils, - GdalConnectionDetails -) +from processing.algs.gdal.GdalUtils import GdalUtils, GdalConnectionDetails -pluginPath = os.path.normpath(os.path.join( - os.path.split(os.path.dirname(__file__))[0], os.pardir)) +pluginPath = os.path.normpath( + os.path.join(os.path.split(os.path.dirname(__file__))[0], os.pardir) +) class GdalAlgorithm(QgsProcessingAlgorithm): @@ -54,7 +54,7 @@ def icon(self): return QgsApplication.getThemeIcon("/providerGdal.svg") def tags(self): - return ['ogr', 'gdal', self.commandName()] + return ["ogr", "gdal", self.commandName()] def svgIconPath(self): return QgsApplication.iconPath("providerGdal.svg") @@ -68,76 +68,102 @@ def createCustomParametersWidget(self, parent): def getConsoleCommands(self, parameters, context, feedback, executing=True): return None - def getOgrCompatibleSource(self, - parameter_name: str, - parameters: Dict, - context: QgsProcessingContext, - feedback: QgsProcessingFeedback, - executing: bool) -> GdalConnectionDetails: + def getOgrCompatibleSource( + self, + parameter_name: str, + parameters: dict, + context: QgsProcessingContext, + feedback: QgsProcessingFeedback, + executing: bool, + ) -> GdalConnectionDetails: """ Interprets a parameter as a GDAL connection details """ - if not executing and parameter_name in parameters and isinstance(parameters[parameter_name], QgsProcessingFeatureSourceDefinition): + if ( + not executing + and parameter_name in parameters + and isinstance( + parameters[parameter_name], QgsProcessingFeatureSourceDefinition + ) + ): # if not executing, then we throw away all 'selected features only' settings # since these have no meaning for command line gdal use, and we don't want to force # an export of selected features only to a temporary file just to show the command! parameters = {parameter_name: parameters[parameter_name].source} input_layer = self.parameterAsVectorLayer(parameters, parameter_name, context) - if input_layer is None or input_layer.providerType() in ('memory', 'grass'): + if input_layer is None or input_layer.providerType() in ("memory", "grass"): if executing: # parameter is not a vector layer - try to convert to a source compatible with OGR # and extract selection if required - ogr_data_path = self.parameterAsCompatibleSourceLayerPath(parameters, parameter_name, context, - QgsVectorFileWriter.supportedFormatExtensions(), - QgsVectorFileWriter.supportedFormatExtensions()[0], - feedback=feedback) + ogr_data_path = self.parameterAsCompatibleSourceLayerPath( + parameters, + parameter_name, + context, + QgsVectorFileWriter.supportedFormatExtensions(), + QgsVectorFileWriter.supportedFormatExtensions()[0], + feedback=feedback, + ) return GdalConnectionDetails( connection_string=ogr_data_path, - layer_name=GdalUtils.ogrLayerName(ogr_data_path) + layer_name=GdalUtils.ogrLayerName(ogr_data_path), ) else: # not executing - don't waste time converting incompatible sources, just return dummy strings # for the command preview (since the source isn't compatible with OGR, it has no meaning anyway and can't # be run directly in the command line) return GdalConnectionDetails( - connection_string='path_to_data_file', - layer_name='layer_name' + connection_string="path_to_data_file", layer_name="layer_name" ) - elif input_layer.providerType() == 'ogr': - if executing and (isinstance(parameters[parameter_name], QgsProcessingFeatureSourceDefinition) and parameters[parameter_name].selectedFeaturesOnly) \ - or input_layer.subsetString(): + elif input_layer.providerType() == "ogr": + if ( + executing + and ( + isinstance( + parameters[parameter_name], QgsProcessingFeatureSourceDefinition + ) + and parameters[parameter_name].selectedFeaturesOnly + ) + or input_layer.subsetString() + ): # parameter is a vector layer, with OGR data provider # so extract selection if required - ogr_data_path = self.parameterAsCompatibleSourceLayerPath(parameters, parameter_name, context, - QgsVectorFileWriter.supportedFormatExtensions(), - feedback=feedback) - parts = QgsProviderRegistry.instance().decodeUri('ogr', ogr_data_path) - ogr_data_path = parts['path'] - if 'layerName' in parts and parts['layerName']: - ogr_layer_name = parts['layerName'] + ogr_data_path = self.parameterAsCompatibleSourceLayerPath( + parameters, + parameter_name, + context, + QgsVectorFileWriter.supportedFormatExtensions(), + feedback=feedback, + ) + parts = QgsProviderRegistry.instance().decodeUri("ogr", ogr_data_path) + ogr_data_path = parts["path"] + if "layerName" in parts and parts["layerName"]: + ogr_layer_name = parts["layerName"] else: ogr_layer_name = GdalUtils.ogrLayerName(ogr_data_path) return GdalConnectionDetails( connection_string=ogr_data_path, layer_name=ogr_layer_name, - open_options=parts.get('openOptions', None), - credential_options=parts.get('credentialOptions', None) + open_options=parts.get("openOptions", None), + credential_options=parts.get("credentialOptions", None), ) else: # either not using the selection, or # not executing - don't worry about 'selected features only' handling. It has no meaning # for the command line preview since it has no meaning outside of a QGIS session! - connection_details = GdalUtils.gdal_connection_details_from_layer(input_layer) - connection_details.layer_name = GdalUtils.ogrLayerName(input_layer.source()) + connection_details = GdalUtils.gdal_connection_details_from_layer( + input_layer + ) + connection_details.layer_name = GdalUtils.ogrLayerName( + input_layer.source() + ) return connection_details - elif input_layer.providerType().lower() == 'wfs': + elif input_layer.providerType().lower() == "wfs": uri = QgsDataSourceUri(input_layer.source()) - baseUrl = uri.param('url').split('?')[0] + baseUrl = uri.param("url").split("?")[0] return GdalConnectionDetails( - connection_string=f"WFS:{baseUrl}", - layer_name=uri.param('typename') + connection_string=f"WFS:{baseUrl}", layer_name=uri.param("typename") ) # vector layer, but not OGR - get OGR compatible path @@ -150,7 +176,9 @@ def setOutputValue(self, name, value): self.output_values[name] = value def processAlgorithm(self, parameters, context, feedback): - commands = self.getConsoleCommands(parameters, context, feedback, executing=True) + commands = self.getConsoleCommands( + parameters, context, feedback, executing=True + ) GdalUtils.runGdal(commands, feedback) # auto generate outputs @@ -164,18 +192,17 @@ def processAlgorithm(self, parameters, context, feedback): return results def commandName(self): - parameters = { - param.name(): "1" - for param in self.parameterDefinitions() - } + parameters = {param.name(): "1" for param in self.parameterDefinitions()} context = QgsProcessingContext() feedback = QgsProcessingFeedback() - name = self.getConsoleCommands(parameters, context, feedback, executing=False)[0] + name = self.getConsoleCommands(parameters, context, feedback, executing=False)[ + 0 + ] if name.endswith(".py"): name = name[:-3] return name - def tr(self, string, context=''): - if context == '': + def tr(self, string, context=""): + if context == "": context = self.__class__.__name__ return QCoreApplication.translate(context, string) diff --git a/python/plugins/processing/algs/gdal/GdalAlgorithmDialog.py b/python/plugins/processing/algs/gdal/GdalAlgorithmDialog.py index f2ac01f5bb8f..618af021698f 100644 --- a/python/plugins/processing/algs/gdal/GdalAlgorithmDialog.py +++ b/python/plugins/processing/algs/gdal/GdalAlgorithmDialog.py @@ -15,31 +15,35 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'May 2015' -__copyright__ = '(C) 2015, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "May 2015" +__copyright__ = "(C) 2015, Victor Olaya" from qgis.PyQt.QtCore import QCoreApplication -from qgis.PyQt.QtWidgets import (QWidget, - QVBoxLayout, - QPushButton, - QLabel, - QPlainTextEdit, - QLineEdit, - QComboBox, - QCheckBox, - QSizePolicy, - QDialogButtonBox) +from qgis.PyQt.QtWidgets import ( + QWidget, + QVBoxLayout, + QPushButton, + QLabel, + QPlainTextEdit, + QLineEdit, + QComboBox, + QCheckBox, + QSizePolicy, + QDialogButtonBox, +) from qgis.core import ( QgsProcessingException, QgsProcessingFeedback, - QgsProcessingParameterDefinition + QgsProcessingParameterDefinition, +) +from qgis.gui import ( + QgsMessageBar, + QgsProjectionSelectionWidget, + QgsProcessingAlgorithmDialogBase, + QgsProcessingLayerOutputDestinationWidget, ) -from qgis.gui import (QgsMessageBar, - QgsProjectionSelectionWidget, - QgsProcessingAlgorithmDialogBase, - QgsProcessingLayerOutputDestinationWidget) from processing.gui.AlgorithmDialog import AlgorithmDialog from processing.gui.AlgorithmDialogBase import AlgorithmDialogBase @@ -124,30 +128,48 @@ def parametersHaveChanged(self): # messy as all heck, but we don't want to call the dialog's implementation of # createProcessingParameters as we want to catch the exceptions raised by the # parameter panel instead... - parameters = {} if self.dialog.mainWidget() is None else self.dialog.mainWidget().createProcessingParameters() + parameters = ( + {} + if self.dialog.mainWidget() is None + else self.dialog.mainWidget().createProcessingParameters() + ) for output in self.algorithm().destinationParameterDefinitions(): if not output.name() in parameters or parameters[output.name()] is None: - if not output.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: + if ( + not output.flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ): parameters[output.name()] = self.tr("[temporary file]") for p in self.algorithm().parameterDefinitions(): if p.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden: continue - if p.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional and p.name() not in parameters: + if ( + p.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + and p.name() not in parameters + ): continue - if p.name() not in parameters or not p.checkValueIsAcceptable(parameters[p.name()]): + if p.name() not in parameters or not p.checkValueIsAcceptable( + parameters[p.name()] + ): # not ready yet - self.text.setPlainText('') + self.text.setPlainText("") return try: - commands = self.algorithm().getConsoleCommands(parameters, context, feedback, executing=False) - commands = [c for c in commands if c not in ['cmd.exe', '/C ']] + commands = self.algorithm().getConsoleCommands( + parameters, context, feedback, executing=False + ) + commands = [c for c in commands if c not in ["cmd.exe", "/C "]] self.text.setPlainText(" ".join(commands)) except QgsProcessingException as e: self.text.setPlainText(str(e)) except AlgorithmDialogBase.InvalidParameterValue as e: - self.text.setPlainText(self.tr("Invalid value for parameter '{0}'").format(e.parameter.description())) + self.text.setPlainText( + self.tr("Invalid value for parameter '{0}'").format( + e.parameter.description() + ) + ) except AlgorithmDialogBase.InvalidOutputExtension as e: self.text.setPlainText(e.message) diff --git a/python/plugins/processing/algs/gdal/GdalAlgorithmProvider.py b/python/plugins/processing/algs/gdal/GdalAlgorithmProvider.py index 7b1baea846e2..ad88e08d2860 100644 --- a/python/plugins/processing/algs/gdal/GdalAlgorithmProvider.py +++ b/python/plugins/processing/algs/gdal/GdalAlgorithmProvider.py @@ -15,18 +15,16 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os from osgeo import gdal from qgis.PyQt.QtCore import QCoreApplication -from qgis.core import (QgsApplication, - QgsProcessingProvider, - QgsRuntimeProfiler) +from qgis.core import QgsApplication, QgsProcessingProvider, QgsRuntimeProfiler from processing.core.ProcessingConfig import ProcessingConfig, Setting from .GdalUtils import GdalUtils @@ -90,8 +88,9 @@ # from .ogr2ogrtabletopostgislist import Ogr2OgrTableToPostGisList -pluginPath = os.path.normpath(os.path.join( - os.path.split(os.path.dirname(__file__))[0], os.pardir)) +pluginPath = os.path.normpath( + os.path.join(os.path.split(os.path.dirname(__file__))[0], os.pardir) +) gdal.UseExceptions() @@ -101,38 +100,41 @@ class GdalAlgorithmProvider(QgsProcessingProvider): def __init__(self): super().__init__() self.algs = [] - QgsApplication.processingRegistry().addAlgorithmAlias('qgis:buildvirtualvector', 'gdal:buildvirtualvector') + QgsApplication.processingRegistry().addAlgorithmAlias( + "qgis:buildvirtualvector", "gdal:buildvirtualvector" + ) def load(self): - with QgsRuntimeProfiler.profile('GDAL Provider'): + with QgsRuntimeProfiler.profile("GDAL Provider"): ProcessingConfig.settingIcons[self.name()] = self.icon() - ProcessingConfig.addSetting(Setting(self.name(), 'ACTIVATE_GDAL', - self.tr('Activate'), True)) + ProcessingConfig.addSetting( + Setting(self.name(), "ACTIVATE_GDAL", self.tr("Activate"), True) + ) ProcessingConfig.readSettings() self.refreshAlgorithms() return True def unload(self): - ProcessingConfig.removeSetting('ACTIVATE_GDAL') + ProcessingConfig.removeSetting("ACTIVATE_GDAL") def isActive(self): - return ProcessingConfig.getSetting('ACTIVATE_GDAL') + return ProcessingConfig.getSetting("ACTIVATE_GDAL") def setActive(self, active): - ProcessingConfig.setSettingValue('ACTIVATE_GDAL', active) + ProcessingConfig.setSettingValue("ACTIVATE_GDAL", active) def name(self): - return 'GDAL' + return "GDAL" def longName(self): version = GdalUtils.readableVersion() - return f'GDAL ({version})' + return f"GDAL ({version})" def id(self): - return 'gdal' + return "gdal" def helpId(self): - return 'gdal' + return "gdal" def icon(self): return QgsApplication.getThemeIcon("/providerGdal.svg") @@ -220,7 +222,7 @@ def supportsNonFileBasedOutput(self): """ return False - def tr(self, string, context=''): - if context == '': - context = 'GdalAlgorithmProvider' + def tr(self, string, context=""): + if context == "": + context = "GdalAlgorithmProvider" return QCoreApplication.translate(context, string) diff --git a/python/plugins/processing/algs/gdal/GdalUtils.py b/python/plugins/processing/algs/gdal/GdalUtils.py index c4a2f21498bb..dde752aef547 100644 --- a/python/plugins/processing/algs/gdal/GdalUtils.py +++ b/python/plugins/processing/algs/gdal/GdalUtils.py @@ -15,15 +15,11 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' - -from typing import ( - Dict, - List, - Optional -) +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" + +from typing import Dict, List, Optional import os import subprocess import platform @@ -49,13 +45,10 @@ QgsProcessingException, QgsProviderRegistry, QgsMapLayer, - QgsProcessingContext + QgsProcessingContext, ) -from qgis.PyQt.QtCore import ( - QCoreApplication, - QProcess -) +from qgis.PyQt.QtCore import QCoreApplication, QProcess @dataclass @@ -63,35 +56,37 @@ class GdalConnectionDetails: """ Encapsulates connection details for a layer """ + connection_string: Optional[str] = None format: Optional[str] = None - open_options: Optional[List[str]] = None + open_options: Optional[list[str]] = None layer_name: Optional[str] = None - credential_options: Optional[Dict] = None + credential_options: Optional[dict] = None - def open_options_as_arguments(self) -> List[str]: + def open_options_as_arguments(self) -> list[str]: """ Returns any open options as a list of arguments """ res = [] for option in self.open_options: - res.append(f'-oo {option}') + res.append(f"-oo {option}") return res - def credential_options_as_arguments(self) -> List[str]: + def credential_options_as_arguments(self) -> list[str]: """ Returns any credential options as a list of arguments """ res = [] for key, value in self.credential_options.items(): - res.append(f'--config {key} {value}') + res.append(f"--config {key} {value}") return res try: from osgeo import gdal, ogr + gdal.UseExceptions() ogr.UseExceptions() @@ -101,7 +96,7 @@ def credential_options_as_arguments(self) -> List[str]: class GdalUtils: - GDAL_HELP_PATH = 'GDAL_HELP_PATH' + GDAL_HELP_PATH = "GDAL_HELP_PATH" supportedRasters = None supportedOutputRasters = None @@ -110,44 +105,50 @@ class GdalUtils: def runGdal(commands, feedback=None): if feedback is None: feedback = QgsProcessingFeedback() - envval = os.getenv('PATH') + envval = os.getenv("PATH") # We need to give some extra hints to get things picked up on OS X isDarwin = False try: - isDarwin = platform.system() == 'Darwin' + isDarwin = platform.system() == "Darwin" except OSError: # https://travis-ci.org/m-kuhn/QGIS#L1493-L1526 pass - if isDarwin and os.path.isfile(os.path.join(QgsApplication.prefixPath(), "bin", "gdalinfo")): + if isDarwin and os.path.isfile( + os.path.join(QgsApplication.prefixPath(), "bin", "gdalinfo") + ): # Looks like there's a bundled gdal. Let's use it. - os.environ['PATH'] = "{}{}{}".format(os.path.join(QgsApplication.prefixPath(), "bin"), os.pathsep, envval) - os.environ['DYLD_LIBRARY_PATH'] = os.path.join(QgsApplication.prefixPath(), "lib") + os.environ["PATH"] = "{}{}{}".format( + os.path.join(QgsApplication.prefixPath(), "bin"), os.pathsep, envval + ) + os.environ["DYLD_LIBRARY_PATH"] = os.path.join( + QgsApplication.prefixPath(), "lib" + ) else: # Other platforms should use default gdal finder codepath settings = QgsSettings() - path = settings.value('/GdalTools/gdalPath', '') + path = settings.value("/GdalTools/gdalPath", "") if not path.lower() in envval.lower().split(os.pathsep): - envval += f'{os.pathsep}{path}' - os.putenv('PATH', envval) + envval += f"{os.pathsep}{path}" + os.putenv("PATH", envval) - fused_command = ' '.join([str(c) for c in commands]) - QgsMessageLog.logMessage(fused_command, 'Processing', Qgis.MessageLevel.Info) - feedback.pushInfo(GdalUtils.tr('GDAL command:')) + fused_command = " ".join([str(c) for c in commands]) + QgsMessageLog.logMessage(fused_command, "Processing", Qgis.MessageLevel.Info) + feedback.pushInfo(GdalUtils.tr("GDAL command:")) feedback.pushCommandInfo(fused_command) - feedback.pushInfo(GdalUtils.tr('GDAL command output:')) + feedback.pushInfo(GdalUtils.tr("GDAL command output:")) - loglines = [GdalUtils.tr('GDAL execution console output')] + loglines = [GdalUtils.tr("GDAL execution console output")] # create string list of number from 0 to 99 progress_string_list = [str(a) for a in range(0, 100)] def on_stdout(ba): - val = ba.data().decode('UTF-8') + val = ba.data().decode("UTF-8") # catch progress reports - if val == '100 - done.': + if val == "100 - done.": on_stdout.progress = 100 feedback.setProgress(on_stdout.progress) else: # remove any number of trailing "." or ".." strings - match = re.match(r'.*?(\d+)\.+\s*$', val) + match = re.match(r".*?(\d+)\.+\s*$", val) found_number = False if match: int_val = match.group(1) @@ -156,31 +157,31 @@ def on_stdout(ba): feedback.setProgress(on_stdout.progress) found_number = True - if not found_number and val == '.': + if not found_number and val == ".": on_stdout.progress += 2.5 feedback.setProgress(on_stdout.progress) on_stdout.buffer += val - if on_stdout.buffer.endswith('\n') or on_stdout.buffer.endswith('\r'): + if on_stdout.buffer.endswith("\n") or on_stdout.buffer.endswith("\r"): # flush buffer feedback.pushConsoleInfo(on_stdout.buffer.rstrip()) loglines.append(on_stdout.buffer.rstrip()) - on_stdout.buffer = '' + on_stdout.buffer = "" on_stdout.progress = 0 - on_stdout.buffer = '' + on_stdout.buffer = "" def on_stderr(ba): - val = ba.data().decode('UTF-8') + val = ba.data().decode("UTF-8") on_stderr.buffer += val - if on_stderr.buffer.endswith('\n') or on_stderr.buffer.endswith('\r'): + if on_stderr.buffer.endswith("\n") or on_stderr.buffer.endswith("\r"): # flush buffer feedback.reportError(on_stderr.buffer.rstrip()) loglines.append(on_stderr.buffer.rstrip()) - on_stderr.buffer = '' + on_stderr.buffer = "" - on_stderr.buffer = '' + on_stderr.buffer = "" command, *arguments = QgsRunProcess.splitCommand(fused_command) proc = QgsBlockingProcess(command, arguments) @@ -189,15 +190,26 @@ def on_stderr(ba): res = proc.run(feedback) if feedback.isCanceled() and res != 0: - feedback.pushInfo(GdalUtils.tr('Process was canceled and did not complete')) - elif not feedback.isCanceled() and proc.exitStatus() == QProcess.ExitStatus.CrashExit: - raise QgsProcessingException(GdalUtils.tr('Process was unexpectedly terminated')) + feedback.pushInfo(GdalUtils.tr("Process was canceled and did not complete")) + elif ( + not feedback.isCanceled() + and proc.exitStatus() == QProcess.ExitStatus.CrashExit + ): + raise QgsProcessingException( + GdalUtils.tr("Process was unexpectedly terminated") + ) elif res == 0: - feedback.pushInfo(GdalUtils.tr('Process completed successfully')) + feedback.pushInfo(GdalUtils.tr("Process completed successfully")) elif proc.processError() == QProcess.ProcessError.FailedToStart: - raise QgsProcessingException(GdalUtils.tr('Process {} failed to start. Either {} is missing, or you may have insufficient permissions to run the program.').format(command, command)) + raise QgsProcessingException( + GdalUtils.tr( + "Process {} failed to start. Either {} is missing, or you may have insufficient permissions to run the program." + ).format(command, command) + ) else: - feedback.reportError(GdalUtils.tr('Process returned error code {}').format(res)) + feedback.reportError( + GdalUtils.tr("Process returned error code {}").format(res) + ) return loglines @@ -214,8 +226,8 @@ def getSupportedRasters(): GdalUtils.supportedRasters = {} GdalUtils.supportedOutputRasters = {} - GdalUtils.supportedRasters['GTiff'] = ['tif', 'tiff'] - GdalUtils.supportedOutputRasters['GTiff'] = ['tif', 'tiff'] + GdalUtils.supportedRasters["GTiff"] = ["tif", "tiff"] + GdalUtils.supportedOutputRasters["GTiff"] = ["tif", "tiff"] for i in range(gdal.GetDriverCount()): driver = gdal.GetDriver(i) @@ -223,19 +235,21 @@ def getSupportedRasters(): continue shortName = driver.ShortName metadata = driver.GetMetadata() - if gdal.DCAP_RASTER not in metadata \ - or metadata[gdal.DCAP_RASTER] != 'YES': + if gdal.DCAP_RASTER not in metadata or metadata[gdal.DCAP_RASTER] != "YES": continue if gdal.DMD_EXTENSIONS in metadata: - extensions = metadata[gdal.DMD_EXTENSIONS].split(' ') + extensions = metadata[gdal.DMD_EXTENSIONS].split(" ") if extensions: GdalUtils.supportedRasters[shortName] = extensions # Only creatable rasters can be referenced in output rasters - if ((gdal.DCAP_CREATE in metadata and - metadata[gdal.DCAP_CREATE] == 'YES') or - (gdal.DCAP_CREATECOPY in metadata and - metadata[gdal.DCAP_CREATECOPY] == 'YES')): + if ( + gdal.DCAP_CREATE in metadata + and metadata[gdal.DCAP_CREATE] == "YES" + ) or ( + gdal.DCAP_CREATECOPY in metadata + and metadata[gdal.DCAP_CREATECOPY] == "YES" + ): GdalUtils.supportedOutputRasters[shortName] = extensions return GdalUtils.supportedRasters @@ -257,10 +271,10 @@ def getSupportedRasterExtensions(): allexts = [] for exts in list(GdalUtils.getSupportedRasters().values()): for ext in exts: - if ext not in allexts and ext not in ['', 'tif', 'tiff']: + if ext not in allexts and ext not in ["", "tif", "tiff"]: allexts.append(ext) allexts.sort() - allexts[0:0] = ['tif', 'tiff'] + allexts[0:0] = ["tif", "tiff"] return allexts @staticmethod @@ -268,63 +282,62 @@ def getSupportedOutputRasterExtensions(): allexts = [] for exts in list(GdalUtils.getSupportedOutputRasters().values()): for ext in exts: - if ext not in allexts and ext not in ['', 'tif', 'tiff']: + if ext not in allexts and ext not in ["", "tif", "tiff"]: allexts.append(ext) allexts.sort() - allexts[0:0] = ['tif', 'tiff'] + allexts[0:0] = ["tif", "tiff"] return allexts @staticmethod def getVectorDriverFromFileName(filename): ext = os.path.splitext(filename)[1] - if ext == '': - return 'ESRI Shapefile' + if ext == "": + return "ESRI Shapefile" formats = QgsVectorFileWriter.supportedFiltersAndFormats() for format in formats: if ext in format.filterString: return format.driverName - return 'ESRI Shapefile' + return "ESRI Shapefile" @staticmethod def getFormatShortNameFromFilename(filename): - ext = filename[filename.rfind('.') + 1:] + ext = filename[filename.rfind(".") + 1 :] supported = GdalUtils.getSupportedRasters() for name in list(supported.keys()): exts = supported[name] if ext in exts: return name - return 'GTiff' + return "GTiff" @staticmethod def escapeAndJoin(strList): - escChars = [' ', '&', '(', ')', '"', ';'] - joined = '' + escChars = [" ", "&", "(", ")", '"', ";"] + joined = "" for s in strList: if not isinstance(s, str): s = str(s) # don't escape if command starts with - and isn't a negative number, e.g. -9999 - if s and re.match(r'^([^-]|-\d)', s) and any(c in s for c in escChars): - escaped = '"' + s.replace('\\', '\\\\').replace('"', '"""') \ - + '"' + if s and re.match(r"^([^-]|-\d)", s) and any(c in s for c in escChars): + escaped = '"' + s.replace("\\", "\\\\").replace('"', '"""') + '"' else: escaped = s if escaped is not None: - joined += escaped + ' ' + joined += escaped + " " return joined.strip() @staticmethod def version(): - return int(gdal.VersionInfo('VERSION_NUM')) + return int(gdal.VersionInfo("VERSION_NUM")) @staticmethod def readableVersion(): - return gdal.VersionInfo('RELEASE_NAME') + return gdal.VersionInfo("RELEASE_NAME") @staticmethod def gdal_connection_details_from_uri( - uri: str, - context: QgsProcessingContext) -> GdalConnectionDetails: + uri: str, context: QgsProcessingContext + ) -> GdalConnectionDetails: """ Generates GDAL connection details from layer source """ @@ -332,10 +345,7 @@ def gdal_connection_details_from_uri( if layer is None: path, ext = os.path.splitext(uri) _format = QgsVectorFileWriter.driverForExtension(ext) - return GdalConnectionDetails( - connection_string=uri, - format=f'"{_format}"' - ) + return GdalConnectionDetails(connection_string=uri, format=f'"{_format}"') return GdalUtils.gdal_connection_details_from_layer(layer) @@ -345,15 +355,14 @@ def gdal_connection_details_from_layer(layer: QgsMapLayer) -> GdalConnectionDeta Builds GDAL connection details from a QGIS map layer """ provider = layer.providerType() - if provider == 'spatialite': + if provider == "spatialite": # dbname='/geodata/osm_ch.sqlite' table="places" (Geometry) sql= regex = re.compile("dbname='(.+)'") r = regex.search(str(layer.source())) return GdalConnectionDetails( - connection_string=r.groups()[0], - format='"SQLite"' + connection_string=r.groups()[0], format='"SQLite"' ) - elif provider == 'postgres': + elif provider == "postgres": # dbname='ktryjh_iuuqef' host=spacialdb.com port=9999 # user='ktryjh_iuuqef' password='xyqwer' sslmode=disable # key='gid' estimatedmetadata=true srid=4326 type=MULTIPOLYGON @@ -366,7 +375,9 @@ def gdal_connection_details_from_layer(layer: QgsMapLayer) -> GdalConnectionDeta try: conn = psycopg2.connect(dsUri.connectionInfo()) except psycopg2.OperationalError: - (ok, user, passwd) = QgsCredentials.instance().get(conninfo, dsUri.username(), dsUri.password()) + (ok, user, passwd) = QgsCredentials.instance().get( + conninfo, dsUri.username(), dsUri.password() + ) if not ok: break @@ -374,34 +385,32 @@ def gdal_connection_details_from_layer(layer: QgsMapLayer) -> GdalConnectionDeta dsUri.setPassword(passwd) if not conn: - raise RuntimeError('Could not connect to PostgreSQL database - check connection info') + raise RuntimeError( + "Could not connect to PostgreSQL database - check connection info" + ) if ok: QgsCredentials.instance().put(conninfo, user, passwd) return GdalConnectionDetails( - connection_string=f"PG:{dsUri.connectionInfo()}", - format='"PostgreSQL"' + connection_string=f"PG:{dsUri.connectionInfo()}", format='"PostgreSQL"' ) - elif provider == 'mssql': + elif provider == "mssql": # 'dbname=\'db_name\' host=myHost estimatedmetadata=true # srid=27700 type=MultiPolygon table="dbo"."my_table" # #(Shape) sql=' dsUri = layer.dataProvider().uri() - ogrstr = 'MSSQL:' - ogrstr += f'database={dsUri.database()};' - ogrstr += f'server={dsUri.host()};' + ogrstr = "MSSQL:" + ogrstr += f"database={dsUri.database()};" + ogrstr += f"server={dsUri.host()};" if dsUri.username() != "": - ogrstr += f'uid={dsUri.username()};' + ogrstr += f"uid={dsUri.username()};" else: - ogrstr += 'trusted_connection=yes;' - if dsUri.password() != '': - ogrstr += f'pwd={dsUri.password()};' - ogrstr += f'tables={dsUri.table()}' - return GdalConnectionDetails( - connection_string=ogrstr, - format='"MSSQL"' - ) + ogrstr += "trusted_connection=yes;" + if dsUri.password() != "": + ogrstr += f"pwd={dsUri.password()};" + ogrstr += f"tables={dsUri.table()}" + return GdalConnectionDetails(connection_string=ogrstr, format='"MSSQL"') elif provider == "oracle": # OCI:user/password@host:port/service:table dsUri = QgsDataSourceUri(layer.dataProvider().dataSourceUri()) @@ -415,7 +424,7 @@ def gdal_connection_details_from_layer(layer: QgsMapLayer) -> GdalConnectionDeta if dsUri.host() != "": ogrstr += delim + dsUri.host() delim = "" - if dsUri.port() not in ["", '1521']: + if dsUri.port() not in ["", "1521"]: ogrstr += ":" + dsUri.port() ogrstr += "/" if dsUri.database() != "": @@ -424,56 +433,50 @@ def gdal_connection_details_from_layer(layer: QgsMapLayer) -> GdalConnectionDeta ogrstr += delim + dsUri.database() if ogrstr == "OCI:": - raise RuntimeError('Invalid oracle data source - check connection info') + raise RuntimeError("Invalid oracle data source - check connection info") ogrstr += ":" if dsUri.schema() != "": ogrstr += dsUri.schema() + "." ogrstr += dsUri.table() - return GdalConnectionDetails( - connection_string=ogrstr, - format='"OCI"' - ) + return GdalConnectionDetails(connection_string=ogrstr, format='"OCI"') elif provider.lower() == "wfs": uri = QgsDataSourceUri(layer.source()) - baseUrl = uri.param('url').split('?')[0] + baseUrl = uri.param("url").split("?")[0] return GdalConnectionDetails( - connection_string=f"WFS:{baseUrl}", - format='"WFS"' + connection_string=f"WFS:{baseUrl}", format='"WFS"' ) elif provider.lower() == "ogr": - parts = QgsProviderRegistry.instance().decodeUri('ogr', - layer.source()) - if 'path' in parts: - path = parts['path'] - if 'vsiPrefix' in parts: - path = parts['vsiPrefix'] + path - - _, ext = os.path.splitext(parts['path']) + parts = QgsProviderRegistry.instance().decodeUri("ogr", layer.source()) + if "path" in parts: + path = parts["path"] + if "vsiPrefix" in parts: + path = parts["vsiPrefix"] + path + + _, ext = os.path.splitext(parts["path"]) format = QgsVectorFileWriter.driverForExtension(ext) return GdalConnectionDetails( connection_string=path, format=f'"{format}"', - open_options=parts.get('openOptions', None), - credential_options=parts.get('credentialOptions', None) + open_options=parts.get("openOptions", None), + credential_options=parts.get("credentialOptions", None), ) elif provider.lower() == "gdal": - parts = QgsProviderRegistry.instance().decodeUri('gdal', - layer.source()) - if 'path' in parts: - path = parts['path'] - if 'vsiPrefix' in parts: - path = parts['vsiPrefix'] + path + parts = QgsProviderRegistry.instance().decodeUri("gdal", layer.source()) + if "path" in parts: + path = parts["path"] + if "vsiPrefix" in parts: + path = parts["vsiPrefix"] + path return GdalConnectionDetails( connection_string=path, - open_options=parts.get('openOptions', None), - credential_options=parts.get('credentialOptions', None) + open_options=parts.get("openOptions", None), + credential_options=parts.get("credentialOptions", None), ) - elif provider == 'postgresraster': - gdal_source = '' + elif provider == "postgresraster": + gdal_source = "" uri = layer.dataProvider().uri() gdal_source = f"PG: {uri.connectionInfo()}" schema = uri.schema() @@ -481,28 +484,28 @@ def gdal_connection_details_from_layer(layer: QgsMapLayer) -> GdalConnectionDeta gdal_source += f" schema='{schema}'" table = uri.table() gdal_source += f" table='{table}'" - column = uri.param('column') or uri.geometryColumn() + column = uri.param("column") or uri.geometryColumn() if column: gdal_source += f" column='{column}'" - is_tiled = any([layer.dataProvider().xSize() != layer.dataProvider().xBlockSize(), - layer.dataProvider().ySize() != layer.dataProvider().yBlockSize()]) + is_tiled = any( + [ + layer.dataProvider().xSize() != layer.dataProvider().xBlockSize(), + layer.dataProvider().ySize() != layer.dataProvider().yBlockSize(), + ] + ) gdal_source += f" mode={2 if is_tiled else 1}" where = layer.dataProvider().subsetString() if where: gdal_source += f" where='{where}'" return GdalConnectionDetails( - connection_string=gdal_source, - format='"PostGISRaster"' + connection_string=gdal_source, format='"PostGISRaster"' ) ogrstr = str(layer.source()).split("|")[0] path, ext = os.path.splitext(ogrstr) format = QgsVectorFileWriter.driverForExtension(ext) - return GdalConnectionDetails( - connection_string=ogrstr, - format=f'"{format}"' - ) + return GdalConnectionDetails(connection_string=ogrstr, format=f'"{format}"') @staticmethod def ogrOutputLayerName(uri): @@ -512,31 +515,31 @@ def ogrOutputLayerName(uri): @staticmethod def ogrLayerName(uri): uri = uri.strip('"') - if ' table=' in uri: + if " table=" in uri: # table="schema"."table" re_table_schema = re.compile(' table="([^"]*)"\\."([^"]*)"') r = re_table_schema.search(uri) if r: - return r.groups()[0] + '.' + r.groups()[1] + return r.groups()[0] + "." + r.groups()[1] # table="table" re_table = re.compile(' table="([^"]*)"') r = re_table.search(uri) if r: return r.groups()[0] - elif 'layername' in uri: - regex = re.compile('(layername=)([^|]*)') + elif "layername" in uri: + regex = re.compile("(layername=)([^|]*)") r = regex.search(uri) return r.groups()[1] - fields = uri.split('|') + fields = uri.split("|") basePath = fields[0] fields = fields[1:] layerid = 0 for f in fields: - if f.startswith('layername='): - return f.split('=')[1] - if f.startswith('layerid='): - layerid = int(f.split('=')[1]) + if f.startswith("layername="): + return f.split("=")[1] + if f.startswith("layerid="): + layerid = int(f.split("=")[1]) try: ds = gdal.OpenEx(basePath, gdal.OF_VECTOR) @@ -553,14 +556,16 @@ def ogrLayerName(uri): @staticmethod def parseCreationOptions(value): - parts = value.split('|') + parts = value.split("|") options = [] for p in parts: - options.extend(['-co', p]) + options.extend(["-co", p]) return options @staticmethod - def writeLayerParameterToTextFile(filename, alg, parameters, parameter_name, context, quote=True, executing=False): + def writeLayerParameterToTextFile( + filename, alg, parameters, parameter_name, context, quote=True, executing=False + ): listFile = QgsProcessingUtils.generateTempFilename(filename, context) if executing: @@ -572,8 +577,8 @@ def writeLayerParameterToTextFile(filename, alg, parameters, parameter_name, con else: layers.append(layer_details.connection_string) - with open(listFile, 'w') as f: - f.write('\n'.join(layers)) + with open(listFile, "w") as f: + f.write("\n".join(layers)) return listFile @@ -585,13 +590,17 @@ def gdal_crs_string(crs): :param crs: crs to convert :return: gdal friendly string """ - if crs.authid().upper().startswith('EPSG:') or crs.authid().upper().startswith('IGNF:') or crs.authid().upper().startswith('ESRI:'): + if ( + crs.authid().upper().startswith("EPSG:") + or crs.authid().upper().startswith("IGNF:") + or crs.authid().upper().startswith("ESRI:") + ): return crs.authid() return crs.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED_GDAL) @classmethod - def tr(cls, string, context=''): - if context == '': + def tr(cls, string, context=""): + if context == "": context = cls.__name__ return QCoreApplication.translate(context, string) diff --git a/python/plugins/processing/algs/gdal/GridAverage.py b/python/plugins/processing/algs/gdal/GridAverage.py index 167ccdd0965b..ce1c8f1da428 100644 --- a/python/plugins/processing/algs/gdal/GridAverage.py +++ b/python/plugins/processing/algs/gdal/GridAverage.py @@ -15,24 +15,26 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'October 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "October 2013" +__copyright__ = "(C) 2013, Alexander Bruy" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsRasterFileWriter, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterEnum, - QgsProcessingParameterField, - QgsProcessingParameterNumber, - QgsProcessingParameterString, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterEnum, + QgsProcessingParameterField, + QgsProcessingParameterNumber, + QgsProcessingParameterString, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -40,149 +42,219 @@ class GridAverage(GdalAlgorithm): - INPUT = 'INPUT' - Z_FIELD = 'Z_FIELD' - RADIUS_1 = 'RADIUS_1' - RADIUS_2 = 'RADIUS_2' - MIN_POINTS = 'MIN_POINTS' - ANGLE = 'ANGLE' - NODATA = 'NODATA' - OPTIONS = 'OPTIONS' - EXTRA = 'EXTRA' - DATA_TYPE = 'DATA_TYPE' - OUTPUT = 'OUTPUT' - - TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8'] + INPUT = "INPUT" + Z_FIELD = "Z_FIELD" + RADIUS_1 = "RADIUS_1" + RADIUS_2 = "RADIUS_2" + MIN_POINTS = "MIN_POINTS" + ANGLE = "ANGLE" + NODATA = "NODATA" + OPTIONS = "OPTIONS" + EXTRA = "EXTRA" + DATA_TYPE = "DATA_TYPE" + OUTPUT = "OUTPUT" + + TYPES = [ + "Byte", + "Int16", + "UInt16", + "UInt32", + "Int32", + "Float32", + "Float64", + "CInt16", + "CInt32", + "CFloat32", + "CFloat64", + "Int8", + ] def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Point layer'), - [QgsProcessing.SourceType.TypeVectorPoint])) - - z_field_param = QgsProcessingParameterField(self.Z_FIELD, - self.tr('Z value from field'), - None, - self.INPUT, - QgsProcessingParameterField.DataType.Numeric, - optional=True) - z_field_param.setFlags(z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Point layer"), + [QgsProcessing.SourceType.TypeVectorPoint], + ) + ) + + z_field_param = QgsProcessingParameterField( + self.Z_FIELD, + self.tr("Z value from field"), + None, + self.INPUT, + QgsProcessingParameterField.DataType.Numeric, + optional=True, + ) + z_field_param.setFlags( + z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(z_field_param) - self.addParameter(QgsProcessingParameterNumber(self.RADIUS_1, - self.tr('The first radius of search ellipse'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=0.0)) - self.addParameter(QgsProcessingParameterNumber(self.RADIUS_2, - self.tr('The second radius of search ellipse'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=0.0)) - self.addParameter(QgsProcessingParameterNumber(self.ANGLE, - self.tr('Angle of search ellipse rotation in degrees (counter clockwise)'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - maxValue=360.0, - defaultValue=0.0)) - self.addParameter(QgsProcessingParameterNumber(self.MIN_POINTS, - self.tr('Minimum number of data points to use'), - type=QgsProcessingParameterNumber.Type.Integer, - minValue=0, - defaultValue=0)) - self.addParameter(QgsProcessingParameterNumber(self.NODATA, - self.tr('NODATA marker to fill empty points'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=0.0)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.addParameter( + QgsProcessingParameterNumber( + self.RADIUS_1, + self.tr("The first radius of search ellipse"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=0.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.RADIUS_2, + self.tr("The second radius of search ellipse"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=0.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.ANGLE, + self.tr( + "Angle of search ellipse rotation in degrees (counter clockwise)" + ), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + maxValue=360.0, + defaultValue=0.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.MIN_POINTS, + self.tr("Minimum number of data points to use"), + type=QgsProcessingParameterNumber.Type.Integer, + minValue=0, + defaultValue=0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.NODATA, + self.tr("NODATA marker to fill empty points"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=0.0, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE, - self.tr('Output data type'), - self.TYPES, - allowMultiple=False, - defaultValue=5) - dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + dataType_param = QgsProcessingParameterEnum( + self.DATA_TYPE, + self.tr("Output data type"), + self.TYPES, + allowMultiple=False, + defaultValue=5, + ) + dataType_param.setFlags( + dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(dataType_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, - self.tr('Interpolated (moving average)'))) + self.addParameter( + QgsProcessingParameterRasterDestination( + self.OUTPUT, self.tr("Interpolated (moving average)") + ) + ) def name(self): - return 'gridaverage' + return "gridaverage" def displayName(self): - return self.tr('Grid (Moving average)') + return self.tr("Grid (Moving average)") def group(self): - return self.tr('Raster analysis') + return self.tr("Raster analysis") def groupId(self): - return 'rasteranalysis' + return "rasteranalysis" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'grid.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "grid.png")) def commandName(self): - return 'gdal_grid' + return "gdal_grid" def getConsoleCommands(self, parameters, context, feedback, executing=True): - input_details = self.getOgrCompatibleSource(self.INPUT, - parameters, context, - feedback, executing) + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) - arguments = ['-l'] + arguments = ["-l"] arguments.append(input_details.layer_name) fieldName = self.parameterAsString(parameters, self.Z_FIELD, context) if fieldName: - arguments.append('-zfield') + arguments.append("-zfield") arguments.append(fieldName) - params = 'average' - params += f':radius1={self.parameterAsDouble(parameters, self.RADIUS_1, context)}' - params += f':radius2={self.parameterAsDouble(parameters, self.RADIUS_2, context)}' - params += f':angle={self.parameterAsDouble(parameters, self.ANGLE, context)}' - params += f':min_points={self.parameterAsInt(parameters, self.MIN_POINTS, context)}' - params += f':nodata={self.parameterAsDouble(parameters, self.NODATA, context)}' - - arguments.append('-a') + params = "average" + params += ( + f":radius1={self.parameterAsDouble(parameters, self.RADIUS_1, context)}" + ) + params += ( + f":radius2={self.parameterAsDouble(parameters, self.RADIUS_2, context)}" + ) + params += f":angle={self.parameterAsDouble(parameters, self.ANGLE, context)}" + params += ( + f":min_points={self.parameterAsInt(parameters, self.MIN_POINTS, context)}" + ) + params += f":nodata={self.parameterAsDouble(parameters, self.NODATA, context)}" + + arguments.append("-a") arguments.append(params) data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context) - if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later')) + if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000: + raise QgsProcessingException( + self.tr("Int8 data type requires GDAL version 3.7 or later") + ) - arguments.append('-ot ' + self.TYPES[data_type]) + arguments.append("-ot " + self.TYPES[data_type]) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, out) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) - arguments.append('-of') + arguments.append("-of") arguments.append(output_format) if input_details.open_options: if GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Open options are not supported by gdal_grid version {} (requires GDAL version 3.7 or later)'.format(GdalUtils.readableVersion()))) + raise QgsProcessingException( + self.tr( + f"Open options are not supported by gdal_grid version {GdalUtils.readableVersion()} (requires GDAL version 3.7 or later)" + ) + ) arguments.extend(input_details.open_options_as_arguments()) @@ -190,7 +262,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) diff --git a/python/plugins/processing/algs/gdal/GridDataMetrics.py b/python/plugins/processing/algs/gdal/GridDataMetrics.py index 7eb604033264..f7b61cdd3a5f 100644 --- a/python/plugins/processing/algs/gdal/GridDataMetrics.py +++ b/python/plugins/processing/algs/gdal/GridDataMetrics.py @@ -15,24 +15,26 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'October 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "October 2013" +__copyright__ = "(C) 2013, Alexander Bruy" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsRasterFileWriter, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterEnum, - QgsProcessingParameterField, - QgsProcessingParameterNumber, - QgsProcessingParameterString, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterEnum, + QgsProcessingParameterField, + QgsProcessingParameterNumber, + QgsProcessingParameterString, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -40,163 +42,236 @@ class GridDataMetrics(GdalAlgorithm): - INPUT = 'INPUT' - Z_FIELD = 'Z_FIELD' - METRIC = 'METRIC' - RADIUS_1 = 'RADIUS_1' - RADIUS_2 = 'RADIUS_2' - MIN_POINTS = 'MIN_POINTS' - ANGLE = 'ANGLE' - NODATA = 'NODATA' - OPTIONS = 'OPTIONS' - EXTRA = 'EXTRA' - DATA_TYPE = 'DATA_TYPE' - OUTPUT = 'OUTPUT' - - TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8'] + INPUT = "INPUT" + Z_FIELD = "Z_FIELD" + METRIC = "METRIC" + RADIUS_1 = "RADIUS_1" + RADIUS_2 = "RADIUS_2" + MIN_POINTS = "MIN_POINTS" + ANGLE = "ANGLE" + NODATA = "NODATA" + OPTIONS = "OPTIONS" + EXTRA = "EXTRA" + DATA_TYPE = "DATA_TYPE" + OUTPUT = "OUTPUT" + + TYPES = [ + "Byte", + "Int16", + "UInt16", + "UInt32", + "Int32", + "Float32", + "Float64", + "CInt16", + "CInt32", + "CFloat32", + "CFloat64", + "Int8", + ] def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.metrics = ((self.tr('Minimum'), 'minimum'), - (self.tr('Maximum'), 'maximum'), - (self.tr('Range'), 'range'), - (self.tr('Count'), 'count'), - (self.tr('Average distance'), 'average_distance'), - (self.tr('Average distance between points'), 'average_distance_pts')) - - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Point layer'), - [QgsProcessing.SourceType.TypeVectorPoint])) - - z_field_param = QgsProcessingParameterField(self.Z_FIELD, - self.tr('Z value from field'), - None, - self.INPUT, - QgsProcessingParameterField.DataType.Numeric, - optional=True) - z_field_param.setFlags(z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.metrics = ( + (self.tr("Minimum"), "minimum"), + (self.tr("Maximum"), "maximum"), + (self.tr("Range"), "range"), + (self.tr("Count"), "count"), + (self.tr("Average distance"), "average_distance"), + (self.tr("Average distance between points"), "average_distance_pts"), + ) + + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Point layer"), + [QgsProcessing.SourceType.TypeVectorPoint], + ) + ) + + z_field_param = QgsProcessingParameterField( + self.Z_FIELD, + self.tr("Z value from field"), + None, + self.INPUT, + QgsProcessingParameterField.DataType.Numeric, + optional=True, + ) + z_field_param.setFlags( + z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(z_field_param) - self.addParameter(QgsProcessingParameterEnum(self.METRIC, - self.tr('Data metric to use'), - options=[i[0] for i in self.metrics], - allowMultiple=False, - defaultValue=0)) - self.addParameter(QgsProcessingParameterNumber(self.RADIUS_1, - self.tr('The first radius of search ellipse'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=0.0)) - self.addParameter(QgsProcessingParameterNumber(self.RADIUS_2, - self.tr('The second radius of search ellipse'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=0.0)) - self.addParameter(QgsProcessingParameterNumber(self.ANGLE, - self.tr('Angle of search ellipse rotation in degrees (counter clockwise)'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - maxValue=360.0, - defaultValue=0.0)) - self.addParameter(QgsProcessingParameterNumber(self.MIN_POINTS, - self.tr('Minimum number of data points to use'), - type=QgsProcessingParameterNumber.Type.Integer, - minValue=0, - defaultValue=0)) - self.addParameter(QgsProcessingParameterNumber(self.NODATA, - self.tr('NODATA marker to fill empty points'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=0.0)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.addParameter( + QgsProcessingParameterEnum( + self.METRIC, + self.tr("Data metric to use"), + options=[i[0] for i in self.metrics], + allowMultiple=False, + defaultValue=0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.RADIUS_1, + self.tr("The first radius of search ellipse"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=0.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.RADIUS_2, + self.tr("The second radius of search ellipse"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=0.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.ANGLE, + self.tr( + "Angle of search ellipse rotation in degrees (counter clockwise)" + ), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + maxValue=360.0, + defaultValue=0.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.MIN_POINTS, + self.tr("Minimum number of data points to use"), + type=QgsProcessingParameterNumber.Type.Integer, + minValue=0, + defaultValue=0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.NODATA, + self.tr("NODATA marker to fill empty points"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=0.0, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE, - self.tr('Output data type'), - self.TYPES, - allowMultiple=False, - defaultValue=5) - dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + dataType_param = QgsProcessingParameterEnum( + self.DATA_TYPE, + self.tr("Output data type"), + self.TYPES, + allowMultiple=False, + defaultValue=5, + ) + dataType_param.setFlags( + dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(dataType_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, - self.tr('Interpolated (data metrics)'))) + self.addParameter( + QgsProcessingParameterRasterDestination( + self.OUTPUT, self.tr("Interpolated (data metrics)") + ) + ) def name(self): - return 'griddatametrics' + return "griddatametrics" def displayName(self): - return self.tr('Grid (Data metrics)') + return self.tr("Grid (Data metrics)") def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'grid.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "grid.png")) def group(self): - return self.tr('Raster analysis') + return self.tr("Raster analysis") def groupId(self): - return 'rasteranalysis' + return "rasteranalysis" def commandName(self): - return 'gdal_grid' + return "gdal_grid" def getConsoleCommands(self, parameters, context, feedback, executing=True): - input_details = self.getOgrCompatibleSource(self.INPUT, - parameters, context, - feedback, executing) - - arguments = [ - '-l', - input_details.layer_name - ] + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) + + arguments = ["-l", input_details.layer_name] fieldName = self.parameterAsString(parameters, self.Z_FIELD, context) if fieldName: - arguments.append('-zfield') + arguments.append("-zfield") arguments.append(fieldName) params = self.metrics[self.parameterAsEnum(parameters, self.METRIC, context)][1] - params += f':radius1={self.parameterAsDouble(parameters, self.RADIUS_1, context)}' - params += f':radius2={self.parameterAsDouble(parameters, self.RADIUS_2, context)}' - params += f':angle={self.parameterAsDouble(parameters, self.ANGLE, context)}' - params += f':min_points={self.parameterAsInt(parameters, self.MIN_POINTS, context)}' - params += f':nodata={self.parameterAsDouble(parameters, self.NODATA, context)}' - - arguments.append('-a') + params += ( + f":radius1={self.parameterAsDouble(parameters, self.RADIUS_1, context)}" + ) + params += ( + f":radius2={self.parameterAsDouble(parameters, self.RADIUS_2, context)}" + ) + params += f":angle={self.parameterAsDouble(parameters, self.ANGLE, context)}" + params += ( + f":min_points={self.parameterAsInt(parameters, self.MIN_POINTS, context)}" + ) + params += f":nodata={self.parameterAsDouble(parameters, self.NODATA, context)}" + + arguments.append("-a") arguments.append(params) data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context) - if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later')) + if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000: + raise QgsProcessingException( + self.tr("Int8 data type requires GDAL version 3.7 or later") + ) - arguments.append('-ot ' + self.TYPES[data_type]) + arguments.append("-ot " + self.TYPES[data_type]) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, out) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) - arguments.append('-of') + arguments.append("-of") arguments.append(output_format) if input_details.open_options: if GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Open options are not supported by gdal_grid version {} (requires GDAL version 3.7 or later)'.format(GdalUtils.readableVersion()))) + raise QgsProcessingException( + self.tr( + f"Open options are not supported by gdal_grid version {GdalUtils.readableVersion()} (requires GDAL version 3.7 or later)" + ) + ) arguments.extend(input_details.open_options_as_arguments()) @@ -205,7 +280,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) diff --git a/python/plugins/processing/algs/gdal/GridInverseDistance.py b/python/plugins/processing/algs/gdal/GridInverseDistance.py index 77e2e57fd5a4..3b2ad0a81542 100644 --- a/python/plugins/processing/algs/gdal/GridInverseDistance.py +++ b/python/plugins/processing/algs/gdal/GridInverseDistance.py @@ -15,24 +15,26 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'October 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "October 2013" +__copyright__ = "(C) 2013, Alexander Bruy" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsRasterFileWriter, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterEnum, - QgsProcessingParameterField, - QgsProcessingParameterNumber, - QgsProcessingParameterString, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterEnum, + QgsProcessingParameterField, + QgsProcessingParameterNumber, + QgsProcessingParameterString, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -40,172 +42,255 @@ class GridInverseDistance(GdalAlgorithm): - INPUT = 'INPUT' - Z_FIELD = 'Z_FIELD' - POWER = 'POWER' - SMOOTHING = 'SMOOTHING' - RADIUS_1 = 'RADIUS_1' - RADIUS_2 = 'RADIUS_2' - MAX_POINTS = 'MAX_POINTS' - MIN_POINTS = 'MIN_POINTS' - ANGLE = 'ANGLE' - NODATA = 'NODATA' - OPTIONS = 'OPTIONS' - EXTRA = 'EXTRA' - DATA_TYPE = 'DATA_TYPE' - OUTPUT = 'OUTPUT' - - TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8'] + INPUT = "INPUT" + Z_FIELD = "Z_FIELD" + POWER = "POWER" + SMOOTHING = "SMOOTHING" + RADIUS_1 = "RADIUS_1" + RADIUS_2 = "RADIUS_2" + MAX_POINTS = "MAX_POINTS" + MIN_POINTS = "MIN_POINTS" + ANGLE = "ANGLE" + NODATA = "NODATA" + OPTIONS = "OPTIONS" + EXTRA = "EXTRA" + DATA_TYPE = "DATA_TYPE" + OUTPUT = "OUTPUT" + + TYPES = [ + "Byte", + "Int16", + "UInt16", + "UInt32", + "Int32", + "Float32", + "Float64", + "CInt16", + "CInt32", + "CFloat32", + "CFloat64", + "Int8", + ] def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Point layer'), - [QgsProcessing.SourceType.TypeVectorPoint])) - - z_field_param = QgsProcessingParameterField(self.Z_FIELD, - self.tr('Z value from field'), - None, - self.INPUT, - QgsProcessingParameterField.DataType.Numeric, - optional=True) - z_field_param.setFlags(z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Point layer"), + [QgsProcessing.SourceType.TypeVectorPoint], + ) + ) + + z_field_param = QgsProcessingParameterField( + self.Z_FIELD, + self.tr("Z value from field"), + None, + self.INPUT, + QgsProcessingParameterField.DataType.Numeric, + optional=True, + ) + z_field_param.setFlags( + z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(z_field_param) - self.addParameter(QgsProcessingParameterNumber(self.POWER, - self.tr('Weighting power'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - maxValue=100.0, - defaultValue=2.0)) - self.addParameter(QgsProcessingParameterNumber(self.SMOOTHING, - self.tr('Smoothing'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=0.0)) - self.addParameter(QgsProcessingParameterNumber(self.RADIUS_1, - self.tr('The first radius of search ellipse'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=0.0)) - self.addParameter(QgsProcessingParameterNumber(self.RADIUS_2, - self.tr('The second radius of search ellipse'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=0.0)) - self.addParameter(QgsProcessingParameterNumber(self.ANGLE, - self.tr('Angle of search ellipse rotation in degrees (counter clockwise)'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - maxValue=360.0, - defaultValue=0.0)) - self.addParameter(QgsProcessingParameterNumber(self.MAX_POINTS, - self.tr('Maximum number of data points to use'), - type=QgsProcessingParameterNumber.Type.Integer, - minValue=0, - defaultValue=0)) - self.addParameter(QgsProcessingParameterNumber(self.MIN_POINTS, - self.tr('Minimum number of data points to use'), - type=QgsProcessingParameterNumber.Type.Integer, - minValue=0, - defaultValue=0)) - self.addParameter(QgsProcessingParameterNumber(self.NODATA, - self.tr('NODATA marker to fill empty points'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=0.0)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.addParameter( + QgsProcessingParameterNumber( + self.POWER, + self.tr("Weighting power"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + maxValue=100.0, + defaultValue=2.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.SMOOTHING, + self.tr("Smoothing"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=0.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.RADIUS_1, + self.tr("The first radius of search ellipse"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=0.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.RADIUS_2, + self.tr("The second radius of search ellipse"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=0.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.ANGLE, + self.tr( + "Angle of search ellipse rotation in degrees (counter clockwise)" + ), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + maxValue=360.0, + defaultValue=0.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.MAX_POINTS, + self.tr("Maximum number of data points to use"), + type=QgsProcessingParameterNumber.Type.Integer, + minValue=0, + defaultValue=0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.MIN_POINTS, + self.tr("Minimum number of data points to use"), + type=QgsProcessingParameterNumber.Type.Integer, + minValue=0, + defaultValue=0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.NODATA, + self.tr("NODATA marker to fill empty points"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=0.0, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE, - self.tr('Output data type'), - self.TYPES, - allowMultiple=False, - defaultValue=5) - dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + dataType_param = QgsProcessingParameterEnum( + self.DATA_TYPE, + self.tr("Output data type"), + self.TYPES, + allowMultiple=False, + defaultValue=5, + ) + dataType_param.setFlags( + dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(dataType_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, - self.tr('Interpolated (IDW)'))) + self.addParameter( + QgsProcessingParameterRasterDestination( + self.OUTPUT, self.tr("Interpolated (IDW)") + ) + ) def name(self): - return 'gridinversedistance' + return "gridinversedistance" def displayName(self): - return self.tr('Grid (Inverse distance to a power)') + return self.tr("Grid (Inverse distance to a power)") def group(self): - return self.tr('Raster analysis') + return self.tr("Raster analysis") def groupId(self): - return 'rasteranalysis' + return "rasteranalysis" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'grid.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "grid.png")) def commandName(self): - return 'gdal_grid' + return "gdal_grid" def getConsoleCommands(self, parameters, context, feedback, executing=True): - input_details = self.getOgrCompatibleSource(self.INPUT, - parameters, context, - feedback, executing) - - arguments = [ - '-l', - input_details.layer_name - ] + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) + + arguments = ["-l", input_details.layer_name] fieldName = self.parameterAsString(parameters, self.Z_FIELD, context) if fieldName: - arguments.append('-zfield') + arguments.append("-zfield") arguments.append(fieldName) - params = 'invdist' - params += f':power={self.parameterAsDouble(parameters, self.POWER, context)}' - params += f':smoothing={self.parameterAsDouble(parameters, self.SMOOTHING, context)}' - params += f':radius1={self.parameterAsDouble(parameters, self.RADIUS_1, context)}' - params += f':radius2={self.parameterAsDouble(parameters, self.RADIUS_2, context)}' - params += f':angle={self.parameterAsDouble(parameters, self.ANGLE, context)}' - params += f':max_points={self.parameterAsInt(parameters, self.MAX_POINTS, context)}' - params += f':min_points={self.parameterAsInt(parameters, self.MIN_POINTS, context)}' - params += f':nodata={self.parameterAsDouble(parameters, self.NODATA, context)}' - - arguments.append('-a') + params = "invdist" + params += f":power={self.parameterAsDouble(parameters, self.POWER, context)}" + params += ( + f":smoothing={self.parameterAsDouble(parameters, self.SMOOTHING, context)}" + ) + params += ( + f":radius1={self.parameterAsDouble(parameters, self.RADIUS_1, context)}" + ) + params += ( + f":radius2={self.parameterAsDouble(parameters, self.RADIUS_2, context)}" + ) + params += f":angle={self.parameterAsDouble(parameters, self.ANGLE, context)}" + params += ( + f":max_points={self.parameterAsInt(parameters, self.MAX_POINTS, context)}" + ) + params += ( + f":min_points={self.parameterAsInt(parameters, self.MIN_POINTS, context)}" + ) + params += f":nodata={self.parameterAsDouble(parameters, self.NODATA, context)}" + + arguments.append("-a") arguments.append(params) data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context) - if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later')) + if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000: + raise QgsProcessingException( + self.tr("Int8 data type requires GDAL version 3.7 or later") + ) - arguments.append('-ot ' + self.TYPES[data_type]) + arguments.append("-ot " + self.TYPES[data_type]) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, out) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) - arguments.append('-of') + arguments.append("-of") arguments.append(output_format) if input_details.open_options: if GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Open options are not supported by gdal_grid version {} (requires GDAL version 3.7 or later)'.format(GdalUtils.readableVersion()))) + raise QgsProcessingException( + self.tr( + f"Open options are not supported by gdal_grid version {GdalUtils.readableVersion()} (requires GDAL version 3.7 or later)" + ) + ) arguments.extend(input_details.open_options_as_arguments()) @@ -213,7 +298,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) diff --git a/python/plugins/processing/algs/gdal/GridInverseDistanceNearestNeighbor.py b/python/plugins/processing/algs/gdal/GridInverseDistanceNearestNeighbor.py index 26e13f00b2b0..bce14acfdc97 100644 --- a/python/plugins/processing/algs/gdal/GridInverseDistanceNearestNeighbor.py +++ b/python/plugins/processing/algs/gdal/GridInverseDistanceNearestNeighbor.py @@ -15,24 +15,26 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'September 2017' -__copyright__ = '(C) 2017, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "September 2017" +__copyright__ = "(C) 2017, Alexander Bruy" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsRasterFileWriter, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterEnum, - QgsProcessingParameterField, - QgsProcessingParameterNumber, - QgsProcessingParameterString, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterEnum, + QgsProcessingParameterField, + QgsProcessingParameterNumber, + QgsProcessingParameterString, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -40,157 +42,226 @@ class GridInverseDistanceNearestNeighbor(GdalAlgorithm): - INPUT = 'INPUT' - Z_FIELD = 'Z_FIELD' - POWER = 'POWER' - SMOOTHING = 'SMOOTHING' - RADIUS = 'RADIUS' - MAX_POINTS = 'MAX_POINTS' - MIN_POINTS = 'MIN_POINTS' - NODATA = 'NODATA' - OPTIONS = 'OPTIONS' - EXTRA = 'EXTRA' - DATA_TYPE = 'DATA_TYPE' - OUTPUT = 'OUTPUT' - - TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8'] + INPUT = "INPUT" + Z_FIELD = "Z_FIELD" + POWER = "POWER" + SMOOTHING = "SMOOTHING" + RADIUS = "RADIUS" + MAX_POINTS = "MAX_POINTS" + MIN_POINTS = "MIN_POINTS" + NODATA = "NODATA" + OPTIONS = "OPTIONS" + EXTRA = "EXTRA" + DATA_TYPE = "DATA_TYPE" + OUTPUT = "OUTPUT" + + TYPES = [ + "Byte", + "Int16", + "UInt16", + "UInt32", + "Int32", + "Float32", + "Float64", + "CInt16", + "CInt32", + "CFloat32", + "CFloat64", + "Int8", + ] def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Point layer'), - [QgsProcessing.SourceType.TypeVectorPoint])) - - z_field_param = QgsProcessingParameterField(self.Z_FIELD, - self.tr('Z value from field'), - None, - self.INPUT, - QgsProcessingParameterField.DataType.Numeric, - optional=True) - z_field_param.setFlags(z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Point layer"), + [QgsProcessing.SourceType.TypeVectorPoint], + ) + ) + + z_field_param = QgsProcessingParameterField( + self.Z_FIELD, + self.tr("Z value from field"), + None, + self.INPUT, + QgsProcessingParameterField.DataType.Numeric, + optional=True, + ) + z_field_param.setFlags( + z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(z_field_param) - self.addParameter(QgsProcessingParameterNumber(self.POWER, - self.tr('Weighting power'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - maxValue=100.0, - defaultValue=2.0)) - self.addParameter(QgsProcessingParameterNumber(self.SMOOTHING, - self.tr('Smoothing'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=0.0)) - self.addParameter(QgsProcessingParameterNumber(self.RADIUS, - self.tr('The radius of the search circle'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=1.0)) - self.addParameter(QgsProcessingParameterNumber(self.MAX_POINTS, - self.tr('Maximum number of data points to use'), - type=QgsProcessingParameterNumber.Type.Integer, - minValue=0, - defaultValue=12)) - self.addParameter(QgsProcessingParameterNumber(self.MIN_POINTS, - self.tr('Minimum number of data points to use'), - type=QgsProcessingParameterNumber.Type.Integer, - minValue=0, - defaultValue=0)) - self.addParameter(QgsProcessingParameterNumber(self.NODATA, - self.tr('NODATA marker to fill empty points'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=0.0)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.addParameter( + QgsProcessingParameterNumber( + self.POWER, + self.tr("Weighting power"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + maxValue=100.0, + defaultValue=2.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.SMOOTHING, + self.tr("Smoothing"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=0.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.RADIUS, + self.tr("The radius of the search circle"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=1.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.MAX_POINTS, + self.tr("Maximum number of data points to use"), + type=QgsProcessingParameterNumber.Type.Integer, + minValue=0, + defaultValue=12, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.MIN_POINTS, + self.tr("Minimum number of data points to use"), + type=QgsProcessingParameterNumber.Type.Integer, + minValue=0, + defaultValue=0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.NODATA, + self.tr("NODATA marker to fill empty points"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=0.0, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE, - self.tr('Output data type'), - self.TYPES, - allowMultiple=False, - defaultValue=5) - dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + dataType_param = QgsProcessingParameterEnum( + self.DATA_TYPE, + self.tr("Output data type"), + self.TYPES, + allowMultiple=False, + defaultValue=5, + ) + dataType_param.setFlags( + dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(dataType_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, - self.tr('Interpolated (IDW with NN search)'))) + self.addParameter( + QgsProcessingParameterRasterDestination( + self.OUTPUT, self.tr("Interpolated (IDW with NN search)") + ) + ) def name(self): - return 'gridinversedistancenearestneighbor' + return "gridinversedistancenearestneighbor" def displayName(self): - return self.tr('Grid (IDW with nearest neighbor searching)') + return self.tr("Grid (IDW with nearest neighbor searching)") def group(self): - return self.tr('Raster analysis') + return self.tr("Raster analysis") def groupId(self): - return 'rasteranalysis' + return "rasteranalysis" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'grid.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "grid.png")) def commandName(self): - return 'gdal_grid' + return "gdal_grid" def getConsoleCommands(self, parameters, context, feedback, executing=True): - input_details = self.getOgrCompatibleSource(self.INPUT, - parameters, context, - feedback, executing) - - arguments = [ - '-l', - input_details.layer_name - ] + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) + + arguments = ["-l", input_details.layer_name] fieldName = self.parameterAsString(parameters, self.Z_FIELD, context) if fieldName: - arguments.append('-zfield') + arguments.append("-zfield") arguments.append(fieldName) - params = 'invdistnn' - params += f':power={self.parameterAsDouble(parameters, self.POWER, context)}' - params += f':smoothing={self.parameterAsDouble(parameters, self.SMOOTHING, context)}' - params += f':radius={self.parameterAsDouble(parameters, self.RADIUS, context)}' - params += f':max_points={self.parameterAsInt(parameters, self.MAX_POINTS, context)}' - params += f':min_points={self.parameterAsInt(parameters, self.MIN_POINTS, context)}' - params += f':nodata={self.parameterAsDouble(parameters, self.NODATA, context)}' - - arguments.append('-a') + params = "invdistnn" + params += f":power={self.parameterAsDouble(parameters, self.POWER, context)}" + params += ( + f":smoothing={self.parameterAsDouble(parameters, self.SMOOTHING, context)}" + ) + params += f":radius={self.parameterAsDouble(parameters, self.RADIUS, context)}" + params += ( + f":max_points={self.parameterAsInt(parameters, self.MAX_POINTS, context)}" + ) + params += ( + f":min_points={self.parameterAsInt(parameters, self.MIN_POINTS, context)}" + ) + params += f":nodata={self.parameterAsDouble(parameters, self.NODATA, context)}" + + arguments.append("-a") arguments.append(params) data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context) - if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later')) + if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000: + raise QgsProcessingException( + self.tr("Int8 data type requires GDAL version 3.7 or later") + ) - arguments.append('-ot ' + self.TYPES[data_type]) + arguments.append("-ot " + self.TYPES[data_type]) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, out) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) - arguments.append('-of') + arguments.append("-of") arguments.append(output_format) if input_details.open_options: if GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Open options are not supported by gdal_grid version {} (requires GDAL version 3.7 or later)'.format(GdalUtils.readableVersion()))) + raise QgsProcessingException( + self.tr( + f"Open options are not supported by gdal_grid version {GdalUtils.readableVersion()} (requires GDAL version 3.7 or later)" + ) + ) arguments.extend(input_details.open_options_as_arguments()) @@ -198,7 +269,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) diff --git a/python/plugins/processing/algs/gdal/GridLinear.py b/python/plugins/processing/algs/gdal/GridLinear.py index f3ec203d8966..bd40da18f5ba 100644 --- a/python/plugins/processing/algs/gdal/GridLinear.py +++ b/python/plugins/processing/algs/gdal/GridLinear.py @@ -15,24 +15,26 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'September 2017' -__copyright__ = '(C) 2017, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "September 2017" +__copyright__ = "(C) 2017, Alexander Bruy" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsRasterFileWriter, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterEnum, - QgsProcessingParameterField, - QgsProcessingParameterNumber, - QgsProcessingParameterString, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterEnum, + QgsProcessingParameterField, + QgsProcessingParameterNumber, + QgsProcessingParameterString, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -41,128 +43,175 @@ class GridLinear(GdalAlgorithm): - INPUT = 'INPUT' - Z_FIELD = 'Z_FIELD' - RADIUS = 'RADIUS' - NODATA = 'NODATA' - OPTIONS = 'OPTIONS' - EXTRA = 'EXTRA' - DATA_TYPE = 'DATA_TYPE' - OUTPUT = 'OUTPUT' - - TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8'] + INPUT = "INPUT" + Z_FIELD = "Z_FIELD" + RADIUS = "RADIUS" + NODATA = "NODATA" + OPTIONS = "OPTIONS" + EXTRA = "EXTRA" + DATA_TYPE = "DATA_TYPE" + OUTPUT = "OUTPUT" + + TYPES = [ + "Byte", + "Int16", + "UInt16", + "UInt32", + "Int32", + "Float32", + "Float64", + "CInt16", + "CInt32", + "CFloat32", + "CFloat64", + "Int8", + ] def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Point layer'), - [QgsProcessing.SourceType.TypeVectorPoint])) - - z_field_param = QgsProcessingParameterField(self.Z_FIELD, - self.tr('Z value from field'), - None, - self.INPUT, - QgsProcessingParameterField.DataType.Numeric, - optional=True) - z_field_param.setFlags(z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Point layer"), + [QgsProcessing.SourceType.TypeVectorPoint], + ) + ) + + z_field_param = QgsProcessingParameterField( + self.Z_FIELD, + self.tr("Z value from field"), + None, + self.INPUT, + QgsProcessingParameterField.DataType.Numeric, + optional=True, + ) + z_field_param.setFlags( + z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(z_field_param) - self.addParameter(QgsProcessingParameterNumber(self.RADIUS, - self.tr('Search distance '), - type=QgsProcessingParameterNumber.Type.Double, - minValue=-1.0, - defaultValue=-1.0)) - self.addParameter(QgsProcessingParameterNumber(self.NODATA, - self.tr('NODATA marker to fill empty points'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=0.0)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.addParameter( + QgsProcessingParameterNumber( + self.RADIUS, + self.tr("Search distance "), + type=QgsProcessingParameterNumber.Type.Double, + minValue=-1.0, + defaultValue=-1.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.NODATA, + self.tr("NODATA marker to fill empty points"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=0.0, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE, - self.tr('Output data type'), - self.TYPES, - allowMultiple=False, - defaultValue=5) - dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + dataType_param = QgsProcessingParameterEnum( + self.DATA_TYPE, + self.tr("Output data type"), + self.TYPES, + allowMultiple=False, + defaultValue=5, + ) + dataType_param.setFlags( + dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(dataType_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, - self.tr('Interpolated (Linear)'))) + self.addParameter( + QgsProcessingParameterRasterDestination( + self.OUTPUT, self.tr("Interpolated (Linear)") + ) + ) def name(self): - return 'gridlinear' + return "gridlinear" def displayName(self): - return self.tr('Grid (Linear)') + return self.tr("Grid (Linear)") def group(self): - return self.tr('Raster analysis') + return self.tr("Raster analysis") def groupId(self): - return 'rasteranalysis' + return "rasteranalysis" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'grid.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "grid.png")) def commandName(self): - return 'gdal_grid' + return "gdal_grid" def getConsoleCommands(self, parameters, context, feedback, executing=True): - input_details = self.getOgrCompatibleSource(self.INPUT, - parameters, context, - feedback, executing) - - arguments = [ - '-l', - input_details.layer_name - ] + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) + + arguments = ["-l", input_details.layer_name] fieldName = self.parameterAsString(parameters, self.Z_FIELD, context) if fieldName: - arguments.append('-zfield') + arguments.append("-zfield") arguments.append(fieldName) - params = 'linear' - params += f':radius={self.parameterAsDouble(parameters, self.RADIUS, context)}' - params += f':nodata={self.parameterAsDouble(parameters, self.NODATA, context)}' + params = "linear" + params += f":radius={self.parameterAsDouble(parameters, self.RADIUS, context)}" + params += f":nodata={self.parameterAsDouble(parameters, self.NODATA, context)}" - arguments.append('-a') + arguments.append("-a") arguments.append(params) data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context) - if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later')) + if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000: + raise QgsProcessingException( + self.tr("Int8 data type requires GDAL version 3.7 or later") + ) - arguments.append('-ot ' + self.TYPES[data_type]) + arguments.append("-ot " + self.TYPES[data_type]) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, out) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) - arguments.append('-of') + arguments.append("-of") arguments.append(output_format) if input_details.open_options: if GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Open options are not supported by gdal_grid version {} (requires GDAL version 3.7 or later)'.format(GdalUtils.readableVersion()))) + raise QgsProcessingException( + self.tr( + f"Open options are not supported by gdal_grid version {GdalUtils.readableVersion()} (requires GDAL version 3.7 or later)" + ) + ) arguments.extend(input_details.open_options_as_arguments()) @@ -170,7 +219,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) diff --git a/python/plugins/processing/algs/gdal/GridNearestNeighbor.py b/python/plugins/processing/algs/gdal/GridNearestNeighbor.py index fd43b9f8eba3..94cc7f34a1c6 100644 --- a/python/plugins/processing/algs/gdal/GridNearestNeighbor.py +++ b/python/plugins/processing/algs/gdal/GridNearestNeighbor.py @@ -15,24 +15,26 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'October 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "October 2013" +__copyright__ = "(C) 2013, Alexander Bruy" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsRasterFileWriter, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterEnum, - QgsProcessingParameterField, - QgsProcessingParameterNumber, - QgsProcessingParameterString, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterEnum, + QgsProcessingParameterField, + QgsProcessingParameterNumber, + QgsProcessingParameterString, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -40,141 +42,204 @@ class GridNearestNeighbor(GdalAlgorithm): - INPUT = 'INPUT' - Z_FIELD = 'Z_FIELD' - RADIUS_1 = 'RADIUS_1' - RADIUS_2 = 'RADIUS_2' - ANGLE = 'ANGLE' - NODATA = 'NODATA' - OPTIONS = 'OPTIONS' - EXTRA = 'EXTRA' - DATA_TYPE = 'DATA_TYPE' - OUTPUT = 'OUTPUT' - - TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8'] + INPUT = "INPUT" + Z_FIELD = "Z_FIELD" + RADIUS_1 = "RADIUS_1" + RADIUS_2 = "RADIUS_2" + ANGLE = "ANGLE" + NODATA = "NODATA" + OPTIONS = "OPTIONS" + EXTRA = "EXTRA" + DATA_TYPE = "DATA_TYPE" + OUTPUT = "OUTPUT" + + TYPES = [ + "Byte", + "Int16", + "UInt16", + "UInt32", + "Int32", + "Float32", + "Float64", + "CInt16", + "CInt32", + "CFloat32", + "CFloat64", + "Int8", + ] def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Point layer'), - [QgsProcessing.SourceType.TypeVectorPoint])) - - z_field_param = QgsProcessingParameterField(self.Z_FIELD, - self.tr('Z value from field'), - None, - self.INPUT, - QgsProcessingParameterField.DataType.Numeric, - optional=True) - z_field_param.setFlags(z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Point layer"), + [QgsProcessing.SourceType.TypeVectorPoint], + ) + ) + + z_field_param = QgsProcessingParameterField( + self.Z_FIELD, + self.tr("Z value from field"), + None, + self.INPUT, + QgsProcessingParameterField.DataType.Numeric, + optional=True, + ) + z_field_param.setFlags( + z_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(z_field_param) - self.addParameter(QgsProcessingParameterNumber(self.RADIUS_1, - self.tr('The first radius of search ellipse'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=0.0)) - self.addParameter(QgsProcessingParameterNumber(self.RADIUS_2, - self.tr('The second radius of search ellipse'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=0.0)) - self.addParameter(QgsProcessingParameterNumber(self.ANGLE, - self.tr('Angle of search ellipse rotation in degrees (counter clockwise)'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - maxValue=360.0, - defaultValue=0.0)) - self.addParameter(QgsProcessingParameterNumber(self.NODATA, - self.tr('NODATA marker to fill empty points'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=0.0)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.addParameter( + QgsProcessingParameterNumber( + self.RADIUS_1, + self.tr("The first radius of search ellipse"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=0.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.RADIUS_2, + self.tr("The second radius of search ellipse"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=0.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.ANGLE, + self.tr( + "Angle of search ellipse rotation in degrees (counter clockwise)" + ), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + maxValue=360.0, + defaultValue=0.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.NODATA, + self.tr("NODATA marker to fill empty points"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=0.0, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE, - self.tr('Output data type'), - self.TYPES, - allowMultiple=False, - defaultValue=5) - dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + dataType_param = QgsProcessingParameterEnum( + self.DATA_TYPE, + self.tr("Output data type"), + self.TYPES, + allowMultiple=False, + defaultValue=5, + ) + dataType_param.setFlags( + dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(dataType_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, - self.tr('Interpolated (Nearest neighbor)'))) + self.addParameter( + QgsProcessingParameterRasterDestination( + self.OUTPUT, self.tr("Interpolated (Nearest neighbor)") + ) + ) def name(self): - return 'gridnearestneighbor' + return "gridnearestneighbor" def displayName(self): - return self.tr('Grid (Nearest neighbor)') + return self.tr("Grid (Nearest neighbor)") def group(self): - return self.tr('Raster analysis') + return self.tr("Raster analysis") def groupId(self): - return 'rasteranalysis' + return "rasteranalysis" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'grid.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "grid.png")) def commandName(self): - return 'gdal_grid' + return "gdal_grid" def getConsoleCommands(self, parameters, context, feedback, executing=True): - input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing) + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) - arguments = [ - '-l', - input_details.layer_name - ] + arguments = ["-l", input_details.layer_name] fieldName = self.parameterAsString(parameters, self.Z_FIELD, context) if fieldName: - arguments.append('-zfield') + arguments.append("-zfield") arguments.append(fieldName) - params = 'nearest' - params += f':radius1={self.parameterAsDouble(parameters, self.RADIUS_1, context)}' - params += f':radius2={self.parameterAsDouble(parameters, self.RADIUS_2, context)}' - params += f':angle={self.parameterAsDouble(parameters, self.ANGLE, context)}' - params += f':nodata={self.parameterAsDouble(parameters, self.NODATA, context)}' - - arguments.append('-a') + params = "nearest" + params += ( + f":radius1={self.parameterAsDouble(parameters, self.RADIUS_1, context)}" + ) + params += ( + f":radius2={self.parameterAsDouble(parameters, self.RADIUS_2, context)}" + ) + params += f":angle={self.parameterAsDouble(parameters, self.ANGLE, context)}" + params += f":nodata={self.parameterAsDouble(parameters, self.NODATA, context)}" + + arguments.append("-a") arguments.append(params) data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context) - if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later')) + if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000: + raise QgsProcessingException( + self.tr("Int8 data type requires GDAL version 3.7 or later") + ) - arguments.append('-ot ' + self.TYPES[data_type]) + arguments.append("-ot " + self.TYPES[data_type]) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, out) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) - arguments.append('-of') + arguments.append("-of") arguments.append(output_format) if input_details.open_options: if GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Open options are not supported by gdal_grid version {} (requires GDAL version 3.7 or later)'.format(GdalUtils.readableVersion()))) + raise QgsProcessingException( + self.tr( + f"Open options are not supported by gdal_grid version {GdalUtils.readableVersion()} (requires GDAL version 3.7 or later)" + ) + ) arguments.extend(input_details.open_options_as_arguments()) @@ -182,7 +247,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) diff --git a/python/plugins/processing/algs/gdal/OffsetCurve.py b/python/plugins/processing/algs/gdal/OffsetCurve.py index 503b6d4249a1..043fb7827c70 100644 --- a/python/plugins/processing/algs/gdal/OffsetCurve.py +++ b/python/plugins/processing/algs/gdal/OffsetCurve.py @@ -15,76 +15,102 @@ *************************************************************************** """ -__author__ = 'Giovanni Manghi' -__date__ = 'January 2015' -__copyright__ = '(C) 2015, Giovanni Manghi' - -from qgis.core import (QgsProcessing, - QgsProcessingParameterDefinition, - QgsProcessingParameterDistance, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterString, - QgsProcessingException, - QgsProcessingParameterVectorDestination) +__author__ = "Giovanni Manghi" +__date__ = "January 2015" +__copyright__ = "(C) 2015, Giovanni Manghi" + +from qgis.core import ( + QgsProcessing, + QgsProcessingParameterDefinition, + QgsProcessingParameterDistance, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterString, + QgsProcessingException, + QgsProcessingParameterVectorDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils class OffsetCurve(GdalAlgorithm): - INPUT = 'INPUT' - GEOMETRY = 'GEOMETRY' - DISTANCE = 'DISTANCE' - OPTIONS = 'OPTIONS' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + GEOMETRY = "GEOMETRY" + DISTANCE = "DISTANCE" + OPTIONS = "OPTIONS" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), - [QgsProcessing.SourceType.TypeVectorLine])) - self.addParameter(QgsProcessingParameterString(self.GEOMETRY, - self.tr('Geometry column name'), - defaultValue='geometry')) - self.addParameter(QgsProcessingParameterDistance(self.DISTANCE, - self.tr('Offset distance (left-sided: positive, right-sided: negative)'), - parentParameterName=self.INPUT, - defaultValue=10)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Input layer"), + [QgsProcessing.SourceType.TypeVectorLine], + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.GEOMETRY, self.tr("Geometry column name"), defaultValue="geometry" + ) + ) + self.addParameter( + QgsProcessingParameterDistance( + self.DISTANCE, + self.tr( + "Offset distance (left-sided: positive, right-sided: negative)" + ), + parentParameterName=self.INPUT, + defaultValue=10, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(options_param) - self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT, - self.tr('Offset curve'), - QgsProcessing.SourceType.TypeVectorLine)) + self.addParameter( + QgsProcessingParameterVectorDestination( + self.OUTPUT, + self.tr("Offset curve"), + QgsProcessing.SourceType.TypeVectorLine, + ) + ) def name(self): - return 'offsetcurve' + return "offsetcurve" def displayName(self): - return self.tr('Offset curve') + return self.tr("Offset curve") def group(self): - return self.tr('Vector geoprocessing') + return self.tr("Vector geoprocessing") def groupId(self): - return 'vectorgeoprocessing' + return "vectorgeoprocessing" def commandName(self): - return 'ogr2ogr' + return "ogr2ogr" def getConsoleCommands(self, parameters, context, feedback, executing=True): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) fields = source.fields() - input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing) + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) geometry = self.parameterAsString(parameters, self.GEOMETRY, context) distance = self.parameterAsDouble(parameters, self.DISTANCE, context) options = self.parameterAsString(parameters, self.OPTIONS, context) @@ -93,19 +119,16 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context) - other_fields_exist = any( - True for f in fields - if f.name() != geometry - ) + other_fields_exist = any(True for f in fields if f.name() != geometry) - other_fields = ',*' if other_fields_exist else '' + other_fields = ",*" if other_fields_exist else "" arguments = [ output_details.connection_string, input_details.connection_string, - '-dialect', - 'sqlite', - '-sql' + "-dialect", + "sqlite", + "-sql", ] sql = f'SELECT ST_OffsetCurve({geometry}, {distance}) AS {geometry}{other_fields} FROM "{input_details.layer_name}"' arguments.append(sql) @@ -120,6 +143,6 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments.append(options) if output_details.format: - arguments.append(f'-f {output_details.format}') + arguments.append(f"-f {output_details.format}") - return ['ogr2ogr', GdalUtils.escapeAndJoin(arguments)] + return ["ogr2ogr", GdalUtils.escapeAndJoin(arguments)] diff --git a/python/plugins/processing/algs/gdal/OgrToPostGis.py b/python/plugins/processing/algs/gdal/OgrToPostGis.py index 39012eedcc97..5bfcd6b63bb0 100644 --- a/python/plugins/processing/algs/gdal/OgrToPostGis.py +++ b/python/plugins/processing/algs/gdal/OgrToPostGis.py @@ -15,19 +15,21 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'November 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "November 2012" +__copyright__ = "(C) 2012, Victor Olaya" -from qgis.core import (QgsProcessing, - QgsProcessingException, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterString, - QgsProcessingParameterEnum, - QgsProcessingParameterCrs, - QgsProcessingParameterField, - QgsProcessingParameterExtent, - QgsProcessingParameterBoolean) +from qgis.core import ( + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterString, + QgsProcessingParameterEnum, + QgsProcessingParameterCrs, + QgsProcessingParameterField, + QgsProcessingParameterExtent, + QgsProcessingParameterBoolean, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -36,166 +38,324 @@ class OgrToPostGis(GdalAlgorithm): - INPUT = 'INPUT' - SHAPE_ENCODING = 'SHAPE_ENCODING' - GTYPE = 'GTYPE' - GEOMTYPE = ['', 'NONE', 'GEOMETRY', 'POINT', 'LINESTRING', 'POLYGON', 'GEOMETRYCOLLECTION', 'MULTIPOINT', - 'MULTIPOLYGON', 'MULTILINESTRING', 'CIRCULARSTRING', 'COMPOUNDCURVE', 'CURVEPOLYGON', 'MULTICURVE', - 'MULTISURFACE', 'CONVERT_TO_LINEAR', 'CONVERT_TO_CURVE'] - S_SRS = 'S_SRS' - T_SRS = 'T_SRS' - A_SRS = 'A_SRS' - HOST = 'HOST' - PORT = 'PORT' - USER = 'USER' - DBNAME = 'DBNAME' - PASSWORD = 'PASSWORD' - SCHEMA = 'SCHEMA' - TABLE = 'TABLE' - PK = 'PK' - PRIMARY_KEY = 'PRIMARY_KEY' - GEOCOLUMN = 'GEOCOLUMN' - DIM = 'DIM' - DIMLIST = ['2', '3', '4'] - SIMPLIFY = 'SIMPLIFY' - SEGMENTIZE = 'SEGMENTIZE' - SPAT = 'SPAT' - CLIP = 'CLIP' - FIELDS = 'FIELDS' - WHERE = 'WHERE' - GT = 'GT' - OVERWRITE = 'OVERWRITE' - APPEND = 'APPEND' - ADDFIELDS = 'ADDFIELDS' - LAUNDER = 'LAUNDER' - INDEX = 'INDEX' - SKIPFAILURES = 'SKIPFAILURES' - PRECISION = 'PRECISION' - MAKEVALID = 'MAKEVALID' - PROMOTETOMULTI = 'PROMOTETOMULTI' - OPTIONS = 'OPTIONS' + INPUT = "INPUT" + SHAPE_ENCODING = "SHAPE_ENCODING" + GTYPE = "GTYPE" + GEOMTYPE = [ + "", + "NONE", + "GEOMETRY", + "POINT", + "LINESTRING", + "POLYGON", + "GEOMETRYCOLLECTION", + "MULTIPOINT", + "MULTIPOLYGON", + "MULTILINESTRING", + "CIRCULARSTRING", + "COMPOUNDCURVE", + "CURVEPOLYGON", + "MULTICURVE", + "MULTISURFACE", + "CONVERT_TO_LINEAR", + "CONVERT_TO_CURVE", + ] + S_SRS = "S_SRS" + T_SRS = "T_SRS" + A_SRS = "A_SRS" + HOST = "HOST" + PORT = "PORT" + USER = "USER" + DBNAME = "DBNAME" + PASSWORD = "PASSWORD" + SCHEMA = "SCHEMA" + TABLE = "TABLE" + PK = "PK" + PRIMARY_KEY = "PRIMARY_KEY" + GEOCOLUMN = "GEOCOLUMN" + DIM = "DIM" + DIMLIST = ["2", "3", "4"] + SIMPLIFY = "SIMPLIFY" + SEGMENTIZE = "SEGMENTIZE" + SPAT = "SPAT" + CLIP = "CLIP" + FIELDS = "FIELDS" + WHERE = "WHERE" + GT = "GT" + OVERWRITE = "OVERWRITE" + APPEND = "APPEND" + ADDFIELDS = "ADDFIELDS" + LAUNDER = "LAUNDER" + INDEX = "INDEX" + SKIPFAILURES = "SKIPFAILURES" + PRECISION = "PRECISION" + MAKEVALID = "MAKEVALID" + PROMOTETOMULTI = "PROMOTETOMULTI" + OPTIONS = "OPTIONS" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), - types=[QgsProcessing.SourceType.TypeVector])) - self.addParameter(QgsProcessingParameterString(self.SHAPE_ENCODING, - self.tr('Shape encoding'), "", optional=True)) - self.addParameter(QgsProcessingParameterEnum(self.GTYPE, - self.tr('Output geometry type'), options=self.GEOMTYPE, - defaultValue=0)) - self.addParameter(QgsProcessingParameterCrs(self.A_SRS, - self.tr('Assign an output CRS'), defaultValue='', optional=True)) - self.addParameter(QgsProcessingParameterCrs(self.T_SRS, - self.tr('Reproject to this CRS on output '), defaultValue='', - optional=True)) - self.addParameter(QgsProcessingParameterCrs(self.S_SRS, - self.tr('Override source CRS'), defaultValue='', optional=True)) - self.addParameter(QgsProcessingParameterString(self.HOST, - self.tr('Host'), defaultValue='localhost', optional=True)) - self.addParameter(QgsProcessingParameterString(self.PORT, - self.tr('Port'), defaultValue='5432', optional=True)) - self.addParameter(QgsProcessingParameterString(self.USER, - self.tr('Username'), defaultValue='', optional=True)) - self.addParameter(QgsProcessingParameterString(self.DBNAME, - self.tr('Database name'), defaultValue='', optional=True)) - self.addParameter(QgsProcessingParameterString(self.PASSWORD, - self.tr('Password'), defaultValue='', optional=True)) - self.addParameter(QgsProcessingParameterString(self.SCHEMA, - self.tr('Schema name'), defaultValue='public', optional=True)) - self.addParameter(QgsProcessingParameterString(self.TABLE, - self.tr('Table name, leave blank to use input name'), - defaultValue='', optional=True)) - self.addParameter(QgsProcessingParameterString(self.PK, - self.tr('Primary key (new field)'), defaultValue='id', - optional=True)) - self.addParameter(QgsProcessingParameterField(self.PRIMARY_KEY, - self.tr( - 'Primary key (existing field, used if the above option is left empty)'), - parentLayerParameterName=self.INPUT, optional=True)) - self.addParameter(QgsProcessingParameterString(self.GEOCOLUMN, - self.tr('Geometry column name'), defaultValue='geom', - optional=True)) - self.addParameter(QgsProcessingParameterEnum(self.DIM, - self.tr('Vector dimensions'), options=self.DIMLIST, - defaultValue=0)) - self.addParameter(QgsProcessingParameterString(self.SIMPLIFY, - self.tr('Distance tolerance for simplification'), - defaultValue='', optional=True)) - self.addParameter(QgsProcessingParameterString(self.SEGMENTIZE, - self.tr('Maximum distance between 2 nodes (densification)'), - defaultValue='', optional=True)) - self.addParameter(QgsProcessingParameterExtent(self.SPAT, - self.tr( - 'Select features by extent (defined in input layer CRS)'), - optional=True)) - self.addParameter(QgsProcessingParameterBoolean(self.CLIP, - self.tr( - 'Clip the input layer using the above (rectangle) extent'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterField(self.FIELDS, - self.tr('Fields to include (leave empty to use all fields)'), - parentLayerParameterName=self.INPUT, - allowMultiple=True, optional=True)) - self.addParameter(QgsProcessingParameterString(self.WHERE, - self.tr( - 'Select features using a SQL "WHERE" statement (Ex: column=\'value\')'), - defaultValue='', optional=True)) - self.addParameter(QgsProcessingParameterString(self.GT, - self.tr('Group N features per transaction (Default: 20000)'), - defaultValue='', optional=True)) - self.addParameter(QgsProcessingParameterBoolean(self.OVERWRITE, - self.tr('Overwrite existing table'), defaultValue=True)) - self.addParameter(QgsProcessingParameterBoolean(self.APPEND, - self.tr('Append to existing table'), defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.ADDFIELDS, - self.tr('Append and add new fields to existing table'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.LAUNDER, - self.tr('Do not launder columns/table names'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.INDEX, - self.tr('Do not create spatial index'), defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.SKIPFAILURES, - self.tr( - 'Continue after a failure, skipping the failed feature'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.MAKEVALID, - self.tr( - 'Validate geometries based on Simple Features specification'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.PROMOTETOMULTI, - self.tr('Promote to Multipart'), - defaultValue=True)) - self.addParameter(QgsProcessingParameterBoolean(self.PRECISION, - self.tr('Keep width and precision of input attributes'), - defaultValue=True)) - self.addParameter(QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), defaultValue='', - optional=True)) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Input layer"), + types=[QgsProcessing.SourceType.TypeVector], + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.SHAPE_ENCODING, self.tr("Shape encoding"), "", optional=True + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.GTYPE, + self.tr("Output geometry type"), + options=self.GEOMTYPE, + defaultValue=0, + ) + ) + self.addParameter( + QgsProcessingParameterCrs( + self.A_SRS, + self.tr("Assign an output CRS"), + defaultValue="", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterCrs( + self.T_SRS, + self.tr("Reproject to this CRS on output "), + defaultValue="", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterCrs( + self.S_SRS, + self.tr("Override source CRS"), + defaultValue="", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.HOST, self.tr("Host"), defaultValue="localhost", optional=True + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.PORT, self.tr("Port"), defaultValue="5432", optional=True + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.USER, self.tr("Username"), defaultValue="", optional=True + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.DBNAME, self.tr("Database name"), defaultValue="", optional=True + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.PASSWORD, self.tr("Password"), defaultValue="", optional=True + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.SCHEMA, + self.tr("Schema name"), + defaultValue="public", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.TABLE, + self.tr("Table name, leave blank to use input name"), + defaultValue="", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.PK, + self.tr("Primary key (new field)"), + defaultValue="id", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.PRIMARY_KEY, + self.tr( + "Primary key (existing field, used if the above option is left empty)" + ), + parentLayerParameterName=self.INPUT, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.GEOCOLUMN, + self.tr("Geometry column name"), + defaultValue="geom", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.DIM, + self.tr("Vector dimensions"), + options=self.DIMLIST, + defaultValue=0, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.SIMPLIFY, + self.tr("Distance tolerance for simplification"), + defaultValue="", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.SEGMENTIZE, + self.tr("Maximum distance between 2 nodes (densification)"), + defaultValue="", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterExtent( + self.SPAT, + self.tr("Select features by extent (defined in input layer CRS)"), + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.CLIP, + self.tr("Clip the input layer using the above (rectangle) extent"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.FIELDS, + self.tr("Fields to include (leave empty to use all fields)"), + parentLayerParameterName=self.INPUT, + allowMultiple=True, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.WHERE, + self.tr( + "Select features using a SQL \"WHERE\" statement (Ex: column='value')" + ), + defaultValue="", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.GT, + self.tr("Group N features per transaction (Default: 20000)"), + defaultValue="", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.OVERWRITE, self.tr("Overwrite existing table"), defaultValue=True + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.APPEND, self.tr("Append to existing table"), defaultValue=False + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.ADDFIELDS, + self.tr("Append and add new fields to existing table"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.LAUNDER, + self.tr("Do not launder columns/table names"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.INDEX, self.tr("Do not create spatial index"), defaultValue=False + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.SKIPFAILURES, + self.tr("Continue after a failure, skipping the failed feature"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.MAKEVALID, + self.tr("Validate geometries based on Simple Features specification"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.PROMOTETOMULTI, self.tr("Promote to Multipart"), defaultValue=True + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.PRECISION, + self.tr("Keep width and precision of input attributes"), + defaultValue=True, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + ) def name(self): - return 'importvectorintopostgisdatabasenewconnection' + return "importvectorintopostgisdatabasenewconnection" def displayName(self): - return self.tr('Export to PostgreSQL (new connection)') + return self.tr("Export to PostgreSQL (new connection)") def shortDescription(self): - return self.tr('Exports a vector layer to a new PostgreSQL database connection') + return self.tr("Exports a vector layer to a new PostgreSQL database connection") def tags(self): - t = self.tr('import,into,postgis,database,vector').split(',') + t = self.tr("import,into,postgis,database,vector").split(",") t.extend(super().tags()) return t def group(self): - return self.tr('Vector miscellaneous') + return self.tr("Vector miscellaneous") def groupId(self): - return 'vectormiscellaneous' + return "vectormiscellaneous" def getConnectionString(self, parameters, context): host = self.parameterAsString(parameters, self.HOST, context) @@ -206,23 +366,27 @@ def getConnectionString(self, parameters, context): schema = self.parameterAsString(parameters, self.SCHEMA, context) arguments = [] if host: - arguments.append('host=' + host) + arguments.append("host=" + host) if port: - arguments.append('port=' + str(port)) + arguments.append("port=" + str(port)) if dbname: - arguments.append('dbname=' + dbname) + arguments.append("dbname=" + dbname) if password: - arguments.append('password=' + password) + arguments.append("password=" + password) if schema: - arguments.append('active_schema=' + schema) + arguments.append("active_schema=" + schema) if user: - arguments.append('user=' + user) + arguments.append("user=" + user) return GdalUtils.escapeAndJoin(arguments) def getConsoleCommands(self, parameters, context, feedback, executing=True): - input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing) + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) if not input_details.layer_name: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) shapeEncoding = self.parameterAsString(parameters, self.SHAPE_ENCODING, context) ssrs = self.parameterAsCrs(parameters, self.S_SRS, context) @@ -242,7 +406,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): spat = self.parameterAsExtent(parameters, self.SPAT, context) clip = self.parameterAsBoolean(parameters, self.CLIP, context) include_fields = self.parameterAsFields(parameters, self.FIELDS, context) - fields_string = '-select "' + ','.join(include_fields) + '"' + fields_string = '-select "' + ",".join(include_fields) + '"' where = self.parameterAsString(parameters, self.WHERE, context) wherestring = '-where "' + where + '"' gt = self.parameterAsString(parameters, self.GT, context) @@ -255,21 +419,20 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): indexstring = "-lco SPATIAL_INDEX=OFF" skipfailures = self.parameterAsBoolean(parameters, self.SKIPFAILURES, context) make_valid = self.parameterAsBoolean(parameters, self.MAKEVALID, context) - promotetomulti = self.parameterAsBoolean(parameters, self.PROMOTETOMULTI, context) + promotetomulti = self.parameterAsBoolean( + parameters, self.PROMOTETOMULTI, context + ) precision = self.parameterAsBoolean(parameters, self.PRECISION, context) options = self.parameterAsString(parameters, self.OPTIONS, context) - arguments = [ - '-progress', - '--config PG_USE_COPY YES' - ] + arguments = ["-progress", "--config PG_USE_COPY YES"] if len(shapeEncoding) > 0: - arguments.append('--config') - arguments.append('SHAPE_ENCODING') + arguments.append("--config") + arguments.append("SHAPE_ENCODING") arguments.append(shapeEncoding) - arguments.append('-f') - arguments.append('PostgreSQL') - arguments.append('PG:' + self.getConnectionString(parameters, context)) + arguments.append("-f") + arguments.append("PostgreSQL") + arguments.append("PG:" + self.getConnectionString(parameters, context)) arguments.append(dimstring) arguments.append(input_details.connection_string) arguments.append(input_details.layer_name) @@ -280,18 +443,25 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if append and overwrite: raise QgsProcessingException( self.tr( - 'Only one of "Overwrite existing table" or "Append to existing table" can be enabled at a time.')) + 'Only one of "Overwrite existing table" or "Append to existing table" can be enabled at a time.' + ) + ) elif append: - arguments.append('-append') + arguments.append("-append") if include_fields: arguments.append(fields_string) if addfields: - arguments.append('-addfields') + arguments.append("-addfields") if overwrite: - arguments.append('-overwrite') - if len(self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]) > 0: - arguments.append('-nlt') - arguments.append(self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]) + arguments.append("-overwrite") + if ( + len(self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]) + > 0 + ): + arguments.append("-nlt") + arguments.append( + self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)] + ) if len(geocolumn) > 0: arguments.append(geocolumnstring) if pk: @@ -301,52 +471,63 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if len(table) == 0: table = input_details.layer_name.lower() if schema: - table = f'{schema}.{table}' - arguments.append('-nln') + table = f"{schema}.{table}" + arguments.append("-nln") arguments.append(table) if ssrs.isValid(): - arguments.append('-s_srs') + arguments.append("-s_srs") arguments.append(GdalUtils.gdal_crs_string(ssrs)) if tsrs.isValid(): - arguments.append('-t_srs') + arguments.append("-t_srs") arguments.append(GdalUtils.gdal_crs_string(tsrs)) if asrs.isValid(): - arguments.append('-a_srs') + arguments.append("-a_srs") arguments.append(GdalUtils.gdal_crs_string(asrs)) if not spat.isNull(): - arguments.append('-spat') + arguments.append("-spat") arguments.append(spat.xMinimum()) arguments.append(spat.yMinimum()) arguments.append(spat.xMaximum()) arguments.append(spat.yMaximum()) if clip: - arguments.append('-clipsrc spat_extent') + arguments.append("-clipsrc spat_extent") if skipfailures: - arguments.append('-skipfailures') + arguments.append("-skipfailures") if where: arguments.append(wherestring) if len(simplify) > 0: - arguments.append('-simplify') + arguments.append("-simplify") arguments.append(simplify) if len(segmentize) > 0: - arguments.append('-segmentize') + arguments.append("-segmentize") arguments.append(segmentize) if len(gt) > 0: - arguments.append('-gt') + arguments.append("-gt") arguments.append(gt) if make_valid: - arguments.append('-makevalid') - if promotetomulti and self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]: - if self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)] == 'CONVERT_TO_LINEAR': - arguments.append('-nlt PROMOTE_TO_MULTI') + arguments.append("-makevalid") + if ( + promotetomulti + and self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)] + ): + if ( + self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)] + == "CONVERT_TO_LINEAR" + ): + arguments.append("-nlt PROMOTE_TO_MULTI") else: raise QgsProcessingException( self.tr( - 'Only one of "Promote to Multipart" or "Output geometry type" (excluding Convert to Linear) can be enabled.')) - elif promotetomulti and not self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]: - arguments.append('-nlt PROMOTE_TO_MULTI') + 'Only one of "Promote to Multipart" or "Output geometry type" (excluding Convert to Linear) can be enabled.' + ) + ) + elif ( + promotetomulti + and not self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)] + ): + arguments.append("-nlt PROMOTE_TO_MULTI") if precision is False: - arguments.append('-lco PRECISION=NO') + arguments.append("-lco PRECISION=NO") if input_details.open_options: arguments.extend(input_details.open_options_as_arguments()) @@ -358,10 +539,9 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments.append(options) if isWindows(): - return ['cmd.exe', '/C ', 'ogr2ogr.exe', - GdalUtils.escapeAndJoin(arguments)] + return ["cmd.exe", "/C ", "ogr2ogr.exe", GdalUtils.escapeAndJoin(arguments)] else: - return ['ogr2ogr', GdalUtils.escapeAndJoin(arguments)] + return ["ogr2ogr", GdalUtils.escapeAndJoin(arguments)] def commandName(self): - return 'ogr2ogr' + return "ogr2ogr" diff --git a/python/plugins/processing/algs/gdal/OneSideBuffer.py b/python/plugins/processing/algs/gdal/OneSideBuffer.py index 3abd451edd27..f9b85b56dec1 100644 --- a/python/plugins/processing/algs/gdal/OneSideBuffer.py +++ b/python/plugins/processing/algs/gdal/OneSideBuffer.py @@ -15,102 +15,142 @@ *************************************************************************** """ -__author__ = 'Giovanni Manghi' -__date__ = 'January 2015' -__copyright__ = '(C) 2015, Giovanni Manghi' - -from qgis.core import (QgsProcessing, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterDistance, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterEnum, - QgsProcessingParameterField, - QgsProcessingParameterString, - QgsProcessingParameterBoolean, - QgsProcessingParameterVectorDestination) +__author__ = "Giovanni Manghi" +__date__ = "January 2015" +__copyright__ = "(C) 2015, Giovanni Manghi" + +from qgis.core import ( + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterDistance, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterEnum, + QgsProcessingParameterField, + QgsProcessingParameterString, + QgsProcessingParameterBoolean, + QgsProcessingParameterVectorDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils class OneSideBuffer(GdalAlgorithm): - INPUT = 'INPUT' - FIELD = 'FIELD' - BUFFER_SIDE = 'BUFFER_SIDE' - GEOMETRY = 'GEOMETRY' - DISTANCE = 'DISTANCE' - DISSOLVE = 'DISSOLVE' - EXPLODE_COLLECTIONS = 'EXPLODE_COLLECTIONS' - OPTIONS = 'OPTIONS' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + FIELD = "FIELD" + BUFFER_SIDE = "BUFFER_SIDE" + GEOMETRY = "GEOMETRY" + DISTANCE = "DISTANCE" + DISSOLVE = "DISSOLVE" + EXPLODE_COLLECTIONS = "EXPLODE_COLLECTIONS" + OPTIONS = "OPTIONS" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.bufferSides = [self.tr('Right'), self.tr('Left')] - - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), - [QgsProcessing.SourceType.TypeVectorLine])) - self.addParameter(QgsProcessingParameterString(self.GEOMETRY, - self.tr('Geometry column name'), - defaultValue='geometry')) - self.addParameter(QgsProcessingParameterDistance(self.DISTANCE, - self.tr('Buffer distance'), - defaultValue=10, - parentParameterName=self.INPUT)) - self.addParameter(QgsProcessingParameterEnum(self.BUFFER_SIDE, - self.tr('Buffer side'), - options=self.bufferSides, - allowMultiple=False, - defaultValue=0)) - self.addParameter(QgsProcessingParameterField(self.FIELD, - self.tr('Dissolve by attribute'), - None, - self.INPUT, - QgsProcessingParameterField.DataType.Any, - optional=True)) - self.addParameter(QgsProcessingParameterBoolean(self.DISSOLVE, - self.tr('Dissolve all results'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.EXPLODE_COLLECTIONS, - self.tr('Produce one feature for each geometry in any kind of geometry collection in the source file'), - defaultValue=False)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.bufferSides = [self.tr("Right"), self.tr("Left")] + + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Input layer"), + [QgsProcessing.SourceType.TypeVectorLine], + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.GEOMETRY, self.tr("Geometry column name"), defaultValue="geometry" + ) + ) + self.addParameter( + QgsProcessingParameterDistance( + self.DISTANCE, + self.tr("Buffer distance"), + defaultValue=10, + parentParameterName=self.INPUT, + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.BUFFER_SIDE, + self.tr("Buffer side"), + options=self.bufferSides, + allowMultiple=False, + defaultValue=0, + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.FIELD, + self.tr("Dissolve by attribute"), + None, + self.INPUT, + QgsProcessingParameterField.DataType.Any, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.DISSOLVE, self.tr("Dissolve all results"), defaultValue=False + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.EXPLODE_COLLECTIONS, + self.tr( + "Produce one feature for each geometry in any kind of geometry collection in the source file" + ), + defaultValue=False, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(options_param) - self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT, - self.tr('One-sided buffer'), - QgsProcessing.SourceType.TypeVectorPolygon)) + self.addParameter( + QgsProcessingParameterVectorDestination( + self.OUTPUT, + self.tr("One-sided buffer"), + QgsProcessing.SourceType.TypeVectorPolygon, + ) + ) def name(self): - return 'onesidebuffer' + return "onesidebuffer" def displayName(self): - return self.tr('One side buffer') + return self.tr("One side buffer") def group(self): - return self.tr('Vector geoprocessing') + return self.tr("Vector geoprocessing") def groupId(self): - return 'vectorgeoprocessing' + return "vectorgeoprocessing" def commandName(self): - return 'ogr2ogr' + return "ogr2ogr" def getConsoleCommands(self, parameters, context, feedback, executing=True): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) fields = source.fields() - input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing) + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) geometry = self.parameterAsString(parameters, self.GEOMETRY, context) distance = self.parameterAsDouble(parameters, self.DISTANCE, context) side = self.parameterAsEnum(parameters, self.BUFFER_SIDE, context) @@ -122,19 +162,16 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context) - other_fields_exist = any( - True for f in fields - if f.name() != geometry - ) + other_fields_exist = any(True for f in fields if f.name() != geometry) - other_fields = ',*' if other_fields_exist else '' + other_fields = ",*" if other_fields_exist else "" arguments = [ output_details.connection_string, input_details.connection_string, - '-dialect', - 'sqlite', - '-sql' + "-dialect", + "sqlite", + "-sql", ] if dissolve or fieldName: @@ -148,7 +185,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments.append(sql) if self.parameterAsBoolean(parameters, self.EXPLODE_COLLECTIONS, context): - arguments.append('-explodecollections') + arguments.append("-explodecollections") if input_details.open_options: arguments.extend(input_details.open_options_as_arguments()) @@ -160,6 +197,6 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments.append(options) if output_details.format: - arguments.append(f'-f {output_details.format}') + arguments.append(f"-f {output_details.format}") - return ['ogr2ogr', GdalUtils.escapeAndJoin(arguments)] + return ["ogr2ogr", GdalUtils.escapeAndJoin(arguments)] diff --git a/python/plugins/processing/algs/gdal/PointsAlongLines.py b/python/plugins/processing/algs/gdal/PointsAlongLines.py index 3d3f5daf7b3b..7b68237a027a 100644 --- a/python/plugins/processing/algs/gdal/PointsAlongLines.py +++ b/python/plugins/processing/algs/gdal/PointsAlongLines.py @@ -15,79 +15,105 @@ *************************************************************************** """ -__author__ = 'Giovanni Manghi' -__date__ = 'January 2015' -__copyright__ = '(C) 2015, Giovanni Manghi' - -from qgis.core import (QgsProcessingException, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterString, - QgsProcessingParameterNumber, - QgsProcessingParameterVectorDestination, - QgsProcessingParameterDefinition, - QgsProcessing) +__author__ = "Giovanni Manghi" +__date__ = "January 2015" +__copyright__ = "(C) 2015, Giovanni Manghi" + +from qgis.core import ( + QgsProcessingException, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterString, + QgsProcessingParameterNumber, + QgsProcessingParameterVectorDestination, + QgsProcessingParameterDefinition, + QgsProcessing, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils class PointsAlongLines(GdalAlgorithm): - INPUT = 'INPUT' - GEOMETRY = 'GEOMETRY' - DISTANCE = 'DISTANCE' - OPTIONS = 'OPTIONS' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + GEOMETRY = "GEOMETRY" + DISTANCE = "DISTANCE" + OPTIONS = "OPTIONS" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), - [QgsProcessing.SourceType.TypeVectorLine])) - self.addParameter(QgsProcessingParameterString(self.GEOMETRY, - self.tr('Geometry column name'), - defaultValue='geometry')) - self.addParameter(QgsProcessingParameterNumber(self.DISTANCE, - self.tr('Distance from line start represented as fraction of line length'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0, - maxValue=1, - defaultValue=0.5)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Input layer"), + [QgsProcessing.SourceType.TypeVectorLine], + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.GEOMETRY, self.tr("Geometry column name"), defaultValue="geometry" + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.DISTANCE, + self.tr( + "Distance from line start represented as fraction of line length" + ), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0, + maxValue=1, + defaultValue=0.5, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(options_param) - self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT, - self.tr('Points along lines'), - QgsProcessing.SourceType.TypeVectorPoint)) + self.addParameter( + QgsProcessingParameterVectorDestination( + self.OUTPUT, + self.tr("Points along lines"), + QgsProcessing.SourceType.TypeVectorPoint, + ) + ) def name(self): - return 'pointsalonglines' + return "pointsalonglines" def displayName(self): - return self.tr('Points along lines') + return self.tr("Points along lines") def group(self): - return self.tr('Vector geoprocessing') + return self.tr("Vector geoprocessing") def groupId(self): - return 'vectorgeoprocessing' + return "vectorgeoprocessing" def commandName(self): - return 'ogr2ogr' + return "ogr2ogr" def getConsoleCommands(self, parameters, context, feedback, executing=True): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) fields = source.fields() - input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing) + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) distance = self.parameterAsDouble(parameters, self.DISTANCE, context) geometry = self.parameterAsString(parameters, self.GEOMETRY, context) outFile = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) @@ -96,33 +122,29 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context) - other_fields_exist = any( - f for f in fields - if f.name() != geometry - ) + other_fields_exist = any(f for f in fields if f.name() != geometry) - other_fields = ',*' if other_fields_exist else '' + other_fields = ",*" if other_fields_exist else "" arguments = [ output_details.connection_string, input_details.connection_string, - '-dialect', - 'sqlite', - '-sql', - f'SELECT ST_Line_Interpolate_Point({geometry}, {distance}) AS {geometry}{other_fields} FROM "{input_details.layer_name}"' + "-dialect", + "sqlite", + "-sql", + f'SELECT ST_Line_Interpolate_Point({geometry}, {distance}) AS {geometry}{other_fields} FROM "{input_details.layer_name}"', ] if input_details.open_options: arguments.extend(input_details.open_options_as_arguments()) if input_details.credential_options: - arguments.extend( - input_details.credential_options_as_arguments()) + arguments.extend(input_details.credential_options_as_arguments()) if options: arguments.append(options) if output_details.format: - arguments.append(f'-f {output_details.format}') + arguments.append(f"-f {output_details.format}") - return ['ogr2ogr', GdalUtils.escapeAndJoin(arguments)] + return ["ogr2ogr", GdalUtils.escapeAndJoin(arguments)] diff --git a/python/plugins/processing/algs/gdal/aspect.py b/python/plugins/processing/algs/gdal/aspect.py index 33848481081f..72c021fa85aa 100644 --- a/python/plugins/processing/algs/gdal/aspect.py +++ b/python/plugins/processing/algs/gdal/aspect.py @@ -15,20 +15,22 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'October 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "October 2013" +__copyright__ = "(C) 2013, Alexander Bruy" import os -from qgis.core import (QgsProcessingException, - QgsRasterFileWriter, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterBand, - QgsProcessingParameterBoolean, - QgsProcessingParameterString, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsProcessingException, + QgsRasterFileWriter, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBand, + QgsProcessingParameterBoolean, + QgsProcessingParameterString, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -36,75 +38,107 @@ class aspect(GdalAlgorithm): - INPUT = 'INPUT' - BAND = 'BAND' - COMPUTE_EDGES = 'COMPUTE_EDGES' - ZEVENBERGEN = 'ZEVENBERGEN' - TRIG_ANGLE = 'TRIG_ANGLE' - ZERO_FLAT = 'ZERO_FLAT' - OPTIONS = 'OPTIONS' - EXTRA = 'EXTRA' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + BAND = "BAND" + COMPUTE_EDGES = "COMPUTE_EDGES" + ZEVENBERGEN = "ZEVENBERGEN" + TRIG_ANGLE = "TRIG_ANGLE" + ZERO_FLAT = "ZERO_FLAT" + OPTIONS = "OPTIONS" + EXTRA = "EXTRA" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterBand(self.BAND, - self.tr('Band number'), - 1, - parentLayerParameterName=self.INPUT)) - self.addParameter(QgsProcessingParameterBoolean(self.TRIG_ANGLE, - self.tr('Return trigonometric angle instead of azimuth'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.ZERO_FLAT, - self.tr('Return 0 for flat instead of -9999'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.COMPUTE_EDGES, - self.tr('Compute edges'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.ZEVENBERGEN, - self.tr("Use Zevenbergen&Thorne formula instead of the Horn's one"), - defaultValue=False)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterBand( + self.BAND, + self.tr("Band number"), + 1, + parentLayerParameterName=self.INPUT, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.TRIG_ANGLE, + self.tr("Return trigonometric angle instead of azimuth"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.ZERO_FLAT, + self.tr("Return 0 for flat instead of -9999"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.COMPUTE_EDGES, self.tr("Compute edges"), defaultValue=False + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.ZEVENBERGEN, + self.tr("Use Zevenbergen&Thorne formula instead of the Horn's one"), + defaultValue=False, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Aspect'))) + self.addParameter( + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Aspect")) + ) def name(self): - return 'aspect' + return "aspect" def displayName(self): - return self.tr('Aspect') + return self.tr("Aspect") def group(self): - return self.tr('Raster analysis') + return self.tr("Raster analysis") def groupId(self): - return 'rasteranalysis' + return "rasteranalysis" def commandName(self): - return 'gdaldem' + return "gdaldem" def getConsoleCommands(self, parameters, context, feedback, executing=True): - arguments = ['aspect'] + arguments = ["aspect"] inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) arguments.append(input_details.connection_string) @@ -115,26 +149,26 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) - arguments.append('-of') + arguments.append("-of") arguments.append(output_format) - arguments.append('-b') + arguments.append("-b") arguments.append(str(self.parameterAsInt(parameters, self.BAND, context))) if self.parameterAsBoolean(parameters, self.TRIG_ANGLE, context): - arguments.append('-trigonometric') + arguments.append("-trigonometric") if self.parameterAsBoolean(parameters, self.ZERO_FLAT, context): - arguments.append('-zero_for_flat') + arguments.append("-zero_for_flat") if self.parameterAsBoolean(parameters, self.COMPUTE_EDGES, context): - arguments.append('-compute_edges') + arguments.append("-compute_edges") if self.parameterAsBoolean(parameters, self.ZEVENBERGEN, context): - arguments.append('-alg') - arguments.append('ZevenbergenThorne') + arguments.append("-alg") + arguments.append("ZevenbergenThorne") options = self.parameterAsString(parameters, self.OPTIONS, context) if options: @@ -143,7 +177,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if input_details.credential_options: arguments.extend(input_details.credential_options_as_arguments()) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) diff --git a/python/plugins/processing/algs/gdal/buildvrt.py b/python/plugins/processing/algs/gdal/buildvrt.py index 7707cdc91859..74728de91703 100644 --- a/python/plugins/processing/algs/gdal/buildvrt.py +++ b/python/plugins/processing/algs/gdal/buildvrt.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Radoslaw Guzinski' -__date__ = 'October 2014' -__copyright__ = '(C) 2014, Radoslaw Guzinski' +__author__ = "Radoslaw Guzinski" +__date__ = "October 2014" +__copyright__ = "(C) 2014, Radoslaw Guzinski" import os import pathlib @@ -25,19 +25,21 @@ from qgis.PyQt.QtCore import QCoreApplication from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsProcessingAlgorithm, - QgsProcessing, - QgsProcessingParameterDefinition, - QgsProperty, - QgsProcessingParameters, - QgsProcessingParameterMultipleLayers, - QgsProcessingParameterEnum, - QgsProcessingParameterBoolean, - QgsProcessingParameterRasterDestination, - QgsProcessingParameterCrs, - QgsProcessingParameterString, - QgsProcessingOutputLayerDefinition, - QgsProcessingUtils) +from qgis.core import ( + QgsProcessingAlgorithm, + QgsProcessing, + QgsProcessingParameterDefinition, + QgsProperty, + QgsProcessingParameters, + QgsProcessingParameterMultipleLayers, + QgsProcessingParameterEnum, + QgsProcessingParameterBoolean, + QgsProcessingParameterRasterDestination, + QgsProcessingParameterCrs, + QgsProcessingParameterString, + QgsProcessingOutputLayerDefinition, + QgsProcessingUtils, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -45,16 +47,16 @@ class buildvrt(GdalAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' - RESOLUTION = 'RESOLUTION' - SEPARATE = 'SEPARATE' - PROJ_DIFFERENCE = 'PROJ_DIFFERENCE' - ADD_ALPHA = 'ADD_ALPHA' - ASSIGN_CRS = 'ASSIGN_CRS' - RESAMPLING = 'RESAMPLING' - SRC_NODATA = 'SRC_NODATA' - EXTRA = 'EXTRA' + INPUT = "INPUT" + OUTPUT = "OUTPUT" + RESOLUTION = "RESOLUTION" + SEPARATE = "SEPARATE" + PROJ_DIFFERENCE = "PROJ_DIFFERENCE" + ADD_ALPHA = "ADD_ALPHA" + ASSIGN_CRS = "ASSIGN_CRS" + RESAMPLING = "RESAMPLING" + SRC_NODATA = "SRC_NODATA" + EXTRA = "EXTRA" def __init__(self): super().__init__() @@ -71,141 +73,209 @@ def clone(self): return copy def defaultFileExtension(self): - return 'vrt' + return "vrt" def createFileFilter(self): - return '{} (*.vrt *.VRT)'.format(QCoreApplication.translate("GdalAlgorithm", 'VRT files')) + return "{} (*.vrt *.VRT)".format( + QCoreApplication.translate("GdalAlgorithm", "VRT files") + ) def supportedOutputRasterLayerExtensions(self): - return ['vrt'] + return ["vrt"] def parameterAsOutputLayer(self, definition, value, context): - return super(QgsProcessingParameterRasterDestination, self).parameterAsOutputLayer(definition, value, context) + return super( + QgsProcessingParameterRasterDestination, self + ).parameterAsOutputLayer(definition, value, context) def isSupportedOutputValue(self, value, context): - output_path = QgsProcessingParameters.parameterAsOutputLayer(self, value, context, testOnly=True) - if pathlib.Path(output_path).suffix.lower() != '.vrt': - return False, QCoreApplication.translate("GdalAlgorithm", 'Output filename must use a .vrt extension') - return True, '' - - self.RESAMPLING_OPTIONS = ((self.tr('Nearest Neighbour'), 'nearest'), - (self.tr('Bilinear (2x2 Kernel)'), 'bilinear'), - (self.tr('Cubic (4x4 Kernel)'), 'cubic'), - (self.tr('Cubic B-Spline (4x4 Kernel)'), 'cubicspline'), - (self.tr('Lanczos (6x6 Kernel)'), 'lanczos'), - (self.tr('Average'), 'average'), - (self.tr('Mode'), 'mode')) - - self.RESOLUTION_OPTIONS = ((self.tr('Average'), 'average'), - (self.tr('Highest'), 'highest'), - (self.tr('Lowest'), 'lowest')) - - self.addParameter(QgsProcessingParameterMultipleLayers(self.INPUT, - self.tr('Input layers'), - QgsProcessing.SourceType.TypeRaster)) - self.addParameter(QgsProcessingParameterEnum(self.RESOLUTION, - self.tr('Resolution'), - options=[i[0] for i in self.RESOLUTION_OPTIONS], - defaultValue=0)) - - separate_param = QgsProcessingParameterBoolean(self.SEPARATE, - self.tr('Place each input file into a separate band'), - defaultValue=True) + output_path = QgsProcessingParameters.parameterAsOutputLayer( + self, value, context, testOnly=True + ) + if pathlib.Path(output_path).suffix.lower() != ".vrt": + return False, QCoreApplication.translate( + "GdalAlgorithm", "Output filename must use a .vrt extension" + ) + return True, "" + + self.RESAMPLING_OPTIONS = ( + (self.tr("Nearest Neighbour"), "nearest"), + (self.tr("Bilinear (2x2 Kernel)"), "bilinear"), + (self.tr("Cubic (4x4 Kernel)"), "cubic"), + (self.tr("Cubic B-Spline (4x4 Kernel)"), "cubicspline"), + (self.tr("Lanczos (6x6 Kernel)"), "lanczos"), + (self.tr("Average"), "average"), + (self.tr("Mode"), "mode"), + ) + + self.RESOLUTION_OPTIONS = ( + (self.tr("Average"), "average"), + (self.tr("Highest"), "highest"), + (self.tr("Lowest"), "lowest"), + ) + + self.addParameter( + QgsProcessingParameterMultipleLayers( + self.INPUT, self.tr("Input layers"), QgsProcessing.SourceType.TypeRaster + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.RESOLUTION, + self.tr("Resolution"), + options=[i[0] for i in self.RESOLUTION_OPTIONS], + defaultValue=0, + ) + ) + + separate_param = QgsProcessingParameterBoolean( + self.SEPARATE, + self.tr("Place each input file into a separate band"), + defaultValue=True, + ) # default to not using separate bands is a friendlier option, but we can't change the parameter's actual # defaultValue without breaking API! separate_param.setGuiDefaultValueOverride(False) self.addParameter(separate_param) - self.addParameter(QgsProcessingParameterBoolean(self.PROJ_DIFFERENCE, - self.tr('Allow projection difference'), - defaultValue=False)) - - add_alpha_param = QgsProcessingParameterBoolean(self.ADD_ALPHA, - self.tr('Add alpha mask band to VRT when source raster has none'), - defaultValue=False) - add_alpha_param.setFlags(add_alpha_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.addParameter( + QgsProcessingParameterBoolean( + self.PROJ_DIFFERENCE, + self.tr("Allow projection difference"), + defaultValue=False, + ) + ) + + add_alpha_param = QgsProcessingParameterBoolean( + self.ADD_ALPHA, + self.tr("Add alpha mask band to VRT when source raster has none"), + defaultValue=False, + ) + add_alpha_param.setFlags( + add_alpha_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(add_alpha_param) - assign_crs = QgsProcessingParameterCrs(self.ASSIGN_CRS, - self.tr('Override projection for the output file'), - defaultValue=None, optional=True) - assign_crs.setFlags(assign_crs.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + assign_crs = QgsProcessingParameterCrs( + self.ASSIGN_CRS, + self.tr("Override projection for the output file"), + defaultValue=None, + optional=True, + ) + assign_crs.setFlags( + assign_crs.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(assign_crs) - resampling = QgsProcessingParameterEnum(self.RESAMPLING, - self.tr('Resampling algorithm'), - options=[i[0] for i in self.RESAMPLING_OPTIONS], - defaultValue=0) - resampling.setFlags(resampling.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + resampling = QgsProcessingParameterEnum( + self.RESAMPLING, + self.tr("Resampling algorithm"), + options=[i[0] for i in self.RESAMPLING_OPTIONS], + defaultValue=0, + ) + resampling.setFlags( + resampling.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(resampling) - src_nodata_param = QgsProcessingParameterString(self.SRC_NODATA, - self.tr('Nodata value(s) for input bands (space separated)'), - defaultValue=None, - optional=True) - src_nodata_param.setFlags(src_nodata_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + src_nodata_param = QgsProcessingParameterString( + self.SRC_NODATA, + self.tr("Nodata value(s) for input bands (space separated)"), + defaultValue=None, + optional=True, + ) + src_nodata_param.setFlags( + src_nodata_param.flags() + | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(src_nodata_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - self.addParameter(ParameterVrtDestination(self.OUTPUT, QCoreApplication.translate("ParameterVrtDestination", 'Virtual'))) + self.addParameter( + ParameterVrtDestination( + self.OUTPUT, + QCoreApplication.translate("ParameterVrtDestination", "Virtual"), + ) + ) def name(self): - return 'buildvirtualraster' + return "buildvirtualraster" def displayName(self): - return QCoreApplication.translate("buildvrt", 'Build virtual raster') + return QCoreApplication.translate("buildvrt", "Build virtual raster") def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'vrt.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "vrt.png")) def group(self): - return QCoreApplication.translate("buildvrt", 'Raster miscellaneous') + return QCoreApplication.translate("buildvrt", "Raster miscellaneous") def groupId(self): - return 'rastermiscellaneous' + return "rastermiscellaneous" def commandName(self): return "gdalbuildvrt" def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments = [ - '-overwrite', - '-resolution', - self.RESOLUTION_OPTIONS[self.parameterAsEnum(parameters, self.RESOLUTION, context)][1] + "-overwrite", + "-resolution", + self.RESOLUTION_OPTIONS[ + self.parameterAsEnum(parameters, self.RESOLUTION, context) + ][1], ] if self.parameterAsBoolean(parameters, buildvrt.SEPARATE, context): - arguments.append('-separate') + arguments.append("-separate") if self.parameterAsBoolean(parameters, buildvrt.PROJ_DIFFERENCE, context): - arguments.append('-allow_projection_difference') + arguments.append("-allow_projection_difference") if self.parameterAsBoolean(parameters, buildvrt.ADD_ALPHA, context): - arguments.append('-addalpha') + arguments.append("-addalpha") crs = self.parameterAsCrs(parameters, self.ASSIGN_CRS, context) if crs.isValid(): - arguments.append('-a_srs') + arguments.append("-a_srs") arguments.append(GdalUtils.gdal_crs_string(crs)) - arguments.append('-r') - arguments.append(self.RESAMPLING_OPTIONS[self.parameterAsEnum(parameters, self.RESAMPLING, context)][1]) - - if self.SRC_NODATA in parameters and parameters[self.SRC_NODATA] not in (None, ''): + arguments.append("-r") + arguments.append( + self.RESAMPLING_OPTIONS[ + self.parameterAsEnum(parameters, self.RESAMPLING, context) + ][1] + ) + + if self.SRC_NODATA in parameters and parameters[self.SRC_NODATA] not in ( + None, + "", + ): nodata = self.parameterAsString(parameters, self.SRC_NODATA, context) - arguments.append('-srcnodata') + arguments.append("-srcnodata") arguments.append(nodata) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) # Always write input files to a text file in case there are many of them and the # length of the command will be longer then allowed in command prompt - list_file = GdalUtils.writeLayerParameterToTextFile(filename='buildvrtInputFiles.txt', alg=self, parameters=parameters, parameter_name=self.INPUT, context=context, executing=executing, quote=False) - arguments.append('-input_file_list') + list_file = GdalUtils.writeLayerParameterToTextFile( + filename="buildvrtInputFiles.txt", + alg=self, + parameters=parameters, + parameter_name=self.INPUT, + context=context, + executing=executing, + quote=False, + ) + arguments.append("-input_file_list") arguments.append(list_file) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) diff --git a/python/plugins/processing/algs/gdal/contour.py b/python/plugins/processing/algs/gdal/contour.py index 5a98ad63023a..d85e1aa876d1 100644 --- a/python/plugins/processing/algs/gdal/contour.py +++ b/python/plugins/processing/algs/gdal/contour.py @@ -15,23 +15,25 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'September 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "September 2013" +__copyright__ = "(C) 2013, Alexander Bruy" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsProcessing, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterBand, - QgsProcessingParameterString, - QgsProcessingParameterNumber, - QgsProcessingParameterBoolean, - QgsProcessingParameterVectorDestination) +from qgis.core import ( + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBand, + QgsProcessingParameterString, + QgsProcessingParameterNumber, + QgsProcessingParameterBoolean, + QgsProcessingParameterVectorDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -39,106 +41,151 @@ class contour(GdalAlgorithm): - INPUT = 'INPUT' - BAND = 'BAND' - INTERVAL = 'INTERVAL' - FIELD_NAME = 'FIELD_NAME' - CREATE_3D = 'CREATE_3D' - IGNORE_NODATA = 'IGNORE_NODATA' - NODATA = 'NODATA' - OFFSET = 'OFFSET' - EXTRA = 'EXTRA' - OPTIONS = 'OPTIONS' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + BAND = "BAND" + INTERVAL = "INTERVAL" + FIELD_NAME = "FIELD_NAME" + CREATE_3D = "CREATE_3D" + IGNORE_NODATA = "IGNORE_NODATA" + NODATA = "NODATA" + OFFSET = "OFFSET" + EXTRA = "EXTRA" + OPTIONS = "OPTIONS" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterBand(self.BAND, - self.tr('Band number'), - 1, - parentLayerParameterName=self.INPUT)) - self.addParameter(QgsProcessingParameterNumber(self.INTERVAL, - self.tr('Interval between contour lines'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=10.0)) - self.addParameter(QgsProcessingParameterString(self.FIELD_NAME, - self.tr('Attribute name (if not set, no elevation attribute is attached)'), - defaultValue='ELEV', - optional=True)) - - create_3d_param = QgsProcessingParameterBoolean(self.CREATE_3D, - self.tr('Produce 3D vector'), - defaultValue=False) - create_3d_param.setFlags(create_3d_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterBand( + self.BAND, + self.tr("Band number"), + 1, + parentLayerParameterName=self.INPUT, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.INTERVAL, + self.tr("Interval between contour lines"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=10.0, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.FIELD_NAME, + self.tr( + "Attribute name (if not set, no elevation attribute is attached)" + ), + defaultValue="ELEV", + optional=True, + ) + ) + + create_3d_param = QgsProcessingParameterBoolean( + self.CREATE_3D, self.tr("Produce 3D vector"), defaultValue=False + ) + create_3d_param.setFlags( + create_3d_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(create_3d_param) - ignore_nodata_param = QgsProcessingParameterBoolean(self.IGNORE_NODATA, - self.tr('Treat all raster values as valid'), - defaultValue=False) - ignore_nodata_param.setFlags(ignore_nodata_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + ignore_nodata_param = QgsProcessingParameterBoolean( + self.IGNORE_NODATA, + self.tr("Treat all raster values as valid"), + defaultValue=False, + ) + ignore_nodata_param.setFlags( + ignore_nodata_param.flags() + | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(ignore_nodata_param) - nodata_param = QgsProcessingParameterNumber(self.NODATA, - self.tr('Input pixel value to treat as NoData'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=None, - optional=True) - nodata_param.setFlags(nodata_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + nodata_param = QgsProcessingParameterNumber( + self.NODATA, + self.tr("Input pixel value to treat as NoData"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=None, + optional=True, + ) + nodata_param.setFlags( + nodata_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(nodata_param) - offset_param = QgsProcessingParameterNumber(self.OFFSET, - self.tr('Offset from zero relative to which to interpret intervals'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=0.0, - optional=True) - nodata_param.setFlags(offset_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + offset_param = QgsProcessingParameterNumber( + self.OFFSET, + self.tr("Offset from zero relative to which to interpret intervals"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=0.0, + optional=True, + ) + nodata_param.setFlags( + offset_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(offset_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) # TODO: remove in QGIS 4 - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden) + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden + ) self.addParameter(options_param) - self.addParameter(QgsProcessingParameterVectorDestination( - self.OUTPUT, self.tr('Contours'), QgsProcessing.SourceType.TypeVectorLine)) + self.addParameter( + QgsProcessingParameterVectorDestination( + self.OUTPUT, + self.tr("Contours"), + QgsProcessing.SourceType.TypeVectorLine, + ) + ) def name(self): - return 'contour' + return "contour" def displayName(self): - return self.tr('Contour') + return self.tr("Contour") def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'contour.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "contour.png")) def group(self): - return self.tr('Raster extraction') + return self.tr("Raster extraction") def groupId(self): - return 'rasterextraction' + return "rasterextraction" def commandName(self): - return 'gdal_contour' + return "gdal_contour" def _buildArgsList(self, parameters, context, feedback, executing): inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) fieldName = self.parameterAsString(parameters, self.FIELD_NAME, context) @@ -152,36 +199,35 @@ def _buildArgsList(self, parameters, context, feedback, executing): self.setOutputValue(self.OUTPUT, outFile) output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context) - arguments = [ - '-b', - str(self.parameterAsInt(parameters, self.BAND, context)) - ] + arguments = ["-b", str(self.parameterAsInt(parameters, self.BAND, context))] if fieldName: - arguments.append('-a') + arguments.append("-a") arguments.append(fieldName) - arguments.append('-i') - arguments.append(str(self.parameterAsDouble(parameters, self.INTERVAL, context))) + arguments.append("-i") + arguments.append( + str(self.parameterAsDouble(parameters, self.INTERVAL, context)) + ) if self.parameterAsBoolean(parameters, self.CREATE_3D, context): - arguments.append('-3d') + arguments.append("-3d") if self.parameterAsBoolean(parameters, self.IGNORE_NODATA, context): - arguments.append('-inodata') + arguments.append("-inodata") if nodata is not None: - arguments.append(f'-snodata {nodata}') + arguments.append(f"-snodata {nodata}") if offset: - arguments.append(f'-off {offset}') + arguments.append(f"-off {offset}") if output_details.format: - arguments.append(f'-f {output_details.format}') + arguments.append(f"-f {output_details.format}") if input_details.credential_options: arguments.extend(input_details.credential_options_as_arguments()) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) @@ -200,8 +246,8 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): class contour_polygon(contour): - FIELD_NAME_MIN = 'FIELD_NAME_MIN' - FIELD_NAME_MAX = 'FIELD_NAME_MAX' + FIELD_NAME_MIN = "FIELD_NAME_MIN" + FIELD_NAME_MAX = "FIELD_NAME_MAX" def __init__(self): super().__init__() @@ -211,26 +257,39 @@ def initAlgorithm(self, config=None): # FIELD_NAME isn't used in polygon mode self.removeParameter(contour.FIELD_NAME) - self.addParameter(QgsProcessingParameterString(self.FIELD_NAME_MIN, - self.tr('Attribute name for minimum elevation of contour polygon'), - defaultValue='ELEV_MIN', - optional=True)) - - self.addParameter(QgsProcessingParameterString(self.FIELD_NAME_MAX, - self.tr('Attribute name for maximum elevation of contour polygon'), - defaultValue='ELEV_MAX', - optional=True)) + self.addParameter( + QgsProcessingParameterString( + self.FIELD_NAME_MIN, + self.tr("Attribute name for minimum elevation of contour polygon"), + defaultValue="ELEV_MIN", + optional=True, + ) + ) + + self.addParameter( + QgsProcessingParameterString( + self.FIELD_NAME_MAX, + self.tr("Attribute name for maximum elevation of contour polygon"), + defaultValue="ELEV_MAX", + optional=True, + ) + ) # Need to replace the output parameter, as we are producing a different type of output self.removeParameter(contour.OUTPUT) - self.addParameter(QgsProcessingParameterVectorDestination( - contour.OUTPUT, self.tr('Contours'), QgsProcessing.SourceType.TypeVectorPolygon)) + self.addParameter( + QgsProcessingParameterVectorDestination( + contour.OUTPUT, + self.tr("Contours"), + QgsProcessing.SourceType.TypeVectorPolygon, + ) + ) def name(self): - return 'contour_polygon' + return "contour_polygon" def displayName(self): - return self.tr('Contour Polygons') + return self.tr("Contour Polygons") def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments = self._buildArgsList(parameters, context, feedback, executing) @@ -240,11 +299,11 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if fieldNameMin: arguments.insert(0, fieldNameMin) - arguments.insert(0, '-amin') + arguments.insert(0, "-amin") if fieldNameMax: arguments.insert(0, fieldNameMax) - arguments.insert(0, '-amax') + arguments.insert(0, "-amax") arguments.insert(0, "-p") diff --git a/python/plugins/processing/algs/gdal/extractprojection.py b/python/plugins/processing/algs/gdal/extractprojection.py index e51a07048ed5..ff34e77e4cc2 100644 --- a/python/plugins/processing/algs/gdal/extractprojection.py +++ b/python/plugins/processing/algs/gdal/extractprojection.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'September 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "September 2013" +__copyright__ = "(C) 2013, Alexander Bruy" import os @@ -27,9 +27,11 @@ from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from qgis.core import QgsProcessingException -from qgis.core import (QgsProcessingParameterRasterLayer, - QgsProcessingParameterBoolean, - QgsProcessingOutputFile) +from qgis.core import ( + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBoolean, + QgsProcessingOutputFile, +) pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] @@ -38,61 +40,58 @@ class ExtractProjection(GdalAlgorithm): - INPUT = 'INPUT' - PRJ_FILE_CREATE = 'PRJ_FILE_CREATE' - WORLD_FILE = 'WORLD_FILE' - PRJ_FILE = 'PRJ_FILE' + INPUT = "INPUT" + PRJ_FILE_CREATE = "PRJ_FILE_CREATE" + WORLD_FILE = "WORLD_FILE" + PRJ_FILE = "PRJ_FILE" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer( - self.INPUT, - self.tr('Input file'))) - self.addParameter(QgsProcessingParameterBoolean( - self.PRJ_FILE_CREATE, - self.tr('Create also .prj file'), False)) - self.addOutput(QgsProcessingOutputFile( - self.WORLD_FILE, - self.tr('World file'))) - self.addOutput(QgsProcessingOutputFile( - self.PRJ_FILE, - self.tr('ESRI Shapefile prj file'))) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input file")) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.PRJ_FILE_CREATE, self.tr("Create also .prj file"), False + ) + ) + self.addOutput(QgsProcessingOutputFile(self.WORLD_FILE, self.tr("World file"))) + self.addOutput( + QgsProcessingOutputFile(self.PRJ_FILE, self.tr("ESRI Shapefile prj file")) + ) def name(self): - return 'extractprojection' + return "extractprojection" def displayName(self): - return self.tr('Extract projection') + return self.tr("Extract projection") def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', - 'projection-export.png')) + return QIcon( + os.path.join(pluginPath, "images", "gdaltools", "projection-export.png") + ) def group(self): - return self.tr('Raster projections') + return self.tr("Raster projections") def groupId(self): - return 'rasterprojections' + return "rasterprojections" def commandName(self): - return 'extractprojection' + return "extractprojection" - def getConsoleCommands(self, parameters, context, feedback, - executing=True): + def getConsoleCommands(self, parameters, context, feedback, executing=True): return [self.commandName()] def processAlgorithm(self, parameters, context, feedback): - createPrj = self.parameterAsBoolean(parameters, - self.PRJ_FILE_CREATE, - context) - raster = self.parameterAsRasterLayer(parameters, self.INPUT, - context) - if raster.dataProvider().name() != 'gdal': - raise QgsProcessingException(self.tr('This algorithm can ' - 'only be used with ' - 'GDAL raster layers')) + createPrj = self.parameterAsBoolean(parameters, self.PRJ_FILE_CREATE, context) + raster = self.parameterAsRasterLayer(parameters, self.INPUT, context) + if raster.dataProvider().name() != "gdal": + raise QgsProcessingException( + self.tr("This algorithm can " "only be used with " "GDAL raster layers") + ) rasterPath = raster.source() rasterDS = gdal.Open(rasterPath, gdal.GA_ReadOnly) geotransform = rasterDS.GetGeoTransform() @@ -105,36 +104,38 @@ def processAlgorithm(self, parameters, context, feedback): outFileName = inFileName[0] # this is not a good idea as it won't work with an extension like .jpeg # outFileExt = '.' + inFileName[1][1:4:2] + 'w' - if (len(inFileName[1]) < 4): - outFileExt = '.wld' + if len(inFileName[1]) < 4: + outFileExt = ".wld" else: - outFileExt = inFileName[1][0:2] + inFileName[1][-1] + 'w' + outFileExt = inFileName[1][0:2] + inFileName[1][-1] + "w" results = {} - if crs != '' and createPrj: + if crs != "" and createPrj: tmp = osr.SpatialReference() tmp.ImportFromWkt(crs) tmp.MorphToESRI() crs = tmp.ExportToWkt() tmp = None - with open(outFileName + '.prj', 'w', encoding='utf-8') as prj: + with open(outFileName + ".prj", "w", encoding="utf-8") as prj: prj.write(crs) - results[self.PRJ_FILE] = outFileName + '.prj' + results[self.PRJ_FILE] = outFileName + ".prj" else: results[self.PRJ_FILE] = None - with open(outFileName + outFileExt, 'w') as wld: - wld.write('%0.8f\n' % geotransform[1]) - wld.write('%0.8f\n' % geotransform[4]) - wld.write('%0.8f\n' % geotransform[2]) - wld.write('%0.8f\n' % geotransform[5]) - wld.write('%0.8f\n' % (geotransform[0] - + 0.5 * geotransform[1] - + 0.5 * geotransform[2])) - wld.write('%0.8f\n' % (geotransform[3] - + 0.5 * geotransform[4] - + 0.5 * geotransform[5])) + with open(outFileName + outFileExt, "w") as wld: + wld.write("%0.8f\n" % geotransform[1]) + wld.write("%0.8f\n" % geotransform[4]) + wld.write("%0.8f\n" % geotransform[2]) + wld.write("%0.8f\n" % geotransform[5]) + wld.write( + "%0.8f\n" + % (geotransform[0] + 0.5 * geotransform[1] + 0.5 * geotransform[2]) + ) + wld.write( + "%0.8f\n" + % (geotransform[3] + 0.5 * geotransform[4] + 0.5 * geotransform[5]) + ) results[self.WORLD_FILE] = outFileName + outFileExt return results diff --git a/python/plugins/processing/algs/gdal/fillnodata.py b/python/plugins/processing/algs/gdal/fillnodata.py index b313c0294c6a..8e7143b5f3eb 100644 --- a/python/plugins/processing/algs/gdal/fillnodata.py +++ b/python/plugins/processing/algs/gdal/fillnodata.py @@ -15,22 +15,24 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os -from qgis.core import (QgsProcessingAlgorithm, - QgsRasterFileWriter, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterBand, - QgsProcessingParameterNumber, - QgsProcessingParameterBoolean, - QgsProcessingParameterString, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsProcessingAlgorithm, + QgsRasterFileWriter, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBand, + QgsProcessingParameterNumber, + QgsProcessingParameterBoolean, + QgsProcessingParameterString, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.tools.system import isWindows from processing.algs.gdal.GdalUtils import GdalUtils @@ -39,80 +41,114 @@ class fillnodata(GdalAlgorithm): - INPUT = 'INPUT' - BAND = 'BAND' - DISTANCE = 'DISTANCE' - ITERATIONS = 'ITERATIONS' - NO_MASK = 'NO_MASK' - MASK_LAYER = 'MASK_LAYER' - OPTIONS = 'OPTIONS' - EXTRA = 'EXTRA' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + BAND = "BAND" + DISTANCE = "DISTANCE" + ITERATIONS = "ITERATIONS" + NO_MASK = "NO_MASK" + MASK_LAYER = "MASK_LAYER" + OPTIONS = "OPTIONS" + EXTRA = "EXTRA" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterBand(self.BAND, - self.tr('Band number'), - 1, - parentLayerParameterName=self.INPUT)) - self.addParameter(QgsProcessingParameterNumber(self.DISTANCE, - self.tr('Maximum distance (in pixels) to search out for values to interpolate'), - type=QgsProcessingParameterNumber.Type.Integer, - minValue=0, - defaultValue=10)) - self.addParameter(QgsProcessingParameterNumber(self.ITERATIONS, - self.tr('Number of smoothing iterations to run after the interpolation'), - type=QgsProcessingParameterNumber.Type.Integer, - minValue=0, - defaultValue=0)) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterBand( + self.BAND, + self.tr("Band number"), + 1, + parentLayerParameterName=self.INPUT, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.DISTANCE, + self.tr( + "Maximum distance (in pixels) to search out for values to interpolate" + ), + type=QgsProcessingParameterNumber.Type.Integer, + minValue=0, + defaultValue=10, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.ITERATIONS, + self.tr( + "Number of smoothing iterations to run after the interpolation" + ), + type=QgsProcessingParameterNumber.Type.Integer, + minValue=0, + defaultValue=0, + ) + ) # The -nomask option is no longer supported since GDAL 3.4 and # it doesn't work as expected even using GDAL < 3.4 https://github.com/OSGeo/gdal/pull/4201 - nomask_param = QgsProcessingParameterBoolean(self.NO_MASK, - self.tr('Do not use the default validity mask for the input band'), - defaultValue=False, - optional=True) - nomask_param.setFlags(nomask_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden) + nomask_param = QgsProcessingParameterBoolean( + self.NO_MASK, + self.tr("Do not use the default validity mask for the input band"), + defaultValue=False, + optional=True, + ) + nomask_param.setFlags( + nomask_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden + ) self.addParameter(nomask_param) - self.addParameter(QgsProcessingParameterRasterLayer(self.MASK_LAYER, - self.tr('Validity mask'), - optional=True)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.addParameter( + QgsProcessingParameterRasterLayer( + self.MASK_LAYER, self.tr("Validity mask"), optional=True + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Filled'))) + self.addParameter( + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Filled")) + ) def name(self): - return 'fillnodata' + return "fillnodata" def displayName(self): - return self.tr('Fill NoData') + return self.tr("Fill NoData") def group(self): - return self.tr('Raster analysis') + return self.tr("Raster analysis") def groupId(self): - return 'rasteranalysis' + return "rasteranalysis" def commandName(self): - return 'gdal_fillnodata' + return "gdal_fillnodata" def flags(self): return super().flags() | QgsProcessingAlgorithm.Flag.FlagDisplayNameIsLiteral @@ -120,7 +156,9 @@ def flags(self): def getConsoleCommands(self, parameters, context, feedback, executing=True): raster = self.parameterAsRasterLayer(parameters, self.INPUT, context) if raster is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) input_details = GdalUtils.gdal_connection_details_from_layer(raster) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) @@ -129,34 +167,34 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments = [ input_details.connection_string, out, - '-md', + "-md", str(self.parameterAsInt(parameters, self.DISTANCE, context)), ] nIterations = self.parameterAsInt(parameters, self.ITERATIONS, context) if nIterations: - arguments.append('-si') + arguments.append("-si") arguments.append(str(nIterations)) - arguments.append('-b') + arguments.append("-b") arguments.append(str(self.parameterAsInt(parameters, self.BAND, context))) mask = self.parameterAsRasterLayer(parameters, self.MASK_LAYER, context) if mask: - arguments.append('-mask') + arguments.append("-mask") arguments.append(mask.source()) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) - arguments.append('-of') + arguments.append("-of") arguments.append(output_format) if input_details.credential_options: arguments.extend(input_details.credential_options_as_arguments()) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) @@ -165,4 +203,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)] + return [ + self.commandName() + (".bat" if isWindows() else ".py"), + GdalUtils.escapeAndJoin(arguments), + ] diff --git a/python/plugins/processing/algs/gdal/gdal2tiles.py b/python/plugins/processing/algs/gdal/gdal2tiles.py index 6e3ba4e6524d..ad60c3284b9f 100644 --- a/python/plugins/processing/algs/gdal/gdal2tiles.py +++ b/python/plugins/processing/algs/gdal/gdal2tiles.py @@ -15,209 +15,264 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'January 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' - -from qgis.core import (QgsProcessingAlgorithm, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterCrs, - QgsProcessingParameterEnum, - QgsProcessingParameterString, - QgsProcessingParameterNumber, - QgsProcessingParameterBoolean, - QgsProcessingParameterFolderDestination) +__author__ = "Médéric Ribreux" +__date__ = "January 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" + +from qgis.core import ( + QgsProcessingAlgorithm, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterCrs, + QgsProcessingParameterEnum, + QgsProcessingParameterString, + QgsProcessingParameterNumber, + QgsProcessingParameterBoolean, + QgsProcessingParameterFolderDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils from processing.tools.system import isWindows class gdal2tiles(GdalAlgorithm): - INPUT = 'INPUT' - PROFILE = 'PROFILE' - RESAMPLING = 'RESAMPLING' - ZOOM = 'ZOOM' - SOURCE_CRS = 'SOURCE_CRS' - NODATA = 'NODATA' - KML = 'KML' - NO_KML = 'NO_KML' - URL = 'URL' - VIEWER = 'VIEWER' - TITLE = 'TITLE' - COPYRIGHT = 'COPYRIGHT' - GOOGLE_KEY = 'GOOGLE_KEY' - BING_KEY = 'BING_KEY' - RESUME = 'RESUME' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + PROFILE = "PROFILE" + RESAMPLING = "RESAMPLING" + ZOOM = "ZOOM" + SOURCE_CRS = "SOURCE_CRS" + NODATA = "NODATA" + KML = "KML" + NO_KML = "NO_KML" + URL = "URL" + VIEWER = "VIEWER" + TITLE = "TITLE" + COPYRIGHT = "COPYRIGHT" + GOOGLE_KEY = "GOOGLE_KEY" + BING_KEY = "BING_KEY" + RESUME = "RESUME" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.profiles = ((self.tr('Mercator'), 'mercator'), - (self.tr('Geodetic'), 'geodetic'), - (self.tr('Raster'), 'raster')) - - self.methods = ((self.tr('Average'), 'average'), - (self.tr('Nearest Neighbour'), 'near'), - (self.tr('Bilinear (2x2 Kernel)'), 'bilinear'), - (self.tr('Cubic (4x4 Kernel)'), 'cubic'), - (self.tr('Cubic B-Spline (4x4 Kernel)'), 'cubicspline'), - (self.tr('Lanczos (6x6 Kernel)'), 'lanczos'), - (self.tr('Antialias'), 'antialias')) - - self.viewers = ((self.tr('All'), 'all'), - (self.tr('GoogleMaps'), 'google'), - (self.tr('OpenLayers'), 'openlayers'), - (self.tr('Leaflet'), 'leaflet'), - (self.tr('None'), 'none')) - - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterEnum(self.PROFILE, - self.tr('Tile cutting profile'), - options=[i[0] for i in self.profiles], - allowMultiple=False, - defaultValue=0)) - self.addParameter(QgsProcessingParameterString(self.ZOOM, - self.tr('Zoom levels to render'), - defaultValue='', - optional=True)) - self.addParameter(QgsProcessingParameterEnum(self.VIEWER, - self.tr('Web viewer to generate'), - options=[i[0] for i in self.viewers], - allowMultiple=False, - defaultValue=0)) - self.addParameter(QgsProcessingParameterString(self.TITLE, - self.tr('Title of the map'), - optional=True)) - self.addParameter(QgsProcessingParameterString(self.COPYRIGHT, - self.tr('Copyright of the map'), - optional=True)) + self.profiles = ( + (self.tr("Mercator"), "mercator"), + (self.tr("Geodetic"), "geodetic"), + (self.tr("Raster"), "raster"), + ) + + self.methods = ( + (self.tr("Average"), "average"), + (self.tr("Nearest Neighbour"), "near"), + (self.tr("Bilinear (2x2 Kernel)"), "bilinear"), + (self.tr("Cubic (4x4 Kernel)"), "cubic"), + (self.tr("Cubic B-Spline (4x4 Kernel)"), "cubicspline"), + (self.tr("Lanczos (6x6 Kernel)"), "lanczos"), + (self.tr("Antialias"), "antialias"), + ) + + self.viewers = ( + (self.tr("All"), "all"), + (self.tr("GoogleMaps"), "google"), + (self.tr("OpenLayers"), "openlayers"), + (self.tr("Leaflet"), "leaflet"), + (self.tr("None"), "none"), + ) + + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.PROFILE, + self.tr("Tile cutting profile"), + options=[i[0] for i in self.profiles], + allowMultiple=False, + defaultValue=0, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.ZOOM, + self.tr("Zoom levels to render"), + defaultValue="", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.VIEWER, + self.tr("Web viewer to generate"), + options=[i[0] for i in self.viewers], + allowMultiple=False, + defaultValue=0, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.TITLE, self.tr("Title of the map"), optional=True + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.COPYRIGHT, self.tr("Copyright of the map"), optional=True + ) + ) params = [ - QgsProcessingParameterEnum(self.RESAMPLING, - self.tr('Resampling method'), - options=[i[0] for i in self.methods], - allowMultiple=False, - defaultValue=0), - QgsProcessingParameterCrs(self.SOURCE_CRS, - self.tr('The spatial reference system used for the source input data'), - optional=True), - QgsProcessingParameterNumber(self.NODATA, - self.tr('Transparency value to assign to the input data'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=0, - optional=True), - QgsProcessingParameterString(self.URL, - self.tr('URL address where the generated tiles are going to be published'), - optional=True), - QgsProcessingParameterString(self.GOOGLE_KEY, - self.tr('Google Maps API key (http://code.google.com/apis/maps/signup.html)'), - optional=True), - QgsProcessingParameterString(self.BING_KEY, - self.tr('Bing Maps API key (https://www.bingmapsportal.com/)'), - optional=True), - QgsProcessingParameterBoolean(self.RESUME, - self.tr('Generate only missing files'), - defaultValue=False), - QgsProcessingParameterBoolean(self.KML, - self.tr('Generate KML for Google Earth'), - defaultValue=False), - QgsProcessingParameterBoolean(self.NO_KML, - self.tr('Avoid automatic generation of KML files for EPSG:4326'), - defaultValue=False) + QgsProcessingParameterEnum( + self.RESAMPLING, + self.tr("Resampling method"), + options=[i[0] for i in self.methods], + allowMultiple=False, + defaultValue=0, + ), + QgsProcessingParameterCrs( + self.SOURCE_CRS, + self.tr("The spatial reference system used for the source input data"), + optional=True, + ), + QgsProcessingParameterNumber( + self.NODATA, + self.tr("Transparency value to assign to the input data"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=0, + optional=True, + ), + QgsProcessingParameterString( + self.URL, + self.tr( + "URL address where the generated tiles are going to be published" + ), + optional=True, + ), + QgsProcessingParameterString( + self.GOOGLE_KEY, + self.tr( + "Google Maps API key (http://code.google.com/apis/maps/signup.html)" + ), + optional=True, + ), + QgsProcessingParameterString( + self.BING_KEY, + self.tr("Bing Maps API key (https://www.bingmapsportal.com/)"), + optional=True, + ), + QgsProcessingParameterBoolean( + self.RESUME, self.tr("Generate only missing files"), defaultValue=False + ), + QgsProcessingParameterBoolean( + self.KML, self.tr("Generate KML for Google Earth"), defaultValue=False + ), + QgsProcessingParameterBoolean( + self.NO_KML, + self.tr("Avoid automatic generation of KML files for EPSG:4326"), + defaultValue=False, + ), ] for param in params: - param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + param.setFlags( + param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(param) - self.addParameter(QgsProcessingParameterFolderDestination(self.OUTPUT, - self.tr('Output directory'))) + self.addParameter( + QgsProcessingParameterFolderDestination( + self.OUTPUT, self.tr("Output directory") + ) + ) def name(self): - return 'gdal2tiles' + return "gdal2tiles" def displayName(self): - return self.tr('gdal2tiles') + return self.tr("gdal2tiles") def group(self): - return self.tr('Raster miscellaneous') + return self.tr("Raster miscellaneous") def groupId(self): - return 'rastermiscellaneous' + return "rastermiscellaneous" def commandName(self): - return 'gdal2tiles' + return "gdal2tiles" def flags(self): return super().flags() | QgsProcessingAlgorithm.Flag.FlagDisplayNameIsLiteral def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments = [ - '-p', + "-p", self.profiles[self.parameterAsEnum(parameters, self.PROFILE, context)][1], ] zoom = self.parameterAsString(parameters, self.ZOOM, context) if zoom: - arguments.append('-z') + arguments.append("-z") arguments.append(str(zoom)) - arguments.append('-w') - arguments.append(self.viewers[self.parameterAsEnum(parameters, self.VIEWER, context)][1]) + arguments.append("-w") + arguments.append( + self.viewers[self.parameterAsEnum(parameters, self.VIEWER, context)][1] + ) title = self.parameterAsString(parameters, self.TITLE, context) if title: - arguments.append('-t') + arguments.append("-t") arguments.append(title) copying = self.parameterAsString(parameters, self.COPYRIGHT, context) if copying: - arguments.append('-c') + arguments.append("-c") arguments.append(copying) - arguments.append('-r') - arguments.append(self.methods[self.parameterAsEnum(parameters, self.RESAMPLING, context)][1]) + arguments.append("-r") + arguments.append( + self.methods[self.parameterAsEnum(parameters, self.RESAMPLING, context)][1] + ) crs = self.parameterAsCrs(parameters, self.SOURCE_CRS, context) if crs.isValid(): - arguments.append('-s') + arguments.append("-s") arguments.append(GdalUtils.gdal_crs_string(crs)) if self.NODATA in parameters and parameters[self.NODATA] is not None: nodata = self.parameterAsDouble(parameters, self.NODATA, context) - arguments.append('-a') + arguments.append("-a") arguments.append(str(nodata)) url = self.parameterAsString(parameters, self.URL, context) if url: - arguments.append('-u') + arguments.append("-u") arguments.append(url) key = self.parameterAsString(parameters, self.GOOGLE_KEY, context) if key: - arguments.append('-g') + arguments.append("-g") arguments.append(key) key = self.parameterAsString(parameters, self.BING_KEY, context) if key: - arguments.append('-b') + arguments.append("-b") arguments.append(key) if self.parameterAsBoolean(parameters, self.RESUME, context): - arguments.append('-e') + arguments.append("-e") if self.parameterAsBoolean(parameters, self.KML, context): - arguments.append('-k') + arguments.append("-k") if self.parameterAsBoolean(parameters, self.NO_KML, context): - arguments.append('-n') + arguments.append("-n") inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) @@ -227,4 +282,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if input_details.credential_options: arguments.extend(input_details.credential_options_as_arguments()) - return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)] + return [ + self.commandName() + (".bat" if isWindows() else ".py"), + GdalUtils.escapeAndJoin(arguments), + ] diff --git a/python/plugins/processing/algs/gdal/gdal2xyz.py b/python/plugins/processing/algs/gdal/gdal2xyz.py index 4b23bd172259..c56fc2d86419 100644 --- a/python/plugins/processing/algs/gdal/gdal2xyz.py +++ b/python/plugins/processing/algs/gdal/gdal2xyz.py @@ -15,112 +15,149 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'September 2013' -__copyright__ = '(C) 2013, Alexander Bruy' - -from qgis.core import (QgsProcessingAlgorithm, - QgsProcessingException, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterBand, - QgsProcessingParameterBoolean, - QgsProcessingParameterFileDestination, - QgsProcessingParameterNumber - ) +__author__ = "Alexander Bruy" +__date__ = "September 2013" +__copyright__ = "(C) 2013, Alexander Bruy" + +from qgis.core import ( + QgsProcessingAlgorithm, + QgsProcessingException, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBand, + QgsProcessingParameterBoolean, + QgsProcessingParameterFileDestination, + QgsProcessingParameterNumber, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils from processing.tools.system import isWindows class gdal2xyz(GdalAlgorithm): - INPUT = 'INPUT' - BAND = 'BAND' - SRCNODATA = 'NODATA_INPUT' - DSTNODATA = 'NODATA_OUTPUT' - SKIPNODATA = 'SKIP_NODATA' - CSV = 'CSV' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + BAND = "BAND" + SRCNODATA = "NODATA_INPUT" + DSTNODATA = "NODATA_OUTPUT" + SKIPNODATA = "SKIP_NODATA" + CSV = "CSV" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterBand(self.BAND, - self.tr('Band number'), - 1, - parentLayerParameterName=self.INPUT)) - - self.addParameter(QgsProcessingParameterNumber(self.SRCNODATA, - self.tr('Input pixel value to treat as NoData'), - optional=True)) # GDAL > 3.6.3 - self.addParameter(QgsProcessingParameterNumber(self.DSTNODATA, - self.tr('Assign specified NoData value to output'), - optional=True)) # GDAL > 3.6.3 - self.addParameter(QgsProcessingParameterBoolean(self.SKIPNODATA, - self.tr('Do not output NoData values'), - defaultValue=False)) # GDAL > 3.3 - self.addParameter(QgsProcessingParameterBoolean(self.CSV, - self.tr('Output comma-separated values'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, - self.tr('XYZ ASCII file'), - self.tr('CSV files (*.csv)'))) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterBand( + self.BAND, + self.tr("Band number"), + 1, + parentLayerParameterName=self.INPUT, + ) + ) + + self.addParameter( + QgsProcessingParameterNumber( + self.SRCNODATA, + self.tr("Input pixel value to treat as NoData"), + optional=True, + ) + ) # GDAL > 3.6.3 + self.addParameter( + QgsProcessingParameterNumber( + self.DSTNODATA, + self.tr("Assign specified NoData value to output"), + optional=True, + ) + ) # GDAL > 3.6.3 + self.addParameter( + QgsProcessingParameterBoolean( + self.SKIPNODATA, + self.tr("Do not output NoData values"), + defaultValue=False, + ) + ) # GDAL > 3.3 + self.addParameter( + QgsProcessingParameterBoolean( + self.CSV, self.tr("Output comma-separated values"), defaultValue=False + ) + ) + self.addParameter( + QgsProcessingParameterFileDestination( + self.OUTPUT, self.tr("XYZ ASCII file"), self.tr("CSV files (*.csv)") + ) + ) def name(self): - return 'gdal2xyz' + return "gdal2xyz" def displayName(self): - return self.tr('gdal2xyz') + return self.tr("gdal2xyz") def group(self): - return self.tr('Raster conversion') + return self.tr("Raster conversion") def groupId(self): - return 'rasterconversion' + return "rasterconversion" def commandName(self): - return 'gdal2xyz' + return "gdal2xyz" def flags(self): return super().flags() | QgsProcessingAlgorithm.Flag.FlagDisplayNameIsLiteral def getConsoleCommands(self, parameters, context, feedback, executing=True): - arguments = [ - '-band', - str(self.parameterAsInt(parameters, self.BAND, context)) - ] + arguments = ["-band", str(self.parameterAsInt(parameters, self.BAND, context))] if self.SRCNODATA in parameters and parameters[self.SRCNODATA] is not None: - if GdalUtils.version() > 3060300: # src/dstnodata broken <= 3.6.3 https://github.com/OSGeo/gdal/issues/7410 + if ( + GdalUtils.version() > 3060300 + ): # src/dstnodata broken <= 3.6.3 https://github.com/OSGeo/gdal/issues/7410 srcnodata = self.parameterAsDouble(parameters, self.SRCNODATA, context) - arguments.append('-srcnodata') + arguments.append("-srcnodata") arguments.append(srcnodata) else: - raise QgsProcessingException(self.tr('The source nodata option (-srcnodata) is only available on GDAL 3.6.4 or later')) + raise QgsProcessingException( + self.tr( + "The source nodata option (-srcnodata) is only available on GDAL 3.6.4 or later" + ) + ) if self.DSTNODATA in parameters and parameters[self.DSTNODATA] is not None: - if GdalUtils.version() > 3060300: # src/dstnodata broken <= 3.6.3 https://github.com/OSGeo/gdal/issues/7410 + if ( + GdalUtils.version() > 3060300 + ): # src/dstnodata broken <= 3.6.3 https://github.com/OSGeo/gdal/issues/7410 dstnodata = self.parameterAsDouble(parameters, self.DSTNODATA, context) - arguments.append('-dstnodata') + arguments.append("-dstnodata") arguments.append(dstnodata) else: - raise QgsProcessingException(self.tr('The destination nodata option (-dstnodata) is only available on GDAL 3.6.4 or later')) + raise QgsProcessingException( + self.tr( + "The destination nodata option (-dstnodata) is only available on GDAL 3.6.4 or later" + ) + ) if self.SKIPNODATA in parameters: if GdalUtils.version() >= 3030000: # skipnodata added at GDAL 3.3 if self.parameterAsBoolean(parameters, self.SKIPNODATA, context): - arguments.append('-skipnodata') + arguments.append("-skipnodata") else: - raise QgsProcessingException(self.tr('The skip nodata option (-skipnodata) is only available on GDAL 3.3 or later')) + raise QgsProcessingException( + self.tr( + "The skip nodata option (-skipnodata) is only available on GDAL 3.3 or later" + ) + ) if self.parameterAsBoolean(parameters, self.CSV, context): - arguments.append('-csv') + arguments.append("-csv") raster = self.parameterAsRasterLayer(parameters, self.INPUT, context) if raster is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) input_details = GdalUtils.gdal_connection_details_from_layer(raster) @@ -130,4 +167,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if input_details.credential_options: arguments.extend(input_details.credential_options_as_arguments()) - return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)] + return [ + self.commandName() + (".bat" if isWindows() else ".py"), + GdalUtils.escapeAndJoin(arguments), + ] diff --git a/python/plugins/processing/algs/gdal/gdaladdo.py b/python/plugins/processing/algs/gdal/gdaladdo.py index 57fedb07229a..1a89afba1e16 100644 --- a/python/plugins/processing/algs/gdal/gdaladdo.py +++ b/python/plugins/processing/algs/gdal/gdaladdo.py @@ -15,21 +15,23 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterEnum, - QgsProcessingParameterString, - QgsProcessingParameterBoolean, - QgsProcessingOutputRasterLayer) +from qgis.core import ( + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterEnum, + QgsProcessingParameterString, + QgsProcessingParameterBoolean, + QgsProcessingOutputRasterLayer, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -37,114 +39,151 @@ class gdaladdo(GdalAlgorithm): - INPUT = 'INPUT' - LEVELS = 'LEVELS' - CLEAN = 'CLEAN' - RESAMPLING = 'RESAMPLING' - FORMAT = 'FORMAT' - EXTRA = 'EXTRA' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + LEVELS = "LEVELS" + CLEAN = "CLEAN" + RESAMPLING = "RESAMPLING" + FORMAT = "FORMAT" + EXTRA = "EXTRA" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.methods = ((self.tr('Nearest Neighbour (default)'), 'nearest'), - (self.tr('Average'), 'average'), - (self.tr('Gaussian'), 'gauss'), - (self.tr('Cubic (4x4 Kernel)'), 'cubic'), - (self.tr('Cubic B-Spline (4x4 Kernel)'), 'cubicspline'), - (self.tr('Lanczos (6x6 Kernel)'), 'lanczos'), - (self.tr('Average MP'), 'average_mp'), - (self.tr('Average in Mag/Phase Space'), 'average_magphase'), - (self.tr('Mode'), 'mode')) - - self.formats = (self.tr('Internal (if possible)'), - self.tr('External (GTiff .ovr)'), - self.tr('External (ERDAS Imagine .aux)')) - - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterBoolean(self.CLEAN, - self.tr('Remove all existing overviews'), - defaultValue=False)) + self.methods = ( + (self.tr("Nearest Neighbour (default)"), "nearest"), + (self.tr("Average"), "average"), + (self.tr("Gaussian"), "gauss"), + (self.tr("Cubic (4x4 Kernel)"), "cubic"), + (self.tr("Cubic B-Spline (4x4 Kernel)"), "cubicspline"), + (self.tr("Lanczos (6x6 Kernel)"), "lanczos"), + (self.tr("Average MP"), "average_mp"), + (self.tr("Average in Mag/Phase Space"), "average_magphase"), + (self.tr("Mode"), "mode"), + ) + + self.formats = ( + self.tr("Internal (if possible)"), + self.tr("External (GTiff .ovr)"), + self.tr("External (ERDAS Imagine .aux)"), + ) + + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.CLEAN, self.tr("Remove all existing overviews"), defaultValue=False + ) + ) if GdalUtils.version() < 230000: - self.addParameter(QgsProcessingParameterString(self.LEVELS, - self.tr('Overview levels'), - defaultValue='2 4 8 16')) + self.addParameter( + QgsProcessingParameterString( + self.LEVELS, self.tr("Overview levels"), defaultValue="2 4 8 16" + ) + ) params = [] if GdalUtils.version() >= 230000: - params.append(QgsProcessingParameterString(self.LEVELS, - self.tr('Overview levels (e.g. 2 4 8 16)'), - defaultValue=None, - optional=True)) - params.append(QgsProcessingParameterEnum(self.RESAMPLING, - self.tr('Resampling method'), - options=[i[0] for i in self.methods], - allowMultiple=False, - defaultValue=None, - optional=True)) - params.append(QgsProcessingParameterEnum(self.FORMAT, - self.tr('Overviews format'), - options=self.formats, - allowMultiple=False, - defaultValue=0, - optional=True)) - params.append(QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True)) + params.append( + QgsProcessingParameterString( + self.LEVELS, + self.tr("Overview levels (e.g. 2 4 8 16)"), + defaultValue=None, + optional=True, + ) + ) + params.append( + QgsProcessingParameterEnum( + self.RESAMPLING, + self.tr("Resampling method"), + options=[i[0] for i in self.methods], + allowMultiple=False, + defaultValue=None, + optional=True, + ) + ) + params.append( + QgsProcessingParameterEnum( + self.FORMAT, + self.tr("Overviews format"), + options=self.formats, + allowMultiple=False, + defaultValue=0, + optional=True, + ) + ) + params.append( + QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + ) for p in params: p.setFlags(p.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) self.addParameter(p) - self.addOutput(QgsProcessingOutputRasterLayer(self.OUTPUT, self.tr('Pyramidized'))) + self.addOutput( + QgsProcessingOutputRasterLayer(self.OUTPUT, self.tr("Pyramidized")) + ) def name(self): - return 'overviews' + return "overviews" def displayName(self): - return self.tr('Build overviews (pyramids)') + return self.tr("Build overviews (pyramids)") def group(self): - return self.tr('Raster miscellaneous') + return self.tr("Raster miscellaneous") def groupId(self): - return 'rastermiscellaneous' + return "rastermiscellaneous" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'raster-overview.png')) + return QIcon( + os.path.join(pluginPath, "images", "gdaltools", "raster-overview.png") + ) def commandName(self): - return 'gdaladdo' + return "gdaladdo" def getConsoleCommands(self, parameters, context, feedback, executing=True): inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) arguments = [input_details.connection_string] if self.RESAMPLING in parameters and parameters[self.RESAMPLING] is not None: - arguments.append('-r') - arguments.append(self.methods[self.parameterAsEnum(parameters, self.RESAMPLING, context)][1]) + arguments.append("-r") + arguments.append( + self.methods[ + self.parameterAsEnum(parameters, self.RESAMPLING, context) + ][1] + ) ovrFormat = self.parameterAsEnum(parameters, self.FORMAT, context) if ovrFormat == 1: - arguments.append('-ro') + arguments.append("-ro") elif ovrFormat == 2: - arguments.extend('--config USE_RRD YES'.split(' ')) + arguments.extend("--config USE_RRD YES".split(" ")) if self.parameterAsBoolean(parameters, self.CLEAN, context): - arguments.append('-clean') + arguments.append("-clean") - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) - arguments.extend(self.parameterAsString(parameters, self.LEVELS, context).split(' ')) + arguments.extend( + self.parameterAsString(parameters, self.LEVELS, context).split(" ") + ) if input_details.credential_options: arguments.extend(input_details.credential_options_as_arguments()) diff --git a/python/plugins/processing/algs/gdal/gdalcalc.py b/python/plugins/processing/algs/gdal/gdalcalc.py index 4380cc41751f..c8c1cf2b8851 100644 --- a/python/plugins/processing/algs/gdal/gdalcalc.py +++ b/python/plugins/processing/algs/gdal/gdalcalc.py @@ -15,19 +15,21 @@ *************************************************************************** """ -__author__ = 'Giovanni Manghi' -__date__ = 'January 2015' -__copyright__ = '(C) 2015, Giovanni Manghi' - -from qgis.core import (QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterBand, - QgsProcessingParameterNumber, - QgsProcessingParameterEnum, - QgsProcessingParameterExtent, - QgsProcessingParameterString, - QgsProcessingParameterRasterDestination) +__author__ = "Giovanni Manghi" +__date__ = "January 2015" +__copyright__ = "(C) 2015, Giovanni Manghi" + +from qgis.core import ( + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBand, + QgsProcessingParameterNumber, + QgsProcessingParameterEnum, + QgsProcessingParameterExtent, + QgsProcessingParameterString, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -35,31 +37,44 @@ class gdalcalc(GdalAlgorithm): - INPUT_A = 'INPUT_A' - INPUT_B = 'INPUT_B' - INPUT_C = 'INPUT_C' - INPUT_D = 'INPUT_D' - INPUT_E = 'INPUT_E' - INPUT_F = 'INPUT_F' - BAND_A = 'BAND_A' - BAND_B = 'BAND_B' - BAND_C = 'BAND_C' - BAND_D = 'BAND_D' - BAND_E = 'BAND_E' - BAND_F = 'BAND_F' - FORMULA = 'FORMULA' + INPUT_A = "INPUT_A" + INPUT_B = "INPUT_B" + INPUT_C = "INPUT_C" + INPUT_D = "INPUT_D" + INPUT_E = "INPUT_E" + INPUT_F = "INPUT_F" + BAND_A = "BAND_A" + BAND_B = "BAND_B" + BAND_C = "BAND_C" + BAND_D = "BAND_D" + BAND_E = "BAND_E" + BAND_F = "BAND_F" + FORMULA = "FORMULA" # TODO QGIS 4.0 : Rename EXTENT_OPT to EXTENT - EXTENT_OPT = 'EXTENT_OPT' - EXTENT_OPTIONS = ['ignore', 'fail', 'union', 'intersect'] + EXTENT_OPT = "EXTENT_OPT" + EXTENT_OPTIONS = ["ignore", "fail", "union", "intersect"] # TODO QGIS 4.0 : Rename EXTENT to PROJWIN or CUSTOM_EXTENT - EXTENT = 'PROJWIN' - OUTPUT = 'OUTPUT' - NO_DATA = 'NO_DATA' - OPTIONS = 'OPTIONS' - EXTRA = 'EXTRA' - RTYPE = 'RTYPE' - - TYPE = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8'] + EXTENT = "PROJWIN" + OUTPUT = "OUTPUT" + NO_DATA = "NO_DATA" + OPTIONS = "OPTIONS" + EXTRA = "EXTRA" + RTYPE = "RTYPE" + + TYPE = [ + "Byte", + "Int16", + "UInt16", + "UInt32", + "Int32", + "Float32", + "Float64", + "CInt16", + "CInt32", + "CFloat32", + "CFloat64", + "Int8", + ] def __init__(self): super().__init__() @@ -67,140 +82,172 @@ def __init__(self): def initAlgorithm(self, config=None): self.addParameter( QgsProcessingParameterRasterLayer( - self.INPUT_A, - self.tr('Input layer A'), - optional=False)) + self.INPUT_A, self.tr("Input layer A"), optional=False + ) + ) self.addParameter( QgsProcessingParameterBand( self.BAND_A, - self.tr('Number of raster band for A'), - parentLayerParameterName=self.INPUT_A)) + self.tr("Number of raster band for A"), + parentLayerParameterName=self.INPUT_A, + ) + ) self.addParameter( QgsProcessingParameterRasterLayer( - self.INPUT_B, - self.tr('Input layer B'), - optional=True)) + self.INPUT_B, self.tr("Input layer B"), optional=True + ) + ) self.addParameter( QgsProcessingParameterBand( self.BAND_B, - self.tr('Number of raster band for B'), + self.tr("Number of raster band for B"), parentLayerParameterName=self.INPUT_B, - optional=True)) + optional=True, + ) + ) self.addParameter( QgsProcessingParameterRasterLayer( - self.INPUT_C, - self.tr('Input layer C'), - optional=True)) + self.INPUT_C, self.tr("Input layer C"), optional=True + ) + ) self.addParameter( QgsProcessingParameterBand( self.BAND_C, - self.tr('Number of raster band for C'), + self.tr("Number of raster band for C"), parentLayerParameterName=self.INPUT_C, - optional=True)) + optional=True, + ) + ) self.addParameter( QgsProcessingParameterRasterLayer( - self.INPUT_D, - self.tr('Input layer D'), - optional=True)) + self.INPUT_D, self.tr("Input layer D"), optional=True + ) + ) self.addParameter( QgsProcessingParameterBand( self.BAND_D, - self.tr('Number of raster band for D'), + self.tr("Number of raster band for D"), parentLayerParameterName=self.INPUT_D, - optional=True)) + optional=True, + ) + ) self.addParameter( QgsProcessingParameterRasterLayer( - self.INPUT_E, - self.tr('Input layer E'), - optional=True)) + self.INPUT_E, self.tr("Input layer E"), optional=True + ) + ) self.addParameter( QgsProcessingParameterBand( self.BAND_E, - self.tr('Number of raster band for E'), + self.tr("Number of raster band for E"), parentLayerParameterName=self.INPUT_E, - optional=True)) + optional=True, + ) + ) self.addParameter( QgsProcessingParameterRasterLayer( - self.INPUT_F, - self.tr('Input layer F'), - optional=True)) + self.INPUT_F, self.tr("Input layer F"), optional=True + ) + ) self.addParameter( QgsProcessingParameterBand( self.BAND_F, - self.tr('Number of raster band for F'), + self.tr("Number of raster band for F"), parentLayerParameterName=self.INPUT_F, - optional=True)) + optional=True, + ) + ) self.addParameter( QgsProcessingParameterString( self.FORMULA, - self.tr('Calculation in gdalnumeric syntax using +-/* or any numpy array functions (i.e. logical_and())'), - 'A*2', - optional=False)) + self.tr( + "Calculation in gdalnumeric syntax using +-/* or any numpy array functions (i.e. logical_and())" + ), + "A*2", + optional=False, + ) + ) self.addParameter( QgsProcessingParameterNumber( self.NO_DATA, - self.tr('Set output NoData value'), + self.tr("Set output NoData value"), type=QgsProcessingParameterNumber.Type.Double, defaultValue=None, - optional=True)) + optional=True, + ) + ) if GdalUtils.version() >= 3030000: extent_opt_param = QgsProcessingParameterEnum( self.EXTENT_OPT, - self.tr('Handling of extent differences'), + self.tr("Handling of extent differences"), options=[o.title() for o in self.EXTENT_OPTIONS], - defaultValue=0) - extent_opt_param.setHelp(self.tr('This option determines how to handle rasters with different extents')) + defaultValue=0, + ) + extent_opt_param.setHelp( + self.tr( + "This option determines how to handle rasters with different extents" + ) + ) self.addParameter(extent_opt_param) if GdalUtils.version() >= 3030000: - extent_param = QgsProcessingParameterExtent(self.EXTENT, - self.tr('Output extent'), - optional=True) - extent_param.setHelp(self.tr('Custom extent of the output raster')) + extent_param = QgsProcessingParameterExtent( + self.EXTENT, self.tr("Output extent"), optional=True + ) + extent_param.setHelp(self.tr("Custom extent of the output raster")) self.addParameter(extent_param) self.addParameter( QgsProcessingParameterEnum( self.RTYPE, - self.tr('Output raster type'), + self.tr("Output raster type"), options=self.TYPE, - defaultValue=5)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + defaultValue=5, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) self.addParameter( - QgsProcessingParameterRasterDestination( - self.OUTPUT, - self.tr('Calculated'))) + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Calculated")) + ) def name(self): - return 'rastercalculator' + return "rastercalculator" def displayName(self): - return self.tr('Raster calculator') + return self.tr("Raster calculator") def group(self): - return self.tr('Raster miscellaneous') + return self.tr("Raster miscellaneous") def groupId(self): - return 'rastermiscellaneous' + return "rastermiscellaneous" def commandName(self): - return 'gdal_calc' + return "gdal_calc" def getConsoleCommands(self, parameters, context, feedback, executing=True): @@ -213,26 +260,37 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): noData = None arguments = [ - '--overwrite', + "--overwrite", f'--calc "{formula}"', - '--format', + "--format", GdalUtils.getFormatShortNameFromFilename(out), ] rtype = self.parameterAsEnum(parameters, self.RTYPE, context) - if self.TYPE[rtype] in ['CInt16', 'CInt32', 'CFloat32', 'CFloat64'] and GdalUtils.version() < 3050300: - raise QgsProcessingException(self.tr('{} data type requires GDAL version 3.5.3 or later').format(self.TYPE[rtype])) - if self.TYPE[rtype] == 'Int8' and GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later')) - - arguments.append('--type ' + self.TYPE[rtype]) + if ( + self.TYPE[rtype] in ["CInt16", "CInt32", "CFloat32", "CFloat64"] + and GdalUtils.version() < 3050300 + ): + raise QgsProcessingException( + self.tr("{} data type requires GDAL version 3.5.3 or later").format( + self.TYPE[rtype] + ) + ) + if self.TYPE[rtype] == "Int8" and GdalUtils.version() < 3070000: + raise QgsProcessingException( + self.tr("Int8 data type requires GDAL version 3.7 or later") + ) + + arguments.append("--type " + self.TYPE[rtype]) if noData is not None: - arguments.append('--NoDataValue') + arguments.append("--NoDataValue") arguments.append(noData) layer_a = self.parameterAsRasterLayer(parameters, self.INPUT_A, context) if layer_a is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_A)) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT_A) + ) layer_a_details = GdalUtils.gdal_connection_details_from_layer(layer_a) def all_equal(iterator): @@ -245,107 +303,165 @@ def all_equal(iterator): # Check GDAL version for projwin and extent options (GDAL 3.3 is required) if GdalUtils.version() < 3030000 and self.EXTENT in parameters.keys(): - raise QgsProcessingException(self.tr('The custom output extent option (--projwin) is only available on GDAL 3.3 or later')) + raise QgsProcessingException( + self.tr( + "The custom output extent option (--projwin) is only available on GDAL 3.3 or later" + ) + ) if GdalUtils.version() < 3030000 and self.EXTENT_OPT in parameters.keys(): - raise QgsProcessingException(self.tr('The output extent option (--extent) is only available on GDAL 3.3 or later')) + raise QgsProcessingException( + self.tr( + "The output extent option (--extent) is only available on GDAL 3.3 or later" + ) + ) # --projwin and --extent option are mutually exclusive - if (self.EXTENT in parameters.keys() and parameters[self.EXTENT] is not None) and (self.EXTENT_OPT in parameters.keys() and parameters[self.EXTENT_OPT] != 0): - raise QgsProcessingException(self.tr('The custom output extent option (--projwin) and output extent option (--extent) are mutually exclusive')) + if ( + self.EXTENT in parameters.keys() and parameters[self.EXTENT] is not None + ) and ( + self.EXTENT_OPT in parameters.keys() and parameters[self.EXTENT_OPT] != 0 + ): + raise QgsProcessingException( + self.tr( + "The custom output extent option (--projwin) and output extent option (--extent) are mutually exclusive" + ) + ) # If extent option is defined, pixel size and SRS of all input raster must be the same if self.EXTENT_OPT in parameters.keys() and parameters[self.EXTENT_OPT] != 0: pixel_size_X, pixel_size_Y, srs = [], [], [] - for input_layer in [self.INPUT_A, self.INPUT_B, self.INPUT_C, self.INPUT_D, self.INPUT_E, self.INPUT_F]: + for input_layer in [ + self.INPUT_A, + self.INPUT_B, + self.INPUT_C, + self.INPUT_D, + self.INPUT_E, + self.INPUT_F, + ]: if input_layer in parameters and parameters[input_layer] is not None: - layer = self.parameterAsRasterLayer(parameters, input_layer, context) + layer = self.parameterAsRasterLayer( + parameters, input_layer, context + ) pixel_size_X.append(layer.rasterUnitsPerPixelX()) pixel_size_Y.append(layer.rasterUnitsPerPixelY()) srs.append(layer.crs().authid()) - if not (all_equal(pixel_size_X) and all_equal(pixel_size_Y) and all_equal(srs)): - raise QgsProcessingException(self.tr('For all output extent options, the pixel size (resolution) and SRS (Spatial Reference System) of all the input rasters must be the same')) - - extent = self.EXTENT_OPTIONS[self.parameterAsEnum(parameters, self.EXTENT_OPT, context)] - if extent != 'ignore': - arguments.append(f'--extent={extent}') + if not ( + all_equal(pixel_size_X) and all_equal(pixel_size_Y) and all_equal(srs) + ): + raise QgsProcessingException( + self.tr( + "For all output extent options, the pixel size (resolution) and SRS (Spatial Reference System) of all the input rasters must be the same" + ) + ) + + extent = self.EXTENT_OPTIONS[ + self.parameterAsEnum(parameters, self.EXTENT_OPT, context) + ] + if extent != "ignore": + arguments.append(f"--extent={extent}") bbox = self.parameterAsExtent(parameters, self.EXTENT, context, layer_a.crs()) if not bbox.isNull(): - arguments.append('--projwin') + arguments.append("--projwin") arguments.append(str(bbox.xMinimum())) arguments.append(str(bbox.yMaximum())) arguments.append(str(bbox.xMaximum())) arguments.append(str(bbox.yMinimum())) - arguments.append('-A') + arguments.append("-A") arguments.append(layer_a_details.connection_string) if self.parameterAsString(parameters, self.BAND_A, context): - arguments.append('--A_band ' + self.parameterAsString(parameters, self.BAND_A, context)) + arguments.append( + "--A_band " + self.parameterAsString(parameters, self.BAND_A, context) + ) if self.INPUT_B in parameters and parameters[self.INPUT_B] is not None: layer_b = self.parameterAsRasterLayer(parameters, self.INPUT_B, context) if layer_b is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_B)) - input_b_details = GdalUtils.gdal_connection_details_from_layer( - layer_b) - arguments.append('-B') + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT_B) + ) + input_b_details = GdalUtils.gdal_connection_details_from_layer(layer_b) + arguments.append("-B") arguments.append(input_b_details.connection_string) if self.parameterAsString(parameters, self.BAND_B, context): - arguments.append('--B_band ' + self.parameterAsString(parameters, self.BAND_B, context)) + arguments.append( + "--B_band " + + self.parameterAsString(parameters, self.BAND_B, context) + ) if self.INPUT_C in parameters and parameters[self.INPUT_C] is not None: layer_c = self.parameterAsRasterLayer(parameters, self.INPUT_C, context) if layer_c is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_C)) - input_c_details = GdalUtils.gdal_connection_details_from_layer( - layer_c) - arguments.append('-C') + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT_C) + ) + input_c_details = GdalUtils.gdal_connection_details_from_layer(layer_c) + arguments.append("-C") arguments.append(input_c_details.connection_string) if self.parameterAsString(parameters, self.BAND_C, context): - arguments.append('--C_band ' + self.parameterAsString(parameters, self.BAND_C, context)) + arguments.append( + "--C_band " + + self.parameterAsString(parameters, self.BAND_C, context) + ) if self.INPUT_D in parameters and parameters[self.INPUT_D] is not None: layer_d = self.parameterAsRasterLayer(parameters, self.INPUT_D, context) if layer_d is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_D)) - input_d_details = GdalUtils.gdal_connection_details_from_layer( - layer_d) - arguments.append('-D') + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT_D) + ) + input_d_details = GdalUtils.gdal_connection_details_from_layer(layer_d) + arguments.append("-D") arguments.append(input_d_details.connection_string) if self.parameterAsString(parameters, self.BAND_D, context): - arguments.append('--D_band ' + self.parameterAsString(parameters, self.BAND_D, context)) + arguments.append( + "--D_band " + + self.parameterAsString(parameters, self.BAND_D, context) + ) if self.INPUT_E in parameters and parameters[self.INPUT_E] is not None: layer_e = self.parameterAsRasterLayer(parameters, self.INPUT_E, context) if layer_e is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_E)) - input_e_details = GdalUtils.gdal_connection_details_from_layer( - layer_e) - arguments.append('-E') + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT_E) + ) + input_e_details = GdalUtils.gdal_connection_details_from_layer(layer_e) + arguments.append("-E") arguments.append(input_e_details.connection_string) if self.parameterAsString(parameters, self.BAND_E, context): - arguments.append('--E_band ' + self.parameterAsString(parameters, self.BAND_E, context)) + arguments.append( + "--E_band " + + self.parameterAsString(parameters, self.BAND_E, context) + ) if self.INPUT_F in parameters and parameters[self.INPUT_F] is not None: layer_f = self.parameterAsRasterLayer(parameters, self.INPUT_F, context) if layer_f is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_F)) - input_f_details = GdalUtils.gdal_connection_details_from_layer( - layer_f) - arguments.append('-F') + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT_F) + ) + input_f_details = GdalUtils.gdal_connection_details_from_layer(layer_f) + arguments.append("-F") arguments.append(input_f_details.connection_string) if self.parameterAsString(parameters, self.BAND_F, context): - arguments.append('--F_band ' + self.parameterAsString(parameters, self.BAND_F, context)) + arguments.append( + "--F_band " + + self.parameterAsString(parameters, self.BAND_F, context) + ) options = self.parameterAsString(parameters, self.OPTIONS, context) if options: - parts = options.split('|') + parts = options.split("|") for p in parts: - arguments.append('--co ' + p) + arguments.append("--co " + p) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) - arguments.append('--outfile') + arguments.append("--outfile") arguments.append(out) - return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)] + return [ + self.commandName() + (".bat" if isWindows() else ".py"), + GdalUtils.escapeAndJoin(arguments), + ] diff --git a/python/plugins/processing/algs/gdal/gdalinfo.py b/python/plugins/processing/algs/gdal/gdalinfo.py index a3cd207bcf2c..3a99f6d67f3e 100644 --- a/python/plugins/processing/algs/gdal/gdalinfo.py +++ b/python/plugins/processing/algs/gdal/gdalinfo.py @@ -15,19 +15,21 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterString, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterBoolean, - QgsProcessingParameterFileDestination) +from qgis.core import ( + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterString, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBoolean, + QgsProcessingParameterFileDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -35,80 +37,105 @@ class gdalinfo(GdalAlgorithm): - INPUT = 'INPUT' - MIN_MAX = 'MIN_MAX' - STATS = 'STATS' - NO_GCP = 'NOGCP' - NO_METADATA = 'NO_METADATA' - EXTRA = 'EXTRA' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + MIN_MAX = "MIN_MAX" + STATS = "STATS" + NO_GCP = "NOGCP" + NO_METADATA = "NO_METADATA" + EXTRA = "EXTRA" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterBoolean(self.MIN_MAX, - self.tr('Force computation of the actual min/max values for each band'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.STATS, - self.tr('Read and display image statistics (force computation if necessary)'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.NO_GCP, - self.tr('Suppress GCP info'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.NO_METADATA, - self.tr('Suppress metadata info'), - defaultValue=False)) - - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.MIN_MAX, + self.tr("Force computation of the actual min/max values for each band"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.STATS, + self.tr( + "Read and display image statistics (force computation if necessary)" + ), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.NO_GCP, self.tr("Suppress GCP info"), defaultValue=False + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.NO_METADATA, self.tr("Suppress metadata info"), defaultValue=False + ) + ) + + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, - self.tr('Layer information'), - self.tr('HTML files (*.html)'))) + self.addParameter( + QgsProcessingParameterFileDestination( + self.OUTPUT, + self.tr("Layer information"), + self.tr("HTML files (*.html)"), + ) + ) def name(self): - return 'gdalinfo' + return "gdalinfo" def displayName(self): - return self.tr('Raster information') + return self.tr("Raster information") def group(self): - return self.tr('Raster miscellaneous') + return self.tr("Raster miscellaneous") def groupId(self): - return 'rastermiscellaneous' + return "rastermiscellaneous" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'raster-info.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "raster-info.png")) def commandName(self): - return 'gdalinfo' + return "gdalinfo" def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments = [] if self.parameterAsBoolean(parameters, self.MIN_MAX, context): - arguments.append('-mm') + arguments.append("-mm") if self.parameterAsBoolean(parameters, self.STATS, context): - arguments.append('-stats') + arguments.append("-stats") if self.parameterAsBoolean(parameters, self.NO_GCP, context): - arguments.append('-nogcp') + arguments.append("-nogcp") if self.parameterAsBoolean(parameters, self.NO_METADATA, context): - arguments.append('-nomd') + arguments.append("-nomd") - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) raster = self.parameterAsRasterLayer(parameters, self.INPUT, context) if raster is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) input_details = GdalUtils.gdal_connection_details_from_layer(raster) arguments.append(input_details.connection_string) @@ -121,12 +148,14 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): return [self.commandName(), GdalUtils.escapeAndJoin(arguments)] def processAlgorithm(self, parameters, context, feedback): - console_output = GdalUtils.runGdal(self.getConsoleCommands(parameters, context, feedback), feedback) + console_output = GdalUtils.runGdal( + self.getConsoleCommands(parameters, context, feedback), feedback + ) output = self.parameterAsFileOutput(parameters, self.OUTPUT, context) - with open(output, 'w') as f: - f.write('
')
+        with open(output, "w") as f:
+            f.write("
")
             for s in console_output[1:]:
                 f.write(str(s))
-            f.write('
') + f.write("
") return {self.OUTPUT: output} diff --git a/python/plugins/processing/algs/gdal/gdaltindex.py b/python/plugins/processing/algs/gdal/gdaltindex.py index 4d6aa530f915..5fd3ff34143a 100644 --- a/python/plugins/processing/algs/gdal/gdaltindex.py +++ b/python/plugins/processing/algs/gdal/gdaltindex.py @@ -15,25 +15,27 @@ *************************************************************************** """ -__author__ = 'Pedro Venancio' -__date__ = 'February 2015' -__copyright__ = '(C) 2015, Pedro Venancio' +__author__ = "Pedro Venancio" +__date__ = "February 2015" +__copyright__ = "(C) 2015, Pedro Venancio" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsMapLayer, - QgsProcessing, - QgsProcessingAlgorithm, - QgsProcessingException, - QgsProcessingParameterCrs, - QgsProcessingParameterEnum, - QgsProcessingParameterString, - QgsProcessingParameterBoolean, - QgsProcessingParameterDefinition, - QgsProcessingParameterMultipleLayers, - QgsProcessingParameterVectorDestination) +from qgis.core import ( + QgsMapLayer, + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingException, + QgsProcessingParameterCrs, + QgsProcessingParameterEnum, + QgsProcessingParameterString, + QgsProcessingParameterBoolean, + QgsProcessingParameterDefinition, + QgsProcessingParameterMultipleLayers, + QgsProcessingParameterVectorDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -41,78 +43,112 @@ class gdaltindex(GdalAlgorithm): - LAYERS = 'LAYERS' - PATH_FIELD_NAME = 'PATH_FIELD_NAME' - ABSOLUTE_PATH = 'ABSOLUTE_PATH' - PROJ_DIFFERENCE = 'PROJ_DIFFERENCE' - TARGET_CRS = 'TARGET_CRS' - CRS_FIELD_NAME = 'CRS_FIELD_NAME' - CRS_FORMAT = 'CRS_FORMAT' - OUTPUT = 'OUTPUT' + LAYERS = "LAYERS" + PATH_FIELD_NAME = "PATH_FIELD_NAME" + ABSOLUTE_PATH = "ABSOLUTE_PATH" + PROJ_DIFFERENCE = "PROJ_DIFFERENCE" + TARGET_CRS = "TARGET_CRS" + CRS_FIELD_NAME = "CRS_FIELD_NAME" + CRS_FORMAT = "CRS_FORMAT" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.formats = ((self.tr('Auto'), 'AUTO'), - (self.tr('Well-known text (WKT)'), 'WKT'), - (self.tr('EPSG'), 'EPSG'), - (self.tr('Proj.4'), 'PROJ')) - - self.addParameter(QgsProcessingParameterMultipleLayers(self.LAYERS, - self.tr('Input files'), - QgsProcessing.SourceType.TypeRaster)) - self.addParameter(QgsProcessingParameterString(self.PATH_FIELD_NAME, - self.tr('Field name to hold the file path to the indexed rasters'), - defaultValue='location')) - self.addParameter(QgsProcessingParameterBoolean(self.ABSOLUTE_PATH, - self.tr('Store absolute path to the indexed rasters'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.PROJ_DIFFERENCE, - self.tr('Skip files with different projection reference'), - defaultValue=False)) - - target_crs_param = QgsProcessingParameterCrs(self.TARGET_CRS, - self.tr('Transform geometries to the given CRS'), - optional=True) - target_crs_param.setFlags(target_crs_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.formats = ( + (self.tr("Auto"), "AUTO"), + (self.tr("Well-known text (WKT)"), "WKT"), + (self.tr("EPSG"), "EPSG"), + (self.tr("Proj.4"), "PROJ"), + ) + + self.addParameter( + QgsProcessingParameterMultipleLayers( + self.LAYERS, self.tr("Input files"), QgsProcessing.SourceType.TypeRaster + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.PATH_FIELD_NAME, + self.tr("Field name to hold the file path to the indexed rasters"), + defaultValue="location", + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.ABSOLUTE_PATH, + self.tr("Store absolute path to the indexed rasters"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.PROJ_DIFFERENCE, + self.tr("Skip files with different projection reference"), + defaultValue=False, + ) + ) + + target_crs_param = QgsProcessingParameterCrs( + self.TARGET_CRS, + self.tr("Transform geometries to the given CRS"), + optional=True, + ) + target_crs_param.setFlags( + target_crs_param.flags() + | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(target_crs_param) - crs_field_param = QgsProcessingParameterString(self.CRS_FIELD_NAME, - self.tr('The name of the field to store the SRS of each tile'), - optional=True) - crs_field_param.setFlags(crs_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + crs_field_param = QgsProcessingParameterString( + self.CRS_FIELD_NAME, + self.tr("The name of the field to store the SRS of each tile"), + optional=True, + ) + crs_field_param.setFlags( + crs_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(crs_field_param) - crs_format_param = QgsProcessingParameterEnum(self.CRS_FORMAT, - self.tr('The format in which the CRS of each tile must be written'), - options=[i[0] for i in self.formats], - allowMultiple=False, - defaultValue=0) - crs_format_param.setFlags(crs_format_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + crs_format_param = QgsProcessingParameterEnum( + self.CRS_FORMAT, + self.tr("The format in which the CRS of each tile must be written"), + options=[i[0] for i in self.formats], + allowMultiple=False, + defaultValue=0, + ) + crs_format_param.setFlags( + crs_format_param.flags() + | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(crs_format_param) - self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT, - self.tr('Tile index'), - QgsProcessing.SourceType.TypeVectorPolygon)) + self.addParameter( + QgsProcessingParameterVectorDestination( + self.OUTPUT, + self.tr("Tile index"), + QgsProcessing.SourceType.TypeVectorPolygon, + ) + ) def name(self): - return 'tileindex' + return "tileindex" def displayName(self): - return self.tr('Tile index') + return self.tr("Tile index") def group(self): - return self.tr('Raster miscellaneous') + return self.tr("Raster miscellaneous") def groupId(self): - return 'rastermiscellaneous' + return "rastermiscellaneous" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'tiles.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "tiles.png")) def commandName(self): - return 'gdaltindex' + return "gdaltindex" def getConsoleCommands(self, parameters, context, feedback, executing=True): crs_field = self.parameterAsString(parameters, self.CRS_FIELD_NAME, context) @@ -124,35 +160,43 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context) arguments = [ - '-tileindex', + "-tileindex", self.parameterAsString(parameters, self.PATH_FIELD_NAME, context), ] if self.parameterAsBoolean(parameters, self.ABSOLUTE_PATH, context): - arguments.append('-write_absolute_path') + arguments.append("-write_absolute_path") if self.parameterAsBoolean(parameters, self.PROJ_DIFFERENCE, context): - arguments.append('-skip_different_projection') + arguments.append("-skip_different_projection") if crs_field: - arguments.append(f'-src_srs_name {crs_field}') + arguments.append(f"-src_srs_name {crs_field}") if crs_format: - arguments.append(f'-src_srs_format {self.formats[crs_format][1]}') + arguments.append(f"-src_srs_format {self.formats[crs_format][1]}") if target_crs.isValid(): - arguments.append('-t_srs') + arguments.append("-t_srs") arguments.append(GdalUtils.gdal_crs_string(target_crs)) if output_details.format: - arguments.append(f'-f {output_details.format}') + arguments.append(f"-f {output_details.format}") arguments.append(output_details.connection_string) # Always write input files to a text file in case there are many of them and the # length of the command will be longer then allowed in command prompt - list_file = GdalUtils.writeLayerParameterToTextFile(filename='tile_index_files.txt', alg=self, parameters=parameters, parameter_name=self.LAYERS, context=context, quote=True, executing=executing) - arguments.append('--optfile') + list_file = GdalUtils.writeLayerParameterToTextFile( + filename="tile_index_files.txt", + alg=self, + parameters=parameters, + parameter_name=self.LAYERS, + context=context, + quote=True, + executing=executing, + ) + arguments.append("--optfile") arguments.append(list_file) return [self.commandName(), GdalUtils.escapeAndJoin(arguments)] diff --git a/python/plugins/processing/algs/gdal/hillshade.py b/python/plugins/processing/algs/gdal/hillshade.py index 40897d4ca71c..4ab62a0c87a2 100644 --- a/python/plugins/processing/algs/gdal/hillshade.py +++ b/python/plugins/processing/algs/gdal/hillshade.py @@ -15,21 +15,23 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'October 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "October 2013" +__copyright__ = "(C) 2013, Alexander Bruy" import os -from qgis.core import (QgsRasterFileWriter, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterBand, - QgsProcessingParameterBoolean, - QgsProcessingParameterNumber, - QgsProcessingParameterString, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBand, + QgsProcessingParameterBoolean, + QgsProcessingParameterNumber, + QgsProcessingParameterString, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -37,100 +39,146 @@ class hillshade(GdalAlgorithm): - INPUT = 'INPUT' - BAND = 'BAND' - COMPUTE_EDGES = 'COMPUTE_EDGES' - ZEVENBERGEN = 'ZEVENBERGEN' - Z_FACTOR = 'Z_FACTOR' - SCALE = 'SCALE' - AZIMUTH = 'AZIMUTH' - ALTITUDE = 'ALTITUDE' - COMBINED = 'COMBINED' - MULTIDIRECTIONAL = 'MULTIDIRECTIONAL' - OPTIONS = 'OPTIONS' - EXTRA = 'EXTRA' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + BAND = "BAND" + COMPUTE_EDGES = "COMPUTE_EDGES" + ZEVENBERGEN = "ZEVENBERGEN" + Z_FACTOR = "Z_FACTOR" + SCALE = "SCALE" + AZIMUTH = "AZIMUTH" + ALTITUDE = "ALTITUDE" + COMBINED = "COMBINED" + MULTIDIRECTIONAL = "MULTIDIRECTIONAL" + OPTIONS = "OPTIONS" + EXTRA = "EXTRA" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterBand(self.BAND, - self.tr('Band number'), - 1, - parentLayerParameterName=self.INPUT)) - self.addParameter(QgsProcessingParameterNumber(self.Z_FACTOR, - self.tr('Z factor (vertical exaggeration)'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=1.0)) - self.addParameter(QgsProcessingParameterNumber(self.SCALE, - self.tr('Scale (ratio of vertical units to horizontal)'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=1.0)) - self.addParameter(QgsProcessingParameterNumber(self.AZIMUTH, - self.tr('Azimuth of the light'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - maxValue=360, - defaultValue=315.0)) - self.addParameter(QgsProcessingParameterNumber(self.ALTITUDE, - self.tr('Altitude of the light'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=45.0)) - self.addParameter(QgsProcessingParameterBoolean(self.COMPUTE_EDGES, - self.tr('Compute edges'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.ZEVENBERGEN, - self.tr("Use Zevenbergen&Thorne formula instead of the Horn's one"), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.COMBINED, - self.tr("Combined shading"), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.MULTIDIRECTIONAL, - self.tr("Multidirectional shading"), - defaultValue=False)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterBand( + self.BAND, + self.tr("Band number"), + 1, + parentLayerParameterName=self.INPUT, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.Z_FACTOR, + self.tr("Z factor (vertical exaggeration)"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=1.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.SCALE, + self.tr("Scale (ratio of vertical units to horizontal)"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=1.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.AZIMUTH, + self.tr("Azimuth of the light"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + maxValue=360, + defaultValue=315.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.ALTITUDE, + self.tr("Altitude of the light"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=45.0, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.COMPUTE_EDGES, self.tr("Compute edges"), defaultValue=False + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.ZEVENBERGEN, + self.tr("Use Zevenbergen&Thorne formula instead of the Horn's one"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.COMBINED, self.tr("Combined shading"), defaultValue=False + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.MULTIDIRECTIONAL, + self.tr("Multidirectional shading"), + defaultValue=False, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Hillshade'))) + self.addParameter( + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Hillshade")) + ) def name(self): - return 'hillshade' + return "hillshade" def displayName(self): - return self.tr('Hillshade') + return self.tr("Hillshade") def group(self): - return self.tr('Raster analysis') + return self.tr("Raster analysis") def groupId(self): - return 'rasteranalysis' + return "rasteranalysis" def commandName(self): - return 'gdaldem' + return "gdaldem" def getConsoleCommands(self, parameters, context, feedback, executing=True): - arguments = ['hillshade'] + arguments = ["hillshade"] inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) arguments.append(input_details.connection_string) @@ -141,52 +189,61 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) - arguments.append('-of') + arguments.append("-of") arguments.append(output_format) - arguments.append('-b') + arguments.append("-b") arguments.append(str(self.parameterAsInt(parameters, self.BAND, context))) - arguments.append('-z') - arguments.append(str(self.parameterAsDouble(parameters, self.Z_FACTOR, context))) - arguments.append('-s') + arguments.append("-z") + arguments.append( + str(self.parameterAsDouble(parameters, self.Z_FACTOR, context)) + ) + arguments.append("-s") arguments.append(str(self.parameterAsDouble(parameters, self.SCALE, context))) - multidirectional = self.parameterAsBoolean(parameters, self.MULTIDIRECTIONAL, context) + multidirectional = self.parameterAsBoolean( + parameters, self.MULTIDIRECTIONAL, context + ) # azimuth and multidirectional are mutually exclusive if not multidirectional: - arguments.append('-az') - arguments.append(str(self.parameterAsDouble(parameters, self.AZIMUTH, context))) + arguments.append("-az") + arguments.append( + str(self.parameterAsDouble(parameters, self.AZIMUTH, context)) + ) - arguments.append('-alt') - arguments.append(str(self.parameterAsDouble(parameters, self.ALTITUDE, context))) + arguments.append("-alt") + arguments.append( + str(self.parameterAsDouble(parameters, self.ALTITUDE, context)) + ) if self.parameterAsBoolean(parameters, self.COMPUTE_EDGES, context): - arguments.append('-compute_edges') + arguments.append("-compute_edges") if self.parameterAsBoolean(parameters, self.ZEVENBERGEN, context): - arguments.append('-alg') - arguments.append('ZevenbergenThorne') + arguments.append("-alg") + arguments.append("ZevenbergenThorne") combined = self.parameterAsBoolean(parameters, self.COMBINED, context) if combined and not multidirectional: - arguments.append('-combined') + arguments.append("-combined") elif multidirectional and not combined: - arguments.append('-multidirectional') + arguments.append("-multidirectional") elif multidirectional and combined: - raise QgsProcessingException(self.tr('Options -multirectional and -combined are mutually exclusive.')) + raise QgsProcessingException( + self.tr("Options -multirectional and -combined are mutually exclusive.") + ) options = self.parameterAsString(parameters, self.OPTIONS, context) if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) if input_details.credential_options: - arguments.extend( - input_details.credential_options_as_arguments()) + arguments.extend(input_details.credential_options_as_arguments()) return [self.commandName(), GdalUtils.escapeAndJoin(arguments)] diff --git a/python/plugins/processing/algs/gdal/merge.py b/python/plugins/processing/algs/gdal/merge.py index b807c4c2ad5b..323c4fb26095 100644 --- a/python/plugins/processing/algs/gdal/merge.py +++ b/python/plugins/processing/algs/gdal/merge.py @@ -15,24 +15,26 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsRasterFileWriter, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterMultipleLayers, - QgsProcessingParameterEnum, - QgsProcessingParameterString, - QgsProcessingParameterBoolean, - QgsProcessingParameterNumber, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterMultipleLayers, + QgsProcessingParameterEnum, + QgsProcessingParameterString, + QgsProcessingParameterBoolean, + QgsProcessingParameterNumber, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -42,89 +44,134 @@ class merge(GdalAlgorithm): - INPUT = 'INPUT' - PCT = 'PCT' - SEPARATE = 'SEPARATE' - OPTIONS = 'OPTIONS' - EXTRA = 'EXTRA' - DATA_TYPE = 'DATA_TYPE' - NODATA_INPUT = 'NODATA_INPUT' - NODATA_OUTPUT = 'NODATA_OUTPUT' - OUTPUT = 'OUTPUT' - - TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8'] + INPUT = "INPUT" + PCT = "PCT" + SEPARATE = "SEPARATE" + OPTIONS = "OPTIONS" + EXTRA = "EXTRA" + DATA_TYPE = "DATA_TYPE" + NODATA_INPUT = "NODATA_INPUT" + NODATA_OUTPUT = "NODATA_OUTPUT" + OUTPUT = "OUTPUT" + + TYPES = [ + "Byte", + "Int16", + "UInt16", + "UInt32", + "Int32", + "Float32", + "Float64", + "CInt16", + "CInt32", + "CFloat32", + "CFloat64", + "Int8", + ] def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterMultipleLayers(self.INPUT, - self.tr('Input layers'), - QgsProcessing.SourceType.TypeRaster)) - self.addParameter(QgsProcessingParameterBoolean(self.PCT, - self.tr('Grab pseudocolor table from first layer'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.SEPARATE, - self.tr('Place each input file into a separate band'), - defaultValue=False)) - - nodata_param = QgsProcessingParameterNumber(self.NODATA_INPUT, - self.tr('Input pixel value to treat as NoData'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=None, - optional=True) - nodata_param.setFlags(nodata_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.addParameter( + QgsProcessingParameterMultipleLayers( + self.INPUT, self.tr("Input layers"), QgsProcessing.SourceType.TypeRaster + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.PCT, + self.tr("Grab pseudocolor table from first layer"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.SEPARATE, + self.tr("Place each input file into a separate band"), + defaultValue=False, + ) + ) + + nodata_param = QgsProcessingParameterNumber( + self.NODATA_INPUT, + self.tr("Input pixel value to treat as NoData"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=None, + optional=True, + ) + nodata_param.setFlags( + nodata_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(nodata_param) - nodata_out_param = QgsProcessingParameterNumber(self.NODATA_OUTPUT, - self.tr('Assign specified NoData value to output'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=None, - optional=True) - nodata_out_param.setFlags(nodata_out_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + nodata_out_param = QgsProcessingParameterNumber( + self.NODATA_OUTPUT, + self.tr("Assign specified NoData value to output"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=None, + optional=True, + ) + nodata_out_param.setFlags( + nodata_out_param.flags() + | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(nodata_out_param) - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - self.addParameter(QgsProcessingParameterEnum(self.DATA_TYPE, - self.tr('Output data type'), - self.TYPES, - allowMultiple=False, - defaultValue=5)) + self.addParameter( + QgsProcessingParameterEnum( + self.DATA_TYPE, + self.tr("Output data type"), + self.TYPES, + allowMultiple=False, + defaultValue=5, + ) + ) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, - self.tr('Merged'))) + self.addParameter( + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Merged")) + ) def name(self): - return 'merge' + return "merge" def displayName(self): - return self.tr('Merge') + return self.tr("Merge") def group(self): - return self.tr('Raster miscellaneous') + return self.tr("Raster miscellaneous") def groupId(self): - return 'rastermiscellaneous' + return "rastermiscellaneous" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'merge.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "merge.png")) def commandName(self): - return 'gdal_merge' + return "gdal_merge" def getConsoleCommands(self, parameters, context, feedback, executing=True): out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) @@ -132,49 +179,72 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments = [] if self.parameterAsBoolean(parameters, self.PCT, context): - arguments.append('-pct') + arguments.append("-pct") if self.parameterAsBoolean(parameters, self.SEPARATE, context): - arguments.append('-separate') - - if self.NODATA_INPUT in parameters and parameters[self.NODATA_INPUT] is not None: - nodata_input = self.parameterAsDouble(parameters, self.NODATA_INPUT, context) - arguments.append('-n') + arguments.append("-separate") + + if ( + self.NODATA_INPUT in parameters + and parameters[self.NODATA_INPUT] is not None + ): + nodata_input = self.parameterAsDouble( + parameters, self.NODATA_INPUT, context + ) + arguments.append("-n") arguments.append(str(nodata_input)) - if self.NODATA_OUTPUT in parameters and parameters[self.NODATA_OUTPUT] is not None: - nodata_output = self.parameterAsDouble(parameters, self.NODATA_OUTPUT, context) - arguments.append('-a_nodata') + if ( + self.NODATA_OUTPUT in parameters + and parameters[self.NODATA_OUTPUT] is not None + ): + nodata_output = self.parameterAsDouble( + parameters, self.NODATA_OUTPUT, context + ) + arguments.append("-a_nodata") arguments.append(str(nodata_output)) data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context) - if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later')) + if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000: + raise QgsProcessingException( + self.tr("Int8 data type requires GDAL version 3.7 or later") + ) - arguments.append('-ot ' + self.TYPES[data_type]) + arguments.append("-ot " + self.TYPES[data_type]) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) - arguments.append('-of') + arguments.append("-of") arguments.append(output_format) options = self.parameterAsString(parameters, self.OPTIONS, context) if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) - arguments.append('-o') + arguments.append("-o") arguments.append(out) # Always write input files to a text file in case there are many of them and the # length of the command will be longer then allowed in command prompt - list_file = GdalUtils.writeLayerParameterToTextFile(filename='mergeInputFiles.txt', alg=self, parameters=parameters, parameter_name=self.INPUT, context=context, quote=True, executing=executing) - arguments.append('--optfile') + list_file = GdalUtils.writeLayerParameterToTextFile( + filename="mergeInputFiles.txt", + alg=self, + parameters=parameters, + parameter_name=self.INPUT, + context=context, + quote=True, + executing=executing, + ) + arguments.append("--optfile") arguments.append(list_file) - return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)] + return [ + self.commandName() + (".bat" if isWindows() else ".py"), + GdalUtils.escapeAndJoin(arguments), + ] diff --git a/python/plugins/processing/algs/gdal/nearblack.py b/python/plugins/processing/algs/gdal/nearblack.py index 3156f5b24dcd..db3ba5cdc18a 100644 --- a/python/plugins/processing/algs/gdal/nearblack.py +++ b/python/plugins/processing/algs/gdal/nearblack.py @@ -15,22 +15,24 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsRasterFileWriter, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterBoolean, - QgsProcessingParameterNumber, - QgsProcessingParameterString, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBoolean, + QgsProcessingParameterNumber, + QgsProcessingParameterString, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -39,66 +41,88 @@ class nearblack(GdalAlgorithm): - INPUT = 'INPUT' - NEAR = 'NEAR' - WHITE = 'WHITE' - OPTIONS = 'OPTIONS' - EXTRA = 'EXTRA' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + NEAR = "NEAR" + WHITE = "WHITE" + OPTIONS = "OPTIONS" + EXTRA = "EXTRA" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterNumber(self.NEAR, - self.tr('How far from black (white)'), - type=QgsProcessingParameterNumber.Type.Integer, - minValue=0, - defaultValue=15)) - self.addParameter(QgsProcessingParameterBoolean(self.WHITE, - self.tr('Search for nearly white pixels instead of nearly black'), - defaultValue=False)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.NEAR, + self.tr("How far from black (white)"), + type=QgsProcessingParameterNumber.Type.Integer, + minValue=0, + defaultValue=15, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.WHITE, + self.tr("Search for nearly white pixels instead of nearly black"), + defaultValue=False, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Nearblack'))) + self.addParameter( + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Nearblack")) + ) def name(self): - return 'nearblack' + return "nearblack" def displayName(self): - return self.tr('Near black') + return self.tr("Near black") def group(self): - return self.tr('Raster analysis') + return self.tr("Raster analysis") def groupId(self): - return 'rasteranalysis' + return "rasteranalysis" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'nearblack.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "nearblack.png")) def commandName(self): - return 'nearblack' + return "nearblack" def getConsoleCommands(self, parameters, context, feedback, executing=True): inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) @@ -106,20 +130,20 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) arguments = [ input_details.connection_string, - '-of', + "-of", output_format, - '-o', + "-o", out, - '-near', - str(self.parameterAsInt(parameters, self.NEAR, context)) + "-near", + str(self.parameterAsInt(parameters, self.NEAR, context)), ] if self.parameterAsBoolean(parameters, self.WHITE, context): - arguments.append('-white') + arguments.append("-white") if input_details.credential_options: arguments.extend(input_details.credential_options_as_arguments()) @@ -128,7 +152,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) diff --git a/python/plugins/processing/algs/gdal/ogr2ogr.py b/python/plugins/processing/algs/gdal/ogr2ogr.py index f030ca6bd6a0..3040b8242eac 100644 --- a/python/plugins/processing/algs/gdal/ogr2ogr.py +++ b/python/plugins/processing/algs/gdal/ogr2ogr.py @@ -15,83 +15,111 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'November 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "November 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os -from qgis.core import (QgsProcessing, - QgsProcessingException, - QgsProcessingParameterBoolean, - QgsProcessingParameterDefinition, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterString, - QgsProcessingParameterVectorDestination) +from qgis.core import ( + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterBoolean, + QgsProcessingParameterDefinition, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterString, + QgsProcessingParameterVectorDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils class ogr2ogr(GdalAlgorithm): - INPUT = 'INPUT' - CONVERT_ALL_LAYERS = 'CONVERT_ALL_LAYERS' - OPTIONS = 'OPTIONS' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + CONVERT_ALL_LAYERS = "CONVERT_ALL_LAYERS" + OPTIONS = "OPTIONS" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), - types=[QgsProcessing.SourceType.TypeVector])) - - convert_all_layers_param = QgsProcessingParameterBoolean(self.CONVERT_ALL_LAYERS, - self.tr('Convert all layers from dataset'), defaultValue=False) - convert_all_layers_param.setHelp(self.tr("Use convert all layers to convert a whole dataset. " - "Supported output formats for this option are GPKG and GML.")) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Input layer"), + types=[QgsProcessing.SourceType.TypeVector], + ) + ) + + convert_all_layers_param = QgsProcessingParameterBoolean( + self.CONVERT_ALL_LAYERS, + self.tr("Convert all layers from dataset"), + defaultValue=False, + ) + convert_all_layers_param.setHelp( + self.tr( + "Use convert all layers to convert a whole dataset. " + "Supported output formats for this option are GPKG and GML." + ) + ) self.addParameter(convert_all_layers_param) - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(options_param) - self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT, - self.tr('Converted'))) + self.addParameter( + QgsProcessingParameterVectorDestination(self.OUTPUT, self.tr("Converted")) + ) def name(self): - return 'convertformat' + return "convertformat" def displayName(self): - return self.tr('Convert format') + return self.tr("Convert format") def group(self): - return self.tr('Vector conversion') + return self.tr("Vector conversion") def groupId(self): - return 'vectorconversion' + return "vectorconversion" def commandName(self): - return 'ogr2ogr' + return "ogr2ogr" def getConsoleCommands(self, parameters, context, feedback, executing=True): - input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing) - convertAllLayers = self.parameterAsBoolean(parameters, self.CONVERT_ALL_LAYERS, context) + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) + convertAllLayers = self.parameterAsBoolean( + parameters, self.CONVERT_ALL_LAYERS, context + ) options = self.parameterAsString(parameters, self.OPTIONS, context) outFile = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, outFile) output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context) - if output_details.format in ('SQLite', 'GPKG') and os.path.isfile(output_details.connection_string): - raise QgsProcessingException(self.tr('Output file "{}" already exists.').format(output_details.connection_string)) + if output_details.format in ("SQLite", "GPKG") and os.path.isfile( + output_details.connection_string + ): + raise QgsProcessingException( + self.tr('Output file "{}" already exists.').format( + output_details.connection_string + ) + ) arguments = [] if output_details.format: - arguments.append(f'-f {output_details.format}') + arguments.append(f"-f {output_details.format}") if input_details.open_options: arguments.extend(input_details.open_options_as_arguments()) @@ -107,12 +135,13 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if not convertAllLayers: arguments.append(input_details.layer_name) - return ['ogr2ogr', GdalUtils.escapeAndJoin(arguments)] + return ["ogr2ogr", GdalUtils.escapeAndJoin(arguments)] def shortHelpString(self): - return self.tr("The algorithm converts simple features data between file formats.\n\n" - "Use convert all layers to convert a whole dataset.\n" - "Supported output formats for this option are:\n" - "- GPKG\n" - "- GML" - ) + return self.tr( + "The algorithm converts simple features data between file formats.\n\n" + "Use convert all layers to convert a whole dataset.\n" + "Supported output formats for this option are:\n" + "- GPKG\n" + "- GML" + ) diff --git a/python/plugins/processing/algs/gdal/ogr2ogrtopostgislist.py b/python/plugins/processing/algs/gdal/ogr2ogrtopostgislist.py index c6645a8bcf8c..364d684067a6 100644 --- a/python/plugins/processing/algs/gdal/ogr2ogrtopostgislist.py +++ b/python/plugins/processing/algs/gdal/ogr2ogrtopostgislist.py @@ -15,25 +15,27 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'November 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "November 2012" +__copyright__ = "(C) 2012, Victor Olaya" -from qgis.core import (QgsProcessing, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterString, - QgsProcessingParameterEnum, - QgsProcessingParameterCrs, - QgsProcessingParameterField, - QgsProcessingParameterExtent, - QgsProcessingParameterBoolean, - QgsProcessingParameterProviderConnection, - QgsProcessingParameterDatabaseSchema, - QgsProcessingParameterDatabaseTable, - QgsProviderRegistry, - QgsProcessingException, - QgsProviderConnectionException, - QgsDataSourceUri) +from qgis.core import ( + QgsProcessing, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterString, + QgsProcessingParameterEnum, + QgsProcessingParameterCrs, + QgsProcessingParameterField, + QgsProcessingParameterExtent, + QgsProcessingParameterBoolean, + QgsProcessingParameterProviderConnection, + QgsProcessingParameterDatabaseSchema, + QgsProcessingParameterDatabaseTable, + QgsProviderRegistry, + QgsProcessingException, + QgsProviderConnectionException, + QgsDataSourceUri, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -42,44 +44,60 @@ class Ogr2OgrToPostGisList(GdalAlgorithm): - DATABASE = 'DATABASE' - INPUT = 'INPUT' - SHAPE_ENCODING = 'SHAPE_ENCODING' - GTYPE = 'GTYPE' - GEOMTYPE = ['', 'NONE', 'GEOMETRY', 'POINT', 'LINESTRING', 'POLYGON', 'GEOMETRYCOLLECTION', 'MULTIPOINT', - 'MULTIPOLYGON', 'MULTILINESTRING', 'CIRCULARSTRING', 'COMPOUNDCURVE', 'CURVEPOLYGON', 'MULTICURVE', - 'MULTISURFACE', 'CONVERT_TO_LINEAR', 'CONVERT_TO_CURVE'] - S_SRS = 'S_SRS' - T_SRS = 'T_SRS' - A_SRS = 'A_SRS' - HOST = 'HOST' - PORT = 'PORT' - USER = 'USER' - DBNAME = 'DBNAME' - PASSWORD = 'PASSWORD' - SCHEMA = 'SCHEMA' - TABLE = 'TABLE' - PK = 'PK' - PRIMARY_KEY = 'PRIMARY_KEY' - GEOCOLUMN = 'GEOCOLUMN' - DIM = 'DIM' - DIMLIST = ['2', '3', '4'] - SIMPLIFY = 'SIMPLIFY' - SEGMENTIZE = 'SEGMENTIZE' - SPAT = 'SPAT' - CLIP = 'CLIP' - WHERE = 'WHERE' - GT = 'GT' - OVERWRITE = 'OVERWRITE' - APPEND = 'APPEND' - ADDFIELDS = 'ADDFIELDS' - LAUNDER = 'LAUNDER' - INDEX = 'INDEX' - SKIPFAILURES = 'SKIPFAILURES' - PRECISION = 'PRECISION' - MAKEVALID = 'MAKEVALID' - PROMOTETOMULTI = 'PROMOTETOMULTI' - OPTIONS = 'OPTIONS' + DATABASE = "DATABASE" + INPUT = "INPUT" + SHAPE_ENCODING = "SHAPE_ENCODING" + GTYPE = "GTYPE" + GEOMTYPE = [ + "", + "NONE", + "GEOMETRY", + "POINT", + "LINESTRING", + "POLYGON", + "GEOMETRYCOLLECTION", + "MULTIPOINT", + "MULTIPOLYGON", + "MULTILINESTRING", + "CIRCULARSTRING", + "COMPOUNDCURVE", + "CURVEPOLYGON", + "MULTICURVE", + "MULTISURFACE", + "CONVERT_TO_LINEAR", + "CONVERT_TO_CURVE", + ] + S_SRS = "S_SRS" + T_SRS = "T_SRS" + A_SRS = "A_SRS" + HOST = "HOST" + PORT = "PORT" + USER = "USER" + DBNAME = "DBNAME" + PASSWORD = "PASSWORD" + SCHEMA = "SCHEMA" + TABLE = "TABLE" + PK = "PK" + PRIMARY_KEY = "PRIMARY_KEY" + GEOCOLUMN = "GEOCOLUMN" + DIM = "DIM" + DIMLIST = ["2", "3", "4"] + SIMPLIFY = "SIMPLIFY" + SEGMENTIZE = "SEGMENTIZE" + SPAT = "SPAT" + CLIP = "CLIP" + WHERE = "WHERE" + GT = "GT" + OVERWRITE = "OVERWRITE" + APPEND = "APPEND" + ADDFIELDS = "ADDFIELDS" + LAUNDER = "LAUNDER" + INDEX = "INDEX" + SKIPFAILURES = "SKIPFAILURES" + PRECISION = "PRECISION" + MAKEVALID = "MAKEVALID" + PROMOTETOMULTI = "PROMOTETOMULTI" + OPTIONS = "OPTIONS" def __init__(self): super().__init__() @@ -87,139 +105,265 @@ def __init__(self): def initAlgorithm(self, config=None): db_param = QgsProcessingParameterProviderConnection( - self.DATABASE, - self.tr('Database (connection name)'), 'postgres') + self.DATABASE, self.tr("Database (connection name)"), "postgres" + ) self.addParameter(db_param) - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), - types=[QgsProcessing.SourceType.TypeVector])) - self.addParameter(QgsProcessingParameterString(self.SHAPE_ENCODING, - self.tr('Shape encoding'), "", optional=True)) - self.addParameter(QgsProcessingParameterEnum(self.GTYPE, - self.tr('Output geometry type'), options=self.GEOMTYPE, - defaultValue=0)) - self.addParameter(QgsProcessingParameterCrs(self.A_SRS, - self.tr('Assign an output CRS'), defaultValue='', optional=True)) - self.addParameter(QgsProcessingParameterCrs(self.T_SRS, - self.tr('Reproject to this CRS on output '), defaultValue='', - optional=True)) - self.addParameter(QgsProcessingParameterCrs(self.S_SRS, - self.tr('Override source CRS'), defaultValue='', optional=True)) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Input layer"), + types=[QgsProcessing.SourceType.TypeVector], + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.SHAPE_ENCODING, self.tr("Shape encoding"), "", optional=True + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.GTYPE, + self.tr("Output geometry type"), + options=self.GEOMTYPE, + defaultValue=0, + ) + ) + self.addParameter( + QgsProcessingParameterCrs( + self.A_SRS, + self.tr("Assign an output CRS"), + defaultValue="", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterCrs( + self.T_SRS, + self.tr("Reproject to this CRS on output "), + defaultValue="", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterCrs( + self.S_SRS, + self.tr("Override source CRS"), + defaultValue="", + optional=True, + ) + ) schema_param = QgsProcessingParameterDatabaseSchema( self.SCHEMA, - self.tr('Schema (schema name)'), defaultValue='public', connectionParameterName=self.DATABASE, - optional=True) + self.tr("Schema (schema name)"), + defaultValue="public", + connectionParameterName=self.DATABASE, + optional=True, + ) self.addParameter(schema_param) table_param = QgsProcessingParameterDatabaseTable( self.TABLE, - self.tr('Table to import to (leave blank to use layer name)'), defaultValue=None, + self.tr("Table to import to (leave blank to use layer name)"), + defaultValue=None, connectionParameterName=self.DATABASE, - schemaParameterName=self.SCHEMA, optional=True, allowNewTableNames=True) + schemaParameterName=self.SCHEMA, + optional=True, + allowNewTableNames=True, + ) self.addParameter(table_param) - self.addParameter(QgsProcessingParameterString(self.PK, - self.tr('Primary key (new field)'), defaultValue='id', - optional=True)) - self.addParameter(QgsProcessingParameterField(self.PRIMARY_KEY, - self.tr( - 'Primary key (existing field, used if the above option is left empty)'), - parentLayerParameterName=self.INPUT, optional=True)) - self.addParameter(QgsProcessingParameterString(self.GEOCOLUMN, - self.tr('Geometry column name'), defaultValue='geom', - optional=True)) - self.addParameter(QgsProcessingParameterEnum(self.DIM, - self.tr('Vector dimensions'), options=self.DIMLIST, - defaultValue=0)) - self.addParameter(QgsProcessingParameterString(self.SIMPLIFY, - self.tr('Distance tolerance for simplification'), - defaultValue='', optional=True)) - self.addParameter(QgsProcessingParameterString(self.SEGMENTIZE, - self.tr('Maximum distance between 2 nodes (densification)'), - defaultValue='', optional=True)) - self.addParameter(QgsProcessingParameterExtent(self.SPAT, - self.tr( - 'Select features by extent (defined in input layer CRS)'), - optional=True)) - self.addParameter(QgsProcessingParameterBoolean(self.CLIP, - self.tr( - 'Clip the input layer using the above (rectangle) extent'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterString(self.WHERE, - self.tr( - 'Select features using a SQL "WHERE" statement (Ex: column=\'value\')'), - defaultValue='', optional=True)) - self.addParameter(QgsProcessingParameterString(self.GT, - self.tr('Group N features per transaction (Default: 20000)'), - defaultValue='', optional=True)) - self.addParameter(QgsProcessingParameterBoolean(self.OVERWRITE, - self.tr('Overwrite existing table'), defaultValue=True)) - self.addParameter(QgsProcessingParameterBoolean(self.APPEND, - self.tr('Append to existing table'), defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.ADDFIELDS, - self.tr('Append and add new fields to existing table'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.LAUNDER, - self.tr('Do not launder columns/table names'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.INDEX, - self.tr('Do not create spatial index'), defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.SKIPFAILURES, - self.tr( - 'Continue after a failure, skipping the failed feature'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.MAKEVALID, - self.tr( - 'Validate geometries based on Simple Features specification'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.PROMOTETOMULTI, - self.tr('Promote to Multipart'), - defaultValue=True)) - self.addParameter(QgsProcessingParameterBoolean(self.PRECISION, - self.tr('Keep width and precision of input attributes'), - defaultValue=True)) - self.addParameter(QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), defaultValue='', - optional=True)) + self.addParameter( + QgsProcessingParameterString( + self.PK, + self.tr("Primary key (new field)"), + defaultValue="id", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.PRIMARY_KEY, + self.tr( + "Primary key (existing field, used if the above option is left empty)" + ), + parentLayerParameterName=self.INPUT, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.GEOCOLUMN, + self.tr("Geometry column name"), + defaultValue="geom", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.DIM, + self.tr("Vector dimensions"), + options=self.DIMLIST, + defaultValue=0, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.SIMPLIFY, + self.tr("Distance tolerance for simplification"), + defaultValue="", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.SEGMENTIZE, + self.tr("Maximum distance between 2 nodes (densification)"), + defaultValue="", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterExtent( + self.SPAT, + self.tr("Select features by extent (defined in input layer CRS)"), + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.CLIP, + self.tr("Clip the input layer using the above (rectangle) extent"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.WHERE, + self.tr( + "Select features using a SQL \"WHERE\" statement (Ex: column='value')" + ), + defaultValue="", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.GT, + self.tr("Group N features per transaction (Default: 20000)"), + defaultValue="", + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.OVERWRITE, self.tr("Overwrite existing table"), defaultValue=True + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.APPEND, self.tr("Append to existing table"), defaultValue=False + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.ADDFIELDS, + self.tr("Append and add new fields to existing table"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.LAUNDER, + self.tr("Do not launder columns/table names"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.INDEX, self.tr("Do not create spatial index"), defaultValue=False + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.SKIPFAILURES, + self.tr("Continue after a failure, skipping the failed feature"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.MAKEVALID, + self.tr("Validate geometries based on Simple Features specification"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.PROMOTETOMULTI, self.tr("Promote to Multipart"), defaultValue=True + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.PRECISION, + self.tr("Keep width and precision of input attributes"), + defaultValue=True, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + ) def name(self): - return 'importvectorintopostgisdatabaseavailableconnections' + return "importvectorintopostgisdatabaseavailableconnections" def displayName(self): - return self.tr('Export to PostgreSQL (available connections)') + return self.tr("Export to PostgreSQL (available connections)") def shortDescription(self): - return self.tr('Exports a vector layer to an existing PostgreSQL database connection') + return self.tr( + "Exports a vector layer to an existing PostgreSQL database connection" + ) def tags(self): - t = self.tr('import,into,postgis,database,vector').split(',') + t = self.tr("import,into,postgis,database,vector").split(",") t.extend(super().tags()) return t def group(self): - return self.tr('Vector miscellaneous') + return self.tr("Vector miscellaneous") def groupId(self): - return 'vectormiscellaneous' + return "vectormiscellaneous" def getConsoleCommands(self, parameters, context, feedback, executing=True): - connection_name = self.parameterAsConnectionName(parameters, self.DATABASE, context) + connection_name = self.parameterAsConnectionName( + parameters, self.DATABASE, context + ) if not connection_name: - raise QgsProcessingException( - self.tr('No connection specified')) + raise QgsProcessingException(self.tr("No connection specified")) # resolve connection details to uri try: - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(connection_name) except QgsProviderConnectionException: raise QgsProcessingException( - self.tr('Could not retrieve connection details for {}').format(connection_name)) + self.tr("Could not retrieve connection details for {}").format( + connection_name + ) + ) uri = conn.uri() - input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing) + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) shapeEncoding = self.parameterAsString(parameters, self.SHAPE_ENCODING, context) ssrs = self.parameterAsCrs(parameters, self.S_SRS, context) tsrs = self.parameterAsCrs(parameters, self.T_SRS, context) @@ -249,24 +393,23 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): indexstring = "-lco SPATIAL_INDEX=OFF" skipfailures = self.parameterAsBoolean(parameters, self.SKIPFAILURES, context) make_valid = self.parameterAsBoolean(parameters, self.MAKEVALID, context) - promotetomulti = self.parameterAsBoolean(parameters, self.PROMOTETOMULTI, context) + promotetomulti = self.parameterAsBoolean( + parameters, self.PROMOTETOMULTI, context + ) precision = self.parameterAsBoolean(parameters, self.PRECISION, context) options = self.parameterAsString(parameters, self.OPTIONS, context) - arguments = [ - '-progress', - '--config PG_USE_COPY YES' - ] + arguments = ["-progress", "--config PG_USE_COPY YES"] if shapeEncoding: - arguments.append('--config') - arguments.append('SHAPE_ENCODING') + arguments.append("--config") + arguments.append("SHAPE_ENCODING") arguments.append(shapeEncoding) - arguments.append('-f') - arguments.append('PostgreSQL') + arguments.append("-f") + arguments.append("PostgreSQL") - connection_parts = QgsDataSourceUri(uri).connectionInfo(executing).split(' ') - connection_parts.append('active_schema={}'.format(schema or 'public')) - arguments.append('PG:{}'.format(' '.join(connection_parts))) + connection_parts = QgsDataSourceUri(uri).connectionInfo(executing).split(" ") + connection_parts.append("active_schema={}".format(schema or "public")) + arguments.append("PG:{}".format(" ".join(connection_parts))) arguments.append(dimstring) arguments.append(input_details.connection_string) @@ -278,16 +421,23 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if append and overwrite: raise QgsProcessingException( self.tr( - 'Only one of "Overwrite existing table" or "Append to existing table" can be enabled at a time.')) + 'Only one of "Overwrite existing table" or "Append to existing table" can be enabled at a time.' + ) + ) elif append: - arguments.append('-append') + arguments.append("-append") if addfields: - arguments.append('-addfields') + arguments.append("-addfields") if overwrite: - arguments.append('-overwrite') - if len(self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]) > 0: - arguments.append('-nlt') - arguments.append(self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]) + arguments.append("-overwrite") + if ( + len(self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]) + > 0 + ): + arguments.append("-nlt") + arguments.append( + self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)] + ) if len(geocolumn) > 0: arguments.append(geocolumnstring) if pk: @@ -297,53 +447,64 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if len(table) == 0: table = input_details.layer_name.lower() if schema: - table = f'{schema}.{table}' - arguments.append('-nln') + table = f"{schema}.{table}" + arguments.append("-nln") arguments.append(table) if ssrs.isValid(): - arguments.append('-s_srs') + arguments.append("-s_srs") arguments.append(GdalUtils.gdal_crs_string(ssrs)) if tsrs.isValid(): - arguments.append('-t_srs') + arguments.append("-t_srs") arguments.append(GdalUtils.gdal_crs_string(tsrs)) if asrs.isValid(): - arguments.append('-a_srs') + arguments.append("-a_srs") arguments.append(GdalUtils.gdal_crs_string(asrs)) if not spat.isNull(): - arguments.append('-spat') + arguments.append("-spat") arguments.append(spat.xMinimum()) arguments.append(spat.yMinimum()) arguments.append(spat.xMaximum()) arguments.append(spat.yMaximum()) if clip: - arguments.append('-clipsrc spat_extent') + arguments.append("-clipsrc spat_extent") if skipfailures: - arguments.append('-skipfailures') + arguments.append("-skipfailures") if where: arguments.append(wherestring) if len(simplify) > 0: - arguments.append('-simplify') + arguments.append("-simplify") arguments.append(simplify) if len(segmentize) > 0: - arguments.append('-segmentize') + arguments.append("-segmentize") arguments.append(segmentize) if len(gt) > 0: - arguments.append('-gt') + arguments.append("-gt") arguments.append(gt) if make_valid: - arguments.append('-makevalid') - if promotetomulti and self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]: - if self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)] == 'CONVERT_TO_LINEAR': - arguments.append('-nlt PROMOTE_TO_MULTI') + arguments.append("-makevalid") + if ( + promotetomulti + and self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)] + ): + if ( + self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)] + == "CONVERT_TO_LINEAR" + ): + arguments.append("-nlt PROMOTE_TO_MULTI") else: raise QgsProcessingException( self.tr( - 'Only one of "Promote to Multipart" or "Output geometry type" (excluding Convert to Linear) can be enabled.')) + 'Only one of "Promote to Multipart" or "Output geometry type" (excluding Convert to Linear) can be enabled.' + ) + ) - elif promotetomulti and not self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)]: - arguments.append('-nlt PROMOTE_TO_MULTI') + elif ( + promotetomulti + and not self.GEOMTYPE[self.parameterAsEnum(parameters, self.GTYPE, context)] + ): + arguments.append("-nlt PROMOTE_TO_MULTI") if precision is False: - arguments.append('-lco PRECISION=NO') + arguments.append("-lco PRECISION=NO") if input_details.open_options: arguments.extend(input_details.open_options_as_arguments()) @@ -355,10 +516,9 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments.append(options) if isWindows(): - return ['cmd.exe', '/C ', 'ogr2ogr.exe', - GdalUtils.escapeAndJoin(arguments)] + return ["cmd.exe", "/C ", "ogr2ogr.exe", GdalUtils.escapeAndJoin(arguments)] else: - return ['ogr2ogr', GdalUtils.escapeAndJoin(arguments)] + return ["ogr2ogr", GdalUtils.escapeAndJoin(arguments)] def commandName(self): return "ogr2ogr" diff --git a/python/plugins/processing/algs/gdal/ogrinfo.py b/python/plugins/processing/algs/gdal/ogrinfo.py index 9fcb4e650c91..77deb97c863f 100644 --- a/python/plugins/processing/algs/gdal/ogrinfo.py +++ b/python/plugins/processing/algs/gdal/ogrinfo.py @@ -15,106 +15,137 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'November 2012' -__copyright__ = '(C) 2012, Victor Olaya' - -from qgis.core import (QgsProcessingException, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterBoolean, - QgsProcessingParameterDefinition, - QgsProcessingParameterString, - QgsProcessingParameterFileDestination) +__author__ = "Victor Olaya" +__date__ = "November 2012" +__copyright__ = "(C) 2012, Victor Olaya" + +from qgis.core import ( + QgsProcessingException, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterBoolean, + QgsProcessingParameterDefinition, + QgsProcessingParameterString, + QgsProcessingParameterFileDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils class ogrinfo(GdalAlgorithm): - INPUT = 'INPUT' - ALL_LAYERS = 'ALL_LAYERS' - SUMMARY_ONLY = 'SUMMARY_ONLY' - NO_METADATA = 'NO_METADATA' - EXTRA = 'EXTRA' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + ALL_LAYERS = "ALL_LAYERS" + SUMMARY_ONLY = "SUMMARY_ONLY" + NO_METADATA = "NO_METADATA" + EXTRA = "EXTRA" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterBoolean(self.ALL_LAYERS, - self.tr('Enable listing of all layers in the dataset'), - defaultValue=False)) - if self.name() == 'ogrinfo': - self.addParameter(QgsProcessingParameterBoolean(self.SUMMARY_ONLY, - self.tr('Summary output only'), - defaultValue=True)) + self.addParameter( + QgsProcessingParameterVectorLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.ALL_LAYERS, + self.tr("Enable listing of all layers in the dataset"), + defaultValue=False, + ) + ) + if self.name() == "ogrinfo": + self.addParameter( + QgsProcessingParameterBoolean( + self.SUMMARY_ONLY, self.tr("Summary output only"), defaultValue=True + ) + ) else: - self.addParameter(QgsProcessingParameterBoolean(self.FEATURES, - self.tr('Enable listing of features'), - defaultValue=False)) - - self.addParameter(QgsProcessingParameterBoolean(self.NO_METADATA, - self.tr('Suppress metadata info'), - defaultValue=False)) - - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.addParameter( + QgsProcessingParameterBoolean( + self.FEATURES, + self.tr("Enable listing of features"), + defaultValue=False, + ) + ) + + self.addParameter( + QgsProcessingParameterBoolean( + self.NO_METADATA, self.tr("Suppress metadata info"), defaultValue=False + ) + ) + + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - if self.name() == 'ogrinfo': - self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, - self.tr('Layer information'), - self.tr('HTML files (*.html)'))) + if self.name() == "ogrinfo": + self.addParameter( + QgsProcessingParameterFileDestination( + self.OUTPUT, + self.tr("Layer information"), + self.tr("HTML files (*.html)"), + ) + ) else: - self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, - self.tr('Layer information'), - self.tr('JSON files (*.json)'))) + self.addParameter( + QgsProcessingParameterFileDestination( + self.OUTPUT, + self.tr("Layer information"), + self.tr("JSON files (*.json)"), + ) + ) def name(self): - return 'ogrinfo' + return "ogrinfo" def displayName(self): - return self.tr('Vector information') + return self.tr("Vector information") def group(self): - return self.tr('Vector miscellaneous') + return self.tr("Vector miscellaneous") def groupId(self): - return 'vectormiscellaneous' + return "vectormiscellaneous" def commandName(self): - return 'ogrinfo' + return "ogrinfo" def getConsoleCommands(self, parameters, context, feedback, executing=True): - if self.name() == 'ogrinfo': - arguments = ['-al'] + if self.name() == "ogrinfo": + arguments = ["-al"] else: - arguments = ['-json'] + arguments = ["-json"] - if self.name() == 'ogrinfo': + if self.name() == "ogrinfo": if self.parameterAsBoolean(parameters, self.SUMMARY_ONLY, context): - arguments.append('-so') + arguments.append("-so") else: if self.parameterAsBoolean(parameters, self.FEATURES, context): - arguments.append('-features') + arguments.append("-features") if self.parameterAsBoolean(parameters, self.NO_METADATA, context): - arguments.append('-nomd') + arguments.append("-nomd") - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) inLayer = self.parameterAsVectorLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) - input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing) + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) arguments.append(input_details.connection_string) if not self.parameterAsBoolean(parameters, self.ALL_LAYERS, context): arguments.append(input_details.layer_name) @@ -128,30 +159,34 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): return [self.commandName(), GdalUtils.escapeAndJoin(arguments)] def processAlgorithm(self, parameters, context, feedback): - console_output = GdalUtils.runGdal(self.getConsoleCommands(parameters, context, feedback), feedback) + console_output = GdalUtils.runGdal( + self.getConsoleCommands(parameters, context, feedback), feedback + ) output = self.parameterAsFileOutput(parameters, self.OUTPUT, context) - with open(output, 'w') as f: - f.write('
')
+        with open(output, "w") as f:
+            f.write("
")
             for s in console_output[1:]:
                 f.write(str(s))
-            f.write('
') + f.write("
") return {self.OUTPUT: output} class ogrinfojson(ogrinfo): - FEATURES = 'FEATURES' + FEATURES = "FEATURES" def name(self): - return 'ogrinfojson' + return "ogrinfojson" def displayName(self): - return self.tr('Vector information (JSON)') + return self.tr("Vector information (JSON)") def processAlgorithm(self, parameters, context, feedback): - console_output = GdalUtils.runGdal(self.getConsoleCommands(parameters, context, feedback)) + console_output = GdalUtils.runGdal( + self.getConsoleCommands(parameters, context, feedback) + ) output = self.parameterAsFileOutput(parameters, self.OUTPUT, context) - with open(output, 'w', newline='') as f: + with open(output, "w", newline="") as f: for s in console_output[1:]: f.write(str(s)) diff --git a/python/plugins/processing/algs/gdal/pansharp.py b/python/plugins/processing/algs/gdal/pansharp.py index 5b62045737ae..b7e6c1cfe0bf 100644 --- a/python/plugins/processing/algs/gdal/pansharp.py +++ b/python/plugins/processing/algs/gdal/pansharp.py @@ -15,19 +15,21 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'March 2019' -__copyright__ = '(C) 2019, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "March 2019" +__copyright__ = "(C) 2019, Alexander Bruy" import os -from qgis.core import (QgsRasterFileWriter, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterEnum, - QgsProcessingParameterString, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterEnum, + QgsProcessingParameterString, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -37,107 +39,141 @@ class pansharp(GdalAlgorithm): - SPECTRAL = 'SPECTRAL' - PANCHROMATIC = 'PANCHROMATIC' - RESAMPLING = 'RESAMPLING' - OPTIONS = 'OPTIONS' - EXTRA = 'EXTRA' - OUTPUT = 'OUTPUT' + SPECTRAL = "SPECTRAL" + PANCHROMATIC = "PANCHROMATIC" + RESAMPLING = "RESAMPLING" + OPTIONS = "OPTIONS" + EXTRA = "EXTRA" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.methods = ((self.tr('Nearest Neighbour'), 'nearest'), - (self.tr('Bilinear (2x2 Kernel)'), 'bilinear'), - (self.tr('Cubic (4x4 Kernel)'), 'cubic'), - (self.tr('Cubic B-Spline (4x4 Kernel)'), 'cubicspline'), - (self.tr('Lanczos (6x6 Kernel)'), 'lanczos'), - (self.tr('Average'), 'average')) - - self.addParameter(QgsProcessingParameterRasterLayer(self.SPECTRAL, - self.tr('Spectral dataset'))) - self.addParameter(QgsProcessingParameterRasterLayer(self.PANCHROMATIC, - self.tr('Panchromatic dataset'))) - - resampling_param = QgsProcessingParameterEnum(self.RESAMPLING, - self.tr('Resampling algorithm'), - options=[i[0] for i in self.methods], - defaultValue=2) - resampling_param.setFlags(resampling_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.methods = ( + (self.tr("Nearest Neighbour"), "nearest"), + (self.tr("Bilinear (2x2 Kernel)"), "bilinear"), + (self.tr("Cubic (4x4 Kernel)"), "cubic"), + (self.tr("Cubic B-Spline (4x4 Kernel)"), "cubicspline"), + (self.tr("Lanczos (6x6 Kernel)"), "lanczos"), + (self.tr("Average"), "average"), + ) + + self.addParameter( + QgsProcessingParameterRasterLayer( + self.SPECTRAL, self.tr("Spectral dataset") + ) + ) + self.addParameter( + QgsProcessingParameterRasterLayer( + self.PANCHROMATIC, self.tr("Panchromatic dataset") + ) + ) + + resampling_param = QgsProcessingParameterEnum( + self.RESAMPLING, + self.tr("Resampling algorithm"), + options=[i[0] for i in self.methods], + defaultValue=2, + ) + resampling_param.setFlags( + resampling_param.flags() + | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(resampling_param) - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, - self.tr('Output'))) + self.addParameter( + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Output")) + ) def name(self): - return 'pansharp' + return "pansharp" def displayName(self): - return self.tr('Pansharpening') + return self.tr("Pansharpening") def group(self): - return self.tr('Raster miscellaneous') + return self.tr("Raster miscellaneous") def groupId(self): - return 'rastermiscellaneous' + return "rastermiscellaneous" def commandName(self): - return 'gdal_pansharpen' + return "gdal_pansharpen" def getConsoleCommands(self, parameters, context, feedback, executing=True): spectral = self.parameterAsRasterLayer(parameters, self.SPECTRAL, context) if spectral is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.SPECTRAL)) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.SPECTRAL) + ) spectral_input_details = GdalUtils.gdal_connection_details_from_layer(spectral) - panchromatic = self.parameterAsRasterLayer(parameters, self.PANCHROMATIC, context) + panchromatic = self.parameterAsRasterLayer( + parameters, self.PANCHROMATIC, context + ) if panchromatic is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.PANCHROMATIC)) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.PANCHROMATIC) + ) panchromatic_input_details = GdalUtils.gdal_connection_details_from_layer( - panchromatic) + panchromatic + ) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, out) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) arguments = [ panchromatic_input_details.connection_string, spectral_input_details.connection_string, out, - '-r', + "-r", self.methods[self.parameterAsEnum(parameters, self.RESAMPLING, context)][1], - '-of', - output_format + "-of", + output_format, ] if panchromatic_input_details.credential_options: - arguments.extend(panchromatic_input_details.credential_options_as_arguments()) + arguments.extend( + panchromatic_input_details.credential_options_as_arguments() + ) options = self.parameterAsString(parameters, self.OPTIONS, context) if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) - return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)] + return [ + self.commandName() + (".bat" if isWindows() else ".py"), + GdalUtils.escapeAndJoin(arguments), + ] diff --git a/python/plugins/processing/algs/gdal/pct2rgb.py b/python/plugins/processing/algs/gdal/pct2rgb.py index e6b91ab71e3a..3410c0a53109 100644 --- a/python/plugins/processing/algs/gdal/pct2rgb.py +++ b/python/plugins/processing/algs/gdal/pct2rgb.py @@ -15,20 +15,22 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsRasterFileWriter, - QgsProcessingException, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterBand, - QgsProcessingParameterBoolean, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessingException, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBand, + QgsProcessingParameterBoolean, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.tools.system import isWindows from processing.algs.gdal.GdalUtils import GdalUtils @@ -37,70 +39,86 @@ class pct2rgb(GdalAlgorithm): - INPUT = 'INPUT' - BAND = 'BAND' - RGBA = 'RGBA' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + BAND = "BAND" + RGBA = "RGBA" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterBand(self.BAND, - self.tr('Band number'), - 1, - parentLayerParameterName=self.INPUT)) - self.addParameter(QgsProcessingParameterBoolean(self.RGBA, - self.tr('Generate a RGBA file'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('PCT to RGB'))) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterBand( + self.BAND, + self.tr("Band number"), + 1, + parentLayerParameterName=self.INPUT, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.RGBA, self.tr("Generate a RGBA file"), defaultValue=False + ) + ) + self.addParameter( + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("PCT to RGB")) + ) def name(self): - return 'pcttorgb' + return "pcttorgb" def displayName(self): - return self.tr('PCT to RGB') + return self.tr("PCT to RGB") def group(self): - return self.tr('Raster conversion') + return self.tr("Raster conversion") def groupId(self): - return 'rasterconversion' + return "rasterconversion" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', '8-to-24-bits.png')) + return QIcon( + os.path.join(pluginPath, "images", "gdaltools", "8-to-24-bits.png") + ) def commandName(self): - return 'pct2rgb' + return "pct2rgb" def getConsoleCommands(self, parameters, context, feedback, executing=True): inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) - input_details = GdalUtils.gdal_connection_details_from_layer( - inLayer) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) + input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, out) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) arguments = [ input_details.connection_string, out, - '-of', + "-of", output_format, - '-b', + "-b", str(self.parameterAsInt(parameters, self.BAND, context)), ] if self.parameterAsBoolean(parameters, self.RGBA, context): - arguments.append('-rgba') + arguments.append("-rgba") if input_details.credential_options: arguments.extend(input_details.credential_options_as_arguments()) - return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)] + return [ + self.commandName() + (".bat" if isWindows() else ".py"), + GdalUtils.escapeAndJoin(arguments), + ] diff --git a/python/plugins/processing/algs/gdal/polygonize.py b/python/plugins/processing/algs/gdal/polygonize.py index 62c22192c733..4419e0dfdf74 100644 --- a/python/plugins/processing/algs/gdal/polygonize.py +++ b/python/plugins/processing/algs/gdal/polygonize.py @@ -15,22 +15,24 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsProcessing, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterBand, - QgsProcessingParameterString, - QgsProcessingParameterBoolean, - QgsProcessingParameterVectorDestination) +from qgis.core import ( + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBand, + QgsProcessingParameterString, + QgsProcessingParameterBoolean, + QgsProcessingParameterVectorDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.tools.system import isWindows from processing.algs.gdal.GdalUtils import GdalUtils @@ -39,77 +41,98 @@ class polygonize(GdalAlgorithm): - INPUT = 'INPUT' - BAND = 'BAND' - FIELD = 'FIELD' - EIGHT_CONNECTEDNESS = 'EIGHT_CONNECTEDNESS' - EXTRA = 'EXTRA' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + BAND = "BAND" + FIELD = "FIELD" + EIGHT_CONNECTEDNESS = "EIGHT_CONNECTEDNESS" + EXTRA = "EXTRA" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterBand(self.BAND, - self.tr('Band number'), - 1, - parentLayerParameterName=self.INPUT)) - self.addParameter(QgsProcessingParameterString(self.FIELD, - self.tr('Name of the field to create'), - defaultValue='DN')) - self.addParameter(QgsProcessingParameterBoolean(self.EIGHT_CONNECTEDNESS, - self.tr('Use 8-connectedness'), - defaultValue=False)) - - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterBand( + self.BAND, + self.tr("Band number"), + 1, + parentLayerParameterName=self.INPUT, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.FIELD, self.tr("Name of the field to create"), defaultValue="DN" + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.EIGHT_CONNECTEDNESS, + self.tr("Use 8-connectedness"), + defaultValue=False, + ) + ) + + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT, - self.tr('Vectorized'), - QgsProcessing.SourceType.TypeVectorPolygon)) + self.addParameter( + QgsProcessingParameterVectorDestination( + self.OUTPUT, + self.tr("Vectorized"), + QgsProcessing.SourceType.TypeVectorPolygon, + ) + ) def name(self): - return 'polygonize' + return "polygonize" def displayName(self): - return self.tr('Polygonize (raster to vector)') + return self.tr("Polygonize (raster to vector)") def group(self): - return self.tr('Raster conversion') + return self.tr("Raster conversion") def groupId(self): - return 'rasterconversion' + return "rasterconversion" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'polygonize.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "polygonize.png")) def commandName(self): - return 'gdal_polygonize' + return "gdal_polygonize" def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments = [] if self.parameterAsBoolean(parameters, self.EIGHT_CONNECTEDNESS, context): - arguments.append('-8') + arguments.append("-8") - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) - input_details = GdalUtils.gdal_connection_details_from_layer( - inLayer) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) + input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) arguments.append(input_details.connection_string) - arguments.append('-b') + arguments.append("-b") arguments.append(str(self.parameterAsInt(parameters, self.BAND, context))) outFile = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) @@ -117,7 +140,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): output_details = GdalUtils.gdal_connection_details_from_uri(outFile, context) if output_details.format: - arguments.append(f'-f {output_details.format}') + arguments.append(f"-f {output_details.format}") arguments.append(output_details.connection_string) @@ -129,4 +152,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if input_details.credential_options: arguments.extend(input_details.credential_options_as_arguments()) - return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)] + return [ + self.commandName() + (".bat" if isWindows() else ".py"), + GdalUtils.escapeAndJoin(arguments), + ] diff --git a/python/plugins/processing/algs/gdal/proximity.py b/python/plugins/processing/algs/gdal/proximity.py index 44cfe6dbf6b2..acc21fa4b38b 100644 --- a/python/plugins/processing/algs/gdal/proximity.py +++ b/python/plugins/processing/algs/gdal/proximity.py @@ -15,23 +15,25 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsRasterFileWriter, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterBand, - QgsProcessingParameterEnum, - QgsProcessingParameterString, - QgsProcessingParameterNumber, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBand, + QgsProcessingParameterEnum, + QgsProcessingParameterString, + QgsProcessingParameterNumber, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -41,108 +43,168 @@ class proximity(GdalAlgorithm): - INPUT = 'INPUT' - BAND = 'BAND' - VALUES = 'VALUES' - MAX_DISTANCE = 'MAX_DISTANCE' - REPLACE = 'REPLACE' - UNITS = 'UNITS' - NODATA = 'NODATA' - OPTIONS = 'OPTIONS' - EXTRA = 'EXTRA' - DATA_TYPE = 'DATA_TYPE' - OUTPUT = 'OUTPUT' - - TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8'] + INPUT = "INPUT" + BAND = "BAND" + VALUES = "VALUES" + MAX_DISTANCE = "MAX_DISTANCE" + REPLACE = "REPLACE" + UNITS = "UNITS" + NODATA = "NODATA" + OPTIONS = "OPTIONS" + EXTRA = "EXTRA" + DATA_TYPE = "DATA_TYPE" + OUTPUT = "OUTPUT" + + TYPES = [ + "Byte", + "Int16", + "UInt16", + "UInt32", + "Int32", + "Float32", + "Float64", + "CInt16", + "CInt32", + "CFloat32", + "CFloat64", + "Int8", + ] def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'proximity.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "proximity.png")) def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.distanceUnits = ((self.tr('Georeferenced coordinates'), 'GEO'), - (self.tr('Pixel coordinates'), 'PIXEL')) - - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterBand(self.BAND, - self.tr('Band number'), - 1, - parentLayerParameterName=self.INPUT)) - self.addParameter(QgsProcessingParameterString(self.VALUES, - self.tr('A list of pixel values in the source image to be considered target pixels'), - optional=True)) - self.addParameter(QgsProcessingParameterEnum(self.UNITS, - self.tr('Distance units'), - options=[i[0] for i in self.distanceUnits], - allowMultiple=False, - defaultValue=1)) - self.addParameter(QgsProcessingParameterNumber(self.MAX_DISTANCE, - self.tr('The maximum distance to be generated'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=0.0, - optional=True)) - self.addParameter(QgsProcessingParameterNumber(self.REPLACE, - self.tr('Value to be applied to all pixels that are within the -maxdist of target pixels'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=0.0, - optional=True)) - self.addParameter(QgsProcessingParameterNumber(self.NODATA, - self.tr('Nodata value to use for the destination proximity raster'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=0.0, - optional=True)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.distanceUnits = ( + (self.tr("Georeferenced coordinates"), "GEO"), + (self.tr("Pixel coordinates"), "PIXEL"), + ) + + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterBand( + self.BAND, + self.tr("Band number"), + 1, + parentLayerParameterName=self.INPUT, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.VALUES, + self.tr( + "A list of pixel values in the source image to be considered target pixels" + ), + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.UNITS, + self.tr("Distance units"), + options=[i[0] for i in self.distanceUnits], + allowMultiple=False, + defaultValue=1, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.MAX_DISTANCE, + self.tr("The maximum distance to be generated"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=0.0, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.REPLACE, + self.tr( + "Value to be applied to all pixels that are within the -maxdist of target pixels" + ), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=0.0, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.NODATA, + self.tr("Nodata value to use for the destination proximity raster"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=0.0, + optional=True, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE, - self.tr('Output data type'), - self.TYPES, - allowMultiple=False, - defaultValue=5) - dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + dataType_param = QgsProcessingParameterEnum( + self.DATA_TYPE, + self.tr("Output data type"), + self.TYPES, + allowMultiple=False, + defaultValue=5, + ) + dataType_param.setFlags( + dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(dataType_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, - self.tr('Proximity map'))) + self.addParameter( + QgsProcessingParameterRasterDestination( + self.OUTPUT, self.tr("Proximity map") + ) + ) def name(self): - return 'proximity' + return "proximity" def displayName(self): - return self.tr('Proximity (raster distance)') + return self.tr("Proximity (raster distance)") def group(self): - return self.tr('Raster analysis') + return self.tr("Raster analysis") def groupId(self): - return 'rasteranalysis' + return "rasteranalysis" def commandName(self): - return 'gdal_proximity' + return "gdal_proximity" def getConsoleCommands(self, parameters, context, feedback, executing=True): inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) - input_details = GdalUtils.gdal_connection_details_from_layer( - inLayer) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) + input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) distance = self.parameterAsDouble(parameters, self.MAX_DISTANCE, context) replaceValue = self.parameterAsDouble(parameters, self.REPLACE, context) @@ -155,47 +217,50 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): self.setOutputValue(self.OUTPUT, out) arguments = [ - '-srcband', + "-srcband", str(self.parameterAsInt(parameters, self.BAND, context)), - '-distunits', - - self.distanceUnits[self.parameterAsEnum(parameters, self.UNITS, context)][1] + "-distunits", + self.distanceUnits[self.parameterAsEnum(parameters, self.UNITS, context)][ + 1 + ], ] values = self.parameterAsString(parameters, self.VALUES, context) if values: - arguments.append('-values') + arguments.append("-values") arguments.append(values) if distance: - arguments.append('-maxdist') + arguments.append("-maxdist") arguments.append(str(distance)) if nodata is not None: - arguments.append('-nodata') + arguments.append("-nodata") arguments.append(str(nodata)) if replaceValue: - arguments.append('-fixed-buf-val') + arguments.append("-fixed-buf-val") arguments.append(str(replaceValue)) data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context) - if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later')) + if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000: + raise QgsProcessingException( + self.tr("Int8 data type requires GDAL version 3.7 or later") + ) - arguments.append('-ot ' + self.TYPES[data_type]) + arguments.append("-ot " + self.TYPES[data_type]) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) - arguments.append('-of') + arguments.append("-of") arguments.append(output_format) if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) @@ -205,4 +270,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if input_details.credential_options: arguments.extend(input_details.credential_options_as_arguments()) - return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)] + return [ + self.commandName() + (".bat" if isWindows() else ".py"), + GdalUtils.escapeAndJoin(arguments), + ] diff --git a/python/plugins/processing/algs/gdal/rasterize.py b/python/plugins/processing/algs/gdal/rasterize.py index cacd5369b323..0dda96cd9e3d 100644 --- a/python/plugins/processing/algs/gdal/rasterize.py +++ b/python/plugins/processing/algs/gdal/rasterize.py @@ -15,25 +15,28 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'September 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "September 2013" +__copyright__ = "(C) 2013, Alexander Bruy" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsRasterFileWriter, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterField, - QgsProcessingParameterNumber, - QgsProcessingParameterString, - QgsProcessingParameterEnum, - QgsProcessingParameterExtent, - QgsProcessingParameterBoolean, - QgsProcessingParameterRasterDestination, NULL) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingParameterNumber, + QgsProcessingParameterString, + QgsProcessingParameterEnum, + QgsProcessingParameterExtent, + QgsProcessingParameterBoolean, + QgsProcessingParameterRasterDestination, + NULL, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -41,203 +44,270 @@ class rasterize(GdalAlgorithm): - INPUT = 'INPUT' - FIELD = 'FIELD' - BURN = 'BURN' - USE_Z = 'USE_Z' - WIDTH = 'WIDTH' - HEIGHT = 'HEIGHT' - UNITS = 'UNITS' - NODATA = 'NODATA' - EXTENT = 'EXTENT' - INIT = 'INIT' - INVERT = 'INVERT' - ALL_TOUCH = 'ALL_TOUCH' - OPTIONS = 'OPTIONS' - DATA_TYPE = 'DATA_TYPE' - EXTRA = 'EXTRA' - OUTPUT = 'OUTPUT' - - TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8'] + INPUT = "INPUT" + FIELD = "FIELD" + BURN = "BURN" + USE_Z = "USE_Z" + WIDTH = "WIDTH" + HEIGHT = "HEIGHT" + UNITS = "UNITS" + NODATA = "NODATA" + EXTENT = "EXTENT" + INIT = "INIT" + INVERT = "INVERT" + ALL_TOUCH = "ALL_TOUCH" + OPTIONS = "OPTIONS" + DATA_TYPE = "DATA_TYPE" + EXTRA = "EXTRA" + OUTPUT = "OUTPUT" + + TYPES = [ + "Byte", + "Int16", + "UInt16", + "UInt32", + "Int32", + "Float32", + "Float64", + "CInt16", + "CInt32", + "CFloat32", + "CFloat64", + "Int8", + ] def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.units = [self.tr("Pixels"), - self.tr("Georeferenced units")] - - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterField(self.FIELD, - self.tr('Field to use for a burn-in value'), - None, - self.INPUT, - QgsProcessingParameterField.DataType.Numeric, - optional=True)) - self.addParameter(QgsProcessingParameterNumber(self.BURN, - self.tr('A fixed value to burn'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=0.0, - optional=True)) - self.addParameter(QgsProcessingParameterBoolean(self.USE_Z, - self.tr('Burn value extracted from the "Z" values of the feature'), - defaultValue=False, - optional=True)) - self.addParameter(QgsProcessingParameterEnum(self.UNITS, - self.tr('Output raster size units'), - self.units)) - self.addParameter(QgsProcessingParameterNumber(self.WIDTH, - self.tr('Width/Horizontal resolution'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=0.0)) - self.addParameter(QgsProcessingParameterNumber(self.HEIGHT, - self.tr('Height/Vertical resolution'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=0.0)) - self.addParameter(QgsProcessingParameterExtent(self.EXTENT, - self.tr('Output extent'), - optional=True)) - nodataParam = QgsProcessingParameterNumber(self.NODATA, - self.tr('Assign a specified NoData value to output bands'), - type=QgsProcessingParameterNumber.Type.Double, - optional=True) + self.units = [self.tr("Pixels"), self.tr("Georeferenced units")] + + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterField( + self.FIELD, + self.tr("Field to use for a burn-in value"), + None, + self.INPUT, + QgsProcessingParameterField.DataType.Numeric, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.BURN, + self.tr("A fixed value to burn"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=0.0, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.USE_Z, + self.tr('Burn value extracted from the "Z" values of the feature'), + defaultValue=False, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.UNITS, self.tr("Output raster size units"), self.units + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.WIDTH, + self.tr("Width/Horizontal resolution"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=0.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.HEIGHT, + self.tr("Height/Vertical resolution"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=0.0, + ) + ) + self.addParameter( + QgsProcessingParameterExtent( + self.EXTENT, self.tr("Output extent"), optional=True + ) + ) + nodataParam = QgsProcessingParameterNumber( + self.NODATA, + self.tr("Assign a specified NoData value to output bands"), + type=QgsProcessingParameterNumber.Type.Double, + optional=True, + ) nodataParam.setGuiDefaultValueOverride(NULL) self.addParameter(nodataParam) - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE, - self.tr('Output data type'), - self.TYPES, - allowMultiple=False, - defaultValue=5) - dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + dataType_param = QgsProcessingParameterEnum( + self.DATA_TYPE, + self.tr("Output data type"), + self.TYPES, + allowMultiple=False, + defaultValue=5, + ) + dataType_param.setFlags( + dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(dataType_param) - init_param = QgsProcessingParameterNumber(self.INIT, - self.tr('Pre-initialize the output image with value'), - type=QgsProcessingParameterNumber.Type.Double, - optional=True) - init_param.setFlags(init_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + init_param = QgsProcessingParameterNumber( + self.INIT, + self.tr("Pre-initialize the output image with value"), + type=QgsProcessingParameterNumber.Type.Double, + optional=True, + ) + init_param.setFlags( + init_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(init_param) - invert_param = QgsProcessingParameterBoolean(self.INVERT, - self.tr('Invert rasterization'), - defaultValue=False) - invert_param.setFlags(invert_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + invert_param = QgsProcessingParameterBoolean( + self.INVERT, self.tr("Invert rasterization"), defaultValue=False + ) + invert_param.setFlags( + invert_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(invert_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, - self.tr('Rasterized'))) + self.addParameter( + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Rasterized")) + ) def name(self): - return 'rasterize' + return "rasterize" def displayName(self): - return self.tr('Rasterize (vector to raster)') + return self.tr("Rasterize (vector to raster)") def group(self): - return self.tr('Vector conversion') + return self.tr("Vector conversion") def groupId(self): - return 'vectorconversion' + return "vectorconversion" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'rasterize.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "rasterize.png")) def commandName(self): - return 'gdal_rasterize' + return "gdal_rasterize" def getConsoleCommands(self, parameters, context, feedback, executing=True): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) - - input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing) - arguments = [ - '-l', - input_details.layer_name - ] + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) + + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) + arguments = ["-l", input_details.layer_name] fieldName = self.parameterAsString(parameters, self.FIELD, context) use_z = self.parameterAsBoolean(parameters, self.USE_Z, context) if use_z: - arguments.append('-3d') + arguments.append("-3d") elif fieldName: - arguments.append('-a') + arguments.append("-a") arguments.append(fieldName) else: - arguments.append('-burn') + arguments.append("-burn") arguments.append(self.parameterAsDouble(parameters, self.BURN, context)) units = self.parameterAsEnum(parameters, self.UNITS, context) if units == 0: - arguments.append('-ts') + arguments.append("-ts") else: - arguments.append('-tr') + arguments.append("-tr") arguments.append(self.parameterAsDouble(parameters, self.WIDTH, context)) arguments.append(self.parameterAsDouble(parameters, self.HEIGHT, context)) if self.INIT in parameters and parameters[self.INIT] is not None: initValue = self.parameterAsDouble(parameters, self.INIT, context) - arguments.append('-init') + arguments.append("-init") arguments.append(initValue) if self.parameterAsBoolean(parameters, self.INVERT, context): - arguments.append('-i') + arguments.append("-i") if self.parameterAsBoolean(parameters, self.ALL_TOUCH, context): - arguments.append('-at') + arguments.append("-at") if self.NODATA in parameters and parameters[self.NODATA] is not None: nodata = self.parameterAsDouble(parameters, self.NODATA, context) - arguments.append('-a_nodata') + arguments.append("-a_nodata") arguments.append(nodata) - extent = self.parameterAsExtent(parameters, self.EXTENT, context, source.sourceCrs()) + extent = self.parameterAsExtent( + parameters, self.EXTENT, context, source.sourceCrs() + ) if not extent.isNull(): - arguments.append('-te') + arguments.append("-te") arguments.append(extent.xMinimum()) arguments.append(extent.yMinimum()) arguments.append(extent.xMaximum()) arguments.append(extent.yMaximum()) data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context) - if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later')) + if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000: + raise QgsProcessingException( + self.tr("Int8 data type requires GDAL version 3.7 or later") + ) - arguments.append('-ot ' + self.TYPES[data_type]) + arguments.append("-ot " + self.TYPES[data_type]) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, out) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) - arguments.append('-of') + arguments.append("-of") arguments.append(output_format) if input_details.open_options: if GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr( - 'Open options are not supported by gdal_rasterize version {} (requires GDAL version 3.7 or later)'.format( - GdalUtils.readableVersion()))) + raise QgsProcessingException( + self.tr( + "Open options are not supported by gdal_rasterize version {} (requires GDAL version 3.7 or later)".format( + GdalUtils.readableVersion() + ) + ) + ) arguments.extend(input_details.open_options_as_arguments()) @@ -248,7 +318,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) diff --git a/python/plugins/processing/algs/gdal/rasterize_over.py b/python/plugins/processing/algs/gdal/rasterize_over.py index dce80ad423ab..31867dc2b0fd 100644 --- a/python/plugins/processing/algs/gdal/rasterize_over.py +++ b/python/plugins/processing/algs/gdal/rasterize_over.py @@ -15,22 +15,24 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'September 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "September 2013" +__copyright__ = "(C) 2013, Alexander Bruy" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterField, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterString, - QgsProcessingParameterBoolean, - QgsProcessingOutputRasterLayer) +from qgis.core import ( + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterString, + QgsProcessingParameterBoolean, + QgsProcessingOutputRasterLayer, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -38,92 +40,108 @@ class rasterize_over(GdalAlgorithm): - INPUT = 'INPUT' - FIELD = 'FIELD' - INPUT_RASTER = 'INPUT_RASTER' - ADD = 'ADD' - EXTRA = 'EXTRA' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + FIELD = "FIELD" + INPUT_RASTER = "INPUT_RASTER" + ADD = "ADD" + EXTRA = "EXTRA" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input vector layer'))) - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT_RASTER, - self.tr('Input raster layer'))) - self.addParameter(QgsProcessingParameterField(self.FIELD, - self.tr('Field to use for burn in value'), - None, - self.INPUT, - QgsProcessingParameterField.DataType.Numeric, - optional=False)) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, self.tr("Input vector layer") + ) + ) + self.addParameter( + QgsProcessingParameterRasterLayer( + self.INPUT_RASTER, self.tr("Input raster layer") + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.FIELD, + self.tr("Field to use for burn in value"), + None, + self.INPUT, + QgsProcessingParameterField.DataType.Numeric, + optional=False, + ) + ) params = [ - QgsProcessingParameterBoolean(self.ADD, - self.tr('Add burn in values to existing raster values'), - defaultValue=False, - ), - QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) + QgsProcessingParameterBoolean( + self.ADD, + self.tr("Add burn in values to existing raster values"), + defaultValue=False, + ), + QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ), ] for p in params: p.setFlags(p.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) self.addParameter(p) - self.addOutput(QgsProcessingOutputRasterLayer(self.OUTPUT, - self.tr('Rasterized'))) + self.addOutput( + QgsProcessingOutputRasterLayer(self.OUTPUT, self.tr("Rasterized")) + ) def name(self): - return 'rasterize_over' + return "rasterize_over" def displayName(self): - return self.tr('Rasterize (overwrite with attribute)') + return self.tr("Rasterize (overwrite with attribute)") def group(self): - return self.tr('Vector conversion') + return self.tr("Vector conversion") def groupId(self): - return 'vectorconversion' + return "vectorconversion" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'rasterize.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "rasterize.png")) def commandName(self): - return 'gdal_rasterize' + return "gdal_rasterize" def getConsoleCommands(self, parameters, context, feedback, executing=True): - input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing) + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) inLayer = self.parameterAsRasterLayer(parameters, self.INPUT_RASTER, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_RASTER)) - input_raster_details = GdalUtils.gdal_connection_details_from_layer( - inLayer) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT_RASTER) + ) + input_raster_details = GdalUtils.gdal_connection_details_from_layer(inLayer) fieldName = self.parameterAsString(parameters, self.FIELD, context) self.setOutputValue(self.OUTPUT, inLayer.source()) - arguments = [ - '-l', - input_details.layer_name, - '-a', - fieldName - ] + arguments = ["-l", input_details.layer_name, "-a", fieldName] if self.parameterAsBool(parameters, self.ADD, context): - arguments.append('-add') + arguments.append("-add") - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) if input_details.open_options: if GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr( - 'Open options are not supported by gdal_rasterize version {} (requires GDAL version 3.7 or later)'.format( - GdalUtils.readableVersion()))) + raise QgsProcessingException( + self.tr( + "Open options are not supported by gdal_rasterize version {} (requires GDAL version 3.7 or later)".format( + GdalUtils.readableVersion() + ) + ) + ) arguments.extend(input_details.open_options_as_arguments()) diff --git a/python/plugins/processing/algs/gdal/rasterize_over_fixed_value.py b/python/plugins/processing/algs/gdal/rasterize_over_fixed_value.py index 5767596a2d35..0a11de412ae9 100644 --- a/python/plugins/processing/algs/gdal/rasterize_over_fixed_value.py +++ b/python/plugins/processing/algs/gdal/rasterize_over_fixed_value.py @@ -15,22 +15,24 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'September 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "September 2013" +__copyright__ = "(C) 2013, Alexander Bruy" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterNumber, - QgsProcessingParameterString, - QgsProcessingParameterBoolean, - QgsProcessingOutputRasterLayer) +from qgis.core import ( + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterNumber, + QgsProcessingParameterString, + QgsProcessingParameterBoolean, + QgsProcessingOutputRasterLayer, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -38,92 +40,114 @@ class rasterize_over_fixed_value(GdalAlgorithm): - INPUT = 'INPUT' - INPUT_RASTER = 'INPUT_RASTER' - ADD = 'ADD' - EXTRA = 'EXTRA' - BURN = 'BURN' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + INPUT_RASTER = "INPUT_RASTER" + ADD = "ADD" + EXTRA = "EXTRA" + BURN = "BURN" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input vector layer'))) - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT_RASTER, - self.tr('Input raster layer'))) - self.addParameter(QgsProcessingParameterNumber(self.BURN, - self.tr('A fixed value to burn'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=0.0)) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, self.tr("Input vector layer") + ) + ) + self.addParameter( + QgsProcessingParameterRasterLayer( + self.INPUT_RASTER, self.tr("Input raster layer") + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.BURN, + self.tr("A fixed value to burn"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=0.0, + ) + ) params = [ - QgsProcessingParameterBoolean(self.ADD, - self.tr('Add burn in values to existing raster values'), - defaultValue=False), - QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) + QgsProcessingParameterBoolean( + self.ADD, + self.tr("Add burn in values to existing raster values"), + defaultValue=False, + ), + QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ), ] for p in params: p.setFlags(p.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) self.addParameter(p) - self.addOutput(QgsProcessingOutputRasterLayer(self.OUTPUT, - self.tr('Rasterized'))) + self.addOutput( + QgsProcessingOutputRasterLayer(self.OUTPUT, self.tr("Rasterized")) + ) def name(self): - return 'rasterize_over_fixed_value' + return "rasterize_over_fixed_value" def displayName(self): - return self.tr('Rasterize (overwrite with fixed value)') + return self.tr("Rasterize (overwrite with fixed value)") def group(self): - return self.tr('Vector conversion') + return self.tr("Vector conversion") def groupId(self): - return 'vectorconversion' + return "vectorconversion" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'rasterize.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "rasterize.png")) def commandName(self): - return 'gdal_rasterize' + return "gdal_rasterize" def getConsoleCommands(self, parameters, context, feedback, executing=True): - input_details = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing) + input_details = self.getOgrCompatibleSource( + self.INPUT, parameters, context, feedback, executing + ) inLayer = self.parameterAsRasterLayer(parameters, self.INPUT_RASTER, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT_RASTER)) - input_raster_details = GdalUtils.gdal_connection_details_from_layer( - inLayer) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT_RASTER) + ) + input_raster_details = GdalUtils.gdal_connection_details_from_layer(inLayer) self.setOutputValue(self.OUTPUT, inLayer.source()) arguments = [ - '-l', + "-l", input_details.layer_name, - '-burn', + "-burn", str(self.parameterAsDouble(parameters, self.BURN, context)), ] if self.parameterAsBool(parameters, self.ADD, context): - arguments.append('-add') + arguments.append("-add") if input_details.open_options: if GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr( - 'Open options are not supported by gdal_rasterize version {} (requires GDAL version 3.7 or later)'.format( - GdalUtils.readableVersion()))) + raise QgsProcessingException( + self.tr( + "Open options are not supported by gdal_rasterize version {} (requires GDAL version 3.7 or later)".format( + GdalUtils.readableVersion() + ) + ) + ) arguments.extend(input_details.open_options_as_arguments()) if input_details.credential_options: arguments.extend(input_details.credential_options_as_arguments()) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) diff --git a/python/plugins/processing/algs/gdal/rearrange_bands.py b/python/plugins/processing/algs/gdal/rearrange_bands.py index 3569f1bbee86..6d0163f76662 100644 --- a/python/plugins/processing/algs/gdal/rearrange_bands.py +++ b/python/plugins/processing/algs/gdal/rearrange_bands.py @@ -15,22 +15,24 @@ *************************************************************************** """ -__author__ = 'Mathieu Pellerin' -__date__ = 'August 2018' -__copyright__ = '(C) 2018, Mathieu Pellerin' +__author__ = "Mathieu Pellerin" +__date__ = "August 2018" +__copyright__ = "(C) 2018, Mathieu Pellerin" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsRasterFileWriter, - QgsProcessingException, - QgsProcessingParameterEnum, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterBand, - QgsProcessingParameterString, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessingException, + QgsProcessingParameterEnum, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBand, + QgsProcessingParameterString, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -38,95 +40,126 @@ class rearrange_bands(GdalAlgorithm): - INPUT = 'INPUT' - BANDS = 'BANDS' - OPTIONS = 'OPTIONS' - DATA_TYPE = 'DATA_TYPE' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + BANDS = "BANDS" + OPTIONS = "OPTIONS" + DATA_TYPE = "DATA_TYPE" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.TYPES = [self.tr('Use Input Layer Data Type'), 'Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8'] - - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterBand(self.BANDS, - self.tr('Selected band(s)'), - None, - self.INPUT, - allowMultiple=True)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.TYPES = [ + self.tr("Use Input Layer Data Type"), + "Byte", + "Int16", + "UInt16", + "UInt32", + "Int32", + "Float32", + "Float64", + "CInt16", + "CInt32", + "CFloat32", + "CFloat64", + "Int8", + ] + + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterBand( + self.BANDS, + self.tr("Selected band(s)"), + None, + self.INPUT, + allowMultiple=True, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE, - self.tr('Output data type'), - self.TYPES, - allowMultiple=False, - defaultValue=0) - dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + dataType_param = QgsProcessingParameterEnum( + self.DATA_TYPE, + self.tr("Output data type"), + self.TYPES, + allowMultiple=False, + defaultValue=0, + ) + dataType_param.setFlags( + dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(dataType_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, - self.tr('Converted'))) + self.addParameter( + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Converted")) + ) def name(self): - return 'rearrange_bands' + return "rearrange_bands" def displayName(self): - return self.tr('Rearrange bands') + return self.tr("Rearrange bands") def group(self): - return self.tr('Raster conversion') + return self.tr("Raster conversion") def groupId(self): - return 'rasterconversion' + return "rasterconversion" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'translate.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "translate.png")) def shortHelpString(self): - return self.tr("This algorithm creates a new raster using selected band(s) from a given raster layer.\n\n" - "The algorithm also makes it possible to reorder the bands for the newly-created raster.") + return self.tr( + "This algorithm creates a new raster using selected band(s) from a given raster layer.\n\n" + "The algorithm also makes it possible to reorder the bands for the newly-created raster." + ) def commandName(self): - return 'gdal_translate' + return "gdal_translate" def getConsoleCommands(self, parameters, context, feedback, executing=True): inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) - input_details = GdalUtils.gdal_connection_details_from_layer( - inLayer) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) + input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, out) bands = self.parameterAsInts(parameters, self.BANDS, context) - arguments = [ - f'-b {band}' - for band in bands - ] + arguments = [f"-b {band}" for band in bands] data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context) if data_type: - if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later')) + if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000: + raise QgsProcessingException( + self.tr("Int8 data type requires GDAL version 3.7 or later") + ) - arguments.append('-ot ' + self.TYPES[data_type]) + arguments.append("-ot " + self.TYPES[data_type]) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) - arguments.append('-of') + arguments.append("-of") arguments.append(output_format) options = self.parameterAsString(parameters, self.OPTIONS, context) diff --git a/python/plugins/processing/algs/gdal/retile.py b/python/plugins/processing/algs/gdal/retile.py index 38c7c8cf2fa4..085ec67ec4d6 100644 --- a/python/plugins/processing/algs/gdal/retile.py +++ b/python/plugins/processing/algs/gdal/retile.py @@ -15,202 +15,268 @@ *************************************************************************** """ -__author__ = 'Médéric Ribreux' -__date__ = 'January 2016' -__copyright__ = '(C) 2016, Médéric Ribreux' - -from qgis.core import (QgsProcessing, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterMultipleLayers, - QgsProcessingParameterCrs, - QgsProcessingParameterEnum, - QgsProcessingParameterString, - QgsProcessingParameterNumber, - QgsProcessingParameterBoolean, - QgsProcessingParameterFileDestination, - QgsProcessingParameterFolderDestination) +__author__ = "Médéric Ribreux" +__date__ = "January 2016" +__copyright__ = "(C) 2016, Médéric Ribreux" + +from qgis.core import ( + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterMultipleLayers, + QgsProcessingParameterCrs, + QgsProcessingParameterEnum, + QgsProcessingParameterString, + QgsProcessingParameterNumber, + QgsProcessingParameterBoolean, + QgsProcessingParameterFileDestination, + QgsProcessingParameterFolderDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils from processing.tools.system import isWindows class retile(GdalAlgorithm): - INPUT = 'INPUT' - TILE_SIZE_X = 'TILE_SIZE_X' - TILE_SIZE_Y = 'TILE_SIZE_Y' - OVERLAP = 'OVERLAP' - LEVELS = 'LEVELS' - - SOURCE_CRS = 'SOURCE_CRS' - FORMAT = 'FORMAT' - RESAMPLING = 'RESAMPLING' - OPTIONS = 'OPTIONS' - EXTRA = 'EXTRA' - DATA_TYPE = 'DATA_TYPE' - DELIMITER = 'DELIMITER' - ONLY_PYRAMIDS = 'ONLY_PYRAMIDS' - DIR_FOR_ROW = 'DIR_FOR_ROW' - OUTPUT = 'OUTPUT' - OUTPUT_CSV = 'OUTPUT_CSV' - - TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8'] + INPUT = "INPUT" + TILE_SIZE_X = "TILE_SIZE_X" + TILE_SIZE_Y = "TILE_SIZE_Y" + OVERLAP = "OVERLAP" + LEVELS = "LEVELS" + + SOURCE_CRS = "SOURCE_CRS" + FORMAT = "FORMAT" + RESAMPLING = "RESAMPLING" + OPTIONS = "OPTIONS" + EXTRA = "EXTRA" + DATA_TYPE = "DATA_TYPE" + DELIMITER = "DELIMITER" + ONLY_PYRAMIDS = "ONLY_PYRAMIDS" + DIR_FOR_ROW = "DIR_FOR_ROW" + OUTPUT = "OUTPUT" + OUTPUT_CSV = "OUTPUT_CSV" + + TYPES = [ + "Byte", + "Int16", + "UInt16", + "UInt32", + "Int32", + "Float32", + "Float64", + "CInt16", + "CInt32", + "CFloat32", + "CFloat64", + "Int8", + ] def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.methods = ((self.tr('Nearest Neighbour'), 'near'), - (self.tr('Bilinear (2x2 Kernel)'), 'bilinear'), - (self.tr('Cubic (4x4 Kernel)'), 'cubic'), - (self.tr('Cubic B-Spline (4x4 Kernel)'), 'cubicspline'), - (self.tr('Lanczos (6x6 Kernel)'), 'lanczos'),) - - self.addParameter(QgsProcessingParameterMultipleLayers(self.INPUT, - self.tr('Input files'), - QgsProcessing.SourceType.TypeRaster)) - self.addParameter(QgsProcessingParameterNumber(self.TILE_SIZE_X, - self.tr('Tile width'), - type=QgsProcessingParameterNumber.Type.Integer, - minValue=0, - defaultValue=256)) - self.addParameter(QgsProcessingParameterNumber(self.TILE_SIZE_Y, - self.tr('Tile height'), - type=QgsProcessingParameterNumber.Type.Integer, - minValue=0, - defaultValue=256)) - self.addParameter(QgsProcessingParameterNumber(self.OVERLAP, - self.tr('Overlap in pixels between consecutive tiles'), - type=QgsProcessingParameterNumber.Type.Integer, - minValue=0, - defaultValue=0)) - self.addParameter(QgsProcessingParameterNumber(self.LEVELS, - self.tr('Number of pyramids levels to build'), - type=QgsProcessingParameterNumber.Type.Integer, - minValue=0, - defaultValue=1)) + self.methods = ( + (self.tr("Nearest Neighbour"), "near"), + (self.tr("Bilinear (2x2 Kernel)"), "bilinear"), + (self.tr("Cubic (4x4 Kernel)"), "cubic"), + (self.tr("Cubic B-Spline (4x4 Kernel)"), "cubicspline"), + (self.tr("Lanczos (6x6 Kernel)"), "lanczos"), + ) + + self.addParameter( + QgsProcessingParameterMultipleLayers( + self.INPUT, self.tr("Input files"), QgsProcessing.SourceType.TypeRaster + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.TILE_SIZE_X, + self.tr("Tile width"), + type=QgsProcessingParameterNumber.Type.Integer, + minValue=0, + defaultValue=256, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.TILE_SIZE_Y, + self.tr("Tile height"), + type=QgsProcessingParameterNumber.Type.Integer, + minValue=0, + defaultValue=256, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.OVERLAP, + self.tr("Overlap in pixels between consecutive tiles"), + type=QgsProcessingParameterNumber.Type.Integer, + minValue=0, + defaultValue=0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.LEVELS, + self.tr("Number of pyramids levels to build"), + type=QgsProcessingParameterNumber.Type.Integer, + minValue=0, + defaultValue=1, + ) + ) params = [ - QgsProcessingParameterCrs(self.SOURCE_CRS, - self.tr('Source coordinate reference system'), - optional=True, - ), - QgsProcessingParameterEnum(self.RESAMPLING, - self.tr('Resampling method'), - options=[i[0] for i in self.methods], - allowMultiple=False, - defaultValue=0), - QgsProcessingParameterString(self.DELIMITER, - self.tr('Column delimiter used in the CSV file'), - defaultValue=';', - optional=True) - + QgsProcessingParameterCrs( + self.SOURCE_CRS, + self.tr("Source coordinate reference system"), + optional=True, + ), + QgsProcessingParameterEnum( + self.RESAMPLING, + self.tr("Resampling method"), + options=[i[0] for i in self.methods], + allowMultiple=False, + defaultValue=0, + ), + QgsProcessingParameterString( + self.DELIMITER, + self.tr("Column delimiter used in the CSV file"), + defaultValue=";", + optional=True, + ), ] - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) params.append(options_param) - params.append(QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True)) - - params.append(QgsProcessingParameterEnum(self.DATA_TYPE, - self.tr('Output data type'), - self.TYPES, - allowMultiple=False, - defaultValue=5)) - - params.append(QgsProcessingParameterBoolean(self.ONLY_PYRAMIDS, - self.tr('Build only the pyramids'), - defaultValue=False)) - params.append(QgsProcessingParameterBoolean(self.DIR_FOR_ROW, - self.tr('Use separate directory for each tiles row'), - defaultValue=False)) + params.append( + QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + ) + + params.append( + QgsProcessingParameterEnum( + self.DATA_TYPE, + self.tr("Output data type"), + self.TYPES, + allowMultiple=False, + defaultValue=5, + ) + ) + + params.append( + QgsProcessingParameterBoolean( + self.ONLY_PYRAMIDS, + self.tr("Build only the pyramids"), + defaultValue=False, + ) + ) + params.append( + QgsProcessingParameterBoolean( + self.DIR_FOR_ROW, + self.tr("Use separate directory for each tiles row"), + defaultValue=False, + ) + ) for param in params: - param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + param.setFlags( + param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(param) - self.addParameter(QgsProcessingParameterFolderDestination(self.OUTPUT, - self.tr('Output directory'))) - - output_csv_param = QgsProcessingParameterFileDestination(self.OUTPUT_CSV, - self.tr('CSV file containing the tile(s) georeferencing information'), - 'CSV files (*.csv)', - optional=True) + self.addParameter( + QgsProcessingParameterFolderDestination( + self.OUTPUT, self.tr("Output directory") + ) + ) + + output_csv_param = QgsProcessingParameterFileDestination( + self.OUTPUT_CSV, + self.tr("CSV file containing the tile(s) georeferencing information"), + "CSV files (*.csv)", + optional=True, + ) output_csv_param.setCreateByDefault(False) self.addParameter(output_csv_param) def name(self): - return 'retile' + return "retile" def displayName(self): - return self.tr('Retile') + return self.tr("Retile") def group(self): - return self.tr('Raster miscellaneous') + return self.tr("Raster miscellaneous") def groupId(self): - return 'rastermiscellaneous' + return "rastermiscellaneous" def commandName(self): return "gdal_retile" def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments = [ - '-ps', + "-ps", str(self.parameterAsInt(parameters, self.TILE_SIZE_X, context)), str(self.parameterAsInt(parameters, self.TILE_SIZE_Y, context)), - - '-overlap', + "-overlap", str(self.parameterAsInt(parameters, self.OVERLAP, context)), - - '-levels', - str(self.parameterAsInt(parameters, self.LEVELS, context)) + "-levels", + str(self.parameterAsInt(parameters, self.LEVELS, context)), ] crs = self.parameterAsCrs(parameters, self.SOURCE_CRS, context) if crs.isValid(): - arguments.append('-s_srs') + arguments.append("-s_srs") arguments.append(GdalUtils.gdal_crs_string(crs)) - arguments.append('-r') - arguments.append(self.methods[self.parameterAsEnum(parameters, self.RESAMPLING, context)][1]) + arguments.append("-r") + arguments.append( + self.methods[self.parameterAsEnum(parameters, self.RESAMPLING, context)][1] + ) data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context) - if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later')) + if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000: + raise QgsProcessingException( + self.tr("Int8 data type requires GDAL version 3.7 or later") + ) - arguments.append('-ot ' + self.TYPES[data_type]) + arguments.append("-ot " + self.TYPES[data_type]) options = self.parameterAsString(parameters, self.OPTIONS, context) if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) if self.parameterAsBoolean(parameters, self.DIR_FOR_ROW, context): - arguments.append('-useDirForEachRow') + arguments.append("-useDirForEachRow") if self.parameterAsBoolean(parameters, self.ONLY_PYRAMIDS, context): - arguments.append('-pyramidOnly') + arguments.append("-pyramidOnly") csvFile = self.parameterAsFileOutput(parameters, self.OUTPUT_CSV, context) if csvFile: - arguments.append('-csv') + arguments.append("-csv") arguments.append(csvFile) delimiter = self.parameterAsString(parameters, self.DELIMITER, context) if delimiter: - arguments.append('-csvDelim') + arguments.append("-csvDelim") arguments.append(delimiter) - arguments.append('-targetDir') + arguments.append("-targetDir") arguments.append(self.parameterAsString(parameters, self.OUTPUT, context)) input_layers = self.parameterAsLayerList(parameters, self.INPUT, context) @@ -222,8 +288,12 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if layer_details.credential_options: credential_options.extend( - layer_details.credential_options_as_arguments()) + layer_details.credential_options_as_arguments() + ) arguments.extend(layers) arguments.extend(credential_options) - return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)] + return [ + self.commandName() + (".bat" if isWindows() else ".py"), + GdalUtils.escapeAndJoin(arguments), + ] diff --git a/python/plugins/processing/algs/gdal/rgb2pct.py b/python/plugins/processing/algs/gdal/rgb2pct.py index 406a85e7f859..8bc9ab9b6cda 100644 --- a/python/plugins/processing/algs/gdal/rgb2pct.py +++ b/python/plugins/processing/algs/gdal/rgb2pct.py @@ -15,19 +15,21 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsRasterFileWriter, - QgsProcessingException, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterNumber, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessingException, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterNumber, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils from processing.tools.system import isWindows @@ -36,41 +38,51 @@ class rgb2pct(GdalAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' - NCOLORS = 'NCOLORS' + INPUT = "INPUT" + OUTPUT = "OUTPUT" + NCOLORS = "NCOLORS" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterNumber(self.NCOLORS, - self.tr('Number of colors'), - type=QgsProcessingParameterNumber.Type.Integer, - minValue=0, - maxValue=255, - defaultValue=2)) - - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('RGB to PCT'))) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.NCOLORS, + self.tr("Number of colors"), + type=QgsProcessingParameterNumber.Type.Integer, + minValue=0, + maxValue=255, + defaultValue=2, + ) + ) + + self.addParameter( + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("RGB to PCT")) + ) def name(self): - return 'rgbtopct' + return "rgbtopct" def displayName(self): - return self.tr('RGB to PCT') + return self.tr("RGB to PCT") def group(self): - return self.tr('Raster conversion') + return self.tr("Raster conversion") def groupId(self): - return 'rasterconversion' + return "rasterconversion" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', '24-to-8-bits.png')) + return QIcon( + os.path.join(pluginPath, "images", "gdaltools", "24-to-8-bits.png") + ) def commandName(self): - return 'rgb2pct' + return "rgb2pct" def getConsoleCommands(self, parameters, context, feedback, executing=True): out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) @@ -78,24 +90,28 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): raster = self.parameterAsRasterLayer(parameters, self.INPUT, context) if raster is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) - input_details = GdalUtils.gdal_connection_details_from_layer( - raster) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) + input_details = GdalUtils.gdal_connection_details_from_layer(raster) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) arguments = [ - '-n', + "-n", str(self.parameterAsInt(parameters, self.NCOLORS, context)), - '-of', + "-of", output_format, input_details.connection_string, - out + out, ] if input_details.credential_options: arguments.extend(input_details.credential_options_as_arguments()) - return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)] + return [ + self.commandName() + (".bat" if isWindows() else ".py"), + GdalUtils.escapeAndJoin(arguments), + ] diff --git a/python/plugins/processing/algs/gdal/roughness.py b/python/plugins/processing/algs/gdal/roughness.py index 4a5be6dddbe0..e02b85ce4598 100644 --- a/python/plugins/processing/algs/gdal/roughness.py +++ b/python/plugins/processing/algs/gdal/roughness.py @@ -15,20 +15,22 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'October 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "October 2013" +__copyright__ = "(C) 2013, Alexander Bruy" import os -from qgis.core import (QgsRasterFileWriter, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterBand, - QgsProcessingParameterString, - QgsProcessingParameterBoolean, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBand, + QgsProcessingParameterString, + QgsProcessingParameterBoolean, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -37,76 +39,91 @@ class roughness(GdalAlgorithm): - INPUT = 'INPUT' - BAND = 'BAND' - COMPUTE_EDGES = 'COMPUTE_EDGES' - OPTIONS = 'OPTIONS' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + BAND = "BAND" + COMPUTE_EDGES = "COMPUTE_EDGES" + OPTIONS = "OPTIONS" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterBand(self.BAND, - self.tr('Band number'), - 1, - parentLayerParameterName=self.INPUT)) - self.addParameter(QgsProcessingParameterBoolean(self.COMPUTE_EDGES, - self.tr('Compute edges'), - defaultValue=False)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterBand( + self.BAND, + self.tr("Band number"), + 1, + parentLayerParameterName=self.INPUT, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.COMPUTE_EDGES, self.tr("Compute edges"), defaultValue=False + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Roughness'))) + self.addParameter( + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Roughness")) + ) def name(self): - return 'roughness' + return "roughness" def displayName(self): - return self.tr('Roughness') + return self.tr("Roughness") def group(self): - return self.tr('Raster analysis') + return self.tr("Raster analysis") def groupId(self): - return 'rasteranalysis' + return "rasteranalysis" def commandName(self): - return 'gdaldem' + return "gdaldem" def getConsoleCommands(self, parameters, context, feedback, executing=True): inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) - input_details = GdalUtils.gdal_connection_details_from_layer( - inLayer) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) + input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, out) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) arguments = [ - 'roughness', + "roughness", input_details.connection_string, out, - '-of', + "-of", output_format, - '-b', - str(self.parameterAsInt(parameters, self.BAND, context)) + "-b", + str(self.parameterAsInt(parameters, self.BAND, context)), ] if self.parameterAsBoolean(parameters, self.COMPUTE_EDGES, context): - arguments.append('-compute_edges') + arguments.append("-compute_edges") if input_details.credential_options: arguments.extend(input_details.credential_options_as_arguments()) diff --git a/python/plugins/processing/algs/gdal/sieve.py b/python/plugins/processing/algs/gdal/sieve.py index eac503d81c8c..806693e876a6 100644 --- a/python/plugins/processing/algs/gdal/sieve.py +++ b/python/plugins/processing/algs/gdal/sieve.py @@ -15,22 +15,24 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsRasterFileWriter, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterNumber, - QgsProcessingParameterBoolean, - QgsProcessingParameterString, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterNumber, + QgsProcessingParameterBoolean, + QgsProcessingParameterString, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.tools.system import isWindows from processing.algs.gdal.GdalUtils import GdalUtils @@ -39,80 +41,101 @@ class sieve(GdalAlgorithm): - INPUT = 'INPUT' - THRESHOLD = 'THRESHOLD' - EIGHT_CONNECTEDNESS = 'EIGHT_CONNECTEDNESS' - NO_MASK = 'NO_MASK' - MASK_LAYER = 'MASK_LAYER' - EXTRA = 'EXTRA' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + THRESHOLD = "THRESHOLD" + EIGHT_CONNECTEDNESS = "EIGHT_CONNECTEDNESS" + NO_MASK = "NO_MASK" + MASK_LAYER = "MASK_LAYER" + EXTRA = "EXTRA" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterNumber(self.THRESHOLD, - self.tr('Threshold'), - type=QgsProcessingParameterNumber.Type.Integer, - minValue=0, - defaultValue=10)) - self.addParameter(QgsProcessingParameterBoolean(self.EIGHT_CONNECTEDNESS, - self.tr('Use 8-connectedness'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.NO_MASK, - self.tr('Do not use the default validity mask for the input band'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterRasterLayer(self.MASK_LAYER, - self.tr('Validity mask'), - optional=True)) - - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.THRESHOLD, + self.tr("Threshold"), + type=QgsProcessingParameterNumber.Type.Integer, + minValue=0, + defaultValue=10, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.EIGHT_CONNECTEDNESS, + self.tr("Use 8-connectedness"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.NO_MASK, + self.tr("Do not use the default validity mask for the input band"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterRasterLayer( + self.MASK_LAYER, self.tr("Validity mask"), optional=True + ) + ) + + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Sieved'))) + self.addParameter( + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Sieved")) + ) def name(self): - return 'sieve' + return "sieve" def displayName(self): - return self.tr('Sieve') + return self.tr("Sieve") def group(self): - return self.tr('Raster analysis') + return self.tr("Raster analysis") def groupId(self): - return 'rasteranalysis' + return "rasteranalysis" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'sieve.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "sieve.png")) def commandName(self): - return 'gdal_sieve' + return "gdal_sieve" def getConsoleCommands(self, parameters, context, feedback, executing=True): arguments = [ - '-st', + "-st", str(self.parameterAsInt(parameters, self.THRESHOLD, context)), ] if self.parameterAsBoolean(parameters, self.EIGHT_CONNECTEDNESS, context): - arguments.append('-8') + arguments.append("-8") else: - arguments.append('-4') + arguments.append("-4") if self.parameterAsBoolean(parameters, self.NO_MASK, context): - arguments.append('-nomask') + arguments.append("-nomask") mask = self.parameterAsRasterLayer(parameters, self.MASK_LAYER, context) if mask: - mask_details = GdalUtils.gdal_connection_details_from_layer( - mask) - arguments.append('-mask') + mask_details = GdalUtils.gdal_connection_details_from_layer(mask) + arguments.append("-mask") arguments.append(mask_details.connection_string) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) @@ -120,20 +143,21 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) - arguments.append('-of') + arguments.append("-of") arguments.append(output_format) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) raster = self.parameterAsRasterLayer(parameters, self.INPUT, context) if raster is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) - input_details = GdalUtils.gdal_connection_details_from_layer( - raster) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) + input_details = GdalUtils.gdal_connection_details_from_layer(raster) arguments.append(input_details.connection_string) arguments.append(out) @@ -141,4 +165,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if input_details.credential_options: arguments.extend(input_details.credential_options_as_arguments()) - return [self.commandName() + ('.bat' if isWindows() else '.py'), GdalUtils.escapeAndJoin(arguments)] + return [ + self.commandName() + (".bat" if isWindows() else ".py"), + GdalUtils.escapeAndJoin(arguments), + ] diff --git a/python/plugins/processing/algs/gdal/slope.py b/python/plugins/processing/algs/gdal/slope.py index e7a0cbff8974..c709662ed30f 100644 --- a/python/plugins/processing/algs/gdal/slope.py +++ b/python/plugins/processing/algs/gdal/slope.py @@ -15,21 +15,23 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'October 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "October 2013" +__copyright__ = "(C) 2013, Alexander Bruy" import os -from qgis.core import (QgsRasterFileWriter, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterBand, - QgsProcessingParameterNumber, - QgsProcessingParameterString, - QgsProcessingParameterBoolean, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBand, + QgsProcessingParameterNumber, + QgsProcessingParameterString, + QgsProcessingParameterBoolean, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -37,107 +39,138 @@ class slope(GdalAlgorithm): - INPUT = 'INPUT' - BAND = 'BAND' - AS_PERCENT = 'AS_PERCENT' - SCALE = 'SCALE' - COMPUTE_EDGES = 'COMPUTE_EDGES' - ZEVENBERGEN = 'ZEVENBERGEN' - OPTIONS = 'OPTIONS' - EXTRA = 'EXTRA' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + BAND = "BAND" + AS_PERCENT = "AS_PERCENT" + SCALE = "SCALE" + COMPUTE_EDGES = "COMPUTE_EDGES" + ZEVENBERGEN = "ZEVENBERGEN" + OPTIONS = "OPTIONS" + EXTRA = "EXTRA" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterBand(self.BAND, - self.tr('Band number'), - 1, - parentLayerParameterName=self.INPUT)) - self.addParameter(QgsProcessingParameterNumber(self.SCALE, - self.tr('Ratio of vertical units to horizontal'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=1.0)) - self.addParameter(QgsProcessingParameterBoolean(self.AS_PERCENT, - self.tr('Slope expressed as percent instead of degrees'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.COMPUTE_EDGES, - self.tr('Compute edges'), - defaultValue=False)) - self.addParameter(QgsProcessingParameterBoolean(self.ZEVENBERGEN, - self.tr("Use Zevenbergen&Thorne formula instead of the Horn's one"), - defaultValue=False)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterBand( + self.BAND, + self.tr("Band number"), + 1, + parentLayerParameterName=self.INPUT, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.SCALE, + self.tr("Ratio of vertical units to horizontal"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=1.0, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.AS_PERCENT, + self.tr("Slope expressed as percent instead of degrees"), + defaultValue=False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.COMPUTE_EDGES, self.tr("Compute edges"), defaultValue=False + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.ZEVENBERGEN, + self.tr("Use Zevenbergen&Thorne formula instead of the Horn's one"), + defaultValue=False, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Slope'))) + self.addParameter( + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Slope")) + ) def name(self): - return 'slope' + return "slope" def displayName(self): - return self.tr('Slope') + return self.tr("Slope") def group(self): - return self.tr('Raster analysis') + return self.tr("Raster analysis") def groupId(self): - return 'rasteranalysis' + return "rasteranalysis" def commandName(self): - return 'gdaldem' + return "gdaldem" def getConsoleCommands(self, parameters, context, feedback, executing=True): inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) - input_details = GdalUtils.gdal_connection_details_from_layer( - inLayer) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) + input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, out) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) arguments = [ - 'slope', + "slope", input_details.connection_string, out, - '-of', + "-of", output_format, - '-b', + "-b", str(self.parameterAsInt(parameters, self.BAND, context)), - '-s', + "-s", str(self.parameterAsDouble(parameters, self.SCALE, context)), ] if self.parameterAsBoolean(parameters, self.AS_PERCENT, context): - arguments.append('-p') + arguments.append("-p") if self.parameterAsBoolean(parameters, self.COMPUTE_EDGES, context): - arguments.append('-compute_edges') + arguments.append("-compute_edges") if self.parameterAsBoolean(parameters, self.ZEVENBERGEN, context): - arguments.append('-alg') - arguments.append('ZevenbergenThorne') + arguments.append("-alg") + arguments.append("ZevenbergenThorne") if input_details.credential_options: arguments.extend(input_details.credential_options_as_arguments()) @@ -146,7 +179,7 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) diff --git a/python/plugins/processing/algs/gdal/tpi.py b/python/plugins/processing/algs/gdal/tpi.py index ecd9971da807..77fe1352b33a 100644 --- a/python/plugins/processing/algs/gdal/tpi.py +++ b/python/plugins/processing/algs/gdal/tpi.py @@ -15,19 +15,21 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'October 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "October 2013" +__copyright__ = "(C) 2013, Alexander Bruy" import os -from qgis.core import (QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterBand, - QgsProcessingParameterString, - QgsProcessingParameterBoolean, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBand, + QgsProcessingParameterString, + QgsProcessingParameterBoolean, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -35,68 +37,85 @@ class tpi(GdalAlgorithm): - INPUT = 'INPUT' - BAND = 'BAND' - COMPUTE_EDGES = 'COMPUTE_EDGES' - OPTIONS = 'OPTIONS' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + BAND = "BAND" + COMPUTE_EDGES = "COMPUTE_EDGES" + OPTIONS = "OPTIONS" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterBand(self.BAND, - self.tr('Band number'), - 1, - parentLayerParameterName=self.INPUT)) - self.addParameter(QgsProcessingParameterBoolean(self.COMPUTE_EDGES, - self.tr('Compute edges'), - defaultValue=False)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterBand( + self.BAND, + self.tr("Band number"), + 1, + parentLayerParameterName=self.INPUT, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.COMPUTE_EDGES, self.tr("Compute edges"), defaultValue=False + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Topographic Position Index'))) + self.addParameter( + QgsProcessingParameterRasterDestination( + self.OUTPUT, self.tr("Topographic Position Index") + ) + ) def name(self): - return 'tpitopographicpositionindex' + return "tpitopographicpositionindex" def displayName(self): - return self.tr('Topographic Position Index (TPI)') + return self.tr("Topographic Position Index (TPI)") def group(self): - return self.tr('Raster analysis') + return self.tr("Raster analysis") def groupId(self): - return 'rasteranalysis' + return "rasteranalysis" def commandName(self): - return 'gdaldem' + return "gdaldem" def getConsoleCommands(self, parameters, context, feedback, executing=True): - arguments = ['TPI'] + arguments = ["TPI"] inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) - input_details = GdalUtils.gdal_connection_details_from_layer( - inLayer) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) + input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) arguments.append(input_details.connection_string) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, out) arguments.append(out) - arguments.append('-b') + arguments.append("-b") arguments.append(str(self.parameterAsInt(parameters, self.BAND, context))) if self.parameterAsBoolean(parameters, self.COMPUTE_EDGES, context): - arguments.append('-compute_edges') + arguments.append("-compute_edges") if input_details.credential_options: arguments.extend(input_details.credential_options_as_arguments()) diff --git a/python/plugins/processing/algs/gdal/translate.py b/python/plugins/processing/algs/gdal/translate.py index b07847326dd7..d820daac0862 100644 --- a/python/plugins/processing/algs/gdal/translate.py +++ b/python/plugins/processing/algs/gdal/translate.py @@ -15,24 +15,26 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsRasterFileWriter, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterNumber, - QgsProcessingParameterBoolean, - QgsProcessingParameterString, - QgsProcessingParameterEnum, - QgsProcessingParameterCrs, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterNumber, + QgsProcessingParameterBoolean, + QgsProcessingParameterString, + QgsProcessingParameterEnum, + QgsProcessingParameterCrs, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -40,86 +42,128 @@ class translate(GdalAlgorithm): - INPUT = 'INPUT' - TARGET_CRS = 'TARGET_CRS' - NODATA = 'NODATA' - COPY_SUBDATASETS = 'COPY_SUBDATASETS' - OPTIONS = 'OPTIONS' - EXTRA = 'EXTRA' - DATA_TYPE = 'DATA_TYPE' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + TARGET_CRS = "TARGET_CRS" + NODATA = "NODATA" + COPY_SUBDATASETS = "COPY_SUBDATASETS" + OPTIONS = "OPTIONS" + EXTRA = "EXTRA" + DATA_TYPE = "DATA_TYPE" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.TYPES = [self.tr('Use Input Layer Data Type'), 'Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8'] - - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterCrs(self.TARGET_CRS, - self.tr('Override the projection for the output file'), - defaultValue=None, - optional=True)) - self.addParameter(QgsProcessingParameterNumber(self.NODATA, - self.tr('Assign a specified NoData value to output bands'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=None, - optional=True)) - self.addParameter(QgsProcessingParameterBoolean(self.COPY_SUBDATASETS, - self.tr('Copy all subdatasets of this file to individual output files'), - defaultValue=False)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.TYPES = [ + self.tr("Use Input Layer Data Type"), + "Byte", + "Int16", + "UInt16", + "UInt32", + "Int32", + "Float32", + "Float64", + "CInt16", + "CInt32", + "CFloat32", + "CFloat64", + "Int8", + ] + + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterCrs( + self.TARGET_CRS, + self.tr("Override the projection for the output file"), + defaultValue=None, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.NODATA, + self.tr("Assign a specified NoData value to output bands"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=None, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.COPY_SUBDATASETS, + self.tr("Copy all subdatasets of this file to individual output files"), + defaultValue=False, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE, - self.tr('Output data type'), - self.TYPES, - allowMultiple=False, - defaultValue=0) - dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + dataType_param = QgsProcessingParameterEnum( + self.DATA_TYPE, + self.tr("Output data type"), + self.TYPES, + allowMultiple=False, + defaultValue=0, + ) + dataType_param.setFlags( + dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(dataType_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, - self.tr('Converted'))) + self.addParameter( + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Converted")) + ) def name(self): - return 'translate' + return "translate" def displayName(self): - return self.tr('Translate (convert format)') + return self.tr("Translate (convert format)") def group(self): - return self.tr('Raster conversion') + return self.tr("Raster conversion") def groupId(self): - return 'rasterconversion' + return "rasterconversion" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'translate.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "translate.png")) def commandName(self): - return 'gdal_translate' + return "gdal_translate" def getConsoleCommands(self, parameters, context, feedback, executing=True): inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) - input_details = GdalUtils.gdal_connection_details_from_layer( - inLayer) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) + input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, out) @@ -132,35 +176,37 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): crs = self.parameterAsCrs(parameters, self.TARGET_CRS, context) if crs.isValid(): - arguments.append('-a_srs') + arguments.append("-a_srs") arguments.append(GdalUtils.gdal_crs_string(crs)) if nodata is not None: - arguments.append('-a_nodata') + arguments.append("-a_nodata") arguments.append(nodata) if self.parameterAsBoolean(parameters, self.COPY_SUBDATASETS, context): - arguments.append('-sds') + arguments.append("-sds") data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context) if data_type: - if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later')) + if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000: + raise QgsProcessingException( + self.tr("Int8 data type requires GDAL version 3.7 or later") + ) - arguments.append('-ot ' + self.TYPES[data_type]) + arguments.append("-ot " + self.TYPES[data_type]) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) - arguments.append('-of') + arguments.append("-of") arguments.append(output_format) options = self.parameterAsString(parameters, self.OPTIONS, context) if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) diff --git a/python/plugins/processing/algs/gdal/tri.py b/python/plugins/processing/algs/gdal/tri.py index 0b5a2c94b581..44b29014f9a6 100644 --- a/python/plugins/processing/algs/gdal/tri.py +++ b/python/plugins/processing/algs/gdal/tri.py @@ -15,19 +15,21 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'October 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "October 2013" +__copyright__ = "(C) 2013, Alexander Bruy" import os -from qgis.core import (QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterBand, - QgsProcessingParameterString, - QgsProcessingParameterBoolean, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBand, + QgsProcessingParameterString, + QgsProcessingParameterBoolean, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -35,70 +37,87 @@ class tri(GdalAlgorithm): - INPUT = 'INPUT' - BAND = 'BAND' - COMPUTE_EDGES = 'COMPUTE_EDGES' - OPTIONS = 'OPTIONS' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + BAND = "BAND" + COMPUTE_EDGES = "COMPUTE_EDGES" + OPTIONS = "OPTIONS" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterBand(self.BAND, - self.tr('Band number'), - 1, - parentLayerParameterName=self.INPUT)) - self.addParameter(QgsProcessingParameterBoolean(self.COMPUTE_EDGES, - self.tr('Compute edges'), - defaultValue=False)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterBand( + self.BAND, + self.tr("Band number"), + 1, + parentLayerParameterName=self.INPUT, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.COMPUTE_EDGES, self.tr("Compute edges"), defaultValue=False + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Terrain Ruggedness Index'))) + self.addParameter( + QgsProcessingParameterRasterDestination( + self.OUTPUT, self.tr("Terrain Ruggedness Index") + ) + ) def name(self): - return 'triterrainruggednessindex' + return "triterrainruggednessindex" def displayName(self): - return self.tr('Terrain Ruggedness Index (TRI)') + return self.tr("Terrain Ruggedness Index (TRI)") def group(self): - return self.tr('Raster analysis') + return self.tr("Raster analysis") def groupId(self): - return 'rasteranalysis' + return "rasteranalysis" def commandName(self): - return 'gdaldem' + return "gdaldem" def getConsoleCommands(self, parameters, context, feedback, executing=True): inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) - input_details = GdalUtils.gdal_connection_details_from_layer( - inLayer) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) + input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, out) arguments = [ - 'TRI', + "TRI", input_details.connection_string, out, - '-b', + "-b", str(self.parameterAsInt(parameters, self.BAND, context)), ] if self.parameterAsBoolean(parameters, self.COMPUTE_EDGES, context): - arguments.append('-compute_edges') + arguments.append("-compute_edges") if input_details.credential_options: arguments.extend(input_details.credential_options_as_arguments()) diff --git a/python/plugins/processing/algs/gdal/viewshed.py b/python/plugins/processing/algs/gdal/viewshed.py index 50d0f4e90305..b908cc6bdafd 100644 --- a/python/plugins/processing/algs/gdal/viewshed.py +++ b/python/plugins/processing/algs/gdal/viewshed.py @@ -15,22 +15,24 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'October 2019' -__copyright__ = '(C) 2019, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "October 2019" +__copyright__ = "(C) 2019, Alexander Bruy" import os -from qgis.core import (QgsRasterFileWriter, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterBand, - QgsProcessingParameterPoint, - QgsProcessingParameterNumber, - QgsProcessingParameterDistance, - QgsProcessingParameterString, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBand, + QgsProcessingParameterPoint, + QgsProcessingParameterNumber, + QgsProcessingParameterDistance, + QgsProcessingParameterString, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -38,83 +40,111 @@ class viewshed(GdalAlgorithm): - INPUT = 'INPUT' - BAND = 'BAND' - OBSERVER = 'OBSERVER' - OBSERVER_HEIGHT = 'OBSERVER_HEIGHT' - TARGET_HEIGHT = 'TARGET_HEIGHT' - MAX_DISTANCE = 'MAX_DISTANCE' - OPTIONS = 'OPTIONS' - EXTRA = 'EXTRA' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + BAND = "BAND" + OBSERVER = "OBSERVER" + OBSERVER_HEIGHT = "OBSERVER_HEIGHT" + TARGET_HEIGHT = "TARGET_HEIGHT" + MAX_DISTANCE = "MAX_DISTANCE" + OPTIONS = "OPTIONS" + EXTRA = "EXTRA" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterBand(self.BAND, - self.tr('Band number'), - 1, - parentLayerParameterName=self.INPUT)) - self.addParameter(QgsProcessingParameterPoint(self.OBSERVER, - self.tr('Observer location'))) - self.addParameter(QgsProcessingParameterNumber(self.OBSERVER_HEIGHT, - self.tr('Observer height, DEM units'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=1.0)) - self.addParameter(QgsProcessingParameterNumber(self.TARGET_HEIGHT, - self.tr('Target height, DEM units'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=1.0)) - self.addParameter(QgsProcessingParameterDistance(self.MAX_DISTANCE, - self.tr('Maximum distance from observer to compute visibility'), - parentParameterName=self.INPUT, - minValue=0.0, - defaultValue=100.0)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterBand( + self.BAND, + self.tr("Band number"), + 1, + parentLayerParameterName=self.INPUT, + ) + ) + self.addParameter( + QgsProcessingParameterPoint(self.OBSERVER, self.tr("Observer location")) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.OBSERVER_HEIGHT, + self.tr("Observer height, DEM units"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=1.0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.TARGET_HEIGHT, + self.tr("Target height, DEM units"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=1.0, + ) + ) + self.addParameter( + QgsProcessingParameterDistance( + self.MAX_DISTANCE, + self.tr("Maximum distance from observer to compute visibility"), + parentParameterName=self.INPUT, + minValue=0.0, + defaultValue=100.0, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, - self.tr('Output'))) + self.addParameter( + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Output")) + ) def name(self): - return 'viewshed' + return "viewshed" def displayName(self): - return self.tr('Viewshed') + return self.tr("Viewshed") def group(self): - return self.tr('Raster miscellaneous') + return self.tr("Raster miscellaneous") def groupId(self): - return 'rastermiscellaneous' + return "rastermiscellaneous" def commandName(self): - return 'gdal_viewshed' + return "gdal_viewshed" def getConsoleCommands(self, parameters, context, feedback, executing=True): dem = self.parameterAsRasterLayer(parameters, self.INPUT, context) if dem is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) - dem_input_details = GdalUtils.gdal_connection_details_from_layer( - dem) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) + dem_input_details = GdalUtils.gdal_connection_details_from_layer(dem) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, out) @@ -122,28 +152,27 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): observer = self.parameterAsPoint(parameters, self.OBSERVER, context, dem.crs()) arguments = [ - '-b', - f'{self.parameterAsInt(parameters, self.BAND, context)}', - '-ox', - f'{observer.x()}', - '-oy', - f'{observer.y()}', - '-oz', - f'{self.parameterAsDouble(parameters, self.OBSERVER_HEIGHT, context)}', - '-tz', - f'{self.parameterAsDouble(parameters, self.TARGET_HEIGHT, context)}', - '-md', - f'{self.parameterAsDouble(parameters, self.MAX_DISTANCE, context)}', - - '-f', - QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) + "-b", + f"{self.parameterAsInt(parameters, self.BAND, context)}", + "-ox", + f"{observer.x()}", + "-oy", + f"{observer.y()}", + "-oz", + f"{self.parameterAsDouble(parameters, self.OBSERVER_HEIGHT, context)}", + "-tz", + f"{self.parameterAsDouble(parameters, self.TARGET_HEIGHT, context)}", + "-md", + f"{self.parameterAsDouble(parameters, self.MAX_DISTANCE, context)}", + "-f", + QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]), ] options = self.parameterAsString(parameters, self.OPTIONS, context) if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) diff --git a/python/plugins/processing/algs/gdal/warp.py b/python/plugins/processing/algs/gdal/warp.py index ea9aa16a7551..f1fe96b19928 100644 --- a/python/plugins/processing/algs/gdal/warp.py +++ b/python/plugins/processing/algs/gdal/warp.py @@ -15,25 +15,26 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsRasterFileWriter, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterCrs, - QgsProcessingParameterNumber, - QgsProcessingParameterEnum, - QgsProcessingParameterBoolean, - QgsProcessingParameterExtent, - QgsProcessingParameterString, - QgsProcessingParameterRasterDestination, - ) +from qgis.core import ( + QgsRasterFileWriter, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterCrs, + QgsProcessingParameterNumber, + QgsProcessingParameterEnum, + QgsProcessingParameterBoolean, + QgsProcessingParameterExtent, + QgsProcessingParameterString, + QgsProcessingParameterRasterDestination, +) from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils @@ -42,135 +43,198 @@ class warp(GdalAlgorithm): - INPUT = 'INPUT' - SOURCE_CRS = 'SOURCE_CRS' - TARGET_CRS = 'TARGET_CRS' - NODATA = 'NODATA' - TARGET_RESOLUTION = 'TARGET_RESOLUTION' - OPTIONS = 'OPTIONS' - RESAMPLING = 'RESAMPLING' - DATA_TYPE = 'DATA_TYPE' - TARGET_EXTENT = 'TARGET_EXTENT' - TARGET_EXTENT_CRS = 'TARGET_EXTENT_CRS' - MULTITHREADING = 'MULTITHREADING' - EXTRA = 'EXTRA' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + SOURCE_CRS = "SOURCE_CRS" + TARGET_CRS = "TARGET_CRS" + NODATA = "NODATA" + TARGET_RESOLUTION = "TARGET_RESOLUTION" + OPTIONS = "OPTIONS" + RESAMPLING = "RESAMPLING" + DATA_TYPE = "DATA_TYPE" + TARGET_EXTENT = "TARGET_EXTENT" + TARGET_EXTENT_CRS = "TARGET_EXTENT_CRS" + MULTITHREADING = "MULTITHREADING" + EXTRA = "EXTRA" + OUTPUT = "OUTPUT" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.methods = ((self.tr('Nearest Neighbour'), 'near'), - (self.tr('Bilinear (2x2 Kernel)'), 'bilinear'), - (self.tr('Cubic (4x4 Kernel)'), 'cubic'), - (self.tr('Cubic B-Spline (4x4 Kernel)'), 'cubicspline'), - (self.tr('Lanczos (6x6 Kernel)'), 'lanczos'), - (self.tr('Average'), 'average'), - (self.tr('Mode'), 'mode'), - (self.tr('Maximum'), 'max'), - (self.tr('Minimum'), 'min'), - (self.tr('Median'), 'med'), - (self.tr('First Quartile (Q1)'), 'q1'), - (self.tr('Third Quartile (Q3)'), 'q3')) - - self.TYPES = [self.tr('Use Input Layer Data Type'), 'Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64', 'Int8'] - - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterCrs(self.SOURCE_CRS, - self.tr('Source CRS'), - optional=True)) - self.addParameter(QgsProcessingParameterCrs(self.TARGET_CRS, - self.tr('Target CRS'), - optional=True)) - self.addParameter(QgsProcessingParameterEnum(self.RESAMPLING, - self.tr('Resampling method to use'), - options=[i[0] for i in self.methods], - defaultValue=0)) - self.addParameter(QgsProcessingParameterNumber(self.NODATA, - self.tr('Nodata value for output bands'), - type=QgsProcessingParameterNumber.Type.Double, - defaultValue=None, - optional=True)) - self.addParameter(QgsProcessingParameterNumber(self.TARGET_RESOLUTION, - self.tr('Output file resolution in target georeferenced units'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, - defaultValue=None, - optional=True)) - - options_param = QgsProcessingParameterString(self.OPTIONS, - self.tr('Additional creation options'), - defaultValue='', - optional=True) - options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) - options_param.setMetadata({'widget_wrapper': {'widget_type': 'rasteroptions'}}) + self.methods = ( + (self.tr("Nearest Neighbour"), "near"), + (self.tr("Bilinear (2x2 Kernel)"), "bilinear"), + (self.tr("Cubic (4x4 Kernel)"), "cubic"), + (self.tr("Cubic B-Spline (4x4 Kernel)"), "cubicspline"), + (self.tr("Lanczos (6x6 Kernel)"), "lanczos"), + (self.tr("Average"), "average"), + (self.tr("Mode"), "mode"), + (self.tr("Maximum"), "max"), + (self.tr("Minimum"), "min"), + (self.tr("Median"), "med"), + (self.tr("First Quartile (Q1)"), "q1"), + (self.tr("Third Quartile (Q3)"), "q3"), + ) + + self.TYPES = [ + self.tr("Use Input Layer Data Type"), + "Byte", + "Int16", + "UInt16", + "UInt32", + "Int32", + "Float32", + "Float64", + "CInt16", + "CInt32", + "CFloat32", + "CFloat64", + "Int8", + ] + + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterCrs( + self.SOURCE_CRS, self.tr("Source CRS"), optional=True + ) + ) + self.addParameter( + QgsProcessingParameterCrs( + self.TARGET_CRS, self.tr("Target CRS"), optional=True + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.RESAMPLING, + self.tr("Resampling method to use"), + options=[i[0] for i in self.methods], + defaultValue=0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.NODATA, + self.tr("Nodata value for output bands"), + type=QgsProcessingParameterNumber.Type.Double, + defaultValue=None, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.TARGET_RESOLUTION, + self.tr("Output file resolution in target georeferenced units"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=None, + optional=True, + ) + ) + + options_param = QgsProcessingParameterString( + self.OPTIONS, + self.tr("Additional creation options"), + defaultValue="", + optional=True, + ) + options_param.setFlags( + options_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) + options_param.setMetadata({"widget_wrapper": {"widget_type": "rasteroptions"}}) self.addParameter(options_param) - dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE, - self.tr('Output data type'), - self.TYPES, - allowMultiple=False, - defaultValue=0) - dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + dataType_param = QgsProcessingParameterEnum( + self.DATA_TYPE, + self.tr("Output data type"), + self.TYPES, + allowMultiple=False, + defaultValue=0, + ) + dataType_param.setFlags( + dataType_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(dataType_param) - target_extent_param = QgsProcessingParameterExtent(self.TARGET_EXTENT, - self.tr('Georeferenced extents of output file to be created'), - optional=True) - target_extent_param.setFlags(target_extent_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + target_extent_param = QgsProcessingParameterExtent( + self.TARGET_EXTENT, + self.tr("Georeferenced extents of output file to be created"), + optional=True, + ) + target_extent_param.setFlags( + target_extent_param.flags() + | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(target_extent_param) - target_extent_crs_param = QgsProcessingParameterCrs(self.TARGET_EXTENT_CRS, - self.tr('CRS of the target raster extent'), - optional=True) - target_extent_crs_param.setFlags(target_extent_crs_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + target_extent_crs_param = QgsProcessingParameterCrs( + self.TARGET_EXTENT_CRS, + self.tr("CRS of the target raster extent"), + optional=True, + ) + target_extent_crs_param.setFlags( + target_extent_crs_param.flags() + | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(target_extent_crs_param) - multithreading_param = QgsProcessingParameterBoolean(self.MULTITHREADING, - self.tr('Use multithreaded warping implementation'), - defaultValue=False) - multithreading_param.setFlags(multithreading_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + multithreading_param = QgsProcessingParameterBoolean( + self.MULTITHREADING, + self.tr("Use multithreaded warping implementation"), + defaultValue=False, + ) + multithreading_param.setFlags( + multithreading_param.flags() + | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(multithreading_param) - extra_param = QgsProcessingParameterString(self.EXTRA, - self.tr('Additional command-line parameters'), - defaultValue=None, - optional=True) - extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + extra_param = QgsProcessingParameterString( + self.EXTRA, + self.tr("Additional command-line parameters"), + defaultValue=None, + optional=True, + ) + extra_param.setFlags( + extra_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(extra_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, - self.tr('Reprojected'))) + self.addParameter( + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Reprojected")) + ) def name(self): - return 'warpreproject' + return "warpreproject" def displayName(self): - return self.tr('Warp (reproject)') + return self.tr("Warp (reproject)") def group(self): - return self.tr('Raster projections') + return self.tr("Raster projections") def groupId(self): - return 'rasterprojections' + return "rasterprojections" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'warp.png')) + return QIcon(os.path.join(pluginPath, "images", "gdaltools", "warp.png")) def commandName(self): - return 'gdalwarp' + return "gdalwarp" def tags(self): - tags = self.tr('transform,reproject,crs,srs,resample').split(',') + tags = self.tr("transform,reproject,crs,srs,resample").split(",") tags.extend(super().tags()) return tags def getConsoleCommands(self, parameters, context, feedback, executing=True): inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context) if inLayer is None: - raise QgsProcessingException(self.invalidRasterError(parameters, self.INPUT)) - input_details = GdalUtils.gdal_connection_details_from_layer( - inLayer) + raise QgsProcessingException( + self.invalidRasterError(parameters, self.INPUT) + ) + input_details = GdalUtils.gdal_connection_details_from_layer(inLayer) sourceCrs = self.parameterAsCrs(parameters, self.SOURCE_CRS, context) targetCrs = self.parameterAsCrs(parameters, self.TARGET_CRS, context) @@ -180,30 +244,32 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): nodata = None resolution = self.parameterAsDouble(parameters, self.TARGET_RESOLUTION, context) - arguments = ['-overwrite'] + arguments = ["-overwrite"] if sourceCrs.isValid(): - arguments.append('-s_srs') + arguments.append("-s_srs") arguments.append(GdalUtils.gdal_crs_string(sourceCrs)) if targetCrs.isValid(): - arguments.append('-t_srs') + arguments.append("-t_srs") arguments.append(GdalUtils.gdal_crs_string(targetCrs)) if nodata is not None: - arguments.append('-dstnodata') + arguments.append("-dstnodata") arguments.append(str(nodata)) if resolution: - arguments.append('-tr') + arguments.append("-tr") arguments.append(str(resolution)) arguments.append(str(resolution)) - arguments.append('-r') - arguments.append(self.methods[self.parameterAsEnum(parameters, self.RESAMPLING, context)][1]) + arguments.append("-r") + arguments.append( + self.methods[self.parameterAsEnum(parameters, self.RESAMPLING, context)][1] + ) extent = self.parameterAsExtent(parameters, self.TARGET_EXTENT, context) if not extent.isNull(): - arguments.append('-te') + arguments.append("-te") arguments.append(extent.xMinimum()) arguments.append(extent.yMinimum()) arguments.append(extent.xMaximum()) @@ -211,34 +277,36 @@ def getConsoleCommands(self, parameters, context, feedback, executing=True): extentCrs = self.parameterAsCrs(parameters, self.TARGET_EXTENT_CRS, context) if extentCrs.isValid(): - arguments.append('-te_srs') + arguments.append("-te_srs") arguments.append(GdalUtils.gdal_crs_string(extentCrs)) if self.parameterAsBoolean(parameters, self.MULTITHREADING, context): - arguments.append('-multi') + arguments.append("-multi") data_type = self.parameterAsEnum(parameters, self.DATA_TYPE, context) if data_type: - if self.TYPES[data_type] == 'Int8' and GdalUtils.version() < 3070000: - raise QgsProcessingException(self.tr('Int8 data type requires GDAL version 3.7 or later')) + if self.TYPES[data_type] == "Int8" and GdalUtils.version() < 3070000: + raise QgsProcessingException( + self.tr("Int8 data type requires GDAL version 3.7 or later") + ) - arguments.append('-ot ' + self.TYPES[data_type]) + arguments.append("-ot " + self.TYPES[data_type]) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) self.setOutputValue(self.OUTPUT, out) output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]) if not output_format: - raise QgsProcessingException(self.tr('Output format is invalid')) + raise QgsProcessingException(self.tr("Output format is invalid")) - arguments.append('-of') + arguments.append("-of") arguments.append(output_format) options = self.parameterAsString(parameters, self.OPTIONS, context) if options: arguments.extend(GdalUtils.parseCreationOptions(options)) - if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''): + if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ""): extra = self.parameterAsString(parameters, self.EXTRA, context) arguments.append(extra) diff --git a/python/plugins/processing/algs/help/__init__.py b/python/plugins/processing/algs/help/__init__.py index 3e6cd60eaec4..b2001ff4bad7 100644 --- a/python/plugins/processing/algs/help/__init__.py +++ b/python/plugins/processing/algs/help/__init__.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'January 2016' -__copyright__ = '(C) 2016, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "January 2016" +__copyright__ = "(C) 2016, Victor Olaya" import os import codecs @@ -37,25 +37,29 @@ def loadShortHelp(): for f in os.listdir(path): if f.endswith("yaml"): filename = os.path.join(path, f) - with codecs.open(filename, encoding='utf-8') as stream: + with codecs.open(filename, encoding="utf-8") as stream: with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) for k, v in yaml.load(stream, Loader=yaml.SafeLoader).items(): if v is None: continue - h[k] = QCoreApplication.translate(f"{f[:-5].upper()}Algorithm", v) + h[k] = QCoreApplication.translate( + f"{f[:-5].upper()}Algorithm", v + ) version = ".".join(Qgis.QGIS_VERSION.split(".")[0:2]) - overrideLocale = QgsSettings().value('locale/overrideFlag', False, bool) + overrideLocale = QgsSettings().value("locale/overrideFlag", False, bool) if not overrideLocale: locale = QLocale.system().name()[:2] else: - locale = QgsSettings().value('locale/userLocale', '') + locale = QgsSettings().value("locale/userLocale", "") locale = locale.split("_")[0] def replace(s): if s is not None: - return s.replace("{qgisdocs}", f"https://docs.qgis.org/{version}/{locale}/docs") + return s.replace( + "{qgisdocs}", f"https://docs.qgis.org/{version}/{locale}/docs" + ) else: return None diff --git a/python/plugins/processing/algs/qgis/BarPlot.py b/python/plugins/processing/algs/qgis/BarPlot.py index f17162870da9..bc2985839d91 100644 --- a/python/plugins/processing/algs/qgis/BarPlot.py +++ b/python/plugins/processing/algs/qgis/BarPlot.py @@ -15,18 +15,20 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'January 2013' -__copyright__ = '(C) 2013, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "January 2013" +__copyright__ = "(C) 2013, Victor Olaya" import warnings -from qgis.core import (QgsFeatureRequest, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterField, - QgsProcessingException, - QgsProcessingParameterFileDestination, - QgsProcessingParameterString,) +from qgis.core import ( + QgsFeatureRequest, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingException, + QgsProcessingParameterFileDestination, + QgsProcessingParameterString, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.tools import vector @@ -34,55 +36,73 @@ class BarPlot(QgisAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' - NAME_FIELD = 'NAME_FIELD' - VALUE_FIELD = 'VALUE_FIELD' - TITLE = 'TITLE' + INPUT = "INPUT" + OUTPUT = "OUTPUT" + NAME_FIELD = "NAME_FIELD" + VALUE_FIELD = "VALUE_FIELD" + TITLE = "TITLE" XAXIS_TITLE = "XAXIS_TITLE" YAXIS_TITLE = "YAXIS_TITLE" def group(self): - return self.tr('Plots') + return self.tr("Plots") def groupId(self): - return 'plots' + return "plots" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterField(self.NAME_FIELD, - self.tr('Category name field'), - None, self.INPUT, QgsProcessingParameterField.DataType.Any)) - self.addParameter(QgsProcessingParameterField(self.VALUE_FIELD, - self.tr('Value field'), - None, self.INPUT, QgsProcessingParameterField.DataType.Numeric)) - - self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, self.tr('Bar plot'), self.tr('HTML files (*.html)'))) - - self.addParameter(QgsProcessingParameterString( - self.TITLE, - self.tr('Title'), - optional=True)) - - self.addParameter(QgsProcessingParameterString( - self.XAXIS_TITLE, - self.tr('X-axis title'), - optional=True)) - - self.addParameter(QgsProcessingParameterString( - self.YAXIS_TITLE, - self.tr('Y-axis title'), - optional=True)) + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterField( + self.NAME_FIELD, + self.tr("Category name field"), + None, + self.INPUT, + QgsProcessingParameterField.DataType.Any, + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.VALUE_FIELD, + self.tr("Value field"), + None, + self.INPUT, + QgsProcessingParameterField.DataType.Numeric, + ) + ) + + self.addParameter( + QgsProcessingParameterFileDestination( + self.OUTPUT, self.tr("Bar plot"), self.tr("HTML files (*.html)") + ) + ) + + self.addParameter( + QgsProcessingParameterString(self.TITLE, self.tr("Title"), optional=True) + ) + + self.addParameter( + QgsProcessingParameterString( + self.XAXIS_TITLE, self.tr("X-axis title"), optional=True + ) + ) + + self.addParameter( + QgsProcessingParameterString( + self.YAXIS_TITLE, self.tr("Y-axis title"), optional=True + ) + ) def name(self): - return 'barplot' + return "barplot" def displayName(self): - return self.tr('Bar plot') + return self.tr("Bar plot") def processAlgorithm(self, parameters, context, feedback): try: @@ -93,11 +113,18 @@ def processAlgorithm(self, parameters, context, feedback): import plotly as plt import plotly.graph_objs as go except ImportError: - raise QgsProcessingException(QCoreApplication.translate('BarPlot', 'This algorithm requires the Python “plotly” library. Please install this library and try again.')) + raise QgsProcessingException( + QCoreApplication.translate( + "BarPlot", + "This algorithm requires the Python “plotly” library. Please install this library and try again.", + ) + ) source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) namefieldname = self.parameterAsString(parameters, self.NAME_FIELD, context) valuefieldname = self.parameterAsString(parameters, self.VALUE_FIELD, context) @@ -121,16 +148,24 @@ def processAlgorithm(self, parameters, context, feedback): values = vector.values(source, valuefieldname) - x_var = vector.convert_nulls([i[namefieldname] for i in source.getFeatures(QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry))], '') + x_var = vector.convert_nulls( + [ + i[namefieldname] + for i in source.getFeatures( + QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry) + ) + ], + "", + ) - data = [go.Bar(x=x_var, - y=values[valuefieldname])] + data = [go.Bar(x=x_var, y=values[valuefieldname])] fig = go.Figure( data=data, layout_title_text=title, layout_xaxis_title=xaxis_title, - layout_yaxis_title=yaxis_title) + layout_yaxis_title=yaxis_title, + ) fig.write_html(output) diff --git a/python/plugins/processing/algs/qgis/BoxPlot.py b/python/plugins/processing/algs/qgis/BoxPlot.py index 55d2d5ba7b7e..ff31b05bcda0 100644 --- a/python/plugins/processing/algs/qgis/BoxPlot.py +++ b/python/plugins/processing/algs/qgis/BoxPlot.py @@ -15,19 +15,21 @@ *************************************************************************** """ -__author__ = 'Matteo Ghetta' -__date__ = 'March 2017' -__copyright__ = '(C) 2017, Matteo Ghetta' +__author__ = "Matteo Ghetta" +__date__ = "March 2017" +__copyright__ = "(C) 2017, Matteo Ghetta" import warnings -from qgis.core import (QgsProcessingException, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterField, - QgsProcessingParameterEnum, - QgsProcessingParameterFileDestination, - QgsFeatureRequest, - QgsProcessingParameterString) +from qgis.core import ( + QgsProcessingException, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingParameterEnum, + QgsProcessingParameterFileDestination, + QgsFeatureRequest, + QgsProcessingParameterString, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.tools import vector @@ -35,66 +37,85 @@ class BoxPlot(QgisAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' - NAME_FIELD = 'NAME_FIELD' - VALUE_FIELD = 'VALUE_FIELD' - MSD = 'MSD' - TITLE = 'TITLE' + INPUT = "INPUT" + OUTPUT = "OUTPUT" + NAME_FIELD = "NAME_FIELD" + VALUE_FIELD = "VALUE_FIELD" + MSD = "MSD" + TITLE = "TITLE" XAXIS_TITLE = "XAXIS_TITLE" YAXIS_TITLE = "YAXIS_TITLE" def group(self): - return self.tr('Plots') + return self.tr("Plots") def groupId(self): - return 'plots' + return "plots" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterField(self.NAME_FIELD, - self.tr('Category name field'), - parentLayerParameterName=self.INPUT, - type=QgsProcessingParameterField.DataType.Any)) - self.addParameter(QgsProcessingParameterField(self.VALUE_FIELD, - self.tr('Value field'), - parentLayerParameterName=self.INPUT, - type=QgsProcessingParameterField.DataType.Numeric)) - msd = [self.tr('Show Mean'), - self.tr('Show Standard Deviation'), - self.tr('Don\'t show Mean and Standard Deviation') - ] - self.addParameter(QgsProcessingParameterEnum( - self.MSD, - self.tr('Additional Statistic Lines'), - options=msd, defaultValue=0)) - - self.addParameter(QgsProcessingParameterString( - self.TITLE, - self.tr('Title'), - optional=True)) - - self.addParameter(QgsProcessingParameterString( - self.XAXIS_TITLE, - self.tr('X-axis title'), - optional=True)) - - self.addParameter(QgsProcessingParameterString( - self.YAXIS_TITLE, - self.tr('Y-axis title'), - optional=True)) - - self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, self.tr('Box plot'), self.tr('HTML files (*.html)'))) + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterField( + self.NAME_FIELD, + self.tr("Category name field"), + parentLayerParameterName=self.INPUT, + type=QgsProcessingParameterField.DataType.Any, + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.VALUE_FIELD, + self.tr("Value field"), + parentLayerParameterName=self.INPUT, + type=QgsProcessingParameterField.DataType.Numeric, + ) + ) + msd = [ + self.tr("Show Mean"), + self.tr("Show Standard Deviation"), + self.tr("Don't show Mean and Standard Deviation"), + ] + self.addParameter( + QgsProcessingParameterEnum( + self.MSD, + self.tr("Additional Statistic Lines"), + options=msd, + defaultValue=0, + ) + ) + + self.addParameter( + QgsProcessingParameterString(self.TITLE, self.tr("Title"), optional=True) + ) + + self.addParameter( + QgsProcessingParameterString( + self.XAXIS_TITLE, self.tr("X-axis title"), optional=True + ) + ) + + self.addParameter( + QgsProcessingParameterString( + self.YAXIS_TITLE, self.tr("Y-axis title"), optional=True + ) + ) + + self.addParameter( + QgsProcessingParameterFileDestination( + self.OUTPUT, self.tr("Box plot"), self.tr("HTML files (*.html)") + ) + ) def name(self): - return 'boxplot' + return "boxplot" def displayName(self): - return self.tr('Box plot') + return self.tr("Box plot") def processAlgorithm(self, parameters, context, feedback): try: @@ -105,11 +126,18 @@ def processAlgorithm(self, parameters, context, feedback): import plotly as plt import plotly.graph_objs as go except ImportError: - raise QgsProcessingException(QCoreApplication.translate('BoxPlot', 'This algorithm requires the Python “plotly” library. Please install this library and try again.')) + raise QgsProcessingException( + QCoreApplication.translate( + "BoxPlot", + "This algorithm requires the Python “plotly” library. Please install this library and try again.", + ) + ) source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) namefieldname = self.parameterAsString(parameters, self.NAME_FIELD, context) valuefieldname = self.parameterAsString(parameters, self.VALUE_FIELD, context) @@ -134,26 +162,34 @@ def processAlgorithm(self, parameters, context, feedback): values = vector.values(source, valuefieldname) x_index = source.fields().lookupField(namefieldname) - x_var = vector.convert_nulls([i[namefieldname] for i in source.getFeatures(QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry).setSubsetOfAttributes([x_index]))], '') + x_var = vector.convert_nulls( + [ + i[namefieldname] + for i in source.getFeatures( + QgsFeatureRequest() + .setFlags(QgsFeatureRequest.Flag.NoGeometry) + .setSubsetOfAttributes([x_index]) + ) + ], + "", + ) msdIndex = self.parameterAsEnum(parameters, self.MSD, context) msd = True if msdIndex == 1: - msd = 'sd' + msd = "sd" elif msdIndex == 2: msd = False - data = [go.Box( - x=x_var, - y=values[valuefieldname], - boxmean=msd)] + data = [go.Box(x=x_var, y=values[valuefieldname], boxmean=msd)] fig = go.Figure( data=data, layout_title_text=title, layout_xaxis_title=xaxis_title, - layout_yaxis_title=yaxis_title) + layout_yaxis_title=yaxis_title, + ) fig.write_html(output) diff --git a/python/plugins/processing/algs/qgis/Buffer.py b/python/plugins/processing/algs/qgis/Buffer.py index 80e5f352f3fb..8ae866643040 100644 --- a/python/plugins/processing/algs/qgis/Buffer.py +++ b/python/plugins/processing/algs/qgis/Buffer.py @@ -15,19 +15,27 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" -from qgis.core import (Qgis, - QgsFeature, - QgsGeometry, - QgsFeatureRequest, - QgsFeatureSink) +from qgis.core import Qgis, QgsFeature, QgsGeometry, QgsFeatureRequest, QgsFeatureSink -def buffering(feedback, context, sink, distance, field, useField, source, dissolve, segments, endCapStyle=1, - joinStyle=1, miterLimit=2): +def buffering( + feedback, + context, + sink, + distance, + field, + useField, + source, + dissolve, + segments, + endCapStyle=1, + joinStyle=1, + miterLimit=2, +): if useField: field = source.fields().lookupField(field) @@ -42,7 +50,9 @@ def buffering(feedback, context, sink, distance, field, useField, source, dissol if useField: attributes_to_fetch.append(field) - features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes(attributes_to_fetch)) + features = source.getFeatures( + QgsFeatureRequest().setSubsetOfAttributes(attributes_to_fetch) + ) buffered_geometries = [] for inFeat in features: if feedback.isCanceled(): @@ -56,7 +66,15 @@ def buffering(feedback, context, sink, distance, field, useField, source, dissol inGeom = inFeat.geometry() - buffered_geometries.append(inGeom.buffer(float(value), segments, Qgis.EndCapStyle(endCapStyle), Qgis.JoinStyle(joinStyle), miterLimit)) + buffered_geometries.append( + inGeom.buffer( + float(value), + segments, + Qgis.EndCapStyle(endCapStyle), + Qgis.JoinStyle(joinStyle), + miterLimit, + ) + ) current += 1 feedback.setProgress(int(current * total)) @@ -80,7 +98,13 @@ def buffering(feedback, context, sink, distance, field, useField, source, dissol value = distance inGeom = inFeat.geometry() outFeat = QgsFeature() - outGeom = inGeom.buffer(float(value), segments, Qgis.EndCapStyle(endCapStyle), Qgis.JoinStyle(joinStyle), miterLimit) + outGeom = inGeom.buffer( + float(value), + segments, + Qgis.EndCapStyle(endCapStyle), + Qgis.JoinStyle(joinStyle), + miterLimit, + ) outFeat.setGeometry(outGeom) outFeat.setAttributes(attrs) sink.addFeature(outFeat, QgsFeatureSink.Flag.FastInsert) diff --git a/python/plugins/processing/algs/qgis/CheckValidity.py b/python/plugins/processing/algs/qgis/CheckValidity.py index 013daabef381..27f6c0439301 100644 --- a/python/plugins/processing/algs/qgis/CheckValidity.py +++ b/python/plugins/processing/algs/qgis/CheckValidity.py @@ -15,33 +15,35 @@ *************************************************************************** """ -__author__ = 'Arnaud Morvan' -__date__ = 'May 2015' -__copyright__ = '(C) 2015, Arnaud Morvan' +__author__ = "Arnaud Morvan" +__date__ = "May 2015" +__copyright__ = "(C) 2015, Arnaud Morvan" import os from qgis.PyQt.QtGui import QIcon from qgis.PyQt.QtCore import QMetaType -from qgis.core import (Qgis, - QgsApplication, - QgsSettings, - QgsGeometry, - QgsFeature, - QgsField, - QgsFeatureRequest, - QgsFeatureSink, - QgsWkbTypes, - QgsFields, - QgsProcessing, - QgsProcessingException, - QgsProcessingFeatureSource, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterEnum, - QgsProcessingParameterFeatureSink, - QgsProcessingOutputNumber, - QgsProcessingParameterBoolean) +from qgis.core import ( + Qgis, + QgsApplication, + QgsSettings, + QgsGeometry, + QgsFeature, + QgsField, + QgsFeatureRequest, + QgsFeatureSink, + QgsWkbTypes, + QgsFields, + QgsProcessing, + QgsProcessingException, + QgsProcessingFeatureSource, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterEnum, + QgsProcessingParameterFeatureSink, + QgsProcessingOutputNumber, + QgsProcessingParameterBoolean, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm settings_method_key = "/digitizing/validate-geometries" @@ -49,15 +51,15 @@ class CheckValidity(QgisAlgorithm): - INPUT_LAYER = 'INPUT_LAYER' - METHOD = 'METHOD' - VALID_OUTPUT = 'VALID_OUTPUT' - VALID_COUNT = 'VALID_COUNT' - INVALID_OUTPUT = 'INVALID_OUTPUT' - INVALID_COUNT = 'INVALID_COUNT' - ERROR_OUTPUT = 'ERROR_OUTPUT' - ERROR_COUNT = 'ERROR_COUNT' - IGNORE_RING_SELF_INTERSECTION = 'IGNORE_RING_SELF_INTERSECTION' + INPUT_LAYER = "INPUT_LAYER" + METHOD = "METHOD" + VALID_OUTPUT = "VALID_OUTPUT" + VALID_COUNT = "VALID_COUNT" + INVALID_OUTPUT = "INVALID_OUTPUT" + INVALID_COUNT = "INVALID_COUNT" + ERROR_OUTPUT = "ERROR_OUTPUT" + ERROR_COUNT = "ERROR_COUNT" + IGNORE_RING_SELF_INTERSECTION = "IGNORE_RING_SELF_INTERSECTION" def icon(self): return QgsApplication.getThemeIcon("/algorithms/mAlgorithmCheckGeometry.svg") @@ -66,51 +68,99 @@ def svgIconPath(self): return QgsApplication.iconPath("/algorithms/mAlgorithmCheckGeometry.svg") def group(self): - return self.tr('Vector geometry') + return self.tr("Vector geometry") def groupId(self): - return 'vectorgeometry' + return "vectorgeometry" def tags(self): - return self.tr('valid,invalid,detect,error').split(',') + return self.tr("valid,invalid,detect,error").split(",") def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.methods = [self.tr('The one selected in digitizing settings'), - 'QGIS', - 'GEOS'] - - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterEnum(self.METHOD, - self.tr('Method'), self.methods, defaultValue=2)) - self.parameterDefinition(self.METHOD).setMetadata({ - 'widget_wrapper': { - 'useCheckBoxes': True, - 'columns': 3}}) + self.methods = [ + self.tr("The one selected in digitizing settings"), + "QGIS", + "GEOS", + ] + + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT_LAYER, self.tr("Input layer") + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.METHOD, self.tr("Method"), self.methods, defaultValue=2 + ) + ) + self.parameterDefinition(self.METHOD).setMetadata( + {"widget_wrapper": {"useCheckBoxes": True, "columns": 3}} + ) - self.addParameter(QgsProcessingParameterBoolean(self.IGNORE_RING_SELF_INTERSECTION, - self.tr('Ignore ring self intersections'), defaultValue=False)) + self.addParameter( + QgsProcessingParameterBoolean( + self.IGNORE_RING_SELF_INTERSECTION, + self.tr("Ignore ring self intersections"), + defaultValue=False, + ) + ) - self.addParameter(QgsProcessingParameterFeatureSink(self.VALID_OUTPUT, self.tr('Valid output'), QgsProcessing.SourceType.TypeVectorAnyGeometry, None, True)) - self.addOutput(QgsProcessingOutputNumber(self.VALID_COUNT, self.tr('Count of valid features'))) + self.addParameter( + QgsProcessingParameterFeatureSink( + self.VALID_OUTPUT, + self.tr("Valid output"), + QgsProcessing.SourceType.TypeVectorAnyGeometry, + None, + True, + ) + ) + self.addOutput( + QgsProcessingOutputNumber( + self.VALID_COUNT, self.tr("Count of valid features") + ) + ) - self.addParameter(QgsProcessingParameterFeatureSink(self.INVALID_OUTPUT, self.tr('Invalid output'), QgsProcessing.SourceType.TypeVectorAnyGeometry, None, True)) - self.addOutput(QgsProcessingOutputNumber(self.INVALID_COUNT, self.tr('Count of invalid features'))) + self.addParameter( + QgsProcessingParameterFeatureSink( + self.INVALID_OUTPUT, + self.tr("Invalid output"), + QgsProcessing.SourceType.TypeVectorAnyGeometry, + None, + True, + ) + ) + self.addOutput( + QgsProcessingOutputNumber( + self.INVALID_COUNT, self.tr("Count of invalid features") + ) + ) - self.addParameter(QgsProcessingParameterFeatureSink(self.ERROR_OUTPUT, self.tr('Error output'), QgsProcessing.SourceType.TypeVectorAnyGeometry, None, True)) - self.addOutput(QgsProcessingOutputNumber(self.ERROR_COUNT, self.tr('Count of errors'))) + self.addParameter( + QgsProcessingParameterFeatureSink( + self.ERROR_OUTPUT, + self.tr("Error output"), + QgsProcessing.SourceType.TypeVectorAnyGeometry, + None, + True, + ) + ) + self.addOutput( + QgsProcessingOutputNumber(self.ERROR_COUNT, self.tr("Count of errors")) + ) def name(self): - return 'checkvalidity' + return "checkvalidity" def displayName(self): - return self.tr('Check validity') + return self.tr("Check validity") def processAlgorithm(self, parameters, context, feedback): - ignore_ring_self_intersection = self.parameterAsBoolean(parameters, self.IGNORE_RING_SELF_INTERSECTION, context) + ignore_ring_self_intersection = self.parameterAsBoolean( + parameters, self.IGNORE_RING_SELF_INTERSECTION, context + ) method_param = self.parameterAsEnum(parameters, self.METHOD, context) if method_param == 0: settings = QgsSettings() @@ -123,29 +173,60 @@ def processAlgorithm(self, parameters, context, feedback): method, parameters, context, feedback, ignore_ring_self_intersection ) - def doCheck(self, method, parameters, context, feedback, ignore_ring_self_intersection): - flags = QgsGeometry.ValidityFlag.FlagAllowSelfTouchingHoles if ignore_ring_self_intersection else QgsGeometry.ValidityFlags() + def doCheck( + self, method, parameters, context, feedback, ignore_ring_self_intersection + ): + flags = ( + QgsGeometry.ValidityFlag.FlagAllowSelfTouchingHoles + if ignore_ring_self_intersection + else QgsGeometry.ValidityFlags() + ) source = self.parameterAsSource(parameters, self.INPUT_LAYER, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT_LAYER)) - - (valid_output_sink, valid_output_dest_id) = self.parameterAsSink(parameters, self.VALID_OUTPUT, context, - source.fields(), source.wkbType(), source.sourceCrs()) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT_LAYER) + ) + + (valid_output_sink, valid_output_dest_id) = self.parameterAsSink( + parameters, + self.VALID_OUTPUT, + context, + source.fields(), + source.wkbType(), + source.sourceCrs(), + ) valid_count = 0 invalid_fields = source.fields() - invalid_fields.append(QgsField('_errors', QMetaType.Type.QString, 'string', 255)) - (invalid_output_sink, invalid_output_dest_id) = self.parameterAsSink(parameters, self.INVALID_OUTPUT, context, - invalid_fields, source.wkbType(), source.sourceCrs()) + invalid_fields.append( + QgsField("_errors", QMetaType.Type.QString, "string", 255) + ) + (invalid_output_sink, invalid_output_dest_id) = self.parameterAsSink( + parameters, + self.INVALID_OUTPUT, + context, + invalid_fields, + source.wkbType(), + source.sourceCrs(), + ) invalid_count = 0 error_fields = QgsFields() - error_fields.append(QgsField('message', QMetaType.Type.QString, 'string', 255)) - (error_output_sink, error_output_dest_id) = self.parameterAsSink(parameters, self.ERROR_OUTPUT, context, - error_fields, QgsWkbTypes.Type.Point, source.sourceCrs()) + error_fields.append(QgsField("message", QMetaType.Type.QString, "string", 255)) + (error_output_sink, error_output_dest_id) = self.parameterAsSink( + parameters, + self.ERROR_OUTPUT, + context, + error_fields, + QgsWkbTypes.Type.Point, + source.sourceCrs(), + ) error_count = 0 - features = source.getFeatures(QgsFeatureRequest(), QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks) + features = source.getFeatures( + QgsFeatureRequest(), + QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks, + ) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, inFeat in enumerate(features): if feedback.isCanceled(): @@ -155,7 +236,9 @@ def doCheck(self, method, parameters, context, feedback, ignore_ring_self_inters valid = True if not geom.isNull() and not geom.isEmpty(): - errors = list(geom.validateGeometry(Qgis.GeometryValidationEngine(method), flags)) + errors = list( + geom.validateGeometry(Qgis.GeometryValidationEngine(method), flags) + ) if errors: valid = False reasons = [] @@ -165,14 +248,16 @@ def doCheck(self, method, parameters, context, feedback, ignore_ring_self_inters errFeat.setGeometry(error_geom) errFeat.setAttributes([error.what()]) if error_output_sink: - error_output_sink.addFeature(errFeat, QgsFeatureSink.Flag.FastInsert) + error_output_sink.addFeature( + errFeat, QgsFeatureSink.Flag.FastInsert + ) error_count += 1 reasons.append(error.what()) reason = "\n".join(reasons) if len(reason) > 255: - reason = reason[:252] + '…' + reason = reason[:252] + "…" attrs.append(reason) outFeat = QgsFeature() @@ -181,12 +266,16 @@ def doCheck(self, method, parameters, context, feedback, ignore_ring_self_inters if valid: if valid_output_sink: - valid_output_sink.addFeature(outFeat, QgsFeatureSink.Flag.FastInsert) + valid_output_sink.addFeature( + outFeat, QgsFeatureSink.Flag.FastInsert + ) valid_count += 1 else: if invalid_output_sink: - invalid_output_sink.addFeature(outFeat, QgsFeatureSink.Flag.FastInsert) + invalid_output_sink.addFeature( + outFeat, QgsFeatureSink.Flag.FastInsert + ) invalid_count += 1 feedback.setProgress(int(current * total)) @@ -194,7 +283,7 @@ def doCheck(self, method, parameters, context, feedback, ignore_ring_self_inters results = { self.VALID_COUNT: valid_count, self.INVALID_COUNT: invalid_count, - self.ERROR_COUNT: error_count + self.ERROR_COUNT: error_count, } if valid_output_sink: valid_output_sink.finalize() diff --git a/python/plugins/processing/algs/qgis/Climb.py b/python/plugins/processing/algs/qgis/Climb.py index 219ea184b36c..cc5efaa48489 100644 --- a/python/plugins/processing/algs/qgis/Climb.py +++ b/python/plugins/processing/algs/qgis/Climb.py @@ -16,9 +16,9 @@ ***************************************************************************/ """ -__author__ = 'Håvard Tveite' -__date__ = '2019-03-01' -__copyright__ = '(C) 2019 by Håvard Tveite' +__author__ = "Håvard Tveite" +__date__ = "2019-03-01" +__copyright__ = "(C) 2019 by Håvard Tveite" import os import math @@ -26,45 +26,47 @@ from qgis.PyQt.QtGui import QIcon from qgis.PyQt.QtCore import QMetaType -from qgis.core import (QgsProcessing, - QgsFeatureSink, - QgsProcessingAlgorithm, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, - QgsProcessingOutputNumber, - QgsProcessingException, - QgsProcessingUtils, - QgsWkbTypes, - QgsFields, - QgsField) +from qgis.core import ( + QgsProcessing, + QgsFeatureSink, + QgsProcessingAlgorithm, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterFeatureSink, + QgsProcessingOutputNumber, + QgsProcessingException, + QgsProcessingUtils, + QgsWkbTypes, + QgsFields, + QgsField, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm class Climb(QgisAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' - - TOTALCLIMB = 'TOTALCLIMB' - TOTALDESCENT = 'TOTALDESCENT' - MINELEVATION = 'MINELEVATION' - MAXELEVATION = 'MAXELEVATION' - CLIMBATTRIBUTE = 'climb' - DESCENTATTRIBUTE = 'descent' - MINELEVATTRIBUTE = 'minelev' - MAXELEVATTRIBUTE = 'maxelev' + INPUT = "INPUT" + OUTPUT = "OUTPUT" + + TOTALCLIMB = "TOTALCLIMB" + TOTALDESCENT = "TOTALDESCENT" + MINELEVATION = "MINELEVATION" + MAXELEVATION = "MAXELEVATION" + CLIMBATTRIBUTE = "climb" + DESCENTATTRIBUTE = "descent" + MINELEVATTRIBUTE = "minelev" + MAXELEVATTRIBUTE = "maxelev" def name(self): - return 'climbalongline' + return "climbalongline" def displayName(self): - return self.tr('Climb along line') + return self.tr("Climb along line") def group(self): - return self.tr('Vector analysis') + return self.tr("Vector analysis") def groupId(self): - return 'vectoranalysis' + return "vectoranalysis" def __init__(self): super().__init__() @@ -73,53 +75,34 @@ def initAlgorithm(self, config=None): self.addParameter( QgsProcessingParameterFeatureSource( self.INPUT, - self.tr('Line layer'), - [QgsProcessing.SourceType.TypeVectorLine] + self.tr("Line layer"), + [QgsProcessing.SourceType.TypeVectorLine], ) ) self.addParameter( - QgsProcessingParameterFeatureSink( - self.OUTPUT, - self.tr('Climb layer') - ) + QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr("Climb layer")) ) self.addOutput( - QgsProcessingOutputNumber( - self.TOTALCLIMB, - self.tr('Total climb') - ) + QgsProcessingOutputNumber(self.TOTALCLIMB, self.tr("Total climb")) ) self.addOutput( - QgsProcessingOutputNumber( - self.TOTALDESCENT, - self.tr('Total descent') - ) + QgsProcessingOutputNumber(self.TOTALDESCENT, self.tr("Total descent")) ) self.addOutput( - QgsProcessingOutputNumber( - self.MINELEVATION, - self.tr('Minimum elevation') - ) + QgsProcessingOutputNumber(self.MINELEVATION, self.tr("Minimum elevation")) ) self.addOutput( - QgsProcessingOutputNumber( - self.MAXELEVATION, - self.tr('Maximum elevation') - ) + QgsProcessingOutputNumber(self.MAXELEVATION, self.tr("Maximum elevation")) ) def processAlgorithm(self, parameters, context, feedback): - source = self.parameterAsSource( - parameters, - self.INPUT, - context - ) + source = self.parameterAsSource(parameters, self.INPUT, context) fcount = source.featureCount() source_fields = source.fields() @@ -127,7 +110,11 @@ def processAlgorithm(self, parameters, context, feedback): hasZ = QgsWkbTypes.hasZ(source.wkbType()) if not hasZ: - raise QgsProcessingException(self.tr('The layer does not have Z values. If you have a DEM, use the Drape algorithm to extract Z values.')) + raise QgsProcessingException( + self.tr( + "The layer does not have Z values. If you have a DEM, use the Drape algorithm to extract Z values." + ) + ) thefields = QgsFields() climbindex = -1 @@ -147,19 +134,21 @@ def processAlgorithm(self, parameters, context, feedback): layerwithz = source - (sink, dest_id) = self.parameterAsSink(parameters, - self.OUTPUT, - context, - out_fields, - layerwithz.wkbType(), - source.sourceCrs()) + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + out_fields, + layerwithz.wkbType(), + source.sourceCrs(), + ) # get features from source (with z values) features = layerwithz.getFeatures() totalclimb = 0 totaldescent = 0 - minelevation = float('Infinity') - maxelevation = float('-Infinity') + minelevation = float("Infinity") + maxelevation = float("-Infinity") no_z_nodes = [] no_geometry = [] @@ -169,16 +158,12 @@ def processAlgorithm(self, parameters, context, feedback): break climb = 0 descent = 0 - minelev = float('Infinity') - maxelev = float('-Infinity') + minelev = float("Infinity") + maxelev = float("-Infinity") # In case of multigeometries we need to do the parts parts = feature.geometry().constParts() if not feature.hasGeometry(): - no_geometry.append(self.tr( - 'Feature: {feature_id}'.format( - feature_id=feature.id()) - ) - ) + no_geometry.append(self.tr(f"Feature: {feature.id()}")) for partnumber, part in enumerate(parts): # Calculate the climb first = True @@ -186,12 +171,14 @@ def processAlgorithm(self, parameters, context, feedback): for idx, v in enumerate(part.vertices()): zval = v.z() if math.isnan(zval): - no_z_nodes.append(self.tr( - 'Feature: {feature_id}, part: {part_id}, point: {point_id}'.format( - feature_id=feature.id(), - part_id=partnumber, - point_id=idx) - ) + no_z_nodes.append( + self.tr( + "Feature: {feature_id}, part: {part_id}, point: {point_id}".format( + feature_id=feature.id(), + part_id=partnumber, + point_id=idx, + ) + ) ) continue if first: @@ -212,13 +199,7 @@ def processAlgorithm(self, parameters, context, feedback): totaldescent += descent # Set the attribute values # Append the attributes to the end of the existing ones - attrs = [ - climb, - descent, - minelev, - maxelev, - *feature.attributes() - ] + attrs = [climb, descent, minelev, maxelev, *feature.attributes()] # Set the final attribute list feature.setAttributes(attrs) # Add a feature to the sink @@ -229,22 +210,29 @@ def processAlgorithm(self, parameters, context, feedback): if fcount > 0: feedback.setProgress(int(100 * current / fcount)) - feedback.pushInfo(self.tr( - 'The following features do not have geometry: {no_geometry_report}'.format( - no_geometry_report=(', '.join(no_geometry))) - ) + feedback.pushInfo( + self.tr( + "The following features do not have geometry: {no_geometry_report}".format( + no_geometry_report=(", ".join(no_geometry)) + ) + ) ) - feedback.pushInfo(self.tr( - 'The following points do not have Z values: {no_z_report}'.format( - no_z_report=(', '.join(no_z_nodes))) - ) + feedback.pushInfo( + self.tr( + "The following points do not have Z values: {no_z_report}".format( + no_z_report=(", ".join(no_z_nodes)) + ) + ) ) sink.finalize() # Return the results - return {self.OUTPUT: dest_id, self.TOTALCLIMB: totalclimb, - self.TOTALDESCENT: totaldescent, - self.MINELEVATION: minelevation, - self.MAXELEVATION: maxelevation} + return { + self.OUTPUT: dest_id, + self.TOTALCLIMB: totalclimb, + self.TOTALDESCENT: totaldescent, + self.MINELEVATION: minelevation, + self.MAXELEVATION: maxelevation, + } diff --git a/python/plugins/processing/algs/qgis/DefineProjection.py b/python/plugins/processing/algs/qgis/DefineProjection.py index 473eb3a4be51..5b1db6673b50 100644 --- a/python/plugins/processing/algs/qgis/DefineProjection.py +++ b/python/plugins/processing/algs/qgis/DefineProjection.py @@ -15,20 +15,22 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'January 2016' -__copyright__ = '(C) 2016, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "January 2016" +__copyright__ = "(C) 2016, Alexander Bruy" import os import re -from qgis.core import (QgsProcessing, - QgsProcessingAlgorithm, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterCrs, - QgsProcessingOutputVectorLayer, - QgsCoordinateReferenceSystem, - QgsProjUtils) +from qgis.core import ( + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterCrs, + QgsProcessingOutputVectorLayer, + QgsCoordinateReferenceSystem, + QgsProjUtils, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm @@ -36,36 +38,44 @@ class DefineProjection(QgisAlgorithm): - INPUT = 'INPUT' - CRS = 'CRS' + INPUT = "INPUT" + CRS = "CRS" def group(self): - return self.tr('Vector general') + return self.tr("Vector general") def groupId(self): - return 'vectorgeneral' + return "vectorgeneral" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT, - self.tr('Input Shapefile'), types=[QgsProcessing.SourceType.TypeVectorAnyGeometry])) - self.addParameter(QgsProcessingParameterCrs(self.CRS, 'CRS', 'EPSG:4326')) - self.addOutput(QgsProcessingOutputVectorLayer(self.INPUT, - self.tr('Layer with projection'))) + self.addParameter( + QgsProcessingParameterVectorLayer( + self.INPUT, + self.tr("Input Shapefile"), + types=[QgsProcessing.SourceType.TypeVectorAnyGeometry], + ) + ) + self.addParameter(QgsProcessingParameterCrs(self.CRS, "CRS", "EPSG:4326")) + self.addOutput( + QgsProcessingOutputVectorLayer(self.INPUT, self.tr("Layer with projection")) + ) def name(self): - return 'definecurrentprojection' + return "definecurrentprojection" def displayName(self): - return self.tr('Define Shapefile projection') + return self.tr("Define Shapefile projection") def tags(self): - return self.tr('layer,shp,prj,qpj,change,alter').split(',') + return self.tr("layer,shp,prj,qpj,change,alter").split(",") def shortDescription(self): - return self.tr('Changes a Shapefile\'s projection to a new CRS without reprojecting features') + return self.tr( + "Changes a Shapefile's projection to a new CRS without reprojecting features" + ) def flags(self): return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading @@ -76,21 +86,23 @@ def processAlgorithm(self, parameters, context, feedback): provider = layer.dataProvider() ds = provider.dataSourceUri() - p = re.compile(r'\|.*') - dsPath = p.sub('', ds) + p = re.compile(r"\|.*") + dsPath = p.sub("", ds) - if dsPath.lower().endswith('.shp'): + if dsPath.lower().endswith(".shp"): dsPath = dsPath[:-4] wkt = crs.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT1_ESRI) - with open(dsPath + '.prj', 'w', encoding='utf-8') as f: + with open(dsPath + ".prj", "w", encoding="utf-8") as f: f.write(wkt) - qpjFile = dsPath + '.qpj' + qpjFile = dsPath + ".qpj" if os.path.exists(qpjFile): os.remove(qpjFile) else: - feedback.pushConsoleInfo(self.tr("Data source isn't a Shapefile, skipping .prj/.qpj creation")) + feedback.pushConsoleInfo( + self.tr("Data source isn't a Shapefile, skipping .prj/.qpj creation") + ) layer.setCrs(crs) layer.triggerRepaint() diff --git a/python/plugins/processing/algs/qgis/EliminateSelection.py b/python/plugins/processing/algs/qgis/EliminateSelection.py index 71ee00554684..c0d7031ae16c 100644 --- a/python/plugins/processing/algs/qgis/EliminateSelection.py +++ b/python/plugins/processing/algs/qgis/EliminateSelection.py @@ -15,26 +15,28 @@ *************************************************************************** """ -__author__ = 'Bernhard Ströbl' -__date__ = 'January 2017' -__copyright__ = '(C) 2017, Bernhard Ströbl' +__author__ = "Bernhard Ströbl" +__date__ = "January 2017" +__copyright__ = "(C) 2017, Bernhard Ströbl" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsApplication, - QgsFeatureRequest, - QgsFeature, - QgsFeatureSink, - QgsGeometry, - QgsProcessingAlgorithm, - QgsProcessingException, - QgsProcessingUtils, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterEnum, - QgsProcessing, - QgsProcessingParameterFeatureSink) +from qgis.core import ( + QgsApplication, + QgsFeatureRequest, + QgsFeature, + QgsFeatureSink, + QgsGeometry, + QgsProcessingAlgorithm, + QgsProcessingException, + QgsProcessingUtils, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterEnum, + QgsProcessing, + QgsProcessingParameterFeatureSink, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm @@ -42,9 +44,9 @@ class EliminateSelection(QgisAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' - MODE = 'MODE' + INPUT = "INPUT" + OUTPUT = "OUTPUT" + MODE = "MODE" MODE_LARGEST_AREA = 0 MODE_SMALLEST_AREA = 1 @@ -57,49 +59,85 @@ def svgIconPath(self): return QgsApplication.iconPath("/algorithms/mAlgorithmDissolve.svg") def group(self): - return self.tr('Vector geometry') + return self.tr("Vector geometry") def groupId(self): - return 'vectorgeometry' + return "vectorgeometry" def __init__(self): super().__init__() def flags(self): - return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool + return ( + super().flags() + | QgsProcessingAlgorithm.Flag.FlagNoThreading + | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool + ) def initAlgorithm(self, config=None): - self.modes = [self.tr('Largest Area'), - self.tr('Smallest Area'), - self.tr('Largest Common Boundary')] - - self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT, - self.tr('Input layer'), [QgsProcessing.SourceType.TypeVectorPolygon])) - self.addParameter(QgsProcessingParameterEnum(self.MODE, - self.tr('Merge selection with the neighbouring polygon with the'), - options=self.modes)) - - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Eliminated'), QgsProcessing.SourceType.TypeVectorPolygon)) + self.modes = [ + self.tr("Largest Area"), + self.tr("Smallest Area"), + self.tr("Largest Common Boundary"), + ] + + self.addParameter( + QgsProcessingParameterVectorLayer( + self.INPUT, + self.tr("Input layer"), + [QgsProcessing.SourceType.TypeVectorPolygon], + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.MODE, + self.tr("Merge selection with the neighbouring polygon with the"), + options=self.modes, + ) + ) + + self.addParameter( + QgsProcessingParameterFeatureSink( + self.OUTPUT, + self.tr("Eliminated"), + QgsProcessing.SourceType.TypeVectorPolygon, + ) + ) def name(self): - return 'eliminateselectedpolygons' + return "eliminateselectedpolygons" def displayName(self): - return self.tr('Eliminate selected polygons') + return self.tr("Eliminate selected polygons") def processAlgorithm(self, parameters, context, feedback): inLayer = self.parameterAsVectorLayer(parameters, self.INPUT, context) - boundary = self.parameterAsEnum(parameters, self.MODE, context) == self.MODE_BOUNDARY - smallestArea = self.parameterAsEnum(parameters, self.MODE, context) == self.MODE_SMALLEST_AREA + boundary = ( + self.parameterAsEnum(parameters, self.MODE, context) == self.MODE_BOUNDARY + ) + smallestArea = ( + self.parameterAsEnum(parameters, self.MODE, context) + == self.MODE_SMALLEST_AREA + ) if inLayer.selectedFeatureCount() == 0: - feedback.reportError(self.tr('{0}: (No selection in input layer "{1}")').format(self.displayName(), parameters[self.INPUT])) + feedback.reportError( + self.tr('{0}: (No selection in input layer "{1}")').format( + self.displayName(), parameters[self.INPUT] + ) + ) featToEliminate = [] selFeatIds = inLayer.selectedFeatureIds() - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - inLayer.fields(), inLayer.wkbType(), inLayer.sourceCrs()) + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + inLayer.fields(), + inLayer.wkbType(), + inLayer.sourceCrs(), + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) @@ -147,7 +185,8 @@ def processAlgorithm(self, parameters, context, feedback): geom2Eliminate = feat.geometry() bbox = geom2Eliminate.boundingBox() fit = processLayer.getFeatures( - QgsFeatureRequest().setFilterRect(bbox).setSubsetOfAttributes([])) + QgsFeatureRequest().setFilterRect(bbox).setSubsetOfAttributes([]) + ) mergeWithFid = None mergeWithGeom = None max = 0 @@ -211,7 +250,10 @@ def processAlgorithm(self, parameters, context, feedback): madeProgress = True else: raise QgsProcessingException( - self.tr('Could not replace geometry of feature with id {0}').format(mergeWithFid)) + self.tr( + "Could not replace geometry of feature with id {0}" + ).format(mergeWithFid) + ) start = start + add feedback.setProgress(start) @@ -224,12 +266,14 @@ def processAlgorithm(self, parameters, context, feedback): # End while if not processLayer.commitChanges(): - raise QgsProcessingException(self.tr('Could not commit changes')) + raise QgsProcessingException(self.tr("Could not commit changes")) for feature in featNotEliminated: if feedback.isCanceled(): break - processLayer.dataProvider().addFeature(feature, QgsFeatureSink.Flag.FastInsert) + processLayer.dataProvider().addFeature( + feature, QgsFeatureSink.Flag.FastInsert + ) return {self.OUTPUT: dest_id} diff --git a/python/plugins/processing/algs/qgis/ExecuteSQL.py b/python/plugins/processing/algs/qgis/ExecuteSQL.py index 4fb42ba62269..c4e353d15b40 100644 --- a/python/plugins/processing/algs/qgis/ExecuteSQL.py +++ b/python/plugins/processing/algs/qgis/ExecuteSQL.py @@ -15,115 +15,149 @@ *************************************************************************** """ -__author__ = 'Hugo Mercier' -__date__ = 'January 2016' -__copyright__ = '(C) 2016, Hugo Mercier' - -from qgis.core import (Qgis, - QgsVirtualLayerDefinition, - QgsVectorLayer, - QgsWkbTypes, - QgsProcessingAlgorithm, - QgsProcessingParameterMultipleLayers, - QgsProcessingParameterDefinition, - QgsExpression, - QgsProcessingUtils, - QgsProcessingParameterString, - QgsProcessingParameterEnum, - QgsProcessingParameterCrs, - QgsProcessingParameterFeatureSink, - QgsFeatureSink, - QgsProcessingException, - QgsVectorFileWriter, - QgsProject) +__author__ = "Hugo Mercier" +__date__ = "January 2016" +__copyright__ = "(C) 2016, Hugo Mercier" + +from qgis.core import ( + Qgis, + QgsVirtualLayerDefinition, + QgsVectorLayer, + QgsWkbTypes, + QgsProcessingAlgorithm, + QgsProcessingParameterMultipleLayers, + QgsProcessingParameterDefinition, + QgsExpression, + QgsProcessingUtils, + QgsProcessingParameterString, + QgsProcessingParameterEnum, + QgsProcessingParameterCrs, + QgsProcessingParameterFeatureSink, + QgsFeatureSink, + QgsProcessingException, + QgsVectorFileWriter, + QgsProject, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm class ParameterExecuteSql(QgsProcessingParameterDefinition): - def __init__(self, name='', description=''): + def __init__(self, name="", description=""): super().__init__(name, description) - self.setMetadata({ - 'widget_wrapper': 'processing.algs.qgis.ui.ExecuteSQLWidget.ExecuteSQLWidgetWrapper' - }) + self.setMetadata( + { + "widget_wrapper": "processing.algs.qgis.ui.ExecuteSQLWidget.ExecuteSQLWidgetWrapper" + } + ) def type(self): - return 'execute_sql' + return "execute_sql" def clone(self): return ParameterExecuteSql(self.name(), self.description()) class ExecuteSQL(QgisAlgorithm): - """ This algorithm allows executing an SQL query on a set of input + """This algorithm allows executing an SQL query on a set of input vector layers thanks to the virtual layer provider """ - INPUT_DATASOURCES = 'INPUT_DATASOURCES' - INPUT_QUERY = 'INPUT_QUERY' - INPUT_UID_FIELD = 'INPUT_UID_FIELD' - INPUT_GEOMETRY_FIELD = 'INPUT_GEOMETRY_FIELD' - INPUT_GEOMETRY_TYPE = 'INPUT_GEOMETRY_TYPE' - INPUT_GEOMETRY_CRS = 'INPUT_GEOMETRY_CRS' - OUTPUT = 'OUTPUT' + INPUT_DATASOURCES = "INPUT_DATASOURCES" + INPUT_QUERY = "INPUT_QUERY" + INPUT_UID_FIELD = "INPUT_UID_FIELD" + INPUT_GEOMETRY_FIELD = "INPUT_GEOMETRY_FIELD" + INPUT_GEOMETRY_TYPE = "INPUT_GEOMETRY_TYPE" + INPUT_GEOMETRY_CRS = "INPUT_GEOMETRY_CRS" + OUTPUT = "OUTPUT" def group(self): - return self.tr('Vector general') + return self.tr("Vector general") def groupId(self): - return 'vectorgeneral' + return "vectorgeneral" def __init__(self): super().__init__() self.geometry_types = [ - (None, self.tr('Autodetect')), - (Qgis.WkbType.NoGeometry, self.tr('No geometry')), - (Qgis.WkbType.Point, self.tr('Point')), - (Qgis.WkbType.LineString, self.tr('LineString')), - (Qgis.WkbType.Polygon, self.tr('Polygon')), - (Qgis.WkbType.MultiPoint, self.tr('MultiPoint')), - (Qgis.WkbType.MultiLineString, self.tr('MultiLineString')), - (Qgis.WkbType.MultiPolygon, self.tr('MultiPolygon'))] + (None, self.tr("Autodetect")), + (Qgis.WkbType.NoGeometry, self.tr("No geometry")), + (Qgis.WkbType.Point, self.tr("Point")), + (Qgis.WkbType.LineString, self.tr("LineString")), + (Qgis.WkbType.Polygon, self.tr("Polygon")), + (Qgis.WkbType.MultiPoint, self.tr("MultiPoint")), + (Qgis.WkbType.MultiLineString, self.tr("MultiLineString")), + (Qgis.WkbType.MultiPolygon, self.tr("MultiPolygon")), + ] def flags(self): return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterMultipleLayers(name=self.INPUT_DATASOURCES, - description=self.tr('Input data sources (called input1, .., inputN in the query)'), - optional=True)) - - self.addParameter(ParameterExecuteSql(name=self.INPUT_QUERY, description=self.tr('SQL query'))) - - self.addParameter(QgsProcessingParameterString(name=self.INPUT_UID_FIELD, - description=self.tr('Unique identifier field'), optional=True)) - - self.addParameter(QgsProcessingParameterString(name=self.INPUT_GEOMETRY_FIELD, - description=self.tr('Geometry field'), optional=True)) - - self.addParameter(QgsProcessingParameterEnum(self.INPUT_GEOMETRY_TYPE, - self.tr('Geometry type'), - options=[t[1] for t in self.geometry_types], - defaultValue=0)) - - self.addParameter(QgsProcessingParameterCrs(self.INPUT_GEOMETRY_CRS, - self.tr('CRS'), optional=True)) - - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('SQL Output'))) + self.addParameter( + QgsProcessingParameterMultipleLayers( + name=self.INPUT_DATASOURCES, + description=self.tr( + "Input data sources (called input1, .., inputN in the query)" + ), + optional=True, + ) + ) + + self.addParameter( + ParameterExecuteSql(name=self.INPUT_QUERY, description=self.tr("SQL query")) + ) + + self.addParameter( + QgsProcessingParameterString( + name=self.INPUT_UID_FIELD, + description=self.tr("Unique identifier field"), + optional=True, + ) + ) + + self.addParameter( + QgsProcessingParameterString( + name=self.INPUT_GEOMETRY_FIELD, + description=self.tr("Geometry field"), + optional=True, + ) + ) + + self.addParameter( + QgsProcessingParameterEnum( + self.INPUT_GEOMETRY_TYPE, + self.tr("Geometry type"), + options=[t[1] for t in self.geometry_types], + defaultValue=0, + ) + ) + + self.addParameter( + QgsProcessingParameterCrs( + self.INPUT_GEOMETRY_CRS, self.tr("CRS"), optional=True + ) + ) + + self.addParameter( + QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr("SQL Output")) + ) def name(self): - return 'executesql' + return "executesql" def displayName(self): - return self.tr('Execute SQL') + return self.tr("Execute SQL") def processAlgorithm(self, parameters, context, feedback): layers = self.parameterAsLayerList(parameters, self.INPUT_DATASOURCES, context) query = self.parameterAsString(parameters, self.INPUT_QUERY, context) uid_field = self.parameterAsString(parameters, self.INPUT_UID_FIELD, context) - geometry_field = self.parameterAsString(parameters, self.INPUT_GEOMETRY_FIELD, context) + geometry_field = self.parameterAsString( + parameters, self.INPUT_GEOMETRY_FIELD, context + ) geometry_type = self.geometry_types[ self.parameterAsEnum(parameters, self.INPUT_GEOMETRY_TYPE, context) ][0] @@ -138,17 +172,21 @@ def processAlgorithm(self, parameters, context, feedback): # belongs to temporary QgsMapLayerStore, not project. # So, we write them to disk is this is the case. if context.project() and not context.project().mapLayer(layer.id()): - basename = "memorylayer." + QgsVectorFileWriter.supportedFormatExtensions()[0] + basename = ( + "memorylayer." + QgsVectorFileWriter.supportedFormatExtensions()[0] + ) tmp_path = QgsProcessingUtils.generateTempFilename(basename, context) QgsVectorFileWriter.writeAsVectorFormat( - layer, tmp_path, layer.dataProvider().encoding()) - df.addSource(f'input{layerIdx + 1}', tmp_path, "ogr") + layer, tmp_path, layer.dataProvider().encoding() + ) + df.addSource(f"input{layerIdx + 1}", tmp_path, "ogr") else: - df.addSource(f'input{layerIdx + 1}', layer.id()) + df.addSource(f"input{layerIdx + 1}", layer.id()) - if query == '': + if query == "": raise QgsProcessingException( - self.tr('Empty SQL. Please enter valid SQL expression and try again.')) + self.tr("Empty SQL. Please enter valid SQL expression and try again.") + ) localContext = self.createExpressionContext(parameters, context) expandedQuery = QgsExpression.replaceExpressionText(query, localContext) df.setQuery(expandedQuery) @@ -173,12 +211,14 @@ def processAlgorithm(self, parameters, context, feedback): if vLayer.wkbType() == QgsWkbTypes.Type.Unknown: raise QgsProcessingException(self.tr("Cannot find geometry field")) - (sink, dest_id) = self.parameterAsSink(parameters, - self.OUTPUT, - context, - vLayer.fields(), - vLayer.wkbType(), - vLayer.crs()) + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + vLayer.fields(), + vLayer.wkbType(), + vLayer.crs(), + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) diff --git a/python/plugins/processing/algs/qgis/ExportGeometryInfo.py b/python/plugins/processing/algs/qgis/ExportGeometryInfo.py index 33d0c25c6b95..fe84aaffcdc5 100644 --- a/python/plugins/processing/algs/qgis/ExportGeometryInfo.py +++ b/python/plugins/processing/algs/qgis/ExportGeometryInfo.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import math @@ -25,22 +25,24 @@ from qgis.PyQt.QtGui import QIcon from qgis.PyQt.QtCore import QMetaType -from qgis.core import (NULL, - Qgis, - QgsApplication, - QgsCoordinateTransform, - QgsField, - QgsFields, - QgsWkbTypes, - QgsPointXY, - QgsFeatureSink, - QgsDistanceArea, - QgsProcessingUtils, - QgsProcessingException, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterEnum, - QgsProcessingParameterFeatureSink, - QgsUnitTypes) +from qgis.core import ( + NULL, + Qgis, + QgsApplication, + QgsCoordinateTransform, + QgsField, + QgsFields, + QgsWkbTypes, + QgsPointXY, + QgsFeatureSink, + QgsDistanceArea, + QgsProcessingUtils, + QgsProcessingException, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterEnum, + QgsProcessingParameterFeatureSink, + QgsUnitTypes, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm @@ -48,24 +50,30 @@ class ExportGeometryInfo(QgisAlgorithm): - INPUT = 'INPUT' - METHOD = 'CALC_METHOD' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + METHOD = "CALC_METHOD" + OUTPUT = "OUTPUT" def icon(self): - return QgsApplication.getThemeIcon("/algorithms/mAlgorithmAddGeometryAttributes.svg") + return QgsApplication.getThemeIcon( + "/algorithms/mAlgorithmAddGeometryAttributes.svg" + ) def svgIconPath(self): - return QgsApplication.iconPath("/algorithms/mAlgorithmAddGeometryAttributes.svg") + return QgsApplication.iconPath( + "/algorithms/mAlgorithmAddGeometryAttributes.svg" + ) def tags(self): - return self.tr('export,add,information,measurements,areas,lengths,perimeters,latitudes,longitudes,x,y,z,extract,points,lines,polygons,sinuosity,fields').split(',') + return self.tr( + "export,add,information,measurements,areas,lengths,perimeters,latitudes,longitudes,x,y,z,extract,points,lines,polygons,sinuosity,fields" + ).split(",") def group(self): - return self.tr('Vector geometry') + return self.tr("Vector geometry") def groupId(self): - return 'vectorgeometry' + return "vectorgeometry" def __init__(self): super().__init__() @@ -74,27 +82,40 @@ def __init__(self): self.distance_area = None self.distance_conversion_factor = 1 self.area_conversion_factor = 1 - self.calc_methods = [self.tr('Layer CRS'), - self.tr('Project CRS'), - self.tr('Ellipsoidal')] + self.calc_methods = [ + self.tr("Layer CRS"), + self.tr("Project CRS"), + self.tr("Ellipsoidal"), + ] def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterEnum(self.METHOD, - self.tr('Calculate using'), options=self.calc_methods, defaultValue=0)) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Added geom info'))) + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.METHOD, + self.tr("Calculate using"), + options=self.calc_methods, + defaultValue=0, + ) + ) + self.addParameter( + QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr("Added geom info")) + ) def name(self): - return 'exportaddgeometrycolumns' + return "exportaddgeometrycolumns" def displayName(self): - return self.tr('Add geometry attributes') + return self.tr("Add geometry attributes") def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) method = self.parameterAsEnum(parameters, self.METHOD, context) @@ -102,30 +123,36 @@ def processAlgorithm(self, parameters, context, feedback): fields = source.fields() new_fields = QgsFields() - if QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.GeometryType.PolygonGeometry: - new_fields.append(QgsField('area', QMetaType.Type.Double)) - new_fields.append(QgsField('perimeter', QMetaType.Type.Double)) - elif QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.GeometryType.LineGeometry: - new_fields.append(QgsField('length', QMetaType.Type.Double)) + if ( + QgsWkbTypes.geometryType(wkb_type) + == QgsWkbTypes.GeometryType.PolygonGeometry + ): + new_fields.append(QgsField("area", QMetaType.Type.Double)) + new_fields.append(QgsField("perimeter", QMetaType.Type.Double)) + elif ( + QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.GeometryType.LineGeometry + ): + new_fields.append(QgsField("length", QMetaType.Type.Double)) if not QgsWkbTypes.isMultiType(source.wkbType()): - new_fields.append(QgsField('straightdis', QMetaType.Type.Double)) - new_fields.append(QgsField('sinuosity', QMetaType.Type.Double)) + new_fields.append(QgsField("straightdis", QMetaType.Type.Double)) + new_fields.append(QgsField("sinuosity", QMetaType.Type.Double)) else: if QgsWkbTypes.isMultiType(source.wkbType()): - new_fields.append(QgsField('numparts', QMetaType.Type.Int)) + new_fields.append(QgsField("numparts", QMetaType.Type.Int)) else: - new_fields.append(QgsField('xcoord', QMetaType.Type.Double)) - new_fields.append(QgsField('ycoord', QMetaType.Type.Double)) + new_fields.append(QgsField("xcoord", QMetaType.Type.Double)) + new_fields.append(QgsField("ycoord", QMetaType.Type.Double)) if QgsWkbTypes.hasZ(source.wkbType()): self.export_z = True - new_fields.append(QgsField('zcoord', QMetaType.Type.Double)) + new_fields.append(QgsField("zcoord", QMetaType.Type.Double)) if QgsWkbTypes.hasM(source.wkbType()): self.export_m = True - new_fields.append(QgsField('mvalue', QMetaType.Type.Double)) + new_fields.append(QgsField("mvalue", QMetaType.Type.Double)) fields = QgsProcessingUtils.combineFields(fields, new_fields) - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, wkb_type, source.sourceCrs()) + (sink, dest_id) = self.parameterAsSink( + parameters, self.OUTPUT, context, fields, wkb_type, source.sourceCrs() + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) @@ -138,19 +165,27 @@ def processAlgorithm(self, parameters, context, feedback): self.distance_area = QgsDistanceArea() if method == 2: - self.distance_area.setSourceCrs(source.sourceCrs(), context.transformContext()) + self.distance_area.setSourceCrs( + source.sourceCrs(), context.transformContext() + ) self.distance_area.setEllipsoid(context.ellipsoid()) - self.distance_conversion_factor = QgsUnitTypes.fromUnitToUnitFactor(self.distance_area.lengthUnits(), - context.distanceUnit()) + self.distance_conversion_factor = QgsUnitTypes.fromUnitToUnitFactor( + self.distance_area.lengthUnits(), context.distanceUnit() + ) - self.area_conversion_factor = QgsUnitTypes.fromUnitToUnitFactor(self.distance_area.areaUnits(), - context.areaUnit()) + self.area_conversion_factor = QgsUnitTypes.fromUnitToUnitFactor( + self.distance_area.areaUnits(), context.areaUnit() + ) elif method == 1: if not context.project(): - raise QgsProcessingException(self.tr('No project is available in this context')) - coordTransform = QgsCoordinateTransform(source.sourceCrs(), context.project().crs(), context.project()) + raise QgsProcessingException( + self.tr("No project is available in this context") + ) + coordTransform = QgsCoordinateTransform( + source.sourceCrs(), context.project().crs(), context.project() + ) features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 @@ -208,13 +243,24 @@ def line_attributes(self, geometry): curve = geometry.constGet() p1 = curve.startPoint() p2 = curve.endPoint() - straight_distance = self.distance_conversion_factor * self.distance_area.measureLine(QgsPointXY(p1), QgsPointXY(p2)) + straight_distance = ( + self.distance_conversion_factor + * self.distance_area.measureLine(QgsPointXY(p1), QgsPointXY(p2)) + ) sinuosity = curve.sinuosity() if math.isnan(sinuosity): sinuosity = NULL - return [self.distance_conversion_factor * self.distance_area.measureLength(geometry), straight_distance, sinuosity] + return [ + self.distance_conversion_factor + * self.distance_area.measureLength(geometry), + straight_distance, + sinuosity, + ] def polygon_attributes(self, geometry): area = self.area_conversion_factor * self.distance_area.measureArea(geometry) - perimeter = self.distance_conversion_factor * self.distance_area.measurePerimeter(geometry) + perimeter = ( + self.distance_conversion_factor + * self.distance_area.measurePerimeter(geometry) + ) return [area, perimeter] diff --git a/python/plugins/processing/algs/qgis/FieldPyculator.py b/python/plugins/processing/algs/qgis/FieldPyculator.py index d08ab657c984..eed8ddc09e01 100644 --- a/python/plugins/processing/algs/qgis/FieldPyculator.py +++ b/python/plugins/processing/algs/qgis/FieldPyculator.py @@ -15,38 +15,40 @@ *************************************************************************** """ -__author__ = 'Victor Olaya & NextGIS' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya & NextGIS' +__author__ = "Victor Olaya & NextGIS" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya & NextGIS" import sys from qgis.PyQt.QtCore import QMetaType -from qgis.core import (Qgis, - QgsProcessingException, - QgsField, - QgsFields, - QgsFeatureSink, - QgsProcessing, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterString, - QgsProcessingParameterEnum, - QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSink, - QgsVariantUtils) +from qgis.core import ( + Qgis, + QgsProcessingException, + QgsField, + QgsFields, + QgsFeatureSink, + QgsProcessing, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterString, + QgsProcessingParameterEnum, + QgsProcessingParameterNumber, + QgsProcessingParameterFeatureSink, + QgsVariantUtils, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm class FieldsPyculator(QgisAlgorithm): - INPUT = 'INPUT' - FIELD_NAME = 'FIELD_NAME' - FIELD_TYPE = 'FIELD_TYPE' - FIELD_LENGTH = 'FIELD_LENGTH' - FIELD_PRECISION = 'FIELD_PRECISION' - GLOBAL = 'GLOBAL' - FORMULA = 'FORMULA' - OUTPUT = 'OUTPUT' - RESULT_VAR_NAME = 'value' + INPUT = "INPUT" + FIELD_NAME = "FIELD_NAME" + FIELD_TYPE = "FIELD_TYPE" + FIELD_LENGTH = "FIELD_LENGTH" + FIELD_PRECISION = "FIELD_PRECISION" + GLOBAL = "GLOBAL" + FORMULA = "FORMULA" + OUTPUT = "OUTPUT" + RESULT_VAR_NAME = "value" def flags(self): # This algorithm represents a security risk, due to the use @@ -54,69 +56,105 @@ def flags(self): return super().flags() | Qgis.ProcessingAlgorithmFlag.SecurityRisk def group(self): - return self.tr('Vector table') + return self.tr("Vector table") def groupId(self): - return 'vectortable' + return "vectortable" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'), - types=[QgsProcessing.SourceType.TypeVector])) - self.addParameter(QgsProcessingParameterString(self.FIELD_NAME, - self.tr('Result field name'), defaultValue='NewField')) - - types = [(QMetaType.Type.Int, QMetaType.Type.UnknownType), - (QMetaType.Type.Double, QMetaType.Type.UnknownType), - (QMetaType.Type.QString, QMetaType.Type.UnknownType), - (QMetaType.Type.Bool, QMetaType.Type.UnknownType), - (QMetaType.Type.QDate, QMetaType.Type.UnknownType), - (QMetaType.Type.QTime, QMetaType.Type.UnknownType), - (QMetaType.Type.QDateTime, QMetaType.Type.UnknownType), - (QMetaType.Type.QByteArray, QMetaType.Type.UnknownType), - (QMetaType.Type.QStringList, QMetaType.Type.QString), - (QMetaType.Type.QVariantList, QMetaType.Type.Int), - (QMetaType.Type.QVariantList, QMetaType.Type.Double)] + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Input layer"), + types=[QgsProcessing.SourceType.TypeVector], + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.FIELD_NAME, self.tr("Result field name"), defaultValue="NewField" + ) + ) + + types = [ + (QMetaType.Type.Int, QMetaType.Type.UnknownType), + (QMetaType.Type.Double, QMetaType.Type.UnknownType), + (QMetaType.Type.QString, QMetaType.Type.UnknownType), + (QMetaType.Type.Bool, QMetaType.Type.UnknownType), + (QMetaType.Type.QDate, QMetaType.Type.UnknownType), + (QMetaType.Type.QTime, QMetaType.Type.UnknownType), + (QMetaType.Type.QDateTime, QMetaType.Type.UnknownType), + (QMetaType.Type.QByteArray, QMetaType.Type.UnknownType), + (QMetaType.Type.QStringList, QMetaType.Type.QString), + (QMetaType.Type.QVariantList, QMetaType.Type.Int), + (QMetaType.Type.QVariantList, QMetaType.Type.Double), + ] type_names = [] type_icons = [] for type_name, subtype_name in types: - type_names.append(QgsVariantUtils.typeToDisplayString(type_name, subtype_name)) + type_names.append( + QgsVariantUtils.typeToDisplayString(type_name, subtype_name) + ) type_icons.append(QgsFields.iconForFieldType(type_name, subtype_name)) - param = QgsProcessingParameterEnum('FIELD_TYPE', 'Field type', options=type_names) - param.setMetadata({'widget_wrapper': {'icons': type_icons}}) + param = QgsProcessingParameterEnum( + "FIELD_TYPE", "Field type", options=type_names + ) + param.setMetadata({"widget_wrapper": {"icons": type_icons}}) self.addParameter(param) - self.addParameter(QgsProcessingParameterNumber(self.FIELD_LENGTH, - self.tr('Field length'), minValue=0, - defaultValue=10)) - self.addParameter(QgsProcessingParameterNumber(self.FIELD_PRECISION, - self.tr('Field precision'), minValue=0, maxValue=15, - defaultValue=3)) - self.addParameter(QgsProcessingParameterString(self.GLOBAL, - self.tr('Global expression'), multiLine=True, optional=True)) - self.addParameter(QgsProcessingParameterString(self.FORMULA, - self.tr('Formula'), defaultValue='value = ', multiLine=True)) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, - self.tr('Calculated'))) + self.addParameter( + QgsProcessingParameterNumber( + self.FIELD_LENGTH, self.tr("Field length"), minValue=0, defaultValue=10 + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.FIELD_PRECISION, + self.tr("Field precision"), + minValue=0, + maxValue=15, + defaultValue=3, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.GLOBAL, self.tr("Global expression"), multiLine=True, optional=True + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.FORMULA, + self.tr("Formula"), + defaultValue="value = ", + multiLine=True, + ) + ) + self.addParameter( + QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr("Calculated")) + ) def name(self): - return 'advancedpythonfieldcalculator' + return "advancedpythonfieldcalculator" def displayName(self): - return self.tr('Advanced Python field calculator') + return self.tr("Advanced Python field calculator") def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) field_name = self.parameterAsString(parameters, self.FIELD_NAME, context) field_type = QMetaType.Type.UnknownType field_sub_type = QMetaType.Type.UnknownType - field_type_parameter = self.parameterAsEnum(parameters, self.FIELD_TYPE, context) + field_type_parameter = self.parameterAsEnum( + parameters, self.FIELD_TYPE, context + ) if field_type_parameter == 0: # Integer field_type = QMetaType.Type.Int elif field_type_parameter == 1: # Float @@ -149,45 +187,57 @@ def processAlgorithm(self, parameters, context, feedback): globalExpression = self.parameterAsString(parameters, self.GLOBAL, context) fields = source.fields() - field = QgsField(field_name, field_type, '', width, precision, '', field_sub_type) + field = QgsField( + field_name, field_type, "", width, precision, "", field_sub_type + ) fields.append(field) new_ns = {} - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, source.wkbType(), source.sourceCrs()) + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + fields, + source.wkbType(), + source.sourceCrs(), + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) # Run global code - if globalExpression.strip() != '': + if globalExpression.strip() != "": try: - bytecode = compile(globalExpression, '', 'exec') + bytecode = compile(globalExpression, "", "exec") exec(bytecode, new_ns) except: raise QgsProcessingException( - self.tr("FieldPyculator code execute error. Global code block can't be executed!\n{0}\n{1}").format( - str(sys.exc_info()[0].__name__), str(sys.exc_info()[1]))) + self.tr( + "FieldPyculator code execute error. Global code block can't be executed!\n{0}\n{1}" + ).format(str(sys.exc_info()[0].__name__), str(sys.exc_info()[1])) + ) # Replace all fields tags fields = source.fields() for num, field in enumerate(fields): field_name = str(field.name()) - replval = '__attr[' + str(num) + ']' - code = code.replace('<' + field_name + '>', replval) + replval = "__attr[" + str(num) + "]" + code = code.replace("<" + field_name + ">", replval) # Replace all special vars - code = code.replace('$id', '__id') - code = code.replace('$geom', '__geom') - need_id = code.find('__id') != -1 - need_geom = code.find('__geom') != -1 - need_attrs = code.find('__attr') != -1 + code = code.replace("$id", "__id") + code = code.replace("$geom", "__geom") + need_id = code.find("__id") != -1 + need_geom = code.find("__geom") != -1 + need_attrs = code.find("__attr") != -1 # Compile try: - bytecode = compile(code, '', 'exec') + bytecode = compile(code, "", "exec") except: raise QgsProcessingException( - self.tr("FieldPyculator code execute error. Field code block can't be executed!\n{0}\n{1}").format( - str(sys.exc_info()[0].__name__), str(sys.exc_info()[1]))) + self.tr( + "FieldPyculator code execute error. Field code block can't be executed!\n{0}\n{1}" + ).format(str(sys.exc_info()[0].__name__), str(sys.exc_info()[1])) + ) # Run features = source.getFeatures() @@ -203,15 +253,15 @@ def processAlgorithm(self, parameters, context, feedback): # Add needed vars if need_id: - new_ns['__id'] = feat_id + new_ns["__id"] = feat_id if need_geom: geom = feat.geometry() - new_ns['__geom'] = geom + new_ns["__geom"] = geom if need_attrs: pyattrs = [a for a in attrs] - new_ns['__attr'] = pyattrs + new_ns["__attr"] = pyattrs # Clear old result if self.RESULT_VAR_NAME in new_ns: @@ -223,9 +273,12 @@ def processAlgorithm(self, parameters, context, feedback): # Check result if self.RESULT_VAR_NAME not in new_ns: raise QgsProcessingException( - self.tr("FieldPyculator code execute error\n" - "Field code block does not return '{0}' variable! " - "Please declare this variable in your code!").format(self.RESULT_VAR_NAME)) + self.tr( + "FieldPyculator code execute error\n" + "Field code block does not return '{0}' variable! " + "Please declare this variable in your code!" + ).format(self.RESULT_VAR_NAME) + ) # Write feature attrs.append(new_ns[self.RESULT_VAR_NAME]) diff --git a/python/plugins/processing/algs/qgis/FindProjection.py b/python/plugins/processing/algs/qgis/FindProjection.py index 10e85f67151b..ddcd4cf52aea 100644 --- a/python/plugins/processing/algs/qgis/FindProjection.py +++ b/python/plugins/processing/algs/qgis/FindProjection.py @@ -15,27 +15,29 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'February 2017' -__copyright__ = '(C) 2017, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "February 2017" +__copyright__ = "(C) 2017, Nyall Dawson" import os -from qgis.core import (QgsGeometry, - QgsFeature, - QgsFeatureSink, - QgsField, - QgsFields, - QgsCoordinateReferenceSystem, - QgsCoordinateTransform, - QgsCoordinateTransformContext, - QgsWkbTypes, - QgsProcessingException, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterExtent, - QgsProcessingParameterCrs, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterDefinition) +from qgis.core import ( + QgsGeometry, + QgsFeature, + QgsFeatureSink, + QgsField, + QgsFields, + QgsCoordinateReferenceSystem, + QgsCoordinateTransform, + QgsCoordinateTransformContext, + QgsWkbTypes, + QgsProcessingException, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterExtent, + QgsProcessingParameterCrs, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterDefinition, +) from qgis.PyQt.QtCore import QMetaType from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm @@ -44,48 +46,59 @@ class FindProjection(QgisAlgorithm): - INPUT = 'INPUT' - TARGET_AREA = 'TARGET_AREA' - TARGET_AREA_CRS = 'TARGET_AREA_CRS' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + TARGET_AREA = "TARGET_AREA" + TARGET_AREA_CRS = "TARGET_AREA_CRS" + OUTPUT = "OUTPUT" def tags(self): - return self.tr('crs,srs,coordinate,reference,system,guess,estimate,finder,determine').split(',') + return self.tr( + "crs,srs,coordinate,reference,system,guess,estimate,finder,determine" + ).split(",") def group(self): - return self.tr('Vector general') + return self.tr("Vector general") def groupId(self): - return 'vectorgeneral' + return "vectorgeneral" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'))) - extent_parameter = QgsProcessingParameterExtent(self.TARGET_AREA, - self.tr('Target area for layer')) + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer")) + ) + extent_parameter = QgsProcessingParameterExtent( + self.TARGET_AREA, self.tr("Target area for layer") + ) self.addParameter(extent_parameter) # deprecated - crs_param = QgsProcessingParameterCrs(self.TARGET_AREA_CRS, 'Target area CRS', optional=True) - crs_param.setFlags(crs_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden) + crs_param = QgsProcessingParameterCrs( + self.TARGET_AREA_CRS, "Target area CRS", optional=True + ) + crs_param.setFlags( + crs_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden + ) self.addParameter(crs_param) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, - self.tr('CRS candidates'))) + self.addParameter( + QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr("CRS candidates")) + ) def name(self): - return 'findprojection' + return "findprojection" def displayName(self): - return self.tr('Find projection') + return self.tr("Find projection") def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) extent = self.parameterAsExtent(parameters, self.TARGET_AREA, context) target_crs = self.parameterAsExtentCrs(parameters, self.TARGET_AREA, context) @@ -97,10 +110,16 @@ def processAlgorithm(self, parameters, context, feedback): target_geom = QgsGeometry.fromRect(extent) fields = QgsFields() - fields.append(QgsField('auth_id', QMetaType.Type.QString, '', 20)) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, QgsWkbTypes.Type.NoGeometry, QgsCoordinateReferenceSystem()) + fields.append(QgsField("auth_id", QMetaType.Type.QString, "", 20)) + + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + fields, + QgsWkbTypes.Type.NoGeometry, + QgsCoordinateReferenceSystem(), + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) @@ -124,7 +143,9 @@ def processAlgorithm(self, parameters, context, feedback): if not candidate_crs.isValid(): continue - transform_candidate = QgsCoordinateTransform(candidate_crs, target_crs, transform_context) + transform_candidate = QgsCoordinateTransform( + candidate_crs, target_crs, transform_context + ) transform_candidate.setBallparkTransformsAreAppropriate(True) transform_candidate.disableFallbackOperationHandler(True) transformed_bounds = QgsGeometry(layer_bounds) @@ -136,7 +157,11 @@ def processAlgorithm(self, parameters, context, feedback): try: if engine.intersects(transformed_bounds.constGet()): - feedback.pushInfo(self.tr('Found candidate CRS: {}').format(candidate_crs.authid())) + feedback.pushInfo( + self.tr("Found candidate CRS: {}").format( + candidate_crs.authid() + ) + ) f = QgsFeature(fields) f.setAttributes([candidate_crs.authid()]) sink.addFeature(f, QgsFeatureSink.Flag.FastInsert) @@ -147,7 +172,7 @@ def processAlgorithm(self, parameters, context, feedback): feedback.setProgress(int(current * total)) if found_results == 0: - feedback.reportError(self.tr('No matching projections found')) + feedback.reportError(self.tr("No matching projections found")) sink.finalize() return {self.OUTPUT: dest_id} diff --git a/python/plugins/processing/algs/qgis/GeometryConvert.py b/python/plugins/processing/algs/qgis/GeometryConvert.py index 773e313088db..7857c3b9b5ed 100644 --- a/python/plugins/processing/algs/qgis/GeometryConvert.py +++ b/python/plugins/processing/algs/qgis/GeometryConvert.py @@ -15,64 +15,75 @@ *************************************************************************** """ -__author__ = 'Michael Minn' -__date__ = 'May 2010' -__copyright__ = '(C) 2010, Michael Minn' - -from qgis.core import (QgsFeature, - QgsGeometry, - QgsMultiPoint, - QgsMultiLineString, - QgsLineString, - QgsPolygon, - QgsFeatureSink, - QgsWkbTypes, - QgsProcessingException, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterEnum, - QgsProcessingParameterFeatureSink) +__author__ = "Michael Minn" +__date__ = "May 2010" +__copyright__ = "(C) 2010, Michael Minn" + +from qgis.core import ( + QgsFeature, + QgsGeometry, + QgsMultiPoint, + QgsMultiLineString, + QgsLineString, + QgsPolygon, + QgsFeatureSink, + QgsWkbTypes, + QgsProcessingException, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterEnum, + QgsProcessingParameterFeatureSink, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm class GeometryConvert(QgisAlgorithm): - INPUT = 'INPUT' - TYPE = 'TYPE' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + TYPE = "TYPE" + OUTPUT = "OUTPUT" def group(self): - return self.tr('Vector geometry') + return self.tr("Vector geometry") def groupId(self): - return 'vectorgeometry' + return "vectorgeometry" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.types = [self.tr('Centroids'), - self.tr('Nodes'), - self.tr('Linestrings'), - self.tr('Multilinestrings'), - self.tr('Polygons')] + self.types = [ + self.tr("Centroids"), + self.tr("Nodes"), + self.tr("Linestrings"), + self.tr("Multilinestrings"), + self.tr("Polygons"), + ] - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterEnum(self.TYPE, - self.tr('New geometry type'), options=self.types)) + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.TYPE, self.tr("New geometry type"), options=self.types + ) + ) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, - self.tr('Converted'))) + self.addParameter( + QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr("Converted")) + ) def name(self): - return 'convertgeometrytype' + return "convertgeometrytype" def displayName(self): - return self.tr('Convert geometry type') + return self.tr("Convert geometry type") def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) index = self.parameterAsEnum(parameters, self.TYPE, context) @@ -103,8 +114,14 @@ def processAlgorithm(self, parameters, context, feedback): if QgsWkbTypes.hasZ(source.wkbType()): newType = QgsWkbTypes.addZ(newType) - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - source.fields(), newType, source.sourceCrs()) + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + source.fields(), + newType, + source.sourceCrs(), + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) @@ -161,10 +178,19 @@ def convertToNodes(self, geom): return [QgsGeometry(mp)] def convertToLineStrings(self, geom): - if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.GeometryType.PointGeometry: + if ( + QgsWkbTypes.geometryType(geom.wkbType()) + == QgsWkbTypes.GeometryType.PointGeometry + ): raise QgsProcessingException( - self.tr('Cannot convert from {0} to LineStrings').format(QgsWkbTypes.displayString(geom.wkbType()))) - elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.GeometryType.LineGeometry: + self.tr("Cannot convert from {0} to LineStrings").format( + QgsWkbTypes.displayString(geom.wkbType()) + ) + ) + elif ( + QgsWkbTypes.geometryType(geom.wkbType()) + == QgsWkbTypes.GeometryType.LineGeometry + ): if QgsWkbTypes.isMultiType(geom.wkbType()): return geom.asGeometryCollection() else: @@ -178,10 +204,19 @@ def convertToLineStrings(self, geom): return boundary.asGeometryCollection() def convertToMultiLineStrings(self, geom): - if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.GeometryType.PointGeometry: + if ( + QgsWkbTypes.geometryType(geom.wkbType()) + == QgsWkbTypes.GeometryType.PointGeometry + ): raise QgsProcessingException( - self.tr('Cannot convert from {0} to MultiLineStrings').format(QgsWkbTypes.displayString(geom.wkbType()))) - elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.GeometryType.LineGeometry: + self.tr("Cannot convert from {0} to MultiLineStrings").format( + QgsWkbTypes.displayString(geom.wkbType()) + ) + ) + elif ( + QgsWkbTypes.geometryType(geom.wkbType()) + == QgsWkbTypes.GeometryType.LineGeometry + ): if QgsWkbTypes.isMultiType(geom.wkbType()): return [geom] else: @@ -195,10 +230,20 @@ def convertToMultiLineStrings(self, geom): return [QgsGeometry(geom.constGet().boundary())] def convertToPolygon(self, geom): - if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.GeometryType.PointGeometry and geom.constGet().nCoordinates() < 3: + if ( + QgsWkbTypes.geometryType(geom.wkbType()) + == QgsWkbTypes.GeometryType.PointGeometry + and geom.constGet().nCoordinates() < 3 + ): raise QgsProcessingException( - self.tr('Cannot convert from Point to Polygon').format(QgsWkbTypes.displayString(geom.wkbType()))) - elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.GeometryType.PointGeometry: + self.tr("Cannot convert from Point to Polygon").format( + QgsWkbTypes.displayString(geom.wkbType()) + ) + ) + elif ( + QgsWkbTypes.geometryType(geom.wkbType()) + == QgsWkbTypes.GeometryType.PointGeometry + ): # multipoint with at least 3 points # TODO: mega inefficient - needs rework when geometry iterators land # (but at least it doesn't lose Z/M values) @@ -212,7 +257,10 @@ def convertToPolygon(self, geom): p = QgsPolygon() p.setExteriorRing(linestring) return [QgsGeometry(p)] - elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.GeometryType.LineGeometry: + elif ( + QgsWkbTypes.geometryType(geom.wkbType()) + == QgsWkbTypes.GeometryType.LineGeometry + ): if QgsWkbTypes.isMultiType(geom.wkbType()): parts = [] for i in range(geom.constGet().numGeometries()): diff --git a/python/plugins/processing/algs/qgis/Heatmap.py b/python/plugins/processing/algs/qgis/Heatmap.py index 619722d203d8..f333e96fa17c 100644 --- a/python/plugins/processing/algs/qgis/Heatmap.py +++ b/python/plugins/processing/algs/qgis/Heatmap.py @@ -15,27 +15,29 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'November 2016' -__copyright__ = '(C) 2016, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "November 2016" +__copyright__ = "(C) 2016, Nyall Dawson" import os from collections import OrderedDict from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsApplication, - QgsFeatureRequest, - QgsRasterFileWriter, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterNumber, - QgsProcessingParameterDistance, - QgsProcessingParameterField, - QgsProcessingParameterEnum, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterDestination) +from qgis.core import ( + QgsApplication, + QgsFeatureRequest, + QgsRasterFileWriter, + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterNumber, + QgsProcessingParameterDistance, + QgsProcessingParameterField, + QgsProcessingParameterEnum, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterDestination, +) from qgis.analysis import QgsKernelDensityEstimation @@ -45,130 +47,226 @@ class Heatmap(QgisAlgorithm): - INPUT = 'INPUT' - RADIUS = 'RADIUS' - RADIUS_FIELD = 'RADIUS_FIELD' - WEIGHT_FIELD = 'WEIGHT_FIELD' - PIXEL_SIZE = 'PIXEL_SIZE' - KERNEL = 'KERNEL' - DECAY = 'DECAY' - OUTPUT_VALUE = 'OUTPUT_VALUE' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + RADIUS = "RADIUS" + RADIUS_FIELD = "RADIUS_FIELD" + WEIGHT_FIELD = "WEIGHT_FIELD" + PIXEL_SIZE = "PIXEL_SIZE" + KERNEL = "KERNEL" + DECAY = "DECAY" + OUTPUT_VALUE = "OUTPUT_VALUE" + OUTPUT = "OUTPUT" def icon(self): return QgsApplication.getThemeIcon("/heatmap.svg") def tags(self): - return self.tr('heatmap,kde,hotspot').split(',') + return self.tr("heatmap,kde,hotspot").split(",") def group(self): - return self.tr('Interpolation') + return self.tr("Interpolation") def groupId(self): - return 'interpolation' + return "interpolation" def name(self): - return 'heatmapkerneldensityestimation' + return "heatmapkerneldensityestimation" def displayName(self): - return self.tr('Heatmap (Kernel Density Estimation)') + return self.tr("Heatmap (Kernel Density Estimation)") def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.KERNELS = OrderedDict([(self.tr('Quartic'), QgsKernelDensityEstimation.KernelShape.KernelQuartic), - (self.tr('Triangular'), QgsKernelDensityEstimation.KernelShape.KernelTriangular), - (self.tr('Uniform'), QgsKernelDensityEstimation.KernelShape.KernelUniform), - (self.tr('Triweight'), QgsKernelDensityEstimation.KernelShape.KernelTriweight), - (self.tr('Epanechnikov'), QgsKernelDensityEstimation.KernelShape.KernelEpanechnikov)]) - - self.OUTPUT_VALUES = OrderedDict([(self.tr('Raw'), QgsKernelDensityEstimation.OutputValues.OutputRaw), - (self.tr('Scaled'), QgsKernelDensityEstimation.OutputValues.OutputScaled)]) - - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Point layer'), - [QgsProcessing.SourceType.TypeVectorPoint])) - - self.addParameter(QgsProcessingParameterDistance(self.RADIUS, - self.tr('Radius'), - 100.0, self.INPUT, False, 0.0)) - - radius_field_param = QgsProcessingParameterField(self.RADIUS_FIELD, - self.tr('Radius from field'), - None, - self.INPUT, - QgsProcessingParameterField.DataType.Numeric, - optional=True - ) - radius_field_param.setFlags(radius_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.KERNELS = OrderedDict( + [ + ( + self.tr("Quartic"), + QgsKernelDensityEstimation.KernelShape.KernelQuartic, + ), + ( + self.tr("Triangular"), + QgsKernelDensityEstimation.KernelShape.KernelTriangular, + ), + ( + self.tr("Uniform"), + QgsKernelDensityEstimation.KernelShape.KernelUniform, + ), + ( + self.tr("Triweight"), + QgsKernelDensityEstimation.KernelShape.KernelTriweight, + ), + ( + self.tr("Epanechnikov"), + QgsKernelDensityEstimation.KernelShape.KernelEpanechnikov, + ), + ] + ) + + self.OUTPUT_VALUES = OrderedDict( + [ + (self.tr("Raw"), QgsKernelDensityEstimation.OutputValues.OutputRaw), + ( + self.tr("Scaled"), + QgsKernelDensityEstimation.OutputValues.OutputScaled, + ), + ] + ) + + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Point layer"), + [QgsProcessing.SourceType.TypeVectorPoint], + ) + ) + + self.addParameter( + QgsProcessingParameterDistance( + self.RADIUS, self.tr("Radius"), 100.0, self.INPUT, False, 0.0 + ) + ) + + radius_field_param = QgsProcessingParameterField( + self.RADIUS_FIELD, + self.tr("Radius from field"), + None, + self.INPUT, + QgsProcessingParameterField.DataType.Numeric, + optional=True, + ) + radius_field_param.setFlags( + radius_field_param.flags() + | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(radius_field_param) class ParameterHeatmapPixelSize(QgsProcessingParameterNumber): - def __init__(self, name='', description='', parent_layer=None, radius_param=None, radius_field_param=None, minValue=None, - default=None, optional=False): - QgsProcessingParameterNumber.__init__(self, name, description, QgsProcessingParameterNumber.Type.Double, default, optional, minValue) + def __init__( + self, + name="", + description="", + parent_layer=None, + radius_param=None, + radius_field_param=None, + minValue=None, + default=None, + optional=False, + ): + QgsProcessingParameterNumber.__init__( + self, + name, + description, + QgsProcessingParameterNumber.Type.Double, + default, + optional, + minValue, + ) self.parent_layer = parent_layer self.radius_param = radius_param self.radius_field_param = radius_field_param def clone(self): - return ParameterHeatmapPixelSize(self.name(), self.description(), self.parent_layer, self.radius_param, self.radius_field_param, self.minimum(), self.maximum(), self.defaultValue((), self.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)) - - pixel_size_param = ParameterHeatmapPixelSize(self.PIXEL_SIZE, - self.tr('Output raster size'), - parent_layer=self.INPUT, - radius_param=self.RADIUS, - radius_field_param=self.RADIUS_FIELD, - minValue=0.0, - default=0.1) - pixel_size_param.setMetadata({ - 'widget_wrapper': { - 'class': 'processing.algs.qgis.ui.HeatmapWidgets.HeatmapPixelSizeWidgetWrapper'}}) + return ParameterHeatmapPixelSize( + self.name(), + self.description(), + self.parent_layer, + self.radius_param, + self.radius_field_param, + self.minimum(), + self.maximum(), + self.defaultValue( + (), + self.flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional, + ), + ) + + pixel_size_param = ParameterHeatmapPixelSize( + self.PIXEL_SIZE, + self.tr("Output raster size"), + parent_layer=self.INPUT, + radius_param=self.RADIUS, + radius_field_param=self.RADIUS_FIELD, + minValue=0.0, + default=0.1, + ) + pixel_size_param.setMetadata( + { + "widget_wrapper": { + "class": "processing.algs.qgis.ui.HeatmapWidgets.HeatmapPixelSizeWidgetWrapper" + } + } + ) self.addParameter(pixel_size_param) - weight_field_param = QgsProcessingParameterField(self.WEIGHT_FIELD, - self.tr('Weight from field'), - None, - self.INPUT, - QgsProcessingParameterField.DataType.Numeric, - optional=True - ) - weight_field_param.setFlags(weight_field_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + weight_field_param = QgsProcessingParameterField( + self.WEIGHT_FIELD, + self.tr("Weight from field"), + None, + self.INPUT, + QgsProcessingParameterField.DataType.Numeric, + optional=True, + ) + weight_field_param.setFlags( + weight_field_param.flags() + | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(weight_field_param) keys = list(self.KERNELS.keys()) - kernel_shape_param = QgsProcessingParameterEnum(self.KERNEL, - self.tr('Kernel shape'), - keys, - allowMultiple=False, - defaultValue=0) - kernel_shape_param.setFlags(kernel_shape_param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + kernel_shape_param = QgsProcessingParameterEnum( + self.KERNEL, + self.tr("Kernel shape"), + keys, + allowMultiple=False, + defaultValue=0, + ) + kernel_shape_param.setFlags( + kernel_shape_param.flags() + | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(kernel_shape_param) - decay_ratio = QgsProcessingParameterNumber(self.DECAY, - self.tr('Decay ratio (Triangular kernels only)'), - QgsProcessingParameterNumber.Type.Double, - 0.0, True, -100.0, 100.0) - decay_ratio.setFlags(decay_ratio.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + decay_ratio = QgsProcessingParameterNumber( + self.DECAY, + self.tr("Decay ratio (Triangular kernels only)"), + QgsProcessingParameterNumber.Type.Double, + 0.0, + True, + -100.0, + 100.0, + ) + decay_ratio.setFlags( + decay_ratio.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(decay_ratio) keys = list(self.OUTPUT_VALUES.keys()) - output_scaling = QgsProcessingParameterEnum(self.OUTPUT_VALUE, - self.tr('Output value scaling'), - keys, - allowMultiple=False, - defaultValue=0) - output_scaling.setFlags(output_scaling.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + output_scaling = QgsProcessingParameterEnum( + self.OUTPUT_VALUE, + self.tr("Output value scaling"), + keys, + allowMultiple=False, + defaultValue=0, + ) + output_scaling.setFlags( + output_scaling.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.addParameter(output_scaling) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Heatmap'))) + self.addParameter( + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Heatmap")) + ) def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) radius = self.parameterAsDouble(parameters, self.RADIUS, context) kernel_shape = self.parameterAsEnum(parameters, self.KERNEL, context) @@ -176,7 +274,9 @@ def processAlgorithm(self, parameters, context, feedback): decay = self.parameterAsDouble(parameters, self.DECAY, context) output_values = self.parameterAsEnum(parameters, self.OUTPUT_VALUE, context) outputFile = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) - output_format = QgsRasterFileWriter.driverForExtension(os.path.splitext(outputFile)[1]) + output_format = QgsRasterFileWriter.driverForExtension( + os.path.splitext(outputFile)[1] + ) weight_field = self.parameterAsString(parameters, self.WEIGHT_FIELD, context) radius_field = self.parameterAsString(parameters, self.RADIUS_FIELD, context) @@ -202,8 +302,7 @@ def processAlgorithm(self, parameters, context, feedback): kde = QgsKernelDensityEstimation(kde_params, outputFile, output_format) if kde.prepare() != QgsKernelDensityEstimation.Result.Success: - raise QgsProcessingException( - self.tr('Could not create destination layer')) + raise QgsProcessingException(self.tr("Could not create destination layer")) request = QgsFeatureRequest() request.setSubsetOfAttributes(attrs) @@ -214,12 +313,13 @@ def processAlgorithm(self, parameters, context, feedback): break if kde.addFeature(f) != QgsKernelDensityEstimation.Result.Success: - feedback.reportError(self.tr('Error adding feature with ID {} to heatmap').format(f.id())) + feedback.reportError( + self.tr("Error adding feature with ID {} to heatmap").format(f.id()) + ) feedback.setProgress(int(current * total)) if kde.finalise() != QgsKernelDensityEstimation.Result.Success: - raise QgsProcessingException( - self.tr('Could not save destination layer')) + raise QgsProcessingException(self.tr("Could not save destination layer")) return {self.OUTPUT: outputFile} diff --git a/python/plugins/processing/algs/qgis/HubDistanceLines.py b/python/plugins/processing/algs/qgis/HubDistanceLines.py index 25e5e495e19d..75fd57c458b8 100644 --- a/python/plugins/processing/algs/qgis/HubDistanceLines.py +++ b/python/plugins/processing/algs/qgis/HubDistanceLines.py @@ -15,88 +15,116 @@ *************************************************************************** """ -__author__ = 'Michael Minn' -__date__ = 'May 2010' -__copyright__ = '(C) 2010, Michael Minn' +__author__ = "Michael Minn" +__date__ = "May 2010" +__copyright__ = "(C) 2010, Michael Minn" from qgis.PyQt.QtCore import QMetaType -from qgis.core import (QgsField, - QgsGeometry, - QgsDistanceArea, - QgsFeature, - QgsFeatureSink, - QgsFeatureRequest, - QgsWkbTypes, - QgsUnitTypes, - QgsProcessing, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterField, - QgsProcessingParameterEnum, - QgsProcessingParameterFeatureSink, - QgsProcessingException, - QgsSpatialIndex) +from qgis.core import ( + QgsField, + QgsGeometry, + QgsDistanceArea, + QgsFeature, + QgsFeatureSink, + QgsFeatureRequest, + QgsWkbTypes, + QgsUnitTypes, + QgsProcessing, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingParameterEnum, + QgsProcessingParameterFeatureSink, + QgsProcessingException, + QgsSpatialIndex, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from math import sqrt class HubDistanceLines(QgisAlgorithm): - INPUT = 'INPUT' - HUBS = 'HUBS' - FIELD = 'FIELD' - UNIT = 'UNIT' - OUTPUT = 'OUTPUT' - - LAYER_UNITS = 'LAYER_UNITS' - - UNITS = [QgsUnitTypes.DistanceUnit.DistanceMeters, - QgsUnitTypes.DistanceUnit.DistanceFeet, - QgsUnitTypes.DistanceUnit.DistanceMiles, - QgsUnitTypes.DistanceUnit.DistanceKilometers, - LAYER_UNITS - ] + INPUT = "INPUT" + HUBS = "HUBS" + FIELD = "FIELD" + UNIT = "UNIT" + OUTPUT = "OUTPUT" + + LAYER_UNITS = "LAYER_UNITS" + + UNITS = [ + QgsUnitTypes.DistanceUnit.DistanceMeters, + QgsUnitTypes.DistanceUnit.DistanceFeet, + QgsUnitTypes.DistanceUnit.DistanceMiles, + QgsUnitTypes.DistanceUnit.DistanceKilometers, + LAYER_UNITS, + ] def group(self): - return self.tr('Vector analysis') + return self.tr("Vector analysis") def groupId(self): - return 'vectoranalysis' + return "vectoranalysis" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.units = [self.tr('Meters'), - self.tr('Feet'), - self.tr('Miles'), - self.tr('Kilometers'), - self.tr('Layer units')] - - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Source points layer'))) - self.addParameter(QgsProcessingParameterFeatureSource(self.HUBS, - self.tr('Destination hubs layer'))) - self.addParameter(QgsProcessingParameterField(self.FIELD, - self.tr('Hub layer name attribute'), parentLayerParameterName=self.HUBS)) - self.addParameter(QgsProcessingParameterEnum(self.UNIT, - self.tr('Measurement unit'), self.units)) - - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Hub distance'), QgsProcessing.SourceType.TypeVectorLine)) + self.units = [ + self.tr("Meters"), + self.tr("Feet"), + self.tr("Miles"), + self.tr("Kilometers"), + self.tr("Layer units"), + ] + + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, self.tr("Source points layer") + ) + ) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.HUBS, self.tr("Destination hubs layer") + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.FIELD, + self.tr("Hub layer name attribute"), + parentLayerParameterName=self.HUBS, + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.UNIT, self.tr("Measurement unit"), self.units + ) + ) + + self.addParameter( + QgsProcessingParameterFeatureSink( + self.OUTPUT, + self.tr("Hub distance"), + QgsProcessing.SourceType.TypeVectorLine, + ) + ) def name(self): - return 'distancetonearesthublinetohub' + return "distancetonearesthublinetohub" def displayName(self): - return self.tr('Distance to nearest hub (line to hub)') + return self.tr("Distance to nearest hub (line to hub)") def processAlgorithm(self, parameters, context, feedback): if parameters[self.INPUT] == parameters[self.HUBS]: raise QgsProcessingException( - self.tr('Same layer given for both hubs and spokes')) + self.tr("Same layer given for both hubs and spokes") + ) point_source = self.parameterAsSource(parameters, self.INPUT, context) if point_source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) hub_source = self.parameterAsSource(parameters, self.HUBS, context) if hub_source is None: @@ -107,15 +135,27 @@ def processAlgorithm(self, parameters, context, feedback): units = self.UNITS[self.parameterAsEnum(parameters, self.UNIT, context)] fields = point_source.fields() - fields.append(QgsField('HubName', QMetaType.Type.QString)) - fields.append(QgsField('HubDist', QMetaType.Type.Double)) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, QgsWkbTypes.Type.LineString, point_source.sourceCrs()) + fields.append(QgsField("HubName", QMetaType.Type.QString)) + fields.append(QgsField("HubDist", QMetaType.Type.Double)) + + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + fields, + QgsWkbTypes.Type.LineString, + point_source.sourceCrs(), + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) - index = QgsSpatialIndex(hub_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(point_source.sourceCrs(), context.transformContext()))) + index = QgsSpatialIndex( + hub_source.getFeatures( + QgsFeatureRequest() + .setSubsetOfAttributes([]) + .setDestinationCrs(point_source.sourceCrs(), context.transformContext()) + ) + ) distance = QgsDistanceArea() distance.setSourceCrs(point_source.sourceCrs(), context.transformContext()) @@ -123,7 +163,9 @@ def processAlgorithm(self, parameters, context, feedback): # Scan source points, find nearest hub, and write to output file features = point_source.getFeatures() - total = 100.0 / point_source.featureCount() if point_source.featureCount() else 0 + total = ( + 100.0 / point_source.featureCount() if point_source.featureCount() else 0 + ) for current, f in enumerate(features): if feedback.isCanceled(): break @@ -137,12 +179,23 @@ def processAlgorithm(self, parameters, context, feedback): if len(neighbors) == 0: continue - ft = next(hub_source.getFeatures(QgsFeatureRequest().setFilterFid(neighbors[0]).setSubsetOfAttributes([fieldName], hub_source.fields()).setDestinationCrs(point_source.sourceCrs(), context.transformContext()))) + ft = next( + hub_source.getFeatures( + QgsFeatureRequest() + .setFilterFid(neighbors[0]) + .setSubsetOfAttributes([fieldName], hub_source.fields()) + .setDestinationCrs( + point_source.sourceCrs(), context.transformContext() + ) + ) + ) closest = ft.geometry().boundingBox().center() hubDist = distance.measureLine(src, closest) if units != self.LAYER_UNITS: - hub_dist_in_desired_units = distance.convertLengthMeasurement(hubDist, units) + hub_dist_in_desired_units = distance.convertLengthMeasurement( + hubDist, units + ) else: hub_dist_in_desired_units = hubDist diff --git a/python/plugins/processing/algs/qgis/HubDistancePoints.py b/python/plugins/processing/algs/qgis/HubDistancePoints.py index e9b8a4649b76..602c1799d070 100644 --- a/python/plugins/processing/algs/qgis/HubDistancePoints.py +++ b/python/plugins/processing/algs/qgis/HubDistancePoints.py @@ -15,85 +15,113 @@ *************************************************************************** """ -__author__ = 'Michael Minn' -__date__ = 'May 2010' -__copyright__ = '(C) 2010, Michael Minn' +__author__ = "Michael Minn" +__date__ = "May 2010" +__copyright__ = "(C) 2010, Michael Minn" from qgis.PyQt.QtCore import QMetaType -from qgis.core import (QgsField, - QgsGeometry, - QgsFeatureSink, - QgsDistanceArea, - QgsFeature, - QgsFeatureRequest, - QgsSpatialIndex, - QgsWkbTypes, - QgsUnitTypes, - QgsProcessing, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterField, - QgsProcessingParameterEnum, - QgsProcessingParameterFeatureSink, - QgsProcessingException) +from qgis.core import ( + QgsField, + QgsGeometry, + QgsFeatureSink, + QgsDistanceArea, + QgsFeature, + QgsFeatureRequest, + QgsSpatialIndex, + QgsWkbTypes, + QgsUnitTypes, + QgsProcessing, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingParameterEnum, + QgsProcessingParameterFeatureSink, + QgsProcessingException, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm class HubDistancePoints(QgisAlgorithm): - INPUT = 'INPUT' - HUBS = 'HUBS' - FIELD = 'FIELD' - UNIT = 'UNIT' - OUTPUT = 'OUTPUT' - LAYER_UNITS = 'LAYER_UNITS' - - UNITS = [QgsUnitTypes.DistanceUnit.DistanceMeters, - QgsUnitTypes.DistanceUnit.DistanceFeet, - QgsUnitTypes.DistanceUnit.DistanceMiles, - QgsUnitTypes.DistanceUnit.DistanceKilometers, - LAYER_UNITS - ] + INPUT = "INPUT" + HUBS = "HUBS" + FIELD = "FIELD" + UNIT = "UNIT" + OUTPUT = "OUTPUT" + LAYER_UNITS = "LAYER_UNITS" + + UNITS = [ + QgsUnitTypes.DistanceUnit.DistanceMeters, + QgsUnitTypes.DistanceUnit.DistanceFeet, + QgsUnitTypes.DistanceUnit.DistanceMiles, + QgsUnitTypes.DistanceUnit.DistanceKilometers, + LAYER_UNITS, + ] def group(self): - return self.tr('Vector analysis') + return self.tr("Vector analysis") def groupId(self): - return 'vectoranalysis' + return "vectoranalysis" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.units = [self.tr('Meters'), - self.tr('Feet'), - self.tr('Miles'), - self.tr('Kilometers'), - self.tr('Layer units')] - - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Source points layer'))) - self.addParameter(QgsProcessingParameterFeatureSource(self.HUBS, - self.tr('Destination hubs layer'))) - self.addParameter(QgsProcessingParameterField(self.FIELD, - self.tr('Hub layer name attribute'), parentLayerParameterName=self.HUBS)) - self.addParameter(QgsProcessingParameterEnum(self.UNIT, - self.tr('Measurement unit'), self.units)) - - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Hub distance'), QgsProcessing.SourceType.TypeVectorPoint)) + self.units = [ + self.tr("Meters"), + self.tr("Feet"), + self.tr("Miles"), + self.tr("Kilometers"), + self.tr("Layer units"), + ] + + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, self.tr("Source points layer") + ) + ) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.HUBS, self.tr("Destination hubs layer") + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.FIELD, + self.tr("Hub layer name attribute"), + parentLayerParameterName=self.HUBS, + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.UNIT, self.tr("Measurement unit"), self.units + ) + ) + + self.addParameter( + QgsProcessingParameterFeatureSink( + self.OUTPUT, + self.tr("Hub distance"), + QgsProcessing.SourceType.TypeVectorPoint, + ) + ) def name(self): - return 'distancetonearesthubpoints' + return "distancetonearesthubpoints" def displayName(self): - return self.tr('Distance to nearest hub (points)') + return self.tr("Distance to nearest hub (points)") def processAlgorithm(self, parameters, context, feedback): if parameters[self.INPUT] == parameters[self.HUBS]: raise QgsProcessingException( - self.tr('Same layer given for both hubs and spokes')) + self.tr("Same layer given for both hubs and spokes") + ) point_source = self.parameterAsSource(parameters, self.INPUT, context) if point_source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) hub_source = self.parameterAsSource(parameters, self.HUBS, context) if hub_source is None: @@ -104,15 +132,27 @@ def processAlgorithm(self, parameters, context, feedback): units = self.UNITS[self.parameterAsEnum(parameters, self.UNIT, context)] fields = point_source.fields() - fields.append(QgsField('HubName', QMetaType.Type.QString)) - fields.append(QgsField('HubDist', QMetaType.Type.Double)) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, QgsWkbTypes.Type.Point, point_source.sourceCrs()) + fields.append(QgsField("HubName", QMetaType.Type.QString)) + fields.append(QgsField("HubDist", QMetaType.Type.Double)) + + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + fields, + QgsWkbTypes.Type.Point, + point_source.sourceCrs(), + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) - index = QgsSpatialIndex(hub_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(point_source.sourceCrs(), context.transformContext()))) + index = QgsSpatialIndex( + hub_source.getFeatures( + QgsFeatureRequest() + .setSubsetOfAttributes([]) + .setDestinationCrs(point_source.sourceCrs(), context.transformContext()) + ) + ) distance = QgsDistanceArea() distance.setSourceCrs(point_source.sourceCrs(), context.transformContext()) @@ -120,7 +160,9 @@ def processAlgorithm(self, parameters, context, feedback): # Scan source points, find nearest hub, and write to output file features = point_source.getFeatures() - total = 100.0 / point_source.featureCount() if point_source.featureCount() else 0 + total = ( + 100.0 / point_source.featureCount() if point_source.featureCount() else 0 + ) for current, f in enumerate(features): if feedback.isCanceled(): break @@ -135,12 +177,23 @@ def processAlgorithm(self, parameters, context, feedback): if len(neighbors) == 0: continue - ft = next(hub_source.getFeatures(QgsFeatureRequest().setFilterFid(neighbors[0]).setSubsetOfAttributes([fieldName], hub_source.fields()).setDestinationCrs(point_source.sourceCrs(), context.transformContext()))) + ft = next( + hub_source.getFeatures( + QgsFeatureRequest() + .setFilterFid(neighbors[0]) + .setSubsetOfAttributes([fieldName], hub_source.fields()) + .setDestinationCrs( + point_source.sourceCrs(), context.transformContext() + ) + ) + ) closest = ft.geometry().boundingBox().center() hubDist = distance.measureLine(src, closest) if units != self.LAYER_UNITS: - hub_dist_in_desired_units = distance.convertLengthMeasurement(hubDist, units) + hub_dist_in_desired_units = distance.convertLengthMeasurement( + hubDist, units + ) else: hub_dist_in_desired_units = hubDist diff --git a/python/plugins/processing/algs/qgis/HypsometricCurves.py b/python/plugins/processing/algs/qgis/HypsometricCurves.py index bcc8d9170882..bbbfd58b6882 100644 --- a/python/plugins/processing/algs/qgis/HypsometricCurves.py +++ b/python/plugins/processing/algs/qgis/HypsometricCurves.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'November 2014' -__copyright__ = '(C) 2014, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "November 2014" +__copyright__ = "(C) 2014, Alexander Bruy" import os import csv @@ -28,16 +28,18 @@ ogr.UseExceptions() osr.UseExceptions() -from qgis.core import (QgsRectangle, - QgsGeometry, - QgsFeatureRequest, - QgsProcessingException, - QgsProcessing, - QgsProcessingParameterBoolean, - QgsProcessingParameterNumber, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFolderDestination) +from qgis.core import ( + QgsRectangle, + QgsGeometry, + QgsFeatureRequest, + QgsProcessingException, + QgsProcessing, + QgsProcessingParameterBoolean, + QgsProcessingParameterNumber, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterFolderDestination, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.tools import raster @@ -46,45 +48,71 @@ class HypsometricCurves(QgisAlgorithm): - INPUT_DEM = 'INPUT_DEM' - BOUNDARY_LAYER = 'BOUNDARY_LAYER' - STEP = 'STEP' - USE_PERCENTAGE = 'USE_PERCENTAGE' - OUTPUT_DIRECTORY = 'OUTPUT_DIRECTORY' + INPUT_DEM = "INPUT_DEM" + BOUNDARY_LAYER = "BOUNDARY_LAYER" + STEP = "STEP" + USE_PERCENTAGE = "USE_PERCENTAGE" + OUTPUT_DIRECTORY = "OUTPUT_DIRECTORY" def group(self): - return self.tr('Raster terrain analysis') + return self.tr("Raster terrain analysis") def groupId(self): - return 'rasterterrainanalysis' + return "rasterterrainanalysis" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT_DEM, - self.tr('DEM to analyze'))) - self.addParameter(QgsProcessingParameterFeatureSource(self.BOUNDARY_LAYER, - self.tr('Boundary layer'), [QgsProcessing.SourceType.TypeVectorPolygon])) - self.addParameter(QgsProcessingParameterNumber(self.STEP, - self.tr('Step'), type=QgsProcessingParameterNumber.Type.Double, minValue=0.0, defaultValue=100.0)) - self.addParameter(QgsProcessingParameterBoolean(self.USE_PERCENTAGE, - self.tr('Use % of area instead of absolute value'), defaultValue=False)) - - self.addParameter(QgsProcessingParameterFolderDestination(self.OUTPUT_DIRECTORY, - self.tr('Hypsometric curves'))) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT_DEM, self.tr("DEM to analyze")) + ) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.BOUNDARY_LAYER, + self.tr("Boundary layer"), + [QgsProcessing.SourceType.TypeVectorPolygon], + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.STEP, + self.tr("Step"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=100.0, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.USE_PERCENTAGE, + self.tr("Use % of area instead of absolute value"), + defaultValue=False, + ) + ) + + self.addParameter( + QgsProcessingParameterFolderDestination( + self.OUTPUT_DIRECTORY, self.tr("Hypsometric curves") + ) + ) def name(self): - return 'hypsometriccurves' + return "hypsometriccurves" def displayName(self): - return self.tr('Hypsometric curves') + return self.tr("Hypsometric curves") def processAlgorithm(self, parameters, context, feedback): try: import numpy except ImportError: - raise QgsProcessingException(QCoreApplication.translate('HypsometricCurves', 'This algorithm requires the Python “numpy” library. Please install this library and try again.')) + raise QgsProcessingException( + QCoreApplication.translate( + "HypsometricCurves", + "This algorithm requires the Python “numpy” library. Please install this library and try again.", + ) + ) raster_layer = self.parameterAsRasterLayer(parameters, self.INPUT_DEM, context) target_crs = raster_layer.crs() @@ -92,7 +120,9 @@ def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.BOUNDARY_LAYER, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.BOUNDARY_LAYER)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.BOUNDARY_LAYER) + ) step = self.parameterAsDouble(parameters, self.STEP, context) percentage = self.parameterAsBoolean(parameters, self.USE_PERCENTAGE, context) @@ -111,19 +141,25 @@ def processAlgorithm(self, parameters, context, feedback): rasterXSize = rasterDS.RasterXSize rasterYSize = rasterDS.RasterYSize - rasterBBox = QgsRectangle(geoTransform[0], - geoTransform[3] - cellYSize * rasterYSize, - geoTransform[0] + cellXSize * rasterXSize, - geoTransform[3]) + rasterBBox = QgsRectangle( + geoTransform[0], + geoTransform[3] - cellYSize * rasterYSize, + geoTransform[0] + cellXSize * rasterXSize, + geoTransform[3], + ) rasterGeom = QgsGeometry.fromRect(rasterBBox) crs = osr.SpatialReference() crs.ImportFromProj4(str(target_crs.toProj())) - memVectorDriver = ogr.GetDriverByName('Memory') - memRasterDriver = gdal.GetDriverByName('MEM') + memVectorDriver = ogr.GetDriverByName("Memory") + memRasterDriver = gdal.GetDriverByName("MEM") - features = source.getFeatures(QgsFeatureRequest().setDestinationCrs(target_crs, context.transformContext())) + features = source.getFeatures( + QgsFeatureRequest().setDestinationCrs( + target_crs, context.transformContext() + ) + ) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): @@ -138,12 +174,16 @@ def processAlgorithm(self, parameters, context, feedback): if intersectedGeom.isEmpty(): feedback.pushInfo( - self.tr('Feature {0} does not intersect raster or ' - 'entirely located in NODATA area').format(f.id())) + self.tr( + "Feature {0} does not intersect raster or " + "entirely located in NODATA area" + ).format(f.id()) + ) continue fName = os.path.join( - outputPath, f'histogram_{source.sourceName()}_{f.id()}.csv') + outputPath, f"histogram_{source.sourceName()}_{f.id()}.csv" + ) ogrGeom = ogr.CreateGeometryFromWkt(intersectedGeom.asWkt()) bbox = intersectedGeom.boundingBox() @@ -163,8 +203,10 @@ def processAlgorithm(self, parameters, context, feedback): if srcOffset[2] == 0 or srcOffset[3] == 0: feedback.pushInfo( - self.tr('Feature {0} is smaller than raster ' - 'cell size').format(f.id())) + self.tr("Feature {0} is smaller than raster " "cell size").format( + f.id() + ) + ) continue newGeoTransform = ( @@ -173,30 +215,35 @@ def processAlgorithm(self, parameters, context, feedback): 0.0, geoTransform[3] + srcOffset[1] * geoTransform[5], 0.0, - geoTransform[5] + geoTransform[5], ) - memVDS = memVectorDriver.CreateDataSource('out') - memLayer = memVDS.CreateLayer('poly', crs, ogr.wkbPolygon) + memVDS = memVectorDriver.CreateDataSource("out") + memLayer = memVDS.CreateLayer("poly", crs, ogr.wkbPolygon) ft = ogr.Feature(memLayer.GetLayerDefn()) ft.SetGeometry(ogrGeom) memLayer.CreateFeature(ft) ft.Destroy() - rasterizedDS = memRasterDriver.Create('', srcOffset[2], - srcOffset[3], 1, gdal.GDT_Byte) + rasterizedDS = memRasterDriver.Create( + "", srcOffset[2], srcOffset[3], 1, gdal.GDT_Byte + ) rasterizedDS.SetGeoTransform(newGeoTransform) gdal.RasterizeLayer(rasterizedDS, [1], memLayer, burn_values=[1]) rasterizedArray = rasterizedDS.ReadAsArray() srcArray = numpy.nan_to_num(srcArray) - masked = numpy.ma.MaskedArray(srcArray, - mask=numpy.logical_or(srcArray == noData, - numpy.logical_not(rasterizedArray))) + masked = numpy.ma.MaskedArray( + srcArray, + mask=numpy.logical_or( + srcArray == noData, numpy.logical_not(rasterizedArray) + ), + ) - self.calculateHypsometry(f.id(), fName, feedback, masked, - cellXSize, cellYSize, percentage, step) + self.calculateHypsometry( + f.id(), fName, feedback, masked, cellXSize, cellYSize, percentage, step + ) memVDS = None rasterizedDS = None @@ -206,14 +253,16 @@ def processAlgorithm(self, parameters, context, feedback): return {self.OUTPUT_DIRECTORY: outputPath} - def calculateHypsometry(self, fid, fName, feedback, data, pX, pY, - percentage, step): + def calculateHypsometry(self, fid, fName, feedback, data, pX, pY, percentage, step): out = dict() d = data.compressed() if d.size == 0: feedback.pushInfo( - self.tr('Feature {0} does not intersect raster or ' - 'entirely located in NODATA area').format(fid)) + self.tr( + "Feature {0} does not intersect raster or " + "entirely located in NODATA area" + ).format(fid) + ) return minValue = d.min() @@ -241,9 +290,9 @@ def calculateHypsometry(self, fid, fName, feedback, data, pX, pY, out[i[0]] = i[1] + out[prev] prev = i[0] - with open(fName, 'w', newline='', encoding='utf-8') as out_file: + with open(fName, "w", newline="", encoding="utf-8") as out_file: writer = csv.writer(out_file) - writer.writerow([self.tr('Area'), self.tr('Elevation')]) + writer.writerow([self.tr("Area"), self.tr("Elevation")]) for i in sorted(out.items()): writer.writerow([i[1], i[0]]) diff --git a/python/plugins/processing/algs/qgis/IdwInterpolation.py b/python/plugins/processing/algs/qgis/IdwInterpolation.py index 98b5e84b1afc..65f9b910bd72 100644 --- a/python/plugins/processing/algs/qgis/IdwInterpolation.py +++ b/python/plugins/processing/algs/qgis/IdwInterpolation.py @@ -15,97 +15,129 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'October 2016' -__copyright__ = '(C) 2016, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "October 2016" +__copyright__ = "(C) 2016, Alexander Bruy" import os import math from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsRectangle, - QgsProcessingUtils, - QgsProcessingParameterNumber, - QgsProcessingParameterExtent, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterDestination, - QgsProcessingException) -from qgis.analysis import (QgsInterpolator, - QgsIDWInterpolator, - QgsGridFileWriter) +from qgis.core import ( + QgsRectangle, + QgsProcessingUtils, + QgsProcessingParameterNumber, + QgsProcessingParameterExtent, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterDestination, + QgsProcessingException, +) +from qgis.analysis import QgsInterpolator, QgsIDWInterpolator, QgsGridFileWriter from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm -from processing.algs.qgis.ui.InterpolationWidgets import ParameterInterpolationData, ParameterPixelSize +from processing.algs.qgis.ui.InterpolationWidgets import ( + ParameterInterpolationData, + ParameterPixelSize, +) pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] class IdwInterpolation(QgisAlgorithm): - INTERPOLATION_DATA = 'INTERPOLATION_DATA' - DISTANCE_COEFFICIENT = 'DISTANCE_COEFFICIENT' - PIXEL_SIZE = 'PIXEL_SIZE' - COLUMNS = 'COLUMNS' - ROWS = 'ROWS' - EXTENT = 'EXTENT' - OUTPUT = 'OUTPUT' + INTERPOLATION_DATA = "INTERPOLATION_DATA" + DISTANCE_COEFFICIENT = "DISTANCE_COEFFICIENT" + PIXEL_SIZE = "PIXEL_SIZE" + COLUMNS = "COLUMNS" + ROWS = "ROWS" + EXTENT = "EXTENT" + OUTPUT = "OUTPUT" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'interpolation.png')) + return QIcon(os.path.join(pluginPath, "images", "interpolation.png")) def group(self): - return self.tr('Interpolation') + return self.tr("Interpolation") def groupId(self): - return 'interpolation' + return "interpolation" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(ParameterInterpolationData(self.INTERPOLATION_DATA, - self.tr('Input layer(s)'))) - self.addParameter(QgsProcessingParameterNumber(self.DISTANCE_COEFFICIENT, - self.tr('Distance coefficient P'), type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, maxValue=99.99, defaultValue=2.0)) - self.addParameter(QgsProcessingParameterExtent(self.EXTENT, - self.tr('Extent'), - optional=False)) - pixel_size_param = ParameterPixelSize(self.PIXEL_SIZE, - self.tr('Output raster size'), - layersData=self.INTERPOLATION_DATA, - extent=self.EXTENT, - minValue=0.0, - default=0.1) + self.addParameter( + ParameterInterpolationData( + self.INTERPOLATION_DATA, self.tr("Input layer(s)") + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.DISTANCE_COEFFICIENT, + self.tr("Distance coefficient P"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + maxValue=99.99, + defaultValue=2.0, + ) + ) + self.addParameter( + QgsProcessingParameterExtent(self.EXTENT, self.tr("Extent"), optional=False) + ) + pixel_size_param = ParameterPixelSize( + self.PIXEL_SIZE, + self.tr("Output raster size"), + layersData=self.INTERPOLATION_DATA, + extent=self.EXTENT, + minValue=0.0, + default=0.1, + ) self.addParameter(pixel_size_param) - cols_param = QgsProcessingParameterNumber(self.COLUMNS, - self.tr('Number of columns'), - optional=True, - minValue=0, maxValue=10000000) - cols_param.setFlags(cols_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden) + cols_param = QgsProcessingParameterNumber( + self.COLUMNS, + self.tr("Number of columns"), + optional=True, + minValue=0, + maxValue=10000000, + ) + cols_param.setFlags( + cols_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden + ) self.addParameter(cols_param) - rows_param = QgsProcessingParameterNumber(self.ROWS, - self.tr('Number of rows'), - optional=True, - minValue=0, maxValue=10000000) - rows_param.setFlags(rows_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden) + rows_param = QgsProcessingParameterNumber( + self.ROWS, + self.tr("Number of rows"), + optional=True, + minValue=0, + maxValue=10000000, + ) + rows_param.setFlags( + rows_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden + ) self.addParameter(rows_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, - self.tr('Interpolated'))) + self.addParameter( + QgsProcessingParameterRasterDestination( + self.OUTPUT, self.tr("Interpolated") + ) + ) def name(self): - return 'idwinterpolation' + return "idwinterpolation" def displayName(self): - return self.tr('IDW interpolation') + return self.tr("IDW interpolation") def processAlgorithm(self, parameters, context, feedback): - interpolationData = ParameterInterpolationData.parseValue(parameters[self.INTERPOLATION_DATA]) - coefficient = self.parameterAsDouble(parameters, self.DISTANCE_COEFFICIENT, context) + interpolationData = ParameterInterpolationData.parseValue( + parameters[self.INTERPOLATION_DATA] + ) + coefficient = self.parameterAsDouble( + parameters, self.DISTANCE_COEFFICIENT, context + ) bbox = self.parameterAsExtent(parameters, self.EXTENT, context) pixel_size = self.parameterAsDouble(parameters, self.PIXEL_SIZE, context) output = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) @@ -119,12 +151,13 @@ def processAlgorithm(self, parameters, context, feedback): if interpolationData is None: raise QgsProcessingException( - self.tr('You need to specify at least one input layer.')) + self.tr("You need to specify at least one input layer.") + ) layerData = [] layers = [] - for i, row in enumerate(interpolationData.split('::|::')): - v = row.split('::~::') + for i, row in enumerate(interpolationData.split("::|::")): + v = row.split("::~::") data = QgsInterpolator.LayerData() # need to keep a reference until interpolation is complete @@ -135,13 +168,19 @@ def processAlgorithm(self, parameters, context, feedback): data.valueSource = int(v[1]) data.interpolationAttribute = int(v[2]) - if data.valueSource == QgsInterpolator.ValueSource.ValueAttribute and data.interpolationAttribute == -1: - raise QgsProcessingException(self.tr( - 'Layer {} is set to use a value attribute, but no attribute was set').format(i + 1)) - - if v[3] == '0': + if ( + data.valueSource == QgsInterpolator.ValueSource.ValueAttribute + and data.interpolationAttribute == -1 + ): + raise QgsProcessingException( + self.tr( + "Layer {} is set to use a value attribute, but no attribute was set" + ).format(i + 1) + ) + + if v[3] == "0": data.sourceType = QgsInterpolator.SourceType.SourcePoints - elif v[3] == '1': + elif v[3] == "1": data.sourceType = QgsInterpolator.SourceType.SourceStructureLines else: data.sourceType = QgsInterpolator.SourceType.SourceBreakLines @@ -150,11 +189,7 @@ def processAlgorithm(self, parameters, context, feedback): interpolator = QgsIDWInterpolator(layerData) interpolator.setDistanceCoefficient(coefficient) - writer = QgsGridFileWriter(interpolator, - output, - bbox, - columns, - rows) + writer = QgsGridFileWriter(interpolator, output, bbox, columns, rows) writer.writeFile(feedback) return {self.OUTPUT: output} diff --git a/python/plugins/processing/algs/qgis/ImportIntoSpatialite.py b/python/plugins/processing/algs/qgis/ImportIntoSpatialite.py index 1923f991fb90..124344882c61 100644 --- a/python/plugins/processing/algs/qgis/ImportIntoSpatialite.py +++ b/python/plugins/processing/algs/qgis/ImportIntoSpatialite.py @@ -15,156 +15,228 @@ *************************************************************************** """ -__author__ = 'Mathieu Pellerin' -__date__ = 'October 2016' -__copyright__ = '(C) 2012, Mathieu Pellerin' - -from qgis.core import (QgsDataSourceUri, - QgsFeatureSink, - QgsProcessingAlgorithm, - QgsVectorLayerExporter, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterField, - QgsProcessingParameterString, - QgsProcessingParameterBoolean, - QgsWkbTypes, - QgsProviderRegistry, - QgsProviderConnectionException, - QgsAbstractDatabaseProviderConnection) +__author__ = "Mathieu Pellerin" +__date__ = "October 2016" +__copyright__ = "(C) 2012, Mathieu Pellerin" + +from qgis.core import ( + QgsDataSourceUri, + QgsFeatureSink, + QgsProcessingAlgorithm, + QgsVectorLayerExporter, + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterField, + QgsProcessingParameterString, + QgsProcessingParameterBoolean, + QgsWkbTypes, + QgsProviderRegistry, + QgsProviderConnectionException, + QgsAbstractDatabaseProviderConnection, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm class ImportIntoSpatialite(QgisAlgorithm): - DATABASE = 'DATABASE' - TABLENAME = 'TABLENAME' - INPUT = 'INPUT' - OVERWRITE = 'OVERWRITE' - CREATEINDEX = 'CREATEINDEX' - GEOMETRY_COLUMN = 'GEOMETRY_COLUMN' - LOWERCASE_NAMES = 'LOWERCASE_NAMES' - DROP_STRING_LENGTH = 'DROP_STRING_LENGTH' - FORCE_SINGLEPART = 'FORCE_SINGLEPART' - PRIMARY_KEY = 'PRIMARY_KEY' - ENCODING = 'ENCODING' + DATABASE = "DATABASE" + TABLENAME = "TABLENAME" + INPUT = "INPUT" + OVERWRITE = "OVERWRITE" + CREATEINDEX = "CREATEINDEX" + GEOMETRY_COLUMN = "GEOMETRY_COLUMN" + LOWERCASE_NAMES = "LOWERCASE_NAMES" + DROP_STRING_LENGTH = "DROP_STRING_LENGTH" + FORCE_SINGLEPART = "FORCE_SINGLEPART" + PRIMARY_KEY = "PRIMARY_KEY" + ENCODING = "ENCODING" def group(self): - return self.tr('Database') + return self.tr("Database") def groupId(self): - return 'database' + return "database" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Layer to import'), - types=[QgsProcessing.SourceType.TypeVector])) - self.addParameter(QgsProcessingParameterVectorLayer(self.DATABASE, self.tr('File database'), optional=False)) self.addParameter( - QgsProcessingParameterString(self.TABLENAME, self.tr('Table to import to (leave blank to use layer name)'), - optional=True)) - self.addParameter(QgsProcessingParameterField(self.PRIMARY_KEY, self.tr('Primary key field'), None, self.INPUT, - QgsProcessingParameterField.DataType.Any, False, True)) - self.addParameter(QgsProcessingParameterString(self.GEOMETRY_COLUMN, self.tr('Geometry column'), 'geom')) - self.addParameter(QgsProcessingParameterString(self.ENCODING, self.tr('Encoding'), 'UTF-8', optional=True)) - self.addParameter(QgsProcessingParameterBoolean(self.OVERWRITE, self.tr('Overwrite'), True)) - self.addParameter(QgsProcessingParameterBoolean(self.CREATEINDEX, self.tr('Create spatial index'), True)) + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Layer to import"), + types=[QgsProcessing.SourceType.TypeVector], + ) + ) self.addParameter( - QgsProcessingParameterBoolean(self.LOWERCASE_NAMES, self.tr('Convert field names to lowercase'), True)) - self.addParameter(QgsProcessingParameterBoolean(self.DROP_STRING_LENGTH, - self.tr('Drop length constraints on character fields'), False)) - self.addParameter(QgsProcessingParameterBoolean(self.FORCE_SINGLEPART, - self.tr('Create single-part geometries instead of multi-part'), - False)) + QgsProcessingParameterVectorLayer( + self.DATABASE, self.tr("File database"), optional=False + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.TABLENAME, + self.tr("Table to import to (leave blank to use layer name)"), + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.PRIMARY_KEY, + self.tr("Primary key field"), + None, + self.INPUT, + QgsProcessingParameterField.DataType.Any, + False, + True, + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.GEOMETRY_COLUMN, self.tr("Geometry column"), "geom" + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.ENCODING, self.tr("Encoding"), "UTF-8", optional=True + ) + ) + self.addParameter( + QgsProcessingParameterBoolean(self.OVERWRITE, self.tr("Overwrite"), True) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.CREATEINDEX, self.tr("Create spatial index"), True + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.LOWERCASE_NAMES, self.tr("Convert field names to lowercase"), True + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.DROP_STRING_LENGTH, + self.tr("Drop length constraints on character fields"), + False, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.FORCE_SINGLEPART, + self.tr("Create single-part geometries instead of multi-part"), + False, + ) + ) def flags(self): return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading def name(self): - return 'importintospatialite' + return "importintospatialite" def displayName(self): - return self.tr('Export to SpatiaLite') + return self.tr("Export to SpatiaLite") def shortDescription(self): - return self.tr('Exports a vector layer to a SpatiaLite database') + return self.tr("Exports a vector layer to a SpatiaLite database") def tags(self): - return self.tr('import,table,layer,into,copy').split(',') + return self.tr("import,table,layer,into,copy").split(",") def processAlgorithm(self, parameters, context, feedback): database = self.parameterAsVectorLayer(parameters, self.DATABASE, context) databaseuri = database.dataProvider().dataSourceUri() uri = QgsDataSourceUri(databaseuri) - if uri.database() == '': - if '|layername' in databaseuri: - databaseuri = databaseuri[:databaseuri.find('|layername')] - elif '|layerid' in databaseuri: - databaseuri = databaseuri[:databaseuri.find('|layerid')] - uri = QgsDataSourceUri('dbname=\'%s\'' % (databaseuri)) + if uri.database() == "": + if "|layername" in databaseuri: + databaseuri = databaseuri[: databaseuri.find("|layername")] + elif "|layerid" in databaseuri: + databaseuri = databaseuri[: databaseuri.find("|layerid")] + uri = QgsDataSourceUri("dbname='%s'" % (databaseuri)) try: - md = QgsProviderRegistry.instance().providerMetadata('spatialite') + md = QgsProviderRegistry.instance().providerMetadata("spatialite") conn = md.createConnection(uri.uri(), {}) except QgsProviderConnectionException: - raise QgsProcessingException(self.tr('Could not connect to {}').format(uri.uri())) + raise QgsProcessingException( + self.tr("Could not connect to {}").format(uri.uri()) + ) overwrite = self.parameterAsBoolean(parameters, self.OVERWRITE, context) createIndex = self.parameterAsBoolean(parameters, self.CREATEINDEX, context) - convertLowerCase = self.parameterAsBoolean(parameters, self.LOWERCASE_NAMES, context) - dropStringLength = self.parameterAsBoolean(parameters, self.DROP_STRING_LENGTH, context) - forceSinglePart = self.parameterAsBoolean(parameters, self.FORCE_SINGLEPART, context) - primaryKeyField = self.parameterAsString(parameters, self.PRIMARY_KEY, context) or 'id' + convertLowerCase = self.parameterAsBoolean( + parameters, self.LOWERCASE_NAMES, context + ) + dropStringLength = self.parameterAsBoolean( + parameters, self.DROP_STRING_LENGTH, context + ) + forceSinglePart = self.parameterAsBoolean( + parameters, self.FORCE_SINGLEPART, context + ) + primaryKeyField = ( + self.parameterAsString(parameters, self.PRIMARY_KEY, context) or "id" + ) encoding = self.parameterAsString(parameters, self.ENCODING, context) source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) table = self.parameterAsString(parameters, self.TABLENAME, context) if table: table.strip() - if not table or table == '': + if not table or table == "": table = source.sourceName() - table = table.replace('.', '_') - table = table.replace(' ', '').lower() - providerName = 'spatialite' + table = table.replace(".", "_") + table = table.replace(" ", "").lower() + providerName = "spatialite" geomColumn = self.parameterAsString(parameters, self.GEOMETRY_COLUMN, context) if not geomColumn: - geomColumn = 'geom' + geomColumn = "geom" options = {} if overwrite: - options['overwrite'] = True + options["overwrite"] = True if convertLowerCase: - options['lowercaseFieldNames'] = True + options["lowercaseFieldNames"] = True geomColumn = geomColumn.lower() if dropStringLength: - options['dropStringConstraints'] = True + options["dropStringConstraints"] = True if forceSinglePart: - options['forceSinglePartGeometryType'] = True + options["forceSinglePartGeometryType"] = True # Clear geometry column for non-geometry tables if source.wkbType() == QgsWkbTypes.Type.NoGeometry: geomColumn = None - uri.setDataSource('', table, geomColumn, '', primaryKeyField) + uri.setDataSource("", table, geomColumn, "", primaryKeyField) if encoding: - options['fileEncoding'] = encoding - - exporter = QgsVectorLayerExporter(uri.uri(), providerName, source.fields(), - source.wkbType(), source.sourceCrs(), overwrite, options) + options["fileEncoding"] = encoding + + exporter = QgsVectorLayerExporter( + uri.uri(), + providerName, + source.fields(), + source.wkbType(), + source.sourceCrs(), + overwrite, + options, + ) if exporter.errorCode() != QgsVectorLayerExporter.ExportError.NoError: raise QgsProcessingException( - self.tr('Error importing to Spatialite\n{0}').format(exporter.errorMessage())) + self.tr("Error importing to Spatialite\n{0}").format( + exporter.errorMessage() + ) + ) features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 @@ -180,14 +252,19 @@ def processAlgorithm(self, parameters, context, feedback): exporter.flushBuffer() if exporter.errorCode() != QgsVectorLayerExporter.ExportError.NoError: raise QgsProcessingException( - self.tr('Error importing to Spatialite\n{0}').format(exporter.errorMessage())) + self.tr("Error importing to Spatialite\n{0}").format( + exporter.errorMessage() + ) + ) if geomColumn and createIndex: try: options = QgsAbstractDatabaseProviderConnection.SpatialIndexOptions() options.geometryColumnName = geomColumn - conn.createSpatialIndex('', table, options) + conn.createSpatialIndex("", table, options) except QgsProviderConnectionException as e: - raise QgsProcessingException(self.tr('Error creating spatial index:\n{0}').format(e)) + raise QgsProcessingException( + self.tr("Error creating spatial index:\n{0}").format(e) + ) return {} diff --git a/python/plugins/processing/algs/qgis/KNearestConcaveHull.py b/python/plugins/processing/algs/qgis/KNearestConcaveHull.py index ce968f6278ed..aa108b839776 100644 --- a/python/plugins/processing/algs/qgis/KNearestConcaveHull.py +++ b/python/plugins/processing/algs/qgis/KNearestConcaveHull.py @@ -18,9 +18,9 @@ ***************************************************************************/ """ -__author__ = 'Detlev Neumann' -__date__ = 'November 2014' -__copyright__ = '(C) 2014, Detlev Neumann' +__author__ = "Detlev Neumann" +__date__ = "November 2014" +__copyright__ = "(C) 2014, Detlev Neumann" import os.path import math @@ -28,41 +28,43 @@ from qgis.PyQt.QtGui import QIcon from qgis.PyQt.QtCore import QMetaType -from qgis.core import (QgsApplication, - QgsExpression, - QgsFeature, - QgsFeatureRequest, - QgsFeatureSink, - QgsField, - QgsFields, - QgsGeometry, - QgsProcessing, - QgsProcessingAlgorithm, - QgsProcessingException, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterField, - QgsProcessingParameterNumber, - QgsPoint, - QgsPointXY, - QgsWkbTypes) +from qgis.core import ( + QgsApplication, + QgsExpression, + QgsFeature, + QgsFeatureRequest, + QgsFeatureSink, + QgsField, + QgsFields, + QgsGeometry, + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingException, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingParameterNumber, + QgsPoint, + QgsPointXY, + QgsWkbTypes, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm class KNearestConcaveHull(QgisAlgorithm): - KNEIGHBORS = 'KNEIGHBORS' - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' - FIELD = 'FIELD' + KNEIGHBORS = "KNEIGHBORS" + INPUT = "INPUT" + OUTPUT = "OUTPUT" + FIELD = "FIELD" def name(self): - return 'knearestconcavehull' + return "knearestconcavehull" def displayName(self): - return self.tr('Concave hull (k-nearest neighbor)') + return self.tr("Concave hull (k-nearest neighbor)") def shortDescription(self): - return self.tr('Creates a concave hull using the k-nearest neighbor algorithm.') + return self.tr("Creates a concave hull using the k-nearest neighbor algorithm.") def icon(self): return QgsApplication.getThemeIcon("/algorithms/mAlgorithmConcaveHull.svg") @@ -71,35 +73,59 @@ def svgIconPath(self): return QgsApplication.iconPath("/algorithms/mAlgorithmConcaveHull.svg") def group(self): - return self.tr('Vector geometry') + return self.tr("Vector geometry") def groupId(self): - return 'vectorgeometry' + return "vectorgeometry" def flags(self): - return super().flags() | QgsProcessingAlgorithm.Flag.FlagDeprecated | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool + return ( + super().flags() + | QgsProcessingAlgorithm.Flag.FlagDeprecated + | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool + ) def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterNumber(self.KNEIGHBORS, - self.tr('Number of neighboring points to consider (a lower number is more concave, a higher number is smoother)'), - QgsProcessingParameterNumber.Type.Integer, - defaultValue=3, minValue=3)) - self.addParameter(QgsProcessingParameterField(self.FIELD, - self.tr('Field (set if creating concave hulls by class)'), - parentLayerParameterName=self.INPUT, optional=True)) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Concave hull'), - QgsProcessing.SourceType.TypeVectorPolygon)) + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.KNEIGHBORS, + self.tr( + "Number of neighboring points to consider (a lower number is more concave, a higher number is smoother)" + ), + QgsProcessingParameterNumber.Type.Integer, + defaultValue=3, + minValue=3, + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.FIELD, + self.tr("Field (set if creating concave hulls by class)"), + parentLayerParameterName=self.INPUT, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterFeatureSink( + self.OUTPUT, + self.tr("Concave hull"), + QgsProcessing.SourceType.TypeVectorPolygon, + ) + ) def processAlgorithm(self, parameters, context, feedback): # Get variables from dialog source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) field_name = self.parameterAsString(parameters, self.FIELD, context) kneighbors = self.parameterAsInt(parameters, self.KNEIGHBORS, context) @@ -108,7 +134,7 @@ def processAlgorithm(self, parameters, context, feedback): field_index = -1 fields = QgsFields() - fields.append(QgsField('id', QMetaType.Type.Int, '', 20)) + fields.append(QgsField("id", QMetaType.Type.Int, "", 20)) current = 0 @@ -116,13 +142,23 @@ def processAlgorithm(self, parameters, context, feedback): if use_field: field_index = source.fields().lookupField(field_name) if field_index >= 0: - fields.append(source.fields()[field_index]) # Add a field with the name of the grouping field + fields.append( + source.fields()[field_index] + ) # Add a field with the name of the grouping field # Initialize writer - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, QgsWkbTypes.Type.Polygon, source.sourceCrs()) + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + fields, + QgsWkbTypes.Type.Polygon, + source.sourceCrs(), + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT) + ) success = False fid = 0 @@ -133,7 +169,9 @@ def processAlgorithm(self, parameters, context, feedback): for unique in unique_values: points = [] - filter = QgsExpression.createFieldEqualityExpression(field_name, unique) + filter = QgsExpression.createFieldEqualityExpression( + field_name, unique + ) request = QgsFeatureRequest().setFilterExpression(filter) request.setSubsetOfAttributes([]) # Get features with the grouping attribute equal to the current grouping value @@ -150,7 +188,9 @@ def processAlgorithm(self, parameters, context, feedback): out_feature = QgsFeature() the_hull = concave_hull(points, kneighbors) if the_hull: - vertex = [QgsPointXY(point[0], point[1]) for point in the_hull] + vertex = [ + QgsPointXY(point[0], point[1]) for point in the_hull + ] poly = QgsGeometry().fromPolygonXY([vertex]) out_feature.setGeometry(poly) @@ -160,19 +200,29 @@ def processAlgorithm(self, parameters, context, feedback): success = True # at least one polygon created fid += 1 if not success: - raise QgsProcessingException('No hulls could be created. Most likely there were not at least three unique points in any of the groups.') + raise QgsProcessingException( + "No hulls could be created. Most likely there were not at least three unique points in any of the groups." + ) sink.finalize() else: # Field parameter provided but can't read from it - raise QgsProcessingException('Unable to find grouping field') + raise QgsProcessingException("Unable to find grouping field") else: # Not grouped by field # Initialize writer - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, QgsWkbTypes.Type.Polygon, source.sourceCrs()) + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + fields, + QgsWkbTypes.Type.Polygon, + source.sourceCrs(), + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT) + ) points = [] request = QgsFeatureRequest() @@ -200,9 +250,13 @@ def processAlgorithm(self, parameters, context, feedback): sink.addFeature(out_feature, QgsFeatureSink.Flag.FastInsert) else: # the_hull returns None only when there are less than three points after cleaning - raise QgsProcessingException('At least three unique points are required to create a concave hull.') + raise QgsProcessingException( + "At least three unique points are required to create a concave hull." + ) else: - raise QgsProcessingException('At least three points are required to create a concave hull.') + raise QgsProcessingException( + "At least three points are required to create a concave hull." + ) sink.finalize() @@ -225,7 +279,9 @@ def find_min_y_point(list_of_points): """ min_y_pt = list_of_points[0] for point in list_of_points[1:]: - if point[1] < min_y_pt[1] or (point[1] == min_y_pt[1] and point[0] < min_y_pt[0]): + if point[1] < min_y_pt[1] or ( + point[1] == min_y_pt[1] and point[0] < min_y_pt[0] + ): min_y_pt = point return min_y_pt @@ -254,7 +310,9 @@ def euclidean_distance(point1, point2): :param point2: tuple (x, y) :return: float """ - return math.sqrt(math.pow(point1[0] - point2[0], 2) + math.pow(point1[1] - point2[1], 2)) + return math.sqrt( + math.pow(point1[0] - point2[0], 2) + math.pow(point1[1] - point2[1], 2) + ) def nearest_points(list_of_points, point, k): @@ -272,7 +330,9 @@ def nearest_points(list_of_points, point, k): # their respective index of list *list_of_distances* list_of_distances = [] for index in range(len(list_of_points)): - list_of_distances.append((euclidean_distance(list_of_points[index], point), index)) + list_of_distances.append( + (euclidean_distance(list_of_points[index], point), index) + ) # sort distances in ascending order list_of_distances.sort() @@ -335,16 +395,24 @@ def intersect(line1, line2): a2 = line2[1][1] - line2[0][1] b2 = line2[0][0] - line2[1][0] c2 = a2 * line2[0][0] + b2 * line2[0][1] - tmp = (a1 * b2 - a2 * b1) + tmp = a1 * b2 - a2 * b1 if tmp == 0: return False sx = (c1 * b2 - c2 * b1) / tmp - if (sx > line1[0][0] and sx > line1[1][0]) or (sx > line2[0][0] and sx > line2[1][0]) or\ - (sx < line1[0][0] and sx < line1[1][0]) or (sx < line2[0][0] and sx < line2[1][0]): + if ( + (sx > line1[0][0] and sx > line1[1][0]) + or (sx > line2[0][0] and sx > line2[1][0]) + or (sx < line1[0][0] and sx < line1[1][0]) + or (sx < line2[0][0] and sx < line2[1][0]) + ): return False sy = (a1 * c2 - a2 * c1) / tmp - if (sy > line1[0][1] and sy > line1[1][1]) or (sy > line2[0][1] and sy > line2[1][1]) or\ - (sy < line1[0][1] and sy < line1[1][1]) or (sy < line2[0][1] and sy < line2[1][1]): + if ( + (sy > line1[0][1] and sy > line1[1][1]) + or (sy > line2[0][1] and sy > line2[1][1]) + or (sy < line1[0][1] and sy < line1[1][1]) + or (sy < line2[0][1] and sy < line2[1][1]) + ): return False return True @@ -516,7 +584,10 @@ def concave_hull(points_list, k): its = False while its is False and (j < len(hull) - last_point): - its = intersect((hull[step - 2], c_points[i]), (hull[step - 2 - j], hull[step - 1 - j])) + its = intersect( + (hull[step - 2], c_points[i]), + (hull[step - 2 - j], hull[step - 1 - j]), + ) j += 1 # there is no candidate to which the connecting line does not intersect any existing segment, so the diff --git a/python/plugins/processing/algs/qgis/LinesToPolygons.py b/python/plugins/processing/algs/qgis/LinesToPolygons.py index 7a0e457aae48..fb5bfbd68ed3 100644 --- a/python/plugins/processing/algs/qgis/LinesToPolygons.py +++ b/python/plugins/processing/algs/qgis/LinesToPolygons.py @@ -15,27 +15,29 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsApplication, - QgsFeature, - QgsGeometry, - QgsGeometryCollection, - QgsPolygon, - QgsMultiPolygon, - QgsMultiSurface, - QgsWkbTypes, - QgsFeatureSink, - QgsProcessing, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, - QgsProcessingUtils) +from qgis.core import ( + QgsApplication, + QgsFeature, + QgsGeometry, + QgsGeometryCollection, + QgsPolygon, + QgsMultiPolygon, + QgsMultiSurface, + QgsWkbTypes, + QgsFeatureSink, + QgsProcessing, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterFeatureSink, + QgsProcessingUtils, +) from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm from processing.tools import dataobjects, vector @@ -52,25 +54,25 @@ def svgIconPath(self): return QgsApplication.iconPath("/algorithms/mAlgorithmLineToPolygon.svg") def tags(self): - return self.tr('line,polygon,convert').split(',') + return self.tr("line,polygon,convert").split(",") def group(self): - return self.tr('Vector geometry') + return self.tr("Vector geometry") def groupId(self): - return 'vectorgeometry' + return "vectorgeometry" def __init__(self): super().__init__() def name(self): - return 'linestopolygons' + return "linestopolygons" def displayName(self): - return self.tr('Lines to polygons') + return self.tr("Lines to polygons") def outputName(self): - return self.tr('Polygons') + return self.tr("Polygons") def outputType(self): return QgsProcessing.SourceType.TypeVectorPolygon @@ -85,7 +87,11 @@ def processFeature(self, feature, context, feedback): if feature.hasGeometry(): feature.setGeometry(QgsGeometry(self.convertToPolygons(feature.geometry()))) if feature.geometry().isEmpty(): - feedback.reportError(self.tr("One or more line ignored due to geometry not having a minimum of three vertices.")) + feedback.reportError( + self.tr( + "One or more line ignored due to geometry not having a minimum of three vertices." + ) + ) return [feature] def supportInPlaceEdit(self, layer): @@ -93,9 +99,15 @@ def supportInPlaceEdit(self, layer): def convertWkbToPolygons(self, wkb): multi_wkb = QgsWkbTypes.Type.NoGeometry - if QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb)) == QgsWkbTypes.Type.LineString: + if ( + QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb)) + == QgsWkbTypes.Type.LineString + ): multi_wkb = QgsWkbTypes.Type.MultiPolygon - elif QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb)) == QgsWkbTypes.Type.CompoundCurve: + elif ( + QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb)) + == QgsWkbTypes.Type.CompoundCurve + ): multi_wkb = QgsWkbTypes.Type.MultiSurface if QgsWkbTypes.hasM(wkb): multi_wkb = QgsWkbTypes.addM(multi_wkb) diff --git a/python/plugins/processing/algs/qgis/MeanAndStdDevPlot.py b/python/plugins/processing/algs/qgis/MeanAndStdDevPlot.py index acf235e7d5a5..24263c7e611f 100644 --- a/python/plugins/processing/algs/qgis/MeanAndStdDevPlot.py +++ b/python/plugins/processing/algs/qgis/MeanAndStdDevPlot.py @@ -15,16 +15,18 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'January 2013' -__copyright__ = '(C) 2013, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "January 2013" +__copyright__ = "(C) 2013, Victor Olaya" import warnings -from qgis.core import (QgsProcessingParameterFeatureSource, - QgsProcessingParameterField, - QgsProcessingException, - QgsProcessingParameterFileDestination) +from qgis.core import ( + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingException, + QgsProcessingParameterFileDestination, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.tools import vector @@ -33,38 +35,52 @@ class MeanAndStdDevPlot(QgisAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' - NAME_FIELD = 'NAME_FIELD' - VALUE_FIELD = 'VALUE_FIELD' + INPUT = "INPUT" + OUTPUT = "OUTPUT" + NAME_FIELD = "NAME_FIELD" + VALUE_FIELD = "VALUE_FIELD" def group(self): - return self.tr('Plots') + return self.tr("Plots") def groupId(self): - return 'plots' + return "plots" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input table'))) - self.addParameter(QgsProcessingParameterField(self.NAME_FIELD, - self.tr('Category name field'), parentLayerParameterName=self.INPUT, - type=QgsProcessingParameterField.DataType.Any)) - self.addParameter(QgsProcessingParameterField(self.VALUE_FIELD, - self.tr('Value field'), - parentLayerParameterName=self.INPUT, - type=QgsProcessingParameterField.DataType.Numeric)) - - self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, self.tr('Plot'), self.tr('HTML files (*.html)'))) + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input table")) + ) + self.addParameter( + QgsProcessingParameterField( + self.NAME_FIELD, + self.tr("Category name field"), + parentLayerParameterName=self.INPUT, + type=QgsProcessingParameterField.DataType.Any, + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.VALUE_FIELD, + self.tr("Value field"), + parentLayerParameterName=self.INPUT, + type=QgsProcessingParameterField.DataType.Numeric, + ) + ) + + self.addParameter( + QgsProcessingParameterFileDestination( + self.OUTPUT, self.tr("Plot"), self.tr("HTML files (*.html)") + ) + ) def name(self): - return 'meanandstandarddeviationplot' + return "meanandstandarddeviationplot" def displayName(self): - return self.tr('Mean and standard deviation plot') + return self.tr("Mean and standard deviation plot") def processAlgorithm(self, parameters, context, feedback): try: @@ -75,11 +91,18 @@ def processAlgorithm(self, parameters, context, feedback): import plotly as plt import plotly.graph_objs as go except ImportError: - raise QgsProcessingException(QCoreApplication.translate('MeanAndStdDevPlot', 'This algorithm requires the Python “plotly” library. Please install this library and try again.')) + raise QgsProcessingException( + QCoreApplication.translate( + "MeanAndStdDevPlot", + "This algorithm requires the Python “plotly” library. Please install this library and try again.", + ) + ) source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) namefieldname = self.parameterAsString(parameters, self.NAME_FIELD, context) valuefieldname = self.parameterAsString(parameters, self.VALUE_FIELD, context) @@ -96,12 +119,7 @@ def processAlgorithm(self, parameters, context, feedback): else: d[v].append(values[valuefieldname][i]) - data = [ - go.Box(y=list(v), - boxmean='sd', - name=k) - for k, v in d.items() - ] + data = [go.Box(y=list(v), boxmean="sd", name=k) for k, v in d.items()] plt.offline.plot(data, filename=output, auto_open=False) return {self.OUTPUT: output} diff --git a/python/plugins/processing/algs/qgis/MinimumBoundingGeometry.py b/python/plugins/processing/algs/qgis/MinimumBoundingGeometry.py index 28f9914f0824..bf85f48efda0 100644 --- a/python/plugins/processing/algs/qgis/MinimumBoundingGeometry.py +++ b/python/plugins/processing/algs/qgis/MinimumBoundingGeometry.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'September 2017' -__copyright__ = '(C) 2017, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "September 2017" +__copyright__ = "(C) 2017, Nyall Dawson" import os import math @@ -25,23 +25,25 @@ from qgis.PyQt.QtGui import QIcon from qgis.PyQt.QtCore import QMetaType -from qgis.core import (QgsApplication, - QgsField, - QgsFeatureSink, - QgsGeometry, - QgsWkbTypes, - QgsFeatureRequest, - QgsFields, - QgsRectangle, - QgsProcessingException, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterField, - QgsProcessingParameterEnum, - QgsProcessingParameterFeatureSink, - QgsProcessing, - QgsFeature, - QgsVertexId, - QgsMultiPoint) +from qgis.core import ( + QgsApplication, + QgsField, + QgsFeatureSink, + QgsGeometry, + QgsWkbTypes, + QgsFeatureRequest, + QgsFields, + QgsRectangle, + QgsProcessingException, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingParameterEnum, + QgsProcessingParameterFeatureSink, + QgsProcessing, + QgsFeature, + QgsVertexId, + QgsMultiPoint, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm @@ -49,10 +51,10 @@ class MinimumBoundingGeometry(QgisAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' - TYPE = 'TYPE' - FIELD = 'FIELD' + INPUT = "INPUT" + OUTPUT = "OUTPUT" + TYPE = "TYPE" + FIELD = "FIELD" def icon(self): return QgsApplication.getThemeIcon("/algorithms/mAlgorithmConvexHull.svg") @@ -61,45 +63,62 @@ def svgIconPath(self): return QgsApplication.iconPath("/algorithms/mAlgorithmConvexHull.svg") def group(self): - return self.tr('Vector geometry') + return self.tr("Vector geometry") def groupId(self): - return 'vectorgeometry' + return "vectorgeometry" def __init__(self): super().__init__() - self.type_names = [self.tr('Envelope (Bounding Box)'), - self.tr('Minimum Oriented Rectangle'), - self.tr('Minimum Enclosing Circle'), - self.tr('Convex Hull')] + self.type_names = [ + self.tr("Envelope (Bounding Box)"), + self.tr("Minimum Oriented Rectangle"), + self.tr("Minimum Enclosing Circle"), + self.tr("Convex Hull"), + ] def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterField(self.FIELD, - self.tr( - 'Field (optional, set if features should be grouped by class)'), - parentLayerParameterName=self.INPUT, optional=True)) - self.addParameter(QgsProcessingParameterEnum(self.TYPE, - self.tr('Geometry type'), options=self.type_names)) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Bounding geometry'), - QgsProcessing.SourceType.TypeVectorPolygon)) + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterField( + self.FIELD, + self.tr("Field (optional, set if features should be grouped by class)"), + parentLayerParameterName=self.INPUT, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.TYPE, self.tr("Geometry type"), options=self.type_names + ) + ) + self.addParameter( + QgsProcessingParameterFeatureSink( + self.OUTPUT, + self.tr("Bounding geometry"), + QgsProcessing.SourceType.TypeVectorPolygon, + ) + ) def name(self): - return 'minimumboundinggeometry' + return "minimumboundinggeometry" def displayName(self): - return self.tr('Minimum bounding geometry') + return self.tr("Minimum bounding geometry") def tags(self): return self.tr( - 'bounding,box,bounds,envelope,minimum,oriented,rectangle,enclosing,circle,convex,hull,generalization').split( - ',') + "bounding,box,bounds,envelope,minimum,oriented,rectangle,enclosing,circle,convex,hull,generalization" + ).split(",") def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) field_name = self.parameterAsString(parameters, self.FIELD, context) type = self.parameterAsEnum(parameters, self.TYPE, context) @@ -108,7 +127,7 @@ def processAlgorithm(self, parameters, context, feedback): field_index = -1 fields = QgsFields() - fields.append(QgsField('id', QMetaType.Type.Int, '', 20)) + fields.append(QgsField("id", QMetaType.Type.Int, "", 20)) if use_field: # keep original field type, name and parameters @@ -117,28 +136,34 @@ def processAlgorithm(self, parameters, context, feedback): fields.append(source.fields()[field_index]) if type == 0: # envelope - fields.append(QgsField('width', QMetaType.Type.Double, '', 20, 6)) - fields.append(QgsField('height', QMetaType.Type.Double, '', 20, 6)) - fields.append(QgsField('area', QMetaType.Type.Double, '', 20, 6)) - fields.append(QgsField('perimeter', QMetaType.Type.Double, '', 20, 6)) + fields.append(QgsField("width", QMetaType.Type.Double, "", 20, 6)) + fields.append(QgsField("height", QMetaType.Type.Double, "", 20, 6)) + fields.append(QgsField("area", QMetaType.Type.Double, "", 20, 6)) + fields.append(QgsField("perimeter", QMetaType.Type.Double, "", 20, 6)) elif type == 1: # oriented rect - fields.append(QgsField('width', QMetaType.Type.Double, '', 20, 6)) - fields.append(QgsField('height', QMetaType.Type.Double, '', 20, 6)) - fields.append(QgsField('angle', QMetaType.Type.Double, '', 20, 6)) - fields.append(QgsField('area', QMetaType.Type.Double, '', 20, 6)) - fields.append(QgsField('perimeter', QMetaType.Type.Double, '', 20, 6)) + fields.append(QgsField("width", QMetaType.Type.Double, "", 20, 6)) + fields.append(QgsField("height", QMetaType.Type.Double, "", 20, 6)) + fields.append(QgsField("angle", QMetaType.Type.Double, "", 20, 6)) + fields.append(QgsField("area", QMetaType.Type.Double, "", 20, 6)) + fields.append(QgsField("perimeter", QMetaType.Type.Double, "", 20, 6)) elif type == 2: # circle - fields.append(QgsField('radius', QMetaType.Type.Double, '', 20, 6)) - fields.append(QgsField('area', QMetaType.Type.Double, '', 20, 6)) + fields.append(QgsField("radius", QMetaType.Type.Double, "", 20, 6)) + fields.append(QgsField("area", QMetaType.Type.Double, "", 20, 6)) elif type == 3: # convex hull - fields.append(QgsField('area', QMetaType.Type.Double, '', 20, 6)) - fields.append(QgsField('perimeter', QMetaType.Type.Double, '', 20, 6)) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, QgsWkbTypes.Type.Polygon, source.sourceCrs()) + fields.append(QgsField("area", QMetaType.Type.Double, "", 20, 6)) + fields.append(QgsField("perimeter", QMetaType.Type.Double, "", 20, 6)) + + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + fields, + QgsWkbTypes.Type.Polygon, + source.sourceCrs(), + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) @@ -146,7 +171,9 @@ def processAlgorithm(self, parameters, context, feedback): geometry_dict = {} bounds_dict = {} total = 50.0 / source.featureCount() if source.featureCount() else 1 - features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([field_index])) + features = source.getFeatures( + QgsFeatureRequest().setSubsetOfAttributes([field_index]) + ) for current, f in enumerate(features): if feedback.isCanceled(): break @@ -159,7 +186,9 @@ def processAlgorithm(self, parameters, context, feedback): if f[field_index] not in bounds_dict: bounds_dict[f[field_index]] = f.geometry().boundingBox() else: - bounds_dict[f[field_index]].combineExtentWith(f.geometry().boundingBox()) + bounds_dict[f[field_index]].combineExtentWith( + f.geometry().boundingBox() + ) else: if f[field_index] not in geometry_dict: geometry_dict[f[field_index]] = [f.geometry()] @@ -179,7 +208,16 @@ def processAlgorithm(self, parameters, context, feedback): # envelope feature = QgsFeature() feature.setGeometry(QgsGeometry.fromRect(rect)) - feature.setAttributes([current, group, rect.width(), rect.height(), rect.area(), rect.perimeter()]) + feature.setAttributes( + [ + current, + group, + rect.width(), + rect.height(), + rect.area(), + rect.perimeter(), + ] + ) sink.addFeature(feature, QgsFeatureSink.Flag.FastInsert) geometry_dict[group] = None @@ -192,7 +230,9 @@ def processAlgorithm(self, parameters, context, feedback): if feedback.isCanceled(): break - feature = self.createFeature(feedback, current, type, geometries, group) + feature = self.createFeature( + feedback, current, type, geometries, group + ) sink.addFeature(feature, QgsFeatureSink.Flag.FastInsert) geometry_dict[group] = None @@ -221,7 +261,15 @@ def processAlgorithm(self, parameters, context, feedback): if type == 0: feature = QgsFeature() feature.setGeometry(QgsGeometry.fromRect(bounds)) - feature.setAttributes([0, bounds.width(), bounds.height(), bounds.area(), bounds.perimeter()]) + feature.setAttributes( + [ + 0, + bounds.width(), + bounds.height(), + bounds.area(), + bounds.perimeter(), + ] + ) else: feature = self.createFeature(feedback, 0, type, geometry_queue) sink.addFeature(feature, QgsFeatureSink.Flag.FastInsert) @@ -262,7 +310,9 @@ def createFeature(self, feedback, feature_id, type, geometries, class_field=None attrs.append(rect.perimeter()) elif type == 1: # oriented rect - output_geometry, area, angle, width, height = geometry.orientedMinimumBoundingBox() + output_geometry, area, angle, width, height = ( + geometry.orientedMinimumBoundingBox() + ) attrs.append(width) attrs.append(height) attrs.append(angle) @@ -270,7 +320,9 @@ def createFeature(self, feedback, feature_id, type, geometries, class_field=None attrs.append(2 * width + 2 * height) elif type == 2: # circle - output_geometry, center, radius = geometry.minimalEnclosingCircle(segments=72) + output_geometry, center, radius = geometry.minimalEnclosingCircle( + segments=72 + ) attrs.append(radius) attrs.append(math.pi * radius * radius) elif type == 3: diff --git a/python/plugins/processing/algs/qgis/PointDistance.py b/python/plugins/processing/algs/qgis/PointDistance.py index 7b1be14e82e9..73e2e2d78af1 100644 --- a/python/plugins/processing/algs/qgis/PointDistance.py +++ b/python/plugins/processing/algs/qgis/PointDistance.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import math @@ -25,24 +25,26 @@ from qgis.PyQt.QtGui import QIcon from qgis.PyQt.QtCore import QMetaType -from qgis.core import (QgsApplication, - QgsFeatureRequest, - QgsField, - QgsFields, - QgsProject, - QgsFeature, - QgsGeometry, - QgsDistanceArea, - QgsFeatureSink, - QgsProcessingParameterFeatureSource, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterEnum, - QgsProcessingParameterField, - QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSink, - QgsSpatialIndex, - QgsWkbTypes) +from qgis.core import ( + QgsApplication, + QgsFeatureRequest, + QgsField, + QgsFields, + QgsProject, + QgsFeature, + QgsGeometry, + QgsDistanceArea, + QgsFeatureSink, + QgsProcessingParameterFeatureSource, + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterEnum, + QgsProcessingParameterField, + QgsProcessingParameterNumber, + QgsProcessingParameterFeatureSink, + QgsSpatialIndex, + QgsWkbTypes, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm @@ -50,13 +52,13 @@ class PointDistance(QgisAlgorithm): - INPUT = 'INPUT' - INPUT_FIELD = 'INPUT_FIELD' - TARGET = 'TARGET' - TARGET_FIELD = 'TARGET_FIELD' - MATRIX_TYPE = 'MATRIX_TYPE' - NEAREST_POINTS = 'NEAREST_POINTS' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + INPUT_FIELD = "INPUT_FIELD" + TARGET = "TARGET" + TARGET_FIELD = "TARGET_FIELD" + MATRIX_TYPE = "MATRIX_TYPE" + NEAREST_POINTS = "NEAREST_POINTS" + OUTPUT = "OUTPUT" def icon(self): return QgsApplication.getThemeIcon("/algorithms/mAlgorithmDistanceMatrix.svg") @@ -65,61 +67,110 @@ def svgIconPath(self): return QgsApplication.iconPath("/algorithms/mAlgorithmDistanceMatrix.svg") def group(self): - return self.tr('Vector analysis') + return self.tr("Vector analysis") def groupId(self): - return 'vectoranalysis' + return "vectoranalysis" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.mat_types = [self.tr('Linear (N*k x 3) distance matrix'), - self.tr('Standard (N x T) distance matrix'), - self.tr('Summary distance matrix (mean, std. dev., min, max)')] - - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input point layer'), - [QgsProcessing.SourceType.TypeVectorPoint])) - self.addParameter(QgsProcessingParameterField(self.INPUT_FIELD, - self.tr('Input unique ID field'), - parentLayerParameterName=self.INPUT, - type=QgsProcessingParameterField.DataType.Any)) - self.addParameter(QgsProcessingParameterFeatureSource(self.TARGET, - self.tr('Target point layer'), - [QgsProcessing.SourceType.TypeVectorPoint])) - self.addParameter(QgsProcessingParameterField(self.TARGET_FIELD, - self.tr('Target unique ID field'), - parentLayerParameterName=self.TARGET, - type=QgsProcessingParameterField.DataType.Any)) - self.addParameter(QgsProcessingParameterEnum(self.MATRIX_TYPE, - self.tr('Output matrix type'), options=self.mat_types, defaultValue=0)) - self.addParameter(QgsProcessingParameterNumber(self.NEAREST_POINTS, - self.tr('Use only the nearest (k) target points'), type=QgsProcessingParameterNumber.Type.Integer, minValue=0, defaultValue=0)) - - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Distance matrix'), QgsProcessing.SourceType.TypeVectorPoint)) + self.mat_types = [ + self.tr("Linear (N*k x 3) distance matrix"), + self.tr("Standard (N x T) distance matrix"), + self.tr("Summary distance matrix (mean, std. dev., min, max)"), + ] + + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Input point layer"), + [QgsProcessing.SourceType.TypeVectorPoint], + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.INPUT_FIELD, + self.tr("Input unique ID field"), + parentLayerParameterName=self.INPUT, + type=QgsProcessingParameterField.DataType.Any, + ) + ) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.TARGET, + self.tr("Target point layer"), + [QgsProcessing.SourceType.TypeVectorPoint], + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.TARGET_FIELD, + self.tr("Target unique ID field"), + parentLayerParameterName=self.TARGET, + type=QgsProcessingParameterField.DataType.Any, + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.MATRIX_TYPE, + self.tr("Output matrix type"), + options=self.mat_types, + defaultValue=0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.NEAREST_POINTS, + self.tr("Use only the nearest (k) target points"), + type=QgsProcessingParameterNumber.Type.Integer, + minValue=0, + defaultValue=0, + ) + ) + + self.addParameter( + QgsProcessingParameterFeatureSink( + self.OUTPUT, + self.tr("Distance matrix"), + QgsProcessing.SourceType.TypeVectorPoint, + ) + ) def name(self): - return 'distancematrix' + return "distancematrix" def displayName(self): - return self.tr('Distance matrix') + return self.tr("Distance matrix") def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) if QgsWkbTypes.isMultiType(source.wkbType()): - raise QgsProcessingException(self.tr('Input point layer is a MultiPoint layer - first convert to single points before using this algorithm.')) + raise QgsProcessingException( + self.tr( + "Input point layer is a MultiPoint layer - first convert to single points before using this algorithm." + ) + ) source_field = self.parameterAsString(parameters, self.INPUT_FIELD, context) target_source = self.parameterAsSource(parameters, self.TARGET, context) if target_source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.TARGET)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.TARGET) + ) if QgsWkbTypes.isMultiType(target_source.wkbType()): - raise QgsProcessingException(self.tr('Target point layer is a MultiPoint layer - first convert to single points before using this algorithm.')) + raise QgsProcessingException( + self.tr( + "Target point layer is a MultiPoint layer - first convert to single points before using this algorithm." + ) + ) target_field = self.parameterAsString(parameters, self.TARGET_FIELD, context) same_source_and_target = parameters[self.INPUT] == parameters[self.TARGET] @@ -131,19 +182,58 @@ def processAlgorithm(self, parameters, context, feedback): if matType == 0: # Linear distance matrix - return self.linearMatrix(parameters, context, source, source_field, target_source, target_field, same_source_and_target, - matType, nPoints, feedback) + return self.linearMatrix( + parameters, + context, + source, + source_field, + target_source, + target_field, + same_source_and_target, + matType, + nPoints, + feedback, + ) elif matType == 1: # Standard distance matrix - return self.regularMatrix(parameters, context, source, source_field, target_source, target_field, - nPoints, feedback) + return self.regularMatrix( + parameters, + context, + source, + source_field, + target_source, + target_field, + nPoints, + feedback, + ) elif matType == 2: # Summary distance matrix - return self.linearMatrix(parameters, context, source, source_field, target_source, target_field, same_source_and_target, - matType, nPoints, feedback) - - def linearMatrix(self, parameters, context, source, inField, target_source, targetField, same_source_and_target, - matType, nPoints, feedback): + return self.linearMatrix( + parameters, + context, + source, + source_field, + target_source, + target_field, + same_source_and_target, + matType, + nPoints, + feedback, + ) + + def linearMatrix( + self, + parameters, + context, + source, + inField, + target_source, + targetField, + same_source_and_target, + matType, + nPoints, + feedback, + ): if same_source_and_target: # need to fetch an extra point from the index, since the closest match will always be the same @@ -155,32 +245,46 @@ def linearMatrix(self, parameters, context, source, inField, target_source, targ fields = QgsFields() input_id_field = source.fields()[inIdx] - input_id_field.setName('InputID') + input_id_field.setName("InputID") fields.append(input_id_field) if matType == 0: target_id_field = target_source.fields()[outIdx] - target_id_field.setName('TargetID') + target_id_field.setName("TargetID") fields.append(target_id_field) - fields.append(QgsField('Distance', QMetaType.Type.Double)) + fields.append(QgsField("Distance", QMetaType.Type.Double)) else: - fields.append(QgsField('MEAN', QMetaType.Type.Double)) - fields.append(QgsField('STDDEV', QMetaType.Type.Double)) - fields.append(QgsField('MIN', QMetaType.Type.Double)) - fields.append(QgsField('MAX', QMetaType.Type.Double)) - - out_wkb = QgsWkbTypes.multiType(source.wkbType()) if matType == 0 else source.wkbType() - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, out_wkb, source.sourceCrs()) + fields.append(QgsField("MEAN", QMetaType.Type.Double)) + fields.append(QgsField("STDDEV", QMetaType.Type.Double)) + fields.append(QgsField("MIN", QMetaType.Type.Double)) + fields.append(QgsField("MAX", QMetaType.Type.Double)) + + out_wkb = ( + QgsWkbTypes.multiType(source.wkbType()) + if matType == 0 + else source.wkbType() + ) + (sink, dest_id) = self.parameterAsSink( + parameters, self.OUTPUT, context, fields, out_wkb, source.sourceCrs() + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) - index = QgsSpatialIndex(target_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(source.sourceCrs(), context.transformContext())), feedback) + index = QgsSpatialIndex( + target_source.getFeatures( + QgsFeatureRequest() + .setSubsetOfAttributes([]) + .setDestinationCrs(source.sourceCrs(), context.transformContext()) + ), + feedback, + ) distArea = QgsDistanceArea() distArea.setSourceCrs(source.sourceCrs(), context.transformContext()) distArea.setEllipsoid(context.ellipsoid()) - features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([inIdx])) + features = source.getFeatures( + QgsFeatureRequest().setSubsetOfAttributes([inIdx]) + ) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, inFeat in enumerate(features): if feedback.isCanceled(): @@ -191,7 +295,12 @@ def linearMatrix(self, parameters, context, source, inField, target_source, targ featList = index.nearestNeighbor(inGeom.asPoint(), nPoints) distList = [] vari = 0.0 - request = QgsFeatureRequest().setFilterFids(featList).setSubsetOfAttributes([outIdx]).setDestinationCrs(source.sourceCrs(), context.transformContext()) + request = ( + QgsFeatureRequest() + .setFilterFids(featList) + .setSubsetOfAttributes([outIdx]) + .setDestinationCrs(source.sourceCrs(), context.transformContext()) + ) for outFeat in target_source.getFeatures(request): if feedback.isCanceled(): break @@ -201,12 +310,13 @@ def linearMatrix(self, parameters, context, source, inField, target_source, targ outID = outFeat[outIdx] outGeom = outFeat.geometry() - dist = distArea.measureLine(inGeom.asPoint(), - outGeom.asPoint()) + dist = distArea.measureLine(inGeom.asPoint(), outGeom.asPoint()) if matType == 0: out_feature = QgsFeature() - out_geom = QgsGeometry.unaryUnion([inFeat.geometry(), outFeat.geometry()]) + out_geom = QgsGeometry.unaryUnion( + [inFeat.geometry(), outFeat.geometry()] + ) out_feature.setGeometry(out_geom) out_feature.setAttributes([inID, outID, dist]) sink.addFeature(out_feature, QgsFeatureSink.Flag.FastInsert) @@ -221,7 +331,9 @@ def linearMatrix(self, parameters, context, source, inField, target_source, targ out_feature = QgsFeature() out_feature.setGeometry(inFeat.geometry()) - out_feature.setAttributes([inID, mean, vari, min(distList), max(distList)]) + out_feature.setAttributes( + [inID, mean, vari, min(distList), max(distList)] + ) sink.addFeature(out_feature, QgsFeatureSink.Flag.FastInsert) feedback.setProgress(int(current * total)) @@ -229,8 +341,17 @@ def linearMatrix(self, parameters, context, source, inField, target_source, targ sink.finalize() return {self.OUTPUT: dest_id} - def regularMatrix(self, parameters, context, source, inField, target_source, targetField, - nPoints, feedback): + def regularMatrix( + self, + parameters, + context, + source, + inField, + target_source, + targetField, + nPoints, + feedback, + ): distArea = QgsDistanceArea() distArea.setSourceCrs(source.sourceCrs(), context.transformContext()) @@ -239,12 +360,21 @@ def regularMatrix(self, parameters, context, source, inField, target_source, tar inIdx = source.fields().lookupField(inField) targetIdx = target_source.fields().lookupField(targetField) - index = QgsSpatialIndex(target_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(source.sourceCrs(), context.transformContext())), feedback) + index = QgsSpatialIndex( + target_source.getFeatures( + QgsFeatureRequest() + .setSubsetOfAttributes([]) + .setDestinationCrs(source.sourceCrs(), context.transformContext()) + ), + feedback, + ) first = True sink = None dest_id = None - features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([inIdx])) + features = source.getFeatures( + QgsFeatureRequest().setSubsetOfAttributes([inIdx]) + ) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, inFeat in enumerate(features): if feedback.isCanceled(): @@ -256,23 +386,40 @@ def regularMatrix(self, parameters, context, source, inField, target_source, tar first = False fields = QgsFields() input_id_field = source.fields()[inIdx] - input_id_field.setName('ID') + input_id_field.setName("ID") fields.append(input_id_field) - for f in target_source.getFeatures(QgsFeatureRequest().setFilterFids(featList).setSubsetOfAttributes([targetIdx]).setDestinationCrs(source.sourceCrs(), context.transformContext())): + for f in target_source.getFeatures( + QgsFeatureRequest() + .setFilterFids(featList) + .setSubsetOfAttributes([targetIdx]) + .setDestinationCrs(source.sourceCrs(), context.transformContext()) + ): fields.append(QgsField(str(f[targetField]), QMetaType.Type.Double)) - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, source.wkbType(), source.sourceCrs()) + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + fields, + source.wkbType(), + source.sourceCrs(), + ) if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) + raise QgsProcessingException( + self.invalidSinkError(parameters, self.OUTPUT) + ) data = [inFeat[inField]] - for target in target_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setFilterFids(featList).setDestinationCrs(source.sourceCrs(), context.transformContext())): + for target in target_source.getFeatures( + QgsFeatureRequest() + .setSubsetOfAttributes([]) + .setFilterFids(featList) + .setDestinationCrs(source.sourceCrs(), context.transformContext()) + ): if feedback.isCanceled(): break outGeom = target.geometry() - dist = distArea.measureLine(inGeom.asPoint(), - outGeom.asPoint()) + dist = distArea.measureLine(inGeom.asPoint(), outGeom.asPoint()) data.append(dist) out_feature = QgsFeature() diff --git a/python/plugins/processing/algs/qgis/PointsDisplacement.py b/python/plugins/processing/algs/qgis/PointsDisplacement.py index b93f146347b2..dfb2ba6fdb22 100644 --- a/python/plugins/processing/algs/qgis/PointsDisplacement.py +++ b/python/plugins/processing/algs/qgis/PointsDisplacement.py @@ -15,77 +15,109 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'July 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "July 2013" +__copyright__ = "(C) 2013, Alexander Bruy" import math -from qgis.core import (QgsFeatureSink, - QgsGeometry, - QgsPointXY, - QgsSpatialIndex, - QgsRectangle, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterDistance, - QgsProcessingParameterBoolean, - QgsProcessingParameterFeatureSink) +from qgis.core import ( + QgsFeatureSink, + QgsGeometry, + QgsPointXY, + QgsSpatialIndex, + QgsRectangle, + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterDistance, + QgsProcessingParameterBoolean, + QgsProcessingParameterFeatureSink, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm class PointsDisplacement(QgisAlgorithm): - INPUT = 'INPUT' - DISTANCE = 'DISTANCE' - PROXIMITY = 'PROXIMITY' - HORIZONTAL = 'HORIZONTAL' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + DISTANCE = "DISTANCE" + PROXIMITY = "PROXIMITY" + HORIZONTAL = "HORIZONTAL" + OUTPUT = "OUTPUT" def group(self): - return self.tr('Vector geometry') + return self.tr("Vector geometry") def groupId(self): - return 'vectorgeometry' + return "vectorgeometry" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), [QgsProcessing.SourceType.TypeVectorPoint])) - param = QgsProcessingParameterDistance(self.PROXIMITY, - self.tr('Minimum distance to other points'), parentParameterName='INPUT', - minValue=0.00001, defaultValue=1.0) - param.setMetadata({'widget_wrapper': {'decimals': 5}}) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Input layer"), + [QgsProcessing.SourceType.TypeVectorPoint], + ) + ) + param = QgsProcessingParameterDistance( + self.PROXIMITY, + self.tr("Minimum distance to other points"), + parentParameterName="INPUT", + minValue=0.00001, + defaultValue=1.0, + ) + param.setMetadata({"widget_wrapper": {"decimals": 5}}) self.addParameter(param) - param = QgsProcessingParameterDistance(self.DISTANCE, - self.tr('Displacement distance'), parentParameterName='INPUT', - minValue=0.00001, defaultValue=1.0) - param.setMetadata({'widget_wrapper': {'decimals': 5}}) + param = QgsProcessingParameterDistance( + self.DISTANCE, + self.tr("Displacement distance"), + parentParameterName="INPUT", + minValue=0.00001, + defaultValue=1.0, + ) + param.setMetadata({"widget_wrapper": {"decimals": 5}}) self.addParameter(param) - self.addParameter(QgsProcessingParameterBoolean(self.HORIZONTAL, - self.tr('Horizontal distribution for two point case'))) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Displaced'), QgsProcessing.SourceType.TypeVectorPoint)) + self.addParameter( + QgsProcessingParameterBoolean( + self.HORIZONTAL, self.tr("Horizontal distribution for two point case") + ) + ) + self.addParameter( + QgsProcessingParameterFeatureSink( + self.OUTPUT, + self.tr("Displaced"), + QgsProcessing.SourceType.TypeVectorPoint, + ) + ) def name(self): - return 'pointsdisplacement' + return "pointsdisplacement" def displayName(self): - return self.tr('Points displacement') + return self.tr("Points displacement") def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) proximity = self.parameterAsDouble(parameters, self.PROXIMITY, context) radius = self.parameterAsDouble(parameters, self.DISTANCE, context) horizontal = self.parameterAsBoolean(parameters, self.HORIZONTAL, context) - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - source.fields(), source.wkbType(), source.sourceCrs()) + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + source.fields(), + source.wkbType(), + source.sourceCrs(), + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) @@ -94,7 +126,12 @@ def processAlgorithm(self, parameters, context, feedback): total = 100.0 / source.featureCount() if source.featureCount() else 0 def searchRect(p): - return QgsRectangle(p.x() - proximity, p.y() - proximity, p.x() + proximity, p.y() + proximity) + return QgsRectangle( + p.x() - proximity, + p.y() - proximity, + p.x() + proximity, + p.y() + proximity, + ) index = QgsSpatialIndex() @@ -136,8 +173,10 @@ def searchRect(p): # calculate new centroid of group old_center = group_locations[min_dist_feature_id] - group_locations[min_dist_feature_id] = QgsPointXY((old_center.x() * len(group) + point.x()) / (len(group) + 1.0), - (old_center.y() * len(group) + point.y()) / (len(group) + 1.0)) + group_locations[min_dist_feature_id] = QgsPointXY( + (old_center.x() * len(group) + point.x()) / (len(group) + 1.0), + (old_center.y() * len(group) + point.y()) / (len(group) + 1.0), + ) # add to a group clustered_groups[group_index_pos].append(f) group_index[f.id()] = group_index_pos diff --git a/python/plugins/processing/algs/qgis/PointsFromLines.py b/python/plugins/processing/algs/qgis/PointsFromLines.py index 755819ef078e..0c702561684c 100644 --- a/python/plugins/processing/algs/qgis/PointsFromLines.py +++ b/python/plugins/processing/algs/qgis/PointsFromLines.py @@ -15,25 +15,27 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'August 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "August 2013" +__copyright__ = "(C) 2013, Alexander Bruy" from osgeo import gdal from qgis.PyQt.QtCore import QMetaType -from qgis.core import (QgsFeature, - QgsFeatureSink, - QgsFields, - QgsField, - QgsGeometry, - QgsPointXY, - QgsWkbTypes, - QgsProcessing, - QgsProcessingException, - QgsFeatureRequest, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink) +from qgis.core import ( + QgsFeature, + QgsFeatureSink, + QgsFields, + QgsField, + QgsGeometry, + QgsPointXY, + QgsWkbTypes, + QgsProcessing, + QgsProcessingException, + QgsFeatureRequest, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterFeatureSink, +) from processing.tools import raster from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm @@ -41,39 +43,57 @@ class PointsFromLines(QgisAlgorithm): - INPUT_RASTER = 'INPUT_RASTER' - RASTER_BAND = 'RASTER_BAND' - INPUT_VECTOR = 'INPUT_VECTOR' - OUTPUT = 'OUTPUT' + INPUT_RASTER = "INPUT_RASTER" + RASTER_BAND = "RASTER_BAND" + INPUT_VECTOR = "INPUT_VECTOR" + OUTPUT = "OUTPUT" def group(self): - return self.tr('Vector creation') + return self.tr("Vector creation") def groupId(self): - return 'vectorcreation' + return "vectorcreation" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT_RASTER, - self.tr('Raster layer'))) - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_VECTOR, - self.tr('Vector layer'), [QgsProcessing.SourceType.TypeVectorLine])) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Points along lines'), QgsProcessing.SourceType.TypeVectorPoint)) + self.addParameter( + QgsProcessingParameterRasterLayer( + self.INPUT_RASTER, self.tr("Raster layer") + ) + ) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT_VECTOR, + self.tr("Vector layer"), + [QgsProcessing.SourceType.TypeVectorLine], + ) + ) + self.addParameter( + QgsProcessingParameterFeatureSink( + self.OUTPUT, + self.tr("Points along lines"), + QgsProcessing.SourceType.TypeVectorPoint, + ) + ) def name(self): - return 'generatepointspixelcentroidsalongline' + return "generatepointspixelcentroidsalongline" def displayName(self): - return self.tr('Generate points (pixel centroids) along line') + return self.tr("Generate points (pixel centroids) along line") def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT_VECTOR, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT_VECTOR)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT_VECTOR) + ) - raster_layer = self.parameterAsRasterLayer(parameters, self.INPUT_RASTER, context) + raster_layer = self.parameterAsRasterLayer( + parameters, self.INPUT_RASTER, context + ) rasterPath = raster_layer.source() rasterDS = gdal.Open(rasterPath, gdal.GA_ReadOnly) @@ -81,12 +101,18 @@ def processAlgorithm(self, parameters, context, feedback): rasterDS = None fields = QgsFields() - fields.append(QgsField('id', QMetaType.Type.Int, '', 10, 0)) - fields.append(QgsField('line_id', QMetaType.Type.Int, '', 10, 0)) - fields.append(QgsField('point_id', QMetaType.Type.Int, '', 10, 0)) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, QgsWkbTypes.Type.Point, raster_layer.crs()) + fields.append(QgsField("id", QMetaType.Type.Int, "", 10, 0)) + fields.append(QgsField("line_id", QMetaType.Type.Int, "", 10, 0)) + fields.append(QgsField("point_id", QMetaType.Type.Int, "", 10, 0)) + + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + fields, + QgsWkbTypes.Type.Point, + raster_layer.crs(), + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) @@ -97,7 +123,11 @@ def processAlgorithm(self, parameters, context, feedback): self.lineId = 0 self.pointId = 0 - features = source.getFeatures(QgsFeatureRequest().setDestinationCrs(raster_layer.crs(), context.transformContext())) + features = source.getFeatures( + QgsFeatureRequest().setDestinationCrs( + raster_layer.crs(), context.transformContext() + ) + ) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): @@ -114,13 +144,10 @@ def processAlgorithm(self, parameters, context, feedback): p1 = line[i] p2 = line[i + 1] - (x1, y1) = raster.mapToPixel(p1.x(), p1.y(), - geoTransform) - (x2, y2) = raster.mapToPixel(p2.x(), p2.y(), - geoTransform) + (x1, y1) = raster.mapToPixel(p1.x(), p1.y(), geoTransform) + (x2, y2) = raster.mapToPixel(p2.x(), p2.y(), geoTransform) - self.buildLine(x1, y1, x2, y2, geoTransform, - sink, outFeature) + self.buildLine(x1, y1, x2, y2, geoTransform, sink, outFeature) else: points = geom.asPolyline() for i in range(len(points) - 1): @@ -130,8 +157,7 @@ def processAlgorithm(self, parameters, context, feedback): (x1, y1) = raster.mapToPixel(p1.x(), p1.y(), geoTransform) (x2, y2) = raster.mapToPixel(p2.x(), p2.y(), geoTransform) - self.buildLine(x1, y1, x2, y2, geoTransform, sink, - outFeature) + self.buildLine(x1, y1, x2, y2, geoTransform, sink, outFeature) self.pointId = 0 self.lineId += 1 @@ -198,9 +224,9 @@ def createPoint(self, pX, pY, geoTransform, writer, feature): (x, y) = raster.pixelToMap(pX, pY, geoTransform) feature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(x, y))) - feature['id'] = self.fid - feature['line_id'] = self.lineId - feature['point_id'] = self.pointId + feature["id"] = self.fid + feature["line_id"] = self.lineId + feature["point_id"] = self.pointId self.fid += 1 self.pointId += 1 diff --git a/python/plugins/processing/algs/qgis/PolarPlot.py b/python/plugins/processing/algs/qgis/PolarPlot.py index 07fa5e5e55ee..96f214629dc3 100644 --- a/python/plugins/processing/algs/qgis/PolarPlot.py +++ b/python/plugins/processing/algs/qgis/PolarPlot.py @@ -15,16 +15,18 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'January 2013' -__copyright__ = '(C) 2013, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "January 2013" +__copyright__ = "(C) 2013, Victor Olaya" import warnings -from qgis.core import (QgsProcessingException, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterField, - QgsProcessingParameterFileDestination) +from qgis.core import ( + QgsProcessingException, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingParameterFileDestination, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.tools import vector @@ -32,37 +34,51 @@ class PolarPlot(QgisAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' - NAME_FIELD = 'NAME_FIELD' - VALUE_FIELD = 'VALUE_FIELD' + INPUT = "INPUT" + OUTPUT = "OUTPUT" + NAME_FIELD = "NAME_FIELD" + VALUE_FIELD = "VALUE_FIELD" def group(self): - return self.tr('Plots') + return self.tr("Plots") def groupId(self): - return 'plots' + return "plots" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterField(self.NAME_FIELD, - self.tr('Category name field'), parentLayerParameterName=self.INPUT)) # FIXME unused? - self.addParameter(QgsProcessingParameterField(self.VALUE_FIELD, - self.tr('Value field'), - parentLayerParameterName=self.INPUT, - type=QgsProcessingParameterField.DataType.Numeric)) - - self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, self.tr('Polar plot'), self.tr('HTML files (*.html)'))) + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterField( + self.NAME_FIELD, + self.tr("Category name field"), + parentLayerParameterName=self.INPUT, + ) + ) # FIXME unused? + self.addParameter( + QgsProcessingParameterField( + self.VALUE_FIELD, + self.tr("Value field"), + parentLayerParameterName=self.INPUT, + type=QgsProcessingParameterField.DataType.Numeric, + ) + ) + + self.addParameter( + QgsProcessingParameterFileDestination( + self.OUTPUT, self.tr("Polar plot"), self.tr("HTML files (*.html)") + ) + ) def name(self): - return 'polarplot' + return "polarplot" def displayName(self): - return self.tr('Polar plot') + return self.tr("Polar plot") def processAlgorithm(self, parameters, context, feedback): try: @@ -73,26 +89,46 @@ def processAlgorithm(self, parameters, context, feedback): import plotly as plt import plotly.graph_objs as go except ImportError: - raise QgsProcessingException(QCoreApplication.translate('PolarPlot', 'This algorithm requires the Python “plotly” library. Please install this library and try again.')) + raise QgsProcessingException( + QCoreApplication.translate( + "PolarPlot", + "This algorithm requires the Python “plotly” library. Please install this library and try again.", + ) + ) try: import numpy as np except ImportError: - raise QgsProcessingException(QCoreApplication.translate('PolarPlot', 'This algorithm requires the Python “numpy” library. Please install this library and try again.')) + raise QgsProcessingException( + QCoreApplication.translate( + "PolarPlot", + "This algorithm requires the Python “numpy” library. Please install this library and try again.", + ) + ) source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) - namefieldname = self.parameterAsString(parameters, self.NAME_FIELD, context) # NOQA FIXME unused? + namefieldname = self.parameterAsString( + parameters, self.NAME_FIELD, context + ) # NOQA FIXME unused? valuefieldname = self.parameterAsString(parameters, self.VALUE_FIELD, context) output = self.parameterAsFileOutput(parameters, self.OUTPUT, context) values = vector.values(source, valuefieldname) - data = [go.Barpolar(r=values[valuefieldname], - theta=np.degrees(np.arange(0.0, 2 * np.pi, 2 * np.pi / len(values[valuefieldname]))))] + data = [ + go.Barpolar( + r=values[valuefieldname], + theta=np.degrees( + np.arange(0.0, 2 * np.pi, 2 * np.pi / len(values[valuefieldname])) + ), + ) + ] plt.offline.plot(data, filename=output, auto_open=False) diff --git a/python/plugins/processing/algs/qgis/PostGISExecuteAndLoadSQL.py b/python/plugins/processing/algs/qgis/PostGISExecuteAndLoadSQL.py index ce8eab29bb4a..f312164b6c47 100644 --- a/python/plugins/processing/algs/qgis/PostGISExecuteAndLoadSQL.py +++ b/python/plugins/processing/algs/qgis/PostGISExecuteAndLoadSQL.py @@ -17,109 +17,132 @@ *************************************************************************** """ -__author__ = 'Anita Graser' -__date__ = 'May 2018' -__copyright__ = '(C) 2018, Anita Graser' - -from qgis.core import (QgsProcessingException, - QgsProcessingParameterString, - QgsVectorLayer, - QgsDataSourceUri, - QgsProcessing, - QgsProcessingOutputVectorLayer, - QgsProcessingContext, - QgsProcessingParameterProviderConnection, - QgsProviderRegistry, - QgsProviderConnectionException, - QgsProcessingAlgorithm - ) +__author__ = "Anita Graser" +__date__ = "May 2018" +__copyright__ = "(C) 2018, Anita Graser" + +from qgis.core import ( + QgsProcessingException, + QgsProcessingParameterString, + QgsVectorLayer, + QgsDataSourceUri, + QgsProcessing, + QgsProcessingOutputVectorLayer, + QgsProcessingContext, + QgsProcessingParameterProviderConnection, + QgsProviderRegistry, + QgsProviderConnectionException, + QgsProcessingAlgorithm, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm class PostGISExecuteAndLoadSQL(QgisAlgorithm): - DATABASE = 'DATABASE' - SQL = 'SQL' - OUTPUT = 'OUTPUT' - ID_FIELD = 'ID_FIELD' - GEOMETRY_FIELD = 'GEOMETRY_FIELD' + DATABASE = "DATABASE" + SQL = "SQL" + OUTPUT = "OUTPUT" + ID_FIELD = "ID_FIELD" + GEOMETRY_FIELD = "GEOMETRY_FIELD" def group(self): - return self.tr('Database') + return self.tr("Database") def groupId(self): - return 'database' + return "database" def __init__(self): super().__init__() def flags(self): - return super().flags() | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool | QgsProcessingAlgorithm.Flag.FlagRequiresProject + return ( + super().flags() + | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool + | QgsProcessingAlgorithm.Flag.FlagRequiresProject + ) def initAlgorithm(self, config=None): db_param = QgsProcessingParameterProviderConnection( - self.DATABASE, - self.tr('Database (connection name)'), 'postgres') + self.DATABASE, self.tr("Database (connection name)"), "postgres" + ) self.addParameter(db_param) - self.addParameter(QgsProcessingParameterString( - self.SQL, - self.tr('SQL query'), - multiLine=True)) - self.addParameter(QgsProcessingParameterString( - self.ID_FIELD, - self.tr('Unique ID field name'), - defaultValue='id')) - self.addParameter(QgsProcessingParameterString( - self.GEOMETRY_FIELD, - self.tr('Geometry field name'), - defaultValue='geom', - optional=True)) - self.addOutput(QgsProcessingOutputVectorLayer( - self.OUTPUT, - self.tr("Output layer"), - QgsProcessing.SourceType.TypeVectorAnyGeometry)) + self.addParameter( + QgsProcessingParameterString(self.SQL, self.tr("SQL query"), multiLine=True) + ) + self.addParameter( + QgsProcessingParameterString( + self.ID_FIELD, self.tr("Unique ID field name"), defaultValue="id" + ) + ) + self.addParameter( + QgsProcessingParameterString( + self.GEOMETRY_FIELD, + self.tr("Geometry field name"), + defaultValue="geom", + optional=True, + ) + ) + self.addOutput( + QgsProcessingOutputVectorLayer( + self.OUTPUT, + self.tr("Output layer"), + QgsProcessing.SourceType.TypeVectorAnyGeometry, + ) + ) def name(self): - return 'postgisexecuteandloadsql' + return "postgisexecuteandloadsql" def displayName(self): - return self.tr('PostgreSQL execute and load SQL') + return self.tr("PostgreSQL execute and load SQL") def shortDescription(self): - return self.tr('Executes a SQL command on a PostgreSQL database and loads the result as a table') + return self.tr( + "Executes a SQL command on a PostgreSQL database and loads the result as a table" + ) def tags(self): - return self.tr('postgis,table,database').split(',') + return self.tr("postgis,table,database").split(",") def processAlgorithm(self, parameters, context, feedback): - connection_name = self.parameterAsConnectionName(parameters, self.DATABASE, context) + connection_name = self.parameterAsConnectionName( + parameters, self.DATABASE, context + ) id_field = self.parameterAsString(parameters, self.ID_FIELD, context) - geom_field = self.parameterAsString( - parameters, self.GEOMETRY_FIELD, context) + geom_field = self.parameterAsString(parameters, self.GEOMETRY_FIELD, context) # resolve connection details to uri try: - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(connection_name) except QgsProviderConnectionException: - raise QgsProcessingException(self.tr('Could not retrieve connection details for {}').format(connection_name)) + raise QgsProcessingException( + self.tr("Could not retrieve connection details for {}").format( + connection_name + ) + ) uri = QgsDataSourceUri(conn.uri()) sql = self.parameterAsString(parameters, self.SQL, context) - sql = sql.replace('\n', ' ') - uri.setDataSource("", "(" + sql.rstrip(';') + ")", geom_field, "", id_field) + sql = sql.replace("\n", " ") + uri.setDataSource("", "(" + sql.rstrip(";") + ")", geom_field, "", id_field) vlayer = QgsVectorLayer(uri.uri(), "layername", "postgres") if not vlayer.isValid(): - raise QgsProcessingException(self.tr("""This layer is invalid! - Please check the PostGIS log for error messages.""")) + raise QgsProcessingException( + self.tr( + """This layer is invalid! + Please check the PostGIS log for error messages.""" + ) + ) context.temporaryLayerStore().addMapLayer(vlayer) context.addLayerToLoadOnCompletion( vlayer.id(), - QgsProcessingContext.LayerDetails('SQL layer', - context.project(), - self.OUTPUT)) + QgsProcessingContext.LayerDetails( + "SQL layer", context.project(), self.OUTPUT + ), + ) return {self.OUTPUT: vlayer.id()} diff --git a/python/plugins/processing/algs/qgis/QgisAlgorithm.py b/python/plugins/processing/algs/qgis/QgisAlgorithm.py index 7e850cf5a6ac..f0bf95805527 100644 --- a/python/plugins/processing/algs/qgis/QgisAlgorithm.py +++ b/python/plugins/processing/algs/qgis/QgisAlgorithm.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'May2017' -__copyright__ = '(C) 2017, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "May2017" +__copyright__ = "(C) 2017, Nyall Dawson" from qgis.core import QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm from qgis.PyQt.QtCore import QCoreApplication @@ -32,13 +32,13 @@ def __init__(self): def shortHelpString(self): return shortHelp.get(self.id(), None) - def tr(self, string, context=''): - if context == '': + def tr(self, string, context=""): + if context == "": context = self.__class__.__name__ return QCoreApplication.translate(context, string) - def trAlgorithm(self, string, context=''): - if context == '': + def trAlgorithm(self, string, context=""): + if context == "": context = self.__class__.__name__ return string, QCoreApplication.translate(context, string) @@ -54,13 +54,13 @@ def __init__(self): def shortHelpString(self): return shortHelp.get(self.id(), None) - def tr(self, string, context=''): - if context == '': + def tr(self, string, context=""): + if context == "": context = self.__class__.__name__ return QCoreApplication.translate(context, string) - def trAlgorithm(self, string, context=''): - if context == '': + def trAlgorithm(self, string, context=""): + if context == "": context = self.__class__.__name__ return string, QCoreApplication.translate(context, string) diff --git a/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py b/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py index 4705e863842d..6a540340b9cd 100644 --- a/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py +++ b/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py @@ -15,15 +15,13 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'December 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "December 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os -from qgis.core import (QgsApplication, - QgsProcessingProvider, - QgsRuntimeProfiler) +from qgis.core import QgsApplication, QgsProcessingProvider, QgsRuntimeProfiler from qgis.PyQt.QtCore import QCoreApplication @@ -80,75 +78,80 @@ class QgisAlgorithmProvider(QgsProcessingProvider): - fieldMappingParameterName = QCoreApplication.translate('Processing', 'Fields Mapper') + fieldMappingParameterName = QCoreApplication.translate( + "Processing", "Fields Mapper" + ) def __init__(self): super().__init__() - QgsApplication.processingRegistry().addAlgorithmAlias('qgis:rectanglesovalsdiamondsfixed', 'native:rectanglesovalsdiamonds') + QgsApplication.processingRegistry().addAlgorithmAlias( + "qgis:rectanglesovalsdiamondsfixed", "native:rectanglesovalsdiamonds" + ) def getAlgs(self): - algs = [BarPlot(), - BoxPlot(), - CheckValidity(), - Climb(), - DefineProjection(), - EliminateSelection(), - ExecuteSQL(), - ExportGeometryInfo(), - FieldsPyculator(), - FindProjection(), - GeometryConvert(), - Heatmap(), - HubDistanceLines(), - HubDistancePoints(), - HypsometricCurves(), - IdwInterpolation(), - ImportIntoSpatialite(), - KNearestConcaveHull(), - LinesToPolygons(), - MeanAndStdDevPlot(), - MinimumBoundingGeometry(), - PointDistance(), - PointsDisplacement(), - PointsFromLines(), - PolarPlot(), - PostGISExecuteAndLoadSQL(), - RandomExtractWithinSubsets(), - RandomPointsAlongLines(), - RandomPointsLayer(), - RandomPointsPolygons(), - RandomSelection(), - RandomSelectionWithinSubsets(), - RasterCalculator(), - RasterLayerHistogram(), - RectanglesOvalsDiamondsVariable(), - RegularPoints(), - Relief(), - SelectByAttribute(), - SelectByExpression(), - SetRasterStyle(), - SetVectorStyle(), - StatisticsByCategories(), - TextToFloat(), - TinInterpolation(), - TopoColor(), - UniqueValues(), - VariableDistanceBuffer(), - VectorLayerHistogram(), - VectorLayerScatterplot(), - VectorLayerScatterplot3D(), - ] + algs = [ + BarPlot(), + BoxPlot(), + CheckValidity(), + Climb(), + DefineProjection(), + EliminateSelection(), + ExecuteSQL(), + ExportGeometryInfo(), + FieldsPyculator(), + FindProjection(), + GeometryConvert(), + Heatmap(), + HubDistanceLines(), + HubDistancePoints(), + HypsometricCurves(), + IdwInterpolation(), + ImportIntoSpatialite(), + KNearestConcaveHull(), + LinesToPolygons(), + MeanAndStdDevPlot(), + MinimumBoundingGeometry(), + PointDistance(), + PointsDisplacement(), + PointsFromLines(), + PolarPlot(), + PostGISExecuteAndLoadSQL(), + RandomExtractWithinSubsets(), + RandomPointsAlongLines(), + RandomPointsLayer(), + RandomPointsPolygons(), + RandomSelection(), + RandomSelectionWithinSubsets(), + RasterCalculator(), + RasterLayerHistogram(), + RectanglesOvalsDiamondsVariable(), + RegularPoints(), + Relief(), + SelectByAttribute(), + SelectByExpression(), + SetRasterStyle(), + SetVectorStyle(), + StatisticsByCategories(), + TextToFloat(), + TinInterpolation(), + TopoColor(), + UniqueValues(), + VariableDistanceBuffer(), + VectorLayerHistogram(), + VectorLayerScatterplot(), + VectorLayerScatterplot3D(), + ] return algs def id(self): - return 'qgis' + return "qgis" def helpId(self): - return 'qgis' + return "qgis" def name(self): - return 'QGIS' + return "QGIS" def icon(self): return QgsApplication.getThemeIcon("/providerQgis.svg") @@ -161,7 +164,7 @@ def loadAlgorithms(self): self.addAlgorithm(a) def load(self): - with QgsRuntimeProfiler.profile('QGIS Python Provider'): + with QgsRuntimeProfiler.profile("QGIS Python Provider"): success = super().load() return success diff --git a/python/plugins/processing/algs/qgis/RandomExtractWithinSubsets.py b/python/plugins/processing/algs/qgis/RandomExtractWithinSubsets.py index 55d517e68519..639d990a1ccb 100644 --- a/python/plugins/processing/algs/qgis/RandomExtractWithinSubsets.py +++ b/python/plugins/processing/algs/qgis/RandomExtractWithinSubsets.py @@ -15,70 +15,94 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import random -from qgis.core import (QgsFeatureSink, - QgsProcessingException, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterEnum, - QgsProcessingParameterField, - QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSink, - QgsProcessingFeatureSource, - QgsFeatureRequest) +from qgis.core import ( + QgsFeatureSink, + QgsProcessingException, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterEnum, + QgsProcessingParameterField, + QgsProcessingParameterNumber, + QgsProcessingParameterFeatureSink, + QgsProcessingFeatureSource, + QgsFeatureRequest, +) from collections import defaultdict from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm class RandomExtractWithinSubsets(QgisAlgorithm): - INPUT = 'INPUT' - METHOD = 'METHOD' - NUMBER = 'NUMBER' - FIELD = 'FIELD' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + METHOD = "METHOD" + NUMBER = "NUMBER" + FIELD = "FIELD" + OUTPUT = "OUTPUT" def group(self): - return self.tr('Vector selection') + return self.tr("Vector selection") def groupId(self): - return 'vectorselection' + return "vectorselection" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.methods = [self.tr('Number of selected features'), - self.tr('Percentage of selected features')] - - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'))) - - self.addParameter(QgsProcessingParameterField(self.FIELD, - self.tr('ID field'), None, self.INPUT)) - - self.addParameter(QgsProcessingParameterEnum(self.METHOD, - self.tr('Method'), self.methods, False, 0)) - - self.addParameter(QgsProcessingParameterNumber(self.NUMBER, - self.tr('Number/percentage of selected features'), QgsProcessingParameterNumber.Type.Integer, - 10, False, 0.0)) - - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Extracted (random stratified)'))) + self.methods = [ + self.tr("Number of selected features"), + self.tr("Percentage of selected features"), + ] + + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer")) + ) + + self.addParameter( + QgsProcessingParameterField( + self.FIELD, self.tr("ID field"), None, self.INPUT + ) + ) + + self.addParameter( + QgsProcessingParameterEnum( + self.METHOD, self.tr("Method"), self.methods, False, 0 + ) + ) + + self.addParameter( + QgsProcessingParameterNumber( + self.NUMBER, + self.tr("Number/percentage of selected features"), + QgsProcessingParameterNumber.Type.Integer, + 10, + False, + 0.0, + ) + ) + + self.addParameter( + QgsProcessingParameterFeatureSink( + self.OUTPUT, self.tr("Extracted (random stratified)") + ) + ) def name(self): - return 'randomextractwithinsubsets' + return "randomextractwithinsubsets" def displayName(self): - return self.tr('Random extract within subsets') + return self.tr("Random extract within subsets") def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) method = self.parameterAsEnum(parameters, self.METHOD, context) @@ -86,24 +110,39 @@ def processAlgorithm(self, parameters, context, feedback): index = source.fields().lookupField(field) - features = source.getFeatures(QgsFeatureRequest(), QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks) + features = source.getFeatures( + QgsFeatureRequest(), + QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks, + ) featureCount = source.featureCount() unique = source.uniqueValues(index) value = self.parameterAsInt(parameters, self.NUMBER, context) if method == 0: if value > featureCount: raise QgsProcessingException( - self.tr('Selected number is greater that feature count. ' - 'Choose lesser value and try again.')) + self.tr( + "Selected number is greater that feature count. " + "Choose lesser value and try again." + ) + ) else: if value > 100: raise QgsProcessingException( - self.tr("Percentage can't be greater than 100. Set " - "correct value and try again.")) + self.tr( + "Percentage can't be greater than 100. Set " + "correct value and try again." + ) + ) value = value / 100.0 - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - source.fields(), source.wkbType(), source.sourceCrs()) + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + source.fields(), + source.wkbType(), + source.sourceCrs(), + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) @@ -122,12 +161,15 @@ def processAlgorithm(self, parameters, context, feedback): selValue = value if method != 1 else int(round(value * len(subset), 0)) if selValue > len(subset): selValue = len(subset) - feedback.reportError(self.tr( - 'Subset "{}" is smaller than requested number of features.').format(k)) + feedback.reportError( + self.tr( + 'Subset "{}" is smaller than requested number of features.' + ).format(k) + ) selran.extend(random.sample(subset, selValue)) total = 100.0 / featureCount if featureCount else 1 - for (i, feat) in enumerate(selran): + for i, feat in enumerate(selran): if feedback.isCanceled(): break sink.addFeature(feat, QgsFeatureSink.Flag.FastInsert) diff --git a/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py b/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py index 0876744a87c8..5e67a9db0848 100644 --- a/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py +++ b/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py @@ -15,72 +15,97 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'April 2014' -__copyright__ = '(C) 2014, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "April 2014" +__copyright__ = "(C) 2014, Alexander Bruy" import random from qgis.PyQt.QtCore import QMetaType -from qgis.core import (Qgis, - QgsField, - QgsFeatureSink, - QgsFeature, - QgsFields, - QgsGeometry, - QgsPointXY, - QgsWkbTypes, - QgsSpatialIndex, - QgsFeatureRequest, - QgsDistanceArea, - QgsProject, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterDistance, - QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterDefinition) +from qgis.core import ( + Qgis, + QgsField, + QgsFeatureSink, + QgsFeature, + QgsFields, + QgsGeometry, + QgsPointXY, + QgsWkbTypes, + QgsSpatialIndex, + QgsFeatureRequest, + QgsDistanceArea, + QgsProject, + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterDistance, + QgsProcessingParameterNumber, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterDefinition, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.tools import vector class RandomPointsAlongLines(QgisAlgorithm): - INPUT = 'INPUT' - POINTS_NUMBER = 'POINTS_NUMBER' - MIN_DISTANCE = 'MIN_DISTANCE' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + POINTS_NUMBER = "POINTS_NUMBER" + MIN_DISTANCE = "MIN_DISTANCE" + OUTPUT = "OUTPUT" def group(self): - return self.tr('Vector creation') + return self.tr("Vector creation") def groupId(self): - return 'vectorcreation' + return "vectorcreation" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), - [QgsProcessing.SourceType.TypeVectorLine])) - self.addParameter(QgsProcessingParameterNumber(self.POINTS_NUMBER, - self.tr('Number of points'), - QgsProcessingParameterNumber.Type.Integer, - 1, False, 1, 1000000000)) - self.addParameter(QgsProcessingParameterDistance(self.MIN_DISTANCE, - self.tr('Minimum distance between points'), - 0, self.INPUT, False, 0, 1000000000)) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, - self.tr('Random points'), - type=QgsProcessing.SourceType.TypeVectorPoint)) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Input layer"), + [QgsProcessing.SourceType.TypeVectorLine], + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.POINTS_NUMBER, + self.tr("Number of points"), + QgsProcessingParameterNumber.Type.Integer, + 1, + False, + 1, + 1000000000, + ) + ) + self.addParameter( + QgsProcessingParameterDistance( + self.MIN_DISTANCE, + self.tr("Minimum distance between points"), + 0, + self.INPUT, + False, + 0, + 1000000000, + ) + ) + self.addParameter( + QgsProcessingParameterFeatureSink( + self.OUTPUT, + self.tr("Random points"), + type=QgsProcessing.SourceType.TypeVectorPoint, + ) + ) def name(self): - return 'randompointsalongline' + return "randompointsalongline" def displayName(self): - return self.tr('Random points along line') + return self.tr("Random points along line") def documentationFlags(self): return Qgis.ProcessingAlgorithmDocumentationFlag.RegeneratesPrimaryKey @@ -88,16 +113,25 @@ def documentationFlags(self): def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) pointCount = self.parameterAsDouble(parameters, self.POINTS_NUMBER, context) minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context) fields = QgsFields() - fields.append(QgsField('id', QMetaType.Type.Int, '', 10, 0)) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, QgsWkbTypes.Type.Point, source.sourceCrs(), QgsFeatureSink.SinkFlag.RegeneratePrimaryKey) + fields.append(QgsField("id", QMetaType.Type.Int, "", 10, 0)) + + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + fields, + QgsWkbTypes.Type.Point, + source.sourceCrs(), + QgsFeatureSink.SinkFlag.RegeneratePrimaryKey, + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) @@ -126,7 +160,11 @@ def processAlgorithm(self, parameters, context, feedback): # pick random feature fid = random.choice(ids) try: - f = next(source.getFeatures(request.setFilterFid(fid).setSubsetOfAttributes([]))) + f = next( + source.getFeatures( + request.setFilterFid(fid).setSubsetOfAttributes([]) + ) + ) except StopIteration: ids.remove(fid) continue @@ -172,7 +210,7 @@ def processAlgorithm(self, parameters, context, feedback): f = QgsFeature(nPoints) f.initAttributes(1) f.setFields(fields) - f.setAttribute('id', nPoints) + f.setAttribute("id", nPoints) f.setGeometry(geom) sink.addFeature(f, QgsFeatureSink.Flag.FastInsert) index.addFeature(f) @@ -182,8 +220,12 @@ def processAlgorithm(self, parameters, context, feedback): nIterations += 1 if nPoints < pointCount: - feedback.pushInfo(self.tr('Could not generate requested number of random points. ' - 'Maximum number of attempts exceeded.')) + feedback.pushInfo( + self.tr( + "Could not generate requested number of random points. " + "Maximum number of attempts exceeded." + ) + ) sink.finalize() return {self.OUTPUT: dest_id} diff --git a/python/plugins/processing/algs/qgis/RandomPointsLayer.py b/python/plugins/processing/algs/qgis/RandomPointsLayer.py index 2d7eee82cdfd..0b6422131304 100644 --- a/python/plugins/processing/algs/qgis/RandomPointsLayer.py +++ b/python/plugins/processing/algs/qgis/RandomPointsLayer.py @@ -15,33 +15,35 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'April 2014' -__copyright__ = '(C) 2014, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "April 2014" +__copyright__ = "(C) 2014, Alexander Bruy" import os import random from qgis.PyQt.QtGui import QIcon from qgis.PyQt.QtCore import QMetaType -from qgis.core import (Qgis, - QgsApplication, - QgsField, - QgsFeatureSink, - QgsFeature, - QgsFields, - QgsGeometry, - QgsPointXY, - QgsWkbTypes, - QgsSpatialIndex, - QgsFeatureRequest, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterNumber, - QgsProcessingParameterDistance, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterDefinition) +from qgis.core import ( + Qgis, + QgsApplication, + QgsField, + QgsFeatureSink, + QgsFeature, + QgsFields, + QgsGeometry, + QgsPointXY, + QgsWkbTypes, + QgsSpatialIndex, + QgsFeatureRequest, + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterNumber, + QgsProcessingParameterDistance, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterDefinition, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.tools import vector @@ -50,46 +52,73 @@ class RandomPointsLayer(QgisAlgorithm): - INPUT = 'INPUT' - POINTS_NUMBER = 'POINTS_NUMBER' - MIN_DISTANCE = 'MIN_DISTANCE' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + POINTS_NUMBER = "POINTS_NUMBER" + MIN_DISTANCE = "MIN_DISTANCE" + OUTPUT = "OUTPUT" def icon(self): - return QgsApplication.getThemeIcon("/algorithms/mAlgorithmRandomPointsWithinExtent.svg") + return QgsApplication.getThemeIcon( + "/algorithms/mAlgorithmRandomPointsWithinExtent.svg" + ) def svgIconPath(self): - return QgsApplication.iconPath("/algorithms/mAlgorithmRandomPointsWithinExtent.svg") + return QgsApplication.iconPath( + "/algorithms/mAlgorithmRandomPointsWithinExtent.svg" + ) def group(self): - return self.tr('Vector creation') + return self.tr("Vector creation") def groupId(self): - return 'vectorcreation' + return "vectorcreation" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), - [QgsProcessing.SourceType.TypeVectorPolygon])) - self.addParameter(QgsProcessingParameterNumber(self.POINTS_NUMBER, - self.tr('Number of points'), - QgsProcessingParameterNumber.Type.Integer, - 1, False, 1, 1000000000)) - self.addParameter(QgsProcessingParameterDistance(self.MIN_DISTANCE, - self.tr('Minimum distance between points'), - 0, self.INPUT, False, 0, 1000000000)) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, - self.tr('Random points'), - type=QgsProcessing.SourceType.TypeVectorPoint)) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Input layer"), + [QgsProcessing.SourceType.TypeVectorPolygon], + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.POINTS_NUMBER, + self.tr("Number of points"), + QgsProcessingParameterNumber.Type.Integer, + 1, + False, + 1, + 1000000000, + ) + ) + self.addParameter( + QgsProcessingParameterDistance( + self.MIN_DISTANCE, + self.tr("Minimum distance between points"), + 0, + self.INPUT, + False, + 0, + 1000000000, + ) + ) + self.addParameter( + QgsProcessingParameterFeatureSink( + self.OUTPUT, + self.tr("Random points"), + type=QgsProcessing.SourceType.TypeVectorPoint, + ) + ) def name(self): - return 'randompointsinlayerbounds' + return "randompointsinlayerbounds" def displayName(self): - return self.tr('Random points in layer bounds') + return self.tr("Random points in layer bounds") def documentationFlags(self): return Qgis.ProcessingAlgorithmDocumentationFlag.RegeneratesPrimaryKey @@ -97,7 +126,9 @@ def documentationFlags(self): def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) pointCount = self.parameterAsDouble(parameters, self.POINTS_NUMBER, context) minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context) @@ -106,10 +137,17 @@ def processAlgorithm(self, parameters, context, feedback): sourceIndex = QgsSpatialIndex(source, feedback) fields = QgsFields() - fields.append(QgsField('id', QMetaType.Type.Int, '', 10, 0)) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, QgsWkbTypes.Type.Point, source.sourceCrs(), QgsFeatureSink.SinkFlag.RegeneratePrimaryKey) + fields.append(QgsField("id", QMetaType.Type.Int, "", 10, 0)) + + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + fields, + QgsWkbTypes.Type.Point, + source.sourceCrs(), + QgsFeatureSink.SinkFlag.RegeneratePrimaryKey, + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) @@ -133,9 +171,10 @@ def processAlgorithm(self, parameters, context, feedback): p = QgsPointXY(rx, ry) geom = QgsGeometry.fromPointXY(p) ids = sourceIndex.intersects(geom.buffer(5, 5).boundingBox()) - if len(ids) > 0 and \ - vector.checkMinDistance(p, index, minDistance, points): - request = QgsFeatureRequest().setFilterFids(ids).setSubsetOfAttributes([]) + if len(ids) > 0 and vector.checkMinDistance(p, index, minDistance, points): + request = ( + QgsFeatureRequest().setFilterFids(ids).setSubsetOfAttributes([]) + ) for f in source.getFeatures(request): if feedback.isCanceled(): break @@ -145,7 +184,7 @@ def processAlgorithm(self, parameters, context, feedback): f = QgsFeature(nPoints) f.initAttributes(1) f.setFields(fields) - f.setAttribute('id', nPoints) + f.setAttribute("id", nPoints) f.setGeometry(geom) sink.addFeature(f, QgsFeatureSink.Flag.FastInsert) index.addFeature(f) @@ -155,8 +194,12 @@ def processAlgorithm(self, parameters, context, feedback): nIterations += 1 if nPoints < pointCount: - feedback.pushInfo(self.tr('Could not generate requested number of random points. ' - 'Maximum number of attempts exceeded.')) + feedback.pushInfo( + self.tr( + "Could not generate requested number of random points. " + "Maximum number of attempts exceeded." + ) + ) sink.finalize() return {self.OUTPUT: dest_id} diff --git a/python/plugins/processing/algs/qgis/RandomPointsPolygons.py b/python/plugins/processing/algs/qgis/RandomPointsPolygons.py index 3d700e9d701b..c970a4f3ce80 100644 --- a/python/plugins/processing/algs/qgis/RandomPointsPolygons.py +++ b/python/plugins/processing/algs/qgis/RandomPointsPolygons.py @@ -15,37 +15,39 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'April 2014' -__copyright__ = '(C) 2014, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "April 2014" +__copyright__ = "(C) 2014, Alexander Bruy" import os import random from qgis.PyQt.QtCore import QMetaType -from qgis.core import (Qgis, - QgsApplication, - QgsField, - QgsFeatureSink, - QgsFeature, - QgsFields, - QgsGeometry, - QgsPointXY, - QgsWkbTypes, - QgsSpatialIndex, - QgsExpression, - QgsDistanceArea, - QgsPropertyDefinition, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameters, - QgsProcessingParameterDefinition, - QgsProcessingParameterNumber, - QgsProcessingParameterDistance, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterExpression, - QgsProcessingParameterEnum) +from qgis.core import ( + Qgis, + QgsApplication, + QgsField, + QgsFeatureSink, + QgsFeature, + QgsFields, + QgsGeometry, + QgsPointXY, + QgsWkbTypes, + QgsSpatialIndex, + QgsExpression, + QgsDistanceArea, + QgsPropertyDefinition, + QgsProcessing, + QgsProcessingException, + QgsProcessingParameters, + QgsProcessingParameterDefinition, + QgsProcessingParameterNumber, + QgsProcessingParameterDistance, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterExpression, + QgsProcessingParameterEnum, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.tools import vector @@ -54,70 +56,101 @@ class RandomPointsPolygons(QgisAlgorithm): - INPUT = 'INPUT' - VALUE = 'VALUE' - EXPRESSION = 'EXPRESSION' - MIN_DISTANCE = 'MIN_DISTANCE' - STRATEGY = 'STRATEGY' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + VALUE = "VALUE" + EXPRESSION = "EXPRESSION" + MIN_DISTANCE = "MIN_DISTANCE" + STRATEGY = "STRATEGY" + OUTPUT = "OUTPUT" def icon(self): - return QgsApplication.getThemeIcon("/algorithms/mAlgorithmRandomPointsWithinPolygon.svg") + return QgsApplication.getThemeIcon( + "/algorithms/mAlgorithmRandomPointsWithinPolygon.svg" + ) def svgIconPath(self): - return QgsApplication.iconPath("/algorithms/mAlgorithmRandomPointsWithinPolygon.svg") + return QgsApplication.iconPath( + "/algorithms/mAlgorithmRandomPointsWithinPolygon.svg" + ) def group(self): - return self.tr('Vector creation') + return self.tr("Vector creation") def groupId(self): - return 'vectorcreation' + return "vectorcreation" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.strategies = [self.tr('Points count'), - self.tr('Points density')] - - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), - [QgsProcessing.SourceType.TypeVectorPolygon])) - self.addParameter(QgsProcessingParameterEnum(self.STRATEGY, - self.tr('Sampling strategy'), - self.strategies, - False, - 0)) - value_param = QgsProcessingParameterNumber(self.VALUE, - self.tr('Point count or density'), - QgsProcessingParameterNumber.Type.Double, - 1, - minValue=0) + self.strategies = [self.tr("Points count"), self.tr("Points density")] + + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Input layer"), + [QgsProcessing.SourceType.TypeVectorPolygon], + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.STRATEGY, self.tr("Sampling strategy"), self.strategies, False, 0 + ) + ) + value_param = QgsProcessingParameterNumber( + self.VALUE, + self.tr("Point count or density"), + QgsProcessingParameterNumber.Type.Double, + 1, + minValue=0, + ) value_param.setIsDynamic(True) value_param.setDynamicLayerParameterName(self.INPUT) value_param.setDynamicPropertyDefinition( - QgsPropertyDefinition("Value", self.tr("Point count or density"), QgsPropertyDefinition.StandardPropertyTemplate.Double)) + QgsPropertyDefinition( + "Value", + self.tr("Point count or density"), + QgsPropertyDefinition.StandardPropertyTemplate.Double, + ) + ) self.addParameter(value_param) # deprecated expression parameter - overrides value parameter if set - exp_param = QgsProcessingParameterExpression(self.EXPRESSION, - self.tr('Expression'), optional=True, - parentLayerParameterName=self.INPUT) - exp_param.setFlags(exp_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden) + exp_param = QgsProcessingParameterExpression( + self.EXPRESSION, + self.tr("Expression"), + optional=True, + parentLayerParameterName=self.INPUT, + ) + exp_param.setFlags( + exp_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden + ) self.addParameter(exp_param) - self.addParameter(QgsProcessingParameterDistance(self.MIN_DISTANCE, - self.tr('Minimum distance between points'), - None, self.INPUT, True, 0, 1000000000)) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, - self.tr('Random points'), - type=QgsProcessing.SourceType.TypeVectorPoint)) + self.addParameter( + QgsProcessingParameterDistance( + self.MIN_DISTANCE, + self.tr("Minimum distance between points"), + None, + self.INPUT, + True, + 0, + 1000000000, + ) + ) + self.addParameter( + QgsProcessingParameterFeatureSink( + self.OUTPUT, + self.tr("Random points"), + type=QgsProcessing.SourceType.TypeVectorPoint, + ) + ) def name(self): - return 'randompointsinsidepolygons' + return "randompointsinsidepolygons" def displayName(self): - return self.tr('Random points inside polygons') + return self.tr("Random points inside polygons") def documentationFlags(self): return Qgis.ProcessingAlgorithmDocumentationFlag.RegeneratesPrimaryKey @@ -125,10 +158,15 @@ def documentationFlags(self): def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) - if self.MIN_DISTANCE in parameters and parameters[self.MIN_DISTANCE] is not None: + if ( + self.MIN_DISTANCE in parameters + and parameters[self.MIN_DISTANCE] is not None + ): minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context) else: minDistance = None @@ -137,7 +175,9 @@ def processAlgorithm(self, parameters, context, feedback): dynamic_value = QgsProcessingParameters.isDynamic(parameters, "VALUE") value_property = None if self.EXPRESSION in parameters and parameters[self.EXPRESSION] is not None: - expression = QgsExpression(self.parameterAsString(parameters, self.EXPRESSION, context)) + expression = QgsExpression( + self.parameterAsString(parameters, self.EXPRESSION, context) + ) value = None if expression.hasParserError(): raise QgsProcessingException(expression.parserErrorString()) @@ -149,11 +189,17 @@ def processAlgorithm(self, parameters, context, feedback): value = self.parameterAsDouble(parameters, self.VALUE, context) fields = QgsFields() - fields.append(QgsField('id', QMetaType.Type.Int, '', 10, 0)) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, QgsWkbTypes.Type.Point, source.sourceCrs(), - QgsFeatureSink.SinkFlag.RegeneratePrimaryKey) + fields.append(QgsField("id", QMetaType.Type.Int, "", 10, 0)) + + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + fields, + QgsWkbTypes.Type.Point, + source.sourceCrs(), + QgsFeatureSink.SinkFlag.RegeneratePrimaryKey, + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) @@ -178,12 +224,17 @@ def processAlgorithm(self, parameters, context, feedback): if value_property is not None or expression is not None: expressionContext.setFeature(f) if value_property: - this_value, _ = value_property.valueAsDouble(expressionContext, value) + this_value, _ = value_property.valueAsDouble( + expressionContext, value + ) else: this_value = expression.evaluate(expressionContext) if expression.hasEvalError(): feedback.pushInfo( - self.tr('Evaluation error for feature ID {}: {}').format(f.id(), expression.evalErrorString())) + self.tr("Evaluation error for feature ID {}: {}").format( + f.id(), expression.evalErrorString() + ) + ) continue fGeom = f.geometry() @@ -197,7 +248,11 @@ def processAlgorithm(self, parameters, context, feedback): pointCount = int(round(this_value * da.measureArea(fGeom))) if pointCount == 0: - feedback.pushInfo(self.tr("Skip feature {} as number of points for it is 0.").format(f.id())) + feedback.pushInfo( + self.tr("Skip feature {} as number of points for it is 0.").format( + f.id() + ) + ) continue index = None @@ -221,12 +276,14 @@ def processAlgorithm(self, parameters, context, feedback): p = QgsPointXY(rx, ry) geom = QgsGeometry.fromPointXY(p) - if engine.contains(geom.constGet()) and \ - (not minDistance or vector.checkMinDistance(p, index, minDistance, points)): + if engine.contains(geom.constGet()) and ( + not minDistance + or vector.checkMinDistance(p, index, minDistance, points) + ): f = QgsFeature(nPoints) f.initAttributes(1) f.setFields(fields) - f.setAttribute('id', pointId) + f.setAttribute("id", pointId) f.setGeometry(geom) sink.addFeature(f, QgsFeatureSink.Flag.FastInsert) if minDistance: @@ -234,12 +291,18 @@ def processAlgorithm(self, parameters, context, feedback): points[nPoints] = p nPoints += 1 pointId += 1 - feedback.setProgress(current_progress + int(nPoints * feature_total)) + feedback.setProgress( + current_progress + int(nPoints * feature_total) + ) nIterations += 1 if nPoints < pointCount: - feedback.pushInfo(self.tr('Could not generate requested number of random ' - 'points. Maximum number of attempts exceeded.')) + feedback.pushInfo( + self.tr( + "Could not generate requested number of random " + "points. Maximum number of attempts exceeded." + ) + ) feedback.setProgress(100) sink.finalize() diff --git a/python/plugins/processing/algs/qgis/RandomSelection.py b/python/plugins/processing/algs/qgis/RandomSelection.py index 448c2d6e5f9a..57e753f11413 100644 --- a/python/plugins/processing/algs/qgis/RandomSelection.py +++ b/python/plugins/processing/algs/qgis/RandomSelection.py @@ -15,24 +15,26 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import random from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsApplication, - QgsFeatureSink, - QgsProcessingException, - QgsProcessingUtils, - QgsProcessingAlgorithm, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterEnum, - QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSink, - QgsProcessingOutputVectorLayer) +from qgis.core import ( + QgsApplication, + QgsFeatureSink, + QgsProcessingException, + QgsProcessingUtils, + QgsProcessingAlgorithm, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterEnum, + QgsProcessingParameterNumber, + QgsProcessingParameterFeatureSink, + QgsProcessingOutputVectorLayer, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm @@ -40,10 +42,10 @@ class RandomSelection(QgisAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' - METHOD = 'METHOD' - NUMBER = 'NUMBER' + INPUT = "INPUT" + OUTPUT = "OUTPUT" + METHOD = "METHOD" + NUMBER = "NUMBER" def icon(self): return QgsApplication.getThemeIcon("/algorithms/mAlgorithmSelectRandom.svg") @@ -52,35 +54,54 @@ def svgIconPath(self): return QgsApplication.iconPath("/algorithms/mAlgorithmSelectRandom.svg") def group(self): - return self.tr('Vector selection') + return self.tr("Vector selection") def groupId(self): - return 'vectorselection' + return "vectorselection" def flags(self): - return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool + return ( + super().flags() + | QgsProcessingAlgorithm.Flag.FlagNoThreading + | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool + ) def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.methods = [self.tr('Number of selected features'), - self.tr('Percentage of selected features')] - - self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterEnum(self.METHOD, - self.tr('Method'), self.methods, False, 0)) - self.addParameter(QgsProcessingParameterNumber(self.NUMBER, - self.tr('Number/percentage of selected features'), QgsProcessingParameterNumber.Type.Integer, - 10, False, 0.0)) - self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Selected (random)'))) + self.methods = [ + self.tr("Number of selected features"), + self.tr("Percentage of selected features"), + ] + + self.addParameter( + QgsProcessingParameterVectorLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.METHOD, self.tr("Method"), self.methods, False, 0 + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.NUMBER, + self.tr("Number/percentage of selected features"), + QgsProcessingParameterNumber.Type.Integer, + 10, + False, + 0.0, + ) + ) + self.addOutput( + QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Selected (random)")) + ) def name(self): - return 'randomselection' + return "randomselection" def displayName(self): - return self.tr('Random selection') + return self.tr("Random selection") def processAlgorithm(self, parameters, context, feedback): layer = self.parameterAsVectorLayer(parameters, self.INPUT, context) @@ -92,13 +113,19 @@ def processAlgorithm(self, parameters, context, feedback): if method == 0: if value > len(ids): raise QgsProcessingException( - self.tr('Selected number is greater than feature count. ' - 'Choose a lower value and try again.')) + self.tr( + "Selected number is greater than feature count. " + "Choose a lower value and try again." + ) + ) else: if value > 100: raise QgsProcessingException( - self.tr("Percentage can't be greater than 100. Set a " - "different value and try again.")) + self.tr( + "Percentage can't be greater than 100. Set a " + "different value and try again." + ) + ) value = int(round(value / 100.0, 4) * len(ids)) selran = random.sample(ids, value) diff --git a/python/plugins/processing/algs/qgis/RandomSelectionWithinSubsets.py b/python/plugins/processing/algs/qgis/RandomSelectionWithinSubsets.py index 4a55b483b3d5..37b8542642fc 100644 --- a/python/plugins/processing/algs/qgis/RandomSelectionWithinSubsets.py +++ b/python/plugins/processing/algs/qgis/RandomSelectionWithinSubsets.py @@ -15,26 +15,28 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import random from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsApplication, - QgsFeatureRequest, - QgsProcessingException, - QgsProcessingUtils, - QgsProcessingAlgorithm, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterEnum, - QgsProcessingParameterField, - QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSink, - QgsProcessingOutputVectorLayer) +from qgis.core import ( + QgsApplication, + QgsFeatureRequest, + QgsProcessingException, + QgsProcessingUtils, + QgsProcessingAlgorithm, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterEnum, + QgsProcessingParameterField, + QgsProcessingParameterNumber, + QgsProcessingParameterFeatureSink, + QgsProcessingOutputVectorLayer, +) from collections import defaultdict from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm @@ -42,11 +44,11 @@ class RandomSelectionWithinSubsets(QgisAlgorithm): - INPUT = 'INPUT' - METHOD = 'METHOD' - NUMBER = 'NUMBER' - FIELD = 'FIELD' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + METHOD = "METHOD" + NUMBER = "NUMBER" + FIELD = "FIELD" + OUTPUT = "OUTPUT" def icon(self): return QgsApplication.getThemeIcon("/algorithms/mAlgorithmSelectRandom.svg") @@ -55,38 +57,61 @@ def svgIconPath(self): return QgsApplication.iconPath("/algorithms/mAlgorithmSelectRandom.svg") def group(self): - return self.tr('Vector selection') + return self.tr("Vector selection") def groupId(self): - return 'vectorselection' + return "vectorselection" def __init__(self): super().__init__() def flags(self): - return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool + return ( + super().flags() + | QgsProcessingAlgorithm.Flag.FlagNoThreading + | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool + ) def initAlgorithm(self, config=None): - self.methods = [self.tr('Number of selected features'), - self.tr('Percentage of selected features')] - - self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterField(self.FIELD, - self.tr('ID field'), None, self.INPUT)) - self.addParameter(QgsProcessingParameterEnum(self.METHOD, - self.tr('Method'), self.methods, False, 0)) - self.addParameter(QgsProcessingParameterNumber(self.NUMBER, - self.tr('Number/percentage of selected features'), - QgsProcessingParameterNumber.Type.Integer, - 10, False, 0.0)) - self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Selected (stratified random)'))) + self.methods = [ + self.tr("Number of selected features"), + self.tr("Percentage of selected features"), + ] + + self.addParameter( + QgsProcessingParameterVectorLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterField( + self.FIELD, self.tr("ID field"), None, self.INPUT + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.METHOD, self.tr("Method"), self.methods, False, 0 + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.NUMBER, + self.tr("Number/percentage of selected features"), + QgsProcessingParameterNumber.Type.Integer, + 10, + False, + 0.0, + ) + ) + self.addOutput( + QgsProcessingOutputVectorLayer( + self.OUTPUT, self.tr("Selected (stratified random)") + ) + ) def name(self): - return 'randomselectionwithinsubsets' + return "randomselectionwithinsubsets" def displayName(self): - return self.tr('Random selection within subsets') + return self.tr("Random selection within subsets") def processAlgorithm(self, parameters, context, feedback): layer = self.parameterAsVectorLayer(parameters, self.INPUT, context) @@ -102,13 +127,19 @@ def processAlgorithm(self, parameters, context, feedback): if method == 0: if value > featureCount: raise QgsProcessingException( - self.tr('Selected number is greater that feature count. ' - 'Choose lesser value and try again.')) + self.tr( + "Selected number is greater that feature count. " + "Choose lesser value and try again." + ) + ) else: if value > 100: raise QgsProcessingException( - self.tr("Percentage can't be greater than 100. Set a " - "different value and try again.")) + self.tr( + "Percentage can't be greater than 100. Set a " + "different value and try again." + ) + ) value = value / 100.0 total = 100.0 / (featureCount * len(unique)) if featureCount else 1 @@ -116,7 +147,11 @@ def processAlgorithm(self, parameters, context, feedback): if len(unique) != featureCount: classes = defaultdict(list) - features = layer.getFeatures(QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry).setSubsetOfAttributes([index])) + features = layer.getFeatures( + QgsFeatureRequest() + .setFlags(QgsFeatureRequest.Flag.NoGeometry) + .setSubsetOfAttributes([index]) + ) for i, feature in enumerate(features): if feedback.isCanceled(): @@ -133,11 +168,17 @@ def processAlgorithm(self, parameters, context, feedback): selValue = value if method != 1 else int(round(value * len(subset), 0)) if selValue > len(subset): selValue = len(subset) - feedback.reportError(self.tr('Subset "{}" is smaller than requested number of features.').format(k)) + feedback.reportError( + self.tr( + 'Subset "{}" is smaller than requested number of features.' + ).format(k) + ) selran.extend(random.sample(subset, selValue)) layer.selectByIds(selran) else: - layer.selectByIds(list(range(featureCount))) # FIXME: implies continuous feature ids + layer.selectByIds( + list(range(featureCount)) + ) # FIXME: implies continuous feature ids return {self.OUTPUT: parameters[self.INPUT]} diff --git a/python/plugins/processing/algs/qgis/RasterCalculator.py b/python/plugins/processing/algs/qgis/RasterCalculator.py index 38f414bf3205..6dcf76f8c273 100644 --- a/python/plugins/processing/algs/qgis/RasterCalculator.py +++ b/python/plugins/processing/algs/qgis/RasterCalculator.py @@ -15,45 +15,47 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'November 2016' -__copyright__ = '(C) 2016, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "November 2016" +__copyright__ = "(C) 2016, Victor Olaya" import os import math from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.algs.gdal.GdalUtils import GdalUtils -from qgis.core import (QgsProcessing, - QgsProcessingAlgorithm, - QgsProcessingException, - QgsProcessingUtils, - QgsProcessingParameterCrs, - QgsProcessingParameterMultipleLayers, - QgsProcessingParameterNumber, - QgsProcessingParameterExtent, - QgsProcessingParameterRasterDestination, - QgsProcessingParameterRasterLayer, - QgsProcessingOutputRasterLayer, - QgsProcessingParameterString, - QgsCoordinateTransform, - QgsMapLayer) +from qgis.core import ( + QgsProcessing, + QgsProcessingAlgorithm, + QgsProcessingException, + QgsProcessingUtils, + QgsProcessingParameterCrs, + QgsProcessingParameterMultipleLayers, + QgsProcessingParameterNumber, + QgsProcessingParameterExtent, + QgsProcessingParameterRasterDestination, + QgsProcessingParameterRasterLayer, + QgsProcessingOutputRasterLayer, + QgsProcessingParameterString, + QgsCoordinateTransform, + QgsMapLayer, +) from qgis.PyQt.QtCore import QObject from qgis.analysis import QgsRasterCalculator, QgsRasterCalculatorEntry class RasterCalculator(QgisAlgorithm): - LAYERS = 'LAYERS' - EXTENT = 'EXTENT' - CELLSIZE = 'CELLSIZE' - EXPRESSION = 'EXPRESSION' - CRS = 'CRS' - OUTPUT = 'OUTPUT' + LAYERS = "LAYERS" + EXTENT = "EXTENT" + CELLSIZE = "CELLSIZE" + EXPRESSION = "EXPRESSION" + CRS = "CRS" + OUTPUT = "OUTPUT" def group(self): - return self.tr('Raster analysis') + return self.tr("Raster analysis") def groupId(self): - return 'rasteranalysis' + return "rasteranalysis" def __init__(self): super().__init__() @@ -61,42 +63,67 @@ def __init__(self): def initAlgorithm(self, config=None): class ParameterRasterCalculatorExpression(QgsProcessingParameterString): - def __init__(self, name='', description='', multiLine=False): + def __init__(self, name="", description="", multiLine=False): super().__init__(name, description, multiLine=multiLine) - self.setMetadata({ - 'widget_wrapper': 'processing.algs.qgis.ui.RasterCalculatorWidgets.ExpressionWidgetWrapper' - }) + self.setMetadata( + { + "widget_wrapper": "processing.algs.qgis.ui.RasterCalculatorWidgets.ExpressionWidgetWrapper" + } + ) def type(self): - return 'raster_calc_expression' + return "raster_calc_expression" def clone(self): - return ParameterRasterCalculatorExpression(self.name(), self.description(), self.multiLine()) - - self.addParameter(ParameterRasterCalculatorExpression(self.EXPRESSION, self.tr('Expression'), - multiLine=True)) - self.addParameter(QgsProcessingParameterMultipleLayers(self.LAYERS, - self.tr('Reference layer(s) (used for automated extent, cellsize, and CRS)'), - layerType=QgsProcessing.SourceType.TypeRaster, - optional=True)) - self.addParameter(QgsProcessingParameterNumber(self.CELLSIZE, - self.tr('Cell size (use 0 or empty to set it automatically)'), - type=QgsProcessingParameterNumber.Type.Double, - minValue=0.0, defaultValue=0.0, optional=True)) - self.addParameter(QgsProcessingParameterExtent(self.EXTENT, - self.tr('Output extent'), - optional=True)) - self.addParameter(QgsProcessingParameterCrs(self.CRS, 'Output CRS', optional=True)) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Output'))) + return ParameterRasterCalculatorExpression( + self.name(), self.description(), self.multiLine() + ) + + self.addParameter( + ParameterRasterCalculatorExpression( + self.EXPRESSION, self.tr("Expression"), multiLine=True + ) + ) + self.addParameter( + QgsProcessingParameterMultipleLayers( + self.LAYERS, + self.tr( + "Reference layer(s) (used for automated extent, cellsize, and CRS)" + ), + layerType=QgsProcessing.SourceType.TypeRaster, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.CELLSIZE, + self.tr("Cell size (use 0 or empty to set it automatically)"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.0, + defaultValue=0.0, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterExtent( + self.EXTENT, self.tr("Output extent"), optional=True + ) + ) + self.addParameter( + QgsProcessingParameterCrs(self.CRS, "Output CRS", optional=True) + ) + self.addParameter( + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Output")) + ) def flags(self): return super().flags() | QgsProcessingAlgorithm.Flag.FlagDeprecated def name(self): - return 'rastercalculator' + return "rastercalculator" def displayName(self): - return self.tr('Raster calculator') + return self.tr("Raster calculator") def processAlgorithm(self, parameters, context, feedback): expression = self.parameterAsString(parameters, self.EXPRESSION, context) @@ -109,18 +136,24 @@ def processAlgorithm(self, parameters, context, feedback): crs = self.parameterAsCrs(parameters, self.CRS, context) if crs is None or not crs.isValid(): if not layers: - raise QgsProcessingException(self.tr("No reference layer selected nor CRS provided")) + raise QgsProcessingException( + self.tr("No reference layer selected nor CRS provided") + ) else: crs = list(layersDict.values())[0].crs() bbox = self.parameterAsExtent(parameters, self.EXTENT, context) if bbox.isNull() and not layers: - raise QgsProcessingException(self.tr("No reference layer selected nor extent box provided")) + raise QgsProcessingException( + self.tr("No reference layer selected nor extent box provided") + ) if not bbox.isNull(): bboxCrs = self.parameterAsExtentCrs(parameters, self.EXTENT, context) if bboxCrs != crs: - transform = QgsCoordinateTransform(bboxCrs, crs, context.transformContext()) + transform = QgsCoordinateTransform( + bboxCrs, crs, context.transformContext() + ) bbox = transform.transformBoundingBox(bbox) if bbox.isNull() and layers: @@ -128,12 +161,16 @@ def processAlgorithm(self, parameters, context, feedback): cellsize = self.parameterAsDouble(parameters, self.CELLSIZE, context) if cellsize == 0 and not layers: - raise QgsProcessingException(self.tr("No reference layer selected nor cellsize value provided")) + raise QgsProcessingException( + self.tr("No reference layer selected nor cellsize value provided") + ) def _cellsize(layer): ext = layer.extent() if layer.crs() != crs: - transform = QgsCoordinateTransform(layer.crs(), crs, context.transformContext()) + transform = QgsCoordinateTransform( + layer.crs(), crs, context.transformContext() + ) ext = transform.transformBoundingBox(ext) return (ext.xMaximum() - ext.xMinimum()) / layer.width() @@ -141,14 +178,18 @@ def _cellsize(layer): cellsize = min([_cellsize(lyr) for lyr in layersDict.values()]) # check for layers available in the model - layersDictCopy = layersDict.copy() # need a shallow copy because next calls invalidate iterator + layersDictCopy = ( + layersDict.copy() + ) # need a shallow copy because next calls invalidate iterator for lyr in layersDictCopy.values(): expression = self.mappedNameToLayer(lyr, expression, layersDict, context) # check for layers available in the project if context.project(): for lyr in QgsProcessingUtils.compatibleRasterLayers(context.project()): - expression = self.mappedNameToLayer(lyr, expression, layersDict, context) + expression = self.mappedNameToLayer( + lyr, expression, layersDict, context + ) # create the list of layers to be passed as inputs to RasterCalculaltor # at this phase expression has been modified to match available layers @@ -156,7 +197,7 @@ def _cellsize(layer): entries = [] for name, lyr in layersDict.items(): for n in range(lyr.bandCount()): - ref = f'{name:s}@{n + 1:d}' + ref = f"{name:s}@{n + 1:d}" if ref in expression: entry = QgsRasterCalculatorEntry() @@ -176,26 +217,30 @@ def _cellsize(layer): height = round((bbox.yMaximum() - bbox.yMinimum()) / cellsize) driverName = GdalUtils.getFormatShortNameFromFilename(output) - calc = QgsRasterCalculator(expression, - output, - driverName, - bbox, - crs, - width, - height, - entries, - context.transformContext()) + calc = QgsRasterCalculator( + expression, + output, + driverName, + bbox, + crs, + width, + height, + entries, + context.transformContext(), + ) res = calc.processCalculation(feedback) if res == QgsRasterCalculator.Result.ParserError: raise QgsProcessingException(self.tr("Error parsing formula")) elif res == QgsRasterCalculator.Result.CalculationError: - raise QgsProcessingException(self.tr("An error occurred while performing the calculation")) + raise QgsProcessingException( + self.tr("An error occurred while performing the calculation") + ) return {self.OUTPUT: output} def mappedNameToLayer(self, lyr, expression, layersDict, context): - '''Try to identify if a real layer is mapped in the expression with a symbolic name.''' + """Try to identify if a real layer is mapped in the expression with a symbolic name.""" nameToMap = lyr.source() @@ -224,10 +269,15 @@ def mappedNameToLayer(self, lyr, expression, layersDict, context): layerInContext = expContextAlgInputsScope.variable(varName) - if not isinstance(layerInContext, str) and not isinstance(layerInContext, QgsMapLayer): + if not isinstance(layerInContext, str) and not isinstance( + layerInContext, QgsMapLayer + ): continue - if isinstance(layerInContext, QgsMapLayer) and nameToMap not in layerInContext.source(): + if ( + isinstance(layerInContext, QgsMapLayer) + and nameToMap not in layerInContext.source() + ): continue varDescription = expContextAlgInputsScope.description(varName) @@ -247,12 +297,14 @@ def mappedNameToLayer(self, lyr, expression, layersDict, context): # HAVE to use the same translated string as in # https://github.com/qgis/QGIS/blob/master/src/core/processing/models/qgsprocessingmodelalgorithm.cpp#L516 translatedDesc = self.tr("Output '%1' from algorithm '%2'") - elementZero = translatedDesc.split(" ")[0] # For english the string result should be "Output" + elementZero = translatedDesc.split(" ")[ + 0 + ] # For english the string result should be "Output" elements = varDescription.split(" ") if len(elements) > 1 and elements[0] == elementZero: # remove heading QObject.tr"Output ") string. Note adding a space at the end of elementZero! - varDescription = varDescription[len(elementZero) + 1:] + varDescription = varDescription[len(elementZero) + 1 :] # check if cleaned varDescription is present in the expression # if not skip it diff --git a/python/plugins/processing/algs/qgis/RasterLayerHistogram.py b/python/plugins/processing/algs/qgis/RasterLayerHistogram.py index df63eb28e143..92c787e3dde4 100644 --- a/python/plugins/processing/algs/qgis/RasterLayerHistogram.py +++ b/python/plugins/processing/algs/qgis/RasterLayerHistogram.py @@ -15,17 +15,19 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'January 2013' -__copyright__ = '(C) 2013, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "January 2013" +__copyright__ = "(C) 2013, Victor Olaya" import warnings -from qgis.core import (QgsProcessingParameterRasterLayer, - QgsProcessingParameterBand, - QgsProcessingParameterNumber, - QgsProcessingParameterFileDestination, - QgsProcessingException) +from qgis.core import ( + QgsProcessingParameterRasterLayer, + QgsProcessingParameterBand, + QgsProcessingParameterNumber, + QgsProcessingParameterFileDestination, + QgsProcessingException, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.tools import raster @@ -34,37 +36,44 @@ class RasterLayerHistogram(QgisAlgorithm): - INPUT = 'INPUT' - BINS = 'BINS' - OUTPUT = 'OUTPUT' - BAND = 'BAND' + INPUT = "INPUT" + BINS = "BINS" + OUTPUT = "OUTPUT" + BAND = "BAND" def group(self): - return self.tr('Plots') + return self.tr("Plots") def groupId(self): - return 'plots' + return "plots" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterBand(self.BAND, - self.tr('Band number'), - 1, - self.INPUT)) - self.addParameter(QgsProcessingParameterNumber(self.BINS, - self.tr('number of bins'), minValue=2, defaultValue=10)) - - self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, self.tr('Histogram'), self.tr('HTML files (*.html)'))) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterBand(self.BAND, self.tr("Band number"), 1, self.INPUT) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.BINS, self.tr("number of bins"), minValue=2, defaultValue=10 + ) + ) + + self.addParameter( + QgsProcessingParameterFileDestination( + self.OUTPUT, self.tr("Histogram"), self.tr("HTML files (*.html)") + ) + ) def name(self): - return 'rasterlayerhistogram' + return "rasterlayerhistogram" def displayName(self): - return self.tr('Raster layer histogram') + return self.tr("Raster layer histogram") def processAlgorithm(self, parameters, context, feedback): try: @@ -75,7 +84,12 @@ def processAlgorithm(self, parameters, context, feedback): import plotly as plt import plotly.graph_objs as go except ImportError: - raise QgsProcessingException(QCoreApplication.translate('RasterLayerHistogram', 'This algorithm requires the Python “plotly” library. Please install this library and try again.')) + raise QgsProcessingException( + QCoreApplication.translate( + "RasterLayerHistogram", + "This algorithm requires the Python “plotly” library. Please install this library and try again.", + ) + ) layer = self.parameterAsRasterLayer(parameters, self.INPUT, context) band = self.parameterAsInt(parameters, self.BAND, context) @@ -86,13 +100,8 @@ def processAlgorithm(self, parameters, context, feedback): # ALERT: this is potentially blocking if the layer is too big values = raster.scanraster(layer, feedback, band) - valueslist = [ - v - for v in values - if v is not None - ] - data = [go.Histogram(x=valueslist, - nbinsx=nbins)] + valueslist = [v for v in values if v is not None] + data = [go.Histogram(x=valueslist, nbinsx=nbins)] plt.offline.plot(data, filename=output, auto_open=False) return {self.OUTPUT: output} diff --git a/python/plugins/processing/algs/qgis/RectanglesOvalsDiamondsVariable.py b/python/plugins/processing/algs/qgis/RectanglesOvalsDiamondsVariable.py index a209d4ce7005..68b420394d0b 100644 --- a/python/plugins/processing/algs/qgis/RectanglesOvalsDiamondsVariable.py +++ b/python/plugins/processing/algs/qgis/RectanglesOvalsDiamondsVariable.py @@ -15,45 +15,47 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Alexander Bruy" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import math from qgis.PyQt.QtCore import QCoreApplication -from qgis.core import (NULL, - QgsWkbTypes, - QgsFeature, - QgsFeatureSink, - QgsGeometry, - QgsPointXY, - QgsProcessing, - QgsProcessingException, - QgsProcessingAlgorithm, - QgsProcessingParameterField, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterEnum, - QgsProcessingParameterNumber, - QgsProcessingParameterFeatureSink) +from qgis.core import ( + NULL, + QgsWkbTypes, + QgsFeature, + QgsFeatureSink, + QgsGeometry, + QgsPointXY, + QgsProcessing, + QgsProcessingException, + QgsProcessingAlgorithm, + QgsProcessingParameterField, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterEnum, + QgsProcessingParameterNumber, + QgsProcessingParameterFeatureSink, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm class RectanglesOvalsDiamondsVariable(QgisAlgorithm): - INPUT = 'INPUT' - SHAPE = 'SHAPE' - WIDTH = 'WIDTH' - HEIGHT = 'HEIGHT' - ROTATION = 'ROTATION' - SEGMENTS = 'SEGMENTS' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + SHAPE = "SHAPE" + WIDTH = "WIDTH" + HEIGHT = "HEIGHT" + ROTATION = "ROTATION" + SEGMENTS = "SEGMENTS" + OUTPUT = "OUTPUT" def group(self): - return self.tr('Vector geometry') + return self.tr("Vector geometry") def groupId(self): - return 'vectorgeometry' + return "vectorgeometry" def __init__(self): super().__init__() @@ -62,47 +64,76 @@ def flags(self): return super().flags() | QgsProcessingAlgorithm.Flag.FlagDeprecated def initAlgorithm(self, config=None): - self.shapes = [self.tr('Rectangles'), self.tr('Diamonds'), self.tr('Ovals')] - - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), - [QgsProcessing.SourceType.TypeVectorPoint])) - - self.addParameter(QgsProcessingParameterEnum(self.SHAPE, - self.tr('Buffer shape'), options=self.shapes)) - - self.addParameter(QgsProcessingParameterField(self.WIDTH, - self.tr('Width field'), - parentLayerParameterName=self.INPUT, - type=QgsProcessingParameterField.DataType.Numeric)) - self.addParameter(QgsProcessingParameterField(self.HEIGHT, - self.tr('Height field'), - parentLayerParameterName=self.INPUT, - type=QgsProcessingParameterField.DataType.Numeric)) - self.addParameter(QgsProcessingParameterField(self.ROTATION, - self.tr('Rotation field'), - parentLayerParameterName=self.INPUT, - type=QgsProcessingParameterField.DataType.Numeric, - optional=True)) - self.addParameter(QgsProcessingParameterNumber(self.SEGMENTS, - self.tr('Number of segments'), - minValue=1, - defaultValue=36)) - - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, - self.tr('Output'), - type=QgsProcessing.SourceType.TypeVectorPolygon)) + self.shapes = [self.tr("Rectangles"), self.tr("Diamonds"), self.tr("Ovals")] + + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Input layer"), + [QgsProcessing.SourceType.TypeVectorPoint], + ) + ) + + self.addParameter( + QgsProcessingParameterEnum( + self.SHAPE, self.tr("Buffer shape"), options=self.shapes + ) + ) + + self.addParameter( + QgsProcessingParameterField( + self.WIDTH, + self.tr("Width field"), + parentLayerParameterName=self.INPUT, + type=QgsProcessingParameterField.DataType.Numeric, + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.HEIGHT, + self.tr("Height field"), + parentLayerParameterName=self.INPUT, + type=QgsProcessingParameterField.DataType.Numeric, + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.ROTATION, + self.tr("Rotation field"), + parentLayerParameterName=self.INPUT, + type=QgsProcessingParameterField.DataType.Numeric, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.SEGMENTS, + self.tr("Number of segments"), + minValue=1, + defaultValue=36, + ) + ) + + self.addParameter( + QgsProcessingParameterFeatureSink( + self.OUTPUT, + self.tr("Output"), + type=QgsProcessing.SourceType.TypeVectorPolygon, + ) + ) def name(self): - return 'rectanglesovalsdiamondsvariable' + return "rectanglesovalsdiamondsvariable" def displayName(self): - return self.tr('Rectangles, ovals, diamonds (variable)') + return self.tr("Rectangles, ovals, diamonds (variable)") def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) shape = self.parameterAsEnum(parameters, self.SHAPE, context) @@ -111,8 +142,14 @@ def processAlgorithm(self, parameters, context, feedback): rotation_field = self.parameterAsString(parameters, self.ROTATION, context) segments = self.parameterAsInt(parameters, self.SEGMENTS, context) - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - source.fields(), QgsWkbTypes.Type.Polygon, source.sourceCrs()) + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + source.fields(), + QgsWkbTypes.Type.Polygon, + source.sourceCrs(), + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) @@ -148,14 +185,20 @@ def rectangles(self, sink, source, width, height, rotation, feedback): angle = feat[rotation] # block 0/NULL width or height, but allow 0 as angle value if not w or not h: - feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty ' - 'width or height. ' - 'Skipping…').format(feat.id())) + feedback.pushInfo( + QCoreApplication.translate( + "RectanglesOvalsDiamondsVariable", + "Feature {} has empty " "width or height. " "Skipping…", + ).format(feat.id()) + ) continue if angle is NULL: - feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty ' - 'angle. ' - 'Skipping…').format(feat.id())) + feedback.pushInfo( + QCoreApplication.translate( + "RectanglesOvalsDiamondsVariable", + "Feature {} has empty " "angle. " "Skipping…", + ).format(feat.id()) + ) continue xOffset = w / 2.0 @@ -165,9 +208,21 @@ def rectangles(self, sink, source, width, height, rotation, feedback): point = feat.geometry().asPoint() x = point.x() y = point.y() - points = [(-xOffset, -yOffset), (-xOffset, yOffset), (xOffset, yOffset), (xOffset, -yOffset)] - polygon = [[QgsPointXY(i[0] * math.cos(phi) + i[1] * math.sin(phi) + x, - -i[0] * math.sin(phi) + i[1] * math.cos(phi) + y) for i in points]] + points = [ + (-xOffset, -yOffset), + (-xOffset, yOffset), + (xOffset, yOffset), + (xOffset, -yOffset), + ] + polygon = [ + [ + QgsPointXY( + i[0] * math.cos(phi) + i[1] * math.sin(phi) + x, + -i[0] * math.sin(phi) + i[1] * math.cos(phi) + y, + ) + for i in points + ] + ] ft.setGeometry(QgsGeometry.fromPolygonXY(polygon)) ft.setAttributes(feat.attributes()) @@ -185,9 +240,12 @@ def rectangles(self, sink, source, width, height, rotation, feedback): w = feat[width] h = feat[height] if not w or not h: - feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty ' - 'width or height. ' - 'Skipping…').format(feat.id())) + feedback.pushInfo( + QCoreApplication.translate( + "RectanglesOvalsDiamondsVariable", + "Feature {} has empty " "width or height. " "Skipping…", + ).format(feat.id()) + ) continue xOffset = w / 2.0 @@ -196,7 +254,12 @@ def rectangles(self, sink, source, width, height, rotation, feedback): point = feat.geometry().asPoint() x = point.x() y = point.y() - points = [(-xOffset, -yOffset), (-xOffset, yOffset), (xOffset, yOffset), (xOffset, -yOffset)] + points = [ + (-xOffset, -yOffset), + (-xOffset, yOffset), + (xOffset, yOffset), + (xOffset, -yOffset), + ] polygon = [[QgsPointXY(i[0] + x, i[1] + y) for i in points]] ft.setGeometry(QgsGeometry.fromPolygonXY(polygon)) @@ -223,14 +286,20 @@ def diamonds(self, sink, source, width, height, rotation, feedback): angle = feat[rotation] # block 0/NULL width or height, but allow 0 as angle value if not w or not h: - feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty ' - 'width or height. ' - 'Skipping…').format(feat.id())) + feedback.pushInfo( + QCoreApplication.translate( + "RectanglesOvalsDiamondsVariable", + "Feature {} has empty " "width or height. " "Skipping…", + ).format(feat.id()) + ) continue if angle is NULL: - feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty ' - 'angle. ' - 'Skipping…').format(feat.id())) + feedback.pushInfo( + QCoreApplication.translate( + "RectanglesOvalsDiamondsVariable", + "Feature {} has empty " "angle. " "Skipping…", + ).format(feat.id()) + ) continue xOffset = w / 2.0 @@ -240,9 +309,21 @@ def diamonds(self, sink, source, width, height, rotation, feedback): point = feat.geometry().asPoint() x = point.x() y = point.y() - points = [(0.0, -yOffset), (-xOffset, 0.0), (0.0, yOffset), (xOffset, 0.0)] - polygon = [[QgsPointXY(i[0] * math.cos(phi) + i[1] * math.sin(phi) + x, - -i[0] * math.sin(phi) + i[1] * math.cos(phi) + y) for i in points]] + points = [ + (0.0, -yOffset), + (-xOffset, 0.0), + (0.0, yOffset), + (xOffset, 0.0), + ] + polygon = [ + [ + QgsPointXY( + i[0] * math.cos(phi) + i[1] * math.sin(phi) + x, + -i[0] * math.sin(phi) + i[1] * math.cos(phi) + y, + ) + for i in points + ] + ] ft.setGeometry(QgsGeometry.fromPolygonXY(polygon)) ft.setAttributes(feat.attributes()) @@ -259,9 +340,12 @@ def diamonds(self, sink, source, width, height, rotation, feedback): w = feat[width] h = feat[height] if not w or not h: - feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty ' - 'width or height. ' - 'Skipping…').format(feat.id())) + feedback.pushInfo( + QCoreApplication.translate( + "RectanglesOvalsDiamondsVariable", + "Feature {} has empty " "width or height. " "Skipping…", + ).format(feat.id()) + ) continue xOffset = w / 2.0 @@ -270,7 +354,12 @@ def diamonds(self, sink, source, width, height, rotation, feedback): point = feat.geometry().asPoint() x = point.x() y = point.y() - points = [(0.0, -yOffset), (-xOffset, 0.0), (0.0, yOffset), (xOffset, 0.0)] + points = [ + (0.0, -yOffset), + (-xOffset, 0.0), + (0.0, yOffset), + (xOffset, 0.0), + ] polygon = [[QgsPointXY(i[0] + x, i[1] + y) for i in points]] ft.setGeometry(QgsGeometry.fromPolygonXY(polygon)) @@ -296,14 +385,20 @@ def ovals(self, sink, source, width, height, rotation, segments, feedback): angle = feat[rotation] # block 0/NULL width or height, but allow 0 as angle value if not w or not h: - feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty ' - 'width or height. ' - 'Skipping…').format(feat.id())) + feedback.pushInfo( + QCoreApplication.translate( + "RectanglesOvalsDiamondsVariable", + "Feature {} has empty " "width or height. " "Skipping…", + ).format(feat.id()) + ) continue if angle == NULL: - feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty ' - 'angle. ' - 'Skipping…').format(feat.id())) + feedback.pushInfo( + QCoreApplication.translate( + "RectanglesOvalsDiamondsVariable", + "Feature {} has empty " "angle. " "Skipping…", + ).format(feat.id()) + ) continue xOffset = w / 2.0 @@ -318,8 +413,15 @@ def ovals(self, sink, source, width, height, rotation, segments, feedback): for t in [(2 * math.pi) / segments * i for i in range(segments)] ] - polygon = [[QgsPointXY(i[0] * math.cos(phi) + i[1] * math.sin(phi) + x, - -i[0] * math.sin(phi) + i[1] * math.cos(phi) + y) for i in points]] + polygon = [ + [ + QgsPointXY( + i[0] * math.cos(phi) + i[1] * math.sin(phi) + x, + -i[0] * math.sin(phi) + i[1] * math.cos(phi) + y, + ) + for i in points + ] + ] ft.setGeometry(QgsGeometry.fromPolygonXY(polygon)) ft.setAttributes(feat.attributes()) @@ -336,9 +438,12 @@ def ovals(self, sink, source, width, height, rotation, segments, feedback): w = feat[width] h = feat[height] if not w or not h: - feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty ' - 'width or height. ' - 'Skipping…').format(feat.id())) + feedback.pushInfo( + QCoreApplication.translate( + "RectanglesOvalsDiamondsVariable", + "Feature {} has empty " "width or height. " "Skipping…", + ).format(feat.id()) + ) continue xOffset = w / 2.0 diff --git a/python/plugins/processing/algs/qgis/RegularPoints.py b/python/plugins/processing/algs/qgis/RegularPoints.py index 738dcd624381..672b1d745fbd 100644 --- a/python/plugins/processing/algs/qgis/RegularPoints.py +++ b/python/plugins/processing/algs/qgis/RegularPoints.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'September 2014' -__copyright__ = '(C) 2014, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "September 2014" +__copyright__ = "(C) 2014, Alexander Bruy" import os from random import seed, uniform @@ -25,21 +25,23 @@ from qgis.PyQt.QtGui import QIcon from qgis.PyQt.QtCore import QMetaType -from qgis.core import (QgsApplication, - QgsFields, - QgsFeatureSink, - QgsField, - QgsFeature, - QgsWkbTypes, - QgsGeometry, - QgsPoint, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterDistance, - QgsProcessingParameterExtent, - QgsProcessingParameterBoolean, - QgsProcessingParameterCrs, - QgsProcessingParameterFeatureSink) +from qgis.core import ( + QgsApplication, + QgsFields, + QgsFeatureSink, + QgsField, + QgsFeature, + QgsWkbTypes, + QgsGeometry, + QgsPoint, + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterDistance, + QgsProcessingParameterExtent, + QgsProcessingParameterBoolean, + QgsProcessingParameterCrs, + QgsProcessingParameterFeatureSink, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm @@ -47,13 +49,13 @@ class RegularPoints(QgisAlgorithm): - EXTENT = 'EXTENT' - SPACING = 'SPACING' - INSET = 'INSET' - RANDOMIZE = 'RANDOMIZE' - IS_SPACING = 'IS_SPACING' - OUTPUT = 'OUTPUT' - CRS = 'CRS' + EXTENT = "EXTENT" + SPACING = "SPACING" + INSET = "INSET" + RANDOMIZE = "RANDOMIZE" + IS_SPACING = "IS_SPACING" + OUTPUT = "OUTPUT" + CRS = "CRS" def icon(self): return QgsApplication.getThemeIcon("/algorithms/mAlgorithmRegularPoints.svg") @@ -62,35 +64,69 @@ def svgIconPath(self): return QgsApplication.iconPath("/algorithms/mAlgorithmRegularPoints.svg") def group(self): - return self.tr('Vector creation') + return self.tr("Vector creation") def groupId(self): - return 'vectorcreation' + return "vectorcreation" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterExtent(self.EXTENT, - self.tr('Input extent'), optional=False)) - self.addParameter(QgsProcessingParameterDistance(self.SPACING, - self.tr('Point spacing/count'), 100, self.CRS, False, 0.000001)) - self.addParameter(QgsProcessingParameterDistance(self.INSET, - self.tr('Initial inset from corner (LH side)'), 0.0, self.CRS, False, 0.0)) - self.addParameter(QgsProcessingParameterBoolean(self.RANDOMIZE, - self.tr('Apply random offset to point spacing'), False)) - self.addParameter(QgsProcessingParameterBoolean(self.IS_SPACING, - self.tr('Use point spacing'), True)) - self.addParameter(QgsProcessingParameterCrs(self.CRS, - self.tr('Output layer CRS'), 'ProjectCrs')) - - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Regular points'), QgsProcessing.SourceType.TypeVectorPoint)) + self.addParameter( + QgsProcessingParameterExtent( + self.EXTENT, self.tr("Input extent"), optional=False + ) + ) + self.addParameter( + QgsProcessingParameterDistance( + self.SPACING, + self.tr("Point spacing/count"), + 100, + self.CRS, + False, + 0.000001, + ) + ) + self.addParameter( + QgsProcessingParameterDistance( + self.INSET, + self.tr("Initial inset from corner (LH side)"), + 0.0, + self.CRS, + False, + 0.0, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.RANDOMIZE, self.tr("Apply random offset to point spacing"), False + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.IS_SPACING, self.tr("Use point spacing"), True + ) + ) + self.addParameter( + QgsProcessingParameterCrs( + self.CRS, self.tr("Output layer CRS"), "ProjectCrs" + ) + ) + + self.addParameter( + QgsProcessingParameterFeatureSink( + self.OUTPUT, + self.tr("Regular points"), + QgsProcessing.SourceType.TypeVectorPoint, + ) + ) def name(self): - return 'regularpoints' + return "regularpoints" def displayName(self): - return self.tr('Regular points') + return self.tr("Regular points") def processAlgorithm(self, parameters, context, feedback): spacing = self.parameterAsDouble(parameters, self.SPACING, context) @@ -101,10 +137,11 @@ def processAlgorithm(self, parameters, context, feedback): extent = self.parameterAsExtent(parameters, self.EXTENT, context, crs) fields = QgsFields() - fields.append(QgsField('id', QMetaType.Type.Int, '', 10, 0)) + fields.append(QgsField("id", QMetaType.Type.Int, "", 10, 0)) - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, QgsWkbTypes.Type.Point, crs) + (sink, dest_id) = self.parameterAsSink( + parameters, self.OUTPUT, context, fields, QgsWkbTypes.Type.Point, crs + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) @@ -137,9 +174,12 @@ def processAlgorithm(self, parameters, context, feedback): break if randomize: - geom = QgsGeometry(QgsPoint( - uniform(x - (pSpacing / 2.0), x + (pSpacing / 2.0)), - uniform(y - (pSpacing / 2.0), y + (pSpacing / 2.0)))) + geom = QgsGeometry( + QgsPoint( + uniform(x - (pSpacing / 2.0), x + (pSpacing / 2.0)), + uniform(y - (pSpacing / 2.0), y + (pSpacing / 2.0)), + ) + ) else: geom = QgsGeometry(QgsPoint(x, y)) diff --git a/python/plugins/processing/algs/qgis/Relief.py b/python/plugins/processing/algs/qgis/Relief.py index e20be453631e..b737b058fba4 100644 --- a/python/plugins/processing/algs/qgis/Relief.py +++ b/python/plugins/processing/algs/qgis/Relief.py @@ -15,23 +15,25 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'December 2016' -__copyright__ = '(C) 2016, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "December 2016" +__copyright__ = "(C) 2016, Alexander Bruy" import os from qgis.PyQt.QtGui import QIcon, QColor from qgis.analysis import QgsRelief -from qgis.core import (QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterNumber, - QgsProcessingParameterBoolean, - QgsProcessingParameterRasterDestination, - QgsProcessingParameterFileDestination, - QgsRasterFileWriter, - QgsProcessingException) +from qgis.core import ( + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterNumber, + QgsProcessingParameterBoolean, + QgsProcessingParameterRasterDestination, + QgsProcessingParameterFileDestination, + QgsRasterFileWriter, + QgsProcessingException, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] @@ -39,96 +41,124 @@ class ParameterReliefColors(QgsProcessingParameterDefinition): - def __init__(self, name='', description='', parent=None, optional=True): + def __init__(self, name="", description="", parent=None, optional=True): super().__init__(name, description, None, optional) self.parent = parent - self.setMetadata({'widget_wrapper': 'processing.algs.qgis.ui.ReliefColorsWidget.ReliefColorsWidgetWrapper'}) + self.setMetadata( + { + "widget_wrapper": "processing.algs.qgis.ui.ReliefColorsWidget.ReliefColorsWidgetWrapper" + } + ) def type(self): - return 'relief_colors' + return "relief_colors" def clone(self): - return ParameterReliefColors(self.name(), self.description(), self.parent, - self.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + return ParameterReliefColors( + self.name(), + self.description(), + self.parent, + self.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional, + ) @staticmethod def valueToColors(value): if value is None: return None - if value == '': + if value == "": return None if isinstance(value, str): - return value.split(';') + return value.split(";") else: return ParameterReliefColors.colorsToString(value) @staticmethod def colorsToString(colors): - return ';'.join('{:f}, {:f}, {:d}, {:d}, {:d}'.format(c[0], - c[1], - c[2], - c[3], - c[4]) - for c in colors) + return ";".join( + f"{c[0]:f}, {c[1]:f}, {c[2]:d}, {c[3]:d}, {c[4]:d}" for c in colors + ) class Relief(QgisAlgorithm): - INPUT = 'INPUT' - Z_FACTOR = 'Z_FACTOR' - AUTO_COLORS = 'AUTO_COLORS' - COLORS = 'COLORS' - OUTPUT = 'OUTPUT' - FREQUENCY_DISTRIBUTION = 'FREQUENCY_DISTRIBUTION' + INPUT = "INPUT" + Z_FACTOR = "Z_FACTOR" + AUTO_COLORS = "AUTO_COLORS" + COLORS = "COLORS" + OUTPUT = "OUTPUT" + FREQUENCY_DISTRIBUTION = "FREQUENCY_DISTRIBUTION" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'dem.png')) + return QIcon(os.path.join(pluginPath, "images", "dem.png")) def group(self): - return self.tr('Raster terrain analysis') + return self.tr("Raster terrain analysis") def groupId(self): - return 'rasterterrainanalysis' + return "rasterterrainanalysis" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, - self.tr('Elevation layer'))) - self.addParameter(QgsProcessingParameterNumber(self.Z_FACTOR, - self.tr('Z factor'), type=QgsProcessingParameterNumber.Type.Double, - minValue=0.00, defaultValue=1.0)) - self.addParameter(QgsProcessingParameterBoolean(self.AUTO_COLORS, - self.tr('Generate relief classes automatically'), - defaultValue=False)) - self.addParameter(ParameterReliefColors(self.COLORS, - self.tr('Relief colors'), - self.INPUT, - True)) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, - self.tr('Relief'))) - self.addParameter(QgsProcessingParameterFileDestination(self.FREQUENCY_DISTRIBUTION, - self.tr('Frequency distribution'), - 'CSV files (*.csv)', - optional=True, - createByDefault=False)) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Elevation layer")) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.Z_FACTOR, + self.tr("Z factor"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0.00, + defaultValue=1.0, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.AUTO_COLORS, + self.tr("Generate relief classes automatically"), + defaultValue=False, + ) + ) + self.addParameter( + ParameterReliefColors( + self.COLORS, self.tr("Relief colors"), self.INPUT, True + ) + ) + self.addParameter( + QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr("Relief")) + ) + self.addParameter( + QgsProcessingParameterFileDestination( + self.FREQUENCY_DISTRIBUTION, + self.tr("Frequency distribution"), + "CSV files (*.csv)", + optional=True, + createByDefault=False, + ) + ) def name(self): - return 'relief' + return "relief" def displayName(self): - return self.tr('Relief') + return self.tr("Relief") def processAlgorithm(self, parameters, context, feedback): - inputFile = self.parameterAsRasterLayer(parameters, self.INPUT, context).source() + inputFile = self.parameterAsRasterLayer( + parameters, self.INPUT, context + ).source() zFactor = self.parameterAsDouble(parameters, self.Z_FACTOR, context) automaticColors = self.parameterAsBoolean(parameters, self.AUTO_COLORS, context) outputFile = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) - frequencyDistribution = self.parameterAsFileOutput(parameters, self.FREQUENCY_DISTRIBUTION, context) + frequencyDistribution = self.parameterAsFileOutput( + parameters, self.FREQUENCY_DISTRIBUTION, context + ) - outputFormat = QgsRasterFileWriter.driverForExtension(os.path.splitext(outputFile)[1]) + outputFormat = QgsRasterFileWriter.driverForExtension( + os.path.splitext(outputFile)[1] + ) relief = QgsRelief(inputFile, outputFile, outputFormat) @@ -138,14 +168,17 @@ def processAlgorithm(self, parameters, context, feedback): colors = ParameterReliefColors.valueToColors(parameters[self.COLORS]) if colors is None or len(colors) == 0: raise QgsProcessingException( - self.tr('Specify relief colors or activate "Generate relief classes automatically" option.')) + self.tr( + 'Specify relief colors or activate "Generate relief classes automatically" option.' + ) + ) reliefColors = [] for c in colors: - v = c.split(',') - color = QgsRelief.ReliefColor(QColor(int(v[2]), int(v[3]), int(v[4])), - float(v[0]), - float(v[1])) + v = c.split(",") + color = QgsRelief.ReliefColor( + QColor(int(v[2]), int(v[3]), int(v[4])), float(v[0]), float(v[1]) + ) reliefColors.append(color) relief.setReliefColors(reliefColors) @@ -154,18 +187,25 @@ def processAlgorithm(self, parameters, context, feedback): relief.exportFrequencyDistributionToCsv(frequencyDistribution) res = relief.processRaster(feedback) if res == 1: - raise QgsProcessingException(self.tr('Can not open input file.')) + raise QgsProcessingException(self.tr("Can not open input file.")) elif res == 2: - raise QgsProcessingException(self.tr('Can not get GDAL driver for output file.')) + raise QgsProcessingException( + self.tr("Can not get GDAL driver for output file.") + ) elif res == 3: - raise QgsProcessingException(self.tr('Can not create output file.')) + raise QgsProcessingException(self.tr("Can not create output file.")) elif res == 4: - raise QgsProcessingException(self.tr('Can not get input band.')) + raise QgsProcessingException(self.tr("Can not get input band.")) elif res == 5: - raise QgsProcessingException(self.tr('Can not create output bands.')) + raise QgsProcessingException(self.tr("Can not create output bands.")) elif res == 6: - raise QgsProcessingException(self.tr('Output raster size is too small (at least 3 rows needed).')) + raise QgsProcessingException( + self.tr("Output raster size is too small (at least 3 rows needed).") + ) elif res == 7: - feedback.pushInfo(self.tr('Canceled.')) + feedback.pushInfo(self.tr("Canceled.")) - return {self.OUTPUT: outputFile, self.FREQUENCY_DISTRIBUTION: frequencyDistribution} + return { + self.OUTPUT: outputFile, + self.FREQUENCY_DISTRIBUTION: frequencyDistribution, + } diff --git a/python/plugins/processing/algs/qgis/SelectByAttribute.py b/python/plugins/processing/algs/qgis/SelectByAttribute.py index c911da4796c6..e22655a14e72 100644 --- a/python/plugins/processing/algs/qgis/SelectByAttribute.py +++ b/python/plugins/processing/algs/qgis/SelectByAttribute.py @@ -15,140 +15,170 @@ *************************************************************************** """ -__author__ = 'Michael Minn' -__date__ = 'May 2010' -__copyright__ = '(C) 2010, Michael Minn' +__author__ = "Michael Minn" +__date__ = "May 2010" +__copyright__ = "(C) 2010, Michael Minn" from qgis.PyQt.QtCore import QMetaType -from qgis.core import (QgsExpression, - QgsVectorLayer, - QgsProcessing, - QgsProcessingException, - QgsProcessingAlgorithm, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterField, - QgsProcessingParameterEnum, - QgsProcessingParameterString, - QgsProcessingOutputVectorLayer) +from qgis.core import ( + QgsExpression, + QgsVectorLayer, + QgsProcessing, + QgsProcessingException, + QgsProcessingAlgorithm, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterField, + QgsProcessingParameterEnum, + QgsProcessingParameterString, + QgsProcessingOutputVectorLayer, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm class SelectByAttribute(QgisAlgorithm): - INPUT = 'INPUT' - FIELD = 'FIELD' - OPERATOR = 'OPERATOR' - VALUE = 'VALUE' - METHOD = 'METHOD' - OUTPUT = 'OUTPUT' - - OPERATORS = ['=', - '<>', - '>', - '>=', - '<', - '<=', - 'begins with', - 'contains', - 'is null', - 'is not null', - 'does not contain' - ] - STRING_OPERATORS = ['begins with', - 'contains', - 'does not contain'] + INPUT = "INPUT" + FIELD = "FIELD" + OPERATOR = "OPERATOR" + VALUE = "VALUE" + METHOD = "METHOD" + OUTPUT = "OUTPUT" + + OPERATORS = [ + "=", + "<>", + ">", + ">=", + "<", + "<=", + "begins with", + "contains", + "is null", + "is not null", + "does not contain", + ] + STRING_OPERATORS = ["begins with", "contains", "does not contain"] def tags(self): - return self.tr('select,attribute,value,contains,null,field').split(',') + return self.tr("select,attribute,value,contains,null,field").split(",") def group(self): - return self.tr('Vector selection') + return self.tr("Vector selection") def groupId(self): - return 'vectorselection' + return "vectorselection" def __init__(self): super().__init__() def flags(self): - return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool + return ( + super().flags() + | QgsProcessingAlgorithm.Flag.FlagNoThreading + | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool + ) def initAlgorithm(self, config=None): - self.operators = ['=', - '≠', - '>', - '≥', - '<', - '≤', - self.tr('begins with'), - self.tr('contains'), - self.tr('is null'), - self.tr('is not null'), - self.tr('does not contain') - ] - - self.methods = [self.tr('creating new selection'), - self.tr('adding to current selection'), - self.tr('removing from current selection'), - self.tr('selecting within current selection')] - - self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT, - self.tr('Input layer'), - types=[QgsProcessing.SourceType.TypeVector])) - self.addParameter(QgsProcessingParameterField(self.FIELD, - self.tr('Selection attribute'), - parentLayerParameterName=self.INPUT)) - self.addParameter(QgsProcessingParameterEnum(self.OPERATOR, - self.tr('Operator'), self.operators, defaultValue=0)) - self.addParameter(QgsProcessingParameterString(self.VALUE, - self.tr('Value'), - optional=True)) - self.addParameter(QgsProcessingParameterEnum(self.METHOD, - self.tr('Modify current selection by'), - self.methods, - defaultValue=0)) - - self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Selected (attribute)'))) + self.operators = [ + "=", + "≠", + ">", + "≥", + "<", + "≤", + self.tr("begins with"), + self.tr("contains"), + self.tr("is null"), + self.tr("is not null"), + self.tr("does not contain"), + ] + + self.methods = [ + self.tr("creating new selection"), + self.tr("adding to current selection"), + self.tr("removing from current selection"), + self.tr("selecting within current selection"), + ] + + self.addParameter( + QgsProcessingParameterVectorLayer( + self.INPUT, + self.tr("Input layer"), + types=[QgsProcessing.SourceType.TypeVector], + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.FIELD, + self.tr("Selection attribute"), + parentLayerParameterName=self.INPUT, + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.OPERATOR, self.tr("Operator"), self.operators, defaultValue=0 + ) + ) + self.addParameter( + QgsProcessingParameterString(self.VALUE, self.tr("Value"), optional=True) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.METHOD, + self.tr("Modify current selection by"), + self.methods, + defaultValue=0, + ) + ) + + self.addOutput( + QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Selected (attribute)")) + ) def name(self): - return 'selectbyattribute' + return "selectbyattribute" def displayName(self): - return self.tr('Select by attribute') + return self.tr("Select by attribute") def processAlgorithm(self, parameters, context, feedback): layer = self.parameterAsVectorLayer(parameters, self.INPUT, context) fieldName = self.parameterAsString(parameters, self.FIELD, context) - operator = self.OPERATORS[self.parameterAsEnum(parameters, self.OPERATOR, context)] + operator = self.OPERATORS[ + self.parameterAsEnum(parameters, self.OPERATOR, context) + ] value = self.parameterAsString(parameters, self.VALUE, context) fields = layer.fields() idx = fields.lookupField(fieldName) if idx < 0: - raise QgsProcessingException(self.tr("Field '{}' was not found in layer").format(fieldName)) + raise QgsProcessingException( + self.tr("Field '{}' was not found in layer").format(fieldName) + ) fieldType = fields[idx].type() if fieldType != QMetaType.Type.QString and operator in self.STRING_OPERATORS: - op = ''.join('"%s", ' % o for o in self.STRING_OPERATORS) + op = "".join('"%s", ' % o for o in self.STRING_OPERATORS) raise QgsProcessingException( - self.tr('Operators {0} can be used only with string fields.').format(op)) + self.tr("Operators {0} can be used only with string fields.").format(op) + ) field_ref = QgsExpression.quotedColumnRef(fieldName) quoted_val = QgsExpression.quotedValue(value) - if operator == 'is null': - expression_string = f'{field_ref} IS NULL' - elif operator == 'is not null': - expression_string = f'{field_ref} IS NOT NULL' - elif operator == 'begins with': + if operator == "is null": + expression_string = f"{field_ref} IS NULL" + elif operator == "is not null": + expression_string = f"{field_ref} IS NOT NULL" + elif operator == "begins with": expression_string = f"{field_ref} LIKE '{value}%'" - elif operator == 'contains': + elif operator == "contains": expression_string = f"{field_ref} LIKE '%{value}%'" - elif operator == 'does not contain': + elif operator == "does not contain": expression_string = f"{field_ref} NOT LIKE '%{value}%'" else: - expression_string = f'{field_ref} {operator} {quoted_val}' + expression_string = f"{field_ref} {operator} {quoted_val}" method = self.parameterAsEnum(parameters, self.METHOD, context) if method == 0: diff --git a/python/plugins/processing/algs/qgis/SelectByExpression.py b/python/plugins/processing/algs/qgis/SelectByExpression.py index 271ab2600ea1..840cf6bd33d7 100644 --- a/python/plugins/processing/algs/qgis/SelectByExpression.py +++ b/python/plugins/processing/algs/qgis/SelectByExpression.py @@ -14,60 +14,87 @@ *************************************************************************** """ -__author__ = 'Michael Douchin' -__date__ = 'July 2014' -__copyright__ = '(C) 2014, Michael Douchin' - -from qgis.core import (QgsExpression, - QgsProcessing, - QgsVectorLayer, - QgsProcessingAlgorithm, - QgsProcessingException, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterExpression, - QgsProcessingParameterEnum, - QgsProcessingOutputVectorLayer) +__author__ = "Michael Douchin" +__date__ = "July 2014" +__copyright__ = "(C) 2014, Michael Douchin" + +from qgis.core import ( + QgsExpression, + QgsProcessing, + QgsVectorLayer, + QgsProcessingAlgorithm, + QgsProcessingException, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterExpression, + QgsProcessingParameterEnum, + QgsProcessingOutputVectorLayer, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm class SelectByExpression(QgisAlgorithm): - INPUT = 'INPUT' - EXPRESSION = 'EXPRESSION' - OUTPUT = 'OUTPUT' - METHOD = 'METHOD' + INPUT = "INPUT" + EXPRESSION = "EXPRESSION" + OUTPUT = "OUTPUT" + METHOD = "METHOD" def group(self): - return self.tr('Vector selection') + return self.tr("Vector selection") def groupId(self): - return 'vectorselection' + return "vectorselection" def __init__(self): super().__init__() def flags(self): - return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool + return ( + super().flags() + | QgsProcessingAlgorithm.Flag.FlagNoThreading + | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool + ) def initAlgorithm(self, config=None): - self.methods = [self.tr('creating new selection'), - self.tr('adding to current selection'), - self.tr('removing from current selection'), - self.tr('selecting within current selection')] - - self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT, self.tr('Input layer'), types=[QgsProcessing.SourceType.TypeVector])) - - self.addParameter(QgsProcessingParameterExpression(self.EXPRESSION, - self.tr('Expression'), parentLayerParameterName=self.INPUT)) - self.addParameter(QgsProcessingParameterEnum(self.METHOD, - self.tr('Modify current selection by'), self.methods, defaultValue=0)) - - self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Selected (attribute)'))) + self.methods = [ + self.tr("creating new selection"), + self.tr("adding to current selection"), + self.tr("removing from current selection"), + self.tr("selecting within current selection"), + ] + + self.addParameter( + QgsProcessingParameterVectorLayer( + self.INPUT, + self.tr("Input layer"), + types=[QgsProcessing.SourceType.TypeVector], + ) + ) + + self.addParameter( + QgsProcessingParameterExpression( + self.EXPRESSION, + self.tr("Expression"), + parentLayerParameterName=self.INPUT, + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.METHOD, + self.tr("Modify current selection by"), + self.methods, + defaultValue=0, + ) + ) + + self.addOutput( + QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Selected (attribute)")) + ) def name(self): - return 'selectbyexpression' + return "selectbyexpression" def displayName(self): - return self.tr('Select by expression') + return self.tr("Select by expression") def processAlgorithm(self, parameters, context, feedback): layer = self.parameterAsVectorLayer(parameters, self.INPUT, context) diff --git a/python/plugins/processing/algs/qgis/SetRasterStyle.py b/python/plugins/processing/algs/qgis/SetRasterStyle.py index b4f884517c56..a6ce2e718b6d 100644 --- a/python/plugins/processing/algs/qgis/SetRasterStyle.py +++ b/python/plugins/processing/algs/qgis/SetRasterStyle.py @@ -15,50 +15,61 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os from qgis.PyQt.QtXml import QDomDocument -from qgis.core import (QgsProcessingAlgorithm, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterFile, - QgsProcessingOutputRasterLayer) +from qgis.core import ( + QgsProcessingAlgorithm, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterFile, + QgsProcessingOutputRasterLayer, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm class SetRasterStyle(QgisAlgorithm): - INPUT = 'INPUT' - STYLE = 'STYLE' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + STYLE = "STYLE" + OUTPUT = "OUTPUT" def group(self): - return self.tr('Raster tools') + return self.tr("Raster tools") def groupId(self): - return 'rastertools' + return "rastertools" def __init__(self): super().__init__() def flags(self): - return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading | QgsProcessingAlgorithm.Flag.FlagDeprecated | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool + return ( + super().flags() + | QgsProcessingAlgorithm.Flag.FlagNoThreading + | QgsProcessingAlgorithm.Flag.FlagDeprecated + | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool + ) def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, - self.tr('Raster layer'))) - self.addParameter(QgsProcessingParameterFile(self.STYLE, - self.tr('Style file'), extension='qml')) - self.addOutput(QgsProcessingOutputRasterLayer(self.INPUT, self.tr('Styled'))) + self.addParameter( + QgsProcessingParameterRasterLayer(self.INPUT, self.tr("Raster layer")) + ) + self.addParameter( + QgsProcessingParameterFile( + self.STYLE, self.tr("Style file"), extension="qml" + ) + ) + self.addOutput(QgsProcessingOutputRasterLayer(self.INPUT, self.tr("Styled"))) def name(self): - return 'setstyleforrasterlayer' + return "setstyleforrasterlayer" def displayName(self): - return self.tr('Set style for raster layer') + return self.tr("Set style for raster layer") def processAlgorithm(self, parameters, context, feedback): layer = self.parameterAsRasterLayer(parameters, self.INPUT, context) diff --git a/python/plugins/processing/algs/qgis/SetVectorStyle.py b/python/plugins/processing/algs/qgis/SetVectorStyle.py index 2aea85e27c53..a61dc33151c3 100644 --- a/python/plugins/processing/algs/qgis/SetVectorStyle.py +++ b/python/plugins/processing/algs/qgis/SetVectorStyle.py @@ -15,47 +15,57 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" -from qgis.core import (QgsProcessingAlgorithm, - QgsProcessingParameterFile, - QgsProcessingParameterVectorLayer, - QgsProcessingOutputVectorLayer) +from qgis.core import ( + QgsProcessingAlgorithm, + QgsProcessingParameterFile, + QgsProcessingParameterVectorLayer, + QgsProcessingOutputVectorLayer, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm class SetVectorStyle(QgisAlgorithm): - INPUT = 'INPUT' - STYLE = 'STYLE' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + STYLE = "STYLE" + OUTPUT = "OUTPUT" def group(self): - return self.tr('Vector general') + return self.tr("Vector general") def groupId(self): - return 'vectorgeneral' + return "vectorgeneral" def __init__(self): super().__init__() def flags(self): - return super().flags() | QgsProcessingAlgorithm.Flag.FlagNoThreading | QgsProcessingAlgorithm.Flag.FlagDeprecated | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool + return ( + super().flags() + | QgsProcessingAlgorithm.Flag.FlagNoThreading + | QgsProcessingAlgorithm.Flag.FlagDeprecated + | QgsProcessingAlgorithm.Flag.FlagNotAvailableInStandaloneTool + ) def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT, - self.tr('Vector layer'))) - self.addParameter(QgsProcessingParameterFile(self.STYLE, - self.tr('Style file'), extension='qml')) - self.addOutput(QgsProcessingOutputVectorLayer(self.INPUT, - self.tr('Styled'))) + self.addParameter( + QgsProcessingParameterVectorLayer(self.INPUT, self.tr("Vector layer")) + ) + self.addParameter( + QgsProcessingParameterFile( + self.STYLE, self.tr("Style file"), extension="qml" + ) + ) + self.addOutput(QgsProcessingOutputVectorLayer(self.INPUT, self.tr("Styled"))) def name(self): - return 'setstyleforvectorlayer' + return "setstyleforvectorlayer" def displayName(self): - return self.tr('Set style for vector layer') + return self.tr("Set style for vector layer") def processAlgorithm(self, parameters, context, feedback): layer = self.parameterAsVectorLayer(parameters, self.INPUT, context) diff --git a/python/plugins/processing/algs/qgis/StatisticsByCategories.py b/python/plugins/processing/algs/qgis/StatisticsByCategories.py index 2c84f605a851..3b3cc86fda45 100644 --- a/python/plugins/processing/algs/qgis/StatisticsByCategories.py +++ b/python/plugins/processing/algs/qgis/StatisticsByCategories.py @@ -15,28 +15,30 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'September 2012' -__copyright__ = '(C) 2012, Victor Olaya' - -from qgis.core import (QgsProcessingParameterFeatureSource, - QgsStatisticalSummary, - QgsDateTimeStatisticalSummary, - QgsStringStatisticalSummary, - QgsFeatureRequest, - QgsApplication, - QgsProcessingException, - QgsProcessingParameterField, - QgsProcessingParameterFeatureSink, - QgsFields, - QgsField, - QgsWkbTypes, - QgsCoordinateReferenceSystem, - QgsFeature, - QgsFeatureSink, - QgsProcessing, - QgsProcessingFeatureSource, - NULL) +__author__ = "Victor Olaya" +__date__ = "September 2012" +__copyright__ = "(C) 2012, Victor Olaya" + +from qgis.core import ( + QgsProcessingParameterFeatureSource, + QgsStatisticalSummary, + QgsDateTimeStatisticalSummary, + QgsStringStatisticalSummary, + QgsFeatureRequest, + QgsApplication, + QgsProcessingException, + QgsProcessingParameterField, + QgsProcessingParameterFeatureSink, + QgsFields, + QgsField, + QgsWkbTypes, + QgsCoordinateReferenceSystem, + QgsFeature, + QgsFeatureSink, + QgsProcessing, + QgsProcessingFeatureSource, + NULL, +) from qgis.PyQt.QtCore import QMetaType from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm @@ -44,20 +46,22 @@ class StatisticsByCategories(QgisAlgorithm): - INPUT = 'INPUT' - VALUES_FIELD_NAME = 'VALUES_FIELD_NAME' - CATEGORIES_FIELD_NAME = 'CATEGORIES_FIELD_NAME' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + VALUES_FIELD_NAME = "VALUES_FIELD_NAME" + CATEGORIES_FIELD_NAME = "CATEGORIES_FIELD_NAME" + OUTPUT = "OUTPUT" def group(self): - return self.tr('Vector analysis') + return self.tr("Vector analysis") def groupId(self): - return 'vectoranalysis' + return "vectoranalysis" def tags(self): - return self.tr('groups,stats,statistics,table,layer,sum,maximum,minimum,mean,average,standard,deviation,' - 'count,distinct,unique,variance,median,quartile,range,majority,minority,histogram,distinct,summary').split(',') + return self.tr( + "groups,stats,statistics,table,layer,sum,maximum,minimum,mean,average,standard,deviation," + "count,distinct,unique,variance,median,quartile,range,majority,minority,histogram,distinct,summary" + ).split(",") def icon(self): return QgsApplication.getThemeIcon("/algorithms/mAlgorithmBasicStatistics.svg") @@ -69,33 +73,58 @@ def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input vector layer'), - types=[QgsProcessing.SourceType.TypeVector])) - self.addParameter(QgsProcessingParameterField(self.VALUES_FIELD_NAME, - self.tr( - 'Field to calculate statistics on (if empty, only count is calculated)'), - parentLayerParameterName=self.INPUT, optional=True)) - self.addParameter(QgsProcessingParameterField(self.CATEGORIES_FIELD_NAME, - self.tr('Field(s) with categories'), - parentLayerParameterName=self.INPUT, - type=QgsProcessingParameterField.DataType.Any, allowMultiple=True)) - - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Statistics by category'))) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Input vector layer"), + types=[QgsProcessing.SourceType.TypeVector], + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.VALUES_FIELD_NAME, + self.tr( + "Field to calculate statistics on (if empty, only count is calculated)" + ), + parentLayerParameterName=self.INPUT, + optional=True, + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.CATEGORIES_FIELD_NAME, + self.tr("Field(s) with categories"), + parentLayerParameterName=self.INPUT, + type=QgsProcessingParameterField.DataType.Any, + allowMultiple=True, + ) + ) + + self.addParameter( + QgsProcessingParameterFeatureSink( + self.OUTPUT, self.tr("Statistics by category") + ) + ) def name(self): - return 'statisticsbycategories' + return "statisticsbycategories" def displayName(self): - return self.tr('Statistics by categories') + return self.tr("Statistics by categories") def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) - value_field_name = self.parameterAsString(parameters, self.VALUES_FIELD_NAME, context) - category_field_names = self.parameterAsFields(parameters, self.CATEGORIES_FIELD_NAME, context) + value_field_name = self.parameterAsString( + parameters, self.VALUES_FIELD_NAME, context + ) + category_field_names = self.parameterAsFields( + parameters, self.CATEGORIES_FIELD_NAME, context + ) value_field_index = source.fields().lookupField(value_field_name) if value_field_index >= 0: @@ -109,7 +138,11 @@ def processAlgorithm(self, parameters, context, feedback): for field_name in category_field_names: c = source.fields().lookupField(field_name) if c == -1: - raise QgsProcessingException(self.tr('Field "{field_name}" does not exist.').format(field_name=field_name)) + raise QgsProcessingException( + self.tr('Field "{field_name}" does not exist.').format( + field_name=field_name + ) + ) category_field_indexes.append(c) fields.append(source.fields().at(c)) @@ -122,45 +155,49 @@ def addField(name): fields.append(field) if value_field is None: - field_type = 'none' - fields.append(QgsField('count', QMetaType.Type.Int)) + field_type = "none" + fields.append(QgsField("count", QMetaType.Type.Int)) elif value_field.isNumeric(): - field_type = 'numeric' - fields.append(QgsField('count', QMetaType.Type.Int)) - fields.append(QgsField('unique', QMetaType.Type.Int)) - fields.append(QgsField('min', QMetaType.Type.Double)) - fields.append(QgsField('max', QMetaType.Type.Double)) - fields.append(QgsField('range', QMetaType.Type.Double)) - fields.append(QgsField('sum', QMetaType.Type.Double)) - fields.append(QgsField('mean', QMetaType.Type.Double)) - fields.append(QgsField('median', QMetaType.Type.Double)) - fields.append(QgsField('stddev', QMetaType.Type.Double)) - fields.append(QgsField('minority', QMetaType.Type.Double)) - fields.append(QgsField('majority', QMetaType.Type.Double)) - fields.append(QgsField('q1', QMetaType.Type.Double)) - fields.append(QgsField('q3', QMetaType.Type.Double)) - fields.append(QgsField('iqr', QMetaType.Type.Double)) - elif value_field.type() in (QMetaType.Type.QDate, QMetaType.Type.QTime, QMetaType.Type.QDateTime): - field_type = 'datetime' - fields.append(QgsField('count', QMetaType.Type.Int)) - fields.append(QgsField('unique', QMetaType.Type.Int)) - fields.append(QgsField('empty', QMetaType.Type.Int)) - fields.append(QgsField('filled', QMetaType.Type.Int)) + field_type = "numeric" + fields.append(QgsField("count", QMetaType.Type.Int)) + fields.append(QgsField("unique", QMetaType.Type.Int)) + fields.append(QgsField("min", QMetaType.Type.Double)) + fields.append(QgsField("max", QMetaType.Type.Double)) + fields.append(QgsField("range", QMetaType.Type.Double)) + fields.append(QgsField("sum", QMetaType.Type.Double)) + fields.append(QgsField("mean", QMetaType.Type.Double)) + fields.append(QgsField("median", QMetaType.Type.Double)) + fields.append(QgsField("stddev", QMetaType.Type.Double)) + fields.append(QgsField("minority", QMetaType.Type.Double)) + fields.append(QgsField("majority", QMetaType.Type.Double)) + fields.append(QgsField("q1", QMetaType.Type.Double)) + fields.append(QgsField("q3", QMetaType.Type.Double)) + fields.append(QgsField("iqr", QMetaType.Type.Double)) + elif value_field.type() in ( + QMetaType.Type.QDate, + QMetaType.Type.QTime, + QMetaType.Type.QDateTime, + ): + field_type = "datetime" + fields.append(QgsField("count", QMetaType.Type.Int)) + fields.append(QgsField("unique", QMetaType.Type.Int)) + fields.append(QgsField("empty", QMetaType.Type.Int)) + fields.append(QgsField("filled", QMetaType.Type.Int)) # keep same data type for these fields - addField('min') - addField('max') + addField("min") + addField("max") else: - field_type = 'string' - fields.append(QgsField('count', QMetaType.Type.Int)) - fields.append(QgsField('unique', QMetaType.Type.Int)) - fields.append(QgsField('empty', QMetaType.Type.Int)) - fields.append(QgsField('filled', QMetaType.Type.Int)) + field_type = "string" + fields.append(QgsField("count", QMetaType.Type.Int)) + fields.append(QgsField("unique", QMetaType.Type.Int)) + fields.append(QgsField("empty", QMetaType.Type.Int)) + fields.append(QgsField("filled", QMetaType.Type.Int)) # keep same data type for these fields - addField('min') - addField('max') - fields.append(QgsField('min_length', QMetaType.Type.Int)) - fields.append(QgsField('max_length', QMetaType.Type.Int)) - fields.append(QgsField('mean_length', QMetaType.Type.Double)) + addField("min") + addField("max") + fields.append(QgsField("min_length", QMetaType.Type.Int)) + fields.append(QgsField("max_length", QMetaType.Type.Int)) + fields.append(QgsField("mean_length", QMetaType.Type.Double)) request = QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry) if value_field is not None: @@ -169,10 +206,12 @@ def addField(name): attrs = [] attrs.extend(category_field_indexes) request.setSubsetOfAttributes(attrs) - features = source.getFeatures(request, QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks) + features = source.getFeatures( + request, QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks + ) total = 50.0 / source.featureCount() if source.featureCount() else 0 - if field_type == 'none': - values = defaultdict(lambda: 0) + if field_type == "none": + values = defaultdict(int) else: values = defaultdict(list) for current, feat in enumerate(features): @@ -182,17 +221,17 @@ def addField(name): feedback.setProgress(int(current * total)) attrs = feat.attributes() cat = tuple([attrs[c] for c in category_field_indexes]) - if field_type == 'none': + if field_type == "none": values[cat] += 1 continue - if field_type == 'numeric': + if field_type == "numeric": if attrs[value_field_index] == NULL: continue else: value = float(attrs[value_field_index]) - elif field_type == 'string': + elif field_type == "string": if attrs[value_field_index] == NULL: - value = '' + value = "" else: value = str(attrs[value_field_index]) elif attrs[value_field_index] == NULL: @@ -201,16 +240,22 @@ def addField(name): value = attrs[value_field_index] values[cat].append(value) - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, QgsWkbTypes.Type.NoGeometry, QgsCoordinateReferenceSystem()) + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + fields, + QgsWkbTypes.Type.NoGeometry, + QgsCoordinateReferenceSystem(), + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) - if field_type == 'none': + if field_type == "none": self.saveCounts(values, sink, feedback) - elif field_type == 'numeric': + elif field_type == "numeric": self.calcNumericStats(values, sink, feedback) - elif field_type == 'datetime': + elif field_type == "datetime": self.calcDateTimeStats(values, sink, feedback) else: self.calcStringStats(values, sink, feedback) @@ -244,20 +289,25 @@ def calcNumericStats(self, values, sink, feedback): stat.calculate(v) f = QgsFeature() - f.setAttributes(list(cat) + [stat.count(), - stat.variety(), - stat.min(), - stat.max(), - stat.range(), - stat.sum(), - stat.mean(), - stat.median(), - stat.stDev(), - stat.minority(), - stat.majority(), - stat.firstQuartile(), - stat.thirdQuartile(), - stat.interQuartileRange()]) + f.setAttributes( + list(cat) + + [ + stat.count(), + stat.variety(), + stat.min(), + stat.max(), + stat.range(), + stat.sum(), + stat.mean(), + stat.median(), + stat.stDev(), + stat.minority(), + stat.majority(), + stat.firstQuartile(), + stat.thirdQuartile(), + stat.interQuartileRange(), + ] + ) sink.addFeature(f, QgsFeatureSink.Flag.FastInsert) current += 1 @@ -275,13 +325,17 @@ def calcDateTimeStats(self, values, sink, feedback): stat.calculate(v) f = QgsFeature() - f.setAttributes(list(cat) + [stat.count(), - stat.countDistinct(), - stat.countMissing(), - stat.count() - stat.countMissing(), - stat.statistic(QgsDateTimeStatisticalSummary.Statistic.Min), - stat.statistic(QgsDateTimeStatisticalSummary.Statistic.Max) - ]) + f.setAttributes( + list(cat) + + [ + stat.count(), + stat.countDistinct(), + stat.countMissing(), + stat.count() - stat.countMissing(), + stat.statistic(QgsDateTimeStatisticalSummary.Statistic.Min), + stat.statistic(QgsDateTimeStatisticalSummary.Statistic.Max), + ] + ) sink.addFeature(f, QgsFeatureSink.Flag.FastInsert) current += 1 @@ -299,16 +353,20 @@ def calcStringStats(self, values, sink, feedback): stat.calculate(v) f = QgsFeature() - f.setAttributes(list(cat) + [stat.count(), - stat.countDistinct(), - stat.countMissing(), - stat.count() - stat.countMissing(), - stat.min(), - stat.max(), - stat.minLength(), - stat.maxLength(), - stat.meanLength() - ]) + f.setAttributes( + list(cat) + + [ + stat.count(), + stat.countDistinct(), + stat.countMissing(), + stat.count() - stat.countMissing(), + stat.min(), + stat.max(), + stat.minLength(), + stat.maxLength(), + stat.meanLength(), + ] + ) sink.addFeature(f, QgsFeatureSink.Flag.FastInsert) current += 1 diff --git a/python/plugins/processing/algs/qgis/TextToFloat.py b/python/plugins/processing/algs/qgis/TextToFloat.py index 310a7f0b4def..0b6b398a1640 100644 --- a/python/plugins/processing/algs/qgis/TextToFloat.py +++ b/python/plugins/processing/algs/qgis/TextToFloat.py @@ -15,26 +15,28 @@ *************************************************************************** """ -__author__ = 'Michael Minn' -__date__ = 'May 2010' -__copyright__ = '(C) 2010, Michael Minn' +__author__ = "Michael Minn" +__date__ = "May 2010" +__copyright__ = "(C) 2010, Michael Minn" from qgis.PyQt.QtCore import QMetaType -from qgis.core import (QgsField, - QgsProcessing, - QgsProcessingParameterField, - QgsProcessingFeatureSource) +from qgis.core import ( + QgsField, + QgsProcessing, + QgsProcessingParameterField, + QgsProcessingFeatureSource, +) from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm class TextToFloat(QgisFeatureBasedAlgorithm): - FIELD = 'FIELD' + FIELD = "FIELD" def group(self): - return self.tr('Vector table') + return self.tr("Vector table") def groupId(self): - return 'vectortable' + return "vectortable" def __init__(self): super().__init__() @@ -42,20 +44,23 @@ def __init__(self): self.field_idx = -1 def initParameters(self, config=None): - self.addParameter(QgsProcessingParameterField(self.FIELD, - self.tr('Text attribute to convert to float'), - parentLayerParameterName='INPUT', - type=QgsProcessingParameterField.DataType.String - )) + self.addParameter( + QgsProcessingParameterField( + self.FIELD, + self.tr("Text attribute to convert to float"), + parentLayerParameterName="INPUT", + type=QgsProcessingParameterField.DataType.String, + ) + ) def name(self): - return 'texttofloat' + return "texttofloat" def displayName(self): - return self.tr('Text to float') + return self.tr("Text to float") def outputName(self): - return self.tr('Float from text') + return self.tr("Float from text") def inputLayerTypes(self): return [QgsProcessing.SourceType.TypeVector] @@ -63,7 +68,9 @@ def inputLayerTypes(self): def outputFields(self, inputFields): self.field_idx = inputFields.lookupField(self.field_name) if self.field_idx >= 0: - inputFields[self.field_idx] = QgsField(self.field_name, QMetaType.Type.Double, '', 24, 15) + inputFields[self.field_idx] = QgsField( + self.field_name, QMetaType.Type.Double, "", 24, 15 + ) return inputFields def prepareAlgorithm(self, parameters, context, feedback): @@ -79,8 +86,8 @@ def sourceFlags(self): def processFeature(self, feature, context, feedback): value = feature[self.field_idx] try: - if '%' in value: - feature[self.field_idx] = float(value.replace('%', '')) / 100.0 + if "%" in value: + feature[self.field_idx] = float(value.replace("%", "")) / 100.0 else: feature[self.field_idx] = float(value) except: diff --git a/python/plugins/processing/algs/qgis/TinInterpolation.py b/python/plugins/processing/algs/qgis/TinInterpolation.py index 772654c91e79..51af0fc9932d 100644 --- a/python/plugins/processing/algs/qgis/TinInterpolation.py +++ b/python/plugins/processing/algs/qgis/TinInterpolation.py @@ -15,112 +15,139 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'October 2016' -__copyright__ = '(C) 2016, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "October 2016" +__copyright__ = "(C) 2016, Alexander Bruy" import os import math from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsProcessingUtils, - QgsProcessing, - QgsProcessingParameterEnum, - QgsProcessingParameterNumber, - QgsProcessingParameterExtent, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterDestination, - QgsWkbTypes, - QgsProcessingParameterFeatureSink, - QgsProcessingException, - QgsCoordinateReferenceSystem) -from qgis.analysis import (QgsInterpolator, - QgsTinInterpolator, - QgsGridFileWriter) +from qgis.core import ( + QgsProcessingUtils, + QgsProcessing, + QgsProcessingParameterEnum, + QgsProcessingParameterNumber, + QgsProcessingParameterExtent, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterDestination, + QgsWkbTypes, + QgsProcessingParameterFeatureSink, + QgsProcessingException, + QgsCoordinateReferenceSystem, +) +from qgis.analysis import QgsInterpolator, QgsTinInterpolator, QgsGridFileWriter from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm -from processing.algs.qgis.ui.InterpolationWidgets import ParameterInterpolationData, ParameterPixelSize +from processing.algs.qgis.ui.InterpolationWidgets import ( + ParameterInterpolationData, + ParameterPixelSize, +) pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] class TinInterpolation(QgisAlgorithm): - INTERPOLATION_DATA = 'INTERPOLATION_DATA' - METHOD = 'METHOD' - PIXEL_SIZE = 'PIXEL_SIZE' - COLUMNS = 'COLUMNS' - ROWS = 'ROWS' - EXTENT = 'EXTENT' - OUTPUT = 'OUTPUT' - TRIANGULATION = 'TRIANGULATION' + INTERPOLATION_DATA = "INTERPOLATION_DATA" + METHOD = "METHOD" + PIXEL_SIZE = "PIXEL_SIZE" + COLUMNS = "COLUMNS" + ROWS = "ROWS" + EXTENT = "EXTENT" + OUTPUT = "OUTPUT" + TRIANGULATION = "TRIANGULATION" def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'interpolation.png')) + return QIcon(os.path.join(pluginPath, "images", "interpolation.png")) def group(self): - return self.tr('Interpolation') + return self.tr("Interpolation") def groupId(self): - return 'interpolation' + return "interpolation" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.METHODS = [self.tr('Linear'), - self.tr('Clough-Toucher (cubic)') - ] - - self.addParameter(ParameterInterpolationData(self.INTERPOLATION_DATA, - self.tr('Input layer(s)'))) - self.addParameter(QgsProcessingParameterEnum(self.METHOD, - self.tr('Interpolation method'), - options=self.METHODS, - defaultValue=0)) - self.addParameter(QgsProcessingParameterExtent(self.EXTENT, - self.tr('Extent'), - optional=False)) - pixel_size_param = ParameterPixelSize(self.PIXEL_SIZE, - self.tr('Output raster size'), - layersData=self.INTERPOLATION_DATA, - extent=self.EXTENT, - minValue=0.0, - default=0.1) + self.METHODS = [self.tr("Linear"), self.tr("Clough-Toucher (cubic)")] + + self.addParameter( + ParameterInterpolationData( + self.INTERPOLATION_DATA, self.tr("Input layer(s)") + ) + ) + self.addParameter( + QgsProcessingParameterEnum( + self.METHOD, + self.tr("Interpolation method"), + options=self.METHODS, + defaultValue=0, + ) + ) + self.addParameter( + QgsProcessingParameterExtent(self.EXTENT, self.tr("Extent"), optional=False) + ) + pixel_size_param = ParameterPixelSize( + self.PIXEL_SIZE, + self.tr("Output raster size"), + layersData=self.INTERPOLATION_DATA, + extent=self.EXTENT, + minValue=0.0, + default=0.1, + ) self.addParameter(pixel_size_param) - cols_param = QgsProcessingParameterNumber(self.COLUMNS, - self.tr('Number of columns'), - optional=True, - minValue=0, maxValue=10000000) - cols_param.setFlags(cols_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden) + cols_param = QgsProcessingParameterNumber( + self.COLUMNS, + self.tr("Number of columns"), + optional=True, + minValue=0, + maxValue=10000000, + ) + cols_param.setFlags( + cols_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden + ) self.addParameter(cols_param) - rows_param = QgsProcessingParameterNumber(self.ROWS, - self.tr('Number of rows'), - optional=True, - minValue=0, maxValue=10000000) - rows_param.setFlags(rows_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden) + rows_param = QgsProcessingParameterNumber( + self.ROWS, + self.tr("Number of rows"), + optional=True, + minValue=0, + maxValue=10000000, + ) + rows_param.setFlags( + rows_param.flags() | QgsProcessingParameterDefinition.Flag.FlagHidden + ) self.addParameter(rows_param) - self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, - self.tr('Interpolated'))) - - triangulation_file_param = QgsProcessingParameterFeatureSink(self.TRIANGULATION, - self.tr('Triangulation'), - type=QgsProcessing.SourceType.TypeVectorLine, - optional=True) + self.addParameter( + QgsProcessingParameterRasterDestination( + self.OUTPUT, self.tr("Interpolated") + ) + ) + + triangulation_file_param = QgsProcessingParameterFeatureSink( + self.TRIANGULATION, + self.tr("Triangulation"), + type=QgsProcessing.SourceType.TypeVectorLine, + optional=True, + ) triangulation_file_param.setCreateByDefault(False) self.addParameter(triangulation_file_param) def name(self): - return 'tininterpolation' + return "tininterpolation" def displayName(self): - return self.tr('TIN interpolation') + return self.tr("TIN interpolation") def processAlgorithm(self, parameters, context, feedback): - interpolationData = ParameterInterpolationData.parseValue(parameters[self.INTERPOLATION_DATA]) + interpolationData = ParameterInterpolationData.parseValue( + parameters[self.INTERPOLATION_DATA] + ) method = self.parameterAsEnum(parameters, self.METHOD, context) bbox = self.parameterAsExtent(parameters, self.EXTENT, context) pixel_size = self.parameterAsDouble(parameters, self.PIXEL_SIZE, context) @@ -135,13 +162,14 @@ def processAlgorithm(self, parameters, context, feedback): if interpolationData is None: raise QgsProcessingException( - self.tr('You need to specify at least one input layer.')) + self.tr("You need to specify at least one input layer.") + ) layerData = [] layers = [] crs = QgsCoordinateReferenceSystem() - for i, row in enumerate(interpolationData.split('::|::')): - v = row.split('::~::') + for i, row in enumerate(interpolationData.split("::|::")): + v = row.split("::~::") data = QgsInterpolator.LayerData() # need to keep a reference until interpolation is complete @@ -154,13 +182,19 @@ def processAlgorithm(self, parameters, context, feedback): data.valueSource = int(v[1]) data.interpolationAttribute = int(v[2]) - if data.valueSource == QgsInterpolator.ValueSource.ValueAttribute and data.interpolationAttribute == -1: - raise QgsProcessingException(self.tr( - 'Layer {} is set to use a value attribute, but no attribute was set').format(i + 1)) - - if v[3] == '0': + if ( + data.valueSource == QgsInterpolator.ValueSource.ValueAttribute + and data.interpolationAttribute == -1 + ): + raise QgsProcessingException( + self.tr( + "Layer {} is set to use a value attribute, but no attribute was set" + ).format(i + 1) + ) + + if v[3] == "0": data.sourceType = QgsInterpolator.SourceType.SourcePoints - elif v[3] == '1': + elif v[3] == "1": data.sourceType = QgsInterpolator.SourceType.SourceStructureLines else: data.sourceType = QgsInterpolator.SourceType.SourceBreakLines @@ -171,18 +205,20 @@ def processAlgorithm(self, parameters, context, feedback): else: interpolationMethod = QgsTinInterpolator.TinInterpolation.CloughTocher - (triangulation_sink, triangulation_dest_id) = self.parameterAsSink(parameters, self.TRIANGULATION, context, - QgsTinInterpolator.triangulationFields(), QgsWkbTypes.Type.LineString, crs) + (triangulation_sink, triangulation_dest_id) = self.parameterAsSink( + parameters, + self.TRIANGULATION, + context, + QgsTinInterpolator.triangulationFields(), + QgsWkbTypes.Type.LineString, + crs, + ) interpolator = QgsTinInterpolator(layerData, interpolationMethod, feedback) if triangulation_sink is not None: interpolator.setTriangulationSink(triangulation_sink) - writer = QgsGridFileWriter(interpolator, - output, - bbox, - columns, - rows) + writer = QgsGridFileWriter(interpolator, output, bbox, columns, rows) writer.writeFile(feedback) if triangulation_sink: diff --git a/python/plugins/processing/algs/qgis/TopoColors.py b/python/plugins/processing/algs/qgis/TopoColors.py index 92c7dcace9d2..0e279cc516cb 100644 --- a/python/plugins/processing/algs/qgis/TopoColors.py +++ b/python/plugins/processing/algs/qgis/TopoColors.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'February 2017' -__copyright__ = '(C) 2017, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "February 2017" +__copyright__ = "(C) 2017, Nyall Dawson" import os import operator @@ -25,19 +25,21 @@ from collections import defaultdict -from qgis.core import (QgsField, - QgsFeatureSink, - QgsGeometry, - QgsSpatialIndex, - QgsPointXY, - NULL, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterDistance, - QgsProcessingParameterNumber, - QgsProcessingParameterEnum, - QgsProcessingParameterFeatureSink) +from qgis.core import ( + QgsField, + QgsFeatureSink, + QgsGeometry, + QgsSpatialIndex, + QgsPointXY, + NULL, + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterDistance, + QgsProcessingParameterNumber, + QgsProcessingParameterEnum, + QgsProcessingParameterFeatureSink, +) from qgis.PyQt.QtCore import QMetaType @@ -47,84 +49,122 @@ class TopoColor(QgisAlgorithm): - INPUT = 'INPUT' - MIN_COLORS = 'MIN_COLORS' - MIN_DISTANCE = 'MIN_DISTANCE' - BALANCE = 'BALANCE' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + MIN_COLORS = "MIN_COLORS" + MIN_DISTANCE = "MIN_DISTANCE" + BALANCE = "BALANCE" + OUTPUT = "OUTPUT" def tags(self): - return self.tr('topocolor,colors,graph,adjacent,assign').split(',') + return self.tr("topocolor,colors,graph,adjacent,assign").split(",") def group(self): - return self.tr('Cartography') + return self.tr("Cartography") def groupId(self): - return 'cartography' + return "cartography" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), - [QgsProcessing.SourceType.TypeVectorPolygon])) - self.addParameter(QgsProcessingParameterNumber(self.MIN_COLORS, - self.tr('Minimum number of colors'), minValue=1, maxValue=1000, - defaultValue=4)) - self.addParameter(QgsProcessingParameterDistance(self.MIN_DISTANCE, - self.tr('Minimum distance between features'), - parentParameterName=self.INPUT, minValue=0.0, - defaultValue=0.0)) - balance_by = [self.tr('By feature count'), - self.tr('By assigned area'), - self.tr('By distance between colors')] - self.addParameter(QgsProcessingParameterEnum( - self.BALANCE, - self.tr('Balance color assignment'), - options=balance_by, defaultValue=0)) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Input layer"), + [QgsProcessing.SourceType.TypeVectorPolygon], + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.MIN_COLORS, + self.tr("Minimum number of colors"), + minValue=1, + maxValue=1000, + defaultValue=4, + ) + ) + self.addParameter( + QgsProcessingParameterDistance( + self.MIN_DISTANCE, + self.tr("Minimum distance between features"), + parentParameterName=self.INPUT, + minValue=0.0, + defaultValue=0.0, + ) + ) + balance_by = [ + self.tr("By feature count"), + self.tr("By assigned area"), + self.tr("By distance between colors"), + ] + self.addParameter( + QgsProcessingParameterEnum( + self.BALANCE, + self.tr("Balance color assignment"), + options=balance_by, + defaultValue=0, + ) + ) self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Colored'), QgsProcessing.SourceType.TypeVectorPolygon)) + QgsProcessingParameterFeatureSink( + self.OUTPUT, + self.tr("Colored"), + QgsProcessing.SourceType.TypeVectorPolygon, + ) + ) def name(self): - return 'topologicalcoloring' + return "topologicalcoloring" def displayName(self): - return self.tr('Topological coloring') + return self.tr("Topological coloring") def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) min_colors = self.parameterAsInt(parameters, self.MIN_COLORS, context) balance_by = self.parameterAsEnum(parameters, self.BALANCE, context) min_distance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context) fields = source.fields() - fields.append(QgsField('color_id', QMetaType.Type.Int)) - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, source.wkbType(), source.sourceCrs()) + fields.append(QgsField("color_id", QMetaType.Type.Int)) + + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + fields, + source.wkbType(), + source.sourceCrs(), + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) features = {f.id(): f for f in source.getFeatures()} - topology, id_graph = self.compute_graph(features, feedback, min_distance=min_distance) - feature_colors = ColoringAlgorithm.balanced(features, - balance=balance_by, - graph=topology, - feedback=feedback, - min_colors=min_colors) + topology, id_graph = self.compute_graph( + features, feedback, min_distance=min_distance + ) + feature_colors = ColoringAlgorithm.balanced( + features, + balance=balance_by, + graph=topology, + feedback=feedback, + min_colors=min_colors, + ) if len(feature_colors) == 0: return {self.OUTPUT: dest_id} max_colors = max(feature_colors.values()) - feedback.pushInfo(self.tr('{} colors required').format(max_colors)) + feedback.pushInfo(self.tr("{} colors required").format(max_colors)) total = 20.0 / len(features) current = 0 @@ -149,14 +189,16 @@ def processAlgorithm(self, parameters, context, feedback): @staticmethod def compute_graph(features, feedback, create_id_graph=False, min_distance=0): - """ compute topology from a layer/field """ + """compute topology from a layer/field""" s = Graph(sort_graph=False) id_graph = None if create_id_graph: id_graph = Graph(sort_graph=True) # skip features without geometry - features_with_geometry = {f_id: f for (f_id, f) in features.items() if f.hasGeometry()} + features_with_geometry = { + f_id: f for (f_id, f) in features.items() if f.hasGeometry() + } total = 70.0 / len(features_with_geometry) if features_with_geometry else 1 index = QgsSpatialIndex() @@ -213,9 +255,12 @@ def balanced(features, graph, feedback, balance=0, min_colors=4): neighbour_count[feature_id] += len(neighbours) # sort features by neighbour count - we want to handle those with more neighbours first - sorted_by_count = [feature_id for feature_id in sorted(neighbour_count.items(), - key=operator.itemgetter(1), - reverse=True)] + sorted_by_count = [ + feature_id + for feature_id in sorted( + neighbour_count.items(), key=operator.itemgetter(1), reverse=True + ) + ] # counts for each color already assigned color_counts = defaultdict(int) color_areas = defaultdict(float) @@ -226,7 +271,7 @@ def balanced(features, graph, feedback, balance=0, min_colors=4): total = 10.0 / len(sorted_by_count) if sorted_by_count else 1 i = 0 - for (feature_id, n) in sorted_by_count: + for feature_id, n in sorted_by_count: if feedback.isCanceled(): break @@ -244,23 +289,35 @@ def balanced(features, graph, feedback, balance=0, min_colors=4): if len(available_colors) == 0: # no existing colors available for this feature, so add new color to pool and repeat min_colors += 1 - return ColoringAlgorithm.balanced(features, graph, feedback, balance, min_colors) + return ColoringAlgorithm.balanced( + features, graph, feedback, balance, min_colors + ) else: if balance == 0: # choose least used available color - counts = [(c, v) for c, v in color_counts.items() if c in available_colors] + counts = [ + (c, v) for c, v in color_counts.items() if c in available_colors + ] feature_color = sorted(counts, key=operator.itemgetter(1))[0][0] color_counts[feature_color] += 1 elif balance == 1: - areas = [(c, v) for c, v in color_areas.items() if c in available_colors] + areas = [ + (c, v) for c, v in color_areas.items() if c in available_colors + ] feature_color = sorted(areas, key=operator.itemgetter(1))[0][0] color_areas[feature_color] += features[feature_id].geometry().area() elif balance == 2: min_distances = {c: sys.float_info.max for c in available_colors} - this_feature_centroid = features[feature_id].geometry().centroid().constGet() + this_feature_centroid = ( + features[feature_id].geometry().centroid().constGet() + ) # find features for all available colors - other_features = {f_id: c for (f_id, c) in feature_colors.items() if c in available_colors} + other_features = { + f_id: c + for (f_id, c) in feature_colors.items() + if c in available_colors + } # loop through these, and calculate the minimum distance from this feature to the nearest # feature with each assigned color @@ -277,7 +334,9 @@ def balanced(features, graph, feedback, balance=0, min_colors=4): # choose color such that minimum distance is maximised! ie we want MAXIMAL separation between # features with the same color - feature_color = sorted(min_distances, key=min_distances.__getitem__, reverse=True)[0] + feature_color = sorted( + min_distances, key=min_distances.__getitem__, reverse=True + )[0] feature_colors[feature_id] = feature_color diff --git a/python/plugins/processing/algs/qgis/UniqueValues.py b/python/plugins/processing/algs/qgis/UniqueValues.py index 4d2df71ac8d1..87201c92d4a1 100644 --- a/python/plugins/processing/algs/qgis/UniqueValues.py +++ b/python/plugins/processing/algs/qgis/UniqueValues.py @@ -15,31 +15,33 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import codecs from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsApplication, - QgsCoordinateReferenceSystem, - QgsWkbTypes, - QgsFeature, - QgsFeatureSink, - QgsFeatureRequest, - QgsFields, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterField, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, - QgsProcessingOutputNumber, - QgsProcessingOutputString, - QgsProcessingFeatureSource, - QgsProcessingParameterFileDestination) +from qgis.core import ( + QgsApplication, + QgsCoordinateReferenceSystem, + QgsWkbTypes, + QgsFeature, + QgsFeatureSink, + QgsFeatureRequest, + QgsFields, + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterField, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterFeatureSink, + QgsProcessingOutputNumber, + QgsProcessingOutputString, + QgsProcessingFeatureSource, + QgsProcessingParameterFileDestination, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm @@ -47,12 +49,12 @@ class UniqueValues(QgisAlgorithm): - INPUT = 'INPUT' - FIELDS = 'FIELDS' - TOTAL_VALUES = 'TOTAL_VALUES' - UNIQUE_VALUES = 'UNIQUE_VALUES' - OUTPUT = 'OUTPUT' - OUTPUT_HTML_FILE = 'OUTPUT_HTML_FILE' + INPUT = "INPUT" + FIELDS = "FIELDS" + TOTAL_VALUES = "TOTAL_VALUES" + UNIQUE_VALUES = "UNIQUE_VALUES" + OUTPUT = "OUTPUT" + OUTPUT_HTML_FILE = "OUTPUT_HTML_FILE" def icon(self): return QgsApplication.getThemeIcon("/algorithms/mAlgorithmUniqueValues.svg") @@ -61,37 +63,66 @@ def svgIconPath(self): return QgsApplication.iconPath("/algorithms/mAlgorithmUniqueValues.svg") def group(self): - return self.tr('Vector analysis') + return self.tr("Vector analysis") def groupId(self): - return 'vectoranalysis' + return "vectoranalysis" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), types=[QgsProcessing.SourceType.TypeVector])) - self.addParameter(QgsProcessingParameterField(self.FIELDS, - self.tr('Target field(s)'), - parentLayerParameterName=self.INPUT, type=QgsProcessingParameterField.DataType.Any, allowMultiple=True)) - - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Unique values'), optional=True, defaultValue=None)) - - self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT_HTML_FILE, self.tr('HTML report'), self.tr('HTML files (*.html)'), None, True)) - self.addOutput(QgsProcessingOutputNumber(self.TOTAL_VALUES, self.tr('Total unique values'))) - self.addOutput(QgsProcessingOutputString(self.UNIQUE_VALUES, self.tr('Unique values'))) + self.addParameter( + QgsProcessingParameterFeatureSource( + self.INPUT, + self.tr("Input layer"), + types=[QgsProcessing.SourceType.TypeVector], + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.FIELDS, + self.tr("Target field(s)"), + parentLayerParameterName=self.INPUT, + type=QgsProcessingParameterField.DataType.Any, + allowMultiple=True, + ) + ) + + self.addParameter( + QgsProcessingParameterFeatureSink( + self.OUTPUT, self.tr("Unique values"), optional=True, defaultValue=None + ) + ) + + self.addParameter( + QgsProcessingParameterFileDestination( + self.OUTPUT_HTML_FILE, + self.tr("HTML report"), + self.tr("HTML files (*.html)"), + None, + True, + ) + ) + self.addOutput( + QgsProcessingOutputNumber(self.TOTAL_VALUES, self.tr("Total unique values")) + ) + self.addOutput( + QgsProcessingOutputString(self.UNIQUE_VALUES, self.tr("Unique values")) + ) def name(self): - return 'listuniquevalues' + return "listuniquevalues" def displayName(self): - return self.tr('List unique values') + return self.tr("List unique values") def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) field_names = self.parameterAsFields(parameters, self.FIELDS, context) @@ -100,13 +131,21 @@ def processAlgorithm(self, parameters, context, feedback): for field_name in field_names: field_index = source.fields().lookupField(field_name) if field_index < 0: - feedback.reportError(self.tr('Invalid field name {}').format(field_name)) + feedback.reportError( + self.tr("Invalid field name {}").format(field_name) + ) continue field = source.fields()[field_index] fields.append(field) field_indices.append(field_index) - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, QgsWkbTypes.Type.NoGeometry, QgsCoordinateReferenceSystem()) + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + fields, + QgsWkbTypes.Type.NoGeometry, + QgsCoordinateReferenceSystem(), + ) results = {} values = set() @@ -120,7 +159,12 @@ def processAlgorithm(self, parameters, context, feedback): request = QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry) request.setSubsetOfAttributes(field_indices) total = 100.0 / source.featureCount() if source.featureCount() else 0 - for current, f in enumerate(source.getFeatures(request, QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks)): + for current, f in enumerate( + source.getFeatures( + request, + QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks, + ) + ): if feedback.isCanceled(): break @@ -139,24 +183,29 @@ def processAlgorithm(self, parameters, context, feedback): sink.finalize() results[self.OUTPUT] = dest_id - output_file = self.parameterAsFileOutput(parameters, self.OUTPUT_HTML_FILE, context) + output_file = self.parameterAsFileOutput( + parameters, self.OUTPUT_HTML_FILE, context + ) if output_file: self.createHTML(output_file, values) results[self.OUTPUT_HTML_FILE] = output_file results[self.TOTAL_VALUES] = len(values) - results[self.UNIQUE_VALUES] = ';'.join(','.join(str(attr) for attr in v) for v in - values) + results[self.UNIQUE_VALUES] = ";".join( + ",".join(str(attr) for attr in v) for v in values + ) return results def createHTML(self, outputFile, algData): - with codecs.open(outputFile, 'w', encoding='utf-8') as f: - f.write('') - f.write('') - f.write(self.tr('

Total unique values: ') + str(len(algData)) + '

') - f.write(self.tr('

Unique values:

')) - f.write('
    ') + with codecs.open(outputFile, "w", encoding="utf-8") as f: + f.write("") + f.write( + '' + ) + f.write(self.tr("

    Total unique values: ") + str(len(algData)) + "

    ") + f.write(self.tr("

    Unique values:

    ")) + f.write("
      ") for s in algData: - f.write('
    • ' + ','.join(str(attr) for attr in s) + '
    • ') - f.write('
    ') + f.write("
  • " + ",".join(str(attr) for attr in s) + "
  • ") + f.write("
") diff --git a/python/plugins/processing/algs/qgis/VariableDistanceBuffer.py b/python/plugins/processing/algs/qgis/VariableDistanceBuffer.py index 6cded3f48c5f..c7c47f0767f1 100644 --- a/python/plugins/processing/algs/qgis/VariableDistanceBuffer.py +++ b/python/plugins/processing/algs/qgis/VariableDistanceBuffer.py @@ -15,25 +15,27 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsApplication, - QgsWkbTypes, - QgsProcessing, - QgsProcessingException, - QgsProcessingAlgorithm, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterField, - QgsProcessingParameterNumber, - QgsProcessingParameterBoolean, - QgsProcessingParameterEnum, - QgsProcessingParameterFeatureSink) +from qgis.core import ( + QgsApplication, + QgsWkbTypes, + QgsProcessing, + QgsProcessingException, + QgsProcessingAlgorithm, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingParameterNumber, + QgsProcessingParameterBoolean, + QgsProcessingParameterEnum, + QgsProcessingParameterFeatureSink, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from . import Buffer as buff @@ -42,14 +44,14 @@ class VariableDistanceBuffer(QgisAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' - FIELD = 'FIELD' - SEGMENTS = 'SEGMENTS' - DISSOLVE = 'DISSOLVE' - END_CAP_STYLE = 'END_CAP_STYLE' - JOIN_STYLE = 'JOIN_STYLE' - MITER_LIMIT = 'MITER_LIMIT' + INPUT = "INPUT" + OUTPUT = "OUTPUT" + FIELD = "FIELD" + SEGMENTS = "SEGMENTS" + DISSOLVE = "DISSOLVE" + END_CAP_STYLE = "END_CAP_STYLE" + JOIN_STYLE = "JOIN_STYLE" + MITER_LIMIT = "MITER_LIMIT" def icon(self): return QgsApplication.getThemeIcon("/algorithms/mAlgorithmBuffer.svg") @@ -58,75 +60,131 @@ def svgIconPath(self): return QgsApplication.iconPath("/algorithms/mAlgorithmBuffer.svg") def group(self): - return self.tr('Vector geometry') + return self.tr("Vector geometry") def groupId(self): - return 'vectorgeometry' + return "vectorgeometry" def __init__(self): super().__init__() def flags(self): - return QgsProcessingAlgorithm.Flag.FlagSupportsBatch | QgsProcessingAlgorithm.Flag.FlagCanCancel | QgsProcessingAlgorithm.Flag.FlagDeprecated + return ( + QgsProcessingAlgorithm.Flag.FlagSupportsBatch + | QgsProcessingAlgorithm.Flag.FlagCanCancel + | QgsProcessingAlgorithm.Flag.FlagDeprecated + ) def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'))) - - self.addParameter(QgsProcessingParameterField(self.FIELD, - self.tr('Distance field'), parentLayerParameterName=self.INPUT)) - self.addParameter(QgsProcessingParameterNumber(self.SEGMENTS, - self.tr('Segments'), type=QgsProcessingParameterNumber.Type.Integer, - minValue=1, defaultValue=5)) - self.addParameter(QgsProcessingParameterBoolean(self.DISSOLVE, - self.tr('Dissolve result'), defaultValue=False)) - self.end_cap_styles = [self.tr('Round'), - 'Flat', - 'Square'] - self.addParameter(QgsProcessingParameterEnum( - self.END_CAP_STYLE, - self.tr('End cap style'), - options=self.end_cap_styles, defaultValue=0)) - self.join_styles = [self.tr('Round'), - 'Miter', - 'Bevel'] - self.addParameter(QgsProcessingParameterEnum( - self.JOIN_STYLE, - self.tr('Join style'), - options=self.join_styles, defaultValue=0)) - self.addParameter(QgsProcessingParameterNumber(self.MITER_LIMIT, - self.tr('Miter limit'), type=QgsProcessingParameterNumber.Type.Double, - minValue=0, defaultValue=2)) + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer")) + ) + + self.addParameter( + QgsProcessingParameterField( + self.FIELD, + self.tr("Distance field"), + parentLayerParameterName=self.INPUT, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.SEGMENTS, + self.tr("Segments"), + type=QgsProcessingParameterNumber.Type.Integer, + minValue=1, + defaultValue=5, + ) + ) + self.addParameter( + QgsProcessingParameterBoolean( + self.DISSOLVE, self.tr("Dissolve result"), defaultValue=False + ) + ) + self.end_cap_styles = [self.tr("Round"), "Flat", "Square"] + self.addParameter( + QgsProcessingParameterEnum( + self.END_CAP_STYLE, + self.tr("End cap style"), + options=self.end_cap_styles, + defaultValue=0, + ) + ) + self.join_styles = [self.tr("Round"), "Miter", "Bevel"] + self.addParameter( + QgsProcessingParameterEnum( + self.JOIN_STYLE, + self.tr("Join style"), + options=self.join_styles, + defaultValue=0, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.MITER_LIMIT, + self.tr("Miter limit"), + type=QgsProcessingParameterNumber.Type.Double, + minValue=0, + defaultValue=2, + ) + ) self.addParameter( - QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Buffer'), QgsProcessing.SourceType.TypeVectorPolygon)) + QgsProcessingParameterFeatureSink( + self.OUTPUT, + self.tr("Buffer"), + QgsProcessing.SourceType.TypeVectorPolygon, + ) + ) def name(self): - return 'variabledistancebuffer' + return "variabledistancebuffer" def displayName(self): - return self.tr('Variable distance buffer') + return self.tr("Variable distance buffer") def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) dissolve = self.parameterAsBoolean(parameters, self.DISSOLVE, context) segments = self.parameterAsInt(parameters, self.SEGMENTS, context) - end_cap_style = self.parameterAsEnum(parameters, self.END_CAP_STYLE, context) + 1 + end_cap_style = ( + self.parameterAsEnum(parameters, self.END_CAP_STYLE, context) + 1 + ) join_style = self.parameterAsEnum(parameters, self.JOIN_STYLE, context) + 1 miter_limit = self.parameterAsDouble(parameters, self.MITER_LIMIT, context) field = self.parameterAsString(parameters, self.FIELD, context) - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - source.fields(), QgsWkbTypes.Type.Polygon, source.sourceCrs()) + (sink, dest_id) = self.parameterAsSink( + parameters, + self.OUTPUT, + context, + source.fields(), + QgsWkbTypes.Type.Polygon, + source.sourceCrs(), + ) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) - buff.buffering(feedback, context, sink, 0, field, True, source, dissolve, segments, end_cap_style, - join_style, miter_limit) + buff.buffering( + feedback, + context, + sink, + 0, + field, + True, + source, + dissolve, + segments, + end_cap_style, + join_style, + miter_limit, + ) sink.finalize() return {self.OUTPUT: dest_id} diff --git a/python/plugins/processing/algs/qgis/VectorLayerHistogram.py b/python/plugins/processing/algs/qgis/VectorLayerHistogram.py index 9ffa8f236070..7d57f2eb8309 100644 --- a/python/plugins/processing/algs/qgis/VectorLayerHistogram.py +++ b/python/plugins/processing/algs/qgis/VectorLayerHistogram.py @@ -15,17 +15,19 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'January 2013' -__copyright__ = '(C) 2013, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "January 2013" +__copyright__ = "(C) 2013, Victor Olaya" import warnings -from qgis.core import (QgsProcessingException, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterField, - QgsProcessingParameterNumber, - QgsProcessingParameterFileDestination) +from qgis.core import ( + QgsProcessingException, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingParameterNumber, + QgsProcessingParameterFileDestination, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.tools import vector @@ -33,36 +35,49 @@ class VectorLayerHistogram(QgisAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' - FIELD = 'FIELD' - BINS = 'BINS' + INPUT = "INPUT" + OUTPUT = "OUTPUT" + FIELD = "FIELD" + BINS = "BINS" def group(self): - return self.tr('Plots') + return self.tr("Plots") def groupId(self): - return 'plots' + return "plots" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterField(self.FIELD, - self.tr('Attribute'), parentLayerParameterName=self.INPUT, - type=QgsProcessingParameterField.DataType.Numeric)) - self.addParameter(QgsProcessingParameterNumber(self.BINS, - self.tr('number of bins'), minValue=2, defaultValue=10)) - - self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, self.tr('Histogram'), self.tr('HTML files (*.html)'))) + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterField( + self.FIELD, + self.tr("Attribute"), + parentLayerParameterName=self.INPUT, + type=QgsProcessingParameterField.DataType.Numeric, + ) + ) + self.addParameter( + QgsProcessingParameterNumber( + self.BINS, self.tr("number of bins"), minValue=2, defaultValue=10 + ) + ) + + self.addParameter( + QgsProcessingParameterFileDestination( + self.OUTPUT, self.tr("Histogram"), self.tr("HTML files (*.html)") + ) + ) def name(self): - return 'vectorlayerhistogram' + return "vectorlayerhistogram" def displayName(self): - return self.tr('Vector layer histogram') + return self.tr("Vector layer histogram") def processAlgorithm(self, parameters, context, feedback): try: @@ -73,11 +88,18 @@ def processAlgorithm(self, parameters, context, feedback): import plotly as plt import plotly.graph_objs as go except ImportError: - raise QgsProcessingException(QCoreApplication.translate('VectorLayerHistogram', 'This algorithm requires the Python “plotly” library. Please install this library and try again.')) + raise QgsProcessingException( + QCoreApplication.translate( + "VectorLayerHistogram", + "This algorithm requires the Python “plotly” library. Please install this library and try again.", + ) + ) source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) fieldname = self.parameterAsString(parameters, self.FIELD, context) bins = self.parameterAsInt(parameters, self.BINS, context) @@ -86,8 +108,7 @@ def processAlgorithm(self, parameters, context, feedback): values = vector.values(source, fieldname) - data = [go.Histogram(x=values[fieldname], - nbinsx=bins)] + data = [go.Histogram(x=values[fieldname], nbinsx=bins)] plt.offline.plot(data, filename=output, auto_open=False) return {self.OUTPUT: output} diff --git a/python/plugins/processing/algs/qgis/VectorLayerScatterplot.py b/python/plugins/processing/algs/qgis/VectorLayerScatterplot.py index b53fe434344f..8f2c6ea0348d 100644 --- a/python/plugins/processing/algs/qgis/VectorLayerScatterplot.py +++ b/python/plugins/processing/algs/qgis/VectorLayerScatterplot.py @@ -15,17 +15,19 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'January 2013' -__copyright__ = '(C) 2013, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "January 2013" +__copyright__ = "(C) 2013, Victor Olaya" import warnings -from qgis.core import (QgsProcessingException, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterField, - QgsProcessingParameterFileDestination, - QgsProcessingParameterString, - QgsProcessingParameterBoolean) +from qgis.core import ( + QgsProcessingException, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingParameterFileDestination, + QgsProcessingParameterString, + QgsProcessingParameterBoolean, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.tools import vector @@ -34,71 +36,91 @@ class VectorLayerScatterplot(QgisAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' - XFIELD = 'XFIELD' - YFIELD = 'YFIELD' - TITLE = 'TITLE' + INPUT = "INPUT" + OUTPUT = "OUTPUT" + XFIELD = "XFIELD" + YFIELD = "YFIELD" + TITLE = "TITLE" XAXIS_TITLE = "XAXIS_TITLE" YAXIS_TITLE = "YAXIS_TITLE" XAXIS_LOG = "XAXIS_LOG" YAXIS_LOG = "YAXIS_LOG" def group(self): - return self.tr('Plots') + return self.tr("Plots") def groupId(self): - return 'plots' + return "plots" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterField(self.XFIELD, - self.tr('X attribute'), - parentLayerParameterName=self.INPUT, - type=QgsProcessingParameterField.DataType.Numeric)) - self.addParameter(QgsProcessingParameterField(self.YFIELD, - self.tr('Y attribute'), - parentLayerParameterName=self.INPUT, - type=QgsProcessingParameterField.DataType.Numeric)) - - self.addParameter(QgsProcessingParameterString( - self.TITLE, - self.tr('Title'), - optional=True)) - - self.addParameter(QgsProcessingParameterString( - self.XAXIS_TITLE, - self.tr('X-axis title'), - optional=True)) - - self.addParameter(QgsProcessingParameterString( - self.YAXIS_TITLE, - self.tr('Y-axis title'), - optional=True)) - - self.addParameter(QgsProcessingParameterBoolean( - self.XAXIS_LOG, - self.tr('Use logarithmic scale for x-axis'), - defaultValue=False, - optional=True)) - - self.addParameter(QgsProcessingParameterBoolean( - self.YAXIS_LOG, - self.tr('Use logarithmic scale for y-axis'), - defaultValue=False, - optional=True)) - - self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, self.tr('Scatterplot'), self.tr('HTML files (*.html)'))) + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterField( + self.XFIELD, + self.tr("X attribute"), + parentLayerParameterName=self.INPUT, + type=QgsProcessingParameterField.DataType.Numeric, + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.YFIELD, + self.tr("Y attribute"), + parentLayerParameterName=self.INPUT, + type=QgsProcessingParameterField.DataType.Numeric, + ) + ) + + self.addParameter( + QgsProcessingParameterString(self.TITLE, self.tr("Title"), optional=True) + ) + + self.addParameter( + QgsProcessingParameterString( + self.XAXIS_TITLE, self.tr("X-axis title"), optional=True + ) + ) + + self.addParameter( + QgsProcessingParameterString( + self.YAXIS_TITLE, self.tr("Y-axis title"), optional=True + ) + ) + + self.addParameter( + QgsProcessingParameterBoolean( + self.XAXIS_LOG, + self.tr("Use logarithmic scale for x-axis"), + defaultValue=False, + optional=True, + ) + ) + + self.addParameter( + QgsProcessingParameterBoolean( + self.YAXIS_LOG, + self.tr("Use logarithmic scale for y-axis"), + defaultValue=False, + optional=True, + ) + ) + + self.addParameter( + QgsProcessingParameterFileDestination( + self.OUTPUT, self.tr("Scatterplot"), self.tr("HTML files (*.html)") + ) + ) def name(self): - return 'vectorlayerscatterplot' + return "vectorlayerscatterplot" def displayName(self): - return self.tr('Vector layer scatterplot') + return self.tr("Vector layer scatterplot") def processAlgorithm(self, parameters, context, feedback): try: @@ -109,11 +131,18 @@ def processAlgorithm(self, parameters, context, feedback): import plotly as plt import plotly.graph_objs as go except ImportError: - raise QgsProcessingException(QCoreApplication.translate('VectorLayerScatterplot', 'This algorithm requires the Python “plotly” library. Please install this library and try again.')) + raise QgsProcessingException( + QCoreApplication.translate( + "VectorLayerScatterplot", + "This algorithm requires the Python “plotly” library. Please install this library and try again.", + ) + ) source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) xfieldname = self.parameterAsString(parameters, self.XFIELD, context) yfieldname = self.parameterAsString(parameters, self.YFIELD, context) @@ -138,14 +167,13 @@ def processAlgorithm(self, parameters, context, feedback): output = self.parameterAsFileOutput(parameters, self.OUTPUT, context) values = vector.values(source, xfieldname, yfieldname) - data = [go.Scatter(x=values[xfieldname], - y=values[yfieldname], - mode='markers')] + data = [go.Scatter(x=values[xfieldname], y=values[yfieldname], mode="markers")] fig = go.Figure( data=data, layout_title_text=title, layout_xaxis_title=xaxis_title, - layout_yaxis_title=yaxis_title) + layout_yaxis_title=yaxis_title, + ) if xaxis_log: fig.update_xaxes(type="log") diff --git a/python/plugins/processing/algs/qgis/VectorLayerScatterplot3D.py b/python/plugins/processing/algs/qgis/VectorLayerScatterplot3D.py index 2039a4657431..9cb0c103f95f 100644 --- a/python/plugins/processing/algs/qgis/VectorLayerScatterplot3D.py +++ b/python/plugins/processing/algs/qgis/VectorLayerScatterplot3D.py @@ -15,16 +15,18 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'January 2013' -__copyright__ = '(C) 2013, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "January 2013" +__copyright__ = "(C) 2013, Victor Olaya" import warnings -from qgis.core import (QgsProcessingParameterFeatureSource, - QgsProcessingParameterField, - QgsProcessingParameterFileDestination, - QgsProcessingException, - QgsProcessingParameterString) +from qgis.core import ( + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingParameterFileDestination, + QgsProcessingException, + QgsProcessingParameterString, +) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm @@ -34,68 +36,87 @@ class VectorLayerScatterplot3D(QgisAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' - XFIELD = 'XFIELD' - YFIELD = 'YFIELD' - ZFIELD = 'ZFIELD' - TITLE = 'TITLE' + INPUT = "INPUT" + OUTPUT = "OUTPUT" + XFIELD = "XFIELD" + YFIELD = "YFIELD" + ZFIELD = "ZFIELD" + TITLE = "TITLE" XAXIS_TITLE = "XAXIS_TITLE" YAXIS_TITLE = "YAXIS_TITLE" ZAXIS_TITLE = "ZAXIS_TITLE" def group(self): - return self.tr('Plots') + return self.tr("Plots") def groupId(self): - return 'plots' + return "plots" def __init__(self): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'))) - self.addParameter(QgsProcessingParameterField(self.XFIELD, - self.tr('X attribute'), - parentLayerParameterName=self.INPUT, - type=QgsProcessingParameterField.DataType.Numeric)) - self.addParameter(QgsProcessingParameterField(self.YFIELD, - self.tr('Y attribute'), - parentLayerParameterName=self.INPUT, - type=QgsProcessingParameterField.DataType.Numeric)) - self.addParameter(QgsProcessingParameterField(self.ZFIELD, - self.tr('Z attribute'), - parentLayerParameterName=self.INPUT, - type=QgsProcessingParameterField.DataType.Numeric)) - - self.addParameter(QgsProcessingParameterString( - self.TITLE, - self.tr('Title'), - optional=True)) - - self.addParameter(QgsProcessingParameterString( - self.XAXIS_TITLE, - self.tr('X-axis title'), - optional=True)) - - self.addParameter(QgsProcessingParameterString( - self.YAXIS_TITLE, - self.tr('Y-axis title'), - optional=True)) - - self.addParameter(QgsProcessingParameterString( - self.ZAXIS_TITLE, - self.tr('Z-axis title'), - optional=True)) - - self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, self.tr('Scatterplot 3D'), self.tr('HTML files (*.html)'))) + self.addParameter( + QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer")) + ) + self.addParameter( + QgsProcessingParameterField( + self.XFIELD, + self.tr("X attribute"), + parentLayerParameterName=self.INPUT, + type=QgsProcessingParameterField.DataType.Numeric, + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.YFIELD, + self.tr("Y attribute"), + parentLayerParameterName=self.INPUT, + type=QgsProcessingParameterField.DataType.Numeric, + ) + ) + self.addParameter( + QgsProcessingParameterField( + self.ZFIELD, + self.tr("Z attribute"), + parentLayerParameterName=self.INPUT, + type=QgsProcessingParameterField.DataType.Numeric, + ) + ) + + self.addParameter( + QgsProcessingParameterString(self.TITLE, self.tr("Title"), optional=True) + ) + + self.addParameter( + QgsProcessingParameterString( + self.XAXIS_TITLE, self.tr("X-axis title"), optional=True + ) + ) + + self.addParameter( + QgsProcessingParameterString( + self.YAXIS_TITLE, self.tr("Y-axis title"), optional=True + ) + ) + + self.addParameter( + QgsProcessingParameterString( + self.ZAXIS_TITLE, self.tr("Z-axis title"), optional=True + ) + ) + + self.addParameter( + QgsProcessingParameterFileDestination( + self.OUTPUT, self.tr("Scatterplot 3D"), self.tr("HTML files (*.html)") + ) + ) def name(self): - return 'scatter3dplot' + return "scatter3dplot" def displayName(self): - return self.tr('Vector layer scatterplot 3D') + return self.tr("Vector layer scatterplot 3D") def processAlgorithm(self, parameters, context, feedback): try: @@ -106,11 +127,18 @@ def processAlgorithm(self, parameters, context, feedback): import plotly as plt import plotly.graph_objs as go except ImportError: - raise QgsProcessingException(QCoreApplication.translate('VectorLayerScatterplot3D', 'This algorithm requires the Python “plotly” library. Please install this library and try again.')) + raise QgsProcessingException( + QCoreApplication.translate( + "VectorLayerScatterplot3D", + "This algorithm requires the Python “plotly” library. Please install this library and try again.", + ) + ) source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) xfieldname = self.parameterAsString(parameters, self.XFIELD, context) yfieldname = self.parameterAsString(parameters, self.YFIELD, context) @@ -136,18 +164,22 @@ def processAlgorithm(self, parameters, context, feedback): values = vector.values(source, xfieldname, yfieldname, zfieldname) - data = [go.Scatter3d( + data = [ + go.Scatter3d( x=values[xfieldname], y=values[yfieldname], z=values[zfieldname], - mode='markers')] + mode="markers", + ) + ] fig = go.Figure( data=data, layout_title_text=title, layout_scene_xaxis_title=xaxis_title, layout_scene_yaxis_title=yaxis_title, - layout_scene_zaxis_title=zaxis_title) + layout_scene_zaxis_title=zaxis_title, + ) fig.write_html(output) diff --git a/python/plugins/processing/algs/qgis/ui/ExecuteSQLWidget.py b/python/plugins/processing/algs/qgis/ui/ExecuteSQLWidget.py index 830e4d6ed907..9ff825e5c43c 100644 --- a/python/plugins/processing/algs/qgis/ui/ExecuteSQLWidget.py +++ b/python/plugins/processing/algs/qgis/ui/ExecuteSQLWidget.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Paul Blottiere' -__date__ = 'November 2018' -__copyright__ = '(C) 2018, Paul Blottiere' +__author__ = "Paul Blottiere" +__date__ = "November 2018" +__copyright__ = "(C) 2018, Paul Blottiere" import os @@ -29,17 +29,15 @@ QgsProcessingParameterString, QgsProcessingParameterNumber, QgsExpression, - QgsProcessingModelChildParameterSource + QgsProcessingModelChildParameterSource, ) from qgis.gui import QgsFieldExpressionWidget -from processing.gui.wrappers import (WidgetWrapper, - dialogTypes, - DIALOG_MODELER) +from processing.gui.wrappers import WidgetWrapper, dialogTypes, DIALOG_MODELER pluginPath = os.path.dirname(__file__) -WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, 'ExecuteSQLWidgetBase.ui')) +WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "ExecuteSQLWidgetBase.ui")) class ExecuteSQLWidget(BASE, WIDGET): @@ -55,7 +53,8 @@ def __init__(self, dialog): # add model parameters in context scope if called from modeler if self.dialogType == DIALOG_MODELER: strings = dialog.getAvailableValuesOfType( - [QgsProcessingParameterString, QgsProcessingParameterNumber], []) + [QgsProcessingParameterString, QgsProcessingParameterNumber], [] + ) model_params = [dialog.resolveValueDescription(s) for s in strings] scope = QgsExpressionContextScope() @@ -71,7 +70,7 @@ def __init__(self, dialog): def insert(self): if self.mExpressionWidget.currentText(): - exp = f'[%{self.mExpressionWidget.currentText()}%]' + exp = f"[%{self.mExpressionWidget.currentText()}%]" self.mText.insertPlainText(exp) def setValue(self, value): @@ -80,20 +79,32 @@ def setValue(self, value): if self.dialogType == DIALOG_MODELER: if isinstance(value, list): for v in value: - if isinstance(v, QgsProcessingModelChildParameterSource) \ - and v.source() == Qgis.ProcessingModelChildParameterSource.ExpressionText: + if ( + isinstance(v, QgsProcessingModelChildParameterSource) + and v.source() + == Qgis.ProcessingModelChildParameterSource.ExpressionText + ): text = v.expressionText() # replace parameter's name by expression (diverging after model save) names = QgsExpression.referencedVariables(text) strings = self.dialog.getAvailableValuesOfType( - [QgsProcessingParameterString, QgsProcessingParameterNumber], []) - model_params = [(self.dialog.resolveValueDescription(s), s) for s in strings] + [ + QgsProcessingParameterString, + QgsProcessingParameterNumber, + ], + [], + ) + model_params = [ + (self.dialog.resolveValueDescription(s), s) for s in strings + ] for k, v in model_params: if v.parameterName() in names: - text = text.replace(f'[% @{v.parameterName()} %]', f'[% @{k} %]') + text = text.replace( + f"[% @{v.parameterName()} %]", f"[% @{k} %]" + ) self.mText.setPlainText(text) @@ -109,7 +120,8 @@ def value(self): def _expressionValues(self, text): strings = self.dialog.getAvailableValuesOfType( - [QgsProcessingParameterString, QgsProcessingParameterNumber], []) + [QgsProcessingParameterString, QgsProcessingParameterNumber], [] + ) model_params = [(self.dialog.resolveValueDescription(s), s) for s in strings] variables = QgsExpression.referencedVariables(text) @@ -119,7 +131,7 @@ def _expressionValues(self, text): for k, v in model_params: if k in descriptions: - text = text.replace(f'[% @{k} %]', f'[% @{v.parameterName()} %]') + text = text.replace(f"[% @{k} %]", f"[% @{v.parameterName()} %]") src = QgsProcessingModelChildParameterSource.fromExpressionText(text) diff --git a/python/plugins/processing/algs/qgis/ui/HeatmapWidgets.py b/python/plugins/processing/algs/qgis/ui/HeatmapWidgets.py index 9fdee8587466..7d14c4eee1a3 100644 --- a/python/plugins/processing/algs/qgis/ui/HeatmapWidgets.py +++ b/python/plugins/processing/algs/qgis/ui/HeatmapWidgets.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'December 2016' -__copyright__ = '(C) 2016, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "December 2016" +__copyright__ = "(C) 2016, Nyall Dawson" from processing.gui.wrappers import WidgetWrapper, DIALOG_STANDARD from processing.tools import dataobjects @@ -27,12 +27,10 @@ from qgis.PyQt import uic from qgis.gui import QgsDoubleSpinBox -from qgis.core import (QgsRectangle, - QgsProcessingUtils) +from qgis.core import QgsRectangle, QgsProcessingUtils pluginPath = os.path.dirname(__file__) -WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'RasterResolutionWidget.ui')) +WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "RasterResolutionWidget.ui")) class HeatmapPixelSizeWidget(BASE, WIDGET): @@ -182,7 +180,9 @@ def createWidget(self): w.setMinimum(0) w.setMaximum(99999999999) w.setDecimals(6) - w.setToolTip(self.tr('Resolution of each pixel in output raster, in layer units')) + w.setToolTip( + self.tr("Resolution of each pixel in output raster, in layer units") + ) return w def postInitialize(self, wrappers): diff --git a/python/plugins/processing/algs/qgis/ui/InterpolationWidgets.py b/python/plugins/processing/algs/qgis/ui/InterpolationWidgets.py index b3a58ca4206e..84b1a73b9e71 100644 --- a/python/plugins/processing/algs/qgis/ui/InterpolationWidgets.py +++ b/python/plugins/processing/algs/qgis/ui/InterpolationWidgets.py @@ -15,20 +15,16 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'December 2016' -__copyright__ = '(C) 2016, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "December 2016" +__copyright__ = "(C) 2016, Alexander Bruy" import os -from typing import ( - Optional, - Union -) +from typing import Optional, Union from qgis.PyQt import uic from qgis.PyQt.QtCore import pyqtSignal -from qgis.PyQt.QtWidgets import (QTreeWidgetItem, - QComboBox) +from qgis.PyQt.QtWidgets import QTreeWidgetItem, QComboBox from qgis.core import ( Qgis, QgsApplication, @@ -40,7 +36,7 @@ QgsProcessingParameterNumber, QgsProcessingParameterDefinition, QgsFieldProxyModel, - QgsVectorLayer + QgsVectorLayer, ) from qgis.gui import QgsDoubleSpinBox from qgis.analysis import QgsInterpolator @@ -53,14 +49,16 @@ class ParameterInterpolationData(QgsProcessingParameterDefinition): - def __init__(self, name='', description=''): + def __init__(self, name="", description=""): super().__init__(name, description) - self.setMetadata({ - 'widget_wrapper': 'processing.algs.qgis.ui.InterpolationWidgets.InterpolationDataWidgetWrapper' - }) + self.setMetadata( + { + "widget_wrapper": "processing.algs.qgis.ui.InterpolationWidgets.InterpolationDataWidgetWrapper" + } + ) def type(self): - return 'idw_interpolation_data' + return "idw_interpolation_data" def clone(self): return ParameterInterpolationData(self.name(), self.description()) @@ -70,26 +68,25 @@ def parseValue(value): if value is None: return None - if value == '': + if value == "": return None if isinstance(value, str): - return value if value != '' else None + return value if value != "" else None else: return ParameterInterpolationData.dataToString(value) @staticmethod def dataToString(data): - s = '' + s = "" for c in data: - s += '{}::~::{}::~::{:d}::~::{:d};'.format(c[0], - c[1], - c[2], - c[3]) + s += f"{c[0]}::~::{c[1]}::~::{c[2]:d}::~::{c[3]:d};" return s[:-1] -WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, 'interpolationdatawidgetbase.ui')) +WIDGET, BASE = uic.loadUiType( + os.path.join(pluginPath, "interpolationdatawidgetbase.ui") +) class InterpolationDataWidget(BASE, WIDGET): @@ -99,8 +96,8 @@ def __init__(self): super().__init__(None) self.setupUi(self) - self.btnAdd.setIcon(QgsApplication.getThemeIcon('/symbologyAdd.svg')) - self.btnRemove.setIcon(QgsApplication.getThemeIcon('/symbologyRemove.svg')) + self.btnAdd.setIcon(QgsApplication.getThemeIcon("/symbologyAdd.svg")) + self.btnRemove.setIcon(QgsApplication.getThemeIcon("/symbologyRemove.svg")) self.btnAdd.clicked.connect(self.addLayer) self.btnRemove.clicked.connect(self.removeLayer) @@ -113,9 +110,9 @@ def __init__(self): def addLayer(self): layer = self.cmbLayers.currentLayer() - attribute = '' + attribute = "" if self.chkUseZCoordinate.isChecked(): - attribute = 'Z_COORD' + attribute = "Z_COORD" else: attribute = self.cmbFields.currentField() @@ -152,22 +149,24 @@ def _addLayerData(self, layerName: str, attribute: str): self.layersTree.addTopLevelItem(item) comboBox = QComboBox() - comboBox.addItem(self.tr('Points')) - comboBox.addItem(self.tr('Structure lines')) - comboBox.addItem(self.tr('Break lines')) + comboBox.addItem(self.tr("Points")) + comboBox.addItem(self.tr("Structure lines")) + comboBox.addItem(self.tr("Break lines")) comboBox.setCurrentIndex(0) self.layersTree.setItemWidget(item, 2, comboBox) def setValue(self, value: str): self.layersTree.clear() - rows = value.split('::|::') + rows = value.split("::|::") for i, r in enumerate(rows): - v = r.split('::~::') - layer = QgsProcessingUtils.mapLayerFromString(v[0], dataobjects.createContext()) + v = r.split("::~::") + layer = QgsProcessingUtils.mapLayerFromString( + v[0], dataobjects.createContext() + ) field_index = int(v[2]) if field_index == -1: - field_name = 'Z_COORD' + field_name = "Z_COORD" else: field_name = layer.fields().at(field_index).name() @@ -179,7 +178,7 @@ def setValue(self, value: str): self.hasChanged.emit() def value(self) -> str: - layers = '' + layers = "" context = dataobjects.createContext() for i in range(self.layersTree.topLevelItemCount()): item = self.layersTree.topLevelItem(i) @@ -195,26 +194,27 @@ def value(self) -> str: interpolationAttribute = item.text(1) interpolationSource = QgsInterpolator.ValueSource.ValueAttribute - if interpolationAttribute == 'Z_COORD': + if interpolationAttribute == "Z_COORD": interpolationSource = QgsInterpolator.ValueSource.ValueZ fieldIndex = -1 else: fieldIndex = layer.fields().indexFromName(interpolationAttribute) - comboBox = self.layersTree.itemWidget(self.layersTree.topLevelItem(i), 2) + comboBox = self.layersTree.itemWidget( + self.layersTree.topLevelItem(i), 2 + ) inputTypeName = comboBox.currentText() - if inputTypeName == self.tr('Points'): + if inputTypeName == self.tr("Points"): inputType = QgsInterpolator.SourceType.SourcePoints - elif inputTypeName == self.tr('Structure lines'): + elif inputTypeName == self.tr("Structure lines"): inputType = QgsInterpolator.SourceType.SourceStructureLines else: inputType = QgsInterpolator.SourceType.SourceBreakLines - layers += '{}::~::{:d}::~::{:d}::~::{:d}::|::'.format(layer.source(), - interpolationSource, - fieldIndex, - inputType) - return layers[:-len('::|::')] + layers += "{}::~::{:d}::~::{:d}::~::{:d}::|::".format( + layer.source(), interpolationSource, fieldIndex, inputType + ) + return layers[: -len("::|::")] class InterpolationDataWidgetWrapper(WidgetWrapper): @@ -233,22 +233,49 @@ def value(self): class ParameterPixelSize(QgsProcessingParameterNumber): - def __init__(self, name='', description='', layersData=None, extent=None, minValue=None, default=None, optional=False): - QgsProcessingParameterNumber.__init__(self, name, description, QgsProcessingParameterNumber.Type.Double, default, optional, minValue) - self.setMetadata({ - 'widget_wrapper': 'processing.algs.qgis.ui.InterpolationWidgets.PixelSizeWidgetWrapper' - }) + def __init__( + self, + name="", + description="", + layersData=None, + extent=None, + minValue=None, + default=None, + optional=False, + ): + QgsProcessingParameterNumber.__init__( + self, + name, + description, + QgsProcessingParameterNumber.Type.Double, + default, + optional, + minValue, + ) + self.setMetadata( + { + "widget_wrapper": "processing.algs.qgis.ui.InterpolationWidgets.PixelSizeWidgetWrapper" + } + ) self.layersData = layersData self.extent = extent self.layers = [] def clone(self): - copy = ParameterPixelSize(self.name(), self.description(), self.layersData, self.extent, self.minimum(), self.defaultValue(), self.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + copy = ParameterPixelSize( + self.name(), + self.description(), + self.layersData, + self.extent, + self.minimum(), + self.defaultValue(), + self.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional, + ) return copy -WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, 'RasterResolutionWidget.ui')) +WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "RasterResolutionWidget.ui")) class PixelSizeWidget(BASE, WIDGET): @@ -258,7 +285,9 @@ def __init__(self): self.setupUi(self) self.context = dataobjects.createContext() - self.extent: Optional[Union[QgsReferencedRectangle, QgsRectangle]] = QgsRectangle() + self.extent: Optional[Union[QgsReferencedRectangle, QgsRectangle]] = ( + QgsRectangle() + ) self.layers = [] self.mCellXSpinBox.setShowClearButton(False) @@ -274,8 +303,8 @@ def __init__(self): def setLayers(self, layersData: str): self.extent = QgsRectangle() self.layers = [] - for row in layersData.split(';'): - v = row.split('::~::') + for row in layersData.split(";"): + v = row.split("::~::") # need to keep a reference until interpolation is complete layer = QgsProcessingUtils.variantToSource(v[0], self.context) if layer: @@ -286,16 +315,15 @@ def setLayers(self, layersData: str): def setExtent(self, extent: Optional[str]): if extent is not None: - tokens = extent.split(' ')[0].split(',') + tokens = extent.split(" ")[0].split(",") ext = QgsRectangle( - float(tokens[0]), - float(tokens[2]), - float(tokens[1]), - float(tokens[3])) + float(tokens[0]), float(tokens[2]), float(tokens[1]), float(tokens[3]) + ) if len(tokens) > 1: self.extent = QgsReferencedRectangle( - ext, QgsCoordinateReferenceSystem(tokens[1][1:-1])) + ext, QgsCoordinateReferenceSystem(tokens[1][1:-1]) + ) else: self.extent = ext @@ -386,7 +414,9 @@ def createWidget(self): w.setMinimum(0) w.setMaximum(99999999999) w.setDecimals(6) - w.setToolTip(self.tr('Resolution of each pixel in output raster, in layer units')) + w.setToolTip( + self.tr("Resolution of each pixel in output raster, in layer units") + ) return w def postInitialize(self, wrappers): diff --git a/python/plugins/processing/algs/qgis/ui/RasterCalculatorWidgets.py b/python/plugins/processing/algs/qgis/ui/RasterCalculatorWidgets.py index df030e4a0c0e..47cc4ea95dec 100644 --- a/python/plugins/processing/algs/qgis/ui/RasterCalculatorWidgets.py +++ b/python/plugins/processing/algs/qgis/ui/RasterCalculatorWidgets.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'November 2016' -__copyright__ = '(C) 2016, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "November 2016" +__copyright__ = "(C) 2016, Victor Olaya" import os from functools import partial @@ -28,15 +28,23 @@ from qgis.PyQt import uic from qgis.PyQt.QtCore import Qt from qgis.PyQt.QtGui import QTextCursor -from qgis.PyQt.QtWidgets import (QLineEdit, QPushButton, QLabel, - QComboBox, QSpacerItem, QSizePolicy, - QListWidgetItem) - -from qgis.core import (QgsProcessingUtils, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingOutputRasterLayer, - QgsProject) +from qgis.PyQt.QtWidgets import ( + QLineEdit, + QPushButton, + QLabel, + QComboBox, + QSpacerItem, + QSizePolicy, + QListWidgetItem, +) + +from qgis.core import ( + QgsProcessingUtils, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingOutputRasterLayer, + QgsProject, +) from processing.gui.wrappers import WidgetWrapper, DIALOG_STANDARD, DIALOG_BATCH from processing.gui.BatchInputSelectionPanel import BatchInputSelectionPanel @@ -49,7 +57,8 @@ pluginPath = os.path.dirname(__file__) WIDGET_ADD_NEW, BASE_ADD_NEW = uic.loadUiType( - os.path.join(pluginPath, 'AddNewExpressionDialog.ui')) + os.path.join(pluginPath, "AddNewExpressionDialog.ui") +) class AddNewExpressionDialog(BASE_ADD_NEW, WIDGET_ADD_NEW): @@ -74,7 +83,8 @@ def okPressed(self): WIDGET_DLG, BASE_DLG = uic.loadUiType( - os.path.join(pluginPath, 'PredefinedExpressionDialog.ui')) + os.path.join(pluginPath, "PredefinedExpressionDialog.ui") +) class PredefinedExpressionDialog(BASE_DLG, WIDGET_DLG): @@ -86,7 +96,7 @@ def __init__(self, expression, options): self.filledExpression = None self.options = options self.expression = expression - self.variables = set(re.findall(r'\[.*?\]', expression)) + self.variables = set(re.findall(r"\[.*?\]", expression)) self.comboBoxes = {} for variable in self.variables: label = QLabel(variable[1:-1]) @@ -97,7 +107,9 @@ def __init__(self, expression, options): self.groupBox.layout().addWidget(label) self.groupBox.layout().addWidget(combo) - verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + verticalSpacer = QSpacerItem( + 20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding + ) self.groupBox.layout().addItem(verticalSpacer) self.buttonBox.rejected.connect(self.cancelPressed) @@ -109,13 +121,13 @@ def cancelPressed(self): def okPressed(self): self.filledExpression = self.expression for name, combo in self.comboBoxes.items(): - self.filledExpression = self.filledExpression.replace(name, - self.options[combo.currentText()]) + self.filledExpression = self.filledExpression.replace( + name, self.options[combo.currentText()] + ) self.close() -WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'RasterCalculatorWidget.ui')) +WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "RasterCalculatorWidget.ui")) class ExpressionWidget(BASE, WIDGET): @@ -133,10 +145,16 @@ def doubleClicked(item): def addButtonText(text): if any(c for c in text if c.islower()): self.text.insertPlainText(f" {text}()") - self.text.moveCursor(QTextCursor.MoveOperation.PreviousCharacter, QTextCursor.MoveMode.MoveAnchor) + self.text.moveCursor( + QTextCursor.MoveOperation.PreviousCharacter, + QTextCursor.MoveMode.MoveAnchor, + ) else: self.text.insertPlainText(f" {text} ") - buttons = [b for b in self.buttonsGroupBox.children()if isinstance(b, QPushButton)] + + buttons = [ + b for b in self.buttonsGroupBox.children() if isinstance(b, QPushButton) + ] for button in buttons: button.clicked.connect(partial(addButtonText, button.text())) self.listWidget.itemDoubleClicked.connect(doubleClicked) @@ -154,25 +172,33 @@ def addButtonText(text): self.text.textChanged.connect(self.expressionValid) def expressionValid(self): - errorString = '' - testNode = QgsRasterCalcNode.parseRasterCalcString(self.text.toPlainText(), errorString) + errorString = "" + testNode = QgsRasterCalcNode.parseRasterCalcString( + self.text.toPlainText(), errorString + ) if not self.text.toPlainText(): - self.expressionErrorLabel.setText(self.tr('Expression is empty')) + self.expressionErrorLabel.setText(self.tr("Expression is empty")) self.expressionErrorLabel.setStyleSheet("QLabel { color: black; }") return False if testNode: - self.expressionErrorLabel.setText(self.tr('Expression is valid')) - self.expressionErrorLabel.setStyleSheet("QLabel { color: green; font-weight: bold; }") + self.expressionErrorLabel.setText(self.tr("Expression is valid")) + self.expressionErrorLabel.setStyleSheet( + "QLabel { color: green; font-weight: bold; }" + ) return True - self.expressionErrorLabel.setText(self.tr('Expression is not valid ') + errorString) - self.expressionErrorLabel.setStyleSheet("QLabel { color : red; font-weight: bold; }") + self.expressionErrorLabel.setText( + self.tr("Expression is not valid ") + errorString + ) + self.expressionErrorLabel.setStyleSheet( + "QLabel { color : red; font-weight: bold; }" + ) return False def expsFile(self): - return os.path.join(userFolder(), 'rastercalcexpressions.json') + return os.path.join(userFolder(), "rastercalcexpressions.json") def addPredefined(self): expression = self.expressions[self.comboPredefined.currentText()] @@ -186,7 +212,7 @@ def savePredefined(self): used = [v for v in self.options.values() if v in exp] for i, v in enumerate(used): - exp = exp.replace(v, f'[{chr(97 + i)}]') + exp = exp.replace(v, f"[{chr(97 + i)}]") dlg = AddNewExpressionDialog(exp) dlg.exec() @@ -210,7 +236,7 @@ def _find_source(name): for entry in entries: if entry.ref == name: return entry.raster.source() - return '' + return "" for name in options.keys(): item = QListWidgetItem(name, self.listWidget) @@ -240,14 +266,25 @@ def _get_options(self): def createWidget(self): if self.dialogType == DIALOG_STANDARD: - if iface is not None and iface.layerTreeView() is not None and iface.layerTreeView().layerTreeModel() is not None: + if ( + iface is not None + and iface.layerTreeView() is not None + and iface.layerTreeView().layerTreeModel() is not None + ): iface.layerTreeView().layerTreeModel().dataChanged.connect(self.refresh) return self._panel(self._get_options()) elif self.dialogType == DIALOG_BATCH: return QLineEdit() else: - layers = self.dialog.getAvailableValuesOfType([QgsProcessingParameterRasterLayer], [QgsProcessingOutputRasterLayer]) - options = {self.dialog.resolveValueDescription(lyr): f"{self.dialog.resolveValueDescription(lyr)}@1" for lyr in layers} + layers = self.dialog.getAvailableValuesOfType( + [QgsProcessingParameterRasterLayer], [QgsProcessingOutputRasterLayer] + ) + options = { + self.dialog.resolveValueDescription( + lyr + ): f"{self.dialog.resolveValueDescription(lyr)}@1" + for lyr in layers + } self.widget = self._panel(options) return self.widget @@ -275,7 +312,9 @@ class LayersListWidgetWrapper(WidgetWrapper): def createWidget(self): if self.dialogType == DIALOG_BATCH: - widget = BatchInputSelectionPanel(self.parameterDefinition(), self.row, self.col, self.dialog) + widget = BatchInputSelectionPanel( + self.parameterDefinition(), self.row, self.col, self.dialog + ) widget.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) return widget else: @@ -291,17 +330,27 @@ def value(self): return self.param.setValue(self.widget.selectedoptions) else: if self.param.datatype == dataobjects.TYPE_RASTER: - options = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False) + options = QgsProcessingUtils.compatibleRasterLayers( + QgsProject.instance(), False + ) elif self.param.datatype == dataobjects.TYPE_VECTOR_ANY: - options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False) + options = QgsProcessingUtils.compatibleVectorLayers( + QgsProject.instance(), [], False + ) else: - options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [self.param.datatype], False) + options = QgsProcessingUtils.compatibleVectorLayers( + QgsProject.instance(), [self.param.datatype], False + ) return [options[i] for i in self.widget.selectedoptions] elif self.dialogType == DIALOG_BATCH: return self.widget.getText() else: options = self._getOptions() values = [options[i] for i in self.widget.selectedoptions] - if len(values) == 0 and not self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: + if ( + len(values) == 0 + and not self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ): raise InvalidParameterValue() return values diff --git a/python/plugins/processing/algs/qgis/ui/ReliefColorsWidget.py b/python/plugins/processing/algs/qgis/ui/ReliefColorsWidget.py index 874183a4ad5b..0fee724bde99 100644 --- a/python/plugins/processing/algs/qgis/ui/ReliefColorsWidget.py +++ b/python/plugins/processing/algs/qgis/ui/ReliefColorsWidget.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'December 2016' -__copyright__ = '(C) 2016, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "December 2016" +__copyright__ = "(C) 2016, Alexander Bruy" import os import codecs @@ -25,12 +25,13 @@ from qgis.PyQt import uic from qgis.PyQt.QtCore import pyqtSlot, QDir from qgis.PyQt.QtGui import QColor, QBrush -from qgis.PyQt.QtWidgets import (QTreeWidgetItem, - QFileDialog, - QMessageBox, - QInputDialog, - QColorDialog - ) +from qgis.PyQt.QtWidgets import ( + QTreeWidgetItem, + QFileDialog, + QMessageBox, + QInputDialog, + QColorDialog, +) from qgis.PyQt.QtXml import QDomDocument from qgis.core import QgsApplication, QgsMapLayer @@ -40,7 +41,7 @@ from processing.tools import system pluginPath = os.path.dirname(__file__) -WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, 'reliefcolorswidgetbase.ui')) +WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "reliefcolorswidgetbase.ui")) class ReliefColorsWidget(BASE, WIDGET): @@ -49,21 +50,21 @@ def __init__(self): super().__init__(None) self.setupUi(self) - self.btnAdd.setIcon(QgsApplication.getThemeIcon('/symbologyAdd.svg')) - self.btnRemove.setIcon(QgsApplication.getThemeIcon('/symbologyRemove.svg')) - self.btnUp.setIcon(QgsApplication.getThemeIcon('/mActionArrowUp.svg')) - self.btnDown.setIcon(QgsApplication.getThemeIcon('/mActionArrowDown.svg')) - self.btnLoad.setIcon(QgsApplication.getThemeIcon('/mActionFileOpen.svg')) - self.btnSave.setIcon(QgsApplication.getThemeIcon('/mActionFileSave.svg')) - self.btnAuto.setIcon(QgsApplication.getThemeIcon('/mActionReload.svg')) + self.btnAdd.setIcon(QgsApplication.getThemeIcon("/symbologyAdd.svg")) + self.btnRemove.setIcon(QgsApplication.getThemeIcon("/symbologyRemove.svg")) + self.btnUp.setIcon(QgsApplication.getThemeIcon("/mActionArrowUp.svg")) + self.btnDown.setIcon(QgsApplication.getThemeIcon("/mActionArrowDown.svg")) + self.btnLoad.setIcon(QgsApplication.getThemeIcon("/mActionFileOpen.svg")) + self.btnSave.setIcon(QgsApplication.getThemeIcon("/mActionFileSave.svg")) + self.btnAuto.setIcon(QgsApplication.getThemeIcon("/mActionReload.svg")) self.layer = None @pyqtSlot() def on_btnAdd_clicked(self): item = QTreeWidgetItem() - item.setText(0, '0.00') - item.setText(1, '0.00') + item.setText(0, "0.00") + item.setText(1, "0.00") item.setBackground(2, QBrush(QColor(127, 127, 127))) self.reliefClassTree.addTopLevelItem(item) @@ -96,63 +97,76 @@ def on_btnUp_clicked(self): @pyqtSlot() def on_btnLoad_clicked(self): - fileName, _ = QFileDialog.getOpenFileName(None, - self.tr('Import Colors and elevations from XML'), - QDir.homePath(), - self.tr('XML files (*.xml *.XML)')) - if fileName == '': + fileName, _ = QFileDialog.getOpenFileName( + None, + self.tr("Import Colors and elevations from XML"), + QDir.homePath(), + self.tr("XML files (*.xml *.XML)"), + ) + if fileName == "": return doc = QDomDocument() - with codecs.open(fileName, 'r', encoding='utf-8') as f: + with codecs.open(fileName, "r", encoding="utf-8") as f: content = f.read() if not doc.setContent(content): - QMessageBox.critical(None, - self.tr('Error parsing XML'), - self.tr('The XML file could not be loaded')) + QMessageBox.critical( + None, + self.tr("Error parsing XML"), + self.tr("The XML file could not be loaded"), + ) return self.reliefClassTree.clear() - reliefColorList = doc.elementsByTagName('ReliefColor') + reliefColorList = doc.elementsByTagName("ReliefColor") for i in range(reliefColorList.length()): elem = reliefColorList.at(i).toElement() item = QTreeWidgetItem() - item.setText(0, elem.attribute('MinElevation')) - item.setText(1, elem.attribute('MaxElevation')) - item.setBackground(2, QBrush(QColor(int(elem.attribute('red')), - int(elem.attribute('green')), - int(elem.attribute('blue'))))) + item.setText(0, elem.attribute("MinElevation")) + item.setText(1, elem.attribute("MaxElevation")) + item.setBackground( + 2, + QBrush( + QColor( + int(elem.attribute("red")), + int(elem.attribute("green")), + int(elem.attribute("blue")), + ) + ), + ) self.reliefClassTree.addTopLevelItem(item) @pyqtSlot() def on_btnSave_clicked(self): - fileName, _ = QFileDialog.getSaveFileName(None, - self.tr('Export Colors and elevations as XML'), - QDir.homePath(), - self.tr('XML files (*.xml *.XML)')) - - if fileName == '': + fileName, _ = QFileDialog.getSaveFileName( + None, + self.tr("Export Colors and elevations as XML"), + QDir.homePath(), + self.tr("XML files (*.xml *.XML)"), + ) + + if fileName == "": return - if not fileName.lower().endswith('.xml'): - fileName += '.xml' + if not fileName.lower().endswith(".xml"): + fileName += ".xml" doc = QDomDocument() - colorsElem = doc.createElement('ReliefColors') + colorsElem = doc.createElement("ReliefColors") doc.appendChild(colorsElem) colors = self.reliefColors() for c in colors: - elem = doc.createElement('ReliefColor') - elem.setAttribute('MinElevation', str(c.minElevation)) - elem.setAttribute('MaxElevation', str(c.maxElevation)) - elem.setAttribute('red', str(c.color.red())) - elem.setAttribute('green', str(c.color.green())) - elem.setAttribute('blue', str(c.color.blue())) + elem = doc.createElement("ReliefColor") + elem.setAttribute("MinElevation", str(c.minElevation)) + elem.setAttribute("MaxElevation", str(c.maxElevation)) + elem.setAttribute("red", str(c.color.red())) + elem.setAttribute("green", str(c.color.green())) + elem.setAttribute("blue", str(c.color.blue())) colorsElem.appendChild(elem) - with codecs.open(fileName, 'w', encoding='utf-8') as f: + with codecs.open(fileName, "w", encoding="utf-8") as f: f.write(doc.toString(2)) @pyqtSlot() @@ -160,7 +174,7 @@ def on_btnAuto_clicked(self): if self.layer is None: return - relief = QgsRelief(self.layer, system.getTempFilename(), 'GTiff') + relief = QgsRelief(self.layer, system.getTempFilename(), "GTiff") colors = relief.calculateOptimizedReliefClasses() self.populateColors(colors) @@ -170,25 +184,31 @@ def on_reliefClassTree_itemDoubleClicked(self, item, column): return if column == 0: - d, ok = QInputDialog.getDouble(None, - self.tr('Enter lower elevation class bound'), - self.tr('Elevation'), - float(item.text(0)), - decimals=2) + d, ok = QInputDialog.getDouble( + None, + self.tr("Enter lower elevation class bound"), + self.tr("Elevation"), + float(item.text(0)), + decimals=2, + ) if ok: item.setText(0, str(d)) elif column == 1: - d, ok = QInputDialog.getDouble(None, - self.tr('Enter upper elevation class bound'), - self.tr('Elevation'), - float(item.text(1)), - decimals=2) + d, ok = QInputDialog.getDouble( + None, + self.tr("Enter upper elevation class bound"), + self.tr("Elevation"), + float(item.text(1)), + decimals=2, + ) if ok: item.setText(1, str(d)) elif column == 2: - c = QColorDialog.getColor(item.background(2).color(), - None, - self.tr('Select color for relief class')) + c = QColorDialog.getColor( + item.background(2).color(), + None, + self.tr("Select color for relief class"), + ) if c.isValid(): item.setBackground(2, QBrush(c)) @@ -197,9 +217,9 @@ def reliefColors(self): for i in range(self.reliefClassTree.topLevelItemCount()): item = self.reliefClassTree.topLevelItem(i) if item: - c = QgsRelief.ReliefColor(item.background(2).color(), - float(item.text(0)), - float(item.text(1))) + c = QgsRelief.ReliefColor( + item.background(2).color(), float(item.text(0)), float(item.text(1)) + ) colors.append(c) return colors @@ -217,9 +237,9 @@ def setLayer(self, layer): def setValue(self, value): self.reliefClassTree.clear() - rows = value.split(';') + rows = value.split(";") for r in rows: - v = r.split(',') + v = r.split(",") item = QTreeWidgetItem() item.setText(0, v[0]) item.setText(1, v[1]) @@ -229,13 +249,15 @@ def setValue(self, value): def value(self): rColors = self.reliefColors() - colors = '' + colors = "" for c in rColors: - colors += '{:f}, {:f}, {:d}, {:d}, {:d};'.format(c.minElevation, - c.maxElevation, - c.color.red(), - c.color.green(), - c.color.blue()) + colors += "{:f}, {:f}, {:d}, {:d}, {:d};".format( + c.minElevation, + c.maxElevation, + c.color.red(), + c.color.green(), + c.color.blue(), + ) return colors[:-1] diff --git a/python/plugins/processing/core/Processing.py b/python/plugins/processing/core/Processing.py index e178cfa7cece..5cf03d80baac 100644 --- a/python/plugins/processing/core/Processing.py +++ b/python/plugins/processing/core/Processing.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import traceback @@ -27,20 +27,22 @@ from qgis.PyQt.QtGui import QCursor from qgis.utils import iface -from qgis.core import (QgsMessageLog, - QgsApplication, - QgsMapLayer, - QgsProcessingProvider, - QgsProcessingAlgorithm, - QgsProcessingException, - QgsProcessingParameterDefinition, - QgsProcessingOutputVectorLayer, - QgsProcessingOutputRasterLayer, - QgsProcessingOutputPointCloudLayer, - QgsProcessingOutputMapLayer, - QgsProcessingOutputMultipleLayers, - QgsProcessingFeedback, - QgsRuntimeProfiler) +from qgis.core import ( + QgsMessageLog, + QgsApplication, + QgsMapLayer, + QgsProcessingProvider, + QgsProcessingAlgorithm, + QgsProcessingException, + QgsProcessingParameterDefinition, + QgsProcessingOutputVectorLayer, + QgsProcessingOutputRasterLayer, + QgsProcessingOutputPointCloudLayer, + QgsProcessingOutputMapLayer, + QgsProcessingOutputMultipleLayers, + QgsProcessingFeedback, + QgsRuntimeProfiler, +) from qgis.analysis import QgsNativeAlgorithms import processing @@ -51,14 +53,16 @@ from processing.script import ScriptUtils from processing.tools import dataobjects -with QgsRuntimeProfiler.profile('Import QGIS Provider'): +with QgsRuntimeProfiler.profile("Import QGIS Provider"): from processing.algs.qgis.QgisAlgorithmProvider import QgisAlgorithmProvider # NOQA -with QgsRuntimeProfiler.profile('Import GDAL Provider'): +with QgsRuntimeProfiler.profile("Import GDAL Provider"): from processing.algs.gdal.GdalAlgorithmProvider import GdalAlgorithmProvider # NOQA -with QgsRuntimeProfiler.profile('Import Script Provider'): - from processing.script.ScriptAlgorithmProvider import ScriptAlgorithmProvider # NOQA +with QgsRuntimeProfiler.profile("Import Script Provider"): + from processing.script.ScriptAlgorithmProvider import ( + ScriptAlgorithmProvider, + ) # NOQA # should be loaded last - ensures that all dependent algorithms are available when loading models from processing.modeler.ModelerAlgorithmProvider import ModelerAlgorithmProvider # NOQA @@ -70,32 +74,51 @@ class Processing: @staticmethod def activateProvider(providerOrName, activate=True): - provider_id = providerOrName.id() if isinstance(providerOrName, QgsProcessingProvider) else providerOrName + provider_id = ( + providerOrName.id() + if isinstance(providerOrName, QgsProcessingProvider) + else providerOrName + ) provider = QgsApplication.processingRegistry().providerById(provider_id) try: provider.setActive(True) provider.refreshAlgorithms() except: # provider could not be activated - QgsMessageLog.logMessage(Processing.tr('Error: Provider {0} could not be activated\n').format(provider_id), - Processing.tr("Processing")) + QgsMessageLog.logMessage( + Processing.tr("Error: Provider {0} could not be activated\n").format( + provider_id + ), + Processing.tr("Processing"), + ) @staticmethod def initialize(): - if "script" in [p.id() for p in QgsApplication.processingRegistry().providers()]: + if "script" in [ + p.id() for p in QgsApplication.processingRegistry().providers() + ]: return - with QgsRuntimeProfiler.profile('Initialize'): + with QgsRuntimeProfiler.profile("Initialize"): # add native provider if not already added - if "native" not in [p.id() for p in QgsApplication.processingRegistry().providers()]: - QgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms(QgsApplication.processingRegistry())) + if "native" not in [ + p.id() for p in QgsApplication.processingRegistry().providers() + ]: + QgsApplication.processingRegistry().addProvider( + QgsNativeAlgorithms(QgsApplication.processingRegistry()) + ) # add 3d provider if available and not already added - if "3d" not in [p.id() for p in QgsApplication.processingRegistry().providers()]: + if "3d" not in [ + p.id() for p in QgsApplication.processingRegistry().providers() + ]: try: from qgis._3d import Qgs3DAlgorithms - QgsApplication.processingRegistry().addProvider(Qgs3DAlgorithms(QgsApplication.processingRegistry())) + + QgsApplication.processingRegistry().addProvider( + Qgs3DAlgorithms(QgsApplication.processingRegistry()) + ) except ImportError: # no 3d library available pass @@ -104,25 +127,23 @@ def initialize(): basic_providers = [ QgisAlgorithmProvider, GdalAlgorithmProvider, - ScriptAlgorithmProvider + ScriptAlgorithmProvider, ] # model providers are deferred for qgis_process startup - if QgsApplication.platform() != 'qgis_process': - basic_providers.extend([ - ModelerAlgorithmProvider, - ProjectProvider - ]) + if QgsApplication.platform() != "qgis_process": + basic_providers.extend([ModelerAlgorithmProvider, ProjectProvider]) for c in basic_providers: p = c() if QgsApplication.processingRegistry().addProvider(p): Processing.BASIC_PROVIDERS.append(p) - if QgsApplication.platform() == 'external': + if QgsApplication.platform() == "external": # for external applications we must also load the builtin providers stored in separate plugins try: from grassprovider.grass_provider import GrassProvider + p = GrassProvider() if QgsApplication.processingRegistry().addProvider(p): Processing.BASIC_PROVIDERS.append(p) @@ -142,9 +163,7 @@ def perform_deferred_model_initialization(): # Add the model providers # note that we don't add the Project Provider, as this cannot be called # from qgis_process - model_providers = [ - ModelerAlgorithmProvider - ] + model_providers = [ModelerAlgorithmProvider] for c in model_providers: p = c() @@ -169,7 +188,7 @@ def runAlgorithm(algOrName, parameters, onFinish=None, feedback=None, context=No feedback = QgsProcessingFeedback() if alg is None: - msg = Processing.tr('Error: Algorithm {0} not found\n').format(algOrName) + msg = Processing.tr("Error: Algorithm {0} not found\n").format(algOrName) feedback.reportError(msg) raise QgsProcessingException(msg) @@ -181,18 +200,22 @@ def runAlgorithm(algOrName, parameters, onFinish=None, feedback=None, context=No ok, msg = alg.checkParameterValues(parameters, context) if not ok: - msg = Processing.tr('Unable to execute algorithm\n{0}').format(msg) + msg = Processing.tr("Unable to execute algorithm\n{0}").format(msg) feedback.reportError(msg) raise QgsProcessingException(msg) if not alg.validateInputCrs(parameters, context): feedback.pushInfo( - Processing.tr('Warning: Not all input layers use the same CRS.\nThis can cause unexpected results.')) - - ret, results = execute(alg, parameters, context, feedback, catch_exceptions=False) + Processing.tr( + "Warning: Not all input layers use the same CRS.\nThis can cause unexpected results." + ) + ) + + ret, results = execute( + alg, parameters, context, feedback, catch_exceptions=False + ) if ret: - feedback.pushInfo( - Processing.tr('Results: {}').format(results)) + feedback.pushInfo(Processing.tr("Results: {}").format(results)) if onFinish is not None: onFinish(alg, context, feedback) @@ -202,19 +225,33 @@ def runAlgorithm(algOrName, parameters, onFinish=None, feedback=None, context=No if out.name() not in results: continue - if isinstance(out, (QgsProcessingOutputVectorLayer, QgsProcessingOutputRasterLayer, QgsProcessingOutputPointCloudLayer, QgsProcessingOutputMapLayer)): + if isinstance( + out, + ( + QgsProcessingOutputVectorLayer, + QgsProcessingOutputRasterLayer, + QgsProcessingOutputPointCloudLayer, + QgsProcessingOutputMapLayer, + ), + ): result = results[out.name()] if not isinstance(result, QgsMapLayer): - layer = context.takeResultLayer(result) # transfer layer ownership out of context + layer = context.takeResultLayer( + result + ) # transfer layer ownership out of context if layer: - results[out.name()] = layer # replace layer string ref with actual layer (+ownership) + results[out.name()] = ( + layer # replace layer string ref with actual layer (+ownership) + ) elif isinstance(out, QgsProcessingOutputMultipleLayers): result = results[out.name()] if result: layers_result = [] for l in result: if not isinstance(l, QgsMapLayer): - layer = context.takeResultLayer(l) # transfer layer ownership out of context + layer = context.takeResultLayer( + l + ) # transfer layer ownership out of context if layer: layers_result.append(layer) else: @@ -222,8 +259,9 @@ def runAlgorithm(algOrName, parameters, onFinish=None, feedback=None, context=No else: layers_result.append(l) - results[ - out.name()] = layers_result # replace layers strings ref with actual layers (+ownership) + results[out.name()] = ( + layers_result # replace layers strings ref with actual layers (+ownership) + ) else: msg = Processing.tr("There were errors executing the algorithm.") @@ -235,7 +273,7 @@ def runAlgorithm(algOrName, parameters, onFinish=None, feedback=None, context=No return results @staticmethod - def tr(string, context=''): - if context == '': - context = 'Processing' + def tr(string, context=""): + if context == "": + context = "Processing" return QCoreApplication.translate(context, string) diff --git a/python/plugins/processing/core/ProcessingConfig.py b/python/plugins/processing/core/ProcessingConfig.py index 07921576be17..2b9d67650cb4 100644 --- a/python/plugins/processing/core/ProcessingConfig.py +++ b/python/plugins/processing/core/ProcessingConfig.py @@ -15,20 +15,22 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import tempfile from qgis.PyQt.QtCore import QCoreApplication, QObject, pyqtSignal -from qgis.core import (NULL, - QgsApplication, - QgsSettings, - QgsVectorFileWriter, - QgsRasterFileWriter, - QgsProcessingUtils) +from qgis.core import ( + NULL, + QgsApplication, + QgsSettings, + QgsVectorFileWriter, + QgsRasterFileWriter, + QgsProcessingUtils, +) from processing.tools.system import defaultOutputFolder import processing.tools.dataobjects from multiprocessing import cpu_count @@ -42,26 +44,26 @@ class SettingsWatcher(QObject): class ProcessingConfig: - OUTPUT_FOLDER = 'OUTPUTS_FOLDER' - RASTER_STYLE = 'RASTER_STYLE' - VECTOR_POINT_STYLE = 'VECTOR_POINT_STYLE' - VECTOR_LINE_STYLE = 'VECTOR_LINE_STYLE' - VECTOR_POLYGON_STYLE = 'VECTOR_POLYGON_STYLE' - FILTER_INVALID_GEOMETRIES = 'FILTER_INVALID_GEOMETRIES' - PREFER_FILENAME_AS_LAYER_NAME = 'prefer-filename-as-layer-name' - KEEP_DIALOG_OPEN = 'KEEP_DIALOG_OPEN' - PRE_EXECUTION_SCRIPT = 'PRE_EXECUTION_SCRIPT' - POST_EXECUTION_SCRIPT = 'POST_EXECUTION_SCRIPT' - SHOW_CRS_DEF = 'SHOW_CRS_DEF' - WARN_UNMATCHING_CRS = 'WARN_UNMATCHING_CRS' - SHOW_PROVIDERS_TOOLTIP = 'SHOW_PROVIDERS_TOOLTIP' - SHOW_ALGORITHMS_KNOWN_ISSUES = 'SHOW_ALGORITHMS_KNOWN_ISSUES' - MAX_THREADS = 'MAX_THREADS' - DEFAULT_OUTPUT_RASTER_LAYER_EXT = 'default-output-raster-ext' - DEFAULT_OUTPUT_VECTOR_LAYER_EXT = 'default-output-vector-ext' - TEMP_PATH = 'temp-path' - RESULTS_GROUP_NAME = 'RESULTS_GROUP_NAME' - VECTOR_FEATURE_COUNT = 'VECTOR_FEATURE_COUNT' + OUTPUT_FOLDER = "OUTPUTS_FOLDER" + RASTER_STYLE = "RASTER_STYLE" + VECTOR_POINT_STYLE = "VECTOR_POINT_STYLE" + VECTOR_LINE_STYLE = "VECTOR_LINE_STYLE" + VECTOR_POLYGON_STYLE = "VECTOR_POLYGON_STYLE" + FILTER_INVALID_GEOMETRIES = "FILTER_INVALID_GEOMETRIES" + PREFER_FILENAME_AS_LAYER_NAME = "prefer-filename-as-layer-name" + KEEP_DIALOG_OPEN = "KEEP_DIALOG_OPEN" + PRE_EXECUTION_SCRIPT = "PRE_EXECUTION_SCRIPT" + POST_EXECUTION_SCRIPT = "POST_EXECUTION_SCRIPT" + SHOW_CRS_DEF = "SHOW_CRS_DEF" + WARN_UNMATCHING_CRS = "WARN_UNMATCHING_CRS" + SHOW_PROVIDERS_TOOLTIP = "SHOW_PROVIDERS_TOOLTIP" + SHOW_ALGORITHMS_KNOWN_ISSUES = "SHOW_ALGORITHMS_KNOWN_ISSUES" + MAX_THREADS = "MAX_THREADS" + DEFAULT_OUTPUT_RASTER_LAYER_EXT = "default-output-raster-ext" + DEFAULT_OUTPUT_VECTOR_LAYER_EXT = "default-output-vector-ext" + TEMP_PATH = "temp-path" + RESULTS_GROUP_NAME = "RESULTS_GROUP_NAME" + VECTOR_FEATURE_COUNT = "VECTOR_FEATURE_COUNT" settings = {} settingIcons = {} @@ -69,128 +71,213 @@ class ProcessingConfig: @staticmethod def initialize(): icon = QgsApplication.getThemeIcon("/processingAlgorithm.svg") - ProcessingConfig.settingIcons['General'] = icon - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.KEEP_DIALOG_OPEN, - ProcessingConfig.tr('Keep dialog open after running an algorithm'), True)) - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.PREFER_FILENAME_AS_LAYER_NAME, - ProcessingConfig.tr('Prefer output filename for layer names'), True, - hasSettingEntry=True)) - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.SHOW_PROVIDERS_TOOLTIP, - ProcessingConfig.tr('Show tooltip when there are disabled providers'), True)) - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.OUTPUT_FOLDER, - ProcessingConfig.tr('Output folder'), defaultOutputFolder(), - valuetype=Setting.FOLDER)) - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.SHOW_CRS_DEF, - ProcessingConfig.tr('Show layer CRS definition in selection boxes'), True)) - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.WARN_UNMATCHING_CRS, - ProcessingConfig.tr("Warn before executing if parameter CRS's do not match"), True)) - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES, - ProcessingConfig.tr("Show algorithms with known issues"), False)) - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.RASTER_STYLE, - ProcessingConfig.tr('Style for raster layers'), '', - valuetype=Setting.FILE)) - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.VECTOR_POINT_STYLE, - ProcessingConfig.tr('Style for point layers'), '', - valuetype=Setting.FILE)) - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.VECTOR_LINE_STYLE, - ProcessingConfig.tr('Style for line layers'), '', - valuetype=Setting.FILE)) - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.VECTOR_POLYGON_STYLE, - ProcessingConfig.tr('Style for polygon layers'), '', - valuetype=Setting.FILE)) - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.PRE_EXECUTION_SCRIPT, - ProcessingConfig.tr('Pre-execution script'), '', - valuetype=Setting.FILE)) - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.POST_EXECUTION_SCRIPT, - ProcessingConfig.tr('Post-execution script'), '', - valuetype=Setting.FILE)) - - invalidFeaturesOptions = [ProcessingConfig.tr('Do not filter (better performance)'), - ProcessingConfig.tr('Skip (ignore) features with invalid geometries'), - ProcessingConfig.tr('Stop algorithm execution when a geometry is invalid')] - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.FILTER_INVALID_GEOMETRIES, - ProcessingConfig.tr('Invalid features filtering'), - invalidFeaturesOptions[2], - valuetype=Setting.SELECTION, - options=invalidFeaturesOptions)) - - threads = QgsApplication.maxThreads() # if user specified limit for rendering, lets keep that as default here, otherwise max - threads = cpu_count() if threads == -1 else threads # if unset, maxThreads() returns -1 - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.MAX_THREADS, - ProcessingConfig.tr('Max Threads'), threads, - valuetype=Setting.INT)) + ProcessingConfig.settingIcons["General"] = icon + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.KEEP_DIALOG_OPEN, + ProcessingConfig.tr("Keep dialog open after running an algorithm"), + True, + ) + ) + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.PREFER_FILENAME_AS_LAYER_NAME, + ProcessingConfig.tr("Prefer output filename for layer names"), + True, + hasSettingEntry=True, + ) + ) + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.SHOW_PROVIDERS_TOOLTIP, + ProcessingConfig.tr("Show tooltip when there are disabled providers"), + True, + ) + ) + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.OUTPUT_FOLDER, + ProcessingConfig.tr("Output folder"), + defaultOutputFolder(), + valuetype=Setting.FOLDER, + ) + ) + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.SHOW_CRS_DEF, + ProcessingConfig.tr("Show layer CRS definition in selection boxes"), + True, + ) + ) + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.WARN_UNMATCHING_CRS, + ProcessingConfig.tr( + "Warn before executing if parameter CRS's do not match" + ), + True, + ) + ) + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES, + ProcessingConfig.tr("Show algorithms with known issues"), + False, + ) + ) + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.RASTER_STYLE, + ProcessingConfig.tr("Style for raster layers"), + "", + valuetype=Setting.FILE, + ) + ) + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.VECTOR_POINT_STYLE, + ProcessingConfig.tr("Style for point layers"), + "", + valuetype=Setting.FILE, + ) + ) + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.VECTOR_LINE_STYLE, + ProcessingConfig.tr("Style for line layers"), + "", + valuetype=Setting.FILE, + ) + ) + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.VECTOR_POLYGON_STYLE, + ProcessingConfig.tr("Style for polygon layers"), + "", + valuetype=Setting.FILE, + ) + ) + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.PRE_EXECUTION_SCRIPT, + ProcessingConfig.tr("Pre-execution script"), + "", + valuetype=Setting.FILE, + ) + ) + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.POST_EXECUTION_SCRIPT, + ProcessingConfig.tr("Post-execution script"), + "", + valuetype=Setting.FILE, + ) + ) + + invalidFeaturesOptions = [ + ProcessingConfig.tr("Do not filter (better performance)"), + ProcessingConfig.tr("Skip (ignore) features with invalid geometries"), + ProcessingConfig.tr("Stop algorithm execution when a geometry is invalid"), + ] + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.FILTER_INVALID_GEOMETRIES, + ProcessingConfig.tr("Invalid features filtering"), + invalidFeaturesOptions[2], + valuetype=Setting.SELECTION, + options=invalidFeaturesOptions, + ) + ) + + threads = ( + QgsApplication.maxThreads() + ) # if user specified limit for rendering, lets keep that as default here, otherwise max + threads = ( + cpu_count() if threads == -1 else threads + ) # if unset, maxThreads() returns -1 + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.MAX_THREADS, + ProcessingConfig.tr("Max Threads"), + threads, + valuetype=Setting.INT, + ) + ) extensions = QgsVectorFileWriter.supportedFormatExtensions() - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.DEFAULT_OUTPUT_VECTOR_LAYER_EXT, - ProcessingConfig.tr('Default output vector layer extension'), - QgsVectorFileWriter.supportedFormatExtensions()[0], - valuetype=Setting.SELECTION_STORE_STRING, - options=extensions, - hasSettingEntry=True)) + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.DEFAULT_OUTPUT_VECTOR_LAYER_EXT, + ProcessingConfig.tr("Default output vector layer extension"), + QgsVectorFileWriter.supportedFormatExtensions()[0], + valuetype=Setting.SELECTION_STORE_STRING, + options=extensions, + hasSettingEntry=True, + ) + ) extensions = QgsRasterFileWriter.supportedFormatExtensions() - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.DEFAULT_OUTPUT_RASTER_LAYER_EXT, - ProcessingConfig.tr('Default output raster layer extension'), - 'tif', - valuetype=Setting.SELECTION_STORE_STRING, - options=extensions, - hasSettingEntry=True)) - - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.TEMP_PATH, - ProcessingConfig.tr('Override temporary output folder path'), None, - valuetype=Setting.FOLDER, - placeholder=ProcessingConfig.tr('Leave blank for default'), - hasSettingEntry=True)) - - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.RESULTS_GROUP_NAME, - ProcessingConfig.tr("Results group name"), - "", - valuetype=Setting.STRING, - placeholder=ProcessingConfig.tr("Leave blank to avoid loading results in a predetermined group") - )) - - ProcessingConfig.addSetting(Setting( - ProcessingConfig.tr('General'), - ProcessingConfig.VECTOR_FEATURE_COUNT, - ProcessingConfig.tr('Show feature count for output vector layers'), False)) + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.DEFAULT_OUTPUT_RASTER_LAYER_EXT, + ProcessingConfig.tr("Default output raster layer extension"), + "tif", + valuetype=Setting.SELECTION_STORE_STRING, + options=extensions, + hasSettingEntry=True, + ) + ) + + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.TEMP_PATH, + ProcessingConfig.tr("Override temporary output folder path"), + None, + valuetype=Setting.FOLDER, + placeholder=ProcessingConfig.tr("Leave blank for default"), + hasSettingEntry=True, + ) + ) + + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.RESULTS_GROUP_NAME, + ProcessingConfig.tr("Results group name"), + "", + valuetype=Setting.STRING, + placeholder=ProcessingConfig.tr( + "Leave blank to avoid loading results in a predetermined group" + ), + ) + ) + + ProcessingConfig.addSetting( + Setting( + ProcessingConfig.tr("General"), + ProcessingConfig.VECTOR_FEATURE_COUNT, + ProcessingConfig.tr("Show feature count for output vector layers"), + False, + ) + ) @staticmethod def setGroupIcon(group, icon): @@ -198,7 +285,7 @@ def setGroupIcon(group, icon): @staticmethod def getGroupIcon(group): - if group == ProcessingConfig.tr('General'): + if group == ProcessingConfig.tr("General"): return QgsApplication.getThemeIcon("/processingAlgorithm.svg") if group in ProcessingConfig.settingIcons: return ProcessingConfig.settingIcons[group] @@ -215,7 +302,7 @@ def removeSetting(name): @staticmethod def getSettings(): - '''Return settings as a dict with group names as keys and lists of settings as values''' + """Return settings as a dict with group names as keys and lists of settings as values""" settings = {} for setting in list(ProcessingConfig.settings.values()): if setting.group not in settings: @@ -251,21 +338,23 @@ def getSetting(name, readable=False): def setSettingValue(name, value): if name in list(ProcessingConfig.settings.keys()): if ProcessingConfig.settings[name].valuetype == Setting.SELECTION: - ProcessingConfig.settings[name].setValue(ProcessingConfig.settings[name].options[value]) + ProcessingConfig.settings[name].setValue( + ProcessingConfig.settings[name].options[value] + ) else: ProcessingConfig.settings[name].setValue(value) ProcessingConfig.settings[name].save() @staticmethod - def tr(string, context=''): - if context == '': - context = 'ProcessingConfig' + def tr(string, context=""): + if context == "": + context = "ProcessingConfig" return QCoreApplication.translate(context, string) class Setting: - """A simple config parameter that will appear on the config dialog. - """ + """A simple config parameter that will appear on the config dialog.""" + STRING = 0 FILE = 1 FOLDER = 2 @@ -275,14 +364,27 @@ class Setting: MULTIPLE_FOLDERS = 6 SELECTION_STORE_STRING = 7 - def __init__(self, group, name, description, default, hidden=False, valuetype=None, - validator=None, options=None, placeholder="", hasSettingEntry=False): + def __init__( + self, + group, + name, + description, + default, + hidden=False, + valuetype=None, + validator=None, + options=None, + placeholder="", + hasSettingEntry=False, + ): """ hasSettingEntry is true if the given setting is part of QgsSettingsRegistry entries """ self.group = group self.name = name - self.qname = ("qgis/configuration/" if hasSettingEntry else "Processing/Configuration/") + self.name + self.qname = ( + "qgis/configuration/" if hasSettingEntry else "Processing/Configuration/" + ) + self.name self.description = description self.default = default self.hidden = hidden @@ -298,38 +400,52 @@ def __init__(self, group, name, description, default, hidden=False, valuetype=No if validator is None: if self.valuetype == self.FLOAT: + def checkFloat(v): try: float(v) except ValueError: - raise ValueError(self.tr('Wrong parameter value:\n{0}').format(v)) + raise ValueError( + self.tr("Wrong parameter value:\n{0}").format(v) + ) validator = checkFloat elif self.valuetype == self.INT: + def checkInt(v): try: int(v) except ValueError: - raise ValueError(self.tr('Wrong parameter value:\n{0}').format(v)) + raise ValueError( + self.tr("Wrong parameter value:\n{0}").format(v) + ) validator = checkInt elif self.valuetype in [self.FILE, self.FOLDER]: + def checkFileOrFolder(v): if v and not os.path.exists(v): - raise ValueError(self.tr('Specified path does not exist:\n{0}').format(v)) + raise ValueError( + self.tr("Specified path does not exist:\n{0}").format(v) + ) validator = checkFileOrFolder elif self.valuetype == self.MULTIPLE_FOLDERS: + def checkMultipleFolders(v): - folders = v.split(';') + folders = v.split(";") for f in folders: if f and not os.path.exists(f): - raise ValueError(self.tr('Specified path does not exist:\n{0}').format(f)) + raise ValueError( + self.tr("Specified path does not exist:\n{0}").format(f) + ) validator = checkMultipleFolders else: + def validator(x): return True + self.validator = validator self.value = default @@ -365,9 +481,9 @@ def save(self, qsettings=None): qsettings.setValue(self.qname, self.value) def __str__(self): - return self.name + '=' + str(self.value) + return self.name + "=" + str(self.value) - def tr(self, string, context=''): - if context == '': - context = 'ProcessingConfig' + def tr(self, string, context=""): + if context == "": + context = "ProcessingConfig" return QCoreApplication.translate(context, string) diff --git a/python/plugins/processing/core/ProcessingResults.py b/python/plugins/processing/core/ProcessingResults.py index b7d3eb7de93d..9586f0002b82 100644 --- a/python/plugins/processing/core/ProcessingResults.py +++ b/python/plugins/processing/core/ProcessingResults.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" from qgis.PyQt.QtCore import QObject, pyqtSignal diff --git a/python/plugins/processing/core/defaultproviders.py b/python/plugins/processing/core/defaultproviders.py index 99bf07d26e2f..f65aad5ddd9c 100644 --- a/python/plugins/processing/core/defaultproviders.py +++ b/python/plugins/processing/core/defaultproviders.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'May 2016' -__copyright__ = '(C) 2016, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "May 2016" +__copyright__ = "(C) 2016, Victor Olaya" def loadDefaultProviders(): diff --git a/python/plugins/processing/core/outputs.py b/python/plugins/processing/core/outputs.py index 094d27d9711c..a19dca82c93c 100644 --- a/python/plugins/processing/core/outputs.py +++ b/python/plugins/processing/core/outputs.py @@ -15,31 +15,33 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import sys -from qgis.core import (QgsExpressionContext, - QgsExpressionContextUtils, - QgsExpression, - QgsExpressionContextScope, - QgsProject, - QgsSettings, - QgsVectorFileWriter, - QgsProcessingUtils, - QgsProcessingParameterDefinition, - QgsProcessingOutputRasterLayer, - QgsProcessingOutputVectorLayer, - QgsProcessingOutputMapLayer, - QgsProcessingOutputHtml, - QgsProcessingOutputNumber, - QgsProcessingOutputString, - QgsProcessingOutputBoolean, - QgsProcessingOutputFolder, - QgsProcessingOutputMultipleLayers, - QgsProcessingOutputPointCloudLayer) +from qgis.core import ( + QgsExpressionContext, + QgsExpressionContextUtils, + QgsExpression, + QgsExpressionContextScope, + QgsProject, + QgsSettings, + QgsVectorFileWriter, + QgsProcessingUtils, + QgsProcessingParameterDefinition, + QgsProcessingOutputRasterLayer, + QgsProcessingOutputVectorLayer, + QgsProcessingOutputMapLayer, + QgsProcessingOutputHtml, + QgsProcessingOutputNumber, + QgsProcessingOutputString, + QgsProcessingOutputBoolean, + QgsProcessingOutputFolder, + QgsProcessingOutputMultipleLayers, + QgsProcessingOutputPointCloudLayer, +) def getOutputFromString(s): @@ -51,22 +53,22 @@ def getOutputFromString(s): return clazz(*params) else: tokens = s.split("=") - if tokens[1].lower()[: len('output')] != 'output': + if tokens[1].lower()[: len("output")] != "output": return None name = tokens[0] description = tokens[0] - token = tokens[1].strip()[len('output') + 1:] + token = tokens[1].strip()[len("output") + 1 :] out = None - if token.lower().strip().startswith('outputraster'): + if token.lower().strip().startswith("outputraster"): out = QgsProcessingOutputRasterLayer(name, description) - elif token.lower().strip() == 'outputvector': + elif token.lower().strip() == "outputvector": out = QgsProcessingOutputVectorLayer(name, description) - elif token.lower().strip() == 'outputlayer': + elif token.lower().strip() == "outputlayer": out = QgsProcessingOutputMapLayer(name, description) - elif token.lower().strip() == 'outputmultilayers': + elif token.lower().strip() == "outputmultilayers": out = QgsProcessingOutputMultipleLayers(name, description) # elif token.lower().strip() == 'vector point': # out = OutputVector(datatype=[dataobjects.TYPE_VECTOR_POINT]) @@ -76,22 +78,22 @@ def getOutputFromString(s): # out = OutputVector(datatype=[OutputVector.TYPE_VECTOR_POLYGON]) # elif token.lower().strip().startswith('table'): # out = OutputTable() - elif token.lower().strip().startswith('outputhtml'): + elif token.lower().strip().startswith("outputhtml"): out = QgsProcessingOutputHtml(name, description) # elif token.lower().strip().startswith('file'): # out = OutputFile() # ext = token.strip()[len('file') + 1:] # if ext: # out.ext = ext - elif token.lower().strip().startswith('outputfolder'): + elif token.lower().strip().startswith("outputfolder"): out = QgsProcessingOutputFolder(name, description) - elif token.lower().strip().startswith('outputnumber'): + elif token.lower().strip().startswith("outputnumber"): out = QgsProcessingOutputNumber(name, description) - elif token.lower().strip().startswith('outputstring'): + elif token.lower().strip().startswith("outputstring"): out = QgsProcessingOutputString(name, description) - elif token.lower().strip().startswith('outputboolean'): + elif token.lower().strip().startswith("outputboolean"): out = QgsProcessingOutputBoolean(name, description) - elif token.lower().strip().startswith('outputPointCloud'): + elif token.lower().strip().startswith("outputPointCloud"): out = QgsProcessingOutputPointCloudLayer(name, description) # elif token.lower().strip().startswith('extent'): # out = OutputExtent() diff --git a/python/plugins/processing/core/parameters.py b/python/plugins/processing/core/parameters.py index b60d4f636b19..1b9fce0872c0 100644 --- a/python/plugins/processing/core/parameters.py +++ b/python/plugins/processing/core/parameters.py @@ -15,88 +15,95 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import sys -from qgis.core import (Qgis, - QgsRasterLayer, - QgsVectorLayer, - QgsMapLayer, - QgsCoordinateReferenceSystem, - QgsExpression, - QgsProject, - QgsRectangle, - QgsWkbTypes, - QgsVectorFileWriter, - QgsProcessing, - QgsProcessingUtils, - QgsProcessingParameters, - QgsProcessingParameterDefinition, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterBand, - QgsProcessingParameterBoolean, - QgsProcessingParameterCrs, - QgsProcessingParameterRange, - QgsProcessingParameterPoint, - QgsProcessingParameterGeometry, - QgsProcessingParameterEnum, - QgsProcessingParameterExtent, - QgsProcessingParameterExpression, - QgsProcessingParameterMatrix, - QgsProcessingParameterFile, - QgsProcessingParameterField, - QgsProcessingParameterVectorDestination, - QgsProcessingParameterFileDestination, - QgsProcessingParameterFolderDestination, - QgsProcessingParameterRasterDestination, - QgsProcessingParameterPointCloudDestination, - QgsProcessingParameterString, - QgsProcessingParameterMapLayer, - QgsProcessingParameterMultipleLayers, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterNumber, - QgsProcessingParameterColor, - QgsProcessingParameterPointCloudLayer, - QgsProcessingParameterAnnotationLayer) +from qgis.core import ( + Qgis, + QgsRasterLayer, + QgsVectorLayer, + QgsMapLayer, + QgsCoordinateReferenceSystem, + QgsExpression, + QgsProject, + QgsRectangle, + QgsWkbTypes, + QgsVectorFileWriter, + QgsProcessing, + QgsProcessingUtils, + QgsProcessingParameters, + QgsProcessingParameterDefinition, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterBand, + QgsProcessingParameterBoolean, + QgsProcessingParameterCrs, + QgsProcessingParameterRange, + QgsProcessingParameterPoint, + QgsProcessingParameterGeometry, + QgsProcessingParameterEnum, + QgsProcessingParameterExtent, + QgsProcessingParameterExpression, + QgsProcessingParameterMatrix, + QgsProcessingParameterFile, + QgsProcessingParameterField, + QgsProcessingParameterVectorDestination, + QgsProcessingParameterFileDestination, + QgsProcessingParameterFolderDestination, + QgsProcessingParameterRasterDestination, + QgsProcessingParameterPointCloudDestination, + QgsProcessingParameterString, + QgsProcessingParameterMapLayer, + QgsProcessingParameterMultipleLayers, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterNumber, + QgsProcessingParameterColor, + QgsProcessingParameterPointCloudLayer, + QgsProcessingParameterAnnotationLayer, +) from qgis.PyQt.QtCore import QCoreApplication -PARAMETER_NUMBER = 'number' -PARAMETER_DISTANCE = 'distance' -PARAMETER_SCALE = 'scale' -PARAMETER_RASTER = 'raster' -PARAMETER_TABLE = 'vector' -PARAMETER_VECTOR = 'source' -PARAMETER_STRING = 'string' -PARAMETER_EXPRESSION = 'expression' -PARAMETER_BOOLEAN = 'boolean' -PARAMETER_TABLE_FIELD = 'field' -PARAMETER_EXTENT = 'extent' -PARAMETER_FILE = 'file' -PARAMETER_POINT = 'point' -PARAMETER_GEOMETRY = 'geometry' -PARAMETER_CRS = 'crs' -PARAMETER_MULTIPLE = 'multilayer' -PARAMETER_BAND = 'band' -PARAMETER_LAYOUTITEM = 'layoutitem' -PARAMETER_MAP_LAYER = 'layer' -PARAMETER_RANGE = 'range' -PARAMETER_ENUM = 'enum' -PARAMETER_MATRIX = 'matrix' -PARAMETER_VECTOR_DESTINATION = 'vectorDestination' -PARAMETER_FILE_DESTINATION = 'fileDestination' -PARAMETER_FOLDER_DESTINATION = 'folderDestination' -PARAMETER_RASTER_DESTINATION = 'rasterDestination' -PARAMETER_POINTCLOUD_DESTINATION = 'pointCloudDestination' +PARAMETER_NUMBER = "number" +PARAMETER_DISTANCE = "distance" +PARAMETER_SCALE = "scale" +PARAMETER_RASTER = "raster" +PARAMETER_TABLE = "vector" +PARAMETER_VECTOR = "source" +PARAMETER_STRING = "string" +PARAMETER_EXPRESSION = "expression" +PARAMETER_BOOLEAN = "boolean" +PARAMETER_TABLE_FIELD = "field" +PARAMETER_EXTENT = "extent" +PARAMETER_FILE = "file" +PARAMETER_POINT = "point" +PARAMETER_GEOMETRY = "geometry" +PARAMETER_CRS = "crs" +PARAMETER_MULTIPLE = "multilayer" +PARAMETER_BAND = "band" +PARAMETER_LAYOUTITEM = "layoutitem" +PARAMETER_MAP_LAYER = "layer" +PARAMETER_RANGE = "range" +PARAMETER_ENUM = "enum" +PARAMETER_MATRIX = "matrix" +PARAMETER_VECTOR_DESTINATION = "vectorDestination" +PARAMETER_FILE_DESTINATION = "fileDestination" +PARAMETER_FOLDER_DESTINATION = "folderDestination" +PARAMETER_RASTER_DESTINATION = "rasterDestination" +PARAMETER_POINTCLOUD_DESTINATION = "pointCloudDestination" -def getParameterFromString(s, context=''): +def getParameterFromString(s, context=""): # Try the parameter definitions used in description files - if '|' in s and (s.startswith("QgsProcessingParameter") or s.startswith("*QgsProcessingParameter") or s.startswith('Parameter') or s.startswith('*Parameter')): + if "|" in s and ( + s.startswith("QgsProcessingParameter") + or s.startswith("*QgsProcessingParameter") + or s.startswith("Parameter") + or s.startswith("*Parameter") + ): isAdvanced = False if s.startswith("*"): s = s[1:] @@ -109,89 +116,107 @@ def getParameterFromString(s, context=''): # convert to correct type if clazz == QgsProcessingParameterRasterLayer: if len(params) > 3: - params[3] = True if params[3].lower() == 'true' else False + params[3] = True if params[3].lower() == "true" else False elif clazz == QgsProcessingParameterPointCloudLayer: if len(params) > 3: - params[3] = True if params[3].lower() == 'true' else False + params[3] = True if params[3].lower() == "true" else False elif clazz == QgsProcessingParameterAnnotationLayer: if len(params) > 3: - params[3] = True if params[3].lower() == 'true' else False + params[3] = True if params[3].lower() == "true" else False elif clazz == QgsProcessingParameterBand: if len(params) > 4: - params[4] = True if params[4].lower() == 'true' else False + params[4] = True if params[4].lower() == "true" else False if len(params) > 5: - params[5] = True if params[5].lower() == 'true' else False + params[5] = True if params[5].lower() == "true" else False elif clazz == QgsProcessingParameterVectorLayer: if len(params) > 2: try: - params[2] = [int(p) for p in params[2].split(';')] + params[2] = [int(p) for p in params[2].split(";")] except ValueError: - params[2] = [getattr(QgsProcessing, p.split(".")[1]) for p in params[2].split(';')] + params[2] = [ + getattr(QgsProcessing, p.split(".")[1]) + for p in params[2].split(";") + ] if len(params) > 4: - params[4] = True if params[4].lower() == 'true' else False + params[4] = True if params[4].lower() == "true" else False elif clazz == QgsProcessingParameterMapLayer: if len(params) > 3: - params[3] = True if params[3].lower() == 'true' else False + params[3] = True if params[3].lower() == "true" else False try: - params[4] = [int(p) for p in params[4].split(';')] + params[4] = [int(p) for p in params[4].split(";")] except ValueError: - params[4] = [getattr(QgsProcessing, p.split(".")[1]) for p in params[4].split(';')] + params[4] = [ + getattr(QgsProcessing, p.split(".")[1]) + for p in params[4].split(";") + ] elif clazz == QgsProcessingParameterBoolean: if len(params) > 2: - params[2] = True if params[2].lower() == 'true' else False + params[2] = True if params[2].lower() == "true" else False if len(params) > 3: - params[3] = True if params[3].lower() == 'true' else False + params[3] = True if params[3].lower() == "true" else False elif clazz == QgsProcessingParameterPoint: if len(params) > 3: - params[3] = True if params[3].lower() == 'true' else False + params[3] = True if params[3].lower() == "true" else False elif clazz == QgsProcessingParameterGeometry: if len(params) > 3: - params[3] = True if params[3].lower() == 'true' else False + params[3] = True if params[3].lower() == "true" else False if len(params) > 4: try: - params[4] = [int(p) for p in params[4].split(';')] + params[4] = [int(p) for p in params[4].split(";")] except ValueError: - params[4] = [getattr(QgsWkbTypes, p.split(".")[1]) for p in params[4].split(';')] + params[4] = [ + getattr(QgsWkbTypes, p.split(".")[1]) + for p in params[4].split(";") + ] if len(params) > 5: - params[5] = True if params[5].lower() == 'true' else False + params[5] = True if params[5].lower() == "true" else False elif clazz == QgsProcessingParameterCrs: if len(params) > 3: - params[3] = True if params[3].lower() == 'true' else False + params[3] = True if params[3].lower() == "true" else False elif clazz == QgsProcessingParameterRange: if len(params) > 2: try: params[2] = Qgis.ProcessingNumberParameterType(int(params[2])) except ValueError: - params[2] = getattr(QgsProcessingParameterNumber, params[2].split(".")[1]) + params[2] = getattr( + QgsProcessingParameterNumber, params[2].split(".")[1] + ) if len(params) > 4: - params[4] = True if params[4].lower() == 'true' else False + params[4] = True if params[4].lower() == "true" else False elif clazz == QgsProcessingParameterExtent: if len(params) > 3: - params[3] = True if params[3].lower() == 'true' else False + params[3] = True if params[3].lower() == "true" else False elif clazz == QgsProcessingParameterExpression: if len(params) > 3: - params[3] = True if params[3].lower() == 'true' else False + params[3] = True if params[3].lower() == "true" else False elif clazz == QgsProcessingParameterEnum: if len(params) > 2: - params[2] = params[2].split(';') + params[2] = params[2].split(";") if len(params) > 3: - params[3] = True if params[3].lower() == 'true' else False + params[3] = True if params[3].lower() == "true" else False if len(params) > 4: # For multiple values; default value is a list of int if params[3] is True: - params[4] = [int(v) for v in params[4].split(',')] if params[4] is not None else None + params[4] = ( + [int(v) for v in params[4].split(",")] + if params[4] is not None + else None + ) else: params[4] = int(params[4]) if params[4] is not None else None if len(params) > 5: - params[5] = True if params[5].lower() == 'true' else False + params[5] = True if params[5].lower() == "true" else False elif clazz == QgsProcessingParameterFeatureSource: if len(params) > 2: try: - params[2] = [int(p) for p in params[2].split(';')] + params[2] = [int(p) for p in params[2].split(";")] except ValueError: - params[2] = [getattr(QgsProcessing, p.split(".")[1]) for p in params[2].split(';')] + params[2] = [ + getattr(QgsProcessing, p.split(".")[1]) + for p in params[2].split(";") + ] if len(params) > 4: - params[4] = True if params[4].lower() == 'true' else False + params[4] = True if params[4].lower() == "true" else False elif clazz == QgsProcessingParameterMultipleLayers: if len(params) > 2: try: @@ -199,81 +224,99 @@ def getParameterFromString(s, context=''): except ValueError: params[2] = getattr(QgsProcessing, params[2].split(".")[1]) if len(params) > 4: - params[4] = True if params[4].lower() == 'true' else False + params[4] = True if params[4].lower() == "true" else False elif clazz == QgsProcessingParameterMatrix: if len(params) > 2: params[2] = int(params[2]) if len(params) > 3: - params[3] = True if params[3].lower() == 'true' else False + params[3] = True if params[3].lower() == "true" else False if len(params) > 4: - params[4] = params[4].split(';') + params[4] = params[4].split(";") if len(params) > 6: - params[6] = True if params[6].lower() == 'true' else False + params[6] = True if params[6].lower() == "true" else False elif clazz == QgsProcessingParameterField: if len(params) > 4: try: - params[4] = Qgis.ProcessingFieldParameterDataType(int(params[4])) + params[4] = Qgis.ProcessingFieldParameterDataType( + int(params[4]) + ) except ValueError: - params[4] = getattr(QgsProcessingParameterField, params[4].split(".")[1]) + params[4] = getattr( + QgsProcessingParameterField, params[4].split(".")[1] + ) if len(params) > 5: - params[5] = True if params[5].lower() == 'true' else False + params[5] = True if params[5].lower() == "true" else False if len(params) > 6: - params[6] = True if params[6].lower() == 'true' else False + params[6] = True if params[6].lower() == "true" else False if len(params) > 7: - params[7] = True if params[7].lower() == 'true' else False + params[7] = True if params[7].lower() == "true" else False elif clazz == QgsProcessingParameterFile: if len(params) > 2: try: params[2] = Qgis.ProcessingFileParameterBehavior(int(params[2])) except ValueError: - params[2] = getattr(QgsProcessingParameterFile, params[2].split(".")[1]) + params[2] = getattr( + QgsProcessingParameterFile, params[2].split(".")[1] + ) if len(params) > 5: - params[5] = True if params[5].lower() == 'true' else False + params[5] = True if params[5].lower() == "true" else False elif clazz == QgsProcessingParameterNumber: if len(params) > 2: try: params[2] = Qgis.ProcessingNumberParameterType(int(params[2])) except ValueError: - params[2] = getattr(QgsProcessingParameterNumber, params[2].split(".")[1]) + params[2] = getattr( + QgsProcessingParameterNumber, params[2].split(".")[1] + ) if len(params) > 3: - params[3] = float(params[3].strip()) if params[3] is not None else None + params[3] = ( + float(params[3].strip()) if params[3] is not None else None + ) if len(params) > 4: - params[4] = True if params[4].lower() == 'true' else False + params[4] = True if params[4].lower() == "true" else False if len(params) > 5: - params[5] = float(params[5].strip()) if params[5] is not None else -sys.float_info.max + 1 + params[5] = ( + float(params[5].strip()) + if params[5] is not None + else -sys.float_info.max + 1 + ) if len(params) > 6: - params[6] = float(params[6].strip()) if params[6] is not None else sys.float_info.max - 1 + params[6] = ( + float(params[6].strip()) + if params[6] is not None + else sys.float_info.max - 1 + ) elif clazz == QgsProcessingParameterString: if len(params) > 3: - params[3] = True if params[3].lower() == 'true' else False + params[3] = True if params[3].lower() == "true" else False if len(params) > 4: - params[4] = True if params[4].lower() == 'true' else False + params[4] = True if params[4].lower() == "true" else False elif clazz == QgsProcessingParameterColor: if len(params) > 3: - params[3] = True if params[3].lower() == 'true' else False + params[3] = True if params[3].lower() == "true" else False if len(params) > 4: - params[4] = True if params[4].lower() == 'true' else False + params[4] = True if params[4].lower() == "true" else False elif clazz == QgsProcessingParameterFileDestination: if len(params) > 4: - params[4] = True if params[4].lower() == 'true' else False + params[4] = True if params[4].lower() == "true" else False if len(params) > 5: - params[5] = True if params[5].lower() == 'true' else False + params[5] = True if params[5].lower() == "true" else False elif clazz == QgsProcessingParameterFolderDestination: if len(params) > 3: - params[3] = True if params[3].lower() == 'true' else False + params[3] = True if params[3].lower() == "true" else False if len(params) > 4: - params[4] = True if params[4].lower() == 'true' else False + params[4] = True if params[4].lower() == "true" else False elif clazz == QgsProcessingParameterRasterDestination: if len(params) > 3: - params[3] = True if params[3].lower() == 'true' else False + params[3] = True if params[3].lower() == "true" else False if len(params) > 4: - params[4] = True if params[4].lower() == 'true' else False + params[4] = True if params[4].lower() == "true" else False elif clazz == QgsProcessingParameterPointCloudDestination: print(params) if len(params) > 3: - params[3] = True if params[3].lower() == 'true' else False + params[3] = True if params[3].lower() == "true" else False if len(params) > 4: - params[4] = True if params[4].lower() == 'true' else False + params[4] = True if params[4].lower() == "true" else False elif clazz == QgsProcessingParameterVectorDestination: if len(params) > 2: try: @@ -281,15 +324,19 @@ def getParameterFromString(s, context=''): except ValueError: params[2] = getattr(QgsProcessing, params[2].split(".")[1]) if len(params) > 4: - params[4] = True if params[4].lower() == 'true' else False + params[4] = True if params[4].lower() == "true" else False if len(params) > 5: - params[5] = True if params[5].lower() == 'true' else False + params[5] = True if params[5].lower() == "true" else False param = clazz(*params) if isAdvanced: - param.setFlags(param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + param.setFlags( + param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) - param.setDescription(QCoreApplication.translate(context, param.description())) + param.setDescription( + QCoreApplication.translate(context, param.description()) + ) return param else: diff --git a/python/plugins/processing/gui/AlgorithmDialog.py b/python/plugins/processing/gui/AlgorithmDialog.py index 091f61df28d0..954623faacd4 100644 --- a/python/plugins/processing/gui/AlgorithmDialog.py +++ b/python/plugins/processing/gui/AlgorithmDialog.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import datetime import time @@ -26,17 +26,21 @@ from qgis.PyQt.QtWidgets import QMessageBox, QPushButton, QDialogButtonBox from qgis.PyQt.QtGui import QColor, QPalette -from qgis.core import (Qgis, - QgsApplication, - QgsProcessingAlgRunnerTask, - QgsProcessingOutputHtml, - QgsProcessingAlgorithm, - QgsProxyProgressTask, - QgsProcessingFeatureSourceDefinition) -from qgis.gui import (QgsGui, - QgsProcessingAlgorithmDialogBase, - QgsProcessingParametersGenerator, - QgsProcessingContextGenerator) +from qgis.core import ( + Qgis, + QgsApplication, + QgsProcessingAlgRunnerTask, + QgsProcessingOutputHtml, + QgsProcessingAlgorithm, + QgsProxyProgressTask, + QgsProcessingFeatureSourceDefinition, +) +from qgis.gui import ( + QgsGui, + QgsProcessingAlgorithmDialogBase, + QgsProcessingParametersGenerator, + QgsProcessingContextGenerator, +) from qgis.utils import iface from processing.core.ProcessingConfig import ProcessingConfig @@ -68,23 +72,36 @@ def __init__(self, alg, in_place=False, parent=None): self.setMainWidget(self.getParametersPanel(alg, self)) if not self.in_place: - self.runAsBatchButton = QPushButton(QCoreApplication.translate("AlgorithmDialog", "Run as Batch Process…")) + self.runAsBatchButton = QPushButton( + QCoreApplication.translate("AlgorithmDialog", "Run as Batch Process…") + ) self.runAsBatchButton.clicked.connect(self.runAsBatch) - self.buttonBox().addButton(self.runAsBatchButton, - QDialogButtonBox.ButtonRole.ResetRole) # reset role to ensure left alignment + self.buttonBox().addButton( + self.runAsBatchButton, QDialogButtonBox.ButtonRole.ResetRole + ) # reset role to ensure left alignment else: - in_place_input_parameter_name = 'INPUT' - if hasattr(alg, 'inputParameterName'): + in_place_input_parameter_name = "INPUT" + if hasattr(alg, "inputParameterName"): in_place_input_parameter_name = alg.inputParameterName() - self.mainWidget().setParameters({in_place_input_parameter_name: self.active_layer}) + self.mainWidget().setParameters( + {in_place_input_parameter_name: self.active_layer} + ) self.runAsBatchButton = None - has_selection = self.active_layer and (self.active_layer.selectedFeatureCount() > 0) + has_selection = self.active_layer and ( + self.active_layer.selectedFeatureCount() > 0 + ) self.buttonBox().button(QDialogButtonBox.StandardButton.Ok).setText( - QCoreApplication.translate("AlgorithmDialog", "Modify Selected Features") - if has_selection else QCoreApplication.translate("AlgorithmDialog", "Modify All Features")) - self.setWindowTitle(self.windowTitle() + ' | ' + self.active_layer.name()) + QCoreApplication.translate( + "AlgorithmDialog", "Modify Selected Features" + ) + if has_selection + else QCoreApplication.translate( + "AlgorithmDialog", "Modify All Features" + ) + ) + self.setWindowTitle(self.windowTitle() + " | " + self.active_layer.name()) self.updateRunButtonVisibility() @@ -114,35 +131,39 @@ def flag_invalid_parameter_value(self, message: str, widget): Highlights a parameter with an invalid value """ try: - self.buttonBox().accepted.connect(lambda w=widget: - w.setPalette(QPalette())) + self.buttonBox().accepted.connect(lambda w=widget: w.setPalette(QPalette())) palette = widget.palette() palette.setColor(QPalette.ColorRole.Base, QColor(255, 255, 0)) widget.setPalette(palette) except: pass self.messageBar().clearWidgets() - self.messageBar().pushMessage("", self.tr("Wrong or missing parameter value: {0}").format( - message), - level=Qgis.MessageLevel.Warning, duration=5) + self.messageBar().pushMessage( + "", + self.tr("Wrong or missing parameter value: {0}").format(message), + level=Qgis.MessageLevel.Warning, + duration=5, + ) def flag_invalid_output_extension(self, message: str, widget): """ Highlights a parameter with an invalid output extension """ try: - self.buttonBox().accepted.connect(lambda w=widget: - w.setPalette(QPalette())) + self.buttonBox().accepted.connect(lambda w=widget: w.setPalette(QPalette())) palette = widget.palette() palette.setColor(QPalette.ColorRole.Base, QColor(255, 255, 0)) widget.setPalette(palette) except: pass self.messageBar().clearWidgets() - self.messageBar().pushMessage("", message, - level=Qgis.MessageLevel.Warning, duration=5) + self.messageBar().pushMessage( + "", message, level=Qgis.MessageLevel.Warning, duration=5 + ) - def createProcessingParameters(self, flags=QgsProcessingParametersGenerator.Flags()): + def createProcessingParameters( + self, flags=QgsProcessingParametersGenerator.Flags() + ): if self.mainWidget() is None: return {} @@ -173,21 +194,31 @@ def runAlgorithm(self): # messy as all heck, but we don't want to call the dialog's implementation of # createProcessingParameters as we want to catch the exceptions raised by the # parameter panel instead... - parameters = {} if self.mainWidget() is None else self.mainWidget().createProcessingParameters() - - if checkCRS and not self.algorithm().validateInputCrs(parameters, self.context): - reply = QMessageBox.question(self, self.tr("Unmatching CRS's"), - self.tr('Parameters do not all use the same CRS. This can ' - 'cause unexpected results.\nDo you want to ' - 'continue?'), - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, - QMessageBox.StandardButton.No) + parameters = ( + {} + if self.mainWidget() is None + else self.mainWidget().createProcessingParameters() + ) + + if checkCRS and not self.algorithm().validateInputCrs( + parameters, self.context + ): + reply = QMessageBox.question( + self, + self.tr("Unmatching CRS's"), + self.tr( + "Parameters do not all use the same CRS. This can " + "cause unexpected results.\nDo you want to " + "continue?" + ), + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + QMessageBox.StandardButton.No, + ) if reply == QMessageBox.StandardButton.No: return ok, msg = self.algorithm().checkParameterValues(parameters, self.context) if not ok: - QMessageBox.warning( - self, self.tr('Unable to execute algorithm'), msg) + QMessageBox.warning(self, self.tr("Unable to execute algorithm"), msg) return self.blockControlsWhileRunning() @@ -197,33 +228,51 @@ def runAlgorithm(self): self.iterateParam = None for param in self.algorithm().parameterDefinitions(): - if isinstance(parameters.get(param.name(), None), QgsProcessingFeatureSourceDefinition) and parameters[ - param.name()].flags & QgsProcessingFeatureSourceDefinition.Flag.FlagCreateIndividualOutputPerInputFeature: + if ( + isinstance( + parameters.get(param.name(), None), + QgsProcessingFeatureSourceDefinition, + ) + and parameters[param.name()].flags + & QgsProcessingFeatureSourceDefinition.Flag.FlagCreateIndividualOutputPerInputFeature + ): self.iterateParam = param.name() break self.clearProgress() self.feedback.pushVersionInfo(self.algorithm().provider()) - if self.algorithm().provider() and self.algorithm().provider().warningMessage(): + if ( + self.algorithm().provider() + and self.algorithm().provider().warningMessage() + ): self.feedback.reportError(self.algorithm().provider().warningMessage()) self.feedback.pushInfo( - QCoreApplication.translate('AlgorithmDialog', 'Algorithm started at: {}').format( - datetime.datetime.now().replace(microsecond=0).isoformat() - ) + QCoreApplication.translate( + "AlgorithmDialog", "Algorithm started at: {}" + ).format(datetime.datetime.now().replace(microsecond=0).isoformat()) ) self.setInfo( - QCoreApplication.translate('AlgorithmDialog', 'Algorithm \'{0}\' starting…').format( - self.algorithm().displayName()), escapeHtml=False) + QCoreApplication.translate( + "AlgorithmDialog", "Algorithm '{0}' starting…" + ).format(self.algorithm().displayName()), + escapeHtml=False, + ) - self.feedback.pushInfo(self.tr('Input parameters:')) + self.feedback.pushInfo(self.tr("Input parameters:")) display_params = [] for k, v in parameters.items(): display_params.append( - "'" + k + "' : " + self.algorithm().parameterDefinition(k).valueAsPythonString(v, self.context)) - self.feedback.pushCommandInfo('{ ' + ', '.join(display_params) + ' }') - self.feedback.pushInfo('') + "'" + + k + + "' : " + + self.algorithm() + .parameterDefinition(k) + .valueAsPythonString(v, self.context) + ) + self.feedback.pushCommandInfo("{ " + ", ".join(display_params) + " }") + self.feedback.pushInfo("") start_time = time.time() def elapsed_time(start_time) -> str: @@ -237,14 +286,21 @@ def elapsed_time(start_time) -> str: str_seconds = [self.tr("second"), self.tr("seconds")][seconds != 1] if hours > 0: - elapsed = '{0:0.2f} {1} ({2} {3} {4} {5} {6:0.0f} {1})'.format( - delta_t, str_seconds, hours, str_hours, minutes, str_minutes, seconds) + elapsed = "{0:0.2f} {1} ({2} {3} {4} {5} {6:0.0f} {1})".format( + delta_t, + str_seconds, + hours, + str_hours, + minutes, + str_minutes, + seconds, + ) elif minutes > 0: - elapsed = '{0:0.2f} {1} ({2} {3} {4:0.0f} {1})'.format( - delta_t, str_seconds, minutes, str_minutes, seconds) + elapsed = "{0:0.2f} {1} ({2} {3} {4:0.0f} {1})".format( + delta_t, str_seconds, minutes, str_minutes, seconds + ) else: - elapsed = '{:0.2f} {}'.format( - delta_t, str_seconds) + elapsed = f"{delta_t:0.2f} {str_seconds}" return elapsed @@ -256,10 +312,21 @@ def elapsed_time(start_time) -> str: except: pass - self.cancelButton().setEnabled(self.algorithm().flags() & QgsProcessingAlgorithm.Flag.FlagCanCancel) - if executeIterating(self.algorithm(), parameters, self.iterateParam, self.context, self.feedback): + self.cancelButton().setEnabled( + self.algorithm().flags() & QgsProcessingAlgorithm.Flag.FlagCanCancel + ) + if executeIterating( + self.algorithm(), + parameters, + self.iterateParam, + self.context, + self.feedback, + ): self.feedback.pushInfo( - self.tr('Execution completed in {}').format(elapsed_time(start_time))) + self.tr("Execution completed in {}").format( + elapsed_time(start_time) + ) + ) self.cancelButton().setEnabled(False) self.finish(True, parameters, self.context, self.feedback) else: @@ -267,34 +334,56 @@ def elapsed_time(start_time) -> str: self.resetGui() else: self.history_details = { - 'python_command': self.algorithm().asPythonCommand(parameters, self.context), - 'algorithm_id': self.algorithm().id(), - 'parameters': self.algorithm().asMap(parameters, self.context) + "python_command": self.algorithm().asPythonCommand( + parameters, self.context + ), + "algorithm_id": self.algorithm().id(), + "parameters": self.algorithm().asMap(parameters, self.context), } - process_command, command_ok = self.algorithm().asQgisProcessCommand(parameters, self.context) + process_command, command_ok = self.algorithm().asQgisProcessCommand( + parameters, self.context + ) if command_ok: - self.history_details['process_command'] = process_command - self.history_log_id, _ = QgsGui.historyProviderRegistry().addEntry('processing', self.history_details) + self.history_details["process_command"] = process_command + self.history_log_id, _ = QgsGui.historyProviderRegistry().addEntry( + "processing", self.history_details + ) - QgsGui.instance().processingRecentAlgorithmLog().push(self.algorithm().id()) - self.cancelButton().setEnabled(self.algorithm().flags() & QgsProcessingAlgorithm.Flag.FlagCanCancel) + QgsGui.instance().processingRecentAlgorithmLog().push( + self.algorithm().id() + ) + self.cancelButton().setEnabled( + self.algorithm().flags() & QgsProcessingAlgorithm.Flag.FlagCanCancel + ) def on_complete(ok, results): if ok: self.feedback.pushInfo( - self.tr('Execution completed in {}').format(elapsed_time(start_time))) - self.feedback.pushFormattedResults(self.algorithm(), self.context, results) + self.tr("Execution completed in {}").format( + elapsed_time(start_time) + ) + ) + self.feedback.pushFormattedResults( + self.algorithm(), self.context, results + ) else: self.feedback.reportError( - self.tr('Execution failed after {}').format(elapsed_time(start_time))) - self.feedback.pushInfo('') + self.tr("Execution failed after {}").format( + elapsed_time(start_time) + ) + ) + self.feedback.pushInfo("") if self.history_log_id is not None: # can't deepcopy this! - self.history_details['results'] = {k: v for k, v in results.items() if k != 'CHILD_INPUTS'} - self.history_details['log'] = self.feedback.htmlLog() + self.history_details["results"] = { + k: v for k, v in results.items() if k != "CHILD_INPUTS" + } + self.history_details["log"] = self.feedback.htmlLog() - QgsGui.historyProviderRegistry().updateEntry(self.history_log_id, self.history_details) + QgsGui.historyProviderRegistry().updateEntry( + self.history_log_id, self.history_details + ) if self.feedback_dialog is not None: self.feedback_dialog.close() @@ -303,16 +392,23 @@ def on_complete(ok, results): self.cancelButton().setEnabled(False) - self.finish(ok, results, self.context, self.feedback, in_place=self.in_place) + self.finish( + ok, results, self.context, self.feedback, in_place=self.in_place + ) self.feedback = None self.context = None - if not self.in_place and not (self.algorithm().flags() & QgsProcessingAlgorithm.Flag.FlagNoThreading): + if not self.in_place and not ( + self.algorithm().flags() + & QgsProcessingAlgorithm.Flag.FlagNoThreading + ): # Make sure the Log tab is visible before executing the algorithm self.showLog() - task = QgsProcessingAlgRunnerTask(self.algorithm(), parameters, self.context, self.feedback) + task = QgsProcessingAlgRunnerTask( + self.algorithm(), parameters, self.context, self.feedback + ) if task.isCanceled(): on_complete(False, {}) else: @@ -320,16 +416,24 @@ def on_complete(ok, results): self.setCurrentTask(task) else: self.proxy_progress = QgsProxyProgressTask( - QCoreApplication.translate("AlgorithmDialog", "Executing “{}”").format( - self.algorithm().displayName())) + QCoreApplication.translate( + "AlgorithmDialog", "Executing “{}”" + ).format(self.algorithm().displayName()) + ) QgsApplication.taskManager().addTask(self.proxy_progress) - self.feedback.progressChanged.connect(self.proxy_progress.setProxyProgress) + self.feedback.progressChanged.connect( + self.proxy_progress.setProxyProgress + ) self.feedback_dialog = self.createProgressDialog() self.feedback_dialog.show() if self.in_place: - ok, results = execute_in_place(self.algorithm(), parameters, self.context, self.feedback) + ok, results = execute_in_place( + self.algorithm(), parameters, self.context, self.feedback + ) else: - ok, results = execute(self.algorithm(), parameters, self.context, self.feedback) + ok, results = execute( + self.algorithm(), parameters, self.context, self.feedback + ) self.feedback.progressChanged.disconnect() self.proxy_progress.finalize(ok) on_complete(ok, results) @@ -340,29 +444,37 @@ def on_complete(ok, results): self.flag_invalid_output_extension(e.message, e.widget) def finish(self, successful, result, context, feedback, in_place=False): - keepOpen = not successful or ProcessingConfig.getSetting(ProcessingConfig.KEEP_DIALOG_OPEN) + keepOpen = not successful or ProcessingConfig.getSetting( + ProcessingConfig.KEEP_DIALOG_OPEN + ) generated_html_outputs = False if not in_place and self.iterateParam is None: # add html results to results dock for out in self.algorithm().outputDefinitions(): - if isinstance(out, QgsProcessingOutputHtml) and out.name() in result and result[out.name()]: - resultsList.addResult(icon=self.algorithm().icon(), name=out.description(), - timestamp=time.localtime(), - result=result[out.name()]) + if ( + isinstance(out, QgsProcessingOutputHtml) + and out.name() in result + and result[out.name()] + ): + resultsList.addResult( + icon=self.algorithm().icon(), + name=out.description(), + timestamp=time.localtime(), + result=result[out.name()], + ) generated_html_outputs = True - if not handleAlgorithmResults( - self.algorithm(), - context, - feedback, - result): + if not handleAlgorithmResults(self.algorithm(), context, feedback, result): self.resetGui() return self.setExecuted(True) self.setResults(result) - self.setInfo(self.tr('Algorithm \'{0}\' finished').format(self.algorithm().displayName()), escapeHtml=False) + self.setInfo( + self.tr("Algorithm '{0}' finished").format(self.algorithm().displayName()), + escapeHtml=False, + ) self.algorithmFinished.emit(successful, result) if not in_place and not keepOpen: @@ -371,5 +483,9 @@ def finish(self, successful, result, context, feedback, in_place=False): self.resetGui() if generated_html_outputs: self.setInfo( - self.tr('HTML output has been generated by this algorithm.' - '\nOpen the results dialog to check it.'), escapeHtml=False) + self.tr( + "HTML output has been generated by this algorithm." + "\nOpen the results dialog to check it." + ), + escapeHtml=False, + ) diff --git a/python/plugins/processing/gui/AlgorithmDialogBase.py b/python/plugins/processing/gui/AlgorithmDialogBase.py index 84a6660d2da3..518d25d890a3 100644 --- a/python/plugins/processing/gui/AlgorithmDialogBase.py +++ b/python/plugins/processing/gui/AlgorithmDialogBase.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" class AlgorithmDialogBase: diff --git a/python/plugins/processing/gui/AlgorithmExecutor.py b/python/plugins/processing/gui/AlgorithmExecutor.py index c2dc506e3d11..c1ef9432d449 100644 --- a/python/plugins/processing/gui/AlgorithmExecutor.py +++ b/python/plugins/processing/gui/AlgorithmExecutor.py @@ -15,30 +15,32 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import sys from qgis.PyQt.QtCore import QCoreApplication -from qgis.core import (Qgis, - QgsApplication, - QgsFeatureSink, - QgsProcessingFeedback, - QgsProcessingUtils, - QgsMessageLog, - QgsProcessingException, - QgsProcessingFeatureSourceDefinition, - QgsProcessingFeatureSource, - QgsProcessingParameters, - QgsProject, - QgsFeatureRequest, - QgsFeature, - QgsExpression, - QgsWkbTypes, - QgsGeometry, - QgsVectorLayerUtils, - QgsVectorLayer) +from qgis.core import ( + Qgis, + QgsApplication, + QgsFeatureSink, + QgsProcessingFeedback, + QgsProcessingUtils, + QgsMessageLog, + QgsProcessingException, + QgsProcessingFeatureSourceDefinition, + QgsProcessingFeatureSource, + QgsProcessingParameters, + QgsProject, + QgsFeatureRequest, + QgsFeature, + QgsExpression, + QgsWkbTypes, + QgsGeometry, + QgsVectorLayerUtils, + QgsVectorLayer, +) from processing.gui.Postprocessing import handleAlgorithmResults from processing.tools import dataobjects from qgis.utils import iface @@ -62,7 +64,9 @@ def execute(alg, parameters, context=None, feedback=None, catch_exceptions=True) results, ok = alg.run(parameters, context, feedback) return ok, results except QgsProcessingException as e: - QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing', Qgis.MessageLevel.Critical) + QgsMessageLog.logMessage( + str(sys.exc_info()[0]), "Processing", Qgis.MessageLevel.Critical + ) if feedback is not None: feedback.reportError(e.msg) return False, {} @@ -71,7 +75,9 @@ def execute(alg, parameters, context=None, feedback=None, catch_exceptions=True) return ok, results -def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exceptions=False): +def execute_in_place_run( + alg, parameters, context=None, feedback=None, raise_exceptions=False +): """Executes an algorithm modifying features in-place in the input layer. :param alg: algorithm to run @@ -96,13 +102,18 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc # Only feature based algs have sourceFlags try: - if alg.sourceFlags() & QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks: - context.setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck) + if ( + alg.sourceFlags() + & QgsProcessingFeatureSource.Flag.FlagSkipGeometryValidityChecks + ): + context.setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck + ) except AttributeError: pass - in_place_input_parameter_name = 'INPUT' - if hasattr(alg, 'inputParameterName'): + in_place_input_parameter_name = "INPUT" + if hasattr(alg, "inputParameterName"): in_place_input_parameter_name = alg.inputParameterName() active_layer = parameters[in_place_input_parameter_name] @@ -129,24 +140,36 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc if not active_layer.isEditable(): if not active_layer.startEditing(): - raise QgsProcessingException(tr("Active layer is not editable (and editing could not be turned on).")) + raise QgsProcessingException( + tr( + "Active layer is not editable (and editing could not be turned on)." + ) + ) if not alg.supportInPlaceEdit(active_layer): - raise QgsProcessingException(tr("Selected algorithm and parameter configuration are not compatible with in-place modifications.")) + raise QgsProcessingException( + tr( + "Selected algorithm and parameter configuration are not compatible with in-place modifications." + ) + ) except QgsProcessingException as e: if raise_exceptions: raise e - QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing', Qgis.MessageLevel.Critical) + QgsMessageLog.logMessage( + str(sys.exc_info()[0]), "Processing", Qgis.MessageLevel.Critical + ) if feedback is not None: - feedback.reportError(getattr(e, 'msg', str(e)), fatalError=True) + feedback.reportError(getattr(e, "msg", str(e)), fatalError=True) return False, {} if not active_layer.selectedFeatureIds(): active_layer.selectAll() # Make sure we are working on selected features only - parameters[in_place_input_parameter_name] = QgsProcessingFeatureSourceDefinition(active_layer.id(), True) - parameters['OUTPUT'] = 'memory:' + parameters[in_place_input_parameter_name] = QgsProcessingFeatureSourceDefinition( + active_layer.id(), True + ) + parameters["OUTPUT"] = "memory:" req = QgsFeatureRequest(QgsExpression(r"$id < 0")) req.setFlags(QgsFeatureRequest.Flag.NoGeometry) @@ -162,15 +185,21 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc active_layer.beginEditCommand(alg.displayName()) # Checks whether the algorithm has a processFeature method - if hasattr(alg, 'processFeature'): # in-place feature editing + if hasattr(alg, "processFeature"): # in-place feature editing # Make a clone or it will crash the second time the dialog # is opened and run - alg = alg.create({'IN_PLACE': True}) + alg = alg.create({"IN_PLACE": True}) if not alg.prepare(parameters, context, feedback): - raise QgsProcessingException(tr("Could not prepare selected algorithm.")) + raise QgsProcessingException( + tr("Could not prepare selected algorithm.") + ) # Check again for compatibility after prepare if not alg.supportInPlaceEdit(active_layer): - raise QgsProcessingException(tr("Selected algorithm and parameter configuration are not compatible with in-place modifications.")) + raise QgsProcessingException( + tr( + "Selected algorithm and parameter configuration are not compatible with in-place modifications." + ) + ) # some algorithms have logic in outputFields/outputCrs/outputWkbType which they require to execute before # they can start processing features @@ -182,7 +211,11 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc iterator_req = QgsFeatureRequest(active_layer.selectedFeatureIds()) iterator_req.setInvalidGeometryCheck(context.invalidGeometryCheck()) feature_iterator = active_layer.getFeatures(iterator_req) - step = 100 / len(active_layer.selectedFeatureIds()) if active_layer.selectedFeatureIds() else 1 + step = ( + 100 / len(active_layer.selectedFeatureIds()) + if active_layer.selectedFeatureIds() + else 1 + ) current = 0 for current, f in enumerate(feature_iterator): if feedback.isCanceled(): @@ -195,7 +228,9 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc context.expressionContext().setFeature(input_feature) new_features = alg.processFeature(input_feature, context, feedback) - new_features = QgsVectorLayerUtils.makeFeaturesCompatible(new_features, active_layer) + new_features = QgsVectorLayerUtils.makeFeaturesCompatible( + new_features, active_layer + ) if len(new_features) == 0: active_layer.deleteFeature(f.id()) @@ -204,7 +239,11 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc if not f.geometry().equals(new_f.geometry()): active_layer.changeGeometry(f.id(), new_f.geometry()) if f.attributes() != new_f.attributes(): - active_layer.changeAttributeValues(f.id(), dict(zip(field_idxs, new_f.attributes())), dict(zip(field_idxs, f.attributes()))) + active_layer.changeAttributeValues( + f.id(), + dict(zip(field_idxs, new_f.attributes())), + dict(zip(field_idxs, f.attributes())), + ) new_feature_ids.append(f.id()) else: active_layer.deleteFeature(f.id()) @@ -214,59 +253,93 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc # them to createFeatures to manage constraints correctly features_data = [] for f in new_features: - features_data.append(QgsVectorLayerUtils.QgsFeatureData(f.geometry(), dict(enumerate(f.attributes())))) - new_features = QgsVectorLayerUtils.createFeatures(active_layer, features_data, context.expressionContext()) + features_data.append( + QgsVectorLayerUtils.QgsFeatureData( + f.geometry(), dict(enumerate(f.attributes())) + ) + ) + new_features = QgsVectorLayerUtils.createFeatures( + active_layer, features_data, context.expressionContext() + ) if not active_layer.addFeatures(new_features): - raise QgsProcessingException(tr("Error adding processed features back into the layer.")) + raise QgsProcessingException( + tr("Error adding processed features back into the layer.") + ) new_ids = {f.id() for f in active_layer.getFeatures(req)} new_feature_ids += list(new_ids - old_ids) feedback.setProgress(int((current + 1) * step)) - results, ok = {'__count': current + 1}, True + results, ok = {"__count": current + 1}, True else: # Traditional 'run' with delete and add features cycle # There is no way to know if some features have been skipped # due to invalid geometries - if context.invalidGeometryCheck() == QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid: + if ( + context.invalidGeometryCheck() + == QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid + ): selected_ids = active_layer.selectedFeatureIds() else: selected_ids = [] - results, ok = alg.run(parameters, context, feedback, configuration={'IN_PLACE': True}) + results, ok = alg.run( + parameters, context, feedback, configuration={"IN_PLACE": True} + ) if ok: - result_layer = QgsProcessingUtils.mapLayerFromString(results['OUTPUT'], context) + result_layer = QgsProcessingUtils.mapLayerFromString( + results["OUTPUT"], context + ) # TODO: check if features have changed before delete/add cycle new_features = [] # Check if there are any skipped features - if context.invalidGeometryCheck() == QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid: - missing_ids = list(set(selected_ids) - set(result_layer.allFeatureIds())) + if ( + context.invalidGeometryCheck() + == QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid + ): + missing_ids = list( + set(selected_ids) - set(result_layer.allFeatureIds()) + ) if missing_ids: - for f in active_layer.getFeatures(QgsFeatureRequest(missing_ids)): + for f in active_layer.getFeatures( + QgsFeatureRequest(missing_ids) + ): if not f.geometry().isGeosValid(): new_features.append(f) active_layer.deleteFeatures(active_layer.selectedFeatureIds()) - regenerate_primary_key = result_layer.customProperty('OnConvertFormatRegeneratePrimaryKey', False) - sink_flags = QgsFeatureSink.SinkFlags(QgsFeatureSink.SinkFlag.RegeneratePrimaryKey) if regenerate_primary_key \ + regenerate_primary_key = result_layer.customProperty( + "OnConvertFormatRegeneratePrimaryKey", False + ) + sink_flags = ( + QgsFeatureSink.SinkFlags( + QgsFeatureSink.SinkFlag.RegeneratePrimaryKey + ) + if regenerate_primary_key else QgsFeatureSink.SinkFlags() + ) for f in result_layer.getFeatures(): - new_features.extend(QgsVectorLayerUtils. - makeFeaturesCompatible([f], active_layer, sink_flags)) + new_features.extend( + QgsVectorLayerUtils.makeFeaturesCompatible( + [f], active_layer, sink_flags + ) + ) # Get the new ids old_ids = {f.id() for f in active_layer.getFeatures(req)} if not active_layer.addFeatures(new_features): - raise QgsProcessingException(tr("Error adding processed features back into the layer.")) + raise QgsProcessingException( + tr("Error adding processed features back into the layer.") + ) new_ids = {f.id() for f in active_layer.getFeatures(req)} new_feature_ids += list(new_ids - old_ids) - results['__count'] = len(new_feature_ids) + results["__count"] = len(new_feature_ids) active_layer.endEditCommand() @@ -282,9 +355,11 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc active_layer.rollBack() if raise_exceptions: raise e - QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing', Qgis.MessageLevel.Critical) + QgsMessageLog.logMessage( + str(sys.exc_info()[0]), "Processing", Qgis.MessageLevel.Critical + ) if feedback is not None: - feedback.reportError(getattr(e, 'msg', str(e)), fatalError=True) + feedback.reportError(getattr(e, "msg", str(e)), fatalError=True) return False, {} @@ -312,19 +387,35 @@ def execute_in_place(alg, parameters, context=None, feedback=None): if context is None: context = dataobjects.createContext(feedback) - in_place_input_parameter_name = 'INPUT' - if hasattr(alg, 'inputParameterName'): + in_place_input_parameter_name = "INPUT" + if hasattr(alg, "inputParameterName"): in_place_input_parameter_name = alg.inputParameterName() - in_place_input_layer_name = 'INPUT' - if hasattr(alg, 'inputParameterDescription'): + in_place_input_layer_name = "INPUT" + if hasattr(alg, "inputParameterDescription"): in_place_input_layer_name = alg.inputParameterDescription() - if in_place_input_parameter_name not in parameters or not parameters[in_place_input_parameter_name]: + if ( + in_place_input_parameter_name not in parameters + or not parameters[in_place_input_parameter_name] + ): parameters[in_place_input_parameter_name] = iface.activeLayer() - ok, results = execute_in_place_run(alg, parameters, context=context, feedback=feedback) + ok, results = execute_in_place_run( + alg, parameters, context=context, feedback=feedback + ) if ok: - if isinstance(parameters[in_place_input_parameter_name], QgsProcessingFeatureSourceDefinition): - layer = alg.parameterAsVectorLayer({in_place_input_parameter_name: parameters[in_place_input_parameter_name].source}, in_place_input_layer_name, context) + if isinstance( + parameters[in_place_input_parameter_name], + QgsProcessingFeatureSourceDefinition, + ): + layer = alg.parameterAsVectorLayer( + { + in_place_input_parameter_name: parameters[ + in_place_input_parameter_name + ].source + }, + in_place_input_layer_name, + context, + ) elif isinstance(parameters[in_place_input_parameter_name], QgsVectorLayer): layer = parameters[in_place_input_parameter_name] if layer: @@ -338,7 +429,9 @@ def executeIterating(alg, parameters, paramToIter, context, feedback): if not parameter_definition: return False - iter_source = QgsProcessingParameters.parameterAsSource(parameter_definition, parameters, context) + iter_source = QgsProcessingParameters.parameterAsSource( + parameter_definition, parameters, context + ) sink_list = [] if iter_source.featureCount() == 0: return False @@ -348,7 +441,13 @@ def executeIterating(alg, parameters, paramToIter, context, feedback): if feedback.isCanceled(): return False - sink, sink_id = QgsProcessingUtils.createFeatureSink('memory:', context, iter_source.fields(), iter_source.wkbType(), iter_source.sourceCrs()) + sink, sink_id = QgsProcessingUtils.createFeatureSink( + "memory:", + context, + iter_source.fields(), + iter_source.wkbType(), + iter_source.sourceCrs(), + ) sink_list.append(sink_id) sink.addFeature(feat, QgsFeatureSink.Flag.FastInsert) del sink @@ -372,8 +471,14 @@ def executeIterating(alg, parameters, paramToIter, context, feedback): continue o = outputs[out.name()] - parameters[out.name()] = QgsProcessingUtils.generateIteratingDestination(o, i, context) - feedback.setProgressText(QCoreApplication.translate('AlgorithmExecutor', 'Executing iteration {0}/{1}…').format(i + 1, len(sink_list))) + parameters[out.name()] = QgsProcessingUtils.generateIteratingDestination( + o, i, context + ) + feedback.setProgressText( + QCoreApplication.translate( + "AlgorithmExecutor", "Executing iteration {0}/{1}…" + ).format(i + 1, len(sink_list)) + ) feedback.setProgress(int((i + 1) * 100 / len(sink_list))) ret, results = execute(alg, parameters, context, feedback) if not ret: @@ -383,7 +488,7 @@ def executeIterating(alg, parameters, paramToIter, context, feedback): return True -def tr(string, context=''): - if context == '': - context = 'AlgorithmExecutor' +def tr(string, context=""): + if context == "": + context = "AlgorithmExecutor" return QCoreApplication.translate(context, string) diff --git a/python/plugins/processing/gui/AlgorithmLocatorFilter.py b/python/plugins/processing/gui/AlgorithmLocatorFilter.py index 4fe3979fe594..a2791df3ab32 100644 --- a/python/plugins/processing/gui/AlgorithmLocatorFilter.py +++ b/python/plugins/processing/gui/AlgorithmLocatorFilter.py @@ -15,20 +15,22 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'May 2017' -__copyright__ = '(C) 2017, Nyall Dawson' - -from qgis.core import (QgsApplication, - QgsProcessingAlgorithm, - QgsProcessingFeatureBasedAlgorithm, - QgsLocatorFilter, - QgsLocatorResult, - QgsProcessing, - QgsWkbTypes, - QgsMapLayerType, - QgsFields, - QgsStringUtils) +__author__ = "Nyall Dawson" +__date__ = "May 2017" +__copyright__ = "(C) 2017, Nyall Dawson" + +from qgis.core import ( + QgsApplication, + QgsProcessingAlgorithm, + QgsProcessingFeatureBasedAlgorithm, + QgsLocatorFilter, + QgsLocatorResult, + QgsProcessing, + QgsWkbTypes, + QgsMapLayerType, + QgsFields, + QgsStringUtils, +) from processing.gui.MessageBarProgress import MessageBarProgress from processing.gui.MessageDialog import MessageDialog from processing.gui.AlgorithmDialog import AlgorithmDialog @@ -46,16 +48,16 @@ def clone(self): return AlgorithmLocatorFilter() def name(self): - return 'processing_alg' + return "processing_alg" def displayName(self): - return self.tr('Processing Algorithms') + return self.tr("Processing Algorithms") def priority(self): return QgsLocatorFilter.Priority.Low def prefix(self): - return 'a' + return "a" def flags(self): return QgsLocatorFilter.Flag.FlagFast @@ -66,8 +68,12 @@ def fetchResults(self, string, context, feedback): for a in QgsApplication.processingRegistry().algorithms(): if a.flags() & QgsProcessingAlgorithm.Flag.FlagHideFromToolbox: continue - if not ProcessingConfig.getSetting(ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES) and \ - a.flags() & QgsProcessingAlgorithm.Flag.FlagKnownIssues: + if ( + not ProcessingConfig.getSetting( + ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES + ) + and a.flags() & QgsProcessingAlgorithm.Flag.FlagKnownIssues + ): continue result = QgsLocatorResult() @@ -77,7 +83,7 @@ def fetchResults(self, string, context, feedback): result.userData = a.id() result.score = 0 - if (context.usingPrefix and not string): + if context.usingPrefix and not string: self.resultFetched.emit(result) if not string: @@ -98,7 +104,10 @@ def fetchResults(self, string, context, feedback): tagScore = 1 break - result.score = QgsStringUtils.fuzzyScore(result.displayString, string) * 0.5 + tagScore * 0.5 + result.score = ( + QgsStringUtils.fuzzyScore(result.displayString, string) * 0.5 + + tagScore * 0.5 + ) if result.score > 0: self.resultFetched.emit(result) @@ -109,7 +118,7 @@ def triggerResult(self, result): ok, message = alg.canExecute() if not ok: dlg = MessageDialog() - dlg.setTitle(self.tr('Missing dependency')) + dlg.setTitle(self.tr("Missing dependency")) dlg.setMessage(message) dlg.exec() return @@ -140,16 +149,16 @@ def clone(self): return InPlaceAlgorithmLocatorFilter() def name(self): - return 'edit_features' + return "edit_features" def displayName(self): - return self.tr('Edit Selected Features') + return self.tr("Edit Selected Features") def priority(self): return QgsLocatorFilter.Priority.Low def prefix(self): - return 'ef' + return "ef" def flags(self): return QgsLocatorFilter.Flag.FlagFast @@ -158,7 +167,10 @@ def fetchResults(self, string, context, feedback): # collect results in main thread, since this method is inexpensive and # accessing the processing registry/current layer is not thread safe - if iface.activeLayer() is None or iface.activeLayer().type() != QgsMapLayerType.VectorLayer: + if ( + iface.activeLayer() is None + or iface.activeLayer().type() != QgsMapLayerType.VectorLayer + ): return for a in QgsApplication.processingRegistry().algorithms(): @@ -175,7 +187,7 @@ def fetchResults(self, string, context, feedback): result.userData = a.id() result.score = 0 - if (context.usingPrefix and not string): + if context.usingPrefix and not string: self.resultFetched.emit(result) if not string: @@ -196,29 +208,37 @@ def fetchResults(self, string, context, feedback): tagScore = 1 break - result.score = QgsStringUtils.fuzzyScore(result.displayString, string) * 0.5 + tagScore * 0.5 + result.score = ( + QgsStringUtils.fuzzyScore(result.displayString, string) * 0.5 + + tagScore * 0.5 + ) if result.score > 0: self.resultFetched.emit(result) def triggerResult(self, result): - config = {'IN_PLACE': True} - alg = QgsApplication.processingRegistry().createAlgorithmById(result.userData, config) + config = {"IN_PLACE": True} + alg = QgsApplication.processingRegistry().createAlgorithmById( + result.userData, config + ) if alg: ok, message = alg.canExecute() if not ok: dlg = MessageDialog() - dlg.setTitle(self.tr('Missing dependency')) + dlg.setTitle(self.tr("Missing dependency")) dlg.setMessage(message) dlg.exec() return - in_place_input_parameter_name = 'INPUT' - if hasattr(alg, 'inputParameterName'): + in_place_input_parameter_name = "INPUT" + if hasattr(alg, "inputParameterName"): in_place_input_parameter_name = alg.inputParameterName() - if [d for d in alg.parameterDefinitions() if - d.name() not in (in_place_input_parameter_name, 'OUTPUT')]: + if [ + d + for d in alg.parameterDefinitions() + if d.name() not in (in_place_input_parameter_name, "OUTPUT") + ]: dlg = alg.createCustomParametersWidget(parent=iface.mainWindow()) if not dlg: dlg = AlgorithmDialog(alg, True, parent=iface.mainWindow()) diff --git a/python/plugins/processing/gui/AutofillDialog.py b/python/plugins/processing/gui/AutofillDialog.py index 2a02abd53c48..c5a3e0b1c717 100644 --- a/python/plugins/processing/gui/AutofillDialog.py +++ b/python/plugins/processing/gui/AutofillDialog.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import warnings @@ -29,8 +29,7 @@ with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) - WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'DlgAutofill.ui')) + WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "ui", "DlgAutofill.ui")) class AutofillDialog(BASE, WIDGET): diff --git a/python/plugins/processing/gui/BatchAlgorithmDialog.py b/python/plugins/processing/gui/BatchAlgorithmDialog.py index c7988ff52d7c..42b66630a672 100644 --- a/python/plugins/processing/gui/BatchAlgorithmDialog.py +++ b/python/plugins/processing/gui/BatchAlgorithmDialog.py @@ -15,18 +15,20 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import codecs import time -from qgis.core import (QgsProcessingOutputHtml, - QgsProcessingOutputNumber, - QgsProcessingOutputString, - QgsProcessingOutputBoolean, - QgsProject) +from qgis.core import ( + QgsProcessingOutputHtml, + QgsProcessingOutputNumber, + QgsProcessingOutputString, + QgsProcessingOutputBoolean, + QgsProject, +) from qgis.gui import QgsProcessingBatchAlgorithmDialogBase from qgis.utils import iface @@ -44,7 +46,9 @@ def __init__(self, alg, parent=None): self.setAlgorithm(alg) - self.setWindowTitle(self.tr('Batch Processing - {0}').format(self.algorithm().displayName())) + self.setWindowTitle( + self.tr("Batch Processing - {0}").format(self.algorithm().displayName()) + ) self.setMainWidget(BatchPanel(self, self.algorithm())) self.context = None @@ -54,6 +58,7 @@ def runAsSingle(self): self.close() from processing.gui.AlgorithmDialog import AlgorithmDialog + dlg = AlgorithmDialog(self.algorithm().create(), parent=iface.mainWindow()) dlg.show() dlg.exec() @@ -79,7 +84,8 @@ def runAlgorithm(self): row=row, context=self.processingContext(), destinationProject=project, - warnOnInvalid=True) + warnOnInvalid=True, + ) if ok: alg_parameters.append(parameters) if not alg_parameters: @@ -92,61 +98,84 @@ def handleAlgorithmResults(self, algorithm, context, feedback, parameters): def loadHtmlResults(self, results, num): for out in self.algorithm().outputDefinitions(): - if isinstance(out, QgsProcessingOutputHtml) and out.name() in results and results[out.name()]: - resultsList.addResult(icon=self.algorithm().icon(), name=f'{out.description()} [{num}]', - result=results[out.name()]) + if ( + isinstance(out, QgsProcessingOutputHtml) + and out.name() in results + and results[out.name()] + ): + resultsList.addResult( + icon=self.algorithm().icon(), + name=f"{out.description()} [{num}]", + result=results[out.name()], + ) def createSummaryTable(self, algorithm_results, errors): createTable = False for out in self.algorithm().outputDefinitions(): - if isinstance(out, (QgsProcessingOutputNumber, QgsProcessingOutputString, QgsProcessingOutputBoolean)): + if isinstance( + out, + ( + QgsProcessingOutputNumber, + QgsProcessingOutputString, + QgsProcessingOutputBoolean, + ), + ): createTable = True break if not createTable and not errors: return - outputFile = getTempFilename('html') - with codecs.open(outputFile, 'w', encoding='utf-8') as f: + outputFile = getTempFilename("html") + with codecs.open(outputFile, "w", encoding="utf-8") as f: if createTable: for i, res in enumerate(algorithm_results): - results = res['results'] - params = res['parameters'] + results = res["results"] + params = res["parameters"] if i > 0: - f.write('
\n') - f.write(self.tr('

Parameters

\n')) - f.write('\n') + f.write("
\n") + f.write(self.tr("

Parameters

\n")) + f.write("
\n") for param in self.algorithm().parameterDefinitions(): if not param.isDestination(): if param.name() in params: - f.write('\n'.format(param.description(), - params[param.name()])) - f.write('
{}{}
\n') - f.write(self.tr('

Results

\n')) - f.write('\n') + f.write( + "\n".format( + param.description(), params[param.name()] + ) + ) + f.write("
{}{}
\n") + f.write(self.tr("

Results

\n")) + f.write("\n") for out in self.algorithm().outputDefinitions(): if out.name() in results: - f.write(f'\n') - f.write('
{out.description()}{results[out.name()]}
\n') + f.write( + f"{out.description()}{results[out.name()]}\n" + ) + f.write("\n") if errors: - f.write('

{}

\n'.format(self.tr('Errors'))) + f.write('

{}

\n'.format(self.tr("Errors"))) for i, res in enumerate(errors): - errors = res['errors'] - params = res['parameters'] + errors = res["errors"] + params = res["parameters"] if i > 0: - f.write('
\n') - f.write(self.tr('

Parameters

\n')) - f.write('\n') + f.write("
\n") + f.write(self.tr("

Parameters

\n")) + f.write("
\n") for param in self.algorithm().parameterDefinitions(): if not param.isDestination(): if param.name() in params: f.write( - f'\n') - f.write('
{param.description()}{params[param.name()]}
\n') - f.write('

{}

\n'.format(self.tr('Error'))) - f.write('

{}

\n'.format('
'.join(errors))) - - resultsList.addResult(icon=self.algorithm().icon(), - name=f'{self.algorithm().name()} [summary]', timestamp=time.localtime(), - result=outputFile) + f"{param.description()}{params[param.name()]}\n" + ) + f.write("\n") + f.write("

{}

\n".format(self.tr("Error"))) + f.write('

{}

\n'.format("
".join(errors))) + + resultsList.addResult( + icon=self.algorithm().icon(), + name=f"{self.algorithm().name()} [summary]", + timestamp=time.localtime(), + result=outputFile, + ) diff --git a/python/plugins/processing/gui/BatchInputSelectionPanel.py b/python/plugins/processing/gui/BatchInputSelectionPanel.py index 6d8d849c4fe4..ef6c62fde695 100644 --- a/python/plugins/processing/gui/BatchInputSelectionPanel.py +++ b/python/plugins/processing/gui/BatchInputSelectionPanel.py @@ -15,30 +15,41 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os from pathlib import Path from qgis.PyQt.QtCore import pyqtSignal, QCoreApplication -from qgis.PyQt.QtWidgets import QWidget, QHBoxLayout, QMenu, QPushButton, QLineEdit, QSizePolicy, QAction, QFileDialog +from qgis.PyQt.QtWidgets import ( + QWidget, + QHBoxLayout, + QMenu, + QPushButton, + QLineEdit, + QSizePolicy, + QAction, + QFileDialog, +) from qgis.PyQt.QtGui import QCursor -from qgis.core import (QgsMapLayer, - QgsRasterLayer, - QgsSettings, - QgsProject, - QgsProcessing, - QgsProcessingUtils, - QgsProcessingParameterMultipleLayers, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterMeshLayer, - QgsProcessingParameterPointCloudLayer, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterMapLayer) +from qgis.core import ( + QgsMapLayer, + QgsRasterLayer, + QgsSettings, + QgsProject, + QgsProcessing, + QgsProcessingUtils, + QgsProcessingParameterMultipleLayers, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterMeshLayer, + QgsProcessingParameterPointCloudLayer, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterMapLayer, +) from processing.gui.MultipleInputDialog import MultipleInputDialog @@ -58,15 +69,16 @@ def __init__(self, param, row, col, dialog): self.horizontalLayout.setSpacing(0) self.horizontalLayout.setMargin(0) self.text = QLineEdit() - self.text.setObjectName('text') + self.text.setObjectName("text") self.text.setMinimumWidth(300) - self.setValue('') + self.setValue("") self.text.editingFinished.connect(self.textEditingFinished) - self.text.setSizePolicy(QSizePolicy.Policy.Expanding, - QSizePolicy.Policy.Expanding) + self.text.setSizePolicy( + QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding + ) self.horizontalLayout.addWidget(self.text) self.pushButton = QPushButton() - self.pushButton.setText('…') + self.pushButton.setText("…") self.pushButton.clicked.connect(self.showPopupMenu) self.horizontalLayout.addWidget(self.pushButton) self.setLayout(self.horizontalLayout) @@ -80,20 +92,30 @@ def _table(self): def showPopupMenu(self): popupmenu = QMenu() - if not (isinstance(self.param, QgsProcessingParameterMultipleLayers) - and self.param.layerType == dataobjects.TYPE_FILE): + if not ( + isinstance(self.param, QgsProcessingParameterMultipleLayers) + and self.param.layerType == dataobjects.TYPE_FILE + ): selectLayerAction = QAction( - QCoreApplication.translate('BatchInputSelectionPanel', 'Select from Open Layers…'), self.pushButton) + QCoreApplication.translate( + "BatchInputSelectionPanel", "Select from Open Layers…" + ), + self.pushButton, + ) selectLayerAction.triggered.connect(self.showLayerSelectionDialog) popupmenu.addAction(selectLayerAction) selectFileAction = QAction( - QCoreApplication.translate('BatchInputSelectionPanel', 'Select Files…'), self.pushButton) + QCoreApplication.translate("BatchInputSelectionPanel", "Select Files…"), + self.pushButton, + ) selectFileAction.triggered.connect(self.showFileSelectionDialog) popupmenu.addAction(selectFileAction) selectDirectoryAction = QAction( - QCoreApplication.translate('BatchInputSelectionPanel', 'Select Directory…'), self.pushButton) + QCoreApplication.translate("BatchInputSelectionPanel", "Select Directory…"), + self.pushButton, + ) selectDirectoryAction.triggered.connect(self.showDirectorySelectionDialog) popupmenu.addAction(selectDirectoryAction) @@ -101,22 +123,27 @@ def showPopupMenu(self): def showLayerSelectionDialog(self): layers = [] - if (isinstance(self.param, QgsProcessingParameterRasterLayer) - or (isinstance(self.param, QgsProcessingParameterMultipleLayers) and - self.param.layerType() == QgsProcessing.SourceType.TypeRaster)): + if isinstance(self.param, QgsProcessingParameterRasterLayer) or ( + isinstance(self.param, QgsProcessingParameterMultipleLayers) + and self.param.layerType() == QgsProcessing.SourceType.TypeRaster + ): layers = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance()) elif isinstance(self.param, QgsProcessingParameterVectorLayer): layers = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance()) elif isinstance(self.param, QgsProcessingParameterMapLayer): layers = QgsProcessingUtils.compatibleLayers(QgsProject.instance()) - elif (isinstance(self.param, QgsProcessingParameterMeshLayer) - or (isinstance(self.param, QgsProcessingParameterMultipleLayers) and - self.param.layerType() == QgsProcessing.SourceType.TypeMesh)): + elif isinstance(self.param, QgsProcessingParameterMeshLayer) or ( + isinstance(self.param, QgsProcessingParameterMultipleLayers) + and self.param.layerType() == QgsProcessing.SourceType.TypeMesh + ): layers = QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance()) - elif (isinstance(self.param, QgsProcessingParameterPointCloudLayer) - or (isinstance(self.param, QgsProcessingParameterMultipleLayers) and - self.param.layerType() == QgsProcessing.SourceType.TypePointCloud)): - layers = QgsProcessingUtils.compatiblePointCloudLayers(QgsProject.instance()) + elif isinstance(self.param, QgsProcessingParameterPointCloudLayer) or ( + isinstance(self.param, QgsProcessingParameterMultipleLayers) + and self.param.layerType() == QgsProcessing.SourceType.TypePointCloud + ): + layers = QgsProcessingUtils.compatiblePointCloudLayers( + QgsProject.instance() + ) else: datatypes = [QgsProcessing.SourceType.TypeVectorAnyGeometry] if isinstance(self.param, QgsProcessingParameterFeatureSource): @@ -125,16 +152,23 @@ def showLayerSelectionDialog(self): datatypes = [self.param.layerType()] if QgsProcessing.SourceType.TypeVectorAnyGeometry not in datatypes: - layers = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), datatypes) + layers = QgsProcessingUtils.compatibleVectorLayers( + QgsProject.instance(), datatypes + ) else: - layers = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance()) + layers = QgsProcessingUtils.compatibleVectorLayers( + QgsProject.instance() + ) dlg = MultipleInputDialog([layer.name() for layer in layers]) dlg.exec() def generate_layer_id(layer): # prefer layer name if unique - if len([l for l in layers if l.name().lower() == layer.name().lower()]) == 1: + if ( + len([l for l in layers if l.name().lower() == layer.name().lower()]) + == 1 + ): return layer.name() else: # otherwise fall back to layer id @@ -146,14 +180,15 @@ def generate_layer_id(layer): self.setValue(generate_layer_id(layers[selected[0]])) else: if isinstance(self.param, QgsProcessingParameterMultipleLayers): - self.text.setText(';'.join(layers[idx].id() for idx in selected)) + self.text.setText(";".join(layers[idx].id() for idx in selected)) else: rowdif = len(selected) - (self._table().rowCount() - self.row) for i in range(rowdif): self._panel().addRow() for i, layeridx in enumerate(selected): - self._table().cellWidget(i + self.row, - self.col).setValue(generate_layer_id(layers[layeridx])) + self._table().cellWidget(i + self.row, self.col).setValue( + generate_layer_id(layers[layeridx]) + ) def showFileSelectionDialog(self): self.showFileDialog(seldir=False) @@ -168,21 +203,23 @@ def showFileDialog(self, seldir): path = text elif not seldir and os.path.isdir(os.path.dirname(text)): path = os.path.dirname(text) - elif settings.contains('/Processing/LastInputPath'): - path = str(settings.value('/Processing/LastInputPath')) + elif settings.contains("/Processing/LastInputPath"): + path = str(settings.value("/Processing/LastInputPath")) else: - path = '' + path = "" if not seldir: ret, selected_filter = QFileDialog.getOpenFileNames( - self, self.tr('Select Files'), path, self.param.createFileFilter() + self, self.tr("Select Files"), path, self.param.createFileFilter() ) else: - ret = QFileDialog.getExistingDirectory(self, self.tr('Select Directory'), path) + ret = QFileDialog.getExistingDirectory( + self, self.tr("Select Directory"), path + ) if ret: if seldir: - settings.setValue('/Processing/LastInputPath', ret) + settings.setValue("/Processing/LastInputPath", ret) files = [] for pp in Path(ret).rglob("*"): @@ -191,9 +228,14 @@ def showFileDialog(self, seldir): p = pp.as_posix() - if ((isinstance(self.param, QgsProcessingParameterRasterLayer) - or (isinstance(self.param, QgsProcessingParameterMultipleLayers) and self.param.layerType() == QgsProcessing.SourceType.TypeRaster)) and - not QgsRasterLayer.isValidRasterFileName(p)): + if ( + isinstance(self.param, QgsProcessingParameterRasterLayer) + or ( + isinstance(self.param, QgsProcessingParameterMultipleLayers) + and self.param.layerType() + == QgsProcessing.SourceType.TypeRaster + ) + ) and not QgsRasterLayer.isValidRasterFileName(p): continue files.append(p) @@ -203,7 +245,9 @@ def showFileDialog(self, seldir): else: files = list(ret) - settings.setValue('/Processing/LastInputPath', os.path.dirname(str(files[0]))) + settings.setValue( + "/Processing/LastInputPath", os.path.dirname(str(files[0])) + ) for i, filename in enumerate(files): files[i] = dataobjects.getRasterSublayer(filename, self.param) @@ -212,14 +256,13 @@ def showFileDialog(self, seldir): self.textEditingFinished() else: if isinstance(self.param, QgsProcessingParameterMultipleLayers): - self.text.setText(';'.join(str(f) for f in files)) + self.text.setText(";".join(str(f) for f in files)) else: rowdif = len(files) - (self._table().rowCount() - self.row) for i in range(rowdif): self._panel().addRow() for i, f in enumerate(files): - self._table().cellWidget(i + self.row, - self.col).setValue(f) + self._table().cellWidget(i + self.row, self.col).setValue(f) def textEditingFinished(self): self._value = self.text.text() diff --git a/python/plugins/processing/gui/BatchOutputSelectionPanel.py b/python/plugins/processing/gui/BatchOutputSelectionPanel.py index bf68ef455840..3ea50265a597 100644 --- a/python/plugins/processing/gui/BatchOutputSelectionPanel.py +++ b/python/plugins/processing/gui/BatchOutputSelectionPanel.py @@ -15,26 +15,35 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import re -from qgis.core import (QgsMapLayer, - QgsSettings, - QgsProcessingParameterFolderDestination, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterMultipleLayers, - QgsProcessingParameterMapLayer, - QgsProcessingParameterBoolean, - QgsProcessingParameterEnum, - QgsProject, - QgsProcessingParameterMatrix) -from qgis.PyQt.QtWidgets import QWidget, QPushButton, QLineEdit, QHBoxLayout, QSizePolicy, QFileDialog +from qgis.core import ( + QgsMapLayer, + QgsSettings, + QgsProcessingParameterFolderDestination, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterMultipleLayers, + QgsProcessingParameterMapLayer, + QgsProcessingParameterBoolean, + QgsProcessingParameterEnum, + QgsProject, + QgsProcessingParameterMatrix, +) +from qgis.PyQt.QtWidgets import ( + QWidget, + QPushButton, + QLineEdit, + QHBoxLayout, + QSizePolicy, + QFileDialog, +) from processing.gui.AutofillDialog import AutofillDialog @@ -53,13 +62,14 @@ def __init__(self, output, alg, row, col, panel): self.horizontalLayout.setSpacing(2) self.horizontalLayout.setMargin(0) self.text = QLineEdit() - self.text.setText('') + self.text.setText("") self.text.setMinimumWidth(300) - self.text.setSizePolicy(QSizePolicy.Policy.Expanding, - QSizePolicy.Policy.Expanding) + self.text.setSizePolicy( + QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding + ) self.horizontalLayout.addWidget(self.text) self.pushButton = QPushButton() - self.pushButton.setText('…') + self.pushButton.setText("…") self.pushButton.clicked.connect(self.showSelectionDialog) self.horizontalLayout.addWidget(self.pushButton) self.setLayout(self.horizontalLayout) @@ -71,48 +81,70 @@ def showSelectionDialog(self): filefilter = self.output.createFileFilter() settings = QgsSettings() - if settings.contains('/Processing/LastBatchOutputPath'): - path = str(settings.value('/Processing/LastBatchOutputPath')) + if settings.contains("/Processing/LastBatchOutputPath"): + path = str(settings.value("/Processing/LastBatchOutputPath")) else: - path = '' - filename, selectedFileFilter = QFileDialog.getSaveFileName(self, - self.tr('Save File'), path, filefilter) + path = "" + filename, selectedFileFilter = QFileDialog.getSaveFileName( + self, self.tr("Save File"), path, filefilter + ) if filename: if not filename.lower().endswith( - tuple(re.findall("\\*(\\.[a-z]{1,10})", filefilter))): + tuple(re.findall("\\*(\\.[a-z]{1,10})", filefilter)) + ): ext = re.search("\\*(\\.[a-z]{1,10})", selectedFileFilter) if ext: filename += ext.group(1) - settings.setValue('/Processing/LastBatchOutputPath', os.path.dirname(filename)) + settings.setValue( + "/Processing/LastBatchOutputPath", os.path.dirname(filename) + ) dlg = AutofillDialog(self.alg) dlg.exec() if dlg.mode is not None: if dlg.mode == AutofillDialog.DO_NOT_AUTOFILL: - self.table.cellWidget(self.row, - self.col).setValue(filename) + self.table.cellWidget(self.row, self.col).setValue(filename) elif dlg.mode == AutofillDialog.FILL_WITH_NUMBERS: n = self.table.rowCount() - self.row for i in range(n): - name = filename[:filename.rfind('.')] \ - + str(i + 1) + filename[filename.rfind('.'):] - self.table.cellWidget(i + self.row, - self.col).setValue(name) + name = ( + filename[: filename.rfind(".")] + + str(i + 1) + + filename[filename.rfind(".") :] + ) + self.table.cellWidget(i + self.row, self.col).setValue(name) elif dlg.mode == AutofillDialog.FILL_WITH_PARAMETER: for row in range(self.row, self.table.rowCount()): v = self.panel.valueForParameter(row - 1, dlg.param_name) param = self.alg.parameterDefinition(dlg.param_name) - if isinstance(param, (QgsProcessingParameterRasterLayer, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterMultipleLayers, - QgsProcessingParameterMapLayer)): + if isinstance( + param, + ( + QgsProcessingParameterRasterLayer, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterMultipleLayers, + QgsProcessingParameterMapLayer, + ), + ): if isinstance(v, QgsMapLayer): s = v.name() else: if v in QgsProject.instance().mapLayers(): layer = QgsProject.instance().mapLayer(v) # value is a layer ID, but we'd prefer to show a layer name if it's unique in the project - if len([l for _, l in QgsProject.instance().mapLayers().items() if l.name().lower() == layer.name().lower()]) == 1: + if ( + len( + [ + l + for _, l in QgsProject.instance() + .mapLayers() + .items() + if l.name().lower() + == layer.name().lower() + ] + ) + == 1 + ): s = layer.name() else: # otherwise fall back to layer id @@ -123,30 +155,33 @@ def showSelectionDialog(self): s = os.path.basename(v) s = os.path.splitext(s)[0] elif isinstance(param, QgsProcessingParameterBoolean): - s = 'true' if v else 'false' + s = "true" if v else "false" elif isinstance(param, QgsProcessingParameterEnum): s = param.options()[v] else: s = str(v) - name = filename[:filename.rfind('.')] + s \ - + filename[filename.rfind('.'):] - self.table.cellWidget(row, - self.col).setValue(name) + name = ( + filename[: filename.rfind(".")] + + s + + filename[filename.rfind(".") :] + ) + self.table.cellWidget(row, self.col).setValue(name) def selectDirectory(self): settings = QgsSettings() - if settings.contains('/Processing/LastBatchOutputPath'): - lastDir = str(settings.value('/Processing/LastBatchOutputPath')) + if settings.contains("/Processing/LastBatchOutputPath"): + lastDir = str(settings.value("/Processing/LastBatchOutputPath")) else: - lastDir = '' + lastDir = "" - dirName = QFileDialog.getExistingDirectory(self, - self.tr('Output Directory'), lastDir, QFileDialog.Option.ShowDirsOnly) + dirName = QFileDialog.getExistingDirectory( + self, self.tr("Output Directory"), lastDir, QFileDialog.Option.ShowDirsOnly + ) if dirName: self.table.cellWidget(self.row, self.col).setValue(dirName) - settings.setValue('/Processing/LastBatchOutputPath', dirName) + settings.setValue("/Processing/LastBatchOutputPath", dirName) def setValue(self, text): return self.text.setText(text) diff --git a/python/plugins/processing/gui/BatchPanel.py b/python/plugins/processing/gui/BatchPanel.py index b3e66e6f42ae..d6b75923543a 100644 --- a/python/plugins/processing/gui/BatchPanel.py +++ b/python/plugins/processing/gui/BatchPanel.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'November 2014' -__copyright__ = '(C) 2014, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "November 2014" +__copyright__ = "(C) 2014, Alexander Bruy" import os import json @@ -34,7 +34,7 @@ QMessageBox, QToolButton, QMenu, - QAction + QAction, ) # adding to this list? also update the QgsProcessingHistoryProvider executeAlgorithm imports!! @@ -42,18 +42,14 @@ from qgis.PyQt.QtCore import ( QTime, # NOQA - must be here for saved file evaluation QDate, # NOQA - must be here for saved file evaluation - QDateTime # NOQA - must be here for saved file evaluation + QDateTime, # NOQA - must be here for saved file evaluation ) from qgis.PyQt.QtGui import ( QPalette, QColor, # NOQA - must be here for saved file evaluation ) -from qgis.PyQt.QtCore import ( - QDir, - QFileInfo, - QCoreApplication -) +from qgis.PyQt.QtCore import QDir, QFileInfo, QCoreApplication from qgis.core import ( Qgis, QgsApplication, @@ -84,14 +80,14 @@ QgsProcessingUtils, QgsFileFilterGenerator, QgsProcessingContext, - QgsFileUtils + QgsFileUtils, ) from qgis.gui import ( QgsProcessingParameterWidgetContext, QgsProcessingContextGenerator, QgsFindFilesByPatternDialog, QgsExpressionBuilderDialog, - QgsPanelWidget + QgsPanelWidget, ) from qgis.utils import iface @@ -106,8 +102,7 @@ with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) - WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'widgetBatchPanel.ui')) + WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "ui", "widgetBatchPanel.ui")) class BatchPanelFillWidget(QToolButton): @@ -122,7 +117,7 @@ def __init__(self, parameterDefinition, column, panel, parent=None): self.column = column self.panel = panel - self.setText(QCoreApplication.translate('BatchPanel', 'Autofill…')) + self.setText(QCoreApplication.translate("BatchPanel", "Autofill…")) f = self.font() f.setItalic(True) self.setFont(f) @@ -137,45 +132,73 @@ def createMenu(self): self.menu.clear() self.menu.setMinimumWidth(self.width()) - fill_down_action = QAction(self.tr('Fill Down'), self.menu) + fill_down_action = QAction(self.tr("Fill Down"), self.menu) fill_down_action.triggered.connect(self.fillDown) - fill_down_action.setToolTip(self.tr('Copy the first value down to all other rows')) + fill_down_action.setToolTip( + self.tr("Copy the first value down to all other rows") + ) self.menu.addAction(fill_down_action) - calculate_by_expression = QAction(QCoreApplication.translate('BatchPanel', 'Calculate by Expression…'), - self.menu) - calculate_by_expression.setIcon(QgsApplication.getThemeIcon('/mActionCalculateField.svg')) + calculate_by_expression = QAction( + QCoreApplication.translate("BatchPanel", "Calculate by Expression…"), + self.menu, + ) + calculate_by_expression.setIcon( + QgsApplication.getThemeIcon("/mActionCalculateField.svg") + ) calculate_by_expression.triggered.connect(self.calculateByExpression) - calculate_by_expression.setToolTip(self.tr('Calculates parameter values by evaluating an expression')) + calculate_by_expression.setToolTip( + self.tr("Calculates parameter values by evaluating an expression") + ) self.menu.addAction(calculate_by_expression) - add_by_expression = QAction(QCoreApplication.translate('BatchPanel', 'Add Values by Expression…'), - self.menu) + add_by_expression = QAction( + QCoreApplication.translate("BatchPanel", "Add Values by Expression…"), + self.menu, + ) add_by_expression.triggered.connect(self.addByExpression) - add_by_expression.setToolTip(self.tr('Adds new parameter values by evaluating an expression')) + add_by_expression.setToolTip( + self.tr("Adds new parameter values by evaluating an expression") + ) self.menu.addAction(add_by_expression) - if not self.parameterDefinition.isDestination() and isinstance(self.parameterDefinition, QgsFileFilterGenerator): + if not self.parameterDefinition.isDestination() and isinstance( + self.parameterDefinition, QgsFileFilterGenerator + ): self.menu.addSeparator() - find_by_pattern_action = QAction(QCoreApplication.translate('BatchPanel', 'Add Files by Pattern…'), - self.menu) + find_by_pattern_action = QAction( + QCoreApplication.translate("BatchPanel", "Add Files by Pattern…"), + self.menu, + ) find_by_pattern_action.triggered.connect(self.addFilesByPattern) - find_by_pattern_action.setToolTip(self.tr('Adds files by a file pattern match')) + find_by_pattern_action.setToolTip( + self.tr("Adds files by a file pattern match") + ) self.menu.addAction(find_by_pattern_action) select_file_action = QAction( - QCoreApplication.translate('BatchInputSelectionPanel', 'Select Files…'), self.menu) + QCoreApplication.translate("BatchInputSelectionPanel", "Select Files…"), + self.menu, + ) select_file_action.triggered.connect(self.showFileSelectionDialog) self.menu.addAction(select_file_action) select_directory_action = QAction( - QCoreApplication.translate('BatchInputSelectionPanel', 'Add All Files from a Directory…'), self.menu) + QCoreApplication.translate( + "BatchInputSelectionPanel", "Add All Files from a Directory…" + ), + self.menu, + ) select_directory_action.triggered.connect(self.showDirectorySelectionDialog) self.menu.addAction(select_directory_action) if not isinstance(self.parameterDefinition, QgsProcessingParameterFile): select_layer_action = QAction( - QCoreApplication.translate('BatchInputSelectionPanel', 'Select from Open Layers…'), self.menu) + QCoreApplication.translate( + "BatchInputSelectionPanel", "Select from Open Layers…" + ), + self.menu, + ) select_layer_action.triggered.connect(self.showLayerSelectionDialog) self.menu.addAction(select_layer_action) @@ -219,7 +242,9 @@ def setRowValue(self, row, value, context): wrapper = self.panel.wrappers[row][self.column] if wrapper is None: # e.g. destination header - self.panel.tblParameters.cellWidget(row + 1, self.column).setValue(str(value)) + self.panel.tblParameters.cellWidget(row + 1, self.column).setValue( + str(value) + ) else: wrapper.setParameterValue(value, context) @@ -241,19 +266,22 @@ def addFilesByPattern(self): def showFileSelectionDialog(self): settings = QgsSettings() - if settings.contains('/Processing/LastInputPath'): - path = str(settings.value('/Processing/LastInputPath')) + if settings.contains("/Processing/LastInputPath"): + path = str(settings.value("/Processing/LastInputPath")) else: path = QDir.homePath() files, selected_filter = QFileDialog.getOpenFileNames( - self, self.tr('Select Files'), path, self.parameterDefinition.createFileFilter() + self, + self.tr("Select Files"), + path, + self.parameterDefinition.createFileFilter(), ) if not files: return - settings.setValue('/Processing/LastInputPath', os.path.dirname(str(files[0]))) + settings.setValue("/Processing/LastInputPath", os.path.dirname(str(files[0]))) context = dataobjects.createContext() @@ -265,16 +293,18 @@ def showFileSelectionDialog(self): def showDirectorySelectionDialog(self): settings = QgsSettings() - if settings.contains('/Processing/LastInputPath'): - path = str(settings.value('/Processing/LastInputPath')) + if settings.contains("/Processing/LastInputPath"): + path = str(settings.value("/Processing/LastInputPath")) else: path = QDir.homePath() - folder = QFileDialog.getExistingDirectory(self, self.tr('Select Directory'), path) + folder = QFileDialog.getExistingDirectory( + self, self.tr("Select Directory"), path + ) if not folder: return - settings.setValue('/Processing/LastInputPath', folder) + settings.setValue("/Processing/LastInputPath", folder) files = [] for pp in Path(folder).rglob("*"): @@ -283,9 +313,14 @@ def showDirectorySelectionDialog(self): p = pp.as_posix() - if isinstance(self.parameterDefinition, QgsProcessingParameterRasterLayer) or ( - isinstance(self.parameterDefinition, QgsProcessingParameterMultipleLayers) - and self.parameterDefinition.layerType() == QgsProcessing.SourceType.TypeRaster + if isinstance( + self.parameterDefinition, QgsProcessingParameterRasterLayer + ) or ( + isinstance( + self.parameterDefinition, QgsProcessingParameterMultipleLayers + ) + and self.parameterDefinition.layerType() + == QgsProcessing.SourceType.TypeRaster ): if not QgsRasterLayer.isValidRasterFileName(p): continue @@ -307,8 +342,11 @@ def showLayerSelectionDialog(self): layers = [] if isinstance(self.parameterDefinition, QgsProcessingParameterRasterLayer): layers = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance()) - elif isinstance(self.parameterDefinition, - QgsProcessingParameterMultipleLayers) and self.parameterDefinition.layerType() == QgsProcessing.SourceType.TypeRaster: + elif ( + isinstance(self.parameterDefinition, QgsProcessingParameterMultipleLayers) + and self.parameterDefinition.layerType() + == QgsProcessing.SourceType.TypeRaster + ): layers = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance()) elif isinstance(self.parameterDefinition, QgsProcessingParameterVectorLayer): layers = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance()) @@ -316,25 +354,45 @@ def showLayerSelectionDialog(self): layers = QgsProcessingUtils.compatibleLayers(QgsProject.instance()) elif isinstance(self.parameterDefinition, QgsProcessingParameterMeshLayer): layers = QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance()) - elif isinstance(self.parameterDefinition, - QgsProcessingParameterMultipleLayers) and self.parameterDefinition.layerType() == QgsProcessing.SourceType.TypeMesh: + elif ( + isinstance(self.parameterDefinition, QgsProcessingParameterMultipleLayers) + and self.parameterDefinition.layerType() + == QgsProcessing.SourceType.TypeMesh + ): layers = QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance()) - elif isinstance(self.parameterDefinition, QgsProcessingParameterPointCloudLayer): - layers = QgsProcessingUtils.compatiblePointCloudLayers(QgsProject.instance()) - elif isinstance(self.parameterDefinition, - QgsProcessingParameterMultipleLayers) and self.parameterDefinition.layerType() == QgsProcessing.SourceType.TypePointCloud: - layers = QgsProcessingUtils.compatiblePointCloudLayers(QgsProject.instance()) + elif isinstance( + self.parameterDefinition, QgsProcessingParameterPointCloudLayer + ): + layers = QgsProcessingUtils.compatiblePointCloudLayers( + QgsProject.instance() + ) + elif ( + isinstance(self.parameterDefinition, QgsProcessingParameterMultipleLayers) + and self.parameterDefinition.layerType() + == QgsProcessing.SourceType.TypePointCloud + ): + layers = QgsProcessingUtils.compatiblePointCloudLayers( + QgsProject.instance() + ) else: datatypes = [QgsProcessing.SourceType.TypeVectorAnyGeometry] - if isinstance(self.parameterDefinition, QgsProcessingParameterFeatureSource): + if isinstance( + self.parameterDefinition, QgsProcessingParameterFeatureSource + ): datatypes = self.parameterDefinition.dataTypes() - elif isinstance(self.parameterDefinition, QgsProcessingParameterMultipleLayers): + elif isinstance( + self.parameterDefinition, QgsProcessingParameterMultipleLayers + ): datatypes = [self.parameterDefinition.layerType()] if QgsProcessing.SourceType.TypeVectorAnyGeometry not in datatypes: - layers = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), datatypes) + layers = QgsProcessingUtils.compatibleVectorLayers( + QgsProject.instance(), datatypes + ) else: - layers = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance()) + layers = QgsProcessingUtils.compatibleVectorLayers( + QgsProject.instance() + ) dlg = MultipleInputDialog([layer.name() for layer in layers]) dlg.exec() @@ -371,29 +429,35 @@ def populateByExpression(self, adding=False): expression_context = context.expressionContext() # use the first row parameter values as a preview during expression creation - params, ok = self.panel.parametersForRow(row=0, - context=context, - warnOnInvalid=False) - alg_scope = QgsExpressionContextUtils.processingAlgorithmScope(self.panel.alg, params, context) + params, ok = self.panel.parametersForRow( + row=0, context=context, warnOnInvalid=False + ) + alg_scope = QgsExpressionContextUtils.processingAlgorithmScope( + self.panel.alg, params, context + ) # create explicit variables corresponding to every parameter for k, v in params.items(): alg_scope.setVariable(k, v, True) # add batchCount in the alg scope to be used in the expressions. 0 is only an example value - alg_scope.setVariable('row_number', 0, False) + alg_scope.setVariable("row_number", 0, False) expression_context.appendScope(alg_scope) # mark the parameter variables as highlighted for discoverability highlighted_vars = expression_context.highlightedVariables() highlighted_vars.extend(list(params.keys())) - highlighted_vars.append('row_number') + highlighted_vars.append("row_number") expression_context.setHighlightedVariables(highlighted_vars) - dlg = QgsExpressionBuilderDialog(layer=None, context=context.expressionContext()) + dlg = QgsExpressionBuilderDialog( + layer=None, context=context.expressionContext() + ) if adding: - dlg.setExpectedOutputFormat(self.tr('An array of values corresponding to each new row to add')) + dlg.setExpectedOutputFormat( + self.tr("An array of values corresponding to each new row to add") + ) if not dlg.exec(): return @@ -413,20 +477,22 @@ def populateByExpression(self, adding=False): else: self.panel.tblParameters.setUpdatesEnabled(False) for row in range(self.panel.batchRowCount()): - params, ok = self.panel.parametersForRow(row=row, - context=context, - warnOnInvalid=False) + params, ok = self.panel.parametersForRow( + row=row, context=context, warnOnInvalid=False + ) # remove previous algorithm scope -- we need to rebuild this completely, using the # other parameter values from the current row expression_context.popScope() - alg_scope = QgsExpressionContextUtils.processingAlgorithmScope(self.panel.alg, params, context) + alg_scope = QgsExpressionContextUtils.processingAlgorithmScope( + self.panel.alg, params, context + ) for k, v in params.items(): alg_scope.setVariable(k, v, True) # add batch row number as evaluable variable in algorithm scope - alg_scope.setVariable('row_number', row, False) + alg_scope.setVariable("row_number", row, False) expression_context.appendScope(alg_scope) @@ -454,11 +520,13 @@ def __init__(self, parent, alg): self.btnAdvanced.hide() # Set icons - self.btnAdd.setIcon(QgsApplication.getThemeIcon('/symbologyAdd.svg')) - self.btnRemove.setIcon(QgsApplication.getThemeIcon('/symbologyRemove.svg')) - self.btnOpen.setIcon(QgsApplication.getThemeIcon('/mActionFileOpen.svg')) - self.btnSave.setIcon(QgsApplication.getThemeIcon('/mActionFileSave.svg')) - self.btnAdvanced.setIcon(QgsApplication.getThemeIcon("/processingAlgorithm.svg")) + self.btnAdd.setIcon(QgsApplication.getThemeIcon("/symbologyAdd.svg")) + self.btnRemove.setIcon(QgsApplication.getThemeIcon("/symbologyRemove.svg")) + self.btnOpen.setIcon(QgsApplication.getThemeIcon("/mActionFileOpen.svg")) + self.btnSave.setIcon(QgsApplication.getThemeIcon("/mActionFileSave.svg")) + self.btnAdvanced.setIcon( + QgsApplication.getThemeIcon("/processingAlgorithm.svg") + ) self.alg = alg self.parent = parent @@ -469,7 +537,9 @@ def __init__(self, parent, alg): self.btnSave.clicked.connect(self.save) self.btnAdvanced.toggled.connect(self.toggleAdvancedMode) - self.tblParameters.horizontalHeader().resizeSections(QHeaderView.ResizeMode.ResizeToContents) + self.tblParameters.horizontalHeader().resizeSections( + QHeaderView.ResizeMode.ResizeToContents + ) self.tblParameters.horizontalHeader().setDefaultSectionSize(250) self.tblParameters.horizontalHeader().setMinimumSectionSize(150) @@ -502,8 +572,7 @@ def initWidgets(self): break # Determine column count - self.tblParameters.setColumnCount( - len(self.alg.parameterDefinitions())) + self.tblParameters.setColumnCount(len(self.alg.parameterDefinitions())) # Table headers column = 0 @@ -511,8 +580,12 @@ def initWidgets(self): if param.isDestination(): continue self.tblParameters.setHorizontalHeaderItem( - column, QTableWidgetItem(param.description())) - if param.flags() & QgsProcessingParameterDefinition.Flag.FlagAdvanced or param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden: + column, QTableWidgetItem(param.description()) + ) + if ( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagAdvanced + or param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden + ): self.tblParameters.setColumnHidden(column, True) self.column_to_parameter_definition[column] = param.name() @@ -522,7 +595,8 @@ def initWidgets(self): for out in self.alg.destinationParameterDefinitions(): if not out.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden: self.tblParameters.setHorizontalHeaderItem( - column, QTableWidgetItem(out.description())) + column, QTableWidgetItem(out.description()) + ) self.column_to_parameter_definition[column] = out.name() self.parameter_to_column[out.name()] = column column += 1 @@ -532,8 +606,12 @@ def initWidgets(self): # Add an empty row to begin self.addRow() - self.tblParameters.horizontalHeader().resizeSections(QHeaderView.ResizeMode.ResizeToContents) - self.tblParameters.verticalHeader().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents) + self.tblParameters.horizontalHeader().resizeSections( + QHeaderView.ResizeMode.ResizeToContents + ) + self.tblParameters.verticalHeader().setSectionResizeMode( + QHeaderView.ResizeMode.ResizeToContents + ) self.tblParameters.horizontalHeader().setStretchLastSection(True) def batchRowCount(self): @@ -552,7 +630,9 @@ def load(self): message_box.setWindowTitle(self.tr("Security warning")) message_box.setText( self.tr( - "This algorithm is a potential security risk if executed with unchecked inputs, and may result in system damage or data leaks. Only continue if you trust the source of the file. Continue?")) + "This algorithm is a potential security risk if executed with unchecked inputs, and may result in system damage or data leaks. Only continue if you trust the source of the file. Continue?" + ) + ) message_box.setIcon(QMessageBox.Icon.Warning) message_box.addButton(QMessageBox.StandardButton.Yes) message_box.addButton(QMessageBox.StandardButton.No) @@ -563,17 +643,20 @@ def load(self): settings = QgsSettings() last_path = settings.value("/Processing/LastBatchPath", QDir.homePath()) - filters = ';;'.join([self.tr('Batch Processing files (*.batch)'), - self.tr('JSON files (*.json)')]) - filename, _ = QFileDialog.getOpenFileName(self, - self.tr('Open Batch'), - last_path, - filters) + filters = ";;".join( + [ + self.tr("Batch Processing files (*.batch)"), + self.tr("JSON files (*.json)"), + ] + ) + filename, _ = QFileDialog.getOpenFileName( + self, self.tr("Open Batch"), last_path, filters + ) if not filename: return last_path = QFileInfo(filename).path() - settings.setValue('/Processing/LastBatchPath', last_path) + settings.setValue("/Processing/LastBatchPath", last_path) with open(filename) as f: values = json.load(f) @@ -583,17 +666,20 @@ def load(self): else: QMessageBox.critical( self, - self.tr('Load Batch Parameters'), - self.tr('This file format is unknown and cannot be opened as batch parameters.')) + self.tr("Load Batch Parameters"), + self.tr( + "This file format is unknown and cannot be opened as batch parameters." + ), + ) else: self.load_old_json_batch_file(values) - def load_batch_file_3_40_version(self, values: Dict): + def load_batch_file_3_40_version(self, values: dict): """ Loads the newer version 3.40 batch parameter JSON format """ context = dataobjects.createContext() - rows: List = values.get(self.ROWS, []) + rows: list = values.get(self.ROWS, []) self.clear() for row_number, row in enumerate(rows): @@ -619,14 +705,17 @@ def load_batch_file_3_40_version(self, values: Dict): widget = self.tblParameters.cellWidget(row_number + 1, column) widget.setValue(value) - def load_old_json_batch_file(self, values: List): + def load_old_json_batch_file(self, values: list): """ Loads the old, insecure batch parameter JSON format """ message_box = QMessageBox() message_box.setWindowTitle(self.tr("Security warning")) message_box.setText( - self.tr("Opening older QGIS batch Processing files from an untrusted source can harm your computer. Only continue if you trust the source of the file. Continue?")) + self.tr( + "Opening older QGIS batch Processing files from an untrusted source can harm your computer. Only continue if you trust the source of the file. Continue?" + ) + ) message_box.setIcon(QMessageBox.Icon.Warning) message_box.addButton(QMessageBox.StandardButton.Yes) message_box.addButton(QMessageBox.StandardButton.No) @@ -663,8 +752,9 @@ def load_old_json_batch_file(self, values: List): except TypeError: QMessageBox.critical( self, - self.tr('Load Batch Parameters'), - self.tr('An error occurred while reading the batch parameters file.')) + self.tr("Load Batch Parameters"), + self.tr("An error occurred while reading the batch parameters file."), + ) def save(self): row_parameters = [] @@ -683,9 +773,12 @@ def save(self): value = wrapper.parameterValue() if not param.checkValueIsAcceptable(value, context): - msg = self.tr('Wrong or missing parameter value: {0} (row {1})').format( - param.description(), row + 2) - self.parent.messageBar().pushMessage("", msg, level=Qgis.MessageLevel.Warning, duration=5) + msg = self.tr( + "Wrong or missing parameter value: {0} (row {1})" + ).format(param.description(), row + 2) + self.parent.messageBar().pushMessage( + "", msg, level=Qgis.MessageLevel.Warning, duration=5 + ) return this_row_params[param.name()] = param.valueAsJsonObject(value, context) @@ -695,34 +788,39 @@ def save(self): col = self.parameter_to_column[out.name()] widget = self.tblParameters.cellWidget(row + 1, col) text = widget.getValue() - if text.strip() != '': + if text.strip() != "": this_row_outputs[out.name()] = text.strip() else: - self.parent.messageBar().pushMessage("", - self.tr('Wrong or missing output value: {0} (row {1})').format( - out.description(), row + 2), - level=Qgis.MessageLevel.Warning, duration=5) + self.parent.messageBar().pushMessage( + "", + self.tr("Wrong or missing output value: {0} (row {1})").format( + out.description(), row + 2 + ), + level=Qgis.MessageLevel.Warning, + duration=5, + ) return - row_parameters.append({self.PARAMETERS: this_row_params, self.OUTPUTS: this_row_outputs}) + row_parameters.append( + {self.PARAMETERS: this_row_params, self.OUTPUTS: this_row_outputs} + ) - output_json = { - self.FORMAT: self.CURRENT_FORMAT, - self.ROWS: row_parameters - } + output_json = {self.FORMAT: self.CURRENT_FORMAT, self.ROWS: row_parameters} settings = QgsSettings() last_path = settings.value("/Processing/LastBatchPath", QDir.homePath()) - filename, __ = QFileDialog.getSaveFileName(self, - self.tr('Save Batch'), - last_path, - self.tr('Batch Processing files (*.batch)')) + filename, __ = QFileDialog.getSaveFileName( + self, + self.tr("Save Batch"), + last_path, + self.tr("Batch Processing files (*.batch)"), + ) if not filename: return - filename = QgsFileUtils.ensureFileNameHasExtension(filename, ['batch']) + filename = QgsFileUtils.ensureFileNameHasExtension(filename, ["batch"]) last_path = QFileInfo(filename).path() - settings.setValue('/Processing/LastBatchPath', last_path) - with open(filename, 'w') as f: + settings.setValue("/Processing/LastBatchPath", last_path) + with open(filename, "w") as f: json.dump(output_json, f, indent=2) def setCellWrapper(self, row, column, wrapper, context): @@ -756,8 +854,12 @@ def setCellWrapper(self, row, column, wrapper, context): def addFillRow(self): self.tblParameters.setRowCount(1) for col, name in self.column_to_parameter_definition.items(): - param_definition = self.alg.parameterDefinition(self.column_to_parameter_definition[col]) - self.tblParameters.setCellWidget(0, col, BatchPanelFillWidget(param_definition, col, self)) + param_definition = self.alg.parameterDefinition( + self.column_to_parameter_definition[col] + ) + self.tblParameters.setCellWidget( + 0, col, BatchPanelFillWidget(param_definition, col, self) + ) def addRow(self, nb=1): self.tblParameters.setUpdatesEnabled(False) @@ -774,7 +876,9 @@ def addRow(self, nb=1): continue column = self.parameter_to_column[param.name()] - wrapper = WidgetWrapperFactory.create_wrapper(param, self.parent, row, column) + wrapper = WidgetWrapperFactory.create_wrapper( + param, self.parent, row, column + ) wrappers[param.name()] = wrapper self.setCellWrapper(row, column, wrapper, context) @@ -784,8 +888,10 @@ def addRow(self, nb=1): column = self.parameter_to_column[out.name()] self.tblParameters.setCellWidget( - row, column, BatchOutputSelectionPanel( - out, self.alg, row, column, self)) + row, + column, + BatchOutputSelectionPanel(out, self.alg, row, column, self), + ) for wrapper in list(wrappers.values()): wrapper.postInitialize(list(wrappers.values())) @@ -819,8 +925,15 @@ def removeRows(self): def toggleAdvancedMode(self, checked): for param in self.alg.parameterDefinitions(): - if param.flags() & QgsProcessingParameterDefinition.Flag.FlagAdvanced and not (param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden): - self.tblParameters.setColumnHidden(self.parameter_to_column[param.name()], not checked) + if ( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagAdvanced + and not ( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden + ) + ): + self.tblParameters.setColumnHidden( + self.parameter_to_column[param.name()], not checked + ) def valueForParameter(self, row, parameter_name): """ @@ -829,11 +942,13 @@ def valueForParameter(self, row, parameter_name): wrapper = self.wrappers[row][self.parameter_to_column[parameter_name]] return wrapper.parameterValue() - def parametersForRow(self, - row: int, - context: QgsProcessingContext, - destinationProject: Optional[QgsProject] = None, - warnOnInvalid: bool = True): + def parametersForRow( + self, + row: int, + context: QgsProcessingContext, + destinationProject: Optional[QgsProject] = None, + warnOnInvalid: bool = True, + ): """ Returns the parameters dictionary corresponding to a row in the batch table """ @@ -844,11 +959,17 @@ def parametersForRow(self, col = self.parameter_to_column[param.name()] wrapper = self.wrappers[row][col] parameters[param.name()] = wrapper.parameterValue() - if warnOnInvalid and not param.checkValueIsAcceptable(wrapper.parameterValue()): - self.parent.messageBar().pushMessage("", - self.tr('Wrong or missing parameter value: {0} (row {1})').format( - param.description(), row + 2), - level=Qgis.MessageLevel.Warning, duration=5) + if warnOnInvalid and not param.checkValueIsAcceptable( + wrapper.parameterValue() + ): + self.parent.messageBar().pushMessage( + "", + self.tr("Wrong or missing parameter value: {0} (row {1})").format( + param.description(), row + 2 + ), + level=Qgis.MessageLevel.Warning, + duration=5, + ) return {}, False count_visible_outputs = 0 @@ -864,25 +985,32 @@ def parametersForRow(self, if warnOnInvalid: if not out.checkValueIsAcceptable(text): msg = self.tr( - 'Wrong or missing output value: {0} (row {1})').format( - out.description(), row + 2) - self.parent.messageBar().pushMessage("", msg, - level=Qgis.MessageLevel.Warning, - duration=5) + "Wrong or missing output value: {0} (row {1})" + ).format(out.description(), row + 2) + self.parent.messageBar().pushMessage( + "", msg, level=Qgis.MessageLevel.Warning, duration=5 + ) return {}, False ok, error = out.isSupportedOutputValue(text, context) if not ok: - self.parent.messageBar().pushMessage("", error, - level=Qgis.MessageLevel.Warning, - duration=5) + self.parent.messageBar().pushMessage( + "", error, level=Qgis.MessageLevel.Warning, duration=5 + ) return {}, False - if isinstance(out, (QgsProcessingParameterRasterDestination, - QgsProcessingParameterVectorDestination, - QgsProcessingParameterFeatureSink)): + if isinstance( + out, + ( + QgsProcessingParameterRasterDestination, + QgsProcessingParameterVectorDestination, + QgsProcessingParameterFeatureSink, + ), + ): # load rasters and sinks on completion - parameters[out.name()] = QgsProcessingOutputLayerDefinition(text, destinationProject) + parameters[out.name()] = QgsProcessingOutputLayerDefinition( + text, destinationProject + ) else: parameters[out.name()] = text diff --git a/python/plugins/processing/gui/CheckboxesPanel.py b/python/plugins/processing/gui/CheckboxesPanel.py index a1aa2cb7fcd6..4e1fb0bf020c 100644 --- a/python/plugins/processing/gui/CheckboxesPanel.py +++ b/python/plugins/processing/gui/CheckboxesPanel.py @@ -16,9 +16,9 @@ *************************************************************************** """ -__author__ = 'Arnaud Morvan' -__date__ = 'January 2015' -__copyright__ = '(C) 2015, Arnaud Morvan' +__author__ = "Arnaud Morvan" +__date__ = "January 2015" +__copyright__ = "(C) 2015, Arnaud Morvan" from qgis.PyQt.QtCore import Qt from qgis.PyQt.QtWidgets import ( @@ -30,7 +30,7 @@ QSpacerItem, QWidget, QMenu, - QAction + QAction, ) from qgis.PyQt.QtGui import QCursor @@ -63,8 +63,11 @@ def __init__(self, options, multiple, columns=2, parent=None): self._buttons.append((v, button)) self._buttonGroup.addButton(button, i) layout.addWidget(button, i % rows, i / rows) - layout.addItem(QSpacerItem(0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum), - 0, columns) + layout.addItem( + QSpacerItem(0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum), + 0, + columns, + ) self.setLayout(layout) if multiple: @@ -73,34 +76,30 @@ def __init__(self, options, multiple, columns=2, parent=None): def showPopupMenu(self): popup_menu = QMenu() - select_all_action = QAction(self.tr('Select All'), popup_menu) + select_all_action = QAction(self.tr("Select All"), popup_menu) select_all_action.triggered.connect(self.selectAll) - clear_all_action = QAction(self.tr('Clear Selection'), popup_menu) + clear_all_action = QAction(self.tr("Clear Selection"), popup_menu) clear_all_action.triggered.connect(self.deselectAll) popup_menu.addAction(select_all_action) popup_menu.addAction(clear_all_action) popup_menu.exec(QCursor.pos()) def selectAll(self): - for (v, button) in self._buttons: + for v, button in self._buttons: button.setChecked(True) def deselectAll(self): - for (v, button) in self._buttons: + for v, button in self._buttons: button.setChecked(False) def value(self): if self._multiple: - return [ - v - for (v, checkbox) in self._buttons - if checkbox.isChecked() - ] + return [v for (v, checkbox) in self._buttons if checkbox.isChecked()] else: return self._options[self._buttonGroup.checkedId()][0] def setValue(self, value): - for (v, button) in self._buttons: + for v, button in self._buttons: if self._multiple: button.setChecked(v in value) else: diff --git a/python/plugins/processing/gui/ConfigDialog.py b/python/plugins/processing/gui/ConfigDialog.py index efc60b27c253..896de8c9b195 100644 --- a/python/plugins/processing/gui/ConfigDialog.py +++ b/python/plugins/processing/gui/ConfigDialog.py @@ -15,41 +15,40 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import warnings from qgis.PyQt import uic from qgis.PyQt.QtCore import Qt, QEvent -from qgis.PyQt.QtWidgets import (QFileDialog, - QStyle, - QMessageBox, - QStyledItemDelegate, - QLineEdit, - QWidget, - QToolButton, - QHBoxLayout, - QComboBox, - QPushButton, - QApplication) -from qgis.PyQt.QtGui import (QIcon, - QStandardItemModel, - QStandardItem, - QCursor) - -from qgis.gui import (QgsDoubleSpinBox, - QgsSpinBox, - QgsOptionsPageWidget, - QgsOptionsDialogHighlightWidget) +from qgis.PyQt.QtWidgets import ( + QFileDialog, + QStyle, + QMessageBox, + QStyledItemDelegate, + QLineEdit, + QWidget, + QToolButton, + QHBoxLayout, + QComboBox, + QPushButton, + QApplication, +) +from qgis.PyQt.QtGui import QIcon, QStandardItemModel, QStandardItem, QCursor + +from qgis.gui import ( + QgsDoubleSpinBox, + QgsSpinBox, + QgsOptionsPageWidget, + QgsOptionsDialogHighlightWidget, +) from qgis.core import NULL, QgsApplication, QgsSettings from qgis.utils import OverrideCursor -from processing.core.ProcessingConfig import (ProcessingConfig, - settingsWatcher, - Setting) +from processing.core.ProcessingConfig import ProcessingConfig, settingsWatcher, Setting from processing.core.Processing import Processing from processing.gui.DirectorySelectorDialog import DirectorySelectorDialog from processing.gui.menus import defaultMenuEntries, menusSettingsGroup @@ -57,8 +56,7 @@ pluginPath = os.path.split(os.path.dirname(__file__))[0] with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) - WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'DlgConfig.ui')) + WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "ui", "DlgConfig.ui")) class ConfigOptionsPage(QgsOptionsPageWidget): @@ -71,7 +69,7 @@ def __init__(self, parent): layout.setMargin(0) self.setLayout(layout) layout.addWidget(self.config_widget) - self.setObjectName('processingOptions') + self.setObjectName("processingOptions") self.highlightWidget = ProcessingTreeHighlight(self.config_widget) self.registerHighlightWidget(self.highlightWidget) @@ -79,7 +77,7 @@ def apply(self): self.config_widget.accept() def helpKey(self): - return 'processing/index.html' + return "processing/index.html" class ProcessingTreeHighlight(QgsOptionsDialogHighlightWidget): @@ -95,7 +93,7 @@ def searchText(self, text): return self.config_dialog.textChanged(text) def reset(self): - self.config_dialog.textChanged('') + self.config_dialog.textChanged("") class ConfigDialog(BASE, WIDGET): @@ -104,7 +102,7 @@ def __init__(self, showSearch=True): super().__init__(None) self.setupUi(self) - self.groupIcon = QgsApplication.getThemeIcon('mIconFolder.svg') + self.groupIcon = QgsApplication.getThemeIcon("mIconFolder.svg") self.model = QStandardItemModel() self.tree.setModel(self.model) @@ -113,8 +111,10 @@ def __init__(self, showSearch=True): self.tree.setItemDelegateForColumn(1, self.delegate) if showSearch: - if hasattr(self.searchBox, 'setPlaceholderText'): - self.searchBox.setPlaceholderText(QApplication.translate('ConfigDialog', 'Search…')) + if hasattr(self.searchBox, "setPlaceholderText"): + self.searchBox.setPlaceholderText( + QApplication.translate("ConfigDialog", "Search…") + ) self.searchBox.textChanged.connect(self.textChanged) else: self.searchBox.hide() @@ -130,7 +130,9 @@ def textChanged(self, text=None): text = str(text.lower()) else: text = str(self.searchBox.text().lower()) - found = self._filterItem(self.model.invisibleRootItem(), text, False if text else True) + found = self._filterItem( + self.model.invisibleRootItem(), text, False if text else True + ) self.auto_adjust_columns = False if text: @@ -148,7 +150,12 @@ def textChanged(self, text=None): def _filterItem(self, item, text, forceShow=False): if item.hasChildren(): - show = forceShow or isinstance(item, QStandardItem) and bool(text) and (text in item.text().lower()) + show = ( + forceShow + or isinstance(item, QStandardItem) + and bool(text) + and (text in item.text().lower()) + ) for i in range(item.rowCount()): child = item.child(i) show = self._filterItem(child, text, forceShow) or show @@ -166,8 +173,7 @@ def fillTree(self): def fillTreeUsingProviders(self): self.items = {} self.model.clear() - self.model.setHorizontalHeaderLabels([self.tr('Setting'), - self.tr('Value')]) + self.model.setHorizontalHeaderLabels([self.tr("Setting"), self.tr("Value")]) settings = ProcessingConfig.getSettings() @@ -176,7 +182,7 @@ def fillTreeUsingProviders(self): """ Filter 'General', 'Models' and 'Scripts' items """ - priorityKeys = [self.tr('General'), self.tr('Models'), self.tr('Scripts')] + priorityKeys = [self.tr("General"), self.tr("Models"), self.tr("Scripts")] for group in priorityKeys: groupItem = QStandardItem(group) icon = ProcessingConfig.getGroupIcon(group) @@ -203,7 +209,7 @@ def fillTreeUsingProviders(self): """ Filter 'Providers' items """ - providersItem = QStandardItem(self.tr('Providers')) + providersItem = QStandardItem(self.tr("Providers")) icon = QgsApplication.getThemeIcon("/processingAlgorithm.svg") providersItem.setIcon(icon) providersItem.setEditable(False) @@ -237,8 +243,8 @@ def fillTreeUsingProviders(self): """ Filter 'Menus' items """ - self.menusItem = QStandardItem(self.tr('Menus')) - icon = QIcon(os.path.join(pluginPath, 'images', 'menu.png')) + self.menusItem = QStandardItem(self.tr("Menus")) + icon = QIcon(os.path.join(pluginPath, "images", "menu.png")) self.menusItem.setIcon(icon) self.menusItem.setEditable(False) emptyItem = QStandardItem() @@ -246,7 +252,7 @@ def fillTreeUsingProviders(self): rootItem.insertRow(0, [self.menusItem, emptyItem]) - button = QPushButton(self.tr('Reset to defaults')) + button = QPushButton(self.tr("Reset to defaults")) button.clicked.connect(self.resetMenusToDefaults) layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) @@ -311,13 +317,20 @@ def accept(self): for setting in list(self.items.keys()): if setting.group != menusSettingsGroup or self.saveMenus: if isinstance(setting.value, bool): - setting.setValue(self.items[setting].checkState() == Qt.CheckState.Checked) + setting.setValue( + self.items[setting].checkState() == Qt.CheckState.Checked + ) else: try: setting.setValue(str(self.items[setting].text())) except ValueError as e: - QMessageBox.warning(self, self.tr('Wrong value'), - self.tr('Wrong value for parameter "{0}":\n\n{1}').format(setting.description, str(e))) + QMessageBox.warning( + self, + self.tr("Wrong value"), + self.tr('Wrong value for parameter "{0}":\n\n{1}').format( + setting.description, str(e) + ), + ) return setting.save(qsettings) @@ -378,7 +391,9 @@ def createEditor(self, parent, options, index): elif setting.valuetype == Setting.MULTIPLE_FOLDERS: return MultipleDirectorySelector(parent, setting.placeholder) else: - value = self.convertValue(index.model().data(index, Qt.ItemDataRole.EditRole)) + value = self.convertValue( + index.model().data(index, Qt.ItemDataRole.EditRole) + ) if isinstance(value, int): spnBox = QgsSpinBox(parent) spnBox.setRange(-999999999, 999999999) @@ -422,7 +437,7 @@ def sizeHint(self, option, index): return QgsSpinBox().sizeHint() def eventFilter(self, editor, event): - if event.type() == QEvent.Type.FocusOut and hasattr(editor, 'canFocusOut'): + if event.type() == QEvent.Type.FocusOut and hasattr(editor, "canFocusOut"): if not editor.canFocusOut: return False return QStyledItemDelegate.eventFilter(self, editor, event) @@ -446,7 +461,7 @@ def __init__(self, parent=None, selectFile=False, placeholder=""): # create gui self.btnSelect = QToolButton() - self.btnSelect.setText('…') + self.btnSelect.setText("…") self.lineEdit = QLineEdit() self.lineEdit.setPlaceholderText(placeholder) self.hbl = QHBoxLayout() @@ -464,15 +479,18 @@ def __init__(self, parent=None, selectFile=False, placeholder=""): self.btnSelect.clicked.connect(self.select) def select(self): - lastDir = '' + lastDir = "" if not self.selectFile: - selectedPath = QFileDialog.getExistingDirectory(None, - self.tr('Select directory'), lastDir, - QFileDialog.Option.ShowDirsOnly) + selectedPath = QFileDialog.getExistingDirectory( + None, + self.tr("Select directory"), + lastDir, + QFileDialog.Option.ShowDirsOnly, + ) else: - selectedPath, selected_filter = QFileDialog.getOpenFileName(None, - self.tr('Select file'), lastDir, self.tr('All files (*)') - ) + selectedPath, selected_filter = QFileDialog.getOpenFileName( + None, self.tr("Select file"), lastDir, self.tr("All files (*)") + ) if not selectedPath: return @@ -494,7 +512,7 @@ def __init__(self, parent=None, placeholder=""): # create gui self.btnSelect = QToolButton() - self.btnSelect.setText('…') + self.btnSelect.setText("…") self.lineEdit = QLineEdit() self.lineEdit.setPlaceholderText(placeholder) self.hbl = QHBoxLayout() @@ -512,8 +530,8 @@ def __init__(self, parent=None, placeholder=""): def select(self): text = self.lineEdit.text() - if text != '': - items = text.split(';') + if text != "": + items = text.split(";") else: items = [] diff --git a/python/plugins/processing/gui/ContextAction.py b/python/plugins/processing/gui/ContextAction.py index 981823495782..8453c6670f22 100644 --- a/python/plugins/processing/gui/ContextAction.py +++ b/python/plugins/processing/gui/ContextAction.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" from qgis.PyQt.QtCore import QCoreApplication from qgis.PyQt.QtGui import QIcon @@ -33,8 +33,8 @@ def setData(self, itemData, toolbox): self.itemData = itemData self.toolbox = toolbox - def tr(self, string, context=''): - if context == '': + def tr(self, string, context=""): + if context == "": context = self.__class__.__name__ return QCoreApplication.translate(context, string) diff --git a/python/plugins/processing/gui/DirectorySelectorDialog.py b/python/plugins/processing/gui/DirectorySelectorDialog.py index b508727eaf6e..dd047749bdb7 100644 --- a/python/plugins/processing/gui/DirectorySelectorDialog.py +++ b/python/plugins/processing/gui/DirectorySelectorDialog.py @@ -15,23 +15,30 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'May 2016' -__copyright__ = '(C) 2016, Victor Olaya' +__author__ = "Alexander Bruy" +__date__ = "May 2016" +__copyright__ = "(C) 2016, Victor Olaya" import os import warnings from qgis.PyQt import uic from qgis.core import QgsSettings -from qgis.PyQt.QtWidgets import QDialog, QAbstractItemView, QPushButton, QDialogButtonBox, QFileDialog +from qgis.PyQt.QtWidgets import ( + QDialog, + QAbstractItemView, + QPushButton, + QDialogButtonBox, + QFileDialog, +) from qgis.PyQt.QtGui import QStandardItemModel, QStandardItem pluginPath = os.path.split(os.path.dirname(__file__))[0] with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'DlgMultipleSelection.ui')) + os.path.join(pluginPath, "ui", "DlgMultipleSelection.ui") + ) class DirectorySelectorDialog(BASE, WIDGET): @@ -40,20 +47,21 @@ def __init__(self, parent, options): super().__init__(None) self.setupUi(self) - self.lstLayers.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection) + self.lstLayers.setSelectionMode( + QAbstractItemView.SelectionMode.ExtendedSelection + ) self.options = options # Additional buttons - self.btnAdd = QPushButton(self.tr('Add')) - self.buttonBox.addButton(self.btnAdd, - QDialogButtonBox.ButtonRole.ActionRole) - self.btnRemove = QPushButton(self.tr('Remove')) - self.buttonBox.addButton(self.btnRemove, - QDialogButtonBox.ButtonRole.ActionRole) - self.btnRemoveAll = QPushButton(self.tr('Remove all')) - self.buttonBox.addButton(self.btnRemoveAll, - QDialogButtonBox.ButtonRole.ActionRole) + self.btnAdd = QPushButton(self.tr("Add")) + self.buttonBox.addButton(self.btnAdd, QDialogButtonBox.ButtonRole.ActionRole) + self.btnRemove = QPushButton(self.tr("Remove")) + self.buttonBox.addButton(self.btnRemove, QDialogButtonBox.ButtonRole.ActionRole) + self.btnRemoveAll = QPushButton(self.tr("Remove all")) + self.buttonBox.addButton( + self.btnRemoveAll, QDialogButtonBox.ButtonRole.ActionRole + ) self.btnAdd.clicked.connect(self.addDirectory) self.btnRemove.clicked.connect(lambda: self.removeRows()) @@ -82,25 +90,23 @@ def reject(self): def addDirectory(self): settings = QgsSettings() - if settings.contains('/Processing/lastDirectory'): - path = settings.value('/Processing/lastDirectory') + if settings.contains("/Processing/lastDirectory"): + path = settings.value("/Processing/lastDirectory") else: - path = '' + path = "" - folder = QFileDialog.getExistingDirectory(self, - self.tr('Select directory'), - path, - QFileDialog.Option.ShowDirsOnly) + folder = QFileDialog.getExistingDirectory( + self, self.tr("Select directory"), path, QFileDialog.Option.ShowDirsOnly + ) - if folder == '': + if folder == "": return model = self.lstLayers.model() item = QStandardItem(folder) model.appendRow(item) - settings.setValue('/Processing/lastDirectory', - os.path.dirname(folder)) + settings.setValue("/Processing/lastDirectory", os.path.dirname(folder)) def removeRows(self, removeAll=False): if removeAll: @@ -118,4 +124,4 @@ def value(self): for i in range(model.rowCount()): folders.append(model.item(i).text()) - return ';'.join(folders) + return ";".join(folders) diff --git a/python/plugins/processing/gui/EditRenderingStylesDialog.py b/python/plugins/processing/gui/EditRenderingStylesDialog.py index a887d8452788..2662cd3eb2ec 100644 --- a/python/plugins/processing/gui/EditRenderingStylesDialog.py +++ b/python/plugins/processing/gui/EditRenderingStylesDialog.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import warnings @@ -26,8 +26,7 @@ from qgis.PyQt.QtCore import Qt from qgis.PyQt.QtWidgets import QDialog, QHeaderView, QTableWidgetItem -from qgis.core import (QgsProcessingOutputRasterLayer, - QgsProcessingOutputVectorLayer) +from qgis.core import QgsProcessingOutputRasterLayer, QgsProcessingOutputVectorLayer from processing.gui.RenderingStyles import RenderingStyles from processing.gui.RenderingStyleFilePanel import RenderingStyleFilePanel @@ -37,7 +36,8 @@ with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'DlgRenderingStyles.ui')) + os.path.join(pluginPath, "ui", "DlgRenderingStyles.ui") + ) class EditRenderingStylesDialog(BASE, WIDGET): @@ -48,7 +48,9 @@ def __init__(self, alg): self.alg = alg - self.tblStyles.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch) + self.tblStyles.horizontalHeader().setSectionResizeMode( + QHeaderView.ResizeMode.Stretch + ) self.setWindowTitle(self.alg.displayName()) self.valueItems = {} @@ -58,21 +60,24 @@ def __init__(self, alg): def setTableContent(self): numOutputs = 0 for output in self.alg.outputDefinitions(): - if isinstance(output, (QgsProcessingOutputVectorLayer, QgsProcessingOutputRasterLayer)): + if isinstance( + output, (QgsProcessingOutputVectorLayer, QgsProcessingOutputRasterLayer) + ): numOutputs += 1 self.tblStyles.setRowCount(numOutputs) i = 0 for output in self.alg.outputDefinitions(): - if isinstance(output, (QgsProcessingOutputVectorLayer, QgsProcessingOutputRasterLayer)): - item = QTableWidgetItem(output.description() + '<' + - output.__class__.__name__ + '>') + if isinstance( + output, (QgsProcessingOutputVectorLayer, QgsProcessingOutputRasterLayer) + ): + item = QTableWidgetItem( + output.description() + "<" + output.__class__.__name__ + ">" + ) item.setFlags(Qt.ItemFlag.ItemIsEnabled) self.tblStyles.setItem(i, 0, item) item = RenderingStyleFilePanel() - style = \ - RenderingStyles.getStyle(self.alg.id(), - output.name()) + style = RenderingStyles.getStyle(self.alg.id(), output.name()) if style: item.setText(str(style)) self.valueItems[output.name()] = item diff --git a/python/plugins/processing/gui/ExtentSelectionPanel.py b/python/plugins/processing/gui/ExtentSelectionPanel.py index f7d67730e07a..0e911e9d3dcd 100644 --- a/python/plugins/processing/gui/ExtentSelectionPanel.py +++ b/python/plugins/processing/gui/ExtentSelectionPanel.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import warnings @@ -29,19 +29,21 @@ QDialog, QVBoxLayout, QDialogButtonBox, - QLabel + QLabel, ) from qgis.PyQt.QtGui import QCursor from qgis.PyQt.QtCore import QCoreApplication, pyqtSignal from qgis.gui import QgsMapLayerComboBox from qgis.utils import iface -from qgis.core import (Qgis, - QgsProcessingParameterDefinition, - QgsProcessingParameters, - QgsProject, - QgsReferencedRectangle, - QgsMapLayerProxyModel) +from qgis.core import ( + Qgis, + QgsProcessingParameterDefinition, + QgsProcessingParameters, + QgsProject, + QgsReferencedRectangle, + QgsMapLayerProxyModel, +) from processing.gui.RectangleMapTool import RectangleMapTool from processing.core.ProcessingConfig import ProcessingConfig from processing.tools.dataobjects import createContext @@ -51,25 +53,33 @@ with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'widgetBaseSelector.ui')) + os.path.join(pluginPath, "ui", "widgetBaseSelector.ui") + ) class LayerSelectionDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) - self.setWindowTitle(self.tr('Select Extent')) + self.setWindowTitle(self.tr("Select Extent")) vl = QVBoxLayout() - vl.addWidget(QLabel(self.tr('Use extent from'))) + vl.addWidget(QLabel(self.tr("Use extent from"))) self.combo = QgsMapLayerComboBox() self.combo.setFilters( - Qgis.LayerFilter.HasGeometry | Qgis.LayerFilter.RasterLayer | Qgis.LayerFilter.MeshLayer) - self.combo.setShowCrs(ProcessingConfig.getSetting(ProcessingConfig.SHOW_CRS_DEF)) + Qgis.LayerFilter.HasGeometry + | Qgis.LayerFilter.RasterLayer + | Qgis.LayerFilter.MeshLayer + ) + self.combo.setShowCrs( + ProcessingConfig.getSetting(ProcessingConfig.SHOW_CRS_DEF) + ) vl.addWidget(self.combo) self.button_box = QDialogButtonBox() - self.button_box.setStandardButtons(QDialogButtonBox.StandardButton.Cancel | QDialogButtonBox.StandardButton.Ok) + self.button_box.setStandardButtons( + QDialogButtonBox.StandardButton.Cancel | QDialogButtonBox.StandardButton.Ok + ) self.button_box.accepted.connect(self.accept) self.button_box.rejected.connect(self.reject) @@ -94,9 +104,10 @@ def __init__(self, dialog, param): self.crs = QgsProject.instance().crs() if self.param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: - if hasattr(self.leText, 'setPlaceholderText'): + if hasattr(self.leText, "setPlaceholderText"): self.leText.setPlaceholderText( - self.tr('[Leave blank to use min covering extent]')) + self.tr("[Leave blank to use min covering extent]") + ) self.btnSelect.clicked.connect(self.selectExtent) @@ -111,14 +122,22 @@ def __init__(self, dialog, param): if param.defaultValue() is not None: context = createContext() - rect = QgsProcessingParameters.parameterAsExtent(param, {param.name(): param.defaultValue()}, context) - crs = QgsProcessingParameters.parameterAsExtentCrs(param, {param.name(): param.defaultValue()}, context) + rect = QgsProcessingParameters.parameterAsExtent( + param, {param.name(): param.defaultValue()}, context + ) + crs = QgsProcessingParameters.parameterAsExtentCrs( + param, {param.name(): param.defaultValue()}, context + ) if not rect.isNull(): try: - s = '{},{},{},{}'.format( - rect.xMinimum(), rect.xMaximum(), rect.yMinimum(), rect.yMaximum()) + s = "{},{},{},{}".format( + rect.xMinimum(), + rect.xMaximum(), + rect.yMinimum(), + rect.yMaximum(), + ) if crs.isValid(): - s += ' [' + crs.authid() + ']' + s += " [" + crs.authid() + "]" self.crs = crs self.leText.setText(s) except: @@ -127,13 +146,16 @@ def __init__(self, dialog, param): def selectExtent(self): popupmenu = QMenu() useCanvasExtentAction = QAction( - QCoreApplication.translate("ExtentSelectionPanel", 'Use Canvas Extent'), - self.btnSelect) + QCoreApplication.translate("ExtentSelectionPanel", "Use Canvas Extent"), + self.btnSelect, + ) useLayerExtentAction = QAction( - QCoreApplication.translate("ExtentSelectionPanel", 'Use Layer Extent…'), - self.btnSelect) + QCoreApplication.translate("ExtentSelectionPanel", "Use Layer Extent…"), + self.btnSelect, + ) selectOnCanvasAction = QAction( - self.tr('Select Extent on Canvas'), self.btnSelect) + self.tr("Select Extent on Canvas"), self.btnSelect + ) popupmenu.addAction(useCanvasExtentAction) popupmenu.addAction(selectOnCanvasAction) @@ -146,16 +168,15 @@ def selectExtent(self): if self.param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: useMincoveringExtentAction = QAction( - self.tr('Use Min Covering Extent from Input Layers'), - self.btnSelect) - useMincoveringExtentAction.triggered.connect( - self.useMinCoveringExtent) + self.tr("Use Min Covering Extent from Input Layers"), self.btnSelect + ) + useMincoveringExtentAction.triggered.connect(self.useMinCoveringExtent) popupmenu.addAction(useMincoveringExtentAction) popupmenu.exec(QCursor.pos()) def useMinCoveringExtent(self): - self.leText.setText('') + self.leText.setText("") def useLayerExtent(self): dlg = LayerSelectionDialog(self) @@ -164,8 +185,12 @@ def useLayerExtent(self): self.setValueFromRect(QgsReferencedRectangle(layer.extent(), layer.crs())) def useCanvasExtent(self): - self.setValueFromRect(QgsReferencedRectangle(iface.mapCanvas().extent(), - iface.mapCanvas().mapSettings().destinationCrs())) + self.setValueFromRect( + QgsReferencedRectangle( + iface.mapCanvas().extent(), + iface.mapCanvas().mapSettings().destinationCrs(), + ) + ) def selectOnCanvas(self): canvas = iface.mapCanvas() @@ -177,15 +202,14 @@ def updateExtent(self): self.setValueFromRect(r) def setValueFromRect(self, r): - s = '{},{},{},{}'.format( - r.xMinimum(), r.xMaximum(), r.yMinimum(), r.yMaximum()) + s = f"{r.xMinimum()},{r.xMaximum()},{r.yMinimum()},{r.yMaximum()}" try: self.crs = r.crs() except: self.crs = QgsProject.instance().crs() if self.crs.isValid(): - s += ' [' + self.crs.authid() + ']' + s += " [" + self.crs.authid() + "]" self.leText.setText(s) self.tool.reset() @@ -196,7 +220,7 @@ def setValueFromRect(self, r): self.dialog.activateWindow() def getValue(self): - if str(self.leText.text()).strip() != '': + if str(self.leText.text()).strip() != "": return str(self.leText.text()) else: return None diff --git a/python/plugins/processing/gui/FileSelectionPanel.py b/python/plugins/processing/gui/FileSelectionPanel.py index 7479b8bca48e..104297d32dfb 100644 --- a/python/plugins/processing/gui/FileSelectionPanel.py +++ b/python/plugins/processing/gui/FileSelectionPanel.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import warnings @@ -33,7 +33,8 @@ with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'widgetBaseSelector.ui')) + os.path.join(pluginPath, "ui", "widgetBaseSelector.ui") + ) class FileSelectionPanel(BASE, WIDGET): @@ -42,7 +43,7 @@ def __init__(self, isFolder, ext=None): super().__init__(None) self.setupUi(self) - self.ext = ext or '*' + self.ext = ext or "*" self.isFolder = isFolder self.btnSelect.clicked.connect(self.showSelectionDialog) @@ -55,30 +56,38 @@ def showSelectionDialog(self): path = text elif os.path.isdir(os.path.dirname(text)): path = os.path.dirname(text) - elif settings.contains('/Processing/LastInputPath'): - path = settings.value('/Processing/LastInputPath') + elif settings.contains("/Processing/LastInputPath"): + path = settings.value("/Processing/LastInputPath") else: - path = '' + path = "" if self.isFolder: - folder = QFileDialog.getExistingDirectory(self, - self.tr('Select Folder'), path) + folder = QFileDialog.getExistingDirectory( + self, self.tr("Select Folder"), path + ) if folder: self.leText.setText(folder) - settings.setValue('/Processing/LastInputPath', - os.path.dirname(folder)) + settings.setValue("/Processing/LastInputPath", os.path.dirname(folder)) else: - filenames, selected_filter = QFileDialog.getOpenFileNames(self, - self.tr('Select File'), path, self.tr('{} files').format(self.ext.upper()) + ' (*.' + self.ext + self.tr(');;All files (*.*)')) + filenames, selected_filter = QFileDialog.getOpenFileNames( + self, + self.tr("Select File"), + path, + self.tr("{} files").format(self.ext.upper()) + + " (*." + + self.ext + + self.tr(");;All files (*.*)"), + ) if filenames: - self.leText.setText(';'.join(filenames)) - settings.setValue('/Processing/LastInputPath', - os.path.dirname(filenames[0])) + self.leText.setText(";".join(filenames)) + settings.setValue( + "/Processing/LastInputPath", os.path.dirname(filenames[0]) + ) def getValue(self): s = self.leText.text() if isWindows(): - s = s.replace('\\', '/') + s = s.replace("\\", "/") return s def setText(self, text): diff --git a/python/plugins/processing/gui/FixedTableDialog.py b/python/plugins/processing/gui/FixedTableDialog.py index 79c996304106..9d76f7e3160c 100644 --- a/python/plugins/processing/gui/FixedTableDialog.py +++ b/python/plugins/processing/gui/FixedTableDialog.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import warnings @@ -25,15 +25,19 @@ from qgis.gui import QgsGui from qgis.PyQt import uic -from qgis.PyQt.QtWidgets import QDialog, QPushButton, QAbstractItemView, QDialogButtonBox +from qgis.PyQt.QtWidgets import ( + QDialog, + QPushButton, + QAbstractItemView, + QDialogButtonBox, +) from qgis.PyQt.QtGui import QStandardItemModel, QStandardItem pluginPath = os.path.split(os.path.dirname(__file__))[0] with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) - WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'DlgFixedTable.ui')) + WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "ui", "DlgFixedTable.ui")) class FixedTableDialog(BASE, WIDGET): @@ -50,22 +54,23 @@ def __init__(self, param, table): QgsGui.instance().enableAutoGeometryRestore(self) - self.tblView.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) + self.tblView.setSelectionBehavior( + QAbstractItemView.SelectionBehavior.SelectRows + ) self.tblView.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection) self.param = param self.rettable = None # Additional buttons - self.btnAdd = QPushButton(self.tr('Add row')) - self.buttonBox.addButton(self.btnAdd, - QDialogButtonBox.ButtonRole.ActionRole) - self.btnRemove = QPushButton(self.tr('Remove row(s)')) - self.buttonBox.addButton(self.btnRemove, - QDialogButtonBox.ButtonRole.ActionRole) - self.btnRemoveAll = QPushButton(self.tr('Remove all')) - self.buttonBox.addButton(self.btnRemoveAll, - QDialogButtonBox.ButtonRole.ActionRole) + self.btnAdd = QPushButton(self.tr("Add row")) + self.buttonBox.addButton(self.btnAdd, QDialogButtonBox.ButtonRole.ActionRole) + self.btnRemove = QPushButton(self.tr("Remove row(s)")) + self.buttonBox.addButton(self.btnRemove, QDialogButtonBox.ButtonRole.ActionRole) + self.btnRemoveAll = QPushButton(self.tr("Remove all")) + self.buttonBox.addButton( + self.btnRemoveAll, QDialogButtonBox.ButtonRole.ActionRole + ) self.btnAdd.clicked.connect(self.addRow) self.btnRemove.clicked.connect(lambda: self.removeRows()) @@ -118,5 +123,5 @@ def removeRows(self, removeAll=False): self.tblView.setUpdatesEnabled(True) def addRow(self): - items = [QStandardItem('0') for i in range(self.tblView.model().columnCount())] + items = [QStandardItem("0") for i in range(self.tblView.model().columnCount())] self.tblView.model().appendRow(items) diff --git a/python/plugins/processing/gui/FixedTablePanel.py b/python/plugins/processing/gui/FixedTablePanel.py index d12c7637579b..70758ce13383 100644 --- a/python/plugins/processing/gui/FixedTablePanel.py +++ b/python/plugins/processing/gui/FixedTablePanel.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import warnings @@ -31,7 +31,8 @@ with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'widgetBaseSelector.ui')) + os.path.join(pluginPath, "ui", "widgetBaseSelector.ui") + ) class FixedTablePanel(BASE, WIDGET): @@ -48,16 +49,22 @@ def __init__(self, param, parent=None): self.table = [] for row in range(param.numberRows()): for col in range(len(param.headers())): - self.table.append('0') + self.table.append("0") self.leText.setText( - self.tr('Fixed table {0}x{1}').format(param.numberRows(), len(param.headers()))) + self.tr("Fixed table {0}x{1}").format( + param.numberRows(), len(param.headers()) + ) + ) self.btnSelect.clicked.connect(self.showFixedTableDialog) def updateSummaryText(self): - self.leText.setText(self.tr('Fixed table {0}x{1}').format( - len(self.table) // len(self.param.headers()), len(self.param.headers()))) + self.leText.setText( + self.tr("Fixed table {0}x{1}").format( + len(self.table) // len(self.param.headers()), len(self.param.headers()) + ) + ) def setValue(self, value): self.table = value diff --git a/python/plugins/processing/gui/Help2Html.py b/python/plugins/processing/gui/Help2Html.py index c5dcef956242..a8cdeba4d833 100644 --- a/python/plugins/processing/gui/Help2Html.py +++ b/python/plugins/processing/gui/Help2Html.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import re @@ -27,17 +27,19 @@ from processing.tools import system -ALG_DESC = 'ALG_DESC' -ALG_CREATOR = 'ALG_CREATOR' -ALG_HELP_CREATOR = 'ALG_HELP_CREATOR' -ALG_VERSION = 'ALG_VERSION' +ALG_DESC = "ALG_DESC" +ALG_CREATOR = "ALG_CREATOR" +ALG_HELP_CREATOR = "ALG_HELP_CREATOR" +ALG_VERSION = "ALG_VERSION" -exps = [(r"\*(.*?)\*", r"\1"), - ("``(.*?)``", r'\1'), - ("(.*?)\n==+\n+?", r'

\1

'), - ("(.*?)\n--+\n+?", r'

\1

'), - (r"::(\s*\n(\s*\n)*((\s+).*?\n)(((\4).*?\n)|(\s*\n))*)", r"
\1
"), - ("\n+", "

")] +exps = [ + (r"\*(.*?)\*", r"\1"), + ("``(.*?)``", r'\1'), + ("(.*?)\n==+\n+?", r"

\1

"), + ("(.*?)\n--+\n+?", r"

\1

"), + (r"::(\s*\n(\s*\n)*((\s+).*?\n)(((\4).*?\n)|(\s*\n))*)", r"
\1
"), + ("\n+", "

"), +] def getHtmlFromRstFile(rst): @@ -60,9 +62,9 @@ def getHtmlFromHelpFile(alg, helpFile): descriptions = json.load(f) content = getHtmlFromDescriptionsDict(alg, descriptions) - algGroup, algName = alg.id().split(':') + algGroup, algName = alg.id().split(":") filePath = os.path.join(system.tempHelpFolder(), f"{algGroup}_{algName}.html") - with open(filePath, 'w', encoding='utf-8') as f: + with open(filePath, "w", encoding="utf-8") as f: f.write(content) return QUrl.fromLocalFile(filePath).toString() except: @@ -70,21 +72,27 @@ def getHtmlFromHelpFile(alg, helpFile): def getHtmlFromDescriptionsDict(alg, descriptions): - s = tr('

Algorithm description

\n') - s += '

' + getDescription(ALG_DESC, descriptions) + '

\n' - s += tr('

Input parameters

\n') + s = tr("

Algorithm description

\n") + s += "

" + getDescription(ALG_DESC, descriptions) + "

\n" + s += tr("

Input parameters

\n") for param in alg.parameterDefinitions(): - s += '

' + param.description() + '

\n' - s += '

' + getDescription(param.name(), descriptions) + '

\n' - s += tr('

Outputs

\n') + s += "

" + param.description() + "

\n" + s += "

" + getDescription(param.name(), descriptions) + "

\n" + s += tr("

Outputs

\n") for out in alg.outputs: - s += '

' + out.description() + '

\n' - s += '

' + getDescription(out.name(), descriptions) + '

\n' - s += '
' - s += tr('

Algorithm author: {0}

').format(getDescription(ALG_CREATOR, descriptions)) - s += tr('

Help author: {0}

').format(getDescription(ALG_HELP_CREATOR, descriptions)) - s += tr('

Algorithm version: {0}

').format(getDescription(ALG_VERSION, descriptions)) - s += '' + s += "

" + out.description() + "

\n" + s += "

" + getDescription(out.name(), descriptions) + "

\n" + s += "
" + s += tr('

Algorithm author: {0}

').format( + getDescription(ALG_CREATOR, descriptions) + ) + s += tr('

Help author: {0}

').format( + getDescription(ALG_HELP_CREATOR, descriptions) + ) + s += tr('

Algorithm version: {0}

').format( + getDescription(ALG_VERSION, descriptions) + ) + s += "" return s @@ -92,8 +100,8 @@ def getDescription(name, descriptions): if name in descriptions: return str(descriptions[name]).replace("\n", "
") else: - return '' + return "" def tr(string): - return QCoreApplication.translate('Help2Html', string) + return QCoreApplication.translate("Help2Html", string) diff --git a/python/plugins/processing/gui/ListMultiselectWidget.py b/python/plugins/processing/gui/ListMultiselectWidget.py index f675ebe99680..22c13c3b51e5 100644 --- a/python/plugins/processing/gui/ListMultiselectWidget.py +++ b/python/plugins/processing/gui/ListMultiselectWidget.py @@ -15,18 +15,20 @@ *************************************************************************** """ -__author__ = 'Marco Bernasocchi' -__date__ = 'June 2016' -__copyright__ = '(C) 2016, Marco Bernasocchi' - -from qgis.PyQt.QtWidgets import (QGroupBox, - QPushButton, - QSizePolicy, - QLabel, - QHBoxLayout, - QVBoxLayout, - QListWidget, - QAbstractItemView) +__author__ = "Marco Bernasocchi" +__date__ = "June 2016" +__copyright__ = "(C) 2016, Marco Bernasocchi" + +from qgis.PyQt.QtWidgets import ( + QGroupBox, + QPushButton, + QSizePolicy, + QLabel, + QHBoxLayout, + QVBoxLayout, + QListWidget, + QAbstractItemView, +) from qgis.PyQt.QtGui import QFont from qgis.PyQt.QtCore import Qt, QSize, pyqtSignal @@ -152,8 +154,7 @@ def _do_move(self, fromList, toList): self.selection_changed.emit() def _setupUI(self): - self.setSizePolicy( - QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred) + self.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred) self.setMinimumHeight(180) @@ -166,7 +167,7 @@ def _setupUI(self): self.deselected_widget = QListWidget(self) self._set_list_widget_defaults(self.deselected_widget) deselected_label = QLabel() - deselected_label.setText('Deselected') + deselected_label.setText("Deselected") deselected_label.setAlignment(Qt.AlignmentFlag.AlignCenter) deselected_label.setFont(italic_font) deselected_v_layout = QVBoxLayout() @@ -177,7 +178,7 @@ def _setupUI(self): self.selected_widget = QListWidget(self) self._set_list_widget_defaults(self.selected_widget) selected_label = QLabel() - selected_label.setText('Selected') + selected_label.setText("Selected") selected_label.setAlignment(Qt.AlignmentFlag.AlignCenter) selected_label.setFont(italic_font) selected_v_layout = QVBoxLayout() @@ -188,14 +189,14 @@ def _setupUI(self): self.buttons_vertical_layout = QVBoxLayout() self.buttons_vertical_layout.setContentsMargins(0, -1, 0, -1) - self.select_all_btn = SmallQPushButton('>>') - self.deselect_all_btn = SmallQPushButton('<<') - self.select_btn = SmallQPushButton('>') - self.deselect_btn = SmallQPushButton('<') - self.select_btn.setToolTip('Add the selected items') - self.deselect_btn.setToolTip('Remove the selected items') - self.select_all_btn.setToolTip('Add all') - self.deselect_all_btn.setToolTip('Remove all') + self.select_all_btn = SmallQPushButton(">>") + self.deselect_all_btn = SmallQPushButton("<<") + self.select_btn = SmallQPushButton(">") + self.deselect_btn = SmallQPushButton("<") + self.select_btn.setToolTip("Add the selected items") + self.deselect_btn.setToolTip("Remove the selected items") + self.select_all_btn.setToolTip("Add all") + self.deselect_all_btn.setToolTip("Remove all") # add buttons spacer_label = QLabel() # pragmatic way to create a spacer with @@ -229,6 +230,7 @@ def __init__(self, text): QPushButton.__init__(self) self.setText(text) buttons_size_policy = QSizePolicy( - QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) + QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed + ) self.setSizePolicy(buttons_size_policy) self.setMaximumSize(QSize(30, 30)) diff --git a/python/plugins/processing/gui/MessageBarProgress.py b/python/plugins/processing/gui/MessageBarProgress.py index aa464b31368b..552cb5ca0e35 100644 --- a/python/plugins/processing/gui/MessageBarProgress.py +++ b/python/plugins/processing/gui/MessageBarProgress.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'April 2013' -__copyright__ = '(C) 2013, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "April 2013" +__copyright__ = "(C) 2013, Victor Olaya" from qgis.PyQt.QtCore import Qt, QCoreApplication from qgis.PyQt.QtWidgets import QProgressBar @@ -32,15 +32,19 @@ def __init__(self, algname=None): QgsProcessingFeedback.__init__(self) self.msg = [] - self.progressMessageBar = \ - iface.messageBar().createMessage(self.tr('Executing algorithm {}'.format(algname if algname else ''))) + self.progressMessageBar = iface.messageBar().createMessage( + self.tr("Executing algorithm {}".format(algname if algname else "")) + ) self.progress = QProgressBar() self.progressChanged.connect(self.set_progress_bar_value) self.progress.setMaximum(100) - self.progress.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter) + self.progress.setAlignment( + Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter + ) self.progressMessageBar.layout().addWidget(self.progress) - self.message_bar_item = iface.messageBar().pushWidget(self.progressMessageBar, - Qgis.MessageLevel.Info) + self.message_bar_item = iface.messageBar().pushWidget( + self.progressMessageBar, Qgis.MessageLevel.Info + ) def set_progress_bar_value(self, progress: float): """ @@ -55,12 +59,16 @@ def reportError(self, msg, fatalError=False): def close(self): if self.msg: dlg = MessageDialog() - dlg.setTitle(QCoreApplication.translate('MessageBarProgress', 'Problem executing algorithm')) + dlg.setTitle( + QCoreApplication.translate( + "MessageBarProgress", "Problem executing algorithm" + ) + ) dlg.setMessage("
".join(self.msg)) dlg.exec() iface.messageBar().popWidget(self.message_bar_item) - def tr(self, string, context=''): - if context == '': - context = 'MessageBarProgress' + def tr(self, string, context=""): + if context == "": + context = "MessageBarProgress" return QCoreApplication.translate(context, string) diff --git a/python/plugins/processing/gui/MessageDialog.py b/python/plugins/processing/gui/MessageDialog.py index 5c99b4c75c05..e9d6fe86c437 100644 --- a/python/plugins/processing/gui/MessageDialog.py +++ b/python/plugins/processing/gui/MessageDialog.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'October 2014' -__copyright__ = '(C) 2014, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "October 2014" +__copyright__ = "(C) 2014, Alexander Bruy" import os import warnings @@ -31,8 +31,7 @@ pluginPath = os.path.split(os.path.dirname(__file__))[0] with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) - WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'DlgMessage.ui')) + WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "ui", "DlgMessage.ui")) class MessageDialog(BASE, WIDGET): @@ -52,7 +51,7 @@ def setMessage(self, message): def openLink(self, url): if url.toString() == "log": self.close() - logDock = iface.mainWindow().findChild(QDockWidget, 'MessageLog') + logDock = iface.mainWindow().findChild(QDockWidget, "MessageLog") logDock.show() else: QDesktopServices.openUrl(url) diff --git a/python/plugins/processing/gui/MultipleFileInputDialog.py b/python/plugins/processing/gui/MultipleFileInputDialog.py index 72372cdf4eed..f13756408442 100644 --- a/python/plugins/processing/gui/MultipleFileInputDialog.py +++ b/python/plugins/processing/gui/MultipleFileInputDialog.py @@ -19,9 +19,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import warnings @@ -29,7 +29,13 @@ from qgis.core import QgsSettings from qgis.PyQt import uic from qgis.PyQt.QtCore import QByteArray -from qgis.PyQt.QtWidgets import QDialog, QAbstractItemView, QPushButton, QDialogButtonBox, QFileDialog +from qgis.PyQt.QtWidgets import ( + QDialog, + QAbstractItemView, + QPushButton, + QDialogButtonBox, + QFileDialog, +) from qgis.PyQt.QtGui import QStandardItemModel, QStandardItem pluginPath = os.path.split(os.path.dirname(__file__))[0] @@ -37,7 +43,8 @@ with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'DlgMultipleSelection.ui')) + os.path.join(pluginPath, "ui", "DlgMultipleSelection.ui") + ) class MultipleFileInputDialog(BASE, WIDGET): @@ -46,33 +53,40 @@ def __init__(self, options): super().__init__(None) self.setupUi(self) - self.lstLayers.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection) + self.lstLayers.setSelectionMode( + QAbstractItemView.SelectionMode.ExtendedSelection + ) self.selectedoptions = options # Additional buttons - self.btnAdd = QPushButton(self.tr('Add file')) - self.buttonBox.addButton(self.btnAdd, - QDialogButtonBox.ButtonRole.ActionRole) - self.btnRemove = QPushButton(self.tr('Remove file(s)')) - self.buttonBox.addButton(self.btnRemove, - QDialogButtonBox.ButtonRole.ActionRole) - self.btnRemoveAll = QPushButton(self.tr('Remove all')) - self.buttonBox.addButton(self.btnRemoveAll, - QDialogButtonBox.ButtonRole.ActionRole) + self.btnAdd = QPushButton(self.tr("Add file")) + self.buttonBox.addButton(self.btnAdd, QDialogButtonBox.ButtonRole.ActionRole) + self.btnRemove = QPushButton(self.tr("Remove file(s)")) + self.buttonBox.addButton(self.btnRemove, QDialogButtonBox.ButtonRole.ActionRole) + self.btnRemoveAll = QPushButton(self.tr("Remove all")) + self.buttonBox.addButton( + self.btnRemoveAll, QDialogButtonBox.ButtonRole.ActionRole + ) self.btnAdd.clicked.connect(self.addFile) self.btnRemove.clicked.connect(lambda: self.removeRows()) self.btnRemoveAll.clicked.connect(lambda: self.removeRows(True)) self.settings = QgsSettings() - self.restoreGeometry(self.settings.value("/Processing/multipleFileInputDialogGeometry", QByteArray())) + self.restoreGeometry( + self.settings.value( + "/Processing/multipleFileInputDialogGeometry", QByteArray() + ) + ) self.populateList() self.finished.connect(self.saveWindowGeometry) def saveWindowGeometry(self): - self.settings.setValue("/Processing/multipleInputDialogGeometry", self.saveGeometry()) + self.settings.setValue( + "/Processing/multipleInputDialogGeometry", self.saveGeometry() + ) def populateList(self): model = QStandardItemModel() @@ -95,13 +109,14 @@ def reject(self): def addFile(self): settings = QgsSettings() - if settings.contains('/Processing/LastInputPath'): - path = settings.value('/Processing/LastInputPath') + if settings.contains("/Processing/LastInputPath"): + path = settings.value("/Processing/LastInputPath") else: - path = '' + path = "" - files, selected_filter = QFileDialog.getOpenFileNames(self, - self.tr('Select File(s)'), path, self.tr('All files (*.*)')) + files, selected_filter = QFileDialog.getOpenFileNames( + self, self.tr("Select File(s)"), path, self.tr("All files (*.*)") + ) if len(files) == 0: return @@ -111,8 +126,7 @@ def addFile(self): item = QStandardItem(filePath) model.appendRow(item) - settings.setValue('/Processing/LastInputPath', - os.path.dirname(files[0])) + settings.setValue("/Processing/LastInputPath", os.path.dirname(files[0])) def removeRows(self, removeAll=False): if removeAll: diff --git a/python/plugins/processing/gui/MultipleInputDialog.py b/python/plugins/processing/gui/MultipleInputDialog.py index 383788fe7006..927248f3b175 100644 --- a/python/plugins/processing/gui/MultipleInputDialog.py +++ b/python/plugins/processing/gui/MultipleInputDialog.py @@ -15,29 +15,38 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import warnings from pathlib import Path -from qgis.core import (QgsSettings, - QgsProcessing, - QgsVectorFileWriter, - QgsProviderRegistry, - QgsProcessingModelChildParameterSource) +from qgis.core import ( + QgsSettings, + QgsProcessing, + QgsVectorFileWriter, + QgsProviderRegistry, + QgsProcessingModelChildParameterSource, +) from qgis.PyQt import uic from qgis.PyQt.QtCore import Qt, QByteArray, QCoreApplication -from qgis.PyQt.QtWidgets import QDialog, QAbstractItemView, QPushButton, QDialogButtonBox, QFileDialog +from qgis.PyQt.QtWidgets import ( + QDialog, + QAbstractItemView, + QPushButton, + QDialogButtonBox, + QFileDialog, +) from qgis.PyQt.QtGui import QStandardItemModel, QStandardItem pluginPath = os.path.split(os.path.dirname(__file__))[0] with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'DlgMultipleSelection.ui')) + os.path.join(pluginPath, "ui", "DlgMultipleSelection.ui") + ) class MultipleInputDialog(BASE, WIDGET): @@ -58,48 +67,63 @@ def __init__(self, options, selectedoptions=None, datatype=None): self.selectedoptions = selectedoptions or [] # Additional buttons - self.btnSelectAll = QPushButton(self.tr('Select All')) - self.buttonBox.addButton(self.btnSelectAll, - QDialogButtonBox.ButtonRole.ActionRole) - self.btnClearSelection = QPushButton(self.tr('Clear Selection')) - self.buttonBox.addButton(self.btnClearSelection, - QDialogButtonBox.ButtonRole.ActionRole) - self.btnToggleSelection = QPushButton(self.tr('Toggle Selection')) - self.buttonBox.addButton(self.btnToggleSelection, - QDialogButtonBox.ButtonRole.ActionRole) + self.btnSelectAll = QPushButton(self.tr("Select All")) + self.buttonBox.addButton( + self.btnSelectAll, QDialogButtonBox.ButtonRole.ActionRole + ) + self.btnClearSelection = QPushButton(self.tr("Clear Selection")) + self.buttonBox.addButton( + self.btnClearSelection, QDialogButtonBox.ButtonRole.ActionRole + ) + self.btnToggleSelection = QPushButton(self.tr("Toggle Selection")) + self.buttonBox.addButton( + self.btnToggleSelection, QDialogButtonBox.ButtonRole.ActionRole + ) if self.datatype is not None: - btnAddFile = QPushButton(QCoreApplication.translate("MultipleInputDialog", 'Add File(s)…')) + btnAddFile = QPushButton( + QCoreApplication.translate("MultipleInputDialog", "Add File(s)…") + ) btnAddFile.clicked.connect(self.addFiles) - self.buttonBox.addButton(btnAddFile, - QDialogButtonBox.ButtonRole.ActionRole) + self.buttonBox.addButton(btnAddFile, QDialogButtonBox.ButtonRole.ActionRole) - btnAddDir = QPushButton(QCoreApplication.translate("MultipleInputDialog", 'Add Directory…')) + btnAddDir = QPushButton( + QCoreApplication.translate("MultipleInputDialog", "Add Directory…") + ) btnAddDir.clicked.connect(self.addDirectory) - self.buttonBox.addButton(btnAddDir, - QDialogButtonBox.ButtonRole.ActionRole) + self.buttonBox.addButton(btnAddDir, QDialogButtonBox.ButtonRole.ActionRole) self.btnSelectAll.clicked.connect(lambda: self.selectAll(True)) self.btnClearSelection.clicked.connect(lambda: self.selectAll(False)) self.btnToggleSelection.clicked.connect(self.toggleSelection) self.settings = QgsSettings() - self.restoreGeometry(self.settings.value("/Processing/multipleInputDialogGeometry", QByteArray())) + self.restoreGeometry( + self.settings.value("/Processing/multipleInputDialogGeometry", QByteArray()) + ) - self.lstLayers.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection) + self.lstLayers.setSelectionMode( + QAbstractItemView.SelectionMode.ExtendedSelection + ) self.lstLayers.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove) self.populateList() self.finished.connect(self.saveWindowGeometry) def saveWindowGeometry(self): - self.settings.setValue("/Processing/multipleInputDialogGeometry", self.saveGeometry()) + self.settings.setValue( + "/Processing/multipleInputDialogGeometry", self.saveGeometry() + ) def populateList(self): self.model = QStandardItemModel() for value, text in self.options: item = QStandardItem(text) item.setData(value, Qt.ItemDataRole.UserRole) - item.setCheckState(Qt.CheckState.Checked if value in self.selectedoptions else Qt.CheckState.Unchecked) + item.setCheckState( + Qt.CheckState.Checked + if value in self.selectedoptions + else Qt.CheckState.Unchecked + ) item.setCheckable(True) item.setDropEnabled(False) self.model.appendRow(item) @@ -143,12 +167,16 @@ def getItemsToModify(self): def selectAll(self, value): for item in self.getItemsToModify(): - item.setCheckState(Qt.CheckState.Checked if value else Qt.CheckState.Unchecked) + item.setCheckState( + Qt.CheckState.Checked if value else Qt.CheckState.Unchecked + ) def toggleSelection(self): for item in self.getItemsToModify(): checked = item.checkState() == Qt.CheckState.Checked - item.setCheckState(Qt.CheckState.Unchecked if checked else Qt.CheckState.Checked) + item.setCheckState( + Qt.CheckState.Unchecked if checked else Qt.CheckState.Checked + ) def getFileFilter(self, datatype): """ @@ -159,25 +187,29 @@ def getFileFilter(self, datatype): if datatype == QgsProcessing.SourceType.TypeRaster: return QgsProviderRegistry.instance().fileRasterFilters() elif datatype == QgsProcessing.SourceType.TypeFile: - return self.tr('All files (*.*)') + return self.tr("All files (*.*)") else: exts = QgsVectorFileWriter.supportedFormatExtensions() for i in range(len(exts)): - exts[i] = self.tr('{0} files (*.{1})').format(exts[i].upper(), exts[i].lower()) - return self.tr('All files (*.*)') + ';;' + ';;'.join(exts) + exts[i] = self.tr("{0} files (*.{1})").format( + exts[i].upper(), exts[i].lower() + ) + return self.tr("All files (*.*)") + ";;" + ";;".join(exts) def addFiles(self): filter = self.getFileFilter(self.datatype) settings = QgsSettings() - path = str(settings.value('/Processing/LastInputPath')) + path = str(settings.value("/Processing/LastInputPath")) - ret, selected_filter = QFileDialog.getOpenFileNames(self, self.tr('Select File(s)'), - path, filter) + ret, selected_filter = QFileDialog.getOpenFileNames( + self, self.tr("Select File(s)"), path, filter + ) if ret: files = list(ret) - settings.setValue('/Processing/LastInputPath', - os.path.dirname(str(files[0]))) + settings.setValue( + "/Processing/LastInputPath", os.path.dirname(str(files[0])) + ) for filename in files: item = QStandardItem(filename) item.setData(filename, Qt.ItemDataRole.UserRole) @@ -188,17 +220,19 @@ def addFiles(self): def addDirectory(self): settings = QgsSettings() - path = str(settings.value('/Processing/LastInputPath')) + path = str(settings.value("/Processing/LastInputPath")) - ret = QFileDialog.getExistingDirectory(self, self.tr('Select File(s)'), path) + ret = QFileDialog.getExistingDirectory(self, self.tr("Select File(s)"), path) if ret: exts = [] if self.datatype == QgsProcessing.SourceType.TypeVector: exts = QgsVectorFileWriter.supportedFormatExtensions() elif self.datatype == QgsProcessing.SourceType.TypeRaster: - for t in QgsProviderRegistry.instance().fileRasterFilters().split(';;')[1:]: - for e in t[t.index('(') + 1:-1].split(' '): + for t in ( + QgsProviderRegistry.instance().fileRasterFilters().split(";;")[1:] + ): + for e in t[t.index("(") + 1 : -1].split(" "): if e != "*.*" and e.startswith("*."): exts.append(e[2:]) @@ -214,7 +248,7 @@ def addDirectory(self): files.append(p) - settings.setValue('/Processing/LastInputPath', ret) + settings.setValue("/Processing/LastInputPath", ret) for filename in files: item = QStandardItem(filename) diff --git a/python/plugins/processing/gui/MultipleInputPanel.py b/python/plugins/processing/gui/MultipleInputPanel.py index 1f7c17c2f287..eba87fd35f62 100644 --- a/python/plugins/processing/gui/MultipleInputPanel.py +++ b/python/plugins/processing/gui/MultipleInputPanel.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import warnings @@ -26,7 +26,7 @@ from qgis.PyQt import uic from qgis.PyQt.QtCore import pyqtSignal -'' +"" from processing.gui.MultipleInputDialog import MultipleInputDialog from processing.gui.MultipleFileInputDialog import MultipleFileInputDialog @@ -35,7 +35,8 @@ with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'widgetBaseSelector.ui')) + os.path.join(pluginPath, "ui", "widgetBaseSelector.ui") + ) class MultipleInputPanel(BASE, WIDGET): @@ -46,7 +47,7 @@ def __init__(self, options=None, datatype=None): self.setupUi(self) self.leText.setEnabled(False) - self.leText.setText(self.tr('0 elements selected')) + self.leText.setText(self.tr("0 elements selected")) self.btnSelect.clicked.connect(self.showSelectionDialog) @@ -58,23 +59,29 @@ def setSelectedItems(self, selected): # No checking is performed! self.selectedoptions = selected self.leText.setText( - self.tr('{0} elements selected').format(len(self.selectedoptions))) + self.tr("{0} elements selected").format(len(self.selectedoptions)) + ) def showSelectionDialog(self): if self.datatype == QgsProcessing.SourceType.TypeFile: dlg = MultipleFileInputDialog(self.selectedoptions) else: - dlg = MultipleInputDialog(self.options, self.selectedoptions, datatype=self.datatype) + dlg = MultipleInputDialog( + self.options, self.selectedoptions, datatype=self.datatype + ) dlg.exec() if dlg.selectedoptions is not None: self.selectedoptions = dlg.selectedoptions self.leText.setText( - self.tr('{0} elements selected').format(len(self.selectedoptions))) + self.tr("{0} elements selected").format(len(self.selectedoptions)) + ) self.selectionChanged.emit() def updateForOptions(self, options): selectedoptions = [] - selected = [self.options[i] if isinstance(i, int) else i for i in self.selectedoptions] + selected = [ + self.options[i] if isinstance(i, int) else i for i in self.selectedoptions + ] for sel in selected: if not isinstance(sel, int): try: diff --git a/python/plugins/processing/gui/NumberInputPanel.py b/python/plugins/processing/gui/NumberInputPanel.py index 969bdf2907af..3a9ece5b36c8 100644 --- a/python/plugins/processing/gui/NumberInputPanel.py +++ b/python/plugins/processing/gui/NumberInputPanel.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import math @@ -41,7 +41,7 @@ QgsProcessingParameterDefinition, QgsProcessingModelChildParameterSource, QgsProcessingFeatureSourceDefinition, - QgsProcessingUtils + QgsProcessingUtils, ) from qgis.gui import QgsExpressionBuilderDialog from processing.tools.dataobjects import createExpressionContext, createContext @@ -50,9 +50,11 @@ with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) NUMBER_WIDGET, NUMBER_BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'widgetNumberSelector.ui')) + os.path.join(pluginPath, "ui", "widgetNumberSelector.ui") + ) WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'widgetBaseSelector.ui')) + os.path.join(pluginPath, "ui", "widgetBaseSelector.ui") + ) class ModelerNumberInputPanel(BASE, WIDGET): @@ -80,15 +82,19 @@ def __init__(self, param, modelParametersDialog): def showExpressionsBuilder(self): context = createExpressionContext() processing_context = createContext() - scope = self.modelParametersDialog.model.createExpressionContextScopeForChildAlgorithm(self.modelParametersDialog.childId, processing_context) + scope = self.modelParametersDialog.model.createExpressionContextScopeForChildAlgorithm( + self.modelParametersDialog.childId, processing_context + ) context.appendScope(scope) highlighted = scope.variableNames() context.setHighlightedVariables(highlighted) - dlg = QgsExpressionBuilderDialog(None, str(self.leText.text()), self, 'generic', context) + dlg = QgsExpressionBuilderDialog( + None, str(self.leText.text()), self, "generic", context + ) - dlg.setWindowTitle(self.tr('Expression Based Input')) + dlg.setWindowTitle(self.tr("Expression Based Input")) if dlg.exec() == QDialog.DialogCode.Accepted: exp = QgsExpression(dlg.expressionText()) if not exp.hasParserError(): @@ -99,22 +105,34 @@ def getValue(self): for param in self.modelParametersDialog.model.parameterDefinitions(): if isinstance(param, QgsProcessingParameterNumber): if "@" + param.name() == value.strip(): - return QgsProcessingModelChildParameterSource.fromModelParameter(param.name()) + return QgsProcessingModelChildParameterSource.fromModelParameter( + param.name() + ) for alg in list(self.modelParametersDialog.model.childAlgorithms().values()): for out in alg.algorithm().outputDefinitions(): - if isinstance(out, QgsProcessingOutputNumber) and f"@{alg.childId()}_{out.name()}" == value.strip(): - return QgsProcessingModelChildParameterSource.fromChildOutput(alg.childId(), out.outputName()) + if ( + isinstance(out, QgsProcessingOutputNumber) + and f"@{alg.childId()}_{out.name()}" == value.strip() + ): + return QgsProcessingModelChildParameterSource.fromChildOutput( + alg.childId(), out.outputName() + ) try: return float(value.strip()) except: - return QgsProcessingModelChildParameterSource.fromExpression(self.leText.text()) + return QgsProcessingModelChildParameterSource.fromExpression( + self.leText.text() + ) def setValue(self, value): if isinstance(value, QgsProcessingModelChildParameterSource): - if value.source() == Qgis.ProcessingModelChildParameterSource.ModelParameter: - self.leText.setText('@' + value.parameterName()) + if ( + value.source() + == Qgis.ProcessingModelChildParameterSource.ModelParameter + ): + self.leText.setText("@" + value.parameterName()) elif value.source() == Qgis.ProcessingModelChildParameterSource.ChildOutput: name = f"{value.outputChildId()}_{value.outputName()}" self.leText.setText(name) @@ -149,7 +167,11 @@ def __init__(self, param): # Guess reasonable step value if self.param.maximum() is not None and self.param.minimum() is not None: try: - self.spnValue.setSingleStep(self.calculateStep(float(self.param.minimum()), float(self.param.maximum()))) + self.spnValue.setSingleStep( + self.calculateStep( + float(self.param.minimum()), float(self.param.maximum()) + ) + ) except: pass @@ -169,7 +191,7 @@ def __init__(self, param): min = self.spnValue.minimum() - 1 self.spnValue.setMinimum(min) self.spnValue.setValue(min) - self.spnValue.setSpecialValueText(self.tr('Not set')) + self.spnValue.setSpecialValueText(self.tr("Not set")) self.allowing_null = True if param.defaultValue() is not None: @@ -201,7 +223,9 @@ def __init__(self, param): sip.delete(self.btnDataDefined) self.btnDataDefined = None else: - self.btnDataDefined.init(0, QgsProperty(), self.param.dynamicPropertyDefinition()) + self.btnDataDefined.init( + 0, QgsProperty(), self.param.dynamicPropertyDefinition() + ) self.btnDataDefined.registerEnabledWidget(self.spnValue, False) self.spnValue.valueChanged.connect(lambda: self.hasChanged.emit()) @@ -261,27 +285,33 @@ class DistanceInputPanel(NumberInputPanel): def __init__(self, param): super().__init__(param) - self.label = QLabel('') + self.label = QLabel("") self.units_combo = QComboBox() self.base_units = QgsUnitTypes.DistanceUnit.DistanceUnknownUnit - for u in (QgsUnitTypes.DistanceUnit.DistanceMeters, - QgsUnitTypes.DistanceUnit.DistanceKilometers, - QgsUnitTypes.DistanceUnit.DistanceFeet, - QgsUnitTypes.DistanceUnit.DistanceMiles, - QgsUnitTypes.DistanceUnit.DistanceYards): + for u in ( + QgsUnitTypes.DistanceUnit.DistanceMeters, + QgsUnitTypes.DistanceUnit.DistanceKilometers, + QgsUnitTypes.DistanceUnit.DistanceFeet, + QgsUnitTypes.DistanceUnit.DistanceMiles, + QgsUnitTypes.DistanceUnit.DistanceYards, + ): self.units_combo.addItem(QgsUnitTypes.toString(u), u) - label_margin = self.fontMetrics().horizontalAdvance('X') + label_margin = self.fontMetrics().horizontalAdvance("X") self.layout().insertSpacing(1, int(label_margin / 2)) self.layout().insertWidget(2, self.label) self.layout().insertWidget(3, self.units_combo) self.layout().insertSpacing(4, int(label_margin / 2)) self.warning_label = QLabel() - icon = QgsApplication.getThemeIcon('mIconWarning.svg') + icon = QgsApplication.getThemeIcon("mIconWarning.svg") size = max(24, self.spnValue.height() * 0.5) self.warning_label.setPixmap(icon.pixmap(icon.actualSize(QSize(size, size)))) - self.warning_label.setToolTip(self.tr('Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results.')) + self.warning_label.setToolTip( + self.tr( + "Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results." + ) + ) self.layout().insertWidget(4, self.warning_label) self.layout().insertSpacing(5, label_margin) @@ -296,7 +326,9 @@ def setUnits(self, units): self.units_combo.setCurrentIndex(self.units_combo.findData(units)) self.units_combo.show() self.label.hide() - self.warning_label.setVisible(units == QgsUnitTypes.DistanceUnit.DistanceDegrees) + self.warning_label.setVisible( + units == QgsUnitTypes.DistanceUnit.DistanceDegrees + ) self.base_units = units def setUnitParameterValue(self, value): @@ -316,7 +348,9 @@ def getValue(self): val = super().getValue() if isinstance(val, float) and self.units_combo.isVisible(): display_unit = self.units_combo.currentData() - return val * QgsUnitTypes.fromUnitToUnitFactor(display_unit, self.base_units) + return val * QgsUnitTypes.fromUnitToUnitFactor( + display_unit, self.base_units + ) return val diff --git a/python/plugins/processing/gui/ParametersPanel.py b/python/plugins/processing/gui/ParametersPanel.py index 2649d95cfe23..c7ddb66ad7c1 100644 --- a/python/plugins/processing/gui/ParametersPanel.py +++ b/python/plugins/processing/gui/ParametersPanel.py @@ -19,22 +19,26 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' - -from qgis.core import (QgsProcessingParameterDefinition, - QgsProcessingParameterExtent, - QgsProject, - QgsProcessingModelAlgorithm, - QgsProcessingOutputLayerDefinition) -from qgis.gui import (QgsProcessingContextGenerator, - QgsProcessingParameterWidgetContext, - QgsProcessingParametersWidget, - QgsGui, - QgsProcessingGui, - QgsProcessingParametersGenerator, - QgsProcessingHiddenWidgetWrapper) +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" + +from qgis.core import ( + QgsProcessingParameterDefinition, + QgsProcessingParameterExtent, + QgsProject, + QgsProcessingModelAlgorithm, + QgsProcessingOutputLayerDefinition, +) +from qgis.gui import ( + QgsProcessingContextGenerator, + QgsProcessingParameterWidgetContext, + QgsProcessingParametersWidget, + QgsGui, + QgsProcessingGui, + QgsProcessingParametersGenerator, + QgsProcessingHiddenWidgetWrapper, +) from qgis.utils import iface from processing.gui.wrappers import WidgetWrapperFactory, WidgetWrapper @@ -92,8 +96,8 @@ def initWidgets(self): if isinstance(self.algorithm(), QgsProcessingModelAlgorithm): widget_context.setModel(self.algorithm()) - in_place_input_parameter_name = 'INPUT' - if hasattr(self.algorithm(), 'inputParameterName'): + in_place_input_parameter_name = "INPUT" + if hasattr(self.algorithm(), "inputParameterName"): in_place_input_parameter_name = self.algorithm().inputParameterName() # Create widgets and put them in layouts @@ -104,12 +108,17 @@ def initWidgets(self): if param.isDestination(): continue else: - if self.in_place and param.name() in (in_place_input_parameter_name, 'OUTPUT'): + if self.in_place and param.name() in ( + in_place_input_parameter_name, + "OUTPUT", + ): # don't show the input/output parameter widgets in in-place mode # we still need to CREATE them, because other wrappers may need to interact # with them (e.g. those parameters which need the input layer for field # selections/crs properties/etc) - self.wrappers[param.name()] = QgsProcessingHiddenWidgetWrapper(param, QgsProcessingGui.WidgetType.Standard, self) + self.wrappers[param.name()] = QgsProcessingHiddenWidgetWrapper( + param, QgsProcessingGui.WidgetType.Standard, self + ) self.wrappers[param.name()].setLinkedVectorLayer(self.active_layer) continue @@ -146,9 +155,12 @@ def initWidgets(self): elif is_python_wrapper: desc = param.description() if isinstance(param, QgsProcessingParameterExtent): - desc += self.tr(' (xmin, xmax, ymin, ymax)') - if param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: - desc += self.tr(' [optional]') + desc += self.tr(" (xmin, xmax, ymin, ymax)") + if ( + param.flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ): + desc += self.tr(" [optional]") widget.setText(desc) self.addParameterWidget(param, widget, stretch) @@ -157,10 +169,15 @@ def initWidgets(self): if output.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden: continue - if self.in_place and output.name() in (in_place_input_parameter_name, 'OUTPUT'): + if self.in_place and output.name() in ( + in_place_input_parameter_name, + "OUTPUT", + ): continue - wrapper = QgsGui.processingGuiRegistry().createParameterWidgetWrapper(output, QgsProcessingGui.WidgetType.Standard) + wrapper = QgsGui.processingGuiRegistry().createParameterWidgetWrapper( + output, QgsProcessingGui.WidgetType.Standard + ) wrapper.setWidgetContext(widget_context) wrapper.registerProcessingContextGenerator(self.context_generator) wrapper.registerProcessingParametersGenerator(self) @@ -196,8 +213,12 @@ def initWidgets(self): for wrapper in list(self.wrappers.values()): wrapper.postInitialize(list(self.wrappers.values())) - def createProcessingParameters(self, flags=QgsProcessingParametersGenerator.Flags()): - include_default = not (flags & QgsProcessingParametersGenerator.Flag.SkipDefaultValueParameters) + def createProcessingParameters( + self, flags=QgsProcessingParametersGenerator.Flags() + ): + include_default = not ( + flags & QgsProcessingParametersGenerator.Flag.SkipDefaultValueParameters + ) parameters = {} for p, v in self.extra_parameters.items(): parameters[p] = v @@ -220,7 +241,10 @@ def createProcessingParameters(self, flags=QgsProcessingParametersGenerator.Flag else: widget = wrapper.wrappedWidget() - if not isinstance(wrapper, QgsProcessingHiddenWidgetWrapper) and widget is None: + if ( + not isinstance(wrapper, QgsProcessingHiddenWidgetWrapper) + and widget is None + ): continue value = wrapper.parameterValue() @@ -230,8 +254,8 @@ def createProcessingParameters(self, flags=QgsProcessingParametersGenerator.Flag if not param.checkValueIsAcceptable(value): raise AlgorithmDialogBase.InvalidParameterValue(param, widget) else: - if self.in_place and param.name() == 'OUTPUT': - parameters[param.name()] = 'memory:' + if self.in_place and param.name() == "OUTPUT": + parameters[param.name()] = "memory:" continue try: @@ -243,7 +267,7 @@ def createProcessingParameters(self, flags=QgsProcessingParametersGenerator.Flag value = wrapper.parameterValue() dest_project = None - if wrapper.customProperties().get('OPEN_AFTER_RUNNING'): + if wrapper.customProperties().get("OPEN_AFTER_RUNNING"): dest_project = QgsProject.instance() if value and isinstance(value, QgsProcessingOutputLayerDefinition): diff --git a/python/plugins/processing/gui/PointMapTool.py b/python/plugins/processing/gui/PointMapTool.py index 739698a2717a..c2528df86af9 100644 --- a/python/plugins/processing/gui/PointMapTool.py +++ b/python/plugins/processing/gui/PointMapTool.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Alexander Bruy" from qgis.PyQt.QtCore import Qt, pyqtSignal diff --git a/python/plugins/processing/gui/PointSelectionPanel.py b/python/plugins/processing/gui/PointSelectionPanel.py index 9baf229d965c..65e87eb17fb1 100644 --- a/python/plugins/processing/gui/PointSelectionPanel.py +++ b/python/plugins/processing/gui/PointSelectionPanel.py @@ -15,16 +15,14 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Alexander Bruy" import os import warnings -from qgis.core import (QgsProject, - QgsReferencedPointXY, - QgsPointXY) +from qgis.core import QgsProject, QgsReferencedPointXY, QgsPointXY from qgis.PyQt import uic from qgis.utils import iface @@ -36,7 +34,8 @@ with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'widgetBaseSelector.ui')) + os.path.join(pluginPath, "ui", "widgetBaseSelector.ui") + ) class PointSelectionPanel(BASE, WIDGET): @@ -62,7 +61,7 @@ def __init__(self, dialog, default=None): self.tool = None if default: - tokens = str(default).split(',') + tokens = str(default).split(",") if len(tokens) == 2: try: float(tokens[0]) @@ -77,10 +76,10 @@ def selectOnCanvas(self): self.dialog.showMinimized() def updatePoint(self, point, button): - s = f'{point.x()},{point.y()}' + s = f"{point.x()},{point.y()}" self.crs = QgsProject.instance().crs() if self.crs.isValid(): - s += ' [' + self.crs.authid() + ']' + s += " [" + self.crs.authid() + "]" self.leText.setText(s) def pointPicked(self): @@ -91,7 +90,7 @@ def pointPicked(self): self.dialog.activateWindow() def getValue(self): - if str(self.leText.text()).strip() != '': + if str(self.leText.text()).strip() != "": return str(self.leText.text()) else: return None diff --git a/python/plugins/processing/gui/Postprocessing.py b/python/plugins/processing/gui/Postprocessing.py index f1b0fec6b72f..d36ce1f34b53 100644 --- a/python/plugins/processing/gui/Postprocessing.py +++ b/python/plugins/processing/gui/Postprocessing.py @@ -15,17 +15,12 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import traceback -from typing import ( - Dict, - List, - Optional, - Tuple -) +from typing import Dict, List, Optional, Tuple from qgis.PyQt.QtCore import QCoreApplication from qgis.core import ( @@ -39,7 +34,7 @@ QgsProcessingAlgorithm, QgsLayerTreeLayer, QgsLayerTreeGroup, - QgsLayerTreeNode + QgsLayerTreeNode, ) from qgis.utils import iface @@ -47,14 +42,16 @@ from processing.gui.RenderingStyles import RenderingStyles -SORT_ORDER_CUSTOM_PROPERTY = '_processing_sort_order' +SORT_ORDER_CUSTOM_PROPERTY = "_processing_sort_order" -def determine_output_name(dest_id: str, - details: QgsProcessingContext.LayerDetails, - alg: QgsProcessingAlgorithm, - context: QgsProcessingContext, - parameters: Dict) -> str: +def determine_output_name( + dest_id: str, + details: QgsProcessingContext.LayerDetails, + alg: QgsProcessingAlgorithm, + context: QgsProcessingContext, + parameters: dict, +) -> str: """ If running a model, the execution will arrive here when an algorithm that is part of that model is executed. We check if @@ -66,9 +63,9 @@ def determine_output_name(dest_id: str, continue output_value = parameters[out.name()] if hasattr(output_value, "sink"): - output_value = output_value.sink.valueAsString( - context.expressionContext() - )[0] + output_value = output_value.sink.valueAsString(context.expressionContext())[ + 0 + ] else: output_value = str(output_value) if output_value == dest_id: @@ -77,9 +74,9 @@ def determine_output_name(dest_id: str, return details.outputName -def post_process_layer(output_name: str, - layer: QgsMapLayer, - alg: QgsProcessingAlgorithm): +def post_process_layer( + output_name: str, layer: QgsMapLayer, alg: QgsProcessingAlgorithm +): """ Applies post-processing steps to a layer """ @@ -92,20 +89,20 @@ def post_process_layer(output_name: str, style = ProcessingConfig.getSetting(ProcessingConfig.RASTER_STYLE) elif layer.type() == Qgis.LayerType.Vector: if layer.geometryType() == QgsWkbTypes.GeometryType.PointGeometry: - style = ProcessingConfig.getSetting( - ProcessingConfig.VECTOR_POINT_STYLE) + style = ProcessingConfig.getSetting(ProcessingConfig.VECTOR_POINT_STYLE) elif layer.geometryType() == QgsWkbTypes.GeometryType.LineGeometry: - style = ProcessingConfig.getSetting( - ProcessingConfig.VECTOR_LINE_STYLE) + style = ProcessingConfig.getSetting(ProcessingConfig.VECTOR_LINE_STYLE) else: style = ProcessingConfig.getSetting( - ProcessingConfig.VECTOR_POLYGON_STYLE) + ProcessingConfig.VECTOR_POLYGON_STYLE + ) if style: layer.loadNamedStyle(style) if layer.type() == Qgis.LayerType.PointCloud: try: from qgis._3d import QgsPointCloudLayer3DRenderer + if layer.renderer3D() is None: # If the layer has no 3D renderer and syncing 3D to 2D # renderer is enabled, we create a renderer and set it up @@ -119,33 +116,36 @@ def post_process_layer(output_name: str, QCoreApplication.translate( "Postprocessing", "3D library is not available, " - "can't assign a 3d renderer to a layer." + "can't assign a 3d renderer to a layer.", ) ) -def create_layer_tree_layer(layer: QgsMapLayer, - details: QgsProcessingContext.LayerDetails) \ - -> QgsLayerTreeLayer: +def create_layer_tree_layer( + layer: QgsMapLayer, details: QgsProcessingContext.LayerDetails +) -> QgsLayerTreeLayer: """ Applies post-processing steps to a QgsLayerTreeLayer created for an algorithm's output """ layer_tree_layer = QgsLayerTreeLayer(layer) - if ProcessingConfig.getSetting(ProcessingConfig.VECTOR_FEATURE_COUNT) and \ - layer.type() == Qgis.LayerType.Vector: + if ( + ProcessingConfig.getSetting(ProcessingConfig.VECTOR_FEATURE_COUNT) + and layer.type() == Qgis.LayerType.Vector + ): layer_tree_layer.setCustomProperty("showFeatureCount", True) if details.layerSortKey: - layer_tree_layer.setCustomProperty(SORT_ORDER_CUSTOM_PROPERTY, - details.layerSortKey) + layer_tree_layer.setCustomProperty( + SORT_ORDER_CUSTOM_PROPERTY, details.layerSortKey + ) return layer_tree_layer -def get_layer_tree_results_group(details: QgsProcessingContext.LayerDetails, - context: QgsProcessingContext) \ - -> Optional[QgsLayerTreeGroup]: +def get_layer_tree_results_group( + details: QgsProcessingContext.LayerDetails, context: QgsProcessingContext +) -> Optional[QgsLayerTreeGroup]: """ Returns the destination layer tree group to store results in, or None if there is no specific destination tree group associated with the layer @@ -158,13 +158,16 @@ def get_layer_tree_results_group(details: QgsProcessingContext.LayerDetails, # if a specific results group is specified in Processing settings, # respect it (and create if necessary) results_group_name = ProcessingConfig.getSetting( - ProcessingConfig.RESULTS_GROUP_NAME) + ProcessingConfig.RESULTS_GROUP_NAME + ) if results_group_name: results_group = destination_project.layerTreeRoot().findGroup( - results_group_name) + results_group_name + ) if not results_group: results_group = destination_project.layerTreeRoot().insertGroup( - 0, results_group_name) + 0, results_group_name + ) results_group.setExpanded(True) # if this particular output layer has a specific output group assigned, @@ -175,8 +178,7 @@ def get_layer_tree_results_group(details: QgsProcessingContext.LayerDetails, group = results_group.findGroup(details.groupName) if not group: - group = results_group.insertGroup( - 0, details.groupName) + group = results_group.insertGroup(0, details.groupName) group.setExpanded(True) else: group = results_group @@ -184,10 +186,12 @@ def get_layer_tree_results_group(details: QgsProcessingContext.LayerDetails, return group -def handleAlgorithmResults(alg: QgsProcessingAlgorithm, - context: QgsProcessingContext, - feedback: Optional[QgsProcessingFeedback] = None, - parameters: Optional[Dict] = None): +def handleAlgorithmResults( + alg: QgsProcessingAlgorithm, + context: QgsProcessingContext, + feedback: Optional[QgsProcessingFeedback] = None, + parameters: Optional[dict] = None, +): if not parameters: parameters = {} if feedback is None: @@ -195,16 +199,14 @@ def handleAlgorithmResults(alg: QgsProcessingAlgorithm, wrong_layers = [] feedback.setProgressText( - QCoreApplication.translate( - 'Postprocessing', - 'Loading resulting layers' - ) + QCoreApplication.translate("Postprocessing", "Loading resulting layers") ) i = 0 - added_layers: List[Tuple[Optional[QgsLayerTreeGroup], QgsLayerTreeLayer]] = [] - layers_to_post_process: List[Tuple[QgsMapLayer, - QgsProcessingContext.LayerDetails]] = [] + added_layers: list[tuple[Optional[QgsLayerTreeGroup], QgsLayerTreeLayer]] = [] + layers_to_post_process: list[ + tuple[QgsMapLayer, QgsProcessingContext.LayerDetails] + ] = [] for dest_id, details in context.layersToLoadOnCompletion().items(): if feedback.isCanceled(): @@ -218,9 +220,7 @@ def handleAlgorithmResults(alg: QgsProcessingAlgorithm, try: layer = QgsProcessingUtils.mapLayerFromString( - dest_id, - context, - typeHint=details.layerTypeHint + dest_id, context, typeHint=details.layerTypeHint ) if layer is not None: details.setOutputLayerName(layer) @@ -256,18 +256,19 @@ def handleAlgorithmResults(alg: QgsProcessingAlgorithm, except Exception: QgsMessageLog.logMessage( QCoreApplication.translate( - 'Postprocessing', - "Error loading result layer:" - ) + "\n" + traceback.format_exc(), - 'Processing', - Qgis.MessageLevel.Critical) + "Postprocessing", "Error loading result layer:" + ) + + "\n" + + traceback.format_exc(), + "Processing", + Qgis.MessageLevel.Critical, + ) wrong_layers.append(str(dest_id)) i += 1 # sort added layer tree layers sorted_layer_tree_layers = sorted( - added_layers, - key=lambda x: x[1].customProperty(SORT_ORDER_CUSTOM_PROPERTY, 0) + added_layers, key=lambda x: x[1].customProperty(SORT_ORDER_CUSTOM_PROPERTY, 0) ) have_set_active_layer = False @@ -286,10 +287,9 @@ def handleAlgorithmResults(alg: QgsProcessingAlgorithm, if isinstance(current_selected_node, QgsLayerTreeLayer): current_node_group = current_selected_node.parent() current_node_index = current_node_group.children().index( - current_selected_node) - current_node_group.insertChildNode( - current_node_index, - layer_node) + current_selected_node + ) + current_node_group.insertChildNode(current_node_index, layer_node) elif isinstance(current_selected_node, QgsLayerTreeGroup): current_selected_node.insertChildNode(0, layer_node) elif context.project(): @@ -302,10 +302,7 @@ def handleAlgorithmResults(alg: QgsProcessingAlgorithm, # all layers have been added to the layer tree, so safe to call # postProcessors now for layer, details in layers_to_post_process: - details.postProcessor().postProcessLayer( - layer, - context, - feedback) + details.postProcessor().postProcessLayer(layer, context, feedback) if iface is not None: iface.layerTreeView().setUpdatesEnabled(True) @@ -314,14 +311,14 @@ def handleAlgorithmResults(alg: QgsProcessingAlgorithm, if wrong_layers: msg = QCoreApplication.translate( - 'Postprocessing', - "The following layers were not correctly generated." + "Postprocessing", "The following layers were not correctly generated." ) - msg += "\n" + "\n".join([f"• {lay}" for lay in wrong_layers]) + '\n' + msg += "\n" + "\n".join([f"• {lay}" for lay in wrong_layers]) + "\n" msg += QCoreApplication.translate( - 'Postprocessing', + "Postprocessing", "You can check the 'Log Messages Panel' in QGIS main window " - "to find more information about the execution of the algorithm.") + "to find more information about the execution of the algorithm.", + ) feedback.reportError(msg) return len(wrong_layers) == 0 diff --git a/python/plugins/processing/gui/ProcessingToolbox.py b/python/plugins/processing/gui/ProcessingToolbox.py index c380d1ccd5a9..1560ca2d33d9 100644 --- a/python/plugins/processing/gui/ProcessingToolbox.py +++ b/python/plugins/processing/gui/ProcessingToolbox.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import operator import os @@ -27,21 +27,20 @@ from qgis.PyQt.QtCore import Qt, QCoreApplication, pyqtSignal from qgis.PyQt.QtWidgets import QWidget, QToolButton, QMenu, QAction from qgis.utils import iface -from qgis.core import (QgsWkbTypes, - QgsMapLayerType, - QgsApplication, - QgsProcessingAlgorithm) -from qgis.gui import (QgsGui, - QgsDockWidget, - QgsProcessingToolboxProxyModel) +from qgis.core import ( + QgsWkbTypes, + QgsMapLayerType, + QgsApplication, + QgsProcessingAlgorithm, +) +from qgis.gui import QgsGui, QgsDockWidget, QgsProcessingToolboxProxyModel from processing.gui.Postprocessing import handleAlgorithmResults from processing.core.ProcessingConfig import ProcessingConfig from processing.gui.MessageDialog import MessageDialog from processing.gui.EditRenderingStylesDialog import EditRenderingStylesDialog from processing.gui.MessageBarProgress import MessageBarProgress -from processing.gui.ProviderActions import (ProviderActions, - ProviderContextMenuActions) +from processing.gui.ProviderActions import ProviderActions, ProviderContextMenuActions from processing.tools import dataobjects pluginPath = os.path.split(os.path.dirname(__file__))[0] @@ -49,13 +48,14 @@ with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'ProcessingToolbox.ui')) + os.path.join(pluginPath, "ui", "ProcessingToolbox.ui") + ) class ProcessingToolbox(QgsDockWidget, WIDGET): - ALG_ITEM = 'ALG_ITEM' - PROVIDER_ITEM = 'PROVIDER_ITEM' - GROUP_ITEM = 'GROUP_ITEM' + ALG_ITEM = "ALG_ITEM" + PROVIDER_ITEM = "PROVIDER_ITEM" + GROUP_ITEM = "GROUP_ITEM" NAME_ROLE = Qt.ItemDataRole.UserRole TAG_ROLE = Qt.ItemDataRole.UserRole + 1 @@ -69,13 +69,19 @@ def __init__(self): self.tipWasClosed = False self.in_place_mode = False self.setupUi(self) - self.setAllowedAreas(Qt.DockWidgetArea.LeftDockWidgetArea | Qt.DockWidgetArea.RightDockWidgetArea) + self.setAllowedAreas( + Qt.DockWidgetArea.LeftDockWidgetArea | Qt.DockWidgetArea.RightDockWidgetArea + ) self.processingToolbar.setIconSize(iface.iconSize(True)) - self.algorithmTree.setRegistry(QgsApplication.processingRegistry(), - QgsGui.instance().processingRecentAlgorithmLog(), - QgsGui.instance().processingFavoriteAlgorithmManager()) - filters = QgsProcessingToolboxProxyModel.Filters(QgsProcessingToolboxProxyModel.Filter.FilterToolbox) + self.algorithmTree.setRegistry( + QgsApplication.processingRegistry(), + QgsGui.instance().processingRecentAlgorithmLog(), + QgsGui.instance().processingFavoriteAlgorithmManager(), + ) + filters = QgsProcessingToolboxProxyModel.Filters( + QgsProcessingToolboxProxyModel.Filter.FilterToolbox + ) if ProcessingConfig.getSetting(ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES): filters |= QgsProcessingToolboxProxyModel.Filter.FilterShowKnownIssues self.algorithmTree.setFilters(filters) @@ -84,8 +90,7 @@ def __init__(self): self.searchBox.textChanged.connect(self.set_filter_string) self.searchBox.returnPressed.connect(self.activateCurrent) - self.algorithmTree.customContextMenuRequested.connect( - self.showPopupMenu) + self.algorithmTree.customContextMenuRequested.connect(self.showPopupMenu) self.algorithmTree.doubleClicked.connect(self.executeAlgorithm) self.txtTip.setVisible(self.disabledProviders()) @@ -94,12 +99,14 @@ def openSettings(url): self.txtTip.setVisible(False) self.tipWasClosed = True else: - iface.showOptionsDialog(iface.mainWindow(), 'processingOptions') + iface.showOptionsDialog(iface.mainWindow(), "processingOptions") self.txtTip.setVisible(self.disabledProviders()) self.txtTip.linkActivated.connect(openSettings) - if hasattr(self.searchBox, 'setPlaceholderText'): - self.searchBox.setPlaceholderText(QCoreApplication.translate('ProcessingToolbox', 'Search…')) + if hasattr(self.searchBox, "setPlaceholderText"): + self.searchBox.setPlaceholderText( + QCoreApplication.translate("ProcessingToolbox", "Search…") + ) # connect to existing providers for p in QgsApplication.processingRegistry().providers(): @@ -121,12 +128,16 @@ def set_filter_string(self, string): self.algorithmTree.setFilterString(string) def set_in_place_edit_mode(self, enabled): - filters = QgsProcessingToolboxProxyModel.Filters(QgsProcessingToolboxProxyModel.Filter.FilterToolbox) + filters = QgsProcessingToolboxProxyModel.Filters( + QgsProcessingToolboxProxyModel.Filter.FilterToolbox + ) if ProcessingConfig.getSetting(ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES): filters |= QgsProcessingToolboxProxyModel.Filter.FilterShowKnownIssues if enabled: - self.algorithmTree.setFilters(filters | QgsProcessingToolboxProxyModel.Filter.FilterInPlace) + self.algorithmTree.setFilters( + filters | QgsProcessingToolboxProxyModel.Filter.FilterInPlace + ) else: self.algorithmTree.setFilters(filters) self.in_place_mode = enabled @@ -150,7 +161,7 @@ def disabledProviders(self): def addProviderActions(self, provider): if provider.id() in ProviderActions.actions: toolbarButton = QToolButton() - toolbarButton.setObjectName('provideraction_' + provider.id()) + toolbarButton.setObjectName("provideraction_" + provider.id()) toolbarButton.setIcon(provider.icon()) toolbarButton.setToolTip(provider.name()) toolbarButton.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup) @@ -171,7 +182,7 @@ def addProvider(self, provider_id): self.addProviderActions(provider) def removeProvider(self, provider_id): - button = self.findChild(QToolButton, 'provideraction-' + provider_id) + button = self.findChild(QToolButton, "provideraction-" + provider_id) if button: self.processingToolbar.removeChild(button) @@ -180,28 +191,44 @@ def showPopupMenu(self, point): popupmenu = QMenu() alg = self.algorithmTree.algorithmForIndex(index) if alg is not None: - executeAction = QAction(QCoreApplication.translate('ProcessingToolbox', 'Execute…'), popupmenu) + executeAction = QAction( + QCoreApplication.translate("ProcessingToolbox", "Execute…"), popupmenu + ) executeAction.triggered.connect(self.executeAlgorithm) popupmenu.addAction(executeAction) if alg.flags() & QgsProcessingAlgorithm.Flag.FlagSupportsBatch: executeBatchAction = QAction( - QCoreApplication.translate('ProcessingToolbox', 'Execute as Batch Process…'), - popupmenu) + QCoreApplication.translate( + "ProcessingToolbox", "Execute as Batch Process…" + ), + popupmenu, + ) executeBatchAction.triggered.connect( - self.executeAlgorithmAsBatchProcess) + self.executeAlgorithmAsBatchProcess + ) popupmenu.addAction(executeBatchAction) popupmenu.addSeparator() editRenderingStylesAction = QAction( - QCoreApplication.translate('ProcessingToolbox', 'Edit Rendering Styles for Outputs…'), - popupmenu) - editRenderingStylesAction.triggered.connect( - self.editRenderingStyles) + QCoreApplication.translate( + "ProcessingToolbox", "Edit Rendering Styles for Outputs…" + ), + popupmenu, + ) + editRenderingStylesAction.triggered.connect(self.editRenderingStyles) popupmenu.addAction(editRenderingStylesAction) popupmenu.addSeparator() - actionText = QCoreApplication.translate('ProcessingToolbox', 'Add to Favorites') - if QgsGui.instance().processingFavoriteAlgorithmManager().isFavorite(alg.id()): - actionText = QCoreApplication.translate('ProcessingToolbox', 'Remove from Favorites') + actionText = QCoreApplication.translate( + "ProcessingToolbox", "Add to Favorites" + ) + if ( + QgsGui.instance() + .processingFavoriteAlgorithmManager() + .isFavorite(alg.id()) + ): + actionText = QCoreApplication.translate( + "ProcessingToolbox", "Remove from Favorites" + ) favoriteAction = QAction(actionText, popupmenu) favoriteAction.triggered.connect(self.toggleFavorite) popupmenu.addAction(favoriteAction) @@ -214,8 +241,7 @@ def showPopupMenu(self, point): if action.is_separator: popupmenu.addSeparator() elif action.isEnabled(): - contextMenuAction = QAction(action.name, - popupmenu) + contextMenuAction = QAction(action.name, popupmenu) contextMenuAction.setIcon(action.icon()) contextMenuAction.triggered.connect(action.execute) popupmenu.addAction(contextMenuAction) @@ -223,7 +249,11 @@ def showPopupMenu(self, point): popupmenu.exec(self.algorithmTree.mapToGlobal(point)) def editRenderingStyles(self): - alg = self.algorithmTree.selectedAlgorithm().create() if self.algorithmTree.selectedAlgorithm() is not None else None + alg = ( + self.algorithmTree.selectedAlgorithm().create() + if self.algorithmTree.selectedAlgorithm() is not None + else None + ) if alg is not None: dlg = EditRenderingStylesDialog(alg) dlg.exec() @@ -244,7 +274,11 @@ def executeAlgorithm(self): def toggleFavorite(self): alg = self.algorithmTree.selectedAlgorithm() if alg is not None: - if QgsGui.instance().processingFavoriteAlgorithmManager().isFavorite(alg.id()): + if ( + QgsGui.instance() + .processingFavoriteAlgorithmManager() + .isFavorite(alg.id()) + ): QgsGui.instance().processingFavoriteAlgorithmManager().remove(alg.id()) else: QgsGui.instance().processingFavoriteAlgorithmManager().add(alg.id()) diff --git a/python/plugins/processing/gui/ProviderActions.py b/python/plugins/processing/gui/ProviderActions.py index 604e21e25db9..974fc5694a87 100644 --- a/python/plugins/processing/gui/ProviderActions.py +++ b/python/plugins/processing/gui/ProviderActions.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'April 2017' -__copyright__ = '(C) 2017, Nyall Dason' +__author__ = "Nyall Dawson" +__date__ = "April 2017" +__copyright__ = "(C) 2017, Nyall Dason" class ProviderActions: @@ -25,12 +25,12 @@ class ProviderActions: @staticmethod def registerProviderActions(provider, actions): - """ Adds actions for a provider """ + """Adds actions for a provider""" ProviderActions.actions[provider.id()] = actions @staticmethod def deregisterProviderActions(provider): - """ Removes actions for a provider """ + """Removes actions for a provider""" if provider.id() in ProviderActions.actions: del ProviderActions.actions[provider.id()] @@ -41,11 +41,11 @@ class ProviderContextMenuActions: @staticmethod def registerProviderContextMenuActions(actions): - """ Adds context menu actions for a provider """ + """Adds context menu actions for a provider""" ProviderContextMenuActions.actions.extend(actions) @staticmethod def deregisterProviderContextMenuActions(actions): - """ Removes context menu actions for a provider """ + """Removes context menu actions for a provider""" for act in actions: ProviderContextMenuActions.actions.remove(act) diff --git a/python/plugins/processing/gui/RangePanel.py b/python/plugins/processing/gui/RangePanel.py index 63bb16cca0b4..f4959c78929e 100644 --- a/python/plugins/processing/gui/RangePanel.py +++ b/python/plugins/processing/gui/RangePanel.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import warnings @@ -33,7 +33,8 @@ with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'widgetRangeSelector.ui')) + os.path.join(pluginPath, "ui", "widgetRangeSelector.ui") + ) class RangePanel(BASE, WIDGET): @@ -70,16 +71,16 @@ def setMaxMin(self): self.hasChanged.emit() def getValue(self): - return f'{self.spnMin.value()},{self.spnMax.value()}' + return f"{self.spnMin.value()},{self.spnMax.value()}" def getValues(self): value = self.getValue() if value: - return [float(a) for a in value.split(',')] + return [float(a) for a in value.split(",")] def setValue(self, value): try: - values = value.split(',') + values = value.split(",") minVal = float(values[0]) maxVal = float(values[1]) self.spnMin.setValue(float(minVal)) diff --git a/python/plugins/processing/gui/RectangleMapTool.py b/python/plugins/processing/gui/RectangleMapTool.py index 67e9d06fc329..34563b4a8ece 100644 --- a/python/plugins/processing/gui/RectangleMapTool.py +++ b/python/plugins/processing/gui/RectangleMapTool.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" from qgis.PyQt.QtCore import pyqtSignal from qgis.PyQt.QtGui import QColor @@ -33,7 +33,9 @@ def __init__(self, canvas): self.canvas = canvas QgsMapToolEmitPoint.__init__(self, self.canvas) - self.rubberBand = QgsRubberBand(self.canvas, QgsWkbTypes.GeometryType.PolygonGeometry) + self.rubberBand = QgsRubberBand( + self.canvas, QgsWkbTypes.GeometryType.PolygonGeometry + ) self.rubberBand.setColor(QColor(255, 0, 0, 100)) self.rubberBand.setWidth(2) @@ -83,8 +85,10 @@ def showRect(self, startPoint, endPoint): def rectangle(self): if self.startPoint is None or self.endPoint is None: return None - elif self.startPoint.x() == self.endPoint.x() or \ - self.startPoint.y() == self.endPoint.y(): + elif ( + self.startPoint.x() == self.endPoint.x() + or self.startPoint.y() == self.endPoint.y() + ): return None return QgsRectangle(self.startPoint, self.endPoint) diff --git a/python/plugins/processing/gui/RenderingStyleFilePanel.py b/python/plugins/processing/gui/RenderingStyleFilePanel.py index 72ef4ff173b0..806cc33602b2 100644 --- a/python/plugins/processing/gui/RenderingStyleFilePanel.py +++ b/python/plugins/processing/gui/RenderingStyleFilePanel.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import warnings @@ -32,7 +32,8 @@ with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'widgetBaseSelector.ui')) + os.path.join(pluginPath, "ui", "widgetBaseSelector.ui") + ) class RenderingStyleFilePanel(BASE, WIDGET): @@ -44,9 +45,12 @@ def __init__(self): self.btnSelect.clicked.connect(self.showSelectionDialog) def showSelectionDialog(self): - filename, selected_filter = QFileDialog.getOpenFileName(self, - self.tr('Select Style File'), '', - self.tr('QGIS Layer Style File (*.qml *.QML)')) + filename, selected_filter = QFileDialog.getOpenFileName( + self, + self.tr("Select Style File"), + "", + self.tr("QGIS Layer Style File (*.qml *.QML)"), + ) if filename: self.leText.setText(filename) @@ -56,5 +60,5 @@ def setText(self, text): def getValue(self): s = self.leText.text() if isWindows(): - s = s.replace('\\', '/') + s = s.replace("\\", "/") return s diff --git a/python/plugins/processing/gui/RenderingStyles.py b/python/plugins/processing/gui/RenderingStyles.py index c9ba752aa784..72f483d0af8f 100644 --- a/python/plugins/processing/gui/RenderingStyles.py +++ b/python/plugins/processing/gui/RenderingStyles.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os from processing.tools.system import userFolder @@ -33,31 +33,32 @@ def addAlgStylesAndSave(algname, styles): @staticmethod def configFile(): - return os.path.join(userFolder(), 'processing_qgis_styles.conf') + return os.path.join(userFolder(), "processing_qgis_styles.conf") @staticmethod def loadStyles(): if not os.path.isfile(RenderingStyles.configFile()): return with open(RenderingStyles.configFile()) as lines: - line = lines.readline().strip('\n') - while line != '': - tokens = line.split('|') + line = lines.readline().strip("\n") + while line != "": + tokens = line.split("|") if tokens[0] in list(RenderingStyles.styles.keys()): RenderingStyles.styles[tokens[0]][tokens[1]] = tokens[2] else: alg = {} alg[tokens[1]] = tokens[2] RenderingStyles.styles[tokens[0]] = alg - line = lines.readline().strip('\n') + line = lines.readline().strip("\n") @staticmethod def saveSettings(): - with open(RenderingStyles.configFile(), 'w') as fout: + with open(RenderingStyles.configFile(), "w") as fout: for alg in list(RenderingStyles.styles.keys()): for out in list(RenderingStyles.styles[alg].keys()): - fout.write(alg + '|' + out + '|' + - RenderingStyles.styles[alg][out] + '\n') + fout.write( + alg + "|" + out + "|" + RenderingStyles.styles[alg][out] + "\n" + ) @staticmethod def getStyle(algname, outputname): diff --git a/python/plugins/processing/gui/ResultsDock.py b/python/plugins/processing/gui/ResultsDock.py index 29ce184978c6..393c817179ee 100644 --- a/python/plugins/processing/gui/ResultsDock.py +++ b/python/plugins/processing/gui/ResultsDock.py @@ -15,18 +15,16 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import time import warnings from qgis.PyQt import uic -from qgis.PyQt.QtCore import (QUrl, - QFileInfo, - QDir) +from qgis.PyQt.QtCore import QUrl, QFileInfo, QDir from qgis.gui import QgsDockWidget from qgis.PyQt.QtGui import QDesktopServices from qgis.PyQt.QtWidgets import QTreeWidgetItem @@ -37,8 +35,7 @@ with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) - WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, 'ui', 'resultsdockbase.ui')) + WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "ui", "resultsdockbase.ui")) class ResultsDock(QgsDockWidget, WIDGET): @@ -90,6 +87,11 @@ class TreeResultItem(QTreeWidgetItem): def __init__(self, result): QTreeWidgetItem.__init__(self) self.setIcon(0, result.icon) - self.setText(0, '{} [{}]'.format(result.name, time.strftime('%I:%M:%S%p', result.timestamp))) + self.setText( + 0, + "{} [{}]".format( + result.name, time.strftime("%I:%M:%S%p", result.timestamp) + ), + ) self.algorithm = result.name self.filename = result.filename diff --git a/python/plugins/processing/gui/TestTools.py b/python/plugins/processing/gui/TestTools.py index 7d5f8cf93e19..d03ff057ca3b 100644 --- a/python/plugins/processing/gui/TestTools.py +++ b/python/plugins/processing/gui/TestTools.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'February 2013' -__copyright__ = '(C) 2013, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "February 2013" +__copyright__ = "(C) 2013, Victor Olaya" import os import posixpath @@ -31,25 +31,27 @@ from numpy import nan_to_num -from qgis.core import (QgsApplication, - QgsProcessing, - QgsProcessingParameterDefinition, - QgsProcessingParameterBoolean, - QgsProcessingParameterNumber, - QgsProcessingParameterDistance, - QgsProcessingParameterDuration, - QgsProcessingParameterFile, - QgsProcessingParameterBand, - QgsProcessingParameterString, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterMultipleLayers, - QgsProcessingParameterRasterDestination, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterVectorDestination, - QgsProcessingParameterFileDestination, - QgsProcessingParameterEnum) +from qgis.core import ( + QgsApplication, + QgsProcessing, + QgsProcessingParameterDefinition, + QgsProcessingParameterBoolean, + QgsProcessingParameterNumber, + QgsProcessingParameterDistance, + QgsProcessingParameterDuration, + QgsProcessingParameterFile, + QgsProcessingParameterBand, + QgsProcessingParameterString, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterMultipleLayers, + QgsProcessingParameterRasterDestination, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterVectorDestination, + QgsProcessingParameterFileDestination, + QgsProcessingParameterEnum, +) from qgis.PyQt.QtCore import QCoreApplication, QMetaObject from qgis.PyQt.QtWidgets import QDialog, QVBoxLayout, QTextEdit, QMessageBox @@ -71,13 +73,13 @@ def extractSchemaPath(filepath): """ parts = [] schema = None - localpath = '' + localpath = "" path = filepath part = True while part and filepath: (path, part) = os.path.split(path) - if part == 'testdata' and not localpath: + if part == "testdata" and not localpath: localparts = parts localparts.reverse() # we always want posix style paths here @@ -88,12 +90,12 @@ def extractSchemaPath(filepath): parts.reverse() try: - testsindex = parts.index('tests') + testsindex = parts.index("tests") except ValueError: - return '', filepath + return "", filepath - if parts[testsindex - 1] == 'processing': - schema = 'proc' + if parts[testsindex - 1] == "processing": + schema = "proc" return schema, localpath @@ -111,7 +113,7 @@ def parseParameters(command): separator = m.group(3) # Handle special values: - if result == 'None': + if result == "None": result = None elif result.lower() == str(True).lower(): result = True @@ -131,13 +133,13 @@ def splitAlgIdAndParameters(command): Extracts the algorithm ID and input parameter list from a processing runalg command """ exp = re.compile(r"""['"](.*?)['"]\s*,\s*(.*)""") - m = exp.search(command[len('processing.run('):-1]) + m = exp.search(command[len("processing.run(") : -1]) alg_id = m.group(1) params = m.group(2) # replace QgsCoordinateReferenceSystem('EPSG:4325') with just string value exp = re.compile(r"""QgsCoordinateReferenceSystem\((['"].*?['"])\)""") - params = exp.sub('\\1', params) + params = exp.sub("\\1", params) return alg_id, ast.literal_eval(params) @@ -149,15 +151,18 @@ def createTest(text): alg = QgsApplication.processingRegistry().createAlgorithmById(alg_id) - definition['name'] = f'Test ({alg_id})' - definition['algorithm'] = alg_id + definition["name"] = f"Test ({alg_id})" + definition["algorithm"] = alg_id params = {} results = {} i = 0 for param in alg.parameterDefinitions(): - if param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden or param.isDestination(): + if ( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden + or param.isDestination() + ): continue if not param.name() in parameters: @@ -166,27 +171,31 @@ def createTest(text): i += 1 token = parameters[param.name()] # Handle empty parameters that are optionals - if param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional and token is None: + if ( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + and token is None + ): continue - if isinstance(param, (QgsProcessingParameterVectorLayer, QgsProcessingParameterFeatureSource)): + if isinstance( + param, + (QgsProcessingParameterVectorLayer, QgsProcessingParameterFeatureSource), + ): schema, filepath = extractSchemaPath(token) - p = { - 'type': 'vector', - 'name': filepath - } + p = {"type": "vector", "name": filepath} if not schema: - p['location'] = '[The source data is not in the testdata directory. Please use data in the processing/tests/testdata folder.]' + p["location"] = ( + "[The source data is not in the testdata directory. Please use data in the processing/tests/testdata folder.]" + ) params[param.name()] = p elif isinstance(param, QgsProcessingParameterRasterLayer): schema, filepath = extractSchemaPath(token) - p = { - 'type': 'raster', - 'name': filepath - } + p = {"type": "raster", "name": filepath} if not schema: - p['location'] = '[The source data is not in the testdata directory. Please use data in the processing/tests/testdata folder.]' + p["location"] = ( + "[The source data is not in the testdata directory. Please use data in the processing/tests/testdata folder.]" + ) params[param.name()] = p elif isinstance(param, QgsProcessingParameterMultipleLayers): @@ -195,41 +204,44 @@ def createTest(text): # Handle datatype detection dataType = param.layerType() - if dataType in [QgsProcessing.SourceType.TypeVectorAnyGeometry, QgsProcessing.SourceType.TypeVectorPoint, QgsProcessing.SourceType.TypeVectorLine, QgsProcessing.SourceType.TypeVectorPolygon, QgsProcessing.SourceType.TypeVector]: - dataType = 'vector' + if dataType in [ + QgsProcessing.SourceType.TypeVectorAnyGeometry, + QgsProcessing.SourceType.TypeVectorPoint, + QgsProcessing.SourceType.TypeVectorLine, + QgsProcessing.SourceType.TypeVectorPolygon, + QgsProcessing.SourceType.TypeVector, + ]: + dataType = "vector" else: - dataType = 'raster' + dataType = "raster" schema = None for mp in multiparams: schema, filepath = extractSchemaPath(mp) - newparam.append({ - 'type': dataType, - 'name': filepath - }) - p = { - 'type': 'multi', - 'params': newparam - } + newparam.append({"type": dataType, "name": filepath}) + p = {"type": "multi", "params": newparam} if not schema: - p['location'] = '[The source data is not in the testdata directory. Please use data in the processing/tests/testdata folder.]' + p["location"] = ( + "[The source data is not in the testdata directory. Please use data in the processing/tests/testdata folder.]" + ) params[param.name()] = p elif isinstance(param, QgsProcessingParameterFile): schema, filepath = extractSchemaPath(token) - p = { - 'type': 'file', - 'name': filepath - } + p = {"type": "file", "name": filepath} if not schema: - p['location'] = '[The source data is not in the testdata directory. Please use data in the processing/tests/testdata folder.]' + p["location"] = ( + "[The source data is not in the testdata directory. Please use data in the processing/tests/testdata folder.]" + ) params[param.name()] = p elif isinstance(param, QgsProcessingParameterString): params[param.name()] = token elif isinstance(param, QgsProcessingParameterBoolean): params[param.name()] = token - elif isinstance(param, (QgsProcessingParameterNumber, QgsProcessingParameterDistance)): + elif isinstance( + param, (QgsProcessingParameterNumber, QgsProcessingParameterDistance) + ): if param.dataType() == QgsProcessingParameterNumber.Type.Integer: params[param.name()] = int(token) else: @@ -248,9 +260,15 @@ def createTest(text): token = token[:-1] params[param.name()] = token - definition['params'] = params + definition["params"] = params - for i, out in enumerate([out for out in alg.destinationParameterDefinitions() if not out.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden]): + for i, out in enumerate( + [ + out + for out in alg.destinationParameterDefinitions() + if not out.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden + ] + ): if not out.name() in parameters: continue @@ -258,56 +276,65 @@ def createTest(text): if isinstance(out, QgsProcessingParameterRasterDestination): if token is None: - QMessageBox.warning(None, - tr('Error'), - tr('Seems some outputs are temporary ' - 'files. To create test you need to ' - 'redirect all algorithm outputs to ' - 'files')) + QMessageBox.warning( + None, + tr("Error"), + tr( + "Seems some outputs are temporary " + "files. To create test you need to " + "redirect all algorithm outputs to " + "files" + ), + ) return try: dataset = gdal.Open(token, GA_ReadOnly) except Exception: - QMessageBox.warning(None, - tr('Error'), - tr('Seems some outputs are temporary ' - 'files. To create test you need to ' - 'redirect all algorithm outputs to ' - 'files')) + QMessageBox.warning( + None, + tr("Error"), + tr( + "Seems some outputs are temporary " + "files. To create test you need to " + "redirect all algorithm outputs to " + "files" + ), + ) return dataArray = nan_to_num(dataset.ReadAsArray(0)) strhash = hashlib.sha224(dataArray.data).hexdigest() - results[out.name()] = { - 'type': 'rasterhash', - 'hash': strhash - } - elif isinstance(out, (QgsProcessingParameterVectorDestination, QgsProcessingParameterFeatureSink)): + results[out.name()] = {"type": "rasterhash", "hash": strhash} + elif isinstance( + out, + ( + QgsProcessingParameterVectorDestination, + QgsProcessingParameterFeatureSink, + ), + ): schema, filepath = extractSchemaPath(token) - results[out.name()] = { - 'type': 'vector', - 'name': filepath - } + results[out.name()] = {"type": "vector", "name": filepath} if not schema: - results[out.name()]['location'] = '[The expected result data is not in the testdata directory. Please write it to processing/tests/testdata/expected. Prefer gml files.]' + results[out.name()][ + "location" + ] = "[The expected result data is not in the testdata directory. Please write it to processing/tests/testdata/expected. Prefer gml files.]" elif isinstance(out, QgsProcessingParameterFileDestination): schema, filepath = extractSchemaPath(token) - results[out.name()] = { - 'type': 'file', - 'name': filepath - } + results[out.name()] = {"type": "file", "name": filepath} if not schema: - results[out.name()]['location'] = '[The expected result file is not in the testdata directory. Please redirect the output to processing/tests/testdata/expected.]' + results[out.name()][ + "location" + ] = "[The expected result file is not in the testdata directory. Please redirect the output to processing/tests/testdata/expected.]" - definition['results'] = results + definition["results"] = results dlg = ShowTestDialog(yaml.dump([definition], default_flow_style=False)) dlg.exec() def tr(string): - return QCoreApplication.translate('TestTools', string) + return QCoreApplication.translate("TestTools", string) class ShowTestDialog(QDialog): @@ -316,13 +343,13 @@ def __init__(self, s): QDialog.__init__(self) self.setModal(True) self.resize(600, 400) - self.setWindowTitle(self.tr('Unit Test')) + self.setWindowTitle(self.tr("Unit Test")) layout = QVBoxLayout() self.text = QTextEdit() self.text.setFontFamily("monospace") self.text.setEnabled(True) # Add two spaces in front of each text for faster copy/paste - self.text.setText(' {}'.format(s.replace('\n', '\n '))) + self.text.setText(" {}".format(s.replace("\n", "\n "))) layout.addWidget(self.text) self.setLayout(layout) QMetaObject.connectSlotsByName(self) diff --git a/python/plugins/processing/gui/ToolboxAction.py b/python/plugins/processing/gui/ToolboxAction.py index bb47e1ec181e..ea8f7ea6d065 100644 --- a/python/plugins/processing/gui/ToolboxAction.py +++ b/python/plugins/processing/gui/ToolboxAction.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" from qgis.PyQt.QtCore import QCoreApplication @@ -32,7 +32,7 @@ def setData(self, toolbox): def getIcon(self): return QgsApplication.getThemeIcon("/processingAlgorithm.svg") - def tr(self, string, context=''): - if context == '': + def tr(self, string, context=""): + if context == "": context = self.__class__.__name__ return QCoreApplication.translate(context, string) diff --git a/python/plugins/processing/gui/__init__.py b/python/plugins/processing/gui/__init__.py index 76b7538a24a5..be57526b8c09 100644 --- a/python/plugins/processing/gui/__init__.py +++ b/python/plugins/processing/gui/__init__.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2013' -__copyright__ = '(C) 2013, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2013" +__copyright__ = "(C) 2013, Victor Olaya" from qgis.PyQt import uic import logging diff --git a/python/plugins/processing/gui/menus.py b/python/plugins/processing/gui/menus.py index 422fae1cbc6b..9f5cebc55381 100644 --- a/python/plugins/processing/gui/menus.py +++ b/python/plugins/processing/gui/menus.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'February 2016' -__copyright__ = '(C) 2016, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "February 2016" +__copyright__ = "(C) 2016, Victor Olaya" import os from qgis.PyQt.QtCore import QCoreApplication @@ -28,7 +28,12 @@ from processing.gui.MessageDialog import MessageDialog from processing.gui.AlgorithmDialog import AlgorithmDialog from qgis.utils import iface -from qgis.core import QgsApplication, QgsMessageLog, QgsStringUtils, QgsProcessingAlgorithm +from qgis.core import ( + QgsApplication, + QgsMessageLog, + QgsStringUtils, + QgsProcessingAlgorithm, +) from qgis.gui import QgsGui from processing.gui.MessageBarProgress import MessageBarProgress from processing.gui.AlgorithmExecutor import execute @@ -37,7 +42,7 @@ from processing.tools import dataobjects algorithmsToolbar = None -menusSettingsGroup = 'Menus' +menusSettingsGroup = "Menus" defaultMenuEntries = {} toolBarButtons = [] toolButton = None @@ -47,97 +52,137 @@ def initMenusAndToolbars(): global defaultMenuEntries, toolBarButtons, toolButton, toolButtonAction vectorMenu = iface.vectorMenu().title() - analysisToolsMenu = vectorMenu + "/" + Processing.tr('&Analysis Tools') - defaultMenuEntries.update({'qgis:distancematrix': analysisToolsMenu, - 'native:sumlinelengths': analysisToolsMenu, - 'native:countpointsinpolygon': analysisToolsMenu, - 'qgis:listuniquevalues': analysisToolsMenu, - 'native:basicstatisticsforfields': analysisToolsMenu, - 'native:nearestneighbouranalysis': analysisToolsMenu, - 'native:meancoordinates': analysisToolsMenu, - 'native:lineintersections': analysisToolsMenu}) - researchToolsMenu = vectorMenu + "/" + Processing.tr('&Research Tools') - defaultMenuEntries.update({'native:creategrid': researchToolsMenu, - 'qgis:randomselection': researchToolsMenu, - 'qgis:randomselectionwithinsubsets': researchToolsMenu, - 'native:randompointsinextent': researchToolsMenu, - 'qgis:randompointsinlayerbounds': researchToolsMenu, - 'native:randompointsinpolygons': researchToolsMenu, - 'qgis:randompointsinsidepolygons': researchToolsMenu, - 'native:randompointsonlines': researchToolsMenu, - 'qgis:regularpoints': researchToolsMenu, - 'native:selectbylocation': researchToolsMenu, - 'native:selectwithindistance': researchToolsMenu, - 'native:polygonfromlayerextent': researchToolsMenu}) - geoprocessingToolsMenu = vectorMenu + "/" + Processing.tr('&Geoprocessing Tools') - defaultMenuEntries.update({'native:buffer': geoprocessingToolsMenu, - 'native:convexhull': geoprocessingToolsMenu, - 'native:intersection': geoprocessingToolsMenu, - 'native:union': geoprocessingToolsMenu, - 'native:symmetricaldifference': geoprocessingToolsMenu, - 'native:clip': geoprocessingToolsMenu, - 'native:difference': geoprocessingToolsMenu, - 'native:dissolve': geoprocessingToolsMenu, - 'qgis:eliminateselectedpolygons': geoprocessingToolsMenu}) - geometryToolsMenu = vectorMenu + "/" + Processing.tr('G&eometry Tools') - defaultMenuEntries.update({'qgis:checkvalidity': geometryToolsMenu, - 'qgis:exportaddgeometrycolumns': geometryToolsMenu, - 'native:centroids': geometryToolsMenu, - 'native:delaunaytriangulation': geometryToolsMenu, - 'native:voronoipolygons': geometryToolsMenu, - 'native:simplifygeometries': geometryToolsMenu, - 'native:densifygeometries': geometryToolsMenu, - 'native:multiparttosingleparts': geometryToolsMenu, - 'native:collect': geometryToolsMenu, - 'native:polygonstolines': geometryToolsMenu, - 'qgis:linestopolygons': geometryToolsMenu, - 'native:extractvertices': geometryToolsMenu}) - managementToolsMenu = vectorMenu + "/" + Processing.tr('&Data Management Tools') - defaultMenuEntries.update({'native:reprojectlayer': managementToolsMenu, - 'native:joinattributesbylocation': managementToolsMenu, - 'native:splitvectorlayer': managementToolsMenu, - 'native:mergevectorlayers': managementToolsMenu, - 'native:createspatialindex': managementToolsMenu}) + analysisToolsMenu = vectorMenu + "/" + Processing.tr("&Analysis Tools") + defaultMenuEntries.update( + { + "qgis:distancematrix": analysisToolsMenu, + "native:sumlinelengths": analysisToolsMenu, + "native:countpointsinpolygon": analysisToolsMenu, + "qgis:listuniquevalues": analysisToolsMenu, + "native:basicstatisticsforfields": analysisToolsMenu, + "native:nearestneighbouranalysis": analysisToolsMenu, + "native:meancoordinates": analysisToolsMenu, + "native:lineintersections": analysisToolsMenu, + } + ) + researchToolsMenu = vectorMenu + "/" + Processing.tr("&Research Tools") + defaultMenuEntries.update( + { + "native:creategrid": researchToolsMenu, + "qgis:randomselection": researchToolsMenu, + "qgis:randomselectionwithinsubsets": researchToolsMenu, + "native:randompointsinextent": researchToolsMenu, + "qgis:randompointsinlayerbounds": researchToolsMenu, + "native:randompointsinpolygons": researchToolsMenu, + "qgis:randompointsinsidepolygons": researchToolsMenu, + "native:randompointsonlines": researchToolsMenu, + "qgis:regularpoints": researchToolsMenu, + "native:selectbylocation": researchToolsMenu, + "native:selectwithindistance": researchToolsMenu, + "native:polygonfromlayerextent": researchToolsMenu, + } + ) + geoprocessingToolsMenu = vectorMenu + "/" + Processing.tr("&Geoprocessing Tools") + defaultMenuEntries.update( + { + "native:buffer": geoprocessingToolsMenu, + "native:convexhull": geoprocessingToolsMenu, + "native:intersection": geoprocessingToolsMenu, + "native:union": geoprocessingToolsMenu, + "native:symmetricaldifference": geoprocessingToolsMenu, + "native:clip": geoprocessingToolsMenu, + "native:difference": geoprocessingToolsMenu, + "native:dissolve": geoprocessingToolsMenu, + "qgis:eliminateselectedpolygons": geoprocessingToolsMenu, + } + ) + geometryToolsMenu = vectorMenu + "/" + Processing.tr("G&eometry Tools") + defaultMenuEntries.update( + { + "qgis:checkvalidity": geometryToolsMenu, + "qgis:exportaddgeometrycolumns": geometryToolsMenu, + "native:centroids": geometryToolsMenu, + "native:delaunaytriangulation": geometryToolsMenu, + "native:voronoipolygons": geometryToolsMenu, + "native:simplifygeometries": geometryToolsMenu, + "native:densifygeometries": geometryToolsMenu, + "native:multiparttosingleparts": geometryToolsMenu, + "native:collect": geometryToolsMenu, + "native:polygonstolines": geometryToolsMenu, + "qgis:linestopolygons": geometryToolsMenu, + "native:extractvertices": geometryToolsMenu, + } + ) + managementToolsMenu = vectorMenu + "/" + Processing.tr("&Data Management Tools") + defaultMenuEntries.update( + { + "native:reprojectlayer": managementToolsMenu, + "native:joinattributesbylocation": managementToolsMenu, + "native:splitvectorlayer": managementToolsMenu, + "native:mergevectorlayers": managementToolsMenu, + "native:createspatialindex": managementToolsMenu, + } + ) rasterMenu = iface.rasterMenu().title() - defaultMenuEntries.update({'native:alignrasters': rasterMenu}) - projectionsMenu = rasterMenu + "/" + Processing.tr('Projections') - defaultMenuEntries.update({'gdal:warpreproject': projectionsMenu, - 'gdal:extractprojection': projectionsMenu, - 'gdal:assignprojection': projectionsMenu}) - conversionMenu = rasterMenu + "/" + Processing.tr('Conversion') - defaultMenuEntries.update({'gdal:rasterize': conversionMenu, - 'gdal:polygonize': conversionMenu, - 'gdal:translate': conversionMenu, - 'gdal:rgbtopct': conversionMenu, - 'gdal:pcttorgb': conversionMenu}) - extractionMenu = rasterMenu + "/" + Processing.tr('Extraction') - defaultMenuEntries.update({'gdal:contour': extractionMenu, - 'gdal:cliprasterbyextent': extractionMenu, - 'gdal:cliprasterbymasklayer': extractionMenu}) - analysisMenu = rasterMenu + "/" + Processing.tr('Analysis') - defaultMenuEntries.update({'gdal:sieve': analysisMenu, - 'gdal:nearblack': analysisMenu, - 'gdal:fillnodata': analysisMenu, - 'gdal:proximity': analysisMenu, - 'gdal:griddatametrics': analysisMenu, - 'gdal:gridaverage': analysisMenu, - 'gdal:gridinversedistance': analysisMenu, - 'gdal:gridnearestneighbor': analysisMenu, - 'gdal:aspect': analysisMenu, - 'gdal:hillshade': analysisMenu, - 'gdal:roughness': analysisMenu, - 'gdal:slope': analysisMenu, - 'gdal:tpitopographicpositionindex': analysisMenu, - 'gdal:triterrainruggednessindex': analysisMenu}) - miscMenu = rasterMenu + "/" + Processing.tr('Miscellaneous') - defaultMenuEntries.update({'gdal:buildvirtualraster': miscMenu, - 'gdal:merge': miscMenu, - 'gdal:gdalinfo': miscMenu, - 'gdal:overviews': miscMenu, - 'gdal:tileindex': miscMenu}) - - toolBarButtons = ['native:selectbylocation', 'native:selectwithindistance'] + defaultMenuEntries.update({"native:alignrasters": rasterMenu}) + projectionsMenu = rasterMenu + "/" + Processing.tr("Projections") + defaultMenuEntries.update( + { + "gdal:warpreproject": projectionsMenu, + "gdal:extractprojection": projectionsMenu, + "gdal:assignprojection": projectionsMenu, + } + ) + conversionMenu = rasterMenu + "/" + Processing.tr("Conversion") + defaultMenuEntries.update( + { + "gdal:rasterize": conversionMenu, + "gdal:polygonize": conversionMenu, + "gdal:translate": conversionMenu, + "gdal:rgbtopct": conversionMenu, + "gdal:pcttorgb": conversionMenu, + } + ) + extractionMenu = rasterMenu + "/" + Processing.tr("Extraction") + defaultMenuEntries.update( + { + "gdal:contour": extractionMenu, + "gdal:cliprasterbyextent": extractionMenu, + "gdal:cliprasterbymasklayer": extractionMenu, + } + ) + analysisMenu = rasterMenu + "/" + Processing.tr("Analysis") + defaultMenuEntries.update( + { + "gdal:sieve": analysisMenu, + "gdal:nearblack": analysisMenu, + "gdal:fillnodata": analysisMenu, + "gdal:proximity": analysisMenu, + "gdal:griddatametrics": analysisMenu, + "gdal:gridaverage": analysisMenu, + "gdal:gridinversedistance": analysisMenu, + "gdal:gridnearestneighbor": analysisMenu, + "gdal:aspect": analysisMenu, + "gdal:hillshade": analysisMenu, + "gdal:roughness": analysisMenu, + "gdal:slope": analysisMenu, + "gdal:tpitopographicpositionindex": analysisMenu, + "gdal:triterrainruggednessindex": analysisMenu, + } + ) + miscMenu = rasterMenu + "/" + Processing.tr("Miscellaneous") + defaultMenuEntries.update( + { + "gdal:buildvirtualraster": miscMenu, + "gdal:merge": miscMenu, + "gdal:gdalinfo": miscMenu, + "gdal:overviews": miscMenu, + "gdal:tileindex": miscMenu, + } + ) + + toolBarButtons = ["native:selectbylocation", "native:selectwithindistance"] toolbar = iface.selectionToolBar() toolButton = QToolButton(toolbar) @@ -153,20 +198,27 @@ def initializeMenus(): for m in defaultMenuEntries.keys(): alg = QgsApplication.processingRegistry().algorithmById(m) if alg is None or alg.id() != m: - QgsMessageLog.logMessage(Processing.tr('Invalid algorithm ID for menu: {}').format(m), - Processing.tr('Processing')) + QgsMessageLog.logMessage( + Processing.tr("Invalid algorithm ID for menu: {}").format(m), + Processing.tr("Processing"), + ) for provider in QgsApplication.processingRegistry().providers(): for alg in provider.algorithms(): d = defaultMenuEntries.get(alg.id(), "") - setting = Setting(menusSettingsGroup, "MENU_" + alg.id(), - "Menu path", d) + setting = Setting(menusSettingsGroup, "MENU_" + alg.id(), "Menu path", d) ProcessingConfig.addSetting(setting) - setting = Setting(menusSettingsGroup, "BUTTON_" + alg.id(), - "Add button", False) + setting = Setting( + menusSettingsGroup, "BUTTON_" + alg.id(), "Add button", False + ) ProcessingConfig.addSetting(setting) - setting = Setting(menusSettingsGroup, "ICON_" + alg.id(), - "Icon", "", valuetype=Setting.FILE) + setting = Setting( + menusSettingsGroup, + "ICON_" + alg.id(), + "Icon", + "", + valuetype=Setting.FILE, + ) ProcessingConfig.addSetting(setting) ProcessingConfig.readSettings() @@ -190,7 +242,9 @@ def createMenus(): if menuPath: paths = menuPath.split("/") subMenuName = paths[-1] if len(paths) > 1 else "" - addAlgorithmEntry(alg, paths[0], subMenuName, addButton=addButton, icon=icon) + addAlgorithmEntry( + alg, paths[0], subMenuName, addButton=addButton, icon=icon + ) def removeMenus(): @@ -201,14 +255,19 @@ def removeMenus(): removeAlgorithmEntry(alg, paths[0], paths[-1]) -def addAlgorithmEntry(alg, menuName, submenuName, actionText=None, icon=None, addButton=False): +def addAlgorithmEntry( + alg, menuName, submenuName, actionText=None, icon=None, addButton=False +): if actionText is None: if (QgsGui.higFlags() & QgsGui.HigFlag.HigMenuTextIsTitleCase) and not ( - alg.flags() & QgsProcessingAlgorithm.Flag.FlagDisplayNameIsLiteral): - alg_title = QgsStringUtils.capitalize(alg.displayName(), QgsStringUtils.Capitalization.TitleCase) + alg.flags() & QgsProcessingAlgorithm.Flag.FlagDisplayNameIsLiteral + ): + alg_title = QgsStringUtils.capitalize( + alg.displayName(), QgsStringUtils.Capitalization.TitleCase + ) else: alg_title = alg.displayName() - actionText = alg_title + QCoreApplication.translate('Processing', '…') + actionText = alg_title + QCoreApplication.translate("Processing", "…") action = QAction(icon or alg.icon(), actionText, iface.mainWindow()) alg_id = alg.id() action.setData(alg_id) @@ -226,9 +285,15 @@ def addAlgorithmEntry(alg, menuName, submenuName, actionText=None, icon=None, ad if addButton: global algorithmsToolbar if algorithmsToolbar is None: - algorithmsToolbar = iface.addToolBar(QCoreApplication.translate('MainWindow', 'Processing Algorithms')) + algorithmsToolbar = iface.addToolBar( + QCoreApplication.translate("MainWindow", "Processing Algorithms") + ) algorithmsToolbar.setObjectName("ProcessingAlgorithms") - algorithmsToolbar.setToolTip(QCoreApplication.translate('MainWindow', 'Processing Algorithms Toolbar')) + algorithmsToolbar.setToolTip( + QCoreApplication.translate( + "MainWindow", "Processing Algorithms Toolbar" + ) + ) algorithmsToolbar.addAction(action) @@ -255,20 +320,24 @@ def _executeAlgorithm(alg_id): alg = QgsApplication.processingRegistry().createAlgorithmById(alg_id) if alg is None: dlg = MessageDialog() - dlg.setTitle(Processing.tr('Missing Algorithm')) + dlg.setTitle(Processing.tr("Missing Algorithm")) dlg.setMessage( - Processing.tr('The algorithm "{}" is no longer available. (Perhaps a plugin was uninstalled?)').format( - alg_id)) + Processing.tr( + 'The algorithm "{}" is no longer available. (Perhaps a plugin was uninstalled?)' + ).format(alg_id) + ) dlg.exec() return ok, message = alg.canExecute() if not ok: dlg = MessageDialog() - dlg.setTitle(Processing.tr('Missing Dependency')) + dlg.setTitle(Processing.tr("Missing Dependency")) dlg.setMessage( - Processing.tr('

Missing dependency. This algorithm cannot ' - 'be run :-(

\n{0}').format(message)) + Processing.tr( + "

Missing dependency. This algorithm cannot " "be run :-(

\n{0}" + ).format(message) + ) dlg.exec() return @@ -306,7 +375,8 @@ def getMenu(name, parent): def findAction(actions, alg): for action in actions: if (isinstance(alg, str) and action.data() == alg) or ( - isinstance(alg, QgsProcessingAlgorithm) and action.data() == alg.id()): + isinstance(alg, QgsProcessingAlgorithm) and action.data() == alg.id() + ): return action return None @@ -318,8 +388,11 @@ def addToolBarButton(index, algId, icon=None, tooltip=None): if tooltip is None: if (QgsGui.higFlags() & QgsGui.HigFlag.HigMenuTextIsTitleCase) and not ( - alg.flags() & QgsProcessingAlgorithm.Flag.FlagDisplayNameIsLiteral): - tooltip = QgsStringUtils.capitalize(alg.displayName(), QgsStringUtils.Capitalization.TitleCase) + alg.flags() & QgsProcessingAlgorithm.Flag.FlagDisplayNameIsLiteral + ): + tooltip = QgsStringUtils.capitalize( + alg.displayName(), QgsStringUtils.Capitalization.TitleCase + ) else: tooltip = alg.displayName() diff --git a/python/plugins/processing/gui/wrappers.py b/python/plugins/processing/gui/wrappers.py index b445a4f9b5a3..c02622ad143e 100644 --- a/python/plugins/processing/gui/wrappers.py +++ b/python/plugins/processing/gui/wrappers.py @@ -16,9 +16,9 @@ *************************************************************************** """ -__author__ = 'Arnaud Morvan' -__date__ = 'May 2016' -__copyright__ = '(C) 2016, Arnaud Morvan' +__author__ = "Arnaud Morvan" +__date__ = "May 2016" +__copyright__ = "(C) 2016, Arnaud Morvan" import os import re @@ -67,7 +67,8 @@ QgsProcessingOutputNumber, QgsProcessingModelChildParameterSource, NULL, - Qgis) + Qgis, +) from qgis.PyQt.QtWidgets import ( QCheckBox, @@ -80,7 +81,7 @@ QPlainTextEdit, QToolButton, QWidget, - QSizePolicy + QSizePolicy, ) from qgis.PyQt.QtGui import QIcon from qgis.gui import ( @@ -95,7 +96,7 @@ QgsRasterBandComboBox, QgsProcessingGui, QgsAbstractProcessingParameterWidgetWrapper, - QgsProcessingMapLayerComboBox + QgsProcessingMapLayerComboBox, ) from qgis.PyQt.QtCore import QVariant, Qt from qgis.utils import iface @@ -103,7 +104,11 @@ from processing.core.ProcessingConfig import ProcessingConfig from processing.modeler.MultilineTextPanel import MultilineTextPanel -from processing.gui.NumberInputPanel import NumberInputPanel, ModelerNumberInputPanel, DistanceInputPanel +from processing.gui.NumberInputPanel import ( + NumberInputPanel, + ModelerNumberInputPanel, + DistanceInputPanel, +) from processing.gui.RangePanel import RangePanel from processing.gui.PointSelectionPanel import PointSelectionPanel from processing.gui.FileSelectionPanel import FileSelectionPanel @@ -126,24 +131,31 @@ class InvalidParameterValue(Exception): pass -dialogTypes = {"AlgorithmDialog": DIALOG_STANDARD, - "ModelerParametersDialog": DIALOG_MODELER, - "BatchAlgorithmDialog": DIALOG_BATCH} +dialogTypes = { + "AlgorithmDialog": DIALOG_STANDARD, + "ModelerParametersDialog": DIALOG_MODELER, + "BatchAlgorithmDialog": DIALOG_BATCH, +} def getExtendedLayerName(layer): authid = layer.crs().authid() - if ProcessingConfig.getSetting(ProcessingConfig.SHOW_CRS_DEF) and authid is not None: - return f'{layer.name()} [{authid}]' + if ( + ProcessingConfig.getSetting(ProcessingConfig.SHOW_CRS_DEF) + and authid is not None + ): + return f"{layer.name()} [{authid}]" else: return layer.name() class WidgetWrapper(QgsAbstractProcessingParameterWidgetWrapper): - NOT_SET_OPTION = '~~~~!!!!NOT SET!!!!~~~~~~~' + NOT_SET_OPTION = "~~~~!!!!NOT SET!!!!~~~~~~~" def __init__(self, param, dialog, row=0, col=0, **kwargs): - self.dialogType = dialogTypes.get(dialog.__class__.__name__, QgsProcessingGui.WidgetType.Standard) + self.dialogType = dialogTypes.get( + dialog.__class__.__name__, QgsProcessingGui.WidgetType.Standard + ) super().__init__(param, self.dialogType) self.dialog = dialog @@ -179,11 +191,14 @@ def createLabel(self): return None desc = self.parameterDefinition().description() if isinstance(self.parameterDefinition(), QgsProcessingParameterExtent): - desc += self.tr(' (xmin, xmax, ymin, ymax)') + desc += self.tr(" (xmin, xmax, ymin, ymax)") if isinstance(self.parameterDefinition(), QgsProcessingParameterPoint): - desc += self.tr(' (x, y)') - if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: - desc += self.tr(' [optional]') + desc += self.tr(" (x, y)") + if ( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ): + desc += self.tr(" [optional]") label = QLabel(desc) label.setToolTip(self.parameterDefinition().name()) @@ -225,24 +240,29 @@ def setComboValue(self, value, combobox=None): def refresh(self): pass - def getFileName(self, initial_value=''): + def getFileName(self, initial_value=""): """Shows a file open dialog""" settings = QgsSettings() if os.path.isdir(initial_value): path = initial_value elif os.path.isdir(os.path.dirname(initial_value)): path = os.path.dirname(initial_value) - elif settings.contains('/Processing/LastInputPath'): - path = str(settings.value('/Processing/LastInputPath')) + elif settings.contains("/Processing/LastInputPath"): + path = str(settings.value("/Processing/LastInputPath")) else: - path = '' + path = "" # TODO: should use selectedFilter argument for default file format - filename, selected_filter = QFileDialog.getOpenFileName(self.widget, self.tr('Select File'), - path, self.parameterDefinition().createFileFilter()) + filename, selected_filter = QFileDialog.getOpenFileName( + self.widget, + self.tr("Select File"), + path, + self.parameterDefinition().createFileFilter(), + ) if filename: - settings.setValue('/Processing/LastInputPath', - os.path.dirname(str(filename))) + settings.setValue( + "/Processing/LastInputPath", os.path.dirname(str(filename)) + ) return filename, selected_filter @@ -268,7 +288,11 @@ def __init__(self, *args, **kwargs): """ from warnings import warn - warn("BooleanWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "BooleanWidgetWrapper is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) def createLabel(self): if self.dialogType == DIALOG_STANDARD: @@ -281,14 +305,16 @@ def createWidget(self): return QCheckBox() elif self.dialogType == DIALOG_BATCH: widget = QComboBox() - widget.addItem(self.tr('Yes'), True) - widget.addItem(self.tr('No'), False) + widget.addItem(self.tr("Yes"), True) + widget.addItem(self.tr("No"), False) return widget else: widget = QComboBox() - widget.addItem(self.tr('Yes'), True) - widget.addItem(self.tr('No'), False) - bools = self.dialog.getAvailableValuesOfType(QgsProcessingParameterBoolean, None) + widget.addItem(self.tr("Yes"), True) + widget.addItem(self.tr("No"), False) + bools = self.dialog.getAvailableValuesOfType( + QgsProcessingParameterBoolean, None + ) for b in bools: widget.addItem(self.dialog.resolveValueDescription(b), b) return widget @@ -318,7 +344,11 @@ def __init__(self, *args, **kwargs): """ from warnings import warn - warn("CrsWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "CrsWidgetWrapper is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) def createWidget(self): if self.dialogType == DIALOG_MODELER: @@ -337,34 +367,54 @@ def createWidget(self): widget.setLayout(layout) self.combo.setEditable(True) - crss = self.dialog.getAvailableValuesOfType((QgsProcessingParameterCrs, QgsProcessingParameterString), QgsProcessingOutputString) + crss = self.dialog.getAvailableValuesOfType( + (QgsProcessingParameterCrs, QgsProcessingParameterString), + QgsProcessingOutputString, + ) for crs in crss: self.combo.addItem(self.dialog.resolveValueDescription(crs), crs) - layers = self.dialog.getAvailableValuesOfType([QgsProcessingParameterRasterLayer, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterMeshLayer, - QgsProcessingParameterFeatureSource], - [QgsProcessingOutputVectorLayer, - QgsProcessingOutputRasterLayer, - QgsProcessingOutputMapLayer]) + layers = self.dialog.getAvailableValuesOfType( + [ + QgsProcessingParameterRasterLayer, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterMeshLayer, + QgsProcessingParameterFeatureSource, + ], + [ + QgsProcessingOutputVectorLayer, + QgsProcessingOutputRasterLayer, + QgsProcessingOutputMapLayer, + ], + ) for l in layers: - self.combo.addItem("Crs of layer " + self.dialog.resolveValueDescription(l), l) + self.combo.addItem( + "Crs of layer " + self.dialog.resolveValueDescription(l), l + ) if self.parameterDefinition().defaultValue(): self.combo.setEditText(self.parameterDefinition().defaultValue()) return widget else: widget = QgsProjectionSelectionWidget() - if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: - widget.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet, True) + if ( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ): + widget.setOptionVisible( + QgsProjectionSelectionWidget.CrsOption.CrsNotSet, True + ) if self.parameterDefinition().defaultValue(): - if self.parameterDefinition().defaultValue() == 'ProjectCrs': + if self.parameterDefinition().defaultValue() == "ProjectCrs": crs = QgsProject.instance().crs() else: - crs = QgsCoordinateReferenceSystem(self.parameterDefinition().defaultValue()) + crs = QgsCoordinateReferenceSystem( + self.parameterDefinition().defaultValue() + ) widget.setCrs(crs) else: - widget.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet, True) + widget.setOptionVisible( + QgsProjectionSelectionWidget.CrsOption.CrsNotSet, True + ) widget.crsChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) return widget @@ -384,7 +434,7 @@ def setValue(self, value): if self.dialogType == DIALOG_MODELER: self.setComboValue(value, self.combo) - elif value == 'ProjectCrs': + elif value == "ProjectCrs": self.widget.setCrs(QgsProject.instance().crs()) else: self.widget.setCrs(QgsCoordinateReferenceSystem(value)) @@ -411,7 +461,11 @@ def __init__(self, *args, **kwargs): """ from warnings import warn - warn("ExtentWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "ExtentWidgetWrapper is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) def createWidget(self): if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): @@ -421,16 +475,27 @@ def createWidget(self): else: widget = QComboBox() widget.setEditable(True) - extents = self.dialog.getAvailableValuesOfType(QgsProcessingParameterExtent, (QgsProcessingOutputString)) - if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: + extents = self.dialog.getAvailableValuesOfType( + QgsProcessingParameterExtent, (QgsProcessingOutputString) + ) + if ( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ): widget.addItem(self.USE_MIN_COVERING_EXTENT, None) - layers = self.dialog.getAvailableValuesOfType([QgsProcessingParameterFeatureSource, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterMeshLayer], - [QgsProcessingOutputRasterLayer, - QgsProcessingOutputVectorLayer, - QgsProcessingOutputMapLayer]) + layers = self.dialog.getAvailableValuesOfType( + [ + QgsProcessingParameterFeatureSource, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterMeshLayer, + ], + [ + QgsProcessingOutputRasterLayer, + QgsProcessingOutputVectorLayer, + QgsProcessingOutputMapLayer, + ], + ) for ex in extents: widget.addItem(self.dialog.resolveValueDescription(ex), ex) for l in layers: @@ -457,14 +522,17 @@ def value(self): s = str(self.widget.currentText()).strip() if s: try: - tokens = s.split(',') + tokens = s.split(",") if len(tokens) != 4: raise InvalidParameterValue() for token in tokens: float(token) except: raise InvalidParameterValue() - elif self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: + elif ( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ): s = None else: raise InvalidParameterValue() @@ -483,15 +551,24 @@ def __init__(self, *args, **kwargs): """ from warnings import warn - warn("PointWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "PointWidgetWrapper is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) def createWidget(self): if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): - return PointSelectionPanel(self.dialog, self.parameterDefinition().defaultValue()) + return PointSelectionPanel( + self.dialog, self.parameterDefinition().defaultValue() + ) else: item = QComboBox() item.setEditable(True) - points = self.dialog.getAvailableValuesOfType((QgsProcessingParameterPoint, QgsProcessingParameterString), (QgsProcessingOutputString)) + points = self.dialog.getAvailableValuesOfType( + (QgsProcessingParameterPoint, QgsProcessingParameterString), + (QgsProcessingOutputString), + ) for p in points: item.addItem(self.dialog.resolveValueDescription(p), p) item.setEditText(str(self.parameterDefinition().defaultValue())) @@ -515,14 +592,17 @@ def value(self): s = str(self.widget.currentText()).strip() if s: try: - tokens = s.split(',') + tokens = s.split(",") if len(tokens) != 2: raise InvalidParameterValue() for token in tokens: float(token) except: raise InvalidParameterValue() - elif self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: + elif ( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ): s = None else: raise InvalidParameterValue() @@ -541,19 +621,38 @@ def __init__(self, *args, **kwargs): """ from warnings import warn - warn("FileWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "FileWidgetWrapper is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) def createWidget(self): if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): - return FileSelectionPanel(self.parameterDefinition().behavior() == QgsProcessingParameterFile.Behavior.Folder, - self.parameterDefinition().extension()) + return FileSelectionPanel( + self.parameterDefinition().behavior() + == QgsProcessingParameterFile.Behavior.Folder, + self.parameterDefinition().extension(), + ) else: self.combo = QComboBox() self.combo.setEditable(True) - files = self.dialog.getAvailableValuesOfType(QgsProcessingParameterFile, (QgsProcessingOutputRasterLayer, QgsProcessingOutputVectorLayer, QgsProcessingOutputMapLayer, QgsProcessingOutputFile, QgsProcessingOutputString)) + files = self.dialog.getAvailableValuesOfType( + QgsProcessingParameterFile, + ( + QgsProcessingOutputRasterLayer, + QgsProcessingOutputVectorLayer, + QgsProcessingOutputMapLayer, + QgsProcessingOutputFile, + QgsProcessingOutputString, + ), + ) for f in files: self.combo.addItem(self.dialog.resolveValueDescription(f), f) - if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: + if ( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ): self.combo.setEditText("") widget = QWidget() layout = QHBoxLayout() @@ -562,7 +661,7 @@ def createWidget(self): layout.setSpacing(6) layout.addWidget(self.combo) btn = QToolButton() - btn.setText('…') + btn.setText("…") btn.setToolTip(self.tr("Select file")) btn.clicked.connect(self.selectFile) layout.addWidget(btn) @@ -573,21 +672,26 @@ def selectFile(self): settings = QgsSettings() if os.path.isdir(os.path.dirname(self.combo.currentText())): path = os.path.dirname(self.combo.currentText()) - if settings.contains('/Processing/LastInputPath'): - path = settings.value('/Processing/LastInputPath') + if settings.contains("/Processing/LastInputPath"): + path = settings.value("/Processing/LastInputPath") else: - path = '' + path = "" if self.parameterDefinition().extension(): - filter = self.tr('{} files').format( - self.parameterDefinition().extension().upper()) + ' (*.' + self.parameterDefinition().extension() + self.tr( - ');;All files (*.*)') + filter = ( + self.tr("{} files").format( + self.parameterDefinition().extension().upper() + ) + + " (*." + + self.parameterDefinition().extension() + + self.tr(");;All files (*.*)") + ) else: - filter = self.tr('All files (*.*)') + filter = self.tr("All files (*.*)") - filename, selected_filter = QFileDialog.getOpenFileName(self.widget, - self.tr('Select File'), path, - filter) + filename, selected_filter = QFileDialog.getOpenFileName( + self.widget, self.tr("Select File"), path, filter + ) if filename: self.combo.setEditText(filename) @@ -617,7 +721,11 @@ def __init__(self, *args, **kwargs): """ from warnings import warn - warn("FixedTableWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "FixedTableWidgetWrapper is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) def createWidget(self): if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): @@ -645,116 +753,265 @@ def value(self): class MultipleLayerWidgetWrapper(WidgetWrapper): def _getOptions(self): - if self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeVectorAnyGeometry: - options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterMultipleLayers), - [QgsProcessingOutputVectorLayer, - QgsProcessingOutputMapLayer, - QgsProcessingOutputMultipleLayers]) - elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeVector: - options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterMultipleLayers), - [QgsProcessingOutputVectorLayer, - QgsProcessingOutputMapLayer, - QgsProcessingOutputMultipleLayers], - [QgsProcessing.SourceType.TypeVector]) - elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeVectorPoint: - options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterMultipleLayers), - [QgsProcessingOutputVectorLayer, - QgsProcessingOutputMapLayer, - QgsProcessingOutputMultipleLayers], - [QgsProcessing.SourceType.TypeVectorPoint, - QgsProcessing.SourceType.TypeVectorAnyGeometry]) - elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeVectorLine: - options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterMultipleLayers), - [QgsProcessingOutputVectorLayer, - QgsProcessingOutputMapLayer, - QgsProcessingOutputMultipleLayers], - [QgsProcessing.SourceType.TypeVectorLine, - QgsProcessing.SourceType.TypeVectorAnyGeometry]) - elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeVectorPolygon: - options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterMultipleLayers), - [QgsProcessingOutputVectorLayer, - QgsProcessingOutputMapLayer, - QgsProcessingOutputMultipleLayers], - [QgsProcessing.SourceType.TypeVectorPolygon, - QgsProcessing.SourceType.TypeVectorAnyGeometry]) - elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeRaster: + if ( + self.parameterDefinition().layerType() + == QgsProcessing.SourceType.TypeVectorAnyGeometry + ): options = self.dialog.getAvailableValuesOfType( - (QgsProcessingParameterRasterLayer, QgsProcessingParameterMultipleLayers), - [QgsProcessingOutputRasterLayer, - QgsProcessingOutputMapLayer, - QgsProcessingOutputMultipleLayers]) - elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeMesh: + ( + QgsProcessingParameterFeatureSource, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterMultipleLayers, + ), + [ + QgsProcessingOutputVectorLayer, + QgsProcessingOutputMapLayer, + QgsProcessingOutputMultipleLayers, + ], + ) + elif ( + self.parameterDefinition().layerType() + == QgsProcessing.SourceType.TypeVector + ): + options = self.dialog.getAvailableValuesOfType( + ( + QgsProcessingParameterFeatureSource, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterMultipleLayers, + ), + [ + QgsProcessingOutputVectorLayer, + QgsProcessingOutputMapLayer, + QgsProcessingOutputMultipleLayers, + ], + [QgsProcessing.SourceType.TypeVector], + ) + elif ( + self.parameterDefinition().layerType() + == QgsProcessing.SourceType.TypeVectorPoint + ): + options = self.dialog.getAvailableValuesOfType( + ( + QgsProcessingParameterFeatureSource, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterMultipleLayers, + ), + [ + QgsProcessingOutputVectorLayer, + QgsProcessingOutputMapLayer, + QgsProcessingOutputMultipleLayers, + ], + [ + QgsProcessing.SourceType.TypeVectorPoint, + QgsProcessing.SourceType.TypeVectorAnyGeometry, + ], + ) + elif ( + self.parameterDefinition().layerType() + == QgsProcessing.SourceType.TypeVectorLine + ): + options = self.dialog.getAvailableValuesOfType( + ( + QgsProcessingParameterFeatureSource, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterMultipleLayers, + ), + [ + QgsProcessingOutputVectorLayer, + QgsProcessingOutputMapLayer, + QgsProcessingOutputMultipleLayers, + ], + [ + QgsProcessing.SourceType.TypeVectorLine, + QgsProcessing.SourceType.TypeVectorAnyGeometry, + ], + ) + elif ( + self.parameterDefinition().layerType() + == QgsProcessing.SourceType.TypeVectorPolygon + ): + options = self.dialog.getAvailableValuesOfType( + ( + QgsProcessingParameterFeatureSource, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterMultipleLayers, + ), + [ + QgsProcessingOutputVectorLayer, + QgsProcessingOutputMapLayer, + QgsProcessingOutputMultipleLayers, + ], + [ + QgsProcessing.SourceType.TypeVectorPolygon, + QgsProcessing.SourceType.TypeVectorAnyGeometry, + ], + ) + elif ( + self.parameterDefinition().layerType() + == QgsProcessing.SourceType.TypeRaster + ): + options = self.dialog.getAvailableValuesOfType( + ( + QgsProcessingParameterRasterLayer, + QgsProcessingParameterMultipleLayers, + ), + [ + QgsProcessingOutputRasterLayer, + QgsProcessingOutputMapLayer, + QgsProcessingOutputMultipleLayers, + ], + ) + elif ( + self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeMesh + ): options = self.dialog.getAvailableValuesOfType( (QgsProcessingParameterMeshLayer, QgsProcessingParameterMultipleLayers), - []) - elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeMapLayer: - options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterRasterLayer, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterMeshLayer, - QgsProcessingParameterMultipleLayers), - [QgsProcessingOutputRasterLayer, - QgsProcessingOutputVectorLayer, - QgsProcessingOutputMapLayer, - QgsProcessingOutputMultipleLayers]) + [], + ) + elif ( + self.parameterDefinition().layerType() + == QgsProcessing.SourceType.TypeMapLayer + ): + options = self.dialog.getAvailableValuesOfType( + ( + QgsProcessingParameterRasterLayer, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterMeshLayer, + QgsProcessingParameterMultipleLayers, + ), + [ + QgsProcessingOutputRasterLayer, + QgsProcessingOutputVectorLayer, + QgsProcessingOutputMapLayer, + QgsProcessingOutputMultipleLayers, + ], + ) else: - options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterFile, QgsProcessingOutputFile) - options = sorted(options, key=lambda opt: self.dialog.resolveValueDescription(opt)) + options = self.dialog.getAvailableValuesOfType( + QgsProcessingParameterFile, QgsProcessingOutputFile + ) + options = sorted( + options, key=lambda opt: self.dialog.resolveValueDescription(opt) + ) return options def createWidget(self): if self.dialogType == DIALOG_STANDARD: - if self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeFile: + if ( + self.parameterDefinition().layerType() + == QgsProcessing.SourceType.TypeFile + ): return MultipleInputPanel(datatype=QgsProcessing.SourceType.TypeFile) else: - if self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeRaster: - options = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False) - elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeMesh: - options = QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance(), False) - elif self.parameterDefinition().layerType() in (QgsProcessing.SourceType.TypeVectorAnyGeometry, QgsProcessing.SourceType.TypeVector): - options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False) - elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeMapLayer: - options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False) - options.extend(QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False)) - options.extend(QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance(), False)) + if ( + self.parameterDefinition().layerType() + == QgsProcessing.SourceType.TypeRaster + ): + options = QgsProcessingUtils.compatibleRasterLayers( + QgsProject.instance(), False + ) + elif ( + self.parameterDefinition().layerType() + == QgsProcessing.SourceType.TypeMesh + ): + options = QgsProcessingUtils.compatibleMeshLayers( + QgsProject.instance(), False + ) + elif self.parameterDefinition().layerType() in ( + QgsProcessing.SourceType.TypeVectorAnyGeometry, + QgsProcessing.SourceType.TypeVector, + ): + options = QgsProcessingUtils.compatibleVectorLayers( + QgsProject.instance(), [], False + ) + elif ( + self.parameterDefinition().layerType() + == QgsProcessing.SourceType.TypeMapLayer + ): + options = QgsProcessingUtils.compatibleVectorLayers( + QgsProject.instance(), [], False + ) + options.extend( + QgsProcessingUtils.compatibleRasterLayers( + QgsProject.instance(), False + ) + ) + options.extend( + QgsProcessingUtils.compatibleMeshLayers( + QgsProject.instance(), False + ) + ) else: - options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [self.parameterDefinition().layerType()], - False) + options = QgsProcessingUtils.compatibleVectorLayers( + QgsProject.instance(), + [self.parameterDefinition().layerType()], + False, + ) opts = [getExtendedLayerName(opt) for opt in options] - return MultipleInputPanel(opts, datatype=self.parameterDefinition().layerType()) + return MultipleInputPanel( + opts, datatype=self.parameterDefinition().layerType() + ) elif self.dialogType == DIALOG_BATCH: - widget = BatchInputSelectionPanel(self.parameterDefinition(), self.row, self.col, self.dialog) + widget = BatchInputSelectionPanel( + self.parameterDefinition(), self.row, self.col, self.dialog + ) widget.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) return widget else: - options = [self.dialog.resolveValueDescription(opt) for opt in self._getOptions()] - return MultipleInputPanel(options, datatype=self.parameterDefinition().layerType()) + options = [ + self.dialog.resolveValueDescription(opt) for opt in self._getOptions() + ] + return MultipleInputPanel( + options, datatype=self.parameterDefinition().layerType() + ) def refresh(self): if self.parameterDefinition().layerType() != QgsProcessing.SourceType.TypeFile: - if self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeRaster: - options = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False) - elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeMesh: - options = QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance(), False) - elif self.parameterDefinition().layerType() in (QgsProcessing.SourceType.TypeVectorAnyGeometry, QgsProcessing.SourceType.TypeVector): - options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False) - elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeMapLayer: - options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False) - options.extend(QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False)) - options.extend(QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance(), False)) + if ( + self.parameterDefinition().layerType() + == QgsProcessing.SourceType.TypeRaster + ): + options = QgsProcessingUtils.compatibleRasterLayers( + QgsProject.instance(), False + ) + elif ( + self.parameterDefinition().layerType() + == QgsProcessing.SourceType.TypeMesh + ): + options = QgsProcessingUtils.compatibleMeshLayers( + QgsProject.instance(), False + ) + elif self.parameterDefinition().layerType() in ( + QgsProcessing.SourceType.TypeVectorAnyGeometry, + QgsProcessing.SourceType.TypeVector, + ): + options = QgsProcessingUtils.compatibleVectorLayers( + QgsProject.instance(), [], False + ) + elif ( + self.parameterDefinition().layerType() + == QgsProcessing.SourceType.TypeMapLayer + ): + options = QgsProcessingUtils.compatibleVectorLayers( + QgsProject.instance(), [], False + ) + options.extend( + QgsProcessingUtils.compatibleRasterLayers( + QgsProject.instance(), False + ) + ) + options.extend( + QgsProcessingUtils.compatibleMeshLayers( + QgsProject.instance(), False + ) + ) else: - options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [self.parameterDefinition().layerType()], - False) + options = QgsProcessingUtils.compatibleVectorLayers( + QgsProject.instance(), + [self.parameterDefinition().layerType()], + False, + ) opts = [getExtendedLayerName(opt) for opt in options] self.widget.updateForOptions(opts) @@ -785,30 +1042,77 @@ def setValue(self, value): def value(self): if self.dialogType == DIALOG_STANDARD: - if self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeFile: + if ( + self.parameterDefinition().layerType() + == QgsProcessing.SourceType.TypeFile + ): return self.widget.selectedoptions else: - if self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeRaster: - options = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False) - elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeMesh: - options = QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance(), False) - elif self.parameterDefinition().layerType() in (QgsProcessing.SourceType.TypeVectorAnyGeometry, QgsProcessing.SourceType.TypeVector): - options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False) - elif self.parameterDefinition().layerType() == QgsProcessing.SourceType.TypeMapLayer: - options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False) - options.extend(QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False)) - options.extend(QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance(), False)) + if ( + self.parameterDefinition().layerType() + == QgsProcessing.SourceType.TypeRaster + ): + options = QgsProcessingUtils.compatibleRasterLayers( + QgsProject.instance(), False + ) + elif ( + self.parameterDefinition().layerType() + == QgsProcessing.SourceType.TypeMesh + ): + options = QgsProcessingUtils.compatibleMeshLayers( + QgsProject.instance(), False + ) + elif self.parameterDefinition().layerType() in ( + QgsProcessing.SourceType.TypeVectorAnyGeometry, + QgsProcessing.SourceType.TypeVector, + ): + options = QgsProcessingUtils.compatibleVectorLayers( + QgsProject.instance(), [], False + ) + elif ( + self.parameterDefinition().layerType() + == QgsProcessing.SourceType.TypeMapLayer + ): + options = QgsProcessingUtils.compatibleVectorLayers( + QgsProject.instance(), [], False + ) + options.extend( + QgsProcessingUtils.compatibleRasterLayers( + QgsProject.instance(), False + ) + ) + options.extend( + QgsProcessingUtils.compatibleMeshLayers( + QgsProject.instance(), False + ) + ) else: - options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [self.parameterDefinition().layerType()], - False) - return [options[i] if isinstance(i, int) else i for i in self.widget.selectedoptions] + options = QgsProcessingUtils.compatibleVectorLayers( + QgsProject.instance(), + [self.parameterDefinition().layerType()], + False, + ) + return [ + options[i] if isinstance(i, int) else i + for i in self.widget.selectedoptions + ] elif self.dialogType == DIALOG_BATCH: return self.widget.getValue() else: options = self._getOptions() - values = [options[i] if isinstance(i, int) else QgsProcessingModelChildParameterSource.fromStaticValue(i) - for i in self.widget.selectedoptions] - if len(values) == 0 and not self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: + values = [ + ( + options[i] + if isinstance(i, int) + else QgsProcessingModelChildParameterSource.fromStaticValue(i) + ) + for i in self.widget.selectedoptions + ] + if ( + len(values) == 0 + and not self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ): raise InvalidParameterValue() return values @@ -823,7 +1127,11 @@ def __init__(self, *args, **kwargs): """ from warnings import warn - warn("NumberWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "NumberWidgetWrapper is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) def createWidget(self): if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): @@ -843,9 +1151,15 @@ def value(self): return self.widget.getValue() def postInitialize(self, wrappers): - if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH) and self.parameterDefinition().isDynamic(): + if ( + self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH) + and self.parameterDefinition().isDynamic() + ): for wrapper in wrappers: - if wrapper.parameterDefinition().name() == self.parameterDefinition().dynamicLayerParameterName(): + if ( + wrapper.parameterDefinition().name() + == self.parameterDefinition().dynamicLayerParameterName() + ): self.widget.setDynamicLayer(wrapper.parameterValue()) wrapper.widgetValueHasChanged.connect(self.parentLayerChanged) break @@ -864,7 +1178,11 @@ def __init__(self, *args, **kwargs): """ from warnings import warn - warn("DistanceWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "DistanceWidgetWrapper is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) def createWidget(self): if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): @@ -886,10 +1204,16 @@ def value(self): def postInitialize(self, wrappers): if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): for wrapper in wrappers: - if wrapper.parameterDefinition().name() == self.parameterDefinition().dynamicLayerParameterName(): + if ( + wrapper.parameterDefinition().name() + == self.parameterDefinition().dynamicLayerParameterName() + ): self.widget.setDynamicLayer(wrapper.parameterValue()) wrapper.widgetValueHasChanged.connect(self.dynamicLayerChanged) - if wrapper.parameterDefinition().name() == self.parameterDefinition().parentParameterName(): + if ( + wrapper.parameterDefinition().name() + == self.parameterDefinition().parentParameterName() + ): self.widget.setUnitParameterValue(wrapper.parameterValue()) wrapper.widgetValueHasChanged.connect(self.parentParameterChanged) @@ -910,7 +1234,11 @@ def __init__(self, *args, **kwargs): """ from warnings import warn - warn("RangeWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "RangeWidgetWrapper is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) def createWidget(self): widget = RangePanel(self.parameterDefinition()) @@ -928,7 +1256,7 @@ def value(self): class MapLayerWidgetWrapper(WidgetWrapper): - NOT_SELECTED = '[Not selected]' + NOT_SELECTED = "[Not selected]" def __init__(self, param, dialog, row=0, col=0, **kwargs): """ @@ -937,7 +1265,11 @@ def __init__(self, param, dialog, row=0, col=0, **kwargs): """ from warnings import warn - warn("MapLayerWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "MapLayerWidgetWrapper is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) super().__init__(param, dialog, row, col, **kwargs) @@ -947,27 +1279,41 @@ def createWidget(self): self.context = dataobjects.createContext() try: - if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: - self.combo.setValue(self.parameterDefinition().defaultValue(), self.context) + if ( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ): + self.combo.setValue( + self.parameterDefinition().defaultValue(), self.context + ) else: if self.parameterDefinition().defaultValue(): - self.combo.setValue(self.parameterDefinition().defaultValue(), self.context) + self.combo.setValue( + self.parameterDefinition().defaultValue(), self.context + ) else: self.combo.setLayer(iface.activeLayer()) except: pass - self.combo.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) + self.combo.valueChanged.connect( + lambda: self.widgetValueHasChanged.emit(self) + ) return self.combo elif self.dialogType == DIALOG_BATCH: - widget = BatchInputSelectionPanel(self.parameterDefinition(), self.row, self.col, self.dialog) + widget = BatchInputSelectionPanel( + self.parameterDefinition(), self.row, self.col, self.dialog + ) widget.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) return widget else: self.combo = QComboBox() layers = self.getAvailableLayers() self.combo.setEditable(True) - if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: + if ( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ): self.combo.addItem(self.NOT_SELECTED, self.NOT_SET_OPTION) for layer in layers: self.combo.addItem(self.dialog.resolveValueDescription(layer), layer) @@ -979,7 +1325,7 @@ def createWidget(self): layout.setSpacing(6) layout.addWidget(self.combo) btn = QToolButton() - btn.setText('…') + btn.setText("…") btn.setToolTip(self.tr("Select file")) btn.clicked.connect(self.selectFile) layout.addWidget(btn) @@ -988,8 +1334,21 @@ def createWidget(self): def getAvailableLayers(self): return self.dialog.getAvailableValuesOfType( - [QgsProcessingParameterRasterLayer, QgsProcessingParameterMeshLayer, QgsProcessingParameterVectorLayer, QgsProcessingParameterMapLayer, QgsProcessingParameterString], - [QgsProcessingOutputRasterLayer, QgsProcessingOutputVectorLayer, QgsProcessingOutputMapLayer, QgsProcessingOutputString, QgsProcessingOutputFile]) + [ + QgsProcessingParameterRasterLayer, + QgsProcessingParameterMeshLayer, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterMapLayer, + QgsProcessingParameterString, + ], + [ + QgsProcessingOutputRasterLayer, + QgsProcessingOutputVectorLayer, + QgsProcessingOutputMapLayer, + QgsProcessingOutputString, + QgsProcessingOutputFile, + ], + ) def selectFile(self): filename, selected_filter = self.getFileName(self.combo.currentText()) @@ -1027,9 +1386,13 @@ def value(self): elif self.dialogType == DIALOG_BATCH: return self.widget.getValue() else: + def validator(v): if not bool(v): - return self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + return ( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ) else: return os.path.exists(v) @@ -1045,18 +1408,30 @@ def __init__(self, param, dialog, row=0, col=0, **kwargs): """ from warnings import warn - warn("RasterWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "RasterWidgetWrapper is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) super().__init__(param, dialog, row, col, **kwargs) def getAvailableLayers(self): - return self.dialog.getAvailableValuesOfType((QgsProcessingParameterRasterLayer, QgsProcessingParameterString), - (QgsProcessingOutputRasterLayer, QgsProcessingOutputFile, QgsProcessingOutputString)) + return self.dialog.getAvailableValuesOfType( + (QgsProcessingParameterRasterLayer, QgsProcessingParameterString), + ( + QgsProcessingOutputRasterLayer, + QgsProcessingOutputFile, + QgsProcessingOutputString, + ), + ) def selectFile(self): filename, selected_filter = self.getFileName(self.combo.currentText()) if filename: - filename = dataobjects.getRasterSublayer(filename, self.parameterDefinition()) + filename = dataobjects.getRasterSublayer( + filename, self.parameterDefinition() + ) if isinstance(self.combo, QgsProcessingMapLayerComboBox): self.combo.setValue(filename, self.context) elif isinstance(self.combo, QgsMapLayerComboBox): @@ -1078,13 +1453,18 @@ def __init__(self, param, dialog, row=0, col=0, **kwargs): """ from warnings import warn - warn("MeshWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "MeshWidgetWrapper is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) super().__init__(param, dialog, row, col, **kwargs) def getAvailableLayers(self): - return self.dialog.getAvailableValuesOfType((QgsProcessingParameterMeshLayer, QgsProcessingParameterString), - ()) + return self.dialog.getAvailableValuesOfType( + (QgsProcessingParameterMeshLayer, QgsProcessingParameterString), () + ) def selectFile(self): filename, selected_filter = self.getFileName(self.combo.currentText()) @@ -1102,7 +1482,7 @@ def selectFile(self): class EnumWidgetWrapper(WidgetWrapper): - NOT_SELECTED = '[Not selected]' + NOT_SELECTED = "[Not selected]" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -1112,15 +1492,21 @@ def __init__(self, *args, **kwargs): """ from warnings import warn - warn("EnumWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "EnumWidgetWrapper is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) def createWidget(self, useCheckBoxes=False, columns=1): if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): self._useCheckBoxes = useCheckBoxes if self._useCheckBoxes and not self.dialogType == DIALOG_BATCH: - return CheckboxesPanel(options=self.parameterDefinition().options(), - multiple=self.parameterDefinition().allowMultiple(), - columns=columns) + return CheckboxesPanel( + options=self.parameterDefinition().options(), + multiple=self.parameterDefinition().allowMultiple(), + columns=columns, + ) if self.parameterDefinition().allowMultiple(): return MultipleInputPanel(options=self.parameterDefinition().options()) else: @@ -1128,11 +1514,16 @@ def createWidget(self, useCheckBoxes=False, columns=1): for i, option in enumerate(self.parameterDefinition().options()): widget.addItem(option, i) if self.parameterDefinition().defaultValue(): - widget.setCurrentIndex(widget.findData(self.parameterDefinition().defaultValue())) + widget.setCurrentIndex( + widget.findData(self.parameterDefinition().defaultValue()) + ) return widget else: self.combobox = QComboBox() - if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: + if ( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ): self.combobox.addItem(self.NOT_SELECTED, self.NOT_SET_OPTION) for i, option in enumerate(self.parameterDefinition().options()): self.combobox.addItem(option, i) @@ -1169,7 +1560,7 @@ def value(self): class FeatureSourceWidgetWrapper(WidgetWrapper): - NOT_SELECTED = '[Not selected]' + NOT_SELECTED = "[Not selected]" def __init__(self, *args, **kwargs): """ @@ -1178,13 +1569,19 @@ def __init__(self, *args, **kwargs): """ from warnings import warn - warn("FeatureSourceWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "FeatureSourceWidgetWrapper is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) self.map_layer_combo = None super().__init__(*args, **kwargs) def createWidget(self): if self.dialogType == DIALOG_STANDARD: - self.map_layer_combo = QgsProcessingMapLayerComboBox(self.parameterDefinition()) + self.map_layer_combo = QgsProcessingMapLayerComboBox( + self.parameterDefinition() + ) self.context = dataobjects.createContext() try: @@ -1193,23 +1590,40 @@ def createWidget(self): except: pass - self.map_layer_combo.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) + self.map_layer_combo.valueChanged.connect( + lambda: self.widgetValueHasChanged.emit(self) + ) return self.map_layer_combo elif self.dialogType == DIALOG_BATCH: - widget = BatchInputSelectionPanel(self.parameterDefinition(), self.row, self.col, self.dialog) + widget = BatchInputSelectionPanel( + self.parameterDefinition(), self.row, self.col, self.dialog + ) widget.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) return widget else: self.combo = QComboBox() layers = self.dialog.getAvailableValuesOfType( - (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer), - (QgsProcessingOutputVectorLayer, QgsProcessingOutputMapLayer, QgsProcessingOutputString, QgsProcessingOutputFile), self.parameterDefinition().dataTypes()) + ( + QgsProcessingParameterFeatureSource, + QgsProcessingParameterVectorLayer, + ), + ( + QgsProcessingOutputVectorLayer, + QgsProcessingOutputMapLayer, + QgsProcessingOutputString, + QgsProcessingOutputFile, + ), + self.parameterDefinition().dataTypes(), + ) self.combo.setEditable(True) for layer in layers: self.combo.addItem(self.dialog.resolveValueDescription(layer), layer) - if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: + if ( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ): self.combo.setEditText("") widget = QWidget() @@ -1219,7 +1633,7 @@ def createWidget(self): layout.setSpacing(2) layout.addWidget(self.combo) btn = QToolButton() - btn.setText('…') + btn.setText("…") btn.setToolTip(self.tr("Select file")) btn.clicked.connect(self.selectFile) layout.addWidget(btn) @@ -1267,9 +1681,13 @@ def value(self): elif self.dialogType == DIALOG_BATCH: return self.widget.getValue() else: + def validator(v): if not bool(v): - return self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + return ( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ) else: return os.path.exists(v) @@ -1289,7 +1707,11 @@ def __init__(self, *args, **kwargs): """ from warnings import warn - warn("StringWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "StringWidgetWrapper is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) def createWidget(self): if self.dialogType == DIALOG_STANDARD: @@ -1305,9 +1727,16 @@ def createWidget(self): else: # strings, numbers, files and table fields are all allowed input types strings = self.dialog.getAvailableValuesOfType( - [QgsProcessingParameterString, QgsProcessingParameterNumber, QgsProcessingParameterDistance, QgsProcessingParameterFile, - QgsProcessingParameterField, QgsProcessingParameterExpression], - [QgsProcessingOutputString, QgsProcessingOutputFile]) + [ + QgsProcessingParameterString, + QgsProcessingParameterNumber, + QgsProcessingParameterDistance, + QgsProcessingParameterFile, + QgsProcessingParameterField, + QgsProcessingParameterExpression, + ], + [QgsProcessingOutputString, QgsProcessingOutputFile], + ) options = [(self.dialog.resolveValueDescription(s), s) for s in strings] if self.parameterDefinition().multiLine(): widget = MultilineTextPanel(options) @@ -1322,9 +1751,9 @@ def showExpressionsBuilder(self): context = dataobjects.createExpressionContext() value = self.value() if not isinstance(value, str): - value = '' - dlg = QgsExpressionBuilderDialog(None, value, self.widget, 'generic', context) - dlg.setWindowTitle(self.tr('Expression based input')) + value = "" + dlg = QgsExpressionBuilderDialog(None, value, self.widget, "generic", context) + dlg.setWindowTitle(self.tr("Expression based input")) if dlg.exec() == QDialog.DialogCode.Accepted: exp = QgsExpression(dlg.expressionText()) if not exp.hasParserError(): @@ -1368,8 +1797,11 @@ def value(self): value = self.widget.getValue() option = self.widget.getOption() if option == MultilineTextPanel.USE_TEXT: - if value == '': - if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: + if value == "": + if ( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ): return None else: raise InvalidParameterValue() @@ -1378,8 +1810,13 @@ def value(self): else: return value else: + def validator(v): - return bool(v) or self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + return ( + bool(v) + or self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ) return self.comboValue(validator) @@ -1393,7 +1830,11 @@ def __init__(self, param, dialog, row=0, col=0, **kwargs): """ from warnings import warn - warn("StringWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "StringWidgetWrapper is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) super().__init__(param, dialog, row, col, **kwargs) self.context = dataobjects.createContext() @@ -1408,8 +1849,14 @@ def createWidget(self): widget.setExpression(self.parameterDefinition().defaultValue()) else: strings = self.dialog.getAvailableValuesOfType( - [QgsProcessingParameterExpression, QgsProcessingParameterString, QgsProcessingParameterNumber, QgsProcessingParameterDistance], - (QgsProcessingOutputString, QgsProcessingOutputNumber)) + [ + QgsProcessingParameterExpression, + QgsProcessingParameterString, + QgsProcessingParameterNumber, + QgsProcessingParameterDistance, + ], + (QgsProcessingOutputString, QgsProcessingOutputNumber), + ) options = [(self.dialog.resolveValueDescription(s), s) for s in strings] widget = QComboBox() widget.setEditable(True) @@ -1420,7 +1867,10 @@ def createWidget(self): def postInitialize(self, wrappers): for wrapper in wrappers: - if wrapper.parameterDefinition().name() == self.parameterDefinition().parentLayerParameterName(): + if ( + wrapper.parameterDefinition().name() + == self.parameterDefinition().parentLayerParameterName() + ): if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): self.setLayer(wrapper.parameterValue()) wrapper.widgetValueHasChanged.connect(self.parentLayerChanged) @@ -1452,14 +1902,19 @@ def value(self): except: return self.widget.expression() else: + def validator(v): - return bool(v) or self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + return ( + bool(v) + or self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ) return self.comboValue(validator) class VectorLayerWidgetWrapper(WidgetWrapper): - NOT_SELECTED = '[Not selected]' + NOT_SELECTED = "[Not selected]" def __init__(self, param, dialog, row=0, col=0, **kwargs): """ @@ -1468,7 +1923,11 @@ def __init__(self, param, dialog, row=0, col=0, **kwargs): """ from warnings import warn - warn("VectorLayerWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "VectorLayerWidgetWrapper is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) super().__init__(param, dialog, row, col, **kwargs) @@ -1483,18 +1942,32 @@ def createWidget(self): except: pass - self.combo.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) + self.combo.valueChanged.connect( + lambda: self.widgetValueHasChanged.emit(self) + ) return self.combo elif self.dialogType == DIALOG_BATCH: - widget = BatchInputSelectionPanel(self.parameterDefinition(), self.row, self.col, self.dialog) + widget = BatchInputSelectionPanel( + self.parameterDefinition(), self.row, self.col, self.dialog + ) widget.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) return widget else: self.combo = QComboBox() self.combo.setEditable(True) - tables = self.dialog.getAvailableValuesOfType((QgsProcessingParameterVectorLayer, QgsProcessingParameterString), - (QgsProcessingOutputVectorLayer, QgsProcessingOutputMapLayer, QgsProcessingOutputFile, QgsProcessingOutputString)) - if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: + tables = self.dialog.getAvailableValuesOfType( + (QgsProcessingParameterVectorLayer, QgsProcessingParameterString), + ( + QgsProcessingOutputVectorLayer, + QgsProcessingOutputMapLayer, + QgsProcessingOutputFile, + QgsProcessingOutputString, + ), + ) + if ( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ): self.combo.addItem(self.NOT_SELECTED, self.NOT_SET_OPTION) for table in tables: self.combo.addItem(self.dialog.resolveValueDescription(table), table) @@ -1506,7 +1979,7 @@ def createWidget(self): layout.setSpacing(6) layout.addWidget(self.combo) btn = QToolButton() - btn.setText('…') + btn.setText("…") btn.setToolTip(self.tr("Select file")) btn.clicked.connect(self.selectFile) layout.addWidget(btn) @@ -1516,7 +1989,9 @@ def createWidget(self): def selectFile(self): filename, selected_filter = self.getFileName(self.combo.currentText()) if filename: - filename = dataobjects.getRasterSublayer(filename, self.parameterDefinition()) + filename = dataobjects.getRasterSublayer( + filename, self.parameterDefinition() + ) if isinstance(self.combo, QgsProcessingMapLayerComboBox): self.combo.setValue(filename, self.context) elif isinstance(self.combo, QgsMapLayerComboBox): @@ -1550,14 +2025,19 @@ def value(self): elif self.dialogType == DIALOG_BATCH: return self.widget.getValue() else: + def validator(v): - return bool(v) or self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + return ( + bool(v) + or self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ) return self.comboValue(validator, combobox=self.combo) class TableFieldWidgetWrapper(WidgetWrapper): - NOT_SET = '[Not set]' + NOT_SET = "[Not set]" def __init__(self, param, dialog, row=0, col=0, **kwargs): super().__init__(param, dialog, row, col, **kwargs) @@ -1567,7 +2047,11 @@ def __init__(self, param, dialog, row=0, col=0, **kwargs): """ from warnings import warn - warn("TableFieldWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "TableFieldWidgetWrapper is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) self.context = dataobjects.createContext() @@ -1580,32 +2064,58 @@ def createWidget(self): return MultipleInputPanel(options=[]) else: widget = QgsFieldComboBox() - widget.setAllowEmptyFieldName(self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) - widget.fieldChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) - if self.parameterDefinition().dataType() == QgsProcessingParameterField.DataType.Numeric: + widget.setAllowEmptyFieldName( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ) + widget.fieldChanged.connect( + lambda: self.widgetValueHasChanged.emit(self) + ) + if ( + self.parameterDefinition().dataType() + == QgsProcessingParameterField.DataType.Numeric + ): widget.setFilters(QgsFieldProxyModel.Filter.Numeric) - elif self.parameterDefinition().dataType() == QgsProcessingParameterField.DataType.String: + elif ( + self.parameterDefinition().dataType() + == QgsProcessingParameterField.DataType.String + ): widget.setFilters(QgsFieldProxyModel.Filter.String) - elif self.parameterDefinition().dataType() == QgsProcessingParameterField.DataType.DateTime: - widget.setFilters(QgsFieldProxyModel.Filter.Date | QgsFieldProxyModel.Filter.Time) + elif ( + self.parameterDefinition().dataType() + == QgsProcessingParameterField.DataType.DateTime + ): + widget.setFilters( + QgsFieldProxyModel.Filter.Date | QgsFieldProxyModel.Filter.Time + ) return widget else: widget = QComboBox() widget.setEditable(True) - fields = self.dialog.getAvailableValuesOfType([QgsProcessingParameterField, QgsProcessingParameterString], - [QgsProcessingOutputString]) - if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: + fields = self.dialog.getAvailableValuesOfType( + [QgsProcessingParameterField, QgsProcessingParameterString], + [QgsProcessingOutputString], + ) + if ( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ): widget.addItem(self.NOT_SET, self.NOT_SET_OPTION) for f in fields: widget.addItem(self.dialog.resolveValueDescription(f), f) widget.setToolTip( self.tr( - 'Input parameter, or name of field (separate field names with ; for multiple field parameters)')) + "Input parameter, or name of field (separate field names with ; for multiple field parameters)" + ) + ) return widget def postInitialize(self, wrappers): for wrapper in wrappers: - if wrapper.parameterDefinition().name() == self.parameterDefinition().parentLayerParameterName(): + if ( + wrapper.parameterDefinition().name() + == self.parameterDefinition().parentLayerParameterName() + ): if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): self.setLayer(wrapper.parameterValue()) wrapper.widgetValueHasChanged.connect(self.parentValueChanged) @@ -1630,15 +2140,24 @@ def setLayer(self, layer): layer = QgsProcessingUtils.mapLayerFromString(layer, self.context) if not isinstance(layer, QgsVectorLayer) or not layer.isValid(): self.dialog.messageBar().clearWidgets() - self.dialog.messageBar().pushMessage("", self.tr("Could not load selected layer/table. Dependent field could not be populated"), - level=Qgis.MessageLevel.Warning, duration=5) + self.dialog.messageBar().pushMessage( + "", + self.tr( + "Could not load selected layer/table. Dependent field could not be populated" + ), + level=Qgis.MessageLevel.Warning, + duration=5, + ) return self._layer = layer self.refreshItems() - if self.parameterDefinition().allowMultiple() and self.parameterDefinition().defaultToAllFields(): + if ( + self.parameterDefinition().allowMultiple() + and self.parameterDefinition().defaultToAllFields() + ): self.setValue(self.getFields()) def refreshItems(self): @@ -1654,12 +2173,26 @@ def getFields(self): if self._layer is None: return [] fieldTypes = [] - if self.parameterDefinition().dataType() == QgsProcessingParameterField.DataType.String: + if ( + self.parameterDefinition().dataType() + == QgsProcessingParameterField.DataType.String + ): fieldTypes = [QVariant.String] - elif self.parameterDefinition().dataType() == QgsProcessingParameterField.DataType.Numeric: - fieldTypes = [QVariant.Int, QVariant.Double, QVariant.LongLong, - QVariant.UInt, QVariant.ULongLong] - elif self.parameterDefinition().dataType() == QgsProcessingParameterField.DataType.DateTime: + elif ( + self.parameterDefinition().dataType() + == QgsProcessingParameterField.DataType.Numeric + ): + fieldTypes = [ + QVariant.Int, + QVariant.Double, + QVariant.LongLong, + QVariant.UInt, + QVariant.ULongLong, + ] + elif ( + self.parameterDefinition().dataType() + == QgsProcessingParameterField.DataType.DateTime + ): fieldTypes = [QVariant.Date, QVariant.Time, QVariant.DateTime] fieldNames = [] @@ -1677,7 +2210,7 @@ def setValue(self, value): options = self.widget.options selected = [] if isinstance(value, str): - value = value.split(';') + value = value.split(";") for v in value: for i, opt in enumerate(options): @@ -1699,18 +2232,27 @@ def value(self): return [self.widget.options[i] for i in self.widget.selectedoptions] else: f = self.widget.currentField() - if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional and not f: + if ( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + and not f + ): return None return f else: + def validator(v): - return bool(v) or self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + return ( + bool(v) + or self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ) return self.comboValue(validator) class BandWidgetWrapper(WidgetWrapper): - NOT_SET = '[Not set]' + NOT_SET = "[Not set]" def __init__(self, param, dialog, row=0, col=0, **kwargs): """ @@ -1719,7 +2261,11 @@ def __init__(self, param, dialog, row=0, col=0, **kwargs): """ from warnings import warn - warn("BandWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "BandWidgetWrapper is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) super().__init__(param, dialog, row, col, **kwargs) self.context = dataobjects.createContext() @@ -1731,15 +2277,27 @@ def createWidget(self): if self.parameterDefinition().allowMultiple(): return MultipleInputPanel(options=[]) widget = QgsRasterBandComboBox() - widget.setShowNotSetOption(self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + widget.setShowNotSetOption( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ) widget.bandChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) return widget else: widget = QComboBox() widget.setEditable(True) - fields = self.dialog.getAvailableValuesOfType([QgsProcessingParameterBand, QgsProcessingParameterDistance, QgsProcessingParameterNumber], - [QgsProcessingOutputNumber]) - if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional: + fields = self.dialog.getAvailableValuesOfType( + [ + QgsProcessingParameterBand, + QgsProcessingParameterDistance, + QgsProcessingParameterNumber, + ], + [QgsProcessingOutputNumber], + ) + if ( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ): widget.addItem(self.NOT_SET, self.NOT_SET_OPTION) for f in fields: widget.addItem(self.dialog.resolveValueDescription(f), f) @@ -1747,7 +2305,10 @@ def createWidget(self): def postInitialize(self, wrappers): for wrapper in wrappers: - if wrapper.parameterDefinition().name() == self.parameterDefinition().parentLayerParameterName(): + if ( + wrapper.parameterDefinition().name() + == self.parameterDefinition().parentLayerParameterName() + ): if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): self.setLayer(wrapper.parameterValue()) wrapper.widgetValueHasChanged.connect(self.parentValueChanged) @@ -1773,7 +2334,7 @@ def getBands(self): name = provider.generateBandName(band) interpretation = provider.colorInterpretationName(band) if interpretation != "Undefined": - name = name + f' ({interpretation})' + name = name + f" ({interpretation})" bands.append(name) return bands @@ -1794,11 +2355,11 @@ def setValue(self, value): options = self.widget.options selected = [] if isinstance(value, str): - value = value.split(';') + value = value.split(";") for v in value: for i, opt in enumerate(options): - match = re.search(f'(?:\\A|[^0-9]){v}(?:\\Z|[^0-9]|)', opt) + match = re.search(f"(?:\\A|[^0-9]){v}(?:\\Z|[^0-9]|)", opt) if match: selected.append(i) @@ -1813,18 +2374,29 @@ def value(self): if self.parameterDefinition().allowMultiple(): bands = [] for i in self.widget.selectedoptions: - match = re.search('(?:\\A|[^0-9])([0-9]+)(?:\\Z|[^0-9]|)', self.widget.options[i]) + match = re.search( + "(?:\\A|[^0-9])([0-9]+)(?:\\Z|[^0-9]|)", self.widget.options[i] + ) if match: bands.append(match.group(1)) return bands else: f = self.widget.currentBand() - if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional and not f: + if ( + self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + and not f + ): return None return f else: + def validator(v): - return bool(v) or self.parameterDefinition().flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + return ( + bool(v) + or self.parameterDefinition().flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ) return self.comboValue(validator) @@ -1836,43 +2408,52 @@ class WidgetWrapperFactory: @staticmethod def create_wrapper(param, dialog, row=0, col=0): - wrapper_metadata = param.metadata().get('widget_wrapper', None) + wrapper_metadata = param.metadata().get("widget_wrapper", None) # VERY messy logic here to avoid breaking 3.0 API which allowed metadata "widget_wrapper" value to be either # a string name of a class OR a dict. # TODO QGIS 4.0 -- require widget_wrapper to be a dict. - if wrapper_metadata and (not isinstance(wrapper_metadata, dict) or wrapper_metadata.get('class', None) is not None): - return WidgetWrapperFactory.create_wrapper_from_metadata(param, dialog, row, col) + if wrapper_metadata and ( + not isinstance(wrapper_metadata, dict) + or wrapper_metadata.get("class", None) is not None + ): + return WidgetWrapperFactory.create_wrapper_from_metadata( + param, dialog, row, col + ) else: # try from c++ registry first class_type = dialog.__class__.__name__ - if class_type == 'ModelerParametersDialog': - wrapper = QgsGui.processingGuiRegistry().createModelerParameterWidget(dialog.model, - dialog.childId, - param, - dialog.context) + if class_type == "ModelerParametersDialog": + wrapper = QgsGui.processingGuiRegistry().createModelerParameterWidget( + dialog.model, dialog.childId, param, dialog.context + ) else: - dialog_type = dialogTypes.get(class_type, - QgsProcessingGui.WidgetType.Standard) - wrapper = QgsGui.processingGuiRegistry().createParameterWidgetWrapper(param, dialog_type) + dialog_type = dialogTypes.get( + class_type, QgsProcessingGui.WidgetType.Standard + ) + wrapper = QgsGui.processingGuiRegistry().createParameterWidgetWrapper( + param, dialog_type + ) if wrapper is not None: wrapper.setDialog(dialog) return wrapper # fallback to Python registry - return WidgetWrapperFactory.create_wrapper_from_class(param, dialog, row, col) + return WidgetWrapperFactory.create_wrapper_from_class( + param, dialog, row, col + ) @staticmethod def create_wrapper_from_metadata(param, dialog, row=0, col=0): - wrapper = param.metadata().get('widget_wrapper', None) + wrapper = param.metadata().get("widget_wrapper", None) params = {} # wrapper metadata should be a dict with class key if isinstance(wrapper, dict): params = deepcopy(wrapper) - wrapper = params.pop('class') + wrapper = params.pop("class") # wrapper metadata should be a class path if isinstance(wrapper, str): - tokens = wrapper.split('.') - mod = __import__('.'.join(tokens[:-1]), fromlist=[tokens[-1]]) + tokens = wrapper.split(".") + mod = __import__(".".join(tokens[:-1]), fromlist=[tokens[-1]]) wrapper = getattr(mod, tokens[-1]) # or directly a class object if isclass(wrapper): @@ -1883,63 +2464,63 @@ def create_wrapper_from_metadata(param, dialog, row=0, col=0): @staticmethod def create_wrapper_from_class(param, dialog, row=0, col=0): wrapper = None - if param.type() == 'boolean': + if param.type() == "boolean": # deprecated, moved to c++ wrapper = BooleanWidgetWrapper - elif param.type() == 'crs': + elif param.type() == "crs": # deprecated, moved to c++ wrapper = CrsWidgetWrapper - elif param.type() == 'extent': + elif param.type() == "extent": # deprecated, moved to c++ wrapper = ExtentWidgetWrapper - elif param.type() == 'point': + elif param.type() == "point": # deprecated, moved to c++ wrapper = PointWidgetWrapper - elif param.type() == 'file': + elif param.type() == "file": # deprecated, moved to c++ wrapper = FileWidgetWrapper - elif param.type() == 'multilayer': + elif param.type() == "multilayer": wrapper = MultipleLayerWidgetWrapper - elif param.type() == 'number': + elif param.type() == "number": # deprecated, moved to c++ wrapper = NumberWidgetWrapper - elif param.type() == 'distance': + elif param.type() == "distance": # deprecated, moved to c++ wrapper = DistanceWidgetWrapper - elif param.type() == 'raster': + elif param.type() == "raster": # deprecated, moved to c++ wrapper = RasterWidgetWrapper - elif param.type() == 'enum': + elif param.type() == "enum": # deprecated, moved to c++ wrapper = EnumWidgetWrapper - elif param.type() == 'string': + elif param.type() == "string": # deprecated, moved to c++ wrapper = StringWidgetWrapper - elif param.type() == 'expression': + elif param.type() == "expression": # deprecated, moved to c++ wrapper = ExpressionWidgetWrapper - elif param.type() == 'vector': + elif param.type() == "vector": # deprecated, moved to c++ wrapper = VectorLayerWidgetWrapper - elif param.type() == 'field': + elif param.type() == "field": # deprecated, moved to c++ wrapper = TableFieldWidgetWrapper - elif param.type() == 'source': + elif param.type() == "source": # deprecated, moved to c++ wrapper = FeatureSourceWidgetWrapper - elif param.type() == 'band': + elif param.type() == "band": # deprecated, moved to c++ wrapper = BandWidgetWrapper - elif param.type() == 'layer': + elif param.type() == "layer": # deprecated, moved to c++ wrapper = MapLayerWidgetWrapper - elif param.type() == 'range': + elif param.type() == "range": # deprecated, moved to c++ wrapper = RangeWidgetWrapper - elif param.type() == 'matrix': + elif param.type() == "matrix": # deprecated, moved to c++ wrapper = FixedTableWidgetWrapper - elif param.type() == 'mesh': + elif param.type() == "mesh": # deprecated, moved to c++ wrapper = MeshWidgetWrapper else: diff --git a/python/plugins/processing/modeler/AddModelFromFileAction.py b/python/plugins/processing/modeler/AddModelFromFileAction.py index c0631b8b8524..69772ff95e24 100644 --- a/python/plugins/processing/modeler/AddModelFromFileAction.py +++ b/python/plugins/processing/modeler/AddModelFromFileAction.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'April 2014' -__copyright__ = '(C) 201, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "April 2014" +__copyright__ = "(C) 201, Victor Olaya" import os import shutil @@ -35,48 +35,75 @@ class AddModelFromFileAction(ToolboxAction): def __init__(self): - self.name = QCoreApplication.translate('AddModelFromFileAction', 'Add Model to Toolbox…') - self.group = self.tr('Tools') + self.name = QCoreApplication.translate( + "AddModelFromFileAction", "Add Model to Toolbox…" + ) + self.group = self.tr("Tools") def getIcon(self): return QgsApplication.getThemeIcon("/processingModel.svg") def execute(self): settings = QgsSettings() - lastDir = settings.value('Processing/lastModelsDir', QDir.homePath()) - filename, selected_filter = QFileDialog.getOpenFileName(self.toolbox, - self.tr('Open Model', 'AddModelFromFileAction'), lastDir, - self.tr('Processing models (*.model3 *.MODEL3)', 'AddModelFromFileAction')) + lastDir = settings.value("Processing/lastModelsDir", QDir.homePath()) + filename, selected_filter = QFileDialog.getOpenFileName( + self.toolbox, + self.tr("Open Model", "AddModelFromFileAction"), + lastDir, + self.tr("Processing models (*.model3 *.MODEL3)", "AddModelFromFileAction"), + ) if filename: - settings.setValue('Processing/lastModelsDir', - QFileInfo(filename).absoluteDir().absolutePath()) + settings.setValue( + "Processing/lastModelsDir", + QFileInfo(filename).absoluteDir().absolutePath(), + ) alg = QgsProcessingModelAlgorithm() if not alg.fromFile(filename): QMessageBox.warning( self.toolbox, - self.tr('Open Model', 'AddModelFromFileAction'), - self.tr('The selected file does not contain a valid model', 'AddModelFromFileAction')) + self.tr("Open Model", "AddModelFromFileAction"), + self.tr( + "The selected file does not contain a valid model", + "AddModelFromFileAction", + ), + ) return - if QgsApplication.instance().processingRegistry().algorithmById(f'model:{alg.id()}'): + if ( + QgsApplication.instance() + .processingRegistry() + .algorithmById(f"model:{alg.id()}") + ): QMessageBox.warning( self.toolbox, - self.tr('Open Model', 'AddModelFromFileAction'), - self.tr('Model with the same name already exists', 'AddModelFromFileAction')) + self.tr("Open Model", "AddModelFromFileAction"), + self.tr( + "Model with the same name already exists", + "AddModelFromFileAction", + ), + ) return - destFilename = os.path.join(ModelerUtils.modelsFolders()[0], os.path.basename(filename)) + destFilename = os.path.join( + ModelerUtils.modelsFolders()[0], os.path.basename(filename) + ) if os.path.exists(destFilename): reply = QMessageBox.question( self.toolbox, - self.tr('Open Model', 'AddModelFromFileAction'), - self.tr('There is already a model file with the same name. Overwrite?', 'AddModelFromFileAction'), + self.tr("Open Model", "AddModelFromFileAction"), + self.tr( + "There is already a model file with the same name. Overwrite?", + "AddModelFromFileAction", + ), QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, - QMessageBox.StandardButton.No) + QMessageBox.StandardButton.No, + ) if reply == QMessageBox.StandardButton.No: return shutil.copyfile(filename, destFilename) - QgsApplication.processingRegistry().providerById('model').refreshAlgorithms() + QgsApplication.processingRegistry().providerById( + "model" + ).refreshAlgorithms() diff --git a/python/plugins/processing/modeler/CreateNewModelAction.py b/python/plugins/processing/modeler/CreateNewModelAction.py index 8ae7b815d466..5e3bcad91d39 100644 --- a/python/plugins/processing/modeler/CreateNewModelAction.py +++ b/python/plugins/processing/modeler/CreateNewModelAction.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os @@ -35,8 +35,10 @@ class CreateNewModelAction(ToolboxAction): def __init__(self): - self.name = QCoreApplication.translate('CreateNewModelAction', 'Create New Model…') - self.group = self.tr('Tools') + self.name = QCoreApplication.translate( + "CreateNewModelAction", "Create New Model…" + ) + self.group = self.tr("Tools") def getIcon(self): return QgsApplication.getThemeIcon("/processingModel.svg") @@ -47,4 +49,4 @@ def execute(self): dlg.show() def updateModel(self): - QgsApplication.processingRegistry().providerById('model').refreshAlgorithms() + QgsApplication.processingRegistry().providerById("model").refreshAlgorithms() diff --git a/python/plugins/processing/modeler/DeleteModelAction.py b/python/plugins/processing/modeler/DeleteModelAction.py index 9eb472fa2e87..2774708d68a7 100644 --- a/python/plugins/processing/modeler/DeleteModelAction.py +++ b/python/plugins/processing/modeler/DeleteModelAction.py @@ -15,14 +15,12 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os -from qgis.core import (QgsApplication, - QgsProcessingAlgorithm, - QgsProject) +from qgis.core import QgsApplication, QgsProcessingAlgorithm, QgsProject from qgis.PyQt.QtWidgets import QMessageBox from qgis.PyQt.QtCore import QCoreApplication from processing.gui.ContextAction import ContextAction @@ -33,10 +31,12 @@ class DeleteModelAction(ContextAction): def __init__(self): super().__init__() - self.name = QCoreApplication.translate('DeleteModelAction', 'Delete Model…') + self.name = QCoreApplication.translate("DeleteModelAction", "Delete Model…") def isEnabled(self): - return isinstance(self.itemData, QgsProcessingAlgorithm) and self.itemData.provider().id() in ("model", "project") + return isinstance( + self.itemData, QgsProcessingAlgorithm + ) and self.itemData.provider().id() in ("model", "project") def execute(self): model = self.itemData @@ -46,22 +46,32 @@ def execute(self): project_provider = model.provider().id() == PROJECT_PROVIDER_ID if project_provider: - msg = self.tr('Are you sure you want to delete this model from the current project?', 'DeleteModelAction') + msg = self.tr( + "Are you sure you want to delete this model from the current project?", + "DeleteModelAction", + ) else: - msg = self.tr('Are you sure you want to delete this model?', 'DeleteModelAction') + msg = self.tr( + "Are you sure you want to delete this model?", "DeleteModelAction" + ) reply = QMessageBox.question( None, - self.tr('Delete Model', 'DeleteModelAction'), + self.tr("Delete Model", "DeleteModelAction"), msg, QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, - QMessageBox.StandardButton.No) + QMessageBox.StandardButton.No, + ) if reply == QMessageBox.StandardButton.Yes: if project_provider: - provider = QgsApplication.processingRegistry().providerById(PROJECT_PROVIDER_ID) + provider = QgsApplication.processingRegistry().providerById( + PROJECT_PROVIDER_ID + ) provider.remove_model(model) QgsProject.instance().setDirty(True) else: os.remove(model.sourceFilePath()) - QgsApplication.processingRegistry().providerById('model').refreshAlgorithms() + QgsApplication.processingRegistry().providerById( + "model" + ).refreshAlgorithms() diff --git a/python/plugins/processing/modeler/EditModelAction.py b/python/plugins/processing/modeler/EditModelAction.py index 9eb0fc287354..e7bc4e2c8668 100644 --- a/python/plugins/processing/modeler/EditModelAction.py +++ b/python/plugins/processing/modeler/EditModelAction.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" from qgis.PyQt.QtCore import QCoreApplication from qgis.core import QgsApplication, QgsProcessingAlgorithm @@ -31,10 +31,12 @@ class EditModelAction(ContextAction): def __init__(self): super().__init__() - self.name = QCoreApplication.translate('EditModelAction', 'Edit Model…') + self.name = QCoreApplication.translate("EditModelAction", "Edit Model…") def isEnabled(self): - return isinstance(self.itemData, QgsProcessingAlgorithm) and self.itemData.provider().id() in ("model", "project") + return isinstance( + self.itemData, QgsProcessingAlgorithm + ) and self.itemData.provider().id() in ("model", "project") def execute(self): alg = self.itemData @@ -44,4 +46,4 @@ def execute(self): dlg.activate() def updateModel(self): - QgsApplication.processingRegistry().providerById('model').refreshAlgorithms() + QgsApplication.processingRegistry().providerById("model").refreshAlgorithms() diff --git a/python/plugins/processing/modeler/ExportModelAsPythonScriptAction.py b/python/plugins/processing/modeler/ExportModelAsPythonScriptAction.py index 8e84b6eb0838..ecca641352d9 100644 --- a/python/plugins/processing/modeler/ExportModelAsPythonScriptAction.py +++ b/python/plugins/processing/modeler/ExportModelAsPythonScriptAction.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'February 2019' -__copyright__ = '(C) 2019, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "February 2019" +__copyright__ = "(C) 2019, Nyall Dawson" from qgis.PyQt.QtCore import QCoreApplication from qgis.core import QgsProcessingAlgorithm, QgsProcessing, QgsApplication @@ -31,17 +31,28 @@ class ExportModelAsPythonScriptAction(ContextAction): def __init__(self): super().__init__() - self.name = QCoreApplication.translate('ExportModelAsPythonScriptAction', 'Export Model as Python Algorithm…') + self.name = QCoreApplication.translate( + "ExportModelAsPythonScriptAction", "Export Model as Python Algorithm…" + ) def isEnabled(self): - return isinstance(self.itemData, QgsProcessingAlgorithm) and self.itemData.provider().id() in ("model", "project") + return isinstance( + self.itemData, QgsProcessingAlgorithm + ) and self.itemData.provider().id() in ("model", "project") def icon(self): - return QgsApplication.getThemeIcon('/mActionSaveAsPython.svg') + return QgsApplication.getThemeIcon("/mActionSaveAsPython.svg") def execute(self): alg = self.itemData dlg = ScriptEditorDialog(parent=iface.mainWindow()) - dlg.editor.setText('\n'.join(alg.asPythonCode(QgsProcessing.PythonOutputType.PythonQgsProcessingAlgorithmSubclass, 4))) + dlg.editor.setText( + "\n".join( + alg.asPythonCode( + QgsProcessing.PythonOutputType.PythonQgsProcessingAlgorithmSubclass, + 4, + ) + ) + ) dlg.show() diff --git a/python/plugins/processing/modeler/ModelerAlgorithmProvider.py b/python/plugins/processing/modeler/ModelerAlgorithmProvider.py index 493b72734679..236412c58e34 100644 --- a/python/plugins/processing/modeler/ModelerAlgorithmProvider.py +++ b/python/plugins/processing/modeler/ModelerAlgorithmProvider.py @@ -15,30 +15,33 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os -from qgis.core import (Qgis, - QgsApplication, - QgsProcessingProvider, - QgsMessageLog, - QgsProcessingModelAlgorithm, - QgsRuntimeProfiler) +from qgis.core import ( + Qgis, + QgsApplication, + QgsProcessingProvider, + QgsMessageLog, + QgsProcessingModelAlgorithm, + QgsRuntimeProfiler, +) from processing.core.ProcessingConfig import ProcessingConfig, Setting from processing.gui.ContextAction import ContextAction -from processing.gui.ProviderActions import (ProviderActions, - ProviderContextMenuActions) +from processing.gui.ProviderActions import ProviderActions, ProviderContextMenuActions from processing.modeler.AddModelFromFileAction import AddModelFromFileAction from processing.modeler.CreateNewModelAction import CreateNewModelAction from processing.modeler.DeleteModelAction import DeleteModelAction from processing.modeler.EditModelAction import EditModelAction -from processing.modeler.ExportModelAsPythonScriptAction import ExportModelAsPythonScriptAction +from processing.modeler.ExportModelAsPythonScriptAction import ( + ExportModelAsPythonScriptAction, +) from processing.modeler.OpenModelFromFileAction import OpenModelFromFileAction from processing.modeler.ModelerUtils import ModelerUtils @@ -49,10 +52,19 @@ class ModelerAlgorithmProvider(QgsProcessingProvider): def __init__(self): super().__init__() - self.actions = [CreateNewModelAction(), OpenModelFromFileAction(), AddModelFromFileAction()] + self.actions = [ + CreateNewModelAction(), + OpenModelFromFileAction(), + AddModelFromFileAction(), + ] sep_action = ContextAction() sep_action.is_separator = True - self.contextMenuActions = [EditModelAction(), DeleteModelAction(), sep_action, ExportModelAsPythonScriptAction()] + self.contextMenuActions = [ + EditModelAction(), + DeleteModelAction(), + sep_action, + ExportModelAsPythonScriptAction(), + ] self.algs = [] self.isLoading = False @@ -67,13 +79,21 @@ def onProviderAdded(self, provider_id): self.refreshAlgorithms() def load(self): - with QgsRuntimeProfiler.profile('Model Provider'): + with QgsRuntimeProfiler.profile("Model Provider"): ProcessingConfig.settingIcons[self.name()] = self.icon() - ProcessingConfig.addSetting(Setting(self.name(), - ModelerUtils.MODELS_FOLDER, self.tr('Models folder', 'ModelerAlgorithmProvider'), - ModelerUtils.defaultModelsFolder(), valuetype=Setting.MULTIPLE_FOLDERS)) + ProcessingConfig.addSetting( + Setting( + self.name(), + ModelerUtils.MODELS_FOLDER, + self.tr("Models folder", "ModelerAlgorithmProvider"), + ModelerUtils.defaultModelsFolder(), + valuetype=Setting.MULTIPLE_FOLDERS, + ) + ) ProviderActions.registerProviderActions(self, self.actions) - ProviderContextMenuActions.registerProviderContextMenuActions(self.contextMenuActions) + ProviderContextMenuActions.registerProviderContextMenuActions( + self.contextMenuActions + ) ProcessingConfig.readSettings() self.refreshAlgorithms() @@ -81,16 +101,18 @@ def load(self): def unload(self): ProviderActions.deregisterProviderActions(self) - ProviderContextMenuActions.deregisterProviderContextMenuActions(self.contextMenuActions) + ProviderContextMenuActions.deregisterProviderContextMenuActions( + self.contextMenuActions + ) def modelsFolder(self): return ModelerUtils.modelsFolders()[0] def name(self): - return self.tr('Models', 'ModelerAlgorithmProvider') + return self.tr("Models", "ModelerAlgorithmProvider") def id(self): - return 'model' + return "model" def icon(self): return QgsApplication.getThemeIcon("/processingModel.svg") @@ -102,7 +124,7 @@ def supportsNonFileBasedOutput(self): return True def loadAlgorithms(self): - with QgsRuntimeProfiler.profile('Load model algorithms'): + with QgsRuntimeProfiler.profile("Load model algorithms"): if self.isLoading: return self.isLoading = True @@ -119,7 +141,7 @@ def loadFromFolder(self, folder): return for path, subdirs, files in os.walk(folder): for descriptionFile in files: - if descriptionFile.endswith('model3'): + if descriptionFile.endswith("model3"): fullpath = os.path.join(path, descriptionFile) alg = QgsProcessingModelAlgorithm() @@ -128,5 +150,10 @@ def loadFromFolder(self, folder): alg.setSourceFilePath(fullpath) self.algs.append(alg) else: - QgsMessageLog.logMessage(self.tr('Could not load model {0}', 'ModelerAlgorithmProvider').format(descriptionFile), - self.tr('Processing'), Qgis.MessageLevel.Critical) + QgsMessageLog.logMessage( + self.tr( + "Could not load model {0}", "ModelerAlgorithmProvider" + ).format(descriptionFile), + self.tr("Processing"), + Qgis.MessageLevel.Critical, + ) diff --git a/python/plugins/processing/modeler/ModelerDialog.py b/python/plugins/processing/modeler/ModelerDialog.py index bbec5d6b0068..d4d2419c4cf6 100644 --- a/python/plugins/processing/modeler/ModelerDialog.py +++ b/python/plugins/processing/modeler/ModelerDialog.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import re @@ -32,29 +32,34 @@ QPointF, pyqtSignal, QUrl, - QFileInfo) -from qgis.PyQt.QtWidgets import (QMessageBox, - QFileDialog) -from qgis.core import (Qgis, - QgsApplication, - QgsProcessing, - QgsProject, - QgsProcessingModelParameter, - QgsProcessingModelAlgorithm, - QgsSettings, - QgsProcessingContext, - QgsFileUtils - ) -from qgis.gui import (QgsProcessingParameterDefinitionDialog, - QgsProcessingParameterWidgetContext, - QgsModelGraphicsScene, - QgsModelDesignerDialog, - QgsProcessingContextGenerator, - QgsProcessingParametersGenerator) + QFileInfo, +) +from qgis.PyQt.QtWidgets import QMessageBox, QFileDialog +from qgis.core import ( + Qgis, + QgsApplication, + QgsProcessing, + QgsProject, + QgsProcessingModelParameter, + QgsProcessingModelAlgorithm, + QgsSettings, + QgsProcessingContext, + QgsFileUtils, +) +from qgis.gui import ( + QgsProcessingParameterDefinitionDialog, + QgsProcessingParameterWidgetContext, + QgsModelGraphicsScene, + QgsModelDesignerDialog, + QgsProcessingContextGenerator, + QgsProcessingParametersGenerator, +) from qgis.utils import iface from processing.gui.AlgorithmDialog import AlgorithmDialog -from processing.modeler.ModelerParameterDefinitionDialog import ModelerParameterDefinitionDialog +from processing.modeler.ModelerParameterDefinitionDialog import ( + ModelerParameterDefinitionDialog, +) from processing.modeler.ModelerParametersDialog import ModelerParametersDialog from processing.modeler.ModelerScene import ModelerScene from processing.modeler.ModelerUtils import ModelerUtils @@ -131,12 +136,18 @@ def saveInProject(self): self.model().setSourceFilePath(None) - project_provider = QgsApplication.processingRegistry().providerById(PROJECT_PROVIDER_ID) + project_provider = QgsApplication.processingRegistry().providerById( + PROJECT_PROVIDER_ID + ) project_provider.add_model(self.model()) self.update_model.emit() - self.messageBar().pushMessage("", self.tr("Model was saved inside current project"), level=Qgis.MessageLevel.Success, - duration=5) + self.messageBar().pushMessage( + "", + self.tr("Model was saved inside current project"), + level=Qgis.MessageLevel.Success, + duration=5, + ) self.setDirty(False) QgsProject.instance().setDirty(True) @@ -152,21 +163,25 @@ def saveModel(self, saveAs) -> bool: if self.model().sourceFilePath(): initial_path = Path(self.model().sourceFilePath()) elif self.model().name(): - initial_path = Path(ModelerUtils.modelsFolders()[0]) / (self.model().name() + '.model3') + initial_path = Path(ModelerUtils.modelsFolders()[0]) / ( + self.model().name() + ".model3" + ) else: initial_path = Path(ModelerUtils.modelsFolders()[0]) - filename, _ = QFileDialog.getSaveFileName(self, - self.tr('Save Model'), - initial_path.as_posix(), - self.tr('Processing models (*.model3 *.MODEL3)')) + filename, _ = QFileDialog.getSaveFileName( + self, + self.tr("Save Model"), + initial_path.as_posix(), + self.tr("Processing models (*.model3 *.MODEL3)"), + ) if not filename: return False - filename = QgsFileUtils.ensureFileNameHasExtension(filename, ['model3']) + filename = QgsFileUtils.ensureFileNameHasExtension(filename, ["model3"]) self.model().setSourceFilePath(filename) - if not self.model().name() or self.model().name() == self.tr('model'): + if not self.model().name() or self.model().name() == self.tr("model"): self.setModelName(Path(filename).stem) elif saveAs and model_name_matched_file_name: # if saving as, and the model name used to match the filename, then automatically update the @@ -175,20 +190,35 @@ def saveModel(self, saveAs) -> bool: if not self.model().toFile(filename): if saveAs: - QMessageBox.warning(self, self.tr('I/O error'), - self.tr('Unable to save edits. Reason:\n {0}').format(str(sys.exc_info()[1]))) + QMessageBox.warning( + self, + self.tr("I/O error"), + self.tr("Unable to save edits. Reason:\n {0}").format( + str(sys.exc_info()[1]) + ), + ) else: - QMessageBox.warning(self, self.tr("Can't save model"), - self.tr( - "This model can't be saved in its original location (probably you do not " - "have permission to do it). Please, use the 'Save as…' option.")) + QMessageBox.warning( + self, + self.tr("Can't save model"), + self.tr( + "This model can't be saved in its original location (probably you do not " + "have permission to do it). Please, use the 'Save as…' option." + ), + ) return False self.update_model.emit() if saveAs: - self.messageBar().pushMessage("", self.tr("Model was saved to {}").format( - QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.MessageLevel.Success, - duration=5) + self.messageBar().pushMessage( + "", + self.tr('Model was saved to {}').format( + QUrl.fromLocalFile(filename).toString(), + QDir.toNativeSeparators(filename), + ), + level=Qgis.MessageLevel.Success, + duration=5, + ) self.setDirty(False) return True @@ -198,25 +228,30 @@ def openModel(self): return settings = QgsSettings() - last_dir = settings.value('Processing/lastModelsDir', QDir.homePath()) - filename, selected_filter = QFileDialog.getOpenFileName(self, - self.tr('Open Model'), - last_dir, - self.tr('Processing models (*.model3 *.MODEL3)')) + last_dir = settings.value("Processing/lastModelsDir", QDir.homePath()) + filename, selected_filter = QFileDialog.getOpenFileName( + self, + self.tr("Open Model"), + last_dir, + self.tr("Processing models (*.model3 *.MODEL3)"), + ) if filename: - settings.setValue('Processing/lastModelsDir', - QFileInfo(filename).absoluteDir().absolutePath()) + settings.setValue( + "Processing/lastModelsDir", + QFileInfo(filename).absoluteDir().absolutePath(), + ) self.loadModel(filename) def repaintModel(self, showControls=True): scene = ModelerScene(self) - scene.setSceneRect(QRectF(0, 0, self.CANVAS_SIZE, - self.CANVAS_SIZE)) + scene.setSceneRect(QRectF(0, 0, self.CANVAS_SIZE, self.CANVAS_SIZE)) if not showControls: scene.setFlag(QgsModelGraphicsScene.Flag.FlagHideControls) - showComments = QgsSettings().value("/Processing/Modeler/ShowComments", True, bool) + showComments = QgsSettings().value( + "/Processing/Modeler/ShowComments", True, bool + ) if not showComments: scene.setFlag(QgsModelGraphicsScene.Flag.FlagHideComments) @@ -251,7 +286,10 @@ def autogenerate_parameter_name(self, parameter): parameter.setName(name) def addInput(self, paramType, pos=None): - if paramType not in [param.id() for param in QgsApplication.instance().processingRegistry().parameterTypes()]: + if paramType not in [ + param.id() + for param in QgsApplication.instance().processingRegistry().parameterTypes() + ]: return new_param = None @@ -265,10 +303,12 @@ def addInput(self, paramType, pos=None): # yay, use new API! context = createContext() widget_context = self.create_widget_context() - dlg = QgsProcessingParameterDefinitionDialog(type=paramType, - context=context, - widgetContext=widget_context, - algorithm=self.model()) + dlg = QgsProcessingParameterDefinitionDialog( + type=paramType, + context=context, + widgetContext=widget_context, + algorithm=self.model(), + ) dlg.registerProcessingContextGenerator(self.context_generator) if dlg.exec(): new_param = dlg.createParameter() @@ -285,11 +325,12 @@ def addInput(self, paramType, pos=None): component.setPosition(pos) component.comment().setDescription(comment) - component.comment().setPosition(component.position() + QPointF( - component.size().width(), - -1.5 * component.size().height())) + component.comment().setPosition( + component.position() + + QPointF(component.size().width(), -1.5 * component.size().height()) + ) - self.beginUndoCommand(self.tr('Add Model Input')) + self.beginUndoCommand(self.tr("Add Model Input")) self.model().addModelParameter(new_param, component) self.repaintModel() # self.view().ensureVisible(self.scene.getLastParameterItem()) @@ -300,7 +341,12 @@ def getPositionForParameterItem(self): BOX_WIDTH = 200 BOX_HEIGHT = 80 if len(self.model().parameterComponents()) > 0: - maxX = max([i.position().x() for i in list(self.model().parameterComponents().values())]) + maxX = max( + [ + i.position().x() + for i in list(self.model().parameterComponents().values()) + ] + ) newX = min(MARGIN + BOX_WIDTH + maxX, self.CANVAS_SIZE - BOX_WIDTH) else: newX = MARGIN + BOX_WIDTH / 2 @@ -319,17 +365,19 @@ def addAlgorithm(self, alg_id, pos=None): else: alg.setPosition(pos) - alg.comment().setPosition(alg.position() + QPointF( - alg.size().width(), - -1.5 * alg.size().height())) + alg.comment().setPosition( + alg.position() + QPointF(alg.size().width(), -1.5 * alg.size().height()) + ) output_offset_x = alg.size().width() output_offset_y = 1.5 * alg.size().height() for out in alg.modelOutputs(): - alg.modelOutput(out).setPosition(alg.position() + QPointF(output_offset_x, output_offset_y)) + alg.modelOutput(out).setPosition( + alg.position() + QPointF(output_offset_x, output_offset_y) + ) output_offset_y += 1.5 * alg.modelOutput(out).size().height() - self.beginUndoCommand(self.tr('Add Algorithm')) + self.beginUndoCommand(self.tr("Add Algorithm")) id = self.model().addChildAlgorithm(alg) self.repaintModel() self.endUndoCommand() @@ -337,10 +385,15 @@ def addAlgorithm(self, alg_id, pos=None): res, errors = self.model().validateChildAlgorithm(id) if not res: self.view().scene().showWarning( - QCoreApplication.translate('ModelerDialog', 'Algorithm “{}” is invalid').format(alg.description()), - self.tr('Algorithm is Invalid'), - QCoreApplication.translate('ModelerDialog', "

The “{}” algorithm is invalid, because:

  • {}
").format(alg.description(), '
  • '.join(errors)), - level=Qgis.MessageLevel.Warning + QCoreApplication.translate( + "ModelerDialog", "Algorithm “{}” is invalid" + ).format(alg.description()), + self.tr("Algorithm is Invalid"), + QCoreApplication.translate( + "ModelerDialog", + "

    The “{}” algorithm is invalid, because:

    • {}
    ", + ).format(alg.description(), "
  • ".join(errors)), + level=Qgis.MessageLevel.Warning, ) else: self.view().scene().messageBar().clearWidgets() @@ -350,11 +403,20 @@ def getPositionForAlgorithmItem(self): BOX_WIDTH = 200 BOX_HEIGHT = 80 if self.model().childAlgorithms(): - maxX = max([alg.position().x() for alg in list(self.model().childAlgorithms().values())]) - maxY = max([alg.position().y() for alg in list(self.model().childAlgorithms().values())]) + maxX = max( + [ + alg.position().x() + for alg in list(self.model().childAlgorithms().values()) + ] + ) + maxY = max( + [ + alg.position().y() + for alg in list(self.model().childAlgorithms().values()) + ] + ) newX = min(MARGIN + BOX_WIDTH + maxX, self.CANVAS_SIZE - BOX_WIDTH) - newY = min(MARGIN + BOX_HEIGHT + maxY, self.CANVAS_SIZE - - BOX_HEIGHT) + newY = min(MARGIN + BOX_HEIGHT + maxY, self.CANVAS_SIZE - BOX_HEIGHT) else: newX = MARGIN + BOX_WIDTH / 2 newY = MARGIN * 2 + BOX_HEIGHT + BOX_HEIGHT / 2 @@ -363,5 +425,12 @@ def getPositionForAlgorithmItem(self): def exportAsScriptAlgorithm(self): dlg = ScriptEditorDialog(parent=iface.mainWindow()) - dlg.editor.setText('\n'.join(self.model().asPythonCode(QgsProcessing.PythonOutputType.PythonQgsProcessingAlgorithmSubclass, 4))) + dlg.editor.setText( + "\n".join( + self.model().asPythonCode( + QgsProcessing.PythonOutputType.PythonQgsProcessingAlgorithmSubclass, + 4, + ) + ) + ) dlg.show() diff --git a/python/plugins/processing/modeler/ModelerGraphicItem.py b/python/plugins/processing/modeler/ModelerGraphicItem.py index 69e6e7dbf356..491779e6f565 100644 --- a/python/plugins/processing/modeler/ModelerGraphicItem.py +++ b/python/plugins/processing/modeler/ModelerGraphicItem.py @@ -15,26 +15,30 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" from qgis.PyQt.QtCore import QCoreApplication -from qgis.core import (QgsProcessingParameterDefinition, - QgsProcessingModelOutput, - QgsProcessingModelAlgorithm, - QgsProject, - Qgis) +from qgis.core import ( + QgsProcessingParameterDefinition, + QgsProcessingModelOutput, + QgsProcessingModelAlgorithm, + QgsProject, + Qgis, +) from qgis.gui import ( QgsProcessingParameterDefinitionDialog, QgsProcessingParameterWidgetContext, QgsModelParameterGraphicItem, QgsModelChildAlgorithmGraphicItem, QgsModelOutputGraphicItem, - QgsProcessingContextGenerator + QgsProcessingContextGenerator, +) +from processing.modeler.ModelerParameterDefinitionDialog import ( + ModelerParameterDefinitionDialog, ) -from processing.modeler.ModelerParameterDefinitionDialog import ModelerParameterDefinitionDialog from processing.modeler.ModelerParametersDialog import ModelerParametersDialog from processing.tools.dataobjects import createContext from qgis.utils import iface @@ -78,7 +82,9 @@ def create_widget_context(self): return widget_context def edit(self, edit_comment=False): - existing_param = self.model().parameterDefinition(self.component().parameterName()) + existing_param = self.model().parameterDefinition( + self.component().parameterName() + ) old_name = existing_param.name() old_description = existing_param.description() @@ -87,8 +93,7 @@ def edit(self, edit_comment=False): new_param = None if ModelerParameterDefinitionDialog.use_legacy_dialog(param=existing_param): # boo, old api - dlg = ModelerParameterDefinitionDialog(self.model(), - param=existing_param) + dlg = ModelerParameterDefinitionDialog(self.model(), param=existing_param) dlg.setComments(comment) dlg.setCommentColor(comment_color) if edit_comment: @@ -101,11 +106,13 @@ def edit(self, edit_comment=False): # yay, use new API! context = createContext() widget_context = self.create_widget_context() - dlg = QgsProcessingParameterDefinitionDialog(type=existing_param.type(), - context=context, - widgetContext=widget_context, - definition=existing_param, - algorithm=self.model()) + dlg = QgsProcessingParameterDefinitionDialog( + type=existing_param.type(), + context=context, + widgetContext=widget_context, + definition=existing_param, + algorithm=self.model(), + ) dlg.setComments(comment) dlg.setCommentColor(comment_color) dlg.registerProcessingContextGenerator(self.context_generator) @@ -122,7 +129,7 @@ def edit(self, edit_comment=False): new_param.setName(safeName.lower()) if new_param is not None: - self.aboutToChange.emit(self.tr('Edit {}').format(new_param.description())) + self.aboutToChange.emit(self.tr("Edit {}").format(new_param.description())) self.model().removeModelParameter(self.component().parameterName()) if new_param.description() != old_description: @@ -169,8 +176,12 @@ def __init__(self, element, model): def edit(self, edit_comment=False): elemAlg = self.component().algorithm() - dlg = ModelerParametersDialog(elemAlg, self.model(), self.component().childId(), - self.component().configuration()) + dlg = ModelerParametersDialog( + elemAlg, + self.model(), + self.component().childId(), + self.component().configuration(), + ) dlg.setComments(self.component().comment().description()) dlg.setCommentColor(self.component().comment().color()) if edit_comment: @@ -179,7 +190,7 @@ def edit(self, edit_comment=False): alg = dlg.createAlgorithm() alg.setChildId(self.component().childId()) alg.copyNonDefinitionPropertiesFromModel(self.model()) - self.aboutToChange.emit(self.tr('Edit {}').format(alg.description())) + self.aboutToChange.emit(self.tr("Edit {}").format(alg.description())) self.model().setChildAlgorithm(alg) self.requestModelRepaint.emit() self.changed.emit() @@ -187,10 +198,15 @@ def edit(self, edit_comment=False): res, errors = self.model().validateChildAlgorithm(alg.childId()) if not res: self.scene().showWarning( - QCoreApplication.translate('ModelerGraphicItem', 'Algorithm “{}” is invalid').format(alg.description()), - self.tr('Algorithm is Invalid'), - QCoreApplication.translate('ModelerGraphicItem', "

    The “{}” algorithm is invalid, because:

    • {}
    ").format(alg.description(), '
  • '.join(errors)), - level=Qgis.MessageLevel.Warning + QCoreApplication.translate( + "ModelerGraphicItem", "Algorithm “{}” is invalid" + ).format(alg.description()), + self.tr("Algorithm is Invalid"), + QCoreApplication.translate( + "ModelerGraphicItem", + "

    The “{}” algorithm is invalid, because:

    • {}
    ", + ).format(alg.description(), "
  • ".join(errors)), + level=Qgis.MessageLevel.Warning, ) else: self.scene().messageBar().clearWidgets() @@ -215,8 +231,12 @@ def __init__(self, element, model): def edit(self, edit_comment=False): child_alg = self.model().childAlgorithm(self.component().childId()) - dlg = ModelerParameterDefinitionDialog(self.model(), - param=self.model().modelParameterFromChildIdAndOutputName(self.component().childId(), self.component().name())) + dlg = ModelerParameterDefinitionDialog( + self.model(), + param=self.model().modelParameterFromChildIdAndOutputName( + self.component().childId(), self.component().name() + ), + ) dlg.setComments(self.component().comment().description()) dlg.setCommentColor(self.component().comment().color()) if edit_comment: @@ -225,19 +245,28 @@ def edit(self, edit_comment=False): if dlg.exec(): model_outputs = child_alg.modelOutputs() - model_output = QgsProcessingModelOutput(model_outputs[self.component().name()]) + model_output = QgsProcessingModelOutput( + model_outputs[self.component().name()] + ) del model_outputs[self.component().name()] model_output.setName(dlg.param.description()) model_output.setDescription(dlg.param.description()) model_output.setDefaultValue(dlg.param.defaultValue()) - model_output.setMandatory(not (dlg.param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional)) + model_output.setMandatory( + not ( + dlg.param.flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ) + ) model_output.comment().setDescription(dlg.comments()) model_output.comment().setColor(dlg.commentColor()) model_outputs[model_output.name()] = model_output child_alg.setModelOutputs(model_outputs) - self.aboutToChange.emit(self.tr('Edit {}').format(model_output.description())) + self.aboutToChange.emit( + self.tr("Edit {}").format(model_output.description()) + ) self.model().updateDestinationParameters() self.requestModelRepaint.emit() diff --git a/python/plugins/processing/modeler/ModelerParameterDefinitionDialog.py b/python/plugins/processing/modeler/ModelerParameterDefinitionDialog.py index f80f665bab3a..4960f1088a77 100644 --- a/python/plugins/processing/modeler/ModelerParameterDefinitionDialog.py +++ b/python/plugins/processing/modeler/ModelerParameterDefinitionDialog.py @@ -15,42 +15,43 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import math -from qgis.PyQt.QtCore import (Qt, - QByteArray, - QCoreApplication) -from qgis.PyQt.QtWidgets import (QDialog, - QVBoxLayout, - QLabel, - QLineEdit, - QComboBox, - QCheckBox, - QDialogButtonBox, - QMessageBox, - QTabWidget, - QWidget, - QTextEdit, - QHBoxLayout) +from qgis.PyQt.QtCore import Qt, QByteArray, QCoreApplication +from qgis.PyQt.QtWidgets import ( + QDialog, + QVBoxLayout, + QLabel, + QLineEdit, + QComboBox, + QCheckBox, + QDialogButtonBox, + QMessageBox, + QTabWidget, + QWidget, + QTextEdit, + QHBoxLayout, +) from qgis.PyQt.QtGui import QColor -from qgis.gui import (QgsProcessingLayerOutputDestinationWidget, - QgsColorButton) -from qgis.core import (QgsApplication, - QgsSettings, - QgsProcessing, - QgsProcessingParameterDefinition, - QgsProcessingDestinationParameter, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterFileDestination, - QgsProcessingParameterFolderDestination, - QgsProcessingParameterRasterDestination, - QgsProcessingParameterVectorDestination, - QgsProcessingModelAlgorithm) +from qgis.gui import QgsProcessingLayerOutputDestinationWidget, QgsColorButton +from qgis.core import ( + QgsApplication, + QgsSettings, + QgsProcessing, + QgsProcessingParameterDefinition, + QgsProcessingDestinationParameter, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterFileDestination, + QgsProcessingParameterFolderDestination, + QgsProcessingParameterRasterDestination, + QgsProcessingParameterVectorDestination, + QgsProcessingModelAlgorithm, +) from processing.core import parameters from processing.modeler.exceptions import UndefinedParameterException @@ -74,11 +75,17 @@ def __init__(self, alg, paramType=None, param=None): self.setModal(True) self.setupUi() settings = QgsSettings() - self.restoreGeometry(settings.value("/Processing/modelParametersDefinitionDialogGeometry", QByteArray())) + self.restoreGeometry( + settings.value( + "/Processing/modelParametersDefinitionDialogGeometry", QByteArray() + ) + ) def closeEvent(self, event): settings = QgsSettings() - settings.setValue("/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry()) + settings.setValue( + "/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry() + ) super().closeEvent(event) def switchToCommentTab(self): @@ -87,8 +94,12 @@ def switchToCommentTab(self): self.commentEdit.selectAll() def setupUi(self): - type_metadata = QgsApplication.processingRegistry().parameterType(self.param.type() if self.param else self.paramType) - self.setWindowTitle(self.tr('{} Parameter Definition').format(type_metadata.name())) + type_metadata = QgsApplication.processingRegistry().parameterType( + self.param.type() if self.param else self.paramType + ) + self.setWindowTitle( + self.tr("{} Parameter Definition").format(type_metadata.name()) + ) self.mainLayout = QVBoxLayout() self.tab = QTabWidget() @@ -98,7 +109,7 @@ def setupUi(self): self.verticalLayout = QVBoxLayout() - self.label = QLabel(self.tr('Parameter name')) + self.label = QLabel(self.tr("Parameter name")) self.verticalLayout.addWidget(self.label) self.nameTextBox = QLineEdit() self.verticalLayout.addWidget(self.nameTextBox) @@ -107,31 +118,44 @@ def setupUi(self): self.nameTextBox.setText(self.param.description()) if isinstance(self.param, QgsProcessingDestinationParameter): - self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) - self.defaultWidget = QgsProcessingLayerOutputDestinationWidget(self.param, defaultSelection=True) + self.verticalLayout.addWidget(QLabel(self.tr("Default value"))) + self.defaultWidget = QgsProcessingLayerOutputDestinationWidget( + self.param, defaultSelection=True + ) self.verticalLayout.addWidget(self.defaultWidget) self.verticalLayout.addSpacing(20) self.requiredCheck = QCheckBox() - self.requiredCheck.setText(self.tr('Mandatory')) + self.requiredCheck.setText(self.tr("Mandatory")) self.requiredCheck.setChecked(True) if self.param is not None: - self.requiredCheck.setChecked(not self.param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.requiredCheck.setChecked( + not self.param.flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.verticalLayout.addWidget(self.requiredCheck) self.advancedCheck = QCheckBox() - self.advancedCheck.setText(self.tr('Advanced')) + self.advancedCheck.setText(self.tr("Advanced")) self.advancedCheck.setChecked(False) if self.param is not None: - self.advancedCheck.setChecked(self.param.flags() & QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.advancedCheck.setChecked( + self.param.flags() & QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) self.verticalLayout.addWidget(self.advancedCheck) # If child algorithm output is mandatory, disable checkbox if isinstance(self.param, QgsProcessingDestinationParameter): - child = self.alg.childAlgorithms()[self.param.metadata()['_modelChildId']] - model_output = child.modelOutput(self.param.metadata()['_modelChildOutputName']) - param_def = child.algorithm().parameterDefinition(model_output.childOutputName()) - if not (param_def.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional): + child = self.alg.childAlgorithms()[self.param.metadata()["_modelChildId"]] + model_output = child.modelOutput( + self.param.metadata()["_modelChildOutputName"] + ) + param_def = child.algorithm().parameterDefinition( + model_output.childOutputName() + ) + if not ( + param_def.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ): self.requiredCheck.setEnabled(False) self.requiredCheck.setChecked(True) @@ -142,7 +166,7 @@ def setupUi(self): w = QWidget() w.setLayout(self.verticalLayout) - self.tab.addTab(w, self.tr('Properties')) + self.tab.addTab(w, self.tr("Properties")) self.commentLayout = QVBoxLayout() self.commentEdit = QTextEdit() @@ -151,23 +175,24 @@ def setupUi(self): hl = QHBoxLayout() hl.setContentsMargins(0, 0, 0, 0) - hl.addWidget(QLabel(self.tr('Color'))) + hl.addWidget(QLabel(self.tr("Color"))) self.comment_color_button = QgsColorButton() self.comment_color_button.setAllowOpacity(True) - self.comment_color_button.setWindowTitle(self.tr('Comment Color')) - self.comment_color_button.setShowNull(True, self.tr('Default')) + self.comment_color_button.setWindowTitle(self.tr("Comment Color")) + self.comment_color_button.setShowNull(True, self.tr("Default")) hl.addWidget(self.comment_color_button) self.commentLayout.addLayout(hl) w2 = QWidget() w2.setLayout(self.commentLayout) - self.tab.addTab(w2, self.tr('Comments')) + self.tab.addTab(w2, self.tr("Comments")) self.buttonBox = QDialogButtonBox(self) self.buttonBox.setOrientation(Qt.Orientation.Horizontal) - self.buttonBox.setStandardButtons(QDialogButtonBox.StandardButton.Cancel | - QDialogButtonBox.StandardButton.Ok) - self.buttonBox.setObjectName('buttonBox') + self.buttonBox.setStandardButtons( + QDialogButtonBox.StandardButton.Cancel | QDialogButtonBox.StandardButton.Ok + ) + self.buttonBox.setObjectName("buttonBox") self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) @@ -188,47 +213,59 @@ def setCommentColor(self, color): self.comment_color_button.setToNull() def commentColor(self): - return self.comment_color_button.color() if not self.comment_color_button.isNull() else QColor() + return ( + self.comment_color_button.color() + if not self.comment_color_button.isNull() + else QColor() + ) def accept(self): description = self.nameTextBox.text() - if description.strip() == '': - QMessageBox.warning(self, self.tr('Unable to define parameter'), - self.tr('Invalid parameter name')) + if description.strip() == "": + QMessageBox.warning( + self, + self.tr("Unable to define parameter"), + self.tr("Invalid parameter name"), + ) return safeName = QgsProcessingModelAlgorithm.safeName(description) name = safeName.lower() # Destination parameter - if (isinstance(self.param, QgsProcessingParameterFeatureSink)): + if isinstance(self.param, QgsProcessingParameterFeatureSink): self.param = QgsProcessingParameterFeatureSink( name=name, description=description, type=self.param.dataType(), - defaultValue=self.defaultWidget.value()) - elif (isinstance(self.param, QgsProcessingParameterFileDestination)): + defaultValue=self.defaultWidget.value(), + ) + elif isinstance(self.param, QgsProcessingParameterFileDestination): self.param = QgsProcessingParameterFileDestination( name=name, description=description, fileFilter=self.param.fileFilter(), - defaultValue=self.defaultWidget.value()) - elif (isinstance(self.param, QgsProcessingParameterFolderDestination)): + defaultValue=self.defaultWidget.value(), + ) + elif isinstance(self.param, QgsProcessingParameterFolderDestination): self.param = QgsProcessingParameterFolderDestination( name=name, description=description, - defaultValue=self.defaultWidget.value()) - elif (isinstance(self.param, QgsProcessingParameterRasterDestination)): + defaultValue=self.defaultWidget.value(), + ) + elif isinstance(self.param, QgsProcessingParameterRasterDestination): self.param = QgsProcessingParameterRasterDestination( name=name, description=description, - defaultValue=self.defaultWidget.value()) - elif (isinstance(self.param, QgsProcessingParameterVectorDestination)): + defaultValue=self.defaultWidget.value(), + ) + elif isinstance(self.param, QgsProcessingParameterVectorDestination): self.param = QgsProcessingParameterVectorDestination( name=name, description=description, type=self.param.dataType(), - defaultValue=self.defaultWidget.value()) + defaultValue=self.defaultWidget.value(), + ) else: if self.paramType: @@ -236,26 +273,40 @@ def accept(self): else: typeId = self.param.type() - paramTypeDef = QgsApplication.instance().processingRegistry().parameterType(typeId) + paramTypeDef = ( + QgsApplication.instance().processingRegistry().parameterType(typeId) + ) if not paramTypeDef: - msg = self.tr('The parameter `{}` is not registered, are you missing a required plugin?').format(typeId) + msg = self.tr( + "The parameter `{}` is not registered, are you missing a required plugin?" + ).format(typeId) raise UndefinedParameterException(msg) self.param = paramTypeDef.create(name) self.param.setDescription(description) self.param.setMetadata(paramTypeDef.metadata()) if not self.requiredCheck.isChecked(): - self.param.setFlags(self.param.flags() | QgsProcessingParameterDefinition.Flag.FlagOptional) + self.param.setFlags( + self.param.flags() | QgsProcessingParameterDefinition.Flag.FlagOptional + ) else: - self.param.setFlags(self.param.flags() & ~QgsProcessingParameterDefinition.Flag.FlagOptional) + self.param.setFlags( + self.param.flags() & ~QgsProcessingParameterDefinition.Flag.FlagOptional + ) if self.advancedCheck.isChecked(): - self.param.setFlags(self.param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.param.setFlags( + self.param.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) else: - self.param.setFlags(self.param.flags() & ~QgsProcessingParameterDefinition.Flag.FlagAdvanced) + self.param.setFlags( + self.param.flags() & ~QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) settings = QgsSettings() - settings.setValue("/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry()) + settings.setValue( + "/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry() + ) QDialog.accept(self) @@ -263,6 +314,8 @@ def reject(self): self.param = None settings = QgsSettings() - settings.setValue("/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry()) + settings.setValue( + "/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry() + ) QDialog.reject(self) diff --git a/python/plugins/processing/modeler/ModelerParametersDialog.py b/python/plugins/processing/modeler/ModelerParametersDialog.py index eaedee37748b..fa221995a0ac 100644 --- a/python/plugins/processing/modeler/ModelerParametersDialog.py +++ b/python/plugins/processing/modeler/ModelerParametersDialog.py @@ -15,38 +15,53 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import webbrowser from qgis.PyQt.QtCore import Qt -from qgis.PyQt.QtWidgets import (QDialog, QDialogButtonBox, QLabel, QLineEdit, - QFrame, QPushButton, QSizePolicy, QVBoxLayout, - QHBoxLayout, QWidget, QTabWidget, QTextEdit) +from qgis.PyQt.QtWidgets import ( + QDialog, + QDialogButtonBox, + QLabel, + QLineEdit, + QFrame, + QPushButton, + QSizePolicy, + QVBoxLayout, + QHBoxLayout, + QWidget, + QTabWidget, + QTextEdit, +) from qgis.PyQt.QtGui import QColor -from qgis.core import (Qgis, - QgsProject, - QgsProcessingParameterDefinition, - QgsProcessingModelOutput, - QgsProcessingModelChildAlgorithm, - QgsProcessingModelChildParameterSource, - QgsProcessingOutputDefinition) - -from qgis.gui import (QgsGui, - QgsMessageBar, - QgsScrollArea, - QgsFilterLineEdit, - QgsHelp, - QgsProcessingContextGenerator, - QgsProcessingModelerParameterWidget, - QgsProcessingParameterWidgetContext, - QgsPanelWidget, - QgsPanelWidgetStack, - QgsColorButton, - QgsModelChildDependenciesWidget) +from qgis.core import ( + Qgis, + QgsProject, + QgsProcessingParameterDefinition, + QgsProcessingModelOutput, + QgsProcessingModelChildAlgorithm, + QgsProcessingModelChildParameterSource, + QgsProcessingOutputDefinition, +) + +from qgis.gui import ( + QgsGui, + QgsMessageBar, + QgsScrollArea, + QgsFilterLineEdit, + QgsHelp, + QgsProcessingContextGenerator, + QgsProcessingModelerParameterWidget, + QgsProcessingParameterWidgetContext, + QgsPanelWidget, + QgsPanelWidgetStack, + QgsColorButton, + QgsModelChildDependenciesWidget, +) from qgis.utils import iface from processing.gui.wrappers import WidgetWrapperFactory @@ -59,7 +74,7 @@ class ModelerParametersDialog(QDialog): def __init__(self, alg, model, algName=None, configuration=None): super().__init__() - self.setObjectName('ModelerParametersDialog') + self.setObjectName("ModelerParametersDialog") self.setModal(True) if iface is not None: @@ -72,14 +87,24 @@ def __init__(self, alg, model, algName=None, configuration=None): self.configuration = configuration self.context = createContext() - self.setWindowTitle(' - '.join([self._alg.group(), self._alg.displayName()]) if self._alg.group() else self._alg.displayName()) + self.setWindowTitle( + " - ".join([self._alg.group(), self._alg.displayName()]) + if self._alg.group() + else self._alg.displayName() + ) - self.widget = ModelerParametersWidget(alg, model, algName, configuration, context=self.context, dialog=self) + self.widget = ModelerParametersWidget( + alg, model, algName, configuration, context=self.context, dialog=self + ) QgsGui.enableAutoGeometryRestore(self) self.buttonBox = QDialogButtonBox() self.buttonBox.setOrientation(Qt.Orientation.Horizontal) - self.buttonBox.setStandardButtons(QDialogButtonBox.StandardButton.Cancel | QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Help) + self.buttonBox.setStandardButtons( + QDialogButtonBox.StandardButton.Cancel + | QDialogButtonBox.StandardButton.Ok + | QDialogButtonBox.StandardButton.Help + ) self.buttonBox.accepted.connect(self.okPressed) self.buttonBox.rejected.connect(self.reject) @@ -119,28 +144,47 @@ def getAvailableValuesOfType(self, paramType, outTypes=[], dataTypes=[]): elif not isinstance(outTypes, (tuple, list)): outTypes = [outTypes] - return self.model.availableSourcesForChild(self.childId, [p.typeName() for p in paramType if - issubclass(p, QgsProcessingParameterDefinition)], - [o.typeName() for o in outTypes if - issubclass(o, QgsProcessingOutputDefinition)], dataTypes) + return self.model.availableSourcesForChild( + self.childId, + [ + p.typeName() + for p in paramType + if issubclass(p, QgsProcessingParameterDefinition) + ], + [ + o.typeName() + for o in outTypes + if issubclass(o, QgsProcessingOutputDefinition) + ], + dataTypes, + ) def resolveValueDescription(self, value): if isinstance(value, QgsProcessingModelChildParameterSource): if value.source() == Qgis.ProcessingModelChildParameterSource.StaticValue: return value.staticValue() - elif value.source() == Qgis.ProcessingModelChildParameterSource.ModelParameter: - return self.model.parameterDefinition(value.parameterName()).description() + elif ( + value.source() + == Qgis.ProcessingModelChildParameterSource.ModelParameter + ): + return self.model.parameterDefinition( + value.parameterName() + ).description() elif value.source() == Qgis.ProcessingModelChildParameterSource.ChildOutput: alg = self.model.childAlgorithm(value.outputChildId()) - output_name = alg.algorithm().outputDefinition(value.outputName()).description() + output_name = ( + alg.algorithm().outputDefinition(value.outputName()).description() + ) # see if this output has been named by the model designer -- if so, we use that friendly name for name, output in alg.modelOutputs().items(): if output.childOutputName() == value.outputName(): output_name = name break - return self.tr("'{0}' from algorithm '{1}'").format(output_name, alg.description()) + return self.tr("'{0}' from algorithm '{1}'").format( + output_name, alg.description() + ) return value @@ -157,9 +201,13 @@ def okPressed(self): def openHelp(self): algHelp = self.widget.algorithm().helpUrl() if not algHelp: - algHelp = QgsHelp.helpUrl("processing_algs/{}/{}.html#{}".format( - self.widget.algorithm().provider().helpId(), self.algorithm().groupId(), - f"{self.algorithm().provider().helpId()}{self.algorithm().name()}")).toString() + algHelp = QgsHelp.helpUrl( + "processing_algs/{}/{}.html#{}".format( + self.widget.algorithm().provider().helpId(), + self.algorithm().groupId(), + f"{self.algorithm().provider().helpId()}{self.algorithm().name()}", + ) + ).toString() if algHelp not in [None, ""]: webbrowser.open(algHelp) @@ -167,7 +215,9 @@ def openHelp(self): class ModelerParametersPanelWidget(QgsPanelWidget): - def __init__(self, alg, model, algName=None, configuration=None, dialog=None, context=None): + def __init__( + self, alg, model, algName=None, configuration=None, dialog=None, context=None + ): super().__init__() self._alg = alg # The algorithm to define in this dialog. It is an instance of QgsProcessingAlgorithm self.model = model # The model this algorithm is going to be added to. It is an instance of QgsProcessingModelAlgorithm @@ -231,10 +281,16 @@ def setupUi(self): widget_context.setModel(self.model) widget_context.setModelChildAlgorithmId(self.childId) - self.algorithmItem = QgsGui.instance().processingGuiRegistry().algorithmConfigurationWidget(self._alg) + self.algorithmItem = ( + QgsGui.instance() + .processingGuiRegistry() + .algorithmConfigurationWidget(self._alg) + ) if self.algorithmItem: self.algorithmItem.setWidgetContext(widget_context) - self.algorithmItem.registerProcessingContextGenerator(self.context_generator) + self.algorithmItem.registerProcessingContextGenerator( + self.context_generator + ) if self.configuration: self.algorithmItem.setConfiguration(self.configuration) self.verticalLayout.addWidget(self.algorithmItem) @@ -242,16 +298,18 @@ def setupUi(self): for param in self._alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.Flag.FlagAdvanced: self.advancedButton = QPushButton() - self.advancedButton.setText(self.tr('Show advanced parameters')) - self.advancedButton.clicked.connect( - self.showAdvancedParametersClicked) + self.advancedButton.setText(self.tr("Show advanced parameters")) + self.advancedButton.clicked.connect(self.showAdvancedParametersClicked) advancedButtonHLayout = QHBoxLayout() advancedButtonHLayout.addWidget(self.advancedButton) advancedButtonHLayout.addStretch() self.verticalLayout.addLayout(advancedButtonHLayout) break for param in self._alg.parameterDefinitions(): - if param.isDestination() or param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden: + if ( + param.isDestination() + or param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden + ): continue wrapper = WidgetWrapperFactory.create_wrapper(param, self.dialog) @@ -283,10 +341,9 @@ def setupUi(self): if output.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden: continue - widget = QgsGui.processingGuiRegistry().createModelerParameterWidget(self.model, - self.childId, - output, - self.context) + widget = QgsGui.processingGuiRegistry().createModelerParameterWidget( + self.model, self.childId, output, self.context + ) widget.setDialog(self.dialog) widget.setWidgetContext(widget_context) widget.registerProcessingContextGenerator(self.context_generator) @@ -294,8 +351,10 @@ def setupUi(self): self.wrappers[output.name()] = widget item = QgsFilterLineEdit() - if hasattr(item, 'setPlaceholderText'): - item.setPlaceholderText(self.tr('[Enter name if this is a final result]')) + if hasattr(item, "setPlaceholderText"): + item.setPlaceholderText( + self.tr("[Enter name if this is a final result]") + ) label = widget.createLabel() if label is not None: @@ -303,10 +362,12 @@ def setupUi(self): self.verticalLayout.addWidget(widget) - label = QLabel(' ') + label = QLabel(" ") self.verticalLayout.addWidget(label) - label = QLabel(self.tr('Dependencies')) - self.dependencies_panel = QgsModelChildDependenciesWidget(self, self.model, self.childId) + label = QLabel(self.tr("Dependencies")) + self.dependencies_panel = QgsModelChildDependenciesWidget( + self, self.model, self.childId + ) self.verticalLayout.addWidget(label) self.verticalLayout.addWidget(self.dependencies_panel) self.verticalLayout.addStretch(1000) @@ -333,9 +394,9 @@ def setupUi(self): def showAdvancedParametersClicked(self): self.showAdvanced = not self.showAdvanced if self.showAdvanced: - self.advancedButton.setText(self.tr('Hide advanced parameters')) + self.advancedButton.setText(self.tr("Hide advanced parameters")) else: - self.advancedButton.setText(self.tr('Show advanced parameters')) + self.advancedButton.setText(self.tr("Show advanced parameters")) for param in self._alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.Flag.FlagAdvanced: wrapper = self.wrappers[param.name()] @@ -352,7 +413,10 @@ def setPreviousValues(self): self.descriptionBox.setText(alg.description()) for param in alg.algorithm().parameterDefinitions(): - if param.isDestination() or param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden: + if ( + param.isDestination() + or param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden + ): continue value = None if param.name() in alg.parameterSources(): @@ -365,15 +429,20 @@ def setPreviousValues(self): wrapper = self.wrappers[param.name()] if issubclass(wrapper.__class__, QgsProcessingModelerParameterWidget): if value is None: - value = QgsProcessingModelChildParameterSource.fromStaticValue(param.defaultValue()) + value = QgsProcessingModelChildParameterSource.fromStaticValue( + param.defaultValue() + ) wrapper.setWidgetValue(value) else: if value is None: value = param.defaultValue() - if isinstance(value, - QgsProcessingModelChildParameterSource) and value.source() == Qgis.ProcessingModelChildParameterSource.StaticValue: + if ( + isinstance(value, QgsProcessingModelChildParameterSource) + and value.source() + == Qgis.ProcessingModelChildParameterSource.StaticValue + ): value = value.staticValue() wrapper.setValue(value) @@ -383,14 +452,20 @@ def setPreviousValues(self): model_output_name = None for name, out in alg.modelOutputs().items(): - if out.childId() == self.childId and out.childOutputName() == output.name(): + if ( + out.childId() == self.childId + and out.childOutputName() == output.name() + ): # this destination parameter is linked to a model output model_output_name = out.name() self.previous_output_definitions[output.name()] = out break value = None - if model_output_name is None and output.name() in alg.parameterSources(): + if ( + model_output_name is None + and output.name() in alg.parameterSources() + ): value = alg.parameterSources()[output.name()] if isinstance(value, list) and len(value) == 1: value = value[0] @@ -403,7 +478,9 @@ def setPreviousValues(self): wrapper.setToModelOutput(model_output_name) elif value is not None or output.defaultValue() is not None: if value is None: - value = QgsProcessingModelChildParameterSource.fromStaticValue(output.defaultValue()) + value = QgsProcessingModelChildParameterSource.fromStaticValue( + output.defaultValue() + ) wrapper.setWidgetValue(value) @@ -420,7 +497,10 @@ def createAlgorithm(self): alg.setConfiguration(self.algorithmItem.configuration()) self._alg = alg.algorithm().create(self.algorithmItem.configuration()) for param in self._alg.parameterDefinitions(): - if param.isDestination() or param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden: + if ( + param.isDestination() + or param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden + ): continue try: wrapper = self.wrappers[param.name()] @@ -435,16 +515,29 @@ def createAlgorithm(self): if isinstance(val, QgsProcessingModelChildParameterSource): val = [val] - elif not (isinstance(val, list) and all( - [isinstance(subval, QgsProcessingModelChildParameterSource) for subval in val])): + elif not ( + isinstance(val, list) + and all( + [ + isinstance(subval, QgsProcessingModelChildParameterSource) + for subval in val + ] + ) + ): val = [QgsProcessingModelChildParameterSource.fromStaticValue(val)] valid = True for subval in val: - if (isinstance(subval, QgsProcessingModelChildParameterSource) - and subval.source() == Qgis.ProcessingModelChildParameterSource.StaticValue - and not param.checkValueIsAcceptable(subval.staticValue())) \ - or (subval is None and not param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional): + if ( + isinstance(subval, QgsProcessingModelChildParameterSource) + and subval.source() + == Qgis.ProcessingModelChildParameterSource.StaticValue + and not param.checkValueIsAcceptable(subval.staticValue()) + ) or ( + subval is None + and not param.flags() + & QgsProcessingParameterDefinition.Flag.FlagOptional + ): valid = False break @@ -461,7 +554,9 @@ def createAlgorithm(self): if name: # if there was a previous output definition already for this output, we start with it, # otherwise we'll lose any existing output comments, coloring, position, etc - model_output = self.previous_output_definitions.get(output.name(), QgsProcessingModelOutput(name, name)) + model_output = self.previous_output_definitions.get( + output.name(), QgsProcessingModelOutput(name, name) + ) model_output.setDescription(name) model_output.setChildId(alg.childId()) model_output.setChildOutputName(output.name()) @@ -476,7 +571,9 @@ def createAlgorithm(self): if output.flags() & QgsProcessingParameterDefinition.Flag.FlagIsModelOutput: if output.name() not in outputs: - model_output = QgsProcessingModelOutput(output.name(), output.name()) + model_output = QgsProcessingModelOutput( + output.name(), output.name() + ) model_output.setChildId(alg.childId()) model_output.setChildOutputName(output.name()) outputs[output.name()] = model_output @@ -489,7 +586,9 @@ def createAlgorithm(self): class ModelerParametersWidget(QWidget): - def __init__(self, alg, model, algName=None, configuration=None, dialog=None, context=None): + def __init__( + self, alg, model, algName=None, configuration=None, dialog=None, context=None + ): super().__init__() self._alg = alg # The algorithm to define in this dialog. It is an instance of QgsProcessingAlgorithm self.model = model # The model this algorithm is going to be added to. It is an instance of QgsProcessingModelAlgorithm @@ -498,7 +597,9 @@ def __init__(self, alg, model, algName=None, configuration=None, dialog=None, co self.context = context self.dialog = dialog - self.widget = ModelerParametersPanelWidget(alg, model, algName, configuration, dialog, context) + self.widget = ModelerParametersPanelWidget( + alg, model, algName, configuration, dialog, context + ) class ContextGenerator(QgsProcessingContextGenerator): @@ -532,7 +633,7 @@ def setupUi(self): self.widget.setDockMode(True) self.param_widget.setMainPanel(self.widget) - self.tab.addTab(self.param_widget, self.tr('Properties')) + self.tab.addTab(self.param_widget, self.tr("Properties")) self.commentLayout = QVBoxLayout() self.commentEdit = QTextEdit() @@ -541,17 +642,17 @@ def setupUi(self): hl = QHBoxLayout() hl.setContentsMargins(0, 0, 0, 0) - hl.addWidget(QLabel(self.tr('Color'))) + hl.addWidget(QLabel(self.tr("Color"))) self.comment_color_button = QgsColorButton() self.comment_color_button.setAllowOpacity(True) - self.comment_color_button.setWindowTitle(self.tr('Comment Color')) - self.comment_color_button.setShowNull(True, self.tr('Default')) + self.comment_color_button.setWindowTitle(self.tr("Comment Color")) + self.comment_color_button.setShowNull(True, self.tr("Default")) hl.addWidget(self.comment_color_button) self.commentLayout.addLayout(hl) w2 = QWidget() w2.setLayout(self.commentLayout) - self.tab.addTab(w2, self.tr('Comments')) + self.tab.addTab(w2, self.tr("Comments")) self.setLayout(self.mainLayout) @@ -568,7 +669,11 @@ def setCommentColor(self, color): self.comment_color_button.setToNull() def commentColor(self): - return self.comment_color_button.color() if not self.comment_color_button.isNull() else QColor() + return ( + self.comment_color_button.color() + if not self.comment_color_button.isNull() + else QColor() + ) def setPreviousValues(self): self.widget.setPreviousValues() diff --git a/python/plugins/processing/modeler/ModelerScene.py b/python/plugins/processing/modeler/ModelerScene.py index b093df0284e0..2ac2b329beec 100644 --- a/python/plugins/processing/modeler/ModelerScene.py +++ b/python/plugins/processing/modeler/ModelerScene.py @@ -15,15 +15,15 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" from qgis.gui import QgsModelGraphicsScene from processing.modeler.ModelerGraphicItem import ( ModelerInputGraphicItem, ModelerOutputGraphicItem, - ModelerChildAlgorithmGraphicItem + ModelerChildAlgorithmGraphicItem, ) diff --git a/python/plugins/processing/modeler/ModelerUtils.py b/python/plugins/processing/modeler/ModelerUtils.py index d8593ed9b136..1fc539da0778 100644 --- a/python/plugins/processing/modeler/ModelerUtils.py +++ b/python/plugins/processing/modeler/ModelerUtils.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os from processing.tools.system import userFolder, mkdir @@ -25,11 +25,11 @@ class ModelerUtils: - MODELS_FOLDER = 'MODELS_FOLDER' + MODELS_FOLDER = "MODELS_FOLDER" @staticmethod def defaultModelsFolder(): - folder = str(os.path.join(userFolder(), 'models')) + folder = str(os.path.join(userFolder(), "models")) mkdir(folder) return os.path.abspath(folder) @@ -37,6 +37,6 @@ def defaultModelsFolder(): def modelsFolders(): folder = ProcessingConfig.getSetting(ModelerUtils.MODELS_FOLDER) if folder is not None: - return folder.split(';') + return folder.split(";") else: return [ModelerUtils.defaultModelsFolder()] diff --git a/python/plugins/processing/modeler/MultilineTextPanel.py b/python/plugins/processing/modeler/MultilineTextPanel.py index eb5ff36fb115..01745c4ed782 100644 --- a/python/plugins/processing/modeler/MultilineTextPanel.py +++ b/python/plugins/processing/modeler/MultilineTextPanel.py @@ -15,11 +15,17 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'January 2013' -__copyright__ = '(C) 2013, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "January 2013" +__copyright__ = "(C) 2013, Victor Olaya" -from qgis.PyQt.QtWidgets import QComboBox, QPlainTextEdit, QSizePolicy, QVBoxLayout, QWidget +from qgis.PyQt.QtWidgets import ( + QComboBox, + QPlainTextEdit, + QSizePolicy, + QVBoxLayout, + QWidget, +) class MultilineTextPanel(QWidget): @@ -32,11 +38,12 @@ def __init__(self, options, parent=None): self.verticalLayout.setSpacing(2) self.verticalLayout.setMargin(0) self.combo = QComboBox() - self.combo.addItem(self.tr('[Use text below]')) + self.combo.addItem(self.tr("[Use text below]")) for option in options: self.combo.addItem(option[0], option[1]) - self.combo.setSizePolicy(QSizePolicy.Policy.Expanding, - QSizePolicy.Policy.Expanding) + self.combo.setSizePolicy( + QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding + ) self.verticalLayout.addWidget(self.combo) self.textBox = QPlainTextEdit() self.verticalLayout.addWidget(self.textBox) diff --git a/python/plugins/processing/modeler/OpenModelFromFileAction.py b/python/plugins/processing/modeler/OpenModelFromFileAction.py index 63ad25a6e79c..540713d13ae8 100644 --- a/python/plugins/processing/modeler/OpenModelFromFileAction.py +++ b/python/plugins/processing/modeler/OpenModelFromFileAction.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'February 2018' -__copyright__ = '(C) 2018, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "February 2018" +__copyright__ = "(C) 2018, Nyall Dawson" import os from qgis.PyQt.QtWidgets import QFileDialog @@ -34,21 +34,28 @@ class OpenModelFromFileAction(ToolboxAction): def __init__(self): - self.name = QCoreApplication.translate('OpenModelFromFileAction', 'Open Existing Model…') - self.group = self.tr('Tools') + self.name = QCoreApplication.translate( + "OpenModelFromFileAction", "Open Existing Model…" + ) + self.group = self.tr("Tools") def getIcon(self): return QgsApplication.getThemeIcon("/processingModel.svg") def execute(self): settings = QgsSettings() - lastDir = settings.value('Processing/lastModelsDir', QDir.homePath()) - filename, selected_filter = QFileDialog.getOpenFileName(self.toolbox, - self.tr('Open Model', 'AddModelFromFileAction'), lastDir, - self.tr('Processing models (*.model3 *.MODEL3)', 'AddModelFromFileAction')) + lastDir = settings.value("Processing/lastModelsDir", QDir.homePath()) + filename, selected_filter = QFileDialog.getOpenFileName( + self.toolbox, + self.tr("Open Model", "AddModelFromFileAction"), + lastDir, + self.tr("Processing models (*.model3 *.MODEL3)", "AddModelFromFileAction"), + ) if filename: - settings.setValue('Processing/lastModelsDir', - QFileInfo(filename).absoluteDir().absolutePath()) + settings.setValue( + "Processing/lastModelsDir", + QFileInfo(filename).absoluteDir().absolutePath(), + ) dlg = ModelerDialog.create() dlg.loadModel(filename) diff --git a/python/plugins/processing/modeler/ProjectProvider.py b/python/plugins/processing/modeler/ProjectProvider.py index 88708f4c6b75..e362000a1eb9 100644 --- a/python/plugins/processing/modeler/ProjectProvider.py +++ b/python/plugins/processing/modeler/ProjectProvider.py @@ -15,20 +15,22 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'July 2018' -__copyright__ = '(C) 2018, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "July 2018" +__copyright__ = "(C) 2018, Nyall Dawson" -from qgis.core import (Qgis, - QgsApplication, - QgsProcessingProvider, - QgsMessageLog, - QgsProcessingModelAlgorithm, - QgsProject, - QgsXmlUtils, - QgsRuntimeProfiler) +from qgis.core import ( + Qgis, + QgsApplication, + QgsProcessingProvider, + QgsMessageLog, + QgsProcessingModelAlgorithm, + QgsProject, + QgsXmlUtils, + QgsRuntimeProfiler, +) -PROJECT_PROVIDER_ID = 'project' +PROJECT_PROVIDER_ID = "project" class ProjectProvider(QgsProcessingProvider): @@ -45,7 +47,9 @@ def __init__(self, project=None): # must reload models if providers list is changed - previously unavailable algorithms # which models depend on may now be available - QgsApplication.processingRegistry().providerAdded.connect(self.on_provider_added) + QgsApplication.processingRegistry().providerAdded.connect( + self.on_provider_added + ) self.project.readProject.connect(self.read_project) self.project.writeProject.connect(self.write_project) @@ -58,7 +62,7 @@ def on_provider_added(self, provider_id): self.refreshAlgorithms() def load(self): - with QgsRuntimeProfiler.profile('Project Provider'): + with QgsRuntimeProfiler.profile("Project Provider"): self.refreshAlgorithms() return True @@ -100,7 +104,7 @@ def read_project(self, doc): :param doc: DOM document """ self.model_definitions = {} - project_models_nodes = doc.elementsByTagName('projectModels') + project_models_nodes = doc.elementsByTagName("projectModels") if project_models_nodes: project_models_node = project_models_nodes.at(0) model_nodes = project_models_node.childNodes() @@ -118,12 +122,12 @@ def write_project(self, doc): Writes out the project model definitions into the project DOM document :param doc: DOM document """ - qgis_nodes = doc.elementsByTagName('qgis') + qgis_nodes = doc.elementsByTagName("qgis") if not qgis_nodes: return qgis_node = qgis_nodes.at(0) - project_models_node = doc.createElement('projectModels') + project_models_node = doc.createElement("projectModels") for a in self.algorithms(): definition = a.toVariant() @@ -132,10 +136,10 @@ def write_project(self, doc): qgis_node.appendChild(project_models_node) def name(self): - return self.tr('Project models', 'ProjectProvider') + return self.tr("Project models", "ProjectProvider") def longName(self): - return self.tr('Models embedded in the current project', 'ProjectProvider') + return self.tr("Models embedded in the current project", "ProjectProvider") def id(self): return PROJECT_PROVIDER_ID @@ -160,7 +164,9 @@ def loadAlgorithms(self): self.addAlgorithm(algorithm) else: QgsMessageLog.logMessage( - self.tr('Could not load model from project', 'ProjectProvider'), - self.tr('Processing'), Qgis.MessageLevel.Critical) + self.tr("Could not load model from project", "ProjectProvider"), + self.tr("Processing"), + Qgis.MessageLevel.Critical, + ) self.is_loading = False diff --git a/python/plugins/processing/script/AddScriptFromFileAction.py b/python/plugins/processing/script/AddScriptFromFileAction.py index 74858f5287f1..b4eb2f4e91e3 100644 --- a/python/plugins/processing/script/AddScriptFromFileAction.py +++ b/python/plugins/processing/script/AddScriptFromFileAction.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'April 2014' -__copyright__ = '(C) 201, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "April 2014" +__copyright__ = "(C) 201, Victor Olaya" import os import shutil @@ -35,16 +35,20 @@ class AddScriptFromFileAction(ToolboxAction): def __init__(self): - self.name = QCoreApplication.translate("AddScriptFromFileAction", "Add Script to Toolbox…") + self.name = QCoreApplication.translate( + "AddScriptFromFileAction", "Add Script to Toolbox…" + ) self.group = self.tr("Tools") def execute(self): settings = QgsSettings() lastDir = settings.value("processing/lastScriptsDir", "") - files, _ = QFileDialog.getOpenFileNames(self.toolbox, - self.tr("Add script(s)"), - lastDir, - self.tr("Processing scripts (*.py *.PY)")) + files, _ = QFileDialog.getOpenFileNames( + self.toolbox, + self.tr("Add script(s)"), + lastDir, + self.tr("Processing scripts (*.py *.PY)"), + ) if files: settings.setValue("processing/lastScriptsDir", os.path.dirname(files[0])) @@ -54,9 +58,13 @@ def execute(self): shutil.copy(f, ScriptUtils.scriptsFolders()[0]) valid += 1 except OSError as e: - QgsMessageLog.logMessage(self.tr("Could not copy script '{}'\n{}").format(f, str(e)), - "Processing", - Qgis.MessageLevel.Warning) + QgsMessageLog.logMessage( + self.tr("Could not copy script '{}'\n{}").format(f, str(e)), + "Processing", + Qgis.MessageLevel.Warning, + ) if valid > 0: - QgsApplication.processingRegistry().providerById("script").refreshAlgorithms() + QgsApplication.processingRegistry().providerById( + "script" + ).refreshAlgorithms() diff --git a/python/plugins/processing/script/AddScriptFromTemplateAction.py b/python/plugins/processing/script/AddScriptFromTemplateAction.py index 29daa568dfb3..f0e59de59b9c 100644 --- a/python/plugins/processing/script/AddScriptFromTemplateAction.py +++ b/python/plugins/processing/script/AddScriptFromTemplateAction.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Matteo Ghetta' -__date__ = 'March 2018' -__copyright__ = '(C) 2018, Matteo Ghetta' +__author__ = "Matteo Ghetta" +__date__ = "March 2018" +__copyright__ = "(C) 2018, Matteo Ghetta" import os import codecs @@ -34,17 +34,18 @@ class AddScriptFromTemplateAction(ToolboxAction): def __init__(self): - self.name = QCoreApplication.translate("AddScriptFromTemplate", "Create New Script from Template…") + self.name = QCoreApplication.translate( + "AddScriptFromTemplate", "Create New Script from Template…" + ) self.group = self.tr("Tools") def execute(self): dlg = ScriptEditorDialog(parent=iface.mainWindow()) pluginPath = os.path.split(os.path.dirname(__file__))[0] - templatePath = os.path.join( - pluginPath, 'script', 'ScriptTemplate.py') + templatePath = os.path.join(pluginPath, "script", "ScriptTemplate.py") - with codecs.open(templatePath, 'r', encoding='utf-8') as f: + with codecs.open(templatePath, "r", encoding="utf-8") as f: templateTxt = f.read() dlg.editor.setText(templateTxt) diff --git a/python/plugins/processing/script/CreateNewScriptAction.py b/python/plugins/processing/script/CreateNewScriptAction.py index 76f3f8c15da0..42a4ad3230c5 100644 --- a/python/plugins/processing/script/CreateNewScriptAction.py +++ b/python/plugins/processing/script/CreateNewScriptAction.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os @@ -33,7 +33,9 @@ class CreateNewScriptAction(ToolboxAction): def __init__(self): - self.name = QCoreApplication.translate("CreateNewScriptAction", "Create New Script…") + self.name = QCoreApplication.translate( + "CreateNewScriptAction", "Create New Script…" + ) self.group = self.tr("Tools") def execute(self): diff --git a/python/plugins/processing/script/DeleteScriptAction.py b/python/plugins/processing/script/DeleteScriptAction.py index 7a3d901c398a..46535dfa0ebd 100644 --- a/python/plugins/processing/script/DeleteScriptAction.py +++ b/python/plugins/processing/script/DeleteScriptAction.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os @@ -38,21 +38,29 @@ def __init__(self): self.name = QCoreApplication.translate("DeleteScriptAction", "Delete Script…") def isEnabled(self): - return isinstance(self.itemData, QgsProcessingAlgorithm) and self.itemData.provider().id() == "script" + return ( + isinstance(self.itemData, QgsProcessingAlgorithm) + and self.itemData.provider().id() == "script" + ) def execute(self): - reply = QMessageBox.question(None, - self.tr("Delete Script"), - self.tr("Are you sure you want to delete this script?"), - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, - QMessageBox.StandardButton.No) + reply = QMessageBox.question( + None, + self.tr("Delete Script"), + self.tr("Are you sure you want to delete this script?"), + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + QMessageBox.StandardButton.No, + ) if reply == QMessageBox.StandardButton.Yes: filePath = ScriptUtils.findAlgorithmSource(self.itemData.name()) if filePath is not None: os.remove(filePath) - QgsApplication.processingRegistry().providerById("script").refreshAlgorithms() + QgsApplication.processingRegistry().providerById( + "script" + ).refreshAlgorithms() else: - QMessageBox.warning(None, - self.tr("Delete Script"), - self.tr("Can not find corresponding script file.") - ) + QMessageBox.warning( + None, + self.tr("Delete Script"), + self.tr("Can not find corresponding script file."), + ) diff --git a/python/plugins/processing/script/EditScriptAction.py b/python/plugins/processing/script/EditScriptAction.py index 77094e206a7b..3b6e6e8193a4 100644 --- a/python/plugins/processing/script/EditScriptAction.py +++ b/python/plugins/processing/script/EditScriptAction.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import inspect @@ -39,7 +39,10 @@ def __init__(self): self.name = QCoreApplication.translate("EditScriptAction", "Edit Script…") def isEnabled(self): - return isinstance(self.itemData, QgsProcessingAlgorithm) and self.itemData.provider().id() == "script" + return ( + isinstance(self.itemData, QgsProcessingAlgorithm) + and self.itemData.provider().id() == "script" + ) def execute(self): filePath = ScriptUtils.findAlgorithmSource(self.itemData.name()) @@ -47,7 +50,8 @@ def execute(self): dlg = ScriptEditorDialog(filePath, parent=iface.mainWindow()) dlg.show() else: - QMessageBox.warning(None, - self.tr("Edit Script"), - self.tr("Can not find corresponding script file.") - ) + QMessageBox.warning( + None, + self.tr("Edit Script"), + self.tr("Can not find corresponding script file."), + ) diff --git a/python/plugins/processing/script/OpenScriptFromFileAction.py b/python/plugins/processing/script/OpenScriptFromFileAction.py index 2b1f3d0d8446..1cb3a7d9a103 100644 --- a/python/plugins/processing/script/OpenScriptFromFileAction.py +++ b/python/plugins/processing/script/OpenScriptFromFileAction.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'February 2018' -__copyright__ = '(C) 2018, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "February 2018" +__copyright__ = "(C) 2018, Nyall Dawson" import os from qgis.PyQt.QtWidgets import QFileDialog @@ -35,21 +35,28 @@ class OpenScriptFromFileAction(ToolboxAction): def __init__(self): - self.name = QCoreApplication.translate('OpenScriptFromFileAction', 'Open Existing Script…') - self.group = self.tr('Tools') + self.name = QCoreApplication.translate( + "OpenScriptFromFileAction", "Open Existing Script…" + ) + self.group = self.tr("Tools") def getIcon(self): return QgsApplication.getThemeIcon("/processingScript.svg") def execute(self): settings = QgsSettings() - lastDir = settings.value('Processing/lastScriptsDir', '') - filename, selected_filter = QFileDialog.getOpenFileName(self.toolbox, - self.tr('Open Script', 'AddScriptFromFileAction'), lastDir, - self.tr('Processing scripts (*.py *.PY)', 'AddScriptFromFileAction')) + lastDir = settings.value("Processing/lastScriptsDir", "") + filename, selected_filter = QFileDialog.getOpenFileName( + self.toolbox, + self.tr("Open Script", "AddScriptFromFileAction"), + lastDir, + self.tr("Processing scripts (*.py *.PY)", "AddScriptFromFileAction"), + ) if filename: - settings.setValue('Processing/lastScriptsDir', - QFileInfo(filename).absoluteDir().absolutePath()) + settings.setValue( + "Processing/lastScriptsDir", + QFileInfo(filename).absoluteDir().absolutePath(), + ) dlg = ScriptEditorDialog(filePath=filename, parent=iface.mainWindow()) dlg.show() diff --git a/python/plugins/processing/script/ScriptAlgorithmProvider.py b/python/plugins/processing/script/ScriptAlgorithmProvider.py index 0868d7184df3..b87f0fa7220e 100644 --- a/python/plugins/processing/script/ScriptAlgorithmProvider.py +++ b/python/plugins/processing/script/ScriptAlgorithmProvider.py @@ -15,22 +15,23 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os -from qgis.core import (Qgis, - QgsMessageLog, - QgsApplication, - QgsProcessingProvider, - QgsRuntimeProfiler) +from qgis.core import ( + Qgis, + QgsMessageLog, + QgsApplication, + QgsProcessingProvider, + QgsRuntimeProfiler, +) from processing.core.ProcessingConfig import ProcessingConfig, Setting -from processing.gui.ProviderActions import (ProviderActions, - ProviderContextMenuActions) +from processing.gui.ProviderActions import ProviderActions, ProviderContextMenuActions from processing.script.AddScriptFromFileAction import AddScriptFromFileAction from processing.script.CreateNewScriptAction import CreateNewScriptAction @@ -48,25 +49,31 @@ def __init__(self): super().__init__() self.algs = [] self.additional_algorithm_classes = [] - self.actions = [CreateNewScriptAction(), - AddScriptFromTemplateAction(), - OpenScriptFromFileAction(), - AddScriptFromFileAction() - ] - self.contextMenuActions = [EditScriptAction(), - DeleteScriptAction()] + self.actions = [ + CreateNewScriptAction(), + AddScriptFromTemplateAction(), + OpenScriptFromFileAction(), + AddScriptFromFileAction(), + ] + self.contextMenuActions = [EditScriptAction(), DeleteScriptAction()] def load(self): - with QgsRuntimeProfiler.profile('Script Provider'): + with QgsRuntimeProfiler.profile("Script Provider"): ProcessingConfig.settingIcons[self.name()] = self.icon() - ProcessingConfig.addSetting(Setting(self.name(), - ScriptUtils.SCRIPTS_FOLDERS, - self.tr("Scripts folder(s)"), - ScriptUtils.defaultScriptsFolder(), - valuetype=Setting.MULTIPLE_FOLDERS)) + ProcessingConfig.addSetting( + Setting( + self.name(), + ScriptUtils.SCRIPTS_FOLDERS, + self.tr("Scripts folder(s)"), + ScriptUtils.defaultScriptsFolder(), + valuetype=Setting.MULTIPLE_FOLDERS, + ) + ) ProviderActions.registerProviderActions(self, self.actions) - ProviderContextMenuActions.registerProviderContextMenuActions(self.contextMenuActions) + ProviderContextMenuActions.registerProviderContextMenuActions( + self.contextMenuActions + ) ProcessingConfig.readSettings() self.refreshAlgorithms() @@ -77,7 +84,9 @@ def unload(self): ProcessingConfig.removeSetting(ScriptUtils.SCRIPTS_FOLDERS) ProviderActions.deregisterProviderActions(self) - ProviderContextMenuActions.deregisterProviderContextMenuActions(self.contextMenuActions) + ProviderContextMenuActions.deregisterProviderContextMenuActions( + self.contextMenuActions + ) def icon(self): return QgsApplication.getThemeIcon("/processingScript.svg") diff --git a/python/plugins/processing/script/ScriptEdit.py b/python/plugins/processing/script/ScriptEdit.py index dc339a335ea3..09f9e44fa0c0 100644 --- a/python/plugins/processing/script/ScriptEdit.py +++ b/python/plugins/processing/script/ScriptEdit.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'April 2013' -__copyright__ = '(C) 2013, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "April 2013" +__copyright__ = "(C) 2013, Alexander Bruy" from qgis.PyQt.QtCore import Qt @@ -39,17 +39,17 @@ def initShortcuts(self): (ctrl, shift) = (self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16) # Disable some shortcuts - self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl) - self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl) - self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl - + shift) - self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl) + self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("D") + ctrl) + self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("L") + ctrl) + self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("L") + ctrl + shift) + self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("T") + ctrl) # self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Z") + ctrl) # self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Y") + ctrl) # Use Ctrl+Space for autocompletion - self.shortcutAutocomplete = QShortcut(QKeySequence(Qt.Modifier.CTRL - + Qt.Key.Key_Space), self) + self.shortcutAutocomplete = QShortcut( + QKeySequence(Qt.Modifier.CTRL + Qt.Key.Key_Space), self + ) self.shortcutAutocomplete.setContext(Qt.ShortcutContext.WidgetShortcut) self.shortcutAutocomplete.activated.connect(self.autoComplete) diff --git a/python/plugins/processing/script/ScriptEditorDialog.py b/python/plugins/processing/script/ScriptEditorDialog.py index e9cc13896378..373eb2c964cc 100644 --- a/python/plugins/processing/script/ScriptEditorDialog.py +++ b/python/plugins/processing/script/ScriptEditorDialog.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Alexander Bruy' -__date__ = 'December 2012' -__copyright__ = '(C) 2012, Alexander Bruy' +__author__ = "Alexander Bruy" +__date__ = "December 2012" +__copyright__ = "(C) 2012, Alexander Bruy" import os import codecs @@ -27,24 +27,16 @@ from qgis.PyQt import uic, sip from qgis.PyQt.QtCore import Qt -from qgis.PyQt.QtWidgets import ( - QMessageBox, - QFileDialog, - QVBoxLayout -) +from qgis.PyQt.QtWidgets import QMessageBox, QFileDialog, QVBoxLayout -from qgis.gui import ( - QgsGui, - QgsErrorDialog, - QgsCodeEditorWidget -) +from qgis.gui import QgsGui, QgsErrorDialog, QgsCodeEditorWidget from qgis.core import ( QgsApplication, QgsFileUtils, QgsSettings, QgsError, QgsProcessingAlgorithm, - QgsProcessingFeatureBasedAlgorithm + QgsProcessingFeatureBasedAlgorithm, ) from qgis.utils import iface, OverrideCursor from qgis.processing import alg as algfactory @@ -58,8 +50,7 @@ with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) - WIDGET, BASE = uic.loadUiType( - os.path.join(pluginPath, "ui", "DlgScriptEditor.ui")) + WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, "ui", "DlgScriptEditor.ui")) class ScriptEditorDialog(BASE, WIDGET): @@ -77,8 +68,9 @@ def __init__(self, filePath=None, parent=None): ScriptEditorDialog.DIALOG_STORE.append(self) def clean_up_store(): - ScriptEditorDialog.DIALOG_STORE =\ - [d for d in ScriptEditorDialog.DIALOG_STORE if d != self] + ScriptEditorDialog.DIALOG_STORE = [ + d for d in ScriptEditorDialog.DIALOG_STORE if d != self + ] self.destroyed.connect(clean_up_store) @@ -100,31 +92,32 @@ def clean_up_store(): self.setStyleSheet(iface.mainWindow().styleSheet()) self.actionOpenScript.setIcon( - QgsApplication.getThemeIcon('/mActionScriptOpen.svg')) + QgsApplication.getThemeIcon("/mActionScriptOpen.svg") + ) self.actionSaveScript.setIcon( - QgsApplication.getThemeIcon('/mActionFileSave.svg')) + QgsApplication.getThemeIcon("/mActionFileSave.svg") + ) self.actionSaveScriptAs.setIcon( - QgsApplication.getThemeIcon('/mActionFileSaveAs.svg')) - self.actionRunScript.setIcon( - QgsApplication.getThemeIcon('/mActionStart.svg')) - self.actionCut.setIcon( - QgsApplication.getThemeIcon('/mActionEditCut.svg')) - self.actionCopy.setIcon( - QgsApplication.getThemeIcon('/mActionEditCopy.svg')) - self.actionPaste.setIcon( - QgsApplication.getThemeIcon('/mActionEditPaste.svg')) - self.actionUndo.setIcon( - QgsApplication.getThemeIcon('/mActionUndo.svg')) - self.actionRedo.setIcon( - QgsApplication.getThemeIcon('/mActionRedo.svg')) + QgsApplication.getThemeIcon("/mActionFileSaveAs.svg") + ) + self.actionRunScript.setIcon(QgsApplication.getThemeIcon("/mActionStart.svg")) + self.actionCut.setIcon(QgsApplication.getThemeIcon("/mActionEditCut.svg")) + self.actionCopy.setIcon(QgsApplication.getThemeIcon("/mActionEditCopy.svg")) + self.actionPaste.setIcon(QgsApplication.getThemeIcon("/mActionEditPaste.svg")) + self.actionUndo.setIcon(QgsApplication.getThemeIcon("/mActionUndo.svg")) + self.actionRedo.setIcon(QgsApplication.getThemeIcon("/mActionRedo.svg")) self.actionFindReplace.setIcon( - QgsApplication.getThemeIcon('/mActionFindReplace.svg')) + QgsApplication.getThemeIcon("/mActionFindReplace.svg") + ) self.actionIncreaseFontSize.setIcon( - QgsApplication.getThemeIcon('/mActionIncreaseFont.svg')) + QgsApplication.getThemeIcon("/mActionIncreaseFont.svg") + ) self.actionDecreaseFontSize.setIcon( - QgsApplication.getThemeIcon('/mActionDecreaseFont.svg')) + QgsApplication.getThemeIcon("/mActionDecreaseFont.svg") + ) self.actionToggleComment.setIcon( - QgsApplication.getThemeIcon('console/iconCommentEditorConsole.svg')) + QgsApplication.getThemeIcon("console/iconCommentEditorConsole.svg") + ) # Connect signals and slots self.actionOpenScript.triggered.connect(self.openScript) @@ -160,16 +153,14 @@ def update_dialog_title(self): Updates the script editor dialog title """ if self.code_editor_widget.filePath(): - path, file_name = os.path.split( - self.code_editor_widget.filePath() - ) + path, file_name = os.path.split(self.code_editor_widget.filePath()) else: - file_name = self.tr('Untitled Script') + file_name = self.tr("Untitled Script") if self.hasChanged: - file_name = '*' + file_name + file_name = "*" + file_name - self.setWindowTitle(self.tr('{} - Processing Script Editor').format(file_name)) + self.setWindowTitle(self.tr("{} - Processing Script Editor").format(file_name)) def closeEvent(self, event): settings = QgsSettings() @@ -178,9 +169,16 @@ def closeEvent(self, event): if self.hasChanged: ret = QMessageBox.question( - self, self.tr('Save Script?'), - self.tr('There are unsaved changes in this script. Do you want to keep those?'), - QMessageBox.StandardButton.Save | QMessageBox.StandardButton.Cancel | QMessageBox.StandardButton.Discard, QMessageBox.StandardButton.Cancel) + self, + self.tr("Save Script?"), + self.tr( + "There are unsaved changes in this script. Do you want to keep those?" + ), + QMessageBox.StandardButton.Save + | QMessageBox.StandardButton.Cancel + | QMessageBox.StandardButton.Discard, + QMessageBox.StandardButton.Cancel, + ) if ret == QMessageBox.StandardButton.Save: self.saveScript(False) @@ -194,18 +192,23 @@ def closeEvent(self, event): def openScript(self): if self.hasChanged: - ret = QMessageBox.warning(self, - self.tr("Unsaved changes"), - self.tr("There are unsaved changes in the script. Continue?"), - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.No) + ret = QMessageBox.warning( + self, + self.tr("Unsaved changes"), + self.tr("There are unsaved changes in the script. Continue?"), + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + QMessageBox.StandardButton.No, + ) if ret == QMessageBox.StandardButton.No: return scriptDir = ScriptUtils.scriptsFolders()[0] - fileName, _ = QFileDialog.getOpenFileName(self, - self.tr("Open script"), - scriptDir, - self.tr("Processing scripts (*.py *.PY)")) + fileName, _ = QFileDialog.getOpenFileName( + self, + self.tr("Open script"), + scriptDir, + self.tr("Processing scripts (*.py *.PY)"), + ) if fileName == "": return @@ -223,13 +226,15 @@ def saveScript(self, saveAs): newPath = None if not self.code_editor_widget.filePath() or saveAs: scriptDir = ScriptUtils.scriptsFolders()[0] - newPath, _ = QFileDialog.getSaveFileName(self, - self.tr("Save script"), - scriptDir, - self.tr("Processing scripts (*.py *.PY)")) + newPath, _ = QFileDialog.getSaveFileName( + self, + self.tr("Save script"), + scriptDir, + self.tr("Processing scripts (*.py *.PY)"), + ) if newPath: - newPath = QgsFileUtils.ensureFileNameHasExtension(newPath, ['py']) + newPath = QgsFileUtils.ensureFileNameHasExtension(newPath, ["py"]) self.code_editor_widget.save(newPath) elif self.code_editor_widget.filePath(): self.code_editor_widget.save() @@ -255,9 +260,7 @@ def runAlgorithm(self): exec(self.editor.text(), _locals) except Exception as e: error = QgsError(traceback.format_exc(), "Processing") - QgsErrorDialog.show(error, - self.tr("Execution error") - ) + QgsErrorDialog.show(error, self.tr("Execution error")) return alg = None @@ -265,15 +268,27 @@ def runAlgorithm(self): alg = algfactory.instances.pop().createInstance() except IndexError: for name, attr in _locals.items(): - if inspect.isclass(attr) and issubclass(attr, (QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm)) and attr.__name__ not in ("QgsProcessingAlgorithm", "QgsProcessingFeatureBasedAlgorithm"): + if ( + inspect.isclass(attr) + and issubclass( + attr, + (QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm), + ) + and attr.__name__ + not in ( + "QgsProcessingAlgorithm", + "QgsProcessingFeatureBasedAlgorithm", + ) + ): alg = attr() break if alg is None: - QMessageBox.warning(self, - self.tr("No script found"), - self.tr("Seems there is no valid script in the file.") - ) + QMessageBox.warning( + self, + self.tr("No script found"), + self.tr("Seems there is no valid script in the file."), + ) return alg.setProvider(QgsApplication.processingRegistry().providerById("script")) diff --git a/python/plugins/processing/script/ScriptTemplate.py b/python/plugins/processing/script/ScriptTemplate.py index 670cd9053396..2db9a15c142a 100644 --- a/python/plugins/processing/script/ScriptTemplate.py +++ b/python/plugins/processing/script/ScriptTemplate.py @@ -10,12 +10,14 @@ """ from qgis.PyQt.QtCore import QCoreApplication -from qgis.core import (QgsProcessing, - QgsFeatureSink, - QgsProcessingException, - QgsProcessingAlgorithm, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink) +from qgis.core import ( + QgsProcessing, + QgsFeatureSink, + QgsProcessingException, + QgsProcessingAlgorithm, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterFeatureSink, +) from qgis import processing @@ -37,14 +39,14 @@ class ExampleProcessingAlgorithm(QgsProcessingAlgorithm): # used when calling the algorithm from another algorithm, or when # calling from the QGIS console. - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + OUTPUT = "OUTPUT" def tr(self, string): """ Returns a translatable string with the self.tr() function. """ - return QCoreApplication.translate('Processing', string) + return QCoreApplication.translate("Processing", string) def createInstance(self): return ExampleProcessingAlgorithm() @@ -57,21 +59,21 @@ def name(self): lowercase alphanumeric characters only and no spaces or other formatting characters. """ - return 'myscript' + return "myscript" def displayName(self): """ Returns the translated algorithm name, which should be used for any user-visible display of the algorithm name. """ - return self.tr('My Script') + return self.tr("My Script") def group(self): """ Returns the name of the group this algorithm belongs to. This string should be localised. """ - return self.tr('Example scripts') + return self.tr("Example scripts") def groupId(self): """ @@ -81,7 +83,7 @@ def groupId(self): contain lowercase alphanumeric characters only and no spaces or other formatting characters. """ - return 'examplescripts' + return "examplescripts" def shortHelpString(self): """ @@ -102,8 +104,8 @@ def initAlgorithm(self, config=None): self.addParameter( QgsProcessingParameterFeatureSource( self.INPUT, - self.tr('Input layer'), - [QgsProcessing.SourceType.TypeVectorAnyGeometry] + self.tr("Input layer"), + [QgsProcessing.SourceType.TypeVectorAnyGeometry], ) ) @@ -111,10 +113,7 @@ def initAlgorithm(self, config=None): # usually takes the form of a newly created vector layer when the # algorithm is run in QGIS). self.addParameter( - QgsProcessingParameterFeatureSink( - self.OUTPUT, - self.tr('Output layer') - ) + QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr("Output layer")) ) def processAlgorithm(self, parameters, context, feedback): @@ -125,18 +124,16 @@ def processAlgorithm(self, parameters, context, feedback): # Retrieve the feature source and sink. The 'dest_id' variable is used # to uniquely identify the feature sink, and must be included in the # dictionary returned by the processAlgorithm function. - source = self.parameterAsSource( - parameters, - self.INPUT, - context - ) + source = self.parameterAsSource(parameters, self.INPUT, context) # If source was not found, throw an exception to indicate that the algorithm # encountered a fatal error. The exception text can be any string, but in this # case we use the pre-built invalidSourceError method to return a standard # helper text for when a source cannot be evaluated if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) + raise QgsProcessingException( + self.invalidSourceError(parameters, self.INPUT) + ) (sink, dest_id) = self.parameterAsSink( parameters, @@ -144,11 +141,11 @@ def processAlgorithm(self, parameters, context, feedback): context, source.fields(), source.wkbType(), - source.sourceCrs() + source.sourceCrs(), ) # Send some information to the user - feedback.pushInfo(f'CRS is {source.sourceCrs().authid()}') + feedback.pushInfo(f"CRS is {source.sourceCrs().authid()}") # If sink was not created, throw an exception to indicate that the algorithm # encountered a fatal error. The exception text can be any string, but in this @@ -179,16 +176,21 @@ def processAlgorithm(self, parameters, context, feedback): # to the executed algorithm, and that the executed algorithm can send feedback # reports to the user (and correctly handle cancellation and progress reports!) if False: - buffered_layer = processing.run("native:buffer", { - 'INPUT': dest_id, - 'DISTANCE': 1.5, - 'SEGMENTS': 5, - 'END_CAP_STYLE': 0, - 'JOIN_STYLE': 0, - 'MITER_LIMIT': 2, - 'DISSOLVE': False, - 'OUTPUT': 'memory:' - }, context=context, feedback=feedback)['OUTPUT'] + buffered_layer = processing.run( + "native:buffer", + { + "INPUT": dest_id, + "DISTANCE": 1.5, + "SEGMENTS": 5, + "END_CAP_STYLE": 0, + "JOIN_STYLE": 0, + "MITER_LIMIT": 2, + "DISSOLVE": False, + "OUTPUT": "memory:", + }, + context=context, + feedback=feedback, + )["OUTPUT"] # Return the results of the algorithm. In this case our only result is # the feature sink which contains the processed features, but some diff --git a/python/plugins/processing/script/ScriptUtils.py b/python/plugins/processing/script/ScriptUtils.py index e9cd4058cd26..793f91ce337e 100644 --- a/python/plugins/processing/script/ScriptUtils.py +++ b/python/plugins/processing/script/ScriptUtils.py @@ -15,10 +15,9 @@ *************************************************************************** """ - -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" from qgis.processing import alg as algfactory import os @@ -27,12 +26,13 @@ from qgis.PyQt.QtCore import QCoreApplication, QDir -from qgis.core import (Qgis, - QgsApplication, - QgsProcessingAlgorithm, - QgsProcessingFeatureBasedAlgorithm, - QgsMessageLog - ) +from qgis.core import ( + Qgis, + QgsApplication, + QgsProcessingAlgorithm, + QgsProcessingFeatureBasedAlgorithm, + QgsMessageLog, +) from processing.core.ProcessingConfig import ProcessingConfig from processing.tools.system import mkdir, userFolder @@ -70,14 +70,29 @@ def loadAlgorithm(moduleName, filePath): except IndexError: for x in dir(module): obj = getattr(module, x) - if inspect.isclass(obj) and issubclass(obj, (QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm)) and obj.__name__ not in ("QgsProcessingAlgorithm", "QgsProcessingFeatureBasedAlgorithm"): + if ( + inspect.isclass(obj) + and issubclass( + obj, + (QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm), + ) + and obj.__name__ + not in ( + "QgsProcessingAlgorithm", + "QgsProcessingFeatureBasedAlgorithm", + ) + ): o = obj() scriptsRegistry[o.name()] = filePath return o except (ImportError, AttributeError, TypeError) as e: - QgsMessageLog.logMessage(QCoreApplication.translate("ScriptUtils", "Could not import script algorithm '{}' from '{}'\n{}").format(moduleName, filePath, str(e)), - QCoreApplication.translate("ScriptUtils", "Processing"), - Qgis.MessageLevel.Critical) + QgsMessageLog.logMessage( + QCoreApplication.translate( + "ScriptUtils", "Could not import script algorithm '{}' from '{}'\n{}" + ).format(moduleName, filePath, str(e)), + QCoreApplication.translate("ScriptUtils", "Processing"), + Qgis.MessageLevel.Critical, + ) def findAlgorithmSource(name): @@ -96,9 +111,13 @@ def resetScriptFolder(folder): if os.path.exists(newFolder): return newFolder - QgsMessageLog.logMessage(QgsApplication .translate("loadAlgorithms", "Script folder {} does not exist").format(newFolder), - QgsApplication.translate("loadAlgorithms", "Processing"), - Qgis.MessageLevel.Warning) + QgsMessageLog.logMessage( + QgsApplication.translate( + "loadAlgorithms", "Script folder {} does not exist" + ).format(newFolder), + QgsApplication.translate("loadAlgorithms", "Processing"), + Qgis.MessageLevel.Warning, + ) if not os.path.isabs(newFolder): return None @@ -115,7 +134,7 @@ def resetScriptFolder(folder): if commonSettingPath in newFolder: # strip not common folder part. e.g. preserve the profile path # stripping the heading part that come from another location - tail = newFolder[newFolder.find(commonSettingPath):] + tail = newFolder[newFolder.find(commonSettingPath) :] # tail folder with the actual userSetting path header = os.path.join(os.sep, os.path.join(*paths[:appIndex])) newFolder = os.path.join(header, tail) @@ -124,8 +143,12 @@ def resetScriptFolder(folder): if not os.path.exists(newFolder): return None - QgsMessageLog.logMessage(QgsApplication .translate("loadAlgorithms", "Script folder changed into {}").format(newFolder), - QgsApplication.translate("loadAlgorithms", "Processing"), - Qgis.MessageLevel.Warning) + QgsMessageLog.logMessage( + QgsApplication.translate( + "loadAlgorithms", "Script folder changed into {}" + ).format(newFolder), + QgsApplication.translate("loadAlgorithms", "Processing"), + Qgis.MessageLevel.Warning, + ) return newFolder diff --git a/python/plugins/processing/tests/AlgorithmsTestBase.py b/python/plugins/processing/tests/AlgorithmsTestBase.py index 3323c5477ac8..e2255a0e32aa 100644 --- a/python/plugins/processing/tests/AlgorithmsTestBase.py +++ b/python/plugins/processing/tests/AlgorithmsTestBase.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'January 2016' -__copyright__ = '(C) 2016, Matthias Kuhn' +__author__ = "Matthias Kuhn" +__date__ = "January 2016" +__copyright__ = "(C) 2016, Matthias Kuhn" import os @@ -35,21 +35,21 @@ from copy import deepcopy from qgis.PyQt.QtCore import QT_VERSION -from qgis.core import (Qgis, - QgsVectorLayer, - QgsRasterLayer, - QgsCoordinateReferenceSystem, - QgsFeatureRequest, - QgsMapLayer, - QgsProject, - QgsApplication, - QgsProcessingContext, - QgsProcessingUtils, - QgsProcessingFeedback) -from qgis.analysis import (QgsNativeAlgorithms) -from qgis.testing import (_UnexpectedSuccess, - QgisTestCase, - start_app) +from qgis.core import ( + Qgis, + QgsVectorLayer, + QgsRasterLayer, + QgsCoordinateReferenceSystem, + QgsFeatureRequest, + QgsMapLayer, + QgsProject, + QgsApplication, + QgsProcessingContext, + QgsProcessingUtils, + QgsProcessingFeedback, +) +from qgis.analysis import QgsNativeAlgorithms +from qgis.testing import _UnexpectedSuccess, QgisTestCase, start_app from utilities import unitTestDataPath import processing @@ -58,11 +58,11 @@ def GDAL_COMPUTE_VERSION(maj, min, rev): - return ((maj) * 1000000 + (min) * 10000 + (rev) * 100) + return (maj) * 1000000 + (min) * 10000 + (rev) * 100 def processingTestDataPath(): - return os.path.join(os.path.dirname(__file__), 'testdata') + return os.path.join(os.path.dirname(__file__), "testdata") class AlgorithmsTest: @@ -71,51 +71,95 @@ def test_algorithms(self): """ This is the main test function. All others will be executed based on the definitions in testdata/algorithm_tests.yaml """ - with open(os.path.join(processingTestDataPath(), self.definition_file())) as stream: + with open( + os.path.join(processingTestDataPath(), self.definition_file()) + ) as stream: algorithm_tests = yaml.load(stream, Loader=yaml.SafeLoader) - if 'tests' in algorithm_tests and algorithm_tests['tests'] is not None: - for idx, algtest in enumerate(algorithm_tests['tests']): - condition = algtest.get('condition') + if "tests" in algorithm_tests and algorithm_tests["tests"] is not None: + for idx, algtest in enumerate(algorithm_tests["tests"]): + condition = algtest.get("condition") if condition: - geos_condition = condition.get('geos') + geos_condition = condition.get("geos") if geos_condition: - less_than_condition = geos_condition.get('less_than') + less_than_condition = geos_condition.get("less_than") if less_than_condition: if Qgis.geosVersionInt() >= less_than_condition: - print('!!! Skipping {}, requires GEOS < {}, have version {}'.format(algtest['name'], less_than_condition, Qgis.geosVersionInt())) + print( + "!!! Skipping {}, requires GEOS < {}, have version {}".format( + algtest["name"], + less_than_condition, + Qgis.geosVersionInt(), + ) + ) continue - at_least_condition = geos_condition.get('at_least') + at_least_condition = geos_condition.get("at_least") if at_least_condition: if Qgis.geosVersionInt() < at_least_condition: - print('!!! Skipping {}, requires GEOS >= {}, have version {}'.format(algtest['name'], at_least_condition, Qgis.geosVersionInt())) + print( + "!!! Skipping {}, requires GEOS >= {}, have version {}".format( + algtest["name"], + at_least_condition, + Qgis.geosVersionInt(), + ) + ) continue - gdal_condition = condition.get('gdal') + gdal_condition = condition.get("gdal") if gdal_condition: - less_than_condition = gdal_condition.get('less_than') + less_than_condition = gdal_condition.get("less_than") if less_than_condition: - if int(gdal.VersionInfo('VERSION_NUM')) >= less_than_condition: - print('!!! Skipping {}, requires GDAL < {}, have version {}'.format(algtest['name'], less_than_condition, gdal.VersionInfo('VERSION_NUM'))) + if ( + int(gdal.VersionInfo("VERSION_NUM")) + >= less_than_condition + ): + print( + "!!! Skipping {}, requires GDAL < {}, have version {}".format( + algtest["name"], + less_than_condition, + gdal.VersionInfo("VERSION_NUM"), + ) + ) continue - at_least_condition = gdal_condition.get('at_least') + at_least_condition = gdal_condition.get("at_least") if at_least_condition: - if int(gdal.VersionInfo('VERSION_NUM')) < at_least_condition: - print('!!! Skipping {}, requires GDAL >= {}, have version {}'.format(algtest['name'], at_least_condition, gdal.VersionInfo('VERSION_NUM'))) + if ( + int(gdal.VersionInfo("VERSION_NUM")) + < at_least_condition + ): + print( + "!!! Skipping {}, requires GDAL >= {}, have version {}".format( + algtest["name"], + at_least_condition, + gdal.VersionInfo("VERSION_NUM"), + ) + ) continue - qt_condition = condition.get('qt') + qt_condition = condition.get("qt") if qt_condition: - less_than_condition = qt_condition.get('less_than') + less_than_condition = qt_condition.get("less_than") if less_than_condition: if QT_VERSION >= less_than_condition: - print('!!! Skipping {}, requires Qt < {}, have version {}'.format(algtest['name'], less_than_condition, QT_VERSION)) + print( + "!!! Skipping {}, requires Qt < {}, have version {}".format( + algtest["name"], less_than_condition, QT_VERSION + ) + ) continue - at_least_condition = qt_condition.get('at_least') + at_least_condition = qt_condition.get("at_least") if at_least_condition: if QT_VERSION < at_least_condition: - print('!!! Skipping {}, requires Qt >= {}, have version {}'.format(algtest['name'], at_least_condition, QT_VERSION)) + print( + "!!! Skipping {}, requires Qt >= {}, have version {}".format( + algtest["name"], at_least_condition, QT_VERSION + ) + ) continue - print('About to start {} of {}: "{}"'.format(idx, len(algorithm_tests['tests']), algtest['name'])) - yield self.check_algorithm, algtest['name'], algtest + print( + 'About to start {} of {}: "{}"'.format( + idx, len(algorithm_tests["tests"]), algtest["name"] + ) + ) + yield self.check_algorithm, algtest["name"], algtest def check_algorithm(self, name, defs): """ @@ -126,25 +170,29 @@ def check_algorithm(self, name, defs): self.vector_layer_params = {} QgsProject.instance().clear() - if 'project' in defs: - full_project_path = os.path.join(processingTestDataPath(), defs['project']) + if "project" in defs: + full_project_path = os.path.join(processingTestDataPath(), defs["project"]) project_read_success = QgsProject.instance().read(full_project_path) - self.assertTrue(project_read_success, 'Failed to load project file: ' + defs['project']) - - if 'project_crs' in defs: - QgsProject.instance().setCrs(QgsCoordinateReferenceSystem(defs['project_crs'])) + self.assertTrue( + project_read_success, "Failed to load project file: " + defs["project"] + ) + + if "project_crs" in defs: + QgsProject.instance().setCrs( + QgsCoordinateReferenceSystem(defs["project_crs"]) + ) else: QgsProject.instance().setCrs(QgsCoordinateReferenceSystem()) - if 'ellipsoid' in defs: - QgsProject.instance().setEllipsoid(defs['ellipsoid']) + if "ellipsoid" in defs: + QgsProject.instance().setEllipsoid(defs["ellipsoid"]) else: - QgsProject.instance().setEllipsoid('') + QgsProject.instance().setEllipsoid("") - params = self.load_params(defs['params']) + params = self.load_params(defs["params"]) - print('Running alg: "{}"'.format(defs['algorithm'])) - alg = QgsApplication.processingRegistry().createAlgorithmById(defs['algorithm']) + print('Running alg: "{}"'.format(defs["algorithm"])) + alg = QgsApplication.processingRegistry().createAlgorithmById(defs["algorithm"]) parameters = {} if isinstance(params, list): @@ -154,51 +202,53 @@ def check_algorithm(self, name, defs): for k, p in params.items(): parameters[k] = p - for r, p in list(defs['results'].items()): - if 'in_place_result' not in p or not p['in_place_result']: + for r, p in list(defs["results"].items()): + if "in_place_result" not in p or not p["in_place_result"]: parameters[r] = self.load_result_param(p) expectFailure = False - if 'expectedFailure' in defs: - exec(('\n'.join(defs['expectedFailure'][:-1])), globals(), locals()) - expectFailure = eval(defs['expectedFailure'][-1]) + if "expectedFailure" in defs: + exec(("\n".join(defs["expectedFailure"][:-1])), globals(), locals()) + expectFailure = eval(defs["expectedFailure"][-1]) - if 'expectedException' in defs: + if "expectedException" in defs: expectFailure = True # ignore user setting for invalid geometry handling context = QgsProcessingContext() context.setProject(QgsProject.instance()) - if 'ellipsoid' in defs: + if "ellipsoid" in defs: # depending on the project settings, we can't always rely # on QgsProject.ellipsoid() returning the same ellipsoid as was # specified in the test definition. So just force ensure that the # context's ellipsoid is the desired one - context.setEllipsoid(defs['ellipsoid']) + context.setEllipsoid(defs["ellipsoid"]) - if 'skipInvalid' in defs and defs['skipInvalid']: - context.setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid) + if "skipInvalid" in defs and defs["skipInvalid"]: + context.setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid + ) feedback = QgsProcessingFeedback() - print(f'Algorithm parameters are {parameters}') + print(f"Algorithm parameters are {parameters}") # first check that algorithm accepts the parameters we pass... ok, msg = alg.checkParameterValues(parameters, context) - self.assertTrue(ok, f'Algorithm failed checkParameterValues with result {msg}') + self.assertTrue(ok, f"Algorithm failed checkParameterValues with result {msg}") if expectFailure: try: results, ok = alg.run(parameters, context, feedback) - self.check_results(results, context, parameters, defs['results']) + self.check_results(results, context, parameters, defs["results"]) if ok: raise _UnexpectedSuccess except Exception: pass else: results, ok = alg.run(parameters, context, feedback) - self.assertTrue(ok, f'params: {parameters}, results: {results}') - self.check_results(results, context, parameters, defs['results']) + self.assertTrue(ok, f"params: {parameters}, results: {results}") + self.check_results(results, context, parameters, defs["results"]) def load_params(self, params): """ @@ -217,68 +267,75 @@ def load_param(self, param, id=None): parameter based on its key `type` and return the appropriate parameter to pass to the algorithm. """ try: - if param['type'] in ('vector', 'raster', 'table'): + if param["type"] in ("vector", "raster", "table"): return self.load_layer(id, param).id() - elif param['type'] == 'vrtlayers': + elif param["type"] == "vrtlayers": vals = [] - for p in param['params']: - p['layer'] = self.load_layer(None, {'type': 'vector', 'name': p['layer']}) + for p in param["params"]: + p["layer"] = self.load_layer( + None, {"type": "vector", "name": p["layer"]} + ) vals.append(p) return vals - elif param['type'] == 'multi': - return [self.load_param(p) for p in param['params']] - elif param['type'] == 'file': + elif param["type"] == "multi": + return [self.load_param(p) for p in param["params"]] + elif param["type"] == "file": return self.filepath_from_param(param) - elif param['type'] == 'interpolation': + elif param["type"] == "interpolation": prefix = processingTestDataPath() - tmp = '' - for r in param['name'].split('::|::'): - v = r.split('::~::') - tmp += '{}::~::{}::~::{}::~::{};'.format(os.path.join(prefix, v[0]), - v[1], v[2], v[3]) + tmp = "" + for r in param["name"].split("::|::"): + v = r.split("::~::") + tmp += "{}::~::{}::~::{}::~::{};".format( + os.path.join(prefix, v[0]), v[1], v[2], v[3] + ) return tmp[:-1] except TypeError: # No type specified, use whatever is there return param - raise KeyError("Unknown type '{}' specified for parameter".format(param['type'])) + raise KeyError( + "Unknown type '{}' specified for parameter".format(param["type"]) + ) def load_result_param(self, param): """ Loads a result parameter. Creates a temporary destination where the result should go to and returns this location so it can be sent to the algorithm as parameter. """ - if param['type'] in ['vector', 'file', 'table', 'regex']: + if param["type"] in ["vector", "file", "table", "regex"]: outdir = tempfile.mkdtemp() self.cleanup_paths.append(outdir) - if isinstance(param['name'], str): - basename = os.path.basename(param['name']) + if isinstance(param["name"], str): + basename = os.path.basename(param["name"]) else: - basename = os.path.basename(param['name'][0]) + basename = os.path.basename(param["name"][0]) filepath = self.uri_path_join(outdir, basename) return filepath - elif param['type'] == 'rasterhash': + elif param["type"] == "rasterhash": outdir = tempfile.mkdtemp() self.cleanup_paths.append(outdir) - basename = 'raster.tif' + basename = "raster.tif" filepath = os.path.join(outdir, basename) return filepath - elif param['type'] == 'directory': + elif param["type"] == "directory": outdir = tempfile.mkdtemp() return outdir - raise KeyError("Unknown type '{}' specified for parameter".format(param['type'])) + raise KeyError( + "Unknown type '{}' specified for parameter".format(param["type"]) + ) def load_layers(self, id, param): layers = [] - if param['type'] in ('vector', 'table'): - if isinstance(param['name'], str) or 'uri' in param: + if param["type"] in ("vector", "table"): + if isinstance(param["name"], str) or "uri" in param: layers.append(self.load_layer(id, param)) else: - for n in param['name']: + for n in param["name"]: layer_param = deepcopy(param) - layer_param['name'] = n + layer_param["name"] = n layers.append(self.load_layer(id, layer_param)) else: layers.append(self.load_layer(id, param)) @@ -291,37 +348,39 @@ def load_layer(self, id, param): filepath = self.filepath_from_param(param) - if 'in_place' in param and param['in_place']: + if "in_place" in param and param["in_place"]: # check if alg modifies layer in place tmpdir = tempfile.mkdtemp() self.cleanup_paths.append(tmpdir) path, file_name = os.path.split(filepath) base, ext = os.path.splitext(file_name) - for file in glob.glob(os.path.join(path, f'{base}.*')): + for file in glob.glob(os.path.join(path, f"{base}.*")): shutil.copy(os.path.join(path, file), tmpdir) filepath = os.path.join(tmpdir, file_name) self.in_place_layers[id] = filepath - if param['type'] in ('vector', 'table'): - gmlrex = r'\.gml\b' + if param["type"] in ("vector", "table"): + gmlrex = r"\.gml\b" if re.search(gmlrex, filepath, re.IGNORECASE): # ewwwww - we have to force SRS detection for GML files, otherwise they'll be loaded # with no srs - filepath += '|option:FORCE_SRS_DETECTION=YES' + filepath += "|option:FORCE_SRS_DETECTION=YES" if filepath in self.vector_layer_params: return self.vector_layer_params[filepath] options = QgsVectorLayer.LayerOptions() options.loadDefaultStyle = False - lyr = QgsVectorLayer(filepath, param['name'], 'ogr', options) + lyr = QgsVectorLayer(filepath, param["name"], "ogr", options) self.vector_layer_params[filepath] = lyr - elif param['type'] == 'raster': + elif param["type"] == "raster": options = QgsRasterLayer.LayerOptions() options.loadDefaultStyle = False - lyr = QgsRasterLayer(filepath, param['name'], 'gdal', options) + lyr = QgsRasterLayer(filepath, param["name"], "gdal", options) - self.assertTrue(lyr.isValid(), f'Could not load layer "{filepath}" from param {param}') + self.assertTrue( + lyr.isValid(), f'Could not load layer "{filepath}" from param {param}' + ) QgsProject.instance().addMapLayer(lyr) return lyr @@ -330,13 +389,13 @@ def filepath_from_param(self, param): Creates a filepath from a param """ prefix = processingTestDataPath() - if 'location' in param and param['location'] == 'qgs': + if "location" in param and param["location"] == "qgs": prefix = unitTestDataPath() - if 'uri' in param: - path = param['uri'] + if "uri" in param: + path = param["uri"] else: - path = param['name'] + path = param["name"] if not path: return None @@ -344,7 +403,7 @@ def filepath_from_param(self, param): return self.uri_path_join(prefix, path) def uri_path_join(self, prefix, filepath): - if filepath.startswith('ogr:'): + if filepath.startswith("ogr:"): if not prefix[-1] == os.path.sep: prefix += os.path.sep filepath = re.sub(r"dbname='", f"dbname='{prefix}", filepath) @@ -358,88 +417,105 @@ def check_results(self, results, context, params, expected): Checks if result produced by an algorithm matches with the expected specification. """ for id, expected_result in expected.items(): - if expected_result['type'] in ('vector', 'table'): - if 'compare' in expected_result and not expected_result['compare']: + if expected_result["type"] in ("vector", "table"): + if "compare" in expected_result and not expected_result["compare"]: # skipping the comparison, so just make sure output is valid if isinstance(results[id], QgsMapLayer): result_lyr = results[id] else: - result_lyr = QgsProcessingUtils.mapLayerFromString(results[id], context) + result_lyr = QgsProcessingUtils.mapLayerFromString( + results[id], context + ) self.assertTrue(result_lyr.isValid()) continue expected_lyrs = self.load_layers(id, expected_result) - if 'in_place_result' in expected_result: - result_lyr = QgsProcessingUtils.mapLayerFromString(self.in_place_layers[id], context) + if "in_place_result" in expected_result: + result_lyr = QgsProcessingUtils.mapLayerFromString( + self.in_place_layers[id], context + ) self.assertTrue(result_lyr.isValid(), self.in_place_layers[id]) else: try: results[id] except KeyError as e: - raise KeyError(f'Expected result {str(e)} does not exist in {list(results.keys())}') + raise KeyError( + f"Expected result {str(e)} does not exist in {list(results.keys())}" + ) if isinstance(results[id], QgsMapLayer): result_lyr = results[id] else: string = results[id] - gmlrex = r'\.gml\b' + gmlrex = r"\.gml\b" if re.search(gmlrex, string, re.IGNORECASE): # ewwwww - we have to force SRS detection for GML files, otherwise they'll be loaded # with no srs - string += '|option:FORCE_SRS_DETECTION=YES' + string += "|option:FORCE_SRS_DETECTION=YES" - result_lyr = QgsProcessingUtils.mapLayerFromString(string, context) + result_lyr = QgsProcessingUtils.mapLayerFromString( + string, context + ) self.assertTrue(result_lyr, results[id]) - compare = expected_result.get('compare', {}) - pk = expected_result.get('pk', None) + compare = expected_result.get("compare", {}) + pk = expected_result.get("pk", None) if len(expected_lyrs) == 1: - self.assertLayersEqual(expected_lyrs[0], result_lyr, compare=compare, pk=pk) + self.assertLayersEqual( + expected_lyrs[0], result_lyr, compare=compare, pk=pk + ) else: res = False for l in expected_lyrs: if self.checkLayersEqual(l, result_lyr, compare=compare, pk=pk): res = True break - self.assertTrue(res, 'Could not find matching layer in expected results') + self.assertTrue( + res, "Could not find matching layer in expected results" + ) - elif 'rasterhash' == expected_result['type']: + elif "rasterhash" == expected_result["type"]: print(f"id:{id} result:{results[id]}") - self.assertTrue(os.path.exists(results[id]), f'File does not exist: {results[id]}, {params}') + self.assertTrue( + os.path.exists(results[id]), + f"File does not exist: {results[id]}, {params}", + ) dataset = gdal.Open(results[id], GA_ReadOnly) dataArray = nan_to_num(dataset.ReadAsArray(0)) strhash = hashlib.sha224(dataArray.data).hexdigest() - if not isinstance(expected_result['hash'], str): - self.assertIn(strhash, expected_result['hash']) + if not isinstance(expected_result["hash"], str): + self.assertIn(strhash, expected_result["hash"]) else: - self.assertEqual(strhash, expected_result['hash']) - elif 'file' == expected_result['type']: + self.assertEqual(strhash, expected_result["hash"]) + elif "file" == expected_result["type"]: result_filepath = results[id] - if isinstance(expected_result.get('name'), list): + if isinstance(expected_result.get("name"), list): # test to see if any match expected - for path in expected_result['name']: - expected_filepath = self.filepath_from_param({'name': path}) + for path in expected_result["name"]: + expected_filepath = self.filepath_from_param({"name": path}) if self.checkFilesEqual(expected_filepath, result_filepath): break else: - expected_filepath = self.filepath_from_param({'name': expected_result['name'][0]}) + expected_filepath = self.filepath_from_param( + {"name": expected_result["name"][0]} + ) else: expected_filepath = self.filepath_from_param(expected_result) self.assertFilesEqual(expected_filepath, result_filepath) - elif 'directory' == expected_result['type']: + elif "directory" == expected_result["type"]: expected_dirpath = self.filepath_from_param(expected_result) result_dirpath = results[id] self.assertDirectoriesEqual(expected_dirpath, result_dirpath) - elif 'regex' == expected_result['type']: + elif "regex" == expected_result["type"]: with open(results[id]) as file: data = file.read() - for rule in expected_result.get('rules', []): + for rule in expected_result.get("rules", []): self.assertRegex(data, rule) @@ -452,21 +528,23 @@ class GenericAlgorithmsTest(QgisTestCase): def setUpClass(cls): start_app() from processing.core.Processing import Processing + Processing.initialize() cls.cleanup_paths = [] @classmethod def tearDownClass(cls): from processing.core.Processing import Processing + Processing.deinitialize() for path in cls.cleanup_paths: shutil.rmtree(path) def testAlgorithmCompliance(self): for p in QgsApplication.processingRegistry().providers(): - print(f'testing provider {p.id()}') + print(f"testing provider {p.id()}") for a in p.algorithms(): - print(f'testing algorithm {a.id()}') + print(f"testing algorithm {a.id()}") self.check_algorithm(a) def check_algorithm(self, alg): @@ -474,5 +552,5 @@ def check_algorithm(self, alg): alg.helpUrl() -if __name__ == '__main__': +if __name__ == "__main__": nose2.main() diff --git a/python/plugins/processing/tests/CheckValidityAlgorithm.py b/python/plugins/processing/tests/CheckValidityAlgorithm.py index db1e40b21a25..0b6f96863033 100644 --- a/python/plugins/processing/tests/CheckValidityAlgorithm.py +++ b/python/plugins/processing/tests/CheckValidityAlgorithm.py @@ -5,9 +5,10 @@ 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' + +__author__ = "Alessandro Pasotti" +__date__ = "2018-09" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication, QVariant from qgis.core import ( @@ -24,7 +25,7 @@ QgsProject, QgsProcessingException, QgsProcessingUtils, - QgsSettings + QgsSettings, ) from processing.core.Processing import Processing from processing.gui.AlgorithmExecutor import execute @@ -51,9 +52,9 @@ def setUpClass(cls): QCoreApplication.setOrganizationName("QGIS_Test") QCoreApplication.setOrganizationDomain( - "QGIS_TestPyQgsProcessingCheckValidity.com") - QCoreApplication.setApplicationName( - "QGIS_TestPyQgsProcessingCheckValidity") + "QGIS_TestPyQgsProcessingCheckValidity.com" + ) + QCoreApplication.setApplicationName("QGIS_TestPyQgsProcessingCheckValidity") QgsSettings().clear() Processing.initialize() cls.registry = QgsApplication.instance().processingRegistry() @@ -61,9 +62,13 @@ def setUpClass(cls): def _make_layer(self, layer_wkb_name): fields = QgsFields() wkb_type = getattr(QgsWkbTypes, layer_wkb_name) - fields.append(QgsField('int_f', QVariant.Int)) + fields.append(QgsField("int_f", QVariant.Int)) layer = QgsMemoryProviderUtils.createMemoryLayer( - '%s_layer' % layer_wkb_name, fields, wkb_type, QgsCoordinateReferenceSystem("EPSG:4326")) + "%s_layer" % layer_wkb_name, + fields, + wkb_type, + QgsCoordinateReferenceSystem("EPSG:4326"), + ) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), wkb_type) return layer @@ -71,18 +76,20 @@ def _make_layer(self, layer_wkb_name): def test_check_validity(self): """Test that the output invalid contains the error reason""" - polygon_layer = self._make_layer('Polygon') + 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))')) + 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))')) + 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() @@ -91,7 +98,7 @@ def test_check_validity(self): QgsProject.instance().addMapLayers([polygon_layer]) - alg = self.registry.createAlgorithmById('qgis:checkvalidity') + alg = self.registry.createAlgorithmById("qgis:checkvalidity") context = QgsProcessingContext() context.setProject(QgsProject.instance()) @@ -99,36 +106,37 @@ def test_check_validity(self): self.assertIsNotNone(alg) parameters = {} - parameters['INPUT_LAYER'] = polygon_layer.id() - parameters['VALID_OUTPUT'] = 'memory:' - parameters['INVALID_OUTPUT'] = 'memory:' - parameters['ERROR_OUTPUT'] = 'memory:' + 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) + 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') + 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']) + self.assertEqual( + f.attributes(), [1, "segments 0 and 2 of line 0 intersect at 1, 1"] + ) # GEOS method - parameters['METHOD'] = 2 - ok, results = execute( - alg, parameters, context=context, feedback=feedback) + 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') + 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']) + self.assertEqual(f.attributes(), [1, "Self-intersection"]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/python/plugins/processing/tests/GdalAlgorithmsGeneralTest.py b/python/plugins/processing/tests/GdalAlgorithmsGeneralTest.py index 40c86a90eed9..17e090601eb6 100644 --- a/python/plugins/processing/tests/GdalAlgorithmsGeneralTest.py +++ b/python/plugins/processing/tests/GdalAlgorithmsGeneralTest.py @@ -15,37 +15,38 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'January 2016' -__copyright__ = '(C) 2016, Matthias Kuhn' +__author__ = "Matthias Kuhn" +__date__ = "January 2016" +__copyright__ = "(C) 2016, Matthias Kuhn" import nose2 import os import shutil import tempfile -from qgis.core import (QgsProcessingContext, - QgsProcessingFeedback, - QgsCoordinateReferenceSystem, - QgsApplication, - QgsFeature, - QgsGeometry, - QgsPointXY, - QgsProject, - QgsVectorLayer, - QgsRectangle, - QgsProjUtils, - QgsProcessingException, - QgsProcessingFeatureSourceDefinition) - -from qgis.testing import (QgisTestCase, - start_app) +from qgis.core import ( + QgsProcessingContext, + QgsProcessingFeedback, + QgsCoordinateReferenceSystem, + QgsApplication, + QgsFeature, + QgsGeometry, + QgsPointXY, + QgsProject, + QgsVectorLayer, + QgsRectangle, + QgsProjUtils, + QgsProcessingException, + QgsProcessingFeatureSourceDefinition, +) + +from qgis.testing import QgisTestCase, start_app from processing.algs.gdal.GdalUtils import GdalUtils from processing.algs.gdal.ogr2ogr import ogr2ogr from processing.algs.gdal.OgrToPostGis import OgrToPostGis -testDataPath = os.path.join(os.path.dirname(__file__), 'testdata') +testDataPath = os.path.join(os.path.dirname(__file__), "testdata") class TestGdalAlgorithms(QgisTestCase): @@ -54,6 +55,7 @@ class TestGdalAlgorithms(QgisTestCase): def setUpClass(cls): start_app() from processing.core.Processing import Processing + Processing.initialize() cls.cleanup_paths = [] @@ -64,25 +66,28 @@ def tearDownClass(cls): def testCommandName(self): # Test that algorithms report a valid commandName - p = QgsApplication.processingRegistry().providerById('gdal') + p = QgsApplication.processingRegistry().providerById("gdal") for a in p.algorithms(): - if a.id() in ('gdal:buildvirtualvector'): + if a.id() in ("gdal:buildvirtualvector"): # build virtual vector is an exception continue - self.assertTrue(a.commandName(), f'Algorithm {a.id()} has no commandName!') + self.assertTrue(a.commandName(), f"Algorithm {a.id()} has no commandName!") def testCommandNameInTags(self): # Test that algorithms commandName is present in provided tags - p = QgsApplication.processingRegistry().providerById('gdal') + p = QgsApplication.processingRegistry().providerById("gdal") for a in p.algorithms(): if not a.commandName(): continue - self.assertTrue(a.commandName() in a.tags(), f'Algorithm {a.id()} commandName not found in tags!') + self.assertTrue( + a.commandName() in a.tags(), + f"Algorithm {a.id()} commandName not found in tags!", + ) def testNoParameters(self): # Test that algorithms throw QgsProcessingException and not base Python # exceptions when no parameters specified - p = QgsApplication.processingRegistry().providerById('gdal') + p = QgsApplication.processingRegistry().providerById("gdal") context = QgsProcessingContext() feedback = QgsProcessingFeedback() for a in p.algorithms(): @@ -93,8 +98,9 @@ def testNoParameters(self): def testGetOgrCompatibleSourceFromMemoryLayer(self): # create a memory layer and add to project and context - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "testmem", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "testmem", "memory" + ) self.assertTrue(layer.isValid()) pr = layer.dataProvider() f = QgsFeature() @@ -109,20 +115,23 @@ def testGetOgrCompatibleSourceFromMemoryLayer(self): context = QgsProcessingContext() context.setProject(QgsProject.instance()) - alg = QgsApplication.processingRegistry().createAlgorithmById('gdal:buffervectors') + alg = QgsApplication.processingRegistry().createAlgorithmById( + "gdal:buffervectors" + ) self.assertIsNotNone(alg) - parameters = {'INPUT': 'testmem'} + parameters = {"INPUT": "testmem"} feedback = QgsProcessingFeedback() # check that memory layer is automatically saved out to geopackage when required by GDAL algorithms - input_details = alg.getOgrCompatibleSource('INPUT', parameters, context, feedback, - executing=True) + input_details = alg.getOgrCompatibleSource( + "INPUT", parameters, context, feedback, executing=True + ) self.assertTrue(input_details.connection_string) - self.assertTrue(input_details.connection_string.endswith('.gpkg')) + self.assertTrue(input_details.connection_string.endswith(".gpkg")) self.assertTrue(os.path.exists(input_details.connection_string)) self.assertTrue(input_details.connection_string) # make sure that layer has correct features - res = QgsVectorLayer(input_details.connection_string, 'res') + res = QgsVectorLayer(input_details.connection_string, "res") self.assertTrue(res.isValid()) self.assertEqual(res.featureCount(), 2) @@ -131,16 +140,17 @@ def testGetOgrCompatibleSourceFromMemoryLayer(self): # - it has no meaning for the gdal command outside of QGIS, memory layers don't exist! # - we don't want to force an export of the whole memory layer to a temp file just to show the command preview # this might be very slow! - input_details = alg.getOgrCompatibleSource('INPUT', parameters, context, feedback, - executing=False) - self.assertEqual(input_details.connection_string, 'path_to_data_file') - self.assertEqual(input_details.layer_name, 'layer_name') + input_details = alg.getOgrCompatibleSource( + "INPUT", parameters, context, feedback, executing=False + ) + self.assertEqual(input_details.connection_string, "path_to_data_file") + self.assertEqual(input_details.layer_name, "layer_name") QgsProject.instance().removeMapLayer(layer) def testGetOgrCompatibleSourceFromOgrLayer(self): p = QgsProject() - source = os.path.join(testDataPath, 'points.gml') + source = os.path.join(testDataPath, "points.gml") vl = QgsVectorLayer(source) self.assertTrue(vl.isValid()) p.addMapLayer(vl) @@ -151,48 +161,63 @@ def testGetOgrCompatibleSourceFromOgrLayer(self): alg = ogr2ogr() alg.initAlgorithm() - input_details = alg.getOgrCompatibleSource('INPUT', {'INPUT': vl.id()}, context, feedback, True) + input_details = alg.getOgrCompatibleSource( + "INPUT", {"INPUT": vl.id()}, context, feedback, True + ) self.assertEqual(input_details.connection_string, source) - input_details = alg.getOgrCompatibleSource('INPUT', {'INPUT': vl.id()}, context, feedback, False) + input_details = alg.getOgrCompatibleSource( + "INPUT", {"INPUT": vl.id()}, context, feedback, False + ) self.assertEqual(input_details.connection_string, source) # with selected features only - if not executing, the 'selected features only' setting # should be ignored (because it has no meaning for the gdal command outside of QGIS!) - parameters = {'INPUT': QgsProcessingFeatureSourceDefinition(vl.id(), True)} - input_details = alg.getOgrCompatibleSource('INPUT', parameters, context, feedback, False) + parameters = {"INPUT": QgsProcessingFeatureSourceDefinition(vl.id(), True)} + input_details = alg.getOgrCompatibleSource( + "INPUT", parameters, context, feedback, False + ) self.assertEqual(input_details.connection_string, source) # with subset string - vl.setSubsetString('x') - input_details = alg.getOgrCompatibleSource('INPUT', parameters, context, feedback, False) + vl.setSubsetString("x") + input_details = alg.getOgrCompatibleSource( + "INPUT", parameters, context, feedback, False + ) self.assertEqual(input_details.connection_string, source) # subset of layer must be exported - input_details = alg.getOgrCompatibleSource('INPUT', parameters, context, feedback, True) + input_details = alg.getOgrCompatibleSource( + "INPUT", parameters, context, feedback, True + ) self.assertNotEqual(input_details.connection_string, source) self.assertTrue(input_details.connection_string) - self.assertTrue(input_details.connection_string.endswith('.gpkg')) + self.assertTrue(input_details.connection_string.endswith(".gpkg")) self.assertTrue(os.path.exists(input_details.connection_string)) self.assertTrue(input_details.layer_name) # geopackage with layer - source = os.path.join(testDataPath, 'custom', 'circular_strings.gpkg') - vl2 = QgsVectorLayer(source + '|layername=circular_strings') + source = os.path.join(testDataPath, "custom", "circular_strings.gpkg") + vl2 = QgsVectorLayer(source + "|layername=circular_strings") self.assertTrue(vl2.isValid()) p.addMapLayer(vl2) - input_details = alg.getOgrCompatibleSource('INPUT', {'INPUT': vl2.id()}, context, feedback, True) + input_details = alg.getOgrCompatibleSource( + "INPUT", {"INPUT": vl2.id()}, context, feedback, True + ) self.assertEqual(input_details.connection_string, source) - self.assertEqual(input_details.layer_name, 'circular_strings') - vl3 = QgsVectorLayer(source + '|layername=circular_strings_with_line') + self.assertEqual(input_details.layer_name, "circular_strings") + vl3 = QgsVectorLayer(source + "|layername=circular_strings_with_line") self.assertTrue(vl3.isValid()) p.addMapLayer(vl3) - input_details = alg.getOgrCompatibleSource('INPUT', {'INPUT': vl3.id()}, context, feedback, True) + input_details = alg.getOgrCompatibleSource( + "INPUT", {"INPUT": vl3.id()}, context, feedback, True + ) self.assertEqual(input_details.connection_string, source) - self.assertEqual(input_details.layer_name, 'circular_strings_with_line') + self.assertEqual(input_details.layer_name, "circular_strings_with_line") def testGetOgrCompatibleSourceFromFeatureSource(self): # create a memory layer and add to project and context - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "testmem", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "testmem", "memory" + ) self.assertTrue(layer.isValid()) pr = layer.dataProvider() f = QgsFeature() @@ -210,76 +235,95 @@ def testGetOgrCompatibleSourceFromFeatureSource(self): context = QgsProcessingContext() context.setProject(QgsProject.instance()) - alg = QgsApplication.processingRegistry().createAlgorithmById('gdal:buffervectors') + alg = QgsApplication.processingRegistry().createAlgorithmById( + "gdal:buffervectors" + ) self.assertIsNotNone(alg) - parameters = {'INPUT': QgsProcessingFeatureSourceDefinition('testmem', True)} + parameters = {"INPUT": QgsProcessingFeatureSourceDefinition("testmem", True)} feedback = QgsProcessingFeedback() # check that memory layer is automatically saved out to geopackage when required by GDAL algorithms - input_details = alg.getOgrCompatibleSource('INPUT', parameters, context, feedback, - executing=True) + input_details = alg.getOgrCompatibleSource( + "INPUT", parameters, context, feedback, executing=True + ) self.assertTrue(input_details.connection_string) - self.assertTrue(input_details.connection_string.endswith('.gpkg')) + self.assertTrue(input_details.connection_string.endswith(".gpkg")) self.assertTrue(os.path.exists(input_details.connection_string)) self.assertTrue(input_details.layer_name) # make sure that layer has only selected feature - res = QgsVectorLayer(input_details.connection_string, 'res') + res = QgsVectorLayer(input_details.connection_string, "res") self.assertTrue(res.isValid()) self.assertEqual(res.featureCount(), 1) QgsProject.instance().removeMapLayer(layer) def testOgrOutputLayerName(self): - self.assertEqual(GdalUtils.ogrOutputLayerName('/home/me/out.shp'), 'out') - self.assertEqual(GdalUtils.ogrOutputLayerName('d:/test/test_out.shp'), 'test_out') - self.assertEqual(GdalUtils.ogrOutputLayerName('d:/test/TEST_OUT.shp'), 'TEST_OUT') - self.assertEqual(GdalUtils.ogrOutputLayerName('d:/test/test_out.gpkg'), 'test_out') + self.assertEqual(GdalUtils.ogrOutputLayerName("/home/me/out.shp"), "out") + self.assertEqual( + GdalUtils.ogrOutputLayerName("d:/test/test_out.shp"), "test_out" + ) + self.assertEqual( + GdalUtils.ogrOutputLayerName("d:/test/TEST_OUT.shp"), "TEST_OUT" + ) + self.assertEqual( + GdalUtils.ogrOutputLayerName("d:/test/test_out.gpkg"), "test_out" + ) def testOgrLayerNameExtraction(self): with tempfile.TemporaryDirectory() as outdir: + def _copyFile(dst): - shutil.copyfile(os.path.join(testDataPath, 'custom', 'weighted.csv'), dst) + shutil.copyfile( + os.path.join(testDataPath, "custom", "weighted.csv"), dst + ) # OGR provider - single layer - _copyFile(os.path.join(outdir, 'a.csv')) + _copyFile(os.path.join(outdir, "a.csv")) name = GdalUtils.ogrLayerName(outdir) - self.assertEqual(name, 'a') + self.assertEqual(name, "a") # OGR provider - multiple layers - _copyFile(os.path.join(outdir, 'b.csv')) - name1 = GdalUtils.ogrLayerName(outdir + '|layerid=0') - name2 = GdalUtils.ogrLayerName(outdir + '|layerid=1') - self.assertEqual(sorted([name1, name2]), ['a', 'b']) + _copyFile(os.path.join(outdir, "b.csv")) + name1 = GdalUtils.ogrLayerName(outdir + "|layerid=0") + name2 = GdalUtils.ogrLayerName(outdir + "|layerid=1") + self.assertEqual(sorted([name1, name2]), ["a", "b"]) - name = GdalUtils.ogrLayerName(outdir + '|layerid=2') + name = GdalUtils.ogrLayerName(outdir + "|layerid=2") self.assertIsNone(name) # OGR provider - layername takes precedence - name = GdalUtils.ogrLayerName(outdir + '|layername=f') - self.assertEqual(name, 'f') + name = GdalUtils.ogrLayerName(outdir + "|layername=f") + self.assertEqual(name, "f") - name = GdalUtils.ogrLayerName(outdir + '|layerid=0|layername=f') - self.assertEqual(name, 'f') + name = GdalUtils.ogrLayerName(outdir + "|layerid=0|layername=f") + self.assertEqual(name, "f") - name = GdalUtils.ogrLayerName(outdir + '|layername=f|layerid=0') - self.assertEqual(name, 'f') + name = GdalUtils.ogrLayerName(outdir + "|layername=f|layerid=0") + self.assertEqual(name, "f") # SQLite provider - name = GdalUtils.ogrLayerName('dbname=\'/tmp/x.sqlite\' table="t" (geometry) sql=') - self.assertEqual(name, 't') + name = GdalUtils.ogrLayerName( + "dbname='/tmp/x.sqlite' table=\"t\" (geometry) sql=" + ) + self.assertEqual(name, "t") # PostgreSQL provider name = GdalUtils.ogrLayerName( - 'port=5493 sslmode=disable key=\'edge_id\' srid=0 type=LineString table="city_data"."edge" (geom) sql=') - self.assertEqual(name, 'city_data.edge') + 'port=5493 sslmode=disable key=\'edge_id\' srid=0 type=LineString table="city_data"."edge" (geom) sql=' + ) + self.assertEqual(name, "city_data.edge") def test_gdal_connection_details_from_uri(self): context = QgsProcessingContext() - output_details = GdalUtils.gdal_connection_details_from_uri('d:/test/test.shp', context) - self.assertEqual(output_details.connection_string, 'd:/test/test.shp') + output_details = GdalUtils.gdal_connection_details_from_uri( + "d:/test/test.shp", context + ) + self.assertEqual(output_details.connection_string, "d:/test/test.shp") self.assertEqual(output_details.format, '"ESRI Shapefile"') - output_details = GdalUtils.gdal_connection_details_from_uri('d:/test/test.mif', context) - self.assertEqual(output_details.connection_string, 'd:/test/test.mif') + output_details = GdalUtils.gdal_connection_details_from_uri( + "d:/test/test.mif", context + ) + self.assertEqual(output_details.connection_string, "d:/test/test.mif") self.assertEqual(output_details.format, '"MapInfo File"') def testConnectionString(self): @@ -291,54 +335,91 @@ def testConnectionString(self): # NOTE: defaults are debatable, see # https://github.com/qgis/QGIS/pull/3607#issuecomment-253971020 - self.assertEqual(alg.getConnectionString(parameters, context), - "host=localhost port=5432 active_schema=public") - - parameters['HOST'] = 'remote' - self.assertEqual(alg.getConnectionString(parameters, context), - "host=remote port=5432 active_schema=public") - - parameters['HOST'] = '' - self.assertEqual(alg.getConnectionString(parameters, context), - "port=5432 active_schema=public") - - parameters['PORT'] = '5555' - self.assertEqual(alg.getConnectionString(parameters, context), - "port=5555 active_schema=public") - - parameters['PORT'] = '' - self.assertEqual(alg.getConnectionString(parameters, context), - "active_schema=public") - - parameters['USER'] = 'usr' - self.assertEqual(alg.getConnectionString(parameters, context), - "active_schema=public user=usr") - - parameters['PASSWORD'] = 'pwd' - self.assertEqual(alg.getConnectionString(parameters, context), - "password=pwd active_schema=public user=usr") + self.assertEqual( + alg.getConnectionString(parameters, context), + "host=localhost port=5432 active_schema=public", + ) + + parameters["HOST"] = "remote" + self.assertEqual( + alg.getConnectionString(parameters, context), + "host=remote port=5432 active_schema=public", + ) + + parameters["HOST"] = "" + self.assertEqual( + alg.getConnectionString(parameters, context), + "port=5432 active_schema=public", + ) + + parameters["PORT"] = "5555" + self.assertEqual( + alg.getConnectionString(parameters, context), + "port=5555 active_schema=public", + ) + + parameters["PORT"] = "" + self.assertEqual( + alg.getConnectionString(parameters, context), "active_schema=public" + ) + + parameters["USER"] = "usr" + self.assertEqual( + alg.getConnectionString(parameters, context), + "active_schema=public user=usr", + ) + + parameters["PASSWORD"] = "pwd" + self.assertEqual( + alg.getConnectionString(parameters, context), + "password=pwd active_schema=public user=usr", + ) def testCrsConversion(self): self.assertFalse(GdalUtils.gdal_crs_string(QgsCoordinateReferenceSystem())) - self.assertEqual(GdalUtils.gdal_crs_string(QgsCoordinateReferenceSystem('EPSG:3111')), 'EPSG:3111') - self.assertEqual(GdalUtils.gdal_crs_string(QgsCoordinateReferenceSystem('POSTGIS:3111')), 'EPSG:3111') - self.assertEqual(GdalUtils.gdal_crs_string(QgsCoordinateReferenceSystem( - 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs')), - 'EPSG:20936') + self.assertEqual( + GdalUtils.gdal_crs_string(QgsCoordinateReferenceSystem("EPSG:3111")), + "EPSG:3111", + ) + self.assertEqual( + GdalUtils.gdal_crs_string(QgsCoordinateReferenceSystem("POSTGIS:3111")), + "EPSG:3111", + ) + self.assertEqual( + GdalUtils.gdal_crs_string( + QgsCoordinateReferenceSystem( + "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" + ) + ), + "EPSG:20936", + ) crs = QgsCoordinateReferenceSystem() crs.createFromProj( - '+proj=utm +zone=36 +south +a=600000 +b=70000 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs') + "+proj=utm +zone=36 +south +a=600000 +b=70000 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" + ) self.assertTrue(crs.isValid()) # proj 6, WKT should be used - self.assertEqual(GdalUtils.gdal_crs_string(crs)[:40], 'BOUNDCRS[SOURCECRS[PROJCRS["unknown",BAS') + self.assertEqual( + GdalUtils.gdal_crs_string(crs)[:40], + 'BOUNDCRS[SOURCECRS[PROJCRS["unknown",BAS', + ) - self.assertEqual(GdalUtils.gdal_crs_string(QgsCoordinateReferenceSystem('ESRI:102003')), 'ESRI:102003') + self.assertEqual( + GdalUtils.gdal_crs_string(QgsCoordinateReferenceSystem("ESRI:102003")), + "ESRI:102003", + ) def testEscapeAndJoin(self): - self.assertEqual(GdalUtils.escapeAndJoin([1, "a", "a b", "a&b", "a(b)", ";"]), '1 a "a b" "a&b" "a(b)" ";"') - self.assertEqual(GdalUtils.escapeAndJoin([1, "-srcnodata", "--srcnodata", "-9999 9999"]), '1 -srcnodata --srcnodata "-9999 9999"') + self.assertEqual( + GdalUtils.escapeAndJoin([1, "a", "a b", "a&b", "a(b)", ";"]), + '1 a "a b" "a&b" "a(b)" ";"', + ) + self.assertEqual( + GdalUtils.escapeAndJoin([1, "-srcnodata", "--srcnodata", "-9999 9999"]), + '1 -srcnodata --srcnodata "-9999 9999"', + ) -if __name__ == '__main__': +if __name__ == "__main__": nose2.main() diff --git a/python/plugins/processing/tests/GdalAlgorithmsRasterTest.py b/python/plugins/processing/tests/GdalAlgorithmsRasterTest.py index 7971a36179a4..390c37e845b3 100644 --- a/python/plugins/processing/tests/GdalAlgorithmsRasterTest.py +++ b/python/plugins/processing/tests/GdalAlgorithmsRasterTest.py @@ -15,29 +15,29 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'January 2016' -__copyright__ = '(C) 2016, Matthias Kuhn' +__author__ = "Matthias Kuhn" +__date__ = "January 2016" +__copyright__ = "(C) 2016, Matthias Kuhn" import nose2 import os import shutil import tempfile -from qgis.core import (QgsProcessingContext, - QgsProcessingException, - QgsProcessingFeedback, - QgsRectangle, - QgsReferencedRectangle, - QgsRasterLayer, - QgsProject, - QgsProjUtils, - QgsPointXY, - QgsCoordinateReferenceSystem) - -from qgis.testing import (QgisTestCase, - start_app, - unittest) +from qgis.core import ( + QgsProcessingContext, + QgsProcessingException, + QgsProcessingFeedback, + QgsRectangle, + QgsReferencedRectangle, + QgsRasterLayer, + QgsProject, + QgsProjUtils, + QgsPointXY, + QgsCoordinateReferenceSystem, +) + +from qgis.testing import QgisTestCase, start_app, unittest import AlgorithmsTestBase from processing.algs.gdal.GdalUtils import GdalUtils @@ -48,7 +48,9 @@ from processing.algs.gdal.GridAverage import GridAverage from processing.algs.gdal.GridDataMetrics import GridDataMetrics from processing.algs.gdal.GridInverseDistance import GridInverseDistance -from processing.algs.gdal.GridInverseDistanceNearestNeighbor import GridInverseDistanceNearestNeighbor +from processing.algs.gdal.GridInverseDistanceNearestNeighbor import ( + GridInverseDistanceNearestNeighbor, +) from processing.algs.gdal.GridLinear import GridLinear from processing.algs.gdal.GridNearestNeighbor import GridNearestNeighbor from processing.algs.gdal.gdal2tiles import gdal2tiles @@ -81,7 +83,7 @@ from processing.algs.gdal.pct2rgb import pct2rgb from processing.algs.gdal.rgb2pct import rgb2pct -testDataPath = os.path.join(os.path.dirname(__file__), 'testdata') +testDataPath = os.path.join(os.path.dirname(__file__), "testdata") class TestGdalRasterAlgorithms(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest): @@ -90,6 +92,7 @@ class TestGdalRasterAlgorithms(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest): def setUpClass(cls): start_app() from processing.core.Processing import Processing + Processing.initialize() cls.cleanup_paths = [] @@ -99,247 +102,383 @@ def tearDownClass(cls): shutil.rmtree(path) def definition_file(self): - return 'gdal_algorithm_raster_tests.yaml' + return "gdal_algorithm_raster_tests.yaml" @staticmethod def get_param_value_and_expected_string_for_custom_crs(proj_def): crs = QgsCoordinateReferenceSystem.fromProj(proj_def) - custom_crs = f'proj4: {proj_def}' - return custom_crs, crs.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED_GDAL).replace('"', '"""') + custom_crs = f"proj4: {proj_def}" + return custom_crs, crs.toWkt( + QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED_GDAL + ).replace('"', '"""') def testAssignProjection(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") alg = AssignProjection() alg.initAlgorithm() # with target srs self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'CRS': 'EPSG:3111'}, context, feedback), - ['gdal_edit.py', - '-a_srs EPSG:3111 ' + - source]) + alg.getConsoleCommands( + {"INPUT": source, "CRS": "EPSG:3111"}, context, feedback + ), + ["gdal_edit.py", "-a_srs EPSG:3111 " + source], + ) # with target using proj string - custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs' + custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'CRS': custom_crs}, context, feedback), - ['gdal_edit.py', - '-a_srs EPSG:20936 ' + - source]) + alg.getConsoleCommands( + {"INPUT": source, "CRS": custom_crs}, context, feedback + ), + ["gdal_edit.py", "-a_srs EPSG:20936 " + source], + ) # with target using custom projection - custom_crs, expected_crs_string = self.get_param_value_and_expected_string_for_custom_crs( - '+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs') + custom_crs, expected_crs_string = ( + self.get_param_value_and_expected_string_for_custom_crs( + "+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" + ) + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'CRS': custom_crs}, context, feedback), - ['gdal_edit.py', - f'-a_srs "{expected_crs_string}" ' + - source]) + alg.getConsoleCommands( + {"INPUT": source, "CRS": custom_crs}, context, feedback + ), + ["gdal_edit.py", f'-a_srs "{expected_crs_string}" ' + source], + ) # with non-EPSG crs code self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'CRS': 'POSTGIS:3111'}, context, feedback), - ['gdal_edit.py', - '-a_srs EPSG:3111 ' + - source]) + alg.getConsoleCommands( + {"INPUT": source, "CRS": "POSTGIS:3111"}, context, feedback + ), + ["gdal_edit.py", "-a_srs EPSG:3111 " + source], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'CRS': 'EPSG:3111'}, context, feedback), - ['gdal_edit.py', - '-a_srs EPSG:3111 ' + - source + ' -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y']) + alg.getConsoleCommands( + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "CRS": "EPSG:3111", + }, + context, + feedback, + ), + [ + "gdal_edit.py", + "-a_srs EPSG:3111 " + + source + + " -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'CRS': 'EPSG:3111'}, context, feedback), - ['gdal_edit.py', - '-a_srs EPSG:3111 ' + - source + ' --config X Y --config Z A']) - - @unittest.skipIf(os.environ.get('TRAVIS', '') == 'true', - 'gdal_edit.py: not found') + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "CRS": "EPSG:3111", + }, + context, + feedback, + ), + [ + "gdal_edit.py", + "-a_srs EPSG:3111 " + source + " --config X Y --config Z A", + ], + ) + + @unittest.skipIf(os.environ.get("TRAVIS", "") == "true", "gdal_edit.py: not found") def testRunAssignProjection(self): # Check that assign projection updates QgsRasterLayer info # GDAL Assign Projection is based on gdal_edit.py context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") alg = AssignProjection() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: - fake_dem = os.path.join(outdir, 'dem-fake-crs.tif') + fake_dem = os.path.join(outdir, "dem-fake-crs.tif") shutil.copy(source, fake_dem) self.assertTrue(os.path.exists(fake_dem)) rlayer = QgsRasterLayer(fake_dem, "Fake dem") self.assertTrue(rlayer.isValid()) - self.assertEqual(rlayer.crs().authid(), 'EPSG:4326') + self.assertEqual(rlayer.crs().authid(), "EPSG:4326") project = QgsProject() - project.setFileName(os.path.join(outdir, 'dem-fake-crs.qgs')) + project.setFileName(os.path.join(outdir, "dem-fake-crs.qgs")) project.addMapLayer(rlayer) self.assertEqual(project.count(), 1) context.setProject(project) - alg.run({'INPUT': fake_dem, 'CRS': 'EPSG:3111'}, - context, feedback) - self.assertEqual(rlayer.crs().authid(), 'EPSG:3111') + alg.run({"INPUT": fake_dem, "CRS": "EPSG:3111"}, context, feedback) + self.assertEqual(rlayer.crs().authid(), "EPSG:3111") def testGdalTranslate(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") translate_alg = translate() translate_alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: # without NODATA value self.assertEqual( - translate_alg.getConsoleCommands({'INPUT': source, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + translate_alg.getConsoleCommands( + {"INPUT": source, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + ["gdal_translate", "-of JPEG " + source + " " + outdir + "/check.jpg"], + ) # with None NODATA value self.assertEqual( - translate_alg.getConsoleCommands({'INPUT': source, - 'NODATA': None, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + translate_alg.getConsoleCommands( + {"INPUT": source, "NODATA": None, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + ["gdal_translate", "-of JPEG " + source + " " + outdir + "/check.jpg"], + ) # with NODATA value self.assertEqual( - translate_alg.getConsoleCommands({'INPUT': source, - 'NODATA': 9999, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-a_nodata 9999.0 ' + - '-of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + translate_alg.getConsoleCommands( + {"INPUT": source, "NODATA": 9999, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_translate", + "-a_nodata 9999.0 " + + "-of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with "0" NODATA value self.assertEqual( - translate_alg.getConsoleCommands({'INPUT': source, - 'NODATA': 0, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-a_nodata 0.0 ' + - '-of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + translate_alg.getConsoleCommands( + {"INPUT": source, "NODATA": 0, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_translate", + "-a_nodata 0.0 " + + "-of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with "0" NODATA value and custom data type self.assertEqual( - translate_alg.getConsoleCommands({'INPUT': source, - 'NODATA': 0, - 'DATA_TYPE': 6, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-a_nodata 0.0 ' + - '-ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + translate_alg.getConsoleCommands( + { + "INPUT": source, + "NODATA": 0, + "DATA_TYPE": 6, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_translate", + "-a_nodata 0.0 " + + "-ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with target srs self.assertEqual( - translate_alg.getConsoleCommands({'INPUT': source, - 'TARGET_CRS': 'EPSG:3111', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-a_srs EPSG:3111 ' + - '-of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + translate_alg.getConsoleCommands( + { + "INPUT": source, + "TARGET_CRS": "EPSG:3111", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_translate", + "-a_srs EPSG:3111 " + + "-of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with target using proj string - custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs' - self.assertEqual( - translate_alg.getConsoleCommands({'INPUT': source, - 'TARGET_CRS': custom_crs, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-a_srs EPSG:20936 ' + - '-of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" + self.assertEqual( + translate_alg.getConsoleCommands( + { + "INPUT": source, + "TARGET_CRS": custom_crs, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_translate", + "-a_srs EPSG:20936 " + + "-of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with target using custom projection - custom_crs, expected_crs_string = self.get_param_value_and_expected_string_for_custom_crs('+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs') - self.assertEqual( - translate_alg.getConsoleCommands({'INPUT': source, - 'TARGET_CRS': custom_crs, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - f'-a_srs "{expected_crs_string}" ' + - '-of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + custom_crs, expected_crs_string = ( + self.get_param_value_and_expected_string_for_custom_crs( + "+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" + ) + ) + self.assertEqual( + translate_alg.getConsoleCommands( + { + "INPUT": source, + "TARGET_CRS": custom_crs, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_translate", + f'-a_srs "{expected_crs_string}" ' + + "-of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with non-EPSG crs code self.assertEqual( - translate_alg.getConsoleCommands({'INPUT': source, - 'TARGET_CRS': 'POSTGIS:3111', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-a_srs EPSG:3111 ' + - '-of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + translate_alg.getConsoleCommands( + { + "INPUT": source, + "TARGET_CRS": "POSTGIS:3111", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_translate", + "-a_srs EPSG:3111 " + + "-of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with copy subdatasets self.assertEqual( - translate_alg.getConsoleCommands({'INPUT': source, - 'COPY_SUBDATASETS': True, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdal_translate', - '-sds ' + - '-of GTiff ' + - source + ' ' + - outdir + '/check.tif']) + translate_alg.getConsoleCommands( + { + "INPUT": source, + "COPY_SUBDATASETS": True, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdal_translate", + "-sds " + "-of GTiff " + source + " " + outdir + "/check.tif", + ], + ) # additional parameters self.assertEqual( - translate_alg.getConsoleCommands({'INPUT': source, - 'EXTRA': '-strict -unscale -epo', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-of JPEG -strict -unscale -epo ' + - source + ' ' + - outdir + '/check.jpg']) - - self.assertEqual( - translate_alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-of JPEG ' + - source + ' ' + - outdir + '/check.jpg -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y']) - - self.assertEqual( - translate_alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-of JPEG ' + - source + ' ' + - outdir + '/check.jpg --config X Y --config Z A']) + translate_alg.getConsoleCommands( + { + "INPUT": source, + "EXTRA": "-strict -unscale -epo", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_translate", + "-of JPEG -strict -unscale -epo " + + source + + " " + + outdir + + "/check.jpg", + ], + ) + + self.assertEqual( + translate_alg.getConsoleCommands( + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_translate", + "-of JPEG " + + source + + " " + + outdir + + "/check.jpg -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y", + ], + ) + + self.assertEqual( + translate_alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_translate", + "-of JPEG " + + source + + " " + + outdir + + "/check.jpg --config X Y --config Z A", + ], + ) def testClipRasterByExtent(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") alg = ClipRasterByExtent() alg.initAlgorithm() extent = QgsRectangle(1, 2, 3, 4) @@ -347,1809 +486,3273 @@ def testClipRasterByExtent(self): with tempfile.TemporaryDirectory() as outdir: # with no NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'EXTENT': extent, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "EXTENT": extent, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + ["gdal_translate", "-of JPEG " + source + " " + outdir + "/check.jpg"], + ) # with NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'EXTENT': extent, - 'NODATA': 9999, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-a_nodata 9999.0 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "EXTENT": extent, + "NODATA": 9999, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_translate", + "-a_nodata 9999.0 -of JPEG " + source + " " + outdir + "/check.jpg", + ], + ) # with "0" NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'EXTENT': extent, - 'NODATA': 0, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-a_nodata 0.0 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "EXTENT": extent, + "NODATA": 0, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_translate", + "-a_nodata 0.0 -of JPEG " + source + " " + outdir + "/check.jpg", + ], + ) # with "0" NODATA value and custom data type self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'EXTENT': extent, - 'NODATA': 0, - 'DATA_TYPE': 6, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-a_nodata 0.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "EXTENT": extent, + "NODATA": 0, + "DATA_TYPE": 6, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_translate", + "-a_nodata 0.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with creation options self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'EXTENT': extent, - 'OPTIONS': 'COMPRESS=DEFLATE|PREDICTOR=2|ZLEVEL=9', - 'DATA_TYPE': 0, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-of JPEG -co COMPRESS=DEFLATE -co PREDICTOR=2 -co ZLEVEL=9 ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "EXTENT": extent, + "OPTIONS": "COMPRESS=DEFLATE|PREDICTOR=2|ZLEVEL=9", + "DATA_TYPE": 0, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_translate", + "-of JPEG -co COMPRESS=DEFLATE -co PREDICTOR=2 -co ZLEVEL=9 " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with additional parameters self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'EXTENT': extent, - 'EXTRA': '-s_srs EPSG:4326 -tps -tr 0.1 0.1', - 'DATA_TYPE': 0, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-of JPEG -s_srs EPSG:4326 -tps -tr 0.1 0.1 ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "EXTENT": extent, + "EXTRA": "-s_srs EPSG:4326 -tps -tr 0.1 0.1", + "DATA_TYPE": 0, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_translate", + "-of JPEG -s_srs EPSG:4326 -tps -tr 0.1 0.1 " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # override CRS self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'EXTENT': extent, - 'OVERCRS': True, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-a_srs EPSG:4326 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'EXTENT': extent, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-of JPEG ' + - source + ' ' + - outdir + '/check.jpg -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'EXTENT': extent, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_translate', - '-of JPEG ' + - source + ' ' + - outdir + '/check.jpg --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source, + "EXTENT": extent, + "OVERCRS": True, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_translate", + "-a_srs EPSG:4326 -of JPEG " + source + " " + outdir + "/check.jpg", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "EXTENT": extent, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_translate", + "-of JPEG " + + source + + " " + + outdir + + "/check.jpg -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "EXTENT": extent, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_translate", + "-of JPEG " + + source + + " " + + outdir + + "/check.jpg --config X Y --config Z A", + ], + ) def testClipRasterByMask(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') - mask = os.path.join(testDataPath, 'polys.gml') - extent = QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('EPSG:4236')) + source = os.path.join(testDataPath, "dem.tif") + mask = os.path.join(testDataPath, "polys.gml") + extent = QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:4236") + ) alg = ClipRasterByMask() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: # with no NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'MASK': mask, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -of JPEG -cutline ' + - mask + ' -cl polys2 -crop_to_cutline ' + source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "MASK": mask, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -of JPEG -cutline " + + mask + + " -cl polys2 -crop_to_cutline " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'MASK': mask, - 'NODATA': 9999, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -of JPEG -cutline ' + - mask + ' -cl polys2 -crop_to_cutline -dstnodata 9999.0 ' + source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "MASK": mask, + "NODATA": 9999, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -of JPEG -cutline " + + mask + + " -cl polys2 -crop_to_cutline -dstnodata 9999.0 " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with "0" NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'MASK': mask, - 'NODATA': 0, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -of JPEG -cutline ' + - mask + ' -cl polys2 -crop_to_cutline -dstnodata 0.0 ' + source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "MASK": mask, + "NODATA": 0, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -of JPEG -cutline " + + mask + + " -cl polys2 -crop_to_cutline -dstnodata 0.0 " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with "0" NODATA value and custom data type self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'MASK': mask, - 'NODATA': 0, - 'DATA_TYPE': 6, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -ot Float32 -of JPEG -cutline ' + - mask + ' -cl polys2 -crop_to_cutline -dstnodata 0.0 ' + source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "MASK": mask, + "NODATA": 0, + "DATA_TYPE": 6, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -ot Float32 -of JPEG -cutline " + + mask + + " -cl polys2 -crop_to_cutline -dstnodata 0.0 " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with creation options self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'MASK': mask, - 'OPTIONS': 'COMPRESS=DEFLATE|PREDICTOR=2|ZLEVEL=9', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -of JPEG -cutline ' + - mask + ' -cl polys2 -crop_to_cutline -co COMPRESS=DEFLATE -co PREDICTOR=2 -co ZLEVEL=9 ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "MASK": mask, + "OPTIONS": "COMPRESS=DEFLATE|PREDICTOR=2|ZLEVEL=9", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -of JPEG -cutline " + + mask + + " -cl polys2 -crop_to_cutline -co COMPRESS=DEFLATE -co PREDICTOR=2 -co ZLEVEL=9 " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with multothreading and additional parameters self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'MASK': mask, - 'MULTITHREADING': True, - 'EXTRA': '-nosrcalpha -wm 2048 -nomd', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -of JPEG -cutline ' + - mask + ' -cl polys2 -crop_to_cutline -multi -nosrcalpha -wm 2048 -nomd ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "MASK": mask, + "MULTITHREADING": True, + "EXTRA": "-nosrcalpha -wm 2048 -nomd", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -of JPEG -cutline " + + mask + + " -cl polys2 -crop_to_cutline -multi -nosrcalpha -wm 2048 -nomd " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with target extent value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'MASK': mask, - 'TARGET_EXTENT': extent, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -te 1.0 2.0 3.0 4.0 -te_srs EPSG:4236 -of JPEG -cutline ' + - mask + ' -cl polys2 -crop_to_cutline ' + source + ' ' + - outdir + '/check.jpg']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'MASK': mask, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -of JPEG -cutline ' + - mask + ' -cl polys2 -crop_to_cutline ' + source + ' ' + - outdir + '/check.jpg -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'MASK': mask, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -of JPEG -cutline ' + - mask + ' -cl polys2 -crop_to_cutline ' + source + ' ' + - outdir + '/check.jpg --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source, + "MASK": mask, + "TARGET_EXTENT": extent, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -te 1.0 2.0 3.0 4.0 -te_srs EPSG:4236 -of JPEG -cutline " + + mask + + " -cl polys2 -crop_to_cutline " + + source + + " " + + outdir + + "/check.jpg", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "MASK": mask, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -of JPEG -cutline " + + mask + + " -cl polys2 -crop_to_cutline " + + source + + " " + + outdir + + "/check.jpg -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "MASK": mask, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -of JPEG -cutline " + + mask + + " -cl polys2 -crop_to_cutline " + + source + + " " + + outdir + + "/check.jpg --config X Y --config Z A", + ], + ) def testContourPolygon(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") alg = contour_polygon() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'FIELD_NAME_MIN': 'min', - 'FIELD_NAME_MAX': 'max', - 'INTERVAL': 5, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['gdal_contour', - '-p -amax max -amin min -b 1 -i 5.0 -f "ESRI Shapefile" ' + - source + ' ' + - outdir + '/check.shp']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "FIELD_NAME_MIN": "min", + "FIELD_NAME_MAX": "max", + "INTERVAL": 5, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "gdal_contour", + '-p -amax max -amin min -b 1 -i 5.0 -f "ESRI Shapefile" ' + + source + + " " + + outdir + + "/check.shp", + ], + ) def testContour(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") alg = contour() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: # with no NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'FIELD_NAME': 'elev', - 'INTERVAL': 5, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['gdal_contour', - '-b 1 -a elev -i 5.0 -f "ESRI Shapefile" ' + - source + ' ' + - outdir + '/check.shp']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "FIELD_NAME": "elev", + "INTERVAL": 5, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "gdal_contour", + '-b 1 -a elev -i 5.0 -f "ESRI Shapefile" ' + + source + + " " + + outdir + + "/check.shp", + ], + ) # with NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'FIELD_NAME': 'elev', - 'INTERVAL': 5, - 'NODATA': 9999, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['gdal_contour', - '-b 1 -a elev -i 5.0 -snodata 9999.0 -f "ESRI Shapefile" ' + - source + ' ' + - outdir + '/check.shp']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "FIELD_NAME": "elev", + "INTERVAL": 5, + "NODATA": 9999, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "gdal_contour", + '-b 1 -a elev -i 5.0 -snodata 9999.0 -f "ESRI Shapefile" ' + + source + + " " + + outdir + + "/check.shp", + ], + ) # with "0" NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'FIELD_NAME': 'elev', - 'INTERVAL': 5, - 'NODATA': 0, - 'OUTPUT': outdir + '/check.gpkg'}, context, feedback), - ['gdal_contour', - '-b 1 -a elev -i 5.0 -snodata 0.0 -f "GPKG" ' + - source + ' ' + - outdir + '/check.gpkg']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "FIELD_NAME": "elev", + "INTERVAL": 5, + "NODATA": 0, + "OUTPUT": outdir + "/check.gpkg", + }, + context, + feedback, + ), + [ + "gdal_contour", + '-b 1 -a elev -i 5.0 -snodata 0.0 -f "GPKG" ' + + source + + " " + + outdir + + "/check.gpkg", + ], + ) # with CREATE_3D self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'CREATE_3D': True, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['gdal_contour', - '-b 1 -a ELEV -i 10.0 -3d -f "ESRI Shapefile" ' + - source + ' ' + - outdir + '/check.shp']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "CREATE_3D": True, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "gdal_contour", + '-b 1 -a ELEV -i 10.0 -3d -f "ESRI Shapefile" ' + + source + + " " + + outdir + + "/check.shp", + ], + ) # with IGNORE_NODATA and OFFSET self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'IGNORE_NODATA': True, - 'OFFSET': 100, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['gdal_contour', - '-b 1 -a ELEV -i 10.0 -inodata -off 100.0 -f "ESRI Shapefile" ' + - source + ' ' + - outdir + '/check.shp']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "IGNORE_NODATA": True, + "OFFSET": 100, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "gdal_contour", + '-b 1 -a ELEV -i 10.0 -inodata -off 100.0 -f "ESRI Shapefile" ' + + source + + " " + + outdir + + "/check.shp", + ], + ) # with additional command line parameters self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'EXTRA': '-e 3 -amin MIN_H', - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['gdal_contour', - '-b 1 -a ELEV -i 10.0 -f "ESRI Shapefile" -e 3 -amin MIN_H ' + - source + ' ' + - outdir + '/check.shp']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "EXTRA": "-e 3 -amin MIN_H", + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "gdal_contour", + '-b 1 -a ELEV -i 10.0 -f "ESRI Shapefile" -e 3 -amin MIN_H ' + + source + + " " + + outdir + + "/check.shp", + ], + ) # obsolete OPTIONS param self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'OPTIONS': '-fl 100 125 150 200', - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['gdal_contour', - '-b 1 -a ELEV -i 10.0 -f "ESRI Shapefile" -fl 100 125 150 200 ' + - source + ' ' + - outdir + '/check.shp']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'BAND': 1, - 'FIELD_NAME': 'elev', - 'INTERVAL': 5, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['gdal_contour', - '-b 1 -a elev -i 5.0 -f "ESRI Shapefile" --config X Y --config Z A ' + - source + ' ' + - outdir + '/check.shp']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "OPTIONS": "-fl 100 125 150 200", + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "gdal_contour", + '-b 1 -a ELEV -i 10.0 -f "ESRI Shapefile" -fl 100 125 150 200 ' + + source + + " " + + outdir + + "/check.shp", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "BAND": 1, + "FIELD_NAME": "elev", + "INTERVAL": 5, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "gdal_contour", + '-b 1 -a elev -i 5.0 -f "ESRI Shapefile" --config X Y --config Z A ' + + source + + " " + + outdir + + "/check.shp", + ], + ) def testGdal2Tiles(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") alg = gdal2tiles() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: # with no NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OUTPUT': outdir + '/'}, context, feedback), - ['gdal2tiles.py', - '-p mercator -w all -r average ' + - source + ' ' + - outdir + '/']) + alg.getConsoleCommands( + {"INPUT": source, "OUTPUT": outdir + "/"}, context, feedback + ), + [ + "gdal2tiles.py", + "-p mercator -w all -r average " + source + " " + outdir + "/", + ], + ) # with NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': -9999, - 'OUTPUT': outdir + '/'}, context, feedback), - ['gdal2tiles.py', - '-p mercator -w all -r average -a -9999.0 ' + - source + ' ' + - outdir + '/']) + alg.getConsoleCommands( + {"INPUT": source, "NODATA": -9999, "OUTPUT": outdir + "/"}, + context, + feedback, + ), + [ + "gdal2tiles.py", + "-p mercator -w all -r average -a -9999.0 " + + source + + " " + + outdir + + "/", + ], + ) # with "0" NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 0, - 'OUTPUT': outdir + '/'}, context, feedback), - ['gdal2tiles.py', - '-p mercator -w all -r average -a 0.0 ' + - source + ' ' + - outdir + '/']) + alg.getConsoleCommands( + {"INPUT": source, "NODATA": 0, "OUTPUT": outdir + "/"}, + context, + feedback, + ), + [ + "gdal2tiles.py", + "-p mercator -w all -r average -a 0.0 " + + source + + " " + + outdir + + "/", + ], + ) # with input srs self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SOURCE_CRS': 'EPSG:3111', - 'OUTPUT': outdir + '/'}, context, feedback), - ['gdal2tiles.py', - '-p mercator -w all -r average -s EPSG:3111 ' + - source + ' ' + - outdir + '/']) + alg.getConsoleCommands( + { + "INPUT": source, + "SOURCE_CRS": "EPSG:3111", + "OUTPUT": outdir + "/", + }, + context, + feedback, + ), + [ + "gdal2tiles.py", + "-p mercator -w all -r average -s EPSG:3111 " + + source + + " " + + outdir + + "/", + ], + ) # with target using proj string - custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs' - self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SOURCE_CRS': custom_crs, - 'OUTPUT': outdir + '/'}, context, feedback), - ['gdal2tiles.py', - '-p mercator -w all -r average -s EPSG:20936 ' + - source + ' ' + - outdir + '/']) + custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" + self.assertEqual( + alg.getConsoleCommands( + {"INPUT": source, "SOURCE_CRS": custom_crs, "OUTPUT": outdir + "/"}, + context, + feedback, + ), + [ + "gdal2tiles.py", + "-p mercator -w all -r average -s EPSG:20936 " + + source + + " " + + outdir + + "/", + ], + ) # with target using custom projection - custom_crs, expected_crs_string = self.get_param_value_and_expected_string_for_custom_crs('+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs') - self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SOURCE_CRS': custom_crs, - 'OUTPUT': outdir + '/'}, context, feedback), - ['gdal2tiles.py', - f'-p mercator -w all -r average -s "{expected_crs_string}" ' + - source + ' ' + - outdir + '/']) + custom_crs, expected_crs_string = ( + self.get_param_value_and_expected_string_for_custom_crs( + "+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" + ) + ) + self.assertEqual( + alg.getConsoleCommands( + {"INPUT": source, "SOURCE_CRS": custom_crs, "OUTPUT": outdir + "/"}, + context, + feedback, + ), + [ + "gdal2tiles.py", + f'-p mercator -w all -r average -s "{expected_crs_string}" ' + + source + + " " + + outdir + + "/", + ], + ) # with non-EPSG crs code self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SOURCE_CRS': 'POSTGIS:3111', - 'OUTPUT': outdir + '/'}, context, feedback), - ['gdal2tiles.py', - '-p mercator -w all -r average -s EPSG:3111 ' + - source + ' ' + - outdir + '/']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'OUTPUT': outdir + '/'}, context, feedback), - ['gdal2tiles.py', - '-p mercator -w all -r average ' + - source + ' ' + - outdir + '/ --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source, + "SOURCE_CRS": "POSTGIS:3111", + "OUTPUT": outdir + "/", + }, + context, + feedback, + ), + [ + "gdal2tiles.py", + "-p mercator -w all -r average -s EPSG:3111 " + + source + + " " + + outdir + + "/", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "OUTPUT": outdir + "/", + }, + context, + feedback, + ), + [ + "gdal2tiles.py", + "-p mercator -w all -r average " + + source + + " " + + outdir + + "/ --config X Y --config Z A", + ], + ) def testGdalCalc(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') - source2 = os.path.join(testDataPath, 'raster.tif') - source3 = os.path.join(testDataPath, 'raster with spaces.tif') + source = os.path.join(testDataPath, "dem.tif") + source2 = os.path.join(testDataPath, "raster.tif") + source3 = os.path.join(testDataPath, "raster with spaces.tif") alg = gdalcalc() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: - output = outdir + '/check.jpg' + output = outdir + "/check.jpg" # default execution - formula = 'A*2' # default formula - self.assertEqual( - alg.getConsoleCommands({'INPUT_A': source, - 'BAND_A': 1, - 'FORMULA': formula, - 'OUTPUT': output}, context, feedback), - ['gdal_calc.py', - f'--overwrite --calc "{formula}" --format JPEG --type Float32 -A {source} --A_band 1 --outfile {output}']) + formula = "A*2" # default formula + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT_A": source, + "BAND_A": 1, + "FORMULA": formula, + "OUTPUT": output, + }, + context, + feedback, + ), + [ + "gdal_calc.py", + f'--overwrite --calc "{formula}" --format JPEG --type Float32 -A {source} --A_band 1 --outfile {output}', + ], + ) if GdalUtils.version() >= 3030000: - extent = QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('EPSG:4326')) + extent = QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:4326") + ) self.assertEqual( - alg.getConsoleCommands({'INPUT_A': source, - 'BAND_A': 1, - 'FORMULA': formula, - 'PROJWIN': extent, - 'OUTPUT': output}, context, feedback), - ['gdal_calc.py', - f'--overwrite --calc "{formula}" --format JPEG --type Float32 --projwin 1.0 4.0 3.0 2.0 -A {source} --A_band 1 --outfile {output}']) + alg.getConsoleCommands( + { + "INPUT_A": source, + "BAND_A": 1, + "FORMULA": formula, + "PROJWIN": extent, + "OUTPUT": output, + }, + context, + feedback, + ), + [ + "gdal_calc.py", + f'--overwrite --calc "{formula}" --format JPEG --type Float32 --projwin 1.0 4.0 3.0 2.0 -A {source} --A_band 1 --outfile {output}', + ], + ) # Inputs A and B share same pixel size and CRS self.assertEqual( - alg.getConsoleCommands({'INPUT_A': source2, - 'BAND_A': 1, - 'INPUT_B': source3, - 'BAND_B': 1, - 'FORMULA': formula, - 'EXTENT_OPT': 3, - 'OUTPUT': output}, context, feedback), - ['gdal_calc.py', - f'--overwrite --calc "{formula}" --format JPEG --type Float32 --extent=intersect -A {source2} --A_band 1 -B "{source3}" --B_band 1 --outfile {output}']) + alg.getConsoleCommands( + { + "INPUT_A": source2, + "BAND_A": 1, + "INPUT_B": source3, + "BAND_B": 1, + "FORMULA": formula, + "EXTENT_OPT": 3, + "OUTPUT": output, + }, + context, + feedback, + ), + [ + "gdal_calc.py", + f'--overwrite --calc "{formula}" --format JPEG --type Float32 --extent=intersect -A {source2} --A_band 1 -B "{source3}" --B_band 1 --outfile {output}', + ], + ) # Test mutually exclusive --extent and --projwin. Should raise an exception self.assertRaises( QgsProcessingException, - lambda: alg.getConsoleCommands({'INPUT_A': source, - 'BAND_A': 1, - 'FORMULA': formula, - 'PROJWIN': extent, - 'EXTENT_OPT': 3, - 'OUTPUT': output}, context, feedback)) + lambda: alg.getConsoleCommands( + { + "INPUT_A": source, + "BAND_A": 1, + "FORMULA": formula, + "PROJWIN": extent, + "EXTENT_OPT": 3, + "OUTPUT": output, + }, + context, + feedback, + ), + ) # Inputs A and B do not share same pixel size and CRS. Should raise an exception - source2 = os.path.join(testDataPath, 'raster.tif') + source2 = os.path.join(testDataPath, "raster.tif") self.assertRaises( QgsProcessingException, - lambda: alg.getConsoleCommands({'INPUT_A': source, - 'BAND_A': 1, - 'INPUT_B': source2, - 'BAND_B': 1, - 'FORMULA': formula, - 'EXTENT_OPT': 3, - 'OUTPUT': output}, context, feedback)) + lambda: alg.getConsoleCommands( + { + "INPUT_A": source, + "BAND_A": 1, + "INPUT_B": source2, + "BAND_B": 1, + "FORMULA": formula, + "EXTENT_OPT": 3, + "OUTPUT": output, + }, + context, + feedback, + ), + ) # check that formula is not escaped and formula is returned as it is - formula = 'A * 2' # <--- add spaces in the formula - self.assertEqual( - alg.getConsoleCommands({'INPUT_A': source, - 'BAND_A': 1, - 'FORMULA': formula, - 'OUTPUT': output}, context, feedback), - ['gdal_calc.py', - f'--overwrite --calc "{formula}" --format JPEG --type Float32 -A {source} --A_band 1 --outfile {output}']) + formula = "A * 2" # <--- add spaces in the formula + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT_A": source, + "BAND_A": 1, + "FORMULA": formula, + "OUTPUT": output, + }, + context, + feedback, + ), + [ + "gdal_calc.py", + f'--overwrite --calc "{formula}" --format JPEG --type Float32 -A {source} --A_band 1 --outfile {output}', + ], + ) # additional creation options - formula = 'A*2' - self.assertEqual( - alg.getConsoleCommands({'INPUT_A': source, - 'BAND_A': 1, - 'FORMULA': formula, - 'OPTIONS': 'COMPRESS=JPEG|JPEG_QUALITY=75', - 'OUTPUT': output}, context, feedback), - ['gdal_calc.py', - f'--overwrite --calc "{formula}" --format JPEG --type Float32 -A {source} --A_band 1 --co COMPRESS=JPEG --co JPEG_QUALITY=75 --outfile {output}']) + formula = "A*2" + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT_A": source, + "BAND_A": 1, + "FORMULA": formula, + "OPTIONS": "COMPRESS=JPEG|JPEG_QUALITY=75", + "OUTPUT": output, + }, + context, + feedback, + ), + [ + "gdal_calc.py", + f'--overwrite --calc "{formula}" --format JPEG --type Float32 -A {source} --A_band 1 --co COMPRESS=JPEG --co JPEG_QUALITY=75 --outfile {output}', + ], + ) # additional parameters - formula = 'A*2' - self.assertEqual( - alg.getConsoleCommands({'INPUT_A': source, - 'BAND_A': 1, - 'FORMULA': formula, - 'EXTRA': '--debug --quiet', - 'OUTPUT': output}, context, feedback), - ['gdal_calc.py', - f'--overwrite --calc "{formula}" --format JPEG --type Float32 -A {source} --A_band 1 --debug --quiet --outfile {output}']) + formula = "A*2" + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT_A": source, + "BAND_A": 1, + "FORMULA": formula, + "EXTRA": "--debug --quiet", + "OUTPUT": output, + }, + context, + feedback, + ), + [ + "gdal_calc.py", + f'--overwrite --calc "{formula}" --format JPEG --type Float32 -A {source} --A_band 1 --debug --quiet --outfile {output}', + ], + ) def testGdalInfo(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") alg = gdalinfo() alg.initAlgorithm() self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'MIN_MAX': False, - 'NOGCP': False, - 'NO_METADATA': False, - 'STATS': False}, context, feedback), - ['gdalinfo', - source]) - - source = os.path.join(testDataPath, 'raster with spaces.tif') + alg.getConsoleCommands( + { + "INPUT": source, + "MIN_MAX": False, + "NOGCP": False, + "NO_METADATA": False, + "STATS": False, + }, + context, + feedback, + ), + ["gdalinfo", source], + ) + + source = os.path.join(testDataPath, "raster with spaces.tif") self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'MIN_MAX': False, - 'NOGCP': False, - 'NO_METADATA': False, - 'STATS': False}, context, feedback), - ['gdalinfo', - '"' + source + '"']) + alg.getConsoleCommands( + { + "INPUT": source, + "MIN_MAX": False, + "NOGCP": False, + "NO_METADATA": False, + "STATS": False, + }, + context, + feedback, + ), + ["gdalinfo", '"' + source + '"'], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'MIN_MAX': True, - 'NOGCP': False, - 'NO_METADATA': False, - 'STATS': False}, context, feedback), - ['gdalinfo', - '-mm "' + source + '"']) + alg.getConsoleCommands( + { + "INPUT": source, + "MIN_MAX": True, + "NOGCP": False, + "NO_METADATA": False, + "STATS": False, + }, + context, + feedback, + ), + ["gdalinfo", '-mm "' + source + '"'], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'MIN_MAX': False, - 'NOGCP': True, - 'NO_METADATA': False, - 'STATS': False}, context, feedback), - ['gdalinfo', - '-nogcp "' + source + '"']) + alg.getConsoleCommands( + { + "INPUT": source, + "MIN_MAX": False, + "NOGCP": True, + "NO_METADATA": False, + "STATS": False, + }, + context, + feedback, + ), + ["gdalinfo", '-nogcp "' + source + '"'], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'MIN_MAX': False, - 'NOGCP': False, - 'NO_METADATA': True, - 'STATS': False}, context, feedback), - ['gdalinfo', - '-nomd "' + source + '"']) + alg.getConsoleCommands( + { + "INPUT": source, + "MIN_MAX": False, + "NOGCP": False, + "NO_METADATA": True, + "STATS": False, + }, + context, + feedback, + ), + ["gdalinfo", '-nomd "' + source + '"'], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'MIN_MAX': False, - 'NOGCP': False, - 'NO_METADATA': False, - 'STATS': True}, context, feedback), - ['gdalinfo', - '-stats "' + source + '"']) + alg.getConsoleCommands( + { + "INPUT": source, + "MIN_MAX": False, + "NOGCP": False, + "NO_METADATA": False, + "STATS": True, + }, + context, + feedback, + ), + ["gdalinfo", '-stats "' + source + '"'], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'MIN_MAX': False, - 'NOGCP': False, - 'NO_METADATA': False, - 'STATS': False, - 'EXTRA': '-proj4 -listmdd -checksum'}, context, feedback), - ['gdalinfo', - '-proj4 -listmdd -checksum "' + source + '"']) + alg.getConsoleCommands( + { + "INPUT": source, + "MIN_MAX": False, + "NOGCP": False, + "NO_METADATA": False, + "STATS": False, + "EXTRA": "-proj4 -listmdd -checksum", + }, + context, + feedback, + ), + ["gdalinfo", '-proj4 -listmdd -checksum "' + source + '"'], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'MIN_MAX': False, - 'NOGCP': False, - 'NO_METADATA': False, - 'STATS': False}, context, feedback), - ['gdalinfo', - '"' + source + '" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y']) + alg.getConsoleCommands( + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "MIN_MAX": False, + "NOGCP": False, + "NO_METADATA": False, + "STATS": False, + }, + context, + feedback, + ), + [ + "gdalinfo", + '"' + + source + + '" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'MIN_MAX': False, - 'NOGCP': False, - 'NO_METADATA': False, - 'STATS': False}, context, feedback), - ['gdalinfo', - '"' + source + '" --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "MIN_MAX": False, + "NOGCP": False, + "NO_METADATA": False, + "STATS": False, + }, + context, + feedback, + ), + ["gdalinfo", '"' + source + '" --config X Y --config Z A'], + ) def testGdalTindex(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") alg = gdaltindex() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: - commands = alg.getConsoleCommands({'LAYERS': [source], - 'OUTPUT': outdir + '/test.shp'}, context, feedback) + commands = alg.getConsoleCommands( + {"LAYERS": [source], "OUTPUT": outdir + "/test.shp"}, context, feedback + ) self.assertEqual(len(commands), 2) - self.assertEqual(commands[0], 'gdaltindex') - self.assertIn('-tileindex location -f "ESRI Shapefile" ' + outdir + '/test.shp', commands[1]) - self.assertIn('--optfile ', commands[1]) + self.assertEqual(commands[0], "gdaltindex") + self.assertIn( + '-tileindex location -f "ESRI Shapefile" ' + outdir + "/test.shp", + commands[1], + ) + self.assertIn("--optfile ", commands[1]) # with input srs - commands = alg.getConsoleCommands({'LAYERS': [source], - 'TARGET_CRS': 'EPSG:3111', - 'OUTPUT': outdir + '/test.shp'}, context, feedback) + commands = alg.getConsoleCommands( + { + "LAYERS": [source], + "TARGET_CRS": "EPSG:3111", + "OUTPUT": outdir + "/test.shp", + }, + context, + feedback, + ) self.assertEqual(len(commands), 2) - self.assertEqual(commands[0], 'gdaltindex') - self.assertIn('-tileindex location -t_srs EPSG:3111 -f "ESRI Shapefile" ' + outdir + '/test.shp', commands[1]) - self.assertIn('--optfile ', commands[1]) + self.assertEqual(commands[0], "gdaltindex") + self.assertIn( + '-tileindex location -t_srs EPSG:3111 -f "ESRI Shapefile" ' + + outdir + + "/test.shp", + commands[1], + ) + self.assertIn("--optfile ", commands[1]) # with target using proj string - custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs' - commands = alg.getConsoleCommands({'LAYERS': [source], - 'TARGET_CRS': custom_crs, - 'OUTPUT': outdir + '/test.shp'}, context, feedback) + custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" + commands = alg.getConsoleCommands( + { + "LAYERS": [source], + "TARGET_CRS": custom_crs, + "OUTPUT": outdir + "/test.shp", + }, + context, + feedback, + ) self.assertEqual(len(commands), 2) - self.assertEqual(commands[0], 'gdaltindex') - self.assertIn('-tileindex location -t_srs EPSG:20936 -f "ESRI Shapefile" ' + outdir + '/test.shp', commands[1]) - self.assertIn('--optfile ', commands[1]) + self.assertEqual(commands[0], "gdaltindex") + self.assertIn( + '-tileindex location -t_srs EPSG:20936 -f "ESRI Shapefile" ' + + outdir + + "/test.shp", + commands[1], + ) + self.assertIn("--optfile ", commands[1]) # with target using custom projection - custom_crs, expected_crs_string = self.get_param_value_and_expected_string_for_custom_crs('+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs') - commands = alg.getConsoleCommands({'LAYERS': [source], - 'TARGET_CRS': custom_crs, - 'OUTPUT': outdir + '/test.shp'}, context, feedback) + custom_crs, expected_crs_string = ( + self.get_param_value_and_expected_string_for_custom_crs( + "+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" + ) + ) + commands = alg.getConsoleCommands( + { + "LAYERS": [source], + "TARGET_CRS": custom_crs, + "OUTPUT": outdir + "/test.shp", + }, + context, + feedback, + ) self.assertEqual(len(commands), 2) - self.assertEqual(commands[0], 'gdaltindex') - self.assertIn(f'-tileindex location -t_srs "{expected_crs_string}" -f "ESRI Shapefile" ' + outdir + '/test.shp', commands[1]) - self.assertIn('--optfile ', commands[1]) + self.assertEqual(commands[0], "gdaltindex") + self.assertIn( + f'-tileindex location -t_srs "{expected_crs_string}" -f "ESRI Shapefile" ' + + outdir + + "/test.shp", + commands[1], + ) + self.assertIn("--optfile ", commands[1]) # with non-EPSG crs code - commands = alg.getConsoleCommands({'LAYERS': [source], - 'TARGET_CRS': 'POSTGIS:3111', - 'OUTPUT': outdir + '/test.shp'}, context, feedback) + commands = alg.getConsoleCommands( + { + "LAYERS": [source], + "TARGET_CRS": "POSTGIS:3111", + "OUTPUT": outdir + "/test.shp", + }, + context, + feedback, + ) self.assertEqual(len(commands), 2) - self.assertEqual(commands[0], 'gdaltindex') + self.assertEqual(commands[0], "gdaltindex") self.assertIn( - '-tileindex location -t_srs EPSG:3111 -f "ESRI Shapefile" ' + outdir + '/test.shp', - commands[1]) - self.assertIn('--optfile ', commands[1]) + '-tileindex location -t_srs EPSG:3111 -f "ESRI Shapefile" ' + + outdir + + "/test.shp", + commands[1], + ) + self.assertIn("--optfile ", commands[1]) def testGridAverage(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'points.gml') + source = os.path.join(testDataPath, "points.gml") alg = GridAverage() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: # with no NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 9999, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=9999.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "NODATA": 9999, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=9999.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with "0" NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 0, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "NODATA": 0, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with additional parameters self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG -z_multiply 1.5 -outsize 1754 1394 ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "EXTRA": "-z_multiply 1.5 -outsize 1754 1394", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG -z_multiply 1.5 -outsize 1754 1394 " + + source + + " " + + outdir + + "/check.jpg", + ], + ) if GdalUtils.version() >= 3070000: self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -z_multiply 1.5 -outsize 1754 1394 ' + - source + ' ' + - outdir + '/check.jpg']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG -z_multiply 1.5 -outsize 1754 1394 ' + - source + ' ' + - outdir + '/check.jpg --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "EXTRA": "-z_multiply 1.5 -outsize 1754 1394", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -z_multiply 1.5 -outsize 1754 1394 " + + source + + " " + + outdir + + "/check.jpg", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "EXTRA": "-z_multiply 1.5 -outsize 1754 1394", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a average:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG -z_multiply 1.5 -outsize 1754 1394 " + + source + + " " + + outdir + + "/check.jpg --config X Y --config Z A", + ], + ) def testGridDataMetrics(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'points.gml') + source = os.path.join(testDataPath, "points.gml") alg = GridDataMetrics() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: # without NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 9999, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=9999.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "NODATA": 9999, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=9999.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with "0" NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 0, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "NODATA": 0, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # non-default datametrics self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'METRIC': 4, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a average_distance:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "METRIC": 4, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a average_distance:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # additional parameters self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdal_grid', - '-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 ' + - '-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 ' + - source + ' ' + - outdir + '/check.tif']) + alg.getConsoleCommands( + { + "INPUT": source, + "EXTRA": "-z_multiply 1.5 -outsize 1754 1394", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 " + + "-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 " + + source + + " " + + outdir + + "/check.tif", + ], + ) if GdalUtils.version() >= 3070000: self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdal_grid', - '-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 ' + - '-ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -z_multiply 1.5 -outsize 1754 1394 ' + - source + ' ' + - outdir + '/check.tif']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdal_grid', - '-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 ' + - '-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 ' + - source + ' ' + - outdir + '/check.tif --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "EXTRA": "-z_multiply 1.5 -outsize 1754 1394", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 " + + "-ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -z_multiply 1.5 -outsize 1754 1394 " + + source + + " " + + outdir + + "/check.tif", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "EXTRA": "-z_multiply 1.5 -outsize 1754 1394", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a minimum:radius1=0.0:radius2=0.0:angle=0.0:min_points=0:nodata=0.0 " + + "-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 " + + source + + " " + + outdir + + "/check.tif --config X Y --config Z A", + ], + ) def testGridInverseDistance(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'points.gml') + source = os.path.join(testDataPath, "points.gml") alg = GridInverseDistance() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: # without NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 9999, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=9999.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "NODATA": 9999, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=9999.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with "0" NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 0, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "NODATA": 0, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # additional parameters self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdal_grid', - '-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 ' + - '-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 ' + - source + ' ' + - outdir + '/check.tif']) + alg.getConsoleCommands( + { + "INPUT": source, + "EXTRA": "-z_multiply 1.5 -outsize 1754 1394", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 " + + "-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 " + + source + + " " + + outdir + + "/check.tif", + ], + ) if GdalUtils.version() >= 3070000: self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdal_grid', - '-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 ' + - '-ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -z_multiply 1.5 -outsize 1754 1394 ' + - source + ' ' + - outdir + '/check.tif']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdal_grid', - '-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 ' + - '-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 ' + - source + ' ' + - outdir + '/check.tif --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "EXTRA": "-z_multiply 1.5 -outsize 1754 1394", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 " + + "-ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -z_multiply 1.5 -outsize 1754 1394 " + + source + + " " + + outdir + + "/check.tif", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "EXTRA": "-z_multiply 1.5 -outsize 1754 1394", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0 " + + "-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 " + + source + + " " + + outdir + + "/check.tif --config X Y --config Z A", + ], + ) def testGridInverseDistanceNearestNeighbour(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'points.gml') + source = os.path.join(testDataPath, "points.gml") alg = GridInverseDistanceNearestNeighbor() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: # without NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 9999, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=9999.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "NODATA": 9999, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=9999.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with "0" NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 0, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "NODATA": 0, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # additional parameters self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdal_grid', - '-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 ' + - '-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 ' + - source + ' ' + - outdir + '/check.tif']) + alg.getConsoleCommands( + { + "INPUT": source, + "EXTRA": "-z_multiply 1.5 -outsize 1754 1394", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 " + + "-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 " + + source + + " " + + outdir + + "/check.tif", + ], + ) if GdalUtils.version() >= 3070000: self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdal_grid', - '-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 ' + - '-ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -z_multiply 1.5 -outsize 1754 1394 ' + - source + ' ' + - outdir + '/check.tif']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdal_grid', - '-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 ' + - '-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 ' + - source + ' ' + - outdir + '/check.tif --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "EXTRA": "-z_multiply 1.5 -outsize 1754 1394", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 " + + "-ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -z_multiply 1.5 -outsize 1754 1394 " + + source + + " " + + outdir + + "/check.tif", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "EXTRA": "-z_multiply 1.5 -outsize 1754 1394", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a invdistnn:power=2.0:smoothing=0.0:radius=1.0:max_points=12:min_points=0:nodata=0.0 " + + "-ot Float32 -of GTiff -z_multiply 1.5 -outsize 1754 1394 " + + source + + " " + + outdir + + "/check.tif --config X Y --config Z A", + ], + ) def testGridLinear(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'points.gml') + source = os.path.join(testDataPath, "points.gml") alg = GridLinear() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: # without NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 9999, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a linear:radius=-1.0:nodata=9999.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "NODATA": 9999, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a linear:radius=-1.0:nodata=9999.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with "0" NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 0, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "NODATA": 0, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # additional parameters self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdal_grid', - '-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of GTiff ' + - '-z_multiply 1.5 -outsize 1754 1394 ' + - source + ' ' + - outdir + '/check.tif']) + alg.getConsoleCommands( + { + "INPUT": source, + "EXTRA": "-z_multiply 1.5 -outsize 1754 1394", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of GTiff " + + "-z_multiply 1.5 -outsize 1754 1394 " + + source + + " " + + outdir + + "/check.tif", + ], + ) if GdalUtils.version() >= 3070000: self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdal_grid', - '-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y ' + - '-z_multiply 1.5 -outsize 1754 1394 ' + - source + ' ' + - outdir + '/check.tif']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdal_grid', - '-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of GTiff ' + - '-z_multiply 1.5 -outsize 1754 1394 ' + - source + ' ' + - outdir + '/check.tif --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "EXTRA": "-z_multiply 1.5 -outsize 1754 1394", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y " + + "-z_multiply 1.5 -outsize 1754 1394 " + + source + + " " + + outdir + + "/check.tif", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "EXTRA": "-z_multiply 1.5 -outsize 1754 1394", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a linear:radius=-1.0:nodata=0.0 -ot Float32 -of GTiff " + + "-z_multiply 1.5 -outsize 1754 1394 " + + source + + " " + + outdir + + "/check.tif --config X Y --config Z A", + ], + ) def testGridNearestNeighbour(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'points.gml') + source = os.path.join(testDataPath, "points.gml") alg = GridNearestNeighbor() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: # without NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 9999, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=9999.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "NODATA": 9999, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=9999.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with "0" NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 0, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_grid', - '-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "NODATA": 0, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # additional parameters self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdal_grid', - '-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of GTiff ' + - '-z_multiply 1.5 -outsize 1754 1394 ' + - source + ' ' + - outdir + '/check.tif']) + alg.getConsoleCommands( + { + "INPUT": source, + "EXTRA": "-z_multiply 1.5 -outsize 1754 1394", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of GTiff " + + "-z_multiply 1.5 -outsize 1754 1394 " + + source + + " " + + outdir + + "/check.tif", + ], + ) if GdalUtils.version() >= 3070000: self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdal_grid', - '-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y ' + - '-z_multiply 1.5 -outsize 1754 1394 ' + - source + ' ' + - outdir + '/check.tif']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'EXTRA': '-z_multiply 1.5 -outsize 1754 1394', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdal_grid', - '-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of GTiff ' + - '-z_multiply 1.5 -outsize 1754 1394 ' + - source + ' ' + - outdir + '/check.tif --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "EXTRA": "-z_multiply 1.5 -outsize 1754 1394", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of GTiff -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y " + + "-z_multiply 1.5 -outsize 1754 1394 " + + source + + " " + + outdir + + "/check.tif", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "EXTRA": "-z_multiply 1.5 -outsize 1754 1394", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdal_grid", + "-l points -a nearest:radius1=0.0:radius2=0.0:angle=0.0:nodata=0.0 -ot Float32 -of GTiff " + + "-z_multiply 1.5 -outsize 1754 1394 " + + source + + " " + + outdir + + "/check.tif --config X Y --config Z A", + ], + ) def testHillshade(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") alg = hillshade() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'Z_FACTOR': 5, - 'SCALE': 2, - 'AZIMUTH': 90, - 'ALTITUDE': 20, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'hillshade ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "Z_FACTOR": 5, + "SCALE": 2, + "AZIMUTH": 90, + "ALTITUDE": 20, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "hillshade " + + source + + " " + + outdir + + "/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0", + ], + ) # paths with space - source_with_space = os.path.join(testDataPath, 'raster with spaces.tif') - self.assertEqual( - alg.getConsoleCommands({'INPUT': source_with_space, - 'BAND': 1, - 'Z_FACTOR': 5, - 'SCALE': 2, - 'AZIMUTH': 90, - 'ALTITUDE': 20, - 'OUTPUT': outdir + '/check out.tif'}, context, feedback), - ['gdaldem', - 'hillshade ' + - '"' + source_with_space + '" ' + - f'"{outdir}/check out.tif" -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0']) + source_with_space = os.path.join(testDataPath, "raster with spaces.tif") + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source_with_space, + "BAND": 1, + "Z_FACTOR": 5, + "SCALE": 2, + "AZIMUTH": 90, + "ALTITUDE": 20, + "OUTPUT": outdir + "/check out.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "hillshade " + + '"' + + source_with_space + + '" ' + + f'"{outdir}/check out.tif" -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0', + ], + ) # compute edges self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'Z_FACTOR': 5, - 'SCALE': 2, - 'AZIMUTH': 90, - 'ALTITUDE': 20, - 'COMPUTE_EDGES': True, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'hillshade ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0 -compute_edges']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "Z_FACTOR": 5, + "SCALE": 2, + "AZIMUTH": 90, + "ALTITUDE": 20, + "COMPUTE_EDGES": True, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "hillshade " + + source + + " " + + outdir + + "/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0 -compute_edges", + ], + ) # with ZEVENBERGEN self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'Z_FACTOR': 5, - 'SCALE': 2, - 'AZIMUTH': 90, - 'ALTITUDE': 20, - 'ZEVENBERGEN': True, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'hillshade ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0 -alg ZevenbergenThorne']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "Z_FACTOR": 5, + "SCALE": 2, + "AZIMUTH": 90, + "ALTITUDE": 20, + "ZEVENBERGEN": True, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "hillshade " + + source + + " " + + outdir + + "/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0 -alg ZevenbergenThorne", + ], + ) # with COMBINED self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'Z_FACTOR': 5, - 'SCALE': 2, - 'AZIMUTH': 90, - 'ALTITUDE': 20, - 'COMBINED': True, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'hillshade ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0 -combined']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "Z_FACTOR": 5, + "SCALE": 2, + "AZIMUTH": 90, + "ALTITUDE": 20, + "COMBINED": True, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "hillshade " + + source + + " " + + outdir + + "/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0 -combined", + ], + ) # with multidirectional - "az" argument is not allowed! self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'Z_FACTOR': 5, - 'SCALE': 2, - 'AZIMUTH': 90, - 'ALTITUDE': 20, - 'MULTIDIRECTIONAL': True, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'hillshade ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -alt 20.0 -multidirectional']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "Z_FACTOR": 5, + "SCALE": 2, + "AZIMUTH": 90, + "ALTITUDE": 20, + "MULTIDIRECTIONAL": True, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "hillshade " + + source + + " " + + outdir + + "/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -alt 20.0 -multidirectional", + ], + ) # defaults with additional parameters self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'EXTRA': '-q', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'hillshade ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 -z 1.0 -s 1.0 -az 315.0 -alt 45.0 -q']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "EXTRA": "-q", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "hillshade " + + source + + " " + + outdir + + "/check.tif -of GTiff -b 1 -z 1.0 -s 1.0 -az 315.0 -alt 45.0 -q", + ], + ) # multidirectional and combined are mutually exclusive self.assertRaises( QgsProcessingException, - lambda: alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'Z_FACTOR': 5, - 'SCALE': 2, - 'AZIMUTH': 90, - 'COMBINED': True, - 'MULTIDIRECTIONAL': True, - 'OUTPUT': outdir + '/check.tif'}, context, feedback)) - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'BAND': 1, - 'Z_FACTOR': 5, - 'SCALE': 2, - 'AZIMUTH': 90, - 'ALTITUDE': 20, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'hillshade ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0 --config X Y --config Z A']) + lambda: alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "Z_FACTOR": 5, + "SCALE": 2, + "AZIMUTH": 90, + "COMBINED": True, + "MULTIDIRECTIONAL": True, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + ) + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "BAND": 1, + "Z_FACTOR": 5, + "SCALE": 2, + "AZIMUTH": 90, + "ALTITUDE": 20, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "hillshade " + + source + + " " + + outdir + + "/check.tif -of GTiff -b 1 -z 5.0 -s 2.0 -az 90.0 -alt 20.0 --config X Y --config Z A", + ], + ) def testAspect(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") alg = aspect() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'TRIG_ANGLE': False, - 'ZERO_FLAT': False, - 'COMPUTE_EDGES': False, - 'ZEVENBERGEN': False, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'aspect ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "TRIG_ANGLE": False, + "ZERO_FLAT": False, + "COMPUTE_EDGES": False, + "ZEVENBERGEN": False, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "aspect " + source + " " + outdir + "/check.tif -of GTiff -b 1", + ], + ) # paths with space - source_with_space = os.path.join(testDataPath, 'raster with spaces.tif') - self.assertEqual( - alg.getConsoleCommands({'INPUT': source_with_space, - 'BAND': 1, - 'TRIG_ANGLE': False, - 'ZERO_FLAT': False, - 'COMPUTE_EDGES': False, - 'ZEVENBERGEN': False, - 'OUTPUT': outdir + '/check out.tif'}, context, feedback), - ['gdaldem', - 'aspect ' + - '"' + source_with_space + '" ' + - f'"{outdir}/check out.tif" -of GTiff -b 1']) + source_with_space = os.path.join(testDataPath, "raster with spaces.tif") + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source_with_space, + "BAND": 1, + "TRIG_ANGLE": False, + "ZERO_FLAT": False, + "COMPUTE_EDGES": False, + "ZEVENBERGEN": False, + "OUTPUT": outdir + "/check out.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "aspect " + + '"' + + source_with_space + + '" ' + + f'"{outdir}/check out.tif" -of GTiff -b 1', + ], + ) # compute edges self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'TRIG_ANGLE': False, - 'ZERO_FLAT': False, - 'COMPUTE_EDGES': True, - 'ZEVENBERGEN': False, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'aspect ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 -compute_edges']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "TRIG_ANGLE": False, + "ZERO_FLAT": False, + "COMPUTE_EDGES": True, + "ZEVENBERGEN": False, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "aspect " + + source + + " " + + outdir + + "/check.tif -of GTiff -b 1 -compute_edges", + ], + ) # with ZEVENBERGEN self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'TRIG_ANGLE': False, - 'ZERO_FLAT': False, - 'COMPUTE_EDGES': False, - 'ZEVENBERGEN': True, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'aspect ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 -alg ZevenbergenThorne']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "TRIG_ANGLE": False, + "ZERO_FLAT": False, + "COMPUTE_EDGES": False, + "ZEVENBERGEN": True, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "aspect " + + source + + " " + + outdir + + "/check.tif -of GTiff -b 1 -alg ZevenbergenThorne", + ], + ) # with ZERO_FLAT self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'TRIG_ANGLE': False, - 'ZERO_FLAT': True, - 'COMPUTE_EDGES': False, - 'ZEVENBERGEN': False, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'aspect ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 -zero_for_flat']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "TRIG_ANGLE": False, + "ZERO_FLAT": True, + "COMPUTE_EDGES": False, + "ZEVENBERGEN": False, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "aspect " + + source + + " " + + outdir + + "/check.tif -of GTiff -b 1 -zero_for_flat", + ], + ) # with TRIG_ANGLE self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'TRIG_ANGLE': True, - 'ZERO_FLAT': False, - 'COMPUTE_EDGES': False, - 'ZEVENBERGEN': False, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'aspect ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 -trigonometric']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "TRIG_ANGLE": True, + "ZERO_FLAT": False, + "COMPUTE_EDGES": False, + "ZEVENBERGEN": False, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "aspect " + + source + + " " + + outdir + + "/check.tif -of GTiff -b 1 -trigonometric", + ], + ) # with creation options self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'TRIG_ANGLE': False, - 'ZERO_FLAT': False, - 'COMPUTE_EDGES': False, - 'ZEVENBERGEN': False, - 'OPTIONS': 'COMPRESS=JPEG|JPEG_QUALITY=75', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'aspect ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 -co COMPRESS=JPEG -co JPEG_QUALITY=75']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "TRIG_ANGLE": False, + "ZERO_FLAT": False, + "COMPUTE_EDGES": False, + "ZEVENBERGEN": False, + "OPTIONS": "COMPRESS=JPEG|JPEG_QUALITY=75", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "aspect " + + source + + " " + + outdir + + "/check.tif -of GTiff -b 1 -co COMPRESS=JPEG -co JPEG_QUALITY=75", + ], + ) # with additional parameter self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'TRIG_ANGLE': False, - 'ZERO_FLAT': False, - 'COMPUTE_EDGES': False, - 'ZEVENBERGEN': False, - 'EXTRA': '-q', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'aspect ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 -q']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'BAND': 1, - 'TRIG_ANGLE': False, - 'ZERO_FLAT': False, - 'COMPUTE_EDGES': False, - 'ZEVENBERGEN': False, - 'EXTRA': '-q', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'aspect ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 --config X Y --config Z A -q']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "TRIG_ANGLE": False, + "ZERO_FLAT": False, + "COMPUTE_EDGES": False, + "ZEVENBERGEN": False, + "EXTRA": "-q", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "aspect " + source + " " + outdir + "/check.tif -of GTiff -b 1 -q", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "BAND": 1, + "TRIG_ANGLE": False, + "ZERO_FLAT": False, + "COMPUTE_EDGES": False, + "ZEVENBERGEN": False, + "EXTRA": "-q", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "aspect " + + source + + " " + + outdir + + "/check.tif -of GTiff -b 1 --config X Y --config Z A -q", + ], + ) def testSlope(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") alg = slope() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'slope ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 -s 1.0']) + alg.getConsoleCommands( + {"INPUT": source, "BAND": 1, "OUTPUT": outdir + "/check.tif"}, + context, + feedback, + ), + [ + "gdaldem", + "slope " + + source + + " " + + outdir + + "/check.tif -of GTiff -b 1 -s 1.0", + ], + ) # compute edges self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'COMPUTE_EDGES': True, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'slope ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 -s 1.0 -compute_edges']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "COMPUTE_EDGES": True, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "slope " + + source + + " " + + outdir + + "/check.tif -of GTiff -b 1 -s 1.0 -compute_edges", + ], + ) # with ZEVENBERGEN self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'ZEVENBERGEN': True, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'slope ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 -s 1.0 -alg ZevenbergenThorne']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "ZEVENBERGEN": True, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "slope " + + source + + " " + + outdir + + "/check.tif -of GTiff -b 1 -s 1.0 -alg ZevenbergenThorne", + ], + ) # custom ratio self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'SCALE': 2.0, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'slope ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 -s 2.0']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "SCALE": 2.0, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "slope " + + source + + " " + + outdir + + "/check.tif -of GTiff -b 1 -s 2.0", + ], + ) # with creation options self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'OPTIONS': 'COMPRESS=JPEG|JPEG_QUALITY=75', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'slope ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 -s 1.0 -co COMPRESS=JPEG -co JPEG_QUALITY=75']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "OPTIONS": "COMPRESS=JPEG|JPEG_QUALITY=75", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "slope " + + source + + " " + + outdir + + "/check.tif -of GTiff -b 1 -s 1.0 -co COMPRESS=JPEG -co JPEG_QUALITY=75", + ], + ) # with additional parameter self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'EXTRA': '-q', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdaldem', - 'slope ' + - source + ' ' + - outdir + '/check.jpg -of JPEG -b 1 -s 1.0 -q']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'BAND': 1, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'slope ' + - source + ' ' + - outdir + '/check.tif -of GTiff -b 1 -s 1.0 --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "EXTRA": "-q", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdaldem", + "slope " + + source + + " " + + outdir + + "/check.jpg -of JPEG -b 1 -s 1.0 -q", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "BAND": 1, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "slope " + + source + + " " + + outdir + + "/check.tif -of GTiff -b 1 -s 1.0 --config X Y --config Z A", + ], + ) def testColorRelief(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') - colorTable = os.path.join(testDataPath, 'colors.txt') + source = os.path.join(testDataPath, "dem.tif") + colorTable = os.path.join(testDataPath, "colors.txt") alg = ColorRelief() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'COLOR_TABLE': colorTable, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'color-relief ' + - source + ' ' + - colorTable + ' ' + - outdir + '/check.tif -of GTiff -b 1']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "COLOR_TABLE": colorTable, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "color-relief " + + source + + " " + + colorTable + + " " + + outdir + + "/check.tif -of GTiff -b 1", + ], + ) # paths with space - source_with_space = os.path.join(testDataPath, 'raster with spaces.tif') - self.assertEqual( - alg.getConsoleCommands({'INPUT': source_with_space, - 'BAND': 1, - 'COLOR_TABLE': colorTable, - 'OUTPUT': outdir + '/check out.tif'}, context, feedback), - ['gdaldem', - 'color-relief ' + - '"' + source_with_space + '" ' + - colorTable + ' ' + - f'"{outdir}/check out.tif" -of GTiff -b 1']) + source_with_space = os.path.join(testDataPath, "raster with spaces.tif") + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source_with_space, + "BAND": 1, + "COLOR_TABLE": colorTable, + "OUTPUT": outdir + "/check out.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "color-relief " + + '"' + + source_with_space + + '" ' + + colorTable + + " " + + f'"{outdir}/check out.tif" -of GTiff -b 1', + ], + ) # compute edges self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'COLOR_TABLE': colorTable, - 'COMPUTE_EDGES': True, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'color-relief ' + - source + ' ' + - colorTable + ' ' + - outdir + '/check.tif -of GTiff -b 1 -compute_edges']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "COLOR_TABLE": colorTable, + "COMPUTE_EDGES": True, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "color-relief " + + source + + " " + + colorTable + + " " + + outdir + + "/check.tif -of GTiff -b 1 -compute_edges", + ], + ) # with custom matching mode self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'COLOR_TABLE': colorTable, - 'MATCH_MODE': 1, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'color-relief ' + - source + ' ' + - colorTable + ' ' + - outdir + '/check.tif -of GTiff -b 1 -nearest_color_entry']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "COLOR_TABLE": colorTable, + "MATCH_MODE": 1, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "color-relief " + + source + + " " + + colorTable + + " " + + outdir + + "/check.tif -of GTiff -b 1 -nearest_color_entry", + ], + ) # with creation options self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'COLOR_TABLE': colorTable, - 'MATCH_MODE': 1, - 'OPTIONS': 'COMPRESS=JPEG|JPEG_QUALITY=75', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'color-relief ' + - source + ' ' + - colorTable + ' ' + - outdir + '/check.tif -of GTiff -b 1 -nearest_color_entry -co COMPRESS=JPEG -co JPEG_QUALITY=75']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "COLOR_TABLE": colorTable, + "MATCH_MODE": 1, + "OPTIONS": "COMPRESS=JPEG|JPEG_QUALITY=75", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "color-relief " + + source + + " " + + colorTable + + " " + + outdir + + "/check.tif -of GTiff -b 1 -nearest_color_entry -co COMPRESS=JPEG -co JPEG_QUALITY=75", + ], + ) # with additional parameter self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'COLOR_TABLE': colorTable, - 'EXTRA': '-alpha -q', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'color-relief ' + - source + ' ' + - colorTable + ' ' + - outdir + '/check.tif -of GTiff -b 1 -alpha -q']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'BAND': 1, - 'COLOR_TABLE': colorTable, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'color-relief ' + - source + ' ' + - colorTable + ' ' + - outdir + '/check.tif -of GTiff -b 1 --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "COLOR_TABLE": colorTable, + "EXTRA": "-alpha -q", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "color-relief " + + source + + " " + + colorTable + + " " + + outdir + + "/check.tif -of GTiff -b 1 -alpha -q", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "BAND": 1, + "COLOR_TABLE": colorTable, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "color-relief " + + source + + " " + + colorTable + + " " + + outdir + + "/check.tif -of GTiff -b 1 --config X Y --config Z A", + ], + ) def testProximity(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") alg = proximity() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: # without NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_proximity.py', - '-srcband 1 -distunits PIXEL -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "BAND": 1, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_proximity.py", + "-srcband 1 -distunits PIXEL -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 9999, - 'BAND': 2, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_proximity.py', - '-srcband 2 -distunits PIXEL -nodata 9999.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "NODATA": 9999, + "BAND": 2, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_proximity.py", + "-srcband 2 -distunits PIXEL -nodata 9999.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with "0" NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 0, - 'BAND': 1, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_proximity.py', - '-srcband 1 -distunits PIXEL -nodata 0.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "NODATA": 0, + "BAND": 1, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_proximity.py", + "-srcband 1 -distunits PIXEL -nodata 0.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # additional parameters self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'EXTRA': '-dstband 2 -values 3,4,12', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_proximity.py', - '-srcband 1 -distunits PIXEL -ot Float32 -of JPEG -dstband 2 -values 3,4,12 ' + - source + ' ' + - outdir + '/check.jpg']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'BAND': 1, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_proximity.py', - '-srcband 1 -distunits PIXEL -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "EXTRA": "-dstband 2 -values 3,4,12", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_proximity.py", + "-srcband 1 -distunits PIXEL -ot Float32 -of JPEG -dstband 2 -values 3,4,12 " + + source + + " " + + outdir + + "/check.jpg", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "BAND": 1, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_proximity.py", + "-srcband 1 -distunits PIXEL -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg --config X Y --config Z A", + ], + ) def testRasterize(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'polys.gml') - sourceZ = os.path.join(testDataPath, 'pointsz.gml') - extent4326 = QgsReferencedRectangle(QgsRectangle(-1, -3, 10, 6), QgsCoordinateReferenceSystem('EPSG:4326')) - extent3857 = QgsReferencedRectangle(QgsRectangle(-111319.491, -334111.171, 1113194.908, 669141.057), QgsCoordinateReferenceSystem('EPSG:3857')) + source = os.path.join(testDataPath, "polys.gml") + sourceZ = os.path.join(testDataPath, "pointsz.gml") + extent4326 = QgsReferencedRectangle( + QgsRectangle(-1, -3, 10, 6), QgsCoordinateReferenceSystem("EPSG:4326") + ) + extent3857 = QgsReferencedRectangle( + QgsRectangle(-111319.491, -334111.171, 1113194.908, 669141.057), + QgsCoordinateReferenceSystem("EPSG:3857"), + ) alg = rasterize() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: # with no NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FIELD': 'id', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_rasterize', - '-l polys2 -a id -ts 0.0 0.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": source, "FIELD": "id", "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_rasterize", + "-l polys2 -a id -ts 0.0 0.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 9999, - 'FIELD': 'id', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_rasterize', - '-l polys2 -a id -ts 0.0 0.0 -a_nodata 9999.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "NODATA": 9999, + "FIELD": "id", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_rasterize", + "-l polys2 -a id -ts 0.0 0.0 -a_nodata 9999.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with "0" INIT value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'INIT': 0, - 'FIELD': 'id', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_rasterize', - '-l polys2 -a id -ts 0.0 0.0 -init 0.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "INIT": 0, + "FIELD": "id", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_rasterize", + "-l polys2 -a id -ts 0.0 0.0 -init 0.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with "0" NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 0, - 'FIELD': 'id', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_rasterize', - '-l polys2 -a id -ts 0.0 0.0 -a_nodata 0.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FIELD': 'id', - 'EXTRA': '-at -add', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_rasterize', - '-l polys2 -a id -ts 0.0 0.0 -ot Float32 -of JPEG -at -add ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "NODATA": 0, + "FIELD": "id", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_rasterize", + "-l polys2 -a id -ts 0.0 0.0 -a_nodata 0.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source, + "FIELD": "id", + "EXTRA": "-at -add", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_rasterize", + "-l polys2 -a id -ts 0.0 0.0 -ot Float32 -of JPEG -at -add " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # use_Z selected with no field self.assertEqual( - alg.getConsoleCommands({'INPUT': sourceZ, - 'USE_Z': True, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_rasterize', - '-l pointsz -3d -ts 0.0 0.0 -ot Float32 -of JPEG ' + - sourceZ + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + {"INPUT": sourceZ, "USE_Z": True, "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdal_rasterize", + "-l pointsz -3d -ts 0.0 0.0 -ot Float32 -of JPEG " + + sourceZ + + " " + + outdir + + "/check.jpg", + ], + ) # use_Z selected with field indicated (should prefer use_Z) self.assertEqual( - alg.getConsoleCommands({'INPUT': sourceZ, - 'FIELD': 'elev', - 'USE_Z': True, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_rasterize', - '-l pointsz -3d -ts 0.0 0.0 -ot Float32 -of JPEG ' + - sourceZ + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": sourceZ, + "FIELD": "elev", + "USE_Z": True, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_rasterize", + "-l pointsz -3d -ts 0.0 0.0 -ot Float32 -of JPEG " + + sourceZ + + " " + + outdir + + "/check.jpg", + ], + ) # with EXTENT in the same CRS as the input layer source self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FIELD': 'id', - 'EXTENT': extent4326, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_rasterize', - '-l polys2 -a id -ts 0.0 0.0 -te -1.0 -3.0 10.0 6.0 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "FIELD": "id", + "EXTENT": extent4326, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_rasterize", + "-l polys2 -a id -ts 0.0 0.0 -te -1.0 -3.0 10.0 6.0 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with EXTENT in a different CRS than that of the input layer source self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FIELD': 'id', - 'EXTENT': extent3857, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_rasterize', - '-l polys2 -a id -ts 0.0 0.0 -te -1.000000001857055 -2.9999999963940835 10.000000000604244 5.99999999960471 -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "FIELD": "id", + "EXTENT": extent3857, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_rasterize", + "-l polys2 -a id -ts 0.0 0.0 -te -1.000000001857055 -2.9999999963940835 10.000000000604244 5.99999999960471 -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) if GdalUtils.version() >= 3070000: self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'FIELD': 'id', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_rasterize', - '-l polys2 -a id -ts 0.0 0.0 -ot Float32 -of JPEG -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y ' + - source + ' ' + - outdir + '/check.jpg']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'FIELD': 'id', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdal_rasterize', - '-l polys2 -a id -ts 0.0 0.0 -ot Float32 -of JPEG --config X Y --config Z A ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "FIELD": "id", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_rasterize", + "-l polys2 -a id -ts 0.0 0.0 -ot Float32 -of JPEG -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y " + + source + + " " + + outdir + + "/check.jpg", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "FIELD": "id", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdal_rasterize", + "-l polys2 -a id -ts 0.0 0.0 -ot Float32 -of JPEG --config X Y --config Z A " + + source + + " " + + outdir + + "/check.jpg", + ], + ) def testRasterizeOver(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - raster = os.path.join(testDataPath, 'dem.tif') - vector = os.path.join(testDataPath, 'polys.gml') + raster = os.path.join(testDataPath, "dem.tif") + vector = os.path.join(testDataPath, "polys.gml") alg = rasterize_over() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: self.assertEqual( - alg.getConsoleCommands({'INPUT': vector, - 'FIELD': 'id', - 'INPUT_RASTER': raster}, context, feedback), - ['gdal_rasterize', - '-l polys2 -a id ' + - vector + ' ' + raster]) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': vector, - 'FIELD': 'id', - 'ADD': True, - 'INPUT_RASTER': raster}, context, feedback), - ['gdal_rasterize', - '-l polys2 -a id -add ' + - vector + ' ' + raster]) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': vector, - 'FIELD': 'id', - 'EXTRA': '-i', - 'INPUT_RASTER': raster}, context, feedback), - ['gdal_rasterize', - '-l polys2 -a id -i ' + - vector + ' ' + raster]) + alg.getConsoleCommands( + {"INPUT": vector, "FIELD": "id", "INPUT_RASTER": raster}, + context, + feedback, + ), + ["gdal_rasterize", "-l polys2 -a id " + vector + " " + raster], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": vector, + "FIELD": "id", + "ADD": True, + "INPUT_RASTER": raster, + }, + context, + feedback, + ), + ["gdal_rasterize", "-l polys2 -a id -add " + vector + " " + raster], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": vector, + "FIELD": "id", + "EXTRA": "-i", + "INPUT_RASTER": raster, + }, + context, + feedback, + ), + ["gdal_rasterize", "-l polys2 -a id -i " + vector + " " + raster], + ) if GdalUtils.version() >= 3070000: self.assertEqual( - alg.getConsoleCommands({'INPUT': vector + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'FIELD': 'id', - 'INPUT_RASTER': raster}, context, feedback), - ['gdal_rasterize', - '-l polys2 -a id -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y ' + - vector + ' ' + raster]) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': vector + '|credential:X=Y|credential:Z=A', - 'FIELD': 'id', - 'INPUT_RASTER': raster}, context, feedback), - ['gdal_rasterize', - '-l polys2 -a id --config X Y --config Z A ' + - vector + ' ' + raster]) + alg.getConsoleCommands( + { + "INPUT": vector + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "FIELD": "id", + "INPUT_RASTER": raster, + }, + context, + feedback, + ), + [ + "gdal_rasterize", + "-l polys2 -a id -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y " + + vector + + " " + + raster, + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": vector + "|credential:X=Y|credential:Z=A", + "FIELD": "id", + "INPUT_RASTER": raster, + }, + context, + feedback, + ), + [ + "gdal_rasterize", + "-l polys2 -a id --config X Y --config Z A " + + vector + + " " + + raster, + ], + ) def testRasterizeOverFixed(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - raster = os.path.join(testDataPath, 'dem.tif') - vector = os.path.join(testDataPath, 'polys.gml') + raster = os.path.join(testDataPath, "dem.tif") + vector = os.path.join(testDataPath, "polys.gml") alg = rasterize_over_fixed_value() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: self.assertEqual( - alg.getConsoleCommands({'INPUT': vector, - 'BURN': 100, - 'INPUT_RASTER': raster}, context, feedback), - ['gdal_rasterize', - '-l polys2 -burn 100.0 ' + - vector + ' ' + raster]) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': vector, - 'BURN': 100, - 'ADD': True, - 'INPUT_RASTER': raster}, context, feedback), - ['gdal_rasterize', - '-l polys2 -burn 100.0 -add ' + - vector + ' ' + raster]) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': vector, - 'BURN': 100, - 'EXTRA': '-i', - 'INPUT_RASTER': raster}, context, feedback), - ['gdal_rasterize', - '-l polys2 -burn 100.0 -i ' + - vector + ' ' + raster]) + alg.getConsoleCommands( + {"INPUT": vector, "BURN": 100, "INPUT_RASTER": raster}, + context, + feedback, + ), + ["gdal_rasterize", "-l polys2 -burn 100.0 " + vector + " " + raster], + ) + + self.assertEqual( + alg.getConsoleCommands( + {"INPUT": vector, "BURN": 100, "ADD": True, "INPUT_RASTER": raster}, + context, + feedback, + ), + [ + "gdal_rasterize", + "-l polys2 -burn 100.0 -add " + vector + " " + raster, + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": vector, + "BURN": 100, + "EXTRA": "-i", + "INPUT_RASTER": raster, + }, + context, + feedback, + ), + ["gdal_rasterize", "-l polys2 -burn 100.0 -i " + vector + " " + raster], + ) if GdalUtils.version() >= 3070000: self.assertEqual( - alg.getConsoleCommands({'INPUT': vector + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'BURN': 100, - 'INPUT_RASTER': raster}, context, feedback), - ['gdal_rasterize', - '-l polys2 -burn 100.0 -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y ' + - vector + ' ' + raster]) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': vector + '|credential:X=Y|credential:Z=A', - 'BURN': 100, - 'INPUT_RASTER': raster}, context, feedback), - ['gdal_rasterize', - '-l polys2 -burn 100.0 --config X Y --config Z A ' + - vector + ' ' + raster]) + alg.getConsoleCommands( + { + "INPUT": vector + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "BURN": 100, + "INPUT_RASTER": raster, + }, + context, + feedback, + ), + [ + "gdal_rasterize", + "-l polys2 -burn 100.0 -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y " + + vector + + " " + + raster, + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": vector + "|credential:X=Y|credential:Z=A", + "BURN": 100, + "INPUT_RASTER": raster, + }, + context, + feedback, + ), + [ + "gdal_rasterize", + "-l polys2 -burn 100.0 --config X Y --config Z A " + + vector + + " " + + raster, + ], + ) def testRasterizeOverRun(self): # Check that rasterize over tools update QgsRasterLayer context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source_vector = os.path.join(testDataPath, 'rasterize_zones.gml') - source_raster = os.path.join(testDataPath, 'dem.tif') + source_vector = os.path.join(testDataPath, "rasterize_zones.gml") + source_raster = os.path.join(testDataPath, "dem.tif") with tempfile.TemporaryDirectory() as outdir: # fixed value alg = rasterize_over_fixed_value() alg.initAlgorithm() - test_dem = os.path.join(outdir, 'rasterize-fixed.tif') + test_dem = os.path.join(outdir, "rasterize-fixed.tif") shutil.copy(source_raster, test_dem) self.assertTrue(os.path.exists(test_dem)) - layer = QgsRasterLayer(test_dem, 'test') + layer = QgsRasterLayer(test_dem, "test") self.assertTrue(layer.isValid()) val, ok = layer.dataProvider().sample(QgsPointXY(18.68704, 45.79568), 1) self.assertEqual(val, 172.2267303466797) project = QgsProject() - project.setFileName(os.path.join(outdir, 'rasterize-fixed.qgs')) + project.setFileName(os.path.join(outdir, "rasterize-fixed.qgs")) project.addMapLayer(layer) self.assertEqual(project.count(), 1) context.setProject(project) - alg.run({'INPUT': source_vector, - 'INPUT_RASTER': test_dem, - 'BURN': 200 - }, context, feedback) + alg.run( + {"INPUT": source_vector, "INPUT_RASTER": test_dem, "BURN": 200}, + context, + feedback, + ) val, ok = layer.dataProvider().sample(QgsPointXY(18.68704, 45.79568), 1) self.assertTrue(ok) @@ -2159,27 +3762,28 @@ def testRasterizeOverRun(self): alg = rasterize_over() alg.initAlgorithm() - test_dem = os.path.join(outdir, 'rasterize-over.tif') + test_dem = os.path.join(outdir, "rasterize-over.tif") shutil.copy(source_raster, test_dem) self.assertTrue(os.path.exists(test_dem)) - layer = QgsRasterLayer(test_dem, 'test') + layer = QgsRasterLayer(test_dem, "test") self.assertTrue(layer.isValid()) val, ok = layer.dataProvider().sample(QgsPointXY(18.68704, 45.79568), 1) self.assertEqual(val, 172.2267303466797) project = QgsProject() - project.setFileName(os.path.join(outdir, 'rasterize-over.qgs')) + project.setFileName(os.path.join(outdir, "rasterize-over.qgs")) project.addMapLayer(layer) self.assertEqual(project.count(), 1) context.setProject(project) - alg.run({'INPUT': source_vector, - 'INPUT_RASTER': test_dem, - 'FIELD': 'value' - }, context, feedback) + alg.run( + {"INPUT": source_vector, "INPUT_RASTER": test_dem, "FIELD": "value"}, + context, + feedback, + ) val, ok = layer.dataProvider().sample(QgsPointXY(18.68704, 45.79568), 1) self.assertTrue(ok) @@ -2188,553 +3792,1016 @@ def testRasterizeOverRun(self): def testRetile(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") alg = retile() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: self.assertEqual( - alg.getConsoleCommands({'INPUT': [source], - 'OUTPUT': outdir}, context, feedback), - ['gdal_retile.py', - f'-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -targetDir {outdir} ' + - source]) + alg.getConsoleCommands( + {"INPUT": [source], "OUTPUT": outdir}, context, feedback + ), + [ + "gdal_retile.py", + f"-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -targetDir {outdir} " + + source, + ], + ) # with input srs self.assertEqual( - alg.getConsoleCommands({'INPUT': [source], - 'SOURCE_CRS': 'EPSG:3111', - 'OUTPUT': outdir}, context, feedback), - ['gdal_retile.py', - f'-ps 256 256 -overlap 0 -levels 1 -s_srs EPSG:3111 -r near -ot Float32 -targetDir {outdir} {source}' - ]) + alg.getConsoleCommands( + {"INPUT": [source], "SOURCE_CRS": "EPSG:3111", "OUTPUT": outdir}, + context, + feedback, + ), + [ + "gdal_retile.py", + f"-ps 256 256 -overlap 0 -levels 1 -s_srs EPSG:3111 -r near -ot Float32 -targetDir {outdir} {source}", + ], + ) # with target using proj string - custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs' - self.assertEqual( - alg.getConsoleCommands({'INPUT': [source], - 'SOURCE_CRS': custom_crs, - 'OUTPUT': outdir}, context, feedback), - ['gdal_retile.py', - f'-ps 256 256 -overlap 0 -levels 1 -s_srs EPSG:20936 -r near -ot Float32 -targetDir {outdir} {source}' - ]) + custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" + self.assertEqual( + alg.getConsoleCommands( + {"INPUT": [source], "SOURCE_CRS": custom_crs, "OUTPUT": outdir}, + context, + feedback, + ), + [ + "gdal_retile.py", + f"-ps 256 256 -overlap 0 -levels 1 -s_srs EPSG:20936 -r near -ot Float32 -targetDir {outdir} {source}", + ], + ) # with target using custom projection - custom_crs, expected_crs_string = self.get_param_value_and_expected_string_for_custom_crs('+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs') - self.assertEqual( - alg.getConsoleCommands({'INPUT': [source], - 'SOURCE_CRS': custom_crs, - 'OUTPUT': outdir}, context, feedback), - ['gdal_retile.py', - f'-ps 256 256 -overlap 0 -levels 1 -s_srs "{expected_crs_string}" -r near -ot Float32 -targetDir {outdir} {source}' - ]) + custom_crs, expected_crs_string = ( + self.get_param_value_and_expected_string_for_custom_crs( + "+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" + ) + ) + self.assertEqual( + alg.getConsoleCommands( + {"INPUT": [source], "SOURCE_CRS": custom_crs, "OUTPUT": outdir}, + context, + feedback, + ), + [ + "gdal_retile.py", + f'-ps 256 256 -overlap 0 -levels 1 -s_srs "{expected_crs_string}" -r near -ot Float32 -targetDir {outdir} {source}', + ], + ) # with non-EPSG crs code self.assertEqual( - alg.getConsoleCommands({'INPUT': [source], - 'SOURCE_CRS': 'POSTGIS:3111', - 'OUTPUT': outdir}, context, feedback), - ['gdal_retile.py', - f'-ps 256 256 -overlap 0 -levels 1 -s_srs EPSG:3111 -r near -ot Float32 -targetDir {outdir} {source}' - ]) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': [source], - 'OUTPUT_CSV': 'out.csv', - 'DELIMITER': '', - 'OUTPUT': outdir}, context, feedback), - ['gdal_retile.py', - f'-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -csv out.csv -targetDir {outdir} ' + - source]) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': [source], - 'OUTPUT_CSV': 'out.csv', - 'DELIMITER': ';', - 'OUTPUT': outdir}, context, feedback), - ['gdal_retile.py', - f'-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -csv out.csv -csvDelim ";" -targetDir {outdir} ' + - source]) + alg.getConsoleCommands( + {"INPUT": [source], "SOURCE_CRS": "POSTGIS:3111", "OUTPUT": outdir}, + context, + feedback, + ), + [ + "gdal_retile.py", + f"-ps 256 256 -overlap 0 -levels 1 -s_srs EPSG:3111 -r near -ot Float32 -targetDir {outdir} {source}", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": [source], + "OUTPUT_CSV": "out.csv", + "DELIMITER": "", + "OUTPUT": outdir, + }, + context, + feedback, + ), + [ + "gdal_retile.py", + f"-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -csv out.csv -targetDir {outdir} " + + source, + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": [source], + "OUTPUT_CSV": "out.csv", + "DELIMITER": ";", + "OUTPUT": outdir, + }, + context, + feedback, + ), + [ + "gdal_retile.py", + f'-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -csv out.csv -csvDelim ";" -targetDir {outdir} ' + + source, + ], + ) # additional parameters self.assertEqual( - alg.getConsoleCommands({'INPUT': [source], - 'EXTRA': '-v -tileIndex tindex.shp', - 'OUTPUT': outdir}, context, feedback), - ['gdal_retile.py', - f'-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -v -tileIndex tindex.shp -targetDir {outdir} ' + - source]) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': [source], - 'ONLY_PYRAMIDS': True, - 'OUTPUT': outdir}, context, feedback), - ['gdal_retile.py', - f'-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -pyramidOnly -targetDir {outdir} ' + - source]) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': [source], - 'DIR_FOR_ROW': True, - 'OUTPUT': outdir}, context, feedback), - ['gdal_retile.py', - f'-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -useDirForEachRow -targetDir {outdir} ' + - source]) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': [source + '|credential:X=Y|credential:Z=A'], - 'DIR_FOR_ROW': True, - 'OUTPUT': outdir}, context, feedback), - ['gdal_retile.py', - f'-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -useDirForEachRow -targetDir {outdir} ' + - source + ' --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": [source], + "EXTRA": "-v -tileIndex tindex.shp", + "OUTPUT": outdir, + }, + context, + feedback, + ), + [ + "gdal_retile.py", + f"-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -v -tileIndex tindex.shp -targetDir {outdir} " + + source, + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + {"INPUT": [source], "ONLY_PYRAMIDS": True, "OUTPUT": outdir}, + context, + feedback, + ), + [ + "gdal_retile.py", + f"-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -pyramidOnly -targetDir {outdir} " + + source, + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + {"INPUT": [source], "DIR_FOR_ROW": True, "OUTPUT": outdir}, + context, + feedback, + ), + [ + "gdal_retile.py", + f"-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -useDirForEachRow -targetDir {outdir} " + + source, + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": [source + "|credential:X=Y|credential:Z=A"], + "DIR_FOR_ROW": True, + "OUTPUT": outdir, + }, + context, + feedback, + ), + [ + "gdal_retile.py", + f"-ps 256 256 -overlap 0 -levels 1 -r near -ot Float32 -useDirForEachRow -targetDir {outdir} " + + source + + " --config X Y --config Z A", + ], + ) def testWarp(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") alg = warp() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: # with no NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SOURCE_CRS': 'EPSG:3111', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -s_srs EPSG:3111 -r near -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "SOURCE_CRS": "EPSG:3111", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -s_srs EPSG:3111 -r near -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with None NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': None, - 'SOURCE_CRS': 'EPSG:3111', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -s_srs EPSG:3111 -r near -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "NODATA": None, + "SOURCE_CRS": "EPSG:3111", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -s_srs EPSG:3111 -r near -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 9999, - 'SOURCE_CRS': 'EPSG:3111', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -s_srs EPSG:3111 -dstnodata 9999.0 -r near -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "NODATA": 9999, + "SOURCE_CRS": "EPSG:3111", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -s_srs EPSG:3111 -dstnodata 9999.0 -r near -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with "0" NODATA value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 0, - 'SOURCE_CRS': 'EPSG:3111', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -s_srs EPSG:3111 -dstnodata 0.0 -r near -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "NODATA": 0, + "SOURCE_CRS": "EPSG:3111", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -s_srs EPSG:3111 -dstnodata 0.0 -r near -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with "0" NODATA value and custom data type self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NODATA': 0, - 'DATA_TYPE': 6, - 'SOURCE_CRS': 'EPSG:3111', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -s_srs EPSG:3111 -dstnodata 0.0 -r near -ot Float32 -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "NODATA": 0, + "DATA_TYPE": 6, + "SOURCE_CRS": "EPSG:3111", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -s_srs EPSG:3111 -dstnodata 0.0 -r near -ot Float32 -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with target using EPSG self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SOURCE_CRS': 'EPSG:3111', - 'TARGET_CRS': 'EPSG:4326', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -s_srs EPSG:3111 -t_srs EPSG:4326 -r near -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "SOURCE_CRS": "EPSG:3111", + "TARGET_CRS": "EPSG:4326", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -s_srs EPSG:3111 -t_srs EPSG:4326 -r near -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with target using proj string - custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs' - self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SOURCE_CRS': custom_crs, - 'TARGET_CRS': custom_crs, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -s_srs EPSG:20936 -t_srs EPSG:20936 -r near -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source, + "SOURCE_CRS": custom_crs, + "TARGET_CRS": custom_crs, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -s_srs EPSG:20936 -t_srs EPSG:20936 -r near -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with target using custom projection - custom_crs, expected_crs_string = self.get_param_value_and_expected_string_for_custom_crs('+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs') - self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SOURCE_CRS': custom_crs, - 'TARGET_CRS': custom_crs, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - f'-overwrite -s_srs "{expected_crs_string}" -t_srs "{expected_crs_string}" -r near -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + custom_crs, expected_crs_string = ( + self.get_param_value_and_expected_string_for_custom_crs( + "+proj=utm +zone=36 +south +a=63785 +b=6357 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" + ) + ) + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source, + "SOURCE_CRS": custom_crs, + "TARGET_CRS": custom_crs, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + f'-overwrite -s_srs "{expected_crs_string}" -t_srs "{expected_crs_string}" -r near -of JPEG ' + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with target using custom projection and user-defined extent - custom_crs2, expected_crs_string2 = self.get_param_value_and_expected_string_for_custom_crs('+proj=longlat +a=6378388 +b=6356912 +no_defs') - self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SOURCE_CRS': custom_crs2, - 'TARGET_CRS': custom_crs2, - 'TARGET_EXTENT': '18.67,18.70,45.78,45.81', - 'TARGET_EXTENT_CRS': custom_crs2, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdalwarp', - f'-overwrite -s_srs "{expected_crs_string2}" -t_srs "{expected_crs_string2}" -r near -te 18.67 45.78 18.7 45.81 -te_srs "{expected_crs_string2}" -of GTiff ' + - source + ' ' + - outdir + '/check.tif']) + custom_crs2, expected_crs_string2 = ( + self.get_param_value_and_expected_string_for_custom_crs( + "+proj=longlat +a=6378388 +b=6356912 +no_defs" + ) + ) + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source, + "SOURCE_CRS": custom_crs2, + "TARGET_CRS": custom_crs2, + "TARGET_EXTENT": "18.67,18.70,45.78,45.81", + "TARGET_EXTENT_CRS": custom_crs2, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdalwarp", + f'-overwrite -s_srs "{expected_crs_string2}" -t_srs "{expected_crs_string2}" -r near -te 18.67 45.78 18.7 45.81 -te_srs "{expected_crs_string2}" -of GTiff ' + + source + + " " + + outdir + + "/check.tif", + ], + ) # with non-EPSG crs code self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SOURCE_CRS': 'POSTGIS:3111', - 'TARGET_CRS': 'POSTGIS:3111', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -s_srs EPSG:3111 -t_srs EPSG:3111 -r near -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "SOURCE_CRS": "POSTGIS:3111", + "TARGET_CRS": "POSTGIS:3111", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -s_srs EPSG:3111 -t_srs EPSG:3111 -r near -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with target resolution with None value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SOURCE_CRS': 'EPSG:3111', - 'TARGET_RESOLUTION': None, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -s_srs EPSG:3111 -r near -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "SOURCE_CRS": "EPSG:3111", + "TARGET_RESOLUTION": None, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -s_srs EPSG:3111 -r near -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # test target resolution with a valid value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SOURCE_CRS': 'EPSG:3111', - 'TARGET_RESOLUTION': 10.0, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -s_srs EPSG:3111 -tr 10.0 10.0 -r near -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "SOURCE_CRS": "EPSG:3111", + "TARGET_RESOLUTION": 10.0, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -s_srs EPSG:3111 -tr 10.0 10.0 -r near -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # test target resolution with a value of zero, to be ignored self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SOURCE_CRS': 'EPSG:3111', - 'TARGET_RESOLUTION': 0.0, - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -s_srs EPSG:3111 -r near -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) + alg.getConsoleCommands( + { + "INPUT": source, + "SOURCE_CRS": "EPSG:3111", + "TARGET_RESOLUTION": 0.0, + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -s_srs EPSG:3111 -r near -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) # with additional command-line parameter self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'EXTRA': '-dstalpha', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -r near -of JPEG -dstalpha ' + - source + ' ' + - outdir + '/check.jpg']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'EXTRA': '-dstalpha -srcnodata -9999', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -r near -of JPEG -dstalpha -srcnodata -9999 ' + - source + ' ' + - outdir + '/check.jpg']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'EXTRA': '-dstalpha -srcnodata "-9999 -8888"', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -r near -of JPEG -dstalpha -srcnodata "-9999 -8888" ' + - source + ' ' + - outdir + '/check.jpg']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'EXTRA': '', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -r near -of JPEG ' + - source + ' ' + - outdir + '/check.jpg']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'SOURCE_CRS': 'EPSG:3111', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -s_srs EPSG:3111 -r near -of JPEG ' + - source + ' ' + - outdir + '/check.jpg -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'SOURCE_CRS': 'EPSG:3111', - 'OUTPUT': outdir + '/check.jpg'}, context, feedback), - ['gdalwarp', - '-overwrite -s_srs EPSG:3111 -r near -of JPEG ' + - source + ' ' + - outdir + '/check.jpg --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source, + "EXTRA": "-dstalpha", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -r near -of JPEG -dstalpha " + + source + + " " + + outdir + + "/check.jpg", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source, + "EXTRA": "-dstalpha -srcnodata -9999", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -r near -of JPEG -dstalpha -srcnodata -9999 " + + source + + " " + + outdir + + "/check.jpg", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source, + "EXTRA": '-dstalpha -srcnodata "-9999 -8888"', + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + '-overwrite -r near -of JPEG -dstalpha -srcnodata "-9999 -8888" ' + + source + + " " + + outdir + + "/check.jpg", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + {"INPUT": source, "EXTRA": "", "OUTPUT": outdir + "/check.jpg"}, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -r near -of JPEG " + + source + + " " + + outdir + + "/check.jpg", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "SOURCE_CRS": "EPSG:3111", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -s_srs EPSG:3111 -r near -of JPEG " + + source + + " " + + outdir + + "/check.jpg -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "SOURCE_CRS": "EPSG:3111", + "OUTPUT": outdir + "/check.jpg", + }, + context, + feedback, + ), + [ + "gdalwarp", + "-overwrite -s_srs EPSG:3111 -r near -of JPEG " + + source + + " " + + outdir + + "/check.jpg --config X Y --config Z A", + ], + ) def testMerge(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = [os.path.join(testDataPath, 'dem1.tif'), os.path.join(testDataPath, 'dem1.tif')] + source = [ + os.path.join(testDataPath, "dem1.tif"), + os.path.join(testDataPath, "dem1.tif"), + ] alg = merge() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: # this algorithm creates temporary text file with input layers # so we strip its path, leaving only filename - cmd = alg.getConsoleCommands({'INPUT': source, - 'OUTPUT': outdir + '/check.tif'}, context, feedback) + cmd = alg.getConsoleCommands( + {"INPUT": source, "OUTPUT": outdir + "/check.tif"}, context, feedback + ) t = cmd[1] - cmd[1] = t[:t.find('--optfile') + 10] + t[t.find('mergeInputFiles.txt'):] - self.assertEqual(cmd, - ['gdal_merge.py', - '-ot Float32 -of GTiff ' + - '-o ' + outdir + '/check.tif ' + - '--optfile mergeInputFiles.txt']) + cmd[1] = t[: t.find("--optfile") + 10] + t[t.find("mergeInputFiles.txt") :] + self.assertEqual( + cmd, + [ + "gdal_merge.py", + "-ot Float32 -of GTiff " + + "-o " + + outdir + + "/check.tif " + + "--optfile mergeInputFiles.txt", + ], + ) # separate - cmd = alg.getConsoleCommands({'INPUT': source, - 'SEPARATE': True, - 'OUTPUT': outdir + '/check.tif'}, context, feedback) + cmd = alg.getConsoleCommands( + {"INPUT": source, "SEPARATE": True, "OUTPUT": outdir + "/check.tif"}, + context, + feedback, + ) t = cmd[1] - cmd[1] = t[:t.find('--optfile') + 10] + t[t.find('mergeInputFiles.txt'):] - self.assertEqual(cmd, - ['gdal_merge.py', - '-separate -ot Float32 -of GTiff ' + - '-o ' + outdir + '/check.tif ' + - '--optfile mergeInputFiles.txt']) + cmd[1] = t[: t.find("--optfile") + 10] + t[t.find("mergeInputFiles.txt") :] + self.assertEqual( + cmd, + [ + "gdal_merge.py", + "-separate -ot Float32 -of GTiff " + + "-o " + + outdir + + "/check.tif " + + "--optfile mergeInputFiles.txt", + ], + ) # assign nodata - cmd = alg.getConsoleCommands({'INPUT': source, - 'EXTRA': '-tap -ps 0.1 0.1', - 'OUTPUT': outdir + '/check.tif'}, context, feedback) + cmd = alg.getConsoleCommands( + { + "INPUT": source, + "EXTRA": "-tap -ps 0.1 0.1", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ) t = cmd[1] - cmd[1] = t[:t.find('--optfile') + 10] + t[t.find('mergeInputFiles.txt'):] - self.assertEqual(cmd, - ['gdal_merge.py', - '-ot Float32 -of GTiff -tap -ps 0.1 0.1 ' + - '-o ' + outdir + '/check.tif ' + - '--optfile mergeInputFiles.txt']) + cmd[1] = t[: t.find("--optfile") + 10] + t[t.find("mergeInputFiles.txt") :] + self.assertEqual( + cmd, + [ + "gdal_merge.py", + "-ot Float32 -of GTiff -tap -ps 0.1 0.1 " + + "-o " + + outdir + + "/check.tif " + + "--optfile mergeInputFiles.txt", + ], + ) # additional parameters - cmd = alg.getConsoleCommands({'INPUT': source, - 'NODATA_OUTPUT': -9999, - 'OUTPUT': outdir + '/check.tif'}, context, feedback) + cmd = alg.getConsoleCommands( + { + "INPUT": source, + "NODATA_OUTPUT": -9999, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ) t = cmd[1] - cmd[1] = t[:t.find('--optfile') + 10] + t[t.find('mergeInputFiles.txt'):] - self.assertEqual(cmd, - ['gdal_merge.py', - '-a_nodata -9999.0 -ot Float32 -of GTiff ' + - '-o ' + outdir + '/check.tif ' + - '--optfile mergeInputFiles.txt']) + cmd[1] = t[: t.find("--optfile") + 10] + t[t.find("mergeInputFiles.txt") :] + self.assertEqual( + cmd, + [ + "gdal_merge.py", + "-a_nodata -9999.0 -ot Float32 -of GTiff " + + "-o " + + outdir + + "/check.tif " + + "--optfile mergeInputFiles.txt", + ], + ) def testNearblack(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") alg = nearblack() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: # defaults self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['nearblack', - source + ' -of GTiff -o ' + outdir + '/check.tif ' + - '-near 15']) + alg.getConsoleCommands( + {"INPUT": source, "OUTPUT": outdir + "/check.tif"}, + context, + feedback, + ), + [ + "nearblack", + source + " -of GTiff -o " + outdir + "/check.tif " + "-near 15", + ], + ) # search white pixels self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'WHITE': True, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['nearblack', - source + ' -of GTiff -o ' + outdir + '/check.tif ' + - '-near 15 -white']) + alg.getConsoleCommands( + {"INPUT": source, "WHITE": True, "OUTPUT": outdir + "/check.tif"}, + context, + feedback, + ), + [ + "nearblack", + source + + " -of GTiff -o " + + outdir + + "/check.tif " + + "-near 15 -white", + ], + ) # additional parameters self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'EXTRA': '-nb 5 -setalpha', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['nearblack', - source + ' -of GTiff -o ' + outdir + '/check.tif ' + - '-near 15 -nb 5 -setalpha']) + alg.getConsoleCommands( + { + "INPUT": source, + "EXTRA": "-nb 5 -setalpha", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "nearblack", + source + + " -of GTiff -o " + + outdir + + "/check.tif " + + "-near 15 -nb 5 -setalpha", + ], + ) # additional parameters and creation options self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OPTIONS': 'COMPRESS=JPEG|JPEG_QUALITY=75', - 'EXTRA': '-nb 5 -setalpha', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['nearblack', - source + ' -of GTiff -o ' + outdir + '/check.tif ' + - '-near 15 -co COMPRESS=JPEG -co JPEG_QUALITY=75 -nb 5 -setalpha']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['nearblack', - source + ' -of GTiff -o ' + outdir + '/check.tif ' + - '-near 15 --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source, + "OPTIONS": "COMPRESS=JPEG|JPEG_QUALITY=75", + "EXTRA": "-nb 5 -setalpha", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "nearblack", + source + + " -of GTiff -o " + + outdir + + "/check.tif " + + "-near 15 -co COMPRESS=JPEG -co JPEG_QUALITY=75 -nb 5 -setalpha", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "nearblack", + source + + " -of GTiff -o " + + outdir + + "/check.tif " + + "-near 15 --config X Y --config Z A", + ], + ) def testRearrangeBands(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") with tempfile.TemporaryDirectory() as outdir: - outsource = outdir + '/check.tif' + outsource = outdir + "/check.tif" alg = rearrange_bands() alg.initAlgorithm() # single band self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BANDS': 1, - 'OUTPUT': outsource}, context, feedback), - ['gdal_translate', '-b 1 ' + - '-of GTiff ' + - source + ' ' + outsource]) + alg.getConsoleCommands( + {"INPUT": source, "BANDS": 1, "OUTPUT": outsource}, + context, + feedback, + ), + ["gdal_translate", "-b 1 " + "-of GTiff " + source + " " + outsource], + ) # three bands, re-ordered self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BANDS': [3, 2, 1], - 'OUTPUT': outsource}, context, feedback), - ['gdal_translate', '-b 3 -b 2 -b 1 ' + - '-of GTiff ' + - source + ' ' + outsource]) + alg.getConsoleCommands( + {"INPUT": source, "BANDS": [3, 2, 1], "OUTPUT": outsource}, + context, + feedback, + ), + [ + "gdal_translate", + "-b 3 -b 2 -b 1 " + "-of GTiff " + source + " " + outsource, + ], + ) # three bands, re-ordered with custom data type self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BANDS': [3, 2, 1], - 'DATA_TYPE': 6, - 'OUTPUT': outsource}, context, feedback), - ['gdal_translate', '-b 3 -b 2 -b 1 ' + - '-ot Float32 -of GTiff ' + - source + ' ' + outsource]) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'BANDS': 1, - 'OUTPUT': outsource}, context, feedback), - ['gdal_translate', '-b 1 ' + - '-of GTiff ' + - source + ' ' + outsource + ' -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'BANDS': 1, - 'OUTPUT': outsource}, context, feedback), - ['gdal_translate', '-b 1 ' + - '-of GTiff ' + - source + ' ' + outsource + ' --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source, + "BANDS": [3, 2, 1], + "DATA_TYPE": 6, + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_translate", + "-b 3 -b 2 -b 1 " + + "-ot Float32 -of GTiff " + + source + + " " + + outsource, + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "BANDS": 1, + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_translate", + "-b 1 " + + "-of GTiff " + + source + + " " + + outsource + + " -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "BANDS": 1, + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_translate", + "-b 1 " + + "-of GTiff " + + source + + " " + + outsource + + " --config X Y --config Z A", + ], + ) def testFillnodata(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') - mask = os.path.join(testDataPath, 'raster.tif') + source = os.path.join(testDataPath, "dem.tif") + mask = os.path.join(testDataPath, "raster.tif") with tempfile.TemporaryDirectory() as outdir: - outsource = outdir + '/check.tif' + outsource = outdir + "/check.tif" alg = fillnodata() alg.initAlgorithm() # with mask value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'DISTANCE': 10, - 'ITERATIONS': 0, - 'MASK_LAYER': mask, - 'NO_MASK': False, - 'OUTPUT': outsource}, context, feedback), - ['gdal_fillnodata.py', - f'{source} {outsource} -md 10 -b 1 -mask {mask} -of GTiff']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "DISTANCE": 10, + "ITERATIONS": 0, + "MASK_LAYER": mask, + "NO_MASK": False, + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_fillnodata.py", + f"{source} {outsource} -md 10 -b 1 -mask {mask} -of GTiff", + ], + ) # without mask value self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'DISTANCE': 10, - 'ITERATIONS': 0, - 'NO_MASK': False, - 'OUTPUT': outsource}, context, feedback), - ['gdal_fillnodata.py', - f'{source} {outsource} -md 10 -b 1 -of GTiff']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "DISTANCE": 10, + "ITERATIONS": 0, + "NO_MASK": False, + "OUTPUT": outsource, + }, + context, + feedback, + ), + ["gdal_fillnodata.py", f"{source} {outsource} -md 10 -b 1 -of GTiff"], + ) # The -nomask option is no longer supported since GDAL 3.4 and # it doesn't work as expected even using GDAL < 3.4 https://github.com/OSGeo/gdal/pull/4201 # Silently ignore the NO_MASK parameter self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'DISTANCE': 10, - 'ITERATIONS': 0, - 'NO_MASK': True, - 'OUTPUT': outsource}, context, feedback), - ['gdal_fillnodata.py', - f'{source} {outsource} -md 10 -b 1 -of GTiff']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "DISTANCE": 10, + "ITERATIONS": 0, + "NO_MASK": True, + "OUTPUT": outsource, + }, + context, + feedback, + ), + ["gdal_fillnodata.py", f"{source} {outsource} -md 10 -b 1 -of GTiff"], + ) # creation options self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'OPTIONS': 'COMPRESS=JPEG|JPEG_QUALITY=75', - 'OUTPUT': outsource}, context, feedback), - ['gdal_fillnodata.py', - f'{source} {outsource} -md 10 -b 1 -of GTiff -co COMPRESS=JPEG -co JPEG_QUALITY=75']) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "OPTIONS": "COMPRESS=JPEG|JPEG_QUALITY=75", + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_fillnodata.py", + f"{source} {outsource} -md 10 -b 1 -of GTiff -co COMPRESS=JPEG -co JPEG_QUALITY=75", + ], + ) # additional parameters self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'EXTRA': '-q', - 'OUTPUT': outsource}, context, feedback), - ['gdal_fillnodata.py', - f'{source} {outsource} -md 10 -b 1 -of GTiff -q']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'BAND': 1, - 'DISTANCE': 10, - 'ITERATIONS': 0, - 'MASK_LAYER': mask, - 'NO_MASK': False, - 'OUTPUT': outsource}, context, feedback), - ['gdal_fillnodata.py', - f'{source} {outsource} -md 10 -b 1 -mask {mask} -of GTiff --config X Y --config Z A']) + alg.getConsoleCommands( + {"INPUT": source, "BAND": 1, "EXTRA": "-q", "OUTPUT": outsource}, + context, + feedback, + ), + [ + "gdal_fillnodata.py", + f"{source} {outsource} -md 10 -b 1 -of GTiff -q", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "BAND": 1, + "DISTANCE": 10, + "ITERATIONS": 0, + "MASK_LAYER": mask, + "NO_MASK": False, + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_fillnodata.py", + f"{source} {outsource} -md 10 -b 1 -mask {mask} -of GTiff --config X Y --config Z A", + ], + ) def testGdalAddo(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") with tempfile.TemporaryDirectory() as outdir: alg = gdaladdo() @@ -2742,705 +4809,1231 @@ def testGdalAddo(self): # defaults self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'LEVELS': '2 4 8 16', - 'CLEAN': False, - 'RESAMPLING': 0, - 'FORMAT': 0}, context, feedback), - ['gdaladdo', - source + ' ' + '-r nearest 2 4 8 16']) + alg.getConsoleCommands( + { + "INPUT": source, + "LEVELS": "2 4 8 16", + "CLEAN": False, + "RESAMPLING": 0, + "FORMAT": 0, + }, + context, + feedback, + ), + ["gdaladdo", source + " " + "-r nearest 2 4 8 16"], + ) # with "clean" option self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'LEVELS': '2 4 8 16', - 'CLEAN': True, - 'RESAMPLING': 0, - 'FORMAT': 0}, context, feedback), - ['gdaladdo', - source + ' ' + '-r nearest -clean 2 4 8 16']) + alg.getConsoleCommands( + { + "INPUT": source, + "LEVELS": "2 4 8 16", + "CLEAN": True, + "RESAMPLING": 0, + "FORMAT": 0, + }, + context, + feedback, + ), + ["gdaladdo", source + " " + "-r nearest -clean 2 4 8 16"], + ) # ovr format self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'LEVELS': '2 4 8 16', - 'CLEAN': False, - 'RESAMPLING': 0, - 'FORMAT': 1}, context, feedback), - ['gdaladdo', - source + ' ' + '-r nearest -ro 2 4 8 16']) + alg.getConsoleCommands( + { + "INPUT": source, + "LEVELS": "2 4 8 16", + "CLEAN": False, + "RESAMPLING": 0, + "FORMAT": 1, + }, + context, + feedback, + ), + ["gdaladdo", source + " " + "-r nearest -ro 2 4 8 16"], + ) # Erdas format self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'LEVELS': '2 4 8 16', - 'CLEAN': False, - 'RESAMPLING': 0, - 'FORMAT': 2}, context, feedback), - ['gdaladdo', - source + ' ' + '-r nearest --config USE_RRD YES 2 4 8 16']) + alg.getConsoleCommands( + { + "INPUT": source, + "LEVELS": "2 4 8 16", + "CLEAN": False, + "RESAMPLING": 0, + "FORMAT": 2, + }, + context, + feedback, + ), + ["gdaladdo", source + " " + "-r nearest --config USE_RRD YES 2 4 8 16"], + ) # custom resampling method format self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'LEVELS': '2 4 8 16', - 'CLEAN': False, - 'RESAMPLING': 4, - 'FORMAT': 0}, context, feedback), - ['gdaladdo', - source + ' ' + '-r cubicspline 2 4 8 16']) + alg.getConsoleCommands( + { + "INPUT": source, + "LEVELS": "2 4 8 16", + "CLEAN": False, + "RESAMPLING": 4, + "FORMAT": 0, + }, + context, + feedback, + ), + ["gdaladdo", source + " " + "-r cubicspline 2 4 8 16"], + ) # more levels self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'LEVELS': '2 4 8 16 32 64', - 'CLEAN': False, - 'RESAMPLING': 0, - 'FORMAT': 0}, context, feedback), - ['gdaladdo', - source + ' ' + '-r nearest 2 4 8 16 32 64']) + alg.getConsoleCommands( + { + "INPUT": source, + "LEVELS": "2 4 8 16 32 64", + "CLEAN": False, + "RESAMPLING": 0, + "FORMAT": 0, + }, + context, + feedback, + ), + ["gdaladdo", source + " " + "-r nearest 2 4 8 16 32 64"], + ) # additional parameters self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'LEVELS': '2 4 8 16', - 'CLEAN': False, - 'EXTRA': '--config COMPRESS_OVERVIEW JPEG'}, context, feedback), - ['gdaladdo', - source + ' ' + '--config COMPRESS_OVERVIEW JPEG 2 4 8 16']) + alg.getConsoleCommands( + { + "INPUT": source, + "LEVELS": "2 4 8 16", + "CLEAN": False, + "EXTRA": "--config COMPRESS_OVERVIEW JPEG", + }, + context, + feedback, + ), + ["gdaladdo", source + " " + "--config COMPRESS_OVERVIEW JPEG 2 4 8 16"], + ) if GdalUtils.version() >= 230000: # without levels self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'CLEAN': False}, context, feedback), - ['gdaladdo', - source]) + alg.getConsoleCommands( + {"INPUT": source, "CLEAN": False}, context, feedback + ), + ["gdaladdo", source], + ) # without advanced params self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'LEVELS': '2 4 8 16', - 'CLEAN': False}, context, feedback), - ['gdaladdo', - source + ' ' + '2 4 8 16']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'LEVELS': '2 4 8 16', - 'CLEAN': False, - 'RESAMPLING': 0, - 'FORMAT': 0}, context, feedback), - ['gdaladdo', - source + ' ' + '-r nearest 2 4 8 16 --config X Y --config Z A']) + alg.getConsoleCommands( + {"INPUT": source, "LEVELS": "2 4 8 16", "CLEAN": False}, + context, + feedback, + ), + ["gdaladdo", source + " " + "2 4 8 16"], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "LEVELS": "2 4 8 16", + "CLEAN": False, + "RESAMPLING": 0, + "FORMAT": 0, + }, + context, + feedback, + ), + [ + "gdaladdo", + source + " " + "-r nearest 2 4 8 16 --config X Y --config Z A", + ], + ) def testSieve(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') - mask = os.path.join(testDataPath, 'raster.tif') + source = os.path.join(testDataPath, "dem.tif") + mask = os.path.join(testDataPath, "raster.tif") with tempfile.TemporaryDirectory() as outdir: - outsource = outdir + '/check.tif' + outsource = outdir + "/check.tif" alg = sieve() alg.initAlgorithm() # defaults self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OUTPUT': outsource}, context, feedback), - ['gdal_sieve.py', - '-st 10 -4 -of GTiff ' + - source + ' ' + - outsource]) + alg.getConsoleCommands( + {"INPUT": source, "OUTPUT": outsource}, context, feedback + ), + ["gdal_sieve.py", "-st 10 -4 -of GTiff " + source + " " + outsource], + ) # Eight connectedness and custom threshold self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'THRESHOLD': 16, - 'EIGHT_CONNECTEDNESS': True, - 'OUTPUT': outsource}, context, feedback), - ['gdal_sieve.py', - '-st 16 -8 -of GTiff ' + - source + ' ' + - outsource]) + alg.getConsoleCommands( + { + "INPUT": source, + "THRESHOLD": 16, + "EIGHT_CONNECTEDNESS": True, + "OUTPUT": outsource, + }, + context, + feedback, + ), + ["gdal_sieve.py", "-st 16 -8 -of GTiff " + source + " " + outsource], + ) # without default mask layer self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NO_MASK': True, - 'OUTPUT': outsource}, context, feedback), - ['gdal_sieve.py', - '-st 10 -4 -nomask -of GTiff ' + - source + ' ' + - outsource]) + alg.getConsoleCommands( + {"INPUT": source, "NO_MASK": True, "OUTPUT": outsource}, + context, + feedback, + ), + [ + "gdal_sieve.py", + "-st 10 -4 -nomask -of GTiff " + source + " " + outsource, + ], + ) # defaults with external validity mask self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'MASK_LAYER': mask, - 'OUTPUT': outsource}, context, feedback), - ['gdal_sieve.py', - '-st 10 -4 -mask ' + - mask + - ' -of GTiff ' + - source + ' ' + - outsource]) + alg.getConsoleCommands( + {"INPUT": source, "MASK_LAYER": mask, "OUTPUT": outsource}, + context, + feedback, + ), + [ + "gdal_sieve.py", + "-st 10 -4 -mask " + + mask + + " -of GTiff " + + source + + " " + + outsource, + ], + ) # additional parameters self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'EXTRA': '-q', - 'OUTPUT': outsource}, context, feedback), - ['gdal_sieve.py', - '-st 10 -4 -of GTiff -q ' + - source + ' ' + - outsource]) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'OUTPUT': outsource}, context, feedback), - ['gdal_sieve.py', - '-st 10 -4 -of GTiff ' + - source + ' ' + - outsource + ' --config X Y --config Z A']) + alg.getConsoleCommands( + {"INPUT": source, "EXTRA": "-q", "OUTPUT": outsource}, + context, + feedback, + ), + ["gdal_sieve.py", "-st 10 -4 -of GTiff -q " + source + " " + outsource], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_sieve.py", + "-st 10 -4 -of GTiff " + + source + + " " + + outsource + + " --config X Y --config Z A", + ], + ) def testGdal2Xyz(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") with tempfile.TemporaryDirectory() as outdir: - outsource = outdir + '/check.csv' + outsource = outdir + "/check.csv" alg = gdal2xyz() alg.initAlgorithm() # defaults self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'CSV': False, - 'OUTPUT': outsource}, context, feedback), - ['gdal2xyz.py', - '-band 1 ' + - source + ' ' + - outsource]) + alg.getConsoleCommands( + {"INPUT": source, "BAND": 1, "CSV": False, "OUTPUT": outsource}, + context, + feedback, + ), + ["gdal2xyz.py", "-band 1 " + source + " " + outsource], + ) # csv output self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'CSV': True, - 'OUTPUT': outsource}, context, feedback), - ['gdal2xyz.py', - '-band 1 -csv ' + - source + ' ' + - outsource]) + alg.getConsoleCommands( + {"INPUT": source, "BAND": 1, "CSV": True, "OUTPUT": outsource}, + context, + feedback, + ), + ["gdal2xyz.py", "-band 1 -csv " + source + " " + outsource], + ) if GdalUtils.version() >= 3030000: # skip nodata output self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'CSV': False, - 'SKIP_NODATA': True, - 'OUTPUT': outsource}, context, feedback), - ['gdal2xyz.py', - '-band 1 -skipnodata ' + - source + ' ' + - outsource]) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "CSV": False, + "SKIP_NODATA": True, + "OUTPUT": outsource, + }, + context, + feedback, + ), + ["gdal2xyz.py", "-band 1 -skipnodata " + source + " " + outsource], + ) if GdalUtils.version() > 3060300: # srcnodata output self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'CSV': False, - 'NODATA_INPUT': -999, - 'SKIP_NODATA': False, - 'OUTPUT': outsource}, context, feedback), - ['gdal2xyz.py', - '-band 1 -srcnodata -999.0 ' + - source + ' ' + - outsource]) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "CSV": False, + "NODATA_INPUT": -999, + "SKIP_NODATA": False, + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal2xyz.py", + "-band 1 -srcnodata -999.0 " + source + " " + outsource, + ], + ) # dstnodata output self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'CSV': False, - 'NODATA_OUTPUT': -999, - 'SKIP_NODATA': False, - 'OUTPUT': outsource}, context, feedback), - ['gdal2xyz.py', - '-band 1 -dstnodata -999.0 ' + - source + ' ' + - outsource]) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "CSV": False, + "NODATA_OUTPUT": -999, + "SKIP_NODATA": False, + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal2xyz.py", + "-band 1 -dstnodata -999.0 " + source + " " + outsource, + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'BAND': 1, - 'CSV': False, - 'OUTPUT': outsource}, context, - feedback), - ['gdal2xyz.py', - '-band 1 ' + - source + ' ' + - outsource + ' --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "BAND": 1, + "CSV": False, + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal2xyz.py", + "-band 1 " + + source + + " " + + outsource + + " --config X Y --config Z A", + ], + ) def testGdalPolygonize(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") with tempfile.TemporaryDirectory() as outdir: - outsource = outdir + '/check.shp' + outsource = outdir + "/check.shp" alg = polygonize() alg.initAlgorithm() # defaults self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'FIELD': 'DN', - 'EIGHT_CONNECTEDNESS': False, - 'OUTPUT': outsource}, context, feedback), - ['gdal_polygonize.py', - source + ' ' + - '-b 1 -f "ESRI Shapefile"' + ' ' + outsource + ' ' + 'check DN' - ]) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'FIELD': 'VAL', - 'EIGHT_CONNECTEDNESS': False, - 'OUTPUT': outsource}, context, feedback), - ['gdal_polygonize.py', - source + ' ' + - '-b 1 -f "ESRI Shapefile"' + ' ' + outsource + ' ' + 'check VAL' - ]) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "FIELD": "DN", + "EIGHT_CONNECTEDNESS": False, + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_polygonize.py", + source + + " " + + '-b 1 -f "ESRI Shapefile"' + + " " + + outsource + + " " + + "check DN", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "FIELD": "VAL", + "EIGHT_CONNECTEDNESS": False, + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_polygonize.py", + source + + " " + + '-b 1 -f "ESRI Shapefile"' + + " " + + outsource + + " " + + "check VAL", + ], + ) # 8 connectedness self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'FIELD': 'DN', - 'EIGHT_CONNECTEDNESS': True, - 'OUTPUT': outsource}, context, feedback), - ['gdal_polygonize.py', - '-8' + ' ' + source + ' ' + - '-b 1 -f "ESRI Shapefile"' + ' ' + outsource + ' ' + 'check DN' - ]) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "FIELD": "DN", + "EIGHT_CONNECTEDNESS": True, + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_polygonize.py", + "-8" + + " " + + source + + " " + + '-b 1 -f "ESRI Shapefile"' + + " " + + outsource + + " " + + "check DN", + ], + ) # custom output format - outsource = outdir + '/check.gpkg' - self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'FIELD': 'DN', - 'EIGHT_CONNECTEDNESS': False, - 'OUTPUT': outsource}, context, feedback), - ['gdal_polygonize.py', - source + ' ' + - '-b 1 -f "GPKG"' + ' ' + outsource + ' ' + 'check DN' - ]) + outsource = outdir + "/check.gpkg" + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "FIELD": "DN", + "EIGHT_CONNECTEDNESS": False, + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_polygonize.py", + source + + " " + + '-b 1 -f "GPKG"' + + " " + + outsource + + " " + + "check DN", + ], + ) # additional parameters self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 1, - 'FIELD': 'DN', - 'EXTRA': '-nomask -q', - 'OUTPUT': outsource}, context, feedback), - ['gdal_polygonize.py', - '-nomask -q' + ' ' + source + ' ' + - '-b 1 -f "GPKG"' + ' ' + outsource + ' ' + 'check DN' - ]) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'BAND': 1, - 'FIELD': 'DN', - 'EIGHT_CONNECTEDNESS': False, - 'OUTPUT': outsource}, context, feedback), - ['gdal_polygonize.py', - source + ' ' + - '-b 1 -f "GPKG"' + ' ' + outsource + ' ' + 'check DN --config X Y --config Z A' - ]) + alg.getConsoleCommands( + { + "INPUT": source, + "BAND": 1, + "FIELD": "DN", + "EXTRA": "-nomask -q", + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_polygonize.py", + "-nomask -q" + + " " + + source + + " " + + '-b 1 -f "GPKG"' + + " " + + outsource + + " " + + "check DN", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "BAND": 1, + "FIELD": "DN", + "EIGHT_CONNECTEDNESS": False, + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_polygonize.py", + source + + " " + + '-b 1 -f "GPKG"' + + " " + + outsource + + " " + + "check DN --config X Y --config Z A", + ], + ) def testGdalPansharpen(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - panchrom = os.path.join(testDataPath, 'dem.tif') - spectral = os.path.join(testDataPath, 'raster.tif') + panchrom = os.path.join(testDataPath, "dem.tif") + spectral = os.path.join(testDataPath, "raster.tif") with tempfile.TemporaryDirectory() as outdir: - outsource = outdir + '/out.tif' + outsource = outdir + "/out.tif" alg = pansharp() alg.initAlgorithm() # defaults self.assertEqual( - alg.getConsoleCommands({'SPECTRAL': spectral, - 'PANCHROMATIC': panchrom, - 'OUTPUT': outsource}, context, feedback), - ['gdal_pansharpen.py', - panchrom + ' ' + - spectral + ' ' + - outsource + ' ' + - '-r cubic -of GTiff' - ]) + alg.getConsoleCommands( + { + "SPECTRAL": spectral, + "PANCHROMATIC": panchrom, + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_pansharpen.py", + panchrom + + " " + + spectral + + " " + + outsource + + " " + + "-r cubic -of GTiff", + ], + ) # custom resampling self.assertEqual( - alg.getConsoleCommands({'SPECTRAL': spectral, - 'PANCHROMATIC': panchrom, - 'RESAMPLING': 4, - 'OUTPUT': outsource}, context, feedback), - ['gdal_pansharpen.py', - panchrom + ' ' + - spectral + ' ' + - outsource + ' ' + - '-r lanczos -of GTiff' - ]) + alg.getConsoleCommands( + { + "SPECTRAL": spectral, + "PANCHROMATIC": panchrom, + "RESAMPLING": 4, + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_pansharpen.py", + panchrom + + " " + + spectral + + " " + + outsource + + " " + + "-r lanczos -of GTiff", + ], + ) # additional parameters self.assertEqual( - alg.getConsoleCommands({'SPECTRAL': spectral, - 'PANCHROMATIC': panchrom, - 'EXTRA': '-bitdepth 12 -threads ALL_CPUS', - 'OUTPUT': outsource}, context, feedback), - ['gdal_pansharpen.py', - panchrom + ' ' + - spectral + ' ' + - outsource + ' ' + - '-r cubic -of GTiff -bitdepth 12 -threads ALL_CPUS' - ]) - - self.assertEqual( - alg.getConsoleCommands({'SPECTRAL': spectral, - 'PANCHROMATIC': panchrom + '|credential:X=Y|credential:Z=A', - 'OUTPUT': outsource}, context, feedback), - ['gdal_pansharpen.py', - panchrom + ' ' + - spectral + ' ' + - outsource + ' ' + - '-r cubic -of GTiff --config X Y --config Z A' - ]) + alg.getConsoleCommands( + { + "SPECTRAL": spectral, + "PANCHROMATIC": panchrom, + "EXTRA": "-bitdepth 12 -threads ALL_CPUS", + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_pansharpen.py", + panchrom + + " " + + spectral + + " " + + outsource + + " " + + "-r cubic -of GTiff -bitdepth 12 -threads ALL_CPUS", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "SPECTRAL": spectral, + "PANCHROMATIC": panchrom + "|credential:X=Y|credential:Z=A", + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_pansharpen.py", + panchrom + + " " + + spectral + + " " + + outsource + + " " + + "-r cubic -of GTiff --config X Y --config Z A", + ], + ) def testGdalViewshed(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - dem = os.path.join(testDataPath, 'dem.tif') + dem = os.path.join(testDataPath, "dem.tif") with tempfile.TemporaryDirectory() as outdir: - outsource = outdir + '/out.tif' + outsource = outdir + "/out.tif" alg = viewshed() alg.initAlgorithm() # defaults self.assertEqual( - alg.getConsoleCommands({'INPUT': dem, - 'BAND': 1, - 'OBSERVER': '18.67274,45.80599', - 'OUTPUT': outsource}, context, feedback), - ['gdal_viewshed', - '-b 1 -ox 18.67274 -oy 45.80599 -oz 1.0 -tz 1.0 -md 100.0 -f GTiff ' + - dem + ' ' + outsource - ]) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': dem, - 'BAND': 2, - 'OBSERVER': '18.67274,45.80599', - 'OBSERVER_HEIGHT': 1.8, - 'TARGET_HEIGHT': 20, - 'MAX_DISTANCE': 1000, - 'OUTPUT': outsource}, context, feedback), - ['gdal_viewshed', - '-b 2 -ox 18.67274 -oy 45.80599 -oz 1.8 -tz 20.0 -md 1000.0 -f GTiff ' + - dem + ' ' + outsource - ]) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': dem, - 'BAND': 1, - 'OBSERVER': '18.67274,45.80599', - 'EXTRA': '-a_nodata=-9999 -cc 0.2', - 'OUTPUT': outsource}, context, feedback), - ['gdal_viewshed', - '-b 1 -ox 18.67274 -oy 45.80599 -oz 1.0 -tz 1.0 -md 100.0 -f GTiff ' + - '-a_nodata=-9999 -cc 0.2 ' + dem + ' ' + outsource - ]) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': dem, - 'BAND': 1, - 'OBSERVER': '18.67274,45.80599', - 'OPTIONS': 'COMPRESS=DEFLATE|PREDICTOR=2|ZLEVEL=9', - 'OUTPUT': outsource}, context, feedback), - ['gdal_viewshed', - '-b 1 -ox 18.67274 -oy 45.80599 -oz 1.0 -tz 1.0 -md 100.0 -f GTiff ' + - '-co COMPRESS=DEFLATE -co PREDICTOR=2 -co ZLEVEL=9 ' + dem + ' ' + outsource - ]) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': dem + '|credential:X=Y|credential:Z=A', - 'BAND': 1, - 'OBSERVER': '18.67274,45.80599', - 'OUTPUT': outsource}, context, feedback), - ['gdal_viewshed', - '-b 1 -ox 18.67274 -oy 45.80599 -oz 1.0 -tz 1.0 -md 100.0 -f GTiff ' + - dem + ' ' + outsource + ' --config X Y --config Z A' - ]) + alg.getConsoleCommands( + { + "INPUT": dem, + "BAND": 1, + "OBSERVER": "18.67274,45.80599", + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_viewshed", + "-b 1 -ox 18.67274 -oy 45.80599 -oz 1.0 -tz 1.0 -md 100.0 -f GTiff " + + dem + + " " + + outsource, + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": dem, + "BAND": 2, + "OBSERVER": "18.67274,45.80599", + "OBSERVER_HEIGHT": 1.8, + "TARGET_HEIGHT": 20, + "MAX_DISTANCE": 1000, + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_viewshed", + "-b 2 -ox 18.67274 -oy 45.80599 -oz 1.8 -tz 20.0 -md 1000.0 -f GTiff " + + dem + + " " + + outsource, + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": dem, + "BAND": 1, + "OBSERVER": "18.67274,45.80599", + "EXTRA": "-a_nodata=-9999 -cc 0.2", + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_viewshed", + "-b 1 -ox 18.67274 -oy 45.80599 -oz 1.0 -tz 1.0 -md 100.0 -f GTiff " + + "-a_nodata=-9999 -cc 0.2 " + + dem + + " " + + outsource, + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": dem, + "BAND": 1, + "OBSERVER": "18.67274,45.80599", + "OPTIONS": "COMPRESS=DEFLATE|PREDICTOR=2|ZLEVEL=9", + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_viewshed", + "-b 1 -ox 18.67274 -oy 45.80599 -oz 1.0 -tz 1.0 -md 100.0 -f GTiff " + + "-co COMPRESS=DEFLATE -co PREDICTOR=2 -co ZLEVEL=9 " + + dem + + " " + + outsource, + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": dem + "|credential:X=Y|credential:Z=A", + "BAND": 1, + "OBSERVER": "18.67274,45.80599", + "OUTPUT": outsource, + }, + context, + feedback, + ), + [ + "gdal_viewshed", + "-b 1 -ox 18.67274 -oy 45.80599 -oz 1.0 -tz 1.0 -md 100.0 -f GTiff " + + dem + + " " + + outsource + + " --config X Y --config Z A", + ], + ) def testBuildVrt(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") alg = buildvrt() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: # defaults - cmd = alg.getConsoleCommands({'INPUT': [source], - 'OUTPUT': outdir + '/check.vrt'}, context, feedback) + cmd = alg.getConsoleCommands( + {"INPUT": [source], "OUTPUT": outdir + "/check.vrt"}, context, feedback + ) t = cmd[1] - cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):] - self.assertEqual(cmd, - ['gdalbuildvrt', - '-overwrite -resolution average -separate -r nearest ' + - '-input_file_list buildvrtInputFiles.txt ' + - outdir + '/check.vrt']) + cmd[1] = ( + t[: t.find("-input_file_list") + 17] + + t[t.find("buildvrtInputFiles.txt") :] + ) + self.assertEqual( + cmd, + [ + "gdalbuildvrt", + "-overwrite -resolution average -separate -r nearest " + + "-input_file_list buildvrtInputFiles.txt " + + outdir + + "/check.vrt", + ], + ) # custom resolution - cmd = alg.getConsoleCommands({'INPUT': [source], - 'RESOLUTION': 2, - 'OUTPUT': outdir + '/check.vrt'}, context, feedback) + cmd = alg.getConsoleCommands( + {"INPUT": [source], "RESOLUTION": 2, "OUTPUT": outdir + "/check.vrt"}, + context, + feedback, + ) t = cmd[1] - cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):] - self.assertEqual(cmd, - ['gdalbuildvrt', - '-overwrite -resolution lowest -separate -r nearest ' + - '-input_file_list buildvrtInputFiles.txt ' + - outdir + '/check.vrt']) + cmd[1] = ( + t[: t.find("-input_file_list") + 17] + + t[t.find("buildvrtInputFiles.txt") :] + ) + self.assertEqual( + cmd, + [ + "gdalbuildvrt", + "-overwrite -resolution lowest -separate -r nearest " + + "-input_file_list buildvrtInputFiles.txt " + + outdir + + "/check.vrt", + ], + ) # single layer - cmd = alg.getConsoleCommands({'INPUT': [source], - 'SEPARATE': False, - 'OUTPUT': outdir + '/check.vrt'}, context, feedback) + cmd = alg.getConsoleCommands( + {"INPUT": [source], "SEPARATE": False, "OUTPUT": outdir + "/check.vrt"}, + context, + feedback, + ) t = cmd[1] - cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):] - self.assertEqual(cmd, - ['gdalbuildvrt', - '-overwrite -resolution average -r nearest ' + - '-input_file_list buildvrtInputFiles.txt ' + - outdir + '/check.vrt']) + cmd[1] = ( + t[: t.find("-input_file_list") + 17] + + t[t.find("buildvrtInputFiles.txt") :] + ) + self.assertEqual( + cmd, + [ + "gdalbuildvrt", + "-overwrite -resolution average -r nearest " + + "-input_file_list buildvrtInputFiles.txt " + + outdir + + "/check.vrt", + ], + ) # projection difference - cmd = alg.getConsoleCommands({'INPUT': [source], - 'PROJ_DIFFERENCE': True, - 'OUTPUT': outdir + '/check.vrt'}, context, feedback) + cmd = alg.getConsoleCommands( + { + "INPUT": [source], + "PROJ_DIFFERENCE": True, + "OUTPUT": outdir + "/check.vrt", + }, + context, + feedback, + ) t = cmd[1] - cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):] - self.assertEqual(cmd, - ['gdalbuildvrt', - '-overwrite -resolution average -separate -allow_projection_difference -r nearest ' + - '-input_file_list buildvrtInputFiles.txt ' + - outdir + '/check.vrt']) + cmd[1] = ( + t[: t.find("-input_file_list") + 17] + + t[t.find("buildvrtInputFiles.txt") :] + ) + self.assertEqual( + cmd, + [ + "gdalbuildvrt", + "-overwrite -resolution average -separate -allow_projection_difference -r nearest " + + "-input_file_list buildvrtInputFiles.txt " + + outdir + + "/check.vrt", + ], + ) # add alpha band - cmd = alg.getConsoleCommands({'INPUT': [source], - 'ADD_ALPHA': True, - 'OUTPUT': outdir + '/check.vrt'}, context, feedback) + cmd = alg.getConsoleCommands( + {"INPUT": [source], "ADD_ALPHA": True, "OUTPUT": outdir + "/check.vrt"}, + context, + feedback, + ) t = cmd[1] - cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):] - self.assertEqual(cmd, - ['gdalbuildvrt', - '-overwrite -resolution average -separate -addalpha -r nearest ' + - '-input_file_list buildvrtInputFiles.txt ' + - outdir + '/check.vrt']) + cmd[1] = ( + t[: t.find("-input_file_list") + 17] + + t[t.find("buildvrtInputFiles.txt") :] + ) + self.assertEqual( + cmd, + [ + "gdalbuildvrt", + "-overwrite -resolution average -separate -addalpha -r nearest " + + "-input_file_list buildvrtInputFiles.txt " + + outdir + + "/check.vrt", + ], + ) # assign CRS - cmd = alg.getConsoleCommands({'INPUT': [source], - 'ASSIGN_CRS': 'EPSG:3111', - 'OUTPUT': outdir + '/check.vrt'}, context, feedback) + cmd = alg.getConsoleCommands( + { + "INPUT": [source], + "ASSIGN_CRS": "EPSG:3111", + "OUTPUT": outdir + "/check.vrt", + }, + context, + feedback, + ) t = cmd[1] - cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):] - self.assertEqual(cmd, - ['gdalbuildvrt', - '-overwrite -resolution average -separate -a_srs EPSG:3111 -r nearest ' + - '-input_file_list buildvrtInputFiles.txt ' + - outdir + '/check.vrt']) - - custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs' - cmd = alg.getConsoleCommands({'INPUT': [source], - 'ASSIGN_CRS': custom_crs, - 'OUTPUT': outdir + '/check.vrt'}, context, feedback) + cmd[1] = ( + t[: t.find("-input_file_list") + 17] + + t[t.find("buildvrtInputFiles.txt") :] + ) + self.assertEqual( + cmd, + [ + "gdalbuildvrt", + "-overwrite -resolution average -separate -a_srs EPSG:3111 -r nearest " + + "-input_file_list buildvrtInputFiles.txt " + + outdir + + "/check.vrt", + ], + ) + + custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" + cmd = alg.getConsoleCommands( + { + "INPUT": [source], + "ASSIGN_CRS": custom_crs, + "OUTPUT": outdir + "/check.vrt", + }, + context, + feedback, + ) t = cmd[1] - cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):] - self.assertEqual(cmd, - ['gdalbuildvrt', - '-overwrite -resolution average -separate -a_srs EPSG:20936 -r nearest ' + - '-input_file_list buildvrtInputFiles.txt ' + - outdir + '/check.vrt']) + cmd[1] = ( + t[: t.find("-input_file_list") + 17] + + t[t.find("buildvrtInputFiles.txt") :] + ) + self.assertEqual( + cmd, + [ + "gdalbuildvrt", + "-overwrite -resolution average -separate -a_srs EPSG:20936 -r nearest " + + "-input_file_list buildvrtInputFiles.txt " + + outdir + + "/check.vrt", + ], + ) # source NODATA - cmd = alg.getConsoleCommands({'INPUT': [source], - 'SRC_NODATA': '-9999', - 'OUTPUT': outdir + '/check.vrt'}, context, feedback) + cmd = alg.getConsoleCommands( + { + "INPUT": [source], + "SRC_NODATA": "-9999", + "OUTPUT": outdir + "/check.vrt", + }, + context, + feedback, + ) t = cmd[1] - cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):] - self.assertEqual(cmd, - ['gdalbuildvrt', - '-overwrite -resolution average -separate -r nearest -srcnodata -9999 ' + - '-input_file_list buildvrtInputFiles.txt ' + - outdir + '/check.vrt']) - - cmd = alg.getConsoleCommands({'INPUT': [source], - 'SRC_NODATA': '-9999 9999', - 'OUTPUT': outdir + '/check.vrt'}, context, feedback) + cmd[1] = ( + t[: t.find("-input_file_list") + 17] + + t[t.find("buildvrtInputFiles.txt") :] + ) + self.assertEqual( + cmd, + [ + "gdalbuildvrt", + "-overwrite -resolution average -separate -r nearest -srcnodata -9999 " + + "-input_file_list buildvrtInputFiles.txt " + + outdir + + "/check.vrt", + ], + ) + + cmd = alg.getConsoleCommands( + { + "INPUT": [source], + "SRC_NODATA": "-9999 9999", + "OUTPUT": outdir + "/check.vrt", + }, + context, + feedback, + ) t = cmd[1] - cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):] - self.assertEqual(cmd, - ['gdalbuildvrt', - '-overwrite -resolution average -separate -r nearest -srcnodata "-9999 9999" ' + - '-input_file_list buildvrtInputFiles.txt ' + - outdir + '/check.vrt']) - - cmd = alg.getConsoleCommands({'INPUT': [source], - 'SRC_NODATA': '', - 'OUTPUT': outdir + '/check.vrt'}, context, feedback) + cmd[1] = ( + t[: t.find("-input_file_list") + 17] + + t[t.find("buildvrtInputFiles.txt") :] + ) + self.assertEqual( + cmd, + [ + "gdalbuildvrt", + '-overwrite -resolution average -separate -r nearest -srcnodata "-9999 9999" ' + + "-input_file_list buildvrtInputFiles.txt " + + outdir + + "/check.vrt", + ], + ) + + cmd = alg.getConsoleCommands( + {"INPUT": [source], "SRC_NODATA": "", "OUTPUT": outdir + "/check.vrt"}, + context, + feedback, + ) t = cmd[1] - cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):] - self.assertEqual(cmd, - ['gdalbuildvrt', - '-overwrite -resolution average -separate -r nearest ' + - '-input_file_list buildvrtInputFiles.txt ' + - outdir + '/check.vrt']) + cmd[1] = ( + t[: t.find("-input_file_list") + 17] + + t[t.find("buildvrtInputFiles.txt") :] + ) + self.assertEqual( + cmd, + [ + "gdalbuildvrt", + "-overwrite -resolution average -separate -r nearest " + + "-input_file_list buildvrtInputFiles.txt " + + outdir + + "/check.vrt", + ], + ) # additional parameters - cmd = alg.getConsoleCommands({'INPUT': [source], - 'EXTRA': '-overwrite -optim RASTER -vrtnodata -9999', - 'OUTPUT': outdir + '/check.vrt'}, context, feedback) + cmd = alg.getConsoleCommands( + { + "INPUT": [source], + "EXTRA": "-overwrite -optim RASTER -vrtnodata -9999", + "OUTPUT": outdir + "/check.vrt", + }, + context, + feedback, + ) t = cmd[1] - cmd[1] = t[:t.find('-input_file_list') + 17] + t[t.find('buildvrtInputFiles.txt'):] - self.assertEqual(cmd, - ['gdalbuildvrt', - '-overwrite -resolution average -separate -r nearest -overwrite -optim RASTER -vrtnodata -9999 ' + - '-input_file_list buildvrtInputFiles.txt ' + - outdir + '/check.vrt']) + cmd[1] = ( + t[: t.find("-input_file_list") + 17] + + t[t.find("buildvrtInputFiles.txt") :] + ) + self.assertEqual( + cmd, + [ + "gdalbuildvrt", + "-overwrite -resolution average -separate -r nearest -overwrite -optim RASTER -vrtnodata -9999 " + + "-input_file_list buildvrtInputFiles.txt " + + outdir + + "/check.vrt", + ], + ) def testPct2Rgb(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") alg = pct2rgb() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: # defaults self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['pct2rgb.py', - source + ' ' + outdir + '/check.tif ' + - '-of GTiff -b 1']) + alg.getConsoleCommands( + {"INPUT": source, "OUTPUT": outdir + "/check.tif"}, + context, + feedback, + ), + [ + "pct2rgb.py", + source + " " + outdir + "/check.tif " + "-of GTiff -b 1", + ], + ) # set band self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 3, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['pct2rgb.py', - source + ' ' + outdir + '/check.tif ' + - '-of GTiff -b 3']) + alg.getConsoleCommands( + {"INPUT": source, "BAND": 3, "OUTPUT": outdir + "/check.tif"}, + context, + feedback, + ), + [ + "pct2rgb.py", + source + " " + outdir + "/check.tif " + "-of GTiff -b 3", + ], + ) # set RGBA self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'RGBA': True, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['pct2rgb.py', - source + ' ' + outdir + '/check.tif ' + - '-of GTiff -b 1 -rgba']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['pct2rgb.py', - source + ' ' + outdir + '/check.tif ' + - '-of GTiff -b 1 --config X Y --config Z A']) + alg.getConsoleCommands( + {"INPUT": source, "RGBA": True, "OUTPUT": outdir + "/check.tif"}, + context, + feedback, + ), + [ + "pct2rgb.py", + source + " " + outdir + "/check.tif " + "-of GTiff -b 1 -rgba", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "pct2rgb.py", + source + + " " + + outdir + + "/check.tif " + + "-of GTiff -b 1 --config X Y --config Z A", + ], + ) def testRgb2Pct(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") alg = rgb2pct() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: # defaults self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['rgb2pct.py', - '-n 2 -of GTiff ' + source + ' ' + outdir + '/check.tif']) + alg.getConsoleCommands( + {"INPUT": source, "OUTPUT": outdir + "/check.tif"}, + context, + feedback, + ), + [ + "rgb2pct.py", + "-n 2 -of GTiff " + source + " " + outdir + "/check.tif", + ], + ) # set number of colors self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'NCOLORS': 8, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['rgb2pct.py', - '-n 8 -of GTiff ' + source + ' ' + outdir + '/check.tif']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['rgb2pct.py', - '-n 2 -of GTiff ' + source + ' ' + outdir + '/check.tif --config X Y --config Z A']) + alg.getConsoleCommands( + {"INPUT": source, "NCOLORS": 8, "OUTPUT": outdir + "/check.tif"}, + context, + feedback, + ), + [ + "rgb2pct.py", + "-n 8 -of GTiff " + source + " " + outdir + "/check.tif", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "rgb2pct.py", + "-n 2 -of GTiff " + + source + + " " + + outdir + + "/check.tif --config X Y --config Z A", + ], + ) def testRoughness(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'dem.tif') + source = os.path.join(testDataPath, "dem.tif") alg = roughness() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: # defaults self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'roughness ' + source + ' ' + outdir + '/check.tif ' + '-of GTiff -b 1']) + alg.getConsoleCommands( + {"INPUT": source, "OUTPUT": outdir + "/check.tif"}, + context, + feedback, + ), + [ + "gdaldem", + "roughness " + + source + + " " + + outdir + + "/check.tif " + + "-of GTiff -b 1", + ], + ) # set band self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'BAND': 3, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'roughness ' + source + ' ' + outdir + '/check.tif ' + '-of GTiff -b 3']) + alg.getConsoleCommands( + {"INPUT": source, "BAND": 3, "OUTPUT": outdir + "/check.tif"}, + context, + feedback, + ), + [ + "gdaldem", + "roughness " + + source + + " " + + outdir + + "/check.tif " + + "-of GTiff -b 3", + ], + ) # compute edges self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'COMPUTE_EDGES': True, - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'roughness ' + source + ' ' + outdir + '/check.tif ' + '-of GTiff -b 1 -compute_edges']) + alg.getConsoleCommands( + { + "INPUT": source, + "COMPUTE_EDGES": True, + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "roughness " + + source + + " " + + outdir + + "/check.tif " + + "-of GTiff -b 1 -compute_edges", + ], + ) # creation options self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OPTIONS': 'COMPRESS=DEFLATE|PREDICTOR=2|ZLEVEL=9', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'roughness ' + source + ' ' + outdir + '/check.tif ' + - '-of GTiff -b 1 -co COMPRESS=DEFLATE -co PREDICTOR=2 -co ZLEVEL=9']) - - self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'OUTPUT': outdir + '/check.tif'}, context, feedback), - ['gdaldem', - 'roughness ' + source + ' ' + outdir + '/check.tif ' + '-of GTiff -b 1 --config X Y --config Z A']) - - -if __name__ == '__main__': + alg.getConsoleCommands( + { + "INPUT": source, + "OPTIONS": "COMPRESS=DEFLATE|PREDICTOR=2|ZLEVEL=9", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "roughness " + + source + + " " + + outdir + + "/check.tif " + + "-of GTiff -b 1 -co COMPRESS=DEFLATE -co PREDICTOR=2 -co ZLEVEL=9", + ], + ) + + self.assertEqual( + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "OUTPUT": outdir + "/check.tif", + }, + context, + feedback, + ), + [ + "gdaldem", + "roughness " + + source + + " " + + outdir + + "/check.tif " + + "-of GTiff -b 1 --config X Y --config Z A", + ], + ) + + +if __name__ == "__main__": nose2.main() diff --git a/python/plugins/processing/tests/GdalAlgorithmsVectorTest.py b/python/plugins/processing/tests/GdalAlgorithmsVectorTest.py index c2f535a40fd9..d7f0f7659c85 100644 --- a/python/plugins/processing/tests/GdalAlgorithmsVectorTest.py +++ b/python/plugins/processing/tests/GdalAlgorithmsVectorTest.py @@ -15,22 +15,23 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'January 2016' -__copyright__ = '(C) 2016, Matthias Kuhn' +__author__ = "Matthias Kuhn" +__date__ = "January 2016" +__copyright__ = "(C) 2016, Matthias Kuhn" import nose2 import os import shutil import tempfile -from qgis.core import (QgsProcessingContext, - QgsProcessingFeedback, - QgsCoordinateReferenceSystem, - QgsRectangle) +from qgis.core import ( + QgsProcessingContext, + QgsProcessingFeedback, + QgsCoordinateReferenceSystem, + QgsRectangle, +) -from qgis.testing import (QgisTestCase, - start_app) +from qgis.testing import QgisTestCase, start_app import AlgorithmsTestBase from processing.algs.gdal.ogr2ogr import ogr2ogr @@ -42,7 +43,7 @@ from processing.algs.gdal.OneSideBuffer import OneSideBuffer from processing.algs.gdal.PointsAlongLines import PointsAlongLines -testDataPath = os.path.join(os.path.dirname(__file__), 'testdata') +testDataPath = os.path.join(os.path.dirname(__file__), "testdata") class TestGdalVectorAlgorithms(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest): @@ -51,6 +52,7 @@ class TestGdalVectorAlgorithms(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest): def setUpClass(cls): start_app() from processing.core.Processing import Processing + Processing.initialize() cls.cleanup_paths = [] @@ -60,1080 +62,1801 @@ def tearDownClass(cls): shutil.rmtree(path) def definition_file(self): - return 'gdal_algorithm_vector_tests.yaml' + return "gdal_algorithm_vector_tests.yaml" def testOgr2Ogr(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'polys.gml') - multi_source = os.path.join(testDataPath, 'multi_layers.gml') + source = os.path.join(testDataPath, "polys.gml") + multi_source = os.path.join(testDataPath, "multi_layers.gml") alg = ogr2ogr() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - '-f "ESRI Shapefile" ' + outdir + '/check.shp ' + - source + ' polys2']) + alg.getConsoleCommands( + {"INPUT": source, "OUTPUT": outdir + "/check.shp"}, + context, + feedback, + ), + [ + "ogr2ogr", + '-f "ESRI Shapefile" ' + + outdir + + "/check.shp " + + source + + " polys2", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OUTPUT': outdir + '/check.kml'}, context, feedback), - ['ogr2ogr', - '-f "LIBKML" ' + outdir + '/check.kml ' + - source + ' polys2']) + alg.getConsoleCommands( + {"INPUT": source, "OUTPUT": outdir + "/check.kml"}, + context, + feedback, + ), + [ + "ogr2ogr", + '-f "LIBKML" ' + outdir + "/check.kml " + source + " polys2", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OUTPUT': outdir + '/my out/check.kml'}, context, feedback), - ['ogr2ogr', - '-f "LIBKML" "' + outdir + '/my out/check.kml" ' + - source + ' polys2']) + alg.getConsoleCommands( + {"INPUT": source, "OUTPUT": outdir + "/my out/check.kml"}, + context, + feedback, + ), + [ + "ogr2ogr", + '-f "LIBKML" "' + + outdir + + '/my out/check.kml" ' + + source + + " polys2", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OUTPUT': outdir + '/check.gpkg'}, context, feedback), - ['ogr2ogr', - '-f "GPKG" ' + outdir + '/check.gpkg ' + - source + ' polys2']) + alg.getConsoleCommands( + {"INPUT": source, "OUTPUT": outdir + "/check.gpkg"}, + context, + feedback, + ), + [ + "ogr2ogr", + '-f "GPKG" ' + outdir + "/check.gpkg " + source + " polys2", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': multi_source + '|layername=lines', - 'CONVERT_ALL_LAYERS': False, - 'OUTPUT': outdir + '/check.gpkg'}, context, feedback), - ['ogr2ogr', - '-f "GPKG" ' + outdir + '/check.gpkg ' + - multi_source + ' lines']) + alg.getConsoleCommands( + { + "INPUT": multi_source + "|layername=lines", + "CONVERT_ALL_LAYERS": False, + "OUTPUT": outdir + "/check.gpkg", + }, + context, + feedback, + ), + [ + "ogr2ogr", + '-f "GPKG" ' + outdir + "/check.gpkg " + multi_source + " lines", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': multi_source + '|layername=lines', - 'CONVERT_ALL_LAYERS': True, - 'OUTPUT': outdir + '/check.gpkg'}, context, feedback), - ['ogr2ogr', - '-f "GPKG" ' + outdir + '/check.gpkg ' + - multi_source]) + alg.getConsoleCommands( + { + "INPUT": multi_source + "|layername=lines", + "CONVERT_ALL_LAYERS": True, + "OUTPUT": outdir + "/check.gpkg", + }, + context, + feedback, + ), + ["ogr2ogr", '-f "GPKG" ' + outdir + "/check.gpkg " + multi_source], + ) self.assertEqual( alg.getConsoleCommands( - {'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'CONVERT_ALL_LAYERS': True, - 'OUTPUT': outdir + '/check.gpkg'}, context, feedback), - ['ogr2ogr', - '-f "GPKG" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y ' + outdir + '/check.gpkg ' + - source]) + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "CONVERT_ALL_LAYERS": True, + "OUTPUT": outdir + "/check.gpkg", + }, + context, + feedback, + ), + [ + "ogr2ogr", + '-f "GPKG" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y ' + + outdir + + "/check.gpkg " + + source, + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'CONVERT_ALL_LAYERS': True, - 'OUTPUT': outdir + '/check.gpkg'}, context, feedback), - ['ogr2ogr', - '-f "GPKG" --config X Y --config Z A ' + outdir + '/check.gpkg ' + - source]) + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "CONVERT_ALL_LAYERS": True, + "OUTPUT": outdir + "/check.gpkg", + }, + context, + feedback, + ), + [ + "ogr2ogr", + '-f "GPKG" --config X Y --config Z A ' + + outdir + + "/check.gpkg " + + source, + ], + ) def testOgrInfo(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'polys.gml') + source = os.path.join(testDataPath, "polys.gml") alg = ogrinfo() alg.initAlgorithm() self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SUMMARY_ONLY': True, - 'NO_METADATA': False}, context, feedback), - ['ogrinfo', - '-al -so ' + - source + ' polys2']) - - source = os.path.join(testDataPath, 'polys.gml') + alg.getConsoleCommands( + {"INPUT": source, "SUMMARY_ONLY": True, "NO_METADATA": False}, + context, + feedback, + ), + ["ogrinfo", "-al -so " + source + " polys2"], + ) + + source = os.path.join(testDataPath, "polys.gml") self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'ALL_LAYERS': True, - 'SUMMARY_ONLY': True, - 'NO_METADATA': False}, context, feedback), - ['ogrinfo', - '-al -so ' + - source]) - - source = os.path.join(testDataPath, 'polys.gml') + alg.getConsoleCommands( + { + "INPUT": source, + "ALL_LAYERS": True, + "SUMMARY_ONLY": True, + "NO_METADATA": False, + }, + context, + feedback, + ), + ["ogrinfo", "-al -so " + source], + ) + + source = os.path.join(testDataPath, "polys.gml") self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'ALL_LAYERS': True, - 'SUMMARY_ONLY': True, - 'EXTRA': '-nocount', - 'NO_METADATA': False}, context, feedback), - ['ogrinfo', - '-al -so -nocount ' + - source]) - - source = os.path.join(testDataPath, 'filename with spaces.gml') + alg.getConsoleCommands( + { + "INPUT": source, + "ALL_LAYERS": True, + "SUMMARY_ONLY": True, + "EXTRA": "-nocount", + "NO_METADATA": False, + }, + context, + feedback, + ), + ["ogrinfo", "-al -so -nocount " + source], + ) + + source = os.path.join(testDataPath, "filename with spaces.gml") self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SUMMARY_ONLY': True, - 'NO_METADATA': False}, context, feedback), - ['ogrinfo', - '-al -so "' + - source + '" filename_with_spaces']) - - source = os.path.join(testDataPath, 'filename with spaces.gml') + alg.getConsoleCommands( + {"INPUT": source, "SUMMARY_ONLY": True, "NO_METADATA": False}, + context, + feedback, + ), + ["ogrinfo", '-al -so "' + source + '" filename_with_spaces'], + ) + + source = os.path.join(testDataPath, "filename with spaces.gml") self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SUMMARY_ONLY': False, - 'NO_METADATA': False}, context, feedback), - ['ogrinfo', - '-al "' + - source + '" filename_with_spaces']) - - source = os.path.join(testDataPath, 'filename with spaces.gml') + alg.getConsoleCommands( + {"INPUT": source, "SUMMARY_ONLY": False, "NO_METADATA": False}, + context, + feedback, + ), + ["ogrinfo", '-al "' + source + '" filename_with_spaces'], + ) + + source = os.path.join(testDataPath, "filename with spaces.gml") self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SUMMARY_ONLY': True, - 'NO_METADATA': True}, context, feedback), - ['ogrinfo', - '-al -so -nomd "' + - source + '" filename_with_spaces']) - - source = os.path.join(testDataPath, 'filename with spaces.gml') + alg.getConsoleCommands( + {"INPUT": source, "SUMMARY_ONLY": True, "NO_METADATA": True}, + context, + feedback, + ), + ["ogrinfo", '-al -so -nomd "' + source + '" filename_with_spaces'], + ) + + source = os.path.join(testDataPath, "filename with spaces.gml") self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'SUMMARY_ONLY': True, - 'NO_METADATA': True}, context, feedback), - ['ogrinfo', - '-al -so -nomd "' + - source + '" filename_with_spaces -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y']) - - source = os.path.join(testDataPath, 'filename with spaces.gml') + alg.getConsoleCommands( + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "SUMMARY_ONLY": True, + "NO_METADATA": True, + }, + context, + feedback, + ), + [ + "ogrinfo", + '-al -so -nomd "' + + source + + '" filename_with_spaces -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y', + ], + ) + + source = os.path.join(testDataPath, "filename with spaces.gml") self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'SUMMARY_ONLY': True, - 'NO_METADATA': True}, context, feedback), - ['ogrinfo', - '-al -so -nomd "' + - source + '" filename_with_spaces --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "SUMMARY_ONLY": True, + "NO_METADATA": True, + }, + context, + feedback, + ), + [ + "ogrinfo", + '-al -so -nomd "' + + source + + '" filename_with_spaces --config X Y --config Z A', + ], + ) def testOgrInfoJson(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'polys.gml') + source = os.path.join(testDataPath, "polys.gml") alg = ogrinfojson() alg.initAlgorithm() self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FEATURES': True, - 'NO_METADATA': False}, context, feedback), - ['ogrinfo', - '-json -features ' + - source + ' polys2']) - - source = os.path.join(testDataPath, 'polys.gml') + alg.getConsoleCommands( + {"INPUT": source, "FEATURES": True, "NO_METADATA": False}, + context, + feedback, + ), + ["ogrinfo", "-json -features " + source + " polys2"], + ) + + source = os.path.join(testDataPath, "polys.gml") self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'ALL_LAYERS': True, - 'FEATURES': True, - 'NO_METADATA': False}, context, feedback), - ['ogrinfo', - '-json -features ' + - source]) - - source = os.path.join(testDataPath, 'polys.gml') + alg.getConsoleCommands( + { + "INPUT": source, + "ALL_LAYERS": True, + "FEATURES": True, + "NO_METADATA": False, + }, + context, + feedback, + ), + ["ogrinfo", "-json -features " + source], + ) + + source = os.path.join(testDataPath, "polys.gml") self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'ALL_LAYERS': True, - 'FEATURES': True, - 'EXTRA': '-nocount', - 'NO_METADATA': False}, context, feedback), - ['ogrinfo', - '-json -features -nocount ' + - source]) - - source = os.path.join(testDataPath, 'filename with spaces.gml') + alg.getConsoleCommands( + { + "INPUT": source, + "ALL_LAYERS": True, + "FEATURES": True, + "EXTRA": "-nocount", + "NO_METADATA": False, + }, + context, + feedback, + ), + ["ogrinfo", "-json -features -nocount " + source], + ) + + source = os.path.join(testDataPath, "filename with spaces.gml") self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FEATURES': True, - 'NO_METADATA': False}, context, feedback), - ['ogrinfo', - '-json -features "' + - source + '" filename_with_spaces']) - - source = os.path.join(testDataPath, 'filename with spaces.gml') + alg.getConsoleCommands( + {"INPUT": source, "FEATURES": True, "NO_METADATA": False}, + context, + feedback, + ), + ["ogrinfo", '-json -features "' + source + '" filename_with_spaces'], + ) + + source = os.path.join(testDataPath, "filename with spaces.gml") self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FEATURES': False, - 'NO_METADATA': False}, context, feedback), - ['ogrinfo', - '-json "' + - source + '" filename_with_spaces']) - - source = os.path.join(testDataPath, 'filename with spaces.gml') + alg.getConsoleCommands( + {"INPUT": source, "FEATURES": False, "NO_METADATA": False}, + context, + feedback, + ), + ["ogrinfo", '-json "' + source + '" filename_with_spaces'], + ) + + source = os.path.join(testDataPath, "filename with spaces.gml") self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FEATURES': True, - 'NO_METADATA': True}, context, feedback), - ['ogrinfo', - '-json -features -nomd "' + - source + '" filename_with_spaces']) - - source = os.path.join(testDataPath, 'filename with spaces.gml') + alg.getConsoleCommands( + {"INPUT": source, "FEATURES": True, "NO_METADATA": True}, + context, + feedback, + ), + ["ogrinfo", '-json -features -nomd "' + source + '" filename_with_spaces'], + ) + + source = os.path.join(testDataPath, "filename with spaces.gml") self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'FEATURES': True, - 'NO_METADATA': True}, context, feedback), - ['ogrinfo', - '-json -features -nomd "' + - source + '" filename_with_spaces -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y']) - - source = os.path.join(testDataPath, 'filename with spaces.gml') + alg.getConsoleCommands( + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "FEATURES": True, + "NO_METADATA": True, + }, + context, + feedback, + ), + [ + "ogrinfo", + '-json -features -nomd "' + + source + + '" filename_with_spaces -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y', + ], + ) + + source = os.path.join(testDataPath, "filename with spaces.gml") self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'FEATURES': True, - 'NO_METADATA': True}, context, feedback), - ['ogrinfo', - '-json -features -nomd "' + - source + '" filename_with_spaces --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "FEATURES": True, + "NO_METADATA": True, + }, + context, + feedback, + ), + [ + "ogrinfo", + '-json -features -nomd "' + + source + + '" filename_with_spaces --config X Y --config Z A', + ], + ) def testBuffer(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'polys.gml') - source_with_space = os.path.join(testDataPath, 'filename with spaces.gml') + source = os.path.join(testDataPath, "polys.gml") + source_with_space = os.path.join(testDataPath, "filename with spaces.gml") alg = Buffer() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'DISTANCE': 5, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_Buffer(geometry, 5.0) AS geometry,* FROM """polys2"""" ' + - '-f "ESRI Shapefile"']) + alg.getConsoleCommands( + {"INPUT": source, "DISTANCE": 5, "OUTPUT": outdir + "/check.shp"}, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_Buffer(geometry, 5.0) AS geometry,* FROM """polys2"""" ' + + '-f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'DISTANCE': -5, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_Buffer(geometry, -5.0) AS geometry,* FROM """polys2"""" ' + - '-f "ESRI Shapefile"']) + alg.getConsoleCommands( + {"INPUT": source, "DISTANCE": -5, "OUTPUT": outdir + "/check.shp"}, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_Buffer(geometry, -5.0) AS geometry,* FROM """polys2"""" ' + + '-f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'DISTANCE': 5, - 'DISSOLVE': True, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_Union(ST_Buffer(geometry, 5.0)) AS geometry,* FROM """polys2"""" ' + - '-f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "DISTANCE": 5, + "DISSOLVE": True, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_Union(ST_Buffer(geometry, 5.0)) AS geometry,* FROM """polys2"""" ' + + '-f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'DISTANCE': 1, - 'DISSOLVE': True, - 'EXPLODE_COLLECTIONS': False, - 'GEOMETRY': 'geom', - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_Union(ST_Buffer(geom, 1.0)) AS geom,* FROM """polys2"""" ' + - '-f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "DISTANCE": 1, + "DISSOLVE": True, + "EXPLODE_COLLECTIONS": False, + "GEOMETRY": "geom", + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_Union(ST_Buffer(geom, 1.0)) AS geom,* FROM """polys2"""" ' + + '-f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'DISTANCE': 5, - 'EXPLODE_COLLECTIONS': True, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_Buffer(geometry, 5.0) AS geometry,* FROM """polys2"""" ' + - '-explodecollections -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "DISTANCE": 5, + "EXPLODE_COLLECTIONS": True, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_Buffer(geometry, 5.0) AS geometry,* FROM """polys2"""" ' + + '-explodecollections -f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'DISTANCE': 5, - 'FIELD': 'total population', - 'EXPLODE_COLLECTIONS': True, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_Union(ST_Buffer(geometry, 5.0)) AS geometry,* FROM """polys2""" GROUP BY """total population"""" ' + - '-explodecollections -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "DISTANCE": 5, + "FIELD": "total population", + "EXPLODE_COLLECTIONS": True, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_Union(ST_Buffer(geometry, 5.0)) AS geometry,* FROM """polys2""" GROUP BY """total population"""" ' + + '-explodecollections -f "ESRI Shapefile"', + ], + ) self.assertEqual( alg.getConsoleCommands( - {'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'DISTANCE': 5, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_Buffer(geometry, 5.0) AS geometry,* FROM """polys2"""" ' + - '-oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -f "ESRI Shapefile"']) + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "DISTANCE": 5, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_Buffer(geometry, 5.0) AS geometry,* FROM """polys2"""" ' + + '-oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'DISTANCE': 5, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_Buffer(geometry, 5.0) AS geometry,* FROM """polys2"""" ' + - '--config X Y --config Z A -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "DISTANCE": 5, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_Buffer(geometry, 5.0) AS geometry,* FROM """polys2"""" ' + + '--config X Y --config Z A -f "ESRI Shapefile"', + ], + ) def testDissolve(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'polys.gml') - source_with_space = os.path.join(testDataPath, 'filename with spaces.gml') + source = os.path.join(testDataPath, "polys.gml") + source_with_space = os.path.join(testDataPath, "filename with spaces.gml") alg = Dissolve() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry FROM """polys2"""" ' + - '-f "ESRI Shapefile"']) + alg.getConsoleCommands( + {"INPUT": source, "OUTPUT": outdir + "/check.shp"}, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry FROM """polys2"""" ' + + '-f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FIELD': 'my_field', - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' + - 'GROUP BY """my_field"""" -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "FIELD": "my_field", + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' + + 'GROUP BY """my_field"""" -f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FIELD': 'total population', - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """total population""" FROM """polys2""" ' + - 'GROUP BY """total population"""" -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "FIELD": "total population", + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """total population""" FROM """polys2""" ' + + 'GROUP BY """total population"""" -f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source_with_space, - 'FIELD': 'my_field', - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - '"' + source_with_space + '" ' + - '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """filename_with_spaces""" ' + - 'GROUP BY """my_field"""" -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source_with_space, + "FIELD": "my_field", + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + '"' + + source_with_space + + '" ' + + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """filename_with_spaces""" ' + + 'GROUP BY """my_field"""" -f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FIELD': 'my_field', - 'GEOMETRY': 'the_geom', - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(the_geom) AS the_geom, """my_field""" FROM """polys2""" ' + - 'GROUP BY """my_field"""" -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "FIELD": "my_field", + "GEOMETRY": "the_geom", + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(the_geom) AS the_geom, """my_field""" FROM """polys2""" ' + + 'GROUP BY """my_field"""" -f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FIELD': 'my_field', - 'KEEP_ATTRIBUTES': False, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' + - 'GROUP BY """my_field"""" -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "FIELD": "my_field", + "KEEP_ATTRIBUTES": False, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' + + 'GROUP BY """my_field"""" -f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'KEEP_ATTRIBUTES': False, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry FROM """polys2"""" ' + - '-f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "KEEP_ATTRIBUTES": False, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry FROM """polys2"""" ' + + '-f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FIELD': 'my_field', - 'EXPLODE_COLLECTIONS': True, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' + - 'GROUP BY """my_field"""" -explodecollections -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "FIELD": "my_field", + "EXPLODE_COLLECTIONS": True, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' + + 'GROUP BY """my_field"""" -explodecollections -f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FIELD': 'my_field', - 'COUNT_FEATURES': True, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""", COUNT(geometry) AS count FROM """polys2""" ' + - 'GROUP BY """my_field"""" -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "FIELD": "my_field", + "COUNT_FEATURES": True, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""", COUNT(geometry) AS count FROM """polys2""" ' + + 'GROUP BY """my_field"""" -f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FIELD': 'my_field', - 'COUNT_FEATURES': True, - 'GEOMETRY': 'the_geom', - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(the_geom) AS the_geom, """my_field""", COUNT(the_geom) AS count FROM """polys2""" ' + - 'GROUP BY """my_field"""" -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "FIELD": "my_field", + "COUNT_FEATURES": True, + "GEOMETRY": "the_geom", + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(the_geom) AS the_geom, """my_field""", COUNT(the_geom) AS count FROM """polys2""" ' + + 'GROUP BY """my_field"""" -f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FIELD': 'my_field', - 'COMPUTE_AREA': True, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""", SUM(ST_Area(geometry)) AS area, ' + - 'ST_Perimeter(ST_Union(geometry)) AS perimeter FROM """polys2""" ' + - 'GROUP BY """my_field"""" -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "FIELD": "my_field", + "COMPUTE_AREA": True, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""", SUM(ST_Area(geometry)) AS area, ' + + 'ST_Perimeter(ST_Union(geometry)) AS perimeter FROM """polys2""" ' + + 'GROUP BY """my_field"""" -f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FIELD': 'my_field', - 'COMPUTE_AREA': True, - 'GEOMETRY': 'the_geom', - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(the_geom) AS the_geom, """my_field""", SUM(ST_Area(the_geom)) AS area, ' + - 'ST_Perimeter(ST_Union(the_geom)) AS perimeter FROM """polys2""" ' + - 'GROUP BY """my_field"""" -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "FIELD": "my_field", + "COMPUTE_AREA": True, + "GEOMETRY": "the_geom", + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(the_geom) AS the_geom, """my_field""", SUM(ST_Area(the_geom)) AS area, ' + + 'ST_Perimeter(ST_Union(the_geom)) AS perimeter FROM """polys2""" ' + + 'GROUP BY """my_field"""" -f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FIELD': 'my_field', - 'COMPUTE_STATISTICS': True, - 'STATISTICS_ATTRIBUTE': 'my_val', - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""", ' + - 'SUM("""my_val""") AS sum, MIN("""my_val""") AS min, MAX("""my_val""") AS max, AVG("""my_val""") AS avg FROM """polys2""" ' + - 'GROUP BY """my_field"""" -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "FIELD": "my_field", + "COMPUTE_STATISTICS": True, + "STATISTICS_ATTRIBUTE": "my_val", + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""", ' + + 'SUM("""my_val""") AS sum, MIN("""my_val""") AS min, MAX("""my_val""") AS max, AVG("""my_val""") AS avg FROM """polys2""" ' + + 'GROUP BY """my_field"""" -f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FIELD': 'test field', - 'COMPUTE_STATISTICS': True, - 'STATISTICS_ATTRIBUTE': 'total population', - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """test field""", ' + - 'SUM("""total population""") AS sum, MIN("""total population""") AS min, MAX("""total population""") AS max, ' + - 'AVG("""total population""") AS avg FROM """polys2""" ' + - 'GROUP BY """test field"""" -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "FIELD": "test field", + "COMPUTE_STATISTICS": True, + "STATISTICS_ATTRIBUTE": "total population", + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """test field""", ' + + 'SUM("""total population""") AS sum, MIN("""total population""") AS min, MAX("""total population""") AS max, ' + + 'AVG("""total population""") AS avg FROM """polys2""" ' + + 'GROUP BY """test field"""" -f "ESRI Shapefile"', + ], + ) # compute stats without stats attribute, and vice versa (should be ignored) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FIELD': 'my_field', - 'COMPUTE_STATISTICS': True, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' + - 'GROUP BY """my_field"""" -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "FIELD": "my_field", + "COMPUTE_STATISTICS": True, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' + + 'GROUP BY """my_field"""" -f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FIELD': 'my_field', - 'STATISTICS_ATTRIBUTE': 'my_val', - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' + - 'GROUP BY """my_field"""" -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "FIELD": "my_field", + "STATISTICS_ATTRIBUTE": "my_val", + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' + + 'GROUP BY """my_field"""" -f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FIELD': 'my_field', - 'OPTIONS': 'my opts', - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' + - 'GROUP BY """my_field"""" "my opts" -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "FIELD": "my_field", + "OPTIONS": "my opts", + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' + + 'GROUP BY """my_field"""" "my opts" -f "ESRI Shapefile"', + ], + ) self.assertEqual( alg.getConsoleCommands( - {'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'FIELD': 'my_field', - 'OPTIONS': 'my opts', - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' + - 'GROUP BY """my_field"""" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y "my opts" -f "ESRI Shapefile"']) + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "FIELD": "my_field", + "OPTIONS": "my opts", + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' + + 'GROUP BY """my_field"""" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y "my opts" -f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'FIELD': 'my_field', - 'OPTIONS': 'my opts', - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' + - 'GROUP BY """my_field"""" --config X Y --config Z A "my opts" -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "FIELD": "my_field", + "OPTIONS": "my opts", + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, """my_field""" FROM """polys2""" ' + + 'GROUP BY """my_field"""" --config X Y --config Z A "my opts" -f "ESRI Shapefile"', + ], + ) def testOgr2PostGis(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'polys.gml') - source_line = os.path.join(testDataPath, 'multilines.gml') - source_with_space = os.path.join(testDataPath, 'filename with spaces.gml') + source = os.path.join(testDataPath, "polys.gml") + source_line = os.path.join(testDataPath, "multilines.gml") + source_with_space = os.path.join(testDataPath, "filename with spaces.gml") alg = OgrToPostGis() alg.initAlgorithm() self.assertEqual( - alg.getConsoleCommands({'INPUT': source}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands({"INPUT": source}, context, feedback), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source_with_space}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 "' + source_with_space + '" filename_with_spaces ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.filename_with_spaces -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands({"INPUT": source_with_space}, context, feedback), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + '-lco DIM=2 "' + source_with_space + '" filename_with_spaces ' + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.filename_with_spaces -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'HOST': 'google.com'}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=google.com port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "HOST": "google.com"}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=google.com port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'PORT': 3333}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=3333 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands({"INPUT": source, "PORT": 3333}, context, feedback), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=3333 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'USER': 'kevin_bacon'}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public user=kevin_bacon" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "USER": "kevin_bacon"}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public user=kevin_bacon" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'DBNAME': 'secret_stuff'}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 dbname=secret_stuff active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "DBNAME": "secret_stuff"}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 dbname=secret_stuff active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'PASSWORD': 'passw0rd'}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 password=passw0rd active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "PASSWORD": "passw0rd"}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 password=passw0rd active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SCHEMA': 'desktop'}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=desktop" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln desktop.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "SCHEMA": "desktop"}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=desktop" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln desktop.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'TABLE': 'out_table'}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.out_table -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "TABLE": "out_table"}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.out_table -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'PK': ''}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -nln public.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands({"INPUT": source, "PK": ""}, context, feedback), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -nln public.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'PK': 'new_fid'}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=new_fid -nln public.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "PK": "new_fid"}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=new_fid -nln public.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'PK': '', - 'PRIMARY_KEY': 'objectid'}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=objectid -nln public.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "PK": "", "PRIMARY_KEY": "objectid"}, + context, + feedback, + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=objectid -nln public.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'PK': 'new_id', - 'PRIMARY_KEY': 'objectid'}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=new_id -nln public.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "PK": "new_id", "PRIMARY_KEY": "objectid"}, + context, + feedback, + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=new_id -nln public.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'GEOCOLUMN': 'my_geom'}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=my_geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "GEOCOLUMN": "my_geom"}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=my_geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'DIM': 1}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=3 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands({"INPUT": source, "DIM": 1}, context, feedback), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=3 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SIMPLIFY': 5}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -simplify 5 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands({"INPUT": source, "SIMPLIFY": 5}, context, feedback), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -simplify 5 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SEGMENTIZE': 4}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -segmentize 4 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "SEGMENTIZE": 4}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -segmentize 4 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SPAT': QgsRectangle(1, 2, 3, 4)}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -spat 1.0 2.0 3.0 4.0 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "SPAT": QgsRectangle(1, 2, 3, 4)}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -spat 1.0 2.0 3.0 4.0 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'FIELDS': ['f1', 'f2']}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 -select "f1,f2" ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "FIELDS": ["f1", "f2"]}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + ' polys2 -select "f1,f2" ' + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'WHERE': '0=1'}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -where "0=1" -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "WHERE": "0=1"}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -where "0=1" -nlt PROMOTE_TO_MULTI', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'GT': 2}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -gt 2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands({"INPUT": source, "GT": 2}, context, feedback), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -gt 2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OVERWRITE': False}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "OVERWRITE": False}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OVERWRITE': False, - 'APPEND': True}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-append -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "OVERWRITE": False, "APPEND": True}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-append -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'ADDFIELDS': True}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-addfields -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "ADDFIELDS": True}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-addfields -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'LAUNDER': True}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-lco LAUNDER=NO -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "LAUNDER": True}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-lco LAUNDER=NO -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'INDEX': True}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-lco SPATIAL_INDEX=OFF -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands({"INPUT": source, "INDEX": True}, context, feedback), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-lco SPATIAL_INDEX=OFF -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SKIPFAILURES': True}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -skipfailures -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "SKIPFAILURES": True}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -skipfailures -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'PROMOTETOMULTI': False}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2']) + alg.getConsoleCommands( + {"INPUT": source, "PROMOTETOMULTI": False}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'PRECISION': False}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI -lco PRECISION=NO']) + alg.getConsoleCommands( + {"INPUT": source, "PRECISION": False}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI -lco PRECISION=NO", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'OPTIONS': 'blah'}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI blah']) + alg.getConsoleCommands( + {"INPUT": source, "OPTIONS": "blah"}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI blah", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'SHAPE_ENCODING': 'blah'}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES --config SHAPE_ENCODING blah -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "SHAPE_ENCODING": "blah"}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES --config SHAPE_ENCODING blah -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'PROMOTETOMULTI': False, - 'GTYPE': 4}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -nlt LINESTRING -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2']) + alg.getConsoleCommands( + {"INPUT": source, "PROMOTETOMULTI": False, "GTYPE": 4}, + context, + feedback, + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -nlt LINESTRING -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source_line, - 'GTYPE': 15}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source_line + ' multilines ' - '-overwrite -nlt CONVERT_TO_LINEAR -lco GEOMETRY_NAME=geom -lco FID=id -nln public.multilines -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source_line, "GTYPE": 15}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source_line + " multilines " + "-overwrite -nlt CONVERT_TO_LINEAR -lco GEOMETRY_NAME=geom -lco FID=id -nln public.multilines -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'A_SRS': 'EPSG:3111'}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "A_SRS": "EPSG:3111"}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'A_SRS': QgsCoordinateReferenceSystem('EPSG:3111')}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI']) - - custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs' + alg.getConsoleCommands( + {"INPUT": source, "A_SRS": QgsCoordinateReferenceSystem("EPSG:3111")}, + context, + feedback, + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI", + ], + ) + + custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'A_SRS': custom_crs}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:20936 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "A_SRS": custom_crs}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:20936 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'T_SRS': 'EPSG:3111'}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -t_srs EPSG:3111 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "T_SRS": "EPSG:3111"}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -t_srs EPSG:3111 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'T_SRS': QgsCoordinateReferenceSystem('EPSG:3111')}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -t_srs EPSG:3111 -nlt PROMOTE_TO_MULTI']) - - custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs' + alg.getConsoleCommands( + {"INPUT": source, "T_SRS": QgsCoordinateReferenceSystem("EPSG:3111")}, + context, + feedback, + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -t_srs EPSG:3111 -nlt PROMOTE_TO_MULTI", + ], + ) + + custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'T_SRS': custom_crs}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -t_srs EPSG:20936 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "T_SRS": custom_crs}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -t_srs EPSG:20936 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'S_SRS': 'EPSG:3111'}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -s_srs EPSG:3111 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "S_SRS": "EPSG:3111"}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -s_srs EPSG:3111 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'S_SRS': QgsCoordinateReferenceSystem('EPSG:3111')}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -s_srs EPSG:3111 -nlt PROMOTE_TO_MULTI']) - - custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs' + alg.getConsoleCommands( + {"INPUT": source, "S_SRS": QgsCoordinateReferenceSystem("EPSG:3111")}, + context, + feedback, + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -s_srs EPSG:3111 -nlt PROMOTE_TO_MULTI", + ], + ) + + custom_crs = "proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'S_SRS': custom_crs}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -s_srs EPSG:20936 -nlt PROMOTE_TO_MULTI']) + alg.getConsoleCommands( + {"INPUT": source, "S_SRS": custom_crs}, context, feedback + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -s_srs EPSG:20936 -nlt PROMOTE_TO_MULTI", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'A_SRS': QgsCoordinateReferenceSystem('EPSG:3111')}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y']) + alg.getConsoleCommands( + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "A_SRS": QgsCoordinateReferenceSystem("EPSG:3111"), + }, + context, + feedback, + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y", + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'A_SRS': QgsCoordinateReferenceSystem('EPSG:3111')}, context, feedback), - ['ogr2ogr', - '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' - '-lco DIM=2 ' + source + ' polys2 ' - '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI --config X Y --config Z A']) + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "A_SRS": QgsCoordinateReferenceSystem("EPSG:3111"), + }, + context, + feedback, + ), + [ + "ogr2ogr", + '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' + "-lco DIM=2 " + source + " polys2 " + "-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI --config X Y --config Z A", + ], + ) def testOffsetCurve(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'polys.gml') - source_with_space = os.path.join(testDataPath, 'filename with spaces.gml') + source = os.path.join(testDataPath, "polys.gml") + source_with_space = os.path.join(testDataPath, "filename with spaces.gml") alg = OffsetCurve() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'DISTANCE': 5, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_OffsetCurve(geometry, 5.0) AS geometry,* FROM """polys2"""" ' + - '-f "ESRI Shapefile"']) + alg.getConsoleCommands( + {"INPUT": source, "DISTANCE": 5, "OUTPUT": outdir + "/check.shp"}, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_OffsetCurve(geometry, 5.0) AS geometry,* FROM """polys2"""" ' + + '-f "ESRI Shapefile"', + ], + ) self.assertEqual( alg.getConsoleCommands( - {'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'DISTANCE': 5, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_OffsetCurve(geometry, 5.0) AS geometry,* FROM """polys2"""" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y ' + - '-f "ESRI Shapefile"']) + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "DISTANCE": 5, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_OffsetCurve(geometry, 5.0) AS geometry,* FROM """polys2"""" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y ' + + '-f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'DISTANCE': 5, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_OffsetCurve(geometry, 5.0) AS geometry,* FROM """polys2"""" --config X Y --config Z A ' + - '-f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "DISTANCE": 5, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_OffsetCurve(geometry, 5.0) AS geometry,* FROM """polys2"""" --config X Y --config Z A ' + + '-f "ESRI Shapefile"', + ], + ) def testOneSidedBuffer(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'polys.gml') - source_with_space = os.path.join(testDataPath, 'filename with spaces.gml') + source = os.path.join(testDataPath, "polys.gml") + source_with_space = os.path.join(testDataPath, "filename with spaces.gml") alg = OneSideBuffer() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'DISTANCE': 5, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_SingleSidedBuffer(geometry, 5.0, 0) AS geometry,* FROM """polys2"""" ' + - '-f "ESRI Shapefile"']) + alg.getConsoleCommands( + {"INPUT": source, "DISTANCE": 5, "OUTPUT": outdir + "/check.shp"}, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_SingleSidedBuffer(geometry, 5.0, 0) AS geometry,* FROM """polys2"""" ' + + '-f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'DISTANCE': 5, - 'DISSOLVE': True, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_Union(ST_SingleSidedBuffer(geometry, 5.0, 0)) AS geometry,* FROM """polys2"""" ' + - '-f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "DISTANCE": 5, + "DISSOLVE": True, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_Union(ST_SingleSidedBuffer(geometry, 5.0, 0)) AS geometry,* FROM """polys2"""" ' + + '-f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'DISTANCE': 5, - 'EXPLODE_COLLECTIONS': True, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_SingleSidedBuffer(geometry, 5.0, 0) AS geometry,* FROM """polys2"""" ' + - '-explodecollections -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "DISTANCE": 5, + "EXPLODE_COLLECTIONS": True, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_SingleSidedBuffer(geometry, 5.0, 0) AS geometry,* FROM """polys2"""" ' + + '-explodecollections -f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'DISTANCE': 5, - 'FIELD': 'total population', - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_Union(ST_SingleSidedBuffer(geometry, 5.0, 0)) AS geometry,* ' + - 'FROM """polys2""" GROUP BY """total population"""" -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source, + "DISTANCE": 5, + "FIELD": "total population", + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_Union(ST_SingleSidedBuffer(geometry, 5.0, 0)) AS geometry,* ' + + 'FROM """polys2""" GROUP BY """total population"""" -f "ESRI Shapefile"', + ], + ) self.assertEqual( alg.getConsoleCommands( - {'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'DISTANCE': 5, - 'FIELD': 'total population', - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_Union(ST_SingleSidedBuffer(geometry, 5.0, 0)) AS geometry,* ' + - 'FROM """polys2""" GROUP BY """total population"""" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -f "ESRI Shapefile"']) + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "DISTANCE": 5, + "FIELD": "total population", + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_Union(ST_SingleSidedBuffer(geometry, 5.0, 0)) AS geometry,* ' + + 'FROM """polys2""" GROUP BY """total population"""" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y -f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'DISTANCE': 5, - 'FIELD': 'total population', - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_Union(ST_SingleSidedBuffer(geometry, 5.0, 0)) AS geometry,* ' + - 'FROM """polys2""" GROUP BY """total population"""" --config X Y --config Z A -f "ESRI Shapefile"']) + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "DISTANCE": 5, + "FIELD": "total population", + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_Union(ST_SingleSidedBuffer(geometry, 5.0, 0)) AS geometry,* ' + + 'FROM """polys2""" GROUP BY """total population"""" --config X Y --config Z A -f "ESRI Shapefile"', + ], + ) def testPointsAlongLines(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() - source = os.path.join(testDataPath, 'polys.gml') - source_with_space = os.path.join(testDataPath, 'filename with spaces.gml') + source = os.path.join(testDataPath, "polys.gml") + source_with_space = os.path.join(testDataPath, "filename with spaces.gml") alg = PointsAlongLines() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: self.assertEqual( - alg.getConsoleCommands({'INPUT': source, - 'DISTANCE': 0.2, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_Line_Interpolate_Point(geometry, 0.2) AS geometry,* FROM """polys2"""" ' + - '-f "ESRI Shapefile"']) + alg.getConsoleCommands( + {"INPUT": source, "DISTANCE": 0.2, "OUTPUT": outdir + "/check.shp"}, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_Line_Interpolate_Point(geometry, 0.2) AS geometry,* FROM """polys2"""" ' + + '-f "ESRI Shapefile"', + ], + ) self.assertEqual( alg.getConsoleCommands( - {'INPUT': source + '|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y', - 'DISTANCE': 0.2, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_Line_Interpolate_Point(geometry, 0.2) AS geometry,* FROM """polys2"""" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y ' + - '-f "ESRI Shapefile"']) + { + "INPUT": source + + "|option:X_POSSIBLE_NAMES=geom_x|option:Y_POSSIBLE_NAMES=geom_y", + "DISTANCE": 0.2, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_Line_Interpolate_Point(geometry, 0.2) AS geometry,* FROM """polys2"""" -oo X_POSSIBLE_NAMES=geom_x -oo Y_POSSIBLE_NAMES=geom_y ' + + '-f "ESRI Shapefile"', + ], + ) self.assertEqual( - alg.getConsoleCommands({'INPUT': source + '|credential:X=Y|credential:Z=A', - 'DISTANCE': 0.2, - 'OUTPUT': outdir + '/check.shp'}, context, feedback), - ['ogr2ogr', - outdir + '/check.shp ' + - source + ' ' + - '-dialect sqlite -sql "SELECT ST_Line_Interpolate_Point(geometry, 0.2) AS geometry,* FROM """polys2"""" --config X Y --config Z A ' + - '-f "ESRI Shapefile"']) - - -if __name__ == '__main__': + alg.getConsoleCommands( + { + "INPUT": source + "|credential:X=Y|credential:Z=A", + "DISTANCE": 0.2, + "OUTPUT": outdir + "/check.shp", + }, + context, + feedback, + ), + [ + "ogr2ogr", + outdir + + "/check.shp " + + source + + " " + + '-dialect sqlite -sql "SELECT ST_Line_Interpolate_Point(geometry, 0.2) AS geometry,* FROM """polys2"""" --config X Y --config Z A ' + + '-f "ESRI Shapefile"', + ], + ) + + +if __name__ == "__main__": nose2.main() diff --git a/python/plugins/processing/tests/GuiTest.py b/python/plugins/processing/tests/GuiTest.py index 57cc1e4dfb07..676393047e8e 100644 --- a/python/plugins/processing/tests/GuiTest.py +++ b/python/plugins/processing/tests/GuiTest.py @@ -15,27 +15,29 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'August 2017' -__copyright__ = '(C) 2017, Nyall Dawson' +__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.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 @@ -90,13 +92,15 @@ start_app() QgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms()) -testDataPath = os.path.join(os.path.dirname(__file__), 'testdata') +testDataPath = os.path.join(os.path.dirname(__file__), "testdata") class AlgorithmDialogTest(QgisTestCase): def testCreation(self): - alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids') + alg = QgsApplication.processingRegistry().createAlgorithmById( + "native:centroids" + ) a = AlgorithmDialog(alg) self.assertEqual(a.mainWidget().algorithm(), alg) @@ -109,7 +113,9 @@ def setUpClass(cls): ProcessingConfig.initialize() def checkConstructWrapper(self, param, expected_wrapper_class): - alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids') + alg = QgsApplication.processingRegistry().createAlgorithmById( + "native:centroids" + ) # algorithm dialog dlg = AlgorithmDialog(alg) @@ -122,7 +128,9 @@ def checkConstructWrapper(self, param, expected_wrapper_class): del wrapper.widget del wrapper - alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids') + alg = QgsApplication.processingRegistry().createAlgorithmById( + "native:centroids" + ) # batch dialog dlg = BatchAlgorithmDialog(alg) wrapper = WidgetWrapperFactory.create_wrapper_from_class(param, dlg) @@ -131,7 +139,9 @@ def checkConstructWrapper(self, param, expected_wrapper_class): self.assertEqual(wrapper.dialog, dlg) self.assertIsNotNone(wrapper.widget) - alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids') + alg = QgsApplication.processingRegistry().createAlgorithmById( + "native:centroids" + ) # modeler dialog model = QgsProcessingModelAlgorithm() @@ -146,46 +156,70 @@ def checkConstructWrapper(self, param, expected_wrapper_class): del wrapper.widget def testBoolean(self): - self.checkConstructWrapper(QgsProcessingParameterBoolean('test'), BooleanWidgetWrapper) + self.checkConstructWrapper( + QgsProcessingParameterBoolean("test"), BooleanWidgetWrapper + ) def testCrs(self): - self.checkConstructWrapper(QgsProcessingParameterCrs('test'), CrsWidgetWrapper) + self.checkConstructWrapper(QgsProcessingParameterCrs("test"), CrsWidgetWrapper) def testExtent(self): - self.checkConstructWrapper(QgsProcessingParameterExtent('test'), ExtentWidgetWrapper) + self.checkConstructWrapper( + QgsProcessingParameterExtent("test"), ExtentWidgetWrapper + ) def testPoint(self): - self.checkConstructWrapper(QgsProcessingParameterPoint('test'), PointWidgetWrapper) + self.checkConstructWrapper( + QgsProcessingParameterPoint("test"), PointWidgetWrapper + ) def testFile(self): - self.checkConstructWrapper(QgsProcessingParameterFile('test'), FileWidgetWrapper) + self.checkConstructWrapper( + QgsProcessingParameterFile("test"), FileWidgetWrapper + ) def testMultiInput(self): - self.checkConstructWrapper(QgsProcessingParameterMultipleLayers('test'), MultipleLayerWidgetWrapper) + self.checkConstructWrapper( + QgsProcessingParameterMultipleLayers("test"), MultipleLayerWidgetWrapper + ) def testRasterInput(self): - self.checkConstructWrapper(QgsProcessingParameterRasterLayer('test'), RasterWidgetWrapper) + self.checkConstructWrapper( + QgsProcessingParameterRasterLayer("test"), RasterWidgetWrapper + ) def testEnum(self): - self.checkConstructWrapper(QgsProcessingParameterEnum('test'), EnumWidgetWrapper) + self.checkConstructWrapper( + QgsProcessingParameterEnum("test"), EnumWidgetWrapper + ) def testString(self): - self.checkConstructWrapper(QgsProcessingParameterString('test'), StringWidgetWrapper) + self.checkConstructWrapper( + QgsProcessingParameterString("test"), StringWidgetWrapper + ) def testExpression(self): - self.checkConstructWrapper(QgsProcessingParameterExpression('test'), ExpressionWidgetWrapper) + self.checkConstructWrapper( + QgsProcessingParameterExpression("test"), ExpressionWidgetWrapper + ) def testVector(self): - self.checkConstructWrapper(QgsProcessingParameterVectorLayer('test'), VectorLayerWidgetWrapper) + self.checkConstructWrapper( + QgsProcessingParameterVectorLayer("test"), VectorLayerWidgetWrapper + ) def testField(self): - self.checkConstructWrapper(QgsProcessingParameterField('test'), TableFieldWidgetWrapper) + self.checkConstructWrapper( + QgsProcessingParameterField("test"), TableFieldWidgetWrapper + ) def testSource(self): - self.checkConstructWrapper(QgsProcessingParameterFeatureSource('test'), FeatureSourceWidgetWrapper) + self.checkConstructWrapper( + QgsProcessingParameterFeatureSource("test"), FeatureSourceWidgetWrapper + ) # dummy layer - layer = QgsVectorLayer('Point', 'test', 'memory') + layer = QgsVectorLayer("Point", "test", "memory") # need at least one feature in order to have a selection layer.dataProvider().addFeature(QgsFeature()) layer.selectAll() @@ -193,9 +227,11 @@ def testSource(self): self.assertTrue(layer.isValid()) QgsProject.instance().addMapLayer(layer) - alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids') + alg = QgsApplication.processingRegistry().createAlgorithmById( + "native:centroids" + ) dlg = AlgorithmDialog(alg) - param = QgsProcessingParameterFeatureSource('test') + param = QgsProcessingParameterFeatureSource("test") wrapper = FeatureSourceWidgetWrapper(param, dlg) widget = wrapper.createWidget() @@ -217,24 +253,29 @@ def testSource(self): self.assertEqual(value, layer.id()) # with non-project layer - wrapper.setValue('/home/my_layer.shp') + wrapper.setValue("/home/my_layer.shp") value = wrapper.value() - self.assertEqual(value, '/home/my_layer.shp') + 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) + self.checkConstructWrapper( + QgsProcessingParameterRange("test"), RangeWidgetWrapper + ) - alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids') + alg = QgsApplication.processingRegistry().createAlgorithmById( + "native:centroids" + ) dlg = AlgorithmDialog(alg) param = QgsProcessingParameterRange( - name='test', - description='test', + name="test", + description="test", type=QgsProcessingParameterNumber.Type.Double, - defaultValue="0.0,100.0") + defaultValue="0.0,100.0", + ) wrapper = RangeWidgetWrapper(param, dlg) widget = wrapper.createWidget() @@ -242,24 +283,25 @@ def testRange(self): # range values check # check initial value - self.assertEqual(widget.getValue(), '0.0,100.0') + 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') + 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') + self.assertEqual(widget.getValue(), "100.0,100.0") widget.spnMax.setValue(50) - self.assertEqual(widget.getValue(), '50.0,50.0') + self.assertEqual(widget.getValue(), "50.0,50.0") widget.spnMin.setValue(100) - self.assertEqual(widget.getValue(), '100.0,100.0') + self.assertEqual(widget.getValue(), "100.0,100.0") # check for integers param = QgsProcessingParameterRange( - name='test', - description='test', + name="test", + description="test", type=QgsProcessingParameterNumber.Type.Integer, - defaultValue="0.1,100.1") + defaultValue="0.1,100.1", + ) wrapper = RangeWidgetWrapper(param, dlg) widget = wrapper.createWidget() @@ -267,35 +309,43 @@ def testRange(self): # range values check # check initial value - self.assertEqual(widget.getValue(), '0.0,100.0') + self.assertEqual(widget.getValue(), "0.0,100.0") # check rounding widget.setValue("100.1,200.1") - self.assertEqual(widget.getValue(), '100.0,200.0') + self.assertEqual(widget.getValue(), "100.0,200.0") widget.setValue("100.6,200.6") - self.assertEqual(widget.getValue(), '101.0,201.0') + 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') + 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') + self.assertEqual(widget.getValue(), "100.0,100.0") widget.spnMax.setValue(50.1) - self.assertEqual(widget.getValue(), '50.0,50.0') + self.assertEqual(widget.getValue(), "50.0,50.0") widget.spnMin.setValue(100.1) - self.assertEqual(widget.getValue(), '100.0,100.0') + self.assertEqual(widget.getValue(), "100.0,100.0") def testMapLayer(self): - self.checkConstructWrapper(QgsProcessingParameterMapLayer('test'), MapLayerWidgetWrapper) + self.checkConstructWrapper( + QgsProcessingParameterMapLayer("test"), MapLayerWidgetWrapper + ) def testMeshLayer(self): - self.checkConstructWrapper(QgsProcessingParameterMeshLayer('test'), MeshWidgetWrapper) + self.checkConstructWrapper( + QgsProcessingParameterMeshLayer("test"), MeshWidgetWrapper + ) def testDistance(self): - self.checkConstructWrapper(QgsProcessingParameterDistance('test'), DistanceWidgetWrapper) + self.checkConstructWrapper( + QgsProcessingParameterDistance("test"), DistanceWidgetWrapper + ) - alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids') + alg = QgsApplication.processingRegistry().createAlgorithmById( + "native:centroids" + ) dlg = AlgorithmDialog(alg) - param = QgsProcessingParameterDistance('test') + param = QgsProcessingParameterDistance("test") wrapper = DistanceWidgetWrapper(param, dlg) widget = wrapper.createWidget() @@ -303,28 +353,32 @@ def testDistance(self): widget.show() # crs values - widget.setUnitParameterValue('EPSG:3111') - self.assertEqual(widget.label.text(), 'meters') + 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) + self.assertEqual( + widget.units_combo.currentData(), QgsUnitTypes.DistanceUnit.DistanceMeters + ) - widget.setUnitParameterValue('EPSG:4326') - self.assertEqual(widget.label.text(), 'degrees') + 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') + 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) + self.assertEqual( + widget.units_combo.currentData(), QgsUnitTypes.DistanceUnit.DistanceMeters + ) - widget.setUnitParameterValue(QgsCoordinateReferenceSystem('EPSG:4326')) - self.assertEqual(widget.label.text(), 'degrees') + 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()) @@ -332,22 +386,24 @@ def testDistance(self): # layer values vl = QgsVectorLayer("Polygon?crs=epsg:3111&field=pk:int", "vl", "memory") widget.setUnitParameterValue(vl) - self.assertEqual(widget.label.text(), 'meters') + 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) + 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.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(), '') + self.assertEqual(widget.label.text(), "") self.assertFalse(widget.warning_label.isVisible()) self.assertFalse(widget.units_combo.isVisible()) self.assertTrue(widget.label.isVisible()) @@ -355,15 +411,19 @@ def testDistance(self): # resolvable text value QgsProject.instance().addMapLayer(vl) widget.setUnitParameterValue(vl.id()) - self.assertEqual(widget.label.text(), 'meters') + 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) + 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)) + widget.units_combo.setCurrentIndex( + widget.units_combo.findData(QgsUnitTypes.DistanceUnit.DistanceKilometers) + ) self.assertEqual(widget.getValue(), 5000) widget.setValue(2) self.assertEqual(widget.getValue(), 2000) @@ -376,16 +436,22 @@ def testDistance(self): widget.deleteLater() def testMatrix(self): - self.checkConstructWrapper(QgsProcessingParameterMatrix('test'), FixedTableWidgetWrapper) + self.checkConstructWrapper( + QgsProcessingParameterMatrix("test"), FixedTableWidgetWrapper + ) - alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids') + alg = QgsApplication.processingRegistry().createAlgorithmById( + "native:centroids" + ) dlg = AlgorithmDialog(alg) - param = QgsProcessingParameterMatrix('test', 'test', 2, True, ['x', 'y'], [['a', 'b'], ['c', 'd']]) + 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']]) + self.assertEqual(wrapper.value(), [["a", "b"], ["c", "d"]]) # test widget widget.show() @@ -395,11 +461,15 @@ def testMatrix(self): widget.deleteLater() def testNumber(self): - self.checkConstructWrapper(QgsProcessingParameterNumber('test'), NumberWidgetWrapper) + self.checkConstructWrapper( + QgsProcessingParameterNumber("test"), NumberWidgetWrapper + ) def testBand(self): - self.checkConstructWrapper(QgsProcessingParameterBand('test'), BandWidgetWrapper) + self.checkConstructWrapper( + QgsProcessingParameterBand("test"), BandWidgetWrapper + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/python/plugins/processing/tests/ModelerTest.py b/python/plugins/processing/tests/ModelerTest.py index 0ef46470485f..604b2d3037cb 100644 --- a/python/plugins/processing/tests/ModelerTest.py +++ b/python/plugins/processing/tests/ModelerTest.py @@ -15,21 +15,23 @@ ***************************************************************************8 """ -__author__ = 'Nyall Dawson' -__date__ = 'November 2016' -__copyright__ = '(C) 2016, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "November 2016" +__copyright__ = "(C) 2016, Nyall Dawson" import unittest from qgis.testing import start_app, QgisTestCase -from qgis.core import (QgsProcessingModelAlgorithm, - QgsProcessingModelParameter, - QgsProcessingParameterString, - QgsProcessingParameterNumber, - QgsProcessingParameterDistance, - QgsProcessingParameterField, - QgsProcessingParameterFile) -from processing.modeler.ModelerParametersDialog import (ModelerParametersDialog) +from qgis.core import ( + QgsProcessingModelAlgorithm, + QgsProcessingModelParameter, + QgsProcessingParameterString, + QgsProcessingParameterNumber, + QgsProcessingParameterDistance, + QgsProcessingParameterField, + QgsProcessingParameterFile, +) +from processing.modeler.ModelerParametersDialog import ModelerParametersDialog start_app() @@ -41,34 +43,60 @@ def testModelerParametersDialogAvailableValuesOfType(self): m = QgsProcessingModelAlgorithm() - string_param_1 = QgsProcessingModelParameter('string') - m.addModelParameter(QgsProcessingParameterString('string'), string_param_1) + string_param_1 = QgsProcessingModelParameter("string") + m.addModelParameter(QgsProcessingParameterString("string"), string_param_1) - string_param_2 = QgsProcessingModelParameter('string2') - m.addModelParameter(QgsProcessingParameterString('string2'), string_param_2) + string_param_2 = QgsProcessingModelParameter("string2") + m.addModelParameter(QgsProcessingParameterString("string2"), string_param_2) - num_param = QgsProcessingModelParameter('number') - m.addModelParameter(QgsProcessingParameterNumber('number'), num_param) + num_param = QgsProcessingModelParameter("number") + m.addModelParameter(QgsProcessingParameterNumber("number"), num_param) - table_field_param = QgsProcessingModelParameter('field') - m.addModelParameter(QgsProcessingParameterField('field'), table_field_param) + table_field_param = QgsProcessingModelParameter("field") + m.addModelParameter(QgsProcessingParameterField("field"), table_field_param) - file_param = QgsProcessingModelParameter('file') - m.addModelParameter(QgsProcessingParameterFile('file'), file_param) + file_param = QgsProcessingModelParameter("file") + m.addModelParameter(QgsProcessingParameterFile("file"), file_param) dlg = ModelerParametersDialog(m, m) # test single types - self.assertEqual({p.parameterName() for p in dlg.getAvailableValuesOfType(QgsProcessingParameterNumber)}, - {'number'}) - self.assertEqual({p.parameterName() for p in dlg.getAvailableValuesOfType(QgsProcessingParameterField)}, - {'field'}) - self.assertEqual({p.parameterName() for p in dlg.getAvailableValuesOfType(QgsProcessingParameterFile)}, - {'file'}) + self.assertEqual( + { + p.parameterName() + for p in dlg.getAvailableValuesOfType(QgsProcessingParameterNumber) + }, + {"number"}, + ) + self.assertEqual( + { + p.parameterName() + for p in dlg.getAvailableValuesOfType(QgsProcessingParameterField) + }, + {"field"}, + ) + self.assertEqual( + { + p.parameterName() + for p in dlg.getAvailableValuesOfType(QgsProcessingParameterFile) + }, + {"file"}, + ) # test multiple types - self.assertEqual({p.parameterName() for p in dlg.getAvailableValuesOfType([QgsProcessingParameterString, QgsProcessingParameterNumber, QgsProcessingParameterFile])}, - {'string', 'string2', 'number', 'file'}) - - -if __name__ == '__main__': + self.assertEqual( + { + p.parameterName() + for p in dlg.getAvailableValuesOfType( + [ + QgsProcessingParameterString, + QgsProcessingParameterNumber, + QgsProcessingParameterFile, + ] + ) + }, + {"string", "string2", "number", "file"}, + ) + + +if __name__ == "__main__": unittest.main() diff --git a/python/plugins/processing/tests/ParametersTest.py b/python/plugins/processing/tests/ParametersTest.py index c5c845c0a618..cfcebc154527 100644 --- a/python/plugins/processing/tests/ParametersTest.py +++ b/python/plugins/processing/tests/ParametersTest.py @@ -15,23 +15,25 @@ *************************************************************************** """ -__author__ = 'René-Luc DHONT' -__date__ = 'May 2021' -__copyright__ = '(C) 2021, René-Luc DHONT' +__author__ = "René-Luc DHONT" +__date__ = "May 2021" +__copyright__ = "(C) 2021, René-Luc DHONT" import os import shutil -from qgis.core import (QgsProcessingParameterDefinition, - QgsProcessingParameterNumber, - QgsProcessingParameterFile, - QgsProcessing) +from qgis.core import ( + QgsProcessingParameterDefinition, + QgsProcessingParameterNumber, + QgsProcessingParameterFile, + QgsProcessing, +) import unittest from qgis.testing import start_app, QgisTestCase from processing.core.parameters import getParameterFromString -testDataPath = os.path.join(os.path.dirname(__file__), 'testdata') +testDataPath = os.path.join(os.path.dirname(__file__), "testdata") start_app() @@ -48,695 +50,889 @@ def tearDownClass(cls): shutil.rmtree(path) def testParameterStringDesc(self): - desc = 'QgsProcessingParameterString|in_string|Input String' + desc = "QgsProcessingParameterString|in_string|Input String" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'string') - self.assertEqual(param.name(), 'in_string') - self.assertEqual(param.description(), 'Input String') - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertEqual(param.type(), "string") + self.assertEqual(param.name(), "in_string") + self.assertEqual(param.description(), "Input String") + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterString|in_string|Input String|default value' + desc = "QgsProcessingParameterString|in_string|Input String|default value" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'string') - self.assertEqual(param.name(), 'in_string') - self.assertEqual(param.description(), 'Input String') - self.assertEqual(param.defaultValue(), 'default value') - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertEqual(param.type(), "string") + self.assertEqual(param.name(), "in_string") + self.assertEqual(param.description(), "Input String") + self.assertEqual(param.defaultValue(), "default value") + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterString|in_string|Input String|default value|True' + desc = "QgsProcessingParameterString|in_string|Input String|default value|True" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'string') - self.assertEqual(param.name(), 'in_string') - self.assertEqual(param.description(), 'Input String') - self.assertEqual(param.defaultValue(), 'default value') + self.assertEqual(param.type(), "string") + self.assertEqual(param.name(), "in_string") + self.assertEqual(param.description(), "Input String") + self.assertEqual(param.defaultValue(), "default value") self.assertTrue(param.multiLine()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterString|in_string|Input String||False|True' + desc = "QgsProcessingParameterString|in_string|Input String||False|True" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'string') - self.assertEqual(param.name(), 'in_string') - self.assertEqual(param.description(), 'Input String') - self.assertEqual(param.defaultValue(), '') + self.assertEqual(param.type(), "string") + self.assertEqual(param.name(), "in_string") + self.assertEqual(param.description(), "Input String") + self.assertEqual(param.defaultValue(), "") self.assertFalse(param.multiLine()) - self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertTrue( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) def testParameterNumberDesc(self): - desc = 'QgsProcessingParameterNumber|in_number|Input Number' + desc = "QgsProcessingParameterNumber|in_number|Input Number" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'number') - self.assertEqual(param.name(), 'in_number') - self.assertEqual(param.description(), 'Input Number') + self.assertEqual(param.type(), "number") + self.assertEqual(param.name(), "in_number") + self.assertEqual(param.description(), "Input Number") self.assertEqual(param.dataType(), QgsProcessingParameterNumber.Type.Integer) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Double' + desc = "QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Double" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'number') - self.assertEqual(param.name(), 'in_number') - self.assertEqual(param.description(), 'Input Number') + self.assertEqual(param.type(), "number") + self.assertEqual(param.name(), "in_number") + self.assertEqual(param.description(), "Input Number") self.assertEqual(param.dataType(), QgsProcessingParameterNumber.Type.Double) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Integer|10' + desc = "QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Integer|10" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'number') - self.assertEqual(param.name(), 'in_number') - self.assertEqual(param.description(), 'Input Number') + self.assertEqual(param.type(), "number") + self.assertEqual(param.name(), "in_number") + self.assertEqual(param.description(), "Input Number") self.assertEqual(param.dataType(), QgsProcessingParameterNumber.Type.Integer) self.assertEqual(param.defaultValue(), 10) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Integer|None|True' + desc = "QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Integer|None|True" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'number') - self.assertEqual(param.name(), 'in_number') - self.assertEqual(param.description(), 'Input Number') + self.assertEqual(param.type(), "number") + self.assertEqual(param.name(), "in_number") + self.assertEqual(param.description(), "Input Number") self.assertEqual(param.dataType(), QgsProcessingParameterNumber.Type.Integer) self.assertIsNone(param.defaultValue()) - self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertTrue( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Integer|10|False|0' + desc = "QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Integer|10|False|0" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'number') - self.assertEqual(param.name(), 'in_number') - self.assertEqual(param.description(), 'Input Number') + self.assertEqual(param.type(), "number") + self.assertEqual(param.name(), "in_number") + self.assertEqual(param.description(), "Input Number") self.assertEqual(param.dataType(), QgsProcessingParameterNumber.Type.Integer) self.assertEqual(param.defaultValue(), 10) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertEqual(param.minimum(), 0) - desc = 'QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Integer|10|False|0|20' + desc = "QgsProcessingParameterNumber|in_number|Input Number|QgsProcessingParameterNumber.Integer|10|False|0|20" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'number') - self.assertEqual(param.name(), 'in_number') - self.assertEqual(param.description(), 'Input Number') + self.assertEqual(param.type(), "number") + self.assertEqual(param.name(), "in_number") + self.assertEqual(param.description(), "Input Number") self.assertEqual(param.dataType(), QgsProcessingParameterNumber.Type.Integer) self.assertEqual(param.defaultValue(), 10) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertEqual(param.minimum(), 0) self.assertEqual(param.maximum(), 20) def testParameterBooleanDesc(self): - desc = 'QgsProcessingParameterBoolean|in_bool|Input Boolean' + desc = "QgsProcessingParameterBoolean|in_bool|Input Boolean" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'boolean') - self.assertEqual(param.name(), 'in_bool') - self.assertEqual(param.description(), 'Input Boolean') + self.assertEqual(param.type(), "boolean") + self.assertEqual(param.name(), "in_bool") + self.assertEqual(param.description(), "Input Boolean") self.assertFalse(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterBoolean|in_bool|Input Boolean|True' + desc = "QgsProcessingParameterBoolean|in_bool|Input Boolean|True" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'boolean') - self.assertEqual(param.name(), 'in_bool') - self.assertEqual(param.description(), 'Input Boolean') + self.assertEqual(param.type(), "boolean") + self.assertEqual(param.name(), "in_bool") + self.assertEqual(param.description(), "Input Boolean") self.assertTrue(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterBoolean|in_bool|Input Boolean|False|True' + desc = "QgsProcessingParameterBoolean|in_bool|Input Boolean|False|True" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'boolean') - self.assertEqual(param.name(), 'in_bool') - self.assertEqual(param.description(), 'Input Boolean') + self.assertEqual(param.type(), "boolean") + self.assertEqual(param.name(), "in_bool") + self.assertEqual(param.description(), "Input Boolean") self.assertFalse(param.defaultValue()) - self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertTrue( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) def testParameterCrsDesc(self): - desc = 'QgsProcessingParameterCrs|in_crs|Input CRS' + desc = "QgsProcessingParameterCrs|in_crs|Input CRS" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'crs') - self.assertEqual(param.name(), 'in_crs') - self.assertEqual(param.description(), 'Input CRS') + self.assertEqual(param.type(), "crs") + self.assertEqual(param.name(), "in_crs") + self.assertEqual(param.description(), "Input CRS") self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterCrs|in_crs|Input CRS|EPSG:2154' + desc = "QgsProcessingParameterCrs|in_crs|Input CRS|EPSG:2154" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'crs') - self.assertEqual(param.name(), 'in_crs') - self.assertEqual(param.description(), 'Input CRS') - self.assertEqual(param.defaultValue(), 'EPSG:2154') - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertEqual(param.type(), "crs") + self.assertEqual(param.name(), "in_crs") + self.assertEqual(param.description(), "Input CRS") + self.assertEqual(param.defaultValue(), "EPSG:2154") + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterCrs|in_crs|Input CRS|None|True' + desc = "QgsProcessingParameterCrs|in_crs|Input CRS|None|True" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'crs') - self.assertEqual(param.name(), 'in_crs') - self.assertEqual(param.description(), 'Input CRS') + self.assertEqual(param.type(), "crs") + self.assertEqual(param.name(), "in_crs") + self.assertEqual(param.description(), "Input CRS") self.assertIsNone(param.defaultValue()) - self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertTrue( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) def testParameterExtentDesc(self): - desc = 'QgsProcessingParameterExtent|in_extent|Input Extent' + desc = "QgsProcessingParameterExtent|in_extent|Input Extent" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'extent') - self.assertEqual(param.name(), 'in_extent') - self.assertEqual(param.description(), 'Input Extent') + self.assertEqual(param.type(), "extent") + self.assertEqual(param.name(), "in_extent") + self.assertEqual(param.description(), "Input Extent") self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterExtent|in_extent|Input Extent|None|True' + desc = "QgsProcessingParameterExtent|in_extent|Input Extent|None|True" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'extent') - self.assertEqual(param.name(), 'in_extent') - self.assertEqual(param.description(), 'Input Extent') + self.assertEqual(param.type(), "extent") + self.assertEqual(param.name(), "in_extent") + self.assertEqual(param.description(), "Input Extent") self.assertIsNone(param.defaultValue()) - self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertTrue( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) def testParameterFileDesc(self): - desc = 'QgsProcessingParameterFile|in_file|Input File' + desc = "QgsProcessingParameterFile|in_file|Input File" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'file') - self.assertEqual(param.name(), 'in_file') - self.assertEqual(param.description(), 'Input File') + self.assertEqual(param.type(), "file") + self.assertEqual(param.name(), "in_file") + self.assertEqual(param.description(), "Input File") self.assertEqual(param.behavior(), QgsProcessingParameterFile.Behavior.File) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterFile|in_folder|Input Folder|1' + desc = "QgsProcessingParameterFile|in_folder|Input Folder|1" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'file') - self.assertEqual(param.name(), 'in_folder') - self.assertEqual(param.description(), 'Input Folder') + self.assertEqual(param.type(), "file") + self.assertEqual(param.name(), "in_folder") + self.assertEqual(param.description(), "Input Folder") self.assertEqual(param.behavior(), QgsProcessingParameterFile.Behavior.Folder) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterFile|in_folder|Input Folder|QgsProcessingParameterFile.Folder' + desc = "QgsProcessingParameterFile|in_folder|Input Folder|QgsProcessingParameterFile.Folder" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'file') - self.assertEqual(param.name(), 'in_folder') - self.assertEqual(param.description(), 'Input Folder') + self.assertEqual(param.type(), "file") + self.assertEqual(param.name(), "in_folder") + self.assertEqual(param.description(), "Input Folder") self.assertEqual(param.behavior(), QgsProcessingParameterFile.Behavior.Folder) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterFile|in_file|Input File|0|gpkg' + desc = "QgsProcessingParameterFile|in_file|Input File|0|gpkg" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'file') - self.assertEqual(param.name(), 'in_file') - self.assertEqual(param.description(), 'Input File') + self.assertEqual(param.type(), "file") + self.assertEqual(param.name(), "in_file") + self.assertEqual(param.description(), "Input File") self.assertEqual(param.behavior(), QgsProcessingParameterFile.Behavior.File) - self.assertEqual(param.extension(), 'gpkg') + self.assertEqual(param.extension(), "gpkg") self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterFile|in_file|Input File|0|png|None|False|PNG Files (*.png);; JPG Files (*.jpg *.jpeg)' + desc = "QgsProcessingParameterFile|in_file|Input File|0|png|None|False|PNG Files (*.png);; JPG Files (*.jpg *.jpeg)" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'file') - self.assertEqual(param.name(), 'in_file') - self.assertEqual(param.description(), 'Input File') + self.assertEqual(param.type(), "file") + self.assertEqual(param.name(), "in_file") + self.assertEqual(param.description(), "Input File") self.assertEqual(param.behavior(), QgsProcessingParameterFile.Behavior.File) - self.assertEqual(param.extension(), '') + self.assertEqual(param.extension(), "") self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) - self.assertEqual(param.fileFilter(), 'PNG Files (*.png);; JPG Files (*.jpg *.jpeg)') + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) + self.assertEqual( + param.fileFilter(), "PNG Files (*.png);; JPG Files (*.jpg *.jpeg)" + ) def testParameterVectorDestDesc(self): - desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination' + desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vectorDestination') - self.assertEqual(param.name(), 'param_vector_dest') - self.assertEqual(param.description(), 'Vector Destination') - self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVectorAnyGeometry) + self.assertEqual(param.type(), "vectorDestination") + self.assertEqual(param.name(), "param_vector_dest") + self.assertEqual(param.description(), "Vector Destination") + self.assertEqual( + param.dataType(), QgsProcessing.SourceType.TypeVectorAnyGeometry + ) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertTrue(param.createByDefault()) - desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Point|0' + desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Point|0" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vectorDestination') - self.assertEqual(param.name(), 'param_vector_dest') - self.assertEqual(param.description(), 'Vector Destination Point') + self.assertEqual(param.type(), "vectorDestination") + self.assertEqual(param.name(), "param_vector_dest") + self.assertEqual(param.description(), "Vector Destination Point") self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVectorPoint) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertTrue(param.createByDefault()) - desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Point|QgsProcessing.TypeVectorPoint' + desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Point|QgsProcessing.TypeVectorPoint" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vectorDestination') - self.assertEqual(param.name(), 'param_vector_dest') - self.assertEqual(param.description(), 'Vector Destination Point') + self.assertEqual(param.type(), "vectorDestination") + self.assertEqual(param.name(), "param_vector_dest") + self.assertEqual(param.description(), "Vector Destination Point") self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVectorPoint) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertTrue(param.createByDefault()) - desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Line|1' + desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Line|1" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vectorDestination') - self.assertEqual(param.name(), 'param_vector_dest') - self.assertEqual(param.description(), 'Vector Destination Line') + self.assertEqual(param.type(), "vectorDestination") + self.assertEqual(param.name(), "param_vector_dest") + self.assertEqual(param.description(), "Vector Destination Line") self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVectorLine) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertTrue(param.createByDefault()) - desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Line|QgsProcessing.TypeVectorLine' + desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Line|QgsProcessing.TypeVectorLine" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vectorDestination') - self.assertEqual(param.name(), 'param_vector_dest') - self.assertEqual(param.description(), 'Vector Destination Line') + self.assertEqual(param.type(), "vectorDestination") + self.assertEqual(param.name(), "param_vector_dest") + self.assertEqual(param.description(), "Vector Destination Line") self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVectorLine) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertTrue(param.createByDefault()) - desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Polygon|2' + desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Polygon|2" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vectorDestination') - self.assertEqual(param.name(), 'param_vector_dest') - self.assertEqual(param.description(), 'Vector Destination Polygon') + self.assertEqual(param.type(), "vectorDestination") + self.assertEqual(param.name(), "param_vector_dest") + self.assertEqual(param.description(), "Vector Destination Polygon") self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVectorPolygon) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertTrue(param.createByDefault()) - desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Polygon|QgsProcessing.TypeVectorPolygon' + desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Polygon|QgsProcessing.TypeVectorPolygon" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vectorDestination') - self.assertEqual(param.name(), 'param_vector_dest') - self.assertEqual(param.description(), 'Vector Destination Polygon') + self.assertEqual(param.type(), "vectorDestination") + self.assertEqual(param.name(), "param_vector_dest") + self.assertEqual(param.description(), "Vector Destination Polygon") self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVectorPolygon) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertTrue(param.createByDefault()) - desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Table|5' + desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Table|5" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vectorDestination') - self.assertEqual(param.name(), 'param_vector_dest') - self.assertEqual(param.description(), 'Vector Destination Table') + self.assertEqual(param.type(), "vectorDestination") + self.assertEqual(param.name(), "param_vector_dest") + self.assertEqual(param.description(), "Vector Destination Table") self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVector) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertTrue(param.createByDefault()) - desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Table|QgsProcessing.TypeVector' + desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination Table|QgsProcessing.TypeVector" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vectorDestination') - self.assertEqual(param.name(), 'param_vector_dest') - self.assertEqual(param.description(), 'Vector Destination Table') + self.assertEqual(param.type(), "vectorDestination") + self.assertEqual(param.name(), "param_vector_dest") + self.assertEqual(param.description(), "Vector Destination Table") self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVector) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertTrue(param.createByDefault()) - desc = 'QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination|-1|None|True|False' + desc = "QgsProcessingParameterVectorDestination|param_vector_dest|Vector Destination|-1|None|True|False" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vectorDestination') - self.assertEqual(param.name(), 'param_vector_dest') - self.assertEqual(param.description(), 'Vector Destination') - self.assertEqual(param.dataType(), QgsProcessing.SourceType.TypeVectorAnyGeometry) + self.assertEqual(param.type(), "vectorDestination") + self.assertEqual(param.name(), "param_vector_dest") + self.assertEqual(param.description(), "Vector Destination") + self.assertEqual( + param.dataType(), QgsProcessing.SourceType.TypeVectorAnyGeometry + ) self.assertIsNone(param.defaultValue()) - self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertTrue( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertFalse(param.createByDefault()) def testParameterRasterDestDesc(self): - desc = 'QgsProcessingParameterRasterDestination|param_raster_dest|Raster Destination' + desc = "QgsProcessingParameterRasterDestination|param_raster_dest|Raster Destination" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'rasterDestination') - self.assertEqual(param.name(), 'param_raster_dest') - self.assertEqual(param.description(), 'Raster Destination') + self.assertEqual(param.type(), "rasterDestination") + self.assertEqual(param.name(), "param_raster_dest") + self.assertEqual(param.description(), "Raster Destination") self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertTrue(param.createByDefault()) - desc = 'QgsProcessingParameterRasterDestination|param_raster_dest|Raster Destination|None|True|False' + desc = "QgsProcessingParameterRasterDestination|param_raster_dest|Raster Destination|None|True|False" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'rasterDestination') - self.assertEqual(param.name(), 'param_raster_dest') - self.assertEqual(param.description(), 'Raster Destination') + self.assertEqual(param.type(), "rasterDestination") + self.assertEqual(param.name(), "param_raster_dest") + self.assertEqual(param.description(), "Raster Destination") self.assertIsNone(param.defaultValue()) - self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertTrue( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertFalse(param.createByDefault()) def testParameterFolderDestDesc(self): - desc = 'QgsProcessingParameterFolderDestination|param_folder_dest|Folder Destination' + desc = "QgsProcessingParameterFolderDestination|param_folder_dest|Folder Destination" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'folderDestination') - self.assertEqual(param.name(), 'param_folder_dest') - self.assertEqual(param.description(), 'Folder Destination') + self.assertEqual(param.type(), "folderDestination") + self.assertEqual(param.name(), "param_folder_dest") + self.assertEqual(param.description(), "Folder Destination") self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertTrue(param.createByDefault()) - desc = 'QgsProcessingParameterFolderDestination|param_folder_dest|Folder Destination|None|True|False' + desc = "QgsProcessingParameterFolderDestination|param_folder_dest|Folder Destination|None|True|False" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'folderDestination') - self.assertEqual(param.name(), 'param_folder_dest') - self.assertEqual(param.description(), 'Folder Destination') + self.assertEqual(param.type(), "folderDestination") + self.assertEqual(param.name(), "param_folder_dest") + self.assertEqual(param.description(), "Folder Destination") self.assertIsNone(param.defaultValue()) - self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertTrue( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertFalse(param.createByDefault()) def testParameterFileDestDesc(self): - desc = 'QgsProcessingParameterFileDestination|param_file_dest|File Destination' + desc = "QgsProcessingParameterFileDestination|param_file_dest|File Destination" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'fileDestination') - self.assertEqual(param.name(), 'param_file_dest') - self.assertEqual(param.description(), 'File Destination') + self.assertEqual(param.type(), "fileDestination") + self.assertEqual(param.name(), "param_file_dest") + self.assertEqual(param.description(), "File Destination") self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertTrue(param.createByDefault()) - desc = 'QgsProcessingParameterFileDestination|param_html_dest|HTML File Destination|HTML Files (*.html)' + desc = "QgsProcessingParameterFileDestination|param_html_dest|HTML File Destination|HTML Files (*.html)" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'fileDestination') - self.assertEqual(param.name(), 'param_html_dest') - self.assertEqual(param.description(), 'HTML File Destination') - self.assertEqual(param.fileFilter(), 'HTML Files (*.html)') - self.assertEqual(param.defaultFileExtension(), 'html') + self.assertEqual(param.type(), "fileDestination") + self.assertEqual(param.name(), "param_html_dest") + self.assertEqual(param.description(), "HTML File Destination") + self.assertEqual(param.fileFilter(), "HTML Files (*.html)") + self.assertEqual(param.defaultFileExtension(), "html") self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertTrue(param.createByDefault()) - desc = 'QgsProcessingParameterFileDestination|param_img_dest|Img File Destination|PNG Files (*.png);; JPG Files (*.jpg *.jpeg)' + desc = "QgsProcessingParameterFileDestination|param_img_dest|Img File Destination|PNG Files (*.png);; JPG Files (*.jpg *.jpeg)" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'fileDestination') - self.assertEqual(param.name(), 'param_img_dest') - self.assertEqual(param.description(), 'Img File Destination') - self.assertEqual(param.fileFilter(), 'PNG Files (*.png);; JPG Files (*.jpg *.jpeg)') - self.assertEqual(param.defaultFileExtension(), 'png') + self.assertEqual(param.type(), "fileDestination") + self.assertEqual(param.name(), "param_img_dest") + self.assertEqual(param.description(), "Img File Destination") + self.assertEqual( + param.fileFilter(), "PNG Files (*.png);; JPG Files (*.jpg *.jpeg)" + ) + self.assertEqual(param.defaultFileExtension(), "png") self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertTrue(param.createByDefault()) - desc = 'QgsProcessingParameterFileDestination|param_csv_dest|CSV File Destination|CSV Files (*.csv)|None|True|False' + desc = "QgsProcessingParameterFileDestination|param_csv_dest|CSV File Destination|CSV Files (*.csv)|None|True|False" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'fileDestination') - self.assertEqual(param.name(), 'param_csv_dest') - self.assertEqual(param.description(), 'CSV File Destination') - self.assertEqual(param.fileFilter(), 'CSV Files (*.csv)') - self.assertEqual(param.defaultFileExtension(), 'csv') + self.assertEqual(param.type(), "fileDestination") + self.assertEqual(param.name(), "param_csv_dest") + self.assertEqual(param.description(), "CSV File Destination") + self.assertEqual(param.fileFilter(), "CSV Files (*.csv)") + self.assertEqual(param.defaultFileExtension(), "csv") self.assertIsNone(param.defaultValue()) - self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertTrue( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) self.assertFalse(param.createByDefault()) def testParameterFeatureSourceDesc(self): - desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector' + desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'source') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') + self.assertEqual(param.type(), "source") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") self.assertListEqual(param.dataTypes(), []) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|0' + desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|0" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'source') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') - self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPoint]) + self.assertEqual(param.type(), "source") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") + self.assertListEqual( + param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPoint] + ) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVectorPoint' + desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVectorPoint" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'source') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') - self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPoint]) + self.assertEqual(param.type(), "source") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") + self.assertListEqual( + param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPoint] + ) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|1' + desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|1" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'source') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') - self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine]) + self.assertEqual(param.type(), "source") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") + self.assertListEqual( + param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine] + ) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVectorLine' + desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVectorLine" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'source') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') - self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine]) + self.assertEqual(param.type(), "source") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") + self.assertListEqual( + param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine] + ) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|2' + desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|2" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'source') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') - self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPolygon]) + self.assertEqual(param.type(), "source") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") + self.assertListEqual( + param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPolygon] + ) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVectorPolygon' + desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVectorPolygon" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'source') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') - self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPolygon]) + self.assertEqual(param.type(), "source") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") + self.assertListEqual( + param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPolygon] + ) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|5' + desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|5" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'source') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') + self.assertEqual(param.type(), "source") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVector]) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVector' + desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVector" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'source') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') + self.assertEqual(param.type(), "source") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVector]) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|1;2' + desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|1;2" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'source') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') - self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine, QgsProcessing.SourceType.TypeVectorPolygon]) + self.assertEqual(param.type(), "source") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") + self.assertListEqual( + param.dataTypes(), + [ + QgsProcessing.SourceType.TypeVectorLine, + QgsProcessing.SourceType.TypeVectorPolygon, + ], + ) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVectorLine;QgsProcessing.TypeVectorPolygon' + desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|QgsProcessing.TypeVectorLine;QgsProcessing.TypeVectorPolygon" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'source') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') - self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine, QgsProcessing.SourceType.TypeVectorPolygon]) + self.assertEqual(param.type(), "source") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") + self.assertListEqual( + param.dataTypes(), + [ + QgsProcessing.SourceType.TypeVectorLine, + QgsProcessing.SourceType.TypeVectorPolygon, + ], + ) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterFeatureSource|in_vector|Input Vector|-1|None|True' + desc = "QgsProcessingParameterFeatureSource|in_vector|Input Vector|-1|None|True" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'source') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') - self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorAnyGeometry]) + self.assertEqual(param.type(), "source") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") + self.assertListEqual( + param.dataTypes(), [QgsProcessing.SourceType.TypeVectorAnyGeometry] + ) self.assertIsNone(param.defaultValue()) - self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertTrue( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) def testParameterVectorLayerDesc(self): - desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector' + desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vector') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') + self.assertEqual(param.type(), "vector") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") self.assertListEqual(param.dataTypes(), []) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|0' + desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|0" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vector') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') - self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPoint]) + self.assertEqual(param.type(), "vector") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") + self.assertListEqual( + param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPoint] + ) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVectorPoint' + desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVectorPoint" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vector') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') - self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPoint]) + self.assertEqual(param.type(), "vector") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") + self.assertListEqual( + param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPoint] + ) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|1' + desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|1" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vector') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') - self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine]) + self.assertEqual(param.type(), "vector") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") + self.assertListEqual( + param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine] + ) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVectorLine' + desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVectorLine" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vector') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') - self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine]) + self.assertEqual(param.type(), "vector") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") + self.assertListEqual( + param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine] + ) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|2' + desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|2" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vector') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') - self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPolygon]) + self.assertEqual(param.type(), "vector") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") + self.assertListEqual( + param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPolygon] + ) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVectorPolygon' + desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVectorPolygon" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vector') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') - self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPolygon]) + self.assertEqual(param.type(), "vector") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") + self.assertListEqual( + param.dataTypes(), [QgsProcessing.SourceType.TypeVectorPolygon] + ) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|5' + desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|5" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vector') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') + self.assertEqual(param.type(), "vector") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVector]) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVector' + desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVector" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vector') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') + self.assertEqual(param.type(), "vector") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVector]) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|1;2' + desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|1;2" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vector') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') - self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine, QgsProcessing.SourceType.TypeVectorPolygon]) + self.assertEqual(param.type(), "vector") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") + self.assertListEqual( + param.dataTypes(), + [ + QgsProcessing.SourceType.TypeVectorLine, + QgsProcessing.SourceType.TypeVectorPolygon, + ], + ) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVectorLine;QgsProcessing.TypeVectorPolygon' + desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|QgsProcessing.TypeVectorLine;QgsProcessing.TypeVectorPolygon" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vector') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') - self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorLine, QgsProcessing.SourceType.TypeVectorPolygon]) + self.assertEqual(param.type(), "vector") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") + self.assertListEqual( + param.dataTypes(), + [ + QgsProcessing.SourceType.TypeVectorLine, + QgsProcessing.SourceType.TypeVectorPolygon, + ], + ) self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterVectorLayer|in_vector|Input Vector|-1|None|True' + desc = "QgsProcessingParameterVectorLayer|in_vector|Input Vector|-1|None|True" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'vector') - self.assertEqual(param.name(), 'in_vector') - self.assertEqual(param.description(), 'Input Vector') - self.assertListEqual(param.dataTypes(), [QgsProcessing.SourceType.TypeVectorAnyGeometry]) + self.assertEqual(param.type(), "vector") + self.assertEqual(param.name(), "in_vector") + self.assertEqual(param.description(), "Input Vector") + self.assertListEqual( + param.dataTypes(), [QgsProcessing.SourceType.TypeVectorAnyGeometry] + ) self.assertIsNone(param.defaultValue()) - self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertTrue( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) def testParameterRasterLayerDesc(self): - desc = 'QgsProcessingParameterRasterLayer|in_raster|Input Raster' + desc = "QgsProcessingParameterRasterLayer|in_raster|Input Raster" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'raster') - self.assertEqual(param.name(), 'in_raster') - self.assertEqual(param.description(), 'Input Raster') + self.assertEqual(param.type(), "raster") + self.assertEqual(param.name(), "in_raster") + self.assertEqual(param.description(), "Input Raster") self.assertIsNone(param.defaultValue()) - self.assertFalse(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertFalse( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) - desc = 'QgsProcessingParameterRasterLayer|in_raster|Input Raster|None|True' + desc = "QgsProcessingParameterRasterLayer|in_raster|Input Raster|None|True" param = getParameterFromString(desc) self.assertIsNotNone(param) - self.assertEqual(param.type(), 'raster') - self.assertEqual(param.name(), 'in_raster') - self.assertEqual(param.description(), 'Input Raster') + self.assertEqual(param.type(), "raster") + self.assertEqual(param.name(), "in_raster") + self.assertEqual(param.description(), "Input Raster") self.assertIsNone(param.defaultValue()) - self.assertTrue(param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional) + self.assertTrue( + param.flags() & QgsProcessingParameterDefinition.Flag.FlagOptional + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/python/plugins/processing/tests/ProcessingGeneralTest.py b/python/plugins/processing/tests/ProcessingGeneralTest.py index 0eb90ffac73c..a6d7731cc7ee 100644 --- a/python/plugins/processing/tests/ProcessingGeneralTest.py +++ b/python/plugins/processing/tests/ProcessingGeneralTest.py @@ -15,21 +15,23 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'January 2019' -__copyright__ = '(C) 2019, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "January 2019" +__copyright__ = "(C) 2019, Nyall Dawson" import nose2 import shutil import gc -from qgis.core import (QgsApplication, - QgsProcessing, - QgsProcessingContext, - QgsVectorLayer, - QgsProject) +from qgis.core import ( + QgsApplication, + QgsProcessing, + QgsProcessingContext, + QgsVectorLayer, + QgsProject, +) from qgis.PyQt import sip -from qgis.analysis import (QgsNativeAlgorithms) +from qgis.analysis import QgsNativeAlgorithms import unittest from qgis.testing import start_app, QgisTestCase import processing @@ -42,6 +44,7 @@ class TestProcessingGeneral(QgisTestCase): def setUpClass(cls): start_app() from processing.core.Processing import Processing + Processing.initialize() cls.cleanup_paths = [] cls.in_place_layers = {} @@ -50,6 +53,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): from processing.core.Processing import Processing + Processing.deinitialize() for path in cls.cleanup_paths: shutil.rmtree(path) @@ -58,27 +62,40 @@ def testRun(self): context = QgsProcessingContext() # try running an alg using processing.run - ownership of result layer should be transferred back to the caller - res = processing.run('qgis:buffer', - {'DISTANCE': 1, 'INPUT': points(), 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT}, - context=context) - self.assertIn('OUTPUT', res) + res = processing.run( + "qgis:buffer", + { + "DISTANCE": 1, + "INPUT": points(), + "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, + }, + context=context, + ) + self.assertIn("OUTPUT", res) # output should be the layer instance itself - self.assertIsInstance(res['OUTPUT'], QgsVectorLayer) + self.assertIsInstance(res["OUTPUT"], QgsVectorLayer) # Python should have ownership - self.assertTrue(sip.ispyowned(res['OUTPUT'])) + self.assertTrue(sip.ispyowned(res["OUTPUT"])) del context gc.collect() - self.assertFalse(sip.isdeleted(res['OUTPUT'])) + self.assertFalse(sip.isdeleted(res["OUTPUT"])) # now try using processing.run with is_child_algorithm = True. Ownership should remain with the context context = QgsProcessingContext() - res = processing.run('qgis:buffer', - {'DISTANCE': 1, 'INPUT': points(), 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT}, - context=context, is_child_algorithm=True) - self.assertIn('OUTPUT', res) + res = processing.run( + "qgis:buffer", + { + "DISTANCE": 1, + "INPUT": points(), + "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, + }, + context=context, + is_child_algorithm=True, + ) + self.assertIn("OUTPUT", res) # output should be a layer string reference, NOT the layer itself - self.assertIsInstance(res['OUTPUT'], str) - layer = context.temporaryLayerStore().mapLayer(res['OUTPUT']) + self.assertIsInstance(res["OUTPUT"], str) + layer = context.temporaryLayerStore().mapLayer(res["OUTPUT"]) self.assertIsInstance(layer, QgsVectorLayer) # context should have ownership self.assertFalse(sip.ispyowned(layer)) @@ -92,15 +109,24 @@ def testRunAndLoadResults(self): # try running an alg using processing.runAndLoadResults - ownership of result layer should be transferred to # project, and layer should be present in project - res = processing.runAndLoadResults('qgis:buffer', - {'DISTANCE': 1, 'INPUT': points(), 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT}, - context=context) - self.assertIn('OUTPUT', res) + res = processing.runAndLoadResults( + "qgis:buffer", + { + "DISTANCE": 1, + "INPUT": points(), + "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, + }, + context=context, + ) + self.assertIn("OUTPUT", res) # output should be the layer path - self.assertIsInstance(res['OUTPUT'], str) + self.assertIsInstance(res["OUTPUT"], str) - self.assertEqual(context.layersToLoadOnCompletion()[res['OUTPUT']].project, QgsProject.instance()) - layer = QgsProject.instance().mapLayer(res['OUTPUT']) + self.assertEqual( + context.layersToLoadOnCompletion()[res["OUTPUT"]].project, + QgsProject.instance(), + ) + layer = QgsProject.instance().mapLayer(res["OUTPUT"]) self.assertIsInstance(layer, QgsVectorLayer) # Python should NOT have ownership @@ -111,14 +137,14 @@ def testProviders(self): When run from a standalone script (like this test), ensure that the providers from separate plugins are available """ providers = [p.id() for p in QgsApplication.processingRegistry().providers()] - self.assertIn('qgis', providers) - self.assertIn('native', providers) - self.assertIn('gdal', providers) - self.assertIn('project', providers) - self.assertIn('script', providers) - self.assertIn('model', providers) - self.assertIn('grass', providers) + self.assertIn("qgis", providers) + self.assertIn("native", providers) + self.assertIn("gdal", providers) + self.assertIn("project", providers) + self.assertIn("script", providers) + self.assertIn("model", providers) + self.assertIn("grass", providers) -if __name__ == '__main__': +if __name__ == "__main__": nose2.main() diff --git a/python/plugins/processing/tests/ProjectProvider.py b/python/plugins/processing/tests/ProjectProvider.py index 6f0b157b7d0b..5bef743acfdc 100644 --- a/python/plugins/processing/tests/ProjectProvider.py +++ b/python/plugins/processing/tests/ProjectProvider.py @@ -15,16 +15,14 @@ ***************************************************************************8 """ -__author__ = 'Nyall Dawson' -__date__ = 'July 2018' -__copyright__ = '(C) 2018, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "July 2018" +__copyright__ = "(C) 2018, Nyall Dawson" import unittest from qgis.testing import start_app, QgisTestCase from qgis.PyQt.QtCore import QTemporaryFile -from qgis.core import (QgsApplication, - QgsProcessingModelAlgorithm, - QgsProject) +from qgis.core import QgsApplication, QgsProcessingModelAlgorithm, QgsProject from processing.modeler.ProjectProvider import ProjectProvider from processing.modeler.ModelerDialog import ModelerDialog @@ -38,9 +36,9 @@ def testSaveRestoreFromProject(self): provider = ProjectProvider(p) # add some algorithms - alg = QgsProcessingModelAlgorithm('test name', 'test group') + alg = QgsProcessingModelAlgorithm("test name", "test group") provider.add_model(alg) - alg2 = QgsProcessingModelAlgorithm('test name2', 'test group2') + alg2 = QgsProcessingModelAlgorithm("test name2", "test group2") provider.add_model(alg2) self.assertEqual(len(provider.algorithms()), 2) @@ -58,10 +56,10 @@ def testSaveRestoreFromProject(self): self.assertEqual(len(provider2.model_definitions), 2) self.assertEqual(len(provider2.algorithms()), 2) - self.assertEqual(provider2.algorithms()[0].name(), 'test name') - self.assertEqual(provider2.algorithms()[0].group(), 'test group') - self.assertEqual(provider2.algorithms()[1].name(), 'test name2') - self.assertEqual(provider2.algorithms()[1].group(), 'test group2') + self.assertEqual(provider2.algorithms()[0].name(), "test name") + self.assertEqual(provider2.algorithms()[0].group(), "test group") + self.assertEqual(provider2.algorithms()[1].name(), "test name2") + self.assertEqual(provider2.algorithms()[1].group(), "test group2") # clear project should remove algorithms p2.clear() @@ -75,9 +73,9 @@ def testDelete(self): provider = ProjectProvider(p) # add some models - alg = QgsProcessingModelAlgorithm('test name', 'test group') + alg = QgsProcessingModelAlgorithm("test name", "test group") provider.add_model(alg) - alg2 = QgsProcessingModelAlgorithm('test name2', 'test group2') + alg2 = QgsProcessingModelAlgorithm("test name2", "test group2") provider.add_model(alg2) self.assertEqual(len(provider.algorithms()), 2) @@ -86,21 +84,21 @@ def testDelete(self): self.assertEqual(len(provider.algorithms()), 2) # not in provider! - alg3 = QgsProcessingModelAlgorithm('test name3', 'test group') + alg3 = QgsProcessingModelAlgorithm("test name3", "test group") provider.remove_model(alg3) self.assertEqual(len(provider.algorithms()), 2) # delete model actually in project provider.remove_model(alg) self.assertEqual(len(provider.algorithms()), 1) - self.assertEqual(provider.algorithms()[0].name(), 'test name2') + self.assertEqual(provider.algorithms()[0].name(), "test name2") # overwrite model - alg2b = QgsProcessingModelAlgorithm('test name2', 'test group2') - alg2b.setHelpContent({'test': 'test'}) + alg2b = QgsProcessingModelAlgorithm("test name2", "test group2") + alg2b.setHelpContent({"test": "test"}) provider.add_model(alg2b) self.assertEqual(len(provider.algorithms()), 1) - self.assertEqual(provider.algorithms()[0].helpContent(), {'test': 'test'}) + self.assertEqual(provider.algorithms()[0].helpContent(), {"test": "test"}) provider.remove_model(alg2) self.assertEqual(len(provider.algorithms()), 0) @@ -114,16 +112,16 @@ def testDialog(self): QgsApplication.processingRegistry().addProvider(provider) # make an algorithm - alg = QgsProcessingModelAlgorithm('test name', 'test group') + alg = QgsProcessingModelAlgorithm("test name", "test group") dialog = ModelerDialog(alg) dialog.saveInProject() self.assertEqual(len(provider.model_definitions), 1) self.assertEqual(len(provider.algorithms()), 1) - self.assertEqual(provider.algorithms()[0].name(), 'test name') - self.assertEqual(provider.algorithms()[0].group(), 'test group') + self.assertEqual(provider.algorithms()[0].name(), "test name") + self.assertEqual(provider.algorithms()[0].group(), "test group") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/python/plugins/processing/tests/QgisAlgorithmsTest1.py b/python/plugins/processing/tests/QgisAlgorithmsTest1.py index 802081224250..fbab5d909dd2 100644 --- a/python/plugins/processing/tests/QgisAlgorithmsTest1.py +++ b/python/plugins/processing/tests/QgisAlgorithmsTest1.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'January 2016' -__copyright__ = '(C) 2016, Matthias Kuhn' +__author__ = "Matthias Kuhn" +__date__ = "January 2016" +__copyright__ = "(C) 2016, Matthias Kuhn" import AlgorithmsTestBase @@ -25,11 +25,13 @@ import shutil import os -from qgis.core import (QgsApplication, - QgsProcessingAlgorithm, - QgsProcessingFeedback, - QgsProcessingException) -from qgis.analysis import (QgsNativeAlgorithms) +from qgis.core import ( + QgsApplication, + QgsProcessingAlgorithm, + QgsProcessingFeedback, + QgsProcessingException, +) +from qgis.analysis import QgsNativeAlgorithms import unittest from qgis.testing import start_app, QgisTestCase from processing.tools.dataobjects import createContext @@ -43,10 +45,10 @@ def __init__(self): super().__init__() def name(self): - return 'testalg' + return "testalg" def displayName(self): - return 'testalg' + return "testalg" def initAlgorithm(self, config=None): pass @@ -55,7 +57,7 @@ def createInstance(self): return TestAlg() def processAlgorithm(self, parameters, context, feedback): - raise QgsProcessingException('Exception while processing') + raise QgsProcessingException("Exception while processing") return {} @@ -65,6 +67,7 @@ class TestQgisAlgorithms(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest): def setUpClass(cls): start_app() from processing.core.Processing import Processing + Processing.initialize() cls.cleanup_paths = [] cls.in_place_layers = {} @@ -73,12 +76,13 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): from processing.core.Processing import Processing + Processing.deinitialize() for path in cls.cleanup_paths: shutil.rmtree(path) def definition_file(self): - return 'qgis_algorithm_tests1.yaml' + return "qgis_algorithm_tests1.yaml" def testProcessingException(self): """ @@ -97,11 +101,13 @@ def testParameterPythonImport(self): # check that pythonImportString correctly imports exec(import_string) # and now we should be able to instantiate an object! - if t.className() == 'QgsProcessingParameterProviderConnection': - exec(f'test = {t.className()}(\'id\',\'name\', \'provider\')\nself.assertIsNotNone(test)') + if t.className() == "QgsProcessingParameterProviderConnection": + exec( + f"test = {t.className()}('id','name', 'provider')\nself.assertIsNotNone(test)" + ) else: - exec(f'test = {t.className()}(\'id\',\'name\')\nself.assertIsNotNone(test)') + exec(f"test = {t.className()}('id','name')\nself.assertIsNotNone(test)") -if __name__ == '__main__': +if __name__ == "__main__": nose2.main() diff --git a/python/plugins/processing/tests/QgisAlgorithmsTest2.py b/python/plugins/processing/tests/QgisAlgorithmsTest2.py index a5a8c34798b7..e8625b3d7a70 100644 --- a/python/plugins/processing/tests/QgisAlgorithmsTest2.py +++ b/python/plugins/processing/tests/QgisAlgorithmsTest2.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'January 2016' -__copyright__ = '(C) 2016, Matthias Kuhn' +__author__ = "Matthias Kuhn" +__date__ = "January 2016" +__copyright__ = "(C) 2016, Matthias Kuhn" import AlgorithmsTestBase @@ -25,9 +25,8 @@ import shutil import os -from qgis.core import (QgsApplication, - QgsProcessingException) -from qgis.analysis import (QgsNativeAlgorithms) +from qgis.core import QgsApplication, QgsProcessingException +from qgis.analysis import QgsNativeAlgorithms import unittest from qgis.testing import start_app, QgisTestCase from processing.core.ProcessingConfig import ProcessingConfig @@ -40,6 +39,7 @@ class TestQgisAlgorithms2(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest): def setUpClass(cls): start_app() from processing.core.Processing import Processing + Processing.initialize() cls.cleanup_paths = [] cls.in_place_layers = {} @@ -48,13 +48,14 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): from processing.core.Processing import Processing + Processing.deinitialize() for path in cls.cleanup_paths: shutil.rmtree(path) def definition_file(self): - return 'qgis_algorithm_tests2.yaml' + return "qgis_algorithm_tests2.yaml" -if __name__ == '__main__': +if __name__ == "__main__": nose2.main() diff --git a/python/plugins/processing/tests/QgisAlgorithmsTest3.py b/python/plugins/processing/tests/QgisAlgorithmsTest3.py index 2ef1fff5ad61..e041236b215c 100644 --- a/python/plugins/processing/tests/QgisAlgorithmsTest3.py +++ b/python/plugins/processing/tests/QgisAlgorithmsTest3.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'January 2016' -__copyright__ = '(C) 2016, Matthias Kuhn' +__author__ = "Matthias Kuhn" +__date__ = "January 2016" +__copyright__ = "(C) 2016, Matthias Kuhn" import AlgorithmsTestBase @@ -25,9 +25,8 @@ import shutil import os -from qgis.core import (QgsApplication, - QgsProcessingException) -from qgis.analysis import (QgsNativeAlgorithms) +from qgis.core import QgsApplication, QgsProcessingException +from qgis.analysis import QgsNativeAlgorithms import unittest from qgis.testing import start_app, QgisTestCase from processing.core.ProcessingConfig import ProcessingConfig @@ -40,6 +39,7 @@ class TestQgisAlgorithms3(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest): def setUpClass(cls): start_app() from processing.core.Processing import Processing + Processing.initialize() cls.cleanup_paths = [] cls.in_place_layers = {} @@ -48,13 +48,14 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): from processing.core.Processing import Processing + Processing.deinitialize() for path in cls.cleanup_paths: shutil.rmtree(path) def definition_file(self): - return 'qgis_algorithm_tests3.yaml' + return "qgis_algorithm_tests3.yaml" -if __name__ == '__main__': +if __name__ == "__main__": nose2.main() diff --git a/python/plugins/processing/tests/QgisAlgorithmsTest4.py b/python/plugins/processing/tests/QgisAlgorithmsTest4.py index af6c5da77a38..3d098f653f13 100644 --- a/python/plugins/processing/tests/QgisAlgorithmsTest4.py +++ b/python/plugins/processing/tests/QgisAlgorithmsTest4.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'January 2016' -__copyright__ = '(C) 2016, Matthias Kuhn' +__author__ = "Matthias Kuhn" +__date__ = "January 2016" +__copyright__ = "(C) 2016, Matthias Kuhn" import AlgorithmsTestBase @@ -25,9 +25,8 @@ import shutil import os -from qgis.core import (QgsApplication, - QgsProcessingException) -from qgis.analysis import (QgsNativeAlgorithms) +from qgis.core import QgsApplication, QgsProcessingException +from qgis.analysis import QgsNativeAlgorithms import unittest from qgis.testing import start_app, QgisTestCase from processing.core.ProcessingConfig import ProcessingConfig @@ -40,10 +39,14 @@ class TestQgisAlgorithms4(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest): def setUpClass(cls): start_app() from processing.core.Processing import Processing + Processing.initialize() # change the model provider folder so that it looks in the test directory for models - ProcessingConfig.setSettingValue(ModelerUtils.MODELS_FOLDER, os.path.join(os.path.dirname(__file__), 'models')) + ProcessingConfig.setSettingValue( + ModelerUtils.MODELS_FOLDER, + os.path.join(os.path.dirname(__file__), "models"), + ) for p in QgsApplication.processingRegistry().providers(): if p.id() == "model": p.refreshAlgorithms() @@ -51,19 +54,24 @@ def setUpClass(cls): cls.cleanup_paths = [] cls.in_place_layers = {} cls.vector_layer_params = {} - cls._original_models_folder = ProcessingConfig.getSetting(ModelerUtils.MODELS_FOLDER) + cls._original_models_folder = ProcessingConfig.getSetting( + ModelerUtils.MODELS_FOLDER + ) @classmethod def tearDownClass(cls): from processing.core.Processing import Processing + Processing.deinitialize() for path in cls.cleanup_paths: shutil.rmtree(path) - ProcessingConfig.setSettingValue(ModelerUtils.MODELS_FOLDER, cls._original_models_folder) + ProcessingConfig.setSettingValue( + ModelerUtils.MODELS_FOLDER, cls._original_models_folder + ) def definition_file(self): - return 'qgis_algorithm_tests4.yaml' + return "qgis_algorithm_tests4.yaml" -if __name__ == '__main__': +if __name__ == "__main__": nose2.main() diff --git a/python/plugins/processing/tests/QgisAlgorithmsTest5.py b/python/plugins/processing/tests/QgisAlgorithmsTest5.py index 3abc91e1817c..5b7e825d203d 100644 --- a/python/plugins/processing/tests/QgisAlgorithmsTest5.py +++ b/python/plugins/processing/tests/QgisAlgorithmsTest5.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'January 2016' -__copyright__ = '(C) 2016, Matthias Kuhn' +__author__ = "Matthias Kuhn" +__date__ = "January 2016" +__copyright__ = "(C) 2016, Matthias Kuhn" import AlgorithmsTestBase @@ -36,19 +36,21 @@ class TestQgisAlgorithms5(QgisTestCase, AlgorithmsTestBase.AlgorithmsTest): def setUpClass(cls): start_app() from processing.core.Processing import Processing + Processing.initialize() cls.cleanup_paths = [] @classmethod def tearDownClass(cls): from processing.core.Processing import Processing + Processing.deinitialize() for path in cls.cleanup_paths: shutil.rmtree(path) def definition_file(self): - return 'qgis_algorithm_tests5.yaml' + return "qgis_algorithm_tests5.yaml" -if __name__ == '__main__': +if __name__ == "__main__": nose2.main() diff --git a/python/plugins/processing/tests/ScriptUtilsTest.py b/python/plugins/processing/tests/ScriptUtilsTest.py index 61bde4bca504..0c436e9c7908 100644 --- a/python/plugins/processing/tests/ScriptUtilsTest.py +++ b/python/plugins/processing/tests/ScriptUtilsTest.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Luigi Pirelli' -__date__ = 'February 2019' -__copyright__ = '(C) 2019, Luigi Pirelli' +__author__ = "Luigi Pirelli" +__date__ = "February 2019" +__copyright__ = "(C) 2019, Luigi Pirelli" import os import shutil @@ -29,7 +29,7 @@ from processing.script import ScriptUtils -testDataPath = os.path.join(os.path.dirname(__file__), 'testdata') +testDataPath = os.path.join(os.path.dirname(__file__), "testdata") start_app() @@ -50,13 +50,13 @@ def testResetScriptFolder(self): defaultScriptFolder = ScriptUtils.defaultScriptsFolder() folder = ScriptUtils.resetScriptFolder(defaultScriptFolder) self.assertEqual(folder, defaultScriptFolder) - folder = ScriptUtils.resetScriptFolder('.') - self.assertEqual(folder, '.') + folder = ScriptUtils.resetScriptFolder(".") + self.assertEqual(folder, ".") # if folder does not exist and not absolute - folder = ScriptUtils.resetScriptFolder('fake') + folder = ScriptUtils.resetScriptFolder("fake") self.assertEqual(folder, None) # if absolute but not relative to QgsApplication.qgisSettingsDirPath() - folder = os.path.join(tempfile.gettempdir(), 'fakePath') + folder = os.path.join(tempfile.gettempdir(), "fakePath") newFolder = ScriptUtils.resetScriptFolder(folder) self.assertEqual(newFolder, folder) @@ -66,13 +66,13 @@ def testResetScriptFolder(self): # modify default profile changing absolute path pointing somewhere paths = folder.split(os.sep) - paths[0] = '/' - paths[1] = 'fakelocation' + paths[0] = "/" + paths[1] = "fakelocation" folder = os.path.join(*paths) folder = ScriptUtils.resetScriptFolder(folder) self.assertEqual(folder, QgsApplication.qgisSettingsDirPath()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/python/plugins/processing/tests/TestData.py b/python/plugins/processing/tests/TestData.py index fc9024ed73a1..5262e26c00d8 100644 --- a/python/plugins/processing/tests/TestData.py +++ b/python/plugins/processing/tests/TestData.py @@ -15,22 +15,22 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'March 2013' -__copyright__ = '(C) 2013, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "March 2013" +__copyright__ = "(C) 2013, Victor Olaya" import os.path -testDataPath = os.path.join(os.path.dirname(__file__), 'testdata') +testDataPath = os.path.join(os.path.dirname(__file__), "testdata") def table(): - return os.path.join(testDataPath, 'table.dbf') + return os.path.join(testDataPath, "table.dbf") def points(): - return os.path.join(testDataPath, 'points.gml') + return os.path.join(testDataPath, "points.gml") def invalid_geometries(): - return os.path.join(testDataPath, 'invalidgeometries.gml') + return os.path.join(testDataPath, "invalidgeometries.gml") diff --git a/python/plugins/processing/tests/ToolsTest.py b/python/plugins/processing/tests/ToolsTest.py index 0cf6c76b7c6e..f3e7bd7952de 100644 --- a/python/plugins/processing/tests/ToolsTest.py +++ b/python/plugins/processing/tests/ToolsTest.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'July 2016' -__copyright__ = '(C) 2016, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "July 2016" +__copyright__ = "(C) 2016, Nyall Dawson" import os import shutil @@ -29,7 +29,7 @@ from processing.tests.TestData import points from processing.tools import vector -testDataPath = os.path.join(os.path.dirname(__file__), 'testdata') +testDataPath = os.path.join(os.path.dirname(__file__), "testdata") start_app() @@ -47,15 +47,15 @@ def tearDownClass(cls): def testValues(self): test_data = points() - test_layer = QgsVectorLayer(test_data, 'test', 'ogr') + test_layer = QgsVectorLayer(test_data, "test", "ogr") # field by index res = vector.values(test_layer, 1) self.assertEqual(res[1], [1, 2, 3, 4, 5, 6, 7, 8, 9]) # field by name - res = vector.values(test_layer, 'id') - self.assertEqual(res['id'], [1, 2, 3, 4, 5, 6, 7, 8, 9]) + res = vector.values(test_layer, "id") + self.assertEqual(res["id"], [1, 2, 3, 4, 5, 6, 7, 8, 9]) # two fields res = vector.values(test_layer, 1, 2) @@ -63,26 +63,28 @@ def testValues(self): self.assertEqual(res[2], [2, 1, 0, 2, 1, 0, 0, 0, 0]) # two fields by name - res = vector.values(test_layer, 'id', 'id2') - self.assertEqual(res['id'], [1, 2, 3, 4, 5, 6, 7, 8, 9]) - self.assertEqual(res['id2'], [2, 1, 0, 2, 1, 0, 0, 0, 0]) + res = vector.values(test_layer, "id", "id2") + self.assertEqual(res["id"], [1, 2, 3, 4, 5, 6, 7, 8, 9]) + self.assertEqual(res["id2"], [2, 1, 0, 2, 1, 0, 0, 0, 0]) # two fields by name and index - res = vector.values(test_layer, 'id', 2) - self.assertEqual(res['id'], [1, 2, 3, 4, 5, 6, 7, 8, 9]) + res = vector.values(test_layer, "id", 2) + self.assertEqual(res["id"], [1, 2, 3, 4, 5, 6, 7, 8, 9]) self.assertEqual(res[2], [2, 1, 0, 2, 1, 0, 0, 0, 0]) def testConvertNulls(self): self.assertEqual(vector.convert_nulls([]), []) - self.assertEqual(vector.convert_nulls([], '_'), []) + self.assertEqual(vector.convert_nulls([], "_"), []) self.assertEqual(vector.convert_nulls([NULL]), [None]) - self.assertEqual(vector.convert_nulls([NULL], '_'), ['_']) + self.assertEqual(vector.convert_nulls([NULL], "_"), ["_"]) self.assertEqual(vector.convert_nulls([NULL], -1), [-1]) self.assertEqual(vector.convert_nulls([1, 2, 3]), [1, 2, 3]) self.assertEqual(vector.convert_nulls([1, None, 3]), [1, None, 3]) self.assertEqual(vector.convert_nulls([1, NULL, 3, NULL]), [1, None, 3, None]) - self.assertEqual(vector.convert_nulls([1, NULL, 3, NULL], '_'), [1, '_', 3, '_']) + self.assertEqual( + vector.convert_nulls([1, NULL, 3, NULL], "_"), [1, "_", 3, "_"] + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/python/plugins/processing/tools/__init__.py b/python/plugins/processing/tools/__init__.py index 9d220581e82e..1d350d9cb43b 100644 --- a/python/plugins/processing/tools/__init__.py +++ b/python/plugins/processing/tools/__init__.py @@ -15,6 +15,6 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'February 2013' -__copyright__ = '(C) 2013, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "February 2013" +__copyright__ = "(C) 2013, Victor Olaya" diff --git a/python/plugins/processing/tools/dataobjects.py b/python/plugins/processing/tools/dataobjects.py index 39929afa06b6..55d9ef9e448d 100644 --- a/python/plugins/processing/tools/dataobjects.py +++ b/python/plugins/processing/tools/dataobjects.py @@ -15,25 +15,27 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" import os import re -from qgis.core import (QgsDataProvider, - QgsRasterLayer, - QgsWkbTypes, - QgsVectorLayer, - QgsProject, - QgsSettings, - QgsProcessingContext, - QgsProcessingUtils, - QgsFeatureRequest, - QgsExpressionContext, - QgsExpressionContextUtils, - QgsExpressionContextScope) +from qgis.core import ( + QgsDataProvider, + QgsRasterLayer, + QgsWkbTypes, + QgsVectorLayer, + QgsProject, + QgsSettings, + QgsProcessingContext, + QgsProcessingUtils, + QgsFeatureRequest, + QgsExpressionContext, + QgsExpressionContextUtils, + QgsExpressionContextScope, +) from qgis.gui import QgsSublayersDialog from qgis.PyQt.QtCore import QCoreApplication from qgis.utils import iface @@ -59,15 +61,25 @@ def createContext(feedback=None): context.setProject(QgsProject.instance()) context.setFeedback(feedback) - invalid_features_method = ProcessingConfig.getSetting(ProcessingConfig.FILTER_INVALID_GEOMETRIES) + invalid_features_method = ProcessingConfig.getSetting( + ProcessingConfig.FILTER_INVALID_GEOMETRIES + ) if invalid_features_method is None: - invalid_features_method = QgsFeatureRequest.InvalidGeometryCheck.GeometryAbortOnInvalid + invalid_features_method = ( + QgsFeatureRequest.InvalidGeometryCheck.GeometryAbortOnInvalid + ) else: - invalid_features_method = QgsFeatureRequest.InvalidGeometryCheck(int(invalid_features_method)) + invalid_features_method = QgsFeatureRequest.InvalidGeometryCheck( + int(invalid_features_method) + ) context.setInvalidGeometryCheck(invalid_features_method) settings = QgsSettings() - context.setDefaultEncoding(QgsProcessingUtils.resolveDefaultEncoding(settings.value("/Processing/encoding"))) + context.setDefaultEncoding( + QgsProcessingUtils.resolveDefaultEncoding( + settings.value("/Processing/encoding") + ) + ) context.setExpressionContext(createExpressionContext()) @@ -83,16 +95,18 @@ def createExpressionContext(): context.appendScope(QgsExpressionContextUtils.projectScope(QgsProject.instance())) if iface and iface.mapCanvas(): - context.appendScope(QgsExpressionContextUtils.mapSettingsScope(iface.mapCanvas().mapSettings())) + context.appendScope( + QgsExpressionContextUtils.mapSettingsScope(iface.mapCanvas().mapSettings()) + ) processingScope = QgsExpressionContextScope() if iface and iface.mapCanvas(): extent = iface.mapCanvas().fullExtent() - processingScope.setVariable('fullextent_minx', extent.xMinimum()) - processingScope.setVariable('fullextent_miny', extent.yMinimum()) - processingScope.setVariable('fullextent_maxx', extent.xMaximum()) - processingScope.setVariable('fullextent_maxy', extent.yMaximum()) + processingScope.setVariable("fullextent_minx", extent.xMinimum()) + processingScope.setVariable("fullextent_miny", extent.yMinimum()) + processingScope.setVariable("fullextent_maxx", extent.xMaximum()) + processingScope.setVariable("fullextent_maxy", extent.yMaximum()) context.appendScope(processingScope) return context @@ -107,7 +121,11 @@ def load(fileName, name=None, crs=None, style=None, isRaster=False): """ from warnings import warn - warn("processing.load is deprecated and will be removed in QGIS 4.0", DeprecationWarning) + + warn( + "processing.load is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) if fileName is None: return @@ -118,7 +136,7 @@ def load(fileName, name=None, crs=None, style=None, isRaster=False): if isRaster: options = QgsRasterLayer.LayerOptions() options.skipCrsValidation = True - qgslayer = QgsRasterLayer(fileName, name, 'gdal', options) + qgslayer = QgsRasterLayer(fileName, name, "gdal", options) if qgslayer.isValid(): if crs is not None and qgslayer.crs() is None: qgslayer.setCrs(crs, False) @@ -127,23 +145,32 @@ def load(fileName, name=None, crs=None, style=None, isRaster=False): qgslayer.loadNamedStyle(style) QgsProject.instance().addMapLayers([qgslayer]) else: - raise RuntimeError(QCoreApplication.translate('dataobject', - 'Could not load layer: {0}\nCheck the processing framework log to look for errors.').format( - fileName)) + raise RuntimeError( + QCoreApplication.translate( + "dataobject", + "Could not load layer: {0}\nCheck the processing framework log to look for errors.", + ).format(fileName) + ) else: options = QgsVectorLayer.LayerOptions() options.skipCrsValidation = True - qgslayer = QgsVectorLayer(fileName, name, 'ogr', options) + qgslayer = QgsVectorLayer(fileName, name, "ogr", options) if qgslayer.isValid(): if crs is not None and qgslayer.crs() is None: qgslayer.setCrs(crs, False) if style is None: if qgslayer.geometryType() == QgsWkbTypes.GeometryType.PointGeometry: - style = ProcessingConfig.getSetting(ProcessingConfig.VECTOR_POINT_STYLE) + style = ProcessingConfig.getSetting( + ProcessingConfig.VECTOR_POINT_STYLE + ) elif qgslayer.geometryType() == QgsWkbTypes.GeometryType.LineGeometry: - style = ProcessingConfig.getSetting(ProcessingConfig.VECTOR_LINE_STYLE) + style = ProcessingConfig.getSetting( + ProcessingConfig.VECTOR_LINE_STYLE + ) else: - style = ProcessingConfig.getSetting(ProcessingConfig.VECTOR_POLYGON_STYLE) + style = ProcessingConfig.getSetting( + ProcessingConfig.VECTOR_POLYGON_STYLE + ) qgslayer.loadNamedStyle(style) QgsProject.instance().addMapLayers([qgslayer]) @@ -156,27 +183,36 @@ def getRasterSublayer(path, param): try: # If the layer is a raster layer and has multiple sublayers, let the user chose one. # Based on QgisApp::askUserForGDALSublayers - if layer and param.showSublayersDialog and layer.dataProvider().name() == "gdal" and len(layer.subLayers()) > 1: + if ( + layer + and param.showSublayersDialog + and layer.dataProvider().name() == "gdal" + and len(layer.subLayers()) > 1 + ): layers = [] subLayerNum = 0 # simplify raster sublayer name for subLayer in layer.subLayers(): # if netcdf/hdf use all text after filename - if bool(re.match('netcdf', subLayer, re.I)) or bool(re.match('hdf', subLayer, re.I)): + if bool(re.match("netcdf", subLayer, re.I)) or bool( + re.match("hdf", subLayer, re.I) + ): subLayer = subLayer.split(path)[1] subLayer = subLayer[1:] else: # remove driver name and file name - subLayer.replace(subLayer.split(QgsDataProvider.SUBLAYER_SEPARATOR)[0], "") + subLayer.replace( + subLayer.split(QgsDataProvider.SUBLAYER_SEPARATOR)[0], "" + ) subLayer.replace(path, "") # remove any : or " left over if subLayer.startswith(":"): subLayer = subLayer[1:] - if subLayer.startswith("\""): + if subLayer.startswith('"'): subLayer = subLayer[1:] if subLayer.endswith(":"): subLayer = subLayer[:-1] - if subLayer.endswith("\""): + if subLayer.endswith('"'): subLayer = subLayer[:-1] ld = QgsSublayersDialog.LayerDefinition() @@ -187,7 +223,9 @@ def getRasterSublayer(path, param): # Use QgsSublayersDialog # Would be good if QgsSublayersDialog had an option to allow only one sublayer to be selected - chooseSublayersDialog = QgsSublayersDialog(QgsSublayersDialog.ProviderType.Gdal, "gdal") + chooseSublayersDialog = QgsSublayersDialog( + QgsSublayersDialog.ProviderType.Gdal, "gdal" + ) chooseSublayersDialog.populateLayerTable(layers) if chooseSublayersDialog.exec(): diff --git a/python/plugins/processing/tools/general.py b/python/plugins/processing/tools/general.py index f6ef2478a11b..3f772555c5e3 100644 --- a/python/plugins/processing/tools/general.py +++ b/python/plugins/processing/tools/general.py @@ -15,19 +15,21 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'April 2013' -__copyright__ = '(C) 2013, Victor Olaya' - -from qgis.core import (QgsApplication, - QgsProcessingAlgorithm, - QgsProcessingParameterDefinition, - QgsProcessingParameterEnum, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterVectorDestination, - QgsProcessingParameterRasterDestination, - QgsProcessingOutputLayerDefinition, - QgsProject) +__author__ = "Victor Olaya" +__date__ = "April 2013" +__copyright__ = "(C) 2013, Victor Olaya" + +from qgis.core import ( + QgsApplication, + QgsProcessingAlgorithm, + QgsProcessingParameterDefinition, + QgsProcessingParameterEnum, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterVectorDestination, + QgsProcessingParameterRasterDestination, + QgsProcessingOutputLayerDefinition, + QgsProject, +) from processing.core.Processing import Processing from processing.gui.Postprocessing import handleAlgorithmResults from processing.gui.AlgorithmDialog import AlgorithmDialog @@ -40,46 +42,50 @@ def algorithmHelp(id: str) -> None: alg = QgsApplication.processingRegistry().algorithmById(id) if alg is not None: - print(f'{alg.displayName()} ({alg.id()})\n') + print(f"{alg.displayName()} ({alg.id()})\n") if alg.shortDescription(): - print(alg.shortDescription() + '\n') + print(alg.shortDescription() + "\n") if alg.shortHelpString(): - print(alg.shortHelpString() + '\n') - print('\n----------------') - print('Input parameters') - print('----------------') + print(alg.shortHelpString() + "\n") + print("\n----------------") + print("Input parameters") + print("----------------") for p in alg.parameterDefinitions(): if p.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden: continue - print(f'\n{p.name()}: {p.description()}') + print(f"\n{p.name()}: {p.description()}") if p.help(): - print(f'\n\t{p.help()}') + print(f"\n\t{p.help()}") - print(f'\n\tParameter type:\t{p.__class__.__name__}') + print(f"\n\tParameter type:\t{p.__class__.__name__}") if isinstance(p, QgsProcessingParameterEnum): opts = [] for i, o in enumerate(p.options()): - opts.append(f'\t\t- {i}: {o}') - print('\n\tAvailable values:\n{}'.format('\n'.join(opts))) + opts.append(f"\t\t- {i}: {o}") + print("\n\tAvailable values:\n{}".format("\n".join(opts))) parameter_type = QgsApplication.processingRegistry().parameterType(p.type()) - accepted_types = parameter_type.acceptedPythonTypes() if parameter_type is not None else [] + accepted_types = ( + parameter_type.acceptedPythonTypes() + if parameter_type is not None + else [] + ) if accepted_types: opts = [] for t in accepted_types: - opts.append(f'\t\t- {t}') - print('\n\tAccepted data types:') - print('\n'.join(opts)) + opts.append(f"\t\t- {t}") + print("\n\tAccepted data types:") + print("\n".join(opts)) - print('\n----------------') - print('Outputs') - print('----------------') + print("\n----------------") + print("Outputs") + print("----------------") for o in alg.outputDefinitions(): - print(f'\n{o.name()}: <{o.__class__.__name__}>') + print(f"\n{o.name()}: <{o.__class__.__name__}>") if o.description(): - print('\t' + o.description()) + print("\t" + o.description()) else: print(f'Algorithm "{id}" not found.') @@ -88,9 +94,18 @@ def algorithmHelp(id: str) -> None: # changing this signature? make sure you update the signature in # python/processing/__init__.py too! # Docstring for this function is in python/processing/__init__.py -def run(algOrName, parameters, onFinish=None, feedback=None, context=None, is_child_algorithm=False): +def run( + algOrName, + parameters, + onFinish=None, + feedback=None, + context=None, + is_child_algorithm=False, +): if onFinish or not is_child_algorithm: - return Processing.runAlgorithm(algOrName, parameters, onFinish, feedback, context) + return Processing.runAlgorithm( + algOrName, parameters, onFinish, feedback, context + ) else: # for child algorithms, we disable to default post-processing step where layer ownership # is transferred from the context to the caller. In this case, we NEED the ownership to remain @@ -98,7 +113,13 @@ def run(algOrName, parameters, onFinish=None, feedback=None, context=None, is_ch def post_process(_alg, _context, _feedback): return - return Processing.runAlgorithm(algOrName, parameters, onFinish=post_process, feedback=feedback, context=context) + return Processing.runAlgorithm( + algOrName, + parameters, + onFinish=post_process, + feedback=feedback, + context=context, + ) # changing this signature? make sure you update the signature in @@ -115,17 +136,30 @@ def runAndLoadResults(algOrName, parameters, feedback=None, context=None): if not param.name() in parameters: continue - if isinstance(param, (QgsProcessingParameterFeatureSink, QgsProcessingParameterVectorDestination, - QgsProcessingParameterRasterDestination)): + if isinstance( + param, + ( + QgsProcessingParameterFeatureSink, + QgsProcessingParameterVectorDestination, + QgsProcessingParameterRasterDestination, + ), + ): p = parameters[param.name()] if not isinstance(p, QgsProcessingOutputLayerDefinition): - parameters[param.name()] = QgsProcessingOutputLayerDefinition(p, QgsProject.instance()) + parameters[param.name()] = QgsProcessingOutputLayerDefinition( + p, QgsProject.instance() + ) else: p.destinationProject = QgsProject.instance() parameters[param.name()] = p - return Processing.runAlgorithm(alg, parameters=parameters, onFinish=handleAlgorithmResults, feedback=feedback, - context=context) + return Processing.runAlgorithm( + alg, + parameters=parameters, + onFinish=handleAlgorithmResults, + feedback=feedback, + context=context, + ) # changing this signature? make sure you update the signature in diff --git a/python/plugins/processing/tools/raster.py b/python/plugins/processing/tools/raster.py index 73c459cb8c55..bbf83b3847cd 100644 --- a/python/plugins/processing/tools/raster.py +++ b/python/plugins/processing/tools/raster.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya and Alexander Bruy' -__date__ = 'February 2013' -__copyright__ = '(C) 2013, Victor Olaya and Alexander Bruy' +__author__ = "Victor Olaya and Alexander Bruy" +__date__ = "February 2013" +__copyright__ = "(C) 2013, Victor Olaya and Alexander Bruy" import struct @@ -36,24 +36,23 @@ def scanraster(layer, feedback, band_number=1): bandtype = gdal.GetDataTypeName(band.DataType) for y in range(band.YSize): feedback.setProgress(y / float(band.YSize) * 100) - scanline = band.ReadRaster(0, y, band.XSize, 1, band.XSize, 1, - band.DataType) - if bandtype == 'Byte': - values = struct.unpack('B' * band.XSize, scanline) - elif bandtype == 'Int16': - values = struct.unpack('h' * band.XSize, scanline) - elif bandtype == 'UInt16': - values = struct.unpack('H' * band.XSize, scanline) - elif bandtype == 'Int32': - values = struct.unpack('i' * band.XSize, scanline) - elif bandtype == 'UInt32': - values = struct.unpack('I' * band.XSize, scanline) - elif bandtype == 'Float32': - values = struct.unpack('f' * band.XSize, scanline) - elif bandtype == 'Float64': - values = struct.unpack('d' * band.XSize, scanline) + scanline = band.ReadRaster(0, y, band.XSize, 1, band.XSize, 1, band.DataType) + if bandtype == "Byte": + values = struct.unpack("B" * band.XSize, scanline) + elif bandtype == "Int16": + values = struct.unpack("h" * band.XSize, scanline) + elif bandtype == "UInt16": + values = struct.unpack("H" * band.XSize, scanline) + elif bandtype == "Int32": + values = struct.unpack("i" * band.XSize, scanline) + elif bandtype == "UInt32": + values = struct.unpack("I" * band.XSize, scanline) + elif bandtype == "Float32": + values = struct.unpack("f" * band.XSize, scanline) + elif bandtype == "Float64": + values = struct.unpack("d" * band.XSize, scanline) else: - raise QgsProcessingException('Raster format not supported') + raise QgsProcessingException("Raster format not supported") for value in values: if value == nodata: value = None @@ -61,8 +60,7 @@ def scanraster(layer, feedback, band_number=1): def mapToPixel(mX, mY, geoTransform): - (pX, pY) = gdal.ApplyGeoTransform( - gdal.InvGeoTransform(geoTransform), mX, mY) + (pX, pY) = gdal.ApplyGeoTransform(gdal.InvGeoTransform(geoTransform), mX, mY) return (int(pX), int(pY)) diff --git a/python/plugins/processing/tools/system.py b/python/plugins/processing/tools/system.py index 7ef861c56233..266dfaf0f276 100644 --- a/python/plugins/processing/tools/system.py +++ b/python/plugins/processing/tools/system.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "August 2012" +__copyright__ = "(C) 2012, Victor Olaya" from typing import Optional import os @@ -27,15 +27,13 @@ import math from qgis.PyQt.QtCore import QDir -from qgis.core import (QgsApplication, - QgsProcessingUtils, - QgsProcessingContext) +from qgis.core import QgsApplication, QgsProcessingUtils, QgsProcessingContext numExported = 1 def userFolder(): - userDir = os.path.join(QgsApplication.qgisSettingsDirPath(), 'processing') + userDir = os.path.join(QgsApplication.qgisSettingsDirPath(), "processing") if not QDir(userDir).exists(): QDir().mkpath(userDir) @@ -43,7 +41,7 @@ def userFolder(): def defaultOutputFolder(): - folder = os.path.join(userFolder(), 'outputs') + folder = os.path.join(userFolder(), "outputs") if not QDir(folder).exists(): QDir().mkpath(folder) @@ -51,22 +49,22 @@ def defaultOutputFolder(): def isWindows(): - return os.name == 'nt' + return os.name == "nt" def isMac(): - return sys.platform == 'darwin' + return sys.platform == "darwin" def getTempFilename(ext=None, context: Optional[QgsProcessingContext] = None): tmpPath = QgsProcessingUtils.tempFolder(context) t = time.time() m = math.floor(t) - uid = f'{m:8x}{int((t - m) * 1000000):05x}' + uid = f"{m:8x}{int((t - m) * 1000000):05x}" if ext is None: - filename = os.path.join(tmpPath, f'{uid}{getNumExportedLayers()}') + filename = os.path.join(tmpPath, f"{uid}{getNumExportedLayers()}") else: - filename = os.path.join(tmpPath, f'{uid}{getNumExportedLayers()}.{ext}') + filename = os.path.join(tmpPath, f"{uid}{getNumExportedLayers()}.{ext}") return filename @@ -77,11 +75,11 @@ def getNumExportedLayers(): def mkdir(newdir): - os.makedirs(newdir.strip('\n\r '), exist_ok=True) + os.makedirs(newdir.strip("\n\r "), exist_ok=True) def tempHelpFolder(): - tmp = os.path.join(str(QDir.tempPath()), 'processing_help') + tmp = os.path.join(str(QDir.tempPath()), "processing_help") if not QDir(tmp).exists(): QDir().mkpath(tmp) @@ -95,14 +93,17 @@ def escapeAndJoin(strList): """ from warnings import warn - warn("processing.escapeAndJoin is deprecated and will be removed in QGIS 4.0", DeprecationWarning) - joined = '' + warn( + "processing.escapeAndJoin is deprecated and will be removed in QGIS 4.0", + DeprecationWarning, + ) + + joined = "" for s in strList: - if s[0] != '-' and ' ' in s: - escaped = '"' + s.replace('\\', '\\\\').replace('"', '\\"') \ - + '"' + if s[0] != "-" and " " in s: + escaped = '"' + s.replace("\\", "\\\\").replace('"', '\\"') + '"' else: escaped = s - joined += escaped + ' ' + joined += escaped + " " return joined.strip() diff --git a/python/plugins/processing/tools/vector.py b/python/plugins/processing/tools/vector.py index b9c644e17ef0..76fc8c463e39 100644 --- a/python/plugins/processing/tools/vector.py +++ b/python/plugins/processing/tools/vector.py @@ -15,12 +15,11 @@ *************************************************************************** """ -__author__ = 'Victor Olaya' -__date__ = 'February 2013' -__copyright__ = '(C) 2013, Victor Olaya' +__author__ = "Victor Olaya" +__date__ = "February 2013" +__copyright__ = "(C) 2013, Victor Olaya" -from qgis.core import (NULL, - QgsFeatureRequest) +from qgis.core import NULL, QgsFeatureRequest def resolveFieldIndex(source, attr): @@ -39,7 +38,7 @@ def resolveFieldIndex(source, attr): else: index = source.fields().lookupField(attr) if index == -1: - raise ValueError('Wrong field name') + raise ValueError("Wrong field name") return index @@ -63,7 +62,11 @@ def values(source, *attributes): attr_keys[index] = attr # use an optimised feature request - request = QgsFeatureRequest().setSubsetOfAttributes(indices).setFlags(QgsFeatureRequest.Flag.NoGeometry) + request = ( + QgsFeatureRequest() + .setSubsetOfAttributes(indices) + .setFlags(QgsFeatureRequest.Flag.NoGeometry) + ) for feature in source.getFeatures(request): for i in indices: diff --git a/python/processing/__init__.py b/python/processing/__init__.py index d2d5a1500f28..d08ff505b183 100644 --- a/python/processing/__init__.py +++ b/python/processing/__init__.py @@ -1,5 +1,3 @@ -# -#- coding: utf-8 -#- - ########################################################################### # __init__.py # --------------------- @@ -22,9 +20,9 @@ to the core QGIS c++ Processing classes. """ -__author__ = 'Nathan Woodrow' -__date__ = 'November 2018' -__copyright__ = '(C) 2018, Nathan Woodrow' +__author__ = "Nathan Woodrow" +__date__ = "November 2018" +__copyright__ = "(C) 2018, Nathan Woodrow" import typing as _typing @@ -39,6 +37,7 @@ # "Forward declare" functions which will be patched in when the Processing plugin loads: + def algorithmHelp(id: str) -> None: """ Prints algorithm parameters with their types. Also @@ -50,15 +49,18 @@ def algorithmHelp(id: str) -> None: :raises: QgsNotSupportedException if the Processing plugin has not been loaded """ from qgis.core import QgsNotSupportedException - raise QgsNotSupportedException('Processing plugin has not been loaded') + raise QgsNotSupportedException("Processing plugin has not been loaded") -def run(algOrName: _typing.Union[str, _QgsProcessingAlgorithm], - parameters: _typing.Dict[str, object], - onFinish: _typing.Optional[_typing.Callable] = None, - feedback: _typing.Optional[_QgsProcessingFeedback] = None, - context: _typing.Optional[_QgsProcessingContext] = None, - is_child_algorithm: bool = False) -> _typing.Union[_typing.Dict, None]: + +def run( + algOrName: _typing.Union[str, _QgsProcessingAlgorithm], + parameters: _typing.Dict[str, object], + onFinish: _typing.Optional[_typing.Callable] = None, + feedback: _typing.Optional[_QgsProcessingFeedback] = None, + context: _typing.Optional[_QgsProcessingContext] = None, + is_child_algorithm: bool = False, +) -> _typing.Union[_typing.Dict, None]: """ Executes given algorithm and returns its outputs as dictionary object. @@ -75,13 +77,16 @@ def run(algOrName: _typing.Union[str, _QgsProcessingAlgorithm], :raises: QgsNotSupportedException if the Processing plugin has not been loaded """ from qgis.core import QgsNotSupportedException - raise QgsNotSupportedException('Processing plugin has not been loaded') + + raise QgsNotSupportedException("Processing plugin has not been loaded") -def runAndLoadResults(algOrName: _typing.Union[str, _QgsProcessingAlgorithm], - parameters: _typing.Dict[str, object], - feedback: _typing.Optional[_QgsProcessingFeedback] = None, - context: _typing.Optional[_QgsProcessingContext] = None) -> _typing.Union[_typing.Dict, None]: +def runAndLoadResults( + algOrName: _typing.Union[str, _QgsProcessingAlgorithm], + parameters: _typing.Dict[str, object], + feedback: _typing.Optional[_QgsProcessingFeedback] = None, + context: _typing.Optional[_QgsProcessingContext] = None, +) -> _typing.Union[_typing.Dict, None]: """ Executes given algorithm and load its results into the current QGIS project when possible. @@ -97,11 +102,14 @@ def runAndLoadResults(algOrName: _typing.Union[str, _QgsProcessingAlgorithm], :raises: QgsNotSupportedException if the Processing plugin has not been loaded """ from qgis.core import QgsNotSupportedException - raise QgsNotSupportedException('Processing plugin has not been loaded') + raise QgsNotSupportedException("Processing plugin has not been loaded") -def createAlgorithmDialog(algOrName: _typing.Union[str, _QgsProcessingAlgorithm], - parameters: _typing.Dict[str, object] = {}) -> _typing.Union[str, _QgsProcessingAlgorithm]: + +def createAlgorithmDialog( + algOrName: _typing.Union[str, _QgsProcessingAlgorithm], + parameters: _typing.Dict[str, object] = {}, +) -> _typing.Union[str, _QgsProcessingAlgorithm]: """ Creates and returns an algorithm dialog for the specified algorithm, prepopulated with a given set of parameters. It is the caller's responsibility to execute @@ -115,11 +123,14 @@ def createAlgorithmDialog(algOrName: _typing.Union[str, _QgsProcessingAlgorithm] :raises: QgsNotSupportedException if the Processing plugin has not been loaded """ from qgis.core import QgsNotSupportedException - raise QgsNotSupportedException('Processing plugin has not been loaded') + + raise QgsNotSupportedException("Processing plugin has not been loaded") -def execAlgorithmDialog(algOrName: _typing.Union[str, _QgsProcessingAlgorithm], - parameters: _typing.Dict[str, object] = {}) -> _typing.Union[_typing.Dict, None]: +def execAlgorithmDialog( + algOrName: _typing.Union[str, _QgsProcessingAlgorithm], + parameters: _typing.Dict[str, object] = {}, +) -> _typing.Union[_typing.Dict, None]: """ Executes an algorithm dialog for the specified algorithm, prepopulated with a given set of parameters. @@ -132,10 +143,13 @@ def execAlgorithmDialog(algOrName: _typing.Union[str, _QgsProcessingAlgorithm], :raises: QgsNotSupportedException if the Processing plugin has not been loaded """ from qgis.core import QgsNotSupportedException - raise QgsNotSupportedException('Processing plugin has not been loaded') + raise QgsNotSupportedException("Processing plugin has not been loaded") -def createContext(feedback: _typing.Optional[_QgsProcessingFeedback] = None) -> _QgsProcessingContext: + +def createContext( + feedback: _typing.Optional[_QgsProcessingFeedback] = None, +) -> _QgsProcessingContext: """ Creates a default processing context @@ -147,4 +161,5 @@ def createContext(feedback: _typing.Optional[_QgsProcessingFeedback] = None) -> :raises: QgsNotSupportedException if the Processing plugin has not been loaded """ from qgis.core import QgsNotSupportedException - raise QgsNotSupportedException('Processing plugin has not been loaded') + + raise QgsNotSupportedException("Processing plugin has not been loaded") diff --git a/python/processing/algfactory.py b/python/processing/algfactory.py index d6a82105059a..d1c4b6d19765 100644 --- a/python/processing/algfactory.py +++ b/python/processing/algfactory.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** algfactory.py @@ -17,72 +15,74 @@ *************************************************************************** """ -__author__ = 'Nathan Woodrow' -__date__ = 'November 2018' -__copyright__ = '(C) 2018, Nathan Woodrow' +__author__ = "Nathan Woodrow" +__date__ = "November 2018" +__copyright__ = "(C) 2018, Nathan Woodrow" from collections import OrderedDict from functools import partial from qgis.PyQt.QtCore import QCoreApplication from qgis.PyQt.QtGui import QIcon -from qgis.core import (QgsProcessingParameterDefinition, - QgsProcessingAlgorithm, - QgsProcessingParameterString, - QgsProcessingParameterAuthConfig, - QgsProcessingParameterNumber, - QgsProcessingParameterDistance, - QgsProcessingParameterDuration, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterFeatureSink, - QgsProcessingParameterFileDestination, - QgsProcessingParameterFolderDestination, - QgsProcessingParameterRasterDestination, - QgsProcessingParameterVectorDestination, - QgsProcessingParameterPointCloudDestination, - QgsProcessingParameterBand, - QgsProcessingParameterBoolean, - QgsProcessingParameterCrs, - QgsProcessingParameterEnum, - QgsProcessingParameterExpression, - QgsProcessingParameterExtent, - QgsProcessingParameterField, - QgsProcessingParameterFile, - QgsProcessingParameterMapLayer, - QgsProcessingParameterMatrix, - QgsProcessingParameterMultipleLayers, - QgsProcessingParameterPoint, - QgsProcessingParameterGeometry, - QgsProcessingParameterRange, - QgsProcessingParameterRasterLayer, - QgsProcessingParameterVectorLayer, - QgsProcessingParameterMeshLayer, - QgsProcessingParameterColor, - QgsProcessingParameterScale, - QgsProcessingParameterLayout, - QgsProcessingParameterLayoutItem, - QgsProcessingParameterDateTime, - QgsProcessingParameterMapTheme, - QgsProcessingParameterProviderConnection, - QgsProcessingParameterDatabaseSchema, - QgsProcessingParameterDatabaseTable, - QgsProcessingParameterCoordinateOperation, - QgsProcessingParameterPointCloudLayer, - QgsProcessingParameterAnnotationLayer, - QgsProcessingOutputString, - QgsProcessingOutputBoolean, - QgsProcessingOutputFile, - QgsProcessingOutputFolder, - QgsProcessingOutputHtml, - QgsProcessingOutputLayerDefinition, - QgsProcessingOutputMapLayer, - QgsProcessingOutputMultipleLayers, - QgsProcessingOutputNumber, - QgsProcessingOutputRasterLayer, - QgsProcessingOutputVectorLayer, - QgsProcessingOutputPointCloudLayer, - QgsMessageLog, - QgsApplication) +from qgis.core import ( + QgsProcessingParameterDefinition, + QgsProcessingAlgorithm, + QgsProcessingParameterString, + QgsProcessingParameterAuthConfig, + QgsProcessingParameterNumber, + QgsProcessingParameterDistance, + QgsProcessingParameterDuration, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterFileDestination, + QgsProcessingParameterFolderDestination, + QgsProcessingParameterRasterDestination, + QgsProcessingParameterVectorDestination, + QgsProcessingParameterPointCloudDestination, + QgsProcessingParameterBand, + QgsProcessingParameterBoolean, + QgsProcessingParameterCrs, + QgsProcessingParameterEnum, + QgsProcessingParameterExpression, + QgsProcessingParameterExtent, + QgsProcessingParameterField, + QgsProcessingParameterFile, + QgsProcessingParameterMapLayer, + QgsProcessingParameterMatrix, + QgsProcessingParameterMultipleLayers, + QgsProcessingParameterPoint, + QgsProcessingParameterGeometry, + QgsProcessingParameterRange, + QgsProcessingParameterRasterLayer, + QgsProcessingParameterVectorLayer, + QgsProcessingParameterMeshLayer, + QgsProcessingParameterColor, + QgsProcessingParameterScale, + QgsProcessingParameterLayout, + QgsProcessingParameterLayoutItem, + QgsProcessingParameterDateTime, + QgsProcessingParameterMapTheme, + QgsProcessingParameterProviderConnection, + QgsProcessingParameterDatabaseSchema, + QgsProcessingParameterDatabaseTable, + QgsProcessingParameterCoordinateOperation, + QgsProcessingParameterPointCloudLayer, + QgsProcessingParameterAnnotationLayer, + QgsProcessingOutputString, + QgsProcessingOutputBoolean, + QgsProcessingOutputFile, + QgsProcessingOutputFolder, + QgsProcessingOutputHtml, + QgsProcessingOutputLayerDefinition, + QgsProcessingOutputMapLayer, + QgsProcessingOutputMultipleLayers, + QgsProcessingOutputNumber, + QgsProcessingOutputRasterLayer, + QgsProcessingOutputVectorLayer, + QgsProcessingOutputPointCloudLayer, + QgsMessageLog, + QgsApplication, +) def _log(*args, **kw): @@ -100,11 +100,11 @@ def _make_output(**args): 'description' The description used on the output :return: """ - cls = args['cls'] - del args['cls'] + cls = args["cls"] + del args["cls"] newargs = { - "name": args['name'], - "description": args['description'], + "name": args["name"], + "description": args["description"], } return cls(**newargs) @@ -115,7 +115,7 @@ class ProcessingAlgFactoryException(Exception): """ def __init__(self, message): - super(ProcessingAlgFactoryException, self).__init__(message) + super().__init__(message) class AlgWrapper(QgsProcessingAlgorithm): @@ -123,10 +123,19 @@ class AlgWrapper(QgsProcessingAlgorithm): Wrapper object used to create new processing algorithms from @alg. """ - def __init__(self, name=None, display=None, - group=None, group_id=None, inputs=None, - outputs=None, func=None, help=None, icon=None): - super(AlgWrapper, self).__init__() + def __init__( + self, + name=None, + display=None, + group=None, + group_id=None, + inputs=None, + outputs=None, + func=None, + help=None, + icon=None, + ): + super().__init__() self._inputs = OrderedDict(inputs or {}) self._outputs = OrderedDict(outputs or {}) self._icon = icon @@ -147,7 +156,15 @@ def _get_parent_id(self, parent): raise NotImplementedError() # Wrapper logic - def define(self, name, label, group, group_label, help=None, icon=QgsApplication.iconPath("processingScript.svg")): + def define( + self, + name, + label, + group, + group_label, + help=None, + icon=QgsApplication.iconPath("processingScript.svg"), + ): self._name = name self._display = label self._group = group_label @@ -160,8 +177,10 @@ def end(self): Finalize the wrapper logic and check for any invalid config. """ if not self.has_outputs: - raise ProcessingAlgFactoryException("No outputs defined for '{}' alg" - "At least one must be defined. Use @alg.output") + raise ProcessingAlgFactoryException( + "No outputs defined for '{}' alg" + "At least one must be defined. Use @alg.output" + ) def add_output(self, type, **kwargs): parm = self._create_param(type, output=True, **kwargs) @@ -183,21 +202,25 @@ def outputs(self): return self._outputs def _create_param(self, type, output=False, **kwargs): - name = kwargs['name'] + name = kwargs["name"] if name in self._inputs or name in self._outputs: - raise ProcessingAlgFactoryException("{} already defined".format(name)) + raise ProcessingAlgFactoryException(f"{name} already defined") parent = kwargs.get("parent") if parent: parentname = self._get_parent_id(parent) if parentname == name: - raise ProcessingAlgFactoryException("{} can't depend on itself. " - "We know QGIS is smart but it's not that smart".format(name)) + raise ProcessingAlgFactoryException( + "{} can't depend on itself. " + "We know QGIS is smart but it's not that smart".format(name) + ) if parentname not in self._inputs and parentname not in self._outputs: - raise ProcessingAlgFactoryException("Can't find parent named {}".format(parentname)) + raise ProcessingAlgFactoryException( + f"Can't find parent named {parentname}" + ) - kwargs['description'] = kwargs.pop("label", "") - kwargs['defaultValue'] = kwargs.pop("default", None) + kwargs["description"] = kwargs.pop("label", "") + kwargs["defaultValue"] = kwargs.pop("default", None) advanced = kwargs.pop("advanced", False) help_str = kwargs.pop("help", "") try: @@ -205,20 +228,26 @@ def _create_param(self, type, output=False, **kwargs): try: make_func = output_type_mapping[type] except KeyError: - raise ProcessingAlgFactoryException("{} is a invalid output type".format(type)) + raise ProcessingAlgFactoryException( + f"{type} is a invalid output type" + ) else: try: make_func = input_type_mapping[type] except KeyError: - raise ProcessingAlgFactoryException("{} is a invalid input type".format(type)) + raise ProcessingAlgFactoryException( + f"{type} is a invalid input type" + ) parm = make_func(**kwargs) if advanced: - parm.setFlags(parm.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced) + parm.setFlags( + parm.flags() | QgsProcessingParameterDefinition.Flag.FlagAdvanced + ) if not output: parm.setHelp(help_str) return parm except KeyError as ex: - raise NotImplementedError("{} not supported".format(str(type))) + raise NotImplementedError(f"{str(type)} not supported") def set_func(self, func): self._func = func @@ -245,7 +274,9 @@ def _get_parameter_value(self, parm, parameters, name, context): """ Extract the real value from the parameter. """ - if isinstance(parm, (QgsProcessingParameterString, QgsProcessingParameterAuthConfig)): + if isinstance( + parm, (QgsProcessingParameterString, QgsProcessingParameterAuthConfig) + ): value = self.parameterAsString(parameters, name, context) return value elif isinstance(parm, QgsProcessingParameterNumber): @@ -281,13 +312,17 @@ def processAlgorithm(self, parameters, context, feedback): return output def createInstance(self): - return AlgWrapper(self._name, self._display, - self._group, self._group_id, - inputs=self._inputs, - outputs=self._outputs, - func=self._func, - help=self._help, - icon=self._icon) + return AlgWrapper( + self._name, + self._display, + self._group, + self._group_id, + inputs=self._inputs, + outputs=self._outputs, + func=self._func, + help=self._help, + icon=self._icon, + ) def initAlgorithm(self, configuration=None, p_str=None, Any=None, *args, **kwargs): for parm in self._inputs.values(): @@ -306,39 +341,39 @@ def icon(self): return QIcon(self._icon) -class ProcessingAlgFactory(): - STRING = "STRING", - INT = "INT", - NUMBER = "NUMBER", - DISTANCE = "DISTANCE", +class ProcessingAlgFactory: + STRING = ("STRING",) + INT = ("INT",) + NUMBER = ("NUMBER",) + DISTANCE = ("DISTANCE",) SINK = "SINK" SOURCE = "SOURCE" - FILE = "FILE", - FOLDER = "FOLDER", - HTML = "HTML", - LAYERDEF = "LAYERDEF", - MAPLAYER = "MAPLAYER", - MULTILAYER = "MULTILAYER", - RASTER_LAYER = "RASTER_LAYER", - VECTOR_LAYER = "VECTOR_LAYER", - MESH_LAYER = "MESH_LAYER", - POINT_CLOUD_LAYER = "POINT_CLOUD_LAYER", - FILE_DEST = "FILE_DEST", - FOLDER_DEST = "FOLDER_DEST", - RASTER_LAYER_DEST = "RASTER_LAYER_DEST", - VECTOR_LAYER_DEST = "VECTOR_LAYER_DEST", - POINTCLOUD_LAYER_DEST = "POINTCLOUD_LAYER_DEST", - BAND = "BAND", - BOOL = "BOOL", - CRS = "CRS", - ENUM = "ENUM", - EXPRESSION = "EXPRESSION", - EXTENT = "EXTENT", - FIELD = "FIELD", - MATRIX = "MATRIX", - POINT = "POINT", - GEOMETRY = "GEOMETRY", - RANGE = "RANGE", + FILE = ("FILE",) + FOLDER = ("FOLDER",) + HTML = ("HTML",) + LAYERDEF = ("LAYERDEF",) + MAPLAYER = ("MAPLAYER",) + MULTILAYER = ("MULTILAYER",) + RASTER_LAYER = ("RASTER_LAYER",) + VECTOR_LAYER = ("VECTOR_LAYER",) + MESH_LAYER = ("MESH_LAYER",) + POINT_CLOUD_LAYER = ("POINT_CLOUD_LAYER",) + FILE_DEST = ("FILE_DEST",) + FOLDER_DEST = ("FOLDER_DEST",) + RASTER_LAYER_DEST = ("RASTER_LAYER_DEST",) + VECTOR_LAYER_DEST = ("VECTOR_LAYER_DEST",) + POINTCLOUD_LAYER_DEST = ("POINTCLOUD_LAYER_DEST",) + BAND = ("BAND",) + BOOL = ("BOOL",) + CRS = ("CRS",) + ENUM = ("ENUM",) + EXPRESSION = ("EXPRESSION",) + EXTENT = ("EXTENT",) + FIELD = ("FIELD",) + MATRIX = ("MATRIX",) + POINT = ("POINT",) + GEOMETRY = ("GEOMETRY",) + RANGE = ("RANGE",) AUTH_CFG = "AUTH_CFG" SCALE = "SCALE" COLOR = "COLOR" @@ -363,7 +398,7 @@ def tr(self, string): """ Returns a translatable string with the self.tr() function. """ - return QCoreApplication.translate('Processing', string) + return QCoreApplication.translate("Processing", string) @property def current(self): @@ -516,11 +551,19 @@ def dec(f): input_type_mapping = { str: QgsProcessingParameterString, - int: partial(QgsProcessingParameterNumber, type=QgsProcessingParameterNumber.Type.Integer), - float: partial(QgsProcessingParameterNumber, type=QgsProcessingParameterNumber.Type.Double), + int: partial( + QgsProcessingParameterNumber, type=QgsProcessingParameterNumber.Type.Integer + ), + float: partial( + QgsProcessingParameterNumber, type=QgsProcessingParameterNumber.Type.Double + ), bool: QgsProcessingParameterBoolean, - ProcessingAlgFactory.NUMBER: partial(QgsProcessingParameterNumber, type=QgsProcessingParameterNumber.Type.Double), - ProcessingAlgFactory.INT: partial(QgsProcessingParameterNumber, type=QgsProcessingParameterNumber.Type.Integer), + ProcessingAlgFactory.NUMBER: partial( + QgsProcessingParameterNumber, type=QgsProcessingParameterNumber.Type.Double + ), + ProcessingAlgFactory.INT: partial( + QgsProcessingParameterNumber, type=QgsProcessingParameterNumber.Type.Integer + ), ProcessingAlgFactory.STRING: QgsProcessingParameterString, ProcessingAlgFactory.DISTANCE: QgsProcessingParameterDistance, ProcessingAlgFactory.SINK: QgsProcessingParameterFeatureSink, @@ -552,16 +595,23 @@ def dec(f): ProcessingAlgFactory.LAYOUT: QgsProcessingParameterLayout, ProcessingAlgFactory.LAYOUT_ITEM: QgsProcessingParameterLayoutItem, ProcessingAlgFactory.COLOR: QgsProcessingParameterColor, - ProcessingAlgFactory.DATETIME: partial(QgsProcessingParameterDateTime, type=QgsProcessingParameterDateTime.Type.DateTime), - ProcessingAlgFactory.DATE: partial(QgsProcessingParameterDateTime, type=QgsProcessingParameterDateTime.Type.Date), - ProcessingAlgFactory.TIME: partial(QgsProcessingParameterDateTime, type=QgsProcessingParameterDateTime.Type.Time), + ProcessingAlgFactory.DATETIME: partial( + QgsProcessingParameterDateTime, + type=QgsProcessingParameterDateTime.Type.DateTime, + ), + ProcessingAlgFactory.DATE: partial( + QgsProcessingParameterDateTime, type=QgsProcessingParameterDateTime.Type.Date + ), + ProcessingAlgFactory.TIME: partial( + QgsProcessingParameterDateTime, type=QgsProcessingParameterDateTime.Type.Time + ), ProcessingAlgFactory.MAP_THEME: QgsProcessingParameterMapTheme, ProcessingAlgFactory.PROVIDER_CONNECTION: QgsProcessingParameterProviderConnection, ProcessingAlgFactory.DATABASE_SCHEMA: QgsProcessingParameterDatabaseSchema, ProcessingAlgFactory.DATABASE_TABLE: QgsProcessingParameterDatabaseTable, ProcessingAlgFactory.COORDINATE_OPERATION: QgsProcessingParameterCoordinateOperation, ProcessingAlgFactory.POINTCLOUD_LAYER: QgsProcessingParameterPointCloudLayer, - ProcessingAlgFactory.ANNOTATION_LAYER: QgsProcessingParameterAnnotationLayer + ProcessingAlgFactory.ANNOTATION_LAYER: QgsProcessingParameterAnnotationLayer, } output_type_mapping = { @@ -575,11 +625,23 @@ def dec(f): ProcessingAlgFactory.FILE: partial(_make_output, cls=QgsProcessingOutputFile), ProcessingAlgFactory.FOLDER: partial(_make_output, cls=QgsProcessingOutputFolder), ProcessingAlgFactory.HTML: partial(_make_output, cls=QgsProcessingOutputHtml), - ProcessingAlgFactory.LAYERDEF: partial(_make_output, cls=QgsProcessingOutputLayerDefinition), - ProcessingAlgFactory.MAPLAYER: partial(_make_output, cls=QgsProcessingOutputMapLayer), - ProcessingAlgFactory.MULTILAYER: partial(_make_output, cls=QgsProcessingOutputMultipleLayers), - ProcessingAlgFactory.RASTER_LAYER: partial(_make_output, cls=QgsProcessingOutputRasterLayer), - ProcessingAlgFactory.VECTOR_LAYER: partial(_make_output, cls=QgsProcessingOutputVectorLayer), - ProcessingAlgFactory.POINTCLOUD_LAYER: partial(_make_output, cls=QgsProcessingOutputPointCloudLayer), + ProcessingAlgFactory.LAYERDEF: partial( + _make_output, cls=QgsProcessingOutputLayerDefinition + ), + ProcessingAlgFactory.MAPLAYER: partial( + _make_output, cls=QgsProcessingOutputMapLayer + ), + ProcessingAlgFactory.MULTILAYER: partial( + _make_output, cls=QgsProcessingOutputMultipleLayers + ), + ProcessingAlgFactory.RASTER_LAYER: partial( + _make_output, cls=QgsProcessingOutputRasterLayer + ), + ProcessingAlgFactory.VECTOR_LAYER: partial( + _make_output, cls=QgsProcessingOutputVectorLayer + ), + ProcessingAlgFactory.POINTCLOUD_LAYER: partial( + _make_output, cls=QgsProcessingOutputPointCloudLayer + ), ProcessingAlgFactory.BOOL: partial(_make_output, cls=QgsProcessingOutputBoolean), } diff --git a/python/pyplugin_installer/__init__.py b/python/pyplugin_installer/__init__.py index 7399b0baf4bc..b355ca4ee264 100644 --- a/python/pyplugin_installer/__init__.py +++ b/python/pyplugin_installer/__init__.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** __init__.py @@ -22,9 +20,9 @@ ***************************************************************************/ """ -__author__ = 'Borys Jurgiel' -__date__ = 'May 2013' -__copyright__ = '(C) 2013, Borys Jurgiel' +__author__ = "Borys Jurgiel" +__date__ = "May 2013" +__copyright__ = "(C) 2013, Borys Jurgiel" # import functions for easier access diff --git a/python/pyplugin_installer/installer.py b/python/pyplugin_installer/installer.py index c7523b4d8127..e9a64bb2fc57 100644 --- a/python/pyplugin_installer/installer.py +++ b/python/pyplugin_installer/installer.py @@ -1,4 +1,3 @@ -# -*- coding:utf-8 -*- """ /*************************************************************************** Plugin Installer module @@ -38,11 +37,19 @@ QMessageBox, QLabel, QVBoxLayout, - QPushButton + QPushButton, ) from qgis.PyQt.QtNetwork import QNetworkRequest -from qgis.core import Qgis, QgsApplication, QgsMessageLog, QgsNetworkAccessManager, QgsSettings, QgsSettingsTree, QgsNetworkRequestParameters +from qgis.core import ( + Qgis, + QgsApplication, + QgsMessageLog, + QgsNetworkAccessManager, + QgsSettings, + QgsSettingsTree, + QgsNetworkRequestParameters, +) from qgis.gui import QgsMessageBar, QgsPasswordLineEdit, QgsHelp from qgis.utils import ( iface, @@ -53,10 +60,9 @@ updateAvailablePlugins, plugins_metadata_parser, isPluginLoaded, - HOME_PLUGIN_PATH + HOME_PLUGIN_PATH, ) -from .installer_data import (repositories, plugins, officialRepo, - reposGroup, removeDir) +from .installer_data import repositories, plugins, officialRepo, reposGroup, removeDir from .qgsplugininstallerinstallingdialog import QgsPluginInstallerInstallingDialog from .qgsplugininstallerpluginerrordialog import QgsPluginInstallerPluginErrorDialog from .qgsplugininstallerfetchingdialog import QgsPluginInstallerFetchingDialog @@ -77,12 +83,11 @@ def initPluginInstaller(): # -------------------------------------------------------- # class QgsPluginInstaller(QObject): - - """ The main class for managing the plugin installer stuff""" + """The main class for managing the plugin installer stuff""" # ----------------------------------------- # def __init__(self): - """ Initialize data objects, starts fetching if appropriate, and warn about/removes obsolete plugins """ + """Initialize data objects, starts fetching if appropriate, and warn about/removes obsolete plugins""" QObject.__init__(self) # initialize QObject in order to to use self.tr() repositories.load() @@ -90,7 +95,11 @@ def __init__(self): self.message_bar_widget = None - if repositories.checkingOnStart() and repositories.timeForChecking() and repositories.allEnabled(): + if ( + repositories.checkingOnStart() + and repositories.timeForChecking() + and repositories.allEnabled() + ): # start fetching repositories repositories.checkingDone.connect(self.checkingDone) for key in repositories.allEnabled(): @@ -106,27 +115,43 @@ def __init__(self): msg = QMessageBox() msg.setIcon(QMessageBox.Icon.Warning) msg.setWindowTitle(self.tr("QGIS Python Plugin Installer")) - msg.addButton(self.tr("Uninstall (recommended)"), QMessageBox.ButtonRole.AcceptRole) - msg.addButton(self.tr("I will uninstall it later"), QMessageBox.ButtonRole.RejectRole) - msg.setText("%s %s

    %s" % (self.tr("Obsolete plugin:"), plugin["name"], self.tr("QGIS has detected an obsolete plugin that masks its more recent version shipped with this copy of QGIS. This is likely due to files associated with a previous installation of QGIS. Do you want to remove the old plugin right now and unmask the more recent version?"))) + msg.addButton( + self.tr("Uninstall (recommended)"), QMessageBox.ButtonRole.AcceptRole + ) + msg.addButton( + self.tr("I will uninstall it later"), QMessageBox.ButtonRole.RejectRole + ) + msg.setText( + "{} {}

    {}".format( + self.tr("Obsolete plugin:"), + plugin["name"], + self.tr( + "QGIS has detected an obsolete plugin that masks its more recent version shipped with this copy of QGIS. This is likely due to files associated with a previous installation of QGIS. Do you want to remove the old plugin right now and unmask the more recent version?" + ), + ) + ) msg.exec() if not msg.result(): settings = QgsSettings() - plugin_is_active = settings.value("/PythonPlugins/" + key, False, type=bool) + plugin_is_active = settings.value( + "/PythonPlugins/" + key, False, type=bool + ) # uninstall the update, update utils and reload if enabled self.uninstallPlugin(key, quiet=True) updateAvailablePlugins() if plugin_is_active: - settings.setValue("/PythonPlugins/watchDogTimestamp/" + key, - QDateTime.currentDateTime().toSecsSinceEpoch()) + settings.setValue( + "/PythonPlugins/watchDogTimestamp/" + key, + QDateTime.currentDateTime().toSecsSinceEpoch(), + ) loadPlugin(key) startPlugin(key) settings.remove("/PythonPlugins/watchDogTimestamp/" + key) # ----------------------------------------- # def fetchAvailablePlugins(self, reloadMode): - """ Fetch plugins from all enabled repositories.""" + """Fetch plugins from all enabled repositories.""" """ reloadMode = true: Fully refresh data from QgsSettings to mRepositories """ """ reloadMode = false: Fetch unready repositories only """ if reloadMode: @@ -135,7 +160,9 @@ def fetchAvailablePlugins(self, reloadMode): plugins.getAllInstalled() for key in repositories.allEnabled(): - if reloadMode or repositories.all()[key]["state"] == 3: # if state = 3 (error or not fetched yet), try to fetch once again + if ( + reloadMode or repositories.all()[key]["state"] == 3 + ): # if state = 3 (error or not fetched yet), try to fetch once again repositories.requestFetching(key, force_reload=reloadMode) if repositories.fetchingInProgress(): @@ -146,19 +173,34 @@ def fetchAvailablePlugins(self, reloadMode): repositories.killConnection(key) # display error messages for every unavailable repository, unless Shift pressed nor all repositories are unavailable - keepQuiet = QgsApplication.keyboardModifiers() == Qt.KeyboardModifiers(Qt.KeyboardModifier.ShiftModifier) - if repositories.allUnavailable() and repositories.allUnavailable() != repositories.allEnabled(): + keepQuiet = QgsApplication.keyboardModifiers() == Qt.KeyboardModifiers( + Qt.KeyboardModifier.ShiftModifier + ) + if ( + repositories.allUnavailable() + and repositories.allUnavailable() != repositories.allEnabled() + ): for key in repositories.allUnavailable(): if not keepQuiet: - QMessageBox.warning(iface.mainWindow(), self.tr("QGIS Python Plugin Installer"), self.tr("Error reading repository:") + " " + key + "\n\n" + repositories.all()[key]["error"]) - if QgsApplication.keyboardModifiers() == Qt.KeyboardModifiers(Qt.KeyboardModifier.ShiftModifier): + QMessageBox.warning( + iface.mainWindow(), + self.tr("QGIS Python Plugin Installer"), + self.tr("Error reading repository:") + + " " + + key + + "\n\n" + + repositories.all()[key]["error"], + ) + if QgsApplication.keyboardModifiers() == Qt.KeyboardModifiers( + Qt.KeyboardModifier.ShiftModifier + ): keepQuiet = True # finally, rebuild plugins from the caches plugins.rebuild() # ----------------------------------------- # def checkingDone(self): - """ Remove the "Looking for new plugins..." label and display a notification instead if any updates available """ + """Remove the "Looking for new plugins..." label and display a notification instead if any updates available""" # rebuild plugins cache plugins.rebuild() @@ -176,104 +218,120 @@ def checkingDone(self): if len(updatable_plugin_names) >= 2: status = self.tr("Multiple plugin updates are available") else: - status = self.tr("An update to the {} plugin is available").format(updatable_plugin_names[0]) + status = self.tr("An update to the {} plugin is available").format( + updatable_plugin_names[0] + ) QgsMessageLog.logMessage( - "Plugin update(s) available : {}".format(','.join(updatable_plugin_names)), self.tr("Plugins")) + "Plugin update(s) available : {}".format(",".join(updatable_plugin_names)), + self.tr("Plugins"), + ) bar = iface.messageBar() - self.message_bar_widget = bar.createMessage('', status) + self.message_bar_widget = bar.createMessage("", status) update_button = QPushButton(self.tr("Install Updates…")) tab_index = 3 # PLUGMAN_TAB_UPGRADEABLE - update_button.pressed.connect(partial(self.showPluginManagerWhenReady, tab_index)) + update_button.pressed.connect( + partial(self.showPluginManagerWhenReady, tab_index) + ) self.message_bar_widget.layout().addWidget(update_button) bar.pushWidget(self.message_bar_widget, Qgis.MessageLevel.Info) # ----------------------------------------- # def exportRepositoriesToManager(self): - """ Update manager's repository tree widget with current data """ + """Update manager's repository tree widget with current data""" iface.pluginManagerInterface().clearRepositoryList() for key in repositories.all(): url = repositories.all()[key]["url"] + repositories.urlParams() if repositories.inspectionFilter(): - enabled = (key == repositories.inspectionFilter()) + enabled = key == repositories.inspectionFilter() else: enabled = repositories.all()[key]["enabled"] - iface.pluginManagerInterface().addToRepositoryList({ - "name": key, - "url": url, - "enabled": enabled and "true" or "false", - "valid": repositories.all()[key]["valid"] and "true" or "false", - "state": str(repositories.all()[key]["state"]), - "error": repositories.all()[key]["error"], - "inspection_filter": repositories.inspectionFilter() and "true" or "false" - }) + iface.pluginManagerInterface().addToRepositoryList( + { + "name": key, + "url": url, + "enabled": enabled and "true" or "false", + "valid": repositories.all()[key]["valid"] and "true" or "false", + "state": str(repositories.all()[key]["state"]), + "error": repositories.all()[key]["error"], + "inspection_filter": repositories.inspectionFilter() + and "true" + or "false", + } + ) # ----------------------------------------- # def exportPluginsToManager(self): - """ Insert plugins metadata to QgsMetadataRegistry """ + """Insert plugins metadata to QgsMetadataRegistry""" iface.pluginManagerInterface().clearPythonPluginMetadata() for key in plugins.all(): plugin = plugins.all()[key] - iface.pluginManagerInterface().addPluginMetadata({ - "id": key, - "plugin_id": plugin["plugin_id"] or "", - "name": plugin["name"], - "description": plugin["description"], - "about": plugin["about"], - "category": plugin["category"], - "tags": plugin["tags"], - "changelog": plugin["changelog"], - "author_name": plugin["author_name"], - "author_email": plugin["author_email"], - "homepage": plugin["homepage"], - "tracker": plugin["tracker"], - "code_repository": plugin["code_repository"], - "version_installed": plugin["version_installed"], - "library": plugin["library"], - "icon": plugin["icon"], - "readonly": plugin["readonly"] and "true" or "false", - "installed": plugin["installed"] and "true" or "false", - "available": plugin["available"] and "true" or "false", - "status": plugin["status"], - "status_exp": plugin["status_exp"], - "error": plugin["error"], - "error_details": plugin["error_details"], - "create_date": plugin["create_date"], - "update_date": plugin["update_date"], - "create_date_stable": plugin["create_date_stable"], - "update_date_stable": plugin["update_date_stable"], - "create_date_experimental": plugin["create_date_experimental"], - "update_date_experimental": plugin["update_date_experimental"], - "experimental": plugin["experimental"] and "true" or "false", - "deprecated": plugin["deprecated"] and "true" or "false", - "trusted": plugin["trusted"] and "true" or "false", - "version_available": plugin["version_available"], - "version_available_stable": plugin["version_available_stable"] or "", - "version_available_experimental": plugin["version_available_experimental"] or "", - "zip_repository": plugin["zip_repository"], - "download_url": plugin["download_url"], - "download_url_stable": plugin["download_url_stable"], - "download_url_experimental": plugin["download_url_experimental"], - "filename": plugin["filename"], - "downloads": plugin["downloads"], - "average_vote": plugin["average_vote"], - "rating_votes": plugin["rating_votes"], - "plugin_dependencies": plugin.get("plugin_dependencies", None), - "pythonic": "true" - }) + iface.pluginManagerInterface().addPluginMetadata( + { + "id": key, + "plugin_id": plugin["plugin_id"] or "", + "name": plugin["name"], + "description": plugin["description"], + "about": plugin["about"], + "category": plugin["category"], + "tags": plugin["tags"], + "changelog": plugin["changelog"], + "author_name": plugin["author_name"], + "author_email": plugin["author_email"], + "homepage": plugin["homepage"], + "tracker": plugin["tracker"], + "code_repository": plugin["code_repository"], + "version_installed": plugin["version_installed"], + "library": plugin["library"], + "icon": plugin["icon"], + "readonly": plugin["readonly"] and "true" or "false", + "installed": plugin["installed"] and "true" or "false", + "available": plugin["available"] and "true" or "false", + "status": plugin["status"], + "status_exp": plugin["status_exp"], + "error": plugin["error"], + "error_details": plugin["error_details"], + "create_date": plugin["create_date"], + "update_date": plugin["update_date"], + "create_date_stable": plugin["create_date_stable"], + "update_date_stable": plugin["update_date_stable"], + "create_date_experimental": plugin["create_date_experimental"], + "update_date_experimental": plugin["update_date_experimental"], + "experimental": plugin["experimental"] and "true" or "false", + "deprecated": plugin["deprecated"] and "true" or "false", + "trusted": plugin["trusted"] and "true" or "false", + "version_available": plugin["version_available"], + "version_available_stable": plugin["version_available_stable"] + or "", + "version_available_experimental": plugin[ + "version_available_experimental" + ] + or "", + "zip_repository": plugin["zip_repository"], + "download_url": plugin["download_url"], + "download_url_stable": plugin["download_url_stable"], + "download_url_experimental": plugin["download_url_experimental"], + "filename": plugin["filename"], + "downloads": plugin["downloads"], + "average_vote": plugin["average_vote"], + "rating_votes": plugin["rating_votes"], + "plugin_dependencies": plugin.get("plugin_dependencies", None), + "pythonic": "true", + } + ) iface.pluginManagerInterface().reloadModel() # ----------------------------------------- # def reloadAndExportData(self): - """ Reload All repositories and export data to the Plugin Manager """ + """Reload All repositories and export data to the Plugin Manager""" self.fetchAvailablePlugins(reloadMode=True) self.exportRepositoriesToManager() self.exportPluginsToManager() # ----------------------------------------- # - def showPluginManagerWhenReady(self, * params): - """ Open the plugin manager window. If fetching is still in progress, it shows the progress window first """ + def showPluginManagerWhenReady(self, *params): + """Open the plugin manager window. If fetching is still in progress, it shows the progress window first""" """ Optionally pass the index of tab to be opened in params """ if self.message_bar_widget: if not sip.isdeleted(self.message_bar_widget): @@ -294,34 +352,47 @@ def showPluginManagerWhenReady(self, * params): # ----------------------------------------- # def onManagerClose(self): - """ Call this method when closing manager window - it resets last-use-dependent values. """ + """Call this method when closing manager window - it resets last-use-dependent values.""" plugins.updateSeenPluginsList() repositories.saveCheckingOnStartLastDate() # ----------------------------------------- # def exportSettingsGroup(self): - """ Return QgsSettings settingsGroup value """ + """Return QgsSettings settingsGroup value""" # todo QGIS 4 remove return "plugin-manager" # ----------------------------------------- # def upgradeAllUpgradeable(self): - """ Reinstall all upgradeable plugins """ + """Reinstall all upgradeable plugins""" for key in plugins.allUpgradeable(): self.installPlugin(key, quiet=True) # ----------------------------------------- # def installPlugin(self, key, quiet=False, stable=True): - """ Install given plugin """ + """Install given plugin""" error = False - status_key = 'status' if stable else 'status_exp' - infoString = ('', '') + status_key = "status" if stable else "status_exp" + infoString = ("", "") plugin = plugins.all()[key] previousStatus = plugin[status_key] if not plugin: return - if plugin[status_key] == "newer" and not plugin["error"]: # ask for confirmation if user downgrades an usable plugin - if QMessageBox.warning(iface.mainWindow(), self.tr("QGIS Python Plugin Installer"), self.tr("Are you sure you want to downgrade the plugin to the latest available version? The installed one is newer!"), QMessageBox.StandardButton.Yes, QMessageBox.StandardButton.No) == QMessageBox.StandardButton.No: + if ( + plugin[status_key] == "newer" and not plugin["error"] + ): # ask for confirmation if user downgrades an usable plugin + if ( + QMessageBox.warning( + iface.mainWindow(), + self.tr("QGIS Python Plugin Installer"), + self.tr( + "Are you sure you want to downgrade the plugin to the latest available version? The installed one is newer!" + ), + QMessageBox.StandardButton.Yes, + QMessageBox.StandardButton.No, + ) + == QMessageBox.StandardButton.No + ): return # if plugin is active, unload it before update, see https://github.com/qgis/QGIS/issues/54968 @@ -329,7 +400,9 @@ def installPlugin(self, key, quiet=False, stable=True): if pluginWasLoaded: unloadPlugin(plugin["id"]) - dlg = QgsPluginInstallerInstallingDialog(iface.mainWindow(), plugin, stable=stable) + dlg = QgsPluginInstallerInstallingDialog( + iface.mainWindow(), plugin, stable=stable + ) dlg.exec() plugin_path = HOME_PLUGIN_PATH + "/" + key @@ -344,11 +417,13 @@ def installPlugin(self, key, quiet=False, stable=True): infoString = ( self.tr("Plugin has disappeared"), self.tr( - "The plugin seems to have been installed but it's not possible to know where. The directory \"{}\" " + 'The plugin seems to have been installed but it\'s not possible to know where. The directory "{}" ' "has not been found. Probably the plugin package contained a wrong named directory.\nPlease search " "the list of installed plugins. You should find the plugin there, but it's not possible to " "determine which of them it is and it's also not possible to inform you about available updates. " - "Please contact the plugin author and submit this issue.").format(plugin_path)) + "Please contact the plugin author and submit this issue." + ).format(plugin_path), + ) with OverrideCursor(Qt.CursorShape.WaitCursor): plugins.getAllInstalled() plugins.rebuild() @@ -375,7 +450,9 @@ def installPlugin(self, key, quiet=False, stable=True): loadPlugin(plugin["id"]) startPlugin(plugin["id"]) else: - unloadPlugin(key) # Just for a case. Will exit quietly if really not loaded + unloadPlugin( + key + ) # Just for a case. Will exit quietly if really not loaded loadPlugin(key) if quiet: infoString = (None, None) @@ -383,10 +460,14 @@ def installPlugin(self, key, quiet=False, stable=True): else: QApplication.restoreOverrideCursor() if plugin["error"] == "incompatible": - message = self.tr("The plugin is not compatible with this version of QGIS. It's designed for QGIS versions:") + message = self.tr( + "The plugin is not compatible with this version of QGIS. It's designed for QGIS versions:" + ) message += " " + plugin["error_details"] + "" elif plugin["error"] == "dependent": - message = self.tr("The plugin depends on some components missing on your system. You need to install the following Python module in order to enable it:") + message = self.tr( + "The plugin depends on some components missing on your system. You need to install the following Python module in order to enable it:" + ) message += " " + plugin["error_details"] + "" else: message = self.tr("The plugin is broken. Python said:") @@ -425,7 +506,7 @@ def installPlugin(self, key, quiet=False, stable=True): # ----------------------------------------- # def uninstallPlugin(self, key, quiet=False): - """ Uninstall given plugin """ + """Uninstall given plugin""" if key in plugins.all(): plugin = plugins.all()[key] else: @@ -433,10 +514,30 @@ def uninstallPlugin(self, key, quiet=False): if not plugin: return if not quiet: - warning = self.tr("Are you sure you want to uninstall the following plugin?") + "\n(" + plugin["name"] + ")" - if plugin["status"] == "orphan" and plugin["status_exp"] == "orphan" and not plugin["error"]: - warning += "\n\n" + self.tr("Warning: this plugin isn't available in any accessible repository!") - if QMessageBox.warning(iface.mainWindow(), self.tr("QGIS Python Plugin Installer"), warning, QMessageBox.StandardButton.Yes, QMessageBox.StandardButton.No) == QMessageBox.StandardButton.No: + warning = ( + self.tr("Are you sure you want to uninstall the following plugin?") + + "\n(" + + plugin["name"] + + ")" + ) + if ( + plugin["status"] == "orphan" + and plugin["status_exp"] == "orphan" + and not plugin["error"] + ): + warning += "\n\n" + self.tr( + "Warning: this plugin isn't available in any accessible repository!" + ) + if ( + QMessageBox.warning( + iface.mainWindow(), + self.tr("QGIS Python Plugin Installer"), + warning, + QMessageBox.StandardButton.Yes, + QMessageBox.StandardButton.No, + ) + == QMessageBox.StandardButton.No + ): return # unload the plugin QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) @@ -448,7 +549,7 @@ def uninstallPlugin(self, key, quiet=False): result = removeDir(pluginDir) if result: QApplication.restoreOverrideCursor() - msg = "%s:%s" % (self.tr("Plugin uninstall failed"), result) + msg = "{}:{}".format(self.tr("Plugin uninstall failed"), result) iface.pluginManagerInterface().pushMessage(msg, Qgis.MessageLevel.Critical) else: # safe remove @@ -474,14 +575,16 @@ def uninstallPlugin(self, key, quiet=False): plugins.rebuild() self.exportPluginsToManager() QApplication.restoreOverrideCursor() - iface.pluginManagerInterface().pushMessage(self.tr("Plugin uninstalled successfully"), Qgis.MessageLevel.Success) + iface.pluginManagerInterface().pushMessage( + self.tr("Plugin uninstalled successfully"), Qgis.MessageLevel.Success + ) settings = QgsSettings() settings.remove("/PythonPlugins/" + key) # ----------------------------------------- # def addRepository(self): - """ add new repository connection """ + """add new repository connection""" dlg = QgsPluginInstallerRepositoryDialog(iface.mainWindow()) dlg.editParams.setText(repositories.urlParams()) dlg.checkBoxEnabled.setCheckState(Qt.CheckState.Checked) @@ -489,7 +592,10 @@ def addRepository(self): return for i in list(repositories.all().values()): if dlg.editURL.text().strip() == i["url"]: - iface.pluginManagerInterface().pushMessage(self.tr("Unable to add another repository with the same URL!"), Qgis.MessageLevel.Warning) + iface.pluginManagerInterface().pushMessage( + self.tr("Unable to add another repository with the same URL!"), + Qgis.MessageLevel.Warning, + ) return settings = QgsSettings() settings.beginGroup(reposGroup) @@ -500,14 +606,16 @@ def addRepository(self): # add to settings settings.setValue(reposName + "/url", reposURL) settings.setValue(reposName + "/authcfg", dlg.editAuthCfg.text().strip()) - settings.setValue(reposName + "/enabled", bool(dlg.checkBoxEnabled.checkState())) + settings.setValue( + reposName + "/enabled", bool(dlg.checkBoxEnabled.checkState()) + ) # refresh lists and populate widgets plugins.removeRepository(reposName) self.reloadAndExportData() # ----------------------------------------- # def editRepository(self, reposName): - """ edit repository connection """ + """edit repository connection""" if not reposName: return checkState = {False: Qt.CheckState.Unchecked, True: Qt.CheckState.Checked} @@ -516,19 +624,31 @@ def editRepository(self, reposName): dlg.editURL.setText(repositories.all()[reposName]["url"]) dlg.editAuthCfg.setText(repositories.all()[reposName]["authcfg"]) dlg.editParams.setText(repositories.urlParams()) - dlg.checkBoxEnabled.setCheckState(checkState[repositories.all()[reposName]["enabled"]]) + dlg.checkBoxEnabled.setCheckState( + checkState[repositories.all()[reposName]["enabled"]] + ) if repositories.all()[reposName]["valid"]: dlg.checkBoxEnabled.setEnabled(True) dlg.labelInfo.setText("") else: dlg.checkBoxEnabled.setEnabled(False) - dlg.labelInfo.setText(self.tr("This repository is blocked due to incompatibility with your QGIS version")) + dlg.labelInfo.setText( + self.tr( + "This repository is blocked due to incompatibility with your QGIS version" + ) + ) dlg.labelInfo.setFrameShape(QFrame.Shape.Box) if not dlg.exec(): return # nothing to do if canceled for i in list(repositories.all().values()): - if dlg.editURL.text().strip() == i["url"] and dlg.editURL.text().strip() != repositories.all()[reposName]["url"]: - iface.pluginManagerInterface().pushMessage(self.tr("Unable to add another repository with the same URL!"), Qgis.MessageLevel.Warning) + if ( + dlg.editURL.text().strip() == i["url"] + and dlg.editURL.text().strip() != repositories.all()[reposName]["url"] + ): + iface.pluginManagerInterface().pushMessage( + self.tr("Unable to add another repository with the same URL!"), + Qgis.MessageLevel.Warning, + ) return # delete old repo from QgsSettings and create new one settings = QgsSettings() @@ -542,7 +662,11 @@ def editRepository(self, reposName): settings.setValue(newName + "/enabled", bool(dlg.checkBoxEnabled.checkState())) if dlg.editAuthCfg.text().strip() != repositories.all()[reposName]["authcfg"]: repositories.all()[reposName]["authcfg"] = dlg.editAuthCfg.text().strip() - if dlg.editURL.text().strip() == repositories.all()[reposName]["url"] and dlg.checkBoxEnabled.checkState() == checkState[repositories.all()[reposName]["enabled"]]: + if ( + dlg.editURL.text().strip() == repositories.all()[reposName]["url"] + and dlg.checkBoxEnabled.checkState() + == checkState[repositories.all()[reposName]["enabled"]] + ): repositories.rename(reposName, newName) self.exportRepositoriesToManager() return # nothing else to do if only repository name was changed @@ -551,16 +675,34 @@ def editRepository(self, reposName): # ----------------------------------------- # def deleteRepository(self, reposName: str): - """ delete repository connection """ + """delete repository connection""" if not reposName: return settings = QgsSettings() settings.beginGroup(reposGroup) if settings.value(reposName + "/url", "", type=str) == officialRepo[1]: - iface.pluginManagerInterface().pushMessage(self.tr("You can't remove the official QGIS Plugin Repository. You can disable it if needed."), Qgis.MessageLevel.Warning) + iface.pluginManagerInterface().pushMessage( + self.tr( + "You can't remove the official QGIS Plugin Repository. You can disable it if needed." + ), + Qgis.MessageLevel.Warning, + ) return - warning = self.tr("Are you sure you want to remove the following repository?") + "\n" + reposName - if QMessageBox.warning(iface.mainWindow(), self.tr("QGIS Python Plugin Installer"), warning, QMessageBox.StandardButton.Yes, QMessageBox.StandardButton.No) == QMessageBox.StandardButton.No: + warning = ( + self.tr("Are you sure you want to remove the following repository?") + + "\n" + + reposName + ) + if ( + QMessageBox.warning( + iface.mainWindow(), + self.tr("QGIS Python Plugin Installer"), + warning, + QMessageBox.StandardButton.Yes, + QMessageBox.StandardButton.No, + ) + == QMessageBox.StandardButton.No + ): return # delete from the settings, refresh data and repopulate all the widgets settings.remove(reposName) @@ -570,23 +712,39 @@ def deleteRepository(self, reposName: str): # ----------------------------------------- # def setRepositoryInspectionFilter(self, reposName=None): - """ temporarily block another repositories to fetch only one for inspection """ + """temporarily block another repositories to fetch only one for inspection""" repositories.setInspectionFilter(reposName) self.reloadAndExportData() # ----------------------------------------- # def sendVote(self, plugin_id, vote): - """ send vote via the RPC """ + """send vote via the RPC""" if not plugin_id or not vote: return False url = "https://plugins.qgis.org/plugins/RPC2/" - params = {"id": "djangorpc", "method": "plugin.vote", "params": [str(plugin_id), str(vote)]} + params = { + "id": "djangorpc", + "method": "plugin.vote", + "params": [str(plugin_id), str(vote)], + } req = QNetworkRequest(QUrl(url)) - req.setAttribute(QNetworkRequest.Attribute(QgsNetworkRequestParameters.RequestAttributes.AttributeInitiatorClass), "QgsPluginInstaller") - req.setAttribute(QNetworkRequest.Attribute(QgsNetworkRequestParameters.RequestAttributes.AttributeInitiatorRequestId), "sendVote") + req.setAttribute( + QNetworkRequest.Attribute( + QgsNetworkRequestParameters.RequestAttributes.AttributeInitiatorClass + ), + "QgsPluginInstaller", + ) + req.setAttribute( + QNetworkRequest.Attribute( + QgsNetworkRequestParameters.RequestAttributes.AttributeInitiatorRequestId + ), + "sendVote", + ) req.setRawHeader(b"Content-Type", b"application/json") - reply = QgsNetworkAccessManager.instance().blockingPost(req, bytes(json.dumps(params), "utf-8")) + reply = QgsNetworkAccessManager.instance().blockingPost( + req, bytes(json.dumps(params), "utf-8") + ) if reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) == 200: return True else: @@ -596,13 +754,17 @@ def installFromZipFile(self, filePath): if not os.path.isfile(filePath): return - QgsSettingsTree.node("plugin-manager").childSetting("last-zip-directory").setValue(QFileInfo(filePath).absoluteDir().absolutePath()) + QgsSettingsTree.node("plugin-manager").childSetting( + "last-zip-directory" + ).setValue(QFileInfo(filePath).absoluteDir().absolutePath()) pluginName = None - with zipfile.ZipFile(filePath, 'r') as zf: + with zipfile.ZipFile(filePath, "r") as zf: # search for metadata.txt. In case of multiple files, we can assume that # the shortest path relates /metadata.txt - metadatafiles = sorted(f for f in zf.namelist() if f.endswith('metadata.txt')) + metadatafiles = sorted( + f for f in zf.namelist() if f.endswith("metadata.txt") + ) if len(metadatafiles) > 0: pluginName = os.path.split(metadatafiles[0])[0] @@ -611,10 +773,18 @@ def installFromZipFile(self, filePath): if not pluginName: msg_box = QMessageBox() msg_box.setIcon(QMessageBox.Icon.Warning) - msg_box.setWindowTitle(self.tr("QGIS Python Install from ZIP Plugin Installer")) - msg_box.setText(self.tr("The Zip file is not a valid QGIS python plugin. No root folder was found inside.")) + msg_box.setWindowTitle( + self.tr("QGIS Python Install from ZIP Plugin Installer") + ) + msg_box.setText( + self.tr( + "The Zip file is not a valid QGIS python plugin. No root folder was found inside." + ) + ) msg_box.setStandardButtons(QMessageBox.StandardButton.Ok) - more_info_btn = msg_box.addButton(self.tr("More Information"), QMessageBox.ButtonRole.HelpRole) + more_info_btn = msg_box.addButton( + self.tr("More Information"), QMessageBox.ButtonRole.HelpRole + ) msg_box.exec() if msg_box.clickedButton() == more_info_btn: QgsHelp.openHelp("plugins/plugins.html#the-install-from-zip-tab") @@ -651,16 +821,24 @@ def installFromZipFile(self, filePath): success = True except Exception as e: success = False - if 'password' in str(e): - infoString = self.tr('Aborted by user') - if 'Bad password' in str(e): - msg = self.tr('Wrong password. Please enter a correct password to the zip file.') + if "password" in str(e): + infoString = self.tr("Aborted by user") + if "Bad password" in str(e): + msg = self.tr( + "Wrong password. Please enter a correct password to the zip file." + ) else: - msg = self.tr('The zip file is encrypted. Please enter password.') + msg = self.tr( + "The zip file is encrypted. Please enter password." + ) # Display a password dialog with QgsPasswordLineEdit dlg = QDialog() - dlg.setWindowTitle(self.tr('Enter password')) - buttonBox = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel, Qt.Orientation.Horizontal) + dlg.setWindowTitle(self.tr("Enter password")) + buttonBox = QDialogButtonBox( + QDialogButtonBox.StandardButton.Ok + | QDialogButtonBox.StandardButton.Cancel, + Qt.Orientation.Horizontal, + ) buttonBox.rejected.connect(dlg.reject) buttonBox.accepted.connect(dlg.accept) lePass = QgsPasswordLineEdit() @@ -672,7 +850,9 @@ def installFromZipFile(self, filePath): keepTrying = dlg.exec() password = lePass.text() else: - infoString = self.tr("Failed to unzip the plugin package\n{}.\nProbably it is broken".format(filePath)) + infoString = self.tr( + f"Failed to unzip the plugin package\n{filePath}.\nProbably it is broken" + ) keepTrying = False if success: @@ -684,19 +864,25 @@ def installFromZipFile(self, filePath): plugins.rebuild() settings = QgsSettings() - if settings.contains('/PythonPlugins/' + pluginName): # Plugin was available? + if settings.contains( + "/PythonPlugins/" + pluginName + ): # Plugin was available? unloadPlugin(pluginName) loadPlugin(pluginName) - if settings.value('/PythonPlugins/' + pluginName, False, bool): # Plugin was also active? + if settings.value( + "/PythonPlugins/" + pluginName, False, bool + ): # Plugin was also active? startPlugin(pluginName) else: if startPlugin(pluginName): - settings.setValue('/PythonPlugins/' + pluginName, True) + settings.setValue("/PythonPlugins/" + pluginName, True) self.exportPluginsToManager() msg = "%s" % self.tr("Plugin installed successfully") else: - msg = "%s: %s" % (self.tr("Plugin installation failed"), infoString) + msg = "{}: {}".format( + self.tr("Plugin installation failed"), infoString + ) level = Qgis.MessageLevel.Success if success else Qgis.MessageLevel.Critical iface.pluginManagerInterface().pushMessage(msg, level) @@ -710,22 +896,47 @@ def processDependencies(self, plugin_id): to_install, to_upgrade, not_found = find_dependencies(plugin_id) if to_install or to_upgrade or not_found: - dlg = QgsPluginDependenciesDialog(plugin_id, to_install, to_upgrade, not_found) + dlg = QgsPluginDependenciesDialog( + plugin_id, to_install, to_upgrade, not_found + ) if dlg.exec() == QgsPluginDependenciesDialog.Accepted: actions = dlg.actions() for dependency_plugin_id, action_data in actions.items(): try: - self.installPlugin(dependency_plugin_id, stable=action_data['use_stable_version']) - if action_data['action'] == 'install': - iface.pluginManagerInterface().pushMessage(self.tr("Plugin dependency %s successfully installed") % - dependency_plugin_id, Qgis.MessageLevel.Success) + self.installPlugin( + dependency_plugin_id, + stable=action_data["use_stable_version"], + ) + if action_data["action"] == "install": + iface.pluginManagerInterface().pushMessage( + self.tr( + "Plugin dependency %s successfully installed" + ) + % dependency_plugin_id, + Qgis.MessageLevel.Success, + ) else: - iface.pluginManagerInterface().pushMessage(self.tr("Plugin dependency %s successfully upgraded") % - dependency_plugin_id, Qgis.MessageLevel.Success) + iface.pluginManagerInterface().pushMessage( + self.tr( + "Plugin dependency %s successfully upgraded" + ) + % dependency_plugin_id, + Qgis.MessageLevel.Success, + ) except Exception as ex: - if action_data['action'] == 'install': - iface.pluginManagerInterface().pushMessage(self.tr("Error installing plugin dependency %s: %s") % - (dependency_plugin_id, ex), Qgis.MessageLevel.Warning) + if action_data["action"] == "install": + iface.pluginManagerInterface().pushMessage( + self.tr( + "Error installing plugin dependency %s: %s" + ) + % (dependency_plugin_id, ex), + Qgis.MessageLevel.Warning, + ) else: - iface.pluginManagerInterface().pushMessage(self.tr("Error upgrading plugin dependency %s: %s") % - (dependency_plugin_id, ex), Qgis.MessageLevel.Warning) + iface.pluginManagerInterface().pushMessage( + self.tr( + "Error upgrading plugin dependency %s: %s" + ) + % (dependency_plugin_id, ex), + Qgis.MessageLevel.Warning, + ) diff --git a/python/pyplugin_installer/installer_data.py b/python/pyplugin_installer/installer_data.py index 089d10a872a5..81a830e554d7 100644 --- a/python/pyplugin_installer/installer_data.py +++ b/python/pyplugin_installer/installer_data.py @@ -1,4 +1,3 @@ -# -*- coding:utf-8 -*- """ /*************************************************************************** Plugin Installer module @@ -22,15 +21,23 @@ * * ***************************************************************************/ """ -from typing import ( - Dict, - Optional, - Any -) -from qgis.PyQt.QtCore import (pyqtSignal, QObject, QCoreApplication, QFile, - QDir, QDirIterator, QDate, QUrl, QFileInfo, - QLocale, QByteArray, QT_VERSION_STR) +from typing import Dict, Optional, Any + +from qgis.PyQt.QtCore import ( + pyqtSignal, + QObject, + QCoreApplication, + QFile, + QDir, + QDirIterator, + QDate, + QUrl, + QFileInfo, + QLocale, + QByteArray, + QT_VERSION_STR, +) from qgis.PyQt.QtXml import QDomDocument from qgis.PyQt.QtNetwork import QNetworkRequest, QNetworkReply from qgis.core import Qgis, QgsSettings, QgsSettingsTree, QgsNetworkRequestParameters @@ -42,12 +49,13 @@ import qgis.utils from qgis.core import QgsNetworkAccessManager, QgsApplication from qgis.gui import QgsGui -from qgis.utils import ( - iface, - plugin_paths, - HOME_PLUGIN_PATH +from qgis.utils import iface, plugin_paths, HOME_PLUGIN_PATH +from .version_compare import ( + pyQgisVersion, + compareVersions, + normalizeVersion, + isCompatible, ) -from .version_compare import pyQgisVersion, compareVersions, normalizeVersion, isCompatible """ @@ -111,14 +119,24 @@ reposGroup = "app/plugin_repositories" -officialRepo = (QCoreApplication.translate("QgsPluginInstaller", "QGIS Official Plugin Repository"), "https://plugins.qgis.org/plugins/plugins.xml") +officialRepo = ( + QCoreApplication.translate("QgsPluginInstaller", "QGIS Official Plugin Repository"), + "https://plugins.qgis.org/plugins/plugins.xml", +) # --- common functions ------------------------------------------------------------------- # def removeDir(path): result = "" if not QFile(path).exists(): - result = QCoreApplication.translate("QgsPluginInstaller", "Nothing to remove! Plugin directory doesn't exist:") + "\n" + path + result = ( + QCoreApplication.translate( + "QgsPluginInstaller", + "Nothing to remove! Plugin directory doesn't exist:", + ) + + "\n" + + path + ) elif QFile(path).remove(): # if it is only link, just remove it without resolving. pass else: @@ -135,7 +153,17 @@ def removeDir(path): if QDir().rmpath(item): pass if QFile(path).exists(): - result = QCoreApplication.translate("QgsPluginInstaller", "Failed to remove the directory:") + "\n" + path + "\n" + QCoreApplication.translate("QgsPluginInstaller", "Check permissions or remove it manually") + result = ( + QCoreApplication.translate( + "QgsPluginInstaller", "Failed to remove the directory:" + ) + + "\n" + + path + + "\n" + + QCoreApplication.translate( + "QgsPluginInstaller", "Check permissions or remove it manually" + ) + ) # restore plugin directory if removed by QDir().rmpath() pluginDir = HOME_PLUGIN_PATH if not QDir(pluginDir).exists(): @@ -147,6 +175,7 @@ class Relay(QObject): """ Relay object for transmitting signals from QPHttp with adding the repoName information """ + anythingChanged = pyqtSignal(str, int, int) def __init__(self, key): @@ -184,71 +213,97 @@ class Repositories(QObject): def __init__(self): QObject.__init__(self) - self.mRepositories: Dict[str, Dict[str, Any]] = {} - self.httpId = {} # {httpId : repoName} + self.mRepositories: dict[str, dict[str, Any]] = {} + self.httpId = {} # {httpId : repoName} self.mInspectionFilter: Optional[str] = None - def all(self) -> Dict[str, Dict[str, Any]]: - """ return dict of all repositories """ + def all(self) -> dict[str, dict[str, Any]]: + """return dict of all repositories""" return self.mRepositories - def allEnabled(self) -> Dict[str, Dict[str, Any]]: - """ return dict of all enabled and valid repositories """ + def allEnabled(self) -> dict[str, dict[str, Any]]: + """return dict of all enabled and valid repositories""" if self.mInspectionFilter: return {self.mInspectionFilter: self.mRepositories[self.mInspectionFilter]} - return {k: v for k, v in self.mRepositories.items() if v['enabled'] and v['valid']} + return { + k: v for k, v in self.mRepositories.items() if v["enabled"] and v["valid"] + } - def allUnavailable(self) -> Dict[str, Dict[str, Any]]: - """ return dict of all unavailable repositories """ + def allUnavailable(self) -> dict[str, dict[str, Any]]: + """return dict of all unavailable repositories""" repos = {} if self.mInspectionFilter: # return the inspected repo if unavailable, otherwise empty dict - if self.mRepositories[self.mInspectionFilter]["state"] == Repositories.STATE_UNAVAILABLE: - repos[self.mInspectionFilter] = self.mRepositories[self.mInspectionFilter] + if ( + self.mRepositories[self.mInspectionFilter]["state"] + == Repositories.STATE_UNAVAILABLE + ): + repos[self.mInspectionFilter] = self.mRepositories[ + self.mInspectionFilter + ] return repos - return {k: v for k, v in self.mRepositories.items() if v['enabled'] and v['valid'] and v['state'] == Repositories.STATE_UNAVAILABLE} + return { + k: v + for k, v in self.mRepositories.items() + if v["enabled"] + and v["valid"] + and v["state"] == Repositories.STATE_UNAVAILABLE + } def urlParams(self) -> str: - """ return GET parameters to be added to every request """ + """return GET parameters to be added to every request""" # Strip down the point release segment from the version string - return "?qgis={}".format(re.sub(r'\.\d*$', '', pyQgisVersion())) + return "?qgis={}".format(re.sub(r"\.\d*$", "", pyQgisVersion())) def setRepositoryData(self, reposName: str, key: str, value): - """ write data to the mRepositories dict """ + """write data to the mRepositories dict""" self.mRepositories[reposName][key] = value def remove(self, reposName: str): - """ remove given item from the mRepositories dict """ + """remove given item from the mRepositories dict""" del self.mRepositories[reposName] def rename(self, oldName: str, newName: str): - """ rename repository key """ + """rename repository key""" if oldName == newName: return self.mRepositories[newName] = self.mRepositories[oldName] del self.mRepositories[oldName] def checkingOnStart(self) -> bool: - """ return true if checking for news and updates is enabled """ - return QgsSettingsTree.node("plugin-manager").childSetting('automatically-check-for-updates').value() + """return true if checking for news and updates is enabled""" + return ( + QgsSettingsTree.node("plugin-manager") + .childSetting("automatically-check-for-updates") + .value() + ) def setCheckingOnStart(self, state: bool): - """ set state of checking for news and updates """ - QgsSettingsTree.node("plugin-manager").childSetting('automatically-check-for-updates').setValue(state) + """set state of checking for news and updates""" + QgsSettingsTree.node("plugin-manager").childSetting( + "automatically-check-for-updates" + ).setValue(state) def saveCheckingOnStartLastDate(self): - """ set today's date as the day of last checking """ - QgsSettingsTree.node("plugin-manager").childSetting('check-on-start-last-date').setValue(QDate.currentDate()) + """set today's date as the day of last checking""" + QgsSettingsTree.node("plugin-manager").childSetting( + "check-on-start-last-date" + ).setValue(QDate.currentDate()) def timeForChecking(self) -> bool: - """ determine whether it's the time for checking for news and updates now """ + """determine whether it's the time for checking for news and updates now""" settings = QgsSettings() try: # QgsSettings may contain ivalid value... - interval = QgsSettingsTree.node("plugin-manager").childSetting('check-on-start-last-date').valueAs(type=QDate).daysTo(QDate.currentDate()) + interval = ( + QgsSettingsTree.node("plugin-manager") + .childSetting("check-on-start-last-date") + .valueAs(type=QDate) + .daysTo(QDate.currentDate()) + ) except: interval = 0 if interval >= Repositories.CHECK_ON_START_INTERVAL: @@ -257,7 +312,7 @@ def timeForChecking(self) -> bool: return False def load(self): - """ populate the mRepositories dict""" + """populate the mRepositories dict""" self.mRepositories = {} settings = QgsSettings() settings.beginGroup(reposGroup) @@ -273,17 +328,29 @@ def load(self): for key in settings.childGroups(): self.mRepositories[key] = {} self.mRepositories[key]["url"] = settings.value(key + "/url", "", type=str) - self.mRepositories[key]["authcfg"] = settings.value(key + "/authcfg", "", type=str) - self.mRepositories[key]["enabled"] = settings.value(key + "/enabled", True, type=bool) - self.mRepositories[key]["valid"] = settings.value(key + "/valid", True, type=bool) + self.mRepositories[key]["authcfg"] = settings.value( + key + "/authcfg", "", type=str + ) + self.mRepositories[key]["enabled"] = settings.value( + key + "/enabled", True, type=bool + ) + self.mRepositories[key]["valid"] = settings.value( + key + "/valid", True, type=bool + ) self.mRepositories[key]["Relay"] = Relay(key) self.mRepositories[key]["xmlData"] = None self.mRepositories[key]["state"] = Repositories.STATE_DISABLED self.mRepositories[key]["error"] = "" settings.endGroup() - def requestFetching(self, key: str, url: Optional[QUrl] = None, redirectionCounter=0, force_reload: bool = False): - """ start fetching the repository given by key """ + def requestFetching( + self, + key: str, + url: Optional[QUrl] = None, + redirectionCounter=0, + force_reload: bool = False, + ): + """start fetching the repository given by key""" self.mRepositories[key]["state"] = Repositories.STATE_LOADING if not url: url = QUrl(self.mRepositories[key]["url"] + self.urlParams()) @@ -291,55 +358,98 @@ def requestFetching(self, key: str, url: Optional[QUrl] = None, redirectionCount # url.addQueryItem('qgis', '.'.join([str(int(s)) for s in [v[0], v[1:3]]]) ) # don't include the bugfix version! self.mRepositories[key]["QRequest"] = QNetworkRequest(url) - self.mRepositories[key]["QRequest"].setAttribute(QNetworkRequest.Attribute(QgsNetworkRequestParameters.RequestAttributes.AttributeInitiatorClass), "Relay") - self.mRepositories[key]["QRequest"].setAttribute(QNetworkRequest.Attribute.RedirectPolicyAttribute, QNetworkRequest.RedirectPolicy.NoLessSafeRedirectPolicy) + self.mRepositories[key]["QRequest"].setAttribute( + QNetworkRequest.Attribute( + QgsNetworkRequestParameters.RequestAttributes.AttributeInitiatorClass + ), + "Relay", + ) + self.mRepositories[key]["QRequest"].setAttribute( + QNetworkRequest.Attribute.RedirectPolicyAttribute, + QNetworkRequest.RedirectPolicy.NoLessSafeRedirectPolicy, + ) if force_reload: - self.mRepositories[key]["QRequest"].setAttribute(QNetworkRequest.Attribute.CacheLoadControlAttribute, QNetworkRequest.CacheLoadControl.AlwaysNetwork) + self.mRepositories[key]["QRequest"].setAttribute( + QNetworkRequest.Attribute.CacheLoadControlAttribute, + QNetworkRequest.CacheLoadControl.AlwaysNetwork, + ) authcfg = self.mRepositories[key]["authcfg"] if authcfg and isinstance(authcfg, str): if not QgsApplication.authManager().updateNetworkRequest( - self.mRepositories[key]["QRequest"], authcfg.strip()): + self.mRepositories[key]["QRequest"], authcfg.strip() + ): msg = QCoreApplication.translate( "QgsPluginInstaller", "Update of network request with authentication " - "credentials FAILED for configuration '{0}'").format(authcfg) - iface.pluginManagerInterface().pushMessage(msg, Qgis.MessageLevel.Warning) + "credentials FAILED for configuration '{0}'", + ).format(authcfg) + iface.pluginManagerInterface().pushMessage( + msg, Qgis.MessageLevel.Warning + ) self.mRepositories[key]["QRequest"] = None return - self.mRepositories[key]["QRequest"].setAttribute(QNetworkRequest.Attribute.User, key) - self.mRepositories[key]["xmlData"] = QgsNetworkAccessManager.instance().get(self.mRepositories[key]["QRequest"]) - self.mRepositories[key]["xmlData"].setProperty('reposName', key) - self.mRepositories[key]["xmlData"].setProperty('redirectionCounter', redirectionCounter) - self.mRepositories[key]["xmlData"].downloadProgress.connect(self.mRepositories[key]["Relay"].dataReadProgress) - self.mRepositories[key]["xmlDataFinished"] = self.mRepositories[key]["xmlData"].finished.connect(self.xmlDownloaded) + self.mRepositories[key]["QRequest"].setAttribute( + QNetworkRequest.Attribute.User, key + ) + self.mRepositories[key]["xmlData"] = QgsNetworkAccessManager.instance().get( + self.mRepositories[key]["QRequest"] + ) + self.mRepositories[key]["xmlData"].setProperty("reposName", key) + self.mRepositories[key]["xmlData"].setProperty( + "redirectionCounter", redirectionCounter + ) + self.mRepositories[key]["xmlData"].downloadProgress.connect( + self.mRepositories[key]["Relay"].dataReadProgress + ) + self.mRepositories[key]["xmlDataFinished"] = self.mRepositories[key][ + "xmlData" + ].finished.connect(self.xmlDownloaded) def fetchingInProgress(self) -> bool: - """ return True if fetching repositories is still in progress """ - return any(v['state'] == Repositories.STATE_LOADING for v in self.mRepositories.values()) + """return True if fetching repositories is still in progress""" + return any( + v["state"] == Repositories.STATE_LOADING + for v in self.mRepositories.values() + ) def killConnection(self, key: str): - """ kill the fetching on demand """ - if self.mRepositories[key]["state"] == Repositories.STATE_LOADING and self.mRepositories[key]["xmlData"] and self.mRepositories[key]["xmlData"].isRunning(): - self.mRepositories[key]["xmlData"].finished.disconnect(self.mRepositories[key]["xmlDataFinished"]) + """kill the fetching on demand""" + if ( + self.mRepositories[key]["state"] == Repositories.STATE_LOADING + and self.mRepositories[key]["xmlData"] + and self.mRepositories[key]["xmlData"].isRunning() + ): + self.mRepositories[key]["xmlData"].finished.disconnect( + self.mRepositories[key]["xmlDataFinished"] + ) self.mRepositories[key]["xmlData"].abort() def xmlDownloaded(self): - """ populate the plugins object with the fetched data """ + """populate the plugins object with the fetched data""" reply = self.sender() - reposName = reply.property('reposName') + reposName = reply.property("reposName") if reply.error() != QNetworkReply.NetworkError.NoError: # fetching failed self.mRepositories[reposName]["state"] = Repositories.STATE_UNAVAILABLE self.mRepositories[reposName]["error"] = reply.errorString() if reply.error() == QNetworkReply.NetworkError.OperationCanceledError: - self.mRepositories[reposName]["error"] += "\n\n" + QCoreApplication.translate("QgsPluginInstaller", "If you haven't canceled the download manually, it was most likely caused by a timeout. In this case consider increasing the connection timeout value in QGIS options window.") + self.mRepositories[reposName][ + "error" + ] += "\n\n" + QCoreApplication.translate( + "QgsPluginInstaller", + "If you haven't canceled the download manually, it was most likely caused by a timeout. In this case consider increasing the connection timeout value in QGIS options window.", + ) elif reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) == 301: - redirectionUrl = reply.attribute(QNetworkRequest.Attribute.RedirectionTargetAttribute) + redirectionUrl = reply.attribute( + QNetworkRequest.Attribute.RedirectionTargetAttribute + ) if redirectionUrl.isRelative(): redirectionUrl = reply.url().resolved(redirectionUrl) - redirectionCounter = reply.property('redirectionCounter') + 1 + redirectionCounter = reply.property("redirectionCounter") + 1 if redirectionCounter > 4: self.mRepositories[reposName]["state"] = Repositories.STATE_UNAVAILABLE - self.mRepositories[reposName]["error"] = QCoreApplication.translate("QgsPluginInstaller", "Too many redirections") + self.mRepositories[reposName]["error"] = QCoreApplication.translate( + "QgsPluginInstaller", "Too many redirections" + ) else: # Fire a new request and exit immediately in order to quietly destroy the old one self.requestFetching(reposName, redirectionUrl, redirectionCounter) @@ -355,62 +465,165 @@ def xmlDownloaded(self): if plugins_tag.size(): pluginNodes = reposXML.elementsByTagName("pyqgis_plugin") for i in range(pluginNodes.size()): - fileName = pluginNodes.item(i).firstChildElement("file_name").text().strip() + fileName = ( + pluginNodes.item(i) + .firstChildElement("file_name") + .text() + .strip() + ) if not fileName: - fileName = QFileInfo(pluginNodes.item(i).firstChildElement("download_url").text().strip().split("?")[0]).fileName() + fileName = QFileInfo( + pluginNodes.item(i) + .firstChildElement("download_url") + .text() + .strip() + .split("?")[0] + ).fileName() name = fileName.partition(".")[0] experimental = False - if pluginNodes.item(i).firstChildElement("experimental").text().strip().upper() in ["TRUE", "YES"]: + if pluginNodes.item(i).firstChildElement( + "experimental" + ).text().strip().upper() in ["TRUE", "YES"]: experimental = True deprecated = False - if pluginNodes.item(i).firstChildElement("deprecated").text().strip().upper() in ["TRUE", "YES"]: + if pluginNodes.item(i).firstChildElement( + "deprecated" + ).text().strip().upper() in ["TRUE", "YES"]: deprecated = True trusted = False - if pluginNodes.item(i).firstChildElement("trusted").text().strip().upper() in ["TRUE", "YES"]: + if pluginNodes.item(i).firstChildElement( + "trusted" + ).text().strip().upper() in ["TRUE", "YES"]: trusted = True icon = pluginNodes.item(i).firstChildElement("icon").text().strip() if icon and not icon.startswith("http"): url = QUrl(self.mRepositories[reposName]["url"]) - if url.scheme() in ('http', 'https'): - icon = "{}://{}/{}".format(url.scheme(), url.host(), icon) + if url.scheme() in ("http", "https"): + icon = f"{url.scheme()}://{url.host()}/{icon}" if pluginNodes.item(i).toElement().hasAttribute("plugin_id"): - plugin_id = pluginNodes.item(i).toElement().attribute("plugin_id") + plugin_id = ( + pluginNodes.item(i).toElement().attribute("plugin_id") + ) else: plugin_id = None version = pluginNodes.item(i).toElement().attribute("version") - download_url = pluginNodes.item(i).firstChildElement("download_url").text().strip() + download_url = ( + pluginNodes.item(i) + .firstChildElement("download_url") + .text() + .strip() + ) plugin = { "id": name, "plugin_id": plugin_id, "name": pluginNodes.item(i).toElement().attribute("name"), "version_available": version, - "version_available_stable": normalizeVersion(version) if not experimental else "", - "version_available_experimental": normalizeVersion(version) if experimental else "", - "description": pluginNodes.item(i).firstChildElement("description").text().strip(), - "about": pluginNodes.item(i).firstChildElement("about").text().strip(), - "author_name": pluginNodes.item(i).firstChildElement("author_name").text().strip(), - "homepage": pluginNodes.item(i).firstChildElement("homepage").text().strip(), + "version_available_stable": ( + normalizeVersion(version) if not experimental else "" + ), + "version_available_experimental": ( + normalizeVersion(version) if experimental else "" + ), + "description": pluginNodes.item(i) + .firstChildElement("description") + .text() + .strip(), + "about": pluginNodes.item(i) + .firstChildElement("about") + .text() + .strip(), + "author_name": pluginNodes.item(i) + .firstChildElement("author_name") + .text() + .strip(), + "homepage": pluginNodes.item(i) + .firstChildElement("homepage") + .text() + .strip(), "download_url": download_url, "download_url_stable": download_url if not experimental else "", - "download_url_experimental": download_url if experimental else "", - "category": pluginNodes.item(i).firstChildElement("category").text().strip(), - "tags": pluginNodes.item(i).firstChildElement("tags").text().strip(), - "changelog": pluginNodes.item(i).firstChildElement("changelog").text().strip(), - "author_email": pluginNodes.item(i).firstChildElement("author_email").text().strip(), - "tracker": pluginNodes.item(i).firstChildElement("tracker").text().strip(), - "code_repository": pluginNodes.item(i).firstChildElement("repository").text().strip(), - "downloads": pluginNodes.item(i).firstChildElement("downloads").text().strip(), - "average_vote": pluginNodes.item(i).firstChildElement("average_vote").text().strip(), - "rating_votes": pluginNodes.item(i).firstChildElement("rating_votes").text().strip(), - "create_date": pluginNodes.item(i).firstChildElement("create_date").text().strip(), - "update_date": pluginNodes.item(i).firstChildElement("update_date").text().strip(), - "create_date_stable": pluginNodes.item(i).firstChildElement("create_date").text().strip() if not experimental else "", - "update_date_stable": pluginNodes.item(i).firstChildElement("update_date").text().strip() if not experimental else "", - "create_date_experimental": pluginNodes.item(i).firstChildElement("create_date").text().strip() if experimental else "", - "update_date_experimental": pluginNodes.item(i).firstChildElement("update_date").text().strip() if experimental else "", + "download_url_experimental": ( + download_url if experimental else "" + ), + "category": pluginNodes.item(i) + .firstChildElement("category") + .text() + .strip(), + "tags": pluginNodes.item(i) + .firstChildElement("tags") + .text() + .strip(), + "changelog": pluginNodes.item(i) + .firstChildElement("changelog") + .text() + .strip(), + "author_email": pluginNodes.item(i) + .firstChildElement("author_email") + .text() + .strip(), + "tracker": pluginNodes.item(i) + .firstChildElement("tracker") + .text() + .strip(), + "code_repository": pluginNodes.item(i) + .firstChildElement("repository") + .text() + .strip(), + "downloads": pluginNodes.item(i) + .firstChildElement("downloads") + .text() + .strip(), + "average_vote": pluginNodes.item(i) + .firstChildElement("average_vote") + .text() + .strip(), + "rating_votes": pluginNodes.item(i) + .firstChildElement("rating_votes") + .text() + .strip(), + "create_date": pluginNodes.item(i) + .firstChildElement("create_date") + .text() + .strip(), + "update_date": pluginNodes.item(i) + .firstChildElement("update_date") + .text() + .strip(), + "create_date_stable": ( + pluginNodes.item(i) + .firstChildElement("create_date") + .text() + .strip() + if not experimental + else "" + ), + "update_date_stable": ( + pluginNodes.item(i) + .firstChildElement("update_date") + .text() + .strip() + if not experimental + else "" + ), + "create_date_experimental": ( + pluginNodes.item(i) + .firstChildElement("create_date") + .text() + .strip() + if experimental + else "" + ), + "update_date_experimental": ( + pluginNodes.item(i) + .firstChildElement("update_date") + .text() + .strip() + if experimental + else "" + ), "icon": icon, "experimental": experimental, "deprecated": deprecated, @@ -426,29 +639,58 @@ def xmlDownloaded(self): "zip_repository": reposName, "library": "", "readonly": False, - "plugin_dependencies": pluginNodes.item(i).firstChildElement("plugin_dependencies").text().strip(), + "plugin_dependencies": pluginNodes.item(i) + .firstChildElement("plugin_dependencies") + .text() + .strip(), } - qgisMinimumVersion = pluginNodes.item(i).firstChildElement("qgis_minimum_version").text().strip() + qgisMinimumVersion = ( + pluginNodes.item(i) + .firstChildElement("qgis_minimum_version") + .text() + .strip() + ) if not qgisMinimumVersion: qgisMinimumVersion = "2" - qgisMaximumVersion = pluginNodes.item(i).firstChildElement("qgis_maximum_version").text().strip() + qgisMaximumVersion = ( + pluginNodes.item(i) + .firstChildElement("qgis_maximum_version") + .text() + .strip() + ) if not qgisMaximumVersion: qgisMaximumVersion = qgisMinimumVersion[0] + ".99" # if compatible, add the plugin to the list - if not pluginNodes.item(i).firstChildElement("disabled").text().strip().upper() in ["TRUE", "YES"]: - if isCompatible(pyQgisVersion(), qgisMinimumVersion, qgisMaximumVersion): + if not pluginNodes.item(i).firstChildElement( + "disabled" + ).text().strip().upper() in ["TRUE", "YES"]: + if isCompatible( + pyQgisVersion(), qgisMinimumVersion, qgisMaximumVersion + ): # add the plugin to the cache plugins.addFromRepository(plugin) self.mRepositories[reposName]["state"] = Repositories.STATE_LOADED else: # no plugin metadata found self.mRepositories[reposName]["state"] = Repositories.STATE_UNAVAILABLE - if reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) == 200: - self.mRepositories[reposName]["error"] = QCoreApplication.translate("QgsPluginInstaller", "Server response is 200 OK, but doesn't contain plugin metadata. This is most likely caused by a proxy or a wrong repository URL. You can configure proxy settings in QGIS options.") + if ( + reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) + == 200 + ): + self.mRepositories[reposName]["error"] = QCoreApplication.translate( + "QgsPluginInstaller", + "Server response is 200 OK, but doesn't contain plugin metadata. This is most likely caused by a proxy or a wrong repository URL. You can configure proxy settings in QGIS options.", + ) else: - self.mRepositories[reposName]["error"] = QCoreApplication.translate("QgsPluginInstaller", "Status code:") + " {} {}".format( - reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute), - reply.attribute(QNetworkRequest.Attribute.HttpReasonPhraseAttribute) + self.mRepositories[reposName]["error"] = QCoreApplication.translate( + "QgsPluginInstaller", "Status code:" + ) + " {} {}".format( + reply.attribute( + QNetworkRequest.Attribute.HttpStatusCodeAttribute + ), + reply.attribute( + QNetworkRequest.Attribute.HttpReasonPhraseAttribute + ), ) self.repositoryFetched.emit(reposName) @@ -460,35 +702,37 @@ def xmlDownloaded(self): reply.deleteLater() def inspectionFilter(self) -> Optional[str]: - """ return inspection filter (only one repository to be fetched) """ + """return inspection filter (only one repository to be fetched)""" return self.mInspectionFilter def setInspectionFilter(self, key: Optional[str] = None): - """ temporarily disable all repositories but this for inspection """ + """temporarily disable all repositories but this for inspection""" self.mInspectionFilter = key # --- class Plugins ---------------------------------------------------------------------- # class Plugins(QObject): + """A dict-like class for handling plugins data""" - """ A dict-like class for handling plugins data """ # ----------------------------------------- # def __init__(self): QObject.__init__(self) - self.mPlugins = {} # the dict of plugins (dicts) - self.repoCache = {} # the dict of lists of plugins (dicts) - self.localCache = {} # the dict of plugins (dicts) - self.obsoletePlugins = [] # the list of outdated 'user' plugins masking newer 'system' ones + self.mPlugins = {} # the dict of plugins (dicts) + self.repoCache = {} # the dict of lists of plugins (dicts) + self.localCache = {} # the dict of plugins (dicts) + self.obsoletePlugins = ( + [] + ) # the list of outdated 'user' plugins masking newer 'system' ones # ----------------------------------------- # def all(self): - """ return all plugins """ + """return all plugins""" return self.mPlugins # ----------------------------------------- # def allUpgradeable(self): - """ return all upgradeable plugins """ + """return all upgradeable plugins""" result = {} for i in self.mPlugins: if self.mPlugins[i]["status"] == "upgradeable": @@ -497,7 +741,7 @@ def allUpgradeable(self): # ----------------------------------------- # def keyByUrl(self, name): - """ return plugin key by given url """ + """return plugin key by given url""" plugins = [i for i in self.mPlugins if self.mPlugins[i]["download_url"] == name] if plugins: return plugins[0] @@ -505,12 +749,12 @@ def keyByUrl(self, name): # ----------------------------------------- # def clearRepoCache(self): - """ clears the repo cache before re-fetching repositories """ + """clears the repo cache before re-fetching repositories""" self.repoCache = {} # ----------------------------------------- # def addFromRepository(self, plugin): - """ add given plugin to the repoCache """ + """add given plugin to the repoCache""" repo = plugin["zip_repository"] try: self.repoCache[repo] += [plugin] @@ -519,44 +763,45 @@ def addFromRepository(self, plugin): # ----------------------------------------- # def removeInstalledPlugin(self, key): - """ remove given plugin from the localCache """ + """remove given plugin from the localCache""" if key in self.localCache: del self.localCache[key] # ----------------------------------------- # def removeRepository(self, repo: str): - """ remove whole repository from the repoCache """ + """remove whole repository from the repoCache""" if repo in self.repoCache: del self.repoCache[repo] # ----------------------------------------- # def getInstalledPlugin(self, key, path, readOnly): - """ get the metadata of an installed plugin """ + """get the metadata of an installed plugin""" + def metadataParser(fct): - """ plugin metadata parser reimplemented from qgis.utils - for better control of which module is examined - in case there is an installed plugin masking a core one """ + """plugin metadata parser reimplemented from qgis.utils + for better control of which module is examined + in case there is an installed plugin masking a core one""" global errorDetails cp = configparser.ConfigParser() try: with codecs.open(metadataFile, "r", "utf8") as f: cp.read_file(f) - return cp.get('general', fct) + return cp.get("general", fct) except Exception as e: if not errorDetails: errorDetails = e.args[0] # set to the first problem return "" def pluginMetadata(fct): - """ calls metadataParser for current l10n. - If failed, fallbacks to the standard metadata """ - overrideLocale = QgsSettings().value('locale/overrideFlag', False, bool) + """calls metadataParser for current l10n. + If failed, fallbacks to the standard metadata""" + overrideLocale = QgsSettings().value("locale/overrideFlag", False, bool) if not overrideLocale: locale = QLocale.system().name() else: - locale = QgsSettings().value('locale/userLocale', '') + locale = QgsSettings().value("locale/userLocale", "") if locale and fct in translatableAttributes: - value = metadataParser("{}[{}]".format(fct, locale)) + value = metadataParser(f"{fct}[{locale}]") if value: return value value = metadataParser("{}[{}]".format(fct, locale.split("_")[0])) @@ -573,19 +818,27 @@ def pluginMetadata(fct): errorDetails = "" version = None - if not os.path.exists(os.path.join(path, '__init__.py')): + if not os.path.exists(os.path.join(path, "__init__.py")): error = "broken" - errorDetails = QCoreApplication.translate("QgsPluginInstaller", "Missing __init__.py") + errorDetails = QCoreApplication.translate( + "QgsPluginInstaller", "Missing __init__.py" + ) - metadataFile = os.path.join(path, 'metadata.txt') + metadataFile = os.path.join(path, "metadata.txt") if os.path.exists(metadataFile): version = normalizeVersion(pluginMetadata("version")) - qt_version = int(QT_VERSION_STR.split('.')[0]) + qt_version = int(QT_VERSION_STR.split(".")[0]) supports_qt6 = pluginMetadata("supportsQt6").strip().upper() in ("TRUE", "YES") - if qt_version == 6 and not supports_qt6 and "QGIS_DISABLE_SUPPORTS_QT6_CHECK" not in os.environ: + if ( + qt_version == 6 + and not supports_qt6 + and "QGIS_DISABLE_SUPPORTS_QT6_CHECK" not in os.environ + ): error = "incompatible" - errorDetails = QCoreApplication.translate("QgsPluginInstaller", "Plugin does not support Qt6 versions of QGIS") + errorDetails = QCoreApplication.translate( + "QgsPluginInstaller", "Plugin does not support Qt6 versions of QGIS" + ) elif version: qgisMinimumVersion = pluginMetadata("qgisMinimumVersion").strip() if not qgisMinimumVersion: @@ -594,16 +847,22 @@ def pluginMetadata(fct): if not qgisMaximumVersion: qgisMaximumVersion = qgisMinimumVersion[0] + ".99" # if compatible, add the plugin to the list - if not isCompatible(pyQgisVersion(), qgisMinimumVersion, qgisMaximumVersion): + if not isCompatible( + pyQgisVersion(), qgisMinimumVersion, qgisMaximumVersion + ): error = "incompatible" - errorDetails = "{} - {}".format(qgisMinimumVersion, qgisMaximumVersion) + errorDetails = f"{qgisMinimumVersion} - {qgisMaximumVersion}" elif not os.path.exists(metadataFile): error = "broken" - errorDetails = QCoreApplication.translate("QgsPluginInstaller", "Missing metadata file") + errorDetails = QCoreApplication.translate( + "QgsPluginInstaller", "Missing metadata file" + ) else: error = "broken" e = errorDetails - errorDetails = QCoreApplication.translate("QgsPluginInstaller", "Error reading metadata") + errorDetails = QCoreApplication.translate( + "QgsPluginInstaller", "Error reading metadata" + ) if e: errorDetails += ": " + e @@ -644,14 +903,16 @@ def pluginMetadata(fct): "version_installed": version, "library": path, "pythonic": True, - "experimental": pluginMetadata("experimental").strip().upper() in ["TRUE", "YES"], - "deprecated": pluginMetadata("deprecated").strip().upper() in ["TRUE", "YES"], + "experimental": pluginMetadata("experimental").strip().upper() + in ["TRUE", "YES"], + "deprecated": pluginMetadata("deprecated").strip().upper() + in ["TRUE", "YES"], "trusted": False, "version_available": "", "version_available_stable": "", "version_available_experimental": "", "zip_repository": "", - "download_url": path, # warning: local path as url! + "download_url": path, # warning: local path as url! "download_url_stable": "", "download_url_experimental": "", "filename": "", @@ -664,7 +925,7 @@ def pluginMetadata(fct): "update_date_stable": pluginMetadata("update_date_stable"), "create_date_experimental": pluginMetadata("create_date_experimental"), "update_date_experimental": pluginMetadata("update_date_experimental"), - "available": False, # Will be overwritten, if any available version found. + "available": False, # Will be overwritten, if any available version found. "installed": True, "status": "orphan", # Will be overwritten, if any available version found. "status_exp": "orphan", # Will be overwritten, if any available version found. @@ -677,7 +938,7 @@ def pluginMetadata(fct): # ----------------------------------------- # def getAllInstalled(self): - """ Build the localCache """ + """Build the localCache""" self.localCache = {} # reversed list of the plugin paths: first system plugins -> then user plugins -> finally custom path(s) @@ -685,7 +946,9 @@ def getAllInstalled(self): pluginPaths.reverse() for pluginsPath in pluginPaths: - isTheSystemDir = (pluginPaths.index(pluginsPath) == 0) # The current dir is the system plugins dir + isTheSystemDir = ( + pluginPaths.index(pluginsPath) == 0 + ) # The current dir is the system plugins dir if isTheSystemDir: # temporarily add the system path as the first element to force loading the readonly plugins, even if masked by user ones. sys.path = [pluginsPath] + sys.path @@ -696,10 +959,19 @@ def getAllInstalled(self): if key not in [".", ".."]: path = QDir.toNativeSeparators(pluginsPath + "/" + key) # readOnly = not QFileInfo(pluginsPath).isWritable() # On windows testing the writable status isn't reliable. - readOnly = isTheSystemDir # Assume only the system plugins are not writable. + readOnly = isTheSystemDir # Assume only the system plugins are not writable. # failedToLoad = settings.value("/PythonPlugins/watchDog/" + key) is not None - plugin = self.getInstalledPlugin(key, path=path, readOnly=readOnly) - if key in list(self.localCache.keys()) and compareVersions(self.localCache[key]["version_installed"], plugin["version_installed"]) == 1: + plugin = self.getInstalledPlugin( + key, path=path, readOnly=readOnly + ) + if ( + key in list(self.localCache.keys()) + and compareVersions( + self.localCache[key]["version_installed"], + plugin["version_installed"], + ) + == 1 + ): # An obsolete plugin in the "user" location is masking a newer one in the "system" location! self.obsoletePlugins += [key] self.localCache[key] = plugin @@ -713,29 +985,45 @@ def getAllInstalled(self): # ----------------------------------------- # def rebuild(self): - """ build or rebuild the mPlugins from the caches """ + """build or rebuild the mPlugins from the caches""" self.mPlugins = {} for i in list(self.localCache.keys()): self.mPlugins[i] = self.localCache[i].copy() - allowExperimental = QgsSettingsTree.node("plugin-manager").childSetting("allow-experimental").value() - allowDeprecated = QgsSettingsTree.node("plugin-manager").childSetting("allow-deprecated").value() + allowExperimental = ( + QgsSettingsTree.node("plugin-manager") + .childSetting("allow-experimental") + .value() + ) + allowDeprecated = ( + QgsSettingsTree.node("plugin-manager") + .childSetting("allow-deprecated") + .value() + ) for i in list(self.repoCache.values()): for j in i: plugin = j.copy() # do not update repoCache elements! key = plugin["id"] # check if the plugin is allowed and if there isn't any better one added already. - if (allowExperimental or not plugin["experimental"]) \ - and (allowDeprecated or not plugin["deprecated"]) \ - and not ( - key in self.mPlugins and self.mPlugins[key]["version_available"] - and compareVersions(self.mPlugins[key]["version_available"], plugin["version_available"]) < 2 - and self.mPlugins[key]["experimental"] and not plugin["experimental"] + if ( + (allowExperimental or not plugin["experimental"]) + and (allowDeprecated or not plugin["deprecated"]) + and not ( + key in self.mPlugins + and self.mPlugins[key]["version_available"] + and compareVersions( + self.mPlugins[key]["version_available"], + plugin["version_available"], + ) + < 2 + and self.mPlugins[key]["experimental"] + and not plugin["experimental"] + ) ): # The mPlugins dict contains now locally installed plugins. # Now, add the available one if not present yet or update it if present already. if key not in self.mPlugins: - self.mPlugins[key] = plugin # just add a new plugin + self.mPlugins[key] = plugin # just add a new plugin else: # update local plugin with remote metadata # description, about, icon: only use remote data if local one not available. Prefer local version because of i18n. @@ -746,18 +1034,56 @@ def rebuild(self): if not self.mPlugins[key][attrib] and plugin[attrib]: self.mPlugins[key][attrib] = plugin[attrib] # other remote metadata is preferred: - for attrib in ["name", "plugin_id", "description", "about", "category", "tags", "changelog", "author_name", "author_email", "homepage", - "tracker", "code_repository", "experimental", "deprecated", "version_available", "zip_repository", - "download_url", "filename", "downloads", "average_vote", "rating_votes", "trusted", "plugin_dependencies", - "version_available_stable", "version_available_experimental", "download_url_stable", "download_url_experimental", - "create_date", "update_date", "create_date_stable", "update_date_stable", "create_date_experimental", "update_date_experimental"]: - if attrib not in translatableAttributes or attrib == "name": # include name! + for attrib in [ + "name", + "plugin_id", + "description", + "about", + "category", + "tags", + "changelog", + "author_name", + "author_email", + "homepage", + "tracker", + "code_repository", + "experimental", + "deprecated", + "version_available", + "zip_repository", + "download_url", + "filename", + "downloads", + "average_vote", + "rating_votes", + "trusted", + "plugin_dependencies", + "version_available_stable", + "version_available_experimental", + "download_url_stable", + "download_url_experimental", + "create_date", + "update_date", + "create_date_stable", + "update_date_stable", + "create_date_experimental", + "update_date_experimental", + ]: + if ( + attrib not in translatableAttributes or attrib == "name" + ): # include name! if plugin.get(attrib, False): self.mPlugins[key][attrib] = plugin[attrib] # If the stable version is higher than the experimental version, we ignore the experimental version - if compareVersions(self.mPlugins[key]["version_available_stable"], self.mPlugins[key]["version_available_experimental"]) == 1: - self.mPlugins[key]["version_available_experimental"] = '' + if ( + compareVersions( + self.mPlugins[key]["version_available_stable"], + self.mPlugins[key]["version_available_experimental"], + ) + == 1 + ): + self.mPlugins[key]["version_available_experimental"] = "" # set status # @@ -769,60 +1095,129 @@ def rebuild(self): # same same "installed" # less greater "upgradeable" # greater less "newer" - if not self.mPlugins[key]["version_available_stable"] and not self.mPlugins[key]["version_installed"]: + if ( + not self.mPlugins[key]["version_available_stable"] + and not self.mPlugins[key]["version_installed"] + ): self.mPlugins[key]["status"] = "none available" - elif not self.mPlugins[key]["version_available_stable"] and self.mPlugins[key]["version_installed"]: + elif ( + not self.mPlugins[key]["version_available_stable"] + and self.mPlugins[key]["version_installed"] + ): self.mPlugins[key]["status"] = "orphan" elif not self.mPlugins[key]["version_installed"]: self.mPlugins[key]["status"] = "not installed" elif self.mPlugins[key]["version_installed"] in ["?", "-1"]: self.mPlugins[key]["status"] = "installed" - elif compareVersions(self.mPlugins[key]["version_available_stable"], self.mPlugins[key]["version_installed"]) == 0: + elif ( + compareVersions( + self.mPlugins[key]["version_available_stable"], + self.mPlugins[key]["version_installed"], + ) + == 0 + ): self.mPlugins[key]["status"] = "installed" - elif compareVersions(self.mPlugins[key]["version_available_stable"], self.mPlugins[key]["version_installed"]) == 1: + elif ( + compareVersions( + self.mPlugins[key]["version_available_stable"], + self.mPlugins[key]["version_installed"], + ) + == 1 + ): self.mPlugins[key]["status"] = "upgradeable" else: self.mPlugins[key]["status"] = "newer" # debug: test if the status match the "installed" tag: - if self.mPlugins[key]["status"] in ["not installed", "none available"] and self.mPlugins[key]["installed"]: - raise Exception("Error: plugin status is ambiguous (1) for plugin {}".format(key)) - if self.mPlugins[key]["status"] in ["installed", "orphan", "upgradeable", "newer"] and not self.mPlugins[key]["installed"]: - raise Exception("Error: plugin status is ambiguous (2) for plugin {}".format(key)) - - if not self.mPlugins[key]["version_available_experimental"] and not self.mPlugins[key]["version_installed"]: + if ( + self.mPlugins[key]["status"] + in ["not installed", "none available"] + and self.mPlugins[key]["installed"] + ): + raise Exception( + f"Error: plugin status is ambiguous (1) for plugin {key}" + ) + if ( + self.mPlugins[key]["status"] + in ["installed", "orphan", "upgradeable", "newer"] + and not self.mPlugins[key]["installed"] + ): + raise Exception( + f"Error: plugin status is ambiguous (2) for plugin {key}" + ) + + if ( + not self.mPlugins[key]["version_available_experimental"] + and not self.mPlugins[key]["version_installed"] + ): self.mPlugins[key]["status_exp"] = "none available" - elif not self.mPlugins[key]["version_available_experimental"] and self.mPlugins[key]["version_installed"]: + elif ( + not self.mPlugins[key]["version_available_experimental"] + and self.mPlugins[key]["version_installed"] + ): self.mPlugins[key]["status_exp"] = "orphan" elif not self.mPlugins[key]["version_installed"]: self.mPlugins[key]["status_exp"] = "not installed" elif self.mPlugins[key]["version_installed"] in ["?", "-1"]: self.mPlugins[key]["status_exp"] = "installed" - elif compareVersions(self.mPlugins[key]["version_available_experimental"], self.mPlugins[key]["version_installed"]) == 0: + elif ( + compareVersions( + self.mPlugins[key]["version_available_experimental"], + self.mPlugins[key]["version_installed"], + ) + == 0 + ): self.mPlugins[key]["status_exp"] = "installed" - elif compareVersions(self.mPlugins[key]["version_available_experimental"], self.mPlugins[key]["version_installed"]) == 1: + elif ( + compareVersions( + self.mPlugins[key]["version_available_experimental"], + self.mPlugins[key]["version_installed"], + ) + == 1 + ): self.mPlugins[key]["status_exp"] = "upgradeable" else: self.mPlugins[key]["status_exp"] = "newer" # debug: test if the status_exp match the "installed" tag: - if self.mPlugins[key]["status_exp"] in ["not installed", "none available"] and self.mPlugins[key]["installed"]: - raise Exception("Error: plugin status_exp is ambiguous (1) for plugin {}".format(key)) - if self.mPlugins[key]["status_exp"] in ["installed", "orphan", "upgradeable", "newer"] and not self.mPlugins[key]["installed"]: - raise Exception("Error: plugin status_exp is ambiguous (2) for plugin {} (status_exp={})".format(key, self.mPlugins[key]["status_exp"])) + if ( + self.mPlugins[key]["status_exp"] + in ["not installed", "none available"] + and self.mPlugins[key]["installed"] + ): + raise Exception( + f"Error: plugin status_exp is ambiguous (1) for plugin {key}" + ) + if ( + self.mPlugins[key]["status_exp"] + in ["installed", "orphan", "upgradeable", "newer"] + and not self.mPlugins[key]["installed"] + ): + raise Exception( + "Error: plugin status_exp is ambiguous (2) for plugin {} (status_exp={})".format( + key, self.mPlugins[key]["status_exp"] + ) + ) self.markNews() # ----------------------------------------- # def markNews(self): - """ mark all new plugins as new """ - seenPlugins = QgsSettingsTree.node("plugin-manager").childSetting("seen-plugins").valueWithDefaultOverride(list(self.mPlugins.keys())) + """mark all new plugins as new""" + seenPlugins = ( + QgsSettingsTree.node("plugin-manager") + .childSetting("seen-plugins") + .valueWithDefaultOverride(list(self.mPlugins.keys())) + ) if len(seenPlugins) > 0: for plugin in list(self.mPlugins.keys()): - if seenPlugins.count(plugin) == 0 and self.mPlugins[plugin]["status"] == "not installed": + if ( + seenPlugins.count(plugin) == 0 + and self.mPlugins[plugin]["status"] == "not installed" + ): self.mPlugins[plugin]["status"] = "new" # ----------------------------------------- # def updateSeenPluginsList(self): - """ update the list of all seen plugins """ + """update the list of all seen plugins""" setting = QgsSettingsTree.node("plugin-manager").childSetting("seen-plugins") seenPlugins = setting.valueWithDefaultOverride(list(self.mPlugins.keys())) for plugin in list(self.mPlugins.keys()): @@ -832,7 +1227,7 @@ def updateSeenPluginsList(self): # ----------------------------------------- # def isThereAnythingNew(self): - """ return true if an upgradeable or new plugin detected """ + """return true if an upgradeable or new plugin detected""" for i in list(self.mPlugins.values()): if i["status"] in ["upgradeable", "new"]: return True diff --git a/python/pyplugin_installer/plugindependencies.py b/python/pyplugin_installer/plugindependencies.py index c95e1f49b06d..4c1910208ca2 100644 --- a/python/pyplugin_installer/plugindependencies.py +++ b/python/pyplugin_installer/plugindependencies.py @@ -1,4 +1,3 @@ -# coding=utf-8 """Parse plugin metadata for plugin_dependencies .. note:: This program is free software; you can redistribute it and/or modify @@ -8,9 +7,9 @@ """ -__author__ = 'elpaso@itopen.it' -__date__ = '2018-05-29' -__copyright__ = 'Copyright 2018, GISCE-TI S.L.' +__author__ = "elpaso@itopen.it" +__date__ = "2018-05-29" +__copyright__ = "Copyright 2018, GISCE-TI S.L." from configparser import NoOptionError, NoSectionError from .version_compare import compareVersions @@ -19,13 +18,12 @@ def __plugin_name_map(plugin_data_values): - return { - plugin['name']: plugin['id'] - for plugin in plugin_data_values - } + return {plugin["name"]: plugin["id"] for plugin in plugin_data_values} -def find_dependencies(plugin_id, plugin_data=None, plugin_deps=None, installed_plugins=None): +def find_dependencies( + plugin_id, plugin_data=None, plugin_deps=None, installed_plugins=None +): """Finds the plugin dependencies and checks if they can be installed or upgraded :param plugin_id: plugin id @@ -52,7 +50,12 @@ def find_dependencies(plugin_id, plugin_data=None, plugin_deps=None, installed_p if installed_plugins is None: metadata_parser = metadataParser() - installed_plugins = {metadata_parser[k].get('general', 'name'): metadata_parser[k].get('general', 'version') for k, v in metadata_parser.items()} + installed_plugins = { + metadata_parser[k] + .get("general", "name"): metadata_parser[k] + .get("general", "version") + for k, v in metadata_parser.items() + } if plugin_data is None: plugin_data = plugin_installer.plugins.all() @@ -64,33 +67,49 @@ def find_dependencies(plugin_id, plugin_data=None, plugin_deps=None, installed_p try: p_id = plugins_map[name] except KeyError: - not_found.update({name: { - 'id': None, - 'version_installed': None, - 'version_required': None, - 'version_available': None, - 'use_stable_version': None, - 'action': None, - 'error': 'missing_id' - }}) + not_found.update( + { + name: { + "id": None, + "version_installed": None, + "version_required": None, + "version_available": None, + "use_stable_version": None, + "action": None, + "error": "missing_id", + } + } + ) continue - affected_plugin = dict({ - "id": p_id, - # "version_installed": installed_plugins.get(p_id, {}).get('installed_plugins', None), - "version_installed": installed_plugins.get(name, None), - "version_required": version_required, - "version_available": plugin_data[p_id].get('version_available', None), - "use_stable_version": True, # Prefer stable by default - "action": None, - }) - version_available_stable = plugin_data[p_id].get('version_available_stable', None) - version_available_experimental = plugin_data[p_id].get('version_available_experimental', None) - - if version_required is not None and version_required == version_available_stable: + affected_plugin = dict( + { + "id": p_id, + # "version_installed": installed_plugins.get(p_id, {}).get('installed_plugins', None), + "version_installed": installed_plugins.get(name, None), + "version_required": version_required, + "version_available": plugin_data[p_id].get("version_available", None), + "use_stable_version": True, # Prefer stable by default + "action": None, + } + ) + version_available_stable = plugin_data[p_id].get( + "version_available_stable", None + ) + version_available_experimental = plugin_data[p_id].get( + "version_available_experimental", None + ) + + if ( + version_required is not None + and version_required == version_available_stable + ): affected_plugin["version_available"] = version_available_stable affected_plugin["use_stable_version"] = True - elif version_required is not None and version_required == version_available_experimental: + elif ( + version_required is not None + and version_required == version_available_experimental + ): affected_plugin["version_available"] = version_available_experimental affected_plugin["use_stable_version"] = False elif version_required is None: @@ -104,21 +123,29 @@ def find_dependencies(plugin_id, plugin_data=None, plugin_deps=None, installed_p # Install is needed if name not in installed_plugins: - affected_plugin['action'] = 'install' + affected_plugin["action"] = "install" destination_list = to_install # Upgrade is needed - elif version_required is not None and compareVersions(installed_plugins[name], version_required) == 2: - affected_plugin['action'] = 'upgrade' + elif ( + version_required is not None + and compareVersions(installed_plugins[name], version_required) == 2 + ): + affected_plugin["action"] = "upgrade" destination_list = to_upgrade # TODO @elpaso: review installed but not activated # No action is needed else: continue - if version_required == affected_plugin['version_available'] or version_required is None: + if ( + version_required == affected_plugin["version_available"] + or version_required is None + ): destination_list.update({name: affected_plugin}) else: - affected_plugin['error'] = 'unavailable {}'.format(affected_plugin['action']) + affected_plugin["error"] = "unavailable {}".format( + affected_plugin["action"] + ) not_found.update({name: affected_plugin}) return to_install, to_upgrade, not_found diff --git a/python/pyplugin_installer/qgsplugindependenciesdialog.py b/python/pyplugin_installer/qgsplugindependenciesdialog.py index ff13fbdeebde..cc8a0f943126 100644 --- a/python/pyplugin_installer/qgsplugindependenciesdialog.py +++ b/python/pyplugin_installer/qgsplugindependenciesdialog.py @@ -1,4 +1,3 @@ -# coding=utf-8 """Plugin dependencies selection dialog .. note:: This program is free software; you can redistribute it and/or modify @@ -8,9 +7,9 @@ """ -__author__ = 'elpaso@itopen.it' -__date__ = '2018-09-19' -__copyright__ = 'Copyright 2018, GISCE-TI S.L.' +__author__ = "elpaso@itopen.it" +__date__ = "2018-09-19" +__copyright__ = "Copyright 2018, GISCE-TI S.L." import os @@ -20,10 +19,14 @@ from qgis.PyQt import QtWidgets, QtCore from qgis.utils import iface -Ui_QgsPluginDependenciesDialogBase, _ = uic.loadUiType(Path(__file__).parent / 'qgsplugindependenciesdialogbase.ui') +Ui_QgsPluginDependenciesDialogBase, _ = uic.loadUiType( + Path(__file__).parent / "qgsplugindependenciesdialogbase.ui" +) -class QgsPluginDependenciesDialog(QtWidgets.QDialog, Ui_QgsPluginDependenciesDialogBase): +class QgsPluginDependenciesDialog( + QtWidgets.QDialog, Ui_QgsPluginDependenciesDialogBase +): """A dialog that shows plugin dependencies and offers a way to install or upgrade the dependencies. """ @@ -46,11 +49,21 @@ def __init__(self, plugin_name, to_install, to_upgrade, not_found, parent=None): super().__init__(parent) self.setupUi(self) self.setWindowTitle(self.tr("Plugin Dependencies Manager")) - self.mPluginDependenciesLabel.setText(self.tr("Plugin dependencies for %s") % plugin_name) + self.mPluginDependenciesLabel.setText( + self.tr("Plugin dependencies for %s") % plugin_name + ) self.setStyleSheet("QTableView { padding: 20px;}") # Name, Version Installed, Version Required, Version Available, Action Checkbox self.pluginList.setColumnCount(5) - self.pluginList.setHorizontalHeaderLabels([self.tr('Name'), self.tr('Installed'), self.tr('Required'), self.tr('Available'), self.tr('Action')]) + self.pluginList.setHorizontalHeaderLabels( + [ + self.tr("Name"), + self.tr("Installed"), + self.tr("Required"), + self.tr("Available"), + self.tr("Action"), + ] + ) self.pluginList.setRowCount(len(not_found) + len(to_install) + len(to_upgrade)) self.__actions = {} @@ -61,18 +74,18 @@ def _display(txt): def _make_row(data, i, name): widget = QtWidgets.QLabel("%s" % name) - widget.p_id = data['id'] - widget.action = data['action'] - widget.use_stable_version = data['use_stable_version'] + widget.p_id = data["id"] + widget.action = data["action"] + widget.use_stable_version = data["use_stable_version"] self.pluginList.setCellWidget(i, 0, widget) self.pluginList.resizeColumnToContents(0) - widget = QtWidgets.QTableWidgetItem(_display(data['version_installed'])) + widget = QtWidgets.QTableWidgetItem(_display(data["version_installed"])) widget.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) self.pluginList.setItem(i, 1, widget) - widget = QtWidgets.QTableWidgetItem(_display(data['version_required'])) + widget = QtWidgets.QTableWidgetItem(_display(data["version_required"])) widget.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) self.pluginList.setItem(i, 2, widget) - widget = QtWidgets.QTableWidgetItem(_display(data['version_available'])) + widget = QtWidgets.QTableWidgetItem(_display(data["version_available"])) widget.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) self.pluginList.setItem(i, 3, widget) @@ -112,8 +125,11 @@ def accept(self): try: if self.pluginList.cellWidget(i, 4).isChecked(): self.__actions[self.pluginList.cellWidget(i, 0).p_id] = { - 'action': self.pluginList.cellWidget(i, 0).action, - 'use_stable_version': self.pluginList.cellWidget(i, 0).use_stable_version} + "action": self.pluginList.cellWidget(i, 0).action, + "use_stable_version": self.pluginList.cellWidget( + i, 0 + ).use_stable_version, + } except: pass super().accept() diff --git a/python/pyplugin_installer/qgsplugininstallerfetchingdialog.py b/python/pyplugin_installer/qgsplugininstallerfetchingdialog.py index c38e15b64cf8..aeee08dbc3c5 100644 --- a/python/pyplugin_installer/qgsplugininstallerfetchingdialog.py +++ b/python/pyplugin_installer/qgsplugininstallerfetchingdialog.py @@ -1,4 +1,3 @@ -# -*- coding:utf-8 -*- """ /*************************************************************************** qgsplugininstallerfetchingdialog.py @@ -33,10 +32,15 @@ from .installer_data import repositories from qgis.gui import QgsGui -Ui_QgsPluginInstallerFetchingDialogBase, _ = uic.loadUiType(Path(__file__).parent / 'qgsplugininstallerfetchingbase.ui') +Ui_QgsPluginInstallerFetchingDialogBase, _ = uic.loadUiType( + Path(__file__).parent / "qgsplugininstallerfetchingbase.ui" +) -class QgsPluginInstallerFetchingDialog(QDialog, Ui_QgsPluginInstallerFetchingDialogBase): + +class QgsPluginInstallerFetchingDialog( + QDialog, Ui_QgsPluginInstallerFetchingDialogBase +): # ----------------------------------------- # def __init__(self, parent): @@ -65,13 +69,23 @@ def __init__(self, parent): def displayState(self, key, state, state2=None): messages = [ self.tr("Success"), - QCoreApplication.translate('QgsPluginInstallerFetchingDialog', "Resolving host name…"), - QCoreApplication.translate('QgsPluginInstallerFetchingDialog', "Connecting…"), - QCoreApplication.translate('QgsPluginInstallerFetchingDialog', "Host connected. Sending request…"), - QCoreApplication.translate('QgsPluginInstallerFetchingDialog', "Downloading data…"), + QCoreApplication.translate( + "QgsPluginInstallerFetchingDialog", "Resolving host name…" + ), + QCoreApplication.translate( + "QgsPluginInstallerFetchingDialog", "Connecting…" + ), + QCoreApplication.translate( + "QgsPluginInstallerFetchingDialog", "Host connected. Sending request…" + ), + QCoreApplication.translate( + "QgsPluginInstallerFetchingDialog", "Downloading data…" + ), self.tr("Idle"), - QCoreApplication.translate('QgsPluginInstallerFetchingDialog', "Closing connection…"), - self.tr("Error") + QCoreApplication.translate( + "QgsPluginInstallerFetchingDialog", "Closing connection…" + ), + self.tr("Error"), ] message = messages[state] if state2: diff --git a/python/pyplugin_installer/qgsplugininstallerinstallingdialog.py b/python/pyplugin_installer/qgsplugininstallerinstallingdialog.py index d82c26d29dc3..ebd96422318f 100644 --- a/python/pyplugin_installer/qgsplugininstallerinstallingdialog.py +++ b/python/pyplugin_installer/qgsplugininstallerinstallingdialog.py @@ -1,4 +1,3 @@ -# -*- coding:utf-8 -*- """ /*************************************************************************** qgsplugininstallerinstallingdialog.py @@ -23,7 +22,6 @@ * * ***************************************************************************/ """ -from builtins import str from pathlib import Path @@ -32,16 +30,24 @@ from qgis.PyQt.QtWidgets import QDialog from qgis.PyQt.QtNetwork import QNetworkRequest, QNetworkReply -from qgis.core import QgsNetworkAccessManager, QgsApplication, QgsNetworkRequestParameters +from qgis.core import ( + QgsNetworkAccessManager, + QgsApplication, + QgsNetworkRequestParameters, +) from qgis.utils import HOME_PLUGIN_PATH from .installer_data import removeDir, repositories from .unzip import unzip -Ui_QgsPluginInstallerInstallingDialogBase, _ = uic.loadUiType(Path(__file__).parent / 'qgsplugininstallerinstallingbase.ui') +Ui_QgsPluginInstallerInstallingDialogBase, _ = uic.loadUiType( + Path(__file__).parent / "qgsplugininstallerinstallingbase.ui" +) -class QgsPluginInstallerInstallingDialog(QDialog, Ui_QgsPluginInstallerInstallingDialogBase): +class QgsPluginInstallerInstallingDialog( + QDialog, Ui_QgsPluginInstallerInstallingDialogBase +): # ----------------------------------------- # def __init__(self, parent, plugin, stable=True): @@ -54,7 +60,11 @@ def __init__(self, parent, plugin, stable=True): self.labelName.setText(plugin["name"]) self.buttonBox.clicked.connect(self.abort) - self.url = QUrl(plugin["download_url_stable"] if stable else plugin["download_url_experimental"]) + self.url = QUrl( + plugin["download_url_stable"] + if stable + else plugin["download_url_experimental"] + ) self.redirectionCounter = 0 fileName = plugin["filename"] @@ -66,14 +76,21 @@ def __init__(self, parent, plugin, stable=True): def requestDownloading(self): self.request = QNetworkRequest(self.url) - self.request.setAttribute(QNetworkRequest.Attribute(QgsNetworkRequestParameters.RequestAttributes.AttributeInitiatorClass), "QgsPluginInstallerInstallingDialog") + self.request.setAttribute( + QNetworkRequest.Attribute( + QgsNetworkRequestParameters.RequestAttributes.AttributeInitiatorClass + ), + "QgsPluginInstallerInstallingDialog", + ) authcfg = repositories.all()[self.plugin["zip_repository"]]["authcfg"] if authcfg and isinstance(authcfg, str): if not QgsApplication.authManager().updateNetworkRequest( - self.request, authcfg.strip()): + self.request, authcfg.strip() + ): self.mResult = self.tr( "Update of network request with authentication " - "credentials FAILED for configuration '{0}'").format(authcfg) + "credentials FAILED for configuration '{0}'" + ).format(authcfg) self.request = None if self.request is not None: @@ -96,14 +113,26 @@ def result(self): # ----------------------------------------- # def stateChanged(self, state): messages = [ - QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Installing…"), - QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Resolving host name…"), - QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Connecting…"), - QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Host connected. Sending request…"), - QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Downloading data…"), + QCoreApplication.translate( + "QgsPluginInstallerInstallingDialog", "Installing…" + ), + QCoreApplication.translate( + "QgsPluginInstallerInstallingDialog", "Resolving host name…" + ), + QCoreApplication.translate( + "QgsPluginInstallerInstallingDialog", "Connecting…" + ), + QCoreApplication.translate( + "QgsPluginInstallerInstallingDialog", "Host connected. Sending request…" + ), + QCoreApplication.translate( + "QgsPluginInstallerInstallingDialog", "Downloading data…" + ), self.tr("Idle"), - QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Closing connection…"), - self.tr("Error") + QCoreApplication.translate( + "QgsPluginInstallerInstallingDialog", "Closing connection…" + ), + self.tr("Error"), ] self.labelState.setText(messages[state]) @@ -120,15 +149,25 @@ def requestFinished(self): if reply.error() != QNetworkReply.NetworkError.NoError: self.mResult = reply.errorString() if reply.error() == QNetworkReply.NetworkError.OperationCanceledError: - self.mResult += "

    " + QCoreApplication.translate("QgsPluginInstaller", "If you haven't canceled the download manually, it might be caused by a timeout. In this case consider increasing the connection timeout value in QGIS options.") + self.mResult += "

    " + QCoreApplication.translate( + "QgsPluginInstaller", + "If you haven't canceled the download manually, it might be caused by a timeout. In this case consider increasing the connection timeout value in QGIS options.", + ) self.reject() reply.deleteLater() return - elif reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) in (301, 302): - redirectionUrl = reply.attribute(QNetworkRequest.Attribute.RedirectionTargetAttribute) + elif reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) in ( + 301, + 302, + ): + redirectionUrl = reply.attribute( + QNetworkRequest.Attribute.RedirectionTargetAttribute + ) self.redirectionCounter += 1 if self.redirectionCounter > 4: - self.mResult = QCoreApplication.translate("QgsPluginInstaller", "Too many redirections") + self.mResult = QCoreApplication.translate( + "QgsPluginInstaller", "Too many redirections" + ) self.reject() reply.deleteLater() return @@ -154,12 +193,22 @@ def requestFinished(self): # if the target directory already exists as a link, remove the link without resolving: QFile(pluginDir + str(QDir.separator()) + self.plugin["id"]).remove() try: - unzip(str(tmpPath), str(pluginDir)) # test extract. If fails, then exception will be raised and no removing occurs + unzip( + str(tmpPath), str(pluginDir) + ) # test extract. If fails, then exception will be raised and no removing occurs # removing old plugin files if exist - removeDir(QDir.cleanPath(pluginDir + "/" + self.plugin["id"])) # remove old plugin if exists + removeDir( + QDir.cleanPath(pluginDir + "/" + self.plugin["id"]) + ) # remove old plugin if exists unzip(str(tmpPath), str(pluginDir)) # final extract. except: - self.mResult = self.tr("Failed to unzip the plugin package. Probably it's broken or missing from the repository. You may also want to make sure that you have write permission to the plugin directory:") + "\n" + pluginDir + self.mResult = ( + self.tr( + "Failed to unzip the plugin package. Probably it's broken or missing from the repository. You may also want to make sure that you have write permission to the plugin directory:" + ) + + "\n" + + pluginDir + ) self.reject() return try: diff --git a/python/pyplugin_installer/qgsplugininstallerpluginerrordialog.py b/python/pyplugin_installer/qgsplugininstallerpluginerrordialog.py index 76f635969bab..ad92ef73d930 100644 --- a/python/pyplugin_installer/qgsplugininstallerpluginerrordialog.py +++ b/python/pyplugin_installer/qgsplugininstallerpluginerrordialog.py @@ -1,4 +1,3 @@ -# -*- coding:utf-8 -*- """ /*************************************************************************** qgsplugininstallerpluginerrordialog.py @@ -30,10 +29,14 @@ from qgis.PyQt import uic -Ui_QgsPluginInstallerPluginErrorDialogBase, _ = uic.loadUiType(Path(__file__).parent / 'qgsplugininstallerpluginerrorbase.ui') +Ui_QgsPluginInstallerPluginErrorDialogBase, _ = uic.loadUiType( + Path(__file__).parent / "qgsplugininstallerpluginerrorbase.ui" +) -class QgsPluginInstallerPluginErrorDialog(QDialog, Ui_QgsPluginInstallerPluginErrorDialogBase): +class QgsPluginInstallerPluginErrorDialog( + QDialog, Ui_QgsPluginInstallerPluginErrorDialogBase +): # ----------------------------------------- # def __init__(self, parent, errorMessage): diff --git a/python/pyplugin_installer/qgsplugininstallerrepositorydialog.py b/python/pyplugin_installer/qgsplugininstallerrepositorydialog.py index 80edeb84bab9..2499d859e4f6 100644 --- a/python/pyplugin_installer/qgsplugininstallerrepositorydialog.py +++ b/python/pyplugin_installer/qgsplugininstallerrepositorydialog.py @@ -1,4 +1,3 @@ -# -*- coding:utf-8 -*- """ /*************************************************************************** qgsplugininstallerrepositorydialog.py @@ -31,10 +30,14 @@ from qgis.PyQt.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout from qgis.PyQt.QtCore import Qt -Ui_QgsPluginInstallerRepositoryDetailsDialogBase, _ = uic.loadUiType(Path(__file__).parent / 'qgsplugininstallerrepositorybase.ui') +Ui_QgsPluginInstallerRepositoryDetailsDialogBase, _ = uic.loadUiType( + Path(__file__).parent / "qgsplugininstallerrepositorybase.ui" +) -class QgsPluginInstallerRepositoryDialog(QDialog, Ui_QgsPluginInstallerRepositoryDetailsDialogBase): +class QgsPluginInstallerRepositoryDialog( + QDialog, Ui_QgsPluginInstallerRepositoryDetailsDialogBase +): # ----------------------------------------- # def __init__(self, parent=None): @@ -49,7 +52,7 @@ def __init__(self, parent=None): # ----------------------------------------- # def textChanged(self, string): - enable = (len(self.editName.text()) > 0 and len(self.editURL.text()) > 0) + enable = len(self.editName.text()) > 0 and len(self.editURL.text()) > 0 self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(enable) def editAuthCfgId(self): @@ -60,7 +63,9 @@ def editAuthCfgId(self): if self.editAuthCfg.text(): selector.setConfigId(self.editAuthCfg.text()) layout.addWidget(selector) - buttonBox = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Close) + buttonBox = QDialogButtonBox( + QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Close + ) buttonBox.accepted.connect(dlg.accept) buttonBox.rejected.connect(dlg.reject) layout.addWidget(buttonBox) diff --git a/python/pyplugin_installer/unzip.py b/python/pyplugin_installer/unzip.py index 7be620e75092..d4a80f8bcda4 100644 --- a/python/pyplugin_installer/unzip.py +++ b/python/pyplugin_installer/unzip.py @@ -1,4 +1,3 @@ -# -*- coding:utf-8 -*- """ /*************************************************************************** Plugin Installer module @@ -25,24 +24,24 @@ def unzip(file, targetDir, password=None): - """ Creates directory structure and extracts the zip contents to it. - file (file object) - the zip file to extract - targetDir (str) - target location - password (str; optional) - password to decrypt the zip file (if encrypted) + """Creates directory structure and extracts the zip contents to it. + file (file object) - the zip file to extract + targetDir (str) - target location + password (str; optional) - password to decrypt the zip file (if encrypted) """ # convert password to bytes if isinstance(password, str): - password = bytes(password, 'utf8') + password = bytes(password, "utf8") # create destination directory if doesn't exist - if not targetDir.endswith(':') and not os.path.exists(targetDir): + if not targetDir.endswith(":") and not os.path.exists(targetDir): os.makedirs(targetDir) zf = zipfile.ZipFile(file) for name in zf.namelist(): # Skip directories - they will be created when necessary by os.makedirs - if name.endswith('/'): + if name.endswith("/"): continue # Read the source file before creating any output, @@ -56,7 +55,7 @@ def unzip(file, targetDir, password=None): os.makedirs(fullDir) # extract file fullPath = os.path.normpath(os.path.join(targetDir, name)) - outfile = open(fullPath, 'wb') + outfile = open(fullPath, "wb") outfile.write(memberContent) outfile.flush() outfile.close() diff --git a/python/pyplugin_installer/version_compare.py b/python/pyplugin_installer/version_compare.py index ebcb5c0924a9..2871062e2bc1 100644 --- a/python/pyplugin_installer/version_compare.py +++ b/python/pyplugin_installer/version_compare.py @@ -45,8 +45,7 @@ list is usually recognized as higher, except following suffixes: ALPHA, BETA, RC, PREVIEW and TRUNK which make the version number lower. """ -from builtins import str -from builtins import range + from qgis.core import Qgis import re @@ -56,21 +55,32 @@ def normalizeVersion(s): - """ remove possible prefix from given string and convert to uppercase """ - prefixes = ['VERSION', 'VER.', 'VER', 'V.', 'V', 'REVISION', 'REV.', 'REV', 'R.', 'R'] + """remove possible prefix from given string and convert to uppercase""" + prefixes = [ + "VERSION", + "VER.", + "VER", + "V.", + "V", + "REVISION", + "REV.", + "REV", + "R.", + "R", + ] if not s: - return str() + return "" s = str(s).upper() for i in prefixes: - if s[:len(i)] == i: - s = s.replace(i, '') + if s[: len(i)] == i: + s = s.replace(i, "") s = s.strip() return s # ------------------------------------------------------------------------ # def classifyCharacter(c): - """ return 0 for delimiter, 1 for digit and 2 for alphabetic character """ + """return 0 for delimiter, 1 for digit and 2 for alphabetic character""" if c in [".", "-", "_", " "]: return 0 if c.isdigit(): @@ -81,7 +91,7 @@ def classifyCharacter(c): # ------------------------------------------------------------------------ # def chopString(s): - """ convert string to list of numbers and words """ + """convert string to list of numbers and words""" l = [s[0]] for i in range(1, len(s)): if classifyCharacter(s[i]) == 0: @@ -95,12 +105,19 @@ def chopString(s): # ------------------------------------------------------------------------ # def compareElements(s1, s2): - """ compare two particular elements """ + """compare two particular elements""" # check if the matter is easy solvable: if s1 == s2: return 0 # try to compare as numeric values (but only if the first character is not 0): - if s1 and s2 and s1.isnumeric() and s2.isnumeric() and s1[0] != '0' and s2[0] != '0': + if ( + s1 + and s2 + and s1.isnumeric() + and s2.isnumeric() + and s1[0] != "0" + and s2[0] != "0" + ): if float(s1) == float(s2): return 0 elif float(s1) > float(s2): @@ -109,10 +126,10 @@ def compareElements(s1, s2): return 2 # if the strings aren't numeric or start from 0, compare them as a strings: # but first, set ALPHA < BETA < PREVIEW < RC < TRUNK < [NOTHING] < [ANYTHING_ELSE] - if s1 not in ['ALPHA', 'BETA', 'PREVIEW', 'RC', 'TRUNK']: - s1 = 'Z' + s1 - if s2 not in ['ALPHA', 'BETA', 'PREVIEW', 'RC', 'TRUNK']: - s2 = 'Z' + s2 + if s1 not in ["ALPHA", "BETA", "PREVIEW", "RC", "TRUNK"]: + s1 = "Z" + s1 + if s2 not in ["ALPHA", "BETA", "PREVIEW", "RC", "TRUNK"]: + s2 = "Z" + s2 # the final test: if s1 > s2: return 1 @@ -122,7 +139,7 @@ def compareElements(s1, s2): # ------------------------------------------------------------------------ # def compareVersions(a, b): - """ Compare two version numbers. Return 0 if a==b or error, 1 if a>b and 2 if b>a """ + """Compare two version numbers. Return 0 if a==b or error, 1 if a>b and 2 if b>a""" if not a or not b: return 0 a = normalizeVersion(a) @@ -143,9 +160,9 @@ def compareVersions(a, b): # if the lists are identical till the end of the shorter string, try to compare the odd tail # with the simple space (because the 'alpha', 'beta', 'preview' and 'rc' are LESS then nothing) if len(v1) > l: - return compareElements(v1[l], ' ') + return compareElements(v1[l], " ") if len(v2) > l: - return compareElements(' ', v2[l]) + return compareElements(" ", v2[l]) # if everything else fails... if a > b: return 1 @@ -160,10 +177,10 @@ def compareVersions(a, b): def splitVersion(s): - """ split string into 2 or 3 numerical segments """ + """split string into 2 or 3 numerical segments""" if not s or type(s) is not str: return None - l = str(s).split('.') + l = str(s).split(".") for c in l: if not c.isnumeric(): return None @@ -175,14 +192,14 @@ def splitVersion(s): def isCompatible(curVer, minVer, maxVer): - """ Compare current QGIS version with qgisMinVersion and qgisMaxVersion """ + """Compare current QGIS version with qgisMinVersion and qgisMaxVersion""" if not minVer or not curVer or not maxVer: return False - minVer = splitVersion(re.sub(r'[^0-9.]+', '', minVer)) - maxVer = splitVersion(re.sub(r'[^0-9.]+', '', maxVer)) - curVer = splitVersion(re.sub(r'[^0-9.]+', '', curVer)) + minVer = splitVersion(re.sub(r"[^0-9.]+", "", minVer)) + maxVer = splitVersion(re.sub(r"[^0-9.]+", "", maxVer)) + curVer = splitVersion(re.sub(r"[^0-9.]+", "", curVer)) if not minVer or not curVer or not maxVer: return False @@ -196,20 +213,20 @@ def isCompatible(curVer, minVer, maxVer): if len(maxVer) < 3: maxVer += ["99"] - minVer = "{:04n}{:04n}{:04n}".format(int(minVer[0]), int(minVer[1]), int(minVer[2])) - maxVer = "{:04n}{:04n}{:04n}".format(int(maxVer[0]), int(maxVer[1]), int(maxVer[2])) - curVer = "{:04n}{:04n}{:04n}".format(int(curVer[0]), int(curVer[1]), int(curVer[2])) + minVer = f"{int(minVer[0]):04n}{int(minVer[1]):04n}{int(minVer[2]):04n}" + maxVer = f"{int(maxVer[0]):04n}{int(maxVer[1]):04n}{int(maxVer[2]):04n}" + curVer = f"{int(curVer[0]):04n}{int(curVer[1]):04n}{int(curVer[2]):04n}" - return (minVer <= curVer and maxVer >= curVer) + return minVer <= curVer and maxVer >= curVer def pyQgisVersion(): - """ Return current QGIS version number as X.Y.Z for testing plugin compatibility. - If Y = 99, bump up to (X+1.0.0), so e.g. 2.99 becomes 3.0.0 - This way QGIS X.99 is only compatible with plugins for the upcoming major release. + """Return current QGIS version number as X.Y.Z for testing plugin compatibility. + If Y = 99, bump up to (X+1.0.0), so e.g. 2.99 becomes 3.0.0 + This way QGIS X.99 is only compatible with plugins for the upcoming major release. """ - x, y, z = re.findall(r'^(\d*).(\d*).(\d*)', Qgis.QGIS_VERSION)[0] - if y == '99': + x, y, z = re.findall(r"^(\d*).(\d*).(\d*)", Qgis.QGIS_VERSION)[0] + if y == "99": x = str(int(x) + 1) - y = z = '0' - return '{}.{}.{}'.format(x, y, z) + y = z = "0" + return f"{x}.{y}.{z}" diff --git a/python/testing/__init__.py b/python/testing/__init__.py index f7608a27518f..33087f26de05 100644 --- a/python/testing/__init__.py +++ b/python/testing/__init__.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** __init__.py @@ -41,13 +39,9 @@ QDir, QUrl, QSize, - QCoreApplication -) -from qgis.PyQt.QtGui import ( - QImage, - QDesktopServices, - QPainter + QCoreApplication, ) +from qgis.PyQt.QtGui import QImage, QDesktopServices, QPainter from qgis.core import ( QgsApplication, QgsFeatureRequest, @@ -71,12 +65,12 @@ def is_ci_run() -> bool: """ Returns True if the test is being run on the CI environment """ - return os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN") == 'true' + return os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN") == "true" @classmethod def setUpClass(cls): - cls.report = '' - cls.markdown_report = '' + cls.report = "" + cls.markdown_report = "" @classmethod def tearDownClass(cls): @@ -98,32 +92,35 @@ def write_local_html_report(cls, report: str): if not report_dir.exists(): QDir().mkpath(report_dir.path()) - report_file = report_dir.filePath('index.html') + report_file = report_dir.filePath("index.html") # only append to existing reports if running under CI file_is_empty = True - if cls.is_ci_run() or \ - os.environ.get("QGIS_APPEND_TO_TEST_REPORT") == 'true': - file_mode = 'ta' + if cls.is_ci_run() or os.environ.get("QGIS_APPEND_TO_TEST_REPORT") == "true": + file_mode = "ta" try: - with open(report_file, 'rt', encoding="utf-8") as f: + with open(report_file, encoding="utf-8") as f: file_is_empty = not bool(f.read()) - except IOError: + except OSError: pass else: - file_mode = 'wt' + file_mode = "wt" - with open(report_file, file_mode, encoding='utf-8') as f: + with open(report_file, file_mode, encoding="utf-8") as f: if file_is_empty: from .test_data_dir import TEST_DATA_DIR # append standard header - with open(TEST_DATA_DIR + "/../test_report_header.html", 'rt', encoding='utf-8') as header_file: + with open( + TEST_DATA_DIR + "/../test_report_header.html", encoding="utf-8" + ) as header_file: f.write(header_file.read()) # append embedded scripts - f.write('\n") @@ -153,7 +150,7 @@ def write_local_markdown_report(cls, report: str): @classmethod def get_test_caller_details( cls, - ) -> Tuple[Optional[str], Optional[str], Optional[int]]: + ) -> tuple[Optional[str], Optional[str], Optional[int]]: """ Retrieves the details of the caller at the earliest position in the stack, excluding unittest internals. @@ -186,7 +183,7 @@ def image_check( size_tolerance: Optional[Union[int, QSize]] = None, expect_fail: bool = False, control_path_prefix: Optional[str] = None, - use_checkerboard_background: bool = False + use_checkerboard_background: bool = False, ) -> bool: if use_checkerboard_background: output_image = QImage(image.size(), QImage.Format.Format_RGB32) @@ -217,7 +214,9 @@ def image_check( if size_tolerance is not None: if isinstance(size_tolerance, QSize): if size_tolerance.isValid(): - checker.setSizeTolerance(size_tolerance.width(), size_tolerance.height()) + checker.setSizeTolerance( + size_tolerance.width(), size_tolerance.height() + ) else: checker.setSizeTolerance(size_tolerance, size_tolerance) @@ -228,7 +227,7 @@ def image_check( markdown = checker.markdownReport() if markdown: - cls.markdown_report += "## {}\n\n".format(name) + cls.markdown_report += f"## {name}\n\n" cls.markdown_report += markdown return result @@ -242,7 +241,7 @@ def render_map_settings_check( control_name=None, color_tolerance: Optional[int] = None, allowed_mismatch: Optional[int] = None, - control_path_prefix: Optional[str] = None + control_path_prefix: Optional[str] = None, ) -> bool: checker = QgsMultiRenderChecker() checker.setMapSettings(map_settings) @@ -265,19 +264,20 @@ def render_map_settings_check( markdown = checker.markdownReport() if markdown: - cls.markdown_report += "## {}\n\n".format(name) + cls.markdown_report += f"## {name}\n\n" cls.markdown_report += markdown return result @classmethod def render_layout_check( - cls, name: str, + cls, + name: str, layout: QgsLayout, size: Optional[QSize] = None, color_tolerance: Optional[int] = None, allowed_mismatch: Optional[int] = None, - page: Optional[int] = 0 + page: Optional[int] = 0, ) -> bool: checker = QgsLayoutChecker(name, layout) @@ -292,15 +292,14 @@ def render_layout_check( if cls.control_path_prefix(): checker.setControlPathPrefix(cls.control_path_prefix()) - result, message = checker.testLayout(page=page, - pixelDiff=allowed_mismatch or 0) + result, message = checker.testLayout(page=page, pixelDiff=allowed_mismatch or 0) if not result: cls.report += f"

    Render {name}

    \n" cls.report += checker.report() markdown = checker.markdownReport() if markdown: - cls.markdown_report += "## {}\n\n".format(name) + cls.markdown_report += f"## {name}\n\n" cls.markdown_report += markdown return result @@ -313,9 +312,8 @@ def get_test_data_path(file_path: str) -> Path: """ from utilities import unitTestDataPath - return ( - Path(unitTestDataPath()) / - (file_path[1:] if file_path.startswith('/') else file_path) + return Path(unitTestDataPath()) / ( + file_path[1:] if file_path.startswith("/") else file_path ) def assertLayersEqual(self, layer_expected, layer_result, **kwargs): @@ -335,7 +333,9 @@ def assertLayersEqual(self, layer_expected, layer_result, **kwargs): """ self.checkLayersEqual(layer_expected, layer_result, True, **kwargs) - def checkLayersEqual(self, layer_expected, layer_result, use_asserts=False, **kwargs): + def checkLayersEqual( + self, layer_expected, layer_result, use_asserts=False, **kwargs + ): """ :param layer_expected: The first layer to compare :param layer_result: The second layer to compare @@ -354,23 +354,36 @@ def checkLayersEqual(self, layer_expected, layer_result, use_asserts=False, **kw """ try: - request = kwargs['request'] + request = kwargs["request"] except KeyError: request = QgsFeatureRequest() try: - compare = kwargs['compare'] + compare = kwargs["compare"] except KeyError: compare = {} # Compare CRS - if 'ignore_crs_check' not in compare or not compare['ignore_crs_check']: - expected_wkt = layer_expected.dataProvider().crs().toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED) - result_wkt = layer_result.dataProvider().crs().toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED) + if "ignore_crs_check" not in compare or not compare["ignore_crs_check"]: + expected_wkt = ( + layer_expected.dataProvider() + .crs() + .toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED) + ) + result_wkt = ( + layer_result.dataProvider() + .crs() + .toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED) + ) if use_asserts: - self.assertEqual(layer_expected.dataProvider().crs(), layer_result.dataProvider().crs()) - elif layer_expected.dataProvider().crs() != layer_result.dataProvider().crs(): + self.assertEqual( + layer_expected.dataProvider().crs(), + layer_result.dataProvider().crs(), + ) + elif ( + layer_expected.dataProvider().crs() != layer_result.dataProvider().crs() + ): return False # Compare features @@ -380,42 +393,42 @@ def checkLayersEqual(self, layer_expected, layer_result, use_asserts=False, **kw return False try: - precision = compare['geometry']['precision'] + precision = compare["geometry"]["precision"] except KeyError: precision = 14 try: - topo_equal_check = compare['geometry']['topo_equal_check'] + topo_equal_check = compare["geometry"]["topo_equal_check"] except KeyError: topo_equal_check = False try: - ignore_part_order = compare['geometry']['ignore_part_order'] + ignore_part_order = compare["geometry"]["ignore_part_order"] except KeyError: ignore_part_order = False try: - normalize = compare['geometry']['normalize'] + normalize = compare["geometry"]["normalize"] except KeyError: normalize = False try: - explode_collections = compare['geometry']['explode_collections'] + explode_collections = compare["geometry"]["explode_collections"] except KeyError: explode_collections = False try: - snap_to_grid = compare['geometry']['snap_to_grid'] + snap_to_grid = compare["geometry"]["snap_to_grid"] except KeyError: snap_to_grid = None try: - unordered = compare['unordered'] + unordered = compare["unordered"] except KeyError: unordered = False try: - equate_null_and_empty = compare['geometry']['equate_null_and_empty'] + equate_null_and_empty = compare["geometry"]["equate_null_and_empty"] except KeyError: equate_null_and_empty = False @@ -424,13 +437,22 @@ def checkLayersEqual(self, layer_expected, layer_result, use_asserts=False, **kw for feat in layer_result.getFeatures(request): feat_expected_equal = None for feat_expected in features_expected: - if self.checkGeometriesEqual(feat.geometry(), feat_expected.geometry(), - feat.id(), feat_expected.id(), - False, precision, topo_equal_check, ignore_part_order, normalize=normalize, - explode_collections=explode_collections, - snap_to_grid=snap_to_grid, - equate_null_and_empty=equate_null_and_empty) and \ - self.checkAttributesEqual(feat, feat_expected, layer_expected.fields(), False, compare): + if self.checkGeometriesEqual( + feat.geometry(), + feat_expected.geometry(), + feat.id(), + feat_expected.id(), + False, + precision, + topo_equal_check, + ignore_part_order, + normalize=normalize, + explode_collections=explode_collections, + snap_to_grid=snap_to_grid, + equate_null_and_empty=equate_null_and_empty, + ) and self.checkAttributesEqual( + feat, feat_expected, layer_expected.fields(), False, compare + ): feat_expected_equal = feat_expected break @@ -440,10 +462,15 @@ def checkLayersEqual(self, layer_expected, layer_result, use_asserts=False, **kw if use_asserts: self.assertTrue( False, - 'Unexpected result feature: fid {}, geometry: {}, attributes: {}'.format( + "Unexpected result feature: fid {}, geometry: {}, attributes: {}".format( feat.id(), - feat.geometry().constGet().asWkt(precision) if feat.geometry() else 'NULL', - feat.attributes()) + ( + feat.geometry().constGet().asWkt(precision) + if feat.geometry() + else "NULL" + ), + feat.attributes(), + ), ) else: return False @@ -452,24 +479,34 @@ def checkLayersEqual(self, layer_expected, layer_result, use_asserts=False, **kw if use_asserts: lst_missing = [] for feat in features_expected: - lst_missing.append('fid {}, geometry: {}, attributes: {}'.format( - feat.id(), - feat.geometry().constGet().asWkt(precision) if feat.geometry() else 'NULL', - feat.attributes()) + lst_missing.append( + "fid {}, geometry: {}, attributes: {}".format( + feat.id(), + ( + feat.geometry().constGet().asWkt(precision) + if feat.geometry() + else "NULL" + ), + feat.attributes(), + ) ) - self.assertTrue(False, 'Some expected features not found in results:\n' + '\n'.join(lst_missing)) + self.assertTrue( + False, + "Some expected features not found in results:\n" + + "\n".join(lst_missing), + ) else: return False return True def get_pk_or_fid(f): - if 'pk' in kwargs and kwargs['pk'] is not None: - key = kwargs['pk'] + if "pk" in kwargs and kwargs["pk"] is not None: + key = kwargs["pk"] if isinstance(key, list) or isinstance(key, tuple): return [f[k] for k in key] else: - return f[kwargs['pk']] + return f[kwargs["pk"]] else: return f.id() @@ -481,39 +518,53 @@ def sort_by_pk_or_fid(f): pk = [(v == NULL, v) for v in pk] return (pk == NULL, pk) - expected_features = sorted(layer_expected.getFeatures(request), key=sort_by_pk_or_fid) - result_features = sorted(layer_result.getFeatures(request), key=sort_by_pk_or_fid) + expected_features = sorted( + layer_expected.getFeatures(request), key=sort_by_pk_or_fid + ) + result_features = sorted( + layer_result.getFeatures(request), key=sort_by_pk_or_fid + ) for feats in zip(expected_features, result_features): - eq = self.checkGeometriesEqual(feats[0].geometry(), - feats[1].geometry(), - feats[0].id(), - feats[1].id(), - use_asserts, precision, topo_equal_check, ignore_part_order, normalize=normalize, explode_collections=explode_collections, - snap_to_grid=snap_to_grid, equate_null_and_empty=equate_null_and_empty) + eq = self.checkGeometriesEqual( + feats[0].geometry(), + feats[1].geometry(), + feats[0].id(), + feats[1].id(), + use_asserts, + precision, + topo_equal_check, + ignore_part_order, + normalize=normalize, + explode_collections=explode_collections, + snap_to_grid=snap_to_grid, + equate_null_and_empty=equate_null_and_empty, + ) if not eq and not use_asserts: return False - eq = self.checkAttributesEqual(feats[0], feats[1], layer_expected.fields(), use_asserts, compare) + eq = self.checkAttributesEqual( + feats[0], feats[1], layer_expected.fields(), use_asserts, compare + ) if not eq and not use_asserts: return False return True def checkFilesEqual(self, filepath_expected, filepath_result, use_asserts=False): - with open(filepath_expected, 'r') as file_expected: - with open(filepath_result, 'r') as file_result: + with open(filepath_expected) as file_expected: + with open(filepath_result) as file_result: diff = difflib.unified_diff( file_expected.readlines(), file_result.readlines(), - fromfile='expected', - tofile='result', + fromfile="expected", + tofile="result", ) diff = list(diff) eq = not len(diff) if use_asserts: - self.assertEqual(0, len(diff), ''.join(diff)) + self.assertEqual(0, len(diff), "".join(diff)) else: return eq @@ -529,8 +580,16 @@ def assertDirectoryEqual(self, dirpath_expected: str, dirpath_result: str): contents_result = list(path_result.iterdir()) contents_expected = list(path_expected.iterdir()) - contents_expected = [p for p in contents_expected if p.suffix != '.png' or not p.stem.endswith('_mask')] - self.assertCountEqual([p.name if p.is_file() else p.stem for p in contents_expected], [p.name if p.is_file() else p.stem for p in contents_result], f'Directory contents mismatch in {dirpath_expected} vs {dirpath_result}') + contents_expected = [ + p + for p in contents_expected + if p.suffix != ".png" or not p.stem.endswith("_mask") + ] + self.assertCountEqual( + [p.name if p.is_file() else p.stem for p in contents_expected], + [p.name if p.is_file() else p.stem for p in contents_result], + f"Directory contents mismatch in {dirpath_expected} vs {dirpath_result}", + ) # compare file contents for expected_file_path in contents_expected: @@ -539,23 +598,29 @@ def assertDirectoryEqual(self, dirpath_expected: str, dirpath_result: str): result_file_path = path_result / expected_file_path.name - if expected_file_path.suffix == '.pbf': + if expected_file_path.suffix == ".pbf": # vector layer, use assertLayersEqual - layer_expected = QgsVectorLayer(str(expected_file_path), 'Expected') + layer_expected = QgsVectorLayer(str(expected_file_path), "Expected") self.assertTrue(layer_expected.isValid()) - layer_result = QgsVectorLayer(str(result_file_path), 'Result') + layer_result = QgsVectorLayer(str(result_file_path), "Result") self.assertTrue(layer_result.isValid()) self.assertLayersEqual(layer_expected, layer_result) - elif expected_file_path.suffix == '.png': + elif expected_file_path.suffix == ".png": # image file, use QgsRenderChecker checker = QgsRenderChecker() - res = checker.compareImages(expected_file_path.stem, expected_file_path.as_posix(), result_file_path.as_posix()) + res = checker.compareImages( + expected_file_path.stem, + expected_file_path.as_posix(), + result_file_path.as_posix(), + ) self.assertTrue(res) else: - assert False, f"Don't know how to compare {expected_file_path.suffix} files" + assert ( + False + ), f"Don't know how to compare {expected_file_path.suffix} files" def assertDirectoriesEqual(self, dirpath_expected: str, dirpath_result: str): - """ Checks whether both directories have the same content (recursively) and raises an assertion error if not. """ + """Checks whether both directories have the same content (recursively) and raises an assertion error if not.""" self.assertDirectoryEqual(dirpath_expected, dirpath_result) # recurse through subfolders @@ -565,26 +630,70 @@ def assertDirectoriesEqual(self, dirpath_expected: str, dirpath_result: str): if p.is_dir(): self.assertDirectoriesEqual(str(p), path_result / p.stem) - def assertGeometriesEqual(self, geom0, geom1, geom0_id='geometry 1', geom1_id='geometry 2', precision=14, topo_equal_check=False, ignore_part_order=False, normalize=False, explode_collections=False, snap_to_grid=None, equate_null_and_empty=False): - self.checkGeometriesEqual(geom0, geom1, geom0_id, geom1_id, use_asserts=True, precision=precision, topo_equal_check=topo_equal_check, ignore_part_order=ignore_part_order, normalize=normalize, explode_collections=explode_collections, snap_to_grid=snap_to_grid, equate_null_and_empty=equate_null_and_empty) + def assertGeometriesEqual( + self, + geom0, + geom1, + geom0_id="geometry 1", + geom1_id="geometry 2", + precision=14, + topo_equal_check=False, + ignore_part_order=False, + normalize=False, + explode_collections=False, + snap_to_grid=None, + equate_null_and_empty=False, + ): + self.checkGeometriesEqual( + geom0, + geom1, + geom0_id, + geom1_id, + use_asserts=True, + precision=precision, + topo_equal_check=topo_equal_check, + ignore_part_order=ignore_part_order, + normalize=normalize, + explode_collections=explode_collections, + snap_to_grid=snap_to_grid, + equate_null_and_empty=equate_null_and_empty, + ) - def checkGeometriesEqual(self, geom0, geom1, geom0_id, geom1_id, use_asserts=False, precision=14, topo_equal_check=False, ignore_part_order=False, normalize=False, explode_collections=False, snap_to_grid=None, equate_null_and_empty=False): - """ Checks whether two geometries are the same - using either a strict check of coordinates (up to given precision) + def checkGeometriesEqual( + self, + geom0, + geom1, + geom0_id, + geom1_id, + use_asserts=False, + precision=14, + topo_equal_check=False, + ignore_part_order=False, + normalize=False, + explode_collections=False, + snap_to_grid=None, + equate_null_and_empty=False, + ): + """Checks whether two geometries are the same - using either a strict check of coordinates (up to given precision) or by using topological equality (where e.g. a polygon with clockwise is equal to a polygon with counter-clockwise order of vertices) .. versionadded:: 3.2 """ - geom0_wkt = '' - geom0_wkt_full = '' - geom1_wkt = '' - geom1_wkt_full = '' + geom0_wkt = "" + geom0_wkt_full = "" + geom1_wkt = "" + geom1_wkt_full = "" geom0_is_null = geom0.isNull() or (equate_null_and_empty and geom0.isEmpty()) geom1_is_null = geom1.isNull() or (equate_null_and_empty and geom1.isEmpty()) if not geom0_is_null and not geom1_is_null: if snap_to_grid is not None: - geom0 = geom0.snappedToGrid(snap_to_grid, snap_to_grid, snap_to_grid, snap_to_grid) - geom1 = geom1.snappedToGrid(snap_to_grid, snap_to_grid, snap_to_grid, snap_to_grid) + geom0 = geom0.snappedToGrid( + snap_to_grid, snap_to_grid, snap_to_grid, snap_to_grid + ) + geom1 = geom1.snappedToGrid( + snap_to_grid, snap_to_grid, snap_to_grid, snap_to_grid + ) if normalize: geom0.normalize() geom1.normalize() @@ -602,7 +711,9 @@ def checkGeometriesEqual(self, geom0, geom1, geom0_id, geom1_id, use_asserts=Fal if not equal and topo_equal_check: equal = geom0.isGeosEqual(geom1) if not equal and ignore_part_order and geom0.isMultipart(): - equal = sorted([p.asWkt(precision) for p in geom0.constParts()]) == sorted([p.asWkt(precision) for p in geom1.constParts()]) + equal = sorted( + [p.asWkt(precision) for p in geom0.constParts()] + ) == sorted([p.asWkt(precision) for p in geom1.constParts()]) elif geom0_is_null and geom1_is_null: equal = True else: @@ -614,90 +725,102 @@ def checkGeometriesEqual(self, geom0, geom1, geom0_id, geom1_id, use_asserts=Fal if use_asserts: self.assertTrue( - equal, '' - ' Features (Expected fid: {}, Result fid: {}) differ in geometry with method {}: \n\n' - ' At given precision ({}):\n' - ' Expected geometry: {}\n' - ' Result geometry: {}\n\n' - ' Full precision:\n' - ' Expected geometry : {}\n' - ' Result geometry: {}\n\n'.format( + equal, + "" + " Features (Expected fid: {}, Result fid: {}) differ in geometry with method {}: \n\n" + " At given precision ({}):\n" + " Expected geometry: {}\n" + " Result geometry: {}\n\n" + " Full precision:\n" + " Expected geometry : {}\n" + " Result geometry: {}\n\n".format( geom0_id, geom1_id, - 'geos' if topo_equal_check else 'wkt', + "geos" if topo_equal_check else "wkt", precision, - geom0_wkt if not geom0_is_null else 'NULL', - geom1_wkt if not geom1_is_null else 'NULL', - geom0_wkt_full if not geom0_is_null else 'NULL', - geom1_wkt_full if not geom1_is_null else 'NULL' - ) + geom0_wkt if not geom0_is_null else "NULL", + geom1_wkt if not geom1_is_null else "NULL", + geom0_wkt_full if not geom0_is_null else "NULL", + geom1_wkt_full if not geom1_is_null else "NULL", + ), ) else: return equal def checkAttributesEqual(self, feat0, feat1, fields_expected, use_asserts, compare): - """ Checks whether attributes of two features are the same + """Checks whether attributes of two features are the same .. versionadded:: 3.2 """ - for attr_expected, field_expected in zip(feat0.attributes(), fields_expected.toList()): + for attr_expected, field_expected in zip( + feat0.attributes(), fields_expected.toList() + ): try: - cmp = compare['fields'][field_expected.name()] + cmp = compare["fields"][field_expected.name()] except KeyError: try: - cmp = compare['fields']['__all__'] + cmp = compare["fields"]["__all__"] except KeyError: cmp = {} # Skip field - if 'skip' in cmp: + if "skip" in cmp: continue if use_asserts: self.assertIn( field_expected.name().lower(), - [name.lower() for name in feat1.fields().names()]) + [name.lower() for name in feat1.fields().names()], + ) attr_result = feat1[field_expected.name()] - field_result = [fld for fld in fields_expected.toList() if fld.name() == field_expected.name()][0] + field_result = [ + fld + for fld in fields_expected.toList() + if fld.name() == field_expected.name() + ][0] # Cast field to a given type isNumber = False - if 'cast' in cmp: - if cmp['cast'] == 'int': + if "cast" in cmp: + if cmp["cast"] == "int": attr_expected = int(attr_expected) if attr_expected else None attr_result = int(attr_result) if attr_result else None isNumber = True - if cmp['cast'] == 'float': + if cmp["cast"] == "float": attr_expected = float(attr_expected) if attr_expected else None attr_result = float(attr_result) if attr_result else None isNumber = True - if cmp['cast'] == 'str': + if cmp["cast"] == "str": if isinstance(attr_expected, QDateTime): - attr_expected = attr_expected.toString('yyyy/MM/dd hh:mm:ss') + attr_expected = attr_expected.toString("yyyy/MM/dd hh:mm:ss") elif isinstance(attr_expected, QDate): - attr_expected = attr_expected.toString('yyyy/MM/dd') + attr_expected = attr_expected.toString("yyyy/MM/dd") else: attr_expected = str(attr_expected) if attr_expected else None if isinstance(attr_result, QDateTime): - attr_result = attr_result.toString('yyyy/MM/dd hh:mm:ss') + attr_result = attr_result.toString("yyyy/MM/dd hh:mm:ss") elif isinstance(attr_result, QDate): - attr_result = attr_result.toString('yyyy/MM/dd') + attr_result = attr_result.toString("yyyy/MM/dd") else: attr_result = str(attr_result) if attr_result else None # Round field (only numeric so it works with __all__) - if 'precision' in cmp and (field_expected.type() in [QVariant.Int, QVariant.Double, QVariant.LongLong] or isNumber): + if "precision" in cmp and ( + field_expected.type() + in [QVariant.Int, QVariant.Double, QVariant.LongLong] + or isNumber + ): if not attr_expected == NULL: - attr_expected = round(attr_expected, cmp['precision']) + attr_expected = round(attr_expected, cmp["precision"]) if not attr_result == NULL: - attr_result = round(attr_result, cmp['precision']) + attr_result = round(attr_result, cmp["precision"]) if use_asserts: self.assertEqual( attr_expected, attr_result, - 'Features {}/{} differ in attributes\n\n * Field expected: {} ({})\n * result : {} ({})\n\n * Expected: {} != Result : {}'.format( + "Features {}/{} differ in attributes\n\n * Field expected: {} ({})\n * result : {} ({})\n\n * Expected: {} != Result : {}".format( feat0.id(), feat1.id(), field_expected.name(), @@ -705,8 +828,8 @@ def checkAttributesEqual(self, feat0, feat1, fields_expected, use_asserts, compa field_result.name(), field_result.typeName(), repr(attr_expected), - repr(attr_result) - ) + repr(attr_result), + ), ) elif attr_expected != attr_result: return False @@ -715,10 +838,10 @@ def checkAttributesEqual(self, feat0, feat1, fields_expected, use_asserts, compa class _UnexpectedSuccess(Exception): - """ The test was supposed to fail, but it didn't! """ + pass @@ -740,7 +863,7 @@ def my_test(self): def my_test(self): self.assertTrue(qgisIsInvented()) """ - if hasattr(args[0], '__call__'): + if hasattr(args[0], "__call__"): # We got a function as parameter: assume usage like # @expectedFailure # def testfunction(): @@ -754,6 +877,7 @@ def wrapper(*args, **kwargs): pass else: raise _UnexpectedSuccess + return wrapper else: # We got a function as parameter: assume usage like @@ -773,6 +897,7 @@ def wrapper(*args, **kwargs): raise _UnexpectedSuccess else: func(*args, **kwargs) + return wrapper return realExpectedFailure @@ -782,64 +907,100 @@ def wrapper(*args, **kwargs): def _deprecatedAssertLayersEqual(*args, **kwargs): - warn('unittest.TestCase.assertLayersEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning) + warn( + "unittest.TestCase.assertLayersEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`", + DeprecationWarning, + ) return QgisTestCase.assertLayersEqual(*args, **kwargs) def _deprecatedCheckLayersEqual(*args, **kwargs): - warn('unittest.TestCase.checkLayersEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning) + warn( + "unittest.TestCase.checkLayersEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`", + DeprecationWarning, + ) return QgisTestCase.checkLayersEqual(*args, **kwargs) def _deprecatedAssertFilesEqual(*args, **kwargs): - warn('unittest.TestCase.assertFilesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning) + warn( + "unittest.TestCase.assertFilesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`", + DeprecationWarning, + ) return QgisTestCase.assertFilesEqual(*args, **kwargs) def _deprecatedCheckFilesEqual(*args, **kwargs): - warn('unittest.TestCase.checkFilesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning) + warn( + "unittest.TestCase.checkFilesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`", + DeprecationWarning, + ) return QgisTestCase.checkFilesEqual(*args, **kwargs) def _deprecatedAssertDirectoryEqual(*args, **kwargs): - warn('unittest.TestCase.assertDirectoryEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning) + warn( + "unittest.TestCase.assertDirectoryEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`", + DeprecationWarning, + ) return QgisTestCase.assertDirectoryEqual(*args, **kwargs) def _deprecatedAssertDirectoriesEqual(*args, **kwargs): - warn('unittest.TestCase.assertDirectoriesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning) + warn( + "unittest.TestCase.assertDirectoriesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`", + DeprecationWarning, + ) return QgisTestCase.assertDirectoriesEqual(*args, **kwargs) def _deprecatedAssertGeometriesEqual(*args, **kwargs): - warn('unittest.TestCase.assertGeometriesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning) + warn( + "unittest.TestCase.assertGeometriesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`", + DeprecationWarning, + ) return QgisTestCase.assertGeometriesEqual(*args, **kwargs) def _deprecatedCheckGeometriesEqual(*args, **kwargs): - warn('unittest.TestCase.checkGeometriesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning) + warn( + "unittest.TestCase.checkGeometriesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`", + DeprecationWarning, + ) return QgisTestCase.checkGeometriesEqual(*args, **kwargs) def _deprecatedCheckAttributesEqual(*args, **kwargs): - warn('unittest.TestCase.checkAttributesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning) + warn( + "unittest.TestCase.checkAttributesEqual is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`", + DeprecationWarning, + ) return QgisTestCase.checkAttributesEqual(*args, **kwargs) def _deprecated_image_check(*args, **kwargs): - warn('unittest.TestCase.image_check is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning) + warn( + "unittest.TestCase.image_check is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`", + DeprecationWarning, + ) # Remove the first args element `self` which we don't need for a @classmethod return QgisTestCase.image_check(*args[1:], **kwargs) def _deprecated_render_map_settings_check(*args, **kwargs): - warn('unittest.TestCase.render_map_settings_check is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning) + warn( + "unittest.TestCase.render_map_settings_check is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`", + DeprecationWarning, + ) # Remove the first args element `self` which we don't need for a @classmethod return QgisTestCase.render_map_settings_check(*args[1:], **kwargs) def _deprecated_render_layout_check(*args, **kwargs): - warn('unittest.TestCase.render_layout_check is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`', DeprecationWarning) + warn( + "unittest.TestCase.render_layout_check is deprecated and will be removed in the future. Port your tests to `qgis.testing.TestCase`", + DeprecationWarning, + ) # Remove the first args element `self` which we don't need for a @classmethod return QgisTestCase.render_layout_check(*args[1:], **kwargs) @@ -890,7 +1051,7 @@ def start_app(cleanup=True): try: sys.argv except AttributeError: - sys.argv = [''] + sys.argv = [""] # In python3 we need to convert to a bytes object (or should # QgsApplication accept a QString instead of const char* ?) @@ -899,22 +1060,26 @@ def start_app(cleanup=True): except AttributeError: argvb = sys.argv - QCoreApplication.setAttribute(Qt.ApplicationAttribute.AA_ShareOpenGLContexts, True) + QCoreApplication.setAttribute( + Qt.ApplicationAttribute.AA_ShareOpenGLContexts, True + ) # Note: QGIS_PREFIX_PATH is evaluated in QgsApplication - # no need to mess with it here. QGISAPP = QgsApplication(argvb, myGuiFlag) - tmpdir = tempfile.mkdtemp('', 'QGIS-PythonTestConfigPath-') - os.environ['QGIS_CUSTOM_CONFIG_PATH'] = tmpdir + tmpdir = tempfile.mkdtemp("", "QGIS-PythonTestConfigPath-") + os.environ["QGIS_CUSTOM_CONFIG_PATH"] = tmpdir QGISAPP.initQgis() print(QGISAPP.showSettings()) def debug_log_message(message, tag, level): - print('{}({}): {}'.format(tag, level, message)) + print(f"{tag}({level}): {message}") - QgsApplication.instance().messageLog().messageReceived.connect(debug_log_message) + QgsApplication.instance().messageLog().messageReceived.connect( + debug_log_message + ) if cleanup: import atexit diff --git a/python/testing/mocked.py b/python/testing/mocked.py index b871d739f829..e94a0d62ab20 100644 --- a/python/testing/mocked.py +++ b/python/testing/mocked.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** mocked @@ -17,13 +15,13 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'January 2016' -__copyright__ = '(C) 2016, Matthias Kuhn' +__author__ = "Matthias Kuhn" +__date__ = "January 2016" +__copyright__ = "(C) 2016, Matthias Kuhn" import os import sys -import mock +from unittest import mock from qgis.gui import QgisInterface, QgsMapCanvas from qgis.core import QgsApplication diff --git a/python/user.py b/python/user.py index 49b0718bc832..fafbe530f272 100644 --- a/python/user.py +++ b/python/user.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** user.py @@ -17,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nathan Woodrow' -__date__ = 'January 2015' -__copyright__ = '(C) 2015, Nathan Woodrow' +__author__ = "Nathan Woodrow" +__date__ = "January 2015" +__copyright__ = "(C) 2015, Nathan Woodrow" import os import sys @@ -43,12 +41,16 @@ def load_user_expressions(path): # As user expression functions should be registered with qgsfunction # just importing the file is enough to get it to load the functions into QGIS try: - __import__("expressions.{0}".format(name), locals(), globals()) + __import__(f"expressions.{name}", locals(), globals()) except: error = traceback.format_exc() msgtitle = QCoreApplication.translate("UserExpressions", "User expressions") - msg = QCoreApplication.translate("UserExpressions", "The user expression {0} is not valid").format(name) - QgsMessageLog.logMessage(msg + "\n" + error, msgtitle, Qgis.MessageLevel.Warning) + msg = QCoreApplication.translate( + "UserExpressions", "The user expression {0} is not valid" + ).format(name) + QgsMessageLog.logMessage( + msg + "\n" + error, msgtitle, Qgis.MessageLevel.Warning + ) def reload_user_expressions(path): @@ -63,12 +65,12 @@ def reload_user_expressions(path): if name == "__init__": continue - mod = "expressions.{0}".format(name) + mod = f"expressions.{name}" if mod not in sys.modules: continue # try removing path - if hasattr(sys.modules[mod], '__path__'): + if hasattr(sys.modules[mod], "__path__"): for path in sys.modules[mod].__path__: try: sys.path.remove(path) diff --git a/python/utils.py b/python/utils.py index 0a27f68f0b02..45378ba7456c 100644 --- a/python/utils.py +++ b/python/utils.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ *************************************************************************** utils.py @@ -17,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Martin Dobias' -__date__ = 'November 2009' -__copyright__ = '(C) 2009, Martin Dobias' +__author__ = "Martin Dobias" +__date__ = "November 2009" +__copyright__ = "(C) 2009, Martin Dobias" """ QGIS utilities module @@ -27,7 +25,14 @@ """ from typing import List, Dict, Optional -from qgis.PyQt.QtCore import QT_VERSION_STR, QCoreApplication, QLocale, QThread, qDebug, QUrl +from qgis.PyQt.QtCore import ( + QT_VERSION_STR, + QCoreApplication, + QLocale, + QThread, + qDebug, + QUrl, +) from qgis.PyQt.QtGui import QDesktopServices from qgis.PyQt.QtWidgets import QPushButton, QApplication from qgis.core import Qgis, QgsMessageLog, qgsfunction, QgsMessageOutput @@ -45,44 +50,49 @@ import functools import builtins -builtins.__dict__['unicode'] = str -builtins.__dict__['basestring'] = str -builtins.__dict__['long'] = int -builtins.__dict__['Set'] = set + +builtins.__dict__["unicode"] = str +builtins.__dict__["basestring"] = str +builtins.__dict__["long"] = int +builtins.__dict__["Set"] = set # ###################### # ERROR HANDLING -warnings.simplefilter('default') +warnings.simplefilter("default") warnings.filterwarnings("ignore", "the sets module is deprecated") def showWarning(message, category, filename, lineno, file=None, line=None): stk = "" for s in traceback.format_stack()[:-2]: - if hasattr(s, 'decode'): + if hasattr(s, "decode"): stk += s.decode(sys.getfilesystemencoding()) else: stk += s - if hasattr(filename, 'decode'): + if hasattr(filename, "decode"): decoded_filename = filename.decode(sys.getfilesystemencoding()) else: decoded_filename = filename QgsMessageLog.logMessage( - "warning:{}\ntraceback:{}".format(warnings.formatwarning(message, category, decoded_filename, lineno), stk), - QCoreApplication.translate("Python", "Python warning") + f"warning:{warnings.formatwarning(message, category, decoded_filename, lineno)}\ntraceback:{stk}", + QCoreApplication.translate("Python", "Python warning"), ) -def showException(type, value, tb, msg, messagebar=False, level=Qgis.MessageLevel.Warning): +def showException( + type, value, tb, msg, messagebar=False, level=Qgis.MessageLevel.Warning +): if msg is None: - msg = QCoreApplication.translate('Python', 'An error has occurred while executing Python code:') + msg = QCoreApplication.translate( + "Python", "An error has occurred while executing Python code:" + ) - logmessage = '' + logmessage = "" for s in traceback.format_exception(type, value, tb): - logmessage += s.decode('utf-8', 'replace') if hasattr(s, 'decode') else s + logmessage += s.decode("utf-8", "replace") if hasattr(s, "decode") else s - title = QCoreApplication.translate('Python', 'Python error') + title = QCoreApplication.translate("Python", "Python error") QgsMessageLog.logMessage(logmessage, title, level) try: @@ -111,10 +121,23 @@ def showException(type, value, tb, msg, messagebar=False, level=Qgis.MessageLeve # Return of we already have a message with the same error message return - widget = bar.createMessage(title, msg + " " + QCoreApplication.translate("Python", "See message log (Python Error) for more details.")) + widget = bar.createMessage( + title, + msg + + " " + + QCoreApplication.translate( + "Python", "See message log (Python Error) for more details." + ), + ) widget.setProperty("Error", msg) - stackbutton = QPushButton(QCoreApplication.translate("Python", "Stack trace"), pressed=functools.partial(open_stack_dialog, type, value, tb, msg)) - button = QPushButton(QCoreApplication.translate("Python", "View message log"), pressed=show_message_log) + stackbutton = QPushButton( + QCoreApplication.translate("Python", "Stack trace"), + pressed=functools.partial(open_stack_dialog, type, value, tb, msg), + ) + button = QPushButton( + QCoreApplication.translate("Python", "View message log"), + pressed=show_message_log, + ) widget.layout().addWidget(stackbutton) widget.layout().addWidget(button) bar.pushWidget(widget, Qgis.MessageLevel.Warning) @@ -132,10 +155,12 @@ def open_stack_dialog(type, value, tb, msg, pop_error=True): iface.messageBar().popWidget() if msg is None: - msg = QCoreApplication.translate('Python', 'An error has occurred while executing Python code:') + msg = QCoreApplication.translate( + "Python", "An error has occurred while executing Python code:" + ) # TODO Move this to a template HTML file - txt = '''{msg} + txt = """{msg}

    {main_error}

    @@ -149,32 +174,36 @@ def open_stack_dialog(type, value, tb, msg, pop_error=True):
     

    {pypath_label}

      {pypath} -
    ''' +""" - error = '' + error = "" lst = traceback.format_exception(type, value, tb) for s in lst: - error += s.decode('utf-8', 'replace') if hasattr(s, 'decode') else s - error = error.replace('\n', '
    ') - - main_error = lst[-1].decode('utf-8', 'replace') if hasattr(lst[-1], 'decode') else lst[-1] - - version_label = QCoreApplication.translate('Python', 'Python version:') - qgis_label = QCoreApplication.translate('Python', 'QGIS version:') - pypath_label = QCoreApplication.translate('Python', 'Python Path:') - txt = txt.format(msg=msg, - main_error=main_error, - error=error, - version_label=version_label, - num=sys.version, - qgis_label=qgis_label, - qversion=Qgis.QGIS_VERSION, - qgisrelease=Qgis.QGIS_RELEASE_NAME, - devversion=Qgis.QGIS_DEV_VERSION, - pypath_label=pypath_label, - pypath="".join("
  • {}
  • ".format(path) for path in sys.path)) - - txt = txt.replace(' ', '  ') # preserve whitespaces for nicer output + error += s.decode("utf-8", "replace") if hasattr(s, "decode") else s + error = error.replace("\n", "
    ") + + main_error = ( + lst[-1].decode("utf-8", "replace") if hasattr(lst[-1], "decode") else lst[-1] + ) + + version_label = QCoreApplication.translate("Python", "Python version:") + qgis_label = QCoreApplication.translate("Python", "QGIS version:") + pypath_label = QCoreApplication.translate("Python", "Python Path:") + txt = txt.format( + msg=msg, + main_error=main_error, + error=error, + version_label=version_label, + num=sys.version, + qgis_label=qgis_label, + qversion=Qgis.QGIS_VERSION, + qgisrelease=Qgis.QGIS_RELEASE_NAME, + devversion=Qgis.QGIS_DEV_VERSION, + pypath_label=pypath_label, + pypath="".join(f"
  • {path}
  • " for path in sys.path), + ) + + txt = txt.replace(" ", "  ") # preserve whitespaces for nicer output dlg = QgsMessageOutput.createMessageOutput() dlg.setTitle(msg) @@ -184,7 +213,10 @@ def open_stack_dialog(type, value, tb, msg, pop_error=True): def qgis_excepthook(type, value, tb): # detect if running in the main thread - in_main_thread = QCoreApplication.instance() is None or QThread.currentThread() == QCoreApplication.instance().thread() + in_main_thread = ( + QCoreApplication.instance() is None + or QThread.currentThread() == QCoreApplication.instance().thread() + ) # only use messagebar if running in main thread - otherwise it will crash! showException(type, value, tb, None, messagebar=in_main_thread) @@ -245,14 +277,14 @@ def initInterface(pointer): def findPlugins(path): - """ for internal use: return list of plugins in given path """ + """for internal use: return list of plugins in given path""" for plugin in glob.glob(path + "/*"): if not os.path.isdir(plugin): continue - if not os.path.exists(os.path.join(plugin, '__init__.py')): + if not os.path.exists(os.path.join(plugin, "__init__.py")): continue - metadataFile = os.path.join(plugin, 'metadata.txt') + metadataFile = os.path.join(plugin, "metadata.txt") if not os.path.exists(metadataFile): continue @@ -274,7 +306,7 @@ def metadataParser() -> dict: def updateAvailablePlugins(sort_by_dependencies=False): - """ Go through the plugin_paths list and find out what plugins are available. """ + """Go through the plugin_paths list and find out what plugins are available.""" # merge the lists plugins = [] metadata_parser = {} @@ -286,16 +318,22 @@ def updateAvailablePlugins(sort_by_dependencies=False): if plugin_id not in plugins: plugins.append(plugin_id) metadata_parser[plugin_id] = parser - plugin_name_map[parser.get('general', 'name')] = plugin_id + plugin_name_map[parser.get("general", "name")] = plugin_id global plugins_metadata_parser plugins_metadata_parser = metadata_parser global available_plugins - available_plugins = _sortAvailablePlugins(plugins, plugin_name_map) if sort_by_dependencies else plugins + available_plugins = ( + _sortAvailablePlugins(plugins, plugin_name_map) + if sort_by_dependencies + else plugins + ) -def _sortAvailablePlugins(plugins: List[str], plugin_name_map: Dict[str, str]) -> List[str]: +def _sortAvailablePlugins( + plugins: list[str], plugin_name_map: dict[str, str] +) -> list[str]: """Place dependent plugins after their dependencies 1. Make a copy of plugins list to modify it. @@ -312,7 +350,7 @@ def _sortAvailablePlugins(plugins: List[str], plugin_name_map: Dict[str, str]) - deps = {} for plugin in plugins: - deps[plugin] = [plugin_name_map.get(dep, '') for dep in get_plugin_deps(plugin)] + deps[plugin] = [plugin_name_map.get(dep, "") for dep in get_plugin_deps(plugin)] for plugin in plugins: _move_plugin(plugin, deps, visited_plugins, sorted_plugins) @@ -320,7 +358,12 @@ def _sortAvailablePlugins(plugins: List[str], plugin_name_map: Dict[str, str]) - return sorted_plugins -def _move_plugin(plugin: str, deps: Dict[str, List[str]], visited: List[str], sorted_plugins: List[str]): +def _move_plugin( + plugin: str, + deps: dict[str, list[str]], + visited: list[str], + sorted_plugins: list[str], +): """Use recursion to move a plugin after its dependencies in a list of sorted plugins. @@ -361,17 +404,17 @@ def _move_plugin(plugin: str, deps: Dict[str, List[str]], visited: List[str], so sorted_plugins.insert(max_index, plugin) -def get_plugin_deps(plugin_id: str) -> Dict[str, Optional[str]]: +def get_plugin_deps(plugin_id: str) -> dict[str, Optional[str]]: result = {} try: parser = plugins_metadata_parser[plugin_id] - plugin_deps = parser.get('general', 'plugin_dependencies') + plugin_deps = parser.get("general", "plugin_dependencies") except (configparser.NoOptionError, configparser.NoSectionError, KeyError): return result - for dep in plugin_deps.split(','): - if dep.find('==') > 0: - name, version_required = dep.split('==') + for dep in plugin_deps.split(","): + if dep.find("==") > 0: + name, version_required = dep.split("==") else: name = dep version_required = None @@ -380,15 +423,15 @@ def get_plugin_deps(plugin_id: str) -> Dict[str, Optional[str]]: def pluginMetadata(packageName: str, fct: str) -> str: - """ fetch metadata from a plugin - use values from metadata.txt """ + """fetch metadata from a plugin - use values from metadata.txt""" try: - return plugins_metadata_parser[packageName].get('general', fct) + return plugins_metadata_parser[packageName].get("general", fct) except Exception: return "__error__" def loadPlugin(packageName: str) -> bool: - """ load plugin's package """ + """load plugin's package""" try: __import__(packageName) @@ -404,13 +447,22 @@ def loadPlugin(packageName: str) -> bool: __import__(packageName) return True except: - msg = QCoreApplication.translate("Python", "Couldn't load plugin '{0}'").format(packageName) - showException(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], msg, messagebar=True, level=Qgis.MessageLevel.Critical) + msg = QCoreApplication.translate("Python", "Couldn't load plugin '{0}'").format( + packageName + ) + showException( + sys.exc_info()[0], + sys.exc_info()[1], + sys.exc_info()[2], + msg, + messagebar=True, + level=Qgis.MessageLevel.Critical, + ) return False def _startPlugin(packageName: str) -> bool: - """ initializes a plugin, but does not load GUI """ + """initializes a plugin, but does not load GUI""" global plugins, active_plugins, iface, plugin_times if packageName in active_plugins: @@ -426,21 +478,32 @@ def _startPlugin(packageName: str) -> bool: plugins[packageName] = package.classFactory(iface) except: _unloadPluginModules(packageName) - errMsg = QCoreApplication.translate("Python", "Couldn't load plugin '{0}'").format(packageName) - msg = QCoreApplication.translate("Python", "{0} due to an error when calling its classFactory() method").format(errMsg) - showException(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], msg, messagebar=True, level=Qgis.MessageLevel.Critical) + errMsg = QCoreApplication.translate( + "Python", "Couldn't load plugin '{0}'" + ).format(packageName) + msg = QCoreApplication.translate( + "Python", "{0} due to an error when calling its classFactory() method" + ).format(errMsg) + showException( + sys.exc_info()[0], + sys.exc_info()[1], + sys.exc_info()[2], + msg, + messagebar=True, + level=Qgis.MessageLevel.Critical, + ) return False return True def _addToActivePlugins(packageName: str, duration: int): - """ Adds a plugin to the list of active plugins """ + """Adds a plugin to the list of active plugins""" active_plugins.append(packageName) - plugin_times[packageName] = "{0:02f}s".format(duration) + plugin_times[packageName] = f"{duration:02f}s" def startPlugin(packageName: str) -> bool: - """ initialize the plugin """ + """initialize the plugin""" global plugins, active_plugins, iface, plugin_times start = time.process_time() if not _startPlugin(packageName): @@ -452,9 +515,20 @@ def startPlugin(packageName: str) -> bool: except: del plugins[packageName] _unloadPluginModules(packageName) - errMsg = QCoreApplication.translate("Python", "Couldn't load plugin '{0}'").format(packageName) - msg = QCoreApplication.translate("Python", "{0} due to an error when calling its initGui() method").format(errMsg) - showException(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], msg, messagebar=True, level=Qgis.MessageLevel.Critical) + errMsg = QCoreApplication.translate( + "Python", "Couldn't load plugin '{0}'" + ).format(packageName) + msg = QCoreApplication.translate( + "Python", "{0} due to an error when calling its initGui() method" + ).format(errMsg) + showException( + sys.exc_info()[0], + sys.exc_info()[1], + sys.exc_info()[2], + msg, + messagebar=True, + level=Qgis.MessageLevel.Critical, + ) return False end = time.process_time() @@ -463,18 +537,29 @@ def startPlugin(packageName: str) -> bool: def startProcessingPlugin(packageName: str) -> bool: - """ initialize only the Processing components of a plugin """ + """initialize only the Processing components of a plugin""" global plugins, active_plugins, iface, plugin_times start = time.process_time() if not _startPlugin(packageName): return False - errMsg = QCoreApplication.translate("Python", "Couldn't load plugin '{0}'").format(packageName) - if not hasattr(plugins[packageName], 'initProcessing'): + errMsg = QCoreApplication.translate("Python", "Couldn't load plugin '{0}'").format( + packageName + ) + if not hasattr(plugins[packageName], "initProcessing"): del plugins[packageName] _unloadPluginModules(packageName) - msg = QCoreApplication.translate("Python", "{0} - plugin has no initProcessing() method").format(errMsg) - showException(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], msg, messagebar=True, level=Qgis.MessageLevel.Critical) + msg = QCoreApplication.translate( + "Python", "{0} - plugin has no initProcessing() method" + ).format(errMsg) + showException( + sys.exc_info()[0], + sys.exc_info()[1], + sys.exc_info()[2], + msg, + messagebar=True, + level=Qgis.MessageLevel.Critical, + ) return False # initProcessing @@ -483,8 +568,16 @@ def startProcessingPlugin(packageName: str) -> bool: except: del plugins[packageName] _unloadPluginModules(packageName) - msg = QCoreApplication.translate("Python", "{0} due to an error when calling its initProcessing() method").format(errMsg) - showException(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], msg, messagebar=True) + msg = QCoreApplication.translate( + "Python", "{0} due to an error when calling its initProcessing() method" + ).format(errMsg) + showException( + sys.exc_info()[0], + sys.exc_info()[1], + sys.exc_info()[2], + msg, + messagebar=True, + ) return False end = time.process_time() @@ -501,11 +594,11 @@ def finalizeProcessingStartup() -> bool: for every installed and enabled plugin. """ global plugins, active_plugins, iface, plugin_times - if 'processing' not in plugins: + if "processing" not in plugins: return False try: - plugins['processing'].finalizeStartup() + plugins["processing"].finalizeStartup() except: return False @@ -513,7 +606,7 @@ def finalizeProcessingStartup() -> bool: def canUninstallPlugin(packageName: str) -> bool: - """ confirm that the plugin can be uninstalled """ + """confirm that the plugin can be uninstalled""" global plugins, active_plugins if packageName not in plugins: @@ -528,12 +621,18 @@ def canUninstallPlugin(packageName: str) -> bool: return bool(metadata.canBeUninstalled()) except: msg = "Error calling " + packageName + ".canBeUninstalled" - showException(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], msg, messagebar=True) + showException( + sys.exc_info()[0], + sys.exc_info()[1], + sys.exc_info()[2], + msg, + messagebar=True, + ) return True def unloadPlugin(packageName: str) -> bool: - """ unload and delete plugin! """ + """unload and delete plugin!""" global plugins, active_plugins if packageName not in plugins: @@ -548,13 +647,21 @@ def unloadPlugin(packageName: str) -> bool: _unloadPluginModules(packageName) return True except Exception as e: - msg = QCoreApplication.translate("Python", "Error while unloading plugin {0}").format(packageName) - showException(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], msg, messagebar=True) + msg = QCoreApplication.translate( + "Python", "Error while unloading plugin {0}" + ).format(packageName) + showException( + sys.exc_info()[0], + sys.exc_info()[1], + sys.exc_info()[2], + msg, + messagebar=True, + ) return False def _unloadPluginModules(packageName: str): - """ unload plugin package with all its modules (files) """ + """unload plugin package with all its modules (files)""" global _plugin_modules if packageName not in _plugin_modules: @@ -570,14 +677,14 @@ def _unloadPluginModules(packageName: str): # otherwise we might experience a segfault next time the plugin is loaded # because Qt will try to access invalid plugin resource data try: - if hasattr(sys.modules[mod], 'qCleanupResources'): + if hasattr(sys.modules[mod], "qCleanupResources"): sys.modules[mod].qCleanupResources() except: # Print stack trace for debug qDebug("qCleanupResources error:\n%s" % traceback.format_exc()) # try removing path - if hasattr(sys.modules[mod], '__path__'): + if hasattr(sys.modules[mod], "__path__"): for path in sys.modules[mod].__path__: try: sys.path.remove(path) @@ -595,16 +702,16 @@ def _unloadPluginModules(packageName: str): def isPluginLoaded(packageName: str) -> bool: - """ find out whether a plugin is active (i.e. has been started) """ + """find out whether a plugin is active (i.e. has been started)""" global plugins, active_plugins if packageName not in plugins: return False - return (packageName in active_plugins) + return packageName in active_plugins def reloadPlugin(packageName: str) -> bool: - """ unload and start again a plugin """ + """unload and start again a plugin""" global active_plugins if packageName not in active_plugins: return False # it's not active @@ -651,7 +758,7 @@ def showPluginHelp(packageName: str = None, filename: str = "index", section: st def pluginDirectory(packageName: str) -> str: - """ return directory where the plugin resides. Plugin must be loaded already """ + """return directory where the plugin resides. Plugin must be loaded already""" return os.path.dirname(sys.modules[packageName].__file__) @@ -662,12 +769,15 @@ def reloadProjectMacros(): from qgis.core import QgsProject code, ok = QgsProject.instance().readEntry("Macros", "/pythonCode") - if not ok or not code or code == '': + if not ok or not code or code == "": return # create a new empty python module import importlib - mod = importlib.util.module_from_spec(importlib.machinery.ModuleSpec("proj_macros_mod", None)) + + mod = importlib.util.module_from_spec( + importlib.machinery.ModuleSpec("proj_macros_mod", None) + ) # set the module code and store it sys.modules exec(str(code), mod.__dict__) @@ -690,7 +800,7 @@ def openProjectMacro(): if "proj_macros_mod" not in sys.modules: return mod = sys.modules["proj_macros_mod"] - if hasattr(mod, 'openProject'): + if hasattr(mod, "openProject"): mod.openProject() @@ -698,7 +808,7 @@ def saveProjectMacro(): if "proj_macros_mod" not in sys.modules: return mod = sys.modules["proj_macros_mod"] - if hasattr(mod, 'saveProject'): + if hasattr(mod, "saveProject"): mod.saveProject() @@ -706,19 +816,22 @@ def closeProjectMacro(): if "proj_macros_mod" not in sys.modules: return mod = sys.modules["proj_macros_mod"] - if hasattr(mod, 'closeProject'): + if hasattr(mod, "closeProject"): mod.closeProject() ####################### + def _list_project_expression_functions(): - """ Get a list of expression functions stored in the current project """ + """Get a list of expression functions stored in the current project""" import ast from qgis.core import QgsProject functions = [] - project_functions, ok = QgsProject.instance().readEntry("ExpressionFunctions", "/pythonCode") + project_functions, ok = QgsProject.instance().readEntry( + "ExpressionFunctions", "/pythonCode" + ) if ok and project_functions: code = ast.parse(project_functions) @@ -741,6 +854,7 @@ def clean_project_expression_functions(): project_functions = _list_project_expression_functions() if project_functions: from qgis.core import QgsExpression + for function in project_functions: QgsExpression.unregisterFunction(function) @@ -775,13 +889,14 @@ def clean_project_expression_functions(): def initServerInterface(pointer): from qgis.server import QgsServerInterface from sip import wrapinstance + sys.excepthook = sys.__excepthook__ global serverIface serverIface = wrapinstance(pointer, QgsServerInterface) def startServerPlugin(packageName: str): - """ initialize the plugin """ + """initialize the plugin""" global server_plugins, server_active_plugins, serverIface if packageName in server_active_plugins: @@ -791,15 +906,18 @@ def startServerPlugin(packageName: str): package = sys.modules[packageName] - errMsg = QCoreApplication.translate("Python", "Couldn't load server plugin {0}").format(packageName) + errMsg = QCoreApplication.translate( + "Python", "Couldn't load server plugin {0}" + ).format(packageName) # create an instance of the plugin try: server_plugins[packageName] = package.serverClassFactory(serverIface) except: _unloadPluginModules(packageName) - msg = QCoreApplication.translate("Python", - "{0} due to an error when calling its serverClassFactory() method").format(errMsg) + msg = QCoreApplication.translate( + "Python", "{0} due to an error when calling its serverClassFactory() method" + ).format(errMsg) showException(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], msg) return False @@ -810,7 +928,7 @@ def startServerPlugin(packageName: str): def spatialite_connect(*args, **kwargs): """returns a dbapi2.Connection to a SpatiaLite db -using the "mod_spatialite" extension (python3)""" + using the "mod_spatialite" extension (python3)""" import sqlite3 import re @@ -827,12 +945,12 @@ def fcnRegexp(pattern, string): # SpatiaLite >= 4.2 and Sqlite < 3.7.17 (Travis) ("mod_spatialite.so", "sqlite3_modspatialite_init"), # SpatiaLite < 4.2 (linux) - ("libspatialite.so", "sqlite3_extension_init") + ("libspatialite.so", "sqlite3_extension_init"), ] found = False for lib, entry_point in libs: try: - cur.execute("select load_extension('{}', '{}')".format(lib, entry_point)) + cur.execute(f"select load_extension('{lib}', '{entry_point}')") except sqlite3.OperationalError: continue else: @@ -840,12 +958,14 @@ def fcnRegexp(pattern, string): break if not found: raise RuntimeError("Cannot find any suitable spatialite module") - if any(['.gpkg' in arg for arg in args]): + if any([".gpkg" in arg for arg in args]): try: cur.execute("SELECT EnableGpkgAmphibiousMode()") except (sqlite3.Error, sqlite3.DatabaseError, sqlite3.NotSupportedError): - QgsMessageLog.logMessage("warning:{}".format("Could not enable geopackage amphibious mode"), - QCoreApplication.translate("Python", "Python warning")) + QgsMessageLog.logMessage( + "warning:{}".format("Could not enable geopackage amphibious mode"), + QCoreApplication.translate("Python", "Python warning"), + ) cur.close() con.enable_load_extension(False) @@ -853,7 +973,7 @@ def fcnRegexp(pattern, string): return con -class OverrideCursor(): +class OverrideCursor: """ Executes a code block with a different cursor set and makes sure the cursor is restored even if exceptions are raised or an intermediate ``return`` @@ -880,15 +1000,15 @@ def __exit__(self, exc_type, exc_val, exc_tb): ####################### # IMPORT wrapper -if os.name == 'nt' and sys.version_info < (3, 8): +if os.name == "nt" and sys.version_info < (3, 8): import ctypes from ctypes import windll, wintypes - kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) + kernel32 = ctypes.WinDLL("kernel32", use_last_error=True) - _hasAddDllDirectory = hasattr(kernel32, 'AddDllDirectory') + _hasAddDllDirectory = hasattr(kernel32, "AddDllDirectory") if _hasAddDllDirectory: - _import_path = os.environ['PATH'] + _import_path = os.environ["PATH"] _import_paths = {} def _errcheck_zero(result, func, args): @@ -910,10 +1030,12 @@ def _errcheck_zero(result, func, args): _uses_builtins = True try: import builtins + _builtin_import = builtins.__import__ except AttributeError: _uses_builtins = False import __builtin__ + _builtin_import = __builtin__.__import__ _plugin_modules = {} @@ -927,37 +1049,49 @@ def _import(name, globals={}, locals={}, fromlist=[], level=None): if level is None: level = 0 - if 'PyQt4' in name: - msg = 'PyQt4 classes cannot be imported in QGIS 3.x.\n' \ - 'Use {} or preferably the version independent {} import instead.'.format(name.replace('PyQt4', 'PyQt5'), name.replace('PyQt4', 'qgis.PyQt')) + if "PyQt4" in name: + msg = ( + "PyQt4 classes cannot be imported in QGIS 3.x.\n" + "Use {} or preferably the version independent {} import instead.".format( + name.replace("PyQt4", "PyQt5"), name.replace("PyQt4", "qgis.PyQt") + ) + ) raise ImportError(msg) - qt_version = int(QT_VERSION_STR.split('.')[0]) - if qt_version == 5 and 'PyQt6' in name: - msg = 'PyQt6 classes cannot be imported in a QGIS build based on Qt5.\n' \ - 'Use {} or preferably the version independent {} import instead (where available).'.format(name.replace('PyQt6', 'PyQt5'), name.replace('PyQt6', 'qgis.PyQt')) + qt_version = int(QT_VERSION_STR.split(".")[0]) + if qt_version == 5 and "PyQt6" in name: + msg = ( + "PyQt6 classes cannot be imported in a QGIS build based on Qt5.\n" + "Use {} or preferably the version independent {} import instead (where available).".format( + name.replace("PyQt6", "PyQt5"), name.replace("PyQt6", "qgis.PyQt") + ) + ) raise ImportError(msg) - elif qt_version == 6 and 'PyQt5' in name: - msg = 'PyQt5 classes cannot be imported in a QGIS build based on Qt6.\n' \ - 'Use {} or preferably the version independent {} import instead (where available).'.format(name.replace('PyQt5', 'PyQt6'), name.replace('PyQt5', 'qgis.PyQt')) + elif qt_version == 6 and "PyQt5" in name: + msg = ( + "PyQt5 classes cannot be imported in a QGIS build based on Qt6.\n" + "Use {} or preferably the version independent {} import instead (where available).".format( + name.replace("PyQt5", "PyQt6"), name.replace("PyQt5", "qgis.PyQt") + ) + ) raise ImportError(msg) - if os.name == 'nt' and sys.version_info < (3, 8): + if os.name == "nt" and sys.version_info < (3, 8): global _hasAddDllDirectory if _hasAddDllDirectory: global _import_path global _import_paths old_path = _import_path - new_path = os.environ['PATH'] + new_path = os.environ["PATH"] if old_path != new_path: global _AddDllDirectory global _RemoveDllDirectory - for p in set(new_path.split(';')) - set(old_path.split(';')): + for p in set(new_path.split(";")) - set(old_path.split(";")): if p is not None and p not in _import_path and os.path.isdir(p): _import_paths[p] = _AddDllDirectory(p) - for p in set(old_path.split(';')) - set(new_path.split(';')): + for p in set(old_path.split(";")) - set(new_path.split(";")): if p in _import_paths: _RemoveDllDirectory(_import_paths.pop(p)) @@ -965,9 +1099,9 @@ def _import(name, globals={}, locals={}, fromlist=[], level=None): mod = _builtin_import(name, globals, locals, fromlist, level) - if mod and getattr(mod, '__file__', None): + if mod and getattr(mod, "__file__", None): module_name = mod.__name__ if fromlist else name - package_name = module_name.split('.')[0] + package_name = module_name.split(".")[0] # check whether the module belongs to one of our plugins if package_name in available_plugins: if package_name not in _plugin_modules: @@ -983,7 +1117,7 @@ def _import(name, globals={}, locals={}, fromlist=[], level=None): return mod -if not os.environ.get('QGIS_NO_OVERRIDE_IMPORT'): +if not os.environ.get("QGIS_NO_OVERRIDE_IMPORT"): if _uses_builtins: builtins.__import__ = _import else: @@ -1013,20 +1147,34 @@ def processing_algorithm_from_script(filepath: str): alg_instance = None try: - from qgis.core import QgsApplication, QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm - _locals = { - '__file__': filename - } + from qgis.core import ( + QgsApplication, + QgsProcessingAlgorithm, + QgsProcessingFeatureBasedAlgorithm, + ) + + _locals = {"__file__": filename} with open(filename.encode(sys.getfilesystemencoding())) as input_file: - code_object = compile(input_file.read(), filename, 'exec') + code_object = compile(input_file.read(), filename, "exec") exec(code_object, _locals) alg_instance = None try: alg_instance = alg.instances.pop().createInstance() except IndexError: for name, attr in _locals.items(): - if inspect.isclass(attr) and issubclass(attr, (QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm)) and attr.__name__ not in ("QgsProcessingAlgorithm", "QgsProcessingFeatureBasedAlgorithm"): + if ( + inspect.isclass(attr) + and issubclass( + attr, + (QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm), + ) + and attr.__name__ + not in ( + "QgsProcessingAlgorithm", + "QgsProcessingFeatureBasedAlgorithm", + ) + ): alg_instance = attr() break @@ -1059,6 +1207,7 @@ def import_script_algorithm(filepath: str) -> Optional[str]: alg_instance = processing_algorithm_from_script(filepath) if alg_instance: from qgis.core import QgsApplication + script_provider = QgsApplication.processingRegistry().providerById("script") script_provider.add_algorithm_class(type(alg_instance)) return alg_instance.id() diff --git a/scripts/2to3 b/scripts/2to3 index 01b6d9c9944e..db82ef2b246b 100755 --- a/scripts/2to3 +++ b/scripts/2to3 @@ -1,7 +1,8 @@ #!/usr/bin/env python3 -import sys, os +import os +import sys from lib2to3.main import main sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__)))) -sys.exit(main('qgis_fixes')) +sys.exit(main("qgis_fixes")) diff --git a/scripts/appinfo2ui.py b/scripts/appinfo2ui.py index c12cffcb7e52..48af6bae35fb 100644 --- a/scripts/appinfo2ui.py +++ b/scripts/appinfo2ui.py @@ -19,19 +19,24 @@ """ import sys -from xml.etree import ElementTree as et + from html import escape +from xml.etree import ElementTree as et strings = {} -d = et.parse('linux/org.qgis.qgis.appdata.xml.in') +d = et.parse("linux/org.qgis.qgis.appdata.xml.in") r = d.getroot() -for elem in ['name', 'summary', 'description']: +for elem in ["name", "summary", "description"]: for c in r.iter(elem): if not c.attrib: l = list(c) - t = c.text if not l else "".join([et.tostring(x).decode("utf-8") for x in l]) + t = ( + c.text + if not l + else "".join([et.tostring(x).decode("utf-8") for x in l]) + ) strings[t] = 1 f = open("linux/org.qgis.qgis.desktop.in") @@ -45,7 +50,8 @@ f.close() -print("""\ +print( + """\ appinfo; -""") +""" +) for k in strings: print(f"{escape(k)}") diff --git a/scripts/doxygen_space.py b/scripts/doxygen_space.py index 73ec171eda9d..987ef39bca97 100755 --- a/scripts/doxygen_space.py +++ b/scripts/doxygen_space.py @@ -15,17 +15,16 @@ # (at your option) any later version. # # # ########################################################################### -import sys import re +import sys def exit_with_error(message): - sys.exit( - f"! Doxygen formatting error: {message}") + sys.exit(f"! Doxygen formatting error: {message}") def process_file(file_path): - with open(file_path, 'r') as file: + with open(file_path) as file: input_lines = file.readlines() output = [] @@ -34,19 +33,19 @@ def process_file(file_path): previous_was_blankline = False previous_was_dox_blankline = False just_finished_a_list = False - buffered_line = '' + buffered_line = "" i = 0 while i < len(input_lines): line = input_lines[i].rstrip() is_blank_line = not line.strip() - if re.match(r'^\s*(?:#ifdef|#ifndef|#else|#endif)', line): + if re.match(r"^\s*(?:#ifdef|#ifndef|#else|#endif)", line): output.append(line) i += 1 continue - if match := re.match(r'^(\s*)/\*[*!]\s*([^\s*].*)\s*$', line): + if match := re.match(r"^(\s*)/\*[*!]\s*([^\s*].*)\s*$", line): # Convert blocks starting with /*! format to /** standard, # and convert # /**Some docs @@ -54,73 +53,89 @@ def process_file(file_path): # /** # * Some docs indent, content = match.groups() - output.append(f'{indent}/**') - line = f'{indent} * {content[0].upper()}{content[1:]}' + output.append(f"{indent}/**") + line = f"{indent} * {content[0].upper()}{content[1:]}" - if match := re.match(r'^(.*)/\*[!*](?!\*)(<*)[ \t\r\n\f]*(.*?)[ \t\r\n\f]*\*/[ \t\r\n\f]*$', line): + if match := re.match( + r"^(.*)/\*[!*](?!\*)(<*)[ \t\r\n\f]*(.*?)[ \t\r\n\f]*\*/[ \t\r\n\f]*$", line + ): # Convert single line doxygen blocks: # /*!< comment */ to //!< comment # /** comment */ to //! comment prefix, tag, content = match.groups() - line = f'{prefix}//!{tag} {content}' + line = f"{prefix}//!{tag} {content}" - if match := re.match(r'^(.*)//!<\s*(.)(.*)$', line): + if match := re.match(r"^(.*)//!<\s*(.)(.*)$", line): # Uppercase initial character in //!< comment prefix, first, remaining = match.groups() - line = f'{prefix}//!< {first.upper()}{remaining}' + line = f"{prefix}//!< {first.upper()}{remaining}" - if match := re.match(r'^(.*)\\param ([\w_]+)\s+[:,.-]\s*(.*?)$', line): + if match := re.match(r"^(.*)\\param ([\w_]+)\s+[:,.-]\s*(.*?)$", line): # Standardize \param prefix, param, suffix = match.groups() - line = f'{prefix}\\param {param} {suffix}' + line = f"{prefix}\\param {param} {suffix}" - if '//!<' in line and (match := re.match(r'^(.*)\.\s*[Ss]ince (?:QGIS )?(\d+\.\d+(?:\.\d+)?)[.]?$', line)): + if "//!<" in line and ( + match := re.match( + r"^(.*)\.\s*[Ss]ince (?:QGIS )?(\d+\.\d+(?:\.\d+)?)[.]?$", line + ) + ): # Use \since annotation prefix, version = match.groups() - line = f'{prefix} \\since QGIS {version}' + line = f"{prefix} \\since QGIS {version}" - if '//!<' in line and (match := re.match(r'^(.*?)\s*\([Ss]ince (?:QGIS )?(\d+\.\d+(?:\.\d+)?)[.)]+$', line)): + if "//!<" in line and ( + match := re.match( + r"^(.*?)\s*\([Ss]ince (?:QGIS )?(\d+\.\d+(?:\.\d+)?)[.)]+$", line + ) + ): # Use \since annotation prefix, version = match.groups() - line = f'{prefix} \\since QGIS {version}' + line = f"{prefix} \\since QGIS {version}" - if match := re.match(r'^(.*)\\since (?:QGIS )?(\d+\.\d+(?:\.\d+)?)[.]?$', line): + if match := re.match(r"^(.*)\\since (?:QGIS )?(\d+\.\d+(?:\.\d+)?)[.]?$", line): # Standard since annotation prefix, version = match.groups() - line = f'{prefix}\\since QGIS {version}' + line = f"{prefix}\\since QGIS {version}" - if match := re.match(r'^(.*)\\deprecated[,.:]? (?:[dD]eprecated )?(?:[sS]ince )?(?:QGIS )?(\d+\.\d+(?:\.\d+)?)[,\s.\-]*(.*?)$', line): + if match := re.match( + r"^(.*)\\deprecated[,.:]? (?:[dD]eprecated )?(?:[sS]ince )?(?:QGIS )?(\d+\.\d+(?:\.\d+)?)[,\s.\-]*(.*?)$", + line, + ): # Standardize deprecated annotation prefix, version, suffix = match.groups() if suffix: - if suffix.startswith('('): - if suffix.endswith(')'): + if suffix.startswith("("): + if suffix.endswith(")"): suffix = suffix[1:-1] - elif suffix.endswith(').'): + elif suffix.endswith(")."): suffix = suffix[1:-2] suffix = suffix[0].upper() + suffix[1:] - if not suffix.endswith('.'): + if not suffix.endswith("."): suffix += "." - line = f'{prefix}\\deprecated QGIS {version}. {suffix}' + line = f"{prefix}\\deprecated QGIS {version}. {suffix}" else: - line = f'{prefix}\\deprecated QGIS {version}' - elif re.match(r'^(.*)\\deprecated', line): - exit_with_error("\\deprecated MUST be followed by the correct version number, eg 'QGIS 3.40'") + line = f"{prefix}\\deprecated QGIS {version}" + elif re.match(r"^(.*)\\deprecated", line): + exit_with_error( + "\\deprecated MUST be followed by the correct version number, eg 'QGIS 3.40'" + ) - if match := re.match(r'^(\s*)//!\s*(.*?)$', line): + if match := re.match(r"^(\s*)//!\s*(.*?)$", line): indentation, comment = match.groups() # found a //! comment # check next line to see if it also begins with //! - if i + 1 < len(input_lines) and re.match(r'^\s*//!\s*(.*?)$', - input_lines[i + 1]): + if i + 1 < len(input_lines) and re.match( + r"^\s*//!\s*(.*?)$", input_lines[i + 1] + ): # we are in a multiline //! comment block, convert to /** block if not previous_was_blankline: - output.append('') + output.append("") output.append(f"{indentation}/**") output.append(f"{indentation} * {comment}") while i + 1 < len(input_lines) and ( - next_match := re.match(r'^\s*//!\s*(.*?)$', - input_lines[i + 1])): + next_match := re.match(r"^\s*//!\s*(.*?)$", input_lines[i + 1]) + ): next_comment = next_match.group(1) if next_comment: output.append(f"{indentation} * {next_comment}") @@ -132,9 +147,9 @@ def process_file(file_path): output.append(line) elif inside_dox_block: # replace "* abc" style doxygen lists with correct "- abc" formatting - line = re.sub(r'^(\s+)\*\s{1,10}\*', r'\1* -', line) + line = re.sub(r"^(\s+)\*\s{1,10}\*", r"\1* -", line) - if re.match(r'^\s*\*\s*$', line): + if re.match(r"^\s*\*\s*$", line): previous_was_dox_blankline = True if inside_dox_list: inside_dox_list = False @@ -143,8 +158,7 @@ def process_file(file_path): # print("end list") else: output.append(line) - elif match := re.match(r'^(\s*)\*\s*-(?![-\d>]) *(.*)$', - line): + elif match := re.match(r"^(\s*)\*\s*-(?![-\d>]) *(.*)$", line): indent, content = match.groups() if not inside_dox_list and not previous_was_dox_blankline: output.append(f"{indent}*") @@ -155,34 +169,34 @@ def process_file(file_path): output.append(f"{indent}* - {content}") inside_dox_list = True just_finished_a_list = False - elif inside_dox_list and ( - match := re.match(r'^(\s*)\*\s{2,}(.*)$', line)): + elif inside_dox_list and (match := re.match(r"^(\s*)\*\s{2,}(.*)$", line)): # print("list continuation") indent, content = match.groups() output.append(f"{indent}* {content}") - elif inside_dox_list and (match := re.match(r'^(\s*)\*(?!/)', line)): + elif inside_dox_list and (match := re.match(r"^(\s*)\*(?!/)", line)): inside_dox_list = False indent = match.group(1) # print("end list without line break") output.append(f"{indent}*") output.append(line) just_finished_a_list = True - elif re.match(r'^(\s*)\*/\s*$', line): + elif re.match(r"^(\s*)\*/\s*$", line): inside_dox_block = False inside_dox_list = False just_finished_a_list = False if buffered_line: output.append(buffered_line) - buffered_line = '' + buffered_line = "" output.append(line) # print("end_block") else: if buffered_line: output.append(buffered_line) - buffered_line = '' + buffered_line = "" - if not re.match(r'^\s*[#*]', line) and ( - match := re.match(r'^(\s*?)(\s?)(.+?)$', line)): + if not re.match(r"^\s*[#*]", line) and ( + match := re.match(r"^(\s*?)(\s?)(.+?)$", line) + ): indent, space, content = match.groups() line = f"{indent}* {content}" @@ -190,11 +204,11 @@ def process_file(file_path): # print("normal dox") previous_was_dox_blankline = False just_finished_a_list = False - elif (match := re.match(r'^(\s*)/\*\*(?!\*)\s*(.*)$', line)): + elif match := re.match(r"^(\s*)/\*\*(?!\*)\s*(.*)$", line): indent, content = match.groups() # Space around doxygen start blocks (force blank line before /**) if not previous_was_blankline: - output.append('') + output.append("") if content: # new line after /** begin block output.append(f"{indent}/**") @@ -206,14 +220,14 @@ def process_file(file_path): else: if buffered_line: output.append(buffered_line) - buffered_line = '' + buffered_line = "" output.append(line) i += 1 previous_was_blankline = is_blank_line - with open(file_path, 'w') as file: - file.write('\n'.join(output) + '\n') + with open(file_path, "w") as file: + file.write("\n".join(output) + "\n") if __name__ == "__main__": diff --git a/scripts/dump_babel_formats.py b/scripts/dump_babel_formats.py index 44e544cfe29c..c3a2762ccf95 100644 --- a/scripts/dump_babel_formats.py +++ b/scripts/dump_babel_formats.py @@ -21,12 +21,12 @@ Dumps a list of babel formats for inclusion in QgsBabelFormatRegistry::QgsBabelFormatRegistry() """ -__author__ = 'Nyall Dawson' -__date__ = 'July 2021' -__copyright__ = '(C) 2021, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "July 2021" +__copyright__ = "(C) 2021, Nyall Dawson" -import subprocess import re +import subprocess def process_lines(lines): @@ -38,25 +38,33 @@ def process_lines(lines): while current_line < len(lines): line = lines[current_line] - fields = line.split('\t') + fields = line.split("\t") assert len(fields) >= 5, fields current_line += 1 html_pages = [] - while lines[current_line].startswith('http'): + while lines[current_line].startswith("http"): html_pages.append(lines[current_line]) current_line += 1 - while current_line < len(lines) and lines[current_line].startswith('option'): - options = lines[current_line].split('\t') + while current_line < len(lines) and lines[current_line].startswith("option"): + options = lines[current_line].split("\t") assert len(options) >= 9, options - name, description, option_type, option_def, option_min, option_max, option_html = options[:7] + ( + name, + description, + option_type, + option_def, + option_min, + option_max, + option_html, + ) = options[:7] # print(name, description, option_type, option_def, option_min, option_max, option_html) option_http_pages = [] current_line += 1 - while current_line < len(lines) and lines[current_line].startswith('http'): + while current_line < len(lines) and lines[current_line].startswith("http"): option_http_pages.append(lines[current_line]) current_line += 1 @@ -64,31 +72,42 @@ def process_lines(lines): description = fields[4] # remove odd comment from description! - description = description.replace(' [ Get Jonathon Johnson to describe', '') - - read_waypoints = fields[1][0] == 'r' - read_tracks = fields[1][2] == 'r' - read_routes = fields[1][4] == 'r' - write_waypoints = fields[1][1] == 'w' - write_tracks = fields[1][3] == 'w' - write_routes = fields[1][5] == 'w' - is_file_format = fields[0] == 'file' - is_device_format = fields[0] == 'serial' - extensions = fields[3].split('/') + description = description.replace(" [ Get Jonathon Johnson to describe", "") + + read_waypoints = fields[1][0] == "r" + read_tracks = fields[1][2] == "r" + read_routes = fields[1][4] == "r" + write_waypoints = fields[1][1] == "w" + write_tracks = fields[1][3] == "w" + write_routes = fields[1][5] == "w" + is_file_format = fields[0] == "file" + is_device_format = fields[0] == "serial" + extensions = fields[3].split("/") if is_file_format and any([read_routes, read_tracks, read_waypoints]): capabilities = [] if read_waypoints: - capabilities.append('Qgis::BabelFormatCapability::Waypoints') + capabilities.append("Qgis::BabelFormatCapability::Waypoints") if read_routes: - capabilities.append('Qgis::BabelFormatCapability::Routes') + capabilities.append("Qgis::BabelFormatCapability::Routes") if read_tracks: - capabilities.append('Qgis::BabelFormatCapability::Tracks') - capabilities_string = ' | '.join(capabilities) - - extensions_string = '{' + ', '.join([f'QStringLiteral( "{ext.strip()}" )' for ext in extensions if ext.strip()]) + '}' - format_out[ - name] = f'mImporters[QStringLiteral( "{name}" )] = new QgsBabelSimpleImportFormat( QStringLiteral( "{name}" ), QStringLiteral( "{description}" ), {capabilities_string}, {extensions_string} );' + capabilities.append("Qgis::BabelFormatCapability::Tracks") + capabilities_string = " | ".join(capabilities) + + extensions_string = ( + "{" + + ", ".join( + [ + f'QStringLiteral( "{ext.strip()}" )' + for ext in extensions + if ext.strip() + ] + ) + + "}" + ) + format_out[name] = ( + f'mImporters[QStringLiteral( "{name}" )] = new QgsBabelSimpleImportFormat( QStringLiteral( "{name}" ), QStringLiteral( "{description}" ), {capabilities_string}, {extensions_string} );' + ) for format_name in sorted(format_out.keys(), key=lambda x: x.lower()): print(format_out[format_name]) diff --git a/scripts/generate_test_mask_image.py b/scripts/generate_test_mask_image.py index 180f156b30a2..968c49d6b4d1 100755 --- a/scripts/generate_test_mask_image.py +++ b/scripts/generate_test_mask_image.py @@ -17,24 +17,25 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'February 2015' -__copyright__ = '(C) 2015, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "February 2015" +__copyright__ = "(C) 2015, Nyall Dawson" # Generates (or updates) a unit test image mask, which is used to specify whether # a pixel in the control image should be checked (black pixel in mask) or not (white # pixel in mask). For non black or white pixels, the pixels lightness is used to # specify a maximum delta for each color component -import os -import sys import argparse -from PyQt5.QtGui import QImage, QColor, qRed, qBlue, qGreen, qAlpha, qRgb +import glob +import os import struct -import urllib.request +import sys import urllib.error import urllib.parse -import glob +import urllib.request + +from PyQt5.QtGui import QColor, QImage, qAlpha, qBlue, qGreen, qRed, qRgb def error(msg): @@ -51,7 +52,7 @@ def colorDiff(c1, c2): def imageFromPath(path): - if (path[:7] == 'http://' or path[:7] == 'file://' or path[:8] == 'https://'): + if path[:7] == "http://" or path[:7] == "file://" or path[:8] == "https://": # fetch remote image data = urllib.request.urlopen(path).read() image = QImage() @@ -67,42 +68,53 @@ def getControlImagePath(path): # else try and find matching test image script_folder = os.path.dirname(os.path.realpath(sys.argv[0])) - control_images_folder = os.path.join(script_folder, '../tests/testdata/control_images') + control_images_folder = os.path.join( + script_folder, "../tests/testdata/control_images" + ) - matching_control_images = [x[0] for x in os.walk(control_images_folder) if path in x[0]] + matching_control_images = [ + x[0] for x in os.walk(control_images_folder) if path in x[0] + ] if len(matching_control_images) > 1: - error(f'Found multiple matching control images for {path}') + error(f"Found multiple matching control images for {path}") elif len(matching_control_images) == 0: - error(f'No matching control images found for {path}') + error(f"No matching control images found for {path}") found_control_image_path = matching_control_images[0] # check for a single matching expected image - images = glob.glob(os.path.join(found_control_image_path, '*.png')) - filtered_images = [i for i in images if not i[-9:] == '_mask.png'] + images = glob.glob(os.path.join(found_control_image_path, "*.png")) + filtered_images = [i for i in images if not i[-9:] == "_mask.png"] if len(filtered_images) > 1: - error(f'Found multiple matching control images for {path}') + error(f"Found multiple matching control images for {path}") elif len(filtered_images) == 0: - error(f'No matching control images found for {path}') + error(f"No matching control images found for {path}") found_image = filtered_images[0] - print(f'Found matching control image: {found_image}') + print(f"Found matching control image: {found_image}") return found_image def updateMask(control_image_path, rendered_image_path, mask_image_path): control_image = imageFromPath(control_image_path) if not control_image: - error(f'Could not read control image {control_image_path}') + error(f"Could not read control image {control_image_path}") rendered_image = imageFromPath(rendered_image_path) if not rendered_image: - error(f'Could not read rendered image {rendered_image_path}') - if not rendered_image.width() == control_image.width() or not rendered_image.height() == control_image.height(): - print('Size mismatch - control image is {}x{}, rendered image is {}x{}'.format(control_image.width(), - control_image.height(), - rendered_image.width(), - rendered_image.height())) + error(f"Could not read rendered image {rendered_image_path}") + if ( + not rendered_image.width() == control_image.width() + or not rendered_image.height() == control_image.height() + ): + print( + "Size mismatch - control image is {}x{}, rendered image is {}x{}".format( + control_image.width(), + control_image.height(), + rendered_image.width(), + rendered_image.height(), + ) + ) max_width = min(rendered_image.width(), control_image.width()) max_height = min(rendered_image.height(), control_image.height()) @@ -110,8 +122,10 @@ def updateMask(control_image_path, rendered_image_path, mask_image_path): # read current mask, if it exist mask_image = imageFromPath(mask_image_path) if mask_image.isNull(): - print(f'Mask image does not exist, creating {mask_image_path}') - mask_image = QImage(control_image.width(), control_image.height(), QImage.Format.Format_ARGB32) + print(f"Mask image does not exist, creating {mask_image_path}") + mask_image = QImage( + control_image.width(), control_image.height(), QImage.Format.Format_ARGB32 + ) mask_image.fill(QColor(0, 0, 0)) # loop through pixels in rendered image and compare @@ -123,14 +137,16 @@ def updateMask(control_image_path, rendered_image_path, mask_image_path): mask_scanline = mask_image.scanLine(y).asstring(linebytes) for x in range(max_width): - currentTolerance = qRed(struct.unpack('I', mask_scanline[x * 4:x * 4 + 4])[0]) + currentTolerance = qRed( + struct.unpack("I", mask_scanline[x * 4 : x * 4 + 4])[0] + ) if currentTolerance == 255: # ignore pixel continue - expected_rgb = struct.unpack('I', control_scanline[x * 4:x * 4 + 4])[0] - rendered_rgb = struct.unpack('I', rendered_scanline[x * 4:x * 4 + 4])[0] + expected_rgb = struct.unpack("I", control_scanline[x * 4 : x * 4 + 4])[0] + rendered_rgb = struct.unpack("I", rendered_scanline[x * 4 : x * 4 + 4])[0] difference = colorDiff(expected_rgb, rendered_rgb) if difference > currentTolerance: @@ -141,20 +157,22 @@ def updateMask(control_image_path, rendered_image_path, mask_image_path): if mismatch_count: # update mask mask_image.save(mask_image_path, "png") - print(f'Updated {mismatch_count} pixels in {mask_image_path}') + print(f"Updated {mismatch_count} pixels in {mask_image_path}") else: - print(f'No mismatches in {mask_image_path}') + print(f"No mismatches in {mask_image_path}") -parser = argparse.ArgumentParser() # OptionParser("usage: %prog control_image rendered_image mask_image") -parser.add_argument('control_image') -parser.add_argument('rendered_image') -parser.add_argument('mask_image', nargs='?', default=None) +parser = ( + argparse.ArgumentParser() +) # OptionParser("usage: %prog control_image rendered_image mask_image") +parser.add_argument("control_image") +parser.add_argument("rendered_image") +parser.add_argument("mask_image", nargs="?", default=None) args = parser.parse_args() args.control_image = getControlImagePath(args.control_image) if not args.mask_image: - args.mask_image = args.control_image[:-4] + '_mask.png' + args.mask_image = args.control_image[:-4] + "_mask.png" updateMask(args.control_image, args.rendered_image, args.mask_image) diff --git a/scripts/includemocs.py b/scripts/includemocs.py index a917511ec060..9c35fd5e8622 100644 --- a/scripts/includemocs.py +++ b/scripts/includemocs.py @@ -15,9 +15,9 @@ # pylint: disable=redefined-outer-name +import argparse import os import re -import argparse import sys dirty = False @@ -38,11 +38,11 @@ def shouldExclude(root, path): return False # No excludes provided assert root.startswith(args.root) - root = stripInitialSlash(root[len(args.root):]) + root = stripInitialSlash(root[len(args.root) :]) if args.headerPrefix: assert root.startswith(args.headerPrefix) - root = stripInitialSlash(root[len(args.headerPrefix):]) + root = stripInitialSlash(root[len(args.headerPrefix) :]) return (path in args.excludes) or (root + "/" + path in args.excludes) @@ -52,7 +52,7 @@ def shouldExclude(root, path): def hasMacro(fileName): - with open(fileName, "r", encoding="ISO-8859-1") as fileHandle: + with open(fileName, encoding="ISO-8859-1") as fileHandle: for line in fileHandle: if regexp.match(line): return True @@ -64,11 +64,11 @@ def hasMacro(fileName): def matchingCPPFile(root, fileName): assert root.startswith(args.root) - root = stripInitialSlash(root[len(args.root):]) + root = stripInitialSlash(root[len(args.root) :]) if args.headerPrefix: assert root.startswith(args.headerPrefix) - root = stripInitialSlash(root[len(args.headerPrefix):]) + root = stripInitialSlash(root[len(args.headerPrefix) :]) if args.sourcePrefix: root = args.sourcePrefix + "/" + root @@ -112,7 +112,7 @@ def trimExistingMocInclude(content, cppFileName): ) match = mocStrRegex.search(content) if match: - return content[: match.start()] + content[match.end():] + return content[: match.start()] + content[match.end() :] return content @@ -143,7 +143,7 @@ def processFile(root, fileName): else: log("Updating %s" % cppFileName) - with open(cppFileName, "r", encoding="utf8") as f: + with open(cppFileName, encoding="utf8") as f: content = f.read() if args.replaceExisting: diff --git a/scripts/mkuidefaults.py b/scripts/mkuidefaults.py index bbad6eba19cf..f1b67c4be6c5 100755 --- a/scripts/mkuidefaults.py +++ b/scripts/mkuidefaults.py @@ -17,19 +17,19 @@ *************************************************************************** """ -__author__ = 'Juergen E. Fischer' -__date__ = 'June 2013' -__copyright__ = '(C) 2013, Juergen E. Fischer' +__author__ = "Juergen E. Fischer" +__date__ = "June 2013" +__copyright__ = "(C) 2013, Juergen E. Fischer" -import sys import struct +import sys from PyQt5.QtCore import QCoreApplication, QSettings def chunks(l, n): for i in range(0, len(l), n): - yield l[i:i + n] + yield l[i : i + n] QCoreApplication.setOrganizationName("QGIS") @@ -37,7 +37,7 @@ def chunks(l, n): QCoreApplication.setApplicationName("QGIS3") if len(sys.argv) == 1: - print("Usage: ./scripts/mkuidefaults.py \"location_to_ini\"") + print('Usage: ./scripts/mkuidefaults.py "location_to_ini"') sys.exit(1) s = QSettings(sys.argv[1], QSettings.Format.IniFormat) @@ -46,40 +46,57 @@ def chunks(l, n): with open("src/app/ui_defaults.h", "w") as f: - f.write("#ifndef UI_DEFAULTS_H\n#define UI_DEFAULTS_H\n" + - "\nstatic const unsigned char defaultUIgeometry[] =\n{\n") + f.write( + "#ifndef UI_DEFAULTS_H\n#define UI_DEFAULTS_H\n" + + "\nstatic const unsigned char defaultUIgeometry[] =\n{\n" + ) for chunk in chunks(ba, 16): - f.write(' {},\n'.format( - ', '.join(map(hex, struct.unpack('B' * len(chunk), chunk))))) + f.write( + " {},\n".format( + ", ".join(map(hex, struct.unpack("B" * len(chunk), chunk))) + ) + ) f.write("};\n\nstatic const unsigned char defaultUIstate[] =\n{\n") ba = bytes(s.value("/UI/state")) for chunk in chunks(ba, 16): - f.write(' {},\n'.format( - ', '.join(map(hex, struct.unpack('B' * len(chunk), chunk))))) + f.write( + " {},\n".format( + ", ".join(map(hex, struct.unpack("B" * len(chunk), chunk))) + ) + ) try: ba = bytes(s.value("/app/LayoutDesigner/geometry")) - f.write("};\n\nstatic const unsigned char " + - "defaultLayerDesignerUIgeometry[] =\n{\n") + f.write( + "};\n\nstatic const unsigned char " + + "defaultLayerDesignerUIgeometry[] =\n{\n" + ) for chunk in chunks(ba, 16): - f.write(' {},\n'.format( - ', '.join(map(hex, struct.unpack('B' * len(chunk), chunk))))) + f.write( + " {},\n".format( + ", ".join(map(hex, struct.unpack("B" * len(chunk), chunk))) + ) + ) except TypeError as ex: pass try: ba = bytes(s.value("/app/LayoutDesigner/state")) - f.write("};\n\nstatic const unsigned char " + - "defaultLayerDesignerUIstate[] =\n{\n") + f.write( + "};\n\nstatic const unsigned char " + "defaultLayerDesignerUIstate[] =\n{\n" + ) for chunk in chunks(ba, 16): - f.write(' {},\n'.format( - ', '.join(map(hex, struct.unpack('B' * len(chunk), chunk))))) + f.write( + " {},\n".format( + ", ".join(map(hex, struct.unpack("B" * len(chunk), chunk))) + ) + ) except TypeError as ex: pass diff --git a/scripts/parse_dash_results.py b/scripts/parse_dash_results.py index 4b06578d9f4e..cdd49a3a748c 100755 --- a/scripts/parse_dash_results.py +++ b/scripts/parse_dash_results.py @@ -17,43 +17,46 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'October 2016' -__copyright__ = '(C) 2016, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "October 2016" +__copyright__ = "(C) 2016, Nyall Dawson" +import argparse +import glob +import json import os +import re +import struct import sys -import argparse -import urllib.request -import urllib.parse import urllib.error -import re -import json -from PyQt5.QtCore import (Qt) -from PyQt5.QtGui import ( - QImage, QColor, qRed, qBlue, qGreen, qAlpha, qRgb, QPixmap) -from PyQt5.QtWidgets import (QDialog, - QApplication, - QLabel, - QVBoxLayout, - QHBoxLayout, - QGridLayout, - QPushButton, - QDoubleSpinBox, - QWidget, - QScrollArea, - QLayout, - QDialogButtonBox, - QListWidget) +import urllib.parse +import urllib.request + import termcolor -import struct -import glob -dash_url = 'https://cdash.orfeo-toolbox.org' +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QColor, QImage, QPixmap, qAlpha, qBlue, qGreen, qRed, qRgb +from PyQt5.QtWidgets import ( + QApplication, + QDialog, + QDialogButtonBox, + QDoubleSpinBox, + QGridLayout, + QHBoxLayout, + QLabel, + QLayout, + QListWidget, + QPushButton, + QScrollArea, + QVBoxLayout, + QWidget, +) + +dash_url = "https://cdash.orfeo-toolbox.org" def error(msg): - print(termcolor.colored(msg, 'red')) + print(termcolor.colored(msg, "red")) sys.exit(1) @@ -66,14 +69,14 @@ def colorDiff(c1, c2): def imageFromPath(path): - if (path[:8] == 'https://' or path[:7] == 'file://'): + if path[:8] == "https://" or path[:7] == "file://": # fetch remote image - print(f'Fetching remote ({path})') + print(f"Fetching remote ({path})") data = urllib.request.urlopen(path).read() image = QImage() image.loadFromData(data) else: - print(f'Using local ({path})') + print(f"Using local ({path})") image = QImage(path) return image @@ -83,15 +86,19 @@ class SelectReferenceImageDialog(QDialog): def __init__(self, parent, test_name, images): super().__init__(parent) - self.setWindowTitle('Select reference image') + self.setWindowTitle("Select reference image") self.setWindowFlags(Qt.WindowType.Window) - self.button_box = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) + self.button_box = QDialogButtonBox( + QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel + ) self.button_box.accepted.connect(self.accept) self.button_box.rejected.connect(self.reject) layout = QVBoxLayout() - layout.addWidget(QLabel(f'Found multiple matching reference images for {test_name}')) + layout.addWidget( + QLabel(f"Found multiple matching reference images for {test_name}") + ) self.list = QListWidget() layout.addWidget(self.list, 1) @@ -110,7 +117,7 @@ class ResultHandler(QDialog): def __init__(self, parent=None): super().__init__(parent) - self.setWindowTitle('Dash results') + self.setWindowTitle("Dash results") self.setWindowFlags(Qt.WindowType.Window) self.control_label = QLabel() self.rendered_label = QLabel() @@ -125,14 +132,14 @@ def __init__(self, parent=None): self.test_name_label = QLabel() grid = QGridLayout() grid.addWidget(self.test_name_label, 0, 0) - grid.addWidget(QLabel('Control'), 1, 0) - grid.addWidget(QLabel('Rendered'), 1, 1) - grid.addWidget(QLabel('Difference'), 1, 2) + grid.addWidget(QLabel("Control"), 1, 0) + grid.addWidget(QLabel("Rendered"), 1, 1) + grid.addWidget(QLabel("Difference"), 1, 2) grid.addWidget(self.control_label, 2, 0) grid.addWidget(self.rendered_label, 2, 1) grid.addWidget(self.diff_label, 2, 2) - grid.addWidget(QLabel('Current Mask'), 3, 0) - grid.addWidget(QLabel('New Mask'), 3, 1) + grid.addWidget(QLabel("Current Mask"), 3, 0) + grid.addWidget(QLabel("New Mask"), 3, 1) grid.addWidget(self.mask_label, 4, 0) grid.addWidget(self.new_mask_label, 4, 1) grid.setSizeConstraint(QLayout.SizeConstraint.SetFixedSize) @@ -143,31 +150,33 @@ def __init__(self, parent=None): v_layout.addWidget(self.scrollArea, 1) next_image_button = QPushButton() - next_image_button.setText('Skip') + next_image_button.setText("Skip") next_image_button.pressed.connect(self.load_next) self.overload_spin = QDoubleSpinBox() self.overload_spin.setMinimum(1) self.overload_spin.setMaximum(255) self.overload_spin.setValue(1) - self.overload_spin.valueChanged.connect(lambda: save_mask_button.setEnabled(False)) + self.overload_spin.valueChanged.connect( + lambda: save_mask_button.setEnabled(False) + ) preview_mask_button = QPushButton() - preview_mask_button.setText('Preview New Mask') + preview_mask_button.setText("Preview New Mask") preview_mask_button.pressed.connect(self.preview_mask) preview_mask_button.pressed.connect(lambda: save_mask_button.setEnabled(True)) save_mask_button = QPushButton() - save_mask_button.setText('Save New Mask') + save_mask_button.setText("Save New Mask") save_mask_button.pressed.connect(self.save_mask) add_ref_image_button = QPushButton() - add_ref_image_button.setText('Add Reference Image') + add_ref_image_button.setText("Add Reference Image") add_ref_image_button.pressed.connect(self.add_reference_image) button_layout = QHBoxLayout() button_layout.addWidget(next_image_button) - button_layout.addWidget(QLabel('Mask diff multiplier:')) + button_layout.addWidget(QLabel("Mask diff multiplier:")) button_layout.addWidget(self.overload_spin) button_layout.addWidget(preview_mask_button) button_layout.addWidget(save_mask_button) @@ -181,27 +190,39 @@ def closeEvent(self, event): def parse_url(self, url): parts = urllib.parse.urlsplit(url) - apiurl = urllib.parse.urlunsplit((parts.scheme, parts.netloc, '/api/v1/testDetails.php', parts.query, parts.fragment)) - print(f'Fetching dash results from api: {apiurl}') + apiurl = urllib.parse.urlunsplit( + ( + parts.scheme, + parts.netloc, + "/api/v1/testDetails.php", + parts.query, + parts.fragment, + ) + ) + print(f"Fetching dash results from api: {apiurl}") page = urllib.request.urlopen(apiurl) - content = json.loads(page.read().decode('utf-8')) + content = json.loads(page.read().decode("utf-8")) # build up list of rendered images - measurement_img = [img for img in content['test']['images'] if img['role'].startswith('Rendered Image')] + measurement_img = [ + img + for img in content["test"]["images"] + if img["role"].startswith("Rendered Image") + ] images = {} for img in measurement_img: - m = re.search(r'Rendered Image (.*?)(\s|$)', img['role']) + m = re.search(r"Rendered Image (.*?)(\s|$)", img["role"]) test_name = m.group(1) - rendered_image = 'displayImage.php?imgid={}'.format(img['imgid']) - images[test_name] = f'{dash_url}/{rendered_image}' + rendered_image = "displayImage.php?imgid={}".format(img["imgid"]) + images[test_name] = f"{dash_url}/{rendered_image}" if images: - print('Found images:\n') + print("Found images:\n") for title, url in images.items(): - print(' ' + termcolor.colored(title, attrs=['bold']) + ' : ' + url) + print(" " + termcolor.colored(title, attrs=["bold"]) + " : " + url) else: - print(termcolor.colored('No images found\n', 'yellow')) + print(termcolor.colored("No images found\n", "yellow")) self.images = images self.load_next() @@ -213,49 +234,53 @@ def load_next(self): test_name, rendered_image = self.images.popitem() self.test_name_label.setText(test_name) - print(termcolor.colored('\n' + test_name, attrs=['bold'])) + print(termcolor.colored("\n" + test_name, attrs=["bold"])) control_image = self.get_control_image_path(test_name) if not control_image: self.load_next() return - self.mask_image_path = control_image[:-4] + '_mask.png' + self.mask_image_path = control_image[:-4] + "_mask.png" self.load_images(control_image, rendered_image, self.mask_image_path) def load_images(self, control_image_path, rendered_image_path, mask_image_path): self.control_image = imageFromPath(control_image_path) if not self.control_image: - error(f'Could not read control image {control_image_path}') + error(f"Could not read control image {control_image_path}") self.rendered_image = imageFromPath(rendered_image_path) if not self.rendered_image: - error( - f'Could not read rendered image {rendered_image_path}') - if not self.rendered_image.width() == self.control_image.width() or not self.rendered_image.height() == self.control_image.height(): + error(f"Could not read rendered image {rendered_image_path}") + if ( + not self.rendered_image.width() == self.control_image.width() + or not self.rendered_image.height() == self.control_image.height() + ): print( - 'Size mismatch - control image is {}x{}, rendered image is {}x{}'.format(self.control_image.width(), - self.control_image.height( - ), - self.rendered_image.width( - ), - self.rendered_image.height())) - - max_width = min( - self.rendered_image.width(), self.control_image.width()) - max_height = min( - self.rendered_image.height(), self.control_image.height()) + "Size mismatch - control image is {}x{}, rendered image is {}x{}".format( + self.control_image.width(), + self.control_image.height(), + self.rendered_image.width(), + self.rendered_image.height(), + ) + ) + + max_width = min(self.rendered_image.width(), self.control_image.width()) + max_height = min(self.rendered_image.height(), self.control_image.height()) # read current mask, if it exist self.mask_image = imageFromPath(mask_image_path) if self.mask_image.isNull(): - print( - f'Mask image does not exist, creating {mask_image_path}') + print(f"Mask image does not exist, creating {mask_image_path}") self.mask_image = QImage( - self.control_image.width(), self.control_image.height(), QImage.Format.Format_ARGB32) + self.control_image.width(), + self.control_image.height(), + QImage.Format.Format_ARGB32, + ) self.mask_image.fill(QColor(0, 0, 0)) self.diff_image = self.create_diff_image( - self.control_image, self.rendered_image, self.mask_image) + self.control_image, self.rendered_image, self.mask_image + ) if not self.diff_image: self.load_next() return @@ -272,7 +297,11 @@ def load_images(self, control_image_path, rendered_image_path, mask_image_path): def preview_mask(self): self.new_mask_image = self.create_mask( - self.control_image, self.rendered_image, self.mask_image, self.overload_spin.value()) + self.control_image, + self.rendered_image, + self.mask_image, + self.overload_spin.value(), + ) self.new_mask_label.setPixmap(QPixmap.fromImage(self.new_mask_image)) self.new_mask_label.setFixedSize(self.new_mask_image.size()) @@ -281,20 +310,24 @@ def save_mask(self): self.load_next() def add_reference_image(self): - if os.path.abspath(self.control_images_base_path) == os.path.abspath(self.found_control_image_path): - images = glob.glob(os.path.join(self.found_control_image_path, '*.png')) - default_path = os.path.join(self.found_control_image_path, 'set1') + if os.path.abspath(self.control_images_base_path) == os.path.abspath( + self.found_control_image_path + ): + images = glob.glob(os.path.join(self.found_control_image_path, "*.png")) + default_path = os.path.join(self.found_control_image_path, "set1") os.makedirs(default_path) for image in images: imgname = os.path.basename(image) os.rename(image, os.path.join(default_path, imgname)) for i in range(2, 100): - new_path = os.path.join(self.control_images_base_path, 'set' + str(i)) + new_path = os.path.join(self.control_images_base_path, "set" + str(i)) if not os.path.exists(new_path): break else: - raise RuntimeError('Could not find a suitable directory for another set of reference images') + raise RuntimeError( + "Could not find a suitable directory for another set of reference images" + ) os.makedirs(new_path) control_image_name = os.path.basename(self.found_image) @@ -306,44 +339,50 @@ def create_mask(self, control_image, rendered_image, mask_image, overload=1): max_height = min(rendered_image.height(), control_image.height()) new_mask_image = QImage( - control_image.width(), control_image.height(), QImage.Format.Format_ARGB32) + control_image.width(), control_image.height(), QImage.Format.Format_ARGB32 + ) new_mask_image.fill(QColor(0, 0, 0)) # loop through pixels in rendered image and compare mismatch_count = 0 linebytes = max_width * 4 for y in range(max_height): - control_scanline = control_image.constScanLine( - y).asstring(linebytes) - rendered_scanline = rendered_image.constScanLine( - y).asstring(linebytes) + control_scanline = control_image.constScanLine(y).asstring(linebytes) + rendered_scanline = rendered_image.constScanLine(y).asstring(linebytes) mask_scanline = mask_image.scanLine(y).asstring(linebytes) for x in range(max_width): currentTolerance = qRed( - struct.unpack('I', mask_scanline[x * 4:x * 4 + 4])[0]) + struct.unpack("I", mask_scanline[x * 4 : x * 4 + 4])[0] + ) if currentTolerance == 255: # ignore pixel new_mask_image.setPixel( - x, y, qRgb(currentTolerance, currentTolerance, currentTolerance)) + x, y, qRgb(currentTolerance, currentTolerance, currentTolerance) + ) continue - expected_rgb = struct.unpack( - 'I', control_scanline[x * 4:x * 4 + 4])[0] - rendered_rgb = struct.unpack( - 'I', rendered_scanline[x * 4:x * 4 + 4])[0] + expected_rgb = struct.unpack("I", control_scanline[x * 4 : x * 4 + 4])[ + 0 + ] + rendered_rgb = struct.unpack("I", rendered_scanline[x * 4 : x * 4 + 4])[ + 0 + ] difference = min( - 255, int(colorDiff(expected_rgb, rendered_rgb) * overload)) + 255, int(colorDiff(expected_rgb, rendered_rgb) * overload) + ) if difference > currentTolerance: # update mask image new_mask_image.setPixel( - x, y, qRgb(difference, difference, difference)) + x, y, qRgb(difference, difference, difference) + ) mismatch_count += 1 else: new_mask_image.setPixel( - x, y, qRgb(currentTolerance, currentTolerance, currentTolerance)) + x, y, qRgb(currentTolerance, currentTolerance, currentTolerance) + ) return new_mask_image def get_control_image_path(self, test_name): @@ -353,16 +392,20 @@ def get_control_image_path(self, test_name): # else try and find matching test image script_folder = os.path.dirname(os.path.realpath(sys.argv[0])) control_images_folder = os.path.join( - script_folder, '../tests/testdata/control_images') + script_folder, "../tests/testdata/control_images" + ) - matching_control_images = [x[0] - for x in os.walk(control_images_folder) if test_name + '/' in x[0] or x[0].endswith(test_name)] + matching_control_images = [ + x[0] + for x in os.walk(control_images_folder) + if test_name + "/" in x[0] or x[0].endswith(test_name) + ] self.control_images_base_path = os.path.commonprefix(matching_control_images) if len(matching_control_images) > 1: for item in matching_control_images: - print(' - ' + item) + print(" - " + item) dlg = SelectReferenceImageDialog(self, test_name, matching_control_images) if not dlg.exec(): @@ -370,22 +413,25 @@ def get_control_image_path(self, test_name): self.found_control_image_path = dlg.selected_image() elif len(matching_control_images) == 0: - print(termcolor.colored(f'No matching control images found for {test_name}', 'yellow')) + print( + termcolor.colored( + f"No matching control images found for {test_name}", "yellow" + ) + ) return None else: self.found_control_image_path = matching_control_images[0] # check for a single matching expected image - images = glob.glob(os.path.join(self.found_control_image_path, '*.png')) - filtered_images = [i for i in images if not i[-9:] == '_mask.png'] + images = glob.glob(os.path.join(self.found_control_image_path, "*.png")) + filtered_images = [i for i in images if not i[-9:] == "_mask.png"] if len(filtered_images) > 1: - error( - f'Found multiple matching control images for {test_name}') + error(f"Found multiple matching control images for {test_name}") elif len(filtered_images) == 0: - error(f'No matching control images found for {test_name}') + error(f"No matching control images found for {test_name}") self.found_image = filtered_images[0] - print(f'Found matching control image: {self.found_image}') + print(f"Found matching control image: {self.found_image}") return self.found_image def create_diff_image(self, control_image, rendered_image, mask_image): @@ -396,28 +442,30 @@ def create_diff_image(self, control_image, rendered_image, mask_image): linebytes = max_width * 4 diff_image = QImage( - control_image.width(), control_image.height(), QImage.Format.Format_ARGB32) + control_image.width(), control_image.height(), QImage.Format.Format_ARGB32 + ) diff_image.fill(QColor(152, 219, 249)) for y in range(max_height): - control_scanline = control_image.constScanLine( - y).asstring(linebytes) - rendered_scanline = rendered_image.constScanLine( - y).asstring(linebytes) + control_scanline = control_image.constScanLine(y).asstring(linebytes) + rendered_scanline = rendered_image.constScanLine(y).asstring(linebytes) mask_scanline = mask_image.scanLine(y).asstring(linebytes) for x in range(max_width): currentTolerance = qRed( - struct.unpack('I', mask_scanline[x * 4:x * 4 + 4])[0]) + struct.unpack("I", mask_scanline[x * 4 : x * 4 + 4])[0] + ) if currentTolerance == 255: # ignore pixel continue - expected_rgb = struct.unpack( - 'I', control_scanline[x * 4:x * 4 + 4])[0] - rendered_rgb = struct.unpack( - 'I', rendered_scanline[x * 4:x * 4 + 4])[0] + expected_rgb = struct.unpack("I", control_scanline[x * 4 : x * 4 + 4])[ + 0 + ] + rendered_rgb = struct.unpack("I", rendered_scanline[x * 4 : x * 4 + 4])[ + 0 + ] difference = colorDiff(expected_rgb, rendered_rgb) if difference > currentTolerance: @@ -428,7 +476,7 @@ def create_diff_image(self, control_image, rendered_image, mask_image): if mismatch_count: return diff_image else: - print(termcolor.colored('No mismatches', 'green')) + print(termcolor.colored("No mismatches", "green")) return None @@ -436,7 +484,7 @@ def main(): app = QApplication(sys.argv) parser = argparse.ArgumentParser( - description='''A tool to automatically update test image masks based on results submitted to cdash. + description="""A tool to automatically update test image masks based on results submitted to cdash. It will take local control images from the QGIS source and rendered images from test results on cdash to create a mask. @@ -445,9 +493,13 @@ def main(): that the new masks will only mask regions on the image that indeed allow for variation. If the resulting mask is too tolerant, consider adding a new control image next to the existing one. - ''') + """ + ) - parser.add_argument('dash_url', help='URL to a dash result with images. E.g. https://cdash.orfeo-toolbox.org/testDetails.php?test=15052561&build=27712') + parser.add_argument( + "dash_url", + help="URL to a dash result with images. E.g. https://cdash.orfeo-toolbox.org/testDetails.php?test=15052561&build=27712", + ) args = parser.parse_args() w = ResultHandler() @@ -455,5 +507,5 @@ def main(): w.exec() -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/scripts/process_function_template.py b/scripts/process_function_template.py index 0ce1daef4f6a..f2cb90ad09a8 100644 --- a/scripts/process_function_template.py +++ b/scripts/process_function_template.py @@ -1,18 +1,18 @@ -import sys -import os -import json import glob +import json +import os +import sys + from copy import deepcopy sys.path.append( - os.path.join( - os.path.dirname(os.path.realpath(__file__)), - '../python/ext-libs')) + os.path.join(os.path.dirname(os.path.realpath(__file__)), "../python/ext-libs") +) cpp = open(sys.argv[1], "w", encoding="utf-8") cpp.write( - "#include \"qgsexpression.h\"\n" - "#include \"qgsexpression_p.h\"\n" + '#include "qgsexpression.h"\n' + '#include "qgsexpression_p.h"\n' "#include \n" "\n" "void QgsExpression::initFunctionHelp()\n" @@ -32,7 +32,7 @@ def quote(v): return map(quote, v) elif isinstance(v, str): - return v.replace('"', '\\"').replace('\n', '\\n') + return v.replace('"', '\\"').replace("\n", "\\n") elif isinstance(v, bool): return v @@ -41,7 +41,7 @@ def quote(v): raise BaseException("unexpected type " + repr(v)) -for f in sorted(glob.glob('resources/function_help/json/*')): +for f in sorted(glob.glob("resources/function_help/json/*")): with open(f, encoding="utf-8") as function_file: try: json_params = json.load(function_file) @@ -51,85 +51,115 @@ def quote(v): json_params = quote(json_params) - for field in ['name', 'type']: + for field in ["name", "type"]: if field not in json_params: raise BaseException(f"{f}: {field} missing") - if not json_params['type'] in ['function', 'operator', 'value', 'expression', 'group']: - raise BaseException("{}: invalid type {} ".format(f, json_params['type'])) + if not json_params["type"] in [ + "function", + "operator", + "value", + "expression", + "group", + ]: + raise BaseException("{}: invalid type {} ".format(f, json_params["type"])) - if 'variants' not in json_params: + if "variants" not in json_params: # convert single variant shortcut to a expanded variant v = {} for i in json_params: v[i] = json_params[i] - v['variant'] = json_params['name'] - v['variant_description'] = json_params['description'] - json_params['variants'] = [v] + v["variant"] = json_params["name"] + v["variant_description"] = json_params["description"] + json_params["variants"] = [v] - name = "\"{}\"".format(json_params['name']) + name = '"{}"'.format(json_params["name"]) - if json_params['type'] == 'operator': - for v in json_params['variants']: - if 'arguments' not in v: + if json_params["type"] == "operator": + for v in json_params["variants"]: + if "arguments" not in v: raise BaseException("%s: arguments expected for operator" % f) - a_list = list(deepcopy(v['arguments'])) + a_list = list(deepcopy(v["arguments"])) if not 1 <= len(a_list) <= 2: - raise BaseException("%s: 1 or 2 arguments expected for operator found %i" % (f, len(a_list))) + raise BaseException( + "%s: 1 or 2 arguments expected for operator found %i" + % (f, len(a_list)) + ) - cpp.write("\n\n QgsExpression::functionHelpTexts().insert( QStringLiteral( {0} ),\n Help( QStringLiteral( {0} ), tr( \"{1}\" ), tr( \"{2}\" ),\n QList()".format( - name, json_params['type'], json_params['description']) + cpp.write( + '\n\n QgsExpression::functionHelpTexts().insert( QStringLiteral( {0} ),\n Help( QStringLiteral( {0} ), tr( "{1}" ), tr( "{2}" ),\n QList()'.format( + name, json_params["type"], json_params["description"] + ) ) - for v in json_params['variants']: + for v in json_params["variants"]: cpp.write( - "\n << HelpVariant( tr( \"{}\" ), tr( \"{}\" ),\n QList()".format(v['variant'], v['variant_description'])) - - if 'arguments' in v: - for a in v['arguments']: - cpp.write("\n << HelpArg( QStringLiteral( \"{}\" ), tr( \"{}\" ), {}, {}, {}, {} )".format( - a['arg'], - a.get('description', ''), - "true" if a.get('descOnly', False) else "false", - "true" if a.get('syntaxOnly', False) else "false", - "true" if a.get('optional', False) else "false", - 'QStringLiteral( "{}" )'.format(a.get('default', '')) if a.get('default', '') else "QString()" - ) + '\n << HelpVariant( tr( "{}" ), tr( "{}" ),\n QList()'.format( + v["variant"], v["variant_description"] + ) + ) + + if "arguments" in v: + for a in v["arguments"]: + cpp.write( + '\n << HelpArg( QStringLiteral( "{}" ), tr( "{}" ), {}, {}, {}, {} )'.format( + a["arg"], + a.get("description", ""), + "true" if a.get("descOnly", False) else "false", + "true" if a.get("syntaxOnly", False) else "false", + "true" if a.get("optional", False) else "false", + ( + 'QStringLiteral( "{}" )'.format(a.get("default", "")) + if a.get("default", "") + else "QString()" + ), + ) ) - cpp.write(",\n /* variableLenArguments */ {}".format( - "true" if v.get('variableLenArguments', False) else "false")) + cpp.write( + ",\n /* variableLenArguments */ {}".format( + "true" if v.get("variableLenArguments", False) else "false" + ) + ) cpp.write(",\n QList()") - if 'examples' in v: - for e in v['examples']: - cpp.write("\n << HelpExample( tr( \"{}\" ), tr( \"{}\" ), tr( \"{}\" ) )".format( - e['expression'], - e['returns'], - e.get('note', '')) + if "examples" in v: + for e in v["examples"]: + cpp.write( + '\n << HelpExample( tr( "{}" ), tr( "{}" ), tr( "{}" ) )'.format( + e["expression"], e["returns"], e.get("note", "") + ) ) - if 'notes' in v: - cpp.write(",\n tr( \"{}\" )".format(v['notes'])) + if "notes" in v: + cpp.write(',\n tr( "{}" )'.format(v["notes"])) else: cpp.write(",\n QString()") cpp.write(",\n QStringList()") - if 'tags' in v: - cpp.write("\n << tr( \"{}\" )".format(",".join(v['tags']))) + if "tags" in v: + cpp.write('\n << tr( "{}" )'.format(",".join(v["tags"]))) cpp.write("\n )") cpp.write("\n )") cpp.write("\n );") -for f in sorted(glob.glob('resources/function_help/text/*')): +for f in sorted(glob.glob("resources/function_help/text/*")): n = os.path.basename(f) with open(f) as content: - cpp.write("\n\n QgsExpression::functionHelpTexts().insert( \"{0}\",\n Help( tr( \"{0}\" ), tr( \"group\" ), tr( \"{1}\" ), QList() ) );\n".format( - n, content.read().replace("\\", "\").replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n'))) + cpp.write( + '\n\n QgsExpression::functionHelpTexts().insert( "{0}",\n Help( tr( "{0}" ), tr( "group" ), tr( "{1}" ), QList() ) );\n'.format( + n, + content.read() + .replace("\\", "\") + .replace("\\", "\\\\") + .replace('"', '\\"') + .replace("\n", "\\n"), + ) + ) cpp.write("\n } );\n}\n") cpp.close() diff --git a/scripts/process_google_fonts.py b/scripts/process_google_fonts.py index d68e888c39c5..7b319c1adffc 100644 --- a/scripts/process_google_fonts.py +++ b/scripts/process_google_fonts.py @@ -1,1573 +1,1575 @@ -from pathlib import Path import re +from pathlib import Path + # path to checked out Google Fonts repo path = Path("/home/me/google/fonts") # list of fonts from Google Fonts to include -fonts = ["ABeeZee", - "ADLaM Display", - "Abel", - "Abhaya Libre", - "Aboreto", - "Abril Fatface", - "Abyssinica SIL", - "Aclonica", - "Acme", - "Actor", - "Adamina", - "Advent Pro", - "Agdasima", - "Aguafina Script", - "Akatab", - "Akaya Kanadaka", - "Akaya Telivigala", - "Akronim", - "Akshar", - "Aladin", - "Alata", - "Alatsi", - "Albert Sans", - "Aldrich", - "Alef", - "Alegreya", - "Alegreya SC", - "Alegreya Sans", - "Alegreya Sans SC", - "Aleo", - "Alex Brush", - "Alexandria", - "Alfa Slab One", - "Alice", - "Alike", - "Alike Angular", - "Alkalami", - "Alkatra", - "Allan", - "Allerta", - "Allerta Stencil", - "Allison", - "Allura", - "Almarai", - "Almendra", - "Almendra Display", - "Almendra SC", - "Alumni Sans", - "Alumni Sans Collegiate One", - "Alumni Sans Inline One", - "Alumni Sans Pinstripe", - "Amarante", - "Amaranth", - "Amatic SC", - "Amethysta", - "Amiko", - "Amiri", - "Amiri Quran", - "Amita", - "Anaheim", - "Andada Pro", - "Andika", - "Anek Bangla", - "Anek Devanagari", - "Anek Gujarati", - "Anek Gurmukhi", - "Anek Kannada", - "Anek Latin", - "Anek Malayalam", - "Anek Odia", - "Anek Tamil", - "Anek Telugu", - "Angkor", - "Annie Use Your Telescope", - "Anonymous Pro", - "Antic", - "Antic Didone", - "Antic Slab", - "Anton", - "Antonio", - "Anuphan", - "Anybody", - "Aoboshi One", - "Arapey", - "Arbutus", - "Arbutus Slab", - "Architects Daughter", - "Archivo", - "Archivo Black", - "Archivo Narrow", - "Are You Serious", - "Aref Ruqaa", - "Aref Ruqaa Ink", - "Arima", - "Arimo", - "Arizonia", - "Armata", - "Arsenal", - "Artifika", - "Arvo", - "Arya", - "Asap", - "Asap Condensed", - "Asar", - "Asset", - "Assistant", - "Astloch", - "Asul", - "Athiti", - "Atkinson Hyperlegible", - "Atomic Age", - "Aubrey", - "Audiowide", - "Autour One", - "Average", - "Average Sans", - "Averia Gruesa Libre", - "Averia Libre", - "Averia Sans Libre", - "Averia Serif Libre", - "Azeret Mono", - "B612", - "B612 Mono", - "BIZ UDGothic", - "BIZ UDMincho", - "BIZ UDPGothic", - "BIZ UDPMincho", - "Babylonica", - "Bacasime Antique", - "Bad Script", - "Bagel Fat One", - "Bahiana", - "Bahianita", - "Bai Jamjuree", - "Bakbak One", - "Ballet", - "Baloo 2", - "Baloo Bhai 2", - "Baloo Bhaijaan 2", - "Baloo Bhaina 2", - "Baloo Chettan 2", - "Baloo Da 2", - "Baloo Paaji 2", - "Baloo Tamma 2", - "Baloo Tammudu 2", - "Baloo Thambi 2", - "Balsamiq Sans", - "Balthazar", - "Bangers", - "Barlow", - "Barlow Condensed", - "Barlow Semi Condensed", - "Barriecito", - "Barrio", - "Basic", - "Baskervville", - "Battambang", - "Baumans", - "Bayon", - "Be Vietnam Pro", - "Beau Rivage", - "Bebas Neue", - "Belanosima", - "Belgrano", - "Bellefair", - "Belleza", - "Bellota", - "Bellota Text", - "BenchNine", - "Benne", - "Bentham", - "Berkshire Swash", - "Besley", - "Beth Ellen", - "Bevan", - "BhuTuka Expanded One", - "Big Shoulders Display", - "Big Shoulders Inline Display", - "Big Shoulders Inline Text", - "Big Shoulders Stencil Display", - "Big Shoulders Stencil Text", - "Big Shoulders Text", - "Bigelow Rules", - "Bigshot One", - "Bilbo", - "Bilbo Swash Caps", - "BioRhyme", - "BioRhyme Expanded", - "Birthstone", - "Birthstone Bounce", - "Biryani", - "Bitter", - "Black And White Picture", - "Black Han Sans", - "Black Ops One", - "Blaka", - "Blaka Hollow", - "Blaka Ink", - "Bodoni Moda", - "Bokor", - "Bona Nova", - "Bonbon", - "Bonheur Royale", - "Boogaloo", - "Borel", - "Bowlby One", - "Bowlby One SC", - "Braah One", - "Brawler", - "Bree Serif", - "Bricolage Grotesque", - "Bruno Ace", - "Bruno Ace SC", - "Brygada 1918", - "Bubblegum Sans", - "Bubbler One", - "Buda", - "Buenard", - "Bungee", - "Bungee Hairline", - "Bungee Inline", - "Bungee Outline", - "Bungee Shade", - "Bungee Spice", - "Butcherman", - "Butterfly Kids", - "Cabin", - "Cabin Condensed", - "Cabin Sketch", - "Caesar Dressing", - "Cagliostro", - "Cairo", - "Cairo Play", - "Caladea", - "Calistoga", - "Calligraffitti", - "Cambay", - "Cambo", - "Candal", - "Cantarell", - "Cantata One", - "Cantora One", - "Caprasimo", - "Capriola", - "Caramel", - "Carattere", - "Cardo", - "Carlito", - "Carme", - "Carrois Gothic", - "Carrois Gothic SC", - "Carter One", - "Castoro", - "Castoro Titling", - "Catamaran", - "Caudex", - "Caveat", - "Caveat Brush", - "Cedarville Cursive", - "Ceviche One", - "Chakra Petch", - "Changa", - "Changa One", - "Chango", - "Charis SIL", - "Charm", - "Charmonman", - "Chau Philomene One", - "Chela One", - "Chelsea Market", - "Chenla", - "Cherish", - "Cherry Bomb One", - "Cherry Cream Soda", - "Cherry Swash", - "Chewy", - "Chicle", - "Chilanka", - "Chivo", - "Chivo Mono", - "Chokokutai", - "Chonburi", - "Cinzel", - "Cinzel Decorative", - "Clicker Script", - "Climate Crisis", - "Coda", - "Codystar", - "Coiny", - "Combo", - "Comfortaa", - "Comforter", - "Comforter Brush", - "Comic Neue", - "Coming Soon", - "Comme", - "Commissioner", - "Concert One", - "Condiment", - "Content", - "Contrail One", - "Convergence", - "Cookie", - "Copse", - "Corben", - "Corinthia", - "Cormorant", - "Cormorant Garamond", - "Cormorant Infant", - "Cormorant SC", - "Cormorant Unicase", - "Cormorant Upright", - "Courgette", - "Courier Prime", - "Cousine", - "Coustard", - "Covered By Your Grace", - "Crafty Girls", - "Creepster", - "Crete Round", - "Crimson Pro", - "Crimson Text", - "Croissant One", - "Crushed", - "Cuprum", - "Cute Font", - "Cutive", - "Cutive Mono", - "DM Mono", - "DM Sans", - "DM Serif Display", - "DM Serif Text", - "Dai Banna SIL", - "Damion", - "Dancing Script", - "Dangrek", - "Darker Grotesque", - "Darumadrop One", - "David Libre", - "Dawning of a New Day", - "Days One", - "Dekko", - "Delicious Handrawn", - "Delius", - "Delius Swash Caps", - "Delius Unicase", - "Della Respira", - "Denk One", - "Devonshire", - "Dhurjati", - "Didact Gothic", - "Diphylleia", - "Diplomata", - "Diplomata SC", - "Do Hyeon", - "Dokdo", - "Domine", - "Donegal One", - "Dongle", - "Doppio One", - "Dorsa", - "Dosis", - "DotGothic16", - "Dr Sugiyama", - # "Droid Sans", - # "Droid Sans Mono", - # "Droid Serif", - "Duru Sans", - "DynaPuff", - "Dynalight", - "EB Garamond", - "Eagle Lake", - "East Sea Dokdo", - "Eater", - "Economica", - "Eczar", - "Edu NSW ACT Foundation", - "Edu QLD Beginner", - "Edu SA Beginner", - "Edu TAS Beginner", - "Edu VIC WA NT Beginner", - "Ek Mukta", - "El Messiri", - "Electrolize", - "Elsie", - "Elsie Swash Caps", - "Emblema One", - "Emilys Candy", - "Encode Sans", - "Encode Sans Condensed", - "Encode Sans Expanded", - "Encode Sans SC", - "Encode Sans Semi Condensed", - "Encode Sans Semi Expanded", - "Engagement", - "Englebert", - "Enriqueta", - "Ephesis", - "Epilogue", - "Erica One", - "Esteban", - "Estonia", - "Euphoria Script", - "Ewert", - "Exo", - "Exo 2", - "Expletus Sans", - "Explora", - "Fahkwang", - "Familjen Grotesk", - "Fanwood Text", - "Farro", - "Farsan", - "Fascinate", - "Fascinate Inline", - "Faster One", - "Fasthand", - "Fauna One", - "Faustina", - "Federant", - "Federo", - "Felipa", - "Fenix", - "Festive", - "Figtree", - "Finger Paint", - "Finlandica", - "Fira Code", - "Fira Mono", - "Fira Sans", - "Fira Sans Condensed", - "Fira Sans Extra Condensed", - "Fira Sans Extra Condensed", - "Fjalla One", - "Fjord One", - "Flamenco", - "Flavors", - "Fleur De Leah", - "Flow Block", - "Flow Circular", - "Flow Rounded", - "Foldit", - "Fondamento", - "Fontdiner Swanky", - "Forum", - "Fragment Mono", - "Francois One", - "Frank Ruhl Libre", - "Fraunces", - "Freckle Face", - "Fredericka the Great", - "Fredoka", - "Freehand", - "Fresca", - "Frijole", - "Fruktur", - "Fugaz One", - "Fuggles", - "Fuzzy Bubbles", - "GFS Didot", - "GFS Neohellenic", - "Gabriela", - "Gaegu", - "Gafata", - "Gajraj One", - "Galada", - "Galdeano", - "Galindo", - "Gamja Flower", - "Gantari", - "Gasoek One", - "Gayathri", - "Gelasio", - "Gemunu Libre", - "Genos", - "Geo", - "Geologica", - "Georama", - "Geostar", - "Geostar Fill", - "Germania One", - "Gideon Roman", - "Gidugu", - "Gilda Display", - "Girassol", - "Give You Glory", - "Glass Antiqua", - "Glegoo", - "Gloock", - "Gloria Hallelujah", - "Glory", - "Gluten", - "Goblin One", - "Gochi Hand", - "Goldman", - "Golos Text", - "Gorditas", - "Gothic A1", - "Gotu", - "Goudy Bookletter 1911", - "Gowun Batang", - "Gowun Dodum", - "Graduate", - "Grand Hotel", - "Grandiflora One", - "Grandstander", - "Grape Nuts", - "Gravitas One", - "Great Vibes", - "Grechen Fuemen", - "Grenze", - "Grenze Gotisch", - "Grey Qo", - "Griffy", - "Gruppo", - "Gudea", - "Gugi", - "Gulzar", - "Gupter", - "Gurajada", - "Gwendolyn", - "Habibi", - "Hachi Maru Pop", - "Hahmlet", - "Halant", - "Hammersmith One", - "Hanalei", - "Hanalei Fill", - "Handjet", - "Handlee", - "Hanken Grotesk", - "Hanuman", - "Happy Monkey", - "Harmattan", - "Headland One", - "Heebo", - "Henny Penny", - "Hepta Slab", - "Herr Von Muellerhoff", - "Hi Melody", - "Hina Mincho", - "Hind", - "Hind Guntur", - "Hind Madurai", - "Hind Siliguri", - "Hind Vadodara", - "Holtwood One SC", - "Homemade Apple", - "Homenaje", - "Hubballi", - "Hurricane", - "IBM Plex Mono", - "IBM Plex Sans", - "IBM Plex Sans Arabic", - "IBM Plex Sans Condensed", - "IBM Plex Sans Devanagari", - "IBM Plex Sans Hebrew", - "IBM Plex Sans JP", - "IBM Plex Sans KR", - "IBM Plex Sans Thai", - "IBM Plex Sans Thai Looped", - "IBM Plex Serif", - "IM Fell DW Pica", - "IM Fell DW Pica SC", - "IM Fell Double Pica", - "IM Fell Double Pica SC", - "IM Fell English", - "IM Fell English SC", - "IM Fell French Canon", - "IM Fell French Canon SC", - "IM Fell Great Primer", - "IM Fell Great Primer SC", - "Ibarra Real Nova", - "Iceberg", - "Iceland", - "Imbue", - "Imperial Script", - "Imprima", - "Inconsolata", - "Inder", - "Indie Flower", - "Ingrid Darling", - "Inika", - "Inknut Antiqua", - "Inria Sans", - "Inria Serif", - "Inspiration", - "Instrument Sans", - "Instrument Serif", - "Inter", - "Inter Tight", - "Irish Grover", - "Island Moments", - "Istok Web", - "Italiana", - "Italianno", - "Itim", - "Jacques Francois", - "Jacques Francois Shadow", - "Jaldi", - "JetBrains Mono", - "Jim Nightshade", - "Joan", - "Jockey One", - "Jolly Lodger", - "Jomhuria", - "Jomolhari", - "Josefin Sans", - "Josefin Slab", - "Jost", - "Joti One", - "Jua", - "Judson", - "Julee", - "Julius Sans One", - "Junge", - "Jura", - "Just Another Hand", - "Just Me Again Down Here", - "K2D", - "Kablammo", - "Kadwa", - "Kaisei Decol", - "Kaisei HarunoUmi", - "Kaisei Opti", - "Kaisei Tokumin", - "Kalam", - "Kameron", - "Kanit", - "Kantumruy Pro", - "Karantina", - "Karla", - "Karma", - "Katibeh", - "Kaushan Script", - "Kavivanar", - "Kavoon", - "Kdam Thmor Pro", - "Keania One", - "Kelly Slab", - "Kenia", - "Khand", - "Khmer", - "Khula", - "Kings", - "Kirang Haerang", - "Kite One", - "Kiwi Maru", - "Klee One", - "Knewave", - "KoHo", - "Kodchasan", - "Koh Santepheap", - "Kolker Brush", - "Konkhmer Sleokchher", - "Kosugi", - "Kosugi Maru", - "Kotta One", - "Koulen", - "Kranky", - "Kreon", - "Kristi", - "Krona One", - "Krub", - "Kufam", - "Kumar One", - "Kumbh Sans", - "Kurale", - "La Belle Aurore", - "Labrada", - "Lacquer", - "Laila", - "Lakki Reddy", - "Lalezar", - "Lancelot", - "Langar", - "Lateef", - "Lato", - "Lavishly Yours", - "League Gothic", - "League Script", - "League Spartan", - "Leckerli One", - "Ledger", - "Lekton", - "Lemon", - "Lemonada", - "Lexend", - "Lexend Deca", - "Lexend Exa", - "Lexend Giga", - "Lexend Mega", - "Lexend Peta", - "Lexend Tera", - "Lexend Zetta", - "Libre Barcode 128", - "Libre Barcode 128 Text", - "Libre Barcode 39", - "Libre Barcode 39 Extended", - "Libre Barcode 39 Extended Text", - "Libre Barcode 39 Text", - "Libre Barcode EAN13 Text", - "Libre Baskerville", - "Libre Bodoni", - "Libre Caslon Display", - "Libre Caslon Text", - "Libre Franklin", - "Licorice", - "Life Savers", - "Lilita One", - "Lily Script One", - "Limelight", - "Linden Hill", - "Lisu Bosa", - "Literata", - "Liu Jian Mao Cao", - "Livvic", - "Lobster", - "Lobster Two", - "Londrina Outline", - "Londrina Shadow", - "Londrina Sketch", - "Londrina Solid", - "Long Cang", - "Lora", - "Love Light", - "Love Ya Like A Sister", - "Loved by the King", - "Lovers Quarrel", - "Luckiest Guy", - "Lugrasimo", - "Lumanosimo", - "Lunasima", - "Lusitana", - "Lustria", - "Luxurious Roman", - "Luxurious Script", - "M PLUS 1", - "M PLUS 1 Code", - "M PLUS 1p", - "M PLUS 2", - "M PLUS Code Latin", - "Ma Shan Zheng", - "Macondo", - "Macondo Swash Caps", - "Mada", - "Magra", - "Maiden Orange", - "Maitree", - "Major Mono Display", - "Mako", - "Mali", - "Mallanna", - "Mandali", - "Manjari", - "Manrope", - "Mansalva", - "Manuale", - "Marcellus", - "Marcellus SC", - "Marck Script", - "Margarine", - "Marhey", - "Markazi Text", - "Marko One", - "Marmelad", - "Martel", - "Martel Sans", - "Martian Mono", - "Marvel", - "Mate", - "Mate SC", - "Maven Pro", - "McLaren", - "Mea Culpa", - "Meddon", - "MedievalSharp", - "Medula One", - "Meera Inimai", - "Megrim", - "Meie Script", - "Meow Script", - "Merienda", - "Merriweather", - "Merriweather Sans", - "Metal", - "Metal Mania", - "Metamorphous", - "Metrophobic", - "Michroma", - "Milonga", - "Miltonian", - "Miltonian Tattoo", - "Mina", - "Mingzat", - "Miniver", - "Miriam Libre", - "Miss Fajardose", - "Mochiy Pop One", - "Mochiy Pop P One", - "Modak", - "Modern Antiqua", - "Mohave", - "Moirai One", - "Molengo", - "Molle", - "Monda", - "Monofett", - "Monomaniac One", - "Monoton", - "Monsieur La Doulaise", - "Montaga", - "Montagu Slab", - "MonteCarlo", - "Montez", - "Montserrat", - "Montserrat Alternates", - "Montserrat Subrayada", - "Moo Lah Lah", - "Moon Dance", - "Moul", - "Moulpali", - "Mountains of Christmas", - "Mouse Memoirs", - "Mr Bedfort", - "Mr Dafoe", - "Mr De Haviland", - "Mrs Saint Delafield", - "Mrs Sheppards", - "Ms Madi", - "Mukta", - "Mukta Mahee", - "Mukta Malar", - "Mukta Vaani", - "Mulish", - "Murecho", - "MuseoModerno", - "My Soul", - "Mynerve", - "Mystery Quest", - "NTR", - "Nabla", - "Nanum Brush Script", - "Nanum Gothic", - "Nanum Gothic Coding", - "Nanum Myeongjo", - "Nanum Pen Script", - "Narnoor", - "Neonderthaw", - "Nerko One", - "Neucha", - "Neuton", - "New Rocker", - "New Tegomin", - "News Cycle", - "Newsreader", - "Niconne", - "Niramit", - "Nixie One", - "Nobile", - "Nokora", - "Norican", - "Nosifer", - "Notable", - "Nothing You Could Do", - "Noticia Text", - "Noto Color Emoji", - "Noto Emoji", - "Noto Kufi Arabic", - "Noto Music", - "Noto Naskh Arabic", - "Noto Nastaliq Urdu", - "Noto Rashi Hebrew", - "Noto Sans", - "Noto Sans Adlam", - "Noto Sans Adlam Unjoined", - "Noto Sans Anatolian Hieroglyphs", - "Noto Sans Arabic", - "Noto Sans Armenian", - "Noto Sans Avestan", - "Noto Sans Balinese", - "Noto Sans Bamum", - "Noto Sans Bassa Vah", - "Noto Sans Batak", - "Noto Sans Bengali", - "Noto Sans Bhaiksuki", - "Noto Sans Brahmi", - "Noto Sans Buginese", - "Noto Sans Buhid", - "Noto Sans Canadian Aboriginal", - "Noto Sans Carian", - "Noto Sans Caucasian Albanian", - "Noto Sans Chakma", - "Noto Sans Cham", - "Noto Sans Cherokee", - "Noto Sans Chorasmian", - "Noto Sans Coptic", - "Noto Sans Cuneiform", - "Noto Sans Cypriot", - "Noto Sans Cypro Minoan", - "Noto Sans Deseret", - "Noto Sans Devanagari", - "Noto Sans Display", - "Noto Sans Duployan", - "Noto Sans Egyptian Hieroglyphs", - "Noto Sans Elbasan", - "Noto Sans Elymaic", - "Noto Sans Ethiopic", - "Noto Sans Georgian", - "Noto Sans Glagolitic", - "Noto Sans Gothic", - "Noto Sans Grantha", - "Noto Sans Gujarati", - "Noto Sans Gunjala Gondi", - "Noto Sans Gurmukhi", - "Noto Sans HK", - "Noto Sans Hanifi Rohingya", - "Noto Sans Hanunoo", - "Noto Sans Hatran", - "Noto Sans Hebrew", - "Noto Sans Imperial Aramaic", - "Noto Sans Indic Siyaq Numbers", - "Noto Sans Inscriptional Pahlavi", - "Noto Sans Inscriptional Parthian", - "Noto Sans JP", - # "Noto Sans Japanese", - "Noto Sans Javanese", - "Noto Sans KR", - "Noto Sans Kaithi", - "Noto Sans Kannada", - "Noto Sans Kayah Li", - "Noto Sans Kharoshthi", - "Noto Sans Khmer", - "Noto Sans Khojki", - "Noto Sans Khudawadi", - # "Noto Sans Korean", - "Noto Sans Lao", - "Noto Sans Lao Looped", - "Noto Sans Lepcha", - "Noto Sans Limbu", - "Noto Sans Linear A", - "Noto Sans Linear B", - "Noto Sans Lisu", - "Noto Sans Lycian", - "Noto Sans Lydian", - "Noto Sans Mahajani", - "Noto Sans Malayalam", - "Noto Sans Mandaic", - "Noto Sans Manichaean", - "Noto Sans Marchen", - "Noto Sans Masaram Gondi", - "Noto Sans Math", - "Noto Sans Mayan Numerals", - "Noto Sans Medefaidrin", - "Noto Sans Meetei Mayek", - "Noto Sans Mende Kikakui", - "Noto Sans Meroitic", - "Noto Sans Miao", - "Noto Sans Modi", - "Noto Sans Mongolian", - "Noto Sans Mono", - "Noto Sans Mro", - "Noto Sans Multani", - "Noto Sans Myanmar", - "Noto Sans NKo", - "Noto Sans Nabataean", - "Noto Sans Nag Mundari", - "Noto Sans Nandinagari", - "Noto Sans New Tai Lue", - "Noto Sans Newa", - "Noto Sans Nushu", - "Noto Sans Ogham", - "Noto Sans Ol Chiki", - "Noto Sans Old Hungarian", - "Noto Sans Old Italic", - "Noto Sans Old North Arabian", - "Noto Sans Old Permic", - "Noto Sans Old Persian", - "Noto Sans Old Sogdian", - "Noto Sans Old South Arabian", - "Noto Sans Old Turkic", - "Noto Sans Oriya", - "Noto Sans Osage", - "Noto Sans Osmanya", - "Noto Sans Pahawh Hmong", - "Noto Sans Palmyrene", - "Noto Sans Pau Cin Hau", - # "Noto Sans Phags Pa", - "Noto Sans Phoenician", - "Noto Sans Psalter Pahlavi", - "Noto Sans Rejang", - "Noto Sans Runic", - "Noto Sans SC", - "Noto Sans Samaritan", - "Noto Sans Saurashtra", - "Noto Sans Sharada", - "Noto Sans Shavian", - "Noto Sans Siddham", - "Noto Sans SignWriting", - "Noto Sans Sinhala", - "Noto Sans Sogdian", - "Noto Sans Sora Sompeng", - "Noto Sans Soyombo", - "Noto Sans Sundanese", - "Noto Sans Syloti Nagri", - "Noto Sans Symbols", - "Noto Sans Symbols 2", - "Noto Sans Syriac", - "Noto Sans Syriac Eastern", - "Noto Sans TC", - "Noto Sans Tagalog", - "Noto Sans Tagbanwa", - "Noto Sans Tai Le", - "Noto Sans Tai Tham", - "Noto Sans Tai Viet", - "Noto Sans Takri", - "Noto Sans Tamil", - "Noto Sans Tamil Supplement", - "Noto Sans Tangsa", - "Noto Sans Telugu", - "Noto Sans Thaana", - "Noto Sans Thai", - "Noto Sans Thai Looped", - "Noto Sans Tifinagh", - "Noto Sans Tirhuta", - "Noto Sans Ugaritic", - "Noto Sans Vai", - "Noto Sans Vithkuqi", - "Noto Sans Wancho", - "Noto Sans Warang Citi", - "Noto Sans Yi", - "Noto Sans Zanabazar Square", - "Noto Serif", - "Noto Serif Ahom", - "Noto Serif Armenian", - "Noto Serif Balinese", - "Noto Serif Bengali", - "Noto Serif Devanagari", - "Noto Serif Display", - "Noto Serif Dogra", - "Noto Serif Ethiopic", - "Noto Serif Georgian", - "Noto Serif Grantha", - "Noto Serif Gujarati", - "Noto Serif Gurmukhi", - "Noto Serif HK", - "Noto Serif Hebrew", - "Noto Serif JP", - "Noto Serif KR", - "Noto Serif Kannada", - "Noto Serif Khitan Small Script", - "Noto Serif Khmer", - "Noto Serif Khojki", - "Noto Serif Lao", - "Noto Serif Makasar", - "Noto Serif Malayalam", - "Noto Serif Myanmar", - "Noto Serif NP Hmong", - "Noto Serif Oriya", - "Noto Serif Ottoman Siyaq", - "Noto Serif SC", - "Noto Serif Sinhala", - "Noto Serif TC", - "Noto Serif Tamil", - "Noto Serif Tangut", - "Noto Serif Telugu", - "Noto Serif Thai", - "Noto Serif Tibetan", - "Noto Serif Toto", - "Noto Serif Vithkuqi", - "Noto Serif Yezidi", - "Noto Traditional Nushu", - "Nova Cut", - "Nova Flat", - "Nova Mono", - "Nova Oval", - "Nova Round", - "Nova Script", - "Nova Slim", - "Nova Square", - "Numans", - "Nunito", - "Nunito Sans", - "Nuosu SIL", - "Odibee Sans", - "Odor Mean Chey", - "Offside", - "Oi", - "Old Standard TT", - "Oldenburg", - "Ole", - "Oleo Script", - "Oleo Script Swash Caps", - "Oooh Baby", - "Open Sans", - # "Open Sans Condensed", - "Oranienbaum", - "Orbit", - "Orbitron", - "Oregano", - "Orelega One", - "Orienta", - "Original Surfer", - "Oswald", - "Outfit", - "Over the Rainbow", - "Overlock", - "Overlock SC", - "Overpass", - "Overpass Mono", - "Ovo", - "Oxanium", - "Oxygen", - "Oxygen Mono", - "PT Mono", - "PT Sans", - "PT Sans Caption", - "PT Sans Narrow", - "PT Serif", - "PT Serif Caption", - "Pacifico", - "Padauk", - "Padyakke Expanded One", - "Palanquin", - "Palanquin Dark", - "Palette Mosaic", - "Pangolin", - "Paprika", - "Parisienne", - "Passero One", - "Passion One", - "Passions Conflict", - "Pathway Extreme", - "Pathway Gothic One", - "Patrick Hand", - "Patrick Hand SC", - "Pattaya", - "Patua One", - "Pavanam", - "Paytone One", - "Peddana", - "Peralta", - "Permanent Marker", - "Petemoss", - "Petit Formal Script", - "Petrona", - "Philosopher", - "Phudu", - "Piazzolla", - "Piedra", - "Pinyon Script", - "Pirata One", - "Plaster", - "Play", - "Playball", - "Playfair", - "Playfair Display", - "Playfair Display SC", - "Plus Jakarta Sans", - "Podkova", - "Poiret One", - "Poller One", - "Poltawski Nowy", - "Poly", - "Pompiere", - "Pontano Sans", - "Poor Story", - "Poppins", - "Port Lligat Sans", - "Port Lligat Slab", - "Potta One", - "Pragati Narrow", - "Praise", - "Preahvihear", - "Press Start 2P", - "Pridi", - "Princess Sofia", - "Prociono", - "Prompt", - "Prosto One", - "Proza Libre", - "Public Sans", - "Puppies Play", - "Puritan", - "Purple Purse", - "Qahiri", - "Quando", - "Quantico", - "Quattrocento", - "Quattrocento Sans", - "Questrial", - "Quicksand", - "Quintessential", - "Qwigley", - "Qwitcher Grypen", - "REM", - "Racing Sans One", - "Radio Canada", - "Radley", - "Rajdhani", - "Rakkas", - "Raleway", - "Raleway Dots", - "Ramabhadra", - "Ramaraja", - "Rambla", - "Rammetto One", - "Rampart One", - "Ranchers", - "Rancho", - "Ranga", - "Rasa", - "Rationale", - "Ravi Prakash", - "Readex Pro", - "Recursive", - "Red Hat Display", - "Red Hat Mono", - "Red Hat Text", - "Red Rose", - "Redacted", - "Redacted Script", - "Redressed", - "Reem Kufi", - "Reem Kufi Fun", - "Reem Kufi Ink", - "Reenie Beanie", - "Reggae One", - "Revalia", - "Rhodium Libre", - "Ribeye", - "Ribeye Marrow", - "Righteous", - "Risque", - "Road Rage", - "Roboto", - "Roboto Condensed", - "Roboto Flex", - "Roboto Mono", - "Roboto Serif", - "Roboto Slab", - "Rochester", - "Rock 3D", - "Rock Salt", - "RocknRoll One", - "Rokkitt", - "Romanesco", - "Ropa Sans", - "Rosario", - "Rosarivo", - "Rouge Script", - "Rowdies", - "Rozha One", - "Rubik", - "Rubik 80s Fade", - "Rubik Beastly", - "Rubik Bubbles", - "Rubik Burned", - "Rubik Dirt", - "Rubik Distressed", - "Rubik Gemstones", - "Rubik Glitch", - "Rubik Iso", - "Rubik Marker Hatch", - "Rubik Maze", - "Rubik Microbe", - "Rubik Mono One", - "Rubik Moonrocks", - "Rubik One", - "Rubik Pixels", - "Rubik Puddles", - "Rubik Spray Paint", - "Rubik Storm", - "Rubik Vinyl", - "Rubik Wet Paint", - "Ruda", - "Rufina", - "Ruge Boogie", - "Ruluko", - "Rum Raisin", - "Ruslan Display", - "Russo One", - "Ruthie", - "Ruwudu", - "Rye", - "STIX Two Text", - "Sacramento", - "Sahitya", - "Sail", - "Saira", - "Saira Condensed", - "Saira Extra Condensed", - "Saira Semi Condensed", - "Saira Stencil One", - "Salsa", - "Sanchez", - "Sancreek", - "Sansita", - "Sansita One", - "Sansita Swashed", - "Sarabun", - "Sarala", - "Sarina", - "Sarpanch", - "Sassy Frass", - "Satisfy", - "Sawarabi Mincho", - "Scada", - "Scheherazade New", - "Schibsted Grotesk", - "Schoolbell", - "Scope One", - "Seaweed Script", - "Secular One", - "Sedgwick Ave", - "Sedgwick Ave Display", - "Sen", - "Send Flowers", - "Sevillana", - "Seymour One", - "Shadows Into Light", - "Shadows Into Light Two", - "Shalimar", - "Shantell Sans", - "Shanti", - "Share", - "Share Tech", - "Share Tech Mono", - "Shippori Antique", - "Shippori Antique B1", - "Shippori Mincho", - "Shippori Mincho B1", - "Shizuru", - "Shojumaru", - "Short Stack", - "Shrikhand", - "Siemreap", - "Sigmar", - "Sigmar One", - "Signika", - "Signika Negative", - "Silkscreen", - "Simonetta", - "Single Day", - "Sintony", - "Sirin Stencil", - "Six Caps", - "Skranji", - "Slabo 13px", - "Slabo 27px", - "Slackey", - "Slackside One", - "Smokum", - "Smooch", - "Smooch Sans", - "Smythe", - "Sniglet", - "Snippet", - "Snowburst One", - "Sofadi One", - "Sofia", - "Sofia Sans", - "Sofia Sans Condensed", - "Sofia Sans Extra Condensed", - "Sofia Sans Semi Condensed", - "Solitreo", - "Solway", - "Song Myung", - "Sono", - "Sonsie One", - "Sora", - "Sorts Mill Goudy", - "Source Code Pro", - "Source Sans 3", - "Space Grotesk", - "Space Mono", - "Special Elite", - "Spectral", - "Spicy Rice", - "Spinnaker", - "Spirax", - "Splash", - "Spline Sans", - "Spline Sans Mono", - "Squada One", - "Square Peg", - "Sree Krushnadevaraya", - "Sriracha", - "Srisakdi", - "Staatliches", - "Stalemate", - "Stalinist One", - "Stardos Stencil", - "Stick", - "Stick No Bills", - "Stint Ultra Condensed", - "Stint Ultra Expanded", - "Stoke", - "Strait", - "Style Script", - "Stylish", - "Sue Ellen Francisco", - "Suez One", - "Sulphur Point", - "Sumana", - "Sunflower", - "Sunshiney", - "Supermercado One", - "Sura", - "Suranna", - "Suravaram", - "Suwannaphum", - "Swanky and Moo Moo", - "Syncopate", - "Syne", - "Syne Mono", - "Syne Tactile", - "Tai Heritage Pro", - "Tajawal", - "Tangerine", - "Tapestry", - "Taprom", - "Tauri", - "Taviraj", - "Teko", - "Tektur", - "Telex", - "Tenali Ramakrishna", - "Tenor Sans", - "Text Me One", - "Texturina", - "Thasadith", - "The Girl Next Door", - "The Nautigal", - "Tienne", - "Tillana", - "Tilt Neon", - "Tilt Prism", - "Tilt Warp", - "Timmana", - "Tinos", - "Tiro Bangla", - "Tiro Devanagari Hindi", - "Tiro Devanagari Marathi", - "Tiro Devanagari Sanskrit", - "Tiro Gurmukhi", - "Tiro Kannada", - "Tiro Tamil", - "Tiro Telugu", - "Titan One", - "Titillium Web", - "Tomorrow", - "Tourney", - "Trade Winds", - "Train One", - "Trirong", - "Trispace", - "Trocchi", - "Trochut", - "Truculenta", - "Trykker", - "Tsukimi Rounded", - "Tulpen One", - "Turret Road", - "Twinkle Star", - "Ubuntu", - "Ubuntu Condensed", - "Ubuntu Mono", - "Uchen", - "Ultra", - "Unbounded", - "Uncial Antiqua", - "Underdog", - "Unica One", - "UnifrakturCook", - "UnifrakturMaguntia", - "Unkempt", - "Unlock", - "Unna", - "Updock", - "Urbanist", - "VT323", - "Vampiro One", - "Varela", - "Varela Round", - "Varta", - "Vast Shadow", - "Vazirmatn", - "Vesper Libre", - "Viaoda Libre", - "Vibes", - "Vibur", - "Victor Mono", - "Vidaloka", - "Viga", - "Vina Sans", - "Voces", - "Volkhov", - "Vollkorn", - "Vollkorn SC", - "Voltaire", - "Vujahday Script", - "Waiting for the Sunrise", - "Wallpoet", - "Walter Turncoat", - "Warnes", - "Water Brush", - "Waterfall", - "Wavefont", - "Wellfleet", - "Wendy One", - "Whisper", - "WindSong", - "Wire One", - "Wix Madefor Display", - "Wix Madefor Text", - "Work Sans", - "Xanh Mono", - "Yaldevi", - "Yanone Kaffeesatz", - "Yantramanav", - "Yatra One", - "Yellowtail", - "Yeon Sung", - "Yeseva One", - "Yesteryear", - "Yomogi", - "Yrsa", - "Ysabeau", - "Ysabeau Infant", - "Ysabeau Office", - "Ysabeau SC", - "Yuji Boku", - "Yuji Hentaigana Akari", - "Yuji Hentaigana Akebono", - "Yuji Mai", - "Yuji Syuku", - "Yusei Magic", - "ZCOOL KuaiLe", - "ZCOOL QingKe HuangYou", - "ZCOOL XiaoWei", - "Zen Antique", - "Zen Antique Soft", - "Zen Dots", - "Zen Kaku Gothic Antique", - "Zen Kaku Gothic New", - "Zen Kurenaido", - "Zen Loop", - "Zen Maru Gothic", - "Zen Old Mincho", - "Zen Tokyo Zoo", - "Zeyada", - "Zhi Mang Xing", - "Zilla Slab", - "Zilla Slab Highlight", - ] +fonts = [ + "ABeeZee", + "ADLaM Display", + "Abel", + "Abhaya Libre", + "Aboreto", + "Abril Fatface", + "Abyssinica SIL", + "Aclonica", + "Acme", + "Actor", + "Adamina", + "Advent Pro", + "Agdasima", + "Aguafina Script", + "Akatab", + "Akaya Kanadaka", + "Akaya Telivigala", + "Akronim", + "Akshar", + "Aladin", + "Alata", + "Alatsi", + "Albert Sans", + "Aldrich", + "Alef", + "Alegreya", + "Alegreya SC", + "Alegreya Sans", + "Alegreya Sans SC", + "Aleo", + "Alex Brush", + "Alexandria", + "Alfa Slab One", + "Alice", + "Alike", + "Alike Angular", + "Alkalami", + "Alkatra", + "Allan", + "Allerta", + "Allerta Stencil", + "Allison", + "Allura", + "Almarai", + "Almendra", + "Almendra Display", + "Almendra SC", + "Alumni Sans", + "Alumni Sans Collegiate One", + "Alumni Sans Inline One", + "Alumni Sans Pinstripe", + "Amarante", + "Amaranth", + "Amatic SC", + "Amethysta", + "Amiko", + "Amiri", + "Amiri Quran", + "Amita", + "Anaheim", + "Andada Pro", + "Andika", + "Anek Bangla", + "Anek Devanagari", + "Anek Gujarati", + "Anek Gurmukhi", + "Anek Kannada", + "Anek Latin", + "Anek Malayalam", + "Anek Odia", + "Anek Tamil", + "Anek Telugu", + "Angkor", + "Annie Use Your Telescope", + "Anonymous Pro", + "Antic", + "Antic Didone", + "Antic Slab", + "Anton", + "Antonio", + "Anuphan", + "Anybody", + "Aoboshi One", + "Arapey", + "Arbutus", + "Arbutus Slab", + "Architects Daughter", + "Archivo", + "Archivo Black", + "Archivo Narrow", + "Are You Serious", + "Aref Ruqaa", + "Aref Ruqaa Ink", + "Arima", + "Arimo", + "Arizonia", + "Armata", + "Arsenal", + "Artifika", + "Arvo", + "Arya", + "Asap", + "Asap Condensed", + "Asar", + "Asset", + "Assistant", + "Astloch", + "Asul", + "Athiti", + "Atkinson Hyperlegible", + "Atomic Age", + "Aubrey", + "Audiowide", + "Autour One", + "Average", + "Average Sans", + "Averia Gruesa Libre", + "Averia Libre", + "Averia Sans Libre", + "Averia Serif Libre", + "Azeret Mono", + "B612", + "B612 Mono", + "BIZ UDGothic", + "BIZ UDMincho", + "BIZ UDPGothic", + "BIZ UDPMincho", + "Babylonica", + "Bacasime Antique", + "Bad Script", + "Bagel Fat One", + "Bahiana", + "Bahianita", + "Bai Jamjuree", + "Bakbak One", + "Ballet", + "Baloo 2", + "Baloo Bhai 2", + "Baloo Bhaijaan 2", + "Baloo Bhaina 2", + "Baloo Chettan 2", + "Baloo Da 2", + "Baloo Paaji 2", + "Baloo Tamma 2", + "Baloo Tammudu 2", + "Baloo Thambi 2", + "Balsamiq Sans", + "Balthazar", + "Bangers", + "Barlow", + "Barlow Condensed", + "Barlow Semi Condensed", + "Barriecito", + "Barrio", + "Basic", + "Baskervville", + "Battambang", + "Baumans", + "Bayon", + "Be Vietnam Pro", + "Beau Rivage", + "Bebas Neue", + "Belanosima", + "Belgrano", + "Bellefair", + "Belleza", + "Bellota", + "Bellota Text", + "BenchNine", + "Benne", + "Bentham", + "Berkshire Swash", + "Besley", + "Beth Ellen", + "Bevan", + "BhuTuka Expanded One", + "Big Shoulders Display", + "Big Shoulders Inline Display", + "Big Shoulders Inline Text", + "Big Shoulders Stencil Display", + "Big Shoulders Stencil Text", + "Big Shoulders Text", + "Bigelow Rules", + "Bigshot One", + "Bilbo", + "Bilbo Swash Caps", + "BioRhyme", + "BioRhyme Expanded", + "Birthstone", + "Birthstone Bounce", + "Biryani", + "Bitter", + "Black And White Picture", + "Black Han Sans", + "Black Ops One", + "Blaka", + "Blaka Hollow", + "Blaka Ink", + "Bodoni Moda", + "Bokor", + "Bona Nova", + "Bonbon", + "Bonheur Royale", + "Boogaloo", + "Borel", + "Bowlby One", + "Bowlby One SC", + "Braah One", + "Brawler", + "Bree Serif", + "Bricolage Grotesque", + "Bruno Ace", + "Bruno Ace SC", + "Brygada 1918", + "Bubblegum Sans", + "Bubbler One", + "Buda", + "Buenard", + "Bungee", + "Bungee Hairline", + "Bungee Inline", + "Bungee Outline", + "Bungee Shade", + "Bungee Spice", + "Butcherman", + "Butterfly Kids", + "Cabin", + "Cabin Condensed", + "Cabin Sketch", + "Caesar Dressing", + "Cagliostro", + "Cairo", + "Cairo Play", + "Caladea", + "Calistoga", + "Calligraffitti", + "Cambay", + "Cambo", + "Candal", + "Cantarell", + "Cantata One", + "Cantora One", + "Caprasimo", + "Capriola", + "Caramel", + "Carattere", + "Cardo", + "Carlito", + "Carme", + "Carrois Gothic", + "Carrois Gothic SC", + "Carter One", + "Castoro", + "Castoro Titling", + "Catamaran", + "Caudex", + "Caveat", + "Caveat Brush", + "Cedarville Cursive", + "Ceviche One", + "Chakra Petch", + "Changa", + "Changa One", + "Chango", + "Charis SIL", + "Charm", + "Charmonman", + "Chau Philomene One", + "Chela One", + "Chelsea Market", + "Chenla", + "Cherish", + "Cherry Bomb One", + "Cherry Cream Soda", + "Cherry Swash", + "Chewy", + "Chicle", + "Chilanka", + "Chivo", + "Chivo Mono", + "Chokokutai", + "Chonburi", + "Cinzel", + "Cinzel Decorative", + "Clicker Script", + "Climate Crisis", + "Coda", + "Codystar", + "Coiny", + "Combo", + "Comfortaa", + "Comforter", + "Comforter Brush", + "Comic Neue", + "Coming Soon", + "Comme", + "Commissioner", + "Concert One", + "Condiment", + "Content", + "Contrail One", + "Convergence", + "Cookie", + "Copse", + "Corben", + "Corinthia", + "Cormorant", + "Cormorant Garamond", + "Cormorant Infant", + "Cormorant SC", + "Cormorant Unicase", + "Cormorant Upright", + "Courgette", + "Courier Prime", + "Cousine", + "Coustard", + "Covered By Your Grace", + "Crafty Girls", + "Creepster", + "Crete Round", + "Crimson Pro", + "Crimson Text", + "Croissant One", + "Crushed", + "Cuprum", + "Cute Font", + "Cutive", + "Cutive Mono", + "DM Mono", + "DM Sans", + "DM Serif Display", + "DM Serif Text", + "Dai Banna SIL", + "Damion", + "Dancing Script", + "Dangrek", + "Darker Grotesque", + "Darumadrop One", + "David Libre", + "Dawning of a New Day", + "Days One", + "Dekko", + "Delicious Handrawn", + "Delius", + "Delius Swash Caps", + "Delius Unicase", + "Della Respira", + "Denk One", + "Devonshire", + "Dhurjati", + "Didact Gothic", + "Diphylleia", + "Diplomata", + "Diplomata SC", + "Do Hyeon", + "Dokdo", + "Domine", + "Donegal One", + "Dongle", + "Doppio One", + "Dorsa", + "Dosis", + "DotGothic16", + "Dr Sugiyama", + # "Droid Sans", + # "Droid Sans Mono", + # "Droid Serif", + "Duru Sans", + "DynaPuff", + "Dynalight", + "EB Garamond", + "Eagle Lake", + "East Sea Dokdo", + "Eater", + "Economica", + "Eczar", + "Edu NSW ACT Foundation", + "Edu QLD Beginner", + "Edu SA Beginner", + "Edu TAS Beginner", + "Edu VIC WA NT Beginner", + "Ek Mukta", + "El Messiri", + "Electrolize", + "Elsie", + "Elsie Swash Caps", + "Emblema One", + "Emilys Candy", + "Encode Sans", + "Encode Sans Condensed", + "Encode Sans Expanded", + "Encode Sans SC", + "Encode Sans Semi Condensed", + "Encode Sans Semi Expanded", + "Engagement", + "Englebert", + "Enriqueta", + "Ephesis", + "Epilogue", + "Erica One", + "Esteban", + "Estonia", + "Euphoria Script", + "Ewert", + "Exo", + "Exo 2", + "Expletus Sans", + "Explora", + "Fahkwang", + "Familjen Grotesk", + "Fanwood Text", + "Farro", + "Farsan", + "Fascinate", + "Fascinate Inline", + "Faster One", + "Fasthand", + "Fauna One", + "Faustina", + "Federant", + "Federo", + "Felipa", + "Fenix", + "Festive", + "Figtree", + "Finger Paint", + "Finlandica", + "Fira Code", + "Fira Mono", + "Fira Sans", + "Fira Sans Condensed", + "Fira Sans Extra Condensed", + "Fira Sans Extra Condensed", + "Fjalla One", + "Fjord One", + "Flamenco", + "Flavors", + "Fleur De Leah", + "Flow Block", + "Flow Circular", + "Flow Rounded", + "Foldit", + "Fondamento", + "Fontdiner Swanky", + "Forum", + "Fragment Mono", + "Francois One", + "Frank Ruhl Libre", + "Fraunces", + "Freckle Face", + "Fredericka the Great", + "Fredoka", + "Freehand", + "Fresca", + "Frijole", + "Fruktur", + "Fugaz One", + "Fuggles", + "Fuzzy Bubbles", + "GFS Didot", + "GFS Neohellenic", + "Gabriela", + "Gaegu", + "Gafata", + "Gajraj One", + "Galada", + "Galdeano", + "Galindo", + "Gamja Flower", + "Gantari", + "Gasoek One", + "Gayathri", + "Gelasio", + "Gemunu Libre", + "Genos", + "Geo", + "Geologica", + "Georama", + "Geostar", + "Geostar Fill", + "Germania One", + "Gideon Roman", + "Gidugu", + "Gilda Display", + "Girassol", + "Give You Glory", + "Glass Antiqua", + "Glegoo", + "Gloock", + "Gloria Hallelujah", + "Glory", + "Gluten", + "Goblin One", + "Gochi Hand", + "Goldman", + "Golos Text", + "Gorditas", + "Gothic A1", + "Gotu", + "Goudy Bookletter 1911", + "Gowun Batang", + "Gowun Dodum", + "Graduate", + "Grand Hotel", + "Grandiflora One", + "Grandstander", + "Grape Nuts", + "Gravitas One", + "Great Vibes", + "Grechen Fuemen", + "Grenze", + "Grenze Gotisch", + "Grey Qo", + "Griffy", + "Gruppo", + "Gudea", + "Gugi", + "Gulzar", + "Gupter", + "Gurajada", + "Gwendolyn", + "Habibi", + "Hachi Maru Pop", + "Hahmlet", + "Halant", + "Hammersmith One", + "Hanalei", + "Hanalei Fill", + "Handjet", + "Handlee", + "Hanken Grotesk", + "Hanuman", + "Happy Monkey", + "Harmattan", + "Headland One", + "Heebo", + "Henny Penny", + "Hepta Slab", + "Herr Von Muellerhoff", + "Hi Melody", + "Hina Mincho", + "Hind", + "Hind Guntur", + "Hind Madurai", + "Hind Siliguri", + "Hind Vadodara", + "Holtwood One SC", + "Homemade Apple", + "Homenaje", + "Hubballi", + "Hurricane", + "IBM Plex Mono", + "IBM Plex Sans", + "IBM Plex Sans Arabic", + "IBM Plex Sans Condensed", + "IBM Plex Sans Devanagari", + "IBM Plex Sans Hebrew", + "IBM Plex Sans JP", + "IBM Plex Sans KR", + "IBM Plex Sans Thai", + "IBM Plex Sans Thai Looped", + "IBM Plex Serif", + "IM Fell DW Pica", + "IM Fell DW Pica SC", + "IM Fell Double Pica", + "IM Fell Double Pica SC", + "IM Fell English", + "IM Fell English SC", + "IM Fell French Canon", + "IM Fell French Canon SC", + "IM Fell Great Primer", + "IM Fell Great Primer SC", + "Ibarra Real Nova", + "Iceberg", + "Iceland", + "Imbue", + "Imperial Script", + "Imprima", + "Inconsolata", + "Inder", + "Indie Flower", + "Ingrid Darling", + "Inika", + "Inknut Antiqua", + "Inria Sans", + "Inria Serif", + "Inspiration", + "Instrument Sans", + "Instrument Serif", + "Inter", + "Inter Tight", + "Irish Grover", + "Island Moments", + "Istok Web", + "Italiana", + "Italianno", + "Itim", + "Jacques Francois", + "Jacques Francois Shadow", + "Jaldi", + "JetBrains Mono", + "Jim Nightshade", + "Joan", + "Jockey One", + "Jolly Lodger", + "Jomhuria", + "Jomolhari", + "Josefin Sans", + "Josefin Slab", + "Jost", + "Joti One", + "Jua", + "Judson", + "Julee", + "Julius Sans One", + "Junge", + "Jura", + "Just Another Hand", + "Just Me Again Down Here", + "K2D", + "Kablammo", + "Kadwa", + "Kaisei Decol", + "Kaisei HarunoUmi", + "Kaisei Opti", + "Kaisei Tokumin", + "Kalam", + "Kameron", + "Kanit", + "Kantumruy Pro", + "Karantina", + "Karla", + "Karma", + "Katibeh", + "Kaushan Script", + "Kavivanar", + "Kavoon", + "Kdam Thmor Pro", + "Keania One", + "Kelly Slab", + "Kenia", + "Khand", + "Khmer", + "Khula", + "Kings", + "Kirang Haerang", + "Kite One", + "Kiwi Maru", + "Klee One", + "Knewave", + "KoHo", + "Kodchasan", + "Koh Santepheap", + "Kolker Brush", + "Konkhmer Sleokchher", + "Kosugi", + "Kosugi Maru", + "Kotta One", + "Koulen", + "Kranky", + "Kreon", + "Kristi", + "Krona One", + "Krub", + "Kufam", + "Kumar One", + "Kumbh Sans", + "Kurale", + "La Belle Aurore", + "Labrada", + "Lacquer", + "Laila", + "Lakki Reddy", + "Lalezar", + "Lancelot", + "Langar", + "Lateef", + "Lato", + "Lavishly Yours", + "League Gothic", + "League Script", + "League Spartan", + "Leckerli One", + "Ledger", + "Lekton", + "Lemon", + "Lemonada", + "Lexend", + "Lexend Deca", + "Lexend Exa", + "Lexend Giga", + "Lexend Mega", + "Lexend Peta", + "Lexend Tera", + "Lexend Zetta", + "Libre Barcode 128", + "Libre Barcode 128 Text", + "Libre Barcode 39", + "Libre Barcode 39 Extended", + "Libre Barcode 39 Extended Text", + "Libre Barcode 39 Text", + "Libre Barcode EAN13 Text", + "Libre Baskerville", + "Libre Bodoni", + "Libre Caslon Display", + "Libre Caslon Text", + "Libre Franklin", + "Licorice", + "Life Savers", + "Lilita One", + "Lily Script One", + "Limelight", + "Linden Hill", + "Lisu Bosa", + "Literata", + "Liu Jian Mao Cao", + "Livvic", + "Lobster", + "Lobster Two", + "Londrina Outline", + "Londrina Shadow", + "Londrina Sketch", + "Londrina Solid", + "Long Cang", + "Lora", + "Love Light", + "Love Ya Like A Sister", + "Loved by the King", + "Lovers Quarrel", + "Luckiest Guy", + "Lugrasimo", + "Lumanosimo", + "Lunasima", + "Lusitana", + "Lustria", + "Luxurious Roman", + "Luxurious Script", + "M PLUS 1", + "M PLUS 1 Code", + "M PLUS 1p", + "M PLUS 2", + "M PLUS Code Latin", + "Ma Shan Zheng", + "Macondo", + "Macondo Swash Caps", + "Mada", + "Magra", + "Maiden Orange", + "Maitree", + "Major Mono Display", + "Mako", + "Mali", + "Mallanna", + "Mandali", + "Manjari", + "Manrope", + "Mansalva", + "Manuale", + "Marcellus", + "Marcellus SC", + "Marck Script", + "Margarine", + "Marhey", + "Markazi Text", + "Marko One", + "Marmelad", + "Martel", + "Martel Sans", + "Martian Mono", + "Marvel", + "Mate", + "Mate SC", + "Maven Pro", + "McLaren", + "Mea Culpa", + "Meddon", + "MedievalSharp", + "Medula One", + "Meera Inimai", + "Megrim", + "Meie Script", + "Meow Script", + "Merienda", + "Merriweather", + "Merriweather Sans", + "Metal", + "Metal Mania", + "Metamorphous", + "Metrophobic", + "Michroma", + "Milonga", + "Miltonian", + "Miltonian Tattoo", + "Mina", + "Mingzat", + "Miniver", + "Miriam Libre", + "Miss Fajardose", + "Mochiy Pop One", + "Mochiy Pop P One", + "Modak", + "Modern Antiqua", + "Mohave", + "Moirai One", + "Molengo", + "Molle", + "Monda", + "Monofett", + "Monomaniac One", + "Monoton", + "Monsieur La Doulaise", + "Montaga", + "Montagu Slab", + "MonteCarlo", + "Montez", + "Montserrat", + "Montserrat Alternates", + "Montserrat Subrayada", + "Moo Lah Lah", + "Moon Dance", + "Moul", + "Moulpali", + "Mountains of Christmas", + "Mouse Memoirs", + "Mr Bedfort", + "Mr Dafoe", + "Mr De Haviland", + "Mrs Saint Delafield", + "Mrs Sheppards", + "Ms Madi", + "Mukta", + "Mukta Mahee", + "Mukta Malar", + "Mukta Vaani", + "Mulish", + "Murecho", + "MuseoModerno", + "My Soul", + "Mynerve", + "Mystery Quest", + "NTR", + "Nabla", + "Nanum Brush Script", + "Nanum Gothic", + "Nanum Gothic Coding", + "Nanum Myeongjo", + "Nanum Pen Script", + "Narnoor", + "Neonderthaw", + "Nerko One", + "Neucha", + "Neuton", + "New Rocker", + "New Tegomin", + "News Cycle", + "Newsreader", + "Niconne", + "Niramit", + "Nixie One", + "Nobile", + "Nokora", + "Norican", + "Nosifer", + "Notable", + "Nothing You Could Do", + "Noticia Text", + "Noto Color Emoji", + "Noto Emoji", + "Noto Kufi Arabic", + "Noto Music", + "Noto Naskh Arabic", + "Noto Nastaliq Urdu", + "Noto Rashi Hebrew", + "Noto Sans", + "Noto Sans Adlam", + "Noto Sans Adlam Unjoined", + "Noto Sans Anatolian Hieroglyphs", + "Noto Sans Arabic", + "Noto Sans Armenian", + "Noto Sans Avestan", + "Noto Sans Balinese", + "Noto Sans Bamum", + "Noto Sans Bassa Vah", + "Noto Sans Batak", + "Noto Sans Bengali", + "Noto Sans Bhaiksuki", + "Noto Sans Brahmi", + "Noto Sans Buginese", + "Noto Sans Buhid", + "Noto Sans Canadian Aboriginal", + "Noto Sans Carian", + "Noto Sans Caucasian Albanian", + "Noto Sans Chakma", + "Noto Sans Cham", + "Noto Sans Cherokee", + "Noto Sans Chorasmian", + "Noto Sans Coptic", + "Noto Sans Cuneiform", + "Noto Sans Cypriot", + "Noto Sans Cypro Minoan", + "Noto Sans Deseret", + "Noto Sans Devanagari", + "Noto Sans Display", + "Noto Sans Duployan", + "Noto Sans Egyptian Hieroglyphs", + "Noto Sans Elbasan", + "Noto Sans Elymaic", + "Noto Sans Ethiopic", + "Noto Sans Georgian", + "Noto Sans Glagolitic", + "Noto Sans Gothic", + "Noto Sans Grantha", + "Noto Sans Gujarati", + "Noto Sans Gunjala Gondi", + "Noto Sans Gurmukhi", + "Noto Sans HK", + "Noto Sans Hanifi Rohingya", + "Noto Sans Hanunoo", + "Noto Sans Hatran", + "Noto Sans Hebrew", + "Noto Sans Imperial Aramaic", + "Noto Sans Indic Siyaq Numbers", + "Noto Sans Inscriptional Pahlavi", + "Noto Sans Inscriptional Parthian", + "Noto Sans JP", + # "Noto Sans Japanese", + "Noto Sans Javanese", + "Noto Sans KR", + "Noto Sans Kaithi", + "Noto Sans Kannada", + "Noto Sans Kayah Li", + "Noto Sans Kharoshthi", + "Noto Sans Khmer", + "Noto Sans Khojki", + "Noto Sans Khudawadi", + # "Noto Sans Korean", + "Noto Sans Lao", + "Noto Sans Lao Looped", + "Noto Sans Lepcha", + "Noto Sans Limbu", + "Noto Sans Linear A", + "Noto Sans Linear B", + "Noto Sans Lisu", + "Noto Sans Lycian", + "Noto Sans Lydian", + "Noto Sans Mahajani", + "Noto Sans Malayalam", + "Noto Sans Mandaic", + "Noto Sans Manichaean", + "Noto Sans Marchen", + "Noto Sans Masaram Gondi", + "Noto Sans Math", + "Noto Sans Mayan Numerals", + "Noto Sans Medefaidrin", + "Noto Sans Meetei Mayek", + "Noto Sans Mende Kikakui", + "Noto Sans Meroitic", + "Noto Sans Miao", + "Noto Sans Modi", + "Noto Sans Mongolian", + "Noto Sans Mono", + "Noto Sans Mro", + "Noto Sans Multani", + "Noto Sans Myanmar", + "Noto Sans NKo", + "Noto Sans Nabataean", + "Noto Sans Nag Mundari", + "Noto Sans Nandinagari", + "Noto Sans New Tai Lue", + "Noto Sans Newa", + "Noto Sans Nushu", + "Noto Sans Ogham", + "Noto Sans Ol Chiki", + "Noto Sans Old Hungarian", + "Noto Sans Old Italic", + "Noto Sans Old North Arabian", + "Noto Sans Old Permic", + "Noto Sans Old Persian", + "Noto Sans Old Sogdian", + "Noto Sans Old South Arabian", + "Noto Sans Old Turkic", + "Noto Sans Oriya", + "Noto Sans Osage", + "Noto Sans Osmanya", + "Noto Sans Pahawh Hmong", + "Noto Sans Palmyrene", + "Noto Sans Pau Cin Hau", + # "Noto Sans Phags Pa", + "Noto Sans Phoenician", + "Noto Sans Psalter Pahlavi", + "Noto Sans Rejang", + "Noto Sans Runic", + "Noto Sans SC", + "Noto Sans Samaritan", + "Noto Sans Saurashtra", + "Noto Sans Sharada", + "Noto Sans Shavian", + "Noto Sans Siddham", + "Noto Sans SignWriting", + "Noto Sans Sinhala", + "Noto Sans Sogdian", + "Noto Sans Sora Sompeng", + "Noto Sans Soyombo", + "Noto Sans Sundanese", + "Noto Sans Syloti Nagri", + "Noto Sans Symbols", + "Noto Sans Symbols 2", + "Noto Sans Syriac", + "Noto Sans Syriac Eastern", + "Noto Sans TC", + "Noto Sans Tagalog", + "Noto Sans Tagbanwa", + "Noto Sans Tai Le", + "Noto Sans Tai Tham", + "Noto Sans Tai Viet", + "Noto Sans Takri", + "Noto Sans Tamil", + "Noto Sans Tamil Supplement", + "Noto Sans Tangsa", + "Noto Sans Telugu", + "Noto Sans Thaana", + "Noto Sans Thai", + "Noto Sans Thai Looped", + "Noto Sans Tifinagh", + "Noto Sans Tirhuta", + "Noto Sans Ugaritic", + "Noto Sans Vai", + "Noto Sans Vithkuqi", + "Noto Sans Wancho", + "Noto Sans Warang Citi", + "Noto Sans Yi", + "Noto Sans Zanabazar Square", + "Noto Serif", + "Noto Serif Ahom", + "Noto Serif Armenian", + "Noto Serif Balinese", + "Noto Serif Bengali", + "Noto Serif Devanagari", + "Noto Serif Display", + "Noto Serif Dogra", + "Noto Serif Ethiopic", + "Noto Serif Georgian", + "Noto Serif Grantha", + "Noto Serif Gujarati", + "Noto Serif Gurmukhi", + "Noto Serif HK", + "Noto Serif Hebrew", + "Noto Serif JP", + "Noto Serif KR", + "Noto Serif Kannada", + "Noto Serif Khitan Small Script", + "Noto Serif Khmer", + "Noto Serif Khojki", + "Noto Serif Lao", + "Noto Serif Makasar", + "Noto Serif Malayalam", + "Noto Serif Myanmar", + "Noto Serif NP Hmong", + "Noto Serif Oriya", + "Noto Serif Ottoman Siyaq", + "Noto Serif SC", + "Noto Serif Sinhala", + "Noto Serif TC", + "Noto Serif Tamil", + "Noto Serif Tangut", + "Noto Serif Telugu", + "Noto Serif Thai", + "Noto Serif Tibetan", + "Noto Serif Toto", + "Noto Serif Vithkuqi", + "Noto Serif Yezidi", + "Noto Traditional Nushu", + "Nova Cut", + "Nova Flat", + "Nova Mono", + "Nova Oval", + "Nova Round", + "Nova Script", + "Nova Slim", + "Nova Square", + "Numans", + "Nunito", + "Nunito Sans", + "Nuosu SIL", + "Odibee Sans", + "Odor Mean Chey", + "Offside", + "Oi", + "Old Standard TT", + "Oldenburg", + "Ole", + "Oleo Script", + "Oleo Script Swash Caps", + "Oooh Baby", + "Open Sans", + # "Open Sans Condensed", + "Oranienbaum", + "Orbit", + "Orbitron", + "Oregano", + "Orelega One", + "Orienta", + "Original Surfer", + "Oswald", + "Outfit", + "Over the Rainbow", + "Overlock", + "Overlock SC", + "Overpass", + "Overpass Mono", + "Ovo", + "Oxanium", + "Oxygen", + "Oxygen Mono", + "PT Mono", + "PT Sans", + "PT Sans Caption", + "PT Sans Narrow", + "PT Serif", + "PT Serif Caption", + "Pacifico", + "Padauk", + "Padyakke Expanded One", + "Palanquin", + "Palanquin Dark", + "Palette Mosaic", + "Pangolin", + "Paprika", + "Parisienne", + "Passero One", + "Passion One", + "Passions Conflict", + "Pathway Extreme", + "Pathway Gothic One", + "Patrick Hand", + "Patrick Hand SC", + "Pattaya", + "Patua One", + "Pavanam", + "Paytone One", + "Peddana", + "Peralta", + "Permanent Marker", + "Petemoss", + "Petit Formal Script", + "Petrona", + "Philosopher", + "Phudu", + "Piazzolla", + "Piedra", + "Pinyon Script", + "Pirata One", + "Plaster", + "Play", + "Playball", + "Playfair", + "Playfair Display", + "Playfair Display SC", + "Plus Jakarta Sans", + "Podkova", + "Poiret One", + "Poller One", + "Poltawski Nowy", + "Poly", + "Pompiere", + "Pontano Sans", + "Poor Story", + "Poppins", + "Port Lligat Sans", + "Port Lligat Slab", + "Potta One", + "Pragati Narrow", + "Praise", + "Preahvihear", + "Press Start 2P", + "Pridi", + "Princess Sofia", + "Prociono", + "Prompt", + "Prosto One", + "Proza Libre", + "Public Sans", + "Puppies Play", + "Puritan", + "Purple Purse", + "Qahiri", + "Quando", + "Quantico", + "Quattrocento", + "Quattrocento Sans", + "Questrial", + "Quicksand", + "Quintessential", + "Qwigley", + "Qwitcher Grypen", + "REM", + "Racing Sans One", + "Radio Canada", + "Radley", + "Rajdhani", + "Rakkas", + "Raleway", + "Raleway Dots", + "Ramabhadra", + "Ramaraja", + "Rambla", + "Rammetto One", + "Rampart One", + "Ranchers", + "Rancho", + "Ranga", + "Rasa", + "Rationale", + "Ravi Prakash", + "Readex Pro", + "Recursive", + "Red Hat Display", + "Red Hat Mono", + "Red Hat Text", + "Red Rose", + "Redacted", + "Redacted Script", + "Redressed", + "Reem Kufi", + "Reem Kufi Fun", + "Reem Kufi Ink", + "Reenie Beanie", + "Reggae One", + "Revalia", + "Rhodium Libre", + "Ribeye", + "Ribeye Marrow", + "Righteous", + "Risque", + "Road Rage", + "Roboto", + "Roboto Condensed", + "Roboto Flex", + "Roboto Mono", + "Roboto Serif", + "Roboto Slab", + "Rochester", + "Rock 3D", + "Rock Salt", + "RocknRoll One", + "Rokkitt", + "Romanesco", + "Ropa Sans", + "Rosario", + "Rosarivo", + "Rouge Script", + "Rowdies", + "Rozha One", + "Rubik", + "Rubik 80s Fade", + "Rubik Beastly", + "Rubik Bubbles", + "Rubik Burned", + "Rubik Dirt", + "Rubik Distressed", + "Rubik Gemstones", + "Rubik Glitch", + "Rubik Iso", + "Rubik Marker Hatch", + "Rubik Maze", + "Rubik Microbe", + "Rubik Mono One", + "Rubik Moonrocks", + "Rubik One", + "Rubik Pixels", + "Rubik Puddles", + "Rubik Spray Paint", + "Rubik Storm", + "Rubik Vinyl", + "Rubik Wet Paint", + "Ruda", + "Rufina", + "Ruge Boogie", + "Ruluko", + "Rum Raisin", + "Ruslan Display", + "Russo One", + "Ruthie", + "Ruwudu", + "Rye", + "STIX Two Text", + "Sacramento", + "Sahitya", + "Sail", + "Saira", + "Saira Condensed", + "Saira Extra Condensed", + "Saira Semi Condensed", + "Saira Stencil One", + "Salsa", + "Sanchez", + "Sancreek", + "Sansita", + "Sansita One", + "Sansita Swashed", + "Sarabun", + "Sarala", + "Sarina", + "Sarpanch", + "Sassy Frass", + "Satisfy", + "Sawarabi Mincho", + "Scada", + "Scheherazade New", + "Schibsted Grotesk", + "Schoolbell", + "Scope One", + "Seaweed Script", + "Secular One", + "Sedgwick Ave", + "Sedgwick Ave Display", + "Sen", + "Send Flowers", + "Sevillana", + "Seymour One", + "Shadows Into Light", + "Shadows Into Light Two", + "Shalimar", + "Shantell Sans", + "Shanti", + "Share", + "Share Tech", + "Share Tech Mono", + "Shippori Antique", + "Shippori Antique B1", + "Shippori Mincho", + "Shippori Mincho B1", + "Shizuru", + "Shojumaru", + "Short Stack", + "Shrikhand", + "Siemreap", + "Sigmar", + "Sigmar One", + "Signika", + "Signika Negative", + "Silkscreen", + "Simonetta", + "Single Day", + "Sintony", + "Sirin Stencil", + "Six Caps", + "Skranji", + "Slabo 13px", + "Slabo 27px", + "Slackey", + "Slackside One", + "Smokum", + "Smooch", + "Smooch Sans", + "Smythe", + "Sniglet", + "Snippet", + "Snowburst One", + "Sofadi One", + "Sofia", + "Sofia Sans", + "Sofia Sans Condensed", + "Sofia Sans Extra Condensed", + "Sofia Sans Semi Condensed", + "Solitreo", + "Solway", + "Song Myung", + "Sono", + "Sonsie One", + "Sora", + "Sorts Mill Goudy", + "Source Code Pro", + "Source Sans 3", + "Space Grotesk", + "Space Mono", + "Special Elite", + "Spectral", + "Spicy Rice", + "Spinnaker", + "Spirax", + "Splash", + "Spline Sans", + "Spline Sans Mono", + "Squada One", + "Square Peg", + "Sree Krushnadevaraya", + "Sriracha", + "Srisakdi", + "Staatliches", + "Stalemate", + "Stalinist One", + "Stardos Stencil", + "Stick", + "Stick No Bills", + "Stint Ultra Condensed", + "Stint Ultra Expanded", + "Stoke", + "Strait", + "Style Script", + "Stylish", + "Sue Ellen Francisco", + "Suez One", + "Sulphur Point", + "Sumana", + "Sunflower", + "Sunshiney", + "Supermercado One", + "Sura", + "Suranna", + "Suravaram", + "Suwannaphum", + "Swanky and Moo Moo", + "Syncopate", + "Syne", + "Syne Mono", + "Syne Tactile", + "Tai Heritage Pro", + "Tajawal", + "Tangerine", + "Tapestry", + "Taprom", + "Tauri", + "Taviraj", + "Teko", + "Tektur", + "Telex", + "Tenali Ramakrishna", + "Tenor Sans", + "Text Me One", + "Texturina", + "Thasadith", + "The Girl Next Door", + "The Nautigal", + "Tienne", + "Tillana", + "Tilt Neon", + "Tilt Prism", + "Tilt Warp", + "Timmana", + "Tinos", + "Tiro Bangla", + "Tiro Devanagari Hindi", + "Tiro Devanagari Marathi", + "Tiro Devanagari Sanskrit", + "Tiro Gurmukhi", + "Tiro Kannada", + "Tiro Tamil", + "Tiro Telugu", + "Titan One", + "Titillium Web", + "Tomorrow", + "Tourney", + "Trade Winds", + "Train One", + "Trirong", + "Trispace", + "Trocchi", + "Trochut", + "Truculenta", + "Trykker", + "Tsukimi Rounded", + "Tulpen One", + "Turret Road", + "Twinkle Star", + "Ubuntu", + "Ubuntu Condensed", + "Ubuntu Mono", + "Uchen", + "Ultra", + "Unbounded", + "Uncial Antiqua", + "Underdog", + "Unica One", + "UnifrakturCook", + "UnifrakturMaguntia", + "Unkempt", + "Unlock", + "Unna", + "Updock", + "Urbanist", + "VT323", + "Vampiro One", + "Varela", + "Varela Round", + "Varta", + "Vast Shadow", + "Vazirmatn", + "Vesper Libre", + "Viaoda Libre", + "Vibes", + "Vibur", + "Victor Mono", + "Vidaloka", + "Viga", + "Vina Sans", + "Voces", + "Volkhov", + "Vollkorn", + "Vollkorn SC", + "Voltaire", + "Vujahday Script", + "Waiting for the Sunrise", + "Wallpoet", + "Walter Turncoat", + "Warnes", + "Water Brush", + "Waterfall", + "Wavefont", + "Wellfleet", + "Wendy One", + "Whisper", + "WindSong", + "Wire One", + "Wix Madefor Display", + "Wix Madefor Text", + "Work Sans", + "Xanh Mono", + "Yaldevi", + "Yanone Kaffeesatz", + "Yantramanav", + "Yatra One", + "Yellowtail", + "Yeon Sung", + "Yeseva One", + "Yesteryear", + "Yomogi", + "Yrsa", + "Ysabeau", + "Ysabeau Infant", + "Ysabeau Office", + "Ysabeau SC", + "Yuji Boku", + "Yuji Hentaigana Akari", + "Yuji Hentaigana Akebono", + "Yuji Mai", + "Yuji Syuku", + "Yusei Magic", + "ZCOOL KuaiLe", + "ZCOOL QingKe HuangYou", + "ZCOOL XiaoWei", + "Zen Antique", + "Zen Antique Soft", + "Zen Dots", + "Zen Kaku Gothic Antique", + "Zen Kaku Gothic New", + "Zen Kurenaido", + "Zen Loop", + "Zen Maru Gothic", + "Zen Old Mincho", + "Zen Tokyo Zoo", + "Zeyada", + "Zhi Mang Xing", + "Zilla Slab", + "Zilla Slab Highlight", +] font_details = {} for p in path.rglob("*METADATA.pb"): - with open(p, "rt", encoding="utf8") as f_in: + with open(p, encoding="utf8") as f_in: contents = f_in.readlines() - github_path = str(p.parent)[len(str(path)) + 1:] + github_path = str(p.parent)[len(str(path)) + 1 :] name = None license = None @@ -1585,29 +1587,35 @@ match = re.match(r'\s*filename: "(.*)"', line) if match: - filenames.append(f'{github_path}/{match.group(1).replace("[", "%5B").replace("]", "%5D")}') + filenames.append( + f'{github_path}/{match.group(1).replace("[", "%5B").replace("]", "%5D")}' + ) license_path = None - if not (p.parent / f'{license}.txt').exists(): - for license in ['LICENCE.txt', 'LICENSE.txt']: + if not (p.parent / f"{license}.txt").exists(): + for license in ["LICENCE.txt", "LICENSE.txt"]: if (p.parent / license).exists(): - license_path = f'{github_path}/{license}.txt' + license_path = f"{github_path}/{license}.txt" break else: - license_path = f'{github_path}/{license}.txt' + license_path = f"{github_path}/{license}.txt" - font_details[name] = {'filenames': filenames, - 'license_path': license_path} + font_details[name] = {"filenames": filenames, "license_path": license_path} def process_font(family: str): assert family in font_details, family - assert font_details[family]['license_path'], family + assert font_details[family]["license_path"], family - filenames = ', '.join([f'QStringLiteral( "{f}" )' for f in font_details[family]['filenames']]) + filenames = ", ".join( + [f'QStringLiteral( "{f}" )' for f in font_details[family]["filenames"]] + ) - print('GoogleFontDetails( QStringLiteral( "{}" ), {{ {} }}, QStringLiteral( "{}" ) ),'.format( - family, filenames, font_details[family]['license_path'])) + print( + 'GoogleFontDetails( QStringLiteral( "{}" ), {{ {} }}, QStringLiteral( "{}" ) ),'.format( + family, filenames, font_details[family]["license_path"] + ) + ) for f in fonts: diff --git a/scripts/pyqt5_to_pyqt6/pyqt5_to_pyqt6.py b/scripts/pyqt5_to_pyqt6/pyqt5_to_pyqt6.py index 2edbfed7210d..da4f07c2c7b6 100755 --- a/scripts/pyqt5_to_pyqt6/pyqt5_to_pyqt6.py +++ b/scripts/pyqt5_to_pyqt6/pyqt5_to_pyqt6.py @@ -34,71 +34,79 @@ tokenize-rt myfile.py """ -__author__ = 'Julien Cabieces' -__date__ = '2023 December' -__copyright__ = '(C) 2023, Julien Cabieces' +__author__ = "Julien Cabieces" +__date__ = "2023 December" +__copyright__ = "(C) 2023, Julien Cabieces" import argparse import ast import glob -import os import inspect +import os import sys -from enum import Enum from collections import defaultdict +from collections.abc import Sequence +from enum import Enum -from tokenize_rt import Offset, src_to_tokens, tokens_to_src, reversed_enumerate, Token - -from typing import Sequence - -from PyQt6 import QtCore, QtGui, QtWidgets, QtTest, QtSql, QtSvg, QtXml, QtNetwork, QtPrintSupport, Qsci +from PyQt6 import ( + Qsci, + QtCore, + QtGui, + QtNetwork, + QtPrintSupport, + QtSql, + QtSvg, + QtTest, + QtWidgets, + QtXml, +) +from PyQt6.Qsci import * # noqa: F403 from PyQt6.QtCore import * # noqa: F403 from PyQt6.QtGui import * # noqa: F403 -from PyQt6.QtWidgets import * # noqa: F403 -from PyQt6.QtTest import * # noqa: F403 -from PyQt6.QtSql import * # noqa: F403 -from PyQt6.QtXml import * # noqa: F403 from PyQt6.QtNetwork import * # noqa: F403 from PyQt6.QtPrintSupport import * # noqa: F403 -from PyQt6.Qsci import * # noqa: F403 +from PyQt6.QtSql import * # noqa: F403 +from PyQt6.QtTest import * # noqa: F403 +from PyQt6.QtWidgets import * # noqa: F403 +from PyQt6.QtXml import * # noqa: F403 +from tokenize_rt import Offset, Token, reversed_enumerate, src_to_tokens, tokens_to_src try: + import qgis._3d as qgis_3d # noqa: F403 + import qgis.analysis as qgis_analysis # noqa: F403 import qgis.core as qgis_core # noqa: F403 import qgis.gui as qgis_gui # noqa: F403 - import qgis.analysis as qgis_analysis # noqa: F403 - import qgis._3d as qgis_3d # noqa: F403 + + from qgis._3d import * # noqa: F403 + from qgis.analysis import * # noqa: F403 from qgis.core import * # noqa: F403 from qgis.gui import * # noqa: F403 - from qgis.analysis import * # noqa: F403 - from qgis._3d import * # noqa: F403 except ImportError: qgis_core = None qgis_gui = None qgis_analysis = None qgis_3d = None - print('QGIS classes not available for introspection, only a partial upgrade will be performed') - -target_modules = [QtCore, - QtGui, - QtWidgets, - QtTest, - QtSql, - QtSvg, - QtXml, - QtNetwork, - QtPrintSupport, - Qsci] -if qgis_core is not None: - target_modules.extend([ - qgis_core, - qgis_gui, - qgis_analysis, - qgis_3d - ] + print( + "QGIS classes not available for introspection, only a partial upgrade will be performed" ) +target_modules = [ + QtCore, + QtGui, + QtWidgets, + QtTest, + QtSql, + QtSvg, + QtXml, + QtNetwork, + QtPrintSupport, + Qsci, +] +if qgis_core is not None: + target_modules.extend([qgis_core, qgis_gui, qgis_analysis, qgis_3d]) + # qmetatype which have been renamed qmetatype_mapping = { "Invalid": "UnknownType", @@ -155,22 +163,18 @@ } deprecated_renamed_enums = { - ('Qt', 'MidButton'): ('MouseButton', 'MiddleButton'), - ('Qt', 'TextColorRole'): ('ItemDataRole', 'ForegroundRole'), - ('Qt', 'BackgroundColorRole'): ('ItemDataRole', 'BackgroundRole'), - ('QPainter', 'HighQualityAntialiasing'): ('RenderHint', 'Antialiasing'), + ("Qt", "MidButton"): ("MouseButton", "MiddleButton"), + ("Qt", "TextColorRole"): ("ItemDataRole", "ForegroundRole"), + ("Qt", "BackgroundColorRole"): ("ItemDataRole", "BackgroundRole"), + ("QPainter", "HighQualityAntialiasing"): ("RenderHint", "Antialiasing"), } -rename_function_attributes = { - 'exec_': 'exec' -} +rename_function_attributes = {"exec_": "exec"} -rename_function_definitions = { - 'exec_': 'exec' -} +rename_function_definitions = {"exec_": "exec"} import_warnings = { - 'QRegExp': 'QRegExp is removed in Qt6, please use QRegularExpression for Qt5/Qt6 compatibility' + "QRegExp": "QRegExp is removed in Qt6, please use QRegularExpression for Qt5/Qt6 compatibility" } # { (class, enum_value) : enum_name } @@ -180,7 +184,7 @@ def fix_file(filename: str, qgis3_compat: bool) -> int: - with open(filename, encoding='UTF-8') as f: + with open(filename, encoding="UTF-8") as f: contents = f.read() fix_qvariant_type = [] # QVariant.Int, QVariant.Double ... @@ -199,8 +203,11 @@ def fix_file(filename: str, qgis3_compat: bool) -> int: object_types = {} def visit_assign(_node: ast.Assign, _parent): - if isinstance(_node.value, ast.Call) and isinstance(_node.value.func, - ast.Name) and _node.value.func.id in ('QFontMetrics', 'QFontMetricsF'): + if ( + isinstance(_node.value, ast.Call) + and isinstance(_node.value.func, ast.Name) + and _node.value.func.id in ("QFontMetrics", "QFontMetricsF") + ): object_types[_node.targets[0].id] = _node.value.func.id def visit_call(_node: ast.Call, _parent): @@ -208,161 +215,202 @@ def visit_call(_node: ast.Call, _parent): if _node.func.attr in rename_function_attributes: attr_node = _node.func member_renames[ - Offset(_node.func.lineno, attr_node.end_col_offset - len( - _node.func.attr) - 1)] = rename_function_attributes[ - _node.func.attr] - if _node.func.attr == 'addAction': + Offset( + _node.func.lineno, + attr_node.end_col_offset - len(_node.func.attr) - 1, + ) + ] = rename_function_attributes[_node.func.attr] + if _node.func.attr == "addAction": if len(_node.args) >= 4: sys.stderr.write( - f'{filename}:{_node.lineno}:{_node.col_offset} WARNING: fragile call to addAction. Use my_action = QAction(...), obj.addAction(my_action) instead.\n') - if _node.func.attr == 'desktop': + f"{filename}:{_node.lineno}:{_node.col_offset} WARNING: fragile call to addAction. Use my_action = QAction(...), obj.addAction(my_action) instead.\n" + ) + if _node.func.attr == "desktop": if len(_node.args) == 0: sys.stderr.write( - f'{filename}:{_node.lineno}:{_node.col_offset} WARNING: QDesktopWidget is deprecated and removed in Qt6. Replace with alternative approach instead.\n') + f"{filename}:{_node.lineno}:{_node.col_offset} WARNING: QDesktopWidget is deprecated and removed in Qt6. Replace with alternative approach instead.\n" + ) - if isinstance(_node.func, ast.Name) and _node.func.id == 'QVariant': + if isinstance(_node.func, ast.Name) and _node.func.id == "QVariant": if not _node.args: - extra_imports['qgis.core'].update({'NULL'}) + extra_imports["qgis.core"].update({"NULL"}) def _invalid_qvariant_to_null(start_index: int, tokens): - assert tokens[start_index].src == 'QVariant' - assert tokens[start_index + 1].src == '(' - assert tokens[start_index + 2].src == ')' + assert tokens[start_index].src == "QVariant" + assert tokens[start_index + 1].src == "(" + assert tokens[start_index + 2].src == ")" - tokens[start_index] = tokens[start_index]._replace(src='NULL') + tokens[start_index] = tokens[start_index]._replace(src="NULL") for i in range(start_index + 1, start_index + 3): - tokens[i] = tokens[i]._replace(src='') - - custom_updates[Offset(_node.lineno, - _node.col_offset)] = _invalid_qvariant_to_null - elif len(_node.args) == 1 and isinstance(_node.args[0], ast.Attribute) and isinstance(_node.args[0].value, ast.Name) and _node.args[0].value.id == 'QVariant': - extra_imports['qgis.core'].update({'NULL'}) + tokens[i] = tokens[i]._replace(src="") + + custom_updates[Offset(_node.lineno, _node.col_offset)] = ( + _invalid_qvariant_to_null + ) + elif ( + len(_node.args) == 1 + and isinstance(_node.args[0], ast.Attribute) + and isinstance(_node.args[0].value, ast.Name) + and _node.args[0].value.id == "QVariant" + ): + extra_imports["qgis.core"].update({"NULL"}) def _fix_null_qvariant(start_index: int, tokens): - assert tokens[start_index].src == 'QVariant' - assert tokens[start_index + 1].src == '(' - assert tokens[start_index + 2].src == 'QVariant' - assert tokens[start_index + 3].src == '.' - assert tokens[start_index + 5].src == ')' + assert tokens[start_index].src == "QVariant" + assert tokens[start_index + 1].src == "(" + assert tokens[start_index + 2].src == "QVariant" + assert tokens[start_index + 3].src == "." + assert tokens[start_index + 5].src == ")" - tokens[start_index] = tokens[start_index]._replace(src='NULL') + tokens[start_index] = tokens[start_index]._replace(src="NULL") for i in range(start_index + 1, start_index + 6): - tokens[i] = tokens[i]._replace(src='') + tokens[i] = tokens[i]._replace(src="") - custom_updates[Offset(_node.lineno, - _node.col_offset)] = _fix_null_qvariant - elif isinstance(_node.func, ast.Name) and _node.func.id == 'QDateTime': + custom_updates[Offset(_node.lineno, _node.col_offset)] = ( + _fix_null_qvariant + ) + elif isinstance(_node.func, ast.Name) and _node.func.id == "QDateTime": if len(_node.args) == 8: # QDateTime(yyyy, mm, dd, hh, MM, ss, ms, ts) doesn't work anymore, # so port to more reliable QDateTime(QDate, QTime, ts) form - extra_imports['qgis.PyQt.QtCore'].update({'QDate', 'QTime'}) + extra_imports["qgis.PyQt.QtCore"].update({"QDate", "QTime"}) def _fix_qdatetime_construct(start_index: int, tokens): i = start_index + 1 - assert tokens[i].src == '(' - tokens[i] = tokens[i]._replace(src='(QDate(') - while tokens[i].offset < Offset(_node.args[2].lineno, _node.args[2].col_offset): + assert tokens[i].src == "(" + tokens[i] = tokens[i]._replace(src="(QDate(") + while tokens[i].offset < Offset( + _node.args[2].lineno, _node.args[2].col_offset + ): i += 1 - assert tokens[i + 1].src == ',' + assert tokens[i + 1].src == "," i += 1 - tokens[i] = tokens[i]._replace(src='), QTime(') + tokens[i] = tokens[i]._replace(src="), QTime(") i += 1 while not tokens[i].src.strip(): - tokens[i] = tokens[i]._replace(src='') + tokens[i] = tokens[i]._replace(src="") i += 1 - while tokens[i].offset < Offset(_node.args[6].lineno, _node.args[6].col_offset): + while tokens[i].offset < Offset( + _node.args[6].lineno, _node.args[6].col_offset + ): i += 1 i += 1 - assert tokens[i].src == ',' - tokens[i] = tokens[i]._replace(src='),') - - custom_updates[Offset(_node.lineno, _node.col_offset)] = _fix_qdatetime_construct - elif len(_node.args) == 1 and isinstance(_node.args[0], ast.Call) and _node.args[0].func.id == 'QDate': + assert tokens[i].src == "," + tokens[i] = tokens[i]._replace(src="),") + + custom_updates[Offset(_node.lineno, _node.col_offset)] = ( + _fix_qdatetime_construct + ) + elif ( + len(_node.args) == 1 + and isinstance(_node.args[0], ast.Call) + and _node.args[0].func.id == "QDate" + ): # QDateTime(QDate(..)) doesn't work anymore, # so port to more reliable QDateTime(QDate(...), QTime(0,0,0)) form - extra_imports['qgis.PyQt.QtCore'].update({'QTime'}) + extra_imports["qgis.PyQt.QtCore"].update({"QTime"}) def _fix_qdatetime_construct(start_index: int, tokens): - assert tokens[start_index].src == 'QDateTime' - assert tokens[start_index + 1].src == '(' - assert tokens[start_index + 2].src == 'QDate' - assert tokens[start_index + 3].src == '(' + assert tokens[start_index].src == "QDateTime" + assert tokens[start_index + 1].src == "(" + assert tokens[start_index + 2].src == "QDate" + assert tokens[start_index + 3].src == "(" i = start_index + 4 - while tokens[i].offset < Offset(_node.args[0].end_lineno, - _node.args[0].end_col_offset): + while tokens[i].offset < Offset( + _node.args[0].end_lineno, _node.args[0].end_col_offset + ): i += 1 - assert tokens[i - 1].src == ')' - tokens[i - 1] = tokens[i - 1]._replace(src='), QTime(0, 0, 0)') + assert tokens[i - 1].src == ")" + tokens[i - 1] = tokens[i - 1]._replace(src="), QTime(0, 0, 0)") - custom_updates[Offset(_node.lineno, - _node.col_offset)] = _fix_qdatetime_construct + custom_updates[Offset(_node.lineno, _node.col_offset)] = ( + _fix_qdatetime_construct + ) def visit_attribute(_node: ast.Attribute, _parent): if isinstance(_node.value, ast.Name): - if _node.value.id == 'qApp': - token_renames[Offset(_node.value.lineno, _node.value.col_offset)] = 'QApplication.instance()' - extra_imports['qgis.PyQt.QtWidgets'].update({'QApplication'}) - removed_imports['qgis.PyQt.QtWidgets'].update({'qApp'}) - if _node.value.id == 'QVariant' and _node.attr == 'Type': + if _node.value.id == "qApp": + token_renames[Offset(_node.value.lineno, _node.value.col_offset)] = ( + "QApplication.instance()" + ) + extra_imports["qgis.PyQt.QtWidgets"].update({"QApplication"}) + removed_imports["qgis.PyQt.QtWidgets"].update({"qApp"}) + if _node.value.id == "QVariant" and _node.attr == "Type": + def _replace_qvariant_type(start_index: int, tokens): # QVariant.Type.XXX doesn't exist, it should be QVariant.XXX - assert tokens[start_index].src == 'QVariant' - assert tokens[start_index + 1].src == '.' - assert tokens[start_index + 2].src == 'Type' - assert tokens[start_index + 3].src == '.' - - tokens[start_index + 2] = tokens[start_index + 2]._replace(src='') - tokens[start_index + 3] = tokens[start_index + 3]._replace( - src='') - - custom_updates[Offset(node.lineno, node.col_offset)] = _replace_qvariant_type - if object_types.get(_node.value.id) in ('QFontMetrics', 'QFontMetricsF'): - if _node.attr == 'width': + assert tokens[start_index].src == "QVariant" + assert tokens[start_index + 1].src == "." + assert tokens[start_index + 2].src == "Type" + assert tokens[start_index + 3].src == "." + + tokens[start_index + 2] = tokens[start_index + 2]._replace(src="") + tokens[start_index + 3] = tokens[start_index + 3]._replace(src="") + + custom_updates[Offset(node.lineno, node.col_offset)] = ( + _replace_qvariant_type + ) + if object_types.get(_node.value.id) in ("QFontMetrics", "QFontMetricsF"): + if _node.attr == "width": sys.stderr.write( - f'{filename}:{_node.lineno}:{_node.col_offset} WARNING: QFontMetrics.width() ' - 'has been removed in Qt6. Use QFontMetrics.horizontalAdvance() if plugin can ' - 'safely require Qt >= 5.11, or QFontMetrics.boundingRect().width() otherwise.\n') + f"{filename}:{_node.lineno}:{_node.col_offset} WARNING: QFontMetrics.width() " + "has been removed in Qt6. Use QFontMetrics.horizontalAdvance() if plugin can " + "safely require Qt >= 5.11, or QFontMetrics.boundingRect().width() otherwise.\n" + ) elif isinstance(_node.value, ast.Call): - if (_node.attr == 'width' and (( - isinstance(_node.value.func, ast.Attribute) and - _node.value.func.attr == 'fontMetrics') - or (isinstance(_node.value.func, ast.Name) and - _node.value.func.id == 'QFontMetrics'))): + if _node.attr == "width" and ( + ( + isinstance(_node.value.func, ast.Attribute) + and _node.value.func.attr == "fontMetrics" + ) + or ( + isinstance(_node.value.func, ast.Name) + and _node.value.func.id == "QFontMetrics" + ) + ): sys.stderr.write( - f'{filename}:{_node.lineno}:{_node.col_offset} WARNING: QFontMetrics.width() ' - 'has been removed in Qt6. Use QFontMetrics.horizontalAdvance() if plugin can ' - 'safely require Qt >= 5.11, or QFontMetrics.boundingRect().width() otherwise.\n') + f"{filename}:{_node.lineno}:{_node.col_offset} WARNING: QFontMetrics.width() " + "has been removed in Qt6. Use QFontMetrics.horizontalAdvance() if plugin can " + "safely require Qt >= 5.11, or QFontMetrics.boundingRect().width() otherwise.\n" + ) def visit_subscript(_node: ast.Subscript, _parent): if isinstance(_node.value, ast.Attribute): - if (_node.value.attr == 'activated' and - isinstance(_node.slice, ast.Name) and - _node.slice.id == 'str'): + if ( + _node.value.attr == "activated" + and isinstance(_node.slice, ast.Name) + and _node.slice.id == "str" + ): sys.stderr.write( - f'{filename}:{_node.lineno}:{_node.col_offset} WARNING: activated[str] ' - 'has been removed in Qt6. Consider using QComboBox.activated instead if the string is not required, ' - 'or QComboBox.textActivated if the plugin can ' - 'safely require Qt >= 5.14. Otherwise conditional Qt version code will need to be introduced.\n') + f"{filename}:{_node.lineno}:{_node.col_offset} WARNING: activated[str] " + "has been removed in Qt6. Consider using QComboBox.activated instead if the string is not required, " + "or QComboBox.textActivated if the plugin can " + "safely require Qt >= 5.14. Otherwise conditional Qt version code will need to be introduced.\n" + ) def visit_import(_node: ast.ImportFrom, _parent): import_offsets[Offset(node.lineno, node.col_offset)] = ( - node.module, set(name.name for name in node.names), node.end_lineno, - node.end_col_offset) + node.module, + {name.name for name in node.names}, + node.end_lineno, + node.end_col_offset, + ) imported_modules.add(node.module) for name in node.names: if name.name in import_warnings: - print(f'{filename}: {import_warnings[name.name]}') - if name.name == 'resources_rc': + print(f"{filename}: {import_warnings[name.name]}") + if name.name == "resources_rc": sys.stderr.write( - f'{filename}:{_node.lineno}:{_node.col_offset} WARNING: support for compiled resources ' - 'is removed in Qt6. Directly load icon resources by file path and load UI fields using ' - 'uic.loadUiType by file path instead.\n') - if _node.module == 'qgis.PyQt.Qt': - extra_imports['qgis.PyQt.QtCore'].update({'Qt'}) - removed_imports['qgis.PyQt.Qt'].update({'Qt'}) + f"{filename}:{_node.lineno}:{_node.col_offset} WARNING: support for compiled resources " + "is removed in Qt6. Directly load icon resources by file path and load UI fields using " + "uic.loadUiType by file path instead.\n" + ) + if _node.module == "qgis.PyQt.Qt": + extra_imports["qgis.PyQt.QtCore"].update({"Qt"}) + removed_imports["qgis.PyQt.Qt"].update({"Qt"}) tree = ast.parse(contents, filename=filename) for parent in ast.walk(tree): @@ -370,8 +418,12 @@ def visit_import(_node: ast.ImportFrom, _parent): if isinstance(node, ast.ImportFrom): visit_import(node, parent) - if (not qgis3_compat and isinstance(node, ast.Attribute) and isinstance(node.value, ast.Name) - and node.value.id == "QVariant"): + if ( + not qgis3_compat + and isinstance(node, ast.Attribute) + and isinstance(node.value, ast.Name) + and node.value.id == "QVariant" + ): fix_qvariant_type.append(Offset(node.lineno, node.col_offset)) if isinstance(node, ast.Call): @@ -383,15 +435,22 @@ def visit_import(_node: ast.ImportFrom, _parent): elif isinstance(node, ast.Assign): visit_assign(node, parent) - if isinstance(node, ast.FunctionDef) and node.name in rename_function_definitions: - function_def_renames[ - Offset(node.lineno, node.col_offset)] = rename_function_definitions[node.name] - - if (isinstance(node, ast.Attribute) and isinstance(node.value, ast.Name) - and (node.value.id, node.attr) in ambiguous_enums): + if ( + isinstance(node, ast.FunctionDef) + and node.name in rename_function_definitions + ): + function_def_renames[Offset(node.lineno, node.col_offset)] = ( + rename_function_definitions[node.name] + ) + + if ( + isinstance(node, ast.Attribute) + and isinstance(node.value, ast.Name) + and (node.value.id, node.attr) in ambiguous_enums + ): disambiguated = False try: - actual = eval(f'{node.value.id}.{node.attr}') + actual = eval(f"{node.value.id}.{node.attr}") obj = globals()[node.value.id] if isinstance(obj, type): for attr_name in dir(obj): @@ -399,9 +458,10 @@ def visit_import(_node: ast.ImportFrom, _parent): if attr is actual.__class__: # print(f'Found alias {node.value.id}.{attr_name}') disambiguated = True - fix_qt_enums[ - Offset(node.lineno, node.col_offset)] = ( - node.value.id, attr_name, node.attr + fix_qt_enums[Offset(node.lineno, node.col_offset)] = ( + node.value.id, + attr_name, + node.attr, ) break @@ -409,37 +469,59 @@ def visit_import(_node: ast.ImportFrom, _parent): pass if not disambiguated: - possible_values = [f'{node.value.id}.{e}.{node.attr}' for e - in ambiguous_enums[ - (node.value.id, node.attr)]] - sys.stderr.write(f'{filename}:{node.lineno}:{node.col_offset} WARNING: ambiguous enum, cannot fix: {node.value.id}.{node.attr}. Could be: {", ".join(possible_values)}\n') - elif (isinstance(node, ast.Attribute) and isinstance(node.value, ast.Name) and not isinstance(parent, ast.Attribute) - and (node.value.id, node.attr) in qt_enums): - fix_qt_enums[Offset(node.lineno, node.col_offset)] = (node.value.id, qt_enums[(node.value.id, node.attr)], node.attr) - - if (isinstance(node, ast.Attribute) and isinstance(node.value, ast.Name) - and (node.value.id, node.attr) in deprecated_renamed_enums): + possible_values = [ + f"{node.value.id}.{e}.{node.attr}" + for e in ambiguous_enums[(node.value.id, node.attr)] + ] + sys.stderr.write( + f'{filename}:{node.lineno}:{node.col_offset} WARNING: ambiguous enum, cannot fix: {node.value.id}.{node.attr}. Could be: {", ".join(possible_values)}\n' + ) + elif ( + isinstance(node, ast.Attribute) + and isinstance(node.value, ast.Name) + and not isinstance(parent, ast.Attribute) + and (node.value.id, node.attr) in qt_enums + ): + fix_qt_enums[Offset(node.lineno, node.col_offset)] = ( + node.value.id, + qt_enums[(node.value.id, node.attr)], + node.attr, + ) + + if ( + isinstance(node, ast.Attribute) + and isinstance(node.value, ast.Name) + and (node.value.id, node.attr) in deprecated_renamed_enums + ): rename_qt_enums.append(Offset(node.lineno, node.col_offset)) - elif (isinstance(node, ast.ImportFrom) and node.module and node.module.startswith("PyQt5.")): + elif ( + isinstance(node, ast.ImportFrom) + and node.module + and node.module.startswith("PyQt5.") + ): fix_pyqt_import.append(Offset(node.lineno, node.col_offset)) for module, classes in extra_imports.items(): if module not in imported_modules: - class_import = ', '.join(classes) - import_statement = f'from {module} import {class_import}' - print(f'{filename}: Missing import, manually add \n\t{import_statement}') - - if not any([fix_qvariant_type, - fix_pyqt_import, - fix_qt_enums, - rename_qt_enums, - member_renames, - function_def_renames, - custom_updates, - extra_imports, - removed_imports, - token_renames]): + class_import = ", ".join(classes) + import_statement = f"from {module} import {class_import}" + print(f"{filename}: Missing import, manually add \n\t{import_statement}") + + if not any( + [ + fix_qvariant_type, + fix_pyqt_import, + fix_qt_enums, + rename_qt_enums, + member_renames, + function_def_renames, + custom_updates, + extra_imports, + removed_imports, + token_renames, + ] + ): return 0 tokens = src_to_tokens(contents) @@ -447,12 +529,12 @@ def visit_import(_node: ast.ImportFrom, _parent): if token.offset in import_offsets: end_import_offset = Offset(*import_offsets[token.offset][-2:]) del import_offsets[token.offset] - assert tokens[i].src == 'from' + assert tokens[i].src == "from" token_index = i + 1 while not tokens[token_index].src.strip(): token_index += 1 - module = '' + module = "" while tokens[token_index].src.strip(): module += tokens[token_index].src token_index += 1 @@ -463,17 +545,18 @@ def visit_import(_node: ast.ImportFrom, _parent): token_index += 1 if tokens[token_index].offset == end_import_offset: break - if tokens[token_index].src.strip() in ('', ',', 'import', '(', ')'): + if tokens[token_index].src.strip() in ("", ",", "import", "(", ")"): continue import_ = tokens[token_index].src if import_ in removed_imports.get(module, set()): - tokens[token_index] = tokens[token_index]._replace(src='') + tokens[token_index] = tokens[token_index]._replace(src="") prev_token_index = token_index - 1 while True: - if tokens[prev_token_index].src.strip() in ('', ','): + if tokens[prev_token_index].src.strip() in ("", ","): tokens[prev_token_index] = tokens[ - prev_token_index]._replace(src='') + prev_token_index + ]._replace(src="") prev_token_index -= 1 else: break @@ -481,7 +564,7 @@ def visit_import(_node: ast.ImportFrom, _parent): none_forward = True current_index = prev_token_index + 1 while True: - if tokens[current_index].src in ('\n', ')'): + if tokens[current_index].src in ("\n", ")"): break elif tokens[current_index].src.strip(): none_forward = False @@ -491,7 +574,7 @@ def visit_import(_node: ast.ImportFrom, _parent): none_backward = True current_index = prev_token_index while True: - if tokens[current_index].src in ('import',): + if tokens[current_index].src in ("import",): break elif tokens[current_index].src.strip(): none_backward = False @@ -500,16 +583,19 @@ def visit_import(_node: ast.ImportFrom, _parent): if none_backward and none_forward: # no more imports from this module, remove whole import while True: - if tokens[current_index].src in ('from',): + if tokens[current_index].src in ("from",): break current_index -= 1 while True: - if tokens[current_index].src in ('\n',): + if tokens[current_index].src in ("\n",): tokens[current_index] = tokens[ - current_index]._replace(src='') + current_index + ]._replace(src="") break - tokens[current_index] = tokens[current_index]._replace(src='') + tokens[current_index] = tokens[current_index]._replace( + src="" + ) current_index += 1 else: @@ -517,16 +603,19 @@ def visit_import(_node: ast.ImportFrom, _parent): imports_to_add = extra_imports.get(module, set()) - current_imports if imports_to_add: - additional_import_string = ', '.join(imports_to_add) - if tokens[token_index - 1].src == ')': + additional_import_string = ", ".join(imports_to_add) + if tokens[token_index - 1].src == ")": token_index -= 1 - while tokens[token_index].src.strip() in ('', ',', ')'): - tokens[token_index] = tokens[token_index]._replace( - src='') + while tokens[token_index].src.strip() in ("", ",", ")"): + tokens[token_index] = tokens[token_index]._replace(src="") token_index -= 1 - tokens[token_index + 1] = tokens[token_index + 1]._replace(src=f", {additional_import_string})") + tokens[token_index + 1] = tokens[token_index + 1]._replace( + src=f", {additional_import_string})" + ) else: - tokens[token_index] = tokens[token_index]._replace(src=f", {additional_import_string}{tokens[token_index].src}") + tokens[token_index] = tokens[token_index]._replace( + src=f", {additional_import_string}{tokens[token_index].src}" + ) if token.offset in fix_qvariant_type: assert tokens[i].src == "QVariant" @@ -544,29 +633,34 @@ def visit_import(_node: ast.ImportFrom, _parent): tokens[i + 2] = tokens[i + 2]._replace(src="qgis.PyQt") if token.offset in function_def_renames and tokens[i].src == "def": - tokens[i + 2] = tokens[i + 2]._replace(src=function_def_renames[token.offset]) + tokens[i + 2] = tokens[i + 2]._replace( + src=function_def_renames[token.offset] + ) if token.offset in token_renames: tokens[i] = tokens[i]._replace(src=token_renames[token.offset]) if token.offset in member_renames: counter = i - while tokens[counter].src != '.': + while tokens[counter].src != ".": counter += 1 - tokens[counter + 1] = tokens[counter + 1]._replace(src=member_renames[token.offset]) + tokens[counter + 1] = tokens[counter + 1]._replace( + src=member_renames[token.offset] + ) if token.offset in fix_qt_enums: assert tokens[i + 1].src == "." _class, enum_name, value = fix_qt_enums[token.offset] # make sure we CAN import enum! try: - eval(f'{_class}.{enum_name}.{value}') + eval(f"{_class}.{enum_name}.{value}") tokens[i + 2] = tokens[i + 2]._replace( - src=f"{enum_name}.{tokens[i + 2].src}") + src=f"{enum_name}.{tokens[i + 2].src}" + ) except AttributeError: # let's see if we can find what the replacement should be automatically... # print(f'Trying to find {_class}.{value}.') - actual = eval(f'{_class}.{value}') + actual = eval(f"{_class}.{value}") # print(f'Trying to find aliases for {actual.__class__}.') obj = globals()[_class] recovered = False @@ -578,13 +672,15 @@ def visit_import(_node: ast.ImportFrom, _parent): # print(f'Found alias {_class}.{attr_name}') recovered = True tokens[i + 2] = tokens[i + 2]._replace( - src=f"{attr_name}.{tokens[i + 2].src}") + src=f"{attr_name}.{tokens[i + 2].src}" + ) except AttributeError: continue if not recovered: sys.stderr.write( - f'{filename}:{token.line}:{token.utf8_byte_offset} ERROR: wanted to replace with {_class}.{enum_name}.{value}, but does not exist\n') + f"{filename}:{token.line}:{token.utf8_byte_offset} ERROR: wanted to replace with {_class}.{enum_name}.{value}, but does not exist\n" + ) continue if token.offset in rename_qt_enums: @@ -594,7 +690,7 @@ def visit_import(_node: ast.ImportFrom, _parent): tokens[i + 2] = tokens[i + 2]._replace(src=f"{enum_name[0]}.{enum_name[1]}") new_contents = tokens_to_src(tokens) - with open(filename, 'w') as f: + with open(filename, "w") as f: f.write(new_contents) return new_contents != contents @@ -609,16 +705,16 @@ def get_class_enums(item): def all_subclasses(cls): if cls is object: return set() - return {cls}.union( - s for c in cls.__subclasses__() for s in all_subclasses(c)) + return {cls}.union(s for c in cls.__subclasses__() for s in all_subclasses(c)) + matched_classes = {item}.union(all_subclasses(item)) for key, value in item.__dict__.items(): - if key == 'baseClass': + if key == "baseClass": continue - if inspect.isclass(value) and type(value).__name__ == 'EnumType': + if inspect.isclass(value) and type(value).__name__ == "EnumType": for ekey, evalue in value.__dict__.items(): for matched_class in matched_classes: if isinstance(evalue, value): @@ -634,18 +730,28 @@ def all_subclasses(cls): pass if (matched_class.__name__, ekey) in ambiguous_enums: - if value.__name__ not in ambiguous_enums[(matched_class.__name__, ekey)]: - ambiguous_enums[(matched_class.__name__, ekey)].add(value.__name__) + if ( + value.__name__ + not in ambiguous_enums[(matched_class.__name__, ekey)] + ): + ambiguous_enums[(matched_class.__name__, ekey)].add( + value.__name__ + ) continue existing_entry = qt_enums.get((matched_class.__name__, ekey)) if existing_entry != value.__name__ and existing_entry: - ambiguous_enums[(matched_class.__name__, ekey)].add(existing_entry) ambiguous_enums[(matched_class.__name__, ekey)].add( - value.__name__) + existing_entry + ) + ambiguous_enums[(matched_class.__name__, ekey)].add( + value.__name__ + ) del qt_enums[(matched_class.__name__, ekey)] else: - qt_enums[(matched_class.__name__, ekey)] = f"{value.__name__}" + qt_enums[(matched_class.__name__, ekey)] = ( + f"{value.__name__}" + ) elif inspect.isclass(value): get_class_enums(value) @@ -653,9 +759,12 @@ def all_subclasses(cls): def main(argv: Sequence[str] | None = None) -> int: parser = argparse.ArgumentParser() - parser.add_argument('directory') - parser.add_argument('--qgis3-incompatible-changes', action='store_true', - help='Apply modifications that would break behavior on QGIS 3, hence code may not work on QGIS 3') + parser.add_argument("directory") + parser.add_argument( + "--qgis3-incompatible-changes", + action="store_true", + help="Apply modifications that would break behavior on QGIS 3, hence code may not work on QGIS 3", + ) args = parser.parse_args(argv) # get all scope for all qt enum @@ -666,12 +775,12 @@ def main(argv: Sequence[str] | None = None) -> int: ret = 0 for filename in glob.glob(os.path.join(args.directory, "**/*.py"), recursive=True): # print(f'Processing {filename}') - if 'auto_additions' in filename: + if "auto_additions" in filename: continue ret |= fix_file(filename, not args.qgis3_incompatible_changes) return ret -if __name__ == '__main__': +if __name__ == "__main__": raise SystemExit(main()) diff --git a/scripts/pyuic_wrapper.py b/scripts/pyuic_wrapper.py index d0f9ee92b0a1..d9963570e985 100644 --- a/scripts/pyuic_wrapper.py +++ b/scripts/pyuic_wrapper.py @@ -15,8 +15,8 @@ *************************************************************************** """ -__author__ = 'Juergen E. Fischer' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Juergen E. Fischer' +__author__ = "Juergen E. Fischer" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Juergen E. Fischer" import qgis.PyQt.uic.pyuic diff --git a/scripts/qgis_fixes/fix_absolute_import.py b/scripts/qgis_fixes/fix_absolute_import.py index 86869f5a365e..d7434a808229 100644 --- a/scripts/qgis_fixes/fix_absolute_import.py +++ b/scripts/qgis_fixes/fix_absolute_import.py @@ -1,4 +1,6 @@ -from libfuturize.fixes.fix_absolute_import import FixAbsoluteImport as FixAbsoluteImportOrig +from libfuturize.fixes.fix_absolute_import import ( + FixAbsoluteImport as FixAbsoluteImportOrig, +) class FixAbsoluteImport(FixAbsoluteImportOrig): diff --git a/scripts/qgis_fixes/fix_future_standard_library_urllib.py b/scripts/qgis_fixes/fix_future_standard_library_urllib.py index cf3cfdc37938..25fd963f226d 100644 --- a/scripts/qgis_fixes/fix_future_standard_library_urllib.py +++ b/scripts/qgis_fixes/fix_future_standard_library_urllib.py @@ -1 +1,3 @@ -from libfuturize.fixes.fix_future_standard_library_urllib import FixFutureStandardLibraryUrllib +from libfuturize.fixes.fix_future_standard_library_urllib import ( + FixFutureStandardLibraryUrllib, +) diff --git a/scripts/qgis_fixes/fix_print_with_import.py b/scripts/qgis_fixes/fix_print_with_import.py index 1821829762a2..3e8451431eee 100644 --- a/scripts/qgis_fixes/fix_print_with_import.py +++ b/scripts/qgis_fixes/fix_print_with_import.py @@ -1,8 +1,11 @@ -from libfuturize.fixes.fix_print_with_import import FixPrintWithImport as FixPrintWithImportOrig -from lib2to3.fixer_util import Node, Leaf, syms, find_indentation - import re +from lib2to3.fixer_util import Leaf, Node, find_indentation, syms + +from libfuturize.fixes.fix_print_with_import import ( + FixPrintWithImport as FixPrintWithImportOrig, +) + class FixPrintWithImport(FixPrintWithImportOrig): @@ -19,6 +22,6 @@ def transform(self, node, results): indentation = find_indentation(node) r.prefix = "# fix_print_with_import\n" + indentation else: - r.prefix = re.sub('([ \t]*$)', r'\1# fix_print_with_import\n\1', r.prefix) + r.prefix = re.sub("([ \t]*$)", r"\1# fix_print_with_import\n\1", r.prefix) return r diff --git a/scripts/qgis_fixes/fix_pyqt.py b/scripts/qgis_fixes/fix_pyqt.py index 54b306ce4e3d..1696c6cbd681 100644 --- a/scripts/qgis_fixes/fix_pyqt.py +++ b/scripts/qgis_fixes/fix_pyqt.py @@ -1,391 +1,422 @@ """Migrate imports of PyQt4 to PyQt wrapper """ + # Author: Juergen E. Fischer # Adapted from fix_urllib -# Local imports -from lib2to3.fixes.fix_imports import alternates, FixImports from lib2to3 import fixer_base -from lib2to3.fixer_util import (Name, Comma, FromImport, Newline, - find_indentation, Node, syms, Leaf) +from lib2to3.fixer_util import ( + Comma, + FromImport, + Leaf, + Name, + Newline, + Node, + find_indentation, + syms, +) + +# Local imports +from lib2to3.fixes.fix_imports import FixImports, alternates MAPPING = { "PyQt4.QtGui": [ - ("qgis.PyQt.QtGui", [ - "QIcon", - "QCursor", - "QColor", - "QDesktopServices", - "QFont", - "QFontMetrics", - "QKeySequence", - "QStandardItemModel", - "QStandardItem", - "QClipboard", - "QPixmap", - "QDoubleValidator", - "QPainter", - "QPen", - "QBrush", - "QPalette", - "QPainterPath", - "QImage", - "QPolygonF", - "QFontMetricsF", - "QGradient", - "QIntValidator", - ]), - ("qgis.PyQt.QtWidgets", [ - "QAbstractButton", - "QAbstractGraphicsShapeItem", - "QAbstractItemDelegate", - "QAbstractItemView", - "QAbstractScrollArea", - "QAbstractSlider", - "QAbstractSpinBox", - "QAbstractTableModel", - "QAction", - "QActionGroup", - "QApplication", - "QBoxLayout", - "QButtonGroup", - "QCalendarWidget", - "QCheckBox", - "QColorDialog", - "QColumnView", - "QComboBox", - "QCommandLinkButton", - "QCommonStyle", - "QCompleter", - "QDataWidgetMapper", - "QDateEdit", - "QDateTimeEdit", - "QDesktopWidget", - "QDial", - "QDialog", - "QDialogButtonBox", - "QDirModel", - "QDockWidget", - "QDoubleSpinBox", - "QErrorMessage", - "QFileDialog", - "QFileIconProvider", - "QFileSystemModel", - "QFocusFrame", - "QFontComboBox", - "QFontDialog", - "QFormLayout", - "QFrame", - "QGesture", - "QGestureEvent", - "QGestureRecognizer", - "QGraphicsAnchor", - "QGraphicsAnchorLayout", - "QGraphicsBlurEffect", - "QGraphicsColorizeEffect", - "QGraphicsDropShadowEffect", - "QGraphicsEffect", - "QGraphicsEllipseItem", - "QGraphicsGridLayout", - "QGraphicsItem", - "QGraphicsItemGroup", - "QGraphicsLayout", - "QGraphicsLayoutItem", - "QGraphicsLineItem", - "QGraphicsLinearLayout", - "QGraphicsObject", - "QGraphicsOpacityEffect", - "QGraphicsPathItem", - "QGraphicsPixmapItem", - "QGraphicsPolygonItem", - "QGraphicsProxyWidget", - "QGraphicsRectItem", - "QGraphicsRotation", - "QGraphicsScale", - "QGraphicsScene", - "QGraphicsSceneContextMenuEvent", - "QGraphicsSceneDragDropEvent", - "QGraphicsSceneEvent", - "QGraphicsSceneHelpEvent", - "QGraphicsSceneHoverEvent", - "QGraphicsSceneMouseEvent", - "QGraphicsSceneMoveEvent", - "QGraphicsSceneResizeEvent", - "QGraphicsSceneWheelEvent", - "QGraphicsSimpleTextItem", - "QGraphicsTextItem", - "QGraphicsTransform", - "QGraphicsView", - "QGraphicsWidget", - "QGridLayout", - "QGroupBox", - "QHBoxLayout", - "QHeaderView", - "QInputDialog", - "QItemDelegate", - "QItemEditorCreatorBase", - "QItemEditorFactory", - "QKeyEventTransition", - "QLCDNumber", - "QLabel", - "QLayout", - "QLayoutItem", - "QLineEdit", - "QListView", - "QListWidget", - "QListWidgetItem", - "QMainWindow", - "QMdiArea", - "QMdiSubWindow", - "QMenu", - "QMenuBar", - "QMessageBox", - "QMouseEventTransition", - "QPanGesture", - "QPinchGesture", - "QPlainTextDocumentLayout", - "QPlainTextEdit", - "QProgressBar", - "QProgressDialog", - "QPushButton", - "QRadioButton", - "QRubberBand", - "QScrollArea", - "QScrollBar", - "QShortcut", - "QSizeGrip", - "QSizePolicy", - "QSlider", - "QSpacerItem", - "QSpinBox", - "QSplashScreen", - "QSplitter", - "QSplitterHandle", - "QStackedLayout", - "QStackedWidget", - "QStatusBar", - "QStyle", - "QStyleFactory", - "QStyleHintReturn", - "QStyleHintReturnMask", - "QStyleHintReturnVariant", - "QStyleOption", - "QStyleOptionButton", - "QStyleOptionComboBox", - "QStyleOptionComplex", - "QStyleOptionDockWidget", - "QStyleOptionFocusRect", - "QStyleOptionFrame", - "QStyleOptionGraphicsItem", - "QStyleOptionGroupBox", - "QStyleOptionHeader", - "QStyleOptionMenuItem", - "QStyleOptionProgressBar", - "QStyleOptionRubberBand", - "QStyleOptionSizeGrip", - "QStyleOptionSlider", - "QStyleOptionSpinBox", - "QStyleOptionTab", - "QStyleOptionTabBarBase", - "QStyleOptionTabWidgetFrame", - "QStyleOptionTitleBar", - "QStyleOptionToolBar", - "QStyleOptionToolBox", - "QStyleOptionToolButton", - "QStyleOptionViewItem", - "QStylePainter", - "QStyledItemDelegate", - "QSwipeGesture", - "QSystemTrayIcon", - "QTabBar", - "QTabWidget", - "QTableView", - "QTableWidget", - "QTableWidgetItem", - "QTableWidgetSelectionRange", - "QTapAndHoldGesture", - "QTapGesture", - "QTextBrowser", - "QTextEdit", - "QTimeEdit", - "QToolBar", - "QToolBox", - "QToolButton", - "QToolTip", - "QTreeView", - "QTreeWidget", - "QTreeWidgetItem", - "QTreeWidgetItemIterator", - "QUndoCommand", - "QUndoGroup", - "QUndoStack", - "QUndoView", - "QVBoxLayout", - "QWhatsThis", - "QWidget", - "QWidgetAction", - "QWidgetItem", - "QWizard", - "QWizardPage", - "qApp", - "qDrawBorderPixmap", - "qDrawPlainRect", - "qDrawShadeLine", - "qDrawShadePanel", - "qDrawShadeRect", - "qDrawWinButton", - "qDrawWinPanel", - ]), - ("qgis.PyQt.QtPrintSupport", [ - "QPrinter", - "QAbstractPrintDialog", - "QPageSetupDialog", - "QPrintDialog", - "QPrintEngine", - "QPrintPreviewDialog", - "QPrintPreviewWidget", - "QPrinterInfo", - ]), - ("qgis.PyQt.QtCore", [ - "QItemSelectionModel", - "QSortFilterProxyModel", - ]), + ( + "qgis.PyQt.QtGui", + [ + "QIcon", + "QCursor", + "QColor", + "QDesktopServices", + "QFont", + "QFontMetrics", + "QKeySequence", + "QStandardItemModel", + "QStandardItem", + "QClipboard", + "QPixmap", + "QDoubleValidator", + "QPainter", + "QPen", + "QBrush", + "QPalette", + "QPainterPath", + "QImage", + "QPolygonF", + "QFontMetricsF", + "QGradient", + "QIntValidator", + ], + ), + ( + "qgis.PyQt.QtWidgets", + [ + "QAbstractButton", + "QAbstractGraphicsShapeItem", + "QAbstractItemDelegate", + "QAbstractItemView", + "QAbstractScrollArea", + "QAbstractSlider", + "QAbstractSpinBox", + "QAbstractTableModel", + "QAction", + "QActionGroup", + "QApplication", + "QBoxLayout", + "QButtonGroup", + "QCalendarWidget", + "QCheckBox", + "QColorDialog", + "QColumnView", + "QComboBox", + "QCommandLinkButton", + "QCommonStyle", + "QCompleter", + "QDataWidgetMapper", + "QDateEdit", + "QDateTimeEdit", + "QDesktopWidget", + "QDial", + "QDialog", + "QDialogButtonBox", + "QDirModel", + "QDockWidget", + "QDoubleSpinBox", + "QErrorMessage", + "QFileDialog", + "QFileIconProvider", + "QFileSystemModel", + "QFocusFrame", + "QFontComboBox", + "QFontDialog", + "QFormLayout", + "QFrame", + "QGesture", + "QGestureEvent", + "QGestureRecognizer", + "QGraphicsAnchor", + "QGraphicsAnchorLayout", + "QGraphicsBlurEffect", + "QGraphicsColorizeEffect", + "QGraphicsDropShadowEffect", + "QGraphicsEffect", + "QGraphicsEllipseItem", + "QGraphicsGridLayout", + "QGraphicsItem", + "QGraphicsItemGroup", + "QGraphicsLayout", + "QGraphicsLayoutItem", + "QGraphicsLineItem", + "QGraphicsLinearLayout", + "QGraphicsObject", + "QGraphicsOpacityEffect", + "QGraphicsPathItem", + "QGraphicsPixmapItem", + "QGraphicsPolygonItem", + "QGraphicsProxyWidget", + "QGraphicsRectItem", + "QGraphicsRotation", + "QGraphicsScale", + "QGraphicsScene", + "QGraphicsSceneContextMenuEvent", + "QGraphicsSceneDragDropEvent", + "QGraphicsSceneEvent", + "QGraphicsSceneHelpEvent", + "QGraphicsSceneHoverEvent", + "QGraphicsSceneMouseEvent", + "QGraphicsSceneMoveEvent", + "QGraphicsSceneResizeEvent", + "QGraphicsSceneWheelEvent", + "QGraphicsSimpleTextItem", + "QGraphicsTextItem", + "QGraphicsTransform", + "QGraphicsView", + "QGraphicsWidget", + "QGridLayout", + "QGroupBox", + "QHBoxLayout", + "QHeaderView", + "QInputDialog", + "QItemDelegate", + "QItemEditorCreatorBase", + "QItemEditorFactory", + "QKeyEventTransition", + "QLCDNumber", + "QLabel", + "QLayout", + "QLayoutItem", + "QLineEdit", + "QListView", + "QListWidget", + "QListWidgetItem", + "QMainWindow", + "QMdiArea", + "QMdiSubWindow", + "QMenu", + "QMenuBar", + "QMessageBox", + "QMouseEventTransition", + "QPanGesture", + "QPinchGesture", + "QPlainTextDocumentLayout", + "QPlainTextEdit", + "QProgressBar", + "QProgressDialog", + "QPushButton", + "QRadioButton", + "QRubberBand", + "QScrollArea", + "QScrollBar", + "QShortcut", + "QSizeGrip", + "QSizePolicy", + "QSlider", + "QSpacerItem", + "QSpinBox", + "QSplashScreen", + "QSplitter", + "QSplitterHandle", + "QStackedLayout", + "QStackedWidget", + "QStatusBar", + "QStyle", + "QStyleFactory", + "QStyleHintReturn", + "QStyleHintReturnMask", + "QStyleHintReturnVariant", + "QStyleOption", + "QStyleOptionButton", + "QStyleOptionComboBox", + "QStyleOptionComplex", + "QStyleOptionDockWidget", + "QStyleOptionFocusRect", + "QStyleOptionFrame", + "QStyleOptionGraphicsItem", + "QStyleOptionGroupBox", + "QStyleOptionHeader", + "QStyleOptionMenuItem", + "QStyleOptionProgressBar", + "QStyleOptionRubberBand", + "QStyleOptionSizeGrip", + "QStyleOptionSlider", + "QStyleOptionSpinBox", + "QStyleOptionTab", + "QStyleOptionTabBarBase", + "QStyleOptionTabWidgetFrame", + "QStyleOptionTitleBar", + "QStyleOptionToolBar", + "QStyleOptionToolBox", + "QStyleOptionToolButton", + "QStyleOptionViewItem", + "QStylePainter", + "QStyledItemDelegate", + "QSwipeGesture", + "QSystemTrayIcon", + "QTabBar", + "QTabWidget", + "QTableView", + "QTableWidget", + "QTableWidgetItem", + "QTableWidgetSelectionRange", + "QTapAndHoldGesture", + "QTapGesture", + "QTextBrowser", + "QTextEdit", + "QTimeEdit", + "QToolBar", + "QToolBox", + "QToolButton", + "QToolTip", + "QTreeView", + "QTreeWidget", + "QTreeWidgetItem", + "QTreeWidgetItemIterator", + "QUndoCommand", + "QUndoGroup", + "QUndoStack", + "QUndoView", + "QVBoxLayout", + "QWhatsThis", + "QWidget", + "QWidgetAction", + "QWidgetItem", + "QWizard", + "QWizardPage", + "qApp", + "qDrawBorderPixmap", + "qDrawPlainRect", + "qDrawShadeLine", + "qDrawShadePanel", + "qDrawShadeRect", + "qDrawWinButton", + "qDrawWinPanel", + ], + ), + ( + "qgis.PyQt.QtPrintSupport", + [ + "QPrinter", + "QAbstractPrintDialog", + "QPageSetupDialog", + "QPrintDialog", + "QPrintEngine", + "QPrintPreviewDialog", + "QPrintPreviewWidget", + "QPrinterInfo", + ], + ), + ( + "qgis.PyQt.QtCore", + [ + "QItemSelectionModel", + "QSortFilterProxyModel", + ], + ), ], "PyQt4.QtCore": [ - ("qgis.PyQt.QtCore", [ - "QAbstractItemModel", - "QAbstractTableModel", - "QByteArray", - "QCoreApplication", - "QDataStream", - "QDir", - "QEvent", - "QFile", - "QFileInfo", - "QIODevice", - "QLocale", - "QMimeData", - "QModelIndex", - "QMutex", - "QObject", - "QProcess", - "QSettings", - "QSize", - "QSizeF", - "QTextCodec", - "QThread", - "QThreadPool", - "QTimer", - "QTranslator", - "QUrl", - "Qt", - "pyqtProperty", - "pyqtWrapperType", - "pyqtSignal", - "pyqtSlot", - "qDebug", - "qWarning", - "qVersion", - "QDate", - "QTime", - "QDateTime", - "QRegExp", - "QTemporaryFile", - "QTextStream", - "QVariant", - "QPyNullVariant", - "QRect", - "QRectF", - "QMetaObject", - "QPoint", - "QPointF", - "QDirIterator", - "QEventLoop", - "NULL", - ]), - (None, [ - "SIGNAL", - "SLOT", - ]), + ( + "qgis.PyQt.QtCore", + [ + "QAbstractItemModel", + "QAbstractTableModel", + "QByteArray", + "QCoreApplication", + "QDataStream", + "QDir", + "QEvent", + "QFile", + "QFileInfo", + "QIODevice", + "QLocale", + "QMimeData", + "QModelIndex", + "QMutex", + "QObject", + "QProcess", + "QSettings", + "QSize", + "QSizeF", + "QTextCodec", + "QThread", + "QThreadPool", + "QTimer", + "QTranslator", + "QUrl", + "Qt", + "pyqtProperty", + "pyqtWrapperType", + "pyqtSignal", + "pyqtSlot", + "qDebug", + "qWarning", + "qVersion", + "QDate", + "QTime", + "QDateTime", + "QRegExp", + "QTemporaryFile", + "QTextStream", + "QVariant", + "QPyNullVariant", + "QRect", + "QRectF", + "QMetaObject", + "QPoint", + "QPointF", + "QDirIterator", + "QEventLoop", + "NULL", + ], + ), + ( + None, + [ + "SIGNAL", + "SLOT", + ], + ), ], "PyQt4.QtNetwork": [ - ("qgis.PyQt.QtNetwork", [ - "QNetworkReply", - "QNetworkRequest", - "QSslCertificate", - "QSslKey", - "QSsl" - ]) + ( + "qgis.PyQt.QtNetwork", + ["QNetworkReply", "QNetworkRequest", "QSslCertificate", "QSslKey", "QSsl"], + ) ], "PyQt4.QtXml": [ - ("qgis.PyQt.QtXml", [ - "QDomDocument" - ]), + ("qgis.PyQt.QtXml", ["QDomDocument"]), ], "PyQt4.Qsci": [ - ("qgis.PyQt.Qsci", [ - "QsciAPIs", - "QsciLexerCustom", - "QsciLexerPython", - "QsciScintilla", - "QsciLexerSQL", - "QsciStyle", - ]), + ( + "qgis.PyQt.Qsci", + [ + "QsciAPIs", + "QsciLexerCustom", + "QsciLexerPython", + "QsciScintilla", + "QsciLexerSQL", + "QsciStyle", + ], + ), ], "PyQt4.QtWebKit": [ - ("qgis.PyQt.QtWebKitWidgets", [ - "QGraphicsWebView", - "QWebFrame", - "QWebHitTestResult", - "QWebInspector", - "QWebPage", - "QWebView", - ]), + ( + "qgis.PyQt.QtWebKitWidgets", + [ + "QGraphicsWebView", + "QWebFrame", + "QWebHitTestResult", + "QWebInspector", + "QWebPage", + "QWebView", + ], + ), ], "PyQt4.QtTest": [ - ("qgis.PyQt.QtTest", [ - "QTest", - ]), + ( + "qgis.PyQt.QtTest", + [ + "QTest", + ], + ), ], "PyQt4.QtSvg": [ - ("qgis.PyQt.QtSvg", [ - "QSvgRenderer", - "QSvgGenerator" - ]), + ("qgis.PyQt.QtSvg", ["QSvgRenderer", "QSvgGenerator"]), ], "PyQt4.QtSql": [ - ("qgis.PyQt.QtSql", [ - "QSqlDatabase", - "QSqlQuery", - "QSqlField" - ]), + ("qgis.PyQt.QtSql", ["QSqlDatabase", "QSqlQuery", "QSqlField"]), ], "PyQt4.uic": [ - ("qgis.PyQt.uic", [ - "loadUiType", - "loadUi", - ]), + ( + "qgis.PyQt.uic", + [ + "loadUiType", + "loadUi", + ], + ), ], "PyQt4": [ - ("qgis.PyQt", [ - "QtCore", - "QtGui", - "QtNetwork", - "QtXml", - "QtWebkit", - "QtSql", - "QtSvg", - "Qsci", - "uic", - ]) + ( + "qgis.PyQt", + [ + "QtCore", + "QtGui", + "QtNetwork", + "QtXml", + "QtWebkit", + "QtSql", + "QtSvg", + "Qsci", + "uic", + ], + ) ], } new_mappings = {} for key, value in MAPPING.items(): - match_str = key.replace('PyQt4', '') - match_str = '{}{}'.format('qgis.PyQt', match_str) + match_str = key.replace("PyQt4", "") + match_str = "{}{}".format("qgis.PyQt", match_str) new_mappings[match_str] = value MAPPING.update(new_mappings) @@ -398,11 +429,11 @@ def build_pattern(): new_module, members = change members = alternates(members) - if '.' not in old_module: + if "." not in old_module: from_name = "%r" % old_module else: - dotted = old_module.split('.') + dotted = old_module.split(".") if len(dotted) == 3: from_name = f"dotted_name<{dotted[0]!r} '.' {dotted[1]!r} '.' {dotted[2]!r}>" else: @@ -411,15 +442,21 @@ def build_pattern(): yield """import_name< 'import' (module={} | dotted_as_names< any* module={} any* >) > - """.format(from_name, from_name) + """.format( + from_name, from_name + ) yield """import_from< 'from' mod_member={} 'import' ( member={} | import_as_name< member={} 'as' any > | import_as_names< members=any* >) > - """.format(from_name, members, members) + """.format( + from_name, members, members + ) yield """import_from< 'from' mod_member={} 'import' '(' ( member={} | import_as_name< member={} 'as' any > | import_as_names< members=any* >) ')' > - """.format(from_name, members, members) + """.format( + from_name, members, members + ) yield """import_from< 'from' module_star=%s 'import' star='*' > """ % from_name yield """import_name< 'import' @@ -427,7 +464,9 @@ def build_pattern(): """ % from_name # bare_with_attr has a special significance for FixImports.match(). yield """power< bare_with_attr={} trailer< '.' member={} > any* > - """.format(from_name, members) + """.format( + from_name, members + ) class FixPyqt(FixImports): @@ -435,15 +474,15 @@ class FixPyqt(FixImports): def build_pattern(self): return "|".join(build_pattern()) -# def match(self, node): -# res = super(FixImports, self).match( node ) -# print repr(node) -# return res + # def match(self, node): + # res = super(FixImports, self).match( node ) + # print repr(node) + # return res def transform_import(self, node, results): """Transform for the basic import case. Replaces the old - import name with a comma separated list of its - replacements. + import name with a comma separated list of its + replacements. """ import_mod = results.get("module") pref = import_mod.prefix @@ -457,12 +496,15 @@ def transform_import(self, node, results): names.append(Name(MAPPING[import_mod.value][-1][0], prefix=pref)) import_mod.replace(names) else: - self.cannot_convert(node, "imports like PyQt4.QtGui or import qgis.PyQt.QtGui are not supported") + self.cannot_convert( + node, + "imports like PyQt4.QtGui or import qgis.PyQt.QtGui are not supported", + ) def transform_member(self, node, results): """Transform for imports of specific module elements. Replaces - the module to be imported from with the appropriate new - module. + the module to be imported from with the appropriate new + module. """ mod_member = results.get("mod_member") if isinstance(mod_member, Node): @@ -480,14 +522,14 @@ def transform_member(self, node, results): # this may be a list of length one, or just a node if isinstance(member, list): member = member[0] - new_name = '' + new_name = "" for change in MAPPING[mod_member.value]: if member.value in change[1]: new_name = change[0] break if new_name: mod_member.replace(Name(new_name, prefix=pref)) - elif new_name == '': + elif new_name == "": self.cannot_convert(node, "This is an invalid module element") else: node.remove() @@ -517,7 +559,9 @@ def transform_member(self, node, results): found = True if not found: f = open("/tmp/missing", "a+") - f.write(f"member {member_name} of {mod_member.value} not found\n") + f.write( + f"member {member_name} of {mod_member.value} not found\n" + ) f.close() missing = True @@ -527,9 +571,11 @@ def transform_member(self, node, results): def handle_name(name, prefix): if name.type == syms.import_as_name: - kids = [Name(name.children[0].value, prefix=prefix), - name.children[1].clone(), - name.children[2].clone()] + kids = [ + Name(name.children[0].value, prefix=prefix), + name.children[1].clone(), + name.children[2].clone(), + ] return [Node(syms.import_as_name, kids)] return [Name(name.value, prefix=prefix)] @@ -573,8 +619,7 @@ def transform_dot(self, node, results): new_name = change[0] break if new_name: - module_dot.replace(Name(new_name, - prefix=module_dot.prefix)) + module_dot.replace(Name(new_name, prefix=module_dot.prefix)) else: self.cannot_convert(node, "This is an invalid module element") diff --git a/scripts/qgis_fixes/fix_qfiledialog.py b/scripts/qgis_fixes/fix_qfiledialog.py index 762bc79f0cce..c111e694cf5d 100644 --- a/scripts/qgis_fixes/fix_qfiledialog.py +++ b/scripts/qgis_fixes/fix_qfiledialog.py @@ -1,6 +1,7 @@ """ Migrate QFileDialog methods from PyQt4 to PyQt5 """ + # Author: Médéric Ribreux # Adapted from fix_pyqt # and http://python3porting.com/fixers.html @@ -23,8 +24,8 @@ def transform(self, node, results): # First case: getOpen/SaveFileName # We need to add __ variable because in PyQt5 # getOpen/SaveFileName returns a tuple - if 'filename' in results: - node = results['filename'] + if "filename" in results: + node = results["filename"] # count number of leaves (result variables) nbLeaves = sum(1 for i in node.leaves()) @@ -33,11 +34,11 @@ def transform(self, node, results): # we add __ special variable if nbLeaves < 3: fileName = node.value - node.value = f'{fileName}, __' + node.value = f"{fileName}, __" node.changed() # Rename *AndFilter methods - if 'filter' in results: - method = results['filter'][0] - method.value = method.value.replace('AndFilter', '') + if "filter" in results: + method = results["filter"][0] + method.value = method.value.replace("AndFilter", "") method.changed() diff --git a/scripts/qgis_fixes/fix_signals.py b/scripts/qgis_fixes/fix_signals.py index e232299defa4..56d4488b8514 100644 --- a/scripts/qgis_fixes/fix_signals.py +++ b/scripts/qgis_fixes/fix_signals.py @@ -1,14 +1,15 @@ """Migrate signals from old style to new style """ + # Author: Juergen E. Fischer # .connect( sender, signal, receiver, slot ) +import re + # Local imports from lib2to3 import fixer_base, pytree -from lib2to3.fixer_util import Call, Name, Attr, ArgList, Node, syms - -import re +from lib2to3.fixer_util import ArgList, Attr, Call, Name, Node, syms class FixSignals(fixer_base.BaseFix): @@ -50,25 +51,29 @@ class FixSignals(fixer_base.BaseFix): ) """ -# def match(self, node): -# res = super(FixSignals, self).match( node ) -# r = repr(node) -# if "emit" in r: -# print "yes" if res else "no", ": ", r -# return res + # def match(self, node): + # res = super(FixSignals, self).match( node ) + # r = repr(node) + # if "emit" in r: + # print "yes" if res else "no", ": ", r + # return res def transform(self, node, results): signal = results.get("signal").value - signal = re.sub('^["\']([^(]+)(?:\\(.*\\))?["\']$', '\\1', signal) + signal = re.sub("^[\"']([^(]+)(?:\\(.*\\))?[\"']$", "\\1", signal) - if 'emitter' in results: + if "emitter" in results: emitter = results.get("emitter").clone() emitter.prefix = node.prefix args = results.get("args").clone() args.children = args.children[2:] if args.children: - args.children[0].prefix = '' - res = Node(syms.power, [emitter, Name('.'), Name(signal), Name('.'), Name('emit')] + [ArgList([args])]) + args.children[0].prefix = "" + res = Node( + syms.power, + [emitter, Name("."), Name(signal), Name("."), Name("emit")] + + [ArgList([args])], + ) else: sender = results.get("sender").clone() method = results.get("method") @@ -78,5 +83,9 @@ def transform(self, node, results): sender.prefix = node.prefix slot = results.get("slot").clone() slot.prefix = "" - res = Node(syms.power, [sender, Name('.'), Name(signal), Name('.'), method] + [ArgList([slot])]) + res = Node( + syms.power, + [sender, Name("."), Name(signal), Name("."), method] + + [ArgList([slot])], + ) return res diff --git a/scripts/qgis_fixes/fix_uiimport.py b/scripts/qgis_fixes/fix_uiimport.py index 296c166327de..fb2026e2603b 100644 --- a/scripts/qgis_fixes/fix_uiimport.py +++ b/scripts/qgis_fixes/fix_uiimport.py @@ -3,8 +3,8 @@ # Local imports from lib2to3 import fixer_base +from lib2to3.fixer_util import FromImport, Leaf, Node, syms from lib2to3.fixes.fix_import import FixImport -from lib2to3.fixer_util import FromImport, Node, Leaf, syms class FixUiimport(fixer_base.BaseFix): @@ -17,14 +17,14 @@ class FixUiimport(fixer_base.BaseFix): """ def transform(self, node, results): - imp = results.get('imp') + imp = results.get("imp") if node.type == syms.import_from: # Some imps are top-level (e.g., 'import ham') # some are first level (e.g., 'import ham.eggs') # some are third level (e.g., 'import ham.eggs as spam') # Hence, the loop - while not hasattr(imp, 'value'): + while not hasattr(imp, "value"): imp = imp.children[0] if imp.value.startswith("ui_"): imp.value = "." + imp.value diff --git a/scripts/qstringfixup.py b/scripts/qstringfixup.py index 4ca86ff78752..fff0d0446adc 100644 --- a/scripts/qstringfixup.py +++ b/scripts/qstringfixup.py @@ -38,7 +38,7 @@ import re import sys -lines = [l[0:-1] if l[-1] == '\n' else l for l in open(sys.argv[1]).readlines()] +lines = [l[0:-1] if l[-1] == "\n" else l for l in open(sys.argv[1]).readlines()] # Double quoted strings that only include ASCII characters string_literal = r"""(R?"(?:(?:\\['"\\nrt])|[\x00-\x21\x23-\x5B\x5D-\x7F])+?")""" @@ -47,25 +47,31 @@ char_literal = r"""('(?:\\['"\\nrt]|[\x00-\x26\x28-\x5B\x5D-\x7F])')""" # Simple expression like foo or foo.bar() or foo.bar(baz, baw) -simple_expr = r"""([a-zA-Z0-9_:<>]+(?:\.(?:[a-zA-Z0-9_]+\([^\(\)]*\)|[a-zA-Z0-9_]+))?)""" +simple_expr = ( + r"""([a-zA-Z0-9_:<>]+(?:\.(?:[a-zA-Z0-9_]+\([^\(\)]*\)|[a-zA-Z0-9_]+))?)""" +) -qsl = fr"""QStringLiteral\( {string_literal} \)""" +qsl = rf"""QStringLiteral\( {string_literal} \)""" # Find lines like " foo += QStringLiteral( "bla" ); // optional comment" -pattern_plus_equal = re.compile(fr'^([ ]*)([^ ]+) \+= {qsl};([ ]*//.*)?$') +pattern_plus_equal = re.compile(rf"^([ ]*)([^ ]+) \+= {qsl};([ ]*//.*)?$") # Find patterns like "...QString( tr( "foo" ) )..." -pattern_qstring_tr = re.compile(fr"""(.*)QString\( tr\( {string_literal} \) \)(.*)""") +pattern_qstring_tr = re.compile(rf"""(.*)QString\( tr\( {string_literal} \) \)(.*)""") # Find patterns like "...== QStringLiteral( "foo" ) something that is not like .arg()" -pattern_equalequal_qsl = re.compile(r'(.*)(==|!=) ' + qsl + r'( \)| \|\|| &&| }|;| \?| ,)(.*)') +pattern_equalequal_qsl = re.compile( + r"(.*)(==|!=) " + qsl + r"( \)| \|\|| &&| }|;| \?| ,)(.*)" +) # Find patterns like "...startsWith( QStringLiteral( "foo" ) )..." -pattern_startswith_qsl = re.compile(fr'(.*)\.(startsWith|endsWith|indexOf|lastIndexOf|compare)\( {qsl} \)(.*)') +pattern_startswith_qsl = re.compile( + rf"(.*)\.(startsWith|endsWith|indexOf|lastIndexOf|compare)\( {qsl} \)(.*)" +) # .replace( 'a' or simple_expr or qsl, QStringLiteral( "foo" ) ) -replace_char_qsl = re.compile(fr"""(.*)\.replace\( {char_literal}, {qsl} \)(.*)""") -replace_str_qsl = re.compile(fr"""(.*)\.replace\( {string_literal}, {qsl} \)(.*)""") +replace_char_qsl = re.compile(rf"""(.*)\.replace\( {char_literal}, {qsl} \)(.*)""") +replace_str_qsl = re.compile(rf"""(.*)\.replace\( {string_literal}, {qsl} \)(.*)""") # Do not use that: if simple_expr is a QRegExp, there is no QString::replace(QRegExp, QLatin1String) # replace_simple_expr_qsl = re.compile(r"""(.*)\.replace\( {simple_expr}, {qsl} \)(.*)""".format(simple_expr=simple_expr, qsl=qsl)) @@ -73,21 +79,23 @@ replace_qsl_qsl = re.compile(r"""(.*)\.replace\( {qsl}, {qsl} \)(.*)""".format(qsl=qsl)) # .replace( QStringLiteral( "foo" ), something -replace_qsl_something = re.compile(fr"""(.*)\.replace\( {qsl}, (.+)""") +replace_qsl_something = re.compile(rf"""(.*)\.replace\( {qsl}, (.+)""") # .arg( QStringLiteral( "foo" ) ) # note: QString QString::arg(QLatin1String a) added in QT 5.10, but using QLatin1String() will work with older too -arg_qsl = re.compile(fr"""(.*)\.arg\( {qsl} \)(.*)""") +arg_qsl = re.compile(rf"""(.*)\.arg\( {qsl} \)(.*)""") # .join( QStringLiteral( "foo" ) ) -join = re.compile(fr"""(.*)\.join\( {qsl} \)(.*)""") +join = re.compile(rf"""(.*)\.join\( {qsl} \)(.*)""") # if QT >= 5.14 .compare would be ok -qlatin1str_single_char = re.compile(r"""(.*)(.startsWith\(|.endsWith\(|.indexOf\(|.lastIndexOf\(|\+=) QLatin1String\( ("[^"]") \)(.*)""") +qlatin1str_single_char = re.compile( + r"""(.*)(.startsWith\(|.endsWith\(|.indexOf\(|.lastIndexOf\(|\+=) QLatin1String\( ("[^"]") \)(.*)""" +) def qlatin1char_or_string(x): - """ x is a double quoted string """ + """x is a double quoted string""" if len(x) == 3 and x[1] == "'": return "QLatin1Char( '\\'' )" elif len(x) == 3: @@ -106,8 +114,8 @@ def qlatin1char_or_string(x): m = pattern_plus_equal.match(line) if m: g = m.groups() - newline = g[0] + g[1] + ' += ' - newline += 'QLatin1String( ' + g[2] + ' );' + newline = g[0] + g[1] + " += " + newline += "QLatin1String( " + g[2] + " );" if g[3]: newline += g[3] line = newline @@ -115,16 +123,16 @@ def qlatin1char_or_string(x): m = pattern_qstring_tr.match(line) if m: g = m.groups() - newline = g[0] + 'tr( ' + g[1] + ' )' + newline = g[0] + "tr( " + g[1] + " )" if g[2]: newline += g[2] line = newline while True: m = pattern_equalequal_qsl.match(line) - if m and 'qgetenv' not in line and 'h.first' not in line: + if m and "qgetenv" not in line and "h.first" not in line: g = m.groups() - newline = g[0] + g[1] + ' QLatin1String( ' + g[2] + ' )' + g[3] + newline = g[0] + g[1] + " QLatin1String( " + g[2] + " )" + g[3] if g[4]: newline += g[4] line = newline @@ -135,7 +143,7 @@ def qlatin1char_or_string(x): m = pattern_startswith_qsl.match(line) if m: g = m.groups() - newline = g[0] + '.' + g[1] + '( QLatin1String( ' + g[2] + ' ) )' + newline = g[0] + "." + g[1] + "( QLatin1String( " + g[2] + " ) )" if g[3]: newline += g[3] line = newline @@ -150,7 +158,7 @@ def qlatin1char_or_string(x): # m = replace_simple_expr_qsl.match(line) if m: g = m.groups() - newline = g[0] + '.replace( ' + g[1] + ', QLatin1String( ' + g[2] + ' ) )' + newline = g[0] + ".replace( " + g[1] + ", QLatin1String( " + g[2] + " ) )" if g[3]: newline += g[3] line = newline @@ -161,7 +169,14 @@ def qlatin1char_or_string(x): m = replace_qsl_qsl.match(line) if m: g = m.groups() - newline = g[0] + '.replace( QLatin1String( ' + g[1] + ' ), QLatin1String( ' + g[2] + ' ) )' + newline = ( + g[0] + + ".replace( QLatin1String( " + + g[1] + + " ), QLatin1String( " + + g[2] + + " ) )" + ) if g[3]: newline += g[3] line = newline @@ -172,7 +187,7 @@ def qlatin1char_or_string(x): m = replace_qsl_something.match(line) if m: g = m.groups() - newline = g[0] + '.replace( QLatin1String( ' + g[1] + ' ), ' + g[2] + newline = g[0] + ".replace( QLatin1String( " + g[1] + " ), " + g[2] line = newline else: break @@ -181,7 +196,7 @@ def qlatin1char_or_string(x): m = arg_qsl.match(line) if m: g = m.groups() - newline = g[0] + '.arg( QLatin1String( ' + g[1] + ') )' + newline = g[0] + ".arg( QLatin1String( " + g[1] + ") )" if g[2]: newline += g[2] line = newline @@ -192,7 +207,7 @@ def qlatin1char_or_string(x): m = join.match(line) if m: g = m.groups() - newline = g[0] + '.join( ' + qlatin1char_or_string(g[1]) + ' )' + newline = g[0] + ".join( " + qlatin1char_or_string(g[1]) + " )" if g[2]: newline += g[2] line = newline @@ -203,7 +218,7 @@ def qlatin1char_or_string(x): m = qlatin1str_single_char.match(line) if m: g = m.groups() - newline = g[0] + g[1] + ' ' + qlatin1char_or_string(g[2]) + newline = g[0] + g[1] + " " + qlatin1char_or_string(g[2]) if g[3]: newline += g[3] line = newline diff --git a/scripts/random_vector.py b/scripts/random_vector.py index f0a3e459cb57..aed6860366c8 100755 --- a/scripts/random_vector.py +++ b/scripts/random_vector.py @@ -2,14 +2,16 @@ # Generates random shapefile which may be used for benchmarks +import math import os -import sys import random import string -import math -from osgeo import ogr +import sys + from optparse import OptionParser +from osgeo import ogr + def error(msg): print(msg) @@ -17,11 +19,47 @@ def error(msg): parser = OptionParser("usage: %prog [options] output") -parser.add_option("-t", "--type", dest="type", type="choice", choices=("point", "line", "polygon"), default="point", help="Geometry type") -parser.add_option("-f", "--features", dest="features", type="int", default=1000, help="Number of features") -parser.add_option("-c", "--coordinates", dest="coordinates", type="int", default=10, help="Number of coordinates per feature (lines and polygons)") -parser.add_option("-a", "--attributes", dest="attributes", type="int", default=10, help="Number of attributes") -parser.add_option("-e", "--extent", dest="extent", type="string", default="-180,-90,180,90", help="Extent") +parser.add_option( + "-t", + "--type", + dest="type", + type="choice", + choices=("point", "line", "polygon"), + default="point", + help="Geometry type", +) +parser.add_option( + "-f", + "--features", + dest="features", + type="int", + default=1000, + help="Number of features", +) +parser.add_option( + "-c", + "--coordinates", + dest="coordinates", + type="int", + default=10, + help="Number of coordinates per feature (lines and polygons)", +) +parser.add_option( + "-a", + "--attributes", + dest="attributes", + type="int", + default=10, + help="Number of attributes", +) +parser.add_option( + "-e", + "--extent", + dest="extent", + type="string", + default="-180,-90,180,90", + help="Extent", +) (options, args) = parser.parse_args() if len(args) != 1: @@ -107,7 +145,10 @@ def error(msg): limit = 10000000 if field_defn.GetType() == ogr.OFTString: nChars = random.randint(0, stringWidth) - val = ''.join(random.choice(string.ascii_letters + string.digits) for x in range(nChars)) + val = "".join( + random.choice(string.ascii_letters + string.digits) + for x in range(nChars) + ) elif field_defn.GetType() == ogr.OFTInteger: val = random.randint(-limit, limit) elif field_defn.GetType() == ogr.OFTReal: diff --git a/scripts/sipify.py b/scripts/sipify.py index 71c6aebc8e62..2f816a58ad66 100755 --- a/scripts/sipify.py +++ b/scripts/sipify.py @@ -5,9 +5,10 @@ import os import re import sys + from collections import defaultdict from enum import Enum, auto -from typing import List, Dict, Any, Tuple, Optional +from typing import Any, Dict, List, Optional, Tuple import yaml @@ -38,8 +39,7 @@ class MultiLineType(Enum): # Parse command-line arguments -parser = argparse.ArgumentParser( - description="Convert header file to SIP and Python") +parser = argparse.ArgumentParser(description="Convert header file to SIP and Python") parser.add_argument("-debug", action="store_true", help="Enable debug mode") parser.add_argument("-qt6", action="store_true", help="Enable Qt6 mode") parser.add_argument("-sip_output", help="SIP output file") @@ -50,21 +50,23 @@ class MultiLineType(Enum): # Read the input file try: - with open(args.headerfile, "r") as f: + with open(args.headerfile) as f: input_lines = f.read().splitlines() -except IOError as e: - print(f"Couldn't open '{args.headerfile}' for reading because: {e}", - file=sys.stderr) +except OSError as e: + print( + f"Couldn't open '{args.headerfile}' for reading because: {e}", file=sys.stderr + ) sys.exit(1) # Read configuration -cfg_file = os.path.join(os.path.dirname(__file__), '../python/sipify.yaml') +cfg_file = os.path.join(os.path.dirname(__file__), "../python/sipify.yaml") try: - with open(cfg_file, 'r') as f: + with open(cfg_file) as f: sip_config = yaml.safe_load(f) -except IOError as e: - print(f"Couldn't open configuration file '{cfg_file}' because: {e}", - file=sys.stderr) +except OSError as e: + print( + f"Couldn't open configuration file '{cfg_file}' because: {e}", file=sys.stderr + ) sys.exit(1) @@ -76,63 +78,68 @@ class Context: def __init__(self): self.debug: bool = False self.is_qt6: bool = False - self.header_file: str = '' + self.header_file: str = "" - self.current_line: str = '' + self.current_line: str = "" self.sip_run: bool = False self.header_code: bool = False - self.access: List[Visibility] = [Visibility.Public] + self.access: list[Visibility] = [Visibility.Public] self.multiline_definition: MultiLineType = MultiLineType.NotMultiline - self.classname: List[str] = [] - self.class_and_struct: List[str] = [] - self.declared_classes: List[str] = [] - self.all_fully_qualified_class_names: List[str] = [] - self.exported: List[int] = [0] - self.actual_class: str = '' - self.python_signature: str = '' - self.enum_int_types: List[str] = [] - self.enum_intflag_types: List[str] = [] - self.enum_class_non_int_types: List[str] = [] - self.enum_monkey_patched_types: List = [] - self.indent: str = '' - self.prev_indent: str = '' - self.comment: str = '' + self.classname: list[str] = [] + self.class_and_struct: list[str] = [] + self.declared_classes: list[str] = [] + self.all_fully_qualified_class_names: list[str] = [] + self.exported: list[int] = [0] + self.actual_class: str = "" + self.python_signature: str = "" + self.enum_int_types: list[str] = [] + self.enum_intflag_types: list[str] = [] + self.enum_class_non_int_types: list[str] = [] + self.enum_monkey_patched_types: list = [] + self.indent: str = "" + self.prev_indent: str = "" + self.comment: str = "" self.comment_param_list: bool = False self.comment_last_line_note_warning: bool = False self.comment_code_snippet: CodeSnippetType = CodeSnippetType.NotCodeSnippet self.comment_template_docstring: bool = False - self.skipped_params_out: List[str] = [] - self.skipped_params_remove: List[str] = [] + self.skipped_params_out: list[str] = [] + self.skipped_params_remove: list[str] = [] self.ifdef_nesting_idx: int = 0 - self.bracket_nesting_idx: List[int] = [0] - self.private_section_line: str = '' - self.last_access_section_line: str = '' - self.return_type: str = '' + self.bracket_nesting_idx: list[int] = [0] + self.private_section_line: str = "" + self.last_access_section_line: str = "" + self.return_type: str = "" self.is_override_or_make_private: PrependType = PrependType.NoPrepend - self.if_feature_condition: str = '' + self.if_feature_condition: str = "" self.found_since: bool = False - self.qflag_hash: Dict[str, Any] = {} - self.input_lines: List[str] = [] + self.qflag_hash: dict[str, Any] = {} + self.input_lines: list[str] = [] self.line_count: int = len(input_lines) self.line_idx: int = 0 - self.output: List[str] = [] - self.output_python: List[str] = [] + self.output: list[str] = [] + self.output_python: list[str] = [] self.doxy_inside_sip_run: int = 0 self.has_pushed_force_int: bool = False self.attribute_docstrings = defaultdict(dict) self.struct_docstrings = defaultdict(dict) - self.current_method_name: str = '' + self.current_method_name: str = "" self.static_methods = defaultdict(dict) self.current_signal_args = [] self.signal_arguments = defaultdict(dict) def current_fully_qualified_class_name(self) -> str: - return '.'.join( - _c for _c in ([c for c in self.classname if c != self.actual_class] + [ - self.actual_class]) if _c) + return ".".join( + _c + for _c in ( + [c for c in self.classname if c != self.actual_class] + + [self.actual_class] + ) + if _c + ) def current_fully_qualified_struct_name(self) -> str: - return '.'.join(self.class_and_struct) + return ".".join(self.class_and_struct) CONTEXT = Context() @@ -559,21 +566,22 @@ def current_fully_qualified_struct_name(self) -> str: "SymbolTable", "TagTable", "TagmapTable", - "TextFormatTable" + "TextFormatTable", ] def replace_macros(line): global CONTEXT - line = re.sub(r'\bTRUE\b', '``True``', line) - line = re.sub(r'\bFALSE\b', '``False``', line) - line = re.sub(r'\bNULLPTR\b', '``None``', line) + line = re.sub(r"\bTRUE\b", "``True``", line) + line = re.sub(r"\bFALSE\b", "``False``", line) + line = re.sub(r"\bNULLPTR\b", "``None``", line) if CONTEXT.is_qt6: # sip for Qt6 chokes on QList/QVector, but is happy if you expand out the map explicitly - line = re.sub(r'(QList<\s*|QVector<\s*)QVariantMap', - r'\1QMap', line) + line = re.sub( + r"(QList<\s*|QVector<\s*)QVariantMap", r"\1QMap", line + ) return line @@ -586,9 +594,10 @@ def read_line(): if CONTEXT.debug: print( - f'LIN:{CONTEXT.line_idx} DEPTH:{len(CONTEXT.access)} ACC:{CONTEXT.access[-1]} ' - f'BRCK:{CONTEXT.bracket_nesting_idx[-1]} SIP:{CONTEXT.sip_run} MLT:{CONTEXT.multiline_definition} ' - f'OVR: {CONTEXT.is_override_or_make_private} CLSS: {CONTEXT.actual_class}/{len(CONTEXT.classname)} :: {new_line}') + f"LIN:{CONTEXT.line_idx} DEPTH:{len(CONTEXT.access)} ACC:{CONTEXT.access[-1]} " + f"BRCK:{CONTEXT.bracket_nesting_idx[-1]} SIP:{CONTEXT.sip_run} MLT:{CONTEXT.multiline_definition} " + f"OVR: {CONTEXT.is_override_or_make_private} CLSS: {CONTEXT.actual_class}/{len(CONTEXT.classname)} :: {new_line}" + ) new_line = replace_macros(new_line) return new_line @@ -600,18 +609,18 @@ def write_output(dbg_code, out, prepend="no"): if CONTEXT.debug: dbg_code = f"{CONTEXT.line_idx} {dbg_code:<4} :: " else: - dbg_code = '' + dbg_code = "" if prepend == "prepend": CONTEXT.output.insert(0, dbg_code + out) else: - if CONTEXT.if_feature_condition != '': + if CONTEXT.if_feature_condition != "": CONTEXT.output.append(f"%If ({CONTEXT.if_feature_condition})\n") CONTEXT.output.append(dbg_code + out) - if CONTEXT.if_feature_condition != '': + if CONTEXT.if_feature_condition != "": CONTEXT.output.append("%End\n") - CONTEXT.if_feature_condition = '' + CONTEXT.if_feature_condition = "" def dbg_info(info): @@ -620,13 +629,15 @@ def dbg_info(info): if CONTEXT.debug: CONTEXT.output.append(f"{info}\n") print( - f"{CONTEXT.line_idx} {len(CONTEXT.access)} {CONTEXT.sip_run} {CONTEXT.multiline_definition} {info}") + f"{CONTEXT.line_idx} {len(CONTEXT.access)} {CONTEXT.sip_run} {CONTEXT.multiline_definition} {info}" + ) def exit_with_error(message): global CONTEXT sys.exit( - f"! Sipify error in {CONTEXT.header_file} at line :: {CONTEXT.line_idx}\n! {message}") + f"! Sipify error in {CONTEXT.header_file} at line :: {CONTEXT.line_idx}\n! {message}" + ) def sip_header_footer(): @@ -636,29 +647,33 @@ def sip_header_footer(): # otherwise "sip up to date" test fails. This is because the test uses %Include entries # and over there we have to use ./3d/X.h entries because SIP parser does not allow a number # as the first letter of a relative path - headerfile_x = re.sub(r'src/core/3d', r'src/core/./3d', - CONTEXT.header_file) + headerfile_x = re.sub(r"src/core/3d", r"src/core/./3d", CONTEXT.header_file) header_footer.append( - "/************************************************************************\n") + "/************************************************************************\n" + ) header_footer.append( - " * This file has been generated automatically from *\n") + " * This file has been generated automatically from *\n" + ) header_footer.append( - " * *\n") + " * *\n" + ) header_footer.append(f" * {headerfile_x:<68} *\n") header_footer.append( - " * *\n") + " * *\n" + ) header_footer.append( - " * Do not edit manually ! Edit header and run scripts/sipify.py again *\n") + " * Do not edit manually ! Edit header and run scripts/sipify.py again *\n" + ) header_footer.append( - " ************************************************************************/\n") + " ************************************************************************/\n" + ) return header_footer def python_header(): global CONTEXT header = [] - headerfile_x = re.sub(r'src/core/3d', r'src/core/./3d', - CONTEXT.header_file) + headerfile_x = re.sub(r"src/core/3d", r"src/core/./3d", CONTEXT.header_file) header.append("# The following has been generated automatically from ") header.append(f"{headerfile_x}\n") return header @@ -668,30 +683,34 @@ def create_class_links(line): global CONTEXT # Replace Qgs classes (but not the current class) with :py:class: links - class_link_match = re.search(r'\b(Qgs[A-Z]\w+|Qgis)\b(\.?$|\W{2})', line) + class_link_match = re.search(r"\b(Qgs[A-Z]\w+|Qgis)\b(\.?$|\W{2})", line) if class_link_match: if CONTEXT.actual_class and class_link_match.group(1) != CONTEXT.actual_class: - line = re.sub(r'\b(Qgs[A-Z]\w+)\b(\.?$|\W{2})', - r':py:class:`\1`\2', line) + line = re.sub(r"\b(Qgs[A-Z]\w+)\b(\.?$|\W{2})", r":py:class:`\1`\2", line) # Replace Qgs class methods with :py:func: links - line = re.sub(r'\b((Qgs[A-Z]\w+|Qgis)\.[a-z]\w+\(\))(?!\w)', - r':py:func:`\1`', line) + line = re.sub(r"\b((Qgs[A-Z]\w+|Qgis)\.[a-z]\w+\(\))(?!\w)", r":py:func:`\1`", line) # Replace other methods with :py:func: links if CONTEXT.actual_class: - line = re.sub(r'(? str: global CONTEXT # Handle SIP_RUN preprocessor directives - if re.search(r'\s*#ifdef SIP_RUN', line): + if re.search(r"\s*#ifdef SIP_RUN", line): CONTEXT.doxy_inside_sip_run = 1 return "" - elif re.search(r'\s*#ifndef SIP_RUN', line): + elif re.search(r"\s*#ifndef SIP_RUN", line): CONTEXT.doxy_inside_sip_run = 2 return "" - elif CONTEXT.doxy_inside_sip_run != 0 and re.search(r'\s*#else', line): + elif CONTEXT.doxy_inside_sip_run != 0 and re.search(r"\s*#else", line): CONTEXT.doxy_inside_sip_run = 2 if CONTEXT.doxy_inside_sip_run == 1 else 1 return "" - elif CONTEXT.doxy_inside_sip_run != 0 and re.search(r'\s*#endif', line): + elif CONTEXT.doxy_inside_sip_run != 0 and re.search(r"\s*#endif", line): CONTEXT.doxy_inside_sip_run = 0 return "" if CONTEXT.doxy_inside_sip_run == 2: return "" - if r'\copydoc' in line: + if r"\copydoc" in line: exit_with_error( - '\\copydoc doxygen command cannot be used for methods exposed to Python') + "\\copydoc doxygen command cannot be used for methods exposed to Python" + ) - if re.search(r'<(?:dl|dt|dd>)', line): + if re.search(r"<(?:dl|dt|dd>)", line): exit_with_error( "Don't use raw html
    ,
    or
    tags in documentation. " - "Use markdown headings instead") - if re.search(r'', line): + "Use markdown headings instead" + ) + if re.search(r"", line): exit_with_error( "Don't use raw html heading tags in documentation. " - "Use markdown headings instead") - if re.search(r'
  • ', line): + "Use markdown headings instead" + ) + if re.search(r"
  • ", line): exit_with_error( - "Don't use raw html lists in documentation. " - "Use markdown lists instead") - if re.search(r'<[ib]>', line): + "Don't use raw html lists in documentation. " "Use markdown lists instead" + ) + if re.search(r"<[ib]>", line): exit_with_error( - "Don't use raw or tags in documentation. " - "Use markdown instead") + "Don't use raw or tags in documentation. " "Use markdown instead" + ) # Detect code snippet - code_match = re.search(r'\\code(\{\.?(\w+)})?', line) + code_match = re.search(r"\\code(\{\.?(\w+)})?", line) if code_match: codelang = f" {code_match.group(2)}" if code_match.group(2) else "" - if not re.search(r'(cpp|py|unparsed)', codelang): + if not re.search(r"(cpp|py|unparsed)", codelang): exit_with_error(f"invalid code snippet format: {codelang}") CONTEXT.comment_code_snippet = CodeSnippetType.NotSpecified - if re.search(r'cpp', codelang): + if re.search(r"cpp", codelang): CONTEXT.comment_code_snippet = CodeSnippetType.Cpp - codelang = codelang.replace('py', 'python').replace('unparsed', 'text') - return "\n" if CONTEXT.comment_code_snippet == CodeSnippetType.Cpp else f"\n.. code-block::{codelang}\n\n" - - if re.search(r'\\endcode', line): + codelang = codelang.replace("py", "python").replace("unparsed", "text") + return ( + "\n" + if CONTEXT.comment_code_snippet == CodeSnippetType.Cpp + else f"\n.. code-block::{codelang}\n\n" + ) + + if re.search(r"\\endcode", line): CONTEXT.comment_code_snippet = CodeSnippetType.NotCodeSnippet return "\n" @@ -757,127 +783,145 @@ def process_doxygen_line(line: str) -> str: if CONTEXT.comment_code_snippet == CodeSnippetType.Cpp: return "" else: - return f" {line}\n" if line != '' else "\n" + return f" {line}\n" if line != "" else "\n" # Remove prepending spaces and apply various replacements - line = re.sub(r'^\s+', '', line) - line = re.sub(r'\\a (.+?)\b', r'``\1``', line) - line = line.replace('::', '.') - line = re.sub(r'\bnullptr\b', 'None', line) + line = re.sub(r"^\s+", "", line) + line = re.sub(r"\\a (.+?)\b", r"``\1``", line) + line = line.replace("::", ".") + line = re.sub(r"\bnullptr\b", "None", line) # Handle section and subsection - section_match = re.match(r'^\\(?Psub)?section', line) + section_match = re.match(r"^\\(?Psub)?section", line) if section_match: - sep = "^" if section_match.group('SUB') else "-" - line = re.sub(r'^\\(sub)?section \w+ ', '', line) - sep_line = re.sub(r'[\w ()]', sep, line) + sep = "^" if section_match.group("SUB") else "-" + line = re.sub(r"^\\(sub)?section \w+ ", "", line) + sep_line = re.sub(r"[\w ()]", sep, line) line += f"\n{sep_line}" # Convert ### style headings - heading_match = re.match(r'^###\s+(.*)$', line) + heading_match = re.match(r"^###\s+(.*)$", line) if heading_match: line = f"{heading_match.group(1)}\n{'-' * (len(heading_match.group(1)) + 30)}" - heading_match = re.match(r'^##\s+(.*)$', line) + heading_match = re.match(r"^##\s+(.*)$", line) if heading_match: line = f"{heading_match.group(1)}\n{'=' * (len(heading_match.group(1)) + 30)}" - if line == '*': - line = '' + if line == "*": + line = "" # Handle multi-line parameters/returns/lists - if line != '': - if re.match(r'^\s*[\-#]', line): + if line != "": + if re.match(r"^\s*[\-#]", line): line = f"{CONTEXT.prev_indent}{line}" CONTEXT.indent = f"{CONTEXT.prev_indent} " elif not re.match( - r'^\s*[\\:]+(param|note|since|return|deprecated|warning|throws)', - line): + r"^\s*[\\:]+(param|note|since|return|deprecated|warning|throws)", line + ): line = f"{CONTEXT.indent}{line}" else: CONTEXT.prev_indent = CONTEXT.indent - CONTEXT.indent = '' + CONTEXT.indent = "" # Replace \returns with :return: - if re.search(r'\\return(s)?', line): - line = re.sub(r'\s*\\return(s)?\s*', '\n:return: ', line) - line = re.sub(r'\s*$', '', line) - CONTEXT.indent = ' ' * (line.index(':', 4) + 1) + if re.search(r"\\return(s)?", line): + line = re.sub(r"\s*\\return(s)?\s*", "\n:return: ", line) + line = re.sub(r"\s*$", "", line) + CONTEXT.indent = " " * (line.index(":", 4) + 1) # Handle params - if re.search(r'\\param(?:\[(?:out|in|,)+])? ', line): - line = re.sub(r'\s*\\param(?:\[(?:out|in|,)+])?\s+(\w+)\b\s*', r':param \1: ', line) - line = re.sub(r'\s*$', '', line) - CONTEXT.indent = ' ' * (line.index(':', 2) + 2) - if line.startswith(':param'): + if re.search(r"\\param(?:\[(?:out|in|,)+])? ", line): + line = re.sub( + r"\s*\\param(?:\[(?:out|in|,)+])?\s+(\w+)\b\s*", r":param \1: ", line + ) + line = re.sub(r"\s*$", "", line) + CONTEXT.indent = " " * (line.index(":", 2) + 2) + if line.startswith(":param"): if not CONTEXT.comment_param_list: line = f"\n{line}" CONTEXT.comment_param_list = True CONTEXT.comment_last_line_note_warning = False # Handle brief - if re.match(r'^\s*[\\@]brief', line): - line = re.sub(r'[\\@]brief\s*', '', line) + if re.match(r"^\s*[\\@]brief", line): + line = re.sub(r"[\\@]brief\s*", "", line) if CONTEXT.found_since: exit_with_error( - f"{CONTEXT.header_file}::{CONTEXT.line_idx} Since annotation must come after brief") + f"{CONTEXT.header_file}::{CONTEXT.line_idx} Since annotation must come after brief" + ) CONTEXT.found_since = False - if re.match(r'^\s*$', line): + if re.match(r"^\s*$", line): return "" # Handle ingroup and class - if re.search(r'[\\@](ingroup|class)', line): + if re.search(r"[\\@](ingroup|class)", line): CONTEXT.prev_indent = CONTEXT.indent - CONTEXT.indent = '' + CONTEXT.indent = "" return "" # Handle since - since_match = re.search(r'\\since .*?([\d.]+)', line, re.IGNORECASE) + since_match = re.search(r"\\since .*?([\d.]+)", line, re.IGNORECASE) if since_match: CONTEXT.prev_indent = CONTEXT.indent - CONTEXT.indent = '' + CONTEXT.indent = "" CONTEXT.found_since = True return f"\n.. versionadded:: {since_match.group(1)}\n" # Handle deprecated if deprecated_match := re.search( - r'\\deprecated QGIS (?P[0-9.]+)\s*(?P.*)?', + r"\\deprecated QGIS (?P[0-9.]+)\s*(?P.*)?", line, - re.IGNORECASE): + re.IGNORECASE, + ): CONTEXT.prev_indent = CONTEXT.indent - CONTEXT.indent = '' - version = deprecated_match.group('DEPR_VERSION') - if version.endswith('.'): + CONTEXT.indent = "" + version = deprecated_match.group("DEPR_VERSION") + if version.endswith("."): version = version[:-1] depr_line = f"\n.. deprecated:: {version}" - message = deprecated_match.group('DEPR_MESSAGE') + message = deprecated_match.group("DEPR_MESSAGE") if message: depr_line += "\n" - depr_line += "\n".join(f"\n {_m}" for _m in message.split('\n')) + depr_line += "\n".join(f"\n {_m}" for _m in message.split("\n")) return create_class_links(depr_line) # Handle see also - see_matches = list(re.finditer(r'\\see +([\w:/.#-]+(\.\w+)*)(\([^()]*\))?(\.?)', line)) + see_matches = list( + re.finditer(r"\\see +([\w:/.#-]+(\.\w+)*)(\([^()]*\))?(\.?)", line) + ) if see_matches: for see_match in reversed(see_matches): seealso = see_match.group(1) seealso_suffix = see_match.group(4) - seeline = '' + seeline = "" dbg_info(f"see also: `{seealso}`") - if re.match(r'^http', seealso): + if re.match(r"^http", seealso): seeline = f"{seealso}" - elif seealso_match := re.match(r'^(Qgs[A-Z]\w+(\([^()]*\))?)(\.)?$', seealso): + elif seealso_match := re.match( + r"^(Qgs[A-Z]\w+(\([^()]*\))?)(\.)?$", seealso + ): dbg_info(f"\\see :py:class:`{seealso_match.group(1)}`") seeline = f":py:class:`{seealso_match.group(1)}`{seealso_match.group(3) or ''}" - elif seealso_match := re.match(r'^((Qgs[A-Z]\w+)\.(\w+)(\([^()]*\))?)(\.)?$', seealso): - dbg_info(f"\\see py:func with param: :py:func:`{seealso_match.group(1)}`") - seeline = f":py:func:`{seealso_match.group(1)}`{seealso_match.group(5) or ''}" - elif seealso_match := re.match(r'^([a-z]\w+(\([^()]*\))?)(\.)?$', seealso): + elif seealso_match := re.match( + r"^((Qgs[A-Z]\w+)\.(\w+)(\([^()]*\))?)(\.)?$", seealso + ): + dbg_info( + f"\\see py:func with param: :py:func:`{seealso_match.group(1)}`" + ) + seeline = ( + f":py:func:`{seealso_match.group(1)}`{seealso_match.group(5) or ''}" + ) + elif seealso_match := re.match(r"^([a-z]\w+(\([^()]*\))?)(\.)?$", seealso): dbg_info(f"\\see :py:func:`{seealso_match.group(1)}`") - seeline = f":py:func:`{seealso_match.group(1)}`{seealso_match.group(3) or ''}" - - if full_line_match := re.match(r'^\s*\\see +(\w+(?:\.\w+)*)(?:\([^()]*\))?[\s,.:-]*(.*?)$', line): - if seeline.startswith('http'): + seeline = ( + f":py:func:`{seealso_match.group(1)}`{seealso_match.group(3) or ''}" + ) + + if full_line_match := re.match( + r"^\s*\\see +(\w+(?:\.\w+)*)(?:\([^()]*\))?[\s,.:-]*(.*?)$", line + ): + if seeline.startswith("http"): return f"\n.. seealso:: {seeline}\n" suffix = full_line_match.group(2) if suffix: @@ -886,32 +930,36 @@ def process_doxygen_line(line: str) -> str: return f"\n.. seealso:: {seeline or seealso}\n" else: if seeline: - line = line[:see_match.start()] + seeline + seealso_suffix + line[ - see_match.end():] # re.sub(r'\\see +(\w+(\.\w+)*(\(\))?)', seeline, line) + line = ( + line[: see_match.start()] + + seeline + + seealso_suffix + + line[see_match.end() :] + ) # re.sub(r'\\see +(\w+(\.\w+)*(\(\))?)', seeline, line) else: - line = line.replace('\\see', 'see') - elif not re.search(r'\\throws.*', line): + line = line.replace("\\see", "see") + elif not re.search(r"\\throws.*", line): line = create_class_links(line) # Handle note, warning, and throws - note_match = re.search(r'[\\@]note (.*)', line) + note_match = re.search(r"[\\@]note (.*)", line) if note_match: CONTEXT.comment_last_line_note_warning = True CONTEXT.prev_indent = CONTEXT.indent - CONTEXT.indent = '' + CONTEXT.indent = "" return f"\n.. note::\n\n {note_match.group(1)}\n" - warning_match = re.search(r'[\\@]warning (.*)', line) + warning_match = re.search(r"[\\@]warning (.*)", line) if warning_match: CONTEXT.prev_indent = CONTEXT.indent - CONTEXT.indent = '' + CONTEXT.indent = "" CONTEXT.comment_last_line_note_warning = True return f"\n.. warning::\n\n {warning_match.group(1)}\n" - throws_match = re.search(r'[\\@]throws (.+?)\b\s*(.*)', line) + throws_match = re.search(r"[\\@]throws (.+?)\b\s*(.*)", line) if throws_match: CONTEXT.prev_indent = CONTEXT.indent - CONTEXT.indent = '' + CONTEXT.indent = "" CONTEXT.comment_last_line_note_warning = True return f"\n:raises {throws_match.group(1)}: {throws_match.group(2)}\n" @@ -928,19 +976,22 @@ def process_doxygen_line(line: str) -> str: def detect_and_remove_following_body_or_initializerlist(): global CONTEXT - signature = '' + signature = "" # Complex regex pattern to match various C++ function declarations and definitions pattern1 = r'^(\s*)?((?:(?:explicit|static|const|unsigned|virtual)\s+)*)(([(?:long )\w:]+(<.*?>)?\s+[*&]?)?(~?\w+|(\w+::)?operator.{1,2})\s*\(([\w=()\/ ,&*<>."-]|::)*\)( +(?:const|SIP_[\w_]+?))*)\s*((\s*[:,]\s+\w+\(.*\))*\s*\{.*\}\s*(?:SIP_[\w_]+)?;?|(?!;))(\s*\/\/.*)?$' - pattern2 = r'SIP_SKIP\s*(?!;)\s*(\/\/.*)?$' - pattern3 = r'^\s*class.*SIP_SKIP' + pattern2 = r"SIP_SKIP\s*(?!;)\s*(\/\/.*)?$" + pattern3 = r"^\s*class.*SIP_SKIP" - if (re.match(pattern1, CONTEXT.current_line) or - re.search(pattern2, CONTEXT.current_line) or - re.match(pattern3, CONTEXT.current_line)): + if ( + re.match(pattern1, CONTEXT.current_line) + or re.search(pattern2, CONTEXT.current_line) + or re.match(pattern3, CONTEXT.current_line) + ): dbg_info( - "remove constructor definition, function bodies, member initializing list (1)") + "remove constructor definition, function bodies, member initializing list (1)" + ) # Extract the parts we want to keep initializer_match = re.match(pattern1, CONTEXT.current_line) @@ -950,8 +1001,7 @@ def detect_and_remove_following_body_or_initializerlist(): newline = CONTEXT.current_line # Call remove_following_body_or_initializerlist() if necessary - if not re.search(r'{.*}(\s*SIP_\w+)*\s*(//.*)?$', - CONTEXT.current_line): + if not re.search(r"{.*}(\s*SIP_\w+)*\s*(//.*)?$", CONTEXT.current_line): signature = remove_following_body_or_initializerlist() CONTEXT.current_line = newline @@ -962,21 +1012,22 @@ def detect_and_remove_following_body_or_initializerlist(): def remove_following_body_or_initializerlist(): global CONTEXT - signature = '' + signature = "" dbg_info( - "remove constructor definition, function bodies, member initializing list (2)") + "remove constructor definition, function bodies, member initializing list (2)" + ) line = read_line() # Python signature - if re.match(r'^\s*\[\s*(\w+\s*)?\(', line): + if re.match(r"^\s*\[\s*(\w+\s*)?\(", line): dbg_info("python signature detected") _nesting_index = 0 while CONTEXT.line_idx < CONTEXT.line_count: - _nesting_index += line.count('[') - _nesting_index -= line.count(']') + _nesting_index += line.count("[") + _nesting_index -= line.count("]") if _nesting_index == 0: - line_match = re.match(r'^(.*);\s*(//.*)?$', line) + line_match = re.match(r"^(.*);\s*(//.*)?$", line) if line_match: line = line_match.group(1) # remove semicolon (added later) signature += f"\n{line}" @@ -986,17 +1037,17 @@ def remove_following_body_or_initializerlist(): line = read_line() # Member initializing list - while re.match(r'^\s*[:,]\s+([\w<>]|::)+\(.*?\)', line): + while re.match(r"^\s*[:,]\s+([\w<>]|::)+\(.*?\)", line): dbg_info("member initializing list") line = read_line() # Body - if re.match(r'^\s*\{', line): + if re.match(r"^\s*\{", line): _nesting_index = 0 while CONTEXT.line_idx < CONTEXT.line_count: dbg_info(" remove body") - _nesting_index += line.count('{') - _nesting_index -= line.count('}') + _nesting_index += line.count("{") + _nesting_index -= line.count("}") if _nesting_index == 0: break line = read_line() @@ -1010,37 +1061,37 @@ def replace_alternative_types(text): """ # Original perl regex was: # s/(\w+)(\<(?>[^<>]|(?2))*\>)?\s+SIP_PYALTERNATIVETYPE\(\s*\'?([^()']+)(\(\s*(?:[^()]++|(?2))*\s*\))?\'?\s*\)/$3/g; - _pattern = r'(\w+)(<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?\s+SIP_PYALTERNATIVETYPE\(\s*\'?([^()\']+)(\(\s*(?:[^()]|\([^()]*\))*\s*\))?\'?\s*\)' + _pattern = r"(\w+)(<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?\s+SIP_PYALTERNATIVETYPE\(\s*\'?([^()\']+)(\(\s*(?:[^()]|\([^()]*\))*\s*\))?\'?\s*\)" while True: - new_text = re.sub(_pattern, r'\3', text, flags=re.S) + new_text = re.sub(_pattern, r"\3", text, flags=re.S) if new_text == text: return text text = new_text -def split_args(args_string: str) -> List[str]: +def split_args(args_string: str) -> list[str]: """ Tries to split a line of arguments into separate parts """ res = [] - current_arg = '' + current_arg = "" paren_level = 0 angle_level = 0 for char in args_string: - if char == ',' and paren_level == 0 and angle_level == 0: + if char == "," and paren_level == 0 and angle_level == 0: res.append(current_arg.strip()) - current_arg = '' + current_arg = "" else: current_arg += char - if char == '(': + if char == "(": paren_level += 1 - elif char == ')': + elif char == ")": paren_level -= 1 - elif char == '<': + elif char == "<": angle_level += 1 - elif char == '>': + elif char == ">": angle_level -= 1 if current_arg: @@ -1055,37 +1106,38 @@ def remove_sip_pyargremove(input_string: str) -> str: """ global CONTEXT # Split the string into function signature and body - signature_split = re.match(r'(.*?)\((.*)\)(.*)', input_string) - if signature_split and 'SIP_PYARGREMOVE' not in signature_split.group(1): + signature_split = re.match(r"(.*?)\((.*)\)(.*)", input_string) + if signature_split and "SIP_PYARGREMOVE" not in signature_split.group(1): prefix, arguments, suffix = signature_split.groups() - prefix += '(' - suffix = ')' + suffix + prefix += "(" + suffix = ")" + suffix else: - signature_split = re.match(r'(\s*)(.*)\)(.*)', input_string) + signature_split = re.match(r"(\s*)(.*)\)(.*)", input_string) if signature_split: prefix, arguments, suffix = signature_split.groups() - suffix = ')' + suffix + suffix = ")" + suffix else: - prefix = '' + prefix = "" arguments = input_string - suffix = '' + suffix = "" arguments_list = split_args(arguments) if CONTEXT.is_qt6: - filtered_args = [arg for arg in arguments_list if - 'SIP_PYARGREMOVE' not in arg] + filtered_args = [arg for arg in arguments_list if "SIP_PYARGREMOVE" not in arg] else: - filtered_args = [re.sub(r'\s*SIP_PYARGREMOVE6\s*', ' ', arg) - for arg in arguments_list if - not ('SIP_PYARGREMOVE' in arg and 'SIP_PYARGREMOVE6' not in arg)] + filtered_args = [ + re.sub(r"\s*SIP_PYARGREMOVE6\s*", " ", arg) + for arg in arguments_list + if not ("SIP_PYARGREMOVE" in arg and "SIP_PYARGREMOVE6" not in arg) + ] # Reassemble the function signature - remaining_args = ', '.join(filtered_args) + remaining_args = ", ".join(filtered_args) if remaining_args and prefix.strip(): - prefix += ' ' + prefix += " " if remaining_args and suffix.strip(): - suffix = ' ' + suffix + suffix = " " + suffix return f"{prefix}{remaining_args}{suffix}" @@ -1093,50 +1145,50 @@ def fix_annotations(line): global CONTEXT # Get removed params to be able to drop them out of the API doc - removed_params = re.findall(r'(\w+)\s+SIP_PYARGREMOVE', line) + removed_params = re.findall(r"(\w+)\s+SIP_PYARGREMOVE", line) if CONTEXT.is_qt6: - removed_params = re.findall(r'(\w+)\s+SIP_PYARGREMOVE6?', line) + removed_params = re.findall(r"(\w+)\s+SIP_PYARGREMOVE6?", line) for param in removed_params: CONTEXT.skipped_params_remove.append(param) dbg_info(f"caught removed param: {CONTEXT.skipped_params_remove[-1]}") - _out_params = re.findall(r'(\w+)\s+SIP_OUT', line) + _out_params = re.findall(r"(\w+)\s+SIP_OUT", line) for param in _out_params: CONTEXT.skipped_params_out.append(param) dbg_info(f"caught removed param: {CONTEXT.skipped_params_out[-1]}") # Printed annotations replacements = { - r'//\s*SIP_ABSTRACT\b': '/Abstract/', - r'\bSIP_ABSTRACT\b': '/Abstract/', - r'\bSIP_ALLOWNONE\b': '/AllowNone/', - r'\bSIP_ARRAY\b': '/Array/', - r'\bSIP_ARRAYSIZE\b': '/ArraySize/', - r'\bSIP_DEPRECATED\b': '/Deprecated/', - r'\bSIP_CONSTRAINED\b': '/Constrained/', - r'\bSIP_EXTERNAL\b': '/External/', - r'\bSIP_FACTORY\b': '/Factory/', - r'\bSIP_IN\b': '/In/', - r'\bSIP_INOUT\b': '/In,Out/', - r'\bSIP_KEEPREFERENCE\b': '/KeepReference/', - r'\bSIP_NODEFAULTCTORS\b': '/NoDefaultCtors/', - r'\bSIP_OUT\b': '/Out/', - r'\bSIP_RELEASEGIL\b': '/ReleaseGIL/', - r'\bSIP_HOLDGIL\b': '/HoldGIL/', - r'\bSIP_TRANSFER\b': '/Transfer/', - r'\bSIP_TRANSFERBACK\b': '/TransferBack/', - r'\bSIP_TRANSFERTHIS\b': '/TransferThis/', - r'\bSIP_GETWRAPPER\b': '/GetWrapper/', - r'SIP_PYNAME\(\s*(\w+)\s*\)': r'/PyName=\1/', - r'SIP_TYPEHINT\(\s*([\w\.\s,\[\]]+?)\s*\)': r'/TypeHint="\1"/', - r'SIP_VIRTUALERRORHANDLER\(\s*(\w+)\s*\)': r'/VirtualErrorHandler=\1/', + r"//\s*SIP_ABSTRACT\b": "/Abstract/", + r"\bSIP_ABSTRACT\b": "/Abstract/", + r"\bSIP_ALLOWNONE\b": "/AllowNone/", + r"\bSIP_ARRAY\b": "/Array/", + r"\bSIP_ARRAYSIZE\b": "/ArraySize/", + r"\bSIP_DEPRECATED\b": "/Deprecated/", + r"\bSIP_CONSTRAINED\b": "/Constrained/", + r"\bSIP_EXTERNAL\b": "/External/", + r"\bSIP_FACTORY\b": "/Factory/", + r"\bSIP_IN\b": "/In/", + r"\bSIP_INOUT\b": "/In,Out/", + r"\bSIP_KEEPREFERENCE\b": "/KeepReference/", + r"\bSIP_NODEFAULTCTORS\b": "/NoDefaultCtors/", + r"\bSIP_OUT\b": "/Out/", + r"\bSIP_RELEASEGIL\b": "/ReleaseGIL/", + r"\bSIP_HOLDGIL\b": "/HoldGIL/", + r"\bSIP_TRANSFER\b": "/Transfer/", + r"\bSIP_TRANSFERBACK\b": "/TransferBack/", + r"\bSIP_TRANSFERTHIS\b": "/TransferThis/", + r"\bSIP_GETWRAPPER\b": "/GetWrapper/", + r"SIP_PYNAME\(\s*(\w+)\s*\)": r"/PyName=\1/", + r"SIP_TYPEHINT\(\s*([\w\.\s,\[\]]+?)\s*\)": r'/TypeHint="\1"/', + r"SIP_VIRTUALERRORHANDLER\(\s*(\w+)\s*\)": r"/VirtualErrorHandler=\1/", } if not CONTEXT.is_qt6: - replacements[r'SIP_THROW\(\s*([\w\s,]+?)\s*\)'] = r'throw( \1 )' + replacements[r"SIP_THROW\(\s*([\w\s,]+?)\s*\)"] = r"throw( \1 )" else: # these have no effect (and aren't required) on sip >= 6 - replacements[r'SIP_THROW\(\s*([\w\s,]+?)\s*\)'] = '' + replacements[r"SIP_THROW\(\s*([\w\s,]+?)\s*\)"] = "" for _pattern, replacement in replacements.items(): line = re.sub(_pattern, replacement, line) @@ -1145,7 +1197,9 @@ def fix_annotations(line): while True: new_line = re.sub( r'/([\w,]+(="?[\w, \[\]]+"?)?)/\s*/([\w,]+(="?[\w, \[\]]+"?)?]?)/', - r'/\1,\3/', line) + r"/\1,\3/", + line, + ) if new_line == line: break line = new_line @@ -1153,22 +1207,23 @@ def fix_annotations(line): # Unprinted annotations line = replace_alternative_types(line) - line = re.sub(r'(\w+)\s+SIP_PYARGRENAME\(\s*(\w+)\s*\)', r'\2', line) + line = re.sub(r"(\w+)\s+SIP_PYARGRENAME\(\s*(\w+)\s*\)", r"\2", line) # Note: this was the original perl regex, which isn't compatible with Python: # line = re.sub(r"""=\s+[^=]*?\s+SIP_PYARGDEFAULT\(\s*\'?([^()']+)(\(\s*(?:[^()]++|(?2))*\s*\))?\'?\s*\)""", r'= \1', line) line = re.sub( r"""=\s+[^=]*?\s+SIP_PYARGDEFAULT\(\s*\'?([^()\']+)(\((?:[^()]|\([^()]*\))*\))?\'?\s*\)""", - r'= \1', - line) + r"= \1", + line, + ) # Remove argument - if 'SIP_PYARGREMOVE' in line: + if "SIP_PYARGREMOVE" in line: dbg_info("remove arg") if CONTEXT.multiline_definition != MultiLineType.NotMultiline: prev_line = CONTEXT.output.pop().rstrip() # Update multi line status - parenthesis_balance = prev_line.count('(') - prev_line.count(')') + parenthesis_balance = prev_line.count("(") - prev_line.count(")") if parenthesis_balance == 1: CONTEXT.multiline_definition = MultiLineType.NotMultiline # Concatenate with above line to bring previous commas @@ -1176,30 +1231,26 @@ def fix_annotations(line): # original perl regex was: # (?, +)?(const )?(\w+)(\<(?>[^<>]|(?4))*\>)?\s+[\w&*]+\s+SIP_PYARGREMOVE( = [^()]*(\(\s*(?:[^()]++|(?6))*\s*\))?)?(?()|,?)// - if 'SIP_PYARGREMOVE' in line: + if "SIP_PYARGREMOVE" in line: line = remove_sip_pyargremove(line) - line = re.sub(r'\(\s+\)', '()', line) + line = re.sub(r"\(\s+\)", "()", line) - line = re.sub(r'SIP_FORCE', '', line) - line = re.sub(r'SIP_DOC_TEMPLATE', '', line) - line = re.sub(r'\s+;$', ';', line) + line = re.sub(r"SIP_FORCE", "", line) + line = re.sub(r"SIP_DOC_TEMPLATE", "", line) + line = re.sub(r"\s+;$", ";", line) return line def fix_constants(line): - line = re.sub(r'\bstd::numeric_limits::max\(\)', 'DBL_MAX', line) - line = re.sub(r'\bstd::numeric_limits::lowest\(\)', '-DBL_MAX', - line) - line = re.sub(r'\bstd::numeric_limits::epsilon\(\)', 'DBL_EPSILON', - line) - line = re.sub(r'\bstd::numeric_limits::min\(\)', 'LLONG_MIN', - line) - line = re.sub(r'\bstd::numeric_limits::max\(\)', 'LLONG_MAX', - line) - line = re.sub(r'\bstd::numeric_limits::max\(\)', 'INT_MAX', line) - line = re.sub(r'\bstd::numeric_limits::min\(\)', 'INT_MIN', line) + line = re.sub(r"\bstd::numeric_limits::max\(\)", "DBL_MAX", line) + line = re.sub(r"\bstd::numeric_limits::lowest\(\)", "-DBL_MAX", line) + line = re.sub(r"\bstd::numeric_limits::epsilon\(\)", "DBL_EPSILON", line) + line = re.sub(r"\bstd::numeric_limits::min\(\)", "LLONG_MIN", line) + line = re.sub(r"\bstd::numeric_limits::max\(\)", "LLONG_MAX", line) + line = re.sub(r"\bstd::numeric_limits::max\(\)", "INT_MAX", line) + line = re.sub(r"\bstd::numeric_limits::min\(\)", "INT_MIN", line) return line @@ -1208,8 +1259,8 @@ def detect_comment_block(strict_mode=True): global CONTEXT CONTEXT.comment_param_list = False - CONTEXT.indent = '' - CONTEXT.prev_indent = '' + CONTEXT.indent = "" + CONTEXT.prev_indent = "" CONTEXT.comment_code_snippet = CodeSnippetType.NotCodeSnippet CONTEXT.comment_last_line_note_warning = False CONTEXT.found_since = False @@ -1217,21 +1268,24 @@ def detect_comment_block(strict_mode=True): CONTEXT.skipped_params_out = [] CONTEXT.skipped_params_remove = [] - if re.match(r'^\s*/\*', CONTEXT.current_line) or ( - not strict_mode and '/*' in CONTEXT.current_line): + if re.match(r"^\s*/\*", CONTEXT.current_line) or ( + not strict_mode and "/*" in CONTEXT.current_line + ): dbg_info("found comment block") CONTEXT.comment = process_doxygen_line( - re.sub(r'^\s*/\*(\*)?(.*?)\n?$', r'\2', CONTEXT.current_line)) - CONTEXT.comment = re.sub(r'^\s*$', '', CONTEXT.comment) + re.sub(r"^\s*/\*(\*)?(.*?)\n?$", r"\2", CONTEXT.current_line) + ) + CONTEXT.comment = re.sub(r"^\s*$", "", CONTEXT.comment) - while not re.search(r'\*/\s*(//.*?)?$', CONTEXT.current_line): + while not re.search(r"\*/\s*(//.*?)?$", CONTEXT.current_line): CONTEXT.current_line = read_line() CONTEXT.comment += process_doxygen_line( - re.sub(r'\s*\*?(.*?)(/)?\n?$', r'\1', CONTEXT.current_line)) + re.sub(r"\s*\*?(.*?)(/)?\n?$", r"\1", CONTEXT.current_line) + ) - CONTEXT.comment = re.sub(r'\n\s+\n', '\n\n', CONTEXT.comment) - CONTEXT.comment = re.sub(r'\n{3,}', '\n\n', CONTEXT.comment) - CONTEXT.comment = re.sub(r'\n+$', '', CONTEXT.comment) + CONTEXT.comment = re.sub(r"\n\s+\n", "\n\n", CONTEXT.comment) + CONTEXT.comment = re.sub(r"\n{3,}", "\n\n", CONTEXT.comment) + CONTEXT.comment = re.sub(r"\n+$", "", CONTEXT.comment) return True @@ -1239,7 +1293,7 @@ def detect_comment_block(strict_mode=True): def detect_non_method_member(line): - _pattern = r'''^\s*(?:template\s*<\w+>\s+)?(?:(const|mutable|static|friend|unsigned)\s+)*\w+(::\w+)?(<([\w<> *&,()]|::)+>)?(,?\s+\*?\w+( = (-?\d+(\.\d+)?|((QMap|QList)<[^()]+>\(\))|(\w+::)*\w+(\([^()]?\))?)|\[\d+\])?)+;''' + _pattern = r"""^\s*(?:template\s*<\w+>\s+)?(?:(const|mutable|static|friend|unsigned)\s+)*\w+(::\w+)?(<([\w<> *&,()]|::)+>)?(,?\s+\*?\w+( = (-?\d+(\.\d+)?|((QMap|QList)<[^()]+>\(\))|(\w+::)*\w+(\([^()]?\))?)|\[\d+\])?)+;""" return re.match(_pattern, line) @@ -1248,41 +1302,41 @@ def convert_type(cpp_type: str) -> str: Converts C++ types to Python types """ type_mapping = { - 'int': 'int', - 'float': 'float', - 'double': 'float', - 'bool': 'bool', - 'char': 'str', - 'QString': 'str', - 'void': 'None', - 'qint64': 'int', - 'unsigned long long': 'int', - 'long long': 'int', - 'qlonglong': 'int', - 'long': 'int', - 'QStringList': 'List[str]', - 'QVariantList': 'List[object]', - 'QVariantMap': 'Dict[str, object]', - 'QVariant': 'object' + "int": "int", + "float": "float", + "double": "float", + "bool": "bool", + "char": "str", + "QString": "str", + "void": "None", + "qint64": "int", + "unsigned long long": "int", + "long long": "int", + "qlonglong": "int", + "long": "int", + "QStringList": "List[str]", + "QVariantList": "List[object]", + "QVariantMap": "Dict[str, object]", + "QVariant": "object", } # Handle templates - template_match = re.match(r'(\w+)\s*<\s*(.+)\s*>', cpp_type) + template_match = re.match(r"(\w+)\s*<\s*(.+)\s*>", cpp_type) if template_match: container, inner_type = template_match.groups() - if container in ('QVector', 'QList'): + if container in ("QVector", "QList"): return f"List[{convert_type(inner_type.strip())}]" - elif container in ('QSet',): + elif container in ("QSet",): return f"Set[{convert_type(inner_type.strip())}]" - elif container in ('QHash', 'QMap'): - key_type, value_type = [t.strip() for t in inner_type.split(',')] + elif container in ("QHash", "QMap"): + key_type, value_type = (t.strip() for t in inner_type.split(",")) return f"Dict[{convert_type(key_type)}, {convert_type(value_type)}]" else: return f"{container}[{convert_type(inner_type.strip())}]" if cpp_type not in type_mapping: - if cpp_type.startswith('Q'): - cpp_type = cpp_type.replace('::', '.') + if cpp_type.startswith("Q"): + cpp_type = cpp_type.replace("::", ".") return cpp_type assert False, cpp_type @@ -1290,27 +1344,27 @@ def convert_type(cpp_type: str) -> str: return type_mapping[cpp_type] -def parse_argument(arg: str) -> Tuple[str, str, Optional[str]]: +def parse_argument(arg: str) -> tuple[str, str, Optional[str]]: # Remove leading/trailing whitespace and 'const' - arg = re.sub(r'^\s*const\s+', '', arg.strip()) + arg = re.sub(r"^\s*const\s+", "", arg.strip()) # Extract default value if present - default_match = re.search(r'=\s*(.+)$', arg) + default_match = re.search(r"=\s*(.+)$", arg) default_value = default_match.group(1).strip() if default_match else None - arg = re.sub(r'\s*=\s*.+$', '', arg) + arg = re.sub(r"\s*=\s*.+$", "", arg) # Handle pointers and references - is_pointer = '*' in arg - arg = arg.replace('*', '').replace('&', '').strip() + is_pointer = "*" in arg + arg = arg.replace("*", "").replace("&", "").strip() # Split type and variable name parts = arg.split() if len(parts) > 1: - cpp_type = ' '.join(parts[:-1]) + cpp_type = " ".join(parts[:-1]) var_name = parts[-1] else: cpp_type = arg - var_name = '' + var_name = "" python_type = convert_type(cpp_type) if is_pointer and default_value: @@ -1318,27 +1372,25 @@ def parse_argument(arg: str) -> Tuple[str, str, Optional[str]]: # Convert default value if default_value: - default_value_map = { - 'QVariantList()': '[]' - } + default_value_map = {"QVariantList()": "[]"} if default_value in default_value_map: default_value = default_value_map[default_value] elif default_value == "nullptr": default_value = "None" - elif python_type == 'int': + elif python_type == "int": pass - elif cpp_type in ("QString", ): - if default_value == 'QString()': - default_value = 'None' - python_type = f'Optional[{python_type}]' - elif default_value.startswith('Q'): - default_value = default_value.replace('::', '.') + elif cpp_type in ("QString",): + if default_value == "QString()": + default_value = "None" + python_type = f"Optional[{python_type}]" + elif default_value.startswith("Q"): + default_value = default_value.replace("::", ".") else: default_value = f'"{default_value}"' elif cpp_type in ("bool",): default_value = f'{"False" if default_value == "false" else "True"}' - elif cpp_type.startswith('Q'): - default_value = default_value.replace('::', '.') + elif cpp_type.startswith("Q"): + default_value = default_value.replace("::", ".") else: assert False, (default_value, cpp_type) @@ -1348,12 +1400,14 @@ def parse_argument(arg: str) -> Tuple[str, str, Optional[str]]: def cpp_to_python_signature(cpp_function: str) -> str: # Extract function name and arguments - match = re.match(r'(\w+)\s*\((.*)\)\s*(?:const)?\s*(?:->)?\s*([\w:]+)?', cpp_function) + match = re.match( + r"(\w+)\s*\((.*)\)\s*(?:const)?\s*(?:->)?\s*([\w:]+)?", cpp_function + ) if not match: raise ValueError("Invalid C++ function signature") func_name, args_str, return_type = match.groups() - args = [arg.strip() for arg in args_str.split(',') if arg.strip()] + args = [arg.strip() for arg in args_str.split(",") if arg.strip()] # Parse arguments python_args = [] @@ -1374,197 +1428,203 @@ def cpp_to_python_signature(cpp_function: str) -> str: while CONTEXT.line_idx < CONTEXT.line_count: - CONTEXT.python_signature = '' + CONTEXT.python_signature = "" CONTEXT.actual_class = CONTEXT.classname[-1] if CONTEXT.classname else None CONTEXT.current_line = read_line() - if re.match(r'^\s*(#define\s+)?SIP_IF_MODULE\(.*\)$', - CONTEXT.current_line): - dbg_info('skipping SIP include condition macro') + if re.match(r"^\s*(#define\s+)?SIP_IF_MODULE\(.*\)$", CONTEXT.current_line): + dbg_info("skipping SIP include condition macro") continue - match = re.match(r'^(.*?)\s*//\s*cppcheck-suppress.*$', - CONTEXT.current_line) + match = re.match(r"^(.*?)\s*//\s*cppcheck-suppress.*$", CONTEXT.current_line) if match: CONTEXT.current_line = match.group(1) - match = re.match(r'^\s*SIP_FEATURE\(\s*(\w+)\s*\)(.*)$', - CONTEXT.current_line) + match = re.match(r"^\s*SIP_FEATURE\(\s*(\w+)\s*\)(.*)$", CONTEXT.current_line) if match: write_output("SF1", f"%Feature {match.group(1)}{match.group(2)}\n") continue - match = re.match(r'^\s*SIP_PROPERTY\((.*)\)$', CONTEXT.current_line) + match = re.match(r"^\s*SIP_PROPERTY\((.*)\)$", CONTEXT.current_line) if match: write_output("SF1", f"%Property({match.group(1)})\n") continue - match = re.match(r'^\s*SIP_IF_FEATURE\(\s*(!?\w+)\s*\)(.*)$', - CONTEXT.current_line) + match = re.match(r"^\s*SIP_IF_FEATURE\(\s*(!?\w+)\s*\)(.*)$", CONTEXT.current_line) if match: write_output("SF2", f"%If ({match.group(1)}){match.group(2)}\n") continue - match = re.match(r'^\s*SIP_CONVERT_TO_SUBCLASS_CODE(.*)$', - CONTEXT.current_line) + match = re.match(r"^\s*SIP_CONVERT_TO_SUBCLASS_CODE(.*)$", CONTEXT.current_line) if match: CONTEXT.current_line = f"%ConvertToSubClassCode{match.group(1)}" # Do not continue here, let the code process the next steps - match = re.match(r'^\s*SIP_VIRTUAL_CATCHER_CODE(.*)$', - CONTEXT.current_line) + match = re.match(r"^\s*SIP_VIRTUAL_CATCHER_CODE(.*)$", CONTEXT.current_line) if match: CONTEXT.current_line = f"%VirtualCatcherCode{match.group(1)}" # Do not continue here, let the code process the next steps - match = re.match(r'^\s*SIP_END(.*)$', CONTEXT.current_line) + match = re.match(r"^\s*SIP_END(.*)$", CONTEXT.current_line) if match: write_output("SEN", f"%End{match.group(1)}\n") continue - match = re.search(r'SIP_WHEN_FEATURE\(\s*(.*?)\s*\)', CONTEXT.current_line) + match = re.search(r"SIP_WHEN_FEATURE\(\s*(.*?)\s*\)", CONTEXT.current_line) if match: - dbg_info('found SIP_WHEN_FEATURE') + dbg_info("found SIP_WHEN_FEATURE") CONTEXT.if_feature_condition = match.group(1) if CONTEXT.is_qt6: - CONTEXT.current_line = re.sub(r'int\s*__len__\s*\(\s*\)', - 'Py_ssize_t __len__()', - CONTEXT.current_line) - CONTEXT.current_line = re.sub(r'long\s*__hash__\s*\(\s*\)', - 'Py_hash_t __hash__()', - CONTEXT.current_line) - - if CONTEXT.is_qt6 and re.match(r'^\s*#ifdef SIP_PYQT5_RUN', - CONTEXT.current_line): + CONTEXT.current_line = re.sub( + r"int\s*__len__\s*\(\s*\)", "Py_ssize_t __len__()", CONTEXT.current_line + ) + CONTEXT.current_line = re.sub( + r"long\s*__hash__\s*\(\s*\)", "Py_hash_t __hash__()", CONTEXT.current_line + ) + + if CONTEXT.is_qt6 and re.match(r"^\s*#ifdef SIP_PYQT5_RUN", CONTEXT.current_line): dbg_info("do not process PYQT5 code") - while not re.match(r'^#endif', CONTEXT.current_line): + while not re.match(r"^#endif", CONTEXT.current_line): CONTEXT.current_line = read_line() - if not CONTEXT.is_qt6 and re.match(r'^\s*#ifdef SIP_PYQT6_RUN', - CONTEXT.current_line): + if not CONTEXT.is_qt6 and re.match( + r"^\s*#ifdef SIP_PYQT6_RUN", CONTEXT.current_line + ): dbg_info("do not process PYQT6 code") - while not re.match(r'^#endif', CONTEXT.current_line): + while not re.match(r"^#endif", CONTEXT.current_line): CONTEXT.current_line = read_line() # Do not process SIP code %XXXCode if CONTEXT.sip_run and re.match( - r'^ *% *(VirtualErrorHandler|MappedType|Type(?:Header)?Code|Module(?:Header)?Code|Convert(?:From|To)(?:Type|SubClass)Code|MethodCode|Docstring)(.*)?$', - CONTEXT.current_line): - CONTEXT.current_line = f"%{re.match(r'^ *% *(.*)$', CONTEXT.current_line).group(1)}" - CONTEXT.comment = '' + r"^ *% *(VirtualErrorHandler|MappedType|Type(?:Header)?Code|Module(?:Header)?Code|Convert(?:From|To)(?:Type|SubClass)Code|MethodCode|Docstring)(.*)?$", + CONTEXT.current_line, + ): + CONTEXT.current_line = ( + f"%{re.match(r'^ *% *(.*)$', CONTEXT.current_line).group(1)}" + ) + CONTEXT.comment = "" dbg_info("do not process SIP code") - while not re.match(r'^ *% *End', CONTEXT.current_line): + while not re.match(r"^ *% *End", CONTEXT.current_line): write_output("COD", CONTEXT.current_line + "\n") CONTEXT.current_line = read_line() if CONTEXT.is_qt6: - CONTEXT.current_line = re.sub(r'SIP_SSIZE_T', 'Py_ssize_t', - CONTEXT.current_line) - CONTEXT.current_line = re.sub(r'SIPLong_AsLong', - 'PyLong_AsLong', - CONTEXT.current_line) + CONTEXT.current_line = re.sub( + r"SIP_SSIZE_T", "Py_ssize_t", CONTEXT.current_line + ) + CONTEXT.current_line = re.sub( + r"SIPLong_AsLong", "PyLong_AsLong", CONTEXT.current_line + ) + CONTEXT.current_line = re.sub( + r"^ *% *(VirtualErrorHandler|MappedType|Type(?:Header)?Code|Module(?:Header)?Code|Convert(?:From|To)(?:Type|SubClass)Code|MethodCode|Docstring)(.*)?$", + r"%\1\2", + CONTEXT.current_line, + ) CONTEXT.current_line = re.sub( - r'^ *% *(VirtualErrorHandler|MappedType|Type(?:Header)?Code|Module(?:Header)?Code|Convert(?:From|To)(?:Type|SubClass)Code|MethodCode|Docstring)(.*)?$', - r'%\1\2', CONTEXT.current_line) - CONTEXT.current_line = re.sub(r'^\s*SIP_END(.*)$', r'%End\1', - CONTEXT.current_line) + r"^\s*SIP_END(.*)$", r"%End\1", CONTEXT.current_line + ) - CONTEXT.current_line = re.sub(r'^\s*% End', '%End', - CONTEXT.current_line) + CONTEXT.current_line = re.sub(r"^\s*% End", "%End", CONTEXT.current_line) write_output("COD", CONTEXT.current_line + "\n") continue # Do not process SIP code %Property - if CONTEXT.sip_run and re.match(r'^ *% *(Property)(.*)?$', - CONTEXT.current_line): - CONTEXT.current_line = f"%{re.match(r'^ *% *(.*)$', CONTEXT.current_line).group(1)}" - CONTEXT.comment = '' + if CONTEXT.sip_run and re.match(r"^ *% *(Property)(.*)?$", CONTEXT.current_line): + CONTEXT.current_line = ( + f"%{re.match(r'^ *% *(.*)$', CONTEXT.current_line).group(1)}" + ) + CONTEXT.comment = "" write_output("COD", CONTEXT.current_line + "\n") continue # Do not process SIP code %If %End - if CONTEXT.sip_run and re.match(r'^ *% (If|End)(.*)?$', - CONTEXT.current_line): - CONTEXT.current_line = f"%{re.match(r'^ *% (.*)$', CONTEXT.current_line).group(1)}" - CONTEXT.comment = '' + if CONTEXT.sip_run and re.match(r"^ *% (If|End)(.*)?$", CONTEXT.current_line): + CONTEXT.current_line = ( + f"%{re.match(r'^ *% (.*)$', CONTEXT.current_line).group(1)}" + ) + CONTEXT.comment = "" write_output("COD", CONTEXT.current_line) continue # Skip preprocessor directives - if re.match(r'^\s*#', CONTEXT.current_line): + if re.match(r"^\s*#", CONTEXT.current_line): # Skip #if 0 or #if defined(Q_OS_WIN) blocks - match = re.match(r'^\s*#if (0|defined\(Q_OS_WIN\))', - CONTEXT.current_line) + match = re.match(r"^\s*#if (0|defined\(Q_OS_WIN\))", CONTEXT.current_line) if match: dbg_info(f"skipping #if {match.group(1)} block") nesting_index = 0 while CONTEXT.line_idx < CONTEXT.line_count: CONTEXT.current_line = read_line() - if re.match(r'^\s*#if(def)?\s+', CONTEXT.current_line): + if re.match(r"^\s*#if(def)?\s+", CONTEXT.current_line): nesting_index += 1 - elif nesting_index == 0 and re.match(r'^\s*#(endif|else)', - CONTEXT.current_line): - CONTEXT.comment = '' + elif nesting_index == 0 and re.match( + r"^\s*#(endif|else)", CONTEXT.current_line + ): + CONTEXT.comment = "" break - elif nesting_index != 0 and re.match(r'^\s*#endif', - CONTEXT.current_line): + elif nesting_index != 0 and re.match( + r"^\s*#endif", CONTEXT.current_line + ): nesting_index -= 1 continue - if re.match(r'^\s*#ifdef SIP_RUN', CONTEXT.current_line): + if re.match(r"^\s*#ifdef SIP_RUN", CONTEXT.current_line): CONTEXT.sip_run = True if CONTEXT.access[-1] == Visibility.Private: dbg_info("writing private content (1)") if CONTEXT.private_section_line: write_output("PRV1", CONTEXT.private_section_line + "\n") - CONTEXT.private_section_line = '' + CONTEXT.private_section_line = "" continue if CONTEXT.sip_run: - if re.match(r'^\s*#endif', CONTEXT.current_line): + if re.match(r"^\s*#endif", CONTEXT.current_line): if CONTEXT.ifdef_nesting_idx == 0: CONTEXT.sip_run = False continue else: CONTEXT.ifdef_nesting_idx -= 1 - if re.match(r'^\s*#if(def)?\s+', CONTEXT.current_line): + if re.match(r"^\s*#if(def)?\s+", CONTEXT.current_line): CONTEXT.ifdef_nesting_idx += 1 # If there is an else at this level, code will be ignored (i.e., not SIP_RUN) - if re.match(r'^\s*#else', - CONTEXT.current_line) and CONTEXT.ifdef_nesting_idx == 0: + if ( + re.match(r"^\s*#else", CONTEXT.current_line) + and CONTEXT.ifdef_nesting_idx == 0 + ): while CONTEXT.line_idx < CONTEXT.line_count: CONTEXT.current_line = read_line() - if re.match(r'^\s*#if(def)?\s+', CONTEXT.current_line): + if re.match(r"^\s*#if(def)?\s+", CONTEXT.current_line): CONTEXT.ifdef_nesting_idx += 1 - elif re.match(r'^\s*#endif', CONTEXT.current_line): + elif re.match(r"^\s*#endif", CONTEXT.current_line): if CONTEXT.ifdef_nesting_idx == 0: - CONTEXT.comment = '' + CONTEXT.comment = "" CONTEXT.sip_run = False break else: CONTEXT.ifdef_nesting_idx -= 1 continue - elif re.match(r'^\s*#ifndef SIP_RUN', CONTEXT.current_line): + elif re.match(r"^\s*#ifndef SIP_RUN", CONTEXT.current_line): # Code is ignored here while CONTEXT.line_idx < CONTEXT.line_count: CONTEXT.current_line = read_line() - if re.match(r'^\s*#if(def)?\s+', CONTEXT.current_line): + if re.match(r"^\s*#if(def)?\s+", CONTEXT.current_line): CONTEXT.ifdef_nesting_idx += 1 - elif re.match(r'^\s*#else', - CONTEXT.current_line) and CONTEXT.ifdef_nesting_idx == 0: + elif ( + re.match(r"^\s*#else", CONTEXT.current_line) + and CONTEXT.ifdef_nesting_idx == 0 + ): # Code here will be printed out if CONTEXT.access[-1] == Visibility.Private: dbg_info("writing private content (2)") - if CONTEXT.private_section_line != '': - write_output("PRV2", - CONTEXT.private_section_line + "\n") - CONTEXT.private_section_line = '' + if CONTEXT.private_section_line != "": + write_output("PRV2", CONTEXT.private_section_line + "\n") + CONTEXT.private_section_line = "" CONTEXT.sip_run = True break - elif re.match(r'^\s*#endif', CONTEXT.current_line): + elif re.match(r"^\s*#endif", CONTEXT.current_line): if CONTEXT.ifdef_nesting_idx == 0: CONTEXT.sip_run = 0 break @@ -1582,80 +1642,88 @@ def cpp_to_python_signature(cpp_function: str) -> str: # Skip forward declarations match = re.match( - r'^\s*(template ? |enum\s+)?(class|struct) \w+(?P *SIP_EXTERNAL)?;\s*(//.*)?$', - CONTEXT.current_line) + r"^\s*(template ? |enum\s+)?(class|struct) \w+(?P *SIP_EXTERNAL)?;\s*(//.*)?$", + CONTEXT.current_line, + ) if match: - if match.group('external'): - dbg_info('do not skip external forward declaration') - CONTEXT.comment = '' + if match.group("external"): + dbg_info("do not skip external forward declaration") + CONTEXT.comment = "" else: - dbg_info('skipping forward declaration') + dbg_info("skipping forward declaration") continue # Skip friend declarations - if re.match(r'^\s*friend class \w+', CONTEXT.current_line): + if re.match(r"^\s*friend class \w+", CONTEXT.current_line): continue # Insert metaobject for Q_GADGET - if re.match(r'^\s*Q_GADGET\b.*?$', CONTEXT.current_line): - if not re.search(r'SIP_SKIP', CONTEXT.current_line): - dbg_info('Q_GADGET') + if re.match(r"^\s*Q_GADGET\b.*?$", CONTEXT.current_line): + if not re.search(r"SIP_SKIP", CONTEXT.current_line): + dbg_info("Q_GADGET") write_output("HCE", " public:\n") - write_output("HCE", - " static const QMetaObject staticMetaObject;\n\n") + write_output("HCE", " static const QMetaObject staticMetaObject;\n\n") continue # Insert in Python output (python/module/__init__.py) - match = re.search(r'Q_(ENUM|FLAG)\(\s*(\w+)\s*\)', CONTEXT.current_line) + match = re.search(r"Q_(ENUM|FLAG)\(\s*(\w+)\s*\)", CONTEXT.current_line) if match: - if not re.search(r'SIP_SKIP', CONTEXT.current_line): - is_flag = 1 if match.group(1) == 'FLAG' else 0 + if not re.search(r"SIP_SKIP", CONTEXT.current_line): + is_flag = 1 if match.group(1) == "FLAG" else 0 enum_helper = f"{CONTEXT.actual_class}.{match.group(2)}.baseClass = {CONTEXT.actual_class}" dbg_info(f"Q_ENUM/Q_FLAG {enum_helper}") if args.python_output: - if enum_helper != '': + if enum_helper != "": CONTEXT.output_python.append(f"{enum_helper}\n") if is_flag == 1: # SIP seems to introduce the flags in the module rather than in the class itself # as a dirty hack, inject directly in module, hopefully we don't have flags with the same name... CONTEXT.output_python.append( - f"{match.group(2)} = {CONTEXT.actual_class} # dirty hack since SIP seems to introduce the flags in module\n") + f"{match.group(2)} = {CONTEXT.actual_class} # dirty hack since SIP seems to introduce the flags in module\n" + ) continue # Skip Q_OBJECT, Q_PROPERTY, Q_ENUM, etc. if re.match( - r'^\s*Q_(OBJECT|ENUMS|ENUM|FLAG|PROPERTY|DECLARE_METATYPE|DECLARE_TYPEINFO|NOWARN_DEPRECATED_(PUSH|POP))\b.*?$', - CONTEXT.current_line): + r"^\s*Q_(OBJECT|ENUMS|ENUM|FLAG|PROPERTY|DECLARE_METATYPE|DECLARE_TYPEINFO|NOWARN_DEPRECATED_(PUSH|POP))\b.*?$", + CONTEXT.current_line, + ): continue - if re.match(r'^\s*QHASH_FOR_CLASS_ENUM', CONTEXT.current_line): + if re.match(r"^\s*QHASH_FOR_CLASS_ENUM", CONTEXT.current_line): continue - if re.search(r'SIP_SKIP|SIP_PYTHON_SPECIAL_', CONTEXT.current_line): - dbg_info('SIP SKIP!') + if re.search(r"SIP_SKIP|SIP_PYTHON_SPECIAL_", CONTEXT.current_line): + dbg_info("SIP SKIP!") # if multiline definition, remove previous lines if CONTEXT.multiline_definition != MultiLineType.NotMultiline: - dbg_info('SIP_SKIP with MultiLine') - opening_line = '' - while not re.match(r'^[^()]*\(([^()]*\([^()]*\)[^()]*)*[^()]*$', - opening_line): + dbg_info("SIP_SKIP with MultiLine") + opening_line = "" + while not re.match( + r"^[^()]*\(([^()]*\([^()]*\)[^()]*)*[^()]*$", opening_line + ): opening_line = CONTEXT.output.pop() if len(CONTEXT.output) < 1: - exit_with_error('could not reach opening definition') + exit_with_error("could not reach opening definition") dbg_info("removed multiline definition of SIP_SKIP method") CONTEXT.multiline_definition = MultiLineType.NotMultiline - del CONTEXT.static_methods[CONTEXT.current_fully_qualified_class_name()][CONTEXT.current_method_name] + del CONTEXT.static_methods[CONTEXT.current_fully_qualified_class_name()][ + CONTEXT.current_method_name + ] # also skip method body if there is one detect_and_remove_following_body_or_initializerlist() # line skipped, go to next iteration - match = re.search(r'SIP_PYTHON_SPECIAL_(\w+)\(\s*(".*"|\w+)\s*\)', - CONTEXT.current_line) + match = re.search( + r'SIP_PYTHON_SPECIAL_(\w+)\(\s*(".*"|\w+)\s*\)', CONTEXT.current_line + ) if match: method_or_code = match.group(2) dbg_info(f"PYTHON SPECIAL method or code: {method_or_code}") - pyop = f"{CONTEXT.actual_class}.__{match.group(1).lower()}__ = lambda self: " + pyop = ( + f"{CONTEXT.actual_class}.__{match.group(1).lower()}__ = lambda self: " + ) if re.match(r'^".*"$', method_or_code): pyop += method_or_code.strip('"') else: @@ -1664,7 +1732,7 @@ def cpp_to_python_signature(cpp_function: str) -> str: if args.python_output: CONTEXT.output_python.append(f"{pyop}\n") - CONTEXT.comment = '' + CONTEXT.comment = "" continue # Detect comment block @@ -1672,16 +1740,20 @@ def cpp_to_python_signature(cpp_function: str) -> str: continue struct_match = re.match( - r'^\s*struct(\s+\w+_EXPORT)?\s+(?P\w+)$', - CONTEXT.current_line) + r"^\s*struct(\s+\w+_EXPORT)?\s+(?P\w+)$", CONTEXT.current_line + ) if struct_match: dbg_info(" going to struct => public") - CONTEXT.class_and_struct.append(struct_match.group('structname')) + CONTEXT.class_and_struct.append(struct_match.group("structname")) CONTEXT.classname.append( - CONTEXT.classname[-1] if CONTEXT.classname else struct_match.group( - 'structname')) # fake new class since struct has considered similarly + CONTEXT.classname[-1] + if CONTEXT.classname + else struct_match.group("structname") + ) # fake new class since struct has considered similarly if CONTEXT.access[-1] != Visibility.Private: - CONTEXT.all_fully_qualified_class_names.append(CONTEXT.current_fully_qualified_struct_name()) + CONTEXT.all_fully_qualified_class_names.append( + CONTEXT.current_fully_qualified_struct_name() + ) CONTEXT.access.append(Visibility.Public) CONTEXT.exported.append(CONTEXT.exported[-1]) CONTEXT.bracket_nesting_idx.append(0) @@ -1702,10 +1774,12 @@ def cpp_to_python_signature(cpp_function: str) -> str: template_inheritance_class2 = [] template_inheritance_class3 = [] - CONTEXT.classname.append(class_pattern_match.group('classname')) - CONTEXT.class_and_struct.append(class_pattern_match.group('classname')) + CONTEXT.classname.append(class_pattern_match.group("classname")) + CONTEXT.class_and_struct.append(class_pattern_match.group("classname")) if CONTEXT.access[-1] != Visibility.Private: - CONTEXT.all_fully_qualified_class_names.append(CONTEXT.current_fully_qualified_struct_name()) + CONTEXT.all_fully_qualified_class_names.append( + CONTEXT.current_fully_qualified_struct_name() + ) CONTEXT.access.append(Visibility.Public) if len(CONTEXT.classname) == 1: @@ -1714,63 +1788,70 @@ def cpp_to_python_signature(cpp_function: str) -> str: dbg_info(f"class: {CONTEXT.classname[-1]}") if ( - re.search(r'\b[A-Z0-9_]+_EXPORT\b', CONTEXT.current_line) + re.search(r"\b[A-Z0-9_]+_EXPORT\b", CONTEXT.current_line) or len(CONTEXT.classname) != 1 - or re.search(r'^\s*template\s*<', - CONTEXT.input_lines[CONTEXT.line_idx - 2]) + or re.search(r"^\s*template\s*<", CONTEXT.input_lines[CONTEXT.line_idx - 2]) ): CONTEXT.exported[-1] += 1 - CONTEXT.current_line = f"{class_pattern_match.group(1)} {class_pattern_match.group('classname')}" + CONTEXT.current_line = ( + f"{class_pattern_match.group(1)} {class_pattern_match.group('classname')}" + ) # append to class map file if args.class_map: - with open(args.class_map, 'a') as fh3: + with open(args.class_map, "a") as fh3: fh3.write( - f"{'.'.join(CONTEXT.classname)}: {CONTEXT.header_file}#L{CONTEXT.line_idx}\n") + f"{'.'.join(CONTEXT.classname)}: {CONTEXT.header_file}#L{CONTEXT.line_idx}\n" + ) # Inheritance - if class_pattern_match.group('domain'): - m = class_pattern_match.group('domain') - m = re.sub(r'public +(\w+, *)*(Ui::\w+,? *)+', '', m) - m = re.sub(r'public +', '', m) - m = re.sub(r'[,:]?\s*private +\w+(::\w+)?', '', m) + if class_pattern_match.group("domain"): + m = class_pattern_match.group("domain") + m = re.sub(r"public +(\w+, *)*(Ui::\w+,? *)+", "", m) + m = re.sub(r"public +", "", m) + m = re.sub(r"[,:]?\s*private +\w+(::\w+)?", "", m) # detect template based inheritance # https://regex101.com/r/9LGhyy/1 tpl_pattern = re.compile( - r'[,:]\s+(?P(?!QList)\w+)< *(?P(\w|::)+) *(, *(?P(\w|::)+)? *(, *(?P(\w|::)+)? *)?)? *>' + r"[,:]\s+(?P(?!QList)\w+)< *(?P(\w|::)+) *(, *(?P(\w|::)+)? *(, *(?P(\w|::)+)? *)?)? *>" ) for match in tpl_pattern.finditer(m): dbg_info("template class") - template_inheritance_template.append(match.group('tpl')) - template_inheritance_class1.append(match.group('cls1')) - template_inheritance_class2.append(match.group('cls2') or "") - template_inheritance_class3.append(match.group('cls3') or "") + template_inheritance_template.append(match.group("tpl")) + template_inheritance_class1.append(match.group("cls1")) + template_inheritance_class2.append(match.group("cls2") or "") + template_inheritance_class3.append(match.group("cls3") or "") dbg_info(f"domain: {m}") tpl_replace_pattern = re.compile( - r'\b(?P(?!QList)\w+)< *(?P(\w|::)+) *(, *(?P(\w|::)+)? *(, *(?P(\w|::)+)? *)?)? *>' + r"\b(?P(?!QList)\w+)< *(?P(\w|::)+) *(, *(?P(\w|::)+)? *(, *(?P(\w|::)+)? *)?)? *>" + ) + m = tpl_replace_pattern.sub( + lambda tpl_match: f"{tpl_match.group('tpl') or ''}{tpl_match.group('cls1') or ''}{tpl_match.group('cls2') or ''}{tpl_match.group('cls3') or ''}Base", + m, ) - m = tpl_replace_pattern.sub(lambda - tpl_match: f"{tpl_match.group('tpl') or ''}{tpl_match.group('cls1') or ''}{tpl_match.group('cls2') or ''}{tpl_match.group('cls3') or ''}Base", - m) - m = re.sub(r'(\w+)< *(?:\w|::)+ *>', '', m) - m = re.sub(r'([:,])\s*,', r'\1', m) - m = re.sub(r'(\s*[:,])?\s*$', '', m) + m = re.sub(r"(\w+)< *(?:\w|::)+ *>", "", m) + m = re.sub(r"([:,])\s*,", r"\1", m) + m = re.sub(r"(\s*[:,])?\s*$", "", m) CONTEXT.current_line += m - if class_pattern_match.group('annot'): - CONTEXT.current_line += class_pattern_match.group('annot') + if class_pattern_match.group("annot"): + CONTEXT.current_line += class_pattern_match.group("annot") CONTEXT.current_line = fix_annotations(CONTEXT.current_line) CONTEXT.current_line += "\n{\n" if CONTEXT.comment.strip(): - CONTEXT.current_line += "%Docstring(signature=\"appended\")\n" + CONTEXT.comment + "\n%End\n" + CONTEXT.current_line += ( + '%Docstring(signature="appended")\n' + CONTEXT.comment + "\n%End\n" + ) - CONTEXT.current_line += f"\n%TypeHeaderCode\n#include \"{os.path.basename(CONTEXT.header_file)}\"" + CONTEXT.current_line += ( + f'\n%TypeHeaderCode\n#include "{os.path.basename(CONTEXT.header_file)}"' + ) # for template based inheritance, add a typedef to define the base type while template_inheritance_template: @@ -1788,19 +1869,23 @@ def cpp_to_python_signature(cpp_function: str) -> str: if tpl not in CONTEXT.declared_classes: tpl_header = f"{tpl.lower()}.h" - if tpl in sip_config['class_headerfile']: - tpl_header = sip_config['class_headerfile'][tpl] - CONTEXT.current_line += f"\n#include \"{tpl_header}\"" + if tpl in sip_config["class_headerfile"]: + tpl_header = sip_config["class_headerfile"][tpl] + CONTEXT.current_line += f'\n#include "{tpl_header}"' if cls2 == "": CONTEXT.current_line += f"\ntypedef {tpl}<{cls1}> {tpl}{cls1}Base;" elif cls3 == "": - CONTEXT.current_line += f"\ntypedef {tpl}<{cls1},{cls2}> {tpl}{cls1}{cls2}Base;" + CONTEXT.current_line += ( + f"\ntypedef {tpl}<{cls1},{cls2}> {tpl}{cls1}{cls2}Base;" + ) else: CONTEXT.current_line += f"\ntypedef {tpl}<{cls1},{cls2},{cls3}> {tpl}{cls1}{cls2}{cls3}Base;" - if any(x == Visibility.Private for x in CONTEXT.access) and len( - CONTEXT.access) != 1: + if ( + any(x == Visibility.Private for x in CONTEXT.access) + and len(CONTEXT.access) != 1 + ): dbg_info("skipping class in private context") continue @@ -1809,11 +1894,11 @@ def cpp_to_python_signature(cpp_function: str) -> str: # Skip opening curly bracket, incrementing hereunder skip = read_line() - if not re.match(r'^\s*{\s*$', skip): + if not re.match(r"^\s*{\s*$", skip): exit_with_error("expecting { after class definition") CONTEXT.bracket_nesting_idx[-1] += 1 - CONTEXT.comment = '' + CONTEXT.comment = "" CONTEXT.header_code = True CONTEXT.access[-1] = Visibility.Private continue @@ -1821,8 +1906,8 @@ def cpp_to_python_signature(cpp_function: str) -> str: # Bracket balance in class/struct tree if not CONTEXT.sip_run: bracket_balance = 0 - bracket_balance += CONTEXT.current_line.count('{') - bracket_balance -= CONTEXT.current_line.count('}') + bracket_balance += CONTEXT.current_line.count("{") + bracket_balance -= CONTEXT.current_line.count("}") if bracket_balance != 0: CONTEXT.bracket_nesting_idx[-1] += bracket_balance @@ -1835,8 +1920,8 @@ def cpp_to_python_signature(cpp_function: str) -> str: CONTEXT.access.pop() if CONTEXT.exported[-1] == 0 and CONTEXT.classname[ - -1] != sip_config.get( - 'no_export_macro'): + -1 + ] != sip_config.get("no_export_macro"): exit_with_error( f"Class {CONTEXT.classname[-1]} should be exported with appropriate [LIB]_EXPORT macro. " f"If this should not be available in python, wrap it in a `#ifndef SIP_RUN` block." @@ -1849,152 +1934,168 @@ def cpp_to_python_signature(cpp_function: str) -> str: if len(CONTEXT.access) == 1: dbg_info("reached top level") - CONTEXT.access[ - -1] = Visibility.Public # Top level should stay public + CONTEXT.access[-1] = ( + Visibility.Public + ) # Top level should stay public - CONTEXT.comment = '' - CONTEXT.return_type = '' - CONTEXT.private_section_line = '' + CONTEXT.comment = "" + CONTEXT.return_type = "" + CONTEXT.private_section_line = "" dbg_info(f"new bracket balance: {CONTEXT.bracket_nesting_idx}") # Private members (exclude SIP_RUN) - if re.match(r'^\s*private( slots)?:', CONTEXT.current_line): + if re.match(r"^\s*private( slots)?:", CONTEXT.current_line): CONTEXT.access[-1] = Visibility.Private CONTEXT.last_access_section_line = CONTEXT.current_line CONTEXT.private_section_line = CONTEXT.current_line - CONTEXT.comment = '' + CONTEXT.comment = "" dbg_info("going private") continue - elif re.match(r'^\s*(public( slots)?):.*$', CONTEXT.current_line): + elif re.match(r"^\s*(public( slots)?):.*$", CONTEXT.current_line): dbg_info("going public") CONTEXT.last_access_section_line = CONTEXT.current_line CONTEXT.access[-1] = Visibility.Public - CONTEXT.comment = '' + CONTEXT.comment = "" - elif re.match(r'^\s*signals:.*$', CONTEXT.current_line): + elif re.match(r"^\s*signals:.*$", CONTEXT.current_line): dbg_info("going public for signals") CONTEXT.last_access_section_line = CONTEXT.current_line CONTEXT.access[-1] = Visibility.Signals - CONTEXT.comment = '' + CONTEXT.comment = "" - elif re.match(r'^\s*(protected)( slots)?:.*$', CONTEXT.current_line): + elif re.match(r"^\s*(protected)( slots)?:.*$", CONTEXT.current_line): dbg_info("going protected") CONTEXT.last_access_section_line = CONTEXT.current_line CONTEXT.access[-1] = Visibility.Protected - CONTEXT.comment = '' + CONTEXT.comment = "" - elif CONTEXT.access[ - -1] == Visibility.Private and 'SIP_FORCE' in CONTEXT.current_line: + elif ( + CONTEXT.access[-1] == Visibility.Private and "SIP_FORCE" in CONTEXT.current_line + ): dbg_info("private with SIP_FORCE") if CONTEXT.private_section_line: write_output("PRV3", CONTEXT.private_section_line + "\n") - CONTEXT.private_section_line = '' + CONTEXT.private_section_line = "" - elif any(x == Visibility.Private for x in - CONTEXT.access) and not CONTEXT.sip_run: - CONTEXT.comment = '' + elif any(x == Visibility.Private for x in CONTEXT.access) and not CONTEXT.sip_run: + CONTEXT.comment = "" continue # Skip operators if CONTEXT.access[-1] != Visibility.Private and re.search( - r'operator(=|<<|>>|->)\s*\(', CONTEXT.current_line): + r"operator(=|<<|>>|->)\s*\(", CONTEXT.current_line + ): dbg_info("skip operator") detect_and_remove_following_body_or_initializerlist() continue # Save comments and do not print them, except in SIP_RUN if not CONTEXT.sip_run: - if re.match(r'^\s*//', CONTEXT.current_line): - match = re.match(r'^\s*//!\s*(.*?)\n?$', CONTEXT.current_line) + if re.match(r"^\s*//", CONTEXT.current_line): + match = re.match(r"^\s*//!\s*(.*?)\n?$", CONTEXT.current_line) if match: CONTEXT.comment_param_list = False CONTEXT.prev_indent = CONTEXT.indent - CONTEXT.indent = '' + CONTEXT.indent = "" CONTEXT.comment_last_line_note_warning = False CONTEXT.comment = process_doxygen_line(match.group(1)) CONTEXT.comment = CONTEXT.comment.rstrip() - elif not re.search(r'\*/', - CONTEXT.input_lines[CONTEXT.line_idx - 1]): - CONTEXT.comment = '' + elif not re.search(r"\*/", CONTEXT.input_lines[CONTEXT.line_idx - 1]): + CONTEXT.comment = "" continue # Handle Q_DECLARE_FLAGS in Qt6 if CONTEXT.is_qt6 and re.match( - r'^\s*Q_DECLARE_FLAGS\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)', - CONTEXT.current_line): - flags_name = re.search(r'\(\s*(\w+)\s*,\s*(\w+)\s*\)', - CONTEXT.current_line).group(1) - flag_name = re.search(r'\(\s*(\w+)\s*,\s*(\w+)\s*\)', - CONTEXT.current_line).group(2) + r"^\s*Q_DECLARE_FLAGS\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)", CONTEXT.current_line + ): + flags_name = re.search( + r"\(\s*(\w+)\s*,\s*(\w+)\s*\)", CONTEXT.current_line + ).group(1) + flag_name = re.search( + r"\(\s*(\w+)\s*,\s*(\w+)\s*\)", CONTEXT.current_line + ).group(2) CONTEXT.output_python.append( - f"{CONTEXT.actual_class}.{flags_name} = lambda flags=0: {CONTEXT.actual_class}.{flag_name}(flags)\n") + f"{CONTEXT.actual_class}.{flags_name} = lambda flags=0: {CONTEXT.actual_class}.{flag_name}(flags)\n" + ) # Enum declaration # For scoped and type-based enum, the type has to be removed if re.match( - r'^\s*Q_DECLARE_FLAGS\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)\s*SIP_MONKEYPATCH_FLAGS_UNNEST\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)\s*$', - CONTEXT.current_line): - flags_name = re.search(r'\(\s*(\w+)\s*,\s*(\w+)\s*\)', - CONTEXT.current_line).group(1) - flag_name = re.search(r'\(\s*(\w+)\s*,\s*(\w+)\s*\)', - CONTEXT.current_line).group(2) + r"^\s*Q_DECLARE_FLAGS\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)\s*SIP_MONKEYPATCH_FLAGS_UNNEST\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)\s*$", + CONTEXT.current_line, + ): + flags_name = re.search( + r"\(\s*(\w+)\s*,\s*(\w+)\s*\)", CONTEXT.current_line + ).group(1) + flag_name = re.search( + r"\(\s*(\w+)\s*,\s*(\w+)\s*\)", CONTEXT.current_line + ).group(2) emkb = re.search( - r'SIP_MONKEYPATCH_FLAGS_UNNEST\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)', - CONTEXT.current_line).group(1) + r"SIP_MONKEYPATCH_FLAGS_UNNEST\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)", + CONTEXT.current_line, + ).group(1) emkf = re.search( - r'SIP_MONKEYPATCH_FLAGS_UNNEST\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)', - CONTEXT.current_line).group(2) + r"SIP_MONKEYPATCH_FLAGS_UNNEST\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)", + CONTEXT.current_line, + ).group(2) if f"{emkb}.{emkf}" != f"{CONTEXT.actual_class}.{flags_name}": CONTEXT.output_python.append( - f"{emkb}.{emkf} = {CONTEXT.actual_class}.{flags_name}\n") + f"{emkb}.{emkf} = {CONTEXT.actual_class}.{flags_name}\n" + ) CONTEXT.enum_monkey_patched_types.append( - [CONTEXT.actual_class, flags_name, emkb, emkf]) + [CONTEXT.actual_class, flags_name, emkb, emkf] + ) CONTEXT.current_line = re.sub( - r'\s*SIP_MONKEYPATCH_FLAGS_UNNEST\(.*?\)', '', - CONTEXT.current_line) + r"\s*SIP_MONKEYPATCH_FLAGS_UNNEST\(.*?\)", "", CONTEXT.current_line + ) enum_match = re.match( - r'^(\s*enum(\s+Q_DECL_DEPRECATED)?\s+(?Pclass\s+)?(?P\w+))(:?\s+SIP_[^:]*)?(\s*:\s*(?P\w+))?(?:\s*SIP_ENUM_BASETYPE\s*\(\s*(?P\w+)\s*\))?(?P.*)$', - CONTEXT.current_line) + r"^(\s*enum(\s+Q_DECL_DEPRECATED)?\s+(?Pclass\s+)?(?P\w+))(:?\s+SIP_[^:]*)?(\s*:\s*(?P\w+))?(?:\s*SIP_ENUM_BASETYPE\s*\(\s*(?P\w+)\s*\))?(?P.*)$", + CONTEXT.current_line, + ) if enum_match: enum_decl = enum_match.group(1) - enum_qualname = enum_match.group('enum_qualname') - enum_type = enum_match.group('enum_type') - isclass = enum_match.group('isclass') - enum_cpp_name = f"{CONTEXT.actual_class}::{enum_qualname}" if CONTEXT.actual_class else enum_qualname + enum_qualname = enum_match.group("enum_qualname") + enum_type = enum_match.group("enum_type") + isclass = enum_match.group("isclass") + enum_cpp_name = ( + f"{CONTEXT.actual_class}::{enum_qualname}" + if CONTEXT.actual_class + else enum_qualname + ) if not isclass and enum_cpp_name not in ALLOWED_NON_CLASS_ENUMS: exit_with_error( - f"Non class enum exposed to Python -- must be a enum class: {enum_cpp_name}") + f"Non class enum exposed to Python -- must be a enum class: {enum_cpp_name}" + ) - oneliner = enum_match.group('oneliner') + oneliner = enum_match.group("oneliner") is_scope_based = bool(isclass) - enum_decl = re.sub(r'\s*\bQ_DECL_DEPRECATED\b', '', enum_decl) + enum_decl = re.sub(r"\s*\bQ_DECL_DEPRECATED\b", "", enum_decl) - py_enum_type_match = re.search(r'SIP_ENUM_BASETYPE\(\s*(.*?)\s*\)', - CONTEXT.current_line) - py_enum_type = py_enum_type_match.group( - 1) if py_enum_type_match else None + py_enum_type_match = re.search( + r"SIP_ENUM_BASETYPE\(\s*(.*?)\s*\)", CONTEXT.current_line + ) + py_enum_type = py_enum_type_match.group(1) if py_enum_type_match else None if py_enum_type == "IntFlag": CONTEXT.enum_intflag_types.append(enum_cpp_name) if enum_type in ["int", "quint32"]: - CONTEXT.enum_int_types.append( - f"{CONTEXT.actual_class}.{enum_qualname}") + CONTEXT.enum_int_types.append(f"{CONTEXT.actual_class}.{enum_qualname}") if CONTEXT.is_qt6: enum_decl += f" /BaseType={py_enum_type or 'IntEnum'}/" elif enum_type: - exit_with_error( - f"Unhandled enum type {enum_type} for {enum_cpp_name}") + exit_with_error(f"Unhandled enum type {enum_type} for {enum_cpp_name}") elif isclass: CONTEXT.enum_class_non_int_types.append( - f"{CONTEXT.actual_class}.{enum_qualname}") + f"{CONTEXT.actual_class}.{enum_qualname}" + ) elif CONTEXT.is_qt6: enum_decl += " /BaseType=IntEnum/" @@ -2006,38 +2107,44 @@ def cpp_to_python_signature(cpp_function: str) -> str: _match = None if is_scope_based: _match = re.search( - r'SIP_MONKEYPATCH_SCOPEENUM(_UNNEST)?(:?\(\s*(?P\w+)\s*,\s*(?P\w+)\s*\))?', - CONTEXT.current_line) + r"SIP_MONKEYPATCH_SCOPEENUM(_UNNEST)?(:?\(\s*(?P\w+)\s*,\s*(?P\w+)\s*\))?", + CONTEXT.current_line, + ) monkeypatch = is_scope_based and _match - enum_mk_base = _match.group('emkb') if _match else '' + enum_mk_base = _match.group("emkb") if _match else "" - enum_old_name = '' - if _match and _match.group('emkf') and monkeypatch: - enum_old_name = _match.group('emkf') + enum_old_name = "" + if _match and _match.group("emkf") and monkeypatch: + enum_old_name = _match.group("emkf") if CONTEXT.actual_class: - if f"{enum_mk_base}.{enum_old_name}" != f"{CONTEXT.actual_class}.{enum_qualname}": + if ( + f"{enum_mk_base}.{enum_old_name}" + != f"{CONTEXT.actual_class}.{enum_qualname}" + ): CONTEXT.output_python.append( - f"{enum_mk_base}.{enum_old_name} = {CONTEXT.actual_class}.{enum_qualname}\n") + f"{enum_mk_base}.{enum_old_name} = {CONTEXT.actual_class}.{enum_qualname}\n" + ) else: CONTEXT.output_python.append( - f"{enum_mk_base}.{enum_old_name} = {enum_qualname}\n") + f"{enum_mk_base}.{enum_old_name} = {enum_qualname}\n" + ) - if re.search(r'\{((\s*\w+)(\s*=\s*[\w\s<|]+.*?)?(,?))+\s*}', - CONTEXT.current_line): - if '=' in CONTEXT.current_line: + if re.search( + r"\{((\s*\w+)(\s*=\s*[\w\s<|]+.*?)?(,?))+\s*}", CONTEXT.current_line + ): + if "=" in CONTEXT.current_line: exit_with_error( - "Sipify does not handle enum one liners with value assignment. Use multiple lines instead. Or just write a new parser.") + "Sipify does not handle enum one liners with value assignment. Use multiple lines instead. Or just write a new parser." + ) continue else: CONTEXT.current_line = read_line() - if not re.match(r'^\s*\{\s*$', CONTEXT.current_line): - exit_with_error( - 'Unexpected content: enum should be followed by {') + if not re.match(r"^\s*\{\s*$", CONTEXT.current_line): + exit_with_error("Unexpected content: enum should be followed by {") write_output("ENU2", f"{CONTEXT.current_line}\n") if is_scope_based: - CONTEXT.output_python.append( - "# monkey patching scoped based enum\n") + CONTEXT.output_python.append("# monkey patching scoped based enum\n") enum_members_doc = [] @@ -2045,117 +2152,150 @@ def cpp_to_python_signature(cpp_function: str) -> str: CONTEXT.current_line = read_line() if detect_comment_block(): continue - if re.search(r'};', CONTEXT.current_line): + if re.search(r"};", CONTEXT.current_line): break - if re.match(r'^\s*\w+\s*\|', - CONTEXT.current_line): # multi line declaration as sum of enums + if re.match( + r"^\s*\w+\s*\|", CONTEXT.current_line + ): # multi line declaration as sum of enums continue enum_match = re.match( - r'^(\s*(?P\w+))(\s+SIP_PYNAME(?:\(\s*(?P[^() ]+)\s*\)\s*)?)?(\s+SIP_MONKEY\w+(?:\(\s*(?P[^() ]+)\s*\)\s*)?)?(?:\s*=\s*(?P(:?[\w\s|+-]|::|<<)+))?(?P,?)(:?\s*//!<\s*(?P.*)|.*)$', - CONTEXT.current_line) - - enum_decl = f"{enum_match.group(1) or ''}{enum_match.group(3) or ''}{enum_match.group('optional_comma') or ''}" if enum_match else CONTEXT.current_line - enum_member = enum_match.group( - 'em') or '' if enum_match else '' - value_comment = enum_match.group( - 'co') or '' if enum_match else '' - compat_name = enum_match.group( - 'compat') or enum_member if enum_match else '' - enum_value = enum_match.group( - 'enum_value') or '' if enum_match else '' - - value_comment = value_comment.replace('::', '.').replace('"', - '\\"') - value_comment = re.sub(r'\\since .*?([\d.]+)', - r'\\n.. versionadded:: \1\\n', - value_comment, flags=re.I) - value_comment = re.sub(r'\\deprecated (?:QGIS )?(.*)', - r'\\n.. deprecated:: \1\\n', - value_comment, flags=re.I) - value_comment = re.sub(r'^\\n+', '', value_comment) - value_comment = re.sub(r'\\n+$', '', value_comment) + r"^(\s*(?P\w+))(\s+SIP_PYNAME(?:\(\s*(?P[^() ]+)\s*\)\s*)?)?(\s+SIP_MONKEY\w+(?:\(\s*(?P[^() ]+)\s*\)\s*)?)?(?:\s*=\s*(?P(:?[\w\s|+-]|::|<<)+))?(?P,?)(:?\s*//!<\s*(?P.*)|.*)$", + CONTEXT.current_line, + ) + + enum_decl = ( + f"{enum_match.group(1) or ''}{enum_match.group(3) or ''}{enum_match.group('optional_comma') or ''}" + if enum_match + else CONTEXT.current_line + ) + enum_member = enum_match.group("em") or "" if enum_match else "" + value_comment = enum_match.group("co") or "" if enum_match else "" + compat_name = ( + enum_match.group("compat") or enum_member if enum_match else "" + ) + enum_value = enum_match.group("enum_value") or "" if enum_match else "" + + value_comment = value_comment.replace("::", ".").replace('"', '\\"') + value_comment = re.sub( + r"\\since .*?([\d.]+)", + r"\\n.. versionadded:: \1\\n", + value_comment, + flags=re.I, + ) + value_comment = re.sub( + r"\\deprecated (?:QGIS )?(.*)", + r"\\n.. deprecated:: \1\\n", + value_comment, + flags=re.I, + ) + value_comment = re.sub(r"^\\n+", "", value_comment) + value_comment = re.sub(r"\\n+$", "", value_comment) dbg_info( - f"is_scope_based:{is_scope_based} enum_mk_base:{enum_mk_base} monkeypatch:{monkeypatch}") + f"is_scope_based:{is_scope_based} enum_mk_base:{enum_mk_base} monkeypatch:{monkeypatch}" + ) if enum_value and ( - re.search(r'.*<<.*', enum_value) or re.search(r'.*0x0.*', - enum_value)): - if f"{CONTEXT.actual_class}::{enum_qualname}" not in CONTEXT.enum_intflag_types: + re.search(r".*<<.*", enum_value) + or re.search(r".*0x0.*", enum_value) + ): + if ( + f"{CONTEXT.actual_class}::{enum_qualname}" + not in CONTEXT.enum_intflag_types + ): exit_with_error( - f"{CONTEXT.actual_class}::{enum_qualname} is a flags type, but was not declared with IntFlag type. Add 'SIP_ENUM_BASETYPE(IntFlag)' to the enum class declaration line") + f"{CONTEXT.actual_class}::{enum_qualname} is a flags type, but was not declared with IntFlag type. Add 'SIP_ENUM_BASETYPE(IntFlag)' to the enum class declaration line" + ) if is_scope_based and enum_member: - value_comment_parts = value_comment.replace('\\n', '\n').split('\n') - value_comment_indented = '' + value_comment_parts = value_comment.replace("\\n", "\n").split("\n") + value_comment_indented = "" for part_idx, part in enumerate(value_comment_parts): if part_idx == 0: - if part.strip().startswith('..'): - exit_with_error(f'Enum member description missing for {CONTEXT.actual_class}::{enum_qualname}') + if part.strip().startswith(".."): + exit_with_error( + f"Enum member description missing for {CONTEXT.actual_class}::{enum_qualname}" + ) value_comment_indented += part.rstrip() else: if part.startswith(".."): value_comment_indented += "\n" - value_comment_indented += ' ' + part.rstrip() + value_comment_indented += " " + part.rstrip() if part.startswith(".."): value_comment_indented += "\n" if part_idx < len(value_comment_parts) - 1: - value_comment_indented += '\n' + value_comment_indented += "\n" - complete_class_path = '.'.join(CONTEXT.classname) + complete_class_path = ".".join(CONTEXT.classname) if monkeypatch and enum_mk_base: if compat_name != enum_member: - value_comment_indented += f'\n\n Available as ``{enum_mk_base}.{compat_name}`` in older QGIS releases.\n' + value_comment_indented += f"\n\n Available as ``{enum_mk_base}.{compat_name}`` in older QGIS releases.\n" if CONTEXT.actual_class: CONTEXT.output_python.append( - f"{enum_mk_base}.{compat_name} = {complete_class_path}.{enum_qualname}.{enum_member}\n") + f"{enum_mk_base}.{compat_name} = {complete_class_path}.{enum_qualname}.{enum_member}\n" + ) if enum_old_name and compat_name != enum_member: CONTEXT.output_python.append( - f"{enum_mk_base}.{enum_old_name}.{compat_name} = {complete_class_path}.{enum_qualname}.{enum_member}\n") + f"{enum_mk_base}.{enum_old_name}.{compat_name} = {complete_class_path}.{enum_qualname}.{enum_member}\n" + ) CONTEXT.output_python.append( - f"{enum_mk_base}.{compat_name}.is_monkey_patched = True\n") + f"{enum_mk_base}.{compat_name}.is_monkey_patched = True\n" + ) CONTEXT.output_python.append( - f"{enum_mk_base}.{compat_name}.__doc__ = \"{value_comment}\"\n") + f'{enum_mk_base}.{compat_name}.__doc__ = "{value_comment}"\n' + ) enum_members_doc.append( - f"* ``{enum_member}``: {value_comment_indented}") + f"* ``{enum_member}``: {value_comment_indented}" + ) else: CONTEXT.output_python.append( - f"{enum_mk_base}.{compat_name} = {enum_qualname}.{enum_member}\n") + f"{enum_mk_base}.{compat_name} = {enum_qualname}.{enum_member}\n" + ) CONTEXT.output_python.append( - f"{enum_mk_base}.{compat_name}.is_monkey_patched = True\n") + f"{enum_mk_base}.{compat_name}.is_monkey_patched = True\n" + ) CONTEXT.output_python.append( - f"{enum_mk_base}.{compat_name}.__doc__ = \"{value_comment}\"\n") + f'{enum_mk_base}.{compat_name}.__doc__ = "{value_comment}"\n' + ) enum_members_doc.append( - f"* ``{enum_member}``: {value_comment_indented}") + f"* ``{enum_member}``: {value_comment_indented}" + ) else: if compat_name != enum_member: - value_comment_indented += f'\n\n Available as ``{CONTEXT.actual_class}.{compat_name}`` in older QGIS releases.\n' + value_comment_indented += f"\n\n Available as ``{CONTEXT.actual_class}.{compat_name}`` in older QGIS releases.\n" if monkeypatch: CONTEXT.output_python.append( - f"{complete_class_path}.{compat_name} = {complete_class_path}.{enum_qualname}.{enum_member}\n") + f"{complete_class_path}.{compat_name} = {complete_class_path}.{enum_qualname}.{enum_member}\n" + ) CONTEXT.output_python.append( - f"{complete_class_path}.{compat_name}.is_monkey_patched = True\n") + f"{complete_class_path}.{compat_name}.is_monkey_patched = True\n" + ) if CONTEXT.actual_class: CONTEXT.output_python.append( - f"{complete_class_path}.{enum_qualname}.{compat_name}.__doc__ = \"{value_comment}\"\n") + f'{complete_class_path}.{enum_qualname}.{compat_name}.__doc__ = "{value_comment}"\n' + ) enum_members_doc.append( - f"* ``{enum_member}``: {value_comment_indented}") + f"* ``{enum_member}``: {value_comment_indented}" + ) else: CONTEXT.output_python.append( - f"{enum_qualname}.{compat_name}.__doc__ = \"{value_comment}\"\n") + f'{enum_qualname}.{compat_name}.__doc__ = "{value_comment}"\n' + ) enum_members_doc.append( - f"* ``{enum_member}``: {value_comment_indented}") + f"* ``{enum_member}``: {value_comment_indented}" + ) if not is_scope_based and CONTEXT.is_qt6 and enum_member: - basename = '.'.join(CONTEXT.class_and_struct) + basename = ".".join(CONTEXT.class_and_struct) if basename: - enum_member = 'None_' if enum_member == 'None' else enum_member + enum_member = "None_" if enum_member == "None" else enum_member CONTEXT.output_python.append( - f"{basename}.{enum_member} = {basename}.{enum_qualname}.{enum_member}\n") + f"{basename}.{enum_member} = {basename}.{enum_qualname}.{enum_member}\n" + ) enum_decl = fix_annotations(enum_decl) write_output("ENU3", f"{enum_decl}\n") @@ -2168,98 +2308,103 @@ def cpp_to_python_signature(cpp_function: str) -> str: enum_member_doc_string = "\n".join(enum_members_doc) if CONTEXT.actual_class: CONTEXT.output_python.append( - f'{".".join(CONTEXT.classname)}.{enum_qualname}.__doc__ = """{CONTEXT.comment}\n\n{enum_member_doc_string}\n\n"""\n# --\n') + f'{".".join(CONTEXT.classname)}.{enum_qualname}.__doc__ = """{CONTEXT.comment}\n\n{enum_member_doc_string}\n\n"""\n# --\n' + ) else: CONTEXT.output_python.append( - f'{enum_qualname}.__doc__ = """{CONTEXT.comment}\n\n{enum_member_doc_string}\n\n"""\n# --\n') + f'{enum_qualname}.__doc__ = """{CONTEXT.comment}\n\n{enum_member_doc_string}\n\n"""\n# --\n' + ) # enums don't have Docstring apparently - CONTEXT.comment = '' + CONTEXT.comment = "" continue # Check for invalid use of doxygen command - if re.search(r'.*//!<', CONTEXT.current_line): + if re.search(r".*//!<", CONTEXT.current_line): exit_with_error( - '"\\!<" doxygen command must only be used for enum documentation') + '"\\!<" doxygen command must only be used for enum documentation' + ) # Handle override, final, and make private keywords - if re.search(r'\boverride\b', CONTEXT.current_line): + if re.search(r"\boverride\b", CONTEXT.current_line): CONTEXT.is_override_or_make_private = PrependType.Virtual - if re.search(r'\bFINAL\b', CONTEXT.current_line): + if re.search(r"\bFINAL\b", CONTEXT.current_line): CONTEXT.is_override_or_make_private = PrependType.Virtual - if re.search(r'\bSIP_MAKE_PRIVATE\b', CONTEXT.current_line): + if re.search(r"\bSIP_MAKE_PRIVATE\b", CONTEXT.current_line): CONTEXT.is_override_or_make_private = PrependType.MakePrivate # Remove Q_INVOKABLE - CONTEXT.current_line = re.sub(r'^(\s*)Q_INVOKABLE ', r'\1', - CONTEXT.current_line) + CONTEXT.current_line = re.sub(r"^(\s*)Q_INVOKABLE ", r"\1", CONTEXT.current_line) # Keyword fixes CONTEXT.current_line = re.sub( - r'^(\s*template\s*<)(?:class|typename) (\w+>)(.*)$', - r'\1\2\3', CONTEXT.current_line) + r"^(\s*template\s*<)(?:class|typename) (\w+>)(.*)$", + r"\1\2\3", + CONTEXT.current_line, + ) + CONTEXT.current_line = re.sub( + r"^(\s*template\s*<)(?:class|typename) (\w+) *, *(?:class|typename) (\w+>)(.*)$", + r"\1\2,\3\4", + CONTEXT.current_line, + ) CONTEXT.current_line = re.sub( - r'^(\s*template\s*<)(?:class|typename) (\w+) *, *(?:class|typename) (\w+>)(.*)$', - r'\1\2,\3\4', - CONTEXT.current_line) + r"^(\s*template\s*<)(?:class|typename) (\w+) *, *(?:class|typename) (\w+) *, *(?:class|typename) (\w+>)(.*)$", + r"\1\2,\3,\4\5", + CONTEXT.current_line, + ) + CONTEXT.current_line = re.sub(r"\s*\boverride\b", "", CONTEXT.current_line) + CONTEXT.current_line = re.sub(r"\s*\bSIP_MAKE_PRIVATE\b", "", CONTEXT.current_line) CONTEXT.current_line = re.sub( - r'^(\s*template\s*<)(?:class|typename) (\w+) *, *(?:class|typename) (\w+) *, *(?:class|typename) (\w+>)(.*)$', - r'\1\2,\3,\4\5', CONTEXT.current_line) - CONTEXT.current_line = re.sub(r'\s*\boverride\b', '', CONTEXT.current_line) - CONTEXT.current_line = re.sub(r'\s*\bSIP_MAKE_PRIVATE\b', '', - CONTEXT.current_line) - CONTEXT.current_line = re.sub(r'\s*\bFINAL\b', ' ${SIP_FINAL}', - CONTEXT.current_line) - CONTEXT.current_line = re.sub(r'\s*\bextern \b', '', CONTEXT.current_line) - CONTEXT.current_line = re.sub(r'\s*\bMAYBE_UNUSED \b', '', - CONTEXT.current_line) - CONTEXT.current_line = re.sub(r'\s*\bNODISCARD \b', '', - CONTEXT.current_line) - CONTEXT.current_line = re.sub(r'\s*\bQ_DECL_DEPRECATED\b', '', - CONTEXT.current_line) - CONTEXT.current_line = re.sub(r'^(\s*)?(const |virtual |static )*inline ', - r'\1\2', CONTEXT.current_line) - CONTEXT.current_line = re.sub(r'\bconstexpr\b', 'const', - CONTEXT.current_line) - CONTEXT.current_line = re.sub(r'\bnullptr\b', '0', CONTEXT.current_line) - CONTEXT.current_line = re.sub(r'\s*=\s*default\b', '', - CONTEXT.current_line) + r"\s*\bFINAL\b", " ${SIP_FINAL}", CONTEXT.current_line + ) + CONTEXT.current_line = re.sub(r"\s*\bextern \b", "", CONTEXT.current_line) + CONTEXT.current_line = re.sub(r"\s*\bMAYBE_UNUSED \b", "", CONTEXT.current_line) + CONTEXT.current_line = re.sub(r"\s*\bNODISCARD \b", "", CONTEXT.current_line) + CONTEXT.current_line = re.sub(r"\s*\bQ_DECL_DEPRECATED\b", "", CONTEXT.current_line) + CONTEXT.current_line = re.sub( + r"^(\s*)?(const |virtual |static )*inline ", r"\1\2", CONTEXT.current_line + ) + CONTEXT.current_line = re.sub(r"\bconstexpr\b", "const", CONTEXT.current_line) + CONTEXT.current_line = re.sub(r"\bnullptr\b", "0", CONTEXT.current_line) + CONTEXT.current_line = re.sub(r"\s*=\s*default\b", "", CONTEXT.current_line) # Handle export macros - if re.search(r'\b\w+_EXPORT\b', CONTEXT.current_line): + if re.search(r"\b\w+_EXPORT\b", CONTEXT.current_line): CONTEXT.exported[-1] += 1 - CONTEXT.current_line = re.sub(r'\b\w+_EXPORT\s+', '', - CONTEXT.current_line) + CONTEXT.current_line = re.sub(r"\b\w+_EXPORT\s+", "", CONTEXT.current_line) # Skip non-method member declaration in non-public sections - if not CONTEXT.sip_run and CONTEXT.access[ - -1] != Visibility.Public and detect_non_method_member( - CONTEXT.current_line): + if ( + not CONTEXT.sip_run + and CONTEXT.access[-1] != Visibility.Public + and detect_non_method_member(CONTEXT.current_line) + ): dbg_info("skip non-method member declaration in non-public sections") continue # Remove static const value assignment # https://regex101.com/r/DyWkgn/6 - if re.search(r'^\s*const static \w+', CONTEXT.current_line): + if re.search(r"^\s*const static \w+", CONTEXT.current_line): exit_with_error( - f"const static should be written static const in {CONTEXT.classname[-1]}") + f"const static should be written static const in {CONTEXT.classname[-1]}" + ) # TODO needs fixing!! # original perl regex was: # ^(? *(?static )?const (\w+::)*\w+(?:<(?:[\w<>, ]|::)+>)? \w+)(?: = [^()]+?(\((?:[^()]++|(?3))*\))?[^()]*?)?(?[|;]) *(\/\/.*?)?$ match = re.search( - r'^(?P *(?Pstatic )?const (\w+::)*\w+(?:<(?:[\w<>, ]|::)+>)? \w+)(?: = [^()]+?(\((?:[^()]|\([^()]*\))*\))?[^()]*?)?(?P[|;]) *(//.*)?$', - CONTEXT.current_line + r"^(?P *(?Pstatic )?const (\w+::)*\w+(?:<(?:[\w<>, ]|::)+>)? \w+)(?: = [^()]+?(\((?:[^()]|\([^()]*\))*\))?[^()]*?)?(?P[|;]) *(//.*)?$", + CONTEXT.current_line, ) if match: CONTEXT.current_line = f"{match.group('staticconst')};" - if match.group('static') is None: - CONTEXT.comment = '' + if match.group("static") is None: + CONTEXT.comment = "" - if match.group('endingchar') == '|': + if match.group("endingchar") == "|": dbg_info("multiline const static assignment") - skip = '' - while not re.search(r';\s*(//.*?)?$', skip): + skip = "" + while not re.search(r";\s*(//.*?)?$", skip): skip = read_line() # Remove struct member assignment @@ -2268,7 +2413,7 @@ def cpp_to_python_signature(cpp_function: str) -> str: # original perl regex: ^(\s*\w+[\w<> *&:,]* \*?\w+) = ([\-\w\:\.]+(< *\w+( \*)? *>)?)+(\([^()]*\))?\s*; # dbg_info(f"attempt struct member assignment '{CONTEXT.current_line}'") - python_regex_verbose = r''' + python_regex_verbose = r""" ^ # Start of the line ( # Start of capturing group for the left-hand side \s* # Optional leading whitespace @@ -2309,58 +2454,69 @@ def cpp_to_python_signature(cpp_function: str) -> str: \s* # Optional whitespace after semicolon (?:\/\/.*)? # Optional single-line comment $ # End of the line - ''' - regex_verbose = re.compile(python_regex_verbose, - re.VERBOSE | re.MULTILINE) + """ + regex_verbose = re.compile(python_regex_verbose, re.VERBOSE | re.MULTILINE) match = regex_verbose.match(CONTEXT.current_line) if match: dbg_info(f"remove struct member assignment '={match.group(2)}'") CONTEXT.current_line = f"{match.group(1)};" # Catch Q_DECLARE_FLAGS - match = re.search(r'^(\s*)Q_DECLARE_FLAGS\(\s*(.*?)\s*,\s*(.*?)\s*\)\s*$', - CONTEXT.current_line) + match = re.search( + r"^(\s*)Q_DECLARE_FLAGS\(\s*(.*?)\s*,\s*(.*?)\s*\)\s*$", CONTEXT.current_line + ) if match: - CONTEXT.actual_class = f"{CONTEXT.classname[-1]}::" if len( - CONTEXT.classname) >= 0 else '' + CONTEXT.actual_class = ( + f"{CONTEXT.classname[-1]}::" if len(CONTEXT.classname) >= 0 else "" + ) dbg_info(f"Declare flags: {CONTEXT.actual_class}") CONTEXT.current_line = f"{match.group(1)}typedef QFlags<{CONTEXT.actual_class}{match.group(3)}> {match.group(2)};\n" - CONTEXT.qflag_hash[ - f"{CONTEXT.actual_class}{match.group(2)}"] = f"{CONTEXT.actual_class}{match.group(3)}" + CONTEXT.qflag_hash[f"{CONTEXT.actual_class}{match.group(2)}"] = ( + f"{CONTEXT.actual_class}{match.group(3)}" + ) if f"{CONTEXT.actual_class}{match.group(3)}" not in CONTEXT.enum_intflag_types: exit_with_error( - f"{CONTEXT.actual_class}{match.group(3)} is a flags type, but was not declared with IntFlag type. Add 'SIP_ENUM_BASETYPE(IntFlag)' to the enum class declaration line") + f"{CONTEXT.actual_class}{match.group(3)} is a flags type, but was not declared with IntFlag type. Add 'SIP_ENUM_BASETYPE(IntFlag)' to the enum class declaration line" + ) # Catch Q_DECLARE_OPERATORS_FOR_FLAGS match = re.search( - r'^(\s*)Q_DECLARE_OPERATORS_FOR_FLAGS\(\s*(.*?)\s*\)\s*$', - CONTEXT.current_line) + r"^(\s*)Q_DECLARE_OPERATORS_FOR_FLAGS\(\s*(.*?)\s*\)\s*$", CONTEXT.current_line + ) if match: flags = match.group(2) flag = CONTEXT.qflag_hash.get(flags) - CONTEXT.current_line = f"{match.group(1)}QFlags<{flag}> operator|({flag} f1, QFlags<{flag}> f2);\n" + CONTEXT.current_line = ( + f"{match.group(1)}QFlags<{flag}> operator|({flag} f1, QFlags<{flag}> f2);\n" + ) py_flag = flag.replace("::", ".") if py_flag in CONTEXT.enum_class_non_int_types: exit_with_error( - f"{flag} is a flags type, but was not declared with int type. Add ': int' to the enum class declaration line") + f"{flag} is a flags type, but was not declared with int type. Add ': int' to the enum class declaration line" + ) elif py_flag not in CONTEXT.enum_int_types: if CONTEXT.is_qt6: dbg_info("monkey patching operators for non-class enum") if not CONTEXT.has_pushed_force_int: CONTEXT.output_python.append( - "from enum import Enum\n\n\ndef _force_int(v): return int(v.value) if isinstance(v, Enum) else v\n\n\n") + "from enum import Enum\n\n\ndef _force_int(v): return int(v.value) if isinstance(v, Enum) else v\n\n\n" + ) CONTEXT.has_pushed_force_int = True CONTEXT.output_python.append( - f"{py_flag}.__bool__ = lambda flag: bool(_force_int(flag))\n") + f"{py_flag}.__bool__ = lambda flag: bool(_force_int(flag))\n" + ) CONTEXT.output_python.append( - f"{py_flag}.__eq__ = lambda flag1, flag2: _force_int(flag1) == _force_int(flag2)\n") + f"{py_flag}.__eq__ = lambda flag1, flag2: _force_int(flag1) == _force_int(flag2)\n" + ) CONTEXT.output_python.append( - f"{py_flag}.__and__ = lambda flag1, flag2: _force_int(flag1) & _force_int(flag2)\n") + f"{py_flag}.__and__ = lambda flag1, flag2: _force_int(flag1) & _force_int(flag2)\n" + ) CONTEXT.output_python.append( - f"{py_flag}.__or__ = lambda flag1, flag2: {py_flag}(_force_int(flag1) | _force_int(flag2))\n") + f"{py_flag}.__or__ = lambda flag1, flag2: {py_flag}(_force_int(flag1) | _force_int(flag2))\n" + ) if not CONTEXT.is_qt6: for patched_type in CONTEXT.enum_monkey_patched_types: @@ -2368,10 +2524,12 @@ def cpp_to_python_signature(cpp_function: str) -> str: dbg_info("monkey patching flags") if not CONTEXT.has_pushed_force_int: CONTEXT.output_python.append( - "from enum import Enum\n\n\ndef _force_int(v): return int(v.value) if isinstance(v, Enum) else v\n\n\n") + "from enum import Enum\n\n\ndef _force_int(v): return int(v.value) if isinstance(v, Enum) else v\n\n\n" + ) CONTEXT.has_pushed_force_int = True CONTEXT.output_python.append( - f"{py_flag}.__or__ = lambda flag1, flag2: {patched_type[0]}.{patched_type[1]}(_force_int(flag1) | _force_int(flag2))\n") + f"{py_flag}.__or__ = lambda flag1, flag2: {patched_type[0]}.{patched_type[1]}(_force_int(flag1) | _force_int(flag2))\n" + ) # Remove keywords if CONTEXT.is_override_or_make_private != PrependType.NoPrepend: @@ -2380,180 +2538,233 @@ def cpp_to_python_signature(cpp_function: str) -> str: rolling_line = CONTEXT.current_line rolling_line_idx = CONTEXT.line_idx dbg_info( - "handle multiline definition to add virtual keyword or making private on opening line") - while not re.match(r'^[^()]*\(([^()]*\([^()]*\)[^()]*)*[^()]*$', - rolling_line): + "handle multiline definition to add virtual keyword or making private on opening line" + ) + while not re.match( + r"^[^()]*\(([^()]*\([^()]*\)[^()]*)*[^()]*$", rolling_line + ): rolling_line_idx -= 1 rolling_line = CONTEXT.input_lines[rolling_line_idx] if rolling_line_idx < 0: - exit_with_error('could not reach opening definition') - dbg_info(f'rolled back to {rolling_line_idx}: {rolling_line}') + exit_with_error("could not reach opening definition") + dbg_info(f"rolled back to {rolling_line_idx}: {rolling_line}") - if CONTEXT.is_override_or_make_private == PrependType.Virtual and not re.match( - r'^(\s*)virtual\b(.*)$', - rolling_line): + if ( + CONTEXT.is_override_or_make_private == PrependType.Virtual + and not re.match(r"^(\s*)virtual\b(.*)$", rolling_line) + ): idx = rolling_line_idx - CONTEXT.line_idx + 1 CONTEXT.output[idx] = fix_annotations( - re.sub(r'^(\s*?)\b(.*)$', r'\1 virtual \2\n', - rolling_line)) + re.sub(r"^(\s*?)\b(.*)$", r"\1 virtual \2\n", rolling_line) + ) elif CONTEXT.is_override_or_make_private == PrependType.MakePrivate: dbg_info("prepending private access") idx = rolling_line_idx - CONTEXT.line_idx - private_access = re.sub(r'(protected|public)', 'private', - CONTEXT.last_access_section_line) + private_access = re.sub( + r"(protected|public)", "private", CONTEXT.last_access_section_line + ) CONTEXT.output.insert(idx + 1, private_access + "\n") CONTEXT.output[idx + 1] = fix_annotations(rolling_line) + "\n" elif CONTEXT.is_override_or_make_private == PrependType.MakePrivate: dbg_info("prepending private access") - CONTEXT.current_line = re.sub(r'(protected|public)', 'private', - CONTEXT.last_access_section_line) + "\n" + CONTEXT.current_line + "\n" - elif CONTEXT.is_override_or_make_private == PrependType.Virtual and not re.match( - r'^(\s*)virtual\b(.*)$', CONTEXT.current_line): + CONTEXT.current_line = ( + re.sub( + r"(protected|public)", "private", CONTEXT.last_access_section_line + ) + + "\n" + + CONTEXT.current_line + + "\n" + ) + elif ( + CONTEXT.is_override_or_make_private == PrependType.Virtual + and not re.match(r"^(\s*)virtual\b(.*)$", CONTEXT.current_line) + ): # SIP often requires the virtual keyword to be present, or it chokes on covariant return types # in overridden methods - dbg_info('adding virtual keyword for overridden method') - CONTEXT.current_line = re.sub(r'^(\s*?)\b(.*)$', r'\1virtual \2\n', - CONTEXT.current_line) + dbg_info("adding virtual keyword for overridden method") + CONTEXT.current_line = re.sub( + r"^(\s*?)\b(.*)$", r"\1virtual \2\n", CONTEXT.current_line + ) # remove constructor definition, function bodies, member initializing list CONTEXT.python_signature = detect_and_remove_following_body_or_initializerlist() # remove inline declarations match = re.search( - r'^(\s*)?(static |const )*(([(?:long )\w]+(<.*?>)?\s+([*&])?)?(\w+)( const*?)*)\s*(\{.*});(\s*//.*)?$', - CONTEXT.current_line) + r"^(\s*)?(static |const )*(([(?:long )\w]+(<.*?>)?\s+([*&])?)?(\w+)( const*?)*)\s*(\{.*});(\s*//.*)?$", + CONTEXT.current_line, + ) if match: CONTEXT.current_line = f"{match.group(1)}{match.group(3)};" - pattern = r'^\s*((?:const |virtual |static |inline ))*(?!explicit)([(?:long )\w:]+(?:<.*?>)?)\s+(?:\*|&)?(\w+|operator.{1,2})(\(.*)$' + pattern = r"^\s*((?:const |virtual |static |inline ))*(?!explicit)([(?:long )\w:]+(?:<.*?>)?)\s+(?:\*|&)?(\w+|operator.{1,2})(\(.*)$" match = re.match(pattern, CONTEXT.current_line) if match: CONTEXT.current_method_name = match.group(3) return_type_candidate = match.group(2) - is_static = bool(match.group(1) and 'static' in match.group(1)) + is_static = bool(match.group(1) and "static" in match.group(1)) class_name = CONTEXT.current_fully_qualified_class_name() if CONTEXT.current_method_name in CONTEXT.static_methods[class_name]: - if CONTEXT.static_methods[class_name][CONTEXT.current_method_name] != is_static: - CONTEXT.static_methods[class_name][ - CONTEXT.current_method_name] = False + if ( + CONTEXT.static_methods[class_name][CONTEXT.current_method_name] + != is_static + ): + CONTEXT.static_methods[class_name][CONTEXT.current_method_name] = False else: CONTEXT.static_methods[class_name][CONTEXT.current_method_name] = is_static if CONTEXT.access[-1] == Visibility.Signals: CONTEXT.current_signal_args = [] signal_args = match.group(4).strip() - if signal_args.startswith('('): + if signal_args.startswith("("): signal_args = signal_args[1:] - if signal_args.endswith(');'): + if signal_args.endswith(");"): signal_args = signal_args[:-2] if signal_args.strip(): CONTEXT.current_signal_args = split_args(signal_args) - dbg_info('SIGARG ' + CONTEXT.current_method_name + " " + str(CONTEXT.current_signal_args)) - if ');' in match.group(4): - CONTEXT.signal_arguments[class_name][ - CONTEXT.current_method_name] = CONTEXT.current_signal_args[:] - dbg_info('SIGARG finalizing' + CONTEXT.current_method_name + " " + str(CONTEXT.current_signal_args)) - - if not re.search(r'(void|SIP_PYOBJECT|operator|return|QFlag)', - return_type_candidate): + dbg_info( + "SIGARG " + + CONTEXT.current_method_name + + " " + + str(CONTEXT.current_signal_args) + ) + if ");" in match.group(4): + CONTEXT.signal_arguments[class_name][CONTEXT.current_method_name] = ( + CONTEXT.current_signal_args[:] + ) + dbg_info( + "SIGARG finalizing" + + CONTEXT.current_method_name + + " " + + str(CONTEXT.current_signal_args) + ) + + if not re.search( + r"(void|SIP_PYOBJECT|operator|return|QFlag)", return_type_candidate + ): # replace :: with . (changes c++ style namespace/class directives to Python style) - CONTEXT.return_type = return_type_candidate.replace('::', '.') + CONTEXT.return_type = return_type_candidate.replace("::", ".") # replace with builtin Python types - CONTEXT.return_type = re.sub(r'\bdouble\b', 'float', - CONTEXT.return_type) - CONTEXT.return_type = re.sub(r'\bQString\b', 'str', - CONTEXT.return_type) - CONTEXT.return_type = re.sub(r'\bQStringList\b', 'list of str', - CONTEXT.return_type) - - list_match = re.match(r'^(?:QList|QVector)<\s*(.*?)[\s*]*>$', - CONTEXT.return_type) + CONTEXT.return_type = re.sub(r"\bdouble\b", "float", CONTEXT.return_type) + CONTEXT.return_type = re.sub(r"\bQString\b", "str", CONTEXT.return_type) + CONTEXT.return_type = re.sub( + r"\bQStringList\b", "list of str", CONTEXT.return_type + ) + + list_match = re.match( + r"^(?:QList|QVector)<\s*(.*?)[\s*]*>$", CONTEXT.return_type + ) if list_match: CONTEXT.return_type = f"list of {list_match.group(1)}" - set_match = re.match(r'^QSet<\s*(.*?)[\s*]*>$', - CONTEXT.return_type) + set_match = re.match(r"^QSet<\s*(.*?)[\s*]*>$", CONTEXT.return_type) if set_match: CONTEXT.return_type = f"set of {set_match.group(1)}" - elif CONTEXT.access[-1] == Visibility.Signals and CONTEXT.current_line.strip() not in ('', 'signals:'): - dbg_info('SIGARG4 ' + CONTEXT.current_method_name + " " + CONTEXT.current_line) + elif CONTEXT.access[ + -1 + ] == Visibility.Signals and CONTEXT.current_line.strip() not in ("", "signals:"): + dbg_info("SIGARG4 " + CONTEXT.current_method_name + " " + CONTEXT.current_line) signal_args = CONTEXT.current_line.strip() - if signal_args.endswith(');'): + if signal_args.endswith(");"): signal_args = signal_args[:-2] if signal_args.strip(): CONTEXT.current_signal_args.extend(split_args(signal_args)) - dbg_info('SIGARG5 ' + CONTEXT.current_method_name + " " + str(CONTEXT.current_signal_args)) - if ');' in CONTEXT.current_line: + dbg_info( + "SIGARG5 " + + CONTEXT.current_method_name + + " " + + str(CONTEXT.current_signal_args) + ) + if ");" in CONTEXT.current_line: class_name = CONTEXT.current_fully_qualified_class_name() - CONTEXT.signal_arguments[class_name][ - CONTEXT.current_method_name] = CONTEXT.current_signal_args[:] - dbg_info('SIGARG finalizing' + CONTEXT.current_method_name + " " + str(CONTEXT.current_signal_args)) + CONTEXT.signal_arguments[class_name][CONTEXT.current_method_name] = ( + CONTEXT.current_signal_args[:] + ) + dbg_info( + "SIGARG finalizing" + + CONTEXT.current_method_name + + " " + + str(CONTEXT.current_signal_args) + ) # deleted functions if re.match( - r'^(\s*)?(const )?(virtual |static )?((\w+(<.*?>)?\s+([*&])?)?(\w+|operator.{1,2})\(.*?(\(.*\))*.*\)( const)?)\s*= delete;(\s*//.*)?$', - CONTEXT.current_line): - CONTEXT.comment = '' + r"^(\s*)?(const )?(virtual |static )?((\w+(<.*?>)?\s+([*&])?)?(\w+|operator.{1,2})\(.*?(\(.*\))*.*\)( const)?)\s*= delete;(\s*//.*)?$", + CONTEXT.current_line, + ): + CONTEXT.comment = "" continue # remove export macro from struct definition - CONTEXT.current_line = re.sub(r'^(\s*struct )\w+_EXPORT (.+)$', r'\1\2', - CONTEXT.current_line) + CONTEXT.current_line = re.sub( + r"^(\s*struct )\w+_EXPORT (.+)$", r"\1\2", CONTEXT.current_line + ) # Skip comments - if re.match(r'^\s*typedef\s+\w+\s*<\s*\w+\s*>\s+\w+\s+.*SIP_DOC_TEMPLATE', - CONTEXT.current_line): + if re.match( + r"^\s*typedef\s+\w+\s*<\s*\w+\s*>\s+\w+\s+.*SIP_DOC_TEMPLATE", + CONTEXT.current_line, + ): # support Docstring for template based classes in SIP 4.19.7+ CONTEXT.comment_template_docstring = True - elif (CONTEXT.multiline_definition == MultiLineType.NotMultiline and - (re.search(r'//', CONTEXT.current_line) or - re.match(r'^\s*typedef ', CONTEXT.current_line) or - re.search(r'\s*struct ', CONTEXT.current_line) or - re.search(r'operator\[]\(', CONTEXT.current_line) or - re.match(r'^\s*operator\b', CONTEXT.current_line) or - re.search(r'operator\s?[!+-=*/\[\]<>]{1,2}', - CONTEXT.current_line) or - re.match(r'^\s*%\w+(.*)?$', CONTEXT.current_line) or - re.match(r'^\s*namespace\s+\w+', CONTEXT.current_line) or - re.match(r'^\s*(virtual\s*)?~', CONTEXT.current_line) or - detect_non_method_member(CONTEXT.current_line) - )): - dbg_info(f'skipping comment for {CONTEXT.current_line}') - if re.search(r'\s*typedef.*?(?!SIP_DOC_TEMPLATE)', - CONTEXT.current_line): - dbg_info('because typedef') - elif CONTEXT.actual_class and detect_non_method_member( - CONTEXT.current_line) and CONTEXT.comment: - attribute_name_match = re.match(r'^.*?\s[*&]*(\w+);.*$', - CONTEXT.current_line) + elif CONTEXT.multiline_definition == MultiLineType.NotMultiline and ( + re.search(r"//", CONTEXT.current_line) + or re.match(r"^\s*typedef ", CONTEXT.current_line) + or re.search(r"\s*struct ", CONTEXT.current_line) + or re.search(r"operator\[]\(", CONTEXT.current_line) + or re.match(r"^\s*operator\b", CONTEXT.current_line) + or re.search(r"operator\s?[!+-=*/\[\]<>]{1,2}", CONTEXT.current_line) + or re.match(r"^\s*%\w+(.*)?$", CONTEXT.current_line) + or re.match(r"^\s*namespace\s+\w+", CONTEXT.current_line) + or re.match(r"^\s*(virtual\s*)?~", CONTEXT.current_line) + or detect_non_method_member(CONTEXT.current_line) + ): + dbg_info(f"skipping comment for {CONTEXT.current_line}") + if re.search(r"\s*typedef.*?(?!SIP_DOC_TEMPLATE)", CONTEXT.current_line): + dbg_info("because typedef") + elif ( + CONTEXT.actual_class + and detect_non_method_member(CONTEXT.current_line) + and CONTEXT.comment + ): + attribute_name_match = re.match( + r"^.*?\s[*&]*(\w+);.*$", CONTEXT.current_line + ) class_name = CONTEXT.current_fully_qualified_struct_name() dbg_info( - f'storing attribute docstring for {class_name} : {attribute_name_match.group(1)}') + f"storing attribute docstring for {class_name} : {attribute_name_match.group(1)}" + ) CONTEXT.attribute_docstrings[class_name][ - attribute_name_match.group(1)] = CONTEXT.comment - elif CONTEXT.current_fully_qualified_struct_name() and re.search(r'\s*struct ', CONTEXT.current_line) and CONTEXT.comment: + attribute_name_match.group(1) + ] = CONTEXT.comment + elif ( + CONTEXT.current_fully_qualified_struct_name() + and re.search(r"\s*struct ", CONTEXT.current_line) + and CONTEXT.comment + ): class_name = CONTEXT.current_fully_qualified_struct_name() - dbg_info( - f'storing struct docstring for {class_name}') + dbg_info(f"storing struct docstring for {class_name}") CONTEXT.struct_docstrings[class_name] = CONTEXT.comment - CONTEXT.comment = '' - CONTEXT.return_type = '' + CONTEXT.comment = "" + CONTEXT.return_type = "" CONTEXT.is_override_or_make_private = PrependType.NoPrepend CONTEXT.current_line = fix_constants(CONTEXT.current_line) CONTEXT.current_line = fix_annotations(CONTEXT.current_line) # fix astyle placing space after % character - CONTEXT.current_line = re.sub(r'/\s+GetWrapper\s+/', '/GetWrapper/', - CONTEXT.current_line) + CONTEXT.current_line = re.sub( + r"/\s+GetWrapper\s+/", "/GetWrapper/", CONTEXT.current_line + ) # MISSING # handle enum/flags QgsSettingsEntryEnumFlag - match = re.match(r'^(\s*)const QgsSettingsEntryEnumFlag<(.*)> (.+);$', - CONTEXT.current_line) + match = re.match( + r"^(\s*)const QgsSettingsEntryEnumFlag<(.*)> (.+);$", CONTEXT.current_line + ) if match: CONTEXT.indent, enum_type, var_name = match.groups() @@ -2570,8 +2781,10 @@ def cpp_to_python_signature(cpp_function: str) -> str: {enum_type} value( const QString &dynamicKeyPart = QString(), bool useDefaultValueOverride = false, const {enum_type} &defaultValueOverride = {enum_type}() ) const; }};""" - CONTEXT.current_line = f"{CONTEXT.indent}const QgsSettingsEntryEnumFlag_{var_name} {var_name};" - CONTEXT.comment = '' + CONTEXT.current_line = ( + f"{CONTEXT.indent}const QgsSettingsEntryEnumFlag_{var_name} {var_name};" + ) + CONTEXT.comment = "" write_output("ENF", f"{prep_line}\n", "prepend") write_output("NOR", f"{CONTEXT.current_line}\n") @@ -2579,12 +2792,14 @@ def cpp_to_python_signature(cpp_function: str) -> str: # append to class map file if args.class_map and CONTEXT.actual_class: match = re.match( - r'^ *(const |virtual |static )* *[\w:]+ +\*?(?P\w+)\(.*$', - CONTEXT.current_line) + r"^ *(const |virtual |static )* *[\w:]+ +\*?(?P\w+)\(.*$", + CONTEXT.current_line, + ) if match: - with open(args.class_map, 'a') as f: + with open(args.class_map, "a") as f: f.write( - f"{'.'.join(CONTEXT.classname)}.{match.group('method')}: {CONTEXT.header_file}#L{CONTEXT.line_idx}\n") + f"{'.'.join(CONTEXT.classname)}.{match.group('method')}: {CONTEXT.header_file}#L{CONTEXT.line_idx}\n" + ) if CONTEXT.python_signature: write_output("PSI", f"{CONTEXT.python_signature}\n") @@ -2596,13 +2811,15 @@ def cpp_to_python_signature(cpp_function: str) -> str: # TODO - original regex is incompatible with python -- it was: # ^([^()]+(\((?:[^()]++|(?1))*\)))*[^()]*\)([^()](throw\([^()]+\))?)*$: if re.match( - r'^([^()]+(\((?:[^()]|\([^()]*\))*\)))*[^()]*\)([^()](throw\([^()]+\))?)*', - CONTEXT.current_line): + r"^([^()]+(\((?:[^()]|\([^()]*\))*\)))*[^()]*\)([^()](throw\([^()]+\))?)*", + CONTEXT.current_line, + ): dbg_info("ending multiline") # remove potential following body - if CONTEXT.multiline_definition != MultiLineType.ConditionalStatement and not re.search( - r'(\{.*}|;)\s*(//.*)?$', - CONTEXT.current_line): + if ( + CONTEXT.multiline_definition != MultiLineType.ConditionalStatement + and not re.search(r"(\{.*}|;)\s*(//.*)?$", CONTEXT.current_line) + ): dbg_info("remove following body of multiline def") last_line = CONTEXT.current_line last_line += remove_following_body_or_initializerlist() @@ -2612,39 +2829,43 @@ def cpp_to_python_signature(cpp_function: str) -> str: CONTEXT.multiline_definition = MultiLineType.NotMultiline else: continue - elif re.match(r'^[^()]+\([^()]*(?:\([^()]*\)[^()]*)*[^)]*$', - CONTEXT.current_line): + elif re.match(r"^[^()]+\([^()]*(?:\([^()]*\)[^()]*)*[^)]*$", CONTEXT.current_line): dbg_info(f"Multiline detected:: {CONTEXT.current_line}") - if re.match(r'^\s*((else )?if|while|for) *\(', CONTEXT.current_line): + if re.match(r"^\s*((else )?if|while|for) *\(", CONTEXT.current_line): CONTEXT.multiline_definition = MultiLineType.ConditionalStatement else: CONTEXT.multiline_definition = MultiLineType.Method continue # write comment - if re.match(r'^\s*$', CONTEXT.current_line): + if re.match(r"^\s*$", CONTEXT.current_line): dbg_info("no more override / private") CONTEXT.is_override_or_make_private = PrependType.NoPrepend continue - if re.match(r'^\s*template\s*<.*>', CONTEXT.current_line): + if re.match(r"^\s*template\s*<.*>", CONTEXT.current_line): # do not comment now for templates, wait for class definition continue if CONTEXT.comment.strip() or CONTEXT.return_type: - if CONTEXT.is_override_or_make_private != PrependType.Virtual and not CONTEXT.comment.strip(): + if ( + CONTEXT.is_override_or_make_private != PrependType.Virtual + and not CONTEXT.comment.strip() + ): # overridden method with no new docs - so don't create a Docstring and use # parent class Docstring pass else: - dbg_info('writing comment') + dbg_info("writing comment") if CONTEXT.comment.strip(): - dbg_info('comment non-empty') - doc_prepend = "@DOCSTRINGSTEMPLATE@" if CONTEXT.comment_template_docstring else "" + dbg_info("comment non-empty") + doc_prepend = ( + "@DOCSTRINGSTEMPLATE@" if CONTEXT.comment_template_docstring else "" + ) write_output("CM1", f"{doc_prepend}%Docstring\n") - doc_string = '' - comment_lines = CONTEXT.comment.split('\n') + doc_string = "" + comment_lines = CONTEXT.comment.split("\n") skipping_param = 0 out_params = [] waiting_for_return_to_end = False @@ -2654,8 +2875,9 @@ def cpp_to_python_signature(cpp_function: str) -> str: comment_line = comment_lines[comment_line_idx] comment_line_idx += 1 if ( - 'versionadded:' in comment_line or 'deprecated:' in comment_line) and out_params: - dbg_info('out style parameters remain to flush!') + "versionadded:" in comment_line or "deprecated:" in comment_line + ) and out_params: + dbg_info("out style parameters remain to flush!") # member has /Out/ parameters, but no return type, so flush out out_params docs now first_out_param = out_params.pop(0) doc_string += f"{doc_prepend}:return: - {first_out_param}\n" @@ -2666,21 +2888,29 @@ def cpp_to_python_signature(cpp_function: str) -> str: doc_string += f"{doc_prepend}\n" out_params = [] - param_match = re.match(r'^:param\s+(\w+)', comment_line) + param_match = re.match(r"^:param\s+(\w+)", comment_line) if param_match: param_name = param_match.group(1) - dbg_info(f'found parameter: {param_name}') - if param_name in CONTEXT.skipped_params_out or param_name in CONTEXT.skipped_params_remove: + dbg_info(f"found parameter: {param_name}") + if ( + param_name in CONTEXT.skipped_params_out + or param_name in CONTEXT.skipped_params_remove + ): dbg_info(str(CONTEXT.skipped_params_out)) if param_name in CONTEXT.skipped_params_out: - dbg_info(f'deferring docs for parameter {param_name} marked as SIP_OUT') + dbg_info( + f"deferring docs for parameter {param_name} marked as SIP_OUT" + ) comment_line = re.sub( - r'^:param\s+(\w+):\s*(.*?)$', r'\1: \2', - comment_line) + r"^:param\s+(\w+):\s*(.*?)$", + r"\1: \2", + comment_line, + ) comment_line = re.sub( - r'(?:optional|if specified|if given|storage for|will be set to),?\s*', - '', - comment_line) + r"(?:optional|if specified|if given|storage for|will be set to),?\s*", + "", + comment_line, + ) out_params.append(comment_line) skipping_param = 2 else: @@ -2688,19 +2918,18 @@ def cpp_to_python_signature(cpp_function: str) -> str: continue if skipping_param > 0: - if re.match(r'^(:.*|\.\..*|\s*)$', comment_line): + if re.match(r"^(:.*|\.\..*|\s*)$", comment_line): skipping_param = 0 elif skipping_param == 2: - comment_line = re.sub(r'^\s+', ' ', comment_line) + comment_line = re.sub(r"^\s+", " ", comment_line) out_params[-1] += comment_line continue else: continue - if ':return:' in comment_line and out_params: + if ":return:" in comment_line and out_params: waiting_for_return_to_end = True - comment_line = comment_line.replace(':return:', - ':return: -') + comment_line = comment_line.replace(":return:", ":return: -") doc_string += f"{doc_prepend}{comment_line}\n" # scan forward to find end of return description @@ -2709,15 +2938,23 @@ def cpp_to_python_signature(cpp_function: str) -> str: while scan_forward_idx < len(comment_lines): scan_forward_line = comment_lines[scan_forward_idx] scan_forward_idx += 1 - if not scan_forward_line.strip() and scan_forward_idx < len(comment_lines) - 1: + if ( + not scan_forward_line.strip() + and scan_forward_idx < len(comment_lines) - 1 + ): # check if following line is start of list - if re.match(r'^\s*-(?!-)', comment_lines[scan_forward_idx + 1]): + if re.match( + r"^\s*-(?!-)", comment_lines[scan_forward_idx + 1] + ): doc_string += "\n" comment_line_idx += 1 needs_blank_line_after_return = True continue - if re.match(r'^(:.*|\.\..*|\s*)$', scan_forward_line) or not scan_forward_line.strip(): + if ( + re.match(r"^(:.*|\.\..*|\s*)$", scan_forward_line) + or not scan_forward_line.strip() + ): break doc_string += f"{doc_prepend} {scan_forward_line}\n" @@ -2733,7 +2970,7 @@ def cpp_to_python_signature(cpp_function: str) -> str: doc_string += f"{doc_prepend}{comment_line}\n" if waiting_for_return_to_end: - if re.match(r'^(:.*|\.\..*|\s*)$', comment_line): + if re.match(r"^(:.*|\.\..*|\s*)$", comment_line): waiting_for_return_to_end = False else: pass # Return docstring should be single line with SIP_OUT params @@ -2741,7 +2978,8 @@ def cpp_to_python_signature(cpp_function: str) -> str: if out_params: if CONTEXT.return_type: exit_with_error( - f"A method with output parameters must contain a return directive ({CONTEXT.current_method_name} method returns {CONTEXT.return_type})") + f"A method with output parameters must contain a return directive ({CONTEXT.current_method_name} method returns {CONTEXT.return_type})" + ) else: doc_string += "\n" @@ -2750,22 +2988,27 @@ def cpp_to_python_signature(cpp_function: str) -> str: if len(out_params) > 1: doc_string += f":return: - {out_param}\n" else: - arg_name_match = re.match(r'^(.*?):\s*(.*?)$', out_param) - doc_string += f":return: {arg_name_match.group(2)}\n" + arg_name_match = re.match( + r"^(.*?):\s*(.*?)$", out_param + ) + doc_string += ( + f":return: {arg_name_match.group(2)}\n" + ) else: doc_string += f"{doc_prepend} - {out_param}\n" - dbg_info(f'doc_string is {doc_string}') + dbg_info(f"doc_string is {doc_string}") write_output("DS", doc_string) if CONTEXT.access[-1] == Visibility.Signals and doc_string: - dbg_info('storing signal docstring') - class_name = '.'.join(CONTEXT.classname) + dbg_info("storing signal docstring") + class_name = ".".join(CONTEXT.classname) CONTEXT.attribute_docstrings[class_name][ - CONTEXT.current_method_name] = doc_string + CONTEXT.current_method_name + ] = doc_string write_output("CM4", f"{doc_prepend}%End\n") - CONTEXT.comment = '' - CONTEXT.return_type = '' + CONTEXT.comment = "" + CONTEXT.return_type = "" if CONTEXT.is_override_or_make_private == PrependType.MakePrivate: write_output("MKP", CONTEXT.last_access_section_line) CONTEXT.is_override_or_make_private = PrependType.NoPrepend @@ -2776,19 +3019,23 @@ def cpp_to_python_signature(cpp_function: str) -> str: # Output results if args.sip_output: - with open(args.sip_output, 'w') as f: - f.write(''.join(sip_header_footer())) - f.write(''.join(CONTEXT.output)) - f.write(''.join(sip_header_footer())) + with open(args.sip_output, "w") as f: + f.write("".join(sip_header_footer())) + f.write("".join(CONTEXT.output)) + f.write("".join(sip_header_footer())) else: - print(''.join(sip_header_footer()) + - ''.join(CONTEXT.output) + - ''.join(sip_header_footer()).rstrip()) + print( + "".join(sip_header_footer()) + + "".join(CONTEXT.output) + + "".join(sip_header_footer()).rstrip() + ) class_additions = defaultdict(list) for class_name, attribute_docstrings in CONTEXT.attribute_docstrings.items(): - class_additions[class_name].append(f'{class_name}.__attribute_docs__ = {str(attribute_docstrings)}') + class_additions[class_name].append( + f"{class_name}.__attribute_docs__ = {str(attribute_docstrings)}" + ) for class_name, static_methods in CONTEXT.static_methods.items(): for method_name, is_static in static_methods.items(): @@ -2796,19 +3043,32 @@ def cpp_to_python_signature(cpp_function: str) -> str: continue # TODO -- fix - if class_name == 'QgsProcessingUtils' and method_name == 'createFeatureSinkPython': - method_name = 'createFeatureSink' - elif class_name == 'QgsRasterAttributeTable' and method_name == 'usageInformationInt': - method_name = 'usageInformation' - elif class_name == 'QgsSymbolLayerUtils' and method_name == 'wellKnownMarkerFromSld': - method_name = 'wellKnownMarkerFromSld2' - elif class_name == 'QgsZonalStatistics' and method_name in ('calculateStatisticsInt', 'calculateStatistics'): + if ( + class_name == "QgsProcessingUtils" + and method_name == "createFeatureSinkPython" + ): + method_name = "createFeatureSink" + elif ( + class_name == "QgsRasterAttributeTable" + and method_name == "usageInformationInt" + ): + method_name = "usageInformation" + elif ( + class_name == "QgsSymbolLayerUtils" + and method_name == "wellKnownMarkerFromSld" + ): + method_name = "wellKnownMarkerFromSld2" + elif class_name == "QgsZonalStatistics" and method_name in ( + "calculateStatisticsInt", + "calculateStatistics", + ): continue - elif class_name == 'QgsServerApiUtils' and method_name == 'temporalExtentList': - method_name = 'temporalExtent' + elif class_name == "QgsServerApiUtils" and method_name == "temporalExtentList": + method_name = "temporalExtent" class_additions[class_name].append( - f'{class_name}.{method_name} = staticmethod({class_name}.{method_name})') + f"{class_name}.{method_name} = staticmethod({class_name}.{method_name})" + ) for class_name, signal_arguments in CONTEXT.signal_arguments.items(): python_signatures = {} @@ -2826,28 +3086,31 @@ def cpp_to_python_signature(cpp_function: str) -> str: if python_signatures: class_additions[class_name].append( - f'{class_name}.__signal_arguments__ = {str(python_signatures)}') + f"{class_name}.__signal_arguments__ = {str(python_signatures)}" + ) for class_name, doc_string in CONTEXT.struct_docstrings.items(): class_additions[class_name].append(f'{class_name}.__doc__ = """{doc_string}"""') -group_match = re.match('^.*src/[a-z0-9_]+/(.*?)/[^/]+$', CONTEXT.header_file) +group_match = re.match("^.*src/[a-z0-9_]+/(.*?)/[^/]+$", CONTEXT.header_file) if group_match: - groups = list(group for group in group_match.group(1).split('/') if group and group != '.') + groups = list( + group for group in group_match.group(1).split("/") if group and group != "." + ) if groups: for class_name in CONTEXT.all_fully_qualified_class_names: - class_additions[class_name].append( - f'{class_name}.__group__ = {groups}') + class_additions[class_name].append(f"{class_name}.__group__ = {groups}") for _class, additions in class_additions.items(): if additions: this_class_additions = "\n".join(" " + c for c in additions) CONTEXT.output_python.append( - f'try:\n{this_class_additions}\nexcept NameError:\n pass\n') + f"try:\n{this_class_additions}\nexcept NameError:\n pass\n" + ) if args.python_output and CONTEXT.output_python: - with open(args.python_output, 'w') as f: - f.write(''.join(python_header())) - f.write(''.join(CONTEXT.output_python)) + with open(args.python_output, "w") as f: + f.write("".join(python_header())) + f.write("".join(CONTEXT.output_python)) diff --git a/scripts/symbol_xml2db.py b/scripts/symbol_xml2db.py index 1a5591350f22..d876a1ba80ed 100644 --- a/scripts/symbol_xml2db.py +++ b/scripts/symbol_xml2db.py @@ -28,34 +28,31 @@ xmlfile = "../resources/symbology-style.xml" dbfile = "../resources/symbology-style.db" -_symbol = "CREATE TABLE symbol("\ - "id INTEGER PRIMARY KEY,"\ - "name TEXT UNIQUE,"\ - "xml TEXT,"\ - "favorite INTEGER)" - -_colorramp = "CREATE TABLE colorramp("\ - "id INTEGER PRIMARY KEY,"\ - "name TEXT UNIQUE,"\ - "xml TEXT,"\ - "favorite INTEGER)" - -_tag = "CREATE TABLE tag("\ - "id INTEGER PRIMARY KEY,"\ - "name TEXT)" - -_tagmap = "CREATE TABLE tagmap("\ - "tag_id INTEGER NOT NULL,"\ - "symbol_id INTEGER)" - -_ctagmap = "CREATE TABLE ctagmap("\ - "tag_id INTEGER NOT NULL,"\ - "colorramp_id INTEGER)" - -_smartgroup = "CREATE TABLE smartgroup("\ - "id INTEGER PRIMARY KEY,"\ - "name TEXT,"\ - "xml TEXT)" +_symbol = ( + "CREATE TABLE symbol(" + "id INTEGER PRIMARY KEY," + "name TEXT UNIQUE," + "xml TEXT," + "favorite INTEGER)" +) + +_colorramp = ( + "CREATE TABLE colorramp(" + "id INTEGER PRIMARY KEY," + "name TEXT UNIQUE," + "xml TEXT," + "favorite INTEGER)" +) + +_tag = "CREATE TABLE tag(" "id INTEGER PRIMARY KEY," "name TEXT)" + +_tagmap = "CREATE TABLE tagmap(" "tag_id INTEGER NOT NULL," "symbol_id INTEGER)" + +_ctagmap = "CREATE TABLE ctagmap(" "tag_id INTEGER NOT NULL," "colorramp_id INTEGER)" + +_smartgroup = ( + "CREATE TABLE smartgroup(" "id INTEGER PRIMARY KEY," "name TEXT," "xml TEXT)" +) create_tables = [_symbol, _colorramp, _tag, _tagmap, _ctagmap, _smartgroup] @@ -80,16 +77,19 @@ if not symbol_favorite: symbol_favorite = 0 - if '@' in symbol_name: - parts = symbol_name.split('@') + if "@" in symbol_name: + parts = symbol_name.split("@") parent_name = parts[1] layerno = int(parts[2]) c.execute("SELECT xml FROM symbol WHERE name=(?)", (parent_name,)) - symdom = parseString(c.fetchone()[0]).getElementsByTagName('symbol')[0] + symdom = parseString(c.fetchone()[0]).getElementsByTagName("symbol")[0] symdom.getElementsByTagName("layer")[layerno].appendChild(symbol) c.execute("UPDATE symbol SET xml=? WHERE name=?", (symdom.toxml(), parent_name)) else: - c.execute("INSERT INTO symbol VALUES (?,?,?,?)", (None, symbol_name, symbol.toxml(), symbol_favorite)) + c.execute( + "INSERT INTO symbol VALUES (?,?,?,?)", + (None, symbol_name, symbol.toxml(), symbol_favorite), + ) conn.commit() @@ -101,7 +101,10 @@ if not symbol_favorite: symbol_favorite = 0 - c.execute("INSERT INTO colorramp VALUES (?,?,?,?)", (None, ramp_name, ramp.toxml(), symbol_favorite)) + c.execute( + "INSERT INTO colorramp VALUES (?,?,?,?)", + (None, ramp_name, ramp.toxml(), symbol_favorite), + ) conn.commit() # Finally close the sqlite cursor diff --git a/scripts/widgets_tree.py b/scripts/widgets_tree.py index 380d358dbbff..10a2b4efe024 100644 --- a/scripts/widgets_tree.py +++ b/scripts/widgets_tree.py @@ -17,9 +17,9 @@ *************************************************************************** """ -__author__ = 'Martin Dobias' -__date__ = 'May 2011' -__copyright__ = '(C) 2011, Martin Dobias' +__author__ = "Martin Dobias" +__date__ = "May 2011" +__copyright__ = "(C) 2011, Martin Dobias" """ Reads .ui files from ../src/ui/ directory and write to stdout an XML describing @@ -33,17 +33,44 @@ """ -import sys -import os import glob -from qgis.PyQt.QtWidgets import QWidget, QDialog, QCheckBox, QComboBox, QDial, QPushButton, QLabel, QLCDNumber, QLineEdit, QRadioButton, QScrollBar, QSlider, QSpinBox, QTextEdit, QDateEdit, QTimeEdit, QDateTimeEdit, QListView, QProgressBar, QTableView, QTabWidget, QTextBrowser, QDialogButtonBox, QScrollArea, QGroupBox, QStackedWidget -from qgis.PyQt.uic import loadUi -from qgis.PyQt.QtXml import QDomDocument +import os +import sys # qwt_plot is missing somehow but it may depend on installed packages from qgis.PyQt import Qwt5 as qwt_plot +from qgis.PyQt.QtWidgets import ( + QCheckBox, + QComboBox, + QDateEdit, + QDateTimeEdit, + QDial, + QDialog, + QDialogButtonBox, + QGroupBox, + QLabel, + QLCDNumber, + QLineEdit, + QListView, + QProgressBar, + QPushButton, + QRadioButton, + QScrollArea, + QScrollBar, + QSlider, + QSpinBox, + QStackedWidget, + QTableView, + QTabWidget, + QTextBrowser, + QTextEdit, + QTimeEdit, + QWidget, +) +from qgis.PyQt.QtXml import QDomDocument +from qgis.PyQt.uic import loadUi -sys.modules['qwt_plot'] = qwt_plot +sys.modules["qwt_plot"] = qwt_plot # loadUi is looking for custom widget in module which is lowercase version of # the class, which do not exist (AFAIK) -> preload them, problems anyway: @@ -51,21 +78,60 @@ # QgsRendererRulesTreeWidget # and QgsProjectionSelector cannot open db file from qgis import gui -for m in ['qgscolorbutton', 'qgscolorrampcombobox', 'qgsprojectionselector', 'qgslabelpreview', 'qgsrulebasedrendererwidget', 'qgscollapsiblegroupbox', 'qgsblendmodecombobox', 'qgsexpressionbuilderwidget', 'qgsrasterformatsaveoptionswidget', 'qgsrasterpyramidsoptionswidget', 'qgsscalecombobox', 'qgsfilterlineedit', 'qgsdualview']: + +for m in [ + "qgscolorbutton", + "qgscolorrampcombobox", + "qgsprojectionselector", + "qgslabelpreview", + "qgsrulebasedrendererwidget", + "qgscollapsiblegroupbox", + "qgsblendmodecombobox", + "qgsexpressionbuilderwidget", + "qgsrasterformatsaveoptionswidget", + "qgsrasterpyramidsoptionswidget", + "qgsscalecombobox", + "qgsfilterlineedit", + "qgsdualview", +]: sys.modules[m] = gui class UiInspector: def __init__(self): - self.ui_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '../src/ui/*.ui')) + self.ui_dir = os.path.abspath( + os.path.join(os.path.dirname(__file__), "../src/ui/*.ui") + ) self.printMsg("Loading UI files " + self.ui_dir) # list of widget classes we want to follow self.follow = [ - QWidget, QDialog, - QCheckBox, QComboBox, QDial, QPushButton, QLabel, QLCDNumber, QLineEdit, QRadioButton, QScrollBar, QSlider, QSpinBox, QTextEdit, - QDateEdit, QTimeEdit, QDateTimeEdit, QListView, QProgressBar, QTableView, QTabWidget, QTextBrowser, QDialogButtonBox, - QScrollArea, QGroupBox, QStackedWidget, + QWidget, + QDialog, + QCheckBox, + QComboBox, + QDial, + QPushButton, + QLabel, + QLCDNumber, + QLineEdit, + QRadioButton, + QScrollBar, + QSlider, + QSpinBox, + QTextEdit, + QDateEdit, + QTimeEdit, + QDateTimeEdit, + QListView, + QProgressBar, + QTableView, + QTabWidget, + QTextBrowser, + QDialogButtonBox, + QScrollArea, + QGroupBox, + QStackedWidget, ] def printMsg(self, msg): @@ -81,29 +147,32 @@ def widgetXml(self, element, widget, level=0, label=None): return lab = label - if hasattr(widget, 'text'): + if hasattr(widget, "text"): lab = widget.text() if widget.windowTitle(): label = widget.windowTitle() if not lab: - lab = '' + lab = "" - subElement = self.doc.createElement('widget') - subElement.setAttribute('class', widget.__class__.__name__) - subElement.setAttribute('objectName', widget.objectName()) - subElement.setAttribute('label', lab) + subElement = self.doc.createElement("widget") + subElement.setAttribute("class", widget.__class__.__name__) + subElement.setAttribute("objectName", widget.objectName()) + subElement.setAttribute("label", lab) element.appendChild(subElement) # print str ( widget.children () ) # tab widget label is stored in QTabWidget->QTabBarPrivate->tabList->QTab .. if type(widget) in [QTabWidget]: - children = list({'widget': widget.widget(i), 'label': widget.tabText(i)} for i in range(0, widget.count())) + children = list( + {"widget": widget.widget(i), "label": widget.tabText(i)} + for i in range(0, widget.count()) + ) else: - children = list({'widget': c, 'label': None} for c in widget.children()) + children = list({"widget": c, "label": None} for c in widget.children()) for child in children: - w = child['widget'] + w = child["widget"] if w.isWidgetType() and (type(w) in self.follow): - self.widgetXml(subElement, w, level + 1, child['label']) + self.widgetXml(subElement, w, level + 1, child["label"]) def xml(self): self.doc = QDomDocument() @@ -122,7 +191,7 @@ def xml(self): return self.doc.toString(2) -if __name__ == '__main__': +if __name__ == "__main__": from qgis.PyQt.QtCore import QApplication app = QApplication(sys.argv) # required by loadUi diff --git a/src/plugins/grass/qgis_grass_test.py b/src/plugins/grass/qgis_grass_test.py index 3e5b79d8f725..2c406f8225c1 100755 --- a/src/plugins/grass/qgis_grass_test.py +++ b/src/plugins/grass/qgis_grass_test.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- # ----------------------------------------------------------- # # Copyright (C) 2012 Radim Blazek @@ -35,15 +34,15 @@ - writes out report *************************************************************************** """ -__author__ = 'Radim Blazek' -__date__ = 'December 2012' -__copyright__ = '(C) 2012, Radim Blazek' +__author__ = "Radim Blazek" +__date__ = "December 2012" +__copyright__ = "(C) 2012, Radim Blazek" import os -import sys +import re import subprocess +import sys import time -import re class Test: @@ -71,7 +70,7 @@ def writeReport(self): def test(self): print("GRASS Direct test") - tmp_dir = os.path.abspath("qgis-grass-test-%s" % time.strftime('%y%m%d-%H%M%S')) + tmp_dir = os.path.abspath("qgis-grass-test-%s" % time.strftime("%y%m%d-%H%M%S")) tmp_dir = os.path.abspath("qgis-grass-test-debug") # debug print("Output will be written to %s" % tmp_dir) @@ -82,14 +81,21 @@ def test(self): print("Getting list of rasters ...") rasters = self.srun(["g.mlist", "type=rast"]).splitlines() max_rasters = 1 - print("%s rasters found, using first %s" % (len(rasters), max_rasters)) + print(f"{len(rasters)} rasters found, using first {max_rasters}") rasters = rasters[0:1] print("Exporting rasters") for raster in rasters: print(raster) - output = "%s/%s.tif" % (files_dir, raster) - self.srun(["g.region", "rast=%s" % raster, "cols=%s" % self.size, "rows=%s" % self.size]) + output = f"{files_dir}/{raster}.tif" + self.srun( + [ + "g.region", + "rast=%s" % raster, + "cols=%s" % self.size, + "rows=%s" % self.size, + ] + ) self.srun(["r.out.gdal", "input=%s" % raster, "output=%s" % output]) # run modules @@ -98,26 +104,49 @@ def test(self): module = re.sub(" *", " ", module) module_name = module.split(" ")[0] # --- native --- - self.srun(["g.region", "rast=%s" % raster, "cols=%s" % self.size, "rows=%s" % self.size]) + self.srun( + [ + "g.region", + "rast=%s" % raster, + "cols=%s" % self.size, + "rows=%s" % self.size, + ] + ) output = "qgistest1" # clean old self.srun(["g.remove", "-f", "rast=%s" % output]) # substitute rasters - native_args = module.replace("R1", raster).replace("RO1", output).split(" ") + native_args = ( + module.replace("R1", raster).replace("RO1", output).split(" ") + ) (code, out, err) = self.run(native_args) if code != 0: self.report("Native failed: %s" % " ".join(native_args)) # export - native_output_file = "%s/%s-%s-native.tif" % (files_dir, module_name, raster) - self.srun(["r.out.gdal", "input=%s" % output, "output=%s" % native_output_file]) + native_output_file = "{}/{}-{}-native.tif".format( + files_dir, module_name, raster + ) + self.srun( + [ + "r.out.gdal", + "input=%s" % output, + "output=%s" % native_output_file, + ] + ) self.srun(["g.remove", "-f", "rast=%s" % output]) # --- direct --- - direct_input_file = "%s/%s.tif" % (files_dir, raster) - direct_output_file = "%s/%s-%s-direct.tif" % (files_dir, module_name, raster) + direct_input_file = f"{files_dir}/{raster}.tif" + direct_output_file = "{}/{}-{}-direct.tif".format( + files_dir, module_name, raster + ) # substitute rasters - direct_args = module.replace("R1", direct_input_file).replace("RO1", direct_output_file).split(" ") + direct_args = ( + module.replace("R1", direct_input_file) + .replace("RO1", direct_output_file) + .split(" ") + ) env = os.environ # CRS @@ -126,38 +155,57 @@ def test(self): proj = proj.splitlines() proj = " ".join(proj) print(proj) - env['QGIS_GRASS_CRS'] = proj + env["QGIS_GRASS_CRS"] = proj # set GRASS region as environment variable reg = self.srun(["g.region", "-g"]) reg_dict = dict(item.split("=") for item in reg.splitlines()) - reg_var = {'n': 'north', 's': 'south', 'e': 'east', 'w': 'west', 'nsres': 'n-s resol', 'ewres': 'e-w resol'} + reg_var = { + "n": "north", + "s": "south", + "e": "east", + "w": "west", + "nsres": "n-s resol", + "ewres": "e-w resol", + } if longlat: region = "proj:3;zone:-1" # longlat else: region = "proj:99;zone:-1" # other projection for k, v in reg_dict.iteritems(): - if k == 'cells': + if k == "cells": continue kn = k if k in reg_var: kn = reg_var[k] - region += ";%s:%s" % (kn, v) + region += f";{kn}:{v}" print(region) - env['GRASS_REGION'] = region + env["GRASS_REGION"] = region # add path to fake GRASS gis library - env['LD_LIBRARY_PATH'] = "%s/lib/qgis/plugins/:%s" % (env['QGIS_PREFIX_PATH'], env['LD_LIBRARY_PATH']) + env["LD_LIBRARY_PATH"] = "{}/lib/qgis/plugins/:{}".format( + env["QGIS_PREFIX_PATH"], env["LD_LIBRARY_PATH"] + ) (code, out, err) = self.run(direct_args, env) print("code = %s" % code) if code != 0: - self.report("Direct failed: %s\n%s\n%s" % (" ".join(direct_args), out, err)) + self.report( + "Direct failed: {}\n{}\n{}".format( + " ".join(direct_args), out, err + ) + ) # TODO: compare native x direct output def run(self, args, env=None, input=None, exit_on_error=False): cmd = " ".join(args) print(cmd) - p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, env=env) + p = subprocess.Popen( + args, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + env=env, + ) com = p.communicate(input) p.wait() @@ -174,13 +222,11 @@ def srun(self, args): def modules(self): # R1 - input raster 1 # RO1 - output raster 1 - modules = [ - "r.slope.aspect elevation=R1 aspect=RO1" - ] + modules = ["r.slope.aspect elevation=R1 aspect=RO1"] return modules -if __name__ == '__main__': +if __name__ == "__main__": test = Test() test.test() test.writeReport() diff --git a/src/plugins/grass/scripts/db.connect-login.pg.py b/src/plugins/grass/scripts/db.connect-login.pg.py index 75bdf6e0a212..4375d45d00f3 100644 --- a/src/plugins/grass/scripts/db.connect-login.pg.py +++ b/src/plugins/grass/scripts/db.connect-login.pg.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- """ *************************************************************************** @@ -18,82 +17,85 @@ *************************************************************************** """ -__author__ = 'Radim Blazek' -__date__ = 'July 2009' -__copyright__ = '(C) 2009, Radim Blazek' - - -#%Module -#% description: Make connection to PostgreSQL database and login. -#% keywords: database -#%End - -#%option -#% key: host -#% type: string -#% label: Host -#% description: Host name of the machine on which the server is running. -#% required : no -#%end - -#%option -#% key: port -#% type: integer -#% label: Port -#% description: TCP port on which the server is listening, usually 5432. -#% required : no -#%end - -#%option -#% key: database -#% type: string -#% key_desc : name -#% gisprompt: old_dbname,dbname,dbname -#% label: Database -#% description: Database name -#% required : yes -#%end - -#%option -#% key: schema -#% type: string -#% label: Schema -#% description: Database schema. -#% required : no -#%end - -#%option -#% key: user -#% type: string -#% label: User -#% description: Connect to the database as the user username instead of the default. -#% required : no -#%end - -#%option -#% key: password -#% type: string -#% label: Password -#% description: Password will be stored in file! -#% required : no -#%end +__author__ = "Radim Blazek" +__date__ = "July 2009" +__copyright__ = "(C) 2009, Radim Blazek" + + +# %Module +# % description: Make connection to PostgreSQL database and login. +# % keywords: database +# %End + +# %option +# % key: host +# % type: string +# % label: Host +# % description: Host name of the machine on which the server is running. +# % required : no +# %end + +# %option +# % key: port +# % type: integer +# % label: Port +# % description: TCP port on which the server is listening, usually 5432. +# % required : no +# %end + +# %option +# % key: database +# % type: string +# % key_desc : name +# % gisprompt: old_dbname,dbname,dbname +# % label: Database +# % description: Database name +# % required : yes +# %end + +# %option +# % key: schema +# % type: string +# % label: Schema +# % description: Database schema. +# % required : no +# %end + +# %option +# % key: user +# % type: string +# % label: User +# % description: Connect to the database as the user username instead of the default. +# % required : no +# %end + +# %option +# % key: password +# % type: string +# % label: Password +# % description: Password will be stored in file! +# % required : no +# %end import sys + try: from grass.script import core as grass except ImportError: import grass except: - raise Exception("Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4") + raise Exception( + "Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4" + ) def main(): - host = options['host'] - port = options['port'] - database = options['database'] - schema = options['schema'] - user = options['user'] - password = options['password'] + host = options["host"] + port = options["port"] + database = options["database"] + schema = options["schema"] + user = options["user"] + password = options["password"] # Test connection conn = "dbname=" + database @@ -106,22 +108,47 @@ def main(): if user or password: print("Setting login (db.login) ... ") sys.stdout.flush() - if grass.run_command('db.login', driver="pg", database=conn, user=user, password=password) != 0: + if ( + grass.run_command( + "db.login", driver="pg", database=conn, user=user, password=password + ) + != 0 + ): grass.fatal("Cannot login") # Try to connect print("Testing connection ...") sys.stdout.flush() - if grass.run_command('db.select', quiet=True, flags='c', driver="pg", database=conn, sql="select version()") != 0: + if ( + grass.run_command( + "db.select", + quiet=True, + flags="c", + driver="pg", + database=conn, + sql="select version()", + ) + != 0 + ): if user or password: print("Deleting login (db.login) ...") sys.stdout.flush() - if grass.run_command('db.login', quiet=True, driver="pg", database=conn, user="", password="") != 0: + if ( + grass.run_command( + "db.login", + quiet=True, + driver="pg", + database=conn, + user="", + password="", + ) + != 0 + ): print("Cannot delete login.") sys.stdout.flush() grass.fatal("Cannot connect to database.") - if grass.run_command('db.connect', driver="pg", database=conn, schema=schema) != 0: + if grass.run_command("db.connect", driver="pg", database=conn, schema=schema) != 0: grass.fatal("Cannot connect to database.") diff --git a/src/plugins/grass/scripts/qgis.v.kernel.rast.py b/src/plugins/grass/scripts/qgis.v.kernel.rast.py index 579e9cdc0759..60c84a219d24 100644 --- a/src/plugins/grass/scripts/qgis.v.kernel.rast.py +++ b/src/plugins/grass/scripts/qgis.v.kernel.rast.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- """ *************************************************************************** @@ -18,9 +17,9 @@ *************************************************************************** """ -__author__ = 'Radim Blazek' -__date__ = 'February 2010' -__copyright__ = '(C) 2010, Radim Blazek' +__author__ = "Radim Blazek" +__date__ = "February 2010" +__copyright__ = "(C) 2010, Radim Blazek" ############################################################################ @@ -30,50 +29,57 @@ # ############################################################################# -#%Module -#% description: Generates a raster density map from vector points data using a moving 2D isotropic Gaussian kernel. -#% keywords: vector, export, database -#%End +# %Module +# % description: Generates a raster density map from vector points data using a moving 2D isotropic Gaussian kernel. +# % keywords: vector, export, database +# %End -#%option -#% key: input -#% type: string -#% gisprompt: old,vector,vector -#% key_desc : name -#% description: Input vector with training points -#% required : yes -#%end +# %option +# % key: input +# % type: string +# % gisprompt: old,vector,vector +# % key_desc : name +# % description: Input vector with training points +# % required : yes +# %end -#%option -#% key: stddeviation -#% type: double -#% description: Standard deviation in map units -#% required : yes -#%end +# %option +# % key: stddeviation +# % type: double +# % description: Standard deviation in map units +# % required : yes +# %end -#%option -#% key: output -#% type: string -#% gisprompt: new,cell,raster -#% key_desc : name -#% description: Output raster map -#% required : yes -#%end +# %option +# % key: output +# % type: string +# % gisprompt: new,cell,raster +# % key_desc : name +# % description: Output raster map +# % required : yes +# %end try: from grass.script import core as grass except ImportError: import grass except: - raise Exception("Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4") + raise Exception( + "Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4" + ) def main(): - input = options['input'] - output = options['output'] - stddeviation = options['stddeviation'] + input = options["input"] + output = options["output"] + stddeviation = options["stddeviation"] - if grass.run_command('v.kernel', input=input, stddeviation=stddeviation, output=output) != 0: + if ( + grass.run_command( + "v.kernel", input=input, stddeviation=stddeviation, output=output + ) + != 0 + ): grass.fatal("Cannot run v.kernel.") diff --git a/src/plugins/grass/scripts/qgis.v.upgrade.py b/src/plugins/grass/scripts/qgis.v.upgrade.py index 2b8aa23b1f0a..78d154d6bcbf 100644 --- a/src/plugins/grass/scripts/qgis.v.upgrade.py +++ b/src/plugins/grass/scripts/qgis.v.upgrade.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- """ *************************************************************************** @@ -18,9 +17,9 @@ *************************************************************************** """ -__author__ = 'Radim Blazek' -__date__ = 'October 2015' -__copyright__ = '(C) 2015 by Radim Blazek' +__author__ = "Radim Blazek" +__date__ = "October 2015" +__copyright__ = "(C) 2015 by Radim Blazek" ############################################################################ @@ -38,33 +37,35 @@ # ############################################################################# -#%Module -#% description: Upgrade all vectors from GRASS 6 to GRASS 7 -#% keywords: vector, upgrade -#%End +# %Module +# % description: Upgrade all vectors from GRASS 6 to GRASS 7 +# % keywords: vector, upgrade +# %End try: from grass.script import core as grass except ImportError: import grass except: - raise Exception("Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4") + raise Exception( + "Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4" + ) def main(): # see https://grasswiki.osgeo.org/wiki/Convert_all_GRASS_6_vector_maps_to_GRASS_7 - grass.message('Building topology') - if grass.run_command('v.build.all') != 0: - grass.warning('Cannot build topology') + grass.message("Building topology") + if grass.run_command("v.build.all") != 0: + grass.warning("Cannot build topology") - grass.message('Creating new DB connection') - if grass.run_command('db.connect', flags='d') != 0: - grass.warning('Cannot create new DB connection') + grass.message("Creating new DB connection") + if grass.run_command("db.connect", flags="d") != 0: + grass.warning("Cannot create new DB connection") return - grass.message('Transferring tables to the new DB') - if grass.run_command('v.db.reconnect.all', flags='cd') != 0: - grass.warning('Cannot transfer tables') + grass.message("Transferring tables to the new DB") + if grass.run_command("v.db.reconnect.all", flags="cd") != 0: + grass.warning("Cannot transfer tables") if __name__ == "__main__": diff --git a/src/plugins/grass/scripts/r.external.all.py b/src/plugins/grass/scripts/r.external.all.py index 7b5487824ccf..b06f0103c2c7 100644 --- a/src/plugins/grass/scripts/r.external.all.py +++ b/src/plugins/grass/scripts/r.external.all.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- """ *************************************************************************** @@ -18,9 +17,9 @@ *************************************************************************** """ -__author__ = 'Lorenzo Masini' -__date__ = 'July 2009' -__copyright__ = '(C) 2009, Lorenzo Masini' +__author__ = "Lorenzo Masini" +__date__ = "July 2009" +__copyright__ = "(C) 2009, Lorenzo Masini" ############################################################################ @@ -38,56 +37,69 @@ # ############################################################################# -#%Module -#% description: Link all GDAL supported raster files into a directory to binary raster map layers. -#% keywords: raster, import -#%End - -#%option -#% key: input -#% type: string -#% gisprompt: input -#% key_desc : name -#% description: Directory containing raster files -#% required : yes -#%end - -#%option -#% key: band -#% type: integer -#% description: Band to select -#% answer: 1 -#% required : no -#%end - -#%flag -#% key: o -#% description: Override projection (use location's projection) -#%end - -#%flag -#% key: e -#% description: Extend location extents based on new dataset -#%end - -#%flag -#% key: r -#% description: Recursively scan subdirectories +# %Module +# % description: Link all GDAL supported raster files into a directory to binary raster map layers. +# % keywords: raster, import +# %End + +# %option +# % key: input +# % type: string +# % gisprompt: input +# % key_desc : name +# % description: Directory containing raster files +# % required : yes +# %end + +# %option +# % key: band +# % type: integer +# % description: Band to select +# % answer: 1 +# % required : no +# %end + +# %flag +# % key: o +# % description: Override projection (use location's projection) +# %end + +# %flag +# % key: e +# % description: Extend location extents based on new dataset +# %end + +# %flag +# % key: r +# % description: Recursively scan subdirectories import os + try: from grass.script import core as grass except ImportError: import grass except: - raise Exception("Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4") + raise Exception( + "Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4" + ) def import_directory_of_rasters(directory, recursive): for dir, dirnames, filenames in os.walk(directory): for filename in filenames: - if grass.run_command('r.external', flags=flags_string, input=os.path.join(dir, filename), band=options['band'], output=filename[:-4], title=filename[:-4]) != 0: - grass.warning('Cannot import file' + filename) + if ( + grass.run_command( + "r.external", + flags=flags_string, + input=os.path.join(dir, filename), + band=options["band"], + output=filename[:-4], + title=filename[:-4], + ) + != 0 + ): + grass.warning("Cannot import file" + filename) if not recursive: break for dirname in dirnames: @@ -95,13 +107,13 @@ def import_directory_of_rasters(directory, recursive): def main(): - input = options['input'] - recursive = flags['r'] + input = options["input"] + recursive = flags["r"] import_directory_of_rasters(input, recursive) if __name__ == "__main__": options, flags = grass.parser() - flags_string = "".join([k for k in flags.keys() if flags[k] and k != 'r']) + flags_string = "".join([k for k in flags.keys() if flags[k] and k != "r"]) main() diff --git a/src/plugins/grass/scripts/t.rast.what.qgis.py b/src/plugins/grass/scripts/t.rast.what.qgis.py index 1b0beba20cc6..91e054c42537 100644 --- a/src/plugins/grass/scripts/t.rast.what.qgis.py +++ b/src/plugins/grass/scripts/t.rast.what.qgis.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- ############################################################################ # # MODULE: t.rast.what @@ -17,81 +16,81 @@ # ############################################################################# -#%module -#% description: Sample a space time raster dataset at specific vector point coordinates and write the output to stdout using different layouts -#% keyword: temporal -#% keyword: sampling -#% keyword: raster -#% keyword: time -#%end - -#%option G_OPT_V_INPUT -#% key: points -#% required: no -#%end - -#%option G_OPT_M_COORDS -#% required: no -#% description: Comma separated list of coordinates -#%end - -#%option G_OPT_STRDS_INPUT -#% key: strds -#%end - -#%option G_OPT_F_OUTPUT -#% required: no -#% description: Name for the output file or "-" in case stdout should be used -#% answer: - -#%end - -#%option G_OPT_T_WHERE -#%end - -#%option G_OPT_M_NULL_VALUE -#%end - -#%option G_OPT_F_SEP -#%end - -#%option -#% key: order -#% type: string -#% description: Sort the maps by category -#% required: no -#% multiple: yes -#% options: id, name, creator, mapset, creation_time, modification_time, start_time, end_time, north, south, west, east, min, max -#% answer: start_time -#%end - -#%option -#% key: layout -#% type: string -#% description: The layout of the output. One point per row (row), one point per column (col), all timsteps in one row (timerow) -#% required: no -#% multiple: no -#% options: row, col, timerow -#% answer: row -#%end - -#%option -#% key: nprocs -#% type: integer -#% description: Number of r.what processes to run in parallel -#% required: no -#% multiple: no -#% answer: 1 -#%end - -#%flag -#% key: n -#% description: Output header row -#%end - -#%flag -#% key: i -#% description: Use stdin as input and ignore coordinates and point option -#%end +# %module +# % description: Sample a space time raster dataset at specific vector point coordinates and write the output to stdout using different layouts +# % keyword: temporal +# % keyword: sampling +# % keyword: raster +# % keyword: time +# %end + +# %option G_OPT_V_INPUT +# % key: points +# % required: no +# %end + +# %option G_OPT_M_COORDS +# % required: no +# % description: Comma separated list of coordinates +# %end + +# %option G_OPT_STRDS_INPUT +# % key: strds +# %end + +# %option G_OPT_F_OUTPUT +# % required: no +# % description: Name for the output file or "-" in case stdout should be used +# % answer: - +# %end + +# %option G_OPT_T_WHERE +# %end + +# %option G_OPT_M_NULL_VALUE +# %end + +# %option G_OPT_F_SEP +# %end + +# %option +# % key: order +# % type: string +# % description: Sort the maps by category +# % required: no +# % multiple: yes +# % options: id, name, creator, mapset, creation_time, modification_time, start_time, end_time, north, south, west, east, min, max +# % answer: start_time +# %end + +# %option +# % key: layout +# % type: string +# % description: The layout of the output. One point per row (row), one point per column (col), all timsteps in one row (timerow) +# % required: no +# % multiple: no +# % options: row, col, timerow +# % answer: row +# %end + +# %option +# % key: nprocs +# % type: integer +# % description: Number of r.what processes to run in parallel +# % required: no +# % multiple: no +# % answer: 1 +# %end + +# %flag +# % key: n +# % description: Output header row +# %end + +# %flag +# % key: i +# % description: Use stdin as input and ignore coordinates and point option +# %end ## Temporary disabled the r.what flags due to test issues ##%flag @@ -109,15 +108,16 @@ ##% description: Output integer category values, not cell values ##%end -import sys import copy +import sys + +import grass.pygrass.modules as pymod import grass.script as gscript import grass.temporal as tgis -import grass.pygrass.modules as pymod - ############################################################################ + def main(options, flags): # Get the options @@ -145,12 +145,16 @@ def main(options, flags): gscript.fatal(_("Options coordinates and points are mutually exclusive")) if not coordinates and not points and not use_stdin: - gscript.fatal(_("Please specify the coordinates, the points option or use the 's' option to pipe coordinate positions to t.rast.what from stdin, to provide the sampling coordinates")) + gscript.fatal( + _( + "Please specify the coordinates, the points option or use the 's' option to pipe coordinate positions to t.rast.what from stdin, to provide the sampling coordinates" + ) + ) if use_stdin: coordinates_stdin = str(sys.__stdin__.read()) # Check if coordinates are given with site names or IDs - stdin_length = len(coordinates_stdin.split('\n')[0].split()) + stdin_length = len(coordinates_stdin.split("\n")[0].split()) if stdin_length <= 2: site_input = False elif stdin_length >= 3: @@ -165,8 +169,7 @@ def main(options, flags): dbif.connect() sp = tgis.open_old_stds(strds, "strds", dbif) - maps = sp.get_registered_maps_as_objects(where=where, order=order, - dbif=dbif) + maps = sp.get_registered_maps_as_objects(where=where, order=order, dbif=dbif) dbif.close() if not maps: @@ -195,27 +198,43 @@ def main(options, flags): # Configure the r.what module if points: - r_what = pymod.Module("r.what", map="dummy", - output="dummy", run_=False, - separator=separator, points=points, - overwrite=overwrite, flags=flags, - quiet=True) + r_what = pymod.Module( + "r.what", + map="dummy", + output="dummy", + run_=False, + separator=separator, + points=points, + overwrite=overwrite, + flags=flags, + quiet=True, + ) elif coordinates: # Create a list of values coord_list = coordinates.split(",") - r_what = pymod.Module("r.what", map="dummy", - output="dummy", run_=False, - separator=separator, - coordinates=coord_list, - overwrite=overwrite, flags=flags, - quiet=True) + r_what = pymod.Module( + "r.what", + map="dummy", + output="dummy", + run_=False, + separator=separator, + coordinates=coord_list, + overwrite=overwrite, + flags=flags, + quiet=True, + ) elif use_stdin: - r_what = pymod.Module("r.what", map="dummy", - output="dummy", run_=False, - separator=separator, - stdin_=coordinates_stdin, - overwrite=overwrite, flags=flags, - quiet=True) + r_what = pymod.Module( + "r.what", + map="dummy", + output="dummy", + run_=False, + separator=separator, + stdin_=coordinates_stdin, + overwrite=overwrite, + flags=flags, + quiet=True, + ) else: grass.error(_("Please specify points or coordinates")) @@ -252,13 +271,24 @@ def main(options, flags): count = 0 for loop in range(num_loops): file_name = gscript.tempfile() + "_%i" % (loop) - count = process_loop(nprocs, maps, file_name, count, maps_per_process, - remaining_maps_per_loop, output_files, - output_time_list, r_what, process_queue) + count = process_loop( + nprocs, + maps, + file_name, + count, + maps_per_process, + remaining_maps_per_loop, + output_files, + output_time_list, + r_what, + process_queue, + ) process_queue.wait() - gscript.verbose("Number of raster map layers remaining for sampling %i" % (remaining_maps)) + gscript.verbose( + "Number of raster map layers remaining for sampling %i" % (remaining_maps) + ) if remaining_maps > 0: # Use a single process if less then 100 maps if remaining_maps <= 100: @@ -270,48 +300,65 @@ def main(options, flags): remaining_maps_per_loop = remaining_maps % nprocs file_name = "out_remain" - process_loop(nprocs, maps, file_name, count, maps_per_process, - remaining_maps_per_loop, output_files, - output_time_list, r_what, process_queue) + process_loop( + nprocs, + maps, + file_name, + count, + maps_per_process, + remaining_maps_per_loop, + output_files, + output_time_list, + r_what, + process_queue, + ) # Wait for unfinished processes process_queue.wait() # Out the output files in the correct order together if layout == "row": - one_point_per_row_output(separator, output_files, output_time_list, - output, write_header, site_input) + one_point_per_row_output( + separator, output_files, output_time_list, output, write_header, site_input + ) elif layout == "col": - one_point_per_col_output(separator, output_files, output_time_list, - output, write_header, site_input) + one_point_per_col_output( + separator, output_files, output_time_list, output, write_header, site_input + ) else: - one_point_per_timerow_output(separator, output_files, output_time_list, - output, write_header, site_input) + one_point_per_timerow_output( + separator, output_files, output_time_list, output, write_header, site_input + ) + ############################################################################ -def one_point_per_row_output(separator, output_files, output_time_list, - output, write_header, site_input): +def one_point_per_row_output( + separator, output_files, output_time_list, output, write_header, site_input +): """Write one point per row - output is of type: x,y,start,end,value + output is of type: x,y,start,end,value """ # open the output file for writing - out_file = open(output, 'w') if output != "-" else sys.stdout + out_file = open(output, "w") if output != "-" else sys.stdout if write_header is True: if site_input: - out_file.write("x%(sep)sy%(sep)ssite%(sep)sstart%(sep)send%(sep)svalue\n" - % ({"sep": separator})) + out_file.write( + "x%(sep)sy%(sep)ssite%(sep)sstart%(sep)send%(sep)svalue\n" + % ({"sep": separator}) + ) else: - out_file.write("x%(sep)sy%(sep)sstart%(sep)send%(sep)svalue\n" - % ({"sep": separator})) + out_file.write( + "x%(sep)sy%(sep)sstart%(sep)send%(sep)svalue\n" % ({"sep": separator}) + ) for count in range(len(output_files)): file_name = output_files[count] gscript.verbose(_("Transforming r.what output file %s" % (file_name))) map_list = output_time_list[count] - in_file = open(file_name, "r") + in_file = open(file_name) for line in in_file: line = line.split(separator) x = line[0] @@ -324,14 +371,29 @@ def one_point_per_row_output(separator, output_files, output_time_list, for i in range(len(values)): start, end = map_list[i].get_temporal_extent_as_tuple() if site_input: - coor_string = "%(x)10.10f%(sep)s%(y)10.10f%(sep)s%(site_name)s%(sep)s"\ - % ({"x": float(x), "y": float(y), "site_name": str(site), "sep": separator}) + coor_string = ( + "%(x)10.10f%(sep)s%(y)10.10f%(sep)s%(site_name)s%(sep)s" + % ( + { + "x": float(x), + "y": float(y), + "site_name": str(site), + "sep": separator, + } + ) + ) else: - coor_string = "%(x)10.10f%(sep)s%(y)10.10f%(sep)s"\ - % ({"x": float(x), "y": float(y), "sep": separator}) - time_string = "%(start)s%(sep)s%(end)s%(sep)s%(val)s\n"\ - % ({"start": str(start), "end": str(end), - "val": (values[i].strip()), "sep": separator}) + coor_string = "%(x)10.10f%(sep)s%(y)10.10f%(sep)s" % ( + {"x": float(x), "y": float(y), "sep": separator} + ) + time_string = "%(start)s%(sep)s%(end)s%(sep)s%(val)s\n" % ( + { + "start": str(start), + "end": str(end), + "val": (values[i].strip()), + "sep": separator, + } + ) out_file.write(coor_string + time_string) @@ -340,26 +402,28 @@ def one_point_per_row_output(separator, output_files, output_time_list, if out_file is not sys.stdout: out_file.close() + ############################################################################ -def one_point_per_col_output(separator, output_files, output_time_list, - output, write_header, site_input): +def one_point_per_col_output( + separator, output_files, output_time_list, output, write_header, site_input +): """Write one point per col - output is of type: - start,end,point_1 value,point_2 value,...,point_n value + output is of type: + start,end,point_1 value,point_2 value,...,point_n value - Each row represents a single raster map, hence a single time stamp + Each row represents a single raster map, hence a single time stamp """ # open the output file for writing - out_file = open(output, 'w') if output != "-" else sys.stdout + out_file = open(output, "w") if output != "-" else sys.stdout first = True for count in range(len(output_files)): file_name = output_files[count] gscript.verbose(_("Transforming r.what output file %s" % (file_name))) map_list = output_time_list[count] - in_file = open(file_name, "r") + in_file = open(file_name) lines = in_file.readlines() matrix = [] @@ -376,19 +440,25 @@ def one_point_per_col_output(separator, output_files, output_time_list, x = row[0] y = row[1] site = row[2] - out_file.write("%(sep)s%(x)10.10f;%(y)10.10f;%(site_name)s" - % ({"sep": separator, - "x": float(x), - "y": float(y), - "site_name": str(site)})) + out_file.write( + "%(sep)s%(x)10.10f;%(y)10.10f;%(site_name)s" + % ( + { + "sep": separator, + "x": float(x), + "y": float(y), + "site_name": str(site), + } + ) + ) else: for row in matrix: x = row[0] y = row[1] - out_file.write("%(sep)s%(x)10.10f;%(y)10.10f" - % ({"sep": separator, - "x": float(x), - "y": float(y)})) + out_file.write( + "%(sep)s%(x)10.10f;%(y)10.10f" + % ({"sep": separator, "x": float(x), "y": float(y)}) + ) out_file.write("\n") @@ -396,35 +466,37 @@ def one_point_per_col_output(separator, output_files, output_time_list, for col in xrange(num_cols - 3): start, end = output_time_list[count][col].get_temporal_extent_as_tuple() - time_string = "%(start)s%(sep)s%(end)s"\ - % ({"start": str(start), "end": str(end), - "sep": separator}) + time_string = "%(start)s%(sep)s%(end)s" % ( + {"start": str(start), "end": str(end), "sep": separator} + ) out_file.write(time_string) for row in xrange(len(matrix)): value = matrix[row][col + 3] - out_file.write("%(sep)s%(value)s" - % ({"sep": separator, - "value": value.strip()})) + out_file.write( + "%(sep)s%(value)s" % ({"sep": separator, "value": value.strip()}) + ) out_file.write("\n") in_file.close() if out_file is not sys.stdout: out_file.close() + ############################################################################ -def one_point_per_timerow_output(separator, output_files, output_time_list, - output, write_header, site_input): +def one_point_per_timerow_output( + separator, output_files, output_time_list, output, write_header, site_input +): """Use the original layout of the r.what output and print instead of - the raster names, the time stamps as header + the raster names, the time stamps as header - One point per line for all time stamps: - x|y|1991-01-01 00:00:00;1991-01-02 00:00:00|1991-01-02 00:00:00;1991-01-03 00:00:00|1991-01-03 00:00:00;1991-01-04 00:00:00|1991-01-04 00:00:00;1991-01-05 00:00:00 - 3730731.49590371|5642483.51236521|6|8|7|7 - 3581249.04638104|5634411.97526282|5|8|7|7 + One point per line for all time stamps: + x|y|1991-01-01 00:00:00;1991-01-02 00:00:00|1991-01-02 00:00:00;1991-01-03 00:00:00|1991-01-03 00:00:00;1991-01-04 00:00:00|1991-01-04 00:00:00;1991-01-05 00:00:00 + 3730731.49590371|5642483.51236521|6|8|7|7 + 3581249.04638104|5634411.97526282|5|8|7|7 """ - out_file = open(output, 'w') if output != "-" else sys.stdout + out_file = open(output, "w") if output != "-" else sys.stdout matrix = [] header = "" @@ -434,7 +506,7 @@ def one_point_per_timerow_output(separator, output_files, output_time_list, file_name = output_files[count] gscript.verbose("Transforming r.what output file %s" % (file_name)) map_list = output_time_list[count] - in_file = open(file_name, "r") + in_file = open(file_name) if write_header: if first is True: @@ -444,9 +516,9 @@ def one_point_per_timerow_output(separator, output_files, output_time_list, header = "x%(sep)sy" % ({"sep": separator}) for map in map_list: start, end = map.get_temporal_extent_as_tuple() - time_string = "%(sep)s%(start)s;%(end)s"\ - % ({"start": str(start), "end": str(end), - "sep": separator}) + time_string = "%(sep)s%(start)s;%(end)s" % ( + {"start": str(start), "end": str(end), "sep": separator} + ) header += time_string lines = in_file.readlines() @@ -484,12 +556,22 @@ def one_point_per_timerow_output(separator, output_files, output_time_list, if out_file is not sys.stdout: out_file.close() + ############################################################################ -def process_loop(nprocs, maps, file_name, count, maps_per_process, - remaining_maps_per_loop, output_files, - output_time_list, r_what, process_queue): +def process_loop( + nprocs, + maps, + file_name, + count, + maps_per_process, + remaining_maps_per_loop, + output_files, + output_time_list, + r_what, + process_queue, +): """Call r.what in parallel subprocesses""" first = True for process in range(nprocs): @@ -513,9 +595,16 @@ def process_loop(nprocs, maps, file_name, count, maps_per_process, output_time_list.append(map_list) - gscript.verbose(("Process maps %(samp_start)i to %(samp_end)i (of %(total)i)" % - ({"samp_start": count - len(map_names) + 1, - "samp_end": count, "total": len(maps)}))) + gscript.verbose( + "Process maps %(samp_start)i to %(samp_end)i (of %(total)i)" + % ( + { + "samp_start": count - len(map_names) + 1, + "samp_end": count, + "total": len(maps), + } + ) + ) mod = copy.deepcopy(r_what) mod(map=map_names, output=final_file_name) # print(mod.get_bash()) diff --git a/src/plugins/grass/scripts/v.class.mlpy.qgis.py b/src/plugins/grass/scripts/v.class.mlpy.qgis.py index dff9493e8e85..f762d5a57155 100644 --- a/src/plugins/grass/scripts/v.class.mlpy.qgis.py +++ b/src/plugins/grass/scripts/v.class.mlpy.qgis.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- ############################################################################ # # MODULE: v.class.mlpy @@ -19,41 +18,41 @@ # ############################################################################ -#%module -#% description: Vector supervised classification tool which uses attributes as classification parameters (order of columns matters, names not), cat column identifies feature, class_column is excluded from classification parameters. -#% keyword: vector -#% keyword: classification -#% keyword: supervised -#%end -#%option G_OPT_V_MAP -#% key: input -#% description: Input vector map (attribute table required) -#% required: yes -#% multiple: no -#%end -#%option G_OPT_V_MAP -#% key: training -#% description: Training vector map (attribute table required) -#% required: yes -#% multiple: no -#%end -#%option G_OPT_V_FIELD -#% key: class_column -#% type: string -#% label: Name of column containing class -#% description: Used for both input/output and training dataset. If column does not exists in input map attribute table, it will be created. -#% required: no -#% multiple: no -#% answer: class -#%end -#%option -#% key: columns -#% type: string -#% label: Columns to be used in classification -#% description: Columns to be used in classification. If left empty, all columns will be used for classification except for class_column and cat column. -#% required: no -#% multiple: yes -#%end +# %module +# % description: Vector supervised classification tool which uses attributes as classification parameters (order of columns matters, names not), cat column identifies feature, class_column is excluded from classification parameters. +# % keyword: vector +# % keyword: classification +# % keyword: supervised +# %end +# %option G_OPT_V_MAP +# % key: input +# % description: Input vector map (attribute table required) +# % required: yes +# % multiple: no +# %end +# %option G_OPT_V_MAP +# % key: training +# % description: Training vector map (attribute table required) +# % required: yes +# % multiple: no +# %end +# %option G_OPT_V_FIELD +# % key: class_column +# % type: string +# % label: Name of column containing class +# % description: Used for both input/output and training dataset. If column does not exists in input map attribute table, it will be created. +# % required: no +# % multiple: no +# % answer: class +# %end +# %option +# % key: columns +# % type: string +# % label: Columns to be used in classification +# % description: Columns to be used in classification. If left empty, all columns will be used for classification except for class_column and cat column. +# % required: no +# % multiple: yes +# %end # TODO: add other classifiers @@ -64,15 +63,13 @@ import grass.script as grass - import numpy as np def addColumn(mapName, columnName, columnType): """Adds column to the map's table.""" - columnDefinition = columnName + ' ' + columnType - grass.run_command('v.db.addcolumn', map=mapName, - columns=columnDefinition) + columnDefinition = columnName + " " + columnType + grass.run_command("v.db.addcolumn", map=mapName, columns=columnDefinition) def hasColumn(tableDescription, column): @@ -80,20 +77,20 @@ def hasColumn(tableDescription, column): \todo This should be part of some object in the lib. """ - for col in tableDescription['cols']: + for col in tableDescription["cols"]: if col[0] == column: return True return False def updateColumn(mapName, column, cats, values=None): - """!Updates column values for rows with a given categories. + r"""!Updates column values for rows with a given categories. \param cats categories to be updated or a list of tuples (cat, value) if \p values is None \param values to be set for column (same length as cats) or \c None """ - statements = '' + statements = "" for i in range(len(cats)): if values is None: cat = str(cats[i][0]) @@ -101,16 +98,15 @@ def updateColumn(mapName, column, cats, values=None): else: cat = str(cats[i]) val = str(values[i]) - statement = 'UPDATE ' + mapName + ' SET ' - statement += column + ' = ' + val - statement += ' WHERE cat = ' + cat - statements += statement + ';\n' + statement = "UPDATE " + mapName + " SET " + statement += column + " = " + val + statement += " WHERE cat = " + cat + statements += statement + ";\n" - grass.write_command('db.execute', input='-', stdin=statements) + grass.write_command("db.execute", input="-", stdin=statements) class Classifier: - """!Interface class between mlpy and other code It does not uses numpy in the interface bu this may be wrong. @@ -120,10 +116,14 @@ def __init__(self): try: import mlpy except ImportError: - grass.fatal(_("Cannot import mlpy (http://mlpy.sourceforge.net)" - " library." - " Please install it or ensure that it is on path" - " (use PYTHONPATH variable).")) + grass.fatal( + _( + "Cannot import mlpy (http://mlpy.sourceforge.net)" + " library." + " Please install it or ensure that it is on path" + " (use PYTHONPATH variable)." + ) + ) # Pytlit has a problem with this mlpy and v.class.mlpy.py # thus, warnings for objects from mlpy has to be disabled self.mlclassifier = mlpy.DLDA(delta=0.01) # pylint: disable=E1101 @@ -144,7 +144,7 @@ def fromDbTableToSimpleTable(dbTable, columnsDescription, columnWithClass): sRow = [] for i, col in enumerate(row): columnName = columnsDescription[i][0] - if columnName != columnWithClass and columnName != 'cat': + if columnName != columnWithClass and columnName != "cat": sRow.append(float(col)) sTable.append(sRow) @@ -177,7 +177,7 @@ def extractColumnWithCats(dbTable, columnsDescription): for row in dbTable: for i, col in enumerate(row): columnName = columnsDescription[i][0] - if columnName == 'cat': + if columnName == "cat": column.append(float(col)) return column @@ -185,35 +185,38 @@ def extractColumnWithCats(dbTable, columnsDescription): # unused def fatal_noAttributeTable(mapName): - grass.fatal(_("Vector map <%s> has no or empty attribute table") - % mapName) + grass.fatal(_("Vector map <%s> has no or empty attribute table") % mapName) def fatal_noEnoughColumns(mapName, ncols, required): - grass.fatal(_("Not enough columns in vector map <%(map)s>" - " (found %(ncols)s, expected at least %(r)s") - % {'map': mapName, 'ncols': ncols, 'r': required}) + grass.fatal( + _( + "Not enough columns in vector map <%(map)s>" + " (found %(ncols)s, expected at least %(r)s" + ) + % {"map": mapName, "ncols": ncols, "r": required} + ) def fatal_noClassColumn(mapName, columnName): - grass.fatal(_("Vector map <%(map)s> does not have" - " the column <%(col)s> containing class") - % {'map': mapName, 'col': columnName}) + grass.fatal( + _("Vector map <%(map)s> does not have" " the column <%(col)s> containing class") + % {"map": mapName, "col": columnName} + ) def fatal_noRows(mapName): - grass.fatal(_("Empty attribute table for map vector <%(map)s>") - % {'map': mapName}) + grass.fatal(_("Empty attribute table for map vector <%(map)s>") % {"map": mapName}) def checkNcols(mapName, tableDescription, requiredNcols): - ncols = tableDescription['ncols'] + ncols = tableDescription["ncols"] if ncols < requiredNcols: fatal_noEnoughColumns(mapName, ncols, requiredNcols) def checkNrows(mapName, tableDescription): - if not tableDescription['nrows'] > 0: + if not tableDescription["nrows"] > 0: fatal_noRows(mapName) @@ -230,15 +233,15 @@ def checkDbConnection(mapName): def main(): options, unused = grass.parser() - mapName = options['input'] - trainingMapName = options['training'] + mapName = options["input"] + trainingMapName = options["training"] - columnWithClass = options['class_column'] + columnWithClass = options["class_column"] useAllColumns = True - if options['columns']: + if options["columns"]: # columns as string - columns = options['columns'].strip() + columns = options["columns"].strip() useAllColumns = False # TODO: allow same input and output map only if --overwrite was specified @@ -286,17 +289,21 @@ def main(): dbTable = grass.db_select(table=trainingMapName) else: # assuming that columns concatenated by comma - sql = 'SELECT %s,%s FROM %s' % (columnWithClass, columns, trainingMapName) + sql = f"SELECT {columnWithClass},{columns} FROM {trainingMapName}" dbTable = grass.db_select(sql=sql) - trainingParameters = fromDbTableToSimpleTable(dbTable, - columnsDescription=trainingTableDescription['cols'], - columnWithClass=columnWithClass) + trainingParameters = fromDbTableToSimpleTable( + dbTable, + columnsDescription=trainingTableDescription["cols"], + columnWithClass=columnWithClass, + ) if useAllColumns: - trainingClasses = extractColumnWithClass(dbTable, - columnsDescription=trainingTableDescription['cols'], - columnWithClass=columnWithClass) + trainingClasses = extractColumnWithClass( + dbTable, + columnsDescription=trainingTableDescription["cols"], + columnWithClass=columnWithClass, + ) else: # FIXME: magic num? trainingClasses = extractNthColumn(dbTable, 0) @@ -306,14 +313,18 @@ def main(): dbTable = grass.db_select(table=mapName) else: # assuming that columns concatenated by comma - sql = 'SELECT %s,%s FROM %s' % ('cat', columns, mapName) + sql = "SELECT {},{} FROM {}".format("cat", columns, mapName) dbTable = grass.db_select(sql=sql) - parameters = fromDbTableToSimpleTable(dbTable, - columnsDescription=tableDescription['cols'], - columnWithClass=columnWithClass) + parameters = fromDbTableToSimpleTable( + dbTable, + columnsDescription=tableDescription["cols"], + columnWithClass=columnWithClass, + ) if useAllColumns: - cats = extractColumnWithCats(dbTable, columnsDescription=tableDescription['cols']) + cats = extractColumnWithCats( + dbTable, columnsDescription=tableDescription["cols"] + ) else: cats = extractNthColumn(dbTable, 0) @@ -327,7 +338,7 @@ def main(): # add column only if not exists and the classification was successful if not hasColumn(tableDescription, columnWithClass): - addColumn(mapName, columnWithClass, 'int') + addColumn(mapName, columnWithClass, "int") updateColumn(mapName, columnWithClass, cats, classes) diff --git a/src/plugins/grass/scripts/v.out.ogr.pg.py b/src/plugins/grass/scripts/v.out.ogr.pg.py index 69da2bcd0cd0..47340cc1b517 100644 --- a/src/plugins/grass/scripts/v.out.ogr.pg.py +++ b/src/plugins/grass/scripts/v.out.ogr.pg.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- """ *************************************************************************** @@ -18,9 +17,9 @@ *************************************************************************** """ -__author__ = 'Radim Blazek' -__date__ = 'July 2009' -__copyright__ = '(C) 2009, Radim Blazek' +__author__ = "Radim Blazek" +__date__ = "July 2009" +__copyright__ = "(C) 2009, Radim Blazek" ############################################################################ @@ -30,69 +29,69 @@ # ############################################################################# -#%Module -#% description: Export vector to PostGIS (PostgreSQL) database table. -#% keywords: vector, export, database -#%End - -#%option -#% key: input -#% type: string -#% gisprompt: old,vector,vector -#% key_desc : name -#% description: Name of input vector map -#% required : yes -#%end - -#%option -#% key: layer -#% type: integer -#% description: Number of input layer -#% answer: 1 -#% required : yes -#%end - -#%option -#% key: type -#% type: string -#% description: Feature type(s) -#% options: point,kernel,centroid,line,boundary,area,face -#% multiple: yes -#% required : yes -#%end - -#%option -#% key: olayer -#% type: string -#% description: Name of output database table -#% required : yes -#%end - -#%option -#% key: host -#% type: string -#% label: Host -#% description: Host name of the machine on which the server is running. -#% required : no -#%end - -#%option -#% key: port -#% type: integer -#% label: Port -#% description: TCP port on which the server is listening, usually 5432. -#% required : no -#%end - -#%option -#% key: database -#% type: string -#% key_desc : name -#% gisprompt: old_dbname,dbname,dbname -#% label: Database -#% description: Database name -#% required : yes -#%end +# %Module +# % description: Export vector to PostGIS (PostgreSQL) database table. +# % keywords: vector, export, database +# %End + +# %option +# % key: input +# % type: string +# % gisprompt: old,vector,vector +# % key_desc : name +# % description: Name of input vector map +# % required : yes +# %end + +# %option +# % key: layer +# % type: integer +# % description: Number of input layer +# % answer: 1 +# % required : yes +# %end + +# %option +# % key: type +# % type: string +# % description: Feature type(s) +# % options: point,kernel,centroid,line,boundary,area,face +# % multiple: yes +# % required : yes +# %end + +# %option +# % key: olayer +# % type: string +# % description: Name of output database table +# % required : yes +# %end + +# %option +# % key: host +# % type: string +# % label: Host +# % description: Host name of the machine on which the server is running. +# % required : no +# %end + +# %option +# % key: port +# % type: integer +# % label: Port +# % description: TCP port on which the server is listening, usually 5432. +# % required : no +# %end + +# %option +# % key: database +# % type: string +# % key_desc : name +# % gisprompt: old_dbname,dbname,dbname +# % label: Database +# % description: Database name +# % required : yes +# %end # AFAIK scheme is not supported well by OGR ##%option @@ -103,46 +102,48 @@ ##% required : no ##%end -#%option -#% key: user -#% type: string -#% label: User -#% description: Connect to the database as the user username instead of the default. -#% required : no -#%end - -#%option -#% key: password -#% type: string -#% label: Password -#% description: Password will be stored in file! -#% required : no -#%end - -#%flag -#% key: c -#% description: to export features with category (labeled) only. Otherwise all features are exported -#%end +# %option +# % key: user +# % type: string +# % label: User +# % description: Connect to the database as the user username instead of the default. +# % required : no +# %end + +# %option +# % key: password +# % type: string +# % label: Password +# % description: Password will be stored in file! +# % required : no +# %end + +# %flag +# % key: c +# % description: to export features with category (labeled) only. Otherwise all features are exported +# %end try: from grass.script import core as grass except ImportError: import grass except: - raise Exception("Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4") + raise Exception( + "Cannot find 'grass' Python module. Python is supported by GRASS from version >= 6.4" + ) def main(): - input = options['input'] - layer = options['layer'] - type = options['type'] - olayer = options['olayer'] - host = options['host'] - port = options['port'] - database = options['database'] + input = options["input"] + layer = options["layer"] + type = options["type"] + olayer = options["olayer"] + host = options["host"] + port = options["port"] + database = options["database"] # schema = options['schema'] - user = options['user'] - password = options['password'] + user = options["user"] + password = options["password"] # Construct dsn string dsn = "PG:dbname=" + database @@ -155,11 +156,23 @@ def main(): if password: dsn += " password=" + password - if grass.run_command('v.out.ogr', flags=flags_string, input=input, layer=layer, type=type, format="PostgreSQL", dsn=dsn, olayer=olayer) != 0: + if ( + grass.run_command( + "v.out.ogr", + flags=flags_string, + input=input, + layer=layer, + type=type, + format="PostgreSQL", + dsn=dsn, + olayer=olayer, + ) + != 0 + ): grass.fatal("Cannot export vector to database.") if __name__ == "__main__": options, flags = grass.parser() - flags_string = "".join([k for k in flags.keys() if flags[k] and k != 'r']) + flags_string = "".join([k for k in flags.keys() if flags[k] and k != "r"]) main() diff --git a/tests/code_layout/acceptable_missing_doc.py b/tests/code_layout/acceptable_missing_doc.py index c4c96cdae63d..58537a4c59bb 100644 --- a/tests/code_layout/acceptable_missing_doc.py +++ b/tests/code_layout/acceptable_missing_doc.py @@ -15,407 +15,2125 @@ *************************************************************************** """ -__author__ = 'Stéphane Brunner' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Stéphane Brunner' +__author__ = "Stéphane Brunner" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Stéphane Brunner" # -*- coding: utf-8 -*- """ The list of acceptable documentation missing """ -__author__ = 'Stéphane Brunner' -__date__ = '18/03/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' +__author__ = "Stéphane Brunner" +__date__ = "18/03/2016" +__copyright__ = "Copyright 2016, The QGIS Project" ACCEPTABLE_MISSING_DOCS = { - "QgsGeometryLineIntersectionCheck": ["QgsGeometryLineIntersectionCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "factoryDescription()", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"], - "QgsRangeConfigDlg": ["rangeWidgetChanged(int index)", "QgsRangeConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent)"], - "QgsFeatureListViewDelegate": ["setEditSelectionModel(QItemSelectionModel *editSelectionModel)", "positionToElement(QPoint pos)", "editButtonClicked(QModelIndex &index)", "setFeatureSelectionModel(QgsFeatureSelectionModel *featureSelectionModel)", "Element", "QgsFeatureListViewDelegate(QgsFeatureListModel *listModel, QObject *parent=nullptr)", "setCurrentFeatureEdited(bool state)"], - "QgsPenStyleComboBox": ["iconForPen(Qt::PenStyle style)", "QgsPenStyleComboBox(QWidget *parent=nullptr)", "penStyle() const", "setPenStyle(Qt::PenStyle style)"], - "QgsRelationReferenceFactory": ["QgsRelationReferenceFactory(const QString &name, QgsMapCanvas *canvas, QgsMessageBar *messageBar)"], - "QgsVectorLayerSelectionManager": ["QgsVectorLayerSelectionManager(QgsVectorLayer *layer, QObject *parent=nullptr)"], - "QgsAuthMethodConfig": ["setMethod(const QString &method)", "setUri(const QString &uri)"], + "QgsGeometryLineIntersectionCheck": [ + "QgsGeometryLineIntersectionCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", + "factoryDescription()", + "ResolutionMethod", + "factoryCompatibleGeometryTypes()", + "factoryCheckType()", + "factoryIsCompatible(QgsVectorLayer *layer)", + "factoryId()", + ], + "QgsRangeConfigDlg": [ + "rangeWidgetChanged(int index)", + "QgsRangeConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent)", + ], + "QgsFeatureListViewDelegate": [ + "setEditSelectionModel(QItemSelectionModel *editSelectionModel)", + "positionToElement(QPoint pos)", + "editButtonClicked(QModelIndex &index)", + "setFeatureSelectionModel(QgsFeatureSelectionModel *featureSelectionModel)", + "Element", + "QgsFeatureListViewDelegate(QgsFeatureListModel *listModel, QObject *parent=nullptr)", + "setCurrentFeatureEdited(bool state)", + ], + "QgsPenStyleComboBox": [ + "iconForPen(Qt::PenStyle style)", + "QgsPenStyleComboBox(QWidget *parent=nullptr)", + "penStyle() const", + "setPenStyle(Qt::PenStyle style)", + ], + "QgsRelationReferenceFactory": [ + "QgsRelationReferenceFactory(const QString &name, QgsMapCanvas *canvas, QgsMessageBar *messageBar)" + ], + "QgsVectorLayerSelectionManager": [ + "QgsVectorLayerSelectionManager(QgsVectorLayer *layer, QObject *parent=nullptr)" + ], + "QgsAuthMethodConfig": [ + "setMethod(const QString &method)", + "setUri(const QString &uri)", + ], "QgsRuleBasedLabeling": ["rootRule()", "rootRule() const"], "QgsDrawSourceWidget": ["QgsDrawSourceWidget(QWidget *parent=nullptr)", "create()"], "QgsLegendSymbolItem": ["QgsLegendSymbolItem(const QgsLegendSymbolItem &other)"], - "QgsMeshDatasetGroupProxyModel": ["QgsMeshDatasetGroupProxyModel(QAbstractItemModel *sourceModel)"], - "QgsStyleManagerDialog": ["editColorRamp()", "currentItemType()", "editSymbol()", "currentItemName()"], + "QgsMeshDatasetGroupProxyModel": [ + "QgsMeshDatasetGroupProxyModel(QAbstractItemModel *sourceModel)" + ], + "QgsStyleManagerDialog": [ + "editColorRamp()", + "currentItemType()", + "editSymbol()", + "currentItemName()", + ], "QgsDirectoryItem": ["directoryChanged()"], - "QgsSymbolLayer": ["drawPreviewIcon(QgsSymbolRenderContext &context, QSize size)=0", "setMapUnitScale(const QgsMapUnitScale &scale)", "type() const", "mapUnitScale() const", "ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const"], - "QgsGraduatedSymbolRenderer": ["sortByLabel(Qt::SortOrder order=Qt::AscendingOrder)", "deleteAllClasses()", "updateRangeLabel(int rangeIndex, const QString &label)", "updateRangeLowerValue(int rangeIndex, double value)", "updateRangeSymbol(int rangeIndex, QgsSymbol *symbol)", "updateRangeUpperValue(int rangeIndex, double value)", "sortByValue(Qt::SortOrder order=Qt::AscendingOrder)", "addClass(QgsSymbol *symbol)", "updateRangeRenderState(int rangeIndex, bool render)", "QgsGraduatedSymbolRenderer(const QString &attrName=QString(), const QgsRangeList &ranges=QgsRangeList())", "deleteClass(int idx)"], - "QgsGeometryAngleCheck": ["factoryDescription()", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()", "QgsGeometryAngleCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)"], - "QgsMapRendererSequentialJob": ["internalFinished()", "QgsMapRendererSequentialJob(const QgsMapSettings &settings)"], - "QgsLayerTreeRegistryBridge": ["groupWillRemoveChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)", "layersWillBeRemoved(const QStringList &layerIds)", "layersAdded(const QList< QgsMapLayer * > &layers)", "groupRemovedChildren()", "setNewLayersVisible(bool enabled)", "isEnabled() const", "removeLayersFromRegistry(const QStringList &layerIds)", "setEnabled(bool enabled)", "newLayersVisible() const"], - "QgsDirectoryParamWidget": ["showHideColumn()", "QgsDirectoryParamWidget(const QString &path, QWidget *parent=nullptr)"], - "QgsDiagramRenderer": ["diagram() const", "QgsDiagramRenderer(const QgsDiagramRenderer &other)", "rendererName() const =0", "setDiagram(QgsDiagram *d)"], - "QgsVectorLayer": ["vectorJoins() const", "setDiagramLayerSettings(const QgsDiagramLayerSettings &s)", "diagramLayerSettings() const", "diagramRenderer() const"], - "QgsRelationReferenceConfigDlg": ["QgsRelationReferenceConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent)"], - "QgsDial": ["setMaximum(const QVariant &max)", "setSingleStep(const QVariant &step)", "setValue(const QVariant &value)", "variantValue() const", "valueChanged(const QVariant &)", "setMinimum(const QVariant &min)"], - "QgsHillshadeFilter": ["lightAzimuth() const", "setLightAngle(float angle)", "QgsHillshadeFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat, double lightAzimuth=300, double lightAngle=40)", "lightAngle() const", "setLightAzimuth(float azimuth)"], - "QgsClipToMinMaxEnhancement": ["QgsClipToMinMaxEnhancement(Qgis::DataType, double, double)"], - "QgsRenderChecker": ["setElapsedTimeTarget(int target)", "setControlPathSuffix(const QString &name)", "setMapSettings(const QgsMapSettings &mapSettings)"], - "QgsDateTimeEditConfig": ["QgsDateTimeEditConfig(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)"], - "QgsGeometryDuplicateCheck": ["factoryDescription()", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()", "QgsGeometryDuplicateCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)"], - "QgsVectorLayerRenderer": ["QgsVectorLayerRenderer(QgsVectorLayer *layer, QgsRenderContext &context)"], - "QgsGeometrySliverPolygonCheck": ["QgsGeometrySliverPolygonCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "factoryId()", "factoryDescription()"], - "QgsRendererRange": ["QgsRendererRange(const QgsRendererRange &range)", "operator<(const QgsRendererRange &other) const", "swap(QgsRendererRange &other)"], + "QgsSymbolLayer": [ + "drawPreviewIcon(QgsSymbolRenderContext &context, QSize size)=0", + "setMapUnitScale(const QgsMapUnitScale &scale)", + "type() const", + "mapUnitScale() const", + "ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const", + ], + "QgsGraduatedSymbolRenderer": [ + "sortByLabel(Qt::SortOrder order=Qt::AscendingOrder)", + "deleteAllClasses()", + "updateRangeLabel(int rangeIndex, const QString &label)", + "updateRangeLowerValue(int rangeIndex, double value)", + "updateRangeSymbol(int rangeIndex, QgsSymbol *symbol)", + "updateRangeUpperValue(int rangeIndex, double value)", + "sortByValue(Qt::SortOrder order=Qt::AscendingOrder)", + "addClass(QgsSymbol *symbol)", + "updateRangeRenderState(int rangeIndex, bool render)", + "QgsGraduatedSymbolRenderer(const QString &attrName=QString(), const QgsRangeList &ranges=QgsRangeList())", + "deleteClass(int idx)", + ], + "QgsGeometryAngleCheck": [ + "factoryDescription()", + "ResolutionMethod", + "factoryCompatibleGeometryTypes()", + "factoryCheckType()", + "factoryIsCompatible(QgsVectorLayer *layer)", + "factoryId()", + "QgsGeometryAngleCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", + ], + "QgsMapRendererSequentialJob": [ + "internalFinished()", + "QgsMapRendererSequentialJob(const QgsMapSettings &settings)", + ], + "QgsLayerTreeRegistryBridge": [ + "groupWillRemoveChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)", + "layersWillBeRemoved(const QStringList &layerIds)", + "layersAdded(const QList< QgsMapLayer * > &layers)", + "groupRemovedChildren()", + "setNewLayersVisible(bool enabled)", + "isEnabled() const", + "removeLayersFromRegistry(const QStringList &layerIds)", + "setEnabled(bool enabled)", + "newLayersVisible() const", + ], + "QgsDirectoryParamWidget": [ + "showHideColumn()", + "QgsDirectoryParamWidget(const QString &path, QWidget *parent=nullptr)", + ], + "QgsDiagramRenderer": [ + "diagram() const", + "QgsDiagramRenderer(const QgsDiagramRenderer &other)", + "rendererName() const =0", + "setDiagram(QgsDiagram *d)", + ], + "QgsVectorLayer": [ + "vectorJoins() const", + "setDiagramLayerSettings(const QgsDiagramLayerSettings &s)", + "diagramLayerSettings() const", + "diagramRenderer() const", + ], + "QgsRelationReferenceConfigDlg": [ + "QgsRelationReferenceConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent)" + ], + "QgsDial": [ + "setMaximum(const QVariant &max)", + "setSingleStep(const QVariant &step)", + "setValue(const QVariant &value)", + "variantValue() const", + "valueChanged(const QVariant &)", + "setMinimum(const QVariant &min)", + ], + "QgsHillshadeFilter": [ + "lightAzimuth() const", + "setLightAngle(float angle)", + "QgsHillshadeFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat, double lightAzimuth=300, double lightAngle=40)", + "lightAngle() const", + "setLightAzimuth(float azimuth)", + ], + "QgsClipToMinMaxEnhancement": [ + "QgsClipToMinMaxEnhancement(Qgis::DataType, double, double)" + ], + "QgsRenderChecker": [ + "setElapsedTimeTarget(int target)", + "setControlPathSuffix(const QString &name)", + "setMapSettings(const QgsMapSettings &mapSettings)", + ], + "QgsDateTimeEditConfig": [ + "QgsDateTimeEditConfig(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)" + ], + "QgsGeometryDuplicateCheck": [ + "factoryDescription()", + "ResolutionMethod", + "factoryCompatibleGeometryTypes()", + "factoryCheckType()", + "factoryIsCompatible(QgsVectorLayer *layer)", + "factoryId()", + "QgsGeometryDuplicateCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", + ], + "QgsVectorLayerRenderer": [ + "QgsVectorLayerRenderer(QgsVectorLayer *layer, QgsRenderContext &context)" + ], + "QgsGeometrySliverPolygonCheck": [ + "QgsGeometrySliverPolygonCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", + "factoryId()", + "factoryDescription()", + ], + "QgsRendererRange": [ + "QgsRendererRange(const QgsRendererRange &range)", + "operator<(const QgsRendererRange &other) const", + "swap(QgsRendererRange &other)", + ], "QgsRasterMinMaxWidget": ["setBands(const QList< int > &bands)"], - "QgsDataDefinedWidthDialog": ["QgsDataDefinedWidthDialog(const QList< QgsSymbol * > &symbolList, QgsVectorLayer *layer)"], - "QgsVectorLayerEditBuffer": ["attributeDeleted(int idx)", "committedFeaturesRemoved(const QString &layerId, const QgsFeatureIds &deletedFeatureIds)", "updateLayerFields()", "committedAttributesAdded(const QString &layerId, const QList< QgsField > &addedAttributes)", "QgsVectorLayerEditBuffer(QgsVectorLayer *layer)", "attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &)", "undoIndexChanged(int index)", "committedGeometriesChanges(const QString &layerId, const QgsGeometryMap &changedGeometries)", "committedFeaturesAdded(const QString &layerId, const QgsFeatureList &addedFeatures)", "featureAdded(QgsFeatureId fid)", "committedAttributeValuesChanges(const QString &layerId, const QgsChangedAttributesMap &changedAttributesValues)", "attributeAdded(int idx)", "featureDeleted(QgsFeatureId fid)"], - "QgsLinearMinMaxEnhancement": ["QgsLinearMinMaxEnhancement(Qgis::DataType, double, double)"], + "QgsDataDefinedWidthDialog": [ + "QgsDataDefinedWidthDialog(const QList< QgsSymbol * > &symbolList, QgsVectorLayer *layer)" + ], + "QgsVectorLayerEditBuffer": [ + "attributeDeleted(int idx)", + "committedFeaturesRemoved(const QString &layerId, const QgsFeatureIds &deletedFeatureIds)", + "updateLayerFields()", + "committedAttributesAdded(const QString &layerId, const QList< QgsField > &addedAttributes)", + "QgsVectorLayerEditBuffer(QgsVectorLayer *layer)", + "attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &)", + "undoIndexChanged(int index)", + "committedGeometriesChanges(const QString &layerId, const QgsGeometryMap &changedGeometries)", + "committedFeaturesAdded(const QString &layerId, const QgsFeatureList &addedFeatures)", + "featureAdded(QgsFeatureId fid)", + "committedAttributeValuesChanges(const QString &layerId, const QgsChangedAttributesMap &changedAttributesValues)", + "attributeAdded(int idx)", + "featureDeleted(QgsFeatureId fid)", + ], + "QgsLinearMinMaxEnhancement": [ + "QgsLinearMinMaxEnhancement(Qgis::DataType, double, double)" + ], "QgsVectorLayerEditUtils": ["QgsVectorLayerEditUtils(QgsVectorLayer *layer)"], - "QgsPointLocator_VisitorNearestEdge": ["QgsPointLocator_VisitorNearestEdge(QgsPointLocator *pl, QgsPointLocator::Match &m, const QgsPointXY &srcPoint, QgsPointLocator::MatchFilter *filter=nullptr)"], - "QgsFieldCalculator": ["QgsFieldCalculator(QgsVectorLayer *vl, QWidget *parent=nullptr)"], - "QgsLayerTreeGroup": ["QgsLayerTreeGroup(const QgsLayerTreeGroup &other)", "nodeVisibilityChanged(QgsLayerTreeNode *node)"], - "QgsLongLongValidator": ["QgsLongLongValidator(qint64 bottom, qint64 top, QObject *parent)", "setRange(qint64 bottom, qint64 top)", "setBottom(qint64 bottom)", "setTop(qint64 top)", "QgsLongLongValidator(QObject *parent)", "bottom() const", "top() const"], + "QgsPointLocator_VisitorNearestEdge": [ + "QgsPointLocator_VisitorNearestEdge(QgsPointLocator *pl, QgsPointLocator::Match &m, const QgsPointXY &srcPoint, QgsPointLocator::MatchFilter *filter=nullptr)" + ], + "QgsFieldCalculator": [ + "QgsFieldCalculator(QgsVectorLayer *vl, QWidget *parent=nullptr)" + ], + "QgsLayerTreeGroup": [ + "QgsLayerTreeGroup(const QgsLayerTreeGroup &other)", + "nodeVisibilityChanged(QgsLayerTreeNode *node)", + ], + "QgsLongLongValidator": [ + "QgsLongLongValidator(qint64 bottom, qint64 top, QObject *parent)", + "setRange(qint64 bottom, qint64 top)", + "setBottom(qint64 bottom)", + "setTop(qint64 top)", + "QgsLongLongValidator(QObject *parent)", + "bottom() const", + "top() const", + ], "QgsScopeLogger": ["QgsScopeLogger(const char *file, const char *func, int line)"], - "QgsPythonRunner": ["evalCommand(QString command, QString &result)=0", "runCommand(QString command, QString messageOnError=QString())=0"], - "QgsAttributeActionDialog": ["init(const QgsActionManager &action, const QgsAttributeTableConfig &attributeTableConfig)", "QgsAttributeActionDialog(const QgsActionManager &actions, QWidget *parent=nullptr)", "attributeTableWidgetStyle() const", "actions() const", "showWidgetInAttributeTable() const"], - "QgsRasterRendererWidget": ["setStdDev(const QString &value)", "setMin(const QString &value, int index=0)", "max(int index=0)", "stdDev()", "selectedBand(int index=0)", "QgsRasterRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent)", "min(int index=0)", "setMax(const QString &value, int index=0)"], - "QgsRasterDataProvider": ["colorTable(int bandNo) const", "setUserNoDataValue(int bandNo, const QgsRasterRangeList &noData)"], - "QgsHueSaturationFilter": ["colorizeStrength() const", "setColorizeStrength(int colorizeStrength)", "QgsHueSaturationFilter(QgsRasterInterface *input=nullptr)", "colorizeColor() const", "setColorizeOn(bool colorizeOn)", "setSaturation(int saturation)", "GrayscaleMode", "grayscaleMode() const", "setGrayscaleMode(QgsHueSaturationFilter::GrayscaleMode grayscaleMode)", "setColorizeColor(const QColor &colorizeColor)", "colorizeOn() const", "saturation() const"], + "QgsPythonRunner": [ + "evalCommand(QString command, QString &result)=0", + "runCommand(QString command, QString messageOnError=QString())=0", + ], + "QgsAttributeActionDialog": [ + "init(const QgsActionManager &action, const QgsAttributeTableConfig &attributeTableConfig)", + "QgsAttributeActionDialog(const QgsActionManager &actions, QWidget *parent=nullptr)", + "attributeTableWidgetStyle() const", + "actions() const", + "showWidgetInAttributeTable() const", + ], + "QgsRasterRendererWidget": [ + "setStdDev(const QString &value)", + "setMin(const QString &value, int index=0)", + "max(int index=0)", + "stdDev()", + "selectedBand(int index=0)", + "QgsRasterRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent)", + "min(int index=0)", + "setMax(const QString &value, int index=0)", + ], + "QgsRasterDataProvider": [ + "colorTable(int bandNo) const", + "setUserNoDataValue(int bandNo, const QgsRasterRangeList &noData)", + ], + "QgsHueSaturationFilter": [ + "colorizeStrength() const", + "setColorizeStrength(int colorizeStrength)", + "QgsHueSaturationFilter(QgsRasterInterface *input=nullptr)", + "colorizeColor() const", + "setColorizeOn(bool colorizeOn)", + "setSaturation(int saturation)", + "GrayscaleMode", + "grayscaleMode() const", + "setGrayscaleMode(QgsHueSaturationFilter::GrayscaleMode grayscaleMode)", + "setColorizeColor(const QColor &colorizeColor)", + "colorizeOn() const", + "saturation() const", + ], "QgsSymbolLevelItem": ["QgsSymbolLevelItem(QgsSymbol *symbol, int layer)"], "QgsCredentials": ["getMasterPassword(QString &password, bool stored=false)"], - "QgsDataDefinedRotationDialog": ["QgsDataDefinedRotationDialog(const QList< QgsSymbol * > &symbolList, QgsVectorLayer *layer)"], - "QgsCptCityColorRamp": ["loadFile()", "setSchemeName(const QString &schemeName)", "variantName() const", "copyingInfo() const", "setName(const QString &schemeName, const QString &variantName=QString(), const QStringList &variantList=QStringList())", "setVariantName(const QString &variantName)", "variantList() const", "setVariantList(const QStringList &variantList)", "cloneGradientRamp() const", "loadPalette()", "hasMultiStops() const", "schemeName() const", "fileName() const", "copyingFileName() const", "fileLoaded() const", "descFileName() const", "copy(const QgsCptCityColorRamp *other)"], - "QgsMapToolIdentifyFeature": ["featureIdentified(QgsFeatureId)", "featureIdentified(const QgsFeature &)"], - "QgsGroupBoxCollapseButton": ["QgsGroupBoxCollapseButton(QWidget *parent=nullptr)", "setAltDown(bool updown)", "setShiftDown(bool shiftdown)", "shiftDown() const", "altDown() const"], + "QgsDataDefinedRotationDialog": [ + "QgsDataDefinedRotationDialog(const QList< QgsSymbol * > &symbolList, QgsVectorLayer *layer)" + ], + "QgsCptCityColorRamp": [ + "loadFile()", + "setSchemeName(const QString &schemeName)", + "variantName() const", + "copyingInfo() const", + "setName(const QString &schemeName, const QString &variantName=QString(), const QStringList &variantList=QStringList())", + "setVariantName(const QString &variantName)", + "variantList() const", + "setVariantList(const QStringList &variantList)", + "cloneGradientRamp() const", + "loadPalette()", + "hasMultiStops() const", + "schemeName() const", + "fileName() const", + "copyingFileName() const", + "fileLoaded() const", + "descFileName() const", + "copy(const QgsCptCityColorRamp *other)", + ], + "QgsMapToolIdentifyFeature": [ + "featureIdentified(QgsFeatureId)", + "featureIdentified(const QgsFeature &)", + ], + "QgsGroupBoxCollapseButton": [ + "QgsGroupBoxCollapseButton(QWidget *parent=nullptr)", + "setAltDown(bool updown)", + "setShiftDown(bool shiftdown)", + "shiftDown() const", + "altDown() const", + ], "QgsGlowWidget": ["QgsGlowWidget(QWidget *parent=nullptr)", "create()"], - "QgsRuggednessFilter": ["QgsRuggednessFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)"], + "QgsRuggednessFilter": [ + "QgsRuggednessFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)" + ], "QgsIFeatureSelectionManager": ["QgsIFeatureSelectionManager(QObject *parent)"], - "QgsGraduatedSymbolRendererWidget": ["classifyGraduated()", "updateUiFromRenderer(bool updateCount=true)", "QgsGraduatedSymbolRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", "connectUpdateHandlers()", "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", "reapplySizes()", "rangesDoubleClicked(const QModelIndex &idx)", "changeRange(int rangeIdx)", "changeCurrentValue(QStandardItem *item)", "showSymbolLevels()", "changeSelectedSymbols()", "selectedRanges()", "reapplyColorRamp()", "disconnectUpdateHandlers()", "rowsOrdered()", "modelDataChanged()", "graduatedColumnChanged(const QString &field)", "rowsMoved()", "findSymbolForRange(double lowerBound, double upperBound, const QgsRangeList &ranges) const", "labelFormatChanged()", "changeRangeSymbol(int rangeIdx)", "rangesClicked(const QModelIndex &idx)"], + "QgsGraduatedSymbolRendererWidget": [ + "classifyGraduated()", + "updateUiFromRenderer(bool updateCount=true)", + "QgsGraduatedSymbolRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", + "connectUpdateHandlers()", + "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", + "reapplySizes()", + "rangesDoubleClicked(const QModelIndex &idx)", + "changeRange(int rangeIdx)", + "changeCurrentValue(QStandardItem *item)", + "showSymbolLevels()", + "changeSelectedSymbols()", + "selectedRanges()", + "reapplyColorRamp()", + "disconnectUpdateHandlers()", + "rowsOrdered()", + "modelDataChanged()", + "graduatedColumnChanged(const QString &field)", + "rowsMoved()", + "findSymbolForRange(double lowerBound, double upperBound, const QgsRangeList &ranges) const", + "labelFormatChanged()", + "changeRangeSymbol(int rangeIdx)", + "rangesClicked(const QModelIndex &idx)", + ], "QgsPointLocator": ["destroyIndex()", "rebuildIndex(int maxFeaturesToIndex=-1)"], "QgsRuleBasedRenderer": ["FeatureFlags", "rootRule()"], - "QgsSimpleFillSymbolLayerWidget": ["setColor(const QColor &color)", "setStrokeColor(const QColor &color)"], + "QgsSimpleFillSymbolLayerWidget": [ + "setColor(const QColor &color)", + "setStrokeColor(const QColor &color)", + ], "pal::Pal": ["FnIsCanceled)(void *ctx)"], "QgsColorSwatchDelegate": ["QgsColorSwatchDelegate(QWidget *parent=nullptr)"], - "QgsMeshDatasetGroupTreeItemDelegate": ["QgsMeshDatasetGroupTreeItemDelegate(QObject *parent=nullptr)"], - "QgsAspectFilter": ["QgsAspectFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)"], - "QgsRasterMatrix": ["asinus()", "setData(int cols, int rows, double *data, double nodataValue)", "power(const QgsRasterMatrix &other)", "number() const", "multiply(const QgsRasterMatrix &other)", "greaterThan(const QgsRasterMatrix &other)", "equal(const QgsRasterMatrix &other)", "greaterEqual(const QgsRasterMatrix &other)", "lesserEqual(const QgsRasterMatrix &other)", "nColumns() const", "logicalOr(const QgsRasterMatrix &other)", "QgsRasterMatrix(const QgsRasterMatrix &m)", "log10()", "tangens()", "divide(const QgsRasterMatrix &other)", "logicalAnd(const QgsRasterMatrix &other)", "sinus()", "squareRoot()", "changeSign()", "nRows() const", "cosinus()", "atangens()", "acosinus()", "lesserThan(const QgsRasterMatrix &other)", "OneArgOperator", "TwoArgOperator", "setNodataValue(double d)", "notEqual(const QgsRasterMatrix &other)", "nodataValue() const", "log()"], - "QgsVectorFileWriter::Option": ["Option(const QString &docString, QgsVectorFileWriter::OptionType type)"], - "QgsErrorMessage": ["file() const", "message() const", "function() const", "line() const", "tag() const"], - "QgsTextEditConfigDlg": ["QgsTextEditConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)"], - "QgsMarkerLineSymbolLayerWidget": ["setInterval(double val)", "setOffsetAlongLine(double val)"], - "QgsNineCellFilter": ["setCellSizeY(double size)", "setZFactor(double factor)", "outputNodataValue() const", "setCellSizeX(double size)", "setInputNodataValue(double value)", "cellSizeY() const", "cellSizeX() const", "setOutputNodataValue(double value)", "inputNodataValue() const", "zFactor() const"], - "QgsIdentifyMenu": ["showFeatureActions()", "maxFeatureDisplay()", "execWithSingleResult()", "allowMultipleReturn()", "maxLayerDisplay()", "resultsIfExternalAction()", "MenuLevel"], - "QgsRuleBasedRendererModel": ["finishedAddingRules()", "updateRule(const QModelIndex &index)", "willAddRules(const QModelIndex &parent, int count)", "clearFeatureCounts()", "insertRule(const QModelIndex &parent, int before, QgsRuleBasedRenderer::Rule *newrule)", "removeRule(const QModelIndex &index)", "updateRule(const QModelIndex &parent, int row)", "ruleForIndex(const QModelIndex &index) const"], + "QgsMeshDatasetGroupTreeItemDelegate": [ + "QgsMeshDatasetGroupTreeItemDelegate(QObject *parent=nullptr)" + ], + "QgsAspectFilter": [ + "QgsAspectFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)" + ], + "QgsRasterMatrix": [ + "asinus()", + "setData(int cols, int rows, double *data, double nodataValue)", + "power(const QgsRasterMatrix &other)", + "number() const", + "multiply(const QgsRasterMatrix &other)", + "greaterThan(const QgsRasterMatrix &other)", + "equal(const QgsRasterMatrix &other)", + "greaterEqual(const QgsRasterMatrix &other)", + "lesserEqual(const QgsRasterMatrix &other)", + "nColumns() const", + "logicalOr(const QgsRasterMatrix &other)", + "QgsRasterMatrix(const QgsRasterMatrix &m)", + "log10()", + "tangens()", + "divide(const QgsRasterMatrix &other)", + "logicalAnd(const QgsRasterMatrix &other)", + "sinus()", + "squareRoot()", + "changeSign()", + "nRows() const", + "cosinus()", + "atangens()", + "acosinus()", + "lesserThan(const QgsRasterMatrix &other)", + "OneArgOperator", + "TwoArgOperator", + "setNodataValue(double d)", + "notEqual(const QgsRasterMatrix &other)", + "nodataValue() const", + "log()", + ], + "QgsVectorFileWriter::Option": [ + "Option(const QString &docString, QgsVectorFileWriter::OptionType type)" + ], + "QgsErrorMessage": [ + "file() const", + "message() const", + "function() const", + "line() const", + "tag() const", + ], + "QgsTextEditConfigDlg": [ + "QgsTextEditConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)" + ], + "QgsMarkerLineSymbolLayerWidget": [ + "setInterval(double val)", + "setOffsetAlongLine(double val)", + ], + "QgsNineCellFilter": [ + "setCellSizeY(double size)", + "setZFactor(double factor)", + "outputNodataValue() const", + "setCellSizeX(double size)", + "setInputNodataValue(double value)", + "cellSizeY() const", + "cellSizeX() const", + "setOutputNodataValue(double value)", + "inputNodataValue() const", + "zFactor() const", + ], + "QgsIdentifyMenu": [ + "showFeatureActions()", + "maxFeatureDisplay()", + "execWithSingleResult()", + "allowMultipleReturn()", + "maxLayerDisplay()", + "resultsIfExternalAction()", + "MenuLevel", + ], + "QgsRuleBasedRendererModel": [ + "finishedAddingRules()", + "updateRule(const QModelIndex &index)", + "willAddRules(const QModelIndex &parent, int count)", + "clearFeatureCounts()", + "insertRule(const QModelIndex &parent, int before, QgsRuleBasedRenderer::Rule *newrule)", + "removeRule(const QModelIndex &index)", + "updateRule(const QModelIndex &parent, int row)", + "ruleForIndex(const QModelIndex &index) const", + ], "QgsSymbolLevelsDialog": ["setForceOrderingEnabled(bool enabled)"], - "QgsSimpleMarkerSymbolLayerWidget": ["setColorStroke(const QColor &color)", "setColorFill(const QColor &color)"], + "QgsSimpleMarkerSymbolLayerWidget": [ + "setColorStroke(const QColor &color)", + "setColorFill(const QColor &color)", + ], "QgsActionMenu": ["reinit()"], "QgsFieldComboBox": ["indexChanged(int i)"], "QgsPaintEffect": ["QgsPaintEffect(const QgsPaintEffect &other)"], - "QgsMeshDatasetGroupTreeModel": ["Roles", "QgsMeshDatasetGroupTreeModel(QObject *parent=nullptr)"], + "QgsMeshDatasetGroupTreeModel": [ + "Roles", + "QgsMeshDatasetGroupTreeModel(QObject *parent=nullptr)", + ], "QgsPaintEngineHack": ["fixFlags()", "fixEngineFlags(QPaintEngine *engine)"], "QgsHeatmapRenderer": ["convertFromRenderer(const QgsFeatureRenderer *renderer)"], - "QgsShadowEffectWidget": ["QgsShadowEffectWidget(QWidget *parent=nullptr)", "create()"], - "QgsCentroidFillSymbolLayer": ["createFromSld(QDomElement &element)", "setPointOnSurface(bool pointOnSurface)", "pointOnSurface() const"], + "QgsShadowEffectWidget": [ + "QgsShadowEffectWidget(QWidget *parent=nullptr)", + "create()", + ], + "QgsCentroidFillSymbolLayer": [ + "createFromSld(QDomElement &element)", + "setPointOnSurface(bool pointOnSurface)", + "pointOnSurface() const", + ], "QgsPluginLayerType": ["QgsPluginLayerType(const QString &name)", "name() const"], - "QgsConditionalStyle": ["QgsConditionalStyle(const QString &rule)", "QgsConditionalStyle(const QgsConditionalStyle &other)"], - "QgsContrastEnhancement": ["contrastEnhancementAlgorithm() const", "readXml(const QDomElement &elem)", "writeXml(QDomDocument &doc, QDomElement &parentElem) const", "QgsContrastEnhancement(const QgsContrastEnhancement &ce)"], - "QgsFontMarkerSymbolLayerWidget": ["setFontFamily(const QFont &font)", "setColor(const QColor &color)", "setAngle(double angle)", "setSize(double size)"], - "QgsBrushStyleComboBox": ["iconForBrush(Qt::BrushStyle style)", "QgsBrushStyleComboBox(QWidget *parent=nullptr)", "setBrushStyle(Qt::BrushStyle style)", "brushStyle() const"], + "QgsConditionalStyle": [ + "QgsConditionalStyle(const QString &rule)", + "QgsConditionalStyle(const QgsConditionalStyle &other)", + ], + "QgsContrastEnhancement": [ + "contrastEnhancementAlgorithm() const", + "readXml(const QDomElement &elem)", + "writeXml(QDomDocument &doc, QDomElement &parentElem) const", + "QgsContrastEnhancement(const QgsContrastEnhancement &ce)", + ], + "QgsFontMarkerSymbolLayerWidget": [ + "setFontFamily(const QFont &font)", + "setColor(const QColor &color)", + "setAngle(double angle)", + "setSize(double size)", + ], + "QgsBrushStyleComboBox": [ + "iconForBrush(Qt::BrushStyle style)", + "QgsBrushStyleComboBox(QWidget *parent=nullptr)", + "setBrushStyle(Qt::BrushStyle style)", + "brushStyle() const", + ], "QgsGlowEffect": ["QgsGlowEffect(const QgsGlowEffect &other)"], "QgsLabelCandidate": ["QgsLabelCandidate(const QRectF &r, double c)"], - "pal::LabelPosition": ["getReversed() const", "resetNumOverlaps()", "getPartId() const", "getProblemFeatureId() const", "getWidth() const", "getNumOverlaps() const", "getHeight() const", "getQuadrant() const", "setPartId(int id)", "getUpsideDown() const"], - "QgsAttributesFormProperties": ["initSuppressCombo()", "QgsAttributesFormProperties(QgsVectorLayer *layer, QWidget *parent=nullptr)", "initLayoutConfig()", "initFormLayoutTree()", "updateButtons()", "FieldPropertiesRoles", "loadRelations()", "initAvailableWidgetsTree()", "init()", "initInitPython()"], + "pal::LabelPosition": [ + "getReversed() const", + "resetNumOverlaps()", + "getPartId() const", + "getProblemFeatureId() const", + "getWidth() const", + "getNumOverlaps() const", + "getHeight() const", + "getQuadrant() const", + "setPartId(int id)", + "getUpsideDown() const", + ], + "QgsAttributesFormProperties": [ + "initSuppressCombo()", + "QgsAttributesFormProperties(QgsVectorLayer *layer, QWidget *parent=nullptr)", + "initLayoutConfig()", + "initFormLayoutTree()", + "updateButtons()", + "FieldPropertiesRoles", + "loadRelations()", + "initAvailableWidgetsTree()", + "init()", + "initInitPython()", + ], "QgsWkbException": ["QgsWkbException(QString const &what)"], - "QgsVectorFileWriter": ["driverMetadata(const QString &driverName, MetaData &driverMetadata)", "OptionType", "WriterError"], + "QgsVectorFileWriter": [ + "driverMetadata(const QString &driverName, MetaData &driverMetadata)", + "OptionType", + "WriterError", + ], "QgsBlurWidget": ["QgsBlurWidget(QWidget *parent=nullptr)", "create()"], - "QgsDataItem": ["icon()", "setIconName(const QString &iconName)", "populate(bool foreground=false)", "deleteLater(QVector< QgsDataItem * > &items)", "children() const", "hasChildren()", "beginInsertItems(QgsDataItem *parent, int first, int last)", "rowCount()", "dataChanged(QgsDataItem *item)", "type() const", "beginRemoveItems(QgsDataItem *parent, int first, int last)", "endRemoveItems()", "path() const", "endInsertItems()", "refresh()", "setIcon(const QIcon &icon)", "findItem(QVector< QgsDataItem * > items, QgsDataItem *item)", "childrenCreated()", "setPath(const QString &path)", "setToolTip(const QString &msg)", "state() const", "populate(const QVector< QgsDataItem * > &children)", "toolTip() const"], + "QgsDataItem": [ + "icon()", + "setIconName(const QString &iconName)", + "populate(bool foreground=false)", + "deleteLater(QVector< QgsDataItem * > &items)", + "children() const", + "hasChildren()", + "beginInsertItems(QgsDataItem *parent, int first, int last)", + "rowCount()", + "dataChanged(QgsDataItem *item)", + "type() const", + "beginRemoveItems(QgsDataItem *parent, int first, int last)", + "endRemoveItems()", + "path() const", + "endInsertItems()", + "refresh()", + "setIcon(const QIcon &icon)", + "findItem(QVector< QgsDataItem * > items, QgsDataItem *item)", + "childrenCreated()", + "setPath(const QString &path)", + "setToolTip(const QString &msg)", + "state() const", + "populate(const QVector< QgsDataItem * > &children)", + "toolTip() const", + ], "QgsMapCanvas": ["setCurrentLayer(QgsMapLayer *layer)"], - "QgsLayerTreeViewDefaultActions": ["actionRenameGroupOrLayer(QObject *parent=nullptr)", "actionShowInOverview(QObject *parent=nullptr)", "addGroup()", "showInOverview()", "QgsLayerTreeViewDefaultActions(QgsLayerTreeView *view)", "actionShowFeatureCount(QObject *parent=nullptr)", "uniqueGroupName(QgsLayerTreeGroup *parentGroup)", "actionGroupSelected(QObject *parent=nullptr)", "groupSelected()", "removeGroupOrLayer()", "zoomToGroup(QgsMapCanvas *canvas)", "renameGroupOrLayer()", "showFeatureCount()", "zoomToGroup()", "actionAddGroup(QObject *parent=nullptr)", "actionZoomToGroup(QgsMapCanvas *canvas, QObject *parent=nullptr)", "actionRemoveGroupOrLayer(QObject *parent=nullptr)", "zoomToLayers(QgsMapCanvas *canvas, const QList< QgsMapLayer * > &layers)"], - "QgsGeometryPointInPolygonCheck": ["factoryDescription()", "factoryIsCompatible(QgsVectorLayer *layer)", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "QgsGeometryPointInPolygonCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "factoryId()"], + "QgsLayerTreeViewDefaultActions": [ + "actionRenameGroupOrLayer(QObject *parent=nullptr)", + "actionShowInOverview(QObject *parent=nullptr)", + "addGroup()", + "showInOverview()", + "QgsLayerTreeViewDefaultActions(QgsLayerTreeView *view)", + "actionShowFeatureCount(QObject *parent=nullptr)", + "uniqueGroupName(QgsLayerTreeGroup *parentGroup)", + "actionGroupSelected(QObject *parent=nullptr)", + "groupSelected()", + "removeGroupOrLayer()", + "zoomToGroup(QgsMapCanvas *canvas)", + "renameGroupOrLayer()", + "showFeatureCount()", + "zoomToGroup()", + "actionAddGroup(QObject *parent=nullptr)", + "actionZoomToGroup(QgsMapCanvas *canvas, QObject *parent=nullptr)", + "actionRemoveGroupOrLayer(QObject *parent=nullptr)", + "zoomToLayers(QgsMapCanvas *canvas, const QList< QgsMapLayer * > &layers)", + ], + "QgsGeometryPointInPolygonCheck": [ + "factoryDescription()", + "factoryIsCompatible(QgsVectorLayer *layer)", + "ResolutionMethod", + "factoryCompatibleGeometryTypes()", + "factoryCheckType()", + "QgsGeometryPointInPolygonCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", + "factoryId()", + ], "QgsMeshRendererMeshSettingsWidget": ["MeshType"], - "QgsDummyConfigDlg": ["QgsDummyConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent, const QString &description)"], - "QgsRasterLayerSaveAsDialog": ["mode() const", "xResolution() const", "tileMode() const", "yResolution() const", "noData() const", "outputCrs()", "pyramidsConfigOptions() const", "nColumns() const", "hideFormat()", "ResolutionState", "pyramidsResamplingMethod() const", "nRows() const", "outputFormat() const", "Mode", "hideOutput()", "outputRectangle() const", "maximumTileSizeX() const", "maximumTileSizeY() const", "outputFileName() const", "createOptions() const", "CrsState", "pyramidsList() const"], - "QgsSlider": ["setMaximum(const QVariant &max)", "setSingleStep(const QVariant &step)", "setValue(const QVariant &value)", "variantValue() const", "valueChanged(const QVariant &)", "setMinimum(const QVariant &min)"], + "QgsDummyConfigDlg": [ + "QgsDummyConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent, const QString &description)" + ], + "QgsRasterLayerSaveAsDialog": [ + "mode() const", + "xResolution() const", + "tileMode() const", + "yResolution() const", + "noData() const", + "outputCrs()", + "pyramidsConfigOptions() const", + "nColumns() const", + "hideFormat()", + "ResolutionState", + "pyramidsResamplingMethod() const", + "nRows() const", + "outputFormat() const", + "Mode", + "hideOutput()", + "outputRectangle() const", + "maximumTileSizeX() const", + "maximumTileSizeY() const", + "outputFileName() const", + "createOptions() const", + "CrsState", + "pyramidsList() const", + ], + "QgsSlider": [ + "setMaximum(const QVariant &max)", + "setSingleStep(const QVariant &step)", + "setValue(const QVariant &value)", + "variantValue() const", + "valueChanged(const QVariant &)", + "setMinimum(const QVariant &min)", + ], "QgsSearchQueryBuilder": ["loadQuery()", "saveQuery()"], - "QgsGpsdConnection": ["QgsGpsdConnection(const QString &host, qint16 port, const QString &device)"], - "QgsSpatialIndexCopyVisitor": ["QgsSpatialIndexCopyVisitor(SpatialIndex::ISpatialIndex *newIndex)"], - "pal::PointSet": ["getCentroid(double &px, double &py, bool forceInside=false) const", "PointSet(double x, double y)", "invalidateGeos() const", "getGeosType() const", "PointSet(int nbPoints, double *x, double *y)", "getNumPoints() const", "deleteCoords()", "preparedGeom() const", "PointSet(const PointSet &ps)", "createGeosGeom() const"], - "QgsSimpleFillSymbolLayer": ["createFromSld(QDomElement &element)", "setBrushStyle(Qt::BrushStyle style)", "setStrokeWidth(double strokeWidth)", "strokeWidth() const", "brushStyle() const", "strokeWidthMapUnitScale() const", "strokeStyle() const", "setPenJoinStyle(Qt::PenJoinStyle style)", "QgsSimpleFillSymbolLayer(const QColor &color=DEFAULT_SIMPLEFILL_COLOR, Qt::BrushStyle style=DEFAULT_SIMPLEFILL_STYLE, const QColor &strokeColor=DEFAULT_SIMPLEFILL_BORDERCOLOR, Qt::PenStyle strokeStyle=DEFAULT_SIMPLEFILL_BORDERSTYLE, double strokeWidth=DEFAULT_SIMPLEFILL_BORDERWIDTH, Qt::PenJoinStyle penJoinStyle=DEFAULT_SIMPLEFILL_JOINSTYLE)", "setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)", "penJoinStyle() const", "setStrokeStyle(Qt::PenStyle strokeStyle)"], - "QgsSingleCategoryDiagramRenderer": ["setDiagramSettings(const QgsDiagramSettings &s)"], + "QgsGpsdConnection": [ + "QgsGpsdConnection(const QString &host, qint16 port, const QString &device)" + ], + "QgsSpatialIndexCopyVisitor": [ + "QgsSpatialIndexCopyVisitor(SpatialIndex::ISpatialIndex *newIndex)" + ], + "pal::PointSet": [ + "getCentroid(double &px, double &py, bool forceInside=false) const", + "PointSet(double x, double y)", + "invalidateGeos() const", + "getGeosType() const", + "PointSet(int nbPoints, double *x, double *y)", + "getNumPoints() const", + "deleteCoords()", + "preparedGeom() const", + "PointSet(const PointSet &ps)", + "createGeosGeom() const", + ], + "QgsSimpleFillSymbolLayer": [ + "createFromSld(QDomElement &element)", + "setBrushStyle(Qt::BrushStyle style)", + "setStrokeWidth(double strokeWidth)", + "strokeWidth() const", + "brushStyle() const", + "strokeWidthMapUnitScale() const", + "strokeStyle() const", + "setPenJoinStyle(Qt::PenJoinStyle style)", + "QgsSimpleFillSymbolLayer(const QColor &color=DEFAULT_SIMPLEFILL_COLOR, Qt::BrushStyle style=DEFAULT_SIMPLEFILL_STYLE, const QColor &strokeColor=DEFAULT_SIMPLEFILL_BORDERCOLOR, Qt::PenStyle strokeStyle=DEFAULT_SIMPLEFILL_BORDERSTYLE, double strokeWidth=DEFAULT_SIMPLEFILL_BORDERWIDTH, Qt::PenJoinStyle penJoinStyle=DEFAULT_SIMPLEFILL_JOINSTYLE)", + "setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)", + "penJoinStyle() const", + "setStrokeStyle(Qt::PenStyle strokeStyle)", + ], + "QgsSingleCategoryDiagramRenderer": [ + "setDiagramSettings(const QgsDiagramSettings &s)" + ], "QgsStackedDiagramRenderer": ["setDiagramSettings(const QgsDiagramSettings &s)"], - "QgsPointDisplacementRendererWidget": ["QgsPointDisplacementRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)"], - "QgsSingleBandGrayRendererWidget": ["create(QgsRasterLayer *layer, const QgsRectangle &extent)", "QgsSingleBandGrayRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent=QgsRectangle())"], - "QgsLayerTreeModel": ["nodeWillRemoveChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)", "disconnectFromLayers(QgsLayerTreeGroup *parentGroup)", "connectToLayers(QgsLayerTreeGroup *parentGroup)", "nodeLayerWillBeUnloaded()", "legendInvalidateMapBasedData()", "nodeCustomPropertyChanged(QgsLayerTreeNode *node, const QString &key)", "legendNodeData(QgsLayerTreeModelLegendNode *node, int role) const", "legendCleanup()", "Flag", "iconGroup()", "disconnectFromRootNode()", "layerNeedsUpdate()", "addLegendToLayer(QgsLayerTreeLayer *nodeL)", "nodeVisibilityChanged(QgsLayerTreeNode *node)", "layerLegendChanged()", "legendRootRowCount(QgsLayerTreeLayer *nL) const", "removeLegendFromLayer(QgsLayerTreeLayer *nodeLayer)", "legendNodeRowCount(QgsLayerTreeModelLegendNode *node) const", "legendNodeDataChanged()", "connectToRootNode()", "legendNodeFlags(QgsLayerTreeModelLegendNode *node) const", "indexOfParentLayerTreeNode(QgsLayerTreeNode *parentNode) const", "nodeLayerLoaded()", "nodeWillAddChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)", "nodeRemovedChildren()", "legendRootIndex(int row, int column, QgsLayerTreeLayer *nL) const", "connectToLayer(QgsLayerTreeLayer *nodeLayer)", "legendIconEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const", "nodeAddedChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)", "legendNodeIndex(int row, int column, QgsLayerTreeModelLegendNode *node) const", "invalidateLegendMapBasedData()", "disconnectFromLayer(QgsLayerTreeLayer *nodeLayer)", "legendEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const", "legendParent(QgsLayerTreeModelLegendNode *legendNode) const"], - "QgsEditorWidgetRegistry": ["createSearchWidget(const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, const QVariantMap &config, QWidget *parent, const QgsAttributeEditorContext &context=QgsAttributeEditorContext())"], - "QgsGeometryCheckerUtils": ["lineIntersections(const QgsLineString *line1, const QgsLineString *line2, double tol)", "polygonRings(const QgsPolygon *polygon)", "getGeomPart(const QgsAbstractGeometry *geom, int partIdx)", "canDeleteVertex(const QgsAbstractGeometry *geom, int iPart, int iRing)", "sharedEdgeLength(const QgsAbstractGeometry *geom1, const QgsAbstractGeometry *geom2, double tol)", "createGeomEngine(const QgsAbstractGeometry *geometry, double tolerance)", "pointOnLine(const QgsPoint &p, const QgsLineString *line, double tol, bool excludeExtremities=false)", "getGeomPart(QgsAbstractGeometry *geom, int partIdx)", "filter1DTypes(QgsAbstractGeometry *geom)"], - "QgsLayerTreeLayer": ["QgsLayerTreeLayer(const QgsLayerTreeLayer &other)", "QgsLayerTreeLayer(QgsMapLayer *layer)", "attachToLayer()"], - "QgsMasterPasswordResetDialog": ["requestMasterPasswordReset(QString *newpass, QString *oldpass, bool *keepbackup)", "QgsMasterPasswordResetDialog(QWidget *parent=nullptr)"], + "QgsPointDisplacementRendererWidget": [ + "QgsPointDisplacementRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", + "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", + ], + "QgsSingleBandGrayRendererWidget": [ + "create(QgsRasterLayer *layer, const QgsRectangle &extent)", + "QgsSingleBandGrayRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent=QgsRectangle())", + ], + "QgsLayerTreeModel": [ + "nodeWillRemoveChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)", + "disconnectFromLayers(QgsLayerTreeGroup *parentGroup)", + "connectToLayers(QgsLayerTreeGroup *parentGroup)", + "nodeLayerWillBeUnloaded()", + "legendInvalidateMapBasedData()", + "nodeCustomPropertyChanged(QgsLayerTreeNode *node, const QString &key)", + "legendNodeData(QgsLayerTreeModelLegendNode *node, int role) const", + "legendCleanup()", + "Flag", + "iconGroup()", + "disconnectFromRootNode()", + "layerNeedsUpdate()", + "addLegendToLayer(QgsLayerTreeLayer *nodeL)", + "nodeVisibilityChanged(QgsLayerTreeNode *node)", + "layerLegendChanged()", + "legendRootRowCount(QgsLayerTreeLayer *nL) const", + "removeLegendFromLayer(QgsLayerTreeLayer *nodeLayer)", + "legendNodeRowCount(QgsLayerTreeModelLegendNode *node) const", + "legendNodeDataChanged()", + "connectToRootNode()", + "legendNodeFlags(QgsLayerTreeModelLegendNode *node) const", + "indexOfParentLayerTreeNode(QgsLayerTreeNode *parentNode) const", + "nodeLayerLoaded()", + "nodeWillAddChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)", + "nodeRemovedChildren()", + "legendRootIndex(int row, int column, QgsLayerTreeLayer *nL) const", + "connectToLayer(QgsLayerTreeLayer *nodeLayer)", + "legendIconEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const", + "nodeAddedChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)", + "legendNodeIndex(int row, int column, QgsLayerTreeModelLegendNode *node) const", + "invalidateLegendMapBasedData()", + "disconnectFromLayer(QgsLayerTreeLayer *nodeLayer)", + "legendEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const", + "legendParent(QgsLayerTreeModelLegendNode *legendNode) const", + ], + "QgsEditorWidgetRegistry": [ + "createSearchWidget(const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, const QVariantMap &config, QWidget *parent, const QgsAttributeEditorContext &context=QgsAttributeEditorContext())" + ], + "QgsGeometryCheckerUtils": [ + "lineIntersections(const QgsLineString *line1, const QgsLineString *line2, double tol)", + "polygonRings(const QgsPolygon *polygon)", + "getGeomPart(const QgsAbstractGeometry *geom, int partIdx)", + "canDeleteVertex(const QgsAbstractGeometry *geom, int iPart, int iRing)", + "sharedEdgeLength(const QgsAbstractGeometry *geom1, const QgsAbstractGeometry *geom2, double tol)", + "createGeomEngine(const QgsAbstractGeometry *geometry, double tolerance)", + "pointOnLine(const QgsPoint &p, const QgsLineString *line, double tol, bool excludeExtremities=false)", + "getGeomPart(QgsAbstractGeometry *geom, int partIdx)", + "filter1DTypes(QgsAbstractGeometry *geom)", + ], + "QgsLayerTreeLayer": [ + "QgsLayerTreeLayer(const QgsLayerTreeLayer &other)", + "QgsLayerTreeLayer(QgsMapLayer *layer)", + "attachToLayer()", + ], + "QgsMasterPasswordResetDialog": [ + "requestMasterPasswordReset(QString *newpass, QString *oldpass, bool *keepbackup)", + "QgsMasterPasswordResetDialog(QWidget *parent=nullptr)", + ], "pal::FeaturePart": ["FeaturePart(const FeaturePart &other)"], - "QgsEffectDrawModeComboBox": ["QgsEffectDrawModeComboBox(QWidget *parent SIP_TRANSFERTHIS=nullptr)"], - "QgsSingleBandColorDataRenderer": ["create(const QDomElement &elem, QgsRasterInterface *input)", "QgsSingleBandColorDataRenderer(QgsRasterInterface *input, int band)"], - "QgsLayerTreeMapCanvasBridge": ["mapCanvas() const", "rootGroup() const", "autoSetupOnFirstLayer() const"], - "QgsGeometrySegmentLengthCheck": ["QgsGeometrySegmentLengthCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "factoryDescription()", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"], + "QgsEffectDrawModeComboBox": [ + "QgsEffectDrawModeComboBox(QWidget *parent SIP_TRANSFERTHIS=nullptr)" + ], + "QgsSingleBandColorDataRenderer": [ + "create(const QDomElement &elem, QgsRasterInterface *input)", + "QgsSingleBandColorDataRenderer(QgsRasterInterface *input, int band)", + ], + "QgsLayerTreeMapCanvasBridge": [ + "mapCanvas() const", + "rootGroup() const", + "autoSetupOnFirstLayer() const", + ], + "QgsGeometrySegmentLengthCheck": [ + "QgsGeometrySegmentLengthCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", + "factoryDescription()", + "ResolutionMethod", + "factoryCompatibleGeometryTypes()", + "factoryCheckType()", + "factoryIsCompatible(QgsVectorLayer *layer)", + "factoryId()", + ], "QgsAttributeDialog": ["attributeForm()", "feature()"], "QgsDiagramSettings": ["LabelPlacementMethod"], "QgsPalLayerSettings": ["QgsPalLayerSettings(const QgsPalLayerSettings &s)"], - "ParametricLine": ["calcSecDer(float t, Vector3D *v)=0", "setParent(ParametricLine *paral)=0", "add(ParametricLine *pl)=0", "calcFirstDer(float t, Vector3D *v)=0", "getParent() const =0", "getControlPoly() const =0", "calcPoint(float t, QgsPoint *p)=0", "getDegree() const =0", "setControlPoly(QVector< QgsPoint * > *cp)=0", "changeDirection()=0", "remove(int i)=0", "getControlPoint(int number) const =0"], - "QgsPalettedRasterRenderer": ["create(const QDomElement &elem, QgsRasterInterface *input)"], + "ParametricLine": [ + "calcSecDer(float t, Vector3D *v)=0", + "setParent(ParametricLine *paral)=0", + "add(ParametricLine *pl)=0", + "calcFirstDer(float t, Vector3D *v)=0", + "getParent() const =0", + "getControlPoly() const =0", + "calcPoint(float t, QgsPoint *p)=0", + "getDegree() const =0", + "setControlPoly(QVector< QgsPoint * > *cp)=0", + "changeDirection()=0", + "remove(int i)=0", + "getControlPoint(int number) const =0", + ], + "QgsPalettedRasterRenderer": [ + "create(const QDomElement &elem, QgsRasterInterface *input)" + ], "QgsDataCollectionItem": ["addChild(QgsDataItem *item)"], - "QgsMapLayerModel": ["addLayers(const QList< QgsMapLayer * > &layers)", "removeLayers(const QStringList &layerIds)"], - "QgsLinePatternFillSymbolLayer": ["ogrFeatureStyleWidth(double widthScaleFactor) const"], - "QgsMeshAvailableDatasetGroupTreeModel": ["QgsMeshAvailableDatasetGroupTreeModel(QObject *parent=nullptr)"], - "QgsSymbolLayerUtils": ["drawStippledBackground(QPainter *painter, QRect rect)", "createLineLayerFromSld(QDomElement &element)", "createDisplacementElement(QDomDocument &doc, QDomElement &element, QPointF offset)", "decodeMapUnitScale(const QString &str)", "createFillLayerFromSld(QDomElement &element)", "decodeBlendMode(const QString &s)", "decodePenJoinStyle(const QString &str)", "encodeSldAlpha(int alpha)", "encodeSldFontWeight(int weight)", "fillToSld(QDomDocument &doc, QDomElement &element, Qt::BrushStyle brushStyle, const QColor &color=QColor())", "createOnlineResourceElement(QDomDocument &doc, QDomElement &element, const QString &path, const QString &format)", "geometryFromSldElement(QDomElement &element, QString &geomFunc)", "needLinePatternFill(QDomElement &element)", "needSvgFill(QDomElement &element)", "hasWellKnownMark(QDomElement &element)", "decodePenStyle(const QString &str)", "clearSymbolMap(QgsSymbolMap &symbols)", "fillFromSld(QDomElement &element, Qt::BrushStyle &brushStyle, QColor &color)", "decodeSldFontWeight(const QString &str)", "needPointPatternFill(QDomElement &element)", "decodeSldFontStyle(const QString &str)", "encodeSldFontStyle(QFont::Style style)", "externalMarkerFromSld(QDomElement &element, QString &path, QString &format, int &markIndex, QColor &color, double &size)", "getVendorOptionList(QDomElement &element)", "needSvgMarker(QDomElement &element)", "lineFromSld(QDomElement &element, Qt::PenStyle &penStyle, QColor &color, double &width, Qt::PenJoinStyle *penJoinStyle=nullptr, Qt::PenCapStyle *penCapStyle=nullptr, QVector< qreal > *customDashPattern=nullptr, double *dashOffset=nullptr)", "decodeSldAlpha(const QString &str)", "needFontMarker(QDomElement &element)", "decodeSldLineCapStyle(const QString &str)", "encodePenCapStyle(Qt::PenCapStyle style)", "decodeBrushStyle(const QString &str)", "onlineResourceFromSldElement(QDomElement &element, QString &path, QString &format)", "createFunctionElement(QDomDocument &doc, QDomElement &element, const QString &function)", "createMarkerLayerFromSld(QDomElement &element)", "encodeSldBrushStyle(Qt::BrushStyle style)", "encodeSldLineJoinStyle(Qt::PenJoinStyle style)", "externalGraphicToSld(QDomDocument &doc, QDomElement &element, const QString &path, const QString &mime, const QColor &color, double size=-1)", "encodeRealVector(const QVector< qreal > &v)", "encodeBrushStyle(Qt::BrushStyle style)", "encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)", "encodePenStyle(Qt::PenStyle style)", "decodePenCapStyle(const QString &str)", "opacityFromSldElement(QDomElement &element, QString &alphaFunc)", "rotationFromSldElement(QDomElement &element, QString &rotationFunc)", "wellKnownMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &name, const QColor &color, const QColor &strokeColor, Qt::PenStyle strokeStyle, double strokeWidth=-1, double size=-1)", "needMarkerLine(QDomElement &element)", "createOpacityElement(QDomDocument &doc, QDomElement &element, const QString &alphaFunc)", "decodeSldLineJoinStyle(const QString &str)", "decodeSldRealVector(const QString &s)", "encodeColor(const QColor &color)", "displacementFromSldElement(QDomElement &element, QPointF &offset)", "encodePenJoinStyle(Qt::PenJoinStyle style)", "decodeSldBrushStyle(const QString &str)", "externalGraphicFromSld(QDomElement &element, QString &path, QString &mime, QColor &color, double &size)", "encodeSldRealVector(const QVector< qreal > &v)", "externalMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &path, const QString &format, int *markIndex=nullptr, const QColor &color=QColor(), double size=-1)", "createRotationElement(QDomDocument &doc, QDomElement &element, const QString &rotationFunc)", "createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)", "labelTextToSld(QDomDocument &doc, QDomElement &element, const QString &label, const QFont &font, const QColor &color=QColor(), double size=-1)", "decodeRealVector(const QString &s)", "functionFromSldElement(QDomElement &element, QString &function)", "getSvgParameterList(QDomElement &element)", "encodeSldLineCapStyle(Qt::PenCapStyle style)", "decodeColor(const QString &str)", "createSvgParameterElement(QDomDocument &doc, const QString &name, const QString &value)", "needEllipseMarker(QDomElement &element)", "createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)"], - "QgsMapRendererQImageJob": ["QgsMapRendererQImageJob(const QgsMapSettings &settings)"], - "QgsSvgSelectorWidget": ["currentSvgPath() const", "svgSelected(const QString &path)", "populateList()"], - "QgsMeshDatasetGroupListModel": ["QgsMeshDatasetGroupListModel(QObject *parent)", "variableNames() const", "setDisplayProviderName(bool displayProviderName)"], - "QgsSmartGroupEditorDialog": ["QgsSmartGroupEditorDialog(QgsStyle *style, QWidget *parent=nullptr)"], - "QgsSvgMarkerSymbolLayer": ["createFromSld(QDomElement &element)", "strokeWidth() const", "setStrokeWidth(double w)", "setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)", "strokeWidthMapUnitScale() const"], - "QgsLUDialog": ["lowerValue() const", "QgsLUDialog(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)", "setLowerValue(const QString &val)", "setUpperValue(const QString &val)", "upperValue() const"], - "QgsMapRendererCustomPainterJob": ["QgsMapRendererCustomPainterJob(const QgsMapSettings &settings, QPainter *painter)"], - "QgsFeatureRenderer": ["type() const", "QgsFeatureRenderer(const QString &type)", "setUsingSymbolLevels(bool usingSymbolLevels)", "usingSymbolLevels() const"], + "QgsMapLayerModel": [ + "addLayers(const QList< QgsMapLayer * > &layers)", + "removeLayers(const QStringList &layerIds)", + ], + "QgsLinePatternFillSymbolLayer": [ + "ogrFeatureStyleWidth(double widthScaleFactor) const" + ], + "QgsMeshAvailableDatasetGroupTreeModel": [ + "QgsMeshAvailableDatasetGroupTreeModel(QObject *parent=nullptr)" + ], + "QgsSymbolLayerUtils": [ + "drawStippledBackground(QPainter *painter, QRect rect)", + "createLineLayerFromSld(QDomElement &element)", + "createDisplacementElement(QDomDocument &doc, QDomElement &element, QPointF offset)", + "decodeMapUnitScale(const QString &str)", + "createFillLayerFromSld(QDomElement &element)", + "decodeBlendMode(const QString &s)", + "decodePenJoinStyle(const QString &str)", + "encodeSldAlpha(int alpha)", + "encodeSldFontWeight(int weight)", + "fillToSld(QDomDocument &doc, QDomElement &element, Qt::BrushStyle brushStyle, const QColor &color=QColor())", + "createOnlineResourceElement(QDomDocument &doc, QDomElement &element, const QString &path, const QString &format)", + "geometryFromSldElement(QDomElement &element, QString &geomFunc)", + "needLinePatternFill(QDomElement &element)", + "needSvgFill(QDomElement &element)", + "hasWellKnownMark(QDomElement &element)", + "decodePenStyle(const QString &str)", + "clearSymbolMap(QgsSymbolMap &symbols)", + "fillFromSld(QDomElement &element, Qt::BrushStyle &brushStyle, QColor &color)", + "decodeSldFontWeight(const QString &str)", + "needPointPatternFill(QDomElement &element)", + "decodeSldFontStyle(const QString &str)", + "encodeSldFontStyle(QFont::Style style)", + "externalMarkerFromSld(QDomElement &element, QString &path, QString &format, int &markIndex, QColor &color, double &size)", + "getVendorOptionList(QDomElement &element)", + "needSvgMarker(QDomElement &element)", + "lineFromSld(QDomElement &element, Qt::PenStyle &penStyle, QColor &color, double &width, Qt::PenJoinStyle *penJoinStyle=nullptr, Qt::PenCapStyle *penCapStyle=nullptr, QVector< qreal > *customDashPattern=nullptr, double *dashOffset=nullptr)", + "decodeSldAlpha(const QString &str)", + "needFontMarker(QDomElement &element)", + "decodeSldLineCapStyle(const QString &str)", + "encodePenCapStyle(Qt::PenCapStyle style)", + "decodeBrushStyle(const QString &str)", + "onlineResourceFromSldElement(QDomElement &element, QString &path, QString &format)", + "createFunctionElement(QDomDocument &doc, QDomElement &element, const QString &function)", + "createMarkerLayerFromSld(QDomElement &element)", + "encodeSldBrushStyle(Qt::BrushStyle style)", + "encodeSldLineJoinStyle(Qt::PenJoinStyle style)", + "externalGraphicToSld(QDomDocument &doc, QDomElement &element, const QString &path, const QString &mime, const QColor &color, double size=-1)", + "encodeRealVector(const QVector< qreal > &v)", + "encodeBrushStyle(Qt::BrushStyle style)", + "encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)", + "encodePenStyle(Qt::PenStyle style)", + "decodePenCapStyle(const QString &str)", + "opacityFromSldElement(QDomElement &element, QString &alphaFunc)", + "rotationFromSldElement(QDomElement &element, QString &rotationFunc)", + "wellKnownMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &name, const QColor &color, const QColor &strokeColor, Qt::PenStyle strokeStyle, double strokeWidth=-1, double size=-1)", + "needMarkerLine(QDomElement &element)", + "createOpacityElement(QDomDocument &doc, QDomElement &element, const QString &alphaFunc)", + "decodeSldLineJoinStyle(const QString &str)", + "decodeSldRealVector(const QString &s)", + "encodeColor(const QColor &color)", + "displacementFromSldElement(QDomElement &element, QPointF &offset)", + "encodePenJoinStyle(Qt::PenJoinStyle style)", + "decodeSldBrushStyle(const QString &str)", + "externalGraphicFromSld(QDomElement &element, QString &path, QString &mime, QColor &color, double &size)", + "encodeSldRealVector(const QVector< qreal > &v)", + "externalMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &path, const QString &format, int *markIndex=nullptr, const QColor &color=QColor(), double size=-1)", + "createRotationElement(QDomDocument &doc, QDomElement &element, const QString &rotationFunc)", + "createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)", + "labelTextToSld(QDomDocument &doc, QDomElement &element, const QString &label, const QFont &font, const QColor &color=QColor(), double size=-1)", + "decodeRealVector(const QString &s)", + "functionFromSldElement(QDomElement &element, QString &function)", + "getSvgParameterList(QDomElement &element)", + "encodeSldLineCapStyle(Qt::PenCapStyle style)", + "decodeColor(const QString &str)", + "createSvgParameterElement(QDomDocument &doc, const QString &name, const QString &value)", + "needEllipseMarker(QDomElement &element)", + "createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)", + ], + "QgsMapRendererQImageJob": [ + "QgsMapRendererQImageJob(const QgsMapSettings &settings)" + ], + "QgsSvgSelectorWidget": [ + "currentSvgPath() const", + "svgSelected(const QString &path)", + "populateList()", + ], + "QgsMeshDatasetGroupListModel": [ + "QgsMeshDatasetGroupListModel(QObject *parent)", + "variableNames() const", + "setDisplayProviderName(bool displayProviderName)", + ], + "QgsSmartGroupEditorDialog": [ + "QgsSmartGroupEditorDialog(QgsStyle *style, QWidget *parent=nullptr)" + ], + "QgsSvgMarkerSymbolLayer": [ + "createFromSld(QDomElement &element)", + "strokeWidth() const", + "setStrokeWidth(double w)", + "setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)", + "strokeWidthMapUnitScale() const", + ], + "QgsLUDialog": [ + "lowerValue() const", + "QgsLUDialog(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)", + "setLowerValue(const QString &val)", + "setUpperValue(const QString &val)", + "upperValue() const", + ], + "QgsMapRendererCustomPainterJob": [ + "QgsMapRendererCustomPainterJob(const QgsMapSettings &settings, QPainter *painter)" + ], + "QgsFeatureRenderer": [ + "type() const", + "QgsFeatureRenderer(const QString &type)", + "setUsingSymbolLevels(bool usingSymbolLevels)", + "usingSymbolLevels() const", + ], "QgsExpressionFieldBuffer": ["expressions() const"], - "QgsValueRelationConfigDlg": ["QgsValueRelationConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)", "editExpression()"], - "QgsRasterPyramidsOptionsWidget": ["checkAllLevels(bool checked)", "overviewList() const", "overviewListChanged()", "apply()", "configOptions() const", "someValueChanged()", "createOptionsWidget()", "setRasterFileName(const QString &file)", "setRasterLayer(QgsRasterLayer *rasterLayer)", "resamplingMethod() const"], - "QgsBrowserModel": ["endInsertItems()", "itemDataChanged(QgsDataItem *item)", "updateProjectHome()", "beginRemoveItems(QgsDataItem *parent, int first, int last)", "ItemDataRole", "beginInsertItems(QgsDataItem *parent, int first, int last)", "removeRootItems()", "endRemoveItems()"], - "QgsRasterFileWriter": ["pyramidsResampling() const", "setPyramidsResampling(const QString &str)"], - "QgsExternalResourceWidget": ["setDocumentPath(const QVariant &documentPath)", "DocumentViewerContent"], + "QgsValueRelationConfigDlg": [ + "QgsValueRelationConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)", + "editExpression()", + ], + "QgsRasterPyramidsOptionsWidget": [ + "checkAllLevels(bool checked)", + "overviewList() const", + "overviewListChanged()", + "apply()", + "configOptions() const", + "someValueChanged()", + "createOptionsWidget()", + "setRasterFileName(const QString &file)", + "setRasterLayer(QgsRasterLayer *rasterLayer)", + "resamplingMethod() const", + ], + "QgsBrowserModel": [ + "endInsertItems()", + "itemDataChanged(QgsDataItem *item)", + "updateProjectHome()", + "beginRemoveItems(QgsDataItem *parent, int first, int last)", + "ItemDataRole", + "beginInsertItems(QgsDataItem *parent, int first, int last)", + "removeRootItems()", + "endRemoveItems()", + ], + "QgsRasterFileWriter": [ + "pyramidsResampling() const", + "setPyramidsResampling(const QString &str)", + ], + "QgsExternalResourceWidget": [ + "setDocumentPath(const QVariant &documentPath)", + "DocumentViewerContent", + ], "QgsStyleExportImportDialog": ["doExportImport()", "importTypeChanged(int)"], "pal::Util": ["unmulti(const GEOSGeometry *the_geom)"], - "QgsProjectFileTransform": ["updateRevision(const QgsProjectVersion &version)", "convertRasterProperties(QDomDocument &doc, QDomNode &parentNode, QDomElement &rasterPropertiesElem, QgsRasterLayer *rlayer)"], - "QgsGeometryDegeneratePolygonCheck": ["factoryDescription()", "QgsGeometryDegeneratePolygonCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"], - "QgsRelief": ["setZFactor(double factor)", "setReliefColors(const QList< QgsRelief::ReliefColor > &c)", "QgsRelief(const QString &inputFile, const QString &outputFile, const QString &outputFormat)", "addReliefColorClass(const QgsRelief::ReliefColor &color)", "reliefColors() const", "clearReliefColors()", "zFactor() const"], - "QgsValueMapConfigDlg": ["QgsValueMapConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent)"], + "QgsProjectFileTransform": [ + "updateRevision(const QgsProjectVersion &version)", + "convertRasterProperties(QDomDocument &doc, QDomNode &parentNode, QDomElement &rasterPropertiesElem, QgsRasterLayer *rlayer)", + ], + "QgsGeometryDegeneratePolygonCheck": [ + "factoryDescription()", + "QgsGeometryDegeneratePolygonCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", + "ResolutionMethod", + "factoryCompatibleGeometryTypes()", + "factoryCheckType()", + "factoryIsCompatible(QgsVectorLayer *layer)", + "factoryId()", + ], + "QgsRelief": [ + "setZFactor(double factor)", + "setReliefColors(const QList< QgsRelief::ReliefColor > &c)", + "QgsRelief(const QString &inputFile, const QString &outputFile, const QString &outputFormat)", + "addReliefColorClass(const QgsRelief::ReliefColor &color)", + "reliefColors() const", + "clearReliefColors()", + "zFactor() const", + ], + "QgsValueMapConfigDlg": [ + "QgsValueMapConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent)" + ], "QgsSnappingUtils": ["mapSettings() const", "IndexingStrategy"], - "QgsVectorFileWriter::BoolOption": ["BoolOption(const QString &docString, bool defaultValue)"], - "QgsNewNameDialog": ["nameChanged()", "fullNames(const QString &name, const QStringList &extensions)", "matching(const QStringList &newNames, const QStringList &existingNames, Qt::CaseSensitivity cs=Qt::CaseSensitive)", "highlightText(const QString &text)"], - "QgsMeshActiveDatasetGroupTreeView": ["QgsMeshActiveDatasetGroupTreeView(QWidget *parent=nullptr)"], - "pal::PriorityQueue": ["print()", "decreaseKey(int key)", "getSize() const", "remove(int key)", "downheap(int id)", "getSizeByPos() const", "getId(int key) const", "isIn(int key) const", "setPriority(int key, double new_p)", "upheap(int key)", "getBest()", "insert(int key, double p)", "sort()"], + "QgsVectorFileWriter::BoolOption": [ + "BoolOption(const QString &docString, bool defaultValue)" + ], + "QgsNewNameDialog": [ + "nameChanged()", + "fullNames(const QString &name, const QStringList &extensions)", + "matching(const QStringList &newNames, const QStringList &existingNames, Qt::CaseSensitivity cs=Qt::CaseSensitive)", + "highlightText(const QString &text)", + ], + "QgsMeshActiveDatasetGroupTreeView": [ + "QgsMeshActiveDatasetGroupTreeView(QWidget *parent=nullptr)" + ], + "pal::PriorityQueue": [ + "print()", + "decreaseKey(int key)", + "getSize() const", + "remove(int key)", + "downheap(int id)", + "getSizeByPos() const", + "getId(int key) const", + "isIn(int key) const", + "setPriority(int key, double new_p)", + "upheap(int key)", + "getBest()", + "insert(int key, double p)", + "sort()", + ], "QgsSvgSelectorGroupsModel": ["QgsSvgSelectorGroupsModel(QObject *parent)"], "QgsEncodingFileDialog": ["pbnCancelAll_clicked()", "saveUsedEncoding()"], "QgsDefaultRasterLayerLegend": ["QgsDefaultRasterLayerLegend(QgsRasterLayer *rl)"], - "QgsDetailedItemDelegate": ["verticalSpacing() const", "horizontalSpacing() const", "setVerticalSpacing(int value)", "setHorizontalSpacing(int value)"], - "QgsStyleGroupSelectionDialog": ["QgsStyleGroupSelectionDialog(QgsStyle *style, QWidget *parent=nullptr)"], + "QgsDetailedItemDelegate": [ + "verticalSpacing() const", + "horizontalSpacing() const", + "setVerticalSpacing(int value)", + "setHorizontalSpacing(int value)", + ], + "QgsStyleGroupSelectionDialog": [ + "QgsStyleGroupSelectionDialog(QgsStyle *style, QWidget *parent=nullptr)" + ], "QgsFeatureModel": ["fidToIndex(QgsFeatureId fid)=0"], - "QgsMimeDataUtils": ["decodeUriList(const QMimeData *data)", "isUriList(const QMimeData *data)"], + "QgsMimeDataUtils": [ + "decodeUriList(const QMimeData *data)", + "isUriList(const QMimeData *data)", + ], "QgsVectorFileWriter::HiddenOption": ["HiddenOption(const QString &value)"], - "QgsAttributeTableDelegate": ["setFeatureSelectionModel(QgsFeatureSelectionModel *featureSelectionModel)"], - "QgisInterface": ["actionAddPgLayer()=0", "actionShowPythonDialog()=0", "actionSaveAllEdits()=0", "actionPluginListSeparator()=0", "actionAddRasterLayer()=0", "actionCancelAllEdits()=0", "actionOpenFieldCalculator()=0", "pluginManagerInterface()=0", "actionHideSelectedLayers()=0", "actionShowAllLayers()=0", "actionLayerProperties()=0", "actionLayerSaveAs()=0", "actionAddToOverview()=0", "actionAddOgrLayer()=0", "actionOptions()=0", "actionAddAllToOverview()=0", "layerTreeView()=0", "actionDuplicateLayer()=0", "actionRollbackEdits()=0", "actionCheckQgisVersion()=0", "actionAddWmsLayer()=0", "actionCustomProjection()=0", "actionQgisHomePage()=0", "actionPasteLayerStyle()=0", "actionShowSelectedLayers()=0", "actionNewVectorLayer()=0", "actionRollbackAllEdits()=0", "actionManagePlugins()=0", "actionCopyLayerStyle()=0", "actionToggleEditing()=0", "actionSaveActiveLayerEdits()=0", "actionCancelEdits()=0", "actionRemoveAllFromOverview()=0", "actionToggleFullScreen()=0", "actionHelpContents()=0", "actionSaveEdits()=0", "actionAllEdits()=0", "actionHideAllLayers()=0", "actionOpenTable()=0", "actionAbout()=0"], - "QgsConnectionPoolGroup": ["initTimer(QObject *parent)", "QgsConnectionPoolGroup(const QString &ci)", "onConnectionExpired()", "release(T conn)", "invalidateConnections()"], - "QgsLinearMinMaxEnhancementWithClip": ["QgsLinearMinMaxEnhancementWithClip(Qgis::DataType, double, double)"], - "QgsFeatureSelectionModel": ["QgsFeatureSelectionModel(QAbstractItemModel *model, QgsFeatureModel *featureModel, QgsIFeatureSelectionManager *featureSelectionHandler, QObject *parent)", "setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)"], - "QgsRasterResampleFilter": ["zoomedOutResampler() const", "setMaxOversampling(double os)", "maxOversampling() const", "QgsRasterResampleFilter(QgsRasterInterface *input=nullptr)", "zoomedInResampler() const"], + "QgsAttributeTableDelegate": [ + "setFeatureSelectionModel(QgsFeatureSelectionModel *featureSelectionModel)" + ], + "QgisInterface": [ + "actionAddPgLayer()=0", + "actionShowPythonDialog()=0", + "actionSaveAllEdits()=0", + "actionPluginListSeparator()=0", + "actionAddRasterLayer()=0", + "actionCancelAllEdits()=0", + "actionOpenFieldCalculator()=0", + "pluginManagerInterface()=0", + "actionHideSelectedLayers()=0", + "actionShowAllLayers()=0", + "actionLayerProperties()=0", + "actionLayerSaveAs()=0", + "actionAddToOverview()=0", + "actionAddOgrLayer()=0", + "actionOptions()=0", + "actionAddAllToOverview()=0", + "layerTreeView()=0", + "actionDuplicateLayer()=0", + "actionRollbackEdits()=0", + "actionCheckQgisVersion()=0", + "actionAddWmsLayer()=0", + "actionCustomProjection()=0", + "actionQgisHomePage()=0", + "actionPasteLayerStyle()=0", + "actionShowSelectedLayers()=0", + "actionNewVectorLayer()=0", + "actionRollbackAllEdits()=0", + "actionManagePlugins()=0", + "actionCopyLayerStyle()=0", + "actionToggleEditing()=0", + "actionSaveActiveLayerEdits()=0", + "actionCancelEdits()=0", + "actionRemoveAllFromOverview()=0", + "actionToggleFullScreen()=0", + "actionHelpContents()=0", + "actionSaveEdits()=0", + "actionAllEdits()=0", + "actionHideAllLayers()=0", + "actionOpenTable()=0", + "actionAbout()=0", + ], + "QgsConnectionPoolGroup": [ + "initTimer(QObject *parent)", + "QgsConnectionPoolGroup(const QString &ci)", + "onConnectionExpired()", + "release(T conn)", + "invalidateConnections()", + ], + "QgsLinearMinMaxEnhancementWithClip": [ + "QgsLinearMinMaxEnhancementWithClip(Qgis::DataType, double, double)" + ], + "QgsFeatureSelectionModel": [ + "QgsFeatureSelectionModel(QAbstractItemModel *model, QgsFeatureModel *featureModel, QgsIFeatureSelectionManager *featureSelectionHandler, QObject *parent)", + "setFeatureSelectionManager(QgsIFeatureSelectionManager *featureSelectionManager)", + ], + "QgsRasterResampleFilter": [ + "zoomedOutResampler() const", + "setMaxOversampling(double os)", + "maxOversampling() const", + "QgsRasterResampleFilter(QgsRasterInterface *input=nullptr)", + "zoomedInResampler() const", + ], "QgsAlignRaster": ["setGridOffset(QPointF offset)", "gridOffset() const"], - "QgsLinearlyInterpolatedDiagramRenderer": ["classificationAttributeIsExpression() const", "lowerValue() const", "upperSize() const", "setUpperValue(double val)", "lowerSize() const", "classificationAttributeExpression() const", "setClassificationAttributeIsExpression(bool isExpression)", "setUpperSize(QSizeF s)", "upperValue() const", "setLowerValue(double val)", "setDiagramSettings(const QgsDiagramSettings &s)", "setLowerSize(QSizeF s)", "setClassificationAttributeExpression(const QString &expression)"], - "QgsRasterBlock": ["toString() const", "applyNoDataValues(const QgsRasterRangeList &rangeList)"], - "QgsRasterLayer": ["showStatusMessage(const QString &message)", "isValidRasterFileName(const QString &fileNameQString)"], + "QgsLinearlyInterpolatedDiagramRenderer": [ + "classificationAttributeIsExpression() const", + "lowerValue() const", + "upperSize() const", + "setUpperValue(double val)", + "lowerSize() const", + "classificationAttributeExpression() const", + "setClassificationAttributeIsExpression(bool isExpression)", + "setUpperSize(QSizeF s)", + "upperValue() const", + "setLowerValue(double val)", + "setDiagramSettings(const QgsDiagramSettings &s)", + "setLowerSize(QSizeF s)", + "setClassificationAttributeExpression(const QString &expression)", + ], + "QgsRasterBlock": [ + "toString() const", + "applyNoDataValues(const QgsRasterRangeList &rangeList)", + ], + "QgsRasterLayer": [ + "showStatusMessage(const QString &message)", + "isValidRasterFileName(const QString &fileNameQString)", + ], "QgsZipItem": ["iconZip()", "getZipFileList()"], - "QgsVectorDataProvider": ["convertValue(QVariant::Type type, const QString &value)"], + "QgsVectorDataProvider": [ + "convertValue(QVariant::Type type, const QString &value)" + ], "QgsQueryBuilder": ["setDatasourceDescription(const QString &uri)", "clear()"], "QgsFillSymbolLayer": ["QgsFillSymbolLayer(bool locked=false)"], "QgsGeometryCollection": ["QgsGeometryCollection(const QgsGeometryCollection &c)"], - "QgsMultiBandColorRendererWidget": ["create(QgsRasterLayer *layer, const QgsRectangle &extent)", "QgsMultiBandColorRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent=QgsRectangle())"], + "QgsMultiBandColorRendererWidget": [ + "create(QgsRasterLayer *layer, const QgsRectangle &extent)", + "QgsMultiBandColorRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent=QgsRectangle())", + ], "QgsTransaction": ["QgsTransaction(const QString &connString)"], - "QgsExpressionHighlighter": ["QgsExpressionHighlighter(QTextDocument *parent=nullptr)", "addFields(const QStringList &fieldList)"], - "QgsPenCapStyleComboBox": ["setPenCapStyle(Qt::PenCapStyle style)", "QgsPenCapStyleComboBox(QWidget *parent=nullptr)", "penCapStyle() const"], - "QgsRuleBasedRendererWidget": ["refineRuleScalesGui(const QModelIndexList &index)", "refineRuleScales()", "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", "saveSectionWidth(int section, int oldSize, int newSize)", "currentRule()", "QgsRuleBasedRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", "selectedRules()", "currentRuleChanged(const QModelIndex ¤t=QModelIndex(), const QModelIndex &previous=QModelIndex())", "selectedRulesChanged()", "clearFeatureCounts()", "editRule()", "refineRuleCategories()", "restoreSectionWidths()", "setRenderingOrder()", "countFeatures()", "refineRule(int type)", "editRule(const QModelIndex &index)", "removeRule()", "addRule()", "refineRuleRanges()"], - "QgsPointLocator_Stream": ["QgsPointLocator_Stream(const QLinkedList< RTree::Data * > &dataList)"], - "QgsCheckBoxConfigDlg": ["QgsCheckBoxConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)"], - "QgsAttributeTableView": ["repaintRequested()", "setModel(QgsAttributeTableFilterModel *filterModel)", "_q_selectRow(int row)", "selectRow(int row)", "repaintRequested(const QModelIndexList &indexes)", "finished()"], - "QgsAttributesDnDTree": ["setType(QgsAttributesDnDTree::Type value)", "QgsAttributesDnDTree(QgsVectorLayer *layer, QWidget *parent=nullptr)", "type() const", "selectFirstMatchingItem(const QgsAttributesFormProperties::DnDTreeItemData &data)", "Type"], - "QgsAbstractFeatureIteratorFromSource": ["QgsAbstractFeatureIteratorFromSource(T *source, bool ownSource, const QgsFeatureRequest &request)"], + "QgsExpressionHighlighter": [ + "QgsExpressionHighlighter(QTextDocument *parent=nullptr)", + "addFields(const QStringList &fieldList)", + ], + "QgsPenCapStyleComboBox": [ + "setPenCapStyle(Qt::PenCapStyle style)", + "QgsPenCapStyleComboBox(QWidget *parent=nullptr)", + "penCapStyle() const", + ], + "QgsRuleBasedRendererWidget": [ + "refineRuleScalesGui(const QModelIndexList &index)", + "refineRuleScales()", + "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", + "saveSectionWidth(int section, int oldSize, int newSize)", + "currentRule()", + "QgsRuleBasedRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", + "selectedRules()", + "currentRuleChanged(const QModelIndex ¤t=QModelIndex(), const QModelIndex &previous=QModelIndex())", + "selectedRulesChanged()", + "clearFeatureCounts()", + "editRule()", + "refineRuleCategories()", + "restoreSectionWidths()", + "setRenderingOrder()", + "countFeatures()", + "refineRule(int type)", + "editRule(const QModelIndex &index)", + "removeRule()", + "addRule()", + "refineRuleRanges()", + ], + "QgsPointLocator_Stream": [ + "QgsPointLocator_Stream(const QLinkedList< RTree::Data * > &dataList)" + ], + "QgsCheckBoxConfigDlg": [ + "QgsCheckBoxConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)" + ], + "QgsAttributeTableView": [ + "repaintRequested()", + "setModel(QgsAttributeTableFilterModel *filterModel)", + "_q_selectRow(int row)", + "selectRow(int row)", + "repaintRequested(const QModelIndexList &indexes)", + "finished()", + ], + "QgsAttributesDnDTree": [ + "setType(QgsAttributesDnDTree::Type value)", + "QgsAttributesDnDTree(QgsVectorLayer *layer, QWidget *parent=nullptr)", + "type() const", + "selectFirstMatchingItem(const QgsAttributesFormProperties::DnDTreeItemData &data)", + "Type", + ], + "QgsAbstractFeatureIteratorFromSource": [ + "QgsAbstractFeatureIteratorFromSource(T *source, bool ownSource, const QgsFeatureRequest &request)" + ], "QgsPointPatternFillSymbolLayer": ["createFromSld(QDomElement &element)"], - "QgsRasterProjector": ["precisionLabel(Precision precision)", "setPrecision(Precision precision)", "precision() const"], - "QgsColorBrewerPalette": ["listSchemeVariants(const QString &schemeName)", "listSchemes()", "listSchemeColors(const QString &schemeName, int colors)"], - "QgsDerivativeFilter": ["QgsDerivativeFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)"], - "QgsVertexMarker": ["setPenWidth(int width)", "QgsVertexMarker(QgsMapCanvas *mapCanvas)", "setIconType(int iconType)", "setIconSize(int iconSize)"], - "QgsAttributeFormLegacyInterface": ["QgsAttributeFormLegacyInterface(const QString &function, const QString &pyFormName, QgsAttributeForm *form)"], - "QgsGpsDetector": ["detectionFailed()", "connDestroyed(QObject *)", "advance()", "detected(const QgsGpsInformation &)", "QgsGpsDetector(const QString &portName)", "availablePorts()"], + "QgsRasterProjector": [ + "precisionLabel(Precision precision)", + "setPrecision(Precision precision)", + "precision() const", + ], + "QgsColorBrewerPalette": [ + "listSchemeVariants(const QString &schemeName)", + "listSchemes()", + "listSchemeColors(const QString &schemeName, int colors)", + ], + "QgsDerivativeFilter": [ + "QgsDerivativeFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)" + ], + "QgsVertexMarker": [ + "setPenWidth(int width)", + "QgsVertexMarker(QgsMapCanvas *mapCanvas)", + "setIconType(int iconType)", + "setIconSize(int iconSize)", + ], + "QgsAttributeFormLegacyInterface": [ + "QgsAttributeFormLegacyInterface(const QString &function, const QString &pyFormName, QgsAttributeForm *form)" + ], + "QgsGpsDetector": [ + "detectionFailed()", + "connDestroyed(QObject *)", + "advance()", + "detected(const QgsGpsInformation &)", + "QgsGpsDetector(const QString &portName)", + "availablePorts()", + ], "QgsSimpleLineSymbolLayerWidget": ["updatePatternIcon()"], "QgsMeshVariableStrokeWidthButton": ["widgetChanged()"], "QgsRunProcess": ["create(const QString &action, bool capture)"], - "pal::GeomFunction": ["findLineCircleIntersection(double cx, double cy, double radius, double x1, double y1, double x2, double y2, double &xRes, double &yRes)", "cross_product(double x1, double y1, double x2, double y2, double x3, double y3)"], - "QgsLayerTreeModelLegendNode": ["isEmbeddedInParent() const", "setUserLabel(const QString &userLabel)", "isScaleOK(double scale) const", "userLabel() const", "setEmbeddedInParent(bool embedded)"], - "QgsCollapsibleGroupBox": ["saveCollapsedState()", "saveCheckedState()", "saveKey() const", "QgsCollapsibleGroupBox(QWidget *parent=nullptr, QgsSettings *settings=nullptr)", "setSettings(QgsSettings *settings)", "QgsCollapsibleGroupBox(const QString &title, QWidget *parent=nullptr, QgsSettings *settings=nullptr)", "init()"], - "QgsFieldValidator": ["dateFormat() const", "QgsFieldValidator(QObject *parent, const QgsField &field, const QString &defaultValue, const QString &dateFormat=\"yyyy-MM-dd\")"], + "pal::GeomFunction": [ + "findLineCircleIntersection(double cx, double cy, double radius, double x1, double y1, double x2, double y2, double &xRes, double &yRes)", + "cross_product(double x1, double y1, double x2, double y2, double x3, double y3)", + ], + "QgsLayerTreeModelLegendNode": [ + "isEmbeddedInParent() const", + "setUserLabel(const QString &userLabel)", + "isScaleOK(double scale) const", + "userLabel() const", + "setEmbeddedInParent(bool embedded)", + ], + "QgsCollapsibleGroupBox": [ + "saveCollapsedState()", + "saveCheckedState()", + "saveKey() const", + "QgsCollapsibleGroupBox(QWidget *parent=nullptr, QgsSettings *settings=nullptr)", + "setSettings(QgsSettings *settings)", + "QgsCollapsibleGroupBox(const QString &title, QWidget *parent=nullptr, QgsSettings *settings=nullptr)", + "init()", + ], + "QgsFieldValidator": [ + "dateFormat() const", + 'QgsFieldValidator(QObject *parent, const QgsField &field, const QString &defaultValue, const QString &dateFormat="yyyy-MM-dd")', + ], "QgsDiagram": ["QgsDiagram(const QgsDiagram &other)", "clearCache()"], - "QgsSourceFieldsProperties": ["setRow(int row, int idx, const QgsField &field)", "QgsSourceFieldsProperties(QgsVectorLayer *layer, QWidget *parent=nullptr)", "apply()", "AttrColumns", "updateButtons()", "toggleEditing()", "loadRows()", "init()"], - "QgsCptCityAllRampsItem": ["QgsCptCityAllRampsItem(QgsCptCityDataItem *parent, const QString &name, const QVector< QgsCptCityDataItem * > &items)"], - "QgsExpressionBuilderDialog": ["setExpressionText(const QString &text)", "QgsExpressionBuilderDialog(QgsVectorLayer *layer, const QString &startText=QString(), QWidget *parent SIP_TRANSFERTHIS=nullptr, const QString &key=\"generic\", const QgsExpressionContext &context=QgsExpressionContext())", "expressionText()"], - "QgsUniqueValuesConfigDlg": ["QgsUniqueValuesConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)"], + "QgsSourceFieldsProperties": [ + "setRow(int row, int idx, const QgsField &field)", + "QgsSourceFieldsProperties(QgsVectorLayer *layer, QWidget *parent=nullptr)", + "apply()", + "AttrColumns", + "updateButtons()", + "toggleEditing()", + "loadRows()", + "init()", + ], + "QgsCptCityAllRampsItem": [ + "QgsCptCityAllRampsItem(QgsCptCityDataItem *parent, const QString &name, const QVector< QgsCptCityDataItem * > &items)" + ], + "QgsExpressionBuilderDialog": [ + "setExpressionText(const QString &text)", + 'QgsExpressionBuilderDialog(QgsVectorLayer *layer, const QString &startText=QString(), QWidget *parent SIP_TRANSFERTHIS=nullptr, const QString &key="generic", const QgsExpressionContext &context=QgsExpressionContext())', + "expressionText()", + ], + "QgsUniqueValuesConfigDlg": [ + "QgsUniqueValuesConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)" + ], "QgsUnitSelectionWidget": ["changed()"], - "QgsRendererRangeLabelFormat": ["setPrecision(int precision)", "setTrimTrailingZeroes(bool trimTrailingZeroes)", "formatNumber(double value) const", "setFormat(const QString &format)", "setFromDomElement(QDomElement &element)", "trimTrailingZeroes() const", "QgsRendererRangeLabelFormat(const QString &format, int precision=4, bool trimTrailingZeroes=false)", "format() const", "precision() const", "saveToDomElement(QDomElement &element)", "labelForRange(const QgsRendererRange &range) const"], + "QgsRendererRangeLabelFormat": [ + "setPrecision(int precision)", + "setTrimTrailingZeroes(bool trimTrailingZeroes)", + "formatNumber(double value) const", + "setFormat(const QString &format)", + "setFromDomElement(QDomElement &element)", + "trimTrailingZeroes() const", + "QgsRendererRangeLabelFormat(const QString &format, int precision=4, bool trimTrailingZeroes=false)", + "format() const", + "precision() const", + "saveToDomElement(QDomElement &element)", + "labelForRange(const QgsRendererRange &range) const", + ], "QgsAbstractLabelProvider": ["Flag"], - "QgsGmlFeatureClass": ["fields()", "geometryAttributes()", "fieldIndex(const QString &name)", "QgsGmlFeatureClass(const QString &name, const QString &path)", "path() const"], - "QgsCategorizedSymbolRendererWidget": ["changeCategorySymbol()", "QgsCategorizedSymbolRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", "addCategories()", "changeCategorizedSymbol()", "deleteCategories()", "updateUiFromRenderer()", "categoriesDoubleClicked(const QModelIndex &idx)", "deleteAllCategories()", "rowsMoved()", "showSymbolLevels()", "categoryColumnChanged(const QString &field)", "addCategory()", "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", "selectedCategoryList()", "populateCategories()"], - "QgsMessageViewer": ["setCheckBoxText(const QString &text)", "setCheckBoxState(Qt::CheckState state)", "checkBoxState()", "setCheckBoxVisible(bool visible)", "setCheckBoxQgsSettingsLabel(const QString &label)", "QgsMessageViewer(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags, bool deleteOnClose=true)", "setMessageAsPlainText(const QString &msg)", "setMessageAsHtml(const QString &msg)"], + "QgsGmlFeatureClass": [ + "fields()", + "geometryAttributes()", + "fieldIndex(const QString &name)", + "QgsGmlFeatureClass(const QString &name, const QString &path)", + "path() const", + ], + "QgsCategorizedSymbolRendererWidget": [ + "changeCategorySymbol()", + "QgsCategorizedSymbolRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", + "addCategories()", + "changeCategorizedSymbol()", + "deleteCategories()", + "updateUiFromRenderer()", + "categoriesDoubleClicked(const QModelIndex &idx)", + "deleteAllCategories()", + "rowsMoved()", + "showSymbolLevels()", + "categoryColumnChanged(const QString &field)", + "addCategory()", + "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", + "selectedCategoryList()", + "populateCategories()", + ], + "QgsMessageViewer": [ + "setCheckBoxText(const QString &text)", + "setCheckBoxState(Qt::CheckState state)", + "checkBoxState()", + "setCheckBoxVisible(bool visible)", + "setCheckBoxQgsSettingsLabel(const QString &label)", + "QgsMessageViewer(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags, bool deleteOnClose=true)", + "setMessageAsPlainText(const QString &msg)", + "setMessageAsHtml(const QString &msg)", + ], "QgsCurvePolygon": ["QgsCurvePolygon(const QgsCurvePolygon &p)"], - "QgsRuleBasedRenderer::Rule": ["setLabel(const QString &label)", "legendSymbolItems(int currentLevel=-1) const", "label() const", "save(QDomDocument &doc, QgsSymbolMap &symbolMap) const", "initFilter()", "dependsOnScale() const", "symbol()"], + "QgsRuleBasedRenderer::Rule": [ + "setLabel(const QString &label)", + "legendSymbolItems(int currentLevel=-1) const", + "label() const", + "save(QDomDocument &doc, QgsSymbolMap &symbolMap) const", + "initFilter()", + "dependsOnScale() const", + "symbol()", + ], "QgsValueRelationSearchWidgetWrapper": ["value() const"], - "QgsGml": ["dataReadProgress(int progress)", "totalStepsUpdate(int totalSteps)", "QgsGml(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields)"], - "QgsCptCitySelectionItem": ["QgsCptCitySelectionItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)", "parseXml()", "selectionsList() const"], - "QgsRasterFormatSaveOptionsWidget": ["apply()", "optionsChanged()", "QgsRasterFormatSaveOptionsWidget(QWidget *parent SIP_TRANSFERTHIS=nullptr, const QString &format=\"GTiff\", QgsRasterFormatSaveOptionsWidget::Type type=Default, const QString &provider=\"gdal\")", "Type"], - "QgsSymbolLayerAbstractMetadata": ["visibleName() const", "type() const", "name() const"], - "QgsMultiBandColorRenderer": ["setRedBand(int band)", "greenBand() const", "redBand() const", "create(const QDomElement &elem, QgsRasterInterface *input)", "blueBand() const", "setBlueBand(int band)", "QgsMultiBandColorRenderer(QgsRasterInterface *input, int redBand, int greenBand, int blueBand, QgsContrastEnhancement *redEnhancement=nullptr, QgsContrastEnhancement *greenEnhancement=nullptr, QgsContrastEnhancement *blueEnhancement=nullptr)", "setGreenBand(int band)"], + "QgsGml": [ + "dataReadProgress(int progress)", + "totalStepsUpdate(int totalSteps)", + "QgsGml(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields)", + ], + "QgsCptCitySelectionItem": [ + "QgsCptCitySelectionItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)", + "parseXml()", + "selectionsList() const", + ], + "QgsRasterFormatSaveOptionsWidget": [ + "apply()", + "optionsChanged()", + 'QgsRasterFormatSaveOptionsWidget(QWidget *parent SIP_TRANSFERTHIS=nullptr, const QString &format="GTiff", QgsRasterFormatSaveOptionsWidget::Type type=Default, const QString &provider="gdal")', + "Type", + ], + "QgsSymbolLayerAbstractMetadata": [ + "visibleName() const", + "type() const", + "name() const", + ], + "QgsMultiBandColorRenderer": [ + "setRedBand(int band)", + "greenBand() const", + "redBand() const", + "create(const QDomElement &elem, QgsRasterInterface *input)", + "blueBand() const", + "setBlueBand(int band)", + "QgsMultiBandColorRenderer(QgsRasterInterface *input, int redBand, int greenBand, int blueBand, QgsContrastEnhancement *redEnhancement=nullptr, QgsContrastEnhancement *greenEnhancement=nullptr, QgsContrastEnhancement *blueEnhancement=nullptr)", + "setGreenBand(int band)", + ], "QgsPreviewEffect": ["PreviewMode", "QgsPreviewEffect(QObject *parent)"], "QgsPixmapLabel": ["setPixmap(const QPixmap &)"], "QgsCapabilitiesCache": ["QgsCapabilitiesCache(int size)"], "QgsCompoundCurve": ["QgsCompoundCurve(const QgsCompoundCurve &curve)"], - "QgsVectorFileWriter::SetOption": ["SetOption(const QString &docString, const QStringList &values, const QString &defaultValue, bool allowNone=false)"], - "QgsVectorFileWriter::StringOption": ["StringOption(const QString &docString, const QString &defaultValue=QString())"], + "QgsVectorFileWriter::SetOption": [ + "SetOption(const QString &docString, const QStringList &values, const QString &defaultValue, bool allowNone=false)" + ], + "QgsVectorFileWriter::StringOption": [ + "StringOption(const QString &docString, const QString &defaultValue=QString())" + ], "QgsOWSSourceSelect": ["enableLayersForCrs(QTreeWidgetItem *item)"], - "QgsGeometry::Error": ["Error(const QString &m, const QgsPointXY &p)", "Error(const QString &m)"], + "QgsGeometry::Error": [ + "Error(const QString &m, const QgsPointXY &p)", + "Error(const QString &m)", + ], "QgisPlugin": ["name()"], "QgsXmlUtils": ["readRectangle(const QDomElement &element)"], - "QgsAttributeTableFilterModel": ["fidToIndexList(QgsFeatureId fid)", "mapFromMaster(const QModelIndex &sourceIndex) const", "mapToMaster(const QModelIndex &proxyIndex) const"], - "QgsVectorLayerLegendWidget": ["QgsVectorLayerLegendWidget(QWidget *parent=nullptr)"], + "QgsAttributeTableFilterModel": [ + "fidToIndexList(QgsFeatureId fid)", + "mapFromMaster(const QModelIndex &sourceIndex) const", + "mapToMaster(const QModelIndex &proxyIndex) const", + ], + "QgsVectorLayerLegendWidget": [ + "QgsVectorLayerLegendWidget(QWidget *parent=nullptr)" + ], "QgsSymbolRenderContext": ["setFeature(const QgsFeature *f)"], - "QgsDartMeasurement": ["send() const", "QgsDartMeasurement(const QString &name, Type type, const QString &value)", "Type", "toString() const"], - "QgsShapeburstFillSymbolLayer": ["setOffsetMapUnitScale(const QgsMapUnitScale &scale)", "setDistanceMapUnitScale(const QgsMapUnitScale &scale)", "offsetMapUnitScale() const", "distanceMapUnitScale() const"], - "QgsJoinDialog": ["QgsJoinDialog(QgsVectorLayer *layer, QList< QgsMapLayer * > alreadyJoinedLayers, QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())"], - "QgsGeometryLineLayerIntersectionCheck": ["factoryDescription()", "QgsGeometryLineLayerIntersectionCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"], - "QgsVectorFileWriter::IntOption": ["IntOption(const QString &docString, int defaultValue)"], - "QgsAttributeTableModel": ["Role", "idToIndex(QgsFeatureId id) const", "idToIndexList(QgsFeatureId id) const", "finished()"], - "QgsFeatureListModel": ["Role", "featureByIndex(const QModelIndex &index, QgsFeature &feat)", "mapSelectionFromMaster(const QItemSelection &selection) const", "mapToMaster(const QModelIndex &proxyIndex) const", "setSourceModel(QgsAttributeTableFilterModel *sourceModel)", "mapFromMaster(const QModelIndex &sourceIndex) const", "mapSelectionToMaster(const QItemSelection &selection) const", "fidToIndexList(QgsFeatureId fid)", "masterModel()", "displayExpression() const"], - "QgsColorEffectWidget": ["QgsColorEffectWidget(QWidget *parent=nullptr)", "create()"], - "QgsDetailedItemWidget": ["setChecked(bool flag)", "setData(const QgsDetailedItemData &data)"], - "QgsGeos": ["getGEOSHandler()", "coordSeqPoint(const GEOSCoordSequence *cs, int i, bool hasZ, bool hasM)", "fromGeosPolygon(const GEOSGeometry *geos)"], - "QgsRasterShaderFunction": ["QgsRasterShaderFunction(double minimumValue=0.0, double maximumValue=255.0)", "minimumMaximumRange() const"], - "QgsGeometryChecker": ["execute(int *totalSteps=nullptr)", "getContext() const", "getMessages() const", "setMergeAttributeIndices(const QMap< QString, int > &mergeAttributeIndices)", "QgsGeometryChecker(const QList< QgsGeometryCheck * > &checks, QgsGeometryCheckContext *context, const QMap< QString, QgsFeaturePool * > &featurePools)", "errorAdded(QgsGeometryCheckError *error)", "fixError(QgsGeometryCheckError *error, int method, bool triggerRepaint=false)", "featurePools() const", "errorUpdated(QgsGeometryCheckError *error, bool statusChanged)", "progressValue(int value)", "getChecks() const"], + "QgsDartMeasurement": [ + "send() const", + "QgsDartMeasurement(const QString &name, Type type, const QString &value)", + "Type", + "toString() const", + ], + "QgsShapeburstFillSymbolLayer": [ + "setOffsetMapUnitScale(const QgsMapUnitScale &scale)", + "setDistanceMapUnitScale(const QgsMapUnitScale &scale)", + "offsetMapUnitScale() const", + "distanceMapUnitScale() const", + ], + "QgsJoinDialog": [ + "QgsJoinDialog(QgsVectorLayer *layer, QList< QgsMapLayer * > alreadyJoinedLayers, QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())" + ], + "QgsGeometryLineLayerIntersectionCheck": [ + "factoryDescription()", + "QgsGeometryLineLayerIntersectionCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", + "ResolutionMethod", + "factoryCompatibleGeometryTypes()", + "factoryCheckType()", + "factoryIsCompatible(QgsVectorLayer *layer)", + "factoryId()", + ], + "QgsVectorFileWriter::IntOption": [ + "IntOption(const QString &docString, int defaultValue)" + ], + "QgsAttributeTableModel": [ + "Role", + "idToIndex(QgsFeatureId id) const", + "idToIndexList(QgsFeatureId id) const", + "finished()", + ], + "QgsFeatureListModel": [ + "Role", + "featureByIndex(const QModelIndex &index, QgsFeature &feat)", + "mapSelectionFromMaster(const QItemSelection &selection) const", + "mapToMaster(const QModelIndex &proxyIndex) const", + "setSourceModel(QgsAttributeTableFilterModel *sourceModel)", + "mapFromMaster(const QModelIndex &sourceIndex) const", + "mapSelectionToMaster(const QItemSelection &selection) const", + "fidToIndexList(QgsFeatureId fid)", + "masterModel()", + "displayExpression() const", + ], + "QgsColorEffectWidget": [ + "QgsColorEffectWidget(QWidget *parent=nullptr)", + "create()", + ], + "QgsDetailedItemWidget": [ + "setChecked(bool flag)", + "setData(const QgsDetailedItemData &data)", + ], + "QgsGeos": [ + "getGEOSHandler()", + "coordSeqPoint(const GEOSCoordSequence *cs, int i, bool hasZ, bool hasM)", + "fromGeosPolygon(const GEOSGeometry *geos)", + ], + "QgsRasterShaderFunction": [ + "QgsRasterShaderFunction(double minimumValue=0.0, double maximumValue=255.0)", + "minimumMaximumRange() const", + ], + "QgsGeometryChecker": [ + "execute(int *totalSteps=nullptr)", + "getContext() const", + "getMessages() const", + "setMergeAttributeIndices(const QMap< QString, int > &mergeAttributeIndices)", + "QgsGeometryChecker(const QList< QgsGeometryCheck * > &checks, QgsGeometryCheckContext *context, const QMap< QString, QgsFeaturePool * > &featurePools)", + "errorAdded(QgsGeometryCheckError *error)", + "fixError(QgsGeometryCheckError *error, int method, bool triggerRepaint=false)", + "featurePools() const", + "errorUpdated(QgsGeometryCheckError *error, bool statusChanged)", + "progressValue(int value)", + "getChecks() const", + ], "QgsRendererRulePropsDialog": ["buildExpression()", "testFilter()", "rule()"], - "QgsCptCityArchive": ["initArchives(bool loadAll=false)", "defaultArchive()", "archiveRegistry()", "initDefaultArchive()", "copyingInfo(const QString &fileName)", "isEmpty()", "baseDir(QString archiveName)", "archiveName() const", "findFileName(const QString &target, const QString &startDir, const QString &baseDir)", "defaultBaseDir()", "rootItems() const", "descFileName(const QString &dirName) const", "setBaseDir(const QString &dirName)", "copyingFileName(const QString &dirName) const", "QgsCptCityArchive(const QString &archiveName=DEFAULT_CPTCITY_ARCHIVE, const QString &baseDir=QString())", "baseDir() const", "clearArchives()", "description(const QString &fileName)", "initArchive(const QString &archiveName, const QString &archiveBaseDir)", "selectionItems() const"], - "QgsSingleBandGrayRenderer": ["gradient() const", "grayBand() const", "setGradient(Gradient gradient)", "create(const QDomElement &elem, QgsRasterInterface *input)", "Gradient", "QgsSingleBandGrayRenderer(QgsRasterInterface *input, int grayBand)", "setGrayBand(int band)", "contrastEnhancement() const"], - "QgsGeometryContainedCheck": ["factoryDescription()", "ResolutionMethod", "QgsGeometryContainedCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"], - "QgsVectorLayerJoinBuffer": ["vectorJoins() const", "QgsVectorLayerJoinBuffer(QgsVectorLayer *layer=nullptr)"], - "QgsAbstractFeatureSource": ["iteratorClosed(QgsAbstractFeatureIterator *it)", "iteratorOpened(QgsAbstractFeatureIterator *it)"], - "QgsRasterCalcNode": ["parseRasterCalcString(const QString &str, QString &parserErrorMsg)", "setRight(QgsRasterCalcNode *right)", "QgsRasterCalcNode(Operator op, QgsRasterCalcNode *left, QgsRasterCalcNode *right)", "QgsRasterCalcNode(QgsRasterMatrix *matrix)", "QgsRasterCalcNode(double number)", "type() const", "setLeft(QgsRasterCalcNode *left)", "QgsRasterCalcNode(const QString &rasterName)"], + "QgsCptCityArchive": [ + "initArchives(bool loadAll=false)", + "defaultArchive()", + "archiveRegistry()", + "initDefaultArchive()", + "copyingInfo(const QString &fileName)", + "isEmpty()", + "baseDir(QString archiveName)", + "archiveName() const", + "findFileName(const QString &target, const QString &startDir, const QString &baseDir)", + "defaultBaseDir()", + "rootItems() const", + "descFileName(const QString &dirName) const", + "setBaseDir(const QString &dirName)", + "copyingFileName(const QString &dirName) const", + "QgsCptCityArchive(const QString &archiveName=DEFAULT_CPTCITY_ARCHIVE, const QString &baseDir=QString())", + "baseDir() const", + "clearArchives()", + "description(const QString &fileName)", + "initArchive(const QString &archiveName, const QString &archiveBaseDir)", + "selectionItems() const", + ], + "QgsSingleBandGrayRenderer": [ + "gradient() const", + "grayBand() const", + "setGradient(Gradient gradient)", + "create(const QDomElement &elem, QgsRasterInterface *input)", + "Gradient", + "QgsSingleBandGrayRenderer(QgsRasterInterface *input, int grayBand)", + "setGrayBand(int band)", + "contrastEnhancement() const", + ], + "QgsGeometryContainedCheck": [ + "factoryDescription()", + "ResolutionMethod", + "QgsGeometryContainedCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", + "factoryCompatibleGeometryTypes()", + "factoryCheckType()", + "factoryIsCompatible(QgsVectorLayer *layer)", + "factoryId()", + ], + "QgsVectorLayerJoinBuffer": [ + "vectorJoins() const", + "QgsVectorLayerJoinBuffer(QgsVectorLayer *layer=nullptr)", + ], + "QgsAbstractFeatureSource": [ + "iteratorClosed(QgsAbstractFeatureIterator *it)", + "iteratorOpened(QgsAbstractFeatureIterator *it)", + ], + "QgsRasterCalcNode": [ + "parseRasterCalcString(const QString &str, QString &parserErrorMsg)", + "setRight(QgsRasterCalcNode *right)", + "QgsRasterCalcNode(Operator op, QgsRasterCalcNode *left, QgsRasterCalcNode *right)", + "QgsRasterCalcNode(QgsRasterMatrix *matrix)", + "QgsRasterCalcNode(double number)", + "type() const", + "setLeft(QgsRasterCalcNode *left)", + "QgsRasterCalcNode(const QString &rasterName)", + ], "QgsFields": ["FieldOrigin"], - "QgsSymbolSelectorDialog": ["lockLayer()", "removeLayer()", "updatePreview()", "addLayer()", "symbolModified()", "layerChanged()", "moveLayerUp()", "updateLayerPreview()", "moveLayerDown()"], + "QgsSymbolSelectorDialog": [ + "lockLayer()", + "removeLayer()", + "updatePreview()", + "addLayer()", + "symbolModified()", + "layerChanged()", + "moveLayerUp()", + "updateLayerPreview()", + "moveLayerDown()", + ], "QgsEffectStack": ["QgsEffectStack(const QgsEffectStack &other)"], - "QgsRelationReferenceWidget": ["setRelation(const QgsRelation &relation, bool allowNullValue)", "CanvasExtent", "setOpenFormButtonVisible(bool openFormButtonVisible)", "QgsRelationReferenceWidget(QWidget *parent)", "setReadOnlySelector(bool readOnly)", "setRelationEditable(bool editable)", "init()", "setAllowMapIdentification(bool allowMapIdentification)", "setEmbedForm(bool display)"], - "QgsDiagramProperties": ["mAttributesTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column)", "scalingTypeChanged()", "mAddCategoryPushButton_clicked()", "mEngineSettingsButton_clicked()", "apply()", "mRemoveCategoryPushButton_clicked()", "showSizeLegendDialog()", "QgsDiagramProperties(QgsVectorLayer *layer, QWidget *parent, QgsMapCanvas *canvas)", "mDiagramAttributesTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column)", "mDiagramStackedWidget_currentChanged(int index)", "mDiagramTypeComboBox_currentIndexChanged(int index)", "mFindMaximumValueButton_clicked()", "showAddAttributeExpressionDialog()", "auxiliaryFieldCreated()", "updatePlacementWidgets()"], - "QgsStackedDiagramProperties": ["apply()", "auxiliaryFieldCreated()", "QgsStackedDiagramProperties(QgsVectorLayer *layer, QWidget *parent, QgsMapCanvas *canvas)"], - "QgsDiagramWidget": ["mDiagramTypeComboBox_currentIndexChanged(int index)", "showEngineConfigDialog()"], - "QgsFeatureListView": ["repaintRequested()", "repaintRequested(const QModelIndexList &indexes)"], - "QgsGradientFillSymbolLayerWidget": ["setGradientSpread(int index)", "setColor(const QColor &color)", "setCoordinateMode(int index)", "setColor2(const QColor &color)", "setGradientType(int index)"], + "QgsRelationReferenceWidget": [ + "setRelation(const QgsRelation &relation, bool allowNullValue)", + "CanvasExtent", + "setOpenFormButtonVisible(bool openFormButtonVisible)", + "QgsRelationReferenceWidget(QWidget *parent)", + "setReadOnlySelector(bool readOnly)", + "setRelationEditable(bool editable)", + "init()", + "setAllowMapIdentification(bool allowMapIdentification)", + "setEmbedForm(bool display)", + ], + "QgsDiagramProperties": [ + "mAttributesTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column)", + "scalingTypeChanged()", + "mAddCategoryPushButton_clicked()", + "mEngineSettingsButton_clicked()", + "apply()", + "mRemoveCategoryPushButton_clicked()", + "showSizeLegendDialog()", + "QgsDiagramProperties(QgsVectorLayer *layer, QWidget *parent, QgsMapCanvas *canvas)", + "mDiagramAttributesTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column)", + "mDiagramStackedWidget_currentChanged(int index)", + "mDiagramTypeComboBox_currentIndexChanged(int index)", + "mFindMaximumValueButton_clicked()", + "showAddAttributeExpressionDialog()", + "auxiliaryFieldCreated()", + "updatePlacementWidgets()", + ], + "QgsStackedDiagramProperties": [ + "apply()", + "auxiliaryFieldCreated()", + "QgsStackedDiagramProperties(QgsVectorLayer *layer, QWidget *parent, QgsMapCanvas *canvas)", + ], + "QgsDiagramWidget": [ + "mDiagramTypeComboBox_currentIndexChanged(int index)", + "showEngineConfigDialog()", + ], + "QgsFeatureListView": [ + "repaintRequested()", + "repaintRequested(const QModelIndexList &indexes)", + ], + "QgsGradientFillSymbolLayerWidget": [ + "setGradientSpread(int index)", + "setColor(const QColor &color)", + "setCoordinateMode(int index)", + "setColor2(const QColor &color)", + "setGradientType(int index)", + ], "QgsFillSymbol": ["setAngle(double angle) const"], - "QgsSmartGroupCondition": ["QgsSmartGroupCondition(int id, QWidget *parent=nullptr)", "removed(int)", "destruct()"], - "QgsRasterRendererRegistry": ["insert(const QgsRasterRendererRegistryEntry &entry)", "entries() const", "renderersList() const", "insertWidgetFunction(const QString &rendererName, QgsRasterRendererWidgetCreateFunc func)", "rendererData(const QString &rendererName, QgsRasterRendererRegistryEntry &data) const"], - "QgsAdvancedDigitizingCanvasItem": ["QgsAdvancedDigitizingCanvasItem(QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget)"], + "QgsSmartGroupCondition": [ + "QgsSmartGroupCondition(int id, QWidget *parent=nullptr)", + "removed(int)", + "destruct()", + ], + "QgsRasterRendererRegistry": [ + "insert(const QgsRasterRendererRegistryEntry &entry)", + "entries() const", + "renderersList() const", + "insertWidgetFunction(const QString &rendererName, QgsRasterRendererWidgetCreateFunc func)", + "rendererData(const QString &rendererName, QgsRasterRendererRegistryEntry &data) const", + ], + "QgsAdvancedDigitizingCanvasItem": [ + "QgsAdvancedDigitizingCanvasItem(QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget)" + ], "QgsSimplifyMethod": ["MethodType"], - "QgsExpressionItem": ["QgsExpressionItem(const QString &label, const QString &expressionText, QgsExpressionItem::ItemType itemType=ExpressionNode)", "ItemType", "QgsExpressionItem(const QString &label, const QString &expressionText, const QString &helpText, QgsExpressionItem::ItemType itemType=ExpressionNode)", "getExpressionText() const"], - "QgsCptCityBrowserModel": ["endInsertItems()", "connectItem(QgsCptCityDataItem *item)", "QgsCptCityBrowserModel(QObject *parent=nullptr, QgsCptCityArchive *archive=QgsCptCityArchive::defaultArchive(), ViewType Type=Authors)", "refresh(const QString &path)", "reload()", "findItem(QgsCptCityDataItem *item, QgsCptCityDataItem *parent=nullptr) const", "refresh(const QModelIndex &index=QModelIndex())", "addRootItems()", "beginRemoveItems(QgsCptCityDataItem *parent, int first, int last)", "removeRootItems()", "endRemoveItems()", "ViewType", "beginInsertItems(QgsCptCityDataItem *parent, int first, int last)"], - "QgsDxfPaintEngine": ["setLayer(const QString &layer)", "layer() const", "setShift(QPointF shift)", "QgsDxfPaintEngine(const QgsDxfPaintDevice *dxfDevice, QgsDxfExport *dxf)"], + "QgsExpressionItem": [ + "QgsExpressionItem(const QString &label, const QString &expressionText, QgsExpressionItem::ItemType itemType=ExpressionNode)", + "ItemType", + "QgsExpressionItem(const QString &label, const QString &expressionText, const QString &helpText, QgsExpressionItem::ItemType itemType=ExpressionNode)", + "getExpressionText() const", + ], + "QgsCptCityBrowserModel": [ + "endInsertItems()", + "connectItem(QgsCptCityDataItem *item)", + "QgsCptCityBrowserModel(QObject *parent=nullptr, QgsCptCityArchive *archive=QgsCptCityArchive::defaultArchive(), ViewType Type=Authors)", + "refresh(const QString &path)", + "reload()", + "findItem(QgsCptCityDataItem *item, QgsCptCityDataItem *parent=nullptr) const", + "refresh(const QModelIndex &index=QModelIndex())", + "addRootItems()", + "beginRemoveItems(QgsCptCityDataItem *parent, int first, int last)", + "removeRootItems()", + "endRemoveItems()", + "ViewType", + "beginInsertItems(QgsCptCityDataItem *parent, int first, int last)", + ], + "QgsDxfPaintEngine": [ + "setLayer(const QString &layer)", + "layer() const", + "setShift(QPointF shift)", + "QgsDxfPaintEngine(const QgsDxfPaintDevice *dxfDevice, QgsDxfExport *dxf)", + ], "QgsGeometryRubberBand": ["IconType"], "QgsProject": ["relationManager() const"], - "QgsMapLayerLegendUtils": ["hasLegendNodeOrder(QgsLayerTreeLayer *nodeLayer)", "legendNodeOrder(QgsLayerTreeLayer *nodeLayer)", "hasLegendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex)", "legendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex)", "setLegendNodeOrder(QgsLayerTreeLayer *nodeLayer, const QList< int > &order)", "setLegendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex, const QString &newLabel)"], + "QgsMapLayerLegendUtils": [ + "hasLegendNodeOrder(QgsLayerTreeLayer *nodeLayer)", + "legendNodeOrder(QgsLayerTreeLayer *nodeLayer)", + "hasLegendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex)", + "legendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex)", + "setLegendNodeOrder(QgsLayerTreeLayer *nodeLayer, const QList< int > &order)", + "setLegendNodeUserLabel(QgsLayerTreeLayer *nodeLayer, int originalIndex, const QString &newLabel)", + ], "QgsTransformWidget": ["create()", "QgsTransformWidget(QWidget *parent=nullptr)"], "QgsBusyIndicatorDialog": ["message() const", "setMessage(const QString &message)"], - "QgsSingleBandPseudoColorRenderer": ["classificationMax() const", "setClassificationMax(double max)", "create(const QDomElement &elem, QgsRasterInterface *input)", "setClassificationMin(double min)", "classificationMin() const"], - "QgsShapeburstFillSymbolLayerWidget": ["setColor2(const QColor &color)", "setColor(const QColor &color)"], + "QgsSingleBandPseudoColorRenderer": [ + "classificationMax() const", + "setClassificationMax(double max)", + "create(const QDomElement &elem, QgsRasterInterface *input)", + "setClassificationMin(double min)", + "classificationMin() const", + ], + "QgsShapeburstFillSymbolLayerWidget": [ + "setColor2(const QColor &color)", + "setColor(const QColor &color)", + ], "QgsExpression": ["SpatialOperator", "BuiltinFunctions()", "Functions()"], "EditBlockerDelegate": ["EditBlockerDelegate(QObject *parent=nullptr)"], - "QgsGeometryMultipartCheck": ["factoryDescription()", "QgsGeometryMultipartCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"], - "QgsGenericFeatureSelectionManager": ["QgsGenericFeatureSelectionManager(QObject *parent=nullptr)", "QgsGenericFeatureSelectionManager(const QgsFeatureIds &initialSelection, QObject *parent=nullptr)"], + "QgsGeometryMultipartCheck": [ + "factoryDescription()", + "QgsGeometryMultipartCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", + "ResolutionMethod", + "factoryCompatibleGeometryTypes()", + "factoryCheckType()", + "factoryIsCompatible(QgsVectorLayer *layer)", + "factoryId()", + ], + "QgsGenericFeatureSelectionManager": [ + "QgsGenericFeatureSelectionManager(QObject *parent=nullptr)", + "QgsGenericFeatureSelectionManager(const QgsFeatureIds &initialSelection, QObject *parent=nullptr)", + ], "QgsAbstractGeometry": ["QgsAbstractGeometry(const QgsAbstractGeometry &geom)"], - "QgsMeshDatasetGroupSaveMenu": ["createSaveMenu(int groupIndex, QMenu *parentMenu=nullptr)", "setMeshLayer(QgsMeshLayer *meshLayer)", "QgsMeshDatasetGroupSaveMenu(QObject *parent=nullptr)", "datasetGroupSaved(const QString &uri)"], - "QgsBrightnessContrastFilter": ["QgsBrightnessContrastFilter(QgsRasterInterface *input=nullptr)"], - "QgsRasterRenderer": ["rasterTransparency() const", "usesTransparency() const", "setAlphaBand(int band)", "alphaBand() const", "setRasterTransparency(QgsRasterTransparency *t)"], + "QgsMeshDatasetGroupSaveMenu": [ + "createSaveMenu(int groupIndex, QMenu *parentMenu=nullptr)", + "setMeshLayer(QgsMeshLayer *meshLayer)", + "QgsMeshDatasetGroupSaveMenu(QObject *parent=nullptr)", + "datasetGroupSaved(const QString &uri)", + ], + "QgsBrightnessContrastFilter": [ + "QgsBrightnessContrastFilter(QgsRasterInterface *input=nullptr)" + ], + "QgsRasterRenderer": [ + "rasterTransparency() const", + "usesTransparency() const", + "setAlphaBand(int band)", + "alphaBand() const", + "setRasterTransparency(QgsRasterTransparency *t)", + ], "QgsDiagramLayerSettings": ["Placement"], - "QgsPalettedRendererWidget": ["create(QgsRasterLayer *layer, const QgsRectangle &extent)", "QgsPalettedRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent=QgsRectangle())"], + "QgsPalettedRendererWidget": [ + "create(QgsRasterLayer *layer, const QgsRectangle &extent)", + "QgsPalettedRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent=QgsRectangle())", + ], "CharacterWidget": ["updateFontMerging(bool enable)"], "QgsDataDefinedValueDialog": ["dataDefinedChanged()"], - "QgsSlopeFilter": ["QgsSlopeFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)"], - "QgsLayerPropertiesWidget": ["populateLayerTypes()", "changed()", "changeLayer(QgsSymbolLayer *)", "emitSignalChanged()", "layerTypeChanged()", "updateSymbolLayerWidget(QgsSymbolLayer *layer)"], - "QgsVectorLayerCache": ["QgsVectorLayerCache(QgsVectorLayer *layer, int cacheSize, QObject *parent=nullptr)"], + "QgsSlopeFilter": [ + "QgsSlopeFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)" + ], + "QgsLayerPropertiesWidget": [ + "populateLayerTypes()", + "changed()", + "changeLayer(QgsSymbolLayer *)", + "emitSignalChanged()", + "layerTypeChanged()", + "updateSymbolLayerWidget(QgsSymbolLayer *layer)", + ], + "QgsVectorLayerCache": [ + "QgsVectorLayerCache(QgsVectorLayer *layer, int cacheSize, QObject *parent=nullptr)" + ], "QgsAttributeTableAction": ["execute()", "featureForm()"], - "QgsAttributesFormProperties::DnDTreeItemData": ["visibilityExpression() const", "setQmlElementEditorConfiguration(QmlElementEditorConfiguration qmlElementEditorConfiguration)", "operator QVariant()", "setType(Type type)", "setShowLabel(bool showLabel)", "setDisplayName(const QString &displayName)", "DnDTreeItemData(Type type, const QString &name, const QString &displayName, const QColor &backgroundColor=QColor())", "setColumnCount(int count)", "displayName() const", "backgroundColor() const", "columnCount() const", "htmlElementEditorConfiguration() const", "type() const", "setHtmlElementEditorConfiguration(HtmlElementEditorConfiguration htmlElementEditorConfiguration)", "Type", "name() const", "relationEditorConfiguration() const", "qmlElementEditorConfiguration() const", "showLabel() const", "DnDTreeItemData()=default", "setRelationEditorConfiguration(RelationEditorConfiguration relationEditorConfiguration)", "setName(const QString &name)", "setBackgroundColor(const QColor &backgroundColor)"], - "QgsVectorFieldSymbolLayer": ["angleUnits() const", "vectorFieldType() const", "createFromSld(QDomElement &element)", "xAttribute() const", "setAngleOrientation(AngleOrientation orientation)", "setScale(double s)", "AngleUnits", "setVectorFieldType(VectorFieldType type)", "yAttribute() const", "scale() const", "setXAttribute(const QString &attribute)", "AngleOrientation", "setAngleUnits(AngleUnits units)", "setDistanceMapUnitScale(const QgsMapUnitScale &scale)", "angleOrientation() const", "setYAttribute(const QString &attribute)", "distanceMapUnitScale() const", "VectorFieldType"], - "QgsGeometryEngine": ["simplify(double tolerance, QString *errorMsg=nullptr) const =0", "interpolate(double distance, QString *errorMsg=nullptr) const =0", "envelope(QString *errorMsg=nullptr) const =0", "QgsGeometryEngine(const QgsAbstractGeometry *geometry)", "isEmpty(QString *errorMsg) const =0", "buffer(double distance, int segments, QString *errorMsg=nullptr) const =0", "area(QString *errorMsg=nullptr) const =0", "length(QString *errorMsg=nullptr) const =0"], + "QgsAttributesFormProperties::DnDTreeItemData": [ + "visibilityExpression() const", + "setQmlElementEditorConfiguration(QmlElementEditorConfiguration qmlElementEditorConfiguration)", + "operator QVariant()", + "setType(Type type)", + "setShowLabel(bool showLabel)", + "setDisplayName(const QString &displayName)", + "DnDTreeItemData(Type type, const QString &name, const QString &displayName, const QColor &backgroundColor=QColor())", + "setColumnCount(int count)", + "displayName() const", + "backgroundColor() const", + "columnCount() const", + "htmlElementEditorConfiguration() const", + "type() const", + "setHtmlElementEditorConfiguration(HtmlElementEditorConfiguration htmlElementEditorConfiguration)", + "Type", + "name() const", + "relationEditorConfiguration() const", + "qmlElementEditorConfiguration() const", + "showLabel() const", + "DnDTreeItemData()=default", + "setRelationEditorConfiguration(RelationEditorConfiguration relationEditorConfiguration)", + "setName(const QString &name)", + "setBackgroundColor(const QColor &backgroundColor)", + ], + "QgsVectorFieldSymbolLayer": [ + "angleUnits() const", + "vectorFieldType() const", + "createFromSld(QDomElement &element)", + "xAttribute() const", + "setAngleOrientation(AngleOrientation orientation)", + "setScale(double s)", + "AngleUnits", + "setVectorFieldType(VectorFieldType type)", + "yAttribute() const", + "scale() const", + "setXAttribute(const QString &attribute)", + "AngleOrientation", + "setAngleUnits(AngleUnits units)", + "setDistanceMapUnitScale(const QgsMapUnitScale &scale)", + "angleOrientation() const", + "setYAttribute(const QString &attribute)", + "distanceMapUnitScale() const", + "VectorFieldType", + ], + "QgsGeometryEngine": [ + "simplify(double tolerance, QString *errorMsg=nullptr) const =0", + "interpolate(double distance, QString *errorMsg=nullptr) const =0", + "envelope(QString *errorMsg=nullptr) const =0", + "QgsGeometryEngine(const QgsAbstractGeometry *geometry)", + "isEmpty(QString *errorMsg) const =0", + "buffer(double distance, int segments, QString *errorMsg=nullptr) const =0", + "area(QString *errorMsg=nullptr) const =0", + "length(QString *errorMsg=nullptr) const =0", + ], "QgsRenderContext": ["QgsRenderContext(const QgsRenderContext &rh)"], - "QgsCptCityDirectoryItem": ["dataItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)", "QgsCptCityDirectoryItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)", "dirEntries() const", "rampsMap()"], + "QgsCptCityDirectoryItem": [ + "dataItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)", + "QgsCptCityDirectoryItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)", + "dirEntries() const", + "rampsMap()", + ], "QgsGeometryValidator": ["addError(const QgsGeometry::Error &)", "stop()"], "QgsWms::QgsWmsParameters": ["PdfFormatOption"], - "QgsConstWkbPtr": ["operator>>(float &r) const", "operator const unsigned char *() const", "operator-=(int n) const", "operator+=(int n) const", "QgsConstWkbPtr(const unsigned char *p, int size)", "operator>>(double &v) const", "operator>>(int &v) const", "operator>>(unsigned int &v) const", "operator>>(char &v) const"], - "QgsLineSymbolLayer": ["widthMapUnitScale() const", "setWidthMapUnitScale(const QgsMapUnitScale &scale)", "QgsLineSymbolLayer(bool locked=false)"], - "QgsMapOverviewCanvas": ["updateFullExtent()", "mapRenderingFinished()", "enableAntiAliasing(bool flag)", "QgsMapOverviewCanvas(QWidget *parent=nullptr, QgsMapCanvas *mapCanvas=nullptr)"], - "QgsDxfPaintDevice": ["setLayer(const QString &layer)", "QgsDxfPaintDevice(QgsDxfExport *dxf)", "setOutputSize(const QRectF &r)", "setDrawingSize(QSizeF size)", "setShift(QPointF shift)"], - "QgsVectorLayerEditPassthrough": ["QgsVectorLayerEditPassthrough(QgsVectorLayer *layer)"], - "QgsGeometrySelfContactCheck": ["QgsGeometrySelfContactCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "factoryDescription()", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"], - "QgsCollapsibleGroupBoxBasic": ["clearModifiers()", "titleRect() const", "QgsCollapsibleGroupBoxBasic(QWidget *parent=nullptr)", "QgsCollapsibleGroupBoxBasic(const QString &title, QWidget *parent=nullptr)", "checkToggled(bool ckd)", "checkClicked(bool ckd)", "toggleCollapsed()", "updateStyle()", "init()"], - "QgsPenJoinStyleComboBox": ["setPenJoinStyle(Qt::PenJoinStyle style)", "QgsPenJoinStyleComboBox(QWidget *parent=nullptr)", "penJoinStyle() const"], - "QgsAttributeActionPropertiesDialog": ["QgsAttributeActionPropertiesDialog(QgsVectorLayer *layer, QWidget *parent=nullptr)", "shortTitle() const", "notificationMessage() const", "type() const", "description() const", "actionText() const", "isEnabledOnlyWhenEditable() const", "capture() const", "iconPath() const", "actionScopes() const"], - "QgsInterpolator": ["QgsInterpolator(const QList< QgsInterpolator::LayerData > &layerData)"], - "QgsCptCityCollectionItem": ["setPopulated()", "childrenRamps(bool recursive)", "addChild(QgsCptCityDataItem *item)", "QgsCptCityCollectionItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)"], + "QgsConstWkbPtr": [ + "operator>>(float &r) const", + "operator const unsigned char *() const", + "operator-=(int n) const", + "operator+=(int n) const", + "QgsConstWkbPtr(const unsigned char *p, int size)", + "operator>>(double &v) const", + "operator>>(int &v) const", + "operator>>(unsigned int &v) const", + "operator>>(char &v) const", + ], + "QgsLineSymbolLayer": [ + "widthMapUnitScale() const", + "setWidthMapUnitScale(const QgsMapUnitScale &scale)", + "QgsLineSymbolLayer(bool locked=false)", + ], + "QgsMapOverviewCanvas": [ + "updateFullExtent()", + "mapRenderingFinished()", + "enableAntiAliasing(bool flag)", + "QgsMapOverviewCanvas(QWidget *parent=nullptr, QgsMapCanvas *mapCanvas=nullptr)", + ], + "QgsDxfPaintDevice": [ + "setLayer(const QString &layer)", + "QgsDxfPaintDevice(QgsDxfExport *dxf)", + "setOutputSize(const QRectF &r)", + "setDrawingSize(QSizeF size)", + "setShift(QPointF shift)", + ], + "QgsVectorLayerEditPassthrough": [ + "QgsVectorLayerEditPassthrough(QgsVectorLayer *layer)" + ], + "QgsGeometrySelfContactCheck": [ + "QgsGeometrySelfContactCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", + "factoryDescription()", + "ResolutionMethod", + "factoryCompatibleGeometryTypes()", + "factoryCheckType()", + "factoryIsCompatible(QgsVectorLayer *layer)", + "factoryId()", + ], + "QgsCollapsibleGroupBoxBasic": [ + "clearModifiers()", + "titleRect() const", + "QgsCollapsibleGroupBoxBasic(QWidget *parent=nullptr)", + "QgsCollapsibleGroupBoxBasic(const QString &title, QWidget *parent=nullptr)", + "checkToggled(bool ckd)", + "checkClicked(bool ckd)", + "toggleCollapsed()", + "updateStyle()", + "init()", + ], + "QgsPenJoinStyleComboBox": [ + "setPenJoinStyle(Qt::PenJoinStyle style)", + "QgsPenJoinStyleComboBox(QWidget *parent=nullptr)", + "penJoinStyle() const", + ], + "QgsAttributeActionPropertiesDialog": [ + "QgsAttributeActionPropertiesDialog(QgsVectorLayer *layer, QWidget *parent=nullptr)", + "shortTitle() const", + "notificationMessage() const", + "type() const", + "description() const", + "actionText() const", + "isEnabledOnlyWhenEditable() const", + "capture() const", + "iconPath() const", + "actionScopes() const", + ], + "QgsInterpolator": [ + "QgsInterpolator(const QList< QgsInterpolator::LayerData > &layerData)" + ], + "QgsCptCityCollectionItem": [ + "setPopulated()", + "childrenRamps(bool recursive)", + "addChild(QgsCptCityDataItem *item)", + "QgsCptCityCollectionItem(QgsCptCityDataItem *parent, const QString &name, const QString &path)", + ], "QgsRasterChecker": ["report() const"], - "QgsRasterInterface": ["yBlockSize() const", "ySize() const", "QgsRasterInterface(QgsRasterInterface *input=nullptr)"], + "QgsRasterInterface": [ + "yBlockSize() const", + "ySize() const", + "QgsRasterInterface(QgsRasterInterface *input=nullptr)", + ], "HalfEdge": ["HalfEdge(int dual, int next, int point, bool mbreak, bool forced)"], - "QgsRasterLayerRenderer": ["QgsRasterLayerRenderer(QgsRasterLayer *layer, QgsRenderContext &rendererContext)"], - "QgsGeometrySelfIntersectionCheck": ["QgsGeometrySelfIntersectionCheck(const QgsGeometryCheckContext *context, const QVariantMap &configuration=QVariantMap())", "ResolutionMethod"], + "QgsRasterLayerRenderer": [ + "QgsRasterLayerRenderer(QgsRasterLayer *layer, QgsRenderContext &rendererContext)" + ], + "QgsGeometrySelfIntersectionCheck": [ + "QgsGeometrySelfIntersectionCheck(const QgsGeometryCheckContext *context, const QVariantMap &configuration=QVariantMap())", + "ResolutionMethod", + ], "QgsOfflineEditing": ["ProgressMode"], - "QgsMeshDatasetGroupTreeView": ["resetDefault(QgsMeshLayer *meshLayer)", "apply()", "selectAllGroups()", "QgsMeshDatasetGroupTreeView(QWidget *parent=nullptr)", "syncToLayer(QgsMeshLayer *layer)", "deselectAllGroups()", "datasetGroupTreeRootItem()"], + "QgsMeshDatasetGroupTreeView": [ + "resetDefault(QgsMeshLayer *meshLayer)", + "apply()", + "selectAllGroups()", + "QgsMeshDatasetGroupTreeView(QWidget *parent=nullptr)", + "syncToLayer(QgsMeshLayer *layer)", + "deselectAllGroups()", + "datasetGroupTreeRootItem()", + ], "QgsMapLayerComboBox": ["indexChanged(int i)", "rowsChanged()"], - "QgsGeometryTypeCheck": ["factoryDescription()", "QgsGeometryTypeCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration, int allowedTypes)", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"], - "QgsRendererWidget": ["QgsRendererWidget(QgsVectorLayer *layer, QgsStyle *style)", "copy()", "contextMenuViewCategories(QPoint p)", "paste()", "refreshSymbolView()"], - "QgsVectorLayerProperties": ["toggleEditing(QgsMapLayer *)", "exportAuxiliaryLayer(QgsAuxiliaryLayer *layer)", "QgsVectorLayerProperties(QgsMapCanvas *canvas, QgsMessageBar *messageBar, QgsVectorLayer *lyr=nullptr, QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)"], - "QgsGeometrySelfIntersectionCheckError": ["QgsGeometrySelfIntersectionCheckError(const QgsSingleGeometryCheck *check, const QgsGeometry &geometry, const QgsGeometry &errorLocation, QgsVertexId vertexId, const QgsGeometryUtils::SelfIntersection &intersection)", "intersection() const"], - "QgsSingleSymbolRendererWidget": ["QgsSingleSymbolRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)"], + "QgsGeometryTypeCheck": [ + "factoryDescription()", + "QgsGeometryTypeCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration, int allowedTypes)", + "factoryCompatibleGeometryTypes()", + "factoryCheckType()", + "factoryIsCompatible(QgsVectorLayer *layer)", + "factoryId()", + ], + "QgsRendererWidget": [ + "QgsRendererWidget(QgsVectorLayer *layer, QgsStyle *style)", + "copy()", + "contextMenuViewCategories(QPoint p)", + "paste()", + "refreshSymbolView()", + ], + "QgsVectorLayerProperties": [ + "toggleEditing(QgsMapLayer *)", + "exportAuxiliaryLayer(QgsAuxiliaryLayer *layer)", + "QgsVectorLayerProperties(QgsMapCanvas *canvas, QgsMessageBar *messageBar, QgsVectorLayer *lyr=nullptr, QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)", + ], + "QgsGeometrySelfIntersectionCheckError": [ + "QgsGeometrySelfIntersectionCheckError(const QgsSingleGeometryCheck *check, const QgsGeometry &geometry, const QgsGeometry &errorLocation, QgsVertexId vertexId, const QgsGeometryUtils::SelfIntersection &intersection)", + "intersection() const", + ], + "QgsSingleSymbolRendererWidget": [ + "QgsSingleSymbolRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", + "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", + ], "QgsCategorizedSymbolRenderer": ["rebuildHash()"], "QgsDualView": ["openConditionalStyles()"], - "QgsRuleBasedLabelProvider": ["QgsRuleBasedLabelProvider(const QgsRuleBasedLabeling &rules, QgsVectorLayer *layer, bool withFeatureLoop=true)"], + "QgsRuleBasedLabelProvider": [ + "QgsRuleBasedLabelProvider(const QgsRuleBasedLabeling &rules, QgsVectorLayer *layer, bool withFeatureLoop=true)" + ], "QgsMapToolAdvancedDigitizing": ["cadDockWidget() const"], - "QgsOptionsDialogBase": ["warnAboutMissingObjects()", "updateWindowTitle()", "setSettings(QgsSettings *settings)"], - "QgsSymbolsListWidget": ["updateDataDefinedMarkerAngle()", "setMarkerSize(double size)", "changed()", "setLineWidth(double width)", "updateDataDefinedMarkerSize()", "setMarkerAngle(double angle)", "clipFeaturesToggled(bool checked)", "updateDataDefinedLineWidth()", "setSymbolColor(const QColor &color)"], - "QgsRasterShader": ["rasterShaderFunction() const", "QgsRasterShader(double minimumValue=0.0, double maximumValue=255.0)", "rasterShaderFunction()"], - "QgsGeometryAreaCheck": ["factoryDescription()", "QgsGeometryAreaCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"], - "QgsWkbPtr": ["operator>>(float &r) const", "QgsWkbPtr(unsigned char *p, int size)", "operator+=(int n) const", "operator>>(double &v) const", "operator unsigned char *() const"], + "QgsOptionsDialogBase": [ + "warnAboutMissingObjects()", + "updateWindowTitle()", + "setSettings(QgsSettings *settings)", + ], + "QgsSymbolsListWidget": [ + "updateDataDefinedMarkerAngle()", + "setMarkerSize(double size)", + "changed()", + "setLineWidth(double width)", + "updateDataDefinedMarkerSize()", + "setMarkerAngle(double angle)", + "clipFeaturesToggled(bool checked)", + "updateDataDefinedLineWidth()", + "setSymbolColor(const QColor &color)", + ], + "QgsRasterShader": [ + "rasterShaderFunction() const", + "QgsRasterShader(double minimumValue=0.0, double maximumValue=255.0)", + "rasterShaderFunction()", + ], + "QgsGeometryAreaCheck": [ + "factoryDescription()", + "QgsGeometryAreaCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", + "ResolutionMethod", + "factoryCompatibleGeometryTypes()", + "factoryCheckType()", + "factoryIsCompatible(QgsVectorLayer *layer)", + "factoryId()", + ], + "QgsWkbPtr": [ + "operator>>(float &r) const", + "QgsWkbPtr(unsigned char *p, int size)", + "operator+=(int n) const", + "operator>>(double &v) const", + "operator unsigned char *() const", + ], "QgsMapToolEdit": ["QgsMapToolEdit(QgsMapCanvas *canvas)"], "QgsSymbolLegendNode": ["iconSize() const"], - "QgsDataDefinedSizeDialog": ["QgsDataDefinedSizeDialog(const QList< QgsSymbol * > &symbolList, QgsVectorLayer *layer)"], - "QgsGeometryDuplicateNodesCheck": ["QgsGeometryDuplicateNodesCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "factoryDescription()", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"], - "QgsTotalCurvatureFilter": ["QgsTotalCurvatureFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)"], - "QgsAttributeFormInterface": ["featureChanged()", "form()", "feature()", "QgsAttributeFormInterface(QgsAttributeForm *form)", "acceptChanges(const QgsFeature &feature)", "initForm()"], - "QgsGeometryPointCoveredByLineCheck": ["factoryDescription()", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "QgsGeometryPointCoveredByLineCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"], - "QgsGeometryContainedCheckError": ["QgsGeometryContainedCheckError(const QgsGeometryCheck *check, const QgsGeometryCheckerUtils::LayerFeature &layerFeature, const QgsPointXY &errorLocation, const QgsGeometryCheckerUtils::LayerFeature &containingFeature)", "containingFeature() const"], + "QgsDataDefinedSizeDialog": [ + "QgsDataDefinedSizeDialog(const QList< QgsSymbol * > &symbolList, QgsVectorLayer *layer)" + ], + "QgsGeometryDuplicateNodesCheck": [ + "QgsGeometryDuplicateNodesCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", + "factoryDescription()", + "ResolutionMethod", + "factoryCompatibleGeometryTypes()", + "factoryCheckType()", + "factoryIsCompatible(QgsVectorLayer *layer)", + "factoryId()", + ], + "QgsTotalCurvatureFilter": [ + "QgsTotalCurvatureFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)" + ], + "QgsAttributeFormInterface": [ + "featureChanged()", + "form()", + "feature()", + "QgsAttributeFormInterface(QgsAttributeForm *form)", + "acceptChanges(const QgsFeature &feature)", + "initForm()", + ], + "QgsGeometryPointCoveredByLineCheck": [ + "factoryDescription()", + "ResolutionMethod", + "factoryCompatibleGeometryTypes()", + "QgsGeometryPointCoveredByLineCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", + "factoryCheckType()", + "factoryIsCompatible(QgsVectorLayer *layer)", + "factoryId()", + ], + "QgsGeometryContainedCheckError": [ + "QgsGeometryContainedCheckError(const QgsGeometryCheck *check, const QgsGeometryCheckerUtils::LayerFeature &layerFeature, const QgsPointXY &errorLocation, const QgsGeometryCheckerUtils::LayerFeature &containingFeature)", + "containingFeature() const", + ], "QgsAuthCertInfo": ["trustCacheRebuilt()"], - "QgsGeometryHoleCheck": ["factoryDescription()", "factoryIsCompatible(QgsVectorLayer *layer)", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "QgsGeometryHoleCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "factoryId()"], + "QgsGeometryHoleCheck": [ + "factoryDescription()", + "factoryIsCompatible(QgsVectorLayer *layer)", + "ResolutionMethod", + "factoryCompatibleGeometryTypes()", + "factoryCheckType()", + "QgsGeometryHoleCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", + "factoryId()", + ], "QgsMapRendererJob": ["QgsMapRendererJob(const QgsMapSettings &settings)"], "QgsRendererCategory": ["swap(QgsRendererCategory &other)"], "pal::Problem": ["init_sol_falp()", "reduce()"], "QgsPaintEffectWidget": ["QgsPaintEffectWidget(QWidget *parent=nullptr)"], - "QgsBrowserTreeView": ["setSettingsSection(const QString §ion)", "hasExpandedDescendant(const QModelIndex &index) const"], + "QgsBrowserTreeView": [ + "setSettingsSection(const QString §ion)", + "hasExpandedDescendant(const QModelIndex &index) const", + ], "QgsAttributeTypeLoadDialog": ["QgsAttributeTypeLoadDialog(QgsVectorLayer *vl)"], - "QgsMapSettings": ["updateDerived()", "readXml(QDomNode &node)", "writeXml(QDomNode &node, QDomDocument &doc)", "mapToPixel() const"], - "QgsManageConnectionsDialog": ["selectionChanged()", "clearSelection()", "doExportImport()", "Mode", "selectAll()", "Type"], + "QgsMapSettings": [ + "updateDerived()", + "readXml(QDomNode &node)", + "writeXml(QDomNode &node, QDomDocument &doc)", + "mapToPixel() const", + ], + "QgsManageConnectionsDialog": [ + "selectionChanged()", + "clearSelection()", + "doExportImport()", + "Mode", + "selectAll()", + "Type", + ], "QgsLayerTreeNode": ["QgsLayerTreeNode(const QgsLayerTreeNode &other)"], - "QgsPointLocator_VisitorNearestVertex": ["QgsPointLocator_VisitorNearestVertex(QgsPointLocator *pl, QgsPointLocator::Match &m, const QgsPointXY &srcPoint, QgsPointLocator::MatchFilter *filter=nullptr)"], - "QgsErrorItem": ["QgsErrorItem(QgsDataItem *parent, const QString &error, const QString &path)"], - "QgsAttributeForm": ["QgsAttributeForm(QgsVectorLayer *vl, const QgsFeature &feature=QgsFeature(), const QgsAttributeEditorContext &context=QgsAttributeEditorContext(), QWidget *parent=nullptr)", "feature()"], + "QgsPointLocator_VisitorNearestVertex": [ + "QgsPointLocator_VisitorNearestVertex(QgsPointLocator *pl, QgsPointLocator::Match &m, const QgsPointXY &srcPoint, QgsPointLocator::MatchFilter *filter=nullptr)" + ], + "QgsErrorItem": [ + "QgsErrorItem(QgsDataItem *parent, const QString &error, const QString &path)" + ], + "QgsAttributeForm": [ + "QgsAttributeForm(QgsVectorLayer *vl, const QgsFeature &feature=QgsFeature(), const QgsAttributeEditorContext &context=QgsAttributeEditorContext(), QWidget *parent=nullptr)", + "feature()", + ], "QgsSocketMonitoringThread": ["run()"], "QgsMeshDatasetGroupTreeWidget": ["datasetGroupAdded()"], - "QgsWmsDimensionDialog": ["setInfo(const QgsMapLayerServerProperties::WmsDimensionInfo &info)", "QgsWmsDimensionDialog(QgsVectorLayer *layer, QStringList alreadyDefinedDimensions, QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())", "info() const"], - "QgsMapToolIdentify": ["formatChanged(QgsRasterLayer *layer)", "identifyMessage(const QString &)", "IdentifyMode", "identifyProgress(int, int)", "Type", "changedRasterResults(QList< QgsMapToolIdentify::IdentifyResult > &)"], - "QgsEllipseSymbolLayer": ["createFromSld(QDomElement &element)", "strokeWidth() const", "strokeWidthMapUnitScale() const", "symbolWidth() const", "setStrokeWidth(double w)", "strokeStyle() const", "symbolHeight() const", "setSymbolHeightMapUnitScale(const QgsMapUnitScale &scale)", "setSymbolWidth(double w)", "symbolWidthMapUnitScale() const", "setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)", "setSymbolWidthMapUnitScale(const QgsMapUnitScale &scale)", "setStrokeStyle(Qt::PenStyle strokeStyle)", "setSymbolHeight(double h)", "symbolHeightMapUnitScale() const"], - "QgsPluginLayer": ["QgsPluginLayer(const QString &layerType, const QString &layerName=QString())"], - "QgsMapRendererParallelJob": ["QgsMapRendererParallelJob(const QgsMapSettings &settings)"], - "QgsVectorLayerFeatureIterator": ["QgsVectorLayerFeatureIterator(QgsVectorLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request)"], + "QgsWmsDimensionDialog": [ + "setInfo(const QgsMapLayerServerProperties::WmsDimensionInfo &info)", + "QgsWmsDimensionDialog(QgsVectorLayer *layer, QStringList alreadyDefinedDimensions, QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())", + "info() const", + ], + "QgsMapToolIdentify": [ + "formatChanged(QgsRasterLayer *layer)", + "identifyMessage(const QString &)", + "IdentifyMode", + "identifyProgress(int, int)", + "Type", + "changedRasterResults(QList< QgsMapToolIdentify::IdentifyResult > &)", + ], + "QgsEllipseSymbolLayer": [ + "createFromSld(QDomElement &element)", + "strokeWidth() const", + "strokeWidthMapUnitScale() const", + "symbolWidth() const", + "setStrokeWidth(double w)", + "strokeStyle() const", + "symbolHeight() const", + "setSymbolHeightMapUnitScale(const QgsMapUnitScale &scale)", + "setSymbolWidth(double w)", + "symbolWidthMapUnitScale() const", + "setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)", + "setSymbolWidthMapUnitScale(const QgsMapUnitScale &scale)", + "setStrokeStyle(Qt::PenStyle strokeStyle)", + "setSymbolHeight(double h)", + "symbolHeightMapUnitScale() const", + ], + "QgsPluginLayer": [ + "QgsPluginLayer(const QString &layerType, const QString &layerName=QString())" + ], + "QgsMapRendererParallelJob": [ + "QgsMapRendererParallelJob(const QgsMapSettings &settings)" + ], + "QgsVectorLayerFeatureIterator": [ + "QgsVectorLayerFeatureIterator(QgsVectorLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request)" + ], "QgsMapLayer": ["readSld(const QDomNode &node, QString &errorMessage)"], - "QgsFieldExpressionWidget": ["setLeftHandButtonStyle(bool isLeft)", "currentFieldChanged()", "isExpressionValid(const QString &expressionStr)"], - "QgsContrastEnhancementFunction": ["QgsContrastEnhancementFunction(const QgsContrastEnhancementFunction &f)", "QgsContrastEnhancementFunction(Qgis::DataType, double, double)"], - "QgsAttributeTableMapLayerAction": ["execute()", "QgsAttributeTableMapLayerAction(const QString &name, QgsDualView *dualView, QgsMapLayerAction *action, const QModelIndex &fieldIdx)"], - "QgsSymbolLayerWidget": ["symbolLayer()=0", "setSymbolLayer(QgsSymbolLayer *layer)=0", "updateDataDefinedProperty()"], - "QgsGeometryFollowBoundariesCheck": ["factoryDescription()", "QgsGeometryFollowBoundariesCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration, QgsVectorLayer *checkLayer)", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"], - "QgsLayerTreeView": ["onCurrentChanged()", "onExpandedChanged(QgsLayerTreeNode *node, bool expanded)", "updateExpandedStateToNode(const QModelIndex &index)", "modelRowsRemoved()", "updateExpandedStateFromNode(QgsLayerTreeNode *node)", "onModelReset()", "modelRowsInserted(const QModelIndex &index, int start, int end)", "layerForIndex(const QModelIndex &index) const"], + "QgsFieldExpressionWidget": [ + "setLeftHandButtonStyle(bool isLeft)", + "currentFieldChanged()", + "isExpressionValid(const QString &expressionStr)", + ], + "QgsContrastEnhancementFunction": [ + "QgsContrastEnhancementFunction(const QgsContrastEnhancementFunction &f)", + "QgsContrastEnhancementFunction(Qgis::DataType, double, double)", + ], + "QgsAttributeTableMapLayerAction": [ + "execute()", + "QgsAttributeTableMapLayerAction(const QString &name, QgsDualView *dualView, QgsMapLayerAction *action, const QModelIndex &fieldIdx)", + ], + "QgsSymbolLayerWidget": [ + "symbolLayer()=0", + "setSymbolLayer(QgsSymbolLayer *layer)=0", + "updateDataDefinedProperty()", + ], + "QgsGeometryFollowBoundariesCheck": [ + "factoryDescription()", + "QgsGeometryFollowBoundariesCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration, QgsVectorLayer *checkLayer)", + "factoryCompatibleGeometryTypes()", + "factoryCheckType()", + "factoryIsCompatible(QgsVectorLayer *layer)", + "factoryId()", + ], + "QgsLayerTreeView": [ + "onCurrentChanged()", + "onExpandedChanged(QgsLayerTreeNode *node, bool expanded)", + "updateExpandedStateToNode(const QModelIndex &index)", + "modelRowsRemoved()", + "updateExpandedStateFromNode(QgsLayerTreeNode *node)", + "onModelReset()", + "modelRowsInserted(const QModelIndex &index, int start, int end)", + "layerForIndex(const QModelIndex &index) const", + ], "CloughTocherInterpolator": ["setTriangulation(NormVecDecorator *tin)"], "QgsDefaultVectorLayerLegend": ["QgsDefaultVectorLayerLegend(QgsVectorLayer *vl)"], - "QgsAttributeEditorContext": ["QgsAttributeEditorContext(const QgsAttributeEditorContext &parentContext, FormMode formMode)", "FormMode", "QgsAttributeEditorContext(const QgsAttributeEditorContext &parentContext, const QgsRelation &relation, RelationMode relationMode, FormMode widgetMode)", "parentContext() const"], + "QgsAttributeEditorContext": [ + "QgsAttributeEditorContext(const QgsAttributeEditorContext &parentContext, FormMode formMode)", + "FormMode", + "QgsAttributeEditorContext(const QgsAttributeEditorContext &parentContext, const QgsRelation &relation, RelationMode relationMode, FormMode widgetMode)", + "parentContext() const", + ], "QgsGpsConnectionRegistry": ["connectionList() const"], - "QgsGeometryDangleCheck": ["factoryDescription()", "QgsGeometryDangleCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", "ResolutionMethod", "factoryCompatibleGeometryTypes()", "factoryCheckType()", "factoryIsCompatible(QgsVectorLayer *layer)", "factoryId()"], - "QgsCptCityDataItem": ["icon()", "toolTip() const", "parent() const", "children() const", "hasChildren()", "populate()", "icon(QSize size)", "rowCount()", "paramWidget()", "handleDrop(const QMimeData *, Qt::DropAction)", "type() const", "beginRemoveItems(QgsCptCityDataItem *parent, int first, int last)", "endRemoveItems()", "path() const", "Type", "isPopulated()", "endInsertItems()", "name() const", "refresh()", "setIcon(const QIcon &icon)", "deleteChildItem(QgsCptCityDataItem *child)", "leafCount() const", "isValid()", "setToolTip(const QString &msg)", "createChildren()", "QgsCptCityDataItem(QgsCptCityDataItem::Type type, QgsCptCityDataItem *parent, const QString &name, const QString &path)", "setParent(QgsCptCityDataItem *parent)", "addChildItem(QgsCptCityDataItem *child, bool refresh=false)", "beginInsertItems(QgsCptCityDataItem *parent, int first, int last)", "shortInfo() const", "acceptDrop()", "info() const", "findItem(QVector< QgsCptCityDataItem * > items, QgsCptCityDataItem *item)", "removeChildItem(QgsCptCityDataItem *child)", "equal(const QgsCptCityDataItem *other)"], - "QgsRasterNuller": ["setNoData(int bandNo, const QgsRasterRangeList &noData)", "noData(int bandNo) const", "QgsRasterNuller(QgsRasterInterface *input=nullptr)"], + "QgsGeometryDangleCheck": [ + "factoryDescription()", + "QgsGeometryDangleCheck(QgsGeometryCheckContext *context, const QVariantMap &configuration)", + "ResolutionMethod", + "factoryCompatibleGeometryTypes()", + "factoryCheckType()", + "factoryIsCompatible(QgsVectorLayer *layer)", + "factoryId()", + ], + "QgsCptCityDataItem": [ + "icon()", + "toolTip() const", + "parent() const", + "children() const", + "hasChildren()", + "populate()", + "icon(QSize size)", + "rowCount()", + "paramWidget()", + "handleDrop(const QMimeData *, Qt::DropAction)", + "type() const", + "beginRemoveItems(QgsCptCityDataItem *parent, int first, int last)", + "endRemoveItems()", + "path() const", + "Type", + "isPopulated()", + "endInsertItems()", + "name() const", + "refresh()", + "setIcon(const QIcon &icon)", + "deleteChildItem(QgsCptCityDataItem *child)", + "leafCount() const", + "isValid()", + "setToolTip(const QString &msg)", + "createChildren()", + "QgsCptCityDataItem(QgsCptCityDataItem::Type type, QgsCptCityDataItem *parent, const QString &name, const QString &path)", + "setParent(QgsCptCityDataItem *parent)", + "addChildItem(QgsCptCityDataItem *child, bool refresh=false)", + "beginInsertItems(QgsCptCityDataItem *parent, int first, int last)", + "shortInfo() const", + "acceptDrop()", + "info() const", + "findItem(QVector< QgsCptCityDataItem * > items, QgsCptCityDataItem *item)", + "removeChildItem(QgsCptCityDataItem *child)", + "equal(const QgsCptCityDataItem *other)", + ], + "QgsRasterNuller": [ + "setNoData(int bandNo, const QgsRasterRangeList &noData)", + "noData(int bandNo) const", + "QgsRasterNuller(QgsRasterInterface *input=nullptr)", + ], "QgsMapThemeCollection": ["setProject(QgsProject *project)"], - "QgsLayerItem": ["iconDefault()", "iconRaster()", "iconPoint()", "iconPolygon()", "iconTable()", "iconLine()"], + "QgsLayerItem": [ + "iconDefault()", + "iconRaster()", + "iconPoint()", + "iconPolygon()", + "iconTable()", + "iconLine()", + ], "QgsCacheIndexFeatureId": ["QgsCacheIndexFeatureId(QgsVectorLayerCache *)"], - "QgsPointLocator_VisitorEdgesInRect": ["QgsPointLocator_VisitorEdgesInRect(QgsPointLocator *pl, QgsPointLocator::MatchList &lst, const QgsRectangle &srcRect, QgsPointLocator::MatchFilter *filter=nullptr)"], - "QgsCptCityColorRampItem": ["ramp() const", "QgsCptCityColorRampItem(QgsCptCityDataItem *parent, const QString &name, const QString &path, const QStringList &variantList, bool initialize=false)", "init()", "QgsCptCityColorRampItem(QgsCptCityDataItem *parent, const QString &name, const QString &path, const QString &variantName=QString(), bool initialize=false)"], + "QgsPointLocator_VisitorEdgesInRect": [ + "QgsPointLocator_VisitorEdgesInRect(QgsPointLocator *pl, QgsPointLocator::MatchList &lst, const QgsRectangle &srcRect, QgsPointLocator::MatchFilter *filter=nullptr)" + ], + "QgsCptCityColorRampItem": [ + "ramp() const", + "QgsCptCityColorRampItem(QgsCptCityDataItem *parent, const QString &name, const QString &path, const QStringList &variantList, bool initialize=false)", + "init()", + "QgsCptCityColorRampItem(QgsCptCityDataItem *parent, const QString &name, const QString &path, const QString &variantName=QString(), bool initialize=false)", + ], "QgsTextDiagram": ["Shape", "Orientation"], "QgsSublayersDialog": ["ProviderType"], - "QgsCharacterSelectorDialog": ["QgsCharacterSelectorDialog(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)"], + "QgsCharacterSelectorDialog": [ + "QgsCharacterSelectorDialog(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)" + ], "QgisVisitor": ["QgisVisitor(QList< QgsFeatureId > &list)"], - "QgsLabelingEngine": ["processProvider(QgsAbstractLabelProvider *provider, QgsRenderContext &context, pal::Pal &p)"], - "QgsNetworkAccessManager": ["requestTimedOut(QNetworkReply *)", "QgsNetworkAccessManager(QObject *parent=nullptr)"], + "QgsLabelingEngine": [ + "processProvider(QgsAbstractLabelProvider *provider, QgsRenderContext &context, pal::Pal &p)" + ], + "QgsNetworkAccessManager": [ + "requestTimedOut(QNetworkReply *)", + "QgsNetworkAccessManager(QObject *parent=nullptr)", + ], "QgsGpsConnection": ["Status"], } @@ -1112,7 +2830,6 @@ "QgsMapLayerLegend", "QgsLayoutRenderContext", "QgsLabelingEngine", - "QgsOgcUtilsExprToFilter", "QgsGeometryLineIntersectionCheck", "QgsRangeConfigDlg", @@ -1815,247 +3532,247 @@ ] ACCEPTABLE_MISSING_BRIEF = [ - 'QgsDial', - 'QgsPluginManagerInterface', - 'QgsRangeWidgetFactory', - 'QgsLinearlyInterpolatedDiagramRenderer', - 'QgsTextDiagram', - 'QgsShapeburstFillSymbolLayer', - 'QgsCptCityArchive', - 'QgsValueRelationConfigDlg', - 'QgsGeometryMultipartCheck', - 'QgsArrowSymbolLayerWidget', - 'QgsCheckboxWidgetFactory', - 'QgsLabelCandidate', - 'QgsGeometrySliverPolygonCheck', - 'QgsMarkerLineSymbolLayerWidget', - 'QgsRelationReferenceFactory', - 'QgsGradientFillSymbolLayer', - 'QgsPointPatternFillSymbolLayer', - 'QgsSymbolLayer', - 'QgsLUDialog', - 'QgsFeatureModel', - 'QgsSimpleMarkerSymbolLayerWidget', - 'QgsMimeDataUtils', - 'QgsRuleBasedLabelProvider', - 'QgsRuntimeProfiler', - 'QgsRelation', - 'QgsGeometryPointCoveredByLineCheck', - 'QgsFontMarkerSymbolLayerWidget', - 'QgsDataDefinedWidthDialog', - 'QgsHistogramDiagram', - 'QgsSymbolLayerWidget', - 'QgsSpatialIndexCopyVisitor', - 'pal::CostCalculator', - 'QgsRendererRangeLabelFormat', - 'QgsGeometrySelfContactCheck', - 'QgsExpressionHighlighter', - 'QgsFillSymbolLayer', - 'QgsRendererRange', - 'QgsVectorFileWriter::HiddenOption', - 'QgsDrawSourceWidget', - 'QgsSvgSelectorDialog', - 'QgsFontMarkerSymbolLayer', - 'QgsStyleGroupSelectionDialog', - 'QgsGeometryLineLayerIntersectionCheck', - 'QgsFeatureRenderer', - 'QgsGeometryDangleCheck', - 'QgsRelationEditorWidget', - 'QgsGeometryPointInPolygonCheck', - 'QgsSymbolLayerUtils', - 'QgsCategorizedSymbolRenderer', - 'QgsRasterRendererWidget', - 'QgsValueMapConfigDlg', - 'QgsSublayersDialog', - 'QgsLabelPosition', - 'QgsSimpleLineSymbolLayerWidget', - 'QgsGeometrySelfIntersectionCheckError', - 'QgsRelationReferenceConfigDlg', - 'QgsFeatureListModel', - 'QgsMessageBarItem', - 'QgsCptCityBrowserModel', - 'QgsQtLocationConnection', - 'HalfEdge', - 'QgsBrushStyleComboBox', - 'QgsDartMeasurement', - 'QgsDateTimeEditFactory', - 'QgsPieDiagram', - 'QgsVectorLayerFeatureIterator', - 'QgsGeometryValidator', - 'QgsGeometrySelfIntersectionCheck', - 'QgsRangeConfigDlg', - 'QgsSymbolsListWidget', - 'QgsDummyConfigDlg', - 'QgsEnumerationWidgetFactory', - 'QgsGeometryDuplicateNodesCheck', - 'QgsVectorLayerEditPassthrough', - 'QgsGeometryTypeCheck', - 'QgsSVGFillSymbolLayerWidget', - 'QgsSingleSymbolRenderer', - 'QgsGeometryAreaCheck', - 'QgsHillshadeFilter', - 'QgsColorWidgetFactory', - 'QgsRendererPropertiesDialog', - 'QgsBrowserWatcher', - 'QgsDxfExport', - 'QgsTransactionGroup', - 'QgsStyle', - 'QgsSingleSymbolRendererWidget', - 'QgsGeometryDuplicateCheckError', - 'QgsSvgMarkerSymbolLayer', - 'QgsGeometry::Error', - 'QgsLayerPropertiesWidget', - 'QgsSymbolSelectorDialog', - 'QgsConstWkbPtr', - 'QgsErrorDialog', - 'QgsPalLayerSettings', - 'QgsRendererRulePropsWidget', - 'QgsTextEditConfigDlg', - 'QgsDateTimeEditConfig', - 'QgsGroupBoxCollapseButton', - 'QgsGeometryFollowBoundariesCheck', - 'QgsLongLongValidator', - 'QgsTextEditWidgetFactory', - 'QgsCentroidFillSymbolLayerWidget', - 'QgsGmlSchema', - 'QgsSingleBandGrayRendererWidget', - 'Qgs25DRenderer', - 'QgsVectorFileWriter::BoolOption', - 'QgsSimpleFillSymbolLayer', - 'QgsDxfPaintEngine', - 'QgsGlowWidget', - 'QgsGroupWmsDataDialog', - 'QgsMapToolCapture', - 'QgsRendererRasterPropertiesWidget', - 'QgsCptCityColorRamp', - 'QgsVectorLayerEditUtils', - 'QgsVectorLayerSelectionManager', - 'QgsTrackedVectorLayerTools', - 'QgsSmartGroupCondition', - 'pal::Sol', - 'QgsAttributeTypeLoadDialog', - 'QgsCentroidFillSymbolLayer', - 'QgsWkbPtr', - 'QgsFeatureSelectionModel', - 'QgsDataDefinedRotationDialog', - 'QgsGraduatedSymbolRendererWidget', - 'QgsTransformWidget', - 'QgsShapeburstFillSymbolLayerWidget', - 'QgsUniqueValuesConfigDlg', - 'QgsHeatmapRendererWidget', - 'QgsScaleUtils', - 'pal::PointSet', - 'QgsEllipseSymbolLayerWidget', - 'QgsFontUtils', - 'QgsRuleBasedLabeling', - 'QgsRasterCalcNode', - 'QgsPointPatternFillSymbolLayerWidget', - 'QgsVectorFileWriter::StringOption', - 'QgsUuidWidgetFactory', - 'QgsHiddenWidgetFactory', - 'QgsGeometryGeneratorSymbolLayer', - 'QgsGeometryAngleCheck', - 'QgsAttributeTableAction', - 'QgsAttributeForm', - 'QgsDatumTransformDialog', - 'pal::PriorityQueue', - 'Qgs25DRendererWidget', - 'QgsShadowEffectWidget', - 'QgsGeometryHoleCheck', - 'QgsVectorFileWriter::Option', - 'QgsRuleBasedRendererWidget', - 'QgsPenCapStyleComboBox', - 'QgsScopeLogger', - 'QgsGeometrySegmentLengthCheck', - 'QgsGeometryContainedCheckError', - 'QgsClassificationWidgetWrapper', - 'QgsMultiBandColorRendererWidget', - 'QgsFeatureListViewDelegate', - 'QgsManageConnectionsDialog', - 'QgsFieldValidator', - 'QgsPalLabeling', - 'QgsLocaleNumC', - 'QgsColorBrewerPalette', - 'pal::Util', - 'QgsVectorFileWriter::IntOption', - 'QgsGeometryLineIntersectionCheck', - 'QgsSymbolRenderContext', - 'QgsCategorizedSymbolRendererWidget', - 'pal::GeomFunction', - 'QgsRendererRulePropsDialog', - 'QgsSvgMarkerSymbolLayerWidget', - 'QgsExternalResourceConfigDlg', - 'QgsClassificationWidgetWrapperFactory', - 'QgsGeometryTypeCheckError', - 'QgsNewVectorLayerDialog', - 'QgsRuleBasedLabeling::Rule', - 'QgsVectorFieldSymbolLayerWidget', - 'QgsSmartGroupEditorDialog', - 'QgsSlider', - 'QgsAttributeDialog', - 'QgsVectorFileWriter::SetOption', - 'QgsNewMemoryLayerDialog', - 'QgsCheckBoxConfigDlg', - 'QgsEnumerationWidgetWrapper', - 'QgsRelationReferenceWidget', - 'QgsRasterLayerSaveAsDialog', - 'QgsValueRelationWidgetFactory', - 'QgsGraduatedSymbolRenderer', - 'QgsGeometryGeneratorSymbolLayerWidget', - 'QgsBlurWidget', - 'QgsLineSymbolLayer', - 'QgsRelationWidgetWrapper', - 'QgsOfflineEditing', - 'QgsValueMapWidgetFactory', - 'QgsGeometryDegeneratePolygonCheck', - 'QgsExternalResourceWidgetFactory', - 'QgsEditFormConfig', - 'QgsAttributeFormInterface', - 'QgsProjectFileTransform', - 'QgsColorEffectWidget', - 'QgsAttributeTableMapLayerAction', - 'QgsGeometryDuplicateCheck', - 'QgsPalettedRendererWidget', - 'QgsSimpleFillSymbolLayerWidget', - 'QgsSurface', - 'QgsAttributeTableFilterModel', - 'QgsLinePatternFillSymbolLayerWidget', - 'QgsCacheIndexFeatureId', - 'QgsGeometryContainedCheck', - 'QgsPenJoinStyleComboBox', - 'QgsDataDefinedSizeDialog', - 'QgsUniqueValueWidgetFactory', - 'QgsStyleExportImportDialog', - 'QgsRasterMatrix', - 'QgsPointDisplacementRendererWidget', - 'QgsVectorLayerEditBuffer', - 'QgsGradientFillSymbolLayerWidget', - 'QgsRasterFillSymbolLayerWidget', - 'QgsRasterMinMaxWidget', - 'QgsSymbolLevelItem', - 'QgsSvgSelectorWidget', - 'QgsPenStyleComboBox', - 'QgsFeatureSelectionDlg', - 'QgsAttributeActionDialog', - 'QgsDiagramProperties', - 'QgsSourceFieldsProperties', - 'QgsJoinDialog', - 'QgsAttributesFormProperties::DnDTreeItemData', - 'QgsMeshDatasetGroupListModel', - 'QgsMeshDatasetGroupSaveMenu', - 'QgsMeshDatasetGroupProxyModel', - 'QgsAttributeActionPropertiesDialog', - 'QgsAttributesFormProperties', - 'QgsMeshAvailableDatasetGroupTreeModel', - 'QgsVectorLayerProperties', - 'QgsSettingsEntryBase', - 'QgsMeshDatasetGroupTreeWidget', - 'QgsAttributesFormInitCode', - 'QgsMeshRendererScalarSettingsWidget', - 'QgsCPLErrorHandler', - 'EditBlockerDelegate' + "QgsDial", + "QgsPluginManagerInterface", + "QgsRangeWidgetFactory", + "QgsLinearlyInterpolatedDiagramRenderer", + "QgsTextDiagram", + "QgsShapeburstFillSymbolLayer", + "QgsCptCityArchive", + "QgsValueRelationConfigDlg", + "QgsGeometryMultipartCheck", + "QgsArrowSymbolLayerWidget", + "QgsCheckboxWidgetFactory", + "QgsLabelCandidate", + "QgsGeometrySliverPolygonCheck", + "QgsMarkerLineSymbolLayerWidget", + "QgsRelationReferenceFactory", + "QgsGradientFillSymbolLayer", + "QgsPointPatternFillSymbolLayer", + "QgsSymbolLayer", + "QgsLUDialog", + "QgsFeatureModel", + "QgsSimpleMarkerSymbolLayerWidget", + "QgsMimeDataUtils", + "QgsRuleBasedLabelProvider", + "QgsRuntimeProfiler", + "QgsRelation", + "QgsGeometryPointCoveredByLineCheck", + "QgsFontMarkerSymbolLayerWidget", + "QgsDataDefinedWidthDialog", + "QgsHistogramDiagram", + "QgsSymbolLayerWidget", + "QgsSpatialIndexCopyVisitor", + "pal::CostCalculator", + "QgsRendererRangeLabelFormat", + "QgsGeometrySelfContactCheck", + "QgsExpressionHighlighter", + "QgsFillSymbolLayer", + "QgsRendererRange", + "QgsVectorFileWriter::HiddenOption", + "QgsDrawSourceWidget", + "QgsSvgSelectorDialog", + "QgsFontMarkerSymbolLayer", + "QgsStyleGroupSelectionDialog", + "QgsGeometryLineLayerIntersectionCheck", + "QgsFeatureRenderer", + "QgsGeometryDangleCheck", + "QgsRelationEditorWidget", + "QgsGeometryPointInPolygonCheck", + "QgsSymbolLayerUtils", + "QgsCategorizedSymbolRenderer", + "QgsRasterRendererWidget", + "QgsValueMapConfigDlg", + "QgsSublayersDialog", + "QgsLabelPosition", + "QgsSimpleLineSymbolLayerWidget", + "QgsGeometrySelfIntersectionCheckError", + "QgsRelationReferenceConfigDlg", + "QgsFeatureListModel", + "QgsMessageBarItem", + "QgsCptCityBrowserModel", + "QgsQtLocationConnection", + "HalfEdge", + "QgsBrushStyleComboBox", + "QgsDartMeasurement", + "QgsDateTimeEditFactory", + "QgsPieDiagram", + "QgsVectorLayerFeatureIterator", + "QgsGeometryValidator", + "QgsGeometrySelfIntersectionCheck", + "QgsRangeConfigDlg", + "QgsSymbolsListWidget", + "QgsDummyConfigDlg", + "QgsEnumerationWidgetFactory", + "QgsGeometryDuplicateNodesCheck", + "QgsVectorLayerEditPassthrough", + "QgsGeometryTypeCheck", + "QgsSVGFillSymbolLayerWidget", + "QgsSingleSymbolRenderer", + "QgsGeometryAreaCheck", + "QgsHillshadeFilter", + "QgsColorWidgetFactory", + "QgsRendererPropertiesDialog", + "QgsBrowserWatcher", + "QgsDxfExport", + "QgsTransactionGroup", + "QgsStyle", + "QgsSingleSymbolRendererWidget", + "QgsGeometryDuplicateCheckError", + "QgsSvgMarkerSymbolLayer", + "QgsGeometry::Error", + "QgsLayerPropertiesWidget", + "QgsSymbolSelectorDialog", + "QgsConstWkbPtr", + "QgsErrorDialog", + "QgsPalLayerSettings", + "QgsRendererRulePropsWidget", + "QgsTextEditConfigDlg", + "QgsDateTimeEditConfig", + "QgsGroupBoxCollapseButton", + "QgsGeometryFollowBoundariesCheck", + "QgsLongLongValidator", + "QgsTextEditWidgetFactory", + "QgsCentroidFillSymbolLayerWidget", + "QgsGmlSchema", + "QgsSingleBandGrayRendererWidget", + "Qgs25DRenderer", + "QgsVectorFileWriter::BoolOption", + "QgsSimpleFillSymbolLayer", + "QgsDxfPaintEngine", + "QgsGlowWidget", + "QgsGroupWmsDataDialog", + "QgsMapToolCapture", + "QgsRendererRasterPropertiesWidget", + "QgsCptCityColorRamp", + "QgsVectorLayerEditUtils", + "QgsVectorLayerSelectionManager", + "QgsTrackedVectorLayerTools", + "QgsSmartGroupCondition", + "pal::Sol", + "QgsAttributeTypeLoadDialog", + "QgsCentroidFillSymbolLayer", + "QgsWkbPtr", + "QgsFeatureSelectionModel", + "QgsDataDefinedRotationDialog", + "QgsGraduatedSymbolRendererWidget", + "QgsTransformWidget", + "QgsShapeburstFillSymbolLayerWidget", + "QgsUniqueValuesConfigDlg", + "QgsHeatmapRendererWidget", + "QgsScaleUtils", + "pal::PointSet", + "QgsEllipseSymbolLayerWidget", + "QgsFontUtils", + "QgsRuleBasedLabeling", + "QgsRasterCalcNode", + "QgsPointPatternFillSymbolLayerWidget", + "QgsVectorFileWriter::StringOption", + "QgsUuidWidgetFactory", + "QgsHiddenWidgetFactory", + "QgsGeometryGeneratorSymbolLayer", + "QgsGeometryAngleCheck", + "QgsAttributeTableAction", + "QgsAttributeForm", + "QgsDatumTransformDialog", + "pal::PriorityQueue", + "Qgs25DRendererWidget", + "QgsShadowEffectWidget", + "QgsGeometryHoleCheck", + "QgsVectorFileWriter::Option", + "QgsRuleBasedRendererWidget", + "QgsPenCapStyleComboBox", + "QgsScopeLogger", + "QgsGeometrySegmentLengthCheck", + "QgsGeometryContainedCheckError", + "QgsClassificationWidgetWrapper", + "QgsMultiBandColorRendererWidget", + "QgsFeatureListViewDelegate", + "QgsManageConnectionsDialog", + "QgsFieldValidator", + "QgsPalLabeling", + "QgsLocaleNumC", + "QgsColorBrewerPalette", + "pal::Util", + "QgsVectorFileWriter::IntOption", + "QgsGeometryLineIntersectionCheck", + "QgsSymbolRenderContext", + "QgsCategorizedSymbolRendererWidget", + "pal::GeomFunction", + "QgsRendererRulePropsDialog", + "QgsSvgMarkerSymbolLayerWidget", + "QgsExternalResourceConfigDlg", + "QgsClassificationWidgetWrapperFactory", + "QgsGeometryTypeCheckError", + "QgsNewVectorLayerDialog", + "QgsRuleBasedLabeling::Rule", + "QgsVectorFieldSymbolLayerWidget", + "QgsSmartGroupEditorDialog", + "QgsSlider", + "QgsAttributeDialog", + "QgsVectorFileWriter::SetOption", + "QgsNewMemoryLayerDialog", + "QgsCheckBoxConfigDlg", + "QgsEnumerationWidgetWrapper", + "QgsRelationReferenceWidget", + "QgsRasterLayerSaveAsDialog", + "QgsValueRelationWidgetFactory", + "QgsGraduatedSymbolRenderer", + "QgsGeometryGeneratorSymbolLayerWidget", + "QgsBlurWidget", + "QgsLineSymbolLayer", + "QgsRelationWidgetWrapper", + "QgsOfflineEditing", + "QgsValueMapWidgetFactory", + "QgsGeometryDegeneratePolygonCheck", + "QgsExternalResourceWidgetFactory", + "QgsEditFormConfig", + "QgsAttributeFormInterface", + "QgsProjectFileTransform", + "QgsColorEffectWidget", + "QgsAttributeTableMapLayerAction", + "QgsGeometryDuplicateCheck", + "QgsPalettedRendererWidget", + "QgsSimpleFillSymbolLayerWidget", + "QgsSurface", + "QgsAttributeTableFilterModel", + "QgsLinePatternFillSymbolLayerWidget", + "QgsCacheIndexFeatureId", + "QgsGeometryContainedCheck", + "QgsPenJoinStyleComboBox", + "QgsDataDefinedSizeDialog", + "QgsUniqueValueWidgetFactory", + "QgsStyleExportImportDialog", + "QgsRasterMatrix", + "QgsPointDisplacementRendererWidget", + "QgsVectorLayerEditBuffer", + "QgsGradientFillSymbolLayerWidget", + "QgsRasterFillSymbolLayerWidget", + "QgsRasterMinMaxWidget", + "QgsSymbolLevelItem", + "QgsSvgSelectorWidget", + "QgsPenStyleComboBox", + "QgsFeatureSelectionDlg", + "QgsAttributeActionDialog", + "QgsDiagramProperties", + "QgsSourceFieldsProperties", + "QgsJoinDialog", + "QgsAttributesFormProperties::DnDTreeItemData", + "QgsMeshDatasetGroupListModel", + "QgsMeshDatasetGroupSaveMenu", + "QgsMeshDatasetGroupProxyModel", + "QgsAttributeActionPropertiesDialog", + "QgsAttributesFormProperties", + "QgsMeshAvailableDatasetGroupTreeModel", + "QgsVectorLayerProperties", + "QgsSettingsEntryBase", + "QgsMeshDatasetGroupTreeWidget", + "QgsAttributesFormInitCode", + "QgsMeshRendererScalarSettingsWidget", + "QgsCPLErrorHandler", + "EditBlockerDelegate", ] -if __name__ == '__main__': +if __name__ == "__main__": for k in sorted(list(ACCEPTABLE_MISSING_DOCS.keys())): print(f' "{k}": {sorted(ACCEPTABLE_MISSING_DOCS[k])},') diff --git a/tests/code_layout/doxygen_parser.py b/tests/code_layout/doxygen_parser.py index 70f59fa84c4d..f558e98dc934 100644 --- a/tests/code_layout/doxygen_parser.py +++ b/tests/code_layout/doxygen_parser.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Denis Rouzaud' -__date__ = 'May 2017' -__copyright__ = '(C) 2017, Denis Rouzaud' +__author__ = "Denis Rouzaud" +__date__ = "May 2017" +__copyright__ = "(C) 2017, Denis Rouzaud" import glob import os @@ -29,12 +29,18 @@ import xml.etree.ElementTree as ET -class DoxygenParser(): +class DoxygenParser: """ Parses the XML files generated by Doxygen which describe the API docs """ - def __init__(self, path, acceptable_missing={}, acceptable_missing_added_note=[], acceptable_missing_brief=[]): + def __init__( + self, + path, + acceptable_missing={}, + acceptable_missing_added_note=[], + acceptable_missing_brief=[], + ): """ Initializes the parser. :param path: Path to Doxygen XML output @@ -53,28 +59,32 @@ def __init__(self, path, acceptable_missing={}, acceptable_missing_added_note=[] self.classes_missing_brief = [] self.classes_missing_version_added = [] # for some reason the Doxygen generation on Travis refuses to assign these classes to groups - self.acceptable_missing_group = ['QgsOgcUtils::LayerProperties', - 'QgsSQLStatement::Node', - 'QgsSQLStatement::NodeBinaryOperator', - 'QgsSQLStatement::NodeColumnRef', - 'QgsSQLStatement::NodeFunction', - 'QgsSQLStatement::NodeInOperator', - 'QgsSQLStatement::NodeList', - 'QgsSQLStatement::NodeLiteral', - 'QgsSQLStatement::NodeUnaryOperator', - 'QgsRuleBasedLabeling::Rule', - 'QgsSQLStatement::Visitor'] - self.version_regex = re.compile(r'.*QGIS\s+(?:)?[\d\.]+.*', re.MULTILINE) + self.acceptable_missing_group = [ + "QgsOgcUtils::LayerProperties", + "QgsSQLStatement::Node", + "QgsSQLStatement::NodeBinaryOperator", + "QgsSQLStatement::NodeColumnRef", + "QgsSQLStatement::NodeFunction", + "QgsSQLStatement::NodeInOperator", + "QgsSQLStatement::NodeList", + "QgsSQLStatement::NodeLiteral", + "QgsSQLStatement::NodeUnaryOperator", + "QgsRuleBasedLabeling::Rule", + "QgsSQLStatement::Visitor", + ] + self.version_regex = re.compile( + r".*QGIS\s+(?:)?[\d\.]+.*", re.MULTILINE + ) self.parseFiles(path) def parseFiles(self, path): - """ Parses all the Doxygen XML files in a folder - :param path: Path to Doxygen XML output + """Parses all the Doxygen XML files in a folder + :param path: Path to Doxygen XML output """ found = False # find groups - for f in glob.glob(os.path.join(path, 'group__*.xml')): + for f in glob.glob(os.path.join(path, "group__*.xml")): found = True group, members = self.parseGroup(f) self.groups[group] = members @@ -82,14 +92,14 @@ def parseFiles(self, path): assert found, "Could not find doxygen groups xml" found = False # parse docs - for f in glob.glob(os.path.join(path, '*.xml')): + for f in glob.glob(os.path.join(path, "*.xml")): found = True self.parseFile(f) assert found, "Could not find doxygen files xml" def parseGroup(self, f): - """ Parses a single Doxygen Group XML file - :param f: XML file path + """Parses a single Doxygen Group XML file + :param f: XML file path """ name = None members = [] @@ -97,9 +107,9 @@ def parseGroup(self, f): # Wrap everything in a try, as sometimes Doxygen XML is malformed try: for event, elem in ET.iterparse(f): - if event == 'end' and elem.tag == 'compoundname': + if event == "end" and elem.tag == "compoundname": name = elem.text - if event == 'end' and elem.tag == 'innerclass': + if event == "end" and elem.tag == "innerclass": members.append(elem.text) except: pass @@ -107,8 +117,8 @@ def parseGroup(self, f): return name, members def hasGroup(self, class_name): - """ Returns true if a class has been assigned to a group - :param class_name class name to test + """Returns true if a class has been assigned to a group + :param class_name class name to test """ for g in self.groups: if class_name in self.groups[g]: @@ -120,11 +130,11 @@ def standardize_signature(signature): """ Standardizes a method's signature for comparison """ - return signature.lower().replace('* >', '*>').replace('< ', '<') + return signature.lower().replace("* >", "*>").replace("< ", "<") def parseFile(self, f): - """ Parses a single Doxygen XML file - :param f: XML file path + """Parses a single Doxygen XML file + :param f: XML file path """ documentable_members = 0 documented_members = 0 @@ -132,39 +142,65 @@ def parseFile(self, f): # Wrap everything in a try, as sometimes Doxygen XML is malformed try: for event, elem in ET.iterparse(f): - if event == 'end' and elem.tag == 'compounddef': + if event == "end" and elem.tag == "compounddef": if self.elemIsPublicClass(elem): # store documentation status - members, documented, undocumented, noncompliant, bindable, has_brief_description, found_version_added, broken_links = self.parseClassElem( - elem) + ( + members, + documented, + undocumented, + noncompliant, + bindable, + has_brief_description, + found_version_added, + broken_links, + ) = self.parseClassElem(elem) documentable_members += members documented_members += documented - class_name = elem.find('compoundname').text + class_name = elem.find("compoundname").text acceptable_missing = self.acceptable_missing.get(class_name, []) - if not self.hasGroup(class_name) and class_name not in self.acceptable_missing_group: + if ( + not self.hasGroup(class_name) + and class_name not in self.acceptable_missing_group + ): self.classes_missing_group.append(class_name) - if class_name not in self.acceptable_missing_brief and not has_brief_description: + if ( + class_name not in self.acceptable_missing_brief + and not has_brief_description + ): self.classes_missing_brief.append(class_name) - if class_name not in self.acceptable_missing_added_note and not found_version_added: + if ( + class_name not in self.acceptable_missing_added_note + and not found_version_added + ): self.classes_missing_version_added.append(class_name) # GEN LIST # if len(undocumented) > 0: # print('"%s": [%s],' % (class_name, ", ".join(['"%s"' % e.replace('"', '\\"') for e in undocumented]))) - unacceptable_undocumented = undocumented - set(acceptable_missing) + unacceptable_undocumented = undocumented - set( + acceptable_missing + ) # do a case insensitive check too unacceptable_undocumented_insensitive = { - DoxygenParser.standardize_signature(u) for u in undocumented} - { - DoxygenParser.standardize_signature(u) for u in acceptable_missing} + DoxygenParser.standardize_signature(u) for u in undocumented + } - { + DoxygenParser.standardize_signature(u) + for u in acceptable_missing + } if len(unacceptable_undocumented_insensitive) > 0: self.undocumented_members[class_name] = {} - self.undocumented_members[class_name]['documented'] = documented - self.undocumented_members[class_name]['members'] = members - self.undocumented_members[class_name]['missing_members'] = unacceptable_undocumented + self.undocumented_members[class_name][ + "documented" + ] = documented + self.undocumented_members[class_name]["members"] = members + self.undocumented_members[class_name][ + "missing_members" + ] = unacceptable_undocumented if len(noncompliant) > 0: self.noncompliant_members[class_name] = noncompliant @@ -186,44 +222,44 @@ def parseFile(self, f): if i == line_num - 1: line = l break - caret = '{:=>{}}'.format('^', col) - print(f'ParseError in {f}\n{e}\n{line}\n{caret}') + caret = "{:=>{}}".format("^", col) + print(f"ParseError in {f}\n{e}\n{line}\n{caret}") self.documentable_members += documentable_members self.documented_members += documented_members def elemIsPublicClass(self, elem): - """ Tests whether an XML element corresponds to a public (or protected) class - :param elem: XML element + """Tests whether an XML element corresponds to a public (or protected) class + :param elem: XML element """ # only looking for classes - if not elem.get('kind') == 'class': + if not elem.get("kind") == "class": return False # only looking for public or protected classes - return elem.get('prot') in ('public', 'protected') + return elem.get("prot") in ("public", "protected") def classElemIsBindable(self, elem): - """ Tests whether a class should have SIP bindings - :param elem: XML element corresponding to a class + """Tests whether a class should have SIP bindings + :param elem: XML element corresponding to a class """ try: # check for classes with special python doc notes (probably 'not available' or renamed classes, either way # they should be safe to ignore as obviously some consideration has been given to Python bindings) - detailed_sec = elem.find('detaileddescription') - for p in detailed_sec.iter('para'): - for s in p.iter('simplesect'): - for ps in s.iter('para'): - if ps.text and 'python' in ps.text.lower(): + detailed_sec = elem.find("detaileddescription") + for p in detailed_sec.iter("para"): + for s in p.iter("simplesect"): + for ps in s.iter("para"): + if ps.text and "python" in ps.text.lower(): return False return True except: return True def parseClassElem(self, e): - """ Parses an XML element corresponding to a Doxygen class - :param e: XML element + """Parses an XML element corresponding to a Doxygen class + :param e: XML element """ documentable_members = 0 documented_members = 0 @@ -232,12 +268,12 @@ def parseClassElem(self, e): bindable_members = [] broken_links = {} # loop through all members - for m in e.iter('memberdef'): + for m in e.iter("memberdef"): signature = self.memberSignature(m) if signature is None: continue if self.elemIsBindableMember(m): - bindable_member = [e.find('compoundname').text, m.find('name').text] + bindable_member = [e.find("compoundname").text, m.find("name").text] if bindable_member not in bindable_members: bindable_members.append(bindable_member) if self.elemIsDocumentableMember(m): @@ -246,69 +282,88 @@ def parseClassElem(self, e): documented_members += 1 error = self.memberDocIsNonCompliant(m) if error: - noncompliant_members.append({m.find('name').text: error}) + noncompliant_members.append({m.find("name").text: error}) else: undocumented_members.add(signature) broken_see_also_links = self.checkForBrokenSeeAlsoLinks(m) if broken_see_also_links: - broken_links[m.find('name').text] = broken_see_also_links + broken_links[m.find("name").text] = broken_see_also_links # test for brief description - d = e.find('briefdescription') + d = e.find("briefdescription") has_brief_description = False if d is not None: has_brief_description = True - for para in d.iter('para'): - if para.text and re.search(r'\btodo\b', para.text.lower()) is not None: - noncompliant_members.append({'Brief description': 'Don\'t add TODO comments to public doxygen documentation. Leave these as c++ code comments only.'}) + for para in d.iter("para"): + if para.text and re.search(r"\btodo\b", para.text.lower()) is not None: + noncompliant_members.append( + { + "Brief description": "Don't add TODO comments to public doxygen documentation. Leave these as c++ code comments only." + } + ) break # test for "added in QGIS xxx" string - d = e.find('detaileddescription') + d = e.find("detaileddescription") found_version_added = False - for para in d.iter('para'): - for s in para.iter('simplesect'): - if s.get('kind') == 'since': - for p in s.iter('para'): + for para in d.iter("para"): + for s in para.iter("simplesect"): + if s.get("kind") == "since": + for p in s.iter("para"): if self.version_regex.match(ET.tostring(p).decode()): found_version_added = True break - for s in para.iter('xrefsect'): - if s.find('xreftitle') is not None and 'Deprecated' in s.find('xreftitle').text: + for s in para.iter("xrefsect"): + if ( + s.find("xreftitle") is not None + and "Deprecated" in s.find("xreftitle").text + ): # can't have both deprecated and since, so if we've found deprecated then treat it as having satisfied the "since" requirement too found_version_added = True break - if para.text and re.search(r'\btodo\b', para.text.lower()) is not None: - noncompliant_members.append({ - 'Detailed description': 'Don\'t add TODO comments to public doxygen documentation. Leave these as c++ code comments only.'}) - - return documentable_members, documented_members, undocumented_members, noncompliant_members, bindable_members, has_brief_description, found_version_added, broken_links + if para.text and re.search(r"\btodo\b", para.text.lower()) is not None: + noncompliant_members.append( + { + "Detailed description": "Don't add TODO comments to public doxygen documentation. Leave these as c++ code comments only." + } + ) + + return ( + documentable_members, + documented_members, + undocumented_members, + noncompliant_members, + bindable_members, + has_brief_description, + found_version_added, + broken_links, + ) def memberSignature(self, elem): - """ Returns the signature for a member - :param elem: XML element for a class member + """Returns the signature for a member + :param elem: XML element for a class member """ - a = elem.find('argsstring') + a = elem.find("argsstring") try: if a is not None: - signature = elem.find('name').text + a.text + signature = elem.find("name").text + a.text else: - signature = elem.find('name').text - if signature.endswith('= default'): - signature = signature[:-len('= default')] + signature = elem.find("name").text + if signature.endswith("= default"): + signature = signature[: -len("= default")] return signature.strip() except: return None def elemIsBindableMember(self, elem): - """ Tests whether an member should be included in SIP bindings - :param elem: XML element for a class member + """Tests whether an member should be included in SIP bindings + :param elem: XML element for a class member """ # only public or protected members are bindable - if not self.visibility(elem) in ('public', 'protected'): + if not self.visibility(elem) in ("public", "protected"): return False # property themselves are not bound, only getters and setters @@ -323,18 +378,18 @@ def elemIsBindableMember(self, elem): if self.isTypeDef(elem): return False - if self.isVariable(elem) and self.visibility(elem) == 'protected': + if self.isVariable(elem) and self.visibility(elem) == "protected": # protected variables can't be bound in SIP return False # check for members with special python doc notes (probably 'not available' or renamed methods, either way # they should be safe to ignore as obviously some consideration has been given to Python bindings) try: - detailed_sec = elem.find('detaileddescription') - for p in detailed_sec.iter('para'): - for s in p.iter('simplesect'): - for ps in s.iter('para'): - if ps.text and 'python' in ps.text.lower(): + detailed_sec = elem.find("detaileddescription") + for p in detailed_sec.iter("para"): + for s in p.iter("simplesect"): + for ps in s.iter("para"): + if ps.text and "python" in ps.text.lower(): return False except: pass @@ -354,8 +409,8 @@ def elemIsBindableMember(self, elem): return True def elemIsDocumentableMember(self, elem): - """ Tests whether an member should be included in Doxygen docs - :param elem: XML element for a class member + """Tests whether an member should be included in Doxygen docs + :param elem: XML element for a class member """ # ignore variables (for now, eventually public/protected variables should be documented) @@ -363,7 +418,7 @@ def elemIsDocumentableMember(self, elem): return False # only public or protected members should be documented - if not self.visibility(elem) in ('public', 'protected'): + if not self.visibility(elem) in ("public", "protected"): return False # ignore reimplemented methods @@ -381,26 +436,43 @@ def elemIsDocumentableMember(self, elem): if self.isConstructor(elem): # ignore constructors with no arguments try: - if re.match(r'^\s*\(\s*\)\s*(?:=\s*(?:default|delete)\s*)?$', elem.find('argsstring').text): + if re.match( + r"^\s*\(\s*\)\s*(?:=\s*(?:default|delete)\s*)?$", + elem.find("argsstring").text, + ): return False except: pass # ignore copy, move constructors - name = elem.find('name').text - match = re.match(r'^\s*\(\s*(?:const)?\s*' + name + r'\s*&{0,2}\s*(?:[a-zA-Z0-9_]+)?\s*\)\s*(?:=\s*(?:default|delete)\s*)?$', elem.find('argsstring').text) + name = elem.find("name").text + match = re.match( + r"^\s*\(\s*(?:const)?\s*" + + name + + r"\s*&{0,2}\s*(?:[a-zA-Z0-9_]+)?\s*\)\s*(?:=\s*(?:default|delete)\s*)?$", + elem.find("argsstring").text, + ) if match: return False - name = elem.find('name') + name = elem.find("name") # ignore certain obvious operators - if name.text in ('operator=', 'operator==', 'operator!=', 'operator>=', 'operator>', 'operator<=', 'operator<', 'Q_ENUM'): + if name.text in ( + "operator=", + "operator==", + "operator!=", + "operator>=", + "operator>", + "operator<=", + "operator<", + "Q_ENUM", + ): return False # ignore on_* slots try: - if name.text.startswith('on_'): + if name.text.startswith("on_"): return False except: pass @@ -412,20 +484,20 @@ def elemIsDocumentableMember(self, elem): return True def visibility(self, elem): - """ Returns the visibility of a class or member - :param elem: XML element for a class or member + """Returns the visibility of a class or member + :param elem: XML element for a class or member """ try: - return elem.get('prot') + return elem.get("prot") except: - return '' + return "" def isVariable(self, member_elem): - """ Tests whether an member is a variable - :param member_elem: XML element for a class member + """Tests whether an member is a variable + :param member_elem: XML element for a class member """ try: - if member_elem.get('kind') == 'variable': + if member_elem.get("kind") == "variable": return True except: pass @@ -433,11 +505,11 @@ def isVariable(self, member_elem): return False def isProperty(self, member_elem): - """ Tests whether an member is a property - :param member_elem: XML element for a class member + """Tests whether an member is a property + :param member_elem: XML element for a class member """ try: - if member_elem.get('kind') == 'property': + if member_elem.get("kind") == "property": return True except: pass @@ -445,12 +517,12 @@ def isProperty(self, member_elem): return False def isDestructor(self, member_elem): - """ Tests whether an member is a destructor - :param member_elem: XML element for a class member + """Tests whether an member is a destructor + :param member_elem: XML element for a class member """ try: - name = member_elem.find('name').text - if name.startswith('~'): + name = member_elem.find("name").text + if name.startswith("~"): # destructor return True except: @@ -458,15 +530,15 @@ def isDestructor(self, member_elem): return False def isConstructor(self, member_elem): - """ Tests whether an member is a constructor - :param member_elem: XML element for a class member + """Tests whether an member is a constructor + :param member_elem: XML element for a class member """ try: - definition = member_elem.find('definition').text - name = member_elem.find('name').text - if f'{name}::{name}' in definition: + definition = member_elem.find("definition").text + name = member_elem.find("name").text + if f"{name}::{name}" in definition: return True - if re.match(rf'{name}\s*\<\s*[a-zA-Z0-9_]+\s*\>\s*::{name}', definition): + if re.match(rf"{name}\s*\<\s*[a-zA-Z0-9_]+\s*\>\s*::{name}", definition): return True except (AttributeError, re.error): pass @@ -474,12 +546,12 @@ def isConstructor(self, member_elem): return False def isOperator(self, member_elem): - """ Tests whether an member is an operator - :param member_elem: XML element for a class member + """Tests whether an member is an operator + :param member_elem: XML element for a class member """ try: - name = member_elem.find('name').text - if re.match(r'^operator\W.*', name): + name = member_elem.find("name").text + if re.match(r"^operator\W.*", name): return True except: pass @@ -487,39 +559,39 @@ def isOperator(self, member_elem): return False def isFriendClass(self, member_elem): - """ Tests whether an member is a friend class - :param member_elem: XML element for a class member + """Tests whether an member is a friend class + :param member_elem: XML element for a class member """ try: - if member_elem.get('kind') == 'friend': + if member_elem.get("kind") == "friend": return True except: pass return False def isTypeDef(self, member_elem): - """ Tests whether an member is a type def - :param member_elem: XML element for a class member + """Tests whether an member is a type def + :param member_elem: XML element for a class member """ try: - if member_elem.get('kind') == 'typedef': + if member_elem.get("kind") == "typedef": return True except: pass return False def isReimplementation(self, member_elem): - """ Tests whether an member is a reimplementation - :param member_elem: XML element for a class member + """Tests whether an member is a reimplementation + :param member_elem: XML element for a class member """ # use two different tests, as Doxygen will not detect reimplemented Qt methods try: - if member_elem.find('reimplements') is not None: + if member_elem.find("reimplements") is not None: return True - if ' override' in member_elem.find('argsstring').text: + if " override" in member_elem.find("argsstring").text: return True - if ' final' in member_elem.find('argsstring').text.lower(): + if " final" in member_elem.find("argsstring").text.lower(): return True except: pass @@ -527,91 +599,108 @@ def isReimplementation(self, member_elem): return False def isDeprecated(self, member_elem): - """ Tests whether an member is deprecated - :param member_elem: XML element for a class member + """Tests whether an member is deprecated + :param member_elem: XML element for a class member """ # look for both Q_DECL_DEPRECATED and Doxygen deprecated tag decl_deprecated = False - type_elem = member_elem.find('type') + type_elem = member_elem.find("type") try: - if 'Q_DECL_DEPRECATED' in type_elem.text: + if "Q_DECL_DEPRECATED" in type_elem.text: decl_deprecated = True except: pass - if b'Q_DECL_DEPRECATED' in ET.tostring(type_elem): + if b"Q_DECL_DEPRECATED" in ET.tostring(type_elem): decl_deprecated = True doxy_deprecated = False has_description = True try: - for p in member_elem.find('detaileddescription').iter('para'): - for s in p.iter('xrefsect'): - if s.find('xreftitle') is not None and 'Deprecated' in s.find('xreftitle').text: + for p in member_elem.find("detaileddescription").iter("para"): + for s in p.iter("xrefsect"): + if ( + s.find("xreftitle") is not None + and "Deprecated" in s.find("xreftitle").text + ): doxy_deprecated = True - if s.find('xrefdescription') is None or s.find('xrefdescription').find('para') is None: + if ( + s.find("xrefdescription") is None + or s.find("xrefdescription").find("para") is None + ): has_description = False break except: - assert 0, member_elem.find('definition').text + assert 0, member_elem.find("definition").text if not decl_deprecated and not doxy_deprecated: return False if doxy_deprecated and not has_description: - assert has_description, 'Error: Missing description for deprecated method {}'.format( - member_elem.find('definition').text) + assert ( + has_description + ), "Error: Missing description for deprecated method {}".format( + member_elem.find("definition").text + ) # only functions for now, but in future this should also apply for enums and variables - if member_elem.get('kind') in ('function', 'variable'): - assert decl_deprecated, 'Error: Missing Q_DECL_DEPRECATED for {}'.format( - member_elem.find('definition').text) - assert doxy_deprecated, 'Error: Missing Doxygen deprecated tag for {}'.format( - member_elem.find('definition').text) + if member_elem.get("kind") in ("function", "variable"): + assert decl_deprecated, "Error: Missing Q_DECL_DEPRECATED for {}".format( + member_elem.find("definition").text + ) + assert ( + doxy_deprecated + ), "Error: Missing Doxygen deprecated tag for {}".format( + member_elem.find("definition").text + ) return True def memberIsDocumented(self, member_elem): - """ Tests whether an member has documentation - :param member_elem: XML element for a class member + """Tests whether an member has documentation + :param member_elem: XML element for a class member """ - for doc_type in ('inbodydescription', 'briefdescription', 'detaileddescription'): + for doc_type in ( + "inbodydescription", + "briefdescription", + "detaileddescription", + ): doc = member_elem.find(doc_type) if doc is not None and list(doc): return True return False def memberDocIsNonCompliant(self, member_elem): - """ Tests whether an member's documentation is non-compliant - :param member_elem: XML element for a class member + """Tests whether an member's documentation is non-compliant + :param member_elem: XML element for a class member """ def _check_compliance(elem): - for para in elem.iter('para'): - for sect in para.iter('simplesect'): + for para in elem.iter("para"): + for sect in para.iter("simplesect"): res = _check_compliance(sect) if res: return res for t in para.itertext(): - if doc_type == 'briefdescription': - if t.strip().lower().startswith('getter'): + if doc_type == "briefdescription": + if t.strip().lower().startswith("getter"): return 'Use "Returns the..." instead of "getter"' - if t.strip().lower().startswith('get '): + if t.strip().lower().startswith("get "): return 'Use "Gets..." (or better, "Returns ...") instead of "get ..."' - elif t.strip().lower().startswith('setter'): + elif t.strip().lower().startswith("setter"): return 'Use "Sets the..." instead of "setter"' - elif t.strip().lower().startswith('mutator'): + elif t.strip().lower().startswith("mutator"): return 'Use "Sets the..." instead of "mutator for..."' - elif t.strip().lower().startswith('accessor'): + elif t.strip().lower().startswith("accessor"): return 'Use "Returns the..." instead of "accessor for..."' - elif t.strip().lower().startswith('return '): + elif t.strip().lower().startswith("return "): return 'Use "Returns the..." instead of "return ..."' - if re.search(r'\btodo\b', t.lower()) is not None: - return 'Don\'t add TODO comments to public doxygen documentation. Leave these as c++ code comments only.' + if re.search(r"\btodo\b", t.lower()) is not None: + return "Don't add TODO comments to public doxygen documentation. Leave these as c++ code comments only." - for doc_type in ['briefdescription', 'detaileddescription']: + for doc_type in ["briefdescription", "detaileddescription"]: doc = member_elem.find(doc_type) if doc is not None: res = _check_compliance(doc) @@ -625,15 +714,18 @@ def checkForBrokenSeeAlsoLinks(self, elem): Checks for any broken 'see also' links """ broken = [] - detailed_sec = elem.find('detaileddescription') - for p in detailed_sec.iter('para'): - for s in p.iter('simplesect'): - if s.get('kind') != 'see': + detailed_sec = elem.find("detaileddescription") + for p in detailed_sec.iter("para"): + for s in p.iter("simplesect"): + if s.get("kind") != "see": continue para = list(s.iter())[1] - if para.find('ref') is None and para.text and ( - not para.text.startswith('Q') or para.text.startswith('Qgs')): + if ( + para.find("ref") is None + and para.text + and (not para.text.startswith("Q") or para.text.startswith("Qgs")) + ): broken.append(para.text) return broken diff --git a/tests/code_layout/test_qgsdoccoverage.py b/tests/code_layout/test_qgsdoccoverage.py index b0bb071c9767..1e26fb81a6d7 100644 --- a/tests/code_layout/test_qgsdoccoverage.py +++ b/tests/code_layout/test_qgsdoccoverage.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '01/02/2015' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "01/02/2015" +__copyright__ = "Copyright 2016, The QGIS Project" import os import sys @@ -38,10 +39,15 @@ class TestQgsDocCoverage(unittest.TestCase): def testCoverage(self): - print('CTEST_FULL_OUTPUT') - prefixPath = os.environ['QGIS_PREFIX_PATH'] - docPath = os.path.join(prefixPath, '..', 'doc', 'api', 'xml') - parser = DoxygenParser(docPath, ACCEPTABLE_MISSING_DOCS, ACCEPTABLE_MISSING_ADDED_NOTE, ACCEPTABLE_MISSING_BRIEF) + print("CTEST_FULL_OUTPUT") + prefixPath = os.environ["QGIS_PREFIX_PATH"] + docPath = os.path.join(prefixPath, "..", "doc", "api", "xml") + parser = DoxygenParser( + docPath, + ACCEPTABLE_MISSING_DOCS, + ACCEPTABLE_MISSING_ADDED_NOTE, + ACCEPTABLE_MISSING_BRIEF, + ) coverage = 100.0 * parser.documented_members / parser.documentable_members missing = parser.documentable_members - parser.documented_members @@ -57,54 +63,117 @@ def testCoverage(self): if parser.undocumented_members: for cls, props in list(parser.undocumented_members.items()): - print('\n\nClass {}, {}/{} members documented\n'.format(colored(cls, 'yellow'), props['documented'], props['members'])) - for mem in props['missing_members']: - print(colored(' "' + mem + '"', 'yellow', attrs=['bold'])) + print( + "\n\nClass {}, {}/{} members documented\n".format( + colored(cls, "yellow"), props["documented"], props["members"] + ) + ) + for mem in props["missing_members"]: + print(colored(' "' + mem + '"', "yellow", attrs=["bold"])) if parser.noncompliant_members: for cls, props in list(parser.noncompliant_members.items()): - print('\n\nClass {}, non-compliant members found\n'.format(colored(cls, 'yellow'))) + print( + "\n\nClass {}, non-compliant members found\n".format( + colored(cls, "yellow") + ) + ) for p in props: for mem, error in p.items(): - print(colored(' ' + mem + ': ' + error, 'yellow', attrs=['bold'])) + print( + colored(" " + mem + ": " + error, "yellow", attrs=["bold"]) + ) if parser.broken_links: for cls, props in list(parser.broken_links.items()): - print('\n\nClass {}, broken see also links found\n'.format(colored(cls, 'yellow'))) + print( + "\n\nClass {}, broken see also links found\n".format( + colored(cls, "yellow") + ) + ) for member, links in props.items(): for l in links: - print(colored(' ' + member + ': ' + l, 'yellow', attrs=['bold'])) + print( + colored(" " + member + ": " + l, "yellow", attrs=["bold"]) + ) # self.assertEquals(len(parser.undocumented_string), 0, 'FAIL: new undocumented members have been introduced, please add documentation for these members') if parser.classes_missing_group: print("---------------------------------") - print('\n') - print(colored(f'{len(parser.classes_missing_group)} classes have been added without Doxygen group tag ("\\ingroup"):', 'yellow')) - print('') - print(' ' + '\n '.join([colored(cls, 'yellow', attrs=['bold']) for cls in parser.classes_missing_group])) + print("\n") + print( + colored( + f'{len(parser.classes_missing_group)} classes have been added without Doxygen group tag ("\\ingroup"):', + "yellow", + ) + ) + print("") + print( + " " + + "\n ".join( + [ + colored(cls, "yellow", attrs=["bold"]) + for cls in parser.classes_missing_group + ] + ) + ) if parser.classes_missing_version_added: print("---------------------------------") - print('\n') - print(colored(f'{len(parser.classes_missing_version_added)} classes have been added without a version added doxygen note ("\\since QGIS x.xx"):', 'yellow')) - print('') - print(' ' + '\n '.join([colored(cls, 'yellow', attrs=['bold']) for cls in parser.classes_missing_version_added])) + print("\n") + print( + colored( + f'{len(parser.classes_missing_version_added)} classes have been added without a version added doxygen note ("\\since QGIS x.xx"):', + "yellow", + ) + ) + print("") + print( + " " + + "\n ".join( + [ + colored(cls, "yellow", attrs=["bold"]) + for cls in parser.classes_missing_version_added + ] + ) + ) if parser.classes_missing_brief: print("---------------------------------") - print('\n') - print(colored(f'{len(parser.classes_missing_brief)} classes have been added without at least a brief description:', 'yellow')) - print('') - print(' ' + '\n '.join([colored(cls, 'yellow', attrs=['bold']) for cls in parser.classes_missing_brief])) + print("\n") + print( + colored( + f"{len(parser.classes_missing_brief)} classes have been added without at least a brief description:", + "yellow", + ) + ) + print("") + print( + " " + + "\n ".join( + [ + colored(cls, "yellow", attrs=["bold"]) + for cls in parser.classes_missing_brief + ] + ) + ) sys.stdout.flush() - self.assertTrue(not parser.undocumented_members, 'Undocumented members found') - self.assertTrue(not parser.classes_missing_group, 'Classes without \\group tag found') - self.assertTrue(not parser.classes_missing_version_added, 'Classes without \\since version tag found') - self.assertTrue(not parser.classes_missing_brief, 'Classes without \\brief description found') - self.assertTrue(not parser.noncompliant_members, 'Non compliant members found') - self.assertTrue(not parser.broken_links, 'Broken links found') - - -if __name__ == '__main__': + self.assertTrue(not parser.undocumented_members, "Undocumented members found") + self.assertTrue( + not parser.classes_missing_group, "Classes without \\group tag found" + ) + self.assertTrue( + not parser.classes_missing_version_added, + "Classes without \\since version tag found", + ) + self.assertTrue( + not parser.classes_missing_brief, + "Classes without \\brief description found", + ) + self.assertTrue(not parser.noncompliant_members, "Non compliant members found") + self.assertTrue(not parser.broken_links, "Broken links found") + + +if __name__ == "__main__": unittest.main() diff --git a/tests/code_layout/test_qgssipcoverage.py b/tests/code_layout/test_qgssipcoverage.py index bc8a87586f1e..afb12c778e77 100644 --- a/tests/code_layout/test_qgssipcoverage.py +++ b/tests/code_layout/test_qgssipcoverage.py @@ -5,12 +5,15 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '15/10/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "15/10/2015" +__copyright__ = "Copyright 2015, The QGIS Project" import os +from doxygen_parser import DoxygenParser + # Import all the things! from qgis.analysis import * # NOQA from qgis.core import * # NOQA @@ -19,8 +22,6 @@ from termcolor import colored from utilities import printImportant -from doxygen_parser import DoxygenParser - try: from qgis.server import * # NOQA except: @@ -30,9 +31,9 @@ class TestQgsSipCoverage(unittest.TestCase): def testCoverage(self): - print('CTEST_FULL_OUTPUT') - prefixPath = os.environ['QGIS_PREFIX_PATH'] - docPath = os.path.join(prefixPath, '..', 'doc', 'api', 'xml') + print("CTEST_FULL_OUTPUT") + prefixPath = os.environ["QGIS_PREFIX_PATH"] + docPath = os.path.join(prefixPath, "..", "doc", "api", "xml") parser = DoxygenParser(docPath) # first look for objects without any bindings @@ -41,8 +42,10 @@ def testCoverage(self): bound_objects = {} for o in objects: try: - if '::' in o: - bound_objects[o] = getattr(globals()[o.split('::')[0]], o.split('::')[1]) + if "::" in o: + bound_objects[o] = getattr( + globals()[o.split("::")[0]], o.split("::")[1] + ) else: bound_objects[o] = globals()[o] except: @@ -71,20 +74,32 @@ def testCoverage(self): if m[1] in dir(obj): continue except: - printImportant(f"SIP coverage test: something strange happened in {m[0]}.{m[1]}, obj={obj}") + printImportant( + f"SIP coverage test: something strange happened in {m[0]}.{m[1]}, obj={obj}" + ) - missing_members.append(f'{m[0]}.{m[1]}') + missing_members.append(f"{m[0]}.{m[1]}") missing_members.sort() if missing_objects: print("---------------------------------") - print(colored('Missing classes:', 'yellow')) - print(' ' + '\n '.join([colored(obj, 'yellow', attrs=['bold']) for obj in missing_objects])) + print(colored("Missing classes:", "yellow")) + print( + " " + + "\n ".join( + [colored(obj, "yellow", attrs=["bold"]) for obj in missing_objects] + ) + ) if missing_members: print("---------------------------------") - print(colored('Missing members:', 'yellow')) - print(' ' + '\n '.join([colored(mem, 'yellow', attrs=['bold']) for mem in missing_members])) + print(colored("Missing members:", "yellow")) + print( + " " + + "\n ".join( + [colored(mem, "yellow", attrs=["bold"]) for mem in missing_members] + ) + ) # print summaries missing_class_count = len(missing_objects) @@ -110,14 +125,22 @@ def testCoverage(self): printImportant("---------------------------------") printImportant(f"{missing_member_count} members missing bindings") - self.assertEqual(missing_class_count, 0, """\n\nFAIL: new unbound classes have been introduced, please add SIP bindings for these classes + self.assertEqual( + missing_class_count, + 0, + """\n\nFAIL: new unbound classes have been introduced, please add SIP bindings for these classes If these classes are not suitable for the Python bindings, please add the Doxygen tag -"\\note not available in Python bindings" to the CLASS Doxygen comments""") +"\\note not available in Python bindings" to the CLASS Doxygen comments""", + ) - self.assertEqual(missing_member_count, 0, """\n\nFAIL: new unbound members have been introduced, please add SIP bindings for these members + self.assertEqual( + missing_member_count, + 0, + """\n\nFAIL: new unbound members have been introduced, please add SIP bindings for these members If these members are not suitable for the Python bindings, please add the Doxygen tag -"\\note not available in Python bindings" to the MEMBER Doxygen comments""") +"\\note not available in Python bindings" to the MEMBER Doxygen comments""", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/featuresourcetestbase.py b/tests/src/python/featuresourcetestbase.py index c492be10e1b1..a17bd06d908b 100644 --- a/tests/src/python/featuresourcetestbase.py +++ b/tests/src/python/featuresourcetestbase.py @@ -6,10 +6,9 @@ (at your option) any later version. """ - -__author__ = 'Nyall Dawson' -__date__ = '2017-05-25' -__copyright__ = 'Copyright 2017, The QGIS Project' +__author__ = "Nyall Dawson" +__date__ = "2017-05-25" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, Qt, QTime from qgis.core import ( @@ -51,7 +50,7 @@ def treat_datetime_tz_as_utc(self): return False def testCrs(self): - self.assertEqual(self.source.sourceCrs().authid(), 'EPSG:4326') + self.assertEqual(self.source.sourceCrs().authid(), "EPSG:4326") def testWkbType(self): self.assertEqual(self.source.wkbType(), QgsWkbTypes.Type.Point) @@ -62,12 +61,18 @@ def testFeatureCount(self): def testFields(self): fields = self.source.fields() - for f in ('pk', 'cnt', 'name', 'name2', 'num_char'): + for f in ("pk", "cnt", "name", "name2", "num_char"): self.assertGreaterEqual(fields.lookupField(f), 0) - def testGetFeatures(self, source=None, extra_features=[], skip_features=[], changed_attributes={}, - changed_geometries={}): - """ Test that expected results are returned when fetching all features """ + def testGetFeatures( + self, + source=None, + extra_features=[], + skip_features=[], + changed_attributes={}, + changed_geometries={}, + ): + """Test that expected results are returned when fetching all features""" # IMPORTANT - we do not use `for f in source.getFeatures()` as we are also # testing that existing attributes & geometry in f are overwritten correctly @@ -85,26 +90,131 @@ def testGetFeatures(self, source=None, extra_features=[], skip_features=[], chan self.assertTrue(f.isValid()) # some source test datasets will include additional attributes which we ignore, # so cherry pick desired attributes - attrs = [f['pk'], f['cnt'], f['name'], f['name2'], f['num_char'], f['dt'], f['date'], f['time']] + attrs = [ + f["pk"], + f["cnt"], + f["name"], + f["name2"], + f["num_char"], + f["dt"], + f["date"], + f["time"], + ] # force the num_char attribute to be text - some sources (e.g., delimited text) will # automatically detect that this attribute contains numbers and set it as a numeric # field - attrs[4] = 'NULL' if attrs[4] is None else str(attrs[4]) - attributes[f['pk']] = attrs - geometries[f['pk']] = f.hasGeometry() and f.geometry().asWkt() - - tz = Qt.TimeSpec.UTC if self.treat_datetime_tz_as_utc() else Qt.TimeSpec.LocalTime - expected_attributes = {5: [5, -200, NULL, 'NuLl', '5', QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14), tz) if not self.treat_datetime_as_string() else '2020-05-04 12:13:14', QDate(2020, 5, 2) if not self.treat_date_as_datetime() and not self.treat_date_as_string() else QDateTime(2020, 5, 2, 0, 0, 0) if not self.treat_date_as_string() else '2020-05-02', QTime(12, 13, 1) if not self.treat_time_as_string() else '12:13:01'], - 3: [3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL], - 1: [1, 100, 'Orange', 'oranGe', '1', QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14), tz) if not self.treat_datetime_as_string() else '2020-05-03 12:13:14', QDate(2020, 5, 3) if not self.treat_date_as_datetime() and not self.treat_date_as_string() else QDateTime(2020, 5, 3, 0, 0, 0) if not self.treat_date_as_string() else '2020-05-03', QTime(12, 13, 14) if not self.treat_time_as_string() else '12:13:14'], - 2: [2, 200, 'Apple', 'Apple', '2', QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14), tz) if not self.treat_datetime_as_string() else '2020-05-04 12:14:14', QDate(2020, 5, 4) if not self.treat_date_as_datetime() and not self.treat_date_as_string() else QDateTime(2020, 5, 4, 0, 0, 0) if not self.treat_date_as_string() else '2020-05-04', QTime(12, 14, 14) if not self.treat_time_as_string() else '12:14:14'], - 4: [4, 400, 'Honey', 'Honey', '4', QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14), tz) if not self.treat_datetime_as_string() else '2021-05-04 13:13:14', QDate(2021, 5, 4) if not self.treat_date_as_datetime() and not self.treat_date_as_string() else QDateTime(2021, 5, 4, 0, 0, 0) if not self.treat_date_as_string() else '2021-05-04', QTime(13, 13, 14) if not self.treat_time_as_string() else '13:13:14']} - - expected_geometries = {1: 'Point (-70.332 66.33)', - 2: 'Point (-68.2 70.8)', - 3: None, - 4: 'Point(-65.32 78.3)', - 5: 'Point(-71.123 78.23)'} + attrs[4] = "NULL" if attrs[4] is None else str(attrs[4]) + attributes[f["pk"]] = attrs + geometries[f["pk"]] = f.hasGeometry() and f.geometry().asWkt() + + tz = ( + Qt.TimeSpec.UTC + if self.treat_datetime_tz_as_utc() + else Qt.TimeSpec.LocalTime + ) + expected_attributes = { + 5: [ + 5, + -200, + NULL, + "NuLl", + "5", + ( + QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14), tz) + if not self.treat_datetime_as_string() + else "2020-05-04 12:13:14" + ), + ( + QDate(2020, 5, 2) + if not self.treat_date_as_datetime() + and not self.treat_date_as_string() + else ( + QDateTime(2020, 5, 2, 0, 0, 0) + if not self.treat_date_as_string() + else "2020-05-02" + ) + ), + QTime(12, 13, 1) if not self.treat_time_as_string() else "12:13:01", + ], + 3: [3, 300, "Pear", "PEaR", "3", NULL, NULL, NULL], + 1: [ + 1, + 100, + "Orange", + "oranGe", + "1", + ( + QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14), tz) + if not self.treat_datetime_as_string() + else "2020-05-03 12:13:14" + ), + ( + QDate(2020, 5, 3) + if not self.treat_date_as_datetime() + and not self.treat_date_as_string() + else ( + QDateTime(2020, 5, 3, 0, 0, 0) + if not self.treat_date_as_string() + else "2020-05-03" + ) + ), + QTime(12, 13, 14) if not self.treat_time_as_string() else "12:13:14", + ], + 2: [ + 2, + 200, + "Apple", + "Apple", + "2", + ( + QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14), tz) + if not self.treat_datetime_as_string() + else "2020-05-04 12:14:14" + ), + ( + QDate(2020, 5, 4) + if not self.treat_date_as_datetime() + and not self.treat_date_as_string() + else ( + QDateTime(2020, 5, 4, 0, 0, 0) + if not self.treat_date_as_string() + else "2020-05-04" + ) + ), + QTime(12, 14, 14) if not self.treat_time_as_string() else "12:14:14", + ], + 4: [ + 4, + 400, + "Honey", + "Honey", + "4", + ( + QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14), tz) + if not self.treat_datetime_as_string() + else "2021-05-04 13:13:14" + ), + ( + QDate(2021, 5, 4) + if not self.treat_date_as_datetime() + and not self.treat_date_as_string() + else ( + QDateTime(2021, 5, 4, 0, 0, 0) + if not self.treat_date_as_string() + else "2021-05-04" + ) + ), + QTime(13, 13, 14) if not self.treat_time_as_string() else "13:13:14", + ], + } + + expected_geometries = { + 1: "Point (-70.332 66.33)", + 2: "Point (-68.2 70.8)", + 3: None, + 4: "Point(-65.32 78.3)", + 5: "Point(-71.123 78.23)", + } for f in extra_features: expected_attributes[f[0]] = f.attributes() if f.hasGeometry(): @@ -118,226 +228,321 @@ def testGetFeatures(self, source=None, extra_features=[], skip_features=[], chan for i, a in changed_attributes.items(): for attr_idx, v in a.items(): expected_attributes[i][attr_idx] = v - for i, g, in changed_geometries.items(): + for ( + i, + g, + ) in changed_geometries.items(): if g: expected_geometries[i] = g.asWkt() else: expected_geometries[i] = None - self.assertEqual(attributes, expected_attributes, f'Expected {expected_attributes}, got {attributes}') + self.assertEqual( + attributes, + expected_attributes, + f"Expected {expected_attributes}, got {attributes}", + ) self.assertEqual(len(expected_geometries), len(geometries)) for pk, geom in list(expected_geometries.items()): if geom: - assert compareWkt(geom, geometries[pk]), "Geometry {} mismatch Expected:\n{}\nGot:\n{}\n".format(pk, - geom, - geometries[ - pk]) + assert compareWkt( + geom, geometries[pk] + ), "Geometry {} mismatch Expected:\n{}\nGot:\n{}\n".format( + pk, geom, geometries[pk] + ) else: - self.assertFalse(geometries[pk], f'Expected null geometry for {pk}') + self.assertFalse(geometries[pk], f"Expected null geometry for {pk}") def assert_query(self, source, expression, expected): - request = QgsFeatureRequest().setFilterExpression(expression).setFlags(QgsFeatureRequest.Flag.NoGeometry | QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation) - result = {f['pk'] for f in source.getFeatures(request)} - assert set(expected) == result, 'Expected {} and got {} when testing expression "{}"'.format(set(expected), - result, expression) + request = ( + QgsFeatureRequest() + .setFilterExpression(expression) + .setFlags( + QgsFeatureRequest.Flag.NoGeometry + | QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation + ) + ) + result = {f["pk"] for f in source.getFeatures(request)} + assert ( + set(expected) == result + ), 'Expected {} and got {} when testing expression "{}"'.format( + set(expected), result, expression + ) self.assertTrue(all(f.isValid() for f in source.getFeatures(request))) # Also check that filter works when referenced fields are not being retrieved by request - result = {f['pk'] for f in source.getFeatures( - QgsFeatureRequest().setFilterExpression(expression).setSubsetOfAttributes(['pk'], self.source.fields()).setFlags(QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation))} - assert set( - expected) == result, 'Expected {} and got {} when testing expression "{}" using empty attribute subset'.format( - set(expected), result, expression) + result = { + f["pk"] + for f in source.getFeatures( + QgsFeatureRequest() + .setFilterExpression(expression) + .setSubsetOfAttributes(["pk"], self.source.fields()) + .setFlags( + QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation + ) + ) + } + assert ( + set(expected) == result + ), 'Expected {} and got {} when testing expression "{}" using empty attribute subset'.format( + set(expected), result, expression + ) # test that results match QgsFeatureRequest.acceptFeature - request = QgsFeatureRequest().setFilterExpression(expression).setFlags(QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation) + request = ( + QgsFeatureRequest() + .setFilterExpression(expression) + .setFlags( + QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation + ) + ) for f in source.getFeatures(): - self.assertEqual(request.acceptFeature(f), f['pk'] in expected) + self.assertEqual(request.acceptFeature(f), f["pk"] in expected) def runGetFeatureTests(self, source): self.assertEqual(len([f for f in source.getFeatures()]), 5) - self.assert_query(source, 'name ILIKE \'QGIS\'', []) + self.assert_query(source, "name ILIKE 'QGIS'", []) self.assert_query(source, '"name" IS NULL', [5]) self.assert_query(source, '"name" IS NOT NULL', [1, 2, 3, 4]) - self.assert_query(source, '"name" NOT LIKE \'Ap%\'', [1, 3, 4]) - self.assert_query(source, '"name" NOT ILIKE \'QGIS\'', [1, 2, 3, 4]) - self.assert_query(source, '"name" NOT ILIKE \'pEAR\'', [1, 2, 4]) - self.assert_query(source, 'name = \'Apple\'', [2]) + self.assert_query(source, "\"name\" NOT LIKE 'Ap%'", [1, 3, 4]) + self.assert_query(source, "\"name\" NOT ILIKE 'QGIS'", [1, 2, 3, 4]) + self.assert_query(source, "\"name\" NOT ILIKE 'pEAR'", [1, 2, 4]) + self.assert_query(source, "name = 'Apple'", [2]) # field names themselves are NOT case sensitive -- QGIS expressions don't care about this - self.assert_query(source, '\"NaMe\" = \'Apple\'', [2]) - self.assert_query(source, 'name <> \'Apple\'', [1, 3, 4]) - self.assert_query(source, 'name = \'apple\'', []) - self.assert_query(source, '"name" <> \'apple\'', [1, 2, 3, 4]) - self.assert_query(source, '(name = \'Apple\') is not null', [1, 2, 3, 4]) - self.assert_query(source, 'name LIKE \'Apple\'', [2]) - self.assert_query(source, 'name LIKE \'aPple\'', []) - self.assert_query(source, 'name LIKE \'Ap_le\'', [2]) - self.assert_query(source, 'name LIKE \'Ap\\_le\'', []) - self.assert_query(source, 'name ILIKE \'aPple\'', [2]) - self.assert_query(source, 'name ILIKE \'%pp%\'', [2]) - self.assert_query(source, 'cnt > 0', [1, 2, 3, 4]) - self.assert_query(source, '-cnt > 0', [5]) - self.assert_query(source, 'cnt < 0', [5]) - self.assert_query(source, '-cnt < 0', [1, 2, 3, 4]) - self.assert_query(source, 'cnt >= 100', [1, 2, 3, 4]) - self.assert_query(source, 'cnt <= 100', [1, 5]) - self.assert_query(source, 'pk IN (1, 2, 4, 8)', [1, 2, 4]) - self.assert_query(source, 'cnt = 50 * 2', [1]) - self.assert_query(source, 'cnt = 150 / 1.5', [1]) - self.assert_query(source, 'cnt = 1000 / 10', [1]) - self.assert_query(source, 'cnt = 1000/11+10', []) # checks that source isn't rounding int/int - self.assert_query(source, 'pk = 9 // 4', [2]) # int division - self.assert_query(source, 'cnt = 99 + 1', [1]) - self.assert_query(source, 'cnt = 101 - 1', [1]) - self.assert_query(source, 'cnt - 1 = 99', [1]) - self.assert_query(source, '-cnt - 1 = -101', [1]) - self.assert_query(source, '-(-cnt) = 100', [1]) - self.assert_query(source, '-(cnt) = -(100)', [1]) - self.assert_query(source, 'cnt + 1 = 101', [1]) - self.assert_query(source, 'cnt = 1100 % 1000', [1]) - self.assert_query(source, '"name" || \' \' || "name" = \'Orange Orange\'', [1]) - self.assert_query(source, '"name" || \' \' || "cnt" = \'Orange 100\'', [1]) - self.assert_query(source, '\'x\' || "name" IS NOT NULL', [1, 2, 3, 4]) - self.assert_query(source, '\'x\' || "name" IS NULL', [5]) - self.assert_query(source, 'cnt = 10 ^ 2', [1]) - self.assert_query(source, '"name" ~ \'[OP]ra[gne]+\'', [1]) - self.assert_query(source, '"name"="name2"', [2, 4]) # mix of matched and non-matched case sensitive names - self.assert_query(source, 'true', [1, 2, 3, 4, 5]) - self.assert_query(source, 'false', []) + self.assert_query(source, "\"NaMe\" = 'Apple'", [2]) + self.assert_query(source, "name <> 'Apple'", [1, 3, 4]) + self.assert_query(source, "name = 'apple'", []) + self.assert_query(source, "\"name\" <> 'apple'", [1, 2, 3, 4]) + self.assert_query(source, "(name = 'Apple') is not null", [1, 2, 3, 4]) + self.assert_query(source, "name LIKE 'Apple'", [2]) + self.assert_query(source, "name LIKE 'aPple'", []) + self.assert_query(source, "name LIKE 'Ap_le'", [2]) + self.assert_query(source, "name LIKE 'Ap\\_le'", []) + self.assert_query(source, "name ILIKE 'aPple'", [2]) + self.assert_query(source, "name ILIKE '%pp%'", [2]) + self.assert_query(source, "cnt > 0", [1, 2, 3, 4]) + self.assert_query(source, "-cnt > 0", [5]) + self.assert_query(source, "cnt < 0", [5]) + self.assert_query(source, "-cnt < 0", [1, 2, 3, 4]) + self.assert_query(source, "cnt >= 100", [1, 2, 3, 4]) + self.assert_query(source, "cnt <= 100", [1, 5]) + self.assert_query(source, "pk IN (1, 2, 4, 8)", [1, 2, 4]) + self.assert_query(source, "cnt = 50 * 2", [1]) + self.assert_query(source, "cnt = 150 / 1.5", [1]) + self.assert_query(source, "cnt = 1000 / 10", [1]) + self.assert_query( + source, "cnt = 1000/11+10", [] + ) # checks that source isn't rounding int/int + self.assert_query(source, "pk = 9 // 4", [2]) # int division + self.assert_query(source, "cnt = 99 + 1", [1]) + self.assert_query(source, "cnt = 101 - 1", [1]) + self.assert_query(source, "cnt - 1 = 99", [1]) + self.assert_query(source, "-cnt - 1 = -101", [1]) + self.assert_query(source, "-(-cnt) = 100", [1]) + self.assert_query(source, "-(cnt) = -(100)", [1]) + self.assert_query(source, "cnt + 1 = 101", [1]) + self.assert_query(source, "cnt = 1100 % 1000", [1]) + self.assert_query(source, "\"name\" || ' ' || \"name\" = 'Orange Orange'", [1]) + self.assert_query(source, "\"name\" || ' ' || \"cnt\" = 'Orange 100'", [1]) + self.assert_query(source, "'x' || \"name\" IS NOT NULL", [1, 2, 3, 4]) + self.assert_query(source, "'x' || \"name\" IS NULL", [5]) + self.assert_query(source, "cnt = 10 ^ 2", [1]) + self.assert_query(source, "\"name\" ~ '[OP]ra[gne]+'", [1]) + self.assert_query( + source, '"name"="name2"', [2, 4] + ) # mix of matched and non-matched case sensitive names + self.assert_query(source, "true", [1, 2, 3, 4, 5]) + self.assert_query(source, "false", []) # Three value logic - self.assert_query(source, 'false and false', []) - self.assert_query(source, 'false and true', []) - self.assert_query(source, 'false and NULL', []) - self.assert_query(source, 'true and false', []) - self.assert_query(source, 'true and true', [1, 2, 3, 4, 5]) - self.assert_query(source, 'true and NULL', []) - self.assert_query(source, 'NULL and false', []) - self.assert_query(source, 'NULL and true', []) - self.assert_query(source, 'NULL and NULL', []) - self.assert_query(source, 'false or false', []) - self.assert_query(source, 'false or true', [1, 2, 3, 4, 5]) - self.assert_query(source, 'false or NULL', []) - self.assert_query(source, 'true or false', [1, 2, 3, 4, 5]) - self.assert_query(source, 'true or true', [1, 2, 3, 4, 5]) - self.assert_query(source, 'true or NULL', [1, 2, 3, 4, 5]) - self.assert_query(source, 'NULL or false', []) - self.assert_query(source, 'NULL or true', [1, 2, 3, 4, 5]) - self.assert_query(source, 'NULL or NULL', []) - self.assert_query(source, 'not true', []) - self.assert_query(source, 'not false', [1, 2, 3, 4, 5]) - self.assert_query(source, 'not null', []) + self.assert_query(source, "false and false", []) + self.assert_query(source, "false and true", []) + self.assert_query(source, "false and NULL", []) + self.assert_query(source, "true and false", []) + self.assert_query(source, "true and true", [1, 2, 3, 4, 5]) + self.assert_query(source, "true and NULL", []) + self.assert_query(source, "NULL and false", []) + self.assert_query(source, "NULL and true", []) + self.assert_query(source, "NULL and NULL", []) + self.assert_query(source, "false or false", []) + self.assert_query(source, "false or true", [1, 2, 3, 4, 5]) + self.assert_query(source, "false or NULL", []) + self.assert_query(source, "true or false", [1, 2, 3, 4, 5]) + self.assert_query(source, "true or true", [1, 2, 3, 4, 5]) + self.assert_query(source, "true or NULL", [1, 2, 3, 4, 5]) + self.assert_query(source, "NULL or false", []) + self.assert_query(source, "NULL or true", [1, 2, 3, 4, 5]) + self.assert_query(source, "NULL or NULL", []) + self.assert_query(source, "not true", []) + self.assert_query(source, "not false", [1, 2, 3, 4, 5]) + self.assert_query(source, "not null", []) # not - self.assert_query(source, 'not name = \'Apple\'', [1, 3, 4]) - self.assert_query(source, 'not name IS NULL', [1, 2, 3, 4]) - self.assert_query(source, 'not name = \'Apple\' or name = \'Apple\'', [1, 2, 3, 4]) - self.assert_query(source, 'not name = \'Apple\' or not name = \'Apple\'', [1, 3, 4]) - self.assert_query(source, 'not name = \'Apple\' and pk = 4', [4]) - self.assert_query(source, 'not name = \'Apple\' and not pk = 4', [1, 3]) - self.assert_query(source, 'not pk IN (1, 2, 4, 8)', [3, 5]) + self.assert_query(source, "not name = 'Apple'", [1, 3, 4]) + self.assert_query(source, "not name IS NULL", [1, 2, 3, 4]) + self.assert_query(source, "not name = 'Apple' or name = 'Apple'", [1, 2, 3, 4]) + self.assert_query(source, "not name = 'Apple' or not name = 'Apple'", [1, 3, 4]) + self.assert_query(source, "not name = 'Apple' and pk = 4", [4]) + self.assert_query(source, "not name = 'Apple' and not pk = 4", [1, 3]) + self.assert_query(source, "not pk IN (1, 2, 4, 8)", [3, 5]) # type conversion - QGIS expressions do not mind that we are comparing a string # against numeric literals - self.assert_query(source, 'num_char IN (2, 4, 5)', [2, 4, 5]) + self.assert_query(source, "num_char IN (2, 4, 5)", [2, 4, 5]) # function - self.assert_query(source, 'sqrt(pk) >= 2', [4, 5]) - self.assert_query(source, 'radians(cnt) < 2', [1, 5]) - self.assert_query(source, 'degrees(pk) <= 200', [1, 2, 3]) - self.assert_query(source, 'abs(cnt) <= 200', [1, 2, 5]) - self.assert_query(source, 'cos(pk) < 0', [2, 3, 4]) - self.assert_query(source, 'sin(pk) < 0', [4, 5]) - self.assert_query(source, 'tan(pk) < 0', [2, 3, 5]) - self.assert_query(source, 'acos(-1) < pk', [4, 5]) - self.assert_query(source, 'asin(1) < pk', [2, 3, 4, 5]) - self.assert_query(source, 'atan(3.14) < pk', [2, 3, 4, 5]) - self.assert_query(source, 'atan2(3.14, pk) < 1', [3, 4, 5]) - self.assert_query(source, 'exp(pk) < 10', [1, 2]) - self.assert_query(source, 'ln(pk) <= 1', [1, 2]) - self.assert_query(source, 'log(3, pk) <= 1', [1, 2, 3]) - self.assert_query(source, 'log10(pk) < 0.5', [1, 2, 3]) - self.assert_query(source, 'round(3.14) <= pk', [3, 4, 5]) - self.assert_query(source, 'round(0.314,1) * 10 = pk', [3]) - self.assert_query(source, 'floor(3.14) <= pk', [3, 4, 5]) - self.assert_query(source, 'ceil(3.14) <= pk', [4, 5]) - self.assert_query(source, 'pk < pi()', [1, 2, 3]) - - self.assert_query(source, 'round(cnt / 66.67) <= 2', [1, 5]) - self.assert_query(source, 'floor(cnt / 66.67) <= 2', [1, 2, 5]) - self.assert_query(source, 'ceil(cnt / 66.67) <= 2', [1, 5]) - self.assert_query(source, 'pk < pi() / 2', [1]) - self.assert_query(source, 'pk = char(51)', [3]) - self.assert_query(source, 'pk = coalesce(NULL,3,4)', [3]) - self.assert_query(source, 'lower(name) = \'apple\'', [2]) - self.assert_query(source, 'upper(name) = \'APPLE\'', [2]) - self.assert_query(source, 'name = trim(\' Apple \')', [2]) + self.assert_query(source, "sqrt(pk) >= 2", [4, 5]) + self.assert_query(source, "radians(cnt) < 2", [1, 5]) + self.assert_query(source, "degrees(pk) <= 200", [1, 2, 3]) + self.assert_query(source, "abs(cnt) <= 200", [1, 2, 5]) + self.assert_query(source, "cos(pk) < 0", [2, 3, 4]) + self.assert_query(source, "sin(pk) < 0", [4, 5]) + self.assert_query(source, "tan(pk) < 0", [2, 3, 5]) + self.assert_query(source, "acos(-1) < pk", [4, 5]) + self.assert_query(source, "asin(1) < pk", [2, 3, 4, 5]) + self.assert_query(source, "atan(3.14) < pk", [2, 3, 4, 5]) + self.assert_query(source, "atan2(3.14, pk) < 1", [3, 4, 5]) + self.assert_query(source, "exp(pk) < 10", [1, 2]) + self.assert_query(source, "ln(pk) <= 1", [1, 2]) + self.assert_query(source, "log(3, pk) <= 1", [1, 2, 3]) + self.assert_query(source, "log10(pk) < 0.5", [1, 2, 3]) + self.assert_query(source, "round(3.14) <= pk", [3, 4, 5]) + self.assert_query(source, "round(0.314,1) * 10 = pk", [3]) + self.assert_query(source, "floor(3.14) <= pk", [3, 4, 5]) + self.assert_query(source, "ceil(3.14) <= pk", [4, 5]) + self.assert_query(source, "pk < pi()", [1, 2, 3]) + + self.assert_query(source, "round(cnt / 66.67) <= 2", [1, 5]) + self.assert_query(source, "floor(cnt / 66.67) <= 2", [1, 2, 5]) + self.assert_query(source, "ceil(cnt / 66.67) <= 2", [1, 5]) + self.assert_query(source, "pk < pi() / 2", [1]) + self.assert_query(source, "pk = char(51)", [3]) + self.assert_query(source, "pk = coalesce(NULL,3,4)", [3]) + self.assert_query(source, "lower(name) = 'apple'", [2]) + self.assert_query(source, "upper(name) = 'APPLE'", [2]) + self.assert_query(source, "name = trim(' Apple ')", [2]) # geometry # azimuth and touches tests are deactivated because they do not pass for WFS source # self.assert_query(source, 'azimuth($geometry,geom_from_wkt( \'Point (-70 70)\')) < pi()', [1, 5]) - self.assert_query(source, 'x($geometry) < -70', [1, 5]) - self.assert_query(source, 'y($geometry) > 70', [2, 4, 5]) - self.assert_query(source, 'xmin($geometry) < -70', [1, 5]) - self.assert_query(source, 'ymin($geometry) > 70', [2, 4, 5]) - self.assert_query(source, 'xmax($geometry) < -70', [1, 5]) - self.assert_query(source, 'ymax($geometry) > 70', [2, 4, 5]) - self.assert_query(source, - 'disjoint($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', - [4, 5]) - self.assert_query(source, - 'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', - [1, 2]) + self.assert_query(source, "x($geometry) < -70", [1, 5]) + self.assert_query(source, "y($geometry) > 70", [2, 4, 5]) + self.assert_query(source, "xmin($geometry) < -70", [1, 5]) + self.assert_query(source, "ymin($geometry) > 70", [2, 4, 5]) + self.assert_query(source, "xmax($geometry) < -70", [1, 5]) + self.assert_query(source, "ymax($geometry) > 70", [2, 4, 5]) + self.assert_query( + source, + "disjoint($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))", + [4, 5], + ) + self.assert_query( + source, + "intersects($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))", + [1, 2], + ) # self.assert_query(source, 'touches($geometry,geom_from_wkt( \'Polygon ((-70.332 66.33, -65.32 66.33, -65.32 78.3, -70.332 78.3, -70.332 66.33))\'))', [1, 4]) - self.assert_query(source, - 'contains(geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'),$geometry)', - [1, 2]) - self.assert_query(source, 'distance($geometry,geom_from_wkt( \'Point (-70 70)\')) > 7', [4, 5]) - self.assert_query(source, - 'intersects($geometry,geom_from_gml( \'-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1\'))', - [1, 2]) + self.assert_query( + source, + "contains(geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'),$geometry)", + [1, 2], + ) + self.assert_query( + source, "distance($geometry,geom_from_wkt( 'Point (-70 70)')) > 7", [4, 5] + ) + self.assert_query( + source, + "intersects($geometry,geom_from_gml( '-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1'))", + [1, 2], + ) # between/not between - self.assert_query(source, 'cnt BETWEEN -200 AND 200', [1, 2, 5]) - self.assert_query(source, 'cnt NOT BETWEEN 100 AND 200', [3, 4, 5]) + self.assert_query(source, "cnt BETWEEN -200 AND 200", [1, 2, 5]) + self.assert_query(source, "cnt NOT BETWEEN 100 AND 200", [3, 4, 5]) if self.treat_datetime_as_string(): - self.assert_query(source, """dt BETWEEN format_date(make_datetime(2020, 5, 3, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss') AND format_date(make_datetime(2020, 5, 4, 12, 14, 14), 'yyyy-MM-dd hh:mm:ss')""", [1, 2, 5]) - self.assert_query(source, """dt NOT BETWEEN format_date(make_datetime(2020, 5, 3, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss') AND format_date(make_datetime(2020, 5, 4, 12, 14, 14), 'yyyy-MM-dd hh:mm:ss')""", [4]) + self.assert_query( + source, + """dt BETWEEN format_date(make_datetime(2020, 5, 3, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss') AND format_date(make_datetime(2020, 5, 4, 12, 14, 14), 'yyyy-MM-dd hh:mm:ss')""", + [1, 2, 5], + ) + self.assert_query( + source, + """dt NOT BETWEEN format_date(make_datetime(2020, 5, 3, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss') AND format_date(make_datetime(2020, 5, 4, 12, 14, 14), 'yyyy-MM-dd hh:mm:ss')""", + [4], + ) else: - self.assert_query(source, 'dt BETWEEN make_datetime(2020, 5, 3, 12, 13, 14) AND make_datetime(2020, 5, 4, 12, 14, 14)', [1, 2, 5]) - self.assert_query(source, 'dt NOT BETWEEN make_datetime(2020, 5, 3, 12, 13, 14) AND make_datetime(2020, 5, 4, 12, 14, 14)', [4]) + self.assert_query( + source, + "dt BETWEEN make_datetime(2020, 5, 3, 12, 13, 14) AND make_datetime(2020, 5, 4, 12, 14, 14)", + [1, 2, 5], + ) + self.assert_query( + source, + "dt NOT BETWEEN make_datetime(2020, 5, 3, 12, 13, 14) AND make_datetime(2020, 5, 4, 12, 14, 14)", + [4], + ) # datetime if self.treat_datetime_as_string(): - self.assert_query(source, '"dt" <= format_date(make_datetime(2020, 5, 4, 12, 13, 14), \'yyyy-MM-dd hh:mm:ss\')', [1, 5]) - self.assert_query(source, '"dt" < format_date(make_date(2020, 5, 4), \'yyyy-MM-dd hh:mm:ss\')', [1]) - self.assert_query(source, '"dt" = format_date(to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\'),\'yyyy-MM-dd hh:mm:ss\')', [5]) + self.assert_query( + source, + "\"dt\" <= format_date(make_datetime(2020, 5, 4, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss')", + [1, 5], + ) + self.assert_query( + source, + "\"dt\" < format_date(make_date(2020, 5, 4), 'yyyy-MM-dd hh:mm:ss')", + [1], + ) + self.assert_query( + source, + "\"dt\" = format_date(to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy'),'yyyy-MM-dd hh:mm:ss')", + [5], + ) else: - self.assert_query(source, '"dt" <= make_datetime(2020, 5, 4, 12, 13, 14)', [1, 5]) + self.assert_query( + source, '"dt" <= make_datetime(2020, 5, 4, 12, 13, 14)', [1, 5] + ) self.assert_query(source, '"dt" < make_date(2020, 5, 4)', [1]) - self.assert_query(source, '"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')', [5]) - - self.assert_query(source, '"date" <= make_datetime(2020, 5, 4, 12, 13, 14)', [1, 2, 5]) + self.assert_query( + source, + "\"dt\" = to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy')", + [5], + ) + + self.assert_query( + source, '"date" <= make_datetime(2020, 5, 4, 12, 13, 14)', [1, 2, 5] + ) self.assert_query(source, '"date" >= make_date(2020, 5, 4)', [2, 4]) if not self.treat_date_as_datetime(): - self.assert_query(source, - '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')', - [2]) + self.assert_query( + source, "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')", [2] + ) else: # TODO - we don't have any expression functions which can upgrade a date value to a datetime value! pass if not self.treat_time_as_string(): self.assert_query(source, '"time" >= make_time(12, 14, 14)', [2, 4]) - self.assert_query(source, '"time" = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')', [1]) + self.assert_query( + source, + "\"time\" = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')", + [1], + ) else: - self.assert_query(source, 'to_time("time") >= make_time(12, 14, 14)', [2, 4]) - self.assert_query(source, 'to_time("time") = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')', [1]) + self.assert_query( + source, 'to_time("time") >= make_time(12, 14, 14)', [2, 4] + ) + self.assert_query( + source, + "to_time(\"time\") = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')", + [1], + ) # TODO - enable, but needs fixing on Travis due to timezone handling issues # if self.treat_datetime_as_string(): @@ -372,94 +577,108 @@ def testGetFeaturesExp(self): self.runGetFeatureTests(self.source) def runOrderByTests(self): - request = QgsFeatureRequest().addOrderBy('cnt') - values = [f['cnt'] for f in self.source.getFeatures(request)] + request = QgsFeatureRequest().addOrderBy("cnt") + values = [f["cnt"] for f in self.source.getFeatures(request)] self.assertEqual(values, [-200, 100, 200, 300, 400]) - request = QgsFeatureRequest().addOrderBy('cnt', False) - values = [f['cnt'] for f in self.source.getFeatures(request)] + request = QgsFeatureRequest().addOrderBy("cnt", False) + values = [f["cnt"] for f in self.source.getFeatures(request)] self.assertEqual(values, [400, 300, 200, 100, -200]) - request = QgsFeatureRequest().addOrderBy('name') - values = [f['name'] for f in self.source.getFeatures(request)] - self.assertEqual(values, ['Apple', 'Honey', 'Orange', 'Pear', NULL]) + request = QgsFeatureRequest().addOrderBy("name") + values = [f["name"] for f in self.source.getFeatures(request)] + self.assertEqual(values, ["Apple", "Honey", "Orange", "Pear", NULL]) - request = QgsFeatureRequest().addOrderBy('name', True, True) - values = [f['name'] for f in self.source.getFeatures(request)] - self.assertEqual(values, [NULL, 'Apple', 'Honey', 'Orange', 'Pear']) + request = QgsFeatureRequest().addOrderBy("name", True, True) + values = [f["name"] for f in self.source.getFeatures(request)] + self.assertEqual(values, [NULL, "Apple", "Honey", "Orange", "Pear"]) - request = QgsFeatureRequest().addOrderBy('name', False) - values = [f['name'] for f in self.source.getFeatures(request)] - self.assertEqual(values, [NULL, 'Pear', 'Orange', 'Honey', 'Apple']) + request = QgsFeatureRequest().addOrderBy("name", False) + values = [f["name"] for f in self.source.getFeatures(request)] + self.assertEqual(values, [NULL, "Pear", "Orange", "Honey", "Apple"]) - request = QgsFeatureRequest().addOrderBy('name', False, False) - values = [f['name'] for f in self.source.getFeatures(request)] - self.assertEqual(values, ['Pear', 'Orange', 'Honey', 'Apple', NULL]) + request = QgsFeatureRequest().addOrderBy("name", False, False) + values = [f["name"] for f in self.source.getFeatures(request)] + self.assertEqual(values, ["Pear", "Orange", "Honey", "Apple", NULL]) - request = QgsFeatureRequest().addOrderBy('num_char', False) - values = [f['pk'] for f in self.source.getFeatures(request)] + request = QgsFeatureRequest().addOrderBy("num_char", False) + values = [f["pk"] for f in self.source.getFeatures(request)] self.assertEqual(values, [5, 4, 3, 2, 1]) - request = QgsFeatureRequest().addOrderBy('dt', False) - values = [f['pk'] for f in self.source.getFeatures(request)] + request = QgsFeatureRequest().addOrderBy("dt", False) + values = [f["pk"] for f in self.source.getFeatures(request)] self.assertEqual(values, [3, 4, 2, 5, 1]) - request = QgsFeatureRequest().addOrderBy('date', False) - values = [f['pk'] for f in self.source.getFeatures(request)] + request = QgsFeatureRequest().addOrderBy("date", False) + values = [f["pk"] for f in self.source.getFeatures(request)] self.assertEqual(values, [3, 4, 2, 1, 5]) - request = QgsFeatureRequest().addOrderBy('time', False) - values = [f['pk'] for f in self.source.getFeatures(request)] + request = QgsFeatureRequest().addOrderBy("time", False) + values = [f["pk"] for f in self.source.getFeatures(request)] self.assertEqual(values, [3, 4, 2, 1, 5]) # Case sensitivity - request = QgsFeatureRequest().addOrderBy('name2') - values = [f['name2'] for f in self.source.getFeatures(request)] - self.assertEqual(values, ['Apple', 'Honey', 'NuLl', 'oranGe', 'PEaR']) + request = QgsFeatureRequest().addOrderBy("name2") + values = [f["name2"] for f in self.source.getFeatures(request)] + self.assertEqual(values, ["Apple", "Honey", "NuLl", "oranGe", "PEaR"]) # Combination with LIMIT - request = QgsFeatureRequest().addOrderBy('pk', False).setLimit(2) - values = [f['pk'] for f in self.source.getFeatures(request)] + request = QgsFeatureRequest().addOrderBy("pk", False).setLimit(2) + values = [f["pk"] for f in self.source.getFeatures(request)] self.assertEqual(values, [5, 4]) # A slightly more complex expression - request = QgsFeatureRequest().addOrderBy('pk*2', False) - values = [f['pk'] for f in self.source.getFeatures(request)] + request = QgsFeatureRequest().addOrderBy("pk*2", False) + values = [f["pk"] for f in self.source.getFeatures(request)] self.assertEqual(values, [5, 4, 3, 2, 1]) # Order reversing expression - request = QgsFeatureRequest().addOrderBy('pk*-1', False) - values = [f['pk'] for f in self.source.getFeatures(request)] + request = QgsFeatureRequest().addOrderBy("pk*-1", False) + values = [f["pk"] for f in self.source.getFeatures(request)] self.assertEqual(values, [1, 2, 3, 4, 5]) # Type dependent expression - request = QgsFeatureRequest().addOrderBy('num_char*2', False) - values = [f['pk'] for f in self.source.getFeatures(request)] + request = QgsFeatureRequest().addOrderBy("num_char*2", False) + values = [f["pk"] for f in self.source.getFeatures(request)] self.assertEqual(values, [5, 4, 3, 2, 1]) # Order by guaranteed to fail - request = QgsFeatureRequest().addOrderBy('not a valid expression*', False) - values = [f['pk'] for f in self.source.getFeatures(request)] + request = QgsFeatureRequest().addOrderBy("not a valid expression*", False) + values = [f["pk"] for f in self.source.getFeatures(request)] self.assertEqual(set(values), {5, 4, 3, 2, 1}) # Multiple order bys and boolean - request = QgsFeatureRequest().addOrderBy('pk > 2').addOrderBy('pk', False) - values = [f['pk'] for f in self.source.getFeatures(request)] + request = QgsFeatureRequest().addOrderBy("pk > 2").addOrderBy("pk", False) + values = [f["pk"] for f in self.source.getFeatures(request)] self.assertEqual(values, [2, 1, 5, 4, 3]) # Multiple order bys, one bad, and a limit - request = QgsFeatureRequest().addOrderBy('pk', False).addOrderBy('not a valid expression*', False).setLimit(2) - values = [f['pk'] for f in self.source.getFeatures(request)] + request = ( + QgsFeatureRequest() + .addOrderBy("pk", False) + .addOrderBy("not a valid expression*", False) + .setLimit(2) + ) + values = [f["pk"] for f in self.source.getFeatures(request)] self.assertEqual(values, [5, 4]) # Bad expression first - request = QgsFeatureRequest().addOrderBy('not a valid expression*', False).addOrderBy('pk', False).setLimit(2) - values = [f['pk'] for f in self.source.getFeatures(request)] + request = ( + QgsFeatureRequest() + .addOrderBy("not a valid expression*", False) + .addOrderBy("pk", False) + .setLimit(2) + ) + values = [f["pk"] for f in self.source.getFeatures(request)] self.assertEqual(values, [5, 4]) # Combination with subset of attributes - request = QgsFeatureRequest().addOrderBy('num_char', False).setSubsetOfAttributes(['pk'], self.source.fields()) - values = [f['pk'] for f in self.source.getFeatures(request)] + request = ( + QgsFeatureRequest() + .addOrderBy("num_char", False) + .setSubsetOfAttributes(["pk"], self.source.fields()) + ) + values = [f["pk"] for f in self.source.getFeatures(request)] self.assertEqual(values, [5, 4, 3, 2, 1]) def testOrderBy(self): @@ -471,7 +690,7 @@ def testOpenIteratorAfterSourceRemoval(self): information should be captured in the iterator's source and there MUST be no links between the iterators and the sources's data source """ - if not getattr(self, 'getSource', None): + if not getattr(self, "getSource", None): return source = self.getSource() @@ -481,22 +700,27 @@ def testOpenIteratorAfterSourceRemoval(self): # get the features pks = [] for f in it: - pks.append(f['pk']) + pks.append(f["pk"]) self.assertEqual(set(pks), {1, 2, 3, 4, 5}) def testGetFeaturesFidTests(self): fids = [f.id() for f in self.source.getFeatures()] - assert len(fids) == 5, f'Expected 5 features, got {len(fids)} instead' + assert len(fids) == 5, f"Expected 5 features, got {len(fids)} instead" for id in fids: - features = [f for f in self.source.getFeatures(QgsFeatureRequest().setFilterFid(id))] + features = [ + f for f in self.source.getFeatures(QgsFeatureRequest().setFilterFid(id)) + ] self.assertEqual(len(features), 1) feature = features[0] self.assertTrue(feature.isValid()) result = [feature.id()] expected = [id] - assert result == expected, 'Expected {} and got {} when testing for feature ID filter'.format(expected, - result) + assert ( + result == expected + ), "Expected {} and got {} when testing for feature ID filter".format( + expected, result + ) # test that results match QgsFeatureRequest.acceptFeature request = QgsFeatureRequest().setFilterFid(id) @@ -521,9 +745,11 @@ def testGetFeaturesFidsTests(self): request = QgsFeatureRequest().setFilterFids([fids[0], fids[2]]) result = {f.id() for f in self.source.getFeatures(request)} - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) expected = {fids[0], fids[2]} - assert result == expected, f'Expected {expected} and got {result} when testing for feature IDs filter' + assert ( + result == expected + ), f"Expected {expected} and got {result} when testing for feature IDs filter" self.assertTrue(all_valid) # test that results match QgsFeatureRequest.acceptFeature @@ -531,19 +757,38 @@ def testGetFeaturesFidsTests(self): self.assertEqual(request.acceptFeature(f), f.id() in expected) result = { - f.id() for f in self.source.getFeatures(QgsFeatureRequest().setFilterFids([fids[1], fids[3], fids[4]]))} + f.id() + for f in self.source.getFeatures( + QgsFeatureRequest().setFilterFids([fids[1], fids[3], fids[4]]) + ) + } expected = {fids[1], fids[3], fids[4]} - assert result == expected, f'Expected {expected} and got {result} when testing for feature IDs filter' + assert ( + result == expected + ), f"Expected {expected} and got {result} when testing for feature IDs filter" # sources should ignore non-existent fids - result = {f.id() for f in self.source.getFeatures( - QgsFeatureRequest().setFilterFids([-101, fids[1], -102, fids[3], -103, fids[4], -104]))} + result = { + f.id() + for f in self.source.getFeatures( + QgsFeatureRequest().setFilterFids( + [-101, fids[1], -102, fids[3], -103, fids[4], -104] + ) + ) + } expected = {fids[1], fids[3], fids[4]} - assert result == expected, f'Expected {expected} and got {result} when testing for feature IDs filter' + assert ( + result == expected + ), f"Expected {expected} and got {result} when testing for feature IDs filter" - result = {f.id() for f in self.source.getFeatures(QgsFeatureRequest().setFilterFids([]))} + result = { + f.id() + for f in self.source.getFeatures(QgsFeatureRequest().setFilterFids([])) + } expected = set() - assert result == expected, f'Expected {expected} and got {result} when testing for feature IDs filter' + assert ( + result == expected + ), f"Expected {expected} and got {result} when testing for feature IDs filter" # Rewind mid-way request = QgsFeatureRequest().setFilterFids([fids[1], fids[3], fids[4]]) @@ -569,29 +814,29 @@ def testGetFeaturesFidsTests(self): def testGetFeaturesFilterRectTests(self): extent = QgsRectangle(-70, 67, -60, 80) request = QgsFeatureRequest().setFilterRect(extent) - features = [f['pk'] for f in self.source.getFeatures(request)] - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) - assert set(features) == {2, 4}, f'Got {features} instead' + features = [f["pk"] for f in self.source.getFeatures(request)] + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) + assert set(features) == {2, 4}, f"Got {features} instead" self.assertTrue(all_valid) # test that results match QgsFeatureRequest.acceptFeature for f in self.source.getFeatures(): - self.assertEqual(request.acceptFeature(f), f['pk'] in {2, 4}) + self.assertEqual(request.acceptFeature(f), f["pk"] in {2, 4}) # test with an empty rectangle extent = QgsRectangle() request = QgsFeatureRequest().setFilterRect(extent) - features = [f['pk'] for f in self.source.getFeatures(request)] - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) - assert set(features) == {1, 2, 3, 4, 5}, f'Got {features} instead' + features = [f["pk"] for f in self.source.getFeatures(request)] + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) + assert set(features) == {1, 2, 3, 4, 5}, f"Got {features} instead" self.assertTrue(all_valid) # ExactIntersection flag set, but no filter rect set. Should be ignored. request = QgsFeatureRequest() request.setFlags(QgsFeatureRequest.Flag.ExactIntersect) - features = [f['pk'] for f in self.source.getFeatures(request)] - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) - assert set(features) == {1, 2, 3, 4, 5}, f'Got {features} instead' + features = [f["pk"] for f in self.source.getFeatures(request)] + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) + assert set(features) == {1, 2, 3, 4, 5}, f"Got {features} instead" self.assertTrue(all_valid) def testGetFeaturesFilterRectTestsNoGeomFlag(self): @@ -604,165 +849,241 @@ def testGetFeaturesFilterRectTestsNoGeomFlag(self): request.setFilterRect(extent) request.setFlags(QgsFeatureRequest.Flag.NoGeometry) - features = [f['pk'] for f in self.source.getFeatures(request)] - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) - assert set(features) == {2, 4}, f'Got {features} instead' + features = [f["pk"] for f in self.source.getFeatures(request)] + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) + assert set(features) == {2, 4}, f"Got {features} instead" self.assertTrue(all_valid) # test that results match QgsFeatureRequest.acceptFeature for f in self.source.getFeatures(): - self.assertEqual(request.acceptFeature(f), f['pk'] in {2, 4}) + self.assertEqual(request.acceptFeature(f), f["pk"] in {2, 4}) # test with an empty rectangle extent = QgsRectangle() - request = QgsFeatureRequest().setFilterRect(extent).setFlags(QgsFeatureRequest.Flag.NoGeometry) - features = [f['pk'] for f in self.source.getFeatures(request)] - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) - assert set(features) == {1, 2, 3, 4, 5}, f'Got {features} instead' + request = ( + QgsFeatureRequest() + .setFilterRect(extent) + .setFlags(QgsFeatureRequest.Flag.NoGeometry) + ) + features = [f["pk"] for f in self.source.getFeatures(request)] + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) + assert set(features) == {1, 2, 3, 4, 5}, f"Got {features} instead" self.assertTrue(all_valid) # ExactIntersection flag set, but no filter rect set. Should be ignored. request = QgsFeatureRequest() - request.setFlags(QgsFeatureRequest.Flag.ExactIntersect | QgsFeatureRequest.Flag.NoGeometry) - features = [f['pk'] for f in self.source.getFeatures(request)] - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) - assert set(features) == {1, 2, 3, 4, 5}, f'Got {features} instead' + request.setFlags( + QgsFeatureRequest.Flag.ExactIntersect | QgsFeatureRequest.Flag.NoGeometry + ) + features = [f["pk"] for f in self.source.getFeatures(request)] + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) + assert set(features) == {1, 2, 3, 4, 5}, f"Got {features} instead" self.assertTrue(all_valid) def testRectAndExpression(self): extent = QgsRectangle(-70, 67, -60, 80) - request = QgsFeatureRequest().setFilterExpression('"cnt">200').setFilterRect(extent) - result = {f['pk'] for f in self.source.getFeatures(request)} - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) + request = ( + QgsFeatureRequest().setFilterExpression('"cnt">200').setFilterRect(extent) + ) + result = {f["pk"] for f in self.source.getFeatures(request)} + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) expected = [4] - assert set( - expected) == result, 'Expected {} and got {} when testing for combination of filterRect and expression'.format( - set(expected), result) + assert ( + set(expected) == result + ), "Expected {} and got {} when testing for combination of filterRect and expression".format( + set(expected), result + ) self.assertTrue(all_valid) # shouldn't matter what order this is done in - request = QgsFeatureRequest().setFilterRect(extent).setFilterExpression('"cnt">200') - result = {f['pk'] for f in self.source.getFeatures(request)} - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) + request = ( + QgsFeatureRequest().setFilterRect(extent).setFilterExpression('"cnt">200') + ) + result = {f["pk"] for f in self.source.getFeatures(request)} + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) expected = [4] - assert set( - expected) == result, 'Expected {} and got {} when testing for combination of filterRect and expression'.format( - set(expected), result) + assert ( + set(expected) == result + ), "Expected {} and got {} when testing for combination of filterRect and expression".format( + set(expected), result + ) self.assertTrue(all_valid) # test that results match QgsFeatureRequest.acceptFeature for f in self.source.getFeatures(): - self.assertEqual(request.acceptFeature(f), f['pk'] in expected) + self.assertEqual(request.acceptFeature(f), f["pk"] in expected) def testGetFeaturesDistanceWithinTests(self): - request = QgsFeatureRequest().setDistanceWithin(QgsGeometry.fromWkt('LineString (-63.2 69.9, -68.47 69.86, -69.74 79.28)'), 1.7) - features = [f['pk'] for f in self.source.getFeatures(request)] - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) - assert set(features) == {2, 5}, f'Got {features} instead' + request = QgsFeatureRequest().setDistanceWithin( + QgsGeometry.fromWkt("LineString (-63.2 69.9, -68.47 69.86, -69.74 79.28)"), + 1.7, + ) + features = [f["pk"] for f in self.source.getFeatures(request)] + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) + assert set(features) == {2, 5}, f"Got {features} instead" self.assertTrue(all_valid) # test that results match QgsFeatureRequest.acceptFeature for f in self.source.getFeatures(): - self.assertEqual(request.acceptFeature(f), f['pk'] in {2, 5}) + self.assertEqual(request.acceptFeature(f), f["pk"] in {2, 5}) - request = QgsFeatureRequest().setDistanceWithin(QgsGeometry.fromWkt('LineString (-63.2 69.9, -68.47 69.86, -69.74 79.28)'), 0.6) - features = [f['pk'] for f in self.source.getFeatures(request)] - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) - assert set(features) == {2}, f'Got {features} instead' + request = QgsFeatureRequest().setDistanceWithin( + QgsGeometry.fromWkt("LineString (-63.2 69.9, -68.47 69.86, -69.74 79.28)"), + 0.6, + ) + features = [f["pk"] for f in self.source.getFeatures(request)] + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) + assert set(features) == {2}, f"Got {features} instead" self.assertTrue(all_valid) # test that results match QgsFeatureRequest.acceptFeature for f in self.source.getFeatures(): - self.assertEqual(request.acceptFeature(f), f['pk'] in {2}) + self.assertEqual(request.acceptFeature(f), f["pk"] in {2}) # in different crs - request = QgsFeatureRequest().setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857'), QgsProject.instance().transformContext()).setDistanceWithin(QgsGeometry.fromWkt('LineString (-7035391 11036245, -7622045 11023301, -7763421 15092839)'), 250000) - features = [f['pk'] for f in self.source.getFeatures(request)] - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) + request = ( + QgsFeatureRequest() + .setDestinationCrs( + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsProject.instance().transformContext(), + ) + .setDistanceWithin( + QgsGeometry.fromWkt( + "LineString (-7035391 11036245, -7622045 11023301, -7763421 15092839)" + ), + 250000, + ) + ) + features = [f["pk"] for f in self.source.getFeatures(request)] + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) self.assertEqual(set(features), {2, 5}) self.assertTrue(all_valid) # using coordinate transform - request = QgsFeatureRequest().setCoordinateTransform( - QgsCoordinateTransform( - self.source.sourceCrs(), - QgsCoordinateReferenceSystem('EPSG:3857'), QgsProject.instance().transformContext() - )).setDistanceWithin(QgsGeometry.fromWkt('LineString (-7035391 11036245, -7622045 11023301, -7763421 15092839)'), 250000) - features = [f['pk'] for f in self.source.getFeatures(request)] - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) + request = ( + QgsFeatureRequest() + .setCoordinateTransform( + QgsCoordinateTransform( + self.source.sourceCrs(), + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsProject.instance().transformContext(), + ) + ) + .setDistanceWithin( + QgsGeometry.fromWkt( + "LineString (-7035391 11036245, -7622045 11023301, -7763421 15092839)" + ), + 250000, + ) + ) + features = [f["pk"] for f in self.source.getFeatures(request)] + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) self.assertEqual(set(features), {2, 5}) self.assertTrue(all_valid) # point geometry request = QgsFeatureRequest().setDistanceWithin( - QgsGeometry.fromWkt('Point (-68.1 78.1)'), 3.6) - features = [f['pk'] for f in self.source.getFeatures(request)] - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) - assert set(features) == {4, 5}, f'Got {features} instead' + QgsGeometry.fromWkt("Point (-68.1 78.1)"), 3.6 + ) + features = [f["pk"] for f in self.source.getFeatures(request)] + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) + assert set(features) == {4, 5}, f"Got {features} instead" self.assertTrue(all_valid) # test that results match QgsFeatureRequest.acceptFeature for f in self.source.getFeatures(): - self.assertEqual(request.acceptFeature(f), f['pk'] in {4, 5}) + self.assertEqual(request.acceptFeature(f), f["pk"] in {4, 5}) request = QgsFeatureRequest().setDistanceWithin( - QgsGeometry.fromWkt('Polygon ((-64.47 79.59, -64.37 73.59, -72.69 73.61, -72.73 68.07, -62.51 68.01, -62.71 79.55, -64.47 79.59))'), 0) - features = [f['pk'] for f in self.source.getFeatures(request)] - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) - assert set(features) == {2}, f'Got {features} instead' + QgsGeometry.fromWkt( + "Polygon ((-64.47 79.59, -64.37 73.59, -72.69 73.61, -72.73 68.07, -62.51 68.01, -62.71 79.55, -64.47 79.59))" + ), + 0, + ) + features = [f["pk"] for f in self.source.getFeatures(request)] + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) + assert set(features) == {2}, f"Got {features} instead" self.assertTrue(all_valid) # test that results match QgsFeatureRequest.acceptFeature for f in self.source.getFeatures(): - self.assertEqual(request.acceptFeature(f), f['pk'] in {2}) + self.assertEqual(request.acceptFeature(f), f["pk"] in {2}) request = QgsFeatureRequest().setDistanceWithin( - QgsGeometry.fromWkt('Polygon ((-64.47 79.59, -64.37 73.59, -72.69 73.61, -72.73 68.07, -62.51 68.01, -62.71 79.55, -64.47 79.59))'), 1.3) - features = [f['pk'] for f in self.source.getFeatures(request)] - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) - assert set(features) == {2, 4}, f'Got {features} instead' + QgsGeometry.fromWkt( + "Polygon ((-64.47 79.59, -64.37 73.59, -72.69 73.61, -72.73 68.07, -62.51 68.01, -62.71 79.55, -64.47 79.59))" + ), + 1.3, + ) + features = [f["pk"] for f in self.source.getFeatures(request)] + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) + assert set(features) == {2, 4}, f"Got {features} instead" self.assertTrue(all_valid) # test that results match QgsFeatureRequest.acceptFeature for f in self.source.getFeatures(): - self.assertEqual(request.acceptFeature(f), f['pk'] in {2, 4}) + self.assertEqual(request.acceptFeature(f), f["pk"] in {2, 4}) request = QgsFeatureRequest().setDistanceWithin( - QgsGeometry.fromWkt('Polygon ((-64.47 79.59, -64.37 73.59, -72.69 73.61, -72.73 68.07, -62.51 68.01, -62.71 79.55, -64.47 79.59))'), 2.3) - features = [f['pk'] for f in self.source.getFeatures(request)] - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) - assert set(features) == {1, 2, 4}, f'Got {features} instead' + QgsGeometry.fromWkt( + "Polygon ((-64.47 79.59, -64.37 73.59, -72.69 73.61, -72.73 68.07, -62.51 68.01, -62.71 79.55, -64.47 79.59))" + ), + 2.3, + ) + features = [f["pk"] for f in self.source.getFeatures(request)] + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) + assert set(features) == {1, 2, 4}, f"Got {features} instead" self.assertTrue(all_valid) # test that results match QgsFeatureRequest.acceptFeature for f in self.source.getFeatures(): - self.assertEqual(request.acceptFeature(f), f['pk'] in {1, 2, 4}) + self.assertEqual(request.acceptFeature(f), f["pk"] in {1, 2, 4}) # test with linestring whose bounding box overlaps all query # points but being only within one of them, which we hope will # be returned NOT as the first one. # This is a test for https://github.com/qgis/QGIS/issues/45352 request = QgsFeatureRequest().setDistanceWithin( - QgsGeometry.fromWkt('LINESTRING(-100 80, -100 66, -30 66, -30 80)'), 0.5) - features = {f['pk'] for f in self.source.getFeatures(request)} - self.assertEqual(features, {1}, "Unexpected return from QgsFeatureRequest with DistanceWithin filter") + QgsGeometry.fromWkt("LINESTRING(-100 80, -100 66, -30 66, -30 80)"), 0.5 + ) + features = {f["pk"] for f in self.source.getFeatures(request)} + self.assertEqual( + features, + {1}, + "Unexpected return from QgsFeatureRequest with DistanceWithin filter", + ) def testGeomAndAllAttributes(self): """ Test combination of a filter which requires geometry and all attributes """ - request = QgsFeatureRequest().setFilterExpression( - 'attribute($currentfeature,\'cnt\')>200 and $x>=-70 and $x<=-60').setSubsetOfAttributes([]).setFlags( - QgsFeatureRequest.Flag.NoGeometry | QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation) - result = {f['pk'] for f in self.source.getFeatures(request)} - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) + request = ( + QgsFeatureRequest() + .setFilterExpression( + "attribute($currentfeature,'cnt')>200 and $x>=-70 and $x<=-60" + ) + .setSubsetOfAttributes([]) + .setFlags( + QgsFeatureRequest.Flag.NoGeometry + | QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation + ) + ) + result = {f["pk"] for f in self.source.getFeatures(request)} + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) self.assertEqual(result, {4}) self.assertTrue(all_valid) - request = QgsFeatureRequest().setFilterExpression( - 'attribute($currentfeature,\'cnt\')>200 and $x>=-70 and $x<=-60').setFlags(QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation) - result = {f['pk'] for f in self.source.getFeatures(request)} - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) + request = ( + QgsFeatureRequest() + .setFilterExpression( + "attribute($currentfeature,'cnt')>200 and $x>=-70 and $x<=-60" + ) + .setFlags( + QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation + ) + ) + result = {f["pk"] for f in self.source.getFeatures(request)} + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) self.assertEqual(result, {4}) self.assertTrue(all_valid) @@ -772,36 +1093,46 @@ def testRectAndFids(self): """ # first get feature ids - ids = {f['pk']: f.id() for f in self.source.getFeatures()} + ids = {f["pk"]: f.id() for f in self.source.getFeatures()} extent = QgsRectangle(-70, 67, -60, 80) - request = QgsFeatureRequest().setFilterFids([ids[3], ids[4]]).setFilterRect(extent) - result = {f['pk'] for f in self.source.getFeatures(request)} - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) + request = ( + QgsFeatureRequest().setFilterFids([ids[3], ids[4]]).setFilterRect(extent) + ) + result = {f["pk"] for f in self.source.getFeatures(request)} + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) expected = [4] - assert set( - expected) == result, 'Expected {} and got {} when testing for combination of filterRect and expression'.format( - set(expected), result) + assert ( + set(expected) == result + ), "Expected {} and got {} when testing for combination of filterRect and expression".format( + set(expected), result + ) self.assertTrue(all_valid) # shouldn't matter what order this is done in - request = QgsFeatureRequest().setFilterRect(extent).setFilterFids([ids[3], ids[4]]) - result = {f['pk'] for f in self.source.getFeatures(request)} - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) + request = ( + QgsFeatureRequest().setFilterRect(extent).setFilterFids([ids[3], ids[4]]) + ) + result = {f["pk"] for f in self.source.getFeatures(request)} + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) expected = [4] - assert set( - expected) == result, 'Expected {} and got {} when testing for combination of filterRect and expression'.format( - set(expected), result) + assert ( + set(expected) == result + ), "Expected {} and got {} when testing for combination of filterRect and expression".format( + set(expected), result + ) self.assertTrue(all_valid) # test that results match QgsFeatureRequest.acceptFeature for f in self.source.getFeatures(): - self.assertEqual(request.acceptFeature(f), f['pk'] in expected) + self.assertEqual(request.acceptFeature(f), f["pk"] in expected) def testGetFeaturesDestinationCrs(self): - request = QgsFeatureRequest().setDestinationCrs(QgsCoordinateReferenceSystem('epsg:3857'), - QgsProject.instance().transformContext()) - features = {f['pk']: f for f in self.source.getFeatures(request)} + request = QgsFeatureRequest().setDestinationCrs( + QgsCoordinateReferenceSystem("epsg:3857"), + QgsProject.instance().transformContext(), + ) + features = {f["pk"]: f for f in self.source.getFeatures(request)} # test that features have been reprojected self.assertAlmostEqual(features[1].geometry().constGet().x(), -7829322, -5) self.assertAlmostEqual(features[1].geometry().constGet().y(), 9967753, -5) @@ -815,9 +1146,15 @@ def testGetFeaturesDestinationCrs(self): # when destination crs is set, filter rect should be in destination crs rect = QgsRectangle(-7650000, 10500000, -7200000, 15000000) - request = QgsFeatureRequest().setDestinationCrs(QgsCoordinateReferenceSystem('epsg:3857'), - QgsProject.instance().transformContext()).setFilterRect(rect) - features = {f['pk']: f for f in self.source.getFeatures(request)} + request = ( + QgsFeatureRequest() + .setDestinationCrs( + QgsCoordinateReferenceSystem("epsg:3857"), + QgsProject.instance().transformContext(), + ) + .setFilterRect(rect) + ) + features = {f["pk"]: f for f in self.source.getFeatures(request)} self.assertEqual(set(features.keys()), {2, 4}) # test that features have been reprojected self.assertAlmostEqual(features[2].geometry().constGet().x(), -7591989, -5) @@ -827,8 +1164,14 @@ def testGetFeaturesDestinationCrs(self): # bad rect for transform rect = QgsRectangle(-99999999999, 99999999999, -99999999998, 99999999998) - request = QgsFeatureRequest().setDestinationCrs(QgsCoordinateReferenceSystem('epsg:28356'), - QgsProject.instance().transformContext()).setFilterRect(rect) + request = ( + QgsFeatureRequest() + .setDestinationCrs( + QgsCoordinateReferenceSystem("epsg:28356"), + QgsProject.instance().transformContext(), + ) + .setFilterRect(rect) + ) features = [f for f in self.source.getFeatures(request)] self.assertFalse(features) @@ -836,10 +1179,11 @@ def testGetFeaturesCoordinateTransform(self): request = QgsFeatureRequest().setCoordinateTransform( QgsCoordinateTransform( self.source.sourceCrs(), - QgsCoordinateReferenceSystem('epsg:3857'), - QgsProject.instance().transformContext()) + QgsCoordinateReferenceSystem("epsg:3857"), + QgsProject.instance().transformContext(), + ) ) - features = {f['pk']: f for f in self.source.getFeatures(request)} + features = {f["pk"]: f for f in self.source.getFeatures(request)} # test that features have been reprojected self.assertAlmostEqual(features[1].geometry().constGet().x(), -7829322, -5) self.assertAlmostEqual(features[1].geometry().constGet().y(), 9967753, -5) @@ -853,13 +1197,18 @@ def testGetFeaturesCoordinateTransform(self): # when destination crs is set, filter rect should be in destination crs rect = QgsRectangle(-7650000, 10500000, -7200000, 15000000) - request = QgsFeatureRequest().setCoordinateTransform( - QgsCoordinateTransform( - self.source.sourceCrs(), - QgsCoordinateReferenceSystem('epsg:3857'), - QgsProject.instance().transformContext()) - ).setFilterRect(rect) - features = {f['pk']: f for f in self.source.getFeatures(request)} + request = ( + QgsFeatureRequest() + .setCoordinateTransform( + QgsCoordinateTransform( + self.source.sourceCrs(), + QgsCoordinateReferenceSystem("epsg:3857"), + QgsProject.instance().transformContext(), + ) + ) + .setFilterRect(rect) + ) + features = {f["pk"]: f for f in self.source.getFeatures(request)} self.assertEqual(set(features.keys()), {2, 4}) # test that features have been reprojected self.assertAlmostEqual(features[2].geometry().constGet().x(), -7591989, -5) @@ -869,218 +1218,466 @@ def testGetFeaturesCoordinateTransform(self): # bad rect for transform rect = QgsRectangle(-99999999999, 99999999999, -99999999998, 99999999998) - request = QgsFeatureRequest().setCoordinateTransform( - QgsCoordinateTransform( - self.source.sourceCrs(), - QgsCoordinateReferenceSystem('epsg:28356'), - QgsProject.instance().transformContext()) - ).setFilterRect(rect) + request = ( + QgsFeatureRequest() + .setCoordinateTransform( + QgsCoordinateTransform( + self.source.sourceCrs(), + QgsCoordinateReferenceSystem("epsg:28356"), + QgsProject.instance().transformContext(), + ) + ) + .setFilterRect(rect) + ) features = [f for f in self.source.getFeatures(request)] self.assertFalse(features) def testGetFeaturesLimit(self): it = self.source.getFeatures(QgsFeatureRequest().setLimit(2)) - features = [f['pk'] for f in it] - assert len(features) == 2, f'Expected two features, got {len(features)} instead' + features = [f["pk"] for f in it] + assert len(features) == 2, f"Expected two features, got {len(features)} instead" # fetch one feature feature = QgsFeature() - assert not it.nextFeature(feature), 'Expected no feature after limit, got one' + assert not it.nextFeature(feature), "Expected no feature after limit, got one" it.rewind() - features = [f['pk'] for f in it] - assert len(features) == 2, f'Expected two features after rewind, got {len(features)} instead' + features = [f["pk"] for f in it] + assert ( + len(features) == 2 + ), f"Expected two features after rewind, got {len(features)} instead" it.rewind() - assert it.nextFeature(feature), 'Expected feature after rewind, got none' + assert it.nextFeature(feature), "Expected feature after rewind, got none" it.rewind() - features = [f['pk'] for f in it] - assert len(features) == 2, f'Expected two features after rewind, got {len(features)} instead' + features = [f["pk"] for f in it] + assert ( + len(features) == 2 + ), f"Expected two features after rewind, got {len(features)} instead" # test with expression, both with and without compilation try: self.disableCompiler() except AttributeError: pass - it = self.source.getFeatures(QgsFeatureRequest().setLimit(2).setFilterExpression('cnt <= 100')) - features = [f['pk'] for f in it] - assert set(features) == {1, 5}, 'Expected [1,5] for expression and feature limit, Got {} instead'.format( - features) + it = self.source.getFeatures( + QgsFeatureRequest().setLimit(2).setFilterExpression("cnt <= 100") + ) + features = [f["pk"] for f in it] + assert set(features) == { + 1, + 5, + }, "Expected [1,5] for expression and feature limit, Got {} instead".format( + features + ) try: self.enableCompiler() except AttributeError: pass - it = self.source.getFeatures(QgsFeatureRequest().setLimit(2).setFilterExpression('cnt <= 100')) - features = [f['pk'] for f in it] - assert set(features) == {1, 5}, 'Expected [1,5] for expression and feature limit, Got {} instead'.format( - features) + it = self.source.getFeatures( + QgsFeatureRequest().setLimit(2).setFilterExpression("cnt <= 100") + ) + features = [f["pk"] for f in it] + assert set(features) == { + 1, + 5, + }, "Expected [1,5] for expression and feature limit, Got {} instead".format( + features + ) # limit to more features than exist - it = self.source.getFeatures(QgsFeatureRequest().setLimit(3).setFilterExpression('cnt <= 100')) - features = [f['pk'] for f in it] - assert set(features) == {1, 5}, 'Expected [1,5] for expression and feature limit, Got {} instead'.format( - features) + it = self.source.getFeatures( + QgsFeatureRequest().setLimit(3).setFilterExpression("cnt <= 100") + ) + features = [f["pk"] for f in it] + assert set(features) == { + 1, + 5, + }, "Expected [1,5] for expression and feature limit, Got {} instead".format( + features + ) # limit to less features than possible - it = self.source.getFeatures(QgsFeatureRequest().setLimit(1).setFilterExpression('cnt <= 100')) - features = [f['pk'] for f in it] - assert 1 in features or 5 in features, 'Expected either 1 or 5 for expression and feature limit, Got {} instead'.format( - features) + it = self.source.getFeatures( + QgsFeatureRequest().setLimit(1).setFilterExpression("cnt <= 100") + ) + features = [f["pk"] for f in it] + assert ( + 1 in features or 5 in features + ), "Expected either 1 or 5 for expression and feature limit, Got {} instead".format( + features + ) def testClosedIterators(self): - """ Test behavior of closed iterators """ + """Test behavior of closed iterators""" # Test retrieving feature after closing iterator f_it = self.source.getFeatures(QgsFeatureRequest()) fet = QgsFeature() - assert f_it.nextFeature(fet), 'Could not fetch feature' - assert fet.isValid(), 'Feature is not valid' - assert f_it.close(), 'Could not close iterator' - self.assertFalse(f_it.nextFeature(fet), - 'Fetched feature after iterator closed, expected nextFeature() to return False') - self.assertFalse(fet.isValid(), 'Valid feature fetched from closed iterator, should be invalid') + assert f_it.nextFeature(fet), "Could not fetch feature" + assert fet.isValid(), "Feature is not valid" + assert f_it.close(), "Could not close iterator" + self.assertFalse( + f_it.nextFeature(fet), + "Fetched feature after iterator closed, expected nextFeature() to return False", + ) + self.assertFalse( + fet.isValid(), + "Valid feature fetched from closed iterator, should be invalid", + ) # Test rewinding closed iterator - self.assertFalse(f_it.rewind(), 'Rewinding closed iterator successful, should not be allowed') + self.assertFalse( + f_it.rewind(), "Rewinding closed iterator successful, should not be allowed" + ) def testGetFeaturesSubsetAttributes(self): - """ Test that expected results are returned when using subsets of attributes """ - - tz = Qt.TimeSpec.UTC if self.treat_datetime_tz_as_utc() else Qt.TimeSpec.LocalTime - tests = {'pk': {1, 2, 3, 4, 5}, - 'cnt': {-200, 300, 100, 200, 400}, - 'name': {'Pear', 'Orange', 'Apple', 'Honey', NULL}, - 'name2': {'NuLl', 'PEaR', 'oranGe', 'Apple', 'Honey'}, - 'dt': {NULL, '2021-05-04 13:13:14' if self.treat_datetime_as_string() else QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14, 0), tz) if not self.treat_datetime_as_string() else '2021-05-04 13:13:14', - '2020-05-04 12:14:14' if self.treat_datetime_as_string() else QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14, 0), tz) if not self.treat_datetime_as_string() else '2020-05-04 12:14:14', - '2020-05-04 12:13:14' if self.treat_datetime_as_string() else QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14, 0), tz) if not self.treat_datetime_as_string() else '2020-05-04 12:13:14', - '2020-05-03 12:13:14' if self.treat_datetime_as_string() else QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14, 0), tz) if not self.treat_datetime_as_string() else '2020-05-03 12:13:14'}, - 'date': {NULL, - '2020-05-02' if self.treat_date_as_string() else QDate(2020, 5, 2) if not self.treat_date_as_datetime() else QDateTime(2020, 5, 2, 0, 0, 0), - '2020-05-03' if self.treat_date_as_string() else QDate(2020, 5, 3) if not self.treat_date_as_datetime() else QDateTime(2020, 5, 3, 0, 0, 0), - '2020-05-04' if self.treat_date_as_string() else QDate(2020, 5, 4) if not self.treat_date_as_datetime() else QDateTime(2020, 5, 4, 0, 0, 0), - '2021-05-04' if self.treat_date_as_string() else QDate(2021, 5, 4) if not self.treat_date_as_datetime() else QDateTime(2021, 5, 4, 0, 0, 0)}, - 'time': {QTime(12, 13, 1) if not self.treat_time_as_string() else '12:13:01', - QTime(12, 14, 14) if not self.treat_time_as_string() else '12:14:14', - QTime(12, 13, 14) if not self.treat_time_as_string() else '12:13:14', - QTime(13, 13, 14) if not self.treat_time_as_string() else '13:13:14', NULL}} + """Test that expected results are returned when using subsets of attributes""" + + tz = ( + Qt.TimeSpec.UTC + if self.treat_datetime_tz_as_utc() + else Qt.TimeSpec.LocalTime + ) + tests = { + "pk": {1, 2, 3, 4, 5}, + "cnt": {-200, 300, 100, 200, 400}, + "name": {"Pear", "Orange", "Apple", "Honey", NULL}, + "name2": {"NuLl", "PEaR", "oranGe", "Apple", "Honey"}, + "dt": { + NULL, + ( + "2021-05-04 13:13:14" + if self.treat_datetime_as_string() + else ( + QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14, 0), tz) + if not self.treat_datetime_as_string() + else "2021-05-04 13:13:14" + ) + ), + ( + "2020-05-04 12:14:14" + if self.treat_datetime_as_string() + else ( + QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14, 0), tz) + if not self.treat_datetime_as_string() + else "2020-05-04 12:14:14" + ) + ), + ( + "2020-05-04 12:13:14" + if self.treat_datetime_as_string() + else ( + QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14, 0), tz) + if not self.treat_datetime_as_string() + else "2020-05-04 12:13:14" + ) + ), + ( + "2020-05-03 12:13:14" + if self.treat_datetime_as_string() + else ( + QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14, 0), tz) + if not self.treat_datetime_as_string() + else "2020-05-03 12:13:14" + ) + ), + }, + "date": { + NULL, + ( + "2020-05-02" + if self.treat_date_as_string() + else ( + QDate(2020, 5, 2) + if not self.treat_date_as_datetime() + else QDateTime(2020, 5, 2, 0, 0, 0) + ) + ), + ( + "2020-05-03" + if self.treat_date_as_string() + else ( + QDate(2020, 5, 3) + if not self.treat_date_as_datetime() + else QDateTime(2020, 5, 3, 0, 0, 0) + ) + ), + ( + "2020-05-04" + if self.treat_date_as_string() + else ( + QDate(2020, 5, 4) + if not self.treat_date_as_datetime() + else QDateTime(2020, 5, 4, 0, 0, 0) + ) + ), + ( + "2021-05-04" + if self.treat_date_as_string() + else ( + QDate(2021, 5, 4) + if not self.treat_date_as_datetime() + else QDateTime(2021, 5, 4, 0, 0, 0) + ) + ), + }, + "time": { + QTime(12, 13, 1) if not self.treat_time_as_string() else "12:13:01", + QTime(12, 14, 14) if not self.treat_time_as_string() else "12:14:14", + QTime(12, 13, 14) if not self.treat_time_as_string() else "12:13:14", + QTime(13, 13, 14) if not self.treat_time_as_string() else "13:13:14", + NULL, + }, + } for field, expected in list(tests.items()): - request = QgsFeatureRequest().setSubsetOfAttributes([field], self.source.fields()) + request = QgsFeatureRequest().setSubsetOfAttributes( + [field], self.source.fields() + ) result = {f[field] for f in self.source.getFeatures(request)} - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) - self.assertEqual(result, expected, f'Expected {expected}, got {result}') + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) + self.assertEqual(result, expected, f"Expected {expected}, got {result}") self.assertTrue(all_valid) def testGetFeaturesSubsetAttributes2(self): - """ Test that other fields are NULL when fetching subsets of attributes """ + """Test that other fields are NULL when fetching subsets of attributes""" - for field_to_fetch in ['pk', 'cnt', 'name', 'name2', 'dt', 'date', 'time']: + for field_to_fetch in ["pk", "cnt", "name", "name2", "dt", "date", "time"]: for f in self.source.getFeatures( - QgsFeatureRequest().setSubsetOfAttributes([field_to_fetch], self.source.fields())): + QgsFeatureRequest().setSubsetOfAttributes( + [field_to_fetch], self.source.fields() + ) + ): # Check that all other fields are NULL and force name to lower-case - for other_field in [field.name() for field in self.source.fields() if - field.name().lower() != field_to_fetch]: - if other_field == 'pk' or other_field == 'PK': + for other_field in [ + field.name() + for field in self.source.fields() + if field.name().lower() != field_to_fetch + ]: + if other_field == "pk" or other_field == "PK": # skip checking the primary key field, as it may be validly fetched by providers to use as feature id continue - self.assertEqual(f[other_field], NULL, - 'Value for field "{}" was present when it should not have been fetched by request'.format( - other_field)) + self.assertEqual( + f[other_field], + NULL, + 'Value for field "{}" was present when it should not have been fetched by request'.format( + other_field + ), + ) def testGetFeaturesNoGeometry(self): - """ Test that no geometry is present when fetching features without geometry""" + """Test that no geometry is present when fetching features without geometry""" - for f in self.source.getFeatures(QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry)): - self.assertFalse(f.hasGeometry(), 'Expected no geometry, got one') + for f in self.source.getFeatures( + QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry) + ): + self.assertFalse(f.hasGeometry(), "Expected no geometry, got one") self.assertTrue(f.isValid()) def testGetFeaturesWithGeometry(self): - """ Test that geometry is present when fetching features without setting NoGeometry flag""" + """Test that geometry is present when fetching features without setting NoGeometry flag""" for f in self.source.getFeatures(QgsFeatureRequest()): - if f['pk'] == 3: + if f["pk"] == 3: # no geometry for this feature continue - assert f.hasGeometry(), 'Expected geometry, got none' + assert f.hasGeometry(), "Expected geometry, got none" self.assertTrue(f.isValid()) def testUniqueValues(self): - self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('cnt'))), - {-200, 100, 200, 300, 400}) - assert {'Apple', 'Honey', 'Orange', 'Pear', NULL} == set( - self.source.uniqueValues(self.source.fields().lookupField('name'))), 'Got {}'.format( - set(self.source.uniqueValues(self.source.fields().lookupField('name')))) + self.assertEqual( + set(self.source.uniqueValues(self.source.fields().lookupField("cnt"))), + {-200, 100, 200, 300, 400}, + ) + assert {"Apple", "Honey", "Orange", "Pear", NULL} == set( + self.source.uniqueValues(self.source.fields().lookupField("name")) + ), "Got {}".format( + set(self.source.uniqueValues(self.source.fields().lookupField("name"))) + ) if self.treat_datetime_as_string(): - self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('dt'))), - {'2021-05-04 13:13:14', '2020-05-04 12:14:14', '2020-05-04 12:13:14', '2020-05-03 12:13:14', NULL}) + self.assertEqual( + set(self.source.uniqueValues(self.source.fields().lookupField("dt"))), + { + "2021-05-04 13:13:14", + "2020-05-04 12:14:14", + "2020-05-04 12:13:14", + "2020-05-03 12:13:14", + NULL, + }, + ) else: if self.treat_datetime_tz_as_utc(): - self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('dt'))), - {QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14, 0), Qt.TimeSpec.UTC), QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14, 0), Qt.TimeSpec.UTC), - QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14, 0), Qt.TimeSpec.UTC), QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14, 0), Qt.TimeSpec.UTC), NULL}) + self.assertEqual( + set( + self.source.uniqueValues(self.source.fields().lookupField("dt")) + ), + { + QDateTime( + QDate(2021, 5, 4), QTime(13, 13, 14, 0), Qt.TimeSpec.UTC + ), + QDateTime( + QDate(2020, 5, 4), QTime(12, 14, 14, 0), Qt.TimeSpec.UTC + ), + QDateTime( + QDate(2020, 5, 4), QTime(12, 13, 14, 0), Qt.TimeSpec.UTC + ), + QDateTime( + QDate(2020, 5, 3), QTime(12, 13, 14, 0), Qt.TimeSpec.UTC + ), + NULL, + }, + ) else: - self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('dt'))), - {QDateTime(2021, 5, 4, 13, 13, 14), QDateTime(2020, 5, 4, 12, 14, 14), QDateTime(2020, 5, 4, 12, 13, 14), QDateTime(2020, 5, 3, 12, 13, 14), NULL}) + self.assertEqual( + set( + self.source.uniqueValues(self.source.fields().lookupField("dt")) + ), + { + QDateTime(2021, 5, 4, 13, 13, 14), + QDateTime(2020, 5, 4, 12, 14, 14), + QDateTime(2020, 5, 4, 12, 13, 14), + QDateTime(2020, 5, 3, 12, 13, 14), + NULL, + }, + ) if self.treat_date_as_string(): - self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('date'))), - {'2020-05-03', '2020-05-04', '2021-05-04', '2020-05-02', NULL}) + self.assertEqual( + set(self.source.uniqueValues(self.source.fields().lookupField("date"))), + {"2020-05-03", "2020-05-04", "2021-05-04", "2020-05-02", NULL}, + ) elif self.treat_date_as_datetime(): - self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('date'))), - {QDateTime(2020, 5, 3, 0, 0, 0), QDateTime(2020, 5, 4, 0, 0, 0), QDateTime(2021, 5, 4, 0, 0, 0), QDateTime(2020, 5, 2, 0, 0, 0), NULL}) + self.assertEqual( + set(self.source.uniqueValues(self.source.fields().lookupField("date"))), + { + QDateTime(2020, 5, 3, 0, 0, 0), + QDateTime(2020, 5, 4, 0, 0, 0), + QDateTime(2021, 5, 4, 0, 0, 0), + QDateTime(2020, 5, 2, 0, 0, 0), + NULL, + }, + ) else: - self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('date'))), - {QDate(2020, 5, 3), QDate(2020, 5, 4), QDate(2021, 5, 4), QDate(2020, 5, 2), NULL}) + self.assertEqual( + set(self.source.uniqueValues(self.source.fields().lookupField("date"))), + { + QDate(2020, 5, 3), + QDate(2020, 5, 4), + QDate(2021, 5, 4), + QDate(2020, 5, 2), + NULL, + }, + ) if self.treat_time_as_string(): - self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('time'))), - {'12:14:14', '13:13:14', '12:13:14', '12:13:01', NULL}) + self.assertEqual( + set(self.source.uniqueValues(self.source.fields().lookupField("time"))), + {"12:14:14", "13:13:14", "12:13:14", "12:13:01", NULL}, + ) else: - self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('time'))), - {QTime(12, 14, 14), QTime(13, 13, 14), QTime(12, 13, 14), QTime(12, 13, 1), NULL}) + self.assertEqual( + set(self.source.uniqueValues(self.source.fields().lookupField("time"))), + { + QTime(12, 14, 14), + QTime(13, 13, 14), + QTime(12, 13, 14), + QTime(12, 13, 1), + NULL, + }, + ) def testMinimumValue(self): - self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('cnt')), -200) - self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('name')), 'Apple') + self.assertEqual( + self.source.minimumValue(self.source.fields().lookupField("cnt")), -200 + ) + self.assertEqual( + self.source.minimumValue(self.source.fields().lookupField("name")), "Apple" + ) if self.treat_datetime_as_string(): - self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('dt')), '2020-05-03 12:13:14') + self.assertEqual( + self.source.minimumValue(self.source.fields().lookupField("dt")), + "2020-05-03 12:13:14", + ) else: - self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('dt')), QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14))) + self.assertEqual( + self.source.minimumValue(self.source.fields().lookupField("dt")), + QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), + ) if self.treat_date_as_string(): - self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('date')), '2020-05-02') + self.assertEqual( + self.source.minimumValue(self.source.fields().lookupField("date")), + "2020-05-02", + ) elif not self.treat_date_as_datetime(): - self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('date')), QDate(2020, 5, 2)) + self.assertEqual( + self.source.minimumValue(self.source.fields().lookupField("date")), + QDate(2020, 5, 2), + ) else: - self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('date')), QDateTime(2020, 5, 2, 0, 0, 0)) + self.assertEqual( + self.source.minimumValue(self.source.fields().lookupField("date")), + QDateTime(2020, 5, 2, 0, 0, 0), + ) if not self.treat_time_as_string(): - self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('time')), QTime(12, 13, 1)) + self.assertEqual( + self.source.minimumValue(self.source.fields().lookupField("time")), + QTime(12, 13, 1), + ) else: - self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('time')), '12:13:01') + self.assertEqual( + self.source.minimumValue(self.source.fields().lookupField("time")), + "12:13:01", + ) def testMaximumValue(self): - self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('cnt')), 400) - self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('name')), 'Pear') + self.assertEqual( + self.source.maximumValue(self.source.fields().lookupField("cnt")), 400 + ) + self.assertEqual( + self.source.maximumValue(self.source.fields().lookupField("name")), "Pear" + ) if not self.treat_datetime_as_string(): - self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('dt')), QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14))) + self.assertEqual( + self.source.maximumValue(self.source.fields().lookupField("dt")), + QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), + ) else: - self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('dt')), '2021-05-04 13:13:14') + self.assertEqual( + self.source.maximumValue(self.source.fields().lookupField("dt")), + "2021-05-04 13:13:14", + ) if self.treat_date_as_string(): - self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('date')), '2021-05-04') + self.assertEqual( + self.source.maximumValue(self.source.fields().lookupField("date")), + "2021-05-04", + ) elif not self.treat_date_as_datetime(): - self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('date')), QDate(2021, 5, 4)) + self.assertEqual( + self.source.maximumValue(self.source.fields().lookupField("date")), + QDate(2021, 5, 4), + ) else: - self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('date')), QDateTime(2021, 5, 4, 0, 0, 0)) + self.assertEqual( + self.source.maximumValue(self.source.fields().lookupField("date")), + QDateTime(2021, 5, 4, 0, 0, 0), + ) if not self.treat_time_as_string(): - self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('time')), QTime(13, 13, 14)) + self.assertEqual( + self.source.maximumValue(self.source.fields().lookupField("time")), + QTime(13, 13, 14), + ) else: - self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('time')), '13:13:14') + self.assertEqual( + self.source.maximumValue(self.source.fields().lookupField("time")), + "13:13:14", + ) def testAllFeatureIds(self): ids = {f.id() for f in self.source.getFeatures()} self.assertEqual(set(self.source.allFeatureIds()), ids) def testSubsetOfAttributesWithFilterExprWithNonExistingColumn(self): - """ Test fix for https://github.com/qgis/QGIS/issues/33878 """ + """Test fix for https://github.com/qgis/QGIS/issues/33878""" request = QgsFeatureRequest().setSubsetOfAttributes([0]) request.setFilterExpression("non_existing = 1") features = [f for f in self.source.getFeatures(request)] diff --git a/tests/src/python/mockedwebserver.py b/tests/src/python/mockedwebserver.py index 7c73b868ea31..eb114897f0ce 100644 --- a/tests/src/python/mockedwebserver.py +++ b/tests/src/python/mockedwebserver.py @@ -52,7 +52,19 @@ def install_http_handler(handler_instance): class RequestResponse: - def __init__(self, method, path, code, headers=None, body=None, custom_method=None, expected_headers=None, expected_body=None, add_content_length_header=True, unexpected_headers=[]): + def __init__( + self, + method, + path, + code, + headers=None, + body=None, + custom_method=None, + expected_headers=None, + expected_body=None, + add_content_length_header=True, + unexpected_headers=[], + ): self.method = method self.path = path self.code = code @@ -73,12 +85,38 @@ def __init__(self): def final_check(self): assert not self.unexpected - assert self.req_count == len(self.req_resp), (self.req_count, len(self.req_resp)) - - def add(self, method, path, code=None, headers=None, body=None, custom_method=None, expected_headers=None, expected_body=None, add_content_length_header=True, unexpected_headers=[]): + assert self.req_count == len(self.req_resp), ( + self.req_count, + len(self.req_resp), + ) + + def add( + self, + method, + path, + code=None, + headers=None, + body=None, + custom_method=None, + expected_headers=None, + expected_body=None, + add_content_length_header=True, + unexpected_headers=[], + ): hdrs = {} if headers is None else headers expected_hdrs = {} if expected_headers is None else expected_headers - req = RequestResponse(method, path, code, hdrs, body, custom_method, expected_hdrs, expected_body, add_content_length_header, unexpected_headers) + req = RequestResponse( + method, + path, + code, + hdrs, + body, + custom_method, + expected_hdrs, + expected_body, + add_content_length_header, + unexpected_headers, + ) self.req_resp.append(req) return req @@ -89,29 +127,34 @@ def _process_req_resp(self, req_resp, request): if req_resp.expected_headers: for k in req_resp.expected_headers: - if k not in request.headers or request.headers[k] != req_resp.expected_headers[k]: - sys.stderr.write('Did not get expected headers: %s\n' % str(request.headers)) + if ( + k not in request.headers + or request.headers[k] != req_resp.expected_headers[k] + ): + sys.stderr.write( + "Did not get expected headers: %s\n" % str(request.headers) + ) request.send_response(400) - request.send_header('Content-Length', 0) + request.send_header("Content-Length", 0) request.end_headers() self.unexpected = True return for k in req_resp.unexpected_headers: if k in request.headers: - sys.stderr.write('Did not expect header: %s\n' % k) + sys.stderr.write("Did not expect header: %s\n" % k) request.send_response(400) - request.send_header('Content-Length', 0) + request.send_header("Content-Length", 0) request.end_headers() self.unexpected = True return if req_resp.expected_body: - content = request.rfile.read(int(request.headers['Content-Length'])) + content = request.rfile.read(int(request.headers["Content-Length"])) if content != req_resp.expected_body: - sys.stderr.write('Did not get expected content: %s\n' % content) + sys.stderr.write("Did not get expected content: %s\n" % content) request.send_response(400) - request.send_header('Content-Length', 0) + request.send_header("Content-Length", 0) request.end_headers() self.unexpected = True return @@ -121,15 +164,15 @@ def _process_req_resp(self, req_resp, request): request.send_header(k, req_resp.headers[k]) if req_resp.add_content_length_header: if req_resp.body: - request.send_header('Content-Length', len(req_resp.body)) - elif 'Content-Length' not in req_resp.headers: - request.send_header('Content-Length', '0') + request.send_header("Content-Length", len(req_resp.body)) + elif "Content-Length" not in req_resp.headers: + request.send_header("Content-Length", "0") request.end_headers() if req_resp.body: try: request.wfile.write(req_resp.body) except: - request.wfile.write(req_resp.body.encode('ascii')) + request.wfile.write(req_resp.body.encode("ascii")) def process(self, method, request): if self.req_count < len(self.req_resp): @@ -139,38 +182,42 @@ def process(self, method, request): self._process_req_resp(req_resp, request) return - request.send_error(500, 'Unexpected %s request for %s, req_count = %d' % (method, request.path, self.req_count)) + request.send_error( + 500, + "Unexpected %s request for %s, req_count = %d" + % (method, request.path, self.req_count), + ) self.unexpected = True def do_HEAD(self, request): - self.process('HEAD', request) + self.process("HEAD", request) def do_GET(self, request): - self.process('GET', request) + self.process("GET", request) def do_POST(self, request): - self.process('POST', request) + self.process("POST", request) def do_PUT(self, request): - self.process('PUT', request) + self.process("PUT", request) def do_DELETE(self, request): - self.process('DELETE', request) + self.process("DELETE", request) class DispatcherHttpHandler(BaseHTTPRequestHandler): # protocol_version = 'HTTP/1.1' - def log_request(self, code='-', size='-'): + def log_request(self, code="-", size="-"): # pylint: disable=unused-argument pass def do_HEAD(self): if do_log: - f = open(tempfile.gettempdir() + '/log.txt', 'a') - f.write('HEAD %s\n' % self.path) + f = open(tempfile.gettempdir() + "/log.txt", "a") + f.write("HEAD %s\n" % self.path) f.close() custom_handler.do_HEAD(self) @@ -178,8 +225,8 @@ def do_HEAD(self): def do_DELETE(self): if do_log: - f = open(tempfile.gettempdir() + '/log.txt', 'a') - f.write('DELETE %s\n' % self.path) + f = open(tempfile.gettempdir() + "/log.txt", "a") + f.write("DELETE %s\n" % self.path) f.close() custom_handler.do_DELETE(self) @@ -187,8 +234,8 @@ def do_DELETE(self): def do_POST(self): if do_log: - f = open(tempfile.gettempdir() + '/log.txt', 'a') - f.write('POST %s\n' % self.path) + f = open(tempfile.gettempdir() + "/log.txt", "a") + f.write("POST %s\n" % self.path) f.close() custom_handler.do_POST(self) @@ -196,8 +243,8 @@ def do_POST(self): def do_PUT(self): if do_log: - f = open(tempfile.gettempdir() + '/log.txt', 'a') - f.write('PUT %s\n' % self.path) + f = open(tempfile.gettempdir() + "/log.txt", "a") + f.write("PUT %s\n" % self.path) f.close() custom_handler.do_PUT(self) @@ -205,8 +252,8 @@ def do_PUT(self): def do_GET(self): if do_log: - f = open(tempfile.gettempdir() + '/log.txt', 'a') - f.write('GET %s\n' % self.path) + f = open(tempfile.gettempdir() + "/log.txt", "a") + f.write("GET %s\n" % self.path) f.close() custom_handler.do_GET(self) @@ -216,7 +263,7 @@ class ThreadedHttpServer(Thread): def __init__(self, handlerClass): Thread.__init__(self) - self.server = HTTPServer(('', 0), handlerClass) + self.server = HTTPServer(("", 0), handlerClass) self.running = False def getPort(self): @@ -227,7 +274,7 @@ def run(self): self.running = True self.server.serve_forever() except KeyboardInterrupt: - print('^C received, shutting down server') + print("^C received, shutting down server") self.stop() def start_and_wait_ready(self): diff --git a/tests/src/python/offlineditingtestbase.py b/tests/src/python/offlineditingtestbase.py index 559e0d49c8f1..20782377fc09 100644 --- a/tests/src/python/offlineditingtestbase.py +++ b/tests/src/python/offlineditingtestbase.py @@ -18,10 +18,9 @@ (at your option) any later version. """ - -__author__ = 'Alessandro Pasotti' -__date__ = '2016-06-30' -__copyright__ = 'Copyright 2016, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "2016-06-30" +__copyright__ = "Copyright 2016, The QGIS Project" from time import sleep @@ -38,16 +37,16 @@ # Tet features, fields: [id, name, geometry] # "id" is used as a pk to retrieve features by attribute TEST_FEATURES = [ - (1, 'name 1', QgsPointXY(9, 45)), - (2, 'name 2', QgsPointXY(9.5, 45.5)), - (3, 'name 3', QgsPointXY(9.5, 46)), - (4, 'name 4', QgsPointXY(10, 46.5)), + (1, "name 1", QgsPointXY(9, 45)), + (2, "name 2", QgsPointXY(9.5, 45.5)), + (3, "name 3", QgsPointXY(9.5, 46)), + (4, "name 4", QgsPointXY(10, 46.5)), ] # Additional features for insert test TEST_FEATURES_INSERT = [ - (5, 'name 5', QgsPointXY(9.7, 45.7)), - (6, 'name 6', QgsPointXY(10.6, 46.6)), + (5, "name 5", QgsPointXY(9.7, 45.7)), + (6, "name 6", QgsPointXY(10.6, 46.6)), ] @@ -58,12 +57,12 @@ def _setUp(self): """Called by setUp: run before each test.""" # Setup: create some features for the test layer features = [] - layer = self._getLayer('test_point') + layer = self._getLayer("test_point") assert layer.startEditing() for id, name, geom in TEST_FEATURES: f = QgsFeature(layer.fields()) - f['id'] = id - f['name'] = name + f["id"] = id + f["name"] = name f.setGeometry(QgsGeometry.fromPointXY(geom)) features.append(f) layer.addFeatures(features) @@ -71,7 +70,7 @@ def _setUp(self): # Add the online layer self.registry = QgsProject.instance() self.registry.removeAllMapLayers() - assert self.registry.addMapLayer(self._getOnlineLayer('test_point')) is not None + assert self.registry.addMapLayer(self._getOnlineLayer("test_point")) is not None def _tearDown(self): """Called by tearDown: run after each test.""" @@ -82,8 +81,11 @@ def _tearDown(self): @classmethod def _compareFeature(cls, layer, attributes): """Compare id, name and geometry""" - f = cls._getFeatureByAttribute(layer, 'id', attributes[0]) - return f['name'] == attributes[1] and f.geometry().asPoint().toString() == attributes[2].toString() + f = cls._getFeatureByAttribute(layer, "id", attributes[0]) + return ( + f["name"] == attributes[1] + and f.geometry().asPoint().toString() == attributes[2].toString() + ) @classmethod def _clearLayer(cls, layer): @@ -114,13 +116,11 @@ def _getFeatureByAttribute(cls, layer, attr_name, attr_value): """ Find the feature and return it, raise exception if not found """ - request = QgsFeatureRequest(QgsExpression("{}={}".format(attr_name, - attr_value))) + request = QgsFeatureRequest(QgsExpression(f"{attr_name}={attr_value}")) try: return next(layer.dataProvider().getFeatures(request)) except StopIteration: - raise Exception("Wrong attributes in WFS layer %s" % - layer.name()) + raise Exception("Wrong attributes in WFS layer %s" % layer.name()) def _testInit(self): """ @@ -131,24 +131,40 @@ def _testInit(self): online_layer = list(self.registry.mapLayers().values())[0] self.assertTrue(online_layer.isSpatial()) # Check we have features - self.assertEqual(len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES)) - self.assertTrue(ol.convertToOfflineProject(self.temp_path, 'offlineDbFile.sqlite', [online_layer.id()])) + self.assertEqual( + len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES) + ) + self.assertTrue( + ol.convertToOfflineProject( + self.temp_path, "offlineDbFile.sqlite", [online_layer.id()] + ) + ) offline_layer = list(self.registry.mapLayers().values())[0] self.assertTrue(offline_layer.isSpatial()) self.assertTrue(offline_layer.isValid()) - self.assertGreater(offline_layer.name().find('(offline)'), -1) - self.assertEqual(len([f for f in offline_layer.getFeatures()]), len(TEST_FEATURES)) + self.assertGreater(offline_layer.name().find("(offline)"), -1) + self.assertEqual( + len([f for f in offline_layer.getFeatures()]), len(TEST_FEATURES) + ) return ol, offline_layer def test_updateFeatures(self): ol, offline_layer = self._testInit() # Edit feature 2 - feat2 = self._getFeatureByAttribute(offline_layer, 'name', "'name 2'") + feat2 = self._getFeatureByAttribute(offline_layer, "name", "'name 2'") self.assertTrue(offline_layer.startEditing()) - self.assertTrue(offline_layer.changeAttributeValue(feat2.id(), offline_layer.fields().lookupField('name'), 'name 2 edited')) - self.assertTrue(offline_layer.changeGeometry(feat2.id(), QgsGeometry.fromPointXY(QgsPointXY(33.0, 60.0)))) + self.assertTrue( + offline_layer.changeAttributeValue( + feat2.id(), offline_layer.fields().lookupField("name"), "name 2 edited" + ) + ) + self.assertTrue( + offline_layer.changeGeometry( + feat2.id(), QgsGeometry.fromPointXY(QgsPointXY(33.0, 60.0)) + ) + ) self.assertTrue(offline_layer.commitChanges()) - feat2 = self._getFeatureByAttribute(offline_layer, 'name', "'name 2 edited'") + feat2 = self._getFeatureByAttribute(offline_layer, "name", "'name 2 edited'") self.assertTrue(ol.isOfflineProject()) # Sync ol.synchronize() @@ -156,14 +172,20 @@ def test_updateFeatures(self): # Does anybody know why the sleep is needed? Is that a threaded WFS consequence? online_layer = list(self.registry.mapLayers().values())[0] self.assertTrue(online_layer.isValid()) - self.assertFalse(online_layer.name().find('(offline)') > -1) - self.assertEqual(len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES)) + self.assertFalse(online_layer.name().find("(offline)") > -1) + self.assertEqual( + len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES) + ) # Check that data have changed in the backend (raise exception if not found) - feat2 = self._getFeatureByAttribute(self._getLayer('test_point'), 'name', "'name 2 edited'") - feat2 = self._getFeatureByAttribute(online_layer, 'name', "'name 2 edited'") - self.assertEqual(feat2.geometry().asPoint().toString(), QgsPointXY(33.0, 60.0).toString()) + feat2 = self._getFeatureByAttribute( + self._getLayer("test_point"), "name", "'name 2 edited'" + ) + feat2 = self._getFeatureByAttribute(online_layer, "name", "'name 2 edited'") + self.assertEqual( + feat2.geometry().asPoint().toString(), QgsPointXY(33.0, 60.0).toString() + ) # Check that all other features have not changed - layer = self._getLayer('test_point') + layer = self._getLayer("test_point") self.assertTrue(self._compareFeature(layer, TEST_FEATURES[1 - 1])) self.assertTrue(self._compareFeature(layer, TEST_FEATURES[3 - 1])) self.assertTrue(self._compareFeature(layer, TEST_FEATURES[4 - 1])) @@ -173,27 +195,39 @@ def test_updateFeatures(self): ol = QgsOfflineEditing() offline_layer = list(self.registry.mapLayers().values())[0] # Edit feature 2 - feat2 = self._getFeatureByAttribute(offline_layer, 'name', "'name 2 edited'") + feat2 = self._getFeatureByAttribute(offline_layer, "name", "'name 2 edited'") self.assertTrue(offline_layer.startEditing()) - self.assertTrue(offline_layer.changeAttributeValue(feat2.id(), offline_layer.fields().lookupField('name'), 'name 2')) - self.assertTrue(offline_layer.changeGeometry(feat2.id(), QgsGeometry.fromPointXY(TEST_FEATURES[1][2]))) + self.assertTrue( + offline_layer.changeAttributeValue( + feat2.id(), offline_layer.fields().lookupField("name"), "name 2" + ) + ) + self.assertTrue( + offline_layer.changeGeometry( + feat2.id(), QgsGeometry.fromPointXY(TEST_FEATURES[1][2]) + ) + ) # Edit feat 4 - feat4 = self._getFeatureByAttribute(offline_layer, 'name', "'name 4'") - self.assertTrue(offline_layer.changeAttributeValue(feat4.id(), offline_layer.fields().lookupField('name'), 'name 4 edited')) + feat4 = self._getFeatureByAttribute(offline_layer, "name", "'name 4'") + self.assertTrue( + offline_layer.changeAttributeValue( + feat4.id(), offline_layer.fields().lookupField("name"), "name 4 edited" + ) + ) self.assertTrue(offline_layer.commitChanges()) # Sync ol.synchronize() # Does anybody knows why the sleep is needed? Is that a threaded WFS consequence? sleep(1) online_layer = list(self.registry.mapLayers().values())[0] - layer = self._getLayer('test_point') + layer = self._getLayer("test_point") # Check that data have changed in the backend (raise exception if not found) - feat4 = self._getFeatureByAttribute(layer, 'name', "'name 4 edited'") - feat4 = self._getFeatureByAttribute(online_layer, 'name', "'name 4 edited'") - feat2 = self._getFeatureByAttribute(layer, 'name', "'name 2'") - feat2 = self._getFeatureByAttribute(online_layer, 'name', "'name 2'") + feat4 = self._getFeatureByAttribute(layer, "name", "'name 4 edited'") + feat4 = self._getFeatureByAttribute(online_layer, "name", "'name 4 edited'") + feat2 = self._getFeatureByAttribute(layer, "name", "'name 2'") + feat2 = self._getFeatureByAttribute(online_layer, "name", "'name 2'") # Check that all other features have not changed - layer = self._getLayer('test_point') + layer = self._getLayer("test_point") self.assertTrue(self._compareFeature(layer, TEST_FEATURES[1 - 1])) self.assertTrue(self._compareFeature(layer, TEST_FEATURES[2 - 1])) self.assertTrue(self._compareFeature(layer, TEST_FEATURES[3 - 1])) @@ -204,11 +238,14 @@ def test_deleteOneFeature(self): """ ol, offline_layer = self._testInit() # Delete feature 3 - feat3 = self._getFeatureByAttribute(offline_layer, 'name', "'name 3'") + feat3 = self._getFeatureByAttribute(offline_layer, "name", "'name 3'") self.assertTrue(offline_layer.startEditing()) self.assertTrue(offline_layer.deleteFeatures([feat3.id()])) self.assertTrue(offline_layer.commitChanges()) - self.assertRaises(Exception, lambda: self._getFeatureByAttribute(offline_layer, 'name', "'name 3'")) + self.assertRaises( + Exception, + lambda: self._getFeatureByAttribute(offline_layer, "name", "'name 3'"), + ) self.assertTrue(ol.isOfflineProject()) # Sync ol.synchronize() @@ -216,12 +253,17 @@ def test_deleteOneFeature(self): sleep(1) online_layer = list(self.registry.mapLayers().values())[0] self.assertTrue(online_layer.isValid()) - self.assertFalse(online_layer.name().find('(offline)') > -1) - self.assertEqual(len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES) - 1) + self.assertFalse(online_layer.name().find("(offline)") > -1) + self.assertEqual( + len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES) - 1 + ) # Check that data have changed in the backend (raise exception if not found) - self.assertRaises(Exception, lambda: self._getFeatureByAttribute(online_layer, 'name', "'name 3'")) + self.assertRaises( + Exception, + lambda: self._getFeatureByAttribute(online_layer, "name", "'name 3'"), + ) # Check that all other features have not changed - layer = self._getLayer('test_point') + layer = self._getLayer("test_point") self.assertTrue(self._compareFeature(layer, TEST_FEATURES[1 - 1])) self.assertTrue(self._compareFeature(layer, TEST_FEATURES[2 - 1])) self.assertTrue(self._compareFeature(layer, TEST_FEATURES[4 - 1])) @@ -232,13 +274,19 @@ def test_deleteMultipleFeatures(self): """ ol, offline_layer = self._testInit() # Delete feature 1 and 3 - feat1 = self._getFeatureByAttribute(offline_layer, 'name', "'name 1'") - feat3 = self._getFeatureByAttribute(offline_layer, 'name', "'name 3'") + feat1 = self._getFeatureByAttribute(offline_layer, "name", "'name 1'") + feat3 = self._getFeatureByAttribute(offline_layer, "name", "'name 3'") self.assertTrue(offline_layer.startEditing()) self.assertTrue(offline_layer.deleteFeatures([feat3.id(), feat1.id()])) self.assertTrue(offline_layer.commitChanges()) - self.assertRaises(Exception, lambda: self._getFeatureByAttribute(offline_layer, 'name', "'name 3'")) - self.assertRaises(Exception, lambda: self._getFeatureByAttribute(offline_layer, 'name', "'name 1'")) + self.assertRaises( + Exception, + lambda: self._getFeatureByAttribute(offline_layer, "name", "'name 3'"), + ) + self.assertRaises( + Exception, + lambda: self._getFeatureByAttribute(offline_layer, "name", "'name 1'"), + ) self.assertTrue(ol.isOfflineProject()) # Sync ol.synchronize() @@ -246,13 +294,21 @@ def test_deleteMultipleFeatures(self): sleep(1) online_layer = list(self.registry.mapLayers().values())[0] self.assertTrue(online_layer.isValid()) - self.assertFalse(online_layer.name().find('(offline)') > -1) - self.assertEqual(len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES) - 2) + self.assertFalse(online_layer.name().find("(offline)") > -1) + self.assertEqual( + len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES) - 2 + ) # Check that data have changed in the backend (raise exception if not found) - self.assertRaises(Exception, lambda: self._getFeatureByAttribute(online_layer, 'name', "'name 3'")) - self.assertRaises(Exception, lambda: self._getFeatureByAttribute(online_layer, 'name', "'name 1'")) + self.assertRaises( + Exception, + lambda: self._getFeatureByAttribute(online_layer, "name", "'name 3'"), + ) + self.assertRaises( + Exception, + lambda: self._getFeatureByAttribute(online_layer, "name", "'name 1'"), + ) # Check that all other features have not changed - layer = self._getLayer('test_point') + layer = self._getLayer("test_point") self.assertTrue(self._compareFeature(layer, TEST_FEATURES[2 - 1])) self.assertTrue(self._compareFeature(layer, TEST_FEATURES[4 - 1])) @@ -266,14 +322,14 @@ def test_InsertFeatures(self): features = [] for id, name, geom in TEST_FEATURES_INSERT: f = QgsFeature(offline_layer.fields()) - f['id'] = id - f['name'] = name + f["id"] = id + f["name"] = name f.setGeometry(QgsGeometry.fromPointXY(geom)) features.append(f) offline_layer.addFeatures(features) self.assertTrue(offline_layer.commitChanges()) - self._getFeatureByAttribute(offline_layer, 'name', "'name 5'") - self._getFeatureByAttribute(offline_layer, 'name', "'name 6'") + self._getFeatureByAttribute(offline_layer, "name", "'name 5'") + self._getFeatureByAttribute(offline_layer, "name", "'name 6'") self.assertTrue(ol.isOfflineProject()) # Sync ol.synchronize() @@ -281,13 +337,15 @@ def test_InsertFeatures(self): sleep(1) online_layer = list(self.registry.mapLayers().values())[0] self.assertTrue(online_layer.isValid()) - self.assertFalse(online_layer.name().find('(offline)') > -1) - self.assertEqual(len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES) + 2) + self.assertFalse(online_layer.name().find("(offline)") > -1) + self.assertEqual( + len([f for f in online_layer.getFeatures()]), len(TEST_FEATURES) + 2 + ) # Check that data have changed in the backend (raise exception if not found) - self._getFeatureByAttribute(online_layer, 'name', "'name 5'") - self._getFeatureByAttribute(online_layer, 'name', "'name 6'") + self._getFeatureByAttribute(online_layer, "name", "'name 5'") + self._getFeatureByAttribute(online_layer, "name", "'name 6'") # Check that all other features have not changed - layer = self._getLayer('test_point') + layer = self._getLayer("test_point") self.assertTrue(self._compareFeature(layer, TEST_FEATURES[1 - 1])) self.assertTrue(self._compareFeature(layer, TEST_FEATURES[2 - 1])) self.assertTrue(self._compareFeature(layer, TEST_FEATURES[3 - 1])) diff --git a/tests/src/python/provider_python.py b/tests/src/python/provider_python.py index 2b99e20e1a44..ad6ab99e0f2a 100644 --- a/tests/src/python/provider_python.py +++ b/tests/src/python/provider_python.py @@ -8,9 +8,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '2018-03-18' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "2018-03-18" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.PyQt.QtCore import QVariant from qgis.core import ( @@ -52,27 +53,50 @@ def __init__(self, source, request): self._filter_rect = self.filterRectToSourceCrs(self._transform) if not self._filter_rect.isNull(): self._select_rect_geom = QgsGeometry.fromRect(self._filter_rect) - self._select_rect_engine = QgsGeometry.createGeometryEngine(self._select_rect_geom.constGet()) + self._select_rect_engine = QgsGeometry.createGeometryEngine( + self._select_rect_geom.constGet() + ) self._select_rect_engine.prepareGeometry() else: self._select_rect_engine = None self._select_rect_geom = None - if self._request.spatialFilterType() == Qgis.SpatialFilterType.DistanceWithin and not self._request.referenceGeometry().isEmpty(): + if ( + self._request.spatialFilterType() == Qgis.SpatialFilterType.DistanceWithin + and not self._request.referenceGeometry().isEmpty() + ): self._select_distance_within_geom = self._request.referenceGeometry() - self._select_distance_within_engine = QgsGeometry.createGeometryEngine(self._select_distance_within_geom.constGet()) + self._select_distance_within_engine = QgsGeometry.createGeometryEngine( + self._select_distance_within_geom.constGet() + ) self._select_distance_within_engine.prepareGeometry() else: self._select_distance_within_geom = None self._select_distance_within_engine = None self._feature_id_list = None - if self._filter_rect is not None and self._source._provider._spatialindex is not None: - self._feature_id_list = self._source._provider._spatialindex.intersects(self._filter_rect) - - if self._request.filterType() == QgsFeatureRequest.FilterType.FilterFid or self._request.filterType() == QgsFeatureRequest.FilterType.FilterFids: - fids = [self._request.filterFid()] if self._request.filterType() == QgsFeatureRequest.FilterType.FilterFid else self._request.filterFids() - self._feature_id_list = list(set(self._feature_id_list).intersection(set(fids))) if self._feature_id_list else fids + if ( + self._filter_rect is not None + and self._source._provider._spatialindex is not None + ): + self._feature_id_list = self._source._provider._spatialindex.intersects( + self._filter_rect + ) + + if ( + self._request.filterType() == QgsFeatureRequest.FilterType.FilterFid + or self._request.filterType() == QgsFeatureRequest.FilterType.FilterFids + ): + fids = ( + [self._request.filterFid()] + if self._request.filterType() == QgsFeatureRequest.FilterType.FilterFid + else self._request.filterFids() + ) + self._feature_id_list = ( + list(set(self._feature_id_list).intersection(set(fids))) + if self._feature_id_list + else fids + ) def fetchFeature(self, f): """fetch next feature, return true on success""" @@ -83,10 +107,15 @@ def fetchFeature(self, f): try: found = False while not found: - _f = self._source._features[list(self._source._features.keys())[self._index]] + _f = self._source._features[ + list(self._source._features.keys())[self._index] + ] self._index += 1 - if self._feature_id_list is not None and _f.id() not in self._feature_id_list: + if ( + self._feature_id_list is not None + and _f.id() not in self._feature_id_list + ): continue if not self._filter_rect.isNull(): @@ -94,29 +123,53 @@ def fetchFeature(self, f): continue if self._request.flags() & QgsFeatureRequest.Flag.ExactIntersect: # do exact check in case we're doing intersection - if not self._select_rect_engine.intersects(_f.geometry().constGet()): + if not self._select_rect_engine.intersects( + _f.geometry().constGet() + ): continue else: - if not _f.geometry().boundingBox().intersects(self._filter_rect): + if ( + not _f.geometry() + .boundingBox() + .intersects(self._filter_rect) + ): continue self._source._expression_context.setFeature(_f) - if self._request.filterType() == QgsFeatureRequest.FilterType.FilterExpression: - if not self._request.filterExpression().evaluate(self._source._expression_context): + if ( + self._request.filterType() + == QgsFeatureRequest.FilterType.FilterExpression + ): + if not self._request.filterExpression().evaluate( + self._source._expression_context + ): continue if self._source._subset_expression: - if not self._source._subset_expression.evaluate(self._source._expression_context): + if not self._source._subset_expression.evaluate( + self._source._expression_context + ): continue - elif self._request.filterType() == QgsFeatureRequest.FilterType.FilterFids: + elif ( + self._request.filterType() + == QgsFeatureRequest.FilterType.FilterFids + ): if not _f.id() in self._request.filterFids(): continue - elif self._request.filterType() == QgsFeatureRequest.FilterType.FilterFid: + elif ( + self._request.filterType() == QgsFeatureRequest.FilterType.FilterFid + ): if _f.id() != self._request.filterFid(): continue f.setGeometry(_f.geometry()) self.geometryToDestinationCrs(f, self._transform) - if self._select_distance_within_engine and self._select_distance_within_engine.distance(f.geometry().constGet()) > self._request.distanceWithin(): + if ( + self._select_distance_within_engine + and self._select_distance_within_engine.distance( + f.geometry().constGet() + ) + > self._request.distanceWithin() + ): continue f.setFields(_f.fields()) @@ -165,7 +218,9 @@ def __init__(self, provider): self._expression_context = QgsExpressionContext() self._expression_context.appendScope(QgsExpressionContextUtils.globalScope()) - self._expression_context.appendScope(QgsExpressionContextUtils.projectScope(QgsProject.instance())) + self._expression_context.appendScope( + QgsExpressionContextUtils.projectScope(QgsProject.instance()) + ) self._expression_context.setFields(self._provider.fields()) if self._provider.subsetString(): self._subset_expression = QgsExpression(self._provider.subsetString()) @@ -184,12 +239,12 @@ class PyProvider(QgsVectorDataProvider): @classmethod def providerKey(cls): """Returns the memory provider key""" - return 'pythonprovider' + return "pythonprovider" @classmethod def description(cls): """Returns the memory provider description""" - return 'Python Test Provider' + return "Python Test Provider" @classmethod def createProvider(cls, uri, providerOptions, flags=QgsDataProvider.ReadFlags()): @@ -197,10 +252,15 @@ def createProvider(cls, uri, providerOptions, flags=QgsDataProvider.ReadFlags()) # Implementation of functions from QgsVectorDataProvider - def __init__(self, uri='', providerOptions=QgsDataProvider.ProviderOptions(), flags=QgsDataProvider.ReadFlags()): + def __init__( + self, + uri="", + providerOptions=QgsDataProvider.ProviderOptions(), + flags=QgsDataProvider.ReadFlags(), + ): super().__init__(uri) # Use the memory layer to parse the uri - mlayer = QgsVectorLayer(uri, 'ml', 'memory') + mlayer = QgsVectorLayer(uri, "ml", "memory") self.setNativeTypes(mlayer.dataProvider().nativeTypes()) self._uri = uri self._fields = mlayer.fields() @@ -208,12 +268,12 @@ def __init__(self, uri='', providerOptions=QgsDataProvider.ProviderOptions(), fl self._features = {} self._extent = QgsRectangle() self._extent.setNull() - self._subset_string = '' + self._subset_string = "" self._crs = mlayer.crs() self._spatialindex = None self._provider_options = providerOptions self._flags = flags - if 'index=yes' in self._uri: + if "index=yes" in self._uri: self.createSpatialIndex() def featureSource(self): @@ -300,7 +360,17 @@ def deleteFeatures(self, ids): def addAttributes(self, attrs): try: for new_f in attrs: - if new_f.type() not in (QVariant.Int, QVariant.Double, QVariant.String, QVariant.Date, QVariant.Time, QVariant.DateTime, QVariant.LongLong, QVariant.StringList, QVariant.List): + if new_f.type() not in ( + QVariant.Int, + QVariant.Double, + QVariant.String, + QVariant.Date, + QVariant.Time, + QVariant.DateTime, + QVariant.LongLong, + QVariant.StringList, + QVariant.List, + ): continue self._fields.append(new_f) for f in self._features.values(): @@ -339,7 +409,7 @@ def deleteAttributes(self, attributes): self._fields.remove(idx) for f in self._features.values(): attr = f.attributes() - del (attr[idx]) + del attr[idx] f.setAttributes(attr) self.clearMinMaxCache() return True @@ -391,7 +461,18 @@ def createSpatialIndex(self): return True def capabilities(self): - return QgsVectorDataProvider.Capability.AddFeatures | QgsVectorDataProvider.Capability.DeleteFeatures | QgsVectorDataProvider.Capability.CreateSpatialIndex | QgsVectorDataProvider.Capability.ChangeGeometries | QgsVectorDataProvider.Capability.ChangeAttributeValues | QgsVectorDataProvider.Capability.AddAttributes | QgsVectorDataProvider.Capability.DeleteAttributes | QgsVectorDataProvider.Capability.RenameAttributes | QgsVectorDataProvider.Capability.SelectAtId | QgsVectorDataProvider.Capability. CircularGeometries + return ( + QgsVectorDataProvider.Capability.AddFeatures + | QgsVectorDataProvider.Capability.DeleteFeatures + | QgsVectorDataProvider.Capability.CreateSpatialIndex + | QgsVectorDataProvider.Capability.ChangeGeometries + | QgsVectorDataProvider.Capability.ChangeAttributeValues + | QgsVectorDataProvider.Capability.AddAttributes + | QgsVectorDataProvider.Capability.DeleteAttributes + | QgsVectorDataProvider.Capability.RenameAttributes + | QgsVectorDataProvider.Capability.SelectAtId + | QgsVectorDataProvider.Capability.CircularGeometries + ) # /* Implementation of functions from QgsDataProvider */ @@ -407,7 +488,9 @@ def extent(self): if feat.hasGeometry(): self._extent.combineExtentWith(feat.geometry().boundingBox()) else: - for f in self.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([])): + for f in self.getFeatures( + QgsFeatureRequest().setSubsetOfAttributes([]) + ): if f.hasGeometry(): self._extent.combineExtentWith(f.geometry().boundingBox()) diff --git a/tests/src/python/providertestbase.py b/tests/src/python/providertestbase.py index c2533b6c8009..073ada0f14f9 100644 --- a/tests/src/python/providertestbase.py +++ b/tests/src/python/providertestbase.py @@ -6,10 +6,9 @@ (at your option) any later version. """ - -__author__ = 'Matthias Kuhn' -__date__ = '2015-04-27' -__copyright__ = 'Copyright 2015, The QGIS Project' +__author__ = "Matthias Kuhn" +__date__ = "2015-04-27" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, Qt, QTime, QVariant from qgis.PyQt.QtTest import QSignalSpy @@ -38,69 +37,87 @@ class ProviderTestCase(FeatureSourceTestCase): - ''' - This is a collection of tests for vector data providers and kept generic. - To make use of it, subclass it and set self.source to a provider you want to test. - Make sure that your provider uses the default dataset by converting one of the provided datasets from the folder - tests/testdata/provider to a dataset your provider is able to handle. + """ + This is a collection of tests for vector data providers and kept generic. + To make use of it, subclass it and set self.source to a provider you want to test. + Make sure that your provider uses the default dataset by converting one of the provided datasets from the folder + tests/testdata/provider to a dataset your provider is able to handle. - To test expression compilation, add the methods `enableCompiler()` and `disableCompiler()` to your subclass. - If these methods are present, the tests will ensure that the result of server side and client side expression - evaluation are equal. + To test expression compilation, add the methods `enableCompiler()` and `disableCompiler()` to your subclass. + If these methods are present, the tests will ensure that the result of server side and client side expression + evaluation are equal. - To enable constraints checks for a data provider, please see the comment to the specific tests: - - testChangeAttributesConstraintViolation - - testUniqueNotNullConstraints + To enable constraints checks for a data provider, please see the comment to the specific tests: + - testChangeAttributesConstraintViolation + - testUniqueNotNullConstraints - ''' + """ def uncompiledFilters(self): - """ Individual derived provider tests should override this to return a list of expressions which - cannot be compiled """ + """Individual derived provider tests should override this to return a list of expressions which + cannot be compiled""" return set() def enableCompiler(self): """By default there is no expression compiling available, needs to be overridden in subclass""" - print('Provider does not support compiling') + print("Provider does not support compiling") return False def partiallyCompiledFilters(self): - """ Individual derived provider tests should override this to return a list of expressions which - should be partially compiled """ + """Individual derived provider tests should override this to return a list of expressions which + should be partially compiled""" return set() @property def pk_name(self): """Return the primary key name, override if different than the default 'pk'""" - return 'pk' + return "pk" def assert_query(self, source, expression, expected): FeatureSourceTestCase.assert_query(self, source, expression, expected) if self.compiled: # Check compilation status - it = source.getFeatures(QgsFeatureRequest().setFilterExpression(expression).setFlags(QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation)) + it = source.getFeatures( + QgsFeatureRequest() + .setFilterExpression(expression) + .setFlags( + QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation + ) + ) if expression in self.uncompiledFilters(): - self.assertEqual(it.compileStatus(), QgsAbstractFeatureIterator.CompileStatus.NoCompilation) + self.assertEqual( + it.compileStatus(), + QgsAbstractFeatureIterator.CompileStatus.NoCompilation, + ) elif expression in self.partiallyCompiledFilters(): - self.assertEqual(it.compileStatus(), QgsAbstractFeatureIterator.CompileStatus.PartiallyCompiled) + self.assertEqual( + it.compileStatus(), + QgsAbstractFeatureIterator.CompileStatus.PartiallyCompiled, + ) else: - self.assertEqual(it.compileStatus(), QgsAbstractFeatureIterator.CompileStatus.Compiled, expression) + self.assertEqual( + it.compileStatus(), + QgsAbstractFeatureIterator.CompileStatus.Compiled, + expression, + ) def runGetFeatureTests(self, source): FeatureSourceTestCase.runGetFeatureTests(self, source) # combination of an uncompilable expression and limit - feature = next(self.vl.getFeatures('pk=4')) + feature = next(self.vl.getFeatures("pk=4")) context = QgsExpressionContext() scope = QgsExpressionContextScope() - scope.setVariable('parent', feature) + scope.setVariable("parent", feature) context.appendScope(scope) request = QgsFeatureRequest() request.setExpressionContext(context) - request.setFilterExpression('"pk" = attribute(@parent, \'pk\')').setFlags(QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation) + request.setFilterExpression("\"pk\" = attribute(@parent, 'pk')").setFlags( + QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation + ) request.setLimit(1) values = [f[self.pk_name] for f in self.vl.getFeatures(request)] @@ -110,42 +127,62 @@ def runPolyGetFeatureTests(self, provider): assert len([f for f in provider.getFeatures()]) == 4 # geometry - self.assert_query(provider, 'x($geometry) < -70', [1]) - self.assert_query(provider, 'y($geometry) > 79', [1, 2]) - self.assert_query(provider, 'xmin($geometry) < -70', [1, 3]) - self.assert_query(provider, 'ymin($geometry) < 76', [3]) - self.assert_query(provider, 'xmax($geometry) > -68', [2, 3]) - self.assert_query(provider, 'ymax($geometry) > 80', [1, 2]) - self.assert_query(provider, 'area($geometry) > 10', [1]) - self.assert_query(provider, 'perimeter($geometry) < 12', [2, 3]) - self.assert_query(provider, - 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\')) = \'FF2FF1212\'', - [1, 3]) - self.assert_query(provider, - 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'), \'****F****\')', - [1, 3]) - self.assert_query(provider, - 'crosses($geometry,geom_from_wkt( \'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)\'))', - [2]) - self.assert_query(provider, - 'overlaps($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'))', - [2]) - self.assert_query(provider, - 'within($geometry,geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - [1]) - self.assert_query(provider, - 'overlaps(translate($geometry,-1,-1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - [1]) - self.assert_query(provider, - 'overlaps(buffer($geometry,1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - [1, 3]) - self.assert_query(provider, - 'intersects(centroid($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', - [2]) - self.assert_query(provider, - 'intersects(point_on_surface($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', - [1, 2]) - self.assert_query(provider, 'distance($geometry,geom_from_wkt( \'Point (-70 70)\')) > 7', [1, 2]) + self.assert_query(provider, "x($geometry) < -70", [1]) + self.assert_query(provider, "y($geometry) > 79", [1, 2]) + self.assert_query(provider, "xmin($geometry) < -70", [1, 3]) + self.assert_query(provider, "ymin($geometry) < 76", [3]) + self.assert_query(provider, "xmax($geometry) > -68", [2, 3]) + self.assert_query(provider, "ymax($geometry) > 80", [1, 2]) + self.assert_query(provider, "area($geometry) > 10", [1]) + self.assert_query(provider, "perimeter($geometry) < 12", [2, 3]) + self.assert_query( + provider, + "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))')) = 'FF2FF1212'", + [1, 3], + ) + self.assert_query( + provider, + "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'), '****F****')", + [1, 3], + ) + self.assert_query( + provider, + "crosses($geometry,geom_from_wkt( 'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)'))", + [2], + ) + self.assert_query( + provider, + "overlaps($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'))", + [2], + ) + self.assert_query( + provider, + "within($geometry,geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + [1], + ) + self.assert_query( + provider, + "overlaps(translate($geometry,-1,-1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + [1], + ) + self.assert_query( + provider, + "overlaps(buffer($geometry,1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + [1, 3], + ) + self.assert_query( + provider, + "intersects(centroid($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))", + [2], + ) + self.assert_query( + provider, + "intersects(point_on_surface($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))", + [1, 2], + ) + self.assert_query( + provider, "distance($geometry,geom_from_wkt( 'Point (-70 70)')) > 7", [1, 2] + ) def testGetFeaturesUncompiled(self): self.compiled = False @@ -154,19 +191,19 @@ def testGetFeaturesUncompiled(self): except AttributeError: pass self.runGetFeatureTests(self.source) - if hasattr(self, 'poly_provider'): + if hasattr(self, "poly_provider"): self.runPolyGetFeatureTests(self.poly_provider) def testGetFeaturesExp(self): if self.enableCompiler(): self.compiled = True self.runGetFeatureTests(self.source) - if hasattr(self, 'poly_provider'): + if hasattr(self, "poly_provider"): self.runPolyGetFeatureTests(self.poly_provider) def testSubsetString(self): if not self.source.supportsSubsetString(): - print('Provider does not support subset strings') + print("Provider does not support subset strings") return changed_spy = QSignalSpy(self.source.dataChanged) @@ -180,12 +217,15 @@ def testSubsetString(self): self.assertEqual(len(changed_spy), 1) result = {f[self.pk_name] for f in self.source.getFeatures()} - all_valid = (all(f.isValid() for f in self.source.getFeatures())) + all_valid = all(f.isValid() for f in self.source.getFeatures()) self.source.setSubsetString(None) expected = {2, 3, 4} - assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected), - result, subset) + assert ( + set(expected) == result + ), "Expected {} and got {} when testing subset string {}".format( + set(expected), result, subset + ) self.assertTrue(all_valid) # Subset string AND filter rect @@ -193,31 +233,43 @@ def testSubsetString(self): extent = QgsRectangle(-70, 70, -60, 75) request = QgsFeatureRequest().setFilterRect(extent) result = {f[self.pk_name] for f in self.source.getFeatures(request)} - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) self.source.setSubsetString(None) expected = {2} - assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected), - result, subset) + assert ( + set(expected) == result + ), "Expected {} and got {} when testing subset string {}".format( + set(expected), result, subset + ) self.assertTrue(all_valid) # Subset string AND filter rect, version 2 self.source.setSubsetString(subset) extent = QgsRectangle(-71, 65, -60, 80) - result = {f[self.pk_name] for f in self.source.getFeatures(QgsFeatureRequest().setFilterRect(extent))} + result = { + f[self.pk_name] + for f in self.source.getFeatures(QgsFeatureRequest().setFilterRect(extent)) + } self.source.setSubsetString(None) expected = {2, 4} - assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected), - result, subset) + assert ( + set(expected) == result + ), "Expected {} and got {} when testing subset string {}".format( + set(expected), result, subset + ) # Subset string AND expression self.source.setSubsetString(subset) request = QgsFeatureRequest().setFilterExpression('length("name")=5') result = {f[self.pk_name] for f in self.source.getFeatures(request)} - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) self.source.setSubsetString(None) expected = {2, 4} - assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected), - result, subset) + assert ( + set(expected) == result + ), "Expected {} and got {} when testing subset string {}".format( + set(expected), result, subset + ) self.assertTrue(all_valid) if self.providerCompatibleOfSubsetStringWithStableFID(): @@ -226,31 +278,37 @@ def testSubsetString(self): self.source.setSubsetString(subset) request = QgsFeatureRequest().setFilterFid(ids[4]) result = {f.id() for f in self.source.getFeatures(request)} - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) self.source.setSubsetString(None) expected = {ids[4]} - assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected), - result, subset) + assert ( + set(expected) == result + ), "Expected {} and got {} when testing subset string {}".format( + set(expected), result, subset + ) self.assertTrue(all_valid) # Subset string AND filter fids self.source.setSubsetString(subset) request = QgsFeatureRequest().setFilterFids([ids[2], ids[4]]) result = {f.id() for f in self.source.getFeatures(request)} - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) self.source.setSubsetString(None) expected = {ids[2], ids[4]} - assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected), - result, subset) + assert ( + set(expected) == result + ), "Expected {} and got {} when testing subset string {}".format( + set(expected), result, subset + ) self.assertTrue(all_valid) def providerCompatibleOfSubsetStringWithStableFID(self): - """ Return whether the provider is expected to have stable FID when changing subsetString. - The WFS provider might not always be able to have that guarantee. """ + """Return whether the provider is expected to have stable FID when changing subsetString. + The WFS provider might not always be able to have that guarantee.""" return True def referenceExtent(self): - """ Extent of the reference dataset """ + """Extent of the reference dataset""" return QgsRectangle(-71.123, 66.33, -65.32, 78.3) def getSubsetString(self): @@ -262,16 +320,16 @@ def getSubsetString2(self): return '"cnt" > 100 and "cnt" < 400' def referenceSubsetString3Extent(self): - """ Extent of the data selected by subset string 3 """ + """Extent of the data selected by subset string 3""" return QgsRectangle(-68.2, 70.8, -68.2, 70.8) def getSubsetString3(self): """Individual providers may need to override this depending on their subset string formats""" - return '"name"=\'Apple\'' + return "\"name\"='Apple'" def getSubsetStringNoMatching(self): """Individual providers may need to override this depending on their subset string formats""" - return '"name"=\'AppleBearOrangePear\'' + return "\"name\"='AppleBearOrangePear'" def testGetFeaturesThreadSafety(self): # no request @@ -280,7 +338,9 @@ def testGetFeaturesThreadSafety(self): # filter rect request extent = QgsRectangle(-73, 70, -63, 80) request = QgsFeatureRequest().setFilterRect(extent) - self.assertTrue(QgsTestUtils.testProviderIteratorThreadSafety(self.source, request)) + self.assertTrue( + QgsTestUtils.testProviderIteratorThreadSafety(self.source, request) + ) def testOrderBy(self): try: @@ -297,7 +357,11 @@ def runOrderByTests(self): FeatureSourceTestCase.runOrderByTests(self) # Combination with subset of attributes - request = QgsFeatureRequest().addOrderBy('num_char', False).setSubsetOfAttributes([self.pk_name], self.vl.fields()) + request = ( + QgsFeatureRequest() + .addOrderBy("num_char", False) + .setSubsetOfAttributes([self.pk_name], self.vl.fields()) + ) values = [f[self.pk_name] for f in self.vl.getFeatures(request)] self.assertEqual(values, [5, 4, 3, 2, 1]) @@ -307,7 +371,7 @@ def testOpenIteratorAfterLayerRemoval(self): information should be captured in the iterator's source and there MUST be no links between the iterators and the layer's data provider """ - if not getattr(self, 'getEditableLayer', None): + if not getattr(self, "getEditableLayer", None): return l = self.getEditableLayer() @@ -337,7 +401,7 @@ def testCloneLayer(self): self.assertEqual(set(pks), {1, 2, 3, 4, 5}) def testGetFeaturesPolyFilterRectTests(self): - """ Test fetching features from a polygon layer with filter rect""" + """Test fetching features from a polygon layer with filter rect""" try: if not self.poly_provider: return @@ -347,85 +411,146 @@ def testGetFeaturesPolyFilterRectTests(self): extent = QgsRectangle(-73, 70, -63, 80) request = QgsFeatureRequest().setFilterRect(extent) features = [f[self.pk_name] for f in self.poly_provider.getFeatures(request)] - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) # Some providers may return the exact intersection matches (2, 3) even without the ExactIntersect flag, so we accept that too - assert set(features) == {2, 3} or set(features) == {1, 2, 3}, f'Got {features} instead' + assert set(features) == {2, 3} or set(features) == { + 1, + 2, + 3, + }, f"Got {features} instead" self.assertTrue(all_valid) # Test with exact intersection - request = QgsFeatureRequest().setFilterRect(extent).setFlags(QgsFeatureRequest.Flag.ExactIntersect) + request = ( + QgsFeatureRequest() + .setFilterRect(extent) + .setFlags(QgsFeatureRequest.Flag.ExactIntersect) + ) features = [f[self.pk_name] for f in self.poly_provider.getFeatures(request)] - all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) - assert set(features) == {2, 3}, f'Got {features} instead' + all_valid = all(f.isValid() for f in self.source.getFeatures(request)) + assert set(features) == {2, 3}, f"Got {features} instead" self.assertTrue(all_valid) # test with an empty rectangle extent = QgsRectangle() - features = [f[self.pk_name] for f in self.source.getFeatures(QgsFeatureRequest().setFilterRect(extent))] - assert set(features) == {1, 2, 3, 4, 5}, f'Got {features} instead' + features = [ + f[self.pk_name] + for f in self.source.getFeatures(QgsFeatureRequest().setFilterRect(extent)) + ] + assert set(features) == {1, 2, 3, 4, 5}, f"Got {features} instead" def testMinValue(self): self.assertFalse(self.source.minimumValue(-1)) self.assertFalse(self.source.minimumValue(1000)) - self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('cnt')), -200) - self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('name')), 'Apple') + self.assertEqual( + self.source.minimumValue(self.source.fields().lookupField("cnt")), -200 + ) + self.assertEqual( + self.source.minimumValue(self.source.fields().lookupField("name")), "Apple" + ) if self.treat_datetime_as_string(): - self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('dt')), '2020-05-03 12:13:14') + self.assertEqual( + self.source.minimumValue(self.source.fields().lookupField("dt")), + "2020-05-03 12:13:14", + ) else: - self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('dt')), - QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14))) + self.assertEqual( + self.source.minimumValue(self.source.fields().lookupField("dt")), + QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), + ) if self.treat_date_as_string(): - self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('date')), '2020-05-02') + self.assertEqual( + self.source.minimumValue(self.source.fields().lookupField("date")), + "2020-05-02", + ) elif not self.treat_date_as_datetime(): - self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('date')), QDate(2020, 5, 2)) + self.assertEqual( + self.source.minimumValue(self.source.fields().lookupField("date")), + QDate(2020, 5, 2), + ) else: - self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('date')), - QDateTime(2020, 5, 2, 0, 0, 0)) + self.assertEqual( + self.source.minimumValue(self.source.fields().lookupField("date")), + QDateTime(2020, 5, 2, 0, 0, 0), + ) if not self.treat_time_as_string(): - self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('time')), QTime(12, 13, 1)) + self.assertEqual( + self.source.minimumValue(self.source.fields().lookupField("time")), + QTime(12, 13, 1), + ) else: - self.assertEqual(self.source.minimumValue(self.source.fields().lookupField('time')), '12:13:01') + self.assertEqual( + self.source.minimumValue(self.source.fields().lookupField("time")), + "12:13:01", + ) if self.source.supportsSubsetString(): subset = self.getSubsetString() self.source.setSubsetString(subset) - min_value = self.source.minimumValue(self.source.fields().lookupField('cnt')) + min_value = self.source.minimumValue( + self.source.fields().lookupField("cnt") + ) self.source.setSubsetString(None) self.assertEqual(min_value, 200) def testMaxValue(self): self.assertFalse(self.source.maximumValue(-1)) self.assertFalse(self.source.maximumValue(1000)) - self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('cnt')), 400) - self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('name')), 'Pear') + self.assertEqual( + self.source.maximumValue(self.source.fields().lookupField("cnt")), 400 + ) + self.assertEqual( + self.source.maximumValue(self.source.fields().lookupField("name")), "Pear" + ) if not self.treat_datetime_as_string(): - self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('dt')), - QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14))) + self.assertEqual( + self.source.maximumValue(self.source.fields().lookupField("dt")), + QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), + ) else: - self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('dt')), '2021-05-04 13:13:14') + self.assertEqual( + self.source.maximumValue(self.source.fields().lookupField("dt")), + "2021-05-04 13:13:14", + ) if self.treat_date_as_string(): - self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('date')), '2021-05-04') + self.assertEqual( + self.source.maximumValue(self.source.fields().lookupField("date")), + "2021-05-04", + ) elif not self.treat_date_as_datetime(): - self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('date')), QDate(2021, 5, 4)) + self.assertEqual( + self.source.maximumValue(self.source.fields().lookupField("date")), + QDate(2021, 5, 4), + ) else: - self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('date')), - QDateTime(2021, 5, 4, 0, 0, 0)) + self.assertEqual( + self.source.maximumValue(self.source.fields().lookupField("date")), + QDateTime(2021, 5, 4, 0, 0, 0), + ) if not self.treat_time_as_string(): - self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('time')), QTime(13, 13, 14)) + self.assertEqual( + self.source.maximumValue(self.source.fields().lookupField("time")), + QTime(13, 13, 14), + ) else: - self.assertEqual(self.source.maximumValue(self.source.fields().lookupField('time')), '13:13:14') + self.assertEqual( + self.source.maximumValue(self.source.fields().lookupField("time")), + "13:13:14", + ) if self.source.supportsSubsetString(): subset = self.getSubsetString2() self.source.setSubsetString(subset) - max_value = self.source.maximumValue(self.source.fields().lookupField('cnt')) + max_value = self.source.maximumValue( + self.source.fields().lookupField("cnt") + ) self.source.setSubsetString(None) self.assertEqual(max_value, 300) @@ -447,10 +572,18 @@ def testExtentSubsetString(self): subset_extent = self.referenceSubsetString3Extent() self.source.setSubsetString(None) self.assertEqual(count, 1) - self.assertAlmostEqual(provider_extent.xMinimum(), subset_extent.xMinimum(), 3) - self.assertAlmostEqual(provider_extent.xMaximum(), subset_extent.xMaximum(), 3) - self.assertAlmostEqual(provider_extent.yMinimum(), subset_extent.yMinimum(), 3) - self.assertAlmostEqual(provider_extent.yMaximum(), subset_extent.yMaximum(), 3) + self.assertAlmostEqual( + provider_extent.xMinimum(), subset_extent.xMinimum(), 3 + ) + self.assertAlmostEqual( + provider_extent.xMaximum(), subset_extent.xMaximum(), 3 + ) + self.assertAlmostEqual( + provider_extent.yMinimum(), subset_extent.yMinimum(), 3 + ) + self.assertAlmostEqual( + provider_extent.yMaximum(), subset_extent.yMaximum(), 3 + ) # with no points subset = self.getSubsetStringNoMatching() @@ -466,74 +599,147 @@ def testUnique(self): self.assertEqual(self.source.uniqueValues(-1), set()) self.assertEqual(self.source.uniqueValues(1000), set()) - self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('cnt'))), - {-200, 100, 200, 300, 400}) - assert {'Apple', 'Honey', 'Orange', 'Pear', NULL} == set( - self.source.uniqueValues(self.source.fields().lookupField('name'))), 'Got {}'.format( - set(self.source.uniqueValues(self.source.fields().lookupField('name')))) + self.assertEqual( + set(self.source.uniqueValues(self.source.fields().lookupField("cnt"))), + {-200, 100, 200, 300, 400}, + ) + assert {"Apple", "Honey", "Orange", "Pear", NULL} == set( + self.source.uniqueValues(self.source.fields().lookupField("name")) + ), "Got {}".format( + set(self.source.uniqueValues(self.source.fields().lookupField("name"))) + ) if self.treat_datetime_as_string(): - self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('dt'))), - {'2021-05-04 13:13:14', '2020-05-04 12:14:14', '2020-05-04 12:13:14', - '2020-05-03 12:13:14', NULL}) + self.assertEqual( + set(self.source.uniqueValues(self.source.fields().lookupField("dt"))), + { + "2021-05-04 13:13:14", + "2020-05-04 12:14:14", + "2020-05-04 12:13:14", + "2020-05-03 12:13:14", + NULL, + }, + ) else: if self.treat_datetime_tz_as_utc(): - self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('dt'))), - {QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14, 0), Qt.TimeSpec.UTC), QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14, 0), Qt.TimeSpec.UTC), - QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14, 0), Qt.TimeSpec.UTC), QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14, 0), Qt.TimeSpec.UTC), NULL}) + self.assertEqual( + set( + self.source.uniqueValues(self.source.fields().lookupField("dt")) + ), + { + QDateTime( + QDate(2021, 5, 4), QTime(13, 13, 14, 0), Qt.TimeSpec.UTC + ), + QDateTime( + QDate(2020, 5, 4), QTime(12, 14, 14, 0), Qt.TimeSpec.UTC + ), + QDateTime( + QDate(2020, 5, 4), QTime(12, 13, 14, 0), Qt.TimeSpec.UTC + ), + QDateTime( + QDate(2020, 5, 3), QTime(12, 13, 14, 0), Qt.TimeSpec.UTC + ), + NULL, + }, + ) else: - self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('dt'))), - {QDateTime(2021, 5, 4, 13, 13, 14), QDateTime(2020, 5, 4, 12, 14, 14), - QDateTime(2020, 5, 4, 12, 13, 14), QDateTime(2020, 5, 3, 12, 13, 14), NULL}) + self.assertEqual( + set( + self.source.uniqueValues(self.source.fields().lookupField("dt")) + ), + { + QDateTime(2021, 5, 4, 13, 13, 14), + QDateTime(2020, 5, 4, 12, 14, 14), + QDateTime(2020, 5, 4, 12, 13, 14), + QDateTime(2020, 5, 3, 12, 13, 14), + NULL, + }, + ) if self.treat_date_as_string(): - self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('date'))), - {'2020-05-03', '2020-05-04', '2021-05-04', '2020-05-02', NULL}) + self.assertEqual( + set(self.source.uniqueValues(self.source.fields().lookupField("date"))), + {"2020-05-03", "2020-05-04", "2021-05-04", "2020-05-02", NULL}, + ) elif self.treat_date_as_datetime(): - self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('date'))), - {QDateTime(2020, 5, 3, 0, 0, 0), QDateTime(2020, 5, 4, 0, 0, 0), - QDateTime(2021, 5, 4, 0, 0, 0), QDateTime(2020, 5, 2, 0, 0, 0), NULL}) + self.assertEqual( + set(self.source.uniqueValues(self.source.fields().lookupField("date"))), + { + QDateTime(2020, 5, 3, 0, 0, 0), + QDateTime(2020, 5, 4, 0, 0, 0), + QDateTime(2021, 5, 4, 0, 0, 0), + QDateTime(2020, 5, 2, 0, 0, 0), + NULL, + }, + ) else: - self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('date'))), - {QDate(2020, 5, 3), QDate(2020, 5, 4), QDate(2021, 5, 4), QDate(2020, 5, 2), NULL}) + self.assertEqual( + set(self.source.uniqueValues(self.source.fields().lookupField("date"))), + { + QDate(2020, 5, 3), + QDate(2020, 5, 4), + QDate(2021, 5, 4), + QDate(2020, 5, 2), + NULL, + }, + ) if self.treat_time_as_string(): - self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('time'))), - {'12:14:14', '13:13:14', '12:13:14', '12:13:01', NULL}) + self.assertEqual( + set(self.source.uniqueValues(self.source.fields().lookupField("time"))), + {"12:14:14", "13:13:14", "12:13:14", "12:13:01", NULL}, + ) else: - self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('time'))), - {QTime(12, 14, 14), QTime(13, 13, 14), QTime(12, 13, 14), QTime(12, 13, 1), NULL}) + self.assertEqual( + set(self.source.uniqueValues(self.source.fields().lookupField("time"))), + { + QTime(12, 14, 14), + QTime(13, 13, 14), + QTime(12, 13, 14), + QTime(12, 13, 1), + NULL, + }, + ) if self.source.supportsSubsetString(): subset = self.getSubsetString2() self.source.setSubsetString(subset) - values = self.source.uniqueValues(self.source.fields().lookupField('cnt')) + values = self.source.uniqueValues(self.source.fields().lookupField("cnt")) self.source.setSubsetString(None) self.assertEqual(set(values), {200, 300}) def testUniqueStringsMatching(self): - self.assertEqual(self.source.uniqueStringsMatching(-1, 'a'), []) - self.assertEqual(self.source.uniqueStringsMatching(100001, 'a'), []) - - field_index = self.source.fields().lookupField('name') - self.assertEqual(set(self.source.uniqueStringsMatching(field_index, 'a')), {'Pear', 'Orange', 'Apple'}) + self.assertEqual(self.source.uniqueStringsMatching(-1, "a"), []) + self.assertEqual(self.source.uniqueStringsMatching(100001, "a"), []) + + field_index = self.source.fields().lookupField("name") + self.assertEqual( + set(self.source.uniqueStringsMatching(field_index, "a")), + {"Pear", "Orange", "Apple"}, + ) # test case insensitive - self.assertEqual(set(self.source.uniqueStringsMatching(field_index, 'A')), {'Pear', 'Orange', 'Apple'}) + self.assertEqual( + set(self.source.uniqueStringsMatching(field_index, "A")), + {"Pear", "Orange", "Apple"}, + ) # test string ending in substring - self.assertEqual(set(self.source.uniqueStringsMatching(field_index, 'ney')), {'Honey'}) + self.assertEqual( + set(self.source.uniqueStringsMatching(field_index, "ney")), {"Honey"} + ) # test limit - result = set(self.source.uniqueStringsMatching(field_index, 'a', 2)) + result = set(self.source.uniqueStringsMatching(field_index, "a", 2)) self.assertEqual(len(result), 2) - self.assertTrue(result.issubset({'Pear', 'Orange', 'Apple'})) + self.assertTrue(result.issubset({"Pear", "Orange", "Apple"})) - assert {'Apple', 'Honey', 'Orange', 'Pear', NULL} == set( - self.source.uniqueValues(field_index)), f'Got {set(self.source.uniqueValues(field_index))}' + assert {"Apple", "Honey", "Orange", "Pear", NULL} == set( + self.source.uniqueValues(field_index) + ), f"Got {set(self.source.uniqueValues(field_index))}" if self.source.supportsSubsetString(): subset = self.getSubsetString2() self.source.setSubsetString(subset) - values = self.source.uniqueStringsMatching(field_index, 'a') + values = self.source.uniqueStringsMatching(field_index, "a") self.source.setSubsetString(None) - self.assertEqual(set(values), {'Pear', 'Apple'}) + self.assertEqual(set(values), {"Pear", "Apple"}) def testFeatureCount(self): self.assertEqual(self.source.featureCount(), 5) @@ -565,7 +771,10 @@ def testFeatureCount(self): def testEmpty(self): self.assertFalse(self.source.empty()) - self.assertEqual(self.source.hasFeatures(), QgsFeatureSource.FeatureAvailability.FeaturesAvailable) + self.assertEqual( + self.source.hasFeatures(), + QgsFeatureSource.FeatureAvailability.FeaturesAvailable, + ) if self.source.supportsSubsetString(): try: @@ -574,70 +783,128 @@ def testEmpty(self): subset = self.getSubsetString() self.source.setSubsetString(subset) self.assertFalse(self.source.empty()) - self.assertEqual(self.source.hasFeatures(), QgsFeatureSource.FeatureAvailability.FeaturesAvailable) + self.assertEqual( + self.source.hasFeatures(), + QgsFeatureSource.FeatureAvailability.FeaturesAvailable, + ) subsetNoMatching = self.getSubsetStringNoMatching() self.source.setSubsetString(subsetNoMatching) self.assertTrue(self.source.empty()) - self.assertEqual(self.source.hasFeatures(), QgsFeatureSource.FeatureAvailability.NoFeaturesAvailable) + self.assertEqual( + self.source.hasFeatures(), + QgsFeatureSource.FeatureAvailability.NoFeaturesAvailable, + ) finally: self.source.setSubsetString(None) self.assertFalse(self.source.empty()) # If the provider supports tests on editable layers - if getattr(self, 'getEditableLayer', None): + if getattr(self, "getEditableLayer", None): l = self.getEditableLayer() self.assertTrue(l.isValid()) - self.assertEqual(l.hasFeatures(), QgsFeatureSource.FeatureAvailability.FeaturesAvailable) + self.assertEqual( + l.hasFeatures(), QgsFeatureSource.FeatureAvailability.FeaturesAvailable + ) # Test that deleting some features in the edit buffer does not # return empty, we accept FeaturesAvailable as well as # MaybeAvailable l.startEditing() l.deleteFeature(next(l.getFeatures()).id()) - self.assertNotEqual(l.hasFeatures(), QgsFeatureSource.FeatureAvailability.NoFeaturesAvailable) + self.assertNotEqual( + l.hasFeatures(), + QgsFeatureSource.FeatureAvailability.NoFeaturesAvailable, + ) l.rollBack() # Call truncate(), we need an empty set now l.dataProvider().truncate() self.assertTrue(l.dataProvider().empty()) - self.assertEqual(l.dataProvider().hasFeatures(), QgsFeatureSource.FeatureAvailability.NoFeaturesAvailable) + self.assertEqual( + l.dataProvider().hasFeatures(), + QgsFeatureSource.FeatureAvailability.NoFeaturesAvailable, + ) def testGetFeaturesNoGeometry(self): - """ Test that no geometry is present when fetching features without geometry""" + """Test that no geometry is present when fetching features without geometry""" - for f in self.source.getFeatures(QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry)): - self.assertFalse(f.hasGeometry(), 'Expected no geometry, got one') + for f in self.source.getFeatures( + QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry) + ): + self.assertFalse(f.hasGeometry(), "Expected no geometry, got one") self.assertTrue(f.isValid()) def testAddFeature(self): - if not getattr(self, 'getEditableLayer', None): + if not getattr(self, "getEditableLayer", None): return l = self.getEditableLayer() self.assertTrue(l.isValid()) f1 = QgsFeature() - f1.setAttributes([6, -220, NULL, 'String', '15', - '2019-01-02 03:04:05' if self.treat_datetime_as_string() else QDateTime(2019, 1, 2, 3, 4, 5), - '2019-01-02' if self.treat_date_as_string() else QDateTime(2019, 1, 2, 0, 0, - 0) if self.treat_date_as_datetime() else QDate( - 2019, 1, 2), - '03:04:05' if self.treat_time_as_string() else QTime(3, 4, 5)]) - f1.setGeometry(QgsGeometry.fromWkt('Point (-72.345 71.987)')) + f1.setAttributes( + [ + 6, + -220, + NULL, + "String", + "15", + ( + "2019-01-02 03:04:05" + if self.treat_datetime_as_string() + else QDateTime(2019, 1, 2, 3, 4, 5) + ), + ( + "2019-01-02" + if self.treat_date_as_string() + else ( + QDateTime(2019, 1, 2, 0, 0, 0) + if self.treat_date_as_datetime() + else QDate(2019, 1, 2) + ) + ), + "03:04:05" if self.treat_time_as_string() else QTime(3, 4, 5), + ] + ) + f1.setGeometry(QgsGeometry.fromWkt("Point (-72.345 71.987)")) f2 = QgsFeature() - f2.setAttributes([7, 330, 'Coconut', 'CoCoNut', '13', - '2018-05-06 07:08:09' if self.treat_datetime_as_string() else QDateTime(2018, 5, 6, 7, 8, 9), - '2018-05-06' if self.treat_date_as_string() else QDateTime(2018, 5, 6, 0, 0, - 0) if self.treat_date_as_datetime() else QDate( - 2018, 5, 6), - '07:08:09' if self.treat_time_as_string() else QTime(7, 8, 9)]) - - if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures: + f2.setAttributes( + [ + 7, + 330, + "Coconut", + "CoCoNut", + "13", + ( + "2018-05-06 07:08:09" + if self.treat_datetime_as_string() + else QDateTime(2018, 5, 6, 7, 8, 9) + ), + ( + "2018-05-06" + if self.treat_date_as_string() + else ( + QDateTime(2018, 5, 6, 0, 0, 0) + if self.treat_date_as_datetime() + else QDate(2018, 5, 6) + ) + ), + "07:08:09" if self.treat_time_as_string() else QTime(7, 8, 9), + ] + ) + + if ( + l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.AddFeatures + ): # expect success result, added = l.dataProvider().addFeatures([f1, f2]) - self.assertTrue(result, 'Provider reported AddFeatures capability, but returned False to addFeatures') + self.assertTrue( + result, + "Provider reported AddFeatures capability, but returned False to addFeatures", + ) f1.setId(added[0].id()) f2.setId(added[1].id()) @@ -650,18 +917,20 @@ def testAddFeature(self): # ensure that returned features have been given the correct id f = next(l.getFeatures(QgsFeatureRequest().setFilterFid(added[0].id()))) self.assertTrue(f.isValid()) - self.assertEqual(f['cnt'], -220) + self.assertEqual(f["cnt"], -220) f = next(l.getFeatures(QgsFeatureRequest().setFilterFid(added[1].id()))) self.assertTrue(f.isValid()) - self.assertEqual(f['cnt'], 330) + self.assertEqual(f["cnt"], 330) else: # expect fail - self.assertFalse(l.dataProvider().addFeatures([f1, f2]), - 'Provider reported no AddFeatures capability, but returned true to addFeatures') + self.assertFalse( + l.dataProvider().addFeatures([f1, f2]), + "Provider reported no AddFeatures capability, but returned true to addFeatures", + ) def testAddFeatureFastInsert(self): - if not getattr(self, 'getEditableLayer', None): + if not getattr(self, "getEditableLayer", None): return l = self.getEditableLayer() @@ -669,109 +938,234 @@ def testAddFeatureFastInsert(self): f1 = QgsFeature() f1.setAttributes( - [6, -220, NULL, 'String', '15', - '2019-01-02 03:04:05' if self.treat_datetime_as_string() else QDateTime(2019, 1, 2, 3, 4, 5), - '2019-01-02' if self.treat_date_as_string() else QDateTime(2019, 1, 2, 0, 0, 0) if self.treat_date_as_datetime() else QDate(2019, 1, 2), - '03:04:05' if self.treat_time_as_string() else QTime(3, 4, 5)]) - f1.setGeometry(QgsGeometry.fromWkt('Point (-72.345 71.987)')) + [ + 6, + -220, + NULL, + "String", + "15", + ( + "2019-01-02 03:04:05" + if self.treat_datetime_as_string() + else QDateTime(2019, 1, 2, 3, 4, 5) + ), + ( + "2019-01-02" + if self.treat_date_as_string() + else ( + QDateTime(2019, 1, 2, 0, 0, 0) + if self.treat_date_as_datetime() + else QDate(2019, 1, 2) + ) + ), + "03:04:05" if self.treat_time_as_string() else QTime(3, 4, 5), + ] + ) + f1.setGeometry(QgsGeometry.fromWkt("Point (-72.345 71.987)")) f2 = QgsFeature() - f2.setAttributes([7, 330, 'Coconut', 'CoCoNut', '13', - '2019-01-02 03:04:05' if self.treat_datetime_as_string() else QDateTime(2019, 1, 2, 3, 4, 5), - '2019-01-02' if self.treat_date_as_string() else QDateTime(2019, 1, 2, 0, 0, 0) if self.treat_date_as_datetime() else QDate(2019, 1, 2), - '03:04:05' if self.treat_time_as_string() else QTime(3, 4, 5)]) - - if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures: + f2.setAttributes( + [ + 7, + 330, + "Coconut", + "CoCoNut", + "13", + ( + "2019-01-02 03:04:05" + if self.treat_datetime_as_string() + else QDateTime(2019, 1, 2, 3, 4, 5) + ), + ( + "2019-01-02" + if self.treat_date_as_string() + else ( + QDateTime(2019, 1, 2, 0, 0, 0) + if self.treat_date_as_datetime() + else QDate(2019, 1, 2) + ) + ), + "03:04:05" if self.treat_time_as_string() else QTime(3, 4, 5), + ] + ) + + if ( + l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.AddFeatures + ): # expect success - result, added = l.dataProvider().addFeatures([f1, f2], QgsFeatureSink.Flag.FastInsert) - self.assertTrue(result, 'Provider reported AddFeatures capability, but returned False to addFeatures') + result, added = l.dataProvider().addFeatures( + [f1, f2], QgsFeatureSink.Flag.FastInsert + ) + self.assertTrue( + result, + "Provider reported AddFeatures capability, but returned False to addFeatures", + ) self.assertEqual(l.dataProvider().featureCount(), 7) def testAddFeatureMissingAttributes(self): - if not getattr(self, 'getEditableLayer', None): + if not getattr(self, "getEditableLayer", None): return l = self.getEditableLayer() self.assertTrue(l.isValid()) - if not l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures: + if ( + not l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.AddFeatures + ): return # test that adding features with missing attributes pads out these # attributes with NULL values to the correct length f1 = QgsFeature() - f1.setAttributes([6, -220, NULL, 'String']) + f1.setAttributes([6, -220, NULL, "String"]) f2 = QgsFeature() f2.setAttributes([7, 330]) result, added = l.dataProvider().addFeatures([f1, f2]) - self.assertTrue(result, - 'Provider returned False to addFeatures with missing attributes. Providers should accept these features but add NULL attributes to the end of the existing attributes to the required field length.') + self.assertTrue( + result, + "Provider returned False to addFeatures with missing attributes. Providers should accept these features but add NULL attributes to the end of the existing attributes to the required field length.", + ) f1.setId(added[0].id()) f2.setId(added[1].id()) # check result - feature attributes MUST be padded out to required number of fields - f1.setAttributes([6, -220, NULL, 'String', 'NULL', NULL, NULL, NULL]) - f2.setAttributes([7, 330, NULL, NULL, 'NULL', NULL, NULL, NULL]) + f1.setAttributes([6, -220, NULL, "String", "NULL", NULL, NULL, NULL]) + f2.setAttributes([7, 330, NULL, NULL, "NULL", NULL, NULL, NULL]) self.testGetFeatures(l.dataProvider(), [f1, f2]) def testAddFeatureExtraAttributes(self): - if not getattr(self, 'getEditableLayer', None): + if not getattr(self, "getEditableLayer", None): return l = self.getEditableLayer() self.assertTrue(l.isValid()) - if not l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures: + if ( + not l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.AddFeatures + ): return # test that adding features with too many attributes drops these attributes # we be more tricky and also add a valid feature to stress test the provider f1 = QgsFeature() - f1.setAttributes([6, -220, NULL, 'String', '15', - '2019-01-02 03:04:05' if self.treat_datetime_as_string() else QDateTime(2019, 1, 2, 3, 4, 5), - '2019-01-02' if self.treat_date_as_string() else QDateTime(2019, 1, 2, 0, 0, 0) if self.treat_date_as_datetime() else QDate(2019, 1, 2), - '03:04:05' if self.treat_time_as_string() else QTime(3, 4, 5)]) + f1.setAttributes( + [ + 6, + -220, + NULL, + "String", + "15", + ( + "2019-01-02 03:04:05" + if self.treat_datetime_as_string() + else QDateTime(2019, 1, 2, 3, 4, 5) + ), + ( + "2019-01-02" + if self.treat_date_as_string() + else ( + QDateTime(2019, 1, 2, 0, 0, 0) + if self.treat_date_as_datetime() + else QDate(2019, 1, 2) + ) + ), + "03:04:05" if self.treat_time_as_string() else QTime(3, 4, 5), + ] + ) f2 = QgsFeature() - f2.setAttributes([7, -230, NULL, 'String', '15', - '2019-01-02 03:04:05' if self.treat_datetime_as_string() else QDateTime(2019, 1, 2, 3, 4, 5), - '2019-01-02' if self.treat_date_as_string() else QDateTime(2019, 1, 2, 0, 0, 0) if self.treat_date_as_datetime() else QDate(2019, 1, 2), - '03:04:05' if self.treat_time_as_string() else QTime(3, 4, 5), 15, 16, 17]) + f2.setAttributes( + [ + 7, + -230, + NULL, + "String", + "15", + ( + "2019-01-02 03:04:05" + if self.treat_datetime_as_string() + else QDateTime(2019, 1, 2, 3, 4, 5) + ), + ( + "2019-01-02" + if self.treat_date_as_string() + else ( + QDateTime(2019, 1, 2, 0, 0, 0) + if self.treat_date_as_datetime() + else QDate(2019, 1, 2) + ) + ), + "03:04:05" if self.treat_time_as_string() else QTime(3, 4, 5), + 15, + 16, + 17, + ] + ) result, added = l.dataProvider().addFeatures([f1, f2]) - self.assertTrue(result, - 'Provider returned False to addFeatures with extra attributes. Providers should accept these features but truncate the extra attributes.') + self.assertTrue( + result, + "Provider returned False to addFeatures with extra attributes. Providers should accept these features but truncate the extra attributes.", + ) # make sure feature was added correctly added = [f for f in l.dataProvider().getFeatures() if f[self.pk_name] == 7][0] - self.assertEqual(added.attributes(), [7, -230, NULL, 'String', '15', - '2019-01-02 03:04:05' if self.treat_datetime_as_string() else QDateTime( - 2019, 1, 2, 3, 4, 5), - '2019-01-02' if self.treat_date_as_string() else QDateTime(2019, 1, 2, 0, 0, 0) if self.treat_date_as_datetime() else QDate(2019, 1, 2), - '03:04:05' if self.treat_time_as_string() else QTime(3, 4, 5)]) + self.assertEqual( + added.attributes(), + [ + 7, + -230, + NULL, + "String", + "15", + ( + "2019-01-02 03:04:05" + if self.treat_datetime_as_string() + else QDateTime(2019, 1, 2, 3, 4, 5) + ), + ( + "2019-01-02" + if self.treat_date_as_string() + else ( + QDateTime(2019, 1, 2, 0, 0, 0) + if self.treat_date_as_datetime() + else QDate(2019, 1, 2) + ) + ), + "03:04:05" if self.treat_time_as_string() else QTime(3, 4, 5), + ], + ) def testAddFeatureWrongGeomType(self): - if not getattr(self, 'getEditableLayer', None): + if not getattr(self, "getEditableLayer", None): return l = self.getEditableLayer() self.assertTrue(l.isValid()) - if not l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures: + if ( + not l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.AddFeatures + ): return # test that adding features with incorrect geometry type rejects the feature # we be more tricky and also add a valid feature to stress test the provider f1 = QgsFeature() - f1.setGeometry(QgsGeometry.fromWkt('LineString (-72.345 71.987, -80 80)')) + f1.setGeometry(QgsGeometry.fromWkt("LineString (-72.345 71.987, -80 80)")) f1.setAttributes([7]) f2 = QgsFeature() - f2.setGeometry(QgsGeometry.fromWkt('Point (-72.345 71.987)')) + f2.setGeometry(QgsGeometry.fromWkt("Point (-72.345 71.987)")) f2.setAttributes([8]) result, added = l.dataProvider().addFeatures([f1, f2]) - self.assertFalse(result, - 'Provider returned True to addFeatures with incorrect geometry type. Providers should reject these features.') + self.assertFalse( + result, + "Provider returned True to addFeatures with incorrect geometry type. Providers should reject these features.", + ) # make sure feature was not added added = [f for f in l.dataProvider().getFeatures() if f[self.pk_name] == 7] @@ -781,33 +1175,42 @@ def testAddFeatureWrongGeomType(self): f3 = QgsFeature() f3.setAttributes([9]) result, added = l.dataProvider().addFeatures([f3]) - self.assertTrue(result, - 'Provider returned False to addFeatures with null geometry. Providers should always accept these features.') + self.assertTrue( + result, + "Provider returned False to addFeatures with null geometry. Providers should always accept these features.", + ) # make sure feature was added correctly added = [f for f in l.dataProvider().getFeatures() if f[self.pk_name] == 9][0] self.assertFalse(added.hasGeometry()) def testAddFeaturesUpdateExtent(self): - if not getattr(self, 'getEditableLayer', None): + if not getattr(self, "getEditableLayer", None): return l = self.getEditableLayer() self.assertTrue(l.isValid()) - self.assertEqual(l.dataProvider().extent().toString(1), '-71.1,66.3 : -65.3,78.3') + self.assertEqual( + l.dataProvider().extent().toString(1), "-71.1,66.3 : -65.3,78.3" + ) - if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures: + if ( + l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.AddFeatures + ): f1 = QgsFeature() - f1.setAttributes([6, -220, NULL, 'String', '15']) - f1.setGeometry(QgsGeometry.fromWkt('Point (-50 90)')) + f1.setAttributes([6, -220, NULL, "String", "15"]) + f1.setGeometry(QgsGeometry.fromWkt("Point (-50 90)")) l.dataProvider().addFeatures([f1]) l.dataProvider().updateExtents() - self.assertEqual(l.dataProvider().extent().toString(1), '-71.1,66.3 : -50.0,90.0') + self.assertEqual( + l.dataProvider().extent().toString(1), "-71.1,66.3 : -50.0,90.0" + ) def testDeleteFeatures(self): - if not getattr(self, 'getEditableLayer', None): + if not getattr(self, "getEditableLayer", None): return l = self.getEditableLayer() @@ -817,10 +1220,16 @@ def testDeleteFeatures(self): features = [f for f in l.dataProvider().getFeatures()] to_delete = [f.id() for f in features if f.attributes()[0] in [1, 3]] - if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.DeleteFeatures: + if ( + l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.DeleteFeatures + ): # expect success result = l.dataProvider().deleteFeatures(to_delete) - self.assertTrue(result, 'Provider reported DeleteFeatures capability, but returned False to deleteFeatures') + self.assertTrue( + result, + "Provider reported DeleteFeatures capability, but returned False to deleteFeatures", + ) # check result self.testGetFeatures(l.dataProvider(), skip_features=[1, 3]) @@ -830,28 +1239,41 @@ def testDeleteFeatures(self): else: # expect fail - self.assertFalse(l.dataProvider().deleteFeatures(to_delete), - 'Provider reported no DeleteFeatures capability, but returned true to deleteFeatures') + self.assertFalse( + l.dataProvider().deleteFeatures(to_delete), + "Provider reported no DeleteFeatures capability, but returned true to deleteFeatures", + ) def testDeleteFeaturesUpdateExtent(self): - if not getattr(self, 'getEditableLayer', None): + if not getattr(self, "getEditableLayer", None): return l = self.getEditableLayer() self.assertTrue(l.isValid()) - self.assertEqual(l.dataProvider().extent().toString(1), '-71.1,66.3 : -65.3,78.3') + self.assertEqual( + l.dataProvider().extent().toString(1), "-71.1,66.3 : -65.3,78.3" + ) - to_delete = [f.id() for f in l.dataProvider().getFeatures() if f.attributes()[0] in [5, 4]] + to_delete = [ + f.id() + for f in l.dataProvider().getFeatures() + if f.attributes()[0] in [5, 4] + ] - if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.DeleteFeatures: + if ( + l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.DeleteFeatures + ): l.dataProvider().deleteFeatures(to_delete) l.dataProvider().updateExtents() - self.assertEqual(l.dataProvider().extent().toString(1), '-70.3,66.3 : -68.2,70.8') + self.assertEqual( + l.dataProvider().extent().toString(1), "-70.3,66.3 : -68.2,70.8" + ) def testTruncate(self): - if not getattr(self, 'getEditableLayer', None): + if not getattr(self, "getEditableLayer", None): return l = self.getEditableLayer() @@ -859,22 +1281,31 @@ def testTruncate(self): features = [f[self.pk_name] for f in l.dataProvider().getFeatures()] - if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.FastTruncate or l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.DeleteFeatures: + if ( + l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.FastTruncate + or l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.DeleteFeatures + ): # expect success result = l.dataProvider().truncate() - self.assertTrue(result, - 'Provider reported FastTruncate or DeleteFeatures capability, but returned False to truncate()') + self.assertTrue( + result, + "Provider reported FastTruncate or DeleteFeatures capability, but returned False to truncate()", + ) # check result features = [f[self.pk_name] for f in l.dataProvider().getFeatures()] self.assertEqual(len(features), 0) else: # expect fail - self.assertFalse(l.dataProvider().truncate(), - 'Provider reported no FastTruncate or DeleteFeatures capability, but returned true to truncate()') + self.assertFalse( + l.dataProvider().truncate(), + "Provider reported no FastTruncate or DeleteFeatures capability, but returned true to truncate()", + ) def testChangeAttributes(self): - if not getattr(self, 'getEditableLayer', None): + if not getattr(self, "getEditableLayer", None): return l = self.getEditableLayer() @@ -886,15 +1317,23 @@ def testChangeAttributes(self): to_change = [f for f in features if f.attributes()[0] == 1] to_change.extend([f for f in features if f.attributes()[0] == 3]) # changes by feature id, for changeAttributeValues call - changes = {to_change[0].id(): {1: 501, 3: 'new string'}, to_change[1].id(): {1: 502, 4: 'NEW'}} + changes = { + to_change[0].id(): {1: 501, 3: "new string"}, + to_change[1].id(): {1: 502, 4: "NEW"}, + } # changes by pk, for testing after retrieving changed features - new_attr_map = {1: {1: 501, 3: 'new string'}, 3: {1: 502, 4: 'NEW'}} + new_attr_map = {1: {1: 501, 3: "new string"}, 3: {1: 502, 4: "NEW"}} - if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.ChangeAttributeValues: + if ( + l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.ChangeAttributeValues + ): # expect success result = l.dataProvider().changeAttributeValues(changes) - self.assertTrue(result, - 'Provider reported ChangeAttributeValues capability, but returned False to changeAttributeValues') + self.assertTrue( + result, + "Provider reported ChangeAttributeValues capability, but returned False to changeAttributeValues", + ) # check result self.testGetFeatures(l.dataProvider(), changed_attributes=new_attr_map) @@ -904,8 +1343,10 @@ def testChangeAttributes(self): else: # expect fail - self.assertFalse(l.dataProvider().changeAttributeValues(changes), - 'Provider reported no ChangeAttributeValues capability, but returned true to changeAttributeValues') + self.assertFalse( + l.dataProvider().changeAttributeValues(changes), + "Provider reported no ChangeAttributeValues capability, but returned true to changeAttributeValues", + ) def testChangeAttributesConstraintViolation(self): """Checks that changing attributes violating a DB-level CHECK constraint returns false @@ -914,30 +1355,35 @@ def testChangeAttributesConstraintViolation(self): The layer must contain at least 2 features, that will be used to test the attribute change. """ - if not getattr(self, 'getEditableLayerWithCheckConstraint', None): + if not getattr(self, "getEditableLayerWithCheckConstraint", None): return l = self.getEditableLayerWithCheckConstraint() self.assertTrue(l.isValid()) - assert l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.ChangeAttributeValues + assert ( + l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.ChangeAttributeValues + ) # find the featurea to change feature0 = [f for f in l.dataProvider().getFeatures()][0] feature1 = [f for f in l.dataProvider().getFeatures()][1] - field_idx = l.fields().indexFromName('i_will_fail_on_no_name') + field_idx = l.fields().indexFromName("i_will_fail_on_no_name") self.assertGreaterEqual(field_idx, 0) # changes by feature id, for changeAttributeValues call changes = { - feature0.id(): {field_idx: 'no name'}, - feature1.id(): {field_idx: 'I have a valid name'} + feature0.id(): {field_idx: "no name"}, + feature1.id(): {field_idx: "I have a valid name"}, } # expect failure result = l.dataProvider().changeAttributeValues(changes) self.assertFalse( - result, 'Provider reported success when changing an attribute value that violates a DB level CHECK constraint') + result, + "Provider reported success when changing an attribute value that violates a DB level CHECK constraint", + ) - if getattr(self, 'stopEditableLayerWithCheckConstraint', None): + if getattr(self, "stopEditableLayerWithCheckConstraint", None): self.stopEditableLayerWithCheckConstraint() def testUniqueNotNullConstraints(self): @@ -950,25 +1396,45 @@ def testUniqueNotNullConstraints(self): """ - if not getattr(self, 'getEditableLayerWithUniqueNotNullConstraints', None): + if not getattr(self, "getEditableLayerWithUniqueNotNullConstraints", None): return vl = self.getEditableLayerWithUniqueNotNullConstraints() self.assertTrue(vl.isValid()) - unique_field_idx = vl.fields().indexFromName('unique') - not_null_field_idx = vl.fields().indexFromName('not_null') + unique_field_idx = vl.fields().indexFromName("unique") + not_null_field_idx = vl.fields().indexFromName("not_null") self.assertGreater(unique_field_idx, 0) self.assertGreater(not_null_field_idx, 0) # Not null - self.assertFalse(bool(vl.fieldConstraints(unique_field_idx) & QgsFieldConstraints.Constraint.ConstraintNotNull)) - self.assertTrue(bool(vl.fieldConstraints(not_null_field_idx) & QgsFieldConstraints.Constraint.ConstraintNotNull)) + self.assertFalse( + bool( + vl.fieldConstraints(unique_field_idx) + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + ) + self.assertTrue( + bool( + vl.fieldConstraints(not_null_field_idx) + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + ) # Unique - self.assertTrue(bool(vl.fieldConstraints(unique_field_idx) & QgsFieldConstraints.Constraint.ConstraintUnique)) - self.assertFalse(bool(vl.fieldConstraints(not_null_field_idx) & QgsFieldConstraints.Constraint.ConstraintUnique)) + self.assertTrue( + bool( + vl.fieldConstraints(unique_field_idx) + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + ) + self.assertFalse( + bool( + vl.fieldConstraints(not_null_field_idx) + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + ) def testChangeGeometries(self): - if not getattr(self, 'getEditableLayer', None): + if not getattr(self, "getEditableLayer", None): return l = self.getEditableLayer() @@ -979,15 +1445,23 @@ def testChangeGeometries(self): to_change = [f for f in features if f.attributes()[0] == 1] to_change.extend([f for f in features if f.attributes()[0] == 3]) # changes by feature id, for changeGeometryValues call - changes = {to_change[0].id(): QgsGeometry.fromWkt('Point (10 20)'), to_change[1].id(): QgsGeometry()} + changes = { + to_change[0].id(): QgsGeometry.fromWkt("Point (10 20)"), + to_change[1].id(): QgsGeometry(), + } # changes by pk, for testing after retrieving changed features - new_geom_map = {1: QgsGeometry.fromWkt('Point ( 10 20 )'), 3: QgsGeometry()} + new_geom_map = {1: QgsGeometry.fromWkt("Point ( 10 20 )"), 3: QgsGeometry()} - if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.ChangeGeometries: + if ( + l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.ChangeGeometries + ): # expect success result = l.dataProvider().changeGeometryValues(changes) - self.assertTrue(result, - 'Provider reported ChangeGeometries capability, but returned False to changeGeometryValues') + self.assertTrue( + result, + "Provider reported ChangeGeometries capability, but returned False to changeGeometryValues", + ) # check result self.testGetFeatures(l.dataProvider(), changed_geometries=new_geom_map) @@ -997,11 +1471,13 @@ def testChangeGeometries(self): else: # expect fail - self.assertFalse(l.dataProvider().changeGeometryValues(changes), - 'Provider reported no ChangeGeometries capability, but returned true to changeGeometryValues') + self.assertFalse( + l.dataProvider().changeGeometryValues(changes), + "Provider reported no ChangeGeometries capability, but returned true to changeGeometryValues", + ) def testChangeFeatures(self): - if not getattr(self, 'getEditableLayer', None): + if not getattr(self, "getEditableLayer", None): return l = self.getEditableLayer() @@ -1015,44 +1491,73 @@ def testChangeFeatures(self): to_change = [f for f in features if f.attributes()[0] == 1] to_change.extend([f for f in features if f.attributes()[0] == 2]) # changes by feature id, for changeAttributeValues call - attribute_changes = {to_change[0].id(): {1: 501, 3: 'new string'}, to_change[1].id(): {1: 502, 4: 'NEW'}} + attribute_changes = { + to_change[0].id(): {1: 501, 3: "new string"}, + to_change[1].id(): {1: 502, 4: "NEW"}, + } # changes by pk, for testing after retrieving changed features - new_attr_map = {1: {1: 501, 3: 'new string'}, 2: {1: 502, 4: 'NEW'}} + new_attr_map = {1: {1: 501, 3: "new string"}, 2: {1: 502, 4: "NEW"}} # find 2 features to change geometries for to_change = [f for f in features if f.attributes()[0] == 1] to_change.extend([f for f in features if f.attributes()[0] == 3]) # changes by feature id, for changeGeometryValues call - geometry_changes = {to_change[0].id(): QgsGeometry.fromWkt('Point (10 20)'), to_change[1].id(): QgsGeometry()} + geometry_changes = { + to_change[0].id(): QgsGeometry.fromWkt("Point (10 20)"), + to_change[1].id(): QgsGeometry(), + } # changes by pk, for testing after retrieving changed features - new_geom_map = {1: QgsGeometry.fromWkt('Point ( 10 20 )'), 3: QgsGeometry()} - - if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.ChangeGeometries and l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.ChangeAttributeValues: + new_geom_map = {1: QgsGeometry.fromWkt("Point ( 10 20 )"), 3: QgsGeometry()} + + if ( + l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.ChangeGeometries + and l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.ChangeAttributeValues + ): # expect success - result = l.dataProvider().changeFeatures(attribute_changes, geometry_changes) - self.assertTrue(result, - 'Provider reported ChangeGeometries and ChangeAttributeValues capability, but returned False to changeFeatures') + result = l.dataProvider().changeFeatures( + attribute_changes, geometry_changes + ) + self.assertTrue( + result, + "Provider reported ChangeGeometries and ChangeAttributeValues capability, but returned False to changeFeatures", + ) # check result - self.testGetFeatures(l.dataProvider(), changed_attributes=new_attr_map, changed_geometries=new_geom_map) + self.testGetFeatures( + l.dataProvider(), + changed_attributes=new_attr_map, + changed_geometries=new_geom_map, + ) # change empty list, should return true for consistency self.assertTrue(l.dataProvider().changeFeatures({}, {})) - elif not l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.ChangeGeometries: + elif ( + not l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.ChangeGeometries + ): # expect fail - self.assertFalse(l.dataProvider().changeFeatures(attribute_changes, geometry_changes), - 'Provider reported no ChangeGeometries capability, but returned true to changeFeatures') - elif not l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.ChangeAttributeValues: + self.assertFalse( + l.dataProvider().changeFeatures(attribute_changes, geometry_changes), + "Provider reported no ChangeGeometries capability, but returned true to changeFeatures", + ) + elif ( + not l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.ChangeAttributeValues + ): # expect fail - self.assertFalse(l.dataProvider().changeFeatures(attribute_changes, geometry_changes), - 'Provider reported no ChangeAttributeValues capability, but returned true to changeFeatures') + self.assertFalse( + l.dataProvider().changeFeatures(attribute_changes, geometry_changes), + "Provider reported no ChangeAttributeValues capability, but returned true to changeFeatures", + ) def testMinMaxAfterChanges(self): """ Tests retrieving field min and max value after making changes to the provider's features """ - if not getattr(self, 'getEditableLayer', None): + if not getattr(self, "getEditableLayer", None): return vl = self.getEditableLayer() @@ -1082,7 +1587,11 @@ def testMinMaxAfterChanges(self): self.assertEqual(vl.dataProvider().maximumValue(1), 1400) # change attribute values - self.assertTrue(vl.dataProvider().changeAttributeValues({f6.id(): {1: 150}, f7.id(): {1: -100}})) + self.assertTrue( + vl.dataProvider().changeAttributeValues( + {f6.id(): {1: 150}, f7.id(): {1: -100}} + ) + ) self.assertEqual(vl.dataProvider().minimumValue(1), -200) self.assertEqual(vl.dataProvider().maximumValue(1), 400) @@ -1095,7 +1604,10 @@ def testMinMaxAfterChanges(self): self.assertEqual(vl.dataProvider().maximumValue(0), 5) self.assertEqual(vl.dataProvider().maximumValue(1), 400) - if vl.dataProvider().capabilities() & QgsVectorDataProvider.Capability.DeleteAttributes: + if ( + vl.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.DeleteAttributes + ): # delete attributes if vl.dataProvider().deleteAttributes([0]): # may not be possible, e.g. if it's a primary key @@ -1108,17 +1620,30 @@ def testStringComparison(self): compiler (or work fine without doing anything :P) """ for expression in ( - '5 LIKE \'5\'', - '5 ILIKE \'5\'', - '15 NOT LIKE \'5\'', - '15 NOT ILIKE \'5\'', - '5 ~ \'5\''): - iterator = self.source.getFeatures(QgsFeatureRequest().setFilterExpression('5 LIKE \'5\'').setFlags(QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation)) + "5 LIKE '5'", + "5 ILIKE '5'", + "15 NOT LIKE '5'", + "15 NOT ILIKE '5'", + "5 ~ '5'", + ): + iterator = self.source.getFeatures( + QgsFeatureRequest() + .setFilterExpression("5 LIKE '5'") + .setFlags( + QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation + ) + ) count = len([f for f in iterator]) self.assertEqual(count, 5) self.assertFalse(iterator.compileFailed()) if self.enableCompiler(): - iterator = self.source.getFeatures(QgsFeatureRequest().setFilterExpression('5 LIKE \'5\'').setFlags(QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation)) + iterator = self.source.getFeatures( + QgsFeatureRequest() + .setFilterExpression("5 LIKE '5'") + .setFlags( + QgsFeatureRequest.Flag.IgnoreStaticNodesDuringExpressionCompilation + ) + ) self.assertEqual(count, 5) self.assertFalse(iterator.compileFailed()) self.disableCompiler() @@ -1142,7 +1667,7 @@ def testConcurrency(self): feat = next(iterators[0]) context = QgsExpressionContext() context.setFeature(feat) - exp = QgsExpression(f'get_feature(\'{self.vl.id()}\', \'pk\', 5)') + exp = QgsExpression(f"get_feature('{self.vl.id()}', 'pk', 5)") exp.evaluate(context) def testEmptySubsetOfAttributesWithSubsetString(self): @@ -1173,7 +1698,7 @@ def testEmptySubsetOfAttributesWithSubsetString(self): def testGeneratedColumns(self): - if not getattr(self, 'getGeneratedColumnsData', None): + if not getattr(self, "getGeneratedColumnsData", None): return vl, generated_value = self.getGeneratedColumnsData() @@ -1236,7 +1761,9 @@ def testGeneratedColumns(self): # Test insertion with default value evaluation on provider side to be sure # it doesn't fail generated columns - vl.dataProvider().setProviderProperty(QgsDataProvider.ProviderProperty.EvaluateDefaultValues, True) + vl.dataProvider().setProviderProperty( + QgsDataProvider.ProviderProperty.EvaluateDefaultValues, True + ) vl.startEditing() feature = QgsVectorLayerUtils.createFeature(vl, QgsGeometry(), {0: 8}) diff --git a/tests/src/python/qgis_interface.py b/tests/src/python/qgis_interface.py index 7faf63c873c8..f2127789fae1 100644 --- a/tests/src/python/qgis_interface.py +++ b/tests/src/python/qgis_interface.py @@ -16,12 +16,14 @@ """ -__author__ = 'tim@linfiniti.com' -__version__ = '0.5.0' -__date__ = '10/01/2011' -__copyright__ = ('Copyright (c) 2010 by Ivan Mincik, ivan.mincik@gista.sk and ' - 'Copyright (c) 2011 German Carrillo, ' - 'geotux_tuxman@linuxmail.org') +__author__ = "tim@linfiniti.com" +__version__ = "0.5.0" +__date__ = "10/01/2011" +__copyright__ = ( + "Copyright (c) 2010 by Ivan Mincik, ivan.mincik@gista.sk and " + "Copyright (c) 2011 German Carrillo, " + "geotux_tuxman@linuxmail.org" +) from qgis.PyQt.QtCore import QObject from qgis.core import QgsProject @@ -93,5 +95,5 @@ def mainWindow(self): pass def addDockWidget(self, area, dockwidget): - """ Add a dock widget to the main window """ + """Add a dock widget to the main window""" pass diff --git a/tests/src/python/qgis_wrapped_server.py b/tests/src/python/qgis_wrapped_server.py index 8cd0c2ecab21..7483d815348c 100644 --- a/tests/src/python/qgis_wrapped_server.py +++ b/tests/src/python/qgis_wrapped_server.py @@ -116,13 +116,13 @@ import os -__author__ = 'Alessandro Pasotti' -__date__ = '05/15/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "05/15/2016" +__copyright__ = "Copyright 2016, The QGIS Project" # Needed on Qt 5 so that the serialization of XML is consistent among all # executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" import copy import math @@ -143,52 +143,52 @@ QgsServerRequest, ) -QGIS_SERVER_PORT = int(os.environ.get('QGIS_SERVER_PORT', '8081')) -QGIS_SERVER_HOST = os.environ.get('QGIS_SERVER_HOST', '127.0.0.1') +QGIS_SERVER_PORT = int(os.environ.get("QGIS_SERVER_PORT", "8081")) +QGIS_SERVER_HOST = os.environ.get("QGIS_SERVER_HOST", "127.0.0.1") # HTTP Basic -QGIS_SERVER_HTTP_BASIC_AUTH = os.environ.get( - 'QGIS_SERVER_HTTP_BASIC_AUTH', False) -QGIS_SERVER_USERNAME = os.environ.get('QGIS_SERVER_USERNAME', 'username') -QGIS_SERVER_PASSWORD = os.environ.get('QGIS_SERVER_PASSWORD', 'password') +QGIS_SERVER_HTTP_BASIC_AUTH = os.environ.get("QGIS_SERVER_HTTP_BASIC_AUTH", False) +QGIS_SERVER_USERNAME = os.environ.get("QGIS_SERVER_USERNAME", "username") +QGIS_SERVER_PASSWORD = os.environ.get("QGIS_SERVER_PASSWORD", "password") # PKI authentication -QGIS_SERVER_PKI_CERTIFICATE = os.environ.get('QGIS_SERVER_PKI_CERTIFICATE') -QGIS_SERVER_PKI_KEY = os.environ.get('QGIS_SERVER_PKI_KEY') -QGIS_SERVER_PKI_AUTHORITY = os.environ.get('QGIS_SERVER_PKI_AUTHORITY') -QGIS_SERVER_PKI_USERNAME = os.environ.get('QGIS_SERVER_PKI_USERNAME') +QGIS_SERVER_PKI_CERTIFICATE = os.environ.get("QGIS_SERVER_PKI_CERTIFICATE") +QGIS_SERVER_PKI_KEY = os.environ.get("QGIS_SERVER_PKI_KEY") +QGIS_SERVER_PKI_AUTHORITY = os.environ.get("QGIS_SERVER_PKI_AUTHORITY") +QGIS_SERVER_PKI_USERNAME = os.environ.get("QGIS_SERVER_PKI_USERNAME") # OAuth2 authentication -QGIS_SERVER_OAUTH2_CERTIFICATE = os.environ.get( - 'QGIS_SERVER_OAUTH2_CERTIFICATE') -QGIS_SERVER_OAUTH2_KEY = os.environ.get('QGIS_SERVER_OAUTH2_KEY') -QGIS_SERVER_OAUTH2_AUTHORITY = os.environ.get('QGIS_SERVER_OAUTH2_AUTHORITY') -QGIS_SERVER_OAUTH2_USERNAME = os.environ.get( - 'QGIS_SERVER_OAUTH2_USERNAME', 'username') -QGIS_SERVER_OAUTH2_PASSWORD = os.environ.get( - 'QGIS_SERVER_OAUTH2_PASSWORD', 'password') +QGIS_SERVER_OAUTH2_CERTIFICATE = os.environ.get("QGIS_SERVER_OAUTH2_CERTIFICATE") +QGIS_SERVER_OAUTH2_KEY = os.environ.get("QGIS_SERVER_OAUTH2_KEY") +QGIS_SERVER_OAUTH2_AUTHORITY = os.environ.get("QGIS_SERVER_OAUTH2_AUTHORITY") +QGIS_SERVER_OAUTH2_USERNAME = os.environ.get("QGIS_SERVER_OAUTH2_USERNAME", "username") +QGIS_SERVER_OAUTH2_PASSWORD = os.environ.get("QGIS_SERVER_OAUTH2_PASSWORD", "password") QGIS_SERVER_OAUTH2_TOKEN_EXPIRES_IN = os.environ.get( - 'QGIS_SERVER_OAUTH2_TOKEN_EXPIRES_IN', 3600) + "QGIS_SERVER_OAUTH2_TOKEN_EXPIRES_IN", 3600 +) # Check if PKI is enabled QGIS_SERVER_PKI_AUTH = ( - QGIS_SERVER_PKI_CERTIFICATE is not None and - os.path.isfile(QGIS_SERVER_PKI_CERTIFICATE) and - QGIS_SERVER_PKI_KEY is not None and - os.path.isfile(QGIS_SERVER_PKI_KEY) and - QGIS_SERVER_PKI_AUTHORITY is not None and - os.path.isfile(QGIS_SERVER_PKI_AUTHORITY) and - QGIS_SERVER_PKI_USERNAME) + QGIS_SERVER_PKI_CERTIFICATE is not None + and os.path.isfile(QGIS_SERVER_PKI_CERTIFICATE) + and QGIS_SERVER_PKI_KEY is not None + and os.path.isfile(QGIS_SERVER_PKI_KEY) + and QGIS_SERVER_PKI_AUTHORITY is not None + and os.path.isfile(QGIS_SERVER_PKI_AUTHORITY) + and QGIS_SERVER_PKI_USERNAME +) # Check if OAuth2 is enabled QGIS_SERVER_OAUTH2_AUTH = ( - QGIS_SERVER_OAUTH2_CERTIFICATE is not None and - os.path.isfile(QGIS_SERVER_OAUTH2_CERTIFICATE) and - QGIS_SERVER_OAUTH2_KEY is not None and - os.path.isfile(QGIS_SERVER_OAUTH2_KEY) and - QGIS_SERVER_OAUTH2_AUTHORITY is not None and - os.path.isfile(QGIS_SERVER_OAUTH2_AUTHORITY) and - QGIS_SERVER_OAUTH2_USERNAME and QGIS_SERVER_OAUTH2_PASSWORD) + QGIS_SERVER_OAUTH2_CERTIFICATE is not None + and os.path.isfile(QGIS_SERVER_OAUTH2_CERTIFICATE) + and QGIS_SERVER_OAUTH2_KEY is not None + and os.path.isfile(QGIS_SERVER_OAUTH2_KEY) + and QGIS_SERVER_OAUTH2_AUTHORITY is not None + and os.path.isfile(QGIS_SERVER_OAUTH2_AUTHORITY) + and QGIS_SERVER_OAUTH2_USERNAME + and QGIS_SERVER_OAUTH2_PASSWORD +) HTTPS_ENABLED = QGIS_SERVER_PKI_AUTH or QGIS_SERVER_OAUTH2_AUTH @@ -202,28 +202,37 @@ class HTTPBasicFilter(QgsServerFilter): def requestReady(self): handler = self.serverInterface().requestHandler() - auth = self.serverInterface().requestHandler().requestHeader('HTTP_AUTHORIZATION') + auth = ( + self.serverInterface() + .requestHandler() + .requestHeader("HTTP_AUTHORIZATION") + ) if auth: - username, password = base64.b64decode(auth[6:]).split(b':') - if (username.decode('utf-8') == os.environ.get('QGIS_SERVER_USERNAME', 'username') and - password.decode('utf-8') == os.environ.get('QGIS_SERVER_PASSWORD', 'password')): + username, password = base64.b64decode(auth[6:]).split(b":") + if username.decode("utf-8") == os.environ.get( + "QGIS_SERVER_USERNAME", "username" + ) and password.decode("utf-8") == os.environ.get( + "QGIS_SERVER_PASSWORD", "password" + ): return - handler.setParameter('SERVICE', 'ACCESS_DENIED') + handler.setParameter("SERVICE", "ACCESS_DENIED") def responseComplete(self): handler = self.serverInterface().requestHandler() - auth = handler.requestHeader('HTTP_AUTHORIZATION') + auth = handler.requestHeader("HTTP_AUTHORIZATION") if auth: - username, password = base64.b64decode(auth[6:]).split(b':') - if (username.decode('utf-8') == os.environ.get('QGIS_SERVER_USERNAME', 'username') and - password.decode('utf-8') == os.environ.get('QGIS_SERVER_PASSWORD', 'password')): + username, password = base64.b64decode(auth[6:]).split(b":") + if username.decode("utf-8") == os.environ.get( + "QGIS_SERVER_USERNAME", "username" + ) and password.decode("utf-8") == os.environ.get( + "QGIS_SERVER_PASSWORD", "password" + ): return # No auth ... handler.clear() - handler.setResponseHeader('Status', '401 Authorization required') - handler.setResponseHeader( - 'WWW-Authenticate', 'Basic realm="QGIS Server"') - handler.appendBody(b'

    Authorization required

    ') + handler.setResponseHeader("Status", "401 Authorization required") + handler.setResponseHeader("WWW-Authenticate", 'Basic realm="QGIS Server"') + handler.appendBody(b"

    Authorization required

    ") filter = HTTPBasicFilter(qgs_server.serverInterface()) qgs_server.serverInterface().registerFilter(filter) @@ -231,8 +240,9 @@ def responseComplete(self): def num2deg(xtile, ytile, zoom): """This returns the NW-corner of the square. Use the function with xtile+1 and/or ytile+1 - to get the other corners. With xtile+0.5 & ytile+0.5 it will return the center of the tile.""" - n = 2.0 ** zoom + to get the other corners. With xtile+0.5 & ytile+0.5 it will return the center of the tile. + """ + n = 2.0**zoom lon_deg = xtile / n * 360.0 - 180.0 lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * ytile / n))) lat_deg = math.degrees(lat_rad) @@ -244,21 +254,21 @@ class XYZFilter(QgsServerFilter): def requestReady(self): handler = self.serverInterface().requestHandler() - if handler.parameter('SERVICE') == 'XYZ': - x = int(handler.parameter('X')) - y = int(handler.parameter('Y')) - z = int(handler.parameter('Z')) + if handler.parameter("SERVICE") == "XYZ": + x = int(handler.parameter("X")) + y = int(handler.parameter("Y")) + z = int(handler.parameter("Z")) # NW corner lat_deg, lon_deg = num2deg(x, y, z) # SE corner lat_deg2, lon_deg2 = num2deg(x + 1, y + 1, z) - handler.setParameter('SERVICE', 'WMS') - handler.setParameter('REQUEST', 'GetMap') - handler.setParameter('VERSION', '1.3.0') - handler.setParameter('SRS', 'EPSG:4326') - handler.setParameter('HEIGHT', '256') - handler.setParameter('WIDTH', '256') - handler.setParameter('BBOX', f"{lat_deg2},{lon_deg},{lat_deg},{lon_deg2}") + handler.setParameter("SERVICE", "WMS") + handler.setParameter("REQUEST", "GetMap") + handler.setParameter("VERSION", "1.3.0") + handler.setParameter("SRS", "EPSG:4326") + handler.setParameter("HEIGHT", "256") + handler.setParameter("WIDTH", "256") + handler.setParameter("BBOX", f"{lat_deg2},{lon_deg},{lat_deg},{lon_deg2}") xyzfilter = XYZFilter(qgs_server.serverInterface()) @@ -282,22 +292,27 @@ def validate_client_id(self, client_id, request): def authenticate_client(self, request, *args, **kwargs): """Wide open""" - request.client = type("Client", (), {'client_id': 'my_id'}) + request.client = type("Client", (), {"client_id": "my_id"}) return True def validate_user(self, username, password, client, request, *args, **kwargs): - if username == QGIS_SERVER_OAUTH2_USERNAME and password == QGIS_SERVER_OAUTH2_PASSWORD: + if ( + username == QGIS_SERVER_OAUTH2_USERNAME + and password == QGIS_SERVER_OAUTH2_PASSWORD + ): return True return False - def validate_grant_type(self, client_id, grant_type, client, request, *args, **kwargs): + def validate_grant_type( + self, client_id, grant_type, client, request, *args, **kwargs + ): # Clients should only be allowed to use one type of grant. - return grant_type in ('password', 'refresh_token') + return grant_type in ("password", "refresh_token") def get_default_scopes(self, client_id, request, *args, **kwargs): # Scopes a client will authorize for if none are supplied in the # authorization request. - return ('my_scope',) + return ("my_scope",) def validate_scopes(self, client_id, scopes, client, request, *args, **kwargs): """Wide open""" @@ -309,18 +324,24 @@ def save_bearer_token(self, token, request, *args, **kwargs): # the authorization code. Don't forget to save both the # access_token and the refresh_token and set expiration for the # access_token to now + expires_in seconds. - _tokens[token['access_token']] = copy.copy(token) - _tokens[token['access_token']]['expiration'] = datetime.now( - ).timestamp() + int(token['expires_in']) + _tokens[token["access_token"]] = copy.copy(token) + _tokens[token["access_token"]][ + "expiration" + ] = datetime.now().timestamp() + int(token["expires_in"]) def validate_bearer_token(self, token, scopes, request): """Check the token""" - return token in _tokens and _tokens[token]['expiration'] > datetime.now().timestamp() + return ( + token in _tokens + and _tokens[token]["expiration"] > datetime.now().timestamp() + ) - def validate_refresh_token(self, refresh_token, client, request, *args, **kwargs): + def validate_refresh_token( + self, refresh_token, client, request, *args, **kwargs + ): """Ensure the Bearer token is valid and authorized access to scopes.""" for t in _tokens.values(): - if t['refresh_token'] == refresh_token: + if t["refresh_token"] == refresh_token: return True return False @@ -330,7 +351,8 @@ def get_original_scopes(self, refresh_token, request, *args, **kwargs): validator = SimpleValidator() oauth_server = LegacyApplicationServer( - validator, token_expires_in=QGIS_SERVER_OAUTH2_TOKEN_EXPIRES_IN) + validator, token_expires_in=QGIS_SERVER_OAUTH2_TOKEN_EXPIRES_IN + ) class OAuth2Filter(QgsServerFilter): """This filter provides testing endpoint for OAuth2 Resource Owner Grant Flow @@ -350,41 +372,46 @@ def responseComplete(self): def _token(ttl): """Common code for new and refresh token""" handler.clear() - body = bytes(handler.data()).decode('utf8') + body = bytes(handler.data()).decode("utf8") old_expires_in = oauth_server.default_token_type.expires_in # Hacky way to dynamically set token expiration time oauth_server.default_token_type.expires_in = ttl headers, payload, code = oauth_server.create_token_response( - '/token', 'post', body, {}) + "/token", "post", body, {} + ) oauth_server.default_token_type.expires_in = old_expires_in for k, v in headers.items(): handler.setResponseHeader(k, v) handler.setStatusCode(code) - handler.appendBody(payload.encode('utf-8')) + handler.appendBody(payload.encode("utf-8")) # Token expiration - ttl = handler.parameterMap().get('TTL', QGIS_SERVER_OAUTH2_TOKEN_EXPIRES_IN) + ttl = handler.parameterMap().get("TTL", QGIS_SERVER_OAUTH2_TOKEN_EXPIRES_IN) # Issue a new token - if handler.url().find('/token') != -1: + if handler.url().find("/token") != -1: _token(ttl) return # Refresh token - if handler.url().find('/refresh') != -1: + if handler.url().find("/refresh") != -1: _token(ttl) return # Check for valid token - auth = handler.requestHeader('HTTP_AUTHORIZATION') + auth = handler.requestHeader("HTTP_AUTHORIZATION") if auth: result, response = oauth_server.verify_request( - urllib.parse.quote_plus(handler.url(), safe='/:?=&'), 'post', '', {'Authorization': auth}) + urllib.parse.quote_plus(handler.url(), safe="/:?=&"), + "post", + "", + {"Authorization": auth}, + ) if result: # This is a test endpoint for OAuth2, it requires a valid # token - if handler.url().find('/result') != -1: + if handler.url().find("/result") != -1: handler.clear() - handler.appendBody(b'Valid Token: enjoy OAuth2') + handler.appendBody(b"Valid Token: enjoy OAuth2") # Standard flow return else: @@ -394,10 +421,9 @@ def _token(ttl): # No auth ... handler.clear() handler.setStatusCode(401) - handler.setResponseHeader('Status', '401 Unauthorized') - handler.setResponseHeader( - 'WWW-Authenticate', 'Bearer realm="QGIS Server"') - handler.appendBody(b'Invalid Token: Authorization required.') + handler.setResponseHeader("Status", "401 Unauthorized") + handler.setResponseHeader("WWW-Authenticate", 'Bearer realm="QGIS Server"') + handler.appendBody(b"Invalid Token: Authorization required.") filter = OAuth2Filter(qgs_server.serverInterface()) qgs_server.serverInterface().registerFilter(filter) @@ -409,17 +435,33 @@ def do_GET(self, post_body=None): # CGI vars: headers = {} for k, v in self.headers.items(): - headers['HTTP_%s' % k.replace(' ', '-').replace('-', '_').replace(' ', '-').upper()] = v - if not self.path.startswith('http'): - self.path = "{}://{}:{}{}".format('https' if HTTPS_ENABLED else 'http', QGIS_SERVER_HOST, self.server.server_port, self.path) + headers[ + "HTTP_%s" + % k.replace(" ", "-").replace("-", "_").replace(" ", "-").upper() + ] = v + if not self.path.startswith("http"): + self.path = "{}://{}:{}{}".format( + "https" if HTTPS_ENABLED else "http", + QGIS_SERVER_HOST, + self.server.server_port, + self.path, + ) request = QgsBufferServerRequest( - self.path, (QgsServerRequest.PostMethod if post_body is not None else QgsServerRequest.GetMethod), headers, post_body) + self.path, + ( + QgsServerRequest.PostMethod + if post_body is not None + else QgsServerRequest.GetMethod + ), + headers, + post_body, + ) response = QgsBufferServerResponse() qgs_server.handleRequest(request, response) headers_dict = response.headers() try: - self.send_response(int(headers_dict['Status'].split(' ')[0])) + self.send_response(int(headers_dict["Status"].split(" ")[0])) except: self.send_response(200) for k, v in headers_dict.items(): @@ -429,18 +471,19 @@ def do_GET(self, post_body=None): return def do_POST(self): - content_len = int(self.headers.get('content-length', 0)) + content_len = int(self.headers.get("content-length", 0)) post_body = self.rfile.read(content_len) return self.do_GET(post_body) class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): """Handle requests in a separate thread.""" + pass -if __name__ == '__main__': - if os.environ.get('MULTITHREADING') == '1': +if __name__ == "__main__": + if os.environ.get("MULTITHREADING") == "1": server = ThreadedHTTPServer((QGIS_SERVER_HOST, QGIS_SERVER_PORT), Handler) else: server = HTTPServer((QGIS_SERVER_HOST, QGIS_SERVER_PORT), Handler) @@ -450,29 +493,28 @@ class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): ssl_version = ssl.PROTOCOL_TLS context = ssl.SSLContext(ssl_version) context.verify_mode = ssl.CERT_NONE # No certs for OAuth2 - context.load_cert_chain(certfile=QGIS_SERVER_OAUTH2_CERTIFICATE, - keyfile=QGIS_SERVER_OAUTH2_KEY) + context.load_cert_chain( + certfile=QGIS_SERVER_OAUTH2_CERTIFICATE, keyfile=QGIS_SERVER_OAUTH2_KEY + ) context.load_verify_locations(cafile=QGIS_SERVER_OAUTH2_AUTHORITY) - server.socket = context.wrap_socket( - server.socket, - server_side=True - ) + server.socket = context.wrap_socket(server.socket, server_side=True) else: ssl_version = ssl.PROTOCOL_TLS context = ssl.SSLContext(ssl_version) context.verify_mode = ssl.CERT_REQUIRED - context.load_cert_chain(certfile=QGIS_SERVER_PKI_CERTIFICATE, - keyfile=QGIS_SERVER_PKI_KEY) + context.load_cert_chain( + certfile=QGIS_SERVER_PKI_CERTIFICATE, keyfile=QGIS_SERVER_PKI_KEY + ) context.load_verify_locations(cafile=QGIS_SERVER_PKI_AUTHORITY) - server.socket = context.wrap_socket( - server.socket, - server_side=True - ) + server.socket = context.wrap_socket(server.socket, server_side=True) - print('Starting server on %s://%s:%s, use to stop' % - ('https' if HTTPS_ENABLED else 'http', QGIS_SERVER_HOST, server.server_port), flush=True) + print( + "Starting server on %s://%s:%s, use to stop" + % ("https" if HTTPS_ENABLED else "http", QGIS_SERVER_HOST, server.server_port), + flush=True, + ) def signal_handler(signal, frame): global qgs_app diff --git a/tests/src/python/qgsauthconfigurationcustomstorage.py b/tests/src/python/qgsauthconfigurationcustomstorage.py index 529d00738b66..1a44d49c2bf6 100644 --- a/tests/src/python/qgsauthconfigurationcustomstorage.py +++ b/tests/src/python/qgsauthconfigurationcustomstorage.py @@ -21,7 +21,7 @@ class QgsAuthConfigurationCustomStorage(QgsAuthConfigurationStorage): """Only for testing purposes: supports authentication - configuration storage in memory""" + configuration storage in memory""" def __init__(self, params: dict = {}): super().__init__(params) @@ -29,33 +29,46 @@ def __init__(self, params: dict = {}): self.payloads = {} self._initialized = False self._id = str(uuid.uuid4()) - self.is_encrypted = params.get('is_encrypted', 'true') in ['true', 'True', '1', 'TRUE', 'on', 'ON', 'YES', 'yes'] + self.is_encrypted = params.get("is_encrypted", "true") in [ + "true", + "True", + "1", + "TRUE", + "on", + "ON", + "YES", + "yes", + ] def settingsParams(self): - param = QgsAuthConfigurationStorage.SettingParam('is_encrypted', 'Whether the storage is encrypted or not', QVariant.Bool) + param = QgsAuthConfigurationStorage.SettingParam( + "is_encrypted", "Whether the storage is encrypted or not", QVariant.Bool + ) return [param] def isEncrypted(self): return self.is_encrypted def name(self): - return 'Custom' + return "Custom" def description(self): - return 'Custom storage' + return "Custom storage" def type(self): - return 'custom' + return "custom" def id(self): return self._id def capabilities(self): - return (Qgis.AuthConfigurationStorageCapability.ReadConfiguration | - Qgis.AuthConfigurationStorageCapability.DeleteConfiguration | - Qgis.AuthConfigurationStorageCapability.CreateConfiguration | - Qgis.AuthConfigurationStorageCapability.UpdateConfiguration | - Qgis.AuthConfigurationStorageCapability.ClearStorage) + return ( + Qgis.AuthConfigurationStorageCapability.ReadConfiguration + | Qgis.AuthConfigurationStorageCapability.DeleteConfiguration + | Qgis.AuthConfigurationStorageCapability.CreateConfiguration + | Qgis.AuthConfigurationStorageCapability.UpdateConfiguration + | Qgis.AuthConfigurationStorageCapability.ClearStorage + ) def isReady(self): return self._initialized @@ -98,11 +111,11 @@ def loadMethodConfig(self, id: str, full=False): else: config = self.configs.get(id, QgsAuthMethodConfig()) config.clearConfigMap() - return self.configs.get(id, QgsAuthMethodConfig()), '' + return self.configs.get(id, QgsAuthMethodConfig()), "" def authMethodConfigsWithPayload(self) -> str: configs = {} for id, config in self.configs.items(): configs[id] = config - configs[id].setConfig('encrypted_payload', self.payloads[id]) + configs[id].setConfig("encrypted_payload", self.payloads[id]) return configs diff --git a/tests/src/python/qgslayermetadataprovidertestbase.py b/tests/src/python/qgslayermetadataprovidertestbase.py index 25ba1e518506..a765ddb83f05 100644 --- a/tests/src/python/qgslayermetadataprovidertestbase.py +++ b/tests/src/python/qgslayermetadataprovidertestbase.py @@ -7,9 +7,9 @@ """ -__author__ = 'elpaso@itopen.it' -__date__ = '2022-08-19' -__copyright__ = 'Copyright 2022, ItOpen' +__author__ = "elpaso@itopen.it" +__date__ = "2022-08-19" +__copyright__ = "Copyright 2022, ItOpen" from qgis.PyQt.QtCore import QCoreApplication from qgis.core import ( @@ -32,7 +32,7 @@ TEST_DATA_DIR = unitTestDataPath() -class LayerMetadataProviderTestBase(): +class LayerMetadataProviderTestBase: """Base test for layer metadata providers Provider tests must implement: @@ -57,11 +57,11 @@ def testMetadataWriteRead(self): data_provider_name = self.test_layer.dataProvider().name() m = self.test_layer.metadata() - m.setAbstract('QGIS Some Data') - m.setIdentifier('MD012345') - m.setTitle('QGIS Test Title') - m.setKeywords({'dtd1': ['Kw1', 'Kw2']}) - m.setCategories(['Cat1', 'Cat2']) + m.setAbstract("QGIS Some Data") + m.setIdentifier("MD012345") + m.setTitle("QGIS Test Title") + m.setKeywords({"dtd1": ["Kw1", "Kw2"]}) + m.setCategories(["Cat1", "Cat2"]) ext = QgsLayerMetadata.Extent() spatial_ext = QgsLayerMetadata.SpatialExtent() spatial_ext.bounds = QgsBox3d(self.test_layer.extent()) @@ -72,66 +72,87 @@ def testMetadataWriteRead(self): md = QgsProviderRegistry.instance().providerMetadata(data_provider_name) self.assertIsNotNone(md) - self.assertTrue(bool(md.providerCapabilities() & QgsProviderMetadata.ProviderCapability.SaveLayerMetadata)) + self.assertTrue( + bool( + md.providerCapabilities() + & QgsProviderMetadata.ProviderCapability.SaveLayerMetadata + ) + ) layer_uri = self.test_layer.publicSource() self.assertTrue(md.saveLayerMetadata(layer_uri, m)[0]) self.test_layer = self.getLayer() m = self.test_layer.metadata() - self.assertEqual(m.title(), 'QGIS Test Title') - self.assertEqual(m.identifier(), 'MD012345') - self.assertEqual(m.abstract(), 'QGIS Some Data') + self.assertEqual(m.title(), "QGIS Test Title") + self.assertEqual(m.identifier(), "MD012345") + self.assertEqual(m.abstract(), "QGIS Some Data") self.assertEqual(m.crs().authid(), layer_authid) del self.test_layer reg = QGIS_APP.layerMetadataProviderRegistry() md_provider = reg.layerMetadataProviderFromId(self.getMetadataProviderId()) - results = md_provider.search(QgsMetadataSearchContext(), 'QgIs SoMe DaTa') + results = md_provider.search(QgsMetadataSearchContext(), "QgIs SoMe DaTa") self.assertEqual(len(results.metadata()), 1) result = results.metadata()[0] - self.assertEqual(result.abstract(), 'QGIS Some Data') - self.assertEqual(result.identifier(), 'MD012345') - self.assertEqual(result.title(), 'QGIS Test Title') + self.assertEqual(result.abstract(), "QGIS Some Data") + self.assertEqual(result.identifier(), "MD012345") + self.assertEqual(result.title(), "QGIS Test Title") self.assertEqual(result.layerType(), layer_type) self.assertEqual(result.authid(), layer_authid) # For raster is unknown if layer_type != QgsMapLayerType.VectorLayer: - self.assertEqual(result.geometryType(), QgsWkbTypes.GeometryType.UnknownGeometry) + self.assertEqual( + result.geometryType(), QgsWkbTypes.GeometryType.UnknownGeometry + ) else: - self.assertEqual(result.geometryType(), QgsWkbTypes.GeometryType.PointGeometry) + self.assertEqual( + result.geometryType(), QgsWkbTypes.GeometryType.PointGeometry + ) self.assertEqual(result.dataProviderName(), data_provider_name) - self.assertEqual(result.standardUri(), 'http://mrcc.com/qgis.dtd') + self.assertEqual(result.standardUri(), "http://mrcc.com/qgis.dtd") self.assertTrue(compareWkt(result.geographicExtent().asWkt(), extent_as_wkt)) # Check layer load if layer_type == QgsMapLayerType.VectorLayer: - test_layer = QgsVectorLayer(result.uri(), 'PG MD Layer', result.dataProviderName()) + test_layer = QgsVectorLayer( + result.uri(), "PG MD Layer", result.dataProviderName() + ) else: - test_layer = QgsRasterLayer(result.uri(), 'PG MD Layer', result.dataProviderName()) + test_layer = QgsRasterLayer( + result.uri(), "PG MD Layer", result.dataProviderName() + ) self.assertTrue(test_layer.isValid()) # Test search filters - results = md_provider.search(QgsMetadataSearchContext(), '', QgsRectangle(0, 0, 1, 1)) + results = md_provider.search( + QgsMetadataSearchContext(), "", QgsRectangle(0, 0, 1, 1) + ) self.assertEqual(len(results.metadata()), 0) - results = md_provider.search(QgsMetadataSearchContext(), '', test_layer.extent()) + results = md_provider.search( + QgsMetadataSearchContext(), "", test_layer.extent() + ) self.assertEqual(len(results.metadata()), 1) - results = md_provider.search(QgsMetadataSearchContext(), 'NOT HERE!', test_layer.extent()) + results = md_provider.search( + QgsMetadataSearchContext(), "NOT HERE!", test_layer.extent() + ) self.assertEqual(len(results.metadata()), 0) - results = md_provider.search(QgsMetadataSearchContext(), 'QGIS', test_layer.extent()) + results = md_provider.search( + QgsMetadataSearchContext(), "QGIS", test_layer.extent() + ) self.assertEqual(len(results.metadata()), 1) # Test keywords - results = md_provider.search(QgsMetadataSearchContext(), 'kw') + results = md_provider.search(QgsMetadataSearchContext(), "kw") self.assertEqual(len(results.metadata()), 1) - results = md_provider.search(QgsMetadataSearchContext(), 'kw2') + results = md_provider.search(QgsMetadataSearchContext(), "kw2") self.assertEqual(len(results.metadata()), 1) # Test categories - results = md_provider.search(QgsMetadataSearchContext(), 'cat') + results = md_provider.search(QgsMetadataSearchContext(), "cat") self.assertEqual(len(results.metadata()), 1) - results = md_provider.search(QgsMetadataSearchContext(), 'cat2') + results = md_provider.search(QgsMetadataSearchContext(), "cat2") self.assertEqual(len(results.metadata()), 1) diff --git a/tests/src/python/stylestoragebase.py b/tests/src/python/stylestoragebase.py index 907e9043dff8..bb7cbc96db57 100644 --- a/tests/src/python/stylestoragebase.py +++ b/tests/src/python/stylestoragebase.py @@ -7,9 +7,9 @@ """ -__author__ = 'elpaso@itopen.it' -__date__ = '2022-11-07' -__copyright__ = 'Copyright 2022, ItOpen' +__author__ = "elpaso@itopen.it" +__date__ = "2022-11-07" +__copyright__ = "Copyright 2022, ItOpen" from qgis.PyQt.QtCore import QCoreApplication, QVariant from qgis.PyQt.QtGui import QColor @@ -41,7 +41,7 @@ def setUpClass(cls): start_app() -class StyleStorageTestBase(): +class StyleStorageTestBase: def layerUri(self, conn, schema_name, table_name): """Providers may override if they need more complex URI generation than @@ -52,26 +52,29 @@ def layerUri(self, conn, schema_name, table_name): def schemaName(self): """Providers may override (Oracle?)""" - return 'test_styles_schema' + return "test_styles_schema" def tableName(self): """Providers may override (Oracle?)""" - return 'test_styles_table' + return "test_styles_table" def testMultipleStyles(self): md = QgsProviderRegistry.instance().providerMetadata(self.providerKey) conn = md.createConnection(self.uri, {}) - md.saveConnection(conn, 'qgis_test1') + md.saveConnection(conn, "qgis_test1") schema = None capabilities = conn.capabilities() - if (capabilities & QgsAbstractDatabaseProviderConnection.Capability.CreateSchema + if ( + capabilities & QgsAbstractDatabaseProviderConnection.Capability.CreateSchema and capabilities & QgsAbstractDatabaseProviderConnection.Capability.Schemas - and capabilities & QgsAbstractDatabaseProviderConnection.Capability.DropSchema): + and capabilities + & QgsAbstractDatabaseProviderConnection.Capability.DropSchema + ): schema = self.schemaName() # Start clean @@ -83,7 +86,7 @@ def testMultipleStyles(self): schemas = conn.schemas() self.assertIn(schema, schemas) - elif (capabilities & QgsAbstractDatabaseProviderConnection.Capability.Schemas): + elif capabilities & QgsAbstractDatabaseProviderConnection.Capability.Schemas: schema = self.schemaName() try: @@ -106,52 +109,54 @@ def testMultipleStyles(self): typ = QgsWkbTypes.Type.Point # Create table - conn.createVectorTable(schema, self.tableName(), fields, typ, crs, True, options) + conn.createVectorTable( + schema, self.tableName(), fields, typ, crs, True, options + ) uri = self.layerUri(conn, schema, self.tableName()) - vl = QgsVectorLayer(uri, 'vl', self.providerKey) + vl = QgsVectorLayer(uri, "vl", self.providerKey) self.assertTrue(vl.isValid()) renderer = vl.renderer() symbol = renderer.symbol().clone() - symbol.setColor(QColor('#ff0000')) + symbol.setColor(QColor("#ff0000")) renderer.setSymbol(symbol) - vl.saveStyleToDatabase('style1', 'style1', False, None) + vl.saveStyleToDatabase("style1", "style1", False, None) symbol = renderer.symbol().clone() - symbol.setColor(QColor('#00ff00')) + symbol.setColor(QColor("#00ff00")) renderer.setSymbol(symbol) - vl.saveStyleToDatabase('style2', 'style2', True, None) + vl.saveStyleToDatabase("style2", "style2", True, None) symbol = renderer.symbol().clone() - symbol.setColor(QColor('#0000ff')) + symbol.setColor(QColor("#0000ff")) renderer.setSymbol(symbol) - vl.saveStyleToDatabase('style3', 'style3', False, None) + vl.saveStyleToDatabase("style3", "style3", False, None) num, ids, names, desc, err = vl.listStylesInDatabase() - self.assertTrue({'style2', 'style3', 'style1'}.issubset(set(names))) + self.assertTrue({"style2", "style3", "style1"}.issubset(set(names))) del vl - vl = QgsVectorLayer(uri, 'vl', self.providerKey) + vl = QgsVectorLayer(uri, "vl", self.providerKey) self.assertTrue(vl.isValid()) renderer = vl.renderer() symbol = renderer.symbol() - self.assertEqual(symbol.color().name(), '#00ff00') + self.assertEqual(symbol.color().name(), "#00ff00") mgr = vl.styleManager() - self.assertEqual(mgr.styles(), ['style2']) + self.assertEqual(mgr.styles(), ["style2"]) del vl options = QgsVectorLayer.LayerOptions() options.loadAllStoredStyles = True - vl = QgsVectorLayer(uri, 'vl', self.providerKey, options) + vl = QgsVectorLayer(uri, "vl", self.providerKey, options) self.assertTrue(vl.isValid()) renderer = vl.renderer() symbol = renderer.symbol() - self.assertEqual(symbol.color().name(), '#00ff00') + self.assertEqual(symbol.color().name(), "#00ff00") mgr = vl.styleManager() - self.assertTrue({'style2', 'style3', 'style1'}.issubset(set(names))) + self.assertTrue({"style2", "style3", "style1"}.issubset(set(names))) diff --git a/tests/src/python/test_authmanager_oauth2_ows.py b/tests/src/python/test_authmanager_oauth2_ows.py index 1a320211d264..fea9213cb9db 100644 --- a/tests/src/python/test_authmanager_oauth2_ows.py +++ b/tests/src/python/test_authmanager_oauth2_ows.py @@ -14,6 +14,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + import json import os import random @@ -24,9 +25,9 @@ import tempfile import urllib -__author__ = 'Alessandro Pasotti' -__date__ = '20/04/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "20/04/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from shutil import rmtree @@ -42,18 +43,25 @@ from utilities import unitTestDataPath, waitServer try: - QGIS_SERVER_ENDPOINT_PORT = os.environ['QGIS_SERVER_ENDPOINT_PORT'] + QGIS_SERVER_ENDPOINT_PORT = os.environ["QGIS_SERVER_ENDPOINT_PORT"] except: - QGIS_SERVER_ENDPOINT_PORT = '0' # Auto + QGIS_SERVER_ENDPOINT_PORT = "0" # Auto QGIS_AUTH_DB_DIR_PATH = tempfile.mkdtemp() -os.environ['QGIS_AUTH_DB_DIR_PATH'] = QGIS_AUTH_DB_DIR_PATH +os.environ["QGIS_AUTH_DB_DIR_PATH"] = QGIS_AUTH_DB_DIR_PATH qgis_app = start_app() -def setup_oauth(username, password, token_uri, refresh_token_uri='', authcfg_id='oauth-2', authcfg_name='OAuth2 test configuration'): +def setup_oauth( + username, + password, + token_uri, + refresh_token_uri="", + authcfg_id="oauth-2", + authcfg_name="OAuth2 test configuration", +): """Setup oauth configuration to access OAuth API, return authcfg_id on success, None on failure """ @@ -66,29 +74,31 @@ def setup_oauth(username, password, token_uri, refresh_token_uri='', authcfg_id= "grantFlow": 2, "password": password, "persistToken": False, - "redirectPort": '7070', + "redirectPort": "7070", "redirectUrl": "", "refreshTokenUrl": refresh_token_uri, - "requestTimeout": '30', + "requestTimeout": "30", "requestUrl": "", "scope": "", "tokenUrl": token_uri, "username": username, - "version": 1 + "version": 1, } if authcfg_id not in QgsApplication.authManager().availableAuthMethodConfigs(): - authConfig = QgsAuthMethodConfig('OAuth2') + authConfig = QgsAuthMethodConfig("OAuth2") authConfig.setId(authcfg_id) authConfig.setName(authcfg_name) - authConfig.setConfig('oauth2config', json.dumps(cfgjson)) + authConfig.setConfig("oauth2config", json.dumps(cfgjson)) if QgsApplication.authManager().storeAuthenticationConfig(authConfig): return authcfg_id else: authConfig = QgsAuthMethodConfig() - QgsApplication.authManager().loadAuthenticationConfig(authcfg_id, authConfig, True) + QgsApplication.authManager().loadAuthenticationConfig( + authcfg_id, authConfig, True + ) authConfig.setName(authcfg_name) - authConfig.setConfig('oauth2config', json.dumps(cfgjson)) + authConfig.setConfig("oauth2config", json.dumps(cfgjson)) if QgsApplication.authManager().updateAuthenticationConfig(authConfig): return authcfg_id return None @@ -100,8 +110,8 @@ class TestAuthManager(QgisTestCase): def setUpAuth(cls): """Run before all tests and set up authentication""" authm = QgsApplication.authManager() - assert (authm.setMasterPassword('masterpassword', True)) - cls.sslrootcert_path = os.path.join(cls.certsdata_path, 'qgis_ca.crt') + assert authm.setMasterPassword("masterpassword", True) + cls.sslrootcert_path = os.path.join(cls.certsdata_path, "qgis_ca.crt") assert os.path.isfile(cls.sslrootcert_path) os.chmod(cls.sslrootcert_path, stat.S_IRUSR) @@ -111,24 +121,24 @@ def setUpAuth(cls): authm.rebuildCaCertsCache() authm.rebuildTrustedCaCertsCache() - cls.server_cert = os.path.join(cls.certsdata_path, '127_0_0_1.crt') - cls.server_key = os.path.join(cls.certsdata_path, '127_0_0_1.key') + cls.server_cert = os.path.join(cls.certsdata_path, "127_0_0_1.crt") + cls.server_key = os.path.join(cls.certsdata_path, "127_0_0_1.key") cls.server_rootcert = cls.sslrootcert_path os.chmod(cls.server_cert, stat.S_IRUSR) os.chmod(cls.server_key, stat.S_IRUSR) os.chmod(cls.server_rootcert, stat.S_IRUSR) - os.environ['QGIS_SERVER_HOST'] = cls.hostname - os.environ['QGIS_SERVER_PORT'] = str(cls.port) - os.environ['QGIS_SERVER_OAUTH2_KEY'] = cls.server_key - os.environ['QGIS_SERVER_OAUTH2_CERTIFICATE'] = cls.server_cert - os.environ['QGIS_SERVER_OAUTH2_USERNAME'] = cls.username - os.environ['QGIS_SERVER_OAUTH2_PASSWORD'] = cls.password - os.environ['QGIS_SERVER_OAUTH2_AUTHORITY'] = cls.server_rootcert + os.environ["QGIS_SERVER_HOST"] = cls.hostname + os.environ["QGIS_SERVER_PORT"] = str(cls.port) + os.environ["QGIS_SERVER_OAUTH2_KEY"] = cls.server_key + os.environ["QGIS_SERVER_OAUTH2_CERTIFICATE"] = cls.server_cert + os.environ["QGIS_SERVER_OAUTH2_USERNAME"] = cls.username + os.environ["QGIS_SERVER_OAUTH2_PASSWORD"] = cls.password + os.environ["QGIS_SERVER_OAUTH2_AUTHORITY"] = cls.server_rootcert # Set default token expiration to 2 seconds, note that this can be # also controlled when issuing token requests by adding ttl= # to the query string - os.environ['QGIS_SERVER_OAUTH2_TOKEN_EXPIRES_IN'] = '2' + os.environ["QGIS_SERVER_OAUTH2_TOKEN_EXPIRES_IN"] = "2" @classmethod def setUpClass(cls): @@ -137,43 +147,63 @@ def setUpClass(cls): Creates an auth configuration""" cls.port = QGIS_SERVER_ENDPOINT_PORT # Clean env just to be sure - env_vars = ['QUERY_STRING', 'QGIS_PROJECT_FILE'] + env_vars = ["QUERY_STRING", "QGIS_PROJECT_FILE"] for ev in env_vars: try: del os.environ[ev] except KeyError: pass - cls.testdata_path = unitTestDataPath('qgis_server') - cls.certsdata_path = os.path.join(unitTestDataPath('auth_system'), 'certs_keys_2048') + cls.testdata_path = unitTestDataPath("qgis_server") + cls.certsdata_path = os.path.join( + unitTestDataPath("auth_system"), "certs_keys_2048" + ) cls.project_path = os.path.join(cls.testdata_path, "test_project.qgs") # cls.hostname = 'localhost' - cls.protocol = 'https' - cls.hostname = '127.0.0.1' - cls.username = 'username' - cls.password = 'password' + cls.protocol = "https" + cls.hostname = "127.0.0.1" + cls.username = "username" + cls.password = "password" cls.setUpAuth() - server_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), - 'qgis_wrapped_server.py') - cls.server = subprocess.Popen([sys.executable, server_path], - env=os.environ, stdout=subprocess.PIPE) + server_path = os.path.join( + os.path.dirname(os.path.realpath(__file__)), "qgis_wrapped_server.py" + ) + cls.server = subprocess.Popen( + [sys.executable, server_path], env=os.environ, stdout=subprocess.PIPE + ) line = cls.server.stdout.readline() - cls.port = int(re.findall(br':(\d+)', line)[0]) + cls.port = int(re.findall(rb":(\d+)", line)[0]) assert cls.port != 0 # We need a valid port before we setup the oauth configuration - cls.token_uri = f'{cls.protocol}://{cls.hostname}:{cls.port}/token' - cls.refresh_token_uri = f'{cls.protocol}://{cls.hostname}:{cls.port}/refresh' + cls.token_uri = f"{cls.protocol}://{cls.hostname}:{cls.port}/token" + cls.refresh_token_uri = f"{cls.protocol}://{cls.hostname}:{cls.port}/refresh" # Need a random authcfg or the cache will bites us back! - cls.authcfg_id = setup_oauth(cls.username, cls.password, cls.token_uri, cls.refresh_token_uri, str(random.randint(0, 10000000))) + cls.authcfg_id = setup_oauth( + cls.username, + cls.password, + cls.token_uri, + cls.refresh_token_uri, + str(random.randint(0, 10000000)), + ) # This is to test wrong credentials - cls.wrong_authcfg_id = setup_oauth('wrong', 'wrong', cls.token_uri, cls.refresh_token_uri, str(random.randint(0, 10000000))) + cls.wrong_authcfg_id = setup_oauth( + "wrong", + "wrong", + cls.token_uri, + cls.refresh_token_uri, + str(random.randint(0, 10000000)), + ) # Get the authentication configuration instance: - cls.auth_config = QgsApplication.authManager().availableAuthMethodConfigs()[cls.authcfg_id] + cls.auth_config = QgsApplication.authManager().availableAuthMethodConfigs()[ + cls.authcfg_id + ] assert cls.auth_config.isValid() # Wait for the server process to start - assert waitServer(f'{cls.protocol}://{cls.hostname}:{cls.port}'), f"Server is not responding! {cls.protocol}://{cls.hostname}:{cls.port}" + assert waitServer( + f"{cls.protocol}://{cls.hostname}:{cls.port}" + ), f"Server is not responding! {cls.protocol}://{cls.hostname}:{cls.port}" @classmethod def tearDownClass(cls): @@ -197,18 +227,18 @@ def _getWFSLayer(cls, type_name, layer_name=None, authcfg=None): WFS layer factory """ if layer_name is None: - layer_name = 'wfs_' + type_name + layer_name = "wfs_" + type_name parms = { - 'srsname': 'EPSG:4326', - 'typename': type_name, - 'url': f'{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}', - 'version': 'auto', - 'table': '', + "srsname": "EPSG:4326", + "typename": type_name, + "url": f"{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}", + "version": "auto", + "table": "", } if authcfg is not None: - parms.update({'authcfg': authcfg}) - uri = ' '.join([(f"{k}='{v}'") for k, v in list(parms.items())]) - wfs_layer = QgsVectorLayer(uri, layer_name, 'WFS') + parms.update({"authcfg": authcfg}) + uri = " ".join([(f"{k}='{v}'") for k, v in list(parms.items())]) + wfs_layer = QgsVectorLayer(uri, layer_name, "WFS") return wfs_layer @classmethod @@ -217,36 +247,36 @@ def _getWMSLayer(cls, layers, layer_name=None, authcfg=None): WMS layer factory """ if layer_name is None: - layer_name = 'wms_' + layers.replace(',', '') + layer_name = "wms_" + layers.replace(",", "") parms = { - 'crs': 'EPSG:4326', - 'url': f'{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}', - 'format': 'image/png', + "crs": "EPSG:4326", + "url": f"{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}", + "format": "image/png", # This is needed because of a really weird implementation in QGIS Server, that # replaces _ in the the real layer name with spaces - 'layers': urllib.parse.quote(layers.replace('_', ' ')), - 'styles': '', - 'version': 'auto', + "layers": urllib.parse.quote(layers.replace("_", " ")), + "styles": "", + "version": "auto", # 'sql': '', } if authcfg is not None: - parms.update({'authcfg': authcfg}) - uri = '&'.join([f"{k}={v.replace('=', '%3D')}" for k, v in list(parms.items())]) - wms_layer = QgsRasterLayer(uri, layer_name, 'wms') + parms.update({"authcfg": authcfg}) + uri = "&".join([f"{k}={v.replace('=', '%3D')}" for k, v in list(parms.items())]) + wms_layer = QgsRasterLayer(uri, layer_name, "wms") return wms_layer def testNoAuthAccess(self): """ Access the protected layer with no credentials """ - wms_layer = self._getWMSLayer('testlayer_èé') + wms_layer = self._getWMSLayer("testlayer_èé") self.assertFalse(wms_layer.isValid()) def testInvalidAuthAccess(self): """ Access the protected layer with wrong credentials """ - wms_layer = self._getWMSLayer('testlayer_èé', authcfg=self.wrong_authcfg_id) + wms_layer = self._getWMSLayer("testlayer_èé", authcfg=self.wrong_authcfg_id) self.assertFalse(wms_layer.isValid()) def testValidAuthAccess(self): @@ -255,11 +285,11 @@ def testValidAuthAccess(self): Note: cannot test invalid access WFS in a separate test because it would fail the subsequent (valid) calls due to cached connections """ - wfs_layer = self._getWFSLayer('testlayer_èé', authcfg=self.auth_config.id()) + wfs_layer = self._getWFSLayer("testlayer_èé", authcfg=self.auth_config.id()) self.assertTrue(wfs_layer.isValid()) - wms_layer = self._getWMSLayer('testlayer_èé', authcfg=self.auth_config.id()) + wms_layer = self._getWMSLayer("testlayer_èé", authcfg=self.auth_config.id()) self.assertTrue(wms_layer.isValid()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_authmanager_ogr.py b/tests/src/python/test_authmanager_ogr.py index d2a51a4d468b..1f578dfb496c 100644 --- a/tests/src/python/test_authmanager_ogr.py +++ b/tests/src/python/test_authmanager_ogr.py @@ -17,9 +17,9 @@ import unittest from qgis.testing import start_app, QgisTestCase -__author__ = 'Alessandro Pasotti' -__date__ = '14/11/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "14/11/2017" +__copyright__ = "Copyright 2017, The QGIS Project" qgis_app = start_app() @@ -28,18 +28,18 @@ TEST_URIS = { "http://mysite.com/geojson authcfg='%s'": "http://username:password@mysite.com/geojson", "PG:\"dbname='databasename' host='addr' port='5432' authcfg='%s'\"": "PG:\"dbname='databasename' host='addr' port='5432' user='username' password='password'", - 'SDE:127.0.0.1,12345,dbname, authcfg=\'%s\'': 'SDE:127.0.0.1,12345,dbname,username,password', - 'IDB:"server=demo_on user=informix dbname=frames authcfg=\'%s\'"': 'IDB:"server=demo_on user=informix dbname=frames user=username pass=password"', - '@driver=ingres,dbname=test,tables=usa/canada authcfg=\'%s\'': '@driver=ingres,dbname=test,tables=usa/canada,userid=username,password=password', - 'MySQL:westholland,port=3306,tables=bedrijven authcfg=\'%s\'': 'MySQL:westholland,port=3306,tables=bedrijven,user=username,password=password', - 'MSSQL:server=.\\MSSQLSERVER2008;database=dbname;trusted_connection=yes authcfg=\'%s\'': 'MSSQL:server=.\\MSSQLSERVER2008;database=dbname;uid=username;pwd=password', - 'OCI:/@database_instance:table,table authcfg=\'%s\'': 'OCI:username/password@database_instance:table,table', - 'ODBC:database_instance authcfg=\'%s\'': 'ODBC:username/password@database_instance', - 'couchdb://myconnection authcfg=\'%s\'': 'couchdb://username:password@myconnection', - 'http://www.myconnection.com/geojson authcfg=\'%s\'': 'http://username:password@www.myconnection.com/geojson', - 'https://www.myconnection.com/geojson authcfg=\'%s\'': 'https://username:password@www.myconnection.com/geojson', - 'ftp://www.myconnection.com/geojson authcfg=\'%s\'': 'ftp://username:password@www.myconnection.com/geojson', - 'DODS://www.myconnection.com/geojson authcfg=\'%s\'': 'DODS://username:password@www.myconnection.com/geojson', + "SDE:127.0.0.1,12345,dbname, authcfg='%s'": "SDE:127.0.0.1,12345,dbname,username,password", + "IDB:\"server=demo_on user=informix dbname=frames authcfg='%s'\"": 'IDB:"server=demo_on user=informix dbname=frames user=username pass=password"', + "@driver=ingres,dbname=test,tables=usa/canada authcfg='%s'": "@driver=ingres,dbname=test,tables=usa/canada,userid=username,password=password", + "MySQL:westholland,port=3306,tables=bedrijven authcfg='%s'": "MySQL:westholland,port=3306,tables=bedrijven,user=username,password=password", + "MSSQL:server=.\\MSSQLSERVER2008;database=dbname;trusted_connection=yes authcfg='%s'": "MSSQL:server=.\\MSSQLSERVER2008;database=dbname;uid=username;pwd=password", + "OCI:/@database_instance:table,table authcfg='%s'": "OCI:username/password@database_instance:table,table", + "ODBC:database_instance authcfg='%s'": "ODBC:username/password@database_instance", + "couchdb://myconnection authcfg='%s'": "couchdb://username:password@myconnection", + "http://www.myconnection.com/geojson authcfg='%s'": "http://username:password@www.myconnection.com/geojson", + "https://www.myconnection.com/geojson authcfg='%s'": "https://username:password@www.myconnection.com/geojson", + "ftp://www.myconnection.com/geojson authcfg='%s'": "ftp://username:password@www.myconnection.com/geojson", + "DODS://www.myconnection.com/geojson authcfg='%s'": "DODS://username:password@www.myconnection.com/geojson", } @@ -49,13 +49,13 @@ class TestAuthManager(QgisTestCase): def setUpAuth(cls): """Run before all tests and set up authentication""" authm = QgsApplication.authManager() - assert (authm.setMasterPassword('masterpassword', True)) + assert authm.setMasterPassword("masterpassword", True) # Client side cls.auth_config = QgsAuthMethodConfig("Basic") - cls.auth_config.setConfig('username', cls.username) - cls.auth_config.setConfig('password', cls.password) - cls.auth_config.setName('test_basic_auth_config') - assert (authm.storeAuthenticationConfig(cls.auth_config)[0]) + cls.auth_config.setConfig("username", cls.username) + cls.auth_config.setConfig("password", cls.password) + cls.auth_config.setName("test_basic_auth_config") + assert authm.storeAuthenticationConfig(cls.auth_config)[0] assert cls.auth_config.isValid() cls.authcfg = cls.auth_config.id() @@ -64,10 +64,10 @@ def setUpClass(cls): super().setUpClass() """Run before all tests: Creates an auth configuration""" - cls.username = 'username' - cls.password = 'password' - cls.dbname = 'test_basic' - cls.hostname = 'localhost' + cls.username = "username" + cls.password = "password" + cls.dbname = "test_basic" + cls.hostname = "localhost" cls.setUpAuth() def setUp(self): @@ -82,15 +82,19 @@ def testConnections(self): """ Test credentials injection """ - pr = QgsProviderRegistry.instance().createProvider('ogr', '') + pr = QgsProviderRegistry.instance().createProvider("ogr", "") for uri, expanded in TEST_URIS.items(): pr.setDataSourceUri(uri % self.authcfg) self.assertIn(expanded, pr.dataSourceUri(True)) # Test sublayers for uri, expanded in TEST_URIS.items(): - pr.setDataSourceUri((uri + '|sublayer1') % self.authcfg) - self.assertEqual(pr.dataSourceUri(True).split('|')[1], "sublayer1", pr.dataSourceUri(True)) + pr.setDataSourceUri((uri + "|sublayer1") % self.authcfg) + self.assertEqual( + pr.dataSourceUri(True).split("|")[1], + "sublayer1", + pr.dataSourceUri(True), + ) def testQuotesAndComma(self): """ @@ -98,18 +102,20 @@ def testQuotesAndComma(self): """ authm = QgsApplication.authManager() auth_config = QgsAuthMethodConfig("Basic") - auth_config.setConfig('username', 'qgis,\"rocks\"') - auth_config.setConfig('password', '\"quoted\"') - auth_config.setName('test_basic_auth_config_quoted') + auth_config.setConfig("username", 'qgis,"rocks"') + auth_config.setConfig("password", '"quoted"') + auth_config.setName("test_basic_auth_config_quoted") self.assertTrue(authm.storeAuthenticationConfig(auth_config)[0]) self.assertTrue(auth_config.isValid()) authcfg = auth_config.id() - pr = QgsProviderRegistry.instance().createProvider('ogr', '') - uri = 'MySQL:hostname authcfg=\'%s\'' + pr = QgsProviderRegistry.instance().createProvider("ogr", "") + uri = "MySQL:hostname authcfg='%s'" pr.setDataSourceUri(uri % authcfg) expanded = pr.dataSourceUri(True) - self.assertEqual(expanded, r'MySQL:hostname,user="qgis,\"rocks\"",password="\"quoted\""') + self.assertEqual( + expanded, r'MySQL:hostname,user="qgis,\"rocks\"",password="\"quoted\""' + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_authmanager_ogr_postgres.py b/tests/src/python/test_authmanager_ogr_postgres.py index 7ca8fe5412a4..4299789b605f 100644 --- a/tests/src/python/test_authmanager_ogr_postgres.py +++ b/tests/src/python/test_authmanager_ogr_postgres.py @@ -23,6 +23,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + import os import signal import stat @@ -42,12 +43,14 @@ from utilities import unitTestDataPath -__author__ = 'Alessandro Pasotti' -__date__ = '03/11/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "03/11/2017" +__copyright__ = "Copyright 2017, The QGIS Project" -QGIS_POSTGRES_SERVER_PORT = os.environ.get('QGIS_POSTGRES_SERVER_PORT', '55432') -QGIS_POSTGRES_EXECUTABLE_PATH = os.environ.get('QGIS_POSTGRES_EXECUTABLE_PATH', '/usr/lib/postgresql/9.4/bin') +QGIS_POSTGRES_SERVER_PORT = os.environ.get("QGIS_POSTGRES_SERVER_PORT", "55432") +QGIS_POSTGRES_EXECUTABLE_PATH = os.environ.get( + "QGIS_POSTGRES_EXECUTABLE_PATH", "/usr/lib/postgresql/9.4/bin" +) assert os.path.exists(QGIS_POSTGRES_EXECUTABLE_PATH) @@ -56,7 +59,7 @@ # Postgres test path QGIS_PG_TEST_PATH = tempfile.mkdtemp() -os.environ['QGIS_AUTH_DB_DIR_PATH'] = QGIS_AUTH_DB_DIR_PATH +os.environ["QGIS_AUTH_DB_DIR_PATH"] = QGIS_AUTH_DB_DIR_PATH qgis_app = start_app() @@ -91,46 +94,51 @@ class TestAuthManager(QgisTestCase): def setUpAuth(cls): """Run before all tests and set up authentication""" authm = QgsApplication.authManager() - assert (authm.setMasterPassword('masterpassword', True)) - cls.pg_conf = os.path.join(cls.tempfolder, 'postgresql.conf') - cls.pg_hba = os.path.join(cls.tempfolder, 'pg_hba.conf') + assert authm.setMasterPassword("masterpassword", True) + cls.pg_conf = os.path.join(cls.tempfolder, "postgresql.conf") + cls.pg_hba = os.path.join(cls.tempfolder, "pg_hba.conf") # Client side - cls.sslrootcert_path = os.path.join(cls.certsdata_path, 'chains_subissuer-issuer-root_issuer2-root2.pem') + cls.sslrootcert_path = os.path.join( + cls.certsdata_path, "chains_subissuer-issuer-root_issuer2-root2.pem" + ) assert os.path.isfile(cls.sslrootcert_path) os.chmod(cls.sslrootcert_path, stat.S_IRUSR) cls.auth_config = QgsAuthMethodConfig("Basic") - cls.auth_config.setConfig('username', cls.username) - cls.auth_config.setConfig('password', cls.password) - cls.auth_config.setName('test_basic_auth_config') + cls.auth_config.setConfig("username", cls.username) + cls.auth_config.setConfig("password", cls.password) + cls.auth_config.setName("test_basic_auth_config") cls.sslrootcert = QSslCertificate.fromPath(cls.sslrootcert_path) assert cls.sslrootcert is not None authm.storeCertAuthorities(cls.sslrootcert) authm.rebuildCaCertsCache() authm.rebuildTrustedCaCertsCache() authm.rebuildCertTrustCache() - assert (authm.storeAuthenticationConfig(cls.auth_config)[0]) + assert authm.storeAuthenticationConfig(cls.auth_config)[0] assert cls.auth_config.isValid() cls.authcfg = cls.auth_config.id() # Server side - cls.server_cert = os.path.join(cls.certsdata_path, 'localhost_ssl_cert.pem') - cls.server_key = os.path.join(cls.certsdata_path, 'localhost_ssl_key.pem') + cls.server_cert = os.path.join(cls.certsdata_path, "localhost_ssl_cert.pem") + cls.server_key = os.path.join(cls.certsdata_path, "localhost_ssl_key.pem") cls.server_rootcert = cls.sslrootcert_path os.chmod(cls.server_cert, stat.S_IRUSR) os.chmod(cls.server_key, stat.S_IRUSR) os.chmod(cls.server_rootcert, stat.S_IRUSR) # Place conf in the data folder - with open(cls.pg_conf, 'w+') as f: - f.write(QGIS_POSTGRES_CONF_TEMPLATE % { - 'port': cls.port, - 'tempfolder': cls.tempfolder, - 'server_cert': cls.server_cert, - 'server_key': cls.server_key, - 'sslrootcert_path': cls.sslrootcert_path, - }) - - with open(cls.pg_hba, 'w+') as f: + with open(cls.pg_conf, "w+") as f: + f.write( + QGIS_POSTGRES_CONF_TEMPLATE + % { + "port": cls.port, + "tempfolder": cls.tempfolder, + "server_cert": cls.server_cert, + "server_key": cls.server_key, + "sslrootcert_path": cls.sslrootcert_path, + } + ) + + with open(cls.pg_hba, "w+") as f: f.write(QGIS_POSTGRES_HBA_TEMPLATE) @classmethod @@ -139,28 +147,36 @@ def setUpClass(cls): Creates an auth configuration""" super().setUpClass() cls.port = QGIS_POSTGRES_SERVER_PORT - cls.username = 'username' - cls.password = 'password' - cls.dbname = 'test_basic' + cls.username = "username" + cls.password = "password" + cls.dbname = "test_basic" cls.tempfolder = QGIS_PG_TEST_PATH - cls.certsdata_path = os.path.join(unitTestDataPath('auth_system'), 'certs_keys') - cls.hostname = 'localhost' - cls.data_path = os.path.join(cls.tempfolder, 'data') + cls.certsdata_path = os.path.join(unitTestDataPath("auth_system"), "certs_keys") + cls.hostname = "localhost" + cls.data_path = os.path.join(cls.tempfolder, "data") os.mkdir(cls.data_path) cls.setUpAuth() - subprocess.check_call([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'initdb'), '-D', cls.data_path]) + subprocess.check_call( + [os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "initdb"), "-D", cls.data_path] + ) # Disable SSL verification for setup operations env = dict(os.environ) - env['PGSSLMODE'] = 'disable' - - cls.server = subprocess.Popen([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'postgres'), '-D', - cls.data_path, '-c', - f"config_file={cls.pg_conf}"], - env=env, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + env["PGSSLMODE"] = "disable" + + cls.server = subprocess.Popen( + [ + os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "postgres"), + "-D", + cls.data_path, + "-c", + f"config_file={cls.pg_conf}", + ], + env=env, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) # Wait max 10 secs for the server to start end = time.time() + 10 while True: @@ -171,12 +187,46 @@ def setUpClass(cls): if time.time() > end: raise Exception("Timeout connecting to PostgreSQL") # Create a DB - subprocess.check_call([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'createdb'), '-h', 'localhost', '-p', cls.port, 'test_basic'], env=env) + subprocess.check_call( + [ + os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "createdb"), + "-h", + "localhost", + "-p", + cls.port, + "test_basic", + ], + env=env, + ) # Inject test SQL from test path - test_sql = os.path.join(unitTestDataPath('provider'), 'testdata_pg.sql') - subprocess.check_call([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'psql'), '-h', 'localhost', '-p', cls.port, '-f', test_sql, cls.dbname], env=env) + test_sql = os.path.join(unitTestDataPath("provider"), "testdata_pg.sql") + subprocess.check_call( + [ + os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "psql"), + "-h", + "localhost", + "-p", + cls.port, + "-f", + test_sql, + cls.dbname, + ], + env=env, + ) # Create a role - subprocess.check_call([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'psql'), '-h', 'localhost', '-p', cls.port, '-c', f'CREATE ROLE "{cls.username}" WITH SUPERUSER LOGIN PASSWORD \'{cls.password}\'', cls.dbname], env=env) + subprocess.check_call( + [ + os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "psql"), + "-h", + "localhost", + "-p", + cls.port, + "-c", + f"CREATE ROLE \"{cls.username}\" WITH SUPERUSER LOGIN PASSWORD '{cls.password}'", + cls.dbname, + ], + env=env, + ) @classmethod def tearDownClass(cls): @@ -198,40 +248,43 @@ def tearDown(self): pass @classmethod - def _getPostGISLayer(cls, type_name, layer_name=None, authcfg=''): + def _getPostGISLayer(cls, type_name, layer_name=None, authcfg=""): """ PG layer factory """ if layer_name is None: - layer_name = 'pg_' + type_name + layer_name = "pg_" + type_name # Warning: OGR needs the schema if it's not the default, so qgis_test.someData - connstring = "PG:dbname='%(dbname)s' host='%(hostname)s' port='%(port)s' sslmode='verify-full' sslrootcert='%(sslrootcert)s'%(authcfg)s|layername=qgis_test.someData" % ( - { - 'dbname': cls.dbname, - 'hostname': cls.hostname, - 'port': cls.port, - 'authcfg': ' authcfg=\'%s\'' % authcfg if authcfg else '', - 'sslrootcert': cls.sslrootcert_path, - } + connstring = ( + "PG:dbname='%(dbname)s' host='%(hostname)s' port='%(port)s' sslmode='verify-full' sslrootcert='%(sslrootcert)s'%(authcfg)s|layername=qgis_test.someData" + % ( + { + "dbname": cls.dbname, + "hostname": cls.hostname, + "port": cls.port, + "authcfg": " authcfg='%s'" % authcfg if authcfg else "", + "sslrootcert": cls.sslrootcert_path, + } + ) ) - layer = QgsVectorLayer(connstring, layer_name, 'ogr') + layer = QgsVectorLayer(connstring, layer_name, "ogr") return layer def testValidAuthAccess(self): """ Access the protected layer with valid credentials """ - pg_layer = self._getPostGISLayer('testlayer_èé', authcfg=self.auth_config.id()) + pg_layer = self._getPostGISLayer("testlayer_èé", authcfg=self.auth_config.id()) self.assertTrue(pg_layer.isValid()) def testInvalidAuthAccess(self): """ Access the protected layer with not valid credentials """ - pg_layer = self._getPostGISLayer('testlayer_èé') + pg_layer = self._getPostGISLayer("testlayer_èé") self.assertFalse(pg_layer.isValid()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_authmanager_password_ows.py b/tests/src/python/test_authmanager_password_ows.py index 697527e3daa2..7d32740d56d3 100644 --- a/tests/src/python/test_authmanager_password_ows.py +++ b/tests/src/python/test_authmanager_password_ows.py @@ -15,6 +15,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + import os import random import re @@ -26,9 +27,9 @@ from functools import partial -__author__ = 'Alessandro Pasotti' -__date__ = '18/09/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "18/09/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from shutil import rmtree @@ -45,13 +46,13 @@ from utilities import unitTestDataPath, waitServer try: - QGIS_SERVER_ENDPOINT_PORT = os.environ['QGIS_SERVER_ENDPOINT_PORT'] + QGIS_SERVER_ENDPOINT_PORT = os.environ["QGIS_SERVER_ENDPOINT_PORT"] except: - QGIS_SERVER_ENDPOINT_PORT = '0' # Auto + QGIS_SERVER_ENDPOINT_PORT = "0" # Auto QGIS_AUTH_DB_DIR_PATH = tempfile.mkdtemp() -os.environ['QGIS_AUTH_DB_DIR_PATH'] = QGIS_AUTH_DB_DIR_PATH +os.environ["QGIS_AUTH_DB_DIR_PATH"] = QGIS_AUTH_DB_DIR_PATH qgis_app = start_app() @@ -65,44 +66,53 @@ def setUpClass(cls): super().setUpClass() cls.port = QGIS_SERVER_ENDPOINT_PORT # Clean env just to be sure - env_vars = ['QUERY_STRING', 'QGIS_PROJECT_FILE'] + env_vars = ["QUERY_STRING", "QGIS_PROJECT_FILE"] for ev in env_vars: try: del os.environ[ev] except KeyError: pass - cls.testdata_path = unitTestDataPath('qgis_server') + '/' + cls.testdata_path = unitTestDataPath("qgis_server") + "/" cls.project_path = cls.testdata_path + "test_project.qgs" # Enable auth # os.environ['QGIS_AUTH_PASSWORD_FILE'] = QGIS_AUTH_PASSWORD_FILE authm = QgsApplication.authManager() - assert (authm.setMasterPassword('masterpassword', True)) - cls.auth_config = QgsAuthMethodConfig('Basic') - cls.auth_config.setName('test_auth_config') - cls.username = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6)) + assert authm.setMasterPassword("masterpassword", True) + cls.auth_config = QgsAuthMethodConfig("Basic") + cls.auth_config.setName("test_auth_config") + cls.username = "".join( + random.choice(string.ascii_uppercase + string.digits) for _ in range(6) + ) cls.password = cls.username[::-1] # reversed - cls.auth_config.setConfig('username', cls.username) - cls.auth_config.setConfig('password', cls.password) - assert (authm.storeAuthenticationConfig(cls.auth_config)[0]) - cls.hostname = '127.0.0.1' - cls.protocol = 'http' - - os.environ['QGIS_SERVER_HTTP_BASIC_AUTH'] = '1' - os.environ['QGIS_SERVER_USERNAME'] = cls.username - os.environ['QGIS_SERVER_PASSWORD'] = cls.password - os.environ['QGIS_SERVER_PORT'] = str(cls.port) - os.environ['QGIS_SERVER_HOST'] = cls.hostname - - server_path = os.path.dirname(os.path.realpath(__file__)) + \ - '/qgis_wrapped_server.py' - cls.server = subprocess.Popen([sys.executable, server_path], - env=os.environ, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + cls.auth_config.setConfig("username", cls.username) + cls.auth_config.setConfig("password", cls.password) + assert authm.storeAuthenticationConfig(cls.auth_config)[0] + cls.hostname = "127.0.0.1" + cls.protocol = "http" + + os.environ["QGIS_SERVER_HTTP_BASIC_AUTH"] = "1" + os.environ["QGIS_SERVER_USERNAME"] = cls.username + os.environ["QGIS_SERVER_PASSWORD"] = cls.password + os.environ["QGIS_SERVER_PORT"] = str(cls.port) + os.environ["QGIS_SERVER_HOST"] = cls.hostname + + server_path = ( + os.path.dirname(os.path.realpath(__file__)) + "/qgis_wrapped_server.py" + ) + cls.server = subprocess.Popen( + [sys.executable, server_path], + env=os.environ, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) line = cls.server.stdout.readline() - cls.port = int(re.findall(br':(\d+)', line)[0]) + cls.port = int(re.findall(rb":(\d+)", line)[0]) assert cls.port != 0 # Wait for the server process to start - assert waitServer(f'{cls.protocol}://{cls.hostname}:{cls.port}'), f"Server is not responding! {cls.protocol}://{cls.hostname}:{cls.port}" + assert waitServer( + f"{cls.protocol}://{cls.hostname}:{cls.port}" + ), f"Server is not responding! {cls.protocol}://{cls.hostname}:{cls.port}" @classmethod def tearDownClass(cls): @@ -126,18 +136,18 @@ def _getWFSLayer(cls, type_name, layer_name=None, authcfg=None): WFS layer factory """ if layer_name is None: - layer_name = 'wfs_' + type_name + layer_name = "wfs_" + type_name parms = { - 'srsname': 'EPSG:4326', - 'typename': type_name, - 'url': f'{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}', - 'version': 'auto', - 'table': '', + "srsname": "EPSG:4326", + "typename": type_name, + "url": f"{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}", + "version": "auto", + "table": "", } if authcfg is not None: - parms.update({'authcfg': authcfg}) - uri = ' '.join([(f"{k}='{v}'") for k, v in list(parms.items())]) - wfs_layer = QgsVectorLayer(uri, layer_name, 'WFS') + parms.update({"authcfg": authcfg}) + uri = " ".join([(f"{k}='{v}'") for k, v in list(parms.items())]) + wfs_layer = QgsVectorLayer(uri, layer_name, "WFS") return wfs_layer @classmethod @@ -146,21 +156,21 @@ def _getWMSLayer(cls, layers, layer_name=None, authcfg=None): WMS layer factory """ if layer_name is None: - layer_name = 'wms_' + layers.replace(',', '') + layer_name = "wms_" + layers.replace(",", "") parms = { - 'crs': 'EPSG:4326', - 'url': f'{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}', + "crs": "EPSG:4326", + "url": f"{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}", # This is needed because of a really weird implementation in QGIS Server, that # replaces _ in the the real layer name with spaces - 'layers': urllib.parse.quote(layers.replace('_', ' ')), - 'styles': '', - 'version': 'auto', + "layers": urllib.parse.quote(layers.replace("_", " ")), + "styles": "", + "version": "auto", # 'sql': '', } if authcfg is not None: - parms.update({'authcfg': authcfg}) - uri = '&'.join([f"{k}={v.replace('=', '%3D')}" for k, v in list(parms.items())]) - wms_layer = QgsRasterLayer(uri, layer_name, 'wms') + parms.update({"authcfg": authcfg}) + uri = "&".join([f"{k}={v.replace('=', '%3D')}" for k, v in list(parms.items())]) + wms_layer = QgsRasterLayer(uri, layer_name, "wms") return wms_layer @classmethod @@ -169,99 +179,119 @@ def _getGeoJsonLayer(cls, type_name, layer_name=None, authcfg=None): OGR layer factory """ if layer_name is None: - layer_name = 'geojson_' + type_name - uri = f'{cls.protocol}://{cls.hostname}:{cls.port}/?MAP={cls.project_path}&SERVICE=WFS&REQUEST=GetFeature&TYPENAME={urllib.parse.quote(type_name)}&VERSION=2.0.0&OUTPUTFORMAT=geojson' + layer_name = "geojson_" + type_name + uri = f"{cls.protocol}://{cls.hostname}:{cls.port}/?MAP={cls.project_path}&SERVICE=WFS&REQUEST=GetFeature&TYPENAME={urllib.parse.quote(type_name)}&VERSION=2.0.0&OUTPUTFORMAT=geojson" if authcfg is not None: uri += f" authcfg='{authcfg}'" - geojson_layer = QgsVectorLayer(uri, layer_name, 'ogr') + geojson_layer = QgsVectorLayer(uri, layer_name, "ogr") return geojson_layer def testValidAuthAccess(self): """ Access the HTTP Basic protected layer with valid credentials """ - wfs_layer = self._getWFSLayer('testlayer_èé', authcfg=self.auth_config.id()) + wfs_layer = self._getWFSLayer("testlayer_èé", authcfg=self.auth_config.id()) self.assertTrue(wfs_layer.isValid()) - wms_layer = self._getWMSLayer('testlayer_èé', authcfg=self.auth_config.id()) + wms_layer = self._getWMSLayer("testlayer_èé", authcfg=self.auth_config.id()) self.assertTrue(wms_layer.isValid()) - geojson_layer = self._getGeoJsonLayer('testlayer_èé', authcfg=self.auth_config.id()) + geojson_layer = self._getGeoJsonLayer( + "testlayer_èé", authcfg=self.auth_config.id() + ) self.assertTrue(geojson_layer.isValid()) def testInvalidAuthAccess(self): """ Access the HTTP Basic protected layer with no credentials """ - wfs_layer = self._getWFSLayer('testlayer èé') + wfs_layer = self._getWFSLayer("testlayer èé") self.assertFalse(wfs_layer.isValid()) - wms_layer = self._getWMSLayer('testlayer_èé') + wms_layer = self._getWMSLayer("testlayer_èé") self.assertFalse(wms_layer.isValid()) - geojson_layer = self._getGeoJsonLayer('testlayer_èé') + geojson_layer = self._getGeoJsonLayer("testlayer_èé") self.assertFalse(geojson_layer.isValid()) def testInvalidAuthFileDownload(self): """ Download a protected map tile without authcfg """ - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.project_path), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "testlayer_èé".replace('_', '%20'), - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) - url = f'{self.protocol}://{self.hostname}:{self.port}/{qs}' + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.project_path), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "testlayer_èé".replace("_", "%20"), + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) + url = f"{self.protocol}://{self.hostname}:{self.port}/{qs}" destination = tempfile.mktemp() loop = QEventLoop() downloader = QgsFileDownloader(QUrl(url), destination, None, False) - downloader.downloadCompleted.connect(partial(self._set_slot, 'completed')) - downloader.downloadExited.connect(partial(self._set_slot, 'exited')) - downloader.downloadCanceled.connect(partial(self._set_slot, 'canceled')) - downloader.downloadError.connect(partial(self._set_slot, 'error')) - downloader.downloadProgress.connect(partial(self._set_slot, 'progress')) + downloader.downloadCompleted.connect(partial(self._set_slot, "completed")) + downloader.downloadExited.connect(partial(self._set_slot, "exited")) + downloader.downloadCanceled.connect(partial(self._set_slot, "canceled")) + downloader.downloadError.connect(partial(self._set_slot, "error")) + downloader.downloadProgress.connect(partial(self._set_slot, "progress")) downloader.downloadExited.connect(loop.quit) loop.exec() self.assertTrue(self.error_was_called) - self.assertIn("Download failed: Host requires authentication", str(self.error_args)) + self.assertIn( + "Download failed: Host requires authentication", str(self.error_args) + ) def testValidAuthFileDownload(self): """ Download a map tile with valid authcfg """ - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.project_path), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "testlayer_èé".replace('_', '%20'), - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) - url = f'{self.protocol}://{self.hostname}:{self.port}/{qs}' + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.project_path), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "testlayer_èé".replace("_", "%20"), + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) + url = f"{self.protocol}://{self.hostname}:{self.port}/{qs}" destination = tempfile.mktemp() loop = QEventLoop() - downloader = QgsFileDownloader(QUrl(url), destination, self.auth_config.id(), False) - downloader.downloadCompleted.connect(partial(self._set_slot, 'completed')) - downloader.downloadExited.connect(partial(self._set_slot, 'exited')) - downloader.downloadCanceled.connect(partial(self._set_slot, 'canceled')) - downloader.downloadError.connect(partial(self._set_slot, 'error')) - downloader.downloadProgress.connect(partial(self._set_slot, 'progress')) + downloader = QgsFileDownloader( + QUrl(url), destination, self.auth_config.id(), False + ) + downloader.downloadCompleted.connect(partial(self._set_slot, "completed")) + downloader.downloadExited.connect(partial(self._set_slot, "exited")) + downloader.downloadCanceled.connect(partial(self._set_slot, "canceled")) + downloader.downloadError.connect(partial(self._set_slot, "error")) + downloader.downloadProgress.connect(partial(self._set_slot, "progress")) downloader.downloadExited.connect(loop.quit) @@ -270,14 +300,14 @@ def testValidAuthFileDownload(self): # Check the we've got a likely PNG image self.assertTrue(self.completed_was_called) self.assertGreater(os.path.getsize(destination), 2000) # > 1MB - with open(destination, 'rb') as f: - self.assertTrue(b'PNG' in f.read()) # is a PNG + with open(destination, "rb") as f: + self.assertTrue(b"PNG" in f.read()) # is a PNG def _set_slot(self, *args, **kwargs): # print('_set_slot(%s) called' % args[0]) - setattr(self, args[0] + '_was_called', True) - setattr(self, args[0] + '_args', args) + setattr(self, args[0] + "_was_called", True) + setattr(self, args[0] + "_args", args) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_authmanager_password_postgres.py b/tests/src/python/test_authmanager_password_postgres.py index ab27daae3104..7911b6eea333 100644 --- a/tests/src/python/test_authmanager_password_postgres.py +++ b/tests/src/python/test_authmanager_password_postgres.py @@ -20,6 +20,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + import os from contextlib import contextmanager @@ -36,9 +37,9 @@ from utilities import unitTestDataPath -__author__ = 'Alessandro Pasotti' -__date__ = '25/10/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "25/10/2016" +__copyright__ = "Copyright 2016, The QGIS Project" qgis_app = start_app() @@ -51,9 +52,9 @@ def ScopedCertAuthority(username, password, sslrootcert_path=None): """ authm = QgsApplication.authManager() auth_config = QgsAuthMethodConfig("Basic") - auth_config.setConfig('username', username) - auth_config.setConfig('password', password) - auth_config.setName('test_password_auth_config') + auth_config.setConfig("username", username) + auth_config.setConfig("password", password) + auth_config.setName("test_password_auth_config") if sslrootcert_path: sslrootcert = QSslCertificate.fromPath(sslrootcert_path) assert sslrootcert is not None @@ -61,7 +62,7 @@ def ScopedCertAuthority(username, password, sslrootcert_path=None): authm.rebuildCaCertsCache() authm.rebuildTrustedCaCertsCache() authm.rebuildCertTrustCache() - assert (authm.storeAuthenticationConfig(auth_config)[0]) + assert authm.storeAuthenticationConfig(auth_config)[0] assert auth_config.isValid() yield auth_config if sslrootcert_path: @@ -79,16 +80,18 @@ def setUpClass(cls): """Run before all tests: Creates an auth configuration""" super().setUpClass() - cls.username = 'docker' - cls.password = 'docker' - cls.dbname = 'qgis_test' - cls.hostname = 'postgres' - cls.port = '5432' + cls.username = "docker" + cls.password = "docker" + cls.dbname = "qgis_test" + cls.hostname = "postgres" + cls.port = "5432" authm = QgsApplication.authManager() - assert (authm.setMasterPassword('masterpassword', True)) - cls.certsdata_path = os.path.join(unitTestDataPath('auth_system'), 'certs_keys_2048') - cls.sslrootcert_path = os.path.join(cls.certsdata_path, 'qgis_ca.crt') + assert authm.setMasterPassword("masterpassword", True) + cls.certsdata_path = os.path.join( + unitTestDataPath("auth_system"), "certs_keys_2048" + ) + cls.sslrootcert_path = os.path.join(cls.certsdata_path, "qgis_ca.crt") def setUp(self): """Run before each test.""" @@ -99,36 +102,46 @@ def tearDown(self): pass @classmethod - def _getPostGISLayer(cls, type_name, layer_name=None, authcfg=None, sslmode=QgsDataSourceUri.SslMode.SslVerifyFull): + def _getPostGISLayer( + cls, + type_name, + layer_name=None, + authcfg=None, + sslmode=QgsDataSourceUri.SslMode.SslVerifyFull, + ): """ PG layer factory """ if layer_name is None: - layer_name = 'pg_' + type_name + layer_name = "pg_" + type_name uri = QgsDataSourceUri() uri.setWkbType(QgsWkbTypes.Type.Point) uri.setConnection(cls.hostname, cls.port, cls.dbname, "", "", sslmode, authcfg) - uri.setKeyColumn('pk') - uri.setSrid('EPSG:4326') - uri.setDataSource('qgis_test', 'someData', "geom", "", "pk") + uri.setKeyColumn("pk") + uri.setSrid("EPSG:4326") + uri.setDataSource("qgis_test", "someData", "geom", "", "pk") # Note: do not expand here! - layer = QgsVectorLayer(uri.uri(False), layer_name, 'postgres') + layer = QgsVectorLayer(uri.uri(False), layer_name, "postgres") return layer def testValidAuthAccess(self): """ Access the protected layer with valid credentials """ - with ScopedCertAuthority(self.username, self.password, self.sslrootcert_path) as auth_config: - pg_layer = self._getPostGISLayer('testlayer_èé', authcfg=auth_config.id()) + with ScopedCertAuthority( + self.username, self.password, self.sslrootcert_path + ) as auth_config: + pg_layer = self._getPostGISLayer("testlayer_èé", authcfg=auth_config.id()) self.assertTrue(pg_layer.isValid()) def testInvalidAuthAccess(self): """ Access the protected layer with invalid credentials """ - with ScopedCertAuthority(self.username, self.password, self.sslrootcert_path) as auth_config: - pg_layer = self._getPostGISLayer('testlayer_èé') + with ScopedCertAuthority( + self.username, self.password, self.sslrootcert_path + ) as auth_config: + pg_layer = self._getPostGISLayer("testlayer_èé") self.assertFalse(pg_layer.isValid()) def testSslRequireNoCaCheck(self): @@ -137,7 +150,11 @@ def testSslRequireNoCaCheck(self): This should work. """ with ScopedCertAuthority(self.username, self.password) as auth_config: - pg_layer = self._getPostGISLayer('testlayer_èé', authcfg=auth_config.id(), sslmode=QgsDataSourceUri.SslMode.SslRequire) + pg_layer = self._getPostGISLayer( + "testlayer_èé", + authcfg=auth_config.id(), + sslmode=QgsDataSourceUri.SslMode.SslRequire, + ) self.assertTrue(pg_layer.isValid()) def testSslVerifyFullCaCheck(self): @@ -146,9 +163,9 @@ def testSslVerifyFullCaCheck(self): This should not work. """ with ScopedCertAuthority(self.username, self.password) as auth_config: - pg_layer = self._getPostGISLayer('testlayer_èé', authcfg=auth_config.id()) + pg_layer = self._getPostGISLayer("testlayer_èé", authcfg=auth_config.id()) self.assertFalse(pg_layer.isValid()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_authmanager_pki_ows.py b/tests/src/python/test_authmanager_pki_ows.py index b2378313918e..1ec1e012fab4 100644 --- a/tests/src/python/test_authmanager_pki_ows.py +++ b/tests/src/python/test_authmanager_pki_ows.py @@ -14,6 +14,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + import os import re import stat @@ -22,9 +23,9 @@ import tempfile import urllib -__author__ = 'Alessandro Pasotti' -__date__ = '25/10/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "25/10/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from shutil import rmtree @@ -40,13 +41,13 @@ from utilities import unitTestDataPath, waitServer try: - QGIS_SERVER_ENDPOINT_PORT = os.environ['QGIS_SERVER_ENDPOINT_PORT'] + QGIS_SERVER_ENDPOINT_PORT = os.environ["QGIS_SERVER_ENDPOINT_PORT"] except: - QGIS_SERVER_ENDPOINT_PORT = '0' # Auto + QGIS_SERVER_ENDPOINT_PORT = "0" # Auto QGIS_AUTH_DB_DIR_PATH = tempfile.mkdtemp() -os.environ['QGIS_AUTH_DB_DIR_PATH'] = QGIS_AUTH_DB_DIR_PATH +os.environ["QGIS_AUTH_DB_DIR_PATH"] = QGIS_AUTH_DB_DIR_PATH qgis_app = start_app() @@ -57,10 +58,10 @@ class TestAuthManager(QgisTestCase): def setUpAuth(cls): """Run before all tests and set up authentication""" authm = QgsApplication.authManager() - assert (authm.setMasterPassword('masterpassword', True)) - cls.sslrootcert_path = os.path.join(cls.certsdata_path, 'qgis_ca.crt') - cls.sslcert = os.path.join(cls.certsdata_path, 'Gerardus.crt') - cls.sslkey = os.path.join(cls.certsdata_path, 'Gerardus.key') + assert authm.setMasterPassword("masterpassword", True) + cls.sslrootcert_path = os.path.join(cls.certsdata_path, "qgis_ca.crt") + cls.sslcert = os.path.join(cls.certsdata_path, "Gerardus.crt") + cls.sslkey = os.path.join(cls.certsdata_path, "Gerardus.key") assert os.path.isfile(cls.sslcert) assert os.path.isfile(cls.sslkey) assert os.path.isfile(cls.sslrootcert_path) @@ -68,31 +69,31 @@ def setUpAuth(cls): os.chmod(cls.sslkey, stat.S_IRUSR) os.chmod(cls.sslrootcert_path, stat.S_IRUSR) cls.auth_config = QgsAuthMethodConfig("PKI-Paths") - cls.auth_config.setConfig('certpath', cls.sslcert) - cls.auth_config.setConfig('keypath', cls.sslkey) - cls.auth_config.setName('test_pki_auth_config') - cls.username = 'Gerardus' + cls.auth_config.setConfig("certpath", cls.sslcert) + cls.auth_config.setConfig("keypath", cls.sslkey) + cls.auth_config.setName("test_pki_auth_config") + cls.username = "Gerardus" cls.sslrootcert = QSslCertificate.fromPath(cls.sslrootcert_path) assert cls.sslrootcert is not None authm.storeCertAuthorities(cls.sslrootcert) authm.rebuildCaCertsCache() authm.rebuildTrustedCaCertsCache() - assert (authm.storeAuthenticationConfig(cls.auth_config)[0]) + assert authm.storeAuthenticationConfig(cls.auth_config)[0] assert cls.auth_config.isValid() - cls.server_cert = os.path.join(cls.certsdata_path, '127_0_0_1.crt') - cls.server_key = os.path.join(cls.certsdata_path, '127_0_0_1.key') + cls.server_cert = os.path.join(cls.certsdata_path, "127_0_0_1.crt") + cls.server_key = os.path.join(cls.certsdata_path, "127_0_0_1.key") cls.server_rootcert = cls.sslrootcert_path os.chmod(cls.server_cert, stat.S_IRUSR) os.chmod(cls.server_key, stat.S_IRUSR) os.chmod(cls.server_rootcert, stat.S_IRUSR) - os.environ['QGIS_SERVER_HOST'] = cls.hostname - os.environ['QGIS_SERVER_PORT'] = str(cls.port) - os.environ['QGIS_SERVER_PKI_KEY'] = cls.server_key - os.environ['QGIS_SERVER_PKI_CERTIFICATE'] = cls.server_cert - os.environ['QGIS_SERVER_PKI_USERNAME'] = cls.username - os.environ['QGIS_SERVER_PKI_AUTHORITY'] = cls.server_rootcert + os.environ["QGIS_SERVER_HOST"] = cls.hostname + os.environ["QGIS_SERVER_PORT"] = str(cls.port) + os.environ["QGIS_SERVER_PKI_KEY"] = cls.server_key + os.environ["QGIS_SERVER_PKI_CERTIFICATE"] = cls.server_cert + os.environ["QGIS_SERVER_PKI_USERNAME"] = cls.username + os.environ["QGIS_SERVER_PKI_AUTHORITY"] = cls.server_rootcert @classmethod def setUpClass(cls): @@ -101,30 +102,36 @@ def setUpClass(cls): super().setUpClass() cls.port = QGIS_SERVER_ENDPOINT_PORT # Clean env just to be sure - env_vars = ['QUERY_STRING', 'QGIS_PROJECT_FILE'] + env_vars = ["QUERY_STRING", "QGIS_PROJECT_FILE"] for ev in env_vars: try: del os.environ[ev] except KeyError: pass - cls.testdata_path = unitTestDataPath('qgis_server') - cls.certsdata_path = os.path.join(unitTestDataPath('auth_system'), 'certs_keys_2048') + cls.testdata_path = unitTestDataPath("qgis_server") + cls.certsdata_path = os.path.join( + unitTestDataPath("auth_system"), "certs_keys_2048" + ) cls.project_path = os.path.join(cls.testdata_path, "test_project.qgs") # cls.hostname = 'localhost' - cls.protocol = 'https' - cls.hostname = '127.0.0.1' + cls.protocol = "https" + cls.hostname = "127.0.0.1" cls.setUpAuth() - server_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), - 'qgis_wrapped_server.py') - cls.server = subprocess.Popen([sys.executable, server_path], - env=os.environ, stdout=subprocess.PIPE) + server_path = os.path.join( + os.path.dirname(os.path.realpath(__file__)), "qgis_wrapped_server.py" + ) + cls.server = subprocess.Popen( + [sys.executable, server_path], env=os.environ, stdout=subprocess.PIPE + ) line = cls.server.stdout.readline() - cls.port = int(re.findall(br':(\d+)', line)[0]) + cls.port = int(re.findall(rb":(\d+)", line)[0]) assert cls.port != 0 # Wait for the server process to start - assert waitServer(f'{cls.protocol}://{cls.hostname}:{cls.port}'), f"Server is not responding! {cls.protocol}://{cls.hostname}:{cls.port}" + assert waitServer( + f"{cls.protocol}://{cls.hostname}:{cls.port}" + ), f"Server is not responding! {cls.protocol}://{cls.hostname}:{cls.port}" @classmethod def tearDownClass(cls): @@ -148,18 +155,18 @@ def _getWFSLayer(cls, type_name, layer_name=None, authcfg=None): WFS layer factory """ if layer_name is None: - layer_name = 'wfs_' + type_name + layer_name = "wfs_" + type_name parms = { - 'srsname': 'EPSG:4326', - 'typename': type_name, - 'url': f'{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}', - 'version': 'auto', - 'table': '', + "srsname": "EPSG:4326", + "typename": type_name, + "url": f"{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}", + "version": "auto", + "table": "", } if authcfg is not None: - parms.update({'authcfg': authcfg}) - uri = ' '.join([(f"{k}='{v}'") for k, v in list(parms.items())]) - wfs_layer = QgsVectorLayer(uri, layer_name, 'WFS') + parms.update({"authcfg": authcfg}) + uri = " ".join([(f"{k}='{v}'") for k, v in list(parms.items())]) + wfs_layer = QgsVectorLayer(uri, layer_name, "WFS") return wfs_layer @classmethod @@ -168,22 +175,22 @@ def _getWMSLayer(cls, layers, layer_name=None, authcfg=None): WMS layer factory """ if layer_name is None: - layer_name = 'wms_' + layers.replace(',', '') + layer_name = "wms_" + layers.replace(",", "") parms = { - 'crs': 'EPSG:4326', - 'url': f'{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}', - 'format': 'image/png', + "crs": "EPSG:4326", + "url": f"{cls.protocol}://{cls.hostname}:{cls.port}/?map={cls.project_path}", + "format": "image/png", # This is needed because of a really weird implementation in QGIS Server, that # replaces _ in the the real layer name with spaces - 'layers': urllib.parse.quote(layers.replace('_', ' ')), - 'styles': '', - 'version': 'auto', + "layers": urllib.parse.quote(layers.replace("_", " ")), + "styles": "", + "version": "auto", # 'sql': '', } if authcfg is not None: - parms.update({'authcfg': authcfg}) - uri = '&'.join([f"{k}={v.replace('=', '%3D')}" for k, v in list(parms.items())]) - wms_layer = QgsRasterLayer(uri, layer_name, 'wms') + parms.update({"authcfg": authcfg}) + uri = "&".join([f"{k}={v.replace('=', '%3D')}" for k, v in list(parms.items())]) + wms_layer = QgsRasterLayer(uri, layer_name, "wms") return wms_layer def testValidAuthAccess(self): @@ -192,11 +199,11 @@ def testValidAuthAccess(self): Note: cannot test invalid access in a separate test because it would fail the subsequent (valid) calls due to cached connections """ - wfs_layer = self._getWFSLayer('testlayer_èé', authcfg=self.auth_config.id()) + wfs_layer = self._getWFSLayer("testlayer_èé", authcfg=self.auth_config.id()) self.assertTrue(wfs_layer.isValid()) - wms_layer = self._getWMSLayer('testlayer_èé', authcfg=self.auth_config.id()) + wms_layer = self._getWMSLayer("testlayer_èé", authcfg=self.auth_config.id()) self.assertTrue(wms_layer.isValid()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_authmanager_pki_postgres.py b/tests/src/python/test_authmanager_pki_postgres.py index 3ab2b6a47b01..2928a9206482 100644 --- a/tests/src/python/test_authmanager_pki_postgres.py +++ b/tests/src/python/test_authmanager_pki_postgres.py @@ -20,6 +20,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + import glob import os import stat @@ -39,9 +40,9 @@ from utilities import unitTestDataPath -__author__ = 'Alessandro Pasotti' -__date__ = '25/10/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "25/10/2016" +__copyright__ = "Copyright 2016, The QGIS Project" qgis_app = start_app() @@ -52,11 +53,11 @@ class TestAuthManager(QgisTestCase): def setUpAuth(cls): """Run before all tests and set up authentication""" authm = QgsApplication.authManager() - assert (authm.setMasterPassword('masterpassword', True)) + assert authm.setMasterPassword("masterpassword", True) # Client side - cls.sslrootcert_path = os.path.join(cls.certsdata_path, 'qgis_ca.crt') - cls.sslcert = os.path.join(cls.certsdata_path, 'docker.crt') - cls.sslkey = os.path.join(cls.certsdata_path, 'docker.key') + cls.sslrootcert_path = os.path.join(cls.certsdata_path, "qgis_ca.crt") + cls.sslcert = os.path.join(cls.certsdata_path, "docker.crt") + cls.sslkey = os.path.join(cls.certsdata_path, "docker.key") assert os.path.isfile(cls.sslcert) assert os.path.isfile(cls.sslkey) assert os.path.isfile(cls.sslrootcert_path) @@ -64,21 +65,21 @@ def setUpAuth(cls): os.chmod(cls.sslkey, stat.S_IRUSR) os.chmod(cls.sslrootcert_path, stat.S_IRUSR) cls.auth_config = QgsAuthMethodConfig("PKI-Paths") - cls.auth_config.setConfig('certpath', cls.sslcert) - cls.auth_config.setConfig('keypath', cls.sslkey) - cls.auth_config.setName('test_pki_auth_config') - cls.pg_user = 'docker' - cls.pg_pass = 'docker' - cls.pg_host = 'postgres' - cls.pg_port = '5432' - cls.pg_dbname = 'qgis_test' + cls.auth_config.setConfig("certpath", cls.sslcert) + cls.auth_config.setConfig("keypath", cls.sslkey) + cls.auth_config.setName("test_pki_auth_config") + cls.pg_user = "docker" + cls.pg_pass = "docker" + cls.pg_host = "postgres" + cls.pg_port = "5432" + cls.pg_dbname = "qgis_test" cls.sslrootcert = QSslCertificate.fromPath(cls.sslrootcert_path) assert cls.sslrootcert is not None authm.storeCertAuthorities(cls.sslrootcert) authm.rebuildCaCertsCache() authm.rebuildTrustedCaCertsCache() authm.rebuildCertTrustCache() - assert (authm.storeAuthenticationConfig(cls.auth_config)[0]) + assert authm.storeAuthenticationConfig(cls.auth_config)[0] assert cls.auth_config.isValid() @classmethod @@ -87,7 +88,9 @@ def setUpClass(cls): Creates an auth configuration""" super().setUpClass() - cls.certsdata_path = os.path.join(unitTestDataPath('auth_system'), 'certs_keys_2048') + cls.certsdata_path = os.path.join( + unitTestDataPath("auth_system"), "certs_keys_2048" + ) cls.setUpAuth() def setUp(self): @@ -104,29 +107,37 @@ def _getPostGISLayer(cls, type_name, layer_name=None, authcfg=None): PG layer factory """ if layer_name is None: - layer_name = 'pg_' + type_name + layer_name = "pg_" + type_name uri = QgsDataSourceUri() uri.setWkbType(QgsWkbTypes.Type.Point) - uri.setConnection(cls.pg_host, cls.pg_port, cls.pg_dbname, cls.pg_user, cls.pg_pass, QgsDataSourceUri.SslMode.SslVerifyFull, authcfg) - uri.setKeyColumn('pk') - uri.setSrid('EPSG:4326') - uri.setDataSource('qgis_test', 'someData', "geom", "", "pk") + uri.setConnection( + cls.pg_host, + cls.pg_port, + cls.pg_dbname, + cls.pg_user, + cls.pg_pass, + QgsDataSourceUri.SslMode.SslVerifyFull, + authcfg, + ) + uri.setKeyColumn("pk") + uri.setSrid("EPSG:4326") + uri.setDataSource("qgis_test", "someData", "geom", "", "pk") # Note: do not expand here! - layer = QgsVectorLayer(uri.uri(False), layer_name, 'postgres') + layer = QgsVectorLayer(uri.uri(False), layer_name, "postgres") return layer def testValidAuthAccess(self): """ Access the protected layer with valid credentials """ - pg_layer = self._getPostGISLayer('testlayer_èé', authcfg=self.auth_config.id()) + pg_layer = self._getPostGISLayer("testlayer_èé", authcfg=self.auth_config.id()) self.assertTrue(pg_layer.isValid()) def testInvalidAuthAccess(self): """ Access the protected layer with not valid credentials """ - pg_layer = self._getPostGISLayer('testlayer_èé') + pg_layer = self._getPostGISLayer("testlayer_èé") self.assertFalse(pg_layer.isValid()) def testRemoveTemporaryCerts(self): @@ -136,7 +147,7 @@ def testRemoveTemporaryCerts(self): """ def cleanTempPki(): - pkies = glob.glob(os.path.join(tempfile.gettempdir(), 'tmp*_{*}.pem')) + pkies = glob.glob(os.path.join(tempfile.gettempdir(), "tmp*_{*}.pem")) for fn in pkies: f = QFile(fn) f.setPermissions(QFile.Permission.WriteOwner) @@ -146,12 +157,12 @@ def cleanTempPki(): # other pki remain after connection cleanTempPki() # connect using postgres provider - pg_layer = self._getPostGISLayer('testlayer_èé', authcfg=self.auth_config.id()) + pg_layer = self._getPostGISLayer("testlayer_èé", authcfg=self.auth_config.id()) self.assertTrue(pg_layer.isValid()) # do test no certs remained - pkies = glob.glob(os.path.join(tempfile.gettempdir(), 'tmp*_{*}.pem')) + pkies = glob.glob(os.path.join(tempfile.gettempdir(), "tmp*_{*}.pem")) self.assertEqual(len(pkies), 0) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_authmanager_proxy.py b/tests/src/python/test_authmanager_proxy.py index ee87283ab12c..90efff340c13 100644 --- a/tests/src/python/test_authmanager_proxy.py +++ b/tests/src/python/test_authmanager_proxy.py @@ -9,6 +9,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + import os import random import string @@ -24,13 +25,13 @@ import unittest from qgis.testing import start_app, QgisTestCase -__author__ = 'Alessandro Pasotti' -__date__ = '27/09/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "27/09/2017" +__copyright__ = "Copyright 2017, The QGIS Project" QGIS_AUTH_DB_DIR_PATH = tempfile.mkdtemp() -os.environ['QGIS_AUTH_DB_DIR_PATH'] = QGIS_AUTH_DB_DIR_PATH +os.environ["QGIS_AUTH_DB_DIR_PATH"] = QGIS_AUTH_DB_DIR_PATH qgis_app = start_app() @@ -45,14 +46,16 @@ def setUpClass(cls): # Enable auth # os.environ['QGIS_AUTH_PASSWORD_FILE'] = QGIS_AUTH_PASSWORD_FILE authm = QgsApplication.authManager() - assert (authm.setMasterPassword('masterpassword', True)) - cls.auth_config = QgsAuthMethodConfig('Basic') - cls.auth_config.setName('test_auth_config') - cls.username = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6)) + assert authm.setMasterPassword("masterpassword", True) + cls.auth_config = QgsAuthMethodConfig("Basic") + cls.auth_config.setName("test_auth_config") + cls.username = "".join( + random.choice(string.ascii_uppercase + string.digits) for _ in range(6) + ) cls.password = cls.username[::-1] # reversed - cls.auth_config.setConfig('username', cls.username) - cls.auth_config.setConfig('password', cls.password) - assert (authm.storeAuthenticationConfig(cls.auth_config)[0]) + cls.auth_config.setConfig("username", cls.username) + cls.auth_config.setConfig("password", cls.password) + assert authm.storeAuthenticationConfig(cls.auth_config)[0] @classmethod def tearDownClass(cls): @@ -75,8 +78,8 @@ def testProxyIsUpdated(self): authm = QgsApplication.authManager() nam = QgsNetworkAccessManager.instance() proxy = nam.proxy() - self.assertEqual(proxy.password(), '') - self.assertEqual(proxy.user(), '') + self.assertEqual(proxy.password(), "") + self.assertEqual(proxy.user(), "") self.assertTrue(authm.updateNetworkProxy(proxy, self.auth_config.id())) self.assertEqual(proxy.user(), self.username) self.assertEqual(proxy.password(), self.password) @@ -88,17 +91,17 @@ def testProxyIsUpdatedByUserSettings(self): nam = QgsNetworkAccessManager.instance() nam.setupDefaultProxyAndCache() proxy = nam.proxy() - self.assertEqual(proxy.password(), '') - self.assertEqual(proxy.user(), '') + self.assertEqual(proxy.password(), "") + self.assertEqual(proxy.user(), "") settings = QgsSettings() settings.setValue("proxy/authcfg", self.auth_config.id()) settings.setValue("proxy/proxyEnabled", True) - del (settings) + del settings nam.setupDefaultProxyAndCache() proxy = nam.fallbackProxy() self.assertEqual(proxy.password(), self.password) self.assertEqual(proxy.user(), self.username) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_authmanager_storage_base.py b/tests/src/python/test_authmanager_storage_base.py index fdf3aae4e718..94cb07a09cc6 100644 --- a/tests/src/python/test_authmanager_storage_base.py +++ b/tests/src/python/test_authmanager_storage_base.py @@ -26,9 +26,9 @@ from qgis.testing import start_app, QgisTestCase from utilities import unitTestDataPath -__author__ = 'Alessandro Pasotti' -__date__ = '2024-06-24' -__copyright__ = 'Copyright 2024, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "2024-06-24" +__copyright__ = "Copyright 2024, The QGIS Project" class AuthManagerStorageBaseTestCase(QgisTestCase): @@ -44,7 +44,7 @@ def setUpClass(cls): super().setUpClass() if cls.storage_uri is not None: - os.environ['QGIS_AUTH_DB_URI'] = cls.storage_uri + os.environ["QGIS_AUTH_DB_URI"] = cls.storage_uri QCoreApplication.setOrganizationName("QGIS_Test") QCoreApplication.setOrganizationDomain("%s.com" % __name__) @@ -52,23 +52,32 @@ def setUpClass(cls): QgsSettings().clear() start_app() - cls.certdata_path = os.path.join(unitTestDataPath('auth_system'), 'certs_keys_2048') + cls.certdata_path = os.path.join( + unitTestDataPath("auth_system"), "certs_keys_2048" + ) -class TestAuthManagerStorageBase(): +class TestAuthManagerStorageBase: def testInitialized(self): assert self.storage is not None self.assertTrue(self.storage.initialize()) if issubclass(type(self.storage), QgsAuthConfigurationStorageDb): - for table in ['auth_authorities', 'auth_identities', 'auth_servers', 'auth_settings', 'auth_trust', 'auth_configs']: + for table in [ + "auth_authorities", + "auth_identities", + "auth_servers", + "auth_settings", + "auth_trust", + "auth_configs", + ]: self.assertTrue(self.storage.tableExists(table)) def testDefaultStorage(self): if self.storage_uri is None: - raise unittest.SkipTest('No storage URI defined') + raise unittest.SkipTest("No storage URI defined") auth_manager = QgsApplication.authManager() auth_manager.ensureInitialized() @@ -79,75 +88,289 @@ def testDefaultStorage(self): # Verify that the registry has the storage registry = QgsApplication.authConfigurationStorageRegistry() storage = registry.readyStorages()[0] - self.assertEqual(storage.settings()['database'], self.storage.settings()['database']) - self.assertEqual(storage.settings()['driver'], self.storage.settings()['driver']) + self.assertEqual( + storage.settings()["database"], self.storage.settings()["database"] + ) + self.assertEqual( + storage.settings()["driver"], self.storage.settings()["driver"] + ) def _assert_readonly(self, storage): self.assertTrue(storage.isReadOnly()) - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadConfiguration)) - self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteConfiguration)) - self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateConfiguration)) - self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateConfiguration)) - - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadSetting)) - self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteSetting)) - self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateSetting)) - self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateSetting)) - - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateIdentity)) - self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteCertificateIdentity)) - self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateCertificateIdentity)) - self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateCertificateIdentity)) - - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadSslCertificateCustomConfig)) - self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteSslCertificateCustomConfig)) - self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateSslCertificateCustomConfig)) - self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateSslCertificateCustomConfig)) - - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateTrustPolicy)) - self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteCertificateTrustPolicy)) - self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateCertificateTrustPolicy)) - self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateCertificateTrustPolicy)) - - self.assertFalse(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ClearStorage)) + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadConfiguration + ) + ) + self.assertFalse( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.DeleteConfiguration + ) + ) + self.assertFalse( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.UpdateConfiguration + ) + ) + self.assertFalse( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.CreateConfiguration + ) + ) + + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadSetting + ) + ) + self.assertFalse( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.DeleteSetting + ) + ) + self.assertFalse( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.UpdateSetting + ) + ) + self.assertFalse( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.CreateSetting + ) + ) + + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadCertificateIdentity + ) + ) + self.assertFalse( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.DeleteCertificateIdentity + ) + ) + self.assertFalse( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.UpdateCertificateIdentity + ) + ) + self.assertFalse( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.CreateCertificateIdentity + ) + ) + + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadSslCertificateCustomConfig + ) + ) + self.assertFalse( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.DeleteSslCertificateCustomConfig + ) + ) + self.assertFalse( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.UpdateSslCertificateCustomConfig + ) + ) + self.assertFalse( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.CreateSslCertificateCustomConfig + ) + ) + + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadCertificateTrustPolicy + ) + ) + self.assertFalse( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.DeleteCertificateTrustPolicy + ) + ) + self.assertFalse( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.UpdateCertificateTrustPolicy + ) + ) + self.assertFalse( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.CreateCertificateTrustPolicy + ) + ) + + self.assertFalse( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ClearStorage + ) + ) # Checks that calling a RO method raises an QgsNotSupportedException with self.assertRaises(QgsNotSupportedException): config = QgsAuthMethodConfig() - storage.storeMethodConfig(config, 'test') + storage.storeMethodConfig(config, "test") def _assert_readwrite(self, storage): self.assertFalse(storage.isReadOnly()) - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadConfiguration)) - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteConfiguration)) - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateConfiguration)) - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateConfiguration)) - - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadSetting)) - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteSetting)) - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateSetting)) - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateSetting)) - - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateIdentity)) - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteCertificateIdentity)) - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateCertificateIdentity)) - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateCertificateIdentity)) - - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadSslCertificateCustomConfig)) - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteSslCertificateCustomConfig)) - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateSslCertificateCustomConfig)) - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateSslCertificateCustomConfig)) - - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateTrustPolicy)) - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteCertificateTrustPolicy)) - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateCertificateTrustPolicy)) - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateCertificateTrustPolicy)) - - self.assertTrue(bool(storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ClearStorage)) + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadConfiguration + ) + ) + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.DeleteConfiguration + ) + ) + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.UpdateConfiguration + ) + ) + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.CreateConfiguration + ) + ) + + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadSetting + ) + ) + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.DeleteSetting + ) + ) + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.UpdateSetting + ) + ) + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.CreateSetting + ) + ) + + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadCertificateIdentity + ) + ) + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.DeleteCertificateIdentity + ) + ) + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.UpdateCertificateIdentity + ) + ) + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.CreateCertificateIdentity + ) + ) + + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadSslCertificateCustomConfig + ) + ) + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.DeleteSslCertificateCustomConfig + ) + ) + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.UpdateSslCertificateCustomConfig + ) + ) + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.CreateSslCertificateCustomConfig + ) + ) + + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadCertificateTrustPolicy + ) + ) + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.DeleteCertificateTrustPolicy + ) + ) + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.UpdateCertificateTrustPolicy + ) + ) + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.CreateCertificateTrustPolicy + ) + ) + + self.assertTrue( + bool( + storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ClearStorage + ) + ) def testAuthStoragePermissions(self): """Checks that the auth manager default DB storage permissions are set correctly""" @@ -172,82 +395,110 @@ def testAuthConfigs(self): self.assertTrue(self.storage.initialize(), self.storage.lastError()) - if not bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadConfiguration): - raise unittest.SkipTest('Storage does not support reading configurations') - - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadConfiguration)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteConfiguration)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateConfiguration)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateConfiguration)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ClearStorage)) + if not bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadConfiguration + ): + raise unittest.SkipTest("Storage does not support reading configurations") + + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadConfiguration + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.DeleteConfiguration + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.UpdateConfiguration + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.CreateConfiguration + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ClearStorage + ) + ) # Create a configuration config = QgsAuthMethodConfig() - config.setId('test') - config.setName('test name') - config.setMethod('basic') - config.setConfig('username', 'test user') - config.setConfig('password', 'test pass') - config.setConfig('realm', 'test realm') + config.setId("test") + config.setName("test name") + config.setMethod("basic") + config.setConfig("username", "test user") + config.setConfig("password", "test pass") + config.setConfig("realm", "test realm") payload = config.configString() self.assertTrue(self.storage.storeMethodConfig(config, payload)) # Create another configuration config2 = QgsAuthMethodConfig() - config2.setId('test2') - config2.setName('test name 2') - config2.setMethod('basic') - config2.setConfig('username', 'test user 2') - config2.setConfig('password', 'test pass 2') - config2.setConfig('realm', 'test realm 2') + config2.setId("test2") + config2.setName("test name 2") + config2.setMethod("basic") + config2.setConfig("username", "test user 2") + config2.setConfig("password", "test pass 2") + config2.setConfig("realm", "test realm 2") payload2 = config2.configString() self.assertTrue(self.storage.storeMethodConfig(config2, payload2)) # Test exists - self.assertTrue(self.storage.methodConfigExists('test')) - self.assertFalse(self.storage.methodConfigExists('xxxx')) + self.assertTrue(self.storage.methodConfigExists("test")) + self.assertFalse(self.storage.methodConfigExists("xxxx")) # Read it back - configback, payloadback = self.storage.loadMethodConfig('test', True) + configback, payloadback = self.storage.loadMethodConfig("test", True) configback.loadConfigString(payloadback) - self.assertEqual(configback.id(), 'test') - self.assertEqual(configback.name(), 'test name') - self.assertEqual(configback.method(), 'basic') - self.assertEqual(configback.config('username'), 'test user') - self.assertEqual(configback.config('password'), 'test pass') - self.assertEqual(configback.config('realm'), 'test realm') + self.assertEqual(configback.id(), "test") + self.assertEqual(configback.name(), "test name") + self.assertEqual(configback.method(), "basic") + self.assertEqual(configback.config("username"), "test user") + self.assertEqual(configback.config("password"), "test pass") + self.assertEqual(configback.config("realm"), "test realm") self.assertEqual(payloadback, payload) - configback, payloadback = self.storage.loadMethodConfig('test', False) - self.assertEqual(payloadback, '') - self.assertEqual(configback.id(), 'test') - self.assertEqual(configback.name(), 'test name') - self.assertEqual(configback.method(), 'basic') - self.assertEqual(configback.config('username'), '') - self.assertEqual(configback.config('password'), '') - self.assertEqual(configback.config('realm'), '') + configback, payloadback = self.storage.loadMethodConfig("test", False) + self.assertEqual(payloadback, "") + self.assertEqual(configback.id(), "test") + self.assertEqual(configback.name(), "test name") + self.assertEqual(configback.method(), "basic") + self.assertEqual(configback.config("username"), "") + self.assertEqual(configback.config("password"), "") + self.assertEqual(configback.config("realm"), "") - configs = self.storage.authMethodConfigs(['xxxx']) + configs = self.storage.authMethodConfigs(["xxxx"]) self.assertEqual(len(configs), 0) - configs = self.storage.authMethodConfigs(['basic']) + configs = self.storage.authMethodConfigs(["basic"]) self.assertEqual(len(configs), 2) configs = self.storage.authMethodConfigsWithPayload() - configback = configs['test'] - payloadback = configback.config('encrypted_payload') + configback = configs["test"] + payloadback = configback.config("encrypted_payload") configback.loadConfigString(payloadback) - self.assertEqual(configback.id(), 'test') - self.assertEqual(configback.name(), 'test name') - self.assertEqual(configback.method(), 'basic') - self.assertEqual(configback.config('username'), 'test user') - self.assertEqual(configback.config('password'), 'test pass') - self.assertEqual(configback.config('realm'), 'test realm') + self.assertEqual(configback.id(), "test") + self.assertEqual(configback.name(), "test name") + self.assertEqual(configback.method(), "basic") + self.assertEqual(configback.config("username"), "test user") + self.assertEqual(configback.config("password"), "test pass") + self.assertEqual(configback.config("realm"), "test realm") self.assertEqual(payloadback, payload) # Remove method config - self.assertTrue(self.storage.removeMethodConfig('test2')) - configs = self.storage.authMethodConfigs(['basic']) + self.assertTrue(self.storage.removeMethodConfig("test2")) + configs = self.storage.authMethodConfigs(["basic"]) self.assertEqual(len(configs), 1) # Clear the storage @@ -263,36 +514,64 @@ def testAuthSettings(self): self.assertTrue(self.storage.initialize(), self.storage.lastError()) - if not bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadSetting): - raise unittest.SkipTest('Storage does not support reading settings') - - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadSetting)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteSetting)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateSetting)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateSetting)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ClearStorage)) + if not bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadSetting + ): + raise unittest.SkipTest("Storage does not support reading settings") + + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadSetting + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.DeleteSetting + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.UpdateSetting + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.CreateSetting + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ClearStorage + ) + ) # Create a setting - self.assertTrue(self.storage.storeAuthSetting('test', 'test value')) + self.assertTrue(self.storage.storeAuthSetting("test", "test value")) # Create another setting - self.assertTrue(self.storage.storeAuthSetting('test2', 'test value 2')) + self.assertTrue(self.storage.storeAuthSetting("test2", "test value 2")) - self.assertTrue(self.storage.authSettingExists('test')) - self.assertTrue(self.storage.authSettingExists('test2')) - self.assertFalse(self.storage.authSettingExists('xxxx')) + self.assertTrue(self.storage.authSettingExists("test")) + self.assertTrue(self.storage.authSettingExists("test2")) + self.assertFalse(self.storage.authSettingExists("xxxx")) # Read it back - value = self.storage.loadAuthSetting('test') - self.assertEqual(value, 'test value') + value = self.storage.loadAuthSetting("test") + self.assertEqual(value, "test value") # Remove setting - self.assertTrue(self.storage.removeAuthSetting('test')) - self.assertTrue(self.storage.removeAuthSetting('test2')) + self.assertTrue(self.storage.removeAuthSetting("test")) + self.assertTrue(self.storage.removeAuthSetting("test2")) # Check it's empty - self.assertFalse(self.storage.authSettingExists('test')) - self.assertFalse(self.storage.authSettingExists('test2')) + self.assertFalse(self.storage.authSettingExists("test")) + self.assertFalse(self.storage.authSettingExists("test2")) def testCertIdentity(self): @@ -300,23 +579,53 @@ def testCertIdentity(self): self.assertTrue(self.storage.initialize(), self.storage.lastError()) - if not bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateIdentity): - raise unittest.SkipTest('Storage does not support reading certificate identities') - - sslrootcert_path = os.path.join(self.certdata_path, 'qgis_ca.crt') - sslcert = os.path.join(self.certdata_path, 'Gerardus.crt') - sslkey_path = os.path.join(self.certdata_path, 'Gerardus.key') + if not bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadCertificateIdentity + ): + raise unittest.SkipTest( + "Storage does not support reading certificate identities" + ) + + sslrootcert_path = os.path.join(self.certdata_path, "qgis_ca.crt") + sslcert = os.path.join(self.certdata_path, "Gerardus.crt") + sslkey_path = os.path.join(self.certdata_path, "Gerardus.key") # In real life, key should be encrypted (the auth manager does that) - with open(sslkey_path, 'r') as f: + with open(sslkey_path) as f: sslkey = f.read() cert = QSslCertificate.fromPath(sslcert)[0] - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateIdentity)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteCertificateIdentity)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateCertificateIdentity)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateCertificateIdentity)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ClearStorage)) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadCertificateIdentity + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.DeleteCertificateIdentity + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.UpdateCertificateIdentity + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.CreateCertificateIdentity + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ClearStorage + ) + ) # Create an identity self.assertTrue(self.storage.storeCertIdentity(cert, sslkey)) @@ -352,47 +661,85 @@ def testSslCertificateCustomConfig(self): self.assertTrue(self.storage.initialize(), self.storage.lastError()) - if not bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadSslCertificateCustomConfig): - raise unittest.SkipTest('Storage does not support reading ssl certificate custom configs') - - sslrootcert_path = os.path.join(self.certdata_path, 'qgis_ca.crt') - sslcert = os.path.join(self.certdata_path, 'Gerardus.crt') - sslkey_path = os.path.join(self.certdata_path, 'Gerardus.key') + if not bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadSslCertificateCustomConfig + ): + raise unittest.SkipTest( + "Storage does not support reading ssl certificate custom configs" + ) + + sslrootcert_path = os.path.join(self.certdata_path, "qgis_ca.crt") + sslcert = os.path.join(self.certdata_path, "Gerardus.crt") + sslkey_path = os.path.join(self.certdata_path, "Gerardus.key") # In real life, key should be encrypted (the auth manager does that) - with open(sslkey_path, 'r') as f: + with open(sslkey_path) as f: sslkey = f.read() cert = QSslCertificate.fromPath(sslcert)[0] - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadSslCertificateCustomConfig)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteSslCertificateCustomConfig)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateSslCertificateCustomConfig)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateSslCertificateCustomConfig)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ClearStorage)) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadSslCertificateCustomConfig + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.DeleteSslCertificateCustomConfig + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.UpdateSslCertificateCustomConfig + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.CreateSslCertificateCustomConfig + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ClearStorage + ) + ) # Create a custom config config = QgsAuthConfigSslServer() config.setSslCertificate(cert) - config.setSslHostPort('localhost:5432') + config.setSslHostPort("localhost:5432") self.assertTrue(self.storage.storeSslCertCustomConfig(config)) ids = self.storage.sslCertCustomConfigIds() cert_id = ids[0] - self.assertTrue(self.storage.sslCertCustomConfigExists(cert_id, config.sslHostPort())) + self.assertTrue( + self.storage.sslCertCustomConfigExists(cert_id, config.sslHostPort()) + ) # Read it back configback = self.storage.loadSslCertCustomConfig(cert_id, config.sslHostPort()) # Verify the config - self.assertEqual(config.sslCertificate().toPem(), configback.sslCertificate().toPem()) + self.assertEqual( + config.sslCertificate().toPem(), configback.sslCertificate().toPem() + ) self.assertEqual(config.sslHostPort(), configback.sslHostPort()) # Remove custom config - self.assertTrue(self.storage.removeSslCertCustomConfig(cert_id, config.sslHostPort())) + self.assertTrue( + self.storage.removeSslCertCustomConfig(cert_id, config.sslHostPort()) + ) # Check it's empty - self.assertFalse(self.storage.sslCertCustomConfigExists(cert_id, config.sslHostPort())) + self.assertFalse( + self.storage.sslCertCustomConfigExists(cert_id, config.sslHostPort()) + ) def testTrust(self): @@ -400,20 +747,50 @@ def testTrust(self): self.assertTrue(self.storage.initialize(), self.storage.lastError()) - if not bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateTrustPolicy): - raise unittest.SkipTest('Storage does not support reading certificate trust policies') - - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateTrustPolicy)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteCertificateTrustPolicy)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateCertificateTrustPolicy)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateCertificateTrustPolicy)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ClearStorage)) - - sslrootcert_path = os.path.join(self.certdata_path, 'qgis_ca.crt') - sslcert = os.path.join(self.certdata_path, 'Gerardus.crt') - sslkey_path = os.path.join(self.certdata_path, 'Gerardus.key') + if not bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadCertificateTrustPolicy + ): + raise unittest.SkipTest( + "Storage does not support reading certificate trust policies" + ) + + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadCertificateTrustPolicy + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.DeleteCertificateTrustPolicy + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.UpdateCertificateTrustPolicy + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.CreateCertificateTrustPolicy + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ClearStorage + ) + ) + + sslrootcert_path = os.path.join(self.certdata_path, "qgis_ca.crt") + sslcert = os.path.join(self.certdata_path, "Gerardus.crt") + sslkey_path = os.path.join(self.certdata_path, "Gerardus.key") # In real life, key should be encrypted (the auth manager does that) - with open(sslkey_path, 'r') as f: + with open(sslkey_path) as f: sslkey = f.read() cert = QSslCertificate.fromPath(sslcert)[0] @@ -444,16 +821,46 @@ def testAuthority(self): self.assertTrue(self.storage.initialize(), self.storage.lastError()) - if not bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateAuthority): - raise unittest.SkipTest('Storage does not support reading certificate authorities') - - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ReadCertificateAuthority)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.DeleteCertificateAuthority)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateCertificateAuthority)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.CreateCertificateAuthority)) - self.assertTrue(bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.ClearStorage)) - - sslrootcert_path = os.path.join(self.certdata_path, 'qgis_ca.crt') + if not bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadCertificateAuthority + ): + raise unittest.SkipTest( + "Storage does not support reading certificate authorities" + ) + + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ReadCertificateAuthority + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.DeleteCertificateAuthority + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.UpdateCertificateAuthority + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.CreateCertificateAuthority + ) + ) + self.assertTrue( + bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.ClearStorage + ) + ) + + sslrootcert_path = os.path.join(self.certdata_path, "qgis_ca.crt") rootcert = QSslCertificate.fromPath(sslrootcert_path)[0] # Create an authority @@ -479,8 +886,13 @@ def testAuthority(self): def testUpdateReadOnly(self): """Tests that updating a setting in a read-only storage fails""" - if not bool(self.storage.capabilities() & Qgis.AuthConfigurationStorageCapability.UpdateSetting): - raise unittest.SkipTest('Storage does not support reading certificate authorities') + if not bool( + self.storage.capabilities() + & Qgis.AuthConfigurationStorageCapability.UpdateSetting + ): + raise unittest.SkipTest( + "Storage does not support reading certificate authorities" + ) auth_manager = QgsApplication.authManager() auth_manager.ensureInitialized() @@ -489,8 +901,8 @@ def testUpdateReadOnly(self): temp_dir_path = temp_dir.path() # Create an empty sqlite database using GDAL - db_path = os.path.join(temp_dir_path, 'test.sqlite') - ds = gdal.GetDriverByName('SQLite').Create(db_path, 0, 0, 0) + db_path = os.path.join(temp_dir_path, "test.sqlite") + ds = gdal.GetDriverByName("SQLite").Create(db_path, 0, 0, 0) del ds uri = f"QSQLITE://{db_path}" @@ -506,13 +918,13 @@ def testUpdateReadOnly(self): self.assertEqual(len(registry.readyStorages()), 2) # Create a setting - self.assertTrue(self.storage.storeAuthSetting('test', 'test value')) + self.assertTrue(self.storage.storeAuthSetting("test", "test value")) # Set the original storage as read-only self.storage.setReadOnly(True) # Try to update the setting using auth manager - self.assertFalse(auth_manager.storeAuthSetting('test', 'test value 2')) + self.assertFalse(auth_manager.storeAuthSetting("test", "test value 2")) # Remove the temp storage self.assertTrue(registry.removeStorage(tmp_storage.id())) diff --git a/tests/src/python/test_authmanager_storage_custom.py b/tests/src/python/test_authmanager_storage_custom.py index fe82e2dcea6d..84d10416a892 100644 --- a/tests/src/python/test_authmanager_storage_custom.py +++ b/tests/src/python/test_authmanager_storage_custom.py @@ -12,12 +12,15 @@ import unittest -from test_authmanager_storage_base import AuthManagerStorageBaseTestCase, TestAuthManagerStorageBase +from test_authmanager_storage_base import ( + AuthManagerStorageBaseTestCase, + TestAuthManagerStorageBase, +) from qgsauthconfigurationcustomstorage import QgsAuthConfigurationCustomStorage -__author__ = 'Alessandro Pasotti' -__date__ = '2024-06-24' -__copyright__ = 'Copyright 2024, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "2024-06-24" +__copyright__ = "Copyright 2024, The QGIS Project" class TestAuthStorageCustom(AuthManagerStorageBaseTestCase, TestAuthManagerStorageBase): @@ -28,11 +31,11 @@ def setUpClass(cls): super().setUpClass() - config = {'is_encrypted': 'false'} + config = {"is_encrypted": "false"} cls.storage = QgsAuthConfigurationCustomStorage(config) assert not cls.storage.isEncrypted() - assert cls.storage.type() == 'custom' + assert cls.storage.type() == "custom" -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_authmanager_storage_psql.py b/tests/src/python/test_authmanager_storage_psql.py index 89dae8ddd62f..a63f1e9f61f5 100644 --- a/tests/src/python/test_authmanager_storage_psql.py +++ b/tests/src/python/test_authmanager_storage_psql.py @@ -13,7 +13,10 @@ import os import unittest -from test_authmanager_storage_base import AuthManagerStorageBaseTestCase, TestAuthManagerStorageBase +from test_authmanager_storage_base import ( + AuthManagerStorageBaseTestCase, + TestAuthManagerStorageBase, +) from qgis.PyQt.QtCore import QTemporaryDir from qgis.core import ( QgsAuthConfigurationStorageDb, @@ -22,52 +25,65 @@ ) from qgis.PyQt import QtSql -__author__ = 'Alessandro Pasotti' -__date__ = '2024-06-24' -__copyright__ = 'Copyright 2024, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "2024-06-24" +__copyright__ = "Copyright 2024, The QGIS Project" # Skip if driver QPSQL/QPSQL7 is not available -@unittest.skipIf(not QtSql.QSqlDatabase.isDriverAvailable('QPSQL') and not QtSql.QSqlDatabase.isDriverAvailable('QPSQL7'), 'QPSQL/QPSQL7 driver not available') +@unittest.skipIf( + not QtSql.QSqlDatabase.isDriverAvailable("QPSQL") + and not QtSql.QSqlDatabase.isDriverAvailable("QPSQL7"), + "QPSQL/QPSQL7 driver not available", +) class TestAuthStoragePsql(AuthManagerStorageBaseTestCase, TestAuthManagerStorageBase): @classmethod def setUpClass(cls): """Run before tests""" - if 'QGIS_PGTEST_DB' not in os.environ: - raise unittest.SkipTest('QGIS_PGTEST_DB not defined') + if "QGIS_PGTEST_DB" not in os.environ: + raise unittest.SkipTest("QGIS_PGTEST_DB not defined") - cls.db_path = os.environ['QGIS_PGTEST_DB'] + cls.db_path = os.environ["QGIS_PGTEST_DB"] config = dict() - if cls.db_path.startswith('service='): + if cls.db_path.startswith("service="): try: # This needs to be installed with pip install pgserviceparser import pgserviceparser + service_name = cls.db_path[8:] # Remove single quotes if present if service_name.startswith("'") and service_name.endswith("'"): service_name = service_name[1:-1] config = pgserviceparser.service_config(service_name) except ImportError: - raise unittest.SkipTest('QGIS_PGTEST_DB is a service connection string (which is not supported by QtSql) and pgserviceparser is not available') + raise unittest.SkipTest( + "QGIS_PGTEST_DB is a service connection string (which is not supported by QtSql) and pgserviceparser is not available" + ) else: # Parse the connection string for item in cls.db_path.split(): - key, value = item.split('=') + key, value = item.split("=") config[key] = value - config['driver'] = 'QPSQL' if QtSql.QSqlDatabase.isDriverAvailable('QPSQL') else 'QPSQL7' - config['database'] = config['dbname'] + config["driver"] = ( + "QPSQL" if QtSql.QSqlDatabase.isDriverAvailable("QPSQL") else "QPSQL7" + ) + config["database"] = config["dbname"] # Remove single quotes if present in user and password and database - for key in ['user', 'password', 'database', 'dbname']: - if key in config and config[key].startswith("'") and config[key].endswith("'"): + for key in ["user", "password", "database", "dbname"]: + if ( + key in config + and config[key].startswith("'") + and config[key].endswith("'") + ): config[key] = config[key][1:-1] - config['schema'] = 'qgis_auth_test' + config["schema"] = "qgis_auth_test" cls.storage_uri = f"{config['driver']}://{config['user']}:{config['password']}@{config['host']}:{config['port']}/{config['dbname']}?schema={config['schema']}" @@ -76,27 +92,30 @@ def setUpClass(cls): super().setUpClass() # Make sure all tables are dropped by dropping the schema - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") # connection uri uri = f"dbname='{config['dbname']}' host={config['host']} port={config['port']} user='{config['user']}' password='{config['password']}'" conn = md.createConnection(uri, {}) - if config['schema'] in conn.schemas(): - conn.dropSchema(config['schema'], True) + if config["schema"] in conn.schemas(): + conn.dropSchema(config["schema"], True) - conn.createSchema(config['schema']) + conn.createSchema(config["schema"]) cls.storage = QgsAuthConfigurationStorageDb(config) - assert cls.storage.type() == 'DB-QPSQL' + assert cls.storage.type() == "DB-QPSQL" - if config['schema']: + if config["schema"]: schema = f"\"{config['schema']}\"." else: - schema = '' + schema = "" - assert cls.storage.quotedQualifiedIdentifier(cls.storage.methodConfigTableName()) == f'{schema}"auth_configs"' + assert ( + cls.storage.quotedQualifiedIdentifier(cls.storage.methodConfigTableName()) + == f'{schema}"auth_configs"' + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_authmanager_storage_sqlite.py b/tests/src/python/test_authmanager_storage_sqlite.py index bdb74981bb85..90ac85872bed 100644 --- a/tests/src/python/test_authmanager_storage_sqlite.py +++ b/tests/src/python/test_authmanager_storage_sqlite.py @@ -14,13 +14,16 @@ from osgeo import gdal import unittest -from test_authmanager_storage_base import AuthManagerStorageBaseTestCase, TestAuthManagerStorageBase +from test_authmanager_storage_base import ( + AuthManagerStorageBaseTestCase, + TestAuthManagerStorageBase, +) from qgis.PyQt.QtCore import QTemporaryDir from qgis.core import QgsAuthConfigurationStorageDb -__author__ = 'Alessandro Pasotti' -__date__ = '2024-06-24' -__copyright__ = 'Copyright 2024, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "2024-06-24" +__copyright__ = "Copyright 2024, The QGIS Project" class TestAuthStorageSqlite(AuthManagerStorageBaseTestCase, TestAuthManagerStorageBase): @@ -33,8 +36,8 @@ def setUpClass(cls): cls.temp_dir_path = cls.temp_dir.path() # Create an empty sqlite database using GDAL - cls.db_path = os.path.join(cls.temp_dir_path, 'test.sqlite') - ds = gdal.GetDriverByName('SQLite').Create(cls.db_path, 0, 0, 0) + cls.db_path = os.path.join(cls.temp_dir_path, "test.sqlite") + ds = gdal.GetDriverByName("SQLite").Create(cls.db_path, 0, 0, 0) del ds # Verify that the file was created @@ -44,17 +47,17 @@ def setUpClass(cls): cls.storage_uri = uri cls.storage = QgsAuthConfigurationStorageDb(uri) - assert cls.storage.type() == 'DB-QSQLITE' + assert cls.storage.type() == "DB-QSQLITE" super().setUpClass() def testCannotCreateDb(self): """Generic DB storage cannot create databases""" - path = os.path.join(self.temp_dir_path, 'test_not_exist.sqlite') + path = os.path.join(self.temp_dir_path, "test_not_exist.sqlite") storage = QgsAuthConfigurationStorageDb(self.storage_uri) assert not os.path.exists(path) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_authsettingswidget.py b/tests/src/python/test_authsettingswidget.py index d3ec981a8659..9df49f302c2e 100644 --- a/tests/src/python/test_authsettingswidget.py +++ b/tests/src/python/test_authsettingswidget.py @@ -9,6 +9,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + import os import random import string @@ -23,13 +24,13 @@ import unittest from qgis.testing import start_app, QgisTestCase -__author__ = 'Alessandro Pasotti' -__date__ = '27/09/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "27/09/2017" +__copyright__ = "Copyright 2017, The QGIS Project" QGIS_AUTH_DB_DIR_PATH = tempfile.mkdtemp() -os.environ['QGIS_AUTH_DB_DIR_PATH'] = QGIS_AUTH_DB_DIR_PATH +os.environ["QGIS_AUTH_DB_DIR_PATH"] = QGIS_AUTH_DB_DIR_PATH qgis_app = start_app() @@ -44,14 +45,16 @@ def setUpClass(cls): # Enable auth # os.environ['QGIS_AUTH_PASSWORD_FILE'] = QGIS_AUTH_PASSWORD_FILE authm = QgsApplication.authManager() - assert (authm.setMasterPassword('masterpassword', True)) - cls.auth_config = QgsAuthMethodConfig('Basic') - cls.auth_config.setName('test_auth_config') - cls.username = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6)) + assert authm.setMasterPassword("masterpassword", True) + cls.auth_config = QgsAuthMethodConfig("Basic") + cls.auth_config.setName("test_auth_config") + cls.username = "".join( + random.choice(string.ascii_uppercase + string.digits) for _ in range(6) + ) cls.password = cls.username[::-1] # reversed - cls.auth_config.setConfig('username', cls.username) - cls.auth_config.setConfig('password', cls.password) - assert (authm.storeAuthenticationConfig(cls.auth_config)[0]) + cls.auth_config.setConfig("username", cls.username) + cls.auth_config.setConfig("password", cls.password) + assert authm.storeAuthenticationConfig(cls.auth_config)[0] @classmethod def tearDownClass(cls): @@ -72,9 +75,9 @@ def testWidgetNoArgs(self): Test the widget with no args """ w = QgsAuthSettingsWidget() - self.assertEqual(w.username(), '') - self.assertEqual(w.password(), '') - self.assertEqual(w.configId(), '') + self.assertEqual(w.username(), "") + self.assertEqual(w.password(), "") + self.assertEqual(w.configId(), "") self.assertTrue(w.configurationTabIsSelected()) self.assertFalse(w.btnConvertToEncryptedIsEnabled()) @@ -83,8 +86,8 @@ def testWidgetConfigId(self): Test the widget with configId """ w = QgsAuthSettingsWidget(None, self.auth_config.id()) - self.assertEqual(w.username(), '') - self.assertEqual(w.password(), '') + self.assertEqual(w.username(), "") + self.assertEqual(w.password(), "") self.assertEqual(w.configId(), self.auth_config.id()) self.assertTrue(w.configurationTabIsSelected()) self.assertFalse(w.btnConvertToEncryptedIsEnabled()) @@ -93,30 +96,30 @@ def testWidgetUsername(self): """ Test the widget with username only """ - w = QgsAuthSettingsWidget(None, None, 'username') - self.assertEqual(w.username(), 'username') - self.assertEqual(w.password(), '') - self.assertEqual(w.configId(), '') + w = QgsAuthSettingsWidget(None, None, "username") + self.assertEqual(w.username(), "username") + self.assertEqual(w.password(), "") + self.assertEqual(w.configId(), "") self.assertFalse(w.configurationTabIsSelected()) def testWidgetPassword(self): """ Test the widget with password only """ - w = QgsAuthSettingsWidget(None, None, None, 'password') - self.assertEqual(w.username(), '') - self.assertEqual(w.password(), 'password') - self.assertEqual(w.configId(), '') + w = QgsAuthSettingsWidget(None, None, None, "password") + self.assertEqual(w.username(), "") + self.assertEqual(w.password(), "password") + self.assertEqual(w.configId(), "") self.assertFalse(w.configurationTabIsSelected()) def testWidgetUsernameAndPassword(self): """ Test the widget with username and password """ - w = QgsAuthSettingsWidget(None, None, 'username', 'password') - self.assertEqual(w.username(), 'username') - self.assertEqual(w.password(), 'password') - self.assertEqual(w.configId(), '') + w = QgsAuthSettingsWidget(None, None, "username", "password") + self.assertEqual(w.username(), "username") + self.assertEqual(w.password(), "password") + self.assertEqual(w.configId(), "") self.assertFalse(w.configurationTabIsSelected()) self.assertTrue(w.btnConvertToEncryptedIsEnabled()) @@ -124,16 +127,16 @@ def testConvertToEncrypted(self): """ Test the widget to encrypted conversion """ - w = QgsAuthSettingsWidget(None, None, 'username', 'password') - self.assertEqual(w.username(), 'username') - self.assertEqual(w.password(), 'password') - self.assertEqual(w.configId(), '') + w = QgsAuthSettingsWidget(None, None, "username", "password") + self.assertEqual(w.username(), "username") + self.assertEqual(w.password(), "password") + self.assertEqual(w.configId(), "") self.assertFalse(w.configurationTabIsSelected()) self.assertTrue(w.btnConvertToEncryptedIsEnabled()) self.assertTrue(w.convertToEncrypted()) - self.assertNotEqual(w.configId(), '') - self.assertEqual(w.username(), '') - self.assertEqual(w.password(), '') + self.assertNotEqual(w.configId(), "") + self.assertEqual(w.username(), "") + self.assertEqual(w.password(), "") self.assertTrue(w.configurationTabIsSelected()) self.assertFalse(w.btnConvertToEncryptedIsEnabled()) @@ -142,13 +145,13 @@ def test_setters(self): Test setters """ w = QgsAuthSettingsWidget() - w.setUsername('username') + w.setUsername("username") self.assertFalse(w.configurationTabIsSelected()) - self.assertEqual(w.username(), 'username') + self.assertEqual(w.username(), "username") w = QgsAuthSettingsWidget() - w.setPassword('password') - self.assertEqual(w.password(), 'password') + w.setPassword("password") + self.assertEqual(w.password(), "password") self.assertFalse(w.configurationTabIsSelected()) w = QgsAuthSettingsWidget() @@ -157,15 +160,15 @@ def test_setters(self): self.assertTrue(w.configurationTabIsSelected()) w = QgsAuthSettingsWidget() - w.setUsername('username') - w.setPassword('password') + w.setUsername("username") + w.setPassword("password") w.setConfigId(self.auth_config.id()) self.assertEqual(w.configId(), self.auth_config.id()) self.assertTrue(w.configurationTabIsSelected()) w = QgsAuthSettingsWidget() - w.setDataprovider('db2') - self.assertEqual(w.dataprovider(), 'db2') + w.setDataprovider("db2") + self.assertEqual(w.dataprovider(), "db2") def test_storeCheckBoxes(self): """ @@ -192,5 +195,5 @@ def test_storeCheckBoxes(self): self.assertTrue(w.storeUsernameIsChecked()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_console.py b/tests/src/python/test_console.py index 83bb64028a0f..b9e1469275b3 100644 --- a/tests/src/python/test_console.py +++ b/tests/src/python/test_console.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Matthias Kuhn' -__date__ = '15.4.2016' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Matthias Kuhn" +__date__ = "15.4.2016" +__copyright__ = "Copyright 2015, The QGIS Project" import os @@ -23,10 +24,10 @@ class TestConsole(QgisTestCase): def setUp(self): - QgsSettings().setValue('pythonConsole/contextHelpOnFirstLaunch', False) + QgsSettings().setValue("pythonConsole/contextHelpOnFirstLaunch", False) def test_show_console(self): - if os.name == 'nt': + if os.name == "nt": QCoreApplication.setOrganizationName("QGIS") QCoreApplication.setOrganizationDomain("qgis.org") QCoreApplication.setApplicationName("QGIS-TEST") diff --git a/tests/src/python/test_core_additions.py b/tests/src/python/test_core_additions.py index 108b517c7de0..18592fa06bc3 100644 --- a/tests/src/python/test_core_additions.py +++ b/tests/src/python/test_core_additions.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Denis Rouzaud' -__date__ = '15.5.2018' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Denis Rouzaud" +__date__ = "15.5.2018" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.core import ( @@ -29,12 +30,12 @@ class TestCoreAdditions(QgisTestCase): def testMetaEnum(self): me = metaEnumFromValue(Qgis.MapToolUnit.Pixels) self.assertIsNotNone(me) - self.assertEqual(me.valueToKey(Qgis.MapToolUnit.Pixels), 'Pixels') + self.assertEqual(me.valueToKey(Qgis.MapToolUnit.Pixels), "Pixels") # check that using same variable twice doesn't segfault me = metaEnumFromValue(Qgis.MapToolUnit.Pixels, QgsTolerance) self.assertIsNotNone(me) - self.assertEqual(me.valueToKey(Qgis.MapToolUnit.Pixels), 'Pixels') + self.assertEqual(me.valueToKey(Qgis.MapToolUnit.Pixels), "Pixels") # do not raise error self.assertIsNone(metaEnumFromValue(1, QgsTolerance, False)) diff --git a/tests/src/python/test_db_manager_gpkg.py b/tests/src/python/test_db_manager_gpkg.py index c49602cbb032..16eb7f38af94 100644 --- a/tests/src/python/test_db_manager_gpkg.py +++ b/tests/src/python/test_db_manager_gpkg.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Even Rouault' -__date__ = '2016-10-17' -__copyright__ = 'Copyright 2016, Even Rouault' + +__author__ = "Even Rouault" +__date__ = "2016-10-17" +__copyright__ = "Copyright 2016, Even Rouault" import os import shutil @@ -25,7 +26,7 @@ def GDAL_COMPUTE_VERSION(maj, min, rev): - return ((maj) * 1000000 + (min) * 10000 + (rev) * 100) + return (maj) * 1000000 + (min) * 10000 + (rev) * 100 class TestPyQgsDBManagerGpkg(QgisTestCase): @@ -43,14 +44,16 @@ def setUpClass(cls): cls.basetestpath = tempfile.mkdtemp() - cls.test_gpkg = os.path.join(cls.basetestpath, 'TestPyQgsDBManagerGpkg.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(cls.test_gpkg) - lyr = ds.CreateLayer('testLayer', geom_type=ogr.wkbLineString, options=['SPATIAL_INDEX=NO']) + cls.test_gpkg = os.path.join(cls.basetestpath, "TestPyQgsDBManagerGpkg.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(cls.test_gpkg) + lyr = ds.CreateLayer( + "testLayer", geom_type=ogr.wkbLineString, options=["SPATIAL_INDEX=NO"] + ) cls.supportsAlterFieldDefn = lyr.TestCapability(ogr.OLCAlterFieldDefn) == 1 - lyr.CreateField(ogr.FieldDefn('text_field', ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("text_field", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f['text_field'] = 'foo' - f.SetGeometry(ogr.CreateGeometryFromWkt('LINESTRING(1 2,3 4)')) + f["text_field"] = "foo" + f.SetGeometry(ogr.CreateGeometryFromWkt("LINESTRING(1 2,3 4)")) lyr.CreateFeature(f) f = None ds = None @@ -64,15 +67,15 @@ def tearDownClass(cls): shutil.rmtree(cls.basetestpath, True) def testSupportedDbTypes(self): - self.assertIn('gpkg', supportedDbTypes()) + self.assertIn("gpkg", supportedDbTypes()) def testCreateDbPlugin(self): - plugin = createDbPlugin('gpkg') + plugin = createDbPlugin("gpkg") self.assertIsNotNone(plugin) def testConnect(self): - connection_name = 'testConnect' - plugin = createDbPlugin('gpkg') + connection_name = "testConnect" + plugin = createDbPlugin("gpkg") uri = QgsDataSourceUri() uri.setDatabase(self.test_gpkg) @@ -81,14 +84,14 @@ def testConnect(self): connections = plugin.connections() self.assertEqual(len(connections), 1) - connection = createDbPlugin('gpkg', connection_name + '_does_not_exist') + connection = createDbPlugin("gpkg", connection_name + "_does_not_exist") connection_succeeded = False try: connection.connect() connection_succeeded = True except: pass - self.assertFalse(connection_succeeded, 'exception should have been raised') + self.assertFalse(connection_succeeded, "exception should have been raised") connection = connections[0] connection.connect() @@ -99,23 +102,23 @@ def testConnect(self): self.assertEqual(len(plugin.connections()), 0) - connection = createDbPlugin('gpkg', connection_name) + connection = createDbPlugin("gpkg", connection_name) connection_succeeded = False try: connection.connect() connection_succeeded = True except: pass - self.assertFalse(connection_succeeded, 'exception should have been raised') + self.assertFalse(connection_succeeded, "exception should have been raised") def testListLayer(self): - connection_name = 'testListLayer' - plugin = createDbPlugin('gpkg') + connection_name = "testListLayer" + plugin = createDbPlugin("gpkg") uri = QgsDataSourceUri() uri.setDatabase(self.test_gpkg) self.assertTrue(plugin.addConnection(connection_name, uri)) - connection = createDbPlugin('gpkg', connection_name) + connection = createDbPlugin("gpkg", connection_name) connection.connect() db = connection.database() @@ -124,7 +127,7 @@ def testListLayer(self): tables = db.tables() self.assertEqual(len(tables), 1) table = tables[0] - self.assertEqual(table.name, 'testLayer') + self.assertEqual(table.name, "testLayer") info = table.info() expected_html = """

    General info

    Relation type: Table 
    Rows: 

    GeoPackage

    Column: geom 
    Geometry: LINESTRING 
    Dimension: XY 
    Spatial ref: Undefined (-1) 
    Extent: 1.00000, 2.00000 - 3.00000, 4.00000 

    No spatial index defined (create it)

    Fields

    Name Type Null Default 
    fid INTEGER  
    geom LINESTRING  
    text_field TEXT  
    """ @@ -138,20 +141,23 @@ def testListLayer(self): connection.remove() - @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'), - 'Test flaky') # see https://travis-ci.org/qgis/QGIS/jobs/502556996 + @unittest.skipIf( + os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), "Test flaky" + ) # see https://travis-ci.org/qgis/QGIS/jobs/502556996 def testCreateRenameDeleteTable(self): - connection_name = 'testCreateRenameDeleteTable' - plugin = createDbPlugin('gpkg') + connection_name = "testCreateRenameDeleteTable" + plugin = createDbPlugin("gpkg") uri = QgsDataSourceUri() - test_gpkg_new = os.path.join(self.basetestpath, 'testCreateRenameDeleteTable.gpkg') + test_gpkg_new = os.path.join( + self.basetestpath, "testCreateRenameDeleteTable.gpkg" + ) shutil.copy(self.test_gpkg, test_gpkg_new) uri.setDatabase(test_gpkg_new) self.assertTrue(plugin.addConnection(connection_name, uri)) - connection = createDbPlugin('gpkg', connection_name) + connection = createDbPlugin("gpkg", connection_name) connection.connect() db = connection.database() @@ -160,8 +166,8 @@ def testCreateRenameDeleteTable(self): tables = db.tables() self.assertEqual(len(tables), 1) table = tables[0] - self.assertTrue(table.rename('newName')) - self.assertEqual(table.name, 'newName') + self.assertTrue(table.rename("newName")) + self.assertEqual(table.name, "newName") connection.reconnect() @@ -169,28 +175,28 @@ def testCreateRenameDeleteTable(self): tables = db.tables() self.assertEqual(len(tables), 1) table = tables[0] - self.assertEqual(table.name, 'newName') + self.assertEqual(table.name, "newName") fields = [] - geom = ['geometry', 'POINT', 4326, 3] + geom = ["geometry", "POINT", 4326, 3] field1 = TableField(table) - field1.name = 'fid' - field1.dataType = 'INTEGER' + field1.name = "fid" + field1.dataType = "INTEGER" field1.notNull = True field1.primaryKey = True field2 = TableField(table) - field2.name = 'str_field' - field2.dataType = 'TEXT' + field2.name = "str_field" + field2.dataType = "TEXT" field2.modifier = 20 fields = [field1, field2] - self.assertTrue(db.createVectorTable('newName2', fields, geom)) + self.assertTrue(db.createVectorTable("newName2", fields, geom)) tables = db.tables() self.assertEqual(len(tables), 2) new_table = tables[1] - self.assertEqual(new_table.name, 'newName2') + self.assertEqual(new_table.name, "newName2") fields = new_table.fields() self.assertEqual(len(fields), 3) self.assertFalse(new_table.hasSpatialIndex()) @@ -214,21 +220,25 @@ def testCreateRenameDeleteFields(self): if not self.supportsAlterFieldDefn: return - connection_name = 'testCreateRenameDeleteFields' - plugin = createDbPlugin('gpkg') + connection_name = "testCreateRenameDeleteFields" + plugin = createDbPlugin("gpkg") uri = QgsDataSourceUri() - test_gpkg_new = os.path.join(self.basetestpath, 'testCreateRenameDeleteFields.gpkg') + test_gpkg_new = os.path.join( + self.basetestpath, "testCreateRenameDeleteFields.gpkg" + ) - ds = ogr.GetDriverByName('GPKG').CreateDataSource(test_gpkg_new) - lyr = ds.CreateLayer('testLayer', geom_type=ogr.wkbLineString, options=['SPATIAL_INDEX=NO']) - lyr.CreateField(ogr.FieldDefn('text_field', ogr.OFTString)) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(test_gpkg_new) + lyr = ds.CreateLayer( + "testLayer", geom_type=ogr.wkbLineString, options=["SPATIAL_INDEX=NO"] + ) + lyr.CreateField(ogr.FieldDefn("text_field", ogr.OFTString)) del ds uri.setDatabase(test_gpkg_new) self.assertTrue(plugin.addConnection(connection_name, uri)) - connection = createDbPlugin('gpkg', connection_name) + connection = createDbPlugin("gpkg", connection_name) connection.connect() db = connection.database() @@ -241,17 +251,24 @@ def testCreateRenameDeleteFields(self): field_before_count = len(table.fields()) field = TableField(table) - field.name = 'real_field' - field.dataType = 'DOUBLE' + field.name = "real_field" + field.dataType = "DOUBLE" self.assertTrue(table.addField(field)) self.assertEqual(len(table.fields()), field_before_count + 1) - self.assertTrue(field.update('real_field2', new_type_str='TEXT (30)', new_not_null=True, new_default_str='foo')) + self.assertTrue( + field.update( + "real_field2", + new_type_str="TEXT (30)", + new_not_null=True, + new_default_str="foo", + ) + ) field = table.fields()[field_before_count] - self.assertEqual(field.name, 'real_field2') - self.assertEqual(field.dataType, 'TEXT(30)') + self.assertEqual(field.name, "real_field2") + self.assertEqual(field.dataType, "TEXT(30)") self.assertEqual(field.notNull, 1) self.assertEqual(field.default, "'foo'") @@ -262,13 +279,13 @@ def testCreateRenameDeleteFields(self): connection.remove() def testTableDataModel(self): - connection_name = 'testTableDataModel' - plugin = createDbPlugin('gpkg') + connection_name = "testTableDataModel" + plugin = createDbPlugin("gpkg") uri = QgsDataSourceUri() uri.setDatabase(self.test_gpkg) self.assertTrue(plugin.addConnection(connection_name, uri)) - connection = createDbPlugin('gpkg', connection_name) + connection = createDbPlugin("gpkg", connection_name) connection.connect() db = connection.database() @@ -277,36 +294,39 @@ def testTableDataModel(self): tables = db.tables() self.assertEqual(len(tables), 1) table = tables[0] - self.assertEqual(table.name, 'testLayer') + self.assertEqual(table.name, "testLayer") model = table.tableDataModel(None) self.assertEqual(model.rowCount(), 1) self.assertEqual(model.getData(0, 0), 1) # fid - self.assertEqual(model.getData(0, 1), 'LINESTRING (1 2,3 4)') - self.assertEqual(model.getData(0, 2), 'foo') + self.assertEqual(model.getData(0, 1), "LINESTRING (1 2,3 4)") + self.assertEqual(model.getData(0, 2), "foo") connection.remove() def testRaster(self): - connection_name = 'testRaster' - plugin = createDbPlugin('gpkg') + connection_name = "testRaster" + plugin = createDbPlugin("gpkg") uri = QgsDataSourceUri() - test_gpkg_new = os.path.join(self.basetestpath, 'testRaster.gpkg') + test_gpkg_new = os.path.join(self.basetestpath, "testRaster.gpkg") shutil.copy(self.test_gpkg, test_gpkg_new) - mem_ds = gdal.GetDriverByName('MEM').Create('', 20, 20) + mem_ds = gdal.GetDriverByName("MEM").Create("", 20, 20) mem_ds.SetGeoTransform([2, 0.01, 0, 49, 0, -0.01]) sr = osr.SpatialReference() sr.ImportFromEPSG(4326) mem_ds.SetProjection(sr.ExportToWkt()) mem_ds.GetRasterBand(1).Fill(255) - gdal.GetDriverByName('GPKG').CreateCopy(test_gpkg_new, mem_ds, - options=['APPEND_SUBDATASET=YES', 'RASTER_TABLE=raster_table']) + gdal.GetDriverByName("GPKG").CreateCopy( + test_gpkg_new, + mem_ds, + options=["APPEND_SUBDATASET=YES", "RASTER_TABLE=raster_table"], + ) mem_ds = None uri.setDatabase(test_gpkg_new) self.assertTrue(plugin.addConnection(connection_name, uri)) - connection = createDbPlugin('gpkg', connection_name) + connection = createDbPlugin("gpkg", connection_name) connection.connect() db = connection.database() @@ -316,7 +336,7 @@ def testRaster(self): self.assertEqual(len(tables), 2) table = None for i in range(2): - if tables[i].name == 'raster_table': + if tables[i].name == "raster_table": table = tables[i] break self.assertIsNotNone(table) @@ -328,28 +348,33 @@ def testRaster(self): connection.remove() def testTwoRaster(self): - connection_name = 'testTwoRaster' - plugin = createDbPlugin('gpkg') + connection_name = "testTwoRaster" + plugin = createDbPlugin("gpkg") uri = QgsDataSourceUri() - test_gpkg_new = os.path.join(self.basetestpath, 'testTwoRaster.gpkg') + test_gpkg_new = os.path.join(self.basetestpath, "testTwoRaster.gpkg") shutil.copy(self.test_gpkg, test_gpkg_new) - mem_ds = gdal.GetDriverByName('MEM').Create('', 20, 20) + mem_ds = gdal.GetDriverByName("MEM").Create("", 20, 20) mem_ds.SetGeoTransform([2, 0.01, 0, 49, 0, -0.01]) sr = osr.SpatialReference() sr.ImportFromEPSG(4326) mem_ds.SetProjection(sr.ExportToWkt()) mem_ds.GetRasterBand(1).Fill(255) for i in range(2): - gdal.GetDriverByName('GPKG').CreateCopy(test_gpkg_new, mem_ds, options=['APPEND_SUBDATASET=YES', - 'RASTER_TABLE=raster_table%d' % ( - i + 1)]) + gdal.GetDriverByName("GPKG").CreateCopy( + test_gpkg_new, + mem_ds, + options=[ + "APPEND_SUBDATASET=YES", + "RASTER_TABLE=raster_table%d" % (i + 1), + ], + ) mem_ds = None uri.setDatabase(test_gpkg_new) self.assertTrue(plugin.addConnection(connection_name, uri)) - connection = createDbPlugin('gpkg', connection_name) + connection = createDbPlugin("gpkg", connection_name) connection.connect() db = connection.database() @@ -359,7 +384,7 @@ def testTwoRaster(self): self.assertEqual(len(tables), 3) table = None for i in range(2): - if tables[i].name.startswith('raster_table'): + if tables[i].name.startswith("raster_table"): table = tables[i] info = table.info() info.toHtml() @@ -368,16 +393,16 @@ def testTwoRaster(self): def testNonSpatial(self): - connection_name = 'testNonSpatial' - plugin = createDbPlugin('gpkg') + connection_name = "testNonSpatial" + plugin = createDbPlugin("gpkg") uri = QgsDataSourceUri() - test_gpkg = os.path.join(self.basetestpath, 'testNonSpatial.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(test_gpkg) - lyr = ds.CreateLayer('testNonSpatial', geom_type=ogr.wkbNone) - lyr.CreateField(ogr.FieldDefn('text_field', ogr.OFTString)) + test_gpkg = os.path.join(self.basetestpath, "testNonSpatial.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(test_gpkg) + lyr = ds.CreateLayer("testNonSpatial", geom_type=ogr.wkbNone) + lyr.CreateField(ogr.FieldDefn("text_field", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f['text_field'] = 'foo' + f["text_field"] = "foo" lyr.CreateFeature(f) f = None ds = None @@ -385,7 +410,7 @@ def testNonSpatial(self): uri.setDatabase(test_gpkg) self.assertTrue(plugin.addConnection(connection_name, uri)) - connection = createDbPlugin('gpkg', connection_name) + connection = createDbPlugin("gpkg", connection_name) connection.connect() db = connection.database() @@ -394,7 +419,7 @@ def testNonSpatial(self): tables = db.tables() self.assertEqual(len(tables), 1) table = tables[0] - self.assertEqual(table.name, 'testNonSpatial') + self.assertEqual(table.name, "testNonSpatial") info = table.info() expected_html = """

    General info

    Relation type: Table 
    Rows: 

    Fields

    Name Type Null Default 
    fid INTEGER  
    text_field TEXT  
    """ @@ -403,36 +428,40 @@ def testNonSpatial(self): # GDAL 2.3.0 expected_html_3 = """

    General info

    Relation type: Table 
    Rows: 

    Fields

    Name Type Null Default 
    fid INTEGER  
    text_field TEXT  

    Triggers

    Name Function 
    trigger_insert_feature_count_testNonSpatial (deleteCREATE TRIGGER "trigger_insert_feature_count_testNonSpatial" AFTER INSERT ON "testNonSpatial" BEGIN UPDATE gpkg_ogr_contents SET feature_count = feature_count + 1 WHERE lower(table_name) = lower('testNonSpatial'); END 
    trigger_delete_feature_count_testNonSpatial (deleteCREATE TRIGGER "trigger_delete_feature_count_testNonSpatial" AFTER DELETE ON "testNonSpatial" BEGIN UPDATE gpkg_ogr_contents SET feature_count = feature_count - 1 WHERE lower(table_name) = lower('testNonSpatial'); END 
    """ - self.assertIn(info.toHtml(), [expected_html, expected_html_2, expected_html_3], info.toHtml()) + self.assertIn( + info.toHtml(), + [expected_html, expected_html_2, expected_html_3], + info.toHtml(), + ) connection.remove() def testAllGeometryTypes(self): - connection_name = 'testAllGeometryTypes' - plugin = createDbPlugin('gpkg') + connection_name = "testAllGeometryTypes" + plugin = createDbPlugin("gpkg") uri = QgsDataSourceUri() - test_gpkg = os.path.join(self.basetestpath, 'testAllGeometryTypes.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(test_gpkg) - ds.CreateLayer('testPoint', geom_type=ogr.wkbPoint) - ds.CreateLayer('testLineString', geom_type=ogr.wkbLineString) - ds.CreateLayer('testPolygon', geom_type=ogr.wkbPolygon) - ds.CreateLayer('testMultiPoint', geom_type=ogr.wkbMultiPoint) - ds.CreateLayer('testMultiLineString', geom_type=ogr.wkbMultiLineString) - ds.CreateLayer('testMultiPolygon', geom_type=ogr.wkbMultiPolygon) - ds.CreateLayer('testGeometryCollection', geom_type=ogr.wkbGeometryCollection) - ds.CreateLayer('testCircularString', geom_type=ogr.wkbCircularString) - ds.CreateLayer('testCompoundCurve', geom_type=ogr.wkbCompoundCurve) - ds.CreateLayer('testCurvePolygon', geom_type=ogr.wkbCurvePolygon) - ds.CreateLayer('testMultiCurve', geom_type=ogr.wkbMultiCurve) - ds.CreateLayer('testMultiSurface', geom_type=ogr.wkbMultiSurface) + test_gpkg = os.path.join(self.basetestpath, "testAllGeometryTypes.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(test_gpkg) + ds.CreateLayer("testPoint", geom_type=ogr.wkbPoint) + ds.CreateLayer("testLineString", geom_type=ogr.wkbLineString) + ds.CreateLayer("testPolygon", geom_type=ogr.wkbPolygon) + ds.CreateLayer("testMultiPoint", geom_type=ogr.wkbMultiPoint) + ds.CreateLayer("testMultiLineString", geom_type=ogr.wkbMultiLineString) + ds.CreateLayer("testMultiPolygon", geom_type=ogr.wkbMultiPolygon) + ds.CreateLayer("testGeometryCollection", geom_type=ogr.wkbGeometryCollection) + ds.CreateLayer("testCircularString", geom_type=ogr.wkbCircularString) + ds.CreateLayer("testCompoundCurve", geom_type=ogr.wkbCompoundCurve) + ds.CreateLayer("testCurvePolygon", geom_type=ogr.wkbCurvePolygon) + ds.CreateLayer("testMultiCurve", geom_type=ogr.wkbMultiCurve) + ds.CreateLayer("testMultiSurface", geom_type=ogr.wkbMultiSurface) ds = None uri.setDatabase(test_gpkg) self.assertTrue(plugin.addConnection(connection_name, uri)) - connection = createDbPlugin('gpkg', connection_name) + connection = createDbPlugin("gpkg", connection_name) connection.connect() db = connection.database() @@ -445,24 +474,42 @@ def testAllGeometryTypes(self): connection.remove() - def testAmphibiousMode(self, ): - connectionName = 'geopack1' - plugin = createDbPlugin('gpkg') + def testAmphibiousMode( + self, + ): + connectionName = "geopack1" + plugin = createDbPlugin("gpkg") uri = QgsDataSourceUri() - test_gpkg = os.path.join(os.path.join(unitTestDataPath(), 'provider'), 'test_json.gpkg') + test_gpkg = os.path.join( + os.path.join(unitTestDataPath(), "provider"), "test_json.gpkg" + ) uri.setDatabase(test_gpkg) plugin.addConnection(connectionName, uri) - connection = createDbPlugin('gpkg', connectionName) + connection = createDbPlugin("gpkg", connectionName) connection.connect() db = connection.database() - res = db.connector._execute(None, f"SELECT St_area({db.tables()[0].fields()[1].name}) from foo") + res = db.connector._execute( + None, f"SELECT St_area({db.tables()[0].fields()[1].name}) from foo" + ) results = [row for row in res] - self.assertEqual(results, - [(215229.265625,), (247328.171875,), (261752.78125,), (547597.2109375,), (15775.7578125,), - (101429.9765625,), (268597.625,), (1634833.390625,), (596610.3359375,), (5268.8125,)]) + self.assertEqual( + results, + [ + (215229.265625,), + (247328.171875,), + (261752.78125,), + (547597.2109375,), + (15775.7578125,), + (101429.9765625,), + (268597.625,), + (1634833.390625,), + (596610.3359375,), + (5268.8125,), + ], + ) connection.remove() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_db_manager_postgis.py b/tests/src/python/test_db_manager_postgis.py index 438c5ec51d2a..95505e1bc0a8 100644 --- a/tests/src/python/test_db_manager_postgis.py +++ b/tests/src/python/test_db_manager_postgis.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Luigi Pirelli' -__date__ = '2017-11-02' -__copyright__ = 'Copyright 2017, Boundless Spatial Inc' + +__author__ = "Luigi Pirelli" +__date__ = "2017-11-02" +__copyright__ = "Copyright 2017, Boundless Spatial Inc" import glob import os @@ -33,8 +34,10 @@ from utilities import unitTestDataPath -QGIS_POSTGRES_SERVER_PORT = os.environ.get('QGIS_POSTGRES_SERVER_PORT', '55432') -QGIS_POSTGRES_EXECUTABLE_PATH = os.environ.get('QGIS_POSTGRES_EXECUTABLE_PATH', '/usr/lib/postgresql/9.4/bin') +QGIS_POSTGRES_SERVER_PORT = os.environ.get("QGIS_POSTGRES_SERVER_PORT", "55432") +QGIS_POSTGRES_EXECUTABLE_PATH = os.environ.get( + "QGIS_POSTGRES_EXECUTABLE_PATH", "/usr/lib/postgresql/9.4/bin" +) assert os.path.exists(QGIS_POSTGRES_EXECUTABLE_PATH) @@ -43,7 +46,7 @@ # Postgres test path QGIS_PG_TEST_PATH = tempfile.mkdtemp() -os.environ['QGIS_AUTH_DB_DIR_PATH'] = QGIS_AUTH_DB_DIR_PATH +os.environ["QGIS_AUTH_DB_DIR_PATH"] = QGIS_AUTH_DB_DIR_PATH qgis_app = start_app() @@ -68,7 +71,7 @@ host all all ::1/32 trust """ -TEST_CONNECTION_NAME = 'test_connection' +TEST_CONNECTION_NAME = "test_connection" class TestPyQgsDBManagerPostgis(QgisTestCase): @@ -77,13 +80,15 @@ class TestPyQgsDBManagerPostgis(QgisTestCase): def setUpAuth(cls): """Run before all tests and set up authentication""" authm = QgsApplication.authManager() - assert (authm.setMasterPassword('masterpassword', True)) - cls.pg_conf = os.path.join(cls.tempfolder, 'postgresql.conf') - cls.pg_hba = os.path.join(cls.tempfolder, 'pg_hba.conf') + assert authm.setMasterPassword("masterpassword", True) + cls.pg_conf = os.path.join(cls.tempfolder, "postgresql.conf") + cls.pg_hba = os.path.join(cls.tempfolder, "pg_hba.conf") # Client side - cls.sslrootcert_path = os.path.join(cls.certsdata_path, 'chains_subissuer-issuer-root_issuer2-root2.pem') - cls.sslcert = os.path.join(cls.certsdata_path, 'gerardus_cert.pem') - cls.sslkey = os.path.join(cls.certsdata_path, 'gerardus_key.pem') + cls.sslrootcert_path = os.path.join( + cls.certsdata_path, "chains_subissuer-issuer-root_issuer2-root2.pem" + ) + cls.sslcert = os.path.join(cls.certsdata_path, "gerardus_cert.pem") + cls.sslkey = os.path.join(cls.certsdata_path, "gerardus_key.pem") assert os.path.isfile(cls.sslcert) assert os.path.isfile(cls.sslkey) assert os.path.isfile(cls.sslrootcert_path) @@ -91,38 +96,41 @@ def setUpAuth(cls): os.chmod(cls.sslkey, stat.S_IRUSR) os.chmod(cls.sslrootcert_path, stat.S_IRUSR) cls.auth_config = QgsAuthMethodConfig("PKI-Paths") - cls.auth_config.setConfig('certpath', cls.sslcert) - cls.auth_config.setConfig('keypath', cls.sslkey) - cls.auth_config.setName('test_pki_auth_config') - cls.username = 'Gerardus' + cls.auth_config.setConfig("certpath", cls.sslcert) + cls.auth_config.setConfig("keypath", cls.sslkey) + cls.auth_config.setName("test_pki_auth_config") + cls.username = "Gerardus" cls.sslrootcert = QSslCertificate.fromPath(cls.sslrootcert_path) assert cls.sslrootcert is not None authm.storeCertAuthorities(cls.sslrootcert) authm.rebuildCaCertsCache() authm.rebuildTrustedCaCertsCache() authm.rebuildCertTrustCache() - assert (authm.storeAuthenticationConfig(cls.auth_config)[0]) + assert authm.storeAuthenticationConfig(cls.auth_config)[0] assert cls.auth_config.isValid() # Server side - cls.server_cert = os.path.join(cls.certsdata_path, 'localhost_ssl_cert.pem') - cls.server_key = os.path.join(cls.certsdata_path, 'localhost_ssl_key.pem') + cls.server_cert = os.path.join(cls.certsdata_path, "localhost_ssl_cert.pem") + cls.server_key = os.path.join(cls.certsdata_path, "localhost_ssl_key.pem") cls.server_rootcert = cls.sslrootcert_path os.chmod(cls.server_cert, stat.S_IRUSR) os.chmod(cls.server_key, stat.S_IRUSR) os.chmod(cls.server_rootcert, stat.S_IRUSR) # Place conf in the data folder - with open(cls.pg_conf, 'w+') as f: - f.write(QGIS_POSTGRES_CONF_TEMPLATE % { - 'port': cls.port, - 'tempfolder': cls.tempfolder, - 'server_cert': cls.server_cert, - 'server_key': cls.server_key, - 'sslrootcert_path': cls.sslrootcert_path, - }) - - with open(cls.pg_hba, 'w+') as f: + with open(cls.pg_conf, "w+") as f: + f.write( + QGIS_POSTGRES_CONF_TEMPLATE + % { + "port": cls.port, + "tempfolder": cls.tempfolder, + "server_cert": cls.server_cert, + "server_key": cls.server_key, + "sslrootcert_path": cls.sslrootcert_path, + } + ) + + with open(cls.pg_hba, "w+") as f: f.write(QGIS_POSTGRES_HBA_TEMPLATE) @classmethod @@ -130,22 +138,30 @@ def setUpServer(cls): """Run before all tests: Creates an auth configuration""" cls.port = QGIS_POSTGRES_SERVER_PORT - cls.dbname = 'test_pki' + cls.dbname = "test_pki" cls.tempfolder = QGIS_PG_TEST_PATH - cls.certsdata_path = os.path.join(unitTestDataPath('auth_system'), 'certs_keys') - cls.hostname = 'localhost' - cls.data_path = os.path.join(cls.tempfolder, 'data') + cls.certsdata_path = os.path.join(unitTestDataPath("auth_system"), "certs_keys") + cls.hostname = "localhost" + cls.data_path = os.path.join(cls.tempfolder, "data") os.mkdir(cls.data_path) cls.setUpAuth() - subprocess.check_call([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'initdb'), '-D', cls.data_path]) - - cls.server = subprocess.Popen([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'postgres'), '-D', - cls.data_path, '-c', - f"config_file={cls.pg_conf}"], - env=os.environ, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + subprocess.check_call( + [os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "initdb"), "-D", cls.data_path] + ) + + cls.server = subprocess.Popen( + [ + os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "postgres"), + "-D", + cls.data_path, + "-c", + f"config_file={cls.pg_conf}", + ], + env=os.environ, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) # Wait max 10 secs for the server to start end = time.time() + 10 while True: @@ -156,28 +172,71 @@ def setUpServer(cls): if time.time() > end: raise Exception("Timeout connecting to PostgreSQL") # Create a DB - subprocess.check_call([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'createdb'), '-h', 'localhost', '-p', cls.port, 'test_pki']) + subprocess.check_call( + [ + os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "createdb"), + "-h", + "localhost", + "-p", + cls.port, + "test_pki", + ] + ) # Inject test SQL from test path - test_sql = os.path.join(unitTestDataPath('provider'), 'testdata_pg.sql') - subprocess.check_call([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'psql'), '-h', 'localhost', '-p', cls.port, '-f', test_sql, cls.dbname]) + test_sql = os.path.join(unitTestDataPath("provider"), "testdata_pg.sql") + subprocess.check_call( + [ + os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "psql"), + "-h", + "localhost", + "-p", + cls.port, + "-f", + test_sql, + cls.dbname, + ] + ) # Create a role - subprocess.check_call([os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, 'psql'), '-h', 'localhost', '-p', cls.port, '-c', f'CREATE ROLE "{cls.username}" WITH SUPERUSER LOGIN', cls.dbname]) + subprocess.check_call( + [ + os.path.join(QGIS_POSTGRES_EXECUTABLE_PATH, "psql"), + "-h", + "localhost", + "-p", + cls.port, + "-c", + f'CREATE ROLE "{cls.username}" WITH SUPERUSER LOGIN', + cls.dbname, + ] + ) @classmethod def setUpProvider(cls, authId): - cls.dbconn = 'service=qgis_test' - if 'QGIS_PGTEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_PGTEST_DB'] + cls.dbconn = "service=qgis_test" + if "QGIS_PGTEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_PGTEST_DB"] uri = QgsDataSourceUri() - uri.setConnection("localhost", cls.port, cls.dbname, "", "", QgsDataSourceUri.SslMode.SslVerifyFull, authId) - uri.setKeyColumn('pk') - uri.setSrid('EPSG:4326') - uri.setDataSource('qgis_test', 'someData', "geom", "", "pk") - provider = QgsProviderRegistry.instance().createProvider('postgres', uri.uri(False)) + uri.setConnection( + "localhost", + cls.port, + cls.dbname, + "", + "", + QgsDataSourceUri.SslMode.SslVerifyFull, + authId, + ) + uri.setKeyColumn("pk") + uri.setSrid("EPSG:4326") + uri.setDataSource("qgis_test", "someData", "geom", "", "pk") + provider = QgsProviderRegistry.instance().createProvider( + "postgres", uri.uri(False) + ) if provider is None: raise Exception("cannot create postgres provider") if not provider.isValid(): - raise Exception(f"Created postgres provider is not valid: {str(provider.errors())}") + raise Exception( + f"Created postgres provider is not valid: {str(provider.errors())}" + ) # save provider config that is the way how db_manager is aware of a PG connection cls.addConnectionConfig(TEST_CONNECTION_NAME, uri) @@ -231,10 +290,10 @@ def tearDownClass(cls): ########################################### def testSupportedDbTypes(self): - self.assertIn('postgis', supportedDbTypes()) + self.assertIn("postgis", supportedDbTypes()) def testCreateDbPlugin(self): - plugin = createDbPlugin('postgis') + plugin = createDbPlugin("postgis") self.assertIsNotNone(plugin) def testConnect(self): @@ -242,7 +301,7 @@ def testConnect(self): # that will be listed in postgis connection of db_manager self.setUpProvider(self.auth_config.id()) - plugin = createDbPlugin('postgis') + plugin = createDbPlugin("postgis") connections = plugin.connections() self.assertEqual(len(connections), 1) # test connection @@ -252,14 +311,14 @@ def testConnect(self): self.assertTrue(postgisConnPlugin.remove()) self.assertEqual(len(plugin.connections()), 0) # test without connection params => fail - connection = createDbPlugin('postgis', 'conn name') + connection = createDbPlugin("postgis", "conn name") connection_succeeded = False try: connection.connect() connection_succeeded = True except: pass - self.assertFalse(connection_succeeded, 'exception should have been raised') + self.assertFalse(connection_succeeded, "exception should have been raised") def testRemoveTemporaryCerts(self): """ @@ -268,7 +327,7 @@ def testRemoveTemporaryCerts(self): """ def cleanTempPki(): - pkies = glob.glob(os.path.join(tempfile.gettempdir(), 'tmp*_{*}.pem')) + pkies = glob.glob(os.path.join(tempfile.gettempdir(), "tmp*_{*}.pem")) for fn in pkies: f = QFile(fn) f.setPermissions(QFile.Permission.WriteOwner) @@ -279,16 +338,16 @@ def cleanTempPki(): cleanTempPki() # connect self.setUpProvider(self.auth_config.id()) - plugin = createDbPlugin('postgis') + plugin = createDbPlugin("postgis") connections = plugin.connections() self.assertEqual(len(connections), 1) # test connection postgisConnPlugin = connections[0] self.assertTrue(postgisConnPlugin.connect()) # do test no certs remained - pkies = glob.glob(os.path.join(tempfile.gettempdir(), 'tmp*_{*}.pem')) + pkies = glob.glob(os.path.join(tempfile.gettempdir(), "tmp*_{*}.pem")) self.assertEqual(len(pkies), 0) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_db_manager_spatialite.py b/tests/src/python/test_db_manager_spatialite.py index 213e14273a89..db83c4c3c133 100644 --- a/tests/src/python/test_db_manager_spatialite.py +++ b/tests/src/python/test_db_manager_spatialite.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Even Rouault' -__date__ = '2016-10-17' -__copyright__ = 'Copyright 2016, Even Rouault' + +__author__ = "Even Rouault" +__date__ = "2016-10-17" +__copyright__ = "Copyright 2016, Even Rouault" import os import shutil @@ -23,7 +24,7 @@ def GDAL_COMPUTE_VERSION(maj, min, rev): - return ((maj) * 1000000 + (min) * 10000 + (rev) * 100) + return (maj) * 1000000 + (min) * 10000 + (rev) * 100 class TestPyQgsDBManagerSpatialite(QgisTestCase): @@ -41,14 +42,18 @@ def setUpClass(cls): cls.basetestpath = tempfile.mkdtemp() - cls.test_spatialite = os.path.join(cls.basetestpath, 'TestPyQgsDBManagerSpatialite.spatialite') - ds = ogr.GetDriverByName('SQLite').CreateDataSource(cls.test_spatialite) - lyr = ds.CreateLayer('testlayer', geom_type=ogr.wkbLineString, options=['SPATIAL_INDEX=NO']) + cls.test_spatialite = os.path.join( + cls.basetestpath, "TestPyQgsDBManagerSpatialite.spatialite" + ) + ds = ogr.GetDriverByName("SQLite").CreateDataSource(cls.test_spatialite) + lyr = ds.CreateLayer( + "testlayer", geom_type=ogr.wkbLineString, options=["SPATIAL_INDEX=NO"] + ) cls.supportsAlterFieldDefn = lyr.TestCapability(ogr.OLCAlterFieldDefn) == 1 - lyr.CreateField(ogr.FieldDefn('text_field', ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("text_field", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f['text_field'] = 'foo' - f.SetGeometry(ogr.CreateGeometryFromWkt('LINESTRING(1 2,3 4)')) + f["text_field"] = "foo" + f.SetGeometry(ogr.CreateGeometryFromWkt("LINESTRING(1 2,3 4)")) lyr.CreateFeature(f) f = None ds = None @@ -62,15 +67,15 @@ def tearDownClass(cls): super().tearDownClass() def testSupportedDbTypes(self): - self.assertIn('spatialite', supportedDbTypes()) + self.assertIn("spatialite", supportedDbTypes()) def testCreateDbPlugin(self): - plugin = createDbPlugin('spatialite') + plugin = createDbPlugin("spatialite") self.assertIsNotNone(plugin) def testConnect(self): - connection_name = 'testConnect' - plugin = createDbPlugin('spatialite') + connection_name = "testConnect" + plugin = createDbPlugin("spatialite") uri = QgsDataSourceUri() uri.setDatabase(self.test_spatialite) @@ -79,14 +84,14 @@ def testConnect(self): connections = plugin.connections() self.assertEqual(len(connections), 1) - connection = createDbPlugin('spatialite', connection_name + '_does_not_exist') + connection = createDbPlugin("spatialite", connection_name + "_does_not_exist") connection_succeeded = False try: connection.connect() connection_succeeded = True except: pass - self.assertFalse(connection_succeeded, 'exception should have been raised') + self.assertFalse(connection_succeeded, "exception should have been raised") connection = connections[0] connection.connect() @@ -97,37 +102,37 @@ def testConnect(self): self.assertEqual(len(plugin.connections()), 0) - connection = createDbPlugin('spatialite', connection_name) + connection = createDbPlugin("spatialite", connection_name) connection_succeeded = False try: connection.connect() connection_succeeded = True except: pass - self.assertFalse(connection_succeeded, 'exception should have been raised') + self.assertFalse(connection_succeeded, "exception should have been raised") def testExecuteRegExp(self): """This test checks for REGEXP syntax support, which is enabled in Qgis.utils' spatialite_connection()""" - connection_name = 'testListLayer' - plugin = createDbPlugin('spatialite') + connection_name = "testListLayer" + plugin = createDbPlugin("spatialite") uri = QgsDataSourceUri() uri.setDatabase(self.test_spatialite) self.assertTrue(plugin.addConnection(connection_name, uri)) - connection = createDbPlugin('spatialite', connection_name) + connection = createDbPlugin("spatialite", connection_name) connection.connect() db = connection.database() - db.connector._execute(None, 'SELECT \'ABC\' REGEXP \'[CBA]\'') + db.connector._execute(None, "SELECT 'ABC' REGEXP '[CBA]'") def testListLayer(self): - connection_name = 'testListLayer' - plugin = createDbPlugin('spatialite') + connection_name = "testListLayer" + plugin = createDbPlugin("spatialite") uri = QgsDataSourceUri() uri.setDatabase(self.test_spatialite) self.assertTrue(plugin.addConnection(connection_name, uri)) - connection = createDbPlugin('spatialite', connection_name) + connection = createDbPlugin("spatialite", connection_name) connection.connect() db = connection.database() @@ -136,7 +141,7 @@ def testListLayer(self): tables = db.tables() self.assertEqual(len(tables), 1) table = tables[0] - self.assertEqual(table.name, 'testlayer') + self.assertEqual(table.name, "testlayer") info = table.info() # expected_html = """

    General info

    Relation type: Table 
    Rows: 

    GeoPackage

    Column: geom 
    Geometry: LINESTRING 
    Dimension: XY 
    Spatial ref: Undefined (-1) 
    Extent: 1.00000, 2.00000 - 3.00000, 4.00000 

    No spatial index defined (create it)

    Fields

    Name Type Null Default 
    fid INTEGER  
    geom LINESTRING  
    text_field TEXT  
    """ @@ -155,17 +160,19 @@ def testListLayer(self): connection.remove() def testCreateRenameDeleteTable(self): - connection_name = 'testCreateRenameDeleteTable' - plugin = createDbPlugin('spatialite') + connection_name = "testCreateRenameDeleteTable" + plugin = createDbPlugin("spatialite") uri = QgsDataSourceUri() - test_spatialite_new = os.path.join(self.basetestpath, 'testCreateRenameDeleteTable.spatialite') + test_spatialite_new = os.path.join( + self.basetestpath, "testCreateRenameDeleteTable.spatialite" + ) shutil.copy(self.test_spatialite, test_spatialite_new) uri.setDatabase(test_spatialite_new) self.assertTrue(plugin.addConnection(connection_name, uri)) - connection = createDbPlugin('spatialite', connection_name) + connection = createDbPlugin("spatialite", connection_name) connection.connect() db = connection.database() @@ -174,8 +181,8 @@ def testCreateRenameDeleteTable(self): tables = db.tables() self.assertEqual(len(tables), 1) table = tables[0] - self.assertTrue(table.rename('newName')) - self.assertEqual(table.name, 'newName') + self.assertTrue(table.rename("newName")) + self.assertEqual(table.name, "newName") connection.reconnect() @@ -183,28 +190,28 @@ def testCreateRenameDeleteTable(self): tables = db.tables() self.assertEqual(len(tables), 1) table = tables[0] - self.assertEqual(table.name, 'newName') + self.assertEqual(table.name, "newName") fields = [] - geom = ['geometry', 'POINT', 4326, 3] + geom = ["geometry", "POINT", 4326, 3] field1 = TableField(table) - field1.name = 'fid' - field1.dataType = 'INTEGER' + field1.name = "fid" + field1.dataType = "INTEGER" field1.notNull = True field1.primaryKey = True field2 = TableField(table) - field2.name = 'str_field' - field2.dataType = 'TEXT' + field2.name = "str_field" + field2.dataType = "TEXT" field2.modifier = 20 fields = [field1, field2] - self.assertTrue(db.createVectorTable('newName2', fields, geom)) + self.assertTrue(db.createVectorTable("newName2", fields, geom)) tables = db.tables() self.assertEqual(len(tables), 2) new_table = tables[1] - self.assertEqual(new_table.name, 'newName2') + self.assertEqual(new_table.name, "newName2") fields = new_table.fields() self.assertEqual(len(fields), 2) @@ -226,17 +233,19 @@ def testCreateRenameDeleteFields(self): if not self.supportsAlterFieldDefn: return - connection_name = 'testCreateRenameDeleteFields' - plugin = createDbPlugin('spatialite') + connection_name = "testCreateRenameDeleteFields" + plugin = createDbPlugin("spatialite") uri = QgsDataSourceUri() - test_spatialite_new = os.path.join(self.basetestpath, 'testCreateRenameDeleteFields.spatialite') + test_spatialite_new = os.path.join( + self.basetestpath, "testCreateRenameDeleteFields.spatialite" + ) shutil.copy(self.test_spatialite, test_spatialite_new) uri.setDatabase(test_spatialite_new) self.assertTrue(plugin.addConnection(connection_name, uri)) - connection = createDbPlugin('spatialite', connection_name) + connection = createDbPlugin("spatialite", connection_name) connection.connect() db = connection.database() @@ -249,8 +258,8 @@ def testCreateRenameDeleteFields(self): field_before_count = len(table.fields()) field = TableField(table) - field.name = 'real_field' - field.dataType = 'DOUBLE' + field.name = "real_field" + field.dataType = "DOUBLE" self.assertTrue(table.addField(field)) self.assertEqual(len(table.fields()), field_before_count + 1) @@ -259,8 +268,8 @@ def testCreateRenameDeleteFields(self): # self.assertTrue(field.update('real_field2', new_type_str='TEXT (30)', new_not_null=True, new_default_str='foo')) field = table.fields()[field_before_count] - self.assertEqual(field.name, 'real_field') - self.assertEqual(field.dataType, 'DOUBLE') + self.assertEqual(field.name, "real_field") + self.assertEqual(field.dataType, "DOUBLE") # self.assertEqual(field.notNull, 1) # self.assertEqual(field.default, "'foo'") @@ -271,13 +280,13 @@ def testCreateRenameDeleteFields(self): connection.remove() def testTableDataModel(self): - connection_name = 'testTableDataModel' - plugin = createDbPlugin('spatialite') + connection_name = "testTableDataModel" + plugin = createDbPlugin("spatialite") uri = QgsDataSourceUri() uri.setDatabase(self.test_spatialite) self.assertTrue(plugin.addConnection(connection_name, uri)) - connection = createDbPlugin('spatialite', connection_name) + connection = createDbPlugin("spatialite", connection_name) connection.connect() db = connection.database() @@ -286,7 +295,7 @@ def testTableDataModel(self): tables = db.tables() self.assertEqual(len(tables), 1) table = tables[0] - self.assertEqual(table.name, 'testlayer') + self.assertEqual(table.name, "testlayer") model = table.tableDataModel(None) self.assertEqual(model.rowCount(), 1) @@ -294,9 +303,9 @@ def testTableDataModel(self): wkb = model.getData(0, 1) geometry = ogr.CreateGeometryFromWkb(wkb) - self.assertEqual(geometry.ExportToWkt(), 'LINESTRING (1 2,3 4)') + self.assertEqual(geometry.ExportToWkt(), "LINESTRING (1 2,3 4)") - self.assertEqual(model.getData(0, 2), 'foo') + self.assertEqual(model.getData(0, 2), "foo") connection.remove() @@ -379,16 +388,16 @@ def testTableDataModel(self): def testNonSpatial(self): - connection_name = 'testnonspatial' - plugin = createDbPlugin('spatialite') + connection_name = "testnonspatial" + plugin = createDbPlugin("spatialite") uri = QgsDataSourceUri() - test_spatialite = os.path.join(self.basetestpath, 'testnonspatial.spatialite') - ds = ogr.GetDriverByName('SQLite').CreateDataSource(test_spatialite) - lyr = ds.CreateLayer('testnonspatial', geom_type=ogr.wkbNone) - lyr.CreateField(ogr.FieldDefn('text_field', ogr.OFTString)) + test_spatialite = os.path.join(self.basetestpath, "testnonspatial.spatialite") + ds = ogr.GetDriverByName("SQLite").CreateDataSource(test_spatialite) + lyr = ds.CreateLayer("testnonspatial", geom_type=ogr.wkbNone) + lyr.CreateField(ogr.FieldDefn("text_field", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f['text_field'] = 'foo' + f["text_field"] = "foo" lyr.CreateFeature(f) f = None ds = None @@ -396,7 +405,7 @@ def testNonSpatial(self): uri.setDatabase(test_spatialite) self.assertTrue(plugin.addConnection(connection_name, uri)) - connection = createDbPlugin('spatialite', connection_name) + connection = createDbPlugin("spatialite", connection_name) connection.connect() db = connection.database() @@ -405,7 +414,7 @@ def testNonSpatial(self): tables = db.tables() self.assertEqual(len(tables), 1) table = tables[0] - self.assertEqual(table.name, 'testnonspatial') + self.assertEqual(table.name, "testnonspatial") info = table.info() # expected_html = """

    General info

    Relation type: Table 
    Rows: 

    Fields

    Name Type Null Default 
    fid INTEGER  
    text_field TEXT  
    """ @@ -420,30 +429,32 @@ def testNonSpatial(self): def testAllGeometryTypes(self): - connection_name = 'testAllGeometryTypes' - plugin = createDbPlugin('spatialite') + connection_name = "testAllGeometryTypes" + plugin = createDbPlugin("spatialite") uri = QgsDataSourceUri() - test_spatialite = os.path.join(self.basetestpath, 'testAllGeometryTypes.spatialite') - ds = ogr.GetDriverByName('SQLite').CreateDataSource(test_spatialite) - ds.CreateLayer('testPoint', geom_type=ogr.wkbPoint) - ds.CreateLayer('testLineString', geom_type=ogr.wkbLineString) - ds.CreateLayer('testPolygon', geom_type=ogr.wkbPolygon) - ds.CreateLayer('testMultiPoint', geom_type=ogr.wkbMultiPoint) - ds.CreateLayer('testMultiLineString', geom_type=ogr.wkbMultiLineString) - ds.CreateLayer('testMultiPolygon', geom_type=ogr.wkbMultiPolygon) - ds.CreateLayer('testGeometryCollection', geom_type=ogr.wkbGeometryCollection) - ds.CreateLayer('testCircularString', geom_type=ogr.wkbCircularString) - ds.CreateLayer('testCompoundCurve', geom_type=ogr.wkbCompoundCurve) - ds.CreateLayer('testCurvePolygon', geom_type=ogr.wkbCurvePolygon) - ds.CreateLayer('testMultiCurve', geom_type=ogr.wkbMultiCurve) - ds.CreateLayer('testMultiSurface', geom_type=ogr.wkbMultiSurface) + test_spatialite = os.path.join( + self.basetestpath, "testAllGeometryTypes.spatialite" + ) + ds = ogr.GetDriverByName("SQLite").CreateDataSource(test_spatialite) + ds.CreateLayer("testPoint", geom_type=ogr.wkbPoint) + ds.CreateLayer("testLineString", geom_type=ogr.wkbLineString) + ds.CreateLayer("testPolygon", geom_type=ogr.wkbPolygon) + ds.CreateLayer("testMultiPoint", geom_type=ogr.wkbMultiPoint) + ds.CreateLayer("testMultiLineString", geom_type=ogr.wkbMultiLineString) + ds.CreateLayer("testMultiPolygon", geom_type=ogr.wkbMultiPolygon) + ds.CreateLayer("testGeometryCollection", geom_type=ogr.wkbGeometryCollection) + ds.CreateLayer("testCircularString", geom_type=ogr.wkbCircularString) + ds.CreateLayer("testCompoundCurve", geom_type=ogr.wkbCompoundCurve) + ds.CreateLayer("testCurvePolygon", geom_type=ogr.wkbCurvePolygon) + ds.CreateLayer("testMultiCurve", geom_type=ogr.wkbMultiCurve) + ds.CreateLayer("testMultiSurface", geom_type=ogr.wkbMultiSurface) ds = None uri.setDatabase(test_spatialite) self.assertTrue(plugin.addConnection(connection_name, uri)) - connection = createDbPlugin('spatialite', connection_name) + connection = createDbPlugin("spatialite", connection_name) connection.connect() db = connection.database() @@ -457,5 +468,5 @@ def testAllGeometryTypes(self): connection.remove() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_db_manager_sql_window.py b/tests/src/python/test_db_manager_sql_window.py index fff40ec7faac..374d281bded4 100644 --- a/tests/src/python/test_db_manager_sql_window.py +++ b/tests/src/python/test_db_manager_sql_window.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Stephen Knox' -__date__ = '2019-08-27' -__copyright__ = 'Copyright 2019, Stephen Knox' + +__author__ = "Stephen Knox" +__date__ = "2019-08-27" +__copyright__ = "Copyright 2019, Stephen Knox" from plugins.db_manager.dlg_sql_window import check_comments_in_sql from qgis.testing import unittest @@ -29,11 +30,15 @@ def test_check_comment_parsing(self): # One comment with a new line query = "SELECT * FROM test -- WHERE a = 1 \n ORDER BY b" - self.assertEqual(check_comments_in_sql(query), "SELECT * FROM test ORDER BY b") + self.assertEqual( + check_comments_in_sql(query), "SELECT * FROM test ORDER BY b" + ) # One comment with 2 new lines query = "SELECT * FROM test \n-- WHERE a = 1 \n ORDER BY b" - self.assertEqual(check_comments_in_sql(query), "SELECT * FROM test ORDER BY b") + self.assertEqual( + check_comments_in_sql(query), "SELECT * FROM test ORDER BY b" + ) # Only comment query = "--SELECT * FROM test" @@ -48,5 +53,5 @@ def test_check_comment_parsing(self): self.assertEqual(check_comments_in_sql(query), query) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_disabled_tests.py b/tests/src/python/test_disabled_tests.py index 6b920946b00a..64d18e0147ac 100644 --- a/tests/src/python/test_disabled_tests.py +++ b/tests/src/python/test_disabled_tests.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '10/08/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "10/08/2022" +__copyright__ = "Copyright 2022, The QGIS Project" import os import shutil @@ -38,12 +39,18 @@ def createChildren(self): children = [] # Add a Python object as child - pyQgsLayerItem = PyQgsLayerItem(None, "name", "", "uri", QgsLayerItem.LayerType.Vector, "my_provider") + pyQgsLayerItem = PyQgsLayerItem( + None, "name", "", "uri", QgsLayerItem.LayerType.Vector, "my_provider" + ) pyQgsLayerItem.tabSetDestroyedFlag = self.tabSetDestroyedFlag children.append(pyQgsLayerItem) # Add a C++ object as child - children.append(QgsLayerItem(None, "name2", "", "uri", QgsLayerItem.LayerType.Vector, "my_provider")) + children.append( + QgsLayerItem( + None, "name2", "", "uri", QgsLayerItem.LayerType.Vector, "my_provider" + ) + ) return children @@ -65,12 +72,14 @@ class TestQgsDisabledTests(QgisTestCase): def setUpClass(cls): """Run before all tests.""" super().setUpClass() - testPath = TEST_DATA_DIR + '/' + 'bug_17878.gpkg' + testPath = TEST_DATA_DIR + "/" + "bug_17878.gpkg" # Copy it tempdir = tempfile.mkdtemp() - testPathCopy = os.path.join(tempdir, 'bug_17878.gpkg') + testPathCopy = os.path.join(tempdir, "bug_17878.gpkg") shutil.copy(testPath, testPathCopy) - cls.vl = QgsVectorLayer(testPathCopy + '|layername=bug_17878', "test_data", "ogr") + cls.vl = QgsVectorLayer( + testPathCopy + "|layername=bug_17878", "test_data", "ogr" + ) assert cls.vl.isValid() @classmethod @@ -85,7 +94,7 @@ def test_dummy(self): """ pass - @unittest.skipIf(QT_VERSION >= 0x050d00, 'Crashes on newer Qt/PyQt versions') + @unittest.skipIf(QT_VERSION >= 0x050D00, "Crashes on newer Qt/PyQt versions") def testPythonCreateChildrenCalledFromCplusplus(self): """ test createChildren() method implemented in Python, called from C++ @@ -151,23 +160,25 @@ def _fld_checker(self, field): QValidator::Intermediate 1 The string is a plausible intermediate value. QValidator::Acceptable 2 The string is acceptable as a final result; i.e. it is valid. """ - validator = QgsFieldValidator(None, field, '0.0', '') + validator = QgsFieldValidator(None, field, "0.0", "") def _test(value, expected): ret = validator.validate(value, 0) self.assertEqual(ret[0], expected) if value: - self.assertEqual(validator.validate('-' + value, 0)[0], expected, '-' + value) + self.assertEqual( + validator.validate("-" + value, 0)[0], expected, "-" + value + ) # Valid - _test('0.1234', QValidator.State.Acceptable) + _test("0.1234", QValidator.State.Acceptable) # If precision is > 0, regexp validator is used (and it does not support sci notation) if field.precision() == 0: - _test('12345.1234e+123', QValidator.State.Acceptable) - _test('12345.1234e-123', QValidator.State.Acceptable) + _test("12345.1234e+123", QValidator.State.Acceptable) + _test("12345.1234e-123", QValidator.State.Acceptable) - @unittest.skipIf(QT_VERSION >= 0x050d00, 'Fails newer Qt/PyQt versions') + @unittest.skipIf(QT_VERSION >= 0x050D00, "Fails newer Qt/PyQt versions") def test_doubleValidatorCommaLocale(self): """Test the double with german locale @@ -182,10 +193,10 @@ def test_doubleValidatorCommaLocale(self): When fixed these tests should be merged back into test_qgsfieldvalidator.py """ QLocale.setDefault(QLocale(QLocale.Language.German, QLocale.Country.Germany)) - self.assertEqual(QLocale().decimalPoint(), ',') - field = self.vl.fields()[self.vl.fields().indexFromName('double_field')] + self.assertEqual(QLocale().decimalPoint(), ",") + field = self.vl.fields()[self.vl.fields().indexFromName("double_field")] self._fld_checker(field) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_hana_utils.py b/tests/src/python/test_hana_utils.py index edace17e8d8c..5955616c7a53 100644 --- a/tests/src/python/test_hana_utils.py +++ b/tests/src/python/test_hana_utils.py @@ -7,9 +7,9 @@ """ -__author__ = 'Maxim Rylov' -__date__ = '2019-11-21' -__copyright__ = 'Copyright 2019, The QGIS Project' +__author__ = "Maxim Rylov" +__date__ = "2019-11-21" +__copyright__ = "Copyright 2019, The QGIS Project" from hdbcli import dbapi from qgis.core import QgsDataSourceUri, QgsVectorLayer @@ -21,14 +21,21 @@ class QgsHanaProviderUtils: def createConnection(uri): ds_uri = QgsDataSourceUri(uri) encrypt = ds_uri.param("ENCRYPT") if ds_uri.hasParam("ENCRYPT") else True - conn = dbapi.connect(address=ds_uri.host(), port=ds_uri.port(), user=ds_uri.username(), - password=ds_uri.password(), ENCRYPT=encrypt, sslValidateCertificate=False, CHAR_AS_UTF8=1) + conn = dbapi.connect( + address=ds_uri.host(), + port=ds_uri.port(), + user=ds_uri.username(), + password=ds_uri.password(), + ENCRYPT=encrypt, + sslValidateCertificate=False, + CHAR_AS_UTF8=1, + ) conn.setautocommit(False) return conn @staticmethod def createVectorLayer(conn_parameters, layer_name): - layer = QgsVectorLayer(conn_parameters, layer_name, 'hana') + layer = QgsVectorLayer(conn_parameters, layer_name, "hana") assert layer.isValid() return layer @@ -64,18 +71,25 @@ def createAndFillTable(conn, create_statement, insert_statement, insert_args): @staticmethod def dropTableIfExists(conn, schema_name, table_name): - res = QgsHanaProviderUtils.executeSQLFetchOne(conn, - f"SELECT COUNT(*) FROM SYS.TABLES WHERE " - f"SCHEMA_NAME='{schema_name}' AND TABLE_NAME='{table_name}'") + res = QgsHanaProviderUtils.executeSQLFetchOne( + conn, + f"SELECT COUNT(*) FROM SYS.TABLES WHERE " + f"SCHEMA_NAME='{schema_name}' AND TABLE_NAME='{table_name}'", + ) if res != 0: - QgsHanaProviderUtils.executeSQL(conn, f'DROP TABLE "{schema_name}"."{table_name}" CASCADE') + QgsHanaProviderUtils.executeSQL( + conn, f'DROP TABLE "{schema_name}"."{table_name}" CASCADE' + ) @staticmethod def dropSchemaIfExists(conn, schema_name): - res = QgsHanaProviderUtils.executeSQLFetchOne(conn, - f"SELECT COUNT(*) FROM SYS.SCHEMAS WHERE SCHEMA_NAME='{schema_name}'") + res = QgsHanaProviderUtils.executeSQLFetchOne( + conn, f"SELECT COUNT(*) FROM SYS.SCHEMAS WHERE SCHEMA_NAME='{schema_name}'" + ) if res != 0: - QgsHanaProviderUtils.executeSQL(conn, f'DROP SCHEMA "{schema_name}" CASCADE') + QgsHanaProviderUtils.executeSQL( + conn, f'DROP SCHEMA "{schema_name}" CASCADE' + ) @staticmethod def createAndFillDefaultTables(conn, schema_name): @@ -83,43 +97,105 @@ def createAndFillDefaultTables(conn, schema_name): QgsHanaProviderUtils.executeSQL(conn, f'CREATE SCHEMA "{schema_name}"') - create_sql = f'CREATE TABLE "{schema_name}"."some_data" ( ' \ - '"pk" INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL PRIMARY KEY,' \ - '"cnt" INTEGER,' \ - '"name" NVARCHAR(32) DEFAULT \'qgis\',' \ - '"name2" NVARCHAR(32) DEFAULT \'qgis\',' \ - '"num_char" NVARCHAR(1),' \ - '"dt" TIMESTAMP,' \ - '"date" DATE,' \ - '"time" TIME,' \ + create_sql = ( + f'CREATE TABLE "{schema_name}"."some_data" ( ' + '"pk" INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL PRIMARY KEY,' + '"cnt" INTEGER,' + "\"name\" NVARCHAR(32) DEFAULT 'qgis'," + "\"name2\" NVARCHAR(32) DEFAULT 'qgis'," + '"num_char" NVARCHAR(1),' + '"dt" TIMESTAMP,' + '"date" DATE,' + '"time" TIME,' '"geom" ST_GEOMETRY(4326))' - insert_sql = f'INSERT INTO "{schema_name}"."some_data" ("pk", "cnt", "name", "name2", "num_char", "dt",' \ + ) + insert_sql = ( + f'INSERT INTO "{schema_name}"."some_data" ("pk", "cnt", "name", "name2", "num_char", "dt",' '"date", "time", "geom") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ST_GeomFromEWKB(?)) ' + ) insert_args = [ - [5, -200, None, 'NuLl', '5', '2020-05-04 12:13:14', '2020-05-02', '12:13:01', - bytes.fromhex('0101000020E61000001D5A643BDFC751C01F85EB51B88E5340')], - [3, 300, 'Pear', 'PEaR', '3', None, None, None, None], - [1, 100, 'Orange', 'oranGe', '1', '2020-05-03 12:13:14', '2020-05-03', '12:13:14', - bytes.fromhex('0101000020E61000006891ED7C3F9551C085EB51B81E955040')], - [2, 200, 'Apple', 'Apple', '2', '2020-05-04 12:14:14', '2020-05-04', '12:14:14', - bytes.fromhex('0101000020E6100000CDCCCCCCCC0C51C03333333333B35140')], - [4, 400, 'Honey', 'Honey', '4', '2021-05-04 13:13:14', '2021-05-04', '13:13:14', - bytes.fromhex('0101000020E610000014AE47E17A5450C03333333333935340')]] - QgsHanaProviderUtils.createAndFillTable(conn, create_sql, insert_sql, insert_args) - QgsHanaProviderUtils.executeSQL(conn, f'COMMENT ON TABLE "{schema_name}"."some_data" IS \'QGIS Test Table\'') - QgsHanaProviderUtils.executeSQL(conn, f'CREATE VIEW "{schema_name}"."some_data_view" AS SELECT * FROM ' - f'"{schema_name}"."some_data"') - - create_sql = f'CREATE TABLE "{schema_name}"."some_poly_data" ( ' \ - '"pk" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,' \ + [ + 5, + -200, + None, + "NuLl", + "5", + "2020-05-04 12:13:14", + "2020-05-02", + "12:13:01", + bytes.fromhex("0101000020E61000001D5A643BDFC751C01F85EB51B88E5340"), + ], + [3, 300, "Pear", "PEaR", "3", None, None, None, None], + [ + 1, + 100, + "Orange", + "oranGe", + "1", + "2020-05-03 12:13:14", + "2020-05-03", + "12:13:14", + bytes.fromhex("0101000020E61000006891ED7C3F9551C085EB51B81E955040"), + ], + [ + 2, + 200, + "Apple", + "Apple", + "2", + "2020-05-04 12:14:14", + "2020-05-04", + "12:14:14", + bytes.fromhex("0101000020E6100000CDCCCCCCCC0C51C03333333333B35140"), + ], + [ + 4, + 400, + "Honey", + "Honey", + "4", + "2021-05-04 13:13:14", + "2021-05-04", + "13:13:14", + bytes.fromhex("0101000020E610000014AE47E17A5450C03333333333935340"), + ], + ] + QgsHanaProviderUtils.createAndFillTable( + conn, create_sql, insert_sql, insert_args + ) + QgsHanaProviderUtils.executeSQL( + conn, f'COMMENT ON TABLE "{schema_name}"."some_data" IS \'QGIS Test Table\'' + ) + QgsHanaProviderUtils.executeSQL( + conn, + f'CREATE VIEW "{schema_name}"."some_data_view" AS SELECT * FROM ' + f'"{schema_name}"."some_data"', + ) + + create_sql = ( + f'CREATE TABLE "{schema_name}"."some_poly_data" ( ' + '"pk" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,' '"geom" ST_GEOMETRY(4326))' + ) insert_sql = f'INSERT INTO "{schema_name}"."some_poly_data" ("pk", "geom") VALUES (?, ST_GeomFromText(?, 4326))' insert_args = [ - [1, 'Polygon ((-69.0 81.4, -69.0 80.2, -73.7 80.2, -73.7 76.3, -74.9 76.3, -74.9 81.4, -69.0 81.4))'], - [2, 'Polygon ((-67.6 81.2, -66.3 81.2, -66.3 76.9, -67.6 76.9, -67.6 81.2))'], - [3, 'Polygon ((-68.4 75.8, -67.5 72.6, -68.6 73.7, -70.2 72.9, -68.4 75.8))'], - [4, None]] - QgsHanaProviderUtils.createAndFillTable(conn, create_sql, insert_sql, insert_args) + [ + 1, + "Polygon ((-69.0 81.4, -69.0 80.2, -73.7 80.2, -73.7 76.3, -74.9 76.3, -74.9 81.4, -69.0 81.4))", + ], + [ + 2, + "Polygon ((-67.6 81.2, -66.3 81.2, -66.3 76.9, -67.6 76.9, -67.6 81.2))", + ], + [ + 3, + "Polygon ((-68.4 75.8, -67.5 72.6, -68.6 73.7, -70.2 72.9, -68.4 75.8))", + ], + [4, None], + ] + QgsHanaProviderUtils.createAndFillTable( + conn, create_sql, insert_sql, insert_args + ) @staticmethod def cleanUp(conn, schema_name): @@ -129,4 +205,4 @@ def cleanUp(conn, schema_name): def generateSchemaName(conn, prefix): sql = "SELECT REPLACE(CURRENT_UTCDATE, '-', '') || '_' || BINTOHEX(SYSUUID) FROM DUMMY;" uid = QgsHanaProviderUtils.executeSQL(conn, sql, return_result=True) - return f'{prefix}_{uid}' + return f"{prefix}_{uid}" diff --git a/tests/src/python/test_layer_dependencies.py b/tests/src/python/test_layer_dependencies.py index 4001279f054f..8603a4fdb648 100644 --- a/tests/src/python/test_layer_dependencies.py +++ b/tests/src/python/test_layer_dependencies.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Hugo Mercier' -__date__ = '12/07/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Hugo Mercier" +__date__ = "12/07/2016" +__copyright__ = "Copyright 2016, The QGIS Project" import os import tempfile @@ -50,24 +51,42 @@ def setUp(self): cur.execute("SELECT InitSpatialMetadata(1)") cur.execute("create table node(id integer primary key autoincrement);") cur.execute("select AddGeometryColumn('node', 'geom', 4326, 'POINT');") - cur.execute("create table section(id integer primary key autoincrement, node1 integer, node2 integer);") + cur.execute( + "create table section(id integer primary key autoincrement, node1 integer, node2 integer);" + ) cur.execute("select AddGeometryColumn('section', 'geom', 4326, 'LINESTRING');") - cur.execute("create trigger add_nodes after insert on section begin insert into node (geom) values (st_startpoint(NEW.geom)); insert into node (geom) values (st_endpoint(NEW.geom)); end;") - cur.execute("insert into node (geom) values (geomfromtext('point(0 0)', 4326));") - cur.execute("insert into node (geom) values (geomfromtext('point(1 0)', 4326));") + cur.execute( + "create trigger add_nodes after insert on section begin insert into node (geom) values (st_startpoint(NEW.geom)); insert into node (geom) values (st_endpoint(NEW.geom)); end;" + ) + cur.execute( + "insert into node (geom) values (geomfromtext('point(0 0)', 4326));" + ) + cur.execute( + "insert into node (geom) values (geomfromtext('point(1 0)', 4326));" + ) cur.execute("create table node2(id integer primary key autoincrement);") cur.execute("select AddGeometryColumn('node2', 'geom', 4326, 'POINT');") - cur.execute("create trigger add_nodes2 after insert on node begin insert into node2 (geom) values (st_translate(NEW.geom, 0.2, 0, 0)); end;") + cur.execute( + "create trigger add_nodes2 after insert on node begin insert into node2 (geom) values (st_translate(NEW.geom, 0.2, 0, 0)); end;" + ) con.commit() con.close() - self.pointsLayer = QgsVectorLayer(f"dbname='{fn}' table=\"node\" (geom) sql=", "points", "spatialite") - assert (self.pointsLayer.isValid()) - self.linesLayer = QgsVectorLayer(f"dbname='{fn}' table=\"section\" (geom) sql=", "lines", "spatialite") - assert (self.linesLayer.isValid()) - self.pointsLayer2 = QgsVectorLayer(f"dbname='{fn}' table=\"node2\" (geom) sql=", "_points2", "spatialite") - assert (self.pointsLayer2.isValid()) - QgsProject.instance().addMapLayers([self.pointsLayer, self.linesLayer, self.pointsLayer2]) + self.pointsLayer = QgsVectorLayer( + f"dbname='{fn}' table=\"node\" (geom) sql=", "points", "spatialite" + ) + assert self.pointsLayer.isValid() + self.linesLayer = QgsVectorLayer( + f"dbname='{fn}' table=\"section\" (geom) sql=", "lines", "spatialite" + ) + assert self.linesLayer.isValid() + self.pointsLayer2 = QgsVectorLayer( + f"dbname='{fn}' table=\"node2\" (geom) sql=", "_points2", "spatialite" + ) + assert self.pointsLayer2.isValid() + QgsProject.instance().addMapLayers( + [self.pointsLayer, self.linesLayer, self.pointsLayer2] + ) # save the project file fo = tempfile.NamedTemporaryFile() @@ -97,9 +116,12 @@ def test_resetSnappingIndex(self): cfg = u.config() cfg.setEnabled(True) cfg.setMode(Qgis.SnappingMode.AdvancedConfiguration) - cfg.setIndividualLayerSettings(self.pointsLayer, - QgsSnappingConfig.IndividualLayerSettings(True, - Qgis.SnappingType.Vertex, 20, Qgis.MapToolUnit.Pixels, 0.0, 0.0)) + cfg.setIndividualLayerSettings( + self.pointsLayer, + QgsSnappingConfig.IndividualLayerSettings( + True, Qgis.SnappingType.Vertex, 20, Qgis.MapToolUnit.Pixels, 0.0, 0.0 + ), + ) u.setConfig(cfg) m = u.snapToMap(QPoint(95, 100)) @@ -140,12 +162,17 @@ def test_resetSnappingIndex(self): self.pointsLayer.setDependencies([]) # test chained layer dependencies A -> B -> C - cfg.setIndividualLayerSettings(self.pointsLayer2, - QgsSnappingConfig.IndividualLayerSettings(True, - Qgis.SnappingType.Vertex, 20, Qgis.MapToolUnit.Pixels, 0.0, 0.0)) + cfg.setIndividualLayerSettings( + self.pointsLayer2, + QgsSnappingConfig.IndividualLayerSettings( + True, Qgis.SnappingType.Vertex, 20, Qgis.MapToolUnit.Pixels, 0.0, 0.0 + ), + ) u.setConfig(cfg) self.pointsLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())]) - self.pointsLayer2.setDependencies([QgsMapLayerDependency(self.pointsLayer.id())]) + self.pointsLayer2.setDependencies( + [QgsMapLayerDependency(self.pointsLayer.id())] + ) # add another line f = QgsFeature(self.linesLayer.fields()) f.setId(3) @@ -170,13 +197,21 @@ def test_circular_dependencies_with_2_layers(self): spy_lines_repaint_requested = QSignalSpy(self.linesLayer.repaintRequested) # only points fire dataChanged because we change its dependencies - self.assertTrue(self.pointsLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())])) + self.assertTrue( + self.pointsLayer.setDependencies( + [QgsMapLayerDependency(self.linesLayer.id())] + ) + ) self.assertEqual(len(spy_points_data_changed), 1) self.assertEqual(len(spy_lines_data_changed), 0) # lines fire dataChanged because we changes its dependencies # points fire dataChanged because it depends on line - self.assertTrue(self.linesLayer.setDependencies([QgsMapLayerDependency(self.pointsLayer.id())])) + self.assertTrue( + self.linesLayer.setDependencies( + [QgsMapLayerDependency(self.pointsLayer.id())] + ) + ) self.assertEqual(len(spy_points_data_changed), 2) self.assertEqual(len(spy_lines_data_changed), 1) @@ -223,7 +258,11 @@ def test_circular_dependencies_with_1_layer(self): spy_lines_repaint_requested = QSignalSpy(self.linesLayer.repaintRequested) # line fire dataChanged because we change its dependencies - self.assertTrue(self.linesLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())])) + self.assertTrue( + self.linesLayer.setDependencies( + [QgsMapLayerDependency(self.linesLayer.id())] + ) + ) self.assertEqual(len(spy_lines_data_changed), 1) f = QgsFeature(self.linesLayer.fields()) @@ -245,7 +284,9 @@ def test_circular_dependencies_with_1_layer(self): self.assertGreaterEqual(len(spy_lines_repaint_requested), 2) # line fire dataChanged on geometryChanged - self.linesLayer.changeGeometry(f.id(), QgsGeometry.fromWkt("LINESTRING(0 0, 2 2)")) + self.linesLayer.changeGeometry( + f.id(), QgsGeometry.fromWkt("LINESTRING(0 0, 2 2)") + ) self.assertEqual(len(spy_lines_data_changed), 4) # commit changes fires dataChanged because external changes could happen (provider side) @@ -267,13 +308,15 @@ def test_layerDefinitionRewriteId(self): newPointsLayer = None newLinesLayer = None for l in grp.findLayers(): - if l.layerId().startswith('points'): + if l.layerId().startswith("points"): newPointsLayer = l.layer() - elif l.layerId().startswith('lines'): + elif l.layerId().startswith("lines"): newLinesLayer = l.layer() self.assertIsNotNone(newPointsLayer) self.assertIsNotNone(newLinesLayer) - self.assertIn(newLinesLayer.id(), [dep.layerId() for dep in newPointsLayer.dependencies()]) + self.assertIn( + newLinesLayer.id(), [dep.layerId() for dep in newPointsLayer.dependencies()] + ) self.pointsLayer.setDependencies([]) @@ -281,14 +324,22 @@ def test_signalConnection(self): # remove all layers QgsProject.instance().removeAllMapLayers() # set dependencies and add back layers - self.pointsLayer = QgsVectorLayer(f"dbname='{self.fn}' table=\"node\" (geom) sql=", "points", "spatialite") + self.pointsLayer = QgsVectorLayer( + f"dbname='{self.fn}' table=\"node\" (geom) sql=", "points", "spatialite" + ) self.assertTrue(self.pointsLayer.isValid()) - self.linesLayer = QgsVectorLayer(f"dbname='{self.fn}' table=\"section\" (geom) sql=", "lines", "spatialite") + self.linesLayer = QgsVectorLayer( + f"dbname='{self.fn}' table=\"section\" (geom) sql=", "lines", "spatialite" + ) self.assertTrue(self.linesLayer.isValid()) - self.pointsLayer2 = QgsVectorLayer(f"dbname='{self.fn}' table=\"node2\" (geom) sql=", "_points2", "spatialite") + self.pointsLayer2 = QgsVectorLayer( + f"dbname='{self.fn}' table=\"node2\" (geom) sql=", "_points2", "spatialite" + ) self.assertTrue(self.pointsLayer2.isValid()) self.pointsLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())]) - self.pointsLayer2.setDependencies([QgsMapLayerDependency(self.pointsLayer.id())]) + self.pointsLayer2.setDependencies( + [QgsMapLayerDependency(self.pointsLayer.id())] + ) # this should update connections between layers QgsProject.instance().addMapLayers([self.pointsLayer]) QgsProject.instance().addMapLayers([self.linesLayer]) @@ -304,12 +355,18 @@ def test_signalConnection(self): cfg = u.config() cfg.setEnabled(True) cfg.setMode(Qgis.SnappingMode.AdvancedConfiguration) - cfg.setIndividualLayerSettings(self.pointsLayer, - QgsSnappingConfig.IndividualLayerSettings(True, - Qgis.SnappingType.Vertex, 20, Qgis.MapToolUnit.Pixels, 0.0, 0.0)) - cfg.setIndividualLayerSettings(self.pointsLayer2, - QgsSnappingConfig.IndividualLayerSettings(True, - Qgis.SnappingType.Vertex, 20, Qgis.MapToolUnit.Pixels, 0.0, 0.0)) + cfg.setIndividualLayerSettings( + self.pointsLayer, + QgsSnappingConfig.IndividualLayerSettings( + True, Qgis.SnappingType.Vertex, 20, Qgis.MapToolUnit.Pixels, 0.0, 0.0 + ), + ) + cfg.setIndividualLayerSettings( + self.pointsLayer2, + QgsSnappingConfig.IndividualLayerSettings( + True, Qgis.SnappingType.Vertex, 20, Qgis.MapToolUnit.Pixels, 0.0, 0.0 + ), + ) u.setConfig(cfg) # add another line f = QgsFeature(self.linesLayer.fields()) @@ -329,5 +386,5 @@ def test_signalConnection(self): self.pointsLayer2.setDependencies([]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_offline_editing_wfs.py b/tests/src/python/test_offline_editing_wfs.py index ed2654727f78..bbfa9431a1ed 100644 --- a/tests/src/python/test_offline_editing_wfs.py +++ b/tests/src/python/test_offline_editing_wfs.py @@ -20,9 +20,9 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '05/15/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "05/15/2016" +__copyright__ = "Copyright 2016, The QGIS Project" import os import re @@ -39,9 +39,9 @@ from utilities import unitTestDataPath, waitServer try: - QGIS_SERVER_OFFLINE_PORT = os.environ['QGIS_SERVER_OFFLINE_PORT'] + QGIS_SERVER_OFFLINE_PORT = os.environ["QGIS_SERVER_OFFLINE_PORT"] except: - QGIS_SERVER_OFFLINE_PORT = '0' # Auto + QGIS_SERVER_OFFLINE_PORT = "0" # Auto qgis_app = start_app() @@ -53,57 +53,63 @@ class TestWFST(QgisTestCase, OfflineTestBase): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestWFST, cls).setUpClass() + super().setUpClass() cls.port = QGIS_SERVER_OFFLINE_PORT # Create tmp folder cls.temp_path = tempfile.mkdtemp() - cls.testdata_path = cls.temp_path + '/' + 'wfs_transactional' + '/' - copytree(unitTestDataPath('wfs_transactional') + '/', - cls.temp_path + '/' + 'wfs_transactional') - cls.project_path = cls.temp_path + '/' + 'wfs_transactional' + '/' + \ - 'wfs_transactional.qgs' - assert os.path.exists(cls.project_path), "Project not found: %s" % \ - cls.project_path + cls.testdata_path = cls.temp_path + "/" + "wfs_transactional" + "/" + copytree( + unitTestDataPath("wfs_transactional") + "/", + cls.temp_path + "/" + "wfs_transactional", + ) + cls.project_path = ( + cls.temp_path + "/" + "wfs_transactional" + "/" + "wfs_transactional.qgs" + ) + assert os.path.exists(cls.project_path), ( + "Project not found: %s" % cls.project_path + ) # Clean env just to be sure - env_vars = ['QUERY_STRING', 'QGIS_PROJECT_FILE'] + env_vars = ["QUERY_STRING", "QGIS_PROJECT_FILE"] for ev in env_vars: try: del os.environ[ev] except KeyError: pass # Clear all test layers - cls._clearLayer(cls._getLayer('test_point')) - os.environ['QGIS_SERVER_PORT'] = str(cls.port) - cls.server_path = os.path.dirname(os.path.realpath(__file__)) + \ - '/qgis_wrapped_server.py' + cls._clearLayer(cls._getLayer("test_point")) + os.environ["QGIS_SERVER_PORT"] = str(cls.port) + cls.server_path = ( + os.path.dirname(os.path.realpath(__file__)) + "/qgis_wrapped_server.py" + ) @classmethod def tearDownClass(cls): """Run after all tests""" rmtree(cls.temp_path) - super(TestWFST, cls).tearDownClass() + super().tearDownClass() def setUp(self): """Run before each test.""" - self.server = subprocess.Popen([sys.executable, self.server_path], - env=os.environ, stdout=subprocess.PIPE) + self.server = subprocess.Popen( + [sys.executable, self.server_path], env=os.environ, stdout=subprocess.PIPE + ) line = self.server.stdout.readline() - self.port = int(re.findall(br':(\d+)', line)[0]) + self.port = int(re.findall(rb":(\d+)", line)[0]) assert self.port != 0 # Wait for the server process to start - assert waitServer(f'http://127.0.0.1:{self.port}'), "Server is not responding!" + assert waitServer(f"http://127.0.0.1:{self.port}"), "Server is not responding!" self._setUp() def tearDown(self): """Run after each test.""" # Clear test layer - self._clearLayer(self._getOnlineLayer('test_point')) + self._clearLayer(self._getOnlineLayer("test_point")) # Kill the server self.server.terminate() self.server.wait() del self.server # Delete the sqlite db - os.unlink(os.path.join(self.temp_path, 'offlineDbFile.sqlite')) + os.unlink(os.path.join(self.temp_path, "offlineDbFile.sqlite")) self._tearDown() def _getOnlineLayer(self, type_name, layer_name=None): @@ -111,20 +117,20 @@ def _getOnlineLayer(self, type_name, layer_name=None): Return a new WFS layer, overriding the WFS cache """ if layer_name is None: - layer_name = 'wfs_' + type_name + layer_name = "wfs_" + type_name parms = { - 'srsname': 'EPSG:4326', - 'typename': type_name, - 'url': 'http://127.0.0.1:{}/{}/?map={}'.format(self.port, - self.counter, - self.project_path), - 'version': 'auto', - 'table': '', + "srsname": "EPSG:4326", + "typename": type_name, + "url": "http://127.0.0.1:{}/{}/?map={}".format( + self.port, self.counter, self.project_path + ), + "version": "auto", + "table": "", # 'sql': '', } self.counter += 1 - uri = ' '.join([(f"{k}='{v}'") for k, v in list(parms.items())]) - wfs_layer = QgsVectorLayer(uri, layer_name, 'WFS') + uri = " ".join([(f"{k}='{v}'") for k, v in list(parms.items())]) + wfs_layer = QgsVectorLayer(uri, layer_name, "WFS") wfs_layer.setParent(QgsApplication.authManager()) assert wfs_layer.isValid() return wfs_layer @@ -134,12 +140,12 @@ def _getLayer(cls, layer_name): """ Layer factory (return the backend layer), provider specific """ - path = cls.testdata_path + layer_name + '.shp' + path = cls.testdata_path + layer_name + ".shp" layer = QgsVectorLayer(path, layer_name, "ogr") layer.setParent(QgsApplication.authManager()) assert layer.isValid() return layer -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_plugindependencies.py b/tests/src/python/test_plugindependencies.py index 8315d606fc55..e01e71175ddb 100644 --- a/tests/src/python/test_plugindependencies.py +++ b/tests/src/python/test_plugindependencies.py @@ -7,9 +7,9 @@ """ -__author__ = 'elpaso@itopen.it' -__date__ = '2018-09-19' -__copyright__ = 'Copyright 2018, GISCE-TI S.L.' +__author__ = "elpaso@itopen.it" +__date__ = "2018-09-19" +__copyright__ = "Copyright 2018, GISCE-TI S.L." import json import os @@ -40,20 +40,20 @@ def setUpClass(cls): # Installed plugins cls.installed_plugins = { - 'MetaSearch': '0.3.5', - 'QuickWKT': '3.1', - 'db_manager': '0.1.20', - 'firstaid': '2.1.1', - 'InaSAFE': '5.0.0', - 'ipyconsole': '1.8', - 'plugin_reloader': '0.7.4', - 'processing': '2.12.99', - 'qgis-geocoding': '2.18', - 'qgisce': '0.9', - 'redistrict': '0.1' + "MetaSearch": "0.3.5", + "QuickWKT": "3.1", + "db_manager": "0.1.20", + "firstaid": "2.1.1", + "InaSAFE": "5.0.0", + "ipyconsole": "1.8", + "plugin_reloader": "0.7.4", + "processing": "2.12.99", + "qgis-geocoding": "2.18", + "qgisce": "0.9", + "redistrict": "0.1", } - data_path = os.path.join(TESTDATA_PATH, 'plugindependencies_data.json') + data_path = os.path.join(TESTDATA_PATH, "plugindependencies_data.json") with open(data_path) as f: cls.plugin_data = json.loads(f.read()) @@ -67,126 +67,157 @@ def tearDown(self): def test_find_dependencies(self): - to_install, to_upgrade, not_found = find_dependencies('qgisce', - self.plugin_data, - plugin_deps={'InaSAFE': None}, - installed_plugins=self.installed_plugins) + to_install, to_upgrade, not_found = find_dependencies( + "qgisce", + self.plugin_data, + plugin_deps={"InaSAFE": None}, + installed_plugins=self.installed_plugins, + ) self.assertEqual(to_install, {}) self.assertEqual(to_upgrade, {}) self.assertEqual(not_found, {}) - to_install, to_upgrade, not_found = find_dependencies('qgisce', - self.plugin_data, - plugin_deps={'InaSAFE': '110.1'}, - installed_plugins=self.installed_plugins) + to_install, to_upgrade, not_found = find_dependencies( + "qgisce", + self.plugin_data, + plugin_deps={"InaSAFE": "110.1"}, + installed_plugins=self.installed_plugins, + ) self.assertEqual(to_install, {}) self.assertEqual(to_upgrade, {}) - self.assertEqual(not_found['InaSAFE']['version_installed'], '5.0.0') + self.assertEqual(not_found["InaSAFE"]["version_installed"], "5.0.0") # QuickWkt is installed, version is not specified: ignore installed_plugins = self.installed_plugins - installed_plugins['QuickWKT'] = '2.1' - to_install, to_upgrade, not_found = find_dependencies('qgisce', - self.plugin_data, - plugin_deps={'QuickMapServices': '0.19.10.1', - 'QuickWKT': None}, - installed_plugins=self.installed_plugins) - self.assertEqual(to_install['QuickMapServices']['version_required'], '0.19.10.1') - self.assertEqual(to_install['QuickMapServices']['version_available'], '0.19.10.1') - self.assertEqual(to_install['QuickMapServices']['use_stable_version'], True) + installed_plugins["QuickWKT"] = "2.1" + to_install, to_upgrade, not_found = find_dependencies( + "qgisce", + self.plugin_data, + plugin_deps={"QuickMapServices": "0.19.10.1", "QuickWKT": None}, + installed_plugins=self.installed_plugins, + ) + self.assertEqual( + to_install["QuickMapServices"]["version_required"], "0.19.10.1" + ) + self.assertEqual( + to_install["QuickMapServices"]["version_available"], "0.19.10.1" + ) + self.assertEqual(to_install["QuickMapServices"]["use_stable_version"], True) self.assertEqual(to_upgrade, {}) self.assertEqual(not_found, {}) # QuickWkt is installed, version requires upgrade and it's in the repo: upgrade - to_install, to_upgrade, not_found = find_dependencies('qgisce', - self.plugin_data, - plugin_deps={'QuickWKT': '3.1'}, - installed_plugins=installed_plugins) + to_install, to_upgrade, not_found = find_dependencies( + "qgisce", + self.plugin_data, + plugin_deps={"QuickWKT": "3.1"}, + installed_plugins=installed_plugins, + ) self.assertEqual(to_install, {}) - self.assertEqual(to_upgrade['QuickWKT']['version_required'], '3.1') - self.assertEqual(to_upgrade['QuickWKT']['version_available'], '3.1') - self.assertEqual(to_upgrade['QuickWKT']['use_stable_version'], True) + self.assertEqual(to_upgrade["QuickWKT"]["version_required"], "3.1") + self.assertEqual(to_upgrade["QuickWKT"]["version_available"], "3.1") + self.assertEqual(to_upgrade["QuickWKT"]["use_stable_version"], True) self.assertEqual(not_found, {}) # QuickWkt is installed, version requires upgrade and it's NOT in the repo: not found - to_install, to_upgrade, not_found = find_dependencies('qgisce', - self.plugin_data, - plugin_deps={'QuickWKT': '300.11234'}, - installed_plugins=installed_plugins) + to_install, to_upgrade, not_found = find_dependencies( + "qgisce", + self.plugin_data, + plugin_deps={"QuickWKT": "300.11234"}, + installed_plugins=installed_plugins, + ) self.assertEqual(to_install, {}) self.assertEqual(to_upgrade, {}) - self.assertEqual(not_found['QuickWKT']['version_required'], '300.11234') - self.assertEqual(not_found['QuickWKT']['version_installed'], '2.1') - self.assertEqual(not_found['QuickWKT']['version_available'], '3.1') + self.assertEqual(not_found["QuickWKT"]["version_required"], "300.11234") + self.assertEqual(not_found["QuickWKT"]["version_installed"], "2.1") + self.assertEqual(not_found["QuickWKT"]["version_available"], "3.1") # Installed version is > than required: ignore (no downgrade is currently possible) - installed_plugins['QuickWKT'] = '300.1' - to_install, to_upgrade, not_found = find_dependencies('qgisce', - self.plugin_data, - plugin_deps={'QuickWKT': '1.2'}, - installed_plugins=installed_plugins) + installed_plugins["QuickWKT"] = "300.1" + to_install, to_upgrade, not_found = find_dependencies( + "qgisce", + self.plugin_data, + plugin_deps={"QuickWKT": "1.2"}, + installed_plugins=installed_plugins, + ) self.assertEqual(to_install, {}) self.assertEqual(to_upgrade, {}) self.assertEqual(not_found, {}) # A plugin offers both stable and experimental versions. A dependent plugin requires the experimental one. - to_install, to_upgrade, not_found = find_dependencies('LADM-COL-Add-on-Ambiente', - self.plugin_data, - plugin_deps={'Asistente LADM-COL': '3.2.0-beta-1'}, - installed_plugins=self.installed_plugins) - self.assertEqual(to_install['Asistente LADM-COL']['version_required'], '3.2.0-beta-1') - self.assertEqual(to_install['Asistente LADM-COL']['version_available'], '3.2.0-beta-1') - self.assertEqual(to_install['Asistente LADM-COL']['use_stable_version'], False) + to_install, to_upgrade, not_found = find_dependencies( + "LADM-COL-Add-on-Ambiente", + self.plugin_data, + plugin_deps={"Asistente LADM-COL": "3.2.0-beta-1"}, + installed_plugins=self.installed_plugins, + ) + self.assertEqual( + to_install["Asistente LADM-COL"]["version_required"], "3.2.0-beta-1" + ) + self.assertEqual( + to_install["Asistente LADM-COL"]["version_available"], "3.2.0-beta-1" + ) + self.assertEqual(to_install["Asistente LADM-COL"]["use_stable_version"], False) self.assertEqual(to_upgrade, {}) self.assertEqual(not_found, {}) # A plugin offers both stable and experimental versions. A dependent plugin requires the stable one. - to_install, to_upgrade, not_found = find_dependencies('LADM-COL-Add-on-Ambiente', - self.plugin_data, - plugin_deps={'Asistente LADM-COL': '3.1.9'}, - installed_plugins=self.installed_plugins) - self.assertEqual(to_install['Asistente LADM-COL']['version_required'], '3.1.9') - self.assertEqual(to_install['Asistente LADM-COL']['version_available'], '3.1.9') - self.assertEqual(to_install['Asistente LADM-COL']['use_stable_version'], True) + to_install, to_upgrade, not_found = find_dependencies( + "LADM-COL-Add-on-Ambiente", + self.plugin_data, + plugin_deps={"Asistente LADM-COL": "3.1.9"}, + installed_plugins=self.installed_plugins, + ) + self.assertEqual(to_install["Asistente LADM-COL"]["version_required"], "3.1.9") + self.assertEqual(to_install["Asistente LADM-COL"]["version_available"], "3.1.9") + self.assertEqual(to_install["Asistente LADM-COL"]["use_stable_version"], True) self.assertEqual(to_upgrade, {}) self.assertEqual(not_found, {}) # A plugin offers both stable and experimental versions. If no version is required, choose the stable one. - to_install, to_upgrade, not_found = find_dependencies('LADM-COL-Add-on-Ambiente', - self.plugin_data, - plugin_deps={'Asistente LADM-COL': None}, - installed_plugins=self.installed_plugins) - self.assertEqual(to_install['Asistente LADM-COL']['version_required'], None) - self.assertEqual(to_install['Asistente LADM-COL']['version_available'], '3.1.9') - self.assertEqual(to_install['Asistente LADM-COL']['use_stable_version'], True) + to_install, to_upgrade, not_found = find_dependencies( + "LADM-COL-Add-on-Ambiente", + self.plugin_data, + plugin_deps={"Asistente LADM-COL": None}, + installed_plugins=self.installed_plugins, + ) + self.assertEqual(to_install["Asistente LADM-COL"]["version_required"], None) + self.assertEqual(to_install["Asistente LADM-COL"]["version_available"], "3.1.9") + self.assertEqual(to_install["Asistente LADM-COL"]["use_stable_version"], True) self.assertEqual(to_upgrade, {}) self.assertEqual(not_found, {}) # A plugin only offers experimental version. If the experimental version is required, give it to him. - to_install, to_upgrade, not_found = find_dependencies('dependent-on-unique_values_viewer', - self.plugin_data, - plugin_deps={'UniqueValuesViewer': '0.2'}, - installed_plugins=self.installed_plugins) - self.assertEqual(to_install['UniqueValuesViewer']['version_required'], '0.2') - self.assertEqual(to_install['UniqueValuesViewer']['version_available'], '0.2') - self.assertEqual(to_install['UniqueValuesViewer']['use_stable_version'], False) + to_install, to_upgrade, not_found = find_dependencies( + "dependent-on-unique_values_viewer", + self.plugin_data, + plugin_deps={"UniqueValuesViewer": "0.2"}, + installed_plugins=self.installed_plugins, + ) + self.assertEqual(to_install["UniqueValuesViewer"]["version_required"], "0.2") + self.assertEqual(to_install["UniqueValuesViewer"]["version_available"], "0.2") + self.assertEqual(to_install["UniqueValuesViewer"]["use_stable_version"], False) self.assertEqual(to_upgrade, {}) self.assertEqual(not_found, {}) # A plugin only offers experimental version. If no version is required, choose the experimental one. - to_install, to_upgrade, not_found = find_dependencies('dependent-on-unique_values_viewer', - self.plugin_data, - plugin_deps={'UniqueValuesViewer': None}, - installed_plugins=self.installed_plugins) - self.assertEqual(to_install['UniqueValuesViewer']['version_required'], None) - self.assertEqual(to_install['UniqueValuesViewer']['version_available'], '0.2') - self.assertEqual(to_install['UniqueValuesViewer']['use_stable_version'], False) + to_install, to_upgrade, not_found = find_dependencies( + "dependent-on-unique_values_viewer", + self.plugin_data, + plugin_deps={"UniqueValuesViewer": None}, + installed_plugins=self.installed_plugins, + ) + self.assertEqual(to_install["UniqueValuesViewer"]["version_required"], None) + self.assertEqual(to_install["UniqueValuesViewer"]["version_available"], "0.2") + self.assertEqual(to_install["UniqueValuesViewer"]["use_stable_version"], False) self.assertEqual(to_upgrade, {}) self.assertEqual(not_found, {}) def pluginSuite(): - return unittest.defaultTestLoader.loadTestsFromTestCase(PluginDependenciesTest, 'test') + return unittest.defaultTestLoader.loadTestsFromTestCase( + PluginDependenciesTest, "test" + ) if __name__ == "__main__": diff --git a/tests/src/python/test_processing_alg_decorator.py b/tests/src/python/test_processing_alg_decorator.py index 29cea78f94cb..8a232a5034f5 100644 --- a/tests/src/python/test_processing_alg_decorator.py +++ b/tests/src/python/test_processing_alg_decorator.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nathan Woodrow' -__date__ = '10.12.2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nathan Woodrow" +__date__ = "10.12.2018" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.processing import alg @@ -21,8 +22,12 @@ def define_new_no_inputs(newid=1): - @alg(name="noinputs", label=alg.tr("Test func"), group="unittest", - group_label=alg.tr("Test label")) + @alg( + name="noinputs", + label=alg.tr("Test func"), + group="unittest", + group_label=alg.tr("Test label"), + ) @alg.output(type=str, name="DISTANCE_OUT", label="Distance out") def testalg(instance, parameters, context, feedback, inputs): """ @@ -31,8 +36,12 @@ def testalg(instance, parameters, context, feedback, inputs): def define_new_no_outputs_but_sink_instead(newid=1): - @alg(name=ARGNAME.format(newid), label=alg.tr("Test func"), group="unittest", - group_label=alg.tr("Test label")) + @alg( + name=ARGNAME.format(newid), + label=alg.tr("Test func"), + group="unittest", + group_label=alg.tr("Test label"), + ) @alg.help(HELPSTRING.format(newid)) @alg.input(type=alg.SOURCE, name="INPUT", label="Input layer") @alg.input(type=alg.DISTANCE, name="DISTANCE", label="Distance", default=30) @@ -44,12 +53,32 @@ def testalg(instance, parameters, context, feedback, inputs): def define_new_input_help(newid=1): - @alg(name=ARGNAME.format(newid), label=alg.tr("Test func"), group="unittest", - group_label=alg.tr("Test label")) + @alg( + name=ARGNAME.format(newid), + label=alg.tr("Test func"), + group="unittest", + group_label=alg.tr("Test label"), + ) @alg.help(HELPSTRING.format(newid)) - @alg.input(type=alg.SOURCE, name="INPUT", label="Input layer", help="The input layer as source") - @alg.input(type=alg.DISTANCE, name="DISTANCE", label="Distance", default=30, help="The distance to split the input layer") - @alg.input(type=alg.SINK, name="SINK", label="Output layer", help="The output layer as sink") + @alg.input( + type=alg.SOURCE, + name="INPUT", + label="Input layer", + help="The input layer as source", + ) + @alg.input( + type=alg.DISTANCE, + name="DISTANCE", + label="Distance", + default=30, + help="The distance to split the input layer", + ) + @alg.input( + type=alg.SINK, + name="SINK", + label="Output layer", + help="The output layer as sink", + ) @alg.output(type=str, name="DISTANCE_OUT", label="Distance out") def testalg(instance, parameters, context, feedback, inputs): """ @@ -58,8 +87,12 @@ def testalg(instance, parameters, context, feedback, inputs): def define_new_doc_string(newid=1): - @alg(name=ARGNAME.format(newid), label=alg.tr("Test func"), group="unittest", - group_label=alg.tr("Test label")) + @alg( + name=ARGNAME.format(newid), + label=alg.tr("Test func"), + group="unittest", + group_label=alg.tr("Test label"), + ) @alg.input(type=alg.SOURCE, name="INPUT", label="Input layer") @alg.output(type=str, name="DISTANCE_OUT", label="Distance out") def testalg(instance, parameters, context, feedback, inputs): @@ -69,8 +102,12 @@ def testalg(instance, parameters, context, feedback, inputs): def define_new(newid=1): - @alg(name=ARGNAME.format(newid), label=alg.tr("Test func"), group="unittest", - group_label=alg.tr("Test label")) + @alg( + name=ARGNAME.format(newid), + label=alg.tr("Test func"), + group="unittest", + group_label=alg.tr("Test label"), + ) @alg.help(HELPSTRING.format(newid)) @alg.input(type=alg.SOURCE, name="INPUT", label="Input layer") @alg.input(type=alg.DISTANCE, name="DISTANCE", label="Distance", default=30) diff --git a/tests/src/python/test_processing_algs_gdal_gdalutils.py b/tests/src/python/test_processing_algs_gdal_gdalutils.py index ded8357ff8bc..c964a1133e8b 100644 --- a/tests/src/python/test_processing_algs_gdal_gdalutils.py +++ b/tests/src/python/test_processing_algs_gdal_gdalutils.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Stefanos Natsis' -__date__ = '03/07/2024' -__copyright__ = 'Copyright 2024, The QGIS Project' + +__author__ = "Stefanos Natsis" +__date__ = "03/07/2024" +__copyright__ = "Copyright 2024, The QGIS Project" import os @@ -16,14 +17,16 @@ import unittest from qgis.testing import start_app, QgisTestCase -from qgis.core import QgsApplication, QgsRasterLayer, QgsDataSourceUri, QgsAuthMethodConfig -from processing.algs.gdal.GdalUtils import ( - GdalUtils, - GdalConnectionDetails +from qgis.core import ( + QgsApplication, + QgsRasterLayer, + QgsDataSourceUri, + QgsAuthMethodConfig, ) +from processing.algs.gdal.GdalUtils import GdalUtils, GdalConnectionDetails QGIS_AUTH_DB_DIR_PATH = tempfile.mkdtemp() -os.environ['QGIS_AUTH_DB_DIR_PATH'] = QGIS_AUTH_DB_DIR_PATH +os.environ["QGIS_AUTH_DB_DIR_PATH"] = QGIS_AUTH_DB_DIR_PATH start_app() @@ -34,7 +37,7 @@ class TestProcessingAlgsGdalGdalUtils(QgisTestCase): def tearDownClass(cls): """Run after all tests""" rmtree(QGIS_AUTH_DB_DIR_PATH) - del os.environ['QGIS_AUTH_DB_DIR_PATH'] + del os.environ["QGIS_AUTH_DB_DIR_PATH"] super().tearDownClass() def test_gdal_connection_details_from_layer_postgresraster(self): @@ -45,14 +48,16 @@ def test_gdal_connection_details_from_layer_postgresraster(self): rl = QgsRasterLayer( "dbname='mydb' host=localhost port=5432 user='asdf' password='42'" " sslmode=disable table=some_table schema=some_schema column=rast sql=pk = 2", - 'pg_layer', 'postgresraster') + "pg_layer", + "postgresraster", + ) - self.assertEqual(rl.providerType(), 'postgresraster') + self.assertEqual(rl.providerType(), "postgresraster") connection_details = GdalUtils.gdal_connection_details_from_layer(rl) s = connection_details.connection_string - self.assertTrue(s.lower().startswith('pg:')) + self.assertTrue(s.lower().startswith("pg:")) self.assertTrue("schema='some_schema'" in s) self.assertTrue("password='42'" in s) self.assertTrue("column='rast'" in s) @@ -65,25 +70,27 @@ def test_gdal_connection_details_from_layer_postgresraster(self): # - column is parsed # - where is skipped authm = QgsApplication.authManager() - self.assertTrue(authm.setMasterPassword('masterpassword', True)) + self.assertTrue(authm.setMasterPassword("masterpassword", True)) config = QgsAuthMethodConfig() - config.setName('Basic') - config.setMethod('Basic') - config.setConfig('username', 'asdf') - config.setConfig('password', '42') + config.setName("Basic") + config.setMethod("Basic") + config.setConfig("username", "asdf") + config.setConfig("password", "42") self.assertTrue(authm.storeAuthenticationConfig(config, True)) rl = QgsRasterLayer( f"dbname='mydb' host=localhost port=5432 authcfg={config.id()}" - f" sslmode=disable table=\"some_schema\".\"some_table\" (rast)", - 'pg_layer', 'postgresraster') + f' sslmode=disable table="some_schema"."some_table" (rast)', + "pg_layer", + "postgresraster", + ) - self.assertEqual(rl.providerType(), 'postgresraster') + self.assertEqual(rl.providerType(), "postgresraster") connection_details = GdalUtils.gdal_connection_details_from_layer(rl) s = connection_details.connection_string - self.assertTrue(s.lower().startswith('pg:')) + self.assertTrue(s.lower().startswith("pg:")) self.assertTrue("schema='some_schema'" in s) self.assertTrue("user='asdf'" in s) self.assertTrue("password='42'" in s) @@ -92,5 +99,5 @@ def test_gdal_connection_details_from_layer_postgresraster(self): self.assertFalse("where=" in s) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_processing_importintopostgis.py b/tests/src/python/test_processing_importintopostgis.py index 8f387c39aeb1..71f683675bd3 100644 --- a/tests/src/python/test_processing_importintopostgis.py +++ b/tests/src/python/test_processing_importintopostgis.py @@ -5,9 +5,10 @@ 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 2019, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "2018-09" +__copyright__ = "Copyright 2019, The QGIS Project" from processing.core.Processing import Processing from processing.gui.AlgorithmExecutor import execute @@ -43,8 +44,7 @@ def setUpClass(cls): """Run before all tests""" super().setUpClass() QCoreApplication.setOrganizationName("QGIS_Test") - QCoreApplication.setOrganizationDomain( - "QGIS_TestPyQgsExportToPostgis.com") + QCoreApplication.setOrganizationDomain("QGIS_TestPyQgsExportToPostgis.com") QCoreApplication.setApplicationName("QGIS_TestPyQgsExportToPostgis") QgsSettings().clear() Processing.initialize() @@ -53,9 +53,9 @@ def setUpClass(cls): # Create DB connection in the settings settings = QgsSettings() - settings.beginGroup('/PostgreSQL/connections/qgis_test') - settings.setValue('service', 'qgis_test') - settings.setValue('database', 'qgis_test') + settings.beginGroup("/PostgreSQL/connections/qgis_test") + settings.setValue("service", "qgis_test") + settings.setValue("database", "qgis_test") def test_import(self): """Test algorithm with CamelCase'singlequote'Schema""" @@ -63,21 +63,21 @@ def test_import(self): alg = self.registry.createAlgorithmById("qgis:importintopostgis") self.assertIsNotNone(alg) - table_name = 'out_TestPyQgsExportToPostgis' + table_name = "out_TestPyQgsExportToPostgis" parameters = { - 'CREATEINDEX': True, - 'DATABASE': 'qgis_test', - 'DROP_STRING_LENGTH': False, - 'ENCODING': 'UTF-8', - 'FORCE_SINGLEPART': False, - 'GEOMETRY_COLUMN': 'geom', - 'INPUT': unitTestDataPath() + '/points.shp', - 'LOWERCASE_NAMES': True, - 'OVERWRITE': True, - 'PRIMARY_KEY': None, - 'SCHEMA': "CamelCase'singlequote'Schema", - 'TABLENAME': table_name + "CREATEINDEX": True, + "DATABASE": "qgis_test", + "DROP_STRING_LENGTH": False, + "ENCODING": "UTF-8", + "FORCE_SINGLEPART": False, + "GEOMETRY_COLUMN": "geom", + "INPUT": unitTestDataPath() + "/points.shp", + "LOWERCASE_NAMES": True, + "OVERWRITE": True, + "PRIMARY_KEY": None, + "SCHEMA": "CamelCase'singlequote'Schema", + "TABLENAME": table_name, } feedback = ConsoleFeedBack() @@ -88,9 +88,13 @@ def test_import(self): self.assertEqual(feedback._errors, []) # Check that data have been imported correctly - exported = QgsVectorLayer(unitTestDataPath() + '/points.shp', 'exported') + exported = QgsVectorLayer(unitTestDataPath() + "/points.shp", "exported") self.assertTrue(exported.isValid()) - imported = QgsVectorLayer(f"service='qgis_test' table=\"CamelCase'singlequote'Schema\".\"{table_name}\" (geom)", 'imported', 'postgres') + imported = QgsVectorLayer( + f"service='qgis_test' table=\"CamelCase'singlequote'Schema\".\"{table_name}\" (geom)", + "imported", + "postgres", + ) self.assertTrue(imported.isValid()) imported_fields = [f.name() for f in imported.fields()] for f in exported.fields(): @@ -104,5 +108,5 @@ def test_import(self): self.assertEqual(exported_f.geometry().asWkt(), imported_f.geometry().asWkt()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_processing_packagelayers.py b/tests/src/python/test_processing_packagelayers.py index 589ec8ffb329..cf144b53198c 100644 --- a/tests/src/python/test_processing_packagelayers.py +++ b/tests/src/python/test_processing_packagelayers.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '2022-07' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "2022-07" +__copyright__ = "Copyright 2022, The QGIS Project" import os @@ -55,16 +56,17 @@ def setUpClass(cls): """Run before all tests""" super().setUpClass() QCoreApplication.setOrganizationName("QGIS_Test") - QCoreApplication.setOrganizationDomain( - "QGIS_TestPyQgsPackageLayers.com") + QCoreApplication.setOrganizationDomain("QGIS_TestPyQgsPackageLayers.com") QCoreApplication.setApplicationName("QGIS_TestPyQgsPackageLayers") QgsSettings().clear() Processing.initialize() QgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms()) cls.registry = QgsApplication.instance().processingRegistry() cls.tmp_dir = QTemporaryDir() - cls.temp_path = os.path.join(cls.tmp_dir.path(), 'package_layers.gpkg') - cls.temp_export_path = os.path.join(cls.tmp_dir.path(), 'package_layers_export.gpkg') + cls.temp_path = os.path.join(cls.tmp_dir.path(), "package_layers.gpkg") + cls.temp_export_path = os.path.join( + cls.tmp_dir.path(), "package_layers_export.gpkg" + ) # Create test DB @@ -83,83 +85,83 @@ def setUpClass(cls): City 4 """ - ds = ogr.GetDriverByName('GPKG').CreateDataSource(cls.temp_path) - lyr = ds.CreateLayer('region', geom_type=ogr.wkbNone) - lyr.CreateField(ogr.FieldDefn('name', ogr.OFTString)) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(cls.temp_path) + lyr = ds.CreateLayer("region", geom_type=ogr.wkbNone) + lyr.CreateField(ogr.FieldDefn("name", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f['name'] = 'region one' + f["name"] = "region one" lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f['name'] = 'region two' + f["name"] = "region two" lyr.CreateFeature(f) - lyr = ds.CreateLayer('province', geom_type=ogr.wkbNone) - lyr.CreateField(ogr.FieldDefn('name', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('region', ogr.OFTInteger)) + lyr = ds.CreateLayer("province", geom_type=ogr.wkbNone) + lyr.CreateField(ogr.FieldDefn("name", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("region", ogr.OFTInteger)) f = ogr.Feature(lyr.GetLayerDefn()) - f['name'] = 'province one' - f['region'] = 1 + f["name"] = "province one" + f["region"] = 1 lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f['name'] = 'province two' - f['region'] = 1 + f["name"] = "province two" + f["region"] = 1 lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f['name'] = 'province three' - f['region'] = 2 + f["name"] = "province three" + f["region"] = 2 lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f['name'] = 'province four' - f['region'] = 2 + f["name"] = "province four" + f["region"] = 2 lyr.CreateFeature(f) - lyr = ds.CreateLayer('city', geom_type=ogr.wkbNone) - lyr.CreateField(ogr.FieldDefn('name', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('province', ogr.OFTInteger)) + lyr = ds.CreateLayer("city", geom_type=ogr.wkbNone) + lyr.CreateField(ogr.FieldDefn("name", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("province", ogr.OFTInteger)) f = ogr.Feature(lyr.GetLayerDefn()) - f['name'] = 'city one' - f['province'] = 1 + f["name"] = "city one" + f["province"] = 1 lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f['name'] = 'city two' - f['province'] = 1 + f["name"] = "city two" + f["province"] = 1 lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f['name'] = 'city three' - f['province'] = 2 + f["name"] = "city three" + f["province"] = 2 lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f['name'] = 'city four' - f['province'] = 4 + f["name"] = "city four" + f["province"] = 4 lyr.CreateFeature(f) f = None ds = None - region = QgsVectorLayer(cls.temp_path + '|layername=region', 'region') - province = QgsVectorLayer(cls.temp_path + '|layername=province', 'province') - city = QgsVectorLayer(cls.temp_path + '|layername=city', 'city') + region = QgsVectorLayer(cls.temp_path + "|layername=region", "region") + province = QgsVectorLayer(cls.temp_path + "|layername=province", "province") + city = QgsVectorLayer(cls.temp_path + "|layername=city", "city") QgsProject.instance().addMapLayers([region, province, city]) relMgr = QgsProject.instance().relationManager() rel = QgsRelation() - rel.setId('rel1') - rel.setName('province -> region') + rel.setId("rel1") + rel.setName("province -> region") rel.setReferencingLayer(province.id()) rel.setReferencedLayer(region.id()) - rel.addFieldPair('region', 'fid') + rel.addFieldPair("region", "fid") assert rel.isValid() relMgr.addRelation(rel) rel = QgsRelation() - rel.setId('rel2') - rel.setName('city -> province') + rel.setId("rel2") + rel.setName("city -> province") rel.setReferencingLayer(city.id()) rel.setReferencedLayer(province.id()) - rel.addFieldPair('province', 'fid') + rel.addFieldPair("province", "fid") assert rel.isValid() relMgr.addRelation(rel) @@ -185,35 +187,37 @@ def _test(parameters): self.assertEqual(feedback._errors, []) # Check export - l = QgsVectorLayer(self.temp_export_path + '|layername=province', 'province') + l = QgsVectorLayer( + self.temp_export_path + "|layername=province", "province" + ) self.assertTrue(l.isValid()) self.assertEqual(l.featureCount(), 4) - l = QgsVectorLayer(self.temp_export_path + '|layername=region', 'region') + l = QgsVectorLayer(self.temp_export_path + "|layername=region", "region") self.assertTrue(l.isValid()) self.assertEqual(l.featureCount(), 2) - l = QgsVectorLayer(self.temp_export_path + '|layername=city', 'city') + l = QgsVectorLayer(self.temp_export_path + "|layername=city", "city") self.assertTrue(l.isValid()) self.assertEqual(l.featureCount(), 4) parameters = { - 'EXPORT_RELATED_LAYERS': True, - 'LAYERS': [QgsProject.instance().mapLayersByName('province')[0]], - 'OUTPUT': self.temp_export_path, - 'OVERWRITE': True, - 'SELECTED_FEATURES_ONLY': False + "EXPORT_RELATED_LAYERS": True, + "LAYERS": [QgsProject.instance().mapLayersByName("province")[0]], + "OUTPUT": self.temp_export_path, + "OVERWRITE": True, + "SELECTED_FEATURES_ONLY": False, } # Test province _test(parameters) # Test region - parameters['LAYERS'] = [QgsProject.instance().mapLayersByName('region')[0]] + parameters["LAYERS"] = [QgsProject.instance().mapLayersByName("region")[0]] _test(parameters) # Test city - parameters['LAYERS'] = [QgsProject.instance().mapLayersByName('city')[0]] + parameters["LAYERS"] = [QgsProject.instance().mapLayersByName("city")[0]] _test(parameters) def test_selected_features_export(self): @@ -234,60 +238,62 @@ def _test(parameters, expected_ids): # Check export for layer_name in list(expected_ids.keys()): - l = QgsVectorLayer(self.temp_export_path + f'|layername={layer_name}', layer_name) + l = QgsVectorLayer( + self.temp_export_path + f"|layername={layer_name}", layer_name + ) self.assertTrue(l.isValid()) ids = {l.id() for l in l.getFeatures()} self.assertEqual(ids, expected_ids[layer_name], layer_name + str(ids)) - region = QgsProject.instance().mapLayersByName('region')[0] - province = QgsProject.instance().mapLayersByName('province')[0] - city = QgsProject.instance().mapLayersByName('city')[0] + region = QgsProject.instance().mapLayersByName("region")[0] + province = QgsProject.instance().mapLayersByName("province")[0] + city = QgsProject.instance().mapLayersByName("city")[0] parameters = { - 'EXPORT_RELATED_LAYERS': True, - 'LAYERS': [province], - 'OUTPUT': self.temp_export_path, - 'OVERWRITE': True, - 'SELECTED_FEATURES_ONLY': True + "EXPORT_RELATED_LAYERS": True, + "LAYERS": [province], + "OUTPUT": self.temp_export_path, + "OVERWRITE": True, + "SELECTED_FEATURES_ONLY": True, } # Test province province.selectByIds([1]) - _test(parameters, {'region': {1}, 'province': {1}, 'city': {1, 2}}) + _test(parameters, {"region": {1}, "province": {1}, "city": {1, 2}}) province.selectByIds([]) # Test region - parameters['LAYERS'] = [region] + parameters["LAYERS"] = [region] region.selectByIds([1]) - _test(parameters, {'region': {1}, 'province': {1, 2}, 'city': {1, 2, 3}}) + _test(parameters, {"region": {1}, "province": {1, 2}, "city": {1, 2, 3}}) region.selectByIds([]) # Test city - parameters['LAYERS'] = [city] + parameters["LAYERS"] = [city] city.selectByIds([3]) - _test(parameters, {'region': {1}, 'province': {2}, 'city': {3}}) + _test(parameters, {"region": {1}, "province": {2}, "city": {3}}) city.selectByIds([]) # Test multiple selection - parameters['LAYERS'] = [city, province] + parameters["LAYERS"] = [city, province] city.selectByIds([3]) province.selectByIds([3]) - _test(parameters, {'region': {1, 2}, 'province': {2, 3}, 'city': {3}}) + _test(parameters, {"region": {1, 2}, "province": {2, 3}, "city": {3}}) city.selectByIds([]) province.selectByIds([]) # Test referencing with selection - parameters['LAYERS'] = [region] + parameters["LAYERS"] = [region] region.selectByIds([2]) - _test(parameters, {'region': {2}, 'province': {3, 4}, 'city': {4}}) + _test(parameters, {"region": {2}, "province": {3, 4}, "city": {4}}) region.selectByIds([]) # Test referencing with selection, empty city expected not to be exported - parameters['LAYERS'] = [province] + parameters["LAYERS"] = [province] province.selectByIds([3]) - _test(parameters, {'region': {2}, 'province': {3}}) + _test(parameters, {"region": {2}, "province": {3}}) province.selectByIds([]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_project_storage_base.py b/tests/src/python/test_project_storage_base.py index 18d68b65acf1..e20c7e71d0b2 100644 --- a/tests/src/python/test_project_storage_base.py +++ b/tests/src/python/test_project_storage_base.py @@ -7,9 +7,9 @@ """ -__author__ = 'Julien Cabieces' -__date__ = '2022-04-19' -__copyright__ = 'Copyright 2022, The QGIS Project' +__author__ = "Julien Cabieces" +__date__ = "2022-04-19" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.PyQt.QtCore import QDateTime @@ -31,18 +31,20 @@ def encode_uri(self, ds_uri, schema_name, project_name=None): def testSaveLoadProject(self): schema_uri = self.encode_uri(self.ds_uri, self.schema) - project_uri = self.encode_uri(self.ds_uri, self.schema, 'abc') + project_uri = self.encode_uri(self.ds_uri, self.schema, "abc") self.dropProjectsTable() # make sure we have a clean start prj = QgsProject() uri = self.vl.source() - vl1 = QgsVectorLayer(uri, 'test', self.provider) + vl1 = QgsVectorLayer(uri, "test", self.provider) self.assertEqual(vl1.isValid(), True) prj.addMapLayer(vl1) - prj_storage = QgsApplication.projectStorageRegistry().projectStorageFromType(self.project_storage_type) + prj_storage = QgsApplication.projectStorageRegistry().projectStorageFromType( + self.project_storage_type + ) self.assertTrue(prj_storage) lst0 = prj_storage.listProjects(schema_uri) @@ -67,8 +69,12 @@ def testSaveLoadProject(self): self.assertEqual(len(prj2.mapLayers()), 1) self.assertEqual(prj2.baseName(), "abc") - self.assertEqual(prj2.absoluteFilePath(), "") # path not supported for project storages - self.assertLess(abs(prj2.lastModified().secsTo(QDateTime.currentDateTime())), 10) + self.assertEqual( + prj2.absoluteFilePath(), "" + ) # path not supported for project storages + self.assertLess( + abs(prj2.lastModified().secsTo(QDateTime.currentDateTime())), 10 + ) lastModified = prj2.lastModified() # try to see project's metadata @@ -99,7 +105,9 @@ def testSaveLoadProject(self): self.assertEqual(list(prj4.mapLayers().values())[0].name(), "testNew") self.assertEqual(prj4.baseName(), "abc") - self.assertEqual(prj4.absoluteFilePath(), "") # path not supported for project storages + self.assertEqual( + prj4.absoluteFilePath(), "" + ) # path not supported for project storages self.assertGreater(prj4.lastModified(), lastModified) # try to remove the project diff --git a/tests/src/python/test_project_storage_oracle.py b/tests/src/python/test_project_storage_oracle.py index ed79f8a5b9fc..72438044f56a 100644 --- a/tests/src/python/test_project_storage_oracle.py +++ b/tests/src/python/test_project_storage_oracle.py @@ -7,9 +7,9 @@ """ -__author__ = 'Julien Cabieces' -__date__ = '2022-04-19' -__copyright__ = 'Copyright 2022, The QGIS Project' +__author__ = "Julien Cabieces" +__date__ = "2022-04-19" +__copyright__ = "Copyright 2022, The QGIS Project" import os @@ -34,28 +34,34 @@ class TestPyQgsProjectStorageOracle(QgisTestCase, TestPyQgsProjectStorageBase): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsProjectStorageOracle, cls).setUpClass() + super().setUpClass() - cls.dbconn = "host=localhost dbname=XEPDB1 port=1521 user='QGIS' password='qgis'" - if 'QGIS_ORACLETEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_ORACLETEST_DB'] + cls.dbconn = ( + "host=localhost dbname=XEPDB1 port=1521 user='QGIS' password='qgis'" + ) + if "QGIS_ORACLETEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_ORACLETEST_DB"] cls.ds_uri = QgsDataSourceUri(cls.dbconn) # Create test layers cls.vl = QgsVectorLayer( - cls.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="QGIS"."SOME_DATA" (GEOM) sql=', 'test', 'oracle') + cls.dbconn + + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="QGIS"."SOME_DATA" (GEOM) sql=', + "test", + "oracle", + ) assert cls.vl.isValid() - cls.con = QSqlDatabase.addDatabase('QOCISPATIAL', "oracletest") - cls.con.setDatabaseName('localhost/XEPDB1') - if 'QGIS_ORACLETEST_DBNAME' in os.environ: - cls.con.setDatabaseName(os.environ['QGIS_ORACLETEST_DBNAME']) - cls.con.setUserName('QGIS') - cls.con.setPassword('qgis') + cls.con = QSqlDatabase.addDatabase("QOCISPATIAL", "oracletest") + cls.con.setDatabaseName("localhost/XEPDB1") + if "QGIS_ORACLETEST_DBNAME" in os.environ: + cls.con.setDatabaseName(os.environ["QGIS_ORACLETEST_DBNAME"]) + cls.con.setUserName("QGIS") + cls.con.setPassword("qgis") - cls.schema = 'QGIS' - cls.provider = 'oracle' - cls.project_storage_type = 'oracle' + cls.schema = "QGIS" + cls.provider = "oracle" + cls.project_storage_type = "oracle" assert cls.con.open() @@ -64,7 +70,7 @@ def execSQLCommand(self, sql, ignore_errors=False): query = QSqlQuery(self.con) res = query.exec(sql) if not ignore_errors: - self.assertTrue(res, sql + ': ' + query.lastError().text()) + self.assertTrue(res, sql + ": " + query.lastError().text()) query.finish() def dropProjectsTable(self): @@ -76,19 +82,21 @@ def encode_uri(self, ds_uri, schema_name, project_name=None): u.setScheme("oracle") u.setHost(ds_uri.host()) - if ds_uri.port() != '': + if ds_uri.port() != "": u.setPort(int(ds_uri.port())) - if ds_uri.username() != '': + if ds_uri.username() != "": u.setUserName(ds_uri.username()) - if ds_uri.password() != '': + if ds_uri.password() != "": u.setPassword(ds_uri.password()) - if ds_uri.service() != '': + if ds_uri.service() != "": urlQuery.addQueryItem("service", ds_uri.service()) - if ds_uri.authConfigId() != '': + if ds_uri.authConfigId() != "": urlQuery.addQueryItem("authcfg", ds_uri.authConfigId()) if ds_uri.sslMode() != QgsDataSourceUri.SslMode.SslPrefer: - urlQuery.addQueryItem("sslmode", QgsDataSourceUri.encodeSslMode(ds_uri.sslMode())) + urlQuery.addQueryItem( + "sslmode", QgsDataSourceUri.encodeSslMode(ds_uri.sslMode()) + ) urlQuery.addQueryItem("dbname", ds_uri.database()) @@ -97,8 +105,8 @@ def encode_uri(self, ds_uri, schema_name, project_name=None): urlQuery.addQueryItem("project", project_name) u.setQuery(urlQuery) - return str(u.toEncoded(), 'utf-8') + return str(u.toEncoded(), "utf-8") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_project_storage_postgres.py b/tests/src/python/test_project_storage_postgres.py index 5c33c6bf2d7c..907f7dbbd1d7 100644 --- a/tests/src/python/test_project_storage_postgres.py +++ b/tests/src/python/test_project_storage_postgres.py @@ -10,9 +10,9 @@ """ -__author__ = 'Martin Dobias' -__date__ = '2018-03-29' -__copyright__ = 'Copyright 2018, The QGIS Project' +__author__ = "Martin Dobias" +__date__ = "2018-03-29" +__copyright__ = "Copyright 2018, The QGIS Project" import os @@ -38,21 +38,26 @@ class TestPyQgsProjectStoragePostgres(QgisTestCase, TestPyQgsProjectStorageBase) def setUpClass(cls): """Run before all tests""" - super(TestPyQgsProjectStoragePostgres, cls).setUpClass() + super().setUpClass() - cls.dbconn = 'service=qgis_test' - if 'QGIS_PGTEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_PGTEST_DB'] + cls.dbconn = "service=qgis_test" + if "QGIS_PGTEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_PGTEST_DB"] cls.ds_uri = QgsDataSourceUri(cls.dbconn) # Create test layers - cls.vl = QgsVectorLayer(cls.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=', 'test', 'postgres') + cls.vl = QgsVectorLayer( + cls.dbconn + + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=', + "test", + "postgres", + ) assert cls.vl.isValid() cls.con = psycopg2.connect(cls.dbconn) - cls.schema = 'qgis_test' - cls.provider = 'postgres' - cls.project_storage_type = 'postgresql' + cls.schema = "qgis_test" + cls.provider = "postgres" + cls.project_storage_type = "postgresql" def execSQLCommand(self, sql): self.assertTrue(self.con) @@ -71,19 +76,21 @@ def encode_uri(self, ds_uri, schema_name, project_name=None): u.setScheme("postgresql") u.setHost(ds_uri.host()) - if ds_uri.port() != '': + if ds_uri.port() != "": u.setPort(int(ds_uri.port())) - if ds_uri.username() != '': + if ds_uri.username() != "": u.setUserName(ds_uri.username()) - if ds_uri.password() != '': + if ds_uri.password() != "": u.setPassword(ds_uri.password()) - if ds_uri.service() != '': + if ds_uri.service() != "": urlQuery.addQueryItem("service", ds_uri.service()) - if ds_uri.authConfigId() != '': + if ds_uri.authConfigId() != "": urlQuery.addQueryItem("authcfg", ds_uri.authConfigId()) if ds_uri.sslMode() != QgsDataSourceUri.SslMode.SslPrefer: - urlQuery.addQueryItem("sslmode", QgsDataSourceUri.encodeSslMode(ds_uri.sslMode())) + urlQuery.addQueryItem( + "sslmode", QgsDataSourceUri.encodeSslMode(ds_uri.sslMode()) + ) urlQuery.addQueryItem("dbname", ds_uri.database()) @@ -92,8 +99,8 @@ def encode_uri(self, ds_uri, schema_name, project_name=None): urlQuery.addQueryItem("project", project_name) u.setQuery(urlQuery) - return str(u.toEncoded(), 'utf-8') + return str(u.toEncoded(), "utf-8") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_provider_afs.py b/tests/src/python/test_provider_afs.py index bdd582704538..e4d087c5c599 100644 --- a/tests/src/python/test_provider_afs.py +++ b/tests/src/python/test_provider_afs.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2018-02-16' -__copyright__ = 'Copyright 2018, Nyall Dawson' + +__author__ = "Nyall Dawson" +__date__ = "2018-02-16" +__copyright__ = "Copyright 2018, Nyall Dawson" import hashlib import tempfile @@ -47,7 +48,7 @@ QgsFillSymbol, QgsSymbolLayer, QgsColorRampTransformer, - QgsGradientColorRamp + QgsGradientColorRamp, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -56,18 +57,22 @@ def sanitize(endpoint, x): - if x.startswith('/query'): - x = x[len('/query'):] - endpoint = endpoint + '_query' + if x.startswith("/query"): + x = x[len("/query") :] + endpoint = endpoint + "_query" if len(endpoint + x) > 150: ret = endpoint + hashlib.md5(x.encode()).hexdigest() # print('Before: ' + endpoint + x) # print('After: ' + ret) return ret - return endpoint + x.replace('?', '_').replace('&', '_').replace('<', '_').replace('>', '_').replace('"', - '_').replace( - "'", '_').replace(' ', '_').replace(':', '_').replace('/', '_').replace('\n', '_') + return endpoint + x.replace("?", "_").replace("&", "_").replace("<", "_").replace( + ">", "_" + ).replace('"', "_").replace("'", "_").replace(" ", "_").replace(":", "_").replace( + "/", "_" + ).replace( + "\n", "_" + ) class MessageLogger(QObject): @@ -86,7 +91,7 @@ def __exit__(self, type, value, traceback): def logMessage(self, msg, tag, level): if tag == self.tag or not self.tag: - self.log.append(msg.encode('UTF-8')) + self.log.append(msg.encode("UTF-8")) def messages(self): return self.log @@ -103,7 +108,7 @@ def treat_time_as_string(self): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsAFSProvider, cls).setUpClass() + super().setUpClass() QCoreApplication.setOrganizationName("QGIS_Test") QCoreApplication.setOrganizationDomain("TestPyQgsAFSProvider.com") @@ -113,10 +118,11 @@ def setUpClass(cls): # On Windows we must make sure that any backslash in the path is # replaced by a forward slash so that QUrl can process it - cls.basetestpath = tempfile.mkdtemp().replace('\\', '/') - endpoint = cls.basetestpath + '/fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + cls.basetestpath = tempfile.mkdtemp().replace("\\", "/") + endpoint = cls.basetestpath + "/fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer.\n","geometryType":"esriGeometryPoint","copyrightText":"","parentLayer":{"id":0,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -138,10 +144,14 @@ def setUpClass(cls): "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", -"ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" +"ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ @@ -152,10 +162,18 @@ def setUpClass(cls): 4 ] } -""") - - with open(sanitize(endpoint, '/query?f=json_where="cnt" > 100 and "cnt" < 410&returnIdsOnly=true'), 'wb') as f: - f.write(b""" +""" + ) + + with open( + sanitize( + endpoint, + '/query?f=json_where="cnt" > 100 and "cnt" < 410&returnIdsOnly=true', + ), + "wb", + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ @@ -164,10 +182,18 @@ def setUpClass(cls): 4 ] } - """) - - with open(sanitize(endpoint, '/query?f=json_where="cnt" > 100 and "cnt" < 400&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + """ + ) + + with open( + sanitize( + endpoint, + '/query?f=json_where="cnt" > 100 and "cnt" < 400&returnIdsOnly=true', + ), + "wb", + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ @@ -175,41 +201,70 @@ def setUpClass(cls): 2 ] } - """) - - with open(sanitize(endpoint, '/query?f=json_where="name"=\'Apple\'&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + """ + ) + + with open( + sanitize( + endpoint, "/query?f=json_where=\"name\"='Apple'&returnIdsOnly=true" + ), + "wb", + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ 2 ] } - """) - - with open(sanitize(endpoint, '/query?f=json_where="name"=\'AppleBearOrangePear\'&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + """ + ) + + with open( + sanitize( + endpoint, + "/query?f=json_where=\"name\"='AppleBearOrangePear'&returnIdsOnly=true", + ), + "wb", + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ ] } - """) - - with open(sanitize(endpoint, '/query?f=json&where="cnt" > 100 and "cnt" < 410&returnIdsOnly=true&geometry=-70.000000,70.000000,-60.000000,75.000000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects'), - 'wb') as f: - f.write(b""" + """ + ) + + with open( + sanitize( + endpoint, + '/query?f=json&where="cnt" > 100 and "cnt" < 410&returnIdsOnly=true&geometry=-70.000000,70.000000,-60.000000,75.000000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects', + ), + "wb", + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ 2 ] } - """) - - with open(sanitize(endpoint, '/query?f=json&where="cnt" > 100 and "cnt" < 410&returnIdsOnly=true&geometry=-71.000000,65.000000,-60.000000,80.000000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects'), - 'wb') as f: - f.write(b""" + """ + ) + + with open( + sanitize( + endpoint, + '/query?f=json&where="cnt" > 100 and "cnt" < 410&returnIdsOnly=true&geometry=-71.000000,65.000000,-60.000000,80.000000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects', + ), + "wb", + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ @@ -217,17 +272,28 @@ def setUpClass(cls): 4 ] } - """) + """ + ) # Create test layer - cls.vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + cls.vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) assert cls.vl.isValid() cls.source = cls.vl.dataProvider() - with open(sanitize(endpoint, - '/query?f=json&objectIds=5,3,1,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'), - 'wb') as f: - f.write((""" + with open( + sanitize( + endpoint, + "/query?f=json&objectIds=5,3,1,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false", + ), + "wb", + ) as f: + f.write( + ( + """ { "displayFieldName": "name", "fieldAliases": { @@ -257,8 +323,18 @@ def setUpClass(cls): "name": null, "name2":"NuLl", "num_char":"5", - "dt": """ + str(QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)).toMSecsSinceEpoch()) + """, - "date": """ + str(QDateTime(QDate(2020, 5, 2), QTime(0, 0, 0)).toMSecsSinceEpoch()) + """, + "dt": """ + + str( + QDateTime( + QDate(2020, 5, 4), QTime(12, 13, 14) + ).toMSecsSinceEpoch() + ) + + """, + "date": """ + + str( + QDateTime(QDate(2020, 5, 2), QTime(0, 0, 0)).toMSecsSinceEpoch() + ) + + """, "time": "12:13:01" }, "geometry": { @@ -288,8 +364,18 @@ def setUpClass(cls): "name": "Orange", "name2":"oranGe", "num_char":"1", - "dt": """ + str(QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)).toMSecsSinceEpoch()) + """, - "date": """ + str(QDateTime(QDate(2020, 5, 3), QTime(0, 0, 0)).toMSecsSinceEpoch()) + """, + "dt": """ + + str( + QDateTime( + QDate(2020, 5, 3), QTime(12, 13, 14) + ).toMSecsSinceEpoch() + ) + + """, + "date": """ + + str( + QDateTime(QDate(2020, 5, 3), QTime(0, 0, 0)).toMSecsSinceEpoch() + ) + + """, "time": "12:13:14" }, "geometry": { @@ -305,8 +391,18 @@ def setUpClass(cls): "name": "Apple", "name2":"Apple", "num_char":"2", - "dt": """ + str(QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)).toMSecsSinceEpoch()) + """, - "date": """ + str(QDateTime(QDate(2020, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch()) + """, + "dt": """ + + str( + QDateTime( + QDate(2020, 5, 4), QTime(12, 14, 14) + ).toMSecsSinceEpoch() + ) + + """, + "date": """ + + str( + QDateTime(QDate(2020, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch() + ) + + """, "time": "12:14:14" }, "geometry": { @@ -322,8 +418,18 @@ def setUpClass(cls): "name": "Honey", "name2":"Honey", "num_char":"4", - "dt": """ + str(QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)).toMSecsSinceEpoch()) + """, - "date": """ + str(QDateTime(QDate(2021, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch()) + """, + "dt": """ + + str( + QDateTime( + QDate(2021, 5, 4), QTime(13, 13, 14) + ).toMSecsSinceEpoch() + ) + + """, + "date": """ + + str( + QDateTime(QDate(2021, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch() + ) + + """, "time": "13:13:14" }, "geometry": { @@ -332,12 +438,20 @@ def setUpClass(cls): } } ] - }""").encode('UTF-8')) - - with open(sanitize(endpoint, - '/query?f=json&objectIds=3,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'), - 'wb') as f: - f.write((""" + }""" + ).encode("UTF-8") + ) + + with open( + sanitize( + endpoint, + "/query?f=json&objectIds=3,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false", + ), + "wb", + ) as f: + f.write( + ( + """ { "displayFieldName": "name", "fieldAliases": { @@ -381,8 +495,18 @@ def setUpClass(cls): "name": "Apple", "name2":"Apple", "num_char":"2", - "dt": """ + str(QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)).toMSecsSinceEpoch()) + """, - "date": """ + str(QDateTime(QDate(2020, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch()) + """, + "dt": """ + + str( + QDateTime( + QDate(2020, 5, 4), QTime(12, 14, 14) + ).toMSecsSinceEpoch() + ) + + """, + "date": """ + + str( + QDateTime(QDate(2020, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch() + ) + + """, "time": "12:14:14" }, "geometry": { @@ -398,8 +522,18 @@ def setUpClass(cls): "name": "Honey", "name2":"Honey", "num_char":"4", - "dt": """ + str(QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)).toMSecsSinceEpoch()) + """, - "date": """ + str(QDateTime(QDate(2021, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch()) + """, + "dt": """ + + str( + QDateTime( + QDate(2021, 5, 4), QTime(13, 13, 14) + ).toMSecsSinceEpoch() + ) + + """, + "date": """ + + str( + QDateTime(QDate(2021, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch() + ) + + """, "time": "13:13:14" }, "geometry": { @@ -408,12 +542,20 @@ def setUpClass(cls): } } ] - }""").encode('UTF-8')) - - with open(sanitize(endpoint, - '/query?f=json&objectIds=3,2&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'), - 'wb') as f: - f.write((""" + }""" + ).encode("UTF-8") + ) + + with open( + sanitize( + endpoint, + "/query?f=json&objectIds=3,2&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false", + ), + "wb", + ) as f: + f.write( + ( + """ { "displayFieldName": "name", "fieldAliases": { @@ -457,8 +599,18 @@ def setUpClass(cls): "name": "Apple", "name2":"Apple", "num_char":"2", - "dt": """ + str(QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)).toMSecsSinceEpoch()) + """, - "date": """ + str(QDateTime(QDate(2020, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch()) + """, + "dt": """ + + str( + QDateTime( + QDate(2020, 5, 4), QTime(12, 14, 14) + ).toMSecsSinceEpoch() + ) + + """, + "date": """ + + str( + QDateTime(QDate(2020, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch() + ) + + """, "time": "12:14:14" }, "geometry": { @@ -474,8 +626,18 @@ def setUpClass(cls): "name": "Honey", "name2":"Honey", "num_char":"4", - "dt": """ + str(QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)).toMSecsSinceEpoch()) + """, - "date": """ + str(QDateTime(QDate(2021, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch()) + """, + "dt": """ + + str( + QDateTime( + QDate(2021, 5, 4), QTime(13, 13, 14) + ).toMSecsSinceEpoch() + ) + + """, + "date": """ + + str( + QDateTime(QDate(2021, 5, 4), QTime(0, 0, 0)).toMSecsSinceEpoch() + ) + + """, "time": "13:13:14" }, "geometry": { @@ -484,12 +646,19 @@ def setUpClass(cls): } } ] - }""").encode('UTF-8')) - - with open(sanitize(endpoint, - '/query?f=json&objectIds=5,3,1,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false&geometry=-71.123000,66.330000,-65.320000,78.300000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects'), - 'wb') as f: - f.write(b""" + }""" + ).encode("UTF-8") + ) + + with open( + sanitize( + endpoint, + "/query?f=json&objectIds=5,3,1,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false&geometry=-71.123000,66.330000,-65.320000,78.300000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects", + ), + "wb", + ) as f: + f.write( + b""" { "displayFieldName": "name", "fieldAliases": { @@ -579,12 +748,18 @@ def setUpClass(cls): } } ] -}""") - - with open(sanitize(endpoint, - '/query?f=json&objectIds=2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'), - 'wb') as f: - f.write(b""" +}""" + ) + + with open( + sanitize( + endpoint, + "/query?f=json&objectIds=2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false", + ), + "wb", + ) as f: + f.write( + b""" { "displayFieldName": "name", "fieldAliases": { @@ -635,12 +810,18 @@ def setUpClass(cls): } } ] - }""") - - with open(sanitize(endpoint, - '/query?f=json&where=1=1&returnIdsOnly=true&geometry=-70.000000,67.000000,-60.000000,80.000000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects'), - 'wb') as f: - f.write(b""" + }""" + ) + + with open( + sanitize( + endpoint, + "/query?f=json&where=1=1&returnIdsOnly=true&geometry=-70.000000,67.000000,-60.000000,80.000000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects", + ), + "wb", + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ @@ -648,12 +829,18 @@ def setUpClass(cls): 4 ] } - """) - - with open(sanitize(endpoint, - '/query?f=json&where==1=&returnIdsOnly=true&geometry=-73.000000,70.000000,-63.000000,80.000000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects'), - 'wb') as f: - f.write(b""" + """ + ) + + with open( + sanitize( + endpoint, + "/query?f=json&where==1=&returnIdsOnly=true&geometry=-73.000000,70.000000,-63.000000,80.000000&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects", + ), + "wb", + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ @@ -661,12 +848,18 @@ def setUpClass(cls): 4 ] } - """) - - with open(sanitize(endpoint, - '/query?f=json&where=1=1&returnIdsOnly=true&geometry=-68.721119,68.177676,-64.678700,79.123755&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects'), - 'wb') as f: - f.write(b""" + """ + ) + + with open( + sanitize( + endpoint, + "/query?f=json&where=1=1&returnIdsOnly=true&geometry=-68.721119,68.177676,-64.678700,79.123755&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelEnvelopeIntersects", + ), + "wb", + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ @@ -674,12 +867,17 @@ def setUpClass(cls): 4 ] } - """) - - with open(sanitize(endpoint, - '/query?f=json&where="name"=\'Apple\'&returnExtentOnly=true'), - 'wb') as f: - f.write(b""" + """ + ) + + with open( + sanitize( + endpoint, "/query?f=json&where=\"name\"='Apple'&returnExtentOnly=true" + ), + "wb", + ) as f: + f.write( + b""" { "extent": { "xmin": -68.2, @@ -688,35 +886,44 @@ def setUpClass(cls): "ymax":70.8 } } - """) - - with open(sanitize(endpoint, - '/query?f=json&where="name"=\'AppleBearOrangePear\'&returnExtentOnly=true'), - 'wb') as f: - f.write(b""" + """ + ) + + with open( + sanitize( + endpoint, + "/query?f=json&where=\"name\"='AppleBearOrangePear'&returnExtentOnly=true", + ), + "wb", + ) as f: + f.write( + b""" { "extent": { } } - """) + """ + ) @classmethod def tearDownClass(cls): """Run after all tests""" QgsSettings().clear() # shutil.rmtree(cls.basetestpath, True) - cls.vl = None # so as to properly close the provider and remove any temporary file + cls.vl = ( + None # so as to properly close the provider and remove any temporary file + ) super().tearDownClass() def testGetFeaturesSubsetAttributes2(self): - """ Override and skip this test for AFS provider, as it's actually more efficient for the AFS provider to return + """Override and skip this test for AFS provider, as it's actually more efficient for the AFS provider to return its features as direct copies (due to implicit sharing of QgsFeature), and the nature of the caching used by the AFS provider. """ pass def testGetFeaturesNoGeometry(self): - """ Override and skip this test for AFS provider, as it's actually more efficient for the AFS provider to return + """Override and skip this test for AFS provider, as it's actually more efficient for the AFS provider to return its features as direct copies (due to implicit sharing of QgsFeature), and the nature of the caching used by the AFS provider. """ @@ -730,27 +937,51 @@ def testDecodeUri(self): Test decoding an AFS uri """ uri = self.vl.source() - parts = QgsProviderRegistry.instance().decodeUri(self.vl.dataProvider().name(), uri) - self.assertEqual(parts, {'crs': 'epsg:4326', 'url': 'http://' + self.basetestpath + '/fake_qgis_http_endpoint'}) + parts = QgsProviderRegistry.instance().decodeUri( + self.vl.dataProvider().name(), uri + ) + self.assertEqual( + parts, + { + "crs": "epsg:4326", + "url": "http://" + self.basetestpath + "/fake_qgis_http_endpoint", + }, + ) def testEncodeUri(self): """ Test encoding an AFS uri """ - parts = {'url': 'http://blah.com', 'crs': 'epsg:4326', 'referer': 'me', 'bounds': QgsRectangle(1, 2, 3, 4)} - uri = QgsProviderRegistry.instance().encodeUri(self.vl.dataProvider().name(), parts) - self.assertEqual(uri, " bbox='1,2,3,4' crs='epsg:4326' url='http://blah.com' http-header:referer='me' referer='me'") + parts = { + "url": "http://blah.com", + "crs": "epsg:4326", + "referer": "me", + "bounds": QgsRectangle(1, 2, 3, 4), + } + uri = QgsProviderRegistry.instance().encodeUri( + self.vl.dataProvider().name(), parts + ) + self.assertEqual( + uri, + " bbox='1,2,3,4' crs='epsg:4326' url='http://blah.com' http-header:referer='me' referer='me'", + ) def testProviderCapabilities(self): # non-editable layer - self.assertEqual(self.vl.dataProvider().capabilities(), QgsVectorDataProvider.Capabilities(QgsVectorDataProvider.Capability.SelectAtId - | QgsVectorDataProvider.Capability.ReadLayerMetadata - | QgsVectorDataProvider.Capability.ReloadData)) + self.assertEqual( + self.vl.dataProvider().capabilities(), + QgsVectorDataProvider.Capabilities( + QgsVectorDataProvider.Capability.SelectAtId + | QgsVectorDataProvider.Capability.ReadLayerMetadata + | QgsVectorDataProvider.Capability.ReloadData + ), + ) # delete capability - endpoint = self.basetestpath + '/delete_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + endpoint = self.basetestpath + "/delete_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -763,30 +994,45 @@ def testProviderCapabilities(self): "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data,Delete","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", - "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ 1 ] } - """) + """ + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) - self.assertEqual(vl.dataProvider().capabilities(), QgsVectorDataProvider.Capabilities(QgsVectorDataProvider.Capability.SelectAtId - | QgsVectorDataProvider.Capability.ReadLayerMetadata - | QgsVectorDataProvider.Capability.ReloadData - | QgsVectorDataProvider.Capability.DeleteFeatures)) + self.assertEqual( + vl.dataProvider().capabilities(), + QgsVectorDataProvider.Capabilities( + QgsVectorDataProvider.Capability.SelectAtId + | QgsVectorDataProvider.Capability.ReadLayerMetadata + | QgsVectorDataProvider.Capability.ReloadData + | QgsVectorDataProvider.Capability.DeleteFeatures + ), + ) # add capability - endpoint = self.basetestpath + '/delete_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + endpoint = self.basetestpath + "/delete_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -799,19 +1045,30 @@ def testProviderCapabilities(self): "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data,Create","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", - "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") + "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) - self.assertEqual(vl.dataProvider().capabilities(), QgsVectorDataProvider.Capabilities(QgsVectorDataProvider.Capability.SelectAtId - | QgsVectorDataProvider.Capability.ReadLayerMetadata - | QgsVectorDataProvider.Capability.ReloadData - | QgsVectorDataProvider.Capability.AddFeatures)) + self.assertEqual( + vl.dataProvider().capabilities(), + QgsVectorDataProvider.Capabilities( + QgsVectorDataProvider.Capability.SelectAtId + | QgsVectorDataProvider.Capability.ReadLayerMetadata + | QgsVectorDataProvider.Capability.ReloadData + | QgsVectorDataProvider.Capability.AddFeatures + ), + ) # update capability - endpoint = self.basetestpath + '/delete_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + endpoint = self.basetestpath + "/delete_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -824,22 +1081,32 @@ def testProviderCapabilities(self): "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data,Update","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", - "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") + "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) - self.assertEqual(vl.dataProvider().capabilities(), - QgsVectorDataProvider.Capabilities(QgsVectorDataProvider.Capability.SelectAtId - | QgsVectorDataProvider.Capability.ReadLayerMetadata - | QgsVectorDataProvider.Capability.ReloadData - | QgsVectorDataProvider.Capability.ChangeAttributeValues - | QgsVectorDataProvider.Capability.ChangeFeatures - | QgsVectorDataProvider.Capability.ChangeGeometries)) + self.assertEqual( + vl.dataProvider().capabilities(), + QgsVectorDataProvider.Capabilities( + QgsVectorDataProvider.Capability.SelectAtId + | QgsVectorDataProvider.Capability.ReadLayerMetadata + | QgsVectorDataProvider.Capability.ReloadData + | QgsVectorDataProvider.Capability.ChangeAttributeValues + | QgsVectorDataProvider.Capability.ChangeFeatures + | QgsVectorDataProvider.Capability.ChangeGeometries + ), + ) # circular strings - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","allowTrueCurvesUpdates":true,"type":"Feature Layer","description": "QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -852,36 +1119,63 @@ def testProviderCapabilities(self): "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data,Update","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", - "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) - self.assertEqual(vl.dataProvider().capabilities(), - QgsVectorDataProvider.Capabilities(QgsVectorDataProvider.Capability.SelectAtId - | QgsVectorDataProvider.Capability.ReadLayerMetadata - | QgsVectorDataProvider.Capability.ReloadData - | QgsVectorDataProvider.Capability.ChangeAttributeValues - | QgsVectorDataProvider.Capability.ChangeFeatures - | QgsVectorDataProvider.Capability.CircularGeometries - | QgsVectorDataProvider.Capability.ChangeGeometries)) + self.assertEqual( + vl.dataProvider().capabilities(), + QgsVectorDataProvider.Capabilities( + QgsVectorDataProvider.Capability.SelectAtId + | QgsVectorDataProvider.Capability.ReadLayerMetadata + | QgsVectorDataProvider.Capability.ReloadData + | QgsVectorDataProvider.Capability.ChangeAttributeValues + | QgsVectorDataProvider.Capability.ChangeFeatures + | QgsVectorDataProvider.Capability.CircularGeometries + | QgsVectorDataProvider.Capability.ChangeGeometries + ), + ) def testFieldProperties(self): self.assertEqual(self.vl.dataProvider().pkAttributeIndexes(), [0]) - self.assertEqual(self.vl.dataProvider().fields()[0].constraints().constraints(), - QgsFieldConstraints.Constraints(QgsFieldConstraints.Constraint.ConstraintNotNull | QgsFieldConstraints.Constraint.ConstraintUnique)) + self.assertEqual( + self.vl.dataProvider().fields()[0].constraints().constraints(), + QgsFieldConstraints.Constraints( + QgsFieldConstraints.Constraint.ConstraintNotNull + | QgsFieldConstraints.Constraint.ConstraintUnique + ), + ) self.assertFalse(self.vl.dataProvider().fields()[1].constraints().constraints()) - self.assertEqual(self.vl.dataProvider().defaultValueClause(0), 'Autogenerate') + self.assertEqual(self.vl.dataProvider().defaultValueClause(0), "Autogenerate") self.assertFalse(self.vl.dataProvider().defaultValueClause(1)) - self.assertTrue(self.vl.dataProvider().skipConstraintCheck(0, QgsFieldConstraints.Constraint.ConstraintUnique, 'Autogenerate')) - self.assertFalse(self.vl.dataProvider().skipConstraintCheck(0, QgsFieldConstraints.Constraint.ConstraintUnique, 'aa')) - self.assertFalse(self.vl.dataProvider().skipConstraintCheck(1, QgsFieldConstraints.Constraint.ConstraintUnique, 'aa')) + self.assertTrue( + self.vl.dataProvider().skipConstraintCheck( + 0, QgsFieldConstraints.Constraint.ConstraintUnique, "Autogenerate" + ) + ) + self.assertFalse( + self.vl.dataProvider().skipConstraintCheck( + 0, QgsFieldConstraints.Constraint.ConstraintUnique, "aa" + ) + ) + self.assertFalse( + self.vl.dataProvider().skipConstraintCheck( + 1, QgsFieldConstraints.Constraint.ConstraintUnique, "aa" + ) + ) def testObjectIdDifferentName(self): - """ Test that object id fields not named OBJECTID work correctly """ + """Test that object id fields not named OBJECTID work correctly""" - endpoint = self.basetestpath + '/oid_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + endpoint = self.basetestpath + "/oid_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer.\n","geometryType":"esriGeometryPoint","copyrightText":"","parentLayer":{"id":0,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -896,10 +1190,14 @@ def testObjectIdDifferentName(self): "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", - "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID1", "objectIds": [ @@ -910,12 +1208,18 @@ def testObjectIdDifferentName(self): 4 ] } - """) - - with open(sanitize(endpoint, - '/query?f=json&objectIds=5,3,1,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'), - 'wb') as f: - f.write(b""" + """ + ) + + with open( + sanitize( + endpoint, + "/query?f=json&objectIds=5,3,1,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false", + ), + "wb", + ) as f: + f.write( + b""" { "displayFieldName": "LABEL", "geometryType": "esriGeometryPoint", @@ -941,21 +1245,27 @@ def testObjectIdDifferentName(self): } } ] - }""") + }""" + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) f = vl.getFeature(0) self.assertTrue(f.isValid()) def testDateTime(self): - """ Test that datetime fields work correctly """ + """Test that datetime fields work correctly""" - endpoint = self.basetestpath + '/oid_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + endpoint = self.basetestpath + "/oid_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer.\n","geometryType":"esriGeometryPoint","copyrightText":"","parentLayer":{"id":0,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -970,10 +1280,14 @@ def testDateTime(self): "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", - "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ @@ -981,19 +1295,31 @@ def testDateTime(self): 2 ] } - """) + """ + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) - self.assertFalse(vl.dataProvider().temporalCapabilities().hasTemporalCapabilities()) - - with open(sanitize(endpoint, - '/query?f=json&objectIds=1,2&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'), - 'wb') as f: - f.write(b""" + self.assertFalse( + vl.dataProvider().temporalCapabilities().hasTemporalCapabilities() + ) + + with open( + sanitize( + endpoint, + "/query?f=json&objectIds=1,2&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false", + ), + "wb", + ) as f: + f.write( + b""" { "displayFieldName": "name", "fieldAliases": { @@ -1032,18 +1358,28 @@ def testDateTime(self): } } ] - }""") + }""" + ) features = [f for f in vl.getFeatures()] self.assertEqual(len(features), 2) - self.assertEqual([f['dt'] for f in features], [QDateTime(QDate(2017, 5, 3), QTime(0, 0, 0, 0), Qt.TimeSpec.UTC).toLocalTime(), NULL]) + self.assertEqual( + [f["dt"] for f in features], + [ + QDateTime( + QDate(2017, 5, 3), QTime(0, 0, 0, 0), Qt.TimeSpec.UTC + ).toLocalTime(), + NULL, + ], + ) def testMetadata(self): - """ Test that metadata is correctly acquired from provider """ + """Test that metadata is correctly acquired from provider""" - endpoint = self.basetestpath + '/metadata_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + endpoint = self.basetestpath + "/metadata_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -1056,20 +1392,29 @@ def testMetadata(self): "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", - "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ 1 ] } - """) + """ + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) extent = QgsLayerMetadata.Extent() @@ -1080,24 +1425,25 @@ def testMetadata(self): md = vl.metadata() self.assertEqual(md.extent(), extent) self.assertEqual(md.crs(), QgsCoordinateReferenceSystem.fromEpsgId(4326)) - self.assertEqual(md.identifier(), 'http://' + sanitize(endpoint, '')) - self.assertEqual(md.parentIdentifier(), 'http://' + self.basetestpath + '/2') - self.assertEqual(md.type(), 'dataset') - self.assertEqual(md.abstract(), 'QGIS Provider Test Layer') - self.assertEqual(md.title(), 'QGIS Test') - self.assertEqual(md.rights(), ['not copyright']) + self.assertEqual(md.identifier(), "http://" + sanitize(endpoint, "")) + self.assertEqual(md.parentIdentifier(), "http://" + self.basetestpath + "/2") + self.assertEqual(md.type(), "dataset") + self.assertEqual(md.abstract(), "QGIS Provider Test Layer") + self.assertEqual(md.title(), "QGIS Test") + self.assertEqual(md.rights(), ["not copyright"]) l = QgsLayerMetadata.Link() - l.name = 'Source' - l.type = 'WWW:LINK' - l.url = 'http://' + sanitize(endpoint, '') + l.name = "Source" + l.type = "WWW:LINK" + l.url = "http://" + sanitize(endpoint, "") self.assertEqual(md.links(), [l]) def testFieldAlias(self): - """ Test that field aliases are correctly acquired from provider """ + """Test that field aliases are correctly acquired from provider""" - endpoint = self.basetestpath + '/alias_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + endpoint = self.basetestpath + "/alias_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -1110,33 +1456,43 @@ def testFieldAlias(self): "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", - "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ 1 ] } - """) + """ + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) - self.assertEqual(vl.fields().at(0).name(), 'OBJECTID') - self.assertEqual(vl.fields().at(0).alias(), 'field id') - self.assertEqual(vl.fields().at(1).name(), 'second') + self.assertEqual(vl.fields().at(0).name(), "OBJECTID") + self.assertEqual(vl.fields().at(0).alias(), "field id") + self.assertEqual(vl.fields().at(1).name(), "second") self.assertFalse(vl.fields().at(1).alias()) def testCategorizedRenderer(self): - """ Test that the categorized renderer is correctly acquired from provider """ + """Test that the categorized renderer is correctly acquired from provider""" - endpoint = self.basetestpath + '/renderer_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + endpoint = self.basetestpath + "/renderer_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -1211,26 +1567,35 @@ def testCategorizedRenderer(self): }, "label": "Canada" }]}}, - "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ 1 ] } - """) + """ + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) self.assertIsNotNone(vl.dataProvider().createRenderer()) self.assertIsInstance(vl.renderer(), QgsCategorizedSymbolRenderer) self.assertEqual(len(vl.renderer().categories()), 2) - self.assertEqual(vl.renderer().categories()[0].value(), 'US') - self.assertEqual(vl.renderer().categories()[1].value(), 'Canada') + self.assertEqual(vl.renderer().categories()[0].value(), "US") + self.assertEqual(vl.renderer().categories()[1].value(), "Canada") def testGraduatedRendererContinuous(self): """ @@ -1238,9 +1603,10 @@ def testGraduatedRendererContinuous(self): is correctly acquired from provider """ - endpoint = self.basetestpath + '/class_breaks_renderer_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b"""{ + endpoint = self.basetestpath + "/class_breaks_renderer_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b"""{ "currentVersion": 11.2, "id": 0, "name": "Test graduated renderer", @@ -1388,37 +1754,54 @@ def testGraduatedRendererContinuous(self): "transparency": 20 }, "allowGeometryUpdates": true - }""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + }""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ 1 ] } - """) + """ + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:3857'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:3857'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) self.assertIsNotNone(vl.dataProvider().createRenderer()) self.assertIsInstance(vl.renderer(), QgsSingleSymbolRenderer) self.assertIsInstance(vl.renderer().symbol(), QgsFillSymbol) - prop = vl.renderer().symbol()[0].dataDefinedProperties().property(QgsSymbolLayer.Property.FillColor) + prop = ( + vl.renderer() + .symbol()[0] + .dataDefinedProperties() + .property(QgsSymbolLayer.Property.FillColor) + ) self.assertEqual(prop.propertyType(), Qgis.PropertyType.Field) - self.assertEqual(prop.field(), 'SUM') + self.assertEqual(prop.field(), "SUM") self.assertIsInstance(prop.transformer(), QgsColorRampTransformer) self.assertEqual(prop.transformer().minValue(), 10151) self.assertEqual(prop.transformer().maxValue(), 2500000) ramp = prop.transformer().colorRamp() self.assertIsInstance(ramp, QgsGradientColorRamp) - self.assertEqual(ramp.color1().name(), '#ffc4ae') - self.assertEqual(ramp.color2().name(), '#7b4238') + self.assertEqual(ramp.color1().name(), "#ffc4ae") + self.assertEqual(ramp.color2().name(), "#7b4238") self.assertEqual([stop.offset for stop in ramp.stops()], [0.25, 0.5, 0.75]) - self.assertEqual([stop.color.name() for stop in ramp.stops()], ['#f9816c', '#ec5244', '#c23d33']) + self.assertEqual( + [stop.color.name() for stop in ramp.stops()], + ["#f9816c", "#ec5244", "#c23d33"], + ) def testGraduatedRendererClassedColor(self): """ @@ -1426,9 +1809,10 @@ def testGraduatedRendererClassedColor(self): is correctly acquired from provider """ - endpoint = self.basetestpath + '/class_breaks_renderer_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b"""{ + endpoint = self.basetestpath + "/class_breaks_renderer_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b"""{ "currentVersion": 11.2, "id": 0, "name": "Test graduated renderer", @@ -1678,20 +2062,29 @@ def testGraduatedRendererClassedColor(self): "labelingInfo": null }, "allowGeometryUpdates": true -}""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" +}""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ 1 ] } - """) + """ + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:3857'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:3857'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) self.assertIsNotNone(vl.dataProvider().createRenderer()) self.assertIsInstance(vl.renderer(), QgsGraduatedSymbolRenderer) @@ -1701,58 +2094,58 @@ def testGraduatedRendererClassedColor(self): _range = vl.renderer().ranges()[0] self.assertEqual(_range.lowerValue(), 7) self.assertEqual(_range.upperValue(), 7) - self.assertEqual(_range.label(), '7.000000') - self.assertEqual(_range.symbol().color().name(), - '#e6eecf') + self.assertEqual(_range.label(), "7.000000") + self.assertEqual(_range.symbol().color().name(), "#e6eecf") _range = vl.renderer().ranges()[1] self.assertEqual(_range.lowerValue(), 7) self.assertEqual(_range.upperValue(), 8) - self.assertEqual(_range.label(), '7.000001 - 8.000000') - self.assertEqual(_range.symbol().color().name(), - '#9bc4c1') + self.assertEqual(_range.label(), "7.000001 - 8.000000") + self.assertEqual(_range.symbol().color().name(), "#9bc4c1") _range = vl.renderer().ranges()[2] self.assertEqual(_range.lowerValue(), 8) self.assertEqual(_range.upperValue(), 11) - self.assertEqual(_range.label(), '8.000001 - 11.000000') - self.assertEqual(_range.symbol().color().name(), - '#69a8b7') + self.assertEqual(_range.label(), "8.000001 - 11.000000") + self.assertEqual(_range.symbol().color().name(), "#69a8b7") _range = vl.renderer().ranges()[3] self.assertEqual(_range.lowerValue(), 11) self.assertEqual(_range.upperValue(), 13) - self.assertEqual(_range.label(), '11.000001 - 13.000000') - self.assertEqual(_range.symbol().color().name(), - '#4b7e98') + self.assertEqual(_range.label(), "11.000001 - 13.000000") + self.assertEqual(_range.symbol().color().name(), "#4b7e98") _range = vl.renderer().ranges()[4] self.assertEqual(_range.lowerValue(), 13) self.assertEqual(_range.upperValue(), 20) - self.assertEqual(_range.label(), '13.000001 - 20.000000') - self.assertEqual(_range.symbol().color().name(), - '#2e557a') + self.assertEqual(_range.label(), "13.000001 - 20.000000") + self.assertEqual(_range.symbol().color().name(), "#2e557a") def testBboxRestriction(self): """ Test limiting provider to features within a preset bounding box """ - endpoint = self.basetestpath + '/fake_qgis_http_endpoint' + endpoint = self.basetestpath + "/fake_qgis_http_endpoint" vl = QgsVectorLayer( - "url='http://" + endpoint + "' crs='epsg:4326' bbox='-70.000000,67.000000,-60.000000,80.000000'", 'test', - 'arcgisfeatureserver') + "url='http://" + + endpoint + + "' crs='epsg:4326' bbox='-70.000000,67.000000,-60.000000,80.000000'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 2) - self.assertEqual([f['pk'] for f in vl.getFeatures()], [2, 4]) + self.assertEqual([f["pk"] for f in vl.getFeatures()], [2, 4]) def testBadMultiPoints(self): """ Test invalid server response where a layer's type is multipoint but single point geometries are returned. Thanks Jack. Thack. """ - endpoint = self.basetestpath + '/multipoint_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + endpoint = self.basetestpath + "/multipoint_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer.\n","geometryType":"esriGeometryMultipoint","copyrightText":"","parentLayer":{"id":0,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -1765,10 +2158,14 @@ def testBadMultiPoints(self): "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", - "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ @@ -1777,16 +2174,26 @@ def testBadMultiPoints(self): 3 ] } - """) + """ + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) - with open(sanitize(endpoint, - '/query?f=json&objectIds=1,2,3&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "/query?f=json&objectIds=1,2,3&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false", + ), + "wb", + ) as f: + f.write( + b""" { "displayFieldName": "name", "fieldAliases": { @@ -1825,20 +2232,24 @@ def testBadMultiPoints(self): } } ] - }""") + }""" + ) features = [f for f in vl.getFeatures()] self.assertEqual(len(features), 3) - self.assertEqual([f.geometry().asWkt() for f in features], - ['MultiPoint ((-70 66))', '', 'MultiPoint ((-68 70),(-22 21))']) + self.assertEqual( + [f.geometry().asWkt() for f in features], + ["MultiPoint ((-70 66))", "", "MultiPoint ((-68 70),(-22 21))"], + ) def testDomain(self): """ Test fields with a domain are mapped to value map wrapper, for correct value display """ - endpoint = self.basetestpath + '/domain_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + endpoint = self.basetestpath + "/domain_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer.\n","geometryType":"esriGeometryPoint","copyrightText":"","parentLayer":{"id":0,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -1874,10 +2285,14 @@ def testDomain(self): "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", - "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ @@ -1886,24 +2301,32 @@ def testDomain(self): 3 ] } - """) + """ + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) self.assertFalse(vl.fields()[0].editorWidgetSetup().type()) - self.assertEqual(vl.fields()[1].editorWidgetSetup().type(), 'ValueMap') - self.assertEqual(vl.fields()[1].editorWidgetSetup().config(), - {'map': [{'Value 1': 1.0}, {'Value 2': 2.0}, {'Value 3': 3.0}]}) + self.assertEqual(vl.fields()[1].editorWidgetSetup().type(), "ValueMap") + self.assertEqual( + vl.fields()[1].editorWidgetSetup().config(), + {"map": [{"Value 1": 1.0}, {"Value 2": 2.0}, {"Value 3": 3.0}]}, + ) def testTemporal1(self): """ Test timeinfo parsing """ - endpoint = self.basetestpath + '/temporal1_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + endpoint = self.basetestpath + "/temporal1_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer.\n","geometryType":"esriGeometryPoint","copyrightText":"","parentLayer":{"id":0,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -1926,10 +2349,14 @@ def testTemporal1(self): "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", - "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ @@ -1938,26 +2365,45 @@ def testTemporal1(self): 3 ] } - """) + """ + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) - self.assertTrue(vl.dataProvider().temporalCapabilities().hasTemporalCapabilities()) - self.assertEqual(vl.dataProvider().temporalCapabilities().startField(), 'date_start') + self.assertTrue( + vl.dataProvider().temporalCapabilities().hasTemporalCapabilities() + ) + self.assertEqual( + vl.dataProvider().temporalCapabilities().startField(), "date_start" + ) self.assertFalse(vl.dataProvider().temporalCapabilities().endField()) - self.assertEqual(vl.dataProvider().temporalCapabilities().mode(), QgsVectorDataProviderTemporalCapabilities.TemporalMode.ProviderStoresFeatureDateTimeInstantInField) - self.assertEqual(vl.dataProvider().temporalCapabilities().availableTemporalRange().begin(), QDateTime(QDate(2006, 3, 10), QTime(14, 13, 20), Qt.TimeSpec.UTC)) - self.assertEqual(vl.dataProvider().temporalCapabilities().availableTemporalRange().end(), QDateTime(QDate(2017, 2, 13), QTime(15, 33, 20), Qt.TimeSpec.UTC)) + self.assertEqual( + vl.dataProvider().temporalCapabilities().mode(), + QgsVectorDataProviderTemporalCapabilities.TemporalMode.ProviderStoresFeatureDateTimeInstantInField, + ) + self.assertEqual( + vl.dataProvider().temporalCapabilities().availableTemporalRange().begin(), + QDateTime(QDate(2006, 3, 10), QTime(14, 13, 20), Qt.TimeSpec.UTC), + ) + self.assertEqual( + vl.dataProvider().temporalCapabilities().availableTemporalRange().end(), + QDateTime(QDate(2017, 2, 13), QTime(15, 33, 20), Qt.TimeSpec.UTC), + ) def testTemporal2(self): """ Test timeinfo parsing """ - endpoint = self.basetestpath + '/temporal2_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + endpoint = self.basetestpath + "/temporal2_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer.\n","geometryType":"esriGeometryPoint","copyrightText":"","parentLayer":{"id":0,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -1980,10 +2426,14 @@ def testTemporal2(self): "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", - "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ @@ -1992,26 +2442,47 @@ def testTemporal2(self): 3 ] } - """) + """ + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) - self.assertTrue(vl.dataProvider().temporalCapabilities().hasTemporalCapabilities()) - self.assertEqual(vl.dataProvider().temporalCapabilities().startField(), 'date_start') - self.assertEqual(vl.dataProvider().temporalCapabilities().endField(), 'date_end') - self.assertEqual(vl.dataProvider().temporalCapabilities().mode(), QgsVectorDataProviderTemporalCapabilities.TemporalMode.ProviderStoresFeatureDateTimeStartAndEndInSeparateFields) - self.assertEqual(vl.dataProvider().temporalCapabilities().availableTemporalRange().begin(), QDateTime(QDate(2006, 3, 10), QTime(14, 13, 20), Qt.TimeSpec.UTC)) - self.assertEqual(vl.dataProvider().temporalCapabilities().availableTemporalRange().end(), QDateTime(QDate(2017, 2, 13), QTime(15, 33, 20), Qt.TimeSpec.UTC)) + self.assertTrue( + vl.dataProvider().temporalCapabilities().hasTemporalCapabilities() + ) + self.assertEqual( + vl.dataProvider().temporalCapabilities().startField(), "date_start" + ) + self.assertEqual( + vl.dataProvider().temporalCapabilities().endField(), "date_end" + ) + self.assertEqual( + vl.dataProvider().temporalCapabilities().mode(), + QgsVectorDataProviderTemporalCapabilities.TemporalMode.ProviderStoresFeatureDateTimeStartAndEndInSeparateFields, + ) + self.assertEqual( + vl.dataProvider().temporalCapabilities().availableTemporalRange().begin(), + QDateTime(QDate(2006, 3, 10), QTime(14, 13, 20), Qt.TimeSpec.UTC), + ) + self.assertEqual( + vl.dataProvider().temporalCapabilities().availableTemporalRange().end(), + QDateTime(QDate(2017, 2, 13), QTime(15, 33, 20), Qt.TimeSpec.UTC), + ) def testImageServer(self): """ Test connecting to a image server endpoints works as a footprint featureserver """ - endpoint = self.basetestpath + '/imageserver_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + endpoint = self.basetestpath + "/imageserver_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" { "currentVersion": 10.51, "serviceDescription": "test", @@ -2205,10 +2676,14 @@ def testImageServer(self): "wkid": 102100, "latestWkid": 3857 } -}""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" +}""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ @@ -2217,19 +2692,25 @@ def testImageServer(self): 3 ] } - """) + """ + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Polygon) def testDelete(self): # delete capability - endpoint = self.basetestpath + '/delete_test_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + endpoint = self.basetestpath + "/delete_test_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -2242,44 +2723,56 @@ def testDelete(self): "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data,Delete","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", - "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ 1 ] } - """) + """ + ) - delete_endpoint = sanitize(endpoint, '/deleteFeatures') - with open(delete_endpoint, 'wb') as f: - f.write(b"""{ + delete_endpoint = sanitize(endpoint, "/deleteFeatures") + with open(delete_endpoint, "wb") as f: + f.write( + b"""{ "deleteResults": [ { "objectId": 1, "success": true } ] -}""") +}""" + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) res = vl.dataProvider().deleteFeatures([0]) self.assertTrue(res) with open(delete_endpoint + "_payload") as f: - res = '\n'.join(f.readlines()) - self.assertEqual(res, 'f=json&objectIds=1') + res = "\n".join(f.readlines()) + self.assertEqual(res, "f=json&objectIds=1") def testAddSuccess(self): # add capability - endpoint = self.basetestpath + '/delete_test_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + endpoint = self.basetestpath + "/delete_test_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -2292,30 +2785,41 @@ def testAddSuccess(self): "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data,Create","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", - "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ 1 ] } - """) + """ + ) - add_endpoint = sanitize(endpoint, '/addFeatures') - with open(add_endpoint, 'wb') as f: - f.write(b"""{ + add_endpoint = sanitize(endpoint, "/addFeatures") + with open(add_endpoint, "wb") as f: + f.write( + b"""{ "addResults": [ { "objectId": 617, "success": true } ] -}""") +}""" + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) f = QgsFeature() @@ -2325,17 +2829,21 @@ def testAddSuccess(self): self.assertTrue(res) with open(add_endpoint + "_payload") as f: - res = '\n'.join(f.readlines()) - self.assertEqual(res, 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 11\n\n }\n\n }\n\n]') + res = "\n".join(f.readlines()) + self.assertEqual( + res, + 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 11\n\n }\n\n }\n\n]', + ) # add empty list, should return true for consistency self.assertTrue(vl.dataProvider().addFeatures([])) def testAddFail(self): # add capability - endpoint = self.basetestpath + '/delete_test_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + endpoint = self.basetestpath + "/delete_test_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -2348,21 +2856,27 @@ def testAddFail(self): "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data,Create","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", - "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ 1 ] } - """) + """ + ) - add_endpoint = sanitize(endpoint, '/addFeatures') - with open(add_endpoint, 'wb') as f: - f.write(b"""{ + add_endpoint = sanitize(endpoint, "/addFeatures") + with open(add_endpoint, "wb") as f: + f.write( + b"""{ "addResults": [ { "success": false, @@ -2372,9 +2886,14 @@ def testAddFail(self): } } ] -}""") +}""" + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) f = QgsFeature() @@ -2382,17 +2901,24 @@ def testAddFail(self): f.setAttributes([11]) res, f = vl.dataProvider().addFeatures([f]) self.assertFalse(res) - self.assertEqual(vl.dataProvider().lastError(), 'Error while adding features: Setting of Value for depth failed.') + self.assertEqual( + vl.dataProvider().lastError(), + "Error while adding features: Setting of Value for depth failed.", + ) with open(add_endpoint + "_payload") as f: - res = '\n'.join(f.readlines()) - self.assertEqual(res, 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 11\n\n }\n\n }\n\n]') + res = "\n".join(f.readlines()) + self.assertEqual( + res, + 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 11\n\n }\n\n }\n\n]', + ) def testChangeAttributeValuesSuccess(self): # add capability - endpoint = self.basetestpath + '/change_attr_test_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + endpoint = self.basetestpath + "/change_attr_test_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -2409,22 +2935,32 @@ def testChangeAttributeValuesSuccess(self): "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data,Create,Update","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", - "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ 1 ] } - """) - - with open(sanitize(endpoint, - '/query?f=json&objectIds=1&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'), - 'wb') as f: - f.write(b""" + """ + ) + + with open( + sanitize( + endpoint, + "/query?f=json&objectIds=1&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false", + ), + "wb", + ) as f: + f.write( + b""" { "displayFieldName": "name", "fieldAliases": { @@ -2454,34 +2990,45 @@ def testChangeAttributeValuesSuccess(self): } } ] - }""") + }""" + ) - add_endpoint = sanitize(endpoint, '/updateFeatures') - with open(add_endpoint, 'wb') as f: - f.write(b"""{ + add_endpoint = sanitize(endpoint, "/updateFeatures") + with open(add_endpoint, "wb") as f: + f.write( + b"""{ "addResults": [ { "objectId": 617, "success": true } ] -}""") +}""" + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) - res = vl.dataProvider().changeAttributeValues({0: {1: 'xxname', 2: 'xxname2'}}) + res = vl.dataProvider().changeAttributeValues({0: {1: "xxname", 2: "xxname2"}}) self.assertTrue(res) with open(add_endpoint + "_payload") as f: - res = '\n'.join(f.readlines()) - self.assertEqual(res, 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 1,\n\n "name": "xxname",\n\n "name2": "xxname2",\n\n "name3": "name3"\n\n }\n\n }\n\n]') + res = "\n".join(f.readlines()) + self.assertEqual( + res, + 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 1,\n\n "name": "xxname",\n\n "name2": "xxname2",\n\n "name3": "name3"\n\n }\n\n }\n\n]', + ) def testChangeGeometriesSuccess(self): # add capability - endpoint = self.basetestpath + '/change_geom_test_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + endpoint = self.basetestpath + "/change_geom_test_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -2498,22 +3045,32 @@ def testChangeGeometriesSuccess(self): "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data,Create,Update","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", - "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ 1 ] } - """) - - with open(sanitize(endpoint, - '/query?f=json&objectIds=1&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'), - 'wb') as f: - f.write(b""" + """ + ) + + with open( + sanitize( + endpoint, + "/query?f=json&objectIds=1&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false", + ), + "wb", + ) as f: + f.write( + b""" { "displayFieldName": "name", "fieldAliases": { @@ -2543,34 +3100,47 @@ def testChangeGeometriesSuccess(self): } } ] - }""") + }""" + ) - add_endpoint = sanitize(endpoint, '/updateFeatures') - with open(add_endpoint, 'wb') as f: - f.write(b"""{ + add_endpoint = sanitize(endpoint, "/updateFeatures") + with open(add_endpoint, "wb") as f: + f.write( + b"""{ "addResults": [ { "objectId": 617, "success": true } ] -}""") +}""" + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) - res = vl.dataProvider().changeGeometryValues({0: QgsGeometry.fromWkt('Point( 111 222)')}) + res = vl.dataProvider().changeGeometryValues( + {0: QgsGeometry.fromWkt("Point( 111 222)")} + ) self.assertTrue(res) with open(add_endpoint + "_payload") as f: - res = '\n'.join(f.readlines()) - self.assertEqual(res, 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 1\n\n },\n\n "geometry": {\n\n "x": 111.0,\n\n "y": 222.0\n\n }\n\n }\n\n]') + res = "\n".join(f.readlines()) + self.assertEqual( + res, + 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 1\n\n },\n\n "geometry": {\n\n "x": 111.0,\n\n "y": 222.0\n\n }\n\n }\n\n]', + ) def testChangeFeaturesSuccess(self): # add capability - endpoint = self.basetestpath + '/change_geom_test_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?f=json'), 'wb') as f: - f.write(b""" + endpoint = self.basetestpath + "/change_geom_test_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "?f=json"), "wb") as f: + f.write( + b""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, @@ -2587,10 +3157,14 @@ def testChangeFeaturesSuccess(self): "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data,Create,Update","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", - "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""") - - with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: - f.write(b""" + "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" + ) + + with open( + sanitize(endpoint, "/query?f=json_where=1=1&returnIdsOnly=true"), "wb" + ) as f: + f.write( + b""" { "objectIdFieldName": "OBJECTID", "objectIds": [ @@ -2598,12 +3172,18 @@ def testChangeFeaturesSuccess(self): 2 ] } - """) - - with open(sanitize(endpoint, - '/query?f=json&objectIds=1,2&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false'), - 'wb') as f: - f.write(b""" + """ + ) + + with open( + sanitize( + endpoint, + "/query?f=json&objectIds=1,2&inSR=4326&outSR=4326&returnGeometry=true&outFields=*&returnM=false&returnZ=false", + ), + "wb", + ) as f: + f.write( + b""" { "displayFieldName": "name", "fieldAliases": { @@ -2644,29 +3224,42 @@ def testChangeFeaturesSuccess(self): } } ] - }""") + }""" + ) - add_endpoint = sanitize(endpoint, '/updateFeatures') - with open(add_endpoint, 'wb') as f: - f.write(b"""{ + add_endpoint = sanitize(endpoint, "/updateFeatures") + with open(add_endpoint, "wb") as f: + f.write( + b"""{ "addResults": [ { "objectId": 617, "success": true } ] -}""") +}""" + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' crs='epsg:4326'", + "test", + "arcgisfeatureserver", + ) self.assertTrue(vl.isValid()) - res = vl.dataProvider().changeFeatures({1: {1: 'bname1_x', 3: 'bname3_x'}}, {0: QgsGeometry.fromWkt('Point( 111 222)')}) + res = vl.dataProvider().changeFeatures( + {1: {1: "bname1_x", 3: "bname3_x"}}, + {0: QgsGeometry.fromWkt("Point( 111 222)")}, + ) self.assertTrue(res) with open(add_endpoint + "_payload") as f: - res = '\n'.join(f.readlines()) - self.assertEqual(res, 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 1,\n\n "name": "name1",\n\n "name2": "name2",\n\n "name3": "name3"\n\n },\n\n "geometry": {\n\n "x": 111.0,\n\n "y": 222.0\n\n }\n\n },\n\n {\n\n "attributes": {\n\n "OBJECTID": 2,\n\n "name": "bname1_x",\n\n "name2": "bname2",\n\n "name3": "bname3_x"\n\n },\n\n "geometry": {\n\n "x": -11.123,\n\n "y": 18.23\n\n }\n\n }\n\n]') + res = "\n".join(f.readlines()) + self.assertEqual( + res, + 'f=json&features=[\n\n {\n\n "attributes": {\n\n "OBJECTID": 1,\n\n "name": "name1",\n\n "name2": "name2",\n\n "name3": "name3"\n\n },\n\n "geometry": {\n\n "x": 111.0,\n\n "y": 222.0\n\n }\n\n },\n\n {\n\n "attributes": {\n\n "OBJECTID": 2,\n\n "name": "bname1_x",\n\n "name2": "bname2",\n\n "name3": "bname3_x"\n\n },\n\n "geometry": {\n\n "x": -11.123,\n\n "y": 18.23\n\n }\n\n }\n\n]', + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_provider_gdal.py b/tests/src/python/test_provider_gdal.py index 88c473437aad..40c17ef9f77e 100644 --- a/tests/src/python/test_provider_gdal.py +++ b/tests/src/python/test_provider_gdal.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2018-30-10' -__copyright__ = 'Copyright 2018, Nyall Dawson' + +__author__ = "Nyall Dawson" +__date__ = "2018-30-10" +__copyright__ = "Copyright 2018, Nyall Dawson" import math import os @@ -32,7 +33,7 @@ def GDAL_COMPUTE_VERSION(maj, min, rev): - return ((maj) * 1000000 + (min) * 10000 + (rev) * 100) + return (maj) * 1000000 + (min) * 10000 + (rev) * 100 class PyQgsGdalProvider(QgisTestCase): @@ -46,23 +47,42 @@ def checkBlockContents(self, block, expected): def testRasterBlock(self): """Test raster block with extent""" - path = os.path.join(unitTestDataPath(), 'landsat_4326.tif') - raster_layer = QgsRasterLayer(path, 'test') + path = os.path.join(unitTestDataPath(), "landsat_4326.tif") + raster_layer = QgsRasterLayer(path, "test") self.assertTrue(raster_layer.isValid()) - extent = QgsRectangle(17.94284482577178252, 30.23021770271909503, 17.94407867909909626, 30.23154272264058307) + extent = QgsRectangle( + 17.94284482577178252, + 30.23021770271909503, + 17.94407867909909626, + 30.23154272264058307, + ) block = raster_layer.dataProvider().block(1, extent, 2, 3) - self.checkBlockContents(block, [ - 125.0, 125.0, - 125.0, 125.0, - 125.0, 124.0, - ]) + self.checkBlockContents( + block, + [ + 125.0, + 125.0, + 125.0, + 125.0, + 125.0, + 124.0, + ], + ) full_content = [ - 125.0, 125.0, 125.0, - 125.0, 125.0, 125.0, - 125.0, 124.0, 125.0, - 126.0, 127.0, 127.0, + 125.0, + 125.0, + 125.0, + 125.0, + 125.0, + 125.0, + 125.0, + 124.0, + 125.0, + 126.0, + 127.0, + 127.0, ] extent = raster_layer.extent() @@ -81,130 +101,260 @@ def testRasterBlock(self): extent.setYMaximum(extent.yMaximum() - row_height * row) extent.setYMinimum(extent.yMaximum() - row_height) block = raster_layer.dataProvider().block(1, extent, 3, 1) - self.checkBlockContents(block, full_content[row * 3:row * 3 + 3]) + self.checkBlockContents(block, full_content[row * 3 : row * 3 + 3]) def testDecodeEncodeUriGpkg(self): """Test decodeUri/encodeUri geopackage support""" - uri = '/my/raster.gpkg' - parts = QgsProviderRegistry.instance().decodeUri('gdal', uri) - self.assertEqual(parts, {'path': '/my/raster.gpkg', 'layerName': None}) - encodedUri = QgsProviderRegistry.instance().encodeUri('gdal', parts) + uri = "/my/raster.gpkg" + parts = QgsProviderRegistry.instance().decodeUri("gdal", uri) + self.assertEqual(parts, {"path": "/my/raster.gpkg", "layerName": None}) + encodedUri = QgsProviderRegistry.instance().encodeUri("gdal", parts) self.assertEqual(encodedUri, uri) - uri = 'GPKG:/my/raster.gpkg' - parts = QgsProviderRegistry.instance().decodeUri('gdal', uri) - self.assertEqual(parts, {'path': '/my/raster.gpkg', 'layerName': None}) - encodedUri = QgsProviderRegistry.instance().encodeUri('gdal', parts) - self.assertEqual(encodedUri, '/my/raster.gpkg') + uri = "GPKG:/my/raster.gpkg" + parts = QgsProviderRegistry.instance().decodeUri("gdal", uri) + self.assertEqual(parts, {"path": "/my/raster.gpkg", "layerName": None}) + encodedUri = QgsProviderRegistry.instance().encodeUri("gdal", parts) + self.assertEqual(encodedUri, "/my/raster.gpkg") - uri = 'GPKG:/my/raster.gpkg:mylayer' - parts = QgsProviderRegistry.instance().decodeUri('gdal', uri) - self.assertEqual(parts, {'path': '/my/raster.gpkg', 'layerName': 'mylayer'}) - encodedUri = QgsProviderRegistry.instance().encodeUri('gdal', parts) + uri = "GPKG:/my/raster.gpkg:mylayer" + parts = QgsProviderRegistry.instance().decodeUri("gdal", uri) + self.assertEqual(parts, {"path": "/my/raster.gpkg", "layerName": "mylayer"}) + encodedUri = QgsProviderRegistry.instance().encodeUri("gdal", parts) self.assertEqual(encodedUri, uri) def testDecodeEncodeUriOptions(self): """Test decodeUri/encodeUri options support""" - uri = '/my/raster.pdf|option:DPI=300|option:GIVEME=TWO' - parts = QgsProviderRegistry.instance().decodeUri('gdal', uri) - self.assertEqual(parts, {'path': '/my/raster.pdf', 'layerName': None, 'openOptions': ['DPI=300', 'GIVEME=TWO']}) - encodedUri = QgsProviderRegistry.instance().encodeUri('gdal', parts) + uri = "/my/raster.pdf|option:DPI=300|option:GIVEME=TWO" + parts = QgsProviderRegistry.instance().decodeUri("gdal", uri) + self.assertEqual( + parts, + { + "path": "/my/raster.pdf", + "layerName": None, + "openOptions": ["DPI=300", "GIVEME=TWO"], + }, + ) + encodedUri = QgsProviderRegistry.instance().encodeUri("gdal", parts) self.assertEqual(encodedUri, uri) def testDecodeEncodeUriCredentialOptions(self): """Test decodeUri/encodeUri credential options support""" - uri = '/my/raster.pdf|option:AN=OPTION|credential:ANOTHER=BBB|credential:SOMEKEY=AAAAA' - parts = QgsProviderRegistry.instance().decodeUri('gdal', uri) - self.assertEqual(parts, { - 'path': '/my/raster.pdf', - 'layerName': None, - 'credentialOptions': { - 'ANOTHER': 'BBB', - 'SOMEKEY': 'AAAAA' + uri = "/my/raster.pdf|option:AN=OPTION|credential:ANOTHER=BBB|credential:SOMEKEY=AAAAA" + parts = QgsProviderRegistry.instance().decodeUri("gdal", uri) + self.assertEqual( + parts, + { + "path": "/my/raster.pdf", + "layerName": None, + "credentialOptions": {"ANOTHER": "BBB", "SOMEKEY": "AAAAA"}, + "openOptions": ["AN=OPTION"], }, - 'openOptions': ['AN=OPTION'] - }) - encodedUri = QgsProviderRegistry.instance().encodeUri('gdal', parts) + ) + encodedUri = QgsProviderRegistry.instance().encodeUri("gdal", parts) self.assertEqual(encodedUri, uri) def testDecodeEncodeUriVsizip(self): """Test decodeUri/encodeUri for /vsizip/ prefixed URIs""" - uri = '/vsizip//my/file.zip/image.tif' - parts = QgsProviderRegistry.instance().decodeUri('gdal', uri) - self.assertEqual(parts, {'path': '/my/file.zip', 'layerName': None, 'vsiPrefix': '/vsizip/', - 'vsiSuffix': '/image.tif'}) - encodedUri = QgsProviderRegistry.instance().encodeUri('gdal', parts) + uri = "/vsizip//my/file.zip/image.tif" + parts = QgsProviderRegistry.instance().decodeUri("gdal", uri) + self.assertEqual( + parts, + { + "path": "/my/file.zip", + "layerName": None, + "vsiPrefix": "/vsizip/", + "vsiSuffix": "/image.tif", + }, + ) + encodedUri = QgsProviderRegistry.instance().encodeUri("gdal", parts) self.assertEqual(encodedUri, uri) def test_provider_sidecar_files_for_uri(self): """ Test retrieving sidecar files for uris """ - metadata = QgsProviderRegistry.instance().providerMetadata('gdal') - - self.assertEqual(metadata.sidecarFilesForUri(''), []) - self.assertEqual(metadata.sidecarFilesForUri('/home/me/some_file.asc'), - ['/home/me/some_file.aux.xml', '/home/me/some_file.asc.aux.xml', '/home/me/some_file.vat.dbf', - '/home/me/some_file.asc.vat.dbf', '/home/me/some_file.ovr', '/home/me/some_file.asc.ovr', - '/home/me/some_file.wld', '/home/me/some_file.asc.wld']) - self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.jpg'), - ['/home/me/special.jpw', '/home/me/special.jgw', '/home/me/special.jpgw', - '/home/me/special.jpegw', '/home/me/special.aux.xml', '/home/me/special.jpg.aux.xml', - '/home/me/special.vat.dbf', '/home/me/special.jpg.vat.dbf', '/home/me/special.ovr', - '/home/me/special.jpg.ovr', '/home/me/special.wld', '/home/me/special.jpg.wld']) - self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.img'), - ['/home/me/special.ige', '/home/me/special.aux.xml', '/home/me/special.img.aux.xml', - '/home/me/special.vat.dbf', '/home/me/special.img.vat.dbf', '/home/me/special.ovr', - '/home/me/special.img.ovr', '/home/me/special.wld', '/home/me/special.img.wld']) - self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.sid'), - ['/home/me/special.j2w', '/home/me/special.aux.xml', '/home/me/special.sid.aux.xml', - '/home/me/special.vat.dbf', '/home/me/special.sid.vat.dbf', '/home/me/special.ovr', - '/home/me/special.sid.ovr', '/home/me/special.wld', '/home/me/special.sid.wld']) - self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.tif'), - ['/home/me/special.tifw', '/home/me/special.tfw', '/home/me/special.aux.xml', - '/home/me/special.tif.aux.xml', '/home/me/special.vat.dbf', '/home/me/special.tif.vat.dbf', - '/home/me/special.ovr', '/home/me/special.tif.ovr', '/home/me/special.wld', - '/home/me/special.tif.wld']) - self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.bil'), - ['/home/me/special.bilw', '/home/me/special.blw', '/home/me/special.aux.xml', - '/home/me/special.bil.aux.xml', '/home/me/special.vat.dbf', '/home/me/special.bil.vat.dbf', - '/home/me/special.ovr', '/home/me/special.bil.ovr', '/home/me/special.wld', - '/home/me/special.bil.wld']) - self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.raster'), - ['/home/me/special.rasterw', '/home/me/special.aux.xml', '/home/me/special.raster.aux.xml', - '/home/me/special.vat.dbf', '/home/me/special.raster.vat.dbf', '/home/me/special.ovr', - '/home/me/special.raster.ovr', '/home/me/special.wld', '/home/me/special.raster.wld']) - self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.bt'), - ['/home/me/special.btw', '/home/me/special.aux.xml', '/home/me/special.bt.aux.xml', - '/home/me/special.vat.dbf', '/home/me/special.bt.vat.dbf', '/home/me/special.ovr', - '/home/me/special.bt.ovr', '/home/me/special.wld', '/home/me/special.bt.wld']) - self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.rst'), - ['/home/me/special.rdc', '/home/me/special.smp', '/home/me/special.ref', - '/home/me/special.vct', '/home/me/special.vdc', '/home/me/special.avl', - '/home/me/special.aux.xml', '/home/me/special.rst.aux.xml', '/home/me/special.vat.dbf', - '/home/me/special.rst.vat.dbf', '/home/me/special.ovr', '/home/me/special.rst.ovr', - '/home/me/special.wld', '/home/me/special.rst.wld']) - self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.sdat'), - ['/home/me/special.sgrd', '/home/me/special.mgrd', '/home/me/special.prj', - '/home/me/special.aux.xml', '/home/me/special.sdat.aux.xml', '/home/me/special.vat.dbf', - '/home/me/special.sdat.vat.dbf', '/home/me/special.ovr', '/home/me/special.sdat.ovr', - '/home/me/special.wld', '/home/me/special.sdat.wld']) - - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 5, 0), "GDAL 3.5.0 required") + metadata = QgsProviderRegistry.instance().providerMetadata("gdal") + + self.assertEqual(metadata.sidecarFilesForUri(""), []) + self.assertEqual( + metadata.sidecarFilesForUri("/home/me/some_file.asc"), + [ + "/home/me/some_file.aux.xml", + "/home/me/some_file.asc.aux.xml", + "/home/me/some_file.vat.dbf", + "/home/me/some_file.asc.vat.dbf", + "/home/me/some_file.ovr", + "/home/me/some_file.asc.ovr", + "/home/me/some_file.wld", + "/home/me/some_file.asc.wld", + ], + ) + self.assertEqual( + metadata.sidecarFilesForUri("/home/me/special.jpg"), + [ + "/home/me/special.jpw", + "/home/me/special.jgw", + "/home/me/special.jpgw", + "/home/me/special.jpegw", + "/home/me/special.aux.xml", + "/home/me/special.jpg.aux.xml", + "/home/me/special.vat.dbf", + "/home/me/special.jpg.vat.dbf", + "/home/me/special.ovr", + "/home/me/special.jpg.ovr", + "/home/me/special.wld", + "/home/me/special.jpg.wld", + ], + ) + self.assertEqual( + metadata.sidecarFilesForUri("/home/me/special.img"), + [ + "/home/me/special.ige", + "/home/me/special.aux.xml", + "/home/me/special.img.aux.xml", + "/home/me/special.vat.dbf", + "/home/me/special.img.vat.dbf", + "/home/me/special.ovr", + "/home/me/special.img.ovr", + "/home/me/special.wld", + "/home/me/special.img.wld", + ], + ) + self.assertEqual( + metadata.sidecarFilesForUri("/home/me/special.sid"), + [ + "/home/me/special.j2w", + "/home/me/special.aux.xml", + "/home/me/special.sid.aux.xml", + "/home/me/special.vat.dbf", + "/home/me/special.sid.vat.dbf", + "/home/me/special.ovr", + "/home/me/special.sid.ovr", + "/home/me/special.wld", + "/home/me/special.sid.wld", + ], + ) + self.assertEqual( + metadata.sidecarFilesForUri("/home/me/special.tif"), + [ + "/home/me/special.tifw", + "/home/me/special.tfw", + "/home/me/special.aux.xml", + "/home/me/special.tif.aux.xml", + "/home/me/special.vat.dbf", + "/home/me/special.tif.vat.dbf", + "/home/me/special.ovr", + "/home/me/special.tif.ovr", + "/home/me/special.wld", + "/home/me/special.tif.wld", + ], + ) + self.assertEqual( + metadata.sidecarFilesForUri("/home/me/special.bil"), + [ + "/home/me/special.bilw", + "/home/me/special.blw", + "/home/me/special.aux.xml", + "/home/me/special.bil.aux.xml", + "/home/me/special.vat.dbf", + "/home/me/special.bil.vat.dbf", + "/home/me/special.ovr", + "/home/me/special.bil.ovr", + "/home/me/special.wld", + "/home/me/special.bil.wld", + ], + ) + self.assertEqual( + metadata.sidecarFilesForUri("/home/me/special.raster"), + [ + "/home/me/special.rasterw", + "/home/me/special.aux.xml", + "/home/me/special.raster.aux.xml", + "/home/me/special.vat.dbf", + "/home/me/special.raster.vat.dbf", + "/home/me/special.ovr", + "/home/me/special.raster.ovr", + "/home/me/special.wld", + "/home/me/special.raster.wld", + ], + ) + self.assertEqual( + metadata.sidecarFilesForUri("/home/me/special.bt"), + [ + "/home/me/special.btw", + "/home/me/special.aux.xml", + "/home/me/special.bt.aux.xml", + "/home/me/special.vat.dbf", + "/home/me/special.bt.vat.dbf", + "/home/me/special.ovr", + "/home/me/special.bt.ovr", + "/home/me/special.wld", + "/home/me/special.bt.wld", + ], + ) + self.assertEqual( + metadata.sidecarFilesForUri("/home/me/special.rst"), + [ + "/home/me/special.rdc", + "/home/me/special.smp", + "/home/me/special.ref", + "/home/me/special.vct", + "/home/me/special.vdc", + "/home/me/special.avl", + "/home/me/special.aux.xml", + "/home/me/special.rst.aux.xml", + "/home/me/special.vat.dbf", + "/home/me/special.rst.vat.dbf", + "/home/me/special.ovr", + "/home/me/special.rst.ovr", + "/home/me/special.wld", + "/home/me/special.rst.wld", + ], + ) + self.assertEqual( + metadata.sidecarFilesForUri("/home/me/special.sdat"), + [ + "/home/me/special.sgrd", + "/home/me/special.mgrd", + "/home/me/special.prj", + "/home/me/special.aux.xml", + "/home/me/special.sdat.aux.xml", + "/home/me/special.vat.dbf", + "/home/me/special.sdat.vat.dbf", + "/home/me/special.ovr", + "/home/me/special.sdat.ovr", + "/home/me/special.wld", + "/home/me/special.sdat.wld", + ], + ) + + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 5, 0), + "GDAL 3.5.0 required", + ) def testInt64(self): """Test Int64 support""" tmp_dir = QTemporaryDir() - tmpfile = os.path.join(tmp_dir.path(), 'testInt64.tif') - ds = gdal.GetDriverByName('GTiff').Create(tmpfile, 2, 2, 1, gdal.GDT_Int64) - ds.WriteRaster(0, 0, 2, 2, struct.pack('q' * 4, -1234567890123, 1234567890123, -(1 << 63), (1 << 63) - 1)) + tmpfile = os.path.join(tmp_dir.path(), "testInt64.tif") + ds = gdal.GetDriverByName("GTiff").Create(tmpfile, 2, 2, 1, gdal.GDT_Int64) + ds.WriteRaster( + 0, + 0, + 2, + 2, + struct.pack( + "q" * 4, -1234567890123, 1234567890123, -(1 << 63), (1 << 63) - 1 + ), + ) ds = None - raster_layer = QgsRasterLayer(tmpfile, 'test') + raster_layer = QgsRasterLayer(tmpfile, "test") self.assertTrue(raster_layer.isValid()) self.assertEqual(raster_layer.dataProvider().dataType(1), Qgis.DataType.Float64) @@ -212,7 +362,10 @@ def testInt64(self): block = raster_layer.dataProvider().block(1, extent, 2, 2) full_content = [ - -1234567890123, 1234567890123, float(-(1 << 63)), float((1 << 63) - 1) + -1234567890123, + 1234567890123, + float(-(1 << 63)), + float((1 << 63) - 1), ] self.checkBlockContents(block, full_content) @@ -230,28 +383,33 @@ def testInt64(self): pos = QgsPointXY(1, -1) value_sample = raster_layer.dataProvider().sample(pos, 1)[0] - self.assertTrue(math.isnan(value_sample)) # (1 << 63) - 1 not exactly representable as double - - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 5, 0), "GDAL 3.5.0 required") + self.assertTrue( + math.isnan(value_sample) + ) # (1 << 63) - 1 not exactly representable as double + + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 5, 0), + "GDAL 3.5.0 required", + ) def testUInt64(self): """Test Int64 support""" tmp_dir = QTemporaryDir() - tmpfile = os.path.join(tmp_dir.path(), 'testUInt64.tif') - ds = gdal.GetDriverByName('GTiff').Create(tmpfile, 2, 2, 1, gdal.GDT_UInt64) - ds.WriteRaster(0, 0, 2, 2, struct.pack('Q' * 4, 1, 1234567890123, 0, (1 << 64) - 1)) + tmpfile = os.path.join(tmp_dir.path(), "testUInt64.tif") + ds = gdal.GetDriverByName("GTiff").Create(tmpfile, 2, 2, 1, gdal.GDT_UInt64) + ds.WriteRaster( + 0, 0, 2, 2, struct.pack("Q" * 4, 1, 1234567890123, 0, (1 << 64) - 1) + ) ds = None - raster_layer = QgsRasterLayer(tmpfile, 'test') + raster_layer = QgsRasterLayer(tmpfile, "test") self.assertTrue(raster_layer.isValid()) self.assertEqual(raster_layer.dataProvider().dataType(1), Qgis.DataType.Float64) extent = raster_layer.extent() block = raster_layer.dataProvider().block(1, extent, 2, 2) - full_content = [ - 1, 1234567890123, 0, float((1 << 64) - 1) - ] + full_content = [1, 1234567890123, 0, float((1 << 64) - 1)] self.checkBlockContents(block, full_content) pos = QgsPointXY(0, 0) @@ -270,37 +428,44 @@ def testUInt64(self): value_sample = raster_layer.dataProvider().sample(pos, 1)[0] self.assertTrue(math.isnan(value_sample)) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 2, 0) or int(gdal.VersionInfo('VERSION_NUM')) >= GDAL_COMPUTE_VERSION(3, 5, 2), "Test only relevant on GDAL >= 3.2.0 and < 3.5.2") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 2, 0) + or int(gdal.VersionInfo("VERSION_NUM")) >= GDAL_COMPUTE_VERSION(3, 5, 2), + "Test only relevant on GDAL >= 3.2.0 and < 3.5.2", + ) def testSanitizeVRT(self): - """Test qgsgdalprovider.cpp sanitizeVRTFile() / workaround for https://github.com/qgis/QGIS/issues/49285 """ + """Test qgsgdalprovider.cpp sanitizeVRTFile() / workaround for https://github.com/qgis/QGIS/issues/49285""" tmp_dir = QTemporaryDir() - tmpfilename = os.path.join(tmp_dir.path(), 'tmp.tif') - path = os.path.join(unitTestDataPath(), 'landsat_4326.tif') - tmp_ds = gdal.Translate(tmpfilename, path, options='-outsize 1024 0') - tmp_ds.BuildOverviews('NEAR', [2]) + tmpfilename = os.path.join(tmp_dir.path(), "tmp.tif") + path = os.path.join(unitTestDataPath(), "landsat_4326.tif") + tmp_ds = gdal.Translate(tmpfilename, path, options="-outsize 1024 0") + tmp_ds.BuildOverviews("NEAR", [2]) tmp_ds = None - vrtfilename = os.path.join(tmp_dir.path(), 'out.vrt') + vrtfilename = os.path.join(tmp_dir.path(), "out.vrt") ds = gdal.BuildVRT(vrtfilename, [tmpfilename]) ds = None - self.assertIn('OverviewList', open(vrtfilename).read()) + self.assertIn("OverviewList", open(vrtfilename).read()) - raster_layer = QgsRasterLayer(vrtfilename, 'test') + raster_layer = QgsRasterLayer(vrtfilename, "test") del raster_layer - self.assertNotIn('OverviewList', open(vrtfilename).read()) + self.assertNotIn("OverviewList", open(vrtfilename).read()) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7.0 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0), + "GDAL 3.7.0 required", + ) def testInt8(self): """Test Int8 support""" tmp_dir = QTemporaryDir() - tmpfile = os.path.join(tmp_dir.path(), 'testInt8.tif') - ds = gdal.GetDriverByName('GTiff').Create(tmpfile, 2, 2, 1, gdal.GDT_Int8) - ds.WriteRaster(0, 0, 2, 2, struct.pack('b' * 4, 1, 127, 0, -128)) + tmpfile = os.path.join(tmp_dir.path(), "testInt8.tif") + ds = gdal.GetDriverByName("GTiff").Create(tmpfile, 2, 2, 1, gdal.GDT_Int8) + ds.WriteRaster(0, 0, 2, 2, struct.pack("b" * 4, 1, 127, 0, -128)) ds = None - raster_layer = QgsRasterLayer(tmpfile, 'test') + raster_layer = QgsRasterLayer(tmpfile, "test") self.assertTrue(raster_layer.isValid()) self.assertEqual(raster_layer.dataProvider().dataType(1), Qgis.DataType.Int8) @@ -326,41 +491,48 @@ def testInt8(self): value_sample = raster_layer.dataProvider().sample(pos, 1)[0] self.assertEqual(value_sample, full_content[3]) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7.0 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0), + "GDAL 3.7.0 required", + ) def testGdbMetadata(self): """Test reading GDB layer metadata""" - path = os.path.join(unitTestDataPath(), 'raster_metadata.gdb') - rl = QgsRasterLayer(f'OpenFileGDB:{path}:int', 'gdb', 'gdal') + path = os.path.join(unitTestDataPath(), "raster_metadata.gdb") + rl = QgsRasterLayer(f"OpenFileGDB:{path}:int", "gdb", "gdal") self.assertTrue(rl.isValid()) - self.assertEqual(rl.metadata().identifier(), 'int') - self.assertEqual(rl.metadata().title(), 'Raster title') - self.assertEqual(rl.metadata().type(), 'dataset') - self.assertEqual(rl.metadata().abstract(), 'My description (abstract)\n\nmy raster summary') + self.assertEqual(rl.metadata().identifier(), "int") + self.assertEqual(rl.metadata().title(), "Raster title") + self.assertEqual(rl.metadata().type(), "dataset") + self.assertEqual( + rl.metadata().abstract(), "My description (abstract)\n\nmy raster summary" + ) def testBandDescription(self): """Test band description getter""" tmp_dir = QTemporaryDir() - tmpfile = os.path.join(tmp_dir.path(), 'testInt8.tif') - ds = gdal.GetDriverByName('GTiff').Create(tmpfile, 2, 2, 1, gdal.GDT_Byte) - ds.WriteRaster(0, 0, 2, 2, struct.pack('b' * 4, 1, 127, 0, -128)) + tmpfile = os.path.join(tmp_dir.path(), "testInt8.tif") + ds = gdal.GetDriverByName("GTiff").Create(tmpfile, 2, 2, 1, gdal.GDT_Byte) + ds.WriteRaster(0, 0, 2, 2, struct.pack("b" * 4, 1, 127, 0, -128)) band = ds.GetRasterBand(1) - band.SetDescription('my description') + band.SetDescription("my description") ds.FlushCache() ds = None rl = QgsRasterLayer(tmpfile) - self.assertEqual(rl.dataProvider().bandDescription(1), 'my description') + self.assertEqual(rl.dataProvider().bandDescription(1), "my description") ds = gdal.OpenEx(tmpfile) band = ds.GetRasterBand(1) - band.SetMetadataItem('DESCRIPTION', 'my metadata description') + band.SetMetadataItem("DESCRIPTION", "my metadata description") ds.FlushCache() ds = None rl = QgsRasterLayer(tmpfile) - self.assertEqual(rl.dataProvider().bandDescription(1), 'my metadata description') + self.assertEqual( + rl.dataProvider().bandDescription(1), "my metadata description" + ) def testDisplayBandNameBadLayer(self): """Test crash from issue GH #54702""" @@ -368,10 +540,10 @@ def testDisplayBandNameBadLayer(self): rl = QgsRasterLayer("https://FAKESERVER/ImageServer/WCSServer", "BadWCS", "wcs") self.assertFalse(rl.isValid()) # This was triggering a std::bad_alloc exception: - self.assertEqual(rl.dataProvider().displayBandName(1), 'Band 1') + self.assertEqual(rl.dataProvider().displayBandName(1), "Band 1") # This was triggering another crash: - self.assertEqual(rl.dataProvider().colorInterpretationName(1), 'Undefined') + self.assertEqual(rl.dataProvider().colorInterpretationName(1), "Undefined") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_provider_gpx.py b/tests/src/python/test_provider_gpx.py index cad0a3cbc390..a765627343a2 100644 --- a/tests/src/python/test_provider_gpx.py +++ b/tests/src/python/test_provider_gpx.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2021-07-30' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2021-07-30" +__copyright__ = "Copyright 2021, The QGIS Project" import os @@ -36,138 +37,138 @@ class TestPyQgsGpxProvider(QgisTestCase, ProviderTestCase): @classmethod def createLayer(cls): vl = QgsVectorLayer( - f'{unitTestDataPath()}/gpx_test_suite.gpx?type=waypoint', - 'test', 'gpx') - assert (vl.isValid()) + f"{unitTestDataPath()}/gpx_test_suite.gpx?type=waypoint", "test", "gpx" + ) + assert vl.isValid() return vl @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsGpxProvider, cls).setUpClass() + super().setUpClass() # Create test layer cls.vl = cls.createLayer() - assert (cls.vl.isValid()) + assert cls.vl.isValid() cls.source = cls.vl.dataProvider() @property def pk_name(self): """Return the primary key name, override if different than the default 'pk'""" - return 'comment' + return "comment" - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testGetFeatures(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testGetFeaturesDestinationCrs(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testGetFeaturesCoordinateTransform(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testGetFeaturesLimit(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testGetFeaturesSubsetAttributes(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testGetFeaturesWithGeometry(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testOrderBy(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testRectAndFids(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testCloneLayer(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testExtent(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testFeatureCount(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testGetFeaturesFilterRectTests(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testGetFeaturesFilterRectTestsNoGeomFlag(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testGetFeaturesDistanceWithinTests(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testFields(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testGeomAndAllAttributes(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testGetFeaturesFidTests(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testGetFeaturesFidsTests(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testGetFeaturesSubsetAttributes2(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testGetFeaturesUncompiled(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testMaxValue(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testMaximumValue(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testMinValue(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testMinimumValue(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testRectAndExpression(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testStringComparison(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testUnique(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testUniqueStringsMatching(self): pass - @unittest.skip('Base provider test is not suitable for GPX provider') + @unittest.skip("Base provider test is not suitable for GPX provider") def testUniqueValues(self): pass @@ -175,7 +176,7 @@ def test_invalid_source(self): """ Test various methods with an invalid source """ - vl = QgsVectorLayer('not a gpx?type=waypoint', 'test', 'gpx') + vl = QgsVectorLayer("not a gpx?type=waypoint", "test", "gpx") self.assertFalse(vl.isValid()) self.assertEqual(vl.featureCount(), -1) self.assertTrue(vl.extent().isNull()) @@ -187,52 +188,83 @@ def test_invalid_source(self): self.assertFalse(vl.dataProvider().deleteFeatures([1, 2])) - self.assertFalse(vl.dataProvider().changeAttributeValues({1: {1: 'a'}})) + self.assertFalse(vl.dataProvider().changeAttributeValues({1: {1: "a"}})) source = vl.dataProvider().featureSource() self.assertFalse(list(source.getFeatures())) def test_encode_decode_uri(self): - metadata = QgsProviderRegistry.instance().providerMetadata('gpx') + metadata = QgsProviderRegistry.instance().providerMetadata("gpx") self.assertIsNotNone(metadata) - self.assertEqual(metadata.encodeUri({}), '') - self.assertEqual(metadata.decodeUri(''), {}) - self.assertEqual(metadata.encodeUri({'path': '/home/me/test.gpx'}), '/home/me/test.gpx') - self.assertEqual(metadata.decodeUri('/home/me/test.gpx'), {'path': '/home/me/test.gpx'}) - self.assertEqual(metadata.encodeUri({'path': '/home/me/test.gpx', - 'layerName': 'waypoints'}), '/home/me/test.gpx?type=waypoints') - self.assertEqual(metadata.decodeUri('/home/me/test.gpx?type=waypoints'), {'path': '/home/me/test.gpx', - 'layerName': 'waypoints'}) - self.assertEqual(metadata.encodeUri({'path': '/home/me/test.gpx', - 'layerName': 'tracks'}), '/home/me/test.gpx?type=tracks') - self.assertEqual(metadata.decodeUri('/home/me/test.gpx?type=tracks'), {'path': '/home/me/test.gpx', - 'layerName': 'tracks'}) - self.assertEqual(metadata.encodeUri({'path': '/home/me/test.gpx', - 'layerName': 'routes'}), '/home/me/test.gpx?type=routes') - self.assertEqual(metadata.decodeUri('/home/me/test.gpx?type=routes'), {'path': '/home/me/test.gpx', - 'layerName': 'routes'}) + self.assertEqual(metadata.encodeUri({}), "") + self.assertEqual(metadata.decodeUri(""), {}) + self.assertEqual( + metadata.encodeUri({"path": "/home/me/test.gpx"}), "/home/me/test.gpx" + ) + self.assertEqual( + metadata.decodeUri("/home/me/test.gpx"), {"path": "/home/me/test.gpx"} + ) + self.assertEqual( + metadata.encodeUri({"path": "/home/me/test.gpx", "layerName": "waypoints"}), + "/home/me/test.gpx?type=waypoints", + ) + self.assertEqual( + metadata.decodeUri("/home/me/test.gpx?type=waypoints"), + {"path": "/home/me/test.gpx", "layerName": "waypoints"}, + ) + self.assertEqual( + metadata.encodeUri({"path": "/home/me/test.gpx", "layerName": "tracks"}), + "/home/me/test.gpx?type=tracks", + ) + self.assertEqual( + metadata.decodeUri("/home/me/test.gpx?type=tracks"), + {"path": "/home/me/test.gpx", "layerName": "tracks"}, + ) + self.assertEqual( + metadata.encodeUri({"path": "/home/me/test.gpx", "layerName": "routes"}), + "/home/me/test.gpx?type=routes", + ) + self.assertEqual( + metadata.decodeUri("/home/me/test.gpx?type=routes"), + {"path": "/home/me/test.gpx", "layerName": "routes"}, + ) def test_absolute_relative_uri(self): context = QgsReadWriteContext() - context.setPathResolver(QgsPathResolver(os.path.join(TEST_DATA_DIR, "project.qgs"))) + context.setPathResolver( + QgsPathResolver(os.path.join(TEST_DATA_DIR, "project.qgs")) + ) - absolute_uri = os.path.join(TEST_DATA_DIR, 'gpx_test_suite.gpx') + '?type=waypoint' - relative_uri = './gpx_test_suite.gpx?type=waypoint' + absolute_uri = ( + os.path.join(TEST_DATA_DIR, "gpx_test_suite.gpx") + "?type=waypoint" + ) + relative_uri = "./gpx_test_suite.gpx?type=waypoint" meta = QgsProviderRegistry.instance().providerMetadata("gpx") assert meta is not None - self.assertEqual(meta.absoluteToRelativeUri(absolute_uri, context), relative_uri) - self.assertEqual(meta.relativeToAbsoluteUri(relative_uri, context), absolute_uri) + self.assertEqual( + meta.absoluteToRelativeUri(absolute_uri, context), relative_uri + ) + self.assertEqual( + meta.relativeToAbsoluteUri(relative_uri, context), absolute_uri + ) def test_waypoint_layer(self): - vl = QgsVectorLayer(f'{unitTestDataPath()}/gpx_test_suite.gpx' + "?type=waypoint", 'test2', 'gpx') + vl = QgsVectorLayer( + f"{unitTestDataPath()}/gpx_test_suite.gpx" + "?type=waypoint", + "test2", + "gpx", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.fields().field("time").type(), QVariant.DateTime) values = [f["time"] for f in vl.getFeatures()] - self.assertEqual(values[0], QDateTime(QDate(2023, 4, 25), QTime(9, 52, 14, 0), Qt.TimeSpec(1))) + self.assertEqual( + values[0], + QDateTime(QDate(2023, 4, 25), QTime(9, 52, 14, 0), Qt.TimeSpec(1)), + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_provider_hana.py b/tests/src/python/test_provider_hana.py index db77e43b3890..d93d22f12e03 100644 --- a/tests/src/python/test_provider_hana.py +++ b/tests/src/python/test_provider_hana.py @@ -11,9 +11,9 @@ """ -__author__ = 'Maxim Rylov' -__date__ = '2019-11-21' -__copyright__ = 'Copyright 2019, The QGIS Project' +__author__ = "Maxim Rylov" +__date__ = "2019-11-21" +__copyright__ = "Copyright 2019, The QGIS Project" import os @@ -52,28 +52,35 @@ class TestPyQgsHanaProvider(QgisTestCase, ProviderTestCase): # HANA connection object conn = None # Name of the schema - schemaName = '' + schemaName = "" @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsHanaProvider, cls).setUpClass() - cls.uri = 'driver=\'/usr/sap/hdbclient/libodbcHDB.so\' host=localhost port=30015 user=SYSTEM ' \ - 'password=mypassword sslEnabled=true sslValidateCertificate=False' - if 'QGIS_HANA_TEST_DB' in os.environ: - cls.uri = os.environ['QGIS_HANA_TEST_DB'] + super().setUpClass() + cls.uri = ( + "driver='/usr/sap/hdbclient/libodbcHDB.so' host=localhost port=30015 user=SYSTEM " + "password=mypassword sslEnabled=true sslValidateCertificate=False" + ) + if "QGIS_HANA_TEST_DB" in os.environ: + cls.uri = os.environ["QGIS_HANA_TEST_DB"] cls.conn = QgsHanaProviderUtils.createConnection(cls.uri) - cls.schemaName = QgsHanaProviderUtils.generateSchemaName(cls.conn, 'qgis_test') + cls.schemaName = QgsHanaProviderUtils.generateSchemaName(cls.conn, "qgis_test") QgsHanaProviderUtils.createAndFillDefaultTables(cls.conn, cls.schemaName) # Create test layers cls.vl = QgsHanaProviderUtils.createVectorLayer( - cls.uri + f' key=\'pk\' srid=4326 type=POINT table="{cls.schemaName}"."some_data" (geom) sql=', 'test') + cls.uri + + f' key=\'pk\' srid=4326 type=POINT table="{cls.schemaName}"."some_data" (geom) sql=', + "test", + ) cls.source = cls.vl.dataProvider() cls.poly_vl = QgsHanaProviderUtils.createVectorLayer( - cls.uri + f' key=\'pk\' srid=4326 type=POLYGON table="{cls.schemaName}"."some_poly_data" (geom) sql=', - 'test') + cls.uri + + f' key=\'pk\' srid=4326 type=POLYGON table="{cls.schemaName}"."some_poly_data" (geom) sql=', + "test", + ) cls.poly_provider = cls.poly_vl.dataProvider() @classmethod @@ -82,111 +89,161 @@ def tearDownClass(cls): QgsHanaProviderUtils.cleanUp(cls.conn, cls.schemaName) cls.conn.close() - super(TestPyQgsHanaProvider, cls).tearDownClass() + super().tearDownClass() def createVectorLayer(self, conn_parameters, layer_name): - layer = QgsHanaProviderUtils.createVectorLayer(self.uri + ' ' + conn_parameters, layer_name) + layer = QgsHanaProviderUtils.createVectorLayer( + self.uri + " " + conn_parameters, layer_name + ) self.assertTrue(layer.isValid()) return layer def prepareTestTable(self, table_name, create_sql, insert_sql, insert_args): - res = QgsHanaProviderUtils.executeSQLFetchOne(self.conn, - f"SELECT COUNT(*) FROM SYS.TABLES WHERE " - f"SCHEMA_NAME='{self.schemaName}' AND TABLE_NAME='{table_name}'") + res = QgsHanaProviderUtils.executeSQLFetchOne( + self.conn, + f"SELECT COUNT(*) FROM SYS.TABLES WHERE " + f"SCHEMA_NAME='{self.schemaName}' AND TABLE_NAME='{table_name}'", + ) if res != 0: - QgsHanaProviderUtils.executeSQL(self.conn, f'DROP TABLE "{self.schemaName}"."{table_name}" CASCADE') - QgsHanaProviderUtils.createAndFillTable(self.conn, create_sql, insert_sql, insert_args) + QgsHanaProviderUtils.executeSQL( + self.conn, f'DROP TABLE "{self.schemaName}"."{table_name}" CASCADE' + ) + QgsHanaProviderUtils.createAndFillTable( + self.conn, create_sql, insert_sql, insert_args + ) def getSource(self): # create temporary table for edit tests - create_sql = f'CREATE TABLE "{self.schemaName}"."edit_data" ( ' \ - '"pk" INTEGER NOT NULL PRIMARY KEY,' \ - '"cnt" INTEGER,' \ - '"name" NVARCHAR(100), ' \ - '"name2" NVARCHAR(100), ' \ - '"num_char" NVARCHAR(100),' \ - '"dt" TIMESTAMP,' \ - '"date" DATE,' \ - '"time" TIME,' \ + create_sql = ( + f'CREATE TABLE "{self.schemaName}"."edit_data" ( ' + '"pk" INTEGER NOT NULL PRIMARY KEY,' + '"cnt" INTEGER,' + '"name" NVARCHAR(100), ' + '"name2" NVARCHAR(100), ' + '"num_char" NVARCHAR(100),' + '"dt" TIMESTAMP,' + '"date" DATE,' + '"time" TIME,' '"geom" ST_POINT(4326))' - insert_sql = f'INSERT INTO "{self.schemaName}"."edit_data" ("pk", "cnt", "name", "name2", "num_char", "dt", "date", ' \ + ) + insert_sql = ( + f'INSERT INTO "{self.schemaName}"."edit_data" ("pk", "cnt", "name", "name2", "num_char", "dt", "date", ' '"time", "geom") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ST_GeomFromEWKB(?)) ' + ) insert_args = [ - [5, -200, None, 'NuLl', '5', '2020-05-04 12:13:14', '2020-05-02', '12:13:01', - bytes.fromhex('0101000020E61000001D5A643BDFC751C01F85EB51B88E5340')], - [3, 300, 'Pear', 'PEaR', '3', None, None, None, None], - [1, 100, 'Orange', 'oranGe', '1', '2020-05-03 12:13:14', '2020-05-03', '12:13:14', - bytes.fromhex('0101000020E61000006891ED7C3F9551C085EB51B81E955040')], - [2, 200, 'Apple', 'Apple', '2', '2020-05-04 12:14:14', '2020-05-04', '12:14:14', - bytes.fromhex('0101000020E6100000CDCCCCCCCC0C51C03333333333B35140')], - [4, 400, 'Honey', 'Honey', '4', '2021-05-04 13:13:14', '2021-05-04', '13:13:14', - bytes.fromhex('0101000020E610000014AE47E17A5450C03333333333935340')]] - self.prepareTestTable('edit_data', create_sql, insert_sql, insert_args) + [ + 5, + -200, + None, + "NuLl", + "5", + "2020-05-04 12:13:14", + "2020-05-02", + "12:13:01", + bytes.fromhex("0101000020E61000001D5A643BDFC751C01F85EB51B88E5340"), + ], + [3, 300, "Pear", "PEaR", "3", None, None, None, None], + [ + 1, + 100, + "Orange", + "oranGe", + "1", + "2020-05-03 12:13:14", + "2020-05-03", + "12:13:14", + bytes.fromhex("0101000020E61000006891ED7C3F9551C085EB51B81E955040"), + ], + [ + 2, + 200, + "Apple", + "Apple", + "2", + "2020-05-04 12:14:14", + "2020-05-04", + "12:14:14", + bytes.fromhex("0101000020E6100000CDCCCCCCCC0C51C03333333333B35140"), + ], + [ + 4, + 400, + "Honey", + "Honey", + "4", + "2021-05-04 13:13:14", + "2021-05-04", + "13:13:14", + bytes.fromhex("0101000020E610000014AE47E17A5450C03333333333935340"), + ], + ] + self.prepareTestTable("edit_data", create_sql, insert_sql, insert_args) return self.createVectorLayer( f'key=\'pk\' srid=4326 type=POINT table="{self.schemaName}"."edit_data" (geom) sql=', - 'test') + "test", + ) def getEditableLayer(self): return self.getSource() def enableCompiler(self): - QgsSettings().setValue('/qgis/compileExpressions', True) + QgsSettings().setValue("/qgis/compileExpressions", True) return True def disableCompiler(self): - QgsSettings().setValue('/qgis/compileExpressions', False) + QgsSettings().setValue("/qgis/compileExpressions", False) def uncompiledFilters(self): filters = { - '(name = \'Apple\') is not null', - 'false and NULL', - 'true and NULL', - 'NULL and false', - 'NULL and true', - 'NULL and NULL', - 'false or NULL', - 'true or NULL', - 'NULL or false', - 'NULL or true', - 'NULL or NULL', - 'not null', - '\'x\' || "name" IS NOT NULL', - '\'x\' || "name" IS NULL', - 'radians(cnt) < 2', - 'degrees(pk) <= 200', - 'log10(pk) < 0.5', - 'x($geometry) < -70', - 'y($geometry) > 70', - 'xmin($geometry) < -70', - 'ymin($geometry) > 70', - 'xmax($geometry) < -70', - 'ymax($geometry) > 70', - 'disjoint($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', - 'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', - 'contains(geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'),$geometry)', - 'distance($geometry,geom_from_wkt( \'Point (-70 70)\')) > 7', - 'intersects($geometry,geom_from_gml( \'-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1\'))', - 'x($geometry) < -70', - 'y($geometry) > 79', - 'xmin($geometry) < -70', - 'ymin($geometry) < 76', - 'xmax($geometry) > -68', - 'ymax($geometry) > 80', - 'area($geometry) > 10', - 'perimeter($geometry) < 12', - 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\')) = \'FF2FF1212\'', - 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'), \'****F****\')', - 'crosses($geometry,geom_from_wkt( \'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)\'))', - 'overlaps($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'))', - 'within($geometry,geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - 'overlaps(translate($geometry,-1,-1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - 'overlaps(buffer($geometry,1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - 'intersects(centroid($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', - 'intersects(point_on_surface($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', - '"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')', - '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')', - '"time" = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')', + "(name = 'Apple') is not null", + "false and NULL", + "true and NULL", + "NULL and false", + "NULL and true", + "NULL and NULL", + "false or NULL", + "true or NULL", + "NULL or false", + "NULL or true", + "NULL or NULL", + "not null", + "'x' || \"name\" IS NOT NULL", + "'x' || \"name\" IS NULL", + "radians(cnt) < 2", + "degrees(pk) <= 200", + "log10(pk) < 0.5", + "x($geometry) < -70", + "y($geometry) > 70", + "xmin($geometry) < -70", + "ymin($geometry) > 70", + "xmax($geometry) < -70", + "ymax($geometry) > 70", + "disjoint($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))", + "intersects($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))", + "contains(geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'),$geometry)", + "distance($geometry,geom_from_wkt( 'Point (-70 70)')) > 7", + "intersects($geometry,geom_from_gml( '-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1'))", + "x($geometry) < -70", + "y($geometry) > 79", + "xmin($geometry) < -70", + "ymin($geometry) < 76", + "xmax($geometry) > -68", + "ymax($geometry) > 80", + "area($geometry) > 10", + "perimeter($geometry) < 12", + "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))')) = 'FF2FF1212'", + "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'), '****F****')", + "crosses($geometry,geom_from_wkt( 'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)'))", + "overlaps($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'))", + "within($geometry,geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + "overlaps(translate($geometry,-1,-1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + "overlaps(buffer($geometry,1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + "intersects(centroid($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))", + "intersects(point_on_surface($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))", + "\"dt\" = to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy')", + "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')", + "\"time\" = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')", } return filters @@ -197,76 +254,115 @@ def partiallyCompiledFilters(self): def testMetadata(self): metadata = self.vl.metadata() self.assertEqual(metadata.crs(), QgsCoordinateReferenceSystem.fromEpsgId(4326)) - self.assertEqual(metadata.type(), 'dataset') - self.assertEqual(metadata.abstract(), 'QGIS Test Table') + self.assertEqual(metadata.type(), "dataset") + self.assertEqual(metadata.abstract(), "QGIS Test Table") def testDefaultValue(self): - self.source.setProviderProperty(QgsDataProvider.ProviderProperty.EvaluateDefaultValues, True) + self.source.setProviderProperty( + QgsDataProvider.ProviderProperty.EvaluateDefaultValues, True + ) self.assertEqual(self.source.defaultValue(0), NULL) self.assertEqual(self.source.defaultValue(1), NULL) - self.assertEqual(self.source.defaultValue(2), 'qgis') - self.assertEqual(self.source.defaultValue(3), 'qgis') + self.assertEqual(self.source.defaultValue(2), "qgis") + self.assertEqual(self.source.defaultValue(3), "qgis") self.assertEqual(self.source.defaultValue(4), NULL) - self.source.setProviderProperty(QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False) + self.source.setProviderProperty( + QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False + ) def testCompositeUniqueConstraints(self): - create_sql = f'CREATE TABLE "{self.schemaName}"."unique_composite_constraints" ( ' \ - '"ID" INTEGER PRIMARY KEY,' \ - '"VAL1" INTEGER,' \ - '"VAL2" INTEGER,' \ - '"VAL3" INTEGER,' \ - 'UNIQUE (VAL1, VAL2))' + create_sql = ( + f'CREATE TABLE "{self.schemaName}"."unique_composite_constraints" ( ' + '"ID" INTEGER PRIMARY KEY,' + '"VAL1" INTEGER,' + '"VAL2" INTEGER,' + '"VAL3" INTEGER,' + "UNIQUE (VAL1, VAL2))" + ) QgsHanaProviderUtils.executeSQL(self.conn, create_sql) - vl = self.createVectorLayer(f'table="{self.schemaName}"."unique_composite_constraints" sql=', - 'testcompositeuniqueconstraints') + vl = self.createVectorLayer( + f'table="{self.schemaName}"."unique_composite_constraints" sql=', + "testcompositeuniqueconstraints", + ) fields = vl.dataProvider().fields() - id_field_idx = fields.indexFromName('ID') - val1_field_idx = vl.fields().indexFromName('VAL1') - val2_field_idx = vl.fields().indexFromName('VAL2') - val3_field_idx = vl.fields().indexFromName('VAL3') + id_field_idx = fields.indexFromName("ID") + val1_field_idx = vl.fields().indexFromName("VAL1") + val2_field_idx = vl.fields().indexFromName("VAL2") + val3_field_idx = vl.fields().indexFromName("VAL3") self.assertGreaterEqual(id_field_idx, 0) self.assertGreaterEqual(val1_field_idx, 0) self.assertGreaterEqual(val2_field_idx, 0) self.assertGreaterEqual(val3_field_idx, 0) - self.assertTrue(bool(vl.fieldConstraints(id_field_idx) & QgsFieldConstraints.Constraint.ConstraintUnique)) - self.assertFalse(bool(vl.fieldConstraints(val1_field_idx) & QgsFieldConstraints.Constraint.ConstraintUnique)) - self.assertFalse(bool(vl.fieldConstraints(val2_field_idx) & QgsFieldConstraints.Constraint.ConstraintUnique)) - self.assertFalse(bool(vl.fieldConstraints(val3_field_idx) & QgsFieldConstraints.Constraint.ConstraintUnique)) + self.assertTrue( + bool( + vl.fieldConstraints(id_field_idx) + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + ) + self.assertFalse( + bool( + vl.fieldConstraints(val1_field_idx) + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + ) + self.assertFalse( + bool( + vl.fieldConstraints(val2_field_idx) + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + ) + self.assertFalse( + bool( + vl.fieldConstraints(val3_field_idx) + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + ) def testQueryLayers(self): - def test_query(query, key, geometry, attribute_names, wkb_type=QgsWkbTypes.Type.NoGeometry): + def test_query( + query, key, geometry, attribute_names, wkb_type=QgsWkbTypes.Type.NoGeometry + ): uri = QgsDataSourceUri() uri.setSchema(self.schemaName) uri.setTable(query) uri.setKeyColumn(key) uri.setGeometryColumn(geometry) - vl = self.createVectorLayer(uri.uri(False), 'testquery') - - for capability in [QgsVectorDataProvider.Capability.SelectAtId, - QgsVectorDataProvider.Capability.TransactionSupport, - QgsVectorDataProvider.Capability.CircularGeometries, - QgsVectorDataProvider.Capability.ReadLayerMetadata]: + vl = self.createVectorLayer(uri.uri(False), "testquery") + + for capability in [ + QgsVectorDataProvider.Capability.SelectAtId, + QgsVectorDataProvider.Capability.TransactionSupport, + QgsVectorDataProvider.Capability.CircularGeometries, + QgsVectorDataProvider.Capability.ReadLayerMetadata, + ]: self.assertTrue(vl.dataProvider().capabilities() & capability) - for capability in [QgsVectorDataProvider.Capability.AddAttributes, - QgsVectorDataProvider.Capability.ChangeAttributeValues, - QgsVectorDataProvider.Capability.DeleteAttributes, - QgsVectorDataProvider.Capability.RenameAttributes, - QgsVectorDataProvider.Capability.AddFeatures, - QgsVectorDataProvider.Capability.ChangeFeatures, - QgsVectorDataProvider.Capability.DeleteFeatures, - QgsVectorDataProvider.Capability.ChangeGeometries, - QgsVectorDataProvider.Capability.FastTruncate]: + for capability in [ + QgsVectorDataProvider.Capability.AddAttributes, + QgsVectorDataProvider.Capability.ChangeAttributeValues, + QgsVectorDataProvider.Capability.DeleteAttributes, + QgsVectorDataProvider.Capability.RenameAttributes, + QgsVectorDataProvider.Capability.AddFeatures, + QgsVectorDataProvider.Capability.ChangeFeatures, + QgsVectorDataProvider.Capability.DeleteFeatures, + QgsVectorDataProvider.Capability.ChangeGeometries, + QgsVectorDataProvider.Capability.FastTruncate, + ]: self.assertFalse(vl.dataProvider().capabilities() & capability) fields = vl.dataProvider().fields() self.assertCountEqual(attribute_names, fields.names()) for field_idx in vl.primaryKeyAttributes(): self.assertIn(fields[field_idx].name(), key.split(",")) - self.assertEqual(len(vl.primaryKeyAttributes()) == 1, - bool(vl.fieldConstraints(field_idx) & QgsFieldConstraints.Constraint.ConstraintUnique)) + self.assertEqual( + len(vl.primaryKeyAttributes()) == 1, + bool( + vl.fieldConstraints(field_idx) + & QgsFieldConstraints.Constraint.ConstraintUnique + ), + ) if fields.count() > 0: if vl.featureCount() == 0: self.assertEqual(NULL, vl.maximumValue(0)) @@ -278,225 +374,326 @@ def test_query(query, key, geometry, attribute_names, wkb_type=QgsWkbTypes.Type. self.assertFalse(vl.addFeatures([QgsFeature()])) self.assertFalse(vl.deleteFeatures([0])) self.assertEqual(wkb_type, vl.wkbType()) - self.assertEqual(wkb_type == QgsWkbTypes.Type.NoGeometry or wkb_type == QgsWkbTypes.Type.Unknown, - vl.extent().isNull()) - - test_query('(SELECT * FROM DUMMY)', None, None, ['DUMMY'], QgsWkbTypes.Type.NoGeometry) - test_query('(SELECT CAST(NULL AS INT) ID1, CAST(NULL AS INT) ID2, CAST(NULL AS ST_GEOMETRY) SHAPE FROM DUMMY)', - 'ID1,ID2', None, ['ID1', 'ID2', 'SHAPE'], QgsWkbTypes.Type.NoGeometry) - test_query('(SELECT CAST(1 AS INT) ID1, CAST(NULL AS BIGINT) ID2 FROM DUMMY)', - 'ID1', None, ['ID1', 'ID2'], QgsWkbTypes.Type.NoGeometry) - test_query('(SELECT CAST(NULL AS INT) ID1, CAST(NULL AS INT) ID2, CAST(NULL AS ST_GEOMETRY) SHAPE FROM DUMMY)', - None, 'SHAPE', ['ID1', 'ID2'], QgsWkbTypes.Type.Unknown) - test_query('(SELECT CAST(NULL AS INT) ID1, CAST(NULL AS BIGINT) ID2, CAST(NULL AS ST_GEOMETRY) SHAPE FROM ' - 'DUMMY)', 'ID2', 'SHAPE', ['ID1', 'ID2'], QgsWkbTypes.Type.Unknown) - test_query('(SELECT CAST(NULL AS INT) ID1, CAST(NULL AS ST_GEOMETRY) SHAPE1, CAST(NULL AS ST_GEOMETRY) SHAPE2 ' - 'FROM DUMMY)', 'ID1', 'SHAPE1', ['ID1', 'SHAPE2'], QgsWkbTypes.Type.Unknown) - test_query(f'(SELECT "pk" AS "key", "cnt", "geom" AS "g" FROM "{self.schemaName}"."some_data")', - 'key', 'g', ['key', 'cnt'], QgsWkbTypes.Type.Point) + self.assertEqual( + wkb_type == QgsWkbTypes.Type.NoGeometry + or wkb_type == QgsWkbTypes.Type.Unknown, + vl.extent().isNull(), + ) + + test_query( + "(SELECT * FROM DUMMY)", None, None, ["DUMMY"], QgsWkbTypes.Type.NoGeometry + ) + test_query( + "(SELECT CAST(NULL AS INT) ID1, CAST(NULL AS INT) ID2, CAST(NULL AS ST_GEOMETRY) SHAPE FROM DUMMY)", + "ID1,ID2", + None, + ["ID1", "ID2", "SHAPE"], + QgsWkbTypes.Type.NoGeometry, + ) + test_query( + "(SELECT CAST(1 AS INT) ID1, CAST(NULL AS BIGINT) ID2 FROM DUMMY)", + "ID1", + None, + ["ID1", "ID2"], + QgsWkbTypes.Type.NoGeometry, + ) + test_query( + "(SELECT CAST(NULL AS INT) ID1, CAST(NULL AS INT) ID2, CAST(NULL AS ST_GEOMETRY) SHAPE FROM DUMMY)", + None, + "SHAPE", + ["ID1", "ID2"], + QgsWkbTypes.Type.Unknown, + ) + test_query( + "(SELECT CAST(NULL AS INT) ID1, CAST(NULL AS BIGINT) ID2, CAST(NULL AS ST_GEOMETRY) SHAPE FROM " + "DUMMY)", + "ID2", + "SHAPE", + ["ID1", "ID2"], + QgsWkbTypes.Type.Unknown, + ) + test_query( + "(SELECT CAST(NULL AS INT) ID1, CAST(NULL AS ST_GEOMETRY) SHAPE1, CAST(NULL AS ST_GEOMETRY) SHAPE2 " + "FROM DUMMY)", + "ID1", + "SHAPE1", + ["ID1", "SHAPE2"], + QgsWkbTypes.Type.Unknown, + ) + test_query( + f'(SELECT "pk" AS "key", "cnt", "geom" AS "g" FROM "{self.schemaName}"."some_data")', + "key", + "g", + ["key", "cnt"], + QgsWkbTypes.Type.Point, + ) def testBooleanType(self): - create_sql = f'CREATE TABLE "{self.schemaName}"."boolean_type" ( ' \ - '"id" INTEGER NOT NULL PRIMARY KEY,' \ + create_sql = ( + f'CREATE TABLE "{self.schemaName}"."boolean_type" ( ' + '"id" INTEGER NOT NULL PRIMARY KEY,' '"fld1" BOOLEAN)' + ) insert_sql = f'INSERT INTO "{self.schemaName}"."boolean_type" ("id", "fld1") VALUES (?, ?)' - insert_args = [[1, 'TRUE'], [2, 'FALSE'], [3, None]] - self.prepareTestTable('boolean_type', create_sql, insert_sql, insert_args) + insert_args = [[1, "TRUE"], [2, "FALSE"], [3, None]] + self.prepareTestTable("boolean_type", create_sql, insert_sql, insert_args) - vl = self.createVectorLayer(f'table="{self.schemaName}"."boolean_type" sql=', 'testbool') + vl = self.createVectorLayer( + f'table="{self.schemaName}"."boolean_type" sql=', "testbool" + ) fields = vl.dataProvider().fields() - self.assertEqual(fields.at(fields.indexFromName('fld1')).type(), QVariant.Bool) + self.assertEqual(fields.at(fields.indexFromName("fld1")).type(), QVariant.Bool) - values = {feat['id']: feat['fld1'] for feat in vl.getFeatures()} + values = {feat["id"]: feat["fld1"] for feat in vl.getFeatures()} expected = {1: True, 2: False, 3: NULL} self.assertEqual(values, expected) def testDecimalAndFloatTypes(self): - create_sql = f'CREATE TABLE "{self.schemaName}"."decimal_and_float_type" ( ' \ - '"id" INTEGER NOT NULL PRIMARY KEY,' \ - '"decimal_field" DECIMAL(15,4),' \ + create_sql = ( + f'CREATE TABLE "{self.schemaName}"."decimal_and_float_type" ( ' + '"id" INTEGER NOT NULL PRIMARY KEY,' + '"decimal_field" DECIMAL(15,4),' '"float_field" FLOAT(12))' - insert_sql = f'INSERT INTO "{self.schemaName}"."decimal_and_float_type" ("id", "decimal_field", ' \ + ) + insert_sql = ( + f'INSERT INTO "{self.schemaName}"."decimal_and_float_type" ("id", "decimal_field", ' f'"float_field") VALUES (?, ?, ?) ' + ) insert_args = [[1, 1.1234, 1.76543]] - self.prepareTestTable('decimal_and_float_type', create_sql, insert_sql, insert_args) + self.prepareTestTable( + "decimal_and_float_type", create_sql, insert_sql, insert_args + ) - vl = self.createVectorLayer(f'table="{self.schemaName}"."decimal_and_float_type" sql=', 'testdecimalfloat') + vl = self.createVectorLayer( + f'table="{self.schemaName}"."decimal_and_float_type" sql=', + "testdecimalfloat", + ) fields = vl.dataProvider().fields() - decimal_field = fields.at(fields.indexFromName('decimal_field')) + decimal_field = fields.at(fields.indexFromName("decimal_field")) self.assertEqual(decimal_field.type(), QVariant.Double) self.assertEqual(decimal_field.length(), 15) self.assertEqual(decimal_field.precision(), 4) - float_field = fields.at(fields.indexFromName('float_field')) + float_field = fields.at(fields.indexFromName("float_field")) self.assertEqual(float_field.type(), QVariant.Double) self.assertEqual(float_field.length(), 7) self.assertEqual(float_field.precision(), 0) feat = next(vl.getFeatures(QgsFeatureRequest())) - decimal_idx = vl.fields().lookupField('decimal_field') + decimal_idx = vl.fields().lookupField("decimal_field") self.assertIsInstance(feat.attributes()[decimal_idx], float) self.assertEqual(feat.attributes()[decimal_idx], 1.1234) - float_idx = vl.fields().lookupField('float_field') + float_idx = vl.fields().lookupField("float_field") self.assertIsInstance(feat.attributes()[float_idx], float) self.assertAlmostEqual(feat.attributes()[float_idx], 1.76543, 5) def testDateTimeTypes(self): - create_sql = f'CREATE TABLE "{self.schemaName}"."date_time_type" ( ' \ - '"id" INTEGER NOT NULL PRIMARY KEY,' \ - '"date_field" DATE,' \ - '"time_field" TIME,' \ + create_sql = ( + f'CREATE TABLE "{self.schemaName}"."date_time_type" ( ' + '"id" INTEGER NOT NULL PRIMARY KEY,' + '"date_field" DATE,' + '"time_field" TIME,' '"datetime_field" TIMESTAMP)' - insert_sql = f'INSERT INTO "{self.schemaName}"."date_time_type" ("id", "date_field", "time_field", "datetime_field") ' \ - 'VALUES (?, ?, ?, ?)' - insert_args = [[1, '2004-03-04', '13:41:52', '2004-03-04 13:41:52']] - self.prepareTestTable('date_time_type', create_sql, insert_sql, insert_args) - - vl = self.createVectorLayer(f'table="{self.schemaName}"."date_time_type" sql=', 'testdatetimes') + ) + insert_sql = ( + f'INSERT INTO "{self.schemaName}"."date_time_type" ("id", "date_field", "time_field", "datetime_field") ' + "VALUES (?, ?, ?, ?)" + ) + insert_args = [[1, "2004-03-04", "13:41:52", "2004-03-04 13:41:52"]] + self.prepareTestTable("date_time_type", create_sql, insert_sql, insert_args) + + vl = self.createVectorLayer( + f'table="{self.schemaName}"."date_time_type" sql=', "testdatetimes" + ) fields = vl.dataProvider().fields() - self.assertEqual(fields.at(fields.indexFromName('date_field')).type(), QVariant.Date) - self.assertEqual(fields.at(fields.indexFromName('time_field')).type(), QVariant.Time) - self.assertEqual(fields.at(fields.indexFromName('datetime_field')).type(), QVariant.DateTime) + self.assertEqual( + fields.at(fields.indexFromName("date_field")).type(), QVariant.Date + ) + self.assertEqual( + fields.at(fields.indexFromName("time_field")).type(), QVariant.Time + ) + self.assertEqual( + fields.at(fields.indexFromName("datetime_field")).type(), QVariant.DateTime + ) f = next(vl.getFeatures(QgsFeatureRequest())) - date_idx = vl.fields().lookupField('date_field') + date_idx = vl.fields().lookupField("date_field") self.assertIsInstance(f.attributes()[date_idx], QDate) self.assertEqual(f.attributes()[date_idx], QDate(2004, 3, 4)) - time_idx = vl.fields().lookupField('time_field') + time_idx = vl.fields().lookupField("time_field") self.assertIsInstance(f.attributes()[time_idx], QTime) self.assertEqual(f.attributes()[time_idx], QTime(13, 41, 52)) - datetime_idx = vl.fields().lookupField('datetime_field') + datetime_idx = vl.fields().lookupField("datetime_field") self.assertIsInstance(f.attributes()[datetime_idx], QDateTime) - self.assertEqual(f.attributes()[datetime_idx], QDateTime(QDate(2004, 3, 4), QTime(13, 41, 52))) + self.assertEqual( + f.attributes()[datetime_idx], + QDateTime(QDate(2004, 3, 4), QTime(13, 41, 52)), + ) def testBinaryType(self): - create_sql = f'CREATE TABLE "{self.schemaName}"."binary_type" ( ' \ - '"id" INTEGER NOT NULL PRIMARY KEY,' \ + create_sql = ( + f'CREATE TABLE "{self.schemaName}"."binary_type" ( ' + '"id" INTEGER NOT NULL PRIMARY KEY,' '"blob" VARBINARY(114))' + ) insert_sql = f'INSERT INTO "{self.schemaName}"."binary_type" ("id", "blob") VALUES (?, ?)' - insert_args = [[1, QByteArray(b'YmludmFsdWU=')], [2, None]] - self.prepareTestTable('binary_type', create_sql, insert_sql, insert_args) + insert_args = [[1, QByteArray(b"YmludmFsdWU=")], [2, None]] + self.prepareTestTable("binary_type", create_sql, insert_sql, insert_args) - vl = self.createVectorLayer(f'table="{self.schemaName}"."binary_type" sql=', 'testbinary') + vl = self.createVectorLayer( + f'table="{self.schemaName}"."binary_type" sql=', "testbinary" + ) fields = vl.dataProvider().fields() - self.assertEqual(fields.at(fields.indexFromName('blob')).type(), QVariant.ByteArray) - self.assertEqual(fields.at(fields.indexFromName('blob')).length(), 114) + self.assertEqual( + fields.at(fields.indexFromName("blob")).type(), QVariant.ByteArray + ) + self.assertEqual(fields.at(fields.indexFromName("blob")).length(), 114) - values = {feat['id']: feat['blob'] for feat in vl.getFeatures()} - expected = {1: QByteArray(b'YmludmFsdWU='), 2: QByteArray()} + values = {feat["id"]: feat["blob"] for feat in vl.getFeatures()} + expected = {1: QByteArray(b"YmludmFsdWU="), 2: QByteArray()} self.assertEqual(values, expected) def testBinaryTypeEdit(self): - create_sql = f'CREATE TABLE "{self.schemaName}"."binary_type_edit" ( ' \ - '"id" INTEGER NOT NULL PRIMARY KEY,' \ + create_sql = ( + f'CREATE TABLE "{self.schemaName}"."binary_type_edit" ( ' + '"id" INTEGER NOT NULL PRIMARY KEY,' '"blob" VARBINARY(1000))' + ) insert_sql = f'INSERT INTO "{self.schemaName}"."binary_type_edit" ("id", "blob") VALUES (?, ?)' - insert_args = [[1, QByteArray(b'YmJi')]] - self.prepareTestTable('binary_type_edit', create_sql, insert_sql, insert_args) - - vl = self.createVectorLayer(f'key=\'id\' table="{self.schemaName}"."binary_type_edit" sql=', 'testbinaryedit') - values = {feat['id']: feat['blob'] for feat in vl.getFeatures()} - expected = {1: QByteArray(b'YmJi')} + insert_args = [[1, QByteArray(b"YmJi")]] + self.prepareTestTable("binary_type_edit", create_sql, insert_sql, insert_args) + + vl = self.createVectorLayer( + f'key=\'id\' table="{self.schemaName}"."binary_type_edit" sql=', + "testbinaryedit", + ) + values = {feat["id"]: feat["blob"] for feat in vl.getFeatures()} + expected = {1: QByteArray(b"YmJi")} self.assertEqual(values, expected) # change attribute value - self.assertTrue(vl.dataProvider().changeAttributeValues({1: {1: QByteArray(b'bbbvx')}})) - values = {feat['id']: feat['blob'] for feat in vl.getFeatures()} - expected = {1: QByteArray(b'bbbvx')} + self.assertTrue( + vl.dataProvider().changeAttributeValues({1: {1: QByteArray(b"bbbvx")}}) + ) + values = {feat["id"]: feat["blob"] for feat in vl.getFeatures()} + expected = {1: QByteArray(b"bbbvx")} self.assertEqual(values, expected) # add feature f = QgsFeature() - f.setAttributes([2, QByteArray(b'cccc')]) + f.setAttributes([2, QByteArray(b"cccc")]) self.assertTrue(vl.dataProvider().addFeature(f)) - values = {feat['id']: feat['blob'] for feat in vl.getFeatures()} - expected = {1: QByteArray(b'bbbvx'), 2: QByteArray(b'cccc')} + values = {feat["id"]: feat["blob"] for feat in vl.getFeatures()} + expected = {1: QByteArray(b"bbbvx"), 2: QByteArray(b"cccc")} self.assertEqual(values, expected) # change feature - self.assertTrue(vl.dataProvider().changeFeatures({2: {1: QByteArray(b'dddd')}}, {})) - values = {feat['id']: feat['blob'] for feat in vl.getFeatures()} - expected = {1: QByteArray(b'bbbvx'), 2: QByteArray(b'dddd')} + self.assertTrue( + vl.dataProvider().changeFeatures({2: {1: QByteArray(b"dddd")}}, {}) + ) + values = {feat["id"]: feat["blob"] for feat in vl.getFeatures()} + expected = {1: QByteArray(b"bbbvx"), 2: QByteArray(b"dddd")} self.assertEqual(values, expected) def testRealVectorType(self): table_name = "real_vector_type" - create_sql = f'CREATE TABLE "{self.schemaName}"."{table_name}" ( ' \ - '"id" INTEGER NOT NULL PRIMARY KEY,' \ + create_sql = ( + f'CREATE TABLE "{self.schemaName}"."{table_name}" ( ' + '"id" INTEGER NOT NULL PRIMARY KEY,' '"emb" REAL_VECTOR(3))' + ) insert_sql = f'INSERT INTO "{self.schemaName}"."{table_name}" ("id", "emb") VALUES (?, TO_REAL_VECTOR(?))' - insert_args = [[1, '[0.1,0.2,0.1]'], [2, None]] - self.prepareTestTable('real_vector_type', create_sql, insert_sql, insert_args) + insert_args = [[1, "[0.1,0.2,0.1]"], [2, None]] + self.prepareTestTable("real_vector_type", create_sql, insert_sql, insert_args) - vl = self.createVectorLayer(f'table="{self.schemaName}"."{table_name}" sql=', 'testrealvector') + vl = self.createVectorLayer( + f'table="{self.schemaName}"."{table_name}" sql=', "testrealvector" + ) fields = vl.dataProvider().fields() - self.assertEqual(fields.at(fields.indexFromName('emb')).type(), QVariant.String) - self.assertEqual(fields.at(fields.indexFromName('emb')).length(), 3) + self.assertEqual(fields.at(fields.indexFromName("emb")).type(), QVariant.String) + self.assertEqual(fields.at(fields.indexFromName("emb")).length(), 3) - values = {feat['id']: feat['emb'] for feat in vl.getFeatures()} - expected = {1: '[0.1,0.2,0.1]', 2: NULL} + values = {feat["id"]: feat["emb"] for feat in vl.getFeatures()} + expected = {1: "[0.1,0.2,0.1]", 2: NULL} self.assertEqual(values, expected) def testRealVectorTypeEdit(self): table_name = "real_vector_type_edit" - create_sql = f'CREATE TABLE "{self.schemaName}"."{table_name}" ( ' \ - '"id" INTEGER NOT NULL PRIMARY KEY,' \ + create_sql = ( + f'CREATE TABLE "{self.schemaName}"."{table_name}" ( ' + '"id" INTEGER NOT NULL PRIMARY KEY,' '"emb" REAL_VECTOR)' + ) insert_sql = f'INSERT INTO "{self.schemaName}"."{table_name}" ("id", "emb") VALUES (?, TO_REAL_VECTOR(?))' - insert_args = [[1, '[0.1,0.2,0.3]']] + insert_args = [[1, "[0.1,0.2,0.3]"]] self.prepareTestTable(table_name, create_sql, insert_sql, insert_args) - vl = self.createVectorLayer(f'key=\'id\' table="{self.schemaName}"."{table_name}" sql=', 'testrealvectoredit') + vl = self.createVectorLayer( + f'key=\'id\' table="{self.schemaName}"."{table_name}" sql=', + "testrealvectoredit", + ) def check_values(expected): - actual = {feat['id']: feat['emb'] for feat in vl.getFeatures()} + actual = {feat["id"]: feat["emb"] for feat in vl.getFeatures()} self.assertEqual(actual, expected) - check_values({1: '[0.1,0.2,0.3]'}) + check_values({1: "[0.1,0.2,0.3]"}) # change attribute value - self.assertTrue(vl.dataProvider().changeAttributeValues({1: {1: '[0.82,0.5,1]'}})) - check_values({1: '[0.82,0.5,1]'}) + self.assertTrue( + vl.dataProvider().changeAttributeValues({1: {1: "[0.82,0.5,1]"}}) + ) + check_values({1: "[0.82,0.5,1]"}) # add feature f = QgsFeature() - f.setAttributes([2, '[1,1,1]']) + f.setAttributes([2, "[1,1,1]"]) self.assertTrue(vl.dataProvider().addFeature(f)) - check_values({1: '[0.82,0.5,1]', 2: '[1,1,1]'}) + check_values({1: "[0.82,0.5,1]", 2: "[1,1,1]"}) # change feature - self.assertTrue(vl.dataProvider().changeFeatures({2: {1: '[2,2,2]'}}, {})) - check_values({1: '[0.82,0.5,1]', 2: '[2,2,2]'}) + self.assertTrue(vl.dataProvider().changeFeatures({2: {1: "[2,2,2]"}}, {})) + check_values({1: "[0.82,0.5,1]", 2: "[2,2,2]"}) def testGeometryAttributes(self): - create_sql = f'CREATE TABLE "{self.schemaName}"."geometry_attribute" ( ' \ - 'ID INTEGER NOT NULL PRIMARY KEY,' \ - 'GEOM1 ST_GEOMETRY(4326),' \ - 'GEOM2 ST_GEOMETRY(4326))' - insert_sql = f'INSERT INTO "{self.schemaName}"."geometry_attribute" (ID, GEOM1, GEOM2) ' \ - f'VALUES (?, ST_GeomFromText(?, 4326), ST_GeomFromText(?, 4326)) ' - insert_args = [[1, 'POINT (1 2)', 'LINESTRING (0 0,1 1)']] - self.prepareTestTable('geometry_attribute', create_sql, insert_sql, insert_args) - - vl = self.createVectorLayer(f'table="{self.schemaName}"."geometry_attribute" (GEOM1) sql=', - 'testgeometryattribute') + create_sql = ( + f'CREATE TABLE "{self.schemaName}"."geometry_attribute" ( ' + "ID INTEGER NOT NULL PRIMARY KEY," + "GEOM1 ST_GEOMETRY(4326)," + "GEOM2 ST_GEOMETRY(4326))" + ) + insert_sql = ( + f'INSERT INTO "{self.schemaName}"."geometry_attribute" (ID, GEOM1, GEOM2) ' + f"VALUES (?, ST_GeomFromText(?, 4326), ST_GeomFromText(?, 4326)) " + ) + insert_args = [[1, "POINT (1 2)", "LINESTRING (0 0,1 1)"]] + self.prepareTestTable("geometry_attribute", create_sql, insert_sql, insert_args) + + vl = self.createVectorLayer( + f'table="{self.schemaName}"."geometry_attribute" (GEOM1) sql=', + "testgeometryattribute", + ) fields = vl.dataProvider().fields() - self.assertEqual(fields.names(), ['ID', 'GEOM2']) - self.assertEqual(fields.at(fields.indexFromName('ID')).type(), QVariant.Int) - self.assertEqual(fields.at(fields.indexFromName('GEOM2')).type(), QVariant.String) - values = {feat['ID']: feat['GEOM2'] for feat in vl.getFeatures()} - self.assertEqual(values, {1: 'LINESTRING (0 0,1 1)'}) + self.assertEqual(fields.names(), ["ID", "GEOM2"]) + self.assertEqual(fields.at(fields.indexFromName("ID")).type(), QVariant.Int) + self.assertEqual( + fields.at(fields.indexFromName("GEOM2")).type(), QVariant.String + ) + values = {feat["ID"]: feat["GEOM2"] for feat in vl.getFeatures()} + self.assertEqual(values, {1: "LINESTRING (0 0,1 1)"}) # change attribute value - self.assertTrue(vl.dataProvider().changeAttributeValues({1: {1: 'LINESTRING (0 0,2 2)'}})) - values = {feat['ID']: feat['GEOM2'] for feat in vl.getFeatures()} - self.assertEqual(values, {1: 'LINESTRING (0 0,2 2)'}) + self.assertTrue( + vl.dataProvider().changeAttributeValues({1: {1: "LINESTRING (0 0,2 2)"}}) + ) + values = {feat["ID"]: feat["GEOM2"] for feat in vl.getFeatures()} + self.assertEqual(values, {1: "LINESTRING (0 0,2 2)"}) def testCreateLayerViaExport(self): def runTest(crs, primaryKey, attributeNames, attributeValues): @@ -505,16 +702,22 @@ def runTest(crs, primaryKey, attributeNames, attributeValues): layer = QgsVectorLayer(f"Point?crs={crs.authid()}", "new_table", "memory") pr = layer.dataProvider() - fields = [QgsField("fldid", QVariant.LongLong), - QgsField("fldtxt", QVariant.String), - QgsField("fldint", QVariant.Int)] + fields = [ + QgsField("fldid", QVariant.LongLong), + QgsField("fldtxt", QVariant.String), + QgsField("fldint", QVariant.Int), + ] if primaryKey == "fldid": constraints = QgsFieldConstraints() - constraints.setConstraint(QgsFieldConstraints.Constraint.ConstraintNotNull, - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) - constraints.setConstraint(QgsFieldConstraints.Constraint.ConstraintUnique, - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) + constraints.setConstraint( + QgsFieldConstraints.Constraint.ConstraintNotNull, + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) + constraints.setConstraint( + QgsFieldConstraints.Constraint.ConstraintUnique, + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) fields[0].setConstraints(constraints) layer.startEditing() @@ -536,35 +739,56 @@ def runTest(crs, primaryKey, attributeNames, attributeValues): pr.addFeatures([f1, f2, f3, f4]) layer.commitChanges() - QgsHanaProviderUtils.dropTableIfExists(self.conn, self.schemaName, 'import_data') + QgsHanaProviderUtils.dropTableIfExists( + self.conn, self.schemaName, "import_data" + ) params = f' key=\'{primaryKey}\' table="{self.schemaName}"."import_data" (geom) sql=' - error, message = QgsVectorLayerExporter.exportLayer(layer, self.uri + params, 'hana', crs) + error, message = QgsVectorLayerExporter.exportLayer( + layer, self.uri + params, "hana", crs + ) self.assertEqual(error, QgsVectorLayerExporter.ExportError.NoError) - import_layer = self.createVectorLayer(params, 'testimportedlayer') + import_layer = self.createVectorLayer(params, "testimportedlayer") self.assertEqual(import_layer.wkbType(), QgsWkbTypes.Type.Point) self.assertEqual([f.name() for f in import_layer.fields()], attributeNames) features = [f.attributes() for f in import_layer.getFeatures()] self.assertEqual(features, attributeValues) geom = [f.geometry().asWkt() for f in import_layer.getFeatures()] - self.assertEqual(geom, ['Point (1 2)', '', 'Point (3 2)', 'Point (4 3)']) + self.assertEqual(geom, ["Point (1 2)", "", "Point (3 2)", "Point (4 3)"]) - QgsHanaProviderUtils.dropTableIfExists(self.conn, self.schemaName, 'import_data') + QgsHanaProviderUtils.dropTableIfExists( + self.conn, self.schemaName, "import_data" + ) def is_crs_installed(srid): - num_crs = QgsHanaProviderUtils.executeSQLFetchOne(self.conn, - f'SELECT COUNT(*) FROM SYS.ST_SPATIAL_REFERENCE_SYSTEMS ' - f'WHERE SRS_ID = {srid}') + num_crs = QgsHanaProviderUtils.executeSQLFetchOne( + self.conn, + f"SELECT COUNT(*) FROM SYS.ST_SPATIAL_REFERENCE_SYSTEMS " + f"WHERE SRS_ID = {srid}", + ) return num_crs == 1 - crs_4326 = QgsCoordinateReferenceSystem('EPSG:4326') + crs_4326 = QgsCoordinateReferenceSystem("EPSG:4326") # primary key already exists in the imported layer - runTest(crs_4326, 'fldid', ['fldid', 'fldtxt', 'fldint'], [[1, 'test', 11], [2, 'test2', 13], - [3, 'test2', NULL], [4, NULL, 13]]) + runTest( + crs_4326, + "fldid", + ["fldid", "fldtxt", "fldint"], + [[1, "test", 11], [2, "test2", 13], [3, "test2", NULL], [4, NULL, 13]], + ) # primary key doesn't exist in the imported layer - runTest(crs_4326, 'pk', ['pk', 'fldid', 'fldtxt', 'fldint'], [[1, 1, 'test', 11], [2, 2, 'test2', 13], - [3, 3, 'test2', NULL], [4, 4, NULL, 13]]) + runTest( + crs_4326, + "pk", + ["pk", "fldid", "fldtxt", "fldint"], + [ + [1, 1, "test", 11], + [2, 2, "test2", 13], + [3, 3, "test2", NULL], + [4, 4, NULL, 13], + ], + ) # crs id that do not exist # unfortunately, we cannot test new units of measure as # QgsCoordinateReferenceSystem does not allow creating @@ -574,157 +798,204 @@ def is_crs_installed(srid): if not is_crs_installed(unknown_srid): crs = QgsCoordinateReferenceSystem.fromEpsgId(unknown_srid) - runTest(crs, 'fldid', ['fldid', 'fldtxt', 'fldint'], [[1, 'test', 11], [2, 'test2', 13], - [3, 'test2', NULL], [4, NULL, 13]]) + runTest( + crs, + "fldid", + ["fldid", "fldtxt", "fldint"], + [[1, "test", 11], [2, "test2", 13], [3, "test2", NULL], [4, NULL, 13]], + ) self.assertTrue(is_crs_installed(unknown_srid)) - QgsHanaProviderUtils.executeSQL(self.conn, f'DROP SPATIAL REFERENCE SYSTEM "{crs.description()}"') + QgsHanaProviderUtils.executeSQL( + self.conn, f'DROP SPATIAL REFERENCE SYSTEM "{crs.description()}"' + ) # QgsHanaProviderUtils.executeSQL(self.conn, 'DROP SPATIAL UNIT OF MEASURE degree_qgis') def testCreateLayerViaExportWithSpecialTypesHandledAsString(self): - table_name = 'binary_types_as_string' - create_sql = f'''CREATE COLUMN TABLE "{self.schemaName}"."{table_name}" ( + table_name = "binary_types_as_string" + create_sql = f"""CREATE COLUMN TABLE "{self.schemaName}"."{table_name}" ( "pk" INTEGER NOT NULL PRIMARY KEY, "vec" REAL_VECTOR(3), "geom1" ST_GEOMETRY(4326), - "geom2" ST_GEOMETRY(4326))''' + "geom2" ST_GEOMETRY(4326))""" - insert_sql = f'INSERT INTO "{self.schemaName}"."{table_name}" ("pk", "vec", "geom1", "geom2") ' \ - 'VALUES (?, TO_REAL_VECTOR(?), ST_GeomFromWKT(?, 4326), ST_GeomFromWKT(?, 4326)) ' + insert_sql = ( + f'INSERT INTO "{self.schemaName}"."{table_name}" ("pk", "vec", "geom1", "geom2") ' + "VALUES (?, TO_REAL_VECTOR(?), ST_GeomFromWKT(?, 4326), ST_GeomFromWKT(?, 4326)) " + ) insert_args = [ - [1, '[0.1,0.3,0.2]', None, 'POINT (-71.123 78.23)'], + [1, "[0.1,0.3,0.2]", None, "POINT (-71.123 78.23)"], [2, None, None, None], - [3, '[0.5,0.8,0.4]', 'POINT (-70.332 66.33)', 'POINT (-71.123 78.23)']] + [3, "[0.5,0.8,0.4]", "POINT (-70.332 66.33)", "POINT (-71.123 78.23)"], + ] self.prepareTestTable(table_name, create_sql, insert_sql, insert_args) - layer = self.createVectorLayer(f'table="{self.schemaName}"."{table_name}" (geom1) sql=', - 'testbinaryattributes') - crs = QgsCoordinateReferenceSystem('EPSG:4326') - params = f' key=\'pk\' table="{self.schemaName}"."import_data_binaries" (geom1) sql=' - error, message = QgsVectorLayerExporter.exportLayer(layer, self.uri + params, 'hana', crs) + layer = self.createVectorLayer( + f'table="{self.schemaName}"."{table_name}" (geom1) sql=', + "testbinaryattributes", + ) + crs = QgsCoordinateReferenceSystem("EPSG:4326") + params = ( + f' key=\'pk\' table="{self.schemaName}"."import_data_binaries" (geom1) sql=' + ) + error, message = QgsVectorLayerExporter.exportLayer( + layer, self.uri + params, "hana", crs + ) self.assertEqual(error, QgsVectorLayerExporter.ExportError.NoError) - import_layer = self.createVectorLayer(params, 'testimportedlayer') + import_layer = self.createVectorLayer(params, "testimportedlayer") fields = import_layer.dataProvider().fields() self.assertEqual(fields.size(), 3) - pk_field = fields.at(fields.indexFromName('pk')) + pk_field = fields.at(fields.indexFromName("pk")) self.assertEqual(pk_field.type(), QVariant.Int) - self.assertEqual(pk_field.typeName(), 'INTEGER') - vec_field = fields.at(fields.indexFromName('vec')) + self.assertEqual(pk_field.typeName(), "INTEGER") + vec_field = fields.at(fields.indexFromName("vec")) self.assertEqual(vec_field.type(), QVariant.String) - self.assertEqual(vec_field.typeName(), 'REAL_VECTOR') + self.assertEqual(vec_field.typeName(), "REAL_VECTOR") self.assertEqual(vec_field.length(), 3) - geom2_field = fields.at(fields.indexFromName('geom2')) + geom2_field = fields.at(fields.indexFromName("geom2")) self.assertEqual(geom2_field.type(), QVariant.String) - self.assertEqual(geom2_field.typeName(), 'ST_GEOMETRY') + self.assertEqual(geom2_field.typeName(), "ST_GEOMETRY") i = 0 for feat in import_layer.getFeatures(): - self.assertEqual(feat['pk'], insert_args[i][0]) - self.assertEqual(feat['vec'], insert_args[i][1]) - self.assertEqual(feat['geom2'], insert_args[i][3]) + self.assertEqual(feat["pk"], insert_args[i][0]) + self.assertEqual(feat["vec"], insert_args[i][1]) + self.assertEqual(feat["geom2"], insert_args[i][3]) i += 1 def testFilterRectOutsideSrsExtent(self): """Test filterRect which partially lies outside of the srs extent""" self.source.setSubsetString(None) extent = QgsRectangle(-103, 46, -25, 97) - result = {f[self.pk_name] for f in self.source.getFeatures(QgsFeatureRequest().setFilterRect(extent))} + result = { + f[self.pk_name] + for f in self.source.getFeatures(QgsFeatureRequest().setFilterRect(extent)) + } expected = {1, 2, 4, 5} self.assertEqual(set(expected), result) def testExtentWithEstimatedMetadata(self): - create_sql = f'CREATE TABLE "{self.schemaName}"."test_extent" ( ' \ - 'ID INTEGER NOT NULL PRIMARY KEY,' \ - 'GEOM1 ST_GEOMETRY(0),' \ - 'GEOM2 ST_GEOMETRY(4326))' - insert_sql = f'INSERT INTO "{self.schemaName}"."test_extent" (ID, GEOM1, GEOM2) ' \ - f'VALUES (?, ST_GeomFromText(?), ST_GeomFromText(?, 4326)) ' - insert_args = [[1, 'POLYGON ((0 0, 20 0, 20 20, 0 20, 0 0))', 'POLYGON ((0 0, 20 0, 20 20, 0 20, 0 0))']] - self.prepareTestTable('test_extent', create_sql, insert_sql, insert_args) - - vl_geom1 = self.createVectorLayer(f'estimatedmetadata=true table="{self.schemaName}"."test_extent" (GEOM1) sql=', 'test_extent') - vl_geom2 = self.createVectorLayer(f'estimatedmetadata=true table="{self.schemaName}"."test_extent" (GEOM2) sql=', 'test_extent') + create_sql = ( + f'CREATE TABLE "{self.schemaName}"."test_extent" ( ' + "ID INTEGER NOT NULL PRIMARY KEY," + "GEOM1 ST_GEOMETRY(0)," + "GEOM2 ST_GEOMETRY(4326))" + ) + insert_sql = ( + f'INSERT INTO "{self.schemaName}"."test_extent" (ID, GEOM1, GEOM2) ' + f"VALUES (?, ST_GeomFromText(?), ST_GeomFromText(?, 4326)) " + ) + insert_args = [ + [ + 1, + "POLYGON ((0 0, 20 0, 20 20, 0 20, 0 0))", + "POLYGON ((0 0, 20 0, 20 20, 0 20, 0 0))", + ] + ] + self.prepareTestTable("test_extent", create_sql, insert_sql, insert_args) + + vl_geom1 = self.createVectorLayer( + f'estimatedmetadata=true table="{self.schemaName}"."test_extent" (GEOM1) sql=', + "test_extent", + ) + vl_geom2 = self.createVectorLayer( + f'estimatedmetadata=true table="{self.schemaName}"."test_extent" (GEOM2) sql=', + "test_extent", + ) self.assertEqual(QgsRectangle(0, 0, 20, 20), vl_geom1.dataProvider().extent()) - self.assertEqual(QgsRectangle(0, 0, 20, 20.284).toString(3), vl_geom2.dataProvider().extent().toString(3)) + self.assertEqual( + QgsRectangle(0, 0, 20, 20.284).toString(3), + vl_geom2.dataProvider().extent().toString(3), + ) def testEncodeDecodeUri(self): """Test HANA encode/decode URI""" - md = QgsProviderRegistry.instance().providerMetadata('hana') + md = QgsProviderRegistry.instance().providerMetadata("hana") self.maxDiff = None - self.assertEqual(md.decodeUri( - "connectionType=0 dsn='HANADB1' " - "driver='/usr/sap/hdbclient/libodbcHDB.so' dbname='qgis_tests' host=localhost port=30015 " - "user='myuser' password='mypwd' srid=2016 table=\"public\".\"gis\" (geom) type=MultiPolygon key='id' " - "sslEnabled='true' sslCryptoProvider='commoncrypto' sslValidateCertificate='false' " - "sslHostNameInCertificate='hostname.domain.com' sslKeyStore='mykey.pem' " - "sslTrustStore='server_root.crt' " - "proxyEnabled='true' proxyHttp='true' proxyHost='h' proxyPort=2 proxyUsername='u' proxyPassword='p' "), + self.assertEqual( + md.decodeUri( + "connectionType=0 dsn='HANADB1' " + "driver='/usr/sap/hdbclient/libodbcHDB.so' dbname='qgis_tests' host=localhost port=30015 " + "user='myuser' password='mypwd' srid=2016 table=\"public\".\"gis\" (geom) type=MultiPolygon key='id' " + "sslEnabled='true' sslCryptoProvider='commoncrypto' sslValidateCertificate='false' " + "sslHostNameInCertificate='hostname.domain.com' sslKeyStore='mykey.pem' " + "sslTrustStore='server_root.crt' " + "proxyEnabled='true' proxyHttp='true' proxyHost='h' proxyPort=2 proxyUsername='u' proxyPassword='p' " + ), { - 'connectionType': '0', - 'dsn': 'HANADB1', - 'driver': '/usr/sap/hdbclient/libodbcHDB.so', - 'dbname': 'qgis_tests', - 'host': 'localhost', - 'port': '30015', - 'username': 'myuser', - 'password': 'mypwd', - 'schema': 'public', - 'table': 'gis', - 'geometrycolumn': 'geom', - 'srid': '2016', - 'type': 6, - 'key': 'id', - 'sslEnabled': 'true', - 'sslCryptoProvider': 'commoncrypto', - 'sslValidateCertificate': 'false', - 'sslHostNameInCertificate': 'hostname.domain.com', - 'sslKeyStore': 'mykey.pem', - 'sslTrustStore': 'server_root.crt', - 'selectatid': False, - 'proxyEnabled': 'true', - 'proxyHttp': 'true', - 'proxyHost': 'h', - 'proxyPort': '2', - 'proxyUsername': 'u', - 'proxyPassword': 'p'}) - - self.assertEqual(md.encodeUri({'connectionType': '0', - 'dsn': 'HANADB1', - 'driver': '/usr/sap/hdbclient/libodbcHDB.so', - 'dbname': 'qgis_tests', - 'host': 'localhost', - 'port': '30015', - 'username': 'myuser', - 'password': 'mypwd', - 'schema': 'public', - 'table': 'gis', - 'geometrycolumn': 'geom', - 'srid': '2016', - 'type': 6, - 'key': 'id', - 'sslEnabled': 'true', - 'sslCryptoProvider': 'commoncrypto', - 'sslValidateCertificate': 'false', - 'sslHostNameInCertificate': 'hostname.domain.com', - 'sslKeyStore': 'mykey.pem', - 'sslTrustStore': 'server_root.crt', - 'selectatid': False, - 'proxyEnabled': 'true', - 'proxyHttp': 'false', - 'proxyHost': 'h', - 'proxyPort': '3', - 'proxyUsername': 'u', - 'proxyPassword': 'p'}), - "dbname='qgis_tests' driver='/usr/sap/hdbclient/libodbcHDB.so' user='myuser' password='mypwd' " - "key='id' srid=2016 connectionType='0' dsn='HANADB1' host='localhost' port='30015' " - "proxyEnabled='true' proxyHost='h' proxyHttp='false' proxyPassword='p' proxyPort='3' " - "proxyUsername='u' selectatid='false' sslCryptoProvider='commoncrypto' sslEnabled='true' " - "sslHostNameInCertificate='hostname.domain.com' sslKeyStore='mykey.pem' " - "sslTrustStore='server_root.crt' sslValidateCertificate='false' type='MultiPolygon' " - "table=\"public\".\"gis\" (geom)") - - -if __name__ == '__main__': + "connectionType": "0", + "dsn": "HANADB1", + "driver": "/usr/sap/hdbclient/libodbcHDB.so", + "dbname": "qgis_tests", + "host": "localhost", + "port": "30015", + "username": "myuser", + "password": "mypwd", + "schema": "public", + "table": "gis", + "geometrycolumn": "geom", + "srid": "2016", + "type": 6, + "key": "id", + "sslEnabled": "true", + "sslCryptoProvider": "commoncrypto", + "sslValidateCertificate": "false", + "sslHostNameInCertificate": "hostname.domain.com", + "sslKeyStore": "mykey.pem", + "sslTrustStore": "server_root.crt", + "selectatid": False, + "proxyEnabled": "true", + "proxyHttp": "true", + "proxyHost": "h", + "proxyPort": "2", + "proxyUsername": "u", + "proxyPassword": "p", + }, + ) + + self.assertEqual( + md.encodeUri( + { + "connectionType": "0", + "dsn": "HANADB1", + "driver": "/usr/sap/hdbclient/libodbcHDB.so", + "dbname": "qgis_tests", + "host": "localhost", + "port": "30015", + "username": "myuser", + "password": "mypwd", + "schema": "public", + "table": "gis", + "geometrycolumn": "geom", + "srid": "2016", + "type": 6, + "key": "id", + "sslEnabled": "true", + "sslCryptoProvider": "commoncrypto", + "sslValidateCertificate": "false", + "sslHostNameInCertificate": "hostname.domain.com", + "sslKeyStore": "mykey.pem", + "sslTrustStore": "server_root.crt", + "selectatid": False, + "proxyEnabled": "true", + "proxyHttp": "false", + "proxyHost": "h", + "proxyPort": "3", + "proxyUsername": "u", + "proxyPassword": "p", + } + ), + "dbname='qgis_tests' driver='/usr/sap/hdbclient/libodbcHDB.so' user='myuser' password='mypwd' " + "key='id' srid=2016 connectionType='0' dsn='HANADB1' host='localhost' port='30015' " + "proxyEnabled='true' proxyHost='h' proxyHttp='false' proxyPassword='p' proxyPort='3' " + "proxyUsername='u' selectatid='false' sslCryptoProvider='commoncrypto' sslEnabled='true' " + "sslHostNameInCertificate='hostname.domain.com' sslKeyStore='mykey.pem' " + "sslTrustStore='server_root.crt' sslValidateCertificate='false' type='MultiPolygon' " + 'table="public"."gis" (geom)', + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_provider_memory.py b/tests/src/python/test_provider_memory.py index 7d2210d99ed8..d4fbc466b279 100644 --- a/tests/src/python/test_provider_memory.py +++ b/tests/src/python/test_provider_memory.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Matthias Kuhn' -__date__ = '2015-04-23' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Matthias Kuhn" +__date__ = "2015-04-23" +__copyright__ = "Copyright 2015, The QGIS Project" from urllib.parse import parse_qs @@ -47,36 +48,74 @@ class TestPyQgsMemoryProvider(QgisTestCase, ProviderTestCase): @classmethod def createLayer(cls): vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk', - 'test', 'memory') - assert (vl.isValid()) + "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk", + "test", + "memory", + ) + assert vl.isValid() f1 = QgsFeature() f1.setAttributes( - [5, -200, NULL, 'NuLl', '5', QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), QDate(2020, 5, 2), - QTime(12, 13, 1)]) - f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)')) + [ + 5, + -200, + NULL, + "NuLl", + "5", + QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), + QDate(2020, 5, 2), + QTime(12, 13, 1), + ] + ) + f1.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)")) f2 = QgsFeature() - f2.setAttributes([3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL]) + f2.setAttributes([3, 300, "Pear", "PEaR", "3", NULL, NULL, NULL]) f3 = QgsFeature() f3.setAttributes( - [1, 100, 'Orange', 'oranGe', '1', QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), QDate(2020, 5, 3), - QTime(12, 13, 14)]) - f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)')) + [ + 1, + 100, + "Orange", + "oranGe", + "1", + QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), + QDate(2020, 5, 3), + QTime(12, 13, 14), + ] + ) + f3.setGeometry(QgsGeometry.fromWkt("Point (-70.332 66.33)")) f4 = QgsFeature() f4.setAttributes( - [2, 200, 'Apple', 'Apple', '2', QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), QDate(2020, 5, 4), - QTime(12, 14, 14)]) - f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)')) + [ + 2, + 200, + "Apple", + "Apple", + "2", + QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), + QDate(2020, 5, 4), + QTime(12, 14, 14), + ] + ) + f4.setGeometry(QgsGeometry.fromWkt("Point (-68.2 70.8)")) f5 = QgsFeature() f5.setAttributes( - [4, 400, 'Honey', 'Honey', '4', QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), QDate(2021, 5, 4), - QTime(13, 13, 14)]) - f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)')) + [ + 4, + 400, + "Honey", + "Honey", + "4", + QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), + QDate(2021, 5, 4), + QTime(13, 13, 14), + ] + ) + f5.setGeometry(QgsGeometry.fromWkt("Point (-65.32 78.3)")) vl.dataProvider().addFeatures([f1, f2, f3, f4, f5]) return vl @@ -84,32 +123,42 @@ def createLayer(cls): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsMemoryProvider, cls).setUpClass() + super().setUpClass() # Create test layer cls.vl = cls.createLayer() - assert (cls.vl.isValid()) + assert cls.vl.isValid() cls.source = cls.vl.dataProvider() # poly layer - cls.poly_vl = QgsVectorLayer('Polygon?crs=epsg:4326&field=pk:integer&key=pk', - 'test', 'memory') - assert (cls.poly_vl.isValid()) + cls.poly_vl = QgsVectorLayer( + "Polygon?crs=epsg:4326&field=pk:integer&key=pk", "test", "memory" + ) + assert cls.poly_vl.isValid() cls.poly_provider = cls.poly_vl.dataProvider() f1 = QgsFeature() f1.setAttributes([1]) - f1.setGeometry(QgsGeometry.fromWkt( - 'Polygon ((-69.03664108 81.35818902, -69.09237722 80.24346619, -73.718477 80.1319939, -73.718477 76.28620011, -74.88893598 76.34193625, -74.83319983 81.35818902, -69.03664108 81.35818902))')) + f1.setGeometry( + QgsGeometry.fromWkt( + "Polygon ((-69.03664108 81.35818902, -69.09237722 80.24346619, -73.718477 80.1319939, -73.718477 76.28620011, -74.88893598 76.34193625, -74.83319983 81.35818902, -69.03664108 81.35818902))" + ) + ) f2 = QgsFeature() f2.setAttributes([2]) - f2.setGeometry(QgsGeometry.fromWkt( - 'Polygon ((-67.58750139 81.1909806, -66.30557012 81.24671674, -66.30557012 76.89929767, -67.58750139 76.89929767, -67.58750139 81.1909806))')) + f2.setGeometry( + QgsGeometry.fromWkt( + "Polygon ((-67.58750139 81.1909806, -66.30557012 81.24671674, -66.30557012 76.89929767, -67.58750139 76.89929767, -67.58750139 81.1909806))" + ) + ) f3 = QgsFeature() f3.setAttributes([3]) - f3.setGeometry(QgsGeometry.fromWkt( - 'Polygon ((-68.36780737 75.78457483, -67.53176524 72.60761475, -68.64648808 73.66660144, -70.20710006 72.9420316, -68.36780737 75.78457483))')) + f3.setGeometry( + QgsGeometry.fromWkt( + "Polygon ((-68.36780737 75.78457483, -67.53176524 72.60761475, -68.64648808 73.66660144, -70.20710006 72.9420316, -68.36780737 75.78457483))" + ) + ) f4 = QgsFeature() f4.setAttributes([4]) @@ -120,55 +169,177 @@ def getEditableLayer(self): return self.createLayer() def testGetFeaturesSubsetAttributes2(self): - """ Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return + """Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass def testGetFeaturesNoGeometry(self): - """ Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return + """Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass def testCtors(self): - testVectors = ["Point", "LineString", "Polygon", "MultiPoint", "MultiLineString", "MultiPolygon", "None"] + testVectors = [ + "Point", + "LineString", + "Polygon", + "MultiPoint", + "MultiLineString", + "MultiPolygon", + "None", + ] for v in testVectors: layer = QgsVectorLayer(v, "test", "memory") self.assertTrue(layer.isValid(), f"Failed to create valid {v} memory layer") def testLayerGeometry(self): - testVectors = [("Point", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.Point), - ("LineString", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineString), - ("Polygon", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.Polygon), - ("MultiPoint", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPoint), - ("MultiLineString", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineString), - ("MultiPolygon", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygon), - ("PointZ", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointZ), - ("LineStringZ", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineStringZ), - ("PolygonZ", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.PolygonZ), - ("MultiPointZ", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPointZ), - ("MultiLineStringZ", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineStringZ), - ("MultiPolygonZ", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygonZ), - ("PointM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointM), - ("LineStringM", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineStringM), - ("PolygonM", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.PolygonM), - ("MultiPointM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPointM), - ("MultiLineStringM", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineStringM), - ("MultiPolygonM", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygonM), - ("PointZM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointZM), - ("LineStringZM", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineStringZM), - ("PolygonZM", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.PolygonZM), - ("MultiPointZM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPointZM), - ("MultiLineStringZM", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineStringZM), - ("MultiPolygonZM", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygonZM), - ("Point25D", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.Point25D), - ("LineString25D", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineString25D), - ("Polygon25D", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.Polygon25D), - ("MultiPoint25D", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPoint25D), - ("MultiLineString25D", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineString25D), - ("MultiPolygon25D", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygon25D), - ("None", QgsWkbTypes.GeometryType.NullGeometry, QgsWkbTypes.Type.NoGeometry)] + testVectors = [ + ("Point", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.Point), + ( + "LineString", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.LineString, + ), + ( + "Polygon", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.Polygon, + ), + ( + "MultiPoint", + QgsWkbTypes.GeometryType.PointGeometry, + QgsWkbTypes.Type.MultiPoint, + ), + ( + "MultiLineString", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.MultiLineString, + ), + ( + "MultiPolygon", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.MultiPolygon, + ), + ("PointZ", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointZ), + ( + "LineStringZ", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.LineStringZ, + ), + ( + "PolygonZ", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.PolygonZ, + ), + ( + "MultiPointZ", + QgsWkbTypes.GeometryType.PointGeometry, + QgsWkbTypes.Type.MultiPointZ, + ), + ( + "MultiLineStringZ", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.MultiLineStringZ, + ), + ( + "MultiPolygonZ", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.MultiPolygonZ, + ), + ("PointM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointM), + ( + "LineStringM", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.LineStringM, + ), + ( + "PolygonM", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.PolygonM, + ), + ( + "MultiPointM", + QgsWkbTypes.GeometryType.PointGeometry, + QgsWkbTypes.Type.MultiPointM, + ), + ( + "MultiLineStringM", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.MultiLineStringM, + ), + ( + "MultiPolygonM", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.MultiPolygonM, + ), + ( + "PointZM", + QgsWkbTypes.GeometryType.PointGeometry, + QgsWkbTypes.Type.PointZM, + ), + ( + "LineStringZM", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.LineStringZM, + ), + ( + "PolygonZM", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.PolygonZM, + ), + ( + "MultiPointZM", + QgsWkbTypes.GeometryType.PointGeometry, + QgsWkbTypes.Type.MultiPointZM, + ), + ( + "MultiLineStringZM", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.MultiLineStringZM, + ), + ( + "MultiPolygonZM", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.MultiPolygonZM, + ), + ( + "Point25D", + QgsWkbTypes.GeometryType.PointGeometry, + QgsWkbTypes.Type.Point25D, + ), + ( + "LineString25D", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.LineString25D, + ), + ( + "Polygon25D", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.Polygon25D, + ), + ( + "MultiPoint25D", + QgsWkbTypes.GeometryType.PointGeometry, + QgsWkbTypes.Type.MultiPoint25D, + ), + ( + "MultiLineString25D", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.MultiLineString25D, + ), + ( + "MultiPolygon25D", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.MultiPolygon25D, + ), + ( + "None", + QgsWkbTypes.GeometryType.NullGeometry, + QgsWkbTypes.Type.NoGeometry, + ), + ] for v in testVectors: layer = QgsVectorLayer(v[0], "test", "memory") @@ -179,18 +350,20 @@ def testAddFeatures(self): layer = QgsVectorLayer("Point", "test", "memory") provider = layer.dataProvider() - res = provider.addAttributes([QgsField("name", QVariant.String), - QgsField("age", QVariant.Int), - QgsField("size", QVariant.Double)]) + res = provider.addAttributes( + [ + QgsField("name", QVariant.String), + QgsField("age", QVariant.Int), + QgsField("size", QVariant.Double), + ] + ) self.assertTrue(res) self.assertEqual(len(provider.fields()), 3) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) - ft.setAttributes(["Johny", - 20, - 0.3]) + ft.setAttributes(["Johny", 20, 0.3]) res, t = provider.addFeatures([ft]) self.assertTrue(res) @@ -211,8 +384,8 @@ def testCloneFeatures(self): Test that cloning a memory layer also clones features """ vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=f1:integer&field=f2:integer', - 'test', 'memory') + "Point?crs=epsg:4326&field=f1:integer&field=f2:integer", "test", "memory" + ) self.assertTrue(vl.isValid()) f1 = QgsFeature() @@ -227,42 +400,55 @@ def testCloneFeatures(self): vl2 = vl.clone() self.assertEqual(vl2.featureCount(), 3) features = [f for f in vl2.getFeatures()] - self.assertTrue([f for f in features if f['f1'] == 5]) - self.assertTrue([f for f in features if f['f1'] == 3]) - self.assertTrue([f for f in features if f['f1'] == 1]) + self.assertTrue([f for f in features if f["f1"] == 5]) + self.assertTrue([f for f in features if f["f1"] == 3]) + self.assertTrue([f for f in features if f["f1"] == 1]) def testCloneId(self): """Test that a cloned layer has a single new id and the same fields as the source layer""" - vl = QgsVectorLayer( - 'Point?crs=epsg:4326', - 'test', 'memory') + vl = QgsVectorLayer("Point?crs=epsg:4326", "test", "memory") self.assertTrue(vl.isValid) dp = vl.dataProvider() - self.assertTrue(dp.addAttributes([QgsField("name", QVariant.String), - QgsField("age", QVariant.Int), - QgsField("size", QVariant.Double)])) + self.assertTrue( + dp.addAttributes( + [ + QgsField("name", QVariant.String), + QgsField("age", QVariant.Int), + QgsField("size", QVariant.Double), + ] + ) + ) vl2 = vl.clone() self.assertTrue( - 'memory?geometry=Point&crs=EPSG:4326&field=name:string(0,0)&field=age:integer(0,0)&field=size:double(0,0)' in vl2.publicSource()) - self.assertEqual(len(parse_qs(vl.publicSource())['uid']), 1) - self.assertEqual(len(parse_qs(vl2.publicSource())['uid']), 1) - self.assertNotEqual(parse_qs(vl2.publicSource())['uid'][0], parse_qs(vl.publicSource())['uid'][0]) + "memory?geometry=Point&crs=EPSG:4326&field=name:string(0,0)&field=age:integer(0,0)&field=size:double(0,0)" + in vl2.publicSource() + ) + self.assertEqual(len(parse_qs(vl.publicSource())["uid"]), 1) + self.assertEqual(len(parse_qs(vl2.publicSource())["uid"]), 1) + self.assertNotEqual( + parse_qs(vl2.publicSource())["uid"][0], + parse_qs(vl.publicSource())["uid"][0], + ) def testGetFields(self): layer = QgsVectorLayer("Point", "test", "memory") provider = layer.dataProvider() - provider.addAttributes([QgsField("name", QVariant.String), - QgsField("age", QVariant.Int), - QgsField("size", QVariant.Double), - QgsField("vallist", QVariant.List, subType=QVariant.Int), - QgsField("stringlist", QVariant.List, subType=QVariant.String), - QgsField("reallist", QVariant.List, subType=QVariant.Double), - QgsField("longlist", QVariant.List, subType=QVariant.LongLong), - QgsField("dict", QVariant.Map), - QgsField("geom", QVariant.UserType, typeName='geometry')]) + provider.addAttributes( + [ + QgsField("name", QVariant.String), + QgsField("age", QVariant.Int), + QgsField("size", QVariant.Double), + QgsField("vallist", QVariant.List, subType=QVariant.Int), + QgsField("stringlist", QVariant.List, subType=QVariant.String), + QgsField("reallist", QVariant.List, subType=QVariant.Double), + QgsField("longlist", QVariant.List, subType=QVariant.LongLong), + QgsField("dict", QVariant.Map), + QgsField("geom", QVariant.UserType, typeName="geometry"), + ] + ) self.assertEqual(len(provider.fields()), 9) self.assertEqual(provider.fields()[0].name(), "name") self.assertEqual(provider.fields()[0].type(), QVariant.String) @@ -289,32 +475,51 @@ def testGetFields(self): self.assertEqual(provider.fields()[7].type(), QVariant.Map) self.assertEqual(provider.fields()[8].name(), "geom") self.assertEqual(provider.fields()[8].type(), QVariant.UserType) - self.assertEqual(provider.fields()[8].typeName(), 'geometry') + self.assertEqual(provider.fields()[8].typeName(), "geometry") ft = QgsFeature(provider.fields()) ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) - ft.setAttributes(["Johny", - 20, - 0.3, - [1, 2, 3], - ['a', 'b', 'c'], - [1.1, 2.2, 3.3], - [1, 2, 3], - {'a': 1, 'b': 2}, - QgsGeometry.fromWkt('Point( 1 2)')]) + ft.setAttributes( + [ + "Johny", + 20, + 0.3, + [1, 2, 3], + ["a", "b", "c"], + [1.1, 2.2, 3.3], + [1, 2, 3], + {"a": 1, "b": 2}, + QgsGeometry.fromWkt("Point( 1 2)"), + ] + ) self.assertTrue(provider.addFeatures([ft])) for f in provider.getFeatures(QgsFeatureRequest()): - self.assertEqual(f.attributes()[:8], ['Johny', 20, 0.3, [1, 2, 3], ['a', 'b', 'c'], [1.1, 2.2, 3.3], [1, 2, 3], {'a': 1, 'b': 2}]) - self.assertEqual(f.attributes()[8].asWkt(), 'Point (1 2)') + self.assertEqual( + f.attributes()[:8], + [ + "Johny", + 20, + 0.3, + [1, 2, 3], + ["a", "b", "c"], + [1.1, 2.2, 3.3], + [1, 2, 3], + {"a": 1, "b": 2}, + ], + ) + self.assertEqual(f.attributes()[8].asWkt(), "Point (1 2)") def testFromUri(self): """Test we can construct the mem provider from a uri""" myMemoryLayer = QgsVectorLayer( - ('Point?crs=epsg:4326&field=name:string(20)&' - 'field=age:integer&field=size:double&index=yes'), - 'test', - 'memory') + ( + "Point?crs=epsg:4326&field=name:string(20)&" + "field=age:integer&field=size:double&index=yes" + ), + "test", + "memory", + ) self.assertIsNotNone(myMemoryLayer) myProvider = myMemoryLayer.dataProvider() @@ -323,111 +528,103 @@ def testFromUri(self): def testLengthPrecisionFromUri(self): """Test we can assign length and precision from a uri""" myMemoryLayer = QgsVectorLayer( - ('Point?crs=epsg:4326&field=size:double(12,9)&index=yes'), - 'test', - 'memory') + ("Point?crs=epsg:4326&field=size:double(12,9)&index=yes"), "test", "memory" + ) - self.assertEqual(myMemoryLayer.fields().field('size').length(), 12) - self.assertEqual(myMemoryLayer.fields().field('size').precision(), 9) + self.assertEqual(myMemoryLayer.fields().field("size").length(), 12) + self.assertEqual(myMemoryLayer.fields().field("size").precision(), 9) myMemoryLayer = QgsVectorLayer( - ('Point?crs=epsg:4326&field=size:double(-1,-1)&index=yes'), - 'test', - 'memory') + ("Point?crs=epsg:4326&field=size:double(-1,-1)&index=yes"), "test", "memory" + ) - self.assertEqual(myMemoryLayer.fields().field('size').length(), -1) - self.assertEqual(myMemoryLayer.fields().field('size').precision(), -1) + self.assertEqual(myMemoryLayer.fields().field("size").length(), -1) + self.assertEqual(myMemoryLayer.fields().field("size").precision(), -1) myMemoryLayer = QgsVectorLayer( - ('Point?crs=epsg:4326&field=size:string(-1)&index=yes'), - 'test', - 'memory') + ("Point?crs=epsg:4326&field=size:string(-1)&index=yes"), "test", "memory" + ) - self.assertEqual(myMemoryLayer.fields().field('size').length(), -1) + self.assertEqual(myMemoryLayer.fields().field("size").length(), -1) def testListFromUri(self): """Test we can create list type fields from a uri""" myMemoryLayer = QgsVectorLayer( - ('Point?crs=epsg:4326&field=a:string(-1)[]&index=yes'), - 'test', - 'memory') + ("Point?crs=epsg:4326&field=a:string(-1)[]&index=yes"), "test", "memory" + ) - self.assertEqual(myMemoryLayer.fields().field('a').type(), QVariant.StringList) - self.assertEqual(myMemoryLayer.fields().field('a').subType(), QVariant.String) + self.assertEqual(myMemoryLayer.fields().field("a").type(), QVariant.StringList) + self.assertEqual(myMemoryLayer.fields().field("a").subType(), QVariant.String) myMemoryLayer = QgsVectorLayer( - ('Point?crs=epsg:4326&field=a:double(-1,-1)[]&index=yes'), - 'test', - 'memory') + ("Point?crs=epsg:4326&field=a:double(-1,-1)[]&index=yes"), "test", "memory" + ) - self.assertEqual(myMemoryLayer.fields().field('a').type(), QVariant.List) - self.assertEqual(myMemoryLayer.fields().field('a').subType(), QVariant.Double) + self.assertEqual(myMemoryLayer.fields().field("a").type(), QVariant.List) + self.assertEqual(myMemoryLayer.fields().field("a").subType(), QVariant.Double) myMemoryLayer = QgsVectorLayer( - ('Point?crs=epsg:4326&field=a:long(-1,-1)[]&index=yes'), - 'test', - 'memory') + ("Point?crs=epsg:4326&field=a:long(-1,-1)[]&index=yes"), "test", "memory" + ) - self.assertEqual(myMemoryLayer.fields().field('a').type(), QVariant.List) - self.assertEqual(myMemoryLayer.fields().field('a').subType(), QVariant.LongLong) + self.assertEqual(myMemoryLayer.fields().field("a").type(), QVariant.List) + self.assertEqual(myMemoryLayer.fields().field("a").subType(), QVariant.LongLong) myMemoryLayer = QgsVectorLayer( - ('Point?crs=epsg:4326&field=a:int(-1,-1)[]&index=yes'), - 'test', - 'memory') + ("Point?crs=epsg:4326&field=a:int(-1,-1)[]&index=yes"), "test", "memory" + ) - self.assertEqual(myMemoryLayer.fields().field('a').type(), QVariant.List) - self.assertEqual(myMemoryLayer.fields().field('a').subType(), QVariant.Int) + self.assertEqual(myMemoryLayer.fields().field("a").type(), QVariant.List) + self.assertEqual(myMemoryLayer.fields().field("a").subType(), QVariant.Int) def testMapFromUri(self): """Test we can create map type fields from a uri""" layer = QgsVectorLayer( - ('Point?crs=epsg:4326&field=a:map(-1)&index=yes'), - 'test', - 'memory') - self.assertEqual(layer.fields().field('a').type(), QVariant.Map) + ("Point?crs=epsg:4326&field=a:map(-1)&index=yes"), "test", "memory" + ) + self.assertEqual(layer.fields().field("a").type(), QVariant.Map) def testGeomFieldFromUri(self): """Test we can create geometry type fields from a uri""" layer = QgsVectorLayer( - ('Point?crs=epsg:4326&field=a:geometry&index=yes'), - 'test', - 'memory') - self.assertEqual(layer.fields().field('a').type(), QVariant.UserType) - self.assertEqual(layer.fields().field('a').typeName(), 'geometry') + ("Point?crs=epsg:4326&field=a:geometry&index=yes"), "test", "memory" + ) + self.assertEqual(layer.fields().field("a").type(), QVariant.UserType) + self.assertEqual(layer.fields().field("a").typeName(), "geometry") def testFromUriWithEncodedField(self): """Test we can construct the mem provider from a uri when a field name is encoded""" layer = QgsVectorLayer( - ('Point?crs=epsg:4326&field=name:string(20)&' - 'field=test%2Ffield:integer'), - 'test', - 'memory') + ("Point?crs=epsg:4326&field=name:string(20)&" "field=test%2Ffield:integer"), + "test", + "memory", + ) self.assertTrue(layer.isValid()) - self.assertEqual([f.name() for f in layer.fields()], ['name', 'test/field']) + self.assertEqual([f.name() for f in layer.fields()], ["name", "test/field"]) def testSaveFields(self): # Create a new memory layer with no fields myMemoryLayer = QgsVectorLayer( - ('Point?crs=epsg:4326&index=yes'), - 'test', - 'memory') + ("Point?crs=epsg:4326&index=yes"), "test", "memory" + ) # Add some fields to the layer - myFields = [QgsField('TestInt', QVariant.Int, 'integer', 2, 0), - QgsField('TestLong', QVariant.LongLong, 'long', -1, 0), - QgsField('TestDbl', QVariant.Double, 'double', 8, 6), - QgsField('TestString', QVariant.String, 'string', 50, 0), - QgsField('TestDate', QVariant.Date, 'date'), - QgsField('TestTime', QVariant.Time, 'time'), - QgsField('TestDateTime', QVariant.DateTime, 'datetime'), - QgsField("vallist", QVariant.List, subType=QVariant.Int), - QgsField("stringlist", QVariant.StringList, subType=QVariant.String), - QgsField("stringlist2", QVariant.List, subType=QVariant.String), - QgsField("reallist", QVariant.List, subType=QVariant.Double), - QgsField("longlist", QVariant.List, subType=QVariant.LongLong), - QgsField("dict", QVariant.Map), - QgsField("geom", QVariant.UserType, typeName="geometry")] + myFields = [ + QgsField("TestInt", QVariant.Int, "integer", 2, 0), + QgsField("TestLong", QVariant.LongLong, "long", -1, 0), + QgsField("TestDbl", QVariant.Double, "double", 8, 6), + QgsField("TestString", QVariant.String, "string", 50, 0), + QgsField("TestDate", QVariant.Date, "date"), + QgsField("TestTime", QVariant.Time, "time"), + QgsField("TestDateTime", QVariant.DateTime, "datetime"), + QgsField("vallist", QVariant.List, subType=QVariant.Int), + QgsField("stringlist", QVariant.StringList, subType=QVariant.String), + QgsField("stringlist2", QVariant.List, subType=QVariant.String), + QgsField("reallist", QVariant.List, subType=QVariant.Double), + QgsField("longlist", QVariant.List, subType=QVariant.LongLong), + QgsField("dict", QVariant.Map), + QgsField("geom", QVariant.UserType, typeName="geometry"), + ] self.assertTrue(myMemoryLayer.startEditing()) for f in myFields: self.assertTrue(myMemoryLayer.addAttribute(f)) @@ -438,11 +635,15 @@ def testSaveFields(self): self.assertEqual(f, myMemoryLayer.fields().field(f.name())) # Export the layer to a layer-definition-XML - qlr = QgsLayerDefinition.exportLayerDefinitionLayers([myMemoryLayer], QgsReadWriteContext()) + qlr = QgsLayerDefinition.exportLayerDefinitionLayers( + [myMemoryLayer], QgsReadWriteContext() + ) self.assertIsNotNone(qlr) # Import the layer from the layer-definition-XML - layers = QgsLayerDefinition.loadLayerDefinitionLayers(qlr, QgsReadWriteContext()) + layers = QgsLayerDefinition.loadLayerDefinitionLayers( + qlr, QgsReadWriteContext() + ) self.assertTrue(layers) myImportedLayer = layers[0] self.assertIsNotNone(myImportedLayer) @@ -451,11 +652,13 @@ def testSaveFields(self): importedFields = myImportedLayer.fields() for f in myFields: self.assertEqual(f.name(), importedFields.field(f.name()).name()) - if f.name() != 'stringlist2': + if f.name() != "stringlist2": self.assertEqual(f.type(), importedFields.field(f.name()).type()) else: # we automatically convert List with String subtype to StringList, to match other data providers - self.assertEqual(importedFields.field(f.name()).type(), QVariant.StringList) + self.assertEqual( + importedFields.field(f.name()).type(), QVariant.StringList + ) self.assertEqual(f.subType(), importedFields.field(f.name()).subType()) self.assertEqual(f.precision(), importedFields.field(f.name()).precision()) @@ -468,8 +671,8 @@ def testSaveFieldWithEditorWidget(self): """ layer = QgsVectorLayer("Point", "test", "memory") - widget = QgsEditorWidgetSetup('ValueMap', {'map': {'key': 'value'}}) - field = QgsField('my_field', QVariant.String) + widget = QgsEditorWidgetSetup("ValueMap", {"map": {"key": "value"}}) + field = QgsField("my_field", QVariant.String) self.assertTrue(layer.startEditing()) @@ -484,39 +687,43 @@ def testRenameAttributes(self): layer = QgsVectorLayer("Point", "test", "memory") provider = layer.dataProvider() - res = provider.addAttributes([QgsField("name", QVariant.String), - QgsField("age", QVariant.Int), - QgsField("size", QVariant.Double)]) + res = provider.addAttributes( + [ + QgsField("name", QVariant.String), + QgsField("age", QVariant.Int), + QgsField("size", QVariant.Double), + ] + ) layer.updateFields() self.assertTrue(res) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) - ft.setAttributes(["Johny", - 20, - 0.3]) + ft.setAttributes(["Johny", 20, 0.3]) res, t = provider.addFeatures([ft]) # bad rename - self.assertFalse(provider.renameAttributes({-1: 'not_a_field'})) - self.assertFalse(provider.renameAttributes({100: 'not_a_field'})) + self.assertFalse(provider.renameAttributes({-1: "not_a_field"})) + self.assertFalse(provider.renameAttributes({100: "not_a_field"})) # already exists - self.assertFalse(provider.renameAttributes({1: 'name'})) + self.assertFalse(provider.renameAttributes({1: "name"})) # rename one field - self.assertTrue(provider.renameAttributes({1: 'this_is_the_new_age'})) - self.assertEqual(provider.fields().at(1).name(), 'this_is_the_new_age') + self.assertTrue(provider.renameAttributes({1: "this_is_the_new_age"})) + self.assertEqual(provider.fields().at(1).name(), "this_is_the_new_age") layer.updateFields() fet = next(layer.getFeatures()) - self.assertEqual(fet.fields()[1].name(), 'this_is_the_new_age') + self.assertEqual(fet.fields()[1].name(), "this_is_the_new_age") # rename two fields - self.assertTrue(provider.renameAttributes({1: 'mapinfo_is_the_stone_age', 2: 'super_size'})) - self.assertEqual(provider.fields().at(1).name(), 'mapinfo_is_the_stone_age') - self.assertEqual(provider.fields().at(2).name(), 'super_size') + self.assertTrue( + provider.renameAttributes({1: "mapinfo_is_the_stone_age", 2: "super_size"}) + ) + self.assertEqual(provider.fields().at(1).name(), "mapinfo_is_the_stone_age") + self.assertEqual(provider.fields().at(2).name(), "super_size") layer.updateFields() fet = next(layer.getFeatures()) - self.assertEqual(fet.fields()[1].name(), 'mapinfo_is_the_stone_age') - self.assertEqual(fet.fields()[2].name(), 'super_size') + self.assertEqual(fet.fields()[1].name(), "mapinfo_is_the_stone_age") + self.assertEqual(fet.fields()[2].name(), "super_size") def testUniqueSource(self): """ @@ -533,45 +740,60 @@ def testCreateMemoryLayer(self): """ # no fields - layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields()) + layer = QgsMemoryProviderUtils.createMemoryLayer("my name", QgsFields()) self.assertTrue(layer.isValid()) - self.assertEqual(layer.name(), 'my name') + self.assertEqual(layer.name(), "my name") self.assertTrue(layer.fields().isEmpty()) self.assertFalse(layer.dataProvider().crs().isValid()) # similar layers should have unique sources - layer2 = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields()) + layer2 = QgsMemoryProviderUtils.createMemoryLayer("my name", QgsFields()) self.assertNotEqual(layer.source(), layer2.source()) # geometry type - layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.Type.Point) + layer = QgsMemoryProviderUtils.createMemoryLayer( + "my name", QgsFields(), QgsWkbTypes.Type.Point + ) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.Type.Point) - layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.Type.PolygonZM) + layer = QgsMemoryProviderUtils.createMemoryLayer( + "my name", QgsFields(), QgsWkbTypes.Type.PolygonZM + ) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.Type.PolygonZM) # crs - layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.Type.PolygonZM, - QgsCoordinateReferenceSystem.fromEpsgId(3111)) + layer = QgsMemoryProviderUtils.createMemoryLayer( + "my name", + QgsFields(), + QgsWkbTypes.Type.PolygonZM, + QgsCoordinateReferenceSystem.fromEpsgId(3111), + ) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), QgsWkbTypes.Type.PolygonZM) self.assertTrue(layer.crs().isValid()) - self.assertEqual(layer.crs().authid(), 'EPSG:3111') + self.assertEqual(layer.crs().authid(), "EPSG:3111") # custom CRS crs = QgsCoordinateReferenceSystem.fromProj( - '+proj=qsc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs') - layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.Type.PolygonZM, crs) + "+proj=qsc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs" + ) + layer = QgsMemoryProviderUtils.createMemoryLayer( + "my name", QgsFields(), QgsWkbTypes.Type.PolygonZM, crs + ) self.assertTrue(layer.isValid()) self.assertTrue(layer.crs().isValid()) - self.assertEqual(layer.crs().toProj(), - '+proj=qsc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs +type=crs') + self.assertEqual( + layer.crs().toProj(), + "+proj=qsc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs +type=crs", + ) # clone it, just to check layer2 = layer.clone() - self.assertEqual(layer2.crs().toProj(), - '+proj=qsc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs +type=crs') + self.assertEqual( + layer2.crs().toProj(), + "+proj=qsc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs +type=crs", + ) # fields fields = QgsFields() @@ -587,35 +809,41 @@ def testCreateMemoryLayer(self): fields.append(QgsField("binaryfield", QVariant.ByteArray)) fields.append(QgsField("boolfield", QVariant.Bool)) fields.append(QgsField("vallist", QVariant.List, subType=QVariant.Int)) - fields.append(QgsField("stringlist", QVariant.StringList, subType=QVariant.String)) + fields.append( + QgsField("stringlist", QVariant.StringList, subType=QVariant.String) + ) fields.append(QgsField("stringlist2", QVariant.List, subType=QVariant.String)) fields.append(QgsField("reallist", QVariant.List, subType=QVariant.Double)) fields.append(QgsField("longlist", QVariant.List, subType=QVariant.LongLong)) fields.append(QgsField("dict", QVariant.Map)) fields.append(QgsField("geom", QVariant.UserType, typeName="geometry")) - layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields) + layer = QgsMemoryProviderUtils.createMemoryLayer("my name", fields) self.assertTrue(layer.isValid()) self.assertFalse(layer.fields().isEmpty()) self.assertEqual(len(layer.fields()), len(fields)) for i in range(len(fields)): self.assertEqual(layer.fields()[i].name(), fields[i].name()) - if layer.fields()[i].name() != 'stringlist2': + if layer.fields()[i].name() != "stringlist2": self.assertEqual(layer.fields()[i].type(), fields[i].type()) else: # we automatically convert List with String subtype to StringList, to match other data providers self.assertEqual(layer.fields()[i].type(), QVariant.StringList) self.assertEqual(layer.fields()[i].length(), fields[i].length()) - self.assertEqual(layer.fields()[i].precision(), fields[i].precision(), fields[i].name()) + self.assertEqual( + layer.fields()[i].precision(), fields[i].precision(), fields[i].name() + ) # unsupported field type fields = QgsFields() fields.append(QgsField("rect", QVariant.RectF)) - layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields) + layer = QgsMemoryProviderUtils.createMemoryLayer("my name", fields) self.assertTrue(layer.isValid()) self.assertFalse(layer.fields().isEmpty()) - self.assertEqual(layer.fields()[0].name(), 'rect') - self.assertEqual(layer.fields()[0].type(), QVariant.String) # should be mapped to string + self.assertEqual(layer.fields()[0].name(), "rect") + self.assertEqual( + layer.fields()[0].type(), QVariant.String + ) # should be mapped to string # field precision fields = QgsFields() @@ -623,7 +851,7 @@ def testCreateMemoryLayer(self): fields.append(QgsField("long", QVariant.LongLong, len=6)) fields.append(QgsField("double", QVariant.Double, len=10, prec=7)) fields.append(QgsField("double2", QVariant.Double, len=-1, prec=-1)) - layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields) + layer = QgsMemoryProviderUtils.createMemoryLayer("my name", fields) self.assertTrue(layer.isValid()) self.assertFalse(layer.fields().isEmpty()) self.assertEqual(len(layer.fields()), len(fields)) @@ -638,7 +866,8 @@ def testChangeAttributeValuesInvalidFieldIndex(self): Test there's no crash when changeAttributeValues is called with a non existing field index (https://github.com/qgis/QGIS/issues/54817) """ layer = QgsVectorLayer( - 'Point?crs=epsg:4326&index=yes&field=pk:integer', 'test', 'memory') + "Point?crs=epsg:4326&index=yes&field=pk:integer", "test", "memory" + ) provider = layer.dataProvider() f = QgsFeature() f.setAttributes([0]) @@ -647,51 +876,69 @@ def testChangeAttributeValuesInvalidFieldIndex(self): saved_feature = next(provider.getFeatures()) self.assertTrue(provider.changeAttributeValues({saved_feature.id(): {-1: 42}})) self.assertTrue(provider.changeAttributeValues({saved_feature.id(): {42: 42}})) - self.assertTrue(provider.changeAttributeValues({saved_feature.id(): {'fortytwo': 42}})) + self.assertTrue( + provider.changeAttributeValues({saved_feature.id(): {"fortytwo": 42}}) + ) def testAddChangeFeatureConvertAttribute(self): """ Test add features with attribute values which require conversion """ layer = QgsVectorLayer( - 'Point?crs=epsg:4326&index=yes&field=pk:integer&field=cnt:int8&field=dt:datetime', 'test', 'memory') + "Point?crs=epsg:4326&index=yes&field=pk:integer&field=cnt:int8&field=dt:datetime", + "test", + "memory", + ) provider = layer.dataProvider() f = QgsFeature() # string value specified for datetime field -- must be converted when adding the feature - f.setAttributes([5, -200, '2021-02-10 00:00']) + f.setAttributes([5, -200, "2021-02-10 00:00"]) self.assertTrue(provider.addFeatures([f])) saved_feature = next(provider.getFeatures()) # saved feature must have a QDateTime value for field, not string - self.assertEqual(saved_feature.attributes(), [5, -200, QDateTime(2021, 2, 10, 0, 0)]) + self.assertEqual( + saved_feature.attributes(), [5, -200, QDateTime(2021, 2, 10, 0, 0)] + ) - self.assertTrue(provider.changeAttributeValues({saved_feature.id(): {2: '2021-02-12 00:00'}})) + self.assertTrue( + provider.changeAttributeValues( + {saved_feature.id(): {2: "2021-02-12 00:00"}} + ) + ) saved_feature = next(provider.getFeatures()) # saved feature must have a QDateTime value for field, not string - self.assertEqual(saved_feature.attributes(), [5, -200, QDateTime(2021, 2, 12, 0, 0)]) + self.assertEqual( + saved_feature.attributes(), [5, -200, QDateTime(2021, 2, 12, 0, 0)] + ) layer = QgsVectorLayer( - 'Point?crs=epsg:4326&index=yes&field=pk:integer&field=geom:geometry', 'test', 'memory') + "Point?crs=epsg:4326&index=yes&field=pk:integer&field=geom:geometry", + "test", + "memory", + ) provider = layer.dataProvider() f = QgsFeature() # string value specified for geom field -- must be converted when adding the feature - f.setAttributes([5, 'Point(1 2)']) + f.setAttributes([5, "Point(1 2)"]) self.assertTrue(provider.addFeatures([f])) saved_feature = next(provider.getFeatures()) # saved feature must have a QgsGeometry value for field, not string self.assertEqual(saved_feature.attributes()[0], 5) - self.assertEqual(saved_feature.attributes()[1].asWkt(), 'Point (1 2)') + self.assertEqual(saved_feature.attributes()[1].asWkt(), "Point (1 2)") def testThreadSafetyWithIndex(self): layer = QgsVectorLayer( - 'Point?crs=epsg:4326&index=yes&field=pk:integer&field=cnt:int8&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk', - 'test', 'memory') + "Point?crs=epsg:4326&index=yes&field=pk:integer&field=cnt:int8&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk", + "test", + "memory", + ) provider = layer.dataProvider() f = QgsFeature() - f.setAttributes([5, -200, NULL, 'NuLl', '5']) - f.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)')) + f.setAttributes([5, -200, NULL, "NuLl", "5"]) + f.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)")) for i in range(100000): provider.addFeatures([f]) @@ -699,7 +946,9 @@ def testThreadSafetyWithIndex(self): # filter rect request extent = QgsRectangle(-73, 70, -63, 80) request = QgsFeatureRequest().setFilterRect(extent) - self.assertTrue(QgsTestUtils.testProviderIteratorThreadSafety(self.source, request)) + self.assertTrue( + QgsTestUtils.testProviderIteratorThreadSafety(self.source, request) + ) def testMinMaxCache(self): """ @@ -707,8 +956,8 @@ def testMinMaxCache(self): :return: """ vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=f1:integer&field=f2:integer', - 'test', 'memory') + "Point?crs=epsg:4326&field=f1:integer&field=f2:integer", "test", "memory" + ) self.assertTrue(vl.isValid()) f1 = QgsFeature() @@ -748,7 +997,11 @@ def testMinMaxCache(self): self.assertEqual(vl.dataProvider().maximumValue(1), 1400) # change attribute values - self.assertTrue(vl.dataProvider().changeAttributeValues({f6.id(): {0: 3, 1: 150}, f7.id(): {0: 4, 1: -100}})) + self.assertTrue( + vl.dataProvider().changeAttributeValues( + {f6.id(): {0: 3, 1: 150}, f7.id(): {0: 4, 1: -100}} + ) + ) self.assertEqual(vl.dataProvider().minimumValue(0), 1) self.assertEqual(vl.dataProvider().minimumValue(1), -200) self.assertEqual(vl.dataProvider().maximumValue(0), 5) @@ -768,18 +1021,18 @@ def testMinMaxCache(self): def testBinary(self): vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=f1:integer&field=f2:binary', - 'test', 'memory') + "Point?crs=epsg:4326&field=f1:integer&field=f2:binary", "test", "memory" + ) self.assertTrue(vl.isValid()) dp = vl.dataProvider() fields = dp.fields() - self.assertEqual([f.name() for f in fields], ['f1', 'f2']) + self.assertEqual([f.name() for f in fields], ["f1", "f2"]) self.assertEqual([f.type() for f in fields], [QVariant.Int, QVariant.ByteArray]) - self.assertEqual([f.typeName() for f in fields], ['integer', 'binary']) + self.assertEqual([f.typeName() for f in fields], ["integer", "binary"]) f = QgsFeature(dp.fields()) - bin_1 = b'xxx' + bin_1 = b"xxx" bin_val1 = QByteArray(bin_1) f.setAttributes([1, bin_val1]) self.assertTrue(dp.addFeature(f)) @@ -788,15 +1041,17 @@ def testBinary(self): self.assertEqual(f2.attributes(), [1, bin_val1]) # add binary field - self.assertTrue(dp.addAttributes([QgsField('binfield2', QVariant.ByteArray, 'Binary')])) + self.assertTrue( + dp.addAttributes([QgsField("binfield2", QVariant.ByteArray, "Binary")]) + ) fields = dp.fields() - bin2_field = fields[fields.lookupField('binfield2')] + bin2_field = fields[fields.lookupField("binfield2")] self.assertEqual(bin2_field.type(), QVariant.ByteArray) - self.assertEqual(bin2_field.typeName(), 'Binary') + self.assertEqual(bin2_field.typeName(), "Binary") f = QgsFeature(fields) - bin_2 = b'yyy' + bin_2 = b"yyy" bin_val2 = QByteArray(bin_2) f.setAttributes([2, NULL, bin_val2]) self.assertTrue(dp.addFeature(f)) @@ -808,15 +1063,15 @@ def testBinary(self): def testBool(self): vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=f1:integer&field=f2:bool', - 'test', 'memory') + "Point?crs=epsg:4326&field=f1:integer&field=f2:bool", "test", "memory" + ) self.assertTrue(vl.isValid()) dp = vl.dataProvider() fields = dp.fields() - self.assertEqual([f.name() for f in fields], ['f1', 'f2']) + self.assertEqual([f.name() for f in fields], ["f1", "f2"]) self.assertEqual([f.type() for f in fields], [QVariant.Int, QVariant.Bool]) - self.assertEqual([f.typeName() for f in fields], ['integer', 'boolean']) + self.assertEqual([f.typeName() for f in fields], ["integer", "boolean"]) f = QgsFeature(dp.fields()) f.setAttributes([1, True]) @@ -826,41 +1081,52 @@ def testBool(self): f3.setAttributes([3, NULL]) self.assertTrue(dp.addFeatures([f, f2, f3])) - self.assertEqual([f.attributes() for f in dp.getFeatures()], [[1, True], [2, False], [3, NULL]]) + self.assertEqual( + [f.attributes() for f in dp.getFeatures()], + [[1, True], [2, False], [3, NULL]], + ) # add boolean field - self.assertTrue(dp.addAttributes([QgsField('boolfield2', QVariant.Bool, 'Boolean')])) + self.assertTrue( + dp.addAttributes([QgsField("boolfield2", QVariant.Bool, "Boolean")]) + ) fields = dp.fields() - bool2_field = fields[fields.lookupField('boolfield2')] + bool2_field = fields[fields.lookupField("boolfield2")] self.assertEqual(bool2_field.type(), QVariant.Bool) - self.assertEqual(bool2_field.typeName(), 'Boolean') + self.assertEqual(bool2_field.typeName(), "Boolean") f = QgsFeature(fields) f.setAttributes([2, NULL, True]) self.assertTrue(dp.addFeature(f)) - self.assertEqual([f.attributes() for f in dp.getFeatures()], - [[1, True, NULL], [2, False, NULL], [3, NULL, NULL], [2, NULL, True]]) + self.assertEqual( + [f.attributes() for f in dp.getFeatures()], + [[1, True, NULL], [2, False, NULL], [3, NULL, NULL], [2, NULL, True]], + ) def testSpatialIndex(self): vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=f1:integer&field=f2:bool', - 'test', 'memory') - self.assertEqual(vl.hasSpatialIndex(), QgsFeatureSource.SpatialIndexPresence.SpatialIndexNotPresent) + "Point?crs=epsg:4326&field=f1:integer&field=f2:bool", "test", "memory" + ) + self.assertEqual( + vl.hasSpatialIndex(), + QgsFeatureSource.SpatialIndexPresence.SpatialIndexNotPresent, + ) vl.dataProvider().createSpatialIndex() - self.assertEqual(vl.hasSpatialIndex(), QgsFeatureSource.SpatialIndexPresence.SpatialIndexPresent) + self.assertEqual( + vl.hasSpatialIndex(), + QgsFeatureSource.SpatialIndexPresence.SpatialIndexPresent, + ) def testTypeValidation(self): """Test that incompatible types in attributes raise errors""" - vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=int:integer', - 'test', 'memory') + vl = QgsVectorLayer("Point?crs=epsg:4326&field=int:integer", "test", "memory") self.assertTrue(vl.isValid()) invalid = QgsFeature(vl.fields()) - invalid.setAttribute('int', 'A string') - invalid.setGeometry(QgsGeometry.fromWkt('point(9 45)')) + invalid.setAttribute("int", "A string") + invalid.setGeometry(QgsGeometry.fromWkt("point(9 45)")) self.assertTrue(vl.startEditing()) # Validation happens on commit self.assertTrue(vl.addFeatures([invalid])) @@ -870,19 +1136,17 @@ def testTypeValidation(self): # Add a valid feature valid = QgsFeature(vl.fields()) - valid.setAttribute('int', 123) + valid.setAttribute("int", 123) self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([valid])) self.assertTrue(vl.commitChanges()) self.assertEqual(vl.featureCount(), 1) f = vl.getFeature(1) - self.assertEqual(f.attribute('int'), 123) + self.assertEqual(f.attribute("int"), 123) # Add both - vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=int:integer', - 'test', 'memory') + vl = QgsVectorLayer("Point?crs=epsg:4326&field=int:integer", "test", "memory") self.assertEqual(vl.featureCount(), 0) self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([valid, invalid])) @@ -892,9 +1156,7 @@ def testTypeValidation(self): self.assertEqual(vl.featureCount(), 0) # Add both swapped - vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=int:integer', - 'test', 'memory') + vl = QgsVectorLayer("Point?crs=epsg:4326&field=int:integer", "test", "memory") self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([invalid, valid])) self.assertFalse(vl.commitChanges()) @@ -903,65 +1165,59 @@ def testTypeValidation(self): self.assertEqual(vl.featureCount(), 0) # Change attribute value - vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=int:integer', - 'test', 'memory') + vl = QgsVectorLayer("Point?crs=epsg:4326&field=int:integer", "test", "memory") self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([valid])) self.assertTrue(vl.commitChanges()) self.assertTrue(vl.startEditing()) - self.assertTrue(vl.changeAttributeValue(1, 0, 'A string')) + self.assertTrue(vl.changeAttributeValue(1, 0, "A string")) self.assertFalse(vl.commitChanges()) f = vl.getFeature(1) - self.assertEqual(f.attribute('int'), 'A string') + self.assertEqual(f.attribute("int"), "A string") self.assertTrue(vl.rollBack()) f = vl.getFeature(1) - self.assertEqual(f.attribute('int'), 123) + self.assertEqual(f.attribute("int"), 123) # Change attribute values - vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=int:integer', - 'test', 'memory') + vl = QgsVectorLayer("Point?crs=epsg:4326&field=int:integer", "test", "memory") self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([valid])) self.assertTrue(vl.commitChanges()) self.assertTrue(vl.startEditing()) - self.assertTrue(vl.changeAttributeValues(1, {0: 'A string'})) + self.assertTrue(vl.changeAttributeValues(1, {0: "A string"})) self.assertFalse(vl.commitChanges()) f = vl.getFeature(1) - self.assertEqual(f.attribute('int'), 'A string') + self.assertEqual(f.attribute("int"), "A string") self.assertTrue(vl.rollBack()) f = vl.getFeature(1) - self.assertEqual(f.attribute('int'), 123) + self.assertEqual(f.attribute("int"), 123) ############################################## # Test direct data provider calls # No rollback (old behavior) - vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=int:integer', - 'test', 'memory') + vl = QgsVectorLayer("Point?crs=epsg:4326&field=int:integer", "test", "memory") dp = vl.dataProvider() self.assertFalse(dp.addFeatures([valid, invalid])[0]) self.assertEqual([f.attributes() for f in dp.getFeatures()], [[123]]) f = vl.getFeature(1) - self.assertEqual(f.attribute('int'), 123) + self.assertEqual(f.attribute("int"), 123) # Roll back - vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=int:integer', - 'test', 'memory') + vl = QgsVectorLayer("Point?crs=epsg:4326&field=int:integer", "test", "memory") dp = vl.dataProvider() - self.assertFalse(dp.addFeatures([valid, invalid], QgsFeatureSink.Flag.RollBackOnErrors)[0]) + self.assertFalse( + dp.addFeatures([valid, invalid], QgsFeatureSink.Flag.RollBackOnErrors)[0] + ) self.assertFalse(dp.hasFeatures()) # Expected behavior for changeAttributeValues is to always roll back self.assertTrue(dp.addFeatures([valid])[0]) - self.assertFalse(dp.changeAttributeValues({1: {0: 'A string'}})) + self.assertFalse(dp.changeAttributeValues({1: {0: "A string"}})) f = vl.getFeature(1) - self.assertEqual(f.attribute('int'), 123) + self.assertEqual(f.attribute("int"), 123) def testAddAttributes(self): """Test that fields with empty/invalid typenames are updated to native type names""" @@ -970,20 +1226,24 @@ def testAddAttributes(self): pr = vl.dataProvider() # add fields - pr.addAttributes([QgsField("name", QVariant.String), - QgsField("age", QVariant.Int, "invalidInteger"), - QgsField("size", QVariant.Double), - QgsField("mytext", QVariant.String, "text"), - QgsField("size2", QVariant.Double, "double precision"), - QgsField("short", QVariant.Int, "int2"), - QgsField("lessshort", QVariant.Int, "int4"), - QgsField("numericfield", QVariant.Double, "numeric"), - QgsField("decimalfield", QVariant.Double, "decimal"), - QgsField("stringlistfield", QVariant.StringList, "stringlist"), - QgsField("integerlistfield", QVariant.List, "integerlist"), - QgsField("doublelistfield", QVariant.List, "doublelist"), - QgsField("dict", QVariant.Map), - QgsField("geom", QVariant.UserType, typeName="geometry")]) + pr.addAttributes( + [ + QgsField("name", QVariant.String), + QgsField("age", QVariant.Int, "invalidInteger"), + QgsField("size", QVariant.Double), + QgsField("mytext", QVariant.String, "text"), + QgsField("size2", QVariant.Double, "double precision"), + QgsField("short", QVariant.Int, "int2"), + QgsField("lessshort", QVariant.Int, "int4"), + QgsField("numericfield", QVariant.Double, "numeric"), + QgsField("decimalfield", QVariant.Double, "decimal"), + QgsField("stringlistfield", QVariant.StringList, "stringlist"), + QgsField("integerlistfield", QVariant.List, "integerlist"), + QgsField("doublelistfield", QVariant.List, "doublelist"), + QgsField("dict", QVariant.Map), + QgsField("geom", QVariant.UserType, typeName="geometry"), + ] + ) self.assertEqual(pr.fields()[0].typeName(), "string") self.assertEqual(pr.fields()[1].typeName(), "integer") @@ -1039,62 +1299,112 @@ class TestPyQgsMemoryProviderIndexed(QgisTestCase, ProviderTestCase): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsMemoryProviderIndexed, cls).setUpClass() + super().setUpClass() # Create test layer cls.vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk', - 'test', 'memory') - assert (cls.vl.isValid()) + "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk", + "test", + "memory", + ) + assert cls.vl.isValid() cls.source = cls.vl.dataProvider() f1 = QgsFeature() f1.setAttributes( - [5, -200, NULL, 'NuLl', '5', QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), QDate(2020, 5, 2), - QTime(12, 13, 1)]) - f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)')) + [ + 5, + -200, + NULL, + "NuLl", + "5", + QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), + QDate(2020, 5, 2), + QTime(12, 13, 1), + ] + ) + f1.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)")) f2 = QgsFeature() - f2.setAttributes([3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL]) + f2.setAttributes([3, 300, "Pear", "PEaR", "3", NULL, NULL, NULL]) f3 = QgsFeature() f3.setAttributes( - [1, 100, 'Orange', 'oranGe', '1', QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), QDate(2020, 5, 3), - QTime(12, 13, 14)]) - f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)')) + [ + 1, + 100, + "Orange", + "oranGe", + "1", + QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), + QDate(2020, 5, 3), + QTime(12, 13, 14), + ] + ) + f3.setGeometry(QgsGeometry.fromWkt("Point (-70.332 66.33)")) f4 = QgsFeature() f4.setAttributes( - [2, 200, 'Apple', 'Apple', '2', QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), QDate(2020, 5, 4), - QTime(12, 14, 14)]) - f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)')) + [ + 2, + 200, + "Apple", + "Apple", + "2", + QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), + QDate(2020, 5, 4), + QTime(12, 14, 14), + ] + ) + f4.setGeometry(QgsGeometry.fromWkt("Point (-68.2 70.8)")) f5 = QgsFeature() f5.setAttributes( - [4, 400, 'Honey', 'Honey', '4', QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), QDate(2021, 5, 4), - QTime(13, 13, 14)]) - f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)')) + [ + 4, + 400, + "Honey", + "Honey", + "4", + QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), + QDate(2021, 5, 4), + QTime(13, 13, 14), + ] + ) + f5.setGeometry(QgsGeometry.fromWkt("Point (-65.32 78.3)")) cls.source.addFeatures([f1, f2, f3, f4, f5]) # poly layer - cls.poly_vl = QgsVectorLayer('Polygon?crs=epsg:4326&index=yes&field=pk:integer&key=pk', - 'test', 'memory') - assert (cls.poly_vl.isValid()) + cls.poly_vl = QgsVectorLayer( + "Polygon?crs=epsg:4326&index=yes&field=pk:integer&key=pk", "test", "memory" + ) + assert cls.poly_vl.isValid() cls.poly_provider = cls.poly_vl.dataProvider() f1 = QgsFeature() f1.setAttributes([1]) - f1.setGeometry(QgsGeometry.fromWkt( - 'Polygon ((-69.0 81.4, -69.0 80.2, -73.7 80.2, -73.7 76.3, -74.9 76.3, -74.9 81.4, -69.0 81.4))')) + f1.setGeometry( + QgsGeometry.fromWkt( + "Polygon ((-69.0 81.4, -69.0 80.2, -73.7 80.2, -73.7 76.3, -74.9 76.3, -74.9 81.4, -69.0 81.4))" + ) + ) f2 = QgsFeature() f2.setAttributes([2]) - f2.setGeometry(QgsGeometry.fromWkt('Polygon ((-67.6 81.2, -66.3 81.2, -66.3 76.9, -67.6 76.9, -67.6 81.2))')) + f2.setGeometry( + QgsGeometry.fromWkt( + "Polygon ((-67.6 81.2, -66.3 81.2, -66.3 76.9, -67.6 76.9, -67.6 81.2))" + ) + ) f3 = QgsFeature() f3.setAttributes([3]) - f3.setGeometry(QgsGeometry.fromWkt('Polygon ((-68.4 75.8, -67.5 72.6, -68.6 73.7, -70.2 72.9, -68.4 75.8))')) + f3.setGeometry( + QgsGeometry.fromWkt( + "Polygon ((-68.4 75.8, -67.5 72.6, -68.6 73.7, -70.2 72.9, -68.4 75.8))" + ) + ) f4 = QgsFeature() f4.setAttributes([4]) @@ -1102,17 +1412,17 @@ def setUpClass(cls): cls.poly_provider.addFeatures([f1, f2, f3, f4]) def testGetFeaturesSubsetAttributes2(self): - """ Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return + """Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass def testGetFeaturesNoGeometry(self): - """ Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return + """Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_provider_mssql.py b/tests/src/python/test_provider_mssql.py index 7969db95a052..dab797efbe60 100644 --- a/tests/src/python/test_provider_mssql.py +++ b/tests/src/python/test_provider_mssql.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2015-12-07' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2015-12-07" +__copyright__ = "Copyright 2015, The QGIS Project" import os @@ -46,35 +47,43 @@ class TestPyQgsMssqlProvider(QgisTestCase, ProviderTestCase): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsMssqlProvider, cls).setUpClass() + super().setUpClass() # These are the connection details for the SQL Server instance running on Travis cls.dbconn = "service='testsqlserver' user=sa password='' " - if 'QGIS_MSSQLTEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_MSSQLTEST_DB'] + if "QGIS_MSSQLTEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_MSSQLTEST_DB"] # Create test layers cls.vl = QgsVectorLayer( - cls.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=', - 'test', 'mssql') - assert cls.vl.dataProvider() is not None, f"No data provider for {cls.vl.source()}" + cls.dbconn + + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=', + "test", + "mssql", + ) + assert ( + cls.vl.dataProvider() is not None + ), f"No data provider for {cls.vl.source()}" assert cls.vl.isValid(), cls.vl.dataProvider().error().message() cls.source = cls.vl.dataProvider() cls.poly_vl = QgsVectorLayer( - cls.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=', - 'test', 'mssql') + cls.dbconn + + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=', + "test", + "mssql", + ) assert cls.poly_vl.isValid(), cls.poly_vl.dataProvider().error().message() cls.poly_provider = cls.poly_vl.dataProvider() # Triggers a segfault in the sql server odbc driver on Travis - TODO test with more recent Ubuntu base image - if os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'): + if os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"): del cls.getEditableLayer # Use connections API - md = QgsProviderRegistry.instance().providerMetadata('mssql') + md = QgsProviderRegistry.instance().providerMetadata("mssql") cls.conn_api = md.createConnection(cls.dbconn, {}) def setUp(self): - for t in ['new_table', 'new_table_multipoint', 'new_table_multipolygon']: - self.execSQLCommand(f'DROP TABLE IF EXISTS qgis_test.[{t}]') + for t in ["new_table", "new_table_multipoint", "new_table_multipolygon"]: + self.execSQLCommand(f"DROP TABLE IF EXISTS qgis_test.[{t}]") def execSQLCommand(self, sql): self.assertTrue(self.conn_api) @@ -82,19 +91,25 @@ def execSQLCommand(self, sql): def getSource(self): # create temporary table for edit tests - self.execSQLCommand('DROP TABLE IF EXISTS qgis_test.edit_data') + self.execSQLCommand("DROP TABLE IF EXISTS qgis_test.edit_data") + self.execSQLCommand( + """CREATE TABLE qgis_test.edit_data (pk INTEGER PRIMARY KEY,cnt integer, name nvarchar(max), name2 nvarchar(max), num_char nvarchar(max), dt datetime, [date] date, [time] time, geom geometry)""" + ) self.execSQLCommand( - """CREATE TABLE qgis_test.edit_data (pk INTEGER PRIMARY KEY,cnt integer, name nvarchar(max), name2 nvarchar(max), num_char nvarchar(max), dt datetime, [date] date, [time] time, geom geometry)""") - self.execSQLCommand("INSERT INTO [qgis_test].[edit_data] (pk, cnt, name, name2, num_char, dt, [date], [time], geom) VALUES " - "(5, -200, NULL, 'NuLl', '5', '2020-05-04T12:13:14', '2020-05-02', '12:13:01', geometry::STGeomFromText('POINT(-71.123 78.23)', 4326))," - "(3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL, NULL)," - "(1, 100, 'Orange', 'oranGe', '1', '2020-05-03T12:13:14', '2020-05-03', '12:13:14', geometry::STGeomFromText('POINT(-70.332 66.33)', 4326))," - "(2, 200, 'Apple', 'Apple', '2', '2020-05-04T12:14:14', '2020-05-04', '12:14:14', geometry::STGeomFromText('POINT(-68.2 70.8)', 4326))," - "(4, 400, 'Honey', 'Honey', '4', '2021-05-04T13:13:14', '2021-05-04', '13:13:14', geometry::STGeomFromText('POINT(-65.32 78.3)', 4326))") + "INSERT INTO [qgis_test].[edit_data] (pk, cnt, name, name2, num_char, dt, [date], [time], geom) VALUES " + "(5, -200, NULL, 'NuLl', '5', '2020-05-04T12:13:14', '2020-05-02', '12:13:01', geometry::STGeomFromText('POINT(-71.123 78.23)', 4326))," + "(3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL, NULL)," + "(1, 100, 'Orange', 'oranGe', '1', '2020-05-03T12:13:14', '2020-05-03', '12:13:14', geometry::STGeomFromText('POINT(-70.332 66.33)', 4326))," + "(2, 200, 'Apple', 'Apple', '2', '2020-05-04T12:14:14', '2020-05-04', '12:14:14', geometry::STGeomFromText('POINT(-68.2 70.8)', 4326))," + "(4, 400, 'Honey', 'Honey', '4', '2021-05-04T13:13:14', '2021-05-04', '13:13:14', geometry::STGeomFromText('POINT(-65.32 78.3)', 4326))" + ) vl = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."edit_data" (geom) sql=', - 'test', 'mssql') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."edit_data" (geom) sql=', + "test", + "mssql", + ) return vl def testDeleteFeaturesPktInt(self): @@ -120,30 +135,30 @@ def getEditableLayer(self): return self.getSource() def enableCompiler(self): - QgsSettings().setValue('/qgis/compileExpressions', True) + QgsSettings().setValue("/qgis/compileExpressions", True) return True def disableCompiler(self): - QgsSettings().setValue('/qgis/compileExpressions', False) + QgsSettings().setValue("/qgis/compileExpressions", False) def partiallyCompiledFilters(self): filters = { - 'name ILIKE \'QGIS\'', - 'name = \'Apple\'', - '\"NaMe\" = \'Apple\'', - 'name = \'apple\'', - 'name LIKE \'Apple\'', - 'name LIKE \'aPple\'', - 'name ILIKE \'aPple\'', - 'name LIKE \'Ap_le\'', - 'name LIKE \'Ap\\_le\'', - 'name ILIKE \'%pp%\'', - '"name" || \' \' || "name" = \'Orange Orange\'', - '"name" || \' \' || "cnt" = \'Orange 100\'', + "name ILIKE 'QGIS'", + "name = 'Apple'", + "\"NaMe\" = 'Apple'", + "name = 'apple'", + "name LIKE 'Apple'", + "name LIKE 'aPple'", + "name ILIKE 'aPple'", + "name LIKE 'Ap_le'", + "name LIKE 'Ap\\_le'", + "name ILIKE '%pp%'", + "\"name\" || ' ' || \"name\" = 'Orange Orange'", + "\"name\" || ' ' || \"cnt\" = 'Orange 100'", '"name"="name2"', - 'lower(name) = \'apple\'', - 'upper(name) = \'APPLE\'', - 'name = trim(\' Apple \')' + "lower(name) = 'apple'", + "upper(name) = 'APPLE'", + "name = trim(' Apple ')", } return filters @@ -151,147 +166,159 @@ def uncompiledFilters(self): filters = { '"name" IS NULL', '"name" IS NOT NULL', - '"name" NOT LIKE \'Ap%\'', - '"name" NOT ILIKE \'QGIS\'', - '"name" NOT ILIKE \'pEAR\'', - 'name <> \'Apple\'', - '"name" <> \'apple\'', - '(name = \'Apple\') is not null', - '\'x\' || "name" IS NOT NULL', - '\'x\' || "name" IS NULL', - '"name" ~ \'[OP]ra[gne]+\'', - 'false and NULL', - 'true and NULL', - 'NULL and false', - 'NULL and true', - 'NULL and NULL', - 'false or NULL', - 'true or NULL', - 'NULL or false', - 'NULL or true', - 'NULL or NULL', - 'not null', - 'not name = \'Apple\'', - 'not name IS NULL', - 'not name = \'Apple\' or name = \'Apple\'', - 'not name = \'Apple\' or not name = \'Apple\'', - 'not name = \'Apple\' and pk = 4', - 'not name = \'Apple\' and not pk = 4', - 'pk = coalesce(NULL,3,4)', - 'x($geometry) < -70', - 'y($geometry) > 70', - 'xmin($geometry) < -70', - 'ymin($geometry) > 70', - 'xmax($geometry) < -70', - 'ymax($geometry) > 70', - 'disjoint($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', - 'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', - 'contains(geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'),$geometry)', - 'distance($geometry,geom_from_wkt( \'Point (-70 70)\')) > 7', - 'intersects($geometry,geom_from_gml( \'-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1\'))', - 'x($geometry) < -70', - 'y($geometry) > 79', - 'xmin($geometry) < -70', - 'ymin($geometry) < 76', - 'xmax($geometry) > -68', - 'ymax($geometry) > 80', - 'area($geometry) > 10', - 'perimeter($geometry) < 12', - 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\')) = \'FF2FF1212\'', - 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'), \'****F****\')', - 'crosses($geometry,geom_from_wkt( \'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)\'))', - 'overlaps($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'))', - 'within($geometry,geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - 'overlaps(translate($geometry,-1,-1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - 'overlaps(buffer($geometry,1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - 'intersects(centroid($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', - 'intersects(point_on_surface($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', - '"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')', - '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')', - '"time" = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')' + "\"name\" NOT LIKE 'Ap%'", + "\"name\" NOT ILIKE 'QGIS'", + "\"name\" NOT ILIKE 'pEAR'", + "name <> 'Apple'", + "\"name\" <> 'apple'", + "(name = 'Apple') is not null", + "'x' || \"name\" IS NOT NULL", + "'x' || \"name\" IS NULL", + "\"name\" ~ '[OP]ra[gne]+'", + "false and NULL", + "true and NULL", + "NULL and false", + "NULL and true", + "NULL and NULL", + "false or NULL", + "true or NULL", + "NULL or false", + "NULL or true", + "NULL or NULL", + "not null", + "not name = 'Apple'", + "not name IS NULL", + "not name = 'Apple' or name = 'Apple'", + "not name = 'Apple' or not name = 'Apple'", + "not name = 'Apple' and pk = 4", + "not name = 'Apple' and not pk = 4", + "pk = coalesce(NULL,3,4)", + "x($geometry) < -70", + "y($geometry) > 70", + "xmin($geometry) < -70", + "ymin($geometry) > 70", + "xmax($geometry) < -70", + "ymax($geometry) > 70", + "disjoint($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))", + "intersects($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))", + "contains(geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'),$geometry)", + "distance($geometry,geom_from_wkt( 'Point (-70 70)')) > 7", + "intersects($geometry,geom_from_gml( '-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1'))", + "x($geometry) < -70", + "y($geometry) > 79", + "xmin($geometry) < -70", + "ymin($geometry) < 76", + "xmax($geometry) > -68", + "ymax($geometry) > 80", + "area($geometry) > 10", + "perimeter($geometry) < 12", + "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))')) = 'FF2FF1212'", + "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'), '****F****')", + "crosses($geometry,geom_from_wkt( 'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)'))", + "overlaps($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'))", + "within($geometry,geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + "overlaps(translate($geometry,-1,-1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + "overlaps(buffer($geometry,1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + "intersects(centroid($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))", + "intersects(point_on_surface($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))", + "\"dt\" = to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy')", + "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')", + "\"time\" = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')", } return filters def testGetFeaturesUncompiled(self): - if os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'): + if os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"): return super().testGetFeaturesUncompiled() def testGetFeaturesExp(self): - if os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'): + if os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"): return super().testGetFeaturesExp() def testOrderBy(self): - if os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'): + if os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"): return super().testOrderBy() def testOrderByCompiled(self): - if os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'): + if os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"): return super().testOrderByCompiled() # HERE GO THE PROVIDER SPECIFIC TESTS def testDateTimeTypes(self): - vl = QgsVectorLayer('%s table="qgis_test"."date_times" sql=' % - (self.dbconn), "testdatetimes", "mssql") + vl = QgsVectorLayer( + '%s table="qgis_test"."date_times" sql=' % (self.dbconn), + "testdatetimes", + "mssql", + ) self.assertTrue(vl.isValid()) fields = vl.dataProvider().fields() - self.assertEqual(fields.at(fields.indexFromName( - 'date_field')).type(), QVariant.Date) - self.assertEqual(fields.at(fields.indexFromName( - 'time_field')).type(), QVariant.Time) - self.assertEqual(fields.at(fields.indexFromName( - 'datetime_field')).type(), QVariant.DateTime) + self.assertEqual( + fields.at(fields.indexFromName("date_field")).type(), QVariant.Date + ) + self.assertEqual( + fields.at(fields.indexFromName("time_field")).type(), QVariant.Time + ) + self.assertEqual( + fields.at(fields.indexFromName("datetime_field")).type(), QVariant.DateTime + ) f = next(vl.getFeatures(QgsFeatureRequest())) - date_idx = vl.fields().lookupField('date_field') + date_idx = vl.fields().lookupField("date_field") self.assertIsInstance(f.attributes()[date_idx], QDate) self.assertEqual(f.attributes()[date_idx], QDate(2004, 3, 4)) - time_idx = vl.fields().lookupField('time_field') + time_idx = vl.fields().lookupField("time_field") self.assertIsInstance(f.attributes()[time_idx], QTime) self.assertEqual(f.attributes()[time_idx], QTime(13, 41, 52)) - datetime_idx = vl.fields().lookupField('datetime_field') + datetime_idx = vl.fields().lookupField("datetime_field") self.assertIsInstance(f.attributes()[datetime_idx], QDateTime) - self.assertEqual(f.attributes()[datetime_idx], QDateTime( - QDate(2004, 3, 4), QTime(13, 41, 52))) + self.assertEqual( + f.attributes()[datetime_idx], + QDateTime(QDate(2004, 3, 4), QTime(13, 41, 52)), + ) def testFloatDecimalFields(self): - vl = QgsVectorLayer('%s table="qgis_test"."float_dec" sql=' % - (self.dbconn), "testprec", "mssql") + vl = QgsVectorLayer( + '%s table="qgis_test"."float_dec" sql=' % (self.dbconn), "testprec", "mssql" + ) self.assertTrue(vl.isValid()) fields = vl.dataProvider().fields() - self.assertEqual(fields.at(fields.indexFromName( - 'float_field')).type(), QVariant.Double) - self.assertEqual(fields.at(fields.indexFromName( - 'float_field')).length(), 15) - self.assertEqual(fields.at(fields.indexFromName( - 'float_field')).precision(), -1) - - self.assertEqual(fields.at(fields.indexFromName( - 'dec_field')).type(), QVariant.Double) - self.assertEqual(fields.at(fields.indexFromName( - 'dec_field')).length(), 7) - self.assertEqual(fields.at(fields.indexFromName( - 'dec_field')).precision(), 3) + self.assertEqual( + fields.at(fields.indexFromName("float_field")).type(), QVariant.Double + ) + self.assertEqual(fields.at(fields.indexFromName("float_field")).length(), 15) + self.assertEqual(fields.at(fields.indexFromName("float_field")).precision(), -1) + + self.assertEqual( + fields.at(fields.indexFromName("dec_field")).type(), QVariant.Double + ) + self.assertEqual(fields.at(fields.indexFromName("dec_field")).length(), 7) + self.assertEqual(fields.at(fields.indexFromName("dec_field")).precision(), 3) f = next(vl.getFeatures(QgsFeatureRequest())) - float_idx = vl.fields().lookupField('float_field') + float_idx = vl.fields().lookupField("float_field") self.assertIsInstance(f.attributes()[float_idx], float) self.assertAlmostEqual(f.attributes()[float_idx], 1.1111111111, 5) - dec_idx = vl.fields().lookupField('dec_field') + dec_idx = vl.fields().lookupField("dec_field") self.assertIsInstance(f.attributes()[dec_idx], float) self.assertEqual(f.attributes()[dec_idx], 1.123) - @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'), 'Failing on Travis') + @unittest.skipIf( + os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), "Failing on Travis" + ) def testCreateLayer(self): - layer = QgsVectorLayer("Point?field=id:integer&field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=id:integer&field=fldtxt:string&field=fldint:integer", + "addfeat", + "memory", + ) pr = layer.dataProvider() f = QgsFeature() f.setAttributes([1, "test", 1]) @@ -307,111 +334,163 @@ def testCreateLayer(self): pr.addFeatures([f, f2, f3, f4]) uri = f'{self.dbconn} table="qgis_test"."new_table" sql=' - error, message = QgsVectorLayerExporter.exportLayer(layer, uri, 'mssql', - QgsCoordinateReferenceSystem('EPSG:4326')) + error, message = QgsVectorLayerExporter.exportLayer( + layer, uri, "mssql", QgsCoordinateReferenceSystem("EPSG:4326") + ) self.assertEqual(error, QgsVectorLayerExporter.ExportError.NoError) - new_layer = QgsVectorLayer(uri, 'new', 'mssql') + new_layer = QgsVectorLayer(uri, "new", "mssql") self.assertTrue(new_layer.isValid()) self.assertEqual(new_layer.wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual([f.name() for f in new_layer.fields()], ['qgs_fid', 'id', 'fldtxt', 'fldint']) + self.assertEqual( + [f.name() for f in new_layer.fields()], + ["qgs_fid", "id", "fldtxt", "fldint"], + ) features = [f.attributes() for f in new_layer.getFeatures()] - self.assertEqual(features, [[1, 1, 'test', 1], - [2, 2, 'test2', 3], - [3, 3, 'test2', NULL], - [4, 4, NULL, 3]]) + self.assertEqual( + features, + [ + [1, 1, "test", 1], + [2, 2, "test2", 3], + [3, 3, "test2", NULL], + [4, 4, NULL, 3], + ], + ) geom = [f.geometry().asWkt() for f in new_layer.getFeatures()] - self.assertEqual(geom, ['Point (1 2)', '', 'Point (3 2)', 'Point (4 3)']) + self.assertEqual(geom, ["Point (1 2)", "", "Point (3 2)", "Point (4 3)"]) - @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'), 'Failing on Travis') + @unittest.skipIf( + os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), "Failing on Travis" + ) def testCreateLayerMultiPoint(self): - layer = QgsVectorLayer("MultiPoint?crs=epsg:3111&field=id:integer&field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "MultiPoint?crs=epsg:3111&field=id:integer&field=fldtxt:string&field=fldint:integer", + "addfeat", + "memory", + ) pr = layer.dataProvider() f = QgsFeature() f.setAttributes([1, "test", 1]) - f.setGeometry(QgsGeometry.fromWkt('MultiPoint(1 2, 3 4)')) + f.setGeometry(QgsGeometry.fromWkt("MultiPoint(1 2, 3 4)")) f2 = QgsFeature() f2.setAttributes([2, "test2", 3]) f3 = QgsFeature() f3.setAttributes([3, "test2", NULL]) - f3.setGeometry(QgsGeometry.fromWkt('MultiPoint(7 8)')) + f3.setGeometry(QgsGeometry.fromWkt("MultiPoint(7 8)")) pr.addFeatures([f, f2, f3]) uri = f'{self.dbconn} table="qgis_test"."new_table_multipoint" sql=' - error, message = QgsVectorLayerExporter.exportLayer(layer, uri, 'mssql', - QgsCoordinateReferenceSystem('EPSG:3111')) + error, message = QgsVectorLayerExporter.exportLayer( + layer, uri, "mssql", QgsCoordinateReferenceSystem("EPSG:3111") + ) self.assertEqual(error, QgsVectorLayerExporter.ExportError.NoError) - new_layer = QgsVectorLayer(uri, 'new', 'mssql') + new_layer = QgsVectorLayer(uri, "new", "mssql") self.assertTrue(new_layer.isValid()) self.assertEqual(new_layer.wkbType(), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(new_layer.crs().authid(), 'EPSG:3111') - self.assertEqual([f.name() for f in new_layer.fields()], ['qgs_fid', 'id', 'fldtxt', 'fldint']) + self.assertEqual(new_layer.crs().authid(), "EPSG:3111") + self.assertEqual( + [f.name() for f in new_layer.fields()], + ["qgs_fid", "id", "fldtxt", "fldint"], + ) features = [f.attributes() for f in new_layer.getFeatures()] - self.assertEqual(features, [[1, 1, 'test', 1], - [2, 2, 'test2', 3], - [3, 3, 'test2', NULL]]) + self.assertEqual( + features, [[1, 1, "test", 1], [2, 2, "test2", 3], [3, 3, "test2", NULL]] + ) geom = [f.geometry().asWkt() for f in new_layer.getFeatures()] - self.assertEqual(geom, ['MultiPoint ((1 2),(3 4))', '', 'MultiPoint ((7 8))']) + self.assertEqual(geom, ["MultiPoint ((1 2),(3 4))", "", "MultiPoint ((7 8))"]) - @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'), 'Failing on Travis') + @unittest.skipIf( + os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), "Failing on Travis" + ) def testCurveGeometries(self): - geomtypes = ['CompoundCurveM', 'CurvePolygonM', 'CircularStringM', 'CompoundCurveZM', 'CurvePolygonZM', - 'CircularStringZM', 'CompoundCurveZ', 'CurvePolygonZ', 'CircularStringZ', 'CompoundCurve', - 'CurvePolygon', 'CircularString'] + geomtypes = [ + "CompoundCurveM", + "CurvePolygonM", + "CircularStringM", + "CompoundCurveZM", + "CurvePolygonZM", + "CircularStringZM", + "CompoundCurveZ", + "CurvePolygonZ", + "CircularStringZ", + "CompoundCurve", + "CurvePolygon", + "CircularString", + ] geoms = [ - 'CompoundCurveM ((0 -23.43778 10, 0 23.43778 10),CircularStringM (0 23.43778 10, -45 33.43778 10, -90 23.43778 10),(-90 23.43778 10, -90 -23.43778 10),CircularStringM (-90 -23.43778 10, -45 -23.43778 10, 0 -23.43778 10))', - 'CurvePolygonM (CompoundCurveM ((0 -23.43778 10, 0 -15.43778 10, 0 23.43778 10),CircularStringM (0 23.43778 10, -45 100 10, -90 23.43778 10),(-90 23.43778 10, -90 -23.43778 10),CircularStringM (-90 -23.43778 10, -45 -16.43778 10, 0 -23.43778 10)),CompoundCurveM (CircularStringM (-30 0 10, -48 -12 10, -60 0 10, -48 -6 10, -30 0 10)))', - 'CircularStringM (0 0 10, 0.14644660940672 0.35355339059327 10, 0.5 0.5 10, 0.85355339059327 0.35355339059327 10, 1 0 10, 0.85355339059327 -0.35355339059327 10, 0.5 -0.5 10, 0.14644660940672 -0.35355339059327 10, 0 0 10)', - 'CompoundCurveZM ((0 -23.43778 2 10, 0 23.43778 2 10),CircularStringZM (0 23.43778 2 10, -45 33.43778 2 10, -90 23.43778 2 10),(-90 23.43778 2 10, -90 -23.43778 2 10),CircularStringZM (-90 -23.43778 2 10, -45 -23.43778 2 10, 0 -23.43778 2 10))', - 'CurvePolygonZM (CompoundCurveZM ((0 -23.43778 5 10, 0 -15.43778 8 10, 0 23.43778 6 10),CircularStringZM (0 23.43778 6 10, -45 100 6 10, -90 23.43778 6 10),(-90 23.43778 6 10, -90 -23.43778 5 10),CircularStringZM (-90 -23.43778 5 10, -45 -16.43778 5 10, 0 -23.43778 5 10)),CompoundCurveZM (CircularStringZM (-30 0 10 10, -48 -12 10 10, -60 0 10 10, -48 -6 10 10, -30 0 10 10)))', - 'CircularStringZM (0 0 1 10, 0.14644660940672 0.35355339059327 1 10, 0.5 0.5 1 10, 0.85355339059327 0.35355339059327 1 10, 1 0 1 10, 0.85355339059327 -0.35355339059327 1 10, 0.5 -0.5 1 10, 0.14644660940672 -0.35355339059327 1 10, 0 0 1 10)', - 'CompoundCurveZ ((0 -23.43778 2, 0 23.43778 2),CircularStringZ (0 23.43778 2, -45 33.43778 2, -90 23.43778 2),(-90 23.43778 2, -90 -23.43778 2),CircularStringZ (-90 -23.43778 2, -45 -23.43778 2, 0 -23.43778 2))', - 'CurvePolygonZ (CompoundCurveZ ((0 -23.43778 5, 0 -15.43778 8, 0 23.43778 6),CircularStringZ (0 23.43778 6, -45 100 6, -90 23.43778 6),(-90 23.43778 6, -90 -23.43778 5),CircularStringZ (-90 -23.43778 5, -45 -16.43778 5, 0 -23.43778 5)),CompoundCurveZ (CircularStringZ (-30 0 10, -48 -12 10, -60 0 10, -48 -6 10, -30 0 10)))', - 'CircularStringZ (0 0 1, 0.14644660940672 0.35355339059327 1, 0.5 0.5 1, 0.85355339059327 0.35355339059327 1, 1 0 1, 0.85355339059327 -0.35355339059327 1, 0.5 -0.5 1, 0.14644660940672 -0.35355339059327 1, 0 0 1)', - 'CompoundCurve ((0 -23.43778, 0 23.43778),CircularString (0 23.43778, -45 33.43778, -90 23.43778),(-90 23.43778, -90 -23.43778),CircularString (-90 -23.43778, -45 -23.43778, 0 -23.43778))', - 'CurvePolygon (CompoundCurve ((0 -23.43778, 0 -15.43778, 0 23.43778),CircularString (0 23.43778, -45 100, -90 23.43778),(-90 23.43778, -90 -23.43778),CircularString (-90 -23.43778, -45 -16.43778, 0 -23.43778)),CompoundCurve (CircularString (-30 0, -48 -12, -60 0, -48 -6, -30 0)))', - 'CircularString (0 0, 0.14644660940672 0.35355339059327, 0.5 0.5, 0.85355339059327 0.35355339059327, 1 0, 0.85355339059327 -0.35355339059327, 0.5 -0.5, 0.14644660940672 -0.35355339059327, 0 0)'] + "CompoundCurveM ((0 -23.43778 10, 0 23.43778 10),CircularStringM (0 23.43778 10, -45 33.43778 10, -90 23.43778 10),(-90 23.43778 10, -90 -23.43778 10),CircularStringM (-90 -23.43778 10, -45 -23.43778 10, 0 -23.43778 10))", + "CurvePolygonM (CompoundCurveM ((0 -23.43778 10, 0 -15.43778 10, 0 23.43778 10),CircularStringM (0 23.43778 10, -45 100 10, -90 23.43778 10),(-90 23.43778 10, -90 -23.43778 10),CircularStringM (-90 -23.43778 10, -45 -16.43778 10, 0 -23.43778 10)),CompoundCurveM (CircularStringM (-30 0 10, -48 -12 10, -60 0 10, -48 -6 10, -30 0 10)))", + "CircularStringM (0 0 10, 0.14644660940672 0.35355339059327 10, 0.5 0.5 10, 0.85355339059327 0.35355339059327 10, 1 0 10, 0.85355339059327 -0.35355339059327 10, 0.5 -0.5 10, 0.14644660940672 -0.35355339059327 10, 0 0 10)", + "CompoundCurveZM ((0 -23.43778 2 10, 0 23.43778 2 10),CircularStringZM (0 23.43778 2 10, -45 33.43778 2 10, -90 23.43778 2 10),(-90 23.43778 2 10, -90 -23.43778 2 10),CircularStringZM (-90 -23.43778 2 10, -45 -23.43778 2 10, 0 -23.43778 2 10))", + "CurvePolygonZM (CompoundCurveZM ((0 -23.43778 5 10, 0 -15.43778 8 10, 0 23.43778 6 10),CircularStringZM (0 23.43778 6 10, -45 100 6 10, -90 23.43778 6 10),(-90 23.43778 6 10, -90 -23.43778 5 10),CircularStringZM (-90 -23.43778 5 10, -45 -16.43778 5 10, 0 -23.43778 5 10)),CompoundCurveZM (CircularStringZM (-30 0 10 10, -48 -12 10 10, -60 0 10 10, -48 -6 10 10, -30 0 10 10)))", + "CircularStringZM (0 0 1 10, 0.14644660940672 0.35355339059327 1 10, 0.5 0.5 1 10, 0.85355339059327 0.35355339059327 1 10, 1 0 1 10, 0.85355339059327 -0.35355339059327 1 10, 0.5 -0.5 1 10, 0.14644660940672 -0.35355339059327 1 10, 0 0 1 10)", + "CompoundCurveZ ((0 -23.43778 2, 0 23.43778 2),CircularStringZ (0 23.43778 2, -45 33.43778 2, -90 23.43778 2),(-90 23.43778 2, -90 -23.43778 2),CircularStringZ (-90 -23.43778 2, -45 -23.43778 2, 0 -23.43778 2))", + "CurvePolygonZ (CompoundCurveZ ((0 -23.43778 5, 0 -15.43778 8, 0 23.43778 6),CircularStringZ (0 23.43778 6, -45 100 6, -90 23.43778 6),(-90 23.43778 6, -90 -23.43778 5),CircularStringZ (-90 -23.43778 5, -45 -16.43778 5, 0 -23.43778 5)),CompoundCurveZ (CircularStringZ (-30 0 10, -48 -12 10, -60 0 10, -48 -6 10, -30 0 10)))", + "CircularStringZ (0 0 1, 0.14644660940672 0.35355339059327 1, 0.5 0.5 1, 0.85355339059327 0.35355339059327 1, 1 0 1, 0.85355339059327 -0.35355339059327 1, 0.5 -0.5 1, 0.14644660940672 -0.35355339059327 1, 0 0 1)", + "CompoundCurve ((0 -23.43778, 0 23.43778),CircularString (0 23.43778, -45 33.43778, -90 23.43778),(-90 23.43778, -90 -23.43778),CircularString (-90 -23.43778, -45 -23.43778, 0 -23.43778))", + "CurvePolygon (CompoundCurve ((0 -23.43778, 0 -15.43778, 0 23.43778),CircularString (0 23.43778, -45 100, -90 23.43778),(-90 23.43778, -90 -23.43778),CircularString (-90 -23.43778, -45 -16.43778, 0 -23.43778)),CompoundCurve (CircularString (-30 0, -48 -12, -60 0, -48 -6, -30 0)))", + "CircularString (0 0, 0.14644660940672 0.35355339059327, 0.5 0.5, 0.85355339059327 0.35355339059327, 1 0, 0.85355339059327 -0.35355339059327, 0.5 -0.5, 0.14644660940672 -0.35355339059327, 0 0)", + ] for idx, t in enumerate(geoms): f = QgsFeature() g = QgsGeometry.fromWkt(t) f.setGeometry(g) - layer = QgsVectorLayer(geomtypes[idx] + "?crs=epsg:4326", "addfeat", "memory") + layer = QgsVectorLayer( + geomtypes[idx] + "?crs=epsg:4326", "addfeat", "memory" + ) pr = layer.dataProvider() pr.addFeatures([f]) - uri = self.dbconn + ' table="qgis_test"."new_table_curvegeom_' + str(idx) + '" sql=' - error, message = QgsVectorLayerExporter.exportLayer(layer, uri, 'mssql', - QgsCoordinateReferenceSystem('EPSG:4326')) + uri = ( + self.dbconn + + ' table="qgis_test"."new_table_curvegeom_' + + str(idx) + + '" sql=' + ) + error, message = QgsVectorLayerExporter.exportLayer( + layer, uri, "mssql", QgsCoordinateReferenceSystem("EPSG:4326") + ) self.assertEqual(error, QgsVectorLayerExporter.ExportError.NoError) - new_layer = QgsVectorLayer(uri, 'new', 'mssql') + new_layer = QgsVectorLayer(uri, "new", "mssql") self.assertTrue(new_layer.isValid()) self.assertEqual(new_layer.wkbType(), g.wkbType()) - self.assertEqual(new_layer.crs().authid(), 'EPSG:4326') + self.assertEqual(new_layer.crs().authid(), "EPSG:4326") result_geoms = [f.geometry().asWkt(14) for f in new_layer.getFeatures()] self.assertEqual(result_geoms, [t]) - self.execSQLCommand(f'DROP TABLE IF EXISTS [qgis_test].[new_table_curvegeom_{str(idx)}]') + self.execSQLCommand( + f"DROP TABLE IF EXISTS [qgis_test].[new_table_curvegeom_{str(idx)}]" + ) def testStyle(self): - self.execSQLCommand('DROP TABLE IF EXISTS layer_styles') + self.execSQLCommand("DROP TABLE IF EXISTS layer_styles") - res, err = QgsProviderRegistry.instance().styleExists('mssql', 'not valid', '') + res, err = QgsProviderRegistry.instance().styleExists("mssql", "not valid", "") self.assertFalse(res) self.assertTrue(err) vl = self.getSource() self.assertTrue(vl.isValid()) - self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, Qgis.ProviderStyleStorageCapability.LoadFromDatabase) - self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.SaveToDatabase, Qgis.ProviderStyleStorageCapability.SaveToDatabase) + self.assertEqual( + int(vl.dataProvider().styleStorageCapabilities()) + & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, + Qgis.ProviderStyleStorageCapability.LoadFromDatabase, + ) + self.assertEqual( + int(vl.dataProvider().styleStorageCapabilities()) + & Qgis.ProviderStyleStorageCapability.SaveToDatabase, + Qgis.ProviderStyleStorageCapability.SaveToDatabase, + ) # table layer_styles does not exist - res, err = QgsProviderRegistry.instance().styleExists('mssql', vl.source(), '') + res, err = QgsProviderRegistry.instance().styleExists("mssql", vl.source(), "") self.assertFalse(res) self.assertFalse(err) - res, err = QgsProviderRegistry.instance().styleExists('mssql', vl.source(), 'a style') + res, err = QgsProviderRegistry.instance().styleExists( + "mssql", vl.source(), "a style" + ) self.assertFalse(res) self.assertFalse(err) @@ -427,22 +506,28 @@ def testStyle(self): self.assertTrue(errmsg) mFilePath = QDir.toNativeSeparators( - f"{unitTestDataPath()}/symbol_layer/singleSymbol.qml") + f"{unitTestDataPath()}/symbol_layer/singleSymbol.qml" + ) status = vl.loadNamedStyle(mFilePath) self.assertTrue(status) # The style is saved as non-default errorMsg = vl.saveStyleToDatabase( - "by day", "faded greens and elegant patterns", False, "") + "by day", "faded greens and elegant patterns", False, "" + ) self.assertFalse(errorMsg) - res, err = QgsProviderRegistry.instance().styleExists('mssql', vl.source(), '') + res, err = QgsProviderRegistry.instance().styleExists("mssql", vl.source(), "") self.assertFalse(res) self.assertFalse(err) - res, err = QgsProviderRegistry.instance().styleExists('mssql', vl.source(), 'a style') + res, err = QgsProviderRegistry.instance().styleExists( + "mssql", vl.source(), "a style" + ) self.assertFalse(res) self.assertFalse(err) - res, err = QgsProviderRegistry.instance().styleExists('mssql', vl.source(), 'by day') + res, err = QgsProviderRegistry.instance().styleExists( + "mssql", vl.source(), "by day" + ) self.assertTrue(res) self.assertFalse(err) @@ -463,30 +548,40 @@ def testStyle(self): self.assertTrue(errmsg) qml, errmsg = vl.getStyleFromDatabase("1") - self.assertTrue(qml.startswith(' 100 and [cnt] < 410' + return "[cnt] > 100 and [cnt] < 410" def getSubsetString2(self): - return '[cnt] > 100 and [cnt] < 400' + return "[cnt] > 100 and [cnt] < 400" def getSubsetString3(self): - return '[name]=\'Apple\'' + return "[name]='Apple'" def getSubsetStringNoMatching(self): - return '[name]=\'AppleBearOrangePear\'' + return "[name]='AppleBearOrangePear'" def testExtentFromGeometryTable(self): """ Check if the behavior of the mssql provider if extent is defined in the geometry_column table """ # Create a layer - layer = QgsVectorLayer("Point?field=id:integer&field=fldtxt:string&field=fldint:integer", - "layer", "memory") + layer = QgsVectorLayer( + "Point?field=id:integer&field=fldtxt:string&field=fldint:integer", + "layer", + "memory", + ) pr = layer.dataProvider() f1 = QgsFeature() f1.setAttributes([1, "test", 1]) @@ -908,63 +1187,87 @@ def testExtentFromGeometryTable(self): f4.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(4, 3))) pr.addFeatures([f1, f2, f3, f4]) uri = f'{self.dbconn} table="qgis_test"."layer_extent_in_geometry_table" sql=' - QgsVectorLayerExporter.exportLayer(layer, uri, 'mssql', QgsCoordinateReferenceSystem('EPSG:4326')) + QgsVectorLayerExporter.exportLayer( + layer, uri, "mssql", QgsCoordinateReferenceSystem("EPSG:4326") + ) layerUri = QgsDataSourceUri(uri) # Load and check if the layer is valid loadedLayer = QgsVectorLayer(layerUri.uri(), "valid", "mssql") self.assertTrue(loadedLayer.isValid()) extent = loadedLayer.extent() - self.assertEqual(extent.toString(1), - QgsRectangle(1.0, 2.0, 4.0, 3.0).toString(1)) + self.assertEqual( + extent.toString(1), QgsRectangle(1.0, 2.0, 4.0, 3.0).toString(1) + ) # Load with flag extent in geometry_columns table and check if the layer is still valid and extent doesn't change - layerUri.setParam('extentInGeometryColumns', '1') + layerUri.setParam("extentInGeometryColumns", "1") loadedLayer = QgsVectorLayer(layerUri.uri(), "invalid", "mssql") self.assertTrue(loadedLayer.isValid()) extent = loadedLayer.extent() - self.assertEqual(extent.toString(1), - QgsRectangle(1.0, 2.0, 4.0, 3.0).toString(1)) + self.assertEqual( + extent.toString(1), QgsRectangle(1.0, 2.0, 4.0, 3.0).toString(1) + ) - md = QgsProviderRegistry.instance().providerMetadata('mssql') + md = QgsProviderRegistry.instance().providerMetadata("mssql") conn = md.createConnection(self.dbconn, {}) - conn.addField(QgsField('qgis_xmin', QVariant.Double, 'FLOAT(24)'), 'dbo', 'geometry_columns') - conn.addField(QgsField('qgis_xmax', QVariant.Double, 'FLOAT(24)'), 'dbo', 'geometry_columns') - conn.addField(QgsField('qgis_ymin', QVariant.Double, 'FLOAT(24)'), 'dbo', 'geometry_columns') - conn.addField(QgsField('qgis_ymax', QVariant.Double, 'FLOAT(24)'), 'dbo', 'geometry_columns') + conn.addField( + QgsField("qgis_xmin", QVariant.Double, "FLOAT(24)"), + "dbo", + "geometry_columns", + ) + conn.addField( + QgsField("qgis_xmax", QVariant.Double, "FLOAT(24)"), + "dbo", + "geometry_columns", + ) + conn.addField( + QgsField("qgis_ymin", QVariant.Double, "FLOAT(24)"), + "dbo", + "geometry_columns", + ) + conn.addField( + QgsField("qgis_ymax", QVariant.Double, "FLOAT(24)"), + "dbo", + "geometry_columns", + ) # try with empty attribute - layerUri.setParam('extentInGeometryColumns', '1') + layerUri.setParam("extentInGeometryColumns", "1") loadedLayer = QgsVectorLayer(layerUri.uri(), "invalid", "mssql") self.assertTrue(loadedLayer.isValid()) self.assertTrue(loadedLayer.isValid()) extent = loadedLayer.extent() - self.assertEqual(extent.toString(1), - QgsRectangle(1.0, 2.0, 4.0, 3.0).toString(1)) + self.assertEqual( + extent.toString(1), QgsRectangle(1.0, 2.0, 4.0, 3.0).toString(1) + ) - conn.execSql('UPDATE dbo.geometry_columns SET qgis_xmin=0, qgis_xmax=5.5, qgis_ymin=0.5, qgis_ymax=6 WHERE f_table_name=\'layer_extent_in_geometry_table\'') + conn.execSql( + "UPDATE dbo.geometry_columns SET qgis_xmin=0, qgis_xmax=5.5, qgis_ymin=0.5, qgis_ymax=6 WHERE f_table_name='layer_extent_in_geometry_table'" + ) # try with valid attribute - layerUri.setParam('extentInGeometryColumns', '1') + layerUri.setParam("extentInGeometryColumns", "1") loadedLayer = QgsVectorLayer(layerUri.uri(), "valid", "mssql") self.assertTrue(loadedLayer.isValid()) extent = loadedLayer.extent() - self.assertEqual(extent.toString(1), - QgsRectangle(0.0, 0.5, 5.5, 6.0).toString(1)) + self.assertEqual( + extent.toString(1), QgsRectangle(0.0, 0.5, 5.5, 6.0).toString(1) + ) def test_insert_pk_escaping(self): """ Test that inserting features works with complex pk name see https://github.com/qgis/QGIS/issues/42290 """ - md = QgsProviderRegistry.instance().providerMetadata('mssql') + md = QgsProviderRegistry.instance().providerMetadata("mssql") conn = md.createConnection(self.dbconn, {}) - conn.execSql('DROP TABLE IF EXISTS qgis_test.test_complex_pk_name') - conn.execSql('CREATE TABLE qgis_test.test_complex_pk_name ([test-field] int)') + conn.execSql("DROP TABLE IF EXISTS qgis_test.test_complex_pk_name") + conn.execSql("CREATE TABLE qgis_test.test_complex_pk_name ([test-field] int)") uri = f'{self.dbconn} table="qgis_test"."test_complex_pk_name" sql=' - vl = QgsVectorLayer(uri, '', 'mssql') + vl = QgsVectorLayer(uri, "", "mssql") self.assertTrue(vl.isValid()) self.assertEqual(vl.primaryKeyAttributes(), [0]) @@ -975,27 +1278,33 @@ def test_insert_pk_escaping(self): self.assertTrue(vl.addFeature(f)) self.assertTrue(vl.commitChanges()) - vl = QgsVectorLayer(uri, '', 'mssql') + vl = QgsVectorLayer(uri, "", "mssql") features = list(vl.getFeatures()) - self.assertEqual([f['test-field'] for f in features], [1]) + self.assertEqual([f["test-field"] for f in features], [1]) def test_nvarchar_length(self): """ Test that nvarchar length is correctly set """ - md = QgsProviderRegistry.instance().providerMetadata('mssql') + md = QgsProviderRegistry.instance().providerMetadata("mssql") conn = md.createConnection(self.dbconn, {}) - conn.execSql('DROP TABLE IF EXISTS qgis_test.test_nvarchar_length') - conn.execSql('CREATE TABLE qgis_test.test_nvarchar_length (id integer PRIMARY KEY)') + conn.execSql("DROP TABLE IF EXISTS qgis_test.test_nvarchar_length") + conn.execSql( + "CREATE TABLE qgis_test.test_nvarchar_length (id integer PRIMARY KEY)" + ) uri = f'{self.dbconn} table="qgis_test"."test_nvarchar_length" sql=' - vl = QgsVectorLayer(uri, '', 'mssql') + vl = QgsVectorLayer(uri, "", "mssql") self.assertTrue(vl.isValid()) - self.assertTrue(vl.dataProvider().addAttributes([QgsField('name', QMetaType.Type.QString, 'nvarchar', 12)])) + self.assertTrue( + vl.dataProvider().addAttributes( + [QgsField("name", QMetaType.Type.QString, "nvarchar", 12)] + ) + ) self.assertEqual(vl.dataProvider().fields().at(1).length(), 12) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_provider_oapif.py b/tests/src/python/test_provider_oapif.py index 47b8d42d8f5b..1cbc6578d7c9 100644 --- a/tests/src/python/test_provider_oapif.py +++ b/tests/src/python/test_provider_oapif.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Even Rouault' -__date__ = '2019-10-12' -__copyright__ = 'Copyright 2019, Even Rouault' + +__author__ = "Even Rouault" +__date__ = "2019-10-12" +__copyright__ = "Copyright 2019, Even Rouault" import copy import hashlib @@ -43,11 +44,13 @@ def sanitize(endpoint, query_params): url = endpoint + query_params # For REST API using URL subpaths, normalize the subpaths - afterEndpointStartPos = url.find("fake_qgis_http_endpoint") + len("fake_qgis_http_endpoint") + afterEndpointStartPos = url.find("fake_qgis_http_endpoint") + len( + "fake_qgis_http_endpoint" + ) afterEndpointStart = url[afterEndpointStartPos:] - afterEndpointStart = afterEndpointStart.replace('/', '_') + afterEndpointStart = afterEndpointStart.replace("/", "_") url = url[0:afterEndpointStartPos] + afterEndpointStart - posQuotationMark = url.find('?') + posQuotationMark = url.find("?") endpoint = url[0:posQuotationMark] query_params = url[posQuotationMark:] @@ -56,23 +59,28 @@ def sanitize(endpoint, query_params): # print('Before: ' + endpoint + query_params) # print('After: ' + ret) return ret - ret = endpoint + query_params.replace('?', '_').replace('&', '_').replace('<', '_').replace('>', '_').replace('"', - '_').replace("'", - '_').replace( - ' ', '_').replace(':', '_').replace('/', '_').replace('\n', '_') + ret = endpoint + query_params.replace("?", "_").replace("&", "_").replace( + "<", "_" + ).replace(">", "_").replace('"', "_").replace("'", "_").replace(" ", "_").replace( + ":", "_" + ).replace( + "/", "_" + ).replace( + "\n", "_" + ) return ret def GDAL_COMPUTE_VERSION(maj, min, rev): - return ((maj) * 1000000 + (min) * 10000 + (rev) * 100) + return (maj) * 1000000 + (min) * 10000 + (rev) * 100 -ACCEPT_LANDING = 'Accept=application/json' -ACCEPT_API = 'Accept=application/vnd.oai.openapi+json;version=3.0, application/openapi+json;version=3.0, application/json' -ACCEPT_COLLECTION = 'Accept=application/json' -ACCEPT_CONFORMANCE = 'Accept=application/json' -ACCEPT_ITEMS = 'Accept=application/geo+json, application/json' -ACCEPT_QUERYABLES = 'Accept=application/schema+json' +ACCEPT_LANDING = "Accept=application/json" +ACCEPT_API = "Accept=application/vnd.oai.openapi+json;version=3.0, application/openapi+json;version=3.0, application/json" +ACCEPT_COLLECTION = "Accept=application/json" +ACCEPT_CONFORMANCE = "Accept=application/json" +ACCEPT_ITEMS = "Accept=application/geo+json, application/json" +ACCEPT_QUERYABLES = "Accept=application/schema+json" def mergeDict(d1, d2): @@ -85,63 +93,97 @@ def mergeDict(d1, d2): return res -def create_landing_page_api_collection(endpoint, - extraparam='', - storageCrs=None, - crsList=None, - bbox=[-71.123, 66.33, -65.32, 78.3], - additionalApiResponse={}, - additionalConformance=[]): +def create_landing_page_api_collection( + endpoint, + extraparam="", + storageCrs=None, + crsList=None, + bbox=[-71.123, 66.33, -65.32, 78.3], + additionalApiResponse={}, + additionalConformance=[], +): - questionmark_extraparam = '?' + extraparam if extraparam else '' + questionmark_extraparam = "?" + extraparam if extraparam else "" def add_params(x, y): if x: - return x + '&' + y + return x + "&" + y return y # Landing page - with open(sanitize(endpoint, '?' + add_params(extraparam, ACCEPT_LANDING)), 'wb') as f: - f.write(json.dumps({ - "links": [ - {"href": "http://" + endpoint + "/api" + questionmark_extraparam, "rel": "service-desc"}, - {"href": "http://" + endpoint + "/collections" + questionmark_extraparam, "rel": "data"}, - {"href": "http://" + endpoint + "/conformance" + questionmark_extraparam, "rel": "conformance"}, - ]}).encode('UTF-8')) + with open( + sanitize(endpoint, "?" + add_params(extraparam, ACCEPT_LANDING)), "wb" + ) as f: + f.write( + json.dumps( + { + "links": [ + { + "href": "http://" + + endpoint + + "/api" + + questionmark_extraparam, + "rel": "service-desc", + }, + { + "href": "http://" + + endpoint + + "/collections" + + questionmark_extraparam, + "rel": "data", + }, + { + "href": "http://" + + endpoint + + "/conformance" + + questionmark_extraparam, + "rel": "conformance", + }, + ] + } + ).encode("UTF-8") + ) # API - with open(sanitize(endpoint, '/api?' + add_params(extraparam, ACCEPT_API)), 'wb') as f: - j = mergeDict(additionalApiResponse, {"components": { - "parameters": { - "limit": { - "schema": { - "maximum": 1000, - "default": 100 + with open( + sanitize(endpoint, "/api?" + add_params(extraparam, ACCEPT_API)), "wb" + ) as f: + j = mergeDict( + additionalApiResponse, + { + "components": { + "parameters": { + "limit": {"schema": {"maximum": 1000, "default": 100}} } } - } - } - }) - f.write(json.dumps(j).encode('UTF-8')) + }, + ) + f.write(json.dumps(j).encode("UTF-8")) # conformance - with open(sanitize(endpoint, '/conformance?' + add_params(extraparam, ACCEPT_CONFORMANCE)), 'wb') as f: - f.write(json.dumps({ - "conformsTo": ["http://www.opengis.net/spec/ogcapi-features-2/1.0/conf/crs"] + additionalConformance - }).encode('UTF-8')) + with open( + sanitize( + endpoint, "/conformance?" + add_params(extraparam, ACCEPT_CONFORMANCE) + ), + "wb", + ) as f: + f.write( + json.dumps( + { + "conformsTo": [ + "http://www.opengis.net/spec/ogcapi-features-2/1.0/conf/crs" + ] + + additionalConformance + } + ).encode("UTF-8") + ) # collection collection = { "id": "mycollection", "title": "my title", "description": "my description", - "extent": { - "spatial": { - "bbox": [ - bbox - ] - } - } + "extent": {"spatial": {"bbox": [bbox]}}, } if bbox is None: del collection["extent"] @@ -150,12 +192,20 @@ def add_params(x, y): if crsList: collection["crs"] = crsList - with open(sanitize(endpoint, '/collections/mycollection?' + add_params(extraparam, ACCEPT_COLLECTION)), 'wb') as f: - f.write(json.dumps(collection).encode('UTF-8')) + with open( + sanitize( + endpoint, + "/collections/mycollection?" + add_params(extraparam, ACCEPT_COLLECTION), + ), + "wb", + ) as f: + f.write(json.dumps(collection).encode("UTF-8")) # Options - with open(sanitize(endpoint, '/collections/mycollection/items?VERB=OPTIONS'), 'wb') as f: - f.write("HEAD, GET".encode("UTF-8")) + with open( + sanitize(endpoint, "/collections/mycollection/items?VERB=OPTIONS"), "wb" + ) as f: + f.write(b"HEAD, GET") class TestPyQgsOapifProvider(QgisTestCase, ProviderTestCase): @@ -163,7 +213,7 @@ class TestPyQgsOapifProvider(QgisTestCase, ProviderTestCase): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsOapifProvider, cls).setUpClass() + super().setUpClass() QCoreApplication.setOrganizationName("QGIS_Test") QCoreApplication.setOrganizationDomain("TestPyQgsOapifProvider.com") @@ -173,8 +223,8 @@ def setUpClass(cls): # On Windows we must make sure that any backslash in the path is # replaced by a forward slash so that QUrl can process it - cls.basetestpath = tempfile.mkdtemp().replace('\\', '/') - endpoint = cls.basetestpath + '/fake_qgis_http_endpoint' + cls.basetestpath = tempfile.mkdtemp().replace("\\", "/") + endpoint = cls.basetestpath + "/fake_qgis_http_endpoint" create_landing_page_api_collection(endpoint) @@ -182,38 +232,112 @@ def setUpClass(cls): "type": "FeatureCollection", "numberMatched": 5, "features": [ - {"type": "Feature", "id": "feat.1", - "properties": {"pk": 1, "cnt": 100, "name": "Orange", "name2": "oranGe", "num_char": "1", "dt": "2020-05-03 12:13:14", "date": "2020-05-03", "time": "12:13:14"}, - "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}}, - {"type": "Feature", "id": "feat.2", - "properties": {"pk": 2, "cnt": 200, "name": "Apple", "name2": "Apple", "num_char": "2", "dt": "2020-05-04 12:14:14", "date": "2020-05-04", "time": "12:14:14"}, - "geometry": {"type": "Point", "coordinates": [-68.2, 70.8]}}, - {"type": "Feature", "id": "feat.3", - "properties": {"pk": 4, "cnt": 400, "name": "Honey", "name2": "Honey", "num_char": "4", "dt": "2021-05-04 13:13:14", "date": "2021-05-04", "time": "13:13:14"}, - "geometry": {"type": "Point", "coordinates": [-65.32, 78.3]}}, - {"type": "Feature", "id": "feat.4", - "properties": {"pk": 3, "cnt": 300, "name": "Pear", "name2": "PEaR", "num_char": "3"}, - "geometry": None}, - {"type": "Feature", "id": "feat.5", - "properties": {"pk": 5, "cnt": -200, "name": None, "name2": "NuLl", "num_char": "5", "dt": "2020-05-04 12:13:14", "date": "2020-05-02", "time": "12:13:01"}, - "geometry": {"type": "Point", "coordinates": [-71.123, 78.23]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": { + "pk": 1, + "cnt": 100, + "name": "Orange", + "name2": "oranGe", + "num_char": "1", + "dt": "2020-05-03 12:13:14", + "date": "2020-05-03", + "time": "12:13:14", + }, + "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}, + }, + { + "type": "Feature", + "id": "feat.2", + "properties": { + "pk": 2, + "cnt": 200, + "name": "Apple", + "name2": "Apple", + "num_char": "2", + "dt": "2020-05-04 12:14:14", + "date": "2020-05-04", + "time": "12:14:14", + }, + "geometry": {"type": "Point", "coordinates": [-68.2, 70.8]}, + }, + { + "type": "Feature", + "id": "feat.3", + "properties": { + "pk": 4, + "cnt": 400, + "name": "Honey", + "name2": "Honey", + "num_char": "4", + "dt": "2021-05-04 13:13:14", + "date": "2021-05-04", + "time": "13:13:14", + }, + "geometry": {"type": "Point", "coordinates": [-65.32, 78.3]}, + }, + { + "type": "Feature", + "id": "feat.4", + "properties": { + "pk": 3, + "cnt": 300, + "name": "Pear", + "name2": "PEaR", + "num_char": "3", + }, + "geometry": None, + }, + { + "type": "Feature", + "id": "feat.5", + "properties": { + "pk": 5, + "cnt": -200, + "name": None, + "name2": "NuLl", + "num_char": "5", + "dt": "2020-05-04 12:13:14", + "date": "2020-05-02", + "time": "12:13:01", + }, + "geometry": {"type": "Point", "coordinates": [-71.123, 78.23]}, + }, + ], } # limit 1 for getting count - with open(sanitize(endpoint, '/collections/mycollection/items?limit=1&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=1&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(items).encode("UTF-8")) # first items - with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(items).encode("UTF-8")) # real page - with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=1000&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(items).encode("UTF-8")) # Create test layer - cls.vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF') + cls.vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF" + ) assert cls.vl.isValid() cls.source = cls.vl.dataProvider() @@ -222,11 +346,13 @@ def tearDownClass(cls): """Run after all tests""" QgsSettings().clear() shutil.rmtree(cls.basetestpath, True) - cls.vl = None # so as to properly close the provider and remove any temporary file - super(TestPyQgsOapifProvider, cls).tearDownClass() + cls.vl = ( + None # so as to properly close the provider and remove any temporary file + ) + super().tearDownClass() def testCrs(self): - self.assertEqual(self.source.sourceCrs().authid(), 'OGC:CRS84') + self.assertEqual(self.source.sourceCrs().authid(), "OGC:CRS84") def testExtentSubsetString(self): # can't run the base provider test suite here - WFS/OAPIF extent handling is different @@ -235,195 +361,300 @@ def testExtentSubsetString(self): def testFeaturePaging(self): - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testFeaturePaging' + endpoint = ( + self.__class__.basetestpath + "/fake_qgis_http_endpoint_testFeaturePaging" + ) create_landing_page_api_collection(endpoint) # first items first_items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100}, - "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": {"pk": 1, "cnt": 100}, + "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}, + } + ], } - with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(first_items).encode("UTF-8")) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF" + ) self.assertTrue(vl.isValid()) # first real page first_page = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100}, - "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}}, - {"type": "Feature", "id": "feat.2", "properties": {"pk": 2, "cnt": 200}, - "geometry": {"type": "Point", "coordinates": [-68.2, 70.8]}} + { + "type": "Feature", + "id": "feat.1", + "properties": {"pk": 1, "cnt": 100}, + "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}, + }, + { + "type": "Feature", + "id": "feat.2", + "properties": {"pk": 2, "cnt": 200}, + "geometry": {"type": "Point", "coordinates": [-68.2, 70.8]}, + }, ], "links": [ # Test multiple media types for next - {"href": "http://" + endpoint + "/second_page.html", "rel": "next", "type": "text/html"}, - {"href": "http://" + endpoint + "/second_page", "rel": "next", "type": "application/geo+json"}, - {"href": "http://" + endpoint + "/second_page.xml", "rel": "next", "type": "text/xml"} - ] + { + "href": "http://" + endpoint + "/second_page.html", + "rel": "next", + "type": "text/html", + }, + { + "href": "http://" + endpoint + "/second_page", + "rel": "next", + "type": "application/geo+json", + }, + { + "href": "http://" + endpoint + "/second_page.xml", + "rel": "next", + "type": "text/xml", + }, + ], } - with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_page).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=1000&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(first_page).encode("UTF-8")) # second page second_page = { "type": "FeatureCollection", "features": [ # Also add a non expected property - {"type": "Feature", "id": "feat.3", "properties": {"a_non_expected": "foo", "pk": 4, "cnt": 400}, - "geometry": {"type": "Point", "coordinates": [-65.32, 78.3]}} + { + "type": "Feature", + "id": "feat.3", + "properties": {"a_non_expected": "foo", "pk": 4, "cnt": 400}, + "geometry": {"type": "Point", "coordinates": [-65.32, 78.3]}, + } ], - "links": [ - {"href": "http://" + endpoint + "/third_page", "rel": "next"} - ] + "links": [{"href": "http://" + endpoint + "/third_page", "rel": "next"}], } - with open(sanitize(endpoint, '/second_page?' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(second_page).encode('UTF-8')) + with open(sanitize(endpoint, "/second_page?" + ACCEPT_ITEMS), "wb") as f: + f.write(json.dumps(second_page).encode("UTF-8")) # third page third_page = { "type": "FeatureCollection", "features": [], "links": [ - {"href": "http://" + endpoint + "/third_page", "rel": "next"} # dummy link to ourselves - ] + { + "href": "http://" + endpoint + "/third_page", + "rel": "next", + } # dummy link to ourselves + ], } - with open(sanitize(endpoint, '/third_page?' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(third_page).encode('UTF-8')) + with open(sanitize(endpoint, "/third_page?" + ACCEPT_ITEMS), "wb") as f: + f.write(json.dumps(third_page).encode("UTF-8")) - values = [f['pk'] for f in vl.getFeatures()] + values = [f["pk"] for f in vl.getFeatures()] self.assertEqual(values, [1, 2, 4]) - values = [f['pk'] for f in vl.getFeatures()] + values = [f["pk"] for f in vl.getFeatures()] self.assertEqual(values, [1, 2, 4]) def testBbox(self): - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testBbox' - create_landing_page_api_collection(endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/4326") + endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_testBbox" + create_landing_page_api_collection( + endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/4326" + ) # first items first_items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100}, - "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": {"pk": 1, "cnt": 100}, + "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}, + } + ], } - with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(first_items).encode("UTF-8")) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test', - 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='mycollection' restrictToRequestBBOX=1", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100}, - "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}}, - {"type": "Feature", "id": "feat.2", "properties": {"pk": 2, "cnt": 200}, - "geometry": {"type": "Point", "coordinates": [70.8, -68.2]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": {"pk": 1, "cnt": 100}, + "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}, + }, + { + "type": "Feature", + "id": "feat.2", + "properties": {"pk": 2, "cnt": 200}, + "geometry": {"type": "Point", "coordinates": [70.8, -68.2]}, + }, + ], } - with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&bbox=65.5,-71,78,-65&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/4326&crs=http://www.opengis.net/def/crs/EPSG/0/4326&' + ACCEPT_ITEMS), - 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + with open( + sanitize( + endpoint, + "/collections/mycollection/items?limit=1000&bbox=65.5,-71,78,-65&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/4326&crs=http://www.opengis.net/def/crs/EPSG/0/4326&" + + ACCEPT_ITEMS, + ), + "wb", + ) as f: + f.write(json.dumps(items).encode("UTF-8")) extent = QgsRectangle(-71, 65.5, -65, 78) request = QgsFeatureRequest().setFilterRect(extent) - values = [f['pk'] for f in vl.getFeatures(request)] + values = [f["pk"] for f in vl.getFeatures(request)] self.assertEqual(values, [1, 2]) # Test request inside above one EPS = 0.1 extent = QgsRectangle(-71 + EPS, 65.5 + EPS, -65 - EPS, 78 - EPS) request = QgsFeatureRequest().setFilterRect(extent) - values = [f['pk'] for f in vl.getFeatures(request)] + values = [f["pk"] for f in vl.getFeatures(request)] self.assertEqual(values, [1, 2]) # Test clamping of bbox with open( - sanitize(endpoint, '/collections/mycollection/items?limit=1000&bbox=64.5,-180,78,-65&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/4326&crs=http://www.opengis.net/def/crs/EPSG/0/4326&' + ACCEPT_ITEMS), - 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + sanitize( + endpoint, + "/collections/mycollection/items?limit=1000&bbox=64.5,-180,78,-65&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/4326&crs=http://www.opengis.net/def/crs/EPSG/0/4326&" + + ACCEPT_ITEMS, + ), + "wb", + ) as f: + f.write(json.dumps(items).encode("UTF-8")) extent = QgsRectangle(-190, 64.5, -65, 78) request = QgsFeatureRequest().setFilterRect(extent) - values = [f['pk'] for f in vl.getFeatures(request)] + values = [f["pk"] for f in vl.getFeatures(request)] self.assertEqual(values, [1, 2]) # Test request completely outside of -180,-90,180,90 extent = QgsRectangle(-1000, -1000, -900, -900) request = QgsFeatureRequest().setFilterRect(extent) - values = [f['pk'] for f in vl.getFeatures(request)] + values = [f["pk"] for f in vl.getFeatures(request)] self.assertEqual(values, []) # Test request containing -180,-90,180,90 items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100}, - "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}}, - {"type": "Feature", "id": "feat.2", "properties": {"pk": 2, "cnt": 200}, - "geometry": {"type": "Point", "coordinates": [70.8, -68.2]}}, - {"type": "Feature", "id": "feat.3", "properties": {"pk": 4, "cnt": 400}, - "geometry": {"type": "Point", "coordinates": [78.3, -65.32]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": {"pk": 1, "cnt": 100}, + "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}, + }, + { + "type": "Feature", + "id": "feat.2", + "properties": {"pk": 2, "cnt": 200}, + "geometry": {"type": "Point", "coordinates": [70.8, -68.2]}, + }, + { + "type": "Feature", + "id": "feat.3", + "properties": {"pk": 4, "cnt": 400}, + "geometry": {"type": "Point", "coordinates": [78.3, -65.32]}, + }, + ], } - with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&bbox=-90,-180,90,180&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/4326&crs=http://www.opengis.net/def/crs/EPSG/0/4326&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + with open( + sanitize( + endpoint, + "/collections/mycollection/items?limit=1000&bbox=-90,-180,90,180&bbox-crs=http://www.opengis.net/def/crs/EPSG/0/4326&crs=http://www.opengis.net/def/crs/EPSG/0/4326&" + + ACCEPT_ITEMS, + ), + "wb", + ) as f: + f.write(json.dumps(items).encode("UTF-8")) extent = QgsRectangle(-181, -91, 181, 91) request = QgsFeatureRequest().setFilterRect(extent) - values = [f['pk'] for f in vl.getFeatures(request)] + values = [f["pk"] for f in vl.getFeatures(request)] self.assertEqual(values, [1, 2, 4]) def testLayerMetadata(self): - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testLayerMetadata' + endpoint = ( + self.__class__.basetestpath + "/fake_qgis_http_endpoint_testLayerMetadata" + ) create_landing_page_api_collection(endpoint) # first items first_items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100}, - "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": {"pk": 1, "cnt": 100}, + "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}, + } + ], } - with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(first_items).encode("UTF-8")) # API - with open(sanitize(endpoint, '/api?' + ACCEPT_API), 'wb') as f: - f.write(json.dumps({ - "components": { - "parameters": { - "limit": { - "schema": { - "maximum": 1000, - "default": 100 - } - } - } - }, - "info": + with open(sanitize(endpoint, "/api?" + ACCEPT_API), "wb") as f: + f.write( + json.dumps( { - "contact": - { + "components": { + "parameters": { + "limit": {"schema": {"maximum": 1000, "default": 100}} + } + }, + "info": { + "contact": { "name": "contact_name", "email": "contact_email", - "url": "contact_url" + "url": "contact_url", } - } - }).encode('UTF-8')) + }, + } + ).encode("UTF-8") + ) # collection base_collection = { @@ -437,75 +668,99 @@ def testLayerMetadata(self): None, # invalid [1, 2, 3], # invalid ["invalid", 1, 2, 3], # invalid - [2, 49, -100, 3, 50, 100] + [2, 49, -100, 3, 50, 100], + ] + }, + "temporal": { + "interval": [ + [None, None], # invalid + ["invalid", "invalid"], + "another_invalid", + ["1980-01-01T12:34:56.789Z", "2020-01-01T00:00:00Z"], + ["1980-01-01T12:34:56.789Z", None], + [None, "2020-01-01T00:00:00Z"], ] }, - "temporal": - { - "interval": [ - [None, None], # invalid - ["invalid", "invalid"], - "another_invalid", - ["1980-01-01T12:34:56.789Z", "2020-01-01T00:00:00Z"], - ["1980-01-01T12:34:56.789Z", None], - [None, "2020-01-01T00:00:00Z"] - ] - } }, "links": [ - {"href": "href_self", "rel": "self", "type": "application/json", "title": "my self link"}, + { + "href": "href_self", + "rel": "self", + "type": "application/json", + "title": "my self link", + }, {"href": "href_parent", "rel": "parent", "title": "my parent link"}, - {"href": "http://download.example.org/buildings.gpkg", - "rel": "enclosure", - "type": "application/geopackage+sqlite3", - "title": "Bulk download (GeoPackage)", - "length": 123456789012345} + { + "href": "http://download.example.org/buildings.gpkg", + "rel": "enclosure", + "type": "application/geopackage+sqlite3", + "title": "Bulk download (GeoPackage)", + "length": 123456789012345, + }, ], # STAC specific - "keywords": ["keyword_a", "keyword_b"] - + "keywords": ["keyword_a", "keyword_b"], } collection = copy.deepcopy(base_collection) - collection['links'].append( - {"href": "https://creativecommons.org/publicdomain/zero/1.0/", - "rel": "license", "type": "text/html", - "title": "CC0-1.0"}) - collection['links'].append( - {"href": "https://creativecommons.org/publicdomain/zero/1.0/rdf", - "rel": "license", "type": "application/rdf+xml", - "title": "CC0-1.0"}) - collection['links'].append( - {"href": "https://example.com", - "rel": "license", "type": "text/html", - "title": "Public domain"}) - with open(sanitize(endpoint, '/collections/mycollection?' + ACCEPT_COLLECTION), 'wb') as f: - f.write(json.dumps(collection).encode('UTF-8')) - - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test', - 'OAPIF') + collection["links"].append( + { + "href": "https://creativecommons.org/publicdomain/zero/1.0/", + "rel": "license", + "type": "text/html", + "title": "CC0-1.0", + } + ) + collection["links"].append( + { + "href": "https://creativecommons.org/publicdomain/zero/1.0/rdf", + "rel": "license", + "type": "application/rdf+xml", + "title": "CC0-1.0", + } + ) + collection["links"].append( + { + "href": "https://example.com", + "rel": "license", + "type": "text/html", + "title": "Public domain", + } + ) + with open( + sanitize(endpoint, "/collections/mycollection?" + ACCEPT_COLLECTION), "wb" + ) as f: + f.write(json.dumps(collection).encode("UTF-8")) + + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='mycollection' restrictToRequestBBOX=1", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) md = vl.metadata() - assert md.identifier() == 'href_self' - assert md.parentIdentifier() == 'href_parent' - assert md.type() == 'dataset' - assert md.title() == 'my title' - assert md.abstract() == 'my description' + assert md.identifier() == "href_self" + assert md.parentIdentifier() == "href_parent" + assert md.type() == "dataset" + assert md.title() == "my title" + assert md.abstract() == "my description" contacts = md.contacts() assert len(contacts) == 1 contact = contacts[0] - assert contact.name == 'contact_name' - assert contact.email == 'contact_email' - assert contact.organization == 'contact_url' + assert contact.name == "contact_name" + assert contact.email == "contact_email" + assert contact.organization == "contact_url" assert len(md.licenses()) == 2 - assert md.licenses()[0] == 'CC0-1.0' - assert md.licenses()[1] == 'Public domain' + assert md.licenses()[0] == "CC0-1.0" + assert md.licenses()[1] == "Public domain" - assert 'keywords' in md.keywords() - assert md.keywords()['keywords'] == ["keyword_a", "keyword_b"] + assert "keywords" in md.keywords() + assert md.keywords()["keywords"] == ["keyword_a", "keyword_b"] assert md.crs().isValid() assert md.crs().authid() == "OGC:CRS84" @@ -514,13 +769,13 @@ def testLayerMetadata(self): links = md.links() assert len(links) == 6, len(links) - assert links[0].type == 'WWW:LINK' - assert links[0].url == 'href_self' - assert links[0].name == 'self' - assert links[0].mimeType == 'application/json' - assert links[0].description == 'my self link' - assert links[0].size == '' - assert links[2].size == '123456789012345' + assert links[0].type == "WWW:LINK" + assert links[0].url == "href_self" + assert links[0].name == "self" + assert links[0].mimeType == "application/json" + assert links[0].description == "my self link" + assert links[0].size == "" + assert links[2].size == "123456789012345" extent = md.extent() assert len(extent.spatialExtents()) == 2 @@ -528,16 +783,20 @@ def testLayerMetadata(self): assert spatialExtent.extentCrs.isValid() assert spatialExtent.extentCrs.isGeographic() assert not spatialExtent.extentCrs.hasAxisInverted() - assert spatialExtent.bounds == QgsBox3d(-71.123, 66.33, float("nan"), -65.32, 78.3, float("nan")) + assert spatialExtent.bounds == QgsBox3d( + -71.123, 66.33, float("nan"), -65.32, 78.3, float("nan") + ) spatialExtent = extent.spatialExtents()[1] assert spatialExtent.bounds == QgsBox3d(2, 49, -100, 3, 50, 100) temporalExtents = extent.temporalExtents() assert len(temporalExtents) == 3 - assert temporalExtents[0].begin() == QDateTime.fromString("1980-01-01T12:34:56.789Z", Qt.DateFormat.ISODateWithMs), \ - temporalExtents[0].begin() - assert temporalExtents[0].end() == QDateTime.fromString("2020-01-01T00:00:00Z", Qt.DateFormat.ISODateWithMs), \ - temporalExtents[0].end() + assert temporalExtents[0].begin() == QDateTime.fromString( + "1980-01-01T12:34:56.789Z", Qt.DateFormat.ISODateWithMs + ), temporalExtents[0].begin() + assert temporalExtents[0].end() == QDateTime.fromString( + "2020-01-01T00:00:00Z", Qt.DateFormat.ISODateWithMs + ), temporalExtents[0].end() assert temporalExtents[1].begin().isValid() assert not temporalExtents[1].end().isValid() assert not temporalExtents[2].begin().isValid() @@ -545,77 +804,120 @@ def testLayerMetadata(self): # Variant using STAC license collection = copy.deepcopy(base_collection) - collection['license'] = 'STAC license' - with open(sanitize(endpoint, '/collections/mycollection?' + ACCEPT_COLLECTION), 'wb') as f: - f.write(json.dumps(collection).encode('UTF-8')) + collection["license"] = "STAC license" + with open( + sanitize(endpoint, "/collections/mycollection?" + ACCEPT_COLLECTION), "wb" + ) as f: + f.write(json.dumps(collection).encode("UTF-8")) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test', - 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='mycollection' restrictToRequestBBOX=1", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) md = vl.metadata() assert len(md.licenses()) == 1 - assert md.licenses()[0] == 'STAC license' + assert md.licenses()[0] == "STAC license" # Variant using STAC license=various collection = copy.deepcopy(base_collection) - collection['license'] = 'various' - collection['links'].append( - {"href": "https://creativecommons.org/publicdomain/zero/1.0/", - "rel": "license", "type": "text/html", - "title": "CC0-1.0"}) - with open(sanitize(endpoint, '/collections/mycollection?' + ACCEPT_COLLECTION), 'wb') as f: - f.write(json.dumps(collection).encode('UTF-8')) - - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test', - 'OAPIF') + collection["license"] = "various" + collection["links"].append( + { + "href": "https://creativecommons.org/publicdomain/zero/1.0/", + "rel": "license", + "type": "text/html", + "title": "CC0-1.0", + } + ) + with open( + sanitize(endpoint, "/collections/mycollection?" + ACCEPT_COLLECTION), "wb" + ) as f: + f.write(json.dumps(collection).encode("UTF-8")) + + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='mycollection' restrictToRequestBBOX=1", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) md = vl.metadata() assert len(md.licenses()) == 1 - assert md.licenses()[0] == 'CC0-1.0' + assert md.licenses()[0] == "CC0-1.0" # Variant using STAC license=proprietary collection = copy.deepcopy(base_collection) - collection['license'] = 'proprietary' - collection['links'].append( - {"href": "https://example.com", - "rel": "license", "type": "text/html", - "title": "my proprietary license"}) - with open(sanitize(endpoint, '/collections/mycollection?' + ACCEPT_COLLECTION), 'wb') as f: - f.write(json.dumps(collection).encode('UTF-8')) - - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test', - 'OAPIF') + collection["license"] = "proprietary" + collection["links"].append( + { + "href": "https://example.com", + "rel": "license", + "type": "text/html", + "title": "my proprietary license", + } + ) + with open( + sanitize(endpoint, "/collections/mycollection?" + ACCEPT_COLLECTION), "wb" + ) as f: + f.write(json.dumps(collection).encode("UTF-8")) + + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='mycollection' restrictToRequestBBOX=1", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) md = vl.metadata() assert len(md.licenses()) == 1 - assert md.licenses()[0] == 'my proprietary license' + assert md.licenses()[0] == "my proprietary license" # Variant using STAC license=proprietary (non conformant: missing a rel=license link) collection = copy.deepcopy(base_collection) - collection['license'] = 'proprietary' - with open(sanitize(endpoint, '/collections/mycollection?' + ACCEPT_COLLECTION), 'wb') as f: - f.write(json.dumps(collection).encode('UTF-8')) + collection["license"] = "proprietary" + with open( + sanitize(endpoint, "/collections/mycollection?" + ACCEPT_COLLECTION), "wb" + ) as f: + f.write(json.dumps(collection).encode("UTF-8")) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test', - 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='mycollection' restrictToRequestBBOX=1", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) md = vl.metadata() assert len(md.licenses()) == 1 - assert md.licenses()[0] == 'proprietary' + assert md.licenses()[0] == "proprietary" # Variant with storageCrs collection = copy.deepcopy(base_collection) - collection['storageCrs'] = "http://www.opengis.net/def/crs/EPSG/0/4258" - collection['storageCrsCoordinateEpoch'] = 2020.0 - with open(sanitize(endpoint, '/collections/mycollection?' + ACCEPT_COLLECTION), 'wb') as f: - f.write(json.dumps(collection).encode('UTF-8')) + collection["storageCrs"] = "http://www.opengis.net/def/crs/EPSG/0/4258" + collection["storageCrsCoordinateEpoch"] = 2020.0 + with open( + sanitize(endpoint, "/collections/mycollection?" + ACCEPT_COLLECTION), "wb" + ) as f: + f.write(json.dumps(collection).encode("UTF-8")) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test', - 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='mycollection' restrictToRequestBBOX=1", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) md = vl.metadata() @@ -627,12 +929,22 @@ def testLayerMetadata(self): # Variant with a list of crs collection = copy.deepcopy(base_collection) - collection['crs'] = ["http://www.opengis.net/def/crs/EPSG/0/4258", "http://www.opengis.net/def/crs/EPSG/0/4326"] - with open(sanitize(endpoint, '/collections/mycollection?' + ACCEPT_COLLECTION), 'wb') as f: - f.write(json.dumps(collection).encode('UTF-8')) + collection["crs"] = [ + "http://www.opengis.net/def/crs/EPSG/0/4258", + "http://www.opengis.net/def/crs/EPSG/0/4326", + ] + with open( + sanitize(endpoint, "/collections/mycollection?" + ACCEPT_COLLECTION), "wb" + ) as f: + f.write(json.dumps(collection).encode("UTF-8")) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test', - 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='mycollection' restrictToRequestBBOX=1", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) md = vl.metadata() @@ -643,109 +955,149 @@ def testLayerMetadata(self): def testDateTimeFiltering(self): - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testDateTimeFiltering' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_testDateTimeFiltering" + ) create_landing_page_api_collection(endpoint) items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": {"my_dt_field": "2019-10-15T00:34:00Z", "foo": "bar"}, - "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": {"my_dt_field": "2019-10-15T00:34:00Z", "foo": "bar"}, + "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}, + } + ], } - no_items = { - "type": "FeatureCollection", - "features": [ - ] - } + no_items = {"type": "FeatureCollection", "features": []} - filename = sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS) - with open(filename, 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + filename = sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ) + with open(filename, "wb") as f: + f.write(json.dumps(items).encode("UTF-8")) vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='mycollection' filter='\"my_dt_field\" >= \\'2019-05-15T00:00:00Z\\''", - 'test', 'OAPIF') + "url='http://" + + endpoint + + "' typename='mycollection' filter='\"my_dt_field\" >= \\'2019-05-15T00:00:00Z\\''", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) os.unlink(filename) - filename = sanitize(endpoint, - '/collections/mycollection/items?limit=1000&datetime=2019-05-15T00:00:00Z/9999-12-31T00:00:00Z&' + ACCEPT_ITEMS) - with open(filename, 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) - values = [f['id'] for f in vl.getFeatures()] + filename = sanitize( + endpoint, + "/collections/mycollection/items?limit=1000&datetime=2019-05-15T00:00:00Z/9999-12-31T00:00:00Z&" + + ACCEPT_ITEMS, + ) + with open(filename, "wb") as f: + f.write(json.dumps(items).encode("UTF-8")) + values = [f["id"] for f in vl.getFeatures()] os.unlink(filename) - self.assertEqual(values, ['feat.1']) + self.assertEqual(values, ["feat.1"]) assert vl.setSubsetString(""""my_dt_field" < '2019-01-01T00:34:00Z'""") - filename = sanitize(endpoint, - '/collections/mycollection/items?limit=1000&datetime=0000-01-01T00:00:00Z/2019-01-01T00:34:00Z&' + ACCEPT_ITEMS) - with open(filename, 'wb') as f: - f.write(json.dumps(no_items).encode('UTF-8')) - values = [f['id'] for f in vl.getFeatures()] + filename = sanitize( + endpoint, + "/collections/mycollection/items?limit=1000&datetime=0000-01-01T00:00:00Z/2019-01-01T00:34:00Z&" + + ACCEPT_ITEMS, + ) + with open(filename, "wb") as f: + f.write(json.dumps(no_items).encode("UTF-8")) + values = [f["id"] for f in vl.getFeatures()] os.unlink(filename) self.assertEqual(values, []) assert vl.setSubsetString(""""my_dt_field" = '2019-10-15T00:34:00Z'""") - filename = sanitize(endpoint, - '/collections/mycollection/items?limit=1000&datetime=2019-10-15T00:34:00Z&' + ACCEPT_ITEMS) - with open(filename, 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) - values = [f['id'] for f in vl.getFeatures()] + filename = sanitize( + endpoint, + "/collections/mycollection/items?limit=1000&datetime=2019-10-15T00:34:00Z&" + + ACCEPT_ITEMS, + ) + with open(filename, "wb") as f: + f.write(json.dumps(items).encode("UTF-8")) + values = [f["id"] for f in vl.getFeatures()] os.unlink(filename) - self.assertEqual(values, ['feat.1']) + self.assertEqual(values, ["feat.1"]) assert vl.setSubsetString( - """("my_dt_field" >= '2019-01-01T00:34:00Z') AND ("my_dt_field" <= '2019-12-31T00:00:00Z')""") - - filename = sanitize(endpoint, - '/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/2019-12-31T00:00:00Z&' + ACCEPT_ITEMS) - with open(filename, 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) - values = [f['id'] for f in vl.getFeatures()] + """("my_dt_field" >= '2019-01-01T00:34:00Z') AND ("my_dt_field" <= '2019-12-31T00:00:00Z')""" + ) + + filename = sanitize( + endpoint, + "/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/2019-12-31T00:00:00Z&" + + ACCEPT_ITEMS, + ) + with open(filename, "wb") as f: + f.write(json.dumps(items).encode("UTF-8")) + values = [f["id"] for f in vl.getFeatures()] os.unlink(filename) - self.assertEqual(values, ['feat.1']) + self.assertEqual(values, ["feat.1"]) # Partial on client side - assert vl.setSubsetString("""("my_dt_field" >= '2019-01-01T00:34:00Z') AND ("foo" = 'bar')""") - - filename = sanitize(endpoint, - '/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/9999-12-31T00:00:00Z&' + ACCEPT_ITEMS) - with open(filename, 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) - values = [f['id'] for f in vl.getFeatures()] + assert vl.setSubsetString( + """("my_dt_field" >= '2019-01-01T00:34:00Z') AND ("foo" = 'bar')""" + ) + + filename = sanitize( + endpoint, + "/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/9999-12-31T00:00:00Z&" + + ACCEPT_ITEMS, + ) + with open(filename, "wb") as f: + f.write(json.dumps(items).encode("UTF-8")) + values = [f["id"] for f in vl.getFeatures()] os.unlink(filename) - self.assertEqual(values, ['feat.1']) + self.assertEqual(values, ["feat.1"]) # Same but with non-matching client-side part - assert vl.setSubsetString("""("my_dt_field" >= '2019-01-01T00:34:00Z') AND ("foo" != 'bar')""") - - filename = sanitize(endpoint, - '/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/9999-12-31T00:00:00Z&' + ACCEPT_ITEMS) - with open(filename, 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) - values = [f['id'] for f in vl.getFeatures()] + assert vl.setSubsetString( + """("my_dt_field" >= '2019-01-01T00:34:00Z') AND ("foo" != 'bar')""" + ) + + filename = sanitize( + endpoint, + "/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/9999-12-31T00:00:00Z&" + + ACCEPT_ITEMS, + ) + with open(filename, "wb") as f: + f.write(json.dumps(items).encode("UTF-8")) + values = [f["id"] for f in vl.getFeatures()] os.unlink(filename) self.assertEqual(values, []) # Switch order - assert vl.setSubsetString("""("foo" = 'bar') AND ("my_dt_field" >= '2019-01-01T00:34:00Z')""") - - filename = sanitize(endpoint, - '/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/9999-12-31T00:00:00Z&' + ACCEPT_ITEMS) - with open(filename, 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) - values = [f['id'] for f in vl.getFeatures()] + assert vl.setSubsetString( + """("foo" = 'bar') AND ("my_dt_field" >= '2019-01-01T00:34:00Z')""" + ) + + filename = sanitize( + endpoint, + "/collections/mycollection/items?limit=1000&datetime=2019-01-01T00:34:00Z/9999-12-31T00:00:00Z&" + + ACCEPT_ITEMS, + ) + with open(filename, "wb") as f: + f.write(json.dumps(items).encode("UTF-8")) + values = [f["id"] for f in vl.getFeatures()] os.unlink(filename) - self.assertEqual(values, ['feat.1']) + self.assertEqual(values, ["feat.1"]) def testSimpleQueryableFiltering(self): """Test simple filtering capabilities, not requiring Part 3""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_encoded_query_testSimpleQueryableFiltering' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_encoded_query_testSimpleQueryableFiltering" + ) additionalApiResponse = { "paths": { "/collections/mycollection/items": { @@ -759,28 +1111,22 @@ def testSimpleQueryableFiltering(self): "in": "query", "style": "form", "explode": False, - "schema": { - "type": "integer" - } + "schema": {"type": "integer"}, }, { "name": "doublefield", "in": "query", "style": "form", "explode": False, - "schema": { - "type": "number" - } + "schema": {"type": "number"}, }, { "name": "boolfield", "in": "query", "style": "form", "explode": False, - "schema": { - "type": "boolean" - } - } + "schema": {"type": "boolean"}, + }, ] } } @@ -792,66 +1138,80 @@ def testSimpleQueryableFiltering(self): "in": "query", "style": "form", "explode": False, - "schema": { - "type": "string" - } + "schema": {"type": "string"}, } } - } + }, } - create_landing_page_api_collection(endpoint, additionalApiResponse=additionalApiResponse) + create_landing_page_api_collection( + endpoint, additionalApiResponse=additionalApiResponse + ) items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": - {"strfield": "foo=bar", - "intfield": 1, - "doublefield": 1.5, - "boolfield": True}, - "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": { + "strfield": "foo=bar", + "intfield": 1, + "doublefield": 1.5, + "boolfield": True, + }, + "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}, + } + ], } - no_items = { - "type": "FeatureCollection", - "features": [ - ] - } + no_items = {"type": "FeatureCollection", "features": []} - filename = sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS) - with open(filename, 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + filename = sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ) + with open(filename, "wb") as f: + f.write(json.dumps(items).encode("UTF-8")) vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF') + "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF" + ) self.assertTrue(vl.isValid()) os.unlink(filename) - assert vl.setSubsetString(""""strfield" = 'foo=bar' and intfield = 1 and doublefield = 1.5 and boolfield = true""") - - filename = sanitize(endpoint, - '/collections/mycollection/items?limit=1000&strfield=foo%3Dbar&intfield=1&doublefield=1.5&boolfield=true&' + ACCEPT_ITEMS) - with open(filename, 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) - values = [f['id'] for f in vl.getFeatures()] + assert vl.setSubsetString( + """"strfield" = 'foo=bar' and intfield = 1 and doublefield = 1.5 and boolfield = true""" + ) + + filename = sanitize( + endpoint, + "/collections/mycollection/items?limit=1000&strfield=foo%3Dbar&intfield=1&doublefield=1.5&boolfield=true&" + + ACCEPT_ITEMS, + ) + with open(filename, "wb") as f: + f.write(json.dumps(items).encode("UTF-8")) + values = [f["id"] for f in vl.getFeatures()] os.unlink(filename) - self.assertEqual(values, ['feat.1']) + self.assertEqual(values, ["feat.1"]) assert vl.setSubsetString(""""strfield" = 'bar'""") - filename = sanitize(endpoint, - '/collections/mycollection/items?limit=1000&strfield=bar&' + ACCEPT_ITEMS) - with open(filename, 'wb') as f: - f.write(json.dumps(no_items).encode('UTF-8')) - values = [f['id'] for f in vl.getFeatures()] + filename = sanitize( + endpoint, + "/collections/mycollection/items?limit=1000&strfield=bar&" + ACCEPT_ITEMS, + ) + with open(filename, "wb") as f: + f.write(json.dumps(no_items).encode("UTF-8")) + values = [f["id"] for f in vl.getFeatures()] os.unlink(filename) self.assertEqual(values, []) def testCQL2TextFiltering(self): """Test Part 3 CQL2-Text filtering""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_encoded_query_testCQL2TextFiltering' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_encoded_query_testCQL2TextFiltering" + ) additionalConformance = [ "http://www.opengis.net/spec/cql2/1.0/conf/advanced-comparison-operators", "http://www.opengis.net/spec/cql2/1.0/conf/basic-cql2", @@ -862,29 +1222,21 @@ def testCQL2TextFiltering(self): "http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/filter", ] - create_landing_page_api_collection(endpoint, additionalConformance=additionalConformance) + create_landing_page_api_collection( + endpoint, additionalConformance=additionalConformance + ) - filename = sanitize(endpoint, '/collections/mycollection/queryables?' + ACCEPT_QUERYABLES) + filename = sanitize( + endpoint, "/collections/mycollection/queryables?" + ACCEPT_QUERYABLES + ) queryables = { "properties": { - "strfield": { - "type": "string" - }, - "strfield2": { - "type": "string" - }, - "intfield": { - "type": "integer" - }, - "doublefield": { - "type": "number" - }, - "boolfield": { - "type": "boolean" - }, - "boolfield2": { - "type": "boolean" - }, + "strfield": {"type": "string"}, + "strfield2": {"type": "string"}, + "intfield": {"type": "integer"}, + "doublefield": {"type": "number"}, + "boolfield": {"type": "boolean"}, + "boolfield2": {"type": "boolean"}, "datetimefield": { "type": "string", "format": "date-time", @@ -893,99 +1245,176 @@ def testCQL2TextFiltering(self): "type": "string", "format": "date", }, - "geometry": { - "$ref": "https://geojson.org/schema/Point.json" - }, + "geometry": {"$ref": "https://geojson.org/schema/Point.json"}, } } - with open(filename, 'wb') as f: - f.write(json.dumps(queryables).encode('UTF-8')) + with open(filename, "wb") as f: + f.write(json.dumps(queryables).encode("UTF-8")) items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": - {"strfield": "foo=bar", - "strfield2": None, - "intfield": 1, - "doublefield": 1.5, - "not_a_queryable": 3, - "datetimefield": "2023-04-19T12:34:56Z", - "datefield": "2023-04-19", - "boolfield": True, - "boolfield2": False}, - "geometry": {"type": "Point", "coordinates": [-70.5, 66.5]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": { + "strfield": "foo=bar", + "strfield2": None, + "intfield": 1, + "doublefield": 1.5, + "not_a_queryable": 3, + "datetimefield": "2023-04-19T12:34:56Z", + "datefield": "2023-04-19", + "boolfield": True, + "boolfield2": False, + }, + "geometry": {"type": "Point", "coordinates": [-70.5, 66.5]}, + } + ], } - filename = sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS) - with open(filename, 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + filename = sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ) + with open(filename, "wb") as f: + f.write(json.dumps(items).encode("UTF-8")) vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF') + "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF" + ) self.assertTrue(vl.isValid()) os.unlink(filename) tests = [ - (""""strfield" = 'foo=bar' and intfield = 1""", - """filter=((strfield%20%3D%20'foo%3Dbar')%20AND%20(intfield%20%3D%201))&filter-lang=cql2-text"""), - ("""doublefield = 1.5 or boolfield = true""", - """filter=((doublefield%20%3D%201.5)%20OR%20(boolfield%20%3D%20TRUE))&filter-lang=cql2-text"""), - ("boolfield2 = false", "filter=(boolfield2%20%3D%20FALSE)&filter-lang=cql2-text"""), - ("NOT(intfield = 0)", """filter=(NOT%20((intfield%20%3D%200)))&filter-lang=cql2-text"""), - ("intfield <> 0", """filter=(intfield%20%3C%3E%200)&filter-lang=cql2-text"""), + ( + """"strfield" = 'foo=bar' and intfield = 1""", + """filter=((strfield%20%3D%20'foo%3Dbar')%20AND%20(intfield%20%3D%201))&filter-lang=cql2-text""", + ), + ( + """doublefield = 1.5 or boolfield = true""", + """filter=((doublefield%20%3D%201.5)%20OR%20(boolfield%20%3D%20TRUE))&filter-lang=cql2-text""", + ), + ( + "boolfield2 = false", + "filter=(boolfield2%20%3D%20FALSE)&filter-lang=cql2-text" "", + ), + ( + "NOT(intfield = 0)", + """filter=(NOT%20((intfield%20%3D%200)))&filter-lang=cql2-text""", + ), + ( + "intfield <> 0", + """filter=(intfield%20%3C%3E%200)&filter-lang=cql2-text""", + ), ("intfield > 0", """filter=(intfield%20%3E%200)&filter-lang=cql2-text"""), - ("intfield >= 1", """filter=(intfield%20%3E%3D%201)&filter-lang=cql2-text"""), + ( + "intfield >= 1", + """filter=(intfield%20%3E%3D%201)&filter-lang=cql2-text""", + ), ("intfield < 2", """filter=(intfield%20%3C%202)&filter-lang=cql2-text"""), - ("intfield <= 1", """filter=(intfield%20%3C%3D%201)&filter-lang=cql2-text"""), - ("intfield IN (1, 2)", """filter=intfield%20IN%20(1,2)&filter-lang=cql2-text"""), - ("intfield NOT IN (3, 4)", """filter=intfield%20NOT%20IN%20(3,4)&filter-lang=cql2-text"""), - ("intfield BETWEEN 0 AND 2", "filter=intfield%20BETWEEN%200%20AND%202&filter-lang=cql2-text"), - ("intfield NOT BETWEEN 3 AND 4", "filter=intfield%20NOT%20BETWEEN%203%20AND%204&filter-lang=cql2-text"), - ("strfield2 IS NULL", """filter=(strfield2%20IS%20NULL)&filter-lang=cql2-text"""), - ("intfield IS NOT NULL", """filter=(intfield%20IS%20NOT%20NULL)&filter-lang=cql2-text"""), - ("datetimefield = make_datetime(2023, 4, 19, 12, 34, 56)", - "filter=(datetimefield%20%3D%20TIMESTAMP('2023-04-19T12:34:56.000Z'))&filter-lang=cql2-text"), - ("datetimefield = '2023-04-19T12:34:56.000Z'", - "filter=(datetimefield%20%3D%20TIMESTAMP('2023-04-19T12:34:56.000Z'))&filter-lang=cql2-text"), - ("datefield = make_date(2023, 4, 19)", - "filter=(datefield%20%3D%20DATE('2023-04-19'))&filter-lang=cql2-text"), - ("datefield = '2023-04-19'", - "filter=(datefield%20%3D%20DATE('2023-04-19'))&filter-lang=cql2-text"), - (""""strfield" LIKE 'foo%'""", - """filter=(strfield%20LIKE%20'foo%25')&filter-lang=cql2-text"""), - (""""strfield" NOT LIKE 'bar'""", - """filter=(strfield%20NOT%20LIKE%20'bar')&filter-lang=cql2-text"""), - (""""strfield" ILIKE 'fo%'""", - """filter=(CASEI(strfield)%20LIKE%20CASEI('fo%25'))&filter-lang=cql2-text"""), - (""""strfield" NOT ILIKE 'bar'""", - """filter=(CASEI(strfield)%20NOT%20LIKE%20CASEI('bar'))&filter-lang=cql2-text"""), - ("""intersects_bbox($geometry, geomFromWkt('POLYGON((-180 -90,-180 90,180 90,180 -90,-180 -90))'))""", - """filter=S_INTERSECTS(geometry,BBOX(-180,-90,180,90))&filter-lang=cql2-text"""), - ("""intersects($geometry, geomFromWkt('POINT(-70.5 66.5))'))""", - """filter=S_INTERSECTS(geometry,POINT(-70.5%2066.5))&filter-lang=cql2-text"""), + ( + "intfield <= 1", + """filter=(intfield%20%3C%3D%201)&filter-lang=cql2-text""", + ), + ( + "intfield IN (1, 2)", + """filter=intfield%20IN%20(1,2)&filter-lang=cql2-text""", + ), + ( + "intfield NOT IN (3, 4)", + """filter=intfield%20NOT%20IN%20(3,4)&filter-lang=cql2-text""", + ), + ( + "intfield BETWEEN 0 AND 2", + "filter=intfield%20BETWEEN%200%20AND%202&filter-lang=cql2-text", + ), + ( + "intfield NOT BETWEEN 3 AND 4", + "filter=intfield%20NOT%20BETWEEN%203%20AND%204&filter-lang=cql2-text", + ), + ( + "strfield2 IS NULL", + """filter=(strfield2%20IS%20NULL)&filter-lang=cql2-text""", + ), + ( + "intfield IS NOT NULL", + """filter=(intfield%20IS%20NOT%20NULL)&filter-lang=cql2-text""", + ), + ( + "datetimefield = make_datetime(2023, 4, 19, 12, 34, 56)", + "filter=(datetimefield%20%3D%20TIMESTAMP('2023-04-19T12:34:56.000Z'))&filter-lang=cql2-text", + ), + ( + "datetimefield = '2023-04-19T12:34:56.000Z'", + "filter=(datetimefield%20%3D%20TIMESTAMP('2023-04-19T12:34:56.000Z'))&filter-lang=cql2-text", + ), + ( + "datefield = make_date(2023, 4, 19)", + "filter=(datefield%20%3D%20DATE('2023-04-19'))&filter-lang=cql2-text", + ), + ( + "datefield = '2023-04-19'", + "filter=(datefield%20%3D%20DATE('2023-04-19'))&filter-lang=cql2-text", + ), + ( + """"strfield" LIKE 'foo%'""", + """filter=(strfield%20LIKE%20'foo%25')&filter-lang=cql2-text""", + ), + ( + """"strfield" NOT LIKE 'bar'""", + """filter=(strfield%20NOT%20LIKE%20'bar')&filter-lang=cql2-text""", + ), + ( + """"strfield" ILIKE 'fo%'""", + """filter=(CASEI(strfield)%20LIKE%20CASEI('fo%25'))&filter-lang=cql2-text""", + ), + ( + """"strfield" NOT ILIKE 'bar'""", + """filter=(CASEI(strfield)%20NOT%20LIKE%20CASEI('bar'))&filter-lang=cql2-text""", + ), + ( + """intersects_bbox($geometry, geomFromWkt('POLYGON((-180 -90,-180 90,180 90,180 -90,-180 -90))'))""", + """filter=S_INTERSECTS(geometry,BBOX(-180,-90,180,90))&filter-lang=cql2-text""", + ), + ( + """intersects($geometry, geomFromWkt('POINT(-70.5 66.5))'))""", + """filter=S_INTERSECTS(geometry,POINT(-70.5%2066.5))&filter-lang=cql2-text""", + ), # Partially evaluated on server - ("intfield >= 1 AND not_a_queryable = 3", """filter=(intfield%20%3E%3D%201)&filter-lang=cql2-text"""), - ("not_a_queryable = 3 AND intfield >= 1", """filter=(intfield%20%3E%3D%201)&filter-lang=cql2-text"""), + ( + "intfield >= 1 AND not_a_queryable = 3", + """filter=(intfield%20%3E%3D%201)&filter-lang=cql2-text""", + ), + ( + "not_a_queryable = 3 AND intfield >= 1", + """filter=(intfield%20%3E%3D%201)&filter-lang=cql2-text""", + ), # Only evaluated on client ("intfield >= 1 OR not_a_queryable = 3", ""), ("not_a_queryable = 3 AND not_a_queryable = 3", ""), ] - for (expr, cql_filter) in tests: + for expr, cql_filter in tests: assert vl.setSubsetString(expr) - filename = sanitize(endpoint, - "/collections/mycollection/items?limit=1000&" + cql_filter + ("&" if cql_filter else "") + ACCEPT_ITEMS) - with open(filename, 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) - values = [f['id'] for f in vl.getFeatures()] + filename = sanitize( + endpoint, + "/collections/mycollection/items?limit=1000&" + + cql_filter + + ("&" if cql_filter else "") + + ACCEPT_ITEMS, + ) + with open(filename, "wb") as f: + f.write(json.dumps(items).encode("UTF-8")) + values = [f["id"] for f in vl.getFeatures()] os.unlink(filename) - self.assertEqual(values, ['feat.1'], expr) + self.assertEqual(values, ["feat.1"], expr) def testCQL2TextFilteringAndPart2(self): - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_encoded_query_testCQL2TextFilteringAndPart2' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_encoded_query_testCQL2TextFilteringAndPart2" + ) additionalConformance = [ "http://www.opengis.net/spec/cql2/1.0/conf/basic-cql2", "http://www.opengis.net/spec/cql2/1.0/conf/basic-spatial-operators", @@ -994,61 +1423,82 @@ def testCQL2TextFilteringAndPart2(self): "http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/filter", ] - create_landing_page_api_collection(endpoint, - storageCrs="http://www.opengis.net/def/crs/EPSG/0/4258", - crsList=["http://www.opengis.net/def/crs/OGC/0/CRS84", - "http://www.opengis.net/def/crs/EPSG/0/4258"], - additionalConformance=additionalConformance) + create_landing_page_api_collection( + endpoint, + storageCrs="http://www.opengis.net/def/crs/EPSG/0/4258", + crsList=[ + "http://www.opengis.net/def/crs/OGC/0/CRS84", + "http://www.opengis.net/def/crs/EPSG/0/4258", + ], + additionalConformance=additionalConformance, + ) - filename = sanitize(endpoint, '/collections/mycollection/queryables?' + ACCEPT_QUERYABLES) + filename = sanitize( + endpoint, "/collections/mycollection/queryables?" + ACCEPT_QUERYABLES + ) queryables = { "properties": { - "geometry": { - "$ref": "https://geojson.org/schema/Point.json" - }, + "geometry": {"$ref": "https://geojson.org/schema/Point.json"}, } } - with open(filename, 'wb') as f: - f.write(json.dumps(queryables).encode('UTF-8')) + with open(filename, "wb") as f: + f.write(json.dumps(queryables).encode("UTF-8")) items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": - {}, - # lat, long order - "geometry": {"type": "Point", "coordinates": [49, 2]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": {}, + # lat, long order + "geometry": {"type": "Point", "coordinates": [49, 2]}, + } + ], } - filename = sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS) - with open(filename, 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + filename = sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ) + with open(filename, "wb") as f: + f.write(json.dumps(items).encode("UTF-8")) vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF') + "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF" + ) self.assertTrue(vl.isValid()) os.unlink(filename) tests = [ - ("""intersects($geometry, geomFromWkt('POINT(2 49))'))""", - """filter=S_INTERSECTS(geometry,POINT(49%202))&filter-lang=cql2-text&filter-crs=http://www.opengis.net/def/crs/EPSG/0/4258"""), + ( + """intersects($geometry, geomFromWkt('POINT(2 49))'))""", + """filter=S_INTERSECTS(geometry,POINT(49%202))&filter-lang=cql2-text&filter-crs=http://www.opengis.net/def/crs/EPSG/0/4258""", + ), ] - for (expr, cql_filter) in tests: + for expr, cql_filter in tests: assert vl.setSubsetString(expr) - filename = sanitize(endpoint, - "/collections/mycollection/items?limit=1000&" + cql_filter + ("&" if cql_filter else "") + "crs=http://www.opengis.net/def/crs/EPSG/0/4258&" + ACCEPT_ITEMS) - with open(filename, 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) - values = [f['id'] for f in vl.getFeatures()] + filename = sanitize( + endpoint, + "/collections/mycollection/items?limit=1000&" + + cql_filter + + ("&" if cql_filter else "") + + "crs=http://www.opengis.net/def/crs/EPSG/0/4258&" + + ACCEPT_ITEMS, + ) + with open(filename, "wb") as f: + f.write(json.dumps(items).encode("UTF-8")) + values = [f["id"] for f in vl.getFeatures()] os.unlink(filename) - self.assertEqual(values, ['feat.1'], expr) + self.assertEqual(values, ["feat.1"], expr) def testCQL2TextFilteringGetFeaturesExpression(self): """Test Part 3 CQL2-Text filtering""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_encoded_query_testCQL2TextFilteringGetFeaturesExpression' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_encoded_query_testCQL2TextFilteringGetFeaturesExpression" + ) additionalConformance = [ "http://www.opengis.net/spec/cql2/1.0/conf/basic-cql2", "http://www.opengis.net/spec/cql2/1.0/conf/cql2-text", @@ -1056,228 +1506,428 @@ def testCQL2TextFilteringGetFeaturesExpression(self): "http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/filter", ] - create_landing_page_api_collection(endpoint, additionalConformance=additionalConformance) + create_landing_page_api_collection( + endpoint, additionalConformance=additionalConformance + ) - filename = sanitize(endpoint, '/collections/mycollection/queryables?' + ACCEPT_QUERYABLES) + filename = sanitize( + endpoint, "/collections/mycollection/queryables?" + ACCEPT_QUERYABLES + ) queryables = { "properties": { - "strfield": { - "type": "string" - }, - "geometry": { - "$ref": "https://geojson.org/schema/Point.json" - }, + "strfield": {"type": "string"}, + "geometry": {"$ref": "https://geojson.org/schema/Point.json"}, } } - with open(filename, 'wb') as f: - f.write(json.dumps(queryables).encode('UTF-8')) + with open(filename, "wb") as f: + f.write(json.dumps(queryables).encode("UTF-8")) items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": - { - "strfield": "foo=bar", - }, - "geometry": {"type": "Point", "coordinates": [-70.5, 66.5]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": { + "strfield": "foo=bar", + }, + "geometry": {"type": "Point", "coordinates": [-70.5, 66.5]}, + } + ], } - filename = sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS) - with open(filename, 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + filename = sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ) + with open(filename, "wb") as f: + f.write(json.dumps(items).encode("UTF-8")) vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF') + "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF" + ) self.assertTrue(vl.isValid()) os.unlink(filename) tests = [ - ("", """"strfield" = 'foo=bar'""", - """filter=(strfield%20%3D%20'foo%3Dbar')&filter-lang=cql2-text"""), - ("strfield <> 'x'", """"strfield" = 'foo=bar'""", - """filter=((strfield%20%3C%3E%20'x'))%20AND%20((strfield%20%3D%20'foo%3Dbar'))&filter-lang=cql2-text"""), + ( + "", + """"strfield" = 'foo=bar'""", + """filter=(strfield%20%3D%20'foo%3Dbar')&filter-lang=cql2-text""", + ), + ( + "strfield <> 'x'", + """"strfield" = 'foo=bar'""", + """filter=((strfield%20%3C%3E%20'x'))%20AND%20((strfield%20%3D%20'foo%3Dbar'))&filter-lang=cql2-text""", + ), ] - for (substring_expr, getfeatures_expr, cql_filter) in tests: + for substring_expr, getfeatures_expr, cql_filter in tests: assert vl.setSubsetString(substring_expr) - filename = sanitize(endpoint, - "/collections/mycollection/items?limit=1000&" + cql_filter + ("&" if cql_filter else "") + ACCEPT_ITEMS) - with open(filename, 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + filename = sanitize( + endpoint, + "/collections/mycollection/items?limit=1000&" + + cql_filter + + ("&" if cql_filter else "") + + ACCEPT_ITEMS, + ) + with open(filename, "wb") as f: + f.write(json.dumps(items).encode("UTF-8")) request = QgsFeatureRequest() if getfeatures_expr: request.setFilterExpression(getfeatures_expr) - values = [f['id'] for f in vl.getFeatures(request)] + values = [f["id"] for f in vl.getFeatures(request)] os.unlink(filename) - self.assertEqual(values, ['feat.1'], (substring_expr, getfeatures_expr)) + self.assertEqual(values, ["feat.1"], (substring_expr, getfeatures_expr)) def testStringList(self): - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testStringList' + endpoint = ( + self.__class__.basetestpath + "/fake_qgis_http_endpoint_testStringList" + ) create_landing_page_api_collection(endpoint) items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": {"my_stringlist_field": ["a", "b"]}, - "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": {"my_stringlist_field": ["a", "b"]}, + "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}, + } + ], } - filename = sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS) - with open(filename, 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + filename = sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ) + with open(filename, "wb") as f: + f.write(json.dumps(items).encode("UTF-8")) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF" + ) self.assertTrue(vl.isValid()) os.unlink(filename) - filename = sanitize(endpoint, '/collections/mycollection/items?limit=1000&' + ACCEPT_ITEMS) - with open(filename, 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + filename = sanitize( + endpoint, "/collections/mycollection/items?limit=1000&" + ACCEPT_ITEMS + ) + with open(filename, "wb") as f: + f.write(json.dumps(items).encode("UTF-8")) features = [f for f in vl.getFeatures()] os.unlink(filename) - self.assertEqual(features[0]['my_stringlist_field'], ["a", "b"]) + self.assertEqual(features[0]["my_stringlist_field"], ["a", "b"]) def testApikey(self): - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_apikey' - create_landing_page_api_collection(endpoint, extraparam='apikey=mykey') + endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_apikey" + create_landing_page_api_collection(endpoint, extraparam="apikey=mykey") # first items first_items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100}, - "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": {"pk": 1, "cnt": 100}, + "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}, + } + ], } - with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&apikey=mykey&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_items).encode('UTF-8')) + with open( + sanitize( + endpoint, + "/collections/mycollection/items?limit=10&apikey=mykey&" + ACCEPT_ITEMS, + ), + "wb", + ) as f: + f.write(json.dumps(first_items).encode("UTF-8")) - with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&apikey=mykey&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_items).encode('UTF-8')) + with open( + sanitize( + endpoint, + "/collections/mycollection/items?limit=1000&apikey=mykey&" + + ACCEPT_ITEMS, + ), + "wb", + ) as f: + f.write(json.dumps(first_items).encode("UTF-8")) app_log = QgsApplication.messageLog() # signals should be emitted by application log app_spy = QSignalSpy(app_log.messageReceived) - vl = QgsVectorLayer("url='http://" + endpoint + "?apikey=mykey' typename='mycollection'", 'test', 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + endpoint + "?apikey=mykey' typename='mycollection'", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) - values = [f['id'] for f in vl.getFeatures()] - self.assertEqual(values, ['feat.1']) + values = [f["id"] for f in vl.getFeatures()] + self.assertEqual(values, ["feat.1"]) self.assertEqual(len(app_spy), 0, list(app_spy)) def testDefaultCRS(self): # On Windows we must make sure that any backslash in the path is # replaced by a forward slash so that QUrl can process it - basetestpath = tempfile.mkdtemp().replace('\\', '/') - endpoint = basetestpath + '/fake_qgis_http_endpoint_ogc84' + basetestpath = tempfile.mkdtemp().replace("\\", "/") + endpoint = basetestpath + "/fake_qgis_http_endpoint_ogc84" - create_landing_page_api_collection(endpoint, - bbox=[66.33, -71.123, 78.3, -65.32]) + create_landing_page_api_collection( + endpoint, bbox=[66.33, -71.123, 78.3, -65.32] + ) items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", - "properties": {"pk": 1, "cnt": 100, "name": "Orange", "name2": "oranGe", "num_char": "1", "dt": "2020-05-03 12:13:14", "date": "2020-05-03", "time": "12:13:14"}, - "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}}, - {"type": "Feature", "id": "feat.2", - "properties": {"pk": 2, "cnt": 200, "name": "Apple", "name2": "Apple", "num_char": "2", "dt": "2020-05-04 12:14:14", "date": "2020-05-04", "time": "12:14:14"}, - "geometry": {"type": "Point", "coordinates": [70.8, -68.2]}}, - {"type": "Feature", "id": "feat.3", - "properties": {"pk": 4, "cnt": 400, "name": "Honey", "name2": "Honey", "num_char": "4", "dt": "2021-05-04 13:13:14", "date": "2021-05-04", "time": "13:13:14"}, - "geometry": {"type": "Point", "coordinates": [78.3, -65.32]}}, - {"type": "Feature", "id": "feat.4", - "properties": {"pk": 3, "cnt": 300, "name": "Pear", "name2": "PEaR", "num_char": "3"}, - "geometry": None}, - {"type": "Feature", "id": "feat.5", - "properties": {"pk": 5, "cnt": -200, "name": None, "name2": "NuLl", "num_char": "5", "dt": "2020-05-04 12:13:14", "date": "2020-05-02", "time": "12:13:01"}, - "geometry": {"type": "Point", "coordinates": [78.23, -71.123]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": { + "pk": 1, + "cnt": 100, + "name": "Orange", + "name2": "oranGe", + "num_char": "1", + "dt": "2020-05-03 12:13:14", + "date": "2020-05-03", + "time": "12:13:14", + }, + "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}, + }, + { + "type": "Feature", + "id": "feat.2", + "properties": { + "pk": 2, + "cnt": 200, + "name": "Apple", + "name2": "Apple", + "num_char": "2", + "dt": "2020-05-04 12:14:14", + "date": "2020-05-04", + "time": "12:14:14", + }, + "geometry": {"type": "Point", "coordinates": [70.8, -68.2]}, + }, + { + "type": "Feature", + "id": "feat.3", + "properties": { + "pk": 4, + "cnt": 400, + "name": "Honey", + "name2": "Honey", + "num_char": "4", + "dt": "2021-05-04 13:13:14", + "date": "2021-05-04", + "time": "13:13:14", + }, + "geometry": {"type": "Point", "coordinates": [78.3, -65.32]}, + }, + { + "type": "Feature", + "id": "feat.4", + "properties": { + "pk": 3, + "cnt": 300, + "name": "Pear", + "name2": "PEaR", + "num_char": "3", + }, + "geometry": None, + }, + { + "type": "Feature", + "id": "feat.5", + "properties": { + "pk": 5, + "cnt": -200, + "name": None, + "name2": "NuLl", + "num_char": "5", + "dt": "2020-05-04 12:13:14", + "date": "2020-05-02", + "time": "12:13:01", + }, + "geometry": {"type": "Point", "coordinates": [78.23, -71.123]}, + }, + ], } # first items - with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(items).encode("UTF-8")) # real page - with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=1000&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(items).encode("UTF-8")) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF" + ) assert vl.isValid() source = vl.dataProvider() - self.assertEqual(source.sourceCrs().authid(), 'OGC:CRS84') + self.assertEqual(source.sourceCrs().authid(), "OGC:CRS84") def testCRS2056(self): # On Windows we must make sure that any backslash in the path is # replaced by a forward slash so that QUrl can process it - basetestpath = tempfile.mkdtemp().replace('\\', '/') - endpoint = basetestpath + '/fake_qgis_http_endpoint_epsg_2056' - - create_landing_page_api_collection(endpoint, - storageCrs="http://www.opengis.net/def/crs/EPSG/0/2056", - crsList=["http://www.opengis.net/def/crs/OGC/0/CRS84", "http://www.opengis.net/def/crs/EPSG/0/2056"]) + basetestpath = tempfile.mkdtemp().replace("\\", "/") + endpoint = basetestpath + "/fake_qgis_http_endpoint_epsg_2056" + + create_landing_page_api_collection( + endpoint, + storageCrs="http://www.opengis.net/def/crs/EPSG/0/2056", + crsList=[ + "http://www.opengis.net/def/crs/OGC/0/CRS84", + "http://www.opengis.net/def/crs/EPSG/0/2056", + ], + ) items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", - "properties": {"pk": 1, "cnt": 100, "name": "Orange", "name2": "oranGe", "num_char": "1", "dt": "2020-05-03 12:13:14", "date": "2020-05-03", "time": "12:13:14"}, - "geometry": {"type": "Point", "coordinates": [2510100, 1155050]}}, - {"type": "Feature", "id": "feat.2", - "properties": {"pk": 2, "cnt": 200, "name": "Apple", "name2": "Apple", "num_char": "2", "dt": "2020-05-04 12:14:14", "date": "2020-05-04", "time": "12:14:14"}, - "geometry": {"type": "Point", "coordinates": [2511250, 1154600]}}, - {"type": "Feature", "id": "feat.3", - "properties": {"pk": 4, "cnt": 400, "name": "Honey", "name2": "Honey", "num_char": "4", "dt": "2021-05-04 13:13:14", "date": "2021-05-04", "time": "13:13:14"}, - "geometry": {"type": "Point", "coordinates": [2511260, 1154610]}}, - {"type": "Feature", "id": "feat.4", - "properties": {"pk": 3, "cnt": 300, "name": "Pear", "name2": "PEaR", "num_char": "3"}, - "geometry": None}, - {"type": "Feature", "id": "feat.5", - "properties": {"pk": 5, "cnt": -200, "name": None, "name2": "NuLl", "num_char": "5", "dt": "2020-05-04 12:13:14", "date": "2020-05-02", "time": "12:13:01"}, - "geometry": {"type": "Point", "coordinates": [2511270, 1154620]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": { + "pk": 1, + "cnt": 100, + "name": "Orange", + "name2": "oranGe", + "num_char": "1", + "dt": "2020-05-03 12:13:14", + "date": "2020-05-03", + "time": "12:13:14", + }, + "geometry": {"type": "Point", "coordinates": [2510100, 1155050]}, + }, + { + "type": "Feature", + "id": "feat.2", + "properties": { + "pk": 2, + "cnt": 200, + "name": "Apple", + "name2": "Apple", + "num_char": "2", + "dt": "2020-05-04 12:14:14", + "date": "2020-05-04", + "time": "12:14:14", + }, + "geometry": {"type": "Point", "coordinates": [2511250, 1154600]}, + }, + { + "type": "Feature", + "id": "feat.3", + "properties": { + "pk": 4, + "cnt": 400, + "name": "Honey", + "name2": "Honey", + "num_char": "4", + "dt": "2021-05-04 13:13:14", + "date": "2021-05-04", + "time": "13:13:14", + }, + "geometry": {"type": "Point", "coordinates": [2511260, 1154610]}, + }, + { + "type": "Feature", + "id": "feat.4", + "properties": { + "pk": 3, + "cnt": 300, + "name": "Pear", + "name2": "PEaR", + "num_char": "3", + }, + "geometry": None, + }, + { + "type": "Feature", + "id": "feat.5", + "properties": { + "pk": 5, + "cnt": -200, + "name": None, + "name2": "NuLl", + "num_char": "5", + "dt": "2020-05-04 12:13:14", + "date": "2020-05-02", + "time": "12:13:01", + }, + "geometry": {"type": "Point", "coordinates": [2511270, 1154620]}, + }, + ], } # first items - with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(items).encode("UTF-8")) # real page - with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=1000&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(items).encode("UTF-8")) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF" + ) assert vl.isValid() source = vl.dataProvider() - self.assertEqual(source.sourceCrs().authid(), 'EPSG:2056') + self.assertEqual(source.sourceCrs().authid(), "EPSG:2056") # Test srsname parameter overrides default CRS - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' srsname='OGC:CRS84'", 'test', 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='mycollection' srsname='OGC:CRS84'", + "test", + "OAPIF", + ) assert vl.isValid() source = vl.dataProvider() - self.assertEqual(source.sourceCrs().authid(), 'OGC:CRS84') + self.assertEqual(source.sourceCrs().authid(), "OGC:CRS84") def testFeatureCountFallbackAndNoBboxInCollection(self): # On Windows we must make sure that any backslash in the path is # replaced by a forward slash so that QUrl can process it - basetestpath = tempfile.mkdtemp().replace('\\', '/') - endpoint = basetestpath + '/fake_qgis_http_endpoint_feature_count_fallback' + basetestpath = tempfile.mkdtemp().replace("\\", "/") + endpoint = basetestpath + "/fake_qgis_http_endpoint_feature_count_fallback" - create_landing_page_api_collection(endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/2056", bbox=None) + create_landing_page_api_collection( + endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/2056", bbox=None + ) items = { "type": "FeatureCollection", @@ -1285,20 +1935,35 @@ def testFeatureCountFallbackAndNoBboxInCollection(self): "links": [ # should not be hit {"href": "http://" + endpoint + "/next_page", "rel": "next"} - ] + ], } for i in range(10): - items["features"].append({"type": "Feature", "id": f"feat.{i}", - "properties": {}, - "geometry": {"type": "Point", "coordinates": [23, 63]}}) + items["features"].append( + { + "type": "Feature", + "id": f"feat.{i}", + "properties": {}, + "geometry": {"type": "Point", "coordinates": [23, 63]}, + } + ) # first items - with open(sanitize(endpoint, '/collections/mycollection/items?limit=1&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=1&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(items).encode("UTF-8")) # first items - with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(items).encode("UTF-8")) # real page @@ -1308,29 +1973,44 @@ def testFeatureCountFallbackAndNoBboxInCollection(self): "links": [ # should not be hit {"href": "http://" + endpoint + "/next_page", "rel": "next"} - ] + ], } for i in range(1001): - items["features"].append({"type": "Feature", "id": f"feat.{i}", - "properties": {}, - "geometry": None}) + items["features"].append( + { + "type": "Feature", + "id": f"feat.{i}", + "properties": {}, + "geometry": None, + } + ) - with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&crs=http://www.opengis.net/def/crs/EPSG/0/2056&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(items).encode('UTF-8')) + with open( + sanitize( + endpoint, + "/collections/mycollection/items?limit=1000&crs=http://www.opengis.net/def/crs/EPSG/0/2056&" + + ACCEPT_ITEMS, + ), + "wb", + ) as f: + f.write(json.dumps(items).encode("UTF-8")) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection'", 'test', 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='mycollection'", "test", "OAPIF" + ) assert vl.isValid() source = vl.dataProvider() # Extent got from first fetched features reference = QgsGeometry.fromRect( - QgsRectangle(3415684, 3094884, - 3415684, 3094884)) + QgsRectangle(3415684, 3094884, 3415684, 3094884) + ) vl_extent = QgsGeometry.fromRect(vl.extent()) - assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0], - 10), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}' + assert QgsGeometry.compare( + vl_extent.asPolygon()[0], reference.asPolygon()[0], 10 + ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}" app_log = QgsApplication.messageLog() # signals should be emitted by application log @@ -1342,73 +2022,148 @@ def testFeatureCountFallbackAndNoBboxInCollection(self): def testFeatureInsertionDeletion(self): - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testFeatureInsertion' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_testFeatureInsertion" + ) create_landing_page_api_collection(endpoint) # first items first_items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100}, - "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": {"pk": 1, "cnt": 100}, + "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}, + } + ], } - with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(first_items).encode("UTF-8")) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test', - 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='mycollection' restrictToRequestBBOX=1", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) # Basic OPTIONS response: no AddFeatures capability - self.assertEqual(vl.dataProvider().capabilities() & vl.dataProvider().AddFeatures, - vl.dataProvider().NoCapabilities) + self.assertEqual( + vl.dataProvider().capabilities() & vl.dataProvider().AddFeatures, + vl.dataProvider().NoCapabilities, + ) # POST on /items, but no DELETE on /items/id - with open(sanitize(endpoint, '/collections/mycollection/items?VERB=OPTIONS'), 'wb') as f: - f.write("HEAD, GET, POST".encode("UTF-8")) - with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?VERB=OPTIONS'), 'wb') as f: - f.write("HEAD, GET".encode("UTF-8")) + with open( + sanitize(endpoint, "/collections/mycollection/items?VERB=OPTIONS"), "wb" + ) as f: + f.write(b"HEAD, GET, POST") + with open( + sanitize(endpoint, "/collections/mycollection/items/feat.1?VERB=OPTIONS"), + "wb", + ) as f: + f.write(b"HEAD, GET") - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test', - 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='mycollection' restrictToRequestBBOX=1", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) - self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().AddFeatures, - vl.dataProvider().NoCapabilities) - self.assertEqual(vl.dataProvider().capabilities() & vl.dataProvider().DeleteFeatures, - vl.dataProvider().NoCapabilities) + self.assertNotEqual( + vl.dataProvider().capabilities() & vl.dataProvider().AddFeatures, + vl.dataProvider().NoCapabilities, + ) + self.assertEqual( + vl.dataProvider().capabilities() & vl.dataProvider().DeleteFeatures, + vl.dataProvider().NoCapabilities, + ) # DELETE on /items/id - with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?VERB=OPTIONS'), 'wb') as f: - f.write("HEAD, GET, DELETE".encode("UTF-8")) + with open( + sanitize(endpoint, "/collections/mycollection/items/feat.1?VERB=OPTIONS"), + "wb", + ) as f: + f.write(b"HEAD, GET, DELETE") - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test', - 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='mycollection' restrictToRequestBBOX=1", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) - self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().AddFeatures, - vl.dataProvider().NoCapabilities) - self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().DeleteFeatures, - vl.dataProvider().NoCapabilities) + self.assertNotEqual( + vl.dataProvider().capabilities() & vl.dataProvider().AddFeatures, + vl.dataProvider().NoCapabilities, + ) + self.assertNotEqual( + vl.dataProvider().capabilities() & vl.dataProvider().DeleteFeatures, + vl.dataProvider().NoCapabilities, + ) - with open(sanitize(endpoint, '/collections/mycollection/items?POSTDATA={"geometry":{"coordinates":[2.0,49.0],"type":"Point"},"properties":{"cnt":1234567890123,"pk":1},"type":"Feature"}'), 'wb') as f: + with open( + sanitize( + endpoint, + '/collections/mycollection/items?POSTDATA={"geometry":{"coordinates":[2.0,49.0],"type":"Point"},"properties":{"cnt":1234567890123,"pk":1},"type":"Feature"}', + ), + "wb", + ) as f: f.write(b"Location: /collections/mycollection/items/new_id\r\n") - with open(sanitize(endpoint, '/collections/mycollection/items?POSTDATA={"geometry":null,"properties":{"cnt":null,"pk":null},"type":"Feature"}'), 'wb') as f: + with open( + sanitize( + endpoint, + '/collections/mycollection/items?POSTDATA={"geometry":null,"properties":{"cnt":null,"pk":null},"type":"Feature"}', + ), + "wb", + ) as f: f.write(b"Location: /collections/mycollection/items/other_id\r\n") - new_id = {"type": "Feature", "id": "new_id", "properties": {"pk": 1, "cnt": 1234567890123}, - "geometry": {"type": "Point", "coordinates": [2, 49]}} - with open(sanitize(endpoint, '/collections/mycollection/items/new_id?' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(new_id).encode('UTF-8')) - - other_id = {"type": "Feature", "id": "other_id", "properties": {"pk": 2, "cnt": 123}, - "geometry": None} - with open(sanitize(endpoint, '/collections/mycollection/items/other_id?' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(other_id).encode('UTF-8')) + new_id = { + "type": "Feature", + "id": "new_id", + "properties": {"pk": 1, "cnt": 1234567890123}, + "geometry": {"type": "Point", "coordinates": [2, 49]}, + } + with open( + sanitize( + endpoint, "/collections/mycollection/items/new_id?" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(new_id).encode("UTF-8")) + + other_id = { + "type": "Feature", + "id": "other_id", + "properties": {"pk": 2, "cnt": 123}, + "geometry": None, + } + with open( + sanitize( + endpoint, "/collections/mycollection/items/other_id?" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(other_id).encode("UTF-8")) f = QgsFeature() f.setFields(vl.fields()) f.setAttributes([None, 1, 1234567890123]) - f.setGeometry(QgsGeometry.fromWkt('Point (2 49)')) + f.setGeometry(QgsGeometry.fromWkt("Point (2 49)")) f2 = QgsFeature() f2.setFields(vl.fields()) @@ -1429,90 +2184,165 @@ def testFeatureInsertionDeletion(self): # Failed attempt self.assertFalse(vl.dataProvider().deleteFeatures([1])) - with open(sanitize(endpoint, '/collections/mycollection/items/new_id?VERB=DELETE'), 'wb') as f: + with open( + sanitize(endpoint, "/collections/mycollection/items/new_id?VERB=DELETE"), + "wb", + ) as f: f.write(b"") - with open(sanitize(endpoint, '/collections/mycollection/items/other_id?VERB=DELETE'), 'wb') as f: + with open( + sanitize(endpoint, "/collections/mycollection/items/other_id?VERB=DELETE"), + "wb", + ) as f: f.write(b"") self.assertTrue(vl.dataProvider().deleteFeatures([1, 2])) def testFeatureInsertionNonDefaultCrs(self): - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testFeatureInsertionNonDefaultCrs' - create_landing_page_api_collection(endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/4326") + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_testFeatureInsertionNonDefaultCrs" + ) + create_landing_page_api_collection( + endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/4326" + ) # first items (lat, long) order first_items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100}, - "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": {"pk": 1, "cnt": 100}, + "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}, + } + ], } - with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(first_items).encode("UTF-8")) # POST on /items, but no DELETE on /items/id - with open(sanitize(endpoint, '/collections/mycollection/items?VERB=OPTIONS'), 'wb') as f: - f.write("HEAD, GET, POST".encode("UTF-8")) - with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?VERB=OPTIONS'), 'wb') as f: - f.write("HEAD, GET".encode("UTF-8")) + with open( + sanitize(endpoint, "/collections/mycollection/items?VERB=OPTIONS"), "wb" + ) as f: + f.write(b"HEAD, GET, POST") + with open( + sanitize(endpoint, "/collections/mycollection/items/feat.1?VERB=OPTIONS"), + "wb", + ) as f: + f.write(b"HEAD, GET") - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test', - 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='mycollection' restrictToRequestBBOX=1", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) # (lat, long) order - with open(sanitize(endpoint, '/collections/mycollection/items?POSTDATA={"geometry":{"coordinates":[49.0,2.0],"type":"Point"},"properties":{"cnt":1234567890123,"pk":1},"type":"Feature"}&Content-Crs=http://www.opengis.net/def/crs/EPSG/0/4326'), 'wb') as f: + with open( + sanitize( + endpoint, + '/collections/mycollection/items?POSTDATA={"geometry":{"coordinates":[49.0,2.0],"type":"Point"},"properties":{"cnt":1234567890123,"pk":1},"type":"Feature"}&Content-Crs=http://www.opengis.net/def/crs/EPSG/0/4326', + ), + "wb", + ) as f: f.write(b"Location: /collections/mycollection/items/new_id\r\n") f = QgsFeature() f.setFields(vl.fields()) f.setAttributes([None, 1, 1234567890123]) - f.setGeometry(QgsGeometry.fromWkt('Point (2 49)')) + f.setGeometry(QgsGeometry.fromWkt("Point (2 49)")) ret, _ = vl.dataProvider().addFeatures([f]) self.assertTrue(ret) def testFeatureGeometryChange(self): - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testFeatureGeometryChange' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_testFeatureGeometryChange" + ) create_landing_page_api_collection(endpoint) # first items first_items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100}, - "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": {"pk": 1, "cnt": 100}, + "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}, + } + ], } - with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(first_items).encode("UTF-8")) - with open(sanitize(endpoint, '/collections/mycollection/items?VERB=OPTIONS'), 'wb') as f: - f.write("HEAD, GET, POST".encode("UTF-8")) - with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?VERB=OPTIONS'), 'wb') as f: - f.write("HEAD, GET, PUT, DELETE".encode("UTF-8")) + with open( + sanitize(endpoint, "/collections/mycollection/items?VERB=OPTIONS"), "wb" + ) as f: + f.write(b"HEAD, GET, POST") + with open( + sanitize(endpoint, "/collections/mycollection/items/feat.1?VERB=OPTIONS"), + "wb", + ) as f: + f.write(b"HEAD, GET, PUT, DELETE") - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test', - 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='mycollection' restrictToRequestBBOX=1", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) - self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries, - vl.dataProvider().NoCapabilities) + self.assertNotEqual( + vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries, + vl.dataProvider().NoCapabilities, + ) # real page - with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=1000&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(first_items).encode("UTF-8")) values = [f.id() for f in vl.getFeatures()] self.assertEqual(values, [1]) - with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?PUTDATA={"geometry":{"coordinates":[3.0,50.0],"type":"Point"},"id":"feat.1","properties":{"cnt":100,"pk":1},"type":"Feature"}'), 'wb') as f: + with open( + sanitize( + endpoint, + '/collections/mycollection/items/feat.1?PUTDATA={"geometry":{"coordinates":[3.0,50.0],"type":"Point"},"id":"feat.1","properties":{"cnt":100,"pk":1},"type":"Feature"}', + ), + "wb", + ) as f: f.write(b"") - self.assertTrue(vl.dataProvider().changeGeometryValues({1: QgsGeometry.fromWkt('Point (3 50)')})) + self.assertTrue( + vl.dataProvider().changeGeometryValues( + {1: QgsGeometry.fromWkt("Point (3 50)")} + ) + ) got_f = [f for f in vl.getFeatures()] got = got_f[0].geometry().constGet() @@ -1520,43 +2350,86 @@ def testFeatureGeometryChange(self): def testFeatureGeometryChangeNonDefaultCrs(self): - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testFeatureGeometryChangeNonDefaultCrs' - create_landing_page_api_collection(endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/4326") + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_testFeatureGeometryChangeNonDefaultCrs" + ) + create_landing_page_api_collection( + endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/4326" + ) # first items first_items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100}, - "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": {"pk": 1, "cnt": 100}, + "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}, + } + ], } - with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(first_items).encode("UTF-8")) - with open(sanitize(endpoint, '/collections/mycollection/items?VERB=OPTIONS'), 'wb') as f: - f.write("HEAD, GET, POST".encode("UTF-8")) - with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?VERB=OPTIONS'), 'wb') as f: - f.write("HEAD, GET, PUT, DELETE".encode("UTF-8")) + with open( + sanitize(endpoint, "/collections/mycollection/items?VERB=OPTIONS"), "wb" + ) as f: + f.write(b"HEAD, GET, POST") + with open( + sanitize(endpoint, "/collections/mycollection/items/feat.1?VERB=OPTIONS"), + "wb", + ) as f: + f.write(b"HEAD, GET, PUT, DELETE") - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test', - 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='mycollection' restrictToRequestBBOX=1", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) - self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries, - vl.dataProvider().NoCapabilities) + self.assertNotEqual( + vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries, + vl.dataProvider().NoCapabilities, + ) # real page - with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&crs=http://www.opengis.net/def/crs/EPSG/0/4326&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_items).encode('UTF-8')) + with open( + sanitize( + endpoint, + "/collections/mycollection/items?limit=1000&crs=http://www.opengis.net/def/crs/EPSG/0/4326&" + + ACCEPT_ITEMS, + ), + "wb", + ) as f: + f.write(json.dumps(first_items).encode("UTF-8")) values = [f.id() for f in vl.getFeatures()] self.assertEqual(values, [1]) # (Lat, Long) order - with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?PUTDATA={"geometry":{"coordinates":[50.0,3.0],"type":"Point"},"id":"feat.1","properties":{"cnt":100,"pk":1},"type":"Feature"}&Content-Crs=http://www.opengis.net/def/crs/EPSG/0/4326'), 'wb') as f: + with open( + sanitize( + endpoint, + '/collections/mycollection/items/feat.1?PUTDATA={"geometry":{"coordinates":[50.0,3.0],"type":"Point"},"id":"feat.1","properties":{"cnt":100,"pk":1},"type":"Feature"}&Content-Crs=http://www.opengis.net/def/crs/EPSG/0/4326', + ), + "wb", + ) as f: f.write(b"") - self.assertTrue(vl.dataProvider().changeGeometryValues({1: QgsGeometry.fromWkt('Point (3 50)')})) + self.assertTrue( + vl.dataProvider().changeGeometryValues( + {1: QgsGeometry.fromWkt("Point (3 50)")} + ) + ) got_f = [f for f in vl.getFeatures()] got = got_f[0].geometry().constGet() @@ -1564,43 +2437,86 @@ def testFeatureGeometryChangeNonDefaultCrs(self): def testFeatureGeometryChangePatch(self): - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testFeatureGeometryChangePatch' - create_landing_page_api_collection(endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/4326") + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_testFeatureGeometryChangePatch" + ) + create_landing_page_api_collection( + endpoint, storageCrs="http://www.opengis.net/def/crs/EPSG/0/4326" + ) # first items first_items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100}, - "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": {"pk": 1, "cnt": 100}, + "geometry": {"type": "Point", "coordinates": [-70.332, 66.33]}, + } + ], } - with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(first_items).encode("UTF-8")) - with open(sanitize(endpoint, '/collections/mycollection/items?VERB=OPTIONS'), 'wb') as f: - f.write("HEAD, GET, POST".encode("UTF-8")) - with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?VERB=OPTIONS'), 'wb') as f: - f.write("HEAD, GET, PUT, DELETE, PATCH".encode("UTF-8")) + with open( + sanitize(endpoint, "/collections/mycollection/items?VERB=OPTIONS"), "wb" + ) as f: + f.write(b"HEAD, GET, POST") + with open( + sanitize(endpoint, "/collections/mycollection/items/feat.1?VERB=OPTIONS"), + "wb", + ) as f: + f.write(b"HEAD, GET, PUT, DELETE, PATCH") - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test', - 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='mycollection' restrictToRequestBBOX=1", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) - self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries, - vl.dataProvider().NoCapabilities) + self.assertNotEqual( + vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries, + vl.dataProvider().NoCapabilities, + ) # real page - with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&crs=http://www.opengis.net/def/crs/EPSG/0/4326&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_items).encode('UTF-8')) + with open( + sanitize( + endpoint, + "/collections/mycollection/items?limit=1000&crs=http://www.opengis.net/def/crs/EPSG/0/4326&" + + ACCEPT_ITEMS, + ), + "wb", + ) as f: + f.write(json.dumps(first_items).encode("UTF-8")) values = [f.id() for f in vl.getFeatures()] self.assertEqual(values, [1]) # (Lat, Long) order - with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?PATCHDATA={"geometry":{"coordinates":[50.0,3.0],"type":"Point"}}&Content-Crs=http://www.opengis.net/def/crs/EPSG/0/4326&Content-Type=application_merge-patch+json'), 'wb') as f: + with open( + sanitize( + endpoint, + '/collections/mycollection/items/feat.1?PATCHDATA={"geometry":{"coordinates":[50.0,3.0],"type":"Point"}}&Content-Crs=http://www.opengis.net/def/crs/EPSG/0/4326&Content-Type=application_merge-patch+json', + ), + "wb", + ) as f: f.write(b"") - self.assertTrue(vl.dataProvider().changeGeometryValues({1: QgsGeometry.fromWkt('Point (3 50)')})) + self.assertTrue( + vl.dataProvider().changeGeometryValues( + {1: QgsGeometry.fromWkt("Point (3 50)")} + ) + ) got_f = [f for f in vl.getFeatures()] got = got_f[0].geometry().constGet() @@ -1608,132 +2524,223 @@ def testFeatureGeometryChangePatch(self): def testFeatureAttributeChange(self): - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testFeatureAttributeChange' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_testFeatureAttributeChange" + ) create_landing_page_api_collection(endpoint) # first items first_items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100}, - "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": {"pk": 1, "cnt": 100}, + "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}, + } + ], } - with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(first_items).encode("UTF-8")) - with open(sanitize(endpoint, '/collections/mycollection/items?VERB=OPTIONS'), 'wb') as f: - f.write("HEAD, GET, POST".encode("UTF-8")) - with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?VERB=OPTIONS'), 'wb') as f: - f.write("HEAD, GET, PUT, DELETE".encode("UTF-8")) + with open( + sanitize(endpoint, "/collections/mycollection/items?VERB=OPTIONS"), "wb" + ) as f: + f.write(b"HEAD, GET, POST") + with open( + sanitize(endpoint, "/collections/mycollection/items/feat.1?VERB=OPTIONS"), + "wb", + ) as f: + f.write(b"HEAD, GET, PUT, DELETE") - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test', - 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='mycollection' restrictToRequestBBOX=1", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) - self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries, - vl.dataProvider().NoCapabilities) + self.assertNotEqual( + vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries, + vl.dataProvider().NoCapabilities, + ) # real page - with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=1000&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(first_items).encode("UTF-8")) values = [f.id() for f in vl.getFeatures()] self.assertEqual(values, [1]) - with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?PUTDATA={"geometry":{"coordinates":[66.33,-70.332],"type":"Point"},"id":"feat.1","properties":{"cnt":200,"pk":1},"type":"Feature"}'), 'wb') as f: + with open( + sanitize( + endpoint, + '/collections/mycollection/items/feat.1?PUTDATA={"geometry":{"coordinates":[66.33,-70.332],"type":"Point"},"id":"feat.1","properties":{"cnt":200,"pk":1},"type":"Feature"}', + ), + "wb", + ) as f: f.write(b"") self.assertTrue(vl.dataProvider().changeAttributeValues({1: {2: 200}})) - values = [f['cnt'] for f in vl.getFeatures()] + values = [f["cnt"] for f in vl.getFeatures()] self.assertEqual(values, [200]) def testFeatureAttributeChangePatch(self): - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testFeatureAttributeChangePatch' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_testFeatureAttributeChangePatch" + ) create_landing_page_api_collection(endpoint) # first items first_items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": {"pk": 1, "cnt": 100}, - "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": {"pk": 1, "cnt": 100}, + "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}, + } + ], } - with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(first_items).encode("UTF-8")) - with open(sanitize(endpoint, '/collections/mycollection/items?VERB=OPTIONS'), 'wb') as f: - f.write("HEAD, GET, POST".encode("UTF-8")) - with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?VERB=OPTIONS'), 'wb') as f: - f.write("HEAD, GET, PUT, DELETE, PATCH".encode("UTF-8")) + with open( + sanitize(endpoint, "/collections/mycollection/items?VERB=OPTIONS"), "wb" + ) as f: + f.write(b"HEAD, GET, POST") + with open( + sanitize(endpoint, "/collections/mycollection/items/feat.1?VERB=OPTIONS"), + "wb", + ) as f: + f.write(b"HEAD, GET, PUT, DELETE, PATCH") - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test', - 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='mycollection' restrictToRequestBBOX=1", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) - self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries, - vl.dataProvider().NoCapabilities) + self.assertNotEqual( + vl.dataProvider().capabilities() & vl.dataProvider().ChangeGeometries, + vl.dataProvider().NoCapabilities, + ) # real page - with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=1000&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(first_items).encode("UTF-8")) values = [f.id() for f in vl.getFeatures()] self.assertEqual(values, [1]) - with open(sanitize(endpoint, '/collections/mycollection/items/feat.1?PATCHDATA={"properties":{"cnt":200}}&Content-Type=application_merge-patch+json'), 'wb') as f: + with open( + sanitize( + endpoint, + '/collections/mycollection/items/feat.1?PATCHDATA={"properties":{"cnt":200}}&Content-Type=application_merge-patch+json', + ), + "wb", + ) as f: f.write(b"") self.assertTrue(vl.dataProvider().changeAttributeValues({1: {2: 200}})) - values = [f['cnt'] for f in vl.getFeatures()] + values = [f["cnt"] for f in vl.getFeatures()] self.assertEqual(values, [200]) # GDAL 3.5.0 is required since it is the first version that tags "complex" # fields as OFSTJSON - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 5, 0), "GDAL 3.5.0 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 5, 0), + "GDAL 3.5.0 required", + ) def testFeatureComplexAttribute(self): - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testFeatureComplexAttribute' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_testFeatureComplexAttribute" + ) create_landing_page_api_collection(endpoint) # first items first_items = { "type": "FeatureCollection", "features": [ - {"type": "Feature", "id": "feat.1", "properties": {"center": { - "type": "Point", - "coordinates": [ - 6.50, - 51.80 - ] - }}, - "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}} - ] + { + "type": "Feature", + "id": "feat.1", + "properties": { + "center": {"type": "Point", "coordinates": [6.50, 51.80]} + }, + "geometry": {"type": "Point", "coordinates": [66.33, -70.332]}, + } + ], } - with open(sanitize(endpoint, '/collections/mycollection/items?limit=10&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=10&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(first_items).encode("UTF-8")) # real page - with open(sanitize(endpoint, '/collections/mycollection/items?limit=1000&' + ACCEPT_ITEMS), 'wb') as f: - f.write(json.dumps(first_items).encode('UTF-8')) + with open( + sanitize( + endpoint, "/collections/mycollection/items?limit=1000&" + ACCEPT_ITEMS + ), + "wb", + ) as f: + f.write(json.dumps(first_items).encode("UTF-8")) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='mycollection' restrictToRequestBBOX=1", 'test', - 'OAPIF') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='mycollection' restrictToRequestBBOX=1", + "test", + "OAPIF", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.fields().field("center").type(), QVariant.Map) # First time we getFeatures(): comes directly from the GeoJSON layer values = [f["center"] for f in vl.getFeatures()] - self.assertEqual(values, [{'coordinates': [6.5, 51.8], 'type': 'Point'}]) + self.assertEqual(values, [{"coordinates": [6.5, 51.8], "type": "Point"}]) # Now, that comes from the Spatialite cache, through # serialization and deserialization values = [f["center"] for f in vl.getFeatures()] - self.assertEqual(values, [{'coordinates': [6.5, 51.8], 'type': 'Point'}]) + self.assertEqual(values, [{"coordinates": [6.5, 51.8], "type": "Point"}]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_provider_ogr.py b/tests/src/python/test_provider_ogr.py index e03ee1ca34a8..aa0d15a90ef4 100644 --- a/tests/src/python/test_provider_ogr.py +++ b/tests/src/python/test_provider_ogr.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Even Rouault' -__date__ = '2016-04-11' -__copyright__ = 'Copyright 2016, Even Rouault' + +__author__ = "Even Rouault" +__date__ = "2016-04-11" +__copyright__ = "Copyright 2016, Even Rouault" import hashlib import os @@ -71,7 +72,7 @@ def GDAL_COMPUTE_VERSION(maj, min, rev): - return ((maj) * 1000000 + (min) * 10000 + (rev) * 100) + return (maj) * 1000000 + (min) * 10000 + (rev) * 100 # Note - doesn't implement ProviderTestCase as most OGR provider is tested by the shapefile provider test @@ -79,12 +80,12 @@ def GDAL_COMPUTE_VERSION(maj, min, rev): def count_opened_filedescriptors(filename_to_test): count = -1 - if sys.platform.startswith('linux'): + if sys.platform.startswith("linux"): count = 0 - open_files_dirname = '/proc/%d/fd' % os.getpid() + open_files_dirname = "/proc/%d/fd" % os.getpid() filenames = os.listdir(open_files_dirname) for filename in filenames: - full_filename = open_files_dirname + '/' + filename + full_filename = open_files_dirname + "/" + filename if os.path.exists(full_filename): link = os.readlink(full_filename) if os.path.basename(link) == os.path.basename(filename_to_test): @@ -100,15 +101,20 @@ def setUpClass(cls): super().setUpClass() # Create test layer cls.basetestpath = tempfile.mkdtemp() - cls.datasource = os.path.join(cls.basetestpath, 'test.csv') - with open(cls.datasource, 'w') as f: - f.write('id,WKT\n') - f.write('1,POINT(2 49)\n') + cls.datasource = os.path.join(cls.basetestpath, "test.csv") + with open(cls.datasource, "w") as f: + f.write("id,WKT\n") + f.write("1,POINT(2 49)\n") # Copy GPKG files to a temporary directory cls.temp_dir = tempfile.TemporaryDirectory() cls.temp_dir_path = cls.temp_dir.name - for f in ('curved_polys.gpkg', 'domains.gpkg', 'gps_timestamp.gpkg', 'mixed_layers.gpkg'): + for f in ( + "curved_polys.gpkg", + "domains.gpkg", + "gps_timestamp.gpkg", + "mixed_layers.gpkg", + ): shutil.copy(os.path.join(unitTestDataPath(), f), cls.temp_dir_path) cls.dirs_to_cleanup = [cls.basetestpath] @@ -123,7 +129,7 @@ def tearDownClass(cls): def testUpdateMode(self): - vl = QgsVectorLayer(f'{self.datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{self.datasource}|layerid=0", "test", "ogr") self.assertTrue(vl.isValid()) caps = vl.dataProvider().capabilities() self.assertTrue(caps & QgsVectorDataProvider.Capability.AddFeatures) @@ -140,60 +146,72 @@ def testUpdateMode(self): def testGeometryTypeKnownAtSecondFeature(self): - datasource = os.path.join(self.basetestpath, 'testGeometryTypeKnownAtSecondFeature.csv') - with open(datasource, 'w') as f: - f.write('id,WKT\n') - f.write('1,\n') - f.write('2,POINT(2 49)\n') + datasource = os.path.join( + self.basetestpath, "testGeometryTypeKnownAtSecondFeature.csv" + ) + with open(datasource, "w") as f: + f.write("id,WKT\n") + f.write("1,\n") + f.write("2,POINT(2 49)\n") - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) def testMixOfPolygonCurvePolygon(self): - datasource = os.path.join(self.basetestpath, 'testMixOfPolygonCurvePolygon.csv') - with open(datasource, 'w') as f: - f.write('id,WKT\n') + datasource = os.path.join(self.basetestpath, "testMixOfPolygonCurvePolygon.csv") + with open(datasource, "w") as f: + f.write("id,WKT\n") f.write('1,"POLYGON((0 0,0 1,1 1,0 0))"\n') f.write('2,"CURVEPOLYGON((0 0,0 1,1 1,0 0))"\n') f.write('3,"MULTIPOLYGON(((0 0,0 1,1 1,0 0)))"\n') f.write('4,"MULTISURFACE(((0 0,0 1,1 1,0 0)))"\n') - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") self.assertTrue(vl.isValid()) self.assertEqual(len(vl.dataProvider().subLayers()), 1) - self.assertEqual(vl.dataProvider().subLayers()[0], QgsDataProvider.SUBLAYER_SEPARATOR.join( - ['0', 'testMixOfPolygonCurvePolygon', '4', 'CurvePolygon', '', ''])) + self.assertEqual( + vl.dataProvider().subLayers()[0], + QgsDataProvider.SUBLAYER_SEPARATOR.join( + ["0", "testMixOfPolygonCurvePolygon", "4", "CurvePolygon", "", ""] + ), + ) def testMixOfLineStringCompoundCurve(self): - datasource = os.path.join(self.basetestpath, 'testMixOfLineStringCompoundCurve.csv') - with open(datasource, 'w') as f: - f.write('id,WKT\n') + datasource = os.path.join( + self.basetestpath, "testMixOfLineStringCompoundCurve.csv" + ) + with open(datasource, "w") as f: + f.write("id,WKT\n") f.write('1,"LINESTRING(0 0,0 1)"\n') f.write('2,"COMPOUNDCURVE((0 0,0 1))"\n') f.write('3,"MULTILINESTRING((0 0,0 1))"\n') f.write('4,"MULTICURVE((0 0,0 1))"\n') f.write('5,"CIRCULARSTRING(0 0,1 1,2 0)"\n') - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") self.assertTrue(vl.isValid()) self.assertEqual(len(vl.dataProvider().subLayers()), 1) - self.assertEqual(vl.dataProvider().subLayers()[0], QgsDataProvider.SUBLAYER_SEPARATOR.join( - ['0', 'testMixOfLineStringCompoundCurve', '5', 'CompoundCurve', '', ''])) + self.assertEqual( + vl.dataProvider().subLayers()[0], + QgsDataProvider.SUBLAYER_SEPARATOR.join( + ["0", "testMixOfLineStringCompoundCurve", "5", "CompoundCurve", "", ""] + ), + ) def testGpxElevation(self): # GPX without elevation data - datasource = os.path.join(TEST_DATA_DIR, 'noelev.gpx') - vl = QgsVectorLayer(f'{datasource}|layername=routes', 'test', 'ogr') + datasource = os.path.join(TEST_DATA_DIR, "noelev.gpx") + vl = QgsVectorLayer(f"{datasource}|layername=routes", "test", "ogr") self.assertTrue(vl.isValid()) f = next(vl.getFeatures()) self.assertEqual(f.geometry().wkbType(), QgsWkbTypes.Type.LineString) # GPX with elevation data - datasource = os.path.join(TEST_DATA_DIR, 'elev.gpx') - vl = QgsVectorLayer(f'{datasource}|layername=routes', 'test', 'ogr') + datasource = os.path.join(TEST_DATA_DIR, "elev.gpx") + vl = QgsVectorLayer(f"{datasource}|layername=routes", "test", "ogr") self.assertTrue(vl.isValid()) f = next(vl.getFeatures()) self.assertEqual(f.geometry().wkbType(), QgsWkbTypes.Type.LineStringZ) @@ -202,15 +220,17 @@ def testGpxElevation(self): self.assertEqual(f.geometry().constGet().pointN(2).z(), 3) def testNoDanglingFileDescriptorAfterCloseVariant1(self): - ''' Test that when closing the provider all file handles are released ''' + """Test that when closing the provider all file handles are released""" - datasource = os.path.join(self.basetestpath, 'testNoDanglingFileDescriptorAfterCloseVariant1.csv') - with open(datasource, 'w') as f: - f.write('id,WKT\n') - f.write('1,\n') - f.write('2,POINT(2 49)\n') + datasource = os.path.join( + self.basetestpath, "testNoDanglingFileDescriptorAfterCloseVariant1.csv" + ) + with open(datasource, "w") as f: + f.write("id,WKT\n") + f.write("1,\n") + f.write("2,POINT(2 49)\n") - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") self.assertTrue(vl.isValid()) # The iterator will take one extra connection myiter = vl.getFeatures() @@ -218,14 +238,14 @@ def testNoDanglingFileDescriptorAfterCloseVariant1(self): f = next(myiter) self.assertTrue(f.isValid()) - if sys.platform.startswith('linux'): + if sys.platform.startswith("linux"): self.assertEqual(count_opened_filedescriptors(datasource), 2) # Should release one file descriptor del vl # Non portable, but Windows testing is done with trying to unlink - if sys.platform.startswith('linux'): + if sys.platform.startswith("linux"): self.assertEqual(count_opened_filedescriptors(datasource), 1) f = next(myiter) @@ -235,7 +255,7 @@ def testNoDanglingFileDescriptorAfterCloseVariant1(self): del myiter # Non portable, but Windows testing is done with trying to unlink - if sys.platform.startswith('linux'): + if sys.platform.startswith("linux"): self.assertEqual(count_opened_filedescriptors(datasource), 0) # Check that deletion works well (can only fail on Windows) @@ -243,29 +263,31 @@ def testNoDanglingFileDescriptorAfterCloseVariant1(self): self.assertFalse(os.path.exists(datasource)) def testNoDanglingFileDescriptorAfterCloseVariant2(self): - ''' Test that when closing the provider all file handles are released ''' + """Test that when closing the provider all file handles are released""" - datasource = os.path.join(self.basetestpath, 'testNoDanglingFileDescriptorAfterCloseVariant2.csv') - with open(datasource, 'w') as f: - f.write('id,WKT\n') - f.write('1,\n') - f.write('2,POINT(2 49)\n') + datasource = os.path.join( + self.basetestpath, "testNoDanglingFileDescriptorAfterCloseVariant2.csv" + ) + with open(datasource, "w") as f: + f.write("id,WKT\n") + f.write("1,\n") + f.write("2,POINT(2 49)\n") - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") self.assertTrue(vl.isValid()) # Consume all features. myiter = vl.getFeatures() for feature in myiter: pass # The iterator is closed, but the corresponding connection still not closed - if sys.platform.startswith('linux'): + if sys.platform.startswith("linux"): self.assertEqual(count_opened_filedescriptors(datasource), 2) # Should release one file descriptor del vl # Non portable, but Windows testing is done with trying to unlink - if sys.platform.startswith('linux'): + if sys.platform.startswith("linux"): self.assertEqual(count_opened_filedescriptors(datasource), 0) # Check that deletion works well (can only fail on Windows) @@ -273,19 +295,21 @@ def testNoDanglingFileDescriptorAfterCloseVariant2(self): self.assertFalse(os.path.exists(datasource)) def testGeometryCollection(self): - ''' Test that we can at least retrieves attribute of features with geometry collection ''' + """Test that we can at least retrieves attribute of features with geometry collection""" - datasource = os.path.join(self.basetestpath, 'testGeometryCollection.csv') - with open(datasource, 'w') as f: - f.write('id,WKT\n') - f.write('1,POINT Z(2 49 0)\n') - f.write('2,GEOMETRYCOLLECTION Z (POINT Z (2 49 0))\n') + datasource = os.path.join(self.basetestpath, "testGeometryCollection.csv") + with open(datasource, "w") as f: + f.write("id,WKT\n") + f.write("1,POINT Z(2 49 0)\n") + f.write("2,GEOMETRYCOLLECTION Z (POINT Z (2 49 0))\n") - vl = QgsVectorLayer(f'{datasource}|layerid=0|geometrytype=GeometryCollection', 'test', 'ogr') + vl = QgsVectorLayer( + f"{datasource}|layerid=0|geometrytype=GeometryCollection", "test", "ogr" + ) self.assertTrue(vl.isValid()) self.assertTrue(vl.featureCount(), 1) - values = [f['id'] for f in vl.getFeatures()] - self.assertEqual(values, ['2']) + values = [f["id"] for f in vl.getFeatures()] + self.assertEqual(values, ["2"]) del vl os.unlink(datasource) @@ -295,66 +319,80 @@ def test_request_invalid_attributes(self): """ Test asking for invalid attributes in feature request """ - points_layer = QgsVectorLayer(os.path.join(unitTestDataPath(), 'points.shp'), 'points') + points_layer = QgsVectorLayer( + os.path.join(unitTestDataPath(), "points.shp"), "points" + ) self.assertTrue(points_layer.isValid()) req = QgsFeatureRequest() req.setSubsetOfAttributes([8, 0, 3, 7, 9, 10, 11, 13, 14]) features = list(points_layer.dataProvider().getFeatures(req)) - self.assertCountEqual([f.attributes() for f in features], - [['Jet', None, None, 2, None, None], - ['Biplane', None, None, 3, None, None], - ['Jet', None, None, 1, None, None], - ['Jet', None, None, 1, None, None], - ['Jet', None, None, 1, None, None], - ['Biplane', None, None, 3, None, None], - ['Biplane', None, None, 3, None, None], - ['Biplane', None, None, 3, None, None], - ['Biplane', None, None, 3, None, None], - ['B52', None, None, 2, None, None], - ['B52', None, None, 1, None, None], - ['B52', None, None, 2, None, None], - ['B52', None, None, 2, None, None], - ['Jet', None, None, 2, None, None], - ['Jet', None, None, 1, None, None], - ['Jet', None, None, 1, None, None], - ['Jet', None, None, 3, None, None]]) + self.assertCountEqual( + [f.attributes() for f in features], + [ + ["Jet", None, None, 2, None, None], + ["Biplane", None, None, 3, None, None], + ["Jet", None, None, 1, None, None], + ["Jet", None, None, 1, None, None], + ["Jet", None, None, 1, None, None], + ["Biplane", None, None, 3, None, None], + ["Biplane", None, None, 3, None, None], + ["Biplane", None, None, 3, None, None], + ["Biplane", None, None, 3, None, None], + ["B52", None, None, 2, None, None], + ["B52", None, None, 1, None, None], + ["B52", None, None, 2, None, None], + ["B52", None, None, 2, None, None], + ["Jet", None, None, 2, None, None], + ["Jet", None, None, 1, None, None], + ["Jet", None, None, 1, None, None], + ["Jet", None, None, 3, None, None], + ], + ) req = QgsFeatureRequest() - req.setSubsetOfAttributes(['nope', 'Class', 'Pilots', 'nope2'], points_layer.dataProvider().fields()) + req.setSubsetOfAttributes( + ["nope", "Class", "Pilots", "nope2"], points_layer.dataProvider().fields() + ) features = list(points_layer.dataProvider().getFeatures(req)) - self.assertCountEqual([f.attributes() for f in features], - [['Jet', None, None, 2, None, None], - ['Biplane', None, None, 3, None, None], - ['Jet', None, None, 1, None, None], - ['Jet', None, None, 1, None, None], - ['Jet', None, None, 1, None, None], - ['Biplane', None, None, 3, None, None], - ['Biplane', None, None, 3, None, None], - ['Biplane', None, None, 3, None, None], - ['Biplane', None, None, 3, None, None], - ['B52', None, None, 2, None, None], - ['B52', None, None, 1, None, None], - ['B52', None, None, 2, None, None], - ['B52', None, None, 2, None, None], - ['Jet', None, None, 2, None, None], - ['Jet', None, None, 1, None, None], - ['Jet', None, None, 1, None, None], - ['Jet', None, None, 3, None, None]]) + self.assertCountEqual( + [f.attributes() for f in features], + [ + ["Jet", None, None, 2, None, None], + ["Biplane", None, None, 3, None, None], + ["Jet", None, None, 1, None, None], + ["Jet", None, None, 1, None, None], + ["Jet", None, None, 1, None, None], + ["Biplane", None, None, 3, None, None], + ["Biplane", None, None, 3, None, None], + ["Biplane", None, None, 3, None, None], + ["Biplane", None, None, 3, None, None], + ["B52", None, None, 2, None, None], + ["B52", None, None, 1, None, None], + ["B52", None, None, 2, None, None], + ["B52", None, None, 2, None, None], + ["Jet", None, None, 2, None, None], + ["Jet", None, None, 1, None, None], + ["Jet", None, None, 1, None, None], + ["Jet", None, None, 3, None, None], + ], + ) def testGdb(self): - """ Test opening a GDB database layer""" - gdb_path = os.path.join(unitTestDataPath(), 'test_gdb.gdb') + """Test opening a GDB database layer""" + gdb_path = os.path.join(unitTestDataPath(), "test_gdb.gdb") for i in range(3): - l = QgsVectorLayer(gdb_path + '|layerid=' + str(i), 'test', 'ogr') + l = QgsVectorLayer(gdb_path + "|layerid=" + str(i), "test", "ogr") self.assertTrue(l.isValid()) def testGdbFilter(self): - """ Test opening a GDB database layer with filter""" - gdb_path = os.path.join(unitTestDataPath(), 'test_gdb.gdb') - l = QgsVectorLayer(gdb_path + '|layerid=1|subset="text" = \'shape 2\'', 'test', 'ogr') + """Test opening a GDB database layer with filter""" + gdb_path = os.path.join(unitTestDataPath(), "test_gdb.gdb") + l = QgsVectorLayer( + gdb_path + "|layerid=1|subset=\"text\" = 'shape 2'", "test", "ogr" + ) self.assertTrue(l.isValid()) it = l.getFeatures() f = QgsFeature() @@ -362,46 +400,76 @@ def testGdbFilter(self): self.assertEqual(f.attribute("text"), "shape 2") def testTriangleTINPolyhedralSurface(self): - """ Test support for Triangles (mapped to Polygons) """ + """Test support for Triangles (mapped to Polygons)""" testsets = ( - ("Triangle((0 0, 0 1, 1 1, 0 0))", QgsWkbTypes.Type.Triangle, "Triangle ((0 0, 0 1, 1 1, 0 0))"), - ("Triangle Z((0 0 1, 0 1 2, 1 1 3, 0 0 1))", QgsWkbTypes.Type.TriangleZ, - "Triangle Z ((0 0 1, 0 1 2, 1 1 3, 0 0 1))"), - ("Triangle M((0 0 4, 0 1 5, 1 1 6, 0 0 4))", QgsWkbTypes.Type.TriangleM, - "Triangle M ((0 0 4, 0 1 5, 1 1 6, 0 0 4))"), - ("Triangle ZM((0 0 0 1, 0 1 2 3, 1 1 4 5, 0 0 0 1))", QgsWkbTypes.Type.TriangleZM, - "Triangle ZM ((0 0 0 1, 0 1 2 3, 1 1 4 5, 0 0 0 1))"), - - ("TIN (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))", QgsWkbTypes.Type.TIN, - "TIN (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))"), - ("TIN Z(((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))", QgsWkbTypes.Type.TINZ, - "TIN Z (((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))"), - ("TIN M(((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))", QgsWkbTypes.Type.TINM, - "TIN M (((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))"), - ("TIN ZM(((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))", - QgsWkbTypes.Type.TINZM, - "TIN ZM (((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))"), - - ("PolyhedralSurface (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))", QgsWkbTypes.Type.PolyhedralSurface, - "PolyhedralSurface (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))"), - ("PolyhedralSurface Z(((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))", - - QgsWkbTypes.Type.PolyhedralSurfaceZ, - "PolyhedralSurface Z (((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))"), - ("PolyhedralSurface M(((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))", - QgsWkbTypes.Type.PolyhedralSurfaceM, - "PolyhedralSurface M (((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))"), - ("PolyhedralSurface ZM(((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))", - QgsWkbTypes.Type.PolyhedralSurfaceZM, - "PolyhedralSurface ZM (((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))") + ( + "Triangle((0 0, 0 1, 1 1, 0 0))", + QgsWkbTypes.Type.Triangle, + "Triangle ((0 0, 0 1, 1 1, 0 0))", + ), + ( + "Triangle Z((0 0 1, 0 1 2, 1 1 3, 0 0 1))", + QgsWkbTypes.Type.TriangleZ, + "Triangle Z ((0 0 1, 0 1 2, 1 1 3, 0 0 1))", + ), + ( + "Triangle M((0 0 4, 0 1 5, 1 1 6, 0 0 4))", + QgsWkbTypes.Type.TriangleM, + "Triangle M ((0 0 4, 0 1 5, 1 1 6, 0 0 4))", + ), + ( + "Triangle ZM((0 0 0 1, 0 1 2 3, 1 1 4 5, 0 0 0 1))", + QgsWkbTypes.Type.TriangleZM, + "Triangle ZM ((0 0 0 1, 0 1 2 3, 1 1 4 5, 0 0 0 1))", + ), + ( + "TIN (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))", + QgsWkbTypes.Type.TIN, + "TIN (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))", + ), + ( + "TIN Z(((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))", + QgsWkbTypes.Type.TINZ, + "TIN Z (((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))", + ), + ( + "TIN M(((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))", + QgsWkbTypes.Type.TINM, + "TIN M (((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))", + ), + ( + "TIN ZM(((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))", + QgsWkbTypes.Type.TINZM, + "TIN ZM (((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))", + ), + ( + "PolyhedralSurface (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))", + QgsWkbTypes.Type.PolyhedralSurface, + "PolyhedralSurface (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))", + ), + ( + "PolyhedralSurface Z(((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))", + QgsWkbTypes.Type.PolyhedralSurfaceZ, + "PolyhedralSurface Z (((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))", + ), + ( + "PolyhedralSurface M(((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))", + QgsWkbTypes.Type.PolyhedralSurfaceM, + "PolyhedralSurface M (((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))", + ), + ( + "PolyhedralSurface ZM(((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))", + QgsWkbTypes.Type.PolyhedralSurfaceZM, + "PolyhedralSurface ZM (((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))", + ), ) for row in testsets: - datasource = os.path.join(self.basetestpath, 'test.csv') - with open(datasource, 'w') as f: - f.write('id,WKT\n') + datasource = os.path.join(self.basetestpath, "test.csv") + with open(datasource, "w") as f: + f.write("id,WKT\n") f.write(f'1,"{row[0]}"') - vl = QgsVectorLayer(datasource, 'test', 'ogr') + vl = QgsVectorLayer(datasource, "test", "ogr") self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), row[1]) @@ -414,40 +482,52 @@ def testSetupProxy(self): """Test proxy setup""" settings = QgsSettings() settings.setValue("proxy/proxyEnabled", True) - settings.setValue("proxy/proxyPort", '1234') - settings.setValue("proxy/proxyHost", 'myproxyhostname.com') - settings.setValue("proxy/proxyUser", 'username') - settings.setValue("proxy/proxyPassword", 'password') - settings.setValue("proxy/proxyExcludedUrls", "http://www.myhost.com|http://www.myotherhost.com") + settings.setValue("proxy/proxyPort", "1234") + settings.setValue("proxy/proxyHost", "myproxyhostname.com") + settings.setValue("proxy/proxyUser", "username") + settings.setValue("proxy/proxyPassword", "password") + settings.setValue( + "proxy/proxyExcludedUrls", + "http://www.myhost.com|http://www.myotherhost.com", + ) QgsNetworkAccessManager.instance().setupDefaultProxyAndCache() - vl = QgsVectorLayer(TEST_DATA_DIR + '/' + 'lines.shp', 'proxy_test', 'ogr') + vl = QgsVectorLayer(TEST_DATA_DIR + "/" + "lines.shp", "proxy_test", "ogr") self.assertTrue(vl.isValid()) - self.assertEqual(gdal.GetConfigOption("GDAL_HTTP_PROXY"), "myproxyhostname.com:1234") - self.assertEqual(gdal.GetConfigOption("GDAL_HTTP_PROXYUSERPWD"), "username:password") + self.assertEqual( + gdal.GetConfigOption("GDAL_HTTP_PROXY"), "myproxyhostname.com:1234" + ) + self.assertEqual( + gdal.GetConfigOption("GDAL_HTTP_PROXYUSERPWD"), "username:password" + ) settings.setValue("proxy/proxyEnabled", True) settings.remove("proxy/proxyPort") - settings.setValue("proxy/proxyHost", 'myproxyhostname.com') - settings.setValue("proxy/proxyUser", 'username') + settings.setValue("proxy/proxyHost", "myproxyhostname.com") + settings.setValue("proxy/proxyUser", "username") settings.remove("proxy/proxyPassword") - settings.setValue("proxy/proxyExcludedUrls", "http://www.myhost.com|http://www.myotherhost.com") + settings.setValue( + "proxy/proxyExcludedUrls", + "http://www.myhost.com|http://www.myotherhost.com", + ) QgsNetworkAccessManager.instance().setupDefaultProxyAndCache() - vl = QgsVectorLayer(TEST_DATA_DIR + '/' + 'lines.shp', 'proxy_test', 'ogr') + vl = QgsVectorLayer(TEST_DATA_DIR + "/" + "lines.shp", "proxy_test", "ogr") self.assertTrue(vl.isValid()) self.assertEqual(gdal.GetConfigOption("GDAL_HTTP_PROXY"), "myproxyhostname.com") self.assertEqual(gdal.GetConfigOption("GDAL_HTTP_PROXYUSERPWD"), "username") def testEditGeoJsonRemoveField(self): - """ Test bugfix of https://github.com/qgis/QGIS/issues/26484 (deleting an existing field)""" + """Test bugfix of https://github.com/qgis/QGIS/issues/26484 (deleting an existing field)""" - datasource = os.path.join(self.basetestpath, 'testEditGeoJsonRemoveField.json') - with open(datasource, 'w') as f: - f.write("""{ + datasource = os.path.join(self.basetestpath, "testEditGeoJsonRemoveField.json") + with open(datasource, "w") as f: + f.write( + """{ "type": "FeatureCollection", "features": [ -{ "type": "Feature", "properties": { "x": 1, "y": 2, "z": 3, "w": 4 }, "geometry": { "type": "Point", "coordinates": [ 0, 0 ] } } ] }""") +{ "type": "Feature", "properties": { "x": 1, "y": 2, "z": 3, "w": 4 }, "geometry": { "type": "Point", "coordinates": [ 0, 0 ] } } ] }""" + ) - vl = QgsVectorLayer(datasource, 'test', 'ogr') + vl = QgsVectorLayer(datasource, "test", "ogr") self.assertTrue(vl.isValid()) self.assertTrue(vl.startEditing()) self.assertTrue(vl.deleteAttribute(1)) @@ -456,70 +536,76 @@ def testEditGeoJsonRemoveField(self): f = QgsFeature() self.assertTrue(vl.getFeatures(QgsFeatureRequest()).nextFeature(f)) - self.assertEqual(f['x'], 1) - self.assertEqual(f['z'], 3) - self.assertEqual(f['w'], 4) + self.assertEqual(f["x"], 1) + self.assertEqual(f["z"], 3) + self.assertEqual(f["w"], 4) def testEditGeoJsonAddField(self): - """ Test bugfix of https://github.com/qgis/QGIS/issues/26484 (adding a new field)""" + """Test bugfix of https://github.com/qgis/QGIS/issues/26484 (adding a new field)""" - datasource = os.path.join(self.basetestpath, 'testEditGeoJsonAddField.json') - with open(datasource, 'w') as f: - f.write("""{ + datasource = os.path.join(self.basetestpath, "testEditGeoJsonAddField.json") + with open(datasource, "w") as f: + f.write( + """{ "type": "FeatureCollection", "features": [ -{ "type": "Feature", "properties": { "x": 1 }, "geometry": { "type": "Point", "coordinates": [ 0, 0 ] } } ] }""") +{ "type": "Feature", "properties": { "x": 1 }, "geometry": { "type": "Point", "coordinates": [ 0, 0 ] } } ] }""" + ) - vl = QgsVectorLayer(datasource, 'test', 'ogr') + vl = QgsVectorLayer(datasource, "test", "ogr") self.assertTrue(vl.isValid()) self.assertTrue(vl.startEditing()) - self.assertTrue(vl.addAttribute(QgsField('strfield', QVariant.String))) + self.assertTrue(vl.addAttribute(QgsField("strfield", QVariant.String))) self.assertTrue(vl.commitChanges()) self.assertEqual(len(vl.dataProvider().fields()), 1 + 1) f = QgsFeature() self.assertTrue(vl.getFeatures(QgsFeatureRequest()).nextFeature(f)) - self.assertIsNone(f['strfield']) + self.assertIsNone(f["strfield"]) # Completely reload file - vl = QgsVectorLayer(datasource, 'test', 'ogr') + vl = QgsVectorLayer(datasource, "test", "ogr") # As we didn't set any value to the new field, it is not written at # all in the GeoJSON file, so it has disappeared self.assertEqual(len(vl.fields()), 1) def testEditGeoJsonAddFieldAndThenAddFeatures(self): - """ Test bugfix of https://github.com/qgis/QGIS/issues/26484 (adding a new field)""" + """Test bugfix of https://github.com/qgis/QGIS/issues/26484 (adding a new field)""" - datasource = os.path.join(self.basetestpath, 'testEditGeoJsonAddField.json') - with open(datasource, 'w') as f: - f.write("""{ + datasource = os.path.join(self.basetestpath, "testEditGeoJsonAddField.json") + with open(datasource, "w") as f: + f.write( + """{ "type": "FeatureCollection", "features": [ -{ "type": "Feature", "properties": { "x": 1 }, "geometry": { "type": "Point", "coordinates": [ 0, 0 ] } } ] }""") +{ "type": "Feature", "properties": { "x": 1 }, "geometry": { "type": "Point", "coordinates": [ 0, 0 ] } } ] }""" + ) - vl = QgsVectorLayer(datasource, 'test', 'ogr') + vl = QgsVectorLayer(datasource, "test", "ogr") self.assertTrue(vl.isValid()) self.assertTrue(vl.startEditing()) - self.assertTrue(vl.addAttribute(QgsField('strfield', QVariant.String))) + self.assertTrue(vl.addAttribute(QgsField("strfield", QVariant.String))) self.assertTrue(vl.commitChanges()) self.assertEqual(len(vl.dataProvider().fields()), 1 + 1) - self.assertEqual([f.name() for f in vl.dataProvider().fields()], ['x', 'strfield']) + self.assertEqual( + [f.name() for f in vl.dataProvider().fields()], ["x", "strfield"] + ) f = QgsFeature() self.assertTrue(vl.getFeatures(QgsFeatureRequest()).nextFeature(f)) - self.assertIsNone(f['strfield']) - self.assertEqual([field.name() for field in f.fields()], ['x', 'strfield']) + self.assertIsNone(f["strfield"]) + self.assertEqual([field.name() for field in f.fields()], ["x", "strfield"]) self.assertTrue(vl.startEditing()) - vl.changeAttributeValue(f.id(), 1, 'x') + vl.changeAttributeValue(f.id(), 1, "x") self.assertTrue(vl.commitChanges()) f = QgsFeature() self.assertTrue(vl.getFeatures(QgsFeatureRequest()).nextFeature(f)) - self.assertEqual(f['strfield'], 'x') - self.assertEqual([field.name() for field in f.fields()], ['x', 'strfield']) + self.assertEqual(f["strfield"], "x") + self.assertEqual([field.name() for field in f.fields()], ["x", "strfield"]) # Completely reload file - vl = QgsVectorLayer(datasource, 'test', 'ogr') + vl = QgsVectorLayer(datasource, "test", "ogr") self.assertEqual(len(vl.fields()), 2) def testAddFeatureWithUnsetValue(self): @@ -527,108 +613,158 @@ def testAddFeatureWithUnsetValue(self): Test adding features with unset values """ with tempfile.TemporaryDirectory() as temp_dir: - tmpfile = os.path.join(temp_dir, 'test_unset_value.gpkg') + tmpfile = os.path.join(temp_dir, "test_unset_value.gpkg") - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) ds.ExecuteSQL( - "CREATE TABLE test(fid INTEGER PRIMARY KEY, name TEXT DEFAULT 'default_value', auto_number INTEGER DEFAULT 55)") + "CREATE TABLE test(fid INTEGER PRIMARY KEY, name TEXT DEFAULT 'default_value', auto_number INTEGER DEFAULT 55)" + ) ds = None - layer = QgsVectorLayer(tmpfile, 'test') + layer = QgsVectorLayer(tmpfile, "test") self.assertTrue(layer.isValid()) self.assertFalse( - layer.dataProvider().skipConstraintCheck(0, QgsFieldConstraints.Constraint.ConstraintUnique, 5)) - self.assertTrue(layer.dataProvider().skipConstraintCheck(0, QgsFieldConstraints.Constraint.ConstraintUnique, 'Autogenerate')) + layer.dataProvider().skipConstraintCheck( + 0, QgsFieldConstraints.Constraint.ConstraintUnique, 5 + ) + ) self.assertTrue( - layer.dataProvider().skipConstraintCheck(0, QgsFieldConstraints.Constraint.ConstraintUnique, QgsUnsetAttributeValue())) + layer.dataProvider().skipConstraintCheck( + 0, QgsFieldConstraints.Constraint.ConstraintUnique, "Autogenerate" + ) + ) + self.assertTrue( + layer.dataProvider().skipConstraintCheck( + 0, + QgsFieldConstraints.Constraint.ConstraintUnique, + QgsUnsetAttributeValue(), + ) + ) self.assertTrue( - layer.dataProvider().skipConstraintCheck(0, QgsFieldConstraints.Constraint.ConstraintUnique, QgsUnsetAttributeValue('Autogenerate'))) - self.assertFalse(layer.dataProvider().skipConstraintCheck(1, QgsFieldConstraints.Constraint.ConstraintUnique, 'my name')) + layer.dataProvider().skipConstraintCheck( + 0, + QgsFieldConstraints.Constraint.ConstraintUnique, + QgsUnsetAttributeValue("Autogenerate"), + ) + ) + self.assertFalse( + layer.dataProvider().skipConstraintCheck( + 1, QgsFieldConstraints.Constraint.ConstraintUnique, "my name" + ) + ) self.assertFalse( - layer.dataProvider().skipConstraintCheck(1, QgsFieldConstraints.Constraint.ConstraintUnique, NULL)) + layer.dataProvider().skipConstraintCheck( + 1, QgsFieldConstraints.Constraint.ConstraintUnique, NULL + ) + ) self.assertTrue( - layer.dataProvider().skipConstraintCheck(1, QgsFieldConstraints.Constraint.ConstraintUnique, QgsUnsetAttributeValue())) + layer.dataProvider().skipConstraintCheck( + 1, + QgsFieldConstraints.Constraint.ConstraintUnique, + QgsUnsetAttributeValue(), + ) + ) self.assertFalse( - layer.dataProvider().skipConstraintCheck(2, QgsFieldConstraints.Constraint.ConstraintUnique, 11)) + layer.dataProvider().skipConstraintCheck( + 2, QgsFieldConstraints.Constraint.ConstraintUnique, 11 + ) + ) self.assertTrue( - layer.dataProvider().skipConstraintCheck(2, QgsFieldConstraints.Constraint.ConstraintUnique, QgsUnsetAttributeValue())) + layer.dataProvider().skipConstraintCheck( + 2, + QgsFieldConstraints.Constraint.ConstraintUnique, + QgsUnsetAttributeValue(), + ) + ) feature = QgsFeature(layer.fields()) - feature.setAttributes([1, 'test1', 11]) + feature.setAttributes([1, "test1", 11]) self.assertTrue(layer.dataProvider().addFeature(feature)) f1 = feature.id() - feature.setAttributes([QgsUnsetAttributeValue('Autonumber'), 'test2', 22]) + feature.setAttributes([QgsUnsetAttributeValue("Autonumber"), "test2", 22]) self.assertTrue(layer.dataProvider().addFeature(feature)) f2 = feature.id() del layer - layer = QgsVectorLayer(tmpfile, 'test') + layer = QgsVectorLayer(tmpfile, "test") # read back in features and test f1_read = layer.getFeature(f1) - self.assertEqual(f1_read.attributes(), [1, 'test1', 11]) + self.assertEqual(f1_read.attributes(), [1, "test1", 11]) f2_read = layer.getFeature(f2) - self.assertEqual(f2_read.attributes(), [f2, 'test2', 22]) + self.assertEqual(f2_read.attributes(), [f2, "test2", 22]) def testDataItems(self): - dataitem = QgsDirectoryItem(None, 'name', unitTestDataPath()) + dataitem = QgsDirectoryItem(None, "name", unitTestDataPath()) children = dataitem.createChildren() # Single layer - item = [i for i in children if i.path().endswith('lines.shp')][0] - self.assertTrue(item.uri().endswith('lines.shp')) + item = [i for i in children if i.path().endswith("lines.shp")][0] + self.assertTrue(item.uri().endswith("lines.shp")) # Multiple layer - item = [i for i in children if i.path().endswith('multilayer.kml')][0] + item = [i for i in children if i.path().endswith("multilayer.kml")][0] children = item.createChildren() self.assertEqual(len(children), 2) - self.assertIn('multilayer.kml|layername=Layer1', children[0].uri()) - self.assertIn('multilayer.kml|layername=Layer2', children[1].uri()) + self.assertIn("multilayer.kml|layername=Layer1", children[0].uri()) + self.assertIn("multilayer.kml|layername=Layer2", children[1].uri()) # Multiple layer (geopackage) - tmpfile = os.path.join(self.basetestpath, 'testDataItems.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('Layer1', geom_type=ogr.wkbPoint) - lyr = ds.CreateLayer('Layer2', geom_type=ogr.wkbPoint) + tmpfile = os.path.join(self.basetestpath, "testDataItems.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("Layer1", geom_type=ogr.wkbPoint) + lyr = ds.CreateLayer("Layer2", geom_type=ogr.wkbPoint) ds = None - dataitem = QgsDirectoryItem(None, 'name', self.basetestpath) + dataitem = QgsDirectoryItem(None, "name", self.basetestpath) children = dataitem.createChildren() - item = [i for i in children if i.path().endswith('testDataItems.gpkg')][0] + item = [i for i in children if i.path().endswith("testDataItems.gpkg")][0] children = item.createChildren() self.assertEqual(len(children), 2) - self.assertIn('testDataItems.gpkg|layername=Layer1', children[0].uri()) - self.assertIn('testDataItems.gpkg|layername=Layer2', children[1].uri()) + self.assertIn("testDataItems.gpkg|layername=Layer1", children[0].uri()) + self.assertIn("testDataItems.gpkg|layername=Layer2", children[1].uri()) def testDataItemsRaster(self): - dataitem = QgsDirectoryItem(None, 'name', unitTestDataPath()) + dataitem = QgsDirectoryItem(None, "name", unitTestDataPath()) dir_children = dataitem.createChildren() # Multiple layer (geopackage) - item = [i for i in dir_children if i.path().endswith('two_raster_layers.gpkg')][0] + item = [i for i in dir_children if i.path().endswith("two_raster_layers.gpkg")][ + 0 + ] children = item.createChildren() self.assertEqual(len(children), 2) - self.assertIn('GPKG:' + unitTestDataPath() + '/two_raster_layers.gpkg:layer01', children[0].uri()) - self.assertIn('GPKG:' + unitTestDataPath() + '/two_raster_layers.gpkg:layer02', children[1].uri()) + self.assertIn( + "GPKG:" + unitTestDataPath() + "/two_raster_layers.gpkg:layer01", + children[0].uri(), + ) + self.assertIn( + "GPKG:" + unitTestDataPath() + "/two_raster_layers.gpkg:layer02", + children[1].uri(), + ) def testOSM(self): - """ Test that opening several layers of the same OSM datasource works properly """ + """Test that opening several layers of the same OSM datasource works properly""" - datasource = os.path.join(TEST_DATA_DIR, 'test.osm') - vl_points = QgsVectorLayer(datasource + "|layername=points", 'test', 'ogr') - vl_multipolygons = QgsVectorLayer(datasource + "|layername=multipolygons", 'test', 'ogr') + datasource = os.path.join(TEST_DATA_DIR, "test.osm") + vl_points = QgsVectorLayer(datasource + "|layername=points", "test", "ogr") + vl_multipolygons = QgsVectorLayer( + datasource + "|layername=multipolygons", "test", "ogr" + ) f = QgsFeature() # When sharing the same dataset handle, the spatial filter of test # points layer would apply to the other layers - iter_points = vl_points.getFeatures(QgsFeatureRequest().setFilterRect(QgsRectangle(-200, -200, -200, -200))) + iter_points = vl_points.getFeatures( + QgsFeatureRequest().setFilterRect(QgsRectangle(-200, -200, -200, -200)) + ) self.assertFalse(iter_points.nextFeature(f)) iter_multipolygons = vl_multipolygons.getFeatures(QgsFeatureRequest()) @@ -655,7 +791,9 @@ def testOSM(self): self.assertEqual(f.id(), 5) # 6 doesn't exist - it = vl_multipolygons.getFeatures(QgsFeatureRequest().setFilterFids([1, 5, 6, 8])) + it = vl_multipolygons.getFeatures( + QgsFeatureRequest().setFilterFids([1, 5, 6, 8]) + ) f = next(it) self.assertTrue(f.isValid()) self.assertEqual(f.id(), 1) @@ -668,43 +806,49 @@ def testOSM(self): del it def testBinaryField(self): - source = os.path.join(TEST_DATA_DIR, 'attachments.gdb') + source = os.path.join(TEST_DATA_DIR, "attachments.gdb") vl = QgsVectorLayer(source + "|layername=points__ATTACH") self.assertTrue(vl.isValid()) fields = vl.fields() - data_field = fields[fields.lookupField('DATA')] + data_field = fields[fields.lookupField("DATA")] self.assertEqual(data_field.type(), QVariant.ByteArray) - self.assertEqual(data_field.typeName(), 'Binary') + self.assertEqual(data_field.typeName(), "Binary") - features = {f['ATTACHMENTID']: f for f in vl.getFeatures()} + features = {f["ATTACHMENTID"]: f for f in vl.getFeatures()} self.assertEqual(len(features), 2) - self.assertIsInstance(features[1]['DATA'], QByteArray) - self.assertEqual(hashlib.md5(features[1]['DATA'].data()).hexdigest(), 'ef3dbc530cc39a545832a6c82aac57b6') - self.assertIsInstance(features[2]['DATA'], QByteArray) - self.assertEqual(hashlib.md5(features[2]['DATA'].data()).hexdigest(), '4b952b80e4288ca5111be2f6dd5d6809') + self.assertIsInstance(features[1]["DATA"], QByteArray) + self.assertEqual( + hashlib.md5(features[1]["DATA"].data()).hexdigest(), + "ef3dbc530cc39a545832a6c82aac57b6", + ) + self.assertIsInstance(features[2]["DATA"], QByteArray) + self.assertEqual( + hashlib.md5(features[2]["DATA"].data()).hexdigest(), + "4b952b80e4288ca5111be2f6dd5d6809", + ) def testGmlStringListField(self): - source = os.path.join(TEST_DATA_DIR, 'stringlist.gml') + source = os.path.join(TEST_DATA_DIR, "stringlist.gml") vl = QgsVectorLayer(source) self.assertTrue(vl.isValid()) fields = vl.fields() - descriptive_group_field = fields[fields.lookupField('descriptiveGroup')] + descriptive_group_field = fields[fields.lookupField("descriptiveGroup")] self.assertEqual(descriptive_group_field.type(), QVariant.StringList) - self.assertEqual(descriptive_group_field.typeName(), 'StringList') + self.assertEqual(descriptive_group_field.typeName(), "StringList") self.assertEqual(descriptive_group_field.subType(), QVariant.String) feature = vl.getFeature(1000002717654) - self.assertEqual(feature['descriptiveGroup'], ['Building']) - self.assertEqual(feature['reasonForChange'], ['Reclassified', 'Attributes']) - - tmpfile = os.path.join(self.basetestpath, 'newstringlistfield.gml') - ds = ogr.GetDriverByName('GML').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger)) - lyr.CreateField(ogr.FieldDefn('strlistfield', ogr.OFTStringList)) + self.assertEqual(feature["descriptiveGroup"], ["Building"]) + self.assertEqual(feature["reasonForChange"], ["Reclassified", "Attributes"]) + + tmpfile = os.path.join(self.basetestpath, "newstringlistfield.gml") + ds = ogr.GetDriverByName("GML").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("strfield", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("intfield", ogr.OFTInteger)) + lyr.CreateField(ogr.FieldDefn("strlistfield", ogr.OFTStringList)) ds = None vl = QgsVectorLayer(tmpfile) @@ -712,24 +856,24 @@ def testGmlStringListField(self): dp = vl.dataProvider() fields = dp.fields() - list_field = fields[fields.lookupField('strlistfield')] + list_field = fields[fields.lookupField("strlistfield")] self.assertEqual(list_field.type(), QVariant.StringList) - self.assertEqual(list_field.typeName(), 'StringList') + self.assertEqual(list_field.typeName(), "StringList") self.assertEqual(list_field.subType(), QVariant.String) def testStringListField(self): - tmpfile = os.path.join(self.basetestpath, 'newstringlistfield.geojson') - ds = ogr.GetDriverByName('GeoJSON').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger)) - lyr.CreateField(ogr.FieldDefn('stringlistfield', ogr.OFTStringList)) + tmpfile = os.path.join(self.basetestpath, "newstringlistfield.geojson") + ds = ogr.GetDriverByName("GeoJSON").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("strfield", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("intfield", ogr.OFTInteger)) + lyr.CreateField(ogr.FieldDefn("stringlistfield", ogr.OFTStringList)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (1 1)')) - f.SetField('strfield', 'one') - f.SetField('intfield', 1) - f.SetFieldStringList(2, ['a', 'b', 'c']) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (1 1)")) + f.SetField("strfield", "one") + f.SetField("intfield", 1) + f.SetFieldStringList(2, ["a", "b", "c"]) lyr.CreateFeature(f) lyr = None @@ -740,21 +884,21 @@ def testStringListField(self): dp = vl.dataProvider() fields = dp.fields() - list_field = fields[fields.lookupField('stringlistfield')] + list_field = fields[fields.lookupField("stringlistfield")] self.assertEqual(list_field.type(), QVariant.StringList) - self.assertEqual(list_field.typeName(), 'StringList') + self.assertEqual(list_field.typeName(), "StringList") self.assertEqual(list_field.subType(), QVariant.String) f = next(vl.getFeatures()) - self.assertEqual(f.attributes(), ['one', 1, ['a', 'b', 'c']]) + self.assertEqual(f.attributes(), ["one", 1, ["a", "b", "c"]]) # add features f = QgsFeature() - f.setAttributes(['two', 2, ['z', 'y', 'x']]) + f.setAttributes(["two", 2, ["z", "y", "x"]]) self.assertTrue(vl.dataProvider().addFeature(f)) - f.setAttributes(['three', 3, NULL]) + f.setAttributes(["three", 3, NULL]) self.assertTrue(vl.dataProvider().addFeature(f)) - f.setAttributes(['four', 4, []]) + f.setAttributes(["four", 4, []]) self.assertTrue(vl.dataProvider().addFeature(f)) vl = None @@ -762,54 +906,81 @@ def testStringListField(self): vl = QgsVectorLayer(tmpfile) self.assertTrue(vl.isValid()) - self.assertEqual([f.attributes() for f in vl.getFeatures()], - [['one', 1, ['a', 'b', 'c']], - ['two', 2, ['z', 'y', 'x']], - ['three', 3, NULL], - ['four', 4, NULL]]) + self.assertEqual( + [f.attributes() for f in vl.getFeatures()], + [ + ["one", 1, ["a", "b", "c"]], + ["two", 2, ["z", "y", "x"]], + ["three", 3, NULL], + ["four", 4, NULL], + ], + ) # change attribute values f1_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 1][0] f3_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 3][0] - self.assertTrue(vl.dataProvider().changeAttributeValues({f1_id: {2: NULL}, f3_id: {2: ['m', 'n', 'o']}})) + self.assertTrue( + vl.dataProvider().changeAttributeValues( + {f1_id: {2: NULL}, f3_id: {2: ["m", "n", "o"]}} + ) + ) vl = QgsVectorLayer(tmpfile) self.assertTrue(vl.isValid()) - self.assertEqual([f.attributes() for f in vl.getFeatures()], - [['one', 1, NULL], - ['two', 2, ['z', 'y', 'x']], - ['three', 3, ['m', 'n', 'o']], - ['four', 4, NULL]]) + self.assertEqual( + [f.attributes() for f in vl.getFeatures()], + [ + ["one", 1, NULL], + ["two", 2, ["z", "y", "x"]], + ["three", 3, ["m", "n", "o"]], + ["four", 4, NULL], + ], + ) # add attribute self.assertTrue( - vl.dataProvider().addAttributes([QgsField('new_list', type=QVariant.StringList, subType=QVariant.String)])) + vl.dataProvider().addAttributes( + [ + QgsField( + "new_list", type=QVariant.StringList, subType=QVariant.String + ) + ] + ) + ) f1_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 1][0] f3_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 3][0] - self.assertTrue(vl.dataProvider().changeAttributeValues({f1_id: {3: ['111', '222']}, f3_id: {3: ['121', '122', '123']}})) + self.assertTrue( + vl.dataProvider().changeAttributeValues( + {f1_id: {3: ["111", "222"]}, f3_id: {3: ["121", "122", "123"]}} + ) + ) vl = QgsVectorLayer(tmpfile) self.assertTrue(vl.isValid()) - self.assertEqual([f.attributes() for f in vl.getFeatures()], - [['one', 1, NULL, ['111', '222']], - ['two', 2, ['z', 'y', 'x'], NULL], - ['three', 3, ['m', 'n', 'o'], ['121', '122', '123']], - ['four', 4, NULL, NULL]]) + self.assertEqual( + [f.attributes() for f in vl.getFeatures()], + [ + ["one", 1, NULL, ["111", "222"]], + ["two", 2, ["z", "y", "x"], NULL], + ["three", 3, ["m", "n", "o"], ["121", "122", "123"]], + ["four", 4, NULL, NULL], + ], + ) def testIntListField(self): - tmpfile = os.path.join(self.basetestpath, 'newintlistfield.geojson') - ds = ogr.GetDriverByName('GeoJSON').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger)) - lyr.CreateField(ogr.FieldDefn('intlistfield', ogr.OFTIntegerList)) + tmpfile = os.path.join(self.basetestpath, "newintlistfield.geojson") + ds = ogr.GetDriverByName("GeoJSON").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("strfield", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("intfield", ogr.OFTInteger)) + lyr.CreateField(ogr.FieldDefn("intlistfield", ogr.OFTIntegerList)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (1 1)')) - f.SetField('strfield', 'one') - f.SetField('intfield', 1) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (1 1)")) + f.SetField("strfield", "one") + f.SetField("intfield", 1) f.SetFieldIntegerList(2, [1, 2, 3, 4]) lyr.CreateFeature(f) @@ -821,21 +992,21 @@ def testIntListField(self): dp = vl.dataProvider() fields = dp.fields() - list_field = fields[fields.lookupField('intlistfield')] + list_field = fields[fields.lookupField("intlistfield")] self.assertEqual(list_field.type(), QVariant.List) - self.assertEqual(list_field.typeName(), 'IntegerList') + self.assertEqual(list_field.typeName(), "IntegerList") self.assertEqual(list_field.subType(), QVariant.Int) f = next(vl.getFeatures()) - self.assertEqual(f.attributes(), ['one', 1, [1, 2, 3, 4]]) + self.assertEqual(f.attributes(), ["one", 1, [1, 2, 3, 4]]) # add features f = QgsFeature() - f.setAttributes(['two', 2, [11, 12, 13, 14]]) + f.setAttributes(["two", 2, [11, 12, 13, 14]]) self.assertTrue(vl.dataProvider().addFeature(f)) - f.setAttributes(['three', 3, NULL]) + f.setAttributes(["three", 3, NULL]) self.assertTrue(vl.dataProvider().addFeature(f)) - f.setAttributes(['four', 4, []]) + f.setAttributes(["four", 4, []]) self.assertTrue(vl.dataProvider().addFeature(f)) vl = None @@ -843,54 +1014,77 @@ def testIntListField(self): vl = QgsVectorLayer(tmpfile) self.assertTrue(vl.isValid()) - self.assertEqual([f.attributes() for f in vl.getFeatures()], - [['one', 1, [1, 2, 3, 4]], - ['two', 2, [11, 12, 13, 14]], - ['three', 3, NULL], - ['four', 4, NULL]]) + self.assertEqual( + [f.attributes() for f in vl.getFeatures()], + [ + ["one", 1, [1, 2, 3, 4]], + ["two", 2, [11, 12, 13, 14]], + ["three", 3, NULL], + ["four", 4, NULL], + ], + ) # change attribute values f1_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 1][0] f3_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 3][0] - self.assertTrue(vl.dataProvider().changeAttributeValues({f1_id: {2: NULL}, f3_id: {2: [21, 22, 23]}})) + self.assertTrue( + vl.dataProvider().changeAttributeValues( + {f1_id: {2: NULL}, f3_id: {2: [21, 22, 23]}} + ) + ) vl = QgsVectorLayer(tmpfile) self.assertTrue(vl.isValid()) - self.assertEqual([f.attributes() for f in vl.getFeatures()], - [['one', 1, NULL], - ['two', 2, [11, 12, 13, 14]], - ['three', 3, [21, 22, 23]], - ['four', 4, NULL]]) + self.assertEqual( + [f.attributes() for f in vl.getFeatures()], + [ + ["one", 1, NULL], + ["two", 2, [11, 12, 13, 14]], + ["three", 3, [21, 22, 23]], + ["four", 4, NULL], + ], + ) # add attribute self.assertTrue( - vl.dataProvider().addAttributes([QgsField('new_list', type=QVariant.List, subType=QVariant.Int)])) + vl.dataProvider().addAttributes( + [QgsField("new_list", type=QVariant.List, subType=QVariant.Int)] + ) + ) f1_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 1][0] f3_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 3][0] - self.assertTrue(vl.dataProvider().changeAttributeValues({f1_id: {3: [111, 222]}, f3_id: {3: [121, 122, 123]}})) + self.assertTrue( + vl.dataProvider().changeAttributeValues( + {f1_id: {3: [111, 222]}, f3_id: {3: [121, 122, 123]}} + ) + ) vl = QgsVectorLayer(tmpfile) self.assertTrue(vl.isValid()) - self.assertEqual([f.attributes() for f in vl.getFeatures()], - [['one', 1, NULL, [111, 222]], - ['two', 2, [11, 12, 13, 14], NULL], - ['three', 3, [21, 22, 23], [121, 122, 123]], - ['four', 4, NULL, NULL]]) + self.assertEqual( + [f.attributes() for f in vl.getFeatures()], + [ + ["one", 1, NULL, [111, 222]], + ["two", 2, [11, 12, 13, 14], NULL], + ["three", 3, [21, 22, 23], [121, 122, 123]], + ["four", 4, NULL, NULL], + ], + ) def testDoubleListField(self): - tmpfile = os.path.join(self.basetestpath, 'newdoublelistfield.geojson') - ds = ogr.GetDriverByName('GeoJSON').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger)) - lyr.CreateField(ogr.FieldDefn('doublelistfield', ogr.OFTRealList)) + tmpfile = os.path.join(self.basetestpath, "newdoublelistfield.geojson") + ds = ogr.GetDriverByName("GeoJSON").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("strfield", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("intfield", ogr.OFTInteger)) + lyr.CreateField(ogr.FieldDefn("doublelistfield", ogr.OFTRealList)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (1 1)')) - f.SetField('strfield', 'one') - f.SetField('intfield', 1) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (1 1)")) + f.SetField("strfield", "one") + f.SetField("intfield", 1) f.SetFieldDoubleList(2, [1.1, 2.2, 3.3, 4.4]) lyr.CreateFeature(f) @@ -902,21 +1096,21 @@ def testDoubleListField(self): dp = vl.dataProvider() fields = dp.fields() - list_field = fields[fields.lookupField('doublelistfield')] + list_field = fields[fields.lookupField("doublelistfield")] self.assertEqual(list_field.type(), QVariant.List) - self.assertEqual(list_field.typeName(), 'RealList') + self.assertEqual(list_field.typeName(), "RealList") self.assertEqual(list_field.subType(), QVariant.Double) f = next(vl.getFeatures()) - self.assertEqual(f.attributes(), ['one', 1, [1.1, 2.2, 3.3, 4.4]]) + self.assertEqual(f.attributes(), ["one", 1, [1.1, 2.2, 3.3, 4.4]]) # add features f = QgsFeature() - f.setAttributes(['two', 2, [11.1, 12.2, 13.3, 14.4]]) + f.setAttributes(["two", 2, [11.1, 12.2, 13.3, 14.4]]) self.assertTrue(vl.dataProvider().addFeature(f)) - f.setAttributes(['three', 3, NULL]) + f.setAttributes(["three", 3, NULL]) self.assertTrue(vl.dataProvider().addFeature(f)) - f.setAttributes(['four', 4, []]) + f.setAttributes(["four", 4, []]) self.assertTrue(vl.dataProvider().addFeature(f)) vl = None @@ -924,56 +1118,80 @@ def testDoubleListField(self): vl = QgsVectorLayer(tmpfile) self.assertTrue(vl.isValid()) - self.assertEqual([f.attributes() for f in vl.getFeatures()], - [['one', 1, [1.1, 2.2, 3.3, 4.4]], - ['two', 2, [11.1, 12.2, 13.3, 14.4]], - ['three', 3, NULL], - ['four', 4, NULL]]) + self.assertEqual( + [f.attributes() for f in vl.getFeatures()], + [ + ["one", 1, [1.1, 2.2, 3.3, 4.4]], + ["two", 2, [11.1, 12.2, 13.3, 14.4]], + ["three", 3, NULL], + ["four", 4, NULL], + ], + ) # change attribute values f1_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 1][0] f3_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 3][0] - self.assertTrue(vl.dataProvider().changeAttributeValues({f1_id: {2: NULL}, f3_id: {2: [21.1, 22.2, 23.3]}})) + self.assertTrue( + vl.dataProvider().changeAttributeValues( + {f1_id: {2: NULL}, f3_id: {2: [21.1, 22.2, 23.3]}} + ) + ) vl = QgsVectorLayer(tmpfile) self.assertTrue(vl.isValid()) - self.assertEqual([f.attributes() for f in vl.getFeatures()], - [['one', 1, NULL], - ['two', 2, [11.1, 12.2, 13.3, 14.4]], - ['three', 3, [21.1, 22.2, 23.3]], - ['four', 4, NULL]]) + self.assertEqual( + [f.attributes() for f in vl.getFeatures()], + [ + ["one", 1, NULL], + ["two", 2, [11.1, 12.2, 13.3, 14.4]], + ["three", 3, [21.1, 22.2, 23.3]], + ["four", 4, NULL], + ], + ) # add attribute self.assertTrue( - vl.dataProvider().addAttributes([QgsField('new_list', type=QVariant.List, subType=QVariant.Double)])) + vl.dataProvider().addAttributes( + [QgsField("new_list", type=QVariant.List, subType=QVariant.Double)] + ) + ) f1_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 1][0] f3_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 3][0] self.assertTrue( - vl.dataProvider().changeAttributeValues({f1_id: {3: [111.1, 222.2]}, f3_id: {3: [121.1, 122.2, 123.3]}})) + vl.dataProvider().changeAttributeValues( + {f1_id: {3: [111.1, 222.2]}, f3_id: {3: [121.1, 122.2, 123.3]}} + ) + ) vl = QgsVectorLayer(tmpfile) self.assertTrue(vl.isValid()) - self.assertEqual([f.attributes() for f in vl.getFeatures()], - [['one', 1, NULL, [111.1, 222.2]], - ['two', 2, [11.1, 12.2, 13.3, 14.4], NULL], - ['three', 3, [21.1, 22.2, 23.3], [121.1, 122.2, 123.3]], - ['four', 4, NULL, NULL]]) + self.assertEqual( + [f.attributes() for f in vl.getFeatures()], + [ + ["one", 1, NULL, [111.1, 222.2]], + ["two", 2, [11.1, 12.2, 13.3, 14.4], NULL], + ["three", 3, [21.1, 22.2, 23.3], [121.1, 122.2, 123.3]], + ["four", 4, NULL, NULL], + ], + ) def testInteger64ListField(self): - tmpfile = os.path.join(self.basetestpath, 'newlonglonglistfield.geojson') - ds = ogr.GetDriverByName('GeoJSON').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger)) - lyr.CreateField(ogr.FieldDefn('longlonglistfield', ogr.OFTInteger64List)) + tmpfile = os.path.join(self.basetestpath, "newlonglonglistfield.geojson") + ds = ogr.GetDriverByName("GeoJSON").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("strfield", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("intfield", ogr.OFTInteger)) + lyr.CreateField(ogr.FieldDefn("longlonglistfield", ogr.OFTInteger64List)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (1 1)')) - f.SetField('strfield', 'one') - f.SetField('intfield', 1) - f.SetFieldDoubleList(2, [1234567890123, 1234567890124, 1234567890125, 1234567890126]) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (1 1)")) + f.SetField("strfield", "one") + f.SetField("intfield", 1) + f.SetFieldDoubleList( + 2, [1234567890123, 1234567890124, 1234567890125, 1234567890126] + ) lyr.CreateFeature(f) lyr = None @@ -984,21 +1202,26 @@ def testInteger64ListField(self): dp = vl.dataProvider() fields = dp.fields() - list_field = fields[fields.lookupField('longlonglistfield')] + list_field = fields[fields.lookupField("longlonglistfield")] self.assertEqual(list_field.type(), QVariant.List) - self.assertEqual(list_field.typeName(), 'Integer64List') + self.assertEqual(list_field.typeName(), "Integer64List") self.assertEqual(list_field.subType(), QVariant.LongLong) f = next(vl.getFeatures()) - self.assertEqual(f.attributes(), ['one', 1, [1234567890123, 1234567890124, 1234567890125, 1234567890126]]) + self.assertEqual( + f.attributes(), + ["one", 1, [1234567890123, 1234567890124, 1234567890125, 1234567890126]], + ) # add features f = QgsFeature() - f.setAttributes(['two', 2, [2234567890123, 2234567890124, 2234567890125, 2234567890126]]) + f.setAttributes( + ["two", 2, [2234567890123, 2234567890124, 2234567890125, 2234567890126]] + ) self.assertTrue(vl.dataProvider().addFeature(f)) - f.setAttributes(['three', 3, NULL]) + f.setAttributes(["three", 3, NULL]) self.assertTrue(vl.dataProvider().addFeature(f)) - f.setAttributes(['four', 4, []]) + f.setAttributes(["four", 4, []]) self.assertTrue(vl.dataProvider().addFeature(f)) vl = None @@ -1006,54 +1229,108 @@ def testInteger64ListField(self): vl = QgsVectorLayer(tmpfile) self.assertTrue(vl.isValid()) - self.assertEqual([f.attributes() for f in vl.getFeatures()], - [['one', 1, [1234567890123, 1234567890124, 1234567890125, 1234567890126]], - ['two', 2, [2234567890123, 2234567890124, 2234567890125, 2234567890126]], - ['three', 3, NULL], - ['four', 4, NULL]]) + self.assertEqual( + [f.attributes() for f in vl.getFeatures()], + [ + [ + "one", + 1, + [1234567890123, 1234567890124, 1234567890125, 1234567890126], + ], + [ + "two", + 2, + [2234567890123, 2234567890124, 2234567890125, 2234567890126], + ], + ["three", 3, NULL], + ["four", 4, NULL], + ], + ) # change attribute values f1_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 1][0] f3_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 3][0] - self.assertTrue(vl.dataProvider().changeAttributeValues( - {f1_id: {2: NULL}, f3_id: {2: [3234567890123, 3234567890124, 3234567890125, 3234567890126]}})) + self.assertTrue( + vl.dataProvider().changeAttributeValues( + { + f1_id: {2: NULL}, + f3_id: { + 2: [3234567890123, 3234567890124, 3234567890125, 3234567890126] + }, + } + ) + ) vl = QgsVectorLayer(tmpfile) self.assertTrue(vl.isValid()) - self.assertEqual([f.attributes() for f in vl.getFeatures()], - [['one', 1, NULL], - ['two', 2, [2234567890123, 2234567890124, 2234567890125, 2234567890126]], - ['three', 3, [3234567890123, 3234567890124, 3234567890125, 3234567890126]], - ['four', 4, NULL]]) + self.assertEqual( + [f.attributes() for f in vl.getFeatures()], + [ + ["one", 1, NULL], + [ + "two", + 2, + [2234567890123, 2234567890124, 2234567890125, 2234567890126], + ], + [ + "three", + 3, + [3234567890123, 3234567890124, 3234567890125, 3234567890126], + ], + ["four", 4, NULL], + ], + ) # add attribute self.assertTrue( - vl.dataProvider().addAttributes([QgsField('new_list', type=QVariant.List, subType=QVariant.LongLong)])) + vl.dataProvider().addAttributes( + [QgsField("new_list", type=QVariant.List, subType=QVariant.LongLong)] + ) + ) f1_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 1][0] f3_id = [f.id() for f in vl.getFeatures() if f.attributes()[1] == 3][0] - self.assertTrue(vl.dataProvider().changeAttributeValues( - {f1_id: {3: [4234567890123, 4234567890124]}, f3_id: {3: [5234567890123, 5234567890124, 5234567890125]}})) + self.assertTrue( + vl.dataProvider().changeAttributeValues( + { + f1_id: {3: [4234567890123, 4234567890124]}, + f3_id: {3: [5234567890123, 5234567890124, 5234567890125]}, + } + ) + ) vl = QgsVectorLayer(tmpfile) self.assertTrue(vl.isValid()) - self.assertEqual([f.attributes() for f in vl.getFeatures()], - [['one', 1, NULL, [4234567890123, 4234567890124]], - ['two', 2, [2234567890123, 2234567890124, 2234567890125, 2234567890126], NULL], - ['three', 3, [3234567890123, 3234567890124, 3234567890125, 3234567890126], - [5234567890123, 5234567890124, 5234567890125]], - ['four', 4, NULL, NULL]]) + self.assertEqual( + [f.attributes() for f in vl.getFeatures()], + [ + ["one", 1, NULL, [4234567890123, 4234567890124]], + [ + "two", + 2, + [2234567890123, 2234567890124, 2234567890125, 2234567890126], + NULL, + ], + [ + "three", + 3, + [3234567890123, 3234567890124, 3234567890125, 3234567890126], + [5234567890123, 5234567890124, 5234567890125], + ], + ["four", 4, NULL, NULL], + ], + ) def testBlobCreation(self): """ Test creating binary blob field in existing table """ - tmpfile = os.path.join(self.basetestpath, 'newbinaryfield.sqlite') - ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid']) - lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger)) + tmpfile = os.path.join(self.basetestpath, "newbinaryfield.sqlite") + ds = ogr.GetDriverByName("SQLite").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint, options=["FID=fid"]) + lyr.CreateField(ogr.FieldDefn("strfield", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("intfield", ogr.OFTInteger)) f = None ds = None @@ -1062,53 +1339,59 @@ def testBlobCreation(self): dp = vl.dataProvider() f = QgsFeature(dp.fields()) - f.setAttributes([1, 'str', 100]) + f.setAttributes([1, "str", 100]) self.assertTrue(dp.addFeature(f)) # add binary field - self.assertTrue(dp.addAttributes([QgsField('binfield', QVariant.ByteArray)])) + self.assertTrue(dp.addAttributes([QgsField("binfield", QVariant.ByteArray)])) fields = dp.fields() - bin1_field = fields[fields.lookupField('binfield')] + bin1_field = fields[fields.lookupField("binfield")] self.assertEqual(bin1_field.type(), QVariant.ByteArray) - self.assertEqual(bin1_field.typeName(), 'Binary') + self.assertEqual(bin1_field.typeName(), "Binary") f = QgsFeature(fields) - bin_1 = b'xxx' + bin_1 = b"xxx" bin_val1 = QByteArray(bin_1) - f.setAttributes([2, 'str2', 200, bin_val1]) + f.setAttributes([2, "str2", 200, bin_val1]) self.assertTrue(dp.addFeature(f)) f2 = [f for f in dp.getFeatures()][1] - self.assertEqual(f2.attributes(), [2, 'str2', 200, QByteArray(bin_1)]) + self.assertEqual(f2.attributes(), [2, "str2", 200, QByteArray(bin_1)]) def testBoolFieldEvaluation(self): - datasource = os.path.join(unitTestDataPath(), 'bool_geojson.json') - vl = QgsVectorLayer(datasource, 'test', 'ogr') + datasource = os.path.join(unitTestDataPath(), "bool_geojson.json") + vl = QgsVectorLayer(datasource, "test", "ogr") self.assertTrue(vl.isValid()) - self.assertEqual(vl.fields().at(0).name(), 'bool') + self.assertEqual(vl.fields().at(0).name(), "bool") self.assertEqual(vl.fields().at(0).type(), QVariant.Bool) self.assertEqual([f[0] for f in vl.getFeatures()], [True, False, NULL]) def testReloadDataAndFeatureCount(self): - filename = '/vsimem/test.json' - gdal.FileFromMemBuffer(filename, """{ + filename = "/vsimem/test.json" + gdal.FileFromMemBuffer( + filename, + """{ "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": null, "geometry": { "type": "Point", "coordinates": [2, 49] } }, { "type": "Feature", "properties": null, "geometry": { "type": "Point", "coordinates": [3, 50] } } ] -}""") - vl = QgsVectorLayer(filename, 'test', 'ogr') +}""", + ) + vl = QgsVectorLayer(filename, "test", "ogr") self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 2) - gdal.FileFromMemBuffer(filename, """{ + gdal.FileFromMemBuffer( + filename, + """{ "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": null, "geometry": { "type": "Point", "coordinates": [2, 49] } } ] -}""") +}""", + ) vl.reload() self.assertEqual(vl.featureCount(), 1) gdal.Unlink(filename) @@ -1143,7 +1426,11 @@ def testSpatialiteDefaultValues(self): cur.execute("COMMIT") con.close() - vl = QgsVectorLayer(dbname + '|layername=test_table_default_values', 'test_table_default_values', 'ogr') + vl = QgsVectorLayer( + dbname + "|layername=test_table_default_values", + "test_table_default_values", + "ogr", + ) self.assertTrue(vl.isValid()) # Save it for the test @@ -1155,12 +1442,12 @@ def testSpatialiteDefaultValues(self): self.assertIsNone(dp.defaultValue(1)) # FIXME: This fails because there is no backend-side evaluation in this provider # self.assertTrue(dp.defaultValue(2).startswith(now.strftime('%Y-%m-%d'))) - self.assertTrue(dp.defaultValue(3).startswith(now.strftime('%Y-%m-%d'))) + self.assertTrue(dp.defaultValue(3).startswith(now.strftime("%Y-%m-%d"))) self.assertEqual(dp.defaultValue(4), 123) - self.assertEqual(dp.defaultValue(5), 'My default') + self.assertEqual(dp.defaultValue(5), "My default") - self.assertEqual(dp.defaultValueClause(0), 'Autogenerate') - self.assertEqual(dp.defaultValueClause(1), '') + self.assertEqual(dp.defaultValueClause(0), "Autogenerate") + self.assertEqual(dp.defaultValueClause(1), "") self.assertEqual(dp.defaultValueClause(2), "datetime('now','localtime')") self.assertEqual(dp.defaultValueClause(3), "CURRENT_TIMESTAMP") # FIXME: ogr provider simply returns values when asked for clauses @@ -1171,153 +1458,264 @@ def testSpatialiteDefaultValues(self): for idx in range(vl.fields().count()): default = vl.dataProvider().defaultValue(idx) if not default: - feature.setAttribute(idx, 'A comment') + feature.setAttribute(idx, "A comment") else: feature.setAttribute(idx, default) self.assertTrue(vl.dataProvider().addFeature(feature)) - del (vl) + del vl # Verify - vl2 = QgsVectorLayer(dbname + '|layername=test_table_default_values', 'test_table_default_values', 'ogr') + vl2 = QgsVectorLayer( + dbname + "|layername=test_table_default_values", + "test_table_default_values", + "ogr", + ) self.assertTrue(vl2.isValid()) feature = next(vl2.getFeatures()) - self.assertEqual(feature.attribute(1), 'A comment') - self.assertTrue(feature.attribute(2).startswith(now.strftime('%Y-%m-%d'))) - self.assertTrue(feature.attribute(3).startswith(now.strftime('%Y-%m-%d'))) + self.assertEqual(feature.attribute(1), "A comment") + self.assertTrue(feature.attribute(2).startswith(now.strftime("%Y-%m-%d"))) + self.assertTrue(feature.attribute(3).startswith(now.strftime("%Y-%m-%d"))) self.assertEqual(feature.attribute(4), 123) - self.assertEqual(feature.attribute(5), 'My default') + self.assertEqual(feature.attribute(5), "My default") - def testMixOfFilterExpressionAndSubsetStringWhenFilterExpressionCompilationFails(self): - datasource = os.path.join(unitTestDataPath(), 'filter_test.shp') - vl = QgsVectorLayer(datasource, 'test', 'ogr') + def testMixOfFilterExpressionAndSubsetStringWhenFilterExpressionCompilationFails( + self, + ): + datasource = os.path.join(unitTestDataPath(), "filter_test.shp") + vl = QgsVectorLayer(datasource, "test", "ogr") self.assertTrue(vl.isValid()) - self.assertCountEqual([f.attributes() for f in vl.getFeatures()], [['circle', '1'], - ['circle', '2'], - ['rectangle', '1'], - ['rectangle', '2']]) + self.assertCountEqual( + [f.attributes() for f in vl.getFeatures()], + [["circle", "1"], ["circle", "2"], ["rectangle", "1"], ["rectangle", "2"]], + ) # note - request uses wrong type for match (string vs int). This is OK for QGIS expressions, # but will be rejected after we try to compile the expression for OGR to use. request = QgsFeatureRequest().setFilterExpression('"color" = 1') - self.assertCountEqual([f.attributes() for f in vl.getFeatures(request)], [['circle', '1'], - ['rectangle', '1']]) + self.assertCountEqual( + [f.attributes() for f in vl.getFeatures(request)], + [["circle", "1"], ["rectangle", "1"]], + ) request = QgsFeatureRequest().setFilterExpression('"color" = 1') - self.assertCountEqual([f.attributes() for f in vl.getFeatures(request)], [['circle', '1'], - ['rectangle', '1']]) + self.assertCountEqual( + [f.attributes() for f in vl.getFeatures(request)], + [["circle", "1"], ["rectangle", "1"]], + ) vl.setSubsetString("\"shape\" = 'rectangle'") - self.assertCountEqual([f.attributes() for f in vl.getFeatures()], [['rectangle', '1'], - ['rectangle', '2']]) + self.assertCountEqual( + [f.attributes() for f in vl.getFeatures()], + [["rectangle", "1"], ["rectangle", "2"]], + ) - self.assertCountEqual([f.attributes() for f in vl.getFeatures(request)], [['rectangle', '1']]) + self.assertCountEqual( + [f.attributes() for f in vl.getFeatures(request)], [["rectangle", "1"]] + ) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 2, 0), "GDAL 3.2 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 2, 0), + "GDAL 3.2 required", + ) def testFieldAliases(self): """ Test that field aliases are taken from OGR where available (requires GDAL 3.2 or later) """ - datasource = os.path.join(unitTestDataPath(), 'field_alias.gdb') - vl = QgsVectorLayer(datasource, 'test', 'ogr') + datasource = os.path.join(unitTestDataPath(), "field_alias.gdb") + vl = QgsVectorLayer(datasource, "test", "ogr") self.assertTrue(vl.isValid()) fields = vl.fields() # proprietary FileGDB driver doesn't have the raster column - if 'raster' not in {f.name() for f in fields}: - expected_fieldnames = ['OBJECTID', 'text', 'short_int', 'long_int', 'float', 'double', 'date', 'blob', - 'guid', 'SHAPE_Length', 'SHAPE_Area'] - expected_alias = ['', 'My Text Field', 'My Short Int Field', 'My Long Int Field', 'My Float Field', - 'My Double Field', 'My Date Field', 'My Blob Field', 'My GUID field', '', ''] - expected_alias_map = {'OBJECTID': '', 'SHAPE_Area': '', 'SHAPE_Length': '', 'blob': 'My Blob Field', - 'date': 'My Date Field', 'double': 'My Double Field', 'float': 'My Float Field', - 'guid': 'My GUID field', 'long_int': 'My Long Int Field', - 'short_int': 'My Short Int Field', 'text': 'My Text Field'} + if "raster" not in {f.name() for f in fields}: + expected_fieldnames = [ + "OBJECTID", + "text", + "short_int", + "long_int", + "float", + "double", + "date", + "blob", + "guid", + "SHAPE_Length", + "SHAPE_Area", + ] + expected_alias = [ + "", + "My Text Field", + "My Short Int Field", + "My Long Int Field", + "My Float Field", + "My Double Field", + "My Date Field", + "My Blob Field", + "My GUID field", + "", + "", + ] + expected_alias_map = { + "OBJECTID": "", + "SHAPE_Area": "", + "SHAPE_Length": "", + "blob": "My Blob Field", + "date": "My Date Field", + "double": "My Double Field", + "float": "My Float Field", + "guid": "My GUID field", + "long_int": "My Long Int Field", + "short_int": "My Short Int Field", + "text": "My Text Field", + } else: - expected_fieldnames = ['OBJECTID', 'text', 'short_int', 'long_int', 'float', 'double', 'date', 'blob', - 'guid', 'raster', 'SHAPE_Length', 'SHAPE_Area'] - expected_alias = ['', 'My Text Field', 'My Short Int Field', 'My Long Int Field', 'My Float Field', - 'My Double Field', 'My Date Field', 'My Blob Field', 'My GUID field', 'My Raster Field', - '', ''] - expected_alias_map = {'OBJECTID': '', 'SHAPE_Area': '', 'SHAPE_Length': '', 'blob': 'My Blob Field', - 'date': 'My Date Field', 'double': 'My Double Field', 'float': 'My Float Field', - 'guid': 'My GUID field', 'long_int': 'My Long Int Field', 'raster': 'My Raster Field', - 'short_int': 'My Short Int Field', 'text': 'My Text Field'} + expected_fieldnames = [ + "OBJECTID", + "text", + "short_int", + "long_int", + "float", + "double", + "date", + "blob", + "guid", + "raster", + "SHAPE_Length", + "SHAPE_Area", + ] + expected_alias = [ + "", + "My Text Field", + "My Short Int Field", + "My Long Int Field", + "My Float Field", + "My Double Field", + "My Date Field", + "My Blob Field", + "My GUID field", + "My Raster Field", + "", + "", + ] + expected_alias_map = { + "OBJECTID": "", + "SHAPE_Area": "", + "SHAPE_Length": "", + "blob": "My Blob Field", + "date": "My Date Field", + "double": "My Double Field", + "float": "My Float Field", + "guid": "My GUID field", + "long_int": "My Long Int Field", + "raster": "My Raster Field", + "short_int": "My Short Int Field", + "text": "My Text Field", + } self.assertEqual([f.name() for f in fields], expected_fieldnames) self.assertEqual([f.alias() for f in fields], expected_alias) self.assertEqual(vl.attributeAliases(), expected_alias_map) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 3, 0), "GDAL 3.3 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 3, 0), + "GDAL 3.3 required", + ) def testFieldDomainNames(self): """ Test that field domain names are taken from OGR where available (requires GDAL 3.3 or later) """ - datasource = os.path.join(self.temp_dir_path, 'domains.gpkg') - vl = QgsVectorLayer(datasource, 'test', 'ogr') + datasource = os.path.join(self.temp_dir_path, "domains.gpkg") + vl = QgsVectorLayer(datasource, "test", "ogr") self.assertTrue(vl.isValid()) fields = vl.fields() - self.assertEqual(fields.field('with_range_domain_int').constraints().domainName(), 'range_domain_int') - self.assertEqual(fields.field('with_glob_domain').constraints().domainName(), 'glob_domain') + self.assertEqual( + fields.field("with_range_domain_int").constraints().domainName(), + "range_domain_int", + ) + self.assertEqual( + fields.field("with_glob_domain").constraints().domainName(), "glob_domain" + ) - self.assertEqual(fields.field('with_range_domain_int').splitPolicy(), Qgis.FieldDomainSplitPolicy.DefaultValue) - self.assertEqual(fields.field('with_glob_domain').splitPolicy(), Qgis.FieldDomainSplitPolicy.DefaultValue) + self.assertEqual( + fields.field("with_range_domain_int").splitPolicy(), + Qgis.FieldDomainSplitPolicy.DefaultValue, + ) + self.assertEqual( + fields.field("with_glob_domain").splitPolicy(), + Qgis.FieldDomainSplitPolicy.DefaultValue, + ) - datasource = os.path.join(self.temp_dir_path, 'gps_timestamp.gpkg') - vl = QgsVectorLayer(datasource, 'test', 'ogr') + datasource = os.path.join(self.temp_dir_path, "gps_timestamp.gpkg") + vl = QgsVectorLayer(datasource, "test", "ogr") self.assertTrue(vl.isValid()) fields = vl.fields() - self.assertFalse(fields.field('stringf').constraints().domainName()) + self.assertFalse(fields.field("stringf").constraints().domainName()) with tempfile.TemporaryDirectory() as temp_dir: - src_file_name = os.path.join(unitTestDataPath(), 'domains.gdb') - dest_file_name = os.path.join(temp_dir, 'domains.gdb') + src_file_name = os.path.join(unitTestDataPath(), "domains.gdb") + dest_file_name = os.path.join(temp_dir, "domains.gdb") shutil.copytree(src_file_name, dest_file_name) - vl = QgsVectorLayer(dest_file_name + '|layername=test', 'test', 'ogr') + vl = QgsVectorLayer(dest_file_name + "|layername=test", "test", "ogr") self.assertTrue(vl.isValid()) fields = vl.fields() - self.assertEqual(fields.field('default_value').splitPolicy(), - Qgis.FieldDomainSplitPolicy.DefaultValue) - self.assertEqual(fields.field('duplicate').splitPolicy(), - Qgis.FieldDomainSplitPolicy.Duplicate) - self.assertEqual(fields.field('ratio').splitPolicy(), - Qgis.FieldDomainSplitPolicy.GeometryRatio) + self.assertEqual( + fields.field("default_value").splitPolicy(), + Qgis.FieldDomainSplitPolicy.DefaultValue, + ) + self.assertEqual( + fields.field("duplicate").splitPolicy(), + Qgis.FieldDomainSplitPolicy.Duplicate, + ) + self.assertEqual( + fields.field("ratio").splitPolicy(), + Qgis.FieldDomainSplitPolicy.GeometryRatio, + ) def testGdbLayerMetadata(self): """ Test that we translate GDB metadata to QGIS layer metadata on loading a GDB source """ - datasource = os.path.join(unitTestDataPath(), 'gdb_metadata.gdb') - vl = QgsVectorLayer(datasource, 'test', 'ogr') - self.assertTrue(vl.isValid()) - self.assertEqual(vl.metadata().identifier(), 'Test') - self.assertEqual(vl.metadata().title(), 'Title') - self.assertEqual(vl.metadata().type(), 'dataset') - self.assertEqual(vl.metadata().language(), 'ENG') - self.assertIn('This is the abstract', vl.metadata().abstract()) - self.assertEqual(vl.metadata().keywords(), {'Search keys': ['Tags']}) - self.assertEqual(vl.metadata().rights(), ['This is the credits']) - self.assertEqual(vl.metadata().constraints()[0].type, 'Limitations of use') - self.assertEqual(vl.metadata().constraints()[0].constraint, 'This is the use limitation') - self.assertEqual(vl.metadata().extent().spatialExtents()[0].bounds.xMinimum(), 1) - self.assertEqual(vl.metadata().extent().spatialExtents()[0].bounds.xMaximum(), 2) - self.assertEqual(vl.metadata().extent().spatialExtents()[0].bounds.yMinimum(), 3) - self.assertEqual(vl.metadata().extent().spatialExtents()[0].bounds.yMaximum(), 4) + datasource = os.path.join(unitTestDataPath(), "gdb_metadata.gdb") + vl = QgsVectorLayer(datasource, "test", "ogr") + self.assertTrue(vl.isValid()) + self.assertEqual(vl.metadata().identifier(), "Test") + self.assertEqual(vl.metadata().title(), "Title") + self.assertEqual(vl.metadata().type(), "dataset") + self.assertEqual(vl.metadata().language(), "ENG") + self.assertIn("This is the abstract", vl.metadata().abstract()) + self.assertEqual(vl.metadata().keywords(), {"Search keys": ["Tags"]}) + self.assertEqual(vl.metadata().rights(), ["This is the credits"]) + self.assertEqual(vl.metadata().constraints()[0].type, "Limitations of use") + self.assertEqual( + vl.metadata().constraints()[0].constraint, "This is the use limitation" + ) + self.assertEqual( + vl.metadata().extent().spatialExtents()[0].bounds.xMinimum(), 1 + ) + self.assertEqual( + vl.metadata().extent().spatialExtents()[0].bounds.xMaximum(), 2 + ) + self.assertEqual( + vl.metadata().extent().spatialExtents()[0].bounds.yMinimum(), 3 + ) + self.assertEqual( + vl.metadata().extent().spatialExtents()[0].bounds.yMaximum(), 4 + ) def testShpLayerMetadata(self): """ Test that we translate .shp.xml metadata to QGIS layer metadata on loading a shp file (if present) """ - datasource = os.path.join(unitTestDataPath(), 'france_parts.shp') - vl = QgsVectorLayer(datasource, 'test', 'ogr') + datasource = os.path.join(unitTestDataPath(), "france_parts.shp") + vl = QgsVectorLayer(datasource, "test", "ogr") self.assertTrue(vl.isValid()) - self.assertEqual(vl.metadata().identifier(), 'QLD_STRUCTURAL_FRAMEWORK_OUTLINE') - self.assertEqual(vl.metadata().title(), 'QLD_STRUCTURAL_FRAMEWORK_OUTLINE') - self.assertEqual(vl.metadata().type(), 'dataset') - self.assertEqual(vl.metadata().language(), 'EN') + self.assertEqual(vl.metadata().identifier(), "QLD_STRUCTURAL_FRAMEWORK_OUTLINE") + self.assertEqual(vl.metadata().title(), "QLD_STRUCTURAL_FRAMEWORK_OUTLINE") + self.assertEqual(vl.metadata().type(), "dataset") + self.assertEqual(vl.metadata().language(), "EN") def testOpenOptions(self): @@ -1330,17 +1728,19 @@ def testOpenOptions(self): ds.ExecuteSQL("INSERT INTO foo VALUES(1, 'bar');") ds = None - vl = QgsVectorLayer(filename + "|option:LIST_ALL_TABLES=NO", 'test', 'ogr') + vl = QgsVectorLayer(filename + "|option:LIST_ALL_TABLES=NO", "test", "ogr") self.assertTrue(vl.isValid()) self.assertEqual(len(vl.dataProvider().subLayers()), 1) del vl - vl = QgsVectorLayer(filename + "|option:LIST_ALL_TABLES=YES", 'test', 'ogr') + vl = QgsVectorLayer(filename + "|option:LIST_ALL_TABLES=YES", "test", "ogr") self.assertTrue(vl.isValid()) self.assertEqual(len(vl.dataProvider().subLayers()), 2) del vl - vl = QgsVectorLayer(filename + "|layername=foo|option:LIST_ALL_TABLES=YES", 'test', 'ogr') + vl = QgsVectorLayer( + filename + "|layername=foo|option:LIST_ALL_TABLES=YES", "test", "ogr" + ) self.assertTrue(vl.isValid()) self.assertEqual(len([f for f in vl.getFeatures()]), 1) del vl @@ -1353,35 +1753,41 @@ def testTransactionGroupExpressionFields(self): project = QgsProject() project.setTransactionMode(Qgis.TransactionMode.AutomaticGroups) tmpfile = os.path.join( - self.basetestpath, 'tempGeoPackageTransactionExpressionFields.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) + self.basetestpath, "tempGeoPackageTransactionExpressionFields.gpkg" + ) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (1 1)')) - f.SetField('str_field', 'one') + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (1 1)")) + f.SetField("str_field", "one") lyr.CreateFeature(f) del lyr del ds - vl = QgsVectorLayer(tmpfile + '|layername=test', 'test', 'ogr') - f = QgsField('expression_field', QVariant.Int) - idx = vl.addExpressionField('123', f) - self.assertEqual(vl.fields().fieldOrigin(idx), QgsFields.FieldOrigin.OriginExpression) + vl = QgsVectorLayer(tmpfile + "|layername=test", "test", "ogr") + f = QgsField("expression_field", QVariant.Int) + idx = vl.addExpressionField("123", f) + self.assertEqual( + vl.fields().fieldOrigin(idx), QgsFields.FieldOrigin.OriginExpression + ) project.addMapLayers([vl]) feature = next(vl.getFeatures()) - feature.setAttributes([None, 'two', 123]) + feature.setAttributes([None, "two", 123]) self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeature(feature)) self.assertFalse(vl.dataProvider().hasErrors()) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 2, 0), "GDAL 3.2 required") - @unittest.skipIf(ogr.GetDriverByName('OAPIF') is None, "OAPIF driver not available") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 2, 0), + "GDAL 3.2 required", + ) + @unittest.skipIf(ogr.GetDriverByName("OAPIF") is None, "OAPIF driver not available") def testHTTPRequestsOverrider(self): """ Test that GDAL curl network requests are redirected through QGIS networking @@ -1391,108 +1797,183 @@ def testHTTPRequestsOverrider(self): # Check failed network requests # Check that the driver requested Accept header is well propagated - handler.add('GET', '/collections/foo', 404, expected_headers={'Accept': 'application/json'}) + handler.add( + "GET", + "/collections/foo", + 404, + expected_headers={"Accept": "application/json"}, + ) with mockedwebserver.install_http_handler(handler): - QgsVectorLayer("OAPIF:http://127.0.0.1:%d/collections/foo" % port, 'test', 'ogr') + QgsVectorLayer( + "OAPIF:http://127.0.0.1:%d/collections/foo" % port, "test", "ogr" + ) # Error coming from Qt network stack, not GDAL/CURL one - self.assertIn('server replied: Not Found', gdal.GetLastErrorMsg()) + self.assertIn("server replied: Not Found", gdal.GetLastErrorMsg()) # Test a nominal case handler = mockedwebserver.SequentialHandler() # Asked when ogr provider try to open. See QgsOgrProvider::QgsOgrProvider#453 open( OpenModeForceReadOnly ); - handler.add('GET', '/collections/foo', 200, {'Content-Type': 'application/json'}, '{ "id": "foo" }') + handler.add( + "GET", + "/collections/foo", + 200, + {"Content-Type": "application/json"}, + '{ "id": "foo" }', + ) # 3.8.3 not necessarily the minimum version - if int(gdal.VersionInfo('VERSION_NUM')) >= GDAL_COMPUTE_VERSION(3, 8, 3): - handler.add('GET', '/', 200, {'Content-Type': 'application/json'}, '{ "id": "foo" }') - handler.add('GET', '/api', 200, {'Content-Type': 'application/json'}, '{ "id": "foo" }') - - handler.add('GET', '/collections/foo/items?limit=20', 200, {'Content-Type': 'application/geo+json'}, - '{ "type": "FeatureCollection", "features": [] }') - handler.add('GET', '/collections/foo/items?limit=1000', 200, {'Content-Type': 'application/geo+json'}, - '{ "type": "FeatureCollection", "features": [] }') + if int(gdal.VersionInfo("VERSION_NUM")) >= GDAL_COMPUTE_VERSION(3, 8, 3): + handler.add( + "GET", + "/", + 200, + {"Content-Type": "application/json"}, + '{ "id": "foo" }', + ) + handler.add( + "GET", + "/api", + 200, + {"Content-Type": "application/json"}, + '{ "id": "foo" }', + ) + + handler.add( + "GET", + "/collections/foo/items?limit=20", + 200, + {"Content-Type": "application/geo+json"}, + '{ "type": "FeatureCollection", "features": [] }', + ) + handler.add( + "GET", + "/collections/foo/items?limit=1000", + 200, + {"Content-Type": "application/geo+json"}, + '{ "type": "FeatureCollection", "features": [] }', + ) else: # See QgsOgrProvider::open#4012 mOgrOrigLayer = QgsOgrProviderUtils::getLayer( mFilePath, false, options, mLayerName, errCause, true ); - handler.add('GET', '/collections/foo/items?limit=10', 200, {'Content-Type': 'application/geo+json'}, - '{ "type": "FeatureCollection", "features": [] }') + handler.add( + "GET", + "/collections/foo/items?limit=10", + 200, + {"Content-Type": "application/geo+json"}, + '{ "type": "FeatureCollection", "features": [] }', + ) # See QgsOgrProvider::open#4066 computeCapabilities(); - handler.add('GET', '/collections/foo/items?limit=10', 200, {'Content-Type': 'application/geo+json'}, - '{ "type": "FeatureCollection", "features": [] }') - - if int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 3, 0): - handler.add('GET', '/collections/foo/items?limit=10', 200, {'Content-Type': 'application/geo+json'}, - '{ "type": "FeatureCollection", "features": [] }') + handler.add( + "GET", + "/collections/foo/items?limit=10", + 200, + {"Content-Type": "application/geo+json"}, + '{ "type": "FeatureCollection", "features": [] }', + ) + + if int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 3, 0): + handler.add( + "GET", + "/collections/foo/items?limit=10", + 200, + {"Content-Type": "application/geo+json"}, + '{ "type": "FeatureCollection", "features": [] }', + ) with mockedwebserver.install_http_handler(handler): - vl = QgsVectorLayer("OAPIF:http://127.0.0.1:%d/collections/foo" % port, 'test', 'ogr') + vl = QgsVectorLayer( + "OAPIF:http://127.0.0.1:%d/collections/foo" % port, "test", "ogr" + ) self.assertTrue(vl.isValid()) # More complicated test using an anthentication configuration authm = QgsApplication.authManager() - self.assertTrue(authm.setMasterPassword('masterpassword', True)) + self.assertTrue(authm.setMasterPassword("masterpassword", True)) config = QgsAuthMethodConfig() - config.setName('Basic') - config.setMethod('Basic') - config.setConfig('username', 'username') - config.setConfig('password', 'password') + config.setName("Basic") + config.setMethod("Basic") + config.setConfig("username", "username") + config.setConfig("password", "password") self.assertTrue(authm.storeAuthenticationConfig(config, True)) handler = mockedwebserver.SequentialHandler() # Check that the authcfg gets expanded during the network request ! - handler.add('GET', '/collections/foo', 404, expected_headers={ - 'Authorization': 'Basic dXNlcm5hbWU6cGFzc3dvcmQ='}) + handler.add( + "GET", + "/collections/foo", + 404, + expected_headers={"Authorization": "Basic dXNlcm5hbWU6cGFzc3dvcmQ="}, + ) with mockedwebserver.install_http_handler(handler): - QgsVectorLayer("OAPIF:http://127.0.0.1:%d/collections/foo authcfg='%s'" % (port, config.id()), 'test', - 'ogr') + QgsVectorLayer( + "OAPIF:http://127.0.0.1:%d/collections/foo authcfg='%s'" + % (port, config.id()), + "test", + "ogr", + ) def testShapefilesWithNoAttributes(self): """Test issue GH #38834""" - ml = QgsVectorLayer('Point?crs=epsg:4326', 'test', 'memory') + ml = QgsVectorLayer("Point?crs=epsg:4326", "test", "memory") self.assertTrue(ml.isValid()) d = QTemporaryDir() options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'ESRI Shapefile' - options.layerName = 'writetest' - err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(ml, os.path.join(d.path(), 'writetest.shp'), - QgsCoordinateTransformContext(), options) + options.driverName = "ESRI Shapefile" + options.layerName = "writetest" + err, _ = QgsVectorFileWriter.writeAsVectorFormatV2( + ml, + os.path.join(d.path(), "writetest.shp"), + QgsCoordinateTransformContext(), + options, + ) self.assertEqual(err, QgsVectorFileWriter.WriterError.NoError) - self.assertTrue(os.path.isfile(os.path.join(d.path(), 'writetest.shp'))) + self.assertTrue(os.path.isfile(os.path.join(d.path(), "writetest.shp"))) - vl = QgsVectorLayer(os.path.join(d.path(), 'writetest.shp')) - self.assertTrue(bool(vl.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures)) + vl = QgsVectorLayer(os.path.join(d.path(), "writetest.shp")) + self.assertTrue( + bool( + vl.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.AddFeatures + ) + ) # Let's try if we can really add features feature = QgsFeature(vl.fields()) - geom = QgsGeometry.fromWkt('POINT(9 45)') + geom = QgsGeometry.fromWkt("POINT(9 45)") feature.setGeometry(geom) self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([feature])) self.assertTrue(vl.commitChanges()) - del (vl) + del vl - vl = QgsVectorLayer(os.path.join(d.path(), 'writetest.shp')) + vl = QgsVectorLayer(os.path.join(d.path(), "writetest.shp")) self.assertEqual(vl.featureCount(), 1) def testFidDoubleSaveAsGeopackage(self): """Test issue GH #25795""" - ml = QgsVectorLayer('Point?crs=epsg:4326&field=fid:double(20,0)', 'test', 'memory') + ml = QgsVectorLayer( + "Point?crs=epsg:4326&field=fid:double(20,0)", "test", "memory" + ) self.assertTrue(ml.isValid()) self.assertEqual(ml.fields()[0].type(), QVariant.Double) d = QTemporaryDir() options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'GPKG' - options.layerName = 'fid_double_test' - err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(ml, os.path.join(d.path(), 'fid_double_test.gpkg'), - QgsCoordinateTransformContext(), options) + options.driverName = "GPKG" + options.layerName = "fid_double_test" + err, _ = QgsVectorFileWriter.writeAsVectorFormatV2( + ml, + os.path.join(d.path(), "fid_double_test.gpkg"), + QgsCoordinateTransformContext(), + options, + ) self.assertEqual(err, QgsVectorFileWriter.WriterError.NoError) - self.assertTrue(os.path.isfile(os.path.join(d.path(), 'fid_double_test.gpkg'))) + self.assertTrue(os.path.isfile(os.path.join(d.path(), "fid_double_test.gpkg"))) - vl = QgsVectorLayer(os.path.join(d.path(), 'fid_double_test.gpkg')) + vl = QgsVectorLayer(os.path.join(d.path(), "fid_double_test.gpkg")) self.assertEqual(vl.fields()[0].type(), QVariant.LongLong) def testNonGeopackageSaveMetadata(self): @@ -1500,58 +1981,66 @@ def testNonGeopackageSaveMetadata(self): Save layer metadata for a file-based format which doesn't have native metadata support. In this case we should resort to a sidecar file instead. """ - ml = QgsVectorLayer('Point?crs=epsg:4326&field=pk:integer&field=cnt:int8', 'test', 'memory') + ml = QgsVectorLayer( + "Point?crs=epsg:4326&field=pk:integer&field=cnt:int8", "test", "memory" + ) self.assertTrue(ml.isValid()) d = QTemporaryDir() options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'ESRI Shapefile' - options.layerName = 'metadatatest' - err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(ml, os.path.join(d.path(), 'metadatatest.shp'), - QgsCoordinateTransformContext(), options) + options.driverName = "ESRI Shapefile" + options.layerName = "metadatatest" + err, _ = QgsVectorFileWriter.writeAsVectorFormatV2( + ml, + os.path.join(d.path(), "metadatatest.shp"), + QgsCoordinateTransformContext(), + options, + ) self.assertEqual(err, QgsVectorFileWriter.WriterError.NoError) - self.assertTrue(os.path.isfile(os.path.join(d.path(), 'metadatatest.shp'))) + self.assertTrue(os.path.isfile(os.path.join(d.path(), "metadatatest.shp"))) - uri = d.path() + '/metadatatest.shp' + uri = d.path() + "/metadatatest.shp" # now save some metadata metadata = QgsLayerMetadata() - metadata.setAbstract('my abstract') - metadata.setIdentifier('my identifier') - metadata.setLicenses(['l1', 'l2']) - ok, err = QgsProviderRegistry.instance().saveLayerMetadata('ogr', uri, metadata) + metadata.setAbstract("my abstract") + metadata.setIdentifier("my identifier") + metadata.setLicenses(["l1", "l2"]) + ok, err = QgsProviderRegistry.instance().saveLayerMetadata("ogr", uri, metadata) self.assertTrue(ok) - self.assertTrue(os.path.exists(os.path.join(d.path(), 'metadatatest.qmd'))) - with open(os.path.join(d.path(), 'metadatatest.qmd')) as f: - metadata_xml = ''.join(f.readlines()) + self.assertTrue(os.path.exists(os.path.join(d.path(), "metadatatest.qmd"))) + with open(os.path.join(d.path(), "metadatatest.qmd")) as f: + metadata_xml = "".join(f.readlines()) metadata2 = QgsLayerMetadata() doc = QDomDocument() doc.setContent(metadata_xml) self.assertTrue(metadata2.readMetadataXml(doc.documentElement())) - self.assertEqual(metadata2.abstract(), 'my abstract') - self.assertEqual(metadata2.identifier(), 'my identifier') - self.assertEqual(metadata2.licenses(), ['l1', 'l2']) + self.assertEqual(metadata2.abstract(), "my abstract") + self.assertEqual(metadata2.identifier(), "my identifier") + self.assertEqual(metadata2.licenses(), ["l1", "l2"]) # try updating existing metadata -- file should be overwritten - metadata2.setAbstract('my abstract 2') - metadata2.setIdentifier('my identifier 2') - metadata2.setHistory(['h1', 'h2']) - ok, err = QgsProviderRegistry.instance().saveLayerMetadata('ogr', uri, metadata2) + metadata2.setAbstract("my abstract 2") + metadata2.setIdentifier("my identifier 2") + metadata2.setHistory(["h1", "h2"]) + ok, err = QgsProviderRegistry.instance().saveLayerMetadata( + "ogr", uri, metadata2 + ) self.assertTrue(ok) - with open(os.path.join(d.path(), 'metadatatest.qmd')) as f: - metadata_xml = ''.join(f.readlines()) + with open(os.path.join(d.path(), "metadatatest.qmd")) as f: + metadata_xml = "".join(f.readlines()) metadata3 = QgsLayerMetadata() doc = QDomDocument() doc.setContent(metadata_xml) self.assertTrue(metadata3.readMetadataXml(doc.documentElement())) - self.assertEqual(metadata3.abstract(), 'my abstract 2') - self.assertEqual(metadata3.identifier(), 'my identifier 2') - self.assertEqual(metadata3.licenses(), ['l1', 'l2']) - self.assertEqual(metadata3.history(), ['h1', 'h2']) + self.assertEqual(metadata3.abstract(), "my abstract 2") + self.assertEqual(metadata3.identifier(), "my identifier 2") + self.assertEqual(metadata3.licenses(), ["l1", "l2"]) + self.assertEqual(metadata3.history(), ["h1", "h2"]) def testSaveMetadataUnsupported(self): """ @@ -1560,70 +2049,110 @@ def testSaveMetadataUnsupported(self): metadata = QgsLayerMetadata() # this should raise a QgsNotSupportedException, as we don't support writing metadata to a WFS uri with self.assertRaises(QgsNotSupportedException): - QgsProviderRegistry.instance().saveLayerMetadata('ogr', 'WFS:http://www2.dmsolutions.ca/cgi-bin/mswfs_gmap', metadata) + QgsProviderRegistry.instance().saveLayerMetadata( + "ogr", "WFS:http://www2.dmsolutions.ca/cgi-bin/mswfs_gmap", metadata + ) def testSaveDefaultMetadataUnsupported(self): """ Test saving default metadata to an unsupported layer """ - layer = QgsVectorLayer('WFS:http://www2.dmsolutions.ca/cgi-bin/mswfs_gmap', 'test') + layer = QgsVectorLayer( + "WFS:http://www2.dmsolutions.ca/cgi-bin/mswfs_gmap", "test" + ) # now save some metadata metadata = QgsLayerMetadata() - metadata.setAbstract('my abstract') - metadata.setIdentifier('my identifier') - metadata.setLicenses(['l1', 'l2']) + metadata.setAbstract("my abstract") + metadata.setIdentifier("my identifier") + metadata.setLicenses(["l1", "l2"]) layer.setMetadata(metadata) # save as default msg, res = layer.saveDefaultMetadata() self.assertFalse(res) - self.assertEqual(msg, 'Storing metadata for the specified uri is not supported') + self.assertEqual(msg, "Storing metadata for the specified uri is not supported") def testEmbeddedSymbolsKml(self): """ Test retrieving embedded symbols from a KML file """ - layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'embedded_symbols', 'samples.kml') + '|layername=Paths', - 'Lines') + layer = QgsVectorLayer( + os.path.join(TEST_DATA_DIR, "embedded_symbols", "samples.kml") + + "|layername=Paths", + "Lines", + ) self.assertTrue(layer.isValid()) # symbols should not be fetched by default self.assertFalse(any(f.embeddedSymbol() for f in layer.getFeatures())) - symbols = [f.embeddedSymbol().clone() if f.embeddedSymbol() else None for f in - layer.getFeatures(QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.EmbeddedSymbols))] - self.assertCountEqual([s.color().name() for s in symbols if s is not None], - ['#ff00ff', '#ffff00', '#000000', '#ff0000']) - self.assertCountEqual([s.color().alpha() for s in symbols if s is not None], [127, 135, 255, 127]) + symbols = [ + f.embeddedSymbol().clone() if f.embeddedSymbol() else None + for f in layer.getFeatures( + QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.EmbeddedSymbols) + ) + ] + self.assertCountEqual( + [s.color().name() for s in symbols if s is not None], + ["#ff00ff", "#ffff00", "#000000", "#ff0000"], + ) + self.assertCountEqual( + [s.color().alpha() for s in symbols if s is not None], [127, 135, 255, 127] + ) self.assertEqual(len([s for s in symbols if s is None]), 2) def testDecodeEncodeUriVsizip(self): """Test decodeUri/encodeUri for /vsizip/ prefixed URIs""" - uri = '/vsizip//my/file.zip/shapefile.shp' - parts = QgsProviderRegistry.instance().decodeUri('ogr', uri) - self.assertEqual(parts, {'path': '/my/file.zip', 'layerName': None, 'layerId': None, 'vsiPrefix': '/vsizip/', - 'vsiSuffix': '/shapefile.shp'}) - encodedUri = QgsProviderRegistry.instance().encodeUri('ogr', parts) + uri = "/vsizip//my/file.zip/shapefile.shp" + parts = QgsProviderRegistry.instance().decodeUri("ogr", uri) + self.assertEqual( + parts, + { + "path": "/my/file.zip", + "layerName": None, + "layerId": None, + "vsiPrefix": "/vsizip/", + "vsiSuffix": "/shapefile.shp", + }, + ) + encodedUri = QgsProviderRegistry.instance().encodeUri("ogr", parts) self.assertEqual(encodedUri, uri) - uri = '/my/file.zip' - parts = QgsProviderRegistry.instance().decodeUri('ogr', uri) - self.assertEqual(parts, {'path': '/my/file.zip', 'layerName': None, 'layerId': None}) - encodedUri = QgsProviderRegistry.instance().encodeUri('ogr', parts) + uri = "/my/file.zip" + parts = QgsProviderRegistry.instance().decodeUri("ogr", uri) + self.assertEqual( + parts, {"path": "/my/file.zip", "layerName": None, "layerId": None} + ) + encodedUri = QgsProviderRegistry.instance().encodeUri("ogr", parts) self.assertEqual(encodedUri, uri) - uri = '/vsizip//my/file.zip|layername=shapefile' - parts = QgsProviderRegistry.instance().decodeUri('ogr', uri) - self.assertEqual(parts, - {'path': '/my/file.zip', 'layerName': 'shapefile', 'layerId': None, 'vsiPrefix': '/vsizip/'}) - encodedUri = QgsProviderRegistry.instance().encodeUri('ogr', parts) + uri = "/vsizip//my/file.zip|layername=shapefile" + parts = QgsProviderRegistry.instance().decodeUri("ogr", uri) + self.assertEqual( + parts, + { + "path": "/my/file.zip", + "layerName": "shapefile", + "layerId": None, + "vsiPrefix": "/vsizip/", + }, + ) + encodedUri = QgsProviderRegistry.instance().encodeUri("ogr", parts) self.assertEqual(encodedUri, uri) - uri = '/vsizip//my/file.zip|layername=shapefile|subset="field"=\'value\'' - parts = QgsProviderRegistry.instance().decodeUri('ogr', uri) - self.assertEqual(parts, {'path': '/my/file.zip', 'layerName': 'shapefile', 'layerId': None, - 'subset': '"field"=\'value\'', 'vsiPrefix': '/vsizip/'}) - encodedUri = QgsProviderRegistry.instance().encodeUri('ogr', parts) + uri = "/vsizip//my/file.zip|layername=shapefile|subset=\"field\"='value'" + parts = QgsProviderRegistry.instance().decodeUri("ogr", uri) + self.assertEqual( + parts, + { + "path": "/my/file.zip", + "layerName": "shapefile", + "layerId": None, + "subset": "\"field\"='value'", + "vsiPrefix": "/vsizip/", + }, + ) + encodedUri = QgsProviderRegistry.instance().encodeUri("ogr", parts) self.assertEqual(encodedUri, uri) @unittest.skipIf(gdal.GetDriverByName("GTFS") is None, "GTFS driver required") @@ -1631,84 +2160,99 @@ def testDecodeGTFS(self): """Test querySublayers() for GTFS .zip dataset""" uri = os.path.join(TEST_DATA_DIR, "ogr", "gtfs_extract.zip") - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") res = metadata.querySublayers(uri) self.assertEqual(len(res), 9) def testDecodeEncodeUriCredentialOptions(self): """Test decodeUri/encodeUri credential options support""" - uri = '/my/vector.shp|option:AN=OPTION|credential:ANOTHER=BBB|credential:SOMEKEY=AAAAA' - parts = QgsProviderRegistry.instance().decodeUri('ogr', uri) - self.assertEqual(parts, { - 'path': '/my/vector.shp', - 'layerId': None, - 'layerName': None, - 'credentialOptions': { - 'ANOTHER': 'BBB', - 'SOMEKEY': 'AAAAA' + uri = "/my/vector.shp|option:AN=OPTION|credential:ANOTHER=BBB|credential:SOMEKEY=AAAAA" + parts = QgsProviderRegistry.instance().decodeUri("ogr", uri) + self.assertEqual( + parts, + { + "path": "/my/vector.shp", + "layerId": None, + "layerName": None, + "credentialOptions": {"ANOTHER": "BBB", "SOMEKEY": "AAAAA"}, + "openOptions": ["AN=OPTION"], }, - 'openOptions': ['AN=OPTION'] - }) - encodedUri = QgsProviderRegistry.instance().encodeUri('ogr', parts) + ) + encodedUri = QgsProviderRegistry.instance().encodeUri("ogr", parts) self.assertEqual(encodedUri, uri) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 3, 0), "GDAL 3.3 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 3, 0), + "GDAL 3.3 required", + ) def testFieldDomains(self): """ Test that field domains are translated from OGR where available (requires GDAL 3.3 or later) """ - datasource = os.path.join(self.temp_dir_path, 'domains.gpkg') - vl = QgsVectorLayer(datasource, 'test', 'ogr') + datasource = os.path.join(self.temp_dir_path, "domains.gpkg") + vl = QgsVectorLayer(datasource, "test", "ogr") self.assertTrue(vl.isValid()) fields = vl.fields() - range_int_field = fields[fields.lookupField('with_range_domain_int')] + range_int_field = fields[fields.lookupField("with_range_domain_int")] range_int_setup = range_int_field.editorWidgetSetup() - self.assertEqual(range_int_setup.type(), 'Range') - self.assertTrue(range_int_setup.config()['AllowNull']) - self.assertEqual(range_int_setup.config()['Max'], 2) - self.assertEqual(range_int_setup.config()['Min'], 1) - self.assertEqual(range_int_setup.config()['Precision'], 0) - self.assertEqual(range_int_setup.config()['Step'], 1) - self.assertEqual(range_int_setup.config()['Style'], 'SpinBox') + self.assertEqual(range_int_setup.type(), "Range") + self.assertTrue(range_int_setup.config()["AllowNull"]) + self.assertEqual(range_int_setup.config()["Max"], 2) + self.assertEqual(range_int_setup.config()["Min"], 1) + self.assertEqual(range_int_setup.config()["Precision"], 0) + self.assertEqual(range_int_setup.config()["Step"], 1) + self.assertEqual(range_int_setup.config()["Style"], "SpinBox") # make sure editor widget config from provider has been copied to layer! - self.assertEqual(vl.editorWidgetSetup(fields.lookupField('with_range_domain_int')).type(), 'Range') + self.assertEqual( + vl.editorWidgetSetup(fields.lookupField("with_range_domain_int")).type(), + "Range", + ) - range_int64_field = fields[fields.lookupField('with_range_domain_int64')] + range_int64_field = fields[fields.lookupField("with_range_domain_int64")] range_int64_setup = range_int64_field.editorWidgetSetup() - self.assertEqual(range_int64_setup.type(), 'Range') - self.assertTrue(range_int64_setup.config()['AllowNull']) - self.assertEqual(range_int64_setup.config()['Max'], 1234567890123) - self.assertEqual(range_int64_setup.config()['Min'], -1234567890123) - self.assertEqual(range_int64_setup.config()['Precision'], 0) - self.assertEqual(range_int64_setup.config()['Step'], 1) - self.assertEqual(range_int64_setup.config()['Style'], 'SpinBox') - self.assertEqual(vl.editorWidgetSetup(fields.lookupField('with_range_domain_int64')).type(), 'Range') - - range_real_field = fields[fields.lookupField('with_range_domain_real')] + self.assertEqual(range_int64_setup.type(), "Range") + self.assertTrue(range_int64_setup.config()["AllowNull"]) + self.assertEqual(range_int64_setup.config()["Max"], 1234567890123) + self.assertEqual(range_int64_setup.config()["Min"], -1234567890123) + self.assertEqual(range_int64_setup.config()["Precision"], 0) + self.assertEqual(range_int64_setup.config()["Step"], 1) + self.assertEqual(range_int64_setup.config()["Style"], "SpinBox") + self.assertEqual( + vl.editorWidgetSetup(fields.lookupField("with_range_domain_int64")).type(), + "Range", + ) + + range_real_field = fields[fields.lookupField("with_range_domain_real")] range_real_setup = range_real_field.editorWidgetSetup() - self.assertEqual(range_real_setup.type(), 'Range') - self.assertTrue(range_real_setup.config()['AllowNull']) - self.assertEqual(range_real_setup.config()['Max'], 2.5) - self.assertEqual(range_real_setup.config()['Min'], 1.5) - self.assertEqual(range_real_setup.config()['Precision'], 0) - self.assertEqual(range_real_setup.config()['Step'], 1) - self.assertEqual(range_real_setup.config()['Style'], 'SpinBox') - self.assertEqual(vl.editorWidgetSetup(fields.lookupField('with_range_domain_real')).type(), 'Range') - - enum_field = fields[fields.lookupField('with_enum_domain')] + self.assertEqual(range_real_setup.type(), "Range") + self.assertTrue(range_real_setup.config()["AllowNull"]) + self.assertEqual(range_real_setup.config()["Max"], 2.5) + self.assertEqual(range_real_setup.config()["Min"], 1.5) + self.assertEqual(range_real_setup.config()["Precision"], 0) + self.assertEqual(range_real_setup.config()["Step"], 1) + self.assertEqual(range_real_setup.config()["Style"], "SpinBox") + self.assertEqual( + vl.editorWidgetSetup(fields.lookupField("with_range_domain_real")).type(), + "Range", + ) + + enum_field = fields[fields.lookupField("with_enum_domain")] enum_setup = enum_field.editorWidgetSetup() - self.assertEqual(enum_setup.type(), 'ValueMap') - self.assertTrue(enum_setup.config()['map'], [{'one': '1'}, {'2': '2'}]) - self.assertEqual(vl.editorWidgetSetup(fields.lookupField('with_enum_domain')).type(), 'ValueMap') + self.assertEqual(enum_setup.type(), "ValueMap") + self.assertTrue(enum_setup.config()["map"], [{"one": "1"}, {"2": "2"}]) + self.assertEqual( + vl.editorWidgetSetup(fields.lookupField("with_enum_domain")).type(), + "ValueMap", + ) def test_provider_editorWidgets(self): if len(QgsGui.editorWidgetRegistry().factories()) == 0: QgsGui.editorWidgetRegistry().initEditors() - editor_widget_type = 'Color' + editor_widget_type = "Color" factory = QgsGui.instance().editorWidgetRegistry().factory(editor_widget_type) self.assertEqual(factory.name(), editor_widget_type) @@ -1716,15 +2260,17 @@ def test_provider_editorWidgets(self): uri = "point?crs=epsg:4326&field=id:integer" layer = QgsVectorLayer(uri, "Scratch point layer", "memory") - path = '/vsimem/test.gpkg' - result, msg = QgsVectorLayerExporter.exportLayer(layer, path, 'ogr', layer.crs()) + path = "/vsimem/test.gpkg" + result, msg = QgsVectorLayerExporter.exportLayer( + layer, path, "ogr", layer.crs() + ) self.assertEqual(result, Qgis.VectorExportResult.Success) layer = QgsVectorLayer(path) self.assertTrue(layer.isValid()) - self.assertEqual(layer.providerType(), 'ogr') + self.assertEqual(layer.providerType(), "ogr") - field1 = QgsField(name='field1', type=QVariant.String) - field2 = QgsField(name='field2', type=QVariant.String) + field1 = QgsField(name="field1", type=QVariant.String) + field2 = QgsField(name="field2", type=QVariant.String) setup1 = QgsEditorWidgetSetup(editor_widget_type, {}) setup2 = QgsEditorWidgetSetup(editor_widget_type, {}) @@ -1746,224 +2292,299 @@ def test_provider_editorWidgets(self): self.assertTrue(layer.commitChanges()) # editor widget should not change by commitChanges - self.assertEqual(layer.editorWidgetSetup(i).type(), - editor_widget_type, - msg='QgsVectorLayer::commitChanged() changed QgsEditorWidgetSetup' + - f'\nDriver: {layer.dataProvider().name()}') + self.assertEqual( + layer.editorWidgetSetup(i).type(), + editor_widget_type, + msg="QgsVectorLayer::commitChanged() changed QgsEditorWidgetSetup" + + f"\nDriver: {layer.dataProvider().name()}", + ) def test_provider_sublayer_details(self): """ Test retrieving sublayer details from data provider metadata """ - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") # invalid uri - res = metadata.querySublayers('') + res = metadata.querySublayers("") self.assertFalse(res) # not a vector - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'landsat.tif')) + res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "landsat.tif")) self.assertFalse(res) # single layer vector - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'lines.shp')) + res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "lines.shp")) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "lines") - self.assertEqual(res[0].description(), '') + self.assertEqual(res[0].description(), "") self.assertEqual(res[0].uri(), TEST_DATA_DIR + "/lines.shp") self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.LineString) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'ESRI Shapefile') + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "ESRI Shapefile") # zip file layer vector - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'zip', 'points2.zip')) + res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "zip", "points2.zip")) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "points.shp") - self.assertEqual(res[0].description(), '') - self.assertEqual(res[0].uri(), '/vsizip/' + TEST_DATA_DIR + "/zip/points2.zip/points.shp|layername=points") + self.assertEqual(res[0].description(), "") + self.assertEqual( + res[0].uri(), + "/vsizip/" + TEST_DATA_DIR + "/zip/points2.zip/points.shp|layername=points", + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'ESRI Shapefile') - options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext()) + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "ESRI Shapefile") + options = QgsProviderSublayerDetails.LayerOptions( + QgsCoordinateTransformContext() + ) vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) # zip file layer vector, explicit file in zip - res = metadata.querySublayers('/vsizip/' + TEST_DATA_DIR + '/zip/points2.zip/points.shp') + res = metadata.querySublayers( + "/vsizip/" + TEST_DATA_DIR + "/zip/points2.zip/points.shp" + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "points.shp") - self.assertEqual(res[0].description(), '') - self.assertEqual(res[0].uri(), '/vsizip/' + TEST_DATA_DIR + "/zip/points2.zip/points.shp|layername=points") + self.assertEqual(res[0].description(), "") + self.assertEqual( + res[0].uri(), + "/vsizip/" + TEST_DATA_DIR + "/zip/points2.zip/points.shp|layername=points", + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'ESRI Shapefile') - options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext()) + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "ESRI Shapefile") + options = QgsProviderSublayerDetails.LayerOptions( + QgsCoordinateTransformContext() + ) vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) # zip file layer vector, explicit file in zip which is NOT a OGR supported source - res = metadata.querySublayers('/vsizip/' + TEST_DATA_DIR + '/zip/points2.zip/points.qml') + res = metadata.querySublayers( + "/vsizip/" + TEST_DATA_DIR + "/zip/points2.zip/points.qml" + ) self.assertEqual(len(res), 0) # multi-layer archive - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'zip', 'testtar.tgz')) + res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "zip", "testtar.tgz")) self.assertEqual(len(res), 2) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "folder/points.geojson") - self.assertEqual(res[0].description(), '') - self.assertEqual(res[0].uri(), '/vsitar/' + TEST_DATA_DIR + "/zip/testtar.tgz/folder/points.geojson|layername=points") + self.assertEqual(res[0].description(), "") + self.assertEqual( + res[0].uri(), + "/vsitar/" + + TEST_DATA_DIR + + "/zip/testtar.tgz/folder/points.geojson|layername=points", + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'GeoJSON') - options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext()) + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "GeoJSON") + options = QgsProviderSublayerDetails.LayerOptions( + QgsCoordinateTransformContext() + ) vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) self.assertEqual(res[1].layerNumber(), 0) self.assertEqual(res[1].name(), "points.shp") - self.assertEqual(res[1].description(), '') - self.assertEqual(res[1].uri(), '/vsitar/' + TEST_DATA_DIR + "/zip/testtar.tgz/points.shp|layername=points") + self.assertEqual(res[1].description(), "") + self.assertEqual( + res[1].uri(), + "/vsitar/" + TEST_DATA_DIR + "/zip/testtar.tgz/points.shp|layername=points", + ) self.assertEqual(res[1].providerKey(), "ogr") self.assertEqual(res[1].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[1].wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(res[1].geometryColumnName(), '') - self.assertEqual(res[1].driverName(), 'ESRI Shapefile') - options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext()) + self.assertEqual(res[1].geometryColumnName(), "") + self.assertEqual(res[1].driverName(), "ESRI Shapefile") + options = QgsProviderSublayerDetails.LayerOptions( + QgsCoordinateTransformContext() + ) vl = res[1].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) # multi-layer archive, but with specific suffix specified - res = metadata.querySublayers('/vsitar/' + os.path.join(TEST_DATA_DIR, 'zip', 'testtar.tgz') + '/folder/points.geojson') + res = metadata.querySublayers( + "/vsitar/" + + os.path.join(TEST_DATA_DIR, "zip", "testtar.tgz") + + "/folder/points.geojson" + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "folder/points.geojson") - self.assertEqual(res[0].description(), '') - self.assertEqual(res[0].uri(), '/vsitar/' + TEST_DATA_DIR + "/zip/testtar.tgz/folder/points.geojson|layername=points") + self.assertEqual(res[0].description(), "") + self.assertEqual( + res[0].uri(), + "/vsitar/" + + TEST_DATA_DIR + + "/zip/testtar.tgz/folder/points.geojson|layername=points", + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'GeoJSON') - options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext()) + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "GeoJSON") + options = QgsProviderSublayerDetails.LayerOptions( + QgsCoordinateTransformContext() + ) vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(vl.dataProvider().storageType(), 'GeoJSON') + self.assertEqual(vl.dataProvider().storageType(), "GeoJSON") - res = metadata.querySublayers('/vsitar/' + os.path.join(TEST_DATA_DIR, 'zip', 'testtar.tgz') + '/points.shp') + res = metadata.querySublayers( + "/vsitar/" + + os.path.join(TEST_DATA_DIR, "zip", "testtar.tgz") + + "/points.shp" + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "points.shp") - self.assertEqual(res[0].description(), '') - self.assertEqual(res[0].uri(), '/vsitar/' + TEST_DATA_DIR + "/zip/testtar.tgz/points.shp|layername=points") + self.assertEqual(res[0].description(), "") + self.assertEqual( + res[0].uri(), + "/vsitar/" + TEST_DATA_DIR + "/zip/testtar.tgz/points.shp|layername=points", + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'ESRI Shapefile') - options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext()) + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "ESRI Shapefile") + options = QgsProviderSublayerDetails.LayerOptions( + QgsCoordinateTransformContext() + ) vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(vl.dataProvider().storageType(), 'ESRI Shapefile') + self.assertEqual(vl.dataProvider().storageType(), "ESRI Shapefile") # archive, with suffix, and layername - res = metadata.querySublayers('/vsitar/' + os.path.join(TEST_DATA_DIR, 'zip', 'testtar.tgz') + '/points.shp|layername=points') + res = metadata.querySublayers( + "/vsitar/" + + os.path.join(TEST_DATA_DIR, "zip", "testtar.tgz") + + "/points.shp|layername=points" + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "points.shp") - self.assertEqual(res[0].description(), '') - self.assertEqual(res[0].uri(), '/vsitar/' + TEST_DATA_DIR + "/zip/testtar.tgz/points.shp|layername=points") + self.assertEqual(res[0].description(), "") + self.assertEqual( + res[0].uri(), + "/vsitar/" + TEST_DATA_DIR + "/zip/testtar.tgz/points.shp|layername=points", + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'ESRI Shapefile') - options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext()) + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "ESRI Shapefile") + options = QgsProviderSublayerDetails.LayerOptions( + QgsCoordinateTransformContext() + ) vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(vl.dataProvider().storageType(), 'ESRI Shapefile') + self.assertEqual(vl.dataProvider().storageType(), "ESRI Shapefile") # geometry collection sublayers -- requires a scan to resolve geometry type - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'multipatch.shp')) + res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "multipatch.shp")) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "multipatch") - self.assertEqual(res[0].description(), '') + self.assertEqual(res[0].description(), "") self.assertEqual(res[0].uri(), TEST_DATA_DIR + "/multipatch.shp") self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Unknown) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'ESRI Shapefile') + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "ESRI Shapefile") # retry with retrieving geometry types - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'multipatch.shp'), Qgis.SublayerQueryFlag.ResolveGeometryType) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "multipatch.shp"), + Qgis.SublayerQueryFlag.ResolveGeometryType, + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "multipatch") - self.assertEqual(res[0].description(), '') - self.assertEqual(res[0].uri(), TEST_DATA_DIR + "/multipatch.shp|geometrytype=Polygon25D|uniqueGeometryType=yes") + self.assertEqual(res[0].description(), "") + self.assertEqual( + res[0].uri(), + TEST_DATA_DIR + + "/multipatch.shp|geometrytype=Polygon25D|uniqueGeometryType=yes", + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.PolygonZ) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'ESRI Shapefile') + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "ESRI Shapefile") # check a feature vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) feature = next(vl.getFeatures()) self.assertEqual(feature.geometry().wkbType(), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(feature.geometry().asWkt(), 'MultiPolygon Z (((0 0 0, 0 1 0, 1 1 0, 0 0 0)),((0 0 0, 1 1 0, 1 0 0,' - ' 0 0 0)),((0 0 0, 0 -1 0, 1 -1 0, 0 0 0)),((0 0 0, 1 -1 0, 1 0 0, 0 0 0)))') + self.assertEqual( + feature.geometry().asWkt(), + "MultiPolygon Z (((0 0 0, 0 1 0, 1 1 0, 0 0 0)),((0 0 0, 1 1 0, 1 0 0," + " 0 0 0)),((0 0 0, 0 -1 0, 1 -1 0, 0 0 0)),((0 0 0, 1 -1 0, 1 0 0, 0 0 0)))", + ) # single layer geopackage -- sublayers MUST have the layerName set on the uri, # in case more layers are added in future to the gpkg - res = metadata.querySublayers(os.path.join(self.temp_dir_path, 'curved_polys.gpkg')) + res = metadata.querySublayers( + os.path.join(self.temp_dir_path, "curved_polys.gpkg") + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "polys") - self.assertEqual(res[0].description(), '') - self.assertEqual(res[0].uri(), self.temp_dir_path + "/curved_polys.gpkg|layername=polys") + self.assertEqual(res[0].description(), "") + self.assertEqual( + res[0].uri(), self.temp_dir_path + "/curved_polys.gpkg|layername=polys" + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.CurvePolygon) - self.assertEqual(res[0].geometryColumnName(), 'geometry') - self.assertEqual(res[0].driverName(), 'GPKG') + self.assertEqual(res[0].geometryColumnName(), "geometry") + self.assertEqual(res[0].driverName(), "GPKG") # make sure result is valid to load layer from vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) # geopackage with two vector layers - res = metadata.querySublayers(os.path.join(self.temp_dir_path, "mixed_layers.gpkg")) + res = metadata.querySublayers( + os.path.join(self.temp_dir_path, "mixed_layers.gpkg") + ) self.assertEqual(len(res), 2) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "points") self.assertEqual(res[0].description(), "") - self.assertEqual(res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=points") + self.assertEqual( + res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=points" + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(res[0].geometryColumnName(), 'geometry') - self.assertEqual(res[0].driverName(), 'GPKG') + self.assertEqual(res[0].geometryColumnName(), "geometry") + self.assertEqual(res[0].driverName(), "GPKG") vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) @@ -1971,89 +2592,110 @@ def test_provider_sublayer_details(self): self.assertEqual(res[1].layerNumber(), 1) self.assertEqual(res[1].name(), "lines") self.assertEqual(res[1].description(), "") - self.assertEqual(res[1].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=lines") + self.assertEqual( + res[1].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=lines" + ) self.assertEqual(res[1].providerKey(), "ogr") self.assertEqual(res[1].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[1].featureCount(), Qgis.FeatureCountState.Uncounted) self.assertEqual(res[1].wkbType(), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(res[1].geometryColumnName(), 'geom') - self.assertEqual(res[1].driverName(), 'GPKG') + self.assertEqual(res[1].geometryColumnName(), "geom") + self.assertEqual(res[1].driverName(), "GPKG") vl = res[1].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.MultiLineString) # request feature count - res = metadata.querySublayers(os.path.join(self.temp_dir_path, "mixed_layers.gpkg"), Qgis.SublayerQueryFlag.CountFeatures) + res = metadata.querySublayers( + os.path.join(self.temp_dir_path, "mixed_layers.gpkg"), + Qgis.SublayerQueryFlag.CountFeatures, + ) self.assertEqual(len(res), 2) self.assertEqual(res[0].name(), "points") self.assertEqual(res[0].featureCount(), 0) - self.assertEqual(res[0].geometryColumnName(), 'geometry') + self.assertEqual(res[0].geometryColumnName(), "geometry") self.assertEqual(res[1].name(), "lines") self.assertEqual(res[1].featureCount(), 6) - self.assertEqual(res[1].geometryColumnName(), 'geom') - self.assertEqual(res[1].driverName(), 'GPKG') + self.assertEqual(res[1].geometryColumnName(), "geom") + self.assertEqual(res[1].driverName(), "GPKG") # geopackage with two layers, but specific layer is requested in uri - res = metadata.querySublayers(os.path.join(self.temp_dir_path, "mixed_layers.gpkg") + '|layerid=0') + res = metadata.querySublayers( + os.path.join(self.temp_dir_path, "mixed_layers.gpkg") + "|layerid=0" + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "points") self.assertEqual(res[0].description(), "") - self.assertEqual(res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=points") + self.assertEqual( + res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=points" + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(res[0].geometryColumnName(), 'geometry') - self.assertEqual(res[0].driverName(), 'GPKG') + self.assertEqual(res[0].geometryColumnName(), "geometry") + self.assertEqual(res[0].driverName(), "GPKG") vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) - res = metadata.querySublayers(os.path.join(self.temp_dir_path, "mixed_layers.gpkg") + '|layerid=1') + res = metadata.querySublayers( + os.path.join(self.temp_dir_path, "mixed_layers.gpkg") + "|layerid=1" + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 1) self.assertEqual(res[0].name(), "lines") self.assertEqual(res[0].description(), "") - self.assertEqual(res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=lines") + self.assertEqual( + res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=lines" + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(res[0].geometryColumnName(), 'geom') - self.assertEqual(res[0].driverName(), 'GPKG') + self.assertEqual(res[0].geometryColumnName(), "geom") + self.assertEqual(res[0].driverName(), "GPKG") vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.MultiLineString) - res = metadata.querySublayers(os.path.join(self.temp_dir_path, "mixed_layers.gpkg") + '|layername=points') + res = metadata.querySublayers( + os.path.join(self.temp_dir_path, "mixed_layers.gpkg") + "|layername=points" + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "points") self.assertEqual(res[0].description(), "") - self.assertEqual(res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=points") + self.assertEqual( + res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=points" + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(res[0].geometryColumnName(), 'geometry') - self.assertEqual(res[0].driverName(), 'GPKG') + self.assertEqual(res[0].geometryColumnName(), "geometry") + self.assertEqual(res[0].driverName(), "GPKG") vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) - res = metadata.querySublayers(os.path.join(self.temp_dir_path, "mixed_layers.gpkg") + '|layername=lines') + res = metadata.querySublayers( + os.path.join(self.temp_dir_path, "mixed_layers.gpkg") + "|layername=lines" + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 1) self.assertEqual(res[0].name(), "lines") self.assertEqual(res[0].description(), "") - self.assertEqual(res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=lines") + self.assertEqual( + res[0].uri(), f"{self.temp_dir_path}/mixed_layers.gpkg|layername=lines" + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(res[0].geometryColumnName(), 'geom') - self.assertEqual(res[0].driverName(), 'GPKG') + self.assertEqual(res[0].geometryColumnName(), "geom") + self.assertEqual(res[0].driverName(), "GPKG") vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.MultiLineString) @@ -2069,13 +2711,16 @@ def test_provider_sublayer_details(self): self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Unknown) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'MapInfo File') + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "MapInfo File") vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) # layer with mixed geometry types - without resolving geometry types, but with feature count - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB"), Qgis.SublayerQueryFlag.CountFeatures) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "mixed_types.TAB"), + Qgis.SublayerQueryFlag.CountFeatures, + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "mixed_types") @@ -2085,22 +2730,27 @@ def test_provider_sublayer_details(self): self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].featureCount(), 13) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Unknown) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'MapInfo File') + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "MapInfo File") # layer with mixed geometry types - resolve geometry type (for OGR provider this implies also that we count features!) - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB"), Qgis.SublayerQueryFlag.ResolveGeometryType) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "mixed_types.TAB"), + Qgis.SublayerQueryFlag.ResolveGeometryType, + ) self.assertEqual(len(res), 3) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "mixed_types") self.assertEqual(res[0].description(), "") - self.assertEqual(res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Point") + self.assertEqual( + res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Point" + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].featureCount(), 4) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'MapInfo File') + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "MapInfo File") vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) @@ -2108,13 +2758,15 @@ def test_provider_sublayer_details(self): self.assertEqual(res[1].layerNumber(), 0) self.assertEqual(res[1].name(), "mixed_types") self.assertEqual(res[1].description(), "") - self.assertEqual(res[1].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=LineString") + self.assertEqual( + res[1].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=LineString" + ) self.assertEqual(res[1].providerKey(), "ogr") self.assertEqual(res[1].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[1].featureCount(), 4) self.assertEqual(res[1].wkbType(), QgsWkbTypes.Type.LineString) - self.assertEqual(res[1].geometryColumnName(), '') - self.assertEqual(res[1].driverName(), 'MapInfo File') + self.assertEqual(res[1].geometryColumnName(), "") + self.assertEqual(res[1].driverName(), "MapInfo File") vl = res[1].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.LineString) @@ -2122,38 +2774,47 @@ def test_provider_sublayer_details(self): self.assertEqual(res[2].layerNumber(), 0) self.assertEqual(res[2].name(), "mixed_types") self.assertEqual(res[2].description(), "") - self.assertEqual(res[2].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Polygon") + self.assertEqual( + res[2].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Polygon" + ) self.assertEqual(res[2].providerKey(), "ogr") self.assertEqual(res[2].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[2].featureCount(), 3) self.assertEqual(res[2].wkbType(), QgsWkbTypes.Type.Polygon) - self.assertEqual(res[2].geometryColumnName(), '') - self.assertEqual(res[2].driverName(), 'MapInfo File') + self.assertEqual(res[2].geometryColumnName(), "") + self.assertEqual(res[2].driverName(), "MapInfo File") vl = res[2].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Polygon) # a layer which reports unknown geometry type and requires a full table scan to resolve, but which only # contains a single type of geometry - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mapinfo", "fill_styles.TAB"), - Qgis.SublayerQueryFlag.ResolveGeometryType) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "mapinfo", "fill_styles.TAB"), + Qgis.SublayerQueryFlag.ResolveGeometryType, + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "fill_styles") self.assertEqual(res[0].description(), "") - self.assertEqual(res[0].uri(), f"{TEST_DATA_DIR}/mapinfo/fill_styles.TAB|geometrytype=Polygon|uniqueGeometryType=yes") + self.assertEqual( + res[0].uri(), + f"{TEST_DATA_DIR}/mapinfo/fill_styles.TAB|geometrytype=Polygon|uniqueGeometryType=yes", + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].featureCount(), 49) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Polygon) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'MapInfo File') + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "MapInfo File") vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Polygon) # same, but don't resolve geometry types - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mapinfo", "fill_styles.TAB")) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "mapinfo", "fill_styles.TAB") + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "fill_styles") @@ -2163,294 +2824,387 @@ def test_provider_sublayer_details(self): self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Unknown) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'MapInfo File') + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "MapInfo File") vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Polygon) # mixed types source, but with a URI which specifies a particular type. Only this type should be returned - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Point"), - Qgis.SublayerQueryFlag.ResolveGeometryType) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Point"), + Qgis.SublayerQueryFlag.ResolveGeometryType, + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "mixed_types") self.assertEqual(res[0].description(), "") - self.assertEqual(res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Point") + self.assertEqual( + res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Point" + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].featureCount(), 4) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'MapInfo File') + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "MapInfo File") vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=LineString"), - Qgis.SublayerQueryFlag.ResolveGeometryType) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=LineString"), + Qgis.SublayerQueryFlag.ResolveGeometryType, + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "mixed_types") self.assertEqual(res[0].description(), "") - self.assertEqual(res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=LineString") + self.assertEqual( + res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=LineString" + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].featureCount(), 4) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.LineString) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'MapInfo File') + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "MapInfo File") vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.LineString) - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Polygon"), - Qgis.SublayerQueryFlag.ResolveGeometryType) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Polygon"), + Qgis.SublayerQueryFlag.ResolveGeometryType, + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "mixed_types") self.assertEqual(res[0].description(), "") - self.assertEqual(res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Polygon") + self.assertEqual( + res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Polygon" + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].featureCount(), 3) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Polygon) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'MapInfo File') + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "MapInfo File") vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Polygon) # same as above, but without ResolveGeometryType flag - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Point")) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Point") + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "mixed_types") self.assertEqual(res[0].description(), "") - self.assertEqual(res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Point") + self.assertEqual( + res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Point" + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'MapInfo File') + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "MapInfo File") vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=LineString")) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=LineString") + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "mixed_types") self.assertEqual(res[0].description(), "") - self.assertEqual(res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=LineString") + self.assertEqual( + res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=LineString" + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.LineString) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'MapInfo File') + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "MapInfo File") vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.LineString) - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Polygon")) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Polygon") + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "mixed_types") self.assertEqual(res[0].description(), "") - self.assertEqual(res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Polygon") + self.assertEqual( + res[0].uri(), f"{TEST_DATA_DIR}/mixed_types.TAB|geometrytype=Polygon" + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Polygon) - self.assertEqual(res[0].geometryColumnName(), '') - self.assertEqual(res[0].driverName(), 'MapInfo File') + self.assertEqual(res[0].geometryColumnName(), "") + self.assertEqual(res[0].driverName(), "MapInfo File") vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Polygon) # spatialite - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "provider/spatialite.db")) - self.assertCountEqual([{'name': r.name(), - 'description': r.description(), - 'uri': r.uri(), - 'providerKey': r.providerKey(), - 'wkbType': r.wkbType(), - 'driverName': r.driverName(), - 'geomColName': r.geometryColumnName()} for r in res], - [{'name': 'somedata', - 'description': '', - 'uri': f'{TEST_DATA_DIR}/provider/spatialite.db|layername=somedata', - 'providerKey': 'ogr', - 'wkbType': 1, - 'driverName': 'SQLite', - 'geomColName': 'geom'}, - {'name': 'somepolydata', - 'description': '', - 'uri': f'{TEST_DATA_DIR}/provider/spatialite.db|layername=somepolydata', - 'providerKey': 'ogr', - 'wkbType': 6, - 'driverName': 'SQLite', - 'geomColName': 'geom'}, - {'name': 'some data', - 'description': '', - 'uri': f'{TEST_DATA_DIR}/provider/spatialite.db|layername=some data', - 'providerKey': 'ogr', - 'wkbType': 1, - 'driverName': 'SQLite', - 'geomColName': 'geom'}, - {'name': 'validator_project_test', - 'description': '', - 'uri': f'{TEST_DATA_DIR}/provider/spatialite.db|layername=validator_project_test', - 'providerKey': 'ogr', - 'wkbType': 1, - 'driverName': 'SQLite', - 'geomColName': 'geom'}, - {'name': 'data_licenses', - 'description': '', - 'uri': f'{TEST_DATA_DIR}/provider/spatialite.db|layername=data_licenses', - 'providerKey': 'ogr', - 'wkbType': 100, - 'driverName': 'SQLite', - 'geomColName': ''}, - {'name': 'some view', - 'description': '', - 'uri': f'{TEST_DATA_DIR}/provider/spatialite.db|layername=some view', - 'providerKey': 'ogr', - 'wkbType': 100, - 'driverName': 'SQLite', - 'geomColName': ''}]) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "provider/spatialite.db") + ) + self.assertCountEqual( + [ + { + "name": r.name(), + "description": r.description(), + "uri": r.uri(), + "providerKey": r.providerKey(), + "wkbType": r.wkbType(), + "driverName": r.driverName(), + "geomColName": r.geometryColumnName(), + } + for r in res + ], + [ + { + "name": "somedata", + "description": "", + "uri": f"{TEST_DATA_DIR}/provider/spatialite.db|layername=somedata", + "providerKey": "ogr", + "wkbType": 1, + "driverName": "SQLite", + "geomColName": "geom", + }, + { + "name": "somepolydata", + "description": "", + "uri": f"{TEST_DATA_DIR}/provider/spatialite.db|layername=somepolydata", + "providerKey": "ogr", + "wkbType": 6, + "driverName": "SQLite", + "geomColName": "geom", + }, + { + "name": "some data", + "description": "", + "uri": f"{TEST_DATA_DIR}/provider/spatialite.db|layername=some data", + "providerKey": "ogr", + "wkbType": 1, + "driverName": "SQLite", + "geomColName": "geom", + }, + { + "name": "validator_project_test", + "description": "", + "uri": f"{TEST_DATA_DIR}/provider/spatialite.db|layername=validator_project_test", + "providerKey": "ogr", + "wkbType": 1, + "driverName": "SQLite", + "geomColName": "geom", + }, + { + "name": "data_licenses", + "description": "", + "uri": f"{TEST_DATA_DIR}/provider/spatialite.db|layername=data_licenses", + "providerKey": "ogr", + "wkbType": 100, + "driverName": "SQLite", + "geomColName": "", + }, + { + "name": "some view", + "description": "", + "uri": f"{TEST_DATA_DIR}/provider/spatialite.db|layername=some view", + "providerKey": "ogr", + "wkbType": 100, + "driverName": "SQLite", + "geomColName": "", + }, + ], + ) # sqlite res = metadata.querySublayers( - os.path.join(TEST_DATA_DIR, "valuerelation_widget_wrapper_test.spatialite.sqlite")) - self.assertCountEqual([{'name': r.name(), - 'systemTable': bool(r.flags() & Qgis.SublayerFlag.SystemTable)} for r in res], - [{'name': 'authors', 'systemTable': False}, - {'name': 'json', 'systemTable': False}]) + os.path.join( + TEST_DATA_DIR, "valuerelation_widget_wrapper_test.spatialite.sqlite" + ) + ) + self.assertCountEqual( + [ + { + "name": r.name(), + "systemTable": bool(r.flags() & Qgis.SublayerFlag.SystemTable), + } + for r in res + ], + [ + {"name": "authors", "systemTable": False}, + {"name": "json", "systemTable": False}, + ], + ) # retrieve system tables res = metadata.querySublayers( - os.path.join(TEST_DATA_DIR, "valuerelation_widget_wrapper_test.spatialite.sqlite"), - Qgis.SublayerQueryFlag.IncludeSystemTables) - self.assertCountEqual([{'name': r.name(), - 'systemTable': bool(r.flags() & Qgis.SublayerFlag.SystemTable)} for r in res], - [{'name': 'ElementaryGeometries', 'systemTable': True}, - {'name': 'SpatialIndex', 'systemTable': True}, - {'name': 'authors', 'systemTable': False}, - {'name': 'geom_cols_ref_sys', 'systemTable': True}, - {'name': 'geometry_columns', 'systemTable': True}, - {'name': 'geometry_columns_auth', 'systemTable': True}, - {'name': 'geometry_columns_field_infos', 'systemTable': True}, - {'name': 'geometry_columns_statistics', 'systemTable': True}, - {'name': 'geometry_columns_time', 'systemTable': True}, - {'name': 'json', 'systemTable': False}, - {'name': 'spatial_ref_sys', 'systemTable': True}, - {'name': 'spatial_ref_sys_all', 'systemTable': True}, - {'name': 'spatial_ref_sys_aux', 'systemTable': True}, - {'name': 'spatialite_history', 'systemTable': True}, - {'name': 'sql_statements_log', 'systemTable': True}, - {'name': 'sqlite_sequence', 'systemTable': True}, - {'name': 'vector_layers', 'systemTable': True}, - {'name': 'vector_layers_auth', 'systemTable': True}, - {'name': 'vector_layers_field_infos', 'systemTable': True}, - {'name': 'vector_layers_statistics', 'systemTable': True}, - {'name': 'views_geometry_columns', 'systemTable': True}, - {'name': 'views_geometry_columns_auth', 'systemTable': True}, - {'name': 'views_geometry_columns_field_infos', 'systemTable': True}, - {'name': 'views_geometry_columns_statistics', 'systemTable': True}, - {'name': 'virts_geometry_columns', 'systemTable': True}, - {'name': 'virts_geometry_columns_auth', 'systemTable': True}, - {'name': 'virts_geometry_columns_field_infos', 'systemTable': True}, - {'name': 'virts_geometry_columns_statistics', 'systemTable': True}]) + os.path.join( + TEST_DATA_DIR, "valuerelation_widget_wrapper_test.spatialite.sqlite" + ), + Qgis.SublayerQueryFlag.IncludeSystemTables, + ) + self.assertCountEqual( + [ + { + "name": r.name(), + "systemTable": bool(r.flags() & Qgis.SublayerFlag.SystemTable), + } + for r in res + ], + [ + {"name": "ElementaryGeometries", "systemTable": True}, + {"name": "SpatialIndex", "systemTable": True}, + {"name": "authors", "systemTable": False}, + {"name": "geom_cols_ref_sys", "systemTable": True}, + {"name": "geometry_columns", "systemTable": True}, + {"name": "geometry_columns_auth", "systemTable": True}, + {"name": "geometry_columns_field_infos", "systemTable": True}, + {"name": "geometry_columns_statistics", "systemTable": True}, + {"name": "geometry_columns_time", "systemTable": True}, + {"name": "json", "systemTable": False}, + {"name": "spatial_ref_sys", "systemTable": True}, + {"name": "spatial_ref_sys_all", "systemTable": True}, + {"name": "spatial_ref_sys_aux", "systemTable": True}, + {"name": "spatialite_history", "systemTable": True}, + {"name": "sql_statements_log", "systemTable": True}, + {"name": "sqlite_sequence", "systemTable": True}, + {"name": "vector_layers", "systemTable": True}, + {"name": "vector_layers_auth", "systemTable": True}, + {"name": "vector_layers_field_infos", "systemTable": True}, + {"name": "vector_layers_statistics", "systemTable": True}, + {"name": "views_geometry_columns", "systemTable": True}, + {"name": "views_geometry_columns_auth", "systemTable": True}, + {"name": "views_geometry_columns_field_infos", "systemTable": True}, + {"name": "views_geometry_columns_statistics", "systemTable": True}, + {"name": "virts_geometry_columns", "systemTable": True}, + {"name": "virts_geometry_columns_auth", "systemTable": True}, + {"name": "virts_geometry_columns_field_infos", "systemTable": True}, + {"name": "virts_geometry_columns_statistics", "systemTable": True}, + ], + ) # metadata.xml file next to tdenv?.adf file -- this is a subcomponent of an ESRI tin layer, should not be exposed res = metadata.querySublayers( - os.path.join(TEST_DATA_DIR, 'esri_tin', 'metadata.xml')) + os.path.join(TEST_DATA_DIR, "esri_tin", "metadata.xml") + ) self.assertFalse(res) # ESRI Arcinfo file - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'esri_coverage', 'testpolyavc')) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "esri_coverage", "testpolyavc") + ) self.assertEqual(len(res), 4) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "ARC") self.assertEqual(res[0].description(), "") - self.assertEqual(res[0].uri(), f"{os.path.join(TEST_DATA_DIR, 'esri_coverage', 'testpolyavc')}|layername=ARC") + self.assertEqual( + res[0].uri(), + f"{os.path.join(TEST_DATA_DIR, 'esri_coverage', 'testpolyavc')}|layername=ARC", + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertFalse(res[0].skippedContainerScan()) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 4, 0), "GDAL 3.4 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 4, 0), + "GDAL 3.4 required", + ) def test_provider_sublayer_details_hierarchy(self): """ Test retrieving sublayer details from a datasource with a hierarchy of layers """ - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'featuredataset.gdb')) + res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "featuredataset.gdb")) self.assertEqual(len(res), 4) - self.assertEqual(res[0].name(), 'fd1_lyr1') - self.assertEqual(res[0].path(), ['fd1']) - self.assertEqual(res[1].name(), 'fd1_lyr2') - self.assertEqual(res[1].path(), ['fd1']) - self.assertEqual(res[2].name(), 'standalone') + self.assertEqual(res[0].name(), "fd1_lyr1") + self.assertEqual(res[0].path(), ["fd1"]) + self.assertEqual(res[1].name(), "fd1_lyr2") + self.assertEqual(res[1].path(), ["fd1"]) + self.assertEqual(res[2].name(), "standalone") self.assertEqual(res[2].path(), []) - self.assertEqual(res[3].name(), 'fd2_lyr') - self.assertEqual(res[3].path(), ['fd2']) + self.assertEqual(res[3].name(), "fd2_lyr") + self.assertEqual(res[3].path(), ["fd2"]) def test_provider_sublayer_details_fast_scan(self): """ Test retrieving sublayer details from data provider metadata, using fast scan """ - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") # invalid uri - res = metadata.querySublayers('', Qgis.SublayerQueryFlag.FastScan) + res = metadata.querySublayers("", Qgis.SublayerQueryFlag.FastScan) self.assertFalse(res) # not a vector - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'landsat.tif'), Qgis.SublayerQueryFlag.FastScan) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "landsat.tif"), Qgis.SublayerQueryFlag.FastScan + ) self.assertFalse(res) # single layer vector - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'lines.shp'), Qgis.SublayerQueryFlag.FastScan) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "lines.shp"), Qgis.SublayerQueryFlag.FastScan + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "lines") - self.assertEqual(res[0].description(), '') + self.assertEqual(res[0].description(), "") self.assertEqual(res[0].uri(), TEST_DATA_DIR + "/lines.shp") self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertFalse(res[0].skippedContainerScan()) # geometry collection sublayers -- requires a scan to resolve geometry type - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'multipatch.shp'), Qgis.SublayerQueryFlag.FastScan) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "multipatch.shp"), + Qgis.SublayerQueryFlag.FastScan, + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "multipatch") - self.assertEqual(res[0].description(), '') + self.assertEqual(res[0].description(), "") self.assertEqual(res[0].uri(), TEST_DATA_DIR + "/multipatch.shp") self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Unknown) - self.assertEqual(res[0].geometryColumnName(), '') + self.assertEqual(res[0].geometryColumnName(), "") self.assertFalse(res[0].skippedContainerScan()) # single layer geopackage -- sublayers MUST have the layerName set on the uri, # in case more layers are added in future to the gpkg - res = metadata.querySublayers(os.path.join(self.temp_dir_path, 'curved_polys.gpkg'), Qgis.SublayerQueryFlag.FastScan) + res = metadata.querySublayers( + os.path.join(self.temp_dir_path, "curved_polys.gpkg"), + Qgis.SublayerQueryFlag.FastScan, + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "curved_polys") - self.assertEqual(res[0].description(), '') + self.assertEqual(res[0].description(), "") self.assertEqual(res[0].uri(), self.temp_dir_path + "/curved_polys.gpkg") self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertTrue(res[0].skippedContainerScan()) # geopackage with two vector layers - res = metadata.querySublayers(os.path.join(self.temp_dir_path, "mixed_layers.gpkg"), Qgis.SublayerQueryFlag.FastScan) + res = metadata.querySublayers( + os.path.join(self.temp_dir_path, "mixed_layers.gpkg"), + Qgis.SublayerQueryFlag.FastScan, + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "mixed_layers") @@ -2461,7 +3215,10 @@ def test_provider_sublayer_details_fast_scan(self): self.assertTrue(res[0].skippedContainerScan()) # layer with mixed geometry types - without resolving geometry types - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB"), Qgis.SublayerQueryFlag.FastScan) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "mixed_types.TAB"), + Qgis.SublayerQueryFlag.FastScan, + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "mixed_types") @@ -2472,7 +3229,10 @@ def test_provider_sublayer_details_fast_scan(self): self.assertFalse(res[0].skippedContainerScan()) # spatialite - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "provider/spatialite.db"), Qgis.SublayerQueryFlag.FastScan) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "provider/spatialite.db"), + Qgis.SublayerQueryFlag.FastScan, + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "spatialite") @@ -2483,12 +3243,17 @@ def test_provider_sublayer_details_fast_scan(self): self.assertTrue(res[0].skippedContainerScan()) # fast scan, but for trivial type -- fast scan flag will be ignored - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "spreadsheet.ods"), Qgis.SublayerQueryFlag.FastScan) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "spreadsheet.ods"), + Qgis.SublayerQueryFlag.FastScan, + ) self.assertEqual(len(res), 2) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "Sheet1") self.assertEqual(res[0].description(), "") - self.assertEqual(res[0].uri(), f"{TEST_DATA_DIR}/spreadsheet.ods|layername=Sheet1") + self.assertEqual( + res[0].uri(), f"{TEST_DATA_DIR}/spreadsheet.ods|layername=Sheet1" + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].driverName(), "ODS") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) @@ -2496,14 +3261,19 @@ def test_provider_sublayer_details_fast_scan(self): self.assertEqual(res[1].layerNumber(), 1) self.assertEqual(res[1].name(), "Sheet2") self.assertEqual(res[1].description(), "") - self.assertEqual(res[1].uri(), f"{TEST_DATA_DIR}/spreadsheet.ods|layername=Sheet2") + self.assertEqual( + res[1].uri(), f"{TEST_DATA_DIR}/spreadsheet.ods|layername=Sheet2" + ) self.assertEqual(res[1].providerKey(), "ogr") self.assertEqual(res[1].driverName(), "ODS") self.assertEqual(res[1].type(), QgsMapLayerType.VectorLayer) self.assertFalse(res[1].skippedContainerScan()) # vector vrt - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "vector_vrt.vrt"), Qgis.SublayerQueryFlag.FastScan) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "vector_vrt.vrt"), + Qgis.SublayerQueryFlag.FastScan, + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "vector_vrt") @@ -2514,76 +3284,126 @@ def test_provider_sublayer_details_fast_scan(self): self.assertTrue(res[0].skippedContainerScan()) # raster vrt - res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "/raster/hub13263.vrt"), Qgis.SublayerQueryFlag.FastScan) + res = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "/raster/hub13263.vrt"), + Qgis.SublayerQueryFlag.FastScan, + ) self.assertEqual(len(res), 0) # metadata.xml file next to tdenv?.adf file -- this is a subcomponent of an ESRI tin layer, should not be exposed res = metadata.querySublayers( - os.path.join(TEST_DATA_DIR, 'esri_tin', 'metadata.xml'), Qgis.SublayerQueryFlag.FastScan) + os.path.join(TEST_DATA_DIR, "esri_tin", "metadata.xml"), + Qgis.SublayerQueryFlag.FastScan, + ) self.assertFalse(res) # ESRI Arcinfo file res = metadata.querySublayers( - os.path.join(TEST_DATA_DIR, 'esri_coverage', 'testpolyavc'), Qgis.SublayerQueryFlag.FastScan) + os.path.join(TEST_DATA_DIR, "esri_coverage", "testpolyavc"), + Qgis.SublayerQueryFlag.FastScan, + ) self.assertEqual(len(res), 4) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "ARC") self.assertEqual(res[0].description(), "") - self.assertEqual(res[0].uri(), f"{os.path.join(TEST_DATA_DIR, 'esri_coverage', 'testpolyavc')}|layername=ARC") + self.assertEqual( + res[0].uri(), + f"{os.path.join(TEST_DATA_DIR, 'esri_coverage', 'testpolyavc')}|layername=ARC", + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertFalse(res[0].skippedContainerScan()) # zip file layer vector, explicit file in zip - res = metadata.querySublayers('/vsizip/' + TEST_DATA_DIR + '/zip/points2.zip/points.shp', Qgis.SublayerQueryFlag.FastScan) + res = metadata.querySublayers( + "/vsizip/" + TEST_DATA_DIR + "/zip/points2.zip/points.shp", + Qgis.SublayerQueryFlag.FastScan, + ) self.assertEqual(len(res), 1) self.assertEqual(res[0].layerNumber(), 0) self.assertEqual(res[0].name(), "points") - self.assertEqual(res[0].description(), '') - self.assertEqual(res[0].uri(), '/vsizip/' + TEST_DATA_DIR + "/zip/points2.zip/points.shp") + self.assertEqual(res[0].description(), "") + self.assertEqual( + res[0].uri(), "/vsizip/" + TEST_DATA_DIR + "/zip/points2.zip/points.shp" + ) self.assertEqual(res[0].providerKey(), "ogr") self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(res[0].wkbType(), QgsWkbTypes.Type.Unknown) - self.assertEqual(res[0].geometryColumnName(), '') - options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext()) + self.assertEqual(res[0].geometryColumnName(), "") + options = QgsProviderSublayerDetails.LayerOptions( + QgsCoordinateTransformContext() + ) vl = res[0].toLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) # zip file layer vector, explicit file in zip which is NOT a OGR supported source - res = metadata.querySublayers('/vsizip/' + TEST_DATA_DIR + '/zip/points2.zip/points.qml', Qgis.SublayerQueryFlag.FastScan) + res = metadata.querySublayers( + "/vsizip/" + TEST_DATA_DIR + "/zip/points2.zip/points.qml", + Qgis.SublayerQueryFlag.FastScan, + ) self.assertEqual(len(res), 0) def test_provider_sidecar_files_for_uri(self): """ Test retrieving sidecar files for uris """ - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') - - self.assertEqual(metadata.sidecarFilesForUri(''), []) - self.assertEqual(metadata.sidecarFilesForUri('/home/me/not special.doc'), []) - self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.shp'), - ['/home/me/special.shx', '/home/me/special.dbf', '/home/me/special.sbn', - '/home/me/special.sbx', '/home/me/special.prj', '/home/me/special.idm', - '/home/me/special.ind', '/home/me/special.qix', '/home/me/special.cpg', - '/home/me/special.qpj', '/home/me/special.shp.xml']) - self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.tab'), - ['/home/me/special.dat', '/home/me/special.id', '/home/me/special.map', '/home/me/special.ind', - '/home/me/special.tda', '/home/me/special.tin', '/home/me/special.tma', - '/home/me/special.lda', '/home/me/special.lin', '/home/me/special.lma']) - self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.mif'), - ['/home/me/special.mid']) - self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.gml'), - ['/home/me/special.gfs', '/home/me/special.xsd']) - self.assertEqual(metadata.sidecarFilesForUri('/home/me/special.csv'), ['/home/me/special.csvt']) + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") + + self.assertEqual(metadata.sidecarFilesForUri(""), []) + self.assertEqual(metadata.sidecarFilesForUri("/home/me/not special.doc"), []) + self.assertEqual( + metadata.sidecarFilesForUri("/home/me/special.shp"), + [ + "/home/me/special.shx", + "/home/me/special.dbf", + "/home/me/special.sbn", + "/home/me/special.sbx", + "/home/me/special.prj", + "/home/me/special.idm", + "/home/me/special.ind", + "/home/me/special.qix", + "/home/me/special.cpg", + "/home/me/special.qpj", + "/home/me/special.shp.xml", + ], + ) + self.assertEqual( + metadata.sidecarFilesForUri("/home/me/special.tab"), + [ + "/home/me/special.dat", + "/home/me/special.id", + "/home/me/special.map", + "/home/me/special.ind", + "/home/me/special.tda", + "/home/me/special.tin", + "/home/me/special.tma", + "/home/me/special.lda", + "/home/me/special.lin", + "/home/me/special.lma", + ], + ) + self.assertEqual( + metadata.sidecarFilesForUri("/home/me/special.mif"), + ["/home/me/special.mid"], + ) + self.assertEqual( + metadata.sidecarFilesForUri("/home/me/special.gml"), + ["/home/me/special.gfs", "/home/me/special.xsd"], + ) + self.assertEqual( + metadata.sidecarFilesForUri("/home/me/special.csv"), + ["/home/me/special.csvt"], + ) def testGeoJsonFieldOrder(self): """Test issue GH #45139""" d = QTemporaryDir() - json_path = os.path.join(d.path(), 'test.geojson') - with open(json_path, 'w+') as f: - f.write(""" + json_path = os.path.join(d.path(), "test.geojson") + with open(json_path, "w+") as f: + f.write( + """ { "type": "FeatureCollection", "features": [ @@ -2610,70 +3430,81 @@ def testGeoJsonFieldOrder(self): } ] } - """) + """ + ) - vl = QgsVectorLayer(json_path, 'json') + vl = QgsVectorLayer(json_path, "json") self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 2) - self.assertEqual(vl.fields().names(), ['A', 'B']) + self.assertEqual(vl.fields().names(), ["A", "B"]) # Append a field self.assertTrue(vl.startEditing()) - self.assertTrue(vl.addAttribute(QgsField('C', QVariant.String))) + self.assertTrue(vl.addAttribute(QgsField("C", QVariant.String))) for f in vl.getFeatures(): - vl.changeAttributeValue(f.id(), 2, 'C') + vl.changeAttributeValue(f.id(), 2, "C") - self.assertEqual(vl.fields().names(), ['A', 'B', 'C']) + self.assertEqual(vl.fields().names(), ["A", "B", "C"]) features = [f for f in vl.getFeatures()] - self.assertEqual(features[0].attribute('B'), NULL) - self.assertEqual(features[0].attribute('C'), 'C') - self.assertEqual(features[1].attribute('B'), 'B') - self.assertEqual(features[1].attribute('C'), 'C') + self.assertEqual(features[0].attribute("B"), NULL) + self.assertEqual(features[0].attribute("C"), "C") + self.assertEqual(features[1].attribute("B"), "B") + self.assertEqual(features[1].attribute("C"), "C") self.assertTrue(vl.commitChanges()) # This has been fixed in GDAL >= 3.4 - if int(gdal.VersionInfo('VERSION_NUM')) >= GDAL_COMPUTE_VERSION(3, 4, 0): - self.assertEqual(vl.fields().names(), ['A', 'B', 'C']) + if int(gdal.VersionInfo("VERSION_NUM")) >= GDAL_COMPUTE_VERSION(3, 4, 0): + self.assertEqual(vl.fields().names(), ["A", "B", "C"]) else: - self.assertEqual(vl.fields().names(), ['A', 'C', 'B']) + self.assertEqual(vl.fields().names(), ["A", "C", "B"]) features = [f for f in vl.getFeatures()] - self.assertEqual(features[0].attribute('B'), NULL) - self.assertEqual(features[0].attribute('C'), 'C') - self.assertEqual(features[1].attribute('B'), 'B') - self.assertEqual(features[1].attribute('C'), 'C') + self.assertEqual(features[0].attribute("B"), NULL) + self.assertEqual(features[0].attribute("C"), "C") + self.assertEqual(features[1].attribute("B"), "B") + self.assertEqual(features[1].attribute("C"), "C") def test_provider_feature_iterator_options(self): """Test issue GH #45534""" - datasource = os.path.join(self.basetestpath, 'testProviderFeatureIteratorOptions.csv') - with open(datasource, 'w') as f: - f.write('id,Longitude,Latitude\n') - f.write('1,1.0,1.0\n') - f.write('2,2.0,2.0\n') - - vl = QgsVectorLayer(f'{datasource}|option:X_POSSIBLE_NAMES=Longitude|option:Y_POSSIBLE_NAMES=Latitude', 'test', 'ogr') + datasource = os.path.join( + self.basetestpath, "testProviderFeatureIteratorOptions.csv" + ) + with open(datasource, "w") as f: + f.write("id,Longitude,Latitude\n") + f.write("1,1.0,1.0\n") + f.write("2,2.0,2.0\n") + + vl = QgsVectorLayer( + f"{datasource}|option:X_POSSIBLE_NAMES=Longitude|option:Y_POSSIBLE_NAMES=Latitude", + "test", + "ogr", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) f = vl.getFeature(1) - self.assertEqual(f.geometry().asWkt(), 'Point (1 1)') + self.assertEqual(f.geometry().asWkt(), "Point (1 1)") f = vl.getFeature(2) - self.assertEqual(f.geometry().asWkt(), 'Point (2 2)') + self.assertEqual(f.geometry().asWkt(), "Point (2 2)") def test_provider_dxf_3d(self): """Test issue GH #45938""" - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') - layers = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'points_lines_3d.dxf'), - Qgis.SublayerQueryFlag.ResolveGeometryType) + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") + layers = metadata.querySublayers( + os.path.join(TEST_DATA_DIR, "points_lines_3d.dxf"), + Qgis.SublayerQueryFlag.ResolveGeometryType, + ) - options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext()) + options = QgsProviderSublayerDetails.LayerOptions( + QgsCoordinateTransformContext() + ) for ld in layers: if ld.wkbType() == QgsWkbTypes.Type.PointZ: @@ -2686,41 +3517,51 @@ def test_provider_dxf_3d(self): feature = next(point_layer.getFeatures()) self.assertTrue(feature.isValid()) self.assertEqual(feature.geometry().wkbType(), QgsWkbTypes.Type.PointZ) - self.assertEqual(feature.geometry().asWkt(), - 'Point Z (635660.10747100005391985 1768912.79759799991734326 3.36980799999999991)') + self.assertEqual( + feature.geometry().asWkt(), + "Point Z (635660.10747100005391985 1768912.79759799991734326 3.36980799999999991)", + ) self.assertTrue(polyline_layer.isValid()) self.assertEqual(polyline_layer.featureCount(), 2) feature = next(polyline_layer.getFeatures()) self.assertTrue(feature.isValid()) self.assertEqual(feature.geometry().wkbType(), QgsWkbTypes.Type.LineStringZ) - self.assertEqual(feature.geometry().vertexAt(1).asWkt(), - 'Point Z (635660.11699699994642287 1768910.93880999996326864 3.33884099999999995)') + self.assertEqual( + feature.geometry().vertexAt(1).asWkt(), + "Point Z (635660.11699699994642287 1768910.93880999996326864 3.33884099999999995)", + ) def test_provider_connection_shp(self): """ Test creating connections for OGR provider """ - layer = QgsVectorLayer(TEST_DATA_DIR + '/' + 'lines.shp', 'lines') + layer = QgsVectorLayer(TEST_DATA_DIR + "/" + "lines.shp", "lines") - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") # start with a connection which only supports one layer - conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'lines.shp', {}) + conn = metadata.createConnection(TEST_DATA_DIR + "/" + "lines.shp", {}) self.assertTrue(conn) - self.assertEqual(conn.tableUri('unused', 'unused'), TEST_DATA_DIR + '/' + 'lines.shp') + self.assertEqual( + conn.tableUri("unused", "unused"), TEST_DATA_DIR + "/" + "lines.shp" + ) - table = conn.table('unused', 'unused') + table = conn.table("unused", "unused") # not set for single layer formats self.assertFalse(table.tableName()) self.assertFalse(table.primaryKeyColumns()) self.assertEqual(table.geometryColumnCount(), 1) self.assertEqual(len(table.geometryColumnTypes()), 1) self.assertEqual(table.geometryColumnTypes()[0].crs, layer.crs()) - self.assertEqual(table.geometryColumnTypes()[0].wkbType, QgsWkbTypes.Type.LineString) - self.assertEqual(table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Vector) + self.assertEqual( + table.geometryColumnTypes()[0].wkbType, QgsWkbTypes.Type.LineString + ) + self.assertEqual( + table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Vector + ) - tables = conn.tables('unused') + tables = conn.tables("unused") self.assertEqual(len(tables), 1) table = tables[0] self.assertFalse(table.tableName()) @@ -2728,100 +3569,161 @@ def test_provider_connection_shp(self): self.assertEqual(table.geometryColumnCount(), 1) self.assertEqual(len(table.geometryColumnTypes()), 1) self.assertEqual(table.geometryColumnTypes()[0].crs, layer.crs()) - self.assertEqual(table.geometryColumnTypes()[0].wkbType, QgsWkbTypes.Type.LineString) - self.assertEqual(table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Vector) + self.assertEqual( + table.geometryColumnTypes()[0].wkbType, QgsWkbTypes.Type.LineString + ) + self.assertEqual( + table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Vector + ) def test_provider_connection_gdb(self): """ Test creating connections for OGR provider """ - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") # start with a connection which only supports one layer - conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'field_alias.gdb', {}) + conn = metadata.createConnection(TEST_DATA_DIR + "/" + "field_alias.gdb", {}) self.assertTrue(conn) - self.assertEqual(conn.tableUri('unused', 'aliases'), TEST_DATA_DIR + '/' + 'field_alias.gdb|layername=aliases') + self.assertEqual( + conn.tableUri("unused", "aliases"), + TEST_DATA_DIR + "/" + "field_alias.gdb|layername=aliases", + ) with self.assertRaises(QgsProviderConnectionException): - conn.table('unused', 'notpresent') + conn.table("unused", "notpresent") - table = conn.table('unused', 'aliases') - self.assertEqual(table.tableName(), 'aliases') - self.assertEqual(table.primaryKeyColumns(), ['OBJECTID']) + table = conn.table("unused", "aliases") + self.assertEqual(table.tableName(), "aliases") + self.assertEqual(table.primaryKeyColumns(), ["OBJECTID"]) self.assertEqual(table.geometryColumnCount(), 1) self.assertEqual(len(table.geometryColumnTypes()), 1) - self.assertEqual(table.geometryColumnTypes()[0].wkbType, QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Vector) + self.assertEqual( + table.geometryColumnTypes()[0].wkbType, QgsWkbTypes.Type.MultiPolygon + ) + self.assertEqual( + table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Vector + ) # aspatial table - table = conn.table('unused', 'fras_aux_aliases') - self.assertEqual(table.tableName(), 'fras_aux_aliases') - self.assertEqual(table.primaryKeyColumns(), ['OBJECTID']) + table = conn.table("unused", "fras_aux_aliases") + self.assertEqual(table.tableName(), "fras_aux_aliases") + self.assertEqual(table.primaryKeyColumns(), ["OBJECTID"]) self.assertEqual(table.geometryColumnCount(), 0) self.assertFalse(table.geometryColumnTypes()) - self.assertEqual(table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial) + self.assertEqual( + table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial + ) # test tables - conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'featuredataset.gdb', {}) - tables = conn.tables('unused') + conn = metadata.createConnection(TEST_DATA_DIR + "/" + "featuredataset.gdb", {}) + tables = conn.tables("unused") self.assertGreaterEqual(len(tables), 4) - table = [t for t in tables if t.tableName() == 'fd1_lyr1'][0] - self.assertEqual(table.tableName(), 'fd1_lyr1') - self.assertEqual(table.primaryKeyColumns(), ['OBJECTID']) + table = [t for t in tables if t.tableName() == "fd1_lyr1"][0] + self.assertEqual(table.tableName(), "fd1_lyr1") + self.assertEqual(table.primaryKeyColumns(), ["OBJECTID"]) self.assertEqual(table.geometryColumnCount(), 1) self.assertEqual(len(table.geometryColumnTypes()), 1) self.assertEqual(table.geometryColumnTypes()[0].wkbType, QgsWkbTypes.Type.Point) - self.assertEqual(table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Vector) + self.assertEqual( + table.flags(), QgsAbstractDatabaseProviderConnection.TableFlag.Vector + ) def testCreateEmptyDatabase(self): - """ Test creating an empty database via the provider metadata """ - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') - self.assertTrue(metadata.capabilities() & QgsProviderMetadata.ProviderMetadataCapability.CreateDatabase) + """Test creating an empty database via the provider metadata""" + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") + self.assertTrue( + metadata.capabilities() + & QgsProviderMetadata.ProviderMetadataCapability.CreateDatabase + ) # empty path should error out - ok, err = metadata.createDatabase('') + ok, err = metadata.createDatabase("") self.assertFalse(ok) self.assertTrue(err) # invalid driver should error out - ok, err = metadata.createDatabase('aaa.xyz') + ok, err = metadata.createDatabase("aaa.xyz") self.assertFalse(ok) self.assertTrue(err) # non-database driver should error out - ok, err = metadata.createDatabase('aaa.tif') + ok, err = metadata.createDatabase("aaa.tif") self.assertFalse(ok) self.assertTrue(err) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 6, 0), "GDAL 3.6 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 6, 0), + "GDAL 3.6 required", + ) def testDiscoverRelationships(self): - table1 = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=table1') + table1 = QgsVectorLayer( + TEST_DATA_DIR + "/" + "relationships.gdb|layerName=table1" + ) self.assertTrue(table1.isValid()) - table2 = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=table2') + table2 = QgsVectorLayer( + TEST_DATA_DIR + "/" + "relationships.gdb|layerName=table2" + ) self.assertTrue(table2.isValid()) - table3 = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=table3') + table3 = QgsVectorLayer( + TEST_DATA_DIR + "/" + "relationships.gdb|layerName=table3" + ) self.assertTrue(table3.isValid()) - table4 = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=table4') + table4 = QgsVectorLayer( + TEST_DATA_DIR + "/" + "relationships.gdb|layerName=table4" + ) self.assertTrue(table4.isValid()) - table6 = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=table6') + table6 = QgsVectorLayer( + TEST_DATA_DIR + "/" + "relationships.gdb|layerName=table6" + ) self.assertTrue(table6.isValid()) - table7 = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=table7') + table7 = QgsVectorLayer( + TEST_DATA_DIR + "/" + "relationships.gdb|layerName=table7" + ) self.assertTrue(table7.isValid()) - table8 = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=table8') + table8 = QgsVectorLayer( + TEST_DATA_DIR + "/" + "relationships.gdb|layerName=table8" + ) self.assertTrue(table8.isValid()) - table9 = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=table9') + table9 = QgsVectorLayer( + TEST_DATA_DIR + "/" + "relationships.gdb|layerName=table9" + ) self.assertTrue(table9.isValid()) - composite_many_to_many = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=composite_many_to_many') + composite_many_to_many = QgsVectorLayer( + TEST_DATA_DIR + "/" + "relationships.gdb|layerName=composite_many_to_many" + ) self.assertTrue(composite_many_to_many.isValid()) - points = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=points') + points = QgsVectorLayer( + TEST_DATA_DIR + "/" + "relationships.gdb|layerName=points" + ) self.assertTrue(points.isValid()) - points__ATTACH = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=points__ATTACH') + points__ATTACH = QgsVectorLayer( + TEST_DATA_DIR + "/" + "relationships.gdb|layerName=points__ATTACH" + ) self.assertTrue(points__ATTACH.isValid()) - simple_attributed = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=simple_attributed') + simple_attributed = QgsVectorLayer( + TEST_DATA_DIR + "/" + "relationships.gdb|layerName=simple_attributed" + ) self.assertTrue(simple_attributed.isValid()) - simple_many_to_many = QgsVectorLayer(TEST_DATA_DIR + '/' + 'relationships.gdb|layerName=simple_many_to_many') + simple_many_to_many = QgsVectorLayer( + TEST_DATA_DIR + "/" + "relationships.gdb|layerName=simple_many_to_many" + ) self.assertTrue(simple_many_to_many.isValid()) - all_tables = [table1, table2, table3, table4, table6, table7, table8, table9, composite_many_to_many, points, points__ATTACH, simple_attributed, simple_many_to_many] + all_tables = [ + table1, + table2, + table3, + table4, + table6, + table7, + table8, + table9, + composite_many_to_many, + points, + points__ATTACH, + simple_attributed, + simple_many_to_many, + ] for table in all_tables: QgsProject.instance().addMapLayer(table) @@ -2830,249 +3732,404 @@ def testDiscoverRelationships(self): self.assertFalse(relations) relations = table1.dataProvider().discoverRelations(table1, all_tables) - self.assertCountEqual([r.id() for r in relations], ['composite_one_to_one', 'simple_many_to_many_forward', 'simple_many_to_many_backward', 'simple_one_to_many', 'simple_relationship_one_to_one']) - rel = [r for r in relations if r.name() == 'simple_relationship_one_to_one'][0] - self.assertEqual(rel.id(), 'simple_relationship_one_to_one') + self.assertCountEqual( + [r.id() for r in relations], + [ + "composite_one_to_one", + "simple_many_to_many_forward", + "simple_many_to_many_backward", + "simple_one_to_many", + "simple_relationship_one_to_one", + ], + ) + rel = [r for r in relations if r.name() == "simple_relationship_one_to_one"][0] + self.assertEqual(rel.id(), "simple_relationship_one_to_one") self.assertEqual(rel.referencedLayer(), table1) self.assertEqual(rel.referencingLayer(), table2) self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Association) - self.assertEqual(rel.fieldPairs(), {'parent_pk': 'pk'}) + self.assertEqual(rel.fieldPairs(), {"parent_pk": "pk"}) - rel = [r for r in relations if r.name() == 'simple_one_to_many'][0] - self.assertEqual(rel.id(), 'simple_one_to_many') + rel = [r for r in relations if r.name() == "simple_one_to_many"][0] + self.assertEqual(rel.id(), "simple_one_to_many") self.assertEqual(rel.referencedLayer(), table1) self.assertEqual(rel.referencingLayer(), table2) self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Association) - self.assertEqual(rel.fieldPairs(), {'parent_pk': 'pk'}) + self.assertEqual(rel.fieldPairs(), {"parent_pk": "pk"}) - rel = [r for r in relations if r.name() == 'composite_one_to_one'][0] - self.assertEqual(rel.id(), 'composite_one_to_one') + rel = [r for r in relations if r.name() == "composite_one_to_one"][0] + self.assertEqual(rel.id(), "composite_one_to_one") self.assertEqual(rel.referencedLayer(), table1) self.assertEqual(rel.referencingLayer(), table3) self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Composition) - self.assertEqual(rel.fieldPairs(), {'parent_pk': 'pk'}) + self.assertEqual(rel.fieldPairs(), {"parent_pk": "pk"}) - rel = [r for r in relations if r.id() == 'simple_many_to_many_forward'][0] - self.assertEqual(rel.name(), 'simple_many_to_many') - self.assertEqual(rel.id(), 'simple_many_to_many_forward') + rel = [r for r in relations if r.id() == "simple_many_to_many_forward"][0] + self.assertEqual(rel.name(), "simple_many_to_many") + self.assertEqual(rel.id(), "simple_many_to_many_forward") self.assertEqual(rel.referencedLayer(), table1) self.assertEqual(rel.referencingLayer(), simple_many_to_many) self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Association) - self.assertEqual(rel.fieldPairs(), {'origin_foreign_key': 'pk'}) + self.assertEqual(rel.fieldPairs(), {"origin_foreign_key": "pk"}) - rel = [r for r in relations if r.id() == 'simple_many_to_many_backward'][0] - self.assertEqual(rel.name(), 'simple_many_to_many') - self.assertEqual(rel.id(), 'simple_many_to_many_backward') + rel = [r for r in relations if r.id() == "simple_many_to_many_backward"][0] + self.assertEqual(rel.name(), "simple_many_to_many") + self.assertEqual(rel.id(), "simple_many_to_many_backward") self.assertEqual(rel.referencedLayer(), table2) self.assertEqual(rel.referencingLayer(), simple_many_to_many) self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Association) - self.assertEqual(rel.fieldPairs(), {'destination_foreign_key': 'parent_pk'}) + self.assertEqual(rel.fieldPairs(), {"destination_foreign_key": "parent_pk"}) relations = table6.dataProvider().discoverRelations(table6, all_tables) - self.assertCountEqual([r.id() for r in relations], - ['composite_many_to_many_forward', 'composite_many_to_many_backward']) - rel = [r for r in relations if r.id() == 'composite_many_to_many_forward'][0] - self.assertEqual(rel.id(), 'composite_many_to_many_forward') + self.assertCountEqual( + [r.id() for r in relations], + ["composite_many_to_many_forward", "composite_many_to_many_backward"], + ) + rel = [r for r in relations if r.id() == "composite_many_to_many_forward"][0] + self.assertEqual(rel.id(), "composite_many_to_many_forward") self.assertEqual(rel.referencedLayer(), table6) self.assertEqual(rel.referencingLayer(), composite_many_to_many) self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Composition) - self.assertEqual(rel.fieldPairs(), {'origin_foreign_key': 'pk'}) + self.assertEqual(rel.fieldPairs(), {"origin_foreign_key": "pk"}) - rel = [r for r in relations if r.id() == 'composite_many_to_many_backward'][0] - self.assertEqual(rel.id(), 'composite_many_to_many_backward') + rel = [r for r in relations if r.id() == "composite_many_to_many_backward"][0] + self.assertEqual(rel.id(), "composite_many_to_many_backward") self.assertEqual(rel.referencedLayer(), table7) self.assertEqual(rel.referencingLayer(), composite_many_to_many) self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Composition) - self.assertEqual(rel.fieldPairs(), {'dest_foreign_key': 'parent_pk'}) + self.assertEqual(rel.fieldPairs(), {"dest_foreign_key": "parent_pk"}) relations = table8.dataProvider().discoverRelations(table8, all_tables) - self.assertCountEqual([r.id() for r in relations], - ['simple_attributed', 'simple_backward_message_direction', 'simple_both_message_direction', 'simple_forward_message_direction']) - rel = [r for r in relations if r.id() == 'simple_attributed'][0] - self.assertEqual(rel.id(), 'simple_attributed') + self.assertCountEqual( + [r.id() for r in relations], + [ + "simple_attributed", + "simple_backward_message_direction", + "simple_both_message_direction", + "simple_forward_message_direction", + ], + ) + rel = [r for r in relations if r.id() == "simple_attributed"][0] + self.assertEqual(rel.id(), "simple_attributed") self.assertEqual(rel.referencedLayer(), table8) self.assertEqual(rel.referencingLayer(), table9) self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Association) - self.assertEqual(rel.fieldPairs(), {'parent_pk': 'pk'}) + self.assertEqual(rel.fieldPairs(), {"parent_pk": "pk"}) relations = points.dataProvider().discoverRelations(points, all_tables) - self.assertCountEqual([r.id() for r in relations], - ['points__ATTACHREL']) - rel = [r for r in relations if r.id() == 'points__ATTACHREL'][0] - self.assertEqual(rel.id(), 'points__ATTACHREL') + self.assertCountEqual([r.id() for r in relations], ["points__ATTACHREL"]) + rel = [r for r in relations if r.id() == "points__ATTACHREL"][0] + self.assertEqual(rel.id(), "points__ATTACHREL") self.assertEqual(rel.referencedLayer(), points) self.assertEqual(rel.referencingLayer(), points__ATTACH) self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Composition) - self.assertEqual(rel.fieldPairs(), {'REL_OBJECTID': 'OBJECTID'}) + self.assertEqual(rel.fieldPairs(), {"REL_OBJECTID": "OBJECTID"}) def test_provider_connection_tables(self): """ Test retrieving tables via the connections API """ - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") # start with a connection which only supports one layer - conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'relationships.gdb', {}) + conn = metadata.createConnection(TEST_DATA_DIR + "/" + "relationships.gdb", {}) self.assertTrue(conn) # don't want system tables included - self.assertCountEqual([t.tableName() for t in conn.tables()], - ['table1', 'table2', 'table3', 'table4', 'table6', 'table7', - 'table8', 'table9', 'points', 'points__ATTACH', - 'composite_many_to_many', 'simple_attributed', - 'simple_many_to_many']) + self.assertCountEqual( + [t.tableName() for t in conn.tables()], + [ + "table1", + "table2", + "table3", + "table4", + "table6", + "table7", + "table8", + "table9", + "points", + "points__ATTACH", + "composite_many_to_many", + "simple_attributed", + "simple_many_to_many", + ], + ) # DO want system tables included - self.assertCountEqual([t.tableName() for t in conn.tables('', - QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial | QgsAbstractDatabaseProviderConnection.TableFlag.Vector | QgsAbstractDatabaseProviderConnection.TableFlag.IncludeSystemTables)], - ['table1', 'table2', 'table3', 'table4', 'table6', 'table7', - 'table8', 'table9', 'points', 'points__ATTACH', - 'composite_many_to_many', 'simple_attributed', - 'simple_many_to_many', 'GDB_DBTune', 'GDB_ItemRelationshipTypes', - 'GDB_ItemRelationships', 'GDB_ItemTypes', 'GDB_Items', - 'GDB_SpatialRefs', 'GDB_SystemCatalog']) + self.assertCountEqual( + [ + t.tableName() + for t in conn.tables( + "", + QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial + | QgsAbstractDatabaseProviderConnection.TableFlag.Vector + | QgsAbstractDatabaseProviderConnection.TableFlag.IncludeSystemTables, + ) + ], + [ + "table1", + "table2", + "table3", + "table4", + "table6", + "table7", + "table8", + "table9", + "points", + "points__ATTACH", + "composite_many_to_many", + "simple_attributed", + "simple_many_to_many", + "GDB_DBTune", + "GDB_ItemRelationshipTypes", + "GDB_ItemRelationships", + "GDB_ItemTypes", + "GDB_Items", + "GDB_SpatialRefs", + "GDB_SystemCatalog", + ], + ) def test_provider_connection_illegal_fields(self): """ Test retrieving illegal field names via the connections API """ - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") # start with a connection which only supports one layer - conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'relationships.gdb', {}) + conn = metadata.createConnection(TEST_DATA_DIR + "/" + "relationships.gdb", {}) self.assertTrue(conn) - self.assertEqual(conn.illegalFieldNames(), - {'ALTER', 'NULL', 'UPDATE', 'LIKE', 'FROM', 'WHERE', 'INSERT', 'CREATE', - 'EXISTS', 'ORDER', 'DROP', 'TABLE', 'BETWEEN', 'SELECT', 'FOR', 'ADD', - 'IS', 'GROUP', 'COLUMN', 'DELETE', 'VALUES', 'IN', 'NOT', 'BY', 'OR', - 'INTO', 'AND', 'SET'}) + self.assertEqual( + conn.illegalFieldNames(), + { + "ALTER", + "NULL", + "UPDATE", + "LIKE", + "FROM", + "WHERE", + "INSERT", + "CREATE", + "EXISTS", + "ORDER", + "DROP", + "TABLE", + "BETWEEN", + "SELECT", + "FOR", + "ADD", + "IS", + "GROUP", + "COLUMN", + "DELETE", + "VALUES", + "IN", + "NOT", + "BY", + "OR", + "INTO", + "AND", + "SET", + }, + ) def test_provider_related_table_types(self): """ Test retrieving related table types """ - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") # GDB - conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'relationships.gdb', {}) - self.assertCountEqual(conn.relatedTableTypes(), ['media', 'features']) + conn = metadata.createConnection(TEST_DATA_DIR + "/" + "relationships.gdb", {}) + self.assertCountEqual(conn.relatedTableTypes(), ["media", "features"]) # GPKG - conn = metadata.createConnection(self.temp_dir_path + '/' + 'domains.gpkg', {}) - self.assertCountEqual(conn.relatedTableTypes(), ['media', 'features', 'simple_attributes', 'attributes', 'tiles']) + conn = metadata.createConnection(self.temp_dir_path + "/" + "domains.gpkg", {}) + self.assertCountEqual( + conn.relatedTableTypes(), + ["media", "features", "simple_attributes", "attributes", "tiles"], + ) # other (not supported) - conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'lines.shp', {}) + conn = metadata.createConnection(TEST_DATA_DIR + "/" + "lines.shp", {}) self.assertEqual(conn.relatedTableTypes(), []) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 6, 0), "GDAL 3.6 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 6, 0), + "GDAL 3.6 required", + ) def test_provider_relationship_capabilities(self): """ Test retrieving relationship capabilities """ - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") # GDB - conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'relationships.gdb', {}) - self.assertCountEqual(conn.supportedRelationshipCardinalities(), [Qgis.RelationshipCardinality.OneToMany, Qgis.RelationshipCardinality.ManyToMany, Qgis.RelationshipCardinality.OneToOne]) - self.assertCountEqual(conn.supportedRelationshipStrengths(), [Qgis.RelationshipStrength.Composition, Qgis.RelationshipStrength.Association]) - self.assertEqual(conn.supportedRelationshipCapabilities(), Qgis.RelationshipCapabilities(Qgis.RelationshipCapability.ForwardPathLabel | Qgis.RelationshipCapability.BackwardPathLabel)) + conn = metadata.createConnection(TEST_DATA_DIR + "/" + "relationships.gdb", {}) + self.assertCountEqual( + conn.supportedRelationshipCardinalities(), + [ + Qgis.RelationshipCardinality.OneToMany, + Qgis.RelationshipCardinality.ManyToMany, + Qgis.RelationshipCardinality.OneToOne, + ], + ) + self.assertCountEqual( + conn.supportedRelationshipStrengths(), + [ + Qgis.RelationshipStrength.Composition, + Qgis.RelationshipStrength.Association, + ], + ) + self.assertEqual( + conn.supportedRelationshipCapabilities(), + Qgis.RelationshipCapabilities( + Qgis.RelationshipCapability.ForwardPathLabel + | Qgis.RelationshipCapability.BackwardPathLabel + ), + ) # GPKG - conn = metadata.createConnection(self.temp_dir_path + '/' + 'domains.gpkg', {}) - self.assertCountEqual(conn.supportedRelationshipCardinalities(), [Qgis.RelationshipCardinality.ManyToMany]) - self.assertCountEqual(conn.supportedRelationshipStrengths(), [Qgis.RelationshipStrength.Association]) - self.assertEqual(conn.supportedRelationshipCapabilities(), Qgis.RelationshipCapabilities()) + conn = metadata.createConnection(self.temp_dir_path + "/" + "domains.gpkg", {}) + self.assertCountEqual( + conn.supportedRelationshipCardinalities(), + [Qgis.RelationshipCardinality.ManyToMany], + ) + self.assertCountEqual( + conn.supportedRelationshipStrengths(), + [Qgis.RelationshipStrength.Association], + ) + self.assertEqual( + conn.supportedRelationshipCapabilities(), Qgis.RelationshipCapabilities() + ) # other (not supported) - conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'lines.shp', {}) + conn = metadata.createConnection(TEST_DATA_DIR + "/" + "lines.shp", {}) self.assertCountEqual(conn.supportedRelationshipCardinalities(), []) self.assertCountEqual(conn.supportedRelationshipStrengths(), []) - self.assertEqual(conn.supportedRelationshipCapabilities(), Qgis.RelationshipCapabilities()) + self.assertEqual( + conn.supportedRelationshipCapabilities(), Qgis.RelationshipCapabilities() + ) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 6, 0), "GDAL 3.6 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 6, 0), + "GDAL 3.6 required", + ) def test_provider_connection_relationships(self): """ Test retrieving relationships via the connections API """ - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") # start with a connection which only supports one layer - conn = metadata.createConnection(TEST_DATA_DIR + '/' + 'relationships.gdb', {}) + conn = metadata.createConnection(TEST_DATA_DIR + "/" + "relationships.gdb", {}) self.assertTrue(conn) - self.assertTrue(conn.capabilities() & QgsAbstractDatabaseProviderConnection.Capability.RetrieveRelationships) + self.assertTrue( + conn.capabilities() + & QgsAbstractDatabaseProviderConnection.Capability.RetrieveRelationships + ) relationships = conn.relationships() - self.assertCountEqual([r.id() for r in relationships], - ['composite_many_to_many', - 'composite_one_to_many', - 'composite_one_to_one', - 'points__ATTACHREL', - 'simple_attributed', - 'simple_backward_message_direction', - 'simple_both_message_direction', - 'simple_forward_message_direction', - 'simple_many_to_many', - 'simple_one_to_many', - 'simple_relationship_one_to_one']) - - rel = [r for r in relationships if r.name() == 'simple_relationship_one_to_one'][0] - self.assertEqual(rel.id(), 'simple_relationship_one_to_one') - self.assertEqual(rel.referencedLayerSource(), TEST_DATA_DIR + '/' + 'relationships.gdb|layername=table1') - self.assertEqual(rel.referencedLayerName(), 'table1') - self.assertEqual(rel.referencedLayerProvider(), 'ogr') - self.assertEqual(rel.referencingLayerSource(), TEST_DATA_DIR + '/' + 'relationships.gdb|layername=table2') - self.assertEqual(rel.referencingLayerProvider(), 'ogr') - self.assertEqual(rel.referencingLayerName(), 'table2') + self.assertCountEqual( + [r.id() for r in relationships], + [ + "composite_many_to_many", + "composite_one_to_many", + "composite_one_to_one", + "points__ATTACHREL", + "simple_attributed", + "simple_backward_message_direction", + "simple_both_message_direction", + "simple_forward_message_direction", + "simple_many_to_many", + "simple_one_to_many", + "simple_relationship_one_to_one", + ], + ) + + rel = [ + r for r in relationships if r.name() == "simple_relationship_one_to_one" + ][0] + self.assertEqual(rel.id(), "simple_relationship_one_to_one") + self.assertEqual( + rel.referencedLayerSource(), + TEST_DATA_DIR + "/" + "relationships.gdb|layername=table1", + ) + self.assertEqual(rel.referencedLayerName(), "table1") + self.assertEqual(rel.referencedLayerProvider(), "ogr") + self.assertEqual( + rel.referencingLayerSource(), + TEST_DATA_DIR + "/" + "relationships.gdb|layername=table2", + ) + self.assertEqual(rel.referencingLayerProvider(), "ogr") + self.assertEqual(rel.referencingLayerName(), "table2") self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Association) - self.assertEqual(rel.referencingLayerFields(), ['parent_pk']) - self.assertEqual(rel.referencedLayerFields(), ['pk']) + self.assertEqual(rel.referencingLayerFields(), ["parent_pk"]) + self.assertEqual(rel.referencedLayerFields(), ["pk"]) self.assertEqual(rel.cardinality(), Qgis.RelationshipCardinality.OneToOne) - self.assertEqual(rel.forwardPathLabel(), 'my forward path label') - self.assertEqual(rel.backwardPathLabel(), 'my backward path label') + self.assertEqual(rel.forwardPathLabel(), "my forward path label") + self.assertEqual(rel.backwardPathLabel(), "my backward path label") # result depends on gdal version - self.assertIn(rel.relatedTableType(), ('feature', 'features')) - - rel = [r for r in relationships if r.id() == 'composite_many_to_many'][0] - self.assertEqual(rel.id(), 'composite_many_to_many') - self.assertEqual(rel.name(), 'composite_many_to_many') - self.assertEqual(rel.referencedLayerSource(), TEST_DATA_DIR + '/' + 'relationships.gdb|layername=table6') - self.assertEqual(rel.referencedLayerProvider(), 'ogr') - self.assertEqual(rel.referencedLayerName(), 'table6') - self.assertEqual(rel.referencingLayerSource(), TEST_DATA_DIR + '/' + 'relationships.gdb|layername=table7') - self.assertEqual(rel.referencingLayerProvider(), 'ogr') - self.assertEqual(rel.referencingLayerName(), 'table7') - self.assertEqual(rel.mappingTableSource(), TEST_DATA_DIR + '/' + 'relationships.gdb|layername=composite_many_to_many') - self.assertEqual(rel.mappingTableProvider(), 'ogr') - self.assertEqual(rel.mappingTableName(), 'composite_many_to_many') + self.assertIn(rel.relatedTableType(), ("feature", "features")) + + rel = [r for r in relationships if r.id() == "composite_many_to_many"][0] + self.assertEqual(rel.id(), "composite_many_to_many") + self.assertEqual(rel.name(), "composite_many_to_many") + self.assertEqual( + rel.referencedLayerSource(), + TEST_DATA_DIR + "/" + "relationships.gdb|layername=table6", + ) + self.assertEqual(rel.referencedLayerProvider(), "ogr") + self.assertEqual(rel.referencedLayerName(), "table6") + self.assertEqual( + rel.referencingLayerSource(), + TEST_DATA_DIR + "/" + "relationships.gdb|layername=table7", + ) + self.assertEqual(rel.referencingLayerProvider(), "ogr") + self.assertEqual(rel.referencingLayerName(), "table7") + self.assertEqual( + rel.mappingTableSource(), + TEST_DATA_DIR + "/" + "relationships.gdb|layername=composite_many_to_many", + ) + self.assertEqual(rel.mappingTableProvider(), "ogr") + self.assertEqual(rel.mappingTableName(), "composite_many_to_many") self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Composition) self.assertEqual(rel.cardinality(), Qgis.RelationshipCardinality.ManyToMany) - self.assertEqual(rel.referencingLayerFields(), ['parent_pk']) - self.assertEqual(rel.mappingReferencingLayerFields(), ['dest_foreign_key']) - self.assertEqual(rel.referencedLayerFields(), ['pk']) - self.assertEqual(rel.mappingReferencedLayerFields(), ['origin_foreign_key']) + self.assertEqual(rel.referencingLayerFields(), ["parent_pk"]) + self.assertEqual(rel.mappingReferencingLayerFields(), ["dest_foreign_key"]) + self.assertEqual(rel.referencedLayerFields(), ["pk"]) + self.assertEqual(rel.mappingReferencedLayerFields(), ["origin_foreign_key"]) # with table filter - relationships = conn.relationships('', 'table5') - self.assertCountEqual([r.id() for r in relationships], - ['composite_one_to_many']) - - rel = [r for r in relationships if r.name() == 'composite_one_to_many'][0] - self.assertEqual(rel.id(), 'composite_one_to_many') - self.assertEqual(rel.referencedLayerSource(), TEST_DATA_DIR + '/' + 'relationships.gdb|layername=table5') - self.assertEqual(rel.referencedLayerProvider(), 'ogr') - self.assertEqual(rel.referencingLayerSource(), TEST_DATA_DIR + '/' + 'relationships.gdb|layername=table4') - self.assertEqual(rel.referencingLayerProvider(), 'ogr') + relationships = conn.relationships("", "table5") + self.assertCountEqual( + [r.id() for r in relationships], ["composite_one_to_many"] + ) + + rel = [r for r in relationships if r.name() == "composite_one_to_many"][0] + self.assertEqual(rel.id(), "composite_one_to_many") + self.assertEqual( + rel.referencedLayerSource(), + TEST_DATA_DIR + "/" + "relationships.gdb|layername=table5", + ) + self.assertEqual(rel.referencedLayerProvider(), "ogr") + self.assertEqual( + rel.referencingLayerSource(), + TEST_DATA_DIR + "/" + "relationships.gdb|layername=table4", + ) + self.assertEqual(rel.referencingLayerProvider(), "ogr") self.assertEqual(rel.strength(), QgsRelation.RelationStrength.Composition) self.assertEqual(rel.cardinality(), Qgis.RelationshipCardinality.OneToMany) - self.assertEqual(rel.referencingLayerFields(), ['parent_pk']) - self.assertEqual(rel.referencedLayerFields(), ['pk']) + self.assertEqual(rel.referencingLayerFields(), ["parent_pk"]) + self.assertEqual(rel.referencedLayerFields(), ["pk"]) - relationships = conn.relationships('', 'table2') + relationships = conn.relationships("", "table2") self.assertFalse(relationships) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 6, 0), "GDAL 3.6 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 6, 0), + "GDAL 3.6 required", + ) def test_provider_connection_modify_relationship(self): """ Test creating relationship via the connections API """ - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") with tempfile.TemporaryDirectory() as temp_dir: - tmpfile = os.path.join(temp_dir, 'test_gdb.gdb') + tmpfile = os.path.join(temp_dir, "test_gdb.gdb") ok, err = metadata.createDatabase(tmpfile) self.assertTrue(ok) @@ -3081,75 +4138,103 @@ def test_provider_connection_modify_relationship(self): conn = metadata.createConnection(tmpfile, {}) self.assertTrue(conn) - conn.createVectorTable('', 'child', QgsFields(), QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:4326'), False, {}) - layer = QgsVectorLayer(tmpfile + '|layername=child') + conn.createVectorTable( + "", + "child", + QgsFields(), + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:4326"), + False, + {}, + ) + layer = QgsVectorLayer(tmpfile + "|layername=child") self.assertTrue(layer.isValid()) - conn.createVectorTable('', 'parent', QgsFields(), QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:4326'), False, {}) - layer = QgsVectorLayer(tmpfile + '|layername=parent') + conn.createVectorTable( + "", + "parent", + QgsFields(), + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:4326"), + False, + {}, + ) + layer = QgsVectorLayer(tmpfile + "|layername=parent") self.assertTrue(layer.isValid()) del layer self.assertTrue( - conn.capabilities() & QgsAbstractDatabaseProviderConnection.Capability.AddRelationship) + conn.capabilities() + & QgsAbstractDatabaseProviderConnection.Capability.AddRelationship + ) relationships = conn.relationships() self.assertFalse(relationships) - rel = QgsWeakRelation('id', - 'rel_name', - Qgis.RelationshipStrength.Association, - 'referencing_id', - 'referencing_name', - tmpfile + '|layername=child', - 'ogr', - 'referenced_id', - 'referenced_name', - tmpfile + '|layername=parent', - 'ogr' - ) - rel.setReferencedLayerFields(['fielda']) - rel.setReferencingLayerFields(['fieldb']) + rel = QgsWeakRelation( + "id", + "rel_name", + Qgis.RelationshipStrength.Association, + "referencing_id", + "referencing_name", + tmpfile + "|layername=child", + "ogr", + "referenced_id", + "referenced_name", + tmpfile + "|layername=parent", + "ogr", + ) + rel.setReferencedLayerFields(["fielda"]) + rel.setReferencingLayerFields(["fieldb"]) conn.addRelationship(rel) relationships = conn.relationships() self.assertEqual(len(relationships), 1) result = relationships[0] - self.assertEqual(result.name(), 'rel_name') - self.assertEqual(result.referencingLayerSource(), tmpfile + '|layername=child') - self.assertEqual(result.referencedLayerSource(), tmpfile + '|layername=parent') - self.assertEqual(result.referencingLayerFields(), ['fieldb']) - self.assertEqual(result.referencedLayerFields(), ['fielda']) + self.assertEqual(result.name(), "rel_name") + self.assertEqual( + result.referencingLayerSource(), tmpfile + "|layername=child" + ) + self.assertEqual( + result.referencedLayerSource(), tmpfile + "|layername=parent" + ) + self.assertEqual(result.referencingLayerFields(), ["fieldb"]) + self.assertEqual(result.referencedLayerFields(), ["fielda"]) # update relationship - rel.setReferencedLayerFields(['fieldc']) - rel.setReferencingLayerFields(['fieldd']) + rel.setReferencedLayerFields(["fieldc"]) + rel.setReferencingLayerFields(["fieldd"]) conn.updateRelationship(rel) relationships = conn.relationships() self.assertEqual(len(relationships), 1) result = relationships[0] - self.assertEqual(result.name(), 'rel_name') - self.assertEqual(result.referencingLayerSource(), tmpfile + '|layername=child') - self.assertEqual(result.referencedLayerSource(), tmpfile + '|layername=parent') - self.assertEqual(result.referencingLayerFields(), ['fieldd']) - self.assertEqual(result.referencedLayerFields(), ['fieldc']) + self.assertEqual(result.name(), "rel_name") + self.assertEqual( + result.referencingLayerSource(), tmpfile + "|layername=child" + ) + self.assertEqual( + result.referencedLayerSource(), tmpfile + "|layername=parent" + ) + self.assertEqual(result.referencingLayerFields(), ["fieldd"]) + self.assertEqual(result.referencedLayerFields(), ["fieldc"]) # try updating non-existing relationship - rel2 = QgsWeakRelation('id', - 'nope', - Qgis.RelationshipStrength.Association, - 'referencing_id', - 'referencing_name', - tmpfile + '|layername=child', - 'ogr', - 'referenced_id', - 'referenced_name', - tmpfile + '|layername=parent', - 'ogr' - ) + rel2 = QgsWeakRelation( + "id", + "nope", + Qgis.RelationshipStrength.Association, + "referencing_id", + "referencing_name", + tmpfile + "|layername=child", + "ogr", + "referenced_id", + "referenced_name", + tmpfile + "|layername=parent", + "ogr", + ) with self.assertRaises(QgsProviderConnectionException): conn.updateRelationship(rel2) @@ -3166,18 +4251,22 @@ def testUniqueGeometryType(self): Test accessing a layer of type wkbUnknown that contains a single geometry type but also null geometries """ - datasource = os.path.join(self.basetestpath, 'testUniqueGeometryType.csv') - with open(datasource, 'w') as f: - f.write('id,WKT\n') + datasource = os.path.join(self.basetestpath, "testUniqueGeometryType.csv") + with open(datasource, "w") as f: + f.write("id,WKT\n") f.write('1,"POINT(1 2)"\n') - f.write('2,\n') + f.write("2,\n") - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') - res = metadata.querySublayers(datasource, Qgis.SublayerQueryFlag.ResolveGeometryType) + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") + res = metadata.querySublayers( + datasource, Qgis.SublayerQueryFlag.ResolveGeometryType + ) self.assertEqual(len(res), 1) - self.assertEqual(res[0].uri(), datasource + "|geometrytype=Point|uniqueGeometryType=yes") + self.assertEqual( + res[0].uri(), datasource + "|geometrytype=Point|uniqueGeometryType=yes" + ) - vl = QgsVectorLayer(res[0].uri(), 'test', 'ogr') + vl = QgsVectorLayer(res[0].uri(), "test", "ogr") self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) self.assertEqual(vl.featureCount(), 2) @@ -3188,18 +4277,22 @@ def testUnknownButNoGeometry(self): Test accessing a layer of type wkbUnknown that contains only null geometries """ - datasource = os.path.join(self.basetestpath, 'testUnknownButNoGeometry.csv') - with open(datasource, 'w') as f: - f.write('id,WKT\n') + datasource = os.path.join(self.basetestpath, "testUnknownButNoGeometry.csv") + with open(datasource, "w") as f: + f.write("id,WKT\n") f.write('1,""\n') - f.write('2,\n') + f.write("2,\n") - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') - res = metadata.querySublayers(datasource, Qgis.SublayerQueryFlag.ResolveGeometryType) + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") + res = metadata.querySublayers( + datasource, Qgis.SublayerQueryFlag.ResolveGeometryType + ) self.assertEqual(len(res), 1) - self.assertEqual(res[0].uri(), datasource + "|geometrytype=None|uniqueGeometryType=yes") + self.assertEqual( + res[0].uri(), datasource + "|geometrytype=None|uniqueGeometryType=yes" + ) - vl = QgsVectorLayer(res[0].uri(), 'test', 'ogr') + vl = QgsVectorLayer(res[0].uri(), "test", "ogr") self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.NoGeometry) self.assertEqual(vl.featureCount(), 2) @@ -3210,44 +4303,50 @@ def testCsvInterleavedUpdate(self): temp_dir = QTemporaryDir() temp_path = temp_dir.path() - csv_path = os.path.join(temp_path, 'test.csv') - with open(csv_path, 'w+') as f: - f.write('fid\tname\n') + csv_path = os.path.join(temp_path, "test.csv") + with open(csv_path, "w+") as f: + f.write("fid\tname\n") f.write('1\t"feat 1"\n') f.write('2\t"feat 2"\n') f.write('3\t"feat 3"\n') - vl = QgsVectorLayer(csv_path, 'csv') + vl = QgsVectorLayer(csv_path, "csv") self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 3) f = next(vl.getFeatures()) - self.assertEqual(f.attributes(), ['1', "feat 1"]) + self.assertEqual(f.attributes(), ["1", "feat 1"]) self.assertTrue(vl.startEditing()) - self.assertTrue(vl.addAttribute(QgsField('newf', QVariant.String))) - self.assertTrue(vl.changeAttributeValues(3, {2: 'fid 3'})) - self.assertTrue(vl.changeAttributeValues(1, {2: 'fid 1'})) - self.assertTrue(vl.changeAttributeValues(2, {2: 'fid 2'})) + self.assertTrue(vl.addAttribute(QgsField("newf", QVariant.String))) + self.assertTrue(vl.changeAttributeValues(3, {2: "fid 3"})) + self.assertTrue(vl.changeAttributeValues(1, {2: "fid 1"})) + self.assertTrue(vl.changeAttributeValues(2, {2: "fid 2"})) self.assertTrue(vl.commitChanges()) - vl = QgsVectorLayer(csv_path, 'csv') + vl = QgsVectorLayer(csv_path, "csv") self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 3) features = {f.id(): f.attributes() for f in vl.getFeatures()} - self.assertEqual(features, { - 1: ['1', 'feat 1', 'fid 1'], - 2: ['2', 'feat 2', 'fid 2'], - 3: ['3', 'feat 3', 'fid 3'] - }) + self.assertEqual( + features, + { + 1: ["1", "feat 1", "fid 1"], + 2: ["2", "feat 2", "fid 2"], + 3: ["3", "feat 3", "fid 3"], + }, + ) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0), + "GDAL 3.7 required", + ) def test_provider_connection_set_field_alias(self): """ Test setting field alias via the connections api """ - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") with tempfile.TemporaryDirectory() as temp_dir: - tmpfile = os.path.join(temp_dir, 'test_gdb.gdb') + tmpfile = os.path.join(temp_dir, "test_gdb.gdb") ok, err = metadata.createDatabase(tmpfile) self.assertTrue(ok) @@ -3257,37 +4356,50 @@ def test_provider_connection_set_field_alias(self): self.assertTrue(conn) fields = QgsFields() - field = QgsField('my_field', QVariant.String) + field = QgsField("my_field", QVariant.String) fields.append(field) - conn.createVectorTable('', 'test', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:4326'), False, {}) - layer = QgsVectorLayer(tmpfile + '|layername=test') + conn.createVectorTable( + "", + "test", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:4326"), + False, + {}, + ) + layer = QgsVectorLayer(tmpfile + "|layername=test") self.assertTrue(layer.isValid()) del layer self.assertTrue( - conn.capabilities2() & Qgis.DatabaseProviderConnectionCapability2.SetFieldAlias) + conn.capabilities2() + & Qgis.DatabaseProviderConnectionCapability2.SetFieldAlias + ) # field does not exist with self.assertRaises(QgsProviderConnectionException): - conn.setFieldAlias('not field', '', 'test', 'my alias') + conn.setFieldAlias("not field", "", "test", "my alias") - conn.setFieldAlias('my_field', '', 'test', 'my alias') + conn.setFieldAlias("my_field", "", "test", "my alias") - layer = QgsVectorLayer(tmpfile + '|layername=test') + layer = QgsVectorLayer(tmpfile + "|layername=test") self.assertTrue(layer.isValid()) fields = layer.fields() - self.assertEqual(fields['my_field'].alias(), 'my alias') + self.assertEqual(fields["my_field"].alias(), "my alias") - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0), + "GDAL 3.7 required", + ) def test_provider_connection_set_field_comment(self): """ Test setting field comments via the connections api """ - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") with tempfile.TemporaryDirectory() as temp_dir: - tmpfile = os.path.join(temp_dir, 'test_gpkg.gpkg') + tmpfile = os.path.join(temp_dir, "test_gpkg.gpkg") ok, err = metadata.createDatabase(tmpfile) self.assertTrue(ok) @@ -3297,37 +4409,50 @@ def test_provider_connection_set_field_comment(self): self.assertTrue(conn) fields = QgsFields() - field = QgsField('my_field', QVariant.String) + field = QgsField("my_field", QVariant.String) fields.append(field) - conn.createVectorTable('', 'test', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:4326'), False, {}) - layer = QgsVectorLayer(tmpfile + '|layername=test') + conn.createVectorTable( + "", + "test", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:4326"), + False, + {}, + ) + layer = QgsVectorLayer(tmpfile + "|layername=test") self.assertTrue(layer.isValid()) del layer self.assertTrue( - conn.capabilities2() & Qgis.DatabaseProviderConnectionCapability2.SetFieldComment) + conn.capabilities2() + & Qgis.DatabaseProviderConnectionCapability2.SetFieldComment + ) # field does not exist with self.assertRaises(QgsProviderConnectionException): - conn.setFieldComment('not field', '', 'test', 'my comment') + conn.setFieldComment("not field", "", "test", "my comment") - conn.setFieldComment('my_field', '', 'test', 'my comment') + conn.setFieldComment("my_field", "", "test", "my comment") - layer = QgsVectorLayer(tmpfile + '|layername=test') + layer = QgsVectorLayer(tmpfile + "|layername=test") self.assertTrue(layer.isValid()) fields = layer.fields() - self.assertEqual(fields['my_field'].comment(), 'my comment') + self.assertEqual(fields["my_field"].comment(), "my comment") - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0), + "GDAL 3.7 required", + ) def test_provider_set_field_alias(self): """ Test setting field alias via the vector data provider api """ - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") with tempfile.TemporaryDirectory() as temp_dir: - tmpfile = os.path.join(temp_dir, 'test_gdb.gdb') + tmpfile = os.path.join(temp_dir, "test_gdb.gdb") ok, err = metadata.createDatabase(tmpfile) self.assertTrue(ok) @@ -3337,41 +4462,54 @@ def test_provider_set_field_alias(self): self.assertTrue(conn) fields = QgsFields() - field = QgsField('my_field', QVariant.String) - field.setAlias('my alias') + field = QgsField("my_field", QVariant.String) + field.setAlias("my alias") fields.append(field) - conn.createVectorTable('', 'test', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:4326'), False, {}) - layer = QgsVectorLayer(tmpfile + '|layername=test') + conn.createVectorTable( + "", + "test", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:4326"), + False, + {}, + ) + layer = QgsVectorLayer(tmpfile + "|layername=test") self.assertTrue(layer.isValid()) fields = layer.fields() - self.assertEqual(fields['my_field'].alias(), 'my alias') + self.assertEqual(fields["my_field"].alias(), "my alias") self.assertTrue( - layer.dataProvider().attributeEditCapabilities() & Qgis.VectorDataProviderAttributeEditCapability.EditAlias) + layer.dataProvider().attributeEditCapabilities() + & Qgis.VectorDataProviderAttributeEditCapability.EditAlias + ) - field2 = QgsField('my_field2', QVariant.String) - field2.setAlias('my alias2') + field2 = QgsField("my_field2", QVariant.String) + field2.setAlias("my alias2") self.assertTrue(layer.dataProvider().addAttributes([field2])) del layer - layer = QgsVectorLayer(tmpfile + '|layername=test') + layer = QgsVectorLayer(tmpfile + "|layername=test") self.assertTrue(layer.isValid()) fields = layer.fields() - self.assertEqual(fields['my_field'].alias(), 'my alias') - self.assertEqual(fields['my_field2'].alias(), 'my alias2') + self.assertEqual(fields["my_field"].alias(), "my alias") + self.assertEqual(fields["my_field2"].alias(), "my alias2") - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0), + "GDAL 3.7 required", + ) def test_provider_set_field_comment(self): """ Test setting field comments via the vector data provider api """ - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") with tempfile.TemporaryDirectory() as temp_dir: - tmpfile = os.path.join(temp_dir, 'test_gpkg.gpkg') + tmpfile = os.path.join(temp_dir, "test_gpkg.gpkg") ok, err = metadata.createDatabase(tmpfile) self.assertTrue(ok) @@ -3381,42 +4519,55 @@ def test_provider_set_field_comment(self): self.assertTrue(conn) fields = QgsFields() - field = QgsField('my_field', QVariant.String) - field.setComment('my comment') + field = QgsField("my_field", QVariant.String) + field.setComment("my comment") fields.append(field) - conn.createVectorTable('', 'test', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:4326'), False, {}) - layer = QgsVectorLayer(tmpfile + '|layername=test') + conn.createVectorTable( + "", + "test", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:4326"), + False, + {}, + ) + layer = QgsVectorLayer(tmpfile + "|layername=test") self.assertTrue(layer.isValid()) fields = layer.fields() - self.assertEqual(fields['my_field'].comment(), 'my comment') + self.assertEqual(fields["my_field"].comment(), "my comment") self.assertTrue( - layer.dataProvider().attributeEditCapabilities() & Qgis.VectorDataProviderAttributeEditCapability.EditComment) + layer.dataProvider().attributeEditCapabilities() + & Qgis.VectorDataProviderAttributeEditCapability.EditComment + ) - field2 = QgsField('my_field2', QVariant.String) - field2.setComment('my comment2') + field2 = QgsField("my_field2", QVariant.String) + field2.setComment("my comment2") self.assertTrue(layer.dataProvider().addAttributes([field2])) del layer - layer = QgsVectorLayer(tmpfile + '|layername=test') + layer = QgsVectorLayer(tmpfile + "|layername=test") self.assertTrue(layer.isValid()) fields = layer.fields() - self.assertEqual(fields['my_field'].comment(), 'my comment') - self.assertEqual(fields['my_field2'].comment(), 'my comment2') + self.assertEqual(fields["my_field"].comment(), "my comment") + self.assertEqual(fields["my_field2"].comment(), "my comment2") - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7.0 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0), + "GDAL 3.7.0 required", + ) def testFieldComment(self): """Test reading field comments""" with tempfile.TemporaryDirectory() as dest_dir: - database_path = os.path.join(dest_dir, 'new_gpkg.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(database_path) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('field1', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('field2', ogr.OFTString)) + database_path = os.path.join(dest_dir, "new_gpkg.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(database_path) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("field1", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("field2", ogr.OFTString)) ds.ExecuteSQL( """CREATE TABLE gpkg_data_columns ( @@ -3438,60 +4589,69 @@ def testFieldComment(self): ds = None - vl = QgsVectorLayer(f'{database_path}|layername=test', 'test') + vl = QgsVectorLayer(f"{database_path}|layername=test", "test") self.assertTrue(vl.isValid()) fields = vl.fields() - self.assertEqual(fields[0].name(), 'fid') + self.assertEqual(fields[0].name(), "fid") - self.assertEqual(fields[1].name(), 'field1') - self.assertEqual(fields[1].comment(), 'my description') + self.assertEqual(fields[1].name(), "field1") + self.assertEqual(fields[1].comment(), "my description") - self.assertEqual(fields[2].name(), 'field2') - self.assertEqual(fields[2].comment(), '') + self.assertEqual(fields[2].name(), "field2") + self.assertEqual(fields[2].comment(), "") - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0), + "GDAL 3.7 required", + ) def test_exporter_capabilities(self): with tempfile.TemporaryDirectory() as temp_dir: - dest_file_name = os.path.join(temp_dir, - 'test_gpkg.gpkg') + dest_file_name = os.path.join(temp_dir, "test_gpkg.gpkg") - layer = QgsVectorLayer("point?crs=epsg:4326&field=id:integer", - "Scratch point layer", "memory") + layer = QgsVectorLayer( + "point?crs=epsg:4326&field=id:integer", "Scratch point layer", "memory" + ) - exporter = QgsVectorLayerExporter(dest_file_name, - 'ogr', - layer.fields(), - layer.wkbType(), - layer.crs()) + exporter = QgsVectorLayerExporter( + dest_file_name, "ogr", layer.fields(), layer.wkbType(), layer.crs() + ) self.assertTrue( - exporter.attributeEditCapabilities() & Qgis.VectorDataProviderAttributeEditCapability.EditAlias) + exporter.attributeEditCapabilities() + & Qgis.VectorDataProviderAttributeEditCapability.EditAlias + ) self.assertTrue( - exporter.attributeEditCapabilities() & Qgis.VectorDataProviderAttributeEditCapability.EditComment) + exporter.attributeEditCapabilities() + & Qgis.VectorDataProviderAttributeEditCapability.EditComment + ) - dest_file_name = os.path.join(temp_dir, - 'test_shp.shp') + dest_file_name = os.path.join(temp_dir, "test_shp.shp") - exporter = QgsVectorLayerExporter(dest_file_name, - 'ogr', - layer.fields(), - layer.wkbType(), - layer.crs()) + exporter = QgsVectorLayerExporter( + dest_file_name, "ogr", layer.fields(), layer.wkbType(), layer.crs() + ) self.assertFalse( - exporter.attributeEditCapabilities() & Qgis.VectorDataProviderAttributeEditCapability.EditAlias) + exporter.attributeEditCapabilities() + & Qgis.VectorDataProviderAttributeEditCapability.EditAlias + ) self.assertFalse( - exporter.attributeEditCapabilities() & Qgis.VectorDataProviderAttributeEditCapability.EditComment) + exporter.attributeEditCapabilities() + & Qgis.VectorDataProviderAttributeEditCapability.EditComment + ) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0), + "GDAL 3.7 required", + ) def testGeoJsonMapType(self): """Test issue GH #54966: Geojson and maps attribute not working""" temp_dir = QTemporaryDir() temp_path = temp_dir.path() - json_path = os.path.join(temp_path, 'test.json') + json_path = os.path.join(temp_path, "test.json") data = """ { @@ -3512,10 +4672,10 @@ def testGeoJsonMapType(self): ] }""" - with open(json_path, 'w+') as f: + with open(json_path, "w+") as f: f.write(data) - vl = QgsVectorLayer(json_path, 'vl') + vl = QgsVectorLayer(json_path, "vl") self.assertTrue(vl.isValid()) self.assertEqual(vl.fields()[0].type(), QVariant.Map) self.assertEqual(vl.fields()[1].type(), QVariant.List) @@ -3525,61 +4685,74 @@ def testGeoJsonMapType(self): self.assertEqual(fid, 0) self.assertEqual(f.attributes()[1], [1, 2]) - self.assertTrue(vl.dataProvider().changeAttributeValues({fid: {0: {"style": {"color": "green"}}}})) - vl = QgsVectorLayer(json_path, 'vl') + self.assertTrue( + vl.dataProvider().changeAttributeValues( + {fid: {0: {"style": {"color": "green"}}}} + ) + ) + vl = QgsVectorLayer(json_path, "vl") self.assertTrue(vl.isValid()) self.assertEqual(vl.fields()[0].type(), QVariant.Map) f = next(vl.getFeatures()) - self.assertEqual(f.attributes()[0], {'style': {'color': 'green'}}) + self.assertEqual(f.attributes()[0], {"style": {"color": "green"}}) f = QgsFeature(vl.fields()) - f.setGeometry(QgsGeometry.fromWkt('POINT(15 40)')) - f.setAttribute(0, {'style': {'color': 'yellow'}}) + f.setGeometry(QgsGeometry.fromWkt("POINT(15 40)")) + f.setAttribute(0, {"style": {"color": "yellow"}}) self.assertTrue(vl.dataProvider().addFeatures([f])) - vl = QgsVectorLayer(json_path, 'vl') + vl = QgsVectorLayer(json_path, "vl") self.assertTrue(vl.isValid()) self.assertEqual(vl.fields()[0].type(), QVariant.Map) f = vl.getFeature(1) - self.assertEqual(f.attributes()[0], {'style': {'color': 'yellow'}}) + self.assertEqual(f.attributes()[0], {"style": {"color": "yellow"}}) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 8, 0), "GDAL 3.8 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 8, 0), + "GDAL 3.8 required", + ) def testDataCommentFileGeodatabase(self): with tempfile.TemporaryDirectory() as temp_dir: - dest_file_name = os.path.join(temp_dir, 'testDataCommentFileGeodatabase.gdb') + dest_file_name = os.path.join( + temp_dir, "testDataCommentFileGeodatabase.gdb" + ) ds = ogr.GetDriverByName("OpenFileGDB").CreateDataSource(dest_file_name) - ds.CreateLayer("test", geom_type=ogr.wkbPoint, options=["LAYER_ALIAS=my_alias"]) + ds.CreateLayer( + "test", geom_type=ogr.wkbPoint, options=["LAYER_ALIAS=my_alias"] + ) ds = None - vl = QgsVectorLayer(dest_file_name, 'vl') + vl = QgsVectorLayer(dest_file_name, "vl") self.assertEqual(vl.dataComment(), "my_alias") def testExtentCsv(self): # 2D points - datasource_2d = os.path.join(self.basetestpath, 'testExtent2D.csv') - with open(datasource_2d, 'w') as f: - f.write('id,WKT\n') + datasource_2d = os.path.join(self.basetestpath, "testExtent2D.csv") + with open(datasource_2d, "w") as f: + f.write("id,WKT\n") for i in range(9): - f.write(f'{i},POINT ({2 * i} {i - 3})\n') + f.write(f"{i},POINT ({2 * i} {i - 3})\n") - vl = QgsVectorLayer(f'{datasource_2d}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource_2d}|layerid=0", "test", "ogr") self.assertTrue(vl.isValid()) self.assertTrue(vl.featureCount(), 9) self.assertEqual(vl.extent(), QgsRectangle(0, -3, 16, 5)) - self.assertEqual(vl.extent3D(), QgsBox3D(0, -3, float('nan'), 16, 5, float('nan'))) + self.assertEqual( + vl.extent3D(), QgsBox3D(0, -3, float("nan"), 16, 5, float("nan")) + ) del vl os.unlink(datasource_2d) self.assertFalse(os.path.exists(datasource_2d)) # 3D points - datasource_3d = os.path.join(self.basetestpath, 'testExtent3D.csv') - with open(datasource_3d, 'w') as f: - f.write('id,WKT\n') + datasource_3d = os.path.join(self.basetestpath, "testExtent3D.csv") + with open(datasource_3d, "w") as f: + f.write("id,WKT\n") for i in range(13): - f.write(f'{i},POINT Z({2 * i} {i - 3} {i - 5})\n') + f.write(f"{i},POINT Z({2 * i} {i - 3} {i - 5})\n") - vl = QgsVectorLayer(f'{datasource_3d}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource_3d}|layerid=0", "test", "ogr") self.assertTrue(vl.isValid()) self.assertTrue(vl.featureCount(), 12) self.assertEqual(vl.extent(), QgsRectangle(0, -3, 24, 9)) @@ -3591,7 +4764,9 @@ def testExtentCsv(self): def testExtentShp(self): # 2D points - vl = QgsVectorLayer(os.path.join(unitTestDataPath(), 'points.shp'), 'points', 'ogr') + vl = QgsVectorLayer( + os.path.join(unitTestDataPath(), "points.shp"), "points", "ogr" + ) self.assertTrue(vl.isValid()) self.assertTrue(vl.featureCount(), 9) self.assertAlmostEqual(vl.extent().xMinimum(), -118.8888, places=3) @@ -3608,7 +4783,9 @@ def testExtentShp(self): del vl # 3D points - vl = QgsVectorLayer(os.path.join(unitTestDataPath(), '3d', 'points_with_z.shp'), 'points', 'ogr') + vl = QgsVectorLayer( + os.path.join(unitTestDataPath(), "3d", "points_with_z.shp"), "points", "ogr" + ) self.assertTrue(vl.isValid()) self.assertTrue(vl.featureCount(), 9) self.assertAlmostEqual(vl.extent().xMinimum(), 321384.94, places=3) @@ -3624,25 +4801,43 @@ def testExtentShp(self): self.assertAlmostEqual(vl.extent3D().zMaximum(), 105.6, places=3) del vl - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 6, 0), "GDAL 3.6 required") - @unittest.skipIf(gdal.GetDriverByName("OpenFileGDB") is None, "GDAL OpenFileGDB driver required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 6, 0), + "GDAL 3.6 required", + ) + @unittest.skipIf( + gdal.GetDriverByName("OpenFileGDB") is None, "GDAL OpenFileGDB driver required" + ) def testReadOnlyFieldsFileGeodatabase(self): with tempfile.TemporaryDirectory() as temp_dir: - dest_file_name = os.path.join(temp_dir, 'testReadOnlyFieldsFileGeodatabase.gdb') + dest_file_name = os.path.join( + temp_dir, "testReadOnlyFieldsFileGeodatabase.gdb" + ) ds = ogr.GetDriverByName("OpenFileGDB").CreateDataSource(dest_file_name) - ds.CreateLayer("test", geom_type=ogr.wkbPolygon, options=["CREATE_SHAPE_AREA_AND_LENGTH_FIELDS=YES"]) + ds.CreateLayer( + "test", + geom_type=ogr.wkbPolygon, + options=["CREATE_SHAPE_AREA_AND_LENGTH_FIELDS=YES"], + ) ds = None - vl = QgsVectorLayer(dest_file_name, 'vl') + vl = QgsVectorLayer(dest_file_name, "vl") self.assertTrue(vl.fields()["Shape_Area"].isReadOnly()) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 6, 0), "GDAL 3.6 required") - @unittest.skipIf(gdal.GetDriverByName("OpenFileGDB") is None, "GDAL OpenFileGDB driver required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 6, 0), + "GDAL 3.6 required", + ) + @unittest.skipIf( + gdal.GetDriverByName("OpenFileGDB") is None, "GDAL OpenFileGDB driver required" + ) def testDeleteFieldFileGeodatabase(self): with tempfile.TemporaryDirectory() as temp_dir: - dest_file_name = os.path.join(temp_dir, 'testDeleteFieldFileGeodatabase.gdb') + dest_file_name = os.path.join( + temp_dir, "testDeleteFieldFileGeodatabase.gdb" + ) ds = ogr.GetDriverByName("OpenFileGDB").CreateDataSource(dest_file_name) lyr = ds.CreateLayer("test", geom_type=ogr.wkbNone) lyr.CreateField(ogr.FieldDefn("fld1")) @@ -3657,19 +4852,16 @@ def testDeleteFieldFileGeodatabase(self): lyr.CreateFeature(f) ds = None - vl = QgsVectorLayer(dest_file_name, 'vl') + vl = QgsVectorLayer(dest_file_name, "vl") self.assertTrue(vl.startEditing()) self.assertTrue(vl.deleteAttribute(1)) # delete field fld1 self.assertTrue(vl.commitChanges()) # Re-open a connection without explicitly closing the one we've edited - vl2 = QgsVectorLayer(dest_file_name, 'vl2') + vl2 = QgsVectorLayer(dest_file_name, "vl2") features = {f.id(): f.attributes() for f in vl2.getFeatures()} - self.assertEqual(features, { - 1: [1, 'b'], - 2: [2, 'd'] - }) + self.assertEqual(features, {1: [1, "b"], 2: [2, "d"]}) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_provider_ogr_gpkg.py b/tests/src/python/test_provider_ogr_gpkg.py index 88c9268ac310..a012ba1d2a6a 100644 --- a/tests/src/python/test_provider_ogr_gpkg.py +++ b/tests/src/python/test_provider_ogr_gpkg.py @@ -8,9 +8,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Even Rouault' -__date__ = '2016-04-21' -__copyright__ = 'Copyright 2016, Even Rouault' + +__author__ = "Even Rouault" +__date__ = "2016-04-21" +__copyright__ = "Copyright 2016, Even Rouault" import os import re @@ -70,7 +71,8 @@ def GDAL_COMPUTE_VERSION(maj, min, rev): - return ((maj) * 1000000 + (min) * 10000 + (rev) * 100) + return (maj) * 1000000 + (min) * 10000 + (rev) * 100 + ######################################################################### # Standard conformance tests for a provider @@ -82,23 +84,22 @@ class TestPyQgsOGRProviderGpkgConformance(QgisTestCase, ProviderTestCase): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsOGRProviderGpkgConformance, cls).setUpClass() + super().setUpClass() # Create test layer cls.basetestpath = tempfile.mkdtemp() cls.repackfilepath = tempfile.mkdtemp() - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - shutil.copy(os.path.join(srcpath, 'geopackage.gpkg'), cls.basetestpath) - shutil.copy(os.path.join(srcpath, 'geopackage_poly.gpkg'), - cls.basetestpath) - cls.basetestfile = os.path.join(cls.basetestpath, 'geopackage.gpkg') - cls.basetestpolyfile = os.path.join( - cls.basetestpath, 'geopackage_poly.gpkg') + srcpath = os.path.join(TEST_DATA_DIR, "provider") + shutil.copy(os.path.join(srcpath, "geopackage.gpkg"), cls.basetestpath) + shutil.copy(os.path.join(srcpath, "geopackage_poly.gpkg"), cls.basetestpath) + cls.basetestfile = os.path.join(cls.basetestpath, "geopackage.gpkg") + cls.basetestpolyfile = os.path.join(cls.basetestpath, "geopackage_poly.gpkg") cls.vl = QgsVectorLayer( - cls.basetestfile + '|layername=geopackage', 'test', 'ogr') + cls.basetestfile + "|layername=geopackage", "test", "ogr" + ) assert cls.vl.isValid() cls.source = cls.vl.dataProvider() - cls.vl_poly = QgsVectorLayer(cls.basetestpolyfile, 'test', 'ogr') + cls.vl_poly = QgsVectorLayer(cls.basetestpolyfile, "test", "ogr") assert cls.vl_poly.isValid() cls.poly_provider = cls.vl_poly.dataProvider() @@ -106,12 +107,16 @@ def setUpClass(cls): # Create the other layer for constraints check cls.check_constraint = QgsVectorLayer( - cls.basetestfile + '|layername=check_constraint', 'check_constraint', 'ogr') + cls.basetestfile + "|layername=check_constraint", "check_constraint", "ogr" + ) cls.check_constraint_editing_started = False # Create the other layer for unique and not null constraints check cls.unique_not_null_constraints = QgsVectorLayer( - cls.basetestfile + '|layername=unique_not_null_constraints', 'unique_not_null_constraints', 'ogr') + cls.basetestfile + "|layername=unique_not_null_constraints", + "unique_not_null_constraints", + "ogr", + ) assert cls.unique_not_null_constraints.isValid() @classmethod @@ -123,16 +128,16 @@ def tearDownClass(cls): del cls.unique_not_null_constraints for dirname in cls.dirs_to_cleanup: shutil.rmtree(dirname, True) - super(TestPyQgsOGRProviderGpkgConformance, cls).tearDownClass() + super().tearDownClass() def getSource(self): tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - shutil.copy(os.path.join(srcpath, 'geopackage.gpkg'), tmpdir) - datasource = os.path.join(tmpdir, 'geopackage.gpkg') + srcpath = os.path.join(TEST_DATA_DIR, "provider") + shutil.copy(os.path.join(srcpath, "geopackage.gpkg"), tmpdir) + datasource = os.path.join(tmpdir, "geopackage.gpkg") - vl = QgsVectorLayer(datasource, 'test', 'ogr') + vl = QgsVectorLayer(datasource, "test", "ogr") return vl @@ -155,11 +160,11 @@ def getEditableLayerWithUniqueNotNullConstraints(self): return self.unique_not_null_constraints def enableCompiler(self): - QgsSettings().setValue('/qgis/compileExpressions', True) + QgsSettings().setValue("/qgis/compileExpressions", True) return True def disableCompiler(self): - QgsSettings().setValue('/qgis/compileExpressions', False) + QgsSettings().setValue("/qgis/compileExpressions", False) def treat_time_as_string(self): return True @@ -168,69 +173,71 @@ def treat_datetime_tz_as_utc(self): return True def uncompiledFilters(self): - return {'cnt = 10 ^ 2', - '"name" ~ \'[OP]ra[gne]+\'', - 'sqrt(pk) >= 2', - 'radians(cnt) < 2', - 'degrees(pk) <= 200', - 'cos(pk) < 0', - 'sin(pk) < 0', - 'tan(pk) < 0', - 'acos(-1) < pk', - 'asin(1) < pk', - 'atan(3.14) < pk', - 'atan2(3.14, pk) < 1', - 'exp(pk) < 10', - 'ln(pk) <= 1', - 'log(3, pk) <= 1', - 'log10(pk) < 0.5', - 'floor(3.14) <= pk', - 'ceil(3.14) <= pk', - 'pk < pi()', - 'floor(cnt / 66.67) <= 2', - 'ceil(cnt / 66.67) <= 2', - 'pk < pi() / 2', - 'x($geometry) < -70', - 'y($geometry) > 70', - 'xmin($geometry) < -70', - 'ymin($geometry) > 70', - 'xmax($geometry) < -70', - 'ymax($geometry) > 70', - 'disjoint($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', - 'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', - 'contains(geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'),$geometry)', - 'distance($geometry,geom_from_wkt( \'Point (-70 70)\')) > 7', - 'intersects($geometry,geom_from_gml( \'-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1\'))', - 'x($geometry) < -70', - 'y($geometry) > 79', - 'xmin($geometry) < -70', - 'ymin($geometry) < 76', - 'xmax($geometry) > -68', - 'ymax($geometry) > 80', - 'area($geometry) > 10', - 'perimeter($geometry) < 12', - 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\')) = \'FF2FF1212\'', - 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'), \'****F****\')', - 'crosses($geometry,geom_from_wkt( \'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)\'))', - 'overlaps($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'))', - 'within($geometry,geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - 'overlaps(translate($geometry,-1,-1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - 'overlaps(buffer($geometry,1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - 'intersects(centroid($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', - 'intersects(point_on_surface($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', - '"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')', - 'to_time("time") >= make_time(12, 14, 14)', - 'to_time("time") = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')', - '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')' - } + return { + "cnt = 10 ^ 2", + "\"name\" ~ '[OP]ra[gne]+'", + "sqrt(pk) >= 2", + "radians(cnt) < 2", + "degrees(pk) <= 200", + "cos(pk) < 0", + "sin(pk) < 0", + "tan(pk) < 0", + "acos(-1) < pk", + "asin(1) < pk", + "atan(3.14) < pk", + "atan2(3.14, pk) < 1", + "exp(pk) < 10", + "ln(pk) <= 1", + "log(3, pk) <= 1", + "log10(pk) < 0.5", + "floor(3.14) <= pk", + "ceil(3.14) <= pk", + "pk < pi()", + "floor(cnt / 66.67) <= 2", + "ceil(cnt / 66.67) <= 2", + "pk < pi() / 2", + "x($geometry) < -70", + "y($geometry) > 70", + "xmin($geometry) < -70", + "ymin($geometry) > 70", + "xmax($geometry) < -70", + "ymax($geometry) > 70", + "disjoint($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))", + "intersects($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))", + "contains(geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'),$geometry)", + "distance($geometry,geom_from_wkt( 'Point (-70 70)')) > 7", + "intersects($geometry,geom_from_gml( '-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1'))", + "x($geometry) < -70", + "y($geometry) > 79", + "xmin($geometry) < -70", + "ymin($geometry) < 76", + "xmax($geometry) > -68", + "ymax($geometry) > 80", + "area($geometry) > 10", + "perimeter($geometry) < 12", + "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))')) = 'FF2FF1212'", + "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'), '****F****')", + "crosses($geometry,geom_from_wkt( 'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)'))", + "overlaps($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'))", + "within($geometry,geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + "overlaps(translate($geometry,-1,-1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + "overlaps(buffer($geometry,1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + "intersects(centroid($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))", + "intersects(point_on_surface($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))", + "\"dt\" = to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy')", + 'to_time("time") >= make_time(12, 14, 14)', + "to_time(\"time\") = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')", + "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')", + } def partiallyCompiledFilters(self): - return {'"name" NOT LIKE \'Ap%\'', - 'name LIKE \'Apple\'', - 'name LIKE \'aPple\'', - 'name LIKE \'Ap_le\'', - 'name LIKE \'Ap\\_le\'' - } + return { + "\"name\" NOT LIKE 'Ap%'", + "name LIKE 'Apple'", + "name LIKE 'aPple'", + "name LIKE 'Ap_le'", + "name LIKE 'Ap\\_le'", + } def testOrderByCompiled(self): self.runOrderByTests() @@ -239,24 +246,28 @@ def testOrderByCompiled(self): # Geopackage # Test orderBy + filter expression - request = QgsFeatureRequest().setFilterExpression('"cnt">=200').addOrderBy('num_char') - values = [f['pk'] for f in self.source.getFeatures(request)] + request = ( + QgsFeatureRequest().setFilterExpression('"cnt">=200').addOrderBy("num_char") + ) + values = [f["pk"] for f in self.source.getFeatures(request)] self.assertEqual(values, [2, 3, 4]) values = [f.geometry().asWkt() for f in self.source.getFeatures(request)] # Check that we get geometries assert compareWkt(values[0], "Point (-68.2 70.8)"), values[0] # Test orderBy + subset string - request = QgsFeatureRequest().addOrderBy('num_char') + request = QgsFeatureRequest().addOrderBy("num_char") self.source.setSubsetString("cnt >= 200") - values = [f['pk'] for f in self.source.getFeatures(request)] + values = [f["pk"] for f in self.source.getFeatures(request)] self.source.setSubsetString(None) self.assertEqual(values, [2, 3, 4]) # Test orderBy + subset string + filter expression - request = QgsFeatureRequest().setFilterExpression('"cnt"<=300').addOrderBy('num_char') + request = ( + QgsFeatureRequest().setFilterExpression('"cnt"<=300').addOrderBy("num_char") + ) self.source.setSubsetString("cnt >= 200") - values = [f['pk'] for f in self.source.getFeatures(request)] + values = [f["pk"] for f in self.source.getFeatures(request)] self.source.setSubsetString(None) self.assertEqual(values, [2, 3]) @@ -266,28 +277,28 @@ def testOrderByCompiled(self): # to analyze the SQL SELECT, but QGIS could probably add the JOIN with # the RTree) extent = QgsRectangle(-70, 67, -60, 80) - request = QgsFeatureRequest().setFilterRect(extent).addOrderBy('num_char') - values = [f['pk'] for f in self.source.getFeatures(request)] + request = QgsFeatureRequest().setFilterRect(extent).addOrderBy("num_char") + values = [f["pk"] for f in self.source.getFeatures(request)] self.assertEqual(values, [2, 4]) # Test orderBy + subset string which is a SELECT # (excluded by the optimization) # For some weird reason, we need to re-open a new connection to the # dataset (this weird behavior predates the optimization) - request = QgsFeatureRequest().addOrderBy('num_char') + request = QgsFeatureRequest().addOrderBy("num_char") tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - shutil.copy(os.path.join(srcpath, 'geopackage.gpkg'), tmpdir) - datasource = os.path.join(tmpdir, 'geopackage.gpkg') - vl = QgsVectorLayer(datasource, 'test', 'ogr') - vl.setSubsetString("SELECT * FROM \"geopackage\" WHERE cnt >= 200") - values = [f['pk'] for f in vl.getFeatures(request)] + srcpath = os.path.join(TEST_DATA_DIR, "provider") + shutil.copy(os.path.join(srcpath, "geopackage.gpkg"), tmpdir) + datasource = os.path.join(tmpdir, "geopackage.gpkg") + vl = QgsVectorLayer(datasource, "test", "ogr") + vl.setSubsetString('SELECT * FROM "geopackage" WHERE cnt >= 200') + values = [f["pk"] for f in vl.getFeatures(request)] self.assertEqual(values, [2, 3, 4]) del vl -class ErrorReceiver(): +class ErrorReceiver: def __init__(self): self.msg = None @@ -298,18 +309,19 @@ def receiveError(self, msg): def count_opened_filedescriptors(filename_to_test): count = -1 - if sys.platform.startswith('linux'): + if sys.platform.startswith("linux"): count = 0 - open_files_dirname = '/proc/%d/fd' % os.getpid() + open_files_dirname = "/proc/%d/fd" % os.getpid() filenames = os.listdir(open_files_dirname) for filename in filenames: - full_filename = open_files_dirname + '/' + filename + full_filename = open_files_dirname + "/" + filename if os.path.exists(full_filename): link = os.readlink(full_filename) if os.path.basename(link) == os.path.basename(filename_to_test): count += 1 return count + # ######################################################################### # # Other tests specific to GPKG handling in OGR provider # ######################################################################### @@ -341,116 +353,130 @@ def tearDownClass(cls): def testDecodeUri(self): - filename = '/home/to/path/my_file.gpkg' + filename = "/home/to/path/my_file.gpkg" registry = QgsProviderRegistry.instance() uri = filename - components = registry.decodeUri('ogr', uri) + components = registry.decodeUri("ogr", uri) self.assertEqual(components["path"], filename) - uri = f'{filename}|layername=test' - components = registry.decodeUri('ogr', uri) + uri = f"{filename}|layername=test" + components = registry.decodeUri("ogr", uri) self.assertEqual(components["path"], filename) - self.assertEqual(components["layerName"], 'test') + self.assertEqual(components["layerName"], "test") - uri = f'{filename}|layerName=test' - components = registry.decodeUri('ogr', uri) + uri = f"{filename}|layerName=test" + components = registry.decodeUri("ogr", uri) self.assertEqual(components["path"], filename) - self.assertEqual(components["layerName"], 'test') + self.assertEqual(components["layerName"], "test") - uri = f'{filename}|layerid=0' - components = registry.decodeUri('ogr', uri) + uri = f"{filename}|layerid=0" + components = registry.decodeUri("ogr", uri) self.assertEqual(components["path"], filename) self.assertEqual(components["layerId"], 0) - uri = f'{filename}|layerId=0' - components = registry.decodeUri('ogr', uri) + uri = f"{filename}|layerId=0" + components = registry.decodeUri("ogr", uri) self.assertEqual(components["path"], filename) self.assertEqual(components["layerId"], 0) - uri = f'{filename}|geometryType=POINT' - components = registry.decodeUri('ogr', uri) + uri = f"{filename}|geometryType=POINT" + components = registry.decodeUri("ogr", uri) self.assertEqual(components["path"], filename) - self.assertEqual(components["geometryType"], 'POINT') + self.assertEqual(components["geometryType"], "POINT") def testEncodeUri(self): - filename = '/home/to/path/my_file.gpkg' + filename = "/home/to/path/my_file.gpkg" registry = QgsProviderRegistry.instance() parts = {"path": filename} - uri = registry.encodeUri('ogr', parts) + uri = registry.encodeUri("ogr", parts) self.assertEqual(uri, filename) # layerName only parts["layerName"] = "test" - uri = registry.encodeUri('ogr', parts) - self.assertEqual(uri, f'{filename}|layername=test') + uri = registry.encodeUri("ogr", parts) + self.assertEqual(uri, f"{filename}|layername=test") del parts["layerName"] # layerId only parts["layerId"] = "0" - uri = registry.encodeUri('ogr', parts) - self.assertEqual(uri, f'{filename}|layerid=0') + uri = registry.encodeUri("ogr", parts) + self.assertEqual(uri, f"{filename}|layerid=0") # Both layerName and layerId: layerName takes precedence parts["layerName"] = "test" - uri = registry.encodeUri('ogr', parts) - self.assertEqual(uri, f'{filename}|layername=test') + uri = registry.encodeUri("ogr", parts) + self.assertEqual(uri, f"{filename}|layername=test") def testSingleToMultiPolygonPromotion(self): - tmpfile = os.path.join(self.basetestpath, 'testSingleToMultiPolygonPromotion.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - ds.CreateLayer('test', geom_type=ogr.wkbMultiPolygon) + tmpfile = os.path.join( + self.basetestpath, "testSingleToMultiPolygonPromotion.gpkg" + ) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + ds.CreateLayer("test", geom_type=ogr.wkbMultiPolygon) ds = None - vl = QgsVectorLayer(f'{tmpfile}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}|layerid=0", "test", "ogr") f = QgsFeature() - f.setGeometry(QgsGeometry.fromWkt('POLYGON ((0 0,0 1,1 1,0 0))')) + f.setGeometry(QgsGeometry.fromWkt("POLYGON ((0 0,0 1,1 1,0 0))")) vl.dataProvider().addFeatures([f]) got = [feat for feat in vl.getFeatures()][0] got_geom = got.geometry() - reference = QgsGeometry.fromWkt('MultiPolygon (((0 0, 0 1, 1 1, 0 0)))') + reference = QgsGeometry.fromWkt("MultiPolygon (((0 0, 0 1, 1 1, 0 0)))") # The geometries must be binarily identical - self.assertEqual(got_geom.asWkb(), reference.asWkb(), - f'Expected {reference.asWkt()}, got {got_geom.asWkt()}') + self.assertEqual( + got_geom.asWkb(), + reference.asWkb(), + f"Expected {reference.asWkt()}, got {got_geom.asWkt()}", + ) def testCurveGeometryType(self): - tmpfile = os.path.join(self.basetestpath, 'testCurveGeometryType.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - ds.CreateLayer('test', geom_type=ogr.wkbCurvePolygon) + tmpfile = os.path.join(self.basetestpath, "testCurveGeometryType.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + ds.CreateLayer("test", geom_type=ogr.wkbCurvePolygon) ds = None - vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr") self.assertEqual(1, vl.dataProvider().subLayerCount()) - self.assertEqual(vl.dataProvider().subLayers(), - [QgsDataProvider.SUBLAYER_SEPARATOR.join(['0', 'test', '0', 'CurvePolygon', 'geom', ''])]) + self.assertEqual( + vl.dataProvider().subLayers(), + [ + QgsDataProvider.SUBLAYER_SEPARATOR.join( + ["0", "test", "0", "CurvePolygon", "geom", ""] + ) + ], + ) f = QgsFeature() - f.setGeometry(QgsGeometry.fromWkt('POLYGON ((0 0,0 1,1 1,0 0))')) + f.setGeometry(QgsGeometry.fromWkt("POLYGON ((0 0,0 1,1 1,0 0))")) vl.dataProvider().addFeatures([f]) got = [feat for feat in vl.getFeatures()][0] got_geom = got.geometry() - reference = QgsGeometry.fromWkt('CurvePolygon ((0 0, 0 1, 1 1, 0 0))') + reference = QgsGeometry.fromWkt("CurvePolygon ((0 0, 0 1, 1 1, 0 0))") # The geometries must be binarily identical - self.assertEqual(got_geom.asWkb(), reference.asWkb(), - f'Expected {reference.asWkt()}, got {got_geom.asWkt()}') + self.assertEqual( + got_geom.asWkb(), + reference.asWkb(), + f"Expected {reference.asWkt()}, got {got_geom.asWkt()}", + ) def internalTestBug15351(self, orderClosing): - tmpfile = os.path.join(self.basetestpath, 'testBug15351.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) + tmpfile = os.path.join(self.basetestpath, "testBug15351.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 0)")) lyr.CreateFeature(f) f = None ds = None - vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr") self.assertTrue(vl.startEditing()) - self.assertTrue(vl.changeGeometry(1, QgsGeometry.fromWkt('Point (3 50)'))) + self.assertTrue(vl.changeGeometry(1, QgsGeometry.fromWkt("Point (3 50)"))) # Iterate over features (will open a new OGR connection), but do not # close the iterator for now @@ -458,7 +484,7 @@ def internalTestBug15351(self, orderClosing): f = QgsFeature() it.nextFeature(f) - if orderClosing == 'closeIter_commit_closeProvider': + if orderClosing == "closeIter_commit_closeProvider": it = None # Commit changes @@ -468,73 +494,77 @@ def internalTestBug15351(self, orderClosing): self.assertIsNone(cbk.msg) # Close layer and iterator in different orders - if orderClosing == 'closeIter_commit_closeProvider': + if orderClosing == "closeIter_commit_closeProvider": vl = None - elif orderClosing == 'commit_closeProvider_closeIter': + elif orderClosing == "commit_closeProvider_closeIter": vl = None it = None else: - assert orderClosing == 'commit_closeIter_closeProvider' + assert orderClosing == "commit_closeIter_closeProvider" it = None vl = None # Test that we succeeded restoring default journal mode, and we # are not let in WAL mode. ds = ogr.Open(tmpfile) - lyr = ds.ExecuteSQL('PRAGMA journal_mode') + lyr = ds.ExecuteSQL("PRAGMA journal_mode") f = lyr.GetNextFeature() res = f.GetField(0) ds.ReleaseResultSet(lyr) ds = None - self.assertEqual(res, 'delete') + self.assertEqual(res, "delete") # We need GDAL 2.0 to issue PRAGMA journal_mode # Note: for that case, we don't strictly need turning on WAL def testBug15351_closeIter_commit_closeProvider(self): - self.internalTestBug15351('closeIter_commit_closeProvider') + self.internalTestBug15351("closeIter_commit_closeProvider") # We need GDAL 2.0 to issue PRAGMA journal_mode def testBug15351_commit_closeProvider_closeIter(self): - self.internalTestBug15351('commit_closeProvider_closeIter') + self.internalTestBug15351("commit_closeProvider_closeIter") # We need GDAL 2.0 to issue PRAGMA journal_mode def testBug15351_commit_closeIter_closeProvider(self): - self.internalTestBug15351('commit_closeIter_closeProvider') + self.internalTestBug15351("commit_closeIter_closeProvider") def testGeopackageExtentUpdate(self): - ''' test https://github.com/qgis/QGIS/issues/23209 ''' - tmpfile = os.path.join(self.basetestpath, 'testGeopackageExtentUpdate.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) + """test https://github.com/qgis/QGIS/issues/23209""" + tmpfile = os.path.join(self.basetestpath, "testGeopackageExtentUpdate.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 0)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(1 1)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(1 1)")) lyr.CreateFeature(f) f = None f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(1 0.5)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(1 0.5)")) lyr.CreateFeature(f) f = None gdal.ErrorReset() - ds.ExecuteSQL('RECOMPUTE EXTENT ON test') - has_error = gdal.GetLastErrorMsg() != '' + ds.ExecuteSQL("RECOMPUTE EXTENT ON test") + has_error = gdal.GetLastErrorMsg() != "" ds = None if has_error: - print('Too old GDAL trunk version. Please update') + print("Too old GDAL trunk version. Please update") return - vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr") # Test moving a geometry that touches the bbox self.assertTrue(vl.startEditing()) - self.assertTrue(vl.changeGeometry(1, QgsGeometry.fromWkt('Point (0.5 0)'))) + self.assertTrue(vl.changeGeometry(1, QgsGeometry.fromWkt("Point (0.5 0)"))) self.assertTrue(vl.commitChanges()) reference = QgsGeometry.fromRect(QgsRectangle(0.5, 0.0, 1.0, 1.0)) provider_extent = QgsGeometry.fromRect(vl.extent()) - self.assertTrue(QgsGeometry.compare(provider_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001), - provider_extent.asPolygon()[0]) + self.assertTrue( + QgsGeometry.compare( + provider_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001 + ), + provider_extent.asPolygon()[0], + ) # Test deleting a geometry that touches the bbox self.assertTrue(vl.startEditing()) @@ -542,39 +572,45 @@ def testGeopackageExtentUpdate(self): self.assertTrue(vl.commitChanges()) reference = QgsGeometry.fromRect(QgsRectangle(0.5, 0.0, 1.0, 0.5)) provider_extent = QgsGeometry.fromRect(vl.extent()) - self.assertTrue(QgsGeometry.compare(provider_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001), - provider_extent.asPolygon()[0]) + self.assertTrue( + QgsGeometry.compare( + provider_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001 + ), + provider_extent.asPolygon()[0], + ) def testSelectSubsetString(self): - tmpfile = os.path.join(self.basetestpath, 'testSelectSubsetString.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbMultiPolygon) - lyr.CreateField(ogr.FieldDefn('foo', ogr.OFTString)) + tmpfile = os.path.join(self.basetestpath, "testSelectSubsetString.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbMultiPolygon) + lyr.CreateField(ogr.FieldDefn("foo", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f['foo'] = 'bar' + f["foo"] = "bar" lyr.CreateFeature(f) f = None f = ogr.Feature(lyr.GetLayerDefn()) - f['foo'] = 'baz' + f["foo"] = "baz" lyr.CreateFeature(f) f = None ds = None - vl = QgsVectorLayer(f'{tmpfile}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}|layerid=0", "test", "ogr") vl.setSubsetString("SELECT fid, foo FROM test WHERE foo = 'baz'") got = [feat for feat in vl.getFeatures()] self.assertEqual(len(got), 1) # test SQLite CTE Common Table Expression (issue https://github.com/qgis/QGIS/issues/54677) - vl.setSubsetString("WITH test_cte AS (SELECT fid, foo FROM test WHERE foo = 'baz') SELECT * FROM test_cte") + vl.setSubsetString( + "WITH test_cte AS (SELECT fid, foo FROM test WHERE foo = 'baz') SELECT * FROM test_cte" + ) self.assertEqual(len(got), 1) del vl - testdata_path = unitTestDataPath('provider') - shutil.copy(os.path.join(testdata_path, 'bug_19826.gpkg'), tmpfile) - vl = QgsVectorLayer(f'{tmpfile}|layerid=0', 'test', 'ogr') + testdata_path = unitTestDataPath("provider") + shutil.copy(os.path.join(testdata_path, "bug_19826.gpkg"), tmpfile) + vl = QgsVectorLayer(f"{tmpfile}|layerid=0", "test", "ogr") vl.setSubsetString("name = 'two'") got = [feat for feat in vl.getFeatures()] self.assertEqual(len(got), 1) @@ -582,7 +618,7 @@ def testSelectSubsetString(self): attributes = got[0].attributes() self.assertEqual(got[0].id(), 2) self.assertEqual(attributes[0], 2) - self.assertEqual(attributes[1], 'two') + self.assertEqual(attributes[1], "two") self.assertNotEqual(attributes[2], None) # Request by FeatureId on a subset layer @@ -591,7 +627,7 @@ def testSelectSubsetString(self): attributes = got[0].attributes() self.assertEqual(got[0].id(), 2) self.assertEqual(attributes[0], 2) - self.assertEqual(attributes[1], 'two') + self.assertEqual(attributes[1], "two") self.assertNotEqual(attributes[2], None) request = QgsFeatureRequest(2).setSubsetOfAttributes([0]) @@ -611,38 +647,38 @@ def testSelectSubsetString(self): # Test setSubsetString() with a SELECT ... statement not selecting # the FID column - vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr") vl.setSubsetString("SELECT name FROM test_layer WHERE name = 'two'") got = [feat for feat in vl.getFeatures()] self.assertEqual(len(got), 1) attributes = got[0].attributes() - self.assertEqual(attributes[0], 'two') + self.assertEqual(attributes[0], "two") def testEditSubsetString(self): - tmpfile = os.path.join(self.basetestpath, 'testEditSubsetString.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbMultiPolygon) - lyr.CreateField(ogr.FieldDefn('foo', ogr.OFTString)) + tmpfile = os.path.join(self.basetestpath, "testEditSubsetString.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbMultiPolygon) + lyr.CreateField(ogr.FieldDefn("foo", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f['foo'] = 'bar' + f["foo"] = "bar" lyr.CreateFeature(f) f = None f = ogr.Feature(lyr.GetLayerDefn()) - f['foo'] = 'baz' + f["foo"] = "baz" lyr.CreateFeature(f) f = None ds = None - vl = QgsVectorLayer(f'{tmpfile}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}|layerid=0", "test", "ogr") self.assertEqual(vl.dataProvider().featureCount(), 2) # Test adding features vl.setSubsetString("foo = 'baz'") self.assertTrue(vl.startEditing()) feature = QgsFeature(vl.fields()) - feature['foo'] = 'abc' + feature["foo"] = "abc" vl.addFeature(feature) vl.commitChanges() vl.setSubsetString(None) @@ -659,23 +695,35 @@ def testEditSubsetString(self): # Test editing a feature vl.setSubsetString("foo = 'baz'") self.assertTrue(vl.startEditing()) - vl.changeAttributeValue(2, 1, 'xx') + vl.changeAttributeValue(2, 1, "xx") vl.commitChanges() vl.setSubsetString(None) - self.assertEqual({feat['foo'] for feat in vl.getFeatures()}, {'xx', 'abc'}) + self.assertEqual({feat["foo"] for feat in vl.getFeatures()}, {"xx", "abc"}) def testStyle(self): # First test with invalid URI - vl = QgsVectorLayer('/idont/exist.gpkg', 'test', 'ogr') - - self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, 0) - self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.SaveToDatabase, 0) - - res, err = QgsProviderRegistry.instance().styleExists('ogr', '/idont/exist.gpkg', '') + vl = QgsVectorLayer("/idont/exist.gpkg", "test", "ogr") + + self.assertEqual( + int(vl.dataProvider().styleStorageCapabilities()) + & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, + 0, + ) + self.assertEqual( + int(vl.dataProvider().styleStorageCapabilities()) + & Qgis.ProviderStyleStorageCapability.SaveToDatabase, + 0, + ) + + res, err = QgsProviderRegistry.instance().styleExists( + "ogr", "/idont/exist.gpkg", "" + ) self.assertFalse(res) self.assertTrue(err) - res, err = QgsProviderRegistry.instance().styleExists('ogr', '/idont/exist.gpkg', 'a style') + res, err = QgsProviderRegistry.instance().styleExists( + "ogr", "/idont/exist.gpkg", "a style" + ) self.assertFalse(res) self.assertTrue(err) @@ -690,43 +738,53 @@ def testStyle(self): self.assertFalse(qml) self.assertTrue(errmsg) - qml, success = vl.loadNamedStyle('/idont/exist.gpkg') + qml, success = vl.loadNamedStyle("/idont/exist.gpkg") self.assertFalse(success) errorMsg = vl.saveStyleToDatabase("name", "description", False, "") self.assertTrue(errorMsg) # Now with valid URI - tmpfile = os.path.join(self.basetestpath, 'testStyle.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbMultiPolygon) - lyr.CreateField(ogr.FieldDefn('foo', ogr.OFTString)) + tmpfile = os.path.join(self.basetestpath, "testStyle.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbMultiPolygon) + lyr.CreateField(ogr.FieldDefn("foo", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f['foo'] = 'bar' + f["foo"] = "bar" lyr.CreateFeature(f) f = None - lyr = ds.CreateLayer('test2', geom_type=ogr.wkbMultiPolygon) - lyr.CreateField(ogr.FieldDefn('foo', ogr.OFTString)) + lyr = ds.CreateLayer("test2", geom_type=ogr.wkbMultiPolygon) + lyr.CreateField(ogr.FieldDefn("foo", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f['foo'] = 'bar' + f["foo"] = "bar" lyr.CreateFeature(f) f = None ds = None - vl = QgsVectorLayer(f'{tmpfile}|layername=test', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}|layername=test", "test", "ogr") self.assertTrue(vl.isValid()) - vl2 = QgsVectorLayer(f'{tmpfile}|layername=test2', 'test2', 'ogr') + vl2 = QgsVectorLayer(f"{tmpfile}|layername=test2", "test2", "ogr") self.assertTrue(vl2.isValid()) - self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, Qgis.ProviderStyleStorageCapability.LoadFromDatabase) - self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.SaveToDatabase, Qgis.ProviderStyleStorageCapability.SaveToDatabase) + self.assertEqual( + int(vl.dataProvider().styleStorageCapabilities()) + & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, + Qgis.ProviderStyleStorageCapability.LoadFromDatabase, + ) + self.assertEqual( + int(vl.dataProvider().styleStorageCapabilities()) + & Qgis.ProviderStyleStorageCapability.SaveToDatabase, + Qgis.ProviderStyleStorageCapability.SaveToDatabase, + ) # style tables don't exist yet - res, err = QgsProviderRegistry.instance().styleExists('ogr', vl.source(), '') + res, err = QgsProviderRegistry.instance().styleExists("ogr", vl.source(), "") self.assertFalse(res) self.assertFalse(err) - res, err = QgsProviderRegistry.instance().styleExists('ogr', vl2.source(), 'a style') + res, err = QgsProviderRegistry.instance().styleExists( + "ogr", vl2.source(), "a style" + ) self.assertFalse(res) self.assertFalse(err) @@ -741,19 +799,23 @@ def testStyle(self): self.assertFalse(qml) self.assertTrue(errmsg) - qml, success = vl.loadNamedStyle(f'{tmpfile}|layerid=0') + qml, success = vl.loadNamedStyle(f"{tmpfile}|layerid=0") self.assertFalse(success) errorMsg = vl.saveStyleToDatabase("name", "description", False, "") self.assertFalse(errorMsg) - res, err = QgsProviderRegistry.instance().styleExists('ogr', vl.source(), '') + res, err = QgsProviderRegistry.instance().styleExists("ogr", vl.source(), "") self.assertFalse(res) self.assertFalse(err) - res, err = QgsProviderRegistry.instance().styleExists('ogr', vl.source(), 'a style') + res, err = QgsProviderRegistry.instance().styleExists( + "ogr", vl.source(), "a style" + ) self.assertFalse(res) self.assertFalse(err) - res, err = QgsProviderRegistry.instance().styleExists('ogr', vl.source(), 'name') + res, err = QgsProviderRegistry.instance().styleExists( + "ogr", vl.source(), "name" + ) self.assertTrue(res) self.assertFalse(err) @@ -764,63 +826,74 @@ def testStyle(self): related_count, idlist, namelist, desclist, errmsg = vl.listStylesInDatabase() self.assertEqual(related_count, 1) self.assertFalse(errmsg) - self.assertEqual(idlist, ['1']) - self.assertEqual(namelist, ['name']) - self.assertEqual(desclist, ['description']) + self.assertEqual(idlist, ["1"]) + self.assertEqual(namelist, ["name"]) + self.assertEqual(desclist, ["description"]) qml, errmsg = vl.getStyleFromDatabase("100") self.assertFalse(qml) self.assertTrue(errmsg) qml, errmsg = vl.getStyleFromDatabase("1") - self.assertTrue(qml.startswith('= 3.4.2 opening a GPKG file doesn't turn on WAL journal_mode """ + """Test that with GDAL >= 3.4.2 opening a GPKG file doesn't turn on WAL journal_mode""" - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - srcfile = os.path.join(srcpath, 'geopackage.gpkg') + srcpath = os.path.join(TEST_DATA_DIR, "provider") + srcfile = os.path.join(srcpath, "geopackage.gpkg") last_modified = QFileInfo(srcfile).lastModified() - vl = QgsVectorLayer(f'{srcfile}' + "|layername=geopackage", 'test', 'ogr') - self.assertEqual(TestPyQgsOGRProviderGpkg._getJournalMode(srcfile), 'delete') + vl = QgsVectorLayer(f"{srcfile}" + "|layername=geopackage", "test", "ogr") + self.assertEqual(TestPyQgsOGRProviderGpkg._getJournalMode(srcfile), "delete") del vl self.assertEqual(last_modified, QFileInfo(srcfile).lastModified()) - shutil.copy(os.path.join(srcpath, 'geopackage.gpkg'), self.basetestpath) - tmpfile = os.path.join(self.basetestpath, 'geopackage.gpkg') + shutil.copy(os.path.join(srcpath, "geopackage.gpkg"), self.basetestpath) + tmpfile = os.path.join(self.basetestpath, "geopackage.gpkg") - vl = QgsVectorLayer(f'{tmpfile}' + "|layername=geopackage", 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}" + "|layername=geopackage", "test", "ogr") - self.assertEqual(TestPyQgsOGRProviderGpkg._getJournalMode(tmpfile), 'delete') + self.assertEqual(TestPyQgsOGRProviderGpkg._getJournalMode(tmpfile), "delete") vl.startEditing() - self.assertEqual(TestPyQgsOGRProviderGpkg._getJournalMode(tmpfile), 'wal') + self.assertEqual(TestPyQgsOGRProviderGpkg._getJournalMode(tmpfile), "wal") vl.commitChanges() - self.assertEqual(TestPyQgsOGRProviderGpkg._getJournalMode(tmpfile), 'delete') + self.assertEqual(TestPyQgsOGRProviderGpkg._getJournalMode(tmpfile), "delete") def testSimulatedDBManagerImport(self): - uri = 'point?field=f1:int' - uri += '&field=f2:double(6,4)' - uri += '&field=f3:string(20)' + uri = "point?field=f1:int" + uri += "&field=f2:double(6,4)" + uri += "&field=f3:string(20)" mem_lyr = QgsVectorLayer(uri, "x", "memory") self.assertTrue(mem_lyr.isValid()) f = QgsFeature(mem_lyr.fields()) - f['f1'] = 1 - f['f2'] = 123.456 - f['f3'] = '12345678.90123456789' + f["f1"] = 1 + f["f2"] = 123.456 + f["f3"] = "12345678.90123456789" f2 = QgsFeature(mem_lyr.fields()) - f2['f1'] = 2 + f2["f1"] = 2 mem_lyr.dataProvider().addFeatures([f, f2]) # Test creating new DB - tmpfile = os.path.join(self.basetestpath, 'testSimulatedDBManagerImport.gpkg') + tmpfile = os.path.join(self.basetestpath, "testSimulatedDBManagerImport.gpkg") options = {} - options['driverName'] = 'GPKG' - err = QgsVectorLayerExporter.exportLayer(mem_lyr, tmpfile, "ogr", mem_lyr.crs(), False, options) - self.assertEqual(err[0], QgsVectorLayerExporter.ExportError.NoError, - f'unexpected import error {err}') + options["driverName"] = "GPKG" + err = QgsVectorLayerExporter.exportLayer( + mem_lyr, tmpfile, "ogr", mem_lyr.crs(), False, options + ) + self.assertEqual( + err[0], + QgsVectorLayerExporter.ExportError.NoError, + f"unexpected import error {err}", + ) lyr = QgsVectorLayer(tmpfile, "y", "ogr") self.assertTrue(lyr.isValid()) features = lyr.getFeatures() f = next(features) - self.assertEqual(f['f1'], 1) - self.assertEqual(f['f2'], 123.456) - self.assertEqual(f['f3'], '12345678.90123456789') + self.assertEqual(f["f1"], 1) + self.assertEqual(f["f2"], 123.456) + self.assertEqual(f["f3"], "12345678.90123456789") f = next(features) - self.assertEqual(f['f1'], 2) + self.assertEqual(f["f1"], 2) features = None del lyr @@ -931,107 +1012,137 @@ def testSimulatedDBManagerImport(self): mem_lyr = QgsVectorLayer(uri, "x", "memory") self.assertTrue(mem_lyr.isValid()) f = QgsFeature(mem_lyr.fields()) - f['f1'] = 1 - f['f2'] = 2 + f["f1"] = 1 + f["f2"] = 2 mem_lyr.dataProvider().addFeatures([f]) options = {} - options['update'] = True - options['driverName'] = 'GPKG' - options['layerName'] = 'my_out_table' - err = QgsVectorLayerExporter.exportLayer(mem_lyr, tmpfile, "ogr", mem_lyr.crs(), False, options) - self.assertEqual(err[0], QgsVectorLayerExporter.ExportError.NoError, - f'unexpected import error {err}') + options["update"] = True + options["driverName"] = "GPKG" + options["layerName"] = "my_out_table" + err = QgsVectorLayerExporter.exportLayer( + mem_lyr, tmpfile, "ogr", mem_lyr.crs(), False, options + ) + self.assertEqual( + err[0], + QgsVectorLayerExporter.ExportError.NoError, + f"unexpected import error {err}", + ) lyr = QgsVectorLayer(tmpfile + "|layername=my_out_table", "y", "ogr") self.assertTrue(lyr.isValid()) features = lyr.getFeatures() f = next(features) - self.assertEqual(f['f1'], 1) - self.assertEqual(f['f2'], 2) + self.assertEqual(f["f1"], 1) + self.assertEqual(f["f2"], 2) features = None del lyr # Test overwriting without overwrite option - err = QgsVectorLayerExporter.exportLayer(mem_lyr, tmpfile, "ogr", mem_lyr.crs(), False, options) + err = QgsVectorLayerExporter.exportLayer( + mem_lyr, tmpfile, "ogr", mem_lyr.crs(), False, options + ) self.assertEqual(err[0], QgsVectorLayerExporter.ExportError.ErrCreateDataSource) # Test overwriting, without specifying a layer name mem_lyr = QgsVectorLayer(uri, "x", "memory") self.assertTrue(mem_lyr.isValid()) f = QgsFeature(mem_lyr.fields()) - f['f1'] = 3 - f['f2'] = 4 + f["f1"] = 3 + f["f2"] = 4 mem_lyr.dataProvider().addFeatures([f]) options = {} - options['driverName'] = 'GPKG' - options['overwrite'] = True - err = QgsVectorLayerExporter.exportLayer(mem_lyr, tmpfile, "ogr", mem_lyr.crs(), False, options) - self.assertEqual(err[0], QgsVectorLayerExporter.ExportError.NoError, - f'unexpected import error {err}') + options["driverName"] = "GPKG" + options["overwrite"] = True + err = QgsVectorLayerExporter.exportLayer( + mem_lyr, tmpfile, "ogr", mem_lyr.crs(), False, options + ) + self.assertEqual( + err[0], + QgsVectorLayerExporter.ExportError.NoError, + f"unexpected import error {err}", + ) lyr = QgsVectorLayer(tmpfile, "y", "ogr") self.assertTrue(lyr.isValid()) features = lyr.getFeatures() f = next(features) - self.assertEqual(f['f1'], 3) - self.assertEqual(f['f2'], 4) + self.assertEqual(f["f1"], 3) + self.assertEqual(f["f2"], 4) features = None def testExportLayerToExistingDatabase(self): fields = QgsFields() - fields.append(QgsField('f1', QVariant.Int)) - tmpfile = os.path.join(self.basetestpath, 'testCreateNewGeopackage.gpkg') + fields.append(QgsField("f1", QVariant.Int)) + tmpfile = os.path.join(self.basetestpath, "testCreateNewGeopackage.gpkg") options = {} - options['update'] = True - options['driverName'] = 'GPKG' - options['layerName'] = 'table1' - exporter = QgsVectorLayerExporter(tmpfile, "ogr", fields, QgsWkbTypes.Type.Polygon, - QgsCoordinateReferenceSystem('EPSG:3111'), False, options) - self.assertFalse(exporter.errorCode(), - f'unexpected export error {exporter.errorCode()}: {exporter.errorMessage()}') + options["update"] = True + options["driverName"] = "GPKG" + options["layerName"] = "table1" + exporter = QgsVectorLayerExporter( + tmpfile, + "ogr", + fields, + QgsWkbTypes.Type.Polygon, + QgsCoordinateReferenceSystem("EPSG:3111"), + False, + options, + ) + self.assertFalse( + exporter.errorCode(), + f"unexpected export error {exporter.errorCode()}: {exporter.errorMessage()}", + ) del exporter - options['layerName'] = 'table2' - exporter = QgsVectorLayerExporter(tmpfile, "ogr", fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:3113'), - False, options) - self.assertFalse(exporter.errorCode(), - f'unexpected export error {exporter.errorCode()} : {exporter.errorMessage()}') + options["layerName"] = "table2" + exporter = QgsVectorLayerExporter( + tmpfile, + "ogr", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:3113"), + False, + options, + ) + self.assertFalse( + exporter.errorCode(), + f"unexpected export error {exporter.errorCode()} : {exporter.errorMessage()}", + ) del exporter # make sure layers exist - lyr = QgsVectorLayer(f'{tmpfile}|layername=table1', "lyr1", "ogr") + lyr = QgsVectorLayer(f"{tmpfile}|layername=table1", "lyr1", "ogr") self.assertTrue(lyr.isValid()) - self.assertEqual(lyr.crs().authid(), 'EPSG:3111') + self.assertEqual(lyr.crs().authid(), "EPSG:3111") self.assertEqual(lyr.wkbType(), QgsWkbTypes.Type.Polygon) - lyr2 = QgsVectorLayer(f'{tmpfile}|layername=table2', "lyr2", "ogr") + lyr2 = QgsVectorLayer(f"{tmpfile}|layername=table2", "lyr2", "ogr") self.assertTrue(lyr2.isValid()) - self.assertEqual(lyr2.crs().authid(), 'EPSG:3113') + self.assertEqual(lyr2.crs().authid(), "EPSG:3113") self.assertEqual(lyr2.wkbType(), QgsWkbTypes.Type.Point) def testGeopackageTwoLayerEdition(self): - ''' test https://github.com/qgis/QGIS/issues/24933 ''' - tmpfile = os.path.join(self.basetestpath, 'testGeopackageTwoLayerEdition.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('layer1', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTInteger)) + """test https://github.com/qgis/QGIS/issues/24933""" + tmpfile = os.path.join(self.basetestpath, "testGeopackageTwoLayerEdition.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("layer1", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("attr", ogr.OFTInteger)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 0)")) lyr.CreateFeature(f) f = None - lyr = ds.CreateLayer('layer2', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTInteger)) + lyr = ds.CreateLayer("layer2", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("attr", ogr.OFTInteger)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(1 1)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(1 1)")) lyr.CreateFeature(f) f = None ds = None - vl1 = QgsVectorLayer(f'{tmpfile}' + "|layername=layer1", 'layer1', 'ogr') - vl2 = QgsVectorLayer(f'{tmpfile}' + "|layername=layer2", 'layer2', 'ogr') + vl1 = QgsVectorLayer(f"{tmpfile}" + "|layername=layer1", "layer1", "ogr") + vl2 = QgsVectorLayer(f"{tmpfile}" + "|layername=layer2", "layer2", "ogr") # Edit vl1, vl2 multiple times self.assertTrue(vl1.startEditing()) self.assertTrue(vl2.startEditing()) - self.assertTrue(vl1.changeGeometry(1, QgsGeometry.fromWkt('Point (2 2)'))) - self.assertTrue(vl2.changeGeometry(1, QgsGeometry.fromWkt('Point (3 3)'))) + self.assertTrue(vl1.changeGeometry(1, QgsGeometry.fromWkt("Point (2 2)"))) + self.assertTrue(vl2.changeGeometry(1, QgsGeometry.fromWkt("Point (3 3)"))) self.assertTrue(vl1.commitChanges()) self.assertTrue(vl2.commitChanges()) @@ -1044,8 +1155,8 @@ def testGeopackageTwoLayerEdition(self): self.assertTrue(vl1.startEditing()) self.assertTrue(vl2.startEditing()) - self.assertTrue(vl1.changeGeometry(1, QgsGeometry.fromWkt('Point (4 4)'))) - self.assertTrue(vl2.changeGeometry(1, QgsGeometry.fromWkt('Point (5 5)'))) + self.assertTrue(vl1.changeGeometry(1, QgsGeometry.fromWkt("Point (4 4)"))) + self.assertTrue(vl2.changeGeometry(1, QgsGeometry.fromWkt("Point (5 5)"))) self.assertTrue(vl1.commitChanges()) self.assertTrue(vl2.commitChanges()) @@ -1053,36 +1164,42 @@ def testGeopackageTwoLayerEdition(self): vl2 = None # Check everything is as expected after re-opening - vl1 = QgsVectorLayer(f'{tmpfile}' + "|layername=layer1", 'layer1', 'ogr') - vl2 = QgsVectorLayer(f'{tmpfile}' + "|layername=layer2", 'layer2', 'ogr') + vl1 = QgsVectorLayer(f"{tmpfile}" + "|layername=layer1", "layer1", "ogr") + vl2 = QgsVectorLayer(f"{tmpfile}" + "|layername=layer2", "layer2", "ogr") got = [feat for feat in vl1.getFeatures()][0] got_geom = got.geometry() - self.assertEqual(got['attr'], 100) - reference = QgsGeometry.fromWkt('Point (4 4)') - self.assertEqual(got_geom.asWkb(), reference.asWkb(), - f'Expected {reference.asWkt()}, got {got_geom.asWkt()}') + self.assertEqual(got["attr"], 100) + reference = QgsGeometry.fromWkt("Point (4 4)") + self.assertEqual( + got_geom.asWkb(), + reference.asWkb(), + f"Expected {reference.asWkt()}, got {got_geom.asWkt()}", + ) got = [feat for feat in vl2.getFeatures()][0] got_geom = got.geometry() - self.assertEqual(got['attr'], 101) - reference = QgsGeometry.fromWkt('Point (5 5)') - self.assertEqual(got_geom.asWkb(), reference.asWkb(), - f'Expected {reference.asWkt()}, got {got_geom.asWkt()}') + self.assertEqual(got["attr"], 101) + reference = QgsGeometry.fromWkt("Point (5 5)") + self.assertEqual( + got_geom.asWkb(), + reference.asWkb(), + f"Expected {reference.asWkt()}, got {got_geom.asWkt()}", + ) def testReplaceLayerWhileOpen(self): - ''' Replace an existing geopackage layer whilst it's open in the project''' - tmpfile = os.path.join(self.basetestpath, 'testGeopackageReplaceOpenLayer.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('layer1', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTInteger)) - lyr.CreateField(ogr.FieldDefn('attr2', ogr.OFTInteger)) + """Replace an existing geopackage layer whilst it's open in the project""" + tmpfile = os.path.join(self.basetestpath, "testGeopackageReplaceOpenLayer.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("layer1", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("attr", ogr.OFTInteger)) + lyr.CreateField(ogr.FieldDefn("attr2", ogr.OFTInteger)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 0)")) lyr.CreateFeature(f) f = None - vl1 = QgsVectorLayer(f'{tmpfile}' + "|layername=layer1", 'layer1', 'ogr') + vl1 = QgsVectorLayer(f"{tmpfile}" + "|layername=layer1", "layer1", "ogr") p = QgsProject() p.addMapLayer(vl1) request = QgsFeatureRequest().setSubsetOfAttributes([0]) @@ -1090,68 +1207,88 @@ def testReplaceLayerWhileOpen(self): self.assertEqual(len(features), 1) # now, overwrite the layer with a different geometry type and fields - ds.DeleteLayer('layer1') - lyr = ds.CreateLayer('layer1', geom_type=ogr.wkbLineString) - lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTString)) + ds.DeleteLayer("layer1") + lyr = ds.CreateLayer("layer1", geom_type=ogr.wkbLineString) + lyr.CreateField(ogr.FieldDefn("attr", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('LineString(0 0, 1 1)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("LineString(0 0, 1 1)")) lyr.CreateFeature(f) f = None - vl2 = QgsVectorLayer(f'{tmpfile}' + "|layername=layer1", 'layer2', 'ogr') + vl2 = QgsVectorLayer(f"{tmpfile}" + "|layername=layer1", "layer2", "ogr") p.addMapLayer(vl2) features = [f for f in vl1.getFeatures(request)] self.assertEqual(len(features), 1) def testPkAttributeIndexes(self): - ''' Test the primary key index ''' - tmpfile = os.path.join(self.basetestpath, 'testPkAttributeIndexes.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - ds.CreateLayer('test', geom_type=ogr.wkbPoint, - options=['COLUMN_TYPES=foo=int8,bar=string', 'GEOMETRY_NAME=the_geom', 'FID=customfid']) + """Test the primary key index""" + tmpfile = os.path.join(self.basetestpath, "testPkAttributeIndexes.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + ds.CreateLayer( + "test", + geom_type=ogr.wkbPoint, + options=[ + "COLUMN_TYPES=foo=int8,bar=string", + "GEOMETRY_NAME=the_geom", + "FID=customfid", + ], + ) ds = None - vl = QgsVectorLayer(f'{tmpfile}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}|layerid=0", "test", "ogr") pks = vl.primaryKeyAttributes() fields = vl.fields() pkfield = fields.at(pks[0]) self.assertEqual(len(pks), 1) self.assertEqual(pks[0], 0) - self.assertEqual(pkfield.name(), 'customfid') - self.assertTrue(pkfield.constraints().constraints() & QgsFieldConstraints.Constraint.ConstraintUnique) + self.assertEqual(pkfield.name(), "customfid") + self.assertTrue( + pkfield.constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintUnique + ) def testSublayerWithComplexLayerName(self): - ''' Test reading a gpkg with a sublayer name containing : ''' - tmpfile = os.path.join(self.basetestpath, 'testGeopackageComplexLayerName.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('layer1:', geom_type=ogr.wkbPoint, options=['GEOMETRY_NAME=geom:']) - lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTInteger)) + """Test reading a gpkg with a sublayer name containing :""" + tmpfile = os.path.join(self.basetestpath, "testGeopackageComplexLayerName.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer( + "layer1:", geom_type=ogr.wkbPoint, options=["GEOMETRY_NAME=geom:"] + ) + lyr.CreateField(ogr.FieldDefn("attr", ogr.OFTInteger)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 0)")) lyr.CreateFeature(f) f = None - vl = QgsVectorLayer(f'{tmpfile}', 'layer', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}", "layer", "ogr") self.assertEqual(1, vl.dataProvider().subLayerCount()) - self.assertEqual(vl.dataProvider().subLayers(), - [QgsDataProvider.SUBLAYER_SEPARATOR.join(['0', 'layer1:', '1', 'Point', 'geom:', ''])]) + self.assertEqual( + vl.dataProvider().subLayers(), + [ + QgsDataProvider.SUBLAYER_SEPARATOR.join( + ["0", "layer1:", "1", "Point", "geom:", ""] + ) + ], + ) def testGeopackageManyLayers(self): - ''' test opening more than 64 layers without running out of Spatialite connections ''' + """test opening more than 64 layers without running out of Spatialite connections""" - tmpfile = os.path.join(self.basetestpath, 'testGeopackageManyLayers.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) + tmpfile = os.path.join(self.basetestpath, "testGeopackageManyLayers.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) for i in range(70): - lyr = ds.CreateLayer('layer%d' % i, geom_type=ogr.wkbPoint) + lyr = ds.CreateLayer("layer%d" % i, geom_type=ogr.wkbPoint) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(%d 0)' % i)) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(%d 0)" % i)) lyr.CreateFeature(f) f = None ds = None vl_tab = [] for i in range(70): - layername = 'layer%d' % i - vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + layername, layername, 'ogr') + layername = "layer%d" % i + vl = QgsVectorLayer( + f"{tmpfile}" + "|layername=" + layername, layername, "ogr" + ) self.assertTrue(vl.isValid()) vl_tab += [vl] @@ -1174,52 +1311,66 @@ def testGeopackageManyLayers(self): self.assertIn(count, (2, 3)) # Re-open an already opened layers. We should get a new handle - layername = 'layer%d' % 0 - vl_extra0 = QgsVectorLayer(f'{tmpfile}' + "|layername=" + layername, layername, 'ogr') + layername = "layer%d" % 0 + vl_extra0 = QgsVectorLayer( + f"{tmpfile}" + "|layername=" + layername, layername, "ogr" + ) self.assertTrue(vl_extra0.isValid()) countNew = count_opened_filedescriptors(tmpfile) if countNew > 0: self.assertLessEqual(countNew, 4) # for some reason we get 4 and not 3 - layername = 'layer%d' % 1 - vl_extra1 = QgsVectorLayer(f'{tmpfile}' + "|layername=" + layername, layername, 'ogr') + layername = "layer%d" % 1 + vl_extra1 = QgsVectorLayer( + f"{tmpfile}" + "|layername=" + layername, layername, "ogr" + ) self.assertTrue(vl_extra1.isValid()) countNew2 = count_opened_filedescriptors(tmpfile) self.assertEqual(countNew2, countNew) def testGeopackageRefreshIfTableListUpdated(self): - ''' test that creating/deleting a layer is reflected when opening a new layer ''' + """test that creating/deleting a layer is reflected when opening a new layer""" - tmpfile = os.path.join(self.basetestpath, 'testGeopackageRefreshIfTableListUpdated.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - ds.CreateLayer('test', geom_type=ogr.wkbPoint) + tmpfile = os.path.join( + self.basetestpath, "testGeopackageRefreshIfTableListUpdated.gpkg" + ) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + ds.CreateLayer("test", geom_type=ogr.wkbPoint) ds = None - vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") self.assertTrue(vl.extent().isNull()) time.sleep(1) # so timestamp gets updated ds = ogr.Open(tmpfile, update=1) - ds.CreateLayer('test2', geom_type=ogr.wkbPoint) + ds.CreateLayer("test2", geom_type=ogr.wkbPoint) ds = None - vl2 = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr') + vl2 = QgsVectorLayer(f"{tmpfile}", "test", "ogr") self.assertEqual(2, vl2.dataProvider().subLayerCount()) vl2.subLayers() - self.assertEqual(vl2.dataProvider().subLayers(), - [QgsDataProvider.SUBLAYER_SEPARATOR.join(['0', 'test', '0', 'Point', 'geom', '']), - QgsDataProvider.SUBLAYER_SEPARATOR.join(['1', 'test2', '0', 'Point', 'geom', ''])]) + self.assertEqual( + vl2.dataProvider().subLayers(), + [ + QgsDataProvider.SUBLAYER_SEPARATOR.join( + ["0", "test", "0", "Point", "geom", ""] + ), + QgsDataProvider.SUBLAYER_SEPARATOR.join( + ["1", "test2", "0", "Point", "geom", ""] + ), + ], + ) def testGeopackageLargeFID(self): - tmpfile = os.path.join(self.basetestpath, 'testGeopackageLargeFID.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) + tmpfile = os.path.join(self.basetestpath, "testGeopackageLargeFID.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString)) ds = None - vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") f = QgsFeature() f.setAttributes([1234567890123, None]) f2 = QgsFeature() @@ -1229,42 +1380,53 @@ def testGeopackageLargeFID(self): self.assertTrue(vl.commitChanges()) got = [feat for feat in vl.getFeatures(QgsFeatureRequest(1234567890123))][0] - self.assertEqual(got['fid'], 1234567890123) + self.assertEqual(got["fid"], 1234567890123) self.assertTrue(vl.startEditing()) - self.assertTrue(vl.changeGeometry(1234567890123, QgsGeometry.fromWkt('Point (3 50)'))) - self.assertTrue(vl.changeAttributeValue(1234567890123, 1, 'foo')) + self.assertTrue( + vl.changeGeometry(1234567890123, QgsGeometry.fromWkt("Point (3 50)")) + ) + self.assertTrue(vl.changeAttributeValue(1234567890123, 1, "foo")) self.assertTrue(vl.commitChanges()) got = [feat for feat in vl.getFeatures(QgsFeatureRequest(1234567890123))][0] - self.assertEqual(got['str_field'], 'foo') + self.assertEqual(got["str_field"], "foo") got_geom = got.geometry() self.assertIsNotNone(got_geom) # We don't change the FID, so OK self.assertTrue(vl.startEditing()) - self.assertTrue(vl.dataProvider().changeAttributeValues({1234567890123: {0: 1234567890123, 1: 'bar'}, - 1234567890124: {0: 1234567890124, 1: 'bar2'}})) + self.assertTrue( + vl.dataProvider().changeAttributeValues( + { + 1234567890123: {0: 1234567890123, 1: "bar"}, + 1234567890124: {0: 1234567890124, 1: "bar2"}, + } + ) + ) self.assertTrue(vl.commitChanges()) got = [feat for feat in vl.getFeatures(QgsFeatureRequest(1234567890123))][0] - self.assertEqual(got['str_field'], 'bar') + self.assertEqual(got["str_field"], "bar") got = [feat for feat in vl.getFeatures(QgsFeatureRequest(1234567890124))][0] - self.assertEqual(got['str_field'], 'bar2') + self.assertEqual(got["str_field"], "bar2") # We try to change the FID, not allowed # also check that all changes where reverted self.assertTrue(vl.startEditing()) - self.assertFalse(vl.dataProvider().changeAttributeValues({1234567890123: {0: 1, 1: 'baz'}, - 1234567890124: {1: 'baz2'}})) + self.assertFalse( + vl.dataProvider().changeAttributeValues( + {1234567890123: {0: 1, 1: "baz"}, 1234567890124: {1: "baz2"}} + ) + ) self.assertTrue(vl.commitChanges()) got = [feat for feat in vl.getFeatures(QgsFeatureRequest(1234567890123))][0] - self.assertEqual(got['str_field'], 'bar') + self.assertEqual(got["str_field"], "bar") got = [feat for feat in vl.getFeatures(QgsFeatureRequest(1234567890124))][0] - self.assertEqual(got['str_field'], 'bar2') + self.assertEqual(got["str_field"], "bar2") self.assertTrue(vl.startEditing()) self.assertTrue(vl.deleteFeature(1234567890123)) @@ -1272,134 +1434,171 @@ def testGeopackageLargeFID(self): def test_AddFeatureNullFid(self): """Test gpkg feature with NULL fid can be added""" - tmpfile = os.path.join(self.basetestpath, 'testGeopackageSplitFeatures.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon) - lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) + tmpfile = os.path.join(self.basetestpath, "testGeopackageSplitFeatures.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon) + lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString)) ds = None - layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + layer = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") # Check that pk field has unique constraint fields = layer.fields() pkfield = fields.at(0) - self.assertTrue(pkfield.constraints().constraints() & QgsFieldConstraints.Constraint.ConstraintUnique) + self.assertTrue( + pkfield.constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintUnique + ) # Test add feature with default Fid (NULL) layer.startEditing() f = QgsFeature() feat = QgsFeature(layer.fields()) - feat.setGeometry(QgsGeometry.fromWkt('Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))')) - feat.setAttribute(1, 'test_value') + feat.setGeometry(QgsGeometry.fromWkt("Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))")) + feat.setAttribute(1, "test_value") layer.addFeature(feat) self.assertTrue(layer.commitChanges()) self.assertEqual(layer.featureCount(), 1) def test_SplitFeature(self): """Test gpkg feature can be split""" - tmpfile = os.path.join(self.basetestpath, 'testGeopackageSplitFeatures.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon) - lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) + tmpfile = os.path.join(self.basetestpath, "testGeopackageSplitFeatures.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon) + lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 1,1 1,1 0,0 0))')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON ((0 0,0 1,1 1,1 0,0 0))")) lyr.CreateFeature(f) f = None ds = None # Split features - layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + layer = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") self.assertTrue(layer.isValid()) self.assertTrue(layer.isSpatial()) - self.assertEqual([f for f in layer.getFeatures()][0].geometry().asWkt(), 'Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))') + self.assertEqual( + [f for f in layer.getFeatures()][0].geometry().asWkt(), + "Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))", + ) layer.startEditing() - self.assertEqual(layer.splitFeatures([QgsPointXY(0.5, 0), QgsPointXY(0.5, 1)], 0), 0) + self.assertEqual( + layer.splitFeatures([QgsPointXY(0.5, 0), QgsPointXY(0.5, 1)], 0), 0 + ) self.assertTrue(layer.commitChanges()) self.assertEqual(layer.featureCount(), 2) - layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + layer = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") self.assertEqual(layer.featureCount(), 2) g, g2 = (f.geometry() for f in layer.getFeatures()) g.normalize() g2.normalize() - self.assertCountEqual([geom.asWkt() for geom in [g, g2]], ['Polygon ((0 0, 0 1, 0.5 1, 0.5 0, 0 0))', - 'Polygon ((0.5 0, 0.5 1, 1 1, 1 0, 0.5 0))']) + self.assertCountEqual( + [geom.asWkt() for geom in [g, g2]], + [ + "Polygon ((0 0, 0 1, 0.5 1, 0.5 0, 0 0))", + "Polygon ((0.5 0, 0.5 1, 1 1, 1 0, 0.5 0))", + ], + ) def test_SplitFeatureErrorIncompatibleGeometryType(self): """Test we behave correctly when split feature is not possible due to incompatible geometry type""" - tmpfile = os.path.join(self.basetestpath, 'test_SplitFeatureErrorIncompatibleGeometryType.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) + tmpfile = os.path.join( + self.basetestpath, "test_SplitFeatureErrorIncompatibleGeometryType.gpkg" + ) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) f = ogr.Feature(lyr.GetLayerDefn()) # For the purpose of this test, we insert a Polygon in a Point layer # which is normally not allowed - f.SetGeometry(ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 1,1 1,1 0,0 0))')) - gdal.PushErrorHandler('CPLQuietErrorHandler') + f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON ((0 0,0 1,1 1,1 0,0 0))")) + gdal.PushErrorHandler("CPLQuietErrorHandler") self.assertEqual(lyr.CreateFeature(f), ogr.OGRERR_NONE) gdal.PopErrorHandler() f = None ds = None # Split features - layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + layer = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") self.assertTrue(layer.isValid()) self.assertTrue(layer.isSpatial()) - self.assertEqual([f for f in layer.getFeatures()][0].geometry().asWkt(), 'Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))') + self.assertEqual( + [f for f in layer.getFeatures()][0].geometry().asWkt(), + "Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))", + ) layer.startEditing() - self.assertEqual(layer.splitFeatures([QgsPointXY(0.5, 0), QgsPointXY(0.5, 1)], 0), 0) + self.assertEqual( + layer.splitFeatures([QgsPointXY(0.5, 0), QgsPointXY(0.5, 1)], 0), 0 + ) self.assertFalse(layer.commitChanges()) - layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + layer = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") self.assertEqual(layer.featureCount(), 1) g = [f.geometry() for f in layer.getFeatures()][0] - self.assertEqual(g.asWkt(), 'Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))') + self.assertEqual(g.asWkt(), "Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))") def test_SplitFeatureErrorIncompatibleGeometryType2(self): """Test we behave correctly when split a single-part multipolygon of a polygon layer (https://github.com/qgis/QGIS/issues/41283)""" # This is really a non-nominal case. Failing properly would also be understandable. - tmpfile = os.path.join(self.basetestpath, 'test_SplitFeatureErrorIncompatibleGeometryType2.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon) + tmpfile = os.path.join( + self.basetestpath, "test_SplitFeatureErrorIncompatibleGeometryType2.gpkg" + ) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon) f = ogr.Feature(lyr.GetLayerDefn()) # For the purpose of this test, we insert a MultiPolygon in a Polygon layer # which is normally not allowed - f.SetGeometry(ogr.CreateGeometryFromWkt('MULTIPOLYGON (((0 0,0 1,1 1,1 0,0 0)))')) - gdal.PushErrorHandler('CPLQuietErrorHandler') + f.SetGeometry( + ogr.CreateGeometryFromWkt("MULTIPOLYGON (((0 0,0 1,1 1,1 0,0 0)))") + ) + gdal.PushErrorHandler("CPLQuietErrorHandler") self.assertEqual(lyr.CreateFeature(f), ogr.OGRERR_NONE) gdal.PopErrorHandler() f = None ds = None # Split features - layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + layer = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") self.assertTrue(layer.isValid()) self.assertTrue(layer.isSpatial()) - self.assertEqual([f for f in layer.getFeatures()][0].geometry().asWkt(), 'MultiPolygon (((0 0, 0 1, 1 1, 1 0, 0 0)))') + self.assertEqual( + [f for f in layer.getFeatures()][0].geometry().asWkt(), + "MultiPolygon (((0 0, 0 1, 1 1, 1 0, 0 0)))", + ) layer.startEditing() - self.assertEqual(layer.splitFeatures([QgsPointXY(0.5, 0), QgsPointXY(0.5, 1)], 0), 0) + self.assertEqual( + layer.splitFeatures([QgsPointXY(0.5, 0), QgsPointXY(0.5, 1)], 0), 0 + ) self.assertTrue(layer.commitChanges()) self.assertEqual(layer.featureCount(), 2) - layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + layer = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") self.assertEqual(layer.featureCount(), 2) g, g2 = (f.geometry() for f in layer.getFeatures()) g.normalize() g2.normalize() - self.assertCountEqual([geom.asWkt() for geom in [g, g2]], ['Polygon ((0 0, 0 1, 0.5 1, 0.5 0, 0 0))', - 'Polygon ((0.5 0, 0.5 1, 1 1, 1 0, 0.5 0))']) + self.assertCountEqual( + [geom.asWkt() for geom in [g, g2]], + [ + "Polygon ((0 0, 0 1, 0.5 1, 0.5 0, 0 0))", + "Polygon ((0.5 0, 0.5 1, 1 1, 1 0, 0.5 0))", + ], + ) def testCreateAttributeIndex(self): - tmpfile = os.path.join(self.basetestpath, 'testGeopackageAttributeIndex.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon) - lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('str_field2', ogr.OFTString)) + tmpfile = os.path.join(self.basetestpath, "testGeopackageAttributeIndex.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon) + lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("str_field2", ogr.OFTString)) f = None ds = None - vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") self.assertTrue(vl.isValid()) - self.assertTrue(vl.dataProvider().capabilities() & QgsVectorDataProvider.Capability.CreateAttributeIndex) + self.assertTrue( + vl.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.CreateAttributeIndex + ) self.assertFalse(vl.dataProvider().createAttributeIndex(-1)) self.assertFalse(vl.dataProvider().createAttributeIndex(100)) @@ -1410,18 +1609,22 @@ def testCreateAttributeIndex(self): con = spatialite_connect(tmpfile, isolation_level=None) cur = con.cursor() - rs = cur.execute("SELECT * FROM sqlite_master WHERE type='index' AND tbl_name='test'") + rs = cur.execute( + "SELECT * FROM sqlite_master WHERE type='index' AND tbl_name='test'" + ) res = [row for row in rs] self.assertEqual(len(res), 1) index_name = res[0][1] rs = cur.execute(f"PRAGMA index_info({index_name})") res = [row for row in rs] self.assertEqual(len(res), 1) - self.assertEqual(res[0][2], 'str_field') + self.assertEqual(res[0][2], "str_field") # second index self.assertTrue(vl.dataProvider().createAttributeIndex(2)) - rs = cur.execute("SELECT * FROM sqlite_master WHERE type='index' AND tbl_name='test'") + rs = cur.execute( + "SELECT * FROM sqlite_master WHERE type='index' AND tbl_name='test'" + ) res = [row for row in rs] self.assertEqual(len(res), 2) indexed_columns = [] @@ -1432,124 +1635,147 @@ def testCreateAttributeIndex(self): self.assertEqual(len(res), 1) indexed_columns.append(res[0][2]) - self.assertCountEqual(indexed_columns, ['str_field', 'str_field2']) + self.assertCountEqual(indexed_columns, ["str_field", "str_field2"]) con.close() def testCreateSpatialIndex(self): - tmpfile = os.path.join(self.basetestpath, 'testGeopackageSpatialIndex.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon, options=['SPATIAL_INDEX=NO']) - lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('str_field2', ogr.OFTString)) + tmpfile = os.path.join(self.basetestpath, "testGeopackageSpatialIndex.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer( + "test", geom_type=ogr.wkbPolygon, options=["SPATIAL_INDEX=NO"] + ) + lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("str_field2", ogr.OFTString)) f = None ds = None - vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") self.assertTrue(vl.isValid()) - self.assertTrue(vl.dataProvider().capabilities() & QgsVectorDataProvider.Capability.CreateSpatialIndex) + self.assertTrue( + vl.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.CreateSpatialIndex + ) self.assertTrue(vl.dataProvider().createSpatialIndex()) def testSubSetStringEditable_bug17795_but_with_modified_behavior(self): """Test that a layer is editable after setting a subset""" - tmpfile = os.path.join(self.basetestpath, 'testSubSetStringEditable_bug17795.gpkg') - shutil.copy(TEST_DATA_DIR + '/' + 'provider/bug_17795.gpkg', tmpfile) + tmpfile = os.path.join( + self.basetestpath, "testSubSetStringEditable_bug17795.gpkg" + ) + shutil.copy(TEST_DATA_DIR + "/" + "provider/bug_17795.gpkg", tmpfile) isEditable = QgsVectorDataProvider.Capability.ChangeAttributeValues - testPath = tmpfile + '|layername=bug_17795' + testPath = tmpfile + "|layername=bug_17795" - vl = QgsVectorLayer(testPath, 'subset_test', 'ogr') + vl = QgsVectorLayer(testPath, "subset_test", "ogr") self.assertTrue(vl.isValid()) self.assertTrue(vl.dataProvider().capabilities() & isEditable) - vl = QgsVectorLayer(testPath, 'subset_test', 'ogr') - vl.setSubsetString('') + vl = QgsVectorLayer(testPath, "subset_test", "ogr") + vl.setSubsetString("") self.assertTrue(vl.isValid()) self.assertTrue(vl.dataProvider().capabilities() & isEditable) - vl = QgsVectorLayer(testPath, 'subset_test', 'ogr') - vl.setSubsetString('"category" = \'one\'') + vl = QgsVectorLayer(testPath, "subset_test", "ogr") + vl.setSubsetString("\"category\" = 'one'") self.assertTrue(vl.isValid()) self.assertTrue(vl.dataProvider().capabilities() & isEditable) - vl.setSubsetString('') + vl.setSubsetString("") self.assertTrue(vl.dataProvider().capabilities() & isEditable) def testSubsetStringExtent_bug17863(self): """Check that the extent is correct when applied in the ctor and when - modified after a subset string is set """ + modified after a subset string is set""" def _lessdigits(s): - return re.sub(r'(\d+\.\d{3})\d+', r'\1', s) + return re.sub(r"(\d+\.\d{3})\d+", r"\1", s) - tmpfile = os.path.join(self.basetestpath, 'testSubsetStringExtent_bug17863.gpkg') - shutil.copy(TEST_DATA_DIR + '/' + 'provider/bug_17795.gpkg', tmpfile) + tmpfile = os.path.join( + self.basetestpath, "testSubsetStringExtent_bug17863.gpkg" + ) + shutil.copy(TEST_DATA_DIR + "/" + "provider/bug_17795.gpkg", tmpfile) - testPath = tmpfile + '|layername=bug_17795' - subSetString = '"name" = \'int\'' - subSet = f'|subset={subSetString}' + testPath = tmpfile + "|layername=bug_17795" + subSetString = "\"name\" = 'int'" + subSet = f"|subset={subSetString}" # unfiltered - vl = QgsVectorLayer(testPath, 'test', 'ogr') + vl = QgsVectorLayer(testPath, "test", "ogr") self.assertTrue(vl.isValid()) unfiltered_extent = _lessdigits(vl.extent().toString()) - del (vl) + del vl # filter after construction ... - subSet_vl2 = QgsVectorLayer(testPath, 'test', 'ogr') + subSet_vl2 = QgsVectorLayer(testPath, "test", "ogr") self.assertEqual(_lessdigits(subSet_vl2.extent().toString()), unfiltered_extent) # ... apply filter now! subSet_vl2.setSubsetString(subSetString) self.assertEqual(subSet_vl2.subsetString(), subSetString) - self.assertNotEqual(_lessdigits(subSet_vl2.extent().toString()), unfiltered_extent) + self.assertNotEqual( + _lessdigits(subSet_vl2.extent().toString()), unfiltered_extent + ) filtered_extent = _lessdigits(subSet_vl2.extent().toString()) - del (subSet_vl2) + del subSet_vl2 # filtered in constructor - subSet_vl = QgsVectorLayer(testPath + subSet, 'subset_test', 'ogr') + subSet_vl = QgsVectorLayer(testPath + subSet, "subset_test", "ogr") self.assertEqual(subSet_vl.subsetString(), subSetString) self.assertTrue(subSet_vl.isValid()) # This was failing in bug 17863 self.assertEqual(_lessdigits(subSet_vl.extent().toString()), filtered_extent) - self.assertNotEqual(_lessdigits(subSet_vl.extent().toString()), unfiltered_extent) + self.assertNotEqual( + _lessdigits(subSet_vl.extent().toString()), unfiltered_extent + ) def testRequestWithoutGeometryOnLayerMixedGeometry(self): - """ Test bugfix for https://github.com/qgis/QGIS/issues/26907 """ + """Test bugfix for https://github.com/qgis/QGIS/issues/26907""" # Issue is more a generic one of the OGR provider, but easy to trigger with GPKG - tmpfile = os.path.join(self.basetestpath, 'testRequestWithoutGeometryOnLayerMixedGeometry.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbUnknown, options=['SPATIAL_INDEX=NO']) + tmpfile = os.path.join( + self.basetestpath, "testRequestWithoutGeometryOnLayerMixedGeometry.gpkg" + ) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer( + "test", geom_type=ogr.wkbUnknown, options=["SPATIAL_INDEX=NO"] + ) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 1)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 1)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('LINESTRING(0 0,1 0)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("LINESTRING(0 0,1 0)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('LINESTRING(0 0,1 0)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("LINESTRING(0 0,1 0)")) lyr.CreateFeature(f) f = None ds = None - vl = QgsVectorLayer(f'{tmpfile}' + "|geometrytype=Point|layername=" + "test", 'test', 'ogr') + vl = QgsVectorLayer( + f"{tmpfile}" + "|geometrytype=Point|layername=" + "test", "test", "ogr" + ) self.assertTrue(vl.isValid()) request = QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry) features = [f for f in vl.getFeatures(request)] self.assertEqual(len(features), 1) def testAddingTwoIntFieldsWithWidth(self): - """ Test buggfix for https://github.com/qgis/QGIS/issues/26840 """ + """Test buggfix for https://github.com/qgis/QGIS/issues/26840""" - tmpfile = os.path.join(self.basetestpath, 'testRequestWithoutGeometryOnLayerMixedGeometry.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['SPATIAL_INDEX=NO']) - lyr.CreateField(ogr.FieldDefn('a', ogr.OFTInteger)) + tmpfile = os.path.join( + self.basetestpath, "testRequestWithoutGeometryOnLayerMixedGeometry.gpkg" + ) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer( + "test", geom_type=ogr.wkbPoint, options=["SPATIAL_INDEX=NO"] + ) + lyr.CreateField(ogr.FieldDefn("a", ogr.OFTInteger)) ds = None - vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") self.assertTrue(vl.isValid()) vl.startEditing() @@ -1561,143 +1787,168 @@ def testAddingTwoIntFieldsWithWidth(self): self.assertTrue(vl.commitChanges()) def testApproxFeatureCountAndExtent(self): - """ Test perf improvement for for https://github.com/qgis/QGIS/issues/26292 """ + """Test perf improvement for for https://github.com/qgis/QGIS/issues/26292""" - tmpfile = os.path.join(self.basetestpath, 'testApproxFeatureCountAndExtent.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) + tmpfile = os.path.join( + self.basetestpath, "testApproxFeatureCountAndExtent.gpkg" + ) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 1)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 1)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(2 3)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(2 3)")) lyr.CreateFeature(f) fid = f.GetFID() f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(4 5)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(4 5)")) lyr.CreateFeature(f) lyr.DeleteFeature(fid) ds = None ds = ogr.Open(tmpfile, update=1) - ds.ExecuteSQL('DROP TABLE gpkg_ogr_contents') + ds.ExecuteSQL("DROP TABLE gpkg_ogr_contents") ds = None - os.environ['QGIS_GPKG_FC_THRESHOLD'] = '1' - vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + os.environ["QGIS_GPKG_FC_THRESHOLD"] = "1" + vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") self.assertTrue(vl.isValid()) fc = vl.featureCount() - del os.environ['QGIS_GPKG_FC_THRESHOLD'] + del os.environ["QGIS_GPKG_FC_THRESHOLD"] self.assertEqual(fc, 3) # didn't notice the hole reference = QgsGeometry.fromRect(QgsRectangle(0, 1, 4, 5)) provider_extent = QgsGeometry.fromRect(vl.extent()) - self.assertTrue(QgsGeometry.compare(provider_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001), - provider_extent.asPolygon()[0]) + self.assertTrue( + QgsGeometry.compare( + provider_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001 + ), + provider_extent.asPolygon()[0], + ) def testRegenerateFid(self): - """ Test regenerating feature ids """ + """Test regenerating feature ids""" fields = QgsFields() - fields.append(QgsField('fid', QVariant.Int)) - fields.append(QgsField('f1', QVariant.Int)) - tmpfile = os.path.join(self.basetestpath, 'testRegenerateFid.gpkg') + fields.append(QgsField("fid", QVariant.Int)) + fields.append(QgsField("f1", QVariant.Int)) + tmpfile = os.path.join(self.basetestpath, "testRegenerateFid.gpkg") options = {} - options['update'] = True - options['driverName'] = 'GPKG' - options['layerName'] = 'table1' - exporter = QgsVectorLayerExporter(tmpfile, "ogr", fields, QgsWkbTypes.Type.Polygon, - QgsCoordinateReferenceSystem('EPSG:3111'), False, options, - QgsFeatureSink.SinkFlag.RegeneratePrimaryKey) - self.assertFalse(exporter.errorCode(), - f'unexpected export error {exporter.errorCode()}: {exporter.errorMessage()}') + options["update"] = True + options["driverName"] = "GPKG" + options["layerName"] = "table1" + exporter = QgsVectorLayerExporter( + tmpfile, + "ogr", + fields, + QgsWkbTypes.Type.Polygon, + QgsCoordinateReferenceSystem("EPSG:3111"), + False, + options, + QgsFeatureSink.SinkFlag.RegeneratePrimaryKey, + ) + self.assertFalse( + exporter.errorCode(), + f"unexpected export error {exporter.errorCode()}: {exporter.errorMessage()}", + ) feat = QgsFeature(fields) - feat['fid'] = 0 - feat['f1'] = 10 + feat["fid"] = 0 + feat["f1"] = 10 exporter.addFeature(feat) - feat['fid'] = 0 - feat['f1'] = 20 + feat["fid"] = 0 + feat["f1"] = 20 exporter.addFeature(feat) - feat['fid'] = 1 - feat['f1'] = 30 + feat["fid"] = 1 + feat["f1"] = 30 exporter.addFeature(feat) - feat['fid'] = 1 - feat['f1'] = 40 + feat["fid"] = 1 + feat["f1"] = 40 exporter.addFeature(feat) del exporter # make sure layers exist - lyr = QgsVectorLayer(f'{tmpfile}|layername=table1', "lyr1", "ogr") + lyr = QgsVectorLayer(f"{tmpfile}|layername=table1", "lyr1", "ogr") self.assertTrue(lyr.isValid()) - self.assertEqual(lyr.crs().authid(), 'EPSG:3111') + self.assertEqual(lyr.crs().authid(), "EPSG:3111") self.assertEqual(lyr.wkbType(), QgsWkbTypes.Type.Polygon) - values = {f['f1'] for f in lyr.getFeatures()} + values = {f["f1"] for f in lyr.getFeatures()} self.assertEqual(values, {10, 20, 30, 40}) - fids = {f['fid'] for f in lyr.getFeatures()} + fids = {f["fid"] for f in lyr.getFeatures()} self.assertEqual(len(fids), 4) def testExportWithoutFids(self): - """ Test export with a feature without fid, regression GH #32927 + """Test export with a feature without fid, regression GH #32927 This test case is related to testRegenerateFid """ fields = QgsFields() - fields.append(QgsField('one', QVariant.Int)) - fields.append(QgsField('two', QVariant.Int)) - tmpfile = os.path.join(self.basetestpath, 'testExportWithoutFids.gpkg') + fields.append(QgsField("one", QVariant.Int)) + fields.append(QgsField("two", QVariant.Int)) + tmpfile = os.path.join(self.basetestpath, "testExportWithoutFids.gpkg") options = {} - options['update'] = True - options['driverName'] = 'GPKG' - options['layerName'] = 'output' - exporter = QgsVectorLayerExporter(tmpfile, "ogr", fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:4326'), - False, options, QgsFeatureSink.SinkFlag.RegeneratePrimaryKey) - self.assertFalse(exporter.errorCode(), - f'unexpected export error {exporter.errorCode()}: {exporter.errorMessage()}') + options["update"] = True + options["driverName"] = "GPKG" + options["layerName"] = "output" + exporter = QgsVectorLayerExporter( + tmpfile, + "ogr", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:4326"), + False, + options, + QgsFeatureSink.SinkFlag.RegeneratePrimaryKey, + ) + self.assertFalse( + exporter.errorCode(), + f"unexpected export error {exporter.errorCode()}: {exporter.errorMessage()}", + ) feat = QgsFeature(fields) - feat['one'] = 100 - feat['two'] = 200 - feat.setGeometry(QgsGeometry.fromWkt('point(4 45)')) + feat["one"] = 100 + feat["two"] = 200 + feat.setGeometry(QgsGeometry.fromWkt("point(4 45)")) exporter.addFeature(feat) del exporter # make sure layers exist - lyr = QgsVectorLayer(f'{tmpfile}|layername=output', "lyr1", "ogr") + lyr = QgsVectorLayer(f"{tmpfile}|layername=output", "lyr1", "ogr") self.assertTrue(lyr.isValid()) - self.assertEqual(lyr.crs().authid(), 'EPSG:4326') + self.assertEqual(lyr.crs().authid(), "EPSG:4326") self.assertEqual(lyr.wkbType(), QgsWkbTypes.Type.Point) feat_out = next(lyr.getFeatures()) - self.assertEqual(feat_out.attribute('two'), 200) - self.assertEqual(feat_out.attribute('one'), 100) + self.assertEqual(feat_out.attribute("two"), 200) + self.assertEqual(feat_out.attribute("one"), 100) def testTransaction(self): - tmpfile = os.path.join(self.basetestpath, 'testTransaction.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('lyr1', geom_type=ogr.wkbPoint) + tmpfile = os.path.join(self.basetestpath, "testTransaction.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("lyr1", geom_type=ogr.wkbPoint) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 1)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 1)")) lyr.CreateFeature(f) - lyr = ds.CreateLayer('lyr2', geom_type=ogr.wkbPoint) + lyr = ds.CreateLayer("lyr2", geom_type=ogr.wkbPoint) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(2 3)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(2 3)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(4 5)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(4 5)")) lyr.CreateFeature(f) ds = None - vl1 = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "lyr1", 'test', 'ogr') + vl1 = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "lyr1", "test", "ogr") self.assertTrue(vl1.isValid()) - vl2 = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "lyr2", 'test', 'ogr') + vl2 = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "lyr2", "test", "ogr") self.assertTrue(vl2.isValid()) # prepare a project with transactions enabled @@ -1713,9 +1964,13 @@ def testTransaction(self): self.assertEqual(len([f for f in vl1.getFeatures(QgsFeatureRequest())]), 0) # But not if opened from another connection - vl1_external = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "lyr1", 'test', 'ogr') + vl1_external = QgsVectorLayer( + f"{tmpfile}" + "|layername=" + "lyr1", "test", "ogr" + ) self.assertTrue(vl1_external.isValid()) - self.assertEqual(len([f for f in vl1_external.getFeatures(QgsFeatureRequest())]), 1) + self.assertEqual( + len([f for f in vl1_external.getFeatures(QgsFeatureRequest())]), 1 + ) del vl1_external self.assertTrue(vl1.commitChanges()) @@ -1743,9 +1998,13 @@ def testTransaction(self): del vl1 del vl2 - vl2_external = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "lyr2", 'test', 'ogr') + vl2_external = QgsVectorLayer( + f"{tmpfile}" + "|layername=" + "lyr2", "test", "ogr" + ) self.assertTrue(vl2_external.isValid()) - self.assertEqual(len([f for f in vl2_external.getFeatures(QgsFeatureRequest())]), 1) + self.assertEqual( + len([f for f in vl2_external.getFeatures(QgsFeatureRequest())]), 1 + ) del vl2_external def testTransactionGroupAutomatic(self): @@ -1753,18 +2012,22 @@ def testTransactionGroupAutomatic(self): temp_dir = QTemporaryDir() temp_path = temp_dir.path() - tmpfile = os.path.join(temp_path, 'testTransactionGroupAutomatic.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('types', geom_type=ogr.wkbNone) - lyr.CreateField(ogr.FieldDefn('name', ogr.OFTString)) - lyr = ds.CreateLayer('shops', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('name', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('type_fk', ogr.OFTString)) + tmpfile = os.path.join(temp_path, "testTransactionGroupAutomatic.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("types", geom_type=ogr.wkbNone) + lyr.CreateField(ogr.FieldDefn("name", ogr.OFTString)) + lyr = ds.CreateLayer("shops", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("name", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("type_fk", ogr.OFTString)) ds = None - type_layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "types", 'types', 'ogr') + type_layer = QgsVectorLayer( + f"{tmpfile}" + "|layername=" + "types", "types", "ogr" + ) self.assertTrue(type_layer.isValid()) - shops_layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "shops", 'shops', 'ogr') + shops_layer = QgsVectorLayer( + f"{tmpfile}" + "|layername=" + "shops", "shops", "ogr" + ) self.assertTrue(shops_layer.isValid()) # prepare a project with transactions enabled @@ -1774,11 +2037,11 @@ def testTransactionGroupAutomatic(self): # Add one to many relation relation = QgsRelation(QgsRelationContext(p)) - relation.setName('shops_types') - relation.setId('shops_types') + relation.setName("shops_types") + relation.setId("shops_types") relation.setReferencingLayer(shops_layer.id()) relation.setReferencedLayer(type_layer.id()) - relation.addFieldPair('type_fk', 'name') + relation.addFieldPair("type_fk", "name") self.assertTrue(relation.isValid(), relation.validationError()) p.relationManager().addRelation(relation) @@ -1787,7 +2050,7 @@ def testTransactionGroupAutomatic(self): self.assertTrue(shops_layer.isEditable()) self.assertTrue(type_layer.isEditable()) f = QgsFeature(shops_layer.fields()) - f['name'] = 'shop1' + f["name"] = "shop1" self.assertTrue(shops_layer.addFeature(f)) self.assertTrue(p.commitChanges(True, shops_layer)) @@ -1802,113 +2065,163 @@ def testTransactionGroupAutomatic(self): self.assertTrue(p.rollBack(True, shops_layer)) def testJson(self): - tmpfile = os.path.join(self.basetestpath, 'test_json.gpkg') - testdata_path = unitTestDataPath('provider') - shutil.copy(os.path.join(unitTestDataPath('provider'), 'test_json.gpkg'), tmpfile) + tmpfile = os.path.join(self.basetestpath, "test_json.gpkg") + testdata_path = unitTestDataPath("provider") + shutil.copy( + os.path.join(unitTestDataPath("provider"), "test_json.gpkg"), tmpfile + ) - vl = QgsVectorLayer(f'{tmpfile}|layerid=0', 'foo', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}|layerid=0", "foo", "ogr") self.assertTrue(vl.isValid()) fields = vl.dataProvider().fields() - self.assertEqual(fields.at(fields.indexFromName('json_content')).type(), QVariant.Map) + self.assertEqual( + fields.at(fields.indexFromName("json_content")).type(), QVariant.Map + ) fi = vl.getFeatures(QgsFeatureRequest()) f = QgsFeature() # test reading dict value from attribute while fi.nextFeature(f): - if f['fid'] == 1: - self.assertIsInstance(f['json_content'], dict) - self.assertEqual(f['json_content'], {'foo': 'bar'}) + if f["fid"] == 1: + self.assertIsInstance(f["json_content"], dict) + self.assertEqual(f["json_content"], {"foo": "bar"}) # test changing dict value in attribute - f['json_content'] = {'foo': 'baz'} - self.assertEqual(f['json_content'], {'foo': 'baz'}) + f["json_content"] = {"foo": "baz"} + self.assertEqual(f["json_content"], {"foo": "baz"}) # test changint dict to list - f['json_content'] = ['eins', 'zwei', 'drei'] - self.assertEqual(f['json_content'], ['eins', 'zwei', 'drei']) + f["json_content"] = ["eins", "zwei", "drei"] + self.assertEqual(f["json_content"], ["eins", "zwei", "drei"]) # test changing list value in attribute - f['json_content'] = ['eins', 'zwei', 'drei', 4] - self.assertEqual(f['json_content'], ['eins', 'zwei', 'drei', 4]) + f["json_content"] = ["eins", "zwei", "drei", 4] + self.assertEqual(f["json_content"], ["eins", "zwei", "drei", 4]) # test changing to complex json structure - f['json_content'] = {'name': 'Lily', 'age': '0', - 'cars': {'car1': ['fiat tipo', 'fiat punto', 'davoser schlitten'], - 'car2': 'bobbycar', 'car3': 'tesla'}} - self.assertEqual(f['json_content'], {'name': 'Lily', 'age': '0', - 'cars': {'car1': ['fiat tipo', 'fiat punto', 'davoser schlitten'], - 'car2': 'bobbycar', 'car3': 'tesla'}}) + f["json_content"] = { + "name": "Lily", + "age": "0", + "cars": { + "car1": ["fiat tipo", "fiat punto", "davoser schlitten"], + "car2": "bobbycar", + "car3": "tesla", + }, + } + self.assertEqual( + f["json_content"], + { + "name": "Lily", + "age": "0", + "cars": { + "car1": ["fiat tipo", "fiat punto", "davoser schlitten"], + "car2": "bobbycar", + "car3": "tesla", + }, + }, + ) # test adding attribute vl.startEditing() self.assertTrue( - vl.addAttribute(QgsField('json_content2', QVariant.Map, "JSON", 60, 0, 'no comment', QVariant.String))) + vl.addAttribute( + QgsField( + "json_content2", + QVariant.Map, + "JSON", + 60, + 0, + "no comment", + QVariant.String, + ) + ) + ) self.assertTrue(vl.commitChanges()) vl.startEditing() self.assertTrue( - vl.addAttribute(QgsField('json_content3', QVariant.Map, "JSON", 60, 0, 'no comment', QVariant.String))) + vl.addAttribute( + QgsField( + "json_content3", + QVariant.Map, + "JSON", + 60, + 0, + "no comment", + QVariant.String, + ) + ) + ) self.assertTrue(vl.commitChanges()) # test setting values to new attributes while fi.nextFeature(f): - if f['fid'] == 2: - f['json_content'] = {'uno': 'foo'} - f['json_content2'] = ['uno', 'due', 'tre'] - f['json_content3'] = {'uno': ['uno', 'due', 'tre']} - self.assertEqual(f['json_content'], {'foo': 'baz'}) - self.assertEqual(f['json_content2'], ['uno', 'due', 'tre']) - self.assertEqual(f['json_content3'], {'uno': ['uno', 'due', 'tre']}) + if f["fid"] == 2: + f["json_content"] = {"uno": "foo"} + f["json_content2"] = ["uno", "due", "tre"] + f["json_content3"] = {"uno": ["uno", "due", "tre"]} + self.assertEqual(f["json_content"], {"foo": "baz"}) + self.assertEqual(f["json_content2"], ["uno", "due", "tre"]) + self.assertEqual(f["json_content3"], {"uno": ["uno", "due", "tre"]}) # test deleting attribute vl.startEditing() - self.assertTrue(vl.deleteAttribute(vl.fields().indexFromName('json_content3'))) + self.assertTrue(vl.deleteAttribute(vl.fields().indexFromName("json_content3"))) self.assertTrue(vl.commitChanges()) # test if index of existent field is not -1 and the one of the deleted is -1 - self.assertNotEqual(vl.fields().indexFromName('json_content2'), -1) - self.assertEqual(vl.fields().indexFromName('json_content3'), -1) + self.assertNotEqual(vl.fields().indexFromName("json_content2"), -1) + self.assertEqual(vl.fields().indexFromName("json_content3"), -1) def test_quote_identifier(self): """Regression #21100""" - tmpfile = os.path.join(self.basetestpath, 'bug_21100-wierd_field_names.gpkg') # spellok - shutil.copy(os.path.join(unitTestDataPath(''), 'bug_21100-wierd_field_names.gpkg'), tmpfile) # spellok - vl = QgsVectorLayer(f'{tmpfile}|layerid=0', 'foo', 'ogr') + tmpfile = os.path.join( + self.basetestpath, "bug_21100-wierd_field_names.gpkg" + ) # spellok + shutil.copy( + os.path.join(unitTestDataPath(""), "bug_21100-wierd_field_names.gpkg"), + tmpfile, + ) # spellok + vl = QgsVectorLayer(f"{tmpfile}|layerid=0", "foo", "ogr") self.assertTrue(vl.isValid()) for i in range(1, len(vl.fields())): - self.assertEqual(vl.uniqueValues(i), {'a', 'b', 'c'}) + self.assertEqual(vl.uniqueValues(i), {"a", "b", "c"}) def testGeopackageLayerMetadata(self): """ Geopackage layer description and identifier should be read into layer metadata automatically """ - tmpfile = os.path.join(self.basetestpath, 'testGeopackageLayerMetadata.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('layer1', geom_type=ogr.wkbPoint) - lyr.SetMetadataItem('DESCRIPTION', "my desc") - lyr.SetMetadataItem('IDENTIFIER', "my title") # see geopackage specs -- "'identifier' is analogous to 'title'" - lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTInteger)) + tmpfile = os.path.join(self.basetestpath, "testGeopackageLayerMetadata.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("layer1", geom_type=ogr.wkbPoint) + lyr.SetMetadataItem("DESCRIPTION", "my desc") + lyr.SetMetadataItem( + "IDENTIFIER", "my title" + ) # see geopackage specs -- "'identifier' is analogous to 'title'" + lyr.CreateField(ogr.FieldDefn("attr", ogr.OFTInteger)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 0)")) lyr.CreateFeature(f) f = None - vl1 = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "layer1", 'test', 'ogr') + vl1 = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "layer1", "test", "ogr") self.assertTrue(vl1.isValid()) - self.assertEqual(vl1.metadata().title(), 'my title') - self.assertEqual(vl1.metadata().abstract(), 'my desc') + self.assertEqual(vl1.metadata().title(), "my title") + self.assertEqual(vl1.metadata().abstract(), "my desc") def testGeopackageSaveMetadata(self): - tmpfile = os.path.join(self.basetestpath, 'testGeopackageSaveMetadata.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon) - lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('str_field2', ogr.OFTString)) + tmpfile = os.path.join(self.basetestpath, "testGeopackageSaveMetadata.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon) + lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("str_field2", ogr.OFTString)) f = None ds = None con = spatialite_connect(tmpfile, isolation_level=None) cur = con.cursor() try: - rs = cur.execute("SELECT * FROM gpkg_metadata_reference WHERE table_name='test'") + rs = cur.execute( + "SELECT * FROM gpkg_metadata_reference WHERE table_name='test'" + ) res = [row for row in rs] self.assertEqual(len(res), 0) con.close() @@ -1918,30 +2231,42 @@ def testGeopackageSaveMetadata(self): # now save some metadata metadata = QgsLayerMetadata() - metadata.setAbstract('my abstract') - metadata.setIdentifier('my identifier') - metadata.setLicenses(['l1', 'l2']) - ok, err = QgsProviderRegistry.instance().saveLayerMetadata('ogr', QgsProviderRegistry.instance().encodeUri('ogr', {'path': tmpfile, 'layerName': 'test'}), metadata) + metadata.setAbstract("my abstract") + metadata.setIdentifier("my identifier") + metadata.setLicenses(["l1", "l2"]) + ok, err = QgsProviderRegistry.instance().saveLayerMetadata( + "ogr", + QgsProviderRegistry.instance().encodeUri( + "ogr", {"path": tmpfile, "layerName": "test"} + ), + metadata, + ) self.assertTrue(ok) con = spatialite_connect(tmpfile, isolation_level=None) cur = con.cursor() # check that main gpkg_contents metadata columns have been updated - rs = cur.execute("SELECT identifier, description FROM gpkg_contents WHERE table_name='test'") + rs = cur.execute( + "SELECT identifier, description FROM gpkg_contents WHERE table_name='test'" + ) rows = [r for r in rs] - self.assertCountEqual(rows[0], ['my identifier', 'my abstract']) + self.assertCountEqual(rows[0], ["my identifier", "my abstract"]) - rs = cur.execute("SELECT md_file_id FROM gpkg_metadata_reference WHERE table_name='test'") + rs = cur.execute( + "SELECT md_file_id FROM gpkg_metadata_reference WHERE table_name='test'" + ) file_ids = [row[0] for row in rs] self.assertTrue(file_ids) - rs = cur.execute("SELECT id, md_scope, mime_type, metadata FROM gpkg_metadata WHERE md_standard_uri='http://mrcc.com/qgis.dtd'") + rs = cur.execute( + "SELECT id, md_scope, mime_type, metadata FROM gpkg_metadata WHERE md_standard_uri='http://mrcc.com/qgis.dtd'" + ) res = [row for row in rs] # id must match md_file_id from gpkg_metadata_reference self.assertIn(res[0][0], file_ids) - self.assertEqual(res[0][1], 'dataset') - self.assertEqual(res[0][2], 'text/xml') + self.assertEqual(res[0][1], "dataset") + self.assertEqual(res[0][2], "text/xml") metadata_xml = res[0][3] con.close() @@ -1949,38 +2274,50 @@ def testGeopackageSaveMetadata(self): doc = QDomDocument() doc.setContent(metadata_xml) self.assertTrue(metadata2.readMetadataXml(doc.documentElement())) - self.assertEqual(metadata2.abstract(), 'my abstract') - self.assertEqual(metadata2.identifier(), 'my identifier') - self.assertEqual(metadata2.licenses(), ['l1', 'l2']) + self.assertEqual(metadata2.abstract(), "my abstract") + self.assertEqual(metadata2.identifier(), "my identifier") + self.assertEqual(metadata2.licenses(), ["l1", "l2"]) # try updating existing metadata -- current row must be updated, not a new row added - metadata2.setAbstract('my abstract 2') - metadata2.setIdentifier('my identifier 2') - metadata2.setHistory(['h1', 'h2']) - ok, err = QgsProviderRegistry.instance().saveLayerMetadata('ogr', QgsProviderRegistry.instance().encodeUri('ogr', {'path': tmpfile, 'layerName': 'test'}), metadata2) + metadata2.setAbstract("my abstract 2") + metadata2.setIdentifier("my identifier 2") + metadata2.setHistory(["h1", "h2"]) + ok, err = QgsProviderRegistry.instance().saveLayerMetadata( + "ogr", + QgsProviderRegistry.instance().encodeUri( + "ogr", {"path": tmpfile, "layerName": "test"} + ), + metadata2, + ) self.assertTrue(ok) con = spatialite_connect(tmpfile, isolation_level=None) cur = con.cursor() # check that main gpkg_contents metadata columns have been updated - rs = cur.execute("SELECT identifier, description FROM gpkg_contents WHERE table_name='test'") + rs = cur.execute( + "SELECT identifier, description FROM gpkg_contents WHERE table_name='test'" + ) rows = [r for r in rs] self.assertEqual(len(rows), 1) - self.assertCountEqual(rows[0], ['my identifier 2', 'my abstract 2']) + self.assertCountEqual(rows[0], ["my identifier 2", "my abstract 2"]) - rs = cur.execute("SELECT md_file_id FROM gpkg_metadata_reference WHERE table_name='test'") + rs = cur.execute( + "SELECT md_file_id FROM gpkg_metadata_reference WHERE table_name='test'" + ) rows = [r for r in rs] file_ids = [row[0] for row in rows] self.assertTrue(file_ids) - rs = cur.execute("SELECT id, md_scope, mime_type, metadata FROM gpkg_metadata WHERE md_standard_uri='http://mrcc.com/qgis.dtd'") + rs = cur.execute( + "SELECT id, md_scope, mime_type, metadata FROM gpkg_metadata WHERE md_standard_uri='http://mrcc.com/qgis.dtd'" + ) res = [row for row in rs] self.assertEqual(len(res), 1) # id must match md_file_id from gpkg_metadata_reference self.assertIn(res[0][0], file_ids) - self.assertEqual(res[0][1], 'dataset') - self.assertEqual(res[0][2], 'text/xml') + self.assertEqual(res[0][1], "dataset") + self.assertEqual(res[0][2], "text/xml") metadata_xml = res[0][3] con.close() @@ -1988,151 +2325,177 @@ def testGeopackageSaveMetadata(self): doc = QDomDocument() doc.setContent(metadata_xml) self.assertTrue(metadata3.readMetadataXml(doc.documentElement())) - self.assertEqual(metadata3.abstract(), 'my abstract 2') - self.assertEqual(metadata3.identifier(), 'my identifier 2') - self.assertEqual(metadata3.licenses(), ['l1', 'l2']) - self.assertEqual(metadata3.history(), ['h1', 'h2']) + self.assertEqual(metadata3.abstract(), "my abstract 2") + self.assertEqual(metadata3.identifier(), "my identifier 2") + self.assertEqual(metadata3.licenses(), ["l1", "l2"]) + self.assertEqual(metadata3.history(), ["h1", "h2"]) def testGeopackageRestoreMetadata(self): """ Test that metadata saved to gpkg_metadata is automatically restored on layer load """ - tmpfile = os.path.join(self.basetestpath, 'testGeopackageRestoreMetadata.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon) - lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('str_field2', ogr.OFTString)) + tmpfile = os.path.join(self.basetestpath, "testGeopackageRestoreMetadata.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon) + lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("str_field2", ogr.OFTString)) f = None ds = None # now save some metadata metadata = QgsLayerMetadata() - metadata.setAbstract('my abstract') - metadata.setIdentifier('my identifier') - metadata.setLicenses(['l1', 'l2']) - ok, err = QgsProviderRegistry.instance().saveLayerMetadata('ogr', QgsProviderRegistry.instance().encodeUri('ogr', {'path': tmpfile, 'layerName': 'test'}), metadata) + metadata.setAbstract("my abstract") + metadata.setIdentifier("my identifier") + metadata.setLicenses(["l1", "l2"]) + ok, err = QgsProviderRegistry.instance().saveLayerMetadata( + "ogr", + QgsProviderRegistry.instance().encodeUri( + "ogr", {"path": tmpfile, "layerName": "test"} + ), + metadata, + ) self.assertTrue(ok) - vl = QgsVectorLayer(tmpfile, 'test') + vl = QgsVectorLayer(tmpfile, "test") self.assertTrue(vl.isValid()) metadata2 = vl.metadata() - self.assertEqual(metadata2.abstract(), 'my abstract') - self.assertEqual(metadata2.identifier(), 'my identifier') - self.assertEqual(metadata2.licenses(), ['l1', 'l2']) + self.assertEqual(metadata2.abstract(), "my abstract") + self.assertEqual(metadata2.identifier(), "my identifier") + self.assertEqual(metadata2.licenses(), ["l1", "l2"]) def testGeopackageSaveDefaultMetadata(self): """ Test saving layer metadata as default to a gpkg file """ - tmpfile = os.path.join(self.basetestpath, 'testGeopackageSaveMetadataDefault.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon) - lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('str_field2', ogr.OFTString)) + tmpfile = os.path.join( + self.basetestpath, "testGeopackageSaveMetadataDefault.gpkg" + ) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon) + lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("str_field2", ogr.OFTString)) f = None ds = None - uri = QgsProviderRegistry.instance().encodeUri('ogr', {'path': tmpfile, 'layerName': 'test'}) - layer = QgsVectorLayer(uri, 'test') + uri = QgsProviderRegistry.instance().encodeUri( + "ogr", {"path": tmpfile, "layerName": "test"} + ) + layer = QgsVectorLayer(uri, "test") self.assertTrue(layer.isValid()) # now save some metadata metadata = QgsLayerMetadata() - metadata.setAbstract('my abstract') - metadata.setIdentifier('my identifier') - metadata.setLicenses(['l1', 'l2']) + metadata.setAbstract("my abstract") + metadata.setIdentifier("my identifier") + metadata.setLicenses(["l1", "l2"]) layer.setMetadata(metadata) # save as default msg, res = layer.saveDefaultMetadata() self.assertTrue(res) # QMD sidecar should NOT exist -- metadata should be written to gpkg_metadata table - self.assertFalse(os.path.exists(os.path.join(self.basetestpath, 'testGeopackageSaveMetadataDefault.qmd'))) + self.assertFalse( + os.path.exists( + os.path.join(self.basetestpath, "testGeopackageSaveMetadataDefault.qmd") + ) + ) con = spatialite_connect(tmpfile, isolation_level=None) cur = con.cursor() # check that main gpkg_contents metadata columns have been updated - rs = cur.execute("SELECT identifier, description FROM gpkg_contents WHERE table_name='test'") + rs = cur.execute( + "SELECT identifier, description FROM gpkg_contents WHERE table_name='test'" + ) rows = [r for r in rs] self.assertEqual(len(rows), 1) - self.assertCountEqual(rows[0], ['my identifier', 'my abstract']) + self.assertCountEqual(rows[0], ["my identifier", "my abstract"]) - rs = cur.execute("SELECT md_file_id FROM gpkg_metadata_reference WHERE table_name='test'") + rs = cur.execute( + "SELECT md_file_id FROM gpkg_metadata_reference WHERE table_name='test'" + ) rows = [r for r in rs] file_ids = [row[0] for row in rows] self.assertTrue(file_ids) - rs = cur.execute("SELECT id, md_scope, mime_type, metadata FROM gpkg_metadata WHERE md_standard_uri='http://mrcc.com/qgis.dtd'") + rs = cur.execute( + "SELECT id, md_scope, mime_type, metadata FROM gpkg_metadata WHERE md_standard_uri='http://mrcc.com/qgis.dtd'" + ) res = [row for row in rs] self.assertEqual(len(res), 1) # id must match md_file_id from gpkg_metadata_reference self.assertIn(res[0][0], file_ids) - self.assertEqual(res[0][1], 'dataset') - self.assertEqual(res[0][2], 'text/xml') + self.assertEqual(res[0][1], "dataset") + self.assertEqual(res[0][2], "text/xml") con.close() # reload layer and check that metadata was restored - layer2 = QgsVectorLayer(uri, 'test') + layer2 = QgsVectorLayer(uri, "test") self.assertTrue(layer2.isValid()) - self.assertEqual(layer2.metadata().abstract(), 'my abstract') - self.assertEqual(layer2.metadata().identifier(), 'my identifier') - self.assertEqual(layer2.metadata().licenses(), ['l1', 'l2']) + self.assertEqual(layer2.metadata().abstract(), "my abstract") + self.assertEqual(layer2.metadata().identifier(), "my identifier") + self.assertEqual(layer2.metadata().licenses(), ["l1", "l2"]) def testUniqueValuesOnFidColumn(self): """Test regression #21311 OGR provider returns an empty set for GPKG uniqueValues""" - tmpfile = os.path.join(self.basetestpath, 'testGeopackageUniqueValuesOnFidColumn.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon) - lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) + tmpfile = os.path.join( + self.basetestpath, "testGeopackageUniqueValuesOnFidColumn.gpkg" + ) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon) + lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 1,1 1,1 0,0 0))')) - f.SetField('str_field', 'one') + f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON ((0 0,0 1,1 1,1 0,0 0))")) + f.SetField("str_field", "one") lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 2,2 2,2 0,0 0))')) - f.SetField('str_field', 'two') + f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON ((0 0,0 2,2 2,2 0,0 0))")) + f.SetField("str_field", "two") lyr.CreateFeature(f) f = None ds = None - vl1 = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + vl1 = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") self.assertTrue(vl1.isValid()) self.assertEqual(vl1.uniqueValues(0), {1, 2}) - self.assertEqual(vl1.uniqueValues(1), {'one', 'two'}) + self.assertEqual(vl1.uniqueValues(1), {"one", "two"}) def testForeignKeyViolation(self): """Test that we can open a dataset with a foreign key violation""" - tmpfile = os.path.join(self.basetestpath, 'testForeignKeyViolation.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) + tmpfile = os.path.join(self.basetestpath, "testForeignKeyViolation.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 1)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 1)")) lyr.CreateFeature(f) ds.ExecuteSQL("PRAGMA foreign_keys = OFF") ds.ExecuteSQL("CREATE TABLE foo(id INTEGER)") ds.ExecuteSQL( - "CREATE TABLE bar(fkey INTEGER, CONSTRAINT fkey_constraint FOREIGN KEY (fkey) REFERENCES foo(id))") + "CREATE TABLE bar(fkey INTEGER, CONSTRAINT fkey_constraint FOREIGN KEY (fkey) REFERENCES foo(id))" + ) ds.ExecuteSQL("INSERT INTO bar VALUES (1)") ds = None - vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") self.assertTrue(vl.isValid()) - fids = {f['fid'] for f in vl.getFeatures()} + fids = {f["fid"] for f in vl.getFeatures()} self.assertEqual(len(fids), 1) def testForeignKeyViolationAfterOpening(self): """Test that foreign keys are enforced""" - tmpfile = os.path.join(self.basetestpath, 'testForeignKeyViolationAfterOpening.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) + tmpfile = os.path.join( + self.basetestpath, "testForeignKeyViolationAfterOpening.gpkg" + ) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 1)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 1)")) lyr.CreateFeature(f) ds.ExecuteSQL( - "CREATE TABLE bar(fid INTEGER PRIMARY KEY, fkey INTEGER, CONSTRAINT fkey_constraint FOREIGN KEY (fkey) REFERENCES test(fid))") + "CREATE TABLE bar(fid INTEGER PRIMARY KEY, fkey INTEGER, CONSTRAINT fkey_constraint FOREIGN KEY (fkey) REFERENCES test(fid))" + ) ds = None - vl = QgsVectorLayer(f'{tmpfile}' + "|layername=bar", 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}" + "|layername=bar", "test", "ogr") self.assertTrue(vl.isValid()) # OK @@ -2148,120 +2511,156 @@ def testForeignKeyViolationAfterOpening(self): def testExportMultiFromShp(self): """Test if a Point is imported as single geom and MultiPoint as multi""" - single_tmpfile = os.path.join(self.basetestpath, 'testExportMultiFromShp_point.shp') - ds = ogr.GetDriverByName('ESRI Shapefile').CreateDataSource(single_tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) + single_tmpfile = os.path.join( + self.basetestpath, "testExportMultiFromShp_point.shp" + ) + ds = ogr.GetDriverByName("ESRI Shapefile").CreateDataSource(single_tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (0 0)')) - f.SetField('str_field', 'one') + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (0 0)")) + f.SetField("str_field", "one") lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (1 1)')) - f.SetField('str_field', 'two') + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (1 1)")) + f.SetField("str_field", "two") lyr.CreateFeature(f) f = None ds = None - multi_tmpfile = os.path.join(self.basetestpath, 'testExportMultiFromShp_multipoint.shp') - ds = ogr.GetDriverByName('ESRI Shapefile').CreateDataSource(multi_tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbMultiPoint) - lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) + multi_tmpfile = os.path.join( + self.basetestpath, "testExportMultiFromShp_multipoint.shp" + ) + ds = ogr.GetDriverByName("ESRI Shapefile").CreateDataSource(multi_tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbMultiPoint) + lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('MULTIPOINT ((0 0))')) - f.SetField('str_field', 'one') + f.SetGeometry(ogr.CreateGeometryFromWkt("MULTIPOINT ((0 0))")) + f.SetField("str_field", "one") lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('MULTIPOINT ((1 1), (2 2))')) - f.SetField('str_field', 'two') + f.SetGeometry(ogr.CreateGeometryFromWkt("MULTIPOINT ((1 1), (2 2))")) + f.SetField("str_field", "two") lyr.CreateFeature(f) f = None ds = None - tmpfile = os.path.join(self.basetestpath, 'testExportMultiFromShpMulti.gpkg') + tmpfile = os.path.join(self.basetestpath, "testExportMultiFromShpMulti.gpkg") options = {} - options['driverName'] = 'GPKG' - lyr = QgsVectorLayer(multi_tmpfile, 'y', 'ogr') + options["driverName"] = "GPKG" + lyr = QgsVectorLayer(multi_tmpfile, "y", "ogr") self.assertTrue(lyr.isValid()) self.assertEqual(lyr.featureCount(), 2) - err, _ = QgsVectorLayerExporter.exportLayer(lyr, tmpfile, "ogr", lyr.crs(), False, options) + err, _ = QgsVectorLayerExporter.exportLayer( + lyr, tmpfile, "ogr", lyr.crs(), False, options + ) self.assertEqual(err, 0) lyr = QgsVectorLayer(tmpfile, "y", "ogr") self.assertTrue(lyr.isValid()) self.assertEqual(lyr.wkbType(), QgsWkbTypes.Type.MultiPoint) features = lyr.getFeatures() f = next(features) - self.assertEqual(f.geometry().asWkt().upper(), 'MULTIPOINT ((0 0))') + self.assertEqual(f.geometry().asWkt().upper(), "MULTIPOINT ((0 0))") f = next(features) - self.assertEqual(f.geometry().asWkt().upper(), 'MULTIPOINT ((1 1),(2 2))') + self.assertEqual(f.geometry().asWkt().upper(), "MULTIPOINT ((1 1),(2 2))") - tmpfile = os.path.join(self.basetestpath, 'testExportMultiFromShpSingle.gpkg') + tmpfile = os.path.join(self.basetestpath, "testExportMultiFromShpSingle.gpkg") options = {} - options['driverName'] = 'GPKG' - lyr = QgsVectorLayer(single_tmpfile, 'y', 'ogr') + options["driverName"] = "GPKG" + lyr = QgsVectorLayer(single_tmpfile, "y", "ogr") self.assertTrue(lyr.isValid()) self.assertEqual(lyr.featureCount(), 2) - err, _ = QgsVectorLayerExporter.exportLayer(lyr, tmpfile, "ogr", lyr.crs(), False, options) + err, _ = QgsVectorLayerExporter.exportLayer( + lyr, tmpfile, "ogr", lyr.crs(), False, options + ) self.assertEqual(err, 0) lyr = QgsVectorLayer(tmpfile, "y", "ogr") self.assertTrue(lyr.isValid()) self.assertEqual(lyr.wkbType(), QgsWkbTypes.Type.Point) features = lyr.getFeatures() f = next(features) - self.assertEqual(f.geometry().asWkt().upper(), 'POINT (0 0)') + self.assertEqual(f.geometry().asWkt().upper(), "POINT (0 0)") f = next(features) - self.assertEqual(f.geometry().asWkt().upper(), 'POINT (1 1)') + self.assertEqual(f.geometry().asWkt().upper(), "POINT (1 1)") def testMinMaxDateField(self): """ Test that provider min/max calls work with date fields :return: """ - tmpfile = os.path.join(self.basetestpath, 'test_min_max_date_field.gpkg') - shutil.copy(TEST_DATA_DIR + '/' + 'qgis_server/test_project_api_timefilters.gpkg', tmpfile) + tmpfile = os.path.join(self.basetestpath, "test_min_max_date_field.gpkg") + shutil.copy( + TEST_DATA_DIR + "/" + "qgis_server/test_project_api_timefilters.gpkg", + tmpfile, + ) - vl = QgsVectorLayer(tmpfile, 'subset_test', 'ogr') + vl = QgsVectorLayer(tmpfile, "subset_test", "ogr") self.assertTrue(vl.isValid()) self.assertEqual(vl.fields().at(2).type(), QVariant.Date) self.assertEqual(vl.fields().at(3).type(), QVariant.DateTime) self.assertEqual(vl.dataProvider().minimumValue(2), QDate(2010, 1, 1)) self.assertEqual(vl.dataProvider().maximumValue(2), QDate(2019, 1, 1)) - self.assertEqual(vl.dataProvider().minimumValue(3), QDateTime(2010, 1, 1, 1, 1, 1, 0)) - self.assertEqual(vl.dataProvider().maximumValue(3), QDateTime(2022, 1, 1, 1, 1, 1, 0)) - self.assertEqual(vl.dataProvider().uniqueValues(2), - {QDate(2017, 1, 1), NULL, QDate(2018, 1, 1), QDate(2019, 1, 1), QDate(2010, 1, 1)}) - self.assertEqual(vl.dataProvider().uniqueValues(3), - {QDateTime(2022, 1, 1, 1, 1, 1), NULL, QDateTime(2019, 1, 1, 1, 1, 1), - QDateTime(2021, 1, 1, 1, 1, 1), QDateTime(2010, 1, 1, 1, 1, 1)}) + self.assertEqual( + vl.dataProvider().minimumValue(3), QDateTime(2010, 1, 1, 1, 1, 1, 0) + ) + self.assertEqual( + vl.dataProvider().maximumValue(3), QDateTime(2022, 1, 1, 1, 1, 1, 0) + ) + self.assertEqual( + vl.dataProvider().uniqueValues(2), + { + QDate(2017, 1, 1), + NULL, + QDate(2018, 1, 1), + QDate(2019, 1, 1), + QDate(2010, 1, 1), + }, + ) + self.assertEqual( + vl.dataProvider().uniqueValues(3), + { + QDateTime(2022, 1, 1, 1, 1, 1), + NULL, + QDateTime(2019, 1, 1, 1, 1, 1), + QDateTime(2021, 1, 1, 1, 1, 1), + QDateTime(2010, 1, 1, 1, 1, 1), + }, + ) def testExporterWithFIDColumn(self): """Test issue GH #34333, a memory layer with FID is not exported correctly to GPKG""" vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=FID:integer(0)&field=name:string(20)', - 'test', - 'memory') + "Point?crs=epsg:4326&field=FID:integer(0)&field=name:string(20)", + "test", + "memory", + ) - self.assertTrue(vl.isValid(), 'Provider not initialized') + self.assertTrue(vl.isValid(), "Provider not initialized") ft = QgsFeature(vl.fields()) - ft.setAttributes([123, 'text1']) - ft.setGeometry(QgsGeometry.fromWkt('Point(2 49)')) + ft.setAttributes([123, "text1"]) + ft.setGeometry(QgsGeometry.fromWkt("Point(2 49)")) myResult, myFeatures = vl.dataProvider().addFeatures([ft]) self.assertTrue(myResult) self.assertTrue(myFeatures) - dest_file_name = tempfile.mktemp('.gpkg') - err = QgsVectorLayerExporter.exportLayer(vl, dest_file_name, "ogr", vl.crs(), False) - self.assertEqual(err[0], QgsVectorLayerExporter.ExportError.NoError, - f'unexpected import error {err}') + dest_file_name = tempfile.mktemp(".gpkg") + err = QgsVectorLayerExporter.exportLayer( + vl, dest_file_name, "ogr", vl.crs(), False + ) + self.assertEqual( + err[0], + QgsVectorLayerExporter.ExportError.NoError, + f"unexpected import error {err}", + ) # Open result and check - created_layer = QgsVectorLayer(dest_file_name, 'test', 'ogr') + created_layer = QgsVectorLayer(dest_file_name, "test", "ogr") self.assertTrue(created_layer.isValid()) f = next(created_layer.getFeatures()) - self.assertEqual(f.geometry().asWkt(), 'Point (2 49)') - self.assertEqual(f.attributes(), [123, 'text1']) + self.assertEqual(f.geometry().asWkt(), "Point (2 49)") + self.assertEqual(f.attributes(), [123, "text1"]) self.assertEqual(f.id(), 123) def testTransactionGroup(self): @@ -2269,25 +2668,29 @@ def testTransactionGroup(self): project = QgsProject() project.setTransactionMode(Qgis.TransactionMode.AutomaticGroups) - tmpfile1 = os.path.join(self.basetestpath, 'tempGeoPackageTransactionGroup1.gpkg') - tmpfile2 = os.path.join(self.basetestpath, 'tempGeoPackageTransactionGroup2.gpkg') + tmpfile1 = os.path.join( + self.basetestpath, "tempGeoPackageTransactionGroup1.gpkg" + ) + tmpfile2 = os.path.join( + self.basetestpath, "tempGeoPackageTransactionGroup2.gpkg" + ) for tmpfile in (tmpfile1, tmpfile2): - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) for i in range(2): - lyr = ds.CreateLayer(f'test{i}', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) + lyr = ds.CreateLayer(f"test{i}", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (1 1)')) - f.SetField('str_field', 'one') + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (1 1)")) + f.SetField("str_field", "one") lyr.CreateFeature(f) - vl1_1 = QgsVectorLayer(tmpfile1, 'test1_1', 'ogr') + vl1_1 = QgsVectorLayer(tmpfile1, "test1_1", "ogr") self.assertTrue(vl1_1.isValid()) - vl1_2 = QgsVectorLayer(tmpfile1, 'test1_2', 'ogr') + vl1_2 = QgsVectorLayer(tmpfile1, "test1_2", "ogr") self.assertTrue(vl1_2.isValid()) - vl2_1 = QgsVectorLayer(tmpfile2, 'test2_1', 'ogr') + vl2_1 = QgsVectorLayer(tmpfile2, "test2_1", "ogr") self.assertTrue(vl2_1.isValid()) - vl2_2 = QgsVectorLayer(tmpfile2, 'test2_2', 'ogr') + vl2_2 = QgsVectorLayer(tmpfile2, "test2_2", "ogr") self.assertTrue(vl2_2.isValid()) project.addMapLayers([vl1_1, vl1_2, vl2_1, vl2_2]) @@ -2314,56 +2717,56 @@ def testTransactionGroupIterator(self): project = QgsProject() project.setTransactionMode(Qgis.TransactionMode.AutomaticGroups) tmpfile = os.path.join( - self.basetestpath, 'tempGeoPackageTransactionGroupIterator.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) + self.basetestpath, "tempGeoPackageTransactionGroupIterator.gpkg" + ) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (1 1)')) - f.SetField('str_field', 'one') + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (1 1)")) + f.SetField("str_field", "one") lyr.CreateFeature(f) del lyr del ds - vl = QgsVectorLayer(tmpfile + '|layername=test', 'test', 'ogr') + vl = QgsVectorLayer(tmpfile + "|layername=test", "test", "ogr") project.addMapLayers([vl]) self.assertTrue(vl.startEditing()) features = [f for f in vl.getFeatures()] for f in features: - self.assertTrue(vl.changeAttributeValue(1, 1, 'new value')) + self.assertTrue(vl.changeAttributeValue(1, 1, "new value")) # Test that QGIS sees the new changes - self.assertEqual(next(vl.getFeatures()).attribute(1), 'new value') + self.assertEqual(next(vl.getFeatures()).attribute(1), "new value") def testTransactionGroupCrash(self): """Test issue GH #39265 segfault""" project = QgsProject() project.setTransactionMode(Qgis.TransactionMode.AutomaticGroups) - tmpfile = os.path.join( - self.basetestpath, 'tempGeoPackageTransactionCrash.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) + tmpfile = os.path.join(self.basetestpath, "tempGeoPackageTransactionCrash.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (1 1)')) - f.SetField('str_field', 'one') + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT (1 1)")) + f.SetField("str_field", "one") lyr.CreateFeature(f) del lyr del ds - vl = QgsVectorLayer(tmpfile + '|layername=test', 'test', 'ogr') + vl = QgsVectorLayer(tmpfile + "|layername=test", "test", "ogr") project.addMapLayers([vl]) feature = next(vl.getFeatures()) - feature.setAttributes([None, 'two']) + feature.setAttributes([None, "two"]) self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeature(feature)) @@ -2372,30 +2775,44 @@ def testTransactionGroupCrash(self): self.assertTrue(vl.commitChanges(False)) # Now add another one - feature.setAttributes([None, 'three']) + feature.setAttributes([None, "three"]) self.assertTrue(vl.addFeature(feature)) self.assertTrue(vl.commitChanges(True)) - def _testVectorLayerExporterDeferredSpatialIndex(self, layerOptions, expectSpatialIndex): - """ Internal method """ + def _testVectorLayerExporterDeferredSpatialIndex( + self, layerOptions, expectSpatialIndex + ): + """Internal method""" tmpfile = os.path.join( - self.basetestpath, 'testVectorLayerExporterDeferredSpatialIndex.gpkg') + self.basetestpath, "testVectorLayerExporterDeferredSpatialIndex.gpkg" + ) if os.path.exists(tmpfile): os.unlink(tmpfile) options = {} - options['driverName'] = 'GPKG' - options['layerName'] = 'table1' + options["driverName"] = "GPKG" + options["layerName"] = "table1" if layerOptions: - options['layerOptions'] = layerOptions - exporter = QgsVectorLayerExporter(tmpfile, "ogr", QgsFields(), QgsWkbTypes.Type.Polygon, - QgsCoordinateReferenceSystem('EPSG:3111'), False, options) - self.assertFalse(exporter.errorCode(), - f'unexpected export error {exporter.errorCode()}: {exporter.errorMessage()}') + options["layerOptions"] = layerOptions + exporter = QgsVectorLayerExporter( + tmpfile, + "ogr", + QgsFields(), + QgsWkbTypes.Type.Polygon, + QgsCoordinateReferenceSystem("EPSG:3111"), + False, + options, + ) + self.assertFalse( + exporter.errorCode(), + f"unexpected export error {exporter.errorCode()}: {exporter.errorMessage()}", + ) # Check that at that point the rtree is *not* created ds = ogr.Open(tmpfile) - sql_lyr = ds.ExecuteSQL("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'gpkg_extensions'") + sql_lyr = ds.ExecuteSQL( + "SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'gpkg_extensions'" + ) assert sql_lyr.GetNextFeature() is None ds.ReleaseResultSet(sql_lyr) del ds @@ -2405,21 +2822,27 @@ def _testVectorLayerExporterDeferredSpatialIndex(self, layerOptions, expectSpati ds = gdal.OpenEx(tmpfile, gdal.OF_VECTOR) if expectSpatialIndex: # Check that at that point the rtree is created - sql_lyr = ds.ExecuteSQL("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'gpkg_extensions'") + sql_lyr = ds.ExecuteSQL( + "SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'gpkg_extensions'" + ) assert sql_lyr.GetNextFeature() is not None ds.ReleaseResultSet(sql_lyr) - sql_lyr = ds.ExecuteSQL("SELECT 1 FROM gpkg_extensions WHERE table_name = 'table1' AND extension_name = 'gpkg_rtree_index'") + sql_lyr = ds.ExecuteSQL( + "SELECT 1 FROM gpkg_extensions WHERE table_name = 'table1' AND extension_name = 'gpkg_rtree_index'" + ) assert sql_lyr.GetNextFeature() is not None ds.ReleaseResultSet(sql_lyr) else: # Check that at that point the rtree is *still not* created - sql_lyr = ds.ExecuteSQL("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'gpkg_extensions'") + sql_lyr = ds.ExecuteSQL( + "SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'gpkg_extensions'" + ) assert sql_lyr.GetNextFeature() is None ds.ReleaseResultSet(sql_lyr) return ds def testVectorLayerExporterDeferredSpatialIndexNoLayerOptions(self): - """ Check that a deferred spatial index is created when no layer creation options is provided """ + """Check that a deferred spatial index is created when no layer creation options is provided""" ds = self._testVectorLayerExporterDeferredSpatialIndex(None, True) filename = ds.GetDescription() @@ -2427,45 +2850,57 @@ def testVectorLayerExporterDeferredSpatialIndexNoLayerOptions(self): gdal.Unlink(filename) def testVectorLayerExporterDeferredSpatialIndexLayerOptions(self): - """ Check that a deferred spatial index is created when other layer creations options is provided """ + """Check that a deferred spatial index is created when other layer creations options is provided""" - ds = self._testVectorLayerExporterDeferredSpatialIndex(['GEOMETRY_NAME=my_geom'], True) + ds = self._testVectorLayerExporterDeferredSpatialIndex( + ["GEOMETRY_NAME=my_geom"], True + ) lyr = ds.GetLayer(0) - self.assertEqual(lyr.GetGeometryColumn(), 'my_geom') + self.assertEqual(lyr.GetGeometryColumn(), "my_geom") filename = ds.GetDescription() del ds gdal.Unlink(filename) def testVectorLayerExporterDeferredSpatialIndexExplicitSpatialIndexAsked(self): - """ Check that a deferred spatial index is created when explicit asked """ + """Check that a deferred spatial index is created when explicit asked""" - ds = self._testVectorLayerExporterDeferredSpatialIndex(['SPATIAL_INDEX=YES'], True) + ds = self._testVectorLayerExporterDeferredSpatialIndex( + ["SPATIAL_INDEX=YES"], True + ) filename = ds.GetDescription() del ds gdal.Unlink(filename) def testVectorLayerExporterDeferredSpatialIndexSpatialIndexDisallowed(self): - """ Check that a deferred spatial index is NOT created when explicit disallowed """ + """Check that a deferred spatial index is NOT created when explicit disallowed""" - ds = self._testVectorLayerExporterDeferredSpatialIndex(['SPATIAL_INDEX=NO'], False) + ds = self._testVectorLayerExporterDeferredSpatialIndex( + ["SPATIAL_INDEX=NO"], False + ) filename = ds.GetDescription() del ds gdal.Unlink(filename) def testRollback(self): - """ Test that a failed operation is properly rolled back """ - tmpfile = os.path.join(self.basetestpath, 'testRollback.gpkg') + """Test that a failed operation is properly rolled back""" + tmpfile = os.path.join(self.basetestpath, "testRollback.gpkg") - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['SPATIAL_INDEX=NO']) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer( + "test", geom_type=ogr.wkbPoint, options=["SPATIAL_INDEX=NO"] + ) # Ugly hack to be able to create a column with unique constraint with GDAL < 3.2 - ds.ExecuteSQL('CREATE TABLE test2 ("fid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "geom" POINT, v INTEGER, v_unique INTEGER UNIQUE)') + ds.ExecuteSQL( + 'CREATE TABLE test2 ("fid" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "geom" POINT, v INTEGER, v_unique INTEGER UNIQUE)' + ) ds.ExecuteSQL("UPDATE gpkg_contents SET table_name = 'test2'") ds.ExecuteSQL("UPDATE gpkg_geometry_columns SET table_name = 'test2'") - ds.ExecuteSQL('INSERT INTO test2 (fid, geom, v, v_unique) VALUES (1, NULL, -1, 123)') + ds.ExecuteSQL( + "INSERT INTO test2 (fid, geom, v, v_unique) VALUES (1, NULL, -1, 123)" + ) ds = None - vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr") self.assertTrue(vl.isValid()) features = [f for f in vl.getFeatures()] @@ -2491,132 +2926,161 @@ def testRollback(self): self.assertEqual(features[1].attributes(), [2, -4, 125]) def testFixWrongMetadataReferenceColumnNameUpdate(self): - """ Test that we (or GDAL) fixes wrong gpkg_metadata_reference_column_name_update trigger """ - tmpfile = os.path.join(self.basetestpath, 'testFixWrongMetadataReferenceColumnNameUpdate.gpkg') + """Test that we (or GDAL) fixes wrong gpkg_metadata_reference_column_name_update trigger""" + tmpfile = os.path.join( + self.basetestpath, "testFixWrongMetadataReferenceColumnNameUpdate.gpkg" + ) - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - ds.CreateLayer('test', geom_type=ogr.wkbPoint) - ds.SetMetadata('FOO', 'BAR') + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + ds.CreateLayer("test", geom_type=ogr.wkbPoint) + ds.SetMetadata("FOO", "BAR") ds = None ds = ogr.Open(tmpfile, update=1) gdal.PushErrorHandler() try: - ds.ExecuteSQL('DROP TRIGGER gpkg_metadata_reference_column_name_update') + ds.ExecuteSQL("DROP TRIGGER gpkg_metadata_reference_column_name_update") except Exception: pass gdal.PopErrorHandler() # inject wrong trigger on purpose - wrong_trigger = "CREATE TRIGGER 'gpkg_metadata_reference_column_name_update' " + \ - "BEFORE UPDATE OF column_name ON 'gpkg_metadata_reference' " + \ - "FOR EACH ROW BEGIN " + \ - "SELECT RAISE(ABORT, 'update on table gpkg_metadata_reference " + \ - "violates constraint: column name must be NULL when reference_scope " + \ - "is \"geopackage\", \"table\" or \"row\"') " + \ - "WHERE (NEW.reference_scope IN ('geopackage','table','row') " + \ - "AND NEW.column_nameIS NOT NULL); END;" + wrong_trigger = ( + "CREATE TRIGGER 'gpkg_metadata_reference_column_name_update' " + + "BEFORE UPDATE OF column_name ON 'gpkg_metadata_reference' " + + "FOR EACH ROW BEGIN " + + "SELECT RAISE(ABORT, 'update on table gpkg_metadata_reference " + + "violates constraint: column name must be NULL when reference_scope " + + 'is "geopackage", "table" or "row"\') ' + + "WHERE (NEW.reference_scope IN ('geopackage','table','row') " + + "AND NEW.column_nameIS NOT NULL); END;" + ) ds.ExecuteSQL(wrong_trigger) ds = None - vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr") self.assertTrue(vl.isValid()) del vl # Check trigger afterwards ds = ogr.Open(tmpfile) sql_lyr = ds.ExecuteSQL( - "SELECT sql FROM sqlite_master WHERE type = 'trigger' " + - "AND name = 'gpkg_metadata_reference_column_name_update'") + "SELECT sql FROM sqlite_master WHERE type = 'trigger' " + + "AND name = 'gpkg_metadata_reference_column_name_update'" + ) f = sql_lyr.GetNextFeature() - sql = f['sql'] + sql = f["sql"] ds.ReleaseResultSet(sql_lyr) ds = None gdal.Unlink(tmpfile) - self.assertNotIn('column_nameIS', sql) + self.assertNotIn("column_nameIS", sql) def testRejectedGeometryUpdate(self): """Test that we correctly behave when a geometry update fails""" - tmpfile = os.path.join(self.basetestpath, 'testRejectedGeometryUpdate.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbUnknown) + tmpfile = os.path.join(self.basetestpath, "testRejectedGeometryUpdate.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbUnknown) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 1,1 1,1 0,0 0))')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON ((0 0,0 1,1 1,1 0,0 0))")) lyr.CreateFeature(f) - ds.ExecuteSQL("CREATE TRIGGER rejectGeometryUpdate BEFORE UPDATE OF geom ON test FOR EACH ROW BEGIN SELECT RAISE(ABORT, 'update forbidden'); END;") + ds.ExecuteSQL( + "CREATE TRIGGER rejectGeometryUpdate BEFORE UPDATE OF geom ON test FOR EACH ROW BEGIN SELECT RAISE(ABORT, 'update forbidden'); END;" + ) f = None ds = None - vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") self.assertTrue(vl.isValid()) self.assertTrue(vl.startEditing()) - self.assertTrue(vl.changeGeometry(1, QgsGeometry.fromWkt('Point (0 0)'))) + self.assertTrue(vl.changeGeometry(1, QgsGeometry.fromWkt("Point (0 0)"))) self.assertFalse(vl.commitChanges()) - vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") self.assertTrue(vl.isValid()) g = [f.geometry() for f in vl.getFeatures()][0] - self.assertEqual(g.asWkt(), 'Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))') + self.assertEqual(g.asWkt(), "Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))") def testSubsetComments(self): """Test issue GH #45754""" tmp_dir = QTemporaryDir() - tmpfile = os.path.join(tmp_dir.path(), 'testSubsetComments.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('my--test', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('text_field', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('my--thing\'s', ogr.OFTString)) + tmpfile = os.path.join(tmp_dir.path(), "testSubsetComments.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("my--test", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("text_field", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("my--thing's", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)')) - f['text_field'] = 'one' - f['my--thing\'s'] = 'one' + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 0)")) + f["text_field"] = "one" + f["my--thing's"] = "one" lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f['text_field'] = 'two' - f['my--thing\'s'] = 'my "things -- all' - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(1 1)')) + f["text_field"] = "two" + f["my--thing's"] = 'my "things -- all' + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(1 1)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f['text_field'] = 'three' - f['my--thing\'s'] = 'my "things \n all' - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(2 2)')) + f["text_field"] = "three" + f["my--thing's"] = 'my "things \n all' + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(2 2)")) lyr.CreateFeature(f) - del (lyr) + del lyr def _test(subset_string): - vl1 = QgsVectorLayer(f'{tmpfile}|subset={subset_string}'.format(tmpfile, subset_string), 'test', 'ogr') + vl1 = QgsVectorLayer( + f"{tmpfile}|subset={subset_string}".format(tmpfile, subset_string), + "test", + "ogr", + ) self.assertTrue(vl1.isValid()) self.assertEqual(vl1.featureCount(), 1) - _test('-- comment\n SELECT * --comment\nFROM "my--test" WHERE text_field=\'one\'') - _test('\n SELECT * --comment\nFROM "my--test" WHERE\n-- comment \ntext_field=\'one\'') - _test(' SELECT * --comment\nFROM "my--test" WHERE\ntext_field=\'one\' AND \ntext_field != \'--embedded comment\'') - _test('SELECT * FROM "my--test" WHERE text_field=\'one\' AND text_field != \' \\\'--embedded comment\'') - _test('select "my--thing\'s" from "my--test" where "my--thing\'s" = \'my "things -- all\'') - _test('select "my--thing\'s" from "my--test" where "my--thing\'s" = \'my "things \n all\'') + _test( + "-- comment\n SELECT * --comment\nFROM \"my--test\" WHERE text_field='one'" + ) + _test( + "\n SELECT * --comment\nFROM \"my--test\" WHERE\n-- comment \ntext_field='one'" + ) + _test( + " SELECT * --comment\nFROM \"my--test\" WHERE\ntext_field='one' AND \ntext_field != '--embedded comment'" + ) + _test( + "SELECT * FROM \"my--test\" WHERE text_field='one' AND text_field != ' \\'--embedded comment'" + ) + _test( + 'select "my--thing\'s" from "my--test" where "my--thing\'s" = \'my "things -- all\'' + ) + _test( + 'select "my--thing\'s" from "my--test" where "my--thing\'s" = \'my "things \n all\'' + ) def testIsSqlQuery(self): """Test that isQuery returns what it should in case of simple filters""" tmp_dir = QTemporaryDir() - tmpfile = os.path.join(tmp_dir.path(), 'testQueryLayers.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('text_field', ogr.OFTString)) + tmpfile = os.path.join(tmp_dir.path(), "testQueryLayers.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("text_field", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)')) - f['text_field'] = 'one' + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 0)")) + f["text_field"] = "one" lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f['text_field'] = 'two' - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(1 1)')) + f["text_field"] = "two" + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(1 1)")) lyr.CreateFeature(f) - del (lyr) + del lyr - vl1 = QgsVectorLayer(f'{tmpfile}|subset=SELECT * FROM test WHERE "text_field"=\'one\''.format(tmpfile), 'test', 'ogr') + vl1 = QgsVectorLayer( + f"{tmpfile}|subset=SELECT * FROM test WHERE \"text_field\"='one'".format( + tmpfile + ), + "test", + "ogr", + ) self.assertTrue(vl1.isValid()) self.assertTrue(vl1.isSqlQuery()) self.assertEqual(vl1.featureCount(), 1) @@ -2624,7 +3088,9 @@ def testIsSqlQuery(self): # Test flags self.assertTrue(vl1.vectorLayerTypeFlags() & Qgis.VectorLayerTypeFlag.SqlQuery) - vl2 = QgsVectorLayer(f'{tmpfile}|subset="text_field"=\'one\''.format(tmpfile), 'test', 'ogr') + vl2 = QgsVectorLayer( + f"{tmpfile}|subset=\"text_field\"='one'".format(tmpfile), "test", "ogr" + ) self.assertTrue(vl2.isValid()) self.assertFalse(vl2.isSqlQuery()) self.assertEqual(vl2.featureCount(), 1) @@ -2633,112 +3099,155 @@ def testIsSqlQuery(self): self.assertFalse(vl2.vectorLayerTypeFlags() & Qgis.VectorLayerTypeFlag.SqlQuery) def testCircularStringOnlyInUnknownTypeLayer(self): - """ Test bugfix for https://github.com/qgis/QGIS/issues/47610 """ + """Test bugfix for https://github.com/qgis/QGIS/issues/47610""" - tmpfile = os.path.join(self.basetestpath, 'testCircularStringOnlyInUnknownTypeLayer.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbUnknown) + tmpfile = os.path.join( + self.basetestpath, "testCircularStringOnlyInUnknownTypeLayer.gpkg" + ) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbUnknown) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('CIRCULARSTRING(0 0,1 1,2 0)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("CIRCULARSTRING(0 0,1 1,2 0)")) lyr.CreateFeature(f) ds = None - vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr") self.assertEqual(1, vl.dataProvider().subLayerCount()) - self.assertEqual(vl.dataProvider().subLayers(), - [QgsDataProvider.SUBLAYER_SEPARATOR.join(['0', 'test', '1', 'CircularString', 'geom', ''])]) + self.assertEqual( + vl.dataProvider().subLayers(), + [ + QgsDataProvider.SUBLAYER_SEPARATOR.join( + ["0", "test", "1", "CircularString", "geom", ""] + ) + ], + ) - vl = QgsVectorLayer(f'{tmpfile}' + '|geometryType=CircularString', 'test', 'ogr') + vl = QgsVectorLayer( + f"{tmpfile}" + "|geometryType=CircularString", "test", "ogr" + ) got = [feat for feat in vl.getFeatures()] self.assertEqual(len(got), 1) def testCompoundCurveOnlyInUnknownTypeLayer(self): - """ Test bugfix for https://github.com/qgis/QGIS/issues/47610 """ + """Test bugfix for https://github.com/qgis/QGIS/issues/47610""" - tmpfile = os.path.join(self.basetestpath, 'testCompoundCurveOnlyInUnknownTypeLayer.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbUnknown) + tmpfile = os.path.join( + self.basetestpath, "testCompoundCurveOnlyInUnknownTypeLayer.gpkg" + ) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbUnknown) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('COMPOUNDCURVE((7 8,9 10))')) + f.SetGeometry(ogr.CreateGeometryFromWkt("COMPOUNDCURVE((7 8,9 10))")) lyr.CreateFeature(f) ds = None - vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr") self.assertEqual(1, vl.dataProvider().subLayerCount()) - self.assertEqual(vl.dataProvider().subLayers(), - [QgsDataProvider.SUBLAYER_SEPARATOR.join(['0', 'test', '1', 'CompoundCurve', 'geom', ''])]) - - vl = QgsVectorLayer(f'{tmpfile}' + '|geometryType=CompoundCurve', 'test', 'ogr') + self.assertEqual( + vl.dataProvider().subLayers(), + [ + QgsDataProvider.SUBLAYER_SEPARATOR.join( + ["0", "test", "1", "CompoundCurve", "geom", ""] + ) + ], + ) + + vl = QgsVectorLayer(f"{tmpfile}" + "|geometryType=CompoundCurve", "test", "ogr") got = [feat for feat in vl.getFeatures()] self.assertEqual(len(got), 1) def testCurvePolygonOnlyInUnknownTypeLayer(self): - """ Test bugfix for https://github.com/qgis/QGIS/issues/47610 """ + """Test bugfix for https://github.com/qgis/QGIS/issues/47610""" - tmpfile = os.path.join(self.basetestpath, 'testCurvePolygonOnlyInUnknownTypeLayer.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbUnknown) + tmpfile = os.path.join( + self.basetestpath, "testCurvePolygonOnlyInUnknownTypeLayer.gpkg" + ) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbUnknown) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('CURVEPOLYGON((10 10,10 11,11 11,10 10))')) + f.SetGeometry( + ogr.CreateGeometryFromWkt("CURVEPOLYGON((10 10,10 11,11 11,10 10))") + ) lyr.CreateFeature(f) ds = None - vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr") self.assertEqual(1, vl.dataProvider().subLayerCount()) - self.assertEqual(vl.dataProvider().subLayers(), - [QgsDataProvider.SUBLAYER_SEPARATOR.join(['0', 'test', '1', 'CurvePolygon', 'geom', ''])]) - - vl = QgsVectorLayer(f'{tmpfile}' + '|geometryType=CurvePolygon', 'test', 'ogr') + self.assertEqual( + vl.dataProvider().subLayers(), + [ + QgsDataProvider.SUBLAYER_SEPARATOR.join( + ["0", "test", "1", "CurvePolygon", "geom", ""] + ) + ], + ) + + vl = QgsVectorLayer(f"{tmpfile}" + "|geometryType=CurvePolygon", "test", "ogr") got = [feat for feat in vl.getFeatures()] self.assertEqual(len(got), 1) def testCurveGeometryTypeInUnknownTypeLayer(self): - """ Test bugfix for https://github.com/qgis/QGIS/issues/47610 """ + """Test bugfix for https://github.com/qgis/QGIS/issues/47610""" - tmpfile = os.path.join(self.basetestpath, 'testFilterCurveGeometryType.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbUnknown) + tmpfile = os.path.join(self.basetestpath, "testFilterCurveGeometryType.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbUnknown) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('CIRCULARSTRING(0 0,1 1,2 0)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("CIRCULARSTRING(0 0,1 1,2 0)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('CIRCULARSTRING Z(0 -10 10,1 -11 10,2 -10 10)')) + f.SetGeometry( + ogr.CreateGeometryFromWkt("CIRCULARSTRING Z(0 -10 10,1 -11 10,2 -10 10)") + ) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('MULTILINESTRING((3 4,5 6))')) + f.SetGeometry(ogr.CreateGeometryFromWkt("MULTILINESTRING((3 4,5 6))")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('COMPOUNDCURVE((7 8,9 10))')) + f.SetGeometry(ogr.CreateGeometryFromWkt("COMPOUNDCURVE((7 8,9 10))")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('CURVEPOLYGON((10 10,10 11,11 11,10 10))')) + f.SetGeometry( + ogr.CreateGeometryFromWkt("CURVEPOLYGON((10 10,10 11,11 11,10 10))") + ) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POLYGON((10 20,10 21,11 21,10 20))')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON((10 20,10 21,11 21,10 20))")) lyr.CreateFeature(f) ds = None - vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr") self.assertEqual(1, vl.dataProvider().subLayerCount()) - self.assertEqual(vl.dataProvider().subLayers(), - [QgsDataProvider.SUBLAYER_SEPARATOR.join(['0', 'test', '4', 'CompoundCurve', 'geom', '']), - QgsDataProvider.SUBLAYER_SEPARATOR.join(['0', 'test', '2', 'CurvePolygon', 'geom', ''])]) - - vl = QgsVectorLayer(f'{tmpfile}' + '|geometryType=CompoundCurve', 'test', 'ogr') + self.assertEqual( + vl.dataProvider().subLayers(), + [ + QgsDataProvider.SUBLAYER_SEPARATOR.join( + ["0", "test", "4", "CompoundCurve", "geom", ""] + ), + QgsDataProvider.SUBLAYER_SEPARATOR.join( + ["0", "test", "2", "CurvePolygon", "geom", ""] + ), + ], + ) + + vl = QgsVectorLayer(f"{tmpfile}" + "|geometryType=CompoundCurve", "test", "ogr") got = [feat for feat in vl.getFeatures()] self.assertEqual(len(got), 4) - vl = QgsVectorLayer(f'{tmpfile}' + '|geometryType=CurvePolygon', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}" + "|geometryType=CurvePolygon", "test", "ogr") got = [feat for feat in vl.getFeatures()] self.assertEqual(len(got), 2) def testCreateEmptyDatabase(self): - """ Test creating an empty database via the provider metadata """ - metadata = QgsProviderRegistry.instance().providerMetadata('ogr') - self.assertTrue(metadata.capabilities() & QgsProviderMetadata.ProviderMetadataCapability.CreateDatabase) + """Test creating an empty database via the provider metadata""" + metadata = QgsProviderRegistry.instance().providerMetadata("ogr") + self.assertTrue( + metadata.capabilities() + & QgsProviderMetadata.ProviderMetadataCapability.CreateDatabase + ) with tempfile.TemporaryDirectory() as dest_dir: - database_path = os.path.join(dest_dir, 'new_gpkg.gpkg') + database_path = os.path.join(dest_dir, "new_gpkg.gpkg") ok, err = metadata.createDatabase(database_path) self.assertTrue(ok) self.assertFalse(err) @@ -2751,16 +3260,23 @@ def testCreateEmptyDatabase(self): def testDateTimeTimeZoneMilliseconds(self): - tmpfile = os.path.join(self.basetestpath, 'testDateTimeTimeZoneMilliseconds.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbMultiPolygon) - lyr.CreateField(ogr.FieldDefn('dt', ogr.OFTDateTime)) + tmpfile = os.path.join( + self.basetestpath, "testDateTimeTimeZoneMilliseconds.gpkg" + ) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbMultiPolygon) + lyr.CreateField(ogr.FieldDefn("dt", ogr.OFTDateTime)) ds = None - vl = QgsVectorLayer(tmpfile, 'test', 'ogr') + vl = QgsVectorLayer(tmpfile, "test", "ogr") f = QgsFeature(vl.fields()) - dt = QDateTime(QDate(2023, 1, 28), QTime(12, 34, 56, 789), Qt.TimeSpec.OffsetFromUTC, 1 * 3600 + 30 * 60) + dt = QDateTime( + QDate(2023, 1, 28), + QTime(12, 34, 56, 789), + Qt.TimeSpec.OffsetFromUTC, + 1 * 3600 + 30 * 60, + ) f.setAttribute(1, dt) self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([f])) @@ -2770,7 +3286,12 @@ def testDateTimeTimeZoneMilliseconds(self): self.assertEqual(got[0]["dt"], dt) self.assertTrue(vl.startEditing()) - new_dt = QDateTime(QDate(2023, 1, 27), QTime(12, 34, 56, 987), Qt.TimeSpec.OffsetFromUTC, 2 * 3600 + 30 * 60) + new_dt = QDateTime( + QDate(2023, 1, 27), + QTime(12, 34, 56, 987), + Qt.TimeSpec.OffsetFromUTC, + 2 * 3600 + 30 * 60, + ) self.assertTrue(vl.changeAttributeValue(1, 1, new_dt)) self.assertTrue(vl.commitChanges()) @@ -2779,16 +3300,18 @@ def testDateTimeTimeZoneMilliseconds(self): def testWriteDateTimeFromLocalTime(self): - tmpfile = os.path.join(self.basetestpath, 'testWriteDateTimeFromLocalTime.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbNone) - lyr.CreateField(ogr.FieldDefn('dt', ogr.OFTDateTime)) + tmpfile = os.path.join(self.basetestpath, "testWriteDateTimeFromLocalTime.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbNone) + lyr.CreateField(ogr.FieldDefn("dt", ogr.OFTDateTime)) ds = None - vl = QgsVectorLayer(tmpfile, 'test', 'ogr') + vl = QgsVectorLayer(tmpfile, "test", "ogr") f = QgsFeature(vl.fields()) - dt = QDateTime(QDate(2023, 1, 28), QTime(12, 34, 56, 789), Qt.TimeSpec.LocalTime) + dt = QDateTime( + QDate(2023, 1, 28), QTime(12, 34, 56, 789), Qt.TimeSpec.LocalTime + ) f.setAttribute(1, dt) self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([f])) @@ -2812,10 +3335,10 @@ def testTransactionModeAutoWithFilter(self): filename = os.path.join(temp_path, "test.gpkg") ds = ogr.GetDriverByName("GPKG").CreateDataSource(filename) lyr = ds.CreateLayer("points", geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('name', ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("name", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f['name'] = 'a' - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(1 2)')) + f["name"] = "a" + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(1 2)")) lyr.CreateFeature(f) f = None ds = None @@ -2824,19 +3347,19 @@ def testTransactionModeAutoWithFilter(self): vl = QgsVectorLayer(filename) self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 1) - self.assertEqual(next(vl.getFeatures())['name'], 'a') + self.assertEqual(next(vl.getFeatures())["name"], "a") p = QgsProject() p.setAutoTransaction(True) self.assertTrue(p.addMapLayers([vl])) - self.assertTrue(vl.setSubsetString('"name" IN (\'a\', \'b\')')) + self.assertTrue(vl.setSubsetString("\"name\" IN ('a', 'b')")) self.assertEqual(vl.featureCount(), 1) self.assertTrue(vl.startEditing()) # Add feature f = QgsFeature(vl.fields()) - f.setAttribute('name', 'b') - g = QgsGeometry.fromWkt('POINT(3 4)') + f.setAttribute("name", "b") + g = QgsGeometry.fromWkt("POINT(3 4)") f.setGeometry(g) # This triggers the issue because it sets the subset filter @@ -2847,16 +3370,16 @@ def testTransactionModeAutoWithFilter(self): self.assertTrue(vl.addFeatures([f])) self.assertTrue(vl.commitChanges()) self.assertEqual(vl.featureCount(), 2) - attrs = [f['name'] for f in vl.getFeatures()] - self.assertEqual(attrs, ['a', 'b']) + attrs = [f["name"] for f in vl.getFeatures()] + self.assertEqual(attrs, ["a", "b"]) # verify del p vl2 = QgsVectorLayer(filename) self.assertTrue(vl2.isValid()) self.assertEqual(vl2.featureCount(), 2) - attrs = [f['name'] for f in vl2.getFeatures()] - self.assertEqual(attrs, ['a', 'b']) + attrs = [f["name"] for f in vl2.getFeatures()] + self.assertEqual(attrs, ["a", "b"]) def testChangeAttributeValuesOptimization(self): """Test issuing 'UPDATE layer SET column_name = constant' when possible""" @@ -2864,19 +3387,21 @@ def testChangeAttributeValuesOptimization(self): # Below value comes from QgsOgrProvider::changeAttributeValues() THRESHOLD_UPDATE_OPTIM = 100 - tmpfile = os.path.join(self.basetestpath, 'testChangeAttributeValuesOptimization.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('int_field', ogr.OFTInteger)) - lyr.CreateField(ogr.FieldDefn('int64_field', ogr.OFTInteger64)) - lyr.CreateField(ogr.FieldDefn('real_field', ogr.OFTReal)) + tmpfile = os.path.join( + self.basetestpath, "testChangeAttributeValuesOptimization.gpkg" + ) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("int_field", ogr.OFTInteger)) + lyr.CreateField(ogr.FieldDefn("int64_field", ogr.OFTInteger64)) + lyr.CreateField(ogr.FieldDefn("real_field", ogr.OFTReal)) for i in range(THRESHOLD_UPDATE_OPTIM + 1): f = ogr.Feature(lyr.GetLayerDefn()) lyr.CreateFeature(f) ds = None - vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") # Does not trigger the optim: not constant value field_name, value, other_value = "str_field", "my_value", "other_value" @@ -2890,7 +3415,7 @@ def testChangeAttributeValuesOptimization(self): vl.commitChanges() got = [feat[field_name] for feat in vl.getFeatures()] - self.assertEqual(set(got), set([value, other_value])) + self.assertEqual(set(got), {value, other_value}) # Does not trigger the optim: update of different fields vl.startEditing() @@ -2904,9 +3429,9 @@ def testChangeAttributeValuesOptimization(self): vl.commitChanges() got = [feat["int_field"] for feat in vl.getFeatures()] - self.assertEqual(set(got), set([1, NULL])) + self.assertEqual(set(got), {1, NULL}) got = [feat["int64_field"] for feat in vl.getFeatures()] - self.assertEqual(set(got), set([1, NULL])) + self.assertEqual(set(got), {1, NULL}) # Does not trigger the optim: not all features updated vl.startEditing() @@ -2918,15 +3443,16 @@ def testChangeAttributeValuesOptimization(self): vl.commitChanges() got = [feat["real_field"] for feat in vl.getFeatures()] - self.assertEqual(set(got), set([1.5, NULL])) + self.assertEqual(set(got), {1.5, NULL}) # Triggers the optim - for field_name, value in [("str_field", "my_value"), - ("int_field", 123), - ("int64_field", 1234567890123), - ("real_field", 2.5), - ("real_field", None), - ]: + for field_name, value in [ + ("str_field", "my_value"), + ("int_field", 123), + ("int64_field", 1234567890123), + ("real_field", 2.5), + ("real_field", None), + ]: vl.startEditing() fieldid = vl.fields().indexFromName(field_name) for feature in vl.getFeatures(): @@ -2935,29 +3461,31 @@ def testChangeAttributeValuesOptimization(self): got = [feat[field_name] for feat in vl.getFeatures()] if value: - self.assertEqual(set(got), set([value])) + self.assertEqual(set(got), {value}) else: - self.assertEqual(set(got), set([NULL])) + self.assertEqual(set(got), {NULL}) def testChangeAttributeValuesErrors(self): - tmpfile = os.path.join(self.basetestpath, 'testChangeAttributeValuesErrors.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) - lyr.CreateField(ogr.FieldDefn('int_field', ogr.OFTInteger)) - lyr.CreateField(ogr.FieldDefn('int64_field', ogr.OFTInteger64)) - lyr.CreateField(ogr.FieldDefn('real_field', ogr.OFTReal)) - lyr.CreateField(ogr.FieldDefn('datetime_field', ogr.OFTDateTime)) - lyr.CreateField(ogr.FieldDefn('date_field', ogr.OFTDateTime)) - lyr.CreateField(ogr.FieldDefn('string_field', ogr.OFTString)) - fld_defn = ogr.FieldDefn('bool_field', ogr.OFTInteger) + tmpfile = os.path.join( + self.basetestpath, "testChangeAttributeValuesErrors.gpkg" + ) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) + lyr.CreateField(ogr.FieldDefn("int_field", ogr.OFTInteger)) + lyr.CreateField(ogr.FieldDefn("int64_field", ogr.OFTInteger64)) + lyr.CreateField(ogr.FieldDefn("real_field", ogr.OFTReal)) + lyr.CreateField(ogr.FieldDefn("datetime_field", ogr.OFTDateTime)) + lyr.CreateField(ogr.FieldDefn("date_field", ogr.OFTDateTime)) + lyr.CreateField(ogr.FieldDefn("string_field", ogr.OFTString)) + fld_defn = ogr.FieldDefn("bool_field", ogr.OFTInteger) fld_defn.SetSubType(ogr.OFSTBoolean) lyr.CreateField(fld_defn) f = ogr.Feature(lyr.GetLayerDefn()) lyr.CreateFeature(f) ds = None - vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") # Changing feature id of feature 1 is not allowed self.assertFalse(vl.dataProvider().changeAttributeValues({1: {0: "asdf"}})) @@ -2973,11 +3501,21 @@ def testChangeAttributeValuesErrors(self): self.assertFalse(vl.dataProvider().changeAttributeValues({1: {"invalid": 1}})) # wrong data type for attribute ... of feature 1 - self.assertFalse(vl.dataProvider().changeAttributeValues({1: {1: "not a integer"}})) - self.assertFalse(vl.dataProvider().changeAttributeValues({1: {2: "not a integer64"}})) - self.assertFalse(vl.dataProvider().changeAttributeValues({1: {3: "not a double"}})) - self.assertFalse(vl.dataProvider().changeAttributeValues({1: {4: "not a datetime"}})) - self.assertFalse(vl.dataProvider().changeAttributeValues({1: {5: "not a date"}})) + self.assertFalse( + vl.dataProvider().changeAttributeValues({1: {1: "not a integer"}}) + ) + self.assertFalse( + vl.dataProvider().changeAttributeValues({1: {2: "not a integer64"}}) + ) + self.assertFalse( + vl.dataProvider().changeAttributeValues({1: {3: "not a double"}}) + ) + self.assertFalse( + vl.dataProvider().changeAttributeValues({1: {4: "not a datetime"}}) + ) + self.assertFalse( + vl.dataProvider().changeAttributeValues({1: {5: "not a date"}}) + ) # wrong value for attribute 7 of feature 1: wrong self.assertFalse(vl.dataProvider().changeAttributeValues({1: {7: "wrong"}})) @@ -2987,15 +3525,25 @@ def testChangeAttributeValuesErrors(self): self.assertTrue(vl.dataProvider().changeAttributeValues({1: {1: 1}})) # int64_field self.assertTrue(vl.dataProvider().changeAttributeValues({1: {2: 1}})) - self.assertTrue(vl.dataProvider().changeAttributeValues({1: {2: 1234567890123}})) + self.assertTrue( + vl.dataProvider().changeAttributeValues({1: {2: 1234567890123}}) + ) # real_field self.assertTrue(vl.dataProvider().changeAttributeValues({1: {3: 1}})) - self.assertTrue(vl.dataProvider().changeAttributeValues({1: {3: 1234567890123}})) + self.assertTrue( + vl.dataProvider().changeAttributeValues({1: {3: 1234567890123}}) + ) self.assertTrue(vl.dataProvider().changeAttributeValues({1: {3: 1.5}})) # datetime_field - self.assertTrue(vl.dataProvider().changeAttributeValues({1: {4: QDateTime(2022, 1, 1, 1, 1, 1, 0)}})) + self.assertTrue( + vl.dataProvider().changeAttributeValues( + {1: {4: QDateTime(2022, 1, 1, 1, 1, 1, 0)}} + ) + ) # date_field - self.assertTrue(vl.dataProvider().changeAttributeValues({1: {5: QDate(2022, 1, 1)}})) + self.assertTrue( + vl.dataProvider().changeAttributeValues({1: {5: QDate(2022, 1, 1)}}) + ) # string_field self.assertTrue(vl.dataProvider().changeAttributeValues({1: {6: "foo"}})) self.assertTrue(vl.dataProvider().changeAttributeValues({1: {6: 12345}})) @@ -3019,15 +3567,15 @@ def testChangeAttributeValuesErrors(self): def testAttributeBoolean(self): - tmpfile = os.path.join(self.basetestpath, 'testAttributeBoolean.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) - fld_defn = ogr.FieldDefn('bool_field', ogr.OFTInteger) + tmpfile = os.path.join(self.basetestpath, "testAttributeBoolean.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) + fld_defn = ogr.FieldDefn("bool_field", ogr.OFTInteger) fld_defn.SetSubType(ogr.OFSTBoolean) lyr.CreateField(fld_defn) ds = None - vl = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") f = QgsFeature(vl.fields()) f.setAttribute(1, False) @@ -3080,12 +3628,16 @@ def testAttributeBoolean(self): ret, _ = vl.dataProvider().addFeatures([f]) self.assertFalse(ret) - self.assertEqual([feat["bool_field"] for feat in vl.getFeatures()], - [False, True, False, True, False, True, False, True]) + self.assertEqual( + [feat["bool_field"] for feat in vl.getFeatures()], + [False, True, False, True, False, True, False, True], + ) def testExtent(self): # 2D points - vl = QgsVectorLayer(os.path.join(unitTestDataPath(), 'points_gpkg.gpkg'), 'points_small', 'ogr') + vl = QgsVectorLayer( + os.path.join(unitTestDataPath(), "points_gpkg.gpkg"), "points_small", "ogr" + ) self.assertTrue(vl.isValid()) self.assertAlmostEqual(vl.extent().xMinimum(), -117.233, places=3) self.assertAlmostEqual(vl.extent().yMinimum(), 22.8002, places=3) @@ -3101,7 +3653,11 @@ def testExtent(self): del vl # 3D points - vl = QgsVectorLayer(os.path.join(unitTestDataPath(), '3d', 'points_with_z.gpkg'), 'points_with_z', 'ogr') + vl = QgsVectorLayer( + os.path.join(unitTestDataPath(), "3d", "points_with_z.gpkg"), + "points_with_z", + "ogr", + ) self.assertTrue(vl.isValid()) self.assertAlmostEqual(vl.extent().xMinimum(), -102.4361, places=3) @@ -3126,14 +3682,14 @@ def testQueryLayers(self): ds = ogr.GetDriverByName("GPKG").CreateDataSource(filename) lyr = ds.CreateLayer("points", geom_type=ogr.wkbPoint) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(1 2)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(1 2)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(3 4)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(3 4)")) lyr.CreateFeature(f) f = None - vl = QgsVectorLayer(filename + '|layername=points') + vl = QgsVectorLayer(filename + "|layername=points") self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 2) @@ -3144,12 +3700,12 @@ def testQueryLayers(self): # Add lines layer lyr = ds.CreateLayer("lines", geom_type=ogr.wkbLineString) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('LINESTRING(1 2, 3 4)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("LINESTRING(1 2, 3 4)")) lyr.CreateFeature(f) f = None ds = None - vl = QgsVectorLayer(filename + '|layername=lines') + vl = QgsVectorLayer(filename + "|layername=lines") self.assertEqual(vl.geometryType(), Qgis.GeometryType.Line) self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 1) @@ -3160,23 +3716,26 @@ def testQueryLayers(self): self.assertEqual(vl.featureCount(), 2) # Set subset string to SELECT * FROM lines - self.assertTrue(vl.setSubsetString('SELECT * FROM lines WHERE fid > 0')) + self.assertTrue(vl.setSubsetString("SELECT * FROM lines WHERE fid > 0")) self.assertTrue(vl.isValid()) - self.assertIn('|subset=SELECT * FROM lines WHERE fid > 0', vl.dataProvider().dataSourceUri()) + self.assertIn( + "|subset=SELECT * FROM lines WHERE fid > 0", + vl.dataProvider().dataSourceUri(), + ) f = next(vl.getFeatures()) self.assertEqual(f.geometry().type(), Qgis.GeometryType.Line) self.assertEqual(vl.featureCount(), 1) # This fails because the vector layer doesn't know about the new geometry type # self.assertEqual(vl.geometryType(), Qgis.GeometryType.Line) - self.assertTrue(vl.setSubsetString('')) + self.assertTrue(vl.setSubsetString("")) self.assertTrue(vl.isValid()) self.assertIn("layername=lines", vl.dataProvider().dataSourceUri()) # This fails because the vector layer doesn't know about the new geometry type # self.assertEqual(vl.geometryType(), Qgis.GeometryType.Line) f = next(vl.getFeatures()) self.assertEqual(f.geometry().type(), Qgis.GeometryType.Line) - self.assertEqual(f.geometry().asWkt().upper(), 'LINESTRING (1 2, 3 4)') + self.assertEqual(f.geometry().asWkt().upper(), "LINESTRING (1 2, 3 4)") self.assertEqual(vl.allFeatureIds(), [1]) # This fails on CI but only on the "5, ALL_BUT_PROVIDERS" workflow # for some reason that I cannto reproduce locally, featureCount returns 2 @@ -3185,15 +3744,19 @@ def testQueryLayers(self): def testOrderByEscapedIdentifier(self): """Test issue GH #58508""" - tmpfile = os.path.join(self.basetestpath, 'points_escaped_identifier.gpkg') - testdata_path = unitTestDataPath('provider') - shutil.copy(os.path.join(testdata_path, 'points_escaped_identifier.gpkg'), tmpfile) - vl = QgsVectorLayer(f'{tmpfile}|layername=table\\"\\table', 'test', 'ogr') + tmpfile = os.path.join(self.basetestpath, "points_escaped_identifier.gpkg") + testdata_path = unitTestDataPath("provider") + shutil.copy( + os.path.join(testdata_path, "points_escaped_identifier.gpkg"), tmpfile + ) + vl = QgsVectorLayer(f'{tmpfile}|layername=table\\"\\table', "test", "ogr") self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 3) request = QgsFeatureRequest() - orderBy = QgsFeatureRequest.OrderBy([QgsFeatureRequest.OrderByClause('NAME', False)]) + orderBy = QgsFeatureRequest.OrderBy( + [QgsFeatureRequest.OrderByClause("NAME", False)] + ) request.setOrderBy(orderBy) features = vl.getFeatures(request) @@ -3204,5 +3767,5 @@ def testOrderByEscapedIdentifier(self): self.assertEqual(featureCount, 3) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_provider_ogr_sqlite.py b/tests/src/python/test_provider_ogr_sqlite.py index 45d24688887a..192aba2fb4b4 100644 --- a/tests/src/python/test_provider_ogr_sqlite.py +++ b/tests/src/python/test_provider_ogr_sqlite.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Even Rouault' -__date__ = '2016-06-01' -__copyright__ = 'Copyright 2016, Even Rouault' + +__author__ = "Even Rouault" +__date__ = "2016-06-01" +__copyright__ = "Copyright 2016, Even Rouault" import os import shutil @@ -33,7 +34,7 @@ def GDAL_COMPUTE_VERSION(maj, min, rev): - return ((maj) * 1000000 + (min) * 10000 + (rev) * 100) + return (maj) * 1000000 + (min) * 10000 + (rev) * 100 class TestPyQgsOGRProviderSqlite(QgisTestCase): @@ -52,72 +53,125 @@ def tearDownClass(cls): super().tearDownClass() def testFidSupport(self): - tmpfile = os.path.join(self.basetestpath, 'testFidSupport.sqlite') - ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid']) - lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger)) + tmpfile = os.path.join(self.basetestpath, "testFidSupport.sqlite") + ds = ogr.GetDriverByName("SQLite").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint, options=["FID=fid"]) + lyr.CreateField(ogr.FieldDefn("strfield", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("intfield", ogr.OFTInteger)) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(12) - f.SetField(0, 'foo') + f.SetField(0, "foo") f.SetField(1, 123) lyr.CreateFeature(f) f = None ds = None - vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr") self.assertEqual(len(vl.fields()), 3) - got = [(f.attribute('fid'), f.attribute('strfield'), f.attribute('intfield')) for f in vl.getFeatures()] - self.assertEqual(got, [(12, 'foo', 123)]) - - got = [(f.attribute('fid'), f.attribute('strfield')) for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression("strfield = 'foo'"))] - self.assertEqual(got, [(12, 'foo')]) - - got = [(f.attribute('fid'), f.attribute('strfield')) for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression("fid = 12"))] - self.assertEqual(got, [(12, 'foo')]) - - result = [f['strfield'] for f in vl.dataProvider().getFeatures(QgsFeatureRequest().setSubsetOfAttributes(['strfield'], vl.dataProvider().fields()))] - self.assertEqual(result, ['foo']) - - result = [f['fid'] for f in vl.dataProvider().getFeatures(QgsFeatureRequest().setSubsetOfAttributes(['fid'], vl.dataProvider().fields()))] + got = [ + (f.attribute("fid"), f.attribute("strfield"), f.attribute("intfield")) + for f in vl.getFeatures() + ] + self.assertEqual(got, [(12, "foo", 123)]) + + got = [ + (f.attribute("fid"), f.attribute("strfield")) + for f in vl.getFeatures( + QgsFeatureRequest().setFilterExpression("strfield = 'foo'") + ) + ] + self.assertEqual(got, [(12, "foo")]) + + got = [ + (f.attribute("fid"), f.attribute("strfield")) + for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression("fid = 12")) + ] + self.assertEqual(got, [(12, "foo")]) + + result = [ + f["strfield"] + for f in vl.dataProvider().getFeatures( + QgsFeatureRequest().setSubsetOfAttributes( + ["strfield"], vl.dataProvider().fields() + ) + ) + ] + self.assertEqual(result, ["foo"]) + + result = [ + f["fid"] + for f in vl.dataProvider().getFeatures( + QgsFeatureRequest().setSubsetOfAttributes( + ["fid"], vl.dataProvider().fields() + ) + ) + ] self.assertEqual(result, [12]) # Test that when the 'fid' field is not set, regular insertion is done f = QgsFeature() f.setFields(vl.fields()) - f.setAttributes([None, 'automatic_id']) + f.setAttributes([None, "automatic_id"]) (res, out_f) = vl.dataProvider().addFeatures([f]) self.assertEqual(out_f[0].id(), 13) - self.assertEqual(out_f[0].attribute('fid'), 13) - self.assertEqual(out_f[0].attribute('strfield'), 'automatic_id') + self.assertEqual(out_f[0].attribute("fid"), 13) + self.assertEqual(out_f[0].attribute("strfield"), "automatic_id") # Test that when the 'fid' field is set, it is really used to set the id f = QgsFeature() f.setFields(vl.fields()) - f.setAttributes([9876543210, 'bar']) + f.setAttributes([9876543210, "bar"]) (res, out_f) = vl.dataProvider().addFeatures([f]) self.assertEqual(out_f[0].id(), 9876543210) - self.assertEqual(out_f[0].attribute('fid'), 9876543210) - self.assertEqual(out_f[0].attribute('strfield'), 'bar') - - got = [(f.attribute('fid'), f.attribute('strfield')) for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression("fid = 9876543210"))] - self.assertEqual(got, [(9876543210, 'bar')]) - - self.assertTrue(vl.dataProvider().changeAttributeValues({9876543210: {1: 'baz'}})) - - got = [(f.attribute('fid'), f.attribute('strfield')) for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression("fid = 9876543210"))] - self.assertEqual(got, [(9876543210, 'baz')]) - - self.assertTrue(vl.dataProvider().changeAttributeValues({9876543210: {0: 9876543210, 1: 'baw'}})) - - got = [(f.attribute('fid'), f.attribute('strfield')) for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression("fid = 9876543210"))] - self.assertEqual(got, [(9876543210, 'baw')]) + self.assertEqual(out_f[0].attribute("fid"), 9876543210) + self.assertEqual(out_f[0].attribute("strfield"), "bar") + + got = [ + (f.attribute("fid"), f.attribute("strfield")) + for f in vl.getFeatures( + QgsFeatureRequest().setFilterExpression("fid = 9876543210") + ) + ] + self.assertEqual(got, [(9876543210, "bar")]) + + self.assertTrue( + vl.dataProvider().changeAttributeValues({9876543210: {1: "baz"}}) + ) + + got = [ + (f.attribute("fid"), f.attribute("strfield")) + for f in vl.getFeatures( + QgsFeatureRequest().setFilterExpression("fid = 9876543210") + ) + ] + self.assertEqual(got, [(9876543210, "baz")]) + + self.assertTrue( + vl.dataProvider().changeAttributeValues( + {9876543210: {0: 9876543210, 1: "baw"}} + ) + ) + + got = [ + (f.attribute("fid"), f.attribute("strfield")) + for f in vl.getFeatures( + QgsFeatureRequest().setFilterExpression("fid = 9876543210") + ) + ] + self.assertEqual(got, [(9876543210, "baw")]) # Not allowed: changing the fid regular field - self.assertFalse(vl.dataProvider().changeAttributeValues({9876543210: {0: 12, 1: 'baw'}})) - - got = [(f.attribute('fid'), f.attribute('strfield')) for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression("fid = 9876543210"))] - self.assertEqual(got, [(9876543210, 'baw')]) + self.assertFalse( + vl.dataProvider().changeAttributeValues({9876543210: {0: 12, 1: "baw"}}) + ) + + got = [ + (f.attribute("fid"), f.attribute("strfield")) + for f in vl.getFeatures( + QgsFeatureRequest().setFilterExpression("fid = 9876543210") + ) + ] + self.assertEqual(got, [(9876543210, "baw")]) # Cannot delete fid self.assertFalse(vl.dataProvider().deleteAttributes([0])) @@ -125,65 +179,97 @@ def testFidSupport(self): # Delete first "genuine" attribute self.assertTrue(vl.dataProvider().deleteAttributes([1])) - got = [(f.attribute('fid'), f.attribute('intfield')) for f in vl.dataProvider().getFeatures(QgsFeatureRequest().setFilterExpression("fid = 12"))] + got = [ + (f.attribute("fid"), f.attribute("intfield")) + for f in vl.dataProvider().getFeatures( + QgsFeatureRequest().setFilterExpression("fid = 12") + ) + ] self.assertEqual(got, [(12, 123)]) def testNotNullConstraint(self): - """ test detection of not null constraint on OGR layer """ + """test detection of not null constraint on OGR layer""" - tmpfile = os.path.join(self.basetestpath, 'testNotNullConstraint.sqlite') - ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid']) - lyr.CreateField(ogr.FieldDefn('field1', ogr.OFTInteger)) - fld2 = ogr.FieldDefn('field2', ogr.OFTInteger) + tmpfile = os.path.join(self.basetestpath, "testNotNullConstraint.sqlite") + ds = ogr.GetDriverByName("SQLite").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint, options=["FID=fid"]) + lyr.CreateField(ogr.FieldDefn("field1", ogr.OFTInteger)) + fld2 = ogr.FieldDefn("field2", ogr.OFTInteger) fld2.SetNullable(False) lyr.CreateField(fld2) ds = None - vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr") self.assertTrue(vl.isValid()) # test some bad indexes - self.assertEqual(vl.dataProvider().fieldConstraints(-1), QgsFieldConstraints.Constraints()) - self.assertEqual(vl.dataProvider().fieldConstraints(1001), QgsFieldConstraints.Constraints()) - - self.assertTrue(vl.dataProvider().fieldConstraints(0) & QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertFalse(vl.dataProvider().fieldConstraints(1) & QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertTrue(vl.dataProvider().fieldConstraints(2) & QgsFieldConstraints.Constraint.ConstraintNotNull) + self.assertEqual( + vl.dataProvider().fieldConstraints(-1), QgsFieldConstraints.Constraints() + ) + self.assertEqual( + vl.dataProvider().fieldConstraints(1001), QgsFieldConstraints.Constraints() + ) + + self.assertTrue( + vl.dataProvider().fieldConstraints(0) + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertFalse( + vl.dataProvider().fieldConstraints(1) + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertTrue( + vl.dataProvider().fieldConstraints(2) + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) # test that constraints have been saved to fields correctly fields = vl.fields() - self.assertTrue(fields.at(0).constraints().constraints() & QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertFalse(fields.at(1).constraints().constraints() & QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertTrue(fields.at(2).constraints().constraints() & QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertEqual(fields.at(2).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) + self.assertTrue( + fields.at(0).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertFalse( + fields.at(1).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertTrue( + fields.at(2).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertEqual( + fields.at(2) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) def testDefaultValues(self): - """ test detection of defaults on OGR layer """ - - tmpfile = os.path.join(self.basetestpath, 'testDefaults.sqlite') - ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid']) - lyr.CreateField(ogr.FieldDefn('field1', ogr.OFTInteger)) - fld2 = ogr.FieldDefn('field2', ogr.OFTInteger) - fld2.SetDefault('5') + """test detection of defaults on OGR layer""" + + tmpfile = os.path.join(self.basetestpath, "testDefaults.sqlite") + ds = ogr.GetDriverByName("SQLite").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint, options=["FID=fid"]) + lyr.CreateField(ogr.FieldDefn("field1", ogr.OFTInteger)) + fld2 = ogr.FieldDefn("field2", ogr.OFTInteger) + fld2.SetDefault("5") lyr.CreateField(fld2) - fld3 = ogr.FieldDefn('field3', ogr.OFTString) + fld3 = ogr.FieldDefn("field3", ogr.OFTString) fld3.SetDefault("'some ''default'") lyr.CreateField(fld3) - fld4 = ogr.FieldDefn('field4', ogr.OFTDate) + fld4 = ogr.FieldDefn("field4", ogr.OFTDate) fld4.SetDefault("CURRENT_DATE") lyr.CreateField(fld4) - fld5 = ogr.FieldDefn('field5', ogr.OFTTime) + fld5 = ogr.FieldDefn("field5", ogr.OFTTime) fld5.SetDefault("CURRENT_TIME") lyr.CreateField(fld5) - fld6 = ogr.FieldDefn('field6', ogr.OFTDateTime) + fld6 = ogr.FieldDefn("field6", ogr.OFTDateTime) fld6.SetDefault("CURRENT_TIMESTAMP") lyr.CreateField(fld6) ds = None - vl = QgsVectorLayer(f'{tmpfile}', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}", "test", "ogr") self.assertTrue(vl.isValid()) # test some bad indexes @@ -196,69 +282,73 @@ def testDefaultValues(self): self.assertEqual(vl.dataProvider().defaultValue(3), "some 'default") self.assertEqual(vl.dataProvider().defaultValue(4), QDate.currentDate()) # time may pass, so we allow 1 second difference here - self.assertLess(vl.dataProvider().defaultValue(5).secsTo(QTime.currentTime()), 1) - self.assertLess(vl.dataProvider().defaultValue(6).secsTo(QDateTime.currentDateTime()), 1) + self.assertLess( + vl.dataProvider().defaultValue(5).secsTo(QTime.currentTime()), 1 + ) + self.assertLess( + vl.dataProvider().defaultValue(6).secsTo(QDateTime.currentDateTime()), 1 + ) def testSubsetStringFids(self): """ - - tests that feature ids are stable even if a subset string is set - - tests that the subset string is correctly set on the ogr layer event when reloading the data source (issue #17122) + - tests that feature ids are stable even if a subset string is set + - tests that the subset string is correctly set on the ogr layer event when reloading the data source (issue #17122) """ - tmpfile = os.path.join(self.basetestpath, 'subsetStringFids.sqlite') - ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid']) - lyr.CreateField(ogr.FieldDefn('type', ogr.OFTInteger)) - lyr.CreateField(ogr.FieldDefn('value', ogr.OFTInteger)) + tmpfile = os.path.join(self.basetestpath, "subsetStringFids.sqlite") + ds = ogr.GetDriverByName("SQLite").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint, options=["FID=fid"]) + lyr.CreateField(ogr.FieldDefn("type", ogr.OFTInteger)) + lyr.CreateField(ogr.FieldDefn("value", ogr.OFTInteger)) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(0) f.SetField(0, 1) f.SetField(1, 11) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point (0 0)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point (0 0)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(1) f.SetField(0, 1) f.SetField(1, 12) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point (1 1)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point (1 1)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(2) f.SetField(0, 1) f.SetField(1, 13) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point (2 2)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point (2 2)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(3) f.SetField(0, 2) f.SetField(1, 14) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point (3 3)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point (3 3)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(4) f.SetField(0, 2) f.SetField(1, 15) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point (4 4)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point (4 4)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(5) f.SetField(0, 2) f.SetField(1, 16) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point (5 5)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point (5 5)")) lyr.CreateFeature(f) f = None ds = None - vl = QgsVectorLayer(tmpfile, 'test', 'ogr') + vl = QgsVectorLayer(tmpfile, "test", "ogr") self.assertTrue(vl.isValid()) - self.assertEqual([f.name() for f in vl.fields()], ['fid', 'type', 'value']) + self.assertEqual([f.name() for f in vl.fields()], ["fid", "type", "value"]) original_fields = vl.fields() - vl = QgsVectorLayer(tmpfile + "|subset=type=2", 'test', 'ogr') + vl = QgsVectorLayer(tmpfile + "|subset=type=2", "test", "ogr") self.assertTrue(vl.isValid()) def run_checks(): - self.assertEqual([f.name() for f in vl.fields()], ['fid', 'type', 'value']) + self.assertEqual([f.name() for f in vl.fields()], ["fid", "type", "value"]) # expression req = QgsFeatureRequest() @@ -268,8 +358,10 @@ def run_checks(): self.assertTrue(it.nextFeature(f)) self.assertEqual(f.id(), 5) self.assertEqual(f.attributes(), [5, 2, 16]) - self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value']) - self.assertEqual(f.geometry().asWkt(), 'Point (5 5)') + self.assertEqual( + [field.name() for field in f.fields()], ["fid", "type", "value"] + ) + self.assertEqual(f.geometry().asWkt(), "Point (5 5)") # filter fid req = QgsFeatureRequest() @@ -279,8 +371,10 @@ def run_checks(): self.assertTrue(it.nextFeature(f)) self.assertEqual(f.id(), 5) self.assertEqual(f.attributes(), [5, 2, 16]) - self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value']) - self.assertEqual(f.geometry().asWkt(), 'Point (5 5)') + self.assertEqual( + [field.name() for field in f.fields()], ["fid", "type", "value"] + ) + self.assertEqual(f.geometry().asWkt(), "Point (5 5)") # filter fids req = QgsFeatureRequest() @@ -290,8 +384,10 @@ def run_checks(): self.assertTrue(it.nextFeature(f)) self.assertEqual(f.id(), 5) self.assertEqual(f.attributes(), [5, 2, 16]) - self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value']) - self.assertEqual(f.geometry().asWkt(), 'Point (5 5)') + self.assertEqual( + [field.name() for field in f.fields()], ["fid", "type", "value"] + ) + self.assertEqual(f.geometry().asWkt(), "Point (5 5)") # check with subset of attributes req = QgsFeatureRequest() @@ -302,8 +398,10 @@ def run_checks(): self.assertTrue(it.nextFeature(f)) self.assertEqual(f.id(), 5) self.assertEqual(f.attributes()[2], 16) - self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value']) - self.assertEqual(f.geometry().asWkt(), 'Point (5 5)') + self.assertEqual( + [field.name() for field in f.fields()], ["fid", "type", "value"] + ) + self.assertEqual(f.geometry().asWkt(), "Point (5 5)") # filter rect and expression req = QgsFeatureRequest() @@ -314,8 +412,10 @@ def run_checks(): self.assertTrue(it.nextFeature(f)) self.assertEqual(f.id(), 5) self.assertEqual(f.attributes(), [5, 2, 16]) - self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value']) - self.assertEqual(f.geometry().asWkt(), 'Point (5 5)') + self.assertEqual( + [field.name() for field in f.fields()], ["fid", "type", "value"] + ) + self.assertEqual(f.geometry().asWkt(), "Point (5 5)") # filter rect and fids req = QgsFeatureRequest() @@ -326,8 +426,10 @@ def run_checks(): self.assertTrue(it.nextFeature(f)) self.assertEqual(f.id(), 5) self.assertEqual(f.attributes(), [5, 2, 16]) - self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value']) - self.assertEqual(f.geometry().asWkt(), 'Point (5 5)') + self.assertEqual( + [field.name() for field in f.fields()], ["fid", "type", "value"] + ) + self.assertEqual(f.geometry().asWkt(), "Point (5 5)") # Ensure that orig_ogc_fid is still retrieved even if attribute subset is passed req = QgsFeatureRequest() @@ -339,7 +441,9 @@ def run_checks(): ids.append(f.id()) geoms[f.id()] = f.geometry().asWkt() self.assertCountEqual(ids, [3, 4, 5]) - self.assertEqual(geoms, {3: 'Point (3 3)', 4: 'Point (4 4)', 5: 'Point (5 5)'}) + self.assertEqual( + geoms, {3: "Point (3 3)", 4: "Point (4 4)", 5: "Point (5 5)"} + ) run_checks() # Check that subset string is correctly set on reload @@ -348,47 +452,61 @@ def run_checks(): def test_SplitFeature(self): """Test sqlite feature can be split""" - tmpfile = os.path.join(self.basetestpath, 'testGeopackageSplitFeatures.sqlite') - ds = ogr.GetDriverByName('SQlite').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon) - lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) + tmpfile = os.path.join(self.basetestpath, "testGeopackageSplitFeatures.sqlite") + ds = ogr.GetDriverByName("SQlite").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon) + lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 1,1 1,1 0,0 0))')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON ((0 0,0 1,1 1,1 0,0 0))")) lyr.CreateFeature(f) f = None ds = None - layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + layer = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") # Check that pk field has unique constraint fields = layer.fields() pkfield = fields.at(0) - self.assertTrue(pkfield.constraints().constraints() & QgsFieldConstraints.Constraint.ConstraintUnique) + self.assertTrue( + pkfield.constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintUnique + ) self.assertTrue(layer.isValid()) self.assertTrue(layer.isSpatial()) - self.assertEqual([f for f in layer.getFeatures()][0].geometry().asWkt(), 'Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))') + self.assertEqual( + [f for f in layer.getFeatures()][0].geometry().asWkt(), + "Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))", + ) layer.startEditing() - self.assertEqual(layer.splitFeatures([QgsPointXY(0.5, 0), QgsPointXY(0.5, 1)], 0), 0) + self.assertEqual( + layer.splitFeatures([QgsPointXY(0.5, 0), QgsPointXY(0.5, 1)], 0), 0 + ) self.assertTrue(layer.commitChanges()) self.assertEqual(layer.featureCount(), 2) - layer = QgsVectorLayer(f'{tmpfile}' + "|layername=" + "test", 'test', 'ogr') + layer = QgsVectorLayer(f"{tmpfile}" + "|layername=" + "test", "test", "ogr") self.assertEqual(layer.featureCount(), 2) - self.assertEqual([f for f in layer.getFeatures()][0].geometry().asWkt(), 'Polygon ((0.5 0, 0.5 1, 1 1, 1 0, 0.5 0))') - self.assertEqual([f for f in layer.getFeatures()][1].geometry().asWkt(), 'Polygon ((0.5 1, 0.5 0, 0 0, 0 1, 0.5 1))') + self.assertEqual( + [f for f in layer.getFeatures()][0].geometry().asWkt(), + "Polygon ((0.5 0, 0.5 1, 1 1, 1 0, 0.5 0))", + ) + self.assertEqual( + [f for f in layer.getFeatures()][1].geometry().asWkt(), + "Polygon ((0.5 1, 0.5 0, 0 0, 0 1, 0.5 1))", + ) def testBlob(self): """ Test binary blob field """ - tmpfile = os.path.join(self.basetestpath, 'binaryfield.sqlite') - ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid']) - lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger)) - lyr.CreateField(ogr.FieldDefn('binfield', ogr.OFTBinary)) - lyr.CreateField(ogr.FieldDefn('binfield2', ogr.OFTBinary)) + tmpfile = os.path.join(self.basetestpath, "binaryfield.sqlite") + ds = ogr.GetDriverByName("SQLite").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint, options=["FID=fid"]) + lyr.CreateField(ogr.FieldDefn("strfield", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("intfield", ogr.OFTInteger)) + lyr.CreateField(ogr.FieldDefn("binfield", ogr.OFTBinary)) + lyr.CreateField(ogr.FieldDefn("binfield2", ogr.OFTBinary)) f = None ds = None @@ -396,184 +514,210 @@ def testBlob(self): self.assertTrue(vl.isValid()) fields = vl.fields() - bin1_field = fields[fields.lookupField('binfield')] + bin1_field = fields[fields.lookupField("binfield")] self.assertEqual(bin1_field.type(), QVariant.ByteArray) - self.assertEqual(bin1_field.typeName(), 'Binary') - bin2_field = fields[fields.lookupField('binfield2')] + self.assertEqual(bin1_field.typeName(), "Binary") + bin2_field = fields[fields.lookupField("binfield2")] self.assertEqual(bin2_field.type(), QVariant.ByteArray) - self.assertEqual(bin2_field.typeName(), 'Binary') + self.assertEqual(bin2_field.typeName(), "Binary") dp = vl.dataProvider() f = QgsFeature(fields) - bin_1 = b'xxx' - bin_2 = b'yyy' + bin_1 = b"xxx" + bin_2 = b"yyy" bin_val1 = QByteArray(bin_1) bin_val2 = QByteArray(bin_2) - f.setAttributes([1, 'str', 100, bin_val1, bin_val2]) + f.setAttributes([1, "str", 100, bin_val1, bin_val2]) self.assertTrue(dp.addFeature(f)) f2 = next(dp.getFeatures()) - self.assertEqual(f2.attributes(), [1, 'str', 100, QByteArray(bin_1), QByteArray(bin_2)]) + self.assertEqual( + f2.attributes(), [1, "str", 100, QByteArray(bin_1), QByteArray(bin_2)] + ) - bin_3 = b'zzz' - bin_4 = b'aaa' + bin_3 = b"zzz" + bin_4 = b"aaa" bin_val3 = QByteArray(bin_3) bin_val4 = QByteArray(bin_4) - self.assertTrue(dp.changeAttributeValues({f2.id(): {fields.lookupField('intfield'): 200, - fields.lookupField('binfield'): bin_val4, - fields.lookupField('binfield2'): bin_val3}})) + self.assertTrue( + dp.changeAttributeValues( + { + f2.id(): { + fields.lookupField("intfield"): 200, + fields.lookupField("binfield"): bin_val4, + fields.lookupField("binfield2"): bin_val3, + } + } + ) + ) f5 = next(dp.getFeatures()) - self.assertEqual(f5.attributes(), [1, 'str', 200, QByteArray(bin_4), QByteArray(bin_3)]) + self.assertEqual( + f5.attributes(), [1, "str", 200, QByteArray(bin_4), QByteArray(bin_3)] + ) def testUniqueValuesOnFidColumn(self): """Test regression #21311 OGR provider returns an empty set for sqlite uniqueValues""" - tmpfile = os.path.join(self.basetestpath, 'testSQLiteUniqueValuesOnFidColumn.db') - ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPolygon) - lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) + tmpfile = os.path.join( + self.basetestpath, "testSQLiteUniqueValuesOnFidColumn.db" + ) + ds = ogr.GetDriverByName("SQLite").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPolygon) + lyr.CreateField(ogr.FieldDefn("str_field", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 1,1 1,1 0,0 0))')) - f.SetField('str_field', 'one') + f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON ((0 0,0 1,1 1,1 0,0 0))")) + f.SetField("str_field", "one") lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POLYGON ((0 0,0 2,2 2,2 0,0 0))')) - f.SetField('str_field', 'two') + f.SetGeometry(ogr.CreateGeometryFromWkt("POLYGON ((0 0,0 2,2 2,2 0,0 0))")) + f.SetField("str_field", "two") lyr.CreateFeature(f) f = None ds = None vl1 = QgsVectorLayer(tmpfile) self.assertTrue(vl1.isValid()) self.assertEqual(vl1.uniqueValues(0), {1, 2}) - self.assertEqual(vl1.uniqueValues(1), {'one', 'two'}) + self.assertEqual(vl1.uniqueValues(1), {"one", "two"}) def testSpatialIndexCapability(self): - """ Test https://github.com/qgis/QGIS/issues/44513 """ + """Test https://github.com/qgis/QGIS/issues/44513""" - tmpfile = os.path.join(self.basetestpath, 'testSpatialIndexCapability.db') - ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile) - ds.CreateLayer('test', geom_type=ogr.wkbPolygon) + tmpfile = os.path.join(self.basetestpath, "testSpatialIndexCapability.db") + ds = ogr.GetDriverByName("SQLite").CreateDataSource(tmpfile) + ds.CreateLayer("test", geom_type=ogr.wkbPolygon) ds = None - vl = QgsVectorLayer(f'{tmpfile}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}|layerid=0", "test", "ogr") caps = vl.dataProvider().capabilities() self.assertFalse(caps & QgsVectorDataProvider.Capability.CreateSpatialIndex) def testSpatialIndexCapabilitySpatialite(self): - """ Test https://github.com/qgis/QGIS/issues/44513 """ - - tmpfile = os.path.join(self.basetestpath, 'testSpatialIndexCapabilitySpatialite.db') - ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile, options=['SPATIALITE=YES']) - ds.CreateLayer('test', geom_type=ogr.wkbPolygon) + """Test https://github.com/qgis/QGIS/issues/44513""" + + tmpfile = os.path.join( + self.basetestpath, "testSpatialIndexCapabilitySpatialite.db" + ) + ds = ogr.GetDriverByName("SQLite").CreateDataSource( + tmpfile, options=["SPATIALITE=YES"] + ) + ds.CreateLayer("test", geom_type=ogr.wkbPolygon) ds = None - vl = QgsVectorLayer(f'{tmpfile}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}|layerid=0", "test", "ogr") caps = vl.dataProvider().capabilities() self.assertTrue(caps & QgsVectorDataProvider.Capability.CreateSpatialIndex) def testExtentSqlite(self): # create 2D dataset - tmpfile = os.path.join(self.basetestpath, 'points.sqlite') - ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid']) + tmpfile = os.path.join(self.basetestpath, "points.sqlite") + ds = ogr.GetDriverByName("SQLite").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint, options=["FID=fid"]) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(0) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point (0 0)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point (0 0)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(1) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point (1 1)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point (1 1)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(2) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point (2 2)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point (2 2)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(3) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point (3 3)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point (3 3)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(4) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point (4 4)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point (4 4)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(5) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point (5 5)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point (5 5)")) lyr.CreateFeature(f) f = None ds = None # create 3D 2.5d dataset - tmpfile = os.path.join(self.basetestpath, 'points_with_z.sqlite') - ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile, options=['SPATIALITE=YES']) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint25D, options=['FID=fid']) + tmpfile = os.path.join(self.basetestpath, "points_with_z.sqlite") + ds = ogr.GetDriverByName("SQLite").CreateDataSource( + tmpfile, options=["SPATIALITE=YES"] + ) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint25D, options=["FID=fid"]) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(0) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (0 0 -5)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (0 0 -5)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(1) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (1 1 -10)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (1 1 -10)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(2) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (2 2 -15)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (2 2 -15)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(3) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (3 3 5)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (3 3 5)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(4) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (4 4 10)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (4 4 10)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(5) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (5 5 15)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (5 5 15)")) lyr.CreateFeature(f) f = None ds = None # create 3D ZM dataset - tmpfile = os.path.join(self.basetestpath, 'points_with_zm.sqlite') - ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile, options=['SPATIALITE=YES']) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPointZM, options=['FID=fid']) + tmpfile = os.path.join(self.basetestpath, "points_with_zm.sqlite") + ds = ogr.GetDriverByName("SQLite").CreateDataSource( + tmpfile, options=["SPATIALITE=YES"] + ) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPointZM, options=["FID=fid"]) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(0) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point ZM (0 0 -5 1)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point ZM (0 0 -5 1)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(1) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point ZM (1 1 -10 2)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point ZM (1 1 -10 2)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(2) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point ZM (2 2 -15 3)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point ZM (2 2 -15 3)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(3) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point ZM (3 3 5 4)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point ZM (3 3 5 4)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(4) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point ZM (4 4 10 5)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point ZM (4 4 10 5)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(5) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point ZM (5 5 15 6)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point ZM (5 5 15 6)")) lyr.CreateFeature(f) f = None ds = None # create empty 3D dataset - tmpfile = os.path.join(self.basetestpath, 'points_z_empty.sqlite') - ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile, options=['SPATIALITE=YES']) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPointZM, options=['FID=fid']) + tmpfile = os.path.join(self.basetestpath, "points_z_empty.sqlite") + ds = ogr.GetDriverByName("SQLite").CreateDataSource( + tmpfile, options=["SPATIALITE=YES"] + ) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPointZM, options=["FID=fid"]) ds = None # 2D points - vl = QgsVectorLayer(os.path.join(self.basetestpath, 'points.sqlite'), 'test', 'ogr') + vl = QgsVectorLayer( + os.path.join(self.basetestpath, "points.sqlite"), "test", "ogr" + ) self.assertTrue(vl.isValid()) self.assertAlmostEqual(vl.extent().xMinimum(), 0, places=3) @@ -590,7 +734,9 @@ def testExtentSqlite(self): del vl # 3D points - vl = QgsVectorLayer(os.path.join(self.basetestpath, 'points_with_z.sqlite'), 'test', 'ogr') + vl = QgsVectorLayer( + os.path.join(self.basetestpath, "points_with_z.sqlite"), "test", "ogr" + ) self.assertTrue(vl.isValid()) self.assertAlmostEqual(vl.extent().xMinimum(), 0, places=3) @@ -606,7 +752,9 @@ def testExtentSqlite(self): self.assertAlmostEqual(vl.extent3D().zMaximum(), 15.0, places=3) del vl - vl = QgsVectorLayer(os.path.join(self.basetestpath, 'points_with_zm.sqlite'), 'test', 'ogr') + vl = QgsVectorLayer( + os.path.join(self.basetestpath, "points_with_zm.sqlite"), "test", "ogr" + ) self.assertTrue(vl.isValid()) self.assertAlmostEqual(vl.extent().xMinimum(), 0, places=3) @@ -622,7 +770,9 @@ def testExtentSqlite(self): self.assertAlmostEqual(vl.extent3D().zMaximum(), 15.0, places=3) del vl - vl = QgsVectorLayer(os.path.join(self.basetestpath, 'points_z_empty.sqlite'), 'test', 'ogr') + vl = QgsVectorLayer( + os.path.join(self.basetestpath, "points_z_empty.sqlite"), "test", "ogr" + ) self.assertTrue(vl.isValid()) self.assertTrue(math.isnan(vl.extent().xMinimum())) @@ -640,69 +790,71 @@ def testExtentSqlite(self): def testExtentGpkg(self): # create 2D dataset - tmpfile = os.path.join(self.basetestpath, 'points.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid']) + tmpfile = os.path.join(self.basetestpath, "points.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint, options=["FID=fid"]) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(0) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point (0 0)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point (0 0)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(1) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point (1 1)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point (1 1)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(2) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point (2 2)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point (2 2)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(3) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point (3 3)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point (3 3)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(4) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point (4 4)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point (4 4)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(5) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point (5 5)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point (5 5)")) lyr.CreateFeature(f) f = None ds = None # create 3D dataset - tmpfile = os.path.join(self.basetestpath, 'points_with_z.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPointZM, options=['FID=fid']) + tmpfile = os.path.join(self.basetestpath, "points_with_z.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPointZM, options=["FID=fid"]) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(0) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (0 0 -5)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (0 0 -5)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(1) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (1 1 -10)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (1 1 -10)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(2) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (2 2 -15)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (2 2 -15)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(3) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (3 3 5)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (3 3 5)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(4) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (4 4 10)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (4 4 10)")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(5) - f.SetGeometry(ogr.CreateGeometryFromWkt('Point Z (5 5 15)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("Point Z (5 5 15)")) lyr.CreateFeature(f) f = None ds = None # 2D points - vl = QgsVectorLayer(os.path.join(self.basetestpath, 'points.gpkg'), 'test', 'ogr') + vl = QgsVectorLayer( + os.path.join(self.basetestpath, "points.gpkg"), "test", "ogr" + ) self.assertTrue(vl.isValid()) self.assertAlmostEqual(vl.extent().xMinimum(), 0, places=3) @@ -719,7 +871,9 @@ def testExtentGpkg(self): del vl # 3D points - vl = QgsVectorLayer(os.path.join(self.basetestpath, 'points_with_z.gpkg'), 'test', 'ogr') + vl = QgsVectorLayer( + os.path.join(self.basetestpath, "points_with_z.gpkg"), "test", "ogr" + ) self.assertTrue(vl.isValid()) self.assertAlmostEqual(vl.extent().xMinimum(), 0, places=3) @@ -736,5 +890,5 @@ def testExtentGpkg(self): del vl -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_provider_oracle.py b/tests/src/python/test_provider_oracle.py index bd234d880138..b9d6a9590162 100644 --- a/tests/src/python/test_provider_oracle.py +++ b/tests/src/python/test_provider_oracle.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2016-07-06' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2016-07-06" +__copyright__ = "Copyright 2016, The QGIS Project" import os import re @@ -49,26 +50,36 @@ class TestPyQgsOracleProvider(QgisTestCase, ProviderTestCase): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsOracleProvider, cls).setUpClass() - cls.dbconn = "host=localhost dbname=XEPDB1 port=1521 user='QGIS' password='qgis'" - if 'QGIS_ORACLETEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_ORACLETEST_DB'] + super().setUpClass() + cls.dbconn = ( + "host=localhost dbname=XEPDB1 port=1521 user='QGIS' password='qgis'" + ) + if "QGIS_ORACLETEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_ORACLETEST_DB"] # Create test layers cls.vl = QgsVectorLayer( - cls.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="QGIS"."SOME_DATA" (GEOM) sql=', 'test', 'oracle') + cls.dbconn + + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="QGIS"."SOME_DATA" (GEOM) sql=', + "test", + "oracle", + ) assert cls.vl.isValid() cls.source = cls.vl.dataProvider() cls.poly_vl = QgsVectorLayer( - cls.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="QGIS"."SOME_POLY_DATA" (GEOM) sql=', 'test', 'oracle') + cls.dbconn + + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="QGIS"."SOME_POLY_DATA" (GEOM) sql=', + "test", + "oracle", + ) assert cls.poly_vl.isValid() cls.poly_provider = cls.poly_vl.dataProvider() - cls.conn = QSqlDatabase.addDatabase('QOCISPATIAL', "oracletest") - cls.conn.setDatabaseName('localhost/XEPDB1') - if 'QGIS_ORACLETEST_DBNAME' in os.environ: - cls.conn.setDatabaseName(os.environ['QGIS_ORACLETEST_DBNAME']) - cls.conn.setUserName('QGIS') - cls.conn.setPassword('qgis') + cls.conn = QSqlDatabase.addDatabase("QOCISPATIAL", "oracletest") + cls.conn.setDatabaseName("localhost/XEPDB1") + if "QGIS_ORACLETEST_DBNAME" in os.environ: + cls.conn.setDatabaseName(os.environ["QGIS_ORACLETEST_DBNAME"]) + cls.conn.setUserName("QGIS") + cls.conn.setPassword("qgis") assert cls.conn.open() def execSQLCommand(self, sql, ignore_errors=False): @@ -76,28 +87,44 @@ def execSQLCommand(self, sql, ignore_errors=False): query = QSqlQuery(self.conn) res = query.exec(sql) if not ignore_errors: - self.assertTrue(res, sql + ': ' + query.lastError().text()) + self.assertTrue(res, sql + ": " + query.lastError().text()) query.finish() def getSource(self): # create temporary table for edit tests - self.execSQLCommand('ALTER TABLE "QGIS"."EDIT_DATA" MODIFY "pk" DROP IDENTITY', ignore_errors=True) + self.execSQLCommand( + 'ALTER TABLE "QGIS"."EDIT_DATA" MODIFY "pk" DROP IDENTITY', + ignore_errors=True, + ) self.execSQLCommand('DROP TABLE "QGIS"."EDIT_DATA"', ignore_errors=True) - self.execSQLCommand("""CREATE TABLE QGIS.EDIT_DATA ("pk" INTEGER GENERATED by default ON null as IDENTITY(START WITH 1 INCREMENT BY 1) PRIMARY KEY, "cnt" INTEGER, "name" VARCHAR2(100), "name2" VARCHAR2(100), "num_char" VARCHAR2(100), "dt" TIMESTAMP, "date" DATE, "time" VARCHAR2(100), GEOM SDO_GEOMETRY)""") - self.execSQLCommand("""DELETE FROM user_sdo_geom_metadata where TABLE_NAME = 'EDIT_DATA'""") self.execSQLCommand( - """INSERT INTO user_sdo_geom_metadata (TABLE_NAME, COLUMN_NAME, DIMINFO, SRID) VALUES ( 'EDIT_DATA', 'GEOM', sdo_dim_array(sdo_dim_element('X',-75,-55,0.005),sdo_dim_element('Y',65,85,0.005)),4326)""", ignore_errors=True) - self.execSQLCommand("""CREATE INDEX edit_data_spatial_idx ON QGIS.EDIT_DATA(GEOM) INDEXTYPE IS MDSYS.SPATIAL_INDEX""") - self.execSQLCommand("""INSERT INTO QGIS.EDIT_DATA ("pk", "cnt", "name", "name2", "num_char", "dt", "date", "time", GEOM) + """CREATE TABLE QGIS.EDIT_DATA ("pk" INTEGER GENERATED by default ON null as IDENTITY(START WITH 1 INCREMENT BY 1) PRIMARY KEY, "cnt" INTEGER, "name" VARCHAR2(100), "name2" VARCHAR2(100), "num_char" VARCHAR2(100), "dt" TIMESTAMP, "date" DATE, "time" VARCHAR2(100), GEOM SDO_GEOMETRY)""" + ) + self.execSQLCommand( + """DELETE FROM user_sdo_geom_metadata where TABLE_NAME = 'EDIT_DATA'""" + ) + self.execSQLCommand( + """INSERT INTO user_sdo_geom_metadata (TABLE_NAME, COLUMN_NAME, DIMINFO, SRID) VALUES ( 'EDIT_DATA', 'GEOM', sdo_dim_array(sdo_dim_element('X',-75,-55,0.005),sdo_dim_element('Y',65,85,0.005)),4326)""", + ignore_errors=True, + ) + self.execSQLCommand( + """CREATE INDEX edit_data_spatial_idx ON QGIS.EDIT_DATA(GEOM) INDEXTYPE IS MDSYS.SPATIAL_INDEX""" + ) + self.execSQLCommand( + """INSERT INTO QGIS.EDIT_DATA ("pk", "cnt", "name", "name2", "num_char", "dt", "date", "time", GEOM) SELECT 5, -200, NULL, 'NuLl', '5', TIMESTAMP '2020-05-04 12:13:14', DATE '2020-05-02','12:13:01', SDO_GEOMETRY( 2001,4326,SDO_POINT_TYPE(-71.123, 78.23, NULL), NULL, NULL) from dual UNION ALL SELECT 3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL, NULL from dual UNION ALL SELECT 1, 100, 'Orange', 'oranGe', '1', TIMESTAMP '2020-05-03 12:13:14', DATE '2020-05-03','12:13:14', SDO_GEOMETRY( 2001,4326,SDO_POINT_TYPE(-70.332, 66.33, NULL), NULL, NULL) from dual UNION ALL SELECT 2, 200, 'Apple', 'Apple', '2', TIMESTAMP '2020-05-04 12:14:14', DATE '2020-05-04','12:14:14', SDO_GEOMETRY( 2001,4326,SDO_POINT_TYPE(-68.2, 70.8, NULL), NULL, NULL) from dual - UNION ALL SELECT 4, 400, 'Honey', 'Honey', '4', TIMESTAMP '2021-05-04 13:13:14', DATE '2021-05-04','13:13:14', SDO_GEOMETRY( 2001,4326,SDO_POINT_TYPE(-65.32, 78.3, NULL), NULL, NULL) from dual""") + UNION ALL SELECT 4, 400, 'Honey', 'Honey', '4', TIMESTAMP '2021-05-04 13:13:14', DATE '2021-05-04','13:13:14', SDO_GEOMETRY( 2001,4326,SDO_POINT_TYPE(-65.32, 78.3, NULL), NULL, NULL) from dual""" + ) vl = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="QGIS"."EDIT_DATA" (GEOM) sql=', - 'test', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="QGIS"."EDIT_DATA" (GEOM) sql=', + "test", + "oracle", + ) return vl def treat_time_as_string(self): @@ -110,73 +137,73 @@ def getEditableLayer(self): return self.getSource() def enableCompiler(self): - QgsSettings().setValue('/qgis/compileExpressions', True) + QgsSettings().setValue("/qgis/compileExpressions", True) return True def disableCompiler(self): - QgsSettings().setValue('/qgis/compileExpressions', False) + QgsSettings().setValue("/qgis/compileExpressions", False) def uncompiledFilters(self): filters = { - '(name = \'Apple\') is not null', - '"name" || \' \' || "name" = \'Orange Orange\'', - '"name" || \' \' || "cnt" = \'Orange 100\'', - '\'x\' || "name" IS NOT NULL', - '\'x\' || "name" IS NULL', - 'false and NULL', - 'true and NULL', - 'NULL and false', - 'NULL and true', - 'NULL and NULL', - 'false or NULL', - 'true or NULL', - 'NULL or false', - 'NULL or true', - 'NULL or NULL', - 'not null', - 'radians(cnt) < 2', - 'degrees(pk) <= 200', - 'atan2(3.14, pk) < 1', - 'pk < pi()', - 'log10(pk) < 0.5', - 'pk < pi() / 2', - 'pk = char(51)', - 'pk = coalesce(NULL,3,4)', - 'name = trim(\' Apple \')', - 'x($geometry) < -70', - 'y($geometry) > 70', - 'xmin($geometry) < -70', - 'ymin($geometry) > 70', - 'xmax($geometry) < -70', - 'ymax($geometry) > 70', - 'disjoint($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', - 'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', - 'contains(geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'),$geometry)', - 'distance($geometry,geom_from_wkt( \'Point (-70 70)\')) > 7', - 'intersects($geometry,geom_from_gml( \'-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1\'))', - 'x($geometry) < -70', - 'y($geometry) > 79', - 'xmin($geometry) < -70', - 'ymin($geometry) < 76', - 'xmax($geometry) > -68', - 'ymax($geometry) > 80', - 'area($geometry) > 10', - 'perimeter($geometry) < 12', - 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\')) = \'FF2FF1212\'', - 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'), \'****F****\')', - 'crosses($geometry,geom_from_wkt( \'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)\'))', - 'overlaps($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'))', - 'within($geometry,geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - 'overlaps(translate($geometry,-1,-1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - 'overlaps(buffer($geometry,1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - 'intersects(centroid($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', - 'intersects(point_on_surface($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', + "(name = 'Apple') is not null", + "\"name\" || ' ' || \"name\" = 'Orange Orange'", + "\"name\" || ' ' || \"cnt\" = 'Orange 100'", + "'x' || \"name\" IS NOT NULL", + "'x' || \"name\" IS NULL", + "false and NULL", + "true and NULL", + "NULL and false", + "NULL and true", + "NULL and NULL", + "false or NULL", + "true or NULL", + "NULL or false", + "NULL or true", + "NULL or NULL", + "not null", + "radians(cnt) < 2", + "degrees(pk) <= 200", + "atan2(3.14, pk) < 1", + "pk < pi()", + "log10(pk) < 0.5", + "pk < pi() / 2", + "pk = char(51)", + "pk = coalesce(NULL,3,4)", + "name = trim(' Apple ')", + "x($geometry) < -70", + "y($geometry) > 70", + "xmin($geometry) < -70", + "ymin($geometry) > 70", + "xmax($geometry) < -70", + "ymax($geometry) > 70", + "disjoint($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))", + "intersects($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))", + "contains(geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'),$geometry)", + "distance($geometry,geom_from_wkt( 'Point (-70 70)')) > 7", + "intersects($geometry,geom_from_gml( '-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1'))", + "x($geometry) < -70", + "y($geometry) > 79", + "xmin($geometry) < -70", + "ymin($geometry) < 76", + "xmax($geometry) > -68", + "ymax($geometry) > 80", + "area($geometry) > 10", + "perimeter($geometry) < 12", + "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))')) = 'FF2FF1212'", + "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'), '****F****')", + "crosses($geometry,geom_from_wkt( 'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)'))", + "overlaps($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'))", + "within($geometry,geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + "overlaps(translate($geometry,-1,-1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + "overlaps(buffer($geometry,1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + "intersects(centroid($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))", + "intersects(point_on_surface($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))", '"dt" < make_date(2020, 5, 4)', - '"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')', + "\"dt\" = to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy')", '"date" >= make_date(2020, 5, 4)', - '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')', + "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')", 'to_time("time") >= make_time(12, 14, 14)', - 'to_time("time") = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')' + "to_time(\"time\") = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')", } return filters @@ -198,30 +225,40 @@ def testCrs(self): # HERE GO THE PROVIDER SPECIFIC TESTS def testDateTimeTypes(self): - vl = QgsVectorLayer('%s table="QGIS"."DATE_TIMES" sql=' % - (self.dbconn), "testdatetimes", "oracle") + vl = QgsVectorLayer( + '%s table="QGIS"."DATE_TIMES" sql=' % (self.dbconn), + "testdatetimes", + "oracle", + ) self.assertTrue(vl.isValid()) fields = vl.dataProvider().fields() - self.assertEqual(fields.at(fields.indexFromName( - 'date_field')).type(), QVariant.DateTime) - self.assertEqual(fields.at(fields.indexFromName( - 'datetime_field')).type(), QVariant.DateTime) + self.assertEqual( + fields.at(fields.indexFromName("date_field")).type(), QVariant.DateTime + ) + self.assertEqual( + fields.at(fields.indexFromName("datetime_field")).type(), QVariant.DateTime + ) f = next(vl.getFeatures(QgsFeatureRequest())) - date_idx = vl.fields().lookupField('date_field') + date_idx = vl.fields().lookupField("date_field") self.assertIsInstance(f.attributes()[date_idx], QDateTime) self.assertEqual(f.attributes()[date_idx], QDateTime(2004, 3, 4, 0, 0, 0)) - datetime_idx = vl.fields().lookupField('datetime_field') + datetime_idx = vl.fields().lookupField("datetime_field") self.assertIsInstance(f.attributes()[datetime_idx], QDateTime) - self.assertEqual(f.attributes()[datetime_idx], QDateTime( - QDate(2004, 3, 4), QTime(13, 41, 52))) + self.assertEqual( + f.attributes()[datetime_idx], + QDateTime(QDate(2004, 3, 4), QTime(13, 41, 52)), + ) def testDateInsertion(self): # fix for https://github.com/qgis/QGIS/issues/27087 - vl = QgsVectorLayer('%s table="QGIS"."DATE_TIMES" sql=' % - (self.dbconn), "testdatetimes", "oracle") + vl = QgsVectorLayer( + '%s table="QGIS"."DATE_TIMES" sql=' % (self.dbconn), + "testdatetimes", + "oracle", + ) self.assertTrue(vl.isValid()) for f in vl.getFeatures(): @@ -234,7 +271,7 @@ def testDateInsertion(self): # add a new feature newf = QgsFeature(f.fields(), new_id) - date_idx = vl.fields().lookupField('date_field') + date_idx = vl.fields().lookupField("date_field") dt = QDate(2019, 10, 15) newf.setAttribute(0, new_id) newf.setAttribute(date_idx, dt) @@ -253,11 +290,19 @@ def testValidLayerDiscoverRelationsSimple(self): """ Test implicit relations that can be discovers between tables, based on declared foreign keys. """ - vl = QgsVectorLayer(f'{self.dbconn} table="QGIS"."REFERENCING_TABLE_SIMPLE" sql=', "test_referencing_table_simple", "oracle") + vl = QgsVectorLayer( + f'{self.dbconn} table="QGIS"."REFERENCING_TABLE_SIMPLE" sql=', + "test_referencing_table_simple", + "oracle", + ) self.assertTrue(vl.isValid()) QgsProject.instance().addMapLayer(vl) vls = [ - QgsVectorLayer(f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_1" sql=', "test_referenced_table_1", "oracle"), + QgsVectorLayer( + f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_1" sql=', + "test_referenced_table_1", + "oracle", + ), ] for lyr in vls: self.assertTrue(lyr.isValid()) @@ -274,13 +319,29 @@ def testValidLayerDiscoverRelationsMulti(self): - two fk referencing the same layer - the third fk referencing another layer """ - vl = QgsVectorLayer(f'{self.dbconn} table="QGIS"."REFERENCING_TABLE_MULTI" sql=', "test_referencing_table_multi", "oracle") + vl = QgsVectorLayer( + f'{self.dbconn} table="QGIS"."REFERENCING_TABLE_MULTI" sql=', + "test_referencing_table_multi", + "oracle", + ) QgsProject.instance().addMapLayer(vl) self.assertTrue(vl.isValid()) vls = [ - QgsVectorLayer(f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_1" sql=', "test_referenced_table_1", "oracle"), - QgsVectorLayer(f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_2" sql=', "test_referenced_table_2", "oracle"), - QgsVectorLayer(f'{self.dbconn} table="QGIS"."POINT_DATA" (GEOM) srid=4326 type=POINT sql=', "testpoints", "oracle") + QgsVectorLayer( + f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_1" sql=', + "test_referenced_table_1", + "oracle", + ), + QgsVectorLayer( + f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_2" sql=', + "test_referenced_table_2", + "oracle", + ), + QgsVectorLayer( + f'{self.dbconn} table="QGIS"."POINT_DATA" (GEOM) srid=4326 type=POINT sql=', + "testpoints", + "oracle", + ), ] for lyr in vls: self.assertTrue(lyr.isValid()) @@ -292,13 +353,29 @@ def testValidLayerDiscoverRelationsComposite(self): """ Test implicit relations that can be discovers between tables, based on composite declared foreign keys. """ - vl = QgsVectorLayer(f'{self.dbconn} table="QGIS"."REFERENCING_TABLE_COMPOSITE" sql=', "test_referencing_table_composite", "oracle") + vl = QgsVectorLayer( + f'{self.dbconn} table="QGIS"."REFERENCING_TABLE_COMPOSITE" sql=', + "test_referencing_table_composite", + "oracle", + ) QgsProject.instance().addMapLayer(vl) self.assertTrue(vl.isValid()) vls = [ - QgsVectorLayer(f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_COMPOSITE" sql=', "test_referenced_table_composite", "oracle"), - QgsVectorLayer(f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_2" sql=', "test_referenced_table_2", "oracle"), - QgsVectorLayer(f'{self.dbconn} table="QGIS"."POINT_DATA" (GEOM) srid=4326 type=POINT sql=', "testpoints", "oracle") + QgsVectorLayer( + f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_COMPOSITE" sql=', + "test_referenced_table_composite", + "oracle", + ), + QgsVectorLayer( + f'{self.dbconn} table="QGIS"."REFERENCED_TABLE_2" sql=', + "test_referenced_table_2", + "oracle", + ), + QgsVectorLayer( + f'{self.dbconn} table="QGIS"."POINT_DATA" (GEOM) srid=4326 type=POINT sql=', + "testpoints", + "oracle", + ), ] for lyr in vls: self.assertTrue(lyr.isValid()) @@ -311,7 +388,9 @@ def testInvalidLayerDiscoverRelations(self): """ Test that discover relations feature can be used on invalid layer. """ - vl = QgsVectorLayer(f'{self.dbconn} table="QGIS"."invalid_layer"', "invalid_layer", "oracle") + vl = QgsVectorLayer( + f'{self.dbconn} table="QGIS"."invalid_layer"', "invalid_layer", "oracle" + ) self.assertFalse(vl.isValid()) self.assertEqual(vl.dataProvider().discoverRelations(vl, []), []) @@ -319,66 +398,90 @@ def testValidLayerDiscoverRelationsNone(self): """ Test checks that discover relation feature can be used on a layer that has no relation. """ - vl = QgsVectorLayer('%s table="QGIS"."POINT_DATA" (GEOM) srid=4326 type=POINT sql=' % - (self.dbconn), "testpoints", "oracle") + vl = QgsVectorLayer( + '%s table="QGIS"."POINT_DATA" (GEOM) srid=4326 type=POINT sql=' + % (self.dbconn), + "testpoints", + "oracle", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.dataProvider().discoverRelations(vl, []), []) def testPoints(self): - vl = QgsVectorLayer('%s table="QGIS"."POINT_DATA" (GEOM) srid=4326 type=POINT sql=' % - (self.dbconn), "testpoints", "oracle") + vl = QgsVectorLayer( + '%s table="QGIS"."POINT_DATA" (GEOM) srid=4326 type=POINT sql=' + % (self.dbconn), + "testpoints", + "oracle", + ) self.assertTrue(vl.isValid()) features = [f for f in vl.getFeatures()] - self.assertEqual(features[0].geometry().asWkt(), 'Point (1 2)') - self.assertEqual(features[1].geometry().asWkt(), 'Point Z (1 2 3)') - self.assertEqual(features[2].geometry().asWkt(), 'MultiPoint Z ((1 2 3),(4 5 6))') - self.assertEqual(features[3].geometry().asWkt(), 'MultiPoint ((1 2),(3 4))') - self.assertEqual(features[4].geometry().asWkt(), 'MultiPoint Z ((1 2 3),(4 5 6))') - self.assertEqual(features[5].geometry().asWkt(), 'Point (1 2)') - self.assertEqual(features[6].geometry().asWkt(), 'Point (3 4)') - self.assertEqual(features[7].geometry().asWkt(), 'Point (5 6)') + self.assertEqual(features[0].geometry().asWkt(), "Point (1 2)") + self.assertEqual(features[1].geometry().asWkt(), "Point Z (1 2 3)") + self.assertEqual( + features[2].geometry().asWkt(), "MultiPoint Z ((1 2 3),(4 5 6))" + ) + self.assertEqual(features[3].geometry().asWkt(), "MultiPoint ((1 2),(3 4))") + self.assertEqual( + features[4].geometry().asWkt(), "MultiPoint Z ((1 2 3),(4 5 6))" + ) + self.assertEqual(features[5].geometry().asWkt(), "Point (1 2)") + self.assertEqual(features[6].geometry().asWkt(), "Point (3 4)") + self.assertEqual(features[7].geometry().asWkt(), "Point (5 6)") def testEditPoints(self): - self.createTable('EDIT_POINTS_DATA', 2, 3857) + self.createTable("EDIT_POINTS_DATA", 2, 3857) # We choose SRID=5698 to get Oracle valid geometries because it support 3D - self.createTable('EDIT_POINTSZ_DATA', 3, 5698) + self.createTable("EDIT_POINTSZ_DATA", 3, 5698) points = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=Point table="QGIS"."EDIT_POINTS_DATA" (GEOM) sql=', - 'test_lines', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=3857 type=Point table="QGIS"."EDIT_POINTS_DATA" (GEOM) sql=', + "test_lines", + "oracle", + ) self.assertTrue(points.isValid()) fid = 1 - self.check_geom(points, fid, 'Point (1 2)') + self.check_geom(points, fid, "Point (1 2)") points_z = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=PointZ table="QGIS"."EDIT_POINTSZ_DATA" (GEOM) sql=', - 'test_lines', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=3857 type=PointZ table="QGIS"."EDIT_POINTSZ_DATA" (GEOM) sql=', + "test_lines", + "oracle", + ) self.assertTrue(points_z.isValid()) fid += 1 - self.check_geom(points_z, fid, 'Point Z (1 2 3)') + self.check_geom(points_z, fid, "Point Z (1 2 3)") multipoints = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=MultiPoint table="QGIS"."EDIT_POINTS_DATA" (GEOM) sql=', - 'test_lines', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=3857 type=MultiPoint table="QGIS"."EDIT_POINTS_DATA" (GEOM) sql=', + "test_lines", + "oracle", + ) self.assertTrue(multipoints.isValid()) fid += 1 - self.check_geom(multipoints, fid, 'MultiPoint ((1 2),(3 4))') + self.check_geom(multipoints, fid, "MultiPoint ((1 2),(3 4))") fid += 1 - self.check_geom(multipoints, fid, 'MultiPoint ((1 2))') + self.check_geom(multipoints, fid, "MultiPoint ((1 2))") multipoints_z = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=MultiPointZ table="QGIS"."EDIT_POINTSZ_DATA" (GEOM) sql=', - 'test_lines', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=3857 type=MultiPointZ table="QGIS"."EDIT_POINTSZ_DATA" (GEOM) sql=', + "test_lines", + "oracle", + ) self.assertTrue(multipoints_z.isValid()) fid += 1 - self.check_geom(multipoints_z, fid, 'MultiPointZ ((1 2 7),(3 4 8))') + self.check_geom(multipoints_z, fid, "MultiPointZ ((1 2 7),(3 4 8))") def testLayerStyles(self): @@ -386,50 +489,134 @@ def testLayerStyles(self): # Table without geometry column vl_no_geom = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'id\' table="QGIS"."DATE_TIMES" sql=', 'test', 'oracle') + self.dbconn + ' sslmode=disable key=\'id\' table="QGIS"."DATE_TIMES" sql=', + "test", + "oracle", + ) # Save layer styles - self.assertEqual(self.vl.saveStyleToDatabase("mystyle", "the best", True, "something.ui"), "") - self.assertEqual(vl_no_geom.saveStyleToDatabase("my_other_style", "the very best", True, "else.ui"), "") + self.assertEqual( + self.vl.saveStyleToDatabase("mystyle", "the best", True, "something.ui"), "" + ) + self.assertEqual( + vl_no_geom.saveStyleToDatabase( + "my_other_style", "the very best", True, "else.ui" + ), + "", + ) # Verify presence of styles in database - res, err = QgsProviderRegistry.instance().styleExists('oracle', self.vl.source(), 'mystyle') + res, err = QgsProviderRegistry.instance().styleExists( + "oracle", self.vl.source(), "mystyle" + ) self.assertTrue(res) self.assertFalse(err) - res, err = QgsProviderRegistry.instance().styleExists('oracle', vl_no_geom.source(), 'my_other_style') + res, err = QgsProviderRegistry.instance().styleExists( + "oracle", vl_no_geom.source(), "my_other_style" + ) self.assertTrue(res) self.assertFalse(err) # Verify listing and loading of styles - self.assertEqual(self.vl.listStylesInDatabase(), (1, ['0', '1'], ['mystyle', 'my_other_style'], ['the best', 'the very best'], '')) + self.assertEqual( + self.vl.listStylesInDatabase(), + ( + 1, + ["0", "1"], + ["mystyle", "my_other_style"], + ["the best", "the very best"], + "", + ), + ) _, res = self.vl.loadNamedStyle(self.vl.source()) self.assertTrue(res) - self.assertEqual(vl_no_geom.listStylesInDatabase(), (1, ['1', '0'], ['my_other_style', 'mystyle'], ['the very best', 'the best'], '')) + self.assertEqual( + vl_no_geom.listStylesInDatabase(), + ( + 1, + ["1", "0"], + ["my_other_style", "mystyle"], + ["the very best", "the best"], + "", + ), + ) _, res = vl_no_geom.loadNamedStyle(vl_no_geom.source()) self.assertTrue(res) self.execSQLCommand('DROP TABLE "QGIS"."LAYER_STYLES"') def testCurves(self): - vl = QgsVectorLayer('%s table="QGIS"."LINE_DATA" (GEOM) srid=4326 type=LINESTRING sql=' % - (self.dbconn), "testlines", "oracle") + vl = QgsVectorLayer( + '%s table="QGIS"."LINE_DATA" (GEOM) srid=4326 type=LINESTRING sql=' + % (self.dbconn), + "testlines", + "oracle", + ) self.assertTrue(vl.isValid()) - features = {f['pk']: f for f in vl.getFeatures()} - self.assertTrue(compareWkt(features[1].geometry().asWkt(), 'LineString (1 2, 3 4, 5 6)', 0.00001), features[1].geometry().asWkt()) - self.assertTrue(compareWkt(features[2].geometry().asWkt(), 'CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4)', 0.00001), features[2].geometry().asWkt()) + features = {f["pk"]: f for f in vl.getFeatures()} self.assertTrue( - compareWkt(features[3].geometry().asWkt(), 'CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.20, 10 0.1, 13 4),(13 4, 17 -6))', 0.00001), features[3].geometry().asWkt()) + compareWkt( + features[1].geometry().asWkt(), "LineString (1 2, 3 4, 5 6)", 0.00001 + ), + features[1].geometry().asWkt(), + ) self.assertTrue( - compareWkt(features[4].geometry().asWkt(), 'LineStringZ (1 2 3, 4 5 6, 7 8 9)', 0.00001), features[4].geometry().asWkt()) + compareWkt( + features[2].geometry().asWkt(), + "CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4)", + 0.00001, + ), + features[2].geometry().asWkt(), + ) self.assertTrue( - compareWkt(features[5].geometry().asWkt(), 'MultiLineString ((1 2, 3 4),(5 6, 7 8, 9 10))', 0.00001), features[5].geometry().asWkt()) + compareWkt( + features[3].geometry().asWkt(), + "CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.20, 10 0.1, 13 4),(13 4, 17 -6))", + 0.00001, + ), + features[3].geometry().asWkt(), + ) self.assertTrue( - compareWkt(features[6].geometry().asWkt(), 'MultiLineStringZ ((1 2 11, 3 4 -11),(5 6 9, 7 8 1, 9 10 -3))', 0.00001), features[6].geometry().asWkt()) + compareWkt( + features[4].geometry().asWkt(), + "LineStringZ (1 2 3, 4 5 6, 7 8 9)", + 0.00001, + ), + features[4].geometry().asWkt(), + ) self.assertTrue( - compareWkt(features[7].geometry().asWkt(), 'MultiCurve (CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),CircularString (-11 -3, 5 7, 10 -1))', 0.00001), features[7].geometry().asWkt()) + compareWkt( + features[5].geometry().asWkt(), + "MultiLineString ((1 2, 3 4),(5 6, 7 8, 9 10))", + 0.00001, + ), + features[5].geometry().asWkt(), + ) self.assertTrue( - compareWkt(features[8].geometry().asWkt(), 'MultiCurve (CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),(13 4, 17 -6)), CircularString (1 3, 5 5, 7 3.2, 10 1.1, 13 5),LineString (-11 -3, 5 7, 10 -1))', 0.00001), features[8].geometry().asWkt()) + compareWkt( + features[6].geometry().asWkt(), + "MultiLineStringZ ((1 2 11, 3 4 -11),(5 6 9, 7 8 1, 9 10 -3))", + 0.00001, + ), + features[6].geometry().asWkt(), + ) + self.assertTrue( + compareWkt( + features[7].geometry().asWkt(), + "MultiCurve (CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),CircularString (-11 -3, 5 7, 10 -1))", + 0.00001, + ), + features[7].geometry().asWkt(), + ) + self.assertTrue( + compareWkt( + features[8].geometry().asWkt(), + "MultiCurve (CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),(13 4, 17 -6)), CircularString (1 3, 5 5, 7 3.2, 10 1.1, 13 5),LineString (-11 -3, 5 7, 10 -1))", + 0.00001, + ), + features[8].geometry().asWkt(), + ) def check_geom(self, layer, pk, wkt, wkt_ref=None, check_valid=True): """ @@ -449,97 +636,159 @@ def check_geom(self, layer, pk, wkt, wkt_ref=None, check_valid=True): if check_valid: self.assertTrue(self.conn) query = QSqlQuery(self.conn) - sql = f"""select p.GEOM.st_isvalid() from QGIS.{table} p where "pk" = {pk}""" + sql = ( + f"""select p.GEOM.st_isvalid() from QGIS.{table} p where "pk" = {pk}""" + ) res = query.exec(sql) - self.assertTrue(res, sql + ': ' + query.lastError().text()) + self.assertTrue(res, sql + ": " + query.lastError().text()) query.next() valid = query.value(0) - self.assertTrue(valid, f"geometry '{wkt}' inserted in database is not valid") + self.assertTrue( + valid, f"geometry '{wkt}' inserted in database is not valid" + ) query.finish() expected_wkt = wkt if wkt_ref is None else wkt_ref res_wkt = layer.getFeature(pk).geometry().asWkt() - self.assertTrue(compareWkt(res_wkt, expected_wkt, 0.00001), f"\nactual = {res_wkt}\nexpected = {expected_wkt}") + self.assertTrue( + compareWkt(res_wkt, expected_wkt, 0.00001), + f"\nactual = {res_wkt}\nexpected = {expected_wkt}", + ) def createTable(self, name, dims, srid): self.execSQLCommand(f'DROP TABLE "QGIS"."{name}"', ignore_errors=True) - self.execSQLCommand(f"""DELETE FROM user_sdo_geom_metadata where TABLE_NAME = '{name}'""") - self.execSQLCommand(f"""CREATE TABLE QGIS.{name} ("pk" INTEGER PRIMARY KEY, GEOM SDO_GEOMETRY)""") - self.execSQLCommand("""INSERT INTO user_sdo_geom_metadata (TABLE_NAME, COLUMN_NAME, DIMINFO, SRID) VALUES ( '{}', 'GEOM', sdo_dim_array(sdo_dim_element('X',-50,50,0.005),sdo_dim_element('Y',-50,50,0.005){}),{})""".format( - name, ",sdo_dim_element('Z',-50,50,0.005)" if dims > 2 else "", srid), ignore_errors=True) - self.execSQLCommand("""CREATE INDEX {0}_spatial_idx ON QGIS.{0}(GEOM) INDEXTYPE IS MDSYS.SPATIAL_INDEX""".format(name)) + self.execSQLCommand( + f"""DELETE FROM user_sdo_geom_metadata where TABLE_NAME = '{name}'""" + ) + self.execSQLCommand( + f"""CREATE TABLE QGIS.{name} ("pk" INTEGER PRIMARY KEY, GEOM SDO_GEOMETRY)""" + ) + self.execSQLCommand( + """INSERT INTO user_sdo_geom_metadata (TABLE_NAME, COLUMN_NAME, DIMINFO, SRID) VALUES ( '{}', 'GEOM', sdo_dim_array(sdo_dim_element('X',-50,50,0.005),sdo_dim_element('Y',-50,50,0.005){}),{})""".format( + name, ",sdo_dim_element('Z',-50,50,0.005)" if dims > 2 else "", srid + ), + ignore_errors=True, + ) + self.execSQLCommand( + """CREATE INDEX {0}_spatial_idx ON QGIS.{0}(GEOM) INDEXTYPE IS MDSYS.SPATIAL_INDEX""".format( + name + ) + ) def testEditCurves(self): - self.createTable('EDIT_CURVE_DATA', 2, 3857) + self.createTable("EDIT_CURVE_DATA", 2, 3857) # We choose SRID=5698 (see https://docs.oracle.com/database/121/SPATL/three-dimensional-coordinate-reference-system-support.htm#SPATL626) # to get Oracle valid geometries because it support 3D and arcs (arcs are not supported in geodetic projection) - self.createTable('EDIT_CURVEZ_DATA', 3, 5698) + self.createTable("EDIT_CURVEZ_DATA", 3, 5698) lines = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=LineString table="QGIS"."EDIT_CURVE_DATA" (GEOM) sql=', - 'test_lines', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=3857 type=LineString table="QGIS"."EDIT_CURVE_DATA" (GEOM) sql=', + "test_lines", + "oracle", + ) self.assertTrue(lines.isValid()) fid = 1 - self.check_geom(lines, fid, 'LineString (1 2, 3 4, 5 6)') + self.check_geom(lines, fid, "LineString (1 2, 3 4, 5 6)") fid += 1 - self.check_geom(lines, fid, 'CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4)') + self.check_geom(lines, fid, "CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4)") fid += 1 - self.check_geom(lines, fid, 'CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.20, 10 0.1, 13 4),(13 4, 17 -6))') + self.check_geom( + lines, + fid, + "CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.20, 10 0.1, 13 4),(13 4, 17 -6))", + ) # We choose SRID=5698 (see https://docs.oracle.com/database/121/SPATL/three-dimensional-coordinate-reference-system-support.htm#SPATL626) # to get Oracle valid geometries because it support 3D and arcs (arcs are not supported in geodetic projection) lines_z = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=5698 type=LineStringZ table="QGIS"."EDIT_CURVEZ_DATA" (GEOM) sql=', - 'test_lines', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=5698 type=LineStringZ table="QGIS"."EDIT_CURVEZ_DATA" (GEOM) sql=', + "test_lines", + "oracle", + ) self.assertTrue(lines_z.isValid()) fid += 1 - self.check_geom(lines_z, fid, 'LineStringZ (1 2 3, 4 5 6, 7 8 9)') + self.check_geom(lines_z, fid, "LineStringZ (1 2 3, 4 5 6, 7 8 9)") # 3D arcs and compound curve are invalid # https://support.oracle.com/knowledge/Oracle%20Database%20Products/1446335_1.html # https://support.oracle.com/knowledge/Oracle%20Database%20Products/1641672_1.html fid += 1 - self.check_geom(lines_z, fid, 'CircularStringZ (1 2 1, 5 4 2, 7 2.2 3, 10 0.1 4, 13 4 5)', check_valid=False) + self.check_geom( + lines_z, + fid, + "CircularStringZ (1 2 1, 5 4 2, 7 2.2 3, 10 0.1 4, 13 4 5)", + check_valid=False, + ) fid += 1 - self.check_geom(lines_z, fid, 'CompoundCurveZ ((-1 -5 1, 1 2 2),CircularStringZ (1 2 2, 5 4 3, 7 2.20 4, 10 0.1 5, 13 4 6),(13 4 6, 17 -6 7))', check_valid=False) + self.check_geom( + lines_z, + fid, + "CompoundCurveZ ((-1 -5 1, 1 2 2),CircularStringZ (1 2 2, 5 4 3, 7 2.20 4, 10 0.1 5, 13 4 6),(13 4 6, 17 -6 7))", + check_valid=False, + ) multi_lines = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=MultiLineString table="QGIS"."EDIT_CURVE_DATA" (GEOM) sql=', - 'test_multilines', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=3857 type=MultiLineString table="QGIS"."EDIT_CURVE_DATA" (GEOM) sql=', + "test_multilines", + "oracle", + ) self.assertTrue(multi_lines.isValid()) fid += 1 - self.check_geom(multi_lines, fid, 'MultiLineString ((1 2, 3 4),(5 6, 7 8, 9 10), (11 12, 13 14))') + self.check_geom( + multi_lines, + fid, + "MultiLineString ((1 2, 3 4),(5 6, 7 8, 9 10), (11 12, 13 14))", + ) fid += 1 - self.check_geom(multi_lines, fid, 'MultiLineString ((1 2, 3 4),(5 6, 7 8, 9 10))') + self.check_geom( + multi_lines, fid, "MultiLineString ((1 2, 3 4),(5 6, 7 8, 9 10))" + ) fid += 1 - self.check_geom(multi_lines, fid, 'MultiLineString ((1 2, 3 4))') + self.check_geom(multi_lines, fid, "MultiLineString ((1 2, 3 4))") multi_lines_z = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=5698 type=MultiLineStringZ table="QGIS"."EDIT_CURVEZ_DATA" (GEOM) sql=', - 'test_multilines', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=5698 type=MultiLineStringZ table="QGIS"."EDIT_CURVEZ_DATA" (GEOM) sql=', + "test_multilines", + "oracle", + ) self.assertTrue(multi_lines_z.isValid()) fid += 1 - self.check_geom(multi_lines_z, fid, 'MultiLineStringZ ((1 2 11, 3 4 -11),(5 6 9, 7 8 1, 9 10 -3))') + self.check_geom( + multi_lines_z, + fid, + "MultiLineStringZ ((1 2 11, 3 4 -11),(5 6 9, 7 8 1, 9 10 -3))", + ) fid += 1 - self.check_geom(multi_lines_z, fid, 'MultiLineStringZ ((1 2 1, 3 4 2),(5 6 3, 7 8 4, 9 10 5), (11 12 6, 13 14 7))') + self.check_geom( + multi_lines_z, + fid, + "MultiLineStringZ ((1 2 1, 3 4 2),(5 6 3, 7 8 4, 9 10 5), (11 12 6, 13 14 7))", + ) fid += 1 - self.check_geom(multi_lines_z, fid, 'MultiLineStringZ ((1 2 1, 3 4 2))') + self.check_geom(multi_lines_z, fid, "MultiLineStringZ ((1 2 1, 3 4 2))") multi_curves = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=MultiCurve table="QGIS"."EDIT_CURVE_DATA" (GEOM) sql=', - 'test_multicurves', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=3857 type=MultiCurve table="QGIS"."EDIT_CURVE_DATA" (GEOM) sql=', + "test_multicurves", + "oracle", + ) self.assertTrue(multi_curves.isValid()) # There is no way to represent a compound curve with only one LineString or CircularString in Oracle database @@ -547,238 +796,556 @@ def testEditCurves(self): # So, this two different WKTs inputs generate the same data in Oracle database, and so the same WKT # output representation (with CompoundCurve() around each MultiCurve parts) fid += 1 - self.check_geom(multi_curves, fid, - 'MultiCurve (CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),(13 4, 17 -6)),CircularString (1 3, 5 5, 7 3.2, 10 1.1, 13 5),LineString (-11 -3, 5 7, 10 -1))') + self.check_geom( + multi_curves, + fid, + "MultiCurve (CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),(13 4, 17 -6)),CircularString (1 3, 5 5, 7 3.2, 10 1.1, 13 5),LineString (-11 -3, 5 7, 10 -1))", + ) fid += 1 - self.check_geom(multi_curves, fid, - 'MultiCurve (CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),(13 4, 17 -6)),CompoundCurve (CircularString (1 3, 5 5, 7 3.2, 10 1.1, 13 5)),(-11 -3, 5 7, 10 -1))', - 'MultiCurve (CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),(13 4, 17 -6)),CircularString (1 3, 5 5, 7 3.2, 10 1.1, 13 5),LineString (-11 -3, 5 7, 10 -1))') + self.check_geom( + multi_curves, + fid, + "MultiCurve (CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),(13 4, 17 -6)),CompoundCurve (CircularString (1 3, 5 5, 7 3.2, 10 1.1, 13 5)),(-11 -3, 5 7, 10 -1))", + "MultiCurve (CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),(13 4, 17 -6)),CircularString (1 3, 5 5, 7 3.2, 10 1.1, 13 5),LineString (-11 -3, 5 7, 10 -1))", + ) fid += 1 - self.check_geom(multi_curves, fid, - 'MultiCurve (CompoundCurve ((-1 -5, 1 2),(1 2, 17 -6)),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4))') + self.check_geom( + multi_curves, + fid, + "MultiCurve (CompoundCurve ((-1 -5, 1 2),(1 2, 17 -6)),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4))", + ) fid += 1 - self.check_geom(multi_curves, fid, - 'MultiCurve (CompoundCurve ((-1 -5, 1 2),(1 2, 17 -6)))') + self.check_geom( + multi_curves, fid, "MultiCurve (CompoundCurve ((-1 -5, 1 2),(1 2, 17 -6)))" + ) multi_curves_z = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=5698 type=MultiCurveZ table="QGIS"."EDIT_CURVEZ_DATA" (GEOM) sql=', - 'test_multicurves_z', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=5698 type=MultiCurveZ table="QGIS"."EDIT_CURVEZ_DATA" (GEOM) sql=', + "test_multicurves_z", + "oracle", + ) self.assertTrue(multi_curves_z.isValid()) # ora-54530 : 3D compound lines are invalid since 11.2.0.3 : https://support.oracle.com/knowledge/Oracle%20Database%20Products/1446335_1.html fid += 1 - self.check_geom(multi_curves_z, fid, - 'MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),CircularStringZ (1 2 4, 5 4 5, 7 2.2 6, 10 0.1 7, 13 4 8),(13 4 8, 17 -6 9)), CircularStringZ (1 3 2, 5 5 3, 7 3.2 4, 10 1.1 5, 13 5 6),LineStringZ (-11 -3 1, 5 7 2, 10 -1 3))', - check_valid=False) + self.check_geom( + multi_curves_z, + fid, + "MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),CircularStringZ (1 2 4, 5 4 5, 7 2.2 6, 10 0.1 7, 13 4 8),(13 4 8, 17 -6 9)), CircularStringZ (1 3 2, 5 5 3, 7 3.2 4, 10 1.1 5, 13 5 6),LineStringZ (-11 -3 1, 5 7 2, 10 -1 3))", + check_valid=False, + ) fid += 1 - self.check_geom(multi_curves_z, fid, - 'MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),CircularStringZ (1 2 4, 5 4 5, 7 2.2 6, 10 0.1 7, 13 4 8),(13 4 8, 17 -6 9)),CompoundCurveZ (CircularStringZ (1 3 2, 5 5 3, 7 3.2 4, 10 1.1 5, 13 5 6)),(-11 -3 1, 5 7 2, 10 -1 3))', - 'MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),CircularStringZ (1 2 4, 5 4 5, 7 2.2 6, 10 0.1 7, 13 4 8),(13 4 8, 17 -6 9)), CircularStringZ (1 3 2, 5 5 3, 7 3.2 4, 10 1.1 5, 13 5 6),LineStringZ (-11 -3 1, 5 7 2, 10 -1 3))', - check_valid=False) + self.check_geom( + multi_curves_z, + fid, + "MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),CircularStringZ (1 2 4, 5 4 5, 7 2.2 6, 10 0.1 7, 13 4 8),(13 4 8, 17 -6 9)),CompoundCurveZ (CircularStringZ (1 3 2, 5 5 3, 7 3.2 4, 10 1.1 5, 13 5 6)),(-11 -3 1, 5 7 2, 10 -1 3))", + "MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),CircularStringZ (1 2 4, 5 4 5, 7 2.2 6, 10 0.1 7, 13 4 8),(13 4 8, 17 -6 9)), CircularStringZ (1 3 2, 5 5 3, 7 3.2 4, 10 1.1 5, 13 5 6),LineStringZ (-11 -3 1, 5 7 2, 10 -1 3))", + check_valid=False, + ) fid += 1 - self.check_geom(multi_curves_z, fid, - 'MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),(1 2 4, 17 -6 8)))', - check_valid=False) + self.check_geom( + multi_curves_z, + fid, + "MultiCurveZ (CompoundCurveZ ((-1 -5 3, 1 2 4),(1 2 4, 17 -6 8)))", + check_valid=False, + ) def testSurfaces(self): - vl = QgsVectorLayer('%s table="QGIS"."POLY_DATA" (GEOM) srid=4326 type=POLYGON sql=' % - (self.dbconn), "testpoly", "oracle") + vl = QgsVectorLayer( + '%s table="QGIS"."POLY_DATA" (GEOM) srid=4326 type=POLYGON sql=' + % (self.dbconn), + "testpoly", + "oracle", + ) self.assertTrue(vl.isValid()) - features = {f['pk']: f for f in vl.getFeatures()} - self.assertTrue(compareWkt(features[1].geometry().asWkt(), 'Polygon ((1 2, 11 2, 11 22, 1 22, 1 2))', 0.00001), features[1].geometry().asWkt()) - self.assertTrue(compareWkt(features[2].geometry().asWkt(), 'PolygonZ ((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3))', 0.00001), features[2].geometry().asWkt()) + features = {f["pk"]: f for f in vl.getFeatures()} + self.assertTrue( + compareWkt( + features[1].geometry().asWkt(), + "Polygon ((1 2, 11 2, 11 22, 1 22, 1 2))", + 0.00001, + ), + features[1].geometry().asWkt(), + ) self.assertTrue( - compareWkt(features[3].geometry().asWkt(), 'Polygon ((1 2, 11 2, 11 22, 1 22, 1 2),(5 6, 8 9, 8 6, 5 6),(3 4, 5 6, 3 6, 3 4))', 0.00001), features[3].geometry().asWkt()) + compareWkt( + features[2].geometry().asWkt(), + "PolygonZ ((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3))", + 0.00001, + ), + features[2].geometry().asWkt(), + ) self.assertTrue( - compareWkt(features[4].geometry().asWkt(), 'PolygonZ ((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3),(5 6 1, 8 9 -1, 8 6 2, 5 6 1))', 0.00001), features[4].geometry().asWkt()) + compareWkt( + features[3].geometry().asWkt(), + "Polygon ((1 2, 11 2, 11 22, 1 22, 1 2),(5 6, 8 9, 8 6, 5 6),(3 4, 5 6, 3 6, 3 4))", + 0.00001, + ), + features[3].geometry().asWkt(), + ) self.assertTrue( - compareWkt(features[5].geometry().asWkt(), 'Polygon ((1 2, 11 2, 11 22, 1 22, 1 2))', 0.00001), features[5].geometry().asWkt()) + compareWkt( + features[4].geometry().asWkt(), + "PolygonZ ((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3),(5 6 1, 8 9 -1, 8 6 2, 5 6 1))", + 0.00001, + ), + features[4].geometry().asWkt(), + ) self.assertTrue( - compareWkt(features[6].geometry().asWkt(), 'CurvePolygon (CircularString (6.76923076923076916 22.82875364393326834, 17.98259979777942519 11.61538461538461497, 6.76923076923076916 0.40201558683595984, -4.44413825931788598 11.61538461538461497, 6.76923076923076916 22.82875364393326834))', 0.00001), features[6].geometry().asWkt()) + compareWkt( + features[5].geometry().asWkt(), + "Polygon ((1 2, 11 2, 11 22, 1 22, 1 2))", + 0.00001, + ), + features[5].geometry().asWkt(), + ) self.assertTrue( - compareWkt(features[7].geometry().asWkt(), 'MultiPolygon (((1 2, 11 2, 11 22, 1 22, 1 2)),((1 2, 11 2, 11 22, 1 22, 1 2),(5 6, 8 9, 8 6, 5 6),(3 4, 5 6, 3 6, 3 4)))', 0.00001), features[7].geometry().asWkt()) + compareWkt( + features[6].geometry().asWkt(), + "CurvePolygon (CircularString (6.76923076923076916 22.82875364393326834, 17.98259979777942519 11.61538461538461497, 6.76923076923076916 0.40201558683595984, -4.44413825931788598 11.61538461538461497, 6.76923076923076916 22.82875364393326834))", + 0.00001, + ), + features[6].geometry().asWkt(), + ) self.assertTrue( - compareWkt(features[8].geometry().asWkt(), 'MultiPolygonZ (((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3)),((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3),(5 6 1, 8 9 -1, 8 6 2, 5 6 1)))', 0.00001), features[8].geometry().asWkt()) + compareWkt( + features[7].geometry().asWkt(), + "MultiPolygon (((1 2, 11 2, 11 22, 1 22, 1 2)),((1 2, 11 2, 11 22, 1 22, 1 2),(5 6, 8 9, 8 6, 5 6),(3 4, 5 6, 3 6, 3 4)))", + 0.00001, + ), + features[7].geometry().asWkt(), + ) self.assertTrue( - compareWkt(features[9].geometry().asWkt(), 'CurvePolygon (CircularString (1 3, 3 5, 4 7, 7 3, 1 3))', 0.00001), features[9].geometry().asWkt()) + compareWkt( + features[8].geometry().asWkt(), + "MultiPolygonZ (((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3)),((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3),(5 6 1, 8 9 -1, 8 6 2, 5 6 1)))", + 0.00001, + ), + features[8].geometry().asWkt(), + ) self.assertTrue( - compareWkt(features[10].geometry().asWkt(), 'CurvePolygon (CircularString (1 3, 3 5, 4 7, 7 3, 1 3),CircularString (3.1 3.3, 3.3 3.5, 3.4 3.7, 3.7 3.3, 3.1 3.3))', 0.00001), features[10].geometry().asWkt()) + compareWkt( + features[9].geometry().asWkt(), + "CurvePolygon (CircularString (1 3, 3 5, 4 7, 7 3, 1 3))", + 0.00001, + ), + features[9].geometry().asWkt(), + ) self.assertTrue( - compareWkt(features[11].geometry().asWkt(), 'CurvePolygon(CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.20, 10 0.1, 13 4),(13 4, 17 -6),CircularString (17 -6, 5 -7, -1 -5)))', 0.00001), features[11].geometry().asWkt()) + compareWkt( + features[10].geometry().asWkt(), + "CurvePolygon (CircularString (1 3, 3 5, 4 7, 7 3, 1 3),CircularString (3.1 3.3, 3.3 3.5, 3.4 3.7, 3.7 3.3, 3.1 3.3))", + 0.00001, + ), + features[10].geometry().asWkt(), + ) self.assertTrue( - compareWkt(features[12].geometry().asWkt(), 'MultiSurface (CurvePolygon (CircularString (1 3, 3 5, 4 7, 7 3, 1 3)),CurvePolygon (CircularString (11 3, 13 5, 14 7, 17 3, 11 3)))', 0.00001), features[12].geometry().asWkt()) + compareWkt( + features[11].geometry().asWkt(), + "CurvePolygon(CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.20, 10 0.1, 13 4),(13 4, 17 -6),CircularString (17 -6, 5 -7, -1 -5)))", + 0.00001, + ), + features[11].geometry().asWkt(), + ) self.assertTrue( - compareWkt(features[13].geometry().asWkt(), 'CurvePolygonZ(CompoundCurveZ (CircularStringZ (-1 -5 1, 5 -7 2, 17 -6 3), (17 -6 3, 13 4 4), CircularStringZ (13 4 4, 10 0.1 5, 7 2.20 6, 5 4 7, 1 2 8),(1 2 8, -1 -5 1)))', 0.00001), features[13].geometry().asWkt()) + compareWkt( + features[12].geometry().asWkt(), + "MultiSurface (CurvePolygon (CircularString (1 3, 3 5, 4 7, 7 3, 1 3)),CurvePolygon (CircularString (11 3, 13 5, 14 7, 17 3, 11 3)))", + 0.00001, + ), + features[12].geometry().asWkt(), + ) self.assertTrue( - compareWkt(features[14].geometry().asWkt(), 'MultiPolygon (((22 22, 28 22, 28 26, 22 26, 22 22)))', 0.00001), features[14].geometry().asWkt()) + compareWkt( + features[13].geometry().asWkt(), + "CurvePolygonZ(CompoundCurveZ (CircularStringZ (-1 -5 1, 5 -7 2, 17 -6 3), (17 -6 3, 13 4 4), CircularStringZ (13 4 4, 10 0.1 5, 7 2.20 6, 5 4 7, 1 2 8),(1 2 8, -1 -5 1)))", + 0.00001, + ), + features[13].geometry().asWkt(), + ) self.assertTrue( - compareWkt(features[15].geometry().asWkt(), 'MultiSurface (CurvePolygon(CompoundCurve (CircularString (-1 -5, 5 -7, 17 -6), (17 -6, -1 -5))), CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3)))', 0.00001), features[15].geometry().asWkt()) + compareWkt( + features[14].geometry().asWkt(), + "MultiPolygon (((22 22, 28 22, 28 26, 22 26, 22 22)))", + 0.00001, + ), + features[14].geometry().asWkt(), + ) + self.assertTrue( + compareWkt( + features[15].geometry().asWkt(), + "MultiSurface (CurvePolygon(CompoundCurve (CircularString (-1 -5, 5 -7, 17 -6), (17 -6, -1 -5))), CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3)))", + 0.00001, + ), + features[15].geometry().asWkt(), + ) def testEditSurfaces(self): - self.createTable('EDIT_SURFACE_DATA', 2, 3857) + self.createTable("EDIT_SURFACE_DATA", 2, 3857) # We choose SRID=5698 (see https://docs.oracle.com/database/121/SPATL/three-dimensional-coordinate-reference-system-support.htm#SPATL626) # to get Oracle valid geometries because it support 3D and arcs (arcs are not supported in geodetic projection) - self.createTable('EDIT_SURFACEZ_DATA', 3, 5698) + self.createTable("EDIT_SURFACEZ_DATA", 3, 5698) polygon = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=Polygon table="QGIS"."EDIT_SURFACE_DATA" (GEOM) sql=', - 'test_polygon', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=3857 type=Polygon table="QGIS"."EDIT_SURFACE_DATA" (GEOM) sql=', + "test_polygon", + "oracle", + ) self.assertTrue(polygon.isValid()) fid = 1 - self.check_geom(polygon, fid, 'Polygon ((1 2, 11 2, 11 22, 1 22, 1 2))') + self.check_geom(polygon, fid, "Polygon ((1 2, 11 2, 11 22, 1 22, 1 2))") fid += 1 - self.check_geom(polygon, fid, 'Polygon ((1 2, 11 2, 11 22, 1 22, 1 2),(5 6, 8 9, 8 6, 5 6),(3 4, 3 6, 5 6, 3 4))') + self.check_geom( + polygon, + fid, + "Polygon ((1 2, 11 2, 11 22, 1 22, 1 2),(5 6, 8 9, 8 6, 5 6),(3 4, 3 6, 5 6, 3 4))", + ) fid += 1 # Outer ring in clockwise order --> reversed on writing - self.check_geom(polygon, fid, 'Polygon ((0 0, 0 1, 1 1, 0 0))', 'Polygon ((0 0, 1 1, 0 1, 0 0))') + self.check_geom( + polygon, + fid, + "Polygon ((0 0, 0 1, 1 1, 0 0))", + "Polygon ((0 0, 1 1, 0 1, 0 0))", + ) fid += 1 # Outer ring in clockwise order --> reversed on writing. Inner ring in clockwise order --> unmodified - self.check_geom(polygon, fid, 'Polygon ((0 0, 0 1, 1 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2))', 'Polygon ((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2))') + self.check_geom( + polygon, + fid, + "Polygon ((0 0, 0 1, 1 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2))", + "Polygon ((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2))", + ) fid += 1 # Inner ring in counterclockwise order --> reversed on writing. Outer ring in counterclockwise order --> unmodified - self.check_geom(polygon, fid, 'Polygon ((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.7 0.9, 0.1 0.9, 0.1 0.2))', 'Polygon ((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2))') + self.check_geom( + polygon, + fid, + "Polygon ((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.7 0.9, 0.1 0.9, 0.1 0.2))", + "Polygon ((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2))", + ) fid += 1 polygon_z = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=5698 type=PolygonZ table="QGIS"."EDIT_SURFACEZ_DATA" (GEOM) sql=', - 'test_polygon_z', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=5698 type=PolygonZ table="QGIS"."EDIT_SURFACEZ_DATA" (GEOM) sql=', + "test_polygon_z", + "oracle", + ) self.assertTrue(polygon_z.isValid()) # non planar polygon are invalid : to http://ora.codes/ora-54505/ - self.check_geom(polygon_z, fid, 'PolygonZ ((1 2 3, 11 2 3, 11 22 3, 1 22 3, 1 2 3))') + self.check_geom( + polygon_z, fid, "PolygonZ ((1 2 3, 11 2 3, 11 22 3, 1 22 3, 1 2 3))" + ) fid += 1 - self.check_geom(polygon_z, fid, 'PolygonZ ((1 2 4, 11 2 5, 11 22 6, 1 22 7, 1 2 1))', check_valid=False) + self.check_geom( + polygon_z, + fid, + "PolygonZ ((1 2 4, 11 2 5, 11 22 6, 1 22 7, 1 2 1))", + check_valid=False, + ) fid += 1 - self.check_geom(polygon_z, fid, 'PolygonZ ((1 2 3, 11 2 3, 11 22 3, 1 22 3, 1 2 3),(5 6 3, 8 9 3, 8 6 3, 5 6 3))') + self.check_geom( + polygon_z, + fid, + "PolygonZ ((1 2 3, 11 2 3, 11 22 3, 1 22 3, 1 2 3),(5 6 3, 8 9 3, 8 6 3, 5 6 3))", + ) fid += 1 - self.check_geom(polygon_z, fid, 'PolygonZ ((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3),(5 6 1, 8 9 -1, 8 6 2, 5 6 1))', check_valid=False) + self.check_geom( + polygon_z, + fid, + "PolygonZ ((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3),(5 6 1, 8 9 -1, 8 6 2, 5 6 1))", + check_valid=False, + ) fid += 1 multi_polygon = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=MultiPolygon table="QGIS"."EDIT_SURFACE_DATA" (GEOM) sql=', - 'multi_polygon', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=3857 type=MultiPolygon table="QGIS"."EDIT_SURFACE_DATA" (GEOM) sql=', + "multi_polygon", + "oracle", + ) self.assertTrue(multi_polygon.isValid()) - self.check_geom(multi_polygon, fid, 'MultiPolygon (((22 22, 28 22, 28 26, 22 26, 22 22)),((1 2, 11 2, 11 22, 1 22, 1 2),(5 6, 8 9, 8 6, 5 6),(3 4, 3 6, 5 6, 3 4)))') + self.check_geom( + multi_polygon, + fid, + "MultiPolygon (((22 22, 28 22, 28 26, 22 26, 22 22)),((1 2, 11 2, 11 22, 1 22, 1 2),(5 6, 8 9, 8 6, 5 6),(3 4, 3 6, 5 6, 3 4)))", + ) fid += 1 - self.check_geom(multi_polygon, fid, 'MultiPolygon (((22 22, 28 22, 28 26, 22 26, 22 22)))') + self.check_geom( + multi_polygon, fid, "MultiPolygon (((22 22, 28 22, 28 26, 22 26, 22 22)))" + ) fid += 1 multi_polygon_z = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=5698 type=MultiPolygonZ table="QGIS"."EDIT_SURFACEZ_DATA" (GEOM) sql=', - 'multi_polygon_z', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=5698 type=MultiPolygonZ table="QGIS"."EDIT_SURFACEZ_DATA" (GEOM) sql=', + "multi_polygon_z", + "oracle", + ) self.assertTrue(multi_polygon_z.isValid()) - self.check_geom(multi_polygon_z, fid, 'MultiPolygonZ (((22 22 1, 28 22 2, 28 26 3, 22 26 4, 22 22 1)),((1 2 3, 11 2 4, 11 22 5, 1 22 6, 1 2 3),(5 6 1, 8 9 2, 8 6 3, 5 6 1),(3 4 0, 3 6 1, 5 6 2, 3 4 0)))', check_valid=False) + self.check_geom( + multi_polygon_z, + fid, + "MultiPolygonZ (((22 22 1, 28 22 2, 28 26 3, 22 26 4, 22 22 1)),((1 2 3, 11 2 4, 11 22 5, 1 22 6, 1 2 3),(5 6 1, 8 9 2, 8 6 3, 5 6 1),(3 4 0, 3 6 1, 5 6 2, 3 4 0)))", + check_valid=False, + ) fid += 1 curve_polygon = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=CurvePolygon table="QGIS"."EDIT_SURFACE_DATA" (GEOM) sql=', - 'curve_polygon', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=3857 type=CurvePolygon table="QGIS"."EDIT_SURFACE_DATA" (GEOM) sql=', + "curve_polygon", + "oracle", + ) self.assertTrue(curve_polygon.isValid()) - self.check_geom(curve_polygon, fid, 'CurvePolygon (CircularString (6.76923076923076916 22.82875364393326834, -4.44413825931788598 11.61538461538461497, 6.76923076923076916 0.40201558683595984, 17.98259979777942519 11.61538461538461497, 6.76923076923076916 22.82875364393326834))') + self.check_geom( + curve_polygon, + fid, + "CurvePolygon (CircularString (6.76923076923076916 22.82875364393326834, -4.44413825931788598 11.61538461538461497, 6.76923076923076916 0.40201558683595984, 17.98259979777942519 11.61538461538461497, 6.76923076923076916 22.82875364393326834))", + ) fid += 1 - self.check_geom(curve_polygon, fid, 'CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3))') + self.check_geom( + curve_polygon, + fid, + "CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3))", + ) fid += 1 - self.check_geom(curve_polygon, fid, 'CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3),CircularString (3.1 3.3, 3.3 3.5, 3.4 3.7, 3.7 3.3, 3.1 3.3))') + self.check_geom( + curve_polygon, + fid, + "CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3),CircularString (3.1 3.3, 3.3 3.5, 3.4 3.7, 3.7 3.3, 3.1 3.3))", + ) fid += 1 - self.check_geom(curve_polygon, fid, 'CurvePolygon(CompoundCurve (CircularString (-1 -5, 5 -7, 17 -6), (17 -6, 13 4), CircularString (13 4, 10 0.1, 7 2.20, 5 4, 1 2),(1 2, -1 -5)))') + self.check_geom( + curve_polygon, + fid, + "CurvePolygon(CompoundCurve (CircularString (-1 -5, 5 -7, 17 -6), (17 -6, 13 4), CircularString (13 4, 10 0.1, 7 2.20, 5 4, 1 2),(1 2, -1 -5)))", + ) fid += 1 - self.check_geom(curve_polygon, fid, 'CurvePolygon(CircularString (0 0, 30 0, 30 20, 0 30, 0 0), CompoundCurve ((13 10, 17 2), CircularString (17 2, 1 1, 13 10)))') + self.check_geom( + curve_polygon, + fid, + "CurvePolygon(CircularString (0 0, 30 0, 30 20, 0 30, 0 0), CompoundCurve ((13 10, 17 2), CircularString (17 2, 1 1, 13 10)))", + ) fid += 1 - self.check_geom(curve_polygon, fid, 'CurvePolygon(CircularString (0 0, 30 0, 30 20, 0 30, 0 0), (13 10, 17 2, 1 1, 13 10))') + self.check_geom( + curve_polygon, + fid, + "CurvePolygon(CircularString (0 0, 30 0, 30 20, 0 30, 0 0), (13 10, 17 2, 1 1, 13 10))", + ) fid += 1 - self.check_geom(curve_polygon, fid, 'CurvePolygon((0 0, 30 0, 30 20, 0 30, 0 0), CircularString (1 3, 3 5, 4 7, 7 3, 1 3))') + self.check_geom( + curve_polygon, + fid, + "CurvePolygon((0 0, 30 0, 30 20, 0 30, 0 0), CircularString (1 3, 3 5, 4 7, 7 3, 1 3))", + ) fid += 1 # Reverse orientation of outer ring - self.check_geom(curve_polygon, fid, 'CurvePolygon((0 0, 0 30, 30 20, 30 0, 0 0), CircularString (1 3, 3 5, 4 7, 7 3, 1 3))', 'CurvePolygon((0 0, 30 0, 30 20, 0 30, 0 0), CircularString (1 3, 3 5, 4 7, 7 3, 1 3))') + self.check_geom( + curve_polygon, + fid, + "CurvePolygon((0 0, 0 30, 30 20, 30 0, 0 0), CircularString (1 3, 3 5, 4 7, 7 3, 1 3))", + "CurvePolygon((0 0, 30 0, 30 20, 0 30, 0 0), CircularString (1 3, 3 5, 4 7, 7 3, 1 3))", + ) fid += 1 # Reverse orientation of outer ring - self.check_geom(curve_polygon, fid, 'CurvePolygon( CompoundCurve ((0 0, 0 1, 1 1),(1 1,0 0)))', 'CurvePolygon (CompoundCurve ((0 0, 1 1),(1 1, 0 1, 0 0)))') + self.check_geom( + curve_polygon, + fid, + "CurvePolygon( CompoundCurve ((0 0, 0 1, 1 1),(1 1,0 0)))", + "CurvePolygon (CompoundCurve ((0 0, 1 1),(1 1, 0 1, 0 0)))", + ) fid += 1 curve_polygon_z = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=5698 type=CurvePolygonZ table="QGIS"."EDIT_SURFACEZ_DATA" (GEOM) sql=', - 'curve_polygon_z', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=5698 type=CurvePolygonZ table="QGIS"."EDIT_SURFACEZ_DATA" (GEOM) sql=', + "curve_polygon_z", + "oracle", + ) self.assertTrue(curve_polygon_z.isValid()) # There is no way to build a valid 3D curve polygon (even with make3d from the valid 2D one) # we get ora-13033 although everything is OK in sdo_elem_array ... - self.check_geom(curve_polygon_z, fid, 'CurvePolygonZ (CircularStringZ (6.76923076923076916 22.82875364393326834 1, -4.44413825931788598 11.61538461538461497 2, 6.76923076923076916 0.40201558683595984 3, 17.98259979777942519 11.61538461538461497 4, 6.76923076923076916 22.82875364393326834 1))', check_valid=False) + self.check_geom( + curve_polygon_z, + fid, + "CurvePolygonZ (CircularStringZ (6.76923076923076916 22.82875364393326834 1, -4.44413825931788598 11.61538461538461497 2, 6.76923076923076916 0.40201558683595984 3, 17.98259979777942519 11.61538461538461497 4, 6.76923076923076916 22.82875364393326834 1))", + check_valid=False, + ) fid += 1 - self.check_geom(curve_polygon_z, fid, 'CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 2, 1 3 1))', check_valid=False) + self.check_geom( + curve_polygon_z, + fid, + "CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 2, 1 3 1))", + check_valid=False, + ) fid += 1 - self.check_geom(curve_polygon_z, fid, 'CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 4, 1 3 1),CircularStringZ (3.1 3.3 1, 3.3 3.5 2, 3.4 3.7 3, 3.7 3.3 4, 3.1 3.3 1))', check_valid=False) + self.check_geom( + curve_polygon_z, + fid, + "CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 4, 1 3 1),CircularStringZ (3.1 3.3 1, 3.3 3.5 2, 3.4 3.7 3, 3.7 3.3 4, 3.1 3.3 1))", + check_valid=False, + ) fid += 1 - self.check_geom(curve_polygon_z, fid, 'CurvePolygonZ(CompoundCurveZ (CircularStringZ (-1 -5 1, 5 -7 2, 17 -6 3), (17 -6 3, 13 4 4), CircularStringZ (13 4 4, 10 0.1 5, 7 2.20 6, 5 4 7, 1 2 8),(1 2 8, -1 -5 1)))', check_valid=False) + self.check_geom( + curve_polygon_z, + fid, + "CurvePolygonZ(CompoundCurveZ (CircularStringZ (-1 -5 1, 5 -7 2, 17 -6 3), (17 -6 3, 13 4 4), CircularStringZ (13 4 4, 10 0.1 5, 7 2.20 6, 5 4 7, 1 2 8),(1 2 8, -1 -5 1)))", + check_valid=False, + ) fid += 1 - self.check_geom(curve_polygon_z, fid, 'CurvePolygonZ(CircularStringZ (0 0 1, 30 0 2, 30 20 3, 0 30 4, 0 0 5), CompoundCurveZ ((13 10 1, 17 2 3), CircularStringZ (17 2 3, 1 1 5, 13 10 1)))', check_valid=False) + self.check_geom( + curve_polygon_z, + fid, + "CurvePolygonZ(CircularStringZ (0 0 1, 30 0 2, 30 20 3, 0 30 4, 0 0 5), CompoundCurveZ ((13 10 1, 17 2 3), CircularStringZ (17 2 3, 1 1 5, 13 10 1)))", + check_valid=False, + ) fid += 1 multi_surface = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=3857 type=MultiSurface table="QGIS"."EDIT_SURFACE_DATA" (GEOM) sql=', - 'multi_surface', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=3857 type=MultiSurface table="QGIS"."EDIT_SURFACE_DATA" (GEOM) sql=', + "multi_surface", + "oracle", + ) self.assertTrue(multi_surface.isValid()) - self.check_geom(multi_surface, fid, 'MultiSurface (CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3)),CurvePolygon (CircularString (11 3, 17 3, 14 7, 13 5, 11 3)))') + self.check_geom( + multi_surface, + fid, + "MultiSurface (CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3)),CurvePolygon (CircularString (11 3, 17 3, 14 7, 13 5, 11 3)))", + ) fid += 1 - self.check_geom(multi_surface, fid, 'MultiSurface (CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3)))') + self.check_geom( + multi_surface, + fid, + "MultiSurface (CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3)))", + ) fid += 1 - self.check_geom(multi_surface, fid, 'MultiSurface (CurvePolygon(CompoundCurve (CircularString (-1 -5, 5 -7, 17 -6), (17 -6, -1 -5))), CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3)))') + self.check_geom( + multi_surface, + fid, + "MultiSurface (CurvePolygon(CompoundCurve (CircularString (-1 -5, 5 -7, 17 -6), (17 -6, -1 -5))), CurvePolygon (CircularString (1 3, 7 3, 4 7, 3 5, 1 3)))", + ) fid += 1 - wkt = 'MultiSurface (((0 0, 1 0, 1 1, 0 0)),((100 100, 101 100, 101 101, 100 100)))' - self.check_geom(multi_surface, fid, wkt, wkt.replace('MultiSurface', 'MultiPolygon')) + wkt = "MultiSurface (((0 0, 1 0, 1 1, 0 0)),((100 100, 101 100, 101 101, 100 100)))" + self.check_geom( + multi_surface, fid, wkt, wkt.replace("MultiSurface", "MultiPolygon") + ) fid += 1 # Outer ring in clockwise order --> reversed on writing - self.check_geom(multi_surface, fid, 'MultiSurface( Polygon ((0 0, 0 1, 1 1, 0 0)))', 'MultiPolygon (((0 0, 1 1, 0 1, 0 0)))') + self.check_geom( + multi_surface, + fid, + "MultiSurface( Polygon ((0 0, 0 1, 1 1, 0 0)))", + "MultiPolygon (((0 0, 1 1, 0 1, 0 0)))", + ) fid += 1 # Outer ring in clockwise order --> reversed on writing. Inner ring in clockwise order --> unmodified - self.check_geom(multi_surface, fid, 'MultiSurface(Polygon ((0 0, 0 1, 1 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2)))', 'MultiPolygon (((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2)))') + self.check_geom( + multi_surface, + fid, + "MultiSurface(Polygon ((0 0, 0 1, 1 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2)))", + "MultiPolygon (((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2)))", + ) fid += 1 # Inner ring in counterclockwise order --> reversed on writing. Outer ring in counterclockwise order --> unmodified - self.check_geom(multi_surface, fid, 'MultiSurface(Polygon ((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.7 0.9, 0.1 0.9, 0.1 0.2)))', 'MultiPolygon (((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2)))') + self.check_geom( + multi_surface, + fid, + "MultiSurface(Polygon ((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.7 0.9, 0.1 0.9, 0.1 0.2)))", + "MultiPolygon (((0 0, 1 1, 0 1, 0 0),(0.1 0.2, 0.1 0.9, 0.7 0.9, 0.1 0.2)))", + ) fid += 1 - self.check_geom(multi_surface, fid, 'MultiSurface (Polygon ((0 0, 1 0, 1 1, 0 0)),CurvePolygon (CompoundCurve (CircularString (100 100, 105.5 99.5, 101 100, 101.5 100.5, 101 101),(101 101, 100 100))))') + self.check_geom( + multi_surface, + fid, + "MultiSurface (Polygon ((0 0, 1 0, 1 1, 0 0)),CurvePolygon (CompoundCurve (CircularString (100 100, 105.5 99.5, 101 100, 101.5 100.5, 101 101),(101 101, 100 100))))", + ) fid += 1 - self.check_geom(multi_surface, fid, 'MultiSurface (CurvePolygon (CompoundCurve (CircularString (100 100, 101 100, 101 101),(101 101, 100 100))),Polygon ((0 0, 1 0, 1 1, 0 0)))') + self.check_geom( + multi_surface, + fid, + "MultiSurface (CurvePolygon (CompoundCurve (CircularString (100 100, 101 100, 101 101),(101 101, 100 100))),Polygon ((0 0, 1 0, 1 1, 0 0)))", + ) fid += 1 - self.check_geom(multi_surface, fid, 'MultiSurface(Polygon((100 100, 101 100, 101 101, 100 100)), CurvePolygon((0 0, 30 0, 30 20, 0 30, 0 0), CircularString (1 3, 3 5, 4 7, 7 3, 1 3)))') + self.check_geom( + multi_surface, + fid, + "MultiSurface(Polygon((100 100, 101 100, 101 101, 100 100)), CurvePolygon((0 0, 30 0, 30 20, 0 30, 0 0), CircularString (1 3, 3 5, 4 7, 7 3, 1 3)))", + ) fid += 1 multi_surface_z = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=5698 type=MultiSurfaceZ table="QGIS"."EDIT_SURFACEZ_DATA" (GEOM) sql=', - 'multi_surface_z', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=5698 type=MultiSurfaceZ table="QGIS"."EDIT_SURFACEZ_DATA" (GEOM) sql=', + "multi_surface_z", + "oracle", + ) self.assertTrue(multi_surface_z.isValid()) # ora-54530 : 3D compound lines are invalid since 11.2.0.3 : https://support.oracle.com/knowledge/Oracle%20Database%20Products/1446335_1.html - self.check_geom(multi_surface_z, fid, 'MultiSurfaceZ (CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 4, 1 3 1)),CurvePolygonZ (CircularStringZ (11 3 1, 17 3 2, 14 7 3, 13 5 4, 11 3 1)))', check_valid=False) + self.check_geom( + multi_surface_z, + fid, + "MultiSurfaceZ (CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 4, 1 3 1)),CurvePolygonZ (CircularStringZ (11 3 1, 17 3 2, 14 7 3, 13 5 4, 11 3 1)))", + check_valid=False, + ) fid += 1 - self.check_geom(multi_surface_z, fid, 'MultiSurfaceZ (CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 4, 1 3 1)))', check_valid=False) + self.check_geom( + multi_surface_z, + fid, + "MultiSurfaceZ (CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 4, 1 3 1)))", + check_valid=False, + ) fid += 1 - self.check_geom(multi_surface_z, fid, 'MultiSurfaceZ (CurvePolygonZ(CompoundCurveZ (CircularStringZ (-1 -5 1, 5 -7 2, 17 -6 3), (17 -6 3, -1 -5 1))), CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 4, 1 3 1)))', check_valid=False) + self.check_geom( + multi_surface_z, + fid, + "MultiSurfaceZ (CurvePolygonZ(CompoundCurveZ (CircularStringZ (-1 -5 1, 5 -7 2, 17 -6 3), (17 -6 3, -1 -5 1))), CurvePolygonZ (CircularStringZ (1 3 1, 7 3 2, 4 7 3, 3 5 4, 1 3 1)))", + check_valid=False, + ) fid += 1 def testFeatureCount(self): - self.execSQLCommand('CREATE OR REPLACE VIEW QGIS.VIEW_POLY_DATA AS SELECT * FROM QGIS.POLY_DATA') - self.execSQLCommand("BEGIN DBMS_STATS.GATHER_TABLE_STATS('QGIS', 'SOME_DATA'); END;") - - view_layer = QgsVectorLayer(self.dbconn + ' sslmode=disable table="QGIS"."VIEW_POLY_DATA" key=\'pk\'', - 'test', 'oracle') + self.execSQLCommand( + "CREATE OR REPLACE VIEW QGIS.VIEW_POLY_DATA AS SELECT * FROM QGIS.POLY_DATA" + ) + self.execSQLCommand( + "BEGIN DBMS_STATS.GATHER_TABLE_STATS('QGIS', 'SOME_DATA'); END;" + ) + + view_layer = QgsVectorLayer( + self.dbconn + ' sslmode=disable table="QGIS"."VIEW_POLY_DATA" key=\'pk\'', + "test", + "oracle", + ) self.assertTrue(view_layer.isValid()) self.assertGreater(view_layer.featureCount(), 0) self.assertTrue(view_layer.setSubsetString('"pk" = 5')) self.assertGreaterEqual(view_layer.featureCount(), 0) - view_layer_estimated = QgsVectorLayer(self.dbconn + ' sslmode=disable estimatedmetadata=true table="QGIS"."VIEW_POLY_DATA" key=\'pk\'', - 'test', 'oracle') + view_layer_estimated = QgsVectorLayer( + self.dbconn + + ' sslmode=disable estimatedmetadata=true table="QGIS"."VIEW_POLY_DATA" key=\'pk\'', + "test", + "oracle", + ) self.assertTrue(view_layer_estimated.isValid()) self.assertGreater(view_layer_estimated.featureCount(), 0) self.assertTrue(view_layer_estimated.setSubsetString('"pk" = 5')) @@ -787,16 +1354,20 @@ def testFeatureCount(self): self.assertGreater(self.vl.featureCount(), 0) self.assertTrue(self.vl.setSubsetString('"pk" = 3')) self.assertGreaterEqual(self.vl.featureCount(), 1) - self.assertTrue(self.vl.setSubsetString('')) - - vl_estimated = QgsVectorLayer(self.dbconn + ' sslmode=disable estimatedmetadata=true table="QGIS"."SOME_DATA"', - 'test', 'oracle') + self.assertTrue(self.vl.setSubsetString("")) + + vl_estimated = QgsVectorLayer( + self.dbconn + + ' sslmode=disable estimatedmetadata=true table="QGIS"."SOME_DATA"', + "test", + "oracle", + ) self.assertTrue(vl_estimated.isValid()) self.assertGreater(vl_estimated.featureCount(), 0) self.assertTrue(vl_estimated.setSubsetString('"pk" = 3')) self.assertGreaterEqual(vl_estimated.featureCount(), 1) - self.execSQLCommand('DROP VIEW QGIS.VIEW_POLY_DATA') + self.execSQLCommand("DROP VIEW QGIS.VIEW_POLY_DATA") def testNestedInsert(self): tg = QgsTransactionGroup() @@ -804,7 +1375,7 @@ def testNestedInsert(self): self.vl.startEditing() it = self.vl.getFeatures() f = next(it) - f['pk'] = NULL + f["pk"] = NULL self.vl.addFeature(f) # Should not deadlock during an active iteration f = next(it) self.vl.rollBack() @@ -833,7 +1404,11 @@ def testTimeout(self): def testTransactionDirtyName(self): # create a vector layer based on oracle vl = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="QGIS"."SOME_POLY_DATA" (GEOM) sql=', 'test', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="QGIS"."SOME_POLY_DATA" (GEOM) sql=', + "test", + "oracle", + ) self.assertTrue(vl.isValid()) # prepare a project with transactions enabled @@ -857,7 +1432,11 @@ def testTransactionDirtyName(self): def testTransactionDirty(self): # create a vector layer based on oracle vl = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="QGIS"."SOME_POLY_DATA" (GEOM) sql=', 'test', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="QGIS"."SOME_POLY_DATA" (GEOM) sql=', + "test", + "oracle", + ) self.assertTrue(vl.isValid()) # prepare a project with transactions enabled @@ -867,7 +1446,7 @@ def testTransactionDirty(self): vl.startEditing() # check that the feature used for testing is ok - ft0 = vl.getFeatures('pk=1') + ft0 = vl.getFeatures("pk=1") f = QgsFeature() self.assertTrue(ft0.nextFeature(f)) @@ -877,10 +1456,10 @@ def testTransactionDirty(self): self.assertTrue(tr.executeSql(sql, True)[0]) # check that the pk of the feature has been changed - ft = vl.getFeatures('pk=1') + ft = vl.getFeatures("pk=1") self.assertFalse(ft.nextFeature(f)) - ft = vl.getFeatures('pk=33') + ft = vl.getFeatures("pk=33") self.assertTrue(ft.nextFeature(f)) # underlying data has been modified but the layer is not tagged as @@ -891,14 +1470,14 @@ def testTransactionDirty(self): vl.undoStack().undo() # check that the original feature with pk is back - ft0 = vl.getFeatures('pk=1') + ft0 = vl.getFeatures("pk=1") self.assertTrue(ft0.nextFeature(f)) # redo vl.undoStack().redo() # check that the pk of the feature has been changed - ft1 = vl.getFeatures('pk=1') + ft1 = vl.getFeatures("pk=1") self.assertFalse(ft1.nextFeature(f)) # rollback @@ -907,8 +1486,11 @@ def testTransactionDirty(self): def testTransactionTuple(self): # create a vector layer based on oracle vl = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="QGIS"."SOME_POLY_DATA" (GEOM) sql=', - 'test', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="QGIS"."SOME_POLY_DATA" (GEOM) sql=', + "test", + "oracle", + ) self.assertTrue(vl.isValid()) # prepare a project with transactions enabled @@ -928,8 +1510,11 @@ def testTransactionTuple(self): def testIdentityCommit(self): # create a vector layer based on oracle vl = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="QGIS"."POINT_DATA_IDENTITY" (GEOM) sql=', - 'test', 'oracle') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="QGIS"."POINT_DATA_IDENTITY" (GEOM) sql=', + "test", + "oracle", + ) self.assertTrue(vl.isValid()) features = [f for f in vl.getFeatures()] @@ -948,15 +1533,28 @@ def testGetFeatureFidInvalid(self): Get feature with an invalid fid https://github.com/qgis/QGIS/issues/31626 """ - self.execSQLCommand('DROP TABLE "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY"', ignore_errors=True) - self.execSQLCommand("""CREATE TABLE "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY" (CODE NUMBER PRIMARY KEY, DESCRIPTION VARCHAR2(25))""") - self.execSQLCommand("""INSERT INTO "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY" VALUES(1000,'Desc for 1st record')""") - self.execSQLCommand("""INSERT INTO "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY" VALUES(2000,'Desc for 2nd record')""") - self.execSQLCommand("""CREATE OR REPLACE VIEW "QGIS"."VIEW_QGIS_ISSUE_FLOAT_KEY" AS SELECT * FROM "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY" """) + self.execSQLCommand( + 'DROP TABLE "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY"', ignore_errors=True + ) + self.execSQLCommand( + """CREATE TABLE "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY" (CODE NUMBER PRIMARY KEY, DESCRIPTION VARCHAR2(25))""" + ) + self.execSQLCommand( + """INSERT INTO "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY" VALUES(1000,'Desc for 1st record')""" + ) + self.execSQLCommand( + """INSERT INTO "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY" VALUES(2000,'Desc for 2nd record')""" + ) + self.execSQLCommand( + """CREATE OR REPLACE VIEW "QGIS"."VIEW_QGIS_ISSUE_FLOAT_KEY" AS SELECT * FROM "QGIS"."TABLE_QGIS_ISSUE_FLOAT_KEY" """ + ) vl = QgsVectorLayer( - self.dbconn + ' sslmode=disable key=\'CODE\' table="QGIS"."VIEW_QGIS_ISSUE_FLOAT_KEY" sql=', - 'test', 'oracle') + self.dbconn + + ' sslmode=disable key=\'CODE\' table="QGIS"."VIEW_QGIS_ISSUE_FLOAT_KEY" sql=', + "test", + "oracle", + ) # feature are not loaded yet, mapping between CODE and fid is not built so feature # is invalid @@ -976,28 +1574,44 @@ def testDeterminePKOnView(self): """ self.execSQLCommand('DROP TABLE "QGIS"."TABLE_TESTPKS"', ignore_errors=True) - self.execSQLCommand("""CREATE TABLE "QGIS"."TABLE_TESTPKS" (pk1 INTEGER, DESCRIPTION VARCHAR2(25), pk2 NUMBER, CONSTRAINT cons_pk PRIMARY KEY(pk1, pk2))""") - self.execSQLCommand("""INSERT INTO "QGIS"."TABLE_TESTPKS" VALUES(1000,'Desc for 1st record', 1)""") - self.execSQLCommand("""INSERT INTO "QGIS"."TABLE_TESTPKS" VALUES(2000,'Desc for 2nd record', 2)""") - self.execSQLCommand("""CREATE OR REPLACE VIEW "QGIS"."VIEW_TESTPKS" AS SELECT * FROM "QGIS"."TABLE_TESTPKS" """) + self.execSQLCommand( + """CREATE TABLE "QGIS"."TABLE_TESTPKS" (pk1 INTEGER, DESCRIPTION VARCHAR2(25), pk2 NUMBER, CONSTRAINT cons_pk PRIMARY KEY(pk1, pk2))""" + ) + self.execSQLCommand( + """INSERT INTO "QGIS"."TABLE_TESTPKS" VALUES(1000,'Desc for 1st record', 1)""" + ) + self.execSQLCommand( + """INSERT INTO "QGIS"."TABLE_TESTPKS" VALUES(2000,'Desc for 2nd record', 2)""" + ) + self.execSQLCommand( + """CREATE OR REPLACE VIEW "QGIS"."VIEW_TESTPKS" AS SELECT * FROM "QGIS"."TABLE_TESTPKS" """ + ) vl = QgsVectorLayer( self.dbconn + ' sslmode=disable table="QGIS"."TABLE_TESTPKS" sql=', - 'test', 'oracle') + "test", + "oracle", + ) self.assertEqual(vl.dataProvider().pkAttributeIndexes(), [0, 2]) vl = QgsVectorLayer( self.dbconn + ' sslmode=disable table="QGIS"."VIEW_TESTPKS" sql=', - 'test', 'oracle') + "test", + "oracle", + ) self.assertEqual(vl.dataProvider().pkAttributeIndexes(), []) - self.execSQLCommand("""ALTER VIEW VIEW_TESTPKS ADD CONSTRAINT const_view_pks PRIMARY KEY (pk1,pk2) DISABLE""") + self.execSQLCommand( + """ALTER VIEW VIEW_TESTPKS ADD CONSTRAINT const_view_pks PRIMARY KEY (pk1,pk2) DISABLE""" + ) vl = QgsVectorLayer( self.dbconn + ' sslmode=disable table="QGIS"."VIEW_TESTPKS" sql=', - 'test', 'oracle') + "test", + "oracle", + ) self.assertEqual(vl.dataProvider().pkAttributeIndexes(), [0, 2]) @@ -1005,8 +1619,14 @@ def getGeneratedColumnsData(self): """ return a tuple with the generated column test layer and the expected generated value """ - return (QgsVectorLayer(self.dbconn + ' sslmode=disable table="QGIS"."GENERATED_COLUMNS"', 'test', 'oracle'), - """'test:'||TO_CHAR("pk")""") + return ( + QgsVectorLayer( + self.dbconn + ' sslmode=disable table="QGIS"."GENERATED_COLUMNS"', + "test", + "oracle", + ), + """'test:'||TO_CHAR("pk")""", + ) def testEvaluateDefaultValues(self): """ @@ -1015,11 +1635,15 @@ def testEvaluateDefaultValues(self): """ self.execSQLCommand('DROP TABLE "QGIS"."TEST_EVAL_EXPR"', ignore_errors=True) - self.execSQLCommand("""CREATE TABLE "QGIS"."TEST_EVAL_EXPR" (pk INTEGER, "name" VARCHAR2(100) DEFAULT 'qgis')""") + self.execSQLCommand( + """CREATE TABLE "QGIS"."TEST_EVAL_EXPR" (pk INTEGER, "name" VARCHAR2(100) DEFAULT 'qgis')""" + ) vl = QgsVectorLayer( self.dbconn + ' sslmode=disable table="QGIS"."TEST_EVAL_EXPR" sql=', - 'test', 'oracle') + "test", + "oracle", + ) self.assertTrue(vl.isValid()) @@ -1028,35 +1652,49 @@ def testEvaluateDefaultValues(self): feat1.setAttributes([1, "'qgis'"]) feat2 = QgsFeature(vl.fields()) - feat2.setAttributes([2, 'test']) + feat2.setAttributes([2, "test"]) self.assertTrue(vl.dataProvider().addFeatures([feat1, feat2])) attributes = [feat.attributes() for feat in vl.getFeatures()] - self.assertEqual(attributes, [[1, 'qgis'], [2, 'test']]) + self.assertEqual(attributes, [[1, "qgis"], [2, "test"]]) - vl.dataProvider().setProviderProperty(QgsDataProvider.ProviderProperty.EvaluateDefaultValues, True) + vl.dataProvider().setProviderProperty( + QgsDataProvider.ProviderProperty.EvaluateDefaultValues, True + ) # feature with already evaluated default value feat1 = QgsFeature(vl.fields()) - feat1.setAttributes([3, 'qgis']) + feat1.setAttributes([3, "qgis"]) feat2 = QgsFeature(vl.fields()) - feat2.setAttributes([4, 'test']) + feat2.setAttributes([4, "test"]) self.assertTrue(vl.dataProvider().addFeatures([feat1, feat2])) attributes = [feat.attributes() for feat in vl.getFeatures()] - self.assertEqual(attributes, [[1, 'qgis'], [2, 'test'], [3, 'qgis'], [4, 'test']]) + self.assertEqual( + attributes, [[1, "qgis"], [2, "test"], [3, "qgis"], [4, "test"]] + ) def testCreateEmptyLayer(self): # cleanup (it seems overwrite option doesn't clean the sdo_geom_metadata table) self.execSQLCommand('DROP TABLE "QGIS"."EMPTY_LAYER"', ignore_errors=True) - self.execSQLCommand("DELETE FROM user_sdo_geom_metadata where TABLE_NAME='EMPTY_LAYER'", ignore_errors=True) - - uri = self.dbconn + "srid=4326 type=POINT table=\"EMPTY_LAYER\" (GEOM)" - exporter = QgsVectorLayerExporter(uri=uri, provider='oracle', fields=QgsFields(), geometryType=QgsWkbTypes.Type.Point, crs=QgsCoordinateReferenceSystem('EPSG:4326'), overwrite=True) + self.execSQLCommand( + "DELETE FROM user_sdo_geom_metadata where TABLE_NAME='EMPTY_LAYER'", + ignore_errors=True, + ) + + uri = self.dbconn + 'srid=4326 type=POINT table="EMPTY_LAYER" (GEOM)' + exporter = QgsVectorLayerExporter( + uri=uri, + provider="oracle", + fields=QgsFields(), + geometryType=QgsWkbTypes.Type.Point, + crs=QgsCoordinateReferenceSystem("EPSG:4326"), + overwrite=True, + ) self.assertEqual(exporter.errorCount(), 0) self.assertEqual(exporter.errorCode(), 0) @@ -1065,7 +1703,11 @@ def testCreateEmptyLayer(self): # check that metadata table has been correctly populated query = QSqlQuery(self.conn) - self.assertTrue(query.exec("SELECT column_name, srid FROM user_sdo_geom_metadata WHERE table_name = 'EMPTY_LAYER'")) + self.assertTrue( + query.exec( + "SELECT column_name, srid FROM user_sdo_geom_metadata WHERE table_name = 'EMPTY_LAYER'" + ) + ) self.assertTrue(query.next()) self.assertEqual(query.value(0), "GEOM") # Cannot work with proj version < 7 because it cannot identify properly EPSG:4326 @@ -1077,21 +1719,32 @@ def testCreateEmptyLayer(self): # no feature, so we cannot guess the geometry type, so the layer is not valid # but srid is set for provider in case you want to add a feature even if the layer is invalid! # layer sourceCrs is empty because the layer is not considered spatial (not know geometry type) - vl = QgsVectorLayer(self.dbconn + ' sslmode=disable table="QGIS"."EMPTY_LAYER" (GEOM) sql=', 'test', 'oracle') + vl = QgsVectorLayer( + self.dbconn + ' sslmode=disable table="QGIS"."EMPTY_LAYER" (GEOM) sql=', + "test", + "oracle", + ) self.assertFalse(vl.isValid()) self.assertEqual(vl.dataProvider().sourceCrs().authid(), "EPSG:4326") # so we set the geometry type - vl = QgsVectorLayer(self.dbconn + ' sslmode=disable type=POINT table="QGIS"."EMPTY_LAYER" (GEOM) sql=', 'test', 'oracle') + vl = QgsVectorLayer( + self.dbconn + + ' sslmode=disable type=POINT table="QGIS"."EMPTY_LAYER" (GEOM) sql=', + "test", + "oracle", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.sourceCrs().authid(), "EPSG:4326") f = QgsFeature(vl.fields()) - f.setGeometry(QgsGeometry.fromWkt('POINT (43.5 1.42)')) + f.setGeometry(QgsGeometry.fromWkt("POINT (43.5 1.42)")) vl.dataProvider().addFeatures([f]) query = QSqlQuery(self.conn) - self.assertTrue(query.exec('SELECT "l"."GEOM"."SDO_SRID" from "QGIS"."EMPTY_LAYER" "l"')) + self.assertTrue( + query.exec('SELECT "l"."GEOM"."SDO_SRID" from "QGIS"."EMPTY_LAYER" "l"') + ) self.assertTrue(query.next()) # Cannot work with proj version < 7 because it cannot identify properly EPSG:4326 # TODO remove this when PROJ will be >= 7 @@ -1100,7 +1753,11 @@ def testCreateEmptyLayer(self): query.finish() # now we can autodetect geom type and srid - vl = QgsVectorLayer(self.dbconn + ' sslmode=disable table="QGIS"."EMPTY_LAYER" (GEOM) sql=', 'test', 'oracle') + vl = QgsVectorLayer( + self.dbconn + ' sslmode=disable table="QGIS"."EMPTY_LAYER" (GEOM) sql=', + "test", + "oracle", + ) self.assertTrue(vl.isValid()) # Cannot work with proj version < 7 because it cannot identify properly EPSG:4326 # TODO remove this when PROJ will be >= 7 @@ -1118,13 +1775,24 @@ def testCreateAspatialLayer(self): fields = QgsFields() fields.append(QgsField("INTEGER_T", QVariant.Int)) - uri = self.dbconn + "table=\"ASPATIAL_LAYER\"" - exporter = QgsVectorLayerExporter(uri=uri, provider='oracle', fields=fields, geometryType=QgsWkbTypes.Type.NoGeometry, crs=QgsCoordinateReferenceSystem(), overwrite=True) + uri = self.dbconn + 'table="ASPATIAL_LAYER"' + exporter = QgsVectorLayerExporter( + uri=uri, + provider="oracle", + fields=fields, + geometryType=QgsWkbTypes.Type.NoGeometry, + crs=QgsCoordinateReferenceSystem(), + overwrite=True, + ) self.assertEqual(exporter.errorCount(), 0) self.assertEqual(exporter.errorCode(), 0) self.execSQLCommand('SELECT count(*) FROM "QGIS"."ASPATIAL_LAYER"') - vl = QgsVectorLayer(self.dbconn + ' sslmode=disable table="QGIS"."ASPATIAL_LAYER" sql=', 'test', 'oracle') + vl = QgsVectorLayer( + self.dbconn + ' sslmode=disable table="QGIS"."ASPATIAL_LAYER" sql=', + "test", + "oracle", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.fields().names(), ["INTEGER_T"]) @@ -1139,9 +1807,18 @@ def testCreateInvalidLayer(self): fields = QgsFields() - uri = self.dbconn + "table=\"INVALID_LAYER\"" - exporter = QgsVectorLayerExporter(uri=uri, provider='oracle', fields=fields, geometryType=QgsWkbTypes.Type.NoGeometry, crs=QgsCoordinateReferenceSystem(), overwrite=True) - self.assertEqual(exporter.errorCode(), QgsVectorLayerExporter.ExportError.ErrCreateDataSource) + uri = self.dbconn + 'table="INVALID_LAYER"' + exporter = QgsVectorLayerExporter( + uri=uri, + provider="oracle", + fields=fields, + geometryType=QgsWkbTypes.Type.NoGeometry, + crs=QgsCoordinateReferenceSystem(), + overwrite=True, + ) + self.assertEqual( + exporter.errorCode(), QgsVectorLayerExporter.ExportError.ErrCreateDataSource + ) def testAddEmptyFeature(self): """ @@ -1157,34 +1834,52 @@ def countFeature(table_name): query.finish() return count - self.execSQLCommand('DROP TABLE "QGIS"."EMPTYFEATURE_LAYER"', ignore_errors=True) - self.execSQLCommand('CREATE TABLE "QGIS"."EMPTYFEATURE_LAYER" ( "num" INTEGER, GEOM SDO_GEOMETRY)') + self.execSQLCommand( + 'DROP TABLE "QGIS"."EMPTYFEATURE_LAYER"', ignore_errors=True + ) + self.execSQLCommand( + 'CREATE TABLE "QGIS"."EMPTYFEATURE_LAYER" ( "num" INTEGER, GEOM SDO_GEOMETRY)' + ) - vl = QgsVectorLayer(self.dbconn + ' sslmode=disable type=Point table="QGIS"."EMPTYFEATURE_LAYER" (GEOM) sql=', 'test', 'oracle') + vl = QgsVectorLayer( + self.dbconn + + ' sslmode=disable type=Point table="QGIS"."EMPTYFEATURE_LAYER" (GEOM) sql=', + "test", + "oracle", + ) self.assertTrue(vl.isValid()) # add feature with no attributes, no geometry feature = QgsFeature(vl.fields()) self.assertTrue(vl.dataProvider().addFeatures([feature])[0]) - self.assertEqual(countFeature('EMPTYFEATURE_LAYER'), 1) + self.assertEqual(countFeature("EMPTYFEATURE_LAYER"), 1) # add feature with no attribute and one geometry feature = QgsFeature(vl.fields()) - feature.setGeometry(QgsGeometry.fromWkt('Point (43.5 1.42)')) + feature.setGeometry(QgsGeometry.fromWkt("Point (43.5 1.42)")) self.assertTrue(vl.dataProvider().addFeatures([feature])[0]) - self.assertEqual(countFeature('EMPTYFEATURE_LAYER'), 2) + self.assertEqual(countFeature("EMPTYFEATURE_LAYER"), 2) - self.execSQLCommand('DROP TABLE "QGIS"."EMPTYFEATURE_NOGEOM_LAYER"', ignore_errors=True) - self.execSQLCommand('CREATE TABLE "QGIS"."EMPTYFEATURE_NOGEOM_LAYER" ( "num" INTEGER)') + self.execSQLCommand( + 'DROP TABLE "QGIS"."EMPTYFEATURE_NOGEOM_LAYER"', ignore_errors=True + ) + self.execSQLCommand( + 'CREATE TABLE "QGIS"."EMPTYFEATURE_NOGEOM_LAYER" ( "num" INTEGER)' + ) # same tests but with no geometry in table definition - vl = QgsVectorLayer(self.dbconn + ' sslmode=disable table="QGIS"."EMPTYFEATURE_NOGEOM_LAYER" sql=', 'test', 'oracle') + vl = QgsVectorLayer( + self.dbconn + + ' sslmode=disable table="QGIS"."EMPTYFEATURE_NOGEOM_LAYER" sql=', + "test", + "oracle", + ) self.assertTrue(vl.isValid()) # add feature with no attributes feature = QgsFeature(vl.fields()) self.assertTrue(vl.dataProvider().addFeatures([feature])[0]) - self.assertEqual(countFeature('EMPTYFEATURE_NOGEOM_LAYER'), 1) + self.assertEqual(countFeature("EMPTYFEATURE_NOGEOM_LAYER"), 1) def testCreateLayerLongFieldNames(self): """ @@ -1199,13 +1894,24 @@ def testCreateLayerLongFieldNames(self): fields = QgsFields() fields.append(QgsField(long_name, QVariant.Int)) - uri = self.dbconn + "table=\"LONGFIELD_LAYER\"" - exporter = QgsVectorLayerExporter(uri=uri, provider='oracle', fields=fields, geometryType=QgsWkbTypes.Type.Point, crs=QgsCoordinateReferenceSystem("EPSG:4326"), overwrite=True) + uri = self.dbconn + 'table="LONGFIELD_LAYER"' + exporter = QgsVectorLayerExporter( + uri=uri, + provider="oracle", + fields=fields, + geometryType=QgsWkbTypes.Type.Point, + crs=QgsCoordinateReferenceSystem("EPSG:4326"), + overwrite=True, + ) self.assertEqual(exporter.errorCount(), 0) self.assertEqual(exporter.errorCode(), 0) self.execSQLCommand('SELECT count(*) FROM "QGIS"."LONGFIELD_LAYER"') - vl = QgsVectorLayer(self.dbconn + ' sslmode=disable table="QGIS"."LONGFIELD_LAYER" sql=', 'test', 'oracle') + vl = QgsVectorLayer( + self.dbconn + ' sslmode=disable table="QGIS"."LONGFIELD_LAYER" sql=', + "test", + "oracle", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.fields().names(), [long_name]) @@ -1221,30 +1927,57 @@ def testCreateGeomLowercase(self): fields = QgsFields() fields.append(QgsField("test", QVariant.Int)) - uri = self.dbconn + "table=\"lowercase_layer\" (GEOM)" - exporter = QgsVectorLayerExporter(uri=uri, provider='oracle', fields=fields, geometryType=QgsWkbTypes.Type.Point, crs=QgsCoordinateReferenceSystem("EPSG:4326"), overwrite=True) + uri = self.dbconn + 'table="lowercase_layer" (GEOM)' + exporter = QgsVectorLayerExporter( + uri=uri, + provider="oracle", + fields=fields, + geometryType=QgsWkbTypes.Type.Point, + crs=QgsCoordinateReferenceSystem("EPSG:4326"), + overwrite=True, + ) self.assertEqual(exporter.errorCode(), 2) # geom column is lower case -> fails - self.execSQLCommand('DROP TABLE "QGIS"."LOWERCASEGEOM_LAYER"', ignore_errors=True) + self.execSQLCommand( + 'DROP TABLE "QGIS"."LOWERCASEGEOM_LAYER"', ignore_errors=True + ) fields = QgsFields() fields.append(QgsField("test", QVariant.Int)) - uri = self.dbconn + "table=\"LOWERCASEGEOM\" (geom)" - exporter = QgsVectorLayerExporter(uri=uri, provider='oracle', fields=fields, geometryType=QgsWkbTypes.Type.Point, crs=QgsCoordinateReferenceSystem("EPSG:4326"), overwrite=True) + uri = self.dbconn + 'table="LOWERCASEGEOM" (geom)' + exporter = QgsVectorLayerExporter( + uri=uri, + provider="oracle", + fields=fields, + geometryType=QgsWkbTypes.Type.Point, + crs=QgsCoordinateReferenceSystem("EPSG:4326"), + overwrite=True, + ) self.assertEqual(exporter.errorCode(), 2) # table and geom column are uppercase -> success - self.execSQLCommand('DROP TABLE "QGIS"."UPPERCASEGEOM_LAYER"', ignore_errors=True) - self.execSQLCommand("""DELETE FROM user_sdo_geom_metadata where TABLE_NAME = 'UPPERCASEGEOM_LAYER'""") + self.execSQLCommand( + 'DROP TABLE "QGIS"."UPPERCASEGEOM_LAYER"', ignore_errors=True + ) + self.execSQLCommand( + """DELETE FROM user_sdo_geom_metadata where TABLE_NAME = 'UPPERCASEGEOM_LAYER'""" + ) fields = QgsFields() fields.append(QgsField("test", QVariant.Int)) - uri = self.dbconn + "table=\"UPPERCASEGEOM_LAYER\" (GEOM)" + uri = self.dbconn + 'table="UPPERCASEGEOM_LAYER" (GEOM)' - exporter = QgsVectorLayerExporter(uri=uri, provider='oracle', fields=fields, geometryType=QgsWkbTypes.Type.Point, crs=QgsCoordinateReferenceSystem("EPSG:4326"), overwrite=True) + exporter = QgsVectorLayerExporter( + uri=uri, + provider="oracle", + fields=fields, + geometryType=QgsWkbTypes.Type.Point, + crs=QgsCoordinateReferenceSystem("EPSG:4326"), + overwrite=True, + ) print(exporter.errorMessage()) self.assertEqual(exporter.errorCount(), 0) self.assertEqual(exporter.errorCode(), 0) @@ -1255,37 +1988,122 @@ def testDetectedGeomType(self): """ testdata = [ - ("POINT", 2, "SDO_GEOMETRY( 2001,5698,SDO_POINT_TYPE(1, 2, NULL), NULL, NULL)", QgsWkbTypes.Type.Point), - ("POINTZ", 3, "SDO_GEOMETRY( 3001,5698,SDO_POINT_TYPE(1, 2, 3), NULL, NULL)", QgsWkbTypes.Type.PointZ), + ( + "POINT", + 2, + "SDO_GEOMETRY( 2001,5698,SDO_POINT_TYPE(1, 2, NULL), NULL, NULL)", + QgsWkbTypes.Type.Point, + ), + ( + "POINTZ", + 3, + "SDO_GEOMETRY( 3001,5698,SDO_POINT_TYPE(1, 2, 3), NULL, NULL)", + QgsWkbTypes.Type.PointZ, + ), # there is difference between line and curve so everything is a compoundcurve to cover both # https://docs.oracle.com/database/121/SPATL/sdo_geometry-object-type.htm - ("LINE", 2, "SDO_GEOMETRY( 2002,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(1,2,3,4,5,6))", QgsWkbTypes.Type.CompoundCurve), - ("LINEZ", 3, "SDO_GEOMETRY(3002,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(1,2,3,4,5,6,7,8,9))", QgsWkbTypes.Type.CompoundCurveZ), - ("CURVE", 2, "SDO_GEOMETRY(2002,5698,NULL, SDO_ELEM_INFO_ARRAY(1, 2, 2), SDO_ORDINATE_ARRAY(1, 2, 5, 4, 7, 2.2, 10, .1, 13, 4))", QgsWkbTypes.Type.CompoundCurve), - ("CURVEZ", 3, "SDO_GEOMETRY(3002,5698,NULL, SDO_ELEM_INFO_ARRAY(1, 2, 2), SDO_ORDINATE_ARRAY(1, 2, 1, 5, 4, 2, 7, 2.2, 3, 10, 0.1, 4, 13, 4, 5))", QgsWkbTypes.Type.CompoundCurveZ), - ("POLYGON", 2, "SDO_GEOMETRY(2003,5698,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1), SDO_ORDINATE_ARRAY(1, 2, 11, 2, 11, 22, 1, 22, 1, 2))", QgsWkbTypes.Type.Polygon), - ("POLYGONZ", 3, "SDO_GEOMETRY(3003,5698,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1), SDO_ORDINATE_ARRAY(1, 2, 3, 11, 2, 13, 11, 22, 15, 1, 22, 7, 1, 2, 3))", QgsWkbTypes.Type.PolygonZ), - - ("MULTIPOINT", 2, "SDO_GEOMETRY( 2005,5698,NULL, sdo_elem_info_array (1,1,1, 3,1,1), sdo_ordinate_array (1,2, 3,4))", QgsWkbTypes.Type.MultiPoint), - ("MULTIPOINTZ", 3, "SDO_GEOMETRY( 3005,5698,NULL, sdo_elem_info_array (1,1,2), sdo_ordinate_array (1,2,3, 4,5,6))", QgsWkbTypes.Type.MultiPointZ), + ( + "LINE", + 2, + "SDO_GEOMETRY( 2002,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(1,2,3,4,5,6))", + QgsWkbTypes.Type.CompoundCurve, + ), + ( + "LINEZ", + 3, + "SDO_GEOMETRY(3002,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(1,2,3,4,5,6,7,8,9))", + QgsWkbTypes.Type.CompoundCurveZ, + ), + ( + "CURVE", + 2, + "SDO_GEOMETRY(2002,5698,NULL, SDO_ELEM_INFO_ARRAY(1, 2, 2), SDO_ORDINATE_ARRAY(1, 2, 5, 4, 7, 2.2, 10, .1, 13, 4))", + QgsWkbTypes.Type.CompoundCurve, + ), + ( + "CURVEZ", + 3, + "SDO_GEOMETRY(3002,5698,NULL, SDO_ELEM_INFO_ARRAY(1, 2, 2), SDO_ORDINATE_ARRAY(1, 2, 1, 5, 4, 2, 7, 2.2, 3, 10, 0.1, 4, 13, 4, 5))", + QgsWkbTypes.Type.CompoundCurveZ, + ), + ( + "POLYGON", + 2, + "SDO_GEOMETRY(2003,5698,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1), SDO_ORDINATE_ARRAY(1, 2, 11, 2, 11, 22, 1, 22, 1, 2))", + QgsWkbTypes.Type.Polygon, + ), + ( + "POLYGONZ", + 3, + "SDO_GEOMETRY(3003,5698,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1), SDO_ORDINATE_ARRAY(1, 2, 3, 11, 2, 13, 11, 22, 15, 1, 22, 7, 1, 2, 3))", + QgsWkbTypes.Type.PolygonZ, + ), + ( + "MULTIPOINT", + 2, + "SDO_GEOMETRY( 2005,5698,NULL, sdo_elem_info_array (1,1,1, 3,1,1), sdo_ordinate_array (1,2, 3,4))", + QgsWkbTypes.Type.MultiPoint, + ), + ( + "MULTIPOINTZ", + 3, + "SDO_GEOMETRY( 3005,5698,NULL, sdo_elem_info_array (1,1,2), sdo_ordinate_array (1,2,3, 4,5,6))", + QgsWkbTypes.Type.MultiPointZ, + ), # there is difference between line and curve so everything is a compoundcurve to cover both # https://docs.oracle.com/database/121/SPATL/sdo_geometry-object-type.htm - ("MULTILINE", 2, "SDO_GEOMETRY(2006,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,1, 5,2,1), SDO_ORDINATE_ARRAY(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))", QgsWkbTypes.Type.MultiCurve), - ("MULTILINEZ", 3, "SDO_GEOMETRY(3006,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,1, 7,2,1), SDO_ORDINATE_ARRAY(1, 2, 11, 3, 4, -11, 5, 6, 9, 7, 8, 1, 9, 10, -3))", QgsWkbTypes.Type.MultiCurveZ), - ("MULTICURVE", 2, "SDO_GEOMETRY(2006,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,2, 11,2,2), SDO_ORDINATE_ARRAY(1, 2, 5, 4, 7, 2.2, 10, .1, 13, 4, -11, -3, 5, 7, 10, -1))", QgsWkbTypes.Type.MultiCurve), - ("MULTICURVEZ", 3, "SDO_GEOMETRY(3006,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,2, 16,2,2), SDO_ORDINATE_ARRAY(1, 2, 1, 5, 4, 2, 7, 2.2, 3, 10, .1, 4, 13, 4, 5, -11, -3, 6, 5, 7, 8, 10, -1, 9))", QgsWkbTypes.Type.MultiCurveZ), - ("MULTIPOLYGON", 2, "SDO_GEOMETRY(2007,5698,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1, 11,1003,1, 21,2003,1, 29,2003,1), SDO_ORDINATE_ARRAY(1, 2, 11, 2, 11, 22, 1, 22, 1, 2, 1, 2, 11, 2, 11, 22, 1, 22, 1, 2, 5, 6, 8, 9, 8, 6, 5, 6, 3, 4, 5, 6, 3, 6, 3, 4))", QgsWkbTypes.Type.MultiPolygon), - ("MULTIPOLYGONZ", 3, "SDO_GEOMETRY(3007,5698,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1, 16,1003,1, 31,2003,1), SDO_ORDINATE_ARRAY(1, 2, 3, 11, 2, 13, 11, 22, 15, 1, 22, 7, 1, 2, 3, 1, 2, 3, 11, 2, 13, 11, 22, 15, 1, 22, 7, 1, 2, 3, 5, 6, 1, 8, 9, -1, 8, 6, 2, 5, 6, 1))", QgsWkbTypes.Type.MultiPolygonZ) + ( + "MULTILINE", + 2, + "SDO_GEOMETRY(2006,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,1, 5,2,1), SDO_ORDINATE_ARRAY(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))", + QgsWkbTypes.Type.MultiCurve, + ), + ( + "MULTILINEZ", + 3, + "SDO_GEOMETRY(3006,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,1, 7,2,1), SDO_ORDINATE_ARRAY(1, 2, 11, 3, 4, -11, 5, 6, 9, 7, 8, 1, 9, 10, -3))", + QgsWkbTypes.Type.MultiCurveZ, + ), + ( + "MULTICURVE", + 2, + "SDO_GEOMETRY(2006,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,2, 11,2,2), SDO_ORDINATE_ARRAY(1, 2, 5, 4, 7, 2.2, 10, .1, 13, 4, -11, -3, 5, 7, 10, -1))", + QgsWkbTypes.Type.MultiCurve, + ), + ( + "MULTICURVEZ", + 3, + "SDO_GEOMETRY(3006,5698,NULL, SDO_ELEM_INFO_ARRAY(1,2,2, 16,2,2), SDO_ORDINATE_ARRAY(1, 2, 1, 5, 4, 2, 7, 2.2, 3, 10, .1, 4, 13, 4, 5, -11, -3, 6, 5, 7, 8, 10, -1, 9))", + QgsWkbTypes.Type.MultiCurveZ, + ), + ( + "MULTIPOLYGON", + 2, + "SDO_GEOMETRY(2007,5698,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1, 11,1003,1, 21,2003,1, 29,2003,1), SDO_ORDINATE_ARRAY(1, 2, 11, 2, 11, 22, 1, 22, 1, 2, 1, 2, 11, 2, 11, 22, 1, 22, 1, 2, 5, 6, 8, 9, 8, 6, 5, 6, 3, 4, 5, 6, 3, 6, 3, 4))", + QgsWkbTypes.Type.MultiPolygon, + ), + ( + "MULTIPOLYGONZ", + 3, + "SDO_GEOMETRY(3007,5698,NULL, SDO_ELEM_INFO_ARRAY(1,1003,1, 16,1003,1, 31,2003,1), SDO_ORDINATE_ARRAY(1, 2, 3, 11, 2, 13, 11, 22, 15, 1, 22, 7, 1, 2, 3, 1, 2, 3, 11, 2, 13, 11, 22, 15, 1, 22, 7, 1, 2, 3, 5, 6, 1, 8, 9, -1, 8, 6, 2, 5, 6, 1))", + QgsWkbTypes.Type.MultiPolygonZ, + ), ] for name, dim, geom, wkb_type in testdata: # We choose SRID=5698 (see https://docs.oracle.com/database/121/SPATL/three-dimensional-coordinate-reference-system-support.htm#SPATL626) # to get Oracle valid geometries because it support 3D and arcs (arcs are not supported in geodetic projection) - self.createTable(f'DETECT_{name}', dim, 5698) - self.execSQLCommand(f'INSERT INTO "QGIS"."DETECT_{name}" ("pk", GEOM) SELECT 1, {geom} from dual') + self.createTable(f"DETECT_{name}", dim, 5698) + self.execSQLCommand( + f'INSERT INTO "QGIS"."DETECT_{name}" ("pk", GEOM) SELECT 1, {geom} from dual' + ) layer = QgsVectorLayer( - self.dbconn + f' sslmode=disable key=\'pk\' srid=3857 table="QGIS"."DETECT_{name}" (GEOM) sql=', f'test{name}', 'oracle') + self.dbconn + + f' sslmode=disable key=\'pk\' srid=3857 table="QGIS"."DETECT_{name}" (GEOM) sql=', + f"test{name}", + "oracle", + ) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), wkb_type) @@ -1332,20 +2150,28 @@ def request(self, realm, username, pwd, msg): self.assertEqual(credentials, QgsCredentials.instance()) # no user/pwd -> credential is called - transaction = QgsProviderRegistry.instance().createTransaction("oracle", conn_wo_login_pwd) + transaction = QgsProviderRegistry.instance().createTransaction( + "oracle", conn_wo_login_pwd + ) self.assertEqual(transaction.begin()[0], True) self.assertEqual(credentials.nbCall, 1) # no user/pwd second times -> use cache - transaction = QgsProviderRegistry.instance().createTransaction("oracle", conn_wo_login_pwd) + transaction = QgsProviderRegistry.instance().createTransaction( + "oracle", conn_wo_login_pwd + ) self.assertEqual(transaction.begin()[0], True) self.assertEqual(credentials.nbCall, 1) # same connection, different user, don't use cache (credentials.nbCall is incremented) - transaction = QgsProviderRegistry.instance().createTransaction("oracle", conn_wo_login_pwd + " user='titi'") - self.assertEqual(transaction.begin()[0], True) # test credentials always return valid credentials so it's valid, but we don't care + transaction = QgsProviderRegistry.instance().createTransaction( + "oracle", conn_wo_login_pwd + " user='titi'" + ) + self.assertEqual( + transaction.begin()[0], True + ) # test credentials always return valid credentials so it's valid, but we don't care self.assertEqual(credentials.nbCall, 2) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_provider_postgres.py b/tests/src/python/test_provider_postgres.py index 0d396417a3c4..fbd4e98279eb 100644 --- a/tests/src/python/test_provider_postgres.py +++ b/tests/src/python/test_provider_postgres.py @@ -14,9 +14,9 @@ """ -__author__ = 'Matthias Kuhn' -__date__ = '2015-04-23' -__copyright__ = 'Copyright 2015, The QGIS Project' +__author__ = "Matthias Kuhn" +__date__ = "2015-04-23" +__copyright__ = "Copyright 2015, The QGIS Project" import os import time @@ -66,7 +66,7 @@ QgsVectorLayerExporter, QgsVectorLayerUtils, QgsWkbTypes, - QgsSettingsTree + QgsSettingsTree, ) from qgis.gui import QgsAttributeForm, QgsGui import unittest @@ -84,24 +84,36 @@ class TestPyQgsPostgresProvider(QgisTestCase, ProviderTestCase): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsPostgresProvider, cls).setUpClass() - cls.dbconn = 'service=qgis_test' - if 'QGIS_PGTEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_PGTEST_DB'] + super().setUpClass() + cls.dbconn = "service=qgis_test" + if "QGIS_PGTEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_PGTEST_DB"] # Create test layers cls.vl = QgsVectorLayer( - cls.dbconn + - ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=', - 'test', 'postgres') - assert cls.vl.isValid(), "Could not create a layer from the 'qgis_test.someData' table using dbconn '" + cls.dbconn + "'" + cls.dbconn + + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=', + "test", + "postgres", + ) + assert cls.vl.isValid(), ( + "Could not create a layer from the 'qgis_test.someData' table using dbconn '" + + cls.dbconn + + "'" + ) cls.source = cls.vl.dataProvider() cls.poly_vl = QgsVectorLayer( - cls.dbconn + - ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=', - 'test', 'postgres') - assert cls.poly_vl.isValid(), "Could not create a layer from the 'qgis_test.some_poly_data' table using dbconn '" + cls.dbconn + "'" + cls.dbconn + + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=', + "test", + "postgres", + ) + assert cls.poly_vl.isValid(), ( + "Could not create a layer from the 'qgis_test.some_poly_data' table using dbconn '" + + cls.dbconn + + "'" + ) cls.poly_provider = cls.poly_vl.dataProvider() QgsGui.editorWidgetRegistry().initEditors() @@ -117,14 +129,23 @@ def execSQLCommand(self, sql): def assertAcceptableEstimatedExtent(self, realExt, estmExt, msg): # 1. test that the estimated extent contains the real one - self.assertTrue(estmExt.contains(realExt), - "Estimated extent {} does not contain real extent {}" - .format(estmExt, realExt)) + self.assertTrue( + estmExt.contains(realExt), + "Estimated extent {} does not contain real extent {}".format( + estmExt, realExt + ), + ) # 2. test that the estimated extent is not larger than 10% of real extent - self.assertLess(estmExt.width() - realExt.width(), realExt.width() / 10, - 'extent width estimated {}, real {} ({})'.format(estmExt.width(), realExt.width(), msg)) - self.assertLess(estmExt.height() - realExt.height(), realExt.height() / 10, - 'extent height estimated {}, real {} ({})'.format(estmExt.height(), realExt.height(), msg)) + self.assertLess( + estmExt.width() - realExt.width(), + realExt.width() / 10, + f"extent width estimated {estmExt.width()}, real {realExt.width()} ({msg})", + ) + self.assertLess( + estmExt.height() - realExt.height(), + realExt.height() / 10, + f"extent height estimated {estmExt.height()}, real {realExt.height()} ({msg})", + ) # Create instances of this class for scoped backups, # example: @@ -134,55 +155,71 @@ def assertAcceptableEstimatedExtent(self, realExt, estmExt, msg): # def scopedTableBackup(self, schema, table): - class ScopedBackup(): + class ScopedBackup: def __init__(self, tester, schema, table): self.schema = schema self.table = table self.tester = tester - tester.execSQLCommand(f'DROP TABLE IF EXISTS {schema}.{table}_edit CASCADE') - tester.execSQLCommand('CREATE TABLE {s}.{t}_edit AS SELECT * FROM {s}.{t}'.format(s=schema, t=table)) + tester.execSQLCommand( + f"DROP TABLE IF EXISTS {schema}.{table}_edit CASCADE" + ) + tester.execSQLCommand( + "CREATE TABLE {s}.{t}_edit AS SELECT * FROM {s}.{t}".format( + s=schema, t=table + ) + ) def __del__(self): - self.tester.execSQLCommand(f'TRUNCATE TABLE {self.schema}.{self.table}') - self.tester.execSQLCommand('INSERT INTO {s}.{t} SELECT * FROM {s}.{t}_edit'.format(s=self.schema, t=self.table)) - self.tester.execSQLCommand(f'DROP TABLE {self.schema}.{self.table}_edit') + self.tester.execSQLCommand(f"TRUNCATE TABLE {self.schema}.{self.table}") + self.tester.execSQLCommand( + "INSERT INTO {s}.{t} SELECT * FROM {s}.{t}_edit".format( + s=self.schema, t=self.table + ) + ) + self.tester.execSQLCommand( + f"DROP TABLE {self.schema}.{self.table}_edit" + ) return ScopedBackup(self, schema, table) def temporarySchema(self, name): - class TemporarySchema(): + class TemporarySchema: def __init__(self, tester, name): self.tester = tester - self.name = name + '_tmp' + self.name = name + "_tmp" def __enter__(self): - self.tester.execSQLCommand(f'DROP SCHEMA IF EXISTS {self.name} CASCADE') - self.tester.execSQLCommand(f'CREATE SCHEMA {self.name}') + self.tester.execSQLCommand(f"DROP SCHEMA IF EXISTS {self.name} CASCADE") + self.tester.execSQLCommand(f"CREATE SCHEMA {self.name}") return self.name def __exit__(self, type, value, traceback): - self.tester.execSQLCommand(f'DROP SCHEMA {self.name} CASCADE') + self.tester.execSQLCommand(f"DROP SCHEMA {self.name} CASCADE") - return TemporarySchema(self, 'qgis_test_' + name) + return TemporarySchema(self, "qgis_test_" + name) def getSource(self): # create temporary table for edit tests + self.execSQLCommand('DROP TABLE IF EXISTS qgis_test."editData" CASCADE') self.execSQLCommand( - 'DROP TABLE IF EXISTS qgis_test."editData" CASCADE') + 'CREATE TABLE qgis_test."editData" ( pk SERIAL NOT NULL PRIMARY KEY, cnt integer, name text, name2 text, num_char text, dt timestamp without time zone, "date" date, "time" time without time zone, geom public.geometry(Point, 4326))' + ) self.execSQLCommand( - 'CREATE TABLE qgis_test."editData" ( pk SERIAL NOT NULL PRIMARY KEY, cnt integer, name text, name2 text, num_char text, dt timestamp without time zone, "date" date, "time" time without time zone, geom public.geometry(Point, 4326))') - self.execSQLCommand("INSERT INTO qgis_test.\"editData\" (pk, cnt, name, name2, num_char, dt, \"date\", \"time\", geom) VALUES " - "(5, -200, NULL, 'NuLl', '5', TIMESTAMP '2020-05-04 12:13:14', '2020-05-02', '12:13:01', '0101000020E61000001D5A643BDFC751C01F85EB51B88E5340')," - "(3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL, NULL)," - "(1, 100, 'Orange', 'oranGe', '1', TIMESTAMP '2020-05-03 12:13:14', '2020-05-03', '12:13:14', '0101000020E61000006891ED7C3F9551C085EB51B81E955040')," - "(2, 200, 'Apple', 'Apple', '2', TIMESTAMP '2020-05-04 12:14:14', '2020-05-04', '12:14:14', '0101000020E6100000CDCCCCCCCC0C51C03333333333B35140')," - "(4, 400, 'Honey', 'Honey', '4', TIMESTAMP '2021-05-04 13:13:14', '2021-05-04', '13:13:14', '0101000020E610000014AE47E17A5450C03333333333935340')") + 'INSERT INTO qgis_test."editData" (pk, cnt, name, name2, num_char, dt, "date", "time", geom) VALUES ' + "(5, -200, NULL, 'NuLl', '5', TIMESTAMP '2020-05-04 12:13:14', '2020-05-02', '12:13:01', '0101000020E61000001D5A643BDFC751C01F85EB51B88E5340')," + "(3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL, NULL)," + "(1, 100, 'Orange', 'oranGe', '1', TIMESTAMP '2020-05-03 12:13:14', '2020-05-03', '12:13:14', '0101000020E61000006891ED7C3F9551C085EB51B81E955040')," + "(2, 200, 'Apple', 'Apple', '2', TIMESTAMP '2020-05-04 12:14:14', '2020-05-04', '12:14:14', '0101000020E6100000CDCCCCCCCC0C51C03333333333B35140')," + "(4, 400, 'Honey', 'Honey', '4', TIMESTAMP '2021-05-04 13:13:14', '2021-05-04', '13:13:14', '0101000020E610000014AE47E17A5450C03333333333935340')" + ) self.execSQLCommand("SELECT setval('qgis_test.\"editData_pk_seq\"', 5, true)") vl = QgsVectorLayer( - self.dbconn + - ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."editData" (geom) sql=', - 'test', 'postgres') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."editData" (geom) sql=', + "test", + "postgres", + ) return vl def getEditableLayer(self): @@ -191,19 +228,26 @@ def getEditableLayer(self): def getEditableLayerWithCheckConstraint(self): """Returns the layer for attribute change CHECK constraint violation""" - return QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'id\' srid=4326 type=POINT table="public"."test_check_constraint" (geom) sql=', 'test_check_constraint', 'postgres') + return QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'id\' srid=4326 type=POINT table="public"."test_check_constraint" (geom) sql=', + "test_check_constraint", + "postgres", + ) def enableCompiler(self): - QgsSettings().setValue('/qgis/compileExpressions', True) + QgsSettings().setValue("/qgis/compileExpressions", True) return True def disableCompiler(self): - QgsSettings().setValue('/qgis/compileExpressions', False) + QgsSettings().setValue("/qgis/compileExpressions", False) def uncompiledFilters(self): - return {'"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')', - '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')', - '"time" = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')'} + return { + "\"dt\" = to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy')", + "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')", + "\"time\" = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')", + } def partiallyCompiledFilters(self): return set() @@ -220,252 +264,285 @@ def getGeneratedColumnsData(self): if pgversion < 120000: return (None, None) else: - return (QgsVectorLayer(self.dbconn + ' sslmode=disable table="qgis_test"."generated_columns"', 'test', 'postgres'), - """('test:'::text || ((pk)::character varying)::text)""") + return ( + QgsVectorLayer( + self.dbconn + + ' sslmode=disable table="qgis_test"."generated_columns"', + "test", + "postgres", + ), + """('test:'::text || ((pk)::character varying)::text)""", + ) # HERE GO THE PROVIDER SPECIFIC TESTS def testDefaultValue(self): self.source.setProviderProperty( - QgsDataProvider.ProviderProperty.EvaluateDefaultValues, True) + QgsDataProvider.ProviderProperty.EvaluateDefaultValues, True + ) self.assertIsInstance(self.source.defaultValue(0), int) self.assertEqual(self.source.defaultValue(1), NULL) - self.assertEqual(self.source.defaultValue(2), 'qgis') + self.assertEqual(self.source.defaultValue(2), "qgis") self.source.setProviderProperty( - QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False) + QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False + ) def testDefaultValueClause(self): self.source.setProviderProperty( - QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False) - self.assertEqual(self.source.defaultValueClause( - 0), 'nextval(\'qgis_test."someData_pk_seq"\'::regclass)') + QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False + ) + self.assertEqual( + self.source.defaultValueClause(0), + "nextval('qgis_test.\"someData_pk_seq\"'::regclass)", + ) self.assertFalse(self.source.defaultValueClause(1)) - self.assertEqual(self.source.defaultValueClause(2), '\'qgis\'::text') + self.assertEqual(self.source.defaultValueClause(2), "'qgis'::text") def testDateTimeTypes(self): - vl = QgsVectorLayer('%s table="qgis_test"."date_times" sql=' % ( - self.dbconn), "testdatetimes", "postgres") + vl = QgsVectorLayer( + '%s table="qgis_test"."date_times" sql=' % (self.dbconn), + "testdatetimes", + "postgres", + ) self.assertTrue(vl.isValid()) fields = vl.dataProvider().fields() - self.assertEqual(fields.at(fields.indexFromName( - 'date_field')).type(), QVariant.Date) - self.assertEqual(fields.at(fields.indexFromName( - 'time_field')).type(), QVariant.Time) - self.assertEqual(fields.at(fields.indexFromName( - 'datetime_field')).type(), QVariant.DateTime) + self.assertEqual( + fields.at(fields.indexFromName("date_field")).type(), QVariant.Date + ) + self.assertEqual( + fields.at(fields.indexFromName("time_field")).type(), QVariant.Time + ) + self.assertEqual( + fields.at(fields.indexFromName("datetime_field")).type(), QVariant.DateTime + ) f = next(vl.getFeatures(QgsFeatureRequest())) - date_idx = vl.fields().lookupField('date_field') + date_idx = vl.fields().lookupField("date_field") self.assertIsInstance(f.attributes()[date_idx], QDate) self.assertEqual(f.attributes()[date_idx], QDate(2004, 3, 4)) - time_idx = vl.fields().lookupField('time_field') + time_idx = vl.fields().lookupField("time_field") self.assertIsInstance(f.attributes()[time_idx], QTime) self.assertEqual(f.attributes()[time_idx], QTime(13, 41, 52)) - datetime_idx = vl.fields().lookupField('datetime_field') + datetime_idx = vl.fields().lookupField("datetime_field") self.assertIsInstance(f.attributes()[datetime_idx], QDateTime) - self.assertEqual(f.attributes()[datetime_idx], QDateTime( - QDate(2004, 3, 4), QTime(13, 41, 52))) + self.assertEqual( + f.attributes()[datetime_idx], + QDateTime(QDate(2004, 3, 4), QTime(13, 41, 52)), + ) def testBooleanType(self): - vl = QgsVectorLayer('{} table="qgis_test"."boolean_table" sql='.format( - self.dbconn), "testbool", "postgres") + vl = QgsVectorLayer( + f'{self.dbconn} table="qgis_test"."boolean_table" sql=', + "testbool", + "postgres", + ) self.assertTrue(vl.isValid()) fields = vl.dataProvider().fields() - self.assertEqual( - fields.at(fields.indexFromName('fld1')).type(), QVariant.Bool) + self.assertEqual(fields.at(fields.indexFromName("fld1")).type(), QVariant.Bool) - values = {feat['id']: feat['fld1'] for feat in vl.getFeatures()} - expected = { - 1: True, - 2: False, - 3: NULL - } + values = {feat["id"]: feat["fld1"] for feat in vl.getFeatures()} + expected = {1: True, 2: False, 3: NULL} self.assertEqual(values, expected) def testByteaType(self): - vl = QgsVectorLayer('{} table="qgis_test"."byte_a_table" sql='.format( - self.dbconn), "testbytea", "postgres") + vl = QgsVectorLayer( + f'{self.dbconn} table="qgis_test"."byte_a_table" sql=', + "testbytea", + "postgres", + ) self.assertTrue(vl.isValid()) fields = vl.dataProvider().fields() - self.assertEqual(fields.at(fields.indexFromName( - 'fld1')).type(), QVariant.ByteArray) + self.assertEqual( + fields.at(fields.indexFromName("fld1")).type(), QVariant.ByteArray + ) - values = {feat['id']: feat['fld1'] for feat in vl.getFeatures()} - expected = { - 1: QByteArray(b'YmludmFsdWU='), - 2: QByteArray() - } + values = {feat["id"]: feat["fld1"] for feat in vl.getFeatures()} + expected = {1: QByteArray(b"YmludmFsdWU="), 2: QByteArray()} self.assertEqual(values, expected) # editing binary values self.execSQLCommand( - 'DROP TABLE IF EXISTS qgis_test."byte_a_table_edit" CASCADE') + 'DROP TABLE IF EXISTS qgis_test."byte_a_table_edit" CASCADE' + ) + self.execSQLCommand( + 'CREATE TABLE qgis_test."byte_a_table_edit" ( pk SERIAL NOT NULL PRIMARY KEY, blobby bytea)' + ) self.execSQLCommand( - 'CREATE TABLE qgis_test."byte_a_table_edit" ( pk SERIAL NOT NULL PRIMARY KEY, blobby bytea)') - self.execSQLCommand("INSERT INTO qgis_test.\"byte_a_table_edit\" (pk, blobby) VALUES " - "(1, encode('bbb', 'base64')::bytea)") + 'INSERT INTO qgis_test."byte_a_table_edit" (pk, blobby) VALUES ' + "(1, encode('bbb', 'base64')::bytea)" + ) vl = QgsVectorLayer( self.dbconn + ' sslmode=disable table="qgis_test"."byte_a_table_edit" sql=', - 'test', 'postgres') + "test", + "postgres", + ) self.assertTrue(vl.isValid()) - values = {feat['pk']: feat['blobby'] for feat in vl.getFeatures()} - expected = { - 1: QByteArray(b'YmJi') - } + values = {feat["pk"]: feat["blobby"] for feat in vl.getFeatures()} + expected = {1: QByteArray(b"YmJi")} self.assertEqual(values, expected) # change attribute value - self.assertTrue(vl.dataProvider().changeAttributeValues( - {1: {1: QByteArray(b'bbbvx')}})) - values = {feat['pk']: feat['blobby'] for feat in vl.getFeatures()} - expected = { - 1: QByteArray(b'bbbvx') - } + self.assertTrue( + vl.dataProvider().changeAttributeValues({1: {1: QByteArray(b"bbbvx")}}) + ) + values = {feat["pk"]: feat["blobby"] for feat in vl.getFeatures()} + expected = {1: QByteArray(b"bbbvx")} self.assertEqual(values, expected) # add feature f = QgsFeature() - f.setAttributes([2, QByteArray(b'cccc')]) + f.setAttributes([2, QByteArray(b"cccc")]) self.assertTrue(vl.dataProvider().addFeature(f)) - values = {feat['pk']: feat['blobby'] for feat in vl.getFeatures()} - expected = { - 1: QByteArray(b'bbbvx'), - 2: QByteArray(b'cccc') - } + values = {feat["pk"]: feat["blobby"] for feat in vl.getFeatures()} + expected = {1: QByteArray(b"bbbvx"), 2: QByteArray(b"cccc")} self.assertEqual(values, expected) # change feature - self.assertTrue(vl.dataProvider().changeFeatures( - {2: {1: QByteArray(b'dddd')}}, {})) - values = {feat['pk']: feat['blobby'] for feat in vl.getFeatures()} - expected = { - 1: QByteArray(b'bbbvx'), - 2: QByteArray(b'dddd') - } + self.assertTrue( + vl.dataProvider().changeFeatures({2: {1: QByteArray(b"dddd")}}, {}) + ) + values = {feat["pk"]: feat["blobby"] for feat in vl.getFeatures()} + expected = {1: QByteArray(b"bbbvx"), 2: QByteArray(b"dddd")} self.assertEqual(values, expected) def testCitextType(self): - vl = QgsVectorLayer('{} table="qgis_test"."citext_table" sql='.format( - self.dbconn), "testbytea", "postgres") + vl = QgsVectorLayer( + f'{self.dbconn} table="qgis_test"."citext_table" sql=', + "testbytea", + "postgres", + ) self.assertTrue(vl.isValid()) fields = vl.dataProvider().fields() self.assertEqual( - fields.at(fields.indexFromName('fld1')).type(), QVariant.String) + fields.at(fields.indexFromName("fld1")).type(), QVariant.String + ) - values = {feat['id']: feat['fld1'] for feat in vl.getFeatures()} - expected = { - 1: 'test val', - 2: NULL - } + values = {feat["id"]: feat["fld1"] for feat in vl.getFeatures()} + expected = {1: "test val", 2: NULL} self.assertEqual(values, expected) # editing citext values self.execSQLCommand( - 'DROP TABLE IF EXISTS qgis_test."citext_table_edit" CASCADE') + 'DROP TABLE IF EXISTS qgis_test."citext_table_edit" CASCADE' + ) + self.execSQLCommand( + 'CREATE TABLE qgis_test."citext_table_edit" ( pk SERIAL NOT NULL PRIMARY KEY, txt citext)' + ) self.execSQLCommand( - 'CREATE TABLE qgis_test."citext_table_edit" ( pk SERIAL NOT NULL PRIMARY KEY, txt citext)') - self.execSQLCommand("INSERT INTO qgis_test.\"citext_table_edit\" (pk, txt) VALUES " - "(1, 'text')") + 'INSERT INTO qgis_test."citext_table_edit" (pk, txt) VALUES ' "(1, 'text')" + ) vl = QgsVectorLayer( self.dbconn + ' sslmode=disable table="qgis_test"."citext_table_edit" sql=', - 'test', 'postgres') + "test", + "postgres", + ) self.assertTrue(vl.isValid()) - values = {feat['pk']: feat['txt'] for feat in vl.getFeatures()} - expected = { - 1: 'text' - } + values = {feat["pk"]: feat["txt"] for feat in vl.getFeatures()} + expected = {1: "text"} self.assertEqual(values, expected) # change attribute value - self.assertTrue( - vl.dataProvider().changeAttributeValues({1: {1: 'teeeext'}})) - values = {feat['pk']: feat['txt'] for feat in vl.getFeatures()} - expected = { - 1: 'teeeext' - } + self.assertTrue(vl.dataProvider().changeAttributeValues({1: {1: "teeeext"}})) + values = {feat["pk"]: feat["txt"] for feat in vl.getFeatures()} + expected = {1: "teeeext"} self.assertEqual(values, expected) # add feature f = QgsFeature() - f.setAttributes([2, 'teeeeeeeeeext']) + f.setAttributes([2, "teeeeeeeeeext"]) self.assertTrue(vl.dataProvider().addFeature(f)) - values = {feat['pk']: feat['txt'] for feat in vl.getFeatures()} - expected = { - 1: 'teeeext', - 2: 'teeeeeeeeeext' - } + values = {feat["pk"]: feat["txt"] for feat in vl.getFeatures()} + expected = {1: "teeeext", 2: "teeeeeeeeeext"} self.assertEqual(values, expected) # change feature - self.assertTrue(vl.dataProvider().changeFeatures( - {2: {1: 'teeeeeeeeeeeeeeeeeeeeeeext'}}, {})) - values = {feat['pk']: feat['txt'] for feat in vl.getFeatures()} - expected = { - 1: 'teeeext', - 2: 'teeeeeeeeeeeeeeeeeeeeeeext' - } + self.assertTrue( + vl.dataProvider().changeFeatures({2: {1: "teeeeeeeeeeeeeeeeeeeeeeext"}}, {}) + ) + values = {feat["pk"]: feat["txt"] for feat in vl.getFeatures()} + expected = {1: "teeeext", 2: "teeeeeeeeeeeeeeeeeeeeeeext"} self.assertEqual(values, expected) def testQueryLayers(self): def test_query(dbconn, query, key): ql = QgsVectorLayer( - '{} srid=4326 table="{}" (geom) key=\'{}\' sql='.format( - dbconn, query.replace('"', '\\"'), key), "testgeom", - "postgres") - self.assertTrue(ql.isValid(), f'{query} ({key})') - - test_query(self.dbconn, - '(SELECT NULL::integer "Id1", NULL::integer "Id2", NULL::geometry(Point, 4326) geom LIMIT 0)', - '"Id1","Id2"') + "{} srid=4326 table=\"{}\" (geom) key='{}' sql=".format( + dbconn, query.replace('"', '\\"'), key + ), + "testgeom", + "postgres", + ) + self.assertTrue(ql.isValid(), f"{query} ({key})") + + test_query( + self.dbconn, + '(SELECT NULL::integer "Id1", NULL::integer "Id2", NULL::geometry(Point, 4326) geom LIMIT 0)', + '"Id1","Id2"', + ) def testWkbTypes(self): def test_table(dbconn, table_name, wkt): - vl = QgsVectorLayer(f'{dbconn} srid=4326 table="qgis_test".{table_name} (geom) sql=', "testgeom", - "postgres") + vl = QgsVectorLayer( + f'{dbconn} srid=4326 table="qgis_test".{table_name} (geom) sql=', + "testgeom", + "postgres", + ) self.assertTrue(vl.isValid()) for f in vl.getFeatures(): self.assertEqual(f.geometry().asWkt(), wkt) - test_table(self.dbconn, 'p2d', 'Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))') - test_table(self.dbconn, 'p3d', - 'Polygon Z ((0 0 0, 1 0 0, 1 1 0, 0 1 0, 0 0 0))') - test_table(self.dbconn, 'triangle2d', 'Triangle ((0 0, 1 0, 1 1, 0 0))') - test_table(self.dbconn, 'triangle3d', - 'Triangle Z ((0 0 0, 1 0 0, 1 1 0, 0 0 0))') - test_table(self.dbconn, 'tin2d', - 'TIN (((0 0, 1 0, 1 1, 0 0)),((0 0, 0 1, 1 1, 0 0)))') - test_table(self.dbconn, 'tin3d', - 'TIN Z (((0 0 0, 1 0 0, 1 1 0, 0 0 0)),((0 0 0, 0 1 0, 1 1 0, 0 0 0)))') - test_table(self.dbconn, 'ps2d', - 'PolyhedralSurface (((0 0, 1 0, 1 1, 0 1, 0 0)))') - test_table(self.dbconn, 'ps3d', - 'PolyhedralSurface Z (((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)),((0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)),((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)),((0 1 0, 0 1 1, 1 1 1, 1 1 0, 0 1 0)),((1 1 0, 1 1 1, 1 0 1, 1 0 0, 1 1 0)),((1 0 0, 1 0 1, 0 0 1, 0 0 0, 1 0 0)))') - test_table(self.dbconn, 'mp3d', - 'MultiPolygon Z (((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)),((0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)),((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)),((0 1 0, 0 1 1, 1 1 1, 1 1 0, 0 1 0)),((1 1 0, 1 1 1, 1 0 1, 1 0 0, 1 1 0)),((1 0 0, 1 0 1, 0 0 1, 0 0 0, 1 0 0)))') - test_table(self.dbconn, 'pt2d', 'Point (0 0)') - test_table(self.dbconn, 'pt3d', 'Point Z (0 0 0)') - test_table(self.dbconn, 'ls2d', 'LineString (0 0, 1 1)') - test_table(self.dbconn, 'ls3d', 'LineString Z (0 0 0, 1 1 1)') - test_table(self.dbconn, 'mpt2d', 'MultiPoint ((0 0),(1 1))') - test_table(self.dbconn, 'mpt3d', 'MultiPoint Z ((0 0 0),(1 1 1))') - test_table(self.dbconn, 'mls2d', - 'MultiLineString ((0 0, 1 1),(2 2, 3 3))') - test_table(self.dbconn, 'mls3d', - 'MultiLineString Z ((0 0 0, 1 1 1),(2 2 2, 3 3 3))') - - test_table(self.dbconn, 'pt4d', 'Point ZM (1 2 3 4)') + test_table(self.dbconn, "p2d", "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))") + test_table( + self.dbconn, "p3d", "Polygon Z ((0 0 0, 1 0 0, 1 1 0, 0 1 0, 0 0 0))" + ) + test_table(self.dbconn, "triangle2d", "Triangle ((0 0, 1 0, 1 1, 0 0))") + test_table( + self.dbconn, "triangle3d", "Triangle Z ((0 0 0, 1 0 0, 1 1 0, 0 0 0))" + ) + test_table( + self.dbconn, "tin2d", "TIN (((0 0, 1 0, 1 1, 0 0)),((0 0, 0 1, 1 1, 0 0)))" + ) + test_table( + self.dbconn, + "tin3d", + "TIN Z (((0 0 0, 1 0 0, 1 1 0, 0 0 0)),((0 0 0, 0 1 0, 1 1 0, 0 0 0)))", + ) + test_table( + self.dbconn, "ps2d", "PolyhedralSurface (((0 0, 1 0, 1 1, 0 1, 0 0)))" + ) + test_table( + self.dbconn, + "ps3d", + "PolyhedralSurface Z (((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)),((0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)),((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)),((0 1 0, 0 1 1, 1 1 1, 1 1 0, 0 1 0)),((1 1 0, 1 1 1, 1 0 1, 1 0 0, 1 1 0)),((1 0 0, 1 0 1, 0 0 1, 0 0 0, 1 0 0)))", + ) + test_table( + self.dbconn, + "mp3d", + "MultiPolygon Z (((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)),((0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)),((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)),((0 1 0, 0 1 1, 1 1 1, 1 1 0, 0 1 0)),((1 1 0, 1 1 1, 1 0 1, 1 0 0, 1 1 0)),((1 0 0, 1 0 1, 0 0 1, 0 0 0, 1 0 0)))", + ) + test_table(self.dbconn, "pt2d", "Point (0 0)") + test_table(self.dbconn, "pt3d", "Point Z (0 0 0)") + test_table(self.dbconn, "ls2d", "LineString (0 0, 1 1)") + test_table(self.dbconn, "ls3d", "LineString Z (0 0 0, 1 1 1)") + test_table(self.dbconn, "mpt2d", "MultiPoint ((0 0),(1 1))") + test_table(self.dbconn, "mpt3d", "MultiPoint Z ((0 0 0),(1 1 1))") + test_table(self.dbconn, "mls2d", "MultiLineString ((0 0, 1 1),(2 2, 3 3))") + test_table( + self.dbconn, "mls3d", "MultiLineString Z ((0 0 0, 1 1 1),(2 2 2, 3 3 3))" + ) + + test_table(self.dbconn, "pt4d", "Point ZM (1 2 3 4)") def testMetadata(self): - """ Test that metadata is correctly acquired from provider """ + """Test that metadata is correctly acquired from provider""" metadata = self.vl.metadata() - self.assertEqual( - metadata.crs(), QgsCoordinateReferenceSystem.fromEpsgId(4326)) - self.assertEqual(metadata.type(), 'dataset') - self.assertEqual(metadata.abstract(), 'QGIS Test Table') + self.assertEqual(metadata.crs(), QgsCoordinateReferenceSystem.fromEpsgId(4326)) + self.assertEqual(metadata.type(), "dataset") + self.assertEqual(metadata.abstract(), "QGIS Test Table") def testGetFeaturesUniqueId(self): """ @@ -479,33 +556,48 @@ def test_unique(features, num_features): featureids.append(f.id()) self.assertEqual(len(features), num_features) - vl = QgsVectorLayer(f"{self.dbconn} srid=4326 table=\"qgis_test\".someData (geom) sql=", "testgeom", - "postgres") + vl = QgsVectorLayer( + f'{self.dbconn} srid=4326 table="qgis_test".someData (geom) sql=', + "testgeom", + "postgres", + ) self.assertTrue(vl.isValid()) # Test someData test_unique([f for f in vl.getFeatures()], 5) # Test base_table_bad: layer is invalid - vl = QgsVectorLayer(f"{self.dbconn} srid=4326 table=\"qgis_test\".base_table_bad (geom) sql=", - "testgeom", "postgres") + vl = QgsVectorLayer( + f'{self.dbconn} srid=4326 table="qgis_test".base_table_bad (geom) sql=', + "testgeom", + "postgres", + ) self.assertFalse(vl.isValid()) # Test base_table_bad with use estimated metadata: layer is valid because the unique test is skipped vl = QgsVectorLayer( '{} srid=4326 estimatedmetadata="true" table="qgis_test".{} (geom) sql='.format( - self.dbconn, 'base_table_bad'), - "testgeom", "postgres") + self.dbconn, "base_table_bad" + ), + "testgeom", + "postgres", + ) self.assertTrue(vl.isValid()) # Test base_table_good: layer is valid - vl = QgsVectorLayer(f"{self.dbconn} srid=4326 table=\"qgis_test\".base_table_good (geom) sql=", - "testgeom", "postgres") + vl = QgsVectorLayer( + f'{self.dbconn} srid=4326 table="qgis_test".base_table_good (geom) sql=', + "testgeom", + "postgres", + ) self.assertTrue(vl.isValid()) test_unique([f for f in vl.getFeatures()], 4) # Test base_table_good with use estimated metadata: layer is valid vl = QgsVectorLayer( '{} srid=4326 estimatedmetadata="true" table="qgis_test".{} (geom) sql='.format( - self.dbconn, 'base_table_good'), - "testgeom", "postgres") + self.dbconn, "base_table_good" + ), + "testgeom", + "postgres", + ) self.assertTrue(vl.isValid()) test_unique([f for f in vl.getFeatures()], 4) @@ -526,7 +618,7 @@ def test_layer(ql, att, val, fidval): def test(dbconn, query, att, val, fidval): table = query.replace('"', '\\"') - uri = f'{dbconn} table="{table}" (g) key=\'{att}\'' + uri = f"{dbconn} table=\"{table}\" (g) key='{att}'" ql = QgsVectorLayer(uri, "t", "postgres") test_layer(ql, att, val, fidval) # now with estimated metadata @@ -535,58 +627,101 @@ def test(dbconn, query, att, val, fidval): # --- INT16 ---- # zero - test(self.dbconn, '(SELECT 0::int2 i, NULL::geometry(Point) g)', 'i', 0, 0) + test(self.dbconn, "(SELECT 0::int2 i, NULL::geometry(Point) g)", "i", 0, 0) # low positive - test(self.dbconn, '(SELECT 1::int2 i, NULL::geometry(Point) g)', 'i', 1, 1) + test(self.dbconn, "(SELECT 1::int2 i, NULL::geometry(Point) g)", "i", 1, 1) # low negative - test(self.dbconn, '(SELECT -1::int2 i, NULL::geometry(Point) g)', - 'i', -1, 4294967295) + test( + self.dbconn, + "(SELECT -1::int2 i, NULL::geometry(Point) g)", + "i", + -1, + 4294967295, + ) # max positive signed 16bit integer - test(self.dbconn, '(SELECT 32767::int2 i, NULL::geometry(Point) g)', - 'i', 32767, 32767) + test( + self.dbconn, + "(SELECT 32767::int2 i, NULL::geometry(Point) g)", + "i", + 32767, + 32767, + ) # max negative signed 16bit integer - test(self.dbconn, '(SELECT (-32768)::int2 i, NULL::geometry(Point) g)', - 'i', -32768, 4294934528) + test( + self.dbconn, + "(SELECT (-32768)::int2 i, NULL::geometry(Point) g)", + "i", + -32768, + 4294934528, + ) # --- INT32 ---- # zero - test(self.dbconn, '(SELECT 0::int4 i, NULL::geometry(Point) g)', 'i', 0, 0) + test(self.dbconn, "(SELECT 0::int4 i, NULL::geometry(Point) g)", "i", 0, 0) # low positive - test(self.dbconn, '(SELECT 2::int4 i, NULL::geometry(Point) g)', 'i', 2, 2) + test(self.dbconn, "(SELECT 2::int4 i, NULL::geometry(Point) g)", "i", 2, 2) # low negative - test(self.dbconn, '(SELECT -2::int4 i, NULL::geometry(Point) g)', - 'i', -2, 4294967294) + test( + self.dbconn, + "(SELECT -2::int4 i, NULL::geometry(Point) g)", + "i", + -2, + 4294967294, + ) # max positive signed 32bit integer - test(self.dbconn, '(SELECT 2147483647::int4 i, NULL::geometry(Point) g)', - 'i', 2147483647, 2147483647) + test( + self.dbconn, + "(SELECT 2147483647::int4 i, NULL::geometry(Point) g)", + "i", + 2147483647, + 2147483647, + ) # max negative signed 32bit integer - test(self.dbconn, '(SELECT (-2147483648)::int4 i, NULL::geometry(Point) g)', - 'i', -2147483648, 2147483648) + test( + self.dbconn, + "(SELECT (-2147483648)::int4 i, NULL::geometry(Point) g)", + "i", + -2147483648, + 2147483648, + ) # --- INT64 (FIDs are always 1 because assigned ex-novo) ---- # zero - test(self.dbconn, '(SELECT 0::int8 i, NULL::geometry(Point) g)', 'i', 0, 1) + test(self.dbconn, "(SELECT 0::int8 i, NULL::geometry(Point) g)", "i", 0, 1) # low positive - test(self.dbconn, '(SELECT 3::int8 i, NULL::geometry(Point) g)', 'i', 3, 1) + test(self.dbconn, "(SELECT 3::int8 i, NULL::geometry(Point) g)", "i", 3, 1) # low negative - test(self.dbconn, '(SELECT -3::int8 i, NULL::geometry(Point) g)', 'i', -3, 1) + test(self.dbconn, "(SELECT -3::int8 i, NULL::geometry(Point) g)", "i", -3, 1) # max positive signed 64bit integer - test(self.dbconn, '(SELECT 9223372036854775807::int8 i, NULL::geometry(Point) g)', - 'i', 9223372036854775807, 1) + test( + self.dbconn, + "(SELECT 9223372036854775807::int8 i, NULL::geometry(Point) g)", + "i", + 9223372036854775807, + 1, + ) # max negative signed 32bit integer - test(self.dbconn, '(SELECT (-9223372036854775808)::int8 i, NULL::geometry(Point) g)', 'i', -9223372036854775808, - 1) + test( + self.dbconn, + "(SELECT (-9223372036854775808)::int8 i, NULL::geometry(Point) g)", + "i", + -9223372036854775808, + 1, + ) def testPktIntInsert(self): - vl = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"bikes_view\" key=\"pk\" sql=", "bikes_view", - "postgres") + vl = QgsVectorLayer( + f'{self.dbconn} table="qgis_test"."bikes_view" key="pk" sql=', + "bikes_view", + "postgres", + ) self.assertTrue(vl.isValid()) f = QgsFeature(vl.fields()) - f['pk'] = NULL - f['name'] = 'Cilo' + f["pk"] = NULL + f["name"] = "Cilo" r, f = vl.dataProvider().addFeatures([f]) self.assertTrue(r) - self.assertNotEqual(f[0]['pk'], NULL, f[0].attributes()) + self.assertNotEqual(f[0]["pk"], NULL, f[0].attributes()) vl.deleteFeatures([f[0].id()]) def testGeneratedFields(self): @@ -600,184 +735,251 @@ def testGeneratedFields(self): return # Backup test table (will be edited) - self.execSQLCommand('DROP TABLE IF EXISTS qgis_test.test_gen_col_edit CASCADE') - self.execSQLCommand('CREATE TABLE qgis_test.test_gen_col_edit AS SELECT id,name,geom FROM qgis_test.test_gen_col') + self.execSQLCommand("DROP TABLE IF EXISTS qgis_test.test_gen_col_edit CASCADE") + self.execSQLCommand( + "CREATE TABLE qgis_test.test_gen_col_edit AS SELECT id,name,geom FROM qgis_test.test_gen_col" + ) # Geometry columns - vl = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"test_gen_col\" (geom) srid=4326 type=POLYGON key=\"id\" sql=", "test_gen_col", "postgres") + vl = QgsVectorLayer( + f'{self.dbconn} table="qgis_test"."test_gen_col" (geom) srid=4326 type=POLYGON key="id" sql=', + "test_gen_col", + "postgres", + ) self.assertTrue(vl.isValid()) # writing geometry... f = QgsFeature(vl.fields()) - ix_name = f.fieldNameIndex('name') + ix_name = f.fieldNameIndex("name") - f.setGeometry(QgsGeometry.fromWkt('Polygon ((-67 -2, -67 0, -68 0, -70 -1, -67 -2))')) - f.setAttribute(ix_name, 'QGIS-3') + f.setGeometry( + QgsGeometry.fromWkt("Polygon ((-67 -2, -67 0, -68 0, -70 -1, -67 -2))") + ) + f.setAttribute(ix_name, "QGIS-3") self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([f])) self.assertTrue(vl.commitChanges()) # reading back to see if we saved the centroid correctly. - vl2 = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"test_gen_col\" (cent) srid=4326 type=POINT key=\"id\" sql=", "test_gen_col", "postgres") + vl2 = QgsVectorLayer( + f'{self.dbconn} table="qgis_test"."test_gen_col" (cent) srid=4326 type=POINT key="id" sql=', + "test_gen_col", + "postgres", + ) f2 = next(vl2.getFeatures(QgsFeatureRequest())) generated_geometry = f2.geometry().asWkt() - expected_geometry = 'Point (-68.047619047619051 -0.90476190476190477)' + expected_geometry = "Point (-68.047619047619051 -0.90476190476190477)" expected_area = 43069568296.34387 - assert compareWkt(generated_geometry, expected_geometry), f"Geometry mismatch! Expected:\n{expected_geometry}\nGot:\n{generated_geometry}\n" - self.assertAlmostEqual(f2['poly_area'], expected_area, places=4) - self.assertEqual(f2['name'], 'QGIS-3') + assert compareWkt( + generated_geometry, expected_geometry + ), f"Geometry mismatch! Expected:\n{expected_geometry}\nGot:\n{generated_geometry}\n" + self.assertAlmostEqual(f2["poly_area"], expected_area, places=4) + self.assertEqual(f2["name"], "QGIS-3") # Checking if we can correctly change values of an existing feature. self.assertTrue(vl2.startEditing()) - ix2_name = f2.fieldNameIndex('name') + ix2_name = f2.fieldNameIndex("name") fid2 = f2.id() - vl2.changeAttributeValue(fid2, ix2_name, 'New') + vl2.changeAttributeValue(fid2, ix2_name, "New") self.assertTrue(vl2.commitChanges()) # getting a brand new QgsVectorLayer - vl = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"test_gen_col\" (geom) srid=4326 type=POLYGON key=\"id\" sql=", "test_gen_col", "postgres") + vl = QgsVectorLayer( + f'{self.dbconn} table="qgis_test"."test_gen_col" (geom) srid=4326 type=POLYGON key="id" sql=', + "test_gen_col", + "postgres", + ) self.assertTrue(vl.isValid()) # checking if the name field was correctly updated f = next(vl.getFeatures(QgsFeatureRequest())) - self.assertEqual(f['name'], 'New') + self.assertEqual(f["name"], "New") # Now, check if we can change the value of a GENERATED field (we shouldn't) self.assertTrue(vl.startEditing()) - ix_area = f.fieldNameIndex('poly_area') + ix_area = f.fieldNameIndex("poly_area") fid = f.id() vl.changeAttributeValue(fid, ix_area, 42) self.assertTrue(vl.commitChanges()) # reading back - vl2 = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"test_gen_col\" (geom) srid=4326 type=POLYGON key=\"id\" sql=", "test_gen_col", "postgres") + vl2 = QgsVectorLayer( + f'{self.dbconn} table="qgis_test"."test_gen_col" (geom) srid=4326 type=POLYGON key="id" sql=', + "test_gen_col", + "postgres", + ) f2 = next(vl2.getFeatures(QgsFeatureRequest())) - self.assertAlmostEqual(f2['poly_area'], expected_area, places=4) + self.assertAlmostEqual(f2["poly_area"], expected_area, places=4) # now, getting a brand new QgsVectorLayer to check if changes (UPDATE) in the geometry are reflected in the generated fields - vl = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"test_gen_col\" (geom) srid=4326 type=POLYGON key=\"id\" sql=", "test_gen_col", "postgres") + vl = QgsVectorLayer( + f'{self.dbconn} table="qgis_test"."test_gen_col" (geom) srid=4326 type=POLYGON key="id" sql=', + "test_gen_col", + "postgres", + ) self.assertTrue(vl.isValid()) f = next(vl.getFeatures(QgsFeatureRequest())) vl.startEditing() fid = f.id() - vl.changeGeometry(fid, QgsGeometry.fromWkt('Polygon ((-67 -2, -65 0, -68 0, -70 -1, -67 -2))')) + vl.changeGeometry( + fid, QgsGeometry.fromWkt("Polygon ((-67 -2, -65 0, -68 0, -70 -1, -67 -2))") + ) vl.commitChanges() # reading back... - vl2 = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"test_gen_col\" (cent) srid=4326 type=POINT key=\"id\" sql=", "test_gen_col", "postgres") + vl2 = QgsVectorLayer( + f'{self.dbconn} table="qgis_test"."test_gen_col" (cent) srid=4326 type=POINT key="id" sql=', + "test_gen_col", + "postgres", + ) f2 = next(vl2.getFeatures(QgsFeatureRequest())) generated_geometry = f2.geometry().asWkt() generated_geometry = f2.geometry().asWkt() - expected_geometry = 'Point (-67.42424242424242209 -0.81818181818181823)' + expected_geometry = "Point (-67.42424242424242209 -0.81818181818181823)" expected_area = 67718478405.28429 - assert compareWkt(generated_geometry, expected_geometry), f"Geometry mismatch! Expected:\n{expected_geometry}\nGot:\n{generated_geometry}\n" - self.assertAlmostEqual(f2['poly_area'], expected_area, places=4) - self.assertEqual(f2['name'], 'New') + assert compareWkt( + generated_geometry, expected_geometry + ), f"Geometry mismatch! Expected:\n{expected_geometry}\nGot:\n{generated_geometry}\n" + self.assertAlmostEqual(f2["poly_area"], expected_area, places=4) + self.assertEqual(f2["name"], "New") # Geography columns - vl3 = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"test_gen_geog_col\" (geog) srid=4326 type=POLYGON key=\"id\" sql=", "test_gen_geog_col", "postgres") + vl3 = QgsVectorLayer( + f'{self.dbconn} table="qgis_test"."test_gen_geog_col" (geog) srid=4326 type=POLYGON key="id" sql=', + "test_gen_geog_col", + "postgres", + ) self.assertTrue(vl3.isValid()) # writing geography... f3 = QgsFeature(vl3.fields()) - f3.setGeometry(QgsGeometry.fromWkt('Polygon ((-67 -2, -67 0, -68 0, -70 -1, -67 -2))')) + f3.setGeometry( + QgsGeometry.fromWkt("Polygon ((-67 -2, -67 0, -68 0, -70 -1, -67 -2))") + ) self.assertTrue(vl3.startEditing()) self.assertTrue(vl3.addFeatures([f3])) self.assertTrue(vl3.commitChanges()) # reading back geography and checking values - vl4 = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"test_gen_geog_col\" (cent) srid=4326 type=POINT key=\"id\" sql=", "test_gen_geog_col", "postgres") + vl4 = QgsVectorLayer( + f'{self.dbconn} table="qgis_test"."test_gen_geog_col" (cent) srid=4326 type=POINT key="id" sql=', + "test_gen_geog_col", + "postgres", + ) f4 = next(vl4.getFeatures(QgsFeatureRequest())) generated_geometry = f4.geometry().asWkt() - expected_geometry = 'Point (-68.0477406158202 -0.904960604589168)' + expected_geometry = "Point (-68.0477406158202 -0.904960604589168)" expected_area = 43088884296.69713 - assert compareWkt(generated_geometry, expected_geometry), f"Geometry mismatch! Expected:\n{expected_geometry}\nGot:\n{generated_geometry}\n" - self.assertEqual(f4['poly_area'], expected_area) + assert compareWkt( + generated_geometry, expected_geometry + ), f"Geometry mismatch! Expected:\n{expected_geometry}\nGot:\n{generated_geometry}\n" + self.assertEqual(f4["poly_area"], expected_area) # Restore test table (after editing it) - self.execSQLCommand('TRUNCATE TABLE qgis_test.test_gen_col') - self.execSQLCommand('INSERT INTO qgis_test.test_gen_col(id,name,geom) SELECT id,name,geom FROM qgis_test.test_gen_col_edit') - self.execSQLCommand('DROP TABLE qgis_test.test_gen_col_edit') + self.execSQLCommand("TRUNCATE TABLE qgis_test.test_gen_col") + self.execSQLCommand( + "INSERT INTO qgis_test.test_gen_col(id,name,geom) SELECT id,name,geom FROM qgis_test.test_gen_col_edit" + ) + self.execSQLCommand("DROP TABLE qgis_test.test_gen_col_edit") def testNonPkBigintField(self): """Test if we can correctly insert, read and change attributes(fields) of type bigint and which are not PKs.""" vl = QgsVectorLayer( '{} sslmode=disable srid=4326 key="pk" table="qgis_test".{} (geom)'.format( - self.dbconn, 'bigint_pk'), - "bigint_pk", "postgres") + self.dbconn, "bigint_pk" + ), + "bigint_pk", + "postgres", + ) self.assertTrue(vl.isValid()) flds = vl.fields() # Backup test table (will be edited) - scopedBackup = self.scopedTableBackup('qgis_test', 'bigint_pk') + scopedBackup = self.scopedTableBackup("qgis_test", "bigint_pk") # check if default values are correctly read back f = next(vl.getFeatures(QgsFeatureRequest())) - bigint_with_default_idx = vl.fields().lookupField('bigint_attribute_def') + bigint_with_default_idx = vl.fields().lookupField("bigint_attribute_def") self.assertEqual(f.attributes()[bigint_with_default_idx], 42) # check if NULL values are correctly read - bigint_def_null_idx = vl.fields().lookupField('bigint_attribute') + bigint_def_null_idx = vl.fields().lookupField("bigint_attribute") self.assertEqual(f.attributes()[bigint_def_null_idx], NULL) # check if we can overwrite a default value vl.startEditing() vl.changeAttributeValue(f.id(), bigint_with_default_idx, 43) - pkidx = vl.fields().lookupField('pk') + pkidx = vl.fields().lookupField("pk") editedid = f.attributes()[pkidx] self.assertTrue(vl.commitChanges()) vl2 = QgsVectorLayer( '{} sslmode=disable srid=4326 key="pk" table="qgis_test".{} (geom)'.format( - self.dbconn, 'bigint_pk'), - "bigint_pk", "postgres") + self.dbconn, "bigint_pk" + ), + "bigint_pk", + "postgres", + ) flds = vl2.fields() self.assertTrue(vl2.isValid()) - f = next(vl2.getFeatures( - QgsFeatureRequest().setFilterExpression('pk = ' + str(editedid)))) - bigint_with_default_idx = vl2.fields().lookupField('bigint_attribute_def') + f = next( + vl2.getFeatures( + QgsFeatureRequest().setFilterExpression("pk = " + str(editedid)) + ) + ) + bigint_with_default_idx = vl2.fields().lookupField("bigint_attribute_def") self.assertEqual(f.attributes()[bigint_with_default_idx], 43) # check if we can insert a new value dp = vl2.dataProvider() - dp.setProviderProperty(QgsDataProvider.ProviderProperty.EvaluateDefaultValues, 1) - pkidx = vl2.fields().lookupField('pk') + dp.setProviderProperty( + QgsDataProvider.ProviderProperty.EvaluateDefaultValues, 1 + ) + pkidx = vl2.fields().lookupField("pk") vl2.startEditing() f = QgsFeature(vl2.fields()) - f['pk'] = NULL - f['value'] = 'The answer.' - f['bigint_attribute'] = 84 + f["pk"] = NULL + f["value"] = "The answer." + f["bigint_attribute"] = 84 f.setAttribute(pkidx, vl2.dataProvider().defaultValue(pkidx)) - f.setAttribute(bigint_with_default_idx, - vl2.dataProvider().defaultValue(bigint_with_default_idx)) + f.setAttribute( + bigint_with_default_idx, + vl2.dataProvider().defaultValue(bigint_with_default_idx), + ) r, f = vl2.dataProvider().addFeatures([f]) self.assertTrue(r) vl2.commitChanges() - inserted_id = f[0]['pk'] + inserted_id = f[0]["pk"] - f = next(vl2.getFeatures( - QgsFeatureRequest().setFilterExpression('pk = ' + str(inserted_id)))) + f = next( + vl2.getFeatures( + QgsFeatureRequest().setFilterExpression("pk = " + str(inserted_id)) + ) + ) - self.assertEqual(f['bigint_attribute'], 84) - self.assertEqual(f['bigint_attribute_def'], 42) + self.assertEqual(f["bigint_attribute"], 84) + self.assertEqual(f["bigint_attribute_def"], 42) def testPktUpdateBigintPk(self): """Test if we can update objects with positive, zero and negative bigint PKs.""" vl = QgsVectorLayer( '{} sslmode=disable srid=4326 key="pk" table="qgis_test".{} (geom)'.format( - self.dbconn, 'bigint_pk'), - "bigint_pk", "postgres") + self.dbconn, "bigint_pk" + ), + "bigint_pk", + "postgres", + ) flds = vl.fields() # Backup test table (will be edited) - scopedBackup = self.scopedTableBackup('qgis_test', 'bigint_pk') + scopedBackup = self.scopedTableBackup("qgis_test", "bigint_pk") self.assertTrue(vl.isValid()) @@ -786,21 +988,17 @@ def testPktUpdateBigintPk(self): statuses = [-1, -1, -1, -1] # changing values... for ft in vl.getFeatures(): - if ft['value'] == 'first value': - vl.changeAttributeValue( - ft.id(), flds.indexOf('value'), '1st value') + if ft["value"] == "first value": + vl.changeAttributeValue(ft.id(), flds.indexOf("value"), "1st value") statuses[0] = 0 - elif ft['value'] == 'second value': - vl.changeAttributeValue( - ft.id(), flds.indexOf('value'), '2nd value') + elif ft["value"] == "second value": + vl.changeAttributeValue(ft.id(), flds.indexOf("value"), "2nd value") statuses[1] = 0 - elif ft['value'] == 'zero value': - vl.changeAttributeValue( - ft.id(), flds.indexOf('value'), '0th value') + elif ft["value"] == "zero value": + vl.changeAttributeValue(ft.id(), flds.indexOf("value"), "0th value") statuses[2] = 0 - elif ft['value'] == 'negative value': - vl.changeAttributeValue( - ft.id(), flds.indexOf('value'), '-1th value') + elif ft["value"] == "negative value": + vl.changeAttributeValue(ft.id(), flds.indexOf("value"), "-1th value") statuses[3] = 0 self.assertTrue(vl.commitChanges()) self.assertTrue(all(x == 0 for x in statuses)) @@ -808,25 +1006,32 @@ def testPktUpdateBigintPk(self): # now, let's see if the values were changed vl2 = QgsVectorLayer( '{} sslmode=disable srid=4326 key="pk" table="qgis_test".{} (geom)'.format( - self.dbconn, 'bigint_pk'), - "bigint_pk", "postgres") + self.dbconn, "bigint_pk" + ), + "bigint_pk", + "postgres", + ) self.assertTrue(vl2.isValid()) for ft in vl2.getFeatures(): - if ft['value'] == '1st value': + if ft["value"] == "1st value": statuses[0] = 1 - elif ft['value'] == '2nd value': + elif ft["value"] == "2nd value": statuses[1] = 1 - elif ft['value'] == '0th value': + elif ft["value"] == "0th value": statuses[2] = 1 - elif ft['value'] == '-1th value': + elif ft["value"] == "-1th value": statuses[3] = 1 self.assertTrue(all(x == 1 for x in statuses)) def testPktUpdateBigintPkNonFirst(self): """Test if we can update objects with positive, zero and negative bigint PKs in tables whose PK is not the first field""" - vl = QgsVectorLayer('{} sslmode=disable srid=4326 key="pk" table="qgis_test".{} (geom)'.format(self.dbconn, - 'bigint_non_first_pk'), - "bigint_non_first_pk", "postgres") + vl = QgsVectorLayer( + '{} sslmode=disable srid=4326 key="pk" table="qgis_test".{} (geom)'.format( + self.dbconn, "bigint_non_first_pk" + ), + "bigint_non_first_pk", + "postgres", + ) flds = vl.fields() self.assertTrue(vl.isValid()) @@ -834,28 +1039,24 @@ def testPktUpdateBigintPkNonFirst(self): vl.startEditing() # Backup test table (will be edited) - scopedBackup = self.scopedTableBackup('qgis_test', 'bigint_non_first_pk') + scopedBackup = self.scopedTableBackup("qgis_test", "bigint_non_first_pk") statuses = [-1, -1, -1, -1] - values = ['first value', 'second value', 'zero value', 'negative value'] - newvalues = ['1st value', '2nd value', '0th value', '-1th value'] + values = ["first value", "second value", "zero value", "negative value"] + newvalues = ["1st value", "2nd value", "0th value", "-1th value"] # changing values... for ft in vl.getFeatures(): - if ft['value'] == values[0]: - vl.changeAttributeValue( - ft.id(), flds.indexOf('value'), newvalues[0]) + if ft["value"] == values[0]: + vl.changeAttributeValue(ft.id(), flds.indexOf("value"), newvalues[0]) statuses[0] = 0 - elif ft['value'] == values[1]: - vl.changeAttributeValue( - ft.id(), flds.indexOf('value'), newvalues[1]) + elif ft["value"] == values[1]: + vl.changeAttributeValue(ft.id(), flds.indexOf("value"), newvalues[1]) statuses[1] = 0 - elif ft['value'] == values[2]: - vl.changeAttributeValue( - ft.id(), flds.indexOf('value'), newvalues[2]) + elif ft["value"] == values[2]: + vl.changeAttributeValue(ft.id(), flds.indexOf("value"), newvalues[2]) statuses[2] = 0 - elif ft['value'] == values[3]: - vl.changeAttributeValue( - ft.id(), flds.indexOf('value'), newvalues[3]) + elif ft["value"] == values[3]: + vl.changeAttributeValue(ft.id(), flds.indexOf("value"), newvalues[3]) statuses[3] = 0 self.assertTrue(vl.commitChanges()) for i in range(len(statuses)): @@ -864,79 +1065,110 @@ def testPktUpdateBigintPkNonFirst(self): # now, let's see if the values were changed vl2 = QgsVectorLayer( '{} sslmode=disable srid=4326 key="pk" table="qgis_test".{} (geom)'.format( - self.dbconn, 'bigint_non_first_pk'), - "bigint_pk_nonfirst", "postgres") + self.dbconn, "bigint_non_first_pk" + ), + "bigint_pk_nonfirst", + "postgres", + ) self.assertTrue(vl2.isValid()) for ft in vl2.getFeatures(): - if ft['value'] == newvalues[0]: + if ft["value"] == newvalues[0]: statuses[0] = 1 - elif ft['value'] == newvalues[1]: + elif ft["value"] == newvalues[1]: statuses[1] = 1 - elif ft['value'] == newvalues[2]: + elif ft["value"] == newvalues[2]: statuses[2] = 1 - elif ft['value'] == newvalues[3]: + elif ft["value"] == newvalues[3]: statuses[3] = 1 for i in range(len(statuses)): - self.assertEqual(statuses[i], 1, f'changed value "{newvalues[i]}" not found') + self.assertEqual( + statuses[i], 1, f'changed value "{newvalues[i]}" not found' + ) def testPktComposite(self): """ Check that tables with PKs composed of many fields of different types are correctly read and written to """ - vl = QgsVectorLayer(f'{self.dbconn} sslmode=disable srid=4326 key=\'"pk1","pk2"\' table="qgis_test"."tb_test_compound_pk" (geom)', "test_compound", "postgres") + vl = QgsVectorLayer( + f'{self.dbconn} sslmode=disable srid=4326 key=\'"pk1","pk2"\' table="qgis_test"."tb_test_compound_pk" (geom)', + "test_compound", + "postgres", + ) self.assertTrue(vl.isValid()) fields = vl.fields() - f = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression('pk1 = 1 AND pk2 = 2'))) + f = next( + vl.getFeatures( + QgsFeatureRequest().setFilterExpression("pk1 = 1 AND pk2 = 2") + ) + ) # first of all: we must be able to fetch a valid feature self.assertTrue(f.isValid()) - self.assertEqual(f['pk1'], 1) - self.assertEqual(f['pk2'], 2) - self.assertEqual(f['value'], 'test 2') + self.assertEqual(f["pk1"], 1) + self.assertEqual(f["pk2"], 2) + self.assertEqual(f["value"], "test 2") # Backup test table (will be edited) - scopedBackup = self.scopedTableBackup('qgis_test', 'tb_test_compound_pk') + scopedBackup = self.scopedTableBackup("qgis_test", "tb_test_compound_pk") # can we edit a field? vl.startEditing() - vl.changeAttributeValue(f.id(), fields.indexOf('value'), 'Edited Test 2') + vl.changeAttributeValue(f.id(), fields.indexOf("value"), "Edited Test 2") self.assertTrue(vl.commitChanges()) # Did we get it right? Let's create a new QgsVectorLayer and try to read back our changes: - vl2 = QgsVectorLayer(f'{self.dbconn} sslmode=disable srid=4326 table="qgis_test"."tb_test_compound_pk" (geom) key=\'"pk1","pk2"\' ', "test_compound2", "postgres") + vl2 = QgsVectorLayer( + f'{self.dbconn} sslmode=disable srid=4326 table="qgis_test"."tb_test_compound_pk" (geom) key=\'"pk1","pk2"\' ', + "test_compound2", + "postgres", + ) self.assertTrue(vl2.isValid()) - f2 = next(vl2.getFeatures(QgsFeatureRequest().setFilterExpression('pk1 = 1 AND pk2 = 2'))) + f2 = next( + vl2.getFeatures( + QgsFeatureRequest().setFilterExpression("pk1 = 1 AND pk2 = 2") + ) + ) self.assertTrue(f2.isValid()) # Then, making sure we really did change our value. - self.assertEqual(f2['value'], 'Edited Test 2') + self.assertEqual(f2["value"], "Edited Test 2") # How about inserting a new field? f3 = QgsFeature(vl2.fields()) - f3['pk1'] = 4 - f3['pk2'] = -9223372036854775800 - f3['value'] = 'other test' + f3["pk1"] = 4 + f3["pk2"] = -9223372036854775800 + f3["value"] = "other test" vl.startEditing() res, f3 = vl.dataProvider().addFeatures([f3]) self.assertTrue(res) self.assertTrue(vl.commitChanges()) # can we catch it on another layer? - f4 = next(vl2.getFeatures(QgsFeatureRequest().setFilterExpression('pk2 = -9223372036854775800'))) + f4 = next( + vl2.getFeatures( + QgsFeatureRequest().setFilterExpression("pk2 = -9223372036854775800") + ) + ) self.assertTrue(f4.isValid()) - expected_attrs = [4, -9223372036854775800, 'other test'] + expected_attrs = [4, -9223372036854775800, "other test"] self.assertEqual(f4.attributes(), expected_attrs) # Finally, let's delete one of the features. - f5 = next(vl2.getFeatures(QgsFeatureRequest().setFilterExpression('pk1 = 2 AND pk2 = 1'))) + f5 = next( + vl2.getFeatures( + QgsFeatureRequest().setFilterExpression("pk1 = 2 AND pk2 = 1") + ) + ) vl2.startEditing() vl2.deleteFeatures([f5.id()]) self.assertTrue(vl2.commitChanges()) # did we really delete? Let's try to get the deleted feature from the first layer. - f_iterator = vl.getFeatures(QgsFeatureRequest().setFilterExpression('pk1 = 2 AND pk2 = 1')) + f_iterator = vl.getFeatures( + QgsFeatureRequest().setFilterExpression("pk1 = 2 AND pk2 = 1") + ) got_feature = True try: @@ -951,70 +1183,94 @@ def testPktCompositeFloat(self): """ Check that tables with PKs composed of many fields of different types are correctly read and written to """ - vl = QgsVectorLayer(f'{self.dbconn} sslmode=disable srid=4326 key=\'"pk1","pk2","pk3"\' table="qgis_test"."tb_test_composite_float_pk" (geom)', "test_composite_float", "postgres") + vl = QgsVectorLayer( + f'{self.dbconn} sslmode=disable srid=4326 key=\'"pk1","pk2","pk3"\' table="qgis_test"."tb_test_composite_float_pk" (geom)', + "test_composite_float", + "postgres", + ) self.assertTrue(vl.isValid()) fields = vl.fields() - f = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk3 = '3.14159274'"))) + f = next( + vl.getFeatures( + QgsFeatureRequest().setFilterExpression("pk3 = '3.14159274'") + ) + ) # first of all: we must be able to fetch a valid feature self.assertTrue(f.isValid()) - self.assertEqual(f['pk1'], 1) - self.assertEqual(f['pk2'], 2) + self.assertEqual(f["pk1"], 1) + self.assertEqual(f["pk2"], 2) - self.assertAlmostEqual(f['pk3'], 3.14159274) - self.assertEqual(f['value'], 'test 2') + self.assertAlmostEqual(f["pk3"], 3.14159274) + self.assertEqual(f["value"], "test 2") # Backup test table (will be edited) - scopedBackup = self.scopedTableBackup('qgis_test', 'tb_test_composite_float_pk') + scopedBackup = self.scopedTableBackup("qgis_test", "tb_test_composite_float_pk") # can we edit a field? vl.startEditing() - vl.changeAttributeValue(f.id(), fields.indexOf('value'), 'Edited Test 2') + vl.changeAttributeValue(f.id(), fields.indexOf("value"), "Edited Test 2") self.assertTrue(vl.commitChanges()) # Did we get it right? Let's create a new QgsVectorLayer and try to read back our changes: - vl2 = QgsVectorLayer(f'{self.dbconn} sslmode=disable srid=4326 key=\'"pk1","pk2","pk3"\' table="qgis_test"."tb_test_composite_float_pk" (geom)', "test_composite_float2", "postgres") + vl2 = QgsVectorLayer( + f'{self.dbconn} sslmode=disable srid=4326 key=\'"pk1","pk2","pk3"\' table="qgis_test"."tb_test_composite_float_pk" (geom)', + "test_composite_float2", + "postgres", + ) self.assertTrue(vl2.isValid()) - f2 = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk3 = '3.14159274'"))) + f2 = next( + vl.getFeatures( + QgsFeatureRequest().setFilterExpression("pk3 = '3.14159274'") + ) + ) self.assertTrue(f2.isValid()) # just making sure we have the correct feature - self.assertAlmostEqual(f2['pk3'], 3.14159274) + self.assertAlmostEqual(f2["pk3"], 3.14159274) # Then, making sure we really did change our value. - self.assertEqual(f2['value'], 'Edited Test 2') + self.assertEqual(f2["value"], "Edited Test 2") # How about inserting a new field? f3 = QgsFeature(vl2.fields()) - f3['pk1'] = 4 - f3['pk2'] = -9223372036854775800 - f3['pk3'] = 7.29154 - f3['value'] = 'other test' + f3["pk1"] = 4 + f3["pk2"] = -9223372036854775800 + f3["pk3"] = 7.29154 + f3["value"] = "other test" vl.startEditing() res, f3 = vl.dataProvider().addFeatures([f3]) self.assertTrue(res) self.assertTrue(vl.commitChanges()) # can we catch it on another layer? - f4 = next(vl2.getFeatures(QgsFeatureRequest().setFilterExpression("pk2 = '-9223372036854775800'"))) + f4 = next( + vl2.getFeatures( + QgsFeatureRequest().setFilterExpression("pk2 = '-9223372036854775800'") + ) + ) self.assertTrue(f4.isValid()) - expected_attrs = [4, -9223372036854775800, 7.29154, 'other test'] - gotten_attrs = [f4['pk1'], f4['pk2'], f4['pk3'], f4['value']] + expected_attrs = [4, -9223372036854775800, 7.29154, "other test"] + gotten_attrs = [f4["pk1"], f4["pk2"], f4["pk3"], f4["value"]] self.assertEqual(gotten_attrs[0], expected_attrs[0]) self.assertEqual(gotten_attrs[1], expected_attrs[1]) self.assertAlmostEqual(gotten_attrs[2], expected_attrs[2], places=4) self.assertEqual(gotten_attrs[3], expected_attrs[3]) # Finally, let's delete one of the features. - f5 = next(vl2.getFeatures(QgsFeatureRequest().setFilterExpression("pk3 = '7.29154'"))) + f5 = next( + vl2.getFeatures(QgsFeatureRequest().setFilterExpression("pk3 = '7.29154'")) + ) vl2.startEditing() vl2.deleteFeatures([f5.id()]) self.assertTrue(vl2.commitChanges()) # did we really delete? - f_iterator = vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk3 = '7.29154'")) + f_iterator = vl.getFeatures( + QgsFeatureRequest().setFilterExpression("pk3 = '7.29154'") + ) got_feature = True try: @@ -1031,34 +1287,66 @@ def testPktFloatingPoint(self): """ # 0. Backup test table (will be edited) - scopedBackup1 = self.scopedTableBackup('qgis_test', 'tb_test_float_pk') - scopedBackup2 = self.scopedTableBackup('qgis_test', 'tb_test_double_pk') + scopedBackup1 = self.scopedTableBackup("qgis_test", "tb_test_float_pk") + scopedBackup2 = self.scopedTableBackup("qgis_test", "tb_test_double_pk") # 1. 32 bit float (PostgreSQL "REAL" type) - vl = QgsVectorLayer(self.dbconn + ' sslmode=disable srid=4326 key="pk" table="qgis_test"."tb_test_float_pk" (geom)', "test_float_pk", "postgres") + vl = QgsVectorLayer( + self.dbconn + + ' sslmode=disable srid=4326 key="pk" table="qgis_test"."tb_test_float_pk" (geom)', + "test_float_pk", + "postgres", + ) self.assertTrue(vl.isValid()) # 1.1. Retrieving - f = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '3.141592653589793238462643383279502884197169'"))) + f = next( + vl.getFeatures( + QgsFeatureRequest().setFilterExpression( + "pk = '3.141592653589793238462643383279502884197169'" + ) + ) + ) self.assertTrue(f.isValid()) - self.assertEqual(f['value'], 'first teste') + self.assertEqual(f["value"], "first teste") # 1.2. Editing self.assertTrue(vl.startEditing()) - vl.changeAttributeValue(f.id(), vl.fields().indexOf('value'), 'Changed first') + vl.changeAttributeValue(f.id(), vl.fields().indexOf("value"), "Changed first") self.assertTrue(vl.commitChanges()) # 1.2.1. Checking edit from another vector layer - vl2 = QgsVectorLayer(self.dbconn + ' sslmode=disable srid=4326 key="pk1" table="qgis_test"."tb_test_float_pk" (geom)', "test_float_pk2", "postgres") + vl2 = QgsVectorLayer( + self.dbconn + + ' sslmode=disable srid=4326 key="pk1" table="qgis_test"."tb_test_float_pk" (geom)', + "test_float_pk2", + "postgres", + ) self.assertTrue(vl2.isValid()) - f2 = next(vl2.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '3.141592653589793238462643383279502884197169'"))) + f2 = next( + vl2.getFeatures( + QgsFeatureRequest().setFilterExpression( + "pk = '3.141592653589793238462643383279502884197169'" + ) + ) + ) self.assertTrue(f2.isValid()) - self.assertEqual(f2['value'], 'Changed first') + self.assertEqual(f2["value"], "Changed first") # 1.3. Deleting - f = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '2.718281828459045235360287471352662497757247'"))) + f = next( + vl.getFeatures( + QgsFeatureRequest().setFilterExpression( + "pk = '2.718281828459045235360287471352662497757247'" + ) + ) + ) vl.startEditing() vl.deleteFeatures([f.id()]) self.assertTrue(vl.commitChanges()) # 1.3.1. Checking deletion - f_iterator = vl2.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '2.718281828459045235360287471352662497757247'")) + f_iterator = vl2.getFeatures( + QgsFeatureRequest().setFilterExpression( + "pk = '2.718281828459045235360287471352662497757247'" + ) + ) got_feature = True try: @@ -1068,53 +1356,95 @@ def testPktFloatingPoint(self): got_feature = False self.assertFalse(got_feature) # 1.4. Inserting new feature - newpointwkt = 'Point(-47.751 -15.644)' + newpointwkt = "Point(-47.751 -15.644)" f = QgsFeature(vl.fields()) - f['pk'] = 0.22222222222222222222222 - f['value'] = 'newly inserted' + f["pk"] = 0.22222222222222222222222 + f["value"] = "newly inserted" f.setGeometry(QgsGeometry.fromWkt(newpointwkt)) vl.startEditing() res, f = vl.dataProvider().addFeatures([f]) self.assertTrue(res) self.assertTrue(vl.commitChanges()) # 1.4.1. Checking insertion - f2 = next(vl2.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '0.22222222222222222222222'"))) + f2 = next( + vl2.getFeatures( + QgsFeatureRequest().setFilterExpression( + "pk = '0.22222222222222222222222'" + ) + ) + ) self.assertTrue(f2.isValid()) - self.assertAlmostEqual(f2['pk'], 0.2222222222222222) - self.assertEqual(f2['value'], 'newly inserted') - assert compareWkt(f2.geometry().asWkt(), newpointwkt), f"Geometry mismatch. Expected: {f2.geometry().asWkt()} Got: {newpointwkt} \n" + self.assertAlmostEqual(f2["pk"], 0.2222222222222222) + self.assertEqual(f2["value"], "newly inserted") + assert compareWkt( + f2.geometry().asWkt(), newpointwkt + ), f"Geometry mismatch. Expected: {f2.geometry().asWkt()} Got: {newpointwkt} \n" # One more check: can we retrieve the same row with the value that we got from this layer? - floatpk = f2['pk'] - f3 = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression(f"pk = '{floatpk}'"))) + floatpk = f2["pk"] + f3 = next( + vl.getFeatures(QgsFeatureRequest().setFilterExpression(f"pk = '{floatpk}'")) + ) self.assertTrue(f3.isValid()) - self.assertEqual(f3['value'], 'newly inserted') - self.assertEqual(f3['pk'], floatpk) + self.assertEqual(f3["value"], "newly inserted") + self.assertEqual(f3["pk"], floatpk) # 2. 64 bit float (PostgreSQL "DOUBLE PRECISION" type) - vl = QgsVectorLayer(self.dbconn + ' sslmode=disable srid=4326 key="pk" table="qgis_test"."tb_test_double_pk" (geom)', "test_double_pk", "postgres") + vl = QgsVectorLayer( + self.dbconn + + ' sslmode=disable srid=4326 key="pk" table="qgis_test"."tb_test_double_pk" (geom)', + "test_double_pk", + "postgres", + ) self.assertTrue(vl.isValid()) # 2.1. Retrieving - f = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '3.141592653589793238462643383279502884197169'"))) + f = next( + vl.getFeatures( + QgsFeatureRequest().setFilterExpression( + "pk = '3.141592653589793238462643383279502884197169'" + ) + ) + ) self.assertTrue(f.isValid()) - self.assertEqual(f['value'], 'first teste') + self.assertEqual(f["value"], "first teste") # 2.2. Editing self.assertTrue(vl.startEditing()) - vl.changeAttributeValue(f.id(), vl.fields().indexOf('value'), 'Changed first') + vl.changeAttributeValue(f.id(), vl.fields().indexOf("value"), "Changed first") self.assertTrue(vl.commitChanges()) # 2.2.1. Checking edit from another vector layer - vl2 = QgsVectorLayer(self.dbconn + ' sslmode=disable srid=4326 key="pk" table="qgis_test"."tb_test_double_pk" (geom)', "test_double_pk2", "postgres") + vl2 = QgsVectorLayer( + self.dbconn + + ' sslmode=disable srid=4326 key="pk" table="qgis_test"."tb_test_double_pk" (geom)', + "test_double_pk2", + "postgres", + ) self.assertTrue(vl2.isValid()) - f2 = next(vl2.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '3.141592653589793238462643383279502884197169'"))) + f2 = next( + vl2.getFeatures( + QgsFeatureRequest().setFilterExpression( + "pk = '3.141592653589793238462643383279502884197169'" + ) + ) + ) self.assertTrue(f2.isValid()) - self.assertEqual(f2['value'], 'Changed first') + self.assertEqual(f2["value"], "Changed first") # 2.3. Deleting - f = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '2.718281828459045235360287471352662497757247'"))) + f = next( + vl.getFeatures( + QgsFeatureRequest().setFilterExpression( + "pk = '2.718281828459045235360287471352662497757247'" + ) + ) + ) vl.startEditing() vl.deleteFeatures([f.id()]) self.assertTrue(vl.commitChanges()) # 2.3.1. Checking deletion - f_iterator = vl2.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '2.718281828459045235360287471352662497757247'")) + f_iterator = vl2.getFeatures( + QgsFeatureRequest().setFilterExpression( + "pk = '2.718281828459045235360287471352662497757247'" + ) + ) got_feature = True try: @@ -1124,56 +1454,74 @@ def testPktFloatingPoint(self): got_feature = False self.assertFalse(got_feature) # 2.4. Inserting new feature - newpointwkt = 'Point(-47.751 -15.644)' + newpointwkt = "Point(-47.751 -15.644)" f = QgsFeature(vl.fields()) - f['pk'] = 0.22222222222222222222222 - f['value'] = 'newly inserted' + f["pk"] = 0.22222222222222222222222 + f["value"] = "newly inserted" f.setGeometry(QgsGeometry.fromWkt(newpointwkt)) vl.startEditing() res, f = vl.dataProvider().addFeatures([f]) self.assertTrue(res) self.assertTrue(vl.commitChanges()) # 2.4.1. Checking insertion - f2 = next(vl2.getFeatures(QgsFeatureRequest().setFilterExpression("pk = '0.22222222222222222222222'"))) + f2 = next( + vl2.getFeatures( + QgsFeatureRequest().setFilterExpression( + "pk = '0.22222222222222222222222'" + ) + ) + ) self.assertTrue(f2.isValid()) - self.assertAlmostEqual(f2['pk'], 0.2222222222222222, places=15) - self.assertEqual(f2['value'], 'newly inserted') - assert compareWkt(f2.geometry().asWkt(), newpointwkt), f"Geometry mismatch. Expected: {f2.geometry().asWkt()} Got: {newpointwkt} \n" + self.assertAlmostEqual(f2["pk"], 0.2222222222222222, places=15) + self.assertEqual(f2["value"], "newly inserted") + assert compareWkt( + f2.geometry().asWkt(), newpointwkt + ), f"Geometry mismatch. Expected: {f2.geometry().asWkt()} Got: {newpointwkt} \n" # One more check: can we retrieve the same row with the value that we got from this layer? - doublepk = f2['pk'] - f3 = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression(f"pk = '{doublepk}'"))) + doublepk = f2["pk"] + f3 = next( + vl.getFeatures( + QgsFeatureRequest().setFilterExpression(f"pk = '{doublepk}'") + ) + ) self.assertTrue(f3.isValid()) - self.assertEqual(f3['value'], 'newly inserted') - self.assertEqual(f3['pk'], doublepk) + self.assertEqual(f3["value"], "newly inserted") + self.assertEqual(f3["pk"], doublepk) # no NUMERIC/DECIMAL checks here. NUMERIC primary keys are unsupported. # TODO: implement NUMERIC primary keys/arbitrary precision arithmethics/fixed point math in QGIS. def testPktMapInsert(self): - vl = QgsVectorLayer(f"{self.dbconn} table=\"qgis_test\".\"oid_serial_table\" key=\"obj_id\" sql=", - "oid_serial", "postgres") + vl = QgsVectorLayer( + f'{self.dbconn} table="qgis_test"."oid_serial_table" key="obj_id" sql=', + "oid_serial", + "postgres", + ) self.assertTrue(vl.isValid()) f = QgsFeature(vl.fields()) - f['obj_id'] = vl.dataProvider().defaultValueClause(0) - f['name'] = 'Test' + f["obj_id"] = vl.dataProvider().defaultValueClause(0) + f["name"] = "Test" r, f = vl.dataProvider().addFeatures([f]) self.assertTrue(r) - self.assertNotEqual(f[0]['obj_id'], NULL, f[0].attributes()) + self.assertNotEqual(f[0]["obj_id"], NULL, f[0].attributes()) vl.deleteFeatures([f[0].id()]) def testClonePreservesFidMap(self): vl = QgsVectorLayer( '{} sslmode=disable srid=4326 key="pk" table="qgis_test".{} (geom)'.format( - self.dbconn, 'bigint_pk'), - "bigint_pk", "postgres") + self.dbconn, "bigint_pk" + ), + "bigint_pk", + "postgres", + ) # Generate primary keys - f = next(vl.getFeatures('pk = 2')) # 1 - f = next(vl.getFeatures('pk = -1')) # 2 + f = next(vl.getFeatures("pk = 2")) # 1 + f = next(vl.getFeatures("pk = -1")) # 2 fid_orig = f.id() clone = vl.clone() - f = next(clone.getFeatures('pk = -1')) # should still be 2 + f = next(clone.getFeatures("pk = -1")) # should still be 2 fid_copy = f.id() self.assertEqual(fid_orig, fid_copy) @@ -1181,8 +1529,12 @@ def testNull(self): """ Asserts that 0, '' and NULL are treated as different values on insert """ - vl = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'gid\' table="qgis_test"."constraints" sql=', 'test1', - 'postgres') + vl = QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'gid\' table="qgis_test"."constraints" sql=', + "test1", + "postgres", + ) self.assertTrue(vl.isValid()) QgsProject.instance().addMapLayer(vl) tg = QgsTransactionGroup() @@ -1196,13 +1548,13 @@ def onError(message): vl.raiseError.connect(onError) f = QgsFeature(vl.fields()) - f['gid'] = 100 - f['val'] = 0 - f['name'] = '' + f["gid"] = 100 + f["val"] = 0 + f["name"] = "" self.assertTrue(vl.addFeature(f)) feature = next(vl.getFeatures('"gid" = 100')) - self.assertEqual(f['val'], feature['val']) - self.assertEqual(f['name'], feature['name']) + self.assertEqual(f["val"], feature["val"]) + self.assertEqual(f["name"], feature["name"]) def testNestedInsert(self): tg = QgsTransactionGroup() @@ -1211,8 +1563,10 @@ def testNestedInsert(self): l.startEditing() it = l.getFeatures() f = next(it) - f['pk'] = NULL - self.assertTrue(l.addFeature(f)) # Should not deadlock during an active iteration + f["pk"] = NULL + self.assertTrue( + l.addFeature(f) + ) # Should not deadlock during an active iteration f = next(it) l.commitChanges() @@ -1231,9 +1585,11 @@ def testTimeout(self): def testTransactionDirtyName(self): # create a vector ayer based on postgres vl = QgsVectorLayer( - self.dbconn + - ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=', - 'test', 'postgres') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=', + "test", + "postgres", + ) self.assertTrue(vl.isValid()) # prepare a project with transactions enabled @@ -1257,9 +1613,11 @@ def testTransactionDirtyName(self): def testTransactionDirty(self): # create a vector layer based on postgres vl = QgsVectorLayer( - self.dbconn + - ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=', - 'test', 'postgres') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=', + "test", + "postgres", + ) self.assertTrue(vl.isValid()) # prepare a project with transactions enabled @@ -1269,7 +1627,7 @@ def testTransactionDirty(self): vl.startEditing() # check that the feature used for testing is ok - ft0 = vl.getFeatures('pk=1') + ft0 = vl.getFeatures("pk=1") f = QgsFeature() self.assertTrue(ft0.nextFeature(f)) @@ -1279,10 +1637,10 @@ def testTransactionDirty(self): self.assertTrue(tr.executeSql(sql, True)[0]) # check that the pk of the feature has been changed - ft = vl.getFeatures('pk=1') + ft = vl.getFeatures("pk=1") self.assertFalse(ft.nextFeature(f)) - ft = vl.getFeatures('pk=33') + ft = vl.getFeatures("pk=33") self.assertTrue(ft.nextFeature(f)) # underlying data has been modified but the layer is not tagged as @@ -1293,20 +1651,24 @@ def testTransactionDirty(self): vl.undoStack().undo() # check that the original feature with pk is back - ft0 = vl.getFeatures('pk=1') + ft0 = vl.getFeatures("pk=1") self.assertTrue(ft0.nextFeature(f)) # redo vl.undoStack().redo() # check that the pk of the feature has been changed - ft1 = vl.getFeatures('pk=1') + ft1 = vl.getFeatures("pk=1") self.assertFalse(ft1.nextFeature(f)) def testTransactionConstraints(self): # create a vector layer based on postgres - vl = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'id\' table="qgis_test"."check_constraints" sql=', - 'test', 'postgres') + vl = QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'id\' table="qgis_test"."check_constraints" sql=', + "test", + "postgres", + ) self.assertTrue(vl.isValid()) # prepare a project with transactions enabled @@ -1316,7 +1678,7 @@ def testTransactionConstraints(self): # get feature f = QgsFeature() - self.assertTrue(vl.getFeatures('id=1').nextFeature(f)) + self.assertTrue(vl.getFeatures("id=1").nextFeature(f)) self.assertEqual(f.attributes(), [1, 4, 3]) # start edition @@ -1332,24 +1694,26 @@ def testTransactionConstraints(self): for w in form.findChildren(QLabel): if w.buddy(): spinBox = w.buddy() - if w.text() == 'a': + if w.text() == "a": spinBox.setValue(1) - elif w.text() == 'b': + elif w.text() == "b": spinBox.setValue(0) # save form.save() # check new values - self.assertTrue(vl.getFeatures('id=1').nextFeature(f)) + self.assertTrue(vl.getFeatures("id=1").nextFeature(f)) self.assertEqual(f.attributes(), [1, 1, 0]) def testTransactionTuple(self): # create a vector layer based on postgres vl = QgsVectorLayer( - self.dbconn + - ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=', - 'test', 'postgres') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=', + "test", + "postgres", + ) self.assertTrue(vl.isValid()) # prepare a project with transactions enabled @@ -1369,88 +1733,122 @@ def testTransactionTuple(self): def testDomainTypes(self): """Test that domain types are correctly mapped""" - vl = QgsVectorLayer('%s table="qgis_test"."domains" sql=' % - (self.dbconn), "domains", "postgres") + vl = QgsVectorLayer( + '%s table="qgis_test"."domains" sql=' % (self.dbconn), "domains", "postgres" + ) self.assertTrue(vl.isValid()) fields = vl.dataProvider().fields() expected = {} - expected['fld_var_char_domain'] = {'type': QVariant.String, 'typeName': 'qgis_test.var_char_domain', - 'length': -1} - expected['fld_var_char_domain_6'] = {'type': QVariant.String, 'typeName': 'qgis_test.var_char_domain_6', - 'length': 6} - expected['fld_character_domain'] = {'type': QVariant.String, 'typeName': 'qgis_test.character_domain', - 'length': 1} - expected['fld_character_domain_6'] = {'type': QVariant.String, 'typeName': 'qgis_test.character_domain_6', - 'length': 6} - expected['fld_char_domain'] = { - 'type': QVariant.String, 'typeName': 'qgis_test.char_domain', 'length': 1} - expected['fld_char_domain_6'] = { - 'type': QVariant.String, 'typeName': 'qgis_test.char_domain_6', 'length': 6} - expected['fld_text_domain'] = { - 'type': QVariant.String, 'typeName': 'qgis_test.text_domain', 'length': -1} - expected['fld_numeric_domain'] = {'type': QVariant.Double, 'typeName': 'qgis_test.numeric_domain', 'length': 10, - 'precision': 4} + expected["fld_var_char_domain"] = { + "type": QVariant.String, + "typeName": "qgis_test.var_char_domain", + "length": -1, + } + expected["fld_var_char_domain_6"] = { + "type": QVariant.String, + "typeName": "qgis_test.var_char_domain_6", + "length": 6, + } + expected["fld_character_domain"] = { + "type": QVariant.String, + "typeName": "qgis_test.character_domain", + "length": 1, + } + expected["fld_character_domain_6"] = { + "type": QVariant.String, + "typeName": "qgis_test.character_domain_6", + "length": 6, + } + expected["fld_char_domain"] = { + "type": QVariant.String, + "typeName": "qgis_test.char_domain", + "length": 1, + } + expected["fld_char_domain_6"] = { + "type": QVariant.String, + "typeName": "qgis_test.char_domain_6", + "length": 6, + } + expected["fld_text_domain"] = { + "type": QVariant.String, + "typeName": "qgis_test.text_domain", + "length": -1, + } + expected["fld_numeric_domain"] = { + "type": QVariant.Double, + "typeName": "qgis_test.numeric_domain", + "length": 10, + "precision": 4, + } for f, e in list(expected.items()): + self.assertEqual(fields.at(fields.indexFromName(f)).type(), e["type"]) self.assertEqual( - fields.at(fields.indexFromName(f)).type(), e['type']) - self.assertEqual(fields.at(fields.indexFromName(f) - ).typeName(), e['typeName']) - self.assertEqual( - fields.at(fields.indexFromName(f)).length(), e['length']) - if 'precision' in e: + fields.at(fields.indexFromName(f)).typeName(), e["typeName"] + ) + self.assertEqual(fields.at(fields.indexFromName(f)).length(), e["length"]) + if "precision" in e: self.assertEqual( - fields.at(fields.indexFromName(f)).precision(), e['precision']) + fields.at(fields.indexFromName(f)).precision(), e["precision"] + ) def testRenameAttributes(self): - ''' Test renameAttributes() ''' - vl = QgsVectorLayer('%s table="qgis_test"."rename_table" sql=' % ( - self.dbconn), "renames", "postgres") + """Test renameAttributes()""" + vl = QgsVectorLayer( + '%s table="qgis_test"."rename_table" sql=' % (self.dbconn), + "renames", + "postgres", + ) provider = vl.dataProvider() - provider.renameAttributes({1: 'field1', 2: 'field2'}) + provider.renameAttributes({1: "field1", 2: "field2"}) # bad rename - self.assertFalse(provider.renameAttributes({-1: 'not_a_field'})) - self.assertFalse(provider.renameAttributes({100: 'not_a_field'})) + self.assertFalse(provider.renameAttributes({-1: "not_a_field"})) + self.assertFalse(provider.renameAttributes({100: "not_a_field"})) # already exists - self.assertFalse(provider.renameAttributes({1: 'field2'})) + self.assertFalse(provider.renameAttributes({1: "field2"})) # rename one field - self.assertTrue(provider.renameAttributes({1: 'newname'})) - self.assertEqual(provider.fields().at(1).name(), 'newname') + self.assertTrue(provider.renameAttributes({1: "newname"})) + self.assertEqual(provider.fields().at(1).name(), "newname") vl.updateFields() fet = next(vl.getFeatures()) - self.assertEqual(fet.fields()[1].name(), 'newname') + self.assertEqual(fet.fields()[1].name(), "newname") # rename two fields - self.assertTrue(provider.renameAttributes( - {1: 'newname2', 2: 'another'})) - self.assertEqual(provider.fields().at(1).name(), 'newname2') - self.assertEqual(provider.fields().at(2).name(), 'another') + self.assertTrue(provider.renameAttributes({1: "newname2", 2: "another"})) + self.assertEqual(provider.fields().at(1).name(), "newname2") + self.assertEqual(provider.fields().at(2).name(), "another") vl.updateFields() fet = next(vl.getFeatures()) - self.assertEqual(fet.fields()[1].name(), 'newname2') - self.assertEqual(fet.fields()[2].name(), 'another') + self.assertEqual(fet.fields()[1].name(), "newname2") + self.assertEqual(fet.fields()[2].name(), "another") # close layer and reopen, then recheck to confirm that changes were saved to db del vl vl = None - vl = QgsVectorLayer('%s table="qgis_test"."rename_table" sql=' % ( - self.dbconn), "renames", "postgres") + vl = QgsVectorLayer( + '%s table="qgis_test"."rename_table" sql=' % (self.dbconn), + "renames", + "postgres", + ) provider = vl.dataProvider() - self.assertEqual(provider.fields().at(1).name(), 'newname2') - self.assertEqual(provider.fields().at(2).name(), 'another') + self.assertEqual(provider.fields().at(1).name(), "newname2") + self.assertEqual(provider.fields().at(2).name(), "another") fet = next(vl.getFeatures()) - self.assertEqual(fet.fields()[1].name(), 'newname2') - self.assertEqual(fet.fields()[2].name(), 'another') + self.assertEqual(fet.fields()[1].name(), "newname2") + self.assertEqual(fet.fields()[2].name(), "another") def testEditorWidgetTypes(self): """Test that editor widget types can be fetched from the qgis_editor_widget_styles table""" - vl = QgsVectorLayer('%s table="qgis_test"."widget_styles" sql=' % ( - self.dbconn), "widget_styles", "postgres") + vl = QgsVectorLayer( + '%s table="qgis_test"."widget_styles" sql=' % (self.dbconn), + "widget_styles", + "postgres", + ) self.assertTrue(vl.isValid()) fields = vl.dataProvider().fields() @@ -1469,45 +1867,50 @@ def testEditorWidgetTypes(self): self.assertEqual(best2.type(), "TextEdit") def testHstore(self): - vl = QgsVectorLayer('%s table="qgis_test"."dict" sql=' % - (self.dbconn), "testhstore", "postgres") + vl = QgsVectorLayer( + '%s table="qgis_test"."dict" sql=' % (self.dbconn), "testhstore", "postgres" + ) self.assertTrue(vl.isValid()) fields = vl.dataProvider().fields() - self.assertEqual( - fields.at(fields.indexFromName('value')).type(), QVariant.Map) + self.assertEqual(fields.at(fields.indexFromName("value")).type(), QVariant.Map) f = next(vl.getFeatures(QgsFeatureRequest())) - value_idx = vl.fields().lookupField('value') + value_idx = vl.fields().lookupField("value") self.assertIsInstance(f.attributes()[value_idx], dict) - self.assertEqual(f.attributes()[value_idx], {'a': 'b', '1': '2'}) + self.assertEqual(f.attributes()[value_idx], {"a": "b", "1": "2"}) new_f = QgsFeature(vl.fields()) - new_f['pk'] = NULL - new_f['value'] = {'simple': '1', 'doubleQuote': '"y"', - 'quote': "'q'", 'backslash': '\\'} + new_f["pk"] = NULL + new_f["value"] = { + "simple": "1", + "doubleQuote": '"y"', + "quote": "'q'", + "backslash": "\\", + } r, fs = vl.dataProvider().addFeatures([new_f]) self.assertTrue(r) - new_pk = fs[0]['pk'] + new_pk = fs[0]["pk"] self.assertNotEqual(new_pk, NULL, fs[0].attributes()) try: read_back = vl.getFeature(new_pk) - self.assertEqual(read_back['pk'], new_pk) - self.assertEqual(read_back['value'], new_f['value']) + self.assertEqual(read_back["pk"], new_pk) + self.assertEqual(read_back["value"], new_f["value"]) finally: self.assertTrue(vl.startEditing()) self.assertTrue(vl.deleteFeatures([new_pk])) self.assertTrue(vl.commitChanges()) def testJson(self): - vl = QgsVectorLayer('%s table="qgis_test"."json" sql=' % - (self.dbconn), "testjson", "postgres") + vl = QgsVectorLayer( + '%s table="qgis_test"."json" sql=' % (self.dbconn), "testjson", "postgres" + ) self.assertTrue(vl.isValid()) # Backup test table (will be edited) - tableBackup = self.scopedTableBackup('qgis_test', 'json') + tableBackup = self.scopedTableBackup("qgis_test", "json") attrs = ( 123, @@ -1518,8 +1921,13 @@ def testJson(self): r"String literal with \"quotes\" 'and' other funny chars []{};#/èé*", [1, 2, 3.4, None], [True, False], - {'a': 123, 'b': 123.34, 'c': 'a string', 'd': [ - 1, 2, 3], 'e': {'a': 123, 'b': 123.45}} + { + "a": 123, + "b": 123.34, + "c": "a string", + "d": [1, 2, 3], + "e": {"a": 123, "b": 123.45}, + }, ) attrs2 = ( 246, @@ -1530,231 +1938,351 @@ def testJson(self): r"Yet another string literal with \"quotes\" 'and' other funny chars: π []{};#/èé*", [2, 4, 3.14159, None], [True, False], - {'a': 246, 'b': 246.68, 'c': 'a rounded area: π × r²', 'd': [ - 1, 2, 3], 'e': {'a': 246, 'b': 246.91}} + { + "a": 246, + "b": 246.68, + "c": "a rounded area: π × r²", + "d": [1, 2, 3], + "e": {"a": 246, "b": 246.91}, + }, ) - json_idx = vl.fields().lookupField('jvalue') - jsonb_idx = vl.fields().lookupField('jbvalue') + json_idx = vl.fields().lookupField("jvalue") + jsonb_idx = vl.fields().lookupField("jbvalue") for attr in attrs: # Add a new feature - vl2 = QgsVectorLayer('%s table="qgis_test"."json" sql=' % ( - self.dbconn), "testjson", "postgres") + vl2 = QgsVectorLayer( + '%s table="qgis_test"."json" sql=' % (self.dbconn), + "testjson", + "postgres", + ) self.assertTrue(vl2.startEditing()) f = QgsFeature(vl2.fields()) f.setAttributes([None, attr, attr]) self.assertTrue(vl2.addFeatures([f])) self.assertTrue(vl2.commitChanges(), attr) # Read back - vl2 = QgsVectorLayer('%s table="qgis_test"."json" sql=' % ( - self.dbconn), "testjson", "postgres") + vl2 = QgsVectorLayer( + '%s table="qgis_test"."json" sql=' % (self.dbconn), + "testjson", + "postgres", + ) fid = [f.id() for f in vl2.getFeatures()][-1] f = vl2.getFeature(fid) self.assertEqual(f.attributes(), [fid, attr, attr]) # Change attribute values - vl2 = QgsVectorLayer('%s table="qgis_test"."json" sql=' % ( - self.dbconn), "testjson", "postgres") + vl2 = QgsVectorLayer( + '%s table="qgis_test"."json" sql=' % (self.dbconn), + "testjson", + "postgres", + ) fid = [f.id() for f in vl2.getFeatures()][-1] self.assertTrue(vl2.startEditing()) - self.assertTrue(vl2.changeAttributeValues( - fid, {json_idx: attr, jsonb_idx: attr})) + self.assertTrue( + vl2.changeAttributeValues(fid, {json_idx: attr, jsonb_idx: attr}) + ) self.assertTrue(vl2.commitChanges()) # Read back - vl2 = QgsVectorLayer('%s table="qgis_test"."json" sql=' % ( - self.dbconn), "testjson", "postgres") + vl2 = QgsVectorLayer( + '%s table="qgis_test"."json" sql=' % (self.dbconn), + "testjson", + "postgres", + ) f = vl2.getFeature(fid) self.assertEqual(f.attributes(), [fid, attr, attr]) # Let's check changeFeatures: for attr in attrs2: - vl2 = QgsVectorLayer('%s table="qgis_test"."json" sql=' % ( - self.dbconn), "testjson", "postgres") + vl2 = QgsVectorLayer( + '%s table="qgis_test"."json" sql=' % (self.dbconn), + "testjson", + "postgres", + ) fid = [f.id() for f in vl2.getFeatures()][-1] self.assertTrue(vl2.startEditing()) - self.assertTrue(vl2.dataProvider().changeFeatures({fid: {json_idx: attr, jsonb_idx: attr}}, {})) + self.assertTrue( + vl2.dataProvider().changeFeatures( + {fid: {json_idx: attr, jsonb_idx: attr}}, {} + ) + ) self.assertTrue(vl2.commitChanges()) # Read back again - vl2 = QgsVectorLayer('%s table="qgis_test"."json" sql=' % ( - self.dbconn), "testjson", "postgres") + vl2 = QgsVectorLayer( + '%s table="qgis_test"."json" sql=' % (self.dbconn), + "testjson", + "postgres", + ) f = vl2.getFeature(fid) self.assertEqual(f.attributes(), [fid, attr, attr]) def testStringArray(self): - vl = QgsVectorLayer('%s table="qgis_test"."string_array" sql=' % ( - self.dbconn), "teststringarray", "postgres") + vl = QgsVectorLayer( + '%s table="qgis_test"."string_array" sql=' % (self.dbconn), + "teststringarray", + "postgres", + ) self.assertTrue(vl.isValid()) fields = vl.dataProvider().fields() - self.assertEqual(fields.at(fields.indexFromName( - 'value')).type(), QVariant.StringList) - self.assertEqual(fields.at(fields.indexFromName( - 'value')).subType(), QVariant.String) + self.assertEqual( + fields.at(fields.indexFromName("value")).type(), QVariant.StringList + ) + self.assertEqual( + fields.at(fields.indexFromName("value")).subType(), QVariant.String + ) f = next(vl.getFeatures(QgsFeatureRequest())) - value_idx = vl.fields().lookupField('value') + value_idx = vl.fields().lookupField("value") self.assertIsInstance(f.attributes()[value_idx], list) - self.assertEqual(f.attributes()[value_idx], ['a', 'b', 'c']) + self.assertEqual(f.attributes()[value_idx], ["a", "b", "c"]) new_f = QgsFeature(vl.fields()) - new_f['pk'] = NULL - new_f['value'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash'] + new_f["pk"] = NULL + new_f["value"] = ["simple", '"doubleQuote"', "'quote'", "back\\slash"] r, fs = vl.dataProvider().addFeatures([new_f]) self.assertTrue(r) - new_pk = fs[0]['pk'] + new_pk = fs[0]["pk"] self.assertNotEqual(new_pk, NULL, fs[0].attributes()) try: read_back = vl.getFeature(new_pk) - self.assertEqual(read_back['pk'], new_pk) - self.assertEqual(read_back['value'], new_f['value']) + self.assertEqual(read_back["pk"], new_pk) + self.assertEqual(read_back["value"], new_f["value"]) finally: self.assertTrue(vl.startEditing()) self.assertTrue(vl.deleteFeatures([new_pk])) self.assertTrue(vl.commitChanges()) def testIntArray(self): - vl = QgsVectorLayer('%s table="qgis_test"."int_array" sql=' % ( - self.dbconn), "testintarray", "postgres") + vl = QgsVectorLayer( + '%s table="qgis_test"."int_array" sql=' % (self.dbconn), + "testintarray", + "postgres", + ) self.assertTrue(vl.isValid()) fields = vl.dataProvider().fields() + self.assertEqual(fields.at(fields.indexFromName("value")).type(), QVariant.List) self.assertEqual( - fields.at(fields.indexFromName('value')).type(), QVariant.List) - self.assertEqual(fields.at(fields.indexFromName( - 'value')).subType(), QVariant.Int) + fields.at(fields.indexFromName("value")).subType(), QVariant.Int + ) f = next(vl.getFeatures(QgsFeatureRequest())) - value_idx = vl.fields().lookupField('value') + value_idx = vl.fields().lookupField("value") self.assertIsInstance(f.attributes()[value_idx], list) self.assertEqual(f.attributes()[value_idx], [1, 2, -5]) def testDoubleArray(self): - vl = QgsVectorLayer('%s table="qgis_test"."double_array" sql=' % ( - self.dbconn), "testdoublearray", "postgres") + vl = QgsVectorLayer( + '%s table="qgis_test"."double_array" sql=' % (self.dbconn), + "testdoublearray", + "postgres", + ) self.assertTrue(vl.isValid()) fields = vl.dataProvider().fields() + self.assertEqual(fields.at(fields.indexFromName("value")).type(), QVariant.List) self.assertEqual( - fields.at(fields.indexFromName('value')).type(), QVariant.List) - self.assertEqual(fields.at(fields.indexFromName( - 'value')).subType(), QVariant.Double) + fields.at(fields.indexFromName("value")).subType(), QVariant.Double + ) f = next(vl.getFeatures(QgsFeatureRequest())) - value_idx = vl.fields().lookupField('value') + value_idx = vl.fields().lookupField("value") self.assertIsInstance(f.attributes()[value_idx], list) self.assertEqual(f.attributes()[value_idx], [1.1, 2, -5.12345]) def testNotNullConstraint(self): - vl = QgsVectorLayer('%s table="qgis_test"."constraints" sql=' % ( - self.dbconn), "constraints", "postgres") + vl = QgsVectorLayer( + '%s table="qgis_test"."constraints" sql=' % (self.dbconn), + "constraints", + "postgres", + ) self.assertTrue(vl.isValid()) self.assertEqual(len(vl.fields()), 4) # test some bad field indexes - self.assertEqual(vl.dataProvider().fieldConstraints(-1), - QgsFieldConstraints.Constraints()) - self.assertEqual(vl.dataProvider().fieldConstraints( - 1001), QgsFieldConstraints.Constraints()) - - self.assertTrue(vl.dataProvider().fieldConstraints(0) & - QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertFalse(vl.dataProvider().fieldConstraints(1) - & QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertTrue(vl.dataProvider().fieldConstraints(2) & - QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertFalse(vl.dataProvider().fieldConstraints(3) - & QgsFieldConstraints.Constraint.ConstraintNotNull) + self.assertEqual( + vl.dataProvider().fieldConstraints(-1), QgsFieldConstraints.Constraints() + ) + self.assertEqual( + vl.dataProvider().fieldConstraints(1001), QgsFieldConstraints.Constraints() + ) + + self.assertTrue( + vl.dataProvider().fieldConstraints(0) + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertFalse( + vl.dataProvider().fieldConstraints(1) + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertTrue( + vl.dataProvider().fieldConstraints(2) + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertFalse( + vl.dataProvider().fieldConstraints(3) + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) # test that constraints have been saved to fields correctly fields = vl.fields() - self.assertTrue(fields.at(0).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertEqual(fields.at(0).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) - self.assertFalse(fields.at(1).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertTrue(fields.at(2).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertEqual(fields.at(2).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) - self.assertFalse(fields.at(3).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintNotNull) + self.assertTrue( + fields.at(0).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertEqual( + fields.at(0) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) + self.assertFalse( + fields.at(1).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertTrue( + fields.at(2).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertEqual( + fields.at(2) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) + self.assertFalse( + fields.at(3).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) def testUniqueConstraint(self): - vl = QgsVectorLayer('%s table="qgis_test"."constraints" sql=' % ( - self.dbconn), "constraints", "postgres") + vl = QgsVectorLayer( + '%s table="qgis_test"."constraints" sql=' % (self.dbconn), + "constraints", + "postgres", + ) self.assertTrue(vl.isValid()) self.assertEqual(len(vl.fields()), 4) # test some bad field indexes - self.assertEqual(vl.dataProvider().fieldConstraints(-1), - QgsFieldConstraints.Constraints()) - self.assertEqual(vl.dataProvider().fieldConstraints( - 1001), QgsFieldConstraints.Constraints()) - - self.assertTrue(vl.dataProvider().fieldConstraints(0) - & QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertTrue(vl.dataProvider().fieldConstraints(1) - & QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertTrue(vl.dataProvider().fieldConstraints(2) - & QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertFalse(vl.dataProvider().fieldConstraints(3) - & QgsFieldConstraints.Constraint.ConstraintUnique) + self.assertEqual( + vl.dataProvider().fieldConstraints(-1), QgsFieldConstraints.Constraints() + ) + self.assertEqual( + vl.dataProvider().fieldConstraints(1001), QgsFieldConstraints.Constraints() + ) + + self.assertTrue( + vl.dataProvider().fieldConstraints(0) + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + self.assertTrue( + vl.dataProvider().fieldConstraints(1) + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + self.assertTrue( + vl.dataProvider().fieldConstraints(2) + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + self.assertFalse( + vl.dataProvider().fieldConstraints(3) + & QgsFieldConstraints.Constraint.ConstraintUnique + ) # test that constraints have been saved to fields correctly fields = vl.fields() - self.assertTrue(fields.at(0).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertEqual(fields.at(0).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) - self.assertTrue(fields.at(1).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertEqual(fields.at(1).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) - self.assertTrue(fields.at(2).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertEqual(fields.at(2).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) - self.assertFalse(fields.at(3).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintUnique) + self.assertTrue( + fields.at(0).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + self.assertEqual( + fields.at(0) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) + self.assertTrue( + fields.at(1).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + self.assertEqual( + fields.at(1) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) + self.assertTrue( + fields.at(2).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + self.assertEqual( + fields.at(2) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) + self.assertFalse( + fields.at(3).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintUnique + ) def testConstraintOverwrite(self): - """ test that Postgres provider constraints can't be overwritten by vector layer method """ - vl = QgsVectorLayer('%s table="qgis_test"."constraints" sql=' % ( - self.dbconn), "constraints", "postgres") + """test that Postgres provider constraints can't be overwritten by vector layer method""" + vl = QgsVectorLayer( + '%s table="qgis_test"."constraints" sql=' % (self.dbconn), + "constraints", + "postgres", + ) self.assertTrue(vl.isValid()) - self.assertTrue(vl.dataProvider().fieldConstraints(0) & - QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertTrue(vl.fields().at(0).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintNotNull) + self.assertTrue( + vl.dataProvider().fieldConstraints(0) + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertTrue( + vl.fields().at(0).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) # add a constraint at the layer level vl.setFieldConstraint(0, QgsFieldConstraints.Constraint.ConstraintUnique) # should be no change at provider level - self.assertTrue(vl.dataProvider().fieldConstraints(0) & - QgsFieldConstraints.Constraint.ConstraintNotNull) + self.assertTrue( + vl.dataProvider().fieldConstraints(0) + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) # but layer should still keep provider constraints... - self.assertTrue(vl.fields().at(0).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertTrue(vl.fieldConstraints( - 0) & QgsFieldConstraints.Constraint.ConstraintNotNull) + self.assertTrue( + vl.fields().at(0).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertTrue( + vl.fieldConstraints(0) & QgsFieldConstraints.Constraint.ConstraintNotNull + ) # ...in addition to layer level constraint - self.assertTrue(vl.fields().at(0).constraints( - ).constraints() & QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertTrue(vl.fieldConstraints( - 0) & QgsFieldConstraints.Constraint.ConstraintUnique) + self.assertTrue( + vl.fields().at(0).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + self.assertTrue( + vl.fieldConstraints(0) & QgsFieldConstraints.Constraint.ConstraintUnique + ) def testReadOnly(self): # Check default edition capabilities - vl = QgsVectorLayer('%s sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=' % - (self.dbconn), "someData", "postgres") + vl = QgsVectorLayer( + '%s sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=' + % (self.dbconn), + "someData", + "postgres", + ) self.assertFalse(vl.readOnly()) caps = vl.dataProvider().capabilities() self.assertTrue(caps & QgsVectorDataProvider.Capability.AddFeatures) @@ -1769,8 +2297,13 @@ def testReadOnly(self): # Check forceReadOnly options = QgsVectorLayer.LayerOptions() options.forceReadOnly = True - vl = QgsVectorLayer('%s sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=' % - (self.dbconn), "someData", "postgres", options) + vl = QgsVectorLayer( + '%s sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=' + % (self.dbconn), + "someData", + "postgres", + options, + ) self.assertTrue(vl.readOnly()) caps = vl.dataProvider().capabilities() self.assertFalse(caps & QgsVectorDataProvider.Capability.AddFeatures) @@ -1783,20 +2316,22 @@ def testReadOnly(self): self.assertTrue(caps & QgsVectorDataProvider.Capability.SelectAtId) def testVectorLayerUtilsUniqueWithProviderDefault(self): - vl = QgsVectorLayer('%s table="qgis_test"."someData" sql=' % - (self.dbconn), "someData", "postgres") - default_clause = 'nextval(\'qgis_test."someData_pk_seq"\'::regclass)' + vl = QgsVectorLayer( + '%s table="qgis_test"."someData" sql=' % (self.dbconn), + "someData", + "postgres", + ) + default_clause = "nextval('qgis_test.\"someData_pk_seq\"'::regclass)" vl.dataProvider().setProviderProperty( - QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False) - self.assertEqual( - vl.dataProvider().defaultValueClause(0), default_clause) + QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False + ) + self.assertEqual(vl.dataProvider().defaultValueClause(0), default_clause) self.assertTrue(QgsVectorLayerUtils.valueExists(vl, 0, 4)) vl.startEditing() f = QgsFeature(vl.fields()) f.setAttribute(0, default_clause) - self.assertFalse( - QgsVectorLayerUtils.valueExists(vl, 0, default_clause)) + self.assertFalse(QgsVectorLayerUtils.valueExists(vl, 0, default_clause)) self.assertTrue(vl.addFeatures([f])) # the default value clause should exist... @@ -1806,85 +2341,107 @@ def testVectorLayerUtilsUniqueWithProviderDefault(self): vl.rollBack() def testSkipConstraintCheck(self): - vl = QgsVectorLayer('%s table="qgis_test"."someData" sql=' % - (self.dbconn), "someData", "postgres") - default_clause = 'nextval(\'qgis_test."someData_pk_seq"\'::regclass)' + vl = QgsVectorLayer( + '%s table="qgis_test"."someData" sql=' % (self.dbconn), + "someData", + "postgres", + ) + default_clause = "nextval('qgis_test.\"someData_pk_seq\"'::regclass)" vl.dataProvider().setProviderProperty( - QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False) - self.assertTrue(vl.dataProvider().skipConstraintCheck( - 0, QgsFieldConstraints.Constraint.ConstraintUnique, default_clause)) - self.assertFalse(vl.dataProvider().skipConstraintCheck( - 0, QgsFieldConstraints.Constraint.ConstraintUnique, 59)) + QgsDataProvider.ProviderProperty.EvaluateDefaultValues, False + ) + self.assertTrue( + vl.dataProvider().skipConstraintCheck( + 0, QgsFieldConstraints.Constraint.ConstraintUnique, default_clause + ) + ) + self.assertFalse( + vl.dataProvider().skipConstraintCheck( + 0, QgsFieldConstraints.Constraint.ConstraintUnique, 59 + ) + ) def testVectorLayerUtilsCreateFeatureWithProviderDefault(self): - vl = QgsVectorLayer('%s table="qgis_test"."someData" sql=' % - (self.dbconn), "someData", "postgres") - default_clause = 'nextval(\'qgis_test."someData_pk_seq"\'::regclass)' - self.assertEqual( - vl.dataProvider().defaultValueClause(0), default_clause) + vl = QgsVectorLayer( + '%s table="qgis_test"."someData" sql=' % (self.dbconn), + "someData", + "postgres", + ) + default_clause = "nextval('qgis_test.\"someData_pk_seq\"'::regclass)" + self.assertEqual(vl.dataProvider().defaultValueClause(0), default_clause) # If an attribute map is provided, QgsVectorLayerUtils.createFeature must # respect it, otherwise default values from provider are checked. # User's choice will not be respected if the value violates unique constraints. # See https://github.com/qgis/QGIS/issues/27758 - f = QgsVectorLayerUtils.createFeature(vl, attributes={1: 5, 3: 'map'}) + f = QgsVectorLayerUtils.createFeature(vl, attributes={1: 5, 3: "map"}) # changed so that createFeature respects user choice - self.assertEqual(f.attributes(), [ - default_clause, 5, "'qgis'::text", 'map', None, None, None, None, None]) + self.assertEqual( + f.attributes(), + [default_clause, 5, "'qgis'::text", "map", None, None, None, None, None], + ) vl.setDefaultValueDefinition(3, QgsDefaultValue("'mappy'")) # test ignore vector layer default value expression overrides postgres provider default clause, # due to user's choice - f = QgsVectorLayerUtils.createFeature(vl, attributes={1: 5, 3: 'map'}) - self.assertEqual(f.attributes(), [ - default_clause, 5, "'qgis'::text", 'map', None, None, None, None, None]) + f = QgsVectorLayerUtils.createFeature(vl, attributes={1: 5, 3: "map"}) + self.assertEqual( + f.attributes(), + [default_clause, 5, "'qgis'::text", "map", None, None, None, None, None], + ) # Since user did not enter a default for field 3, test must return the default value chosen f = QgsVectorLayerUtils.createFeature(vl, attributes={1: 5}) - self.assertEqual(f.attributes(), [ - default_clause, 5, "'qgis'::text", 'mappy', None, None, None, None, None]) + self.assertEqual( + f.attributes(), + [default_clause, 5, "'qgis'::text", "mappy", None, None, None, None, None], + ) # See https://github.com/qgis/QGIS/issues/23127 def testNumericPrecision(self): - uri = 'point?field=f1:int' - uri += '&field=f2:double(6,4)' - uri += '&field=f3:string(20)' + uri = "point?field=f1:int" + uri += "&field=f2:double(6,4)" + uri += "&field=f3:string(20)" lyr = QgsVectorLayer(uri, "x", "memory") self.assertTrue(lyr.isValid()) f = QgsFeature(lyr.fields()) - f['f1'] = 1 - f['f2'] = 123.456 - f['f3'] = '12345678.90123456789' + f["f1"] = 1 + f["f2"] = 123.456 + f["f3"] = "12345678.90123456789" lyr.dataProvider().addFeatures([f]) uri = f'{self.dbconn} table="qgis_test"."b18155" (g) key=\'f1\'' - self.execSQLCommand('DROP TABLE IF EXISTS qgis_test.b18155') - err = QgsVectorLayerExporter.exportLayer( - lyr, uri, "postgres", lyr.crs()) - self.assertEqual(err[0], QgsVectorLayerExporter.ExportError.NoError, - f'unexpected import error {err}') + self.execSQLCommand("DROP TABLE IF EXISTS qgis_test.b18155") + err = QgsVectorLayerExporter.exportLayer(lyr, uri, "postgres", lyr.crs()) + self.assertEqual( + err[0], + QgsVectorLayerExporter.ExportError.NoError, + f"unexpected import error {err}", + ) lyr = QgsVectorLayer(uri, "y", "postgres") self.assertTrue(lyr.isValid()) f = next(lyr.getFeatures()) - self.assertEqual(f['f1'], 1) - self.assertEqual(f['f2'], 123.456) - self.assertEqual(f['f3'], '12345678.90123456789') + self.assertEqual(f["f1"], 1) + self.assertEqual(f["f2"], 123.456) + self.assertEqual(f["f3"], "12345678.90123456789") # See https://github.com/qgis/QGIS/issues/23163 def testImportKey(self): - uri = 'point?field=f1:int' - uri += '&field=F2:double(6,4)' - uri += '&field=f3:string(20)' + uri = "point?field=f1:int" + uri += "&field=F2:double(6,4)" + uri += "&field=f3:string(20)" lyr = QgsVectorLayer(uri, "x", "memory") self.assertTrue(lyr.isValid()) def testKey(lyr, key, kfnames): - self.execSQLCommand('DROP TABLE IF EXISTS qgis_test.import_test') + self.execSQLCommand("DROP TABLE IF EXISTS qgis_test.import_test") uri = f'{self.dbconn} table="qgis_test"."import_test" (g)' if key is not None: - uri += f' key=\'{key}\'' - err = QgsVectorLayerExporter.exportLayer( - lyr, uri, "postgres", lyr.crs()) - self.assertEqual(err[0], QgsVectorLayerExporter.ExportError.NoError, - f'unexpected import error {err}') + uri += f" key='{key}'" + err = QgsVectorLayerExporter.exportLayer(lyr, uri, "postgres", lyr.crs()) + self.assertEqual( + err[0], + QgsVectorLayerExporter.ExportError.NoError, + f"unexpected import error {err}", + ) olyr = QgsVectorLayer(uri, "y", "postgres") self.assertTrue(olyr.isValid()) flds = lyr.fields() @@ -1905,33 +2462,31 @@ def testKey(lyr, key, kfnames): for i in range(0, len(kfnames)): self.assertEqual(oflds[pks[i]].name(), kfnames[i]) - testKey(lyr, 'f1', ['f1']) - testKey(lyr, '"f1"', ['f1']) - testKey(lyr, '"f1","F2"', ['f1', 'F2']) - testKey(lyr, '"f1","F2","f3"', ['f1', 'F2', 'f3']) - testKey(lyr, None, ['id']) + testKey(lyr, "f1", ["f1"]) + testKey(lyr, '"f1"', ["f1"]) + testKey(lyr, '"f1","F2"', ["f1", "F2"]) + testKey(lyr, '"f1","F2","f3"', ["f1", "F2", "f3"]) + testKey(lyr, None, ["id"]) # See https://github.com/qgis/QGIS/issues/25415 def testImportWithoutSchema(self): def _test(table, schema=None): - self.execSQLCommand(f'DROP TABLE IF EXISTS {table} CASCADE') - uri = 'point?field=f1:int' - uri += '&field=F2:double(6,4)' - uri += '&field=f3:string(20)' + self.execSQLCommand(f"DROP TABLE IF EXISTS {table} CASCADE") + uri = "point?field=f1:int" + uri += "&field=F2:double(6,4)" + uri += "&field=f3:string(20)" lyr = QgsVectorLayer(uri, "x", "memory") self.assertTrue(lyr.isValid()) - table = f"{table}" if schema is None else ( - f"\"{schema}\".\"{table}\"") + table = f"{table}" if schema is None else (f'"{schema}"."{table}"') dest_uri = f"{self.dbconn} sslmode=disable table={table} (geom) sql" - QgsVectorLayerExporter.exportLayer( - lyr, dest_uri, "postgres", lyr.crs()) + QgsVectorLayerExporter.exportLayer(lyr, dest_uri, "postgres", lyr.crs()) olyr = QgsVectorLayer(dest_uri, "y", "postgres") self.assertTrue(olyr.isValid(), f"Failed URI: {dest_uri}") # Test bug 17518 - _test('b17518') + _test("b17518") # Test fully qualified table (with schema) _test("b17518", "qgis_test") @@ -1947,20 +2502,36 @@ def _test(table, schema=None): _test("b17518", "qgis_test_wrong") def testStyle(self): - self.execSQLCommand('DROP TABLE IF EXISTS layer_styles CASCADE') + self.execSQLCommand("DROP TABLE IF EXISTS layer_styles CASCADE") vl = self.getEditableLayer() self.assertTrue(vl.isValid()) - self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, Qgis.ProviderStyleStorageCapability.LoadFromDatabase) - self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.SaveToDatabase, Qgis.ProviderStyleStorageCapability.SaveToDatabase) - self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.DeleteFromDatabase, Qgis.ProviderStyleStorageCapability.DeleteFromDatabase) + self.assertEqual( + int(vl.dataProvider().styleStorageCapabilities()) + & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, + Qgis.ProviderStyleStorageCapability.LoadFromDatabase, + ) + self.assertEqual( + int(vl.dataProvider().styleStorageCapabilities()) + & Qgis.ProviderStyleStorageCapability.SaveToDatabase, + Qgis.ProviderStyleStorageCapability.SaveToDatabase, + ) + self.assertEqual( + int(vl.dataProvider().styleStorageCapabilities()) + & Qgis.ProviderStyleStorageCapability.DeleteFromDatabase, + Qgis.ProviderStyleStorageCapability.DeleteFromDatabase, + ) # table layer_styles does not exist - res, err = QgsProviderRegistry.instance().styleExists('postgres', vl.source(), '') + res, err = QgsProviderRegistry.instance().styleExists( + "postgres", vl.source(), "" + ) self.assertFalse(res) self.assertFalse(err) - res, err = QgsProviderRegistry.instance().styleExists('postgres', vl.source(), 'a style') + res, err = QgsProviderRegistry.instance().styleExists( + "postgres", vl.source(), "a style" + ) self.assertFalse(res) self.assertFalse(err) @@ -1976,13 +2547,15 @@ def testStyle(self): self.assertTrue(errmsg) mFilePath = QDir.toNativeSeparators( - f"{unitTestDataPath()}/symbol_layer/singleSymbol.qml") + f"{unitTestDataPath()}/symbol_layer/singleSymbol.qml" + ) status = vl.loadNamedStyle(mFilePath) self.assertTrue(status) # The style is saved as non-default errorMsg = vl.saveStyleToDatabase( - "by day", "faded greens and elegant patterns", False, "") + "by day", "faded greens and elegant patterns", False, "" + ) self.assertFalse(errorMsg) # the style id should be "1", not "by day" @@ -1990,13 +2563,19 @@ def testStyle(self): self.assertEqual(qml, "") self.assertNotEqual(errmsg, "") - res, err = QgsProviderRegistry.instance().styleExists('postgres', vl.source(), '') + res, err = QgsProviderRegistry.instance().styleExists( + "postgres", vl.source(), "" + ) self.assertFalse(res) self.assertFalse(err) - res, err = QgsProviderRegistry.instance().styleExists('postgres', vl.source(), 'a style') + res, err = QgsProviderRegistry.instance().styleExists( + "postgres", vl.source(), "a style" + ) self.assertFalse(res) self.assertFalse(err) - res, err = QgsProviderRegistry.instance().styleExists('postgres', vl.source(), 'by day') + res, err = QgsProviderRegistry.instance().styleExists( + "postgres", vl.source(), "by day" + ) self.assertTrue(res) self.assertFalse(err) @@ -2012,7 +2591,7 @@ def testStyle(self): self.assertTrue(errmsg) qml, errmsg = vl.getStyleFromDatabase("1") - self.assertTrue(qml.startswith(' xMax and normalization ==> nothing found - _test(vl, QgsRectangle(180.0 - 0.0017, 45.0 - 0.0001, - -(180.0 - 0.0017), 45.0 + 0.0001), []) + _test( + vl, + QgsRectangle( + 180.0 - 0.0017, 45.0 - 0.0001, -(180.0 - 0.0017), 45.0 + 0.0001 + ), + [], + ) # good order but with xMin > xMax and without normalization - _test(vl, QgsRectangle(180.0 - 0.0017, 45.0 - 0.0001, - -(180.0 - 0.0017), 45.0 + 0.0001, False), [4]) + _test( + vl, + QgsRectangle( + 180.0 - 0.0017, 45.0 - 0.0001, -(180.0 - 0.0017), 45.0 + 0.0001, False + ), + [4], + ) # now from 3857 - _test(vl, QgsRectangle(-20037699.584651027, 5621430.516018896, -20037317.10092746, 5621612.352543215), [4], "EPSG:3857") + _test( + vl, + QgsRectangle( + -20037699.584651027, + 5621430.516018896, + -20037317.10092746, + 5621612.352543215, + ), + [4], + "EPSG:3857", + ) def testBBoxFilterOnGeographyType(self): """Test bounding box filter on geography type""" - self._doTestBBoxFilter(' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."testgeog" (geog) sql=') + self._doTestBBoxFilter( + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."testgeog" (geog) sql=' + ) def testBBoxFilterOnGeometryType(self): """Test bounding box filter on somegeometry type""" self._doTestBBoxFilter( - ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someBorderlineData" (geom) sql=') + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someBorderlineData" (geom) sql=' + ) def testReadCustomSRID(self): """Test that we can correctly read the SRS from a custom SRID""" @@ -2944,52 +3744,91 @@ def testReadCustomSRID(self): # Cleanup if needed try: - conn.dropVectorTable('qgis_test', 'test_custom_srid') + conn.dropVectorTable("qgis_test", "test_custom_srid") except QgsProviderConnectionException: pass - conn.executeSql("DELETE FROM spatial_ref_sys WHERE srid = 543210 AND auth_name='FOO' AND auth_srid=32600;") - conn.executeSql("""INSERT INTO spatial_ref_sys (srid, auth_name, auth_srid, srtext, proj4text) VALUES (543210, 'FOO', 32600, 'PROJCS["my_projection",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Easting",EAST],AXIS["Northing",NORTH]]','+proj=tmerc +lat_0=0 +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs');""") + conn.executeSql( + "DELETE FROM spatial_ref_sys WHERE srid = 543210 AND auth_name='FOO' AND auth_srid=32600;" + ) + conn.executeSql( + """INSERT INTO spatial_ref_sys (srid, auth_name, auth_srid, srtext, proj4text) VALUES (543210, 'FOO', 32600, 'PROJCS["my_projection",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Easting",EAST],AXIS["Northing",NORTH]]','+proj=tmerc +lat_0=0 +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs');""" + ) - conn.executeSql(''' + conn.executeSql( + """ CREATE TABLE "qgis_test"."test_custom_srid" ( gid serial primary key, geom geometry(Point, 543210) - );''') + );""" + ) - layer = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'gid\'table="qgis_test"."test_custom_srid" (geom) sql=', 'test', 'postgres') + layer = QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'gid\'table="qgis_test"."test_custom_srid" (geom) sql=', + "test", + "postgres", + ) - conn.executeSql("DELETE FROM spatial_ref_sys WHERE srid = 543210 AND auth_name='FOO' AND auth_srid=32600;") + conn.executeSql( + "DELETE FROM spatial_ref_sys WHERE srid = 543210 AND auth_name='FOO' AND auth_srid=32600;" + ) self.assertTrue(layer.isValid()) - self.assertEqual(layer.crs().description(), 'my_projection') + self.assertEqual(layer.crs().description(), "my_projection") def testSingleMultiColumnPkSmallData(self): """Test Single and Multi Column PK, `Small` Data""" from itertools import combinations - def test_for_pk_combinations(test_type_list, pk_column_name_list, fids_get_count): - pk_column_name = ','.join(pk_column_name_list) - set_new_pk = ''' + def test_for_pk_combinations( + test_type_list, pk_column_name_list, fids_get_count + ): + pk_column_name = ",".join(pk_column_name_list) + set_new_pk = """ ALTER TABLE qgis_test.multi_column_pk_small_data_table DROP CONSTRAINT multi_column_pk_small_data_pk; ALTER TABLE qgis_test.multi_column_pk_small_data_table - ADD CONSTRAINT multi_column_pk_small_data_pk PRIMARY KEY ({});''' + ADD CONSTRAINT multi_column_pk_small_data_pk PRIMARY KEY ({});""" set_new_layer = ' sslmode=disable key=\'{}\' srid=3857 type=POLYGON table="qgis_test"."multi_column_pk_small_data_{}" (geom) sql=' - error_string = 'from {} with PK - {} : expected {}, got {}' + error_string = "from {} with PK - {} : expected {}, got {}" - if 'table' in test_type_list: + if "table" in test_type_list: self.execSQLCommand(set_new_pk.format(pk_column_name)) for test_type in test_type_list: - vl = QgsVectorLayer(self.dbconn + set_new_layer.format(pk_column_name, test_type), 'test_multi_column_pk_small_data', 'postgres') - fids = [f.id() for f in vl.getFeatures(QgsFeatureRequest().setLimit(fids_get_count))] + vl = QgsVectorLayer( + self.dbconn + set_new_layer.format(pk_column_name, test_type), + "test_multi_column_pk_small_data", + "postgres", + ) + fids = [ + f.id() + for f in vl.getFeatures( + QgsFeatureRequest().setLimit(fids_get_count) + ) + ] fids2 = [f.id() for f in vl.getFeatures(fids)] - self.assertEqual(fids_get_count, len(fids), "Get with limit " + - error_string.format(test_type, pk_column_name, fids_get_count, len(fids))) - self.assertEqual(fids_get_count, len(fids2), "Get by fids " + - error_string.format(test_type, pk_column_name, fids_get_count, len(fids2))) + self.assertEqual( + fids_get_count, + len(fids), + "Get with limit " + + error_string.format( + test_type, pk_column_name, fids_get_count, len(fids) + ), + ) + self.assertEqual( + fids_get_count, + len(fids2), + "Get by fids " + + error_string.format( + test_type, pk_column_name, fids_get_count, len(fids2) + ), + ) - self.execSQLCommand('DROP TABLE IF EXISTS qgis_test.multi_column_pk_small_data_table CASCADE;') - self.execSQLCommand(''' + self.execSQLCommand( + "DROP TABLE IF EXISTS qgis_test.multi_column_pk_small_data_table CASCADE;" + ) + self.execSQLCommand( + """ CREATE TABLE qgis_test.multi_column_pk_small_data_table ( id_serial serial NOT NULL, id_uuid uuid NOT NULL, @@ -3007,14 +3846,18 @@ def test_for_pk_combinations(test_type_list, pk_column_name_list, fids_get_count id_all_null_uuid uuid, geom geometry(Polygon,3857), CONSTRAINT multi_column_pk_small_data_pk - PRIMARY KEY (id_serial, id_uuid, id_int, id_bigint, id_str) );''') - self.execSQLCommand(''' + PRIMARY KEY (id_serial, id_uuid, id_int, id_bigint, id_str) );""" + ) + self.execSQLCommand( + """ CREATE OR REPLACE VIEW qgis_test.multi_column_pk_small_data_view AS SELECT * FROM qgis_test.multi_column_pk_small_data_table; DROP MATERIALIZED VIEW IF EXISTS qgis_test.multi_column_pk_small_data_mat_view; CREATE MATERIALIZED VIEW qgis_test.multi_column_pk_small_data_mat_view AS - SELECT * FROM qgis_test.multi_column_pk_small_data_table;''') - self.execSQLCommand(''' + SELECT * FROM qgis_test.multi_column_pk_small_data_table;""" + ) + self.execSQLCommand( + """ TRUNCATE qgis_test.multi_column_pk_small_data_table; INSERT INTO qgis_test.multi_column_pk_small_data_table( id_uuid, id_int, id_bigint, id_str, id_inet4, id_inet6, id_cidr4, id_cidr6, @@ -3040,18 +3883,42 @@ def test_for_pk_combinations(test_type_list, pk_column_name_list, fids_get_count 100.0 * dx, 100.0 * dy ) FROM generate_series(1,3) dx, generate_series(1,3) dy; - REFRESH MATERIALIZED VIEW qgis_test.multi_column_pk_small_data_mat_view;''') + REFRESH MATERIALIZED VIEW qgis_test.multi_column_pk_small_data_mat_view;""" + ) - pk_col_list = ("id_serial", "id_uuid", "id_int", "id_bigint", "id_str", "id_inet4", "id_inet6", "id_cidr4", "id_cidr6", "id_macaddr", "id_macaddr8") + pk_col_list = ( + "id_serial", + "id_uuid", + "id_int", + "id_bigint", + "id_str", + "id_inet4", + "id_inet6", + "id_cidr4", + "id_cidr6", + "id_macaddr", + "id_macaddr8", + ) test_type_list = ["table", "view", "mat_view"] for n in [1, 2, len(pk_col_list)]: pk_col_set_list = list(combinations(pk_col_list, n)) for pk_col_set in pk_col_set_list: test_for_pk_combinations(test_type_list, pk_col_set, 7) - for col_name in ["id_serial", "id_uuid", "id_int", "id_bigint", "id_str", "id_inet4"]: - test_for_pk_combinations(["view", "mat_view"], ["id_half_null_uuid", col_name], 7) - test_for_pk_combinations(["view", "mat_view"], ["id_all_null_uuid", col_name], 7) + for col_name in [ + "id_serial", + "id_uuid", + "id_int", + "id_bigint", + "id_str", + "id_inet4", + ]: + test_for_pk_combinations( + ["view", "mat_view"], ["id_half_null_uuid", col_name], 7 + ) + test_for_pk_combinations( + ["view", "mat_view"], ["id_all_null_uuid", col_name], 7 + ) def testChangeAttributeWithDefaultValue(self): """Test that we can change an attribute value with its default value""" @@ -3061,23 +3928,32 @@ def testChangeAttributeWithDefaultValue(self): # Cleanup try: - conn.dropVectorTable('qgis_test', 'test_change_att_w_default_value') + conn.dropVectorTable("qgis_test", "test_change_att_w_default_value") except QgsProviderConnectionException: pass - conn.executeSql(''' + conn.executeSql( + """ CREATE TABLE "qgis_test"."test_change_att_w_default_value" ( id serial primary key, thetext1 character varying(8) DEFAULT NULL::character varying, thetext2 character varying(8) DEFAULT NULL, thetext3 character varying(8) DEFAULT 'blabla', thenumber integer DEFAULT 2+2 - );''') + );""" + ) - conn.executeSql(''' - INSERT INTO "qgis_test"."test_change_att_w_default_value" (thetext1,thetext2,thetext3,thenumber) VALUES ('test1','test2','test3',6);''') + conn.executeSql( + """ + INSERT INTO "qgis_test"."test_change_att_w_default_value" (thetext1,thetext2,thetext3,thenumber) VALUES ('test1','test2','test3',6);""" + ) - layer = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'id\'table="qgis_test"."test_change_att_w_default_value" sql=', 'test', 'postgres') + layer = QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'id\'table="qgis_test"."test_change_att_w_default_value" sql=', + "test", + "postgres", + ) self.assertTrue(layer.isValid()) self.assertEqual(layer.featureCount(), 1) feat = next(layer.getFeatures()) @@ -3086,14 +3962,29 @@ def testChangeAttributeWithDefaultValue(self): self.assertTrue(feat["thetext3"], "test3") self.assertTrue(feat["thenumber"], 6) - self.assertEqual(layer.dataProvider().defaultValueClause(1), "NULL::character varying") - self.assertEqual(layer.dataProvider().defaultValueClause(2), "NULL::character varying") - self.assertEqual(layer.dataProvider().defaultValueClause(3), "'blabla'::character varying") + self.assertEqual( + layer.dataProvider().defaultValueClause(1), "NULL::character varying" + ) + self.assertEqual( + layer.dataProvider().defaultValueClause(2), "NULL::character varying" + ) + self.assertEqual( + layer.dataProvider().defaultValueClause(3), "'blabla'::character varying" + ) self.assertEqual(layer.dataProvider().defaultValueClause(4), "(2 + 2)") layer.startEditing() - self.assertTrue(layer.changeAttributeValues(1, {1: "NULL::character varying", 2: "NULL::character varying", - 3: "'blabla'::character varying", 4: "(2 + 2)"})) + self.assertTrue( + layer.changeAttributeValues( + 1, + { + 1: "NULL::character varying", + 2: "NULL::character varying", + 3: "'blabla'::character varying", + 4: "(2 + 2)", + }, + ) + ) self.assertTrue(layer.commitChanges()) feat = next(layer.getFeatures()) @@ -3106,87 +3997,135 @@ def testChangeAttributeWithDefaultValue(self): def testExtractWithinDistanceAlgorithm(self): - with self.temporarySchema('extract_within_distance') as schema: + with self.temporarySchema("extract_within_distance") as schema: # Create and populate target table in PseudoWebMercator CRS self.execSQLCommand( - 'CREATE TABLE {}.target_3857 (id serial primary key, g geometry(linestring, 3857))' - .format(schema)) + "CREATE TABLE {}.target_3857 (id serial primary key, g geometry(linestring, 3857))".format( + schema + ) + ) # -- first line (id=1) self.execSQLCommand( - "INSERT INTO {}.target_3857 (g) values('SRID=3857;LINESTRING(0 0, 1000 1000)')" - .format(schema)) + "INSERT INTO {}.target_3857 (g) values('SRID=3857;LINESTRING(0 0, 1000 1000)')".format( + schema + ) + ) # -- secodn line is a great circle line on the right (id=2) self.execSQLCommand( - "INSERT INTO {}.target_3857 (g) values( ST_Transform('SRID=4326;LINESTRING(80 0,160 80)'::geometry, 3857) )" - .format(schema)) + "INSERT INTO {}.target_3857 (g) values( ST_Transform('SRID=4326;LINESTRING(80 0,160 80)'::geometry, 3857) )".format( + schema + ) + ) # Create and populate reference table in PseudoWebMercator CRS self.execSQLCommand( - 'CREATE TABLE {}.reference_3857 (id serial primary key, g geometry(point, 3857))' - .format(schema)) + "CREATE TABLE {}.reference_3857 (id serial primary key, g geometry(point, 3857))".format( + schema + ) + ) self.execSQLCommand( - "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(500 999)')" - .format(schema)) + "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(500 999)')".format( + schema + ) + ) self.execSQLCommand( - "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(501 999)')" - .format(schema)) + "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(501 999)')".format( + schema + ) + ) self.execSQLCommand( # -- this reference (id=3) is ON the first line (id=1) in webmercator # -- and probably very close in latlong WGS84 - "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(500 500)')" - .format(schema)) + "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(500 500)')".format( + schema + ) + ) self.execSQLCommand( # -- this reference (id=4) is at ~ 5 meters from second line (id=2) in webmercator - "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(12072440.688888172 5525668.358321408)')" - .format(schema)) + "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(12072440.688888172 5525668.358321408)')".format( + schema + ) + ) self.execSQLCommand( - "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(503 999)')" - .format(schema)) + "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(503 999)')".format( + schema + ) + ) self.execSQLCommand( - "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(504 999)')" - .format(schema)) + "INSERT INTO {}.reference_3857 (g) values('SRID=3857;POINT(504 999)')".format( + schema + ) + ) # Create and populate target and reference table in WGS84 latlong self.execSQLCommand( - 'CREATE TABLE {0}.target_4326 AS SELECT id, ST_Transform(g, 4326)::geometry(linestring,4326) as g FROM {0}.target_3857' - .format(schema)) + "CREATE TABLE {0}.target_4326 AS SELECT id, ST_Transform(g, 4326)::geometry(linestring,4326) as g FROM {0}.target_3857".format( + schema + ) + ) self.execSQLCommand( - 'CREATE TABLE {0}.reference_4326 AS SELECT id, ST_Transform(g, 4326)::geometry(point,4326) as g FROM {0}.reference_3857' - .format(schema)) + "CREATE TABLE {0}.reference_4326 AS SELECT id, ST_Transform(g, 4326)::geometry(point,4326) as g FROM {0}.reference_3857".format( + schema + ) + ) # Create target and reference layers vl_target_3857 = QgsVectorLayer( - '{} sslmode=disable key=id srid=3857 type=LINESTRING table="{}"."target_3857" (g) sql=' - .format(self.dbconn, schema), - 'target_3857', 'postgres') - self.assertTrue(vl_target_3857.isValid(), f"Could not create a layer from the '{schema}.target_3857' table using dbconn '{self.dbconn}'") + '{} sslmode=disable key=id srid=3857 type=LINESTRING table="{}"."target_3857" (g) sql='.format( + self.dbconn, schema + ), + "target_3857", + "postgres", + ) + self.assertTrue( + vl_target_3857.isValid(), + f"Could not create a layer from the '{schema}.target_3857' table using dbconn '{self.dbconn}'", + ) vl_reference_3857 = QgsVectorLayer( - '{} sslmode=disable key=id srid=3857 type=POINT table="{}"."reference_3857" (g) sql=' - .format(self.dbconn, schema), - 'reference_3857', 'postgres') - self.assertTrue(vl_reference_3857.isValid(), f"Could not create a layer from the '{schema}.reference_3857' table using dbconn '{self.dbconn}'") + '{} sslmode=disable key=id srid=3857 type=POINT table="{}"."reference_3857" (g) sql='.format( + self.dbconn, schema + ), + "reference_3857", + "postgres", + ) + self.assertTrue( + vl_reference_3857.isValid(), + f"Could not create a layer from the '{schema}.reference_3857' table using dbconn '{self.dbconn}'", + ) vl_target_4326 = QgsVectorLayer( - '{} sslmode=disable key=id srid=4326 type=LINESTRING table="{}"."target_4326" (g) sql=' - .format(self.dbconn, schema), - 'target_4326', 'postgres') - self.assertTrue(vl_target_4326.isValid(), f"Could not create a layer from the '{schema}.target_4326' table using dbconn '{self.dbconn}'") + '{} sslmode=disable key=id srid=4326 type=LINESTRING table="{}"."target_4326" (g) sql='.format( + self.dbconn, schema + ), + "target_4326", + "postgres", + ) + self.assertTrue( + vl_target_4326.isValid(), + f"Could not create a layer from the '{schema}.target_4326' table using dbconn '{self.dbconn}'", + ) vl_reference_4326 = QgsVectorLayer( - '{} sslmode=disable key=id srid=4326 type=POINT table="{}"."reference_4326" (g) sql=' - .format(self.dbconn, schema), - 'reference_4326', 'postgres') - self.assertTrue(vl_reference_4326.isValid(), f"Could not create a layer from the '{schema}.reference_4326' table using dbconn '{self.dbconn}'") + '{} sslmode=disable key=id srid=4326 type=POINT table="{}"."reference_4326" (g) sql='.format( + self.dbconn, schema + ), + "reference_4326", + "postgres", + ) + self.assertTrue( + vl_reference_4326.isValid(), + f"Could not create a layer from the '{schema}.reference_4326' table using dbconn '{self.dbconn}'", + ) # Create the ExtractWithinDistance algorithm # TODO: move registry initialization in class initialization ? QgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms()) registry = QgsApplication.instance().processingRegistry() - alg = registry.createAlgorithmById('native:extractwithindistance') + alg = registry.createAlgorithmById("native:extractwithindistance") self.assertIsNotNone(alg) # Utility feedback and context objects class ConsoleFeedBack(QgsProcessingFeedback): - _error = '' + _error = "" def reportError(self, error, fatalError=False): self._error = error @@ -3201,24 +4140,26 @@ def reportError(self, error, fatalError=False): parameters = { # extract features from here: - 'INPUT': vl_target_3857, + "INPUT": vl_target_3857, # extracted features must be within given # distance from this layer: - 'REFERENCE': vl_reference_3857, + "REFERENCE": vl_reference_3857, # distance (in INPUT units) - 'DISTANCE': 10, # meters - 'OUTPUT': 'memory:result' + "DISTANCE": 10, # meters + "OUTPUT": "memory:result", } # Note: the following returns true also in case of errors ... result = alg.run(parameters, context, feedback) self.assertEqual(result[1], True) - result_layer_name = result[0]['OUTPUT'] - vl_result = QgsProcessingUtils.mapLayerFromString(result_layer_name, context) + result_layer_name = result[0]["OUTPUT"] + vl_result = QgsProcessingUtils.mapLayerFromString( + result_layer_name, context + ) self.assertTrue(vl_result.isValid()) - extracted_fids = [f['id'] for f in vl_result.getFeatures()] + extracted_fids = [f["id"] for f in vl_result.getFeatures()] self.assertEqual(set(extracted_fids), {1, 2}) # ---------------------------------------------------------------- @@ -3227,24 +4168,26 @@ def reportError(self, error, fatalError=False): parameters = { # extract features from here: - 'INPUT': vl_target_4326, + "INPUT": vl_target_4326, # extracted features must be within given # distance from this layer: - 'REFERENCE': vl_reference_4326, + "REFERENCE": vl_reference_4326, # distance (in INPUT units) - 'DISTANCE': 9e-5, # degrees - 'OUTPUT': 'memory:result' + "DISTANCE": 9e-5, # degrees + "OUTPUT": "memory:result", } # Note: the following returns true also in case of errors ... result = alg.run(parameters, context, feedback) self.assertEqual(result[1], True) - result_layer_name = result[0]['OUTPUT'] - vl_result = QgsProcessingUtils.mapLayerFromString(result_layer_name, context) + result_layer_name = result[0]["OUTPUT"] + vl_result = QgsProcessingUtils.mapLayerFromString( + result_layer_name, context + ) self.assertTrue(vl_result.isValid()) - extracted_fids = [f['id'] for f in vl_result.getFeatures()] + extracted_fids = [f["id"] for f in vl_result.getFeatures()] self.assertEqual(set(extracted_fids), {1}) # ---------------------------------------------------------------- @@ -3253,24 +4196,26 @@ def reportError(self, error, fatalError=False): parameters = { # extract features from here: - 'INPUT': vl_target_4326, + "INPUT": vl_target_4326, # extracted features must be within given # distance from this layer: - 'REFERENCE': vl_reference_3857, + "REFERENCE": vl_reference_3857, # distance (in INPUT units) - 'DISTANCE': 9e-5, # degrees - 'OUTPUT': 'memory:result' + "DISTANCE": 9e-5, # degrees + "OUTPUT": "memory:result", } # Note: the following returns true also in case of errors ... result = alg.run(parameters, context, feedback) self.assertEqual(result[1], True) - result_layer_name = result[0]['OUTPUT'] - vl_result = QgsProcessingUtils.mapLayerFromString(result_layer_name, context) + result_layer_name = result[0]["OUTPUT"] + vl_result = QgsProcessingUtils.mapLayerFromString( + result_layer_name, context + ) self.assertTrue(vl_result.isValid()) - extracted_fids = [f['id'] for f in vl_result.getFeatures()] + extracted_fids = [f["id"] for f in vl_result.getFeatures()] self.assertEqual(set(extracted_fids), {1}) # ---------------------------------------------------------------- @@ -3279,45 +4224,60 @@ def reportError(self, error, fatalError=False): parameters = { # extract features from here: - 'INPUT': vl_target_3857, + "INPUT": vl_target_3857, # extracted features must be within given # distance from this layer: - 'REFERENCE': vl_reference_4326, + "REFERENCE": vl_reference_4326, # distance (in INPUT units) - 'DISTANCE': 10, # meters - 'OUTPUT': 'memory:result' + "DISTANCE": 10, # meters + "OUTPUT": "memory:result", } # Note: the following returns true also in case of errors ... result = alg.run(parameters, context, feedback) self.assertEqual(result[1], True) - result_layer_name = result[0]['OUTPUT'] - vl_result = QgsProcessingUtils.mapLayerFromString(result_layer_name, context) + result_layer_name = result[0]["OUTPUT"] + vl_result = QgsProcessingUtils.mapLayerFromString( + result_layer_name, context + ) self.assertTrue(vl_result.isValid()) - extracted_fids = [f['id'] for f in vl_result.getFeatures()] + extracted_fids = [f["id"] for f in vl_result.getFeatures()] self.assertEqual(set(extracted_fids), {1, 2}) # Bug ? def testGeographyAddFeature(self): """Test issue GH #54572 Error saving edit on PostGIS geometry when table also contains geography""" + self.execSQLCommand('DROP TABLE IF EXISTS qgis_test."geom_and_geog" CASCADE') self.execSQLCommand( - 'DROP TABLE IF EXISTS qgis_test."geom_and_geog" CASCADE') - self.execSQLCommand(""" + """ CREATE TABLE qgis_test.geom_and_geog ( pkey SERIAL PRIMARY KEY, geom geometry(POLYGON, 3857), geog geography(POLYGON, 4326) - );""") + );""" + ) - vl = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'pkey\' srid=3857 table="qgis_test"."geom_and_geog" (geom) sql=', 'geom_and_geog', 'postgres') + vl = QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'pkey\' srid=3857 table="qgis_test"."geom_and_geog" (geom) sql=', + "geom_and_geog", + "postgres", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 0) dp = vl.dataProvider() f = QgsFeature(vl.fields()) - f.setGeometry(QgsGeometry.fromWkt('POLYGON((28.030080546000004 -26.2055410477482,28.030103891999996 -26.20540054874821,28.030532775999998 -26.205458576748192,28.030553322999996 -26.2056050407482,28.030080546000004 -26.2055410477482))')) - f.setAttribute('geog', 'POLYGON((28.030080546000004 -26.2055410477482,28.030103891999996 -26.20540054874821,28.030532775999998 -26.205458576748192,28.030553322999996 -26.2056050407482,28.030080546000004 -26.2055410477482))') + f.setGeometry( + QgsGeometry.fromWkt( + "POLYGON((28.030080546000004 -26.2055410477482,28.030103891999996 -26.20540054874821,28.030532775999998 -26.205458576748192,28.030553322999996 -26.2056050407482,28.030080546000004 -26.2055410477482))" + ) + ) + f.setAttribute( + "geog", + "POLYGON((28.030080546000004 -26.2055410477482,28.030103891999996 -26.20540054874821,28.030532775999998 -26.205458576748192,28.030553322999996 -26.2056050407482,28.030080546000004 -26.2055410477482))", + ) self.assertTrue(dp.addFeature(f)) self.assertEqual(vl.featureCount(), 1) @@ -3327,67 +4287,76 @@ def testExtent(self): md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.dbconn, {}) - conn.executeSql(''' + conn.executeSql( + """ DROP TABLE IF EXISTS public.test_ext; CREATE TABLE public.test_ext (id SERIAL PRIMARY KEY, g geometry); INSERT INTO public.test_ext(g) SELECT ST_MakePoint(n,n*7) FROM generate_series(2,10,1) n; - ''') + """ + ) realExtent = QgsRectangle(2, 14, 10, 70) uri = QgsDataSourceUri(self.dbconn + ' table="public"."test_ext" (g)') # Create layer with computed (not estimated) metadata - vlReal = QgsVectorLayer(uri.uri(), 'test', 'postgres') + vlReal = QgsVectorLayer(uri.uri(), "test", "postgres") self.assertTrue(vlReal.isValid()) self.assertEqual(vlReal.extent(), realExtent) # Create layer with estimated metadata - vlEstm = QgsVectorLayer(uri.uri() + " estimatedmetadata='true'", 'estimated', 'postgres') + vlEstm = QgsVectorLayer( + uri.uri() + " estimatedmetadata='true'", "estimated", "postgres" + ) self.assertTrue(vlEstm.isValid()) # No stats - self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), 'with no stats') + self.assertAcceptableEstimatedExtent( + realExtent, vlEstm.extent(), "with no stats" + ) # Add stats - conn.executeSql('ANALYZE public.test_ext') + conn.executeSql("ANALYZE public.test_ext") vlEstm.updateExtents() - self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), 'with stats') + self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), "with stats") # Add index - conn.executeSql('CREATE INDEX ON public.test_ext using gist (g)') + conn.executeSql("CREATE INDEX ON public.test_ext using gist (g)") vlEstm.updateExtents() - self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), 'with index') + self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), "with index") # Cleanup - conn.executeSql('DROP TABLE IF EXISTS public.test_ext') + conn.executeSql("DROP TABLE IF EXISTS public.test_ext") def testExtent3D(self): def test_table(dbconn, table_name, wkt): - vl = QgsVectorLayer(f'{dbconn} srid=4326 table="qgis_test".{table_name} (geom) sql=', "testgeom", - "postgres") + vl = QgsVectorLayer( + f'{dbconn} srid=4326 table="qgis_test".{table_name} (geom) sql=', + "testgeom", + "postgres", + ) self.assertTrue(vl.isValid()) - self.assertEqual(str(vl.extent3D()), '') - - test_table(self.dbconn, 'p2d', [0, 0, float('nan'), 1, 1, float('nan')]) - test_table(self.dbconn, 'p3d', [0, 0, 0, 1, 1, 0]) - test_table(self.dbconn, 'triangle2d', [0, 0, float('nan'), 1, 1, float('nan')]) - test_table(self.dbconn, 'triangle3d', [0, 0, 0, 1, 1, 0]) - test_table(self.dbconn, 'tin2d', [0, 0, float('nan'), 1, 1, float('nan')]) - test_table(self.dbconn, 'tin3d', [0, 0, 0, 1, 1, 0]) - test_table(self.dbconn, 'ps2d', [0, 0, float('nan'), 1, 1, float('nan')]) - test_table(self.dbconn, 'ps3d', [0, 0, 0, 1, 1, 1]) - test_table(self.dbconn, 'mp3d', [0, 0, 0, 1, 1, 1]) - test_table(self.dbconn, 'pt2d', [0, 0, float('nan'), 0, 0, float('nan')]) - test_table(self.dbconn, 'pt3d', [0, 0, 0, 0, 0, 0]) - test_table(self.dbconn, 'ls2d', [0, 0, float('nan'), 1, 1, float('nan')]) - test_table(self.dbconn, 'ls3d', [0, 0, 0, 1, 1, 1]) - test_table(self.dbconn, 'mpt2d', [0, 0, float('nan'), 1, 1, float('nan')]) - test_table(self.dbconn, 'mpt3d', [0, 0, 0, 1, 1, 1]) - test_table(self.dbconn, 'mls2d', [0, 0, float('nan'), 3, 3, float('nan')]) - test_table(self.dbconn, 'mls3d', [0, 0, 0, 3, 3, 3]) - test_table(self.dbconn, 'pt4d', [1, 2, 3, 1, 2, 3]) + self.assertEqual(str(vl.extent3D()), "") + + test_table(self.dbconn, "p2d", [0, 0, float("nan"), 1, 1, float("nan")]) + test_table(self.dbconn, "p3d", [0, 0, 0, 1, 1, 0]) + test_table(self.dbconn, "triangle2d", [0, 0, float("nan"), 1, 1, float("nan")]) + test_table(self.dbconn, "triangle3d", [0, 0, 0, 1, 1, 0]) + test_table(self.dbconn, "tin2d", [0, 0, float("nan"), 1, 1, float("nan")]) + test_table(self.dbconn, "tin3d", [0, 0, 0, 1, 1, 0]) + test_table(self.dbconn, "ps2d", [0, 0, float("nan"), 1, 1, float("nan")]) + test_table(self.dbconn, "ps3d", [0, 0, 0, 1, 1, 1]) + test_table(self.dbconn, "mp3d", [0, 0, 0, 1, 1, 1]) + test_table(self.dbconn, "pt2d", [0, 0, float("nan"), 0, 0, float("nan")]) + test_table(self.dbconn, "pt3d", [0, 0, 0, 0, 0, 0]) + test_table(self.dbconn, "ls2d", [0, 0, float("nan"), 1, 1, float("nan")]) + test_table(self.dbconn, "ls3d", [0, 0, 0, 1, 1, 1]) + test_table(self.dbconn, "mpt2d", [0, 0, float("nan"), 1, 1, float("nan")]) + test_table(self.dbconn, "mpt3d", [0, 0, 0, 1, 1, 1]) + test_table(self.dbconn, "mls2d", [0, 0, float("nan"), 3, 3, float("nan")]) + test_table(self.dbconn, "mls3d", [0, 0, 0, 3, 3, 3]) + test_table(self.dbconn, "pt4d", [1, 2, 3, 1, 2, 3]) # See https://github.com/qgis/QGIS/issues/30294 def testGeographyExtent(self): @@ -3395,41 +4364,49 @@ def testGeographyExtent(self): conn = md.createConnection(self.dbconn, {}) # Create a 10 rows table with extent -10 -10 to 10 10 - conn.executeSql(''' + conn.executeSql( + """ DROP TABLE IF EXISTS public.test_geog_ext; CREATE TABLE public.test_geog_ext (id SERIAL PRIMARY KEY, g geography); INSERT INTO public.test_geog_ext(g) SELECT ST_MakePoint(n*4,n) FROM generate_series(-10,10,1) n; - ''') + """ + ) realExtent = QgsRectangle(-40, -10, 40, 10) uri = QgsDataSourceUri(self.dbconn + ' table="public"."test_geog_ext" (g)') # Create layer with computed (not estimated) metadata - vlReal = QgsVectorLayer(uri.uri(), 'real', 'postgres') - self.assertTrue(vlReal.isValid(), "Could not create test layer from qgis_test.test_geog_ext") + vlReal = QgsVectorLayer(uri.uri(), "real", "postgres") + self.assertTrue( + vlReal.isValid(), "Could not create test layer from qgis_test.test_geog_ext" + ) self.assertEqual(vlReal.extent(), realExtent) # Create layer with estimated metadata - vlEstm = QgsVectorLayer(uri.uri() + " estimatedmetadata='true'", 'estimated', 'postgres') + vlEstm = QgsVectorLayer( + uri.uri() + " estimatedmetadata='true'", "estimated", "postgres" + ) self.assertTrue(vlEstm.isValid()) # No stats - self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), 'with no stats') + self.assertAcceptableEstimatedExtent( + realExtent, vlEstm.extent(), "with no stats" + ) # Add stats - conn.executeSql('ANALYZE public.test_geog_ext') + conn.executeSql("ANALYZE public.test_geog_ext") vlEstm.updateExtents() - self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), 'with stats') + self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), "with stats") # Add index - conn.executeSql('CREATE INDEX ON public.test_geog_ext using gist (g)') + conn.executeSql("CREATE INDEX ON public.test_geog_ext using gist (g)") vlEstm.updateExtents() - self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), 'with index') + self.assertAcceptableEstimatedExtent(realExtent, vlEstm.extent(), "with index") # Cleanup - conn.executeSql('DROP TABLE public.test_geog_ext') + conn.executeSql("DROP TABLE public.test_geog_ext") # See: https://github.com/qgis/QGIS/issues/55856 def testPktLowerCase(self): @@ -3444,11 +4421,23 @@ def testPktLowerCase(self): self.assertTrue(layer.isValid()) # export the vector layer to postgresql with lowercase field names - self.execSQLCommand('DROP TABLE IF EXISTS qgis_test.pk_lowercase') - output_uri = f'{self.dbconn} table="qgis_test"."pk_lowercase" key=\'{pk_key.lower()}\'' - err = QgsVectorLayerExporter.exportLayer(layer, output_uri, "postgres", layer.crs(), False, {'lowercaseFieldNames': True}) - self.assertEqual(err[0], QgsVectorLayerExporter.ExportError.NoError, - f'unexpected import error {err}') + self.execSQLCommand("DROP TABLE IF EXISTS qgis_test.pk_lowercase") + output_uri = ( + f'{self.dbconn} table="qgis_test"."pk_lowercase" key=\'{pk_key.lower()}\'' + ) + err = QgsVectorLayerExporter.exportLayer( + layer, + output_uri, + "postgres", + layer.crs(), + False, + {"lowercaseFieldNames": True}, + ) + self.assertEqual( + err[0], + QgsVectorLayerExporter.ExportError.NoError, + f"unexpected import error {err}", + ) # retrieve the columns and type and check them cur = self.con.cursor() @@ -3458,9 +4447,10 @@ def testPktLowerCase(self): ) cur.execute(sql_cols) expected_cols = [ - ('dep', 'character varying'), - ('reg', 'character varying'), - ('number', 'integer')] + ("dep", "character varying"), + ("reg", "character varying"), + ("number", "integer"), + ] self.assertEqual(cur.fetchall(), expected_cols) # Retrieve the primary key and check its name and type @@ -3473,11 +4463,16 @@ def testPktLowerCase(self): "AND i.indisprimary;" ) cur.execute(sql_pk) - self.assertEqual(cur.fetchall(), [('dep', 'character varying')]) + self.assertEqual(cur.fetchall(), [("dep", "character varying")]) def testNameType(self): - vl = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'"table_catalog","table_schema","table_name"\' table="information_schema"."tables" () sql=', 'test', 'postgres') + vl = QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'"table_catalog","table_schema","table_name"\' table="information_schema"."tables" () sql=', + "test", + "postgres", + ) self.assertTrue(vl.isValid()) feat = next(vl.getFeatures()) @@ -3486,51 +4481,75 @@ def testNameType(self): def testColumnRestrictedLayerIsEditable(self): """ - Test editability of table with partial column insert privs - See https://github.com/qgis/QGIS/issues/28835 + Test editability of table with partial column insert privs + See https://github.com/qgis/QGIS/issues/28835 """ md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.dbconn, {}) - conn.executeSql(''' + conn.executeSql( + """ DROP TABLE IF EXISTS public.qgis_issue_gh_28835; CREATE UNLOGGED TABLE public.qgis_issue_gh_28835 ( id INT PRIMARY KEY, restricted_column TEXT, geom GEOMETRY(point, 4326) ) - ''') + """ + ) - uri = QgsDataSourceUri(self.dbconn + ' table="public"."qgis_issue_gh_28835" (geom)') - uri.setUsername('qgis_test_unprivileged_user') - uri.setPassword('qgis_test_unprivileged_user_password') + uri = QgsDataSourceUri( + self.dbconn + ' table="public"."qgis_issue_gh_28835" (geom)' + ) + uri.setUsername("qgis_test_unprivileged_user") + uri.setPassword("qgis_test_unprivileged_user_password") - conn.executeSql('GRANT SELECT ON public.qgis_issue_gh_28835 TO qgis_test_unprivileged_user') - vl = QgsVectorLayer(uri.uri(), 'test', 'postgres') + conn.executeSql( + "GRANT SELECT ON public.qgis_issue_gh_28835 TO qgis_test_unprivileged_user" + ) + vl = QgsVectorLayer(uri.uri(), "test", "postgres") self.assertTrue(vl.isValid(), "qgis_issue_gh_28835 is an invalid layer") - self.assertFalse(vl.startEditing(), "qgis_issue_gh_28835 is unexpectedly editable by qgis_test_unprivileged_user before grants") + self.assertFalse( + vl.startEditing(), + "qgis_issue_gh_28835 is unexpectedly editable by qgis_test_unprivileged_user before grants", + ) - conn.executeSql('GRANT INSERT(geom) ON public.qgis_issue_gh_28835 TO qgis_test_unprivileged_user') - vl = QgsVectorLayer(uri.uri(), 'test', 'postgres') + conn.executeSql( + "GRANT INSERT(geom) ON public.qgis_issue_gh_28835 TO qgis_test_unprivileged_user" + ) + vl = QgsVectorLayer(uri.uri(), "test", "postgres") self.assertTrue(vl.isValid(), "qgis_issue_gh_28835 is an invalid layer") - self.assertTrue(vl.startEditing(), "qgis_issue_gh_28835 is not editable by qgis_test_unprivileged_user after restricted-column insert grant") + self.assertTrue( + vl.startEditing(), + "qgis_issue_gh_28835 is not editable by qgis_test_unprivileged_user after restricted-column insert grant", + ) def testBitAndBitVarying(self): """Test issue GH #59129""" self.execSQLCommand( - 'ALTER TABLE IF EXISTS qgis_test."bit_and_bit_varying" DROP CONSTRAINT IF EXISTS pk_bit_and_bit_varying;') + 'ALTER TABLE IF EXISTS qgis_test."bit_and_bit_varying" DROP CONSTRAINT IF EXISTS pk_bit_and_bit_varying;' + ) self.execSQLCommand( - 'DROP TABLE IF EXISTS qgis_test."bit_and_bit_varying" CASCADE;') + 'DROP TABLE IF EXISTS qgis_test."bit_and_bit_varying" CASCADE;' + ) self.execSQLCommand( - 'CREATE TABLE qgis_test."bit_and_bit_varying" ( "T_Id" integer NOT NULL, a BIT(3), b BIT VARYING(5) );') + 'CREATE TABLE qgis_test."bit_and_bit_varying" ( "T_Id" integer NOT NULL, a BIT(3), b BIT VARYING(5) );' + ) self.execSQLCommand( - """INSERT INTO qgis_test."bit_and_bit_varying" VALUES (1, B'101', B'00');""") + """INSERT INTO qgis_test."bit_and_bit_varying" VALUES (1, B'101', B'00');""" + ) self.execSQLCommand( - 'ALTER TABLE qgis_test."bit_and_bit_varying" ADD CONSTRAINT pk_gh_bit_and_bit_varying PRIMARY KEY ("T_Id");') + 'ALTER TABLE qgis_test."bit_and_bit_varying" ADD CONSTRAINT pk_gh_bit_and_bit_varying PRIMARY KEY ("T_Id");' + ) - vl = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'id\' table="qgis_test"."bit_and_bit_varying" () sql=', 'bit_and_bit_varying', 'postgres') + vl = QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'id\' table="qgis_test"."bit_and_bit_varying" () sql=', + "bit_and_bit_varying", + "postgres", + ) self.assertTrue(vl.isValid()) feat = next(vl.getFeatures()) @@ -3544,29 +4563,33 @@ class TestPyQgsPostgresProviderCompoundKey(QgisTestCase, ProviderTestCase): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsPostgresProviderCompoundKey, cls).setUpClass() - cls.dbconn = 'service=qgis_test' - if 'QGIS_PGTEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_PGTEST_DB'] + super().setUpClass() + cls.dbconn = "service=qgis_test" + if "QGIS_PGTEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_PGTEST_DB"] # Create test layers cls.vl = QgsVectorLayer( - cls.dbconn + - ' sslmode=disable key=\'"key1","key2"\' srid=4326 type=POINT table="qgis_test"."someDataCompound" (geom) sql=', - 'test', 'postgres') + cls.dbconn + + ' sslmode=disable key=\'"key1","key2"\' srid=4326 type=POINT table="qgis_test"."someDataCompound" (geom) sql=', + "test", + "postgres", + ) assert cls.vl.isValid() cls.source = cls.vl.dataProvider() def enableCompiler(self): - QgsSettings().setValue('/qgis/compileExpressions', True) + QgsSettings().setValue("/qgis/compileExpressions", True) return True def disableCompiler(self): - QgsSettings().setValue('/qgis/compileExpressions', False) + QgsSettings().setValue("/qgis/compileExpressions", False) def uncompiledFilters(self): - return {'"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')', - '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')', - '"time" = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')'} + return { + "\"dt\" = to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy')", + "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')", + "\"time\" = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')", + } def partiallyCompiledFilters(self): return set() @@ -3575,68 +4598,98 @@ def testConstraints(self): for key in ["key1", "key2"]: idx = self.vl.dataProvider().fieldNameIndex(key) self.assertGreaterEqual(idx, 0) - self.assertFalse(self.vl.dataProvider().fieldConstraints( - idx) & QgsFieldConstraints.Constraint.ConstraintUnique) + self.assertFalse( + self.vl.dataProvider().fieldConstraints(idx) + & QgsFieldConstraints.Constraint.ConstraintUnique + ) def testCompoundPkChanges(self): - """ Check if fields with compound primary keys can be changed """ + """Check if fields with compound primary keys can be changed""" vl = self.vl self.assertTrue(vl.isValid()) - idx_key1 = vl.fields().lookupField('key1') - idx_key2 = vl.fields().lookupField('key2') + idx_key1 = vl.fields().lookupField("key1") + idx_key2 = vl.fields().lookupField("key2") # the name "pk" for this datasource is misleading; # the primary key is actually composed by the fields key1 and key2 - idx_pk = vl.fields().lookupField('pk') - idx_name = vl.fields().lookupField('name') - idx_name2 = vl.fields().lookupField('name2') + idx_pk = vl.fields().lookupField("pk") + idx_name = vl.fields().lookupField("name") + idx_name2 = vl.fields().lookupField("name2") - geomwkt = 'Point(-47.945 -15.812)' + geomwkt = "Point(-47.945 -15.812)" # start editing ordinary attribute. - ft1 = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("key1 = 2 AND key2 = 2"))) + ft1 = next( + vl.getFeatures( + QgsFeatureRequest().setFilterExpression("key1 = 2 AND key2 = 2") + ) + ) self.assertTrue(ft1.isValid()) original_geometry = ft1.geometry().asWkt() vl.startEditing() - self.assertTrue(vl.changeAttributeValues(ft1.id(), {idx_name: 'Rose'})) + self.assertTrue(vl.changeAttributeValues(ft1.id(), {idx_name: "Rose"})) self.assertTrue(vl.commitChanges()) # check change - ft2 = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("key1 = 2 AND key2 = 2"))) - self.assertEqual(ft2['name'], 'Rose') - self.assertEqual(ft2['name2'], 'Apple') - self.assertEqual(ft2['pk'], 2) + ft2 = next( + vl.getFeatures( + QgsFeatureRequest().setFilterExpression("key1 = 2 AND key2 = 2") + ) + ) + self.assertEqual(ft2["name"], "Rose") + self.assertEqual(ft2["name2"], "Apple") + self.assertEqual(ft2["pk"], 2) # now, start editing one of the PK field components vl.startEditing() - self.assertTrue(vl.dataProvider().changeFeatures({ft2.id(): {idx_key2: 42, idx_name: 'Orchid', idx_name2: 'Daisy'}}, {ft2.id(): QgsGeometry.fromWkt(geomwkt)})) + self.assertTrue( + vl.dataProvider().changeFeatures( + {ft2.id(): {idx_key2: 42, idx_name: "Orchid", idx_name2: "Daisy"}}, + {ft2.id(): QgsGeometry.fromWkt(geomwkt)}, + ) + ) self.assertTrue(vl.commitChanges()) # let's check if we still have the same fid... ft2 = next(vl.getFeatures(QgsFeatureRequest().setFilterFid(ft2.id()))) - self.assertEqual(ft2['key2'], 42) - self.assertEqual(ft2['name'], 'Orchid') - self.assertEqual(ft2['name2'], 'Daisy') + self.assertEqual(ft2["key2"], 42) + self.assertEqual(ft2["name"], "Orchid") + self.assertEqual(ft2["name2"], "Daisy") self.assertTrue(vl.startEditing()) - vl.changeAttributeValues(ft2.id(), {idx_key1: 21, idx_name2: 'Hibiscus'}) + vl.changeAttributeValues(ft2.id(), {idx_key1: 21, idx_name2: "Hibiscus"}) self.assertTrue(vl.commitChanges()) ft2 = next(vl.getFeatures(QgsFeatureRequest().setFilterFid(ft2.id()))) - self.assertEqual(ft2['key1'], 21) - self.assertEqual(ft2['name2'], 'Hibiscus') + self.assertEqual(ft2["key1"], 21) + self.assertEqual(ft2["name2"], "Hibiscus") # lets get a brand new feature and check how it went... - ft3 = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression('pk = 2'))) - self.assertEqual(ft3['name'], 'Orchid') - self.assertEqual(ft3['key1'], 21) - self.assertEqual(ft3['key2'], 42) + ft3 = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk = 2"))) + self.assertEqual(ft3["name"], "Orchid") + self.assertEqual(ft3["key1"], 21) + self.assertEqual(ft3["key2"], 42) - assert compareWkt(ft3.geometry().asWkt(), geomwkt), f"Geometry mismatch. Expected: {ft3.geometry().asWkt()} Got: {geomwkt}\n" + assert compareWkt( + ft3.geometry().asWkt(), geomwkt + ), f"Geometry mismatch. Expected: {ft3.geometry().asWkt()} Got: {geomwkt}\n" # Now, we leave the record as we found it, so further tests can proceed vl.startEditing() - self.assertTrue(vl.dataProvider().changeFeatures({ft3.id(): {idx_key1: 2, idx_key2: 2, idx_pk: 2, idx_name: 'Apple', idx_name2: 'Apple'}}, {ft3.id(): QgsGeometry.fromWkt(original_geometry)})) + self.assertTrue( + vl.dataProvider().changeFeatures( + { + ft3.id(): { + idx_key1: 2, + idx_key2: 2, + idx_pk: 2, + idx_name: "Apple", + idx_name2: "Apple", + } + }, + {ft3.id(): QgsGeometry.fromWkt(original_geometry)}, + ) + ) self.assertTrue(vl.commitChanges()) @@ -3645,36 +4698,43 @@ class TestPyQgsPostgresProviderBigintSinglePk(QgisTestCase, ProviderTestCase): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsPostgresProviderBigintSinglePk, cls).setUpClass() - cls.dbconn = 'service=qgis_test' - if 'QGIS_PGTEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_PGTEST_DB'] + super().setUpClass() + cls.dbconn = "service=qgis_test" + if "QGIS_PGTEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_PGTEST_DB"] # Create test layers cls.vl = QgsVectorLayer( - cls.dbconn + - ' sslmode=disable key=\'"pk"\' srid=4326 type=POINT table="qgis_test"."provider_bigint_single_pk" (geom) sql=', - 'bigint_pk', 'postgres') + cls.dbconn + + ' sslmode=disable key=\'"pk"\' srid=4326 type=POINT table="qgis_test"."provider_bigint_single_pk" (geom) sql=', + "bigint_pk", + "postgres", + ) assert cls.vl.isValid() cls.source = cls.vl.dataProvider() cls.con = psycopg2.connect(cls.dbconn) def getSource(self): - """ drops/recreates the test data anew, like TestPyQgsPostgresProvider::getSource above. """ + """drops/recreates the test data anew, like TestPyQgsPostgresProvider::getSource above.""" self.execSqlCommand( - "DROP TABLE IF EXISTS qgis_test.provider_edit_bigint_single_pk") + "DROP TABLE IF EXISTS qgis_test.provider_edit_bigint_single_pk" + ) self.execSqlCommand( - "CREATE TABLE qgis_test.provider_edit_bigint_single_pk ( pk bigserial PRIMARY KEY, cnt integer, name text DEFAULT 'qgis', name2 text DEFAULT 'qgis', num_char text, dt timestamp without time zone, \"date\" date, \"time\" time without time zone, geom public.geometry(Point,4326), key1 integer, key2 integer)") + "CREATE TABLE qgis_test.provider_edit_bigint_single_pk ( pk bigserial PRIMARY KEY, cnt integer, name text DEFAULT 'qgis', name2 text DEFAULT 'qgis', num_char text, dt timestamp without time zone, \"date\" date, \"time\" time without time zone, geom public.geometry(Point,4326), key1 integer, key2 integer)" + ) self.execSqlCommand( - "INSERT INTO qgis_test.provider_edit_bigint_single_pk ( key1, key2, pk, cnt, name, name2, num_char, dt, \"date\", \"time\", geom) VALUES" + 'INSERT INTO qgis_test.provider_edit_bigint_single_pk ( key1, key2, pk, cnt, name, name2, num_char, dt, "date", "time", geom) VALUES' "(1, 1, 5, -200, NULL, 'NuLl', '5', TIMESTAMP '2020-05-04 12:13:14', '2020-05-02', '12:13:01', '0101000020E61000001D5A643BDFC751C01F85EB51B88E5340')," "(1, 2, 3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL, NULL)," "(2, 1, 1, 100, 'Orange', 'oranGe', '1', TIMESTAMP '2020-05-03 12:13:14', '2020-05-03', '12:13:14', '0101000020E61000006891ED7C3F9551C085EB51B81E955040')," "(2, 2, 2, 200, 'Apple', 'Apple', '2', TIMESTAMP '2020-05-04 12:14:14', '2020-05-04', '12:14:14', '0101000020E6100000CDCCCCCCCC0C51C03333333333B35140')," - "(2, 3, 4, 400, 'Honey', 'Honey', '4', TIMESTAMP '2021-05-04 13:13:14', '2021-05-04', '13:13:14', '0101000020E610000014AE47E17A5450C03333333333935340')") + "(2, 3, 4, 400, 'Honey', 'Honey', '4', TIMESTAMP '2021-05-04 13:13:14', '2021-05-04', '13:13:14', '0101000020E610000014AE47E17A5450C03333333333935340')" + ) vl = QgsVectorLayer( - self.dbconn + - ' sslmode=disable key=\'"pk"\' srid=4326 type=POINT table="qgis_test"."provider_edit_bigint_single_pk" (geom) sql=', - 'edit_bigint_pk', 'postgres') + self.dbconn + + ' sslmode=disable key=\'"pk"\' srid=4326 type=POINT table="qgis_test"."provider_edit_bigint_single_pk" (geom) sql=', + "edit_bigint_pk", + "postgres", + ) return vl def getEditableLayer(self): @@ -3689,16 +4749,18 @@ def execSqlCommand(self, sql): self.con.commit() def enableCompiler(self): - QgsSettings().setValue('/qgis/compileExpressions', True) + QgsSettings().setValue("/qgis/compileExpressions", True) return True def disableCompiler(self): - QgsSettings().setValue('/qgis/compileExpressions', False) + QgsSettings().setValue("/qgis/compileExpressions", False) def uncompiledFilters(self): - return {'"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')', - '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')', - '"time" = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')'} + return { + "\"dt\" = to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy')", + "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')", + "\"time\" = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')", + } def partiallyCompiledFilters(self): return set() @@ -3709,18 +4771,22 @@ def testConstraints(self): def testGetFeaturesFidTests(self): fids = [f.id() for f in self.source.getFeatures()] - assert len(fids) == 5, f'Expected 5 features, got {len(fids)} instead' + assert len(fids) == 5, f"Expected 5 features, got {len(fids)} instead" for id in fids: - features = [f for f in self.source.getFeatures( - QgsFeatureRequest().setFilterFid(id))] + features = [ + f for f in self.source.getFeatures(QgsFeatureRequest().setFilterFid(id)) + ] self.assertEqual(len(features), 1) feature = features[0] self.assertTrue(feature.isValid()) result = [feature.id()] expected = [id] - assert result == expected, 'Expected {} and got {} when testing for feature ID filter'.format(expected, - result) + assert ( + result == expected + ), "Expected {} and got {} when testing for feature ID filter".format( + expected, result + ) # test that results match QgsFeatureRequest.acceptFeature request = QgsFeatureRequest().setFilterFid(id) @@ -3730,9 +4796,15 @@ def testGetFeaturesFidTests(self): # TODO: bad features are not tested because the PostgreSQL provider # doesn't mark explicitly set invalid features as such. - def testGetFeatures(self, source=None, extra_features=[], skip_features=[], changed_attributes={}, - changed_geometries={}): - """ Test that expected results are returned when fetching all features """ + def testGetFeatures( + self, + source=None, + extra_features=[], + skip_features=[], + changed_attributes={}, + changed_geometries={}, + ): + """Test that expected results are returned when fetching all features""" # IMPORTANT - we do not use `for f in source.getFeatures()` as we are also # testing that existing attributes & geometry in f are overwritten correctly @@ -3750,26 +4822,30 @@ def testGetFeatures(self, source=None, extra_features=[], skip_features=[], chan self.assertTrue(f.isValid()) # some source test datasets will include additional attributes which we ignore, # so cherry pick desired attributes - attrs = [f['pk'], f['cnt'], f['name'], f['name2'], f['num_char']] + attrs = [f["pk"], f["cnt"], f["name"], f["name2"], f["num_char"]] # DON'T force the num_char attribute to be text - some sources (e.g., delimited text) will # automatically detect that this attribute contains numbers and set it as a numeric # field # TODO: PostgreSQL 12 won't accept conversion from integer to text. # attrs[4] = str(attrs[4]) - attributes[f['pk']] = attrs - geometries[f['pk']] = f.hasGeometry() and f.geometry().asWkt() - - expected_attributes = {5: [5, -200, NULL, 'NuLl', '5'], - 3: [3, 300, 'Pear', 'PEaR', '3'], - 1: [1, 100, 'Orange', 'oranGe', '1'], - 2: [2, 200, 'Apple', 'Apple', '2'], - 4: [4, 400, 'Honey', 'Honey', '4']} - - expected_geometries = {1: 'Point (-70.332 66.33)', - 2: 'Point (-68.2 70.8)', - 3: None, - 4: 'Point(-65.32 78.3)', - 5: 'Point(-71.123 78.23)'} + attributes[f["pk"]] = attrs + geometries[f["pk"]] = f.hasGeometry() and f.geometry().asWkt() + + expected_attributes = { + 5: [5, -200, NULL, "NuLl", "5"], + 3: [3, 300, "Pear", "PEaR", "3"], + 1: [1, 100, "Orange", "oranGe", "1"], + 2: [2, 200, "Apple", "Apple", "2"], + 4: [4, 400, "Honey", "Honey", "4"], + } + + expected_geometries = { + 1: "Point (-70.332 66.33)", + 2: "Point (-68.2 70.8)", + 3: None, + 4: "Point(-65.32 78.3)", + 5: "Point(-71.123 78.23)", + } for f in extra_features: expected_attributes[f[0]] = f.attributes() if f.hasGeometry(): @@ -3783,62 +4859,79 @@ def testGetFeatures(self, source=None, extra_features=[], skip_features=[], chan for i, a in changed_attributes.items(): for attr_idx, v in a.items(): expected_attributes[i][attr_idx] = v - for i, g, in changed_geometries.items(): + for ( + i, + g, + ) in changed_geometries.items(): if g: expected_geometries[i] = g.asWkt() else: expected_geometries[i] = None - self.assertEqual(attributes, expected_attributes, 'Expected {}, got {}'.format( - expected_attributes, attributes)) + self.assertEqual( + attributes, + expected_attributes, + f"Expected {expected_attributes}, got {attributes}", + ) self.assertEqual(len(expected_geometries), len(geometries)) for pk, geom in list(expected_geometries.items()): if geom: - assert compareWkt(geom, geometries[pk]), "Geometry {} mismatch Expected:\n{}\nGot:\n{}\n".format(pk, - geom, - geometries[ - pk]) + assert compareWkt( + geom, geometries[pk] + ), "Geometry {} mismatch Expected:\n{}\nGot:\n{}\n".format( + pk, geom, geometries[pk] + ) else: - self.assertFalse( - geometries[pk], f'Expected null geometry for {pk}') + self.assertFalse(geometries[pk], f"Expected null geometry for {pk}") def testAddFeatureExtraAttributes(self): - if not getattr(self, 'getEditableLayer', None): + if not getattr(self, "getEditableLayer", None): return l = self.getEditableLayer() self.assertTrue(l.isValid()) - if not l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures: + if ( + not l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.AddFeatures + ): return # test that adding features with too many attributes drops these attributes # we be more tricky and also add a valid feature to stress test the provider f1 = QgsFeature() - f1.setAttributes([6, -220, 'qgis', 'String', '15']) + f1.setAttributes([6, -220, "qgis", "String", "15"]) f2 = QgsFeature() - f2.setAttributes([7, -230, 'qgis', 'String', '15', 15, 16, 17]) + f2.setAttributes([7, -230, "qgis", "String", "15", 15, 16, 17]) result, added = l.dataProvider().addFeatures([f1, f2]) - self.assertTrue(result, - 'Provider returned False to addFeatures with extra attributes. Providers should accept these features but truncate the extra attributes.') + self.assertTrue( + result, + "Provider returned False to addFeatures with extra attributes. Providers should accept these features but truncate the extra attributes.", + ) # make sure feature was added correctly - added = [f for f in l.dataProvider().getFeatures() if f['pk'] == 7][0] + added = [f for f in l.dataProvider().getFeatures() if f["pk"] == 7][0] # TODO: The PostgreSQL provider doesn't truncate extra attributes! - self.assertNotEqual(added.attributes(), [7, -230, 'qgis', 'String', '15'], - 'The PostgreSQL provider doesn\'t truncate extra attributes.') + self.assertNotEqual( + added.attributes(), + [7, -230, "qgis", "String", "15"], + "The PostgreSQL provider doesn't truncate extra attributes.", + ) def testAddFeatureMissingAttributes(self): - if not getattr(self, 'getEditableLayer', None): + if not getattr(self, "getEditableLayer", None): return l = self.getEditableLayer() self.assertTrue(l.isValid()) - if not l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures: + if ( + not l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.AddFeatures + ): return # test that adding features with missing attributes pads out these @@ -3850,23 +4943,25 @@ def testAddFeatureMissingAttributes(self): # that is indicated, or the value mentioned by the user; there is no # implicit conversion of PyQGIS::NULL to PostgreSQL DEFAULT. f1 = QgsFeature() - f1.setAttributes([6, -220, 'qgis', 'String']) + f1.setAttributes([6, -220, "qgis", "String"]) f2 = QgsFeature() f2.setAttributes([7, 330]) result, added = l.dataProvider().addFeatures([f1, f2]) - self.assertTrue(result, - 'Provider returned False to addFeatures with missing attributes. Providers should accept these features but add NULL attributes to the end of the existing attributes to the required field length.') + self.assertTrue( + result, + "Provider returned False to addFeatures with missing attributes. Providers should accept these features but add NULL attributes to the end of the existing attributes to the required field length.", + ) f1.setId(added[0].id()) f2.setId(added[1].id()) # check result - feature attributes MUST be padded out to required number of fields - f1.setAttributes([6, -220, 'qgis', 'String', NULL]) - f2.setAttributes([7, 330, 'qgis', 'qgis', NULL]) + f1.setAttributes([6, -220, "qgis", "String", NULL]) + f2.setAttributes([7, 330, "qgis", "qgis", NULL]) self.testGetFeatures(l.dataProvider(), [f1, f2]) def testAddFeature(self): - if not getattr(self, 'getEditableLayer', None): + if not getattr(self, "getEditableLayer", None): return l = self.getEditableLayer() @@ -3879,17 +4974,22 @@ def testAddFeature(self): # value; if the attribute is present, the saved value will be NULL if # that is indicated, or the value mentioned by the user; there is no # implicit conversion of PyQGIS::NULL to PostgreSQL DEFAULT. - f1.setAttributes([6, -220, 'qgis', 'String', '15']) - f1.setGeometry(QgsGeometry.fromWkt('Point (-72.345 71.987)')) + f1.setAttributes([6, -220, "qgis", "String", "15"]) + f1.setGeometry(QgsGeometry.fromWkt("Point (-72.345 71.987)")) f2 = QgsFeature() - f2.setAttributes([7, 330, 'Coconut', 'CoCoNut', '13']) + f2.setAttributes([7, 330, "Coconut", "CoCoNut", "13"]) - if l.dataProvider().capabilities() & QgsVectorDataProvider.Capability.AddFeatures: + if ( + l.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.AddFeatures + ): # expect success result, added = l.dataProvider().addFeatures([f1, f2]) self.assertTrue( - result, 'Provider reported AddFeatures capability, but returned False to addFeatures') + result, + "Provider reported AddFeatures capability, but returned False to addFeatures", + ) f1.setId(added[0].id()) f2.setId(added[1].id()) @@ -3900,46 +5000,60 @@ def testAddFeature(self): self.assertTrue(l.dataProvider().addFeatures([])) # ensure that returned features have been given the correct id - f = next(l.getFeatures( - QgsFeatureRequest().setFilterFid(added[0].id()))) + f = next(l.getFeatures(QgsFeatureRequest().setFilterFid(added[0].id()))) self.assertTrue(f.isValid()) - self.assertEqual(f['cnt'], -220) + self.assertEqual(f["cnt"], -220) - f = next(l.getFeatures( - QgsFeatureRequest().setFilterFid(added[1].id()))) + f = next(l.getFeatures(QgsFeatureRequest().setFilterFid(added[1].id()))) self.assertTrue(f.isValid()) - self.assertEqual(f['cnt'], 330) + self.assertEqual(f["cnt"], 330) else: # expect fail - self.assertFalse(l.dataProvider().addFeatures([f1, f2]), - 'Provider reported no AddFeatures capability, but returned true to addFeatures') + self.assertFalse( + l.dataProvider().addFeatures([f1, f2]), + "Provider reported no AddFeatures capability, but returned true to addFeatures", + ) def testModifyPk(self): - """ Check if we can modify a primary key value. Since this PK is bigint, we also exercise the mapping between fid and values """ + """Check if we can modify a primary key value. Since this PK is bigint, we also exercise the mapping between fid and values""" vl = self.getEditableLayer() self.assertTrue(vl.isValid()) - geomwkt = 'Point(-47.945 -15.812)' + geomwkt = "Point(-47.945 -15.812)" - feature = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression('pk = 4'))) + feature = next( + vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk = 4")) + ) self.assertTrue(feature.isValid()) self.assertTrue(vl.startEditing()) - idxpk = vl.fields().lookupField('pk') + idxpk = vl.fields().lookupField("pk") - self.assertTrue(vl.dataProvider().changeFeatures({feature.id(): {idxpk: 42}}, {feature.id(): QgsGeometry.fromWkt(geomwkt)})) + self.assertTrue( + vl.dataProvider().changeFeatures( + {feature.id(): {idxpk: 42}}, + {feature.id(): QgsGeometry.fromWkt(geomwkt)}, + ) + ) self.assertTrue(vl.commitChanges()) # read back - ft = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression('pk = 42'))) + ft = next(vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk = 42"))) self.assertTrue(ft.isValid()) - self.assertEqual(ft['name'], 'Honey') - assert compareWkt(ft.geometry().asWkt(), geomwkt), f"Geometry mismatch. Expected: {ft.geometry().asWkt()} Got: {geomwkt}\n" + self.assertEqual(ft["name"], "Honey") + assert compareWkt( + ft.geometry().asWkt(), geomwkt + ), f"Geometry mismatch. Expected: {ft.geometry().asWkt()} Got: {geomwkt}\n" def testDuplicatedFieldNamesInQueryLayers(self): """Test regresssion GH #36205""" - vl = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'__rid__\' table="(SELECT row_number() OVER () AS __rid__, * FROM (SELECT * from qgis_test.some_poly_data a, qgis_test.some_poly_data b where ST_Intersects(a.geom,b.geom)) as foo)" sql=', 'test_36205', 'postgres') + vl = QgsVectorLayer( + self.dbconn + + " sslmode=disable key='__rid__' table=\"(SELECT row_number() OVER () AS __rid__, * FROM (SELECT * from qgis_test.some_poly_data a, qgis_test.some_poly_data b where ST_Intersects(a.geom,b.geom)) as foo)\" sql=", + "test_36205", + "postgres", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 3) @@ -3957,70 +5071,113 @@ def testUnrestrictedGeometryType(self): # Cleanup if needed try: - conn.dropVectorTable('qgis_test', 'test_unrestricted_geometry') + conn.dropVectorTable("qgis_test", "test_unrestricted_geometry") except QgsProviderConnectionException: pass - conn.executeSql(''' + conn.executeSql( + """ CREATE TABLE "qgis_test"."test_unrestricted_geometry" ( gid serial primary key, geom geometry(Geometry, 4326) - );''') + );""" + ) - points = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'gid\' srid=4326 type=POINT table="qgis_test"."test_unrestricted_geometry" (geom) sql=', 'test_points', 'postgres') - lines = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'gid\' srid=4326 type=LINESTRING table="qgis_test"."test_unrestricted_geometry" (geom) sql=', 'test_lines', 'postgres') - polygons = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'gid\' srid=4326 type=POLYGON table="qgis_test"."test_unrestricted_geometry" (geom) sql=', 'test_polygons', 'postgres') + points = QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'gid\' srid=4326 type=POINT table="qgis_test"."test_unrestricted_geometry" (geom) sql=', + "test_points", + "postgres", + ) + lines = QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'gid\' srid=4326 type=LINESTRING table="qgis_test"."test_unrestricted_geometry" (geom) sql=', + "test_lines", + "postgres", + ) + polygons = QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'gid\' srid=4326 type=POLYGON table="qgis_test"."test_unrestricted_geometry" (geom) sql=', + "test_polygons", + "postgres", + ) self.assertTrue(points.isValid()) self.assertTrue(lines.isValid()) self.assertTrue(polygons.isValid()) f = QgsFeature(points.fields()) - f.setGeometry(QgsGeometry.fromWkt('point(9 45)')) + f.setGeometry(QgsGeometry.fromWkt("point(9 45)")) self.assertTrue(points.dataProvider().addFeatures([f])) self.assertEqual(points.featureCount(), 1) self.assertEqual(lines.featureCount(), 0) self.assertEqual(polygons.featureCount(), 0) # Fetch from iterator - self.assertTrue(compareWkt(next(points.getFeatures()).geometry().asWkt(), 'point(9 45)')) + self.assertTrue( + compareWkt(next(points.getFeatures()).geometry().asWkt(), "point(9 45)") + ) with self.assertRaises(StopIteration): next(lines.getFeatures()) with self.assertRaises(StopIteration): next(polygons.getFeatures()) - f.setGeometry(QgsGeometry.fromWkt('linestring(9 45, 10 46)')) + f.setGeometry(QgsGeometry.fromWkt("linestring(9 45, 10 46)")) self.assertTrue(lines.dataProvider().addFeatures([f])) self.assertEqual(points.featureCount(), 1) self.assertEqual(lines.featureCount(), 1) self.assertEqual(polygons.featureCount(), 0) # Fetch from iterator - self.assertTrue(compareWkt(next(points.getFeatures()).geometry().asWkt(), 'point(9 45)')) - self.assertTrue(compareWkt(next(lines.getFeatures()).geometry().asWkt(), 'linestring(9 45, 10 46)')) + self.assertTrue( + compareWkt(next(points.getFeatures()).geometry().asWkt(), "point(9 45)") + ) + self.assertTrue( + compareWkt( + next(lines.getFeatures()).geometry().asWkt(), "linestring(9 45, 10 46)" + ) + ) with self.assertRaises(StopIteration): next(polygons.getFeatures()) # Test regression GH #38567 (no SRID requested in the data source URI) # Cleanup if needed - conn.executeSql('DELETE FROM "qgis_test"."test_unrestricted_geometry" WHERE \'t\'') + conn.executeSql( + 'DELETE FROM "qgis_test"."test_unrestricted_geometry" WHERE \'t\'' + ) - points = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'gid\' type=POINT table="qgis_test"."test_unrestricted_geometry" (geom) sql=', 'test_points', 'postgres') - lines = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'gid\' type=LINESTRING table="qgis_test"."test_unrestricted_geometry" (geom) sql=', 'test_lines', 'postgres') - polygons = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'gid\' type=POLYGON table="qgis_test"."test_unrestricted_geometry" (geom) sql=', 'test_polygons', 'postgres') + points = QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'gid\' type=POINT table="qgis_test"."test_unrestricted_geometry" (geom) sql=', + "test_points", + "postgres", + ) + lines = QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'gid\' type=LINESTRING table="qgis_test"."test_unrestricted_geometry" (geom) sql=', + "test_lines", + "postgres", + ) + polygons = QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'gid\' type=POLYGON table="qgis_test"."test_unrestricted_geometry" (geom) sql=', + "test_polygons", + "postgres", + ) self.assertTrue(points.isValid()) self.assertTrue(lines.isValid()) self.assertTrue(polygons.isValid()) def test_read_wkb(self): - """ Test to read WKB from Postgis. """ + """Test to read WKB from Postgis.""" md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.dbconn, {}) results = conn.executeSql("SELECT ST_AsBinary(ST_MakePoint(5, 10));") wkb = results[0][0] geom = QgsGeometry() import binascii + geom.fromWkb(binascii.unhexlify(wkb[2:])) self.assertEqual(geom.asWkt(), "Point (5 10)") @@ -4028,9 +5185,11 @@ def testTrustFlag(self): """Test regression https://github.com/qgis/QGIS/issues/38809""" vl = QgsVectorLayer( - self.dbconn + - ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."editData" (geom) sql=', - 'testTrustFlag', 'postgres') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."editData" (geom) sql=', + "testTrustFlag", + "postgres", + ) self.assertTrue(vl.isValid()) @@ -4039,14 +5198,14 @@ def testTrustFlag(self): dir_path = d.path() self.assertTrue(p.addMapLayers([vl])) - project_path = os.path.join(dir_path, 'testTrustFlag.qgs') + project_path = os.path.join(dir_path, "testTrustFlag.qgs") self.assertTrue(p.write(project_path)) del vl p.clear() self.assertTrue(p.read(project_path)) - vl = p.mapLayersByName('testTrustFlag')[0] + vl = p.mapLayersByName("testTrustFlag")[0] self.assertTrue(vl.isValid()) self.assertFalse(p.trustLayerMetadata()) @@ -4058,7 +5217,7 @@ def testTrustFlag(self): p.clear() self.assertTrue(p.read(project_path)) self.assertTrue(p.trustLayerMetadata()) - vl = p.mapLayersByName('testTrustFlag')[0] + vl = p.mapLayersByName("testTrustFlag")[0] self.assertTrue(vl.isValid()) def testQueryLayerDuplicatedFields(self): @@ -4066,35 +5225,49 @@ def testQueryLayerDuplicatedFields(self): def _get_layer(sql): return QgsVectorLayer( - self.dbconn + - ' sslmode=disable key=\'__rid__\' table=\'(SELECT row_number() OVER () AS __rid__, * FROM (' + sql + ') as foo)\' sql=', - 'test', 'postgres') - - l = _get_layer('SELECT 1, 2') + self.dbconn + + " sslmode=disable key='__rid__' table='(SELECT row_number() OVER () AS __rid__, * FROM (" + + sql + + ") as foo)' sql=", + "test", + "postgres", + ) + + l = _get_layer("SELECT 1, 2") self.assertEqual(l.fields().count(), 3) - self.assertEqual([f.name() for f in l.fields()], ['__rid__', '?column?', '?column? (2)']) + self.assertEqual( + [f.name() for f in l.fields()], ["__rid__", "?column?", "?column? (2)"] + ) - l = _get_layer('SELECT 1 as id, 2 as id') + l = _get_layer("SELECT 1 as id, 2 as id") self.assertEqual(l.fields().count(), 3) - self.assertEqual([f.name() for f in l.fields()], ['__rid__', 'id', 'id (2)']) + self.assertEqual([f.name() for f in l.fields()], ["__rid__", "id", "id (2)"]) def testInsertOnlyFieldIsEditable(self): """Test issue #40922 when an INSERT only use cannot insert a new feature""" md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.dbconn, {}) - conn.executeSql('DROP TABLE IF EXISTS public.insert_only_points') - conn.executeSql('DROP USER IF EXISTS insert_only_user') - conn.executeSql('CREATE USER insert_only_user WITH PASSWORD \'insert_only_user\'') - conn.executeSql('CREATE TABLE insert_only_points (id SERIAL PRIMARY KEY, name VARCHAR(64))') - conn.executeSql("SELECT AddGeometryColumn('public', 'insert_only_points', 'geom', 4326, 'POINT', 2 )") - conn.executeSql('GRANT SELECT ON "public"."insert_only_points" TO insert_only_user') - - uri = QgsDataSourceUri(self.dbconn + - ' sslmode=disable key=\'id\'srid=4326 type=POINT table="public"."insert_only_points" (geom) sql=') - uri.setUsername('insert_only_user') - uri.setPassword('insert_only_user') - vl = QgsVectorLayer(uri.uri(), 'test', 'postgres') + conn.executeSql("DROP TABLE IF EXISTS public.insert_only_points") + conn.executeSql("DROP USER IF EXISTS insert_only_user") + conn.executeSql("CREATE USER insert_only_user WITH PASSWORD 'insert_only_user'") + conn.executeSql( + "CREATE TABLE insert_only_points (id SERIAL PRIMARY KEY, name VARCHAR(64))" + ) + conn.executeSql( + "SELECT AddGeometryColumn('public', 'insert_only_points', 'geom', 4326, 'POINT', 2 )" + ) + conn.executeSql( + 'GRANT SELECT ON "public"."insert_only_points" TO insert_only_user' + ) + + uri = QgsDataSourceUri( + self.dbconn + + ' sslmode=disable key=\'id\'srid=4326 type=POINT table="public"."insert_only_points" (geom) sql=' + ) + uri.setUsername("insert_only_user") + uri.setPassword("insert_only_user") + vl = QgsVectorLayer(uri.uri(), "test", "postgres") self.assertTrue(vl.isValid()) self.assertFalse(vl.startEditing()) @@ -4102,8 +5275,10 @@ def testInsertOnlyFieldIsEditable(self): self.assertFalse(QgsVectorLayerUtils.fieldIsEditable(vl, 0, feature)) self.assertFalse(QgsVectorLayerUtils.fieldIsEditable(vl, 1, feature)) - conn.executeSql('GRANT INSERT ON "public"."insert_only_points" TO insert_only_user') - vl = QgsVectorLayer(uri.uri(), 'test', 'postgres') + conn.executeSql( + 'GRANT INSERT ON "public"."insert_only_points" TO insert_only_user' + ) + vl = QgsVectorLayer(uri.uri(), "test", "postgres") feature = QgsFeature(vl.fields()) self.assertTrue(vl.startEditing()) @@ -4116,13 +5291,19 @@ def testPkeyIntArray(self): """ md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.dbconn, {}) - conn.executeSql('DROP TABLE IF EXISTS public.test_pkey_intarray') - conn.executeSql('CREATE TABLE public.test_pkey_intarray (id _int8 PRIMARY KEY, name VARCHAR(64))') - conn.executeSql("""INSERT INTO public.test_pkey_intarray (id, name) VALUES('{0,0,19111815}', 'test')""") + conn.executeSql("DROP TABLE IF EXISTS public.test_pkey_intarray") + conn.executeSql( + "CREATE TABLE public.test_pkey_intarray (id _int8 PRIMARY KEY, name VARCHAR(64))" + ) + conn.executeSql( + """INSERT INTO public.test_pkey_intarray (id, name) VALUES('{0,0,19111815}', 'test')""" + ) - uri = QgsDataSourceUri(self.dbconn + - ' sslmode=disable key=\'id\' table="public"."test_pkey_intarray" sql=') - vl = QgsVectorLayer(uri.uri(), 'test', 'postgres') + uri = QgsDataSourceUri( + self.dbconn + + ' sslmode=disable key=\'id\' table="public"."test_pkey_intarray" sql=' + ) + vl = QgsVectorLayer(uri.uri(), "test", "postgres") self.assertTrue(vl.isValid()) feat = next(vl.getFeatures()) @@ -4142,75 +5323,109 @@ def testExportPkGuessLogic(self): md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.dbconn, {}) conn.executeSql( - 'DROP TABLE IF EXISTS qgis_test."testExportPkGuessLogic_source" CASCADE') + 'DROP TABLE IF EXISTS qgis_test."testExportPkGuessLogic_source" CASCADE' + ) conn.executeSql( - 'DROP TABLE IF EXISTS qgis_test."testExportPkGuessLogic_exported" CASCADE') + 'DROP TABLE IF EXISTS qgis_test."testExportPkGuessLogic_exported" CASCADE' + ) conn.executeSql( """CREATE TABLE qgis_test."testExportPkGuessLogic_source" ( id bigint generated always as identity primary key, geom geometry(Point, 4326) check (st_isvalid(geom)), - name text unique, author text not null)""") + name text unique, author text not null)""" + ) - source_layer = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'id\' srid=4326 type=POINT table="qgis_test"."testExportPkGuessLogic_source" (geom) sql=', 'testExportPkGuessLogic_source', 'postgres') + source_layer = QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'id\' srid=4326 type=POINT table="qgis_test"."testExportPkGuessLogic_source" (geom) sql=', + "testExportPkGuessLogic_source", + "postgres", + ) - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.dbconn, {}) table = conn.table("qgis_test", "testExportPkGuessLogic_source") - self.assertEqual(table.primaryKeyColumns(), ['id']) + self.assertEqual(table.primaryKeyColumns(), ["id"]) self.assertTrue(source_layer.isValid()) # Create the URI as the browser does (no PK information) - uri = self.dbconn + ' sslmode=disable srid=4326 type=POINT table="qgis_test"."testExportPkGuessLogic_exported" (geom) sql=' + uri = ( + self.dbconn + + ' sslmode=disable srid=4326 type=POINT table="qgis_test"."testExportPkGuessLogic_exported" (geom) sql=' + ) - exporter = QgsVectorLayerExporter(uri, 'postgres', source_layer.fields(), source_layer.wkbType(), source_layer.crs(), True, {}) + exporter = QgsVectorLayerExporter( + uri, + "postgres", + source_layer.fields(), + source_layer.wkbType(), + source_layer.crs(), + True, + {}, + ) self.assertFalse(exporter.lastError()) - exported_layer = QgsVectorLayer(self.dbconn + ' sslmode=disable srid=4326 type=POINT table="qgis_test"."testExportPkGuessLogic_exported" (geom) sql=', 'testExportPkGuessLogic_exported', 'postgres') + exported_layer = QgsVectorLayer( + self.dbconn + + ' sslmode=disable srid=4326 type=POINT table="qgis_test"."testExportPkGuessLogic_exported" (geom) sql=', + "testExportPkGuessLogic_exported", + "postgres", + ) self.assertTrue(exported_layer.isValid()) table = conn.table("qgis_test", "testExportPkGuessLogic_exported") - self.assertEqual(table.primaryKeyColumns(), ['id']) + self.assertEqual(table.primaryKeyColumns(), ["id"]) - self.assertEqual(exported_layer.fields().names(), ['id', 'name', 'author']) + self.assertEqual(exported_layer.fields().names(), ["id", "name", "author"]) def testEwkt(self): - vl = QgsVectorLayer(f'{self.dbconn} table="qgis_test"."someData" sql=', "someData", "postgres") + vl = QgsVectorLayer( + f'{self.dbconn} table="qgis_test"."someData" sql=', "someData", "postgres" + ) tg = QgsTransactionGroup() tg.addLayer(vl) feature = next(vl.getFeatures()) # make sure we get a QgsReferenceGeometry and not "just" a string - self.assertEqual(feature['geom'].crs().authid(), 'EPSG:4326') + self.assertEqual(feature["geom"].crs().authid(), "EPSG:4326") vl.startEditing() # Layer accepts a referenced geometry - feature['geom'] = QgsReferencedGeometry(QgsGeometry.fromWkt('POINT(70 70)'), QgsCoordinateReferenceSystem.fromEpsgId(4326)) + feature["geom"] = QgsReferencedGeometry( + QgsGeometry.fromWkt("POINT(70 70)"), + QgsCoordinateReferenceSystem.fromEpsgId(4326), + ) self.assertTrue(vl.updateFeature(feature)) # Layer will accept null geometry - feature['geom'] = QgsReferencedGeometry() + feature["geom"] = QgsReferencedGeometry() self.assertTrue(vl.updateFeature(feature)) # Layer will not accept invalid crs - feature['geom'] = QgsReferencedGeometry(QgsGeometry.fromWkt('POINT(1 1)'), QgsCoordinateReferenceSystem()) + feature["geom"] = QgsReferencedGeometry( + QgsGeometry.fromWkt("POINT(1 1)"), QgsCoordinateReferenceSystem() + ) self.assertFalse(vl.updateFeature(feature)) # EWKT strings are accepted too - feature['geom'] = 'SRID=4326;Point (71 78)' + feature["geom"] = "SRID=4326;Point (71 78)" self.assertTrue(vl.updateFeature(feature)) # addFeature - feature['pk'] = 8 + feature["pk"] = 8 self.assertTrue(vl.addFeature(feature)) # changeAttributeValue - geom = QgsReferencedGeometry(QgsGeometry.fromWkt('POINT(3 3)'), QgsCoordinateReferenceSystem.fromEpsgId(4326)) + geom = QgsReferencedGeometry( + QgsGeometry.fromWkt("POINT(3 3)"), + QgsCoordinateReferenceSystem.fromEpsgId(4326), + ) - feature['pk'] = 8 + feature["pk"] = 8 self.assertTrue(vl.changeAttributeValue(8, 8, geom)) - self.assertEqual(vl.getFeature(8)['geom'].asWkt(), geom.asWkt()) - self.assertEqual(vl.getFeature(8)['geom'].crs(), geom.crs()) + self.assertEqual(vl.getFeature(8)["geom"].asWkt(), geom.asWkt()) + self.assertEqual(vl.getFeature(8)["geom"].crs(), geom.crs()) class TestPyQgsPostgresProviderAsyncCreation(QgisTestCase): @@ -4218,21 +5433,29 @@ class TestPyQgsPostgresProviderAsyncCreation(QgisTestCase): @classmethod def setUpClass(cls): """Run before all tests""" - cls.dbconn = 'service=qgis_test' - if 'QGIS_PGTEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_PGTEST_DB'] + cls.dbconn = "service=qgis_test" + if "QGIS_PGTEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_PGTEST_DB"] # Create test layers vl1 = QgsVectorLayer( - cls.dbconn + ' sslmode=disable srid=4326 type=POINT table="qgis_test"."b31799_test_table" (geom) sql=', - 'layer 1', 'postgres') + cls.dbconn + + ' sslmode=disable srid=4326 type=POINT table="qgis_test"."b31799_test_table" (geom) sql=', + "layer 1", + "postgres", + ) vl2 = QgsVectorLayer( - cls.dbconn + ' sslmode=disable srid=3857 type=POINT table="qgis_test"."array_tbl" (geom) sql=', 'layer 2', - 'postgres') + cls.dbconn + + ' sslmode=disable srid=3857 type=POINT table="qgis_test"."array_tbl" (geom) sql=', + "layer 2", + "postgres", + ) cls.layers = [vl1, vl2] cls.con = psycopg2.connect(cls.dbconn) - cls.projectTempFile = QTemporaryFile(QDir.temp().absoluteFilePath("XXXXXX_test.qgs")) + cls.projectTempFile = QTemporaryFile( + QDir.temp().absoluteFilePath("XXXXXX_test.qgs") + ) cls.projectTempFile.open() @classmethod @@ -4253,7 +5476,9 @@ def testReadProject(self): self.assertTrue(project.write(self.projectTempFile.fileName())) - settings = QgsSettingsTree.node('core').childSetting('provider-parallel-loading') + settings = QgsSettingsTree.node("core").childSetting( + "provider-parallel-loading" + ) self.assertTrue(settings is not None) current_value = settings.valueAsVariant() settings.setVariantValue(True) @@ -4273,5 +5498,5 @@ def testReadProject(self): settings.setVariantValue(current_value) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_provider_postgres_latency.py b/tests/src/python/test_provider_postgres_latency.py index 707a24e62a09..82c823e2fdb8 100644 --- a/tests/src/python/test_provider_postgres_latency.py +++ b/tests/src/python/test_provider_postgres_latency.py @@ -12,9 +12,9 @@ """ -__author__ = 'Daryna Dyka' -__date__ = '2021-06-13' -__copyright__ = 'Copyright 2021, The QGIS Project' +__author__ = "Daryna Dyka" +__date__ = "2021-06-13" +__copyright__ = "Copyright 2021, The QGIS Project" import os import time @@ -43,29 +43,29 @@ class TestPyQgsPostgresProviderLatency(QgisTestCase): def setUpClass(cls): """Run before all tests""" super().setUpClass() - cls.dbconn = 'service=qgis_test' - if 'QGIS_PGTEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_PGTEST_DB'] + cls.dbconn = "service=qgis_test" + if "QGIS_PGTEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_PGTEST_DB"] cls.con = psycopg2.connect(cls.dbconn) @classmethod def tearDownClass(cls): """Run after all tests""" - os.system('tc qdisc del dev eth0 root') + os.system("tc qdisc del dev eth0 root") super().tearDownClass() def setDelay(self, delay_in_ms): if delay_in_ms == 0: - os.system('tc qdisc del dev eth0 root') + os.system("tc qdisc del dev eth0 root") else: - os.system(f'tc qdisc add dev eth0 root netem delay {delay_in_ms}ms') + os.system(f"tc qdisc add dev eth0 root netem delay {delay_in_ms}ms") def getDelay(self): self.assertTrue(self.con) cur = self.con.cursor() self.assertTrue(cur) start_time = time.time() - cur.execute('SELECT 1;') + cur.execute("SELECT 1;") duration = round(1000 * abs(time.time() - start_time), 1) cur.close() self.con.commit() @@ -91,9 +91,13 @@ def testStatsSetDelayToDB(self): self.setDelay(delay_ms) delay_get[delay_ms] = self.getDelay() self.setDelay(0) - delay_delta[delay_ms] = round(delay_get[delay_ms] / 2.0 - delay_set[delay_ms], 1) + delay_delta[delay_ms] = round( + delay_get[delay_ms] / 2.0 - delay_set[delay_ms], 1 + ) - self.assertTrue(False, f'\nset: {delay_set}\nget: {delay_get}\nget/2 - set: {delay_delta}') + self.assertTrue( + False, f"\nset: {delay_set}\nget: {delay_get}\nget/2 - set: {delay_delta}" + ) def testSetDelayToDB(self): """Test Set delay to remote DB""" @@ -101,12 +105,16 @@ def testSetDelayToDB(self): self.setDelay(100) delay_get = self.getDelay() / 2 self.setDelay(0) - self.assertTrue(delay_get > 90 and delay_get < 110, f'set delay to 100ms - unsuccessful (got: {delay_get}ms)') + self.assertTrue( + delay_get > 90 and delay_get < 110, + f"set delay to 100ms - unsuccessful (got: {delay_get}ms)", + ) def testSaveChangedGeometryToDB(self): """Test Save geometries to remote DB""" - self.execSQLCommand(''' + self.execSQLCommand( + """ DROP TABLE IF EXISTS qgis_test.speed_test_remote_db CASCADE; CREATE TABLE qgis_test.speed_test_remote_db ( id_serial serial NOT NULL, @@ -119,12 +127,15 @@ def testSaveChangedGeometryToDB(self): 3396830.0 6521870.0,3396830.0 6521800.0,3396900.0 6521800.0))\', 3857 ), 100.0 * dx, 100.0 * dy ) - FROM generate_series(1,42) dx, generate_series(1,42) dy;''') + FROM generate_series(1,42) dx, generate_series(1,42) dy;""" + ) set_new_layer = ' sslmode=disable key=\'id_serial\' srid=3857 type=POLYGON table="qgis_test"."speed_test_remote_db" (geom) sql=' - error_string = 'Save geoms to remote DB : expected < 10s, got {}s' + error_string = "Save geoms to remote DB : expected < 10s, got {}s" - vl = QgsVectorLayer(self.dbconn + set_new_layer, 'test_vl_remote_save', 'postgres') + vl = QgsVectorLayer( + self.dbconn + set_new_layer, "test_vl_remote_save", "postgres" + ) # fids = [f.id() for f in vl.getFeatures(QgsFeatureRequest().setLimit(1000))] fids = [f.id() for f in vl.getFeatures(QgsFeatureRequest().setLimit(50))] self.assertTrue(vl.startEditing()) @@ -139,27 +150,41 @@ def testSaveChangedGeometryToDB(self): self.assertTrue(duration < 10, error_string.format(duration)) def testProjectOpenTime(self): - """ open project, provider-parallel-loading = False """ + """open project, provider-parallel-loading = False""" - projectFile = QTemporaryFile(QDir.temp().absoluteFilePath("testProjectOpenTime.qgz")) + projectFile = QTemporaryFile( + QDir.temp().absoluteFilePath("testProjectOpenTime.qgz") + ) projectFile.open() project = QgsProject() set_new_layer = ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=' - project.addMapLayer(QgsVectorLayer(self.dbconn + set_new_layer, 'test_vl_01', 'postgres')) - project.addMapLayer(QgsVectorLayer(self.dbconn + set_new_layer, 'test_vl_02', 'postgres')) - project.addMapLayer(QgsVectorLayer(self.dbconn + set_new_layer, 'test_vl_03', 'postgres')) - project.addMapLayer(QgsVectorLayer(self.dbconn + set_new_layer, 'test_vl_04', 'postgres')) - project.addMapLayer(QgsVectorLayer(self.dbconn + set_new_layer, 'test_vl_05', 'postgres')) + project.addMapLayer( + QgsVectorLayer(self.dbconn + set_new_layer, "test_vl_01", "postgres") + ) + project.addMapLayer( + QgsVectorLayer(self.dbconn + set_new_layer, "test_vl_02", "postgres") + ) + project.addMapLayer( + QgsVectorLayer(self.dbconn + set_new_layer, "test_vl_03", "postgres") + ) + project.addMapLayer( + QgsVectorLayer(self.dbconn + set_new_layer, "test_vl_04", "postgres") + ) + project.addMapLayer( + QgsVectorLayer(self.dbconn + set_new_layer, "test_vl_05", "postgres") + ) self.assertTrue(project.write(projectFile.fileName())) - settings = QgsSettingsTree.node('core').childSetting('provider-parallel-loading') + settings = QgsSettingsTree.node("core").childSetting( + "provider-parallel-loading" + ) settings.setVariantValue(False) davg = 7.61 dmin = round(davg - 0.2, 2) dmax = round(davg + 0.3, 2) - error_string = 'expected from {0}s to {1}s, got {2}s\nHINT: set davg={2} to pass the test :)' + error_string = "expected from {0}s to {1}s, got {2}s\nHINT: set davg={2} to pass the test :)" project = QgsProject() self.setDelay(100) @@ -167,8 +192,11 @@ def testProjectOpenTime(self): self.assertTrue(project.read(projectFile.fileName())) duration = round(abs(time.time() - start_time), 2) self.setDelay(0) - self.assertTrue(duration > dmin and duration < dmax, error_string.format(dmin, dmax, duration)) + self.assertTrue( + duration > dmin and duration < dmax, + error_string.format(dmin, dmax, duration), + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_provider_postgresraster.py b/tests/src/python/test_provider_postgresraster.py index 607e1dbd59c8..940429c60a18 100644 --- a/tests/src/python/test_provider_postgresraster.py +++ b/tests/src/python/test_provider_postgresraster.py @@ -14,9 +14,9 @@ """ -__author__ = 'Alessandro Pasotti' -__date__ = '2019-12-20' -__copyright__ = 'Copyright 2019, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "2019-12-20" +__copyright__ = "Copyright 2019, The QGIS Project" import os import time @@ -53,48 +53,55 @@ class TestPyQgsPostgresRasterProvider(QgisTestCase): def _load_test_table(cls, schemaname, tablename, basename=None): postgres_conn = cls.dbconn + " sslmode=disable " - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(postgres_conn, {}) if basename is None: basename = tablename if tablename not in [n.tableName() for n in conn.tables(schemaname)]: - with open(os.path.join(TEST_DATA_DIR, 'provider', 'postgresraster', basename + '.sql')) as f: + with open( + os.path.join( + TEST_DATA_DIR, "provider", "postgresraster", basename + ".sql" + ) + ) as f: sql = f.read() conn.executeSql(sql) - assert (tablename in [n.tableName() for n in conn.tables( - schemaname)]), tablename + ' not found!' + assert tablename in [n.tableName() for n in conn.tables(schemaname)], ( + tablename + " not found!" + ) @classmethod def setUpClass(cls): """Run before all tests""" super().setUpClass() cls.iface = get_iface() - cls.dbconn = 'service=qgis_test' - if 'QGIS_PGTEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_PGTEST_DB'] - - cls._load_test_table('public', 'raster_tiled_3035') - cls._load_test_table('public', 'raster_3035_no_constraints') - cls._load_test_table('public', 'raster_3035_tiled_no_overviews') - cls._load_test_table('public', 'raster_3035_tiled_no_pk') - cls._load_test_table('public', 'raster_3035_tiled_composite_pk') - cls._load_test_table('public', 'raster_3035_untiled_multiple_rows') - cls._load_test_table('idro', 'cosmo_i5_snow', 'bug_34823_pg_raster') - cls._load_test_table( - 'public', 'int16_regression_36689', 'bug_36689_pg_raster') - cls._load_test_table('public', 'bug_37968_dem_linear_cdn_extract') - cls._load_test_table('public', 'bug_39017_untiled_no_metadata') - cls._load_test_table('public', 'raster_sparse_3035') + cls.dbconn = "service=qgis_test" + if "QGIS_PGTEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_PGTEST_DB"] + + cls._load_test_table("public", "raster_tiled_3035") + cls._load_test_table("public", "raster_3035_no_constraints") + cls._load_test_table("public", "raster_3035_tiled_no_overviews") + cls._load_test_table("public", "raster_3035_tiled_no_pk") + cls._load_test_table("public", "raster_3035_tiled_composite_pk") + cls._load_test_table("public", "raster_3035_untiled_multiple_rows") + cls._load_test_table("idro", "cosmo_i5_snow", "bug_34823_pg_raster") + cls._load_test_table("public", "int16_regression_36689", "bug_36689_pg_raster") + cls._load_test_table("public", "bug_37968_dem_linear_cdn_extract") + cls._load_test_table("public", "bug_39017_untiled_no_metadata") + cls._load_test_table("public", "raster_sparse_3035") # Fix timing issues in backend # time.sleep(1) # Create test layer cls.rl = QgsRasterLayer( - cls.dbconn + ' sslmode=disable key=\'rid\' srid=3035 table="public"."raster_tiled_3035" sql=', 'test', - 'postgresraster') + cls.dbconn + + ' sslmode=disable key=\'rid\' srid=3035 table="public"."raster_tiled_3035" sql=', + "test", + "postgresraster", + ) assert cls.rl.isValid() cls.source = cls.rl.dataProvider() @@ -104,61 +111,86 @@ def gdal_block_compare(self, rlayer, band, extent, width, height, value): uri = rlayer.uri() gdal_uri = "PG: dbname={dbname} mode=2 host={host} port={port} table={table} schema={schema} sslmode=disable".format( **{ - 'dbname': uri.database(), - 'host': uri.host(), - 'port': uri.port(), - 'table': uri.table(), - 'schema': uri.schema() - }) + "dbname": uri.database(), + "host": uri.host(), + "port": uri.port(), + "table": uri.table(), + "schema": uri.schema(), + } + ) gdal_rl = QgsRasterLayer(gdal_uri, "rl", "gdal") self.assertTrue(gdal_rl.isValid()) - self.assertEqual(value, gdal_rl.dataProvider().block( - band, self.rl.extent(), 6, 5).data().toHex()) + self.assertEqual( + value, + gdal_rl.dataProvider().block(band, self.rl.extent(), 6, 5).data().toHex(), + ) def testExtent(self): extent = self.rl.extent() - self.assertEqual(extent, QgsRectangle( - 4080050, 2430625, 4080200, 2430750)) + self.assertEqual(extent, QgsRectangle(4080050, 2430625, 4080200, 2430750)) def testSize(self): self.assertEqual(self.source.xSize(), 6) self.assertEqual(self.source.ySize(), 5) def testCrs(self): - self.assertEqual(self.source.crs().authid(), 'EPSG:3035') + self.assertEqual(self.source.crs().authid(), "EPSG:3035") def testGetData(self): - identify = self.source.identify(QgsPointXY( - 4080137.9, 2430687.9), QgsRaster.IdentifyFormat.IdentifyFormatValue) + identify = self.source.identify( + QgsPointXY(4080137.9, 2430687.9), + QgsRaster.IdentifyFormat.IdentifyFormatValue, + ) expected = 192.51044 self.assertAlmostEqual(identify.results()[1], expected, 4) def testGetDataFromSparse(self): """Test issue GH #55753""" rl = QgsRasterLayer( - self.dbconn + " sslmode=disable table={table} schema={schema}".format( - table='raster_sparse_3035', schema='public'), 'pg_layer', 'postgresraster') + self.dbconn + + " sslmode=disable table={table} schema={schema}".format( + table="raster_sparse_3035", schema="public" + ), + "pg_layer", + "postgresraster", + ) self.assertTrue(rl.isValid()) - self.assertTrue(compareWkt(rl.extent().asWktPolygon( - ), 'POLYGON((4080050 2430625, 4080326 2430625, 4080326 2430855, 4080050 2430855, 4080050 2430625))', 0.01)) + self.assertTrue( + compareWkt( + rl.extent().asWktPolygon(), + "POLYGON((4080050 2430625, 4080326 2430625, 4080326 2430855, 4080050 2430855, 4080050 2430625))", + 0.01, + ) + ) app_log = QgsApplication.messageLog() log_spy = QSignalSpy(app_log.messageReceived) # Identify pixel from area not containing data - identify = rl.dataProvider().identify(QgsPointXY( - 4080320, 2430854), QgsRaster.IdentifyFormat.IdentifyFormatValue) + identify = rl.dataProvider().identify( + QgsPointXY(4080320, 2430854), QgsRaster.IdentifyFormat.IdentifyFormatValue + ) self.assertEqual(identify.results()[1], -9999) - postgis_warning_logs = list(filter(lambda log: log[2] == Qgis.MessageLevel.Warning and log[1] == "PostGIS", list(log_spy))) + postgis_warning_logs = list( + filter( + lambda log: log[2] == Qgis.MessageLevel.Warning and log[1] == "PostGIS", + list(log_spy), + ) + ) # TODO: there is still NOTICE: row number 0 is out of range 0..-1 warning... - conversion_logs = list(filter(lambda log: "Cannot convert identified value" in log[0], postgis_warning_logs)) + conversion_logs = list( + filter( + lambda log: "Cannot convert identified value" in log[0], + postgis_warning_logs, + ) + ) self.assertEqual(len(conversion_logs), 0, list(conversion_logs)) def testBlockTiled(self): - expected = b'6a610843880b0e431cc2194306342543b7633c43861858436e0a1143bbad194359612743a12b334317be4343dece59432b621b43f0e42843132b3843ac824043e6cf48436e465a435c4d2d430fa63d43f87a4843b5494a4349454e4374f35b43906e41433ab54c43b056504358575243b1ec574322615f43' + expected = b"6a610843880b0e431cc2194306342543b7633c43861858436e0a1143bbad194359612743a12b334317be4343dece59432b621b43f0e42843132b3843ac824043e6cf48436e465a435c4d2d430fa63d43f87a4843b5494a4349454e4374f35b43906e41433ab54c43b056504358575243b1ec574322615f43" block = self.source.block(1, self.rl.extent(), 6, 5) actual = block.data().toHex() self.assertEqual(len(actual), len(expected)) @@ -168,94 +200,146 @@ def testNoConstraintRaster(self): """Read unconstrained raster layer""" rl = QgsRasterLayer( - self.dbconn + ' sslmode=disable key=\'pk\' srid=3035 table="public"."raster_3035_no_constraints" sql=', - 'test', 'postgresraster') + self.dbconn + + ' sslmode=disable key=\'pk\' srid=3035 table="public"."raster_3035_no_constraints" sql=', + "test", + "postgresraster", + ) self.assertTrue(rl.isValid()) def testPkGuessing(self): """Read raster layer with no pkey in uri""" - rl = QgsRasterLayer(self.dbconn + ' sslmode=disable srid=3035 table="public"."raster_tiled_3035" sql=', 'test', - 'postgresraster') + rl = QgsRasterLayer( + self.dbconn + + ' sslmode=disable srid=3035 table="public"."raster_tiled_3035" sql=', + "test", + "postgresraster", + ) self.assertTrue(rl.isValid()) def testWhereCondition(self): """Read raster layer with where condition""" rl_nowhere = QgsRasterLayer( - self.dbconn + ' sslmode=disable srid=3035 table="public"."raster_3035_tiled_no_overviews"' + - 'sql=', 'test', 'postgresraster') + self.dbconn + + ' sslmode=disable srid=3035 table="public"."raster_3035_tiled_no_overviews"' + + "sql=", + "test", + "postgresraster", + ) self.assertTrue(rl_nowhere.isValid()) rl = QgsRasterLayer( - self.dbconn + ' sslmode=disable srid=3035 table="public"."raster_3035_tiled_no_overviews"' + - 'sql="category" = \'cat2\'', 'test', 'postgresraster') + self.dbconn + + ' sslmode=disable srid=3035 table="public"."raster_3035_tiled_no_overviews"' + + "sql=\"category\" = 'cat2'", + "test", + "postgresraster", + ) self.assertTrue(rl.isValid()) self.assertTrue(not rl.extent().isEmpty()) self.assertNotEqual(rl_nowhere.extent(), rl.extent()) self.assertIsNone( - rl.dataProvider().identify(QgsPointXY(4080137.9, 2430687.9), QgsRaster.IdentifyFormat.IdentifyFormatValue).results()[1]) - self.assertIsNotNone(rl_nowhere.dataProvider().identify(QgsPointXY(4080137.9, 2430687.9), - QgsRaster.IdentifyFormat.IdentifyFormatValue).results()[1]) + rl.dataProvider() + .identify( + QgsPointXY(4080137.9, 2430687.9), + QgsRaster.IdentifyFormat.IdentifyFormatValue, + ) + .results()[1] + ) + self.assertIsNotNone( + rl_nowhere.dataProvider() + .identify( + QgsPointXY(4080137.9, 2430687.9), + QgsRaster.IdentifyFormat.IdentifyFormatValue, + ) + .results()[1] + ) self.assertAlmostEqual( - rl.dataProvider().identify(rl.extent().center(), QgsRaster.IdentifyFormat.IdentifyFormatValue).results()[1], 223.38, 2) + rl.dataProvider() + .identify( + rl.extent().center(), QgsRaster.IdentifyFormat.IdentifyFormatValue + ) + .results()[1], + 223.38, + 2, + ) - self.assertTrue(compareWkt(rl_nowhere.extent().asWktPolygon(), - 'POLYGON((4080050 2430625, 4080200 2430625, 4080200 2430750, 4080050 2430750, 4080050 2430625))')) + self.assertTrue( + compareWkt( + rl_nowhere.extent().asWktPolygon(), + "POLYGON((4080050 2430625, 4080200 2430625, 4080200 2430750, 4080050 2430750, 4080050 2430625))", + ) + ) - self.assertTrue(compareWkt(rl.extent().asWktPolygon(), - 'POLYGON((4080150 2430625, 4080200 2430625, 4080200 2430650, 4080150 2430650, 4080150 2430625))')) + self.assertTrue( + compareWkt( + rl.extent().asWktPolygon(), + "POLYGON((4080150 2430625, 4080200 2430625, 4080200 2430650, 4080150 2430650, 4080150 2430625))", + ) + ) self.assertNotEqual(rl.extent(), rl_nowhere.extent()) # Now check if setSubsetString updates the extent - self.assertTrue(rl_nowhere.setSubsetString('"category" = \'cat2\'')) + self.assertTrue(rl_nowhere.setSubsetString("\"category\" = 'cat2'")) self.assertEqual(rl.extent(), rl_nowhere.extent()) def testNoPk(self): """Read raster with no PK""" - rl = QgsRasterLayer(self.dbconn + ' sslmode=disable srid=3035 table="public"."raster_3035_tiled_no_pk"' + - 'sql=', 'test', 'postgresraster') + rl = QgsRasterLayer( + self.dbconn + + ' sslmode=disable srid=3035 table="public"."raster_3035_tiled_no_pk"' + + "sql=", + "test", + "postgresraster", + ) self.assertTrue(rl.isValid()) def testCompositeKey(self): """Read raster with composite pks""" rl = QgsRasterLayer( - self.dbconn + ' sslmode=disable srid=3035 table="public"."raster_3035_tiled_composite_pk"' + - 'sql=', 'test', 'postgresraster') + self.dbconn + + ' sslmode=disable srid=3035 table="public"."raster_3035_tiled_composite_pk"' + + "sql=", + "test", + "postgresraster", + ) self.assertTrue(rl.isValid()) data = rl.dataProvider().block(1, rl.extent(), 3, 3) self.assertEqual(int(data.value(0, 0)), 142) - @unittest.skip('Performance test is disabled in Travis environment') + @unittest.skip("Performance test is disabled in Travis environment") def testSpeed(self): """Compare speed with GDAL provider, this test was used during development""" conn = "user={user} host=localhost port=5432 password={password} dbname={speed_db} ".format( - user=os.environ.get('USER'), - password=os.environ.get('USER'), - speed_db='qgis_test' + user=os.environ.get("USER"), + password=os.environ.get("USER"), + speed_db="qgis_test", ) - table = 'basic_map_tiled' - schema = 'public' + table = "basic_map_tiled" + schema = "public" def _speed_check(schema, table, width, height): - print('-' * 80) + print("-" * 80) print(f"Testing: {schema}.{table}") - print('-' * 80) + print("-" * 80) # GDAL start = time.time() rl = QgsRasterLayer( - "PG: " + conn + - f"table={table} mode=2 schema={schema}", 'gdal_layer', - 'gdal') + "PG: " + conn + f"table={table} mode=2 schema={schema}", + "gdal_layer", + "gdal", + ) self.assertTrue(rl.isValid()) # Make is smaller than full extent extent = rl.extent().buffered(-rl.extent().width() * 0.2) @@ -268,12 +352,13 @@ def _speed_check(schema, table, width, height): checkpoint_3 = time.time() print(f"Tiled GDAL second block time: {checkpoint_3 - checkpoint_2:.6f}") print(f"Total GDAL time: {checkpoint_3 - start:.6f}") - print('-' * 80) + print("-" * 80) # PG native start = time.time() - rl = QgsRasterLayer(conn + f"table={table} schema={schema}", 'gdal_layer', - 'postgresraster') + rl = QgsRasterLayer( + conn + f"table={table} schema={schema}", "gdal_layer", "postgresraster" + ) self.assertTrue(rl.isValid()) extent = rl.extent().buffered(-rl.extent().width() * 0.2) checkpoint_1 = time.time() @@ -285,7 +370,7 @@ def _speed_check(schema, table, width, height): checkpoint_3 = time.time() print(f"Tiled PG second block time: {checkpoint_3 - checkpoint_2:.6f}") print(f"Total PG time: {checkpoint_3 - start:.6f}") - print('-' * 80) + print("-" * 80) _speed_check(schema, table, 1000, 1000) @@ -295,16 +380,28 @@ def testOtherSchema(self): rl = QgsRasterLayer( self.dbconn + " sslmode=disable table=cosmo_i5_snow schema=idro", - 'pg_layer', 'postgresraster') + "pg_layer", + "postgresraster", + ) self.assertTrue(rl.isValid()) - self.assertTrue(compareWkt(rl.extent().asWktPolygon(), - 'POLYGON((-64.79286766849691048 -77.26689086732433509, -62.18292922825105506 -77.26689086732433509, -62.18292922825105506 -74.83694818157819384, -64.79286766849691048 -74.83694818157819384, -64.79286766849691048 -77.26689086732433509))')) + self.assertTrue( + compareWkt( + rl.extent().asWktPolygon(), + "POLYGON((-64.79286766849691048 -77.26689086732433509, -62.18292922825105506 -77.26689086732433509, -62.18292922825105506 -74.83694818157819384, -64.79286766849691048 -74.83694818157819384, -64.79286766849691048 -77.26689086732433509))", + ) + ) def testUntiledMultipleRows(self): """Test multiple rasters (one per row)""" - rl = QgsRasterLayer(self.dbconn + " sslmode=disable table={table} schema={schema} sql=\"pk\" = 1".format( - table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster') + rl = QgsRasterLayer( + self.dbconn + + ' sslmode=disable table={table} schema={schema} sql="pk" = 1'.format( + table="raster_3035_untiled_multiple_rows", schema="public" + ), + "pg_layer", + "postgresraster", + ) self.assertTrue(rl.isValid()) block = rl.dataProvider().block(1, rl.extent(), 2, 2) data = [] @@ -313,8 +410,14 @@ def testUntiledMultipleRows(self): data.append(int(block.value(i, j))) self.assertEqual(data, [136, 142, 145, 153]) - rl = QgsRasterLayer(self.dbconn + " sslmode=disable table={table} schema={schema} sql=\"pk\" = 2".format( - table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster') + rl = QgsRasterLayer( + self.dbconn + + ' sslmode=disable table={table} schema={schema} sql="pk" = 2'.format( + table="raster_3035_untiled_multiple_rows", schema="public" + ), + "pg_layer", + "postgresraster", + ) self.assertTrue(rl.isValid()) block = rl.dataProvider().block(1, rl.extent(), 2, 2) data = [] @@ -326,8 +429,14 @@ def testUntiledMultipleRows(self): def testSetSubsetString(self): """Test setSubsetString""" - rl = QgsRasterLayer(self.dbconn + " sslmode=disable table={table} schema={schema} sql=\"pk\" = 2".format( - table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster') + rl = QgsRasterLayer( + self.dbconn + + ' sslmode=disable table={table} schema={schema} sql="pk" = 2'.format( + table="raster_3035_untiled_multiple_rows", schema="public" + ), + "pg_layer", + "postgresraster", + ) self.assertTrue(rl.isValid()) block = rl.dataProvider().block(1, rl.extent(), 2, 2) @@ -338,7 +447,8 @@ def testSetSubsetString(self): self.assertEqual(data, [136, 142, 161, 169]) stats = rl.dataProvider().bandStatistics( - 1, QgsRasterBandStats.Stats.Min | QgsRasterBandStats.Stats.Max, rl.extent()) + 1, QgsRasterBandStats.Stats.Min | QgsRasterBandStats.Stats.Max, rl.extent() + ) self.assertEqual(int(stats.minimumValue), 136) self.assertEqual(int(stats.maximumValue), 169) @@ -357,7 +467,8 @@ def testSetSubsetString(self): # Check that we have new statistics stats = rl.dataProvider().bandStatistics( - 1, QgsRasterBandStats.Stats.Min | QgsRasterBandStats.Stats.Max, rl.extent()) + 1, QgsRasterBandStats.Stats.Min | QgsRasterBandStats.Stats.Max, rl.extent() + ) self.assertEqual(int(stats.minimumValue), 136) self.assertEqual(int(stats.maximumValue), 153) @@ -394,46 +505,76 @@ def _test_block(rl, expected_block, expected_single): # First check that setting different temporal default values we get different results rl = QgsRasterLayer( - self.dbconn + " sslmode=disable table={table} schema={schema} temporalDefaultTime='2020-04-01T00:00:00' temporalFieldIndex='1'".format( - table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster') + self.dbconn + + " sslmode=disable table={table} schema={schema} temporalDefaultTime='2020-04-01T00:00:00' temporalFieldIndex='1'".format( + table="raster_3035_untiled_multiple_rows", schema="public" + ), + "pg_layer", + "postgresraster", + ) self.assertEqual(rl.subsetString(), "") _test_block(rl, [136, 142, 145, 153], 153) rl = QgsRasterLayer( - self.dbconn + " sslmode=disable table={table} schema={schema} temporalDefaultTime='2020-04-05T00:00:00' temporalFieldIndex='1'".format( - table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster') + self.dbconn + + " sslmode=disable table={table} schema={schema} temporalDefaultTime='2020-04-05T00:00:00' temporalFieldIndex='1'".format( + table="raster_3035_untiled_multiple_rows", schema="public" + ), + "pg_layer", + "postgresraster", + ) self.assertEqual(rl.subsetString(), "") _test_block(rl, [136, 142, 161, 169], 169) # Check that manually setting a subsetString we get the same results rl = QgsRasterLayer( - self.dbconn + " sslmode=disable table={table} schema={schema} sql=\"data\" = '2020-04-01'".format( - table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster') - self.assertEqual(rl.subsetString(), '"data" = \'2020-04-01\'') + self.dbconn + + " sslmode=disable table={table} schema={schema} sql=\"data\" = '2020-04-01'".format( + table="raster_3035_untiled_multiple_rows", schema="public" + ), + "pg_layer", + "postgresraster", + ) + self.assertEqual(rl.subsetString(), "\"data\" = '2020-04-01'") _test_block(rl, [136, 142, 145, 153], 153) rl = QgsRasterLayer( - self.dbconn + " sslmode=disable table={table} schema={schema} sql=\"data\" = '2020-04-05'".format( - table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster') - self.assertEqual(rl.subsetString(), '"data" = \'2020-04-05\'') + self.dbconn + + " sslmode=disable table={table} schema={schema} sql=\"data\" = '2020-04-05'".format( + table="raster_3035_untiled_multiple_rows", schema="public" + ), + "pg_layer", + "postgresraster", + ) + self.assertEqual(rl.subsetString(), "\"data\" = '2020-04-05'") _test_block(rl, [136, 142, 161, 169], 169) # Now check if the varchar temporal field works the same rl = QgsRasterLayer( - self.dbconn + " sslmode=disable table={table} schema={schema} temporalDefaultTime='2020-04-01T00:00:00' temporalFieldIndex='2'".format( - table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster') - self.assertEqual(rl.subsetString(), '') + self.dbconn + + " sslmode=disable table={table} schema={schema} temporalDefaultTime='2020-04-01T00:00:00' temporalFieldIndex='2'".format( + table="raster_3035_untiled_multiple_rows", schema="public" + ), + "pg_layer", + "postgresraster", + ) + self.assertEqual(rl.subsetString(), "") _test_block(rl, [136, 142, 145, 153], 153) rl = QgsRasterLayer( - self.dbconn + " sslmode=disable table={table} schema={schema} temporalDefaultTime='2020-04-05T00:00:00' temporalFieldIndex='2'".format( - table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster') - self.assertEqual(rl.subsetString(), '') + self.dbconn + + " sslmode=disable table={table} schema={schema} temporalDefaultTime='2020-04-05T00:00:00' temporalFieldIndex='2'".format( + table="raster_3035_untiled_multiple_rows", schema="public" + ), + "pg_layer", + "postgresraster", + ) + self.assertEqual(rl.subsetString(), "") _test_block(rl, [136, 142, 161, 169], 169) @@ -444,53 +585,67 @@ def _round_trip(uri): decoded = md.decodeUri(uri) self.assertEqual(decoded, md.decodeUri(md.encodeUri(decoded))) - uri = self.dbconn + \ - ' sslmode=disable key=\'rid\' srid=3035 table="public"."raster_tiled_3035" sql=' - md = QgsProviderRegistry.instance().providerMetadata('postgresraster') + uri = ( + self.dbconn + + ' sslmode=disable key=\'rid\' srid=3035 table="public"."raster_tiled_3035" sql=' + ) + md = QgsProviderRegistry.instance().providerMetadata("postgresraster") decoded = md.decodeUri(uri) - self.assertEqual(decoded, { - 'key': 'rid', - 'schema': 'public', - 'service': 'qgis_test', - 'srid': '3035', - 'sslmode': QgsDataSourceUri.SslMode.SslDisable, - 'table': 'raster_tiled_3035', - }) + self.assertEqual( + decoded, + { + "key": "rid", + "schema": "public", + "service": "qgis_test", + "srid": "3035", + "sslmode": QgsDataSourceUri.SslMode.SslDisable, + "table": "raster_tiled_3035", + }, + ) _round_trip(uri) - uri = self.dbconn + \ - ' sslmode=prefer key=\'rid\' srid=3035 temporalFieldIndex=2 temporalDefaultTime=2020-03-02 ' + \ - 'authcfg=afebeff username=\'my username\' password=\'my secret password=\' ' + \ - 'enableTime=true table="public"."raster_tiled_3035" (rast) sql="a_field" != 1223223' + uri = ( + self.dbconn + + " sslmode=prefer key='rid' srid=3035 temporalFieldIndex=2 temporalDefaultTime=2020-03-02 " + + "authcfg=afebeff username='my username' password='my secret password=' " + + 'enableTime=true table="public"."raster_tiled_3035" (rast) sql="a_field" != 1223223' + ) _round_trip(uri) decoded = md.decodeUri(uri) - self.assertEqual(decoded, { - 'authcfg': 'afebeff', - 'enableTime': 'true', - 'geometrycolumn': 'rast', - 'key': 'rid', - 'password': 'my secret password=', - 'schema': 'public', - 'service': 'qgis_test', - 'sql': '"a_field" != 1223223', - 'srid': '3035', - 'sslmode': QgsDataSourceUri.SslMode.SslPrefer, - 'table': 'raster_tiled_3035', - 'temporalDefaultTime': - '2020-03-02', - 'temporalFieldIndex': '2', - 'username': 'my username', - }) + self.assertEqual( + decoded, + { + "authcfg": "afebeff", + "enableTime": "true", + "geometrycolumn": "rast", + "key": "rid", + "password": "my secret password=", + "schema": "public", + "service": "qgis_test", + "sql": '"a_field" != 1223223', + "srid": "3035", + "sslmode": QgsDataSourceUri.SslMode.SslPrefer, + "table": "raster_tiled_3035", + "temporalDefaultTime": "2020-03-02", + "temporalFieldIndex": "2", + "username": "my username", + }, + ) def testInt16(self): """Test regression https://github.com/qgis/QGIS/issues/36689""" rl = QgsRasterLayer( - self.dbconn + " sslmode=disable table={table} schema={schema}".format( - table='int16_regression_36689', schema='public'), 'pg_layer', 'postgresraster') + self.dbconn + + " sslmode=disable table={table} schema={schema}".format( + table="int16_regression_36689", schema="public" + ), + "pg_layer", + "postgresraster", + ) self.assertTrue(rl.isValid()) block = rl.dataProvider().block(1, rl.extent(), 6, 6) @@ -499,8 +654,47 @@ def testInt16(self): for j in range(6): data.append(int(block.value(i, j))) - self.assertEqual(data, [55, 52, 46, 39, 33, 30, 58, 54, 49, 45, 41, 37, 58, 54, 50, - 47, 45, 43, 54, 51, 49, 47, 46, 44, 47, 47, 47, 47, 46, 45, 41, 43, 45, 48, 49, 46]) + self.assertEqual( + data, + [ + 55, + 52, + 46, + 39, + 33, + 30, + 58, + 54, + 49, + 45, + 41, + 37, + 58, + 54, + 50, + 47, + 45, + 43, + 54, + 51, + 49, + 47, + 46, + 44, + 47, + 47, + 47, + 47, + 46, + 45, + 41, + 43, + 45, + 48, + 49, + 46, + ], + ) def testNegativeScaleY(self): """Test regression https://github.com/qgis/QGIS/issues/37968 @@ -508,51 +702,131 @@ def testNegativeScaleY(self): """ rl = QgsRasterLayer( - self.dbconn + " sslmode=disable table={table} schema={schema}".format( - table='bug_37968_dem_linear_cdn_extract', schema='public'), 'pg_layer', 'postgresraster') + self.dbconn + + " sslmode=disable table={table} schema={schema}".format( + table="bug_37968_dem_linear_cdn_extract", schema="public" + ), + "pg_layer", + "postgresraster", + ) self.assertTrue(rl.isValid()) - self.assertTrue(compareWkt(rl.extent().asWktPolygon( - ), 'POLYGON((-40953 170588, -40873 170588, -40873 170668, -40953 170668, -40953 170588))', 1)) + self.assertTrue( + compareWkt( + rl.extent().asWktPolygon(), + "POLYGON((-40953 170588, -40873 170588, -40873 170668, -40953 170668, -40953 170588))", + 1, + ) + ) block = rl.dataProvider().block(1, rl.extent(), 6, 6) data = [] for i in range(6): for j in range(6): data.append(int(block.value(i, j))) - self.assertEqual(data, [52, 52, 52, 52, 44, 43, 52, 52, 52, 48, 44, 44, 49, 52, 49, 44, 44, 44, 43, 47, 46, 44, 44, 44, 42, 42, 43, 44, 44, 48, 42, 43, 43, 44, 44, 47]) + self.assertEqual( + data, + [ + 52, + 52, + 52, + 52, + 44, + 43, + 52, + 52, + 52, + 48, + 44, + 44, + 49, + 52, + 49, + 44, + 44, + 44, + 43, + 47, + 46, + 44, + 44, + 44, + 42, + 42, + 43, + 44, + 44, + 48, + 42, + 43, + 43, + 44, + 44, + 47, + ], + ) def testUntiledMosaicNoMetadata(self): """Test regression https://github.com/qgis/QGIS/issues/39017 - +-----------+------------------------------+ - | | | - | rid = 1 | rid = 2 | - | | | - +-----------+------------------------------+ + +-----------+------------------------------+ + | | | + | rid = 1 | rid = 2 | + | | | + +-----------+------------------------------+ """ rl = QgsRasterLayer( - self.dbconn + " sslmode=disable table={table} schema={schema}".format( - table='bug_39017_untiled_no_metadata', schema='public'), 'pg_layer', 'postgresraster') + self.dbconn + + " sslmode=disable table={table} schema={schema}".format( + table="bug_39017_untiled_no_metadata", schema="public" + ), + "pg_layer", + "postgresraster", + ) self.assertTrue(rl.isValid()) - self.assertTrue(compareWkt(rl.extent().asWktPolygon( - ), 'POLYGON((47.061 40.976, 47.123 40.976, 47.123 41.000, 47.061 41.000, 47.061 40.976))', 0.01)) + self.assertTrue( + compareWkt( + rl.extent().asWktPolygon(), + "POLYGON((47.061 40.976, 47.123 40.976, 47.123 41.000, 47.061 41.000, 47.061 40.976))", + 0.01, + ) + ) rl1 = QgsRasterLayer( - self.dbconn + " sslmode=disable table={table} schema={schema} sql=\"rid\"=1".format( - table='bug_39017_untiled_no_metadata', schema='public'), 'pg_layer', 'postgresraster') + self.dbconn + + ' sslmode=disable table={table} schema={schema} sql="rid"=1'.format( + table="bug_39017_untiled_no_metadata", schema="public" + ), + "pg_layer", + "postgresraster", + ) self.assertTrue(rl1.isValid()) - self.assertTrue(compareWkt(rl1.extent().asWktPolygon( - ), 'POLYGON((47.061 40.976, 47.070 40.976, 47.070 41.000, 47.061 41.000, 47.061 40.976))', 0.01)) + self.assertTrue( + compareWkt( + rl1.extent().asWktPolygon(), + "POLYGON((47.061 40.976, 47.070 40.976, 47.070 41.000, 47.061 41.000, 47.061 40.976))", + 0.01, + ) + ) rl2 = QgsRasterLayer( - self.dbconn + " sslmode=disable table={table} schema={schema} sql=\"rid\"=2".format( - table='bug_39017_untiled_no_metadata', schema='public'), 'pg_layer', 'postgresraster') + self.dbconn + + ' sslmode=disable table={table} schema={schema} sql="rid"=2'.format( + table="bug_39017_untiled_no_metadata", schema="public" + ), + "pg_layer", + "postgresraster", + ) self.assertTrue(rl2.isValid()) - self.assertTrue(compareWkt(rl2.extent().asWktPolygon( - ), 'POLYGON((47.061 40.976, 47.123 40.976, 47.123 41.000, 47.070 41.000, 47.070 40.976))', 0.01)) + self.assertTrue( + compareWkt( + rl2.extent().asWktPolygon(), + "POLYGON((47.061 40.976, 47.123 40.976, 47.123 41.000, 47.070 41.000, 47.070 40.976))", + 0.01, + ) + ) extent_1 = rl1.extent() extent_2 = rl2.extent() @@ -577,8 +851,13 @@ def testView(self): """Test issue GH #50841""" rl = QgsRasterLayer( - self.dbconn + " key=\'rid\' srid=3035 sslmode=disable table={table} schema={schema}".format( - table='raster_tiled_3035_view', schema='public'), 'pg_layer', 'postgresraster') + self.dbconn + + " key='rid' srid=3035 sslmode=disable table={table} schema={schema}".format( + table="raster_tiled_3035_view", schema="public" + ), + "pg_layer", + "postgresraster", + ) self.assertTrue(rl.isValid()) @@ -586,7 +865,7 @@ def testSparseRaster(self): """Test issue GH #55753""" project: QgsProject = QgsProject.instance() canvas: QgsMapCanvas = self.iface.mapCanvas() - project.setCrs(QgsCoordinateReferenceSystem('EPSG:3035')) + project.setCrs(QgsCoordinateReferenceSystem("EPSG:3035")) canvas.setExtent(QgsRectangle(4080050, 2430625, 4080200, 2430750)) bridge = QgsLayerTreeMapCanvasBridge( # noqa: F841, this needs to be assigned @@ -594,11 +873,21 @@ def testSparseRaster(self): ) rl = QgsRasterLayer( - self.dbconn + " sslmode=disable table={table} schema={schema}".format( - table='raster_sparse_3035', schema='public'), 'pg_layer', 'postgresraster') + self.dbconn + + " sslmode=disable table={table} schema={schema}".format( + table="raster_sparse_3035", schema="public" + ), + "pg_layer", + "postgresraster", + ) self.assertTrue(rl.isValid()) - self.assertTrue(compareWkt(rl.extent().asWktPolygon( - ), 'POLYGON((4080050 2430625, 4080326 2430625, 4080326 2430855, 4080050 2430855, 4080050 2430625))', 0.01)) + self.assertTrue( + compareWkt( + rl.extent().asWktPolygon(), + "POLYGON((4080050 2430625, 4080326 2430625, 4080326 2430855, 4080050 2430855, 4080050 2430625))", + 0.01, + ) + ) app_log = QgsApplication.messageLog() log_spy = QSignalSpy(app_log.messageReceived) @@ -616,8 +905,13 @@ def testSparseRaster(self): project.removeMapLayer(rl.id()) rl2 = QgsRasterLayer( - self.dbconn + " sslmode=disable table={table} schema={schema}".format( - table='raster_sparse_3035', schema='public'), 'pg_layer', 'postgresraster') + self.dbconn + + " sslmode=disable table={table} schema={schema}".format( + table="raster_sparse_3035", schema="public" + ), + "pg_layer", + "postgresraster", + ) project.addMapLayer(rl2) for _ in range(zoom_times): @@ -626,21 +920,34 @@ def testSparseRaster(self): time.sleep(sleep_time) # Log should not contain any critical warnings - critical_postgis_logs = list(filter(lambda log: log[2] == Qgis.MessageLevel.Critical and log[1] == "PostGIS", list(log_spy))) + critical_postgis_logs = list( + filter( + lambda log: log[2] == Qgis.MessageLevel.Critical + and log[1] == "PostGIS", + list(log_spy), + ) + ) self.assertEqual(len(critical_postgis_logs), 0, list(log_spy)) def testSparseTiles(self): """Test issue GH #55784""" rl = QgsRasterLayer( - self.dbconn + " key=\'rid\' srid=3035 sslmode=disable table={table} schema={schema}".format( - table='raster_sparse_3035', schema='public'), 'pg_layer', 'postgresraster') + self.dbconn + + " key='rid' srid=3035 sslmode=disable table={table} schema={schema}".format( + table="raster_sparse_3035", schema="public" + ), + "pg_layer", + "postgresraster", + ) self.assertTrue(rl.isValid()) dp = rl.dataProvider() - r = dp.identify(QgsPointXY(4080317.72, 2430635.68), Qgis.RasterIdentifyFormat.Value).results() + r = dp.identify( + QgsPointXY(4080317.72, 2430635.68), Qgis.RasterIdentifyFormat.Value + ).results() self.assertEqual(r[1], -9999.0) # tile request returned no tiles, check nodata @@ -669,8 +976,13 @@ def testBlockSize(self): # untiled have blocksize == size rl = QgsRasterLayer( - self.dbconn + " sslmode=disable table={table} schema={schema} sql=\"pk\" = 2".format( - table='raster_3035_untiled_multiple_rows', schema='public'), 'pg_layer', 'postgresraster') + self.dbconn + + ' sslmode=disable table={table} schema={schema} sql="pk" = 2'.format( + table="raster_3035_untiled_multiple_rows", schema="public" + ), + "pg_layer", + "postgresraster", + ) self.assertTrue(rl.isValid()) @@ -683,8 +995,13 @@ def testBlockSize(self): # tiled have blocksize != size rl = QgsRasterLayer( - self.dbconn + " srid=3035 sslmode=disable table={table} schema={schema}".format( - table='raster_3035_tiled_no_overviews', schema='public'), 'pg_layer', 'postgresraster') + self.dbconn + + " srid=3035 sslmode=disable table={table} schema={schema}".format( + table="raster_3035_tiled_no_overviews", schema="public" + ), + "pg_layer", + "postgresraster", + ) self.assertTrue(rl.isValid()) @@ -696,5 +1013,5 @@ def testBlockSize(self): self.assertEqual(dp.yBlockSize(), 2) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_provider_python.py b/tests/src/python/test_provider_python.py index cb77d30547c0..f45bdf8129c0 100644 --- a/tests/src/python/test_provider_python.py +++ b/tests/src/python/test_provider_python.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '2018-03-18' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "2018-03-18" +__copyright__ = "Copyright 2018, The QGIS Project" # -*- coding: utf-8 -*- """QGIS Unit tests for the py layerprovider. @@ -19,9 +20,9 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Matthias Kuhn' -__date__ = '2015-04-23' -__copyright__ = 'Copyright 2015, The QGIS Project' +__author__ = "Matthias Kuhn" +__date__ = "2015-04-23" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, QTime, QVariant from qgis.core import ( @@ -56,28 +57,74 @@ class TestPyQgsPythonProvider(QgisTestCase, ProviderTestCase): @classmethod def createLayer(cls): vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk', - 'test', 'pythonprovider') - assert (vl.isValid()) + "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk", + "test", + "pythonprovider", + ) + assert vl.isValid() f1 = QgsFeature() - f1.setAttributes([5, -200, NULL, 'NuLl', '5', QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), QDate(2020, 5, 2), QTime(12, 13, 1)]) - f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)')) + f1.setAttributes( + [ + 5, + -200, + NULL, + "NuLl", + "5", + QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), + QDate(2020, 5, 2), + QTime(12, 13, 1), + ] + ) + f1.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)")) f2 = QgsFeature() - f2.setAttributes([3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL]) + f2.setAttributes([3, 300, "Pear", "PEaR", "3", NULL, NULL, NULL]) f3 = QgsFeature() - f3.setAttributes([1, 100, 'Orange', 'oranGe', '1', QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), QDate(2020, 5, 3), QTime(12, 13, 14)]) - f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)')) + f3.setAttributes( + [ + 1, + 100, + "Orange", + "oranGe", + "1", + QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), + QDate(2020, 5, 3), + QTime(12, 13, 14), + ] + ) + f3.setGeometry(QgsGeometry.fromWkt("Point (-70.332 66.33)")) f4 = QgsFeature() - f4.setAttributes([2, 200, 'Apple', 'Apple', '2', QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), QDate(2020, 5, 4), QTime(12, 14, 14)]) - f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)')) + f4.setAttributes( + [ + 2, + 200, + "Apple", + "Apple", + "2", + QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), + QDate(2020, 5, 4), + QTime(12, 14, 14), + ] + ) + f4.setGeometry(QgsGeometry.fromWkt("Point (-68.2 70.8)")) f5 = QgsFeature() - f5.setAttributes([4, 400, 'Honey', 'Honey', '4', QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), QDate(2021, 5, 4), QTime(13, 13, 14)]) - f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)')) + f5.setAttributes( + [ + 4, + 400, + "Honey", + "Honey", + "4", + QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), + QDate(2021, 5, 4), + QTime(13, 13, 14), + ] + ) + f5.setGeometry(QgsGeometry.fromWkt("Point (-65.32 78.3)")) vl.dataProvider().addFeatures([f1, f2, f3, f4, f5]) return vl @@ -85,35 +132,52 @@ def createLayer(cls): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsPythonProvider, cls).setUpClass() + super().setUpClass() # Register the provider r = QgsProviderRegistry.instance() - metadata = QgsProviderMetadata(PyProvider.providerKey(), PyProvider.description(), PyProvider.createProvider) + metadata = QgsProviderMetadata( + PyProvider.providerKey(), + PyProvider.description(), + PyProvider.createProvider, + ) assert r.registerProvider(metadata) assert r.providerMetadata(PyProvider.providerKey()) == metadata # Create test layer cls.vl = cls.createLayer() - assert (cls.vl.isValid()) + assert cls.vl.isValid() cls.source = cls.vl.dataProvider() # poly layer - cls.poly_vl = QgsVectorLayer('Polygon?crs=epsg:4326&field=pk:integer&key=pk', - 'test', 'pythonprovider') - assert (cls.poly_vl.isValid()) + cls.poly_vl = QgsVectorLayer( + "Polygon?crs=epsg:4326&field=pk:integer&key=pk", "test", "pythonprovider" + ) + assert cls.poly_vl.isValid() cls.poly_provider = cls.poly_vl.dataProvider() f1 = QgsFeature() f1.setAttributes([1]) - f1.setGeometry(QgsGeometry.fromWkt('Polygon ((-69.03664108 81.35818902, -69.09237722 80.24346619, -73.718477 80.1319939, -73.718477 76.28620011, -74.88893598 76.34193625, -74.83319983 81.35818902, -69.03664108 81.35818902))')) + f1.setGeometry( + QgsGeometry.fromWkt( + "Polygon ((-69.03664108 81.35818902, -69.09237722 80.24346619, -73.718477 80.1319939, -73.718477 76.28620011, -74.88893598 76.34193625, -74.83319983 81.35818902, -69.03664108 81.35818902))" + ) + ) f2 = QgsFeature() f2.setAttributes([2]) - f2.setGeometry(QgsGeometry.fromWkt('Polygon ((-67.58750139 81.1909806, -66.30557012 81.24671674, -66.30557012 76.89929767, -67.58750139 76.89929767, -67.58750139 81.1909806))')) + f2.setGeometry( + QgsGeometry.fromWkt( + "Polygon ((-67.58750139 81.1909806, -66.30557012 81.24671674, -66.30557012 76.89929767, -67.58750139 76.89929767, -67.58750139 81.1909806))" + ) + ) f3 = QgsFeature() f3.setAttributes([3]) - f3.setGeometry(QgsGeometry.fromWkt('Polygon ((-68.36780737 75.78457483, -67.53176524 72.60761475, -68.64648808 73.66660144, -70.20710006 72.9420316, -68.36780737 75.78457483))')) + f3.setGeometry( + QgsGeometry.fromWkt( + "Polygon ((-68.36780737 75.78457483, -67.53176524 72.60761475, -68.64648808 73.66660144, -70.20710006 72.9420316, -68.36780737 75.78457483))" + ) + ) f4 = QgsFeature() f4.setAttributes([4]) @@ -124,13 +188,13 @@ def getEditableLayer(self): return self.createLayer() def testGetFeaturesSubsetAttributes2(self): - """ Override and skip this test for pythonprovider provider, as it's actually more efficient for the pythonprovider provider to return + """Override and skip this test for pythonprovider provider, as it's actually more efficient for the pythonprovider provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass def testGetFeaturesNoGeometry(self): - """ Override and skip this test for pythonprovider provider, as it's actually more efficient for the pythonprovider provider to return + """Override and skip this test for pythonprovider provider, as it's actually more efficient for the pythonprovider provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass @@ -140,75 +204,199 @@ def testGetFeaturesDestinationCrs(self): super().testGetFeaturesDestinationCrs() def testCtors(self): - testVectors = ["Point", "LineString", "Polygon", "MultiPoint", "MultiLineString", "MultiPolygon", "None"] + testVectors = [ + "Point", + "LineString", + "Polygon", + "MultiPoint", + "MultiLineString", + "MultiPolygon", + "None", + ] for v in testVectors: layer = QgsVectorLayer(v, "test", "pythonprovider") assert layer.isValid(), f"Failed to create valid {v} pythonprovider layer" def testLayerGeometry(self): - testVectors = [("Point", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.Point), - ("LineString", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineString), - ("Polygon", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.Polygon), - ("MultiPoint", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPoint), - ("MultiLineString", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineString), - ("MultiPolygon", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygon), - ("PointZ", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointZ), - ("LineStringZ", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineStringZ), - ("PolygonZ", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.PolygonZ), - ("MultiPointZ", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPointZ), - ("MultiLineStringZ", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineStringZ), - ("MultiPolygonZ", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygonZ), - ("PointM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointM), - ("LineStringM", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineStringM), - ("PolygonM", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.PolygonM), - ("MultiPointM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPointM), - ("MultiLineStringM", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineStringM), - ("MultiPolygonM", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygonM), - ("PointZM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointZM), - ("LineStringZM", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineStringZM), - ("PolygonZM", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.PolygonZM), - ("MultiPointZM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPointZM), - ("MultiLineStringZM", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineStringZM), - ("MultiPolygonZM", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygonZM), - ("Point25D", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.Point25D), - ("LineString25D", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.LineString25D), - ("Polygon25D", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.Polygon25D), - ("MultiPoint25D", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.MultiPoint25D), - ("MultiLineString25D", QgsWkbTypes.GeometryType.LineGeometry, QgsWkbTypes.Type.MultiLineString25D), - ("MultiPolygon25D", QgsWkbTypes.GeometryType.PolygonGeometry, QgsWkbTypes.Type.MultiPolygon25D), - ("None", QgsWkbTypes.GeometryType.NullGeometry, QgsWkbTypes.Type.NoGeometry)] + testVectors = [ + ("Point", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.Point), + ( + "LineString", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.LineString, + ), + ( + "Polygon", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.Polygon, + ), + ( + "MultiPoint", + QgsWkbTypes.GeometryType.PointGeometry, + QgsWkbTypes.Type.MultiPoint, + ), + ( + "MultiLineString", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.MultiLineString, + ), + ( + "MultiPolygon", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.MultiPolygon, + ), + ("PointZ", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointZ), + ( + "LineStringZ", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.LineStringZ, + ), + ( + "PolygonZ", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.PolygonZ, + ), + ( + "MultiPointZ", + QgsWkbTypes.GeometryType.PointGeometry, + QgsWkbTypes.Type.MultiPointZ, + ), + ( + "MultiLineStringZ", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.MultiLineStringZ, + ), + ( + "MultiPolygonZ", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.MultiPolygonZ, + ), + ("PointM", QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.Type.PointM), + ( + "LineStringM", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.LineStringM, + ), + ( + "PolygonM", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.PolygonM, + ), + ( + "MultiPointM", + QgsWkbTypes.GeometryType.PointGeometry, + QgsWkbTypes.Type.MultiPointM, + ), + ( + "MultiLineStringM", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.MultiLineStringM, + ), + ( + "MultiPolygonM", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.MultiPolygonM, + ), + ( + "PointZM", + QgsWkbTypes.GeometryType.PointGeometry, + QgsWkbTypes.Type.PointZM, + ), + ( + "LineStringZM", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.LineStringZM, + ), + ( + "PolygonZM", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.PolygonZM, + ), + ( + "MultiPointZM", + QgsWkbTypes.GeometryType.PointGeometry, + QgsWkbTypes.Type.MultiPointZM, + ), + ( + "MultiLineStringZM", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.MultiLineStringZM, + ), + ( + "MultiPolygonZM", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.MultiPolygonZM, + ), + ( + "Point25D", + QgsWkbTypes.GeometryType.PointGeometry, + QgsWkbTypes.Type.Point25D, + ), + ( + "LineString25D", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.LineString25D, + ), + ( + "Polygon25D", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.Polygon25D, + ), + ( + "MultiPoint25D", + QgsWkbTypes.GeometryType.PointGeometry, + QgsWkbTypes.Type.MultiPoint25D, + ), + ( + "MultiLineString25D", + QgsWkbTypes.GeometryType.LineGeometry, + QgsWkbTypes.Type.MultiLineString25D, + ), + ( + "MultiPolygon25D", + QgsWkbTypes.GeometryType.PolygonGeometry, + QgsWkbTypes.Type.MultiPolygon25D, + ), + ( + "None", + QgsWkbTypes.GeometryType.NullGeometry, + QgsWkbTypes.Type.NoGeometry, + ), + ] for v in testVectors: layer = QgsVectorLayer(v[0], "test", "pythonprovider") - myMessage = f'Expected: {v[1]}\nGot: {layer.geometryType()}\n' + myMessage = f"Expected: {v[1]}\nGot: {layer.geometryType()}\n" assert layer.geometryType() == v[1], myMessage - myMessage = f'Expected: {v[2]}\nGot: {layer.wkbType()}\n' + myMessage = f"Expected: {v[2]}\nGot: {layer.wkbType()}\n" assert layer.wkbType() == v[2], myMessage def testAddFeatures(self): layer = QgsVectorLayer("Point", "test", "pythonprovider") provider = layer.dataProvider() - res = provider.addAttributes([QgsField("name", QVariant.String), - QgsField("age", QVariant.Int), - QgsField("size", QVariant.Double)]) + res = provider.addAttributes( + [ + QgsField("name", QVariant.String), + QgsField("age", QVariant.Int), + QgsField("size", QVariant.Double), + ] + ) assert res, "Failed to add attributes" - myMessage = f'Expected: {3}\nGot: {len(provider.fields())}\n' + myMessage = f"Expected: {3}\nGot: {len(provider.fields())}\n" assert len(provider.fields()) == 3, myMessage ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) - ft.setAttributes(["Johny", - 20, - 0.3]) + ft.setAttributes(["Johny", 20, 0.3]) res, t = provider.addFeatures([ft]) assert res, "Failed to add feature" - myMessage = f'Expected: {1}\nGot: {provider.featureCount()}\n' + myMessage = f"Expected: {1}\nGot: {provider.featureCount()}\n" assert provider.featureCount() == 1, myMessage for f in provider.getFeatures(QgsFeatureRequest()): @@ -216,11 +404,11 @@ def testAddFeatures(self): assert f[0] == "Johny", myMessage - myMessage = f'Expected: {20}\nGot: {f[1]}\n' + myMessage = f"Expected: {20}\nGot: {f[1]}\n" assert f[1] == 20, myMessage - myMessage = f'Expected: {0.3}\nGot: {f[2]}\n' + myMessage = f"Expected: {0.3}\nGot: {f[2]}\n" assert (f[2] - 0.3) < 0.0000001, myMessage @@ -234,18 +422,20 @@ def testGetFields(self): layer = QgsVectorLayer("Point", "test", "pythonprovider") provider = layer.dataProvider() - provider.addAttributes([QgsField("name", QVariant.String), - QgsField("age", QVariant.Int), - QgsField("size", QVariant.Double)]) - myMessage = f'Expected: {3}\nGot: {len(provider.fields())}\n' + provider.addAttributes( + [ + QgsField("name", QVariant.String), + QgsField("age", QVariant.Int), + QgsField("size", QVariant.Double), + ] + ) + myMessage = f"Expected: {3}\nGot: {len(provider.fields())}\n" assert len(provider.fields()) == 3, myMessage ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) - ft.setAttributes(["Johny", - 20, - 0.3]) + ft.setAttributes(["Johny", 20, 0.3]) provider.addFeatures([ft]) for f in provider.getFeatures(QgsFeatureRequest()): @@ -256,41 +446,46 @@ def testGetFields(self): def testFromUri(self): """Test we can construct the mem provider from a uri""" myPyLayer = QgsVectorLayer( - ('Point?crs=epsg:4326&field=name:string(20)&' - 'field=age:integer&field=size:double&index=yes'), - 'test', - 'pythonprovider') - - assert myPyLayer is not None, 'Provider not initialized' + ( + "Point?crs=epsg:4326&field=name:string(20)&" + "field=age:integer&field=size:double&index=yes" + ), + "test", + "pythonprovider", + ) + + assert myPyLayer is not None, "Provider not initialized" myProvider = myPyLayer.dataProvider() assert myProvider is not None def testLengthPrecisionFromUri(self): """Test we can assign length and precision from a uri""" myPyLayer = QgsVectorLayer( - ('Point?crs=epsg:4326&field=size:double(12,9)&index=yes'), - 'test', - 'pythonprovider') + ("Point?crs=epsg:4326&field=size:double(12,9)&index=yes"), + "test", + "pythonprovider", + ) - self.assertEqual(myPyLayer.fields().field('size').length(), 12) - self.assertEqual(myPyLayer.fields().field('size').precision(), 9) + self.assertEqual(myPyLayer.fields().field("size").length(), 12) + self.assertEqual(myPyLayer.fields().field("size").precision(), 9) @QgisTestCase.expectedFailure("Handled layers are hardcoded") def testSaveFields(self): # Create a new py layerwith no fields myPyLayer = QgsVectorLayer( - ('Point?crs=epsg:4326&index=yes'), - 'test', - 'pythonprovider') + ("Point?crs=epsg:4326&index=yes"), "test", "pythonprovider" + ) # Add some fields to the layer - myFields = [QgsField('TestInt', QVariant.Int, 'integer', 2, 0), - QgsField('TestLong', QVariant.LongLong, 'long', -1, 0), - QgsField('TestDbl', QVariant.Double, 'double', 8, 6), - QgsField('TestString', QVariant.String, 'string', 50, 0), - QgsField('TestDate', QVariant.Date, 'date'), - QgsField('TestTime', QVariant.Time, 'time'), - QgsField('TestDateTime', QVariant.DateTime, 'datetime')] + myFields = [ + QgsField("TestInt", QVariant.Int, "integer", 2, 0), + QgsField("TestLong", QVariant.LongLong, "long", -1, 0), + QgsField("TestDbl", QVariant.Double, "double", 8, 6), + QgsField("TestString", QVariant.String, "string", 50, 0), + QgsField("TestDate", QVariant.Date, "date"), + QgsField("TestTime", QVariant.Time, "time"), + QgsField("TestDateTime", QVariant.DateTime, "datetime"), + ] assert myPyLayer.startEditing() for f in myFields: assert myPyLayer.addAttribute(f) @@ -298,11 +493,15 @@ def testSaveFields(self): myPyLayer.updateFields() # Export the layer to a layer-definition-XML - qlr = QgsLayerDefinition.exportLayerDefinitionLayers([myPyLayer], QgsReadWriteContext()) + qlr = QgsLayerDefinition.exportLayerDefinitionLayers( + [myPyLayer], QgsReadWriteContext() + ) assert qlr is not None # Import the layer from the layer-definition-XML - layers = QgsLayerDefinition.loadLayerDefinitionLayers(qlr, QgsReadWriteContext()) + layers = QgsLayerDefinition.loadLayerDefinitionLayers( + qlr, QgsReadWriteContext() + ) assert layers is not None myImportedLayer = layers[0] assert myImportedLayer is not None @@ -317,48 +516,55 @@ def testRenameAttributes(self): layer = QgsVectorLayer("Point", "test", "pythonprovider") provider = layer.dataProvider() - res = provider.addAttributes([QgsField("name", QVariant.String), - QgsField("age", QVariant.Int), - QgsField("size", QVariant.Double)]) + res = provider.addAttributes( + [ + QgsField("name", QVariant.String), + QgsField("age", QVariant.Int), + QgsField("size", QVariant.Double), + ] + ) layer.updateFields() assert res, "Failed to add attributes" ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) - ft.setAttributes(["Johny", - 20, - 0.3]) + ft.setAttributes(["Johny", 20, 0.3]) res, t = provider.addFeatures([ft]) # bad rename - self.assertFalse(provider.renameAttributes({-1: 'not_a_field'})) - self.assertFalse(provider.renameAttributes({100: 'not_a_field'})) + self.assertFalse(provider.renameAttributes({-1: "not_a_field"})) + self.assertFalse(provider.renameAttributes({100: "not_a_field"})) # already exists - self.assertFalse(provider.renameAttributes({1: 'name'})) + self.assertFalse(provider.renameAttributes({1: "name"})) # rename one field - self.assertTrue(provider.renameAttributes({1: 'this_is_the_new_age'})) - self.assertEqual(provider.fields().at(1).name(), 'this_is_the_new_age') + self.assertTrue(provider.renameAttributes({1: "this_is_the_new_age"})) + self.assertEqual(provider.fields().at(1).name(), "this_is_the_new_age") layer.updateFields() fet = next(layer.getFeatures()) - self.assertEqual(fet.fields()[1].name(), 'this_is_the_new_age') + self.assertEqual(fet.fields()[1].name(), "this_is_the_new_age") # rename two fields - self.assertTrue(provider.renameAttributes({1: 'mapinfo_is_the_stone_age', 2: 'super_size'})) - self.assertEqual(provider.fields().at(1).name(), 'mapinfo_is_the_stone_age') - self.assertEqual(provider.fields().at(2).name(), 'super_size') + self.assertTrue( + provider.renameAttributes({1: "mapinfo_is_the_stone_age", 2: "super_size"}) + ) + self.assertEqual(provider.fields().at(1).name(), "mapinfo_is_the_stone_age") + self.assertEqual(provider.fields().at(2).name(), "super_size") layer.updateFields() fet = next(layer.getFeatures()) - self.assertEqual(fet.fields()[1].name(), 'mapinfo_is_the_stone_age') - self.assertEqual(fet.fields()[2].name(), 'super_size') + self.assertEqual(fet.fields()[1].name(), "mapinfo_is_the_stone_age") + self.assertEqual(fet.fields()[2].name(), "super_size") def testThreadSafetyWithIndex(self): - layer = QgsVectorLayer('Point?crs=epsg:4326&index=yes&field=pk:integer&field=cnt:int8&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk', - 'test', 'pythonprovider') + layer = QgsVectorLayer( + "Point?crs=epsg:4326&index=yes&field=pk:integer&field=cnt:int8&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk", + "test", + "pythonprovider", + ) provider = layer.dataProvider() f = QgsFeature() - f.setAttributes([5, -200, NULL, 'NuLl', '5']) - f.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)')) + f.setAttributes([5, -200, NULL, "NuLl", "5"]) + f.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)")) for i in range(100000): provider.addFeatures([f]) @@ -366,12 +572,18 @@ def testThreadSafetyWithIndex(self): # filter rect request extent = QgsRectangle(-73, 70, -63, 80) request = QgsFeatureRequest().setFilterRect(extent) - self.assertTrue(QgsTestUtils.testProviderIteratorThreadSafety(self.source, request)) + self.assertTrue( + QgsTestUtils.testProviderIteratorThreadSafety(self.source, request) + ) def tesRegisterSameProviderTwice(self): """Test that a provider cannot be registered twice""" r = QgsProviderRegistry.instance() - metadata = QgsProviderMetadata(PyProvider.providerKey(), PyProvider.description(), PyProvider.createProvider) + metadata = QgsProviderMetadata( + PyProvider.providerKey(), + PyProvider.description(), + PyProvider.createProvider, + ) self.assertFalse(r.registerProvider(metadata)) def testGetFeaturesFromProvider(self): @@ -380,12 +592,16 @@ def testGetFeaturesFromProvider(self): result should be the same... """ layer = self.createLayer() - provider_features = {f.id(): f.attributes() for f in layer.dataProvider().getFeatures()} + provider_features = { + f.id(): f.attributes() for f in layer.dataProvider().getFeatures() + } self.assertTrue(provider_features) - layer_features = {f.id(): f.attributes() for f in layer.dataProvider().getFeatures()} + layer_features = { + f.id(): f.attributes() for f in layer.dataProvider().getFeatures() + } self.assertTrue(layer_features) self.assertEqual(provider_features, layer_features) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_provider_sensorthings.py b/tests/src/python/test_provider_sensorthings.py index bf8b55b2147a..0f27a5bf98d1 100644 --- a/tests/src/python/test_provider_sensorthings.py +++ b/tests/src/python/test_provider_sensorthings.py @@ -7,6 +7,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + __author__ = "Nyall Dawson" __date__ = "2023-11-08" @@ -23,19 +24,21 @@ QgsSensorThingsUtils, QgsFeatureRequest, QgsRectangle, - QgsSensorThingsExpansionDefinition + QgsSensorThingsExpansionDefinition, ) from qgis.testing import start_app, QgisTestCase def sanitize(endpoint, x): - for prefix in ('/Locations', - '/HistoricalLocations', - '/Things', - '/FeaturesOfInterest', - '/MultiDatastreams'): + for prefix in ( + "/Locations", + "/HistoricalLocations", + "/Things", + "/FeaturesOfInterest", + "/MultiDatastreams", + ): if x.startswith(prefix): - x = x[len(prefix):] + x = x[len(prefix) :] endpoint = endpoint + "_" + prefix[1:] if len(endpoint + x) > 150: @@ -58,7 +61,7 @@ class TestPyQgsSensorThingsProvider(QgisTestCase): # , ProviderTestCase): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsSensorThingsProvider, cls).setUpClass() + super().setUpClass() QCoreApplication.setOrganizationName("QGIS_Test") QCoreApplication.setOrganizationDomain("TestPyQgsSensorThingsProvider.com") @@ -86,24 +89,34 @@ def test_filter_for_wkb_type(self): features with a desired WKB type """ self.assertEqual( - QgsSensorThingsUtils.filterForWkbType(Qgis.SensorThingsEntity.Location, Qgis.WkbType.Point), - "location/type eq 'Point' or location/geometry/type eq 'Point'" + QgsSensorThingsUtils.filterForWkbType( + Qgis.SensorThingsEntity.Location, Qgis.WkbType.Point + ), + "location/type eq 'Point' or location/geometry/type eq 'Point'", ) self.assertEqual( - QgsSensorThingsUtils.filterForWkbType(Qgis.SensorThingsEntity.Location, Qgis.WkbType.PointZ), - "location/type eq 'Point' or location/geometry/type eq 'Point'" + QgsSensorThingsUtils.filterForWkbType( + Qgis.SensorThingsEntity.Location, Qgis.WkbType.PointZ + ), + "location/type eq 'Point' or location/geometry/type eq 'Point'", ) self.assertEqual( - QgsSensorThingsUtils.filterForWkbType(Qgis.SensorThingsEntity.FeatureOfInterest, Qgis.WkbType.Polygon), - "feature/type eq 'Polygon' or feature/geometry/type eq 'Polygon'" + QgsSensorThingsUtils.filterForWkbType( + Qgis.SensorThingsEntity.FeatureOfInterest, Qgis.WkbType.Polygon + ), + "feature/type eq 'Polygon' or feature/geometry/type eq 'Polygon'", ) self.assertEqual( - QgsSensorThingsUtils.filterForWkbType(Qgis.SensorThingsEntity.Location, Qgis.WkbType.LineString), - "location/type eq 'LineString' or location/geometry/type eq 'LineString'" + QgsSensorThingsUtils.filterForWkbType( + Qgis.SensorThingsEntity.Location, Qgis.WkbType.LineString + ), + "location/type eq 'LineString' or location/geometry/type eq 'LineString'", ) self.assertEqual( - QgsSensorThingsUtils.filterForWkbType(Qgis.SensorThingsEntity.MultiDatastream, Qgis.WkbType.Polygon), - "observedArea/type eq 'Polygon' or observedArea/geometry/type eq 'Polygon'" + QgsSensorThingsUtils.filterForWkbType( + Qgis.SensorThingsEntity.MultiDatastream, Qgis.WkbType.Polygon + ), + "observedArea/type eq 'Polygon' or observedArea/geometry/type eq 'Polygon'", ) def test_utils_string_to_entity(self): @@ -192,18 +205,20 @@ def test_utils_string_to_entityset(self): def test_utils_entity_to_set_string(self): self.assertEqual( QgsSensorThingsUtils.entityToSetString(Qgis.SensorThingsEntity.Invalid), - '', + "", ) self.assertEqual( QgsSensorThingsUtils.entityToSetString(Qgis.SensorThingsEntity.Thing), - "Things" + "Things", ) self.assertEqual( QgsSensorThingsUtils.entityToSetString(Qgis.SensorThingsEntity.Location), "Locations", ) self.assertEqual( - QgsSensorThingsUtils.entityToSetString(Qgis.SensorThingsEntity.HistoricalLocation), + QgsSensorThingsUtils.entityToSetString( + Qgis.SensorThingsEntity.HistoricalLocation + ), "HistoricalLocations", ) self.assertEqual( @@ -212,22 +227,28 @@ def test_utils_entity_to_set_string(self): ) self.assertEqual( QgsSensorThingsUtils.entityToSetString(Qgis.SensorThingsEntity.Sensor), - "Sensors" + "Sensors", ) self.assertEqual( - QgsSensorThingsUtils.entityToSetString(Qgis.SensorThingsEntity.ObservedProperty), + QgsSensorThingsUtils.entityToSetString( + Qgis.SensorThingsEntity.ObservedProperty + ), "ObservedProperties", ) self.assertEqual( QgsSensorThingsUtils.entityToSetString(Qgis.SensorThingsEntity.Observation), - "Observations" + "Observations", ) self.assertEqual( - QgsSensorThingsUtils.entityToSetString(Qgis.SensorThingsEntity.FeatureOfInterest), + QgsSensorThingsUtils.entityToSetString( + Qgis.SensorThingsEntity.FeatureOfInterest + ), "FeaturesOfInterest", ) self.assertEqual( - QgsSensorThingsUtils.entityToSetString(Qgis.SensorThingsEntity.MultiDatastream), + QgsSensorThingsUtils.entityToSetString( + Qgis.SensorThingsEntity.MultiDatastream + ), "MultiDatastreams", ) @@ -240,90 +261,149 @@ def test_expansion_definition(self): self.assertFalse(expansion.asQueryString(Qgis.SensorThingsEntity.Invalid)) # test getters/setters - expansion = QgsSensorThingsExpansionDefinition(Qgis.SensorThingsEntity.ObservedProperty) + expansion = QgsSensorThingsExpansionDefinition( + Qgis.SensorThingsEntity.ObservedProperty + ) self.assertTrue(expansion.isValid()) - self.assertEqual(expansion.childEntity(), Qgis.SensorThingsEntity.ObservedProperty) + self.assertEqual( + expansion.childEntity(), Qgis.SensorThingsEntity.ObservedProperty + ) self.assertEqual(expansion.limit(), 100) self.assertFalse(expansion.filter()) - self.assertEqual(repr(expansion), '') - self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Datastream), '$expand=ObservedProperty($top=100)') - self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Datastream, ['$expand=Locations($top=101)']), - '$expand=ObservedProperty($top=100;$expand=Locations($top=101))') + self.assertEqual( + repr(expansion), + "", + ) + self.assertEqual( + expansion.asQueryString(Qgis.SensorThingsEntity.Datastream), + "$expand=ObservedProperty($top=100)", + ) + self.assertEqual( + expansion.asQueryString( + Qgis.SensorThingsEntity.Datastream, ["$expand=Locations($top=101)"] + ), + "$expand=ObservedProperty($top=100;$expand=Locations($top=101))", + ) expansion.setChildEntity(Qgis.SensorThingsEntity.Location) - self.assertEqual(expansion.childEntity(), - Qgis.SensorThingsEntity.Location) - self.assertEqual(repr(expansion), - '') - self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing), - '$expand=Locations($top=100)') - self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing, ['$expand=Datastreams($top=101)']), - '$expand=Locations($top=100;$expand=Datastreams($top=101))') + self.assertEqual(expansion.childEntity(), Qgis.SensorThingsEntity.Location) + self.assertEqual( + repr(expansion), "" + ) + self.assertEqual( + expansion.asQueryString(Qgis.SensorThingsEntity.Thing), + "$expand=Locations($top=100)", + ) + self.assertEqual( + expansion.asQueryString( + Qgis.SensorThingsEntity.Thing, ["$expand=Datastreams($top=101)"] + ), + "$expand=Locations($top=100;$expand=Datastreams($top=101))", + ) expansion.setLimit(-1) self.assertEqual(expansion.limit(), -1) - self.assertEqual(repr(expansion), - '') - self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing), - '$expand=Locations') - self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing, - ['$expand=Datastreams($top=101)']), - '$expand=Locations($expand=Datastreams($top=101))') - - expansion.setOrderBy('id') - self.assertEqual(expansion.orderBy(), 'id') - self.assertEqual(repr(expansion), - '') - self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing), - '$expand=Locations($orderby=id)') - self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing, - ['$expand=Datastreams($top=101)']), - '$expand=Locations($orderby=id;$expand=Datastreams($top=101))') + self.assertEqual( + repr(expansion), "" + ) + self.assertEqual( + expansion.asQueryString(Qgis.SensorThingsEntity.Thing), "$expand=Locations" + ) + self.assertEqual( + expansion.asQueryString( + Qgis.SensorThingsEntity.Thing, ["$expand=Datastreams($top=101)"] + ), + "$expand=Locations($expand=Datastreams($top=101))", + ) + + expansion.setOrderBy("id") + self.assertEqual(expansion.orderBy(), "id") + self.assertEqual( + repr(expansion), + "", + ) + self.assertEqual( + expansion.asQueryString(Qgis.SensorThingsEntity.Thing), + "$expand=Locations($orderby=id)", + ) + self.assertEqual( + expansion.asQueryString( + Qgis.SensorThingsEntity.Thing, ["$expand=Datastreams($top=101)"] + ), + "$expand=Locations($orderby=id;$expand=Datastreams($top=101))", + ) expansion.setSortOrder(Qt.SortOrder.DescendingOrder) self.assertEqual(expansion.sortOrder(), Qt.SortOrder.DescendingOrder) - self.assertEqual(repr(expansion), - '') - self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing), - '$expand=Locations($orderby=id desc)') - self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing, ['$expand=Datastreams($top=101)']), - '$expand=Locations($orderby=id desc;$expand=Datastreams($top=101))') + self.assertEqual( + repr(expansion), + "", + ) + self.assertEqual( + expansion.asQueryString(Qgis.SensorThingsEntity.Thing), + "$expand=Locations($orderby=id desc)", + ) + self.assertEqual( + expansion.asQueryString( + Qgis.SensorThingsEntity.Thing, ["$expand=Datastreams($top=101)"] + ), + "$expand=Locations($orderby=id desc;$expand=Datastreams($top=101))", + ) expansion.setLimit(3) - self.assertEqual(repr(expansion), - '') - self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing), - '$expand=Locations($orderby=id desc;$top=3)') - self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing, ['$expand=Datastreams($top=101)']), - '$expand=Locations($orderby=id desc;$top=3;$expand=Datastreams($top=101))') - - expansion.setFilter('result eq 1') - self.assertEqual(expansion.filter(), 'result eq 1') - self.assertEqual(repr(expansion), - '') - self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing), - '$expand=Locations($orderby=id desc;$top=3;$filter=result eq 1)') - self.assertEqual(expansion.asQueryString(Qgis.SensorThingsEntity.Thing, ['$expand=Datastreams($top=101)']), - '$expand=Locations($orderby=id desc;$top=3;$filter=result eq 1;$expand=Datastreams($top=101))') + self.assertEqual( + repr(expansion), + "", + ) + self.assertEqual( + expansion.asQueryString(Qgis.SensorThingsEntity.Thing), + "$expand=Locations($orderby=id desc;$top=3)", + ) + self.assertEqual( + expansion.asQueryString( + Qgis.SensorThingsEntity.Thing, ["$expand=Datastreams($top=101)"] + ), + "$expand=Locations($orderby=id desc;$top=3;$expand=Datastreams($top=101))", + ) + + expansion.setFilter("result eq 1") + self.assertEqual(expansion.filter(), "result eq 1") + self.assertEqual( + repr(expansion), + "", + ) + self.assertEqual( + expansion.asQueryString(Qgis.SensorThingsEntity.Thing), + "$expand=Locations($orderby=id desc;$top=3;$filter=result eq 1)", + ) + self.assertEqual( + expansion.asQueryString( + Qgis.SensorThingsEntity.Thing, ["$expand=Datastreams($top=101)"] + ), + "$expand=Locations($orderby=id desc;$top=3;$filter=result eq 1;$expand=Datastreams($top=101))", + ) # test equality expansion1 = QgsSensorThingsExpansionDefinition( - Qgis.SensorThingsEntity.ObservedProperty) + Qgis.SensorThingsEntity.ObservedProperty + ) expansion2 = QgsSensorThingsExpansionDefinition( - Qgis.SensorThingsEntity.ObservedProperty) + Qgis.SensorThingsEntity.ObservedProperty + ) self.assertEqual(expansion1, expansion2) self.assertNotEqual(expansion1, QgsSensorThingsExpansionDefinition()) self.assertNotEqual(QgsSensorThingsExpansionDefinition(), expansion2) - self.assertEqual(QgsSensorThingsExpansionDefinition(), - QgsSensorThingsExpansionDefinition()) + self.assertEqual( + QgsSensorThingsExpansionDefinition(), QgsSensorThingsExpansionDefinition() + ) expansion2.setChildEntity(Qgis.SensorThingsEntity.Sensor) self.assertNotEqual(expansion1, expansion2) expansion2.setChildEntity(Qgis.SensorThingsEntity.ObservedProperty) self.assertEqual(expansion1, expansion2) - expansion2.setOrderBy('x') + expansion2.setOrderBy("x") self.assertNotEqual(expansion1, expansion2) - expansion2.setOrderBy('') + expansion2.setOrderBy("") self.assertEqual(expansion1, expansion2) expansion2.setSortOrder(Qt.SortOrder.DescendingOrder) @@ -336,9 +416,9 @@ def test_expansion_definition(self): expansion2.setLimit(100) self.assertEqual(expansion1, expansion2) - expansion2.setFilter('result eq 1') + expansion2.setFilter("result eq 1") self.assertNotEqual(expansion1, expansion2) - expansion2.setFilter('') + expansion2.setFilter("") self.assertEqual(expansion1, expansion2) # test to/from string @@ -357,12 +437,12 @@ def test_expansion_definition(self): self.assertFalse(res.orderBy()) self.assertEqual(res.limit(), -1) - expansion.setOrderBy('test') + expansion.setOrderBy("test") string = expansion.toString() res = QgsSensorThingsExpansionDefinition.fromString(string) self.assertTrue(res.isValid()) self.assertEqual(res.childEntity(), Qgis.SensorThingsEntity.Sensor) - self.assertEqual(res.orderBy(), 'test') + self.assertEqual(res.orderBy(), "test") self.assertEqual(res.sortOrder(), Qt.SortOrder.AscendingOrder) self.assertEqual(res.limit(), -1) @@ -371,7 +451,7 @@ def test_expansion_definition(self): res = QgsSensorThingsExpansionDefinition.fromString(string) self.assertTrue(res.isValid()) self.assertEqual(res.childEntity(), Qgis.SensorThingsEntity.Sensor) - self.assertEqual(res.orderBy(), 'test') + self.assertEqual(res.orderBy(), "test") self.assertEqual(res.sortOrder(), Qt.SortOrder.DescendingOrder) self.assertEqual(res.limit(), -1) @@ -380,11 +460,11 @@ def test_expansion_definition(self): res = QgsSensorThingsExpansionDefinition.fromString(string) self.assertTrue(res.isValid()) self.assertEqual(res.childEntity(), Qgis.SensorThingsEntity.Sensor) - self.assertEqual(res.orderBy(), 'test') + self.assertEqual(res.orderBy(), "test") self.assertEqual(res.sortOrder(), Qt.SortOrder.DescendingOrder) self.assertEqual(res.limit(), 5) - expansion.setOrderBy('') + expansion.setOrderBy("") string = expansion.toString() res = QgsSensorThingsExpansionDefinition.fromString(string) self.assertTrue(res.isValid()) @@ -392,7 +472,7 @@ def test_expansion_definition(self): self.assertFalse(res.orderBy()) self.assertEqual(res.limit(), 5) - expansion.setFilter('request eq 1:2') + expansion.setFilter("request eq 1:2") string = expansion.toString() res = QgsSensorThingsExpansionDefinition.fromString(string) self.assertTrue(res.isValid()) @@ -403,75 +483,88 @@ def test_expansions_as_query_string(self): Test constructing query strings from a list of expansions """ self.assertFalse( - QgsSensorThingsUtils.asQueryString(Qgis.SensorThingsEntity.Invalid, - []) + QgsSensorThingsUtils.asQueryString(Qgis.SensorThingsEntity.Invalid, []) ) self.assertEqual( - QgsSensorThingsUtils.asQueryString(Qgis.SensorThingsEntity.Thing, - [ - QgsSensorThingsExpansionDefinition( - Qgis.SensorThingsEntity.Location, - orderBy='id', limit=3) - ]), - '$expand=Locations($orderby=id;$top=3)' + QgsSensorThingsUtils.asQueryString( + Qgis.SensorThingsEntity.Thing, + [ + QgsSensorThingsExpansionDefinition( + Qgis.SensorThingsEntity.Location, orderBy="id", limit=3 + ) + ], + ), + "$expand=Locations($orderby=id;$top=3)", ) self.assertEqual( - QgsSensorThingsUtils.asQueryString(Qgis.SensorThingsEntity.Thing, - [ - QgsSensorThingsExpansionDefinition(), - QgsSensorThingsExpansionDefinition( - Qgis.SensorThingsEntity.Datastream, - orderBy='id', limit=3) - ]), - '$expand=Datastreams($orderby=id;$top=3)' + QgsSensorThingsUtils.asQueryString( + Qgis.SensorThingsEntity.Thing, + [ + QgsSensorThingsExpansionDefinition(), + QgsSensorThingsExpansionDefinition( + Qgis.SensorThingsEntity.Datastream, orderBy="id", limit=3 + ), + ], + ), + "$expand=Datastreams($orderby=id;$top=3)", ) self.assertEqual( - QgsSensorThingsUtils.asQueryString(Qgis.SensorThingsEntity.Thing, - [ - QgsSensorThingsExpansionDefinition( - Qgis.SensorThingsEntity.Datastream, - orderBy='id', limit=3) - ]), - '$expand=Datastreams($orderby=id;$top=3)' + QgsSensorThingsUtils.asQueryString( + Qgis.SensorThingsEntity.Thing, + [ + QgsSensorThingsExpansionDefinition( + Qgis.SensorThingsEntity.Datastream, orderBy="id", limit=3 + ) + ], + ), + "$expand=Datastreams($orderby=id;$top=3)", ) self.assertEqual( QgsSensorThingsUtils.asQueryString( Qgis.SensorThingsEntity.Observation, - [QgsSensorThingsExpansionDefinition( - Qgis.SensorThingsEntity.Datastream, - orderBy='id', limit=3) - ]), - '$expand=Datastream($orderby=id;$top=3)' + [ + QgsSensorThingsExpansionDefinition( + Qgis.SensorThingsEntity.Datastream, orderBy="id", limit=3 + ) + ], + ), + "$expand=Datastream($orderby=id;$top=3)", ) self.assertEqual( - QgsSensorThingsUtils.asQueryString(Qgis.SensorThingsEntity.Thing, - [ - QgsSensorThingsExpansionDefinition( - Qgis.SensorThingsEntity.Location, - orderBy='id', limit=3), - QgsSensorThingsExpansionDefinition( - Qgis.SensorThingsEntity.Sensor, - orderBy='description', - limit=30) - ]), - '$expand=Locations($orderby=id;$top=3;$expand=Sensors($orderby=description;$top=30))' + QgsSensorThingsUtils.asQueryString( + Qgis.SensorThingsEntity.Thing, + [ + QgsSensorThingsExpansionDefinition( + Qgis.SensorThingsEntity.Location, orderBy="id", limit=3 + ), + QgsSensorThingsExpansionDefinition( + Qgis.SensorThingsEntity.Sensor, orderBy="description", limit=30 + ), + ], + ), + "$expand=Locations($orderby=id;$top=3;$expand=Sensors($orderby=description;$top=30))", ) self.assertEqual( QgsSensorThingsUtils.asQueryString( Qgis.SensorThingsEntity.Location, [ QgsSensorThingsExpansionDefinition( - Qgis.SensorThingsEntity.Thing, - orderBy='id', limit=3), + Qgis.SensorThingsEntity.Thing, orderBy="id", limit=3 + ), QgsSensorThingsExpansionDefinition( Qgis.SensorThingsEntity.Datastream, - orderBy='description', limit=30), + orderBy="description", + limit=30, + ), QgsSensorThingsExpansionDefinition( Qgis.SensorThingsEntity.ObservedProperty, - orderBy='name', limit=-1) - ]), - '$expand=Things($orderby=id;$top=3;$expand=Datastreams($orderby=description;$top=30;$expand=ObservedProperty($orderby=name)))' + orderBy="name", + limit=-1, + ), + ], + ), + "$expand=Things($orderby=id;$top=3;$expand=Datastreams($orderby=description;$top=30;$expand=ObservedProperty($orderby=name)))", ) def test_fields_for_expanded_entity(self): @@ -479,47 +572,71 @@ def test_fields_for_expanded_entity(self): Test calculating fields for an expanded entity """ fields = QgsSensorThingsUtils.fieldsForExpandedEntityType( - Qgis.SensorThingsEntity.Location, - []) - self.assertEqual([field.name() for field in fields], - ['id', 'selfLink', 'name', 'description', - 'properties']) + Qgis.SensorThingsEntity.Location, [] + ) + self.assertEqual( + [field.name() for field in fields], + ["id", "selfLink", "name", "description", "properties"], + ) fields = QgsSensorThingsUtils.fieldsForExpandedEntityType( - Qgis.SensorThingsEntity.Location, - [Qgis.SensorThingsEntity.Thing]) - self.assertEqual([field.name() for field in fields], - ['id', 'selfLink', 'name', 'description', - 'properties', 'Thing_id', 'Thing_selfLink', - 'Thing_name', 'Thing_description', - 'Thing_properties']) + Qgis.SensorThingsEntity.Location, [Qgis.SensorThingsEntity.Thing] + ) + self.assertEqual( + [field.name() for field in fields], + [ + "id", + "selfLink", + "name", + "description", + "properties", + "Thing_id", + "Thing_selfLink", + "Thing_name", + "Thing_description", + "Thing_properties", + ], + ) fields = QgsSensorThingsUtils.fieldsForExpandedEntityType( Qgis.SensorThingsEntity.Location, - [Qgis.SensorThingsEntity.Thing, - Qgis.SensorThingsEntity.Datastream]) - self.assertEqual([field.name() for field in fields], - ['id', 'selfLink', 'name', 'description', - 'properties', 'Thing_id', 'Thing_selfLink', - 'Thing_name', 'Thing_description', - 'Thing_properties', 'Thing_Datastream_id', - 'Thing_Datastream_selfLink', 'Thing_Datastream_name', - 'Thing_Datastream_description', - 'Thing_Datastream_unitOfMeasurement', - 'Thing_Datastream_observationType', - 'Thing_Datastream_properties', - 'Thing_Datastream_phenomenonTimeStart', - 'Thing_Datastream_phenomenonTimeEnd', - 'Thing_Datastream_resultTimeStart', - 'Thing_Datastream_resultTimeEnd']) + [Qgis.SensorThingsEntity.Thing, Qgis.SensorThingsEntity.Datastream], + ) + self.assertEqual( + [field.name() for field in fields], + [ + "id", + "selfLink", + "name", + "description", + "properties", + "Thing_id", + "Thing_selfLink", + "Thing_name", + "Thing_description", + "Thing_properties", + "Thing_Datastream_id", + "Thing_Datastream_selfLink", + "Thing_Datastream_name", + "Thing_Datastream_description", + "Thing_Datastream_unitOfMeasurement", + "Thing_Datastream_observationType", + "Thing_Datastream_properties", + "Thing_Datastream_phenomenonTimeStart", + "Thing_Datastream_phenomenonTimeEnd", + "Thing_Datastream_resultTimeStart", + "Thing_Datastream_resultTimeEnd", + ], + ) def test_expandable_targets(self): """ Test valid expansion targets for entity types """ - self.assertEqual(QgsSensorThingsUtils.expandableTargets( - Qgis.SensorThingsEntity.Thing), - [Qgis.SensorThingsEntity.HistoricalLocation, - Qgis.SensorThingsEntity.Datastream - ] + self.assertEqual( + QgsSensorThingsUtils.expandableTargets(Qgis.SensorThingsEntity.Thing), + [ + Qgis.SensorThingsEntity.HistoricalLocation, + Qgis.SensorThingsEntity.Datastream, + ], ) def test_filter_for_extent(self): @@ -527,22 +644,31 @@ def test_filter_for_extent(self): Test constructing valid filter strings for features which intersect an extent """ - self.assertFalse(QgsSensorThingsUtils.filterForExtent('', QgsRectangle())) - self.assertFalse(QgsSensorThingsUtils.filterForExtent('test', QgsRectangle())) - self.assertFalse(QgsSensorThingsUtils.filterForExtent('', QgsRectangle(1, 2, 3, 4))) - self.assertEqual(QgsSensorThingsUtils.filterForExtent('test', QgsRectangle(1, 2, 3, 4)), - "geo.intersects(test, geography'Polygon ((1 2, 3 2, 3 4, 1 4, 1 2))')") + self.assertFalse(QgsSensorThingsUtils.filterForExtent("", QgsRectangle())) + self.assertFalse(QgsSensorThingsUtils.filterForExtent("test", QgsRectangle())) + self.assertFalse( + QgsSensorThingsUtils.filterForExtent("", QgsRectangle(1, 2, 3, 4)) + ) + self.assertEqual( + QgsSensorThingsUtils.filterForExtent("test", QgsRectangle(1, 2, 3, 4)), + "geo.intersects(test, geography'Polygon ((1 2, 3 2, 3 4, 1 4, 1 2))')", + ) def test_combine_filters(self): """ Test combining multiple filter strings into one """ self.assertFalse(QgsSensorThingsUtils.combineFilters([])) - self.assertFalse(QgsSensorThingsUtils.combineFilters([''])) - self.assertEqual(QgsSensorThingsUtils.combineFilters(['', 'a eq 1']), 'a eq 1') - self.assertEqual(QgsSensorThingsUtils.combineFilters(['a eq 1', 'b eq 2']), '(a eq 1) and (b eq 2)') - self.assertEqual(QgsSensorThingsUtils.combineFilters(['a eq 1', '', 'b eq 2', 'c eq 3']), - '(a eq 1) and (b eq 2) and (c eq 3)') + self.assertFalse(QgsSensorThingsUtils.combineFilters([""])) + self.assertEqual(QgsSensorThingsUtils.combineFilters(["", "a eq 1"]), "a eq 1") + self.assertEqual( + QgsSensorThingsUtils.combineFilters(["a eq 1", "b eq 2"]), + "(a eq 1) and (b eq 2)", + ) + self.assertEqual( + QgsSensorThingsUtils.combineFilters(["a eq 1", "", "b eq 2", "c eq 3"]), + "(a eq 1) and (b eq 2) and (c eq 3)", + ) def test_invalid_layer(self): """ @@ -567,7 +693,7 @@ def test_layer_invalid_json(self): with tempfile.TemporaryDirectory() as temp_dir: base_path = temp_dir.replace("\\", "/") endpoint = base_path + "/fake_qgis_http_endpoint" - with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f: + with open(sanitize(endpoint, ""), "w", encoding="utf8") as f: f.write( """ { @@ -585,7 +711,7 @@ def test_layer(self): with tempfile.TemporaryDirectory() as temp_dir: base_path = temp_dir.replace("\\", "/") endpoint = base_path + "/fake_qgis_http_endpoint" - with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f: + with open(sanitize(endpoint, ""), "w", encoding="utf8") as f: f.write( """ { @@ -635,8 +761,11 @@ def test_layer(self): ) with open( - sanitize(endpoint, "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"), - "wt", + sanitize( + endpoint, + "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'", + ), + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":4962,"value":[]}""") @@ -689,7 +818,7 @@ def test_thing(self): with tempfile.TemporaryDirectory() as temp_dir: base_path = temp_dir.replace("\\", "/") endpoint = base_path + "/fake_qgis_http_endpoint" - with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f: + with open(sanitize(endpoint, ""), "w", encoding="utf8") as f: f.write( """ { @@ -708,14 +837,14 @@ def test_thing(self): with open( sanitize(endpoint, "/Things?$top=0&$count=true"), - "wt", + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":3,"value":[]}""") with open( sanitize(endpoint, "/Things?$top=2&$count=false"), - "wt", + "w", encoding="utf8", ) as f: f.write( @@ -758,7 +887,7 @@ def test_thing(self): with open( sanitize(endpoint, "/Things?$top=2&$skip=2"), - "wt", + "w", encoding="utf8", ) as f: f.write( @@ -846,7 +975,7 @@ def test_location(self): with tempfile.TemporaryDirectory() as temp_dir: base_path = temp_dir.replace("\\", "/") endpoint = base_path + "/fake_qgis_http_endpoint" - with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f: + with open(sanitize(endpoint, ""), "w", encoding="utf8") as f: f.write( """ { @@ -864,15 +993,21 @@ def test_location(self): ) with open( - sanitize(endpoint, "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"), - "wt", + sanitize( + endpoint, + "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'", + ), + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":3,"value":[]}""") with open( - sanitize(endpoint, "/Locations?$top=2&$count=false&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"), - "wt", + sanitize( + endpoint, + "/Locations?$top=2&$count=false&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'", + ), + "w", encoding="utf8", ) as f: f.write( @@ -927,8 +1062,11 @@ def test_location(self): ) with open( - sanitize(endpoint, "/Locations?$top=2&$skip=2&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"), - "wt", + sanitize( + endpoint, + "/Locations?$top=2&$skip=2&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'", + ), + "w", encoding="utf8", ) as f: f.write( @@ -1033,7 +1171,7 @@ def test_location_formalism(self): with tempfile.TemporaryDirectory() as temp_dir: base_path = temp_dir.replace("\\", "/") endpoint = base_path + "/fake_qgis_http_endpoint" - with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f: + with open(sanitize(endpoint, ""), "w", encoding="utf8") as f: f.write( """ { @@ -1051,17 +1189,21 @@ def test_location_formalism(self): ) with open( - sanitize(endpoint, - "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"), - "wt", + sanitize( + endpoint, + "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'", + ), + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":3,"value":[]}""") with open( - sanitize(endpoint, - "/Locations?$top=2&$count=false&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"), - "wt", + sanitize( + endpoint, + "/Locations?$top=2&$count=false&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'", + ), + "w", encoding="utf8", ) as f: f.write( @@ -1122,9 +1264,11 @@ def test_location_formalism(self): ) with open( - sanitize(endpoint, - "/Locations?$top=2&$skip=2&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"), - "wt", + sanitize( + endpoint, + "/Locations?$top=2&$skip=2&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'", + ), + "w", encoding="utf8", ) as f: f.write( @@ -1172,10 +1316,8 @@ def test_location_formalism(self): self.assertEqual(vl.extent(), QgsRectangle(-180, -90, 180, 90)) self.assertEqual(vl.featureCount(), 3) self.assertEqual(vl.crs().authid(), "EPSG:4326") - self.assertIn("Entity TypeLocation", - vl.htmlMetadata()) - self.assertIn(f'href="http://{endpoint}/Locations"', - vl.htmlMetadata()) + self.assertIn("Entity TypeLocation", vl.htmlMetadata()) + self.assertIn(f'href="http://{endpoint}/Locations"', vl.htmlMetadata()) self.assertEqual( [f.name() for f in vl.fields()], @@ -1210,24 +1352,20 @@ def test_location_formalism(self): ["Location 1", "Location 2", "Location 3"], ) self.assertEqual( - [f["description"] for f in features], - ["Desc 1", "Desc 2", "Desc 3"] + [f["description"] for f in features], ["Desc 1", "Desc 2", "Desc 3"] ) self.assertEqual( [f["properties"] for f in features], - [{"owner": "owner 1"}, {"owner": "owner 2"}, - {"owner": "owner 3"}], + [{"owner": "owner 1"}, {"owner": "owner 2"}, {"owner": "owner 3"}], ) self.assertEqual( [f.geometry().asWkt(1) for f in features], - ["Point (11.6 52.1)", "Point (12.6 53.1)", - "Point (13.6 55.1)"], + ["Point (11.6 52.1)", "Point (12.6 53.1)", "Point (13.6 55.1)"], ) # all features fetched, accurate extent should be returned - self.assertEqual(vl.extent(), - QgsRectangle(11.6, 52.1, 13.6, 55.1)) + self.assertEqual(vl.extent(), QgsRectangle(11.6, 52.1, 13.6, 55.1)) def test_filter_rect(self): """ @@ -1237,7 +1375,7 @@ def test_filter_rect(self): with tempfile.TemporaryDirectory() as temp_dir: base_path = temp_dir.replace("\\", "/") endpoint = base_path + "/fake_qgis_http_endpoint" - with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f: + with open(sanitize(endpoint, ""), "w", encoding="utf8") as f: f.write( """ { @@ -1255,15 +1393,21 @@ def test_filter_rect(self): ) with open( - sanitize(endpoint, "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"), - "wt", + sanitize( + endpoint, + "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'", + ), + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":3,"value":[]}""") with open( - sanitize(endpoint, "/Locations?$top=2&$count=false&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"), - "wt", + sanitize( + endpoint, + "/Locations?$top=2&$count=false&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'", + ), + "w", encoding="utf8", ) as f: f.write( @@ -1318,8 +1462,11 @@ def test_filter_rect(self): ) with open( - sanitize(endpoint, "/Locations?$top=2&$skip=2&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"), - "wt", + sanitize( + endpoint, + "/Locations?$top=2&$skip=2&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'", + ), + "w", encoding="utf8", ) as f: f.write( @@ -1353,9 +1500,11 @@ def test_filter_rect(self): ) with open( - sanitize(endpoint, - "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 10 0, 10 80, 1 80, 1 0))'))"), - "wt", + sanitize( + endpoint, + "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 10 0, 10 80, 1 80, 1 0))'))", + ), + "w", encoding="utf8", ) as f: f.write( @@ -1407,9 +1556,11 @@ def test_filter_rect(self): ) with open( - sanitize(endpoint, - "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((10 0, 20 0, 20 80, 10 80, 10 0))'))"), - "wt", + sanitize( + endpoint, + "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((10 0, 20 0, 20 80, 10 80, 10 0))'))", + ), + "w", encoding="utf8", ) as f: f.write( @@ -1453,16 +1604,12 @@ def test_filter_rect(self): self.assertEqual(vl.wkbType(), Qgis.WkbType.PointZ) self.assertEqual(vl.featureCount(), 3) self.assertEqual(vl.crs().authid(), "EPSG:4326") - self.assertIn("Entity TypeLocation", - vl.htmlMetadata()) - self.assertIn(f'href="http://{endpoint}/Locations"', - vl.htmlMetadata()) + self.assertIn("Entity TypeLocation", vl.htmlMetadata()) + self.assertIn(f'href="http://{endpoint}/Locations"', vl.htmlMetadata()) # test retrieving subset of features from a filter rect only request = QgsFeatureRequest() - request.setFilterRect( - QgsRectangle(1, 0, 10, 80) - ) + request.setFilterRect(QgsRectangle(1, 0, 10, 80)) features = list(vl.getFeatures(request)) self.assertEqual([f["id"] for f in features], ["1", "3"]) @@ -1474,27 +1621,20 @@ def test_filter_rect(self): [f["name"] for f in features], ["Location 1", "Location 3"], ) - self.assertEqual( - [f["description"] for f in features], - ["Desc 1", "Desc 3"] - ) + self.assertEqual([f["description"] for f in features], ["Desc 1", "Desc 3"]) self.assertEqual( [f["properties"] for f in features], - [{"owner": "owner 1"}, - {"owner": "owner 3"}], + [{"owner": "owner 1"}, {"owner": "owner 3"}], ) self.assertEqual( [f.geometry().asWkt(1) for f in features], - ["Point (1.6 52.1)", - "Point (3.6 55.1)"], + ["Point (1.6 52.1)", "Point (3.6 55.1)"], ) # test retrieving a different subset with a different extent request = QgsFeatureRequest() - request.setFilterRect( - QgsRectangle(10, 0, 20, 80) - ) + request.setFilterRect(QgsRectangle(10, 0, 20, 80)) features = list(vl.getFeatures(request)) self.assertEqual([f["id"] for f in features], ["2"]) @@ -1506,10 +1646,7 @@ def test_filter_rect(self): [f["name"] for f in features], ["Location 2"], ) - self.assertEqual( - [f["description"] for f in features], - ["Desc 2"] - ) + self.assertEqual([f["description"] for f in features], ["Desc 2"]) self.assertEqual( [f["properties"] for f in features], [{"owner": "owner 2"}], @@ -1522,9 +1659,7 @@ def test_filter_rect(self): # a filter rect which covers all features request = QgsFeatureRequest() - request.setFilterRect( - QgsRectangle(0, 0, 20, 80) - ) + request.setFilterRect(QgsRectangle(0, 0, 20, 80)) features = list(vl.getFeatures(request)) self.assertEqual([f["id"] for f in features], ["1", "3", "2"]) @@ -1540,7 +1675,7 @@ def test_extent_limit(self): with tempfile.TemporaryDirectory() as temp_dir: base_path = temp_dir.replace("\\", "/") endpoint = base_path + "/fake_qgis_http_endpoint" - with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f: + with open(sanitize(endpoint, ""), "w", encoding="utf8") as f: f.write( """ { @@ -1558,17 +1693,21 @@ def test_extent_limit(self): ) with open( - sanitize(endpoint, - "/Locations?$top=0&$count=true&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 10 0, 10 80, 1 80, 1 0))'))"), - "wt", + sanitize( + endpoint, + "/Locations?$top=0&$count=true&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 10 0, 10 80, 1 80, 1 0))'))", + ), + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":2,"value":[]}""") with open( - sanitize(endpoint, - "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 10 0, 10 80, 1 80, 1 0))'))"), - "wt", + sanitize( + endpoint, + "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 10 0, 10 80, 1 80, 1 0))'))", + ), + "w", encoding="utf8", ) as f: f.write( @@ -1621,9 +1760,11 @@ def test_extent_limit(self): ) with open( - sanitize(endpoint, - "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 3 0, 3 50, 1 50, 1 0))'))"), - "wt", + sanitize( + endpoint, + "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 3 0, 3 50, 1 50, 1 0))'))", + ), + "w", encoding="utf8", ) as f: f.write( @@ -1668,18 +1809,14 @@ def test_extent_limit(self): # should use the hardcoded extent limit as the initial guess, not global extents self.assertEqual(vl.extent(), QgsRectangle(1, 0, 10, 80)) self.assertEqual(vl.crs().authid(), "EPSG:4326") - self.assertIn("Entity TypeLocation", - vl.htmlMetadata()) - self.assertIn(f'href="http://{endpoint}/Locations"', - vl.htmlMetadata()) + self.assertIn("Entity TypeLocation", vl.htmlMetadata()) + self.assertIn(f'href="http://{endpoint}/Locations"', vl.htmlMetadata()) # test retrieving a subset of the features from the layer, # using a filter rect which only covers a part of the hardcoded # provider's extent request = QgsFeatureRequest() - request.setFilterRect( - QgsRectangle(1, 0, 3, 50) - ) + request.setFilterRect(QgsRectangle(1, 0, 3, 50)) features = list(vl.getFeatures(request)) self.assertEqual([f["id"] for f in features], ["1"]) @@ -1691,10 +1828,7 @@ def test_extent_limit(self): [f["name"] for f in features], ["Location 1"], ) - self.assertEqual( - [f["description"] for f in features], - ["Desc 1"] - ) + self.assertEqual([f["description"] for f in features], ["Desc 1"]) self.assertEqual( [f["properties"] for f in features], [{"owner": "owner 1"}], @@ -1718,25 +1852,27 @@ def test_extent_limit(self): [f["name"] for f in features], ["Location 1", "Location 3"], ) - self.assertEqual( - [f["description"] for f in features], - ["Desc 1", "Desc 3"] - ) + self.assertEqual([f["description"] for f in features], ["Desc 1", "Desc 3"]) self.assertEqual( [f["properties"] for f in features], - [{"owner": "owner 1"}, - {"owner": "owner 3"}], + [{"owner": "owner 1"}, {"owner": "owner 3"}], ) self.assertEqual( [f.geometry().asWkt(1) for f in features], - ["Point (1.6 52.1)", - "Point (3.6 55.1)"], + ["Point (1.6 52.1)", "Point (3.6 55.1)"], ) # should have accurate layer extent now - self.assertEqual(vl.extent(), QgsRectangle(1.62337299999999995, 52.13201699999999761, 3.62337299999999995, - 55.13201699999999761)) + self.assertEqual( + vl.extent(), + QgsRectangle( + 1.62337299999999995, + 52.13201699999999761, + 3.62337299999999995, + 55.13201699999999761, + ), + ) def test_subset_string(self): """ @@ -1746,7 +1882,7 @@ def test_subset_string(self): with tempfile.TemporaryDirectory() as temp_dir: base_path = temp_dir.replace("\\", "/") endpoint = base_path + "/fake_qgis_http_endpoint" - with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f: + with open(sanitize(endpoint, ""), "w", encoding="utf8") as f: f.write( """ { @@ -1764,25 +1900,31 @@ def test_subset_string(self): ) with open( - sanitize(endpoint, - "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"), - "wt", + sanitize( + endpoint, + "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'", + ), + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":2,"value":[]}""") with open( - sanitize(endpoint, - "/Locations?$top=0&$count=true&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (name eq 'Location 1')"), - "wt", + sanitize( + endpoint, + "/Locations?$top=0&$count=true&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (name eq 'Location 1')", + ), + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":1,"value":[]}""") with open( - sanitize(endpoint, - "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 3 0, 3 50, 1 50, 1 0))')) and (name eq 'Location 1')"), - "wt", + sanitize( + endpoint, + "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 3 0, 3 50, 1 50, 1 0))')) and (name eq 'Location 1')", + ), + "w", encoding="utf8", ) as f: f.write( @@ -1816,9 +1958,11 @@ def test_subset_string(self): ) with open( - sanitize(endpoint, - "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 3 0, 3 50, 1 50, 1 0))'))"), - "wt", + sanitize( + endpoint, + "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 3 0, 3 50, 1 50, 1 0))'))", + ), + "w", encoding="utf8", ) as f: f.write( @@ -1863,21 +2007,20 @@ def test_subset_string(self): vl.setSubsetString("name eq 'Location 1'") self.assertEqual(vl.subsetString(), "name eq 'Location 1'") - self.assertEqual(vl.source(), f" type=PointZ entity='Location' pageSize='2' url='http://{endpoint}' sql=name eq 'Location 1'") + self.assertEqual( + vl.source(), + f" type=PointZ entity='Location' pageSize='2' url='http://{endpoint}' sql=name eq 'Location 1'", + ) self.assertEqual(vl.featureCount(), 1) self.assertEqual(vl.crs().authid(), "EPSG:4326") - self.assertIn("Entity TypeLocation", - vl.htmlMetadata()) - self.assertIn(f'href="http://{endpoint}/Locations"', - vl.htmlMetadata()) + self.assertIn("Entity TypeLocation", vl.htmlMetadata()) + self.assertIn(f'href="http://{endpoint}/Locations"', vl.htmlMetadata()) # test retrieving a subset of features, using a request which # must be combined with the layer's subset filter request = QgsFeatureRequest() - request.setFilterRect( - QgsRectangle(1, 0, 3, 50) - ) + request.setFilterRect(QgsRectangle(1, 0, 3, 50)) features = list(vl.getFeatures(request)) self.assertEqual([f["id"] for f in features], ["1"]) @@ -1889,10 +2032,7 @@ def test_subset_string(self): [f["name"] for f in features], ["Location 1"], ) - self.assertEqual( - [f["description"] for f in features], - ["Desc 1"] - ) + self.assertEqual([f["description"] for f in features], ["Desc 1"]) self.assertEqual( [f["properties"] for f in features], [{"owner": "owner 1"}], @@ -1917,10 +2057,7 @@ def test_subset_string(self): [f["name"] for f in features], ["Location 1"], ) - self.assertEqual( - [f["description"] for f in features], - ["Desc 1"] - ) + self.assertEqual([f["description"] for f in features], ["Desc 1"]) self.assertEqual( [f["properties"] for f in features], [{"owner": "owner 1"}], @@ -1932,10 +2069,15 @@ def test_subset_string(self): ) # should have accurate layer extent now - self.assertEqual(vl.extent(), QgsRectangle(1.62337299999999995, - 52.13201699999999761, - 1.62337299999999995, - 52.13201699999999761)) + self.assertEqual( + vl.extent(), + QgsRectangle( + 1.62337299999999995, + 52.13201699999999761, + 1.62337299999999995, + 52.13201699999999761, + ), + ) def test_feature_limit(self): """ @@ -1945,7 +2087,7 @@ def test_feature_limit(self): with tempfile.TemporaryDirectory() as temp_dir: base_path = temp_dir.replace("\\", "/") endpoint = base_path + "/fake_qgis_http_endpoint" - with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f: + with open(sanitize(endpoint, ""), "w", encoding="utf8") as f: f.write( """ { @@ -1963,25 +2105,31 @@ def test_feature_limit(self): ) with open( - sanitize(endpoint, - "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'"), - "wt", + sanitize( + endpoint, + "/Locations?$top=0&$count=true&$filter=location/type eq 'Point' or location/geometry/type eq 'Point'", + ), + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":3,"value":[]}""") with open( - sanitize(endpoint, - "/Locations?$top=0&$count=true&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (name eq 'Location 1')"), - "wt", + sanitize( + endpoint, + "/Locations?$top=0&$count=true&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (name eq 'Location 1')", + ), + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":1,"value":[]}""") with open( - sanitize(endpoint, - "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 3 0, 3 50, 1 50, 1 0))'))"), - "wt", + sanitize( + endpoint, + "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((1 0, 3 0, 3 50, 1 50, 1 0))'))", + ), + "w", encoding="utf8", ) as f: f.write( @@ -2014,9 +2162,11 @@ def test_feature_limit(self): ) with open( - sanitize(endpoint, - "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((0 0, 100 0, 100 150, 0 150, 0 0))'))"), - "wt", + sanitize( + endpoint, + "/Locations?$top=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((0 0, 100 0, 100 150, 0 150, 0 0))'))", + ), + "w", encoding="utf8", ) as f: f.write( @@ -2071,9 +2221,11 @@ def test_feature_limit(self): # Note -- top param here should be replaced by "top=1", NOT be the "top=2" parameter from the previous page's iot.nextLink url! with open( - sanitize(endpoint, - "/Locations?$top=1&$skip=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((0 0, 100 0, 100 150, 0 150, 0 0))'))"), - "wt", + sanitize( + endpoint, + "/Locations?$top=1&$skip=2&$count=false&$filter=(location/type eq 'Point' or location/geometry/type eq 'Point') and (geo.intersects(location, geography'Polygon ((0 0, 100 0, 100 150, 0 150, 0 0))'))", + ), + "w", encoding="utf8", ) as f: f.write( @@ -2121,9 +2273,7 @@ def test_feature_limit(self): # test retrieving a subset of the 3 features by using # a request with a filter rect only matching one of the features request = QgsFeatureRequest() - request.setFilterRect( - QgsRectangle(1, 0, 3, 50) - ) + request.setFilterRect(QgsRectangle(1, 0, 3, 50)) features = list(vl.getFeatures(request)) self.assertEqual([f["id"] for f in features], ["1"]) @@ -2135,10 +2285,7 @@ def test_feature_limit(self): [f["name"] for f in features], ["Location 1"], ) - self.assertEqual( - [f["description"] for f in features], - ["Desc 1"] - ) + self.assertEqual([f["description"] for f in features], ["Desc 1"]) self.assertEqual( [f["properties"] for f in features], [{"owner": "owner 1"}], @@ -2155,21 +2302,16 @@ def test_feature_limit(self): # skip/limit values (if it isn't, then we'll get no features # back since the dummy endpoint address used above won't match) request = QgsFeatureRequest() - request.setFilterRect( - QgsRectangle(0, 0, 100, 150) - ) + request.setFilterRect(QgsRectangle(0, 0, 100, 150)) features = list(vl.getFeatures(request)) - self.assertEqual([f["id"] for f in features], ['1', '2', '3']) + self.assertEqual([f["id"] for f in features], ["1", "2", "3"]) self.assertEqual( [f["selfLink"][-13:] for f in features], ["/Locations(1)", "/Locations(2)", "/Locations(3)"], ) # should have accurate layer extent now - self.assertEqual(vl.extent(), QgsRectangle(1.62337299999999995, - 52, - 82, - 53)) + self.assertEqual(vl.extent(), QgsRectangle(1.62337299999999995, 52, 82, 53)) def test_historical_location(self): """ @@ -2178,7 +2320,7 @@ def test_historical_location(self): with tempfile.TemporaryDirectory() as temp_dir: base_path = temp_dir.replace("\\", "/") endpoint = base_path + "/fake_qgis_http_endpoint" - with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f: + with open(sanitize(endpoint, ""), "w", encoding="utf8") as f: f.write( """ { @@ -2197,14 +2339,14 @@ def test_historical_location(self): with open( sanitize(endpoint, "/HistoricalLocations?$top=0&$count=true"), - "wt", + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":3,"value":[]}""") with open( sanitize(endpoint, "/HistoricalLocations?$top=2&$count=false"), - "wt", + "w", encoding="utf8", ) as f: f.write( @@ -2236,7 +2378,7 @@ def test_historical_location(self): with open( sanitize(endpoint, "/HistoricalLocations?$top=2&$skip=2"), - "wt", + "w", encoding="utf8", ) as f: f.write( @@ -2307,9 +2449,15 @@ def test_historical_location(self): self.assertEqual( [f["time"] for f in features], [ - QDateTime(QDate(2020, 3, 20), QTime(16, 35, 23, 384), Qt.TimeSpec(1)), - QDateTime(QDate(2021, 3, 20), QTime(16, 35, 23, 384), Qt.TimeSpec(1)), - QDateTime(QDate(2022, 3, 20), QTime(16, 35, 23, 384), Qt.TimeSpec(1)), + QDateTime( + QDate(2020, 3, 20), QTime(16, 35, 23, 384), Qt.TimeSpec(1) + ), + QDateTime( + QDate(2021, 3, 20), QTime(16, 35, 23, 384), Qt.TimeSpec(1) + ), + QDateTime( + QDate(2022, 3, 20), QTime(16, 35, 23, 384), Qt.TimeSpec(1) + ), ], ) @@ -2320,7 +2468,7 @@ def test_datastream(self): with tempfile.TemporaryDirectory() as temp_dir: base_path = temp_dir.replace("\\", "/") endpoint = base_path + "/fake_qgis_http_endpoint" - with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f: + with open(sanitize(endpoint, ""), "w", encoding="utf8") as f: f.write( """ { @@ -2339,14 +2487,14 @@ def test_datastream(self): with open( sanitize(endpoint, "/Datastreams?$top=0&$count=true"), - "wt", + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":3,"value":[]}""") with open( sanitize(endpoint, "/Datastreams?$top=2&$count=false"), - "wt", + "w", encoding="utf8", ) as f: f.write( @@ -2402,7 +2550,7 @@ def test_datastream(self): with open( sanitize(endpoint, "/Datastreams?$top=2&$skip=2"), - "wt", + "w", encoding="utf8", ) as f: f.write( @@ -2569,7 +2717,7 @@ def test_sensor(self): with tempfile.TemporaryDirectory() as temp_dir: base_path = temp_dir.replace("\\", "/") endpoint = base_path + "/fake_qgis_http_endpoint" - with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f: + with open(sanitize(endpoint, ""), "w", encoding="utf8") as f: f.write( """ { @@ -2588,14 +2736,14 @@ def test_sensor(self): with open( sanitize(endpoint, "/Sensors?$top=0&$count=true"), - "wt", + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":3,"value":[]}""") with open( sanitize(endpoint, "/Sensors?$top=2&$count=false"), - "wt", + "w", encoding="utf8", ) as f: f.write( @@ -2639,7 +2787,7 @@ def test_sensor(self): with open( sanitize(endpoint, "/Sensors?$top=2&$skip=2"), - "wt", + "w", encoding="utf8", ) as f: f.write( @@ -2738,7 +2886,7 @@ def test_observed_property(self): with tempfile.TemporaryDirectory() as temp_dir: base_path = temp_dir.replace("\\", "/") endpoint = base_path + "/fake_qgis_http_endpoint" - with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f: + with open(sanitize(endpoint, ""), "w", encoding="utf8") as f: f.write( """ { @@ -2757,14 +2905,14 @@ def test_observed_property(self): with open( sanitize(endpoint, "/ObservedProperties?$top=0&$count=true"), - "wt", + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":3,"value":[]}""") with open( sanitize(endpoint, "/ObservedProperties?$top=2&$count=false"), - "wt", + "w", encoding="utf8", ) as f: f.write( @@ -2806,7 +2954,7 @@ def test_observed_property(self): with open( sanitize(endpoint, "/ObservedProperties?$top=2&$skip=2"), - "wt", + "w", encoding="utf8", ) as f: f.write( @@ -2912,7 +3060,7 @@ def test_observation(self): with tempfile.TemporaryDirectory() as temp_dir: base_path = temp_dir.replace("\\", "/") endpoint = base_path + "/fake_qgis_http_endpoint" - with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f: + with open(sanitize(endpoint, ""), "w", encoding="utf8") as f: f.write( """ { @@ -2931,14 +3079,14 @@ def test_observation(self): with open( sanitize(endpoint, "/Observations?$top=0&$count=true"), - "wt", + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":3,"value":[]}""") with open( sanitize(endpoint, "/Observations?$top=2&$count=false"), - "wt", + "w", encoding="utf8", ) as f: f.write( @@ -2986,7 +3134,7 @@ def test_observation(self): with open( sanitize(endpoint, "/Observations?$top=2&$skip=2"), - "wt", + "w", encoding="utf8", ) as f: f.write( @@ -3124,7 +3272,7 @@ def test_feature_of_interest(self): with tempfile.TemporaryDirectory() as temp_dir: base_path = temp_dir.replace("\\", "/") endpoint = base_path + "/fake_qgis_http_endpoint" - with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f: + with open(sanitize(endpoint, ""), "w", encoding="utf8") as f: f.write( """ { @@ -3142,15 +3290,21 @@ def test_feature_of_interest(self): ) with open( - sanitize(endpoint, "/FeaturesOfInterest?$top=0&$count=true&$filter=feature/type eq 'Point' or feature/geometry/type eq 'Point'"), - "wt", + sanitize( + endpoint, + "/FeaturesOfInterest?$top=0&$count=true&$filter=feature/type eq 'Point' or feature/geometry/type eq 'Point'", + ), + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":3,"value":[]}""") with open( - sanitize(endpoint, "/FeaturesOfInterest?$top=2&$count=false&$filter=feature/type eq 'Point' or feature/geometry/type eq 'Point'"), - "wt", + sanitize( + endpoint, + "/FeaturesOfInterest?$top=2&$count=false&$filter=feature/type eq 'Point' or feature/geometry/type eq 'Point'", + ), + "w", encoding="utf8", ) as f: f.write( @@ -3210,8 +3364,11 @@ def test_feature_of_interest(self): ) with open( - sanitize(endpoint, "/FeaturesOfInterest?$top=2&$skip=2&$filter=feature/type eq 'Point' or feature/geometry/type eq 'Point'"), - "wt", + sanitize( + endpoint, + "/FeaturesOfInterest?$top=2&$skip=2&$filter=feature/type eq 'Point' or feature/geometry/type eq 'Point'", + ), + "w", encoding="utf8", ) as f: f.write( @@ -3292,32 +3449,51 @@ def test_feature_of_interest(self): self.assertEqual([f["id"] for f in features], ["1", "2", "3"]) self.assertEqual( [f["selfLink"][-22:] for f in features], - ["/FeaturesOfInterest(1)", "/FeaturesOfInterest(2)", "/FeaturesOfInterest(3)"], + [ + "/FeaturesOfInterest(1)", + "/FeaturesOfInterest(2)", + "/FeaturesOfInterest(3)", + ], ) self.assertEqual( [f["name"] for f in features], - ['SAM.09.LAA.822.7.1', 'SAM.09.LOB.823.7.1', 'SAM.09.LOB.824.1.1'], + ["SAM.09.LAA.822.7.1", "SAM.09.LOB.823.7.1", "SAM.09.LOB.824.1.1"], ) self.assertEqual( [f["description"] for f in features], - ['Air quality sample SAM.09.LAA.822.7.1', None, 'Air quality sample SAM.09.LOB.824.1.1'] + [ + "Air quality sample SAM.09.LAA.822.7.1", + None, + "Air quality sample SAM.09.LOB.824.1.1", + ], ) self.assertEqual( [f["properties"] for f in features], - [{'localId': 'SAM.09.LAA.822.7.1', - 'metadata': 'http://luft.umweltbundesamt.at/inspire/wfs?service=WFS&version=2.0.0&request=GetFeature&typeName=aqd:AQD_Sample', - 'namespace': 'AT.0008.20.AQ', 'owner': 'http://luft.umweltbundesamt.at'}, - {'localId': 'SAM.09.LOB.823.7.1', - 'metadata': 'http://luft.umweltbundesamt.at/inspire/wfs?service=WFS&version=2.0.0&request=GetFeature&typeName=aqd:AQD_Sample', - 'namespace': 'AT.0008.20.AQ', 'owner': 'http://luft.umweltbundesamt.at'}, - {'localId': 'SAM.09.LOB.824.1.1', - 'metadata': 'http://luft.umweltbundesamt.at/inspire/wfs?service=WFS&version=2.0.0&request=GetFeature&typeName=aqd:AQD_Sample', - 'namespace': 'AT.0008.20.AQ', 'owner': 'http://luft.umweltbundesamt.at'}], + [ + { + "localId": "SAM.09.LAA.822.7.1", + "metadata": "http://luft.umweltbundesamt.at/inspire/wfs?service=WFS&version=2.0.0&request=GetFeature&typeName=aqd:AQD_Sample", + "namespace": "AT.0008.20.AQ", + "owner": "http://luft.umweltbundesamt.at", + }, + { + "localId": "SAM.09.LOB.823.7.1", + "metadata": "http://luft.umweltbundesamt.at/inspire/wfs?service=WFS&version=2.0.0&request=GetFeature&typeName=aqd:AQD_Sample", + "namespace": "AT.0008.20.AQ", + "owner": "http://luft.umweltbundesamt.at", + }, + { + "localId": "SAM.09.LOB.824.1.1", + "metadata": "http://luft.umweltbundesamt.at/inspire/wfs?service=WFS&version=2.0.0&request=GetFeature&typeName=aqd:AQD_Sample", + "namespace": "AT.0008.20.AQ", + "owner": "http://luft.umweltbundesamt.at", + }, + ], ) self.assertEqual( [f.geometry().asWkt(1) for f in features], - ['Point (16.4 48.2)', 'Point (16.5 48.2)', 'Point (16.5 48.2)'], + ["Point (16.4 48.2)", "Point (16.5 48.2)", "Point (16.5 48.2)"], ) def test_multidatastream_no_geometry(self): @@ -3327,7 +3503,7 @@ def test_multidatastream_no_geometry(self): with tempfile.TemporaryDirectory() as temp_dir: base_path = temp_dir.replace("\\", "/") endpoint = base_path + "/fake_qgis_http_endpoint" - with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f: + with open(sanitize(endpoint, ""), "w", encoding="utf8") as f: f.write( """ { @@ -3346,14 +3522,14 @@ def test_multidatastream_no_geometry(self): with open( sanitize(endpoint, "/MultiDatastreams?$top=0&$count=true"), - "wt", + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":3,"value":[]}""") with open( sanitize(endpoint, "/MultiDatastreams?$top=2&$count=false"), - "wt", + "w", encoding="utf8", ) as f: f.write( @@ -3414,7 +3590,7 @@ def test_multidatastream_no_geometry(self): with open( sanitize(endpoint, "/MultiDatastreams?$top=2&$skip=2"), - "wt", + "w", encoding="utf8", ) as f: f.write( @@ -3459,10 +3635,10 @@ def test_multidatastream_no_geometry(self): self.assertEqual(vl.wkbType(), Qgis.WkbType.NoGeometry) self.assertEqual(vl.featureCount(), 3) self.assertFalse(vl.crs().isValid()) - self.assertIn("Entity TypeMultiDatastream", - vl.htmlMetadata()) - self.assertIn(f'href="http://{endpoint}/MultiDatastreams"', - vl.htmlMetadata()) + self.assertIn("Entity TypeMultiDatastream", vl.htmlMetadata()) + self.assertIn( + f'href="http://{endpoint}/MultiDatastreams"', vl.htmlMetadata() + ) self.assertEqual( [f.name() for f in vl.fields()], @@ -3505,34 +3681,43 @@ def test_multidatastream_no_geometry(self): self.assertEqual([f["id"] for f in features], ["1", "2", "3"]) self.assertEqual( [f["selfLink"][-20:] for f in features], - ["/MultiDatastreams(1)", "/MultiDatastreams(2)", "/MultiDatastreams(3)"], + [ + "/MultiDatastreams(1)", + "/MultiDatastreams(2)", + "/MultiDatastreams(3)", + ], ) self.assertEqual( [f["name"] for f in features], ["MultiDatastream 1", "MultiDatastream 2", "MultiDatastream 3"], ) self.assertEqual( - [f["description"] for f in features], - ["Desc 1", "Desc 2", "Desc 3"] + [f["description"] for f in features], ["Desc 1", "Desc 2", "Desc 3"] ) self.assertEqual( [f["unitOfMeasurements"] for f in features], [ - [{ - "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3", - "name": "ug.m-3", - "symbol": "ug.m-3", - }], - [{ - "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3", - "name": "ug.m-3", - "symbol": "ug.m-3", - }], - [{ - "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3", - "name": "ug.m-3", - "symbol": "ug.m-3", - }], + [ + { + "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3", + "name": "ug.m-3", + "symbol": "ug.m-3", + } + ], + [ + { + "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3", + "name": "ug.m-3", + "symbol": "ug.m-3", + } + ], + [ + { + "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3", + "name": "ug.m-3", + "symbol": "ug.m-3", + } + ], ], ) self.assertEqual( @@ -3546,59 +3731,52 @@ def test_multidatastream_no_geometry(self): self.assertEqual( [f["multiObservationDataTypes"] for f in features], [ - ["http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement"], - ["http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement"], - ["http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement"], + [ + "http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement" + ], + [ + "http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement" + ], + [ + "http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement" + ], ], ) self.assertEqual( [f["phenomenonTimeStart"] for f in features], [ - QDateTime(QDate(2017, 12, 31), QTime(23, 0, 0, 0), - Qt.TimeSpec(1)), - QDateTime(QDate(2018, 12, 31), QTime(23, 0, 0, 0), - Qt.TimeSpec(1)), - QDateTime(QDate(2020, 12, 31), QTime(23, 0, 0, 0), - Qt.TimeSpec(1)), + QDateTime(QDate(2017, 12, 31), QTime(23, 0, 0, 0), Qt.TimeSpec(1)), + QDateTime(QDate(2018, 12, 31), QTime(23, 0, 0, 0), Qt.TimeSpec(1)), + QDateTime(QDate(2020, 12, 31), QTime(23, 0, 0, 0), Qt.TimeSpec(1)), ], ) self.assertEqual( [f["phenomenonTimeEnd"] for f in features], [ - QDateTime(QDate(2018, 1, 12), QTime(4, 0, 0, 0), - Qt.TimeSpec(1)), - QDateTime(QDate(2019, 1, 12), QTime(4, 0, 0, 0), - Qt.TimeSpec(1)), - QDateTime(QDate(2021, 1, 12), QTime(4, 0, 0, 0), - Qt.TimeSpec(1)), + QDateTime(QDate(2018, 1, 12), QTime(4, 0, 0, 0), Qt.TimeSpec(1)), + QDateTime(QDate(2019, 1, 12), QTime(4, 0, 0, 0), Qt.TimeSpec(1)), + QDateTime(QDate(2021, 1, 12), QTime(4, 0, 0, 0), Qt.TimeSpec(1)), ], ) self.assertEqual( [f["resultTimeStart"] for f in features], [ - QDateTime(QDate(2017, 12, 31), QTime(23, 30, 0, 0), - Qt.TimeSpec(1)), - QDateTime(QDate(2018, 12, 31), QTime(23, 30, 0, 0), - Qt.TimeSpec(1)), - QDateTime(QDate(2020, 12, 31), QTime(23, 30, 0, 0), - Qt.TimeSpec(1)), + QDateTime(QDate(2017, 12, 31), QTime(23, 30, 0, 0), Qt.TimeSpec(1)), + QDateTime(QDate(2018, 12, 31), QTime(23, 30, 0, 0), Qt.TimeSpec(1)), + QDateTime(QDate(2020, 12, 31), QTime(23, 30, 0, 0), Qt.TimeSpec(1)), ], ) self.assertEqual( [f["resultTimeEnd"] for f in features], [ - QDateTime(QDate(2017, 12, 31), QTime(23, 31, 0, 0), - Qt.TimeSpec(1)), - QDateTime(QDate(2018, 12, 31), QTime(23, 31, 0, 0), - Qt.TimeSpec(1)), - QDateTime(QDate(2020, 12, 31), QTime(23, 31, 0, 0), - Qt.TimeSpec(1)), + QDateTime(QDate(2017, 12, 31), QTime(23, 31, 0, 0), Qt.TimeSpec(1)), + QDateTime(QDate(2018, 12, 31), QTime(23, 31, 0, 0), Qt.TimeSpec(1)), + QDateTime(QDate(2020, 12, 31), QTime(23, 31, 0, 0), Qt.TimeSpec(1)), ], ) self.assertEqual( [f["properties"] for f in features], - [{"owner": "owner 1"}, {"owner": "owner 2"}, - {"owner": "owner 3"}], + [{"owner": "owner 1"}, {"owner": "owner 2"}, {"owner": "owner 3"}], ) def test_multidatastream_polygons(self): @@ -3608,7 +3786,7 @@ def test_multidatastream_polygons(self): with tempfile.TemporaryDirectory() as temp_dir: base_path = temp_dir.replace("\\", "/") endpoint = base_path + "/fake_qgis_http_endpoint" - with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f: + with open(sanitize(endpoint, ""), "w", encoding="utf8") as f: f.write( """ { @@ -3626,15 +3804,21 @@ def test_multidatastream_polygons(self): ) with open( - sanitize(endpoint, "/MultiDatastreams?$top=0&$count=true&$filter=observedArea/type eq 'Polygon' or observedArea/geometry/type eq 'Polygon'"), - "wt", + sanitize( + endpoint, + "/MultiDatastreams?$top=0&$count=true&$filter=observedArea/type eq 'Polygon' or observedArea/geometry/type eq 'Polygon'", + ), + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":3,"value":[]}""") with open( - sanitize(endpoint, "/MultiDatastreams?$top=2&$count=false&$filter=observedArea/type eq 'Polygon' or observedArea/geometry/type eq 'Polygon'"), - "wt", + sanitize( + endpoint, + "/MultiDatastreams?$top=2&$count=false&$filter=observedArea/type eq 'Polygon' or observedArea/geometry/type eq 'Polygon'", + ), + "w", encoding="utf8", ) as f: f.write( @@ -3710,8 +3894,11 @@ def test_multidatastream_polygons(self): ) with open( - sanitize(endpoint, "/MultiDatastreams?$top=2&$skip=2&$filter=observedArea/type eq 'Polygon' or observedArea/geometry/type eq 'Polygon'"), - "wt", + sanitize( + endpoint, + "/MultiDatastreams?$top=2&$skip=2&$filter=observedArea/type eq 'Polygon' or observedArea/geometry/type eq 'Polygon'", + ), + "w", encoding="utf8", ) as f: f.write( @@ -3763,11 +3950,11 @@ def test_multidatastream_polygons(self): self.assertEqual(vl.storageType(), "OGC SensorThings API") self.assertEqual(vl.wkbType(), Qgis.WkbType.MultiPolygonZ) self.assertEqual(vl.featureCount(), 3) - self.assertEqual(vl.crs().authid(), 'EPSG:4326') - self.assertIn("Entity TypeMultiDatastream", - vl.htmlMetadata()) - self.assertIn(f'href="http://{endpoint}/MultiDatastreams"', - vl.htmlMetadata()) + self.assertEqual(vl.crs().authid(), "EPSG:4326") + self.assertIn("Entity TypeMultiDatastream", vl.htmlMetadata()) + self.assertIn( + f'href="http://{endpoint}/MultiDatastreams"', vl.htmlMetadata() + ) self.assertEqual( [f.name() for f in vl.fields()], @@ -3810,34 +3997,43 @@ def test_multidatastream_polygons(self): self.assertEqual([f["id"] for f in features], ["1", "2", "3"]) self.assertEqual( [f["selfLink"][-20:] for f in features], - ["/MultiDatastreams(1)", "/MultiDatastreams(2)", "/MultiDatastreams(3)"], + [ + "/MultiDatastreams(1)", + "/MultiDatastreams(2)", + "/MultiDatastreams(3)", + ], ) self.assertEqual( [f["name"] for f in features], ["MultiDatastream 1", "MultiDatastream 2", "MultiDatastream 3"], ) self.assertEqual( - [f["description"] for f in features], - ["Desc 1", "Desc 2", "Desc 3"] + [f["description"] for f in features], ["Desc 1", "Desc 2", "Desc 3"] ) self.assertEqual( [f["unitOfMeasurements"] for f in features], [ - [{ - "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3", - "name": "ug.m-3", - "symbol": "ug.m-3", - }], - [{ - "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3", - "name": "ug.m-3", - "symbol": "ug.m-3", - }], - [{ - "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3", - "name": "ug.m-3", - "symbol": "ug.m-3", - }], + [ + { + "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3", + "name": "ug.m-3", + "symbol": "ug.m-3", + } + ], + [ + { + "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3", + "name": "ug.m-3", + "symbol": "ug.m-3", + } + ], + [ + { + "definition": "http://dd.eionet.europa.eu/vocabulary/uom/concentration/ug.m-3", + "name": "ug.m-3", + "symbol": "ug.m-3", + } + ], ], ) self.assertEqual( @@ -3851,65 +4047,60 @@ def test_multidatastream_polygons(self): self.assertEqual( [f["multiObservationDataTypes"] for f in features], [ - ["http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement"], - ["http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement"], - ["http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement"], + [ + "http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement" + ], + [ + "http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement" + ], + [ + "http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement" + ], ], ) self.assertEqual( [f["phenomenonTimeStart"] for f in features], [ - QDateTime(QDate(2017, 12, 31), QTime(23, 0, 0, 0), - Qt.TimeSpec(1)), - QDateTime(QDate(2018, 12, 31), QTime(23, 0, 0, 0), - Qt.TimeSpec(1)), - QDateTime(QDate(2020, 12, 31), QTime(23, 0, 0, 0), - Qt.TimeSpec(1)), + QDateTime(QDate(2017, 12, 31), QTime(23, 0, 0, 0), Qt.TimeSpec(1)), + QDateTime(QDate(2018, 12, 31), QTime(23, 0, 0, 0), Qt.TimeSpec(1)), + QDateTime(QDate(2020, 12, 31), QTime(23, 0, 0, 0), Qt.TimeSpec(1)), ], ) self.assertEqual( [f["phenomenonTimeEnd"] for f in features], [ - QDateTime(QDate(2018, 1, 12), QTime(4, 0, 0, 0), - Qt.TimeSpec(1)), - QDateTime(QDate(2019, 1, 12), QTime(4, 0, 0, 0), - Qt.TimeSpec(1)), - QDateTime(QDate(2021, 1, 12), QTime(4, 0, 0, 0), - Qt.TimeSpec(1)), + QDateTime(QDate(2018, 1, 12), QTime(4, 0, 0, 0), Qt.TimeSpec(1)), + QDateTime(QDate(2019, 1, 12), QTime(4, 0, 0, 0), Qt.TimeSpec(1)), + QDateTime(QDate(2021, 1, 12), QTime(4, 0, 0, 0), Qt.TimeSpec(1)), ], ) self.assertEqual( [f["resultTimeStart"] for f in features], [ - QDateTime(QDate(2017, 12, 31), QTime(23, 30, 0, 0), - Qt.TimeSpec(1)), - QDateTime(QDate(2018, 12, 31), QTime(23, 30, 0, 0), - Qt.TimeSpec(1)), - QDateTime(QDate(2020, 12, 31), QTime(23, 30, 0, 0), - Qt.TimeSpec(1)), + QDateTime(QDate(2017, 12, 31), QTime(23, 30, 0, 0), Qt.TimeSpec(1)), + QDateTime(QDate(2018, 12, 31), QTime(23, 30, 0, 0), Qt.TimeSpec(1)), + QDateTime(QDate(2020, 12, 31), QTime(23, 30, 0, 0), Qt.TimeSpec(1)), ], ) self.assertEqual( [f["resultTimeEnd"] for f in features], [ - QDateTime(QDate(2017, 12, 31), QTime(23, 31, 0, 0), - Qt.TimeSpec(1)), - QDateTime(QDate(2018, 12, 31), QTime(23, 31, 0, 0), - Qt.TimeSpec(1)), - QDateTime(QDate(2020, 12, 31), QTime(23, 31, 0, 0), - Qt.TimeSpec(1)), + QDateTime(QDate(2017, 12, 31), QTime(23, 31, 0, 0), Qt.TimeSpec(1)), + QDateTime(QDate(2018, 12, 31), QTime(23, 31, 0, 0), Qt.TimeSpec(1)), + QDateTime(QDate(2020, 12, 31), QTime(23, 31, 0, 0), Qt.TimeSpec(1)), ], ) self.assertEqual( [f["properties"] for f in features], - [{"owner": "owner 1"}, {"owner": "owner 2"}, - {"owner": "owner 3"}], + [{"owner": "owner 1"}, {"owner": "owner 2"}, {"owner": "owner 3"}], ) self.assertEqual( [f.geometry().asWkt() for f in features], - ['Polygon ((100 0, 101 0, 101 1, 100 1, 100 0))', - 'Polygon ((102 0, 103 0, 103 1, 102 1, 102 0))', - 'Polygon ((103 0, 104 0, 104 1, 103 1, 103 0))'], + [ + "Polygon ((100 0, 101 0, 101 1, 100 1, 100 0))", + "Polygon ((102 0, 103 0, 103 1, 102 1, 102 0))", + "Polygon ((103 0, 104 0, 104 1, 103 1, 103 0))", + ], ) def test_feature_expansion(self): @@ -3919,7 +4110,7 @@ def test_feature_expansion(self): with tempfile.TemporaryDirectory() as temp_dir: base_path = temp_dir.replace("\\", "/") endpoint = base_path + "/fake_qgis_http_endpoint" - with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f: + with open(sanitize(endpoint, ""), "w", encoding="utf8") as f: f.write( """ { @@ -3937,17 +4128,21 @@ def test_feature_expansion(self): ) with open( - sanitize(endpoint, - "/Locations?$top=0&$count=true&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'"), - "wt", + sanitize( + endpoint, + "/Locations?$top=0&$count=true&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'", + ), + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":3,"value":[]}""") with open( - sanitize(endpoint, - "/Locations?$top=2&$count=false&$expand=Things($expand=Datastreams)&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'"), - "wt", + sanitize( + endpoint, + "/Locations?$top=2&$count=false&$expand=Things($expand=Datastreams)&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'", + ), + "w", encoding="utf8", ) as f: f.write( @@ -4123,9 +4318,11 @@ def test_feature_expansion(self): ) with open( - sanitize(endpoint, - "/Locations?$top=2&$skip=2&$expand=Things($expand=Datastreams)&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'"), - "wt", + sanitize( + endpoint, + "/Locations?$top=2&$skip=2&$expand=Things($expand=Datastreams)&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'", + ), + "w", encoding="utf8", ) as f: f.write( @@ -4223,26 +4420,35 @@ def test_feature_expansion(self): self.assertEqual(vl.wkbType(), Qgis.WkbType.MultiPolygonZ) self.assertEqual(vl.featureCount(), -1) - self.assertEqual(vl.crs().authid(), 'EPSG:4326') - self.assertIn("Entity TypeLocation", - vl.htmlMetadata()) - self.assertIn(f'href="http://{endpoint}/Locations"', - vl.htmlMetadata()) + self.assertEqual(vl.crs().authid(), "EPSG:4326") + self.assertIn("Entity TypeLocation", vl.htmlMetadata()) + self.assertIn(f'href="http://{endpoint}/Locations"', vl.htmlMetadata()) self.assertEqual( [f.name() for f in vl.fields()], - ['id', 'selfLink', 'name', 'description', 'properties', - 'Thing_id', 'Thing_selfLink', 'Thing_name', - 'Thing_description', 'Thing_properties', - 'Thing_Datastream_id', 'Thing_Datastream_selfLink', - 'Thing_Datastream_name', 'Thing_Datastream_description', - 'Thing_Datastream_unitOfMeasurement', - 'Thing_Datastream_observationType', - 'Thing_Datastream_properties', - 'Thing_Datastream_phenomenonTimeStart', - 'Thing_Datastream_phenomenonTimeEnd', - 'Thing_Datastream_resultTimeStart', - 'Thing_Datastream_resultTimeEnd'], + [ + "id", + "selfLink", + "name", + "description", + "properties", + "Thing_id", + "Thing_selfLink", + "Thing_name", + "Thing_description", + "Thing_properties", + "Thing_Datastream_id", + "Thing_Datastream_selfLink", + "Thing_Datastream_name", + "Thing_Datastream_description", + "Thing_Datastream_unitOfMeasurement", + "Thing_Datastream_observationType", + "Thing_Datastream_properties", + "Thing_Datastream_phenomenonTimeStart", + "Thing_Datastream_phenomenonTimeEnd", + "Thing_Datastream_resultTimeStart", + "Thing_Datastream_resultTimeEnd", + ], ) self.assertEqual( [f.type() for f in vl.fields()], @@ -4273,97 +4479,146 @@ def test_feature_expansion(self): # test retrieving all features from layer features = list(vl.getFeatures()) - self.assertEqual([f.id() for f in features], - [0, 1, 2, 3, 4, 5]) - self.assertEqual([f["id"] for f in features], - ["1", "1", "2", "2", "3", "3"]) + self.assertEqual([f.id() for f in features], [0, 1, 2, 3, 4, 5]) + self.assertEqual( + [f["id"] for f in features], ["1", "1", "2", "2", "3", "3"] + ) self.assertEqual( [f["selfLink"][-13:] for f in features], - ["/Locations(1)", "/Locations(1)", - "/Locations(2)", "/Locations(2)", - "/Locations(3)", "/Locations(3)"], + [ + "/Locations(1)", + "/Locations(1)", + "/Locations(2)", + "/Locations(2)", + "/Locations(3)", + "/Locations(3)", + ], ) self.assertEqual( [f["name"] for f in features], - ["Location 1", "Location 1", - "Location 2", "Location 2", - "Location 3", "Location 3"], + [ + "Location 1", + "Location 1", + "Location 2", + "Location 2", + "Location 3", + "Location 3", + ], ) self.assertEqual( [f["description"] for f in features], - ["Desc 1", "Desc 1", - "Desc 2", "Desc 2", - "Desc 3", "Desc 3"] + ["Desc 1", "Desc 1", "Desc 2", "Desc 2", "Desc 3", "Desc 3"], ) self.assertEqual( [f["properties"] for f in features], - [{'owner': 'owner 1'}, {'owner': 'owner 1'}, - {'owner': 'owner 2'}, {'owner': 'owner 2'}, - {'owner': 'owner 3'}, {'owner': 'owner 3'}] + [ + {"owner": "owner 1"}, + {"owner": "owner 1"}, + {"owner": "owner 2"}, + {"owner": "owner 2"}, + {"owner": "owner 3"}, + {"owner": "owner 3"}, + ], ) self.assertEqual( - [f["Thing_id"] for f in features], - ['1', '1', '2', '3', '8', '8'] + [f["Thing_id"] for f in features], ["1", "1", "2", "3", "8", "8"] ) self.assertEqual( [f["Thing_selfLink"][-10:] for f in features], - ['/Things(1)', '/Things(1)', '/Things(2)', '/Things(3)', - '/Things(8)', '/Things(8)'] + [ + "/Things(1)", + "/Things(1)", + "/Things(2)", + "/Things(3)", + "/Things(8)", + "/Things(8)", + ], ) self.assertEqual( [f["Thing_name"] for f in features], - ['Thing 1', 'Thing 1', 'Thing 2', 'Thing 3', 'Thing 8', - 'Thing 8'] + ["Thing 1", "Thing 1", "Thing 2", "Thing 3", "Thing 8", "Thing 8"], ) self.assertEqual( [f["Thing_description"] for f in features], - ['Description Thing 1', 'Description Thing 1', - 'Description Thing 2', 'Description Thing 3', - 'Description Thing 8', 'Description Thing 8'] + [ + "Description Thing 1", + "Description Thing 1", + "Description Thing 2", + "Description Thing 3", + "Description Thing 8", + "Description Thing 8", + ], ) self.assertEqual( [f["Thing_properties"] for f in features], - [{'countryCode': 'AT'}, {'countryCode': 'AT'}, - {'countryCode': 'AT'}, {'countryCode': 'AT'}, - {'countryCode': 'AT'}, {'countryCode': 'AT'}] + [ + {"countryCode": "AT"}, + {"countryCode": "AT"}, + {"countryCode": "AT"}, + {"countryCode": "AT"}, + {"countryCode": "AT"}, + {"countryCode": "AT"}, + ], ) self.assertEqual( [f["Thing_Datastream_id"] for f in features], - ['45', '46', '51', '52', '59', '60'] + ["45", "46", "51", "52", "59", "60"], ) self.assertEqual( [f["Thing_Datastream_selfLink"][-16:] for f in features], - ['/Datastreams(45)', '/Datastreams(46)', - '/Datastreams(51)', - '/Datastreams(52)', '/Datastreams(59)', - '/Datastreams(60)'] + [ + "/Datastreams(45)", + "/Datastreams(46)", + "/Datastreams(51)", + "/Datastreams(52)", + "/Datastreams(59)", + "/Datastreams(60)", + ], ) self.assertEqual( [f["Thing_Datastream_name"] for f in features], - ['Datastream 45', 'Datastream 46', 'Datastream 51', - 'Datastream 52', 'Datastream 59', 'Datastream 60'] + [ + "Datastream 45", + "Datastream 46", + "Datastream 51", + "Datastream 52", + "Datastream 59", + "Datastream 60", + ], ) self.assertEqual( [f["Thing_Datastream_description"] for f in features], - ['Description datastream 45', 'Description datastream 46', - 'Description datastream 51', 'Description datastream 52', - 'Description datastream 59', 'Description datastream 60'] + [ + "Description datastream 45", + "Description datastream 46", + "Description datastream 51", + "Description datastream 52", + "Description datastream 59", + "Description datastream 60", + ], ) self.assertEqual( [f["Thing_Datastream_properties"] for f in features], - [{'owner': 'someone'}, {'owner': 'someone'}, - {'owner': 'someone'}, {'owner': 'someone'}, - {'owner': 'someone'}, {'owner': 'someone'}] + [ + {"owner": "someone"}, + {"owner": "someone"}, + {"owner": "someone"}, + {"owner": "someone"}, + {"owner": "someone"}, + {"owner": "someone"}, + ], ) self.assertEqual( [f.geometry().asWkt() for f in features], - ['Polygon ((100 0, 101 0, 101 1, 100 1, 100 0))', - 'Polygon ((100 0, 101 0, 101 1, 100 1, 100 0))', - 'Polygon ((102 0, 103 0, 103 1, 102 1, 102 0))', - 'Polygon ((102 0, 103 0, 103 1, 102 1, 102 0))', - 'Polygon ((103 0, 104 0, 104 1, 103 1, 103 0))', - 'Polygon ((103 0, 104 0, 104 1, 103 1, 103 0))'], + [ + "Polygon ((100 0, 101 0, 101 1, 100 1, 100 0))", + "Polygon ((100 0, 101 0, 101 1, 100 1, 100 0))", + "Polygon ((102 0, 103 0, 103 1, 102 1, 102 0))", + "Polygon ((102 0, 103 0, 103 1, 102 1, 102 0))", + "Polygon ((103 0, 104 0, 104 1, 103 1, 103 0))", + "Polygon ((103 0, 104 0, 104 1, 103 1, 103 0))", + ], ) def test_feature_expansion_with_limit(self): @@ -4373,7 +4628,7 @@ def test_feature_expansion_with_limit(self): with tempfile.TemporaryDirectory() as temp_dir: base_path = temp_dir.replace("\\", "/") endpoint = base_path + "/fake_qgis_http_endpoint" - with open(sanitize(endpoint, ""), "wt", encoding="utf8") as f: + with open(sanitize(endpoint, ""), "w", encoding="utf8") as f: f.write( """ { @@ -4391,17 +4646,21 @@ def test_feature_expansion_with_limit(self): ) with open( - sanitize(endpoint, - "/Locations?$top=0&$count=true&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'"), - "wt", + sanitize( + endpoint, + "/Locations?$top=0&$count=true&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'", + ), + "w", encoding="utf8", ) as f: f.write("""{"@iot.count":3,"value":[]}""") with open( - sanitize(endpoint, - "/Locations?$top=2&$count=false&$expand=Things($expand=Datastreams($top=1))&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'"), - "wt", + sanitize( + endpoint, + "/Locations?$top=2&$count=false&$expand=Things($expand=Datastreams($top=1))&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'", + ), + "w", encoding="utf8", ) as f: f.write( @@ -4535,9 +4794,11 @@ def test_feature_expansion_with_limit(self): ) with open( - sanitize(endpoint, - "/Locations?$top=2&$skip=2&$expand=Things($expand=Datastreams($top=1))&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'"), - "wt", + sanitize( + endpoint, + "/Locations?$top=2&$skip=2&$expand=Things($expand=Datastreams($top=1))&$filter=location/type eq 'Polygon' or location/geometry/type eq 'Polygon'", + ), + "w", encoding="utf8", ) as f: f.write( @@ -4619,26 +4880,35 @@ def test_feature_expansion_with_limit(self): self.assertEqual(vl.wkbType(), Qgis.WkbType.MultiPolygonZ) self.assertEqual(vl.featureCount(), -1) - self.assertEqual(vl.crs().authid(), 'EPSG:4326') - self.assertIn("Entity TypeLocation", - vl.htmlMetadata()) - self.assertIn(f'href="http://{endpoint}/Locations"', - vl.htmlMetadata()) + self.assertEqual(vl.crs().authid(), "EPSG:4326") + self.assertIn("Entity TypeLocation", vl.htmlMetadata()) + self.assertIn(f'href="http://{endpoint}/Locations"', vl.htmlMetadata()) self.assertEqual( [f.name() for f in vl.fields()], - ['id', 'selfLink', 'name', 'description', 'properties', - 'Thing_id', 'Thing_selfLink', 'Thing_name', - 'Thing_description', 'Thing_properties', - 'Thing_Datastream_id', 'Thing_Datastream_selfLink', - 'Thing_Datastream_name', 'Thing_Datastream_description', - 'Thing_Datastream_unitOfMeasurement', - 'Thing_Datastream_observationType', - 'Thing_Datastream_properties', - 'Thing_Datastream_phenomenonTimeStart', - 'Thing_Datastream_phenomenonTimeEnd', - 'Thing_Datastream_resultTimeStart', - 'Thing_Datastream_resultTimeEnd'], + [ + "id", + "selfLink", + "name", + "description", + "properties", + "Thing_id", + "Thing_selfLink", + "Thing_name", + "Thing_description", + "Thing_properties", + "Thing_Datastream_id", + "Thing_Datastream_selfLink", + "Thing_Datastream_name", + "Thing_Datastream_description", + "Thing_Datastream_unitOfMeasurement", + "Thing_Datastream_observationType", + "Thing_Datastream_properties", + "Thing_Datastream_phenomenonTimeStart", + "Thing_Datastream_phenomenonTimeEnd", + "Thing_Datastream_resultTimeStart", + "Thing_Datastream_resultTimeEnd", + ], ) self.assertEqual( [f.type() for f in vl.fields()], @@ -4669,82 +4939,70 @@ def test_feature_expansion_with_limit(self): # test retrieving all features from layer features = list(vl.getFeatures()) - self.assertEqual([f.id() for f in features], - [0, 1, 2]) - self.assertEqual([f["id"] for f in features], - ["1", "2", "3"]) + self.assertEqual([f.id() for f in features], [0, 1, 2]) + self.assertEqual([f["id"] for f in features], ["1", "2", "3"]) self.assertEqual( [f["selfLink"][-13:] for f in features], - ["/Locations(1)", "/Locations(2)", - "/Locations(3)"], + ["/Locations(1)", "/Locations(2)", "/Locations(3)"], ) self.assertEqual( [f["name"] for f in features], - ["Location 1", "Location 2", - "Location 3"], + ["Location 1", "Location 2", "Location 3"], ) self.assertEqual( - [f["description"] for f in features], - ["Desc 1", "Desc 2", - "Desc 3"] + [f["description"] for f in features], ["Desc 1", "Desc 2", "Desc 3"] ) self.assertEqual( [f["properties"] for f in features], - [{'owner': 'owner 1'}, - {'owner': 'owner 2'}, - {'owner': 'owner 3'}] - ) - self.assertEqual( - [f["Thing_id"] for f in features], - ['1', '2', '8'] + [{"owner": "owner 1"}, {"owner": "owner 2"}, {"owner": "owner 3"}], ) + self.assertEqual([f["Thing_id"] for f in features], ["1", "2", "8"]) self.assertEqual( [f["Thing_selfLink"][-10:] for f in features], - ['/Things(1)', '/Things(2)', '/Things(8)'] + ["/Things(1)", "/Things(2)", "/Things(8)"], ) self.assertEqual( - [f["Thing_name"] for f in features], - ['Thing 1', 'Thing 2', 'Thing 8'] + [f["Thing_name"] for f in features], ["Thing 1", "Thing 2", "Thing 8"] ) self.assertEqual( [f["Thing_description"] for f in features], - ['Description Thing 1', 'Description Thing 2', - 'Description Thing 8'] + ["Description Thing 1", "Description Thing 2", "Description Thing 8"], ) self.assertEqual( [f["Thing_properties"] for f in features], - [{'countryCode': 'AT'}, {'countryCode': 'AT'}, - {'countryCode': 'AT'}] + [{"countryCode": "AT"}, {"countryCode": "AT"}, {"countryCode": "AT"}], ) self.assertEqual( - [f["Thing_Datastream_id"] for f in features], - ['45', '51', '59'] + [f["Thing_Datastream_id"] for f in features], ["45", "51", "59"] ) self.assertEqual( [f["Thing_Datastream_selfLink"][-16:] for f in features], - ['/Datastreams(45)', '/Datastreams(51)', - '/Datastreams(59)'] + ["/Datastreams(45)", "/Datastreams(51)", "/Datastreams(59)"], ) self.assertEqual( [f["Thing_Datastream_name"] for f in features], - ['Datastream 45', 'Datastream 51', 'Datastream 59'] + ["Datastream 45", "Datastream 51", "Datastream 59"], ) self.assertEqual( [f["Thing_Datastream_description"] for f in features], - ['Description datastream 45', 'Description datastream 51', - 'Description datastream 59'] + [ + "Description datastream 45", + "Description datastream 51", + "Description datastream 59", + ], ) self.assertEqual( [f["Thing_Datastream_properties"] for f in features], - [{'owner': 'someone'}, {'owner': 'someone'}, - {'owner': 'someone'}] + [{"owner": "someone"}, {"owner": "someone"}, {"owner": "someone"}], ) self.assertEqual( [f.geometry().asWkt() for f in features], - ['Polygon ((100 0, 101 0, 101 1, 100 1, 100 0))', - 'Polygon ((102 0, 103 0, 103 1, 102 1, 102 0))', - 'Polygon ((103 0, 104 0, 104 1, 103 1, 103 0))'], + [ + "Polygon ((100 0, 101 0, 101 1, 100 1, 100 0))", + "Polygon ((102 0, 103 0, 103 1, 102 1, 102 0))", + "Polygon ((103 0, 104 0, 104 1, 103 1, 103 0))", + ], ) def testDecodeUri(self): @@ -4811,7 +5069,7 @@ def testDecodeUri(self): "entity": "Location", "geometryType": "polygon", "authcfg": "abc", - "bounds": QgsRectangle(1, 2, 3, 4) + "bounds": QgsRectangle(1, 2, 3, 4), }, ) @@ -4824,7 +5082,7 @@ def testDecodeUri(self): "entity": "Location", "geometryType": "polygon", "authcfg": "abc", - "sql": "name eq 'test'" + "sql": "name eq 'test'", }, ) @@ -4837,7 +5095,7 @@ def testDecodeUri(self): "entity": "Location", "geometryType": "polygon", "authcfg": "abc", - "featureLimit": 50 + "featureLimit": 50, }, ) @@ -4850,12 +5108,14 @@ def testDecodeUri(self): "entity": "Location", "geometryType": "polygon", "authcfg": "abc", - "expandTo": [QgsSensorThingsExpansionDefinition( - Qgis.SensorThingsEntity.Thing, orderBy='description', - limit=5), + "expandTo": [ QgsSensorThingsExpansionDefinition( - Qgis.SensorThingsEntity.Datastream, - orderBy='time', limit=3)], + Qgis.SensorThingsEntity.Thing, orderBy="description", limit=5 + ), + QgsSensorThingsExpansionDefinition( + Qgis.SensorThingsEntity.Datastream, orderBy="time", limit=3 + ), + ], }, ) @@ -4917,7 +5177,7 @@ def testEncodeUri(self): "authcfg": "aaaaa", "entity": "location", "geometryType": "polygon", - "bounds": QgsRectangle(1, 2, 3, 4) + "bounds": QgsRectangle(1, 2, 3, 4), } uri = QgsProviderRegistry.instance().encodeUri("sensorthings", parts) self.assertEqual( @@ -4930,7 +5190,7 @@ def testEncodeUri(self): "authcfg": "aaaaa", "entity": "location", "geometryType": "polygon", - "sql": "name eq 'test'" + "sql": "name eq 'test'", } uri = QgsProviderRegistry.instance().encodeUri("sensorthings", parts) self.assertEqual( @@ -4943,7 +5203,7 @@ def testEncodeUri(self): "authcfg": "aaaaa", "entity": "location", "geometryType": "polygon", - "featureLimit": 50 + "featureLimit": 50, } uri = QgsProviderRegistry.instance().encodeUri("sensorthings", parts) self.assertEqual( @@ -4956,8 +5216,14 @@ def testEncodeUri(self): "authcfg": "aaaaa", "entity": "location", "geometryType": "polygon", - "expandTo": [QgsSensorThingsExpansionDefinition(Qgis.SensorThingsEntity.Thing, orderBy='description', limit=5), - QgsSensorThingsExpansionDefinition(Qgis.SensorThingsEntity.Datastream, orderBy='time', limit=3)] + "expandTo": [ + QgsSensorThingsExpansionDefinition( + Qgis.SensorThingsEntity.Thing, orderBy="description", limit=5 + ), + QgsSensorThingsExpansionDefinition( + Qgis.SensorThingsEntity.Datastream, orderBy="time", limit=3 + ), + ], } uri = QgsProviderRegistry.instance().encodeUri("sensorthings", parts) self.assertEqual( diff --git a/tests/src/python/test_provider_shapefile.py b/tests/src/python/test_provider_shapefile.py index 180e54da95ba..ab1291a54a4a 100644 --- a/tests/src/python/test_provider_shapefile.py +++ b/tests/src/python/test_provider_shapefile.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Matthias Kuhn' -__date__ = '2015-04-23' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Matthias Kuhn" +__date__ = "2015-04-23" +__copyright__ = "Copyright 2015, The QGIS Project" import glob import os @@ -47,10 +48,10 @@ def GDAL_COMPUTE_VERSION(maj, min, rev): - return ((maj) * 1000000 + (min) * 10000 + (rev) * 100) + return (maj) * 1000000 + (min) * 10000 + (rev) * 100 -class ErrorReceiver(): +class ErrorReceiver: def __init__(self): self.msg = None @@ -64,24 +65,24 @@ class TestPyQgsShapefileProvider(QgisTestCase, ProviderTestCase): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsShapefileProvider, cls).setUpClass() + super().setUpClass() # Create test layer cls.basetestpath = tempfile.mkdtemp() cls.repackfilepath = tempfile.mkdtemp() - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - for file in glob.glob(os.path.join(srcpath, 'shapefile.*')): + srcpath = os.path.join(TEST_DATA_DIR, "provider") + for file in glob.glob(os.path.join(srcpath, "shapefile.*")): shutil.copy(os.path.join(srcpath, file), cls.basetestpath) shutil.copy(os.path.join(srcpath, file), cls.repackfilepath) - for file in glob.glob(os.path.join(srcpath, 'shapefile_poly.*')): + for file in glob.glob(os.path.join(srcpath, "shapefile_poly.*")): shutil.copy(os.path.join(srcpath, file), cls.basetestpath) - cls.basetestfile = os.path.join(cls.basetestpath, 'shapefile.shp') - cls.repackfile = os.path.join(cls.repackfilepath, 'shapefile.shp') - cls.basetestpolyfile = os.path.join(cls.basetestpath, 'shapefile_poly.shp') - cls.vl = QgsVectorLayer(f'{cls.basetestfile}|layerid=0', 'test', 'ogr') + cls.basetestfile = os.path.join(cls.basetestpath, "shapefile.shp") + cls.repackfile = os.path.join(cls.repackfilepath, "shapefile.shp") + cls.basetestpolyfile = os.path.join(cls.basetestpath, "shapefile_poly.shp") + cls.vl = QgsVectorLayer(f"{cls.basetestfile}|layerid=0", "test", "ogr") assert cls.vl.isValid() cls.source = cls.vl.dataProvider() - cls.vl_poly = QgsVectorLayer(f'{cls.basetestpolyfile}|layerid=0', 'test', 'ogr') + cls.vl_poly = QgsVectorLayer(f"{cls.basetestpolyfile}|layerid=0", "test", "ogr") assert cls.vl_poly.isValid() cls.poly_provider = cls.vl_poly.dataProvider() @@ -94,7 +95,7 @@ def tearDownClass(cls): del cls.vl_poly for dirname in cls.dirs_to_cleanup: shutil.rmtree(dirname, True) - super(TestPyQgsShapefileProvider, cls).tearDownClass() + super().tearDownClass() def treat_time_as_string(self): return True @@ -105,166 +106,174 @@ def treat_datetime_as_string(self): def getSource(self): tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - for file in glob.glob(os.path.join(srcpath, 'shapefile.*')): + srcpath = os.path.join(TEST_DATA_DIR, "provider") + for file in glob.glob(os.path.join(srcpath, "shapefile.*")): shutil.copy(os.path.join(srcpath, file), tmpdir) - datasource = os.path.join(tmpdir, 'shapefile.shp') + datasource = os.path.join(tmpdir, "shapefile.shp") - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") return vl def getEditableLayer(self): return self.getSource() def enableCompiler(self): - QgsSettings().setValue('/qgis/compileExpressions', True) + QgsSettings().setValue("/qgis/compileExpressions", True) return True def disableCompiler(self): - QgsSettings().setValue('/qgis/compileExpressions', False) + QgsSettings().setValue("/qgis/compileExpressions", False) def uncompiledFilters(self): - filters = {'name ILIKE \'QGIS\'', - '"name" NOT LIKE \'Ap%\'', - '"name" NOT ILIKE \'QGIS\'', - '"name" NOT ILIKE \'pEAR\'', - 'name <> \'Apple\'', - '"name" <> \'apple\'', - '(name = \'Apple\') is not null', - 'name ILIKE \'aPple\'', - 'name ILIKE \'%pp%\'', - 'cnt = 1100 % 1000', - '"name" || \' \' || "name" = \'Orange Orange\'', - '"name" || \' \' || "cnt" = \'Orange 100\'', - '\'x\' || "name" IS NOT NULL', - '\'x\' || "name" IS NULL', - 'cnt = 10 ^ 2', - '"name" ~ \'[OP]ra[gne]+\'', - 'false and NULL', - 'true and NULL', - 'NULL and false', - 'NULL and true', - 'NULL and NULL', - 'false or NULL', - 'true or NULL', - 'NULL or false', - 'NULL or true', - 'NULL or NULL', - 'not name = \'Apple\'', - 'not name = \'Apple\' or name = \'Apple\'', - 'not name = \'Apple\' or not name = \'Apple\'', - 'not name = \'Apple\' and pk = 4', - 'not name = \'Apple\' and not pk = 4', - 'num_char IN (2, 4, 5)', - '-cnt > 0', - '-cnt < 0', - '-cnt - 1 = -101', - '-(-cnt) = 100', - '-(cnt) = -(100)', - 'sqrt(pk) >= 2', - 'radians(cnt) < 2', - 'degrees(pk) <= 200', - 'abs(cnt) <= 200', - 'cos(pk) < 0', - 'sin(pk) < 0', - 'tan(pk) < 0', - 'acos(-1) < pk', - 'asin(1) < pk', - 'atan(3.14) < pk', - 'atan2(3.14, pk) < 1', - 'exp(pk) < 10', - 'ln(pk) <= 1', - 'log(3, pk) <= 1', - 'log10(pk) < 0.5', - 'round(3.14) <= pk', - 'round(0.314,1) * 10 = pk', - 'floor(3.14) <= pk', - 'ceil(3.14) <= pk', - 'pk < pi()', - 'round(cnt / 66.67) <= 2', - 'floor(cnt / 66.67) <= 2', - 'ceil(cnt / 66.67) <= 2', - 'pk < pi() / 2', - 'pk = char(51)', - 'pk = coalesce(NULL,3,4)', - 'lower(name) = \'apple\'', - 'upper(name) = \'APPLE\'', - 'name = trim(\' Apple \')', - 'x($geometry) < -70', - 'y($geometry) > 70', - 'xmin($geometry) < -70', - 'ymin($geometry) > 70', - 'xmax($geometry) < -70', - 'ymax($geometry) > 70', - 'disjoint($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', - 'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', - 'contains(geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'),$geometry)', - 'distance($geometry,geom_from_wkt( \'Point (-70 70)\')) > 7', - 'intersects($geometry,geom_from_gml( \'-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1\'))', - 'x($geometry) < -70', - 'y($geometry) > 79', - 'xmin($geometry) < -70', - 'ymin($geometry) < 76', - 'xmax($geometry) > -68', - 'ymax($geometry) > 80', - 'area($geometry) > 10', - 'perimeter($geometry) < 12', - 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\')) = \'FF2FF1212\'', - 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'), \'****F****\')', - 'crosses($geometry,geom_from_wkt( \'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)\'))', - 'overlaps($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'))', - 'within($geometry,geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - 'overlaps(translate($geometry,-1,-1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - 'overlaps(buffer($geometry,1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - 'intersects(centroid($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', - 'intersects(point_on_surface($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', - '"dt" <= format_date(make_datetime(2020, 5, 4, 12, 13, 14), \'yyyy-MM-dd hh:mm:ss\')', - '"dt" < format_date(make_date(2020, 5, 4), \'yyyy-MM-dd hh:mm:ss\')', - '"dt" = format_date(to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\'),\'yyyy-MM-dd hh:mm:ss\')', - """dt BETWEEN format_date(make_datetime(2020, 5, 3, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss') AND format_date(make_datetime(2020, 5, 4, 12, 14, 14), 'yyyy-MM-dd hh:mm:ss')""", - """dt NOT BETWEEN format_date(make_datetime(2020, 5, 3, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss') AND format_date(make_datetime(2020, 5, 4, 12, 14, 14), 'yyyy-MM-dd hh:mm:ss')""", - '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')', - 'to_time("time") >= make_time(12, 14, 14)', - 'to_time("time") = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')', - 'to_datetime("dt", \'yyyy-MM-dd hh:mm:ss\') + make_interval(days:=1) <= make_datetime(2020, 5, 4, 12, 13, 14)', - 'to_datetime("dt", \'yyyy-MM-dd hh:mm:ss\') + make_interval(days:=0.01) <= make_datetime(2020, 5, 4, 12, 13, 14)', - 'cnt BETWEEN -200 AND 200' # NoUnaryMinus - } + filters = { + "name ILIKE 'QGIS'", + "\"name\" NOT LIKE 'Ap%'", + "\"name\" NOT ILIKE 'QGIS'", + "\"name\" NOT ILIKE 'pEAR'", + "name <> 'Apple'", + "\"name\" <> 'apple'", + "(name = 'Apple') is not null", + "name ILIKE 'aPple'", + "name ILIKE '%pp%'", + "cnt = 1100 % 1000", + "\"name\" || ' ' || \"name\" = 'Orange Orange'", + "\"name\" || ' ' || \"cnt\" = 'Orange 100'", + "'x' || \"name\" IS NOT NULL", + "'x' || \"name\" IS NULL", + "cnt = 10 ^ 2", + "\"name\" ~ '[OP]ra[gne]+'", + "false and NULL", + "true and NULL", + "NULL and false", + "NULL and true", + "NULL and NULL", + "false or NULL", + "true or NULL", + "NULL or false", + "NULL or true", + "NULL or NULL", + "not name = 'Apple'", + "not name = 'Apple' or name = 'Apple'", + "not name = 'Apple' or not name = 'Apple'", + "not name = 'Apple' and pk = 4", + "not name = 'Apple' and not pk = 4", + "num_char IN (2, 4, 5)", + "-cnt > 0", + "-cnt < 0", + "-cnt - 1 = -101", + "-(-cnt) = 100", + "-(cnt) = -(100)", + "sqrt(pk) >= 2", + "radians(cnt) < 2", + "degrees(pk) <= 200", + "abs(cnt) <= 200", + "cos(pk) < 0", + "sin(pk) < 0", + "tan(pk) < 0", + "acos(-1) < pk", + "asin(1) < pk", + "atan(3.14) < pk", + "atan2(3.14, pk) < 1", + "exp(pk) < 10", + "ln(pk) <= 1", + "log(3, pk) <= 1", + "log10(pk) < 0.5", + "round(3.14) <= pk", + "round(0.314,1) * 10 = pk", + "floor(3.14) <= pk", + "ceil(3.14) <= pk", + "pk < pi()", + "round(cnt / 66.67) <= 2", + "floor(cnt / 66.67) <= 2", + "ceil(cnt / 66.67) <= 2", + "pk < pi() / 2", + "pk = char(51)", + "pk = coalesce(NULL,3,4)", + "lower(name) = 'apple'", + "upper(name) = 'APPLE'", + "name = trim(' Apple ')", + "x($geometry) < -70", + "y($geometry) > 70", + "xmin($geometry) < -70", + "ymin($geometry) > 70", + "xmax($geometry) < -70", + "ymax($geometry) > 70", + "disjoint($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))", + "intersects($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))", + "contains(geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'),$geometry)", + "distance($geometry,geom_from_wkt( 'Point (-70 70)')) > 7", + "intersects($geometry,geom_from_gml( '-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1'))", + "x($geometry) < -70", + "y($geometry) > 79", + "xmin($geometry) < -70", + "ymin($geometry) < 76", + "xmax($geometry) > -68", + "ymax($geometry) > 80", + "area($geometry) > 10", + "perimeter($geometry) < 12", + "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))')) = 'FF2FF1212'", + "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'), '****F****')", + "crosses($geometry,geom_from_wkt( 'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)'))", + "overlaps($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'))", + "within($geometry,geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + "overlaps(translate($geometry,-1,-1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + "overlaps(buffer($geometry,1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + "intersects(centroid($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))", + "intersects(point_on_surface($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))", + "\"dt\" <= format_date(make_datetime(2020, 5, 4, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss')", + "\"dt\" < format_date(make_date(2020, 5, 4), 'yyyy-MM-dd hh:mm:ss')", + "\"dt\" = format_date(to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy'),'yyyy-MM-dd hh:mm:ss')", + """dt BETWEEN format_date(make_datetime(2020, 5, 3, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss') AND format_date(make_datetime(2020, 5, 4, 12, 14, 14), 'yyyy-MM-dd hh:mm:ss')""", + """dt NOT BETWEEN format_date(make_datetime(2020, 5, 3, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss') AND format_date(make_datetime(2020, 5, 4, 12, 14, 14), 'yyyy-MM-dd hh:mm:ss')""", + "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')", + 'to_time("time") >= make_time(12, 14, 14)', + "to_time(\"time\") = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')", + "to_datetime(\"dt\", 'yyyy-MM-dd hh:mm:ss') + make_interval(days:=1) <= make_datetime(2020, 5, 4, 12, 13, 14)", + "to_datetime(\"dt\", 'yyyy-MM-dd hh:mm:ss') + make_interval(days:=0.01) <= make_datetime(2020, 5, 4, 12, 13, 14)", + "cnt BETWEEN -200 AND 200", # NoUnaryMinus + } return filters def partiallyCompiledFilters(self): - return {'name = \'Apple\'', - 'name = \'apple\'', - '\"NaMe\" = \'Apple\'', - 'name LIKE \'Apple\'', - 'name LIKE \'aPple\'', - 'name LIKE \'Ap_le\'', - 'name LIKE \'Ap\\_le\'', - '"name"="name2"'} + return { + "name = 'Apple'", + "name = 'apple'", + "\"NaMe\" = 'Apple'", + "name LIKE 'Apple'", + "name LIKE 'aPple'", + "name LIKE 'Ap_le'", + "name LIKE 'Ap\\_le'", + '"name"="name2"', + } def testRepack(self): - vl = QgsVectorLayer(f'{self.repackfile}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{self.repackfile}|layerid=0", "test", "ogr") - ids = [f.id() for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression('pk=1'))] + ids = [ + f.id() + for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression("pk=1")) + ] vl.selectByIds(ids) self.assertEqual(vl.selectedFeatureIds(), ids) self.assertEqual(vl.featureCount(), 5) self.assertTrue(vl.startEditing()) self.assertTrue(vl.deleteFeature(3)) self.assertTrue(vl.commitChanges()) - self.assertTrue(vl.selectedFeatureCount() == 0 or vl.selectedFeatures()[0]['pk'] == 1) + self.assertTrue( + vl.selectedFeatureCount() == 0 or vl.selectedFeatures()[0]["pk"] == 1 + ) def testUpdateMode(self): - """ Test that on-the-fly re-opening in update/read-only mode works """ + """Test that on-the-fly re-opening in update/read-only mode works""" tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - for file in glob.glob(os.path.join(srcpath, 'shapefile.*')): + srcpath = os.path.join(TEST_DATA_DIR, "provider") + for file in glob.glob(os.path.join(srcpath, "shapefile.*")): shutil.copy(os.path.join(srcpath, file), tmpdir) - datasource = os.path.join(tmpdir, 'shapefile.shp') + datasource = os.path.join(tmpdir, "shapefile.shp") - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") caps = vl.dataProvider().capabilities() self.assertTrue(caps & QgsVectorDataProvider.Capability.AddFeatures) self.assertTrue(caps & QgsVectorDataProvider.Capability.DeleteFeatures) @@ -299,23 +308,31 @@ def testUpdateMode(self): f = QgsFeature() f.setAttributes([200]) - f.setGeometry(QgsGeometry.fromWkt('Point (2 49)')) + f.setGeometry(QgsGeometry.fromWkt("Point (2 49)")) (ret, feature_list) = vl.dataProvider().addFeatures([f]) self.assertTrue(ret) fid = feature_list[0].id() - features = [f_iter for f_iter in vl.getFeatures(QgsFeatureRequest().setFilterFid(fid))] - values = [f_iter['pk'] for f_iter in features] + features = [ + f_iter for f_iter in vl.getFeatures(QgsFeatureRequest().setFilterFid(fid)) + ] + values = [f_iter["pk"] for f_iter in features] self.assertEqual(values, [200]) got_geom = [f_iter.geometry() for f_iter in features][0].constGet() self.assertEqual((got_geom.x(), got_geom.y()), (2.0, 49.0)) - self.assertTrue(vl.dataProvider().changeGeometryValues({fid: QgsGeometry.fromWkt('Point (3 50)')})) + self.assertTrue( + vl.dataProvider().changeGeometryValues( + {fid: QgsGeometry.fromWkt("Point (3 50)")} + ) + ) self.assertTrue(vl.dataProvider().changeAttributeValues({fid: {0: 100}})) - features = [f_iter for f_iter in vl.getFeatures(QgsFeatureRequest().setFilterFid(fid))] - values = [f_iter['pk'] for f_iter in features] + features = [ + f_iter for f_iter in vl.getFeatures(QgsFeatureRequest().setFilterFid(fid)) + ] + values = [f_iter["pk"] for f_iter in features] got_geom = [f_iter.geometry() for f_iter in features][0].constGet() self.assertEqual((got_geom.x(), got_geom.y()), (3.0, 50.0)) @@ -323,13 +340,21 @@ def testUpdateMode(self): self.assertTrue(vl.dataProvider().deleteFeatures([fid])) # Check that it has really disappeared - osgeo.gdal.PushErrorHandler('CPLQuietErrorHandler') - features = [f_iter for f_iter in vl.getFeatures(QgsFeatureRequest().setFilterFid(fid))] + osgeo.gdal.PushErrorHandler("CPLQuietErrorHandler") + features = [ + f_iter for f_iter in vl.getFeatures(QgsFeatureRequest().setFilterFid(fid)) + ] osgeo.gdal.PopErrorHandler() self.assertEqual(features, []) - self.assertTrue(vl.dataProvider().addAttributes([QgsField("new_field", QVariant.Int, "integer")])) - self.assertTrue(vl.dataProvider().deleteAttributes([len(vl.dataProvider().fields()) - 1])) + self.assertTrue( + vl.dataProvider().addAttributes( + [QgsField("new_field", QVariant.Int, "integer")] + ) + ) + self.assertTrue( + vl.dataProvider().deleteAttributes([len(vl.dataProvider().fields()) - 1]) + ) self.assertTrue(vl.startEditing()) self.assertEqual(vl.dataProvider().property("_debug_open_mode"), "read-write") @@ -353,21 +378,21 @@ def testUpdateMode(self): self.assertEqual(vl.dataProvider().property("_debug_open_mode"), "read-write") def testUpdateModeFailedReopening(self): - ''' Test that methods on provider don't crash after a failed reopening ''' + """Test that methods on provider don't crash after a failed reopening""" # Windows doesn't like removing files opened by OGR, whatever # their open mode, so that makes it hard to test - if sys.platform == 'win32': + if sys.platform == "win32": return tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - for file in glob.glob(os.path.join(srcpath, 'shapefile.*')): + srcpath = os.path.join(TEST_DATA_DIR, "provider") + for file in glob.glob(os.path.join(srcpath, "shapefile.*")): shutil.copy(os.path.join(srcpath, file), tmpdir) - datasource = os.path.join(tmpdir, 'shapefile.shp') + datasource = os.path.join(tmpdir, "shapefile.shp") - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") os.unlink(datasource) @@ -378,29 +403,33 @@ def testUpdateModeFailedReopening(self): self.assertFalse(vl.dataProvider().isValid()) self.assertEqual(len([f for f in vl.dataProvider().getFeatures()]), 0) self.assertEqual(len(vl.dataProvider().subLayers()), 0) - self.assertFalse(vl.dataProvider().setSubsetString('TRUE')) + self.assertFalse(vl.dataProvider().setSubsetString("TRUE")) (ret, _) = vl.dataProvider().addFeatures([QgsFeature()]) self.assertFalse(ret) self.assertFalse(vl.dataProvider().deleteFeatures([1])) self.assertFalse(vl.dataProvider().addAttributes([QgsField()])) self.assertFalse(vl.dataProvider().deleteAttributes([1])) - self.assertFalse(vl.dataProvider().changeGeometryValues({0: QgsGeometry.fromWkt('Point (3 50)')})) + self.assertFalse( + vl.dataProvider().changeGeometryValues( + {0: QgsGeometry.fromWkt("Point (3 50)")} + ) + ) self.assertFalse(vl.dataProvider().changeAttributeValues({0: {0: 0}})) self.assertFalse(vl.dataProvider().createSpatialIndex()) self.assertFalse(vl.dataProvider().createAttributeIndex(0)) def testreloadData(self): - ''' Test reloadData() ''' + """Test reloadData()""" tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - for file in glob.glob(os.path.join(srcpath, 'shapefile.*')): + srcpath = os.path.join(TEST_DATA_DIR, "provider") + for file in glob.glob(os.path.join(srcpath, "shapefile.*")): shutil.copy(os.path.join(srcpath, file), tmpdir) - datasource = os.path.join(tmpdir, 'shapefile.shp') + datasource = os.path.join(tmpdir, "shapefile.shp") - vl1 = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') - vl2 = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl1 = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") + vl2 = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") self.assertTrue(vl1.startEditing()) self.assertTrue(vl1.deleteAttributes([1])) self.assertTrue(vl1.commitChanges()) @@ -411,80 +440,80 @@ def testreloadData(self): self.assertEqual(len(vl1.fields()), len(vl2.fields())) def testRenameAttributes(self): - ''' Test renameAttributes() ''' + """Test renameAttributes()""" tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - for file in glob.glob(os.path.join(srcpath, 'shapefile.*')): + srcpath = os.path.join(TEST_DATA_DIR, "provider") + for file in glob.glob(os.path.join(srcpath, "shapefile.*")): shutil.copy(os.path.join(srcpath, file), tmpdir) - datasource = os.path.join(tmpdir, 'shapefile.shp') + datasource = os.path.join(tmpdir, "shapefile.shp") - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") provider = vl.dataProvider() # bad rename - self.assertFalse(provider.renameAttributes({-1: 'not_a_field'})) - self.assertFalse(provider.renameAttributes({100: 'not_a_field'})) + self.assertFalse(provider.renameAttributes({-1: "not_a_field"})) + self.assertFalse(provider.renameAttributes({100: "not_a_field"})) # already exists - self.assertFalse(provider.renameAttributes({2: 'cnt'})) + self.assertFalse(provider.renameAttributes({2: "cnt"})) # rename one field - self.assertTrue(provider.renameAttributes({2: 'newname'})) - self.assertEqual(provider.fields().at(2).name(), 'newname') + self.assertTrue(provider.renameAttributes({2: "newname"})) + self.assertEqual(provider.fields().at(2).name(), "newname") vl.updateFields() fet = next(vl.getFeatures()) - self.assertEqual(fet.fields()[2].name(), 'newname') + self.assertEqual(fet.fields()[2].name(), "newname") # rename two fields - self.assertTrue(provider.renameAttributes({2: 'newname2', 3: 'another'})) - self.assertEqual(provider.fields().at(2).name(), 'newname2') - self.assertEqual(provider.fields().at(3).name(), 'another') + self.assertTrue(provider.renameAttributes({2: "newname2", 3: "another"})) + self.assertEqual(provider.fields().at(2).name(), "newname2") + self.assertEqual(provider.fields().at(3).name(), "another") vl.updateFields() fet = next(vl.getFeatures()) - self.assertEqual(fet.fields()[2].name(), 'newname2') - self.assertEqual(fet.fields()[3].name(), 'another') + self.assertEqual(fet.fields()[2].name(), "newname2") + self.assertEqual(fet.fields()[3].name(), "another") # close file and reopen, then recheck to confirm that changes were saved to file del vl vl = None - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") provider = vl.dataProvider() - self.assertEqual(provider.fields().at(2).name(), 'newname2') - self.assertEqual(provider.fields().at(3).name(), 'another') + self.assertEqual(provider.fields().at(2).name(), "newname2") + self.assertEqual(provider.fields().at(3).name(), "another") fet = next(vl.getFeatures()) - self.assertEqual(fet.fields()[2].name(), 'newname2') - self.assertEqual(fet.fields()[3].name(), 'another') + self.assertEqual(fet.fields()[2].name(), "newname2") + self.assertEqual(fet.fields()[3].name(), "another") def testDeleteGeometry(self): - ''' Test changeGeometryValues() with a null geometry ''' + """Test changeGeometryValues() with a null geometry""" tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - for file in glob.glob(os.path.join(srcpath, 'shapefile.*')): + srcpath = os.path.join(TEST_DATA_DIR, "provider") + for file in glob.glob(os.path.join(srcpath, "shapefile.*")): shutil.copy(os.path.join(srcpath, file), tmpdir) - datasource = os.path.join(tmpdir, 'shapefile.shp') + datasource = os.path.join(tmpdir, "shapefile.shp") - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") self.assertTrue(vl.dataProvider().changeGeometryValues({0: QgsGeometry()})) vl = None - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") fet = next(vl.getFeatures()) self.assertFalse(fet.hasGeometry()) def testDeleteShapes(self): - ''' Test fix for #11007 ''' + """Test fix for #11007""" tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - for file in glob.glob(os.path.join(srcpath, 'shapefile.*')): + srcpath = os.path.join(TEST_DATA_DIR, "provider") + for file in glob.glob(os.path.join(srcpath, "shapefile.*")): shutil.copy(os.path.join(srcpath, file), tmpdir) - datasource = os.path.join(tmpdir, 'shapefile.shp') + datasource = os.path.join(tmpdir, "shapefile.shp") - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") feature_count = vl.featureCount() # Start an iterator that will open a new connection iterator = vl.getFeatures() @@ -520,16 +549,16 @@ def testDeleteShapes(self): vl = None def testDontRepackOnReload(self): - ''' Test fix for #18421 ''' + """Test fix for #18421""" tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - for file in glob.glob(os.path.join(srcpath, 'shapefile.*')): + srcpath = os.path.join(TEST_DATA_DIR, "provider") + for file in glob.glob(os.path.join(srcpath, "shapefile.*")): shutil.copy(os.path.join(srcpath, file), tmpdir) - datasource = os.path.join(tmpdir, 'shapefile.shp') + datasource = os.path.join(tmpdir, "shapefile.shp") - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") feature_count = vl.featureCount() # Start an iterator that will open a new connection iterator = vl.getFeatures() @@ -548,21 +577,21 @@ def testDontRepackOnReload(self): vl = None def testRepackUnderFileLocks(self): - ''' Test fix for #15570 and #15393 ''' + """Test fix for #15570 and #15393""" tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - for file in glob.glob(os.path.join(srcpath, 'shapefile.*')): + srcpath = os.path.join(TEST_DATA_DIR, "provider") + for file in glob.glob(os.path.join(srcpath, "shapefile.*")): shutil.copy(os.path.join(srcpath, file), tmpdir) - datasource = os.path.join(tmpdir, 'shapefile.shp') + datasource = os.path.join(tmpdir, "shapefile.shp") - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") feature_count = vl.featureCount() # Keep a file descriptor opened on the .dbf, .shp and .shx - f_shp = open(os.path.join(tmpdir, 'shapefile.shp'), 'rb') - f_shx = open(os.path.join(tmpdir, 'shapefile.shx'), 'rb') - f_dbf = open(os.path.join(tmpdir, 'shapefile.dbf'), 'rb') + f_shp = open(os.path.join(tmpdir, "shapefile.shp"), "rb") + f_shx = open(os.path.join(tmpdir, "shapefile.shx"), "rb") + f_dbf = open(os.path.join(tmpdir, "shapefile.dbf"), "rb") # Delete a feature self.assertTrue(vl.startEditing()) @@ -586,13 +615,13 @@ def testRepackUnderFileLocks(self): ds = None def testRepackAtFirstSave(self): - ''' Test fix for #15407 ''' + """Test fix for #15407""" tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - for file in glob.glob(os.path.join(srcpath, 'shapefile.*')): + srcpath = os.path.join(TEST_DATA_DIR, "provider") + for file in glob.glob(os.path.join(srcpath, "shapefile.*")): shutil.copy(os.path.join(srcpath, file), tmpdir) - datasource = os.path.join(tmpdir, 'shapefile.shp') + datasource = os.path.join(tmpdir, "shapefile.shp") ds = osgeo.ogr.Open(datasource, update=1) lyr = ds.GetLayer(0) @@ -600,7 +629,7 @@ def testRepackAtFirstSave(self): lyr.DeleteFeature(2) ds = None - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") self.assertTrue(vl.featureCount(), original_feature_count) @@ -624,8 +653,8 @@ def testRepackAtFirstSave(self): ds = None def testOpenWithFilter(self): - file_path = os.path.join(TEST_DATA_DIR, 'provider', 'shapefile.shp') - uri = f'{file_path}|layerid=0|subset="name" = \'Apple\'' + file_path = os.path.join(TEST_DATA_DIR, "provider", "shapefile.shp") + uri = f"{file_path}|layerid=0|subset=\"name\" = 'Apple'" options = QgsDataProvider.ProviderOptions() # ensure that no longer required ogr SQL layers are correctly cleaned up # we need to run this twice for the incorrect cleanup asserts to trip, @@ -633,80 +662,83 @@ def testOpenWithFilter(self): # connection pool for i in range(2): vl = QgsVectorLayer(uri) - self.assertTrue(vl.isValid(), f'Layer not valid, iteration {i + 1}') + self.assertTrue(vl.isValid(), f"Layer not valid, iteration {i + 1}") self.assertEqual(vl.featureCount(), 1) f = next(vl.getFeatures()) - self.assertEqual(f['name'], 'Apple') + self.assertEqual(f["name"], "Apple") # force close of data provider - vl.setDataSource('', 'test', 'ogr', options) + vl.setDataSource("", "test", "ogr", options) def testEncoding_iso(self): - file_path = os.path.join(TEST_DATA_DIR, 'shapefile', 'iso-8859-1.shp') + file_path = os.path.join(TEST_DATA_DIR, "shapefile", "iso-8859-1.shp") vl = QgsVectorLayer(file_path) self.assertTrue(vl.isValid()) - self.assertEqual(vl.dataProvider().encoding(), 'ISO-8859-1') - self.assertEqual(next(vl.getFeatures())[1], 'äöü') + self.assertEqual(vl.dataProvider().encoding(), "ISO-8859-1") + self.assertEqual(next(vl.getFeatures())[1], "äöü") - file_path = os.path.join(TEST_DATA_DIR, 'shapefile', 'iso-8859-1_ldid.shp') + file_path = os.path.join(TEST_DATA_DIR, "shapefile", "iso-8859-1_ldid.shp") vl = QgsVectorLayer(file_path) self.assertTrue(vl.isValid()) - self.assertEqual(vl.dataProvider().encoding(), 'ISO-8859-1') - self.assertEqual(next(vl.getFeatures())[1], 'äöü') + self.assertEqual(vl.dataProvider().encoding(), "ISO-8859-1") + self.assertEqual(next(vl.getFeatures())[1], "äöü") - file_path = os.path.join(TEST_DATA_DIR, 'shapefile', 'latin1.shp') + file_path = os.path.join(TEST_DATA_DIR, "shapefile", "latin1.shp") vl = QgsVectorLayer(file_path) self.assertTrue(vl.isValid()) - self.assertEqual(vl.dataProvider().encoding(), 'ISO-8859-1') - self.assertEqual(next(vl.getFeatures())[1], 'äöü') + self.assertEqual(vl.dataProvider().encoding(), "ISO-8859-1") + self.assertEqual(next(vl.getFeatures())[1], "äöü") - file_path = os.path.join(TEST_DATA_DIR, 'shapefile', 'utf8.shp') + file_path = os.path.join(TEST_DATA_DIR, "shapefile", "utf8.shp") vl = QgsVectorLayer(file_path) self.assertTrue(vl.isValid()) - self.assertEqual(vl.dataProvider().encoding(), 'UTF-8') - self.assertEqual(next(vl.getFeatures())[1], 'äöü') + self.assertEqual(vl.dataProvider().encoding(), "UTF-8") + self.assertEqual(next(vl.getFeatures())[1], "äöü") - file_path = os.path.join(TEST_DATA_DIR, 'shapefile', 'windows-1252.shp') + file_path = os.path.join(TEST_DATA_DIR, "shapefile", "windows-1252.shp") vl = QgsVectorLayer(file_path) self.assertTrue(vl.isValid()) - self.assertEqual(vl.dataProvider().encoding(), 'windows-1252') - self.assertEqual(next(vl.getFeatures())[1], 'äöü') + self.assertEqual(vl.dataProvider().encoding(), "windows-1252") + self.assertEqual(next(vl.getFeatures())[1], "äöü") - file_path = os.path.join(TEST_DATA_DIR, 'shapefile', 'windows-1252_ldid.shp') + file_path = os.path.join(TEST_DATA_DIR, "shapefile", "windows-1252_ldid.shp") vl = QgsVectorLayer(file_path) self.assertTrue(vl.isValid()) - self.assertEqual(vl.dataProvider().encoding(), 'windows-1252') - self.assertEqual(next(vl.getFeatures())[1], 'äöü') + self.assertEqual(vl.dataProvider().encoding(), "windows-1252") + self.assertEqual(next(vl.getFeatures())[1], "äöü") - if int(gdal.VersionInfo('VERSION_NUM')) >= GDAL_COMPUTE_VERSION(3, 1, 0): + if int(gdal.VersionInfo("VERSION_NUM")) >= GDAL_COMPUTE_VERSION(3, 1, 0): # correct autodetection of vsizip based shapefiles depends on GDAL 3.1 - file_path = os.path.join(TEST_DATA_DIR, 'shapefile', 'windows-1252.zip') - vl = QgsVectorLayer(f'/vsizip/{file_path}') + file_path = os.path.join(TEST_DATA_DIR, "shapefile", "windows-1252.zip") + vl = QgsVectorLayer(f"/vsizip/{file_path}") self.assertTrue(vl.isValid()) - self.assertEqual(vl.dataProvider().encoding(), 'windows-1252') - self.assertEqual(next(vl.getFeatures())[1], 'äöü') + self.assertEqual(vl.dataProvider().encoding(), "windows-1252") + self.assertEqual(next(vl.getFeatures())[1], "äöü") - file_path = os.path.join(TEST_DATA_DIR, 'shapefile', 'system_encoding.shp') + file_path = os.path.join(TEST_DATA_DIR, "shapefile", "system_encoding.shp") vl = QgsVectorLayer(file_path) self.assertTrue(vl.isValid()) # no encoding hints, so it should default to UTF-8 (which is wrong for this particular file, but the correct guess to make first!) - self.assertEqual(vl.dataProvider().encoding(), 'UTF-8') - self.assertNotEqual(next(vl.getFeatures())[1], 'äöü') + self.assertEqual(vl.dataProvider().encoding(), "UTF-8") + self.assertNotEqual(next(vl.getFeatures())[1], "äöü") # set to correct encoding - vl.dataProvider().setEncoding('ISO-8859-1') - self.assertEqual(vl.dataProvider().encoding(), 'ISO-8859-1') - self.assertEqual(next(vl.getFeatures())[1], 'äöü') + vl.dataProvider().setEncoding("ISO-8859-1") + self.assertEqual(vl.dataProvider().encoding(), "ISO-8859-1") + self.assertEqual(next(vl.getFeatures())[1], "äöü") def testCreateAttributeIndex(self): tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - for file in glob.glob(os.path.join(srcpath, 'shapefile.*')): + srcpath = os.path.join(TEST_DATA_DIR, "provider") + for file in glob.glob(os.path.join(srcpath, "shapefile.*")): shutil.copy(os.path.join(srcpath, file), tmpdir) - datasource = os.path.join(tmpdir, 'shapefile.shp') + datasource = os.path.join(tmpdir, "shapefile.shp") - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") self.assertTrue(vl.isValid()) - self.assertTrue(vl.dataProvider().capabilities() & QgsVectorDataProvider.Capability.CreateAttributeIndex) + self.assertTrue( + vl.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.CreateAttributeIndex + ) self.assertFalse(vl.dataProvider().createAttributeIndex(-1)) self.assertFalse(vl.dataProvider().createAttributeIndex(100)) self.assertTrue(vl.dataProvider().createAttributeIndex(1)) @@ -714,181 +746,206 @@ def testCreateAttributeIndex(self): def testCreateSpatialIndex(self): tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - for file in glob.glob(os.path.join(srcpath, 'shapefile.*')): + srcpath = os.path.join(TEST_DATA_DIR, "provider") + for file in glob.glob(os.path.join(srcpath, "shapefile.*")): shutil.copy(os.path.join(srcpath, file), tmpdir) - datasource = os.path.join(tmpdir, 'shapefile.shp') + datasource = os.path.join(tmpdir, "shapefile.shp") - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") self.assertTrue(vl.isValid()) - self.assertTrue(vl.dataProvider().capabilities() & QgsVectorDataProvider.Capability.CreateSpatialIndex) + self.assertTrue( + vl.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.CreateSpatialIndex + ) self.assertTrue(vl.dataProvider().createSpatialIndex()) def testSubSetStringEditable_bug17795_but_with_modified_behavior(self): """Test that a layer is still editable after setting a subset""" - testPath = TEST_DATA_DIR + '/' + 'lines.shp' + testPath = TEST_DATA_DIR + "/" + "lines.shp" isEditable = QgsVectorDataProvider.Capability.ChangeAttributeValues - vl = QgsVectorLayer(testPath, 'subset_test', 'ogr') + vl = QgsVectorLayer(testPath, "subset_test", "ogr") self.assertTrue(vl.isValid()) self.assertTrue(vl.dataProvider().capabilities() & isEditable) - vl = QgsVectorLayer(testPath, 'subset_test', 'ogr') - vl.setSubsetString('') + vl = QgsVectorLayer(testPath, "subset_test", "ogr") + vl.setSubsetString("") self.assertTrue(vl.isValid()) self.assertTrue(vl.dataProvider().capabilities() & isEditable) - vl = QgsVectorLayer(testPath, 'subset_test', 'ogr') - vl.setSubsetString('"Name" = \'Arterial\'') + vl = QgsVectorLayer(testPath, "subset_test", "ogr") + vl.setSubsetString("\"Name\" = 'Arterial'") self.assertTrue(vl.isValid()) self.assertTrue(vl.dataProvider().capabilities() & isEditable) - vl.setSubsetString('') + vl.setSubsetString("") self.assertTrue(vl.dataProvider().capabilities() & isEditable) def testSubsetStringExtent_bug17863(self): """Check that the extent is correct when applied in the ctor and when - modified after a subset string is set """ + modified after a subset string is set""" def _lessdigits(s): - return re.sub(r'(\d+\.\d{3})\d+', r'\1', s) + return re.sub(r"(\d+\.\d{3})\d+", r"\1", s) - testPath = TEST_DATA_DIR + '/' + 'points.shp' - subSetString = '"Class" = \'Biplane\'' - subSet = f'|layerid=0|subset={subSetString}' + testPath = TEST_DATA_DIR + "/" + "points.shp" + subSetString = "\"Class\" = 'Biplane'" + subSet = f"|layerid=0|subset={subSetString}" # unfiltered - vl = QgsVectorLayer(testPath, 'test', 'ogr') + vl = QgsVectorLayer(testPath, "test", "ogr") self.assertTrue(vl.isValid()) unfiltered_extent = _lessdigits(vl.extent().toString()) del vl # filter after construction ... - subSet_vl2 = QgsVectorLayer(testPath, 'test', 'ogr') + subSet_vl2 = QgsVectorLayer(testPath, "test", "ogr") self.assertEqual(_lessdigits(subSet_vl2.extent().toString()), unfiltered_extent) # ... apply filter now! subSet_vl2.setSubsetString(subSetString) self.assertEqual(subSet_vl2.subsetString(), subSetString) - self.assertNotEqual(_lessdigits(subSet_vl2.extent().toString()), unfiltered_extent) + self.assertNotEqual( + _lessdigits(subSet_vl2.extent().toString()), unfiltered_extent + ) filtered_extent = _lessdigits(subSet_vl2.extent().toString()) del subSet_vl2 # filtered in constructor - subSet_vl = QgsVectorLayer(testPath + subSet, 'subset_test', 'ogr') + subSet_vl = QgsVectorLayer(testPath + subSet, "subset_test", "ogr") self.assertEqual(subSet_vl.subsetString(), subSetString) self.assertTrue(subSet_vl.isValid()) # This was failing in bug 17863 self.assertEqual(_lessdigits(subSet_vl.extent().toString()), filtered_extent) - self.assertNotEqual(_lessdigits(subSet_vl.extent().toString()), unfiltered_extent) + self.assertNotEqual( + _lessdigits(subSet_vl.extent().toString()), unfiltered_extent + ) def testMalformedSubsetStrings(self): """Test that invalid where clauses always return false""" - testPath = TEST_DATA_DIR + '/' + 'lines.shp' + testPath = TEST_DATA_DIR + "/" + "lines.shp" - vl = QgsVectorLayer(testPath, 'subset_test', 'ogr') + vl = QgsVectorLayer(testPath, "subset_test", "ogr") self.assertTrue(vl.isValid()) - self.assertTrue(vl.setSubsetString('')) - self.assertTrue(vl.setSubsetString('"Name" = \'Arterial\'')) - self.assertTrue(vl.setSubsetString('select * from lines where "Name" = \'Arterial\'')) - self.assertFalse(vl.setSubsetString('this is invalid sql')) - self.assertFalse(vl.setSubsetString('select * from lines where "NonExistentField" = \'someValue\'')) - self.assertFalse(vl.setSubsetString('select * from lines where "Name" = \'Arte...')) - self.assertFalse(vl.setSubsetString('select * from lines where "Name" in (\'Arterial\', \'Highway\' ')) - self.assertFalse(vl.setSubsetString('select * from NonExistentTable')) - self.assertFalse(vl.setSubsetString('select NonExistentField from lines')) - self.assertFalse(vl.setSubsetString('"NonExistentField" = \'someValue\'')) + self.assertTrue(vl.setSubsetString("")) + self.assertTrue(vl.setSubsetString("\"Name\" = 'Arterial'")) + self.assertTrue( + vl.setSubsetString("select * from lines where \"Name\" = 'Arterial'") + ) + self.assertFalse(vl.setSubsetString("this is invalid sql")) + self.assertFalse( + vl.setSubsetString( + "select * from lines where \"NonExistentField\" = 'someValue'" + ) + ) + self.assertFalse( + vl.setSubsetString('select * from lines where "Name" = \'Arte...') + ) + self.assertFalse( + vl.setSubsetString( + "select * from lines where \"Name\" in ('Arterial', 'Highway' " + ) + ) + self.assertFalse(vl.setSubsetString("select * from NonExistentTable")) + self.assertFalse(vl.setSubsetString("select NonExistentField from lines")) + self.assertFalse(vl.setSubsetString("\"NonExistentField\" = 'someValue'")) self.assertFalse(vl.setSubsetString('"Name" = \'Arte...')) - self.assertFalse(vl.setSubsetString('"Name" in (\'Arterial\', \'Highway\' ')) - self.assertTrue(vl.setSubsetString('')) + self.assertFalse(vl.setSubsetString("\"Name\" in ('Arterial', 'Highway' ")) + self.assertTrue(vl.setSubsetString("")) def testMultipatch(self): """Check that we can deal with multipatch shapefiles, returned natively by OGR as GeometryCollection of TIN""" - testPath = TEST_DATA_DIR + '/' + 'multipatch.shp' - vl = QgsVectorLayer(testPath, 'test', 'ogr') + testPath = TEST_DATA_DIR + "/" + "multipatch.shp" + vl = QgsVectorLayer(testPath, "test", "ogr") self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.MultiPolygonZ) f = next(vl.getFeatures()) self.assertEqual(f.geometry().wkbType(), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(f.geometry().constGet().asWkt(), - 'MultiPolygon Z (((0 0 0, 0 1 0, 1 1 0, 0 0 0)),((0 0 0, 1 1 0, 1 0 0, 0 0 0)),((0 0 0, 0 -1 0, 1 -1 0, 0 0 0)),((0 0 0, 1 -1 0, 1 0 0, 0 0 0)))') + self.assertEqual( + f.geometry().constGet().asWkt(), + "MultiPolygon Z (((0 0 0, 0 1 0, 1 1 0, 0 0 0)),((0 0 0, 1 1 0, 1 0 0, 0 0 0)),((0 0 0, 0 -1 0, 1 -1 0, 0 0 0)),((0 0 0, 1 -1 0, 1 0 0, 0 0 0)))", + ) def testShzSupport(self): - ''' Test support for single layer compressed shapefiles (.shz) ''' + """Test support for single layer compressed shapefiles (.shz)""" - if int(osgeo.gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 1, 0): + if int(osgeo.gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 1, 0): return - tmpfile = os.path.join(self.basetestpath, 'testShzSupport.shz') - ds = osgeo.ogr.GetDriverByName('ESRI Shapefile').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('testShzSupport', geom_type=osgeo.ogr.wkbPoint) - lyr.CreateField(osgeo.ogr.FieldDefn('attr', osgeo.ogr.OFTInteger)) + tmpfile = os.path.join(self.basetestpath, "testShzSupport.shz") + ds = osgeo.ogr.GetDriverByName("ESRI Shapefile").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("testShzSupport", geom_type=osgeo.ogr.wkbPoint) + lyr.CreateField(osgeo.ogr.FieldDefn("attr", osgeo.ogr.OFTInteger)) f = osgeo.ogr.Feature(lyr.GetLayerDefn()) - f.SetField('attr', 1) - f.SetGeometry(osgeo.ogr.CreateGeometryFromWkt('POINT(0 0)')) + f.SetField("attr", 1) + f.SetGeometry(osgeo.ogr.CreateGeometryFromWkt("POINT(0 0)")) lyr.CreateFeature(f) f = None ds = None - vl = QgsVectorLayer(tmpfile, 'test', 'ogr') + vl = QgsVectorLayer(tmpfile, "test", "ogr") self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) f = next(vl.getFeatures()) - assert f['attr'] == 1 - self.assertEqual(f.geometry().constGet().asWkt(), 'Point (0 0)') + assert f["attr"] == 1 + self.assertEqual(f.geometry().constGet().asWkt(), "Point (0 0)") self.assertTrue(vl.startEditing()) self.assertTrue(vl.changeAttributeValue(f.id(), 0, -1)) self.assertTrue(vl.commitChanges()) f = next(vl.getFeatures()) - assert f['attr'] == -1 + assert f["attr"] == -1 # Check DataItem registry = QgsApplication.dataItemProviderRegistry() - files_provider = next(provider for provider in registry.providers() if provider.name() == 'files') + files_provider = next( + provider for provider in registry.providers() if provider.name() == "files" + ) item = files_provider.createDataItem(tmpfile, None) - self.assertTrue(item.uri().endswith('testShzSupport.shz')) + self.assertTrue(item.uri().endswith("testShzSupport.shz")) def testShpZipSupport(self): - ''' Test support for multi layer compressed shapefiles (.shp.zip) ''' + """Test support for multi layer compressed shapefiles (.shp.zip)""" - if int(osgeo.gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 1, 0): + if int(osgeo.gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 1, 0): return - tmpfile = os.path.join(self.basetestpath, 'testShpZipSupport.shp.zip') - ds = osgeo.ogr.GetDriverByName('ESRI Shapefile').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('layer1', geom_type=osgeo.ogr.wkbPoint) - lyr.CreateField(osgeo.ogr.FieldDefn('attr', osgeo.ogr.OFTInteger)) + tmpfile = os.path.join(self.basetestpath, "testShpZipSupport.shp.zip") + ds = osgeo.ogr.GetDriverByName("ESRI Shapefile").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("layer1", geom_type=osgeo.ogr.wkbPoint) + lyr.CreateField(osgeo.ogr.FieldDefn("attr", osgeo.ogr.OFTInteger)) f = osgeo.ogr.Feature(lyr.GetLayerDefn()) - f.SetField('attr', 1) - f.SetGeometry(osgeo.ogr.CreateGeometryFromWkt('POINT(0 0)')) + f.SetField("attr", 1) + f.SetGeometry(osgeo.ogr.CreateGeometryFromWkt("POINT(0 0)")) lyr.CreateFeature(f) f = None - lyr = ds.CreateLayer('layer2', geom_type=osgeo.ogr.wkbMultiLineString) - lyr.CreateField(osgeo.ogr.FieldDefn('attr', osgeo.ogr.OFTInteger)) + lyr = ds.CreateLayer("layer2", geom_type=osgeo.ogr.wkbMultiLineString) + lyr.CreateField(osgeo.ogr.FieldDefn("attr", osgeo.ogr.OFTInteger)) f = osgeo.ogr.Feature(lyr.GetLayerDefn()) - f.SetField('attr', 2) - f.SetGeometry(osgeo.ogr.CreateGeometryFromWkt('LINESTRING(0 0,1 1)')) + f.SetField("attr", 2) + f.SetGeometry(osgeo.ogr.CreateGeometryFromWkt("LINESTRING(0 0,1 1)")) lyr.CreateFeature(f) f = None ds = None - vl1 = QgsVectorLayer(tmpfile + '|layername=layer1', 'test', 'ogr') - vl2 = QgsVectorLayer(tmpfile + '|layername=layer2', 'test', 'ogr') + vl1 = QgsVectorLayer(tmpfile + "|layername=layer1", "test", "ogr") + vl2 = QgsVectorLayer(tmpfile + "|layername=layer2", "test", "ogr") self.assertTrue(vl1.isValid()) self.assertTrue(vl2.isValid()) self.assertEqual(vl1.wkbType(), QgsWkbTypes.Type.Point) self.assertEqual(vl2.wkbType(), QgsWkbTypes.Type.MultiLineString) f1 = next(vl1.getFeatures()) f2 = next(vl2.getFeatures()) - assert f1['attr'] == 1 - self.assertEqual(f1.geometry().constGet().asWkt(), 'Point (0 0)') - assert f2['attr'] == 2 - self.assertEqual(f2.geometry().constGet().asWkt(), 'MultiLineString ((0 0, 1 1))') + assert f1["attr"] == 1 + self.assertEqual(f1.geometry().constGet().asWkt(), "Point (0 0)") + assert f2["attr"] == 2 + self.assertEqual( + f2.geometry().constGet().asWkt(), "MultiLineString ((0 0, 1 1))" + ) self.assertTrue(vl1.startEditing()) self.assertTrue(vl2.startEditing()) @@ -898,20 +955,22 @@ def testShpZipSupport(self): self.assertTrue(vl2.commitChanges()) f = next(vl1.getFeatures()) - assert f['attr'] == -1 + assert f["attr"] == -1 f = next(vl2.getFeatures()) - assert f['attr'] == -2 + assert f["attr"] == -2 # Check DataItem registry = QgsApplication.dataItemProviderRegistry() - files_provider = next(provider for provider in registry.providers() if provider.name() == 'files') + files_provider = next( + provider for provider in registry.providers() if provider.name() == "files" + ) item = files_provider.createDataItem(tmpfile, None) children = item.createChildren() self.assertEqual(len(children), 2) uris = sorted([children[i].uri() for i in range(2)]) - self.assertIn('testShpZipSupport.shp.zip|layername=layer1', uris[0]) - self.assertIn('testShpZipSupport.shp.zip|layername=layer2', uris[1]) + self.assertIn("testShpZipSupport.shp.zip|layername=layer1", uris[0]) + self.assertIn("testShpZipSupport.shp.zip|layername=layer2", uris[1]) def testWriteShapefileWithSingleConversion(self): """Check writing geometries from a POLYGON ESRI shapefile does not @@ -924,41 +983,40 @@ def testWriteShapefileWithSingleConversion(self): and not multi. """ - ml = QgsVectorLayer( - ('Polygon?crs=epsg:4326&field=id:int'), - 'test', - 'memory') + ml = QgsVectorLayer(("Polygon?crs=epsg:4326&field=id:int"), "test", "memory") provider = ml.dataProvider() ft = QgsFeature() - ft.setGeometry(QgsGeometry.fromWkt('Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))')) + ft.setGeometry(QgsGeometry.fromWkt("Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))")) ft.setAttributes([1]) res, features = provider.addFeatures([ft]) - dest_file_name = os.path.join(self.basetestpath, 'multipart.shp') - write_result, error_message = QgsVectorLayerExporter.exportLayer(ml, - dest_file_name, - 'ogr', - ml.crs(), - False, - {"driverName": "ESRI Shapefile"} - ) - self.assertEqual(write_result, QgsVectorLayerExporter.ExportError.NoError, error_message) + dest_file_name = os.path.join(self.basetestpath, "multipart.shp") + write_result, error_message = QgsVectorLayerExporter.exportLayer( + ml, dest_file_name, "ogr", ml.crs(), False, {"driverName": "ESRI Shapefile"} + ) + self.assertEqual( + write_result, QgsVectorLayerExporter.ExportError.NoError, error_message + ) # Open the newly created layer shapefile_layer = QgsVectorLayer(dest_file_name) - dest_singlepart_file_name = os.path.join(self.basetestpath, 'singlepart.gpkg') - write_result, error_message = QgsVectorLayerExporter.exportLayer(shapefile_layer, - dest_singlepart_file_name, - 'ogr', - shapefile_layer.crs(), - False, - { - "forceSinglePartGeometryType": True, - "driverName": "GPKG", - }) - self.assertEqual(write_result, QgsVectorLayerExporter.ExportError.NoError, error_message) + dest_singlepart_file_name = os.path.join(self.basetestpath, "singlepart.gpkg") + write_result, error_message = QgsVectorLayerExporter.exportLayer( + shapefile_layer, + dest_singlepart_file_name, + "ogr", + shapefile_layer.crs(), + False, + { + "forceSinglePartGeometryType": True, + "driverName": "GPKG", + }, + ) + self.assertEqual( + write_result, QgsVectorLayerExporter.ExportError.NoError, error_message + ) # Load result layer and check that it's NOT MULTI single_layer = QgsVectorLayer(dest_singlepart_file_name) @@ -966,17 +1024,21 @@ def testWriteShapefileWithSingleConversion(self): self.assertTrue(QgsWkbTypes.isSingleType(single_layer.wkbType())) # Now save the shapfile layer into a gpkg with no force options - dest_multipart_file_name = os.path.join(self.basetestpath, 'multipart.gpkg') - write_result, error_message = QgsVectorLayerExporter.exportLayer(shapefile_layer, - dest_multipart_file_name, - 'ogr', - shapefile_layer.crs(), - False, - { - "forceSinglePartGeometryType": False, - "driverName": "GPKG", - }) - self.assertEqual(write_result, QgsVectorLayerExporter.ExportError.NoError, error_message) + dest_multipart_file_name = os.path.join(self.basetestpath, "multipart.gpkg") + write_result, error_message = QgsVectorLayerExporter.exportLayer( + shapefile_layer, + dest_multipart_file_name, + "ogr", + shapefile_layer.crs(), + False, + { + "forceSinglePartGeometryType": False, + "driverName": "GPKG", + }, + ) + self.assertEqual( + write_result, QgsVectorLayerExporter.ExportError.NoError, error_message + ) # Load result layer and check that it's MULTI multi_layer = QgsVectorLayer(dest_multipart_file_name) self.assertTrue(multi_layer.isValid()) @@ -985,119 +1047,268 @@ def testWriteShapefileWithSingleConversion(self): # Failing case: add a real multi to the shapefile and try to force to single self.assertTrue(shapefile_layer.startEditing()) ft = QgsFeature() - ft.setGeometry(QgsGeometry.fromWkt('MultiPolygon (((0 0, 0 1, 1 1, 1 0, 0 0)), ((-10 -10,-10 -9,-9 -9,-10 -10)))')) + ft.setGeometry( + QgsGeometry.fromWkt( + "MultiPolygon (((0 0, 0 1, 1 1, 1 0, 0 0)), ((-10 -10,-10 -9,-9 -9,-10 -10)))" + ) + ) ft.setAttributes([2]) self.assertTrue(shapefile_layer.addFeatures([ft])) self.assertTrue(shapefile_layer.commitChanges()) - dest_multipart_failure_file_name = os.path.join(self.basetestpath, 'multipart_failure.gpkg') - write_result, error_message = QgsVectorLayerExporter.exportLayer(shapefile_layer, - dest_multipart_failure_file_name, - 'ogr', - shapefile_layer.crs(), - False, - { - "forceSinglePartGeometryType": True, - "driverName": "GPKG", - }) + dest_multipart_failure_file_name = os.path.join( + self.basetestpath, "multipart_failure.gpkg" + ) + write_result, error_message = QgsVectorLayerExporter.exportLayer( + shapefile_layer, + dest_multipart_failure_file_name, + "ogr", + shapefile_layer.crs(), + False, + { + "forceSinglePartGeometryType": True, + "driverName": "GPKG", + }, + ) self.assertTrue(QgsWkbTypes.isMultiType(multi_layer.wkbType())) - self.assertEqual(write_result, QgsVectorLayerExporter.ExportError.ErrFeatureWriteFailed, "Failed to transform a feature with ID '1' to single part. Writing stopped.") + self.assertEqual( + write_result, + QgsVectorLayerExporter.ExportError.ErrFeatureWriteFailed, + "Failed to transform a feature with ID '1' to single part. Writing stopped.", + ) def testReadingLayerGeometryTypes(self): - tests = [(osgeo.ogr.wkbPoint, 'Point (0 0)', QgsWkbTypes.Type.Point, 'Point (0 0)'), - (osgeo.ogr.wkbPoint25D, 'Point Z (0 0 1)', QgsWkbTypes.Type.PointZ, 'Point Z (0 0 1)'), - (osgeo.ogr.wkbPointM, 'Point M (0 0 1)', QgsWkbTypes.Type.PointM, 'Point M (0 0 1)'), - (osgeo.ogr.wkbPointZM, 'Point ZM (0 0 1 2)', QgsWkbTypes.Type.PointZM, 'Point ZM (0 0 1 2)'), - (osgeo.ogr.wkbLineString, 'LineString (0 0, 1 1)', QgsWkbTypes.Type.MultiLineString, 'MultiLineString ((0 0, 1 1))'), - (osgeo.ogr.wkbLineString25D, 'LineString Z (0 0 10, 1 1 10)', QgsWkbTypes.Type.MultiLineStringZ, 'MultiLineString Z ((0 0 10, 1 1 10))'), - (osgeo.ogr.wkbLineStringM, 'LineString M (0 0 10, 1 1 10)', QgsWkbTypes.Type.MultiLineStringM, 'MultiLineString M ((0 0 10, 1 1 10))'), - (osgeo.ogr.wkbLineStringZM, 'LineString ZM (0 0 10 20, 1 1 10 20)', QgsWkbTypes.Type.MultiLineStringZM, 'MultiLineString ZM ((0 0 10 20, 1 1 10 20))'), - (osgeo.ogr.wkbPolygon, 'Polygon ((0 0,0 1,1 1,0 0))', QgsWkbTypes.Type.MultiPolygon, 'MultiPolygon (((0 0, 0 1, 1 1, 0 0)))'), - (osgeo.ogr.wkbPolygon25D, 'Polygon Z ((0 0 10, 0 1 10, 1 1 10, 0 0 10))', QgsWkbTypes.Type.MultiPolygonZ, 'MultiPolygon Z (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))'), - (osgeo.ogr.wkbPolygonM, 'Polygon M ((0 0 10, 0 1 10, 1 1 10, 0 0 10))', QgsWkbTypes.Type.MultiPolygonM, 'MultiPolygon M (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))'), - (osgeo.ogr.wkbPolygonZM, 'Polygon ZM ((0 0 10 20, 0 1 10 20, 1 1 10 20, 0 0 10 20))', QgsWkbTypes.Type.MultiPolygonZM, 'MultiPolygon ZM (((0 0 10 20, 0 1 10 20, 1 1 10 20, 0 0 10 20)))'), - (osgeo.ogr.wkbMultiPoint, 'MultiPoint (0 0,1 1)', QgsWkbTypes.Type.MultiPoint, 'MultiPoint ((0 0),(1 1))'), - (osgeo.ogr.wkbMultiPoint25D, 'MultiPoint Z ((0 0 10), (1 1 10))', QgsWkbTypes.Type.MultiPointZ, 'MultiPoint Z ((0 0 10),(1 1 10))'), - (osgeo.ogr.wkbMultiPointM, 'MultiPoint M ((0 0 10), (1 1 10))', QgsWkbTypes.Type.MultiPointM, 'MultiPoint M ((0 0 10),(1 1 10))'), - (osgeo.ogr.wkbMultiPointZM, 'MultiPoint ZM ((0 0 10 20), (1 1 10 20))', QgsWkbTypes.Type.MultiPointZM, 'MultiPoint ZM ((0 0 10 20),(1 1 10 20))'), - (osgeo.ogr.wkbMultiLineString, 'MultiLineString ((0 0, 1 1))', QgsWkbTypes.Type.MultiLineString, 'MultiLineString ((0 0, 1 1))'), - (osgeo.ogr.wkbMultiLineString25D, 'MultiLineString Z ((0 0 10, 1 1 10))', QgsWkbTypes.Type.MultiLineStringZ, 'MultiLineString Z ((0 0 10, 1 1 10))'), - (osgeo.ogr.wkbMultiLineStringM, 'MultiLineString M ((0 0 10, 1 1 10))', QgsWkbTypes.Type.MultiLineStringM, 'MultiLineString M ((0 0 10, 1 1 10))'), - (osgeo.ogr.wkbMultiLineStringZM, 'MultiLineString ZM ((0 0 10 20, 1 1 10 20))', QgsWkbTypes.Type.MultiLineStringZM, 'MultiLineString ZM ((0 0 10 20, 1 1 10 20))'), - (osgeo.ogr.wkbMultiPolygon, 'MultiPolygon (((0 0,0 1,1 1,0 0)))', QgsWkbTypes.Type.MultiPolygon, 'MultiPolygon (((0 0, 0 1, 1 1, 0 0)))'), - (osgeo.ogr.wkbMultiPolygon25D, 'MultiPolygon Z (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))', QgsWkbTypes.Type.MultiPolygonZ, 'MultiPolygon Z (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))'), - (osgeo.ogr.wkbMultiPolygonM, 'MultiPolygon M (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))', QgsWkbTypes.Type.MultiPolygonM, 'MultiPolygon M (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))'), - (osgeo.ogr.wkbMultiPolygonZM, 'MultiPolygon ZM (((0 0 10 20, 0 1 10 20, 1 1 10 20, 0 0 10 20)))', QgsWkbTypes.Type.MultiPolygonZM, 'MultiPolygon ZM (((0 0 10 20, 0 1 10 20, 1 1 10 20, 0 0 10 20)))'), - ] + tests = [ + (osgeo.ogr.wkbPoint, "Point (0 0)", QgsWkbTypes.Type.Point, "Point (0 0)"), + ( + osgeo.ogr.wkbPoint25D, + "Point Z (0 0 1)", + QgsWkbTypes.Type.PointZ, + "Point Z (0 0 1)", + ), + ( + osgeo.ogr.wkbPointM, + "Point M (0 0 1)", + QgsWkbTypes.Type.PointM, + "Point M (0 0 1)", + ), + ( + osgeo.ogr.wkbPointZM, + "Point ZM (0 0 1 2)", + QgsWkbTypes.Type.PointZM, + "Point ZM (0 0 1 2)", + ), + ( + osgeo.ogr.wkbLineString, + "LineString (0 0, 1 1)", + QgsWkbTypes.Type.MultiLineString, + "MultiLineString ((0 0, 1 1))", + ), + ( + osgeo.ogr.wkbLineString25D, + "LineString Z (0 0 10, 1 1 10)", + QgsWkbTypes.Type.MultiLineStringZ, + "MultiLineString Z ((0 0 10, 1 1 10))", + ), + ( + osgeo.ogr.wkbLineStringM, + "LineString M (0 0 10, 1 1 10)", + QgsWkbTypes.Type.MultiLineStringM, + "MultiLineString M ((0 0 10, 1 1 10))", + ), + ( + osgeo.ogr.wkbLineStringZM, + "LineString ZM (0 0 10 20, 1 1 10 20)", + QgsWkbTypes.Type.MultiLineStringZM, + "MultiLineString ZM ((0 0 10 20, 1 1 10 20))", + ), + ( + osgeo.ogr.wkbPolygon, + "Polygon ((0 0,0 1,1 1,0 0))", + QgsWkbTypes.Type.MultiPolygon, + "MultiPolygon (((0 0, 0 1, 1 1, 0 0)))", + ), + ( + osgeo.ogr.wkbPolygon25D, + "Polygon Z ((0 0 10, 0 1 10, 1 1 10, 0 0 10))", + QgsWkbTypes.Type.MultiPolygonZ, + "MultiPolygon Z (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))", + ), + ( + osgeo.ogr.wkbPolygonM, + "Polygon M ((0 0 10, 0 1 10, 1 1 10, 0 0 10))", + QgsWkbTypes.Type.MultiPolygonM, + "MultiPolygon M (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))", + ), + ( + osgeo.ogr.wkbPolygonZM, + "Polygon ZM ((0 0 10 20, 0 1 10 20, 1 1 10 20, 0 0 10 20))", + QgsWkbTypes.Type.MultiPolygonZM, + "MultiPolygon ZM (((0 0 10 20, 0 1 10 20, 1 1 10 20, 0 0 10 20)))", + ), + ( + osgeo.ogr.wkbMultiPoint, + "MultiPoint (0 0,1 1)", + QgsWkbTypes.Type.MultiPoint, + "MultiPoint ((0 0),(1 1))", + ), + ( + osgeo.ogr.wkbMultiPoint25D, + "MultiPoint Z ((0 0 10), (1 1 10))", + QgsWkbTypes.Type.MultiPointZ, + "MultiPoint Z ((0 0 10),(1 1 10))", + ), + ( + osgeo.ogr.wkbMultiPointM, + "MultiPoint M ((0 0 10), (1 1 10))", + QgsWkbTypes.Type.MultiPointM, + "MultiPoint M ((0 0 10),(1 1 10))", + ), + ( + osgeo.ogr.wkbMultiPointZM, + "MultiPoint ZM ((0 0 10 20), (1 1 10 20))", + QgsWkbTypes.Type.MultiPointZM, + "MultiPoint ZM ((0 0 10 20),(1 1 10 20))", + ), + ( + osgeo.ogr.wkbMultiLineString, + "MultiLineString ((0 0, 1 1))", + QgsWkbTypes.Type.MultiLineString, + "MultiLineString ((0 0, 1 1))", + ), + ( + osgeo.ogr.wkbMultiLineString25D, + "MultiLineString Z ((0 0 10, 1 1 10))", + QgsWkbTypes.Type.MultiLineStringZ, + "MultiLineString Z ((0 0 10, 1 1 10))", + ), + ( + osgeo.ogr.wkbMultiLineStringM, + "MultiLineString M ((0 0 10, 1 1 10))", + QgsWkbTypes.Type.MultiLineStringM, + "MultiLineString M ((0 0 10, 1 1 10))", + ), + ( + osgeo.ogr.wkbMultiLineStringZM, + "MultiLineString ZM ((0 0 10 20, 1 1 10 20))", + QgsWkbTypes.Type.MultiLineStringZM, + "MultiLineString ZM ((0 0 10 20, 1 1 10 20))", + ), + ( + osgeo.ogr.wkbMultiPolygon, + "MultiPolygon (((0 0,0 1,1 1,0 0)))", + QgsWkbTypes.Type.MultiPolygon, + "MultiPolygon (((0 0, 0 1, 1 1, 0 0)))", + ), + ( + osgeo.ogr.wkbMultiPolygon25D, + "MultiPolygon Z (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))", + QgsWkbTypes.Type.MultiPolygonZ, + "MultiPolygon Z (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))", + ), + ( + osgeo.ogr.wkbMultiPolygonM, + "MultiPolygon M (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))", + QgsWkbTypes.Type.MultiPolygonM, + "MultiPolygon M (((0 0 10, 0 1 10, 1 1 10, 0 0 10)))", + ), + ( + osgeo.ogr.wkbMultiPolygonZM, + "MultiPolygon ZM (((0 0 10 20, 0 1 10 20, 1 1 10 20, 0 0 10 20)))", + QgsWkbTypes.Type.MultiPolygonZM, + "MultiPolygon ZM (((0 0 10 20, 0 1 10 20, 1 1 10 20, 0 0 10 20)))", + ), + ] for ogr_type, wkt, qgis_type, expected_wkt in tests: - filename = 'testPromoteToMulti' + filename = "testPromoteToMulti" tmpfile = os.path.join(self.basetestpath, filename) - ds = osgeo.ogr.GetDriverByName('ESRI Shapefile').CreateDataSource(tmpfile) + ds = osgeo.ogr.GetDriverByName("ESRI Shapefile").CreateDataSource(tmpfile) lyr = ds.CreateLayer(filename, geom_type=ogr_type) f = osgeo.ogr.Feature(lyr.GetLayerDefn()) f.SetGeometry(osgeo.ogr.CreateGeometryFromWkt(wkt)) lyr.CreateFeature(f) ds = None - vl = QgsVectorLayer(tmpfile, 'test', 'ogr') + vl = QgsVectorLayer(tmpfile, "test", "ogr") self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), qgis_type) f = next(vl.getFeatures()) self.assertEqual(f.geometry().constGet().asWkt(), expected_wkt) del vl - osgeo.ogr.GetDriverByName('ESRI Shapefile').DeleteDataSource(tmpfile) + osgeo.ogr.GetDriverByName("ESRI Shapefile").DeleteDataSource(tmpfile) def testEncoding_cp852(self): - """ Test that CP852 shapefile is read/written correctly """ + """Test that CP852 shapefile is read/written correctly""" tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) - for file in glob.glob(os.path.join(TEST_DATA_DIR, 'test_852.*')): + for file in glob.glob(os.path.join(TEST_DATA_DIR, "test_852.*")): shutil.copy(os.path.join(TEST_DATA_DIR, file), tmpdir) - datasource = os.path.join(tmpdir, 'test_852.shp') + datasource = os.path.join(tmpdir, "test_852.shp") - vl = QgsVectorLayer(datasource, 'test') + vl = QgsVectorLayer(datasource, "test") self.assertTrue(vl.isValid()) - self.assertEqual([f.attributes() for f in vl.dataProvider().getFeatures()], [['abcŐ']]) + self.assertEqual( + [f.attributes() for f in vl.dataProvider().getFeatures()], [["abcŐ"]] + ) f = QgsFeature() - f.setAttributes(['abcŐabcŐabcŐ']) + f.setAttributes(["abcŐabcŐabcŐ"]) self.assertTrue(vl.dataProvider().addFeature(f)) # read it back in - vl = QgsVectorLayer(datasource, 'test') + vl = QgsVectorLayer(datasource, "test") self.assertTrue(vl.isValid()) - self.assertEqual([f.attributes() for f in vl.dataProvider().getFeatures()], [['abcŐ'], ['abcŐabcŐabcŐ']]) + self.assertEqual( + [f.attributes() for f in vl.dataProvider().getFeatures()], + [["abcŐ"], ["abcŐabcŐabcŐ"]], + ) def testSkipFeatureCountOnFeatureCount(self): """Test QgsDataProvider.SkipFeatureCount on featureCount()""" - testPath = TEST_DATA_DIR + '/' + 'lines.shp' - provider = QgsProviderRegistry.instance().createProvider('ogr', testPath, QgsDataProvider.ProviderOptions(), QgsDataProvider.ReadFlag.SkipFeatureCount) + testPath = TEST_DATA_DIR + "/" + "lines.shp" + provider = QgsProviderRegistry.instance().createProvider( + "ogr", + testPath, + QgsDataProvider.ProviderOptions(), + QgsDataProvider.ReadFlag.SkipFeatureCount, + ) self.assertTrue(provider.isValid()) - self.assertEqual(provider.featureCount(), QgsVectorDataProvider.FeatureCountState.UnknownCount) + self.assertEqual( + provider.featureCount(), + QgsVectorDataProvider.FeatureCountState.UnknownCount, + ) def testSkipFeatureCountOnSubLayers(self): """Test QgsDataProvider.SkipFeatureCount on subLayers()""" - datasource = os.path.join(TEST_DATA_DIR, 'shapefile') - provider = QgsProviderRegistry.instance().createProvider('ogr', datasource, QgsDataProvider.ProviderOptions(), QgsDataProvider.ReadFlag.SkipFeatureCount) + datasource = os.path.join(TEST_DATA_DIR, "shapefile") + provider = QgsProviderRegistry.instance().createProvider( + "ogr", + datasource, + QgsDataProvider.ProviderOptions(), + QgsDataProvider.ReadFlag.SkipFeatureCount, + ) self.assertTrue(provider.isValid()) sublayers = provider.subLayers() self.assertGreater(len(sublayers), 1) - self.assertEqual(int(sublayers[0].split(QgsDataProvider.sublayerSeparator())[2]), int(Qgis.FeatureCountState.Uncounted)) + self.assertEqual( + int(sublayers[0].split(QgsDataProvider.sublayerSeparator())[2]), + int(Qgis.FeatureCountState.Uncounted), + ) def testLayersOnSameOGRLayerWithAndWithoutFilter(self): """Test fix for https://github.com/qgis/QGIS/issues/43361""" - file_path = os.path.join(TEST_DATA_DIR, 'provider', 'shapefile.shp') - uri = f'{file_path}|layerId=0|subset="name" = \'Apple\'' + file_path = os.path.join(TEST_DATA_DIR, "provider", "shapefile.shp") + uri = f"{file_path}|layerId=0|subset=\"name\" = 'Apple'" options = QgsDataProvider.ProviderOptions() - vl1 = QgsVectorLayer(uri, 'vl1', 'ogr') - vl2 = QgsVectorLayer(uri, 'vl2', 'ogr') - vl3 = QgsVectorLayer(f'{file_path}|layerId=0', 'vl3', 'ogr') + vl1 = QgsVectorLayer(uri, "vl1", "ogr") + vl2 = QgsVectorLayer(uri, "vl2", "ogr") + vl3 = QgsVectorLayer(f"{file_path}|layerId=0", "vl3", "ogr") self.assertEqual(vl1.featureCount(), 1) vl1_extent = QgsGeometry.fromRect(vl1.extent()) self.assertEqual(vl2.featureCount(), 1) @@ -1106,23 +1317,26 @@ def testLayersOnSameOGRLayerWithAndWithoutFilter(self): vl3_extent = QgsGeometry.fromRect(vl3.extent()) reference = QgsGeometry.fromRect(QgsRectangle(-68.2, 70.8, -68.2, 70.8)) - assert QgsGeometry.compare(vl1_extent.asPolygon()[0], reference.asPolygon()[0], - 0.00001), f'Expected {reference.asWkt()}, got {vl1_extent.asWkt()}' - assert QgsGeometry.compare(vl2_extent.asPolygon()[0], reference.asPolygon()[0], - 0.00001), f'Expected {reference.asWkt()}, got {vl2_extent.asWkt()}' + assert QgsGeometry.compare( + vl1_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001 + ), f"Expected {reference.asWkt()}, got {vl1_extent.asWkt()}" + assert QgsGeometry.compare( + vl2_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001 + ), f"Expected {reference.asWkt()}, got {vl2_extent.asWkt()}" reference = QgsGeometry.fromRect(QgsRectangle(-71.123, 66.33, -65.32, 78.3)) - assert QgsGeometry.compare(vl3_extent.asPolygon()[0], reference.asPolygon()[0], - 0.00001), f'Expected {reference.asWkt()}, got {vl3_extent.asWkt()}' + assert QgsGeometry.compare( + vl3_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001 + ), f"Expected {reference.asWkt()}, got {vl3_extent.asWkt()}" def testWritingMultiPolygon(self): """Test that a MultiPolygon written to a Shape Polygon layer doesn't get converted to Polygon""" - tmpfile = os.path.join(self.basetestpath, 'testWritingMultiPolygon.shp') - ds = osgeo.ogr.GetDriverByName('ESRI Shapefile').CreateDataSource(tmpfile) - ds.CreateLayer('testWritingMultiPolygon', geom_type=osgeo.ogr.wkbPolygon) + tmpfile = os.path.join(self.basetestpath, "testWritingMultiPolygon.shp") + ds = osgeo.ogr.GetDriverByName("ESRI Shapefile").CreateDataSource(tmpfile) + ds.CreateLayer("testWritingMultiPolygon", geom_type=osgeo.ogr.wkbPolygon) ds = None - vl = QgsVectorLayer(tmpfile, 'test') + vl = QgsVectorLayer(tmpfile, "test") f = QgsFeature() f.setAttributes([200]) wkt = "MultiPolygon (((0 0, 0 1, 1 1, 0 0)),((10 0, 10 1, 11 1, 10 0)))" @@ -1133,26 +1347,26 @@ def testWritingMultiPolygon(self): self.assertEqual(f.geometry().constGet().asWkt(), wkt) def testFilterWithComment(self): - file_path = os.path.join(TEST_DATA_DIR, 'provider', 'shapefile.shp') - uri = f'{file_path}|layerid=0|subset="name" = \'Apple\' -- comment' - vl = QgsVectorLayer(uri, 'test', 'ogr') + file_path = os.path.join(TEST_DATA_DIR, "provider", "shapefile.shp") + uri = f"{file_path}|layerid=0|subset=\"name\" = 'Apple' -- comment" + vl = QgsVectorLayer(uri, "test", "ogr") self.assertTrue(vl.isValid()) - self.assertEqual(vl.subsetString(), '"name" = \'Apple\' -- comment') + self.assertEqual(vl.subsetString(), "\"name\" = 'Apple' -- comment") self.assertEqual(vl.featureCount(), 1) f = next(vl.getFeatures()) - self.assertEqual(f['name'], 'Apple') + self.assertEqual(f["name"], "Apple") def testRecomputeExtent(self): """Test that extents are recomputed correctly after update""" tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - for file in glob.glob(os.path.join(srcpath, 'shapefile.*')): + srcpath = os.path.join(TEST_DATA_DIR, "provider") + for file in glob.glob(os.path.join(srcpath, "shapefile.*")): shutil.copy(os.path.join(srcpath, file), tmpdir) - datasource = os.path.join(tmpdir, 'shapefile.shp') + datasource = os.path.join(tmpdir, "shapefile.shp") - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") extent = vl.extent() vl.startEditing() for fet in vl.getFeatures(): @@ -1167,10 +1381,10 @@ def testRecomputeExtent(self): # close file and reopen, then recheck to confirm that changes were saved to file del vl vl = None - vl = QgsVectorLayer(f'{datasource}|layerid=0', 'test', 'ogr') + vl = QgsVectorLayer(f"{datasource}|layerid=0", "test", "ogr") reopened_extent = vl.extent() self.assertEqual(reopened_extent, updated_extent) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_provider_spatialite.py b/tests/src/python/test_provider_spatialite.py index 4bf9f9cbd249..a88a80c3fefa 100644 --- a/tests/src/python/test_provider_spatialite.py +++ b/tests/src/python/test_provider_spatialite.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Vincent Mora' -__date__ = '09/07/2013' -__copyright__ = 'Copyright 2013, The QGIS Project' + +__author__ = "Vincent Mora" +__date__ = "09/07/2013" +__copyright__ = "Copyright 2013, The QGIS Project" import os import re @@ -38,7 +39,9 @@ QgsVectorLayer, QgsVectorLayerExporter, QgsVectorLayerUtils, - QgsWkbTypes, NULL) + QgsWkbTypes, + NULL, +) import unittest from qgis.testing import start_app, QgisTestCase from qgis.utils import spatialite_connect @@ -53,12 +56,12 @@ def count_opened_filedescriptors(filename_to_test): count = -1 - if sys.platform.startswith('linux'): + if sys.platform.startswith("linux"): count = 0 - open_files_dirname = '/proc/%d/fd' % os.getpid() + open_files_dirname = "/proc/%d/fd" % os.getpid() filenames = os.listdir(open_files_dirname) for filename in filenames: - full_filename = open_files_dirname + '/' + filename + full_filename = open_files_dirname + "/" + filename if os.path.exists(full_filename): link = os.readlink(full_filename) if os.path.basename(link) == os.path.basename(filename_to_test): @@ -71,21 +74,27 @@ class TestQgsSpatialiteProvider(QgisTestCase, ProviderTestCase): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestQgsSpatialiteProvider, cls).setUpClass() - print(' ### Setup Spatialite Provider Test Class') + super().setUpClass() + print(" ### Setup Spatialite Provider Test Class") # setup provider for base tests cls.vl = QgsVectorLayer( - 'dbname=\'{}/provider/spatialite.db\' table="somedata" (geom) sql='.format( - TEST_DATA_DIR), 'test', - 'spatialite') - assert (cls.vl.isValid()) + "dbname='{}/provider/spatialite.db' table=\"somedata\" (geom) sql=".format( + TEST_DATA_DIR + ), + "test", + "spatialite", + ) + assert cls.vl.isValid() cls.source = cls.vl.dataProvider() cls.vl_poly = QgsVectorLayer( - 'dbname=\'{}/provider/spatialite.db\' table="somepolydata" (geom) sql='.format( - TEST_DATA_DIR), 'test', - 'spatialite') - assert (cls.vl_poly.isValid()) + "dbname='{}/provider/spatialite.db' table=\"somepolydata\" (geom) sql=".format( + TEST_DATA_DIR + ), + "test", + "spatialite", + ) + assert cls.vl_poly.isValid() cls.poly_provider = cls.vl_poly.dataProvider() # create test db @@ -99,16 +108,22 @@ def setUpClass(cls): cur.execute(sql) # simple table with primary key - sql = "CREATE TABLE test_pg (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)" + sql = ( + "CREATE TABLE test_pg (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)" + ) cur.execute(sql) sql = "SELECT AddGeometryColumn('test_pg', 'geometry', 4326, 'POLYGON', 'XY')" cur.execute(sql) sql = "INSERT INTO test_pg (id, name, geometry) " - sql += "VALUES (1, 'toto 1', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))" + sql += ( + "VALUES (1, 'toto 1', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))" + ) cur.execute(sql) # table with Z dimension geometry, 1 point - sql = "CREATE TABLE test_z (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)" + sql = ( + "CREATE TABLE test_z (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)" + ) cur.execute(sql) sql = "SELECT AddGeometryColumn('test_z', 'geometry', 4326, 'POINT', 'XYZ')" cur.execute(sql) @@ -117,7 +132,9 @@ def setUpClass(cls): cur.execute(sql) # table with Z dimension geometry, multiple points - sql = "CREATE TABLE test_z2 (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)" + sql = ( + "CREATE TABLE test_z2 (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)" + ) cur.execute(sql) sql = "SELECT AddGeometryColumn('test_z2', 'geometry', 4326, 'POINT', 'XYZ')" cur.execute(sql) @@ -127,7 +144,9 @@ def setUpClass(cls): cur.execute(sql) # table with M value geometry - sql = "CREATE TABLE test_m (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)" + sql = ( + "CREATE TABLE test_m (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)" + ) cur.execute(sql) sql = "SELECT AddGeometryColumn('test_m', 'geometry', 4326, 'POINT', 'XYM')" cur.execute(sql) @@ -136,7 +155,9 @@ def setUpClass(cls): cur.execute(sql) # table with Z dimension and M value geometry - sql = "CREATE TABLE test_zm (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)" + sql = ( + "CREATE TABLE test_zm (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)" + ) cur.execute(sql) sql = "SELECT AddGeometryColumn('test_zm', 'geometry', 4326, 'POINT', 'XYZM')" cur.execute(sql) @@ -147,14 +168,20 @@ def setUpClass(cls): # table with multiple column primary key sql = "CREATE TABLE test_pg_mk (id INTEGER NOT NULL, name TEXT NOT NULL, PRIMARY KEY(id,name))" cur.execute(sql) - sql = "SELECT AddGeometryColumn('test_pg_mk', 'geometry', 4326, 'POLYGON', 'XY')" + sql = ( + "SELECT AddGeometryColumn('test_pg_mk', 'geometry', 4326, 'POLYGON', 'XY')" + ) cur.execute(sql) sql = "INSERT INTO test_pg_mk (id, name, geometry) " - sql += "VALUES (1, 'toto 1', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))" + sql += ( + "VALUES (1, 'toto 1', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))" + ) cur.execute(sql) # simple table with primary key - sql = "CREATE TABLE test_q (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)" + sql = ( + "CREATE TABLE test_q (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)" + ) cur.execute(sql) sql = "SELECT AddGeometryColumn('test_q', 'geometry', 4326, 'POLYGON', 'XY')" cur.execute(sql) @@ -166,21 +193,29 @@ def setUpClass(cls): cur.execute(sql) # simple table with a geometry column named 'Geometry' - sql = "CREATE TABLE test_n (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)" + sql = ( + "CREATE TABLE test_n (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)" + ) cur.execute(sql) sql = "SELECT AddGeometryColumn('test_n', 'Geometry', 4326, 'POLYGON', 'XY')" cur.execute(sql) sql = "INSERT INTO test_n (id, name, geometry) " - sql += "VALUES (1, 'toto 1', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))" + sql += ( + "VALUES (1, 'toto 1', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))" + ) cur.execute(sql) sql = "INSERT INTO test_n (id, name, geometry) " - sql += "VALUES (2, 'toto 1', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))" + sql += ( + "VALUES (2, 'toto 1', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))" + ) cur.execute(sql) # table with different array types, stored as JSON sql = "CREATE TABLE test_arrays (id INTEGER NOT NULL PRIMARY KEY, strings JSONSTRINGLIST NOT NULL, ints JSONINTEGERLIST NOT NULL, reals JSONREALLIST NOT NULL)" cur.execute(sql) - sql = "SELECT AddGeometryColumn('test_arrays', 'Geometry', 4326, 'POLYGON', 'XY')" + sql = ( + "SELECT AddGeometryColumn('test_arrays', 'Geometry', 4326, 'POLYGON', 'XY')" + ) cur.execute(sql) sql = "INSERT INTO test_arrays (id, strings, ints, reals, geometry) " sql += "VALUES (1, '[\"toto\",\"tutu\"]', '[1,-2,724562]', '[1.0, -232567.22]', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))" @@ -261,9 +296,11 @@ def setUpClass(cls): cur.execute(sql) # no fields table - sql = "CREATE TABLE \"test_nofields\"(pkuid integer primary key autoincrement)" + sql = 'CREATE TABLE "test_nofields"(pkuid integer primary key autoincrement)' cur.execute(sql) - sql = "SELECT AddGeometryColumn('test_nofields', 'geometry', 4326, 'POINT', 'XY')" + sql = ( + "SELECT AddGeometryColumn('test_nofields', 'geometry', 4326, 'POINT', 'XY')" + ) cur.execute(sql) # constraints check table @@ -278,7 +315,7 @@ def setUpClass(cls): cur.execute(sql) # Unique and not null constraints - sql = "CREATE TABLE \"unique_not_null_constraints\"(pkuid integer primary key autoincrement, \"unique\" TEXT UNIQUE, \"not_null\" TEXT NOT NULL)" + sql = 'CREATE TABLE "unique_not_null_constraints"(pkuid integer primary key autoincrement, "unique" TEXT UNIQUE, "not_null" TEXT NOT NULL)' cur.execute(sql) sql = "SELECT AddGeometryColumn('unique_not_null_constraints', 'geometry', 4326, 'POINT', 'XY')" cur.execute(sql) @@ -295,11 +332,15 @@ def setUpClass(cls): cur.execute(sql) # Transaction tables - sql = "CREATE TABLE \"test_transactions1\"(pkuid integer primary key autoincrement)" + sql = ( + 'CREATE TABLE "test_transactions1"(pkuid integer primary key autoincrement)' + ) cur.execute(sql) - sql = "CREATE TABLE \"test_transactions2\"(pkuid integer primary key autoincrement)" + sql = ( + 'CREATE TABLE "test_transactions2"(pkuid integer primary key autoincrement)' + ) cur.execute(sql) - sql = "INSERT INTO \"test_transactions2\" VALUES (NULL)" + sql = 'INSERT INTO "test_transactions2" VALUES (NULL)' cur.execute(sql) # table to test getQueryGeometryDetails() for geometries with Z, M and ZM @@ -325,36 +366,44 @@ def tearDownClass(cls): # os.remove(cls.dbname) for dirname in cls.dirs_to_cleanup: shutil.rmtree(dirname, True) - super(TestQgsSpatialiteProvider, cls).tearDownClass() + super().tearDownClass() def getSource(self): tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - datasource = os.path.join(tmpdir, 'spatialite.db') - shutil.copy(os.path.join(srcpath, 'spatialite.db'), datasource) + srcpath = os.path.join(TEST_DATA_DIR, "provider") + datasource = os.path.join(tmpdir, "spatialite.db") + shutil.copy(os.path.join(srcpath, "spatialite.db"), datasource) vl = QgsVectorLayer( - f'dbname=\'{datasource}\' table="somedata" (geom) sql=', 'test', - 'spatialite') + f"dbname='{datasource}' table=\"somedata\" (geom) sql=", + "test", + "spatialite", + ) return vl def getEditableLayerWithCheckConstraint(self): """Returns the layer for attribute change CHECK constraint violation""" vl = QgsVectorLayer( - 'dbname=\'{}\' table="check_constraint" (geometry) sql='.format( - self.dbname), 'check_constraint', - 'spatialite') + "dbname='{}' table=\"check_constraint\" (geometry) sql=".format( + self.dbname + ), + "check_constraint", + "spatialite", + ) return vl def getEditableLayerWithUniqueNotNullConstraints(self): """Returns the layer for UNIQUE and NOT NULL constraints detection""" vl = QgsVectorLayer( - 'dbname=\'{}\' table="unique_not_null_constraints" (geometry) sql='.format( - self.dbname), 'unique_not_null_constraints', - 'spatialite') + "dbname='{}' table=\"unique_not_null_constraints\" (geometry) sql=".format( + self.dbname + ), + "unique_not_null_constraints", + "spatialite", + ) return vl def treat_time_as_string(self): @@ -372,109 +421,119 @@ def tearDown(self): pass def enableCompiler(self): - QgsSettings().setValue('/qgis/compileExpressions', True) + QgsSettings().setValue("/qgis/compileExpressions", True) return True def disableCompiler(self): - QgsSettings().setValue('/qgis/compileExpressions', False) + QgsSettings().setValue("/qgis/compileExpressions", False) def uncompiledFilters(self): - return {'cnt = 10 ^ 2', - '"name" ~ \'[OP]ra[gne]+\'', - 'sqrt(pk) >= 2', - 'radians(cnt) < 2', - 'degrees(pk) <= 200', - 'cos(pk) < 0', - 'sin(pk) < 0', - 'tan(pk) < 0', - 'acos(-1) < pk', - 'asin(1) < pk', - 'atan(3.14) < pk', - 'atan2(3.14, pk) < 1', - 'exp(pk) < 10', - 'ln(pk) <= 1', - 'log(3, pk) <= 1', - 'log10(pk) < 0.5', - 'floor(3.14) <= pk', - 'ceil(3.14) <= pk', - 'pk < pi()', - 'floor(cnt / 66.67) <= 2', - 'ceil(cnt / 66.67) <= 2', - 'pk < pi() / 2', - 'x($geometry) < -70', - 'y($geometry) > 70', - 'xmin($geometry) < -70', - 'ymin($geometry) > 70', - 'xmax($geometry) < -70', - 'ymax($geometry) > 70', - 'disjoint($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', - 'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', - 'contains(geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'),$geometry)', - 'distance($geometry,geom_from_wkt( \'Point (-70 70)\')) > 7', - 'intersects($geometry,geom_from_gml( \'-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1\'))', - 'x($geometry) < -70', - 'y($geometry) > 79', - 'xmin($geometry) < -70', - 'ymin($geometry) < 76', - 'xmax($geometry) > -68', - 'ymax($geometry) > 80', - 'area($geometry) > 10', - 'perimeter($geometry) < 12', - 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\')) = \'FF2FF1212\'', - 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'), \'****F****\')', - 'crosses($geometry,geom_from_wkt( \'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)\'))', - 'overlaps($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'))', - 'within($geometry,geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - 'overlaps(translate($geometry,-1,-1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - 'overlaps(buffer($geometry,1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', - 'intersects(centroid($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', - 'intersects(point_on_surface($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', - '"dt" = to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\')', - '"dt" <= format_date(make_datetime(2020, 5, 4, 12, 13, 14), \'yyyy-MM-dd hh:mm:ss\')', - '"dt" < format_date(make_date(2020, 5, 4), \'yyyy-MM-dd hh:mm:ss\')', - '"dt" = format_date(to_datetime(\'000www14ww13ww12www4ww5ww2020\',\'zzzwwwsswwmmwwhhwwwdwwMwwyyyy\'),\'yyyy-MM-dd hh:mm:ss\')', - 'to_time("time") >= make_time(12, 14, 14)', - 'to_time("time") = to_time(\'000www14ww13ww12www\',\'zzzwwwsswwmmwwhhwww\')', - '"date" = to_date(\'www4ww5ww2020\',\'wwwdwwMwwyyyy\')', - 'dt BETWEEN make_datetime(2020, 5, 3, 12, 13, 14) AND make_datetime(2020, 5, 4, 12, 14, 14)', - 'dt NOT BETWEEN make_datetime(2020, 5, 3, 12, 13, 14) AND make_datetime(2020, 5, 4, 12, 14, 14)', - '"dt" <= make_datetime(2020, 5, 4, 12, 13, 14)', - '"date" <= make_datetime(2020, 5, 4, 12, 13, 14)' - } + return { + "cnt = 10 ^ 2", + "\"name\" ~ '[OP]ra[gne]+'", + "sqrt(pk) >= 2", + "radians(cnt) < 2", + "degrees(pk) <= 200", + "cos(pk) < 0", + "sin(pk) < 0", + "tan(pk) < 0", + "acos(-1) < pk", + "asin(1) < pk", + "atan(3.14) < pk", + "atan2(3.14, pk) < 1", + "exp(pk) < 10", + "ln(pk) <= 1", + "log(3, pk) <= 1", + "log10(pk) < 0.5", + "floor(3.14) <= pk", + "ceil(3.14) <= pk", + "pk < pi()", + "floor(cnt / 66.67) <= 2", + "ceil(cnt / 66.67) <= 2", + "pk < pi() / 2", + "x($geometry) < -70", + "y($geometry) > 70", + "xmin($geometry) < -70", + "ymin($geometry) > 70", + "xmax($geometry) < -70", + "ymax($geometry) > 70", + "disjoint($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))", + "intersects($geometry,geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'))", + "contains(geom_from_wkt( 'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))'),$geometry)", + "distance($geometry,geom_from_wkt( 'Point (-70 70)')) > 7", + "intersects($geometry,geom_from_gml( '-72.2,66.1 -65.2,66.1 -65.2,72.0 -72.2,72.0 -72.2,66.1'))", + "x($geometry) < -70", + "y($geometry) > 79", + "xmin($geometry) < -70", + "ymin($geometry) < 76", + "xmax($geometry) > -68", + "ymax($geometry) > 80", + "area($geometry) > 10", + "perimeter($geometry) < 12", + "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))')) = 'FF2FF1212'", + "relate($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'), '****F****')", + "crosses($geometry,geom_from_wkt( 'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)'))", + "overlaps($geometry,geom_from_wkt( 'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))'))", + "within($geometry,geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + "overlaps(translate($geometry,-1,-1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + "overlaps(buffer($geometry,1),geom_from_wkt( 'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))'))", + "intersects(centroid($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))", + "intersects(point_on_surface($geometry),geom_from_wkt( 'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))'))", + "\"dt\" = to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy')", + "\"dt\" <= format_date(make_datetime(2020, 5, 4, 12, 13, 14), 'yyyy-MM-dd hh:mm:ss')", + "\"dt\" < format_date(make_date(2020, 5, 4), 'yyyy-MM-dd hh:mm:ss')", + "\"dt\" = format_date(to_datetime('000www14ww13ww12www4ww5ww2020','zzzwwwsswwmmwwhhwwwdwwMwwyyyy'),'yyyy-MM-dd hh:mm:ss')", + 'to_time("time") >= make_time(12, 14, 14)', + "to_time(\"time\") = to_time('000www14ww13ww12www','zzzwwwsswwmmwwhhwww')", + "\"date\" = to_date('www4ww5ww2020','wwwdwwMwwyyyy')", + "dt BETWEEN make_datetime(2020, 5, 3, 12, 13, 14) AND make_datetime(2020, 5, 4, 12, 14, 14)", + "dt NOT BETWEEN make_datetime(2020, 5, 3, 12, 13, 14) AND make_datetime(2020, 5, 4, 12, 14, 14)", + '"dt" <= make_datetime(2020, 5, 4, 12, 13, 14)', + '"date" <= make_datetime(2020, 5, 4, 12, 13, 14)', + } def partiallyCompiledFilters(self): - return {'"name" NOT LIKE \'Ap%\'', - 'name LIKE \'Apple\'', - 'name LIKE \'aPple\'', - 'name LIKE \'Ap_le\'', - 'name LIKE \'Ap\\_le\'' - } + return { + "\"name\" NOT LIKE 'Ap%'", + "name LIKE 'Apple'", + "name LIKE 'aPple'", + "name LIKE 'Ap_le'", + "name LIKE 'Ap\\_le'", + } def test_SplitFeature(self): """Create SpatiaLite database""" - layer = QgsVectorLayer("dbname=%s table=test_pg (geometry)" % - self.dbname, "test_pg", "spatialite") + layer = QgsVectorLayer( + "dbname=%s table=test_pg (geometry)" % self.dbname, "test_pg", "spatialite" + ) self.assertTrue(layer.isValid()) self.assertTrue(layer.isSpatial()) layer.startEditing() - self.assertEqual(layer.splitFeatures( - [QgsPointXY(0.75, -0.5), QgsPointXY(0.75, 1.5)], 0), 0) - self.assertEqual(layer.splitFeatures( - [QgsPointXY(-0.5, 0.25), QgsPointXY(1.5, 0.25)], 0), 0) + self.assertEqual( + layer.splitFeatures([QgsPointXY(0.75, -0.5), QgsPointXY(0.75, 1.5)], 0), 0 + ) + self.assertEqual( + layer.splitFeatures([QgsPointXY(-0.5, 0.25), QgsPointXY(1.5, 0.25)], 0), 0 + ) self.assertTrue(layer.commitChanges()) self.assertEqual(layer.featureCount(), 4) def test_SplitFeatureWithMultiKey(self): """Create SpatiaLite database""" - layer = QgsVectorLayer("dbname=%s table=test_pg_mk (geometry)" % - self.dbname, "test_pg_mk", "spatialite") + layer = QgsVectorLayer( + "dbname=%s table=test_pg_mk (geometry)" % self.dbname, + "test_pg_mk", + "spatialite", + ) self.assertTrue(layer.isValid()) self.assertTrue(layer.isSpatial()) layer.startEditing() - self.assertEqual(layer.splitFeatures( - [QgsPointXY(0.5, -0.5), QgsPointXY(0.5, 1.5)], 0), 0) - self.assertEqual(layer.splitFeatures( - [QgsPointXY(-0.5, 0.5), QgsPointXY(1.5, 0.5)], 0), 0) + self.assertEqual( + layer.splitFeatures([QgsPointXY(0.5, -0.5), QgsPointXY(0.5, 1.5)], 0), 0 + ) + self.assertEqual( + layer.splitFeatures([QgsPointXY(-0.5, 0.5), QgsPointXY(1.5, 0.5)], 0), 0 + ) self.assertTrue(layer.commitChanges()) def test_crash_on_constraint_detection(self): @@ -482,16 +541,22 @@ def test_crash_on_constraint_detection(self): Test that constraint detection does not crash """ # should be no crash! - QgsVectorLayer(f"dbname={TEST_DATA_DIR + '/views_test.sqlite'} table=KNN", "KNN", - "spatialite") + QgsVectorLayer( + f"dbname={TEST_DATA_DIR + '/views_test.sqlite'} table=KNN", + "KNN", + "spatialite", + ) def test_queries(self): """Test loading of query-based layers""" # a query with a geometry, but no unique id # the id will be autoincremented - l = QgsVectorLayer(f"dbname={self.dbname} table='(select * from test_q)' (geometry)", "test_pg_query1", - "spatialite") + l = QgsVectorLayer( + f"dbname={self.dbname} table='(select * from test_q)' (geometry)", + "test_pg_query1", + "spatialite", + ) self.assertTrue(l.isValid()) # the id() is autoincremented sum_id1 = sum(f.id() for f in l.getFeatures()) @@ -501,8 +566,11 @@ def test_queries(self): self.assertEqual(sum_id2, 32) # 11 + 21 # and now with an id declared - l = QgsVectorLayer(f"dbname={self.dbname} table='(select * from test_q)' (geometry) key='id'", - "test_pg_query1", "spatialite") + l = QgsVectorLayer( + f"dbname={self.dbname} table='(select * from test_q)' (geometry) key='id'", + "test_pg_query1", + "spatialite", + ) self.assertTrue(l.isValid()) sum_id1 = sum(f.id() for f in l.getFeatures()) sum_id2 = sum(f.attributes()[0] for f in l.getFeatures()) @@ -510,8 +578,11 @@ def test_queries(self): self.assertEqual(sum_id2, 32) # a query, but no geometry - l = QgsVectorLayer(f"dbname={self.dbname} table='(select id,name from test_q)' key='id'", "test_pg_query1", - "spatialite") + l = QgsVectorLayer( + f"dbname={self.dbname} table='(select id,name from test_q)' key='id'", + "test_pg_query1", + "spatialite", + ) self.assertTrue(l.isValid()) sum_id1 = sum(f.id() for f in l.getFeatures()) sum_id2 = sum(f.attributes()[0] for f in l.getFeatures()) @@ -520,24 +591,33 @@ def test_queries(self): def test_zm(self): """Test Z dimension and M value""" - l = QgsVectorLayer("dbname=%s table='test_z' (geometry) key='id'" % - self.dbname, "test_z", "spatialite") + l = QgsVectorLayer( + "dbname=%s table='test_z' (geometry) key='id'" % self.dbname, + "test_z", + "spatialite", + ) self.assertTrue(l.isValid()) self.assertTrue(QgsWkbTypes.hasZ(l.wkbType())) feature = l.getFeature(1) geom = feature.geometry().constGet() self.assertEqual(geom.z(), 1.0) - l = QgsVectorLayer("dbname=%s table='test_m' (geometry) key='id'" % - self.dbname, "test_m", "spatialite") + l = QgsVectorLayer( + "dbname=%s table='test_m' (geometry) key='id'" % self.dbname, + "test_m", + "spatialite", + ) self.assertTrue(l.isValid()) self.assertTrue(QgsWkbTypes.hasM(l.wkbType())) feature = l.getFeature(1) geom = feature.geometry().constGet() self.assertEqual(geom.m(), 1.0) - l = QgsVectorLayer("dbname=%s table='test_zm' (geometry) key='id'" % - self.dbname, "test_zm", "spatialite") + l = QgsVectorLayer( + "dbname=%s table='test_zm' (geometry) key='id'" % self.dbname, + "test_zm", + "spatialite", + ) self.assertTrue(l.isValid()) self.assertTrue(QgsWkbTypes.hasZ(l.wkbType())) self.assertTrue(QgsWkbTypes.hasM(l.wkbType())) @@ -548,34 +628,41 @@ def test_zm(self): def test_case(self): """Test case sensitivity issues""" - l = QgsVectorLayer("dbname=%s table='test_n' (geometry) key='id'" % - self.dbname, "test_n1", "spatialite") + l = QgsVectorLayer( + "dbname=%s table='test_n' (geometry) key='id'" % self.dbname, + "test_n1", + "spatialite", + ) self.assertTrue(l.isValid()) self.assertEqual(l.dataProvider().fields().count(), 2) fields = [f.name() for f in l.dataProvider().fields()] - self.assertNotIn('Geometry', fields) + self.assertNotIn("Geometry", fields) def test_invalid_iterator(self): - """ Test invalid iterator """ - corrupt_dbname = self.dbname + '.corrupt' + """Test invalid iterator""" + corrupt_dbname = self.dbname + ".corrupt" shutil.copy(self.dbname, corrupt_dbname) - layer = QgsVectorLayer("dbname=%s table=test_pg (geometry)" % - corrupt_dbname, "test_pg", "spatialite") + layer = QgsVectorLayer( + "dbname=%s table=test_pg (geometry)" % corrupt_dbname, + "test_pg", + "spatialite", + ) # Corrupt the database - with open(corrupt_dbname, 'wb') as f: - f.write(b'') + with open(corrupt_dbname, "wb") as f: + f.write(b"") layer.getFeatures() layer = None os.unlink(corrupt_dbname) def testNoDanglingFileDescriptorAfterCloseVariant1(self): - ''' Test that when closing the provider all file handles are released ''' + """Test that when closing the provider all file handles are released""" - temp_dbname = self.dbname + '.no_dangling_test1' + temp_dbname = self.dbname + ".no_dangling_test1" shutil.copy(self.dbname, temp_dbname) - vl = QgsVectorLayer("dbname=%s table=test_n (geometry)" % - temp_dbname, "test_n", "spatialite") + vl = QgsVectorLayer( + "dbname=%s table=test_n (geometry)" % temp_dbname, "test_n", "spatialite" + ) self.assertTrue(vl.isValid()) # The iterator will take one extra connection myiter = vl.getFeatures() @@ -584,14 +671,14 @@ def testNoDanglingFileDescriptorAfterCloseVariant1(self): f = next(myiter) self.assertTrue(f.isValid()) - if sys.platform.startswith('linux'): + if sys.platform.startswith("linux"): self.assertEqual(count_opened_filedescriptors(temp_dbname), 2) # does NO release one file descriptor, because shared with the iterator del vl # Non portable, but Windows testing is done with trying to unlink - if sys.platform.startswith('linux'): + if sys.platform.startswith("linux"): self.assertEqual(count_opened_filedescriptors(temp_dbname), 2) f = next(myiter) @@ -601,7 +688,7 @@ def testNoDanglingFileDescriptorAfterCloseVariant1(self): del myiter # Non portable, but Windows testing is done with trying to unlink - if sys.platform.startswith('linux'): + if sys.platform.startswith("linux"): self.assertEqual(count_opened_filedescriptors(temp_dbname), 0) # Check that deletion works well (can only fail on Windows) @@ -609,13 +696,14 @@ def testNoDanglingFileDescriptorAfterCloseVariant1(self): self.assertFalse(os.path.exists(temp_dbname)) def testNoDanglingFileDescriptorAfterCloseVariant2(self): - ''' Test that when closing the provider all file handles are released ''' + """Test that when closing the provider all file handles are released""" - temp_dbname = self.dbname + '.no_dangling_test2' + temp_dbname = self.dbname + ".no_dangling_test2" shutil.copy(self.dbname, temp_dbname) - vl = QgsVectorLayer("dbname=%s table=test_n (geometry)" % - temp_dbname, "test_n", "spatialite") + vl = QgsVectorLayer( + "dbname=%s table=test_n (geometry)" % temp_dbname, "test_n", "spatialite" + ) self.assertTrue(vl.isValid()) self.assertTrue(vl.isValid()) # Consume all features. @@ -623,14 +711,14 @@ def testNoDanglingFileDescriptorAfterCloseVariant2(self): for feature in myiter: pass # The iterator is closed - if sys.platform.startswith('linux'): + if sys.platform.startswith("linux"): self.assertEqual(count_opened_filedescriptors(temp_dbname), 2) # Should release one file descriptor del vl # Non portable, but Windows testing is done with trying to unlink - if sys.platform.startswith('linux'): + if sys.platform.startswith("linux"): self.assertEqual(count_opened_filedescriptors(temp_dbname), 0) # Check that deletion works well (can only fail on Windows) @@ -639,94 +727,106 @@ def testNoDanglingFileDescriptorAfterCloseVariant2(self): def test_arrays(self): """Test loading of layers with arrays""" - l = QgsVectorLayer("dbname=%s table=test_arrays (geometry)" % - self.dbname, "test_arrays", "spatialite") + l = QgsVectorLayer( + "dbname=%s table=test_arrays (geometry)" % self.dbname, + "test_arrays", + "spatialite", + ) self.assertTrue(l.isValid()) features = [f for f in l.getFeatures()] self.assertEqual(len(features), 1) - strings_field = l.fields().field('strings') - self.assertEqual(strings_field.typeName(), 'jsonstringlist') + strings_field = l.fields().field("strings") + self.assertEqual(strings_field.typeName(), "jsonstringlist") self.assertEqual(strings_field.type(), QVariant.StringList) self.assertEqual(strings_field.subType(), QVariant.String) strings = features[0].attributes()[1] - self.assertEqual(strings, ['toto', 'tutu']) + self.assertEqual(strings, ["toto", "tutu"]) - ints_field = l.fields().field('ints') - self.assertEqual(ints_field.typeName(), 'jsonintegerlist') + ints_field = l.fields().field("ints") + self.assertEqual(ints_field.typeName(), "jsonintegerlist") self.assertEqual(ints_field.type(), QVariant.List) self.assertEqual(ints_field.subType(), QVariant.LongLong) ints = features[0].attributes()[2] self.assertEqual(ints, [1, -2, 724562]) - reals_field = l.fields().field('reals') - self.assertEqual(reals_field.typeName(), 'jsonreallist') + reals_field = l.fields().field("reals") + self.assertEqual(reals_field.typeName(), "jsonreallist") self.assertEqual(reals_field.type(), QVariant.List) self.assertEqual(reals_field.subType(), QVariant.Double) reals = features[0].attributes()[3] self.assertEqual(reals, [1.0, -232567.22]) new_f = QgsFeature(l.fields()) - new_f['id'] = 2 - new_f['strings'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash'] - new_f['ints'] = [1, 2, 3, 4] - new_f['reals'] = [1e67, 1e-56] + new_f["id"] = 2 + new_f["strings"] = ["simple", '"doubleQuote"', "'quote'", "back\\slash"] + new_f["ints"] = [1, 2, 3, 4] + new_f["reals"] = [1e67, 1e-56] r, fs = l.dataProvider().addFeatures([new_f]) self.assertTrue(r) - read_back = l.getFeature(new_f['id']) - self.assertEqual(read_back['id'], new_f['id']) - self.assertEqual(read_back['strings'], new_f['strings']) - self.assertEqual(read_back['ints'], new_f['ints']) - self.assertEqual(read_back['reals'], new_f['reals']) + read_back = l.getFeature(new_f["id"]) + self.assertEqual(read_back["id"], new_f["id"]) + self.assertEqual(read_back["strings"], new_f["strings"]) + self.assertEqual(read_back["ints"], new_f["ints"]) + self.assertEqual(read_back["reals"], new_f["reals"]) def test_arrays_write(self): """Test writing of layers with arrays""" - l = QgsVectorLayer("dbname=%s table=test_arrays_write (geometry)" % - self.dbname, "test_arrays", "spatialite") + l = QgsVectorLayer( + "dbname=%s table=test_arrays_write (geometry)" % self.dbname, + "test_arrays", + "spatialite", + ) self.assertTrue(l.isValid()) new_f = QgsFeature(l.fields()) - new_f['id'] = 2 - new_f['array'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash'] - new_f['strings'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash'] - new_f['ints'] = [1, 2, 3, 4] - new_f['reals'] = [1e67, 1e-56] + new_f["id"] = 2 + new_f["array"] = ["simple", '"doubleQuote"', "'quote'", "back\\slash"] + new_f["strings"] = ["simple", '"doubleQuote"', "'quote'", "back\\slash"] + new_f["ints"] = [1, 2, 3, 4] + new_f["reals"] = [1e67, 1e-56] r, fs = l.dataProvider().addFeatures([new_f]) self.assertTrue(r) - read_back = l.getFeature(new_f['id']) - self.assertEqual(read_back['id'], new_f['id']) - self.assertEqual(read_back['array'], new_f['array']) - self.assertEqual(read_back['strings'], new_f['strings']) - self.assertEqual(read_back['ints'], new_f['ints']) - self.assertEqual(read_back['reals'], new_f['reals']) + read_back = l.getFeature(new_f["id"]) + self.assertEqual(read_back["id"], new_f["id"]) + self.assertEqual(read_back["array"], new_f["array"]) + self.assertEqual(read_back["strings"], new_f["strings"]) + self.assertEqual(read_back["ints"], new_f["ints"]) + self.assertEqual(read_back["reals"], new_f["reals"]) new_f = QgsFeature(l.fields()) - new_f['id'] = 3 - new_f['array'] = [1, 1.2345, '"doubleQuote"', "'quote'", 'back\\slash'] - new_f['strings'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash'] - new_f['ints'] = [1, 2, 3, 4] - new_f['reals'] = [1e67, 1e-56] + new_f["id"] = 3 + new_f["array"] = [1, 1.2345, '"doubleQuote"', "'quote'", "back\\slash"] + new_f["strings"] = ["simple", '"doubleQuote"', "'quote'", "back\\slash"] + new_f["ints"] = [1, 2, 3, 4] + new_f["reals"] = [1e67, 1e-56] r, fs = l.dataProvider().addFeatures([new_f]) self.assertTrue(r) - read_back = l.getFeature(new_f['id']) - self.assertEqual(read_back['id'], new_f['id']) - self.assertEqual(read_back['array'], new_f['array']) - self.assertEqual(read_back['strings'], new_f['strings']) - self.assertEqual(read_back['ints'], new_f['ints']) - self.assertEqual(read_back['reals'], new_f['reals']) + read_back = l.getFeature(new_f["id"]) + self.assertEqual(read_back["id"], new_f["id"]) + self.assertEqual(read_back["array"], new_f["array"]) + self.assertEqual(read_back["strings"], new_f["strings"]) + self.assertEqual(read_back["ints"], new_f["ints"]) + self.assertEqual(read_back["reals"], new_f["reals"]) - read_back = l.getFeature(new_f['id']) + read_back = l.getFeature(new_f["id"]) def test_discover_relation(self): - artist = QgsVectorLayer(f"dbname={self.dbname} table=test_relation_a (geometry)", "test_relation_a", - "spatialite") + artist = QgsVectorLayer( + f"dbname={self.dbname} table=test_relation_a (geometry)", + "test_relation_a", + "spatialite", + ) self.assertTrue(artist.isValid()) - track = QgsVectorLayer(f"dbname={self.dbname} table=test_relation_b (geometry)", "test_relation_b", - "spatialite") + track = QgsVectorLayer( + f"dbname={self.dbname} table=test_relation_b (geometry)", + "test_relation_b", + "spatialite", + ) self.assertTrue(track.isValid()) QgsProject.instance().addMapLayer(artist) QgsProject.instance().addMapLayer(track) @@ -734,12 +834,12 @@ def test_discover_relation(self): relMgr = QgsProject.instance().relationManager() relations = relMgr.discoverRelations([], [artist, track]) relations = {r.name(): r for r in relations} - self.assertEqual({'fk_test_relation_b_0'}, set(relations.keys())) + self.assertEqual({"fk_test_relation_b_0"}, set(relations.keys())) - a2t = relations['fk_test_relation_b_0'] + a2t = relations["fk_test_relation_b_0"] self.assertTrue(a2t.isValid()) - self.assertEqual('test_relation_b', a2t.referencingLayer().name()) - self.assertEqual('test_relation_a', a2t.referencedLayer().name()) + self.assertEqual("test_relation_b", a2t.referencingLayer().name()) + self.assertEqual("test_relation_a", a2t.referencedLayer().name()) self.assertEqual([2], a2t.referencingFields()) self.assertEqual([0], a2t.referencedFields()) finally: @@ -747,112 +847,197 @@ def test_discover_relation(self): QgsProject.instance().removeMapLayer(artist.id()) def testNotNullConstraint(self): - vl = QgsVectorLayer(f"dbname={self.dbname} table=test_constraints key='id'", "test_constraints", - "spatialite") + vl = QgsVectorLayer( + f"dbname={self.dbname} table=test_constraints key='id'", + "test_constraints", + "spatialite", + ) self.assertTrue(vl.isValid()) self.assertEqual(len(vl.fields()), 5) # test some bad field indexes - self.assertEqual(vl.dataProvider().fieldConstraints(-1), - QgsFieldConstraints.Constraints()) - self.assertEqual(vl.dataProvider().fieldConstraints( - 1001), QgsFieldConstraints.Constraints()) - - self.assertTrue(vl.dataProvider().fieldConstraints(0) & - QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertTrue(vl.dataProvider().fieldConstraints(1) & - QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertFalse(vl.dataProvider().fieldConstraints(2) - & QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertFalse(vl.dataProvider().fieldConstraints(3) - & QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertTrue(vl.dataProvider().fieldConstraints(4) & - QgsFieldConstraints.Constraint.ConstraintNotNull) + self.assertEqual( + vl.dataProvider().fieldConstraints(-1), QgsFieldConstraints.Constraints() + ) + self.assertEqual( + vl.dataProvider().fieldConstraints(1001), QgsFieldConstraints.Constraints() + ) + + self.assertTrue( + vl.dataProvider().fieldConstraints(0) + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertTrue( + vl.dataProvider().fieldConstraints(1) + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertFalse( + vl.dataProvider().fieldConstraints(2) + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertFalse( + vl.dataProvider().fieldConstraints(3) + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertTrue( + vl.dataProvider().fieldConstraints(4) + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) # test that constraints have been saved to fields correctly fields = vl.fields() - self.assertTrue(fields.at(0).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertEqual(fields.at(0).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) - self.assertTrue(fields.at(1).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertEqual(fields.at(1).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) - self.assertFalse(fields.at(2).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertFalse(fields.at(3).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertTrue(fields.at(4).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertEqual(fields.at(4).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) + self.assertTrue( + fields.at(0).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertEqual( + fields.at(0) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) + self.assertTrue( + fields.at(1).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertEqual( + fields.at(1) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) + self.assertFalse( + fields.at(2).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertFalse( + fields.at(3).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertTrue( + fields.at(4).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertEqual( + fields.at(4) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) def testUniqueConstraint(self): - vl = QgsVectorLayer(f"dbname={self.dbname} table=test_constraints key='id'", "test_constraints", - "spatialite") + vl = QgsVectorLayer( + f"dbname={self.dbname} table=test_constraints key='id'", + "test_constraints", + "spatialite", + ) self.assertTrue(vl.isValid()) self.assertEqual(len(vl.fields()), 5) # test some bad field indexes - self.assertEqual(vl.dataProvider().fieldConstraints(-1), - QgsFieldConstraints.Constraints()) - self.assertEqual(vl.dataProvider().fieldConstraints( - 1001), QgsFieldConstraints.Constraints()) - - self.assertTrue(vl.dataProvider().fieldConstraints(0) - & QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertFalse(vl.dataProvider().fieldConstraints(1) - & QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertTrue(vl.dataProvider().fieldConstraints(2) - & QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertFalse(vl.dataProvider().fieldConstraints(3) - & QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertTrue(vl.dataProvider().fieldConstraints(4) - & QgsFieldConstraints.Constraint.ConstraintUnique) + self.assertEqual( + vl.dataProvider().fieldConstraints(-1), QgsFieldConstraints.Constraints() + ) + self.assertEqual( + vl.dataProvider().fieldConstraints(1001), QgsFieldConstraints.Constraints() + ) + + self.assertTrue( + vl.dataProvider().fieldConstraints(0) + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + self.assertFalse( + vl.dataProvider().fieldConstraints(1) + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + self.assertTrue( + vl.dataProvider().fieldConstraints(2) + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + self.assertFalse( + vl.dataProvider().fieldConstraints(3) + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + self.assertTrue( + vl.dataProvider().fieldConstraints(4) + & QgsFieldConstraints.Constraint.ConstraintUnique + ) # test that constraints have been saved to fields correctly fields = vl.fields() - self.assertTrue(fields.at(0).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertEqual(fields.at(0).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) - self.assertFalse(fields.at(1).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertTrue(fields.at(2).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertEqual(fields.at(2).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) - self.assertFalse(fields.at(3).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertTrue(fields.at(4).constraints().constraints() - & QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertEqual(fields.at(4).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) + self.assertTrue( + fields.at(0).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + self.assertEqual( + fields.at(0) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) + self.assertFalse( + fields.at(1).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + self.assertTrue( + fields.at(2).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + self.assertEqual( + fields.at(2) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) + self.assertFalse( + fields.at(3).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + self.assertTrue( + fields.at(4).constraints().constraints() + & QgsFieldConstraints.Constraint.ConstraintUnique + ) + self.assertEqual( + fields.at(4) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) def testSkipConstraintCheck(self): - vl = QgsVectorLayer(f"dbname={self.dbname} table=test_autoincrement", "test_autoincrement", - "spatialite") + vl = QgsVectorLayer( + f"dbname={self.dbname} table=test_autoincrement", + "test_autoincrement", + "spatialite", + ) self.assertTrue(vl.isValid()) self.assertTrue( - vl.dataProvider().skipConstraintCheck(0, QgsFieldConstraints.Constraint.ConstraintUnique, "Autogenerate")) - self.assertFalse(vl.dataProvider().skipConstraintCheck( - 0, QgsFieldConstraints.Constraint.ConstraintUnique, 123)) + vl.dataProvider().skipConstraintCheck( + 0, QgsFieldConstraints.Constraint.ConstraintUnique, "Autogenerate" + ) + ) + self.assertFalse( + vl.dataProvider().skipConstraintCheck( + 0, QgsFieldConstraints.Constraint.ConstraintUnique, 123 + ) + ) # This test would fail. It would require turning on WAL def XXXXXtestLocking(self): - temp_dbname = self.dbname + '.locking' + temp_dbname = self.dbname + ".locking" shutil.copy(self.dbname, temp_dbname) - vl = QgsVectorLayer("dbname=%s table=test_n (geometry)" % - temp_dbname, "test_n", "spatialite") + vl = QgsVectorLayer( + "dbname=%s table=test_n (geometry)" % temp_dbname, "test_n", "spatialite" + ) self.assertTrue(vl.isValid()) self.assertTrue(vl.startEditing()) - self.assertTrue(vl.changeGeometry( - 1, QgsGeometry.fromWkt('POLYGON((0 0,1 0,1 1,0 1,0 0))'))) + self.assertTrue( + vl.changeGeometry(1, QgsGeometry.fromWkt("POLYGON((0 0,1 0,1 1,0 1,0 0))")) + ) # The iterator will take one extra connection myiter = vl.getFeatures() @@ -865,8 +1050,11 @@ def XXXXXtestLocking(self): def testDefaultValues(self): - l = QgsVectorLayer("dbname=%s table='test_defaults' key='id'" % - self.dbname, "test_defaults", "spatialite") + l = QgsVectorLayer( + "dbname=%s table='test_defaults' key='id'" % self.dbname, + "test_defaults", + "spatialite", + ) self.assertTrue(l.isValid()) self.assertEqual(l.dataProvider().defaultValue(1), "qgis 'is good") @@ -875,29 +1063,35 @@ def testDefaultValues(self): self.assertFalse(l.dataProvider().defaultValue(4)) def testVectorLayerUtilsCreateFeatureWithProviderDefaultLiteral(self): - vl = QgsVectorLayer("dbname=%s table='test_defaults' key='id'" % - self.dbname, "test_defaults", "spatialite") + vl = QgsVectorLayer( + "dbname=%s table='test_defaults' key='id'" % self.dbname, + "test_defaults", + "spatialite", + ) self.assertEqual(vl.dataProvider().defaultValue(2), 5) f = QgsVectorLayerUtils.createFeature(vl) self.assertEqual(f.attributes(), [None, "qgis 'is good", 5, 5.7, None]) # check that provider default literals do not take precedence over passed attribute values - f = QgsVectorLayerUtils.createFeature( - vl, attributes={1: 'qgis is great', 0: 3}) + f = QgsVectorLayerUtils.createFeature(vl, attributes={1: "qgis is great", 0: 3}) self.assertEqual(f.attributes(), [3, "qgis is great", 5, 5.7, None]) # test that vector layer default value expression overrides provider default literal vl.setDefaultValueDefinition(3, QgsDefaultValue("4*3")) - f = QgsVectorLayerUtils.createFeature( - vl, attributes={1: 'qgis is great', 0: 3}) + f = QgsVectorLayerUtils.createFeature(vl, attributes={1: "qgis is great", 0: 3}) self.assertEqual(f.attributes(), [3, "qgis is great", 5, 12, None]) def testCreateAttributeIndex(self): - vl = QgsVectorLayer("dbname=%s table='test_defaults' key='id'" % - self.dbname, "test_defaults", "spatialite") - self.assertTrue(vl.dataProvider().capabilities() & - QgsVectorDataProvider.Capability.CreateAttributeIndex) + vl = QgsVectorLayer( + "dbname=%s table='test_defaults' key='id'" % self.dbname, + "test_defaults", + "spatialite", + ) + self.assertTrue( + vl.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.CreateAttributeIndex + ) self.assertFalse(vl.dataProvider().createAttributeIndex(-1)) self.assertFalse(vl.dataProvider().createAttributeIndex(100)) self.assertTrue(vl.dataProvider().createAttributeIndex(1)) @@ -905,19 +1099,21 @@ def testCreateAttributeIndex(self): con = spatialite_connect(self.dbname, isolation_level=None) cur = con.cursor() rs = cur.execute( - "SELECT * FROM sqlite_master WHERE type='index' AND tbl_name='test_defaults'") + "SELECT * FROM sqlite_master WHERE type='index' AND tbl_name='test_defaults'" + ) res = [row for row in rs] self.assertEqual(len(res), 1) index_name = res[0][1] rs = cur.execute(f"PRAGMA index_info({index_name})") res = [row for row in rs] self.assertEqual(len(res), 1) - self.assertEqual(res[0][2], 'name') + self.assertEqual(res[0][2], "name") # second index self.assertTrue(vl.dataProvider().createAttributeIndex(2)) rs = cur.execute( - "SELECT * FROM sqlite_master WHERE type='index' AND tbl_name='test_defaults'") + "SELECT * FROM sqlite_master WHERE type='index' AND tbl_name='test_defaults'" + ) res = [row for row in rs] self.assertEqual(len(res), 2) indexed_columns = [] @@ -928,100 +1124,102 @@ def testCreateAttributeIndex(self): self.assertEqual(len(res), 1) indexed_columns.append(res[0][2]) - self.assertEqual(set(indexed_columns), {'name', 'number'}) + self.assertEqual(set(indexed_columns), {"name", "number"}) con.close() def testSubsetStringRegexp(self): """Check that the provider supports the REGEXP syntax""" testPath = f"dbname={self.dbname} table='test_filter' (geometry) key='id'" - vl = QgsVectorLayer(testPath, 'test', 'spatialite') + vl = QgsVectorLayer(testPath, "test", "spatialite") self.assertTrue(vl.isValid()) - vl.setSubsetString('"name" REGEXP \'[txe]{3}\'') + vl.setSubsetString("\"name\" REGEXP '[txe]{3}'") self.assertEqual(vl.featureCount(), 4) - del (vl) + del vl def testSubsetStringExtent_bug17863(self): """Check that the extent is correct when applied in the ctor and when - modified after a subset string is set """ + modified after a subset string is set""" def _lessdigits(s): - return re.sub(r'(\d+\.\d{3})\d+', r'\1', s) + return re.sub(r"(\d+\.\d{3})\d+", r"\1", s) testPath = f"dbname={self.dbname} table='test_filter' (geometry) key='id'" - subSetString = '"name" = \'int\'' - subSet = f' sql={subSetString}' + subSetString = "\"name\" = 'int'" + subSet = f" sql={subSetString}" # unfiltered - vl = QgsVectorLayer(testPath, 'test', 'spatialite') + vl = QgsVectorLayer(testPath, "test", "spatialite") self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 8) unfiltered_extent = _lessdigits(vl.extent().toString()) - self.assertNotEqual('Empty', unfiltered_extent) - del (vl) + self.assertNotEqual("Empty", unfiltered_extent) + del vl # filter after construction ... - subSet_vl2 = QgsVectorLayer(testPath, 'test', 'spatialite') - self.assertEqual(_lessdigits( - subSet_vl2.extent().toString()), unfiltered_extent) + subSet_vl2 = QgsVectorLayer(testPath, "test", "spatialite") + self.assertEqual(_lessdigits(subSet_vl2.extent().toString()), unfiltered_extent) self.assertEqual(subSet_vl2.featureCount(), 8) # ... apply filter now! subSet_vl2.setSubsetString(subSetString) self.assertEqual(subSet_vl2.featureCount(), 4) self.assertEqual(subSet_vl2.subsetString(), subSetString) - self.assertNotEqual(_lessdigits( - subSet_vl2.extent().toString()), unfiltered_extent) + self.assertNotEqual( + _lessdigits(subSet_vl2.extent().toString()), unfiltered_extent + ) filtered_extent = _lessdigits(subSet_vl2.extent().toString()) - del (subSet_vl2) + del subSet_vl2 # filtered in constructor - subSet_vl = QgsVectorLayer( - testPath + subSet, 'subset_test', 'spatialite') + subSet_vl = QgsVectorLayer(testPath + subSet, "subset_test", "spatialite") self.assertEqual(subSet_vl.subsetString(), subSetString) self.assertTrue(subSet_vl.isValid()) # This was failing in bug 17863 self.assertEqual(subSet_vl.featureCount(), 4) - self.assertEqual(_lessdigits( - subSet_vl.extent().toString()), filtered_extent) - self.assertNotEqual(_lessdigits( - subSet_vl.extent().toString()), unfiltered_extent) + self.assertEqual(_lessdigits(subSet_vl.extent().toString()), filtered_extent) + self.assertNotEqual( + _lessdigits(subSet_vl.extent().toString()), unfiltered_extent + ) - self.assertTrue(subSet_vl.setSubsetString('')) + self.assertTrue(subSet_vl.setSubsetString("")) self.assertEqual(subSet_vl.featureCount(), 8) - self.assertEqual(_lessdigits( - subSet_vl.extent().toString()), unfiltered_extent) + self.assertEqual(_lessdigits(subSet_vl.extent().toString()), unfiltered_extent) def testDecodeUri(self): """Check that the provider URI decoding returns expected values""" - filename = '/home/to/path/test.db' - uri = f'dbname=\'{filename}\' table="test" (geometry) key=testkey sql=1=1' + filename = "/home/to/path/test.db" + uri = f"dbname='{filename}' table=\"test\" (geometry) key=testkey sql=1=1" registry = QgsProviderRegistry.instance() - components = registry.decodeUri('spatialite', uri) - self.assertEqual(components['path'], filename) - self.assertEqual(components['layerName'], 'test') - self.assertEqual(components['subset'], '1=1') - self.assertEqual(components['geometryColumn'], 'geometry') - self.assertEqual(components['keyColumn'], 'testkey') + components = registry.decodeUri("spatialite", uri) + self.assertEqual(components["path"], filename) + self.assertEqual(components["layerName"], "test") + self.assertEqual(components["subset"], "1=1") + self.assertEqual(components["geometryColumn"], "geometry") + self.assertEqual(components["keyColumn"], "testkey") def testEncodeUri(self): """Check that the provider URI encoding returns expected values""" - filename = '/home/to/path/test.db' + filename = "/home/to/path/test.db" registry = QgsProviderRegistry.instance() - parts = {'path': filename, - 'layerName': 'test', - 'subset': '1=1', - 'geometryColumn': 'geometry', - 'keyColumn': 'testkey'} - uri = registry.encodeUri('spatialite', parts) - self.assertEqual(uri, f'dbname=\'{filename}\' key=\'testkey\' table="test" (geometry) sql=1=1') + parts = { + "path": filename, + "layerName": "test", + "subset": "1=1", + "geometryColumn": "geometry", + "keyColumn": "testkey", + } + uri = registry.encodeUri("spatialite", parts) + self.assertEqual( + uri, f"dbname='{filename}' key='testkey' table=\"test\" (geometry) sql=1=1" + ) def testPKNotInt(self): - """ Check when primary key is not an integer """ + """Check when primary key is not an integer""" # create test db tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) @@ -1030,7 +1228,7 @@ def testPKNotInt(self): cur = con.cursor() # try the two different types of index creation - for index_creation_method in ['CreateSpatialIndex', 'CreateMbrCache']: + for index_creation_method in ["CreateSpatialIndex", "CreateMbrCache"]: table_name = f"pk_is_string_{index_creation_method}" cur.execute("BEGIN") @@ -1038,7 +1236,9 @@ def testPKNotInt(self): cur.execute(sql) # create table with spatial index and pk is string - sql = "CREATE TABLE {}(id VARCHAR PRIMARY KEY NOT NULL, name TEXT NOT NULL);" + sql = ( + "CREATE TABLE {}(id VARCHAR PRIMARY KEY NOT NULL, name TEXT NOT NULL);" + ) cur.execute(sql.format(table_name)) sql = "SELECT AddGeometryColumn('{}', 'geometry', 4326, 'POINT', 'XY')" @@ -1053,7 +1253,7 @@ def testPKNotInt(self): cur.execute("COMMIT") testPath = f"dbname={dbname} table='{table_name}' (geometry)" - vl = QgsVectorLayer(testPath, 'test', 'spatialite') + vl = QgsVectorLayer(testPath, "test", "spatialite") self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 1) @@ -1084,41 +1284,57 @@ def testLoadStyle(self): cur.execute(sql) # simple table with primary key - sql = "CREATE TABLE test_pg (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)" + sql = ( + "CREATE TABLE test_pg (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)" + ) cur.execute(sql) sql = "SELECT AddGeometryColumn('test_pg', 'geometry', 4326, 'POLYGON', 'XY')" cur.execute(sql) sql = "INSERT INTO test_pg (id, name, geometry) " - sql += "VALUES (1, 'toto', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))" + sql += ( + "VALUES (1, 'toto', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))" + ) cur.execute(sql) cur.execute("COMMIT") con.close() testPath = f"dbname={dbname} table='test_pg' (geometry) key='id'" - vl = QgsVectorLayer(testPath, 'test', 'spatialite') + vl = QgsVectorLayer(testPath, "test", "spatialite") self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 1) err, ok = vl.loadDefaultStyle() self.assertFalse(ok) - vl.saveStyleToDatabase('my_style', 'My description', True, '') + vl.saveStyleToDatabase("my_style", "My description", True, "") err, ok = vl.loadDefaultStyle() self.assertTrue(ok) def testStyleStorage(self): # First test with invalid URI - vl = QgsVectorLayer('/idont/exist.sqlite', 'test', 'spatialite') + vl = QgsVectorLayer("/idont/exist.sqlite", "test", "spatialite") - self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, 0) - self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.SaveToDatabase, 0) + self.assertEqual( + int(vl.dataProvider().styleStorageCapabilities()) + & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, + 0, + ) + self.assertEqual( + int(vl.dataProvider().styleStorageCapabilities()) + & Qgis.ProviderStyleStorageCapability.SaveToDatabase, + 0, + ) - res, err = QgsProviderRegistry.instance().styleExists('spatialite', '/idont/exist.sqlite', '') + res, err = QgsProviderRegistry.instance().styleExists( + "spatialite", "/idont/exist.sqlite", "" + ) self.assertFalse(res) self.assertTrue(err) - res, err = QgsProviderRegistry.instance().styleExists('spatialite', '/idont/exist.sqlite', 'a style') + res, err = QgsProviderRegistry.instance().styleExists( + "spatialite", "/idont/exist.sqlite", "a style" + ) self.assertFalse(res) self.assertTrue(err) @@ -1133,7 +1349,7 @@ def testStyleStorage(self): self.assertFalse(qml) self.assertTrue(errmsg) - qml, success = vl.loadNamedStyle('/idont/exist.sqlite') + qml, success = vl.loadNamedStyle("/idont/exist.sqlite") self.assertFalse(success) errorMsg = vl.saveStyleToDatabase("name", "description", False, "") @@ -1150,31 +1366,47 @@ def testStyleStorage(self): cur.execute(sql) # simple table with primary key - sql = "CREATE TABLE test_pg (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)" + sql = ( + "CREATE TABLE test_pg (id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL)" + ) cur.execute(sql) sql = "SELECT AddGeometryColumn('test_pg', 'geometry', 4326, 'POLYGON', 'XY')" cur.execute(sql) sql = "INSERT INTO test_pg (id, name, geometry) " - sql += "VALUES (1, 'toto', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))" + sql += ( + "VALUES (1, 'toto', GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))', 4326))" + ) cur.execute(sql) cur.execute("COMMIT") con.close() testPath = f"dbname={dbname} table='test_pg' (geometry) key='id'" - vl = QgsVectorLayer(testPath, 'test', 'spatialite') + vl = QgsVectorLayer(testPath, "test", "spatialite") self.assertTrue(vl.isValid()) - self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, Qgis.ProviderStyleStorageCapability.LoadFromDatabase) - self.assertEqual(int(vl.dataProvider().styleStorageCapabilities()) & Qgis.ProviderStyleStorageCapability.SaveToDatabase, Qgis.ProviderStyleStorageCapability.SaveToDatabase) + self.assertEqual( + int(vl.dataProvider().styleStorageCapabilities()) + & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, + Qgis.ProviderStyleStorageCapability.LoadFromDatabase, + ) + self.assertEqual( + int(vl.dataProvider().styleStorageCapabilities()) + & Qgis.ProviderStyleStorageCapability.SaveToDatabase, + Qgis.ProviderStyleStorageCapability.SaveToDatabase, + ) # style tables don't exist yet - res, err = QgsProviderRegistry.instance().styleExists('spatialite', vl.source(), '') + res, err = QgsProviderRegistry.instance().styleExists( + "spatialite", vl.source(), "" + ) self.assertFalse(res) self.assertFalse(err) - res, err = QgsProviderRegistry.instance().styleExists('spatialite', vl.source(), 'a style') + res, err = QgsProviderRegistry.instance().styleExists( + "spatialite", vl.source(), "a style" + ) self.assertFalse(res) self.assertFalse(err) @@ -1189,19 +1421,25 @@ def testStyleStorage(self): self.assertFalse(qml) self.assertTrue(errmsg) - qml, success = vl.loadNamedStyle(f'{dbname}|layerid=0') + qml, success = vl.loadNamedStyle(f"{dbname}|layerid=0") self.assertFalse(success) errorMsg = vl.saveStyleToDatabase("name", "description", False, "") self.assertEqual(errorMsg, "") - res, err = QgsProviderRegistry.instance().styleExists('spatialite', vl.source(), '') + res, err = QgsProviderRegistry.instance().styleExists( + "spatialite", vl.source(), "" + ) self.assertFalse(res) self.assertFalse(err) - res, err = QgsProviderRegistry.instance().styleExists('spatialite', vl.source(), 'a style') + res, err = QgsProviderRegistry.instance().styleExists( + "spatialite", vl.source(), "a style" + ) self.assertFalse(res) self.assertFalse(err) - res, err = QgsProviderRegistry.instance().styleExists('spatialite', vl.source(), 'name') + res, err = QgsProviderRegistry.instance().styleExists( + "spatialite", vl.source(), "name" + ) self.assertTrue(res) self.assertFalse(err) @@ -1212,16 +1450,16 @@ def testStyleStorage(self): related_count, idlist, namelist, desclist, errmsg = vl.listStylesInDatabase() self.assertEqual(related_count, 1) self.assertFalse(errmsg) - self.assertEqual(idlist, ['1']) - self.assertEqual(namelist, ['name']) - self.assertEqual(desclist, ['description']) + self.assertEqual(idlist, ["1"]) + self.assertEqual(namelist, ["name"]) + self.assertEqual(desclist, ["description"]) qml, errmsg = vl.getStyleFromDatabase("100") self.assertEqual(qml, "") self.assertNotEqual(errmsg, "") qml, errmsg = vl.getStyleFromDatabase("1") - self.assertTrue(qml.startswith('?layer=ogr:{percent_path_relative}', content) + content = "".join(f.readlines()) + self.assertIn(f"?layer=ogr:{percent_path_relative}", content) # Check that project is correctly re-read with all layers QgsProject.instance().setFileName(temp) @@ -874,17 +1230,19 @@ def test_relative_paths(self): self.assertEqual(len(QgsProject.instance().mapLayers()), 2) # Store absolute - QgsProject.instance().writeEntryBool('Paths', '/Absolute', True) + QgsProject.instance().writeEntryBool("Paths", "/Absolute", True) QgsProject.instance().write() QgsProject.instance().clear() self.assertEqual(len(QgsProject.instance().mapLayers()), 0) # Check that virtual layer source is stored with absolute path - percent_path_absolute = toPercent(os.path.join(self.testDataDir, "france_parts.shp")) + percent_path_absolute = toPercent( + os.path.join(self.testDataDir, "france_parts.shp") + ) with open(temp) as f: - content = ''.join(f.readlines()) - self.assertIn(f'?layer=ogr:{percent_path_absolute}', content) + content = "".join(f.readlines()) + self.assertIn(f"?layer=ogr:{percent_path_absolute}", content) # Check that project is correctly re-read with all layers QgsProject.instance().setFileName(temp) @@ -893,10 +1251,14 @@ def test_relative_paths(self): def test_absolute_relative_uri(self): context = QgsReadWriteContext() - context.setPathResolver(QgsPathResolver(os.path.join(self.testDataDir, "project.qgs"))) + context.setPathResolver( + QgsPathResolver(os.path.join(self.testDataDir, "project.qgs")) + ) df_abs = QgsVirtualLayerDefinition() - df_abs.addSource("vtab", os.path.join(self.testDataDir, "france_parts.shp"), "ogr") + df_abs.addSource( + "vtab", os.path.join(self.testDataDir, "france_parts.shp"), "ogr" + ) df_rel = QgsVirtualLayerDefinition() df_rel.addSource("vtab", "./france_parts.shp", "ogr") @@ -907,25 +1269,35 @@ def test_absolute_relative_uri(self): meta = QgsProviderRegistry.instance().providerMetadata("virtual") assert meta is not None - self.assertEqual(meta.absoluteToRelativeUri(absolute_uri, context), relative_uri) - self.assertEqual(meta.relativeToAbsoluteUri(relative_uri, context), absolute_uri) + self.assertEqual( + meta.absoluteToRelativeUri(absolute_uri, context), relative_uri + ) + self.assertEqual( + meta.relativeToAbsoluteUri(relative_uri, context), absolute_uri + ) def test_qgisExpressionFunctions(self): - QgsProject.instance().setTitle('project') - self.assertEqual(QgsProject.instance().title(), 'project') + QgsProject.instance().setTitle("project") + self.assertEqual(QgsProject.instance().title(), "project") df = QgsVirtualLayerDefinition() df.setQuery( - "SELECT format('hello %1', 'world') as a, year(todate('2016-01-02')) as b, title('This') as t, var('project_title') as c") + "SELECT format('hello %1', 'world') as a, year(todate('2016-01-02')) as b, title('This') as t, var('project_title') as c" + ) l = QgsVectorLayer(df.toString(), "testq", "virtual") self.assertTrue(l.isValid()) for f in l.getFeatures(): - self.assertEqual(f.attributes(), ['hello world', 2016, 'This', 'project']) + self.assertEqual(f.attributes(), ["hello world", 2016, "This", "project"]) def test_query_with_accents(self): # shapefile with accents and latin1 encoding df = QgsVirtualLayerDefinition() - df.addSource("vtab", os.path.join(self.testDataDir, "france_parts.shp"), "ogr", "ISO-8859-1") + df.addSource( + "vtab", + os.path.join(self.testDataDir, "france_parts.shp"), + "ogr", + "ISO-8859-1", + ) df.setQuery("SELECT * FROM vtab WHERE TYPE_1 = 'Région'") vl = QgsVectorLayer(df.toString(), "testq", "virtual") self.assertTrue(vl.isValid()) @@ -933,7 +1305,9 @@ def test_query_with_accents(self): self.assertEqual(len(ids), 4) # the same shapefile with a wrong encoding - df.addSource("vtab", os.path.join(self.testDataDir, "france_parts.shp"), "ogr", "UTF-8") + df.addSource( + "vtab", os.path.join(self.testDataDir, "france_parts.shp"), "ogr", "UTF-8" + ) df.setQuery("SELECT * FROM vtab WHERE TYPE_1 = 'Région'") vl2 = QgsVectorLayer(df.toString(), "testq", "virtual") self.assertTrue(vl2.isValid()) @@ -941,8 +1315,12 @@ def test_query_with_accents(self): self.assertEqual(ids, []) def test_layer_with_accents(self): - l1 = QgsVectorLayer(os.path.join(self.testDataDir, "france_parts.shp"), "françéà", "ogr", - QgsVectorLayer.LayerOptions(False)) + l1 = QgsVectorLayer( + os.path.join(self.testDataDir, "france_parts.shp"), + "françéà", + "ogr", + QgsVectorLayer.LayerOptions(False), + ) self.assertTrue(l1.isValid()) QgsProject.instance().addMapLayer(l1) @@ -957,8 +1335,12 @@ def test_layer_with_accents(self): QgsProject.instance().removeMapLayer(l1.id()) def test_lazy(self): - l1 = QgsVectorLayer(os.path.join(self.testDataDir, "france_parts.shp"), "françéà", "ogr", - QgsVectorLayer.LayerOptions(False)) + l1 = QgsVectorLayer( + os.path.join(self.testDataDir, "france_parts.shp"), + "françéà", + "ogr", + QgsVectorLayer.LayerOptions(False), + ) self.assertTrue(l1.isValid()) QgsProject.instance().addMapLayer(l1) @@ -978,16 +1360,29 @@ def test_lazy(self): QgsProject.instance().removeMapLayer(l1.id()) def test_joined_layers_conversion(self): - v1 = QgsVectorLayer("Point?field=id:integer&field=b_id:integer&field=c_id:integer&field=name:string", "A", - "memory") + v1 = QgsVectorLayer( + "Point?field=id:integer&field=b_id:integer&field=c_id:integer&field=name:string", + "A", + "memory", + ) self.assertTrue(v1.isValid()) - v2 = QgsVectorLayer("Point?field=id:integer&field=bname:string&field=bfield:integer", "B", "memory") + v2 = QgsVectorLayer( + "Point?field=id:integer&field=bname:string&field=bfield:integer", + "B", + "memory", + ) self.assertTrue(v2.isValid()) v3 = QgsVectorLayer("Point?field=id:integer&field=cname:string", "C", "memory") self.assertTrue(v3.isValid()) - tl1 = QgsVectorLayer("NoGeometry?field=id:integer&field=e_id:integer&field=0name:string", "D", "memory") + tl1 = QgsVectorLayer( + "NoGeometry?field=id:integer&field=e_id:integer&field=0name:string", + "D", + "memory", + ) self.assertTrue(tl1.isValid()) - tl2 = QgsVectorLayer("NoGeometry?field=id:integer&field=ena me:string", "E", "memory") + tl2 = QgsVectorLayer( + "NoGeometry?field=id:integer&field=ena me:string", "E", "memory" + ) self.assertTrue(tl2.isValid()) QgsProject.instance().addMapLayers([v1, v2, v3, tl1, tl2]) joinInfo = QgsVectorLayerJoinInfo() @@ -999,9 +1394,12 @@ def test_joined_layers_conversion(self): self.assertEqual(len(v1.fields()), 6) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) - self.assertEqual(df.query(), - 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "B_bname", j1."bfield" AS "B_bfield" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id"'.format( - v1.id(), v2.id())) + self.assertEqual( + df.query(), + 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "B_bname", j1."bfield" AS "B_bfield" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id"'.format( + v1.id(), v2.id() + ), + ) # with a field subset v1.removeJoin(v2.id()) @@ -1009,9 +1407,12 @@ def test_joined_layers_conversion(self): v1.addJoin(joinInfo) self.assertEqual(len(v1.fields()), 5) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) - self.assertEqual(df.query(), - 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "B_bname" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id"'.format( - v1.id(), v2.id())) + self.assertEqual( + df.query(), + 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "B_bname" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id"'.format( + v1.id(), v2.id() + ), + ) joinInfo.setJoinFieldNamesSubset(None) # add a table prefix to the join @@ -1020,9 +1421,12 @@ def test_joined_layers_conversion(self): v1.addJoin(joinInfo) self.assertEqual(len(v1.fields()), 6) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) - self.assertEqual(df.query(), - 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "BB_bname", j1."bfield" AS "BB_bfield" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id"'.format( - v1.id(), v2.id())) + self.assertEqual( + df.query(), + 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "BB_bname", j1."bfield" AS "BB_bfield" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id"'.format( + v1.id(), v2.id() + ), + ) joinInfo.setPrefix("") v1.removeJoin(v2.id()) v1.addJoin(joinInfo) @@ -1035,10 +1439,14 @@ def test_joined_layers_conversion(self): v1.addJoin(joinInfo2) self.assertEqual(len(v1.fields()), 7) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) - self.assertEqual(df.query(), ( - 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "B_bname", j1."bfield" AS "B_bfield", j2."cname" AS "C_cname" FROM "{}" AS t ' + - 'LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id" ' + - 'LEFT JOIN "{}" AS j2 ON t."c_id"=j2."id"').format(v1.id(), v2.id(), v3.id())) + self.assertEqual( + df.query(), + ( + 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "B_bname", j1."bfield" AS "B_bfield", j2."cname" AS "C_cname" FROM "{}" AS t ' + + 'LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id" ' + + 'LEFT JOIN "{}" AS j2 ON t."c_id"=j2."id"' + ).format(v1.id(), v2.id(), v3.id()), + ) # test NoGeometry joined layers with field names starting with a digit or containing white spaces joinInfo3 = QgsVectorLayerJoinInfo() @@ -1048,65 +1456,96 @@ def test_joined_layers_conversion(self): tl1.addJoin(joinInfo3) self.assertEqual(len(tl1.fields()), 4) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(tl1) - self.assertEqual(df.query(), - 'SELECT t.rowid AS uid, t."id", t."e_id", t."0name", j1."ena me" AS "E_ena me" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."e_id"=j1."id"'.format( - tl1.id(), tl2.id())) + self.assertEqual( + df.query(), + 'SELECT t.rowid AS uid, t."id", t."e_id", t."0name", j1."ena me" AS "E_ena me" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."e_id"=j1."id"'.format( + tl1.id(), tl2.id() + ), + ) - QgsProject.instance().removeMapLayers([v1.id(), v2.id(), v3.id(), tl1.id(), tl2.id()]) + QgsProject.instance().removeMapLayers( + [v1.id(), v2.id(), v3.id(), tl1.id(), tl2.id()] + ) def testFieldsWithSpecialCharacters(self): - ml = QgsVectorLayer("Point?srid=EPSG:4326&field=123:int", "mem_with_nontext_fieldnames", "memory") + ml = QgsVectorLayer( + "Point?srid=EPSG:4326&field=123:int", + "mem_with_nontext_fieldnames", + "memory", + ) self.assertTrue(ml.isValid()) QgsProject.instance().addMapLayer(ml) ml.startEditing() - self.assertTrue(ml.addAttribute(QgsField('abc:123', QVariant.String))) - self.assertTrue(ml.addAttribute(QgsField('map', QVariant.String))) # matches QGIS expression function name + self.assertTrue(ml.addAttribute(QgsField("abc:123", QVariant.String))) + self.assertTrue( + ml.addAttribute(QgsField("map", QVariant.String)) + ) # matches QGIS expression function name f1 = QgsFeature(ml.fields()) - f1.setGeometry(QgsGeometry.fromWkt('POINT(0 0)')) - f1.setAttributes([1, 'a', 'b']) + f1.setGeometry(QgsGeometry.fromWkt("POINT(0 0)")) + f1.setAttributes([1, "a", "b"]) f2 = QgsFeature(ml.fields()) - f2.setGeometry(QgsGeometry.fromWkt('POINT(1 1)')) - f2.setAttributes([2, 'c', 'd']) + f2.setGeometry(QgsGeometry.fromWkt("POINT(1 1)")) + f2.setAttributes([2, "c", "d"]) ml.addFeatures([f1, f2]) ml.commitChanges() - vl = QgsVectorLayer("?query=select * from mem_with_nontext_fieldnames", "vl", "virtual") + vl = QgsVectorLayer( + "?query=select * from mem_with_nontext_fieldnames", "vl", "virtual" + ) self.assertTrue(vl.isValid()) - self.assertEqual(vl.fields().at(0).name(), '123') - self.assertEqual(vl.fields().at(1).name(), 'abc:123') + self.assertEqual(vl.fields().at(0).name(), "123") + self.assertEqual(vl.fields().at(1).name(), "abc:123") self.assertEqual(vl.featureCount(), 2) - features = [f for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression('"abc:123"=\'c\''))] + features = [ + f + for f in vl.getFeatures( + QgsFeatureRequest().setFilterExpression("\"abc:123\"='c'") + ) + ] self.assertEqual(len(features), 1) - self.assertEqual(features[0].attributes(), [2, 'c', 'd']) - - features = [f for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression('"map"=\'b\''))] + self.assertEqual(features[0].attributes(), [2, "c", "d"]) + + features = [ + f + for f in vl.getFeatures( + QgsFeatureRequest().setFilterExpression("\"map\"='b'") + ) + ] self.assertEqual(len(features), 1) - self.assertEqual(features[0].attributes(), [1, 'a', 'b']) + self.assertEqual(features[0].attributes(), [1, "a", "b"]) - vl2 = QgsVectorLayer("?query=select * from mem_with_nontext_fieldnames where \"abc:123\"='c'", "vl", "virtual") + vl2 = QgsVectorLayer( + "?query=select * from mem_with_nontext_fieldnames where \"abc:123\"='c'", + "vl", + "virtual", + ) self.assertTrue(vl2.isValid()) - self.assertEqual(vl2.fields().at(0).name(), '123') - self.assertEqual(vl2.fields().at(1).name(), 'abc:123') + self.assertEqual(vl2.fields().at(0).name(), "123") + self.assertEqual(vl2.fields().at(1).name(), "abc:123") self.assertEqual(vl2.featureCount(), 1) features = [f for f in vl2.getFeatures()] self.assertEqual(len(features), 1) - self.assertEqual(features[0].attributes(), [2, 'c', 'd']) + self.assertEqual(features[0].attributes(), [2, "c", "d"]) - vl3 = QgsVectorLayer("?query=select * from mem_with_nontext_fieldnames where \"map\"='b'", "vl", "virtual") + vl3 = QgsVectorLayer( + "?query=select * from mem_with_nontext_fieldnames where \"map\"='b'", + "vl", + "virtual", + ) self.assertTrue(vl3.isValid()) - self.assertEqual(vl3.fields().at(0).name(), '123') - self.assertEqual(vl3.fields().at(1).name(), 'abc:123') + self.assertEqual(vl3.fields().at(0).name(), "123") + self.assertEqual(vl3.fields().at(1).name(), "abc:123") self.assertEqual(vl3.featureCount(), 1) features = [f for f in vl3.getFeatures()] self.assertEqual(len(features), 1) - self.assertEqual(features[0].attributes(), [1, 'a', 'b']) + self.assertEqual(features[0].attributes(), [1, "a", "b"]) QgsProject.instance().removeMapLayer(ml) @@ -1119,13 +1558,13 @@ def testFiltersWithoutUid(self): ml.startEditing() for i in range(10): f = QgsFeature(ml.fields()) - f.setGeometry(QgsGeometry.fromWkt(f'POINT({i} 0)')) + f.setGeometry(QgsGeometry.fromWkt(f"POINT({i} 0)")) f.setAttributes([i]) ml.addFeatures([f]) ml.commitChanges() df = QgsVirtualLayerDefinition() - df.setQuery('select * from mem_no_uid') + df.setQuery("select * from mem_no_uid") vl = QgsVectorLayer(df.toString(), "vl", "virtual") self.assertTrue(vl.isValid()) @@ -1140,11 +1579,11 @@ def testFiltersWithoutUid(self): self.assertEqual(fids, [5]) req = QgsFeatureRequest().setFilterFid(5) - a = [(f.id(), f['a']) for f in vl.getFeatures(req)] + a = [(f.id(), f["a"]) for f in vl.getFeatures(req)] self.assertEqual(a, [(5, 5)]) req = QgsFeatureRequest().setFilterFids([5, 6, 8]) - a = [(f.id(), f['a']) for f in vl.getFeatures(req)] + a = [(f.id(), f["a"]) for f in vl.getFeatures(req)] self.assertEqual(a, [(5, 5), (6, 6), (8, 8)]) QgsProject.instance().removeMapLayer(ml) @@ -1160,7 +1599,7 @@ def testUpdatedFields(self): ml.startEditing() f1 = QgsFeature(ml.fields()) - f1.setGeometry(QgsGeometry.fromWkt('POINT(2 3)')) + f1.setGeometry(QgsGeometry.fromWkt("POINT(2 3)")) ml.addFeatures([f1]) ml.commitChanges() @@ -1168,7 +1607,7 @@ def testUpdatedFields(self): self.assertTrue(vl.isValid()) # add one more field - ml.dataProvider().addAttributes([QgsField('newfield', QVariant.Int)]) + ml.dataProvider().addAttributes([QgsField("newfield", QVariant.Int)]) ml.updateFields() self.assertEqual(ml.featureCount(), vl.featureCount()) @@ -1187,7 +1626,9 @@ def test_filter_rect_precise(self): # Check if don't lost precision when filtering on rect (see https://github.com/qgis/QGIS/issues/36054) - pl = QgsVectorLayer(os.path.join(self.testDataDir, "points.shp"), "points", "ogr") + pl = QgsVectorLayer( + os.path.join(self.testDataDir, "points.shp"), "points", "ogr" + ) self.assertTrue(pl.isValid()) QgsProject.instance().addMapLayer(pl) @@ -1198,7 +1639,12 @@ def test_filter_rect_precise(self): # Take an extent where east farthest point is excluded and second farthest east is on the edge # and should be returned - extent = QgsRectangle(-117.23257418909581418, 22.80020703933767834, -85.6521739130433276, 46.87198067632875365) + extent = QgsRectangle( + -117.23257418909581418, + 22.80020703933767834, + -85.6521739130433276, + 46.87198067632875365, + ) r = QgsFeatureRequest(extent) features = [feature for feature in vl.getFeatures(r)] self.assertEqual(len(features), 16) @@ -1212,35 +1658,40 @@ def test_subset_string(self): project = QgsProject.instance() project.clear() - data_layer = QgsVectorLayer('Point?crs=epsg:4326&field=fid:integer&field=value:integer&field=join_pk:integer', 'data', 'memory') - join_layer = QgsVectorLayer('NoGeometry?field=fid:integer&field=value:string', 'join', 'memory') + data_layer = QgsVectorLayer( + "Point?crs=epsg:4326&field=fid:integer&field=value:integer&field=join_pk:integer", + "data", + "memory", + ) + join_layer = QgsVectorLayer( + "NoGeometry?field=fid:integer&field=value:string", "join", "memory" + ) tempdir = QTemporaryDir() - gpkg_path = os.path.join(tempdir.path(), 'test_subset.gpkg') - project_path = os.path.join(tempdir.path(), 'test_subset.qgs') + gpkg_path = os.path.join(tempdir.path(), "test_subset.gpkg") + project_path = os.path.join(tempdir.path(), "test_subset.qgs") self.assertTrue(data_layer.isValid()) self.assertTrue(join_layer.isValid()) self.assertFalse(join_layer.isSpatial()) f = QgsFeature(data_layer.fields()) f.setAttributes([1, 20, 2]) - f.setGeometry(QgsGeometry.fromWkt('point(9 45')) + f.setGeometry(QgsGeometry.fromWkt("point(9 45")) self.assertTrue(data_layer.dataProvider().addFeature(f)) f = QgsFeature(data_layer.fields()) f.setAttributes([2, 10, 1]) - f.setGeometry(QgsGeometry.fromWkt('point(9 45')) + f.setGeometry(QgsGeometry.fromWkt("point(9 45")) self.assertTrue(data_layer.dataProvider().addFeature(f)) options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'GPKG' - options.actionOnExistingFile = QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteFile - options.layerName = 'data' + options.driverName = "GPKG" + options.actionOnExistingFile = ( + QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteFile + ) + options.layerName = "data" _, _ = QgsVectorFileWriter.writeAsVectorFormatV2( - data_layer, - gpkg_path, - data_layer.transformContext(), - options + data_layer, gpkg_path, data_layer.transformContext(), options ) f = QgsFeature(join_layer.fields()) @@ -1249,18 +1700,17 @@ def test_subset_string(self): f.setAttributes([2, "twenty"]) self.assertTrue(join_layer.dataProvider().addFeature(f)) - options.layerName = 'join' - options.actionOnExistingFile = QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteLayer + options.layerName = "join" + options.actionOnExistingFile = ( + QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteLayer + ) _, _ = QgsVectorFileWriter.writeAsVectorFormatV2( - join_layer, - gpkg_path, - join_layer.transformContext(), - options + join_layer, gpkg_path, join_layer.transformContext(), options ) - gpkg_join_layer = QgsVectorLayer(gpkg_path + '|layername=join', 'join', 'ogr') - gpkg_data_layer = QgsVectorLayer(gpkg_path + '|layername=data', 'data', 'ogr') + gpkg_join_layer = QgsVectorLayer(gpkg_path + "|layername=join", "join", "ogr") + gpkg_data_layer = QgsVectorLayer(gpkg_path + "|layername=data", "data", "ogr") self.assertTrue(gpkg_join_layer.isValid()) self.assertTrue(gpkg_data_layer.isValid()) @@ -1280,8 +1730,8 @@ def test_subset_string(self): # Reload project self.assertTrue(project.read(project_path)) - gpkg_data_layer = project.mapLayersByName('data')[0] - gpkg_join_layer = project.mapLayersByName('join')[0] + gpkg_data_layer = project.mapLayersByName("data")[0] + gpkg_join_layer = project.mapLayersByName("join")[0] self.assertEqual(gpkg_data_layer.vectorJoins()[0], joinInfo) @@ -1292,28 +1742,35 @@ def test_subset_string(self): project.addMapLayers([virtual]) self.assertEqual(virtual.featureCount(), 2) - self.assertTrue(virtual.setSubsetString('"join_value" = \'twenty\'')) + self.assertTrue(virtual.setSubsetString("\"join_value\" = 'twenty'")) self.assertEqual(virtual.featureCount(), 1) - self.assertEqual([f.attributes() for f in virtual.getFeatures()], [[1, 20, 2, 'twenty']]) + self.assertEqual( + [f.attributes() for f in virtual.getFeatures()], [[1, 20, 2, "twenty"]] + ) # Store and reload the project self.assertTrue(project.write(project_path)) self.assertTrue(project.read(project_path)) - gpkg_virtual_layer = project.mapLayersByName('virtual_data')[0] + gpkg_virtual_layer = project.mapLayersByName("virtual_data")[0] self.assertEqual(gpkg_virtual_layer.featureCount(), 1) - self.assertEqual(gpkg_virtual_layer.subsetString(), '"join_value" = \'twenty\'') + self.assertEqual(gpkg_virtual_layer.subsetString(), "\"join_value\" = 'twenty'") def test_feature_count_on_error(self): """Test that triggered exception while getting feature count on a badly defined - virtual layer is correctly caught (see https://github.com/qgis/QGIS/issues/34378)""" + virtual layer is correctly caught (see https://github.com/qgis/QGIS/issues/34378) + """ - l1 = QgsVectorLayer(os.path.join(self.testDataDir, "france_parts.shp"), "france", "ogr", - QgsVectorLayer.LayerOptions(False)) + l1 = QgsVectorLayer( + os.path.join(self.testDataDir, "france_parts.shp"), + "france", + "ogr", + QgsVectorLayer.LayerOptions(False), + ) self.assertTrue(l1.isValid()) QgsProject.instance().addMapLayer(l1) df = QgsVirtualLayerDefinition() - df.setQuery('select error') + df.setQuery("select error") vl = QgsVectorLayer(df.toString(), "testq", "virtual") self.assertFalse(vl.isValid()) @@ -1331,30 +1788,34 @@ def test_bool_fields(self): ml.startEditing() f1 = QgsFeature(ml.fields()) - f1.setAttribute('a', 1) - f1.setAttribute('b', True) + f1.setAttribute("a", 1) + f1.setAttribute("b", True) f2 = QgsFeature(ml.fields()) - f2.setAttribute('a', 2) - f2.setAttribute('b', False) + f2.setAttribute("a", 2) + f2.setAttribute("b", False) ml.addFeatures([f1, f2]) ml.commitChanges() - self.assertEqual([(f['a'], f['b']) for f in ml.getFeatures()], [(1, True), (2, False)]) + self.assertEqual( + [(f["a"], f["b"]) for f in ml.getFeatures()], [(1, True), (2, False)] + ) df = QgsVirtualLayerDefinition() - df.setQuery('select * from mem') + df.setQuery("select * from mem") vl = QgsVectorLayer(df.toString(), "testq", "virtual") - self.assertEqual([(f['a'], f['b']) for f in vl.getFeatures()], [(1, True), (2, False)]) + self.assertEqual( + [(f["a"], f["b"]) for f in vl.getFeatures()], [(1, True), (2, False)] + ) df = QgsVirtualLayerDefinition() - df.setQuery('select * from mem where b') + df.setQuery("select * from mem where b") vl = QgsVectorLayer(df.toString(), "testq", "virtual") - self.assertEqual([(f['a'], f['b']) for f in vl.getFeatures()], [(1, True)]) + self.assertEqual([(f["a"], f["b"]) for f in vl.getFeatures()], [(1, True)]) df = QgsVirtualLayerDefinition() - df.setQuery('select * from mem where not b') + df.setQuery("select * from mem where not b") vl = QgsVectorLayer(df.toString(), "testq", "virtual") - self.assertEqual([(f['a'], f['b']) for f in vl.getFeatures()], [(2, False)]) + self.assertEqual([(f["a"], f["b"]) for f in vl.getFeatures()], [(2, False)]) QgsProject.instance().removeMapLayer(ml.id()) @@ -1364,32 +1825,35 @@ def test_int64(self): """ bigint = 2262000000 - ml = QgsVectorLayer('NoGeometry?crs=epsg:4326&field=fldlonglong:long', - 'test_bigint', 'memory') + ml = QgsVectorLayer( + "NoGeometry?crs=epsg:4326&field=fldlonglong:long", "test_bigint", "memory" + ) provider = ml.dataProvider() feat = QgsFeature(ml.fields()) - feat.setAttribute('fldlonglong', bigint) + feat.setAttribute("fldlonglong", bigint) provider.addFeatures([feat]) self.assertTrue(ml.isValid()) QgsProject.instance().addMapLayer(ml) df = QgsVirtualLayerDefinition() - df.setQuery('select * from test_bigint') + df.setQuery("select * from test_bigint") vl = QgsVectorLayer(df.toString(), "testq", "virtual") self.assertEqual(len(vl.fields()), 1) field = vl.fields()[0] self.assertEqual(field.type(), QVariant.LongLong) self.assertTrue(vl.isValid()) feat = next(vl.getFeatures()) - self.assertEqual(feat.attribute('fldlonglong'), bigint) + self.assertEqual(feat.attribute("fldlonglong"), bigint) def test_layer_starting_with_digit(self): """Test issue GH #45347""" project = QgsProject.instance() project.clear() - layer = QgsVectorLayer('Point?crs=epsg:4326&field=fid:integer', '1_layer', 'memory') + layer = QgsVectorLayer( + "Point?crs=epsg:4326&field=fid:integer", "1_layer", "memory" + ) project.addMapLayers([layer]) df = QgsVirtualLayerDefinition() @@ -1402,18 +1866,22 @@ def test_layer_using_joined_fields_from_another_layer(self): project = QgsProject.instance() project.clear() - layer_1 = QgsVectorLayer('Point?crs=epsg:4326&field=fid:integer', 'layer_1', 'memory') - layer_2 = QgsVectorLayer('Point?crs=epsg:4326&field=fid:integer', 'layer_2', 'memory') + layer_1 = QgsVectorLayer( + "Point?crs=epsg:4326&field=fid:integer", "layer_1", "memory" + ) + layer_2 = QgsVectorLayer( + "Point?crs=epsg:4326&field=fid:integer", "layer_2", "memory" + ) project.addMapLayers([layer_1]) # Add a join from 2 to 1 join_info = QgsVectorLayerJoinInfo() join_info.setJoinLayer(layer_1) - join_info.setJoinFieldName('layer_1_fid') - join_info.setTargetFieldName('fid') + join_info.setJoinFieldName("layer_1_fid") + join_info.setTargetFieldName("fid") self.assertTrue(layer_2.addJoin(join_info)) - self.assertIn('layer_1_fid', layer_2.fields().names()) + self.assertIn("layer_1_fid", layer_2.fields().names()) project.addMapLayers([layer_2]) @@ -1426,16 +1894,16 @@ def test_layer_using_joined_fields_from_another_layer(self): tmp = QTemporaryDir() path = tmp.path() - project.write(os.path.join(path, 'test_4683.qgs')) + project.write(os.path.join(path, "test_4683.qgs")) project.clear() - project.read(os.path.join(path, 'test_4683.qgs')) + project.read(os.path.join(path, "test_4683.qgs")) - layer_2 = project.mapLayersByName('layer_2')[0] - vl = project.mapLayersByName('virtual')[0] + layer_2 = project.mapLayersByName("layer_2")[0] + vl = project.mapLayersByName("virtual")[0] self.assertTrue(vl.isValid()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_provider_wfs.py b/tests/src/python/test_provider_wfs.py index 0108fb823216..1fff943a9bbe 100644 --- a/tests/src/python/test_provider_wfs.py +++ b/tests/src/python/test_provider_wfs.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Even Rouault' -__date__ = '2016-03-25' -__copyright__ = 'Copyright 2016, Even Rouault' + +__author__ = "Even Rouault" +__date__ = "2016-03-25" +__copyright__ = "Copyright 2016, Even Rouault" import hashlib import http.server @@ -19,7 +20,7 @@ import threading # Needed on Qt 5 so that the serialization of XML is consistent among all executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" from providertestbase import ProviderTestCase from qgis.core import ( @@ -61,7 +62,7 @@ from osgeo import gdal # Default value is 2 second, which is too short when run under Valgrind -gdal.SetConfigOption('OGR_GMLAS_XERCES_MAX_TIME', '20') +gdal.SetConfigOption("OGR_GMLAS_XERCES_MAX_TIME", "20") TEST_DATA_DIR = unitTestDataPath() @@ -69,14 +70,17 @@ def sanitize(endpoint, x): if len(endpoint + x) > 256: # print('Before: ' + endpoint + x) - x = x.replace('/', '_').encode() + x = x.replace("/", "_").encode() ret = endpoint + hashlib.md5(x).hexdigest() # print('After: ' + ret) return ret - ret = endpoint + x.replace('?', '_').replace('&', '_').replace('<', '_').replace('>', '_').replace('"', - '_').replace("'", - '_').replace( - ' ', '_').replace(':', '_').replace('/', '_').replace('\n', '_') + ret = endpoint + x.replace("?", "_").replace("&", "_").replace("<", "_").replace( + ">", "_" + ).replace('"', "_").replace("'", "_").replace(" ", "_").replace(":", "_").replace( + "/", "_" + ).replace( + "\n", "_" + ) # print('Sanitize: ' + x) return ret @@ -97,7 +101,7 @@ def __exit__(self, type, value, traceback): def logMessage(self, msg, tag, level): if tag == self.tag or not self.tag: - self.log.append(msg.encode('UTF-8')) + self.log.append(msg.encode("UTF-8")) def messages(self): return self.log @@ -114,7 +118,7 @@ def treat_time_as_string(self): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsWFSProvider, cls).setUpClass() + super().setUpClass() QCoreApplication.setOrganizationName("QGIS_Test") QCoreApplication.setOrganizationDomain("TestPyQgsWFSProvider.com") @@ -124,11 +128,17 @@ def setUpClass(cls): # On Windows we must make sure that any backslash in the path is # replaced by a forward slash so that QUrl can process it - cls.basetestpath = tempfile.mkdtemp().replace('\\', '/') - endpoint = cls.basetestpath + '/fake_qgis_http_endpoint' - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), - 'wb') as f: - f.write(b""" + cls.basetestpath = tempfile.mkdtemp().replace("\\", "/") + endpoint = cls.basetestpath + "/fake_qgis_http_endpoint" + with open( + sanitize( + endpoint, + "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0", + ), + "wb", + ) as f: + f.write( + b""" @@ -142,12 +152,18 @@ def setUpClass(cls): -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -173,17 +189,29 @@ def setUpClass(cls): -""") +""" + ) # Create test layer - cls.vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' skipInitialGetFeature='true'", 'test', 'WFS') + cls.vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' skipInitialGetFeature='true'", + "test", + "WFS", + ) assert cls.vl.isValid() cls.source = cls.vl.dataProvider() - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ), + "wb", + ) as f: + f.write( + b""" 12:13:01 -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&RESULTTYPE=hits'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&RESULTTYPE=hits", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) - with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= cnt @@ -278,15 +316,23 @@ def setUpClass(cls): -&RESULTTYPE=hits"""), 'wb') as f: - f.write(b""" +&RESULTTYPE=hits""", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) - with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= cnt @@ -298,8 +344,12 @@ def setUpClass(cls): -"""), 'wb') as f: - f.write(b""" +""", + ), + "wb", + ) as f: + f.write( + b""" 3 -""") +""" + ) - with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= cnt @@ -350,15 +404,23 @@ def setUpClass(cls): -&RESULTTYPE=hits"""), 'wb') as f: - f.write(b""" +&RESULTTYPE=hits""", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) - with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= cnt @@ -370,8 +432,12 @@ def setUpClass(cls): -"""), 'wb') as f: - f.write(b""" +""", + ), + "wb", + ) as f: + f.write( + b""" 3 -""") +""" + ) - with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= name Apple -&RESULTTYPE=hits"""), 'wb') as f: - f.write(b""" +&RESULTTYPE=hits""", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) - with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= name Apple -"""), 'wb') as f: - f.write(b""" +""", + ), + "wb", + ) as f: + f.write( + b""" 2 -""") +""" + ) - with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= name AppleBearOrangePear -&RESULTTYPE=hits"""), 'wb') as f: - f.write(b""" +&RESULTTYPE=hits""", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) - with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= name AppleBearOrangePear -"""), 'wb') as f: - f.write(b""" +""", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) @classmethod def tearDownClass(cls): """Run after all tests""" QgsSettings().clear() shutil.rmtree(cls.basetestpath, True) - cls.vl = None # so as to properly close the provider and remove any temporary file - super(TestPyQgsWFSProvider, cls).tearDownClass() + cls.vl = ( + None # so as to properly close the provider and remove any temporary file + ) + super().tearDownClass() def tearDown(self): """Run after each test""" @@ -486,44 +587,62 @@ def testWkbType(self): pass def providerCompatibleOfSubsetStringWithStableFID(self): - """ Return whether the provider is expected to have stable FID when changing subsetString. - The WFS provider might not always be able to have that guarantee. """ + """Return whether the provider is expected to have stable FID when changing subsetString. + The WFS provider might not always be able to have that guarantee.""" return False def testInconsistentUri(self): """Test a URI with a typename that doesn't match a type of the capabilities""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testInconsistentUri' - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), - 'wb') as f: - f.write(b""" + endpoint = ( + self.__class__.basetestpath + "/fake_qgis_http_endpoint_testInconsistentUri" + ) + with open( + sanitize( + endpoint, + "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) # Could not find typename my:typename in capabilities - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='my:typename'", "test", "WFS" + ) self.assertFalse(vl.isValid()) def testMissingTypename(self): # No typename - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS1.0' - with MessageLogger('WFS') as logger: - vl = QgsVectorLayer("url='http://" + endpoint + "'", 'test', 'WFS') + endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_WFS1.0" + with MessageLogger("WFS") as logger: + vl = QgsVectorLayer("url='http://" + endpoint + "'", "test", "WFS") self.assertFalse(vl.isValid()) self.assertEqual(len(logger.messages()), 1, logger.messages()) - self.assertEqual(logger.messages()[0].decode('UTF-8'), "Missing or empty 'typename' URI parameter") + self.assertEqual( + logger.messages()[0].decode("UTF-8"), + "Missing or empty 'typename' URI parameter", + ) def testWFS10(self): """Test WFS 1.0 read-only""" # We also test attribute fields in upper-case, and a field named GEOMETRY - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS1.0' + endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_WFS1.0" - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -535,11 +654,18 @@ def testWFS10(self): -""") +""" + ) - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -559,22 +685,35 @@ def testWFS10(self): -""") +""" + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) self.assertEqual(len(vl.fields()), 5) self.assertEqual(vl.featureCount(), 0) - reference = QgsGeometry.fromRect(QgsRectangle(400000.0, 5400000.0, 450000.0, 5500000.0)) + reference = QgsGeometry.fromRect( + QgsRectangle(400000.0, 5400000.0, 450000.0, 5500000.0) + ) vl_extent = QgsGeometry.fromRect(vl.extent()) - assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0], - 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}' + assert QgsGeometry.compare( + vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001 + ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}" with open( - sanitize(endpoint, '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631'), - 'wb') as f: - f.write(b""" + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631", + ), + "wb", + ) as f: + f.write( + b""" 2016-04-10T12:34:56.789Z -""") +""" + ) # Also test that on file iterator works - os.environ['QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD'] = '0' + os.environ["QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD"] = "0" - values = [f['INTFIELD'] for f in vl.getFeatures()] + values = [f["INTFIELD"] for f in vl.getFeatures()] self.assertEqual(values, [1]) - del os.environ['QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD'] + del os.environ["QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD"] - values = [f['GEOMETRY'] for f in vl.getFeatures()] + values = [f["GEOMETRY"] for f in vl.getFeatures()] self.assertEqual(values, [2]) - values = [f['longfield'] for f in vl.getFeatures()] + values = [f["longfield"] for f in vl.getFeatures()] self.assertEqual(values, [1234567890123]) - values = [f['stringfield'] for f in vl.getFeatures()] - self.assertEqual(values, ['foo']) - - values = [f['datetimefield'] for f in vl.getFeatures()] - self.assertEqual(values, [QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))]) + values = [f["stringfield"] for f in vl.getFeatures()] + self.assertEqual(values, ["foo"]) + + values = [f["datetimefield"] for f in vl.getFeatures()] + self.assertEqual( + values, + [ + QDateTime( + QDate(2016, 4, 10), + QTime(12, 34, 56, 789), + Qt.TimeSpec(Qt.TimeSpec.UTC), + ) + ], + ) got_f = [f for f in vl.getFeatures()] got = got_f[0].geometry().constGet() @@ -620,7 +769,10 @@ def testWFS10(self): self.assertEqual(vl.featureCount(), 1) - self.assertTrue(vl.dataProvider().capabilities() & QgsVectorDataProvider.Capability.SelectAtId) + self.assertTrue( + vl.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.SelectAtId + ) (ret, _) = vl.dataProvider().addFeatures([QgsFeature()]) self.assertFalse(ret) @@ -632,9 +784,14 @@ def testWFS10(self): vl.dataProvider().reloadData() with open( - sanitize(endpoint, '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631'), - 'wb') as f: - f.write(b""" + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631", + ), + "wb", + ) as f: + f.write( + b""" 30 -""") +""" + ) features = [f for f in vl.getFeatures()] self.assertEqual(features[0].id(), 2) - self.assertEqual(features[0]['INTFIELD'], 20) + self.assertEqual(features[0]["INTFIELD"], 20) self.assertEqual(features[1].id(), 1) - self.assertEqual(features[1]['INTFIELD'], 30) + self.assertEqual(features[1]["INTFIELD"], 30) # Test with restrictToRequestBBOX=1 - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&BBOX=400000,5400000,450000,5500000'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&BBOX=400000,5400000,450000,5500000", + ), + "wb", + ) as f: + f.write( + b""" 100 -""") +""" + ) - uri = "url='http://" + endpoint + "' typename='my:typename' version='1.0.0' restrictToRequestBBOX=1" - vl = QgsVectorLayer( - uri, 'test', - 'WFS') + uri = ( + "url='http://" + + endpoint + + "' typename='my:typename' version='1.0.0' restrictToRequestBBOX=1" + ) + vl = QgsVectorLayer(uri, "test", "WFS") extent = QgsRectangle(400000.0, 5400000.0, 450000.0, 5500000.0) request = QgsFeatureRequest().setFilterRect(extent) - values = [(f.id(), f['INTFIELD']) for f in vl.getFeatures(request)] + values = [(f.id(), f["INTFIELD"]) for f in vl.getFeatures(request)] self.assertEqual(values[0][1], 100) # Issue a request by id on a cached feature request = QgsFeatureRequest(values[0][0]) - values = [(f.id(), f['INTFIELD']) for f in vl.getFeatures(request)] + values = [(f.id(), f["INTFIELD"]) for f in vl.getFeatures(request)] self.assertEqual(values[0][1], 100) # Check behavior with setLimit(1) request = QgsFeatureRequest().setLimit(1) - values = [(f.id(), f['INTFIELD']) for f in vl.getFeatures(request)] + values = [(f.id(), f["INTFIELD"]) for f in vl.getFeatures(request)] self.assertEqual(values[0][1], 100) - metadata = QgsProviderRegistry.instance().providerMetadata('wfs') + metadata = QgsProviderRegistry.instance().providerMetadata("wfs") sublayers = metadata.querySublayers(uri, Qgis.SublayerQueryFlag.FastScan) self.assertEqual(len(sublayers), 0) @@ -711,20 +877,33 @@ def testWFS10(self): self.assertEqual(sublayers[0].wkbType(), vl.wkbType()) # Unexpected foo parameter key - with MessageLogger('WFS') as logger: - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0' foo='bar'", 'test', 'WFS') + with MessageLogger("WFS") as logger: + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' version='1.0.0' foo='bar'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(len(logger.messages()), 1, logger.messages()) - self.assertEqual(logger.messages()[0].decode('UTF-8'), "The following unknown parameter(s) have been found in the URI: foo") + self.assertEqual( + logger.messages()[0].decode("UTF-8"), + "The following unknown parameter(s) have been found in the URI: foo", + ) def testWFS10_outputformat_GML3_2(self): """Test WFS 1.0 with OUTPUTFORMAT=GML3""" # We also test attribute fields in upper-case, and a field named GEOMETRY - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS1.0_gml3' + endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_WFS1.0_gml3" - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -746,11 +925,18 @@ def testWFS10_outputformat_GML3_2(self): -""") +""" + ) - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -764,15 +950,25 @@ def testWFS10_outputformat_GML3_2(self): -""") +""" + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML3'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML3", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) got_f = [f for f in vl.getFeatures()] got = got_f[0].geometry().constGet() self.assertEqual((got.x(), got.y()), (426858.0, 5427937.0)) # Test with explicit OUTPUTFORMAT as parameter - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0' outputformat='GML2'", - 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' version='1.0.0' outputformat='GML2'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML2'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML2", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) got_f = [f for f in vl.getFeatures()] got = got_f[0].geometry().constGet() self.assertEqual((got.x(), got.y()), (1.0, 2.0)) # Test with explicit OUTPUTFORMAT in URL - vl = QgsVectorLayer("url='http://" + endpoint + "?OUTPUTFORMAT=GML2' typename='my:typename' version='1.0.0'", - 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "?OUTPUTFORMAT=GML2' typename='my:typename' version='1.0.0'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML2'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML2", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) got_f = [f for f in vl.getFeatures()] got = got_f[0].geometry().constGet() @@ -848,10 +1067,17 @@ def testWFS10_outputformat_GML3_2(self): def testWFS10_latlongboundingbox_in_WGS84(self): """Test WFS 1.0 with non conformatn LatLongBoundingBox""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS1.0_latlongboundingbox_in_WGS84' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_WFS1.0_latlongboundingbox_in_WGS84" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -864,11 +1090,18 @@ def testWFS10_latlongboundingbox_in_WGS84(self): -""") +""" + ) - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -882,27 +1115,45 @@ def testWFS10_latlongboundingbox_in_WGS84(self): -""") +""" + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) reference = QgsGeometry.fromRect( - QgsRectangle(399999.9999999680439942, 5399338.9090830031782389, 449999.9999999987776391, - 5500658.0448500607162714)) + QgsRectangle( + 399999.9999999680439942, + 5399338.9090830031782389, + 449999.9999999987776391, + 5500658.0448500607162714, + ) + ) vl_extent = QgsGeometry.fromRect(vl.extent()) - assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0], - 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}' + assert QgsGeometry.compare( + vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001 + ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}" def testWFST10(self): """Test WFS-T 1.0 (read-write)""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_T_1.0' + endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_WFS_T_1.0" - transaction_endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_T_1.0_transaction' + transaction_endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_WFS_T_1.0_transaction" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f: - f.write(""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0"), + "wb", + ) as f: + f.write( + """ @@ -948,11 +1199,22 @@ def testWFST10(self): -""".format(transaction_endpoint=transaction_endpoint).encode('UTF-8')) +""".format( + transaction_endpoint=transaction_endpoint + ).encode( + "UTF-8" + ) + ) - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -970,18 +1232,25 @@ def testWFST10(self): -""") +""" + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) - self.assertEqual(vl.dataProvider().capabilities(), - QgsVectorDataProvider.Capability.AddFeatures - | QgsVectorDataProvider.Capability.ChangeAttributeValues - | QgsVectorDataProvider.Capability.ChangeGeometries - | QgsVectorDataProvider.Capability.DeleteFeatures - | QgsVectorDataProvider.Capability.SelectAtId - | QgsVectorDataProvider.Capability.ReloadData) + self.assertEqual( + vl.dataProvider().capabilities(), + QgsVectorDataProvider.Capability.AddFeatures + | QgsVectorDataProvider.Capability.ChangeAttributeValues + | QgsVectorDataProvider.Capability.ChangeGeometries + | QgsVectorDataProvider.Capability.DeleteFeatures + | QgsVectorDataProvider.Capability.SelectAtId + | QgsVectorDataProvider.Capability.ReloadData, + ) (ret, _) = vl.dataProvider().addFeatures([QgsFeature()]) self.assertFalse(ret) @@ -992,7 +1261,11 @@ def testWFST10(self): self.assertEqual(vl.featureCount(), 0) - self.assertFalse(vl.dataProvider().changeGeometryValues({0: QgsGeometry.fromWkt('Point (3 50)')})) + self.assertFalse( + vl.dataProvider().changeGeometryValues( + {0: QgsGeometry.fromWkt("Point (3 50)")} + ) + ) self.assertFalse(vl.dataProvider().changeAttributeValues({0: {0: 0}})) @@ -1010,25 +1283,44 @@ def testWFST10(self): """ - if int(QT_VERSION_STR.split('.')[0]) >= 6: + if int(QT_VERSION_STR.split(".")[0]) >= 6: attrs = 'xmlns="http://www.opengis.net/wfs" service="WFS" version="1.0.0" xmlns:gml="http://www.opengis.net/gml" xmlns:my="http://my" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://my http://fake_qgis_http_endpoint?REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename"' else: attrs = 'xmlns="http://www.opengis.net/wfs" service="WFS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://my http://fake_qgis_http_endpoint?REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename" xmlns:my="http://my" xmlns:gml="http://www.opengis.net/gml" version="1.0.0"' - with open(sanitize(transaction_endpoint, - f'?SERVICE=WFS&POSTDATA=11234567890123foo2016-04-10T12:34:56.789Z2,49'), - 'wb') as f: - f.write(response.encode('UTF-8')) + with open( + sanitize( + transaction_endpoint, + f'?SERVICE=WFS&POSTDATA=11234567890123foo2016-04-10T12:34:56.789Z2,49', + ), + "wb", + ) as f: + f.write(response.encode("UTF-8")) # Qt 4 order ?? - with open(sanitize(transaction_endpoint, - '?SERVICE=WFS&POSTDATA=11234567890123foo2016-04-10T12:34:56.789Z2,49'), - 'wb') as f: - f.write(response.encode('UTF-8')) + with open( + sanitize( + transaction_endpoint, + '?SERVICE=WFS&POSTDATA=11234567890123foo2016-04-10T12:34:56.789Z2,49', + ), + "wb", + ) as f: + f.write(response.encode("UTF-8")) f = QgsFeature() - f.setAttributes([1, 1234567890123, 'foo', QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))]) - f.setGeometry(QgsGeometry.fromWkt('Point (2 49)')) + f.setAttributes( + [ + 1, + 1234567890123, + "foo", + QDateTime( + QDate(2016, 4, 10), + QTime(12, 34, 56, 789), + Qt.TimeSpec(Qt.TimeSpec.UTC), + ), + ] + ) + f.setGeometry(QgsGeometry.fromWkt("Point (2 49)")) # def logMessage(msg, tag, level): # print('--------################----------------') @@ -1043,17 +1335,26 @@ def testWFST10(self): self.assertEqual(vl.featureCount(), 1) - values = [f['intfield'] for f in vl.getFeatures()] + values = [f["intfield"] for f in vl.getFeatures()] self.assertEqual(values, [1]) - values = [f['longfield'] for f in vl.getFeatures()] + values = [f["longfield"] for f in vl.getFeatures()] self.assertEqual(values, [1234567890123]) - values = [f['stringfield'] for f in vl.getFeatures()] - self.assertEqual(values, ['foo']) - - values = [f['datetimefield'] for f in vl.getFeatures()] - self.assertEqual(values, [QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))]) + values = [f["stringfield"] for f in vl.getFeatures()] + self.assertEqual(values, ["foo"]) + + values = [f["datetimefield"] for f in vl.getFeatures()] + self.assertEqual( + values, + [ + QDateTime( + QDate(2016, 4, 10), + QTime(12, 34, 56, 789), + Qt.TimeSpec(Qt.TimeSpec.UTC), + ) + ], + ) got_f = [f for f in vl.getFeatures()] got = got_f[0].geometry().constGet() @@ -1070,34 +1371,55 @@ def testWFST10(self): """ - with open(sanitize(transaction_endpoint, - f'?SERVICE=WFS&POSTDATA=my:geometryProperty3,50'), - 'wb') as f: - f.write(content.encode('UTF-8')) + with open( + sanitize( + transaction_endpoint, + f'?SERVICE=WFS&POSTDATA=my:geometryProperty3,50', + ), + "wb", + ) as f: + f.write(content.encode("UTF-8")) # Qt 4 order ?? - with open(sanitize(transaction_endpoint, - '?SERVICE=WFS&POSTDATA=my:geometryProperty3,50'), - 'wb') as f: - f.write(content.encode('UTF-8')) - - self.assertTrue(vl.dataProvider().changeGeometryValues({1: QgsGeometry.fromWkt('Point (3 50)')})) + with open( + sanitize( + transaction_endpoint, + '?SERVICE=WFS&POSTDATA=my:geometryProperty3,50', + ), + "wb", + ) as f: + f.write(content.encode("UTF-8")) + + self.assertTrue( + vl.dataProvider().changeGeometryValues( + {1: QgsGeometry.fromWkt("Point (3 50)")} + ) + ) got_f = [f for f in vl.getFeatures()] got = got_f[0].geometry().constGet() self.assertEqual((got.x(), got.y()), (3.0, 50.0)) - values = [f['intfield'] for f in vl.getFeatures()] + values = [f["intfield"] for f in vl.getFeatures()] self.assertEqual(values, [1]) - values = [f['longfield'] for f in vl.getFeatures()] + values = [f["longfield"] for f in vl.getFeatures()] self.assertEqual(values, [1234567890123]) - values = [f['stringfield'] for f in vl.getFeatures()] - self.assertEqual(values, ['foo']) - - values = [f['datetimefield'] for f in vl.getFeatures()] - self.assertEqual(values, [QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))]) + values = [f["stringfield"] for f in vl.getFeatures()] + self.assertEqual(values, ["foo"]) + + values = [f["datetimefield"] for f in vl.getFeatures()] + self.assertEqual( + values, + [ + QDateTime( + QDate(2016, 4, 10), + QTime(12, 34, 56, 789), + Qt.TimeSpec(Qt.TimeSpec.UTC), + ) + ], + ) # Test changeAttributeValues content = """ @@ -1110,31 +1432,62 @@ def testWFST10(self): """ - with open(sanitize(transaction_endpoint, - f'?SERVICE=WFS&POSTDATA=my:intfield2my:longfield3my:stringfieldbarmy:datetimefield2015-04-10T12:34:56.789Z'), - 'wb') as f: - f.write(response.encode('UTF-8')) + with open( + sanitize( + transaction_endpoint, + f'?SERVICE=WFS&POSTDATA=my:intfield2my:longfield3my:stringfieldbarmy:datetimefield2015-04-10T12:34:56.789Z', + ), + "wb", + ) as f: + f.write(response.encode("UTF-8")) # Qt 4 order ?? - with open(sanitize(transaction_endpoint, - '?SERVICE=WFS&POSTDATA=my:intfield2my:longfield3my:stringfieldbarmy:datetimefield2015-04-10T12:34:56.789Z'), - 'wb') as f: - f.write(content.encode('UTF-8')) - - self.assertTrue(vl.dataProvider().changeAttributeValues( - {1: {0: 2, 1: 3, 2: "bar", 3: QDateTime(QDate(2015, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))}})) - - values = [f['intfield'] for f in vl.getFeatures()] + with open( + sanitize( + transaction_endpoint, + '?SERVICE=WFS&POSTDATA=my:intfield2my:longfield3my:stringfieldbarmy:datetimefield2015-04-10T12:34:56.789Z', + ), + "wb", + ) as f: + f.write(content.encode("UTF-8")) + + self.assertTrue( + vl.dataProvider().changeAttributeValues( + { + 1: { + 0: 2, + 1: 3, + 2: "bar", + 3: QDateTime( + QDate(2015, 4, 10), + QTime(12, 34, 56, 789), + Qt.TimeSpec(Qt.TimeSpec.UTC), + ), + } + } + ) + ) + + values = [f["intfield"] for f in vl.getFeatures()] self.assertEqual(values, [2]) - values = [f['longfield'] for f in vl.getFeatures()] + values = [f["longfield"] for f in vl.getFeatures()] self.assertEqual(values, [3]) - values = [f['stringfield'] for f in vl.getFeatures()] - self.assertEqual(values, ['bar']) - - values = [f['datetimefield'] for f in vl.getFeatures()] - self.assertEqual(values, [QDateTime(QDate(2015, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))]) + values = [f["stringfield"] for f in vl.getFeatures()] + self.assertEqual(values, ["bar"]) + + values = [f["datetimefield"] for f in vl.getFeatures()] + self.assertEqual( + values, + [ + QDateTime( + QDate(2015, 4, 10), + QTime(12, 34, 56, 789), + Qt.TimeSpec(Qt.TimeSpec.UTC), + ) + ], + ) got_f = [f for f in vl.getFeatures()] got = got_f[0].geometry().constGet() @@ -1151,16 +1504,24 @@ def testWFST10(self): """ - with open(sanitize(transaction_endpoint, - f'?SERVICE=WFS&POSTDATA='), - 'wb') as f: - f.write(response.encode('UTF-8')) + with open( + sanitize( + transaction_endpoint, + f'?SERVICE=WFS&POSTDATA=', + ), + "wb", + ) as f: + f.write(response.encode("UTF-8")) # Qt 4 order ?? - with open(sanitize(transaction_endpoint, - '?SERVICE=WFS&POSTDATA='), - 'wb') as f: - f.write(content.encode('UTF-8')) + with open( + sanitize( + transaction_endpoint, + '?SERVICE=WFS&POSTDATA=', + ), + "wb", + ) as f: + f.write(content.encode("UTF-8")) self.assertTrue(vl.dataProvider().deleteFeatures([1])) @@ -1169,11 +1530,19 @@ def testWFST10(self): def testWFS20Paging(self): """Test WFS 2.0 paging""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_2.0_paging' + endpoint = ( + self.__class__.basetestpath + "/fake_qgis_http_endpoint_WFS_2.0_paging" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0", + ), + "wb", + ) as f: + f.write( + b""" @@ -1199,12 +1568,18 @@ def testWFS20Paging(self): -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -1219,12 +1594,18 @@ def testWFS20Paging(self): -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ), + "wb", + ) as f: + f.write( + b""" 1 -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ), + "wb", + ) as f: + f.write( + b""" 1 -""") +""" + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='my:typename'", "test", "WFS" + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=1&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=1&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ), + "wb", + ) as f: + f.write( + b""" 2 -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=2&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=2&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) - values = [f['id'] for f in vl.getFeatures()] + values = [f["id"] for f in vl.getFeatures()] self.assertEqual(values, [1, 2]) # Suppress GetFeature responses to demonstrate that the cache is used - os.unlink(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326')) - os.unlink(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=1&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326')) - os.unlink(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=2&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326')) - - values = [f['id'] for f in vl.getFeatures()] + os.unlink( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ) + ) + os.unlink( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=1&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ) + ) + os.unlink( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=2&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ) + ) + + values = [f["id"] for f in vl.getFeatures()] self.assertEqual(values, [1, 2]) # No need for hits since the download went to its end @@ -1309,25 +1723,40 @@ def testWFS20Paging(self): vl.dataProvider().reloadData() # Hits working - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&RESULTTYPE=hits'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&RESULTTYPE=hits", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) self.assertEqual(vl.featureCount(), 2) def testWFS20PagingPageSizeOverride(self): """Test WFS 2.0 paging""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_2.0_paging_override' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_WFS_2.0_paging_override" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0", + ), + "wb", + ) as f: + f.write( + b""" @@ -1353,12 +1782,18 @@ def testWFS20PagingPageSizeOverride(self): -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -1373,18 +1808,29 @@ def testWFS20PagingPageSizeOverride(self): -""") +""" + ) # user pageSize < user maxNumFeatures < server pagesize - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' maxNumFeatures='3' pageSize='2' skipInitialGetFeature='true'", - 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' maxNumFeatures='3' pageSize='2' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=2&SRSNAME=urn:ogc:def:crs:EPSG::4326'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=2&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ), + "wb", + ) as f: + f.write( + b""" 2 -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=2&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=2&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ), + "wb", + ) as f: + f.write( + b""" 3 -""") +""" + ) - values = [f['id'] for f in vl.getFeatures()] + values = [f["id"] for f in vl.getFeatures()] self.assertEqual(values, [1, 2, 3]) - os.unlink(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=2&SRSNAME=urn:ogc:def:crs:EPSG::4326')) - os.unlink(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=2&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326')) + os.unlink( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=2&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ) + ) + os.unlink( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=2&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ) + ) # user maxNumFeatures < user pageSize < server pagesize - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' maxNumFeatures='1' pageSize='2' skipInitialGetFeature='true'", - 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' maxNumFeatures='1' pageSize='2' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ), + "wb", + ) as f: + f.write( + b""" 1 -""") +""" + ) - values = [f['id'] for f in vl.getFeatures()] + values = [f["id"] for f in vl.getFeatures()] self.assertEqual(values, [1]) - os.unlink(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326')) + os.unlink( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ) + ) # user user pageSize > server pagesize - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' pageSize='100' skipInitialGetFeature='true'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' pageSize='100' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=10&SRSNAME=urn:ogc:def:crs:EPSG::4326'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=10&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ), + "wb", + ) as f: + f.write( + b""" 1 -""") +""" + ) - values = [f['id'] for f in vl.getFeatures()] + values = [f["id"] for f in vl.getFeatures()] self.assertEqual(values, [1]) - os.unlink(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=10&SRSNAME=urn:ogc:def:crs:EPSG::4326')) + os.unlink( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=10&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ) + ) vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' pagingEnabled='false' maxNumFeatures='3' skipInitialGetFeature='true'", 'test', - 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' pagingEnabled='false' maxNumFeatures='3' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=3&SRSNAME=urn:ogc:def:crs:EPSG::4326'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=3&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ), + "wb", + ) as f: + f.write( + b""" 2000 -""") +""" + ) - values = [f['id'] for f in vl.getFeatures()] + values = [f["id"] for f in vl.getFeatures()] self.assertEqual(values, [1000, 2000]) def testWFSGetOnlyFeaturesInViewExtent(self): - """Test 'get only features in view extent' """ + """Test 'get only features in view extent'""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_only_features_in_view_extent' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_only_features_in_view_extent" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0", + ), + "wb", + ) as f: + f.write( + b""" @@ -1541,11 +2052,18 @@ def testWFSGetOnlyFeaturesInViewExtent(self): -""") +""" + ) - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -1561,19 +2079,28 @@ def testWFSGetOnlyFeaturesInViewExtent(self): -""") +""" + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' restrictToRequestBBOX=1 skipInitialGetFeature='true'", 'test', - 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' restrictToRequestBBOX=1 skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) return - last_url = sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=2&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=60,-70,80,-60,urn:ogc:def:crs:EPSG::4326') - with open(last_url, 'wb') as f: - f.write(b""" + last_url = sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=2&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=60,-70,80,-60,urn:ogc:def:crs:EPSG::4326", + ) + with open(last_url, "wb") as f: + f.write( + b""" 2 -""") +""" + ) extent = QgsRectangle(-70, 60, -60, 80) request = QgsFeatureRequest().setFilterRect(extent) - values = [f['ogc_fid'] for f in vl.getFeatures(request)] + values = [f["ogc_fid"] for f in vl.getFeatures(request)] self.assertEqual(values, [2]) # To show that if we zoom-in, we won't issue a new request - with open(last_url, 'wb') as f: - f.write(b""" + with open(last_url, "wb") as f: + f.write( + b""" 200 -""") +""" + ) extent = QgsRectangle(-66, 62, -62, 78) request = QgsFeatureRequest().setFilterRect(extent) - values = [f['ogc_fid'] for f in vl.getFeatures(request)] + values = [f["ogc_fid"] for f in vl.getFeatures(request)] self.assertEqual(values, [2]) # Move to a neighbouring area, and reach the download limit - last_url = sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=2&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=65,-70,90,-60,urn:ogc:def:crs:EPSG::4326') - with open(last_url, 'wb') as f: - f.write(b""" + last_url = sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=2&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=65,-70,90,-60,urn:ogc:def:crs:EPSG::4326", + ) + with open(last_url, "wb") as f: + f.write( + b""" 3 -""") +""" + ) extent = QgsRectangle(-70, 65, -60, 90) request = QgsFeatureRequest().setFilterRect(extent) - values = [f['ogc_fid'] for f in vl.getFeatures(request)] + values = [f["ogc_fid"] for f in vl.getFeatures(request)] self.assertEqual(values, [2, 3]) # Zoom-in again, and bring more features - last_url = sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=2&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=66,-69,89,-61,urn:ogc:def:crs:EPSG::4326') - with open(last_url, 'wb') as f: - f.write(b""" + last_url = sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=2&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=66,-69,89,-61,urn:ogc:def:crs:EPSG::4326", + ) + with open(last_url, "wb") as f: + f.write( + b""" 4 -""") +""" + ) extent = QgsRectangle(-69, 66, -61, 89) request = QgsFeatureRequest().setFilterRect(extent) - values = [f['ogc_fid'] for f in vl.getFeatures(request)] + values = [f["ogc_fid"] for f in vl.getFeatures(request)] self.assertEqual(values, [2, 3, 4]) # Test RESULTTYPE=hits - last_url = sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&RESULTTYPE=hits') - with open(last_url, 'wb') as f: - f.write(b""" + last_url = sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&RESULTTYPE=hits", + ) + with open(last_url, "wb") as f: + f.write( + b""" """) + numberOfFeatures="10" timeStamp="2016-03-25T14:51:48.998Z"/>""" + ) self.assertEqual(vl.featureCount(), 10) # Combine BBOX and FILTER - last_url = sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=2&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= + last_url = sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=2&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= geometryProperty @@ -1689,9 +2233,11 @@ def testWFSGetOnlyFeaturesInViewExtent(self): -""") - with open(last_url, 'wb') as f: - f.write(b""" +""", + ) + with open(last_url, "wb") as f: + f.write( + b""" 101 -""") +""" + ) - vl.dataProvider().setSubsetString('ogc_fid = 101') + vl.dataProvider().setSubsetString("ogc_fid = 101") extent = QgsRectangle(-69, 66, -61, 89) request = QgsFeatureRequest().setFilterRect(extent) - values = [f['ogc_fid'] for f in vl.getFeatures(request)] + values = [f["ogc_fid"] for f in vl.getFeatures(request)] self.assertEqual(values, [101]) # Check behavior with setLimit(1) - with open(sanitize(endpoint, - "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::4326"), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ), + "wb", + ) as f: + f.write( + b""" 12345 -""") - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' restrictToRequestBBOX=1 skipInitialGetFeature='true'", 'test', - 'WFS') +""" + ) + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' restrictToRequestBBOX=1 skipInitialGetFeature='true'", + "test", + "WFS", + ) request = QgsFeatureRequest().setLimit(1) - values = [f['ogc_fid'] for f in vl.getFeatures(request)] + values = [f["ogc_fid"] for f in vl.getFeatures(request)] self.assertEqual(values, [12345]) # Check that the layer extent is not built from this single feature reference = QgsGeometry.fromRect(QgsRectangle(-80, 60, -50, 80)) vl_extent = QgsGeometry.fromRect(vl.extent()) - assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0], - 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}' + assert QgsGeometry.compare( + vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001 + ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}" def testWFSGetOnlyFeaturesInViewExtentZoomOut(self): - """Test zoom out outside of declare extent in metadata (#20742) """ + """Test zoom out outside of declare extent in metadata (#20742)""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_20742' + endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_20742" - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0", + ), + "wb", + ) as f: + f.write( + b""" @@ -1767,11 +2332,18 @@ def testWFSGetOnlyFeaturesInViewExtentZoomOut(self): -""") +""" + ) - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -1786,10 +2358,13 @@ def testWFSGetOnlyFeaturesInViewExtentZoomOut(self): -""") +""" + ) - last_url = sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=60,-80,80,-50,urn:ogc:def:crs:EPSG::4326') + last_url = sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=60,-80,80,-50,urn:ogc:def:crs:EPSG::4326", + ) getfeature_response = b""" """ - with open(last_url, 'wb') as f: + with open(last_url, "wb") as f: f.write(getfeature_response) - last_url = sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=50,-90,90,-40,urn:ogc:def:crs:EPSG::4326') - with open(last_url, 'wb') as f: + last_url = sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=50,-90,90,-40,urn:ogc:def:crs:EPSG::4326", + ) + with open(last_url, "wb") as f: f.write(getfeature_response) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' restrictToRequestBBOX=1 skipInitialGetFeature='true'", 'test', - 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' restrictToRequestBBOX=1 skipInitialGetFeature='true'", + "test", + "WFS", + ) # First request with declared extent in metadata extent = QgsRectangle(-80, 60, -50, 80) request = QgsFeatureRequest().setFilterRect(extent) self.assertEqual(len([f for f in vl.getFeatures(request)]), 2) reference = QgsGeometry.fromRect(QgsRectangle(-65, 70, -64, 71)) vl_extent = QgsGeometry.fromRect(vl.extent()) - assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0], - 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}' + assert QgsGeometry.compare( + vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001 + ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}" # Second request: zoomed out extent = QgsRectangle(-90, 50, -40, 90) request = QgsFeatureRequest().setFilterRect(extent) self.assertEqual(len([f for f in vl.getFeatures(request)]), 2) vl_extent = QgsGeometry.fromRect(vl.extent()) - assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0], - 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}' + assert QgsGeometry.compare( + vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001 + ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}" def testWFS20TruncatedResponse(self): """Test WFS 2.0 truncatedResponse""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_2.0_truncated_response' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_WFS_2.0_truncated_response" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0", + ), + "wb", + ) as f: + f.write( + b""" @@ -1848,12 +2441,18 @@ def testWFS20TruncatedResponse(self): urn:ogc:def:crs:EPSG::4326 -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -1867,12 +2466,18 @@ def testWFS20TruncatedResponse(self): -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' skipInitialGetFeature='true'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) # Check that we get a log message - with MessageLogger('WFS') as logger: + with MessageLogger("WFS") as logger: [f for f in vl.getFeatures()] # Let signals to be notified to QgsVectorDataProvider @@ -1896,15 +2508,24 @@ def testWFS20TruncatedResponse(self): loop.processEvents() self.assertEqual(len(logger.messages()), 1, logger.messages()) - self.assertGreaterEqual(logger.messages()[0].decode('UTF-8').find('The download limit has been reached'), 0) + self.assertGreaterEqual( + logger.messages()[0] + .decode("UTF-8") + .find("The download limit has been reached"), + 0, + ) def testRetryLogic(self): - """Test retry logic """ + """Test retry logic""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_retry' + endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_retry" - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -1914,11 +2535,18 @@ def testRetryLogic(self): EPSG:4326 -""") +""" + ) - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -1932,15 +2560,20 @@ def testRetryLogic(self): -""") +""" + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.NoGeometry) self.assertEqual(len(vl.fields()), 1) # Failed download: test that error is propagated to the data provider, so as to get application notification - [f['INTFIELD'] for f in vl.getFeatures()] + [f["INTFIELD"] for f in vl.getFeatures()] # Let signals to be notified to QgsVectorDataProvider loop = QEventLoop() @@ -1953,16 +2586,25 @@ def testRetryLogic(self): vl.reload() # First retry: Empty response - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:4326&RETRY=1'), - 'wb') as f: - f.write(b'') + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:4326&RETRY=1", + ), + "wb", + ) as f: + f.write(b"") # Second retry: Incomplete response - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:4326&RETRY=2'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:4326&RETRY=2", + ), + "wb", + ) as f: + f.write( + b""" - 2""") + 2""" + ) # Third retry: Valid response - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:4326&RETRY=3'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:4326&RETRY=3", + ), + "wb", + ) as f: + f.write( + b""" 2 -""") +""" + ) - values = [f['INTFIELD'] for f in vl.getFeatures()] + values = [f["INTFIELD"] for f in vl.getFeatures()] self.assertEqual(values, [1, 2]) def testDetachedFeatureSource(self): - """Test using a feature source after the provider has been destroyed """ + """Test using a feature source after the provider has been destroyed""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_detached_source' + endpoint = ( + self.__class__.basetestpath + "/fake_qgis_http_endpoint_detached_source" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -2016,11 +2671,18 @@ def testDetachedFeatureSource(self): EPSG:4326 -""") +""" + ) - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -2034,9 +2696,14 @@ def testDetachedFeatureSource(self): -""") +""" + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.NoGeometry) self.assertEqual(len(vl.fields()), 1) @@ -2046,9 +2713,14 @@ def testDetachedFeatureSource(self): vl = None with open( - sanitize(endpoint, '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:4326'), - 'wb') as f: - f.write(b""" + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:4326", + ), + "wb", + ) as f: + f.write( + b""" 1 -""") +""" + ) - values = [f['INTFIELD'] for f in source.getFeatures(QgsFeatureRequest())] + values = [f["INTFIELD"] for f in source.getFeatures(QgsFeatureRequest())] self.assertEqual(values, [1]) def testLayerConstructionNoPrefix(self): @@ -2069,12 +2742,14 @@ def testLayerConstructionNoPrefix(self): without the prefix, when it's safe to do so. """ - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_no_prefix' + endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_no_prefix" - with open(sanitize(endpoint, - '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), - 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -2108,7 +2783,8 @@ def testLayerConstructionNoPrefix(self): -""") +""" + ) schema = """ @@ -2126,10 +2802,14 @@ def testLayerConstructionNoPrefix(self): """ - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:uniquename&TYPENAME=my:uniquename'), - 'wb') as f: - f.write(schema.encode('UTF-8')) + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:uniquename&TYPENAME=my:uniquename", + ), + "wb", + ) as f: + f.write(schema.encode("UTF-8")) schema = """ @@ -2147,45 +2827,71 @@ def testLayerConstructionNoPrefix(self): """ - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:ambiguousname&TYPENAME=my:ambiguousname'), - 'wb') as f: - f.write(schema.encode('UTF-8')) + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:ambiguousname&TYPENAME=my:ambiguousname", + ), + "wb", + ) as f: + f.write(schema.encode("UTF-8")) # Explicitly stating namespace for unique layer name vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:uniquename' version='2.0.0' skipInitialGetFeature='true'", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:uniquename' version='2.0.0' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) # excluding namespace for unique layer name vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='uniquename' version='2.0.0' skipInitialGetFeature='true'", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='uniquename' version='2.0.0' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) # Explicitly stating namespace for otherwise ambiguous name vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:ambiguousname' version='2.0.0' skipInitialGetFeature='true'", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:ambiguousname' version='2.0.0' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) # excluding namespace for ambiguous name -- is not permitted vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='ambiguousname' version='2.0.0' skipInitialGetFeature='true'", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='ambiguousname' version='2.0.0' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertFalse(vl.isValid()) def testJoins(self): - """Test SELECT with joins """ + """Test SELECT with joins""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_detached_source' + endpoint = ( + self.__class__.basetestpath + "/fake_qgis_http_endpoint_detached_source" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -2239,7 +2945,8 @@ def testJoins(self): -""") +""" + ) schema = """ @@ -2269,12 +2976,19 @@ def testJoins(self): """ - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename,my:othertypename&TYPENAME=my:typename,my:othertypename'), - 'wb') as f: - f.write(schema.encode('UTF-8')) + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename,my:othertypename&TYPENAME=my:typename,my:othertypename", + ), + "wb", + ) as f: + f.write(schema.encode("UTF-8")) - with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename,my:othertypename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename,my:othertypename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= my:typename/id @@ -2286,8 +3000,12 @@ def testJoins(self): -&SORTBY=id DESC"""), 'wb') as f: - f.write(b""" +&SORTBY=id DESC""", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) # * syntax vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM \"my:typename\" JOIN \"my:othertypename\" o ON \"my:typename\".id = o.main_id WHERE \"my:typename\".id > 0 ORDER BY \"my:typename\".id DESC", - 'test', 'WFS') + "url='http://" + + endpoint + + '\' typename=\'my:typename\' version=\'2.0.0\' skipInitialGetFeature=\'true\' sql=SELECT * FROM "my:typename" JOIN "my:othertypename" o ON "my:typename".id = o.main_id WHERE "my:typename".id > 0 ORDER BY "my:typename".id DESC', + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) fields = vl.fields() self.assertEqual(len(fields), 3, fields) - self.assertEqual(fields[0].name(), 'typename.id') - self.assertEqual(fields[1].name(), 'o.main_id') - self.assertEqual(fields[2].name(), 'o.second_id') - - values = [(f['typename.id'], f['o.main_id'], f['o.second_id']) for f in vl.getFeatures()] + self.assertEqual(fields[0].name(), "typename.id") + self.assertEqual(fields[1].name(), "o.main_id") + self.assertEqual(fields[2].name(), "o.second_id") + + values = [ + (f["typename.id"], f["o.main_id"], f["o.second_id"]) + for f in vl.getFeatures() + ] self.assertEqual(values, [(1, 1, 2)]) # * syntax with unprefixed typenames vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' sql=SELECT * FROM typename JOIN othertypename o ON typename.id = o.main_id WHERE typename.id > 0 ORDER BY typename.id DESC", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' sql=SELECT * FROM typename JOIN othertypename o ON typename.id = o.main_id WHERE typename.id > 0 ORDER BY typename.id DESC", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) fields = vl.fields() self.assertEqual(len(fields), 3, fields) - self.assertEqual(fields[0].name(), 'typename.id') - self.assertEqual(fields[1].name(), 'o.main_id') - self.assertEqual(fields[2].name(), 'o.second_id') - - values = [(f['typename.id'], f['o.main_id'], f['o.second_id']) for f in vl.getFeatures()] + self.assertEqual(fields[0].name(), "typename.id") + self.assertEqual(fields[1].name(), "o.main_id") + self.assertEqual(fields[2].name(), "o.second_id") + + values = [ + (f["typename.id"], f["o.main_id"], f["o.second_id"]) + for f in vl.getFeatures() + ] self.assertEqual(values, [(1, 1, 2)]) # main table not appearing in first - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:othertypename,my:typename&TYPENAME=my:othertypename,my:typename'), - 'wb') as f: - f.write(schema.encode('UTF-8')) + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:othertypename,my:typename&TYPENAME=my:othertypename,my:typename", + ), + "wb", + ) as f: + f.write(schema.encode("UTF-8")) vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM othertypename o, typename WHERE typename.id = o.main_id AND typename.id > 0 ORDER BY typename.id DESC", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM othertypename o, typename WHERE typename.id = o.main_id AND typename.id > 0 ORDER BY typename.id DESC", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) fields = vl.fields() self.assertEqual(len(fields), 3, fields) - self.assertEqual(fields[0].name(), 'o.main_id') - self.assertEqual(fields[1].name(), 'o.second_id') - self.assertEqual(fields[2].name(), 'typename.id') + self.assertEqual(fields[0].name(), "o.main_id") + self.assertEqual(fields[1].name(), "o.second_id") + self.assertEqual(fields[2].name(), "typename.id") # main table not appearing in first, not in FROM but in JOIN vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM othertypename o JOIN typename ON typename.id = o.main_id WHERE typename.id > 0 ORDER BY typename.id DESC", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM othertypename o JOIN typename ON typename.id = o.main_id WHERE typename.id > 0 ORDER BY typename.id DESC", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) fields = vl.fields() self.assertEqual(len(fields), 3, fields) - self.assertEqual(fields[0].name(), 'o.main_id') - self.assertEqual(fields[1].name(), 'o.second_id') - self.assertEqual(fields[2].name(), 'typename.id') + self.assertEqual(fields[0].name(), "o.main_id") + self.assertEqual(fields[1].name(), "o.second_id") + self.assertEqual(fields[2].name(), "typename.id") # table_alias.*, field alias vl.setSubsetString( - "SELECT o.*, m.id AS m_id FROM \"my:typename\" m JOIN \"my:othertypename\" o ON m.id = o.main_id WHERE m.id > 0 ORDER BY m.id DESC") + 'SELECT o.*, m.id AS m_id FROM "my:typename" m JOIN "my:othertypename" o ON m.id = o.main_id WHERE m.id > 0 ORDER BY m.id DESC' + ) fields = vl.fields() self.assertEqual(len(fields), 3, fields) - self.assertEqual(fields[0].name(), 'o.main_id') - self.assertEqual(fields[1].name(), 'o.second_id') - self.assertEqual(fields[2].name(), 'm_id') + self.assertEqual(fields[0].name(), "o.main_id") + self.assertEqual(fields[1].name(), "o.second_id") + self.assertEqual(fields[2].name(), "m_id") - values = [(f['o.main_id'], f['o.second_id'], f['m_id']) for f in vl.getFeatures()] + values = [ + (f["o.main_id"], f["o.second_id"], f["m_id"]) for f in vl.getFeatures() + ] self.assertEqual(values, [(1, 2, 1)]) # table_alias.*, field alias, with unprefixed typenames vl.setSubsetString( - "SELECT o.*, m.id AS m_id FROM typename m JOIN othertypename o ON m.id = o.main_id WHERE m.id > 0 ORDER BY m.id DESC") + "SELECT o.*, m.id AS m_id FROM typename m JOIN othertypename o ON m.id = o.main_id WHERE m.id > 0 ORDER BY m.id DESC" + ) fields = vl.fields() self.assertEqual(len(fields), 3, fields) - self.assertEqual(fields[0].name(), 'o.main_id') - self.assertEqual(fields[1].name(), 'o.second_id') - self.assertEqual(fields[2].name(), 'm_id') + self.assertEqual(fields[0].name(), "o.main_id") + self.assertEqual(fields[1].name(), "o.second_id") + self.assertEqual(fields[2].name(), "m_id") - values = [(f['o.main_id'], f['o.second_id'], f['m_id']) for f in vl.getFeatures()] + values = [ + (f["o.main_id"], f["o.second_id"], f["m_id"]) for f in vl.getFeatures() + ] self.assertEqual(values, [(1, 2, 1)]) # Test going back to single layer vl.setSubsetString(None) fields = vl.fields() self.assertEqual(len(fields), 1, fields) - self.assertEqual(fields[0].name(), 'id') + self.assertEqual(fields[0].name(), "id") - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write(schema.encode('UTF-8')) + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write(schema.encode("UTF-8")) # Duplicate fields vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT id, id FROM \"my:typename\"", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT id, id FROM \"my:typename\"", + "test", + "WFS", + ) self.assertFalse(vl.isValid()) # * syntax with single layer vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM \"my:typename\"", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM \"my:typename\"", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) fields = vl.fields() self.assertEqual(len(fields), 1, fields) - self.assertEqual(fields[0].name(), 'id') + self.assertEqual(fields[0].name(), "id") # * syntax with single layer, unprefixed vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM typename", 'test', - 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM typename", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) fields = vl.fields() self.assertEqual(len(fields), 1, fields) - self.assertEqual(fields[0].name(), 'id') + self.assertEqual(fields[0].name(), "id") # test with unqualified field name, and geometry name specified vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT id, geometryProperty FROM typename", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT id, geometryProperty FROM typename", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) fields = vl.fields() self.assertEqual(len(fields), 1, fields) - self.assertEqual(fields[0].name(), 'id') + self.assertEqual(fields[0].name(), "id") # Ambiguous typename vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='first_ns:ambiguous' version='2.0.0' skipInitialGetFeature='true' sql=SELECT id FROM ambiguous", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='first_ns:ambiguous' version='2.0.0' skipInitialGetFeature='true' sql=SELECT id FROM ambiguous", + "test", + "WFS", + ) self.assertFalse(vl.isValid()) # main table missing from SQL vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:othertypename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM typename", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:othertypename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM typename", + "test", + "WFS", + ) self.assertFalse(vl.isValid()) def testFunctionValidation(self): - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_function_validation' + endpoint = ( + self.__class__.basetestpath + "/fake_qgis_http_endpoint_function_validation" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -2490,10 +3275,15 @@ def testFunctionValidation(self): -""") +""" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0"), + "wb", + ) as f: + f.write( + b""" @@ -2540,10 +3330,15 @@ def testFunctionValidation(self): -""") +""" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -2594,7 +3389,8 @@ def testFunctionValidation(self): -""") +""" + ) schema = """ @@ -2612,84 +3408,144 @@ def testFunctionValidation(self): """ - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'), - 'wb') as f: - f.write(schema.encode('UTF-8')) - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename'), - 'wb') as f: - f.write(schema.encode('UTF-8')) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write(schema.encode('UTF-8')) + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write(schema.encode("UTF-8")) + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write(schema.encode("UTF-8")) + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write(schema.encode("UTF-8")) # Existing function and validation enabled vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='1.0.0' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE abs(\"my:typename\".id) > 1", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='1.0.0' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE abs(\"my:typename\".id) > 1", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) # Existing spatial predicated and validation enabled vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='1.0.0' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE ST_Intersects(geom, geom)", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='1.0.0' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE ST_Intersects(geom, geom)", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) # Non existing function and validation enabled vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='1.0.0' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE non_existing(\"my:typename\".id) > 1", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='1.0.0' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE non_existing(\"my:typename\".id) > 1", + "test", + "WFS", + ) self.assertFalse(vl.isValid()) # Non existing function, but validation disabled vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='1.0.0' sql=SELECT * FROM \"my:typename\" WHERE non_existing(\"my:typename\".id) > 1", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='1.0.0' sql=SELECT * FROM \"my:typename\" WHERE non_existing(\"my:typename\".id) > 1", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) # Existing function and validation enabled vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE abs(\"my:typename\".id) > 1", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE abs(\"my:typename\".id) > 1", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) # Existing spatial predicated and validation enabled vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE ST_Intersects(geom, geom)", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE ST_Intersects(geom, geom)", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) # Non existing function and validation enabled vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE non_existing(\"my:typename\".id) > 1", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE non_existing(\"my:typename\".id) > 1", + "test", + "WFS", + ) self.assertFalse(vl.isValid()) # Existing function and validation enabled vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE abs(\"my:typename\".id) > 1", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE abs(\"my:typename\".id) > 1", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) # Existing spatial predicated and validation enabled vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE ST_Intersects(geom, geom)", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE ST_Intersects(geom, geom)", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) # Non existing function and validation enabled vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE non_existing(\"my:typename\".id) > 1", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' validateSQLFunctions=1 sql=SELECT * FROM \"my:typename\" WHERE non_existing(\"my:typename\".id) > 1", + "test", + "WFS", + ) self.assertFalse(vl.isValid()) def testSelectDistinct(self): - """Test SELECT DISTINCT """ + """Test SELECT DISTINCT""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_select_distinct' + endpoint = ( + self.__class__.basetestpath + "/fake_qgis_http_endpoint_select_distinct" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -2703,12 +3559,18 @@ def testSelectDistinct(self): -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -2725,12 +3587,18 @@ def testSelectDistinct(self): -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326"""), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326""", + ), + "wb", + ) as f: + f.write( + b""" 2016-04-10T12:34:56.788Z -""") +""" + ) vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT DISTINCT * FROM \"my:typename\"", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT DISTINCT * FROM \"my:typename\"", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) - values = [(f['intfield'], f['longfield'], f['stringfield'], f['datetimefield']) for f in vl.getFeatures()] - self.assertEqual(values, [(1, 1234567890, 'foo', QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))), - (2, 1234567890, 'foo', QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))), - (1, 1234567891, 'foo', QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))), - (1, 1234567890, 'fop', QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))), - (1, 1234567890, 'foo', QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 788), Qt.TimeSpec(Qt.TimeSpec.UTC)))]) + values = [ + (f["intfield"], f["longfield"], f["stringfield"], f["datetimefield"]) + for f in vl.getFeatures() + ] + self.assertEqual( + values, + [ + ( + 1, + 1234567890, + "foo", + QDateTime( + QDate(2016, 4, 10), + QTime(12, 34, 56, 789), + Qt.TimeSpec(Qt.TimeSpec.UTC), + ), + ), + ( + 2, + 1234567890, + "foo", + QDateTime( + QDate(2016, 4, 10), + QTime(12, 34, 56, 789), + Qt.TimeSpec(Qt.TimeSpec.UTC), + ), + ), + ( + 1, + 1234567891, + "foo", + QDateTime( + QDate(2016, 4, 10), + QTime(12, 34, 56, 789), + Qt.TimeSpec(Qt.TimeSpec.UTC), + ), + ), + ( + 1, + 1234567890, + "fop", + QDateTime( + QDate(2016, 4, 10), + QTime(12, 34, 56, 789), + Qt.TimeSpec(Qt.TimeSpec.UTC), + ), + ), + ( + 1, + 1234567890, + "foo", + QDateTime( + QDate(2016, 4, 10), + QTime(12, 34, 56, 788), + Qt.TimeSpec(Qt.TimeSpec.UTC), + ), + ), + ], + ) vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT DISTINCT intfield FROM \"my:typename\"", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT DISTINCT intfield FROM \"my:typename\"", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) - values = [(f['intfield']) for f in vl.getFeatures()] + values = [(f["intfield"]) for f in vl.getFeatures()] self.assertEqual(values, [(1), (2)]) def testWrongCapabilityExtent(self): @@ -2811,10 +3741,17 @@ def testWrongCapabilityExtent(self): # Note the logic that is tested is purely heuristic, trying to recover from wrong server behavior, # so it might be legitimate to change that at a later point. - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_wrong_capability_extent' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_wrong_capability_extent" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -2828,12 +3765,18 @@ def testWrongCapabilityExtent(self): -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -2848,12 +3791,18 @@ def testWrongCapabilityExtent(self): -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326"""), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326""", + ), + "wb", + ) as f: + f.write( + b""" 49 2 -""") +""" + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) # Download all features @@ -2875,31 +3831,47 @@ def testWrongCapabilityExtent(self): reference = QgsGeometry.fromRect(QgsRectangle(2, 49, 2, 49)) vl_extent = QgsGeometry.fromRect(vl.extent()) - assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0], - 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}' + assert QgsGeometry.compare( + vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001 + ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}" # Same with restrictToRequestBBOX=1 vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' restrictToRequestBBOX=1 skipInitialGetFeature='true'", 'test', - 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' restrictToRequestBBOX=1 skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) # First request that will be attempted - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=-0.125,-0.125,1.125,1.125,urn:ogc:def:crs:EPSG::4326"""), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=-0.125,-0.125,1.125,1.125,urn:ogc:def:crs:EPSG::4326""", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) # And fallback - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1"""), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1""", + ), + "wb", + ) as f: + f.write( + b""" 49 2 -""") +""" + ) # Download all features in a BBOX that encloses the extent reported by capabilities extent = QgsRectangle(-0.125, -0.125, 1.125, 1.125) @@ -2924,10 +3897,14 @@ def testWrongCapabilityExtent(self): def testGeomedia(self): """Test various interoperability specifities that occur with Geomedia Web Server.""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_geomedia' + endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_geomedia" - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -2947,12 +3924,18 @@ def testGeomedia(self): -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -2967,12 +3950,18 @@ def testGeomedia(self): -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=EPSG:32631"""), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=EPSG:32631""", + ), + "wb", + ) as f: + f.write( + b""" 500000 4500000 500000 4510000 510000 4510000 510000 4500000 500000 4500000 -""") +""" + ) # Simulate improper paging support by returning same result set whatever the STARTINDEX is - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=1&COUNT=1&SRSNAME=EPSG:32631"""), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=1&COUNT=1&SRSNAME=EPSG:32631""", + ), + "wb", + ) as f: + f.write( + b""" 500000 4500000 500000 4510000 510000 4510000 510000 4500000 500000 4500000 -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=EPSG:32631"""), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=EPSG:32631""", + ), + "wb", + ) as f: + f.write( + b""" 500000 4500000 500000 4510000 510000 4510000 510000 4500000 500000 4500000 -""") +""" + ) - QgsSettings().setValue('wfs/max_feature_count_if_not_provided', '1') + QgsSettings().setValue("wfs/max_feature_count_if_not_provided", "1") - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.MultiPolygon) # Extent before downloading features reference = QgsGeometry.fromRect( - QgsRectangle(243900.3520259926444851, 4427769.1559739429503679, 1525592.3040170343592763, - 5607994.6020106188952923)) + QgsRectangle( + 243900.3520259926444851, + 4427769.1559739429503679, + 1525592.3040170343592763, + 5607994.6020106188952923, + ) + ) vl_extent = QgsGeometry.fromRect(vl.extent()) - assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0], - 0.05), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}' + assert QgsGeometry.compare( + vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.05 + ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}" # Download all features features = [f for f in vl.getFeatures()] @@ -3045,18 +4059,25 @@ def testGeomedia(self): loop = QEventLoop() loop.processEvents() vl_extent = QgsGeometry.fromRect(vl.extent()) - assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0], - 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}' - self.assertEqual(features[0]['intfield'], 1) - self.assertEqual(features[1]['intfield'], 2) + assert QgsGeometry.compare( + vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001 + ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}" + self.assertEqual(features[0]["intfield"], 1) + self.assertEqual(features[1]["intfield"], 2) def testMapServerWFS1_1_EPSG_4326(self): """Test interoperability with MapServer WFS 1.1.""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_mapserver_wfs_1_1' + endpoint = ( + self.__class__.basetestpath + "/fake_qgis_http_endpoint_mapserver_wfs_1_1" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0"), + "wb", + ) as f: + f.write( + b""" @@ -3070,11 +4091,18 @@ def testMapServerWFS1_1_EPSG_4326(self): -""") +""" + ) - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326"""), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326""", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) got_f = [f for f in vl.getFeatures()] @@ -3144,10 +4185,17 @@ def testMapServerWFS1_1_EPSG_4326(self): def testDescribeFeatureTypeWithInlineType(self): """Test a DescribeFeatureType response with a inline ComplexType (#15395).""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testDescribeFeatureTypeWithInlineType' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_testDescribeFeatureTypeWithInlineType" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0"), + "wb", + ) as f: + f.write( + b""" @@ -3161,11 +4209,18 @@ def testDescribeFeatureTypeWithInlineType(self): -""") +""" + ) - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326"""), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326""", + ), + "wb", + ) as f: + f.write( + b""" -""") - - shutil.copyfile(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326"""), - sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::4326""")) +""" + ) + + shutil.copyfile( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326""", + ), + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::4326""", + ), + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' version='1.1.0' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) got_f = [f for f in vl.getFeatures()] @@ -3240,11 +4314,20 @@ def testDescribeFeatureTypeWithInlineType(self): def testWFS20TransactionsDisabled(self): """Test WFS 2.0 Transaction disabled""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_2.0_transaction_disabled' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_WFS_2.0_transaction_disabled" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0", + ), + "wb", + ) as f: + f.write( + b""" @@ -3270,12 +4353,18 @@ def testWFS20TransactionsDisabled(self): -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -3289,23 +4378,41 @@ def testWFS20TransactionsDisabled(self): -""") +""" + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' skipInitialGetFeature='true'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) - self.assertEqual(vl.dataProvider().capabilities() & vl.dataProvider().EditingCapabilities, - vl.dataProvider().NoCapabilities) + self.assertEqual( + vl.dataProvider().capabilities() & vl.dataProvider().EditingCapabilities, + vl.dataProvider().NoCapabilities, + ) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) def testWFS20TransactionsEnabled(self): """Test WFS 2.0 Transaction enabled""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_2.0_transaction_enabled' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_WFS_2.0_transaction_enabled" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), - 'wb') as f: - f.write(""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0", + ), + "wb", + ) as f: + f.write( + """ @@ -3350,12 +4457,22 @@ def testWFS20TransactionsEnabled(self): -""".format(endpoint=endpoint).encode('UTF-8')) +""".format( + endpoint=endpoint + ).encode( + "UTF-8" + ) + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -3373,22 +4490,37 @@ def testWFS20TransactionsEnabled(self): -""") +""" + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' skipInitialGetFeature='true'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) - self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().EditingCapabilities, - vl.dataProvider().NoCapabilities) + self.assertNotEqual( + vl.dataProvider().capabilities() & vl.dataProvider().EditingCapabilities, + vl.dataProvider().NoCapabilities, + ) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) def testDeprecatedGML2GeometryDeclaration(self): """Test ref="gml:pointProperty" """ - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_deprecated_gml2' + endpoint = ( + self.__class__.basetestpath + "/fake_qgis_http_endpoint_deprecated_gml2" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -3400,11 +4532,18 @@ def testDeprecatedGML2GeometryDeclaration(self): -""") +""" + ) - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -3419,17 +4558,27 @@ def testDeprecatedGML2GeometryDeclaration(self): -""") +""" + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) self.assertEqual(len(vl.fields()), 1) with open( - sanitize(endpoint, '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631'), - 'wb') as f: - f.write(b""" + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631", + ), + "wb", + ) as f: + f.write( + b""" 1 -""") +""" + ) - values = [f['INTFIELD'] for f in vl.getFeatures()] + values = [f["INTFIELD"] for f in vl.getFeatures()] self.assertEqual(values, [1]) got_f = [f for f in vl.getFeatures()] @@ -3453,12 +4603,19 @@ def testDeprecatedGML2GeometryDeclaration(self): self.assertEqual((got.x(), got.y()), (426858.0, 5427937.0)) def testGetFeatureWithNamespaces(self): - ''' test https://github.com/qgis/QGIS/issues/22649 ''' + """test https://github.com/qgis/QGIS/issues/22649""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_getfeature_with_namespaces' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_getfeature_with_namespaces" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -3472,12 +4629,18 @@ def testGetFeatureWithNamespaces(self): -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&NAMESPACES=xmlns(my,http://my)&TYPENAME=my:typename&NAMESPACE=xmlns(my,http://my)'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&NAMESPACES=xmlns(my,http://my)&TYPENAME=my:typename&NAMESPACE=xmlns(my,http://my)", + ), + "wb", + ) as f: + f.write( + b""" @@ -3491,16 +4654,28 @@ def testGetFeatureWithNamespaces(self): -""") +""" + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(len(vl.fields()), 1) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::32631&NAMESPACES=xmlns(my,http://my)&NAMESPACE=xmlns(my,http://my)'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::32631&NAMESPACES=xmlns(my,http://my)&NAMESPACE=xmlns(my,http://my)", + ), + "wb", + ) as f: + f.write( + b""" 1 -""") +""" + ) - values = [f['intfield'] for f in vl.getFeatures()] + values = [f["intfield"] for f in vl.getFeatures()] self.assertEqual(values, [1]) def testGetFeatureWithNamespaceAndFilter(self): - ''' test https://github.com/qgis/QGIS/issues/43957 ''' + """test https://github.com/qgis/QGIS/issues/43957""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_getfeature_with_namespace_and_filter' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_getfeature_with_namespace_and_filter" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -3535,12 +4718,18 @@ def testGetFeatureWithNamespaceAndFilter(self): -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&NAMESPACES=xmlns(my,http://my)&TYPENAME=my:typename&NAMESPACE=xmlns(my,http://my)'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&NAMESPACES=xmlns(my,http://my)&TYPENAME=my:typename&NAMESPACE=xmlns(my,http://my)", + ), + "wb", + ) as f: + f.write( + b""" @@ -3555,23 +4744,35 @@ def testGetFeatureWithNamespaceAndFilter(self): -""") +""" + ) # SQL query with type with namespace - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM \"my:typename\" WHERE intfield = 1", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' sql=SELECT * FROM \"my:typename\" WHERE intfield = 1", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(len(vl.fields()), 1) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::32631&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::32631&FILTER= my:intfield 1 -&NAMESPACES=xmlns(my,http://my)&NAMESPACE=xmlns(my,http://my)"""), - 'wb') as f: - f.write(b""" +&NAMESPACES=xmlns(my,http://my)&NAMESPACE=xmlns(my,http://my)""", + ), + "wb", + ) as f: + f.write( + b""" 1 -""") +""" + ) - values = [f['intfield'] for f in vl.getFeatures()] + values = [f["intfield"] for f in vl.getFeatures()] self.assertEqual(values, [1]) # SQL query with type with namespace and bounding box vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' restrictToRequestBBOX=1 sql=SELECT * FROM \"my:typename\" WHERE intfield > 0", 'test', - 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' restrictToRequestBBOX=1 sql=SELECT * FROM \"my:typename\" WHERE intfield > 0", + "test", + "WFS", + ) extent = QgsRectangle(400000.0, 5400000.0, 450000.0, 5500000.0) request = QgsFeatureRequest().setFilterRect(extent) - if int(QT_VERSION_STR.split('.')[0]) >= 6: + if int(QT_VERSION_STR.split(".")[0]) >= 6: filter_attrs = 'xmlns:fes="http://www.opengis.net/fes/2.0" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:my="http://my"' else: filter_attrs = 'xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:my="http://my" xmlns:fes="http://www.opengis.net/fes/2.0"' - with open(sanitize(endpoint, - f"""?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::32631&FILTER= + with open( + sanitize( + endpoint, + f"""?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::32631&FILTER= my:geometryProperty @@ -3615,9 +4823,12 @@ def testGetFeatureWithNamespaceAndFilter(self): -&NAMESPACES=xmlns(my,http://my)&NAMESPACE=xmlns(my,http://my)"""), - 'wb') as f: - f.write(b""" +&NAMESPACES=xmlns(my,http://my)&NAMESPACE=xmlns(my,http://my)""", + ), + "wb", + ) as f: + f.write( + b""" 1 -""") +""" + ) - values = [f['intfield'] for f in vl.getFeatures(request)] + values = [f["intfield"] for f in vl.getFeatures(request)] self.assertEqual(values, [1]) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='2.0.0' restrictToRequestBBOX=1", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' restrictToRequestBBOX=1", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) # Test that properties in subset strings are prefixed and the namespace URI # is included in the filter - vl.setSubsetString('intfield = 2') - with open(sanitize(endpoint, - f"""?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::32631&FILTER= + vl.setSubsetString("intfield = 2") + with open( + sanitize( + endpoint, + f"""?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::32631&FILTER= my:geometryProperty @@ -3654,9 +4874,12 @@ def testGetFeatureWithNamespaceAndFilter(self): -&NAMESPACES=xmlns(my,http://my)&NAMESPACE=xmlns(my,http://my)"""), - 'wb') as f: - f.write(b""" +&NAMESPACES=xmlns(my,http://my)&NAMESPACE=xmlns(my,http://my)""", + ), + "wb", + ) as f: + f.write( + b""" 2 -""") +""" + ) - values = [f['intfield'] for f in vl.getFeatures(request)] + values = [f["intfield"] for f in vl.getFeatures(request)] self.assertEqual(values, [2]) vl.setSubsetString(None) def testGetFeatureWithServerExpression(self): - ''' test binary spatial operation expression on server ''' + """test binary spatial operation expression on server""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_getfeature_with_server_expression' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_getfeature_with_server_expression" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -3693,12 +4924,18 @@ def testGetFeatureWithServerExpression(self): -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -3713,18 +4950,30 @@ def testGetFeatureWithServerExpression(self): -""") +""" + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' skipInitialGetFeature='true' version='2.0.0'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' skipInitialGetFeature='true' version='2.0.0'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(len(vl.fields()), 1) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) # Simple test - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ), + "wb", + ) as f: + f.write( + b""" 1 1 -""") +""" + ) - values = [f['intfield'] for f in vl.getFeatures()] + values = [f["intfield"] for f in vl.getFeatures()] self.assertEqual(values, [1]) # Get feature according to expression - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' skipInitialGetFeature='true' version='2.0.0'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' skipInitialGetFeature='true' version='2.0.0'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(len(vl.fields()), 1) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) parent_feature = QgsFeature() - parent_feature.setGeometry(QgsGeometry.fromWkt('Polygon ((-20 -20, -20 20, 20 20, 20 -20, -20 -20))')) + parent_feature.setGeometry( + QgsGeometry.fromWkt("Polygon ((-20 -20, -20 20, 20 20, 20 -20, -20 -20))") + ) context = QgsExpressionContext() context.appendScope(QgsExpressionContextUtils.globalScope()) scope = QgsExpressionContextScope() - scope.setVariable('parent', parent_feature, True) + scope.setVariable("parent", parent_feature, True) context.appendScope(scope) request = QgsFeatureRequest() request.setExpressionContext(context) request.setFilterExpression("intersects( $geometry, geometry(var('parent')))") - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= geometryProperty @@ -3770,9 +5030,12 @@ def testGetFeatureWithServerExpression(self): -"""), - 'wb') as f: - f.write(b""" +""", + ), + "wb", + ) as f: + f.write( + b""" 1 1 -""") - values = [f['intfield'] for f in vl.getFeatures(request)] +""" + ) + values = [f["intfield"] for f in vl.getFeatures(request)] self.assertEqual(values, [1]) # Get feature according to expression and filter - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' skipInitialGetFeature='true' version='2.0.0' sql=SELECT * FROM \"my:typename\" WHERE intfield = 1", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' skipInitialGetFeature='true' version='2.0.0' sql=SELECT * FROM \"my:typename\" WHERE intfield = 1", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(len(vl.fields()), 1) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) parent_feature = QgsFeature() - parent_feature.setGeometry(QgsGeometry.fromWkt('Polygon ((-20 -20, -20 20, 20 20, 20 -20, -20 -20))')) + parent_feature.setGeometry( + QgsGeometry.fromWkt("Polygon ((-20 -20, -20 20, 20 20, 20 -20, -20 -20))") + ) scope = QgsExpressionContextScope() - scope.setVariable('parent', parent_feature, True) + scope.setVariable("parent", parent_feature, True) context = QgsExpressionContext() context.appendScope(QgsExpressionContextUtils.globalScope()) context.appendScope(scope) @@ -3804,13 +5076,15 @@ def testGetFeatureWithServerExpression(self): request.setExpressionContext(context) request.setFilterExpression("intersects( $geometry, geometry(var('parent')))") - if int(QT_VERSION_STR.split('.')[0]) >= 6: + if int(QT_VERSION_STR.split(".")[0]) >= 6: polygon_attrs = 'xmlns:gml="http://www.opengis.net/gml/3.2" srsName="urn:ogc:def:crs:EPSG::4326" gml:id="qgis_id_geom_1"' else: polygon_attrs = 'xmlns:gml="http://www.opengis.net/gml/3.2" gml:id="qgis_id_geom_1" srsName="urn:ogc:def:crs:EPSG::4326"' - with open(sanitize(endpoint, - f"""?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= + with open( + sanitize( + endpoint, + f"""?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= geometryProperty @@ -3828,8 +5102,12 @@ def testGetFeatureWithServerExpression(self): -"""), 'wb') as f: - f.write(b""" +""", + ), + "wb", + ) as f: + f.write( + b""" 1 1 - """) - values = [f['intfield'] for f in vl.getFeatures(request)] + """ + ) + values = [f["intfield"] for f in vl.getFeatures(request)] self.assertEqual(values, [1]) # Get feature according to expression and filter and bounding box vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' restrictToRequestBBOX=1 sql=SELECT * FROM \"my:typename\" WHERE intfield = 1", 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true' restrictToRequestBBOX=1 sql=SELECT * FROM \"my:typename\" WHERE intfield = 1", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(len(vl.fields()), 1) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) @@ -3855,22 +5139,26 @@ def testGetFeatureWithServerExpression(self): request = QgsFeatureRequest().setFilterRect(extent) parent_feature = QgsFeature() - parent_feature.setGeometry(QgsGeometry.fromWkt('Polygon ((-20 -20, -20 20, 20 20, 20 -20, -20 -20))')) + parent_feature.setGeometry( + QgsGeometry.fromWkt("Polygon ((-20 -20, -20 20, 20 20, 20 -20, -20 -20))") + ) scope = QgsExpressionContextScope() - scope.setVariable('parent', parent_feature, True) + scope.setVariable("parent", parent_feature, True) context = QgsExpressionContext() context.appendScope(QgsExpressionContextUtils.globalScope()) context.appendScope(scope) request.setExpressionContext(context) request.setFilterExpression("intersects( $geometry, geometry(var('parent')))") - if int(QT_VERSION_STR.split('.')[0]) >= 6: + if int(QT_VERSION_STR.split(".")[0]) >= 6: filter_attrs = 'xmlns:fes="http://www.opengis.net/fes/2.0" xmlns:gml="http://www.opengis.net/gml/3.2"' else: filter_attrs = 'xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:fes="http://www.opengis.net/fes/2.0"' - with open(sanitize(endpoint, - f"""?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= + with open( + sanitize( + endpoint, + f"""?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= geometryProperty @@ -3895,8 +5183,12 @@ def testGetFeatureWithServerExpression(self): -"""), 'wb') as f: - f.write(b""" +""", + ), + "wb", + ) as f: + f.write( + b""" 1 -""") +""" + ) - values = [f['intfield'] for f in vl.getFeatures(request)] + values = [f["intfield"] for f in vl.getFeatures(request)] self.assertEqual(values, [1]) def testExtentSubsetString(self): @@ -3919,11 +5212,20 @@ def testExtentSubsetString(self): def testWFS10DCP(self): """Test a server with different DCP endpoints""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_DCP_1.0' - endpoint_alternate = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_DCP_1.0_alternate' + endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_WFS_DCP_1.0" + endpoint_alternate = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_WFS_DCP_1.0_alternate" + ) - with open(sanitize(endpoint, '?FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0'), 'wb') as f: - f.write(""" + with open( + sanitize( + endpoint, "?FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0" + ), + "wb", + ) as f: + f.write( + """ @@ -3952,12 +5254,22 @@ def testWFS10DCP(self): - """.format(endpoint_alternate).encode('UTF-8')) + """.format( + endpoint_alternate + ).encode( + "UTF-8" + ) + ) - with open(sanitize(endpoint_alternate, - '?FOO=BAR&SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint_alternate, + "?FOO=BAR&SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -3977,24 +5289,38 @@ def testWFS10DCP(self): -""") +""" + ) vl = QgsVectorLayer( - "url='http://" + endpoint + "?FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.1.0" + "' typename='my:typename' version='1.0.0'", - 'test', 'WFS') + "url='http://" + + endpoint + + "?FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.1.0" + + "' typename='my:typename' version='1.0.0'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) self.assertEqual(len(vl.fields()), 5) self.assertEqual(vl.featureCount(), 0) - reference = QgsGeometry.fromRect(QgsRectangle(400000.0, 5400000.0, 450000.0, 5500000.0)) + reference = QgsGeometry.fromRect( + QgsRectangle(400000.0, 5400000.0, 450000.0, 5500000.0) + ) vl_extent = QgsGeometry.fromRect(vl.extent()) - assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0], - 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}' + assert QgsGeometry.compare( + vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001 + ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}" - with open(sanitize(endpoint_alternate, - '?FOO=BAR&SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint_alternate, + "?FOO=BAR&SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631", + ), + "wb", + ) as f: + f.write( + b""" 2016-04-10T12:34:56.789Z - """) + """ + ) # Also test that on file iterator works - os.environ['QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD'] = '0' + os.environ["QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD"] = "0" - values = [f['INTFIELD'] for f in vl.getFeatures()] + values = [f["INTFIELD"] for f in vl.getFeatures()] self.assertEqual(values, [1]) - del os.environ['QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD'] + del os.environ["QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD"] - values = [f['GEOMETRY'] for f in vl.getFeatures()] + values = [f["GEOMETRY"] for f in vl.getFeatures()] self.assertEqual(values, [2]) - values = [f['longfield'] for f in vl.getFeatures()] + values = [f["longfield"] for f in vl.getFeatures()] self.assertEqual(values, [1234567890123]) - values = [f['stringfield'] for f in vl.getFeatures()] - self.assertEqual(values, ['foo']) - - values = [f['datetimefield'] for f in vl.getFeatures()] - self.assertEqual(values, [QDateTime(QDate(2016, 4, 10), QTime(12, 34, 56, 789), Qt.TimeSpec(Qt.TimeSpec.UTC))]) + values = [f["stringfield"] for f in vl.getFeatures()] + self.assertEqual(values, ["foo"]) + + values = [f["datetimefield"] for f in vl.getFeatures()] + self.assertEqual( + values, + [ + QDateTime( + QDate(2016, 4, 10), + QTime(12, 34, 56, 789), + Qt.TimeSpec(Qt.TimeSpec.UTC), + ) + ], + ) got_f = [f for f in vl.getFeatures()] got = got_f[0].geometry().constGet() @@ -4040,7 +5376,10 @@ def testWFS10DCP(self): self.assertEqual(vl.featureCount(), 1) - self.assertTrue(vl.dataProvider().capabilities() & QgsVectorDataProvider.Capability.SelectAtId) + self.assertTrue( + vl.dataProvider().capabilities() + & QgsVectorDataProvider.Capability.SelectAtId + ) (ret, _) = vl.dataProvider().addFeatures([QgsFeature()]) self.assertFalse(ret) @@ -4048,10 +5387,15 @@ def testWFS10DCP(self): self.assertFalse(vl.dataProvider().deleteFeatures([0])) # Test with restrictToRequestBBOX=1 - with open(sanitize(endpoint_alternate, - '?FOO=BAR&SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&BBOX=400000,5400000,450000,5500000'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint_alternate, + "?FOO=BAR&SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&BBOX=400000,5400000,450000,5500000", + ), + "wb", + ) as f: + f.write( + b""" 100 - """) + """ + ) vl = QgsVectorLayer( - "url='http://" + endpoint + "?FOO=BAR" + "' typename='my:typename' version='1.0.0' restrictToRequestBBOX=1", - 'test', 'WFS') + "url='http://" + + endpoint + + "?FOO=BAR" + + "' typename='my:typename' version='1.0.0' restrictToRequestBBOX=1", + "test", + "WFS", + ) extent = QgsRectangle(400000.0, 5400000.0, 450000.0, 5500000.0) request = QgsFeatureRequest().setFilterRect(extent) - values = [f['INTFIELD'] for f in vl.getFeatures(request)] + values = [f["INTFIELD"] for f in vl.getFeatures(request)] self.assertEqual(values, [100]) def testWFS10_outputformat_GML3_1(self): """Test WFS 1.0 with OUTPUTFORMAT=GML3""" # We also test attribute fields in upper-case, and a field named GEOMETRY - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS1.0_gml3' + endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_WFS1.0_gml3" - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -4105,11 +5459,18 @@ def testWFS10_outputformat_GML3_1(self): -""") +""" + ) - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -4123,15 +5484,25 @@ def testWFS10_outputformat_GML3_1(self): -""") +""" + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML3'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML3", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) got_f = [f for f in vl.getFeatures()] got = got_f[0].geometry().constGet() self.assertEqual((got.x(), got.y()), (426858.0, 5427937.0)) # Test with explicit OUTPUTFORMAT as parameter - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0' outputformat='GML2'", - 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' version='1.0.0' outputformat='GML2'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML2'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML2", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) got_f = [f for f in vl.getFeatures()] got = got_f[0].geometry().constGet() self.assertEqual((got.x(), got.y()), (1.0, 2.0)) # Test with explicit OUTPUTFORMAT in URL - vl = QgsVectorLayer("url='http://" + endpoint + "?OUTPUTFORMAT=GML2' typename='my:typename' version='1.0.0'", - 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "?OUTPUTFORMAT=GML2' typename='my:typename' version='1.0.0'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML2'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631&OUTPUTFORMAT=GML2", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) got_f = [f for f in vl.getFeatures()] got = got_f[0].geometry().constGet() @@ -4207,10 +5601,14 @@ def testWFS10_outputformat_GML3_1(self): def testWfs20SamServer(self): """Unknown russian WFS 2.0.0 http://geoportal.samregion.ru/wfs12""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_sam' + endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_sam" - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"), + "wb", + ) as f: + f.write( + b""" EC422 @@ -4219,12 +5617,18 @@ def testWfs20SamServer(self): urn:ogc:def:crs:EPSG::4326 -""") +""" + ) with open( - sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=EC422&TYPENAME=EC422'), - 'wb') as f: - f.write(b""" -""") +""" + ) feature_content = """ """ - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=EC422&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'), - 'wb') as f: - f.write(feature_content.encode('UTF-8')) + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=EC422&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ), + "wb", + ) as f: + f.write(feature_content.encode("UTF-8")) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=EC422&SRSNAME=urn:ogc:def:crs:EPSG::4326'), - 'wb') as f: - f.write(feature_content.encode('UTF-8')) + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=EC422&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ), + "wb", + ) as f: + f.write(feature_content.encode("UTF-8")) - vl = QgsVectorLayer("url='http://" + endpoint + "' version='2.0.0' skipInitialGetFeature='true' typename='EC422'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' version='2.0.0' skipInitialGetFeature='true' typename='EC422'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) features = list(vl.getFeatures()) self.assertEqual(len(features), 3) geom = features[0].geometry() geom_string = geom.asWkt() - geom_string = re.sub(r'\.\d+', '', geom_string)[:100] - self.assertEqual(geom_string, - "LineString (9540051 5997366, 9539934 5997127, 9539822 5996862, 9539504 5996097, 9539529 5996093, 953") + geom_string = re.sub(r"\.\d+", "", geom_string)[:100] + self.assertEqual( + geom_string, + "LineString (9540051 5997366, 9539934 5997127, 9539822 5996862, 9539504 5996097, 9539529 5996093, 953", + ) def testDescribeFeatureTypeWithSingleInclude(self): """Test DescribeFeatureType response which has a single child node""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_DescribeFeatureTypeWithSingleInclude' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_DescribeFeatureTypeWithSingleInclude" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0", + ), + "wb", + ) as f: + f.write( + b""" @@ -4434,19 +5864,30 @@ def testDescribeFeatureTypeWithSingleInclude(self): urn:ogc:def:crs:EPSG::4326 -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write((""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + ( + """ -""" % ('http://' + endpoint + '?myschema.xsd')).encode('UTF-8')) +""" + % ("http://" + endpoint + "?myschema.xsd") + ).encode("UTF-8") + ) - with open(sanitize(endpoint, '?myschema.xsd'), 'wb') as f: - f.write(b""" + with open(sanitize(endpoint, "?myschema.xsd"), "wb") as f: + f.write( + b""" @@ -4460,19 +5901,30 @@ def testDescribeFeatureTypeWithSingleInclude(self): -""") +""" + ) # Create test layer - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' skipInitialGetFeature='true'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) def testGeometryCollectionAsMultiLineString(self): - """Test https://github.com/qgis/QGIS/issues/27398 """ + """Test https://github.com/qgis/QGIS/issues/27398""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_gc_as_mls' + endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_gc_as_mls" - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0"), + "wb", + ) as f: + f.write( + b""" @@ -4486,11 +5938,18 @@ def testGeometryCollectionAsMultiLineString(self): -""") +""" + ) - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) get_features = """ """ - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::4326"""), - 'wb') as f: - f.write(get_features.encode('UTF-8')) + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::4326""", + ), + "wb", + ) as f: + f.write(get_features.encode("UTF-8")) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326"""), - 'wb') as f: - f.write(get_features.encode('UTF-8')) + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326""", + ), + "wb", + ) as f: + f.write(get_features.encode("UTF-8")) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.1.0'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='my:typename' version='1.1.0'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) got_f = [f for f in vl.getFeatures()] geom = got_f[0].geometry().constGet() geom_string = geom.asWkt() - geom_string = re.sub(r'\.\d+', '', geom_string) - self.assertEqual(geom_string, 'MultiLineString ((2 49, 3 50))') + geom_string = re.sub(r"\.\d+", "", geom_string) + self.assertEqual(geom_string, "MultiLineString ((2 49, 3 50))") reference = QgsGeometry.fromRect(QgsRectangle(2, 49, 3, 50)) vl_extent = QgsGeometry.fromRect(vl.extent()) - assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0], - 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}' + assert QgsGeometry.compare( + vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001 + ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}" def test_NullValues_regression_20961(self): """Test that provider handles null values, regression #20961""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_null_values' + endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_null_values" - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0"), + "wb", + ) as f: + f.write( + b""" @@ -4588,11 +6065,18 @@ def test_NullValues_regression_20961(self): -""") +""" + ) - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=points'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=points", + ), + "wb", + ) as f: + f.write( + b""" @@ -4610,7 +6094,8 @@ def test_NullValues_regression_20961(self): -""") +""" + ) get_feature_1 = """ @@ -4698,44 +6183,65 @@ def test_NullValues_regression_20961(self): """ - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::3857"""), - 'wb') as f: - f.write(get_feature_1.encode('UTF-8')) + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::3857""", + ), + "wb", + ) as f: + f.write(get_feature_1.encode("UTF-8")) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&SRSNAME=urn:ogc:def:crs:EPSG::3857"""), - 'wb') as f: - f.write(get_features.encode('UTF-8')) + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&SRSNAME=urn:ogc:def:crs:EPSG::3857""", + ), + "wb", + ) as f: + f.write(get_features.encode("UTF-8")) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='points' version='1.1.0' skipInitialGetFeature='true'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='points' version='1.1.0' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) got_f = [f for f in vl.getFeatures()] - self.assertEqual(got_f[0]['type'], NULL) - self.assertEqual(got_f[0]['elevation'], NULL) - self.assertEqual(str(got_f[0]['name']), 'Xxx') - self.assertEqual(str(got_f[1]['type']), '0') - self.assertEqual(got_f[1]['elevation'], NULL) - self.assertEqual(str(got_f[1]['name']), 'sdf') + self.assertEqual(got_f[0]["type"], NULL) + self.assertEqual(got_f[0]["elevation"], NULL) + self.assertEqual(str(got_f[0]["name"]), "Xxx") + self.assertEqual(str(got_f[1]["type"]), "0") + self.assertEqual(got_f[1]["elevation"], NULL) + self.assertEqual(str(got_f[1]["name"]), "sdf") # Now iterate ! Regression #20961 ids = [f.id() for f in got_f] got_f2 = [vl.getFeature(id) for id in ids] - self.assertEqual(got_f2[0]['type'], NULL) - self.assertEqual(got_f2[0]['elevation'], NULL) - self.assertEqual(str(got_f2[0]['name']), 'Xxx') - self.assertEqual(str(got_f2[1]['type']), '0') - self.assertEqual(got_f2[1]['elevation'], NULL) - self.assertEqual(str(got_f2[1]['name']), 'sdf') + self.assertEqual(got_f2[0]["type"], NULL) + self.assertEqual(got_f2[0]["elevation"], NULL) + self.assertEqual(str(got_f2[0]["name"]), "Xxx") + self.assertEqual(str(got_f2[1]["type"]), "0") + self.assertEqual(got_f2[1]["elevation"], NULL) + self.assertEqual(str(got_f2[1]["name"]), "sdf") def testFilteredFeatureRequests(self): - """Test https://github.com/qgis/QGIS/issues/28895 """ + """Test https://github.com/qgis/QGIS/issues/28895""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_filtered_feature_requests' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_filtered_feature_requests" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0"), + "wb", + ) as f: + f.write( + b""" @@ -4749,11 +6255,18 @@ def testFilteredFeatureRequests(self): -""") +""" + ) - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=points'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=points", + ), + "wb", + ) as f: + f.write( + b""" @@ -4771,7 +6284,8 @@ def testFilteredFeatureRequests(self): -""") +""" + ) get_feature_1 = """ @@ -4859,29 +6373,47 @@ def testFilteredFeatureRequests(self): """ - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::3857"""), - 'wb') as f: - f.write(get_feature_1.encode('UTF-8')) + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::3857""", + ), + "wb", + ) as f: + f.write(get_feature_1.encode("UTF-8")) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&SRSNAME=urn:ogc:def:crs:EPSG::3857"""), - 'wb') as f: - f.write(get_features.encode('UTF-8')) + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&SRSNAME=urn:ogc:def:crs:EPSG::3857""", + ), + "wb", + ) as f: + f.write(get_features.encode("UTF-8")) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='points' version='1.1.0' skipInitialGetFeature='true'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='points' version='1.1.0' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) # Fill the cache [f for f in vl.getFeatures()] - qgis_feat = next(vl.getFeatures(QgsFeatureRequest(QgsExpression('"name" = \'qgis\'')))) - other_feat = next(vl.getFeatures(QgsFeatureRequest(QgsExpression('"name" != \'qgis\'')))) - self.assertEqual(qgis_feat['name'], 'qgis') - self.assertEqual(other_feat['name'], 'Xxx') + qgis_feat = next( + vl.getFeatures(QgsFeatureRequest(QgsExpression("\"name\" = 'qgis'"))) + ) + other_feat = next( + vl.getFeatures(QgsFeatureRequest(QgsExpression("\"name\" != 'qgis'"))) + ) + self.assertEqual(qgis_feat["name"], "qgis") + self.assertEqual(other_feat["name"], "Xxx") form_scope = QgsExpressionContextUtils.formScope(qgis_feat) - form_exp = QgsExpression('current_value(\'name\') = "name"') + form_exp = QgsExpression("current_value('name') = \"name\"") ctx = QgsExpressionContext() ctx.appendScope(form_scope) ctx.setFeature(qgis_feat) @@ -4895,12 +6427,19 @@ def testFilteredFeatureRequests(self): qgis_feat = next(vl.getFeatures(req)) def testWFSFieldWithSameNameButDifferentCase(self): - """Test a layer with field foo and FOO """ + """Test a layer with field foo and FOO""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_FieldWithSameNameButDifferentCase' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_FieldWithSameNameButDifferentCase" + ) - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -4912,11 +6451,18 @@ def testWFSFieldWithSameNameButDifferentCase(self): -""") +""" + ) - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -4933,12 +6479,18 @@ def testWFSFieldWithSameNameButDifferentCase(self): -""") +""" + ) with open( - sanitize(endpoint, '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631'), - 'wb') as f: - f.write(b""" + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631", + ), + "wb", + ) as f: + f.write( + b""" 3 - """) + """ + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(len(vl.fields()), 3) - values = [f['foo'] for f in vl.getFeatures()] + values = [f["foo"] for f in vl.getFeatures()] self.assertEqual(values, [1]) - values = [f['FOO'] for f in vl.getFeatures()] + values = [f["FOO"] for f in vl.getFeatures()] self.assertEqual(values, [2]) - values = [f['FOO2'] for f in vl.getFeatures()] + values = [f["FOO2"] for f in vl.getFeatures()] self.assertEqual(values, [3]) # Also test that on file iterator works - os.environ['QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD'] = '0' + os.environ["QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD"] = "0" - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS') - values = [f['foo'] for f in vl.getFeatures()] + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", + "test", + "WFS", + ) + values = [f["foo"] for f in vl.getFeatures()] self.assertEqual(values, [1]) - values = [f['FOO'] for f in vl.getFeatures()] + values = [f["FOO"] for f in vl.getFeatures()] self.assertEqual(values, [2]) - values = [f['FOO2'] for f in vl.getFeatures()] + values = [f["FOO2"] for f in vl.getFeatures()] self.assertEqual(values, [3]) - del os.environ['QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD'] + del os.environ["QGIS_WFS_ITERATOR_TRANSFER_THRESHOLD"] - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS') - request = QgsFeatureRequest().setFilterExpression('FOO = 2') - values = [f['FOO'] for f in vl.getFeatures(request)] + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", + "test", + "WFS", + ) + request = QgsFeatureRequest().setFilterExpression("FOO = 2") + values = [f["FOO"] for f in vl.getFeatures(request)] self.assertEqual(values, [2]) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS') - request = QgsFeatureRequest().setSubsetOfAttributes(['FOO'], vl.fields()) - values = [f['FOO'] for f in vl.getFeatures(request)] + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", + "test", + "WFS", + ) + request = QgsFeatureRequest().setSubsetOfAttributes(["FOO"], vl.fields()) + values = [f["FOO"] for f in vl.getFeatures(request)] self.assertEqual(values, [2]) def testRetryLogicOnExceptionLackOfPrimaryKey(self): - """Test retry logic on 'Cannot do natural order without a primary key' server exception (GeoServer) """ + """Test retry logic on 'Cannot do natural order without a primary key' server exception (GeoServer)""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_retry' + endpoint = self.__class__.basetestpath + "/fake_qgis_http_endpoint_retry" - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=GetCapabilities&VERSION=2.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS&REQUEST=GetCapabilities&VERSION=2.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -5023,12 +6596,18 @@ def testRetryLogicOnExceptionLackOfPrimaryKey(self): -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -5042,30 +6621,48 @@ def testRetryLogicOnExceptionLackOfPrimaryKey(self): -""") +""" + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.NoGeometry) self.assertEqual(len(vl.fields()), 1) # Initial request: exception - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326", + ), + "wb", + ) as f: + f.write( + b""" java.lang.RuntimeException: java.lang.RuntimeException: java.io.IOException java.lang.RuntimeException: java.io.IOException java.io.IOExceptionCannot do natural order without a primary key, please add it or specify a manual sort over existing attributes -""") +""" + ) # Retry - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&RETRY=1'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&RETRY=1", + ), + "wb", + ) as f: + f.write( + b""" 2 -""") +""" + ) - values = [f['INTFIELD'] for f in vl.getFeatures()] + values = [f["INTFIELD"] for f in vl.getFeatures()] self.assertEqual(values, [1, 2]) def testCacheRead(self): @@ -5091,7 +6689,7 @@ def testCacheRead(self): QgsSettings().setValue("cache/directory", cache_dir) # don't retry, http server never fails - QgsSettings().setValue('qgis/defaultTileMaxRetry', '0') + QgsSettings().setValue("qgis/defaultTileMaxRetry", "0") responses = [] @@ -5102,15 +6700,17 @@ def do_GET(self): self.send_response(c) self.send_header("Content-type", "application/xml") self.send_header("Content-length", len(response)) - self.send_header('Last-Modified', 'Wed, 05 Jun 2019 15:33:27 GMT') + self.send_header("Last-Modified", "Wed, 05 Jun 2019 15:33:27 GMT") self.end_headers() - self.wfile.write(response.encode('UTF-8')) + self.wfile.write(response.encode("UTF-8")) - httpd = socketserver.TCPServer(('localhost', 0), SequentialHandler) + httpd = socketserver.TCPServer(("localhost", 0), SequentialHandler) port = httpd.server_address[1] - responses.append((200, - """ + responses.append( + ( + 200, + """ @@ -5120,10 +6720,14 @@ def do_GET(self): EPSG:4326 -""")) - - responses.append((200, - """ +""", + ) + ) + + responses.append( + ( + 200, + """ @@ -5137,10 +6741,14 @@ def do_GET(self): -""")) - - responses.append((200, - """ +""", + ) + ) + + responses.append( + ( + 200, + """ 2 -""")) +""", + ) + ) httpd_thread = threading.Thread(target=httpd.serve_forever) httpd_thread.daemon = True httpd_thread.start() - vl = QgsVectorLayer(f"url='http://localhost:{port}' typename='my:typename' version='1.0.0'", 'test', - 'WFS') + vl = QgsVectorLayer( + f"url='http://localhost:{port}' typename='my:typename' version='1.0.0'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.NoGeometry) self.assertEqual(len(vl.fields()), 1) - res = [f['INTFIELD'] for f in vl.getFeatures()] + res = [f["INTFIELD"] for f in vl.getFeatures()] self.assertEqual(sorted(res), [1, 2]) # next response is empty, cache must be used @@ -5176,7 +6789,7 @@ def do_GET(self): # Reload vl.reload() - res = [f['INTFIELD'] for f in vl.getFeatures()] + res = [f["INTFIELD"] for f in vl.getFeatures()] # self.assertEqual(len(server.errors()), 0, server.errors()) self.assertEqual(sorted(res), [1, 2]) @@ -5187,7 +6800,10 @@ def testWFS20CaseInsensitiveKVP(self): """Test an URL with non standard query string arguments where the server exposes the same parameters with different case: see https://github.com/qgis/QGIS/issues/34148 """ - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_case_insensitive_kvp_2.0' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_WFS_case_insensitive_kvp_2.0" + ) get_cap = """ @@ -5218,22 +6834,39 @@ def testWFS20CaseInsensitiveKVP(self): - """.format(endpoint).encode('UTF-8') + """.format( + endpoint + ).encode( + "UTF-8" + ) - with open(sanitize(endpoint, - '?PARAMETER1=Value1&PARAMETER2=Value2&FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0'), - 'wb') as f: + with open( + sanitize( + endpoint, + "?PARAMETER1=Value1&PARAMETER2=Value2&FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0", + ), + "wb", + ) as f: f.write(get_cap) - with open(sanitize(endpoint, - '?Parameter1=Value1&Parameter2=Value2&FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0'), - 'wb') as f: + with open( + sanitize( + endpoint, + "?Parameter1=Value1&Parameter2=Value2&FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0", + ), + "wb", + ) as f: f.write(get_cap) - with open(sanitize(endpoint, - '?PARAMETER1=Value1&PARAMETER2=Value2&FOO=BAR&SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?PARAMETER1=Value1&PARAMETER2=Value2&FOO=BAR&SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -5253,24 +6886,35 @@ def testWFS20CaseInsensitiveKVP(self): -""") +""" + ) vl = QgsVectorLayer( - "url='http://" + endpoint + "?Parameter1=Value1&Parameter2=Value2&FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.1.0" + "' typename='my:typename' version='1.0.0'", - 'test', 'WFS') + "url='http://" + + endpoint + + "?Parameter1=Value1&Parameter2=Value2&FOO=BAR&SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.1.0" + + "' typename='my:typename' version='1.0.0'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) self.assertEqual(len(vl.fields()), 5) self.assertEqual(vl.featureCount(), 0) - reference = QgsGeometry.fromRect(QgsRectangle(400000.0, 5400000.0, 450000.0, 5500000.0)) + reference = QgsGeometry.fromRect( + QgsRectangle(400000.0, 5400000.0, 450000.0, 5500000.0) + ) vl_extent = QgsGeometry.fromRect(vl.extent()) - assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0], - 0.00001), f'Expected {reference.asWkt()}, got {vl_extent.asWkt()}' + assert QgsGeometry.compare( + vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001 + ), f"Expected {reference.asWkt()}, got {vl_extent.asWkt()}" def testGetCapabilitiesReturnWFSException(self): - """Test parsing of WFS exception - """ - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testGetCapabilitiesReturnWFSException' + """Test parsing of WFS exception""" + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_testGetCapabilitiesReturnWFSException" + ) get_cap_response = b""" """ - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0'), - 'wb') as f: + with open( + sanitize(endpoint, "?SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0"), + "wb", + ) as f: f.write(get_cap_response) - with MessageLogger('WFS') as logger: - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS') + with MessageLogger("WFS") as logger: + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", + "test", + "WFS", + ) self.assertFalse(vl.isValid()) self.assertEqual(len(logger.messages()), 1, logger.messages()) - self.assertIn("foo: bar", logger.messages()[0].decode('UTF-8')) + self.assertIn("foo: bar", logger.messages()[0].decode("UTF-8")) def testGetCapabilitiesReturnWMSException(self): - """Test fix for https://github.com/qgis/QGIS/issues/29866 - """ - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testGetCapabilitiesReturnWMSxception' + """Test fix for https://github.com/qgis/QGIS/issues/29866""" + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_testGetCapabilitiesReturnWMSxception" + ) get_cap_response = b""" @@ -5307,40 +6958,81 @@ def testGetCapabilitiesReturnWMSException(self): """ - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0'), - 'wb') as f: + with open( + sanitize(endpoint, "?SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0"), + "wb", + ) as f: f.write(get_cap_response) - with MessageLogger('WFS') as logger: - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS') + with MessageLogger("WFS") as logger: + vl = QgsVectorLayer( + "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", + "test", + "WFS", + ) self.assertFalse(vl.isValid()) self.assertEqual(len(logger.messages()), 1, logger.messages()) - self.assertIn("InvalidFormat: Can't recognize service requested.", logger.messages()[0].decode('UTF-8')) + self.assertIn( + "InvalidFormat: Can't recognize service requested.", + logger.messages()[0].decode("UTF-8"), + ) def testWFST11(self): """Test WFS-T 1.1 (read-write) taken from a geoserver session""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_T_1_1_transaction' - - shutil.copy(os.path.join(TEST_DATA_DIR, 'provider', 'wfst-1-1', 'getcapabilities.xml'), sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0')) - shutil.copy(os.path.join(TEST_DATA_DIR, 'provider', 'wfst-1-1', 'describefeaturetype_polygons.xml'), sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=ws1:polygons')) + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_WFS_T_1_1_transaction" + ) + + shutil.copy( + os.path.join(TEST_DATA_DIR, "provider", "wfst-1-1", "getcapabilities.xml"), + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0"), + ) + shutil.copy( + os.path.join( + TEST_DATA_DIR, + "provider", + "wfst-1-1", + "describefeaturetype_polygons.xml", + ), + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=ws1:polygons", + ), + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='ws1:polygons' version='1.1.0' skipInitialGetFeature='true'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='ws1:polygons' version='1.1.0' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 0) - self.assertEqual(vl.dataProvider().capabilities(), - QgsVectorDataProvider.Capability.AddFeatures - | QgsVectorDataProvider.Capability.ChangeAttributeValues - | QgsVectorDataProvider.Capability.ChangeGeometries - | QgsVectorDataProvider.Capability.DeleteFeatures - | QgsVectorDataProvider.Capability.SelectAtId - | QgsVectorDataProvider.Capability.ReloadData) + self.assertEqual( + vl.dataProvider().capabilities(), + QgsVectorDataProvider.Capability.AddFeatures + | QgsVectorDataProvider.Capability.ChangeAttributeValues + | QgsVectorDataProvider.Capability.ChangeGeometries + | QgsVectorDataProvider.Capability.DeleteFeatures + | QgsVectorDataProvider.Capability.SelectAtId + | QgsVectorDataProvider.Capability.ReloadData, + ) # Transaction response failure (no modifications) - shutil.copy(os.path.join(TEST_DATA_DIR, 'provider', 'wfst-1-1', 'transaction_response_empty.xml'), sanitize(endpoint, '?SERVICE=WFS&POSTDATA=<_Insert><_Transaction>')) + shutil.copy( + os.path.join( + TEST_DATA_DIR, "provider", "wfst-1-1", "transaction_response_empty.xml" + ), + sanitize( + endpoint, + '?SERVICE=WFS&POSTDATA=<_Insert><_Transaction>', + ), + ) (ret, _) = vl.dataProvider().addFeatures([QgsFeature()]) self.assertFalse(ret) @@ -5349,51 +7041,109 @@ def testWFST11(self): # Test add features for real # Transaction response with 1 feature added - if int(QT_VERSION_STR.split('.')[0]) >= 6: + if int(QT_VERSION_STR.split(".")[0]) >= 6: attrs = 'xmlns="http:__www.opengis.net_wfs" service="WFS" version="1.1.0" xmlns:gml="http:__www.opengis.net_gml" xmlns:ws1="ws1" xmlns:xsi="http:__www.w3.org_2001_XMLSchema-instance" xsi:schemaLocation="ws1 http:__fake_qgis_http_endpoint?REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=ws1:polygons"' else: attrs = 'xmlns="http:__www.opengis.net_wfs" xmlns:xsi="http:__www.w3.org_2001_XMLSchema-instance" xmlns:gml="http:__www.opengis.net_gml" xmlns:ws1="ws1" xsi:schemaLocation="ws1 http:__fake_qgis_http_endpoint?REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=ws1:polygons" version="1.1.0" service="WFS"' - shutil.copy(os.path.join(TEST_DATA_DIR, 'provider', 'wfst-1-1', 'transaction_response_feature_added.xml'), sanitize(endpoint, f'?SERVICE=WFS&POSTDATA=one<_name>1<_value>45 9 45 10 46 10 46 9 45 9<_gml:posList><_gml:LinearRing><_gml:exterior><_gml:Polygon><_geometry><_polygons><_Insert><_Transaction>')) + shutil.copy( + os.path.join( + TEST_DATA_DIR, + "provider", + "wfst-1-1", + "transaction_response_feature_added.xml", + ), + sanitize( + endpoint, + f'?SERVICE=WFS&POSTDATA=one<_name>1<_value>45 9 45 10 46 10 46 9 45 9<_gml:posList><_gml:LinearRing><_gml:exterior><_gml:Polygon><_geometry><_polygons><_Insert><_Transaction>', + ), + ) feat = QgsFeature(vl.fields()) - feat.setAttribute('name', 'one') - feat.setAttribute('value', 1) - feat.setGeometry(QgsGeometry.fromWkt('Polygon ((9 45, 10 45, 10 46, 9 46, 9 45))')) + feat.setAttribute("name", "one") + feat.setAttribute("value", 1) + feat.setGeometry( + QgsGeometry.fromWkt("Polygon ((9 45, 10 45, 10 46, 9 46, 9 45))") + ) (ret, features) = vl.dataProvider().addFeatures([feat]) - self.assertEqual(features[0].attributes(), ['one', 1]) + self.assertEqual(features[0].attributes(), ["one", 1]) self.assertEqual(vl.featureCount(), 1) # Test change attributes # Transaction response with 1 feature changed - shutil.copy(os.path.join(TEST_DATA_DIR, 'provider', 'wfst-1-1', 'transaction_response_feature_changed.xml'), sanitize(endpoint, f'?SERVICE=WFS&POSTDATA=ws1:nameone-one-onews1:value111')) - - self.assertTrue(vl.dataProvider().changeAttributeValues({1: {0: 'one-one-one', 1: 111}})) - self.assertEqual(next(vl.dataProvider().getFeatures()).attributes(), ['one-one-one', 111]) + shutil.copy( + os.path.join( + TEST_DATA_DIR, + "provider", + "wfst-1-1", + "transaction_response_feature_changed.xml", + ), + sanitize( + endpoint, + f'?SERVICE=WFS&POSTDATA=ws1:nameone-one-onews1:value111', + ), + ) + + self.assertTrue( + vl.dataProvider().changeAttributeValues({1: {0: "one-one-one", 1: 111}}) + ) + self.assertEqual( + next(vl.dataProvider().getFeatures()).attributes(), ["one-one-one", 111] + ) # Test change geometry # Transaction response with 1 feature changed - shutil.copy(os.path.join(TEST_DATA_DIR, 'provider', 'wfst-1-1', 'transaction_response_feature_changed.xml'), sanitize(endpoint, f'?SERVICE=WFS&POSTDATA=ws1:geometry<_Name>46 10 46 11 47 11 47 10 46 10<_gml:posList><_gml:LinearRing><_gml:exterior><_gml:Polygon><_Value><_Property><_Filter><_Update><_Transaction>')) - - new_geom = QgsGeometry.fromWkt('Polygon ((10 46, 11 46, 11 47, 10 47, 10 46))') + shutil.copy( + os.path.join( + TEST_DATA_DIR, + "provider", + "wfst-1-1", + "transaction_response_feature_changed.xml", + ), + sanitize( + endpoint, + f'?SERVICE=WFS&POSTDATA=ws1:geometry<_Name>46 10 46 11 47 11 47 10 46 10<_gml:posList><_gml:LinearRing><_gml:exterior><_gml:Polygon><_Value><_Property><_Filter><_Update><_Transaction>', + ), + ) + + new_geom = QgsGeometry.fromWkt("Polygon ((10 46, 11 46, 11 47, 10 47, 10 46))") self.assertTrue(vl.dataProvider().changeGeometryValues({1: new_geom})) - self.assertEqual(next(vl.dataProvider().getFeatures()).geometry().asWkt(), new_geom.asWkt()) + self.assertEqual( + next(vl.dataProvider().getFeatures()).geometry().asWkt(), new_geom.asWkt() + ) # Test delete feature # Transaction response with 1 feature deleted - shutil.copy(os.path.join(TEST_DATA_DIR, 'provider', 'wfst-1-1', 'transaction_response_feature_deleted.xml'), sanitize(endpoint, f'?SERVICE=WFS&POSTDATA=')) + shutil.copy( + os.path.join( + TEST_DATA_DIR, + "provider", + "wfst-1-1", + "transaction_response_feature_deleted.xml", + ), + sanitize( + endpoint, + f'?SERVICE=WFS&POSTDATA=', + ), + ) self.assertTrue(vl.dataProvider().deleteFeatures([1])) self.assertEqual(vl.featureCount(), 0) def testSelectZeroFeature(self): - """Test a layer with a filter that returns 0 feature. See https://github.com/qgis/QGIS/issues/43950 """ + """Test a layer with a filter that returns 0 feature. See https://github.com/qgis/QGIS/issues/43950""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_select_zero_feature' + endpoint = ( + self.__class__.basetestpath + "/fake_qgis_http_endpoint_select_zero_feature" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -5407,12 +7157,18 @@ def testSelectZeroFeature(self): -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -5427,28 +7183,40 @@ def testSelectZeroFeature(self): -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= intfield -1 -"""), - 'wb') as f: - f.write(b""" +""", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326"""), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326""", + ), + "wb", + ) as f: + f.write( + b""" 78.3 -65.32 -""") +""" + ) vl = QgsVectorLayer( - "url='http://" + endpoint + "' typename='my:typename' version='2.0.0' sql=SELECT * FROM \"my:typename\" WHERE intfield = -1", - 'test', 'WFS') + "url='http://" + + endpoint + + "' typename='my:typename' version='2.0.0' sql=SELECT * FROM \"my:typename\" WHERE intfield = -1", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) def testLayerWithGeometryFieldButNoGeom(self): - """ https://github.com/qgis/QGIS/pull/50237#pullrequestreview-1111702042 """ + """https://github.com/qgis/QGIS/pull/50237#pullrequestreview-1111702042""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_layer_with_geometry_field_but_no_geom' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_layer_with_geometry_field_but_no_geom" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -5487,12 +7267,18 @@ def testLayerWithGeometryFieldButNoGeom(self): -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -5507,12 +7293,18 @@ def testLayerWithGeometryFieldButNoGeom(self): -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326"""), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326""", + ), + "wb", + ) as f: + f.write( + b""" 1 -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=-90,-180,90,180,urn:ogc:def:crs:EPSG::4326"""), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=-90,-180,90,180,urn:ogc:def:crs:EPSG::4326""", + ), + "wb", + ) as f: + f.write( + b""" -""") +""" + ) vl = QgsVectorLayer( "url='http://" + endpoint + "' typename='my:typename' version='2.0.0'", - 'test', 'WFS') + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.NoGeometry) def testWFS20LayerWithGeometryFieldButInitialFeatureHasNoGeom(self): - """ https://github.com/qgis/QGIS/pull/50237 """ + """https://github.com/qgis/QGIS/pull/50237""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_wfs20_layer_with_geometry_field_but_initial_filter_has_no_geom' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_wfs20_layer_with_geometry_field_but_initial_filter_has_no_geom" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -5560,12 +7368,18 @@ def testWFS20LayerWithGeometryFieldButInitialFeatureHasNoGeom(self): -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -5580,12 +7394,18 @@ def testWFS20LayerWithGeometryFieldButInitialFeatureHasNoGeom(self): -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326"""), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326""", + ), + "wb", + ) as f: + f.write( + b""" 1 -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=-90,-180,90,180,urn:ogc:def:crs:EPSG::4326"""), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=-90,-180,90,180,urn:ogc:def:crs:EPSG::4326""", + ), + "wb", + ) as f: + f.write( + b""" 78.3 -65.32 -""") +""" + ) vl = QgsVectorLayer( "url='http://" + endpoint + "' typename='my:typename' version='2.0.0'", - 'test', 'WFS') + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) def testWFS10LayerWithGeometryFieldButInitialFeatureHasNoGeom(self): - """ https://github.com/qgis/QGIS/issues/50935 """ + """https://github.com/qgis/QGIS/issues/50935""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_wfs10_layer_with_geometry_field_but_initial_filter_has_no_geom' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_wfs10_layer_with_geometry_field_but_initial_filter_has_no_geom" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -5637,11 +7473,18 @@ def testWFS10LayerWithGeometryFieldButInitialFeatureHasNoGeom(self): -""") +""" + ) - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -5657,12 +7500,18 @@ def testWFS10LayerWithGeometryFieldButInitialFeatureHasNoGeom(self): -""") +""" + ) with open( - sanitize(endpoint, '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&MAXFEATURES=1&SRSNAME=EPSG:32631'), - 'wb') as f: - f.write(b""" + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&MAXFEATURES=1&SRSNAME=EPSG:32631", + ), + "wb", + ) as f: + f.write( + b""" 1 -""") +""" + ) with open( - sanitize(endpoint, '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&MAXFEATURES=1&SRSNAME=EPSG:32631&BBOX=-100000000,-100000000,100000000,100000000'), - 'wb') as f: - f.write(b""" + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&MAXFEATURES=1&SRSNAME=EPSG:32631&BBOX=-100000000,-100000000,100000000,100000000", + ), + "wb", + ) as f: + f.write( + b""" 1 -""") +""" + ) vl = QgsVectorLayer( "url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", - 'test', 'WFS') + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Point) def testLayerWithFieldsInGMLNamespace(self): - """ https://github.com/qgis/QGIS/issues/42660 """ + """https://github.com/qgis/QGIS/issues/42660""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_layer_with_fields_in_gml_namespace' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_layer_with_fields_in_gml_namespace" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -5720,12 +7585,18 @@ def testLayerWithFieldsInGMLNamespace(self): -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -5740,12 +7611,18 @@ def testLayerWithFieldsInGMLNamespace(self): -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326"""), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326""", + ), + "wb", + ) as f: + f.write( + b""" 78.3 -65.32 -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326"""), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326""", + ), + "wb", + ) as f: + f.write( + b""" 78.3 -65.32 -""") +""" + ) vl = QgsVectorLayer( "url='http://" + endpoint + "' typename='my:typename' version='2.0.0'", - 'test', 'WFS') + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(len(vl.fields()), 4) - values = [f['description'] for f in vl.getFeatures()] + values = [f["description"] for f in vl.getFeatures()] self.assertEqual(values, ["gml_description"]) - values = [f['identifier'] for f in vl.getFeatures()] + values = [f["identifier"] for f in vl.getFeatures()] self.assertEqual(values, ["gml_identifier"]) - values = [f['name'] for f in vl.getFeatures()] + values = [f["name"] for f in vl.getFeatures()] self.assertEqual(values, ["gml_name"]) - values = [f['intfield'] for f in vl.getFeatures()] + values = [f["intfield"] for f in vl.getFeatures()] self.assertEqual(values, [1]) def testLayerWith_gmlId_gmlName_gmlDescription_fields(self): - """ https://github.com/qgis/QGIS/pull/51144#issuecomment-1350590774 """ + """https://github.com/qgis/QGIS/pull/51144#issuecomment-1350590774""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_layer_with_gmlId_gmlName_gmlDescription_fields' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_layer_with_gmlId_gmlName_gmlDescription_fields" + ) - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -5818,12 +7711,18 @@ def testLayerWith_gmlId_gmlName_gmlDescription_fields(self): -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -5841,12 +7740,18 @@ def testLayerWith_gmlId_gmlName_gmlDescription_fields(self): -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326"""), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326""", + ), + "wb", + ) as f: + f.write( + b""" 78.3 -65.32 -""") +""" + ) vl = QgsVectorLayer( "url='http://" + endpoint + "' typename='my:typename' version='2.0.0'", - 'test', 'WFS') + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(len(vl.fields()), 4) def _createBaseFilesForTestsDeegreeServerWithUnknownGeometryType(self, endpoint): # Cf https://xplanung.freiburg.de/xplansyn-wfs/services/xplansynwfs?SERVICE=WFS&REQUEST=GetCapabilities&VERSION=2.0.0 - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=2.0.0"), + "wb", + ) as f: + f.write( + b""" @@ -5943,12 +7855,18 @@ def _createBaseFilesForTestsDeegreeServerWithUnknownGeometryType(self, endpoint) -""") +""" + ) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), - 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -5963,40 +7881,60 @@ def _createBaseFilesForTestsDeegreeServerWithUnknownGeometryType(self, endpoint) -""") +""" + ) def testDeegreeServerWithUnknownGeometryType(self): - """ https://github.com/qgis/QGIS/issues/49328 """ + """https://github.com/qgis/QGIS/issues/49328""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_layer_unknown_geometry_type' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_layer_unknown_geometry_type" + ) self._createBaseFilesForTestsDeegreeServerWithUnknownGeometryType(endpoint) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&RESULTTYPE=hits'), 'wb') as f: - f.write(b""" -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= geometry -&RESULTTYPE=hits"""), 'wb') as f: - f.write(b""" -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= @@ -6011,16 +7949,23 @@ def testDeegreeServerWithUnknownGeometryType(self): -&RESULTTYPE=hits"""), 'wb') as f: - f.write(b""" -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= @@ -6035,16 +7980,23 @@ def testDeegreeServerWithUnknownGeometryType(self): -&RESULTTYPE=hits"""), 'wb') as f: - f.write(b""" -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= @@ -6059,17 +8011,22 @@ def testDeegreeServerWithUnknownGeometryType(self): -&RESULTTYPE=hits"""), 'wb') as f: - f.write(b""" -""") +""" + ) uri = "url='http://" + endpoint + "' typename='my:typename' version='2.0.0'" - metadata = QgsProviderRegistry.instance().providerMetadata('wfs') + metadata = QgsProviderRegistry.instance().providerMetadata("wfs") sublayers = metadata.querySublayers("invalid") self.assertEqual(len(sublayers), 0) @@ -6079,7 +8036,11 @@ def testDeegreeServerWithUnknownGeometryType(self): self.assertEqual(sublayers[0].uri(), uri + " geometryTypeFilter='NoGeometry'") self.assertEqual(sublayers[0].type(), QgsMapLayerType.VectorLayer) - self.assertEqual(sublayers[0].name(), "my:typename " + QgsWkbTypes.translatedDisplayString(QgsWkbTypes.Type.NoGeometry)) + self.assertEqual( + sublayers[0].name(), + "my:typename " + + QgsWkbTypes.translatedDisplayString(QgsWkbTypes.Type.NoGeometry), + ) self.assertEqual(sublayers[0].providerKey(), "WFS") self.assertEqual(sublayers[0].wkbType(), QgsWkbTypes.Type.NoGeometry) self.assertEqual(sublayers[0].featureCount(), 2) @@ -6102,14 +8063,18 @@ def testDeegreeServerWithUnknownGeometryType(self): self.assertEqual(sublayers[3].wkbType(), QgsWkbTypes.Type.MultiSurface) self.assertEqual(sublayers[3].featureCount(), 5) - self.assertEqual(sublayers[4].uri(), uri + " geometryTypeFilter='GeometryCollection'") + self.assertEqual( + sublayers[4].uri(), uri + " geometryTypeFilter='GeometryCollection'" + ) self.assertEqual(sublayers[4].type(), QgsMapLayerType.VectorLayer) self.assertEqual(sublayers[4].providerKey(), "WFS") self.assertEqual(sublayers[4].wkbType(), QgsWkbTypes.Type.GeometryCollection) self.assertEqual(sublayers[4].featureCount(), 20 - (2 + 3 + 4 + 5)) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= @@ -6124,8 +8089,12 @@ def testDeegreeServerWithUnknownGeometryType(self): -"""), 'wb') as f: - f.write(b""" +""", + ), + "wb", + ) as f: + f.write( + b""" 78.3 -65.32 -""") +""" + ) # Test NoGeometry layer - vl = QgsVectorLayer(sublayers[0].uri(), 'test', 'WFS') + vl = QgsVectorLayer(sublayers[0].uri(), "test", "WFS") self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.NoGeometry) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= geometry -"""), 'wb') as f: - f.write(b""" +""", + ), + "wb", + ) as f: + f.write( + b""" 0 -""") +""" + ) got_f = [f for f in vl.getFeatures()] geom = got_f[0].geometry() @@ -6169,12 +8146,14 @@ def testDeegreeServerWithUnknownGeometryType(self): self.assertEqual(vl.featureCount(), sublayers[0].featureCount()) # Test MultiPoint layer - vl = QgsVectorLayer(sublayers[1].uri(), 'test', 'WFS') + vl = QgsVectorLayer(sublayers[1].uri(), "test", "WFS") self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.MultiPoint) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= @@ -6189,8 +8168,12 @@ def testDeegreeServerWithUnknownGeometryType(self): -"""), 'wb') as f: - f.write(b""" +""", + ), + "wb", + ) as f: + f.write( + b""" 78.3 -65.32 -""") +""" + ) got_f = [f for f in vl.getFeatures()] geom = got_f[0].geometry() - assert compareWkt('MultiPoint((-65.32 78.3))', geom.asWkt()), geom.asWkt() + assert compareWkt("MultiPoint((-65.32 78.3))", geom.asWkt()), geom.asWkt() self.assertEqual(vl.featureCount(), sublayers[1].featureCount()) # Test GeometryCollection layer - vl = QgsVectorLayer(sublayers[4].uri(), 'test', 'WFS') + vl = QgsVectorLayer(sublayers[4].uri(), "test", "WFS") self.assertTrue(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.GeometryCollection) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&STARTINDEX=0&COUNT=1&SRSNAME=urn:ogc:def:crs:EPSG::4326&FILTER= @@ -6242,8 +8228,12 @@ def testDeegreeServerWithUnknownGeometryType(self): -"""), 'wb') as f: - f.write(b""" +""", + ), + "wb", + ) as f: + f.write( + b""" 0 12 3 4 5 -""") +""" + ) got_f = [f for f in vl.getFeatures()] geom = got_f[0].geometry() - assert compareWkt('GeometryCollection (Point (0 1),LineString (2 3, 4 5))', geom.asWkt()), geom.asWkt() + assert compareWkt( + "GeometryCollection (Point (0 1),LineString (2 3, 4 5))", geom.asWkt() + ), geom.asWkt() - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= @@ -6288,48 +8283,72 @@ def testDeegreeServerWithUnknownGeometryType(self): -&RESULTTYPE=hits"""), 'wb') as f: - f.write(b""" -""") +""" + ) self.assertEqual(vl.featureCount(), 100) def testDeegreeServerWithUnknownGeometryTypeOnlyCurve(self): - """ https://github.com/qgis/QGIS/issues/49328 """ + """https://github.com/qgis/QGIS/issues/49328""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_layer_unknown_geometry_type_only_curve' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_layer_unknown_geometry_type_only_curve" + ) self._createBaseFilesForTestsDeegreeServerWithUnknownGeometryType(endpoint) - with open(sanitize(endpoint, - '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&RESULTTYPE=hits'), 'wb') as f: - f.write(b""" -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= geometry -&RESULTTYPE=hits"""), 'wb') as f: - f.write(b""" -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= @@ -6344,16 +8363,23 @@ def testDeegreeServerWithUnknownGeometryTypeOnlyCurve(self): -&RESULTTYPE=hits"""), 'wb') as f: - f.write(b""" -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= @@ -6368,16 +8394,23 @@ def testDeegreeServerWithUnknownGeometryTypeOnlyCurve(self): -&RESULTTYPE=hits"""), 'wb') as f: - f.write(b""" -""") +""" + ) - with open(sanitize(endpoint, - """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= + with open( + sanitize( + endpoint, + """?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=my:typename&FILTER= @@ -6392,17 +8425,22 @@ def testDeegreeServerWithUnknownGeometryTypeOnlyCurve(self): -&RESULTTYPE=hits"""), 'wb') as f: - f.write(b""" -""") +""" + ) uri = "url='http://" + endpoint + "' typename='my:typename' version='2.0.0'" - metadata = QgsProviderRegistry.instance().providerMetadata('wfs') + metadata = QgsProviderRegistry.instance().providerMetadata("wfs") sublayers = metadata.querySublayers(uri) self.assertEqual(len(sublayers), 1) @@ -6413,15 +8451,18 @@ def testDeegreeServerWithUnknownGeometryTypeOnlyCurve(self): self.assertEqual(sublayers[0].featureCount(), 20) def testDeegreeServerWithUnknownGeometryTypeErrorSituation(self): - """ https://github.com/qgis/QGIS/issues/49328 """ + """https://github.com/qgis/QGIS/issues/49328""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_layer_unknown_geometry_type_error_situation' + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_layer_unknown_geometry_type_error_situation" + ) self._createBaseFilesForTestsDeegreeServerWithUnknownGeometryType(endpoint) uri = "url='http://" + endpoint + "' typename='my:typename' version='2.0.0'" - metadata = QgsProviderRegistry.instance().providerMetadata('wfs') + metadata = QgsProviderRegistry.instance().providerMetadata("wfs") sublayers = metadata.querySublayers(uri) @@ -6436,53 +8477,161 @@ def testDeegreeServerWithUnknownGeometryTypeErrorSituation(self): def testWFSComplexFeatures(self): """Test reading complex features""" - endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_complex_features' - - shutil.copy(os.path.join(TEST_DATA_DIR, 'provider', 'wfs', 'inspire_complexfeatures', 'getcapabilities.xml'), sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities&VERSION=2.0.0')) - shutil.copy(os.path.join(TEST_DATA_DIR, 'provider', 'wfs', 'inspire_complexfeatures', 'describefeaturetype.xml'), sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=ps:ProtectedSite&TYPENAME=ps:ProtectedSite')) - shutil.copy(os.path.join(TEST_DATA_DIR, 'provider', 'wfs', 'inspire_complexfeatures', 'getfeature_hits.xml'), sanitize(endpoint, '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=ps:ProtectedSite&RESULTTYPE=hits')) - shutil.copy(os.path.join(TEST_DATA_DIR, 'provider', 'wfs', 'inspire_complexfeatures', 'getfeature.xml'), sanitize(endpoint, '?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=ps:ProtectedSite&SRSNAME=urn:ogc:def:crs:EPSG::25833')) + endpoint = ( + self.__class__.basetestpath + + "/fake_qgis_http_endpoint_WFS_complex_features" + ) + + shutil.copy( + os.path.join( + TEST_DATA_DIR, + "provider", + "wfs", + "inspire_complexfeatures", + "getcapabilities.xml", + ), + sanitize(endpoint, "?SERVICE=WFS?REQUEST=GetCapabilities&VERSION=2.0.0"), + ) + shutil.copy( + os.path.join( + TEST_DATA_DIR, + "provider", + "wfs", + "inspire_complexfeatures", + "describefeaturetype.xml", + ), + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=ps:ProtectedSite&TYPENAME=ps:ProtectedSite", + ), + ) + shutil.copy( + os.path.join( + TEST_DATA_DIR, + "provider", + "wfs", + "inspire_complexfeatures", + "getfeature_hits.xml", + ), + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=ps:ProtectedSite&RESULTTYPE=hits", + ), + ) + shutil.copy( + os.path.join( + TEST_DATA_DIR, + "provider", + "wfs", + "inspire_complexfeatures", + "getfeature.xml", + ), + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=ps:ProtectedSite&SRSNAME=urn:ogc:def:crs:EPSG::25833", + ), + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='ps:ProtectedSite' version='2.0.0' skipInitialGetFeature='true'", 'test', 'WFS') + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='ps:ProtectedSite' version='2.0.0' skipInitialGetFeature='true'", + "test", + "WFS", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 1228) self.assertEqual(len(vl.fields()), 26) - self.assertEqual([field.name() for field in vl.fields()], ['id', 'metadataproperty', 'description_href', 'description_title', 'description_nilreason', 'description', 'descriptionreference_href', 'descriptionreference_title', 'descriptionreference_nilreason', 'identifier_codespace', 'identifier', 'name', 'location_location', 'inspireid_identifier_localid', 'inspireid_identifier_namespace', 'inspireid_identifier_versionid_nilreason', 'inspireid_identifier_versionid_nil', 'inspireid_identifier_versionid', 'legalfoundationdate_nilreason', 'legalfoundationdate', 'legalfoundationdocument_nilreason', 'legalfoundationdocument_owns', 'legalfoundationdocument_ci_citation', 'sitedesignation', 'sitename', 'siteprotectionclassification']) + self.assertEqual( + [field.name() for field in vl.fields()], + [ + "id", + "metadataproperty", + "description_href", + "description_title", + "description_nilreason", + "description", + "descriptionreference_href", + "descriptionreference_title", + "descriptionreference_nilreason", + "identifier_codespace", + "identifier", + "name", + "location_location", + "inspireid_identifier_localid", + "inspireid_identifier_namespace", + "inspireid_identifier_versionid_nilreason", + "inspireid_identifier_versionid_nil", + "inspireid_identifier_versionid", + "legalfoundationdate_nilreason", + "legalfoundationdate", + "legalfoundationdocument_nilreason", + "legalfoundationdocument_owns", + "legalfoundationdocument_ci_citation", + "sitedesignation", + "sitename", + "siteprotectionclassification", + ], + ) self.assertEqual(vl.fields()["sitedesignation"].type(), QVariant.String) got_f = [f for f in vl.getFeatures()] self.assertEqual(len(got_f), 1) geom = got_f[0].geometry() self.assertFalse(geom.isNull()) - self.assertEqual(got_f[0]["id"], 'ProtectedSite_FFH_553_DE4546-303') - self.assertEqual(got_f[0]["sitedesignation"], '{"ps:DesignationType":{"ps:designation":{"@xlink:href":"http://inspire.ec.europa.eu/codelist/Natura2000DesignationValue/specialAreaOfConservation"},"ps:designationScheme":{"@xlink:href":"http://inspire.ec.europa.eu/codelist/DesignationSchemeValue/natura2000"}}}') + self.assertEqual(got_f[0]["id"], "ProtectedSite_FFH_553_DE4546-303") + self.assertEqual( + got_f[0]["sitedesignation"], + '{"ps:DesignationType":{"ps:designation":{"@xlink:href":"http://inspire.ec.europa.eu/codelist/Natura2000DesignationValue/specialAreaOfConservation"},"ps:designationScheme":{"@xlink:href":"http://inspire.ec.europa.eu/codelist/DesignationSchemeValue/natura2000"}}}', + ) - vl = QgsVectorLayer("url='http://" + endpoint + "' typename='ps:ProtectedSite' version='2.0.0' skipInitialGetFeature='true'", 'test', 'WFS') - vl.setSubsetString("inspireid_identifier_localid = 'ProtectedSite_FFH_553_DE4546'") + vl = QgsVectorLayer( + "url='http://" + + endpoint + + "' typename='ps:ProtectedSite' version='2.0.0' skipInitialGetFeature='true'", + "test", + "WFS", + ) + vl.setSubsetString( + "inspireid_identifier_localid = 'ProtectedSite_FFH_553_DE4546'" + ) # There's something messy with the ProtectedSite schema referencing http://inspire.ec.europa.eu/schemas/base/3.3 # and also the GeographicalNames schema which references http://inspire.ec.europa.eu/schemas/base/4.0 # There's likely some confusion in the GMLAS driver or QGIS to decide which one to fetch... - for base_version in ('3.3', '4.0'): - if int(QT_VERSION_STR.split('.')[0]) >= 6: + for base_version in ("3.3", "4.0"): + if int(QT_VERSION_STR.split(".")[0]) >= 6: attrs = f'xmlns:base="http://inspire.ec.europa.eu/schemas/base/{base_version}" xmlns:ps="http://inspire.ec.europa.eu/schemas/ps/4.0"' else: attrs = f'xmlns:ps="http://inspire.ec.europa.eu/schemas/ps/4.0" xmlns:base="http://inspire.ec.europa.eu/schemas/base/{base_version}"' - with open(sanitize(endpoint, - f"""?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=ps:ProtectedSite&SRSNAME=urn:ogc:def:crs:EPSG::25833&FILTER= + with open( + sanitize( + endpoint, + f"""?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=ps:ProtectedSite&SRSNAME=urn:ogc:def:crs:EPSG::25833&FILTER= ps:inspireID/base:Identifier/base:localId ProtectedSite_FFH_553_DE4546 -"""), - 'wb') as f: - with open(os.path.join(TEST_DATA_DIR, 'provider', 'wfs', 'inspire_complexfeatures', 'getfeature.xml'), "rb") as f_source: +""", + ), + "wb", + ) as f: + with open( + os.path.join( + TEST_DATA_DIR, + "provider", + "wfs", + "inspire_complexfeatures", + "getfeature.xml", + ), + "rb", + ) as f_source: f.write(f_source.read()) got_f = [f for f in vl.getFeatures()] self.assertEqual(len(got_f), 1) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_provider_wfs_gui.py b/tests/src/python/test_provider_wfs_gui.py index 4eff718f703b..ab672ea961de 100644 --- a/tests/src/python/test_provider_wfs_gui.py +++ b/tests/src/python/test_provider_wfs_gui.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Even Rouault' -__date__ = '2016-03-25' -__copyright__ = 'Copyright 2016, Even Rouault' + +__author__ = "Even Rouault" +__date__ = "2016-03-25" +__copyright__ = "Copyright 2016, Even Rouault" import hashlib import shutil @@ -33,7 +34,13 @@ def sanitize(endpoint, x): if len(endpoint + x) > 256: return endpoint + hashlib.md5(x.encode()).hexdigest() - return endpoint + x.replace('?', '_').replace('&', '_').replace('<', '_').replace('>', '_').replace('"', '_').replace("'", '_').replace(' ', '_').replace(':', '_').replace('/', '_').replace('\n', '_') + return endpoint + x.replace("?", "_").replace("&", "_").replace("<", "_").replace( + ">", "_" + ).replace('"', "_").replace("'", "_").replace(" ", "_").replace(":", "_").replace( + "/", "_" + ).replace( + "\n", "_" + ) def find_window(name): @@ -55,7 +62,7 @@ def setUpClass(cls): QgsSettings().clear() start_app() - cls.basetestpath = tempfile.mkdtemp().replace('\\', '/') + cls.basetestpath = tempfile.mkdtemp().replace("\\", "/") @classmethod def tearDownClass(cls): @@ -97,7 +104,11 @@ def test(self): # if 'TRAVIS_OS_NAME' in os.environ and os.environ['TRAVIS_OS_NAME'] == 'osx': # return - main_dialog = QgsGui.providerGuiRegistry().sourceSelectProviders("WFS")[0].createDataSourceWidget() + main_dialog = ( + QgsGui.providerGuiRegistry() + .sourceSelectProviders("WFS")[0] + .createDataSourceWidget() + ) main_dialog.setProperty("hideDialogs", True) self.assertIsNotNone(main_dialog) @@ -106,7 +117,7 @@ def test(self): btnNew = main_dialog.findChild(QWidget, "btnNew") self.assertIsNotNone(btnNew) QTest.mouseClick(btnNew, Qt.MouseButton.LeftButton) - new_conn = find_window('QgsNewHttpConnectionBase') + new_conn = find_window("QgsNewHttpConnectionBase") self.assertIsNotNone(new_conn) txtName = new_conn.findChild(QLineEdit, "txtName") self.assertIsNotNone(txtName) @@ -127,7 +138,7 @@ def test(self): QApplication.processEvents() # Second attempt for OAPIF request QApplication.processEvents() - error_box = find_window('WFSCapabilitiesErrorBox') + error_box = find_window("WFSCapabilitiesErrorBox") self.assertIsNotNone(error_box) # Close error box error_box.accept() @@ -139,7 +150,9 @@ def test(self): btnEdit = main_dialog.findChild(QWidget, "btnEdit") self.assertIsNotNone(btnEdit) QTest.mouseClick(btnEdit, Qt.MouseButton.LeftButton) - new_conn = find_window('QgsNewHttpConnectionBase',) + new_conn = find_window( + "QgsNewHttpConnectionBase", + ) self.assertIsNotNone(new_conn) txtName = new_conn.findChild(QLineEdit, "txtName") self.assertIsNotNone(txtName) @@ -147,12 +160,19 @@ def test(self): txtUrl = new_conn.findChild(QLineEdit, "txtUrl") self.assertIsNotNone(txtUrl) - endpoint = self.basetestpath + '/fake_qgis_http_endpoint' + endpoint = self.basetestpath + "/fake_qgis_http_endpoint" expected_endpoint = endpoint - if sys.platform == 'win32' and expected_endpoint[1] == ':': + if sys.platform == "win32" and expected_endpoint[1] == ":": expected_endpoint = expected_endpoint[0] + expected_endpoint[2:] - with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0", + ), + "wb", + ) as f: + f.write( + b""" @@ -203,7 +223,8 @@ def test(self): -""") +""" + ) txtUrl.setText("http://" + endpoint) new_conn.accept() @@ -228,14 +249,20 @@ def test(self): self.addWfsLayer_layer_name = None main_dialog.addVectorLayer.connect(self.slotAddWfsLayer) QTest.mouseClick(buttonAdd, Qt.MouseButton.LeftButton) - self.assertEqual(self.addWfsLayer_uri, ' pagingEnabled=\'default\' preferCoordinatesForWfsT11=\'false\' restrictToRequestBBOX=\'1\' srsname=\'EPSG:4326\' typename=\'my:typename\' url=\'' + "http://" + expected_endpoint + '\' version=\'auto\'') - self.assertEqual(self.addWfsLayer_layer_name, 'my:typename') + self.assertEqual( + self.addWfsLayer_uri, + " pagingEnabled='default' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1' srsname='EPSG:4326' typename='my:typename' url='" + + "http://" + + expected_endpoint + + "' version='auto'", + ) + self.assertEqual(self.addWfsLayer_layer_name, "my:typename") # Click on Build Query buttonBuildQuery = self.get_button_build_query(main_dialog) self.assertTrue(buttonBuildQuery.isEnabled()) QTest.mouseClick(buttonBuildQuery, Qt.MouseButton.LeftButton) - error_box = find_window('WFSFeatureTypeErrorBox') + error_box = find_window("WFSFeatureTypeErrorBox") self.assertIsNotNone(error_box) # Close error box error_box.accept() @@ -244,8 +271,15 @@ def test(self): # Click again but with valid DescribeFeatureType - with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename'), 'wb') as f: - f.write(b""" + with open( + sanitize( + endpoint, + "?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAMES=my:typename&TYPENAME=my:typename", + ), + "wb", + ) as f: + f.write( + b""" @@ -260,34 +294,41 @@ def test(self): -""") +""" + ) QTest.mouseClick(buttonBuildQuery, Qt.MouseButton.LeftButton) # Check that the combos are properly initialized - dialog = find_window('QgsSQLComposerDialogBase') + dialog = find_window("QgsSQLComposerDialogBase") self.assertIsNotNone(dialog) mTablesCombo = dialog.findChild(QComboBox, "mTablesCombo") self.assertIsNotNone(mTablesCombo) - self.assertEqual(mTablesCombo.itemText(1), 'typename (Title)') + self.assertEqual(mTablesCombo.itemText(1), "typename (Title)") mColumnsCombo = dialog.findChild(QComboBox, "mColumnsCombo") self.assertIsNotNone(mColumnsCombo) - self.assertEqual(mColumnsCombo.itemText(1), 'intfield (int)') - self.assertEqual(mColumnsCombo.itemText(mColumnsCombo.count() - 2), 'geometryProperty (geometry)') - self.assertEqual(mColumnsCombo.itemText(mColumnsCombo.count() - 1), '*') + self.assertEqual(mColumnsCombo.itemText(1), "intfield (int)") + self.assertEqual( + mColumnsCombo.itemText(mColumnsCombo.count() - 2), + "geometryProperty (geometry)", + ) + self.assertEqual(mColumnsCombo.itemText(mColumnsCombo.count() - 1), "*") mFunctionsCombo = dialog.findChild(QComboBox, "mFunctionsCombo") self.assertIsNotNone(mFunctionsCombo) - self.assertEqual(mFunctionsCombo.itemText(1), 'abs(param: int): int') + self.assertEqual(mFunctionsCombo.itemText(1), "abs(param: int): int") mSpatialPredicatesCombo = dialog.findChild(QComboBox, "mSpatialPredicatesCombo") self.assertIsNotNone(mSpatialPredicatesCombo) - self.assertEqual(mSpatialPredicatesCombo.itemText(1), 'ST_Disjoint(geometry, geometry): boolean') + self.assertEqual( + mSpatialPredicatesCombo.itemText(1), + "ST_Disjoint(geometry, geometry): boolean", + ) mWhereEditor = dialog.findChild(QTextEdit, "mWhereEditor") self.assertIsNotNone(mWhereEditor) - mWhereEditor.setText('1 = 1') + mWhereEditor.setText("1 = 1") dialog.accept() # Wait for object to be destroyed @@ -301,8 +342,14 @@ def test(self): self.addWfsLayer_layer_name = None main_dialog.addVectorLayer.connect(self.slotAddWfsLayer) QTest.mouseClick(buttonAdd, Qt.MouseButton.LeftButton) - self.assertEqual(self.addWfsLayer_uri, ' pagingEnabled=\'default\' preferCoordinatesForWfsT11=\'false\' restrictToRequestBBOX=\'1\' srsname=\'EPSG:4326\' typename=\'my:typename\' url=\'' + "http://" + expected_endpoint + '\' version=\'auto\' sql=SELECT * FROM typename WHERE 1 = 1') - self.assertEqual(self.addWfsLayer_layer_name, 'my:typename') + self.assertEqual( + self.addWfsLayer_uri, + " pagingEnabled='default' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1' srsname='EPSG:4326' typename='my:typename' url='" + + "http://" + + expected_endpoint + + "' version='auto' sql=SELECT * FROM typename WHERE 1 = 1", + ) + self.assertEqual(self.addWfsLayer_layer_name, "my:typename") # main_dialog.setProperty("hideDialogs", None) # main_dialog.exec_() @@ -312,5 +359,5 @@ def slotAddWfsLayer(self, uri, layer_name): self.addWfsLayer_layer_name = layer_name -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_python_repr.py b/tests/src/python/test_python_repr.py index 604774bef7d9..3cdcdbae218d 100644 --- a/tests/src/python/test_python_repr.py +++ b/tests/src/python/test_python_repr.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Denis Rouzaud' -__date__ = '05.06.2018' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Denis Rouzaud" +__date__ = "05.06.2018" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.PyQt.QtCore import QVariant @@ -72,62 +73,77 @@ class TestPython__repr__(QgisTestCase): def testQgsGeometryRepr(self): g = QgsGeometry() - self.assertEqual(g.__repr__(), '') + self.assertEqual(g.__repr__(), "") p = QgsPointXY(123.456, 987.654) g = QgsGeometry.fromPointXY(p) - self.assertTrue(g.__repr__().startswith('')) + self.assertTrue(g.__repr__().startswith("")) self.assertEqual(len(g.__repr__()), 1018) def testQgsPointRepr(self): p = QgsPoint(123.456, 987.654, 100) - self.assertTrue(p.__repr__().startswith('')) + p = QgsReferencedPointXY( + QgsPointXY(123.456, 987.654), QgsCoordinateReferenceSystem("EPSG:4326") + ) + self.assertTrue(p.__repr__().startswith("")) def testQgsCircleRepr(self): c = QgsCircle(QgsPoint(1, 1), 2.0) - self.assertEqual(c.__repr__(), '') + self.assertEqual( + c.__repr__(), + "", + ) def testQgsCircularstringRepr(self): cs = QgsCircularString(QgsPoint(1, 2), QgsPoint(2, 3), QgsPoint(3, 4)) - self.assertEqual(cs.__repr__(), '') + self.assertEqual( + cs.__repr__(), "" + ) def testQgsClassificationRange(self): - c = QgsClassificationRange('from 1 to 2', 1, 2) + c = QgsClassificationRange("from 1 to 2", 1, 2) self.assertEqual(c.__repr__(), "") def testQgsCompoundcurveRepr(self): cs = QgsCircularString(QgsPoint(1, 2), QgsPoint(2, 3), QgsPoint(3, 4)) cc = QgsCompoundCurve() cc.addCurve(cs) - self.assertEqual(cc.__repr__(), '') + self.assertEqual( + cc.__repr__(), + "", + ) def testQgsCurvepolygonRepr(self): cp = QgsCurvePolygon() cs = QgsCircularString(QgsPoint(1, 10), QgsPoint(2, 11), QgsPoint(1, 10)) cp.setExteriorRing(cs) - self.assertEqual(cp.__repr__(), '') + self.assertEqual( + cp.__repr__(), + "", + ) def testQgsEllipseRepr(self): e = QgsEllipse(QgsPoint(1, 2), 2.0, 3.0) - self.assertEqual(e.__repr__(), '') + self.assertEqual( + e.__repr__(), + "", + ) def testQgsLineStringRepr(self): ls = QgsLineString([QgsPoint(10, 2), QgsPoint(10, 1), QgsPoint(5, 1)]) - self.assertEqual(ls.__repr__(), '') + self.assertEqual(ls.__repr__(), "") def testQgsMulticurveRepr(self): mc = QgsMultiCurve() @@ -135,135 +151,219 @@ def testQgsMulticurveRepr(self): mc.addGeometry(cs) cs2 = QgsCircularString(QgsPoint(4, 20), QgsPoint(5, 22), QgsPoint(6, 24)) mc.addGeometry(cs2) - self.assertEqual(mc.__repr__(), '') + self.assertEqual( + mc.__repr__(), + "", + ) def testQgsMultilineStringRepr(self): ml = QgsGeometry.fromMultiPolylineXY( [ - [QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 0), ], - [QgsPointXY(3, 0), QgsPointXY(3, 1), QgsPointXY(5, 1), QgsPointXY(5, 0), QgsPointXY(6, 0), ] + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 0), + ], + [ + QgsPointXY(3, 0), + QgsPointXY(3, 1), + QgsPointXY(5, 1), + QgsPointXY(5, 0), + QgsPointXY(6, 0), + ], ] ) - self.assertEqual(ml.constGet().__repr__(), '') + self.assertEqual( + ml.constGet().__repr__(), + "", + ) def testQgsMultiPointRepr(self): wkt = "MultiPoint ((10 30),(40 20),(30 10),(20 10))" mp = QgsGeometry.fromWkt(wkt) - self.assertEqual(mp.constGet().__repr__(), '') + self.assertEqual( + mp.constGet().__repr__(), + "", + ) def testQgsMultipolygonRepr(self): - mp = QgsGeometry.fromMultiPolygonXY([ - [[QgsPointXY(1, 1), - QgsPointXY(2, 2), - QgsPointXY(1, 2), - QgsPointXY(1, 1)]], - [[QgsPointXY(2, 2), - QgsPointXY(3, 3), - QgsPointXY(3, 1), - QgsPointXY(2, 2)]] - ]) - self.assertEqual(mp.constGet().__repr__(), '') + mp = QgsGeometry.fromMultiPolygonXY( + [ + [ + [ + QgsPointXY(1, 1), + QgsPointXY(2, 2), + QgsPointXY(1, 2), + QgsPointXY(1, 1), + ] + ], + [ + [ + QgsPointXY(2, 2), + QgsPointXY(3, 3), + QgsPointXY(3, 1), + QgsPointXY(2, 2), + ] + ], + ] + ) + self.assertEqual( + mp.constGet().__repr__(), + "", + ) def testQgsPolygonRepr(self): p = QgsGeometry.fromPolygonXY( - [[QgsPointXY(0, 0), - QgsPointXY(2, 0), - QgsPointXY(2, 2), - QgsPointXY(0, 2), - QgsPointXY(0, 0)]]) - self.assertEqual(p.constGet().__repr__(), '') + [ + [ + QgsPointXY(0, 0), + QgsPointXY(2, 0), + QgsPointXY(2, 2), + QgsPointXY(0, 2), + QgsPointXY(0, 0), + ] + ] + ) + self.assertEqual( + p.constGet().__repr__(), "" + ) def testQgsRectangleRepr(self): r = QgsRectangle(1, 2, 3, 4) - self.assertEqual(r.__repr__(), '') + self.assertEqual(r.__repr__(), "") r = QgsRectangle() - self.assertEqual(r.__repr__(), '') + self.assertEqual(r.__repr__(), "") def testQgsReferencedRectangleRepr(self): - r = QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('EPSG:4326')) - self.assertEqual(r.__repr__(), '') + r = QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:4326") + ) + self.assertEqual(r.__repr__(), "") def testQgsReferencedGeometryRepr(self): - g = QgsReferencedGeometry(QgsGeometry.fromPointXY(QgsPointXY(1, 2)), QgsCoordinateReferenceSystem('EPSG:4326')) - self.assertEqual(g.__repr__(), '') + g = QgsReferencedGeometry( + QgsGeometry.fromPointXY(QgsPointXY(1, 2)), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + self.assertEqual( + g.__repr__(), "" + ) def testQgsCoordinateReferenceSystem(self): crs = QgsCoordinateReferenceSystem() - self.assertEqual(crs.__repr__(), '') - crs = QgsCoordinateReferenceSystem('EPSG:4326') - self.assertEqual(crs.__repr__(), '') + self.assertEqual(crs.__repr__(), "") + crs = QgsCoordinateReferenceSystem("EPSG:4326") + self.assertEqual(crs.__repr__(), "") crs.setCoordinateEpoch(2021.3) - self.assertEqual(crs.__repr__(), '') - crs = QgsCoordinateReferenceSystem('EPSG:3111') - self.assertEqual(crs.__repr__(), '') + self.assertEqual( + crs.__repr__(), "" + ) + crs = QgsCoordinateReferenceSystem("EPSG:3111") + self.assertEqual(crs.__repr__(), "") def testQgsCoordinateTransform(self): xform = QgsCoordinateTransform() - self.assertEqual(xform.__repr__(), '') - xform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem(), QgsProject.instance()) - self.assertEqual(xform.__repr__(), '') - xform = QgsCoordinateTransform(QgsCoordinateReferenceSystem(), QgsCoordinateReferenceSystem('EPSG:4326'), QgsProject.instance()) - self.assertEqual(xform.__repr__(), '') - xform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:3111'), QgsCoordinateReferenceSystem('EPSG:4326'), QgsProject.instance()) - self.assertEqual(xform.__repr__(), '') + self.assertEqual(xform.__repr__(), "") + xform = QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem(), + QgsProject.instance(), + ) + self.assertEqual( + xform.__repr__(), "" + ) + xform = QgsCoordinateTransform( + QgsCoordinateReferenceSystem(), + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsProject.instance(), + ) + self.assertEqual( + xform.__repr__(), "" + ) + xform = QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsProject.instance(), + ) + self.assertEqual( + xform.__repr__(), "" + ) def testQgsVector(self): v = QgsVector(1, 2) - self.assertEqual(v.__repr__(), '') + self.assertEqual(v.__repr__(), "") v = QgsVector3D(1, 2, 3) - self.assertEqual(v.__repr__(), '') + self.assertEqual(v.__repr__(), "") def testQgsExpressionRepr(self): - e = QgsExpression('my expression') + e = QgsExpression("my expression") self.assertEqual(e.__repr__(), "") def testQgsFieldRepr(self): - f = QgsField('field_name', QVariant.Double, 'double') + f = QgsField("field_name", QVariant.Double, "double") self.assertEqual(f.__repr__(), "") def testQgsErrorRepr(self): - e = QgsError('you done wrong son', 'dad') + e = QgsError("you done wrong son", "dad") self.assertEqual(e.__repr__(), "") def testQgsMimeDataUri(self): d = QgsMimeDataUtils.Uri() - d.uri = 'my_uri' - d.providerKey = 'my_provider' + d.uri = "my_uri" + d.providerKey = "my_provider" self.assertEqual(d.__repr__(), "") def testQgsMapLayerRepr(self): vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk', - 'QGIS搖滾', 'memory') + "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk", + "QGIS搖滾", + "memory", + ) self.assertEqual(vl.__repr__(), "") - rl = QgsRasterLayer('', 'QGIS搖滾', 'gdal') + rl = QgsRasterLayer("", "QGIS搖滾", "gdal") self.assertEqual(rl.__repr__(), "") - ml = QgsMeshLayer('', 'QGIS搖滾', 'mdal') + ml = QgsMeshLayer("", "QGIS搖滾", "mdal") self.assertEqual(ml.__repr__(), "") - al = QgsAnnotationLayer('QGIS搖滾', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) + al = QgsAnnotationLayer( + "QGIS搖滾", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) self.assertEqual(al.__repr__(), "") - pcl = QgsPointCloudLayer('', 'QGIS搖滾', 'pc') + pcl = QgsPointCloudLayer("", "QGIS搖滾", "pc") self.assertEqual(pcl.__repr__(), "") - vtl = QgsVectorTileLayer('', 'QGIS搖滾') + vtl = QgsVectorTileLayer("", "QGIS搖滾") self.assertEqual(vtl.__repr__(), "") def testQgsProjectRepr(self): p = QgsProject() self.assertEqual(p.__repr__(), "") - p.setFileName('/home/test/my_project.qgs') + p.setFileName("/home/test/my_project.qgs") self.assertEqual(p.__repr__(), "") - self.assertEqual(QgsProject.instance().__repr__(), "") - QgsProject.instance().setFileName('/home/test/my_project.qgs') - self.assertEqual(QgsProject.instance().__repr__(), "") + self.assertEqual( + QgsProject.instance().__repr__(), "" + ) + QgsProject.instance().setFileName("/home/test/my_project.qgs") + self.assertEqual( + QgsProject.instance().__repr__(), + "", + ) def testQgsBookmark(self): b = QgsBookmark() self.assertEqual(b.__repr__(), "") - b.setName('test bookmark') + b.setName("test bookmark") self.assertEqual(b.__repr__(), "") - b.setExtent(QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('EPSG:3111'))) - self.assertEqual(b.__repr__(), "") + b.setExtent( + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3111") + ) + ) + self.assertEqual( + b.__repr__(), "" + ) def testQgsLayoutPoint(self): b = QgsLayoutPoint(1, 2, QgsUnitTypes.LayoutUnit.LayoutInches) @@ -278,77 +378,109 @@ def testQgsLayoutSize(self): self.assertEqual(b.__repr__(), "") def testQgsConditionalStyle(self): - b = QgsConditionalStyle('@value > 20') + b = QgsConditionalStyle("@value > 20") self.assertEqual(b.__repr__(), " 20>") - b.setName('test name') - self.assertEqual(b.__repr__(), " 20)>") + b.setName("test name") + self.assertEqual( + b.__repr__(), " 20)>" + ) def testQgsTableCell(self): - b = QgsTableCell('test') + b = QgsTableCell("test") self.assertEqual(b.__repr__(), "") b.setContent(5) self.assertEqual(b.__repr__(), "") def testQgsProperty(self): p = QgsProperty.fromValue(5) - self.assertEqual(p.__repr__(), '') - p = QgsProperty.fromField('my_field') - self.assertEqual(p.__repr__(), '') - p = QgsProperty.fromExpression('5*5 || \'a\'') - self.assertEqual(p.__repr__(), '') + self.assertEqual(p.__repr__(), "") + p = QgsProperty.fromField("my_field") + self.assertEqual(p.__repr__(), "") + p = QgsProperty.fromExpression("5*5 || 'a'") + self.assertEqual(p.__repr__(), "") p = QgsProperty.fromValue(5, False) - self.assertEqual(p.__repr__(), '') - p = QgsProperty.fromField('my_field', False) - self.assertEqual(p.__repr__(), '') - p = QgsProperty.fromExpression('5*5 || \'a\'', False) - self.assertEqual(p.__repr__(), '') + self.assertEqual(p.__repr__(), "") + p = QgsProperty.fromField("my_field", False) + self.assertEqual(p.__repr__(), "") + p = QgsProperty.fromExpression("5*5 || 'a'", False) + self.assertEqual( + p.__repr__(), "" + ) p = QgsProperty() - self.assertEqual(p.__repr__(), '') + self.assertEqual(p.__repr__(), "") def testQgsVertexId(self): v = QgsVertexId() - self.assertEqual(v.__repr__(), '') + self.assertEqual(v.__repr__(), "") v = QgsVertexId(1, 2, 3) - self.assertEqual(v.__repr__(), '') + self.assertEqual(v.__repr__(), "") v = QgsVertexId(1, 2, 3, _type=QgsVertexId.VertexType.CurveVertex) - self.assertEqual(v.__repr__(), '') + self.assertEqual(v.__repr__(), "") def testProviderMetadata(self): - self.assertEqual(QgsProviderRegistry.instance().providerMetadata('ogr').__repr__(), '') + self.assertEqual( + QgsProviderRegistry.instance().providerMetadata("ogr").__repr__(), + "", + ) def testDataSourceUri(self): ds = QgsDataSourceUri() - ds.setConnection(aHost='my_host', aPort='2322', aDatabase='my_db', aUsername='user', aPassword='pw') - self.assertEqual(ds.__repr__(), "") + ds.setConnection( + aHost="my_host", + aPort="2322", + aDatabase="my_db", + aUsername="user", + aPassword="pw", + ) + self.assertEqual( + ds.__repr__(), + "", + ) def testDoubleRange(self): self.assertEqual(QgsDoubleRange(1, 10).__repr__(), "") - self.assertEqual(QgsDoubleRange(1, 10, False).__repr__(), - "") - self.assertEqual(QgsDoubleRange(1, 10, True, False).__repr__(), - "") + self.assertEqual( + QgsDoubleRange(1, 10, False).__repr__(), "" + ) + self.assertEqual( + QgsDoubleRange(1, 10, True, False).__repr__(), "" + ) def testIntRange(self): self.assertEqual(QgsIntRange(1, 10).__repr__(), "") - self.assertEqual(QgsIntRange(1, 10, False).__repr__(), - "") - self.assertEqual(QgsIntRange(1, 10, True, False).__repr__(), - "") + self.assertEqual(QgsIntRange(1, 10, False).__repr__(), "") + self.assertEqual( + QgsIntRange(1, 10, True, False).__repr__(), "" + ) def testDefaultValue(self): - self.assertEqual(QgsDefaultValue().__repr__(), '') - self.assertEqual(QgsDefaultValue('1+3').__repr__(), '') + self.assertEqual(QgsDefaultValue().__repr__(), "") + self.assertEqual(QgsDefaultValue("1+3").__repr__(), "") def testRendererRange(self): - self.assertEqual(QgsRendererRange().__repr__(), '') - self.assertEqual(QgsRendererRange(1.0, 2.0, None, None).__repr__(), '') - self.assertEqual(QgsRendererRange(1.0, 2.0, None, 'my class').__repr__(), '') + self.assertEqual(QgsRendererRange().__repr__(), "") + self.assertEqual( + QgsRendererRange(1.0, 2.0, None, None).__repr__(), + "", + ) + self.assertEqual( + QgsRendererRange(1.0, 2.0, None, "my class").__repr__(), + "", + ) def testRendererCategory(self): - self.assertEqual(QgsRendererCategory().__repr__(), '') - self.assertEqual(QgsRendererCategory(5, None, None).__repr__(), '') - self.assertEqual(QgsRendererCategory('abc', None, None).__repr__(), '') - self.assertEqual(QgsRendererCategory('abc', None, 'my class').__repr__(), '') + self.assertEqual(QgsRendererCategory().__repr__(), "") + self.assertEqual( + QgsRendererCategory(5, None, None).__repr__(), "" + ) + self.assertEqual( + QgsRendererCategory("abc", None, None).__repr__(), + "", + ) + self.assertEqual( + QgsRendererCategory("abc", None, "my class").__repr__(), + "", + ) if __name__ == "__main__": diff --git a/tests/src/python/test_python_utils.py b/tests/src/python/test_python_utils.py index 072cc429c542..1221e1124869 100644 --- a/tests/src/python/test_python_utils.py +++ b/tests/src/python/test_python_utils.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Germán Carrillo' -__date__ = '31.8.2021' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Germán Carrillo" +__date__ = "31.8.2021" +__copyright__ = "Copyright 2021, The QGIS Project" import os @@ -43,13 +44,21 @@ def test_update_available_plugins(self): def test_sort_by_dependency(self): plugins = ["dependent_plugin_2", "dependent_plugin_1", "PluginPathTest"] - plugin_name_map = {"Dependent plugin 2": "dependent_plugin_2", "Dependent plugin 1": "dependent_plugin_1", "plugin path test": "PluginPathTest"} + plugin_name_map = { + "Dependent plugin 2": "dependent_plugin_2", + "Dependent plugin 1": "dependent_plugin_1", + "plugin path test": "PluginPathTest", + } utils.plugin_paths = [os.path.join(unitTestDataPath(), "test_plugin_path")] utils.updateAvailablePlugins() # Required to have a proper plugins_metadata_parser sorted_plugins = utils._sortAvailablePlugins(plugins, plugin_name_map) - expected_sorted_plugins = ["PluginPathTest", "dependent_plugin_1", "dependent_plugin_2"] + expected_sorted_plugins = [ + "PluginPathTest", + "dependent_plugin_1", + "dependent_plugin_2", + ] self.assertEqual(sorted_plugins, expected_sorted_plugins) def test_sort_by_dependency_move_plugin(self): @@ -62,7 +71,18 @@ def test_sort_by_dependency_move_plugin(self): for plugin in plugins: utils._move_plugin(plugin, deps, visited, sorted_plugins) - expected_sorted_plugins = ["MSP", "P1", "P2", "MB", "A", "LA", "LPA", "P3", "LAA", "P4"] + expected_sorted_plugins = [ + "MSP", + "P1", + "P2", + "MB", + "A", + "LA", + "LPA", + "P3", + "LAA", + "P4", + ] self.assertEqual(sorted_plugins, expected_sorted_plugins) diff --git a/tests/src/python/test_qgs3dmaterials.py b/tests/src/python/test_qgs3dmaterials.py index 21605bdb75ee..fb4d0379a1d5 100644 --- a/tests/src/python/test_qgs3dmaterials.py +++ b/tests/src/python/test_qgs3dmaterials.py @@ -6,19 +6,16 @@ (at your option) any later version. """ - from qgis.PyQt.QtGui import QColor from qgis.PyQt.QtXml import QDomDocument -from qgis.core import ( - QgsReadWriteContext -) +from qgis.core import QgsReadWriteContext from qgis._3d import ( QgsSimpleLineMaterialSettings, QgsPhongMaterialSettings, QgsGoochMaterialSettings, QgsMetalRoughMaterialSettings, QgsPhongTexturedMaterialSettings, - QgsNullMaterialSettings + QgsNullMaterialSettings, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -36,8 +33,7 @@ def test_getters_setters(self): settings = QgsSimpleLineMaterialSettings() # Test default value - self.assertEqual(settings.ambient(), - QColor.fromRgbF(0.1, 0.1, 0.1, 1.0)) + self.assertEqual(settings.ambient(), QColor.fromRgbF(0.1, 0.1, 0.1, 1.0)) # Test setter/getter settings.setAmbient(QColor(255, 0, 0)) @@ -101,12 +97,9 @@ def test_getters_setters(self): settings = QgsPhongMaterialSettings() # Test default values - self.assertEqual(settings.ambient(), - QColor.fromRgbF(0.1, 0.1, 0.1, 1.0)) - self.assertIn(settings.diffuse().name(), - ('#b2b2b2', '#b3b3b3')) - self.assertEqual(settings.specular(), - QColor.fromRgbF(1.0, 1.0, 1.0, 1.0)) + self.assertEqual(settings.ambient(), QColor.fromRgbF(0.1, 0.1, 0.1, 1.0)) + self.assertIn(settings.diffuse().name(), ("#b2b2b2", "#b3b3b3")) + self.assertEqual(settings.specular(), QColor.fromRgbF(1.0, 1.0, 1.0, 1.0)) self.assertEqual(settings.shininess(), 0.0) self.assertEqual(settings.opacity(), 1.0) self.assertEqual(settings.ambientCoefficient(), 1.0) @@ -248,10 +241,8 @@ def test_getters_setters(self): # Test default values self.assertEqual(settings.warm(), QColor(107, 0, 107)) self.assertEqual(settings.cool(), QColor(255, 130, 0)) - self.assertIn(settings.diffuse().name(), - ('#b2b2b2', '#b3b3b3')) - self.assertEqual(settings.specular(), - QColor.fromRgbF(1.0, 1.0, 1.0, 1.0)) + self.assertIn(settings.diffuse().name(), ("#b2b2b2", "#b3b3b3")) + self.assertEqual(settings.specular(), QColor.fromRgbF(1.0, 1.0, 1.0, 1.0)) self.assertEqual(settings.shininess(), 100.0) self.assertEqual(settings.alpha(), 0.25) self.assertEqual(settings.beta(), 0.5) @@ -377,8 +368,7 @@ def test_getters_setters(self): settings = QgsMetalRoughMaterialSettings() # Test default values - self.assertEqual(settings.baseColor(), - QColor.fromRgbF(0.5, 0.5, 0.5, 1.0)) + self.assertEqual(settings.baseColor(), QColor.fromRgbF(0.5, 0.5, 0.5, 1.0)) self.assertEqual(settings.metalness(), 0.0) self.assertEqual(settings.roughness(), 0.0) @@ -459,12 +449,10 @@ def test_getters_setters(self): settings = QgsPhongTexturedMaterialSettings() # Test default values - self.assertEqual(settings.ambient(), - QColor.fromRgbF(0.1, 0.1, 0.1, 1.0)) - self.assertEqual(settings.specular(), - QColor.fromRgbF(1.0, 1.0, 1.0, 1.0)) + self.assertEqual(settings.ambient(), QColor.fromRgbF(0.1, 0.1, 0.1, 1.0)) + self.assertEqual(settings.specular(), QColor.fromRgbF(1.0, 1.0, 1.0, 1.0)) self.assertEqual(settings.shininess(), 0.0) - self.assertEqual(settings.diffuseTexturePath(), '') + self.assertEqual(settings.diffuseTexturePath(), "") self.assertEqual(settings.textureScale(), 1.0) self.assertEqual(settings.textureRotation(), 0.0) self.assertEqual(settings.opacity(), 1.0) @@ -479,8 +467,8 @@ def test_getters_setters(self): settings.setShininess(0.5) self.assertEqual(settings.shininess(), 0.5) - settings.setDiffuseTexturePath('/path/to/texture.png') - self.assertEqual(settings.diffuseTexturePath(), '/path/to/texture.png') + settings.setDiffuseTexturePath("/path/to/texture.png") + self.assertEqual(settings.diffuseTexturePath(), "/path/to/texture.png") settings.setTextureScale(2.0) self.assertEqual(settings.textureScale(), 2.0) @@ -496,7 +484,7 @@ def test_clone(self): settings.setAmbient(QColor(255, 0, 0)) settings.setSpecular(QColor(0, 0, 255)) settings.setShininess(0.5) - settings.setDiffuseTexturePath('/path/to/texture.png') + settings.setDiffuseTexturePath("/path/to/texture.png") settings.setTextureScale(2.0) settings.setTextureRotation(45.0) settings.setOpacity(0.7) @@ -506,7 +494,7 @@ def test_clone(self): self.assertEqual(cloned.ambient(), QColor(255, 0, 0)) self.assertEqual(cloned.specular(), QColor(0, 0, 255)) self.assertEqual(cloned.shininess(), 0.5) - self.assertEqual(cloned.diffuseTexturePath(), '/path/to/texture.png') + self.assertEqual(cloned.diffuseTexturePath(), "/path/to/texture.png") self.assertEqual(cloned.textureScale(), 2.0) self.assertEqual(cloned.textureRotation(), 45.0) self.assertEqual(cloned.opacity(), 0.7) @@ -532,9 +520,9 @@ def test_equality(self): settings1.setShininess(0.5) self.assertEqual(settings1, settings2) - settings2.setDiffuseTexturePath('/path/to/texture.png') + settings2.setDiffuseTexturePath("/path/to/texture.png") self.assertNotEqual(settings1, settings2) - settings1.setDiffuseTexturePath('/path/to/texture.png') + settings1.setDiffuseTexturePath("/path/to/texture.png") self.assertEqual(settings1, settings2) settings2.setTextureScale(2.0) @@ -569,7 +557,7 @@ def test_xml_roundtrip(self): settings.setAmbient(QColor(255, 0, 0)) settings.setSpecular(QColor(0, 0, 255)) settings.setShininess(0.5) - settings.setDiffuseTexturePath('/path/to/texture.png') + settings.setDiffuseTexturePath("/path/to/texture.png") settings.setTextureScale(2.0) settings.setTextureRotation(45.0) settings.setOpacity(0.7) @@ -587,10 +575,10 @@ def test_requires_texture_coordinates(self): settings = QgsPhongTexturedMaterialSettings() self.assertFalse(settings.requiresTextureCoordinates()) - settings.setDiffuseTexturePath('/path/to/texture.png') + settings.setDiffuseTexturePath("/path/to/texture.png") self.assertTrue(settings.requiresTextureCoordinates()) - settings.setDiffuseTexturePath('') + settings.setDiffuseTexturePath("") self.assertFalse(settings.requiresTextureCoordinates()) @@ -620,5 +608,5 @@ def test_xml_roundtrip(self): self.assertTrue(settings.equals(settings2)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsaction.py b/tests/src/python/test_qgsaction.py index b833d95bac6a..98398d81bccd 100644 --- a/tests/src/python/test_qgsaction.py +++ b/tests/src/python/test_qgsaction.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '24/11/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "24/11/2021" +__copyright__ = "Copyright 2021, The QGIS Project" import os from functools import partial @@ -42,21 +43,31 @@ def test_post_urlencoded_action(self): def _req_logger(self, params): self.body = bytes(params.content()) - QgsNetworkAccessManager.instance().requestAboutToBeCreated[QgsNetworkRequestParameters].connect(partial(_req_logger, self)) + QgsNetworkAccessManager.instance().requestAboutToBeCreated[ + QgsNetworkRequestParameters + ].connect(partial(_req_logger, self)) temp_dir = QTemporaryDir() temp_path = temp_dir.path() - temp_file = os.path.join(temp_path, 'urlencoded.txt') - - action = QgsAction(QgsAction.ActionType.SubmitUrlEncoded, 'url_encoded', "http://fake_qgis_http_endpoint" + temp_file + r"?[% url_encode(map('a&+b', 'a and plus b', 'a=b', 'a equals b')) %]") + temp_file = os.path.join(temp_path, "urlencoded.txt") + + action = QgsAction( + QgsAction.ActionType.SubmitUrlEncoded, + "url_encoded", + "http://fake_qgis_http_endpoint" + + temp_file + + r"?[% url_encode(map('a&+b', 'a and plus b', 'a=b', 'a equals b')) %]", + ) ctx = QgsExpressionContext() action.run(ctx) while not self.body: QgsApplication.instance().processEvents() - self.assertEqual(self.body, br"a%26%2Bb=a%20and%20plus%20b&a%3Db=a%20equals%20b") + self.assertEqual( + self.body, rb"a%26%2Bb=a%20and%20plus%20b&a%3Db=a%20equals%20b" + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsactionmanager.py b/tests/src/python/test_qgsactionmanager.py index 9105c094e538..20f5a20b573d 100644 --- a/tests/src/python/test_qgsactionmanager.py +++ b/tests/src/python/test_qgsactionmanager.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '28/05/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "28/05/2016" +__copyright__ = "Copyright 2016, The QGIS Project" import os import platform @@ -36,15 +37,18 @@ class TestQgsActionManager(QgisTestCase): @classmethod def setUpClass(cls): super().setUpClass() - cls.layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=flddate:datetime", - "test_layer", "memory") + cls.layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer&field=flddate:datetime", + "test_layer", + "memory", + ) cls.manager = QgsActionManager(cls.layer) # make a little script to aid in recording action outputs # this is just a little python file which writes out its arguments to a text file - cls.run_script_file = os.path.join(QDir.tempPath(), 'run_action.py') - with open(cls.run_script_file, 'w') as s: - s.write('import sys\n') + cls.run_script_file = os.path.join(QDir.tempPath(), "run_action.py") + with open(cls.run_script_file, "w") as s: + s.write("import sys\n") s.write('open(sys.argv[1], "w").write(" ".join(sys.argv[2:]))\n') @classmethod @@ -62,54 +66,66 @@ def get_temp_filename(self): return tmpName def create_action(self, dest_file, text_to_write): - """ returns an action which writes some output to a file """ - return f'python {self.run_script_file} {dest_file} {text_to_write}' + """returns an action which writes some output to a file""" + return f"python {self.run_script_file} {dest_file} {text_to_write}" def testLayer(self): self.assertEqual(self.manager.layer(), self.layer) def testAddAction(self): - """ Test adding actions """ + """Test adding actions""" # should be empty to start with self.assertEqual(self.manager.actions(), []) # add an action - action1 = QgsAction(QgsAction.ActionType.GenericPython, 'Test Action', 'i=1') + action1 = QgsAction(QgsAction.ActionType.GenericPython, "Test Action", "i=1") self.manager.addAction(action1) self.assertEqual(len(self.manager.actions()), 1) - self.assertEqual(self.manager.actions()[0].type(), QgsAction.ActionType.GenericPython) - self.assertEqual(self.manager.actions()[0].name(), 'Test Action') - self.assertEqual(self.manager.actions()[0].command(), 'i=1') + self.assertEqual( + self.manager.actions()[0].type(), QgsAction.ActionType.GenericPython + ) + self.assertEqual(self.manager.actions()[0].name(), "Test Action") + self.assertEqual(self.manager.actions()[0].command(), "i=1") # add another action - action2 = QgsAction(QgsAction.ActionType.Windows, 'Test Action2', 'i=2') + action2 = QgsAction(QgsAction.ActionType.Windows, "Test Action2", "i=2") self.manager.addAction(action2) self.assertEqual(len(self.manager.actions()), 2) - self.assertEqual(self.manager.action(action2.id()).type(), QgsAction.ActionType.Windows) - self.assertEqual(self.manager.action(action2.id()).name(), 'Test Action2') - self.assertEqual(self.manager.action(action2.id()).command(), 'i=2') - - id3 = self.manager.addAction(QgsAction.ActionType.Generic, 'Test Action3', 'i=3') + self.assertEqual( + self.manager.action(action2.id()).type(), QgsAction.ActionType.Windows + ) + self.assertEqual(self.manager.action(action2.id()).name(), "Test Action2") + self.assertEqual(self.manager.action(action2.id()).command(), "i=2") + + id3 = self.manager.addAction( + QgsAction.ActionType.Generic, "Test Action3", "i=3" + ) self.assertEqual(len(self.manager.actions()), 3) self.assertEqual(self.manager.action(id3).type(), QgsAction.ActionType.Generic) - self.assertEqual(self.manager.action(id3).name(), 'Test Action3') - self.assertEqual(self.manager.action(id3).command(), 'i=3') + self.assertEqual(self.manager.action(id3).name(), "Test Action3") + self.assertEqual(self.manager.action(id3).command(), "i=3") def testRemoveActions(self): - """ test removing actions """ + """test removing actions""" # add an action - self.manager.addAction(QgsAction.ActionType.GenericPython, 'test_action', 'i=1') + self.manager.addAction(QgsAction.ActionType.GenericPython, "test_action", "i=1") # clear the manager and check that it's empty self.manager.clearActions() self.assertEqual(self.manager.actions(), []) # add some actions - id1 = self.manager.addAction(QgsAction.ActionType.GenericPython, 'test_action', 'i=1') - id2 = self.manager.addAction(QgsAction.ActionType.GenericPython, 'test_action2', 'i=2') - id3 = self.manager.addAction(QgsAction.ActionType.GenericPython, 'test_action3', 'i=3') + id1 = self.manager.addAction( + QgsAction.ActionType.GenericPython, "test_action", "i=1" + ) + id2 = self.manager.addAction( + QgsAction.ActionType.GenericPython, "test_action2", "i=2" + ) + id3 = self.manager.addAction( + QgsAction.ActionType.GenericPython, "test_action3", "i=3" + ) # remove non-existent action self.manager.removeAction(QUuid.createUuid()) @@ -117,88 +133,116 @@ def testRemoveActions(self): # remove them one by one self.manager.removeAction(id2) self.assertEqual(len(self.manager.actions()), 2) - self.assertEqual(self.manager.action(id1).name(), 'test_action') - self.assertEqual(self.manager.action(id3).name(), 'test_action3') + self.assertEqual(self.manager.action(id1).name(), "test_action") + self.assertEqual(self.manager.action(id3).name(), "test_action3") self.manager.removeAction(id1) self.assertEqual(len(self.manager.actions()), 1) - self.assertEqual(self.manager.action(id3).name(), 'test_action3') + self.assertEqual(self.manager.action(id3).name(), "test_action3") self.manager.removeAction(id3) self.assertEqual(len(self.manager.actions()), 0) def testDefaultAction(self): - """ test default action for layer""" + """test default action for layer""" self.manager.clearActions() - action1 = QgsAction(QgsAction.ActionType.GenericPython, 'test_action', '', 'i=1', False, actionScopes={'Feature'}) + action1 = QgsAction( + QgsAction.ActionType.GenericPython, + "test_action", + "", + "i=1", + False, + actionScopes={"Feature"}, + ) self.manager.addAction(action1) - action2 = QgsAction(QgsAction.ActionType.GenericPython, 'test_action2', 'i=2') + action2 = QgsAction(QgsAction.ActionType.GenericPython, "test_action2", "i=2") self.manager.addAction(action2) # initially should be not set - self.assertFalse(self.manager.defaultAction('Feature').isValid()) + self.assertFalse(self.manager.defaultAction("Feature").isValid()) # set bad default action - self.manager.setDefaultAction('Feature', QUuid.createUuid()) - self.assertFalse(self.manager.defaultAction('Feature').isValid()) + self.manager.setDefaultAction("Feature", QUuid.createUuid()) + self.assertFalse(self.manager.defaultAction("Feature").isValid()) # set good default action - self.manager.setDefaultAction('Feature', action1.id()) - self.assertTrue(self.manager.defaultAction('Feature').isValid()) - self.assertEqual(self.manager.defaultAction('Feature').id(), action1.id()) - self.assertNotEqual(self.manager.defaultAction('Feature').id(), action2.id()) + self.manager.setDefaultAction("Feature", action1.id()) + self.assertTrue(self.manager.defaultAction("Feature").isValid()) + self.assertEqual(self.manager.defaultAction("Feature").id(), action1.id()) + self.assertNotEqual(self.manager.defaultAction("Feature").id(), action2.id()) # if default action is removed, should be reset to -1 self.manager.clearActions() - self.assertFalse(self.manager.defaultAction('Feature').isValid()) + self.assertFalse(self.manager.defaultAction("Feature").isValid()) def check_action_result(self, temp_file): with open(temp_file) as result: output = result.read() return output - @QgisTestCase.expectedFailure(platform.system() != 'Linux') - @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'), 'Test is flaky on Travis environment') + @QgisTestCase.expectedFailure(platform.system() != "Linux") + @unittest.skipIf( + os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), + "Test is flaky on Travis environment", + ) def testDoAction(self): - """ test running action """ + """test running action""" self.manager.clearActions() # simple action temp_file = self.get_temp_filename() - id1 = self.manager.addAction(QgsAction.ActionType.Unix, 'test_action', self.create_action(temp_file, 'test output')) + id1 = self.manager.addAction( + QgsAction.ActionType.Unix, + "test_action", + self.create_action(temp_file, "test output"), + ) fields = QgsFields() - fields.append(QgsField('my_field')) - fields.append(QgsField('my_other_field')) + fields.append(QgsField("my_field")) + fields.append(QgsField("my_other_field")) f = QgsFeature(fields, 1) - f.setAttributes([5, 'val']) + f.setAttributes([5, "val"]) c = QgsExpressionContext() self.manager.doAction(id1, f, c) time.sleep(0.5) - self.assertEqual(self.check_action_result(temp_file), 'test output') + self.assertEqual(self.check_action_result(temp_file), "test output") # action with substitutions temp_file = self.get_temp_filename() - id2 = self.manager.addAction(QgsAction.ActionType.Unix, 'test_action', self.create_action(temp_file, 'test [% $id %] output [% @layer_name %]')) + id2 = self.manager.addAction( + QgsAction.ActionType.Unix, + "test_action", + self.create_action(temp_file, "test [% $id %] output [% @layer_name %]"), + ) self.manager.doAction(id2, f, c) time.sleep(0.5) - self.assertEqual(self.check_action_result(temp_file), 'test 1 output test_layer') + self.assertEqual( + self.check_action_result(temp_file), "test 1 output test_layer" + ) # test doAction using field variant temp_file = self.get_temp_filename() - id3 = self.manager.addAction(QgsAction.ActionType.Unix, 'test_action', - self.create_action(temp_file, 'test : [% @field_index %] : [% @field_name %] : [% @field_value%]')) + id3 = self.manager.addAction( + QgsAction.ActionType.Unix, + "test_action", + self.create_action( + temp_file, + "test : [% @field_index %] : [% @field_name %] : [% @field_value%]", + ), + ) self.manager.doActionFeature(id3, f, 0) time.sleep(0.5) - self.assertEqual(self.check_action_result(temp_file), 'test : 0 : my_field : 5') + self.assertEqual(self.check_action_result(temp_file), "test : 0 : my_field : 5") self.manager.doActionFeature(id3, f, 1) time.sleep(0.5) - self.assertEqual(self.check_action_result(temp_file), 'test : 1 : my_other_field : val') + self.assertEqual( + self.check_action_result(temp_file), "test : 1 : my_other_field : val" + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsactionwidgetwrapper.py b/tests/src/python/test_qgsactionwidgetwrapper.py index a3eb76b34144..6aea5b632120 100644 --- a/tests/src/python/test_qgsactionwidgetwrapper.py +++ b/tests/src/python/test_qgsactionwidgetwrapper.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '16/08/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "16/08/2021" +__copyright__ = "Copyright 2021, The QGIS Project" from qgis.PyQt.QtCore import QUuid from qgis.PyQt.QtWidgets import QPushButton, QWidget @@ -28,15 +29,41 @@ class TestQgsActionWidgetWrapper(QgisTestCase): @classmethod def setUpClass(cls): super().setUpClass() - cls.layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=flddate:datetime", - "test_layer", "memory") + cls.layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer&field=flddate:datetime", + "test_layer", + "memory", + ) cls.action_id1 = QUuid.createUuid() cls.action_id2 = QUuid.createUuid() cls.action_id3 = QUuid.createUuid() - cls.action1 = QgsAction(cls.action_id1, QgsAction.ActionType.GenericPython, 'Test Action 1 Desc', 'i=1', '', False, 'Test Action 1 Short Title') - cls.action2 = QgsAction(cls.action_id2, QgsAction.ActionType.GenericPython, 'Test Action 2 Desc', 'i=2', QGISAPP.appIconPath(), False, 'Test Action 2 Short Title') - cls.action3 = QgsAction(cls.action_id3, QgsAction.ActionType.GenericPython, 'Test Action 3 Desc', 'i=3', '', False) + cls.action1 = QgsAction( + cls.action_id1, + QgsAction.ActionType.GenericPython, + "Test Action 1 Desc", + "i=1", + "", + False, + "Test Action 1 Short Title", + ) + cls.action2 = QgsAction( + cls.action_id2, + QgsAction.ActionType.GenericPython, + "Test Action 2 Desc", + "i=2", + QGISAPP.appIconPath(), + False, + "Test Action 2 Short Title", + ) + cls.action3 = QgsAction( + cls.action_id3, + QgsAction.ActionType.GenericPython, + "Test Action 3 Desc", + "i=3", + "", + False, + ) @classmethod def tearDownClass(cls): @@ -56,26 +83,26 @@ def testWrapper(self): self.assertIsInstance(button, QPushButton) wrapper.initWidget(button) - self.assertEqual(button.text(), 'Test Action 1 Short Title') - self.assertEqual(button.toolTip(), 'Test Action 1 Desc') + self.assertEqual(button.text(), "Test Action 1 Short Title") + self.assertEqual(button.toolTip(), "Test Action 1 Desc") self.assertTrue(button.icon().isNull()) wrapper.setAction(self.action2) button = wrapper.createWidget(parent) wrapper.initWidget(button) self.assertTrue(wrapper.valid()) - self.assertEqual(button.text(), '') + self.assertEqual(button.text(), "") self.assertFalse(button.icon().isNull()) - self.assertEqual(button.toolTip(), 'Test Action 2 Desc') + self.assertEqual(button.toolTip(), "Test Action 2 Desc") wrapper.setAction(self.action3) button = wrapper.createWidget(parent) wrapper.initWidget(button) self.assertTrue(wrapper.valid()) - self.assertEqual(button.text(), 'Test Action 3 Desc') + self.assertEqual(button.text(), "Test Action 3 Desc") self.assertTrue(button.icon().isNull()) - self.assertEqual(button.toolTip(), '') + self.assertEqual(button.toolTip(), "") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsaggregatecalculator.py b/tests/src/python/test_qgsaggregatecalculator.py index 8fcea770695a..90a472880f18 100644 --- a/tests/src/python/test_qgsaggregatecalculator.py +++ b/tests/src/python/test_qgsaggregatecalculator.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '16/05/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "16/05/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, QTime from qgis.core import ( @@ -34,38 +35,42 @@ class TestQgsAggregateCalculator(QgisTestCase): def testLayer(self): - """ Test setting/retrieving layer """ + """Test setting/retrieving layer""" a = QgsAggregateCalculator(None) self.assertEqual(a.layer(), None) # should not crash - val, ok = a.calculate(QgsAggregateCalculator.Aggregate.Sum, 'field') + val, ok = a.calculate(QgsAggregateCalculator.Aggregate.Sum, "field") self.assertFalse(ok) - layer = QgsVectorLayer("Point?field=fldint:integer&field=flddbl:double", - "layer", "memory") + layer = QgsVectorLayer( + "Point?field=fldint:integer&field=flddbl:double", "layer", "memory" + ) a = QgsAggregateCalculator(layer) self.assertEqual(a.layer(), layer) def testParameters(self): - """ Test setting parameters""" + """Test setting parameters""" a = QgsAggregateCalculator(None) params = QgsAggregateCalculator.AggregateParameters() - params.filter = 'string filter' - params.delimiter = 'delim' + params.filter = "string filter" + params.delimiter = "delim" a.setParameters(params) - self.assertEqual(a.filter(), 'string filter') - self.assertEqual(a.delimiter(), 'delim') + self.assertEqual(a.filter(), "string filter") + self.assertEqual(a.delimiter(), "delim") def testGeometry(self): - """ Test calculation of aggregates on geometry expressions """ + """Test calculation of aggregates on geometry expressions""" - layer = QgsVectorLayer("Point?", - "layer", "memory") + layer = QgsVectorLayer("Point?", "layer", "memory") pr = layer.dataProvider() # must be same length: - geometry_values = [QgsGeometry.fromWkt("Point ( 0 0 )"), QgsGeometry.fromWkt("Point ( 1 1 )"), QgsGeometry.fromWkt("Point ( 2 2 )")] + geometry_values = [ + QgsGeometry.fromWkt("Point ( 0 0 )"), + QgsGeometry.fromWkt("Point ( 1 1 )"), + QgsGeometry.fromWkt("Point ( 2 2 )"), + ] features = [] for i in range(len(geometry_values)): @@ -76,17 +81,20 @@ def testGeometry(self): agg = QgsAggregateCalculator(layer) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.GeometryCollect, '$geometry') + val, ok = agg.calculate( + QgsAggregateCalculator.Aggregate.GeometryCollect, "$geometry" + ) self.assertTrue(ok) expwkt = "MultiPoint ((0 0), (1 1), (2 2))" wkt = val.asWkt() self.assertTrue(compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n") def testNumeric(self): - """ Test calculation of aggregates on numeric fields""" + """Test calculation of aggregates on numeric fields""" - layer = QgsVectorLayer("Point?field=fldint:integer&field=flddbl:double", - "layer", "memory") + layer = QgsVectorLayer( + "Point?field=fldint:integer&field=flddbl:double", "layer", "memory" + ) pr = layer.dataProvider() # must be same length: @@ -102,37 +110,38 @@ def testNumeric(self): features.append(f) assert pr.addFeatures(features) - tests = [[QgsAggregateCalculator.Aggregate.Count, 'fldint', 6], - [QgsAggregateCalculator.Aggregate.Count, 'flddbl', 6], - [QgsAggregateCalculator.Aggregate.Sum, 'fldint', 24], - [QgsAggregateCalculator.Aggregate.Sum, 'flddbl', 37.5], - [QgsAggregateCalculator.Aggregate.Mean, 'fldint', 4], - [QgsAggregateCalculator.Aggregate.Mean, 'flddbl', 6.25], - [QgsAggregateCalculator.Aggregate.StDev, 'fldint', 2.0816], - [QgsAggregateCalculator.Aggregate.StDev, 'flddbl', 1.7969], - [QgsAggregateCalculator.Aggregate.StDevSample, 'fldint', 2.2803], - [QgsAggregateCalculator.Aggregate.StDevSample, 'flddbl', 1.9685], - [QgsAggregateCalculator.Aggregate.Min, 'fldint', 2], - [QgsAggregateCalculator.Aggregate.Min, 'flddbl', 3.5], - [QgsAggregateCalculator.Aggregate.Max, 'fldint', 8], - [QgsAggregateCalculator.Aggregate.Max, 'flddbl', 9], - [QgsAggregateCalculator.Aggregate.Range, 'fldint', 6], - [QgsAggregateCalculator.Aggregate.Range, 'flddbl', 5.5], - [QgsAggregateCalculator.Aggregate.Median, 'fldint', 3.5], - [QgsAggregateCalculator.Aggregate.Median, 'flddbl', 6.25], - [QgsAggregateCalculator.Aggregate.CountDistinct, 'fldint', 5], - [QgsAggregateCalculator.Aggregate.CountDistinct, 'flddbl', 6], - [QgsAggregateCalculator.Aggregate.CountMissing, 'fldint', 1], - [QgsAggregateCalculator.Aggregate.CountMissing, 'flddbl', 1], - [QgsAggregateCalculator.Aggregate.FirstQuartile, 'fldint', 2], - [QgsAggregateCalculator.Aggregate.FirstQuartile, 'flddbl', 5.0], - [QgsAggregateCalculator.Aggregate.ThirdQuartile, 'fldint', 5.0], - [QgsAggregateCalculator.Aggregate.ThirdQuartile, 'flddbl', 7.5], - [QgsAggregateCalculator.Aggregate.InterQuartileRange, 'fldint', 3.0], - [QgsAggregateCalculator.Aggregate.InterQuartileRange, 'flddbl', 2.5], - [QgsAggregateCalculator.Aggregate.ArrayAggregate, 'fldint', int_values], - [QgsAggregateCalculator.Aggregate.ArrayAggregate, 'flddbl', dbl_values], - ] + tests = [ + [QgsAggregateCalculator.Aggregate.Count, "fldint", 6], + [QgsAggregateCalculator.Aggregate.Count, "flddbl", 6], + [QgsAggregateCalculator.Aggregate.Sum, "fldint", 24], + [QgsAggregateCalculator.Aggregate.Sum, "flddbl", 37.5], + [QgsAggregateCalculator.Aggregate.Mean, "fldint", 4], + [QgsAggregateCalculator.Aggregate.Mean, "flddbl", 6.25], + [QgsAggregateCalculator.Aggregate.StDev, "fldint", 2.0816], + [QgsAggregateCalculator.Aggregate.StDev, "flddbl", 1.7969], + [QgsAggregateCalculator.Aggregate.StDevSample, "fldint", 2.2803], + [QgsAggregateCalculator.Aggregate.StDevSample, "flddbl", 1.9685], + [QgsAggregateCalculator.Aggregate.Min, "fldint", 2], + [QgsAggregateCalculator.Aggregate.Min, "flddbl", 3.5], + [QgsAggregateCalculator.Aggregate.Max, "fldint", 8], + [QgsAggregateCalculator.Aggregate.Max, "flddbl", 9], + [QgsAggregateCalculator.Aggregate.Range, "fldint", 6], + [QgsAggregateCalculator.Aggregate.Range, "flddbl", 5.5], + [QgsAggregateCalculator.Aggregate.Median, "fldint", 3.5], + [QgsAggregateCalculator.Aggregate.Median, "flddbl", 6.25], + [QgsAggregateCalculator.Aggregate.CountDistinct, "fldint", 5], + [QgsAggregateCalculator.Aggregate.CountDistinct, "flddbl", 6], + [QgsAggregateCalculator.Aggregate.CountMissing, "fldint", 1], + [QgsAggregateCalculator.Aggregate.CountMissing, "flddbl", 1], + [QgsAggregateCalculator.Aggregate.FirstQuartile, "fldint", 2], + [QgsAggregateCalculator.Aggregate.FirstQuartile, "flddbl", 5.0], + [QgsAggregateCalculator.Aggregate.ThirdQuartile, "fldint", 5.0], + [QgsAggregateCalculator.Aggregate.ThirdQuartile, "flddbl", 7.5], + [QgsAggregateCalculator.Aggregate.InterQuartileRange, "fldint", 3.0], + [QgsAggregateCalculator.Aggregate.InterQuartileRange, "flddbl", 2.5], + [QgsAggregateCalculator.Aggregate.ArrayAggregate, "fldint", int_values], + [QgsAggregateCalculator.Aggregate.ArrayAggregate, "flddbl", dbl_values], + ] agg = QgsAggregateCalculator(layer) for t in tests: @@ -144,34 +153,46 @@ def testNumeric(self): self.assertAlmostEqual(val, t[2], 3) # bad tests - the following stats should not be calculatable for numeric fields - for t in [QgsAggregateCalculator.Aggregate.StringMinimumLength, - QgsAggregateCalculator.Aggregate.StringMaximumLength]: - val, ok = agg.calculate(t, 'fldint') + for t in [ + QgsAggregateCalculator.Aggregate.StringMinimumLength, + QgsAggregateCalculator.Aggregate.StringMaximumLength, + ]: + val, ok = agg.calculate(t, "fldint") self.assertFalse(ok) - val, ok = agg.calculate(t, 'flddbl') + val, ok = agg.calculate(t, "flddbl") self.assertFalse(ok) # with order by agg = QgsAggregateCalculator(layer) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.ArrayAggregate, 'fldint') + val, ok = agg.calculate( + QgsAggregateCalculator.Aggregate.ArrayAggregate, "fldint" + ) self.assertEqual(val, [4, 2, 3, 2, 5, NULL, 8]) params = QgsAggregateCalculator.AggregateParameters() - params.orderBy = QgsFeatureRequest.OrderBy([QgsFeatureRequest.OrderByClause('fldint')]) + params.orderBy = QgsFeatureRequest.OrderBy( + [QgsFeatureRequest.OrderByClause("fldint")] + ) agg.setParameters(params) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.ArrayAggregate, 'fldint') + val, ok = agg.calculate( + QgsAggregateCalculator.Aggregate.ArrayAggregate, "fldint" + ) self.assertEqual(val, [2, 2, 3, 4, 5, 8, NULL]) - params.orderBy = QgsFeatureRequest.OrderBy([QgsFeatureRequest.OrderByClause('flddbl')]) + params.orderBy = QgsFeatureRequest.OrderBy( + [QgsFeatureRequest.OrderByClause("flddbl")] + ) agg.setParameters(params) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.ArrayAggregate, 'fldint') + val, ok = agg.calculate( + QgsAggregateCalculator.Aggregate.ArrayAggregate, "fldint" + ) self.assertEqual(val, [2, 2, 4, 8, 3, 5, NULL]) def testString(self): - """ Test calculation of aggregates on string fields""" + """Test calculation of aggregates on string fields""" layer = QgsVectorLayer("Point?field=fldstring:string", "layer", "memory") pr = layer.dataProvider() - values = ['cc', 'aaaa', 'bbbbbbbb', 'aaaa', 'eeee', '', 'eeee', '', 'dddd'] + values = ["cc", "aaaa", "bbbbbbbb", "aaaa", "eeee", "", "eeee", "", "dddd"] features = [] for v in values: f = QgsFeature() @@ -180,15 +201,16 @@ def testString(self): features.append(f) assert pr.addFeatures(features) - tests = [[QgsAggregateCalculator.Aggregate.Count, 'fldstring', 9], - [QgsAggregateCalculator.Aggregate.CountDistinct, 'fldstring', 6], - [QgsAggregateCalculator.Aggregate.CountMissing, 'fldstring', 2], - [QgsAggregateCalculator.Aggregate.Min, 'fldstring', 'aaaa'], - [QgsAggregateCalculator.Aggregate.Max, 'fldstring', 'eeee'], - [QgsAggregateCalculator.Aggregate.StringMinimumLength, 'fldstring', 0], - [QgsAggregateCalculator.Aggregate.StringMaximumLength, 'fldstring', 8], - [QgsAggregateCalculator.Aggregate.ArrayAggregate, 'fldstring', values], - ] + tests = [ + [QgsAggregateCalculator.Aggregate.Count, "fldstring", 9], + [QgsAggregateCalculator.Aggregate.CountDistinct, "fldstring", 6], + [QgsAggregateCalculator.Aggregate.CountMissing, "fldstring", 2], + [QgsAggregateCalculator.Aggregate.Min, "fldstring", "aaaa"], + [QgsAggregateCalculator.Aggregate.Max, "fldstring", "eeee"], + [QgsAggregateCalculator.Aggregate.StringMinimumLength, "fldstring", 0], + [QgsAggregateCalculator.Aggregate.StringMaximumLength, "fldstring", 8], + [QgsAggregateCalculator.Aggregate.ArrayAggregate, "fldstring", values], + ] agg = QgsAggregateCalculator(layer) for t in tests: @@ -197,70 +219,93 @@ def testString(self): self.assertEqual(val, t[2]) # test string concatenation - agg.setDelimiter(',') - self.assertEqual(agg.delimiter(), ',') - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.StringConcatenate, 'fldstring') + agg.setDelimiter(",") + self.assertEqual(agg.delimiter(), ",") + val, ok = agg.calculate( + QgsAggregateCalculator.Aggregate.StringConcatenate, "fldstring" + ) self.assertTrue(ok) - self.assertEqual(val, 'cc,aaaa,bbbbbbbb,aaaa,eeee,,eeee,,dddd') - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.StringConcatenateUnique, 'fldstring') + self.assertEqual(val, "cc,aaaa,bbbbbbbb,aaaa,eeee,,eeee,,dddd") + val, ok = agg.calculate( + QgsAggregateCalculator.Aggregate.StringConcatenateUnique, "fldstring" + ) self.assertTrue(ok) - self.assertEqual(val, 'cc,aaaa,bbbbbbbb,eeee,,dddd') + self.assertEqual(val, "cc,aaaa,bbbbbbbb,eeee,,dddd") # bad tests - the following stats should not be calculatable for string fields - for t in [QgsAggregateCalculator.Aggregate.Sum, - QgsAggregateCalculator.Aggregate.Mean, - QgsAggregateCalculator.Aggregate.Median, - QgsAggregateCalculator.Aggregate.StDev, - QgsAggregateCalculator.Aggregate.StDevSample, - QgsAggregateCalculator.Aggregate.Range, - QgsAggregateCalculator.Aggregate.FirstQuartile, - QgsAggregateCalculator.Aggregate.ThirdQuartile, - QgsAggregateCalculator.Aggregate.InterQuartileRange - ]: - val, ok = agg.calculate(t, 'fldstring') + for t in [ + QgsAggregateCalculator.Aggregate.Sum, + QgsAggregateCalculator.Aggregate.Mean, + QgsAggregateCalculator.Aggregate.Median, + QgsAggregateCalculator.Aggregate.StDev, + QgsAggregateCalculator.Aggregate.StDevSample, + QgsAggregateCalculator.Aggregate.Range, + QgsAggregateCalculator.Aggregate.FirstQuartile, + QgsAggregateCalculator.Aggregate.ThirdQuartile, + QgsAggregateCalculator.Aggregate.InterQuartileRange, + ]: + val, ok = agg.calculate(t, "fldstring") self.assertFalse(ok) # with order by agg = QgsAggregateCalculator(layer) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.ArrayAggregate, 'fldstring') - self.assertEqual(val, ['cc', 'aaaa', 'bbbbbbbb', 'aaaa', 'eeee', '', 'eeee', '', 'dddd']) + val, ok = agg.calculate( + QgsAggregateCalculator.Aggregate.ArrayAggregate, "fldstring" + ) + self.assertEqual( + val, ["cc", "aaaa", "bbbbbbbb", "aaaa", "eeee", "", "eeee", "", "dddd"] + ) params = QgsAggregateCalculator.AggregateParameters() - params.orderBy = QgsFeatureRequest.OrderBy([QgsFeatureRequest.OrderByClause('fldstring')]) + params.orderBy = QgsFeatureRequest.OrderBy( + [QgsFeatureRequest.OrderByClause("fldstring")] + ) agg.setParameters(params) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.ArrayAggregate, 'fldstring') - self.assertEqual(val, ['', '', 'aaaa', 'aaaa', 'bbbbbbbb', 'cc', 'dddd', 'eeee', 'eeee']) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.StringConcatenate, 'fldstring') - self.assertEqual(val, 'aaaaaaaabbbbbbbbccddddeeeeeeee') - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Minority, 'fldstring') - self.assertEqual(val, 'bbbbbbbb') - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Majority, 'fldstring') - self.assertEqual(val, '') + val, ok = agg.calculate( + QgsAggregateCalculator.Aggregate.ArrayAggregate, "fldstring" + ) + self.assertEqual( + val, ["", "", "aaaa", "aaaa", "bbbbbbbb", "cc", "dddd", "eeee", "eeee"] + ) + val, ok = agg.calculate( + QgsAggregateCalculator.Aggregate.StringConcatenate, "fldstring" + ) + self.assertEqual(val, "aaaaaaaabbbbbbbbccddddeeeeeeee") + val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Minority, "fldstring") + self.assertEqual(val, "bbbbbbbb") + val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Majority, "fldstring") + self.assertEqual(val, "") def testDateTime(self): - """ Test calculation of aggregates on date/datetime fields""" + """Test calculation of aggregates on date/datetime fields""" - layer = QgsVectorLayer("Point?field=flddate:date&field=flddatetime:datetime", "layer", "memory") + layer = QgsVectorLayer( + "Point?field=flddate:date&field=flddatetime:datetime", "layer", "memory" + ) pr = layer.dataProvider() # must be same length: - datetime_values = [QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), - QDateTime(QDate(2011, 1, 5), QTime(15, 3, 1)), - QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), - QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), - QDateTime(QDate(2019, 12, 28), QTime(23, 10, 1)), - QDateTime(), - QDateTime(QDate(1998, 1, 2), QTime(1, 10, 54)), - QDateTime(), - QDateTime(QDate(2011, 1, 5), QTime(11, 10, 54))] - date_values = [QDate(2015, 3, 4), - QDate(2015, 3, 4), - QDate(2019, 12, 28), - QDate(), - QDate(1998, 1, 2), - QDate(), - QDate(2011, 1, 5), - QDate(2011, 1, 5), - QDate(2011, 1, 5)] + datetime_values = [ + QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), + QDateTime(QDate(2011, 1, 5), QTime(15, 3, 1)), + QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), + QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), + QDateTime(QDate(2019, 12, 28), QTime(23, 10, 1)), + QDateTime(), + QDateTime(QDate(1998, 1, 2), QTime(1, 10, 54)), + QDateTime(), + QDateTime(QDate(2011, 1, 5), QTime(11, 10, 54)), + ] + date_values = [ + QDate(2015, 3, 4), + QDate(2015, 3, 4), + QDate(2019, 12, 28), + QDate(), + QDate(1998, 1, 2), + QDate(), + QDate(2011, 1, 5), + QDate(2011, 1, 5), + QDate(2011, 1, 5), + ] self.assertEqual(len(datetime_values), len(date_values)) features = [] @@ -271,23 +316,50 @@ def testDateTime(self): features.append(f) assert pr.addFeatures(features) - tests = [[QgsAggregateCalculator.Aggregate.Count, 'flddatetime', 9], - [QgsAggregateCalculator.Aggregate.Count, 'flddate', 9], - [QgsAggregateCalculator.Aggregate.CountDistinct, 'flddatetime', 6], - [QgsAggregateCalculator.Aggregate.CountDistinct, 'flddate', 5], - [QgsAggregateCalculator.Aggregate.CountMissing, 'flddatetime', 2], - [QgsAggregateCalculator.Aggregate.CountMissing, 'flddate', 2], - [QgsAggregateCalculator.Aggregate.Min, 'flddatetime', QDateTime(QDate(1998, 1, 2), QTime(1, 10, 54))], - [QgsAggregateCalculator.Aggregate.Min, 'flddate', QDateTime(QDate(1998, 1, 2), QTime(0, 0, 0))], - [QgsAggregateCalculator.Aggregate.Max, 'flddatetime', QDateTime(QDate(2019, 12, 28), QTime(23, 10, 1))], - [QgsAggregateCalculator.Aggregate.Max, 'flddate', QDateTime(QDate(2019, 12, 28), QTime(0, 0, 0))], - - [QgsAggregateCalculator.Aggregate.Range, 'flddatetime', QgsInterval(693871147)], - [QgsAggregateCalculator.Aggregate.Range, 'flddate', QgsInterval(693792000)], - - [QgsAggregateCalculator.Aggregate.ArrayAggregate, 'flddatetime', [None if v.isNull() else v for v in datetime_values]], - [QgsAggregateCalculator.Aggregate.ArrayAggregate, 'flddate', [None if v.isNull() else v for v in date_values]], - ] + tests = [ + [QgsAggregateCalculator.Aggregate.Count, "flddatetime", 9], + [QgsAggregateCalculator.Aggregate.Count, "flddate", 9], + [QgsAggregateCalculator.Aggregate.CountDistinct, "flddatetime", 6], + [QgsAggregateCalculator.Aggregate.CountDistinct, "flddate", 5], + [QgsAggregateCalculator.Aggregate.CountMissing, "flddatetime", 2], + [QgsAggregateCalculator.Aggregate.CountMissing, "flddate", 2], + [ + QgsAggregateCalculator.Aggregate.Min, + "flddatetime", + QDateTime(QDate(1998, 1, 2), QTime(1, 10, 54)), + ], + [ + QgsAggregateCalculator.Aggregate.Min, + "flddate", + QDateTime(QDate(1998, 1, 2), QTime(0, 0, 0)), + ], + [ + QgsAggregateCalculator.Aggregate.Max, + "flddatetime", + QDateTime(QDate(2019, 12, 28), QTime(23, 10, 1)), + ], + [ + QgsAggregateCalculator.Aggregate.Max, + "flddate", + QDateTime(QDate(2019, 12, 28), QTime(0, 0, 0)), + ], + [ + QgsAggregateCalculator.Aggregate.Range, + "flddatetime", + QgsInterval(693871147), + ], + [QgsAggregateCalculator.Aggregate.Range, "flddate", QgsInterval(693792000)], + [ + QgsAggregateCalculator.Aggregate.ArrayAggregate, + "flddatetime", + [None if v.isNull() else v for v in datetime_values], + ], + [ + QgsAggregateCalculator.Aggregate.ArrayAggregate, + "flddate", + [None if v.isNull() else v for v in date_values], + ], + ] agg = QgsAggregateCalculator(layer) for t in tests: @@ -296,24 +368,25 @@ def testDateTime(self): self.assertEqual(val, t[2]) # bad tests - the following stats should not be calculatable for string fields - for t in [QgsAggregateCalculator.Aggregate.Sum, - QgsAggregateCalculator.Aggregate.Mean, - QgsAggregateCalculator.Aggregate.Median, - QgsAggregateCalculator.Aggregate.StDev, - QgsAggregateCalculator.Aggregate.StDevSample, - QgsAggregateCalculator.Aggregate.Minority, - QgsAggregateCalculator.Aggregate.Majority, - QgsAggregateCalculator.Aggregate.FirstQuartile, - QgsAggregateCalculator.Aggregate.ThirdQuartile, - QgsAggregateCalculator.Aggregate.InterQuartileRange, - QgsAggregateCalculator.Aggregate.StringMinimumLength, - QgsAggregateCalculator.Aggregate.StringMaximumLength, - ]: - val, ok = agg.calculate(t, 'flddatetime') + for t in [ + QgsAggregateCalculator.Aggregate.Sum, + QgsAggregateCalculator.Aggregate.Mean, + QgsAggregateCalculator.Aggregate.Median, + QgsAggregateCalculator.Aggregate.StDev, + QgsAggregateCalculator.Aggregate.StDevSample, + QgsAggregateCalculator.Aggregate.Minority, + QgsAggregateCalculator.Aggregate.Majority, + QgsAggregateCalculator.Aggregate.FirstQuartile, + QgsAggregateCalculator.Aggregate.ThirdQuartile, + QgsAggregateCalculator.Aggregate.InterQuartileRange, + QgsAggregateCalculator.Aggregate.StringMinimumLength, + QgsAggregateCalculator.Aggregate.StringMaximumLength, + ]: + val, ok = agg.calculate(t, "flddatetime") self.assertFalse(ok) def testFilter(self): - """ test calculating aggregate with filter """ + """test calculating aggregate with filter""" layer = QgsVectorLayer("Point?field=fldint:integer", "layer", "memory") pr = layer.dataProvider() @@ -334,18 +407,18 @@ def testFilter(self): agg.setFilter(filter_string) self.assertEqual(agg.filter(), filter_string) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Sum, 'fldint') + val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Sum, "fldint") self.assertTrue(ok) self.assertEqual(val, 20) # remove filter and retest agg.setFilter(None) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Sum, 'fldint') + val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Sum, "fldint") self.assertTrue(ok) self.assertEqual(val, 24) def testExpression(self): - """ test aggregate calculation using an expression """ + """test aggregate calculation using an expression""" # numeric layer = QgsVectorLayer("Point?field=fldint:integer", "layer", "memory") @@ -363,37 +436,50 @@ def testExpression(self): # int agg = QgsAggregateCalculator(layer) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Sum, 'fldint * 2') + val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Sum, "fldint * 2") self.assertTrue(ok) self.assertEqual(val, 48) # double - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Sum, 'fldint * 1.5') + val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Sum, "fldint * 1.5") self.assertTrue(ok) self.assertEqual(val, 36) # datetime - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Max, "to_date('2012-05-04') + to_interval( fldint || ' day' )") + val, ok = agg.calculate( + QgsAggregateCalculator.Aggregate.Max, + "to_date('2012-05-04') + to_interval( fldint || ' day' )", + ) self.assertTrue(ok) self.assertEqual(val, QDateTime(QDate(2012, 5, 12), QTime(0, 0, 0))) # date - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Min, "to_date(to_date('2012-05-04') + to_interval( fldint || ' day' ))") + val, ok = agg.calculate( + QgsAggregateCalculator.Aggregate.Min, + "to_date(to_date('2012-05-04') + to_interval( fldint || ' day' ))", + ) self.assertTrue(ok) self.assertEqual(val, QDateTime(QDate(2012, 5, 6), QTime(0, 0, 0))) # string - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Max, "fldint || ' oranges'") + val, ok = agg.calculate( + QgsAggregateCalculator.Aggregate.Max, "fldint || ' oranges'" + ) self.assertTrue(ok) - self.assertEqual(val, '8 oranges') + self.assertEqual(val, "8 oranges") # geometry - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.GeometryCollect, "make_point( coalesce(fldint,0), 2 )") + val, ok = agg.calculate( + QgsAggregateCalculator.Aggregate.GeometryCollect, + "make_point( coalesce(fldint,0), 2 )", + ) self.assertTrue(ok) - self.assertTrue(val.asWkt(), 'MultiPoint((4 2, 2 2, 3 2, 2 2,5 2, 0 2,8 2))') + self.assertTrue(val.asWkt(), "MultiPoint((4 2, 2 2, 3 2, 2 2,5 2, 0 2,8 2))") # try a bad expression - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Max, "not_a_field || ' oranges'") + val, ok = agg.calculate( + QgsAggregateCalculator.Aggregate.Max, "not_a_field || ' oranges'" + ) self.assertFalse(ok) val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Max, "5+") self.assertFalse(ok) @@ -404,7 +490,7 @@ def testExpression(self): # should have layer variables: val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Min, "@layer_name") self.assertTrue(ok) - self.assertEqual(val, 'layer') + self.assertEqual(val, "layer") # but not custom variables: val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Min, "@my_var") self.assertTrue(ok) @@ -412,34 +498,50 @@ def testExpression(self): # test with manual expression context scope = QgsExpressionContextScope() - scope.setVariable('my_var', 5) + scope.setVariable("my_var", 5) context = QgsExpressionContext() context.appendScope(scope) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Min, "@my_var", context) + val, ok = agg.calculate( + QgsAggregateCalculator.Aggregate.Min, "@my_var", context + ) self.assertTrue(ok) self.assertEqual(val, 5) # test with subset agg = QgsAggregateCalculator(layer) # reset to remove expression filter agg.setFidsFilter([1, 2]) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Sum, 'fldint') + val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Sum, "fldint") self.assertTrue(ok) self.assertEqual(val, 6.0) # test with empty subset agg.setFidsFilter(list()) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Sum, 'fldint') + val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Sum, "fldint") self.assertTrue(ok) self.assertEqual(val, 0.0) def testExpressionNullValuesAtStart(self): - """ test aggregate calculation using an expression which returns null values at first """ + """test aggregate calculation using an expression which returns null values at first""" # numeric layer = QgsVectorLayer("Point?field=fldstr:string", "layer", "memory") pr = layer.dataProvider() - values = [None, None, None, None, None, None, None, None, None, None, '2', '3', '5'] + values = [ + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "2", + "3", + "5", + ] features = [] for v in values: @@ -451,88 +553,101 @@ def testExpressionNullValuesAtStart(self): # number aggregation agg = QgsAggregateCalculator(layer) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Sum, 'to_int(fldstr)') + val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Sum, "to_int(fldstr)") self.assertTrue(ok) self.assertEqual(val, 10) # string aggregation - agg.setDelimiter(',') - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.StringConcatenate, 'fldstr || \'suffix\'') + agg.setDelimiter(",") + val, ok = agg.calculate( + QgsAggregateCalculator.Aggregate.StringConcatenate, "fldstr || 'suffix'" + ) self.assertTrue(ok) - self.assertEqual(val, ',,,,,,,,,,2suffix,3suffix,5suffix') + self.assertEqual(val, ",,,,,,,,,,2suffix,3suffix,5suffix") def testExpressionNoMatch(self): - """ test aggregate calculation using an expression with no features """ + """test aggregate calculation using an expression with no features""" # no features layer = QgsVectorLayer("Point?field=fldint:integer", "layer", "memory") # sum agg = QgsAggregateCalculator(layer) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Sum, 'fldint * 2') + val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Sum, "fldint * 2") self.assertTrue(ok) self.assertEqual(val, None) # count agg = QgsAggregateCalculator(layer) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Count, 'fldint * 2') + val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Count, "fldint * 2") self.assertTrue(ok) self.assertEqual(val, 0) # count distinct agg = QgsAggregateCalculator(layer) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.CountDistinct, 'fldint * 2') + val, ok = agg.calculate( + QgsAggregateCalculator.Aggregate.CountDistinct, "fldint * 2" + ) self.assertTrue(ok) self.assertEqual(val, 0) # count missing agg = QgsAggregateCalculator(layer) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.CountMissing, 'fldint * 2') + val, ok = agg.calculate( + QgsAggregateCalculator.Aggregate.CountMissing, "fldint * 2" + ) self.assertTrue(ok) self.assertEqual(val, 0) # min agg = QgsAggregateCalculator(layer) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Min, 'fldint * 2') + val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Min, "fldint * 2") self.assertTrue(ok) self.assertEqual(val, None) # max agg = QgsAggregateCalculator(layer) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Max, 'fldint * 2') + val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.Max, "fldint * 2") self.assertTrue(ok) self.assertEqual(val, None) # array_agg agg = QgsAggregateCalculator(layer) - val, ok = agg.calculate(QgsAggregateCalculator.Aggregate.ArrayAggregate, 'fldint * 2') + val, ok = agg.calculate( + QgsAggregateCalculator.Aggregate.ArrayAggregate, "fldint * 2" + ) self.assertTrue(ok) self.assertEqual(val, []) def testStringToAggregate(self): - """ test converting strings to aggregate types """ - - tests = [[QgsAggregateCalculator.Aggregate.Count, ' cOUnT '], - [QgsAggregateCalculator.Aggregate.CountDistinct, ' count_distinct '], - [QgsAggregateCalculator.Aggregate.CountMissing, 'COUNT_MISSING'], - [QgsAggregateCalculator.Aggregate.Min, ' MiN'], - [QgsAggregateCalculator.Aggregate.Max, 'mAX'], - [QgsAggregateCalculator.Aggregate.Sum, 'sum'], - [QgsAggregateCalculator.Aggregate.Mean, 'MEAn '], - [QgsAggregateCalculator.Aggregate.Median, 'median'], - [QgsAggregateCalculator.Aggregate.StDev, 'stdev'], - [QgsAggregateCalculator.Aggregate.StDevSample, 'stdevsample'], - [QgsAggregateCalculator.Aggregate.Range, 'range'], - [QgsAggregateCalculator.Aggregate.Minority, 'minority'], - [QgsAggregateCalculator.Aggregate.Majority, 'majority'], - [QgsAggregateCalculator.Aggregate.FirstQuartile, 'q1'], - [QgsAggregateCalculator.Aggregate.ThirdQuartile, 'q3'], - [QgsAggregateCalculator.Aggregate.InterQuartileRange, 'iqr'], - [QgsAggregateCalculator.Aggregate.StringMinimumLength, 'min_length'], - [QgsAggregateCalculator.Aggregate.StringMaximumLength, 'max_length'], - [QgsAggregateCalculator.Aggregate.StringConcatenate, 'concatenate'], - [QgsAggregateCalculator.Aggregate.StringConcatenateUnique, 'concatenate_unique'], - [QgsAggregateCalculator.Aggregate.GeometryCollect, 'collect']] + """test converting strings to aggregate types""" + + tests = [ + [QgsAggregateCalculator.Aggregate.Count, " cOUnT "], + [QgsAggregateCalculator.Aggregate.CountDistinct, " count_distinct "], + [QgsAggregateCalculator.Aggregate.CountMissing, "COUNT_MISSING"], + [QgsAggregateCalculator.Aggregate.Min, " MiN"], + [QgsAggregateCalculator.Aggregate.Max, "mAX"], + [QgsAggregateCalculator.Aggregate.Sum, "sum"], + [QgsAggregateCalculator.Aggregate.Mean, "MEAn "], + [QgsAggregateCalculator.Aggregate.Median, "median"], + [QgsAggregateCalculator.Aggregate.StDev, "stdev"], + [QgsAggregateCalculator.Aggregate.StDevSample, "stdevsample"], + [QgsAggregateCalculator.Aggregate.Range, "range"], + [QgsAggregateCalculator.Aggregate.Minority, "minority"], + [QgsAggregateCalculator.Aggregate.Majority, "majority"], + [QgsAggregateCalculator.Aggregate.FirstQuartile, "q1"], + [QgsAggregateCalculator.Aggregate.ThirdQuartile, "q3"], + [QgsAggregateCalculator.Aggregate.InterQuartileRange, "iqr"], + [QgsAggregateCalculator.Aggregate.StringMinimumLength, "min_length"], + [QgsAggregateCalculator.Aggregate.StringMaximumLength, "max_length"], + [QgsAggregateCalculator.Aggregate.StringConcatenate, "concatenate"], + [ + QgsAggregateCalculator.Aggregate.StringConcatenateUnique, + "concatenate_unique", + ], + [QgsAggregateCalculator.Aggregate.GeometryCollect, "collect"], + ] for t in tests: agg, ok = QgsAggregateCalculator.stringToAggregate(t[1]) @@ -540,9 +655,9 @@ def testStringToAggregate(self): self.assertEqual(agg, t[0]) # test some bad values - agg, ok = QgsAggregateCalculator.stringToAggregate('') + agg, ok = QgsAggregateCalculator.stringToAggregate("") self.assertFalse(ok) - agg, ok = QgsAggregateCalculator.stringToAggregate('bad') + agg, ok = QgsAggregateCalculator.stringToAggregate("bad") self.assertFalse(ok) diff --git a/tests/src/python/test_qgsaggregatemappingwidget.py b/tests/src/python/test_qgsaggregatemappingwidget.py index 875f2ad0ef14..abcdf04059c5 100644 --- a/tests/src/python/test_qgsaggregatemappingwidget.py +++ b/tests/src/python/test_qgsaggregatemappingwidget.py @@ -8,15 +8,18 @@ (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '03/06/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "03/06/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import ( QCoreApplication, QItemSelectionModel, QModelIndex, - QVariant, Qt) + QVariant, + Qt, +) from qgis.core import QgsField, QgsFields from qgis.gui import QgsAggregateMappingModel, QgsAggregateMappingWidget import unittest @@ -39,9 +42,9 @@ def setUp(self): """Run before each test""" source_fields = QgsFields() - f = QgsField('source_field1', QVariant.String) + f = QgsField("source_field1", QVariant.String) self.assertTrue(source_fields.append(f)) - f = QgsField('source_field2', QVariant.Int, 'integer', 10, 8) + f = QgsField("source_field2", QVariant.Int, "integer", 10, 8) self.assertTrue(source_fields.append(f)) self.source_fields = source_fields @@ -50,6 +53,7 @@ def _showDialog(self, widget): """Used during development""" from qgis.PyQt.QtWidgets import QDialog, QVBoxLayout + d = QDialog() l = QVBoxLayout() l.addWidget(widget) @@ -63,52 +67,93 @@ def testModel(self): self.assertEqual(model.rowCount(QModelIndex()), 2) self.assertIsNone(model.data(model.index(9999, 0), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), '"source_field1"') - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 'concatenate') - self.assertEqual(model.data(model.index(0, 2), Qt.ItemDataRole.DisplayRole), ',') - self.assertEqual(model.data(model.index(0, 3), Qt.ItemDataRole.DisplayRole), 'source_field1') - self.assertEqual(model.data(model.index(0, 4), Qt.ItemDataRole.DisplayRole), 'text') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), + '"source_field1"', + ) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "concatenate" + ) + self.assertEqual( + model.data(model.index(0, 2), Qt.ItemDataRole.DisplayRole), "," + ) + self.assertEqual( + model.data(model.index(0, 3), Qt.ItemDataRole.DisplayRole), "source_field1" + ) + self.assertEqual( + model.data(model.index(0, 4), Qt.ItemDataRole.DisplayRole), "text" + ) self.assertEqual(model.data(model.index(0, 5), Qt.ItemDataRole.DisplayRole), 0) self.assertEqual(model.data(model.index(0, 6), Qt.ItemDataRole.DisplayRole), 0) - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), '"source_field2"') - self.assertEqual(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), 'sum') - self.assertEqual(model.data(model.index(1, 2), Qt.ItemDataRole.DisplayRole), ',') - self.assertEqual(model.data(model.index(1, 3), Qt.ItemDataRole.DisplayRole), 'source_field2') - self.assertEqual(model.data(model.index(1, 4), Qt.ItemDataRole.DisplayRole), 'integer') + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), + '"source_field2"', + ) + self.assertEqual( + model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), "sum" + ) + self.assertEqual( + model.data(model.index(1, 2), Qt.ItemDataRole.DisplayRole), "," + ) + self.assertEqual( + model.data(model.index(1, 3), Qt.ItemDataRole.DisplayRole), "source_field2" + ) + self.assertEqual( + model.data(model.index(1, 4), Qt.ItemDataRole.DisplayRole), "integer" + ) self.assertEqual(model.data(model.index(1, 5), Qt.ItemDataRole.DisplayRole), 10) self.assertEqual(model.data(model.index(1, 6), Qt.ItemDataRole.DisplayRole), 8) # Test expression scope ctx = model.contextGenerator().createExpressionContext() - self.assertIn('source_field1', ctx.fields().names()) + self.assertIn("source_field1", ctx.fields().names()) # Test add fields - model.appendField(QgsField('field3', QVariant.String), 'upper("field3")', 'first_value') + model.appendField( + QgsField("field3", QVariant.String), 'upper("field3")', "first_value" + ) self.assertEqual(model.rowCount(QModelIndex()), 3) - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'upper("field3")') - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 'first_value') - self.assertEqual(model.data(model.index(2, 2), Qt.ItemDataRole.DisplayRole), ',') - self.assertEqual(model.data(model.index(2, 3), Qt.ItemDataRole.DisplayRole), 'field3') - self.assertEqual(model.data(model.index(2, 4), Qt.ItemDataRole.DisplayRole), 'text') + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), + 'upper("field3")', + ) + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "first_value" + ) + self.assertEqual( + model.data(model.index(2, 2), Qt.ItemDataRole.DisplayRole), "," + ) + self.assertEqual( + model.data(model.index(2, 3), Qt.ItemDataRole.DisplayRole), "field3" + ) + self.assertEqual( + model.data(model.index(2, 4), Qt.ItemDataRole.DisplayRole), "text" + ) self.assertEqual(model.data(model.index(2, 5), Qt.ItemDataRole.DisplayRole), 0) self.assertEqual(model.data(model.index(2, 6), Qt.ItemDataRole.DisplayRole), 0) # Test remove field model.removeField(model.index(1, 0)) self.assertEqual(model.rowCount(QModelIndex()), 2) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), '"source_field1"') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'upper("field3")') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), + '"source_field1"', + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), + 'upper("field3")', + ) # Test edit fields mapping = model.mapping() - self.assertEqual(mapping[0].field.name(), 'source_field1') - self.assertEqual(mapping[0].aggregate, 'concatenate') - self.assertEqual(mapping[0].delimiter, ',') + self.assertEqual(mapping[0].field.name(), "source_field1") + self.assertEqual(mapping[0].aggregate, "concatenate") + self.assertEqual(mapping[0].delimiter, ",") self.assertEqual(mapping[0].source, '"source_field1"') - self.assertEqual(mapping[1].field.name(), 'field3') - self.assertEqual(mapping[1].aggregate, 'first_value') - self.assertEqual(mapping[1].delimiter, ',') + self.assertEqual(mapping[1].field.name(), "field3") + self.assertEqual(mapping[1].aggregate, "first_value") + self.assertEqual(mapping[1].delimiter, ",") self.assertEqual(mapping[1].source, 'upper("field3")') # Test move up or down @@ -119,80 +164,138 @@ def testModel(self): self.assertTrue(model.moveDown(model.index(0, 0))) mapping = model.mapping() - self.assertEqual(mapping[0].field.name(), 'field3') - self.assertEqual(mapping[1].field.name(), 'source_field1') + self.assertEqual(mapping[0].field.name(), "field3") + self.assertEqual(mapping[1].field.name(), "source_field1") self.assertTrue(model.moveUp(model.index(1, 0))) mapping = model.mapping() - self.assertEqual(mapping[0].field.name(), 'source_field1') - self.assertEqual(mapping[1].field.name(), 'field3') + self.assertEqual(mapping[0].field.name(), "source_field1") + self.assertEqual(mapping[1].field.name(), "field3") def testSetSourceFields(self): """Test that changing source fields also empty expressions are updated""" model = QgsAggregateMappingModel(self.source_fields) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), '"source_field1"') - self.assertEqual(model.data(model.index(0, 3), Qt.ItemDataRole.DisplayRole), 'source_field1') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), '"source_field2"') - self.assertEqual(model.data(model.index(1, 3), Qt.ItemDataRole.DisplayRole), 'source_field2') - - f = QgsField('source_field3', QVariant.String) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), + '"source_field1"', + ) + self.assertEqual( + model.data(model.index(0, 3), Qt.ItemDataRole.DisplayRole), "source_field1" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), + '"source_field2"', + ) + self.assertEqual( + model.data(model.index(1, 3), Qt.ItemDataRole.DisplayRole), "source_field2" + ) + + f = QgsField("source_field3", QVariant.String) fields = self.source_fields fields.append(f) model.setSourceFields(fields) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), '"source_field1"') - self.assertEqual(model.data(model.index(0, 3), Qt.ItemDataRole.DisplayRole), 'source_field1') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), '"source_field2"') - self.assertEqual(model.data(model.index(1, 3), Qt.ItemDataRole.DisplayRole), 'source_field2') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), '"source_field3"') - self.assertEqual(model.data(model.index(2, 3), Qt.ItemDataRole.DisplayRole), 'source_field3') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), + '"source_field1"', + ) + self.assertEqual( + model.data(model.index(0, 3), Qt.ItemDataRole.DisplayRole), "source_field1" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), + '"source_field2"', + ) + self.assertEqual( + model.data(model.index(1, 3), Qt.ItemDataRole.DisplayRole), "source_field2" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), + '"source_field3"', + ) + self.assertEqual( + model.data(model.index(2, 3), Qt.ItemDataRole.DisplayRole), "source_field3" + ) def testProperties(self): model = QgsAggregateMappingModel(self.source_fields) mapping = model.mapping() - self.assertEqual(mapping[0].field.name(), 'source_field1') + self.assertEqual(mapping[0].field.name(), "source_field1") self.assertEqual(mapping[0].source, '"source_field1"') - self.assertEqual(mapping[0].aggregate, 'concatenate') - self.assertEqual(mapping[0].delimiter, ',') - self.assertEqual(mapping[1].field.name(), 'source_field2') + self.assertEqual(mapping[0].aggregate, "concatenate") + self.assertEqual(mapping[0].delimiter, ",") + self.assertEqual(mapping[1].field.name(), "source_field2") self.assertEqual(mapping[1].source, '"source_field2"') - self.assertEqual(mapping[1].aggregate, 'sum') - self.assertEqual(mapping[1].delimiter, ',') + self.assertEqual(mapping[1].aggregate, "sum") + self.assertEqual(mapping[1].delimiter, ",") mapping[0].source = 'upper("source_field2")' - mapping[0].aggregate = 'first_value' - mapping[0].delimiter = '|' + mapping[0].aggregate = "first_value" + mapping[0].delimiter = "|" new_aggregate = QgsAggregateMappingModel.Aggregate() - new_aggregate.field = QgsField('output_field3', QVariant.Double, len=4, prec=2) - new_aggregate.source = 'randf(1,2)' - new_aggregate.aggregate = 'mean' - new_aggregate.delimiter = '*' + new_aggregate.field = QgsField("output_field3", QVariant.Double, len=4, prec=2) + new_aggregate.source = "randf(1,2)" + new_aggregate.aggregate = "mean" + new_aggregate.delimiter = "*" mapping.append(new_aggregate) model.setMapping(mapping) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'upper("source_field2")') - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 'first_value') - self.assertEqual(model.data(model.index(0, 2), Qt.ItemDataRole.DisplayRole), '|') - self.assertEqual(model.data(model.index(0, 3), Qt.ItemDataRole.DisplayRole), 'source_field1') - self.assertEqual(model.data(model.index(0, 4), Qt.ItemDataRole.DisplayRole), 'text') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), + 'upper("source_field2")', + ) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "first_value" + ) + self.assertEqual( + model.data(model.index(0, 2), Qt.ItemDataRole.DisplayRole), "|" + ) + self.assertEqual( + model.data(model.index(0, 3), Qt.ItemDataRole.DisplayRole), "source_field1" + ) + self.assertEqual( + model.data(model.index(0, 4), Qt.ItemDataRole.DisplayRole), "text" + ) self.assertEqual(model.data(model.index(0, 5), Qt.ItemDataRole.DisplayRole), 0) self.assertEqual(model.data(model.index(0, 6), Qt.ItemDataRole.DisplayRole), 0) - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), '"source_field2"') - self.assertEqual(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), 'sum') - self.assertEqual(model.data(model.index(1, 2), Qt.ItemDataRole.DisplayRole), ',') - self.assertEqual(model.data(model.index(1, 3), Qt.ItemDataRole.DisplayRole), 'source_field2') - self.assertEqual(model.data(model.index(1, 4), Qt.ItemDataRole.DisplayRole), 'integer') + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), + '"source_field2"', + ) + self.assertEqual( + model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), "sum" + ) + self.assertEqual( + model.data(model.index(1, 2), Qt.ItemDataRole.DisplayRole), "," + ) + self.assertEqual( + model.data(model.index(1, 3), Qt.ItemDataRole.DisplayRole), "source_field2" + ) + self.assertEqual( + model.data(model.index(1, 4), Qt.ItemDataRole.DisplayRole), "integer" + ) self.assertEqual(model.data(model.index(1, 5), Qt.ItemDataRole.DisplayRole), 10) self.assertEqual(model.data(model.index(1, 6), Qt.ItemDataRole.DisplayRole), 8) - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'randf(1,2)') - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 'mean') - self.assertEqual(model.data(model.index(2, 2), Qt.ItemDataRole.DisplayRole), '*') - self.assertEqual(model.data(model.index(2, 3), Qt.ItemDataRole.DisplayRole), 'output_field3') - self.assertEqual(model.data(model.index(2, 4), Qt.ItemDataRole.DisplayRole), 'double precision') + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "randf(1,2)" + ) + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "mean" + ) + self.assertEqual( + model.data(model.index(2, 2), Qt.ItemDataRole.DisplayRole), "*" + ) + self.assertEqual( + model.data(model.index(2, 3), Qt.ItemDataRole.DisplayRole), "output_field3" + ) + self.assertEqual( + model.data(model.index(2, 4), Qt.ItemDataRole.DisplayRole), + "double precision", + ) self.assertEqual(model.data(model.index(2, 5), Qt.ItemDataRole.DisplayRole), 4) self.assertEqual(model.data(model.index(2, 6), Qt.ItemDataRole.DisplayRole), 2) @@ -215,21 +318,27 @@ def _compare(widget, expected): selection_model = widget.selectionModel() selection_model.clear() for i in range(0, 10, 2): - selection_model.select(widget.model().index(i, 0), QItemSelectionModel.SelectionFlag.Select) + selection_model.select( + widget.model().index(i, 0), QItemSelectionModel.SelectionFlag.Select + ) self.assertTrue(widget.moveSelectedFieldsDown()) _compare(widget, [1, 0, 3, 2, 5, 4, 7, 6, 9, 8]) selection_model.clear() for i in range(1, 10, 2): - selection_model.select(widget.model().index(i, 0), QItemSelectionModel.SelectionFlag.Select) + selection_model.select( + widget.model().index(i, 0), QItemSelectionModel.SelectionFlag.Select + ) self.assertTrue(widget.moveSelectedFieldsUp()) _compare(widget, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) selection_model.clear() for i in range(0, 10, 2): - selection_model.select(widget.model().index(i, 0), QItemSelectionModel.SelectionFlag.Select) + selection_model.select( + widget.model().index(i, 0), QItemSelectionModel.SelectionFlag.Select + ) self.assertTrue(widget.removeSelectedFields()) _compare(widget, [1, 3, 5, 7, 9]) @@ -237,42 +346,42 @@ def _compare(widget, expected): widget.setSourceFields(self.source_fields) mapping = widget.mapping() - self.assertEqual(mapping[0].field.name(), 'source_field1') + self.assertEqual(mapping[0].field.name(), "source_field1") self.assertEqual(mapping[0].source, '"source_field1"') - self.assertEqual(mapping[0].aggregate, 'concatenate') - self.assertEqual(mapping[0].delimiter, ',') - self.assertEqual(mapping[1].field.name(), 'source_field2') + self.assertEqual(mapping[0].aggregate, "concatenate") + self.assertEqual(mapping[0].delimiter, ",") + self.assertEqual(mapping[1].field.name(), "source_field2") self.assertEqual(mapping[1].source, '"source_field2"') - self.assertEqual(mapping[1].aggregate, 'sum') - self.assertEqual(mapping[1].delimiter, ',') + self.assertEqual(mapping[1].aggregate, "sum") + self.assertEqual(mapping[1].delimiter, ",") mapping[0].source = 'upper("source_field2")' - mapping[0].aggregate = 'first_value' - mapping[0].delimiter = '|' + mapping[0].aggregate = "first_value" + mapping[0].delimiter = "|" new_aggregate = QgsAggregateMappingModel.Aggregate() - new_aggregate.field = QgsField('output_field3', QVariant.Double, len=4, prec=2) - new_aggregate.source = 'randf(1,2)' - new_aggregate.aggregate = 'mean' - new_aggregate.delimiter = '*' + new_aggregate.field = QgsField("output_field3", QVariant.Double, len=4, prec=2) + new_aggregate.source = "randf(1,2)" + new_aggregate.aggregate = "mean" + new_aggregate.delimiter = "*" mapping.append(new_aggregate) widget.setMapping(mapping) mapping = widget.mapping() - self.assertEqual(mapping[0].field.name(), 'source_field1') + self.assertEqual(mapping[0].field.name(), "source_field1") self.assertEqual(mapping[0].source, 'upper("source_field2")') - self.assertEqual(mapping[0].aggregate, 'first_value') - self.assertEqual(mapping[0].delimiter, '|') - self.assertEqual(mapping[1].field.name(), 'source_field2') + self.assertEqual(mapping[0].aggregate, "first_value") + self.assertEqual(mapping[0].delimiter, "|") + self.assertEqual(mapping[1].field.name(), "source_field2") self.assertEqual(mapping[1].source, '"source_field2"') - self.assertEqual(mapping[1].aggregate, 'sum') - self.assertEqual(mapping[1].delimiter, ',') - self.assertEqual(mapping[2].field.name(), 'output_field3') - self.assertEqual(mapping[2].source, 'randf(1,2)') - self.assertEqual(mapping[2].aggregate, 'mean') - self.assertEqual(mapping[2].delimiter, '*') + self.assertEqual(mapping[1].aggregate, "sum") + self.assertEqual(mapping[1].delimiter, ",") + self.assertEqual(mapping[2].field.name(), "output_field3") + self.assertEqual(mapping[2].source, "randf(1,2)") + self.assertEqual(mapping[2].aggregate, "mean") + self.assertEqual(mapping[2].delimiter, "*") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsalignmentcombobox.py b/tests/src/python/test_qgsalignmentcombobox.py index d0879873a481..aaaf2cd45382 100644 --- a/tests/src/python/test_qgsalignmentcombobox.py +++ b/tests/src/python/test_qgsalignmentcombobox.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '26/06/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "26/06/2019" +__copyright__ = "Copyright 2019, The QGIS Project" from qgis.PyQt.QtCore import Qt from qgis.PyQt.QtTest import QSignalSpy @@ -23,9 +24,11 @@ class TestQgsAlignmentComboBox(QgisTestCase): def testGettersSetters(self): - """ test widget getters/setters """ + """test widget getters/setters""" w = QgsAlignmentComboBox() - w.setAvailableAlignments(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignJustify) + w.setAvailableAlignments( + Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignJustify + ) w.setCurrentAlignment(Qt.AlignmentFlag.AlignRight) self.assertEqual(w.currentAlignment(), Qt.AlignmentFlag.AlignRight) w.setCurrentAlignment(Qt.AlignmentFlag.AlignJustify) @@ -35,7 +38,7 @@ def testGettersSetters(self): self.assertEqual(w.currentAlignment(), Qt.AlignmentFlag.AlignJustify) def test_ChangedSignals(self): - """ test that signals are correctly emitted when setting alignment""" + """test that signals are correctly emitted when setting alignment""" w = QgsAlignmentComboBox() spy = QSignalSpy(w.changed) @@ -45,12 +48,16 @@ def test_ChangedSignals(self): self.assertEqual(len(spy), 1) w.setCurrentAlignment(Qt.AlignmentFlag.AlignLeft) self.assertEqual(len(spy), 2) - w.setAvailableAlignments(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignJustify) + w.setAvailableAlignments( + Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignJustify + ) self.assertEqual(len(spy), 3) self.assertEqual(w.currentAlignment(), Qt.AlignmentFlag.AlignRight) - w.setAvailableAlignments(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignRight) + w.setAvailableAlignments( + Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignRight + ) self.assertEqual(len(spy), 3) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsanimatedmarkersymbollayer.py b/tests/src/python/test_qgsanimatedmarkersymbollayer.py index 466b4191b478..01e1ec69c2bf 100644 --- a/tests/src/python/test_qgsanimatedmarkersymbollayer.py +++ b/tests/src/python/test_qgsanimatedmarkersymbollayer.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'April 2022' -__copyright__ = '(C) 2022, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "April 2022" +__copyright__ = "(C) 2022, Nyall Dawson" import os @@ -46,15 +46,14 @@ def control_path_prefix(cls): return "symbol_animatedmarker" def testRenderFrame1(self): - point_shp = os.path.join(TEST_DATA_DIR, 'points.shp') - point_layer = QgsVectorLayer(point_shp, 'Lines', 'ogr') + point_shp = os.path.join(TEST_DATA_DIR, "points.shp") + point_layer = QgsVectorLayer(point_shp, "Lines", "ogr") self.assertTrue(point_layer.isValid()) marker_symbol = QgsMarkerSymbol() marker_symbol.deleteSymbolLayer(0) - marker_symbol.appendSymbolLayer( - QgsAnimatedMarkerSymbolLayer()) - marker_symbol[0].setPath(os.path.join(TEST_DATA_DIR, 'qgis_logo_animated.gif')) + marker_symbol.appendSymbolLayer(QgsAnimatedMarkerSymbolLayer()) + marker_symbol[0].setPath(os.path.join(TEST_DATA_DIR, "qgis_logo_animated.gif")) marker_symbol[0].setSize(20) point_layer.setRenderer(QgsSingleSymbolRenderer(marker_symbol)) @@ -69,22 +68,19 @@ def testRenderFrame1(self): self.assertTrue( self.render_map_settings_check( - 'animatedmarker_frame1', - 'animatedmarker_frame1', - ms + "animatedmarker_frame1", "animatedmarker_frame1", ms ) ) def testRenderFrame2(self): - point_shp = os.path.join(TEST_DATA_DIR, 'points.shp') - point_layer = QgsVectorLayer(point_shp, 'Lines', 'ogr') + point_shp = os.path.join(TEST_DATA_DIR, "points.shp") + point_layer = QgsVectorLayer(point_shp, "Lines", "ogr") self.assertTrue(point_layer.isValid()) marker_symbol = QgsMarkerSymbol() marker_symbol.deleteSymbolLayer(0) - marker_symbol.appendSymbolLayer( - QgsAnimatedMarkerSymbolLayer()) - marker_symbol[0].setPath(os.path.join(TEST_DATA_DIR, 'qgis_logo_animated.gif')) + marker_symbol.appendSymbolLayer(QgsAnimatedMarkerSymbolLayer()) + marker_symbol[0].setPath(os.path.join(TEST_DATA_DIR, "qgis_logo_animated.gif")) marker_symbol[0].setSize(20) point_layer.setRenderer(QgsSingleSymbolRenderer(marker_symbol)) @@ -99,12 +95,10 @@ def testRenderFrame2(self): self.assertTrue( self.render_map_settings_check( - 'animatedmarker_frame2', - 'animatedmarker_frame2', - ms + "animatedmarker_frame2", "animatedmarker_frame2", ms ) ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsannotation.py b/tests/src/python/test_qgsannotation.py index a5eee2462d70..3d82164fc533 100644 --- a/tests/src/python/test_qgsannotation.py +++ b/tests/src/python/test_qgsannotation.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '24/1/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "24/1/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os import tempfile @@ -36,7 +37,7 @@ QgsVectorLayer, QgsAnnotationPictureItem, QgsAnnotationRectangleTextItem, - QgsBalloonCallout + QgsBalloonCallout, ) from qgis.gui import QgsFormAnnotation import unittest @@ -55,38 +56,38 @@ def control_path_prefix(cls): return "annotations" def testTextAnnotation(self): - """ test rendering a text annotation""" + """test rendering a text annotation""" a = QgsTextAnnotation() a.fillSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) a.markerSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) a.setFrameSizeMm(QSizeF(300 / 3.7795275, 200 / 3.7795275)) a.setFrameOffsetFromReferencePointMm(QPointF(40 / 3.7795275, 50 / 3.7795275)) doc = QTextDocument() - doc.setHtml('

    test annotation

    ') + doc.setHtml( + '

    test annotation

    ' + ) a.setDocument(doc) im = self.renderAnnotation(a, QPointF(20, 30)) - self.assertTrue( - self.image_check('text_annotation', 'text_annotation', im) - ) + self.assertTrue(self.image_check("text_annotation", "text_annotation", im)) # check clone clone = a.clone() im = self.renderAnnotation(clone, QPointF(20, 30)) - self.assertTrue( - self.image_check('text_annotation', 'text_annotation', im) - ) + self.assertTrue(self.image_check("text_annotation", "text_annotation", im)) def testTextAnnotationInLayout(self): - """ test rendering a text annotation""" + """test rendering a text annotation""" a = QgsTextAnnotation() a.fillSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) a.markerSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) a.setFrameSizeMm(QSizeF(300 / 3.7795275, 200 / 3.7795275)) a.setFrameOffsetFromReferencePointMm(QPointF(40 / 3.7795275, 50 / 3.7795275)) doc = QTextDocument() - doc.setHtml('

    test annotation

    ') + doc.setHtml( + '

    test annotation

    ' + ) a.setDocument(doc) - self.assertTrue(self.renderAnnotationInLayout('text_annotation_in_layout', a)) + self.assertTrue(self.renderAnnotationInLayout("text_annotation_in_layout", a)) def test_svg_annotation_project_upgrade(self): """ @@ -98,9 +99,8 @@ def test_svg_annotation_project_upgrade(self): a.setFrameSizeMm(QSizeF(300 / 3.7795275, 200 / 3.7795275)) a.setHasFixedMapPosition(True) a.setMapPosition(QgsPointXY(QPointF(20, 30))) - a.setMapPositionCrs(QgsCoordinateReferenceSystem('EPSG:4326')) - a.setFrameOffsetFromReferencePointMm( - QPointF(40 / 3.7795275, 50 / 3.7795275)) + a.setMapPositionCrs(QgsCoordinateReferenceSystem("EPSG:4326")) + a.setFrameOffsetFromReferencePointMm(QPointF(40 / 3.7795275, 50 / 3.7795275)) svg = TEST_DATA_DIR + "/sample_svg.svg" a.setFilePath(svg) @@ -119,7 +119,7 @@ def test_svg_annotation_project_upgrade(self): p2 = QgsProject() with tempfile.TemporaryDirectory() as temp_dir: - path = os.path.join(temp_dir, 'test_project.qgs') + path = os.path.join(temp_dir, "test_project.qgs") p.write(path) p2.read(path) @@ -134,17 +134,18 @@ def test_svg_annotation_project_upgrade(self): self.assertIsInstance(item_a, QgsAnnotationPictureItem) self.assertIsInstance(item_b, QgsAnnotationPictureItem) - self.assertEqual(item_a.calloutAnchor().asWkt(), 'Point (20 30)') + self.assertEqual(item_a.calloutAnchor().asWkt(), "Point (20 30)") self.assertEqual(item_a.placementMode(), Qgis.AnnotationPlacementMode.FixedSize) - self.assertIsInstance(item_a.callout(), - QgsBalloonCallout) + self.assertIsInstance(item_a.callout(), QgsBalloonCallout) self.assertAlmostEqual(item_a.fixedSize().width(), 79.375, 1) self.assertAlmostEqual(item_a.fixedSize().height(), 52.9166, 1) self.assertAlmostEqual(item_a.offsetFromCallout().width(), 10.5833, 1) self.assertAlmostEqual(item_a.offsetFromCallout().height(), 13.229, 1) self.assertIsNone(item_b.callout()) - self.assertEqual(item_b.placementMode(), Qgis.AnnotationPlacementMode.RelativeToMapFrame) + self.assertEqual( + item_b.placementMode(), Qgis.AnnotationPlacementMode.RelativeToMapFrame + ) self.assertAlmostEqual(item_b.fixedSize().width(), 79.375, 1) self.assertAlmostEqual(item_b.fixedSize().height(), 52.9166, 1) self.assertAlmostEqual(item_b.bounds().center().x(), 0.2, 3) @@ -160,10 +161,9 @@ def test_text_annotation_project_upgrade(self): a.setFrameSizeMm(QSizeF(300 / 3.7795275, 200 / 3.7795275)) a.setHasFixedMapPosition(True) a.setMapPosition(QgsPointXY(QPointF(20, 30))) - a.setMapPositionCrs(QgsCoordinateReferenceSystem('EPSG:4326')) - a.setFrameOffsetFromReferencePointMm( - QPointF(40 / 3.7795275, 50 / 3.7795275)) - a.document().setHtml('

    test annotation

    ') + a.setMapPositionCrs(QgsCoordinateReferenceSystem("EPSG:4326")) + a.setFrameOffsetFromReferencePointMm(QPointF(40 / 3.7795275, 50 / 3.7795275)) + a.document().setHtml("

    test annotation

    ") b = QgsTextAnnotation() b.fillSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) @@ -171,7 +171,7 @@ def test_text_annotation_project_upgrade(self): b.setFrameSizeMm(QSizeF(300 / 3.7795275, 200 / 3.7795275)) b.setRelativePosition(QPointF(0.2, 0.7)) b.setHasFixedMapPosition(False) - b.document().setHtml('

    test annotation

    ') + b.document().setHtml("

    test annotation

    ") p = QgsProject() p.annotationManager().addAnnotation(a) @@ -179,7 +179,7 @@ def test_text_annotation_project_upgrade(self): p2 = QgsProject() with tempfile.TemporaryDirectory() as temp_dir: - path = os.path.join(temp_dir, 'test_project.qgs') + path = os.path.join(temp_dir, "test_project.qgs") p.write(path) p2.read(path) @@ -194,24 +194,25 @@ def test_text_annotation_project_upgrade(self): self.assertIsInstance(item_a, QgsAnnotationRectangleTextItem) self.assertIsInstance(item_b, QgsAnnotationRectangleTextItem) - self.assertEqual(item_a.calloutAnchor().asWkt(), 'Point (20 30)') + self.assertEqual(item_a.calloutAnchor().asWkt(), "Point (20 30)") self.assertEqual(item_a.placementMode(), Qgis.AnnotationPlacementMode.FixedSize) - self.assertIsInstance(item_a.callout(), - QgsBalloonCallout) + self.assertIsInstance(item_a.callout(), QgsBalloonCallout) self.assertAlmostEqual(item_a.fixedSize().width(), 79.375, 1) self.assertAlmostEqual(item_a.fixedSize().height(), 52.9166, 1) self.assertAlmostEqual(item_a.offsetFromCallout().width(), 10.5833, 1) self.assertAlmostEqual(item_a.offsetFromCallout().height(), 13.229, 1) self.assertIsNone(item_b.callout()) - self.assertEqual(item_b.placementMode(), Qgis.AnnotationPlacementMode.RelativeToMapFrame) + self.assertEqual( + item_b.placementMode(), Qgis.AnnotationPlacementMode.RelativeToMapFrame + ) self.assertAlmostEqual(item_b.fixedSize().width(), 79.375, 1) self.assertAlmostEqual(item_b.fixedSize().height(), 52.9166, 1) self.assertAlmostEqual(item_b.bounds().center().x(), 0.2, 3) self.assertAlmostEqual(item_b.bounds().center().y(), 0.7, 3) def testSvgAnnotation(self): - """ test rendering a svg annotation""" + """test rendering a svg annotation""" a = QgsSvgAnnotation() a.fillSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) a.markerSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) @@ -220,19 +221,15 @@ def testSvgAnnotation(self): svg = TEST_DATA_DIR + "/sample_svg.svg" a.setFilePath(svg) im = self.renderAnnotation(a, QPointF(20, 30)) - self.assertTrue( - self.image_check('svg_annotation', 'svg_annotation', im) - ) + self.assertTrue(self.image_check("svg_annotation", "svg_annotation", im)) # check clone clone = a.clone() im = self.renderAnnotation(clone, QPointF(20, 30)) - self.assertTrue( - self.image_check('svg_annotation', 'svg_annotation', im) - ) + self.assertTrue(self.image_check("svg_annotation", "svg_annotation", im)) def testSvgAnnotationInLayout(self): - """ test rendering a svg annotation""" + """test rendering a svg annotation""" a = QgsSvgAnnotation() a.fillSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) a.markerSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) @@ -240,10 +237,10 @@ def testSvgAnnotationInLayout(self): a.setFrameOffsetFromReferencePointMm(QPointF(40 / 3.7795275, 50 / 3.7795275)) svg = TEST_DATA_DIR + "/sample_svg.svg" a.setFilePath(svg) - self.assertTrue(self.renderAnnotationInLayout('svg_annotation_in_layout', a)) + self.assertTrue(self.renderAnnotationInLayout("svg_annotation_in_layout", a)) def testHtmlAnnotation(self): - """ test rendering a html annotation""" + """test rendering a html annotation""" a = QgsHtmlAnnotation() a.fillSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) a.markerSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) @@ -252,19 +249,15 @@ def testHtmlAnnotation(self): html = TEST_DATA_DIR + "/test_html.html" a.setSourceFile(html) im = self.renderAnnotation(a, QPointF(20, 30)) - self.assertTrue( - self.image_check('html_annotation', 'html_annotation', im) - ) + self.assertTrue(self.image_check("html_annotation", "html_annotation", im)) # check clone clone = a.clone() im = self.renderAnnotation(clone, QPointF(20, 30)) - self.assertTrue( - self.image_check('html_annotation', 'html_annotation', im) - ) + self.assertTrue(self.image_check("html_annotation", "html_annotation", im)) def testHtmlAnnotationSetHtmlSource(self): - """ test rendering html annotation where the html is set directly (not from file)""" + """test rendering html annotation where the html is set directly (not from file)""" a = QgsHtmlAnnotation() a.fillSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) a.markerSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) @@ -275,13 +268,11 @@ def testHtmlAnnotationSetHtmlSource(self): a.setHtmlSource(htmlText) im = self.renderAnnotation(a, QPointF(20, 30)) self.assertTrue( - self.image_check( - 'html_annotation_html_source', 'html_annotation', im - ) + self.image_check("html_annotation_html_source", "html_annotation", im) ) def testHtmlAnnotationInLayout(self): - """ test rendering a svg annotation""" + """test rendering a svg annotation""" a = QgsHtmlAnnotation() a.fillSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) a.markerSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) @@ -289,12 +280,15 @@ def testHtmlAnnotationInLayout(self): a.setFrameOffsetFromReferencePointMm(QPointF(70 / 3.7795275, 90 / 3.7795275)) html = TEST_DATA_DIR + "/test_html.html" a.setSourceFile(html) - self.assertTrue(self.renderAnnotationInLayout('html_annotation_in_layout', a)) + self.assertTrue(self.renderAnnotationInLayout("html_annotation_in_layout", a)) def testHtmlAnnotationWithFeature(self): - """ test rendering a html annotation with a feature""" - layer = QgsVectorLayer("Point?crs=EPSG:3111&field=station:string&field=suburb:string", - 'test', "memory") + """test rendering a html annotation with a feature""" + layer = QgsVectorLayer( + "Point?crs=EPSG:3111&field=station:string&field=suburb:string", + "test", + "memory", + ) a = QgsHtmlAnnotation() a.fillSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) @@ -305,20 +299,16 @@ def testHtmlAnnotationWithFeature(self): html = TEST_DATA_DIR + "/test_html_feature.html" a.setSourceFile(html) im = self.renderAnnotation(a, QPointF(20, 30)) - self.assertTrue( - self.image_check('html_nofeature', 'html_nofeature', im) - ) + self.assertTrue(self.image_check("html_nofeature", "html_nofeature", im)) f = QgsFeature(layer.fields()) f.setValid(True) - f.setAttributes(['hurstbridge', 'somewhere']) + f.setAttributes(["hurstbridge", "somewhere"]) a.setAssociatedFeature(f) im = self.renderAnnotation(a, QPointF(20, 30)) - self.assertTrue( - self.image_check('html_feature', 'html_feature', im) - ) + self.assertTrue(self.image_check("html_feature", "html_feature", im)) def testFormAnnotation(self): - """ test rendering a form annotation""" + """test rendering a form annotation""" a = QgsFormAnnotation() a.fillSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) a.markerSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) @@ -327,19 +317,15 @@ def testFormAnnotation(self): ui = TEST_DATA_DIR + "/test_form.ui" a.setDesignerForm(ui) im = self.renderAnnotation(a, QPointF(20, 30)) - self.assertTrue( - self.image_check('form_annotation', 'form_annotation', im) - ) + self.assertTrue(self.image_check("form_annotation", "form_annotation", im)) # check clone clone = a.clone() im = self.renderAnnotation(clone, QPointF(20, 30)) - self.assertTrue( - self.image_check('form_annotation', 'form_annotation', im) - ) + self.assertTrue(self.image_check("form_annotation", "form_annotation", im)) def testFormAnnotationInLayout(self): - """ test rendering a form annotation""" + """test rendering a form annotation""" a = QgsFormAnnotation() a.fillSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) a.markerSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) @@ -347,10 +333,10 @@ def testFormAnnotationInLayout(self): a.setFrameOffsetFromReferencePointMm(QPointF(70 / 3.7795275, 90 / 3.7795275)) ui = TEST_DATA_DIR + "/test_form.ui" a.setDesignerForm(ui) - self.assertTrue(self.renderAnnotationInLayout('form_annotation_in_layout', a)) + self.assertTrue(self.renderAnnotationInLayout("form_annotation_in_layout", a)) def testRelativePosition(self): - """ test rendering an annotation without map point""" + """test rendering an annotation without map point""" a = QgsHtmlAnnotation() a.fillSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) a.setFrameSizeMm(QSizeF(400 / 3.7795275, 250 / 3.7795275)) @@ -358,12 +344,10 @@ def testRelativePosition(self): html = TEST_DATA_DIR + "/test_html.html" a.setSourceFile(html) im = self.renderAnnotation(a, QPointF(20, 30)) - self.assertTrue( - self.image_check('relative_style', 'relative_style', im) - ) + self.assertTrue(self.image_check("relative_style", "relative_style", im)) def testMargins(self): - """ test rendering an annotation with margins""" + """test rendering an annotation with margins""" a = QgsHtmlAnnotation() a.fillSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) a.setFrameSizeMm(QSizeF(400 / 3.7795275, 250 / 3.7795275)) @@ -373,20 +357,22 @@ def testMargins(self): a.setSourceFile(html) im = self.renderAnnotation(a, QPointF(20, 30)) self.assertTrue( - self.image_check('annotation_margins', 'annotation_margins', im) + self.image_check("annotation_margins", "annotation_margins", im) ) def testFillSymbol(self): - """ test rendering an annotation with fill symbol""" + """test rendering an annotation with fill symbol""" a = QgsTextAnnotation() a.setFrameSizeMm(QSizeF(400 / 3.7795275, 250 / 3.7795275)) a.setHasFixedMapPosition(False) - a.setFillSymbol(QgsFillSymbol.createSimple({'color': 'blue', 'width_border': '5', 'outline_color': 'black'})) + a.setFillSymbol( + QgsFillSymbol.createSimple( + {"color": "blue", "width_border": "5", "outline_color": "black"} + ) + ) im = self.renderAnnotation(a, QPointF(20, 30)) self.assertTrue( - self.image_check( - 'annotation_fillstyle', 'annotation_fillstyle', im - ) + self.image_check("annotation_fillstyle", "annotation_fillstyle", im) ) def renderAnnotation(self, annotation, offset): @@ -396,7 +382,7 @@ def renderAnnotation(self, annotation, offset): painter = QPainter() ms = QgsMapSettings() - ms.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + ms.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) extent = QgsRectangle(0, 5, 40, 30) ms.setExtent(extent) @@ -427,11 +413,9 @@ def renderAnnotationInLayout(self, test_name, annotation): pr.annotationManager().addAnnotation(annotation) return self.render_layout_check( - test_name, - layout=l, - size=QSize(1122 * 2, 794 * 2) + test_name, layout=l, size=QSize(1122 * 2, 794 * 2) ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsannotationitemeditoperation.py b/tests/src/python/test_qgsannotationitemeditoperation.py index 7351b7a91ec9..20dc4eac366b 100644 --- a/tests/src/python/test_qgsannotationitemeditoperation.py +++ b/tests/src/python/test_qgsannotationitemeditoperation.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 by Nyall Dawson' -__date__ = '09/09/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 by Nyall Dawson" +__date__ = "09/09/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.core import ( QgsAnnotationItemEditOperationAddNode, @@ -31,29 +32,33 @@ class TestQgsAnnotationItemEditOperation(QgisTestCase): def test_move_operation(self): - operation = QgsAnnotationItemEditOperationMoveNode('item id', QgsVertexId(1, 2, 3), QgsPoint(4, 5), QgsPoint(6, 7)) - self.assertEqual(operation.itemId(), 'item id') + operation = QgsAnnotationItemEditOperationMoveNode( + "item id", QgsVertexId(1, 2, 3), QgsPoint(4, 5), QgsPoint(6, 7) + ) + self.assertEqual(operation.itemId(), "item id") self.assertEqual(operation.nodeId(), QgsVertexId(1, 2, 3)) self.assertEqual(operation.before(), QgsPoint(4, 5)) self.assertEqual(operation.after(), QgsPoint(6, 7)) def test_delete_node_operation(self): - operation = QgsAnnotationItemEditOperationDeleteNode('item id', QgsVertexId(1, 2, 3), QgsPoint(6, 7)) - self.assertEqual(operation.itemId(), 'item id') + operation = QgsAnnotationItemEditOperationDeleteNode( + "item id", QgsVertexId(1, 2, 3), QgsPoint(6, 7) + ) + self.assertEqual(operation.itemId(), "item id") self.assertEqual(operation.nodeId(), QgsVertexId(1, 2, 3)) self.assertEqual(operation.before(), QgsPoint(6, 7)) def test_add_node_operation(self): - operation = QgsAnnotationItemEditOperationAddNode('item id', QgsPoint(6, 7)) - self.assertEqual(operation.itemId(), 'item id') + operation = QgsAnnotationItemEditOperationAddNode("item id", QgsPoint(6, 7)) + self.assertEqual(operation.itemId(), "item id") self.assertEqual(operation.point(), QgsPoint(6, 7)) def test_translate_operation(self): - operation = QgsAnnotationItemEditOperationTranslateItem('item id', 6, 7) - self.assertEqual(operation.itemId(), 'item id') + operation = QgsAnnotationItemEditOperationTranslateItem("item id", 6, 7) + self.assertEqual(operation.itemId(), "item id") self.assertEqual(operation.translationX(), 6) self.assertEqual(operation.translationY(), 7) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsannotationitemnode.py b/tests/src/python/test_qgsannotationitemnode.py index 12de1ba236c4..6958011ecec2 100644 --- a/tests/src/python/test_qgsannotationitemnode.py +++ b/tests/src/python/test_qgsannotationitemnode.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 by Nyall Dawson' -__date__ = '29/07/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 by Nyall Dawson" +__date__ = "29/07/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.core import Qgis, QgsAnnotationItemNode, QgsPointXY, QgsVertexId import unittest @@ -24,7 +25,11 @@ class TestQgsAnnotationItemNode(QgisTestCase): def test_basic(self): - node = QgsAnnotationItemNode(QgsVertexId(0, 0, 1), QgsPointXY(1, 2), Qgis.AnnotationItemNodeType.VertexHandle) + node = QgsAnnotationItemNode( + QgsVertexId(0, 0, 1), + QgsPointXY(1, 2), + Qgis.AnnotationItemNodeType.VertexHandle, + ) self.assertEqual(node.point(), QgsPointXY(1, 2)) self.assertEqual(node.id(), QgsVertexId(0, 0, 1)) @@ -34,21 +39,41 @@ def test_basic(self): self.assertEqual(node.type(), Qgis.AnnotationItemNodeType.VertexHandle) def test_repr(self): - node = QgsAnnotationItemNode(QgsVertexId(0, 0, 1), QgsPointXY(1, 2), Qgis.AnnotationItemNodeType.VertexHandle) - self.assertEqual(str(node), '') + node = QgsAnnotationItemNode( + QgsVertexId(0, 0, 1), + QgsPointXY(1, 2), + Qgis.AnnotationItemNodeType.VertexHandle, + ) + self.assertEqual(str(node), "") def test_equality(self): - node = QgsAnnotationItemNode(QgsVertexId(0, 0, 1), QgsPointXY(1, 2), Qgis.AnnotationItemNodeType.VertexHandle) - node2 = QgsAnnotationItemNode(QgsVertexId(0, 0, 1), QgsPointXY(1, 2), Qgis.AnnotationItemNodeType.VertexHandle) + node = QgsAnnotationItemNode( + QgsVertexId(0, 0, 1), + QgsPointXY(1, 2), + Qgis.AnnotationItemNodeType.VertexHandle, + ) + node2 = QgsAnnotationItemNode( + QgsVertexId(0, 0, 1), + QgsPointXY(1, 2), + Qgis.AnnotationItemNodeType.VertexHandle, + ) self.assertEqual(node, node2) node2.setPoint(QgsPointXY(3, 4)) self.assertNotEqual(node, node2) - node = QgsAnnotationItemNode(QgsVertexId(0, 0, 1), QgsPointXY(1, 2), Qgis.AnnotationItemNodeType.VertexHandle) - node2 = QgsAnnotationItemNode(QgsVertexId(0, 0, 2), QgsPointXY(1, 2), Qgis.AnnotationItemNodeType.VertexHandle) + node = QgsAnnotationItemNode( + QgsVertexId(0, 0, 1), + QgsPointXY(1, 2), + Qgis.AnnotationItemNodeType.VertexHandle, + ) + node2 = QgsAnnotationItemNode( + QgsVertexId(0, 0, 2), + QgsPointXY(1, 2), + Qgis.AnnotationItemNodeType.VertexHandle, + ) self.assertNotEqual(node, node2) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsannotationlayer.py b/tests/src/python/test_qgsannotationlayer.py index 8a75ab47e3ed..9f52e1113d02 100644 --- a/tests/src/python/test_qgsannotationlayer.py +++ b/tests/src/python/test_qgsannotationlayer.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 by Nyall Dawson' -__date__ = '29/07/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 by Nyall Dawson" +__date__ = "29/07/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QSize, QTemporaryDir from qgis.PyQt.QtGui import QColor, QImage, QPainter @@ -39,7 +40,7 @@ QgsRectangle, QgsRenderContext, QgsVertexId, - QgsVectorLayer + QgsVectorLayer, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -54,20 +55,38 @@ class TestQgsAnnotationLayer(QgisTestCase): @classmethod def control_path_prefix(cls): - return 'annotation_layer' + return "annotation_layer" def testItems(self): - layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) + layer = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) self.assertTrue(layer.isValid()) self.assertTrue(layer.isEmpty()) - self.assertIsNone(layer.item('xxxx')) - self.assertIsNone(layer.item('')) - - polygon_item_id = layer.addItem(QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)])))) + self.assertIsNone(layer.item("xxxx")) + self.assertIsNone(layer.item("")) + + polygon_item_id = layer.addItem( + QgsAnnotationPolygonItem( + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) + ) linestring_item_id = layer.addItem( - QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]))) + QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]) + ) + ) marker_item_id = layer.addItem(QgsAnnotationMarkerItem(QgsPoint(12, 13))) self.assertEqual(len(layer.items()), 3) @@ -80,10 +99,10 @@ def testItems(self): self.assertIsInstance(layer.item(polygon_item_id), QgsAnnotationPolygonItem) self.assertIsInstance(layer.item(linestring_item_id), QgsAnnotationLineItem) self.assertIsInstance(layer.item(marker_item_id), QgsAnnotationMarkerItem) - self.assertIsNone(layer.item('xxxx')) - self.assertIsNone(layer.item('')) + self.assertIsNone(layer.item("xxxx")) + self.assertIsNone(layer.item("")) - self.assertFalse(layer.removeItem('xxxx')) + self.assertFalse(layer.removeItem("xxxx")) self.assertEqual(len(layer.items()), 3) self.assertTrue(layer.removeItem(linestring_item_id)) self.assertEqual(len(layer.items()), 2) @@ -99,9 +118,25 @@ def testItems(self): self.assertEqual(len(layer.items()), 0) self.assertTrue(layer.isEmpty()) - layer.addItem(QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)])))) - layer.addItem(QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]))) + layer.addItem( + QgsAnnotationPolygonItem( + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) + ) + layer.addItem( + QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]) + ) + ) layer.addItem(QgsAnnotationMarkerItem(QgsPoint(12, 13))) self.assertEqual(len(layer.items()), 3) @@ -109,32 +144,85 @@ def testItems(self): self.assertEqual(len(layer.items()), 0) def testReplaceItem(self): - layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) - - polygon_item_id = layer.addItem(QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)])))) + layer = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) + + polygon_item_id = layer.addItem( + QgsAnnotationPolygonItem( + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) + ) linestring_item_id = layer.addItem( - QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]))) + QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]) + ) + ) marker_item_id = layer.addItem(QgsAnnotationMarkerItem(QgsPoint(12, 13))) - self.assertEqual(layer.item(polygon_item_id).geometry().asWkt(), 'Polygon ((12 13, 14 13, 14 15, 12 13))') - self.assertEqual(layer.item(linestring_item_id).geometry().asWkt(), 'LineString (11 13, 12 13, 12 15)') - self.assertEqual(layer.item(marker_item_id).geometry().asWkt(), 'POINT(12 13)') - - layer.replaceItem(linestring_item_id, - QgsAnnotationLineItem(QgsLineString([QgsPoint(21, 13), QgsPoint(22, 13), QgsPoint(22, 15)]))) - self.assertEqual(layer.item(polygon_item_id).geometry().asWkt(), 'Polygon ((12 13, 14 13, 14 15, 12 13))') - self.assertEqual(layer.item(linestring_item_id).geometry().asWkt(), 'LineString (21 13, 22 13, 22 15)') - self.assertEqual(layer.item(marker_item_id).geometry().asWkt(), 'POINT(12 13)') + self.assertEqual( + layer.item(polygon_item_id).geometry().asWkt(), + "Polygon ((12 13, 14 13, 14 15, 12 13))", + ) + self.assertEqual( + layer.item(linestring_item_id).geometry().asWkt(), + "LineString (11 13, 12 13, 12 15)", + ) + self.assertEqual(layer.item(marker_item_id).geometry().asWkt(), "POINT(12 13)") + + layer.replaceItem( + linestring_item_id, + QgsAnnotationLineItem( + QgsLineString([QgsPoint(21, 13), QgsPoint(22, 13), QgsPoint(22, 15)]) + ), + ) + self.assertEqual( + layer.item(polygon_item_id).geometry().asWkt(), + "Polygon ((12 13, 14 13, 14 15, 12 13))", + ) + self.assertEqual( + layer.item(linestring_item_id).geometry().asWkt(), + "LineString (21 13, 22 13, 22 15)", + ) + self.assertEqual(layer.item(marker_item_id).geometry().asWkt(), "POINT(12 13)") def testReset(self): - layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) + layer = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) self.assertTrue(layer.isValid()) - layer.addItem(QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)])))) - layer.addItem(QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]))) + layer.addItem( + QgsAnnotationPolygonItem( + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) + ) + layer.addItem( + QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]) + ) + ) layer.addItem(QgsAnnotationMarkerItem(QgsPoint(12, 13))) - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) layer.setOpacity(0.5) layer.reset() @@ -144,12 +232,31 @@ def testReset(self): self.assertEqual(layer.undoStackStyles().count(), 0) def testExtent(self): - layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) + layer = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) self.assertTrue(layer.isValid()) - layer.addItem(QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)])))) - layer.addItem(QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]))) + layer.addItem( + QgsAnnotationPolygonItem( + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) + ) + layer.addItem( + QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]) + ) + ) layer.addItem(QgsAnnotationMarkerItem(QgsPoint(12, 13))) extent = layer.extent() @@ -159,7 +266,7 @@ def testExtent(self): self.assertEqual(extent.yMaximum(), 15.0) # should have no effect -- item geometries are in layer crs - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) extent = layer.extent() self.assertEqual(extent.xMinimum(), 11.0) self.assertEqual(extent.xMaximum(), 14.0) @@ -167,51 +274,97 @@ def testExtent(self): self.assertEqual(extent.yMaximum(), 15.0) def testItemsInBounds(self): - layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) + layer = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) self.assertTrue(layer.isValid()) - item1uuid = layer.addItem(QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)])))) + item1uuid = layer.addItem( + QgsAnnotationPolygonItem( + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) + ) item2uuid = layer.addItem( - QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 150)]))) + QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 150)]) + ) + ) item3uuid = layer.addItem(QgsAnnotationMarkerItem(QgsPoint(120, 13))) rc = QgsRenderContext() self.assertFalse(layer.itemsInBounds(QgsRectangle(-10, -10, -9, 9), rc)) - self.assertCountEqual(layer.itemsInBounds(QgsRectangle(12, 13, 14, 15), rc), [item1uuid, item2uuid]) - self.assertCountEqual(layer.itemsInBounds(QgsRectangle(12, 130, 14, 150), rc), [item2uuid]) - self.assertCountEqual(layer.itemsInBounds(QgsRectangle(110, 0, 120, 20), rc), [item3uuid]) + self.assertCountEqual( + layer.itemsInBounds(QgsRectangle(12, 13, 14, 15), rc), + [item1uuid, item2uuid], + ) + self.assertCountEqual( + layer.itemsInBounds(QgsRectangle(12, 130, 14, 150), rc), [item2uuid] + ) + self.assertCountEqual( + layer.itemsInBounds(QgsRectangle(110, 0, 120, 20), rc), [item3uuid] + ) def testReadWriteXml(self): doc = QDomDocument("testdoc") - layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) + layer = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) self.assertTrue(layer.isValid()) - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) layer.setScaleBasedVisibility(True) - QgsLayerNotesUtils.setLayerNotes(layer, 'test layer notes') + QgsLayerNotesUtils.setLayerNotes(layer, "test layer notes") - other_layer = QgsVectorLayer('Point', 'test', 'memory') + other_layer = QgsVectorLayer("Point", "test", "memory") QgsProject.instance().addMapLayer(other_layer) layer.setLinkedVisibilityLayer(other_layer) self.assertEqual(layer.linkedVisibilityLayer(), other_layer) - polygon_item_id = layer.addItem(QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)])))) + polygon_item_id = layer.addItem( + QgsAnnotationPolygonItem( + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) + ) linestring_item_id = layer.addItem( - QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]))) + QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]) + ) + ) marker_item_id = layer.addItem(QgsAnnotationMarkerItem(QgsPoint(12, 13))) elem = doc.createElement("maplayer") self.assertTrue(layer.writeLayerXml(elem, doc, QgsReadWriteContext())) - layer2 = QgsAnnotationLayer('test2', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) + layer2 = QgsAnnotationLayer( + "test2", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) self.assertTrue(layer2.readLayerXml(elem, QgsReadWriteContext())) layer2.resolveReferences(QgsProject.instance()) - self.assertEqual(layer2.crs().authid(), 'EPSG:4326') + self.assertEqual(layer2.crs().authid(), "EPSG:4326") self.assertTrue(layer2.hasScaleBasedVisibility()) - self.assertEqual(QgsLayerNotesUtils.layerNotes(layer2), 'test layer notes') + self.assertEqual(QgsLayerNotesUtils.layerNotes(layer2), "test layer notes") self.assertEqual(layer2.linkedVisibilityLayer(), other_layer) self.assertEqual(len(layer2.items()), 3) @@ -220,16 +373,34 @@ def testReadWriteXml(self): self.assertIsInstance(layer2.items()[marker_item_id], QgsAnnotationMarkerItem) def testClone(self): - layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) + layer = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) self.assertTrue(layer.isValid()) - polygon_item_id = layer.addItem(QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)])))) + polygon_item_id = layer.addItem( + QgsAnnotationPolygonItem( + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) + ) linestring_item_id = layer.addItem( - QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]))) + QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]) + ) + ) marker_item_id = layer.addItem(QgsAnnotationMarkerItem(QgsPoint(12, 13))) - other_layer = QgsVectorLayer('Point', 'test', 'memory') + other_layer = QgsVectorLayer("Point", "test", "memory") QgsProject.instance().addMapLayer(other_layer) layer.setLinkedVisibilityLayer(other_layer) @@ -238,7 +409,9 @@ def testClone(self): self.assertEqual(len(layer2.items()), 3) self.assertIsInstance(layer2.items()[polygon_item_id], QgsAnnotationPolygonItem) # should not be the SAME instance of the item -- the item must have been cloned for the cloned layer! - self.assertNotEqual(layer.items()[polygon_item_id], layer2.items()[polygon_item_id]) + self.assertNotEqual( + layer.items()[polygon_item_id], layer2.items()[polygon_item_id] + ) self.assertIsInstance(layer2.items()[linestring_item_id], QgsAnnotationLineItem) self.assertIsInstance(layer2.items()[marker_item_id], QgsAnnotationMarkerItem) self.assertEqual(layer2.linkedVisibilityLayer(), other_layer) @@ -248,11 +421,28 @@ def testProjectMainAnnotationLayer(self): self.assertIsNotNone(p.mainAnnotationLayer()) # add some items to project annotation layer - polygon_item_id = p.mainAnnotationLayer().addItem(QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)])))) + polygon_item_id = p.mainAnnotationLayer().addItem( + QgsAnnotationPolygonItem( + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) + ) linestring_item_id = p.mainAnnotationLayer().addItem( - QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]))) - marker_item_id = p.mainAnnotationLayer().addItem(QgsAnnotationMarkerItem(QgsPoint(12, 13))) + QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]) + ) + ) + marker_item_id = p.mainAnnotationLayer().addItem( + QgsAnnotationMarkerItem(QgsPoint(12, 13)) + ) # save project to xml tmpDir = QTemporaryDir() @@ -267,80 +457,163 @@ def testProjectMainAnnotationLayer(self): p2 = QgsProject() self.assertTrue(p2.read(tmpFile)) self.assertEqual(len(p2.mainAnnotationLayer().items()), 3) - self.assertIsInstance(p2.mainAnnotationLayer().items()[polygon_item_id], QgsAnnotationPolygonItem) - self.assertIsInstance(p2.mainAnnotationLayer().items()[linestring_item_id], QgsAnnotationLineItem) - self.assertIsInstance(p2.mainAnnotationLayer().items()[marker_item_id], QgsAnnotationMarkerItem) + self.assertIsInstance( + p2.mainAnnotationLayer().items()[polygon_item_id], QgsAnnotationPolygonItem + ) + self.assertIsInstance( + p2.mainAnnotationLayer().items()[linestring_item_id], QgsAnnotationLineItem + ) + self.assertIsInstance( + p2.mainAnnotationLayer().items()[marker_item_id], QgsAnnotationMarkerItem + ) def testMainAnnotationLayerCrs(self): p = QgsProject() self.assertEqual(p.crs(), p.mainAnnotationLayer().crs()) # main annotation layer should follow project crs - p.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) + p.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertEqual(p.crs(), p.mainAnnotationLayer().crs()) - p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + p.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) self.assertEqual(p.crs(), p.mainAnnotationLayer().crs()) # add an item, should lock in the crs for the main annotation layer - p.mainAnnotationLayer().addItem(QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)])))) - - p.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) - self.assertEqual(p.mainAnnotationLayer().crs().authid(), 'EPSG:4326') + p.mainAnnotationLayer().addItem( + QgsAnnotationPolygonItem( + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) + ) + + p.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) + self.assertEqual(p.mainAnnotationLayer().crs().authid(), "EPSG:4326") def test_apply_edit(self): """ Test applying edits to a layer """ - layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) + layer = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) self.assertTrue(layer.isValid()) - polygon_item_id = layer.addItem(QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)])))) + polygon_item_id = layer.addItem( + QgsAnnotationPolygonItem( + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) + ) linestring_item_id = layer.addItem( - QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]))) + QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]) + ) + ) marker_item_id = layer.addItem(QgsAnnotationMarkerItem(QgsPoint(12, 13))) rc = QgsRenderContext() - self.assertCountEqual(layer.itemsInBounds(QgsRectangle(1, 1, 20, 20), rc), [polygon_item_id, linestring_item_id, marker_item_id]) + self.assertCountEqual( + layer.itemsInBounds(QgsRectangle(1, 1, 20, 20), rc), + [polygon_item_id, linestring_item_id, marker_item_id], + ) # can't apply a move to an item which doesn't exist in the layer - self.assertEqual(layer.applyEdit(QgsAnnotationItemEditOperationMoveNode('xxx', QgsVertexId(0, 0, 2), QgsPoint(14, 15), QgsPoint(19, 15))), Qgis.AnnotationItemEditOperationResult.Invalid) + self.assertEqual( + layer.applyEdit( + QgsAnnotationItemEditOperationMoveNode( + "xxx", QgsVertexId(0, 0, 2), QgsPoint(14, 15), QgsPoint(19, 15) + ) + ), + Qgis.AnnotationItemEditOperationResult.Invalid, + ) # apply move to polygon - self.assertEqual(layer.applyEdit( - QgsAnnotationItemEditOperationMoveNode(polygon_item_id, QgsVertexId(0, 0, 2), QgsPoint(14, 15), - QgsPoint(19, 15))), Qgis.AnnotationItemEditOperationResult.Success) + self.assertEqual( + layer.applyEdit( + QgsAnnotationItemEditOperationMoveNode( + polygon_item_id, + QgsVertexId(0, 0, 2), + QgsPoint(14, 15), + QgsPoint(19, 15), + ) + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) - self.assertEqual(layer.item(polygon_item_id).geometry().asWkt(), 'Polygon ((12 13, 14 13, 19 15, 12 13))') + self.assertEqual( + layer.item(polygon_item_id).geometry().asWkt(), + "Polygon ((12 13, 14 13, 19 15, 12 13))", + ) # ensure that spatial index was updated - self.assertCountEqual(layer.itemsInBounds(QgsRectangle(18, 1, 20, 16), rc), [polygon_item_id]) + self.assertCountEqual( + layer.itemsInBounds(QgsRectangle(18, 1, 20, 16), rc), [polygon_item_id] + ) def testRenderLayer(self): - layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + layer = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) self.assertTrue(layer.isValid()) item = QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)]))) + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) item.setSymbol( - QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2'})) + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black", "outline_width": "2"} + ) + ) item.setZIndex(3) i1_id = layer.addItem(item) - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])) - item.setSymbol(QgsLineSymbol.createSimple({'color': '#ffff00', 'line_width': '3'})) + item = QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]) + ) + item.setSymbol( + QgsLineSymbol.createSimple({"color": "#ffff00", "line_width": "3"}) + ) item.setZIndex(2) i2_id = layer.addItem(item) item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) - item.setSymbol(QgsMarkerSymbol.createSimple({'color': '100,200,200', 'size': '6', 'outline_color': 'black'})) + item.setSymbol( + QgsMarkerSymbol.createSimple( + {"color": "100,200,200", "size": "6", "outline_color": "black"} + ) + ) item.setZIndex(1) i3_id = layer.addItem(item) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(300, 300)) @@ -360,53 +633,93 @@ def testRenderLayer(self): finally: painter.end() - self.assertTrue(self.image_check('layer_render', 'layer_render', image)) + self.assertTrue(self.image_check("layer_render", "layer_render", image)) # also check details of rendered items item_details = renderer.takeRenderedItemDetails() self.assertEqual([i.layerId() for i in item_details], [layer.id()] * 3) self.assertCountEqual([i.itemId() for i in item_details], [i1_id, i2_id, i3_id]) - self.assertEqual([i.boundingBox() for i in item_details if i.itemId() == i1_id][0], - QgsRectangle(12, 13, 14, 15)) - self.assertEqual([i.boundingBox() for i in item_details if i.itemId() == i2_id][0], - QgsRectangle(11, 13, 12, 15)) - self.assertEqual([i.boundingBox().toString(1) for i in item_details if i.itemId() == i3_id][0], - '11.7,12.7 : 12.3,13.3') + self.assertEqual( + [i.boundingBox() for i in item_details if i.itemId() == i1_id][0], + QgsRectangle(12, 13, 14, 15), + ) + self.assertEqual( + [i.boundingBox() for i in item_details if i.itemId() == i2_id][0], + QgsRectangle(11, 13, 12, 15), + ) + self.assertEqual( + [i.boundingBox().toString(1) for i in item_details if i.itemId() == i3_id][ + 0 + ], + "11.7,12.7 : 12.3,13.3", + ) def testRenderWithTransform(self): - layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) + layer = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) self.assertTrue(layer.isValid()) item = QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(11.5, 13), QgsPoint(12, 13), QgsPoint(12, 13.5), QgsPoint(11.5, 13)]))) + QgsPolygon( + QgsLineString( + [ + QgsPoint(11.5, 13), + QgsPoint(12, 13), + QgsPoint(12, 13.5), + QgsPoint(11.5, 13), + ] + ) + ) + ) item.setSymbol( - QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2'})) + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black", "outline_width": "2"} + ) + ) item.setZIndex(1) i1_id = layer.addItem(item) - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])) - item.setSymbol(QgsLineSymbol.createSimple({'color': '#ffff00', 'line_width': '3'})) + item = QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]) + ) + item.setSymbol( + QgsLineSymbol.createSimple({"color": "#ffff00", "line_width": "3"}) + ) item.setZIndex(2) i2_id = layer.addItem(item) item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) - item.setSymbol(QgsMarkerSymbol.createSimple({'color': '100,200,200', 'size': '6', 'outline_color': 'black'})) + item.setSymbol( + QgsMarkerSymbol.createSimple( + {"color": "100,200,200", "size": "6", "outline_color": "black"} + ) + ) item.setZIndex(3) i3_id = layer.addItem(item) - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) settings.setExtent(QgsRectangle(1250958, 1386945, 1420709, 1532518)) settings.setOutputSize(QSize(300, 300)) settings.setFlag(QgsMapSettings.Flag.Antialiasing, False) rc = QgsRenderContext.fromMapSettings(settings) - rc.setCoordinateTransform(QgsCoordinateTransform(layer.crs(), settings.destinationCrs(), QgsProject.instance())) + rc.setCoordinateTransform( + QgsCoordinateTransform( + layer.crs(), settings.destinationCrs(), QgsProject.instance() + ) + ) rc.setExtent( - rc.coordinateTransform().transformBoundingBox(settings.extent(), QgsCoordinateTransform.TransformDirection.ReverseTransform)) + rc.coordinateTransform().transformBoundingBox( + settings.extent(), + QgsCoordinateTransform.TransformDirection.ReverseTransform, + ) + ) image = QImage(200, 200, QImage.Format.Format_ARGB32) image.setDotsPerMeterX(int(96 / 25.4 * 1000)) image.setDotsPerMeterY(int(96 / 25.4 * 1000)) @@ -420,43 +733,77 @@ def testRenderWithTransform(self): finally: painter.end() - self.assertTrue(self.image_check('layer_render_transform', 'layer_render_transform', image)) + self.assertTrue( + self.image_check("layer_render_transform", "layer_render_transform", image) + ) # also check details of rendered items item_details = renderer.takeRenderedItemDetails() self.assertEqual([i.layerId() for i in item_details], [layer.id()] * 3) self.assertCountEqual([i.itemId() for i in item_details], [i1_id, i2_id, i3_id]) - self.assertEqual([i.boundingBox() for i in item_details if i.itemId() == i1_id][0], - QgsRectangle(11.5, 13, 12, 13.5)) - self.assertEqual([i.boundingBox() for i in item_details if i.itemId() == i2_id][0], - QgsRectangle(11, 13, 12, 15)) - self.assertEqual([i.boundingBox().toString(2) for i in item_details if i.itemId() == i3_id][0], - '11.94,12.94 : 12.06,13.06') + self.assertEqual( + [i.boundingBox() for i in item_details if i.itemId() == i1_id][0], + QgsRectangle(11.5, 13, 12, 13.5), + ) + self.assertEqual( + [i.boundingBox() for i in item_details if i.itemId() == i2_id][0], + QgsRectangle(11, 13, 12, 15), + ) + self.assertEqual( + [i.boundingBox().toString(2) for i in item_details if i.itemId() == i3_id][ + 0 + ], + "11.94,12.94 : 12.06,13.06", + ) def testRenderLayerWithReferenceScale(self): - layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + layer = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) self.assertTrue(layer.isValid()) item = QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)]))) + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) item.setSymbol( - QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2'})) + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black", "outline_width": "2"} + ) + ) item.setZIndex(3) i1_id = layer.addItem(item) - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])) - item.setSymbol(QgsLineSymbol.createSimple({'color': '#ffff00', 'line_width': '3'})) + item = QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]) + ) + item.setSymbol( + QgsLineSymbol.createSimple({"color": "#ffff00", "line_width": "3"}) + ) item.setZIndex(2) i2_id = layer.addItem(item) item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) - item.setSymbol(QgsMarkerSymbol.createSimple({'color': '100,200,200', 'size': '6', 'outline_color': 'black'})) + item.setSymbol( + QgsMarkerSymbol.createSimple( + {"color": "100,200,200", "size": "6", "outline_color": "black"} + ) + ) item.setZIndex(1) i3_id = layer.addItem(item) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(300, 300)) @@ -485,46 +832,82 @@ def testRenderLayerWithReferenceScale(self): finally: painter.end() - self.assertTrue(self.image_check('layer_render_reference_scale', 'layer_render_reference_scale', image)) + self.assertTrue( + self.image_check( + "layer_render_reference_scale", "layer_render_reference_scale", image + ) + ) # also check details of rendered items item_details = renderer.takeRenderedItemDetails() self.assertEqual([i.layerId() for i in item_details], [layer.id()] * 3) self.assertCountEqual([i.itemId() for i in item_details], [i1_id, i2_id, i3_id]) - self.assertEqual([i.boundingBox() for i in item_details if i.itemId() == i1_id][0], - QgsRectangle(12, 13, 14, 15)) - self.assertEqual([i.boundingBox() for i in item_details if i.itemId() == i2_id][0], - QgsRectangle(11, 13, 12, 15)) - self.assertEqual([i.boundingBox().toString(1) for i in item_details if i.itemId() == i3_id][0], - '11.4,12.4 : 12.6,13.6') + self.assertEqual( + [i.boundingBox() for i in item_details if i.itemId() == i1_id][0], + QgsRectangle(12, 13, 14, 15), + ) + self.assertEqual( + [i.boundingBox() for i in item_details if i.itemId() == i2_id][0], + QgsRectangle(11, 13, 12, 15), + ) + self.assertEqual( + [i.boundingBox().toString(1) for i in item_details if i.itemId() == i3_id][ + 0 + ], + "11.4,12.4 : 12.6,13.6", + ) def testRenderLayerWithLinkedVisibility(self): - layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + layer = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) self.assertTrue(layer.isValid()) item = QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)]))) + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) item.setSymbol( - QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2'})) + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black", "outline_width": "2"} + ) + ) item.setZIndex(3) i1_id = layer.addItem(item) - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])) - item.setSymbol(QgsLineSymbol.createSimple({'color': '#ffff00', 'line_width': '3'})) + item = QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]) + ) + item.setSymbol( + QgsLineSymbol.createSimple({"color": "#ffff00", "line_width": "3"}) + ) item.setZIndex(2) i2_id = layer.addItem(item) item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) - item.setSymbol(QgsMarkerSymbol.createSimple({'color': '100,200,200', 'size': '6', 'outline_color': 'black'})) + item.setSymbol( + QgsMarkerSymbol.createSimple( + {"color": "100,200,200", "size": "6", "outline_color": "black"} + ) + ) item.setZIndex(1) i3_id = layer.addItem(item) - other_layer = QgsVectorLayer('Point', 'test', 'memory') + other_layer = QgsVectorLayer("Point", "test", "memory") layer.setLinkedVisibilityLayer(None) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(300, 300)) @@ -544,7 +927,7 @@ def testRenderLayerWithLinkedVisibility(self): finally: painter.end() - self.assertTrue(self.image_check('layer_render', 'layer_render', image)) + self.assertTrue(self.image_check("layer_render", "layer_render", image)) # with linked visibility layer, annotations should not be drawn layer.setLinkedVisibilityLayer(other_layer) @@ -564,36 +947,63 @@ def testRenderLayerWithLinkedVisibility(self): painter.end() self.assertTrue( - self.image_check('layer_render_not_visible', 'layer_render_not_visible', image)) + self.image_check( + "layer_render_not_visible", "layer_render_not_visible", image + ) + ) def test_render_via_job(self): """ Test rendering an annotation layer via a map render job """ - layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) + layer = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) self.assertTrue(layer.isValid()) item = QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(11.5, 13), QgsPoint(12, 13), QgsPoint(12, 13.5), QgsPoint(11.5, 13)]))) + QgsPolygon( + QgsLineString( + [ + QgsPoint(11.5, 13), + QgsPoint(12, 13), + QgsPoint(12, 13.5), + QgsPoint(11.5, 13), + ] + ) + ) + ) item.setSymbol( - QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2'})) + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black", "outline_width": "2"} + ) + ) item.setZIndex(1) i1_id = layer.addItem(item) - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])) - item.setSymbol(QgsLineSymbol.createSimple({'color': '#ffff00', 'line_width': '3'})) + item = QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]) + ) + item.setSymbol( + QgsLineSymbol.createSimple({"color": "#ffff00", "line_width": "3"}) + ) item.setZIndex(2) i2_id = layer.addItem(item) item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) - item.setSymbol(QgsMarkerSymbol.createSimple({'color': '100,200,200', 'size': '6', 'outline_color': 'black'})) + item.setSymbol( + QgsMarkerSymbol.createSimple( + {"color": "100,200,200", "size": "6", "outline_color": "black"} + ) + ) item.setZIndex(3) i3_id = layer.addItem(item) - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(200, 200)) settings.setLayers([layer]) @@ -609,49 +1019,101 @@ def test_render_via_job(self): self.assertEqual([i.layerId() for i in item_details], [layer.id()] * 3) self.assertCountEqual([i.itemId() for i in item_details], [i1_id, i2_id, i3_id]) self.assertCountEqual( - [i.itemId() for i in item_results.renderedAnnotationItemsInBounds(QgsRectangle(0, 0, 1, 1))], []) + [ + i.itemId() + for i in item_results.renderedAnnotationItemsInBounds( + QgsRectangle(0, 0, 1, 1) + ) + ], + [], + ) self.assertCountEqual( - [i.itemId() for i in item_results.renderedAnnotationItemsInBounds(QgsRectangle(10, 10, 11, 18))], [i2_id]) + [ + i.itemId() + for i in item_results.renderedAnnotationItemsInBounds( + QgsRectangle(10, 10, 11, 18) + ) + ], + [i2_id], + ) self.assertCountEqual( - [i.itemId() for i in item_results.renderedAnnotationItemsInBounds(QgsRectangle(10, 10, 12, 18))], - [i1_id, i2_id, i3_id]) + [ + i.itemId() + for i in item_results.renderedAnnotationItemsInBounds( + QgsRectangle(10, 10, 12, 18) + ) + ], + [i1_id, i2_id, i3_id], + ) # bounds should be in map crs - self.assertEqual([i.boundingBox() for i in item_details if i.itemId() == i1_id][0], - QgsRectangle(11.5, 13, 12, 13.5)) - self.assertEqual([i.boundingBox() for i in item_details if i.itemId() == i2_id][0], - QgsRectangle(11, 13, 12, 15)) - self.assertEqual([i.boundingBox().toString(1) for i in item_details if i.itemId() == i3_id][0], - '11.5,12.5 : 12.5,13.5') + self.assertEqual( + [i.boundingBox() for i in item_details if i.itemId() == i1_id][0], + QgsRectangle(11.5, 13, 12, 13.5), + ) + self.assertEqual( + [i.boundingBox() for i in item_details if i.itemId() == i2_id][0], + QgsRectangle(11, 13, 12, 15), + ) + self.assertEqual( + [i.boundingBox().toString(1) for i in item_details if i.itemId() == i3_id][ + 0 + ], + "11.5,12.5 : 12.5,13.5", + ) def test_render_via_job_with_transform(self): """ Test rendering an annotation layer via a map render job """ - layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) + layer = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) self.assertTrue(layer.isValid()) item = QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(11.5, 13), QgsPoint(12, 13), QgsPoint(12, 13.5), QgsPoint(11.5, 13)]))) + QgsPolygon( + QgsLineString( + [ + QgsPoint(11.5, 13), + QgsPoint(12, 13), + QgsPoint(12, 13.5), + QgsPoint(11.5, 13), + ] + ) + ) + ) item.setSymbol( - QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2'})) + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black", "outline_width": "2"} + ) + ) item.setZIndex(1) i1_id = layer.addItem(item) - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])) - item.setSymbol(QgsLineSymbol.createSimple({'color': '#ffff00', 'line_width': '3'})) + item = QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]) + ) + item.setSymbol( + QgsLineSymbol.createSimple({"color": "#ffff00", "line_width": "3"}) + ) item.setZIndex(2) i2_id = layer.addItem(item) item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) - item.setSymbol(QgsMarkerSymbol.createSimple({'color': '100,200,200', 'size': '6', 'outline_color': 'black'})) + item.setSymbol( + QgsMarkerSymbol.createSimple( + {"color": "100,200,200", "size": "6", "outline_color": "black"} + ) + ) item.setZIndex(3) i3_id = layer.addItem(item) - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) settings.setExtent(QgsRectangle(1250958, 1386945, 1420709, 1532518)) settings.setOutputSize(QSize(200, 200)) settings.setLayers([layer]) @@ -668,18 +1130,37 @@ def test_render_via_job_with_transform(self): self.assertCountEqual([i.itemId() for i in item_details], [i1_id, i2_id, i3_id]) # bounds should be in map crs self.assertEqual( - [QgsGeometry.fromRect(i.boundingBox()).asWkt(0) for i in item_details if i.itemId() == i1_id][0], - 'Polygon ((1280174 1459732, 1335834 1459732, 1335834 1516914, 1280174 1516914, 1280174 1459732))') + [ + QgsGeometry.fromRect(i.boundingBox()).asWkt(0) + for i in item_details + if i.itemId() == i1_id + ][0], + "Polygon ((1280174 1459732, 1335834 1459732, 1335834 1516914, 1280174 1516914, 1280174 1459732))", + ) self.assertEqual( - [QgsGeometry.fromRect(i.boundingBox()).asWkt(0) for i in item_details if i.itemId() == i2_id][0], - 'Polygon ((1224514 1459732, 1335834 1459732, 1335834 1689200, 1224514 1689200, 1224514 1459732))') - expected = 'Polygon ((1325786 1449684, 1345882 1449684, 1345882 1469780, 1325786 1469780, 1325786 1449684))' - result = [QgsGeometry.fromRect(i.boundingBox()).asWkt(0) for i in item_details if i.itemId() == i3_id][0] - self.assertTrue(compareWkt(result, expected, tol=1000), "mismatch Expected:\n{}\nGot:\n{}\n".format(expected, - result)) + [ + QgsGeometry.fromRect(i.boundingBox()).asWkt(0) + for i in item_details + if i.itemId() == i2_id + ][0], + "Polygon ((1224514 1459732, 1335834 1459732, 1335834 1689200, 1224514 1689200, 1224514 1459732))", + ) + expected = "Polygon ((1325786 1449684, 1345882 1449684, 1345882 1469780, 1325786 1469780, 1325786 1449684))" + result = [ + QgsGeometry.fromRect(i.boundingBox()).asWkt(0) + for i in item_details + if i.itemId() == i3_id + ][0] + self.assertTrue( + compareWkt(result, expected, tol=1000), + f"mismatch Expected:\n{expected}\nGot:\n{result}\n", + ) def test_force_raster_render(self): - layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) + layer = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) self.assertTrue(layer.isValid()) settings = QgsMapSettings() rc = QgsRenderContext.fromMapSettings(settings) @@ -698,35 +1179,63 @@ def test_force_raster_render(self): self.assertTrue(renderer.forceRasterRender()) def testRenderWithDisabledItems(self): - layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) + layer = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) self.assertTrue(layer.isValid()) item = QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(11.5, 13), QgsPoint(12, 13), QgsPoint(12, 13.5), QgsPoint(11.5, 13)]))) + QgsPolygon( + QgsLineString( + [ + QgsPoint(11.5, 13), + QgsPoint(12, 13), + QgsPoint(12, 13.5), + QgsPoint(11.5, 13), + ] + ) + ) + ) item.setSymbol( - QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2'})) + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black", "outline_width": "2"} + ) + ) item.setZIndex(1) i1_id = layer.addItem(item) - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])) - item.setSymbol(QgsLineSymbol.createSimple({'color': '#ffff00', 'line_width': '3'})) + item = QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]) + ) + item.setSymbol( + QgsLineSymbol.createSimple({"color": "#ffff00", "line_width": "3"}) + ) item.setZIndex(2) item.setEnabled(False) i2_id = layer.addItem(item) - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) settings.setExtent(QgsRectangle(1250958, 1386945, 1420709, 1532518)) settings.setOutputSize(QSize(300, 300)) settings.setFlag(QgsMapSettings.Flag.Antialiasing, False) rc = QgsRenderContext.fromMapSettings(settings) - rc.setCoordinateTransform(QgsCoordinateTransform(layer.crs(), settings.destinationCrs(), QgsProject.instance())) + rc.setCoordinateTransform( + QgsCoordinateTransform( + layer.crs(), settings.destinationCrs(), QgsProject.instance() + ) + ) rc.setExtent( - rc.coordinateTransform().transformBoundingBox(settings.extent(), QgsCoordinateTransform.TransformDirection.ReverseTransform)) + rc.coordinateTransform().transformBoundingBox( + settings.extent(), + QgsCoordinateTransform.TransformDirection.ReverseTransform, + ) + ) image = QImage(200, 200, QImage.Format.Format_ARGB32) image.setDotsPerMeterX(int(96 / 25.4 * 1000)) image.setDotsPerMeterY(int(96 / 25.4 * 1000)) @@ -740,12 +1249,14 @@ def testRenderWithDisabledItems(self): finally: painter.end() - self.assertTrue(self.image_check('layer_render_disabled', 'layer_render_disabled', image)) + self.assertTrue( + self.image_check("layer_render_disabled", "layer_render_disabled", image) + ) # also check details of rendered items item_details = renderer.takeRenderedItemDetails() self.assertEqual([i.layerId() for i in item_details], [layer.id()] * 1) self.assertCountEqual([i.itemId() for i in item_details], [i1_id]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsannotationlineitem.py b/tests/src/python/test_qgsannotationlineitem.py index 9c913138c877..aa6635d2d6ee 100644 --- a/tests/src/python/test_qgsannotationlineitem.py +++ b/tests/src/python/test_qgsannotationlineitem.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 by Nyall Dawson' -__date__ = '29/07/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 by Nyall Dawson" +__date__ = "29/07/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QSize from qgis.PyQt.QtGui import QColor, QImage, QPainter @@ -53,85 +54,219 @@ def control_path_prefix(cls): return "annotation_layer" def testBasic(self): - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)])) + item = QgsAnnotationLineItem( + QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)]) + ) - self.assertEqual(item.geometry().asWkt(), 'LineString (12 13, 14 13, 14 15)') + self.assertEqual(item.geometry().asWkt(), "LineString (12 13, 14 13, 14 15)") - item.setGeometry(QgsLineString([QgsPoint(22, 23), QgsPoint(24, 23), QgsPoint(24, 25)])) + item.setGeometry( + QgsLineString([QgsPoint(22, 23), QgsPoint(24, 23), QgsPoint(24, 25)]) + ) item.setZIndex(11) - self.assertEqual(item.geometry().asWkt(), 'LineString (22 23, 24 23, 24 25)') + self.assertEqual(item.geometry().asWkt(), "LineString (22 23, 24 23, 24 25)") self.assertEqual(item.zIndex(), 11) - item.setSymbol(QgsLineSymbol.createSimple({'color': '#ffff00', 'line_width': '3'})) + item.setSymbol( + QgsLineSymbol.createSimple({"color": "#ffff00", "line_width": "3"}) + ) self.assertEqual(item.symbol()[0].color(), QColor(255, 255, 0)) def test_nodes(self): """ Test nodes for item """ - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)])) - self.assertEqual(item.nodesV2(QgsAnnotationItemEditContext()), [QgsAnnotationItemNode(QgsVertexId(0, 0, 0), QgsPointXY(12, 13), Qgis.AnnotationItemNodeType.VertexHandle), - QgsAnnotationItemNode(QgsVertexId(0, 0, 1), QgsPointXY(14, 13), Qgis.AnnotationItemNodeType.VertexHandle), - QgsAnnotationItemNode(QgsVertexId(0, 0, 2), QgsPointXY(14, 15), Qgis.AnnotationItemNodeType.VertexHandle)]) + item = QgsAnnotationLineItem( + QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)]) + ) + self.assertEqual( + item.nodesV2(QgsAnnotationItemEditContext()), + [ + QgsAnnotationItemNode( + QgsVertexId(0, 0, 0), + QgsPointXY(12, 13), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + QgsAnnotationItemNode( + QgsVertexId(0, 0, 1), + QgsPointXY(14, 13), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + QgsAnnotationItemNode( + QgsVertexId(0, 0, 2), + QgsPointXY(14, 15), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + ], + ) def test_transform(self): - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)])) - self.assertEqual(item.geometry().asWkt(), 'LineString (12 13, 14 13, 14 15)') - - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.geometry().asWkt(), 'LineString (112 213, 114 213, 114 215)') + item = QgsAnnotationLineItem( + QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)]) + ) + self.assertEqual(item.geometry().asWkt(), "LineString (12 13, 14 13, 14 15)") + + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual( + item.geometry().asWkt(), "LineString (112 213, 114 213, 114 215)" + ) def test_apply_move_node_edit(self): - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)])) - self.assertEqual(item.geometry().asWkt(), 'LineString (12 13, 14 13, 14 15)') - - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(14, 13), QgsPoint(17, 18)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.geometry().asWkt(), 'LineString (12 13, 17 18, 14 15)') - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 2), QgsPoint(14, 15), QgsPoint(19, 20)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.geometry().asWkt(), 'LineString (12 13, 17 18, 19 20)') - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 3), QgsPoint(14, 15), QgsPoint(19, 20)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Invalid) - self.assertEqual(item.geometry().asWkt(), 'LineString (12 13, 17 18, 19 20)') + item = QgsAnnotationLineItem( + QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)]) + ) + self.assertEqual(item.geometry().asWkt(), "LineString (12 13, 14 13, 14 15)") + + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 1), QgsPoint(14, 13), QgsPoint(17, 18) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.geometry().asWkt(), "LineString (12 13, 17 18, 14 15)") + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 2), QgsPoint(14, 15), QgsPoint(19, 20) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.geometry().asWkt(), "LineString (12 13, 17 18, 19 20)") + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 3), QgsPoint(14, 15), QgsPoint(19, 20) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Invalid, + ) + self.assertEqual(item.geometry().asWkt(), "LineString (12 13, 17 18, 19 20)") def test_apply_delete_node_edit(self): - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(16, 17)])) - self.assertEqual(item.geometry().asWkt(), 'LineString (12 13, 14 13, 14 15, 16 17)') - - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationDeleteNode('', QgsVertexId(0, 0, 1), QgsPoint(14, 13)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.geometry().asWkt(), 'LineString (12 13, 14 15, 16 17)') - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationDeleteNode('', QgsVertexId(0, 0, 0), QgsPoint(12, 13)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.geometry().asWkt(), 'LineString (14 15, 16 17)') - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationDeleteNode('', QgsVertexId(0, 0, 3), QgsPoint(14, 15)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Invalid) - self.assertEqual(item.geometry().asWkt(), 'LineString (14 15, 16 17)') - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationDeleteNode('', QgsVertexId(0, 0, 1), QgsPoint(16, 17)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.ItemCleared) - self.assertEqual(item.geometry().asWkt(), 'LineString EMPTY') + item = QgsAnnotationLineItem( + QgsLineString( + [QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(16, 17)] + ) + ) + self.assertEqual( + item.geometry().asWkt(), "LineString (12 13, 14 13, 14 15, 16 17)" + ) + + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationDeleteNode( + "", QgsVertexId(0, 0, 1), QgsPoint(14, 13) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.geometry().asWkt(), "LineString (12 13, 14 15, 16 17)") + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationDeleteNode( + "", QgsVertexId(0, 0, 0), QgsPoint(12, 13) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.geometry().asWkt(), "LineString (14 15, 16 17)") + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationDeleteNode( + "", QgsVertexId(0, 0, 3), QgsPoint(14, 15) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Invalid, + ) + self.assertEqual(item.geometry().asWkt(), "LineString (14 15, 16 17)") + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationDeleteNode( + "", QgsVertexId(0, 0, 1), QgsPoint(16, 17) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.ItemCleared, + ) + self.assertEqual(item.geometry().asWkt(), "LineString EMPTY") def test_apply_add_node_edit(self): - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(16, 17)])) - self.assertEqual(item.geometry().asWkt(), 'LineString (12 13, 14 13, 14 15, 16 17)') - - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationAddNode('', QgsPoint(15, 16)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.geometry().asWkt(), 'LineString (12 13, 14 13, 14 15, 15 16, 16 17)') + item = QgsAnnotationLineItem( + QgsLineString( + [QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(16, 17)] + ) + ) + self.assertEqual( + item.geometry().asWkt(), "LineString (12 13, 14 13, 14 15, 16 17)" + ) + + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationAddNode("", QgsPoint(15, 16)), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual( + item.geometry().asWkt(), "LineString (12 13, 14 13, 14 15, 15 16, 16 17)" + ) def test_transient_move_operation(self): - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)])) - self.assertEqual(item.geometry().asWkt(), 'LineString (12 13, 14 13, 14 15)') - - res = item.transientEditResultsV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(14, 13), QgsPoint(17, 18)), QgsAnnotationItemEditContext()) - self.assertEqual(res.representativeGeometry().asWkt(), 'LineString (12 13, 17 18, 14 15)') + item = QgsAnnotationLineItem( + QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)]) + ) + self.assertEqual(item.geometry().asWkt(), "LineString (12 13, 14 13, 14 15)") + + res = item.transientEditResultsV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 1), QgsPoint(14, 13), QgsPoint(17, 18) + ), + QgsAnnotationItemEditContext(), + ) + self.assertEqual( + res.representativeGeometry().asWkt(), "LineString (12 13, 17 18, 14 15)" + ) def test_transient_translate_operation(self): - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)])) - self.assertEqual(item.geometry().asWkt(), 'LineString (12 13, 14 13, 14 15)') - - res = item.transientEditResultsV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200), QgsAnnotationItemEditContext()) - self.assertEqual(res.representativeGeometry().asWkt(), 'LineString (112 213, 114 213, 114 215)') + item = QgsAnnotationLineItem( + QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)]) + ) + self.assertEqual(item.geometry().asWkt(), "LineString (12 13, 14 13, 14 15)") + + res = item.transientEditResultsV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200), + QgsAnnotationItemEditContext(), + ) + self.assertEqual( + res.representativeGeometry().asWkt(), + "LineString (112 213, 114 213, 114 215)", + ) def testReadWriteXml(self): doc = QDomDocument("testdoc") - elem = doc.createElement('test') - - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)])) - item.setSymbol(QgsLineSymbol.createSimple({'color': '#ffff00', 'line_width': '3'})) + elem = doc.createElement("test") + + item = QgsAnnotationLineItem( + QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)]) + ) + item.setSymbol( + QgsLineSymbol.createSimple({"color": "#ffff00", "line_width": "3"}) + ) item.setZIndex(11) item.setUseSymbologyReferenceScale(True) item.setSymbologyReferenceScale(5000) @@ -141,32 +276,40 @@ def testReadWriteXml(self): s2 = QgsAnnotationLineItem.create() self.assertTrue(s2.readXml(elem, QgsReadWriteContext())) - self.assertEqual(s2.geometry().asWkt(), 'LineString (12 13, 14 13, 14 15)') + self.assertEqual(s2.geometry().asWkt(), "LineString (12 13, 14 13, 14 15)") self.assertEqual(s2.symbol()[0].color(), QColor(255, 255, 0)) self.assertEqual(s2.zIndex(), 11) self.assertTrue(s2.useSymbologyReferenceScale()) self.assertEqual(s2.symbologyReferenceScale(), 5000) def testClone(self): - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)])) - item.setSymbol(QgsLineSymbol.createSimple({'color': '#ffff00', 'line_width': '3'})) + item = QgsAnnotationLineItem( + QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)]) + ) + item.setSymbol( + QgsLineSymbol.createSimple({"color": "#ffff00", "line_width": "3"}) + ) item.setZIndex(11) item.setUseSymbologyReferenceScale(True) item.setSymbologyReferenceScale(5000) item2 = item.clone() - self.assertEqual(item2.geometry().asWkt(), 'LineString (12 13, 14 13, 14 15)') + self.assertEqual(item2.geometry().asWkt(), "LineString (12 13, 14 13, 14 15)") self.assertEqual(item2.symbol()[0].color(), QColor(255, 255, 0)) self.assertEqual(item2.zIndex(), 11) self.assertTrue(item2.useSymbologyReferenceScale()) self.assertEqual(item2.symbologyReferenceScale(), 5000) def testRenderLineString(self): - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)])) - item.setSymbol(QgsLineSymbol.createSimple({'color': '#ffff00', 'line_width': '3'})) + item = QgsAnnotationLineItem( + QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)]) + ) + item.setSymbol( + QgsLineSymbol.createSimple({"color": "#ffff00", "line_width": "3"}) + ) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(300, 300)) @@ -185,14 +328,18 @@ def testRenderLineString(self): finally: painter.end() - self.assertTrue(self.image_check('linestring_item', 'linestring_item', image)) + self.assertTrue(self.image_check("linestring_item", "linestring_item", image)) def testRenderCurve(self): - item = QgsAnnotationLineItem(QgsCircularString(QgsPoint(12, 13.2), QgsPoint(14, 13.4), QgsPoint(14, 15))) - item.setSymbol(QgsLineSymbol.createSimple({'color': '#ffff00', 'line_width': '3'})) + item = QgsAnnotationLineItem( + QgsCircularString(QgsPoint(12, 13.2), QgsPoint(14, 13.4), QgsPoint(14, 15)) + ) + item.setSymbol( + QgsLineSymbol.createSimple({"color": "#ffff00", "line_width": "3"}) + ) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(300, 300)) @@ -211,21 +358,33 @@ def testRenderCurve(self): finally: painter.end() - self.assertTrue(self.image_check('line_circularstring', 'line_circularstring', image)) + self.assertTrue( + self.image_check("line_circularstring", "line_circularstring", image) + ) def testRenderWithTransform(self): - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])) - item.setSymbol(QgsLineSymbol.createSimple({'color': '#ffff00', 'line_width': '3'})) + item = QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]) + ) + item.setSymbol( + QgsLineSymbol.createSimple({"color": "#ffff00", "line_width": "3"}) + ) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) settings.setExtent(QgsRectangle(1250958, 1386945, 1420709, 1532518)) settings.setOutputSize(QSize(300, 300)) settings.setFlag(QgsMapSettings.Flag.Antialiasing, False) rc = QgsRenderContext.fromMapSettings(settings) - rc.setCoordinateTransform(QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'), settings.destinationCrs(), QgsProject.instance())) + rc.setCoordinateTransform( + QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + settings.destinationCrs(), + QgsProject.instance(), + ) + ) image = QImage(200, 200, QImage.Format.Format_ARGB32) image.setDotsPerMeterX(int(96 / 25.4 * 1000)) image.setDotsPerMeterY(int(96 / 25.4 * 1000)) @@ -238,8 +397,12 @@ def testRenderWithTransform(self): finally: painter.end() - self.assertTrue(self.image_check('linestring_item_transform', 'linestring_item_transform', image)) + self.assertTrue( + self.image_check( + "linestring_item_transform", "linestring_item_transform", image + ) + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsannotationlinetextitem.py b/tests/src/python/test_qgsannotationlinetextitem.py index 065959afd4ae..5cd8dc1769f3 100644 --- a/tests/src/python/test_qgsannotationlinetextitem.py +++ b/tests/src/python/test_qgsannotationlinetextitem.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 by Nyall Dawson' -__date__ = '10/08/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 by Nyall Dawson" +__date__ = "10/08/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QSize from qgis.PyQt.QtGui import QColor, QImage, QPainter @@ -53,16 +54,17 @@ def control_path_prefix(cls): return "annotation_layer" def testBasic(self): - item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13)))) + item = QgsAnnotationLineTextItem( + "my text", QgsLineString(((12, 13), (13, 13.1), (14, 13))) + ) - self.assertEqual(item.text(), 'my text') - self.assertEqual(item.geometry().asWkt(1), 'LineString (12 13, 13 13.1, 14 13)') + self.assertEqual(item.text(), "my text") + self.assertEqual(item.geometry().asWkt(1), "LineString (12 13, 13 13.1, 14 13)") self.assertEqual(item.offsetFromLine(), 0) - self.assertEqual(item.offsetFromLineUnit(), - Qgis.RenderUnit.Millimeters) + self.assertEqual(item.offsetFromLineUnit(), Qgis.RenderUnit.Millimeters) - item.setText('tttttt') + item.setText("tttttt") item.setGeometry(QgsLineString(((12, 13), (13, 13.1)))) item.setZIndex(11) item.setOffsetFromLine(3.4) @@ -73,81 +75,157 @@ def testBasic(self): format.setSize(37) item.setFormat(format) - self.assertEqual(item.text(), 'tttttt') - self.assertEqual(item.geometry().asWkt(1), 'LineString (12 13, 13 13.1)') + self.assertEqual(item.text(), "tttttt") + self.assertEqual(item.geometry().asWkt(1), "LineString (12 13, 13 13.1)") self.assertEqual(item.zIndex(), 11) self.assertEqual(item.format().size(), 37) self.assertEqual(item.offsetFromLine(), 3.4) - self.assertEqual(item.offsetFromLineUnit(), - Qgis.RenderUnit.Inches) - self.assertEqual(item.offsetFromLineMapUnitScale().minScale, - 5) - self.assertEqual(item.offsetFromLineMapUnitScale().maxScale, - 15) + self.assertEqual(item.offsetFromLineUnit(), Qgis.RenderUnit.Inches) + self.assertEqual(item.offsetFromLineMapUnitScale().minScale, 5) + self.assertEqual(item.offsetFromLineMapUnitScale().maxScale, 15) def test_nodes(self): """ Test nodes for item """ - item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13)))) - self.assertEqual(item.nodesV2(QgsAnnotationItemEditContext()), [ - QgsAnnotationItemNode(QgsVertexId(0, 0, 0), QgsPointXY(12, 13), - Qgis.AnnotationItemNodeType.VertexHandle), - QgsAnnotationItemNode(QgsVertexId(0, 0, 1), QgsPointXY(13, 13.1), - Qgis.AnnotationItemNodeType.VertexHandle), - QgsAnnotationItemNode(QgsVertexId(0, 0, 2), QgsPointXY(14, 13), - Qgis.AnnotationItemNodeType.VertexHandle) - ]) + item = QgsAnnotationLineTextItem( + "my text", QgsLineString(((12, 13), (13, 13.1), (14, 13))) + ) + self.assertEqual( + item.nodesV2(QgsAnnotationItemEditContext()), + [ + QgsAnnotationItemNode( + QgsVertexId(0, 0, 0), + QgsPointXY(12, 13), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + QgsAnnotationItemNode( + QgsVertexId(0, 0, 1), + QgsPointXY(13, 13.1), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + QgsAnnotationItemNode( + QgsVertexId(0, 0, 2), + QgsPointXY(14, 13), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + ], + ) def test_transform(self): - item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13)))) - self.assertEqual(item.geometry().asWkt(1), 'LineString (12 13, 13 13.1, 14 13)') - - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.geometry().asWkt(1), 'LineString (112 213, 113 213.1, 114 213)') + item = QgsAnnotationLineTextItem( + "my text", QgsLineString(((12, 13), (13, 13.1), (14, 13))) + ) + self.assertEqual(item.geometry().asWkt(1), "LineString (12 13, 13 13.1, 14 13)") + + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual( + item.geometry().asWkt(1), "LineString (112 213, 113 213.1, 114 213)" + ) def test_apply_move_node_edit(self): - item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13)))) - self.assertEqual(item.geometry().asWkt(1), 'LineString (12 13, 13 13.1, 14 13)') - - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(13, 13.1), QgsPoint(17, 18)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.geometry().asWkt(1), 'LineString (12 13, 17 18, 14 13)') + item = QgsAnnotationLineTextItem( + "my text", QgsLineString(((12, 13), (13, 13.1), (14, 13))) + ) + self.assertEqual(item.geometry().asWkt(1), "LineString (12 13, 13 13.1, 14 13)") + + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 1), QgsPoint(13, 13.1), QgsPoint(17, 18) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.geometry().asWkt(1), "LineString (12 13, 17 18, 14 13)") def test_transient_move_operation(self): - item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13)))) - self.assertEqual(item.geometry().asWkt(1), 'LineString (12 13, 13 13.1, 14 13)') - - res = item.transientEditResultsV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(13, 13.1), QgsPoint(17, 18)), QgsAnnotationItemEditContext()) - self.assertEqual(res.representativeGeometry().asWkt(1), 'LineString (12 13, 17 18, 14 13)') + item = QgsAnnotationLineTextItem( + "my text", QgsLineString(((12, 13), (13, 13.1), (14, 13))) + ) + self.assertEqual(item.geometry().asWkt(1), "LineString (12 13, 13 13.1, 14 13)") + + res = item.transientEditResultsV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 1), QgsPoint(13, 13.1), QgsPoint(17, 18) + ), + QgsAnnotationItemEditContext(), + ) + self.assertEqual( + res.representativeGeometry().asWkt(1), "LineString (12 13, 17 18, 14 13)" + ) def test_transient_translate_operation(self): - item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13)))) - self.assertEqual(item.geometry().asWkt(1), 'LineString (12 13, 13 13.1, 14 13)') - - res = item.transientEditResultsV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200), QgsAnnotationItemEditContext()) - self.assertEqual(res.representativeGeometry().asWkt(1), 'LineString (112 213, 113 213.1, 114 213)') + item = QgsAnnotationLineTextItem( + "my text", QgsLineString(((12, 13), (13, 13.1), (14, 13))) + ) + self.assertEqual(item.geometry().asWkt(1), "LineString (12 13, 13 13.1, 14 13)") + + res = item.transientEditResultsV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200), + QgsAnnotationItemEditContext(), + ) + self.assertEqual( + res.representativeGeometry().asWkt(1), + "LineString (112 213, 113 213.1, 114 213)", + ) def test_apply_delete_node_edit(self): - item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13)))) - self.assertEqual(item.geometry().asWkt(1), 'LineString (12 13, 13 13.1, 14 13)') - - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationDeleteNode('', QgsVertexId(0, 0, 1), QgsPoint(13, 13.1)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.geometry().asWkt(1), - 'LineString (12 13, 14 13)') - - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationDeleteNode('', QgsVertexId(0, 0, 1), QgsPoint(14, 13)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.ItemCleared) + item = QgsAnnotationLineTextItem( + "my text", QgsLineString(((12, 13), (13, 13.1), (14, 13))) + ) + self.assertEqual(item.geometry().asWkt(1), "LineString (12 13, 13 13.1, 14 13)") + + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationDeleteNode( + "", QgsVertexId(0, 0, 1), QgsPoint(13, 13.1) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.geometry().asWkt(1), "LineString (12 13, 14 13)") + + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationDeleteNode( + "", QgsVertexId(0, 0, 1), QgsPoint(14, 13) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.ItemCleared, + ) def test_apply_add_node_edit(self): - item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13)))) - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationAddNode('', QgsPoint(12.5, 12.8)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.geometry().asWkt(1), - 'LineString (12 13, 12.5 13, 13 13.1, 14 13)') + item = QgsAnnotationLineTextItem( + "my text", QgsLineString(((12, 13), (13, 13.1), (14, 13))) + ) + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationAddNode("", QgsPoint(12.5, 12.8)), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual( + item.geometry().asWkt(1), "LineString (12 13, 12.5 13, 13 13.1, 14 13)" + ) def testReadWriteXml(self): doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") - item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13)))) + item = QgsAnnotationLineTextItem( + "my text", QgsLineString(((12, 13), (13, 13.1), (14, 13))) + ) item.setZIndex(11) format = QgsTextFormat() format.setSize(37) @@ -162,22 +240,21 @@ def testReadWriteXml(self): s2 = QgsAnnotationLineTextItem.create() self.assertTrue(s2.readXml(elem, QgsReadWriteContext())) - self.assertEqual(s2.text(), 'my text') - self.assertEqual(s2.geometry().asWkt(1), 'LineString (12 13, 13 13.1, 14 13)') + self.assertEqual(s2.text(), "my text") + self.assertEqual(s2.geometry().asWkt(1), "LineString (12 13, 13 13.1, 14 13)") self.assertEqual(s2.zIndex(), 11) self.assertEqual(s2.format().size(), 37) self.assertTrue(s2.useSymbologyReferenceScale()) self.assertEqual(s2.symbologyReferenceScale(), 5000) self.assertEqual(s2.offsetFromLine(), 3.4) - self.assertEqual(s2.offsetFromLineUnit(), - Qgis.RenderUnit.Inches) - self.assertEqual(s2.offsetFromLineMapUnitScale().minScale, - 5) - self.assertEqual(s2.offsetFromLineMapUnitScale().maxScale, - 15) + self.assertEqual(s2.offsetFromLineUnit(), Qgis.RenderUnit.Inches) + self.assertEqual(s2.offsetFromLineMapUnitScale().minScale, 5) + self.assertEqual(s2.offsetFromLineMapUnitScale().maxScale, 15) def testClone(self): - item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 13)))) + item = QgsAnnotationLineTextItem( + "my text", QgsLineString(((12, 13), (13, 13.1), (14, 13))) + ) item.setZIndex(11) format = QgsTextFormat() format.setSize(37) @@ -189,31 +266,32 @@ def testClone(self): item.setOffsetFromLineMapUnitScale(QgsMapUnitScale(5, 15)) item2 = item.clone() - self.assertEqual(item2.text(), 'my text') - self.assertEqual(item2.geometry().asWkt(1), 'LineString (12 13, 13 13.1, 14 13)') + self.assertEqual(item2.text(), "my text") + self.assertEqual( + item2.geometry().asWkt(1), "LineString (12 13, 13 13.1, 14 13)" + ) self.assertEqual(item2.zIndex(), 11) self.assertEqual(item2.format().size(), 37) self.assertTrue(item2.useSymbologyReferenceScale()) self.assertEqual(item2.symbologyReferenceScale(), 5000) self.assertEqual(item2.offsetFromLine(), 3.4) - self.assertEqual(item2.offsetFromLineUnit(), - Qgis.RenderUnit.Inches) - self.assertEqual(item2.offsetFromLineMapUnitScale().minScale, - 5) - self.assertEqual(item2.offsetFromLineMapUnitScale().maxScale, - 15) + self.assertEqual(item2.offsetFromLineUnit(), Qgis.RenderUnit.Inches) + self.assertEqual(item2.offsetFromLineMapUnitScale().minScale, 5) + self.assertEqual(item2.offsetFromLineMapUnitScale().maxScale, 15) def testRenderLine(self): - item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 12)))) + item = QgsAnnotationLineTextItem( + "my text", QgsLineString(((12, 13), (13, 13.1), (14, 12))) + ) - format = QgsTextFormat.fromQFont(getTestFont('Bold')) + format = QgsTextFormat.fromQFont(getTestFont("Bold")) format.setColor(QColor(255, 0, 0)) format.setOpacity(150 / 255) format.setSize(55) item.setFormat(format) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(11.9, 11.9, 14.5, 14)) settings.setOutputSize(QSize(600, 300)) @@ -233,12 +311,14 @@ def testRenderLine(self): finally: painter.end() - self.assertTrue(self.image_check('linetext_item', 'linetext_item', image)) + self.assertTrue(self.image_check("linetext_item", "linetext_item", image)) def testRenderLineOffsetPositive(self): - item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 12)))) + item = QgsAnnotationLineTextItem( + "my text", QgsLineString(((12, 13), (13, 13.1), (14, 12))) + ) - format = QgsTextFormat.fromQFont(getTestFont('Bold')) + format = QgsTextFormat.fromQFont(getTestFont("Bold")) format.setColor(QColor(255, 0, 0)) format.setOpacity(150 / 255) format.setSize(55) @@ -247,7 +327,7 @@ def testRenderLineOffsetPositive(self): item.setOffsetFromLine(6) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(11.9, 11.9, 14.5, 14)) settings.setOutputSize(QSize(600, 300)) @@ -267,12 +347,18 @@ def testRenderLineOffsetPositive(self): finally: painter.end() - self.assertTrue(self.image_check('linetext_item_offset_positive', 'linetext_item_offset_positive', image)) + self.assertTrue( + self.image_check( + "linetext_item_offset_positive", "linetext_item_offset_positive", image + ) + ) def testRenderLineOffsetNegative(self): - item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 12)))) + item = QgsAnnotationLineTextItem( + "my text", QgsLineString(((12, 13), (13, 13.1), (14, 12))) + ) - format = QgsTextFormat.fromQFont(getTestFont('Bold')) + format = QgsTextFormat.fromQFont(getTestFont("Bold")) format.setColor(QColor(255, 0, 0)) format.setOpacity(150 / 255) format.setSize(55) @@ -281,7 +367,7 @@ def testRenderLineOffsetNegative(self): item.setOffsetFromLine(-6) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(11.9, 11.9, 14.5, 14)) settings.setOutputSize(QSize(600, 300)) @@ -301,19 +387,25 @@ def testRenderLineOffsetNegative(self): finally: painter.end() - self.assertTrue(self.image_check('linetext_item_offset_negative', 'linetext_item_offset_negative', image)) + self.assertTrue( + self.image_check( + "linetext_item_offset_negative", "linetext_item_offset_negative", image + ) + ) def testRenderLineTruncate(self): - item = QgsAnnotationLineTextItem('my text', QgsLineString(((12, 13), (13, 13.1), (14, 12)))) + item = QgsAnnotationLineTextItem( + "my text", QgsLineString(((12, 13), (13, 13.1), (14, 12))) + ) - format = QgsTextFormat.fromQFont(getTestFont('Bold')) + format = QgsTextFormat.fromQFont(getTestFont("Bold")) format.setColor(QColor(255, 0, 0)) format.setOpacity(150 / 255) format.setSize(75) item.setFormat(format) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(11.9, 11.9, 14.5, 14)) settings.setOutputSize(QSize(600, 300)) @@ -333,19 +425,23 @@ def testRenderLineTruncate(self): finally: painter.end() - self.assertTrue(self.image_check('linetext_item_truncate', 'linetext_item_truncate', image)) + self.assertTrue( + self.image_check("linetext_item_truncate", "linetext_item_truncate", image) + ) def testRenderLineTextExpression(self): - item = QgsAnnotationLineTextItem('[% 1 + 1.5 %]', QgsLineString(((12, 13), (13, 13.1), (14, 12)))) + item = QgsAnnotationLineTextItem( + "[% 1 + 1.5 %]", QgsLineString(((12, 13), (13, 13.1), (14, 12))) + ) - format = QgsTextFormat.fromQFont(getTestFont('Bold')) + format = QgsTextFormat.fromQFont(getTestFont("Bold")) format.setColor(QColor(255, 0, 0)) format.setOpacity(150 / 255) format.setSize(55) item.setFormat(format) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(11.9, 11.9, 14.5, 14)) settings.setOutputSize(QSize(600, 300)) @@ -365,20 +461,25 @@ def testRenderLineTextExpression(self): finally: painter.end() - self.assertTrue(self.image_check('linetext_item_expression', 'linetext_item_expression', image)) + self.assertTrue( + self.image_check( + "linetext_item_expression", "linetext_item_expression", image + ) + ) def testRenderWithTransform(self): - item = QgsAnnotationLineTextItem('my text', QgsLineString( - ((12, 13), (13, 13.1), (14, 12)))) + item = QgsAnnotationLineTextItem( + "my text", QgsLineString(((12, 13), (13, 13.1), (14, 12))) + ) - format = QgsTextFormat.fromQFont(getTestFont('Bold')) + format = QgsTextFormat.fromQFont(getTestFont("Bold")) format.setColor(QColor(255, 0, 0)) format.setOpacity(150 / 255) format.setSize(55) item.setFormat(format) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) settings.setExtent(QgsRectangle(1291958, 1386945, 1420709, 1532518)) settings.setOutputSize(QSize(600, 300)) @@ -386,7 +487,13 @@ def testRenderWithTransform(self): rc = QgsRenderContext.fromMapSettings(settings) rc.setScaleFactor(96 / 25.4) # 96 DPI - rc.setCoordinateTransform(QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'), settings.destinationCrs(), QgsProject.instance())) + rc.setCoordinateTransform( + QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + settings.destinationCrs(), + QgsProject.instance(), + ) + ) image = QImage(600, 300, QImage.Format.Format_ARGB32) image.setDotsPerMeterX(int(96 / 25.4 * 1000)) image.setDotsPerMeterY(int(96 / 25.4 * 1000)) @@ -399,8 +506,12 @@ def testRenderWithTransform(self): finally: painter.end() - self.assertTrue(self.image_check('linetext_item_transform', 'linetext_item_transform', image)) + self.assertTrue( + self.image_check( + "linetext_item_transform", "linetext_item_transform", image + ) + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsannotationmarkeritem.py b/tests/src/python/test_qgsannotationmarkeritem.py index 4040d45d21d7..8c9022f85fd2 100644 --- a/tests/src/python/test_qgsannotationmarkeritem.py +++ b/tests/src/python/test_qgsannotationmarkeritem.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 by Nyall Dawson' -__date__ = '29/07/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 by Nyall Dawson" +__date__ = "29/07/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QSize from qgis.PyQt.QtGui import QColor, QImage, QPainter @@ -62,7 +63,11 @@ def testBasic(self): self.assertEqual(item.geometry().y(), 2000.0) self.assertEqual(item.zIndex(), 11) - item.setSymbol(QgsMarkerSymbol.createSimple({'color': '100,200,200', 'size': '3', 'outline_color': 'black'})) + item.setSymbol( + QgsMarkerSymbol.createSimple( + {"color": "100,200,200", "size": "3", "outline_color": "black"} + ) + ) self.assertEqual(item.symbol()[0].color(), QColor(100, 200, 200)) def test_nodes(self): @@ -70,52 +75,101 @@ def test_nodes(self): Test nodes for item """ item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) - self.assertEqual(item.nodesV2(QgsAnnotationItemEditContext()), [QgsAnnotationItemNode(QgsVertexId(0, 0, 0), QgsPointXY(12, 13), Qgis.AnnotationItemNodeType.VertexHandle)]) + self.assertEqual( + item.nodesV2(QgsAnnotationItemEditContext()), + [ + QgsAnnotationItemNode( + QgsVertexId(0, 0, 0), + QgsPointXY(12, 13), + Qgis.AnnotationItemNodeType.VertexHandle, + ) + ], + ) def test_transform(self): item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) - self.assertEqual(item.geometry().asWkt(), 'POINT(12 13)') + self.assertEqual(item.geometry().asWkt(), "POINT(12 13)") - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.geometry().asWkt(), 'POINT(112 213)') + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.geometry().asWkt(), "POINT(112 213)") def test_apply_move_node_edit(self): item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) - self.assertEqual(item.geometry().asWkt(), 'POINT(12 13)') - - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(14, 13), QgsPoint(17, 18)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.geometry().asWkt(), 'POINT(17 18)') + self.assertEqual(item.geometry().asWkt(), "POINT(12 13)") + + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 1), QgsPoint(14, 13), QgsPoint(17, 18) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.geometry().asWkt(), "POINT(17 18)") def test_apply_delete_node_edit(self): item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) - self.assertEqual(item.geometry().asWkt(), 'POINT(12 13)') - - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationDeleteNode('', QgsVertexId(0, 0, 0), QgsPoint(12, 13)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.ItemCleared) + self.assertEqual(item.geometry().asWkt(), "POINT(12 13)") + + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationDeleteNode( + "", QgsVertexId(0, 0, 0), QgsPoint(12, 13) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.ItemCleared, + ) def test_apply_add_node_edit(self): item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationAddNode('', QgsPoint(13, 14)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Invalid) + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationAddNode("", QgsPoint(13, 14)), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Invalid, + ) def test_transient_move_operation(self): item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) - self.assertEqual(item.geometry().asWkt(), 'POINT(12 13)') + self.assertEqual(item.geometry().asWkt(), "POINT(12 13)") - res = item.transientEditResultsV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 0), QgsPoint(12, 13), QgsPoint(17, 18)), QgsAnnotationItemEditContext()) - self.assertEqual(res.representativeGeometry().asWkt(), 'Point (17 18)') + res = item.transientEditResultsV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 0), QgsPoint(12, 13), QgsPoint(17, 18) + ), + QgsAnnotationItemEditContext(), + ) + self.assertEqual(res.representativeGeometry().asWkt(), "Point (17 18)") def test_transient_translate_operation(self): item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) - self.assertEqual(item.geometry().asWkt(), 'POINT(12 13)') + self.assertEqual(item.geometry().asWkt(), "POINT(12 13)") - res = item.transientEditResultsV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200), QgsAnnotationItemEditContext()) - self.assertEqual(res.representativeGeometry().asWkt(), 'Point (112 213)') + res = item.transientEditResultsV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200), + QgsAnnotationItemEditContext(), + ) + self.assertEqual(res.representativeGeometry().asWkt(), "Point (112 213)") def testReadWriteXml(self): doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) - item.setSymbol(QgsMarkerSymbol.createSimple({'color': '100,200,200', 'size': '3', 'outline_color': 'black'})) + item.setSymbol( + QgsMarkerSymbol.createSimple( + {"color": "100,200,200", "size": "3", "outline_color": "black"} + ) + ) item.setZIndex(11) item.setUseSymbologyReferenceScale(True) item.setSymbologyReferenceScale(5000) @@ -134,7 +188,11 @@ def testReadWriteXml(self): def testClone(self): item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) - item.setSymbol(QgsMarkerSymbol.createSimple({'color': '100,200,200', 'size': '3', 'outline_color': 'black'})) + item.setSymbol( + QgsMarkerSymbol.createSimple( + {"color": "100,200,200", "size": "3", "outline_color": "black"} + ) + ) item.setZIndex(11) item.setUseSymbologyReferenceScale(True) item.setSymbologyReferenceScale(5000) @@ -149,10 +207,14 @@ def testClone(self): def testRenderMarker(self): item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) - item.setSymbol(QgsMarkerSymbol.createSimple({'color': '100,200,200', 'size': '3', 'outline_color': 'black'})) + item.setSymbol( + QgsMarkerSymbol.createSimple( + {"color": "100,200,200", "size": "3", "outline_color": "black"} + ) + ) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 16, 16)) settings.setOutputSize(QSize(300, 300)) @@ -171,21 +233,31 @@ def testRenderMarker(self): finally: painter.end() - self.assertTrue(self.image_check('marker_item', 'marker_item', image)) + self.assertTrue(self.image_check("marker_item", "marker_item", image)) def testRenderWithTransform(self): item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) - item.setSymbol(QgsMarkerSymbol.createSimple({'color': '100,200,200', 'size': '3', 'outline_color': 'black'})) + item.setSymbol( + QgsMarkerSymbol.createSimple( + {"color": "100,200,200", "size": "3", "outline_color": "black"} + ) + ) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) settings.setExtent(QgsRectangle(1250958, 1386945, 1420709, 1532518)) settings.setOutputSize(QSize(300, 300)) settings.setFlag(QgsMapSettings.Flag.Antialiasing, False) rc = QgsRenderContext.fromMapSettings(settings) - rc.setCoordinateTransform(QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'), settings.destinationCrs(), QgsProject.instance())) + rc.setCoordinateTransform( + QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + settings.destinationCrs(), + QgsProject.instance(), + ) + ) image = QImage(200, 200, QImage.Format.Format_ARGB32) image.setDotsPerMeterX(int(96 / 25.4 * 1000)) image.setDotsPerMeterY(int(96 / 25.4 * 1000)) @@ -198,8 +270,10 @@ def testRenderWithTransform(self): finally: painter.end() - self.assertTrue(self.image_check('marker_item_transform', 'marker_item_transform', image)) + self.assertTrue( + self.image_check("marker_item_transform", "marker_item_transform", image) + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsannotationpictureitem.py b/tests/src/python/test_qgsannotationpictureitem.py index 5045540752ee..3df7b2f23fa2 100644 --- a/tests/src/python/test_qgsannotationpictureitem.py +++ b/tests/src/python/test_qgsannotationpictureitem.py @@ -38,7 +38,7 @@ QgsCallout, QgsBalloonCallout, QgsGeometry, - QgsSimpleLineCallout + QgsSimpleLineCallout, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -56,148 +56,232 @@ def control_path_prefix(cls): return "annotation_layer" def testBasic(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, self.get_test_data_path('rgb256x256.png').as_posix(), - QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(10, 20, 30, 40), + ) - self.assertEqual(item.path(), self.get_test_data_path('rgb256x256.png').as_posix()) + self.assertEqual( + item.path(), self.get_test_data_path("rgb256x256.png").as_posix() + ) self.assertEqual(item.format(), Qgis.PictureFormat.Raster) - self.assertEqual(item.boundingBox().toString(3), '10.000,20.000 : 30.000,40.000') - self.assertEqual(item.placementMode(), Qgis.AnnotationPlacementMode.SpatialBounds) + self.assertEqual( + item.boundingBox().toString(3), "10.000,20.000 : 30.000,40.000" + ) + self.assertEqual( + item.placementMode(), Qgis.AnnotationPlacementMode.SpatialBounds + ) item.setBounds(QgsRectangle(100, 200, 300, 400)) item.setZIndex(11) - item.setPath(Qgis.PictureFormat.SVG, self.get_test_data_path('sample_svg.svg').as_posix()) + item.setPath( + Qgis.PictureFormat.SVG, self.get_test_data_path("sample_svg.svg").as_posix() + ) item.setLockAspectRatio(False) item.setBackgroundEnabled(True) item.setFrameEnabled(True) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - item.setFixedSize(QSizeF(56, - 57)) + item.setFixedSize(QSizeF(56, 57)) item.setFixedSizeUnit(Qgis.RenderUnit.Inches) item.setOffsetFromCallout(QSizeF(13.6, 17.2)) item.setOffsetFromCalloutUnit(Qgis.RenderUnit.Inches) - self.assertEqual(item.bounds().toString(3), '100.000,200.000 : 300.000,400.000') - self.assertEqual(item.path(), self.get_test_data_path('sample_svg.svg').as_posix()) + self.assertEqual(item.bounds().toString(3), "100.000,200.000 : 300.000,400.000") + self.assertEqual( + item.path(), self.get_test_data_path("sample_svg.svg").as_posix() + ) self.assertEqual(item.format(), Qgis.PictureFormat.SVG) self.assertEqual(item.zIndex(), 11) self.assertFalse(item.lockAspectRatio()) self.assertTrue(item.backgroundEnabled()) self.assertTrue(item.frameEnabled()) - self.assertEqual(item.placementMode(), - Qgis.AnnotationPlacementMode.FixedSize) - self.assertEqual(item.fixedSize(), QSizeF(56, - 57)) + self.assertEqual(item.placementMode(), Qgis.AnnotationPlacementMode.FixedSize) + self.assertEqual(item.fixedSize(), QSizeF(56, 57)) self.assertEqual(item.fixedSizeUnit(), Qgis.RenderUnit.Inches) self.assertEqual(item.offsetFromCallout(), QSizeF(13.6, 17.2)) self.assertEqual(item.offsetFromCalloutUnit(), Qgis.RenderUnit.Inches) - item.setBackgroundSymbol(QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black'})) - item.setFrameSymbol(QgsFillSymbol.createSimple( - {'color': '100,200,250', 'outline_color': 'black'})) + item.setBackgroundSymbol( + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black"} + ) + ) + item.setFrameSymbol( + QgsFillSymbol.createSimple( + {"color": "100,200,250", "outline_color": "black"} + ) + ) self.assertEqual(item.backgroundSymbol()[0].color(), QColor(200, 100, 100)) - self.assertEqual(item.frameSymbol()[0].color(), - QColor(100, 200, 250)) + self.assertEqual(item.frameSymbol()[0].color(), QColor(100, 200, 250)) def test_nodes_spatial_bounds(self): """ Test nodes for item, spatial bounds mode """ - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, self.get_test_data_path('rgb256x256.png').as_posix(), - QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(10, 20, 30, 40), + ) # nodes shouldn't form a closed ring - self.assertEqual(item.nodesV2(QgsAnnotationItemEditContext()), [ - QgsAnnotationItemNode(QgsVertexId(0, 0, 0), QgsPointXY(10, 20), Qgis.AnnotationItemNodeType.VertexHandle), - QgsAnnotationItemNode(QgsVertexId(0, 0, 1), QgsPointXY(30, 20), Qgis.AnnotationItemNodeType.VertexHandle), - QgsAnnotationItemNode(QgsVertexId(0, 0, 2), QgsPointXY(30, 40), Qgis.AnnotationItemNodeType.VertexHandle), - QgsAnnotationItemNode(QgsVertexId(0, 0, 3), QgsPointXY(10, 40), Qgis.AnnotationItemNodeType.VertexHandle), - QgsAnnotationItemNode(QgsVertexId(1, 0, 0), QgsPointXY(20, 30), Qgis.AnnotationItemNodeType.CalloutHandle)]) + self.assertEqual( + item.nodesV2(QgsAnnotationItemEditContext()), + [ + QgsAnnotationItemNode( + QgsVertexId(0, 0, 0), + QgsPointXY(10, 20), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + QgsAnnotationItemNode( + QgsVertexId(0, 0, 1), + QgsPointXY(30, 20), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + QgsAnnotationItemNode( + QgsVertexId(0, 0, 2), + QgsPointXY(30, 40), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + QgsAnnotationItemNode( + QgsVertexId(0, 0, 3), + QgsPointXY(10, 40), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + QgsAnnotationItemNode( + QgsVertexId(1, 0, 0), + QgsPointXY(20, 30), + Qgis.AnnotationItemNodeType.CalloutHandle, + ), + ], + ) def test_nodes_fixed_size(self): """ Test nodes for item, fixed size mode """ - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, self.get_test_data_path('rgb256x256.png').as_posix(), - QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(10, 20, 30, 40), + ) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) context = QgsAnnotationItemEditContext() context.setCurrentItemBounds(QgsRectangle(10, 20, 30, 40)) - self.assertEqual(item.nodesV2(context), [ - QgsAnnotationItemNode(QgsVertexId(0, 0, 0), QgsPointXY(20, 30), Qgis.AnnotationItemNodeType.VertexHandle), - QgsAnnotationItemNode(QgsVertexId(1, 0, 0), QgsPointXY(10, 20), Qgis.AnnotationItemNodeType.CalloutHandle)]) + self.assertEqual( + item.nodesV2(context), + [ + QgsAnnotationItemNode( + QgsVertexId(0, 0, 0), + QgsPointXY(20, 30), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + QgsAnnotationItemNode( + QgsVertexId(1, 0, 0), + QgsPointXY(10, 20), + Qgis.AnnotationItemNodeType.CalloutHandle, + ), + ], + ) def test_nodes_relative_to_map(self): """ Test nodes for item, relative to map mode """ - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, self.get_test_data_path('rgb256x256.png').as_posix(), - QgsRectangle(0.25, 0.75, 30, 40)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(0.25, 0.75, 30, 40), + ) item.setPlacementMode(Qgis.AnnotationPlacementMode.RelativeToMapFrame) context = QgsAnnotationItemEditContext() context.setCurrentItemBounds(QgsRectangle(10, 20, 30, 40)) - self.assertEqual(item.nodesV2(context), [ - QgsAnnotationItemNode(QgsVertexId(0, 0, 0), QgsPointXY(20, 30), Qgis.AnnotationItemNodeType.VertexHandle)]) + self.assertEqual( + item.nodesV2(context), + [ + QgsAnnotationItemNode( + QgsVertexId(0, 0, 0), + QgsPointXY(20, 30), + Qgis.AnnotationItemNodeType.VertexHandle, + ) + ], + ) def test_translate_spatial_bounds(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, - self.get_test_data_path( - 'rgb256x256.png').as_posix(), - QgsRectangle(10, 20, 30, 40)) - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(10, 20, 30, 40), + ) + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200), - QgsAnnotationItemEditContext()), - Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '110.000,220.000 : 130.000,240.000') + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "110.000,220.000 : 130.000,240.000") def test_translate_fixed_size(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, - self.get_test_data_path( - 'rgb256x256.png').as_posix(), - QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(10, 20, 30, 40), + ) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") context = QgsAnnotationItemEditContext() render_context = QgsRenderContext() render_context.setScaleFactor(5) context.setRenderContext(render_context) - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200), - context), - Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '110.000,220.000 : 130.000,240.000') + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200), context + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "110.000,220.000 : 130.000,240.000") self.assertEqual(item.offsetFromCallout(), QSizeF()) def test_translate_fixed_size_with_callout_anchor(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, - self.get_test_data_path( - 'rgb256x256.png').as_posix(), - QgsRectangle(10, 20, 30, 40)) - item.setCalloutAnchor(QgsGeometry.fromWkt('Point(1 3)')) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(10, 20, 30, 40), + ) + item.setCalloutAnchor(QgsGeometry.fromWkt("Point(1 3)")) item.setCallout(QgsBalloonCallout()) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") context = QgsAnnotationItemEditContext() render_context = QgsRenderContext() render_context.setScaleFactor(5) context.setRenderContext(render_context) - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200, 50, 30), - context), - Qgis.AnnotationItemEditOperationResult.Success) + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200, 50, 30), + context, + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) # should affect callout offset only self.assertEqual(item.offsetFromCallout(), QSizeF(9, 5)) self.assertEqual(item.offsetFromCalloutUnit(), Qgis.RenderUnit.Millimeters) def test_translate_relative_to_map(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, - self.get_test_data_path( - 'rgb256x256.png').as_posix(), - QgsRectangle(0.2, 0.8, 30, 40)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(0.2, 0.8, 30, 40), + ) item.setPlacementMode(Qgis.AnnotationPlacementMode.RelativeToMapFrame) - self.assertEqual(item.bounds().toString(3), '0.200,0.800 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "0.200,0.800 : 30.000,40.000") context = QgsAnnotationItemEditContext() render_context = QgsRenderContext() @@ -205,80 +289,128 @@ def test_translate_relative_to_map(self): render_context.setOutputSize(QSize(1000, 600)) context.setRenderContext(render_context) - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200, 100, 200), - context), - Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '0.300,1.133 : 30.100,40.333') + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200, 100, 200), + context, + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "0.300,1.133 : 30.100,40.333") self.assertEqual(item.offsetFromCallout(), QSizeF()) def test_apply_move_node_edit_spatial_bounds(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, - self.get_test_data_path( - 'rgb256x256.png').as_posix(), - QgsRectangle(10, 20, 30, 40)) - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') - - self.assertEqual(item.applyEditV2( - QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(30, 20), QgsPoint(17, 18)), - QgsAnnotationItemEditContext()), - Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '10.000,18.000 : 17.000,40.000') - self.assertEqual(item.applyEditV2( - QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 0), QgsPoint(10, 18), QgsPoint(5, 13)), - QgsAnnotationItemEditContext()), - Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '5.000,13.000 : 17.000,40.000') - self.assertEqual(item.applyEditV2( - QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 2), QgsPoint(17, 14), QgsPoint(18, 38)), - QgsAnnotationItemEditContext()), - Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '5.000,13.000 : 18.000,38.000') - self.assertEqual(item.applyEditV2( - QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 3), QgsPoint(5, 38), QgsPoint(2, 39)), - QgsAnnotationItemEditContext()), - Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '2.000,13.000 : 18.000,39.000') + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(10, 20, 30, 40), + ) + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") + + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 1), QgsPoint(30, 20), QgsPoint(17, 18) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "10.000,18.000 : 17.000,40.000") + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 0), QgsPoint(10, 18), QgsPoint(5, 13) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "5.000,13.000 : 17.000,40.000") + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 2), QgsPoint(17, 14), QgsPoint(18, 38) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "5.000,13.000 : 18.000,38.000") + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 3), QgsPoint(5, 38), QgsPoint(2, 39) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "2.000,13.000 : 18.000,39.000") # move callout handle - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(1, 0, 0), QgsPoint(14, 13), QgsPoint(1, 3)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '2.000,13.000 : 18.000,39.000') - self.assertEqual(item.calloutAnchor().asWkt(), 'Point (1 3)') + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(1, 0, 0), QgsPoint(14, 13), QgsPoint(1, 3) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "2.000,13.000 : 18.000,39.000") + self.assertEqual(item.calloutAnchor().asWkt(), "Point (1 3)") # callout should have been automatically created self.assertIsInstance(item.callout(), QgsCallout) def test_apply_move_node_edit_fixed_size(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, - self.get_test_data_path( - 'rgb256x256.png').as_posix(), - QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(10, 20, 30, 40), + ) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") context = QgsAnnotationItemEditContext() render_context = QgsRenderContext() render_context.setScaleFactor(5) context.setRenderContext(render_context) - self.assertEqual(item.applyEditV2( - QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 0), QgsPoint(30, 20), QgsPoint(17, 18)), - context), - Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '7.000,8.000 : 27.000,28.000') + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 0), QgsPoint(30, 20), QgsPoint(17, 18) + ), + context, + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "7.000,8.000 : 27.000,28.000") # move callout handle - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(1, 0, 0), QgsPoint(14, 13), QgsPoint(1, 3)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '7.000,8.000 : 27.000,28.000') - self.assertEqual(item.calloutAnchor().asWkt(), 'Point (1 3)') + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(1, 0, 0), QgsPoint(14, 13), QgsPoint(1, 3) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "7.000,8.000 : 27.000,28.000") + self.assertEqual(item.calloutAnchor().asWkt(), "Point (1 3)") # callout should have been automatically created self.assertIsInstance(item.callout(), QgsCallout) def test_apply_move_node_edit_relative_to_map(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, - self.get_test_data_path( - 'rgb256x256.png').as_posix(), - QgsRectangle(0.2, 0.8, 30, 40)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(0.2, 0.8, 30, 40), + ) item.setPlacementMode(Qgis.AnnotationPlacementMode.RelativeToMapFrame) - self.assertEqual(item.bounds().toString(3), '0.200,0.800 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "0.200,0.800 : 30.000,40.000") context = QgsAnnotationItemEditContext() render_context = QgsRenderContext() @@ -286,82 +418,123 @@ def test_apply_move_node_edit_relative_to_map(self): render_context.setOutputSize(QSize(2000, 600)) context.setRenderContext(render_context) - self.assertEqual(item.applyEditV2( - QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 0), QgsPoint(30, 20), QgsPoint(17, 18), 100, 200), - context), - Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '0.250,1.133 : 30.050,40.333') + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", + QgsVertexId(0, 0, 0), + QgsPoint(30, 20), + QgsPoint(17, 18), + 100, + 200, + ), + context, + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "0.250,1.133 : 30.050,40.333") def test_apply_delete_node_edit(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, - self.get_test_data_path( - 'rgb256x256.png').as_posix(), - QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(10, 20, 30, 40), + ) self.assertEqual( - item.applyEdit(QgsAnnotationItemEditOperationDeleteNode('', QgsVertexId(0, 0, 1), QgsPoint(14, 13))), - Qgis.AnnotationItemEditOperationResult.Invalid) + item.applyEdit( + QgsAnnotationItemEditOperationDeleteNode( + "", QgsVertexId(0, 0, 1), QgsPoint(14, 13) + ) + ), + Qgis.AnnotationItemEditOperationResult.Invalid, + ) def test_apply_add_node_edit(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, - self.get_test_data_path( - 'rgb256x256.png').as_posix(), - QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(10, 20, 30, 40), + ) - self.assertEqual(item.applyEdit(QgsAnnotationItemEditOperationAddNode('', QgsPoint(15, 16))), - Qgis.AnnotationItemEditOperationResult.Invalid) + self.assertEqual( + item.applyEdit(QgsAnnotationItemEditOperationAddNode("", QgsPoint(15, 16))), + Qgis.AnnotationItemEditOperationResult.Invalid, + ) def test_transient_move_operation_spatial_bounds(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, - self.get_test_data_path( - 'rgb256x256.png').as_posix(), - QgsRectangle(10, 20, 30, 40)) - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(10, 20, 30, 40), + ) + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") res = item.transientEditResultsV2( - QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(30, 20), QgsPoint(17, 18)), - QgsAnnotationItemEditContext()) - self.assertEqual(res.representativeGeometry().asWkt(), 'Polygon ((10 18, 17 18, 17 40, 10 40, 10 18))') + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 1), QgsPoint(30, 20), QgsPoint(17, 18) + ), + QgsAnnotationItemEditContext(), + ) + self.assertEqual( + res.representativeGeometry().asWkt(), + "Polygon ((10 18, 17 18, 17 40, 10 40, 10 18))", + ) # move callout handle - res = item.transientEditResultsV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(1, 0, 0), QgsPoint(14, 13), QgsPoint(1, 3)), QgsAnnotationItemEditContext()) - self.assertEqual(res.representativeGeometry().asWkt(), - 'Point (1 3)') + res = item.transientEditResultsV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(1, 0, 0), QgsPoint(14, 13), QgsPoint(1, 3) + ), + QgsAnnotationItemEditContext(), + ) + self.assertEqual(res.representativeGeometry().asWkt(), "Point (1 3)") def test_transient_move_operation_fixed_size(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, - self.get_test_data_path( - 'rgb256x256.png').as_posix(), - QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(10, 20, 30, 40), + ) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - item.setFixedSize(QSizeF(56, - 57)) + item.setFixedSize(QSizeF(56, 57)) item.setFixedSizeUnit(Qgis.RenderUnit.Inches) - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") - op = QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(30, 20), QgsPoint(17, 18)) + op = QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 1), QgsPoint(30, 20), QgsPoint(17, 18) + ) context = QgsAnnotationItemEditContext() context.setCurrentItemBounds(QgsRectangle(1, 2, 3, 4)) res = item.transientEditResultsV2(op, context) - self.assertEqual(res.representativeGeometry().asWkt(), 'Polygon ((16 17, 18 17, 18 19, 16 19, 16 17))') + self.assertEqual( + res.representativeGeometry().asWkt(), + "Polygon ((16 17, 18 17, 18 19, 16 19, 16 17))", + ) # move callout handle - res = item.transientEditResultsV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(1, 0, 0), QgsPoint(14, 13), QgsPoint(1, 3)), QgsAnnotationItemEditContext()) - self.assertEqual(res.representativeGeometry().asWkt(), - 'Point (1 3)') + res = item.transientEditResultsV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(1, 0, 0), QgsPoint(14, 13), QgsPoint(1, 3) + ), + QgsAnnotationItemEditContext(), + ) + self.assertEqual(res.representativeGeometry().asWkt(), "Point (1 3)") def test_transient_move_operation_relative_map(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, - self.get_test_data_path( - 'rgb256x256.png').as_posix(), - QgsRectangle(0.2, 0.8, 30, 40)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(0.2, 0.8, 30, 40), + ) item.setPlacementMode(Qgis.AnnotationPlacementMode.RelativeToMapFrame) - item.setFixedSize(QSizeF(56, - 57)) + item.setFixedSize(QSizeF(56, 57)) item.setFixedSizeUnit(Qgis.RenderUnit.Inches) - self.assertEqual(item.bounds().toString(3), '0.200,0.800 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "0.200,0.800 : 30.000,40.000") - op = QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(30, 20), QgsPoint(17, 18), 100, 200) + op = QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 1), QgsPoint(30, 20), QgsPoint(17, 18), 100, 200 + ) render_context = QgsRenderContext() render_context.setScaleFactor(5) render_context.setOutputSize(QSize(2000, 600)) @@ -370,32 +543,40 @@ def test_transient_move_operation_relative_map(self): context.setRenderContext(render_context) context.setCurrentItemBounds(QgsRectangle(1, 2, 3, 4)) res = item.transientEditResultsV2(op, context) - self.assertEqual(res.representativeGeometry().asWkt(), 'Polygon ((-12 0, -10 0, -10 2, -12 2, -12 0))') + self.assertEqual( + res.representativeGeometry().asWkt(), + "Polygon ((-12 0, -10 0, -10 2, -12 2, -12 0))", + ) def test_transient_translate_operation_spatial_bounds(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, - self.get_test_data_path( - 'rgb256x256.png').as_posix(), - QgsRectangle(10, 20, 30, 40)) - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(10, 20, 30, 40), + ) + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") - res = item.transientEditResultsV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200), - QgsAnnotationItemEditContext()) - self.assertEqual(res.representativeGeometry().asWkt(), - 'Polygon ((110 220, 130 220, 130 240, 110 240, 110 220))') + res = item.transientEditResultsV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200), + QgsAnnotationItemEditContext(), + ) + self.assertEqual( + res.representativeGeometry().asWkt(), + "Polygon ((110 220, 130 220, 130 240, 110 240, 110 220))", + ) def test_transient_translate_operation_fixed_size(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, - self.get_test_data_path( - 'rgb256x256.png').as_posix(), - QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(10, 20, 30, 40), + ) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - item.setFixedSize(QSizeF(56, - 57)) + item.setFixedSize(QSizeF(56, 57)) item.setFixedSizeUnit(Qgis.RenderUnit.Inches) - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") - op = QgsAnnotationItemEditOperationTranslateItem('', 100, 200) + op = QgsAnnotationItemEditOperationTranslateItem("", 100, 200) context = QgsAnnotationItemEditContext() context.setCurrentItemBounds(QgsRectangle(1, 2, 3, 4)) render_context = QgsRenderContext() @@ -403,23 +584,25 @@ def test_transient_translate_operation_fixed_size(self): context.setRenderContext(render_context) res = item.transientEditResultsV2(op, context) - self.assertEqual(res.representativeGeometry().asWkt(), - 'Polygon ((119 229, 121 229, 121 231, 119 231, 119 229))') + self.assertEqual( + res.representativeGeometry().asWkt(), + "Polygon ((119 229, 121 229, 121 231, 119 231, 119 229))", + ) def test_transient_translate_operation_fixed_size_with_callout_anchor(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, - self.get_test_data_path( - 'rgb256x256.png').as_posix(), - QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(10, 20, 30, 40), + ) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - item.setFixedSize(QSizeF(56, - 57)) + item.setFixedSize(QSizeF(56, 57)) item.setFixedSizeUnit(Qgis.RenderUnit.Inches) - item.setCalloutAnchor(QgsGeometry.fromWkt('Point(1 3)')) + item.setCalloutAnchor(QgsGeometry.fromWkt("Point(1 3)")) item.setCallout(QgsBalloonCallout()) - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") - op = QgsAnnotationItemEditOperationTranslateItem('', 100, 200, 50, 30) + op = QgsAnnotationItemEditOperationTranslateItem("", 100, 200, 50, 30) context = QgsAnnotationItemEditContext() context.setCurrentItemBounds(QgsRectangle(1, 2, 3, 4)) render_context = QgsRenderContext() @@ -427,21 +610,23 @@ def test_transient_translate_operation_fixed_size_with_callout_anchor(self): context.setRenderContext(render_context) res = item.transientEditResultsV2(op, context) - self.assertEqual(res.representativeGeometry().asWkt(2), - 'Polygon ((50.5 -26.5, 761.7 -26.5, 761.7 -750.4, 50.5 -750.4, 50.5 -26.5))') + self.assertEqual( + res.representativeGeometry().asWkt(2), + "Polygon ((50.5 -26.5, 761.7 -26.5, 761.7 -750.4, 50.5 -750.4, 50.5 -26.5))", + ) def test_transient_translate_operation_relative_map(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, - self.get_test_data_path( - 'rgb256x256.png').as_posix(), - QgsRectangle(0.2, 0.8, 30, 40)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(0.2, 0.8, 30, 40), + ) item.setPlacementMode(Qgis.AnnotationPlacementMode.RelativeToMapFrame) - item.setFixedSize(QSizeF(56, - 57)) + item.setFixedSize(QSizeF(56, 57)) item.setFixedSizeUnit(Qgis.RenderUnit.Inches) - self.assertEqual(item.bounds().toString(3), '0.200,0.800 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "0.200,0.800 : 30.000,40.000") - op = QgsAnnotationItemEditOperationTranslateItem('', 100, 200, 100, 200) + op = QgsAnnotationItemEditOperationTranslateItem("", 100, 200, 100, 200) context = QgsAnnotationItemEditContext() context.setCurrentItemBounds(QgsRectangle(1, 2, 3, 4)) render_context = QgsRenderContext() @@ -449,26 +634,38 @@ def test_transient_translate_operation_relative_map(self): context.setRenderContext(render_context) res = item.transientEditResultsV2(op, context) - self.assertEqual(res.representativeGeometry().asWkt(), - 'Polygon ((101 202, 103 202, 103 204, 101 204, 101 202))') + self.assertEqual( + res.representativeGeometry().asWkt(), + "Polygon ((101 202, 103 202, 103 204, 101 204, 101 202))", + ) def testReadWriteXml(self): doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, self.get_test_data_path('rgb256x256.png').as_posix(), - QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(10, 20, 30, 40), + ) item.setBackgroundEnabled(True) - item.setBackgroundSymbol(QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black'})) + item.setBackgroundSymbol( + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black"} + ) + ) item.setFrameEnabled(True) - item.setFrameSymbol(QgsFillSymbol.createSimple({'color': '100,200,150', 'outline_color': 'black'})) + item.setFrameSymbol( + QgsFillSymbol.createSimple( + {"color": "100,200,150", "outline_color": "black"} + ) + ) item.setZIndex(11) item.setLockAspectRatio(False) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - item.setFixedSize(QSizeF(56, - 57)) + item.setFixedSize(QSizeF(56, 57)) item.setFixedSizeUnit(Qgis.RenderUnit.Inches) - item.setCalloutAnchor(QgsGeometry.fromWkt('Point(1 3)')) + item.setCalloutAnchor(QgsGeometry.fromWkt("Point(1 3)")) item.setCallout(QgsBalloonCallout()) item.setOffsetFromCallout(QSizeF(13.6, 17.2)) item.setOffsetFromCalloutUnit(Qgis.RenderUnit.Inches) @@ -478,72 +675,83 @@ def testReadWriteXml(self): s2 = QgsAnnotationPictureItem.create() self.assertTrue(s2.readXml(elem, QgsReadWriteContext())) - self.assertEqual(s2.bounds().toString(3), '10.000,20.000 : 30.000,40.000') - self.assertEqual(s2.path(), self.get_test_data_path('rgb256x256.png').as_posix()) + self.assertEqual(s2.bounds().toString(3), "10.000,20.000 : 30.000,40.000") + self.assertEqual( + s2.path(), self.get_test_data_path("rgb256x256.png").as_posix() + ) self.assertEqual(s2.format(), Qgis.PictureFormat.Raster) self.assertEqual(s2.backgroundSymbol()[0].color(), QColor(200, 100, 100)) - self.assertEqual(s2.frameSymbol()[0].color(), - QColor(100, 200, 150)) + self.assertEqual(s2.frameSymbol()[0].color(), QColor(100, 200, 150)) self.assertEqual(s2.zIndex(), 11) self.assertTrue(s2.frameEnabled()) self.assertTrue(s2.backgroundEnabled()) self.assertFalse(s2.lockAspectRatio()) - self.assertEqual(s2.placementMode(), - Qgis.AnnotationPlacementMode.FixedSize) - self.assertEqual(s2.fixedSize(), QSizeF(56, - 57)) + self.assertEqual(s2.placementMode(), Qgis.AnnotationPlacementMode.FixedSize) + self.assertEqual(s2.fixedSize(), QSizeF(56, 57)) self.assertEqual(s2.fixedSizeUnit(), Qgis.RenderUnit.Inches) - self.assertEqual(s2.calloutAnchor().asWkt(), 'Point (1 3)') + self.assertEqual(s2.calloutAnchor().asWkt(), "Point (1 3)") self.assertIsInstance(s2.callout(), QgsBalloonCallout) self.assertEqual(s2.offsetFromCallout(), QSizeF(13.6, 17.2)) self.assertEqual(s2.offsetFromCalloutUnit(), Qgis.RenderUnit.Inches) def testClone(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, self.get_test_data_path('rgb256x256.png').as_posix(), - QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(10, 20, 30, 40), + ) item.setBackgroundEnabled(True) - item.setBackgroundSymbol(QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black'})) + item.setBackgroundSymbol( + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black"} + ) + ) item.setFrameEnabled(True) - item.setFrameSymbol(QgsFillSymbol.createSimple({'color': '100,200,150', 'outline_color': 'black'})) + item.setFrameSymbol( + QgsFillSymbol.createSimple( + {"color": "100,200,150", "outline_color": "black"} + ) + ) item.setZIndex(11) item.setLockAspectRatio(False) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - item.setFixedSize(QSizeF(56, - 57)) + item.setFixedSize(QSizeF(56, 57)) item.setFixedSizeUnit(Qgis.RenderUnit.Inches) - item.setCalloutAnchor(QgsGeometry.fromWkt('Point(1 3)')) + item.setCalloutAnchor(QgsGeometry.fromWkt("Point(1 3)")) item.setCallout(QgsBalloonCallout()) item.setOffsetFromCallout(QSizeF(13.6, 17.2)) item.setOffsetFromCalloutUnit(Qgis.RenderUnit.Inches) s2 = item.clone() - self.assertEqual(s2.bounds().toString(3), '10.000,20.000 : 30.000,40.000') - self.assertEqual(s2.path(), self.get_test_data_path('rgb256x256.png').as_posix()) + self.assertEqual(s2.bounds().toString(3), "10.000,20.000 : 30.000,40.000") + self.assertEqual( + s2.path(), self.get_test_data_path("rgb256x256.png").as_posix() + ) self.assertEqual(s2.format(), Qgis.PictureFormat.Raster) self.assertEqual(s2.backgroundSymbol()[0].color(), QColor(200, 100, 100)) - self.assertEqual(s2.frameSymbol()[0].color(), - QColor(100, 200, 150)) + self.assertEqual(s2.frameSymbol()[0].color(), QColor(100, 200, 150)) self.assertEqual(s2.zIndex(), 11) self.assertTrue(s2.frameEnabled()) self.assertTrue(s2.backgroundEnabled()) self.assertFalse(s2.lockAspectRatio()) - self.assertEqual(s2.placementMode(), - Qgis.AnnotationPlacementMode.FixedSize) - self.assertEqual(s2.fixedSize(), QSizeF(56, - 57)) + self.assertEqual(s2.placementMode(), Qgis.AnnotationPlacementMode.FixedSize) + self.assertEqual(s2.fixedSize(), QSizeF(56, 57)) self.assertEqual(s2.fixedSizeUnit(), Qgis.RenderUnit.Inches) - self.assertEqual(s2.calloutAnchor().asWkt(), 'Point (1 3)') + self.assertEqual(s2.calloutAnchor().asWkt(), "Point (1 3)") self.assertIsInstance(s2.callout(), QgsBalloonCallout) self.assertEqual(s2.offsetFromCallout(), QSizeF(13.6, 17.2)) self.assertEqual(s2.offsetFromCalloutUnit(), Qgis.RenderUnit.Inches) def testRenderRasterLockedAspect(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, self.get_test_data_path('rgb256x256.png').as_posix(), - QgsRectangle(12, 13, 16, 15)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(12, 13, 16, 15), + ) item.setLockAspectRatio(True) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(300, 300)) @@ -562,15 +770,22 @@ def testRenderRasterLockedAspect(self): finally: painter.end() - self.assertTrue(self.image_check('picture_raster_locked_aspect', 'picture_raster_locked_aspect', image)) + self.assertTrue( + self.image_check( + "picture_raster_locked_aspect", "picture_raster_locked_aspect", image + ) + ) def testRenderRasterUnlockedAspect(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, self.get_test_data_path('rgb256x256.png').as_posix(), - QgsRectangle(12, 13, 16, 15)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(12, 13, 16, 15), + ) item.setLockAspectRatio(False) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(300, 300)) @@ -589,15 +804,24 @@ def testRenderRasterUnlockedAspect(self): finally: painter.end() - self.assertTrue(self.image_check('picture_raster_unlocked_aspect', 'picture_raster_unlocked_aspect', image)) + self.assertTrue( + self.image_check( + "picture_raster_unlocked_aspect", + "picture_raster_unlocked_aspect", + image, + ) + ) def testRenderSvgLockedAspect(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.SVG, self.get_test_data_path('sample_svg.svg').as_posix(), - QgsRectangle(12, 13, 16, 15)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.SVG, + self.get_test_data_path("sample_svg.svg").as_posix(), + QgsRectangle(12, 13, 16, 15), + ) item.setLockAspectRatio(True) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(300, 300)) @@ -616,15 +840,22 @@ def testRenderSvgLockedAspect(self): finally: painter.end() - self.assertTrue(self.image_check('picture_svg_locked_aspect', 'picture_svg_locked_aspect', image)) + self.assertTrue( + self.image_check( + "picture_svg_locked_aspect", "picture_svg_locked_aspect", image + ) + ) def testRenderSvgUnlockedAspect(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.SVG, self.get_test_data_path('sample_svg.svg').as_posix(), - QgsRectangle(12, 13, 16, 15)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.SVG, + self.get_test_data_path("sample_svg.svg").as_posix(), + QgsRectangle(12, 13, 16, 15), + ) item.setLockAspectRatio(False) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(300, 300)) @@ -643,14 +874,21 @@ def testRenderSvgUnlockedAspect(self): finally: painter.end() - self.assertTrue(self.image_check('picture_svg_unlocked_aspect', 'picture_svg_unlocked_aspect', image)) + self.assertTrue( + self.image_check( + "picture_svg_unlocked_aspect", "picture_svg_unlocked_aspect", image + ) + ) def testRenderWithTransform(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, self.get_test_data_path('rgb256x256.png').as_posix(), - QgsRectangle(11.5, 13, 12, 13.5)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(11.5, 13, 12, 13.5), + ) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) settings.setExtent(QgsRectangle(1250958, 1386945, 1420709, 1532518)) settings.setOutputSize(QSize(300, 300)) @@ -658,8 +896,12 @@ def testRenderWithTransform(self): rc = QgsRenderContext.fromMapSettings(settings) rc.setCoordinateTransform( - QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'), settings.destinationCrs(), - QgsProject.instance())) + QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + settings.destinationCrs(), + QgsProject.instance(), + ) + ) image = QImage(200, 200, QImage.Format.Format_ARGB32) image.setDotsPerMeterX(int(96 / 25.4 * 1000)) image.setDotsPerMeterY(int(96 / 25.4 * 1000)) @@ -672,20 +914,25 @@ def testRenderWithTransform(self): finally: painter.end() - self.assertTrue(self.image_check('picture_transform', 'picture_transform', image)) + self.assertTrue( + self.image_check("picture_transform", "picture_transform", image) + ) def testRenderCallout(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, self.get_test_data_path('rgb256x256.png').as_posix(), - QgsRectangle(12, 13, 16, 15)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(12, 13, 16, 15), + ) item.setLockAspectRatio(True) callout = QgsSimpleLineCallout() callout.lineSymbol().setWidth(1) item.setCallout(callout) - item.setCalloutAnchor(QgsGeometry.fromWkt('Point(11 12)')) + item.setCalloutAnchor(QgsGeometry.fromWkt("Point(11 12)")) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 8, 18, 16)) settings.setOutputSize(QSize(300, 300)) @@ -704,19 +951,21 @@ def testRenderCallout(self): finally: painter.end() - self.assertTrue(self.image_check('picture_callout', 'picture_callout', image)) + self.assertTrue(self.image_check("picture_callout", "picture_callout", image)) def testRenderFixedSizeRaster(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, self.get_test_data_path('rgb256x256.png').as_posix(), - QgsRectangle(12, 13, 16, 15)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(12, 13, 16, 15), + ) item.setLockAspectRatio(True) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - item.setFixedSize(QSizeF(10, - 20)) + item.setFixedSize(QSizeF(10, 20)) item.setFixedSizeUnit(Qgis.RenderUnit.Millimeters) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(300, 300)) @@ -735,26 +984,32 @@ def testRenderFixedSizeRaster(self): finally: painter.end() - self.assertTrue(self.image_check('picture_fixed_size_raster', 'picture_fixed_size_raster', image)) + self.assertTrue( + self.image_check( + "picture_fixed_size_raster", "picture_fixed_size_raster", image + ) + ) def testRenderFixedSizeCallout(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, self.get_test_data_path('rgb256x256.png').as_posix(), - QgsRectangle(12, 13, 16, 15)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(12, 13, 16, 15), + ) item.setLockAspectRatio(True) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - item.setFixedSize(QSizeF(10, - 20)) + item.setFixedSize(QSizeF(10, 20)) item.setFixedSizeUnit(Qgis.RenderUnit.Millimeters) callout = QgsSimpleLineCallout() callout.lineSymbol().setWidth(1) item.setCallout(callout) - item.setCalloutAnchor(QgsGeometry.fromWkt('Point(11 12)')) + item.setCalloutAnchor(QgsGeometry.fromWkt("Point(11 12)")) item.setOffsetFromCallout(QSizeF(60, -80)) item.setOffsetFromCalloutUnit(Qgis.RenderUnit.Points) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 8, 18, 16)) settings.setOutputSize(QSize(300, 300)) @@ -773,19 +1028,25 @@ def testRenderFixedSizeCallout(self): finally: painter.end() - self.assertTrue(self.image_check('picture_fixed_size_callout', 'picture_fixed_size_callout', image)) + self.assertTrue( + self.image_check( + "picture_fixed_size_callout", "picture_fixed_size_callout", image + ) + ) def testRenderSvgFixedSize(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.SVG, self.get_test_data_path('sample_svg.svg').as_posix(), - QgsRectangle(12, 13, 16, 15)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.SVG, + self.get_test_data_path("sample_svg.svg").as_posix(), + QgsRectangle(12, 13, 16, 15), + ) item.setLockAspectRatio(True) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - item.setFixedSize(QSizeF(30, - 50)) + item.setFixedSize(QSizeF(30, 50)) item.setFixedSizeUnit(Qgis.RenderUnit.Millimeters) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(300, 300)) @@ -804,18 +1065,22 @@ def testRenderSvgFixedSize(self): finally: painter.end() - self.assertTrue(self.image_check('picture_svg_fixed_size', 'picture_svg_fixed_size', image)) + self.assertTrue( + self.image_check("picture_svg_fixed_size", "picture_svg_fixed_size", image) + ) def testRenderWithTransformFixedSize(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, self.get_test_data_path('rgb256x256.png').as_posix(), - QgsRectangle(11.5, 13, 12, 13.5)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(11.5, 13, 12, 13.5), + ) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - item.setFixedSize(QSizeF(10, - 20)) + item.setFixedSize(QSizeF(10, 20)) item.setFixedSizeUnit(Qgis.RenderUnit.Millimeters) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) settings.setExtent(QgsRectangle(1250958, 1386945, 1420709, 1532518)) settings.setOutputSize(QSize(300, 300)) @@ -823,8 +1088,12 @@ def testRenderWithTransformFixedSize(self): rc = QgsRenderContext.fromMapSettings(settings) rc.setCoordinateTransform( - QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'), settings.destinationCrs(), - QgsProject.instance())) + QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + settings.destinationCrs(), + QgsProject.instance(), + ) + ) image = QImage(200, 200, QImage.Format.Format_ARGB32) image.setDotsPerMeterX(int(96 / 25.4 * 1000)) image.setDotsPerMeterY(int(96 / 25.4 * 1000)) @@ -837,19 +1106,25 @@ def testRenderWithTransformFixedSize(self): finally: painter.end() - self.assertTrue(self.image_check('picture_transform_fixed_size', 'picture_transform_fixed_size', image)) + self.assertTrue( + self.image_check( + "picture_transform_fixed_size", "picture_transform_fixed_size", image + ) + ) def testRenderRelativeMapRaster(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, self.get_test_data_path('rgb256x256.png').as_posix(), - QgsRectangle.fromCenterAndSize(QgsPointXY(0.3, 0.7), 1, 1)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle.fromCenterAndSize(QgsPointXY(0.3, 0.7), 1, 1), + ) item.setLockAspectRatio(True) item.setPlacementMode(Qgis.AnnotationPlacementMode.RelativeToMapFrame) - item.setFixedSize(QSizeF(10, - 20)) + item.setFixedSize(QSizeF(10, 20)) item.setFixedSizeUnit(Qgis.RenderUnit.Millimeters) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(300, 300)) @@ -868,20 +1143,38 @@ def testRenderRelativeMapRaster(self): finally: painter.end() - self.assertTrue(self.image_check('picture_relative_to_map', 'picture_relative_to_map', image)) + self.assertTrue( + self.image_check( + "picture_relative_to_map", "picture_relative_to_map", image + ) + ) def testRenderBackgroundFrame(self): - item = QgsAnnotationPictureItem(Qgis.PictureFormat.Raster, self.get_test_data_path('rgb256x256.png').as_posix(), - QgsRectangle(12, 13, 16, 15)) + item = QgsAnnotationPictureItem( + Qgis.PictureFormat.Raster, + self.get_test_data_path("rgb256x256.png").as_posix(), + QgsRectangle(12, 13, 16, 15), + ) item.setLockAspectRatio(True) item.setFrameEnabled(True) item.setBackgroundEnabled(True) - item.setBackgroundSymbol(QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black'})) - item.setFrameSymbol(QgsFillSymbol.createSimple( - {'color': '100,200,250,120', 'outline_color': 'black', 'outline_width': 2})) + item.setBackgroundSymbol( + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black"} + ) + ) + item.setFrameSymbol( + QgsFillSymbol.createSimple( + { + "color": "100,200,250,120", + "outline_color": "black", + "outline_width": 2, + } + ) + ) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(300, 300)) @@ -900,8 +1193,12 @@ def testRenderBackgroundFrame(self): finally: painter.end() - self.assertTrue(self.image_check('picture_frame_background', 'picture_frame_background', image)) + self.assertTrue( + self.image_check( + "picture_frame_background", "picture_frame_background", image + ) + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsannotationpointtextitem.py b/tests/src/python/test_qgsannotationpointtextitem.py index 919791b0e1ff..0e6d6ae662c3 100644 --- a/tests/src/python/test_qgsannotationpointtextitem.py +++ b/tests/src/python/test_qgsannotationpointtextitem.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 by Nyall Dawson' -__date__ = '10/08/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 by Nyall Dawson" +__date__ = "10/08/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QSize, Qt from qgis.PyQt.QtGui import QColor, QImage, QPainter @@ -37,7 +38,7 @@ QgsCallout, QgsBalloonCallout, QgsGeometry, - QgsSimpleLineCallout + QgsSimpleLineCallout, ) import unittest @@ -56,13 +57,13 @@ def control_path_prefix(cls): return "annotation_layer" def testBasic(self): - item = QgsAnnotationPointTextItem('my text', QgsPointXY(12, 13)) + item = QgsAnnotationPointTextItem("my text", QgsPointXY(12, 13)) - self.assertEqual(item.text(), 'my text') + self.assertEqual(item.text(), "my text") self.assertEqual(item.point().x(), 12.0) self.assertEqual(item.point().y(), 13.0) - item.setText('tttttt') + item.setText("tttttt") item.setPoint(QgsPointXY(1000, 2000)) item.setAngle(55) item.setAlignment(Qt.AlignmentFlag.AlignRight) @@ -73,76 +74,134 @@ def testBasic(self): format.setSize(37) item.setFormat(format) - self.assertEqual(item.text(), 'tttttt') + self.assertEqual(item.text(), "tttttt") self.assertEqual(item.point().x(), 1000.0) self.assertEqual(item.point().y(), 2000.0) self.assertEqual(item.angle(), 55.0) self.assertEqual(item.alignment(), Qt.AlignmentFlag.AlignRight) self.assertEqual(item.zIndex(), 11) self.assertEqual(item.format().size(), 37) - self.assertEqual(item.rotationMode(), Qgis.SymbolRotationMode.RespectMapRotation) + self.assertEqual( + item.rotationMode(), Qgis.SymbolRotationMode.RespectMapRotation + ) def test_nodes(self): """ Test nodes for item """ - item = QgsAnnotationPointTextItem('my text', QgsPointXY(12, 13)) + item = QgsAnnotationPointTextItem("my text", QgsPointXY(12, 13)) context = QgsAnnotationItemEditContext() context.setCurrentItemBounds(QgsRectangle(12, 13, 20, 23)) - self.assertEqual(item.nodesV2(context), - [QgsAnnotationItemNode(QgsVertexId(0, 0, 0), QgsPointXY(12, 13), Qgis.AnnotationItemNodeType.VertexHandle), - QgsAnnotationItemNode(QgsVertexId(0, 0, 1), QgsPointXY(16, 18), Qgis.AnnotationItemNodeType.CalloutHandle)]) + self.assertEqual( + item.nodesV2(context), + [ + QgsAnnotationItemNode( + QgsVertexId(0, 0, 0), + QgsPointXY(12, 13), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + QgsAnnotationItemNode( + QgsVertexId(0, 0, 1), + QgsPointXY(16, 18), + Qgis.AnnotationItemNodeType.CalloutHandle, + ), + ], + ) def test_transform(self): - item = QgsAnnotationPointTextItem('my text', QgsPointXY(12, 13)) - self.assertEqual(item.point().asWkt(), 'POINT(12 13)') - - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.point().asWkt(), 'POINT(112 213)') + item = QgsAnnotationPointTextItem("my text", QgsPointXY(12, 13)) + self.assertEqual(item.point().asWkt(), "POINT(12 13)") + + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.point().asWkt(), "POINT(112 213)") def test_apply_move_node_edit(self): - item = QgsAnnotationPointTextItem('my text', QgsPointXY(12, 13)) - self.assertEqual(item.point().asWkt(), 'POINT(12 13)') - - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 0), QgsPoint(14, 13), QgsPoint(17, 18)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.point().asWkt(), 'POINT(17 18)') + item = QgsAnnotationPointTextItem("my text", QgsPointXY(12, 13)) + self.assertEqual(item.point().asWkt(), "POINT(12 13)") + + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 0), QgsPoint(14, 13), QgsPoint(17, 18) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.point().asWkt(), "POINT(17 18)") # move callout handle - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(14, 13), QgsPoint(1, 3)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.point().asWkt(), 'POINT(17 18)') - self.assertEqual(item.calloutAnchor().asWkt(), 'Point (1 3)') + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 1), QgsPoint(14, 13), QgsPoint(1, 3) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.point().asWkt(), "POINT(17 18)") + self.assertEqual(item.calloutAnchor().asWkt(), "Point (1 3)") # callout should have been automatically created self.assertIsInstance(item.callout(), QgsCallout) def test_transient_move_operation(self): - item = QgsAnnotationPointTextItem('my text', QgsPointXY(12, 13)) - self.assertEqual(item.point().asWkt(), 'POINT(12 13)') + item = QgsAnnotationPointTextItem("my text", QgsPointXY(12, 13)) + self.assertEqual(item.point().asWkt(), "POINT(12 13)") - res = item.transientEditResultsV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 0), QgsPoint(12, 13), QgsPoint(17, 18)), QgsAnnotationItemEditContext()) - self.assertEqual(res.representativeGeometry().asWkt(), 'Point (17 18)') + res = item.transientEditResultsV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 0), QgsPoint(12, 13), QgsPoint(17, 18) + ), + QgsAnnotationItemEditContext(), + ) + self.assertEqual(res.representativeGeometry().asWkt(), "Point (17 18)") def test_transient_translate_operation(self): - item = QgsAnnotationPointTextItem('my text', QgsPointXY(12, 13)) - self.assertEqual(item.point().asWkt(), 'POINT(12 13)') + item = QgsAnnotationPointTextItem("my text", QgsPointXY(12, 13)) + self.assertEqual(item.point().asWkt(), "POINT(12 13)") - res = item.transientEditResultsV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200), QgsAnnotationItemEditContext()) - self.assertEqual(res.representativeGeometry().asWkt(), 'Point (112 213)') + res = item.transientEditResultsV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200), + QgsAnnotationItemEditContext(), + ) + self.assertEqual(res.representativeGeometry().asWkt(), "Point (112 213)") def test_apply_delete_node_edit(self): - item = QgsAnnotationPointTextItem('my text', QgsPointXY(12, 13)) - self.assertEqual(item.point().asWkt(), 'POINT(12 13)') - - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationDeleteNode('', QgsVertexId(0, 0, 0), QgsPoint(12, 13)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.ItemCleared) + item = QgsAnnotationPointTextItem("my text", QgsPointXY(12, 13)) + self.assertEqual(item.point().asWkt(), "POINT(12 13)") + + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationDeleteNode( + "", QgsVertexId(0, 0, 0), QgsPoint(12, 13) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.ItemCleared, + ) def test_apply_add_node_edit(self): - item = QgsAnnotationPointTextItem('my text', QgsPointXY(12, 13)) - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationAddNode('', QgsPoint(13, 14)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Invalid) + item = QgsAnnotationPointTextItem("my text", QgsPointXY(12, 13)) + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationAddNode("", QgsPoint(13, 14)), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Invalid, + ) def testReadWriteXml(self): doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") - item = QgsAnnotationPointTextItem('my text', QgsPointXY(12, 13)) + item = QgsAnnotationPointTextItem("my text", QgsPointXY(12, 13)) item.setAngle(55) item.setAlignment(Qt.AlignmentFlag.AlignRight) item.setZIndex(11) @@ -152,14 +211,14 @@ def testReadWriteXml(self): item.setUseSymbologyReferenceScale(True) item.setSymbologyReferenceScale(5000) item.setRotationMode(Qgis.SymbolRotationMode.RespectMapRotation) - item.setCalloutAnchor(QgsGeometry.fromWkt('Point(1 3)')) + item.setCalloutAnchor(QgsGeometry.fromWkt("Point(1 3)")) item.setCallout(QgsBalloonCallout()) self.assertTrue(item.writeXml(elem, doc, QgsReadWriteContext())) s2 = QgsAnnotationPointTextItem.create() self.assertTrue(s2.readXml(elem, QgsReadWriteContext())) - self.assertEqual(s2.text(), 'my text') + self.assertEqual(s2.text(), "my text") self.assertEqual(s2.point().x(), 12.0) self.assertEqual(s2.point().y(), 13.0) self.assertEqual(s2.angle(), 55.0) @@ -169,11 +228,11 @@ def testReadWriteXml(self): self.assertTrue(s2.useSymbologyReferenceScale()) self.assertEqual(s2.symbologyReferenceScale(), 5000) self.assertEqual(s2.rotationMode(), Qgis.SymbolRotationMode.RespectMapRotation) - self.assertEqual(s2.calloutAnchor().asWkt(), 'Point (1 3)') + self.assertEqual(s2.calloutAnchor().asWkt(), "Point (1 3)") self.assertIsInstance(s2.callout(), QgsBalloonCallout) def testClone(self): - item = QgsAnnotationPointTextItem('my text', QgsPointXY(12, 13)) + item = QgsAnnotationPointTextItem("my text", QgsPointXY(12, 13)) item.setAngle(55) item.setAlignment(Qt.AlignmentFlag.AlignRight) item.setZIndex(11) @@ -183,11 +242,11 @@ def testClone(self): item.setUseSymbologyReferenceScale(True) item.setSymbologyReferenceScale(5000) item.setRotationMode(Qgis.SymbolRotationMode.RespectMapRotation) - item.setCalloutAnchor(QgsGeometry.fromWkt('Point(1 3)')) + item.setCalloutAnchor(QgsGeometry.fromWkt("Point(1 3)")) item.setCallout(QgsBalloonCallout()) item2 = item.clone() - self.assertEqual(item2.text(), 'my text') + self.assertEqual(item2.text(), "my text") self.assertEqual(item2.point().x(), 12.0) self.assertEqual(item2.point().y(), 13.0) self.assertEqual(item2.angle(), 55.0) @@ -196,14 +255,16 @@ def testClone(self): self.assertEqual(item2.format().size(), 37) self.assertTrue(item2.useSymbologyReferenceScale()) self.assertEqual(item2.symbologyReferenceScale(), 5000) - self.assertEqual(item2.rotationMode(), Qgis.SymbolRotationMode.RespectMapRotation) - self.assertEqual(item2.calloutAnchor().asWkt(), 'Point (1 3)') + self.assertEqual( + item2.rotationMode(), Qgis.SymbolRotationMode.RespectMapRotation + ) + self.assertEqual(item2.calloutAnchor().asWkt(), "Point (1 3)") self.assertIsInstance(item2.callout(), QgsBalloonCallout) def testRenderMarker(self): - item = QgsAnnotationPointTextItem('my text', QgsPointXY(12.3, 13.2)) + item = QgsAnnotationPointTextItem("my text", QgsPointXY(12.3, 13.2)) - format = QgsTextFormat.fromQFont(getTestFont('Bold')) + format = QgsTextFormat.fromQFont(getTestFont("Bold")) format.setColor(QColor(255, 0, 0)) format.setOpacity(150 / 255) format.setSize(20) @@ -213,7 +274,7 @@ def testRenderMarker(self): item.setAlignment(Qt.AlignmentFlag.AlignRight) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 16, 16)) settings.setOutputSize(QSize(300, 300)) @@ -233,12 +294,12 @@ def testRenderMarker(self): finally: painter.end() - self.assertTrue(self.image_check('pointtext_item', 'pointtext_item', image)) + self.assertTrue(self.image_check("pointtext_item", "pointtext_item", image)) def testRenderMapRotation(self): - item = QgsAnnotationPointTextItem('my text', QgsPointXY(12.3, 13.2)) + item = QgsAnnotationPointTextItem("my text", QgsPointXY(12.3, 13.2)) - format = QgsTextFormat.fromQFont(getTestFont('Bold')) + format = QgsTextFormat.fromQFont(getTestFont("Bold")) format.setColor(QColor(255, 0, 0)) format.setOpacity(150 / 255) format.setSize(20) @@ -248,7 +309,7 @@ def testRenderMapRotation(self): item.setAlignment(Qt.AlignmentFlag.AlignRight) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 16, 16)) settings.setOutputSize(QSize(300, 300)) settings.setRotation(90) @@ -269,12 +330,18 @@ def testRenderMapRotation(self): finally: painter.end() - self.assertTrue(self.image_check('pointtext_item_ignore_map_rotation', 'pointtext_item_ignore_map_rotation', image)) + self.assertTrue( + self.image_check( + "pointtext_item_ignore_map_rotation", + "pointtext_item_ignore_map_rotation", + image, + ) + ) def testRenderRespectMapRotation(self): - item = QgsAnnotationPointTextItem('my text', QgsPointXY(12.3, 13.2)) + item = QgsAnnotationPointTextItem("my text", QgsPointXY(12.3, 13.2)) - format = QgsTextFormat.fromQFont(getTestFont('Bold')) + format = QgsTextFormat.fromQFont(getTestFont("Bold")) format.setColor(QColor(255, 0, 0)) format.setOpacity(150 / 255) format.setSize(20) @@ -286,7 +353,7 @@ def testRenderRespectMapRotation(self): item.setAlignment(Qt.AlignmentFlag.AlignRight) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 16, 16)) settings.setOutputSize(QSize(300, 300)) settings.setRotation(90) @@ -307,12 +374,18 @@ def testRenderRespectMapRotation(self): finally: painter.end() - self.assertTrue(self.image_check('pointtext_item_respect_map_rotation', 'pointtext_item_respect_map_rotation', image)) + self.assertTrue( + self.image_check( + "pointtext_item_respect_map_rotation", + "pointtext_item_respect_map_rotation", + image, + ) + ) def testRenderMarkerExpression(self): - item = QgsAnnotationPointTextItem('[% 1 + 1.5 %]', QgsPointXY(12.3, 13.2)) + item = QgsAnnotationPointTextItem("[% 1 + 1.5 %]", QgsPointXY(12.3, 13.2)) - format = QgsTextFormat.fromQFont(getTestFont('Bold')) + format = QgsTextFormat.fromQFont(getTestFont("Bold")) format.setColor(QColor(255, 0, 0)) format.setOpacity(150 / 255) format.setSize(20) @@ -322,7 +395,7 @@ def testRenderMarkerExpression(self): item.setAlignment(Qt.AlignmentFlag.AlignRight) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 16, 16)) settings.setOutputSize(QSize(300, 300)) @@ -342,12 +415,16 @@ def testRenderMarkerExpression(self): finally: painter.end() - self.assertTrue(self.image_check('pointtext_item_expression', 'pointtext_item_expression', image)) + self.assertTrue( + self.image_check( + "pointtext_item_expression", "pointtext_item_expression", image + ) + ) def testRenderWithTransform(self): - item = QgsAnnotationPointTextItem('my text', QgsPointXY(12.3, 13.2)) + item = QgsAnnotationPointTextItem("my text", QgsPointXY(12.3, 13.2)) - format = QgsTextFormat.fromQFont(getTestFont('Bold')) + format = QgsTextFormat.fromQFont(getTestFont("Bold")) format.setColor(QColor(255, 0, 0)) format.setOpacity(150 / 255) format.setSize(20) @@ -357,7 +434,7 @@ def testRenderWithTransform(self): item.setAlignment(Qt.AlignmentFlag.AlignRight) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) settings.setExtent(QgsRectangle(1250958, 1386945, 1420709, 1532518)) settings.setOutputSize(QSize(300, 300)) @@ -365,7 +442,13 @@ def testRenderWithTransform(self): rc = QgsRenderContext.fromMapSettings(settings) rc.setScaleFactor(96 / 25.4) # 96 DPI - rc.setCoordinateTransform(QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'), settings.destinationCrs(), QgsProject.instance())) + rc.setCoordinateTransform( + QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + settings.destinationCrs(), + QgsProject.instance(), + ) + ) image = QImage(200, 200, QImage.Format.Format_ARGB32) image.setDotsPerMeterX(int(96 / 25.4 * 1000)) image.setDotsPerMeterY(int(96 / 25.4 * 1000)) @@ -378,23 +461,27 @@ def testRenderWithTransform(self): finally: painter.end() - self.assertTrue(self.image_check('pointtext_item_transform', 'pointtext_item_transform', image)) + self.assertTrue( + self.image_check( + "pointtext_item_transform", "pointtext_item_transform", image + ) + ) def testRenderCallout(self): - item = QgsAnnotationPointTextItem('my text', QgsPointXY(12.3, 13.2)) - item.setCalloutAnchor(QgsGeometry.fromWkt('Point(1 5)')) + item = QgsAnnotationPointTextItem("my text", QgsPointXY(12.3, 13.2)) + item.setCalloutAnchor(QgsGeometry.fromWkt("Point(1 5)")) callout = QgsSimpleLineCallout() callout.lineSymbol().setWidth(1) item.setCallout(callout) - format = QgsTextFormat.fromQFont(getTestFont('Bold')) + format = QgsTextFormat.fromQFont(getTestFont("Bold")) format.setColor(QColor(255, 0, 0)) format.setOpacity(150 / 255) format.setSize(20) item.setFormat(format) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(0, 5, 26, 11)) settings.setOutputSize(QSize(300, 300)) @@ -414,8 +501,10 @@ def testRenderCallout(self): finally: painter.end() - self.assertTrue(self.image_check('pointtext_callout', 'pointtext_callout', image)) + self.assertTrue( + self.image_check("pointtext_callout", "pointtext_callout", image) + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsannotationpolygonitem.py b/tests/src/python/test_qgsannotationpolygonitem.py index aba71ac3c450..cf66ffaf0dbe 100644 --- a/tests/src/python/test_qgsannotationpolygonitem.py +++ b/tests/src/python/test_qgsannotationpolygonitem.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 by Nyall Dawson' -__date__ = '29/07/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 by Nyall Dawson" +__date__ = "29/07/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QSize from qgis.PyQt.QtGui import QColor, QImage, QPainter @@ -55,92 +56,356 @@ def control_path_prefix(cls): return "annotation_layer" def testBasic(self): - item = QgsAnnotationPolygonItem(QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)]))) - - self.assertEqual(item.geometry().asWkt(), 'Polygon ((12 13, 14 13, 14 15, 12 13))') - - item.setGeometry(QgsPolygon(QgsLineString([QgsPoint(22, 23), QgsPoint(24, 23), QgsPoint(24, 25), QgsPoint(22, 23)]))) + item = QgsAnnotationPolygonItem( + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) + + self.assertEqual( + item.geometry().asWkt(), "Polygon ((12 13, 14 13, 14 15, 12 13))" + ) + + item.setGeometry( + QgsPolygon( + QgsLineString( + [ + QgsPoint(22, 23), + QgsPoint(24, 23), + QgsPoint(24, 25), + QgsPoint(22, 23), + ] + ) + ) + ) item.setZIndex(11) - self.assertEqual(item.geometry().asWkt(), 'Polygon ((22 23, 24 23, 24 25, 22 23))') + self.assertEqual( + item.geometry().asWkt(), "Polygon ((22 23, 24 23, 24 25, 22 23))" + ) self.assertEqual(item.zIndex(), 11) - item.setSymbol(QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black'})) + item.setSymbol( + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black"} + ) + ) self.assertEqual(item.symbol()[0].color(), QColor(200, 100, 100)) def test_nodes(self): """ Test nodes for item """ - item = QgsAnnotationPolygonItem(QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)]))) + item = QgsAnnotationPolygonItem( + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) # nodes shouldn't form a closed ring - self.assertEqual(item.nodesV2(QgsAnnotationItemEditContext()), [QgsAnnotationItemNode(QgsVertexId(0, 0, 0), QgsPointXY(12, 13), Qgis.AnnotationItemNodeType.VertexHandle), - QgsAnnotationItemNode(QgsVertexId(0, 0, 1), QgsPointXY(14, 13), Qgis.AnnotationItemNodeType.VertexHandle), - QgsAnnotationItemNode(QgsVertexId(0, 0, 2), QgsPointXY(14, 15), Qgis.AnnotationItemNodeType.VertexHandle)]) + self.assertEqual( + item.nodesV2(QgsAnnotationItemEditContext()), + [ + QgsAnnotationItemNode( + QgsVertexId(0, 0, 0), + QgsPointXY(12, 13), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + QgsAnnotationItemNode( + QgsVertexId(0, 0, 1), + QgsPointXY(14, 13), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + QgsAnnotationItemNode( + QgsVertexId(0, 0, 2), + QgsPointXY(14, 15), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + ], + ) def test_transform(self): - item = QgsAnnotationPolygonItem(QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)]))) - self.assertEqual(item.geometry().asWkt(), 'Polygon ((12 13, 14 13, 14 15, 12 13))') - - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.geometry().asWkt(), 'Polygon ((112 213, 114 213, 114 215, 112 213))') + item = QgsAnnotationPolygonItem( + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) + self.assertEqual( + item.geometry().asWkt(), "Polygon ((12 13, 14 13, 14 15, 12 13))" + ) + + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual( + item.geometry().asWkt(), "Polygon ((112 213, 114 213, 114 215, 112 213))" + ) def test_apply_move_node_edit(self): item = QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)]))) - self.assertEqual(item.geometry().asWkt(), 'Polygon ((12 13, 14 13, 14 15, 12 13))') - - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(14, 13), QgsPoint(17, 18)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.geometry().asWkt(), 'Polygon ((12 13, 17 18, 14 15, 12 13))') - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 3), QgsPoint(12, 13), QgsPoint(19, 20)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.geometry().asWkt(), 'Polygon ((19 20, 17 18, 14 15, 19 20))') - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 4), QgsPoint(14, 15), QgsPoint(19, 20)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Invalid) - self.assertEqual(item.geometry().asWkt(), 'Polygon ((19 20, 17 18, 14 15, 19 20))') + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) + self.assertEqual( + item.geometry().asWkt(), "Polygon ((12 13, 14 13, 14 15, 12 13))" + ) + + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 1), QgsPoint(14, 13), QgsPoint(17, 18) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual( + item.geometry().asWkt(), "Polygon ((12 13, 17 18, 14 15, 12 13))" + ) + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 3), QgsPoint(12, 13), QgsPoint(19, 20) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual( + item.geometry().asWkt(), "Polygon ((19 20, 17 18, 14 15, 19 20))" + ) + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 4), QgsPoint(14, 15), QgsPoint(19, 20) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Invalid, + ) + self.assertEqual( + item.geometry().asWkt(), "Polygon ((19 20, 17 18, 14 15, 19 20))" + ) def test_apply_delete_node_edit(self): item = QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(14.5, 15.5), QgsPoint(14.5, 16.5), QgsPoint(14.5, 17.5), QgsPoint(12, 13)]))) - self.assertEqual(item.geometry().asWkt(), 'Polygon ((12 13, 14 13, 14 15, 14.5 15.5, 14.5 16.5, 14.5 17.5, 12 13))') - - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationDeleteNode('', QgsVertexId(0, 0, 1), QgsPoint(14, 13)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.geometry().asWkt(), 'Polygon ((12 13, 14 15, 14.5 15.5, 14.5 16.5, 14.5 17.5, 12 13))') - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationDeleteNode('', QgsVertexId(0, 0, 2), QgsPoint(14.5, 15.5)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.geometry().asWkt(), 'Polygon ((12 13, 14 15, 14.5 16.5, 14.5 17.5, 12 13))') - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationDeleteNode('', QgsVertexId(0, 0, 7), QgsPoint(14, 15)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Invalid) - self.assertEqual(item.geometry().asWkt(), 'Polygon ((12 13, 14 15, 14.5 16.5, 14.5 17.5, 12 13))') - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationDeleteNode('', QgsVertexId(0, 0, 0), QgsPoint(12, 13)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationDeleteNode('', QgsVertexId(0, 0, 0), QgsPoint(12, 13)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.ItemCleared) - self.assertEqual(item.geometry().asWkt(), 'Polygon EMPTY') + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(14.5, 15.5), + QgsPoint(14.5, 16.5), + QgsPoint(14.5, 17.5), + QgsPoint(12, 13), + ] + ) + ) + ) + self.assertEqual( + item.geometry().asWkt(), + "Polygon ((12 13, 14 13, 14 15, 14.5 15.5, 14.5 16.5, 14.5 17.5, 12 13))", + ) + + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationDeleteNode( + "", QgsVertexId(0, 0, 1), QgsPoint(14, 13) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual( + item.geometry().asWkt(), + "Polygon ((12 13, 14 15, 14.5 15.5, 14.5 16.5, 14.5 17.5, 12 13))", + ) + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationDeleteNode( + "", QgsVertexId(0, 0, 2), QgsPoint(14.5, 15.5) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual( + item.geometry().asWkt(), + "Polygon ((12 13, 14 15, 14.5 16.5, 14.5 17.5, 12 13))", + ) + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationDeleteNode( + "", QgsVertexId(0, 0, 7), QgsPoint(14, 15) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Invalid, + ) + self.assertEqual( + item.geometry().asWkt(), + "Polygon ((12 13, 14 15, 14.5 16.5, 14.5 17.5, 12 13))", + ) + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationDeleteNode( + "", QgsVertexId(0, 0, 0), QgsPoint(12, 13) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationDeleteNode( + "", QgsVertexId(0, 0, 0), QgsPoint(12, 13) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.ItemCleared, + ) + self.assertEqual(item.geometry().asWkt(), "Polygon EMPTY") def test_apply_add_node_edit(self): item = QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(14.5, 15.5), QgsPoint(14.5, 16.5), QgsPoint(14.5, 17.5), QgsPoint(12, 13)]))) - self.assertEqual(item.geometry().asWkt(), 'Polygon ((12 13, 14 13, 14 15, 14.5 15.5, 14.5 16.5, 14.5 17.5, 12 13))') - - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationAddNode('', QgsPoint(15, 16)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.geometry().asWkt(), 'Polygon ((12 13, 14 13, 14 15, 14.5 15.5, 14.5 16, 14.5 16.5, 14.5 17.5, 12 13))') + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(14.5, 15.5), + QgsPoint(14.5, 16.5), + QgsPoint(14.5, 17.5), + QgsPoint(12, 13), + ] + ) + ) + ) + self.assertEqual( + item.geometry().asWkt(), + "Polygon ((12 13, 14 13, 14 15, 14.5 15.5, 14.5 16.5, 14.5 17.5, 12 13))", + ) + + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationAddNode("", QgsPoint(15, 16)), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual( + item.geometry().asWkt(), + "Polygon ((12 13, 14 13, 14 15, 14.5 15.5, 14.5 16, 14.5 16.5, 14.5 17.5, 12 13))", + ) def test_transient_move_operation(self): item = QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)]))) - self.assertEqual(item.geometry().asWkt(), 'Polygon ((12 13, 14 13, 14 15, 12 13))') - - res = item.transientEditResultsV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(14, 13), QgsPoint(17, 18)), QgsAnnotationItemEditContext()) - self.assertEqual(res.representativeGeometry().asWkt(), 'Polygon ((12 13, 17 18, 14 15, 12 13))') + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) + self.assertEqual( + item.geometry().asWkt(), "Polygon ((12 13, 14 13, 14 15, 12 13))" + ) + + res = item.transientEditResultsV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 1), QgsPoint(14, 13), QgsPoint(17, 18) + ), + QgsAnnotationItemEditContext(), + ) + self.assertEqual( + res.representativeGeometry().asWkt(), + "Polygon ((12 13, 17 18, 14 15, 12 13))", + ) def test_transient_translate_operation(self): item = QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)]))) - self.assertEqual(item.geometry().asWkt(), 'Polygon ((12 13, 14 13, 14 15, 12 13))') - - res = item.transientEditResultsV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200), QgsAnnotationItemEditContext()) - self.assertEqual(res.representativeGeometry().asWkt(), 'Polygon ((112 213, 114 213, 114 215, 112 213))') + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) + self.assertEqual( + item.geometry().asWkt(), "Polygon ((12 13, 14 13, 14 15, 12 13))" + ) + + res = item.transientEditResultsV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200), + QgsAnnotationItemEditContext(), + ) + self.assertEqual( + res.representativeGeometry().asWkt(), + "Polygon ((112 213, 114 213, 114 215, 112 213))", + ) def testReadWriteXml(self): doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") - item = QgsAnnotationPolygonItem(QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)]))) - item.setSymbol(QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black'})) + item = QgsAnnotationPolygonItem( + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) + item.setSymbol( + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black"} + ) + ) item.setZIndex(11) item.setUseSymbologyReferenceScale(True) item.setSymbologyReferenceScale(5000) @@ -150,32 +415,66 @@ def testReadWriteXml(self): s2 = QgsAnnotationPolygonItem.create() self.assertTrue(s2.readXml(elem, QgsReadWriteContext())) - self.assertEqual(s2.geometry().asWkt(), 'Polygon ((12 13, 14 13, 14 15, 12 13))') + self.assertEqual( + s2.geometry().asWkt(), "Polygon ((12 13, 14 13, 14 15, 12 13))" + ) self.assertEqual(s2.symbol()[0].color(), QColor(200, 100, 100)) self.assertEqual(s2.zIndex(), 11) self.assertTrue(s2.useSymbologyReferenceScale()) self.assertEqual(s2.symbologyReferenceScale(), 5000) def testClone(self): - item = QgsAnnotationPolygonItem(QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)]))) - item.setSymbol(QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black'})) + item = QgsAnnotationPolygonItem( + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) + item.setSymbol( + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black"} + ) + ) item.setZIndex(11) item.setUseSymbologyReferenceScale(True) item.setSymbologyReferenceScale(5000) item2 = item.clone() - self.assertEqual(item2.geometry().asWkt(), 'Polygon ((12 13, 14 13, 14 15, 12 13))') + self.assertEqual( + item2.geometry().asWkt(), "Polygon ((12 13, 14 13, 14 15, 12 13))" + ) self.assertEqual(item2.symbol()[0].color(), QColor(200, 100, 100)) self.assertEqual(item2.zIndex(), 11) self.assertTrue(item2.useSymbologyReferenceScale()) self.assertEqual(item2.symbologyReferenceScale(), 5000) def testRenderPolygon(self): - item = QgsAnnotationPolygonItem(QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)]))) - item.setSymbol(QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2'})) + item = QgsAnnotationPolygonItem( + QgsPolygon( + QgsLineString( + [ + QgsPoint(12, 13), + QgsPoint(14, 13), + QgsPoint(14, 15), + QgsPoint(12, 13), + ] + ) + ) + ) + item.setSymbol( + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black", "outline_width": "2"} + ) + ) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(300, 300)) @@ -194,18 +493,30 @@ def testRenderPolygon(self): finally: painter.end() - self.assertTrue(self.image_check('polygon_item', 'polygon_item', image)) + self.assertTrue(self.image_check("polygon_item", "polygon_item", image)) def testRenderCurvePolygon(self): cs = QgsCircularString() - cs.setPoints([QgsPoint(12, 13.2), QgsPoint(14, 13.4), QgsPoint(14, 15), QgsPoint(13, 15.1), QgsPoint(12, 13.2)]) + cs.setPoints( + [ + QgsPoint(12, 13.2), + QgsPoint(14, 13.4), + QgsPoint(14, 15), + QgsPoint(13, 15.1), + QgsPoint(12, 13.2), + ] + ) cp = QgsCurvePolygon() cp.setExteriorRing(cs) item = QgsAnnotationPolygonItem(cp) - item.setSymbol(QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2'})) + item.setSymbol( + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black", "outline_width": "2"} + ) + ) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(300, 300)) @@ -224,21 +535,44 @@ def testRenderCurvePolygon(self): finally: painter.end() - self.assertTrue(self.image_check('curvepolygon_item', 'curvepolygon_item', image)) + self.assertTrue( + self.image_check("curvepolygon_item", "curvepolygon_item", image) + ) def testRenderWithTransform(self): - item = QgsAnnotationPolygonItem(QgsPolygon(QgsLineString([QgsPoint(11.5, 13), QgsPoint(12, 13), QgsPoint(12, 13.5), QgsPoint(11.5, 13)]))) - item.setSymbol(QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2'})) + item = QgsAnnotationPolygonItem( + QgsPolygon( + QgsLineString( + [ + QgsPoint(11.5, 13), + QgsPoint(12, 13), + QgsPoint(12, 13.5), + QgsPoint(11.5, 13), + ] + ) + ) + ) + item.setSymbol( + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black", "outline_width": "2"} + ) + ) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) settings.setExtent(QgsRectangle(1250958, 1386945, 1420709, 1532518)) settings.setOutputSize(QSize(300, 300)) settings.setFlag(QgsMapSettings.Flag.Antialiasing, False) rc = QgsRenderContext.fromMapSettings(settings) - rc.setCoordinateTransform(QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'), settings.destinationCrs(), QgsProject.instance())) + rc.setCoordinateTransform( + QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + settings.destinationCrs(), + QgsProject.instance(), + ) + ) image = QImage(200, 200, QImage.Format.Format_ARGB32) image.setDotsPerMeterX(int(96 / 25.4 * 1000)) image.setDotsPerMeterY(int(96 / 25.4 * 1000)) @@ -251,8 +585,10 @@ def testRenderWithTransform(self): finally: painter.end() - self.assertTrue(self.image_check('polygon_item_transform', 'polygon_item_transform', image)) + self.assertTrue( + self.image_check("polygon_item_transform", "polygon_item_transform", image) + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsannotationrecttextitem.py b/tests/src/python/test_qgsannotationrecttextitem.py index 014b14b16bc4..2b6403391c89 100644 --- a/tests/src/python/test_qgsannotationrecttextitem.py +++ b/tests/src/python/test_qgsannotationrecttextitem.py @@ -40,7 +40,7 @@ QgsCallout, QgsBalloonCallout, QgsGeometry, - QgsSimpleLineCallout + QgsSimpleLineCallout, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -58,14 +58,16 @@ def control_path_prefix(cls): return "annotation_layer" def testBasic(self): - item = QgsAnnotationRectangleTextItem('my text', QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(10, 20, 30, 40)) - self.assertEqual(item.text(), 'my text') - self.assertEqual(item.boundingBox().toString(3), '10.000,20.000 : 30.000,40.000') + self.assertEqual(item.text(), "my text") + self.assertEqual( + item.boundingBox().toString(3), "10.000,20.000 : 30.000,40.000" + ) item.setBounds(QgsRectangle(100, 200, 300, 400)) item.setZIndex(11) - item.setText('different text') + item.setText("different text") item.setBackgroundEnabled(True) item.setFrameEnabled(True) item.setAlignment(Qt.AlignmentFlag.AlignRight) @@ -75,14 +77,13 @@ def testBasic(self): item.setMargins(QgsMargins(1, 2, 3, 4)) item.setMarginsUnit(Qgis.RenderUnit.Points) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - item.setFixedSize(QSizeF(56, - 57)) + item.setFixedSize(QSizeF(56, 57)) item.setFixedSizeUnit(Qgis.RenderUnit.Inches) item.setOffsetFromCallout(QSizeF(13.6, 17.2)) item.setOffsetFromCalloutUnit(Qgis.RenderUnit.Inches) - self.assertEqual(item.bounds().toString(3), '100.000,200.000 : 300.000,400.000') - self.assertEqual(item.text(), 'different text') + self.assertEqual(item.bounds().toString(3), "100.000,200.000 : 300.000,400.000") + self.assertEqual(item.text(), "different text") self.assertEqual(item.zIndex(), 11) self.assertTrue(item.backgroundEnabled()) self.assertTrue(item.frameEnabled()) @@ -90,118 +91,167 @@ def testBasic(self): self.assertEqual(item.format().size(), 37) self.assertEqual(item.margins(), QgsMargins(1, 2, 3, 4)) self.assertEqual(item.marginsUnit(), Qgis.RenderUnit.Points) - self.assertEqual(item.placementMode(), - Qgis.AnnotationPlacementMode.FixedSize) - self.assertEqual(item.fixedSize(), QSizeF(56, - 57)) + self.assertEqual(item.placementMode(), Qgis.AnnotationPlacementMode.FixedSize) + self.assertEqual(item.fixedSize(), QSizeF(56, 57)) self.assertEqual(item.fixedSizeUnit(), Qgis.RenderUnit.Inches) self.assertEqual(item.offsetFromCallout(), QSizeF(13.6, 17.2)) self.assertEqual(item.offsetFromCalloutUnit(), Qgis.RenderUnit.Inches) - item.setBackgroundSymbol(QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black'})) - item.setFrameSymbol(QgsFillSymbol.createSimple( - {'color': '100,200,250', 'outline_color': 'black'})) + item.setBackgroundSymbol( + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black"} + ) + ) + item.setFrameSymbol( + QgsFillSymbol.createSimple( + {"color": "100,200,250", "outline_color": "black"} + ) + ) self.assertEqual(item.backgroundSymbol()[0].color(), QColor(200, 100, 100)) - self.assertEqual(item.frameSymbol()[0].color(), - QColor(100, 200, 250)) + self.assertEqual(item.frameSymbol()[0].color(), QColor(100, 200, 250)) def test_nodes_spatial_bounds(self): """ Test nodes for item, spatial bounds mode """ - item = QgsAnnotationRectangleTextItem('my text', QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(10, 20, 30, 40)) # nodes shouldn't form a closed ring - self.assertEqual(item.nodesV2(QgsAnnotationItemEditContext()), - [QgsAnnotationItemNode(QgsVertexId(0, 0, 0), QgsPointXY(10, 20), - Qgis.AnnotationItemNodeType.VertexHandle), - QgsAnnotationItemNode(QgsVertexId(0, 0, 1), QgsPointXY(30, 20), - Qgis.AnnotationItemNodeType.VertexHandle), - QgsAnnotationItemNode(QgsVertexId(0, 0, 2), QgsPointXY(30, 40), - Qgis.AnnotationItemNodeType.VertexHandle), - QgsAnnotationItemNode(QgsVertexId(0, 0, 3), QgsPointXY(10, 40), - Qgis.AnnotationItemNodeType.VertexHandle), - QgsAnnotationItemNode(QgsVertexId(1, 0, 0), - QgsPointXY(20, 30), - Qgis.AnnotationItemNodeType.CalloutHandle) - ]) + self.assertEqual( + item.nodesV2(QgsAnnotationItemEditContext()), + [ + QgsAnnotationItemNode( + QgsVertexId(0, 0, 0), + QgsPointXY(10, 20), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + QgsAnnotationItemNode( + QgsVertexId(0, 0, 1), + QgsPointXY(30, 20), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + QgsAnnotationItemNode( + QgsVertexId(0, 0, 2), + QgsPointXY(30, 40), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + QgsAnnotationItemNode( + QgsVertexId(0, 0, 3), + QgsPointXY(10, 40), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + QgsAnnotationItemNode( + QgsVertexId(1, 0, 0), + QgsPointXY(20, 30), + Qgis.AnnotationItemNodeType.CalloutHandle, + ), + ], + ) def test_nodes_fixed_size(self): """ Test nodes for item, fixed size mode """ - item = QgsAnnotationRectangleTextItem('my text', - QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(10, 20, 30, 40)) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) context = QgsAnnotationItemEditContext() context.setCurrentItemBounds(QgsRectangle(10, 20, 30, 40)) - self.assertEqual(item.nodesV2(context), [ - QgsAnnotationItemNode(QgsVertexId(0, 0, 0), QgsPointXY(20, 30), Qgis.AnnotationItemNodeType.VertexHandle), - QgsAnnotationItemNode(QgsVertexId(1, 0, 0), QgsPointXY(10, 20), Qgis.AnnotationItemNodeType.CalloutHandle)]) + self.assertEqual( + item.nodesV2(context), + [ + QgsAnnotationItemNode( + QgsVertexId(0, 0, 0), + QgsPointXY(20, 30), + Qgis.AnnotationItemNodeType.VertexHandle, + ), + QgsAnnotationItemNode( + QgsVertexId(1, 0, 0), + QgsPointXY(10, 20), + Qgis.AnnotationItemNodeType.CalloutHandle, + ), + ], + ) def test_nodes_relative_to_map(self): """ Test nodes for item, relative to map mode """ - item = QgsAnnotationRectangleTextItem('my text', - QgsRectangle(0.25, 0.75, 30, 40)) + item = QgsAnnotationRectangleTextItem( + "my text", QgsRectangle(0.25, 0.75, 30, 40) + ) item.setPlacementMode(Qgis.AnnotationPlacementMode.RelativeToMapFrame) context = QgsAnnotationItemEditContext() context.setCurrentItemBounds(QgsRectangle(10, 20, 30, 40)) - self.assertEqual(item.nodesV2(context), [ - QgsAnnotationItemNode(QgsVertexId(0, 0, 0), QgsPointXY(20, 30), Qgis.AnnotationItemNodeType.VertexHandle)]) + self.assertEqual( + item.nodesV2(context), + [ + QgsAnnotationItemNode( + QgsVertexId(0, 0, 0), + QgsPointXY(20, 30), + Qgis.AnnotationItemNodeType.VertexHandle, + ) + ], + ) def test_translate_spatial_bounds(self): - item = QgsAnnotationRectangleTextItem('my text', QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(10, 20, 30, 40)) - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") self.assertEqual( - item.applyEditV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200), QgsAnnotationItemEditContext()), - Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '110.000,220.000 : 130.000,240.000') + item.applyEditV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "110.000,220.000 : 130.000,240.000") def test_translate_fixed_size(self): - item = QgsAnnotationRectangleTextItem('my text', - QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(10, 20, 30, 40)) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") context = QgsAnnotationItemEditContext() render_context = QgsRenderContext() render_context.setScaleFactor(5) context.setRenderContext(render_context) - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200), - context), - Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '110.000,220.000 : 130.000,240.000') + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200), context + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "110.000,220.000 : 130.000,240.000") self.assertEqual(item.offsetFromCallout(), QSizeF()) def test_translate_fixed_size_with_callout_anchor(self): - item = QgsAnnotationRectangleTextItem('my text', - QgsRectangle(10, 20, 30, 40)) - item.setCalloutAnchor(QgsGeometry.fromWkt('Point(1 3)')) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(10, 20, 30, 40)) + item.setCalloutAnchor(QgsGeometry.fromWkt("Point(1 3)")) item.setCallout(QgsBalloonCallout()) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") context = QgsAnnotationItemEditContext() render_context = QgsRenderContext() render_context.setScaleFactor(5) context.setRenderContext(render_context) - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200, 50, 30), - context), - Qgis.AnnotationItemEditOperationResult.Success) + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200, 50, 30), + context, + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) # should affect callout offset only self.assertEqual(item.offsetFromCallout(), QSizeF(9, 5)) self.assertEqual(item.offsetFromCalloutUnit(), Qgis.RenderUnit.Millimeters) def test_translate_relative_to_map(self): - item = QgsAnnotationRectangleTextItem('my text', - QgsRectangle(0.2, 0.8, 30, 40)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(0.2, 0.8, 30, 40)) item.setPlacementMode(Qgis.AnnotationPlacementMode.RelativeToMapFrame) - self.assertEqual(item.bounds().toString(3), '0.200,0.800 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "0.200,0.800 : 30.000,40.000") context = QgsAnnotationItemEditContext() render_context = QgsRenderContext() @@ -209,71 +259,117 @@ def test_translate_relative_to_map(self): render_context.setOutputSize(QSize(1000, 600)) context.setRenderContext(render_context) - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200, 100, 200), - context), - Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '0.300,1.133 : 30.100,40.333') + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200, 100, 200), + context, + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "0.300,1.133 : 30.100,40.333") self.assertEqual(item.offsetFromCallout(), QSizeF()) def test_apply_move_node_edit_spatial_bounds(self): - item = QgsAnnotationRectangleTextItem('my text', QgsRectangle(10, 20, 30, 40)) - - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') - - self.assertEqual(item.applyEditV2( - QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(30, 20), QgsPoint(17, 18)), - QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '10.000,18.000 : 17.000,40.000') - self.assertEqual(item.applyEditV2( - QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 0), QgsPoint(10, 18), QgsPoint(5, 13)), - QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '5.000,13.000 : 17.000,40.000') - self.assertEqual(item.applyEditV2( - QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 2), QgsPoint(17, 14), QgsPoint(18, 38)), - QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '5.000,13.000 : 18.000,38.000') - self.assertEqual(item.applyEditV2( - QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 3), QgsPoint(5, 38), QgsPoint(2, 39)), - QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '2.000,13.000 : 18.000,39.000') + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(10, 20, 30, 40)) + + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") + + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 1), QgsPoint(30, 20), QgsPoint(17, 18) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "10.000,18.000 : 17.000,40.000") + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 0), QgsPoint(10, 18), QgsPoint(5, 13) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "5.000,13.000 : 17.000,40.000") + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 2), QgsPoint(17, 14), QgsPoint(18, 38) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "5.000,13.000 : 18.000,38.000") + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 3), QgsPoint(5, 38), QgsPoint(2, 39) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "2.000,13.000 : 18.000,39.000") # move callout handle - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(1, 0, 0), QgsPoint(14, 13), QgsPoint(1, 3)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), - '2.000,13.000 : 18.000,39.000') - self.assertEqual(item.calloutAnchor().asWkt(), 'Point (1 3)') + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(1, 0, 0), QgsPoint(14, 13), QgsPoint(1, 3) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "2.000,13.000 : 18.000,39.000") + self.assertEqual(item.calloutAnchor().asWkt(), "Point (1 3)") # callout should have been automatically created self.assertIsInstance(item.callout(), QgsCallout) def test_apply_move_node_edit_fixed_size(self): - item = QgsAnnotationRectangleTextItem('my text', - QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(10, 20, 30, 40)) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") context = QgsAnnotationItemEditContext() render_context = QgsRenderContext() render_context.setScaleFactor(5) context.setRenderContext(render_context) - self.assertEqual(item.applyEditV2( - QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 0), QgsPoint(30, 20), QgsPoint(17, 18)), - context), - Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '7.000,8.000 : 27.000,28.000') + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 0), QgsPoint(30, 20), QgsPoint(17, 18) + ), + context, + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "7.000,8.000 : 27.000,28.000") # move callout handle - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(1, 0, 0), QgsPoint(14, 13), QgsPoint(1, 3)), QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '7.000,8.000 : 27.000,28.000') - self.assertEqual(item.calloutAnchor().asWkt(), 'Point (1 3)') + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(1, 0, 0), QgsPoint(14, 13), QgsPoint(1, 3) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "7.000,8.000 : 27.000,28.000") + self.assertEqual(item.calloutAnchor().asWkt(), "Point (1 3)") # callout should have been automatically created self.assertIsInstance(item.callout(), QgsCallout) def test_apply_move_node_edit_relative_to_map(self): - item = QgsAnnotationRectangleTextItem('my text', - QgsRectangle(0.2, 0.8, 30, 40)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(0.2, 0.8, 30, 40)) item.setPlacementMode(Qgis.AnnotationPlacementMode.RelativeToMapFrame) - self.assertEqual(item.bounds().toString(3), '0.200,0.800 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "0.200,0.800 : 30.000,40.000") context = QgsAnnotationItemEditContext() render_context = QgsRenderContext() @@ -281,72 +377,108 @@ def test_apply_move_node_edit_relative_to_map(self): render_context.setOutputSize(QSize(2000, 600)) context.setRenderContext(render_context) - self.assertEqual(item.applyEditV2( - QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 0), QgsPoint(30, 20), QgsPoint(17, 18), 100, 200), - context), - Qgis.AnnotationItemEditOperationResult.Success) - self.assertEqual(item.bounds().toString(3), '0.250,1.133 : 30.050,40.333') + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationMoveNode( + "", + QgsVertexId(0, 0, 0), + QgsPoint(30, 20), + QgsPoint(17, 18), + 100, + 200, + ), + context, + ), + Qgis.AnnotationItemEditOperationResult.Success, + ) + self.assertEqual(item.bounds().toString(3), "0.250,1.133 : 30.050,40.333") def test_apply_delete_node_edit(self): - item = QgsAnnotationRectangleTextItem('my text', QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(10, 20, 30, 40)) self.assertEqual( - item.applyEditV2(QgsAnnotationItemEditOperationDeleteNode('', QgsVertexId(0, 0, 1), QgsPoint(14, 13)), - QgsAnnotationItemEditContext()), Qgis.AnnotationItemEditOperationResult.Invalid) + item.applyEditV2( + QgsAnnotationItemEditOperationDeleteNode( + "", QgsVertexId(0, 0, 1), QgsPoint(14, 13) + ), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Invalid, + ) def test_apply_add_node_edit(self): - item = QgsAnnotationRectangleTextItem('my text', QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(10, 20, 30, 40)) - self.assertEqual(item.applyEditV2(QgsAnnotationItemEditOperationAddNode('', QgsPoint(15, 16)), - QgsAnnotationItemEditContext()), - Qgis.AnnotationItemEditOperationResult.Invalid) + self.assertEqual( + item.applyEditV2( + QgsAnnotationItemEditOperationAddNode("", QgsPoint(15, 16)), + QgsAnnotationItemEditContext(), + ), + Qgis.AnnotationItemEditOperationResult.Invalid, + ) def test_transient_move_operation_spatial_bounds(self): - item = QgsAnnotationRectangleTextItem('my text', QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(10, 20, 30, 40)) - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") res = item.transientEditResultsV2( - QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(30, 20), QgsPoint(17, 18)), - QgsAnnotationItemEditContext() + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 1), QgsPoint(30, 20), QgsPoint(17, 18) + ), + QgsAnnotationItemEditContext(), + ) + self.assertEqual( + res.representativeGeometry().asWkt(), + "Polygon ((10 18, 17 18, 17 40, 10 40, 10 18))", ) - self.assertEqual(res.representativeGeometry().asWkt(), 'Polygon ((10 18, 17 18, 17 40, 10 40, 10 18))') # move callout handle - res = item.transientEditResultsV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(1, 0, 0), QgsPoint(14, 13), QgsPoint(1, 3)), QgsAnnotationItemEditContext()) - self.assertEqual(res.representativeGeometry().asWkt(), - 'Point (1 3)') + res = item.transientEditResultsV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(1, 0, 0), QgsPoint(14, 13), QgsPoint(1, 3) + ), + QgsAnnotationItemEditContext(), + ) + self.assertEqual(res.representativeGeometry().asWkt(), "Point (1 3)") def test_transient_move_operation_fixed_size(self): - item = QgsAnnotationRectangleTextItem('my text', - QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(10, 20, 30, 40)) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - item.setFixedSize(QSizeF(56, - 57)) + item.setFixedSize(QSizeF(56, 57)) item.setFixedSizeUnit(Qgis.RenderUnit.Inches) - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") - op = QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(30, 20), QgsPoint(17, 18)) + op = QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 1), QgsPoint(30, 20), QgsPoint(17, 18) + ) context = QgsAnnotationItemEditContext() context.setCurrentItemBounds(QgsRectangle(1, 2, 3, 4)) res = item.transientEditResultsV2(op, context) - self.assertEqual(res.representativeGeometry().asWkt(), 'Polygon ((16 17, 18 17, 18 19, 16 19, 16 17))') + self.assertEqual( + res.representativeGeometry().asWkt(), + "Polygon ((16 17, 18 17, 18 19, 16 19, 16 17))", + ) # move callout handle - res = item.transientEditResultsV2(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(1, 0, 0), QgsPoint(14, 13), QgsPoint(1, 3)), QgsAnnotationItemEditContext()) - self.assertEqual(res.representativeGeometry().asWkt(), - 'Point (1 3)') + res = item.transientEditResultsV2( + QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(1, 0, 0), QgsPoint(14, 13), QgsPoint(1, 3) + ), + QgsAnnotationItemEditContext(), + ) + self.assertEqual(res.representativeGeometry().asWkt(), "Point (1 3)") def test_transient_move_operation_relative_map(self): - item = QgsAnnotationRectangleTextItem('my text', - QgsRectangle(0.2, 0.8, 30, 40)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(0.2, 0.8, 30, 40)) item.setPlacementMode(Qgis.AnnotationPlacementMode.RelativeToMapFrame) - item.setFixedSize(QSizeF(56, - 57)) + item.setFixedSize(QSizeF(56, 57)) item.setFixedSizeUnit(Qgis.RenderUnit.Inches) - self.assertEqual(item.bounds().toString(3), '0.200,0.800 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "0.200,0.800 : 30.000,40.000") - op = QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(30, 20), QgsPoint(17, 18), 100, 200) + op = QgsAnnotationItemEditOperationMoveNode( + "", QgsVertexId(0, 0, 1), QgsPoint(30, 20), QgsPoint(17, 18), 100, 200 + ) render_context = QgsRenderContext() render_context.setScaleFactor(5) render_context.setOutputSize(QSize(2000, 600)) @@ -355,29 +487,33 @@ def test_transient_move_operation_relative_map(self): context.setRenderContext(render_context) context.setCurrentItemBounds(QgsRectangle(1, 2, 3, 4)) res = item.transientEditResultsV2(op, context) - self.assertEqual(res.representativeGeometry().asWkt(), 'Polygon ((-12 0, -10 0, -10 2, -12 2, -12 0))') + self.assertEqual( + res.representativeGeometry().asWkt(), + "Polygon ((-12 0, -10 0, -10 2, -12 2, -12 0))", + ) def test_transient_translate_operation_spatial_bounds(self): - item = QgsAnnotationRectangleTextItem('my text', QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(10, 20, 30, 40)) - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") - res = item.transientEditResultsV2(QgsAnnotationItemEditOperationTranslateItem('', 100, 200), - QgsAnnotationItemEditContext() - ) - self.assertEqual(res.representativeGeometry().asWkt(), - 'Polygon ((110 220, 130 220, 130 240, 110 240, 110 220))') + res = item.transientEditResultsV2( + QgsAnnotationItemEditOperationTranslateItem("", 100, 200), + QgsAnnotationItemEditContext(), + ) + self.assertEqual( + res.representativeGeometry().asWkt(), + "Polygon ((110 220, 130 220, 130 240, 110 240, 110 220))", + ) def test_transient_translate_operation_fixed_size(self): - item = QgsAnnotationRectangleTextItem('my text', - QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(10, 20, 30, 40)) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - item.setFixedSize(QSizeF(56, - 57)) + item.setFixedSize(QSizeF(56, 57)) item.setFixedSizeUnit(Qgis.RenderUnit.Inches) - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") - op = QgsAnnotationItemEditOperationTranslateItem('', 100, 200) + op = QgsAnnotationItemEditOperationTranslateItem("", 100, 200) context = QgsAnnotationItemEditContext() context.setCurrentItemBounds(QgsRectangle(1, 2, 3, 4)) render_context = QgsRenderContext() @@ -385,21 +521,21 @@ def test_transient_translate_operation_fixed_size(self): context.setRenderContext(render_context) res = item.transientEditResultsV2(op, context) - self.assertEqual(res.representativeGeometry().asWkt(), - 'Polygon ((119 229, 121 229, 121 231, 119 231, 119 229))') + self.assertEqual( + res.representativeGeometry().asWkt(), + "Polygon ((119 229, 121 229, 121 231, 119 231, 119 229))", + ) def test_transient_translate_operation_fixed_size_with_callout_anchor(self): - item = QgsAnnotationRectangleTextItem('my text', - QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(10, 20, 30, 40)) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - item.setFixedSize(QSizeF(56, - 57)) + item.setFixedSize(QSizeF(56, 57)) item.setFixedSizeUnit(Qgis.RenderUnit.Inches) - item.setCalloutAnchor(QgsGeometry.fromWkt('Point(1 3)')) + item.setCalloutAnchor(QgsGeometry.fromWkt("Point(1 3)")) item.setCallout(QgsBalloonCallout()) - self.assertEqual(item.bounds().toString(3), '10.000,20.000 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "10.000,20.000 : 30.000,40.000") - op = QgsAnnotationItemEditOperationTranslateItem('', 100, 200, 50, 30) + op = QgsAnnotationItemEditOperationTranslateItem("", 100, 200, 50, 30) context = QgsAnnotationItemEditContext() context.setCurrentItemBounds(QgsRectangle(1, 2, 3, 4)) render_context = QgsRenderContext() @@ -407,19 +543,19 @@ def test_transient_translate_operation_fixed_size_with_callout_anchor(self): context.setRenderContext(render_context) res = item.transientEditResultsV2(op, context) - self.assertEqual(res.representativeGeometry().asWkt(2), - 'Polygon ((50.5 -26.5, 761.7 -26.5, 761.7 -750.4, 50.5 -750.4, 50.5 -26.5))') + self.assertEqual( + res.representativeGeometry().asWkt(2), + "Polygon ((50.5 -26.5, 761.7 -26.5, 761.7 -750.4, 50.5 -750.4, 50.5 -26.5))", + ) def test_transient_translate_operation_relative_map(self): - item = QgsAnnotationRectangleTextItem('my text', - QgsRectangle(0.2, 0.8, 30, 40)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(0.2, 0.8, 30, 40)) item.setPlacementMode(Qgis.AnnotationPlacementMode.RelativeToMapFrame) - item.setFixedSize(QSizeF(56, - 57)) + item.setFixedSize(QSizeF(56, 57)) item.setFixedSizeUnit(Qgis.RenderUnit.Inches) - self.assertEqual(item.bounds().toString(3), '0.200,0.800 : 30.000,40.000') + self.assertEqual(item.bounds().toString(3), "0.200,0.800 : 30.000,40.000") - op = QgsAnnotationItemEditOperationTranslateItem('', 100, 200, 100, 200) + op = QgsAnnotationItemEditOperationTranslateItem("", 100, 200, 100, 200) context = QgsAnnotationItemEditContext() context.setCurrentItemBounds(QgsRectangle(1, 2, 3, 4)) render_context = QgsRenderContext() @@ -427,19 +563,29 @@ def test_transient_translate_operation_relative_map(self): context.setRenderContext(render_context) res = item.transientEditResultsV2(op, context) - self.assertEqual(res.representativeGeometry().asWkt(), - 'Polygon ((101 202, 103 202, 103 204, 101 204, 101 202))') + self.assertEqual( + res.representativeGeometry().asWkt(), + "Polygon ((101 202, 103 202, 103 204, 101 204, 101 202))", + ) def testReadWriteXml(self): doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") - item = QgsAnnotationRectangleTextItem('my text', QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(10, 20, 30, 40)) item.setBackgroundEnabled(True) - item.setBackgroundSymbol(QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black'})) + item.setBackgroundSymbol( + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black"} + ) + ) item.setFrameEnabled(True) - item.setFrameSymbol(QgsFillSymbol.createSimple({'color': '100,200,150', 'outline_color': 'black'})) + item.setFrameSymbol( + QgsFillSymbol.createSimple( + {"color": "100,200,150", "outline_color": "black"} + ) + ) item.setZIndex(11) item.setAlignment(Qt.AlignmentFlag.AlignRight) format = QgsTextFormat() @@ -447,13 +593,12 @@ def testReadWriteXml(self): item.setFormat(format) item.setMargins(QgsMargins(1, 2, 3, 4)) item.setMarginsUnit(Qgis.RenderUnit.Points) - item.setCalloutAnchor(QgsGeometry.fromWkt('Point(1 3)')) + item.setCalloutAnchor(QgsGeometry.fromWkt("Point(1 3)")) item.setCallout(QgsBalloonCallout()) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - item.setFixedSize(QSizeF(56, - 57)) + item.setFixedSize(QSizeF(56, 57)) item.setFixedSizeUnit(Qgis.RenderUnit.Inches) - item.setCalloutAnchor(QgsGeometry.fromWkt('Point(1 3)')) + item.setCalloutAnchor(QgsGeometry.fromWkt("Point(1 3)")) item.setCallout(QgsBalloonCallout()) item.setOffsetFromCallout(QSizeF(13.6, 17.2)) item.setOffsetFromCalloutUnit(Qgis.RenderUnit.Inches) @@ -463,11 +608,10 @@ def testReadWriteXml(self): s2 = QgsAnnotationRectangleTextItem.create() self.assertTrue(s2.readXml(elem, QgsReadWriteContext())) - self.assertEqual(s2.bounds().toString(3), '10.000,20.000 : 30.000,40.000') - self.assertEqual(s2.text(), 'my text') + self.assertEqual(s2.bounds().toString(3), "10.000,20.000 : 30.000,40.000") + self.assertEqual(s2.text(), "my text") self.assertEqual(s2.backgroundSymbol()[0].color(), QColor(200, 100, 100)) - self.assertEqual(s2.frameSymbol()[0].color(), - QColor(100, 200, 150)) + self.assertEqual(s2.frameSymbol()[0].color(), QColor(100, 200, 150)) self.assertEqual(s2.zIndex(), 11) self.assertTrue(s2.frameEnabled()) self.assertTrue(s2.backgroundEnabled()) @@ -475,23 +619,29 @@ def testReadWriteXml(self): self.assertEqual(s2.format().size(), 37) self.assertEqual(s2.margins(), QgsMargins(1, 2, 3, 4)) self.assertEqual(s2.marginsUnit(), Qgis.RenderUnit.Points) - self.assertEqual(s2.placementMode(), - Qgis.AnnotationPlacementMode.FixedSize) - self.assertEqual(s2.fixedSize(), QSizeF(56, - 57)) + self.assertEqual(s2.placementMode(), Qgis.AnnotationPlacementMode.FixedSize) + self.assertEqual(s2.fixedSize(), QSizeF(56, 57)) self.assertEqual(s2.fixedSizeUnit(), Qgis.RenderUnit.Inches) - self.assertEqual(s2.calloutAnchor().asWkt(), 'Point (1 3)') + self.assertEqual(s2.calloutAnchor().asWkt(), "Point (1 3)") self.assertIsInstance(s2.callout(), QgsBalloonCallout) self.assertEqual(s2.offsetFromCallout(), QSizeF(13.6, 17.2)) self.assertEqual(s2.offsetFromCalloutUnit(), Qgis.RenderUnit.Inches) def testClone(self): - item = QgsAnnotationRectangleTextItem('my text', QgsRectangle(10, 20, 30, 40)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(10, 20, 30, 40)) item.setBackgroundEnabled(True) - item.setBackgroundSymbol(QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black'})) + item.setBackgroundSymbol( + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black"} + ) + ) item.setFrameEnabled(True) - item.setFrameSymbol(QgsFillSymbol.createSimple({'color': '100,200,150', 'outline_color': 'black'})) + item.setFrameSymbol( + QgsFillSymbol.createSimple( + {"color": "100,200,150", "outline_color": "black"} + ) + ) item.setZIndex(11) item.setAlignment(Qt.AlignmentFlag.AlignRight) format = QgsTextFormat() @@ -500,20 +650,18 @@ def testClone(self): item.setMargins(QgsMargins(1, 2, 3, 4)) item.setMarginsUnit(Qgis.RenderUnit.Points) item.setPlacementMode(Qgis.AnnotationPlacementMode.FixedSize) - item.setFixedSize(QSizeF(56, - 57)) + item.setFixedSize(QSizeF(56, 57)) item.setFixedSizeUnit(Qgis.RenderUnit.Inches) - item.setCalloutAnchor(QgsGeometry.fromWkt('Point(1 3)')) + item.setCalloutAnchor(QgsGeometry.fromWkt("Point(1 3)")) item.setCallout(QgsBalloonCallout()) item.setOffsetFromCallout(QSizeF(13.6, 17.2)) item.setOffsetFromCalloutUnit(Qgis.RenderUnit.Inches) s2 = item.clone() - self.assertEqual(s2.bounds().toString(3), '10.000,20.000 : 30.000,40.000') - self.assertEqual(s2.text(), 'my text') + self.assertEqual(s2.bounds().toString(3), "10.000,20.000 : 30.000,40.000") + self.assertEqual(s2.text(), "my text") self.assertEqual(s2.backgroundSymbol()[0].color(), QColor(200, 100, 100)) - self.assertEqual(s2.frameSymbol()[0].color(), - QColor(100, 200, 150)) + self.assertEqual(s2.frameSymbol()[0].color(), QColor(100, 200, 150)) self.assertEqual(s2.zIndex(), 11) self.assertTrue(s2.frameEnabled()) self.assertTrue(s2.backgroundEnabled()) @@ -521,30 +669,31 @@ def testClone(self): self.assertEqual(s2.format().size(), 37) self.assertEqual(s2.margins(), QgsMargins(1, 2, 3, 4)) self.assertEqual(s2.marginsUnit(), Qgis.RenderUnit.Points) - self.assertEqual(s2.placementMode(), - Qgis.AnnotationPlacementMode.FixedSize) - self.assertEqual(s2.fixedSize(), QSizeF(56, - 57)) + self.assertEqual(s2.placementMode(), Qgis.AnnotationPlacementMode.FixedSize) + self.assertEqual(s2.fixedSize(), QSizeF(56, 57)) self.assertEqual(s2.fixedSizeUnit(), Qgis.RenderUnit.Inches) - self.assertEqual(s2.calloutAnchor().asWkt(), 'Point (1 3)') + self.assertEqual(s2.calloutAnchor().asWkt(), "Point (1 3)") self.assertIsInstance(s2.callout(), QgsBalloonCallout) self.assertEqual(s2.offsetFromCallout(), QSizeF(13.6, 17.2)) self.assertEqual(s2.offsetFromCalloutUnit(), Qgis.RenderUnit.Inches) def testRender(self): - item = QgsAnnotationRectangleTextItem('my text', QgsRectangle(12, 13, 14, 15)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(12, 13, 14, 15)) item.setMargins(QgsMargins(1, 0.5, 1, 0)) - item.setFrameSymbol(QgsFillSymbol.createSimple( - {'color': '0,0,0,0', 'outline_color': 'black', 'outline_width': 2})) + item.setFrameSymbol( + QgsFillSymbol.createSimple( + {"color": "0,0,0,0", "outline_color": "black", "outline_width": 2} + ) + ) - format = QgsTextFormat.fromQFont(getTestFont('Bold')) + format = QgsTextFormat.fromQFont(getTestFont("Bold")) format.setColor(QColor(255, 0, 0)) format.setOpacity(150 / 255) format.setSize(20) item.setFormat(format) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(300, 300)) @@ -563,15 +712,18 @@ def testRender(self): finally: painter.end() - self.assertTrue(self.image_check('recttext_render', 'recttext_render', image)) + self.assertTrue(self.image_check("recttext_render", "recttext_render", image)) def testRenderAlignment(self): - item = QgsAnnotationRectangleTextItem('my text', QgsRectangle(12, 13, 14, 15)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(12, 13, 14, 15)) item.setMargins(QgsMargins(1, 0.5, 1, 0)) - item.setFrameSymbol(QgsFillSymbol.createSimple( - {'color': '0,0,0,0', 'outline_color': 'black', 'outline_width': 2})) + item.setFrameSymbol( + QgsFillSymbol.createSimple( + {"color": "0,0,0,0", "outline_color": "black", "outline_width": 2} + ) + ) - format = QgsTextFormat.fromQFont(getTestFont('Bold')) + format = QgsTextFormat.fromQFont(getTestFont("Bold")) format.setColor(QColor(255, 0, 0)) format.setOpacity(150 / 255) format.setSize(20) @@ -580,7 +732,7 @@ def testRenderAlignment(self): item.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignBottom) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(300, 300)) @@ -599,21 +751,28 @@ def testRenderAlignment(self): finally: painter.end() - self.assertTrue(self.image_check('recttext_render_align', 'recttext_render_align', image)) + self.assertTrue( + self.image_check("recttext_render_align", "recttext_render_align", image) + ) def testRenderWithTransform(self): - item = QgsAnnotationRectangleTextItem('my text', QgsRectangle(11.5, 13, 12, 13.5)) + item = QgsAnnotationRectangleTextItem( + "my text", QgsRectangle(11.5, 13, 12, 13.5) + ) - format = QgsTextFormat.fromQFont(getTestFont('Bold')) + format = QgsTextFormat.fromQFont(getTestFont("Bold")) format.setColor(QColor(255, 0, 0)) format.setOpacity(150 / 255) format.setSize(20) item.setFormat(format) - item.setFrameSymbol(QgsFillSymbol.createSimple( - {'color': '0,0,0,0', 'outline_color': 'black', 'outline_width': 1})) + item.setFrameSymbol( + QgsFillSymbol.createSimple( + {"color": "0,0,0,0", "outline_color": "black", "outline_width": 1} + ) + ) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) settings.setExtent(QgsRectangle(1250958, 1386945, 1420709, 1532518)) settings.setOutputSize(QSize(300, 300)) @@ -621,8 +780,12 @@ def testRenderWithTransform(self): rc = QgsRenderContext.fromMapSettings(settings) rc.setCoordinateTransform( - QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'), settings.destinationCrs(), - QgsProject.instance())) + QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + settings.destinationCrs(), + QgsProject.instance(), + ) + ) image = QImage(200, 200, QImage.Format.Format_ARGB32) image.setDotsPerMeterX(int(96 / 25.4 * 1000)) image.setDotsPerMeterY(int(96 / 25.4 * 1000)) @@ -635,25 +798,40 @@ def testRenderWithTransform(self): finally: painter.end() - self.assertTrue(self.image_check('recttext_render_transform', 'recttext_render_transform', image)) + self.assertTrue( + self.image_check( + "recttext_render_transform", "recttext_render_transform", image + ) + ) def testRenderBackgroundFrame(self): - item = QgsAnnotationRectangleTextItem('my text', QgsRectangle(12, 13, 16, 15)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(12, 13, 16, 15)) item.setFrameEnabled(True) item.setBackgroundEnabled(True) - item.setBackgroundSymbol(QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black'})) - item.setFrameSymbol(QgsFillSymbol.createSimple( - {'color': '100,200,250,120', 'outline_color': 'black', 'outline_width': 2})) + item.setBackgroundSymbol( + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black"} + ) + ) + item.setFrameSymbol( + QgsFillSymbol.createSimple( + { + "color": "100,200,250,120", + "outline_color": "black", + "outline_width": 2, + } + ) + ) - format = QgsTextFormat.fromQFont(getTestFont('Bold')) + format = QgsTextFormat.fromQFont(getTestFont("Bold")) format.setColor(QColor(255, 0, 0)) format.setOpacity(150 / 255) format.setSize(20) item.setFormat(format) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(300, 300)) @@ -672,26 +850,33 @@ def testRenderBackgroundFrame(self): finally: painter.end() - self.assertTrue(self.image_check('recttext_background_frame', 'recttext_background_frame', image)) + self.assertTrue( + self.image_check( + "recttext_background_frame", "recttext_background_frame", image + ) + ) def testRenderCallout(self): - item = QgsAnnotationRectangleTextItem('my text', QgsRectangle(12, 13, 14, 15)) + item = QgsAnnotationRectangleTextItem("my text", QgsRectangle(12, 13, 14, 15)) item.setMargins(QgsMargins(1, 0.5, 1, 0)) - item.setFrameSymbol(QgsFillSymbol.createSimple( - {'color': '0,0,0,0', 'outline_color': 'black', 'outline_width': 2})) + item.setFrameSymbol( + QgsFillSymbol.createSimple( + {"color": "0,0,0,0", "outline_color": "black", "outline_width": 2} + ) + ) callout = QgsSimpleLineCallout() callout.lineSymbol().setWidth(1) item.setCallout(callout) - item.setCalloutAnchor(QgsGeometry.fromWkt('Point(11 12)')) + item.setCalloutAnchor(QgsGeometry.fromWkt("Point(11 12)")) - format = QgsTextFormat.fromQFont(getTestFont('Bold')) + format = QgsTextFormat.fromQFont(getTestFont("Bold")) format.setColor(QColor(255, 0, 0)) format.setOpacity(150 / 255) format.setSize(20) item.setFormat(format) settings = QgsMapSettings() - settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) settings.setExtent(QgsRectangle(10, 8, 18, 16)) settings.setOutputSize(QSize(300, 300)) @@ -710,8 +895,12 @@ def testRenderCallout(self): finally: painter.end() - self.assertTrue(self.image_check('recttext_render_callout', 'recttext_render_callout', image)) + self.assertTrue( + self.image_check( + "recttext_render_callout", "recttext_render_callout", image + ) + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsapplication.py b/tests/src/python/test_qgsapplication.py index 2c4cf005341c..02f1196a07e0 100644 --- a/tests/src/python/test_qgsapplication.py +++ b/tests/src/python/test_qgsapplication.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Tim Sutton (tim@linfiniti.com)' -__date__ = '20/01/2011' -__copyright__ = 'Copyright 2012, The QGIS Project' + +__author__ = "Tim Sutton (tim@linfiniti.com)" +__date__ = "20/01/2011" +__copyright__ = "Copyright 2012, The QGIS Project" import unittest @@ -20,12 +21,12 @@ class TestPyQgsApplication(QgisTestCase): def testInvalidThemeName(self): """Check using an invalid theme will fallback to 'default'""" - QGISAPP.setUITheme('fooobar') - myExpectedResult = 'default' + QGISAPP.setUITheme("fooobar") + myExpectedResult = "default" myResult = QGISAPP.themeName() - myMessage = f'Expected:\n{myExpectedResult}\nGot:\n{myResult}\n' + myMessage = f"Expected:\n{myExpectedResult}\nGot:\n{myResult}\n" assert myExpectedResult == myResult, myMessage -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsappstartup.py b/tests/src/python/test_qgsappstartup.py index 9fbcd284b431..7d819804f0f9 100644 --- a/tests/src/python/test_qgsappstartup.py +++ b/tests/src/python/test_qgsappstartup.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Hugo Mercier (hugo.mercier@oslandia.com)' -__date__ = '17/07/2013' -__copyright__ = 'Copyright 2013, The QGIS Project' + +__author__ = "Hugo Mercier (hugo.mercier@oslandia.com)" +__date__ = "17/07/2013" +__copyright__ = "Copyright 2013, The QGIS Project" import errno import glob @@ -25,14 +26,14 @@ from utilities import unitTestDataPath -print('CTEST_FULL_OUTPUT') +print("CTEST_FULL_OUTPUT") TEST_DATA_DIR = unitTestDataPath() class TestPyQgsAppStartup(unittest.TestCase): - TMP_DIR = '' + TMP_DIR = "" @classmethod def setUpClass(cls): @@ -47,9 +48,17 @@ def tearDownClass(cls): super().tearDownClass() # TODO: refactor parameters to **kwargs to handle all startup combinations - def doTestStartup(self, option='', testDir='', testFile='', - loadPlugins=False, customization=False, - timeOut=360, env=None, additionalArguments=[]): + def doTestStartup( + self, + option="", + testDir="", + testFile="", + loadPlugins=False, + customization=False, + timeOut=360, + env=None, + additionalArguments=[], + ): """Run QGIS with the given option. Wait for testFile to be created. If time runs out, fail. """ @@ -65,30 +74,41 @@ def doTestStartup(self, option='', testDir='', testFile='', os.remove(myTestFile) # whether to load plugins - plugins = '' if loadPlugins else '--noplugins' + plugins = "" if loadPlugins else "--noplugins" # whether to enable GUI customization - customize = '' if customization else '--nocustomization' + customize = "" if customization else "--nocustomization" # environment variables = system variables + provided 'env' myenv = os.environ.copy() if env is not None: myenv.update(env) - call = [QGIS_BIN, "--nologo", plugins, customize, option, testDir] + additionalArguments + call = [ + QGIS_BIN, + "--nologo", + plugins, + customize, + option, + testDir, + ] + additionalArguments p = subprocess.Popen(call, env=myenv) s = 0 while not os.path.exists(myTestFile): p.poll() if p.returncode is not None: - raise Exception(f"Return code: {p.returncode}, Call: \"{' '.join(call)}\", Env: {env}") + raise Exception( + f"Return code: {p.returncode}, Call: \"{' '.join(call)}\", Env: {env}" + ) time.sleep(1) s += 1 if s > timeOut: - raise Exception(f"Timed out waiting for application start, Call: \"{' '.join(call)}\", Env: {env}") + raise Exception( + f"Timed out waiting for application start, Call: \"{' '.join(call)}\", Env: {env}" + ) - with open(myTestFile, encoding='utf-8') as res_file: + with open(myTestFile, encoding="utf-8") as res_file: lines = res_file.readlines() try: @@ -102,78 +122,85 @@ def doTestStartup(self, option='', testDir='', testFile='', def testPyQgisStartupEnvVar(self): # verify PYQGIS_STARTUP env variable file is run by embedded interpreter # create a temp python module that writes out test file - testfile = 'pyqgis_startup.txt' - testfilepath = os.path.join(self.TMP_DIR, testfile).replace('\\', '/') + testfile = "pyqgis_startup.txt" + testfilepath = os.path.join(self.TMP_DIR, testfile).replace("\\", "/") testcode = [ f"from qgis.core import QgsApplication\nf = open('{testfilepath}', 'w')\n", "f.write('Platform: ' + QgsApplication.platform())\n", - "f.close()\n" + "f.close()\n", ] - testmod = os.path.join(self.TMP_DIR, 'pyqgis_startup.py').replace('\\', '/') - f = open(testmod, 'w') + testmod = os.path.join(self.TMP_DIR, "pyqgis_startup.py").replace("\\", "/") + f = open(testmod, "w") f.writelines(testcode) f.close() testfile_lines = self.doTestStartup( - testFile=testfilepath, - timeOut=360, - env={'PYQGIS_STARTUP': testmod}) + testFile=testfilepath, timeOut=360, env={"PYQGIS_STARTUP": testmod} + ) # platform should be "Desktop" - self.assertEqual(testfile_lines, ['Platform: desktop']) + self.assertEqual(testfile_lines, ["Platform: desktop"]) def testPyArgs(self): - testfile = 'pyqgis_code.txt' - testfilepath = os.path.join(self.TMP_DIR, testfile).replace('\\', '/') + testfile = "pyqgis_code.txt" + testfilepath = os.path.join(self.TMP_DIR, testfile).replace("\\", "/") testcode = [ f"import sys\nf = open('{testfilepath}', 'a')\n", - "for arg in sys.argv:\n" - " f.write(arg)\n", + "for arg in sys.argv:\n" " f.write(arg)\n", " f.write('\\n')\n", - "f.close()\n" + "f.close()\n", ] - testmod = os.path.join(self.TMP_DIR, 'pyqgis_code.py').replace('\\', '/') - f = open(testmod, 'w') + testmod = os.path.join(self.TMP_DIR, "pyqgis_code.py").replace("\\", "/") + f = open(testmod, "w") f.writelines(testcode) f.close() testfile_lines = self.doTestStartup( testFile=testfilepath, timeOut=10, - additionalArguments=["--code", testmod, "--py-args", "--specialScriptArgument's", 'a "Quoted" text arg', "--"]) - - self.assertEqual(testfile_lines, [testmod + '\n', - "--specialScriptArgument's\n", - 'a "Quoted" text arg\n']) - - -if __name__ == '__main__': + additionalArguments=[ + "--code", + testmod, + "--py-args", + "--specialScriptArgument's", + 'a "Quoted" text arg', + "--", + ], + ) + + self.assertEqual( + testfile_lines, + [testmod + "\n", "--specialScriptArgument's\n", 'a "Quoted" text arg\n'], + ) + + +if __name__ == "__main__": # look for qgis bin path - QGIS_BIN = '' - prefixPath = os.environ['QGIS_PREFIX_PATH'] + QGIS_BIN = "" + prefixPath = os.environ["QGIS_PREFIX_PATH"] # see qgsapplication.cpp:98 - for f in ['', '..', 'bin']: + for f in ["", "..", "bin"]: d = os.path.join(prefixPath, f) - b = os.path.abspath(os.path.join(d, 'qgis')) + b = os.path.abspath(os.path.join(d, "qgis")) if os.path.exists(b): QGIS_BIN = b break - b = os.path.abspath(os.path.join(d, 'qgis.exe')) + b = os.path.abspath(os.path.join(d, "qgis.exe")) if os.path.exists(b): QGIS_BIN = b break - if sys.platform[:3] == 'dar': # Mac + if sys.platform[:3] == "dar": # Mac # QGIS.app may be QGIS_x.x-dev.app for nightlies # internal binary will match, minus the '.app' found = False - for app_path in glob.glob(d + '/QGIS*.app'): - m = re.search(r'/(QGIS(_\d\.\d-dev)?)\.app', app_path) + for app_path in glob.glob(d + "/QGIS*.app"): + m = re.search(r"/(QGIS(_\d\.\d-dev)?)\.app", app_path) if m: - QGIS_BIN = app_path + '/Contents/MacOS/' + m.group(1) + QGIS_BIN = app_path + "/Contents/MacOS/" + m.group(1) found = True break if found: break - print(f'\nQGIS_BIN: {QGIS_BIN}') - assert QGIS_BIN, 'QGIS binary not found, skipping test suite' + print(f"\nQGIS_BIN: {QGIS_BIN}") + assert QGIS_BIN, "QGIS binary not found, skipping test suite" unittest.main() diff --git a/tests/src/python/test_qgsarcgisportalutils.py b/tests/src/python/test_qgsarcgisportalutils.py index f363f6f12606..821c1d269877 100644 --- a/tests/src/python/test_qgsarcgisportalutils.py +++ b/tests/src/python/test_qgsarcgisportalutils.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2018-02-16' -__copyright__ = 'Copyright 2018, Nyall Dawson' + +__author__ = "Nyall Dawson" +__date__ = "2018-02-16" +__copyright__ = "Copyright 2018, Nyall Dawson" import hashlib import os @@ -24,18 +25,22 @@ def sanitize(endpoint, x): if not os.path.exists(endpoint): os.makedirs(endpoint) - if x.startswith('/query'): - x = x[len('/query'):] - endpoint = endpoint + '_query' + if x.startswith("/query"): + x = x[len("/query") :] + endpoint = endpoint + "_query" if len(endpoint + x) > 150: ret = endpoint + hashlib.md5(x.encode()).hexdigest() # print('Before: ' + endpoint + x) # print('After: ' + ret) return ret - return endpoint + x.replace('?', '_').replace('&', '_').replace('<', '_').replace('>', '_').replace('"', - '_').replace( - "'", '_').replace(' ', '_').replace(':', '_').replace('/', '_').replace('\n', '_') + return endpoint + x.replace("?", "_").replace("&", "_").replace("<", "_").replace( + ">", "_" + ).replace('"', "_").replace("'", "_").replace(" ", "_").replace(":", "_").replace( + "/", "_" + ).replace( + "\n", "_" + ) class MessageLogger(QObject): @@ -54,7 +59,7 @@ def __exit__(self, type, value, traceback): def logMessage(self, msg, tag, level): if tag == self.tag or not self.tag: - self.log.append(msg.encode('UTF-8')) + self.log.append(msg.encode("UTF-8")) def messages(self): return self.log @@ -75,7 +80,7 @@ def setUpClass(cls): # On Windows we must make sure that any backslash in the path is # replaced by a forward slash so that QUrl can process it - cls.basetestpath = tempfile.mkdtemp().replace('\\', '/') + cls.basetestpath = tempfile.mkdtemp().replace("\\", "/") @classmethod def tearDownClass(cls): @@ -89,9 +94,10 @@ def testUserInfoSelf(self): Test retrieving logged on user info """ print(self.basetestpath) - endpoint = self.basetestpath + '/user_fake_qgis_http_endpoint' - with open(sanitize(endpoint, '/self?f=json'), 'wb') as f: - f.write(b"""{ + endpoint = self.basetestpath + "/user_fake_qgis_http_endpoint" + with open(sanitize(endpoint, "/self?f=json"), "wb") as f: + f.write( + b"""{ "username": "me", "id": "2a", "groups": [ @@ -104,24 +110,35 @@ def testUserInfoSelf(self): "title": "Another Group" } ] -}""") +}""" + ) - res = QgsArcGisPortalUtils.retrieveUserInfo('http://' + endpoint, '', '') + res = QgsArcGisPortalUtils.retrieveUserInfo("http://" + endpoint, "", "") # no errors self.assertFalse(res[1]) self.assertFalse(res[2]) - self.assertEqual(res[0], {'groups': [{'id': 'c4', 'title': 'A Group'}, {'id': 'd4', 'title': 'Another Group'}], - 'id': '2a', 'username': 'me'}) + self.assertEqual( + res[0], + { + "groups": [ + {"id": "c4", "title": "A Group"}, + {"id": "d4", "title": "Another Group"}, + ], + "id": "2a", + "username": "me", + }, + ) def testUserInfoExplicit(self): """ Test retrieving explicitly specified user info """ print(self.basetestpath) - endpoint = self.basetestpath + '/user_fake_qgis_http_endpoint' + endpoint = self.basetestpath + "/user_fake_qgis_http_endpoint" - with open(sanitize(endpoint + '_users/', 'some_user?f=json'), 'wb') as f: - f.write(b"""{ + with open(sanitize(endpoint + "_users/", "some_user?f=json"), "wb") as f: + f.write( + b"""{ "username": "some_user", "id": "2b", "groups": [ @@ -134,25 +151,38 @@ def testUserInfoExplicit(self): "title": "Another Group" } ] -}""") +}""" + ) - headers = {'referer': 'http://google.com'} - res = QgsArcGisPortalUtils.retrieveUserInfo('http://' + endpoint, 'some_user', '', headers) + headers = {"referer": "http://google.com"} + res = QgsArcGisPortalUtils.retrieveUserInfo( + "http://" + endpoint, "some_user", "", headers + ) # no errors self.assertFalse(res[1]) self.assertFalse(res[2]) - self.assertEqual(res[0], {'groups': [{'id': 'c4', 'title': 'A Group'}, {'id': 'd4', 'title': 'Another Group'}], - 'id': '2b', 'username': 'some_user'}) + self.assertEqual( + res[0], + { + "groups": [ + {"id": "c4", "title": "A Group"}, + {"id": "d4", "title": "Another Group"}, + ], + "id": "2b", + "username": "some_user", + }, + ) def test_retrieve_groups(self): """ Test retrieving user groups """ print(self.basetestpath) - endpoint = self.basetestpath + '/group_fake_qgis_http_endpoint' + endpoint = self.basetestpath + "/group_fake_qgis_http_endpoint" - with open(sanitize(endpoint + '_users/', 'some_user?f=json'), 'wb') as f: - f.write(b"""{ + with open(sanitize(endpoint + "_users/", "some_user?f=json"), "wb") as f: + f.write( + b"""{ "username": "some_user", "id": "2b", "groups": [ @@ -165,23 +195,32 @@ def test_retrieve_groups(self): "title": "Another Group" } ] - }""") + }""" + ) - res = QgsArcGisPortalUtils.retrieveUserGroups('http://' + endpoint, 'some_user', '') + res = QgsArcGisPortalUtils.retrieveUserGroups( + "http://" + endpoint, "some_user", "" + ) # no errors self.assertFalse(res[1]) self.assertFalse(res[2]) - self.assertEqual(res[0], [{'id': 'c4', 'title': 'A Group'}, {'id': 'd4', 'title': 'Another Group'}]) + self.assertEqual( + res[0], + [{"id": "c4", "title": "A Group"}, {"id": "d4", "title": "Another Group"}], + ) def test_retrieve_group_items(self): """ Test retrieving group content """ print(self.basetestpath) - endpoint = self.basetestpath + '/group_items_fake_qgis_http_endpoint' + endpoint = self.basetestpath + "/group_items_fake_qgis_http_endpoint" - with open(sanitize(endpoint + '_groups/', 'ab1?f=json&start=1&num=2'), 'wb') as f: - f.write(b"""{ + with open( + sanitize(endpoint + "_groups/", "ab1?f=json&start=1&num=2"), "wb" + ) as f: + f.write( + b"""{ "total": 3, "start": 1, "num": 2, @@ -196,10 +235,14 @@ def test_retrieve_group_items(self): "title": "Item 2" } ] -}""") - - with open(sanitize(endpoint + '_groups/', 'ab1?f=json&start=3&num=2'), 'wb') as f: - f.write(b"""{ +}""" + ) + + with open( + sanitize(endpoint + "_groups/", "ab1?f=json&start=3&num=2"), "wb" + ) as f: + f.write( + b"""{ "total": 3, "start": 3, "num": 1, @@ -210,23 +253,35 @@ def test_retrieve_group_items(self): "title": "Item 3" } ] - }""") - res = QgsArcGisPortalUtils.retrieveGroupContent('http://' + endpoint, 'ab1', '', pageSize=2) + }""" + ) + res = QgsArcGisPortalUtils.retrieveGroupContent( + "http://" + endpoint, "ab1", "", pageSize=2 + ) # no errors self.assertFalse(res[1]) self.assertFalse(res[2]) - self.assertEqual(res[0], [{'id': '74', 'title': 'Item 1'}, {'id': '20', 'title': 'Item 2'}, - {'id': '75', 'title': 'Item 3'}]) + self.assertEqual( + res[0], + [ + {"id": "74", "title": "Item 1"}, + {"id": "20", "title": "Item 2"}, + {"id": "75", "title": "Item 3"}, + ], + ) def test_retrieve_group_items_filtered(self): """ Test retrieving group content """ print(self.basetestpath) - endpoint = self.basetestpath + '/groupf_items_fake_qgis_http_endpoint' + endpoint = self.basetestpath + "/groupf_items_fake_qgis_http_endpoint" - with open(sanitize(endpoint + '_groups/', 'ab1?f=json&start=1&num=2'), 'wb') as f: - f.write(b"""{ + with open( + sanitize(endpoint + "_groups/", "ab1?f=json&start=1&num=2"), "wb" + ) as f: + f.write( + b"""{ "total": 3, "start": 1, "num": 2, @@ -243,10 +298,14 @@ def test_retrieve_group_items_filtered(self): "type":"Map Service" } ] -}""") - - with open(sanitize(endpoint + '_groups/', 'ab1?f=json&start=3&num=2'), 'wb') as f: - f.write(b"""{ +}""" + ) + + with open( + sanitize(endpoint + "_groups/", "ab1?f=json&start=3&num=2"), "wb" + ) as f: + f.write( + b"""{ "total": 3, "start": 3, "num": 1, @@ -258,34 +317,68 @@ def test_retrieve_group_items_filtered(self): "type":"Image Service" } ] - }""") - res = QgsArcGisPortalUtils.retrieveGroupItemsOfType('http://' + endpoint, 'ab1', '', - [QgsArcGisPortalUtils.ItemType.FeatureService], pageSize=2) + }""" + ) + res = QgsArcGisPortalUtils.retrieveGroupItemsOfType( + "http://" + endpoint, + "ab1", + "", + [QgsArcGisPortalUtils.ItemType.FeatureService], + pageSize=2, + ) # no errors self.assertFalse(res[1]) self.assertFalse(res[2]) - self.assertEqual(res[0], [{'id': '74', 'title': 'Item 1', 'type': 'Feature Service'}]) - res = QgsArcGisPortalUtils.retrieveGroupItemsOfType('http://' + endpoint, 'ab1', '', - [QgsArcGisPortalUtils.ItemType.MapService], pageSize=2) + self.assertEqual( + res[0], [{"id": "74", "title": "Item 1", "type": "Feature Service"}] + ) + res = QgsArcGisPortalUtils.retrieveGroupItemsOfType( + "http://" + endpoint, + "ab1", + "", + [QgsArcGisPortalUtils.ItemType.MapService], + pageSize=2, + ) # no errors self.assertFalse(res[1]) self.assertFalse(res[2]) - self.assertEqual(res[0], [{'id': '20', 'title': 'Item 2', 'type': 'Map Service'}]) - res = QgsArcGisPortalUtils.retrieveGroupItemsOfType('http://' + endpoint, 'ab1', '', - [QgsArcGisPortalUtils.ItemType.ImageService], pageSize=2) + self.assertEqual( + res[0], [{"id": "20", "title": "Item 2", "type": "Map Service"}] + ) + res = QgsArcGisPortalUtils.retrieveGroupItemsOfType( + "http://" + endpoint, + "ab1", + "", + [QgsArcGisPortalUtils.ItemType.ImageService], + pageSize=2, + ) # no errors self.assertFalse(res[1]) self.assertFalse(res[2]) - self.assertEqual(res[0], [{'id': '75', 'title': 'Item 3', 'type': 'Image Service'}]) - res = QgsArcGisPortalUtils.retrieveGroupItemsOfType('http://' + endpoint, 'ab1', '', - [QgsArcGisPortalUtils.ItemType.FeatureService, - QgsArcGisPortalUtils.ItemType.MapService], pageSize=2) + self.assertEqual( + res[0], [{"id": "75", "title": "Item 3", "type": "Image Service"}] + ) + res = QgsArcGisPortalUtils.retrieveGroupItemsOfType( + "http://" + endpoint, + "ab1", + "", + [ + QgsArcGisPortalUtils.ItemType.FeatureService, + QgsArcGisPortalUtils.ItemType.MapService, + ], + pageSize=2, + ) # no errors self.assertFalse(res[1]) self.assertFalse(res[2]) - self.assertEqual(res[0], [{'id': '74', 'title': 'Item 1', 'type': 'Feature Service'}, - {'id': '20', 'title': 'Item 2', 'type': 'Map Service'}]) + self.assertEqual( + res[0], + [ + {"id": "74", "title": "Item 1", "type": "Feature Service"}, + {"id": "20", "title": "Item 2", "type": "Map Service"}, + ], + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsarcgisrestutils.py b/tests/src/python/test_qgsarcgisrestutils.py index 58254bd4b092..33106246e10c 100644 --- a/tests/src/python/test_qgsarcgisrestutils.py +++ b/tests/src/python/test_qgsarcgisrestutils.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2022 by Nyall Dawson' -__date__ = '14/07/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "(C) 2022 by Nyall Dawson" +__date__ = "14/07/2022" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, Qt, QTime, QTimeZone, QVariant from qgis.core import ( @@ -35,328 +36,837 @@ class TestQgsArcGisRestUtils(QgisTestCase): def test_json_to_geometry(self): - tests = [('esriGeometryPolyline', - {'curvePaths': [[[148.38318344186538, -17.139016173514584], {'c': [[150.99306515432036, -16.733335282152847], [150.46567981044387, -15.976063814628597]]}, {'c': [[153.67056039605595, -16.314131721058928], [153.02147048339893, -17.855719902399045]]}, [155.13101252753447, -14.556180364908652], [150.533293548165, -13.636636042108115], {'c': [[147.6394350119692, -14.353339106615321], [147.99102541902195, -12.83879629512887]]}]], - 'hasM': False, 'hasZ': False}, - 'MultiCurve (CompoundCurve (CircularString (148.38318 -17.13902, 150.46568 -15.97606, 150.99307 -16.73334),CircularString (150.99307 -16.73334, 153.02147 -17.85572, 153.67056 -16.31413),(153.67056 -16.31413, 155.13101 -14.55618, 150.53329 -13.63664),CircularString (150.53329 -13.63664, 147.99103 -12.8388, 147.63944 -14.35334)))')] + tests = [ + ( + "esriGeometryPolyline", + { + "curvePaths": [ + [ + [148.38318344186538, -17.139016173514584], + { + "c": [ + [150.99306515432036, -16.733335282152847], + [150.46567981044387, -15.976063814628597], + ] + }, + { + "c": [ + [153.67056039605595, -16.314131721058928], + [153.02147048339893, -17.855719902399045], + ] + }, + [155.13101252753447, -14.556180364908652], + [150.533293548165, -13.636636042108115], + { + "c": [ + [147.6394350119692, -14.353339106615321], + [147.99102541902195, -12.83879629512887], + ] + }, + ] + ], + "hasM": False, + "hasZ": False, + }, + "MultiCurve (CompoundCurve (CircularString (148.38318 -17.13902, 150.46568 -15.97606, 150.99307 -16.73334),CircularString (150.99307 -16.73334, 153.02147 -17.85572, 153.67056 -16.31413),(153.67056 -16.31413, 155.13101 -14.55618, 150.53329 -13.63664),CircularString (150.53329 -13.63664, 147.99103 -12.8388, 147.63944 -14.35334)))", + ) + ] for type_string, json, expected in tests: - geometry, _ = QgsArcGisRestUtils.convertGeometry(json, type_string, json.get('hasM'), json.get('hasZ')) + geometry, _ = QgsArcGisRestUtils.convertGeometry( + json, type_string, json.get("hasM"), json.get("hasZ") + ) self.assertEqual(geometry.asWkt(5), expected) def test_geometry_to_json(self): tests = [ - ('Point(1 2)', {'x': 1.0, 'y': 2.0}), - ('PointZ(1 2 3)', {'x': 1.0, 'y': 2.0, 'z': 3.0}), - ('PointM(1 2 4)', {'x': 1.0, 'y': 2.0, 'm': 4.0}), - ('PointZM(1 2 3 4)', {'x': 1.0, 'y': 2.0, 'z': 3.0, 'm': 4.0}), - ('MultiPoint(1 1, 10 1, 3 4)', - {'hasM': False, 'hasZ': False, 'points': [[1.0, 1.0], [10.0, 1.0], [3.0, 4.0]]}), - ('MultiPointZ(1 1 3, 10 1 8, 3 4 9)', - {'hasM': False, 'hasZ': True, 'points': [[1.0, 1.0, 3.0], [10.0, 1.0, 8.0], [3.0, 4.0, 9.0]]}), - ('MultiPointM(1 1 22, 10 1 23, 3 4 24)', {'hasM': True, 'hasZ': False, - 'points': [[1.0, 1.0, 22.0], [10.0, 1.0, 23.0], - [3.0, 4.0, 24.0]]}), - ('MultiPointZM(1 1 3 22, 10 1 8 24, 3 4 9 55)', - {'hasM': True, 'hasZ': True, - 'points': [[1.0, 1.0, 3.0, 22.0], [10.0, 1.0, 8.0, 24.0], [3.0, 4.0, 9.0, 55.0]]}), - ('LineString(1 2, 3 4)', - {'hasM': False, 'hasZ': False, 'paths': [[[1.0, 2.0], [3.0, 4.0]]]}), - ('LineString(1 2, 3 4, 5 6)', - {'hasM': False, 'hasZ': False, 'paths': [[[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]]}), - ('LineStringZ(1 2 11, 3 4 12)', - {'hasM': False, 'hasZ': True, 'paths': [[[1.0, 2.0, 11.0], [3.0, 4.0, 12.0]]]}), - ('LineStringM(1 2 21, 3 4 22)', - {'hasM': True, 'hasZ': False, 'paths': [[[1.0, 2.0, 21.0], [3.0, 4.0, 22.0]]]}), - ('LineStringZM(1 2 21 22, 3 4 31 33)', - {'hasM': True, 'hasZ': True, 'paths': [[[1.0, 2.0, 21.0, 22.0], [3.0, 4.0, 31.0, 33.0]]]}), - ('CircularString (0 0, 1 4, 3 3)', - {'hasM': False, 'hasZ': False, 'curvePaths': [[[0.0, 0.0], - {'c': [[3.0, 3.0], [1.0, 4.0]]}]]}), - ('CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4)', - {'hasM': False, 'hasZ': False, 'curvePaths': [[[1.0, 2.0], - {'c': [[7.0, 2.2], [5.0, 4.0]]}, - {'c': [[13.0, 4.0], [10.0, 0.1]]}]]}), - ('CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4, 15 6)', - # invalid curve, has extra node which must be ignored - {'hasM': False, 'hasZ': False, 'curvePaths': [[[1.0, 2.0], - {'c': [[7.0, 2.2], [5.0, 4.0]]}, - {'c': [[13.0, 4.0], [10.0, 0.1]]}]]}), - ('CircularStringZ (1 2 3, 5 4 4, 7 2.2 5)', - {'hasM': False, 'hasZ': True, 'curvePaths': [[[1.0, 2.0, 3.0], - {'c': [[7.0, 2.2, 5.0], [5.0, 4.0, 4.0]]}]]}), - ('CircularStringM (1 2 3, 5 4 4, 7 2.2 5)', - {'hasM': True, 'hasZ': False, 'curvePaths': [[[1.0, 2.0, 3.0], - {'c': [[7.0, 2.2, 5.0], [5.0, 4.0, 4.0]]}]]}), - ('CircularStringZM (1 2 3 11, 5 4 4 12, 7 2.2 5 13)', - {'hasM': True, 'hasZ': True, 'curvePaths': [[[1.0, 2.0, 3.0, 11.0], - {'c': [[7.0, 2.2, 5.0, 13.0], [5.0, 4.0, 4.0, 12.0]]}]]}), + ("Point(1 2)", {"x": 1.0, "y": 2.0}), + ("PointZ(1 2 3)", {"x": 1.0, "y": 2.0, "z": 3.0}), + ("PointM(1 2 4)", {"x": 1.0, "y": 2.0, "m": 4.0}), + ("PointZM(1 2 3 4)", {"x": 1.0, "y": 2.0, "z": 3.0, "m": 4.0}), + ( + "MultiPoint(1 1, 10 1, 3 4)", + { + "hasM": False, + "hasZ": False, + "points": [[1.0, 1.0], [10.0, 1.0], [3.0, 4.0]], + }, + ), + ( + "MultiPointZ(1 1 3, 10 1 8, 3 4 9)", + { + "hasM": False, + "hasZ": True, + "points": [[1.0, 1.0, 3.0], [10.0, 1.0, 8.0], [3.0, 4.0, 9.0]], + }, + ), + ( + "MultiPointM(1 1 22, 10 1 23, 3 4 24)", + { + "hasM": True, + "hasZ": False, + "points": [[1.0, 1.0, 22.0], [10.0, 1.0, 23.0], [3.0, 4.0, 24.0]], + }, + ), + ( + "MultiPointZM(1 1 3 22, 10 1 8 24, 3 4 9 55)", + { + "hasM": True, + "hasZ": True, + "points": [ + [1.0, 1.0, 3.0, 22.0], + [10.0, 1.0, 8.0, 24.0], + [3.0, 4.0, 9.0, 55.0], + ], + }, + ), + ( + "LineString(1 2, 3 4)", + {"hasM": False, "hasZ": False, "paths": [[[1.0, 2.0], [3.0, 4.0]]]}, + ), + ( + "LineString(1 2, 3 4, 5 6)", + { + "hasM": False, + "hasZ": False, + "paths": [[[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]], + }, + ), + ( + "LineStringZ(1 2 11, 3 4 12)", + { + "hasM": False, + "hasZ": True, + "paths": [[[1.0, 2.0, 11.0], [3.0, 4.0, 12.0]]], + }, + ), + ( + "LineStringM(1 2 21, 3 4 22)", + { + "hasM": True, + "hasZ": False, + "paths": [[[1.0, 2.0, 21.0], [3.0, 4.0, 22.0]]], + }, + ), + ( + "LineStringZM(1 2 21 22, 3 4 31 33)", + { + "hasM": True, + "hasZ": True, + "paths": [[[1.0, 2.0, 21.0, 22.0], [3.0, 4.0, 31.0, 33.0]]], + }, + ), + ( + "CircularString (0 0, 1 4, 3 3)", + { + "hasM": False, + "hasZ": False, + "curvePaths": [[[0.0, 0.0], {"c": [[3.0, 3.0], [1.0, 4.0]]}]], + }, + ), + ( + "CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4)", + { + "hasM": False, + "hasZ": False, + "curvePaths": [ + [ + [1.0, 2.0], + {"c": [[7.0, 2.2], [5.0, 4.0]]}, + {"c": [[13.0, 4.0], [10.0, 0.1]]}, + ] + ], + }, + ), + ( + "CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4, 15 6)", + # invalid curve, has extra node which must be ignored + { + "hasM": False, + "hasZ": False, + "curvePaths": [ + [ + [1.0, 2.0], + {"c": [[7.0, 2.2], [5.0, 4.0]]}, + {"c": [[13.0, 4.0], [10.0, 0.1]]}, + ] + ], + }, + ), + ( + "CircularStringZ (1 2 3, 5 4 4, 7 2.2 5)", + { + "hasM": False, + "hasZ": True, + "curvePaths": [ + [[1.0, 2.0, 3.0], {"c": [[7.0, 2.2, 5.0], [5.0, 4.0, 4.0]]}] + ], + }, + ), + ( + "CircularStringM (1 2 3, 5 4 4, 7 2.2 5)", + { + "hasM": True, + "hasZ": False, + "curvePaths": [ + [[1.0, 2.0, 3.0], {"c": [[7.0, 2.2, 5.0], [5.0, 4.0, 4.0]]}] + ], + }, + ), + ( + "CircularStringZM (1 2 3 11, 5 4 4 12, 7 2.2 5 13)", + { + "hasM": True, + "hasZ": True, + "curvePaths": [ + [ + [1.0, 2.0, 3.0, 11.0], + {"c": [[7.0, 2.2, 5.0, 13.0], [5.0, 4.0, 4.0, 12.0]]}, + ] + ], + }, + ), # compound curve with no curved components should return paths, not curvePaths - ('CompoundCurve ((-1 -5, 1 2))', - {'hasM': False, 'hasZ': False, 'paths': [[[-1.0, -5.0], [1.0, 2.0]]]}), - ('CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.20, 10 0.1, 13 4),(13 4, 17 -6))', - {'hasM': False, 'hasZ': False, 'curvePaths': [[[-1.0, -5.0], - [1.0, 2.0], - {'c': [[7.0, 2.2], [5.0, 4.0]]}, - {'c': [[13.0, 4.0], [10.0, 0.1]]}, - [17.0, -6.0] - ]]}), - ( - 'CompoundCurveZ ((-1 -5 3, 1 2 4),CircularStringZ (1 2 4, 5 4 5, 7 2.20 6, 10 0.1 7, 13 4 8),(13 4 8, 17 -6 9))', - {'hasM': False, 'hasZ': True, 'curvePaths': [[[-1.0, -5.0, 3.0], - [1.0, 2.0, 4.0], - {'c': [[7.0, 2.2, 6.0], [5.0, 4.0, 5.0]]}, - {'c': [[13.0, 4.0, 8.0], [10.0, 0.1, 7.0]]}, - [17.0, -6.0, 9.0] - ]]}), - ( - 'CompoundCurveM ((-1 -5 3, 1 2 4),CircularStringM (1 2 4, 5 4 5, 7 2.20 6, 10 0.1 7, 13 4 8),(13 4 8, 17 -6 9))', - {'hasM': True, 'hasZ': False, 'curvePaths': [[[-1.0, -5.0, 3.0], - [1.0, 2.0, 4.0], - {'c': [[7.0, 2.2, 6.0], [5.0, 4.0, 5.0]]}, - {'c': [[13.0, 4.0, 8.0], [10.0, 0.1, 7.0]]}, - [17.0, -6.0, 9.0] - ]]}), - ( - 'CompoundCurveZM ((-1 -5 3 11, 1 2 4 12),CircularStringZM (1 2 4 12, 5 4 5 13, 7 2.20 6 14, 10 0.1 7 15, 13 4 8 16),(13 4 8 16, 17 -6 9 17))', - {'hasM': True, 'hasZ': True, 'curvePaths': [[[-1.0, -5.0, 3.0, 11.0], - [1.0, 2.0, 4.0, 12.0], - {'c': [[7.0, 2.2, 6.0, 14.0], [5.0, 4.0, 5.0, 13.0]]}, - {'c': [[13.0, 4.0, 8.0, 16.0], [10.0, 0.1, 7.0, 15.0]]}, - [17.0, -6.0, 9.0, 17.0] - ]]}), - ('MultiCurve (CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),CircularString (-11 -3, 5 7, 10 -1))', - {'hasM': False, 'hasZ': False, 'curvePaths': [[[1.0, 2.0], - {'c': [[7.0, 2.2], [5.0, 4.0]]}, - {'c': [[13.0, 4.0], [10.0, 0.1]]} - ], - [ - [-11.0, -3.0], - {'c': [[10.0, -1.0], [5.0, 7.0]]} - ]]}), - ( - 'MultiCurveZ (CircularStringZ (1 2 10, 5 4 11, 7 2.2 12, 10 0.1 13, 13 4 14),CircularStringZ (-11 -3 20, 5 7 21, 10 -1 22))', - {'hasM': False, 'hasZ': True, 'curvePaths': [[[1.0, 2.0, 10.0], - {'c': [[7.0, 2.2, 12.0], [5.0, 4.0, 11.0]]}, - {'c': [[13.0, 4.0, 14.0], [10.0, 0.1, 13.0]]} - ], - [ - [-11.0, -3.0, 20.0], - {'c': [[10.0, -1.0, 22.0], [5.0, 7.0, 21.0]]} - ]]}), - ( - 'MultiCurveM (CircularStringM (1 2 10, 5 4 11, 7 2.2 12, 10 0.1 13, 13 4 14),CircularStringM (-11 -3 20, 5 7 21, 10 -1 22))', - {'hasM': True, 'hasZ': False, 'curvePaths': [[[1.0, 2.0, 10.0], - {'c': [[7.0, 2.2, 12.0], [5.0, 4.0, 11.0]]}, - {'c': [[13.0, 4.0, 14.0], [10.0, 0.1, 13.0]]} - ], - [ - [-11.0, -3.0, 20.0], - {'c': [[10.0, -1.0, 22.0], [5.0, 7.0, 21.0]]} - ]]}), - ( - 'MultiCurveZM (CircularStringZM (1 2 10 20, 5 4 11 21, 7 2.2 12 22, 10 0.1 13 23, 13 4 14 24),CircularStringZM (-11 -3 20 31, 5 7 21 32, 10 -1 22 33))', - {'hasM': True, 'hasZ': True, 'curvePaths': [[[1.0, 2.0, 10.0, 20.0], - {'c': [[7.0, 2.2, 12.0, 22.0], [5.0, 4.0, 11.0, 21.0]]}, - {'c': [[13.0, 4.0, 14.0, 24.0], [10.0, 0.1, 13.0, 23.0]]} - ], - [ - [-11.0, -3.0, 20.0, 31.0], - {'c': [[10.0, -1.0, 22.0, 33.0], - [5.0, 7.0, 21.0, 32.0]]} - ]]}), - ('MultiLineString((1 2, 3 4, 3 6), (11 12, 13 16, 18 19, 21 3))', - {'hasM': False, 'hasZ': False, - 'paths': [[[1.0, 2.0], [3.0, 4.0], [3.0, 6.0]], - [[11.0, 12.0], [13.0, 16.0], [18.0, 19.0], [21.0, 3.0]]]}), - ('MultiLineStringZ((1 2 11, 3 4 12, 3 6 13), (11 12 21, 13 16 22, 18 19 23, 21 3 24))', - {'hasM': False, 'hasZ': True, - 'paths': [[[1.0, 2.0, 11.0], [3.0, 4.0, 12.0], [3.0, 6.0, 13.0]], - [[11.0, 12.0, 21.0], [13.0, 16.0, 22.0], [18.0, 19.0, 23.0], [21.0, 3.0, 24.0]]]}), - ('MultiLineStringM((1 2 11, 3 4 12, 3 6 13), (11 12 21, 13 16 22, 18 19 23, 21 3 24))', - {'hasM': True, 'hasZ': False, - 'paths': [[[1.0, 2.0, 11.0], [3.0, 4.0, 12.0], [3.0, 6.0, 13.0]], - [[11.0, 12.0, 21.0], [13.0, 16.0, 22.0], [18.0, 19.0, 23.0], [21.0, 3.0, 24.0]]]}), - ( - 'MultiLineStringZM((1 2 11 33, 3 4 12 34, 3 6 13 35), (11 12 21 31, 13 16 22 32, 18 19 23 33, 21 3 24 34))', - {'hasM': True, 'hasZ': True, - 'paths': [[[1.0, 2.0, 11.0, 33.0], [3.0, 4.0, 12.0, 34.0], [3.0, 6.0, 13.0, 35.0]], - [[11.0, 12.0, 21.0, 31.0], [13.0, 16.0, 22.0, 32.0], [18.0, 19.0, 23.0, 33.0], - [21.0, 3.0, 24.0, 34.0]]]}), - ('Polygon((1 2, 10 2, 10 12, 1 12, 1 2))', - {'hasM': False, 'hasZ': False, - 'rings': [[[1.0, 2.0], [1.0, 12.0], [10.0, 12.0], [10.0, 2.0], [1.0, 2.0]]]}), - ('Polygon((1 2, 10 2, 10 12, 1 12, 1 2),(5 6, 6 6, 5 7, 5 6))', - {'hasM': False, 'hasZ': False, - 'rings': [[[1.0, 2.0], [1.0, 12.0], [10.0, 12.0], [10.0, 2.0], [1.0, 2.0]], - [[5.0, 6.0], [6.0, 6.0], [5.0, 7.0], [5.0, 6.0]]]}), - ('PolygonZ((1 2 33, 10 2 33, 10 12 33, 1 12 33, 1 2 33))', - {'hasM': False, 'hasZ': True, - 'rings': [ - [[1.0, 2.0, 33.0], [1.0, 12.0, 33.0], [10.0, 12.0, 33.0], [10.0, 2.0, 33.0], [1.0, 2.0, 33.0]]]}), - ('PolygonM((1 2 44, 10 2 44, 10 12 44, 1 12 44, 1 2 44))', - {'hasM': True, 'hasZ': False, - 'rings': [ - [[1.0, 2.0, 44.0], [1.0, 12.0, 44.0], [10.0, 12.0, 44.0], [10.0, 2.0, 44.0], [1.0, 2.0, 44.0]]]}), - ('PolygonZM((1 2 33 44, 10 2 33 44, 10 12 33 45, 1 12 33 46, 1 2 33 44))', - {'hasM': True, 'hasZ': True, 'rings': [ - [[1.0, 2.0, 33.0, 44.0], [1.0, 12.0, 33.0, 46.0], [10.0, 12.0, 33.0, 45.0], [10.0, 2.0, 33.0, 44.0], - [1.0, 2.0, 33.0, 44.0]]]}), - ('CurvePolygon(CircularString(1 2, 10 2, 10 12, 1 12, 1 2))', - {'hasM': False, 'hasZ': False, - 'curveRings': [[[1.0, 2.0], {'c': [[10.0, 12.0], [1.0, 12.0]]}, {'c': [[1.0, 2.0], [10.0, 2.0]]}]]}), - ( - 'CurvePolygon(CircularString(1 2, 10 2, 10 12, 1 12, 1 2), CircularString(21 2, 20 2, 20 12, 21 12, 21 2))', - {'hasM': False, 'hasZ': False, - 'curveRings': [[[1.0, 2.0], {'c': [[10.0, 12.0], [1.0, 12.0]]}, {'c': [[1.0, 2.0], [10.0, 2.0]]}], - [[21.0, 2.0], {'c': [[20.0, 12.0], [21.0, 12.0]]}, {'c': [[21.0, 2.0], [20.0, 2.0]]}]]}), - - ( - 'CurvePolygon (CompoundCurve ((0 -23.43778, 0 -15.43778, 0 23.43778),CircularString (0 23.43778, -45 100, -90 23.43778),(-90 23.43778, -90 -23.43778),CircularString (-90 -23.43778, -45 -16.43778, 0 -23.43778)),CompoundCurve (CircularString (-30 0, -48 -12, -60 0, -48 -6, -30 0)))', - {'hasM': False, 'hasZ': False, - 'curveRings': [[[0.0, -23.43778], {'c': [[-90.0, -23.43778], [-45.0, -16.43778]]}, [-90.0, 23.43778], - {'c': [[0.0, 23.43778], [-45.0, 100.0]]}, [0.0, -15.43778], [0.0, -23.43778]], - [[-30.0, 0.0], {'c': [[-60.0, 0.0], [-48.0, -6.0]]}, - {'c': [[-30.0, 0.0], [-48.0, -12.0]]}]] - }), - - ('MultiPolygon(((1 2, 10 2, 10 12, 1 12, 1 2)),((20 10, 22 10, 20 13, 20 10)))', - {'hasM': False, 'hasZ': False, - 'rings': [[[1.0, 2.0], [1.0, 12.0], [10.0, 12.0], [10.0, 2.0], [1.0, 2.0]], - [[20.0, 10.0], [20.0, 13.0], [22.0, 10.0], [20.0, 10.0]]]}), - ('MultiPolygon(((1 2, 10 2, 10 12, 1 12, 1 2),(5 6, 6 6, 5 7, 5 6)),((20 10, 22 10, 20 13, 20 10)))', - {'hasM': False, 'hasZ': False, - 'rings': [[[1.0, 2.0], [1.0, 12.0], [10.0, 12.0], [10.0, 2.0], [1.0, 2.0]], + ( + "CompoundCurve ((-1 -5, 1 2))", + {"hasM": False, "hasZ": False, "paths": [[[-1.0, -5.0], [1.0, 2.0]]]}, + ), + ( + "CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.20, 10 0.1, 13 4),(13 4, 17 -6))", + { + "hasM": False, + "hasZ": False, + "curvePaths": [ + [ + [-1.0, -5.0], + [1.0, 2.0], + {"c": [[7.0, 2.2], [5.0, 4.0]]}, + {"c": [[13.0, 4.0], [10.0, 0.1]]}, + [17.0, -6.0], + ] + ], + }, + ), + ( + "CompoundCurveZ ((-1 -5 3, 1 2 4),CircularStringZ (1 2 4, 5 4 5, 7 2.20 6, 10 0.1 7, 13 4 8),(13 4 8, 17 -6 9))", + { + "hasM": False, + "hasZ": True, + "curvePaths": [ + [ + [-1.0, -5.0, 3.0], + [1.0, 2.0, 4.0], + {"c": [[7.0, 2.2, 6.0], [5.0, 4.0, 5.0]]}, + {"c": [[13.0, 4.0, 8.0], [10.0, 0.1, 7.0]]}, + [17.0, -6.0, 9.0], + ] + ], + }, + ), + ( + "CompoundCurveM ((-1 -5 3, 1 2 4),CircularStringM (1 2 4, 5 4 5, 7 2.20 6, 10 0.1 7, 13 4 8),(13 4 8, 17 -6 9))", + { + "hasM": True, + "hasZ": False, + "curvePaths": [ + [ + [-1.0, -5.0, 3.0], + [1.0, 2.0, 4.0], + {"c": [[7.0, 2.2, 6.0], [5.0, 4.0, 5.0]]}, + {"c": [[13.0, 4.0, 8.0], [10.0, 0.1, 7.0]]}, + [17.0, -6.0, 9.0], + ] + ], + }, + ), + ( + "CompoundCurveZM ((-1 -5 3 11, 1 2 4 12),CircularStringZM (1 2 4 12, 5 4 5 13, 7 2.20 6 14, 10 0.1 7 15, 13 4 8 16),(13 4 8 16, 17 -6 9 17))", + { + "hasM": True, + "hasZ": True, + "curvePaths": [ + [ + [-1.0, -5.0, 3.0, 11.0], + [1.0, 2.0, 4.0, 12.0], + {"c": [[7.0, 2.2, 6.0, 14.0], [5.0, 4.0, 5.0, 13.0]]}, + {"c": [[13.0, 4.0, 8.0, 16.0], [10.0, 0.1, 7.0, 15.0]]}, + [17.0, -6.0, 9.0, 17.0], + ] + ], + }, + ), + ( + "MultiCurve (CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),CircularString (-11 -3, 5 7, 10 -1))", + { + "hasM": False, + "hasZ": False, + "curvePaths": [ + [ + [1.0, 2.0], + {"c": [[7.0, 2.2], [5.0, 4.0]]}, + {"c": [[13.0, 4.0], [10.0, 0.1]]}, + ], + [[-11.0, -3.0], {"c": [[10.0, -1.0], [5.0, 7.0]]}], + ], + }, + ), + ( + "MultiCurveZ (CircularStringZ (1 2 10, 5 4 11, 7 2.2 12, 10 0.1 13, 13 4 14),CircularStringZ (-11 -3 20, 5 7 21, 10 -1 22))", + { + "hasM": False, + "hasZ": True, + "curvePaths": [ + [ + [1.0, 2.0, 10.0], + {"c": [[7.0, 2.2, 12.0], [5.0, 4.0, 11.0]]}, + {"c": [[13.0, 4.0, 14.0], [10.0, 0.1, 13.0]]}, + ], + [ + [-11.0, -3.0, 20.0], + {"c": [[10.0, -1.0, 22.0], [5.0, 7.0, 21.0]]}, + ], + ], + }, + ), + ( + "MultiCurveM (CircularStringM (1 2 10, 5 4 11, 7 2.2 12, 10 0.1 13, 13 4 14),CircularStringM (-11 -3 20, 5 7 21, 10 -1 22))", + { + "hasM": True, + "hasZ": False, + "curvePaths": [ + [ + [1.0, 2.0, 10.0], + {"c": [[7.0, 2.2, 12.0], [5.0, 4.0, 11.0]]}, + {"c": [[13.0, 4.0, 14.0], [10.0, 0.1, 13.0]]}, + ], + [ + [-11.0, -3.0, 20.0], + {"c": [[10.0, -1.0, 22.0], [5.0, 7.0, 21.0]]}, + ], + ], + }, + ), + ( + "MultiCurveZM (CircularStringZM (1 2 10 20, 5 4 11 21, 7 2.2 12 22, 10 0.1 13 23, 13 4 14 24),CircularStringZM (-11 -3 20 31, 5 7 21 32, 10 -1 22 33))", + { + "hasM": True, + "hasZ": True, + "curvePaths": [ + [ + [1.0, 2.0, 10.0, 20.0], + {"c": [[7.0, 2.2, 12.0, 22.0], [5.0, 4.0, 11.0, 21.0]]}, + {"c": [[13.0, 4.0, 14.0, 24.0], [10.0, 0.1, 13.0, 23.0]]}, + ], + [ + [-11.0, -3.0, 20.0, 31.0], + {"c": [[10.0, -1.0, 22.0, 33.0], [5.0, 7.0, 21.0, 32.0]]}, + ], + ], + }, + ), + ( + "MultiLineString((1 2, 3 4, 3 6), (11 12, 13 16, 18 19, 21 3))", + { + "hasM": False, + "hasZ": False, + "paths": [ + [[1.0, 2.0], [3.0, 4.0], [3.0, 6.0]], + [[11.0, 12.0], [13.0, 16.0], [18.0, 19.0], [21.0, 3.0]], + ], + }, + ), + ( + "MultiLineStringZ((1 2 11, 3 4 12, 3 6 13), (11 12 21, 13 16 22, 18 19 23, 21 3 24))", + { + "hasM": False, + "hasZ": True, + "paths": [ + [[1.0, 2.0, 11.0], [3.0, 4.0, 12.0], [3.0, 6.0, 13.0]], + [ + [11.0, 12.0, 21.0], + [13.0, 16.0, 22.0], + [18.0, 19.0, 23.0], + [21.0, 3.0, 24.0], + ], + ], + }, + ), + ( + "MultiLineStringM((1 2 11, 3 4 12, 3 6 13), (11 12 21, 13 16 22, 18 19 23, 21 3 24))", + { + "hasM": True, + "hasZ": False, + "paths": [ + [[1.0, 2.0, 11.0], [3.0, 4.0, 12.0], [3.0, 6.0, 13.0]], + [ + [11.0, 12.0, 21.0], + [13.0, 16.0, 22.0], + [18.0, 19.0, 23.0], + [21.0, 3.0, 24.0], + ], + ], + }, + ), + ( + "MultiLineStringZM((1 2 11 33, 3 4 12 34, 3 6 13 35), (11 12 21 31, 13 16 22 32, 18 19 23 33, 21 3 24 34))", + { + "hasM": True, + "hasZ": True, + "paths": [ + [ + [1.0, 2.0, 11.0, 33.0], + [3.0, 4.0, 12.0, 34.0], + [3.0, 6.0, 13.0, 35.0], + ], + [ + [11.0, 12.0, 21.0, 31.0], + [13.0, 16.0, 22.0, 32.0], + [18.0, 19.0, 23.0, 33.0], + [21.0, 3.0, 24.0, 34.0], + ], + ], + }, + ), + ( + "Polygon((1 2, 10 2, 10 12, 1 12, 1 2))", + { + "hasM": False, + "hasZ": False, + "rings": [ + [[1.0, 2.0], [1.0, 12.0], [10.0, 12.0], [10.0, 2.0], [1.0, 2.0]] + ], + }, + ), + ( + "Polygon((1 2, 10 2, 10 12, 1 12, 1 2),(5 6, 6 6, 5 7, 5 6))", + { + "hasM": False, + "hasZ": False, + "rings": [ + [ + [1.0, 2.0], + [1.0, 12.0], + [10.0, 12.0], + [10.0, 2.0], + [1.0, 2.0], + ], [[5.0, 6.0], [6.0, 6.0], [5.0, 7.0], [5.0, 6.0]], - [[20.0, 10.0], [20.0, 13.0], [22.0, 10.0], [20.0, 10.0]]]}), - + ], + }, + ), ( - 'MultiSurface(CurvePolygon(CircularString(1 2, 10 2, 10 12, 1 12, 1 2)),CurvePolygon(CircularString(1 2, 10 2, 10 12, 1 12, 1 2), CircularString(21 2, 20 2, 20 12, 21 12, 21 2)))', - {'hasM': False, 'hasZ': False, - 'curveRings': [ - [[1.0, 2.0], {'c': [[10.0, 12.0], [1.0, 12.0]]}, {'c': [[1.0, 2.0], [10.0, 2.0]]}], - [[1.0, 2.0], {'c': [[10.0, 12.0], [1.0, 12.0]]}, {'c': [[1.0, 2.0], [10.0, 2.0]]}], - [[21.0, 2.0], {'c': [[20.0, 12.0], [21.0, 12.0]]}, {'c': [[21.0, 2.0], [20.0, 2.0]]}]]}) + "PolygonZ((1 2 33, 10 2 33, 10 12 33, 1 12 33, 1 2 33))", + { + "hasM": False, + "hasZ": True, + "rings": [ + [ + [1.0, 2.0, 33.0], + [1.0, 12.0, 33.0], + [10.0, 12.0, 33.0], + [10.0, 2.0, 33.0], + [1.0, 2.0, 33.0], + ] + ], + }, + ), + ( + "PolygonM((1 2 44, 10 2 44, 10 12 44, 1 12 44, 1 2 44))", + { + "hasM": True, + "hasZ": False, + "rings": [ + [ + [1.0, 2.0, 44.0], + [1.0, 12.0, 44.0], + [10.0, 12.0, 44.0], + [10.0, 2.0, 44.0], + [1.0, 2.0, 44.0], + ] + ], + }, + ), + ( + "PolygonZM((1 2 33 44, 10 2 33 44, 10 12 33 45, 1 12 33 46, 1 2 33 44))", + { + "hasM": True, + "hasZ": True, + "rings": [ + [ + [1.0, 2.0, 33.0, 44.0], + [1.0, 12.0, 33.0, 46.0], + [10.0, 12.0, 33.0, 45.0], + [10.0, 2.0, 33.0, 44.0], + [1.0, 2.0, 33.0, 44.0], + ] + ], + }, + ), + ( + "CurvePolygon(CircularString(1 2, 10 2, 10 12, 1 12, 1 2))", + { + "hasM": False, + "hasZ": False, + "curveRings": [ + [ + [1.0, 2.0], + {"c": [[10.0, 12.0], [1.0, 12.0]]}, + {"c": [[1.0, 2.0], [10.0, 2.0]]}, + ] + ], + }, + ), + ( + "CurvePolygon(CircularString(1 2, 10 2, 10 12, 1 12, 1 2), CircularString(21 2, 20 2, 20 12, 21 12, 21 2))", + { + "hasM": False, + "hasZ": False, + "curveRings": [ + [ + [1.0, 2.0], + {"c": [[10.0, 12.0], [1.0, 12.0]]}, + {"c": [[1.0, 2.0], [10.0, 2.0]]}, + ], + [ + [21.0, 2.0], + {"c": [[20.0, 12.0], [21.0, 12.0]]}, + {"c": [[21.0, 2.0], [20.0, 2.0]]}, + ], + ], + }, + ), + ( + "CurvePolygon (CompoundCurve ((0 -23.43778, 0 -15.43778, 0 23.43778),CircularString (0 23.43778, -45 100, -90 23.43778),(-90 23.43778, -90 -23.43778),CircularString (-90 -23.43778, -45 -16.43778, 0 -23.43778)),CompoundCurve (CircularString (-30 0, -48 -12, -60 0, -48 -6, -30 0)))", + { + "hasM": False, + "hasZ": False, + "curveRings": [ + [ + [0.0, -23.43778], + {"c": [[-90.0, -23.43778], [-45.0, -16.43778]]}, + [-90.0, 23.43778], + {"c": [[0.0, 23.43778], [-45.0, 100.0]]}, + [0.0, -15.43778], + [0.0, -23.43778], + ], + [ + [-30.0, 0.0], + {"c": [[-60.0, 0.0], [-48.0, -6.0]]}, + {"c": [[-30.0, 0.0], [-48.0, -12.0]]}, + ], + ], + }, + ), + ( + "MultiPolygon(((1 2, 10 2, 10 12, 1 12, 1 2)),((20 10, 22 10, 20 13, 20 10)))", + { + "hasM": False, + "hasZ": False, + "rings": [ + [ + [1.0, 2.0], + [1.0, 12.0], + [10.0, 12.0], + [10.0, 2.0], + [1.0, 2.0], + ], + [[20.0, 10.0], [20.0, 13.0], [22.0, 10.0], [20.0, 10.0]], + ], + }, + ), + ( + "MultiPolygon(((1 2, 10 2, 10 12, 1 12, 1 2),(5 6, 6 6, 5 7, 5 6)),((20 10, 22 10, 20 13, 20 10)))", + { + "hasM": False, + "hasZ": False, + "rings": [ + [ + [1.0, 2.0], + [1.0, 12.0], + [10.0, 12.0], + [10.0, 2.0], + [1.0, 2.0], + ], + [[5.0, 6.0], [6.0, 6.0], [5.0, 7.0], [5.0, 6.0]], + [[20.0, 10.0], [20.0, 13.0], [22.0, 10.0], [20.0, 10.0]], + ], + }, + ), + ( + "MultiSurface(CurvePolygon(CircularString(1 2, 10 2, 10 12, 1 12, 1 2)),CurvePolygon(CircularString(1 2, 10 2, 10 12, 1 12, 1 2), CircularString(21 2, 20 2, 20 12, 21 12, 21 2)))", + { + "hasM": False, + "hasZ": False, + "curveRings": [ + [ + [1.0, 2.0], + {"c": [[10.0, 12.0], [1.0, 12.0]]}, + {"c": [[1.0, 2.0], [10.0, 2.0]]}, + ], + [ + [1.0, 2.0], + {"c": [[10.0, 12.0], [1.0, 12.0]]}, + {"c": [[1.0, 2.0], [10.0, 2.0]]}, + ], + [ + [21.0, 2.0], + {"c": [[20.0, 12.0], [21.0, 12.0]]}, + {"c": [[21.0, 2.0], [20.0, 2.0]]}, + ], + ], + }, + ), ] context = QgsArcGisRestContext() for test_wkt, expected in tests: input = QgsGeometry.fromWkt(test_wkt) json = QgsArcGisRestUtils.geometryToJson(input, context) - self.assertEqual(json, expected, f'Mismatch for {test_wkt}') + self.assertEqual(json, expected, f"Mismatch for {test_wkt}") def test_crs_conversion(self): - self.assertEqual(QgsArcGisRestUtils.crsToJson(QgsCoordinateReferenceSystem()), {}) - self.assertEqual(QgsArcGisRestUtils.crsToJson(QgsCoordinateReferenceSystem('EPSG:4326')), {'wkid': '4326'}) - self.assertEqual(QgsArcGisRestUtils.crsToJson(QgsCoordinateReferenceSystem('EPSG:3857')), {'wkid': '3857'}) - self.assertEqual(QgsArcGisRestUtils.crsToJson(QgsCoordinateReferenceSystem('ESRI:53079')), {'wkid': '53079'}) + self.assertEqual( + QgsArcGisRestUtils.crsToJson(QgsCoordinateReferenceSystem()), {} + ) + self.assertEqual( + QgsArcGisRestUtils.crsToJson(QgsCoordinateReferenceSystem("EPSG:4326")), + {"wkid": "4326"}, + ) + self.assertEqual( + QgsArcGisRestUtils.crsToJson(QgsCoordinateReferenceSystem("EPSG:3857")), + {"wkid": "3857"}, + ) + self.assertEqual( + QgsArcGisRestUtils.crsToJson(QgsCoordinateReferenceSystem("ESRI:53079")), + {"wkid": "53079"}, + ) # should be represented via wkt - self.assertTrue(QgsArcGisRestUtils.crsToJson(QgsCoordinateReferenceSystem('IGNF:WGS84'))['wkt']) + self.assertTrue( + QgsArcGisRestUtils.crsToJson(QgsCoordinateReferenceSystem("IGNF:WGS84"))[ + "wkt" + ] + ) def test_geometry_with_crs(self): - geom = QgsGeometry.fromWkt('Point( 1 2)') + geom = QgsGeometry.fromWkt("Point( 1 2)") context = QgsArcGisRestContext() - self.assertEqual(QgsArcGisRestUtils.geometryToJson(geom, context, QgsCoordinateReferenceSystem('EPSG:4326')), - {'spatialReference': {'wkid': '4326'}, 'x': 1.0, 'y': 2.0}) - self.assertEqual(QgsArcGisRestUtils.geometryToJson(geom, context, QgsCoordinateReferenceSystem('EPSG:3857')), - {'spatialReference': {'wkid': '3857'}, 'x': 1.0, 'y': 2.0}) + self.assertEqual( + QgsArcGisRestUtils.geometryToJson( + geom, context, QgsCoordinateReferenceSystem("EPSG:4326") + ), + {"spatialReference": {"wkid": "4326"}, "x": 1.0, "y": 2.0}, + ) + self.assertEqual( + QgsArcGisRestUtils.geometryToJson( + geom, context, QgsCoordinateReferenceSystem("EPSG:3857") + ), + {"spatialReference": {"wkid": "3857"}, "x": 1.0, "y": 2.0}, + ) def test_feature_to_json(self): test_fields = QgsFields() attributes = [] - test_fields.append(QgsField('a_string_field', QVariant.String)) - attributes.append('my string value') + test_fields.append(QgsField("a_string_field", QVariant.String)) + attributes.append("my string value") - test_fields.append(QgsField('a_int_field', QVariant.Int)) + test_fields.append(QgsField("a_int_field", QVariant.Int)) attributes.append(5) - test_fields.append(QgsField('a_double_field', QVariant.Double)) + test_fields.append(QgsField("a_double_field", QVariant.Double)) attributes.append(5.5) - test_fields.append(QgsField('a_boolean_field', QVariant.Bool)) + test_fields.append(QgsField("a_boolean_field", QVariant.Bool)) attributes.append(True) - test_fields.append(QgsField('a_datetime_field', QVariant.DateTime)) - attributes.append(QDateTime(QDate(2022, 3, 4), QTime(12, 13, 14), Qt.TimeSpec.UTC)) + test_fields.append(QgsField("a_datetime_field", QVariant.DateTime)) + attributes.append( + QDateTime(QDate(2022, 3, 4), QTime(12, 13, 14), Qt.TimeSpec.UTC) + ) - test_fields.append(QgsField('a_date_field', QVariant.Date)) + test_fields.append(QgsField("a_date_field", QVariant.Date)) attributes.append(QDate(2022, 3, 4)) - test_fields.append(QgsField('a_null_value', QVariant.String)) + test_fields.append(QgsField("a_null_value", QVariant.String)) attributes.append(NULL) test_feature = QgsFeature(test_fields) test_feature.setAttributes(attributes) - test_feature.setGeometry(QgsGeometry.fromWkt('Point(1 2)')) + test_feature.setGeometry(QgsGeometry.fromWkt("Point(1 2)")) context = QgsArcGisRestContext() context.setTimeZone(QTimeZone.utc()) res = QgsArcGisRestUtils.featureToJson(test_feature, context) - self.assertEqual(res, {'attributes': {'a_boolean_field': True, - 'a_datetime_field': 1646395994000, - 'a_date_field': 1646352000000, - 'a_double_field': 5.5, - 'a_int_field': 5, - 'a_string_field': 'my%20string%20value', - 'a_null_value': None}, - 'geometry': {'x': 1.0, 'y': 2.0}}) + self.assertEqual( + res, + { + "attributes": { + "a_boolean_field": True, + "a_datetime_field": 1646395994000, + "a_date_field": 1646352000000, + "a_double_field": 5.5, + "a_int_field": 5, + "a_string_field": "my%20string%20value", + "a_null_value": None, + }, + "geometry": {"x": 1.0, "y": 2.0}, + }, + ) # without geometry - res = QgsArcGisRestUtils.featureToJson(test_feature, context, flags=QgsArcGisRestUtils.FeatureToJsonFlags(QgsArcGisRestUtils.FeatureToJsonFlag.IncludeNonObjectIdAttributes)) - self.assertEqual(res, {'attributes': {'a_boolean_field': True, - 'a_datetime_field': 1646395994000, - 'a_date_field': 1646352000000, - 'a_double_field': 5.5, - 'a_int_field': 5, - 'a_string_field': 'my%20string%20value', - 'a_null_value': None}}) + res = QgsArcGisRestUtils.featureToJson( + test_feature, + context, + flags=QgsArcGisRestUtils.FeatureToJsonFlags( + QgsArcGisRestUtils.FeatureToJsonFlag.IncludeNonObjectIdAttributes + ), + ) + self.assertEqual( + res, + { + "attributes": { + "a_boolean_field": True, + "a_datetime_field": 1646395994000, + "a_date_field": 1646352000000, + "a_double_field": 5.5, + "a_int_field": 5, + "a_string_field": "my%20string%20value", + "a_null_value": None, + } + }, + ) # without attributes - context.setObjectIdFieldName('a_int_field') - res = QgsArcGisRestUtils.featureToJson(test_feature, context, flags=QgsArcGisRestUtils.FeatureToJsonFlags(QgsArcGisRestUtils.FeatureToJsonFlag.IncludeGeometry)) - self.assertEqual(res, {'attributes': { - 'a_int_field': 5}, - 'geometry': {'x': 1.0, 'y': 2.0}}) + context.setObjectIdFieldName("a_int_field") + res = QgsArcGisRestUtils.featureToJson( + test_feature, + context, + flags=QgsArcGisRestUtils.FeatureToJsonFlags( + QgsArcGisRestUtils.FeatureToJsonFlag.IncludeGeometry + ), + ) + self.assertEqual( + res, {"attributes": {"a_int_field": 5}, "geometry": {"x": 1.0, "y": 2.0}} + ) # with special characters - attributes[0] = 'aaa" \' , . - ; : ä ö ü è é à ? + & \\ /' + attributes[0] = "aaa\" ' , . - ; : ä ö ü è é à ? + & \\ /" test_feature.setAttributes(attributes) - res = QgsArcGisRestUtils.featureToJson(test_feature, context, flags=QgsArcGisRestUtils.FeatureToJsonFlags(QgsArcGisRestUtils.FeatureToJsonFlag.IncludeNonObjectIdAttributes)) - self.assertEqual(res, {'attributes': {'a_boolean_field': True, - 'a_datetime_field': 1646395994000, - 'a_date_field': 1646352000000, - 'a_double_field': 5.5, - 'a_int_field': 5, - 'a_string_field': """aaa%5C%22%20'%20%2C%20.%20-%20%3B%20%3A%20%C3%A4%20%C3%B6%20%C3%BC%20%C3%A8%20%C3%A9%20%C3%A0%20%3F%20%2B%20%26%20%5C%5C%20%2F""", - 'a_null_value': None}}) + res = QgsArcGisRestUtils.featureToJson( + test_feature, + context, + flags=QgsArcGisRestUtils.FeatureToJsonFlags( + QgsArcGisRestUtils.FeatureToJsonFlag.IncludeNonObjectIdAttributes + ), + ) + self.assertEqual( + res, + { + "attributes": { + "a_boolean_field": True, + "a_datetime_field": 1646395994000, + "a_date_field": 1646352000000, + "a_double_field": 5.5, + "a_int_field": 5, + "a_string_field": """aaa%5C%22%20'%20%2C%20.%20-%20%3B%20%3A%20%C3%A4%20%C3%B6%20%C3%BC%20%C3%A8%20%C3%A9%20%C3%A0%20%3F%20%2B%20%26%20%5C%5C%20%2F""", + "a_null_value": None, + } + }, + ) def test_field_to_json(self): - field = QgsField('my name', QVariant.LongLong) - field.setAlias('my alias') - self.assertEqual(QgsArcGisRestUtils.fieldDefinitionToJson(field), {'alias': 'my alias', 'editable': True, 'name': 'my name', 'nullable': True, 'type': 'esriFieldTypeInteger'}) - field = QgsField('my name', QVariant.Int) - self.assertEqual(QgsArcGisRestUtils.fieldDefinitionToJson(field), {'editable': True, 'name': 'my name', 'nullable': True, 'type': 'esriFieldTypeSmallInteger'}) - field = QgsField('my name', QVariant.Double) - self.assertEqual(QgsArcGisRestUtils.fieldDefinitionToJson(field), {'editable': True, 'name': 'my name', 'nullable': True, 'type': 'esriFieldTypeDouble'}) - field = QgsField('my name', QVariant.String) - self.assertEqual(QgsArcGisRestUtils.fieldDefinitionToJson(field), {'editable': True, 'name': 'my name', 'nullable': True, 'type': 'esriFieldTypeString'}) - field = QgsField('my name', QVariant.DateTime) - self.assertEqual(QgsArcGisRestUtils.fieldDefinitionToJson(field), {'editable': True, 'name': 'my name', 'nullable': True, 'type': 'esriFieldTypeDate'}) - field = QgsField('my name', QVariant.ByteArray) - self.assertEqual(QgsArcGisRestUtils.fieldDefinitionToJson(field), {'editable': True, 'name': 'my name', 'nullable': True, 'type': 'esriFieldTypeBlob'}) + field = QgsField("my name", QVariant.LongLong) + field.setAlias("my alias") + self.assertEqual( + QgsArcGisRestUtils.fieldDefinitionToJson(field), + { + "alias": "my alias", + "editable": True, + "name": "my name", + "nullable": True, + "type": "esriFieldTypeInteger", + }, + ) + field = QgsField("my name", QVariant.Int) + self.assertEqual( + QgsArcGisRestUtils.fieldDefinitionToJson(field), + { + "editable": True, + "name": "my name", + "nullable": True, + "type": "esriFieldTypeSmallInteger", + }, + ) + field = QgsField("my name", QVariant.Double) + self.assertEqual( + QgsArcGisRestUtils.fieldDefinitionToJson(field), + { + "editable": True, + "name": "my name", + "nullable": True, + "type": "esriFieldTypeDouble", + }, + ) + field = QgsField("my name", QVariant.String) + self.assertEqual( + QgsArcGisRestUtils.fieldDefinitionToJson(field), + { + "editable": True, + "name": "my name", + "nullable": True, + "type": "esriFieldTypeString", + }, + ) + field = QgsField("my name", QVariant.DateTime) + self.assertEqual( + QgsArcGisRestUtils.fieldDefinitionToJson(field), + { + "editable": True, + "name": "my name", + "nullable": True, + "type": "esriFieldTypeDate", + }, + ) + field = QgsField("my name", QVariant.ByteArray) + self.assertEqual( + QgsArcGisRestUtils.fieldDefinitionToJson(field), + { + "editable": True, + "name": "my name", + "nullable": True, + "type": "esriFieldTypeBlob", + }, + ) # unsupported type - field = QgsField('my name', QVariant.Time) - self.assertEqual(QgsArcGisRestUtils.fieldDefinitionToJson(field), {'editable': True, 'name': 'my name', 'nullable': True, 'type': 'esriFieldTypeString'}) + field = QgsField("my name", QVariant.Time) + self.assertEqual( + QgsArcGisRestUtils.fieldDefinitionToJson(field), + { + "editable": True, + "name": "my name", + "nullable": True, + "type": "esriFieldTypeString", + }, + ) # not nullable - field = QgsField('my name', QVariant.Int) + field = QgsField("my name", QVariant.Int) field_constraints = field.constraints() - field_constraints.setConstraint(QgsFieldConstraints.Constraint.ConstraintNotNull) + field_constraints.setConstraint( + QgsFieldConstraints.Constraint.ConstraintNotNull + ) field.setConstraints(field_constraints) - self.assertEqual(QgsArcGisRestUtils.fieldDefinitionToJson(field), {'editable': True, 'name': 'my name', 'nullable': False, 'type': 'esriFieldTypeSmallInteger'}) - - -if __name__ == '__main__': + self.assertEqual( + QgsArcGisRestUtils.fieldDefinitionToJson(field), + { + "editable": True, + "name": "my name", + "nullable": False, + "type": "esriFieldTypeSmallInteger", + }, + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsarrowsymbollayer.py b/tests/src/python/test_qgsarrowsymbollayer.py index eafe33557c47..9ae8d6770a5b 100644 --- a/tests/src/python/test_qgsarrowsymbollayer.py +++ b/tests/src/python/test_qgsarrowsymbollayer.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Hugo Mercier' -__date__ = 'March 2016' -__copyright__ = '(C) 2016, Hugo Mercier' +__author__ = "Hugo Mercier" +__date__ = "March 2016" +__copyright__ = "(C) 2016, Hugo Mercier" import os @@ -56,12 +56,12 @@ class TestQgsArrowSymbolLayer(QgisTestCase): def setUp(self): self.iface = get_iface() - lines_shp = os.path.join(TEST_DATA_DIR, 'lines.shp') - self.lines_layer = QgsVectorLayer(lines_shp, 'Lines', 'ogr') + lines_shp = os.path.join(TEST_DATA_DIR, "lines.shp") + self.lines_layer = QgsVectorLayer(lines_shp, "Lines", "ogr") QgsProject.instance().addMapLayer(self.lines_layer) # Create style - sym2 = QgsLineSymbol.createSimple({'color': '#fdbf6f'}) + sym2 = QgsLineSymbol.createSimple({"color": "#fdbf6f"}) self.lines_layer.setRenderer(QgsSingleSymbolRenderer(sym2)) self.mapsettings = self.iface.mapCanvas().mapSettings() @@ -75,14 +75,27 @@ def tearDown(self): def test_1(self): sym = self.lines_layer.renderer().symbol() - sym_layer = QgsArrowSymbolLayer.create({'head_length': '6.5', 'head_thickness': '6.5'}) + sym_layer = QgsArrowSymbolLayer.create( + {"head_length": "6.5", "head_thickness": "6.5"} + ) dd = QgsProperty.fromExpression("(@geometry_point_num % 4) * 2") sym_layer.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyArrowWidth, dd) dd2 = QgsProperty.fromExpression("(@geometry_point_num % 4) * 2") - sym_layer.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyArrowHeadLength, dd2) + sym_layer.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyArrowHeadLength, dd2 + ) dd3 = QgsProperty.fromExpression("(@geometry_point_num % 4) * 2") - sym_layer.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyArrowHeadThickness, dd3) - fill_sym = QgsFillSymbol.createSimple({'color': '#8bcfff', 'outline_color': '#000000', 'outline_style': 'solid', 'outline_width': '1'}) + sym_layer.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyArrowHeadThickness, dd3 + ) + fill_sym = QgsFillSymbol.createSimple( + { + "color": "#8bcfff", + "outline_color": "#000000", + "outline_style": "solid", + "outline_width": "1", + } + ) sym_layer.setSubSymbol(fill_sym) sym.changeSymbolLayer(0, sym_layer) @@ -91,17 +104,29 @@ def test_1(self): self.assertTrue( self.render_map_settings_check( - 'arrowsymbollayer_1', - 'arrowsymbollayer_1', - self.mapsettings + "arrowsymbollayer_1", "arrowsymbollayer_1", self.mapsettings ) ) def test_2(self): sym = self.lines_layer.renderer().symbol() # double headed - sym_layer = QgsArrowSymbolLayer.create({'arrow_width': '5', 'head_length': '4', 'head_thickness': '6', 'head_type': '2'}) - fill_sym = QgsFillSymbol.createSimple({'color': '#8bcfff', 'outline_color': '#000000', 'outline_style': 'solid', 'outline_width': '1'}) + sym_layer = QgsArrowSymbolLayer.create( + { + "arrow_width": "5", + "head_length": "4", + "head_thickness": "6", + "head_type": "2", + } + ) + fill_sym = QgsFillSymbol.createSimple( + { + "color": "#8bcfff", + "outline_color": "#000000", + "outline_style": "solid", + "outline_width": "1", + } + ) sym_layer.setSubSymbol(fill_sym) sym.changeSymbolLayer(0, sym_layer) @@ -110,17 +135,31 @@ def test_2(self): self.assertTrue( self.render_map_settings_check( - 'arrowsymbollayer_2', - 'arrowsymbollayer_2', - self.mapsettings + "arrowsymbollayer_2", "arrowsymbollayer_2", self.mapsettings ) ) def test_3(self): sym = self.lines_layer.renderer().symbol() # double headed - sym_layer = QgsArrowSymbolLayer.create({'arrow_width': '7', 'head_length': '6', 'head_thickness': '8', 'head_type': '0', 'arrow_type': '1', 'is_curved': '0'}) - fill_sym = QgsFillSymbol.createSimple({'color': '#8bcfff', 'outline_color': '#000000', 'outline_style': 'solid', 'outline_width': '1'}) + sym_layer = QgsArrowSymbolLayer.create( + { + "arrow_width": "7", + "head_length": "6", + "head_thickness": "8", + "head_type": "0", + "arrow_type": "1", + "is_curved": "0", + } + ) + fill_sym = QgsFillSymbol.createSimple( + { + "color": "#8bcfff", + "outline_color": "#000000", + "outline_style": "solid", + "outline_width": "1", + } + ) sym_layer.setSubSymbol(fill_sym) sym.changeSymbolLayer(0, sym_layer) @@ -131,19 +170,32 @@ def test_3(self): ms.setExtent(QgsRectangle(-101, 35, -99, 37)) self.assertTrue( self.render_map_settings_check( - 'arrowsymbollayer_3', - 'arrowsymbollayer_3', - ms + "arrowsymbollayer_3", "arrowsymbollayer_3", ms ) ) def test_unrepeated(self): sym = self.lines_layer.renderer().symbol() # double headed - sym_layer = QgsArrowSymbolLayer.create({'arrow_width': '7', 'head_length': '6', 'head_thickness': '8', 'head_type': '0', 'arrow_type': '0'}) + sym_layer = QgsArrowSymbolLayer.create( + { + "arrow_width": "7", + "head_length": "6", + "head_thickness": "8", + "head_type": "0", + "arrow_type": "0", + } + ) # no repetition sym_layer.setIsRepeated(False) - fill_sym = QgsFillSymbol.createSimple({'color': '#8bcfff', 'outline_color': '#000000', 'outline_style': 'solid', 'outline_width': '1'}) + fill_sym = QgsFillSymbol.createSimple( + { + "color": "#8bcfff", + "outline_color": "#000000", + "outline_style": "solid", + "outline_width": "1", + } + ) sym_layer.setSubSymbol(fill_sym) sym.changeSymbolLayer(0, sym_layer) @@ -155,9 +207,7 @@ def test_unrepeated(self): self.assertTrue( self.render_map_settings_check( - 'arrowsymbollayer_4', - 'arrowsymbollayer_4', - ms + "arrowsymbollayer_4", "arrowsymbollayer_4", ms ) ) @@ -177,33 +227,61 @@ def testRingNumberVariable(self): # test test geometry_ring_num variable s3 = QgsFillSymbol() s3.deleteSymbolLayer(0) - s3.appendSymbolLayer( - QgsArrowSymbolLayer()) + s3.appendSymbolLayer(QgsArrowSymbolLayer()) s3.symbolLayer(0).setIsCurved(False) - s3.symbolLayer(0).subSymbol()[0].setDataDefinedProperty(QgsSymbolLayer.Property.PropertyFillColor, - QgsProperty.fromExpression('case when @geometry_ring_num=0 then \'green\' when @geometry_ring_num=1 then \'blue\' when @geometry_ring_num=2 then \'red\' end')) + s3.symbolLayer(0).subSymbol()[0].setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyFillColor, + QgsProperty.fromExpression( + "case when @geometry_ring_num=0 then 'green' when @geometry_ring_num=1 then 'blue' when @geometry_ring_num=2 then 'red' end" + ), + ) - g = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))') + g = QgsGeometry.fromWkt( + "Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))" + ) rendered_image = self.renderGeometry(s3, g) self.assertTrue( - self.image_check('arrow_ring_num', - 'arrow_ring_num', - rendered_image, - control_path_prefix="symbol_arrow") + self.image_check( + "arrow_ring_num", + "arrow_ring_num", + rendered_image, + control_path_prefix="symbol_arrow", + ) ) def testOpacityWithDataDefinedColor(self): - line_shp = os.path.join(TEST_DATA_DIR, 'lines.shp') - line_layer = QgsVectorLayer(line_shp, 'Lines', 'ogr') + line_shp = os.path.join(TEST_DATA_DIR, "lines.shp") + line_layer = QgsVectorLayer(line_shp, "Lines", "ogr") self.assertTrue(line_layer.isValid()) sym = QgsLineSymbol() - sym_layer = QgsArrowSymbolLayer.create({'arrow_width': '7', 'head_length': '6', 'head_thickness': '8', 'head_type': '0', 'arrow_type': '0', 'is_repeated': '0', 'is_curved': '0'}) - fill_sym = QgsFillSymbol.createSimple({'color': '#8bcfff', 'outline_color': '#000000', 'outline_style': 'solid', 'outline_width': '1'}) - fill_sym.symbolLayer(0).setDataDefinedProperty(QgsSymbolLayer.Property.PropertyFillColor, QgsProperty.fromExpression( - "if(Name='Arterial', 'red', 'green')")) - fill_sym.symbolLayer(0).setDataDefinedProperty(QgsSymbolLayer.Property.PropertyStrokeColor, QgsProperty.fromExpression( - "if(Name='Arterial', 'magenta', 'blue')")) + sym_layer = QgsArrowSymbolLayer.create( + { + "arrow_width": "7", + "head_length": "6", + "head_thickness": "8", + "head_type": "0", + "arrow_type": "0", + "is_repeated": "0", + "is_curved": "0", + } + ) + fill_sym = QgsFillSymbol.createSimple( + { + "color": "#8bcfff", + "outline_color": "#000000", + "outline_style": "solid", + "outline_width": "1", + } + ) + fill_sym.symbolLayer(0).setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyFillColor, + QgsProperty.fromExpression("if(Name='Arterial', 'red', 'green')"), + ) + fill_sym.symbolLayer(0).setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyStrokeColor, + QgsProperty.fromExpression("if(Name='Arterial', 'magenta', 'blue')"), + ) sym_layer.setSubSymbol(fill_sym) sym.changeSymbolLayer(0, sym_layer) @@ -222,30 +300,54 @@ def testOpacityWithDataDefinedColor(self): self.assertTrue( self.render_map_settings_check( - 'arrow_opacityddcolor', - 'arrow_opacityddcolor', + "arrow_opacityddcolor", + "arrow_opacityddcolor", ms, - control_path_prefix='symbol_arrow' + control_path_prefix="symbol_arrow", ) ) def testDataDefinedOpacity(self): - line_shp = os.path.join(TEST_DATA_DIR, 'lines.shp') - line_layer = QgsVectorLayer(line_shp, 'Lines', 'ogr') + line_shp = os.path.join(TEST_DATA_DIR, "lines.shp") + line_layer = QgsVectorLayer(line_shp, "Lines", "ogr") self.assertTrue(line_layer.isValid()) sym = QgsLineSymbol() - sym_layer = QgsArrowSymbolLayer.create({'arrow_width': '7', 'head_length': '6', 'head_thickness': '8', 'head_type': '0', 'arrow_type': '0', 'is_repeated': '0', 'is_curved': '0'}) - fill_sym = QgsFillSymbol.createSimple({'color': '#8bcfff', 'outline_color': '#000000', 'outline_style': 'solid', 'outline_width': '1'}) - fill_sym.symbolLayer(0).setDataDefinedProperty(QgsSymbolLayer.Property.PropertyFillColor, QgsProperty.fromExpression( - "if(Name='Arterial', 'red', 'green')")) - fill_sym.symbolLayer(0).setDataDefinedProperty(QgsSymbolLayer.Property.PropertyStrokeColor, QgsProperty.fromExpression( - "if(Name='Arterial', 'magenta', 'blue')")) + sym_layer = QgsArrowSymbolLayer.create( + { + "arrow_width": "7", + "head_length": "6", + "head_thickness": "8", + "head_type": "0", + "arrow_type": "0", + "is_repeated": "0", + "is_curved": "0", + } + ) + fill_sym = QgsFillSymbol.createSimple( + { + "color": "#8bcfff", + "outline_color": "#000000", + "outline_style": "solid", + "outline_width": "1", + } + ) + fill_sym.symbolLayer(0).setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyFillColor, + QgsProperty.fromExpression("if(Name='Arterial', 'red', 'green')"), + ) + fill_sym.symbolLayer(0).setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyStrokeColor, + QgsProperty.fromExpression("if(Name='Arterial', 'magenta', 'blue')"), + ) sym_layer.setSubSymbol(fill_sym) sym.changeSymbolLayer(0, sym_layer) - sym.setDataDefinedProperty(QgsSymbol.Property.PropertyOpacity, QgsProperty.fromExpression("if(\"Value\" = 1, 25, 50)")) + sym.setDataDefinedProperty( + QgsSymbol.Property.PropertyOpacity, + QgsProperty.fromExpression('if("Value" = 1, 25, 50)'), + ) line_layer.setRenderer(QgsSingleSymbolRenderer(sym)) @@ -257,10 +359,10 @@ def testDataDefinedOpacity(self): self.assertTrue( self.render_map_settings_check( - 'arrow_ddopacity', - 'arrow_ddopacity', + "arrow_ddopacity", + "arrow_ddopacity", ms, - control_path_prefix='symbol_arrow' + control_path_prefix="symbol_arrow", ) ) @@ -297,5 +399,5 @@ def renderGeometry(self, symbol, geom): return image -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsattributeeditoraction.py b/tests/src/python/test_qgsattributeeditoraction.py index 13eb220b47ec..4459368ec44e 100644 --- a/tests/src/python/test_qgsattributeeditoraction.py +++ b/tests/src/python/test_qgsattributeeditoraction.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '16/08/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "16/08/2021" +__copyright__ = "Copyright 2021, The QGIS Project" from qgis.PyQt.QtCore import QUuid from qgis.core import ( @@ -32,17 +33,43 @@ class TestQgsActionWidgetWrapper(QgisTestCase): @classmethod def setUpClass(cls): super().setUpClass() - cls.layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=flddate:datetime", - "test_layer", "memory") + cls.layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer&field=flddate:datetime", + "test_layer", + "memory", + ) QgsProject.instance().addMapLayers([cls.layer]) cls.action_id1 = QUuid.createUuid() cls.action_id2 = QUuid.createUuid() cls.action_id3 = QUuid.createUuid() - cls.action1 = QgsAction(cls.action_id1, QgsAction.ActionType.GenericPython, 'Test Action 1 Desc', 'i=1', '', False, 'Test Action 1 Short Title') - cls.action2 = QgsAction(cls.action_id2, QgsAction.ActionType.GenericPython, 'Test Action 2 Desc', 'i=2', QGISAPP.appIconPath(), False, 'Test Action 2 Short Title') - cls.action3 = QgsAction(cls.action_id3, QgsAction.ActionType.GenericPython, 'Test Action 3 Desc', 'i=3', '', False) + cls.action1 = QgsAction( + cls.action_id1, + QgsAction.ActionType.GenericPython, + "Test Action 1 Desc", + "i=1", + "", + False, + "Test Action 1 Short Title", + ) + cls.action2 = QgsAction( + cls.action_id2, + QgsAction.ActionType.GenericPython, + "Test Action 2 Desc", + "i=2", + QGISAPP.appIconPath(), + False, + "Test Action 2 Short Title", + ) + cls.action3 = QgsAction( + cls.action_id3, + QgsAction.ActionType.GenericPython, + "Test Action 3 Desc", + "i=3", + "", + False, + ) cls.layer.actions().addAction(cls.action1) cls.layer.actions().addAction(cls.action2) cls.layer.actions().addAction(cls.action3) @@ -55,7 +82,7 @@ def tearDownClass(cls): def testEditorActionCtor(self): - parent = QgsAttributeEditorContainer('container', None) + parent = QgsAttributeEditorContainer("container", None) editor_action = QgsAttributeEditorAction(self.action1, parent) self.assertEqual(QUuid(editor_action.action(self.layer).id()), self.action_id1) self.assertEqual(editor_action.action(self.layer).id(), self.action1.id()) @@ -67,12 +94,12 @@ def testEditorActionCtor(self): def testSetAction(self): - parent = QgsAttributeEditorContainer('container', None) + parent = QgsAttributeEditorContainer("container", None) editor_action = QgsAttributeEditorAction(self.action1, parent) editor_action.setAction(self.action2) self.assertEqual(QUuid(editor_action.action(self.layer).id()), self.action_id2) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsattributeform.py b/tests/src/python/test_qgsattributeform.py index 1c4216b7e3bf..2b5dffc89f5f 100644 --- a/tests/src/python/test_qgsattributeform.py +++ b/tests/src/python/test_qgsattributeform.py @@ -9,9 +9,10 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '2019-06-06' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "2019-06-06" +__copyright__ = "Copyright 2019, The QGIS Project" from qgis.PyQt.QtCore import QVariant from qgis.core import ( @@ -45,8 +46,7 @@ def setUpClass(cls): @classmethod def createLayerWithOnePoint(cls, field_type): - layer = QgsVectorLayer(f"Point?field=fld:{field_type}", - "vl", "memory") + layer = QgsVectorLayer(f"Point?field=fld:{field_type}", "vl", "memory") pr = layer.dataProvider() f = QgsFeature() assert pr.addFeatures([f]) @@ -65,22 +65,25 @@ def createFormWithDuplicateWidget(cls, vl, field_type, widget_type): vl.setEditFormConfig(config) vl.setEditorWidgetSetup(0, QgsEditorWidgetSetup(widget_type, {})) form = QgsAttributeForm(vl, next(vl.getFeatures())) - assert (form.editable()) + assert form.editable() return form @classmethod def get_widgets_for_field(cls, vl): """Get compatible widget names""" - return [k for k, v in QgsGui.editorWidgetRegistry().factories().items() if v.supportsField(vl, 0)] + return [ + k + for k, v in QgsGui.editorWidgetRegistry().factories().items() + if v.supportsField(vl, 0) + ] @classmethod def checkForm(cls, field_type, value): - """Creates a vector layer and an associated form with two identical widgets for the same field and test it with NULL and after setting a value - """ + """Creates a vector layer and an associated form with two identical widgets for the same field and test it with NULL and after setting a value""" vl = cls.createLayerWithOnePoint(field_type) - assert (vl.startEditing()) + assert vl.startEditing() for widget_type in cls.get_widgets_for_field(vl): form = cls.createFormWithDuplicateWidget(vl, field_type, widget_type) vl.changeAttributeValue(1, 0, value) @@ -97,21 +100,21 @@ def test_duplicated_widgets(self): """ field_types = { - 'integer': 123, - 'double': 123.45, - 'string': 'lorem ipsum', - 'date': '2019-01-01', - 'time': '12:12:12', - 'datetime': '2019-01-01', - 'int2': 123, - 'int4': 123, - 'int8': 123, - 'numeric': 123.45, - 'decimal': 123.45, - 'real': 123.45, - 'double precision': 123.45, - 'text': 'lorem ipsum', - 'bool': True, + "integer": 123, + "double": 123.45, + "string": "lorem ipsum", + "date": "2019-01-01", + "time": "12:12:12", + "datetime": "2019-01-01", + "int2": 123, + "int4": 123, + "int8": 123, + "numeric": 123.45, + "decimal": 123.45, + "real": 123.45, + "double precision": 123.45, + "text": "lorem ipsum", + "bool": True, # 'binary' } @@ -123,7 +126,7 @@ def test_duplicated_widgets_multiedit(self): Test multiedit with duplicated widgets """ - field_type = 'integer' + field_type = "integer" vl = self.createLayerWithOnePoint(field_type) # add another point @@ -137,7 +140,7 @@ def test_duplicated_widgets_multiedit(self): assert vl.changeAttributeValue(1, 0, 123) assert vl.changeAttributeValue(2, 0, 456) - widget_type = 'TextEdit' + widget_type = "TextEdit" form = self.createFormWithDuplicateWidget(vl, field_type, widget_type) fids = list() @@ -148,7 +151,7 @@ def test_duplicated_widgets_multiedit(self): form.setMultiEditFeatureIds(fids) for children in form.findChildren(QgsFilterLineEdit): - if children.objectName() == 'fld': + if children.objectName() == "fld": # As the values are mixed, the widget values should be empty assert not children.text() @@ -163,22 +166,22 @@ def test_on_update(self): layer = QgsVectorLayer("Point?field=age:int", "vl", "memory") # set default value for numbers to [1, {age}], it will depend on the field age and should update - field = QgsField('numbers', QVariant.List, 'array') - field.setEditorWidgetSetup(QgsEditorWidgetSetup('List', {})) + field = QgsField("numbers", QVariant.List, "array") + field.setEditorWidgetSetup(QgsEditorWidgetSetup("List", {})) layer.dataProvider().addAttributes([field]) layer.updateFields() - layer.setDefaultValueDefinition(1, QgsDefaultValue('array(1, age)', True)) - layer.setEditorWidgetSetup(1, QgsEditorWidgetSetup('List', {})) + layer.setDefaultValueDefinition(1, QgsDefaultValue("array(1, age)", True)) + layer.setEditorWidgetSetup(1, QgsEditorWidgetSetup("List", {})) layer.startEditing() form = QgsAttributeForm(layer) feature = QgsFeature(layer.fields()) form.setFeature(feature) form.setMode(QgsAttributeEditorContext.Mode.AddFeatureMode) - form.changeAttribute('numbers', [12]) - form.changeAttribute('age', 1) - self.assertEqual(form.currentFormFeature()['numbers'], [1, 1]) - form.changeAttribute('age', 7) - self.assertEqual(form.currentFormFeature()['numbers'], [1, 7]) + form.changeAttribute("numbers", [12]) + form.changeAttribute("age", 1) + self.assertEqual(form.currentFormFeature()["numbers"], [1, 1]) + form.changeAttribute("age", 7) + self.assertEqual(form.currentFormFeature()["numbers"], [1, 7]) def test_default_value_always_updated(self): """Test that default values are not updated on every edit operation @@ -186,16 +189,18 @@ def test_default_value_always_updated(self): layer = QgsVectorLayer("Point?field=age:int&field=number:int", "vl", "memory") - layer.setEditorWidgetSetup(0, QgsEditorWidgetSetup('Range', {})) + layer.setEditorWidgetSetup(0, QgsEditorWidgetSetup("Range", {})) # set default value for numbers to attribute("age"), it will depend on the field age and should not update - layer.setDefaultValueDefinition(1, QgsDefaultValue("attribute(@feature, 'age')", False)) - layer.setEditorWidgetSetup(1, QgsEditorWidgetSetup('Range', {})) + layer.setDefaultValueDefinition( + 1, QgsDefaultValue("attribute(@feature, 'age')", False) + ) + layer.setEditorWidgetSetup(1, QgsEditorWidgetSetup("Range", {})) layer.startEditing() feature = QgsFeature(layer.fields()) - feature.setAttribute('age', 15) + feature.setAttribute("age", 15) form = QgsAttributeForm(layer) form.setMode(QgsAttributeEditorContext.Mode.AddFeatureMode) @@ -203,15 +208,15 @@ def test_default_value_always_updated(self): QGISAPP.processEvents() - self.assertEqual(form.currentFormFeature()['age'], 15) + self.assertEqual(form.currentFormFeature()["age"], 15) # not yet update it on init - self.assertEqual(form.currentFormFeature()['number'], None) + self.assertEqual(form.currentFormFeature()["number"], None) # return - form.changeAttribute('number', 12) - form.changeAttribute('age', 1) - self.assertEqual(form.currentFormFeature()['number'], 12) - form.changeAttribute('age', 7) - self.assertEqual(form.currentFormFeature()['number'], 12) + form.changeAttribute("number", 12) + form.changeAttribute("age", 1) + self.assertEqual(form.currentFormFeature()["number"], 12) + form.changeAttribute("age", 7) + self.assertEqual(form.currentFormFeature()["number"], 12) def test_default_value_always_updated_live_edit(self): """ @@ -239,78 +244,94 @@ def test_default_value_always_updated_live_edit(self): - update pos and random because of volatile functions """ - layer = QgsVectorLayer("Point?field=age:int&field=year:int&field=birthday:int&field=pos:int&field=random:int", "vl", "memory") + layer = QgsVectorLayer( + "Point?field=age:int&field=year:int&field=birthday:int&field=pos:int&field=random:int", + "vl", + "memory", + ) # add another field numbers - field = QgsField('numbers', QVariant.List, subType=QVariant.Int) - field.setEditorWidgetSetup(QgsEditorWidgetSetup('List', {})) + field = QgsField("numbers", QVariant.List, subType=QVariant.Int) + field.setEditorWidgetSetup(QgsEditorWidgetSetup("List", {})) layer.dataProvider().addAttributes([field]) layer.updateFields() apply_on_update = True - layer.setEditorWidgetSetup(0, QgsEditorWidgetSetup('Range', {})) - layer.setEditorWidgetSetup(1, QgsEditorWidgetSetup('Range', {})) + layer.setEditorWidgetSetup(0, QgsEditorWidgetSetup("Range", {})) + layer.setEditorWidgetSetup(1, QgsEditorWidgetSetup("Range", {})) # set default value for birthday (2), it will depend on the field age and year - layer.setDefaultValueDefinition(2, QgsDefaultValue('year - age', apply_on_update)) - layer.setEditorWidgetSetup(2, QgsEditorWidgetSetup('Range', {})) + layer.setDefaultValueDefinition( + 2, QgsDefaultValue("year - age", apply_on_update) + ) + layer.setEditorWidgetSetup(2, QgsEditorWidgetSetup("Range", {})) # set default value for pos (3), it will depend on the field age and it contains a volatile function and should update after save (on singleeditmode) - layer.setDefaultValueDefinition(3, QgsDefaultValue('pos + age + day_of_week( now() ) - day_of_week( now() )', apply_on_update)) - layer.setEditorWidgetSetup(3, QgsEditorWidgetSetup('Range', {})) + layer.setDefaultValueDefinition( + 3, + QgsDefaultValue( + "pos + age + day_of_week( now() ) - day_of_week( now() )", + apply_on_update, + ), + ) + layer.setEditorWidgetSetup(3, QgsEditorWidgetSetup("Range", {})) # set default value for random (4), it contains a volatile function and should update after save (on singleeditmode) - layer.setDefaultValueDefinition(4, QgsDefaultValue('random + random + rand(0,0)', apply_on_update)) - layer.setEditorWidgetSetup(4, QgsEditorWidgetSetup('Range', {})) + layer.setDefaultValueDefinition( + 4, QgsDefaultValue("random + random + rand(0,0)", apply_on_update) + ) + layer.setEditorWidgetSetup(4, QgsEditorWidgetSetup("Range", {})) # set default value for numbers (5), it will depend on the field age - layer.setDefaultValueDefinition(5, QgsDefaultValue('array(1, age)', apply_on_update)) - layer.setEditorWidgetSetup(5, QgsEditorWidgetSetup('List', {})) + layer.setDefaultValueDefinition( + 5, QgsDefaultValue("array(1, age)", apply_on_update) + ) + layer.setEditorWidgetSetup(5, QgsEditorWidgetSetup("List", {})) layer.startEditing() form = QgsAttributeForm(layer) feature = QgsFeature(layer.fields()) - feature.setAttribute('age', 15) - feature.setAttribute('year', 2023) - feature.setAttribute('random', 100) - feature.setAttribute('birthday', 1900) - feature.setAttribute('pos', 100) - feature.setAttribute('numbers', [12]) + feature.setAttribute("age", 15) + feature.setAttribute("year", 2023) + feature.setAttribute("random", 100) + feature.setAttribute("birthday", 1900) + feature.setAttribute("pos", 100) + feature.setAttribute("numbers", [12]) form.setFeature(feature) form.setMode(QgsAttributeEditorContext.Mode.AddFeatureMode) QGISAPP.processEvents() # editing age - form.changeAttribute('age', 10) - self.assertEqual(form.currentFormFeature()['age'], 10) + form.changeAttribute("age", 10) + self.assertEqual(form.currentFormFeature()["age"], 10) # don't update year - self.assertEqual(form.currentFormFeature()['year'], 2023) + self.assertEqual(form.currentFormFeature()["year"], 2023) # update birthday because of age - self.assertEqual(form.currentFormFeature()['birthday'], 2013) + self.assertEqual(form.currentFormFeature()["birthday"], 2013) # update pos because of age - self.assertEqual(form.currentFormFeature()['pos'], 110) + self.assertEqual(form.currentFormFeature()["pos"], 110) # don't update random (yet) - self.assertEqual(form.currentFormFeature()['random'], 100) + self.assertEqual(form.currentFormFeature()["random"], 100) # update number because of age - self.assertEqual(form.currentFormFeature()['numbers'], [1, 10]) + self.assertEqual(form.currentFormFeature()["numbers"], [1, 10]) # editing year - form.changeAttribute('year', 2024) - self.assertEqual(form.currentFormFeature()['year'], 2024) + form.changeAttribute("year", 2024) + self.assertEqual(form.currentFormFeature()["year"], 2024) # don't update age - self.assertEqual(form.currentFormFeature()['age'], 10) + self.assertEqual(form.currentFormFeature()["age"], 10) # update birthday because of year - self.assertEqual(form.currentFormFeature()['birthday'], 2014) + self.assertEqual(form.currentFormFeature()["birthday"], 2014) # don't update pos (yet) - self.assertEqual(form.currentFormFeature()['pos'], 110) + self.assertEqual(form.currentFormFeature()["pos"], 110) # don't update random (yet) - self.assertEqual(form.currentFormFeature()['random'], 100) + self.assertEqual(form.currentFormFeature()["random"], 100) # don't update numbers - self.assertEqual(form.currentFormFeature()['numbers'], [1, 10]) + self.assertEqual(form.currentFormFeature()["numbers"], [1, 10]) # save form - this leads not to any updates (because it's a newly created features) form.save() @@ -319,17 +340,17 @@ def test_default_value_always_updated_live_edit(self): feature = next(layer.getFeatures()) # don't updated age - self.assertEqual(feature.attribute('age'), 10) + self.assertEqual(feature.attribute("age"), 10) # don't updated year - self.assertEqual(feature.attribute('year'), 2024) + self.assertEqual(feature.attribute("year"), 2024) # don't updated birthday - self.assertEqual(feature.attribute('birthday'), 2014) + self.assertEqual(feature.attribute("birthday"), 2014) # don't updated pos (because newly created feature) - self.assertEqual(feature.attribute('pos'), 110) + self.assertEqual(feature.attribute("pos"), 110) # don't updated random (because newly created feature) - self.assertEqual(feature.attribute('random'), 100) + self.assertEqual(feature.attribute("random"), 100) # don't updated numbers - self.assertEqual(feature.attribute('numbers'), [1, 10]) + self.assertEqual(feature.attribute("numbers"), [1, 10]) # changing mode of form form.setMode(QgsAttributeEditorContext.Mode.SingleEditMode) @@ -338,45 +359,45 @@ def test_default_value_always_updated_live_edit(self): # check if nothing updated because of loading it: # don't update year - self.assertEqual(form.currentFormFeature()['year'], 2024) + self.assertEqual(form.currentFormFeature()["year"], 2024) # don't update age - self.assertEqual(form.currentFormFeature()['age'], 10) + self.assertEqual(form.currentFormFeature()["age"], 10) # don't update birthday - self.assertEqual(form.currentFormFeature()['birthday'], 2014) + self.assertEqual(form.currentFormFeature()["birthday"], 2014) # don't update pos (because newly created feature) - self.assertEqual(form.currentFormFeature()['pos'], 110) + self.assertEqual(form.currentFormFeature()["pos"], 110) # don't update random (because newly created feature) - self.assertEqual(form.currentFormFeature()['random'], 100) + self.assertEqual(form.currentFormFeature()["random"], 100) # don't update numbers - self.assertEqual(form.currentFormFeature()['numbers'], [1, 10]) + self.assertEqual(form.currentFormFeature()["numbers"], [1, 10]) # editing birthday - form.changeAttribute('birthday', 2200) - self.assertEqual(form.currentFormFeature()['birthday'], 2200) + form.changeAttribute("birthday", 2200) + self.assertEqual(form.currentFormFeature()["birthday"], 2200) # don't update age - self.assertEqual(form.currentFormFeature()['age'], 10) + self.assertEqual(form.currentFormFeature()["age"], 10) # don't update year - self.assertEqual(form.currentFormFeature()['year'], 2024) + self.assertEqual(form.currentFormFeature()["year"], 2024) # don't update pos - self.assertEqual(form.currentFormFeature()['pos'], 110) + self.assertEqual(form.currentFormFeature()["pos"], 110) # don't update random - self.assertEqual(form.currentFormFeature()['random'], 100) + self.assertEqual(form.currentFormFeature()["random"], 100) # editing age - form.changeAttribute('age', 41) - self.assertEqual(form.currentFormFeature()['age'], 41) + form.changeAttribute("age", 41) + self.assertEqual(form.currentFormFeature()["age"], 41) # don't update year - self.assertEqual(form.currentFormFeature()['year'], 2024) + self.assertEqual(form.currentFormFeature()["year"], 2024) # update birthday because of age - self.assertEqual(form.currentFormFeature()['birthday'], 1983) + self.assertEqual(form.currentFormFeature()["birthday"], 1983) # update pos because of age - self.assertEqual(form.currentFormFeature()['pos'], 151) + self.assertEqual(form.currentFormFeature()["pos"], 151) # don't update random (yet) - self.assertEqual(form.currentFormFeature()['random'], 100) + self.assertEqual(form.currentFormFeature()["random"], 100) # update number because of age - self.assertEqual(form.currentFormFeature()['numbers'], [1, 41]) + self.assertEqual(form.currentFormFeature()["numbers"], [1, 41]) # save form - this leads to updates, because existing feature form.save() @@ -385,18 +406,18 @@ def test_default_value_always_updated_live_edit(self): feature = next(layer.getFeatures()) # don't updated age - self.assertEqual(feature.attribute('age'), 41) + self.assertEqual(feature.attribute("age"), 41) # don't updated year - self.assertEqual(feature.attribute('year'), 2024) + self.assertEqual(feature.attribute("year"), 2024) # don't updated birthday - self.assertEqual(feature.attribute('birthday'), 1983) + self.assertEqual(feature.attribute("birthday"), 1983) # again updated pos - self.assertEqual(feature.attribute('pos'), 192) + self.assertEqual(feature.attribute("pos"), 192) # updated random - self.assertEqual(feature.attribute('random'), 200) + self.assertEqual(feature.attribute("random"), 200) # don't updated numbers - self.assertEqual(feature.attribute('numbers'), [1, 41]) + self.assertEqual(feature.attribute("numbers"), [1, 41]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsattributeformeditorwidget.py b/tests/src/python/test_qgsattributeformeditorwidget.py index 57dc09093c76..413803369ac5 100644 --- a/tests/src/python/test_qgsattributeformeditorwidget.py +++ b/tests/src/python/test_qgsattributeformeditorwidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2016-05' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2016-05" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, QTime, QVariant, QTemporaryDir from qgis.PyQt.QtWidgets import QDateTimeEdit, QWidget @@ -31,7 +32,7 @@ class PyQgsAttributeFormEditorWidget(QgisTestCase): def testCurrentFilterExpression(self): - """ Test creating an expression using the widget""" + """Test creating an expression using the widget""" layer = QgsVectorLayer("Point?field=fldint:integer", "test", "memory") parent = QWidget() @@ -43,7 +44,7 @@ def testCurrentFilterExpression(self): af.setMode(QgsAttributeFormWidget.Mode.SearchMode) # test that filter combines both current value in search widget wrapper and flags from search tool button - w.lineEdit().setText('5.5') + w.lineEdit().setText("5.5") sb = af.findChild(QWidget, "SearchWidgetToolButton") sb.setActiveFlags(QgsSearchWidgetWrapper.FilterFlag.EqualTo) self.assertEqual(af.currentFilterExpression(), '"fldint"=5.5') @@ -51,9 +52,11 @@ def testCurrentFilterExpression(self): self.assertEqual(af.currentFilterExpression(), '"fldint"<>5.5') def testSetActive(self): - """ Test setting the search as active - should set active flags to match search widget wrapper's defaults """ + """Test setting the search as active - should set active flags to match search widget wrapper's defaults""" - layer = QgsVectorLayer("Point?field=fldtext:string&field=fldint:integer", "test", "memory") + layer = QgsVectorLayer( + "Point?field=fldtext:string&field=fldint:integer", "test", "memory" + ) parent = QWidget() w = QgsDefaultSearchWidgetWrapper(layer, 0, parent) setup = QgsGui.editorWidgetRegistry().findBest(layer, "fldint") @@ -81,11 +84,13 @@ def testSetActive(self): self.assertTrue(sb.activeFlags() & QgsSearchWidgetWrapper.FilterFlag.EqualTo) def testBetweenFilter(self): - """ Test creating a between type filter """ - layer = QgsVectorLayer("Point?field=fldtext:string&field=fldint:integer", "test", "memory") + """Test creating a between type filter""" + layer = QgsVectorLayer( + "Point?field=fldtext:string&field=fldint:integer", "test", "memory" + ) form = QgsAttributeForm(layer) wrapper = QgsGui.editorWidgetRegistry().create(layer, 0, None, form) - af = QgsAttributeFormEditorWidget(wrapper, 'DateTime', None) + af = QgsAttributeFormEditorWidget(wrapper, "DateTime", None) af.createSearchWidgetWrappers() af.setMode(QgsAttributeFormWidget.Mode.SearchMode) @@ -96,99 +101,105 @@ def testBetweenFilter(self): sb = af.findChild(QWidget, "SearchWidgetToolButton") sb.setActiveFlags(QgsSearchWidgetWrapper.FilterFlag.Between) - self.assertEqual(af.currentFilterExpression(), '"fldtext">=\'2013-05-06\' AND "fldtext"<=\'2013-05-16\'') + self.assertEqual( + af.currentFilterExpression(), + "\"fldtext\">='2013-05-06' AND \"fldtext\"<='2013-05-16'", + ) sb.setActiveFlags(QgsSearchWidgetWrapper.FilterFlag.IsNotBetween) - self.assertEqual(af.currentFilterExpression(), '"fldtext"<\'2013-05-06\' OR "fldtext">\'2013-05-16\'') + self.assertEqual( + af.currentFilterExpression(), + "\"fldtext\"<'2013-05-06' OR \"fldtext\">'2013-05-16'", + ) def verifyJSONTypeFindBest(self, field_type, layer): # Create a JSON field - field = QgsField('json', field_type, 'JSON', 0, 0, 'comment', QVariant.String) + field = QgsField("json", field_type, "JSON", 0, 0, "comment", QVariant.String) self.assertTrue(layer.startEditing()) self.assertTrue(layer.addAttribute(field)) self.assertTrue(layer.commitChanges()) # No records, so should default to key/value registry = QgsGui.editorWidgetRegistry() - setup = registry.findBest(layer, 'json') - self.assertEqual(setup.type(), 'KeyValue') + setup = registry.findBest(layer, "json") + self.assertEqual(setup.type(), "KeyValue") # Add a key/value record layer.startEditing() feature = QgsFeature(layer.fields()) - feature.setAttribute('json', '{"key": "value"}') + feature.setAttribute("json", '{"key": "value"}') self.assertTrue(layer.addFeature(feature)) - setup = registry.findBest(layer, 'json') - self.assertEqual(setup.type(), 'KeyValue') + setup = registry.findBest(layer, "json") + self.assertEqual(setup.type(), "KeyValue") layer.rollBack() # Add an array record self.assertTrue(layer.startEditing()) feature = QgsFeature(layer.fields()) - feature.setAttribute('json', '["value", "another_value"]') + feature.setAttribute("json", '["value", "another_value"]') self.assertTrue(layer.addFeature(feature)) - setup = registry.findBest(layer, 'json') - self.assertEqual(setup.type(), 'List') + setup = registry.findBest(layer, "json") + self.assertEqual(setup.type(), "List") self.assertTrue(layer.rollBack()) # Add a null record followed by a map record followed by a list record self.assertTrue(layer.startEditing()) feature = QgsFeature(layer.fields()) - feature.setAttribute('json', None) + feature.setAttribute("json", None) self.assertTrue(layer.addFeature(feature)) feature = QgsFeature(layer.fields()) - feature.setAttribute('json', '{"key": "value"}') + feature.setAttribute("json", '{"key": "value"}') self.assertTrue(layer.addFeature(feature)) feature = QgsFeature(layer.fields()) - feature.setAttribute('json', '["value", "another_value"]') + feature.setAttribute("json", '["value", "another_value"]') self.assertTrue(layer.addFeature(feature)) - setup = registry.findBest(layer, 'json') - self.assertEqual(setup.type(), 'KeyValue') + setup = registry.findBest(layer, "json") + self.assertEqual(setup.type(), "KeyValue") self.assertTrue(layer.rollBack()) # Add a null record followed by A list record followed by a map record self.assertTrue(layer.startEditing()) feature = QgsFeature(layer.fields()) - feature.setAttribute('json', None) + feature.setAttribute("json", None) self.assertTrue(layer.addFeature(feature)) feature = QgsFeature(layer.fields()) - feature.setAttribute('json', '["value", "another_value"]') + feature.setAttribute("json", '["value", "another_value"]') self.assertTrue(layer.addFeature(feature)) feature = QgsFeature(layer.fields()) - feature.setAttribute('json', '{"key": "value"}') + feature.setAttribute("json", '{"key": "value"}') self.assertTrue(layer.addFeature(feature)) - setup = registry.findBest(layer, 'json') - self.assertEqual(setup.type(), 'List') + setup = registry.findBest(layer, "json") + self.assertEqual(setup.type(), "List") self.assertTrue(layer.rollBack()) # Add a string record which is neither a list or a map self.assertTrue(layer.startEditing()) feature = QgsFeature(layer.fields()) - feature.setAttribute('json', 'not a list or map') + feature.setAttribute("json", "not a list or map") self.assertTrue(layer.addFeature(feature)) - setup = registry.findBest(layer, 'json') - self.assertNotEqual(setup.type(), 'List') - self.assertNotEqual(setup.type(), 'KeyValue') + setup = registry.findBest(layer, "json") + self.assertNotEqual(setup.type(), "List") + self.assertNotEqual(setup.type(), "KeyValue") self.assertTrue(layer.rollBack()) # Add 21 records with a JSON field, only the last is NOT NULL self.assertTrue(layer.startEditing()) for i in range(20): feature = QgsFeature(layer.fields()) - feature.setAttribute('json', None) + feature.setAttribute("json", None) self.assertTrue(layer.addFeature(feature)) feature = QgsFeature(layer.fields()) - feature.setAttribute('json', '["value", "another_value"]') + feature.setAttribute("json", '["value", "another_value"]') self.assertTrue(layer.addFeature(feature)) - setup = registry.findBest(layer, 'json') - self.assertNotEqual(setup.type(), 'List') + setup = registry.findBest(layer, "json") + self.assertNotEqual(setup.type(), "List") # KeyValue is the default, - self.assertEqual(setup.type(), 'KeyValue') + self.assertEqual(setup.type(), "KeyValue") self.assertTrue(layer.rollBack()) # Cleanup removing the field self.assertTrue(layer.startEditing()) - field_idx = layer.fields().indexOf('json') + field_idx = layer.fields().indexOf("json") self.assertTrue(layer.deleteAttribute(field_idx)) self.assertTrue(layer.commitChanges()) @@ -202,16 +213,16 @@ def testJSONGeoPackageLayer(self): temp_dir = QTemporaryDir() uri = temp_dir.filePath("test.gpkg") # Create a new geopackage layer using ogr - driver = ogr.GetDriverByName('GPKG') + driver = ogr.GetDriverByName("GPKG") ds = driver.CreateDataSource(uri) srs = osr.SpatialReference() srs.ImportFromEPSG(4326) - layer = ds.CreateLayer('test', srs, ogr.wkbPoint) + layer = ds.CreateLayer("test", srs, ogr.wkbPoint) del layer del ds - layer = QgsVectorLayer(uri, 'test', 'ogr') + layer = QgsVectorLayer(uri, "test", "ogr") self.verifyJSONTypeFindBest(QVariant.Map, layer) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsattributetableconfig.py b/tests/src/python/test_qgsattributetableconfig.py index 688795344213..f20d8279fb23 100644 --- a/tests/src/python/test_qgsattributetableconfig.py +++ b/tests/src/python/test_qgsattributetableconfig.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '07/06/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "07/06/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.core import QgsAttributeTableConfig, QgsVectorLayer @@ -20,17 +21,18 @@ class TestQgsAttributeTableConfig(QgisTestCase): def testLayerConfig(self): - """ test retrieving attribute table config from a layer """ + """test retrieving attribute table config from a layer""" # make a layer - point_layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "pointlayer", "memory") + point_layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "pointlayer", "memory" + ) # make sure attribute table config is initially populated config = point_layer.attributeTableConfig() self.assertFalse(config.isEmpty()) - self.assertEqual(config.columns()[0].name, 'fldtxt') - self.assertEqual(config.columns()[1].name, 'fldint') + self.assertEqual(config.columns()[0].name, "fldtxt") + self.assertEqual(config.columns()[1].name, "fldint") # try replacing it config.setColumns([config.columns()[1], config.columns()[0]]) @@ -39,16 +41,16 @@ def testLayerConfig(self): # and make sure changes were applied config = point_layer.attributeTableConfig() self.assertFalse(config.isEmpty()) - self.assertEqual(config.columns()[0].name, 'fldint') - self.assertEqual(config.columns()[1].name, 'fldtxt') + self.assertEqual(config.columns()[0].name, "fldint") + self.assertEqual(config.columns()[1].name, "fldtxt") def testIsEmpty(self): - """ test isEmpty method """ + """test isEmpty method""" config = QgsAttributeTableConfig() self.assertTrue(config.isEmpty()) c = QgsAttributeTableConfig.ColumnConfig() - c.name = 'test' + c.name = "test" config.setColumns([c]) self.assertFalse(config.isEmpty()) @@ -68,36 +70,36 @@ def testSize(self): self.assertEqual(len(config), 2) def testSetColumns(self): - """ test setting columns """ + """test setting columns""" config = QgsAttributeTableConfig() self.assertEqual(config.columns(), []) c1 = QgsAttributeTableConfig.ColumnConfig() - c1.name = 'test' + c1.name = "test" c1.hidden = False c1.width = 9 c2 = QgsAttributeTableConfig.ColumnConfig() - c2.name = 'test2' + c2.name = "test2" c2.hidden = True c2.width = 11 config.setColumns([c1, c2]) result = config.columns() - self.assertEqual(result[0].name, 'test') - self.assertEqual(result[1].name, 'test2') + self.assertEqual(result[0].name, "test") + self.assertEqual(result[1].name, "test2") self.assertEqual(result[0].hidden, False) self.assertEqual(result[1].hidden, True) self.assertEqual(result[0].width, 9) self.assertEqual(result[1].width, 11) def testColumnHidden(self): - """ test hiding columns """ + """test hiding columns""" config = QgsAttributeTableConfig() c1 = QgsAttributeTableConfig.ColumnConfig() - c1.name = 'test' + c1.name = "test" c1.hidden = False c2 = QgsAttributeTableConfig.ColumnConfig() - c2.name = 'test2' + c2.name = "test2" c2.hidden = False config.setColumns([c1, c2]) @@ -132,14 +134,14 @@ def testColumnHidden(self): self.assertTrue(config.columnHidden(1)) def testColumnWidth(self): - """ test setting column widths """ + """test setting column widths""" config = QgsAttributeTableConfig() c1 = QgsAttributeTableConfig.ColumnConfig() - c1.name = 'test' + c1.name = "test" c1.width = -1 c2 = QgsAttributeTableConfig.ColumnConfig() - c2.name = 'test2' + c2.name = "test2" c2.width = 27 config.setColumns([c1, c2]) @@ -174,15 +176,15 @@ def testColumnWidth(self): self.assertEqual(config.columnWidth(1), 12) def testSameColumns(self): - """ test hasSameColumns() check """ + """test hasSameColumns() check""" config = QgsAttributeTableConfig() c1 = QgsAttributeTableConfig.ColumnConfig() - c1.name = 'test' + c1.name = "test" c1.hidden = False c1.width = 100 c2 = QgsAttributeTableConfig.ColumnConfig() - c2.name = 'test2' + c2.name = "test2" c2.hidden = False c2.width = 120 config.setColumns([c1, c2]) @@ -202,7 +204,7 @@ def testSameColumns(self): config2.setColumns([c2, c1]) self.assertFalse(config.hasSameColumns(config2)) - c2.name = 'test3' + c2.name = "test3" config2.setColumns([c1, c2]) self.assertFalse(config.hasSameColumns(config2)) @@ -210,5 +212,5 @@ def testMapVisibleColumn(self): pass -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsattributetablemodel.py b/tests/src/python/test_qgsattributetablemodel.py index 89aab5d09f83..0a376943202c 100644 --- a/tests/src/python/test_qgsattributetablemodel.py +++ b/tests/src/python/test_qgsattributetablemodel.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Matthias Kuhn' -__date__ = '27/05/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Matthias Kuhn" +__date__ = "27/05/2015" +__copyright__ = "Copyright 2015, The QGIS Project" import os @@ -31,7 +32,12 @@ QgsVectorLayerCache, QgsVectorLayerExporter, ) -from qgis.gui import QgsAttributeTableModel, QgsAttributeTableFilterModel, QgsEditorWidgetFactory, QgsGui +from qgis.gui import ( + QgsAttributeTableModel, + QgsAttributeTableFilterModel, + QgsEditorWidgetFactory, + QgsGui, +) import unittest from qgis.testing import start_app, QgisTestCase @@ -63,7 +69,9 @@ def fieldScore(self, vl, fieldIdx): return 0 cls.testWidgetFactory = TestEditorWidgetFactory() - QgsGui.editorWidgetRegistry().registerWidget("testWidget", cls.testWidgetFactory) + QgsGui.editorWidgetRegistry().registerWidget( + "testWidget", cls.testWidgetFactory + ) def setUp(self): self.layer = self.createLayer() @@ -78,8 +86,9 @@ def tearDown(self): del self.layer def createLayer(self): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) pr = layer.dataProvider() features = list() for i in range(10): @@ -131,7 +140,9 @@ def testEdit(self): feature_model = self.am.feature(model_index) # check that feature from layer and model are sync - self.assertEqual(feature.attribute(field_idx), feature_model.attribute(field_idx)) + self.assertEqual( + feature.attribute(field_idx), feature_model.attribute(field_idx) + ) # change attribute value for a feature and commit self.layer.startEditing() @@ -159,7 +170,9 @@ def testEdit(self): feature_model = self.am.feature(model_index) # check that index from layer and model are sync - self.assertEqual(feature.attribute(field_idx), feature_model.attribute(field_idx)) + self.assertEqual( + feature.attribute(field_idx), feature_model.attribute(field_idx) + ) def testEditWithFilter(self): fid = 2 @@ -176,7 +189,9 @@ def testEditWithFilter(self): feature_model = am.feature(model_index) # check that feature from layer and model are sync - self.assertEqual(feature.attribute(field_idx), feature_model.attribute(field_idx)) + self.assertEqual( + feature.attribute(field_idx), feature_model.attribute(field_idx) + ) # change attribute value for a feature and commit self.layer.startEditing() @@ -204,7 +219,9 @@ def testEditWithFilter(self): feature_model = am.feature(model_index) # check that index from layer and model are sync - self.assertEqual(feature.attribute(field_idx), feature_model.attribute(field_idx)) + self.assertEqual( + feature.attribute(field_idx), feature_model.attribute(field_idx) + ) def testStyle(self): style_threshold = 2 @@ -218,7 +235,7 @@ def testStyle(self): model_index = self.am.idToIndex(f.id()) text_color = self.am.data(model_index, Qt.ItemDataRole.ForegroundRole) - if f['fldint'] <= style_threshold: + if f["fldint"] <= style_threshold: self.assertEqual(text_color, color) else: self.assertIsNone(text_color) @@ -226,9 +243,9 @@ def testStyle(self): self.assertTrue(self.layer.startEditing()) feature1 = self.layer.getFeature(2) - feature1['fldint'] = style_threshold + 1 + feature1["fldint"] = style_threshold + 1 feature2 = self.layer.getFeature(8) - feature2['fldint'] = style_threshold + feature2["fldint"] = style_threshold self.assertTrue(self.layer.updateFeature(feature1)) self.assertTrue(self.layer.updateFeature(feature2)) @@ -238,10 +255,12 @@ def testStyle(self): model_index = self.am.idToIndex(f.id()) text_color = self.am.data(model_index, Qt.ItemDataRole.ForegroundRole) - if f['fldint'] <= style_threshold: - self.assertEqual(color, text_color, f'Feature {f.id()} should have color') + if f["fldint"] <= style_threshold: + self.assertEqual( + color, text_color, f"Feature {f.id()} should have color" + ) else: - self.assertIsNone(text_color, f'Feature {f.id()} should have no color') + self.assertIsNone(text_color, f"Feature {f.id()} should have no color") self.layer.conditionalStyles().setRowStyles([]) @@ -252,25 +271,28 @@ def testTransactionRollback(self): path = d.path() source_fields = QgsFields() - source_fields.append(QgsField('int', QVariant.Int)) - vl = QgsMemoryProviderUtils.createMemoryLayer('test', source_fields) + source_fields.append(QgsField("int", QVariant.Int)) + vl = QgsMemoryProviderUtils.createMemoryLayer("test", source_fields) f = QgsFeature() f.setAttributes([1]) vl.dataProvider().addFeature(f) - tmpfile = os.path.join(path, 'testTransactionRollback.sqlite') + tmpfile = os.path.join(path, "testTransactionRollback.sqlite") - options = { - 'driverName': 'SpatiaLite', - 'layerName': 'test' - } + options = {"driverName": "SpatiaLite", "layerName": "test"} - err = QgsVectorLayerExporter.exportLayer(vl, tmpfile, "ogr", vl.crs(), False, options) - self.assertEqual(err[0], QgsVectorLayerExporter.ExportError.NoError, - f'unexpected import error {err}') + err = QgsVectorLayerExporter.exportLayer( + vl, tmpfile, "ogr", vl.crs(), False, options + ) + self.assertEqual( + err[0], + QgsVectorLayerExporter.ExportError.NoError, + f"unexpected import error {err}", + ) vl = QgsVectorLayer( - f'dbname=\'{tmpfile}\' table="test" () sql=', 'test', 'spatialite') + f"dbname='{tmpfile}' table=\"test\" () sql=", "test", "spatialite" + ) self.assertTrue(vl.isValid()) @@ -284,7 +306,7 @@ def testTransactionRollback(self): self.assertEqual(am.rowCount(), 1) self.assertTrue(vl.startEditing()) - vl.beginEditCommand('edit1') + vl.beginEditCommand("edit1") f = QgsFeature() f.setAttributes([2]) @@ -328,7 +350,11 @@ def __init__(self): super().__init__() def data(self, index, role): - if role == Qt.ItemDataRole.DisplayRole and self.sourceModel().extraColumns() > 0 and index.column() > 1: + if ( + role == Qt.ItemDataRole.DisplayRole + and self.sourceModel().extraColumns() > 0 + and index.column() > 1 + ): return f"extra_{index.column()}" return super().data(index, role) @@ -353,7 +379,9 @@ def data(self, index, role): self.assertEqual(fm.data(fm.index(2, 0), Qt.ItemDataRole.DisplayRole), "test") self.assertEqual(fm.data(fm.index(2, 1), Qt.ItemDataRole.DisplayRole), "2") - self.assertEqual(fm.data(fm.index(2, 2), Qt.ItemDataRole.DisplayRole), "extra_2") + self.assertEqual( + fm.data(fm.index(2, 2), Qt.ItemDataRole.DisplayRole), "extra_2" + ) self.assertEqual(twf.widgetLoaded, 0) @@ -377,7 +405,9 @@ def data(self, index, role): self.assertEqual(colsRemoved, 0) # add field, widget will be reloaded when data will be called - self.layer.addExpressionField("'newfield_' || \"fldtxt\"", QgsField("newfield", QVariant.String)) + self.layer.addExpressionField( + "'newfield_' || \"fldtxt\"", QgsField("newfield", QVariant.String) + ) self.assertEqual(twf.widgetLoaded, 0) self.assertEqual(colsInserted, 1) self.assertEqual(colsRemoved, 0) @@ -386,7 +416,9 @@ def data(self, index, role): self.assertEqual(fm.data(fm.index(2, 0), Qt.ItemDataRole.DisplayRole), "test") self.assertEqual(fm.data(fm.index(2, 1), Qt.ItemDataRole.DisplayRole), "2") - self.assertEqual(fm.data(fm.index(2, 2), Qt.ItemDataRole.DisplayRole), "newfield_test") + self.assertEqual( + fm.data(fm.index(2, 2), Qt.ItemDataRole.DisplayRole), "newfield_test" + ) twf.widgetLoaded = 0 # remove field, widget will be reloaded again @@ -403,8 +435,7 @@ def data(self, index, role): twf.widgetLoaded = 0 def test_sort_requires_geometry(self): - layer = QgsVectorLayer("Linestring?field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer("Linestring?field=fldint:integer", "addfeat", "memory") pr = layer.dataProvider() features = list() f = QgsFeature(layer.fields()) @@ -425,21 +456,21 @@ def test_sort_requires_geometry(self): fm = QgsAttributeTableFilterModel(None, am, am) fm.sort('"fldint"', Qt.SortOrder.AscendingOrder) - self.assertEqual(fm.data(fm.index(0, 0), Qt.ItemDataRole.DisplayRole), '1') - self.assertEqual(fm.data(fm.index(1, 0), Qt.ItemDataRole.DisplayRole), '2') + self.assertEqual(fm.data(fm.index(0, 0), Qt.ItemDataRole.DisplayRole), "1") + self.assertEqual(fm.data(fm.index(1, 0), Qt.ItemDataRole.DisplayRole), "2") fm.sort('"fldint"', Qt.SortOrder.DescendingOrder) - self.assertEqual(fm.data(fm.index(0, 0), Qt.ItemDataRole.DisplayRole), '2') - self.assertEqual(fm.data(fm.index(1, 0), Qt.ItemDataRole.DisplayRole), '1') + self.assertEqual(fm.data(fm.index(0, 0), Qt.ItemDataRole.DisplayRole), "2") + self.assertEqual(fm.data(fm.index(1, 0), Qt.ItemDataRole.DisplayRole), "1") - fm.sort('$length', Qt.SortOrder.DescendingOrder) - self.assertEqual(fm.data(fm.index(0, 0), Qt.ItemDataRole.DisplayRole), '1') - self.assertEqual(fm.data(fm.index(1, 0), Qt.ItemDataRole.DisplayRole), '2') + fm.sort("$length", Qt.SortOrder.DescendingOrder) + self.assertEqual(fm.data(fm.index(0, 0), Qt.ItemDataRole.DisplayRole), "1") + self.assertEqual(fm.data(fm.index(1, 0), Qt.ItemDataRole.DisplayRole), "2") - fm.sort('$length', Qt.SortOrder.AscendingOrder) - self.assertEqual(fm.data(fm.index(0, 0), Qt.ItemDataRole.DisplayRole), '2') - self.assertEqual(fm.data(fm.index(1, 0), Qt.ItemDataRole.DisplayRole), '1') + fm.sort("$length", Qt.SortOrder.AscendingOrder) + self.assertEqual(fm.data(fm.index(0, 0), Qt.ItemDataRole.DisplayRole), "2") + self.assertEqual(fm.data(fm.index(1, 0), Qt.ItemDataRole.DisplayRole), "1") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsauthbasicmethod.py b/tests/src/python/test_qgsauthbasicmethod.py index f5c1bcd3dc30..39d41dbeb207 100644 --- a/tests/src/python/test_qgsauthbasicmethod.py +++ b/tests/src/python/test_qgsauthbasicmethod.py @@ -23,12 +23,12 @@ from qgis.testing import start_app, QgisTestCase AUTHDBDIR = tempfile.mkdtemp() -os.environ['QGIS_AUTH_DB_DIR_PATH'] = AUTHDBDIR +os.environ["QGIS_AUTH_DB_DIR_PATH"] = AUTHDBDIR -__author__ = 'Alessandro Pasotti' -__date__ = '13/10/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "13/10/2020" +__copyright__ = "Copyright 2020, The QGIS Project" qgis_app = start_app() @@ -38,13 +38,13 @@ class TestAuthManager(QgisTestCase): @classmethod def setUpAuth(cls, username, password): """Run before all tests and set up authentication""" - assert (cls.authm.setMasterPassword('masterpassword', True)) + assert cls.authm.setMasterPassword("masterpassword", True) # Client side auth_config = QgsAuthMethodConfig("Basic") - auth_config.setConfig('username', username) - auth_config.setConfig('password', password) - auth_config.setName('test_basic_auth_config') - assert (cls.authm.storeAuthenticationConfig(auth_config)[0]) + auth_config.setConfig("username", username) + auth_config.setConfig("password", password) + auth_config.setName("test_basic_auth_config") + assert cls.authm.storeAuthenticationConfig(auth_config)[0] assert auth_config.isValid() return auth_config @@ -55,12 +55,11 @@ def setUpClass(cls): cls.authm = QgsApplication.authManager() assert not cls.authm.isDisabled(), cls.authm.disabledMessage() - cls.mpass = 'pass' # master password + cls.mpass = "pass" # master password - db1 = QFileInfo(cls.authm.authenticationDatabasePath() - ).canonicalFilePath() - db2 = QFileInfo(AUTHDBDIR + '/qgis-auth.db').canonicalFilePath() - msg = 'Auth db temp path does not match db path of manager' + db1 = QFileInfo(cls.authm.authenticationDatabasePath()).canonicalFilePath() + db2 = QFileInfo(AUTHDBDIR + "/qgis-auth.db").canonicalFilePath() + msg = "Auth db temp path does not match db path of manager" assert db1 == db2, msg def setUp(self): @@ -75,24 +74,24 @@ def _get_decoded_credentials(self, username, password): """Extracts and decode credentials from request Authorization header""" ac = self.setUpAuth(username, password) - req = QNetworkRequest(QUrl('http://none')) + req = QNetworkRequest(QUrl("http://none")) self.authm.updateNetworkRequest(req, ac.id()) - auth = bytes(req.rawHeader(b'Authorization'))[6:] + auth = bytes(req.rawHeader(b"Authorization"))[6:] # Note that RFC7617 states clearly: User-ids containing colons cannot be encoded in user-pass strings - u, p = base64.b64decode(auth).split(b':') - return u.decode('utf8'), p.decode('utf8') + u, p = base64.b64decode(auth).split(b":") + return u.decode("utf8"), p.decode("utf8") def testHeaderEncoding(self): """Test credentials encoding""" for creds in ( - ('username', 'password'), - ('username', r'pa%%word'), - ('username', r'èé'), - ('username', r'😁😂😍'), + ("username", "password"), + ("username", r"pa%%word"), + ("username", r"èé"), + ("username", r"😁😂😍"), ): self.assertEqual(self._get_decoded_credentials(*creds), creds) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsauthconfigurationstorageregistry.py b/tests/src/python/test_qgsauthconfigurationstorageregistry.py index d9361f6f8787..c4eb331f31ff 100644 --- a/tests/src/python/test_qgsauthconfigurationstorageregistry.py +++ b/tests/src/python/test_qgsauthconfigurationstorageregistry.py @@ -41,17 +41,17 @@ def setUp(self): self.temp_dir_path = self.temp_dir.path() # Create an empty sqlite database using GDAL - self.db_path = os.path.join(self.temp_dir_path, 'test.sqlite') - ds = gdal.GetDriverByName('SQLite').Create(self.db_path, 0, 0, 0) + self.db_path = os.path.join(self.temp_dir_path, "test.sqlite") + ds = gdal.GetDriverByName("SQLite").Create(self.db_path, 0, 0, 0) del ds # Verify that the file was created assert os.path.exists(self.db_path) - self.storage = QgsAuthConfigurationStorageDb('QSQLITE:' + self.db_path) + self.storage = QgsAuthConfigurationStorageDb("QSQLITE:" + self.db_path) assert self.storage.initialize() - assert self.storage.type() == 'DB-QSQLITE' + assert self.storage.type() == "DB-QSQLITE" def testStorageRegistry(self): """Test storage registry""" @@ -70,11 +70,11 @@ def testStorageRegistry(self): # Create a new configuration config = QgsAuthMethodConfig() - config.setId('test') - config.setName('Test') - config.setMethod('basic') - config.setConfig('username', 'test') - config.setConfig('password', 'test') + config.setId("test") + config.setName("Test") + config.setMethod("basic") + config.setConfig("username", "test") + config.setConfig("password", "test") payload = config.configString() self.assertTrue(self.storage.storeMethodConfig(config, payload)) @@ -92,5 +92,5 @@ def testStorageRegistry(self): self.assertEqual(len(spy_removed), 1) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsauthsystem.py b/tests/src/python/test_qgsauthsystem.py index 8d80be2db6a3..07591b33f45d 100644 --- a/tests/src/python/test_qgsauthsystem.py +++ b/tests/src/python/test_qgsauthsystem.py @@ -7,15 +7,22 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Larry Shaffer' -__date__ = '2014/11/05' -__copyright__ = 'Copyright 2014, Boundless Spatial, Inc.' + +__author__ = "Larry Shaffer" +__date__ = "2014/11/05" +__copyright__ = "Copyright 2014, Boundless Spatial, Inc." import os import tempfile from qgis.PyQt.QtCore import QFileInfo, qDebug -from qgis.PyQt.QtNetwork import QSsl, QSslCertificate, QSslError, QSslSocket, QSslConfiguration +from qgis.PyQt.QtNetwork import ( + QSsl, + QSslCertificate, + QSslError, + QSslSocket, + QSslConfiguration, +) from qgis.PyQt.QtTest import QTest from qgis.PyQt.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout from qgis.core import ( @@ -33,11 +40,11 @@ from utilities import unitTestDataPath AUTHDBDIR = tempfile.mkdtemp() -os.environ['QGIS_AUTH_DB_DIR_PATH'] = AUTHDBDIR +os.environ["QGIS_AUTH_DB_DIR_PATH"] = AUTHDBDIR start_app() -TESTDATA = os.path.join(unitTestDataPath(), 'auth_system') -PKIDATA = os.path.join(TESTDATA, 'certs_keys') +TESTDATA = os.path.join(unitTestDataPath(), "auth_system") +PKIDATA = os.path.join(TESTDATA, "certs_keys") class TestQgsAuthManager(QgisTestCase): @@ -48,31 +55,38 @@ def setUpClass(cls): cls.authm = QgsApplication.authManager() assert not cls.authm.isDisabled(), cls.authm.disabledMessage() - cls.mpass = 'pass' # master password + cls.mpass = "pass" # master password db1 = QFileInfo(cls.authm.authenticationDatabasePath()).canonicalFilePath() - db2 = QFileInfo(AUTHDBDIR + '/qgis-auth.db').canonicalFilePath() - msg = 'Auth db temp path does not match db path of manager' + db2 = QFileInfo(AUTHDBDIR + "/qgis-auth.db").canonicalFilePath() + msg = "Auth db temp path does not match db path of manager" assert db1 == db2, msg def setUp(self): - testid = self.id().split('.') - testheader = f'\n#####_____ {testid[1]}.{testid[2]} _____#####\n' + testid = self.id().split(".") + testheader = f"\n#####_____ {testid[1]}.{testid[2]} _____#####\n" qDebug(testheader) - if (not self.authm.masterPasswordIsSet() or - not self.authm.masterPasswordHashInDatabase()): + if ( + not self.authm.masterPasswordIsSet() + or not self.authm.masterPasswordHashInDatabase() + ): self.set_master_password() def checkCA(self): """For debugging the test""" - cert_ids = set([QgsAuthCertUtils.shaHexForCert(c) for c in QgsAuthCertUtils.certsFromFile(PKIDATA + '/chain_subissuer-issuer-root.pem')]) + cert_ids = { + QgsAuthCertUtils.shaHexForCert(c) + for c in QgsAuthCertUtils.certsFromFile( + PKIDATA + "/chain_subissuer-issuer-root.pem" + ) + } cfg = QSslConfiguration.defaultConfiguration() # Get list of CA certificates - ids = set([QgsAuthCertUtils.shaHexForCert(c) for c in cfg.caCertificates()]) + ids = {QgsAuthCertUtils.shaHexForCert(c) for c in cfg.caCertificates()} for c in cert_ids: - self.assertNotIn(c, ids, f'CA certificate {c} is already in the system') + self.assertNotIn(c, ids, f"CA certificate {c} is already in the system") def widget_dialog(self, widget): dlg = QDialog() @@ -87,12 +101,12 @@ def widget_dialog(self, widget): return dlg def mkPEMBundle(self, client_cert, client_key, password, chain): - return QgsPkiBundle.fromPemPaths(PKIDATA + '/' + client_cert, - PKIDATA + '/' + client_key, - password, - QgsAuthCertUtils.certsFromFile( - PKIDATA + '/' + chain - )) + return QgsPkiBundle.fromPemPaths( + PKIDATA + "/" + client_cert, + PKIDATA + "/" + client_key, + password, + QgsAuthCertUtils.certsFromFile(PKIDATA + "/" + chain), + ) def show_editors_widget(self): editors = QgsAuthEditorWidgets() @@ -100,27 +114,27 @@ def show_editors_widget(self): dlg.exec() def set_master_password(self): - msg = 'Failed to store and verify master password in auth db' + msg = "Failed to store and verify master password in auth db" assert self.authm.setMasterPassword(self.mpass, True), msg def test_010_master_password(self): - msg = 'Master password is not set' + msg = "Master password is not set" self.assertTrue(self.authm.masterPasswordIsSet(), msg) - msg = 'Master password hash is not in database' + msg = "Master password hash is not in database" self.assertTrue(self.authm.masterPasswordHashInDatabase(), msg) - msg = 'Master password not verified against hash in database' + msg = "Master password not verified against hash in database" self.assertTrue(self.authm.verifyMasterPassword(), msg) - msg = 'Master password comparison dissimilar' + msg = "Master password comparison dissimilar" self.assertTrue(self.authm.masterPasswordSame(self.mpass), msg) - msg = 'Master password not unset' + msg = "Master password not unset" self.authm.clearMasterPassword() self.assertFalse(self.authm.masterPasswordIsSet(), msg) - msg = 'Master password not reset and validated' + msg = "Master password not reset and validated" self.assertTrue(self.authm.setMasterPassword(self.mpass, True), msg) # NOTE: reset of master password is in auth db test unit @@ -134,66 +148,63 @@ def test_030_auth_settings(self): def test_040_authorities(self): def rebuild_caches(): - m = 'Authorities cache could not be rebuilt' + m = "Authorities cache could not be rebuilt" self.assertTrue(self.authm.rebuildCaCertsCache(), m) - m = 'Authorities trust policy cache could not be rebuilt' + m = "Authorities trust policy cache could not be rebuilt" self.assertTrue(self.authm.rebuildTrustedCaCertsCache(), m) def trusted_ca_certs(): tr_certs = self.authm.trustedCaCerts() - m = 'Trusted authorities cache is empty' + m = "Trusted authorities cache is empty" self.assertIsNotNone(tr_certs, m) return tr_certs - msg = 'No system root CAs' + msg = "No system root CAs" self.assertIsNotNone(self.authm.systemRootCAs()) self.checkCA() # TODO: add more tests - full_chain = 'chains_subissuer-issuer-root_issuer2-root2.pem' + full_chain = "chains_subissuer-issuer-root_issuer2-root2.pem" full_chain_path = os.path.join(PKIDATA, full_chain) # load CA file authorities for later comparison # noinspection PyTypeChecker # ca_certs = QSslCertificate.fromPath(full_chain_path) ca_certs = QgsAuthCertUtils.certsFromFile(full_chain_path) - msg = 'Authorities file could not be parsed' + msg = "Authorities file could not be parsed" self.assertIsNotNone(ca_certs, msg) - msg = 'Authorities file parsed count is incorrect' + msg = "Authorities file parsed count is incorrect" self.assertEqual(len(ca_certs), 5, msg) # first test CA file can be set and loaded - msg = 'Authority file path setting could not be stored' - self.assertTrue( - self.authm.storeAuthSetting('cafile', full_chain_path), msg) + msg = "Authority file path setting could not be stored" + self.assertTrue(self.authm.storeAuthSetting("cafile", full_chain_path), msg) msg = "Authority file 'allow invalids' setting could not be stored" - self.assertTrue( - self.authm.storeAuthSetting('cafileallowinvalid', False), msg) + self.assertTrue(self.authm.storeAuthSetting("cafileallowinvalid", False), msg) rebuild_caches() trusted_certs = trusted_ca_certs() not_cached = any([ca not in trusted_certs for ca in ca_certs]) - msg = 'Authorities not in trusted authorities cache' + msg = "Authorities not in trusted authorities cache" self.assertFalse(not_cached, msg) # test CA file can be unset - msg = 'Authority file path setting could not be removed' - self.assertTrue(self.authm.removeAuthSetting('cafile'), msg) + msg = "Authority file path setting could not be removed" + self.assertTrue(self.authm.removeAuthSetting("cafile"), msg) msg = "Authority file 'allow invalids' setting could not be removed" - self.assertTrue( - self.authm.removeAuthSetting('cafileallowinvalid'), msg) + self.assertTrue(self.authm.removeAuthSetting("cafileallowinvalid"), msg) rebuild_caches() trusted_certs = trusted_ca_certs() still_cached = any([ca in trusted_certs for ca in ca_certs]) - msg = 'Authorities still in trusted authorities cache' + msg = "Authorities still in trusted authorities cache" self.assertFalse(still_cached, msg) # test CAs can be stored in database @@ -204,7 +215,7 @@ def trusted_ca_certs(): trusted_certs = trusted_ca_certs() not_cached = any([ca not in trusted_certs for ca in ca_certs]) - msg = 'Stored authorities not in trusted authorities cache' + msg = "Stored authorities not in trusted authorities cache" self.assertFalse(not_cached, msg) # Cleanup @@ -216,7 +227,7 @@ def trusted_ca_certs(): trusted_certs = trusted_ca_certs() still_cached = any([ca in trusted_certs for ca in ca_certs]) - msg = 'Stored authorities still in trusted authorities cache' + msg = "Stored authorities still in trusted authorities cache" self.assertFalse(still_cached, msg) # dlg = QgsAuthTrustedCAsDialog() @@ -230,16 +241,17 @@ def test_060_identities(self): self.checkCA() - client_cert_path = os.path.join(PKIDATA, 'fra_cert.pem') - client_key_path = os.path.join(PKIDATA, 'fra_key_w-pass.pem') - client_key_pass = 'password' - client_p12_path = os.path.join(PKIDATA, 'gerardus_w-chain.p12') - client_p12_pass = 'password' + client_cert_path = os.path.join(PKIDATA, "fra_cert.pem") + client_key_path = os.path.join(PKIDATA, "fra_key_w-pass.pem") + client_key_pass = "password" + client_p12_path = os.path.join(PKIDATA, "gerardus_w-chain.p12") + client_p12_pass = "password" # store regular PEM cert/key and generate config # noinspection PyTypeChecker - bundle1 = QgsPkiBundle.fromPemPaths(client_cert_path, client_key_path, - client_key_pass) + bundle1 = QgsPkiBundle.fromPemPaths( + client_cert_path, client_key_path, client_key_pass + ) bundle1_cert = bundle1.clientCert() bundle1_key = bundle1.clientKey() bundle1_ca_chain = bundle1.caChain() @@ -249,43 +261,42 @@ def test_060_identities(self): # key_data = f.read() # # client_cert = QgsAuthCertUtils.certsFromFile(client_cert_path)[0] - msg = 'Identity PEM certificate is null' + msg = "Identity PEM certificate is null" self.assertFalse(bundle1_cert.isNull(), msg) # cert_sha = QgsAuthCertUtils.shaHexForCert(client_cert) # # client_key = QSslKey(key_data, QSsl.Rsa, QSsl.Pem, # QSsl.PrivateKey, client_key_pass) - msg = 'Identity PEM key is null' + msg = "Identity PEM key is null" self.assertFalse(bundle1_key.isNull(), msg) - msg = 'Identity PEM certificate chain is not empty' + msg = "Identity PEM certificate chain is not empty" self.assertEqual(len(bundle1_ca_chain), 0, msg) msg = "Identity PEM could not be stored in database" - self.assertTrue( - self.authm.storeCertIdentity(bundle1_cert, bundle1_key), msg) + self.assertTrue(self.authm.storeCertIdentity(bundle1_cert, bundle1_key), msg) msg = "Identity PEM not found in database" self.assertTrue(self.authm.existsCertIdentity(bundle1_cert_sha), msg) config1 = QgsAuthMethodConfig() - config1.setName('IdentityCert - PEM') - config1.setMethod('Identity-Cert') - config1.setConfig('certid', bundle1_cert_sha) + config1.setName("IdentityCert - PEM") + config1.setMethod("Identity-Cert") + config1.setConfig("certid", bundle1_cert_sha) - msg = 'Could not store PEM identity config' + msg = "Could not store PEM identity config" self.assertTrue(self.authm.storeAuthenticationConfig(config1), msg) configid1 = config1.id() - msg = 'Could not retrieve PEM identity config id from store op' + msg = "Could not retrieve PEM identity config id from store op" self.assertIsNotNone(configid1, msg) config2 = QgsAuthMethodConfig() - msg = 'Could not load PEM identity config' + msg = "Could not load PEM identity config" self.assertTrue( - self.authm.loadAuthenticationConfig(configid1, config2, True), - msg) + self.authm.loadAuthenticationConfig(configid1, config2, True), msg + ) # store PKCS#12 bundled cert/key and generate config # bundle = QgsPkcsBundle(client_p12_path, client_p12_pass) @@ -296,66 +307,62 @@ def test_060_identities(self): bundle_ca_chain = bundle.caChain() bundle_cert_sha = QgsAuthCertUtils.shaHexForCert(bundle_cert) - msg = 'Identity bundle certificate is null' + msg = "Identity bundle certificate is null" self.assertFalse(bundle_cert.isNull(), msg) - msg = 'Identity bundle key is null' + msg = "Identity bundle key is null" self.assertFalse(bundle_key.isNull(), msg) - msg = 'Identity bundle CA chain is not correct depth' + msg = "Identity bundle CA chain is not correct depth" self.assertEqual(len(bundle_ca_chain), 3, msg) msg = "Identity bundle could not be stored in database" - self.assertTrue( - self.authm.storeCertIdentity(bundle_cert, bundle_key), msg) + self.assertTrue(self.authm.storeCertIdentity(bundle_cert, bundle_key), msg) msg = "Identity bundle not found in database" self.assertTrue(self.authm.existsCertIdentity(bundle_cert_sha), msg) bundle_config = QgsAuthMethodConfig() - bundle_config.setName('IdentityCert - Bundle') - bundle_config.setMethod('Identity-Cert') - bundle_config.setConfig('certid', bundle_cert_sha) + bundle_config.setName("IdentityCert - Bundle") + bundle_config.setMethod("Identity-Cert") + bundle_config.setConfig("certid", bundle_cert_sha) - msg = 'Could not store bundle identity config' - self.assertTrue( - self.authm.storeAuthenticationConfig(bundle_config), msg) + msg = "Could not store bundle identity config" + self.assertTrue(self.authm.storeAuthenticationConfig(bundle_config), msg) bundle_configid = bundle_config.id() - msg = 'Could not retrieve bundle identity config id from store op' + msg = "Could not retrieve bundle identity config id from store op" self.assertIsNotNone(bundle_configid, msg) bundle_config2 = QgsAuthMethodConfig() - msg = 'Could not load bundle identity config' + msg = "Could not load bundle identity config" self.assertTrue( - self.authm.loadAuthenticationConfig(bundle_configid, - bundle_config2, - True), - msg) + self.authm.loadAuthenticationConfig(bundle_configid, bundle_config2, True), + msg, + ) # TODO: add more tests # self.show_editors_widget() - msg = 'Could not remove PEM identity config' + msg = "Could not remove PEM identity config" self.assertTrue(self.authm.removeAuthenticationConfig(configid1), msg) - msg = 'Could not remove bundle identity config' - self.assertTrue( - self.authm.removeAuthenticationConfig(bundle_configid), msg) + msg = "Could not remove bundle identity config" + self.assertTrue(self.authm.removeAuthenticationConfig(bundle_configid), msg) def test_070_servers(self): self.checkCA() - ssl_cert_path = os.path.join(PKIDATA, 'localhost_ssl_cert.pem') + ssl_cert_path = os.path.join(PKIDATA, "localhost_ssl_cert.pem") ssl_cert = QgsAuthCertUtils.certsFromFile(ssl_cert_path)[0] - msg = 'SSL server certificate is null' + msg = "SSL server certificate is null" self.assertFalse(ssl_cert.isNull(), msg) cert_sha = QgsAuthCertUtils.shaHexForCert(ssl_cert) - hostport = 'localhost:8443' + hostport = "localhost:8443" config = QgsAuthConfigSslServer() config.setSslCertificate(ssl_cert) config.setSslHostPort(hostport) @@ -364,179 +371,171 @@ def test_070_servers(self): config.setSslPeerVerifyDepth(3) config.setSslProtocol(QSsl.SslProtocol.TlsV1_1) - msg = 'SSL config is null' + msg = "SSL config is null" self.assertFalse(config.isNull(), msg) - msg = 'Could not store SSL config' + msg = "Could not store SSL config" self.assertTrue(self.authm.storeSslCertCustomConfig(config), msg) - msg = 'Could not verify storage of SSL config' - self.assertTrue( - self.authm.existsSslCertCustomConfig(cert_sha, hostport), msg) + msg = "Could not verify storage of SSL config" + self.assertTrue(self.authm.existsSslCertCustomConfig(cert_sha, hostport), msg) - msg = 'Could not verify SSL config in all configs' + msg = "Could not verify SSL config in all configs" self.assertIsNotNone(self.authm.sslCertCustomConfigs(), msg) - msg = 'Could not retrieve SSL config' + msg = "Could not retrieve SSL config" config2 = self.authm.sslCertCustomConfig(cert_sha, hostport) """:type: QgsAuthConfigSslServer""" self.assertFalse(config2.isNull(), msg) - msg = 'Certificate of retrieved SSL config does not match' + msg = "Certificate of retrieved SSL config does not match" self.assertEqual(config.sslCertificate(), config2.sslCertificate(), msg) - msg = 'HostPort of retrieved SSL config does not match' + msg = "HostPort of retrieved SSL config does not match" self.assertEqual(config.sslHostPort(), config2.sslHostPort(), msg) enums = config2.sslIgnoredErrorEnums() self.assertIn(QSslError.SslError.SelfSignedCertificate, enums) - msg = 'PeerVerifyMode of retrieved SSL config does not match' - self.assertEqual(config.sslPeerVerifyMode(), - config2.sslPeerVerifyMode(), msg) + msg = "PeerVerifyMode of retrieved SSL config does not match" + self.assertEqual(config.sslPeerVerifyMode(), config2.sslPeerVerifyMode(), msg) - msg = 'PeerVerifyDepth of retrieved SSL config does not match' - self.assertEqual(config.sslPeerVerifyDepth(), - config2.sslPeerVerifyDepth(), msg) + msg = "PeerVerifyDepth of retrieved SSL config does not match" + self.assertEqual(config.sslPeerVerifyDepth(), config2.sslPeerVerifyDepth(), msg) - msg = 'Protocol of retrieved SSL config does not match' + msg = "Protocol of retrieved SSL config does not match" self.assertEqual(config.sslProtocol(), config2.sslProtocol(), msg) # dlg = QgsAuthSslConfigDialog(None, ssl_cert, hostport) # dlg.exec_() - msg = 'Could not remove SSL config' - self.assertTrue( - self.authm.removeSslCertCustomConfig(cert_sha, hostport), msg) + msg = "Could not remove SSL config" + self.assertTrue(self.authm.removeSslCertCustomConfig(cert_sha, hostport), msg) - msg = 'Could not verify removal of SSL config' - self.assertFalse( - self.authm.existsSslCertCustomConfig(cert_sha, hostport), msg) + msg = "Could not verify removal of SSL config" + self.assertFalse(self.authm.existsSslCertCustomConfig(cert_sha, hostport), msg) def test_080_auth_configid(self): self.checkCA() - msg = 'Could not generate a config id' + msg = "Could not generate a config id" self.assertIsNotNone(self.authm.uniqueConfigId(), msg) uids = [] for _ in range(50): # time.sleep(0.01) # or else the salt is not random enough uids.append(self.authm.uniqueConfigId()) - msg = f'Generated 50 config ids are not unique:\n{uids}\n{list(set(uids))}' + msg = f"Generated 50 config ids are not unique:\n{uids}\n{list(set(uids))}" self.assertEqual(len(uids), len(list(set(uids))), msg) def config_list(self): - return ['Basic', 'PKI-Paths', 'PKI-PKCS#12'] + return ["Basic", "PKI-Paths", "PKI-PKCS#12"] def config_obj(self, kind, base=True): config = QgsAuthMethodConfig() config.setName(kind) config.setMethod(kind) - config.setUri('http://example.com') + config.setUri("http://example.com") if base: return config - if kind == 'Basic': - config.setConfig('username', 'username') - config.setConfig('password', 'password') - config.setConfig('realm', 'Realm') - elif kind == 'PKI-Paths': - config.setConfig('certpath', - os.path.join(PKIDATA, 'gerardus_cert.pem')) - config.setConfig('keypath', - os.path.join(PKIDATA, 'gerardus_key_w-pass.pem')) - config.setConfig('keypass', 'password') - elif kind == 'PKI-PKCS#12': - config.setConfig('bundlepath', - os.path.join(PKIDATA, 'gerardus.p12')) - config.setConfig('bundlepass', 'password') + if kind == "Basic": + config.setConfig("username", "username") + config.setConfig("password", "password") + config.setConfig("realm", "Realm") + elif kind == "PKI-Paths": + config.setConfig("certpath", os.path.join(PKIDATA, "gerardus_cert.pem")) + config.setConfig( + "keypath", os.path.join(PKIDATA, "gerardus_key_w-pass.pem") + ) + config.setConfig("keypass", "password") + elif kind == "PKI-PKCS#12": + config.setConfig("bundlepath", os.path.join(PKIDATA, "gerardus.p12")) + config.setConfig("bundlepass", "password") return config def config_values_valid(self, kind, config): """:type config: QgsAuthMethodConfig""" - if (config.name() != kind or - config.method() != kind or - config.uri() != 'http://example.com'): + if ( + config.name() != kind + or config.method() != kind + or config.uri() != "http://example.com" + ): return False - if kind == 'Basic': + if kind == "Basic": return ( - config.config('username') == 'username' and - config.config('password') == 'password' and - config.config('realm') == 'Realm' + config.config("username") == "username" + and config.config("password") == "password" + and config.config("realm") == "Realm" ) - elif kind == 'PKI-Paths': + elif kind == "PKI-Paths": return ( - config.config('certpath') == - os.path.join(PKIDATA, 'gerardus_cert.pem') and - config.config('keypath') == - os.path.join(PKIDATA, 'gerardus_key_w-pass.pem') and - config.config('keypass') == 'password' + config.config("certpath") == os.path.join(PKIDATA, "gerardus_cert.pem") + and config.config("keypath") + == os.path.join(PKIDATA, "gerardus_key_w-pass.pem") + and config.config("keypass") == "password" ) - elif kind == 'PKI-PKCS#12': + elif kind == "PKI-PKCS#12": return ( - config.config('bundlepath') == - os.path.join(PKIDATA, 'gerardus.p12') and - config.config('bundlepass') == 'password' + config.config("bundlepath") == os.path.join(PKIDATA, "gerardus.p12") + and config.config("bundlepass") == "password" ) def test_090_auth_configs(self): # these list items need to match the QgsAuthType provider type strings for kind in self.config_list(): config = self.config_obj(kind, base=False) - msg = f'Could not validate {kind} config' + msg = f"Could not validate {kind} config" self.assertTrue(config.isValid(), msg) - msg = f'Could not store {kind} config' + msg = f"Could not store {kind} config" self.assertTrue(self.authm.storeAuthenticationConfig(config), msg) configid = config.id() - msg = f'Could not retrieve {kind} config id from store op' + msg = f"Could not retrieve {kind} config id from store op" self.assertIsNotNone(configid, msg) - msg = f'Config id {configid} not in db' + msg = f"Config id {configid} not in db" self.assertFalse(self.authm.configIdUnique(configid), msg) self.assertIn(configid, self.authm.configIds()) - msg = f'Could not retrieve method key for {kind} config' - self.assertTrue( - self.authm.configAuthMethodKey(configid) == kind, msg) + msg = f"Could not retrieve method key for {kind} config" + self.assertTrue(self.authm.configAuthMethodKey(configid) == kind, msg) - msg = f'Could not retrieve method ptr for {kind} config' + msg = f"Could not retrieve method ptr for {kind} config" self.assertTrue( - isinstance(self.authm.configAuthMethod(configid), - QgsAuthMethod), msg) + isinstance(self.authm.configAuthMethod(configid), QgsAuthMethod), msg + ) config2 = self.config_obj(kind, base=True) - msg = f'Could not load {kind} config' + msg = f"Could not load {kind} config" self.assertTrue( - self.authm.loadAuthenticationConfig(configid, config2, True), - msg) + self.authm.loadAuthenticationConfig(configid, config2, True), msg + ) - msg = f'Could not validate loaded {kind} config values' + msg = f"Could not validate loaded {kind} config values" self.assertTrue(self.config_values_valid(kind, config2), msg) # values haven't been changed, but the db update still takes place - msg = f'Could not update {kind} config values' + msg = f"Could not update {kind} config values" self.assertTrue(self.authm.updateAuthenticationConfig(config2), msg) config3 = self.config_obj(kind, base=True) - msg = f'Could not load updated {kind} config' + msg = f"Could not load updated {kind} config" self.assertTrue( - self.authm.loadAuthenticationConfig(configid, config3, True), - msg) + self.authm.loadAuthenticationConfig(configid, config3, True), msg + ) - msg = f'Could not validate updated {kind} config values' + msg = f"Could not validate updated {kind} config values" self.assertTrue(self.config_values_valid(kind, config3), msg) - msg = f'Could not remove {kind} config (by id) from db' - self.assertTrue( - self.authm.removeAuthenticationConfig(configid), msg) + msg = f"Could not remove {kind} config (by id) from db" + self.assertTrue(self.authm.removeAuthenticationConfig(configid), msg) - msg = f'Did not remove {kind} config id from db' + msg = f"Did not remove {kind} config id from db" self.assertFalse(configid in self.authm.configIds(), msg) def test_100_auth_db(self): @@ -545,55 +544,57 @@ def test_100_auth_db(self): for kind in self.config_list(): config = self.config_obj(kind, base=False) - msg = f'Could not store {kind} config' + msg = f"Could not store {kind} config" self.assertTrue(self.authm.storeAuthenticationConfig(config), msg) - msg = 'Could not store a sample of all configs in auth db' - self.assertTrue( - (len(self.authm.configIds()) == len(self.config_list())), msg) + msg = "Could not store a sample of all configs in auth db" + self.assertTrue((len(self.authm.configIds()) == len(self.config_list())), msg) - msg = 'Could not retrieve available configs from auth db' + msg = "Could not retrieve available configs from auth db" self.assertGreater(len(self.authm.availableAuthMethodConfigs()), 0) backup = None resetpass, backup = self.authm.resetMasterPassword( - 'newpass', self.mpass, True, backup) - msg = 'Could not reset master password and/or re-encrypt configs' + "newpass", self.mpass, True, backup + ) + msg = "Could not reset master password and/or re-encrypt configs" self.assertTrue(resetpass, msg) # qDebug('Backup db path: {0}'.format(backup)) - msg = 'Could not retrieve backup path for reset master password op' + msg = "Could not retrieve backup path for reset master password op" self.assertIsNotNone(backup) self.assertNotEqual(backup, self.authm.authenticationDatabasePath()) - msg = 'Could not verify reset master password' - self.assertTrue(self.authm.setMasterPassword('newpass', True), msg) + msg = "Could not verify reset master password" + self.assertTrue(self.authm.setMasterPassword("newpass", True), msg) - msg = 'Could not remove all configs from auth db' + msg = "Could not remove all configs from auth db" self.assertTrue(self.authm.removeAllAuthenticationConfigs(), msg) - msg = 'Configs were not removed from auth db' + msg = "Configs were not removed from auth db" self.assertEqual(len(self.authm.configIds()), 0) - msg = 'Auth db does not exist' + msg = "Auth db does not exist" self.assertTrue(os.path.exists(self.authm.authenticationDatabasePath()), msg) QTest.qSleep(1000) # necessary for new backup to have different name - msg = 'Could not erase auth db' + msg = "Could not erase auth db" backup = None - reserase, backup = \ - self.authm.eraseAuthenticationDatabase(True, backup) + reserase, backup = self.authm.eraseAuthenticationDatabase(True, backup) self.assertTrue(reserase, msg) # qDebug('Erase db backup db path: {0}'.format(backup)) - msg = 'Could not retrieve backup path for erase db op' + msg = "Could not retrieve backup path for erase db op" self.assertIsNotNone(backup) self.assertNotEqual(backup, self.authm.authenticationDatabasePath()) - msg = 'Master password not erased from auth db' - self.assertTrue(not self.authm.masterPasswordIsSet() and - not self.authm.masterPasswordHashInDatabase(), msg) + msg = "Master password not erased from auth db" + self.assertTrue( + not self.authm.masterPasswordIsSet() + and not self.authm.masterPasswordHashInDatabase(), + msg, + ) self.set_master_password() @@ -601,32 +602,32 @@ def test_100_auth_db(self): def test_110_pkcs12_cas(self): """Test if CAs can be read from a pkcs12 bundle""" - path = PKIDATA + '/fra_w-chain.p12' - cas = QgsAuthCertUtils.pkcs12BundleCas(path, 'password') + path = PKIDATA + "/fra_w-chain.p12" + cas = QgsAuthCertUtils.pkcs12BundleCas(path, "password") - self.assertEqual(cas[0].issuerInfo(b'CN'), ['QGIS Test Root CA']) - self.assertEqual(cas[0].subjectInfo(b'CN'), ['QGIS Test Issuer CA']) - self.assertEqual(cas[0].serialNumber(), b'02') - self.assertEqual(cas[1].issuerInfo(b'CN'), ['QGIS Test Root CA']) - self.assertEqual(cas[1].subjectInfo(b'CN'), ['QGIS Test Root CA']) - self.assertEqual(cas[1].serialNumber(), b'01') + self.assertEqual(cas[0].issuerInfo(b"CN"), ["QGIS Test Root CA"]) + self.assertEqual(cas[0].subjectInfo(b"CN"), ["QGIS Test Issuer CA"]) + self.assertEqual(cas[0].serialNumber(), b"02") + self.assertEqual(cas[1].issuerInfo(b"CN"), ["QGIS Test Root CA"]) + self.assertEqual(cas[1].subjectInfo(b"CN"), ["QGIS Test Root CA"]) + self.assertEqual(cas[1].serialNumber(), b"01") def test_120_pem_cas_from_file(self): """Test if CAs can be read from a pem bundle""" - path = PKIDATA + '/fra_w-chain.pem' + path = PKIDATA + "/fra_w-chain.pem" cas = QgsAuthCertUtils.casFromFile(path) - self.assertEqual(cas[0].issuerInfo(b'CN'), ['QGIS Test Root CA']) - self.assertEqual(cas[0].subjectInfo(b'CN'), ['QGIS Test Issuer CA']) - self.assertEqual(cas[0].serialNumber(), b'02') - self.assertEqual(cas[1].issuerInfo(b'CN'), ['QGIS Test Root CA']) - self.assertEqual(cas[1].subjectInfo(b'CN'), ['QGIS Test Root CA']) - self.assertEqual(cas[1].serialNumber(), b'01') + self.assertEqual(cas[0].issuerInfo(b"CN"), ["QGIS Test Root CA"]) + self.assertEqual(cas[0].subjectInfo(b"CN"), ["QGIS Test Issuer CA"]) + self.assertEqual(cas[0].serialNumber(), b"02") + self.assertEqual(cas[1].issuerInfo(b"CN"), ["QGIS Test Root CA"]) + self.assertEqual(cas[1].subjectInfo(b"CN"), ["QGIS Test Root CA"]) + self.assertEqual(cas[1].serialNumber(), b"01") def test_130_cas_merge(self): - """Test CAs merge """ - trusted_path = PKIDATA + '/subissuer_ca_cert.pem' - extra_path = PKIDATA + '/fra_w-chain.pem' + """Test CAs merge""" + trusted_path = PKIDATA + "/subissuer_ca_cert.pem" + extra_path = PKIDATA + "/fra_w-chain.pem" trusted = QgsAuthCertUtils.casFromFile(trusted_path) extra = QgsAuthCertUtils.casFromFile(extra_path) @@ -642,8 +643,8 @@ def test_130_cas_merge(self): self.assertIn(trusted[0], merged) def test_140_cas_remove_self_signed(self): - """Test CAs merge """ - extra_path = PKIDATA + '/fra_w-chain.pem' + """Test CAs merge""" + extra_path = PKIDATA + "/fra_w-chain.pem" extra = QgsAuthCertUtils.casFromFile(extra_path) filtered = QgsAuthCertUtils.casRemoveSelfSigned(extra) @@ -662,96 +663,266 @@ def test_150_verify_keychain(self): def testChain(path): # Test that a chain with an untrusted CA is not valid - self.assertGreater(len(QgsAuthCertUtils.validateCertChain(QgsAuthCertUtils.certsFromFile(path))), 0) + self.assertGreater( + len( + QgsAuthCertUtils.validateCertChain( + QgsAuthCertUtils.certsFromFile(path) + ) + ), + 0, + ) # Test that a chain with an untrusted CA is valid when the addRootCa argument is true - self.assertEqual(len(QgsAuthCertUtils.validateCertChain(QgsAuthCertUtils.certsFromFile(path), None, True)), 0) + self.assertEqual( + len( + QgsAuthCertUtils.validateCertChain( + QgsAuthCertUtils.certsFromFile(path), None, True + ) + ), + 0, + ) # Test that a chain with an untrusted CA is not valid when the addRootCa argument is true # and a wrong domain is true - self.assertGreater(len(QgsAuthCertUtils.validateCertChain(QgsAuthCertUtils.certsFromFile(path), 'my.wrong.domain', True)), 0) + self.assertGreater( + len( + QgsAuthCertUtils.validateCertChain( + QgsAuthCertUtils.certsFromFile(path), "my.wrong.domain", True + ) + ), + 0, + ) self.checkCA() - testChain(PKIDATA + '/chain_subissuer-issuer-root.pem') - testChain(PKIDATA + '/localhost_ssl_w-chain.pem') - testChain(PKIDATA + '/fra_w-chain.pem') + testChain(PKIDATA + "/chain_subissuer-issuer-root.pem") + testChain(PKIDATA + "/localhost_ssl_w-chain.pem") + testChain(PKIDATA + "/fra_w-chain.pem") - path = PKIDATA + '/localhost_ssl_w-chain.pem' + path = PKIDATA + "/localhost_ssl_w-chain.pem" # Test that a chain with an untrusted CA is not valid when the addRootCa argument is true # and a wrong domain is set - self.assertGreater(len(QgsAuthCertUtils.validateCertChain(QgsAuthCertUtils.certsFromFile(path), 'my.wrong.domain', True)), 0) + self.assertGreater( + len( + QgsAuthCertUtils.validateCertChain( + QgsAuthCertUtils.certsFromFile(path), "my.wrong.domain", True + ) + ), + 0, + ) # Test that a chain with an untrusted CA is valid when the addRootCa argument is true # and a right domain is set - self.assertEqual(len(QgsAuthCertUtils.validateCertChain(QgsAuthCertUtils.certsFromFile(path), 'localhost', True)), 0) + self.assertEqual( + len( + QgsAuthCertUtils.validateCertChain( + QgsAuthCertUtils.certsFromFile(path), "localhost", True + ) + ), + 0, + ) # Test that a chain with an untrusted CA is not valid when the addRootCa argument is false # and a right domain is set - self.assertGreater(len(QgsAuthCertUtils.validateCertChain(QgsAuthCertUtils.certsFromFile(path), 'localhost', False)), 0) + self.assertGreater( + len( + QgsAuthCertUtils.validateCertChain( + QgsAuthCertUtils.certsFromFile(path), "localhost", False + ) + ), + 0, + ) def test_validate_pki_bundle(self): """Text the pki bundle validation""" # Valid bundle: - bundle = self.mkPEMBundle('fra_cert.pem', 'fra_key.pem', 'password', 'chain_subissuer-issuer-root.pem') + bundle = self.mkPEMBundle( + "fra_cert.pem", "fra_key.pem", "password", "chain_subissuer-issuer-root.pem" + ) # Test valid bundle with intermediates and without trusted root - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(bundle), ['The root certificate of the certificate chain is self-signed, and untrusted']) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle(bundle), + [ + "The root certificate of the certificate chain is self-signed, and untrusted" + ], + ) # Test valid without intermediates - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(bundle, False), ['The issuer certificate of a locally looked up certificate could not be found', 'No certificates could be verified']) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle(bundle, False), + [ + "The issuer certificate of a locally looked up certificate could not be found", + "No certificates could be verified", + ], + ) # Test valid with intermediates and trusted root self.assertEqual(QgsAuthCertUtils.validatePKIBundle(bundle, True, True), []) # Wrong chain - bundle = self.mkPEMBundle('fra_cert.pem', 'fra_key.pem', 'password', 'chain_issuer2-root2.pem') + bundle = self.mkPEMBundle( + "fra_cert.pem", "fra_key.pem", "password", "chain_issuer2-root2.pem" + ) # Test invalid bundle with intermediates and without trusted root - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(bundle), ['The issuer certificate of a locally looked up certificate could not be found', 'No certificates could be verified']) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle(bundle), + [ + "The issuer certificate of a locally looked up certificate could not be found", + "No certificates could be verified", + ], + ) # Test valid without intermediates - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(bundle, False), ['The issuer certificate of a locally looked up certificate could not be found', 'No certificates could be verified']) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle(bundle, False), + [ + "The issuer certificate of a locally looked up certificate could not be found", + "No certificates could be verified", + ], + ) # Test valid with intermediates and trusted root - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(bundle, True, True), ['The issuer certificate of a locally looked up certificate could not be found', 'No certificates could be verified']) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle(bundle, True, True), + [ + "The issuer certificate of a locally looked up certificate could not be found", + "No certificates could be verified", + ], + ) # Wrong key - bundle = self.mkPEMBundle('fra_cert.pem', 'ptolemy_key.pem', 'password', 'chain_subissuer-issuer-root.pem') + bundle = self.mkPEMBundle( + "fra_cert.pem", + "ptolemy_key.pem", + "password", + "chain_subissuer-issuer-root.pem", + ) # Test invalid bundle with intermediates and without trusted root - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(bundle), ['The root certificate of the certificate chain is self-signed, and untrusted', 'Private key does not match client certificate public key.']) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle(bundle), + [ + "The root certificate of the certificate chain is self-signed, and untrusted", + "Private key does not match client certificate public key.", + ], + ) # Test invalid without intermediates - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(bundle, False), ['The issuer certificate of a locally looked up certificate could not be found', 'No certificates could be verified', 'Private key does not match client certificate public key.']) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle(bundle, False), + [ + "The issuer certificate of a locally looked up certificate could not be found", + "No certificates could be verified", + "Private key does not match client certificate public key.", + ], + ) # Test invalid with intermediates and trusted root - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(bundle, True, True), ['Private key does not match client certificate public key.']) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle(bundle, True, True), + ["Private key does not match client certificate public key."], + ) # Expired root CA - bundle = self.mkPEMBundle('piri_cert.pem', 'piri_key.pem', 'password', 'chain_issuer3-root3-EXPIRED.pem') - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(bundle), ['The root certificate of the certificate chain is self-signed, and untrusted', 'The certificate has expired']) - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(bundle, False), ['The issuer certificate of a locally looked up certificate could not be found', 'No certificates could be verified']) - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(bundle, True, True), ['The root certificate of the certificate chain is self-signed, and untrusted', 'The certificate has expired']) + bundle = self.mkPEMBundle( + "piri_cert.pem", + "piri_key.pem", + "password", + "chain_issuer3-root3-EXPIRED.pem", + ) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle(bundle), + [ + "The root certificate of the certificate chain is self-signed, and untrusted", + "The certificate has expired", + ], + ) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle(bundle, False), + [ + "The issuer certificate of a locally looked up certificate could not be found", + "No certificates could be verified", + ], + ) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle(bundle, True, True), + [ + "The root certificate of the certificate chain is self-signed, and untrusted", + "The certificate has expired", + ], + ) # Expired intermediate CA - bundle = self.mkPEMBundle('marinus_cert-EXPIRED.pem', 'marinus_key_w-pass.pem', 'password', 'chain_issuer2-root2.pem') - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(bundle), ['The root certificate of the certificate chain is self-signed, and untrusted', 'The certificate has expired']) + bundle = self.mkPEMBundle( + "marinus_cert-EXPIRED.pem", + "marinus_key_w-pass.pem", + "password", + "chain_issuer2-root2.pem", + ) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle(bundle), + [ + "The root certificate of the certificate chain is self-signed, and untrusted", + "The certificate has expired", + ], + ) res = QgsAuthCertUtils.validatePKIBundle(bundle, False) - self.assertIn('The issuer certificate of a locally looked up certificate could not be found', res) - self.assertIn('No certificates could be verified', res) - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(bundle, True, True), ['The certificate has expired']) + self.assertIn( + "The issuer certificate of a locally looked up certificate could not be found", + res, + ) + self.assertIn("No certificates could be verified", res) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle(bundle, True, True), + ["The certificate has expired"], + ) # Expired client cert - bundle = self.mkPEMBundle('henricus_cert.pem', 'henricus_key_w-pass.pem', 'password', 'chain_issuer4-EXPIRED-root2.pem') - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(bundle), ['The root certificate of the certificate chain is self-signed, and untrusted', 'The certificate has expired']) - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(bundle, False), ['The issuer certificate of a locally looked up certificate could not be found', 'No certificates could be verified']) - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(bundle, True, True), ['The certificate has expired']) + bundle = self.mkPEMBundle( + "henricus_cert.pem", + "henricus_key_w-pass.pem", + "password", + "chain_issuer4-EXPIRED-root2.pem", + ) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle(bundle), + [ + "The root certificate of the certificate chain is self-signed, and untrusted", + "The certificate has expired", + ], + ) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle(bundle, False), + [ + "The issuer certificate of a locally looked up certificate could not be found", + "No certificates could be verified", + ], + ) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle(bundle, True, True), + ["The certificate has expired"], + ) # Untrusted root, positive test before untrust is applied - bundle = self.mkPEMBundle('nicholas_cert.pem', 'nicholas_key.pem', 'password', 'chain_issuer2-root2.pem') + bundle = self.mkPEMBundle( + "nicholas_cert.pem", + "nicholas_key.pem", + "password", + "chain_issuer2-root2.pem", + ) # Test valid with intermediates and trusted root self.assertEqual(QgsAuthCertUtils.validatePKIBundle(bundle, True, True), []) # Untrust this root - root2 = QgsAuthCertUtils.certFromFile(PKIDATA + '/' + 'root2_ca_cert.pem') + root2 = QgsAuthCertUtils.certFromFile(PKIDATA + "/" + "root2_ca_cert.pem") QgsApplication.authManager().storeCertAuthority(root2) - self.assertTrue(QgsApplication.authManager().storeCertTrustPolicy(root2, QgsAuthCertUtils.CertTrustPolicy.Untrusted)) + self.assertTrue( + QgsApplication.authManager().storeCertTrustPolicy( + root2, QgsAuthCertUtils.CertTrustPolicy.Untrusted + ) + ) QgsApplication.authManager().rebuildCaCertsCache() # Test valid with intermediates and untrusted root - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(bundle, True, True), ['The issuer certificate of a locally looked up certificate could not be found']) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle(bundle, True, True), + [ + "The issuer certificate of a locally looked up certificate could not be found" + ], + ) def test_160_cert_viable(self): """Text the viability of a given certificate""" @@ -766,7 +937,7 @@ def test_160_cert_viable(self): cert.clear() res.clear() # valid cert - cert = QgsAuthCertUtils.certFromFile(PKIDATA + '/gerardus_cert.pem') + cert = QgsAuthCertUtils.certFromFile(PKIDATA + "/gerardus_cert.pem") self.assertTrue(QgsAuthCertUtils.certIsCurrent(cert)) res = QgsAuthCertUtils.certViabilityErrors(cert) self.assertEqual(len(res), 0) @@ -775,7 +946,7 @@ def test_160_cert_viable(self): cert.clear() res.clear() # expired cert - cert = QgsAuthCertUtils.certFromFile(PKIDATA + '/marinus_cert-EXPIRED.pem') + cert = QgsAuthCertUtils.certFromFile(PKIDATA + "/marinus_cert-EXPIRED.pem") self.assertFalse(QgsAuthCertUtils.certIsCurrent(cert)) res = QgsAuthCertUtils.certViabilityErrors(cert) self.assertGreater(len(res), 0) @@ -785,26 +956,113 @@ def test_160_cert_viable(self): def test_170_pki_key_encoding(self): """Test that a DER/PEM RSA/DSA/EC keys can be opened whatever the extension is""" - self.assertFalse(QgsAuthCertUtils.keyFromFile(PKIDATA + '/' + 'ptolemy_key.pem').isNull()) - self.assertFalse(QgsAuthCertUtils.keyFromFile(PKIDATA + '/' + 'ptolemy_key.der').isNull()) - self.assertFalse(QgsAuthCertUtils.keyFromFile(PKIDATA + '/' + 'ptolemy_key_pem.key').isNull()) - self.assertFalse(QgsAuthCertUtils.keyFromFile(PKIDATA + '/' + 'ptolemy_key_der.key').isNull()) - self.assertFalse(QgsAuthCertUtils.keyFromFile(PKIDATA + '/' + 'donald_key_EC.pem').isNull()) - self.assertFalse(QgsAuthCertUtils.keyFromFile(PKIDATA + '/' + 'donald_key_EC.der').isNull()) - self.assertFalse(QgsAuthCertUtils.keyFromFile(PKIDATA + '/' + 'donald_key_DSA.pem').isNull()) - self.assertFalse(QgsAuthCertUtils.keyFromFile(PKIDATA + '/' + 'donald_key_DSA.der').isNull()) - self.assertFalse(QgsAuthCertUtils.keyFromFile(PKIDATA + '/' + 'donald_key_DSA_crlf.pem').isNull()) - self.assertFalse(QgsAuthCertUtils.keyFromFile(PKIDATA + '/' + 'donald_key_DSA_nonl.pem').isNull()) - donald_dsa = QgsAuthCertUtils.keyFromFile(PKIDATA + '/' + 'donald_key_DSA.pem').toPem() - self.assertEqual(donald_dsa, QgsAuthCertUtils.keyFromFile(PKIDATA + '/' + 'donald_key_DSA.der').toPem()) - self.assertEqual(donald_dsa, QgsAuthCertUtils.keyFromFile(PKIDATA + '/' + 'donald_key_DSA_crlf.pem').toPem()) - self.assertEqual(donald_dsa, QgsAuthCertUtils.keyFromFile(PKIDATA + '/' + 'donald_key_DSA_nonl.pem').toPem()) - - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(self.mkPEMBundle('ptolemy_cert.pem', 'ptolemy_key.pem', 'password', 'chain_subissuer-issuer-root.pem'), True, True), []) - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(self.mkPEMBundle('ptolemy_cert.pem', 'ptolemy_key.der', 'password', 'chain_subissuer-issuer-root.pem'), True, True), []) - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(self.mkPEMBundle('ptolemy_cert.pem', 'ptolemy_key_pem.key', 'password', 'chain_subissuer-issuer-root.pem'), True, True), []) - self.assertEqual(QgsAuthCertUtils.validatePKIBundle(self.mkPEMBundle('ptolemy_cert.pem', 'ptolemy_key_der.key', 'password', 'chain_subissuer-issuer-root.pem'), True, True), []) - - -if __name__ == '__main__': + self.assertFalse( + QgsAuthCertUtils.keyFromFile(PKIDATA + "/" + "ptolemy_key.pem").isNull() + ) + self.assertFalse( + QgsAuthCertUtils.keyFromFile(PKIDATA + "/" + "ptolemy_key.der").isNull() + ) + self.assertFalse( + QgsAuthCertUtils.keyFromFile(PKIDATA + "/" + "ptolemy_key_pem.key").isNull() + ) + self.assertFalse( + QgsAuthCertUtils.keyFromFile(PKIDATA + "/" + "ptolemy_key_der.key").isNull() + ) + self.assertFalse( + QgsAuthCertUtils.keyFromFile(PKIDATA + "/" + "donald_key_EC.pem").isNull() + ) + self.assertFalse( + QgsAuthCertUtils.keyFromFile(PKIDATA + "/" + "donald_key_EC.der").isNull() + ) + self.assertFalse( + QgsAuthCertUtils.keyFromFile(PKIDATA + "/" + "donald_key_DSA.pem").isNull() + ) + self.assertFalse( + QgsAuthCertUtils.keyFromFile(PKIDATA + "/" + "donald_key_DSA.der").isNull() + ) + self.assertFalse( + QgsAuthCertUtils.keyFromFile( + PKIDATA + "/" + "donald_key_DSA_crlf.pem" + ).isNull() + ) + self.assertFalse( + QgsAuthCertUtils.keyFromFile( + PKIDATA + "/" + "donald_key_DSA_nonl.pem" + ).isNull() + ) + donald_dsa = QgsAuthCertUtils.keyFromFile( + PKIDATA + "/" + "donald_key_DSA.pem" + ).toPem() + self.assertEqual( + donald_dsa, + QgsAuthCertUtils.keyFromFile(PKIDATA + "/" + "donald_key_DSA.der").toPem(), + ) + self.assertEqual( + donald_dsa, + QgsAuthCertUtils.keyFromFile( + PKIDATA + "/" + "donald_key_DSA_crlf.pem" + ).toPem(), + ) + self.assertEqual( + donald_dsa, + QgsAuthCertUtils.keyFromFile( + PKIDATA + "/" + "donald_key_DSA_nonl.pem" + ).toPem(), + ) + + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle( + self.mkPEMBundle( + "ptolemy_cert.pem", + "ptolemy_key.pem", + "password", + "chain_subissuer-issuer-root.pem", + ), + True, + True, + ), + [], + ) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle( + self.mkPEMBundle( + "ptolemy_cert.pem", + "ptolemy_key.der", + "password", + "chain_subissuer-issuer-root.pem", + ), + True, + True, + ), + [], + ) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle( + self.mkPEMBundle( + "ptolemy_cert.pem", + "ptolemy_key_pem.key", + "password", + "chain_subissuer-issuer-root.pem", + ), + True, + True, + ), + [], + ) + self.assertEqual( + QgsAuthCertUtils.validatePKIBundle( + self.mkPEMBundle( + "ptolemy_cert.pem", + "ptolemy_key_der.key", + "password", + "chain_subissuer-issuer-root.pem", + ), + True, + True, + ), + [], + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsauxiliarystorage.py b/tests/src/python/test_qgsauxiliarystorage.py index c562018f728b..98562b5f06e8 100644 --- a/tests/src/python/test_qgsauxiliarystorage.py +++ b/tests/src/python/test_qgsauxiliarystorage.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Paul Blottiere' -__date__ = '06/09/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Paul Blottiere" +__date__ = "06/09/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os @@ -47,33 +48,35 @@ def tmpPath(): f.close() os.remove(f.fileName()) - return f.fileName().replace('.', '_') + return f.fileName().replace(".", "_") def createLayer(): vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk', - 'test', 'memory') - assert (vl.isValid()) + "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk", + "test", + "memory", + ) + assert vl.isValid() f1 = QgsFeature() - f1.setAttributes([5, -200, NULL, 'NuLl', '5']) - f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)')) + f1.setAttributes([5, -200, NULL, "NuLl", "5"]) + f1.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)")) f2 = QgsFeature() - f2.setAttributes([3, 300, 'Pear', 'PEaR', '3']) + f2.setAttributes([3, 300, "Pear", "PEaR", "3"]) f3 = QgsFeature() - f3.setAttributes([1, 100, 'Orange', 'oranGe', '1']) - f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)')) + f3.setAttributes([1, 100, "Orange", "oranGe", "1"]) + f3.setGeometry(QgsGeometry.fromWkt("Point (-70.332 66.33)")) f4 = QgsFeature() - f4.setAttributes([2, 200, 'Apple', 'Apple', '2']) - f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)')) + f4.setAttributes([2, 200, "Apple", "Apple", "2"]) + f4.setGeometry(QgsGeometry.fromWkt("Point (-68.2 70.8)")) f5 = QgsFeature() - f5.setAttributes([4, 400, 'Honey', 'Honey', '4']) - f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)')) + f5.setAttributes([4, 400, "Honey", "Honey", "4"]) + f5.setGeometry(QgsGeometry.fromWkt("Point (-65.32 78.3)")) vl.dataProvider().addFeatures([f1, f2, f3, f4, f5]) return vl @@ -94,16 +97,18 @@ def testCreateSaveOpenStorageWithString(self): # Create a new auxiliary layer with 'pk' as key vl0 = createLayer() - pkf = vl0.fields().field(vl0.fields().indexOf('pk')) + pkf = vl0.fields().field(vl0.fields().indexOf("pk")) al0 = s0.createAuxiliaryLayer(pkf, vl0) self.assertTrue(al0.isValid()) # Test the auxiliary key key = al0.joinInfo().targetFieldName() - self.assertEqual(key, 'pk') + self.assertEqual(key, "pk") # Add a field in auxiliary layer - p = QgsPropertyDefinition('propName', QgsPropertyDefinition.DataType.DataTypeNumeric, '', '', 'user') + p = QgsPropertyDefinition( + "propName", QgsPropertyDefinition.DataType.DataTypeNumeric, "", "", "user" + ) self.assertTrue(al0.addAuxiliaryField(p)) # saveAs without saving the auxiliary layer, the auxiliary field is lost @@ -164,41 +169,45 @@ def testProjectStorage(self): # Create new layers with key otherwise auxiliary layers are not # automacially created when added in project vl0 = createLayer() - vl0Shp = writeShape(vl0, 'vl0.shp') + vl0Shp = writeShape(vl0, "vl0.shp") vl1 = createLayer() - vl1Shp = writeShape(vl1, 'vl1.shp') + vl1Shp = writeShape(vl1, "vl1.shp") - vl0 = QgsVectorLayer(vl0Shp, 'points', 'ogr') + vl0 = QgsVectorLayer(vl0Shp, "points", "ogr") self.assertTrue(vl0.isValid()) - vl1 = QgsVectorLayer(vl1Shp, 'points', 'ogr') + vl1 = QgsVectorLayer(vl1Shp, "points", "ogr") self.assertTrue(vl1.isValid()) # Add layers to project and check underlying auxiliary layers p0.addMapLayers([vl0, vl1]) - self.assertTrue(vl0.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'pk')) - self.assertTrue(vl1.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'num_char')) + self.assertTrue(vl0.loadAuxiliaryLayer(p0.auxiliaryStorage(), "pk")) + self.assertTrue(vl1.loadAuxiliaryLayer(p0.auxiliaryStorage(), "num_char")) al0 = vl0.auxiliaryLayer() al1 = vl1.auxiliaryLayer() - self.assertEqual(al0.joinInfo().targetFieldName(), 'pk') - self.assertEqual(al1.joinInfo().targetFieldName(), 'num_char') + self.assertEqual(al0.joinInfo().targetFieldName(), "pk") + self.assertEqual(al1.joinInfo().targetFieldName(), "num_char") # Add a field in auxiliary layers - pdef0 = QgsPropertyDefinition('propname', QgsPropertyDefinition.DataType.DataTypeNumeric, '', '', 'ut') + pdef0 = QgsPropertyDefinition( + "propname", QgsPropertyDefinition.DataType.DataTypeNumeric, "", "", "ut" + ) self.assertTrue(al0.addAuxiliaryField(pdef0)) - pdef1 = QgsPropertyDefinition('propname1', QgsPropertyDefinition.DataType.DataTypeString, '', '', 'ut') + pdef1 = QgsPropertyDefinition( + "propname1", QgsPropertyDefinition.DataType.DataTypeString, "", "", "ut" + ) self.assertTrue(al1.addAuxiliaryField(pdef1)) # Check auxiliary fields names af0Name = QgsAuxiliaryLayer.nameFromProperty(pdef0, False) - self.assertEqual(af0Name, 'ut_propname') + self.assertEqual(af0Name, "ut_propname") af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, False) - self.assertEqual(af1Name, 'ut_propname1') + self.assertEqual(af1Name, "ut_propname1") # Set value for auxiliary fields req = QgsFeatureRequest().setFilterExpression("name = 'Honey'") @@ -215,16 +224,16 @@ def testProjectStorage(self): self.assertTrue(f.isValid()) af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, True) index1 = vl1.fields().indexOf(af1Name) - vl1.changeAttributeValue(f.id(), index0, 'myvalue') + vl1.changeAttributeValue(f.id(), index0, "myvalue") req = QgsFeatureRequest().setFilterExpression("name = 'Orange'") f = QgsFeature() vl1.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) - vl1.changeAttributeValue(f.id(), index0, 'myvalue1') + vl1.changeAttributeValue(f.id(), index0, "myvalue1") # Save the project in a zip file - f = tmpPath() + '.qgz' + f = tmpPath() + ".qgz" p0.write(f) # Open the zip file with embedded auxiliary storage @@ -240,10 +249,10 @@ def testProjectStorage(self): af = al.auxiliaryFields()[0] afPropDef = QgsAuxiliaryLayer.propertyDefinitionFromField(af) - self.assertEqual(afPropDef.origin(), 'ut') + self.assertEqual(afPropDef.origin(), "ut") - if vl.auxiliaryLayer().joinInfo().targetFieldName() == 'pk': - self.assertEqual(afPropDef.name(), 'propname') + if vl.auxiliaryLayer().joinInfo().targetFieldName() == "pk": + self.assertEqual(afPropDef.name(), "propname") self.assertEqual(al.featureCount(), 1) req = QgsFeatureRequest().setFilterExpression("name = 'Honey'") @@ -253,19 +262,19 @@ def testProjectStorage(self): self.assertEqual(f.attributes()[index0], 333.0) else: # num_char self.assertEqual(al.featureCount(), 2) - self.assertEqual(afPropDef.name(), 'propname1') + self.assertEqual(afPropDef.name(), "propname1") req = QgsFeatureRequest().setFilterExpression("name = 'Apple'") f = QgsFeature() vl.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) - self.assertEqual(f.attributes()[index1], 'myvalue') + self.assertEqual(f.attributes()[index1], "myvalue") req = QgsFeatureRequest().setFilterExpression("name = 'Orange'") f = QgsFeature() vl.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) - self.assertEqual(f.attributes()[index1], 'myvalue1') + self.assertEqual(f.attributes()[index1], "myvalue1") def testAuxiliaryFieldWidgets(self): # Init storage @@ -274,7 +283,7 @@ def testAuxiliaryFieldWidgets(self): # Create a new auxiliary layer with 'pk' as key vl = createLayer() - pkf = vl.fields().field(vl.fields().indexOf('pk')) + pkf = vl.fields().field(vl.fields().indexOf("pk")) al = s.createAuxiliaryLayer(pkf, vl) self.assertTrue(al.isValid()) @@ -282,7 +291,9 @@ def testAuxiliaryFieldWidgets(self): vl.setAuxiliaryLayer(al) # Add a visible property - p = QgsPropertyDefinition('propName', QgsPropertyDefinition.DataType.DataTypeNumeric, '', '', 'user') + p = QgsPropertyDefinition( + "propName", QgsPropertyDefinition.DataType.DataTypeNumeric, "", "", "user" + ) self.assertTrue(al.addAuxiliaryField(p)) index = al.indexOfPropertyDefinition(p) @@ -291,7 +302,7 @@ def testAuxiliaryFieldWidgets(self): afName = QgsAuxiliaryLayer.nameFromProperty(p, True) index = vl.fields().indexOf(afName) setup = vl.editorWidgetSetup(index) - self.assertEqual(setup.type(), '') + self.assertEqual(setup.type(), "") tested = False for c in vl.attributeTableConfig().columns(): @@ -302,7 +313,9 @@ def testAuxiliaryFieldWidgets(self): self.assertTrue(tested) # Add a PAL hidden property - p = QgsPalLayerSettings.propertyDefinitions()[QgsPalLayerSettings.Property.PositionX] + p = QgsPalLayerSettings.propertyDefinitions()[ + QgsPalLayerSettings.Property.PositionX + ] self.assertTrue(al.addAuxiliaryField(p)) index = al.indexOfPropertyDefinition(p) @@ -311,7 +324,7 @@ def testAuxiliaryFieldWidgets(self): afName = QgsAuxiliaryLayer.nameFromProperty(p, True) index = vl.fields().indexOf(afName) setup = vl.editorWidgetSetup(index) - self.assertEqual(setup.type(), 'Hidden') + self.assertEqual(setup.type(), "Hidden") tested = False for c in vl.attributeTableConfig().columns(): @@ -322,7 +335,9 @@ def testAuxiliaryFieldWidgets(self): self.assertTrue(tested) # Add a PAL color property - p = QgsSymbolLayer.propertyDefinitions()[QgsSymbolLayer.Property.PropertyFillColor] + p = QgsSymbolLayer.propertyDefinitions()[ + QgsSymbolLayer.Property.PropertyFillColor + ] self.assertTrue(al.addAuxiliaryField(p)) index = al.indexOfPropertyDefinition(p) @@ -331,7 +346,7 @@ def testAuxiliaryFieldWidgets(self): afName = QgsAuxiliaryLayer.nameFromProperty(p, True) index = vl.fields().indexOf(afName) setup = vl.editorWidgetSetup(index) - self.assertEqual(setup.type(), 'Color') + self.assertEqual(setup.type(), "Color") # Add a symbol hidden property p = QgsSymbolLayer.propertyDefinitions()[QgsSymbolLayer.Property.PropertyAngle] @@ -343,7 +358,7 @@ def testAuxiliaryFieldWidgets(self): afName = QgsAuxiliaryLayer.nameFromProperty(p, True) index = vl.fields().indexOf(afName) setup = vl.editorWidgetSetup(index) - self.assertEqual(setup.type(), 'Hidden') + self.assertEqual(setup.type(), "Hidden") tested = False for c in vl.attributeTableConfig().columns(): @@ -366,13 +381,15 @@ def testClear(self): # Create a new auxiliary layer with 'pk' as key vl = createLayer() - pkf = vl.fields().field(vl.fields().indexOf('pk')) + pkf = vl.fields().field(vl.fields().indexOf("pk")) al = s.createAuxiliaryLayer(pkf, vl) self.assertTrue(al.isValid()) vl.setAuxiliaryLayer(al) # Add a field in auxiliary layer - p = QgsPropertyDefinition('myprop', QgsPropertyDefinition.DataType.DataTypeNumeric, '', '', 'me') + p = QgsPropertyDefinition( + "myprop", QgsPropertyDefinition.DataType.DataTypeNumeric, "", "", "me" + ) self.assertFalse(al.exists(p)) self.assertTrue(al.addAuxiliaryField(p)) self.assertTrue(al.exists(p)) @@ -402,7 +419,7 @@ def testSetAuxiliaryLayer(self): # Create a new auxiliary layer with 'pk' as key vl = createLayer() - pkf = vl.fields().field(vl.fields().indexOf('pk')) + pkf = vl.fields().field(vl.fields().indexOf("pk")) al = s.createAuxiliaryLayer(pkf, vl) self.assertTrue(al.isValid()) vl.setAuxiliaryLayer(al) @@ -422,7 +439,7 @@ def testCreateProperty(self): # Create a new auxiliary layer with 'pk' as key vl = createLayer() - pkf = vl.fields().field(vl.fields().indexOf('pk')) + pkf = vl.fields().field(vl.fields().indexOf("pk")) al = s.createAuxiliaryLayer(pkf, vl) self.assertTrue(al.isValid()) vl.setAuxiliaryLayer(al) @@ -443,7 +460,9 @@ def testCreateProperty(self): # with existing property key = QgsPalLayerSettings.Property.PositionY settings = QgsPalLayerSettings() - settings.dataDefinedProperties().setProperty(key, QgsProperty.fromExpression('$y + 20')) + settings.dataDefinedProperties().setProperty( + key, QgsProperty.fromExpression("$y + 20") + ) vl.setLabeling(QgsVectorLayerSimpleLabeling(settings)) # without overwriting existing, property should be upgraded to coalesce("aux field", 'existing expression') type @@ -455,12 +474,15 @@ def testCreateProperty(self): settings = vl.labeling().settings() self.assertTrue(settings.dataDefinedProperties().property(key).isActive()) - self.assertEqual(settings.dataDefinedProperties().property(key).asExpression(), 'coalesce("auxiliary_storage_labeling_positiony",$y + 20)') + self.assertEqual( + settings.dataDefinedProperties().property(key).asExpression(), + 'coalesce("auxiliary_storage_labeling_positiony",$y + 20)', + ) # with existing but invalid field name key = QgsPalLayerSettings.Property.PositionY settings = QgsPalLayerSettings() - settings.dataDefinedProperties().setProperty(key, QgsProperty.fromField('')) + settings.dataDefinedProperties().setProperty(key, QgsProperty.fromField("")) vl.setLabeling(QgsVectorLayerSimpleLabeling(settings)) # even when asked to not overwrite existing, this is an invalid property and should be overwritten @@ -472,12 +494,15 @@ def testCreateProperty(self): settings = vl.labeling().settings() self.assertTrue(settings.dataDefinedProperties().property(key).isActive()) - self.assertEqual(settings.dataDefinedProperties().property(key).asExpression(), '"auxiliary_storage_labeling_positiony"') + self.assertEqual( + settings.dataDefinedProperties().property(key).asExpression(), + '"auxiliary_storage_labeling_positiony"', + ) # with existing valid field name key = QgsPalLayerSettings.Property.PositionY settings = QgsPalLayerSettings() - settings.dataDefinedProperties().setProperty(key, QgsProperty.fromField('asd')) + settings.dataDefinedProperties().setProperty(key, QgsProperty.fromField("asd")) vl.setLabeling(QgsVectorLayerSimpleLabeling(settings)) index = QgsAuxiliaryLayer.createProperty(key, vl, False) @@ -488,12 +513,17 @@ def testCreateProperty(self): settings = vl.labeling().settings() self.assertTrue(settings.dataDefinedProperties().property(key).isActive()) - self.assertEqual(settings.dataDefinedProperties().property(key).asExpression(), 'coalesce("auxiliary_storage_labeling_positiony","asd")') + self.assertEqual( + settings.dataDefinedProperties().property(key).asExpression(), + 'coalesce("auxiliary_storage_labeling_positiony","asd")', + ) # with overwrite existing key = QgsPalLayerSettings.Property.Show settings = QgsPalLayerSettings() - settings.dataDefinedProperties().setProperty(key, QgsProperty.fromExpression('$y > 20')) + settings.dataDefinedProperties().setProperty( + key, QgsProperty.fromExpression("$y > 20") + ) vl.setLabeling(QgsVectorLayerSimpleLabeling(settings)) # existing property should be discarded @@ -505,7 +535,10 @@ def testCreateProperty(self): settings = vl.labeling().settings() self.assertTrue(settings.dataDefinedProperties().property(key).isActive()) - self.assertEqual(settings.dataDefinedProperties().property(key).field(), 'auxiliary_storage_labeling_show') + self.assertEqual( + settings.dataDefinedProperties().property(key).field(), + "auxiliary_storage_labeling_show", + ) def testCreateCalloutProperty(self): s = QgsAuxiliaryStorage() @@ -513,7 +546,7 @@ def testCreateCalloutProperty(self): # Create a new auxiliary layer with 'pk' as key vl = createLayer() - pkf = vl.fields().field(vl.fields().indexOf('pk')) + pkf = vl.fields().field(vl.fields().indexOf("pk")) al = s.createAuxiliaryLayer(pkf, vl) self.assertTrue(al.isValid()) vl.setAuxiliaryLayer(al) @@ -545,7 +578,10 @@ def testCreateCalloutProperty(self): self.assertEqual(index, afIndex) settings = vl.labeling().settings() - self.assertEqual(settings.callout().dataDefinedProperties().property(key), QgsProperty.fromField('auxiliary_storage_callouts_destinationx')) + self.assertEqual( + settings.callout().dataDefinedProperties().property(key), + QgsProperty.fromField("auxiliary_storage_callouts_destinationx"), + ) key2 = QgsCallout.Property.DestinationY index = QgsAuxiliaryLayer.createProperty(key2, vl) @@ -556,16 +592,22 @@ def testCreateCalloutProperty(self): self.assertEqual(index, afIndex) settings = vl.labeling().settings() - self.assertEqual(settings.callout().dataDefinedProperties().property(key), - QgsProperty.fromField('auxiliary_storage_callouts_destinationx')) - self.assertEqual(settings.callout().dataDefinedProperties().property(key2), - QgsProperty.fromField('auxiliary_storage_callouts_destinationy')) + self.assertEqual( + settings.callout().dataDefinedProperties().property(key), + QgsProperty.fromField("auxiliary_storage_callouts_destinationx"), + ) + self.assertEqual( + settings.callout().dataDefinedProperties().property(key2), + QgsProperty.fromField("auxiliary_storage_callouts_destinationy"), + ) # with existing property key = QgsCallout.Property.OriginX settings = QgsPalLayerSettings() callout = QgsSimpleLineCallout() - callout.dataDefinedProperties().setProperty(key, QgsProperty.fromExpression('$x + 20')) + callout.dataDefinedProperties().setProperty( + key, QgsProperty.fromExpression("$x + 20") + ) callout.setEnabled(True) settings.setCallout(callout) vl.setLabeling(QgsVectorLayerSimpleLabeling(settings)) @@ -578,13 +620,20 @@ def testCreateCalloutProperty(self): self.assertEqual(index, afIndex) settings = vl.labeling().settings() - self.assertTrue(settings.callout().dataDefinedProperties().property(key).isActive()) - self.assertEqual(settings.callout().dataDefinedProperties().property(key).asExpression(), 'coalesce("auxiliary_storage_callouts_originx",$x + 20)') + self.assertTrue( + settings.callout().dataDefinedProperties().property(key).isActive() + ) + self.assertEqual( + settings.callout().dataDefinedProperties().property(key).asExpression(), + 'coalesce("auxiliary_storage_callouts_originx",$x + 20)', + ) # with overwrite existing key = QgsCallout.Property.OriginY callout = QgsSimpleLineCallout() - callout.dataDefinedProperties().setProperty(key, QgsProperty.fromExpression('$y + 20')) + callout.dataDefinedProperties().setProperty( + key, QgsProperty.fromExpression("$y + 20") + ) settings.setCallout(callout) vl.setLabeling(QgsVectorLayerSimpleLabeling(settings)) @@ -596,8 +645,13 @@ def testCreateCalloutProperty(self): self.assertEqual(index, afIndex) settings = vl.labeling().settings() - self.assertTrue(settings.callout().dataDefinedProperties().property(key).isActive()) - self.assertEqual(settings.callout().dataDefinedProperties().property(key).field(), 'auxiliary_storage_callouts_originy') + self.assertTrue( + settings.callout().dataDefinedProperties().property(key).isActive() + ) + self.assertEqual( + settings.callout().dataDefinedProperties().property(key).field(), + "auxiliary_storage_callouts_originy", + ) def testCreatePropertyDiagram(self): s = QgsAuxiliaryStorage() @@ -605,7 +659,7 @@ def testCreatePropertyDiagram(self): # Create a new auxiliary layer with 'pk' as key vl = createLayer() - pkf = vl.fields().field(vl.fields().indexOf('pk')) + pkf = vl.fields().field(vl.fields().indexOf("pk")) al = s.createAuxiliaryLayer(pkf, vl) self.assertTrue(al.isValid()) vl.setAuxiliaryLayer(al) @@ -628,12 +682,17 @@ def testCreatePropertyDiagram(self): settings = vl.diagramLayerSettings() self.assertTrue(settings.dataDefinedProperties().property(key).isActive()) - self.assertEqual(settings.dataDefinedProperties().property(key).field(), "auxiliary_storage_diagram_positionx") + self.assertEqual( + settings.dataDefinedProperties().property(key).field(), + "auxiliary_storage_diagram_positionx", + ) # with existing property key = QgsDiagramLayerSettings.Property.Distance settings = QgsDiagramLayerSettings() - settings.dataDefinedProperties().setProperty(key, QgsProperty.fromExpression('$y + 20')) + settings.dataDefinedProperties().setProperty( + key, QgsProperty.fromExpression("$y + 20") + ) vl.setDiagramLayerSettings(settings) # without overwriting existing, property should be upgraded to coalesce("aux field", 'existing expression') type @@ -645,12 +704,17 @@ def testCreatePropertyDiagram(self): settings = vl.diagramLayerSettings() self.assertTrue(settings.dataDefinedProperties().property(key).isActive()) - self.assertEqual(settings.dataDefinedProperties().property(key).asExpression(), 'coalesce("auxiliary_storage_diagram_distance",$y + 20)') + self.assertEqual( + settings.dataDefinedProperties().property(key).asExpression(), + 'coalesce("auxiliary_storage_diagram_distance",$y + 20)', + ) # with overwrite existing key = QgsDiagramLayerSettings.Property.PositionY settings = QgsDiagramLayerSettings() - settings.dataDefinedProperties().setProperty(key, QgsProperty.fromExpression('$y > 20')) + settings.dataDefinedProperties().setProperty( + key, QgsProperty.fromExpression("$y > 20") + ) vl.setDiagramLayerSettings(settings) # existing property should be discarded @@ -662,7 +726,10 @@ def testCreatePropertyDiagram(self): settings = vl.diagramLayerSettings() self.assertTrue(settings.dataDefinedProperties().property(key).isActive()) - self.assertEqual(settings.dataDefinedProperties().property(key).field(), 'auxiliary_storage_diagram_positiony') + self.assertEqual( + settings.dataDefinedProperties().property(key).field(), + "auxiliary_storage_diagram_positiony", + ) def testCreateField(self): s = QgsAuxiliaryStorage() @@ -670,32 +737,34 @@ def testCreateField(self): # Create a new auxiliary layer with 'pk' as key vl = createLayer() - pkf = vl.fields().field(vl.fields().indexOf('pk')) + pkf = vl.fields().field(vl.fields().indexOf("pk")) al = s.createAuxiliaryLayer(pkf, vl) self.assertTrue(al.isValid()) vl.setAuxiliaryLayer(al) prop = QgsPropertyDefinition() - prop.setComment('test_field') + prop.setComment("test_field") prop.setDataType(QgsPropertyDefinition.DataType.DataTypeNumeric) - prop.setOrigin('user') - prop.setName('custom') + prop.setOrigin("user") + prop.setName("custom") self.assertTrue(al.addAuxiliaryField(prop)) prop = QgsPropertyDefinition() - prop.setComment('test_field_string') + prop.setComment("test_field_string") prop.setDataType(QgsPropertyDefinition.DataType.DataTypeString) - prop.setOrigin('user') - prop.setName('custom') + prop.setOrigin("user") + prop.setName("custom") self.assertTrue(al.addAuxiliaryField(prop)) self.assertEqual(len(al.auxiliaryFields()), 2) - self.assertEqual(al.auxiliaryFields()[0].name(), 'user_custom_test_field') + self.assertEqual(al.auxiliaryFields()[0].name(), "user_custom_test_field") self.assertEqual(al.auxiliaryFields()[0].type(), QVariant.Double) - self.assertEqual(al.auxiliaryFields()[0].typeName(), 'Real') - self.assertEqual(al.auxiliaryFields()[1].name(), 'user_custom_test_field_string') + self.assertEqual(al.auxiliaryFields()[0].typeName(), "Real") + self.assertEqual( + al.auxiliaryFields()[1].name(), "user_custom_test_field_string" + ) self.assertEqual(al.auxiliaryFields()[1].type(), QVariant.String) - self.assertEqual(al.auxiliaryFields()[1].typeName(), 'String') + self.assertEqual(al.auxiliaryFields()[1].typeName(), "String") def testQgdCreation(self): # New project @@ -704,12 +773,12 @@ def testQgdCreation(self): # Save the project path = tmpPath() - qgs = path + '.qgs' + qgs = path + ".qgs" self.assertTrue(p.write(qgs)) self.assertTrue(os.path.exists(qgs)) # Auxiliary storage is empty so .qgd file should not be saved - qgd = path + '.qgd' + qgd = path + ".qgd" self.assertFalse(os.path.exists(qgd)) # Add a vector layer and an auxiliary layer in the project @@ -717,31 +786,33 @@ def testQgdCreation(self): self.assertTrue(vl.isValid()) p.addMapLayers([vl]) - pkf = vl.fields().field(vl.fields().indexOf('pk')) + pkf = vl.fields().field(vl.fields().indexOf("pk")) al = p.auxiliaryStorage().createAuxiliaryLayer(pkf, vl) self.assertTrue(al.isValid()) vl.setAuxiliaryLayer(al) # Add an auxiliary field to have a non empty auxiliary storage - pdef = QgsPropertyDefinition('propname', QgsPropertyDefinition.DataType.DataTypeNumeric, '', '', 'ut') + pdef = QgsPropertyDefinition( + "propname", QgsPropertyDefinition.DataType.DataTypeNumeric, "", "", "ut" + ) self.assertTrue(al.addAuxiliaryField(pdef)) # Save the project newpath = tmpPath() - qgs = newpath + '.qgs' + qgs = newpath + ".qgs" self.assertTrue(p.write(qgs)) self.assertTrue(os.path.exists(qgs)) # Auxiliary storage is NOT empty so .qgd file should be saved now - qgd = newpath + '.qgd' + qgd = newpath + ".qgd" self.assertTrue(os.path.exists(qgd)) def testInvalidPrimaryKey(self): # create layer vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&key=pk', - 'test', 'memory') - assert (vl.isValid()) + "Point?crs=epsg:4326&field=pk:integer&key=pk", "test", "memory" + ) + assert vl.isValid() # add a field with an invalid typename field = QgsField(name="invalid_pk", type=QVariant.Int, typeName="xsd:int") @@ -764,7 +835,7 @@ def testQgdCreationInQgz(self): # Save the project path = tmpPath() - qgz = path + '.qgz' + qgz = path + ".qgz" self.assertTrue(p.write(qgz)) self.assertTrue(os.path.exists(qgz)) @@ -779,18 +850,20 @@ def testQgdCreationInQgz(self): self.assertTrue(vl.isValid()) p.addMapLayers([vl]) - pkf = vl.fields().field(vl.fields().indexOf('pk')) + pkf = vl.fields().field(vl.fields().indexOf("pk")) al = p.auxiliaryStorage().createAuxiliaryLayer(pkf, vl) self.assertTrue(al.isValid()) vl.setAuxiliaryLayer(al) # Add an auxiliary field to have a non empty auxiliary storage - pdef = QgsPropertyDefinition('propname', QgsPropertyDefinition.DataType.DataTypeNumeric, '', '', 'ut') + pdef = QgsPropertyDefinition( + "propname", QgsPropertyDefinition.DataType.DataTypeNumeric, "", "", "ut" + ) self.assertTrue(al.addAuxiliaryField(pdef)) # Save the project path = tmpPath() - qgz = path + '.qgz' + qgz = path + ".qgz" self.assertTrue(p.write(qgz)) self.assertTrue(os.path.exists(qgz)) @@ -798,7 +871,7 @@ def testQgdCreationInQgz(self): # because it's not empty archive = QgsProjectArchive() archive.unzip(qgz) - self.assertNotEqual(archive.auxiliaryStorageFile(), '') + self.assertNotEqual(archive.auxiliaryStorageFile(), "") def testAfterRemovingLayerFromProject(self): # init project @@ -806,33 +879,37 @@ def testAfterRemovingLayerFromProject(self): # add vector layers in project vl0 = createLayer() - vl0Shp = writeShape(vl0, 'vl0.shp') + vl0Shp = writeShape(vl0, "vl0.shp") vl1 = createLayer() - vl1Shp = writeShape(vl1, 'vl1.shp') + vl1Shp = writeShape(vl1, "vl1.shp") p0.addMapLayers([vl0, vl1]) # add auxiliary layer for vl0 - pkf = vl0.fields().field(vl0.fields().indexOf('pk')) + pkf = vl0.fields().field(vl0.fields().indexOf("pk")) al0 = p0.auxiliaryStorage().createAuxiliaryLayer(pkf, vl0) self.assertTrue(al0.isValid()) vl0.setAuxiliaryLayer(al0) - pdef = QgsPropertyDefinition('propname', QgsPropertyDefinition.DataType.DataTypeNumeric, '', '', 'ut') + pdef = QgsPropertyDefinition( + "propname", QgsPropertyDefinition.DataType.DataTypeNumeric, "", "", "ut" + ) self.assertTrue(al0.addAuxiliaryField(pdef)) # add auxiliary layer for vl1 - pkf = vl1.fields().field(vl1.fields().indexOf('pk')) + pkf = vl1.fields().field(vl1.fields().indexOf("pk")) al1 = p0.auxiliaryStorage().createAuxiliaryLayer(pkf, vl1) self.assertTrue(al1.isValid()) vl1.setAuxiliaryLayer(al1) - pdef = QgsPropertyDefinition('propname', QgsPropertyDefinition.DataType.DataTypeNumeric, '', '', 'ut') + pdef = QgsPropertyDefinition( + "propname", QgsPropertyDefinition.DataType.DataTypeNumeric, "", "", "ut" + ) self.assertTrue(al1.addAuxiliaryField(pdef)) # save project - f = tmpPath() + '.qgs' + f = tmpPath() + ".qgs" p0.write(f) # open project and check that auxiliary layers exist @@ -847,17 +924,17 @@ def testAfterRemovingLayerFromProject(self): qgd = p1.auxiliaryStorage().currentFileName() - layer = QgsVectorLayer(f"{qgd}|layername={vl0.id()}", 'test', 'ogr') + layer = QgsVectorLayer(f"{qgd}|layername={vl0.id()}", "test", "ogr") self.assertTrue(layer.isValid()) - layer = QgsVectorLayer(f"{qgd}|layername={vl1.id()}", 'test', 'ogr') + layer = QgsVectorLayer(f"{qgd}|layername={vl1.id()}", "test", "ogr") self.assertTrue(layer.isValid()) # remove layer from project p1.removeMapLayer(vl0.id()) # save project - f = tmpPath() + '.qgz' + f = tmpPath() + ".qgz" p1.write(f) # open project @@ -869,13 +946,13 @@ def testAfterRemovingLayerFromProject(self): qgd = p2.auxiliaryStorage().currentFileName() uri = f"{qgd}|layername={vl0.id()}" - layer = QgsVectorLayer(uri, 'test', 'ogr') + layer = QgsVectorLayer(uri, "test", "ogr") self.assertFalse(layer.isValid()) uri = f"{qgd}|layername={vl1.id()}" - layer = QgsVectorLayer(uri, 'test', 'ogr') + layer = QgsVectorLayer(uri, "test", "ogr") self.assertTrue(layer.isValid()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsbabelgpsformat.py b/tests/src/python/test_qgsbabelgpsformat.py index 25c1832828a9..8b6f739523a2 100644 --- a/tests/src/python/test_qgsbabelgpsformat.py +++ b/tests/src/python/test_qgsbabelgpsformat.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2021-07' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2021-07" +__copyright__ = "Copyright 2021, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication from qgis.core import ( @@ -39,63 +40,123 @@ def test_simple_format(self): """ Test QgsBabelSimpleImportFormat """ - f = QgsBabelSimpleImportFormat('shapefile', 'ESRI Shapefile', Qgis.BabelFormatCapability.Waypoints, ['shp', 'shx']) - self.assertEqual(f.name(), 'shapefile') - self.assertEqual(f.description(), 'ESRI Shapefile') - self.assertEqual(f.extensions(), ['shp', 'shx']) - self.assertEqual(f.capabilities(), Qgis.BabelFormatCapabilities( - Qgis.BabelFormatCapability.Waypoints | Qgis.BabelFormatCapability.Import)) - f = QgsBabelSimpleImportFormat('shapefile', 'ESRI Shapefile', Qgis.BabelFormatCapabilities( - Qgis.BabelFormatCapability.Waypoints | Qgis.BabelFormatCapability.Tracks)) - self.assertEqual(f.capabilities(), Qgis.BabelFormatCapabilities( - Qgis.BabelFormatCapability.Waypoints | Qgis.BabelFormatCapability.Tracks | Qgis.BabelFormatCapability.Import)) + f = QgsBabelSimpleImportFormat( + "shapefile", + "ESRI Shapefile", + Qgis.BabelFormatCapability.Waypoints, + ["shp", "shx"], + ) + self.assertEqual(f.name(), "shapefile") + self.assertEqual(f.description(), "ESRI Shapefile") + self.assertEqual(f.extensions(), ["shp", "shx"]) + self.assertEqual( + f.capabilities(), + Qgis.BabelFormatCapabilities( + Qgis.BabelFormatCapability.Waypoints | Qgis.BabelFormatCapability.Import + ), + ) + f = QgsBabelSimpleImportFormat( + "shapefile", + "ESRI Shapefile", + Qgis.BabelFormatCapabilities( + Qgis.BabelFormatCapability.Waypoints | Qgis.BabelFormatCapability.Tracks + ), + ) + self.assertEqual( + f.capabilities(), + Qgis.BabelFormatCapabilities( + Qgis.BabelFormatCapability.Waypoints + | Qgis.BabelFormatCapability.Tracks + | Qgis.BabelFormatCapability.Import + ), + ) self.assertEqual( - f.importCommand('babel.exe', Qgis.GpsFeatureType.Waypoint, 'c:/test/test.shp', 'c:/test/test.gpx'), - ['babel.exe', - '-w', - '-i', - 'shapefile', - '-o', - 'gpx', - 'c:/test/test.shp', - 'c:/test/test.gpx']) + f.importCommand( + "babel.exe", + Qgis.GpsFeatureType.Waypoint, + "c:/test/test.shp", + "c:/test/test.gpx", + ), + [ + "babel.exe", + "-w", + "-i", + "shapefile", + "-o", + "gpx", + "c:/test/test.shp", + "c:/test/test.gpx", + ], + ) self.assertEqual( - f.importCommand('babel.exe', Qgis.GpsFeatureType.Track, 'c:/test/test.shp', 'c:/test/test.gpx'), - ['babel.exe', - '-t', - '-i', - 'shapefile', - '-o', - 'gpx', - 'c:/test/test.shp', - 'c:/test/test.gpx']) + f.importCommand( + "babel.exe", + Qgis.GpsFeatureType.Track, + "c:/test/test.shp", + "c:/test/test.gpx", + ), + [ + "babel.exe", + "-t", + "-i", + "shapefile", + "-o", + "gpx", + "c:/test/test.shp", + "c:/test/test.gpx", + ], + ) self.assertEqual( - f.importCommand('babel.exe', Qgis.GpsFeatureType.Route, 'c:/test/test.shp', 'c:/test/test.gpx'), - ['babel.exe', - '-r', - '-i', - 'shapefile', - '-o', - 'gpx', - 'c:/test/test.shp', - 'c:/test/test.gpx']) + f.importCommand( + "babel.exe", + Qgis.GpsFeatureType.Route, + "c:/test/test.shp", + "c:/test/test.gpx", + ), + [ + "babel.exe", + "-r", + "-i", + "shapefile", + "-o", + "gpx", + "c:/test/test.shp", + "c:/test/test.gpx", + ], + ) # with quoted paths self.assertEqual( - f.importCommand('babel.exe', Qgis.GpsFeatureType.Route, 'c:/test/test.shp', 'c:/test/test.gpx', Qgis.BabelCommandFlag.QuoteFilePaths), - ['"babel.exe"', - '-r', - '-i', - 'shapefile', - '-o', - 'gpx', - '"c:/test/test.shp"', - '"c:/test/test.gpx"']) + f.importCommand( + "babel.exe", + Qgis.GpsFeatureType.Route, + "c:/test/test.shp", + "c:/test/test.gpx", + Qgis.BabelCommandFlag.QuoteFilePaths, + ), + [ + '"babel.exe"', + "-r", + "-i", + "shapefile", + "-o", + "gpx", + '"c:/test/test.shp"', + '"c:/test/test.gpx"', + ], + ) # export not supported self.assertEqual( - f.exportCommand('babel.exe', Qgis.GpsFeatureType.Waypoint, 'c:/test/test.shp', 'c:/test/test.gpx'), []) + f.exportCommand( + "babel.exe", + Qgis.GpsFeatureType.Waypoint, + "c:/test/test.shp", + "c:/test/test.gpx", + ), + [], + ) def test_gps_device_format(self): """ @@ -107,150 +168,208 @@ def test_gps_device_format(self): "%babel -r -i garmin -o gpx %in %out", "%babel -r -i gpx -o garmin %in %out", "%babel -t -i garmin -o gpx %in %out", - "%babel -t -i gpx -o garmin %in %out" + "%babel -t -i gpx -o garmin %in %out", ) # waypoint/track/route capability should be automatically set/removed # depending on whether the corresponding commands are empty - self.assertEqual(f.capabilities(), Qgis.BabelFormatCapabilities( - Qgis.BabelFormatCapability.Waypoints | Qgis.BabelFormatCapability.Import - | Qgis.BabelFormatCapability.Export | Qgis.BabelFormatCapability.Tracks | Qgis.BabelFormatCapability.Routes)) + self.assertEqual( + f.capabilities(), + Qgis.BabelFormatCapabilities( + Qgis.BabelFormatCapability.Waypoints + | Qgis.BabelFormatCapability.Import + | Qgis.BabelFormatCapability.Export + | Qgis.BabelFormatCapability.Tracks + | Qgis.BabelFormatCapability.Routes + ), + ) self.assertEqual( - f.importCommand('babel.exe', Qgis.GpsFeatureType.Waypoint, 'c:/test/test.shp', 'c:/test/test.gpx'), - ['babel.exe', - '-w', - '-i', - 'garmin', - '-o', - 'gpx', - 'c:/test/test.shp', - 'c:/test/test.gpx']) + f.importCommand( + "babel.exe", + Qgis.GpsFeatureType.Waypoint, + "c:/test/test.shp", + "c:/test/test.gpx", + ), + [ + "babel.exe", + "-w", + "-i", + "garmin", + "-o", + "gpx", + "c:/test/test.shp", + "c:/test/test.gpx", + ], + ) self.assertEqual( - f.importCommand('babel.exe', Qgis.GpsFeatureType.Track, 'c:/test/test.shp', 'c:/test/test.gpx'), - ['babel.exe', - '-t', - '-i', - 'garmin', - '-o', - 'gpx', - 'c:/test/test.shp', - 'c:/test/test.gpx']) + f.importCommand( + "babel.exe", + Qgis.GpsFeatureType.Track, + "c:/test/test.shp", + "c:/test/test.gpx", + ), + [ + "babel.exe", + "-t", + "-i", + "garmin", + "-o", + "gpx", + "c:/test/test.shp", + "c:/test/test.gpx", + ], + ) self.assertEqual( - f.importCommand('babel.exe', Qgis.GpsFeatureType.Route, 'c:/test/test.shp', 'c:/test/test.gpx'), - ['babel.exe', - '-r', - '-i', - 'garmin', - '-o', - 'gpx', - 'c:/test/test.shp', - 'c:/test/test.gpx']) + f.importCommand( + "babel.exe", + Qgis.GpsFeatureType.Route, + "c:/test/test.shp", + "c:/test/test.gpx", + ), + [ + "babel.exe", + "-r", + "-i", + "garmin", + "-o", + "gpx", + "c:/test/test.shp", + "c:/test/test.gpx", + ], + ) self.assertEqual( - f.exportCommand('babel.exe', Qgis.GpsFeatureType.Waypoint, 'c:/test/test.shp', 'c:/test/test.gpx'), - ['babel.exe', - '-w', - '-i', - 'gpx', - '-o', - 'garmin', - 'c:/test/test.shp', - 'c:/test/test.gpx']) + f.exportCommand( + "babel.exe", + Qgis.GpsFeatureType.Waypoint, + "c:/test/test.shp", + "c:/test/test.gpx", + ), + [ + "babel.exe", + "-w", + "-i", + "gpx", + "-o", + "garmin", + "c:/test/test.shp", + "c:/test/test.gpx", + ], + ) self.assertEqual( - f.exportCommand('babel.exe', Qgis.GpsFeatureType.Track, 'c:/test/test.shp', 'c:/test/test.gpx'), - ['babel.exe', - '-t', - '-i', - 'gpx', - '-o', - 'garmin', - 'c:/test/test.shp', - 'c:/test/test.gpx']) + f.exportCommand( + "babel.exe", + Qgis.GpsFeatureType.Track, + "c:/test/test.shp", + "c:/test/test.gpx", + ), + [ + "babel.exe", + "-t", + "-i", + "gpx", + "-o", + "garmin", + "c:/test/test.shp", + "c:/test/test.gpx", + ], + ) self.assertEqual( - f.exportCommand('babel.exe', Qgis.GpsFeatureType.Route, 'c:/test/test.shp', 'c:/test/test.gpx'), - ['babel.exe', - '-r', - '-i', - 'gpx', - '-o', - 'garmin', - 'c:/test/test.shp', - 'c:/test/test.gpx']) + f.exportCommand( + "babel.exe", + Qgis.GpsFeatureType.Route, + "c:/test/test.shp", + "c:/test/test.gpx", + ), + [ + "babel.exe", + "-r", + "-i", + "gpx", + "-o", + "garmin", + "c:/test/test.shp", + "c:/test/test.gpx", + ], + ) # with quoted paths self.assertEqual( - f.exportCommand('babel.exe', Qgis.GpsFeatureType.Route, 'c:/test/test.shp', 'c:/test/test.gpx', Qgis.BabelCommandFlag.QuoteFilePaths), - ['"babel.exe"', - '-r', - '-i', - 'gpx', - '-o', - 'garmin', - '"c:/test/test.shp"', - '"c:/test/test.gpx"']) + f.exportCommand( + "babel.exe", + Qgis.GpsFeatureType.Route, + "c:/test/test.shp", + "c:/test/test.gpx", + Qgis.BabelCommandFlag.QuoteFilePaths, + ), + [ + '"babel.exe"', + "-r", + "-i", + "gpx", + "-o", + "garmin", + '"c:/test/test.shp"', + '"c:/test/test.gpx"', + ], + ) # waypoint/track/route capability should be automatically set/removed # depending on whether the corresponding commands are empty f = QgsBabelGpsDeviceFormat( - "%babel -w -i garmin -o gpx %in %out", - None, - None, - None, - None, - None - ) - self.assertEqual(f.capabilities(), Qgis.BabelFormatCapabilities( - Qgis.BabelFormatCapability.Waypoints | Qgis.BabelFormatCapability.Import)) + "%babel -w -i garmin -o gpx %in %out", None, None, None, None, None + ) + self.assertEqual( + f.capabilities(), + Qgis.BabelFormatCapabilities( + Qgis.BabelFormatCapability.Waypoints | Qgis.BabelFormatCapability.Import + ), + ) f = QgsBabelGpsDeviceFormat( - None, - "%babel -w -i gpx -o garmin %in %out", - None, - None, - None, - None + None, "%babel -w -i gpx -o garmin %in %out", None, None, None, None + ) + self.assertEqual( + f.capabilities(), + Qgis.BabelFormatCapabilities( + Qgis.BabelFormatCapability.Waypoints | Qgis.BabelFormatCapability.Export + ), ) - self.assertEqual(f.capabilities(), Qgis.BabelFormatCapabilities( - Qgis.BabelFormatCapability.Waypoints | Qgis.BabelFormatCapability.Export)) f = QgsBabelGpsDeviceFormat( - None, - None, - "%babel -r -i garmin -o gpx %in %out", - None, - None, - None + None, None, "%babel -r -i garmin -o gpx %in %out", None, None, None + ) + self.assertEqual( + f.capabilities(), + Qgis.BabelFormatCapabilities( + Qgis.BabelFormatCapability.Routes | Qgis.BabelFormatCapability.Import + ), ) - self.assertEqual(f.capabilities(), Qgis.BabelFormatCapabilities( - Qgis.BabelFormatCapability.Routes | Qgis.BabelFormatCapability.Import)) f = QgsBabelGpsDeviceFormat( - None, - None, - None, - "%babel -r -i gpx -o garmin %in %out", - None, - None + None, None, None, "%babel -r -i gpx -o garmin %in %out", None, None + ) + self.assertEqual( + f.capabilities(), + Qgis.BabelFormatCapabilities( + Qgis.BabelFormatCapability.Routes | Qgis.BabelFormatCapability.Export + ), ) - self.assertEqual(f.capabilities(), Qgis.BabelFormatCapabilities( - Qgis.BabelFormatCapability.Routes | Qgis.BabelFormatCapability.Export)) f = QgsBabelGpsDeviceFormat( - None, - None, - None, - None, - "%babel -t -i garmin -o gpx %in %out", - None + None, None, None, None, "%babel -t -i garmin -o gpx %in %out", None + ) + self.assertEqual( + f.capabilities(), + Qgis.BabelFormatCapabilities( + Qgis.BabelFormatCapability.Tracks | Qgis.BabelFormatCapability.Import + ), ) - self.assertEqual(f.capabilities(), Qgis.BabelFormatCapabilities( - Qgis.BabelFormatCapability.Tracks | Qgis.BabelFormatCapability.Import)) f = QgsBabelGpsDeviceFormat( - None, - None, - None, - None, - None, - "%babel -t -i gpx -o garmin %in %out" - ) - self.assertEqual(f.capabilities(), Qgis.BabelFormatCapabilities( - Qgis.BabelFormatCapability.Tracks | Qgis.BabelFormatCapability.Export)) + None, None, None, None, None, "%babel -t -i gpx -o garmin %in %out" + ) + self.assertEqual( + f.capabilities(), + Qgis.BabelFormatCapabilities( + Qgis.BabelFormatCapability.Tracks | Qgis.BabelFormatCapability.Export + ), + ) def test_registry(self): """ @@ -259,31 +378,51 @@ def test_registry(self): self.assertIsNotNone(QgsApplication.gpsBabelFormatRegistry()) registry = QgsBabelFormatRegistry() - self.assertIn('garmin_poi', registry.importFormatNames()) - self.assertIn('dna', registry.importFormatNames()) + self.assertIn("garmin_poi", registry.importFormatNames()) + self.assertIn("dna", registry.importFormatNames()) - self.assertIsNone(registry.importFormat('aaaaaa')) - self.assertIsNotNone(registry.importFormat('dna')) - self.assertEqual(registry.importFormat('dna').name(), 'dna') - self.assertEqual(registry.importFormat('dna').description(), 'Navitrak DNA marker format') - self.assertEqual(registry.importFormat('dna').extensions(), ['dna']) + self.assertIsNone(registry.importFormat("aaaaaa")) + self.assertIsNotNone(registry.importFormat("dna")) + self.assertEqual(registry.importFormat("dna").name(), "dna") + self.assertEqual( + registry.importFormat("dna").description(), "Navitrak DNA marker format" + ) + self.assertEqual(registry.importFormat("dna").extensions(), ["dna"]) - self.assertIsNone(registry.importFormatByDescription('aaaaaa')) - self.assertEqual(registry.importFormatByDescription('Navitrak DNA marker format').name(), 'dna') - self.assertEqual(registry.importFormatByDescription('navitrak dna marker format').name(), 'dna') - self.assertEqual(registry.importFormatByDescription('PocketFMS flightplan (.xml)').name(), 'pocketfms_fp') + self.assertIsNone(registry.importFormatByDescription("aaaaaa")) + self.assertEqual( + registry.importFormatByDescription("Navitrak DNA marker format").name(), + "dna", + ) + self.assertEqual( + registry.importFormatByDescription("navitrak dna marker format").name(), + "dna", + ) + self.assertEqual( + registry.importFormatByDescription("PocketFMS flightplan (.xml)").name(), + "pocketfms_fp", + ) # see explanation in QgsBabelFormatRegistry::importFileFilter()! - self.assertEqual(registry.importFormatByDescription('PocketFMS flightplan [.xml]').name(), 'pocketfms_fp') + self.assertEqual( + registry.importFormatByDescription("PocketFMS flightplan [.xml]").name(), + "pocketfms_fp", + ) - self.assertIn(';;ESRI shapefile (*.shp);;', registry.importFileFilter()) - self.assertIn(';;PocketFMS flightplan [.xml] (*.xml);;', registry.importFileFilter()) + self.assertIn(";;ESRI shapefile (*.shp);;", registry.importFileFilter()) + self.assertIn( + ";;PocketFMS flightplan [.xml] (*.xml);;", registry.importFileFilter() + ) # should have only one device by default - self.assertEqual(registry.deviceNames(), ['Garmin serial']) - self.assertIsNotNone(registry.deviceFormat('Garmin serial')) - self.assertEqual(registry.deviceFormat('Garmin serial').importCommand('bb', Qgis.GpsFeatureType.Waypoint, 'in_file.shp', 'out_file.gpx'), - ['bb', '-w', '-i', 'garmin', '-o', 'gpx', 'in_file.shp', 'out_file.gpx']) + self.assertEqual(registry.deviceNames(), ["Garmin serial"]) + self.assertIsNotNone(registry.deviceFormat("Garmin serial")) + self.assertEqual( + registry.deviceFormat("Garmin serial").importCommand( + "bb", Qgis.GpsFeatureType.Waypoint, "in_file.shp", "out_file.gpx" + ), + ["bb", "-w", "-i", "garmin", "-o", "gpx", "in_file.shp", "out_file.gpx"], + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsbearingutils.py b/tests/src/python/test_qgsbearingutils.py index bf59c07798e9..28f4bdbd25fc 100644 --- a/tests/src/python/test_qgsbearingutils.py +++ b/tests/src/python/test_qgsbearingutils.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '18/10/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "18/10/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.core import ( @@ -25,33 +26,80 @@ class TestQgsBearingUtils(QgisTestCase): def testTrueNorth(self): - """ test calculating bearing to true north""" + """test calculating bearing to true north""" # short circuit - already a geographic crs crs = QgsCoordinateReferenceSystem.fromEpsgId(4326) transformContext = QgsCoordinateTransformContext() - self.assertEqual(QgsBearingUtils.bearingTrueNorth(crs, transformContext, QgsPointXY(0, 0)), 0) - self.assertEqual(QgsBearingUtils.bearingTrueNorth(crs, transformContext, QgsPointXY(44, 0)), 0) - self.assertEqual(QgsBearingUtils.bearingTrueNorth(crs, transformContext, QgsPointXY(44, -43)), 0) - self.assertEqual(QgsBearingUtils.bearingTrueNorth(crs, transformContext, QgsPointXY(44, 43)), 0) + self.assertEqual( + QgsBearingUtils.bearingTrueNorth(crs, transformContext, QgsPointXY(0, 0)), 0 + ) + self.assertEqual( + QgsBearingUtils.bearingTrueNorth(crs, transformContext, QgsPointXY(44, 0)), + 0, + ) + self.assertEqual( + QgsBearingUtils.bearingTrueNorth( + crs, transformContext, QgsPointXY(44, -43) + ), + 0, + ) + self.assertEqual( + QgsBearingUtils.bearingTrueNorth(crs, transformContext, QgsPointXY(44, 43)), + 0, + ) - self.assertEqual(QgsBearingUtils.bearingTrueNorth(crs, transformContext, QgsPointXY(44, 200)), 0) - self.assertEqual(QgsBearingUtils.bearingTrueNorth(crs, transformContext, QgsPointXY(44, -200)), 0) + self.assertEqual( + QgsBearingUtils.bearingTrueNorth( + crs, transformContext, QgsPointXY(44, 200) + ), + 0, + ) + self.assertEqual( + QgsBearingUtils.bearingTrueNorth( + crs, transformContext, QgsPointXY(44, -200) + ), + 0, + ) # no short circuit crs = QgsCoordinateReferenceSystem.fromEpsgId(3111) - self.assertAlmostEqual(QgsBearingUtils.bearingTrueNorth(crs, transformContext, QgsPointXY(2508807, 2423425)), 0.06, 2) + self.assertAlmostEqual( + QgsBearingUtils.bearingTrueNorth( + crs, transformContext, QgsPointXY(2508807, 2423425) + ), + 0.06, + 2, + ) # try a south-up crs crs = QgsCoordinateReferenceSystem.fromEpsgId(2053) - self.assertAlmostEqual(QgsBearingUtils.bearingTrueNorth(crs, transformContext, QgsPointXY(29, -27.55)), -180.0, 1) + self.assertAlmostEqual( + QgsBearingUtils.bearingTrueNorth( + crs, transformContext, QgsPointXY(29, -27.55) + ), + -180.0, + 1, + ) # try a north pole crs crs = QgsCoordinateReferenceSystem.fromEpsgId(3575) - self.assertAlmostEqual(QgsBearingUtils.bearingTrueNorth(crs, transformContext, QgsPointXY(-780770, 652329)), 129.9, 1) - self.assertAlmostEqual(QgsBearingUtils.bearingTrueNorth(crs, transformContext, QgsPointXY(513480, 873173)), -149.5, 1) + self.assertAlmostEqual( + QgsBearingUtils.bearingTrueNorth( + crs, transformContext, QgsPointXY(-780770, 652329) + ), + 129.9, + 1, + ) + self.assertAlmostEqual( + QgsBearingUtils.bearingTrueNorth( + crs, transformContext, QgsPointXY(513480, 873173) + ), + -149.5, + 1, + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsbinarywidget.py b/tests/src/python/test_qgsbinarywidget.py index afc087ce9158..4271d6f36173 100644 --- a/tests/src/python/test_qgsbinarywidget.py +++ b/tests/src/python/test_qgsbinarywidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '11/11/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "11/11/2018" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.PyQt.QtCore import QByteArray from qgis.core import NULL, QgsFeature, QgsGeometry, QgsPointXY, QgsVectorLayer @@ -29,11 +30,14 @@ def setUp(self): """ create a layer with one feature """ - self.layer = QgsVectorLayer("Point?crs=EPSG:21781&field=fldint:integer&field=fldbin:binary", - "addfeat", "memory") + self.layer = QgsVectorLayer( + "Point?crs=EPSG:21781&field=fldint:integer&field=fldbin:binary", + "addfeat", + "memory", + ) self.assertTrue(self.layer.isValid()) f = QgsFeature() - bin_1 = b'xxx' + bin_1 = b"xxx" bin_val1 = QByteArray(bin_1) f.setAttributes([123, bin_val1]) f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(600000, 200000))) @@ -43,9 +47,9 @@ def __createBinaryWidget(self): create a binary widget """ reg = QgsGui.editorWidgetRegistry() - configWdg = reg.createConfigWidget('Binary', self.layer, 1, None) + configWdg = reg.createConfigWidget("Binary", self.layer, 1, None) config = configWdg.config() - binary_widget = reg.create('Binary', self.layer, 1, config, None, None) + binary_widget = reg.create("Binary", self.layer, 1, config, None, None) return binary_widget def testValue(self): @@ -54,7 +58,7 @@ def testValue(self): self.assertFalse(widget.value()) - bin_2 = b'yyy' + bin_2 = b"yyy" bin_val2 = QByteArray(bin_2) widget.setValues(bin_val2, []) @@ -64,5 +68,5 @@ def testValue(self): self.assertEqual(widget.value(), QByteArray()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsblendmodes.py b/tests/src/python/test_qgsblendmodes.py index c1eb093f4b0e..ef72d8284642 100644 --- a/tests/src/python/test_qgsblendmodes.py +++ b/tests/src/python/test_qgsblendmodes.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'May 2013' -__copyright__ = '(C) 2013, Nyall Dawson, Massimo Endrighi' +__author__ = "Nyall Dawson" +__date__ = "May 2013" +__copyright__ = "(C) 2013, Nyall Dawson, Massimo Endrighi" import os import unittest @@ -49,31 +49,35 @@ def __init__(self, methodName): QgisTestCase.__init__(self, methodName) # create point layer - shp_file = os.path.join(TEST_DATA_DIR, 'points.shp') - self.point_layer = QgsVectorLayer(shp_file, 'Points', 'ogr') + shp_file = os.path.join(TEST_DATA_DIR, "points.shp") + self.point_layer = QgsVectorLayer(shp_file, "Points", "ogr") simplify_method = QgsVectorSimplifyMethod() - simplify_method.setSimplifyHints(QgsVectorSimplifyMethod.SimplifyHint.NoSimplification) + simplify_method.setSimplifyHints( + QgsVectorSimplifyMethod.SimplifyHint.NoSimplification + ) # create polygon layer - shp_file = os.path.join(TEST_DATA_DIR, 'polys.shp') - self.polygon_layer = QgsVectorLayer(shp_file, 'Polygons', 'ogr') + shp_file = os.path.join(TEST_DATA_DIR, "polys.shp") + self.polygon_layer = QgsVectorLayer(shp_file, "Polygons", "ogr") self.polygon_layer.setSimplifyMethod(simplify_method) # create line layer - shp_file = os.path.join(TEST_DATA_DIR, 'lines.shp') - self.line_layer = QgsVectorLayer(shp_file, 'Lines', 'ogr') + shp_file = os.path.join(TEST_DATA_DIR, "lines.shp") + self.line_layer = QgsVectorLayer(shp_file, "Lines", "ogr") self.line_layer.setSimplifyMethod(simplify_method) # create two raster layers - raster_file = os.path.join(TEST_DATA_DIR, 'rgb256x256.png') + raster_file = os.path.join(TEST_DATA_DIR, "rgb256x256.png") self.raster_layer1 = QgsRasterLayer(raster_file, "raster1") self.raster_layer2 = QgsRasterLayer(raster_file, "raster2") - multi_band_renderer1 = QgsMultiBandColorRenderer(self.raster_layer1.dataProvider(), 1, 2, - 3) + multi_band_renderer1 = QgsMultiBandColorRenderer( + self.raster_layer1.dataProvider(), 1, 2, 3 + ) self.raster_layer1.setRenderer(multi_band_renderer1) - multi_band_renderer2 = QgsMultiBandColorRenderer(self.raster_layer2.dataProvider(), 1, 2, - 3) + multi_band_renderer2 = QgsMultiBandColorRenderer( + self.raster_layer2.dataProvider(), 1, 2, 3 + ) self.raster_layer2.setRenderer(multi_band_renderer2) # to match blend modes test comparisons background @@ -83,8 +87,12 @@ def __init__(self, methodName): self.map_settings.setOutputSize(QSize(400, 400)) self.map_settings.setOutputDpi(96) - self.extent = QgsRectangle(-118.8888888888887720, 22.8002070393376783, - -83.3333333333331581, 46.8719806763287536) + self.extent = QgsRectangle( + -118.8888888888887720, + 22.8002070393376783, + -83.3333333333331581, + 46.8719806763287536, + ) def testVectorBlending(self): """Test that blend modes work for vector layers.""" @@ -94,20 +102,28 @@ def testVectorBlending(self): self.map_settings.setExtent(self.extent) # Set blending modes for both layers - self.line_layer.setBlendMode(QPainter.CompositionMode.CompositionMode_Difference) - self.polygon_layer.setBlendMode(QPainter.CompositionMode.CompositionMode_Difference) + self.line_layer.setBlendMode( + QPainter.CompositionMode.CompositionMode_Difference + ) + self.polygon_layer.setBlendMode( + QPainter.CompositionMode.CompositionMode_Difference + ) result = self.render_map_settings_check( - 'vector_blendmodes', - 'vector_blendmodes', + "vector_blendmodes", + "vector_blendmodes", self.map_settings, allowed_mismatch=20, - color_tolerance=1 + color_tolerance=1, ) # Reset layers - self.line_layer.setBlendMode(QPainter.CompositionMode.CompositionMode_SourceOver) - self.polygon_layer.setBlendMode(QPainter.CompositionMode.CompositionMode_SourceOver) + self.line_layer.setBlendMode( + QPainter.CompositionMode.CompositionMode_SourceOver + ) + self.polygon_layer.setBlendMode( + QPainter.CompositionMode.CompositionMode_SourceOver + ) self.assertTrue(result) @@ -119,18 +135,22 @@ def testVectorFeatureBlending(self): self.map_settings.setExtent(self.extent) # Set feature blending for line layer - self.line_layer.setFeatureBlendMode(QPainter.CompositionMode.CompositionMode_Plus) + self.line_layer.setFeatureBlendMode( + QPainter.CompositionMode.CompositionMode_Plus + ) result = self.render_map_settings_check( - 'vector_featureblendmodes', - 'vector_featureblendmodes', + "vector_featureblendmodes", + "vector_featureblendmodes", self.map_settings, allowed_mismatch=20, - color_tolerance=1 + color_tolerance=1, ) # Reset layers - self.line_layer.setFeatureBlendMode(QPainter.CompositionMode.CompositionMode_SourceOver) + self.line_layer.setFeatureBlendMode( + QPainter.CompositionMode.CompositionMode_SourceOver + ) self.assertTrue(result) @@ -145,11 +165,11 @@ def testVectorLayerOpacity(self): self.line_layer.setOpacity(0.5) result = self.render_map_settings_check( - 'vector_layertransparency', - 'vector_layertransparency', + "vector_layertransparency", + "vector_layertransparency", self.map_settings, allowed_mismatch=20, - color_tolerance=1 + color_tolerance=1, ) self.line_layer.setOpacity(1) @@ -162,17 +182,21 @@ def testRasterBlending(self): self.map_settings.setExtent(self.raster_layer1.extent()) # Set blending mode for top layer - self.raster_layer1.setBlendMode(QPainter.CompositionMode.CompositionMode_Difference) + self.raster_layer1.setBlendMode( + QPainter.CompositionMode.CompositionMode_Difference + ) result = self.render_map_settings_check( - 'raster_blendmodes', - 'raster_blendmodes', + "raster_blendmodes", + "raster_blendmodes", self.map_settings, allowed_mismatch=20, - color_tolerance=1 + color_tolerance=1, ) - self.raster_layer1.setBlendMode(QPainter.CompositionMode.CompositionMode_SourceOver) + self.raster_layer1.setBlendMode( + QPainter.CompositionMode.CompositionMode_SourceOver + ) self.assertTrue(result) @@ -187,5 +211,5 @@ def test_is_clipping_mode(self): self.assertTrue(QgsPainting.isClippingMode(Qgis.BlendMode.DestinationAtop)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsblockingnetworkrequest.py b/tests/src/python/test_qgsblockingnetworkrequest.py index 1b039b23224a..d1ae0981ac1d 100644 --- a/tests/src/python/test_qgsblockingnetworkrequest.py +++ b/tests/src/python/test_qgsblockingnetworkrequest.py @@ -6,9 +6,9 @@ (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '12/11/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' +__author__ = "Nyall Dawson" +__date__ = "12/11/2018" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.PyQt.QtCore import QUrl from qgis.PyQt.QtNetwork import QNetworkReply, QNetworkRequest @@ -47,10 +47,10 @@ def testFetchEmptyUrl(self): def testFetchBadUrl(self): request = QgsBlockingNetworkRequest() spy = QSignalSpy(request.finished) - err = request.get(QNetworkRequest(QUrl('http://x'))) + err = request.get(QNetworkRequest(QUrl("http://x"))) self.assertEqual(len(spy), 1) self.assertEqual(err, QgsBlockingNetworkRequest.ErrorCode.ServerExceptionError) - self.assertEqual(request.errorMessage(), 'Host x not found') + self.assertEqual(request.errorMessage(), "Host x not found") reply = request.reply() self.assertFalse(reply.content()) @@ -59,85 +59,148 @@ def testFetchBadUrl2(self): spy = QSignalSpy(request.finished) handler = mockedwebserver.SequentialHandler() - handler.add('GET', '/ffff', 404, {}, '\n\n \n \n Error response\n \n \n

    Error response

    \n

    Error code: 404

    \n

    Message: File not found.

    \n

    Error code explanation: HTTPStatus.NOT_FOUND - Nothing matches the given URI.

    \n \n\n') + handler.add( + "GET", + "/ffff", + 404, + {}, + '\n\n \n \n Error response\n \n \n

    Error response

    \n

    Error code: 404

    \n

    Message: File not found.

    \n

    Error code explanation: HTTPStatus.NOT_FOUND - Nothing matches the given URI.

    \n \n\n', + ) with mockedwebserver.install_http_handler(handler): - err = request.get(QNetworkRequest(QUrl('http://localhost:' + str(TestQgsBlockingNetworkRequest.port) + '/ffff'))) + err = request.get( + QNetworkRequest( + QUrl( + "http://localhost:" + + str(TestQgsBlockingNetworkRequest.port) + + "/ffff" + ) + ) + ) self.assertEqual(len(spy), 1) self.assertEqual(err, QgsBlockingNetworkRequest.ErrorCode.ServerExceptionError) - self.assertIn('Not Found', request.errorMessage()) + self.assertIn("Not Found", request.errorMessage()) reply = request.reply() self.assertEqual(reply.error(), QNetworkReply.NetworkError.ContentNotFoundError) - self.assertEqual(reply.content(), '\n\n \n \n Error response\n \n \n

    Error response

    \n

    Error code: 404

    \n

    Message: File not found.

    \n

    Error code explanation: HTTPStatus.NOT_FOUND - Nothing matches the given URI.

    \n \n\n') + self.assertEqual( + reply.content(), + '\n\n \n \n Error response\n \n \n

    Error response

    \n

    Error code: 404

    \n

    Message: File not found.

    \n

    Error code explanation: HTTPStatus.NOT_FOUND - Nothing matches the given URI.

    \n \n\n', + ) def testGet(self): request = QgsBlockingNetworkRequest() spy = QSignalSpy(request.finished) handler = mockedwebserver.SequentialHandler() - handler.add('GET', '/test.html', 200, {'Content-type': 'text/html'}, '\n') + handler.add( + "GET", "/test.html", 200, {"Content-type": "text/html"}, "\n" + ) with mockedwebserver.install_http_handler(handler): - err = request.get(QNetworkRequest(QUrl('http://localhost:' + str(TestQgsBlockingNetworkRequest.port) + '/test.html')), True) + err = request.get( + QNetworkRequest( + QUrl( + "http://localhost:" + + str(TestQgsBlockingNetworkRequest.port) + + "/test.html" + ) + ), + True, + ) self.assertEqual(len(spy), 1) self.assertEqual(err, QgsBlockingNetworkRequest.ErrorCode.NoError) - self.assertEqual(request.errorMessage(), '') + self.assertEqual(request.errorMessage(), "") reply = request.reply() self.assertEqual(reply.error(), QNetworkReply.NetworkError.NoError) - self.assertEqual(reply.content(), '\n') - self.assertEqual(reply.rawHeaderList(), [b'Server', - b'Date', - b'Content-type', - b'Content-Length']) - self.assertEqual(reply.rawHeader(b'Content-type'), 'text/html') - self.assertEqual(reply.rawHeader(b'xxxxxxxxx'), '') - self.assertEqual(reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute), 200) - self.assertEqual(reply.attribute(QNetworkRequest.Attribute.HttpReasonPhraseAttribute), 'OK') - self.assertEqual(reply.attribute(QNetworkRequest.Attribute.RedirectionTargetAttribute), None) + self.assertEqual(reply.content(), "\n") + self.assertEqual( + reply.rawHeaderList(), + [b"Server", b"Date", b"Content-type", b"Content-Length"], + ) + self.assertEqual(reply.rawHeader(b"Content-type"), "text/html") + self.assertEqual(reply.rawHeader(b"xxxxxxxxx"), "") + self.assertEqual( + reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute), 200 + ) + self.assertEqual( + reply.attribute(QNetworkRequest.Attribute.HttpReasonPhraseAttribute), "OK" + ) + self.assertEqual( + reply.attribute(QNetworkRequest.Attribute.RedirectionTargetAttribute), None + ) def testHead(self): request = QgsBlockingNetworkRequest() spy = QSignalSpy(request.finished) handler = mockedwebserver.SequentialHandler() - handler.add('HEAD', '/test.html', 200, {'Content-type': 'text/html'}) + handler.add("HEAD", "/test.html", 200, {"Content-type": "text/html"}) with mockedwebserver.install_http_handler(handler): - err = request.head(QNetworkRequest(QUrl('http://localhost:' + str(TestQgsBlockingNetworkRequest.port) + '/test.html')), True) + err = request.head( + QNetworkRequest( + QUrl( + "http://localhost:" + + str(TestQgsBlockingNetworkRequest.port) + + "/test.html" + ) + ), + True, + ) self.assertEqual(len(spy), 1) self.assertEqual(err, QgsBlockingNetworkRequest.ErrorCode.NoError) - self.assertEqual(request.errorMessage(), '') + self.assertEqual(request.errorMessage(), "") def testPost(self): request = QgsBlockingNetworkRequest() spy = QSignalSpy(request.finished) handler = mockedwebserver.SequentialHandler() - handler.add('POST', '/test.html', 200, expected_body=b"foo") + handler.add("POST", "/test.html", 200, expected_body=b"foo") with mockedwebserver.install_http_handler(handler): - req = QNetworkRequest(QUrl('http://localhost:' + str(TestQgsBlockingNetworkRequest.port) + '/test.html')) - req.setHeader(QNetworkRequest.KnownHeaders.ContentTypeHeader, 'text/plain') + req = QNetworkRequest( + QUrl( + "http://localhost:" + + str(TestQgsBlockingNetworkRequest.port) + + "/test.html" + ) + ) + req.setHeader(QNetworkRequest.KnownHeaders.ContentTypeHeader, "text/plain") err = request.post(req, b"foo") self.assertEqual(err, QgsBlockingNetworkRequest.ErrorCode.NoError) - self.assertEqual(request.errorMessage(), '') + self.assertEqual(request.errorMessage(), "") def testPut(self): request = QgsBlockingNetworkRequest() spy = QSignalSpy(request.finished) handler = mockedwebserver.SequentialHandler() - handler.add('PUT', '/test.html', 200, expected_body=b"foo") + handler.add("PUT", "/test.html", 200, expected_body=b"foo") with mockedwebserver.install_http_handler(handler): - req = QNetworkRequest(QUrl('http://localhost:' + str(TestQgsBlockingNetworkRequest.port) + '/test.html')) - req.setHeader(QNetworkRequest.KnownHeaders.ContentTypeHeader, 'text/plain') + req = QNetworkRequest( + QUrl( + "http://localhost:" + + str(TestQgsBlockingNetworkRequest.port) + + "/test.html" + ) + ) + req.setHeader(QNetworkRequest.KnownHeaders.ContentTypeHeader, "text/plain") err = request.put(req, b"foo") self.assertEqual(len(spy), 1) self.assertEqual(err, QgsBlockingNetworkRequest.ErrorCode.NoError) - self.assertEqual(request.errorMessage(), '') + self.assertEqual(request.errorMessage(), "") def testDelete(self): request = QgsBlockingNetworkRequest() spy = QSignalSpy(request.finished) handler = mockedwebserver.SequentialHandler() - handler.add('DELETE', '/test.html', 200) + handler.add("DELETE", "/test.html", 200) with mockedwebserver.install_http_handler(handler): - err = request.deleteResource(QNetworkRequest(QUrl('http://localhost:' + str(TestQgsBlockingNetworkRequest.port) + '/test.html'))) + err = request.deleteResource( + QNetworkRequest( + QUrl( + "http://localhost:" + + str(TestQgsBlockingNetworkRequest.port) + + "/test.html" + ) + ) + ) self.assertEqual(len(spy), 1) self.assertEqual(err, QgsBlockingNetworkRequest.ErrorCode.NoError) - self.assertEqual(request.errorMessage(), '') + self.assertEqual(request.errorMessage(), "") if __name__ == "__main__": diff --git a/tests/src/python/test_qgsblockingprocess.py b/tests/src/python/test_qgsblockingprocess.py index 107fa53cb6cc..55de3a785a7b 100644 --- a/tests/src/python/test_qgsblockingprocess.py +++ b/tests/src/python/test_qgsblockingprocess.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'January 2021' -__copyright__ = '(C) 2021, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "January 2021" +__copyright__ = "(C) 2021, Nyall Dawson" import os import tempfile @@ -38,45 +38,45 @@ class TestQgsBlockingProcess(QgisTestCase): def test_process_ok(self): def std_out(ba): - std_out.val += ba.data().decode('UTF-8') + std_out.val += ba.data().decode("UTF-8") - std_out.val = '' + std_out.val = "" def std_err(ba): - std_err.val += ba.data().decode('UTF-8') + std_err.val += ba.data().decode("UTF-8") - std_err.val = '' + std_err.val = "" - p = QgsBlockingProcess('ogrinfo', ['--version']) + p = QgsBlockingProcess("ogrinfo", ["--version"]) p.setStdOutHandler(std_out) p.setStdErrHandler(std_err) f = QgsFeedback() self.assertEqual(p.run(f), 0) self.assertEqual(p.exitStatus(), QProcess.ExitStatus.NormalExit) - self.assertIn('GDAL', std_out.val) - self.assertEqual(std_err.val, '') + self.assertIn("GDAL", std_out.val) + self.assertEqual(std_err.val, "") def test_process_err(self): def std_out(ba): - std_out.val += ba.data().decode('UTF-8') + std_out.val += ba.data().decode("UTF-8") - std_out.val = '' + std_out.val = "" def std_err(ba): - std_err.val += ba.data().decode('UTF-8') + std_err.val += ba.data().decode("UTF-8") - std_err.val = '' + std_err.val = "" - p = QgsBlockingProcess('ogrinfo', []) + p = QgsBlockingProcess("ogrinfo", []) p.setStdOutHandler(std_out) p.setStdErrHandler(std_err) f = QgsFeedback() self.assertEqual(p.run(f), 1) self.assertEqual(p.exitStatus(), QProcess.ExitStatus.NormalExit) - self.assertIn('Usage', std_out.val) - self.assertIn('FAILURE', std_err.val) + self.assertIn("Usage", std_out.val) + self.assertIn("FAILURE", std_err.val) def test_process_crash(self): """ @@ -84,23 +84,23 @@ def test_process_crash(self): """ temp_folder = tempfile.mkdtemp() - script_file = os.path.join(temp_folder, 'crash_process.sh') - with open(script_file, 'w') as f: - f.write('kill $$') + script_file = os.path.join(temp_folder, "crash_process.sh") + with open(script_file, "w") as f: + f.write("kill $$") os.chmod(script_file, 0o775) def std_out(ba): - std_out.val += ba.data().decode('UTF-8') + std_out.val += ba.data().decode("UTF-8") - std_out.val = '' + std_out.val = "" def std_err(ba): - std_err.val += ba.data().decode('UTF-8') + std_err.val += ba.data().decode("UTF-8") - std_err.val = '' + std_err.val = "" - p = QgsBlockingProcess('sh', [script_file]) + p = QgsBlockingProcess("sh", [script_file]) p.setStdOutHandler(std_out) p.setStdErrHandler(std_err) @@ -114,17 +114,17 @@ def test_process_no_file(self): """ def std_out(ba): - std_out.val += ba.data().decode('UTF-8') + std_out.val += ba.data().decode("UTF-8") - std_out.val = '' + std_out.val = "" def std_err(ba): - std_err.val += ba.data().decode('UTF-8') + std_err.val += ba.data().decode("UTF-8") - std_err.val = '' + std_err.val = "" # this program definitely doesn't exist! - p = QgsBlockingProcess('qgis_sucks', ['--version']) + p = QgsBlockingProcess("qgis_sucks", ["--version"]) p.setStdOutHandler(std_out) p.setStdErrHandler(std_err) @@ -139,24 +139,24 @@ def test_process_env(self): """ temp_folder = tempfile.mkdtemp() - script_file = os.path.join(temp_folder, 'process_env.sh') - with open(script_file, 'w') as f: - f.write('echo $my_var') + script_file = os.path.join(temp_folder, "process_env.sh") + with open(script_file, "w") as f: + f.write("echo $my_var") os.chmod(script_file, 0o775) def std_out(ba): - std_out.val += ba.data().decode('UTF-8') + std_out.val += ba.data().decode("UTF-8") - std_out.val = '' + std_out.val = "" def std_err(ba): - std_err.val += ba.data().decode('UTF-8') + std_err.val += ba.data().decode("UTF-8") - std_err.val = '' + std_err.val = "" # environment variable not set: - p = QgsBlockingProcess('sh', [script_file]) + p = QgsBlockingProcess("sh", [script_file]) p.setStdOutHandler(std_out) p.setStdErrHandler(std_err) @@ -167,32 +167,32 @@ def std_err(ba): self.assertFalse(std_err.val.strip()) # set environment variable - os.environ['my_var'] = 'my test variable' - std_out.val = '' - std_err.val = '' - p = QgsBlockingProcess('sh', [script_file]) + os.environ["my_var"] = "my test variable" + std_out.val = "" + std_err.val = "" + p = QgsBlockingProcess("sh", [script_file]) p.setStdOutHandler(std_out) p.setStdErrHandler(std_err) f = QgsFeedback() self.assertEqual(p.run(f), 0) self.assertEqual(p.exitStatus(), QProcess.ExitStatus.NormalExit) - self.assertEqual(std_out.val.strip(), 'my test variable') + self.assertEqual(std_out.val.strip(), "my test variable") self.assertFalse(std_err.val.strip()) # test python changing path - script_file = os.path.join(temp_folder, 'process_env_path.sh') - with open(script_file, 'w') as f: - f.write('echo $PATH') + script_file = os.path.join(temp_folder, "process_env_path.sh") + with open(script_file, "w") as f: + f.write("echo $PATH") - prev_path_val = os.getenv('PATH') + prev_path_val = os.getenv("PATH") new_path = f"/my_test/folder{os.pathsep}{prev_path_val}" - os.environ['PATH'] = new_path + os.environ["PATH"] = new_path - std_out.val = '' - std_err.val = '' - p = QgsBlockingProcess('sh', [script_file]) + std_out.val = "" + std_err.val = "" + p = QgsBlockingProcess("sh", [script_file]) p.setStdOutHandler(std_out) p.setStdErrHandler(std_err) @@ -203,5 +203,5 @@ def std_err(ba): self.assertFalse(std_err.val.strip()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsbookmarkmanager.py b/tests/src/python/test_qgsbookmarkmanager.py index 33f9f8ab0e06..aab16385c98f 100644 --- a/tests/src/python/test_qgsbookmarkmanager.py +++ b/tests/src/python/test_qgsbookmarkmanager.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2019 by Nyall Dawson' -__date__ = '02/09/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "(C) 2019 by Nyall Dawson" +__date__ = "02/09/2019" +__copyright__ = "Copyright 2019, The QGIS Project" import os @@ -59,55 +60,84 @@ def testBookmark(self): b = QgsBookmark() self.assertFalse(b.id()) self.assertFalse(b.name()) - b.setId('id') - self.assertEqual(b.id(), 'id') - b.setName('name') - self.assertEqual(b.name(), 'name') - b.setGroup('group') - self.assertEqual(b.group(), 'group') - b.setExtent(QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('EPSG:3111'))) - self.assertEqual(b.extent(), QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('EPSG:3111'))) + b.setId("id") + self.assertEqual(b.id(), "id") + b.setName("name") + self.assertEqual(b.name(), "name") + b.setGroup("group") + self.assertEqual(b.group(), "group") + b.setExtent( + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3111") + ) + ) + self.assertEqual( + b.extent(), + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3111") + ), + ) b.setRotation(45.4) self.assertEqual(b.rotation(), 45.4) def testBookmarkEquality(self): b = QgsBookmark() - b.setId('id') - b.setName('name') - b.setGroup('group') - b.setExtent(QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('EPSG:3111'))) + b.setId("id") + b.setName("name") + b.setGroup("group") + b.setExtent( + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3111") + ) + ) b2 = QgsBookmark() - b2.setId('id') - b2.setName('name') - b2.setGroup('group') - b2.setExtent(QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('EPSG:3111'))) + b2.setId("id") + b2.setName("name") + b2.setGroup("group") + b2.setExtent( + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3111") + ) + ) self.assertEqual(b, b2) - b2.setId('x') + b2.setId("x") self.assertNotEqual(b, b2) - b2.setId('id') + b2.setId("id") self.assertEqual(b, b2) - b2.setName('x') + b2.setName("x") self.assertNotEqual(b, b2) - b2.setName('name') + b2.setName("name") self.assertEqual(b, b2) - b2.setGroup('x') + b2.setGroup("x") self.assertNotEqual(b, b2) - b2.setGroup('group') + b2.setGroup("group") self.assertEqual(b, b2) b2.setRotation(-1) self.assertNotEqual(b, b2) b2.setRotation(0) self.assertEqual(b, b2) - b2.setExtent(QgsReferencedRectangle(QgsRectangle(1, 2, 3, 5), QgsCoordinateReferenceSystem('EPSG:3111'))) + b2.setExtent( + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 5), QgsCoordinateReferenceSystem("EPSG:3111") + ) + ) self.assertNotEqual(b, b2) - b2.setExtent(QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('EPSG:4326'))) + b2.setExtent( + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) self.assertNotEqual(b, b2) def testAddBookmark(self): project = QgsProject() b = QgsBookmark() - b.setName('b1') - b.setExtent(QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('EPSG:3111'))) + b.setName("b1") + b.setExtent( + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3111") + ) + ) manager = QgsBookmarkManager.createProjectBasedManager(project) @@ -121,8 +151,13 @@ def testAddBookmark(self): self.assertEqual(bookmark_added_spy[0][0], id) b = manager.bookmarkById(id) - self.assertEqual(b.name(), 'b1') - self.assertEqual(b.extent(), QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('EPSG:3111'))) + self.assertEqual(b.name(), "b1") + self.assertEqual( + b.extent(), + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3111") + ), + ) # adding it again should fail id, res = manager.addBookmark(b) @@ -130,21 +165,25 @@ def testAddBookmark(self): # try adding a second bookmark b2 = QgsBookmark() - b2.setId('my id') - b2.setName('b2') - b2.setExtent(QgsReferencedRectangle(QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem('EPSG:4326'))) + b2.setId("my id") + b2.setName("b2") + b2.setExtent( + QgsReferencedRectangle( + QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) id2, res = manager.addBookmark(b2) self.assertTrue(res) - self.assertEqual(id2, 'my id') + self.assertEqual(id2, "my id") self.assertEqual(len(bookmark_added_spy), 2) - self.assertEqual(bookmark_about_to_be_added_spy[1][0], 'my id') + self.assertEqual(bookmark_about_to_be_added_spy[1][0], "my id") self.assertEqual(len(bookmark_about_to_be_added_spy), 2) - self.assertEqual(bookmark_added_spy[1][0], 'my id') + self.assertEqual(bookmark_added_spy[1][0], "my id") # adding a bookmark with duplicate id should fail b3 = QgsBookmark() - b3.setId('my id') + b3.setId("my id") id, res = manager.addBookmark(b3) self.assertFalse(res) @@ -154,19 +193,31 @@ def testBookmarks(self): manager = QgsBookmarkManager.createProjectBasedManager(project) b = QgsBookmark() - b.setId('1') - b.setName('b1') - b.setExtent(QgsReferencedRectangle(QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem('EPSG:4326'))) + b.setId("1") + b.setName("b1") + b.setExtent( + QgsReferencedRectangle( + QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b2 = QgsBookmark() - b2.setId('2') - b2.setName('b2') - b2.setExtent(QgsReferencedRectangle(QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem('EPSG:4326'))) + b2.setId("2") + b2.setName("b2") + b2.setExtent( + QgsReferencedRectangle( + QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b3 = QgsBookmark() - b3.setId('3') - b3.setName('b3') - b3.setExtent(QgsReferencedRectangle(QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem('EPSG:4326'))) + b3.setId("3") + b3.setName("b3") + b3.setExtent( + QgsReferencedRectangle( + QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) manager.addBookmark(b) self.assertEqual(manager.bookmarks(), [b]) @@ -180,51 +231,57 @@ def testBookmarkGroups(self): manager = QgsBookmarkManager.createProjectBasedManager(project) b = QgsBookmark() - b.setId('1') - b.setName('b1') + b.setId("1") + b.setName("b1") manager.addBookmark(b) b2 = QgsBookmark() - b2.setId('2') - b2.setName('b2') - b2.setGroup('group1') + b2.setId("2") + b2.setName("b2") + b2.setGroup("group1") manager.addBookmark(b2) b3 = QgsBookmark() - b3.setId('3') - b3.setName('b3') - b3.setGroup('group2') + b3.setId("3") + b3.setName("b3") + b3.setGroup("group2") manager.addBookmark(b3) # test that groups are adjusted when bookmarks are added - self.assertEqual(manager.groups(), ['', 'group1', 'group2']) + self.assertEqual(manager.groups(), ["", "group1", "group2"]) - manager.removeBookmark('3') + manager.removeBookmark("3") # test that groups are adjusted when a bookmark is removed - self.assertEqual(manager.groups(), ['', 'group1']) + self.assertEqual(manager.groups(), ["", "group1"]) - b2.setGroup('groupmodified') + b2.setGroup("groupmodified") manager.updateBookmark(b2) # test that groups are adjusted when a bookmark group is edited - self.assertEqual(manager.groups(), ['', 'groupmodified']) + self.assertEqual(manager.groups(), ["", "groupmodified"]) def bookmarkAboutToBeRemoved(self, id): # bookmark should still exist at this time - self.assertEqual(id, '1') - self.assertTrue(self.manager.bookmarkById('1').name()) + self.assertEqual(id, "1") + self.assertTrue(self.manager.bookmarkById("1").name()) self.aboutFired = True def testRemoveBookmark(self): project = QgsProject() b = QgsBookmark() - b.setId('1') - b.setName('b1') - b.setExtent(QgsReferencedRectangle(QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem('EPSG:4326'))) + b.setId("1") + b.setName("b1") + b.setExtent( + QgsReferencedRectangle( + QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) self.manager = QgsBookmarkManager.createProjectBasedManager(project) bookmark_removed_spy = QSignalSpy(self.manager.bookmarkRemoved) - bookmark_about_to_be_removed_spy = QSignalSpy(self.manager.bookmarkAboutToBeRemoved) + bookmark_about_to_be_removed_spy = QSignalSpy( + self.manager.bookmarkAboutToBeRemoved + ) # tests that bookmark still exists when bookmarkAboutToBeRemoved is fired self.manager.bookmarkAboutToBeRemoved.connect(self.bookmarkAboutToBeRemoved) @@ -238,9 +295,9 @@ def testRemoveBookmark(self): self.assertTrue(self.manager.removeBookmark(b.id())) self.assertEqual(len(self.manager.bookmarks()), 0) self.assertEqual(len(bookmark_removed_spy), 1) - self.assertEqual(bookmark_removed_spy[0][0], '1') + self.assertEqual(bookmark_removed_spy[0][0], "1") self.assertEqual(len(bookmark_about_to_be_removed_spy), 1) - self.assertEqual(bookmark_about_to_be_removed_spy[0][0], '1') + self.assertEqual(bookmark_about_to_be_removed_spy[0][0], "1") self.assertTrue(self.aboutFired) self.manager = None @@ -250,19 +307,31 @@ def testClear(self): # add a bunch of bookmarks b = QgsBookmark() - b.setId('1') - b.setName('b1') - b.setExtent(QgsReferencedRectangle(QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem('EPSG:4326'))) + b.setId("1") + b.setName("b1") + b.setExtent( + QgsReferencedRectangle( + QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b2 = QgsBookmark() - b2.setId('2') - b2.setName('b2') - b2.setExtent(QgsReferencedRectangle(QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem('EPSG:4326'))) + b2.setId("2") + b2.setName("b2") + b2.setExtent( + QgsReferencedRectangle( + QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b3 = QgsBookmark() - b3.setId('3') - b3.setName('b3') - b3.setExtent(QgsReferencedRectangle(QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem('EPSG:4326'))) + b3.setId("3") + b3.setName("b3") + b3.setExtent( + QgsReferencedRectangle( + QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) manager.addBookmark(b) manager.addBookmark(b2) @@ -281,28 +350,40 @@ def testBookmarksById(self): # add a bunch of bookmarks b = QgsBookmark() - b.setId('1') - b.setName('b1') - b.setExtent(QgsReferencedRectangle(QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem('EPSG:4326'))) + b.setId("1") + b.setName("b1") + b.setExtent( + QgsReferencedRectangle( + QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b2 = QgsBookmark() - b2.setId('2') - b2.setName('b2') - b2.setExtent(QgsReferencedRectangle(QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem('EPSG:4326'))) + b2.setId("2") + b2.setName("b2") + b2.setExtent( + QgsReferencedRectangle( + QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b3 = QgsBookmark() - b3.setId('3') - b3.setName('b3') - b3.setExtent(QgsReferencedRectangle(QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem('EPSG:4326'))) + b3.setId("3") + b3.setName("b3") + b3.setExtent( + QgsReferencedRectangle( + QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) manager.addBookmark(b) manager.addBookmark(b2) manager.addBookmark(b3) - self.assertFalse(manager.bookmarkById('asdf').name()) - self.assertEqual(manager.bookmarkById('1'), b) - self.assertEqual(manager.bookmarkById('2'), b2) - self.assertEqual(manager.bookmarkById('3'), b3) + self.assertFalse(manager.bookmarkById("asdf").name()) + self.assertEqual(manager.bookmarkById("1"), b) + self.assertEqual(manager.bookmarkById("2"), b2) + self.assertEqual(manager.bookmarkById("3"), b3) def testReadWriteXml(self): """ @@ -313,21 +394,33 @@ def testReadWriteXml(self): # add a bunch of bookmarks b = QgsBookmark() - b.setId('1') - b.setName('b1') - b.setExtent(QgsReferencedRectangle(QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem('EPSG:3857'))) + b.setId("1") + b.setName("b1") + b.setExtent( + QgsReferencedRectangle( + QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem("EPSG:3857") + ) + ) b.setRotation(90) b2 = QgsBookmark() - b2.setId('2') - b2.setName('b2') - b2.setExtent(QgsReferencedRectangle(QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem('EPSG:4326'))) + b2.setId("2") + b2.setName("b2") + b2.setExtent( + QgsReferencedRectangle( + QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b2.setRotation(-1.1) b3 = QgsBookmark() - b3.setId('3') - b3.setName('b3') - b3.setExtent(QgsReferencedRectangle(QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem('EPSG:4326'))) + b3.setId("3") + b3.setName("b3") + b3.setExtent( + QgsReferencedRectangle( + QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b3.setRotation(280) manager.addBookmark(b) @@ -347,22 +440,37 @@ def testReadWriteXml(self): self.assertEqual(len(manager2.bookmarks()), 3) # Check b1 values - self.assertEqual(manager2.bookmarkById('1').name(), 'b1') - self.assertEqual(manager2.bookmarkById('1').extent(), QgsReferencedRectangle(QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem('EPSG:3857'))) - self.assertEqual(manager2.bookmarkById('1').rotation(), 90) + self.assertEqual(manager2.bookmarkById("1").name(), "b1") + self.assertEqual( + manager2.bookmarkById("1").extent(), + QgsReferencedRectangle( + QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem("EPSG:3857") + ), + ) + self.assertEqual(manager2.bookmarkById("1").rotation(), 90) # Check b2 values - self.assertEqual(manager2.bookmarkById('2').name(), 'b2') - self.assertEqual(manager2.bookmarkById('2').extent(), QgsReferencedRectangle(QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem('EPSG:4326'))) - self.assertEqual(manager2.bookmarkById('2').rotation(), -1.1) + self.assertEqual(manager2.bookmarkById("2").name(), "b2") + self.assertEqual( + manager2.bookmarkById("2").extent(), + QgsReferencedRectangle( + QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem("EPSG:4326") + ), + ) + self.assertEqual(manager2.bookmarkById("2").rotation(), -1.1) # Check b3 values - self.assertEqual(manager2.bookmarkById('3').name(), 'b3') - self.assertEqual(manager2.bookmarkById('3').extent(), QgsReferencedRectangle(QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem('EPSG:4326'))) - self.assertEqual(manager2.bookmarkById('3').rotation(), 280) + self.assertEqual(manager2.bookmarkById("3").name(), "b3") + self.assertEqual( + manager2.bookmarkById("3").extent(), + QgsReferencedRectangle( + QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem("EPSG:4326") + ), + ) + self.assertEqual(manager2.bookmarkById("3").rotation(), 280) names = [c.name() for c in manager2.bookmarks()] - self.assertCountEqual(names, ['b1', 'b2', 'b3']) + self.assertCountEqual(names, ["b1", "b2", "b3"]) def testUpdateBookmark(self): project = QgsProject() @@ -370,58 +478,84 @@ def testUpdateBookmark(self): changed_spy = QSignalSpy(manager.bookmarkChanged) b = QgsBookmark() - b.setId('1') - b.setName('b1') - b.setExtent(QgsReferencedRectangle(QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem('EPSG:4326'))) + b.setId("1") + b.setName("b1") + b.setExtent( + QgsReferencedRectangle( + QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) self.assertFalse(manager.updateBookmark(b)) self.assertEqual(len(changed_spy), 0) manager.addBookmark(b) - b.setName('new b1') + b.setName("new b1") self.assertTrue(manager.updateBookmark(b)) - self.assertEqual(manager.bookmarkById('1').name(), 'new b1') + self.assertEqual(manager.bookmarkById("1").name(), "new b1") self.assertEqual(len(changed_spy), 1) - self.assertEqual(changed_spy[-1][0], '1') + self.assertEqual(changed_spy[-1][0], "1") b2 = QgsBookmark() - b2.setId('2') - b2.setName('b2') - b2.setExtent(QgsReferencedRectangle(QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem('EPSG:4326'))) + b2.setId("2") + b2.setName("b2") + b2.setExtent( + QgsReferencedRectangle( + QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) manager.addBookmark(b2) - b.setName('new b1 2') - b2.setName('new b2 2') + b.setName("new b1 2") + b2.setName("new b2 2") self.assertTrue(manager.updateBookmark(b)) - self.assertEqual(manager.bookmarkById('1').name(), 'new b1 2') - self.assertEqual(manager.bookmarkById('2').name(), 'b2') + self.assertEqual(manager.bookmarkById("1").name(), "new b1 2") + self.assertEqual(manager.bookmarkById("2").name(), "b2") self.assertEqual(len(changed_spy), 2) - self.assertEqual(changed_spy[-1][0], '1') + self.assertEqual(changed_spy[-1][0], "1") self.assertTrue(manager.updateBookmark(b2)) - self.assertEqual(manager.bookmarkById('1').name(), 'new b1 2') - self.assertEqual(manager.bookmarkById('2').name(), 'new b2 2') + self.assertEqual(manager.bookmarkById("1").name(), "new b1 2") + self.assertEqual(manager.bookmarkById("2").name(), "new b2 2") self.assertEqual(len(changed_spy), 3) - self.assertEqual(changed_spy[-1][0], '2') + self.assertEqual(changed_spy[-1][0], "2") def testOldBookmarks(self): """ Test upgrading older bookmark storage format """ - project_path = os.path.join(TEST_DATA_DIR, 'projects', 'old_bookmarks.qgs') + project_path = os.path.join(TEST_DATA_DIR, "projects", "old_bookmarks.qgs") p = QgsProject() self.assertTrue(p.read(project_path)) self.assertEqual(len(p.bookmarkManager().bookmarks()), 3) - self.assertEqual(p.bookmarkManager().bookmarkById('bookmark_0').name(), 'b1') - self.assertEqual(p.bookmarkManager().bookmarkById('bookmark_0').extent().crs().authid(), 'EPSG:4283') - self.assertEqual(p.bookmarkManager().bookmarkById('bookmark_0').extent().toString(1), '150.0,-23.0 : 150.6,-22.0') - - self.assertEqual(p.bookmarkManager().bookmarkById('bookmark_1').name(), 'b2') - self.assertEqual(p.bookmarkManager().bookmarkById('bookmark_1').extent().crs().authid(), 'EPSG:4283') - self.assertEqual(p.bookmarkManager().bookmarkById('bookmark_1').extent().toString(1), '149.0,-21.6 : 149.4,-21.1') - - self.assertEqual(p.bookmarkManager().bookmarkById('bookmark_2').name(), 'b3') - self.assertEqual(p.bookmarkManager().bookmarkById('bookmark_2').extent().crs().authid(), 'EPSG:28355') - self.assertEqual(p.bookmarkManager().bookmarkById('bookmark_2').extent().toString(1), '807985.7,7450916.9 : 876080.0,7564407.4') + self.assertEqual(p.bookmarkManager().bookmarkById("bookmark_0").name(), "b1") + self.assertEqual( + p.bookmarkManager().bookmarkById("bookmark_0").extent().crs().authid(), + "EPSG:4283", + ) + self.assertEqual( + p.bookmarkManager().bookmarkById("bookmark_0").extent().toString(1), + "150.0,-23.0 : 150.6,-22.0", + ) + + self.assertEqual(p.bookmarkManager().bookmarkById("bookmark_1").name(), "b2") + self.assertEqual( + p.bookmarkManager().bookmarkById("bookmark_1").extent().crs().authid(), + "EPSG:4283", + ) + self.assertEqual( + p.bookmarkManager().bookmarkById("bookmark_1").extent().toString(1), + "149.0,-21.6 : 149.4,-21.1", + ) + + self.assertEqual(p.bookmarkManager().bookmarkById("bookmark_2").name(), "b3") + self.assertEqual( + p.bookmarkManager().bookmarkById("bookmark_2").extent().crs().authid(), + "EPSG:28355", + ) + self.assertEqual( + p.bookmarkManager().bookmarkById("bookmark_2").extent().toString(1), + "807985.7,7450916.9 : 876080.0,7564407.4", + ) def testFileStorage(self): """ @@ -436,19 +570,31 @@ def testFileStorage(self): # add a bunch of bookmarks b = QgsBookmark() - b.setId('1') - b.setName('b1') - b.setExtent(QgsReferencedRectangle(QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem('EPSG:4326'))) + b.setId("1") + b.setName("b1") + b.setExtent( + QgsReferencedRectangle( + QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b2 = QgsBookmark() - b2.setId('2') - b2.setName('b2') - b2.setExtent(QgsReferencedRectangle(QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem('EPSG:4326'))) + b2.setId("2") + b2.setName("b2") + b2.setExtent( + QgsReferencedRectangle( + QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b3 = QgsBookmark() - b3.setId('3') - b3.setName('b3') - b3.setExtent(QgsReferencedRectangle(QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem('EPSG:4326'))) + b3.setId("3") + b3.setName("b3") + b3.setExtent( + QgsReferencedRectangle( + QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) manager.addBookmark(b) manager.addBookmark(b2) @@ -479,19 +625,31 @@ def testApplicationInstance(self): # add a bunch of bookmarks b = QgsBookmark() - b.setId('1') - b.setName('b1') - b.setExtent(QgsReferencedRectangle(QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem('EPSG:4326'))) + b.setId("1") + b.setName("b1") + b.setExtent( + QgsReferencedRectangle( + QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b2 = QgsBookmark() - b2.setId('2') - b2.setName('b2') - b2.setExtent(QgsReferencedRectangle(QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem('EPSG:4326'))) + b2.setId("2") + b2.setName("b2") + b2.setExtent( + QgsReferencedRectangle( + QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b3 = QgsBookmark() - b3.setId('3') - b3.setName('b3') - b3.setExtent(QgsReferencedRectangle(QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem('EPSG:4326'))) + b3.setId("3") + b3.setName("b3") + b3.setExtent( + QgsReferencedRectangle( + QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) manager.addBookmark(b) manager.addBookmark(b2) @@ -513,19 +671,31 @@ def testMoveBookmark(self): # add a bunch of bookmarks b = QgsBookmark() - b.setId('1') - b.setName('b1') - b.setExtent(QgsReferencedRectangle(QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem('EPSG:4326'))) + b.setId("1") + b.setName("b1") + b.setExtent( + QgsReferencedRectangle( + QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b2 = QgsBookmark() - b2.setId('2') - b2.setName('b2') - b2.setExtent(QgsReferencedRectangle(QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem('EPSG:4326'))) + b2.setId("2") + b2.setName("b2") + b2.setExtent( + QgsReferencedRectangle( + QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b3 = QgsBookmark() - b3.setId('3') - b3.setName('b3') - b3.setExtent(QgsReferencedRectangle(QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem('EPSG:4326'))) + b3.setId("3") + b3.setName("b3") + b3.setExtent( + QgsReferencedRectangle( + QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) manager.addBookmark(b) manager.addBookmark(b2) @@ -534,7 +704,7 @@ def testMoveBookmark(self): self.assertEqual(manager.bookmarks(), [b, b2]) self.assertEqual(manager2.bookmarks(), [b3]) - self.assertFalse(manager.moveBookmark('bbbb', manager2)) + self.assertFalse(manager.moveBookmark("bbbb", manager2)) self.assertFalse(manager.moveBookmark(b3.id(), manager2)) self.assertEqual(manager.bookmarks(), [b, b2]) self.assertEqual(manager2.bookmarks(), [b3]) @@ -567,21 +737,33 @@ def testExportImport(self): # add a bunch of bookmarks b = QgsBookmark() - b.setId('1') - b.setName('b1') - b.setGroup('g1') - b.setExtent(QgsReferencedRectangle(QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem('EPSG:4326'))) + b.setId("1") + b.setName("b1") + b.setGroup("g1") + b.setExtent( + QgsReferencedRectangle( + QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b2 = QgsBookmark() - b2.setId('2') - b2.setName('b2') - b2.setExtent(QgsReferencedRectangle(QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem('EPSG:4326'))) + b2.setId("2") + b2.setName("b2") + b2.setExtent( + QgsReferencedRectangle( + QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b3 = QgsBookmark() - b3.setId('3') - b3.setName('b3') - b3.setGroup('g1') - b3.setExtent(QgsReferencedRectangle(QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem('EPSG:4326'))) + b3.setId("3") + b3.setName("b3") + b3.setGroup("g1") + b3.setExtent( + QgsReferencedRectangle( + QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) manager.addBookmark(b) manager.addBookmark(b2) @@ -590,19 +772,30 @@ def testExportImport(self): # export one manager's bookmarks self.assertTrue(QgsBookmarkManager.exportToFile(tmpFile, [manager])) self.assertTrue(manager3.importFromFile(tmpFile)) - self.assertEqual([(b.name(), b.extent()) for b in manager3.bookmarks()], [(b.name(), b.extent()) for b in [b, b2]]) + self.assertEqual( + [(b.name(), b.extent()) for b in manager3.bookmarks()], + [(b.name(), b.extent()) for b in [b, b2]], + ) manager3.clear() # export both manager's bookmarks self.assertTrue(QgsBookmarkManager.exportToFile(tmpFile, [manager, manager2])) self.assertTrue(manager3.importFromFile(tmpFile)) - self.assertEqual([(b.name(), b.extent()) for b in manager3.bookmarks()], [(b.name(), b.extent()) for b in [b, b2, b3]]) + self.assertEqual( + [(b.name(), b.extent()) for b in manager3.bookmarks()], + [(b.name(), b.extent()) for b in [b, b2, b3]], + ) manager3.clear() # restrict to group - self.assertTrue(QgsBookmarkManager.exportToFile(tmpFile, [manager, manager2], 'g1')) + self.assertTrue( + QgsBookmarkManager.exportToFile(tmpFile, [manager, manager2], "g1") + ) self.assertTrue(manager3.importFromFile(tmpFile)) - self.assertEqual([(b.name(), b.extent()) for b in manager3.bookmarks()], [(b.name(), b.extent()) for b in [b, b3]]) + self.assertEqual( + [(b.name(), b.extent()) for b in manager3.bookmarks()], + [(b.name(), b.extent()) for b in [b, b3]], + ) def testRenameGroup(self): """ @@ -613,58 +806,64 @@ def testRenameGroup(self): # add a bunch of bookmarks b = QgsBookmark() - b.setId('1') - b.setName('b1') - b.setGroup('g1') - b.setExtent(QgsReferencedRectangle(QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem('EPSG:4326'))) + b.setId("1") + b.setName("b1") + b.setGroup("g1") + b.setExtent( + QgsReferencedRectangle( + QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b2 = QgsBookmark() - b2.setId('2') - b2.setName('b2') - b2.setGroup('g1') - b2.setExtent(QgsReferencedRectangle(QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem('EPSG:4326'))) + b2.setId("2") + b2.setName("b2") + b2.setGroup("g1") + b2.setExtent( + QgsReferencedRectangle( + QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b3 = QgsBookmark() - b3.setId('3') - b3.setName('b3') - b3.setGroup('g3') - b3.setExtent(QgsReferencedRectangle(QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem('EPSG:4326'))) + b3.setId("3") + b3.setName("b3") + b3.setGroup("g3") + b3.setExtent( + QgsReferencedRectangle( + QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) manager.addBookmark(b) manager.addBookmark(b2) manager.addBookmark(b3) changed_spy = QSignalSpy(manager.bookmarkChanged) - self.assertEqual([b.group() for b in manager.bookmarks()], - ['g1', 'g1', 'g3']) + self.assertEqual([b.group() for b in manager.bookmarks()], ["g1", "g1", "g3"]) - manager.renameGroup('xxxxx', 'yyyyy') - self.assertEqual([b.group() for b in manager.bookmarks()], - ['g1', 'g1', 'g3']) + manager.renameGroup("xxxxx", "yyyyy") + self.assertEqual([b.group() for b in manager.bookmarks()], ["g1", "g1", "g3"]) self.assertEqual(len(changed_spy), 0) - manager.renameGroup('', '') - self.assertEqual([b.group() for b in manager.bookmarks()], - ['g1', 'g1', 'g3']) + manager.renameGroup("", "") + self.assertEqual([b.group() for b in manager.bookmarks()], ["g1", "g1", "g3"]) self.assertEqual(len(changed_spy), 0) - manager.renameGroup('g1', 'g2') - self.assertEqual([b.group() for b in manager.bookmarks()], - ['g2', 'g2', 'g3']) + manager.renameGroup("g1", "g2") + self.assertEqual([b.group() for b in manager.bookmarks()], ["g2", "g2", "g3"]) self.assertEqual(len(changed_spy), 2) - self.assertEqual(changed_spy[0][0], '1') - self.assertEqual(changed_spy[1][0], '2') - manager.renameGroup('g3', 'g2') - self.assertEqual([b.group() for b in manager.bookmarks()], - ['g2', 'g2', 'g2']) + self.assertEqual(changed_spy[0][0], "1") + self.assertEqual(changed_spy[1][0], "2") + manager.renameGroup("g3", "g2") + self.assertEqual([b.group() for b in manager.bookmarks()], ["g2", "g2", "g2"]) self.assertEqual(len(changed_spy), 3) - self.assertEqual(changed_spy[2][0], '3') - manager.renameGroup('g2', 'g') - self.assertEqual([b.group() for b in manager.bookmarks()], - ['g', 'g', 'g']) + self.assertEqual(changed_spy[2][0], "3") + manager.renameGroup("g2", "g") + self.assertEqual([b.group() for b in manager.bookmarks()], ["g", "g", "g"]) self.assertEqual(len(changed_spy), 6) - self.assertEqual(changed_spy[3][0], '1') - self.assertEqual(changed_spy[4][0], '2') - self.assertEqual(changed_spy[5][0], '3') + self.assertEqual(changed_spy[3][0], "1") + self.assertEqual(changed_spy[4][0], "2") + self.assertEqual(changed_spy[5][0], "3") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsbookmarkmodel.py b/tests/src/python/test_qgsbookmarkmodel.py index f712b36b9992..d546dd9a6503 100644 --- a/tests/src/python/test_qgsbookmarkmodel.py +++ b/tests/src/python/test_qgsbookmarkmodel.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2019 by Nyall Dawson' -__date__ = '02/09/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "(C) 2019 by Nyall Dawson" +__date__ = "02/09/2019" +__copyright__ = "Copyright 2019, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication, QLocale, Qt from qgis.core import ( @@ -54,9 +55,11 @@ def testBookmarkModel(self): self.assertFalse(model.data(model.index(-1, 0))) self.assertFalse(model.data(model.index(1, 0))) self.assertFalse(model.data(model.index(0, 0))) - self.assertFalse(model.data(model.index(0, 0), QgsBookmarkManagerModel.CustomRoles.RoleName)) + self.assertFalse( + model.data(model.index(0, 0), QgsBookmarkManagerModel.CustomRoles.RoleName) + ) - self.assertEqual(model.headerData(0, Qt.Orientation.Horizontal), 'Name') + self.assertEqual(model.headerData(0, Qt.Orientation.Horizontal), "Name") self.assertEqual(model.headerData(9, Qt.Orientation.Horizontal), 10) self.assertEqual(model.headerData(-1, Qt.Orientation.Horizontal), 0) @@ -68,17 +71,25 @@ def testBookmarkModel(self): # add some bookmarks b = QgsBookmark() - b.setId('1') - b.setGroup('group 1') - b.setName('b1') - b.setExtent(QgsReferencedRectangle(QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem('EPSG:4326'))) + b.setId("1") + b.setGroup("group 1") + b.setName("b1") + b.setExtent( + QgsReferencedRectangle( + QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b.setRotation(0) b2 = QgsBookmark() - b2.setId('2') - b2.setGroup('group 2') - b2.setName('b2') - b2.setExtent(QgsReferencedRectangle(QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem('EPSG:4326'))) + b2.setId("2") + b2.setGroup("group 2") + b2.setName("b2") + b2.setExtent( + QgsReferencedRectangle( + QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) b2.setRotation(180.5) app_manager.addBookmark(b) @@ -86,46 +97,82 @@ def testBookmarkModel(self): self.assertEqual(model.rowCount(), 2) self.assertFalse(model.data(model.index(-1, 0))) - self.assertEqual(model.data(model.index(0, 0)), 'b1') - self.assertEqual(model.data(model.index(0, 1)), 'group 1') + self.assertEqual(model.data(model.index(0, 0)), "b1") + self.assertEqual(model.data(model.index(0, 1)), "group 1") self.assertEqual(model.data(model.index(0, 2)), 11.0) self.assertEqual(model.data(model.index(0, 3)), 21.0) self.assertEqual(model.data(model.index(0, 4)), 31.0) self.assertEqual(model.data(model.index(0, 5)), 41.0) self.assertEqual(model.data(model.index(0, 6)), 0.0) - self.assertEqual(model.data(model.index(0, 7)), 'EPSG:4326') + self.assertEqual(model.data(model.index(0, 7)), "EPSG:4326") self.assertEqual(model.data(model.index(0, 8)), None) - self.assertEqual(model.data(model.index(0, 8), Qt.ItemDataRole.CheckStateRole), Qt.CheckState.Unchecked) - self.assertEqual(model.data(model.index(0, 0), QgsBookmarkManagerModel.CustomRoles.RoleName), 'b1') - self.assertEqual(model.data(model.index(0, 0), QgsBookmarkManagerModel.CustomRoles.RoleGroup), 'group 1') + self.assertEqual( + model.data(model.index(0, 8), Qt.ItemDataRole.CheckStateRole), + Qt.CheckState.Unchecked, + ) + self.assertEqual( + model.data(model.index(0, 0), QgsBookmarkManagerModel.CustomRoles.RoleName), + "b1", + ) + self.assertEqual( + model.data( + model.index(0, 0), QgsBookmarkManagerModel.CustomRoles.RoleGroup + ), + "group 1", + ) id = model.data(model.index(0, 0), QgsBookmarkManagerModel.CustomRoles.RoleId) - self.assertEqual(app_manager.bookmarkById(id).name(), 'b1') - self.assertEqual(model.data(model.index(0, 0), QgsBookmarkManagerModel.CustomRoles.RoleExtent), app_manager.bookmarkById(id).extent()) + self.assertEqual(app_manager.bookmarkById(id).name(), "b1") + self.assertEqual( + model.data( + model.index(0, 0), QgsBookmarkManagerModel.CustomRoles.RoleExtent + ), + app_manager.bookmarkById(id).extent(), + ) - self.assertEqual(model.data(model.index(1, 0)), 'b2') - self.assertEqual(model.data(model.index(1, 1)), 'group 2') + self.assertEqual(model.data(model.index(1, 0)), "b2") + self.assertEqual(model.data(model.index(1, 1)), "group 2") self.assertEqual(model.data(model.index(1, 2)), 12.0) self.assertEqual(model.data(model.index(1, 3)), 22.0) self.assertEqual(model.data(model.index(1, 4)), 32.0) self.assertEqual(model.data(model.index(1, 5)), 42.0) self.assertEqual(model.data(model.index(1, 6)), 180.5) - self.assertEqual(model.data(model.index(1, 7)), 'EPSG:4326') + self.assertEqual(model.data(model.index(1, 7)), "EPSG:4326") self.assertEqual(model.data(model.index(1, 8)), None) - self.assertEqual(model.data(model.index(1, 8), Qt.ItemDataRole.CheckStateRole), Qt.CheckState.Unchecked) - self.assertEqual(model.data(model.index(1, 0), QgsBookmarkManagerModel.CustomRoles.RoleName), 'b2') - self.assertEqual(model.data(model.index(1, 0), QgsBookmarkManagerModel.CustomRoles.RoleGroup), 'group 2') + self.assertEqual( + model.data(model.index(1, 8), Qt.ItemDataRole.CheckStateRole), + Qt.CheckState.Unchecked, + ) + self.assertEqual( + model.data(model.index(1, 0), QgsBookmarkManagerModel.CustomRoles.RoleName), + "b2", + ) + self.assertEqual( + model.data( + model.index(1, 0), QgsBookmarkManagerModel.CustomRoles.RoleGroup + ), + "group 2", + ) id = model.data(model.index(1, 0), QgsBookmarkManagerModel.CustomRoles.RoleId) - self.assertEqual(app_manager.bookmarkById(id).name(), 'b2') - self.assertEqual(model.data(model.index(1, 0), QgsBookmarkManagerModel.CustomRoles.RoleExtent), app_manager.bookmarkById(id).extent()) + self.assertEqual(app_manager.bookmarkById(id).name(), "b2") + self.assertEqual( + model.data( + model.index(1, 0), QgsBookmarkManagerModel.CustomRoles.RoleExtent + ), + app_manager.bookmarkById(id).extent(), + ) self.assertFalse(model.data(model.index(2, 0))) self.assertFalse(model.setData(model.index(-1, 0), 4, Qt.ItemDataRole.EditRole)) - self.assertTrue(model.setData(model.index(0, 0), 'new name', Qt.ItemDataRole.EditRole)) - self.assertEqual(model.data(model.index(0, 0)), 'new name') - self.assertEqual(app_manager.bookmarks()[0].name(), 'new name') - self.assertTrue(model.setData(model.index(1, 1), 'new group', Qt.ItemDataRole.EditRole)) - self.assertEqual(model.data(model.index(1, 1)), 'new group') - self.assertEqual(app_manager.bookmarks()[1].group(), 'new group') + self.assertTrue( + model.setData(model.index(0, 0), "new name", Qt.ItemDataRole.EditRole) + ) + self.assertEqual(model.data(model.index(0, 0)), "new name") + self.assertEqual(app_manager.bookmarks()[0].name(), "new name") + self.assertTrue( + model.setData(model.index(1, 1), "new group", Qt.ItemDataRole.EditRole) + ) + self.assertEqual(model.data(model.index(1, 1)), "new group") + self.assertEqual(app_manager.bookmarks()[1].group(), "new group") self.assertTrue(model.setData(model.index(0, 2), 1, Qt.ItemDataRole.EditRole)) self.assertEqual(model.data(model.index(0, 2)), 1.0) self.assertEqual(app_manager.bookmarks()[0].extent().xMinimum(), 1.0) @@ -138,75 +185,113 @@ def testBookmarkModel(self): self.assertTrue(model.setData(model.index(0, 5), 4, Qt.ItemDataRole.EditRole)) self.assertEqual(model.data(model.index(0, 5)), 4.0) self.assertEqual(app_manager.bookmarks()[0].extent().yMaximum(), 4.0) - self.assertTrue(model.setData(model.index(0, 6), -1.2, Qt.ItemDataRole.EditRole)) + self.assertTrue( + model.setData(model.index(0, 6), -1.2, Qt.ItemDataRole.EditRole) + ) self.assertEqual(model.data(model.index(0, 6)), -1.2) self.assertEqual(app_manager.bookmarks()[0].rotation(), -1.2) self.assertFalse(model.setData(model.index(2, 0), 4, Qt.ItemDataRole.EditRole)) self.assertTrue(model.flags(model.index(0, 0)) & Qt.ItemFlag.ItemIsEnabled) self.assertTrue(model.flags(model.index(0, 0)) & Qt.ItemFlag.ItemIsEditable) - self.assertTrue(model.flags(model.index(0, 8)) & Qt.ItemFlag.ItemIsUserCheckable) - self.assertTrue(model.flags(model.index(1, 8)) & Qt.ItemFlag.ItemIsUserCheckable) + self.assertTrue( + model.flags(model.index(0, 8)) & Qt.ItemFlag.ItemIsUserCheckable + ) + self.assertTrue( + model.flags(model.index(1, 8)) & Qt.ItemFlag.ItemIsUserCheckable + ) self.assertTrue(model.flags(model.index(1, 0)) & Qt.ItemFlag.ItemIsEnabled) self.assertTrue(model.flags(model.index(1, 0)) & Qt.ItemFlag.ItemIsEditable) self.assertFalse(model.flags(model.index(2, 0)) & Qt.ItemFlag.ItemIsEnabled) self.assertFalse(model.flags(model.index(2, 0)) & Qt.ItemFlag.ItemIsEditable) - self.assertFalse(model.flags(model.index(2, 8)) & Qt.ItemFlag.ItemIsUserCheckable) + self.assertFalse( + model.flags(model.index(2, 8)) & Qt.ItemFlag.ItemIsUserCheckable + ) # add bookmark to project manager b3 = QgsBookmark() - b3.setId('3') - b3.setName('b3') - b3.setGroup('group 3') - b3.setExtent(QgsReferencedRectangle(QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem('EPSG:28355'))) + b3.setId("3") + b3.setName("b3") + b3.setGroup("group 3") + b3.setExtent( + QgsReferencedRectangle( + QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem("EPSG:28355") + ) + ) b3.setRotation(90) project_manager.addBookmark(b3) self.assertEqual(model.rowCount(), 3) self.assertFalse(model.data(model.index(-1, 0))) - self.assertEqual(model.data(model.index(0, 0)), 'new name') - self.assertEqual(model.data(model.index(0, 1)), 'group 1') + self.assertEqual(model.data(model.index(0, 0)), "new name") + self.assertEqual(model.data(model.index(0, 1)), "group 1") self.assertEqual(model.data(model.index(0, 2)), 1.0) self.assertEqual(model.data(model.index(0, 3)), 2.0) self.assertEqual(model.data(model.index(0, 4)), 3.0) self.assertEqual(model.data(model.index(0, 5)), 4.0) self.assertEqual(model.data(model.index(0, 6)), -1.2) - self.assertEqual(model.data(model.index(0, 7)), 'EPSG:4326') + self.assertEqual(model.data(model.index(0, 7)), "EPSG:4326") self.assertEqual(model.data(model.index(0, 8)), None) - self.assertEqual(model.data(model.index(0, 8), Qt.ItemDataRole.CheckStateRole), Qt.CheckState.Unchecked) - self.assertEqual(model.data(model.index(1, 0)), 'b2') - self.assertEqual(model.data(model.index(1, 1)), 'new group') + self.assertEqual( + model.data(model.index(0, 8), Qt.ItemDataRole.CheckStateRole), + Qt.CheckState.Unchecked, + ) + self.assertEqual(model.data(model.index(1, 0)), "b2") + self.assertEqual(model.data(model.index(1, 1)), "new group") self.assertEqual(model.data(model.index(1, 2)), 12.0) self.assertEqual(model.data(model.index(1, 3)), 22.0) self.assertEqual(model.data(model.index(1, 4)), 32.0) self.assertEqual(model.data(model.index(1, 5)), 42.0) self.assertEqual(model.data(model.index(1, 6)), 180.5) - self.assertEqual(model.data(model.index(1, 7)), 'EPSG:4326') + self.assertEqual(model.data(model.index(1, 7)), "EPSG:4326") self.assertEqual(model.data(model.index(1, 8)), None) - self.assertEqual(model.data(model.index(1, 8), Qt.ItemDataRole.CheckStateRole), Qt.CheckState.Unchecked) - self.assertEqual(model.data(model.index(2, 0)), 'b3') - self.assertEqual(model.data(model.index(2, 1)), 'group 3') + self.assertEqual( + model.data(model.index(1, 8), Qt.ItemDataRole.CheckStateRole), + Qt.CheckState.Unchecked, + ) + self.assertEqual(model.data(model.index(2, 0)), "b3") + self.assertEqual(model.data(model.index(2, 1)), "group 3") self.assertEqual(model.data(model.index(2, 2)), 32.0) self.assertEqual(model.data(model.index(2, 3)), 32.0) self.assertEqual(model.data(model.index(2, 4)), 33.0) self.assertEqual(model.data(model.index(2, 5)), 43.0) self.assertEqual(model.data(model.index(2, 6)), 90.0) - self.assertEqual(model.data(model.index(2, 7)), 'EPSG:28355') + self.assertEqual(model.data(model.index(2, 7)), "EPSG:28355") self.assertEqual(model.data(model.index(2, 8)), None) - self.assertEqual(model.data(model.index(2, 8), Qt.ItemDataRole.CheckStateRole), Qt.CheckState.Checked) - self.assertEqual(model.data(model.index(2, 0), QgsBookmarkManagerModel.CustomRoles.RoleName), 'b3') - self.assertEqual(model.data(model.index(2, 0), QgsBookmarkManagerModel.CustomRoles.RoleGroup), 'group 3') + self.assertEqual( + model.data(model.index(2, 8), Qt.ItemDataRole.CheckStateRole), + Qt.CheckState.Checked, + ) + self.assertEqual( + model.data(model.index(2, 0), QgsBookmarkManagerModel.CustomRoles.RoleName), + "b3", + ) + self.assertEqual( + model.data( + model.index(2, 0), QgsBookmarkManagerModel.CustomRoles.RoleGroup + ), + "group 3", + ) id = model.data(model.index(2, 0), QgsBookmarkManagerModel.CustomRoles.RoleId) - self.assertEqual(project_manager.bookmarkById(id).name(), 'b3') - self.assertEqual(model.data(model.index(2, 0), QgsBookmarkManagerModel.CustomRoles.RoleExtent), project_manager.bookmarkById(id).extent()) + self.assertEqual(project_manager.bookmarkById(id).name(), "b3") + self.assertEqual( + model.data( + model.index(2, 0), QgsBookmarkManagerModel.CustomRoles.RoleExtent + ), + project_manager.bookmarkById(id).extent(), + ) self.assertFalse(model.data(model.index(3, 0))) - self.assertTrue(model.setData(model.index(2, 0), 'new name 2', Qt.ItemDataRole.EditRole)) - self.assertEqual(model.data(model.index(2, 0)), 'new name 2') - self.assertEqual(project_manager.bookmarks()[0].name(), 'new name 2') - self.assertTrue(model.setData(model.index(2, 1), 'new group', Qt.ItemDataRole.EditRole)) - self.assertEqual(model.data(model.index(2, 1)), 'new group') - self.assertEqual(project_manager.bookmarks()[0].group(), 'new group') + self.assertTrue( + model.setData(model.index(2, 0), "new name 2", Qt.ItemDataRole.EditRole) + ) + self.assertEqual(model.data(model.index(2, 0)), "new name 2") + self.assertEqual(project_manager.bookmarks()[0].name(), "new name 2") + self.assertTrue( + model.setData(model.index(2, 1), "new group", Qt.ItemDataRole.EditRole) + ) + self.assertEqual(model.data(model.index(2, 1)), "new group") + self.assertEqual(project_manager.bookmarks()[0].group(), "new group") self.assertTrue(model.setData(model.index(2, 2), 1, Qt.ItemDataRole.EditRole)) self.assertEqual(model.data(model.index(2, 2)), 1.0) self.assertEqual(project_manager.bookmarks()[0].extent().xMinimum(), 1.0) @@ -226,37 +311,69 @@ def testBookmarkModel(self): self.assertTrue(model.flags(model.index(0, 0)) & Qt.ItemFlag.ItemIsEnabled) self.assertTrue(model.flags(model.index(0, 0)) & Qt.ItemFlag.ItemIsEditable) - self.assertTrue(model.flags(model.index(0, 8)) & Qt.ItemFlag.ItemIsUserCheckable) - self.assertTrue(model.flags(model.index(1, 8)) & Qt.ItemFlag.ItemIsUserCheckable) + self.assertTrue( + model.flags(model.index(0, 8)) & Qt.ItemFlag.ItemIsUserCheckable + ) + self.assertTrue( + model.flags(model.index(1, 8)) & Qt.ItemFlag.ItemIsUserCheckable + ) self.assertTrue(model.flags(model.index(1, 0)) & Qt.ItemFlag.ItemIsEnabled) self.assertTrue(model.flags(model.index(1, 0)) & Qt.ItemFlag.ItemIsEditable) self.assertTrue(model.flags(model.index(2, 0)) & Qt.ItemFlag.ItemIsEnabled) self.assertTrue(model.flags(model.index(2, 0)) & Qt.ItemFlag.ItemIsEditable) - self.assertTrue(model.flags(model.index(2, 8)) & Qt.ItemFlag.ItemIsUserCheckable) + self.assertTrue( + model.flags(model.index(2, 8)) & Qt.ItemFlag.ItemIsUserCheckable + ) self.assertFalse(model.flags(model.index(3, 0)) & Qt.ItemFlag.ItemIsEnabled) self.assertFalse(model.flags(model.index(3, 0)) & Qt.ItemFlag.ItemIsEditable) - self.assertFalse(model.flags(model.index(3, 8)) & Qt.ItemFlag.ItemIsUserCheckable) + self.assertFalse( + model.flags(model.index(3, 8)) & Qt.ItemFlag.ItemIsUserCheckable + ) # try transferring bookmark from app->project - self.assertTrue(model.setData(model.index(1, 8), Qt.CheckState.Checked, Qt.ItemDataRole.CheckStateRole)) - self.assertEqual([b.name() for b in project_manager.bookmarks()], ['new name 2', 'b2']) - self.assertEqual([b.name() for b in app_manager.bookmarks()], ['new name']) - self.assertFalse(model.setData(model.index(1, 8), Qt.CheckState.Checked, Qt.ItemDataRole.CheckStateRole)) + self.assertTrue( + model.setData( + model.index(1, 8), Qt.CheckState.Checked, Qt.ItemDataRole.CheckStateRole + ) + ) + self.assertEqual( + [b.name() for b in project_manager.bookmarks()], ["new name 2", "b2"] + ) + self.assertEqual([b.name() for b in app_manager.bookmarks()], ["new name"]) + self.assertFalse( + model.setData( + model.index(1, 8), Qt.CheckState.Checked, Qt.ItemDataRole.CheckStateRole + ) + ) # try transferring bookmark from project->app - self.assertTrue(model.setData(model.index(1, 8), Qt.CheckState.Unchecked, Qt.ItemDataRole.CheckStateRole)) - self.assertEqual([b.name() for b in project_manager.bookmarks()], ['b2']) - self.assertEqual([b.name() for b in app_manager.bookmarks()], ['new name', 'new name 2']) - self.assertFalse(model.setData(model.index(1, 8), Qt.CheckState.Unchecked, Qt.ItemDataRole.CheckStateRole)) + self.assertTrue( + model.setData( + model.index(1, 8), + Qt.CheckState.Unchecked, + Qt.ItemDataRole.CheckStateRole, + ) + ) + self.assertEqual([b.name() for b in project_manager.bookmarks()], ["b2"]) + self.assertEqual( + [b.name() for b in app_manager.bookmarks()], ["new name", "new name 2"] + ) + self.assertFalse( + model.setData( + model.index(1, 8), + Qt.CheckState.Unchecked, + Qt.ItemDataRole.CheckStateRole, + ) + ) # remove rows model.removeRows(0, 1) - self.assertEqual([b.name() for b in project_manager.bookmarks()], ['b2']) - self.assertEqual([b.name() for b in app_manager.bookmarks()], ['new name 2']) + self.assertEqual([b.name() for b in project_manager.bookmarks()], ["b2"]) + self.assertEqual([b.name() for b in app_manager.bookmarks()], ["new name 2"]) model.removeRows(0, 2) self.assertEqual([b.name() for b in project_manager.bookmarks()], []) self.assertEqual([b.name() for b in app_manager.bookmarks()], []) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsbox3d.py b/tests/src/python/test_qgsbox3d.py index f1bd9ec936c7..164130c63a12 100644 --- a/tests/src/python/test_qgsbox3d.py +++ b/tests/src/python/test_qgsbox3d.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '11/04/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "11/04/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import sys @@ -122,7 +123,7 @@ def testCtor(self): def test_repr(self): box = QgsBox3d(5.0, 6.0, 7.0, 10.0, 11.0, 12.0) - self.assertEqual(str(box), '') + self.assertEqual(str(box), "") def testSetters(self): box = QgsBox3d(5.0, 6.0, 7.0, 10.0, 11.0, 12.0) @@ -167,7 +168,7 @@ def testNormalize(self): self.assertEqual(box.yMaximum(), 11.0) self.assertEqual(box.zMaximum(), 12.0) - box2 = QgsBox3d(float('NaN'), 5, 12, 9, float('NaN'), float('NaN')) + box2 = QgsBox3d(float("NaN"), 5, 12, 9, float("NaN"), float("NaN")) self.assertNotEqual(box2.xMinimum(), box.xMinimum()) self.assertEqual(box2.yMinimum(), 5.0) self.assertEqual(box2.zMinimum(), 12.0) @@ -210,7 +211,9 @@ def testIntersects(self): self.assertTrue(box.intersects(QgsBox3d(7.0, 8.0, 9.0, 10.0, 11.0, 12.0))) self.assertTrue(box.intersects(QgsBox3d(0.0, 1.0, 2.0, 100.0, 111.0, 112.0))) self.assertTrue(box.intersects(QgsBox3d(1.0, 2.0, 3.0, 6.0, 7.0, 8.0))) - self.assertFalse(box.intersects(QgsBox3d(15.0, 16.0, 17.0, 110.0, 112.0, 113.0))) + self.assertFalse( + box.intersects(QgsBox3d(15.0, 16.0, 17.0, 110.0, 112.0, 113.0)) + ) self.assertFalse(box.intersects(QgsBox3d(5.0, 6.0, 17.0, 11.0, 13.0, 113.0))) self.assertFalse(box.intersects(QgsBox3d(5.0, 16.0, 7.0, 11.0, 23.0, 15.0))) self.assertFalse(box.intersects(QgsBox3d(15.0, 6.0, 7.0, 21.0, 13.0, 15.0))) @@ -302,7 +305,14 @@ def testCombineWith(self): self.assertEqual(box9.yMaximum(), 12.0) self.assertEqual(box9.zMaximum(), 13.0) - box10 = QgsBox3d(float('nan'), float('nan'), float('nan'), float('nan'), float('nan'), float('nan')) + box10 = QgsBox3d( + float("nan"), + float("nan"), + float("nan"), + float("nan"), + float("nan"), + float("nan"), + ) box11 = QgsBox3d(1, 2, 3, 4, 5, 6) box10.combineWith(box11) self.assertEqual(box11.xMinimum(), 1) @@ -312,7 +322,14 @@ def testCombineWith(self): self.assertEqual(box11.yMaximum(), 5) self.assertEqual(box11.zMaximum(), 6) - box12 = QgsBox3d(float('nan'), float('nan'), float('nan'), float('nan'), float('nan'), float('nan')) + box12 = QgsBox3d( + float("nan"), + float("nan"), + float("nan"), + float("nan"), + float("nan"), + float("nan"), + ) box12.combineWith(7, 8, 9) self.assertEqual(box12.xMinimum(), 7) self.assertEqual(box12.yMinimum(), 8) @@ -321,7 +338,7 @@ def testCombineWith(self): self.assertEqual(box12.yMaximum(), 8) self.assertEqual(box12.zMaximum(), 9) - box13 = QgsBox3d(float('nan'), -5, float('nan'), 14, float('nan'), float('nan')) + box13 = QgsBox3d(float("nan"), -5, float("nan"), 14, float("nan"), float("nan")) box14 = QgsBox3d(1, 2, 3, 4, 5, 6) box13.combineWith(box14) self.assertEqual(box13.xMinimum(), 1) @@ -331,7 +348,7 @@ def testCombineWith(self): self.assertEqual(box13.yMaximum(), 5) self.assertEqual(box13.zMaximum(), 6) - box15 = QgsBox3d(-2, float('nan'), float('nan'), float('nan'), float('nan'), 23) + box15 = QgsBox3d(-2, float("nan"), float("nan"), float("nan"), float("nan"), 23) box15.combineWith(5, 6, 7) self.assertEqual(box15.xMinimum(), -2) self.assertEqual(box15.yMinimum(), 6) @@ -364,7 +381,7 @@ def testIs2d(self): self.assertFalse(box.is2d()) box = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, -7.0, False) self.assertTrue(box.is2d()) - box = QgsBox3d(5.0, 6.0, float('nan'), 11.0, 13.0, float('nan')) + box = QgsBox3d(5.0, 6.0, float("nan"), 11.0, 13.0, float("nan")) self.assertTrue(box.is2d()) def testIs3d(self): @@ -440,13 +457,13 @@ def testIsNull(self): box4 = QgsBox3d(5, 6, 7, 12, 13, 14) self.assertFalse(box4.isNull()) - box5 = QgsBox3d(5, 6, float('nan'), 12, 13, float('nan')) + box5 = QgsBox3d(5, 6, float("nan"), 12, 13, float("nan")) self.assertFalse(box5.isNull()) - box6 = QgsBox3d(0, 0, float('nan'), 0, 0, float('nan')) + box6 = QgsBox3d(0, 0, float("nan"), 0, 0, float("nan")) self.assertFalse(box6.isNull()) - box7 = QgsBox3d(0, 0, float('nan'), 0, 0, float('nan')) + box7 = QgsBox3d(0, 0, float("nan"), 0, 0, float("nan")) self.assertFalse(box7.isNull()) box8 = QgsBox3d(0, 6, 8, 0, 13, 14) @@ -459,8 +476,14 @@ def testIsNull(self): self.assertFalse(box10.isNull()) box11 = QgsBox3d( - sys.float_info.max, sys.float_info.max, sys.float_info.max, - -sys.float_info.max, -sys.float_info.max, -sys.float_info.max, False) + sys.float_info.max, + sys.float_info.max, + sys.float_info.max, + -sys.float_info.max, + -sys.float_info.max, + -sys.float_info.max, + False, + ) self.assertTrue(box11.isNull()) def testIsEmpty(self): @@ -505,13 +528,14 @@ def testToString(self): box4 = QgsBox3d(1, 2, 3, 4, 5, 6) self.assertEqual( box4.toString(), - ("1.0000000000000000,2.0000000000000000,3.0000000000000000 : " - "4.0000000000000000,5.0000000000000000,6.0000000000000000")) + ( + "1.0000000000000000,2.0000000000000000,3.0000000000000000 : " + "4.0000000000000000,5.0000000000000000,6.0000000000000000" + ), + ) box3 = QgsBox3d(1.451845, 2.8543302, 3.3490346, 4.654983, 5.5484343, 6.4567982) - self.assertEqual( - box3.toString(3), - "1.452,2.854,3.349 : 4.655,5.548,6.457") + self.assertEqual(box3.toString(3), "1.452,2.854,3.349 : 4.655,5.548,6.457") def testMove(self): box1 = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 15.0) @@ -532,7 +556,7 @@ def testMove(self): self.assertEqual(box1b.yMaximum(), 11.0) self.assertEqual(box1b.zMaximum(), 12.0) - box1a += QgsVector3D(10., 20., 30.) + box1a += QgsVector3D(10.0, 20.0, 30.0) self.assertEqual(box1a.xMinimum(), 16.0) self.assertEqual(box1a.yMinimum(), 28.0) self.assertEqual(box1a.zMinimum(), 40.0) @@ -540,7 +564,7 @@ def testMove(self): self.assertEqual(box1a.yMaximum(), 35.0) self.assertEqual(box1a.zMaximum(), 48.0) - box1a -= QgsVector3D(10., 20., 30.) + box1a -= QgsVector3D(10.0, 20.0, 30.0) self.assertEqual(box1a.xMinimum(), 6.0) self.assertEqual(box1a.yMinimum(), 8.0) self.assertEqual(box1a.zMinimum(), 10.0) @@ -551,15 +575,19 @@ def testMove(self): def test_corners(self): box1 = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 15.0) - self.assertEqual(box1.corners(), - [QgsVector3D(5, 6, 7), - QgsVector3D(5, 13, 7), - QgsVector3D(11, 6, 7), - QgsVector3D(11, 13, 7), - QgsVector3D(5, 6, 15), - QgsVector3D(5, 13, 15), - QgsVector3D(11, 6, 15), - QgsVector3D(11, 13, 15)]) + self.assertEqual( + box1.corners(), + [ + QgsVector3D(5, 6, 7), + QgsVector3D(5, 13, 7), + QgsVector3D(11, 6, 7), + QgsVector3D(11, 13, 7), + QgsVector3D(5, 6, 15), + QgsVector3D(5, 13, 15), + QgsVector3D(11, 6, 15), + QgsVector3D(11, 13, 15), + ], + ) def test_set(self): box1 = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 15.0) @@ -595,5 +623,5 @@ def test_set(self): self.assertEqual(box1.zMaximum(), 14.0) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscalloutpanelwidget.py b/tests/src/python/test_qgscalloutpanelwidget.py index ef6aa4622dfe..9f8294aacddd 100644 --- a/tests/src/python/test_qgscalloutpanelwidget.py +++ b/tests/src/python/test_qgscalloutpanelwidget.py @@ -8,13 +8,8 @@ from qgis.PyQt.QtWidgets import QComboBox from qgis.PyQt.QtTest import QSignalSpy -from qgis.core import ( - QgsBalloonCallout, - QgsSimpleLineCallout -) -from qgis.gui import ( - QgsCalloutPanelWidget -) +from qgis.core import QgsBalloonCallout, QgsSimpleLineCallout +from qgis.gui import QgsCalloutPanelWidget import unittest from qgis.testing import start_app, QgisTestCase @@ -33,17 +28,17 @@ def testWidget(self): widget.setCallout(callout) self.assertEqual(len(changed_spy), 1) - style_combo = widget.findChild(QComboBox, 'mCalloutStyleComboBox') + style_combo = widget.findChild(QComboBox, "mCalloutStyleComboBox") self.assertIsInstance(style_combo, QComboBox) style_combo.setCurrentIndex(style_combo.findData("curved")) self.assertEqual(len(changed_spy), 2) - self.assertEqual(widget.callout().type(), 'curved') + self.assertEqual(widget.callout().type(), "curved") style_combo.setCurrentIndex(style_combo.findData("balloon")) self.assertEqual(len(changed_spy), 3) - self.assertEqual(widget.callout().type(), 'balloon') + self.assertEqual(widget.callout().type(), "balloon") callout = QgsBalloonCallout() callout.setWedgeWidth(11) @@ -53,5 +48,5 @@ def testWidget(self): self.assertEqual(widget.callout().wedgeWidth(), 11) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscategorizedsymbolrenderer.py b/tests/src/python/test_qgscategorizedsymbolrenderer.py index f021f0a6212d..fb230c3c92cf 100644 --- a/tests/src/python/test_qgscategorizedsymbolrenderer.py +++ b/tests/src/python/test_qgscategorizedsymbolrenderer.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2/12/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2/12/2015" +__copyright__ = "Copyright 2015, The QGIS Project" import os @@ -51,25 +52,19 @@ def createMarkerSymbol(): - symbol = QgsMarkerSymbol.createSimple({ - "color": "100,150,50", - "name": "square", - "size": "3.0" - }) + symbol = QgsMarkerSymbol.createSimple( + {"color": "100,150,50", "name": "square", "size": "3.0"} + ) return symbol def createLineSymbol(): - symbol = QgsLineSymbol.createSimple({ - "color": "100,150,50" - }) + symbol = QgsLineSymbol.createSimple({"color": "100,150,50"}) return symbol def createFillSymbol(): - symbol = QgsFillSymbol.createSimple({ - "color": "100,150,50" - }) + symbol = QgsFillSymbol.createSimple({"color": "100,150,50"}) return symbol @@ -78,26 +73,34 @@ class TestQgsCategorizedSymbolRenderer(QgisTestCase): def testFilter(self): """Test filter creation""" renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('field') + renderer.setClassAttribute("field") - renderer.addCategory(QgsRendererCategory('a', createMarkerSymbol(), 'a')) - renderer.addCategory(QgsRendererCategory('b', createMarkerSymbol(), 'b')) - renderer.addCategory(QgsRendererCategory('c', createMarkerSymbol(), 'c')) + renderer.addCategory(QgsRendererCategory("a", createMarkerSymbol(), "a")) + renderer.addCategory(QgsRendererCategory("b", createMarkerSymbol(), "b")) + renderer.addCategory(QgsRendererCategory("c", createMarkerSymbol(), "c")) # add default category - renderer.addCategory(QgsRendererCategory('', createMarkerSymbol(), 'default')) + renderer.addCategory(QgsRendererCategory("", createMarkerSymbol(), "default")) fields = QgsFields() - fields.append(QgsField('field', QVariant.String)) - fields.append(QgsField('num', QVariant.Double)) + fields.append(QgsField("field", QVariant.String)) + fields.append(QgsField("num", QVariant.Double)) - self.assertEqual(renderer.filter(fields), '') + self.assertEqual(renderer.filter(fields), "") # remove categories, leaving default assert renderer.updateCategoryRenderState(0, False) - self.assertEqual(renderer.filter(fields), "(\"field\") NOT IN ('a') OR (\"field\") IS NULL") + self.assertEqual( + renderer.filter(fields), '("field") NOT IN (\'a\') OR ("field") IS NULL' + ) assert renderer.updateCategoryRenderState(1, False) - self.assertEqual(renderer.filter(fields), "(\"field\") NOT IN ('a','b') OR (\"field\") IS NULL") + self.assertEqual( + renderer.filter(fields), + "(\"field\") NOT IN ('a','b') OR (\"field\") IS NULL", + ) assert renderer.updateCategoryRenderState(2, False) - self.assertEqual(renderer.filter(fields), "(\"field\") NOT IN ('a','b','c') OR (\"field\") IS NULL") + self.assertEqual( + renderer.filter(fields), + "(\"field\") NOT IN ('a','b','c') OR (\"field\") IS NULL", + ) # remove default category assert renderer.updateCategoryRenderState(3, False) self.assertEqual(renderer.filter(fields), "FALSE") @@ -111,16 +114,16 @@ def testFilter(self): renderer.deleteAllCategories() # just default category - renderer.addCategory(QgsRendererCategory('', createMarkerSymbol(), 'default')) - self.assertEqual(renderer.filter(fields), '') + renderer.addCategory(QgsRendererCategory("", createMarkerSymbol(), "default")) + self.assertEqual(renderer.filter(fields), "") assert renderer.updateCategoryRenderState(0, False) - self.assertEqual(renderer.filter(fields), 'FALSE') + self.assertEqual(renderer.filter(fields), "FALSE") renderer.deleteAllCategories() # no default category - renderer.addCategory(QgsRendererCategory('a', createMarkerSymbol(), 'a')) - renderer.addCategory(QgsRendererCategory('b', createMarkerSymbol(), 'b')) - renderer.addCategory(QgsRendererCategory('c', createMarkerSymbol(), 'c')) + renderer.addCategory(QgsRendererCategory("a", createMarkerSymbol(), "a")) + renderer.addCategory(QgsRendererCategory("b", createMarkerSymbol(), "b")) + renderer.addCategory(QgsRendererCategory("c", createMarkerSymbol(), "c")) self.assertEqual(renderer.filter(fields), "(\"field\") IN ('a','b','c')") assert renderer.updateCategoryRenderState(0, False) self.assertEqual(renderer.filter(fields), "(\"field\") IN ('b','c')") @@ -130,32 +133,40 @@ def testFilter(self): self.assertEqual(renderer.filter(fields), "FALSE") renderer.deleteAllCategories() - renderer.setClassAttribute('num') + renderer.setClassAttribute("num") # numeric categories - renderer.addCategory(QgsRendererCategory(1, createMarkerSymbol(), 'a')) - renderer.addCategory(QgsRendererCategory(2, createMarkerSymbol(), 'b')) - renderer.addCategory(QgsRendererCategory(3, createMarkerSymbol(), 'c')) - self.assertEqual(renderer.filter(fields), '(\"num\") IN (1,2,3)') + renderer.addCategory(QgsRendererCategory(1, createMarkerSymbol(), "a")) + renderer.addCategory(QgsRendererCategory(2, createMarkerSymbol(), "b")) + renderer.addCategory(QgsRendererCategory(3, createMarkerSymbol(), "c")) + self.assertEqual(renderer.filter(fields), '("num") IN (1,2,3)') assert renderer.updateCategoryRenderState(0, False) - self.assertEqual(renderer.filter(fields), "(\"num\") IN (2,3)") + self.assertEqual(renderer.filter(fields), '("num") IN (2,3)') assert renderer.updateCategoryRenderState(2, False) - self.assertEqual(renderer.filter(fields), "(\"num\") IN (2)") + self.assertEqual(renderer.filter(fields), '("num") IN (2)') assert renderer.updateCategoryRenderState(1, False) self.assertEqual(renderer.filter(fields), "FALSE") # with value lists renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('field') + renderer.setClassAttribute("field") - renderer.addCategory(QgsRendererCategory(['a', 'b'], createMarkerSymbol(), 'ab')) - renderer.addCategory(QgsRendererCategory('c', createMarkerSymbol(), 'c')) - renderer.addCategory(QgsRendererCategory('', createMarkerSymbol(), 'default')) - self.assertEqual(renderer.filter(fields), '') + renderer.addCategory( + QgsRendererCategory(["a", "b"], createMarkerSymbol(), "ab") + ) + renderer.addCategory(QgsRendererCategory("c", createMarkerSymbol(), "c")) + renderer.addCategory(QgsRendererCategory("", createMarkerSymbol(), "default")) + self.assertEqual(renderer.filter(fields), "") # remove categories, leaving default assert renderer.updateCategoryRenderState(0, False) - self.assertEqual(renderer.filter(fields), "(\"field\") NOT IN ('a','b') OR (\"field\") IS NULL") + self.assertEqual( + renderer.filter(fields), + "(\"field\") NOT IN ('a','b') OR (\"field\") IS NULL", + ) assert renderer.updateCategoryRenderState(1, False) - self.assertEqual(renderer.filter(fields), "(\"field\") NOT IN ('a','b','c') OR (\"field\") IS NULL") + self.assertEqual( + renderer.filter(fields), + "(\"field\") NOT IN ('a','b','c') OR (\"field\") IS NULL", + ) assert renderer.updateCategoryRenderState(2, False) self.assertEqual(renderer.filter(fields), "FALSE") assert renderer.updateCategoryRenderState(0, True) @@ -164,41 +175,52 @@ def testFilter(self): self.assertEqual(renderer.filter(fields), "(\"field\") IN ('a','b','c')") assert renderer.updateCategoryRenderState(1, False) assert renderer.updateCategoryRenderState(2, True) - self.assertEqual(renderer.filter(fields), "(\"field\") NOT IN ('c') OR (\"field\") IS NULL") + self.assertEqual( + renderer.filter(fields), '("field") NOT IN (\'c\') OR ("field") IS NULL' + ) renderer.deleteAllCategories() - renderer.setClassAttribute('num') - renderer.addCategory(QgsRendererCategory([1, 2], createMarkerSymbol(), 'a')) - renderer.addCategory(QgsRendererCategory(3, createMarkerSymbol(), 'b')) - self.assertEqual(renderer.filter(fields), '(\"num\") IN (1,2,3)') + renderer.setClassAttribute("num") + renderer.addCategory(QgsRendererCategory([1, 2], createMarkerSymbol(), "a")) + renderer.addCategory(QgsRendererCategory(3, createMarkerSymbol(), "b")) + self.assertEqual(renderer.filter(fields), '("num") IN (1,2,3)') assert renderer.updateCategoryRenderState(0, False) - self.assertEqual(renderer.filter(fields), "(\"num\") IN (3)") + self.assertEqual(renderer.filter(fields), '("num") IN (3)') assert renderer.updateCategoryRenderState(1, False) self.assertEqual(renderer.filter(fields), "FALSE") assert renderer.updateCategoryRenderState(0, True) - self.assertEqual(renderer.filter(fields), "(\"num\") IN (1,2)") + self.assertEqual(renderer.filter(fields), '("num") IN (1,2)') def testFilterExpression(self): """Test filter creation with expression""" renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('field + field2') + renderer.setClassAttribute("field + field2") - renderer.addCategory(QgsRendererCategory('a', createMarkerSymbol(), 'a')) - renderer.addCategory(QgsRendererCategory('b', createMarkerSymbol(), 'b')) - renderer.addCategory(QgsRendererCategory('c', createMarkerSymbol(), 'c')) + renderer.addCategory(QgsRendererCategory("a", createMarkerSymbol(), "a")) + renderer.addCategory(QgsRendererCategory("b", createMarkerSymbol(), "b")) + renderer.addCategory(QgsRendererCategory("c", createMarkerSymbol(), "c")) # add default category - renderer.addCategory(QgsRendererCategory('', createMarkerSymbol(), 'default')) + renderer.addCategory(QgsRendererCategory("", createMarkerSymbol(), "default")) fields = QgsFields() - fields.append(QgsField('field', QVariant.String)) + fields.append(QgsField("field", QVariant.String)) - self.assertEqual(renderer.filter(fields), '') + self.assertEqual(renderer.filter(fields), "") # remove categories, leaving default assert renderer.updateCategoryRenderState(0, False) - self.assertEqual(renderer.filter(fields), "(field + field2) NOT IN ('a') OR (field + field2) IS NULL") + self.assertEqual( + renderer.filter(fields), + "(field + field2) NOT IN ('a') OR (field + field2) IS NULL", + ) assert renderer.updateCategoryRenderState(1, False) - self.assertEqual(renderer.filter(fields), "(field + field2) NOT IN ('a','b') OR (field + field2) IS NULL") + self.assertEqual( + renderer.filter(fields), + "(field + field2) NOT IN ('a','b') OR (field + field2) IS NULL", + ) assert renderer.updateCategoryRenderState(2, False) - self.assertEqual(renderer.filter(fields), "(field + field2) NOT IN ('a','b','c') OR (field + field2) IS NULL") + self.assertEqual( + renderer.filter(fields), + "(field + field2) NOT IN ('a','b','c') OR (field + field2) IS NULL", + ) # remove default category assert renderer.updateCategoryRenderState(3, False) self.assertEqual(renderer.filter(fields), "FALSE") @@ -212,16 +234,16 @@ def testFilterExpression(self): renderer.deleteAllCategories() # just default category - renderer.addCategory(QgsRendererCategory('', createMarkerSymbol(), 'default')) - self.assertEqual(renderer.filter(fields), '') + renderer.addCategory(QgsRendererCategory("", createMarkerSymbol(), "default")) + self.assertEqual(renderer.filter(fields), "") assert renderer.updateCategoryRenderState(0, False) - self.assertEqual(renderer.filter(fields), 'FALSE') + self.assertEqual(renderer.filter(fields), "FALSE") renderer.deleteAllCategories() # no default category - renderer.addCategory(QgsRendererCategory('a', createMarkerSymbol(), 'a')) - renderer.addCategory(QgsRendererCategory('b', createMarkerSymbol(), 'b')) - renderer.addCategory(QgsRendererCategory('c', createMarkerSymbol(), 'c')) + renderer.addCategory(QgsRendererCategory("a", createMarkerSymbol(), "a")) + renderer.addCategory(QgsRendererCategory("b", createMarkerSymbol(), "b")) + renderer.addCategory(QgsRendererCategory("c", createMarkerSymbol(), "c")) self.assertEqual(renderer.filter(fields), "(field + field2) IN ('a','b','c')") assert renderer.updateCategoryRenderState(0, False) self.assertEqual(renderer.filter(fields), "(field + field2) IN ('b','c')") @@ -232,10 +254,10 @@ def testFilterExpression(self): renderer.deleteAllCategories() # numeric categories - renderer.addCategory(QgsRendererCategory(1, createMarkerSymbol(), 'a')) - renderer.addCategory(QgsRendererCategory(2, createMarkerSymbol(), 'b')) - renderer.addCategory(QgsRendererCategory(3, createMarkerSymbol(), 'c')) - self.assertEqual(renderer.filter(fields), '(field + field2) IN (1,2,3)') + renderer.addCategory(QgsRendererCategory(1, createMarkerSymbol(), "a")) + renderer.addCategory(QgsRendererCategory(2, createMarkerSymbol(), "b")) + renderer.addCategory(QgsRendererCategory(3, createMarkerSymbol(), "c")) + self.assertEqual(renderer.filter(fields), "(field + field2) IN (1,2,3)") assert renderer.updateCategoryRenderState(0, False) self.assertEqual(renderer.filter(fields), "(field + field2) IN (2,3)") assert renderer.updateCategoryRenderState(2, False) @@ -245,15 +267,23 @@ def testFilterExpression(self): # with value lists renderer.deleteAllCategories() - renderer.addCategory(QgsRendererCategory(['a', 'b'], createMarkerSymbol(), 'ab')) - renderer.addCategory(QgsRendererCategory('c', createMarkerSymbol(), 'c')) - renderer.addCategory(QgsRendererCategory('', createMarkerSymbol(), 'default')) - self.assertEqual(renderer.filter(fields), '') + renderer.addCategory( + QgsRendererCategory(["a", "b"], createMarkerSymbol(), "ab") + ) + renderer.addCategory(QgsRendererCategory("c", createMarkerSymbol(), "c")) + renderer.addCategory(QgsRendererCategory("", createMarkerSymbol(), "default")) + self.assertEqual(renderer.filter(fields), "") # remove categories, leaving default assert renderer.updateCategoryRenderState(0, False) - self.assertEqual(renderer.filter(fields), "(field + field2) NOT IN ('a','b') OR (field + field2) IS NULL") + self.assertEqual( + renderer.filter(fields), + "(field + field2) NOT IN ('a','b') OR (field + field2) IS NULL", + ) assert renderer.updateCategoryRenderState(1, False) - self.assertEqual(renderer.filter(fields), "(field + field2) NOT IN ('a','b','c') OR (field + field2) IS NULL") + self.assertEqual( + renderer.filter(fields), + "(field + field2) NOT IN ('a','b','c') OR (field + field2) IS NULL", + ) # remove default category assert renderer.updateCategoryRenderState(2, False) self.assertEqual(renderer.filter(fields), "FALSE") @@ -264,9 +294,9 @@ def testFilterExpression(self): self.assertEqual(renderer.filter(fields), "(field + field2) IN ('a','b','c')") renderer.deleteAllCategories() # numeric categories - renderer.addCategory(QgsRendererCategory([1, 2], createMarkerSymbol(), 'a')) - renderer.addCategory(QgsRendererCategory(3, createMarkerSymbol(), 'b')) - self.assertEqual(renderer.filter(fields), '(field + field2) IN (1,2,3)') + renderer.addCategory(QgsRendererCategory([1, 2], createMarkerSymbol(), "a")) + renderer.addCategory(QgsRendererCategory(3, createMarkerSymbol(), "b")) + self.assertEqual(renderer.filter(fields), "(field + field2) IN (1,2,3)") assert renderer.updateCategoryRenderState(0, False) self.assertEqual(renderer.filter(fields), "(field + field2) IN (3)") assert renderer.updateCategoryRenderState(1, False) @@ -277,51 +307,51 @@ def testFilterExpression(self): def testSymbolForValue(self): """Test symbolForValue""" renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('field') + renderer.setClassAttribute("field") symbol_a = createMarkerSymbol() symbol_a.setColor(QColor(255, 0, 0)) - renderer.addCategory(QgsRendererCategory('a', symbol_a, 'a')) + renderer.addCategory(QgsRendererCategory("a", symbol_a, "a")) symbol_b = createMarkerSymbol() symbol_b.setColor(QColor(0, 255, 0)) - renderer.addCategory(QgsRendererCategory('b', symbol_b, 'b')) + renderer.addCategory(QgsRendererCategory("b", symbol_b, "b")) symbol_c = createMarkerSymbol() symbol_c.setColor(QColor(0, 0, 255)) - renderer.addCategory(QgsRendererCategory('c', symbol_c, 'c', False)) + renderer.addCategory(QgsRendererCategory("c", symbol_c, "c", False)) symbol_d = createMarkerSymbol() symbol_d.setColor(QColor(255, 0, 255)) - renderer.addCategory(QgsRendererCategory(['d', 'e'], symbol_d, 'de')) + renderer.addCategory(QgsRendererCategory(["d", "e"], symbol_d, "de")) # add default category default_symbol = createMarkerSymbol() default_symbol.setColor(QColor(255, 255, 255)) - renderer.addCategory(QgsRendererCategory('', default_symbol, 'default')) + renderer.addCategory(QgsRendererCategory("", default_symbol, "default")) context = QgsRenderContext() renderer.startRender(context, QgsFields()) - symbol, ok = renderer.symbolForValue2('a') + symbol, ok = renderer.symbolForValue2("a") self.assertEqual(symbol.color(), QColor(255, 0, 0)) self.assertTrue(ok) - symbol, ok = renderer.symbolForValue2('b') + symbol, ok = renderer.symbolForValue2("b") self.assertEqual(symbol.color(), QColor(0, 255, 0)) self.assertTrue(ok) # hidden category - symbol, ok = renderer.symbolForValue2('c') + symbol, ok = renderer.symbolForValue2("c") self.assertIsNone(symbol) self.assertTrue(ok) # list - symbol, ok = renderer.symbolForValue2('d') + symbol, ok = renderer.symbolForValue2("d") self.assertEqual(symbol.color(), QColor(255, 0, 255)) self.assertTrue(ok) - symbol, ok = renderer.symbolForValue2('e') + symbol, ok = renderer.symbolForValue2("e") self.assertEqual(symbol.color(), QColor(255, 0, 255)) self.assertTrue(ok) # no matching category - symbol, ok = renderer.symbolForValue2('xxxx') + symbol, ok = renderer.symbolForValue2("xxxx") self.assertIsNone(symbol) self.assertFalse(ok) @@ -330,57 +360,57 @@ def testSymbolForValue(self): def testOriginalSymbolForFeature(self): # test renderer with features fields = QgsFields() - fields.append(QgsField('x')) + fields.append(QgsField("x")) # setup renderer renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('x') + renderer.setClassAttribute("x") symbol_a = createMarkerSymbol() symbol_a.setColor(QColor(255, 0, 0)) - renderer.addCategory(QgsRendererCategory('a', symbol_a, 'a')) + renderer.addCategory(QgsRendererCategory("a", symbol_a, "a")) symbol_b = createMarkerSymbol() symbol_b.setColor(QColor(0, 255, 0)) - renderer.addCategory(QgsRendererCategory('b', symbol_b, 'b')) + renderer.addCategory(QgsRendererCategory("b", symbol_b, "b")) symbol_c = createMarkerSymbol() symbol_c.setColor(QColor(0, 0, 255)) - renderer.addCategory(QgsRendererCategory('c', symbol_c, 'c', False)) + renderer.addCategory(QgsRendererCategory("c", symbol_c, "c", False)) symbol_d = createMarkerSymbol() symbol_d.setColor(QColor(255, 0, 255)) - renderer.addCategory(QgsRendererCategory(['d', 'e'], symbol_d, 'de')) + renderer.addCategory(QgsRendererCategory(["d", "e"], symbol_d, "de")) # add default category default_symbol = createMarkerSymbol() default_symbol.setColor(QColor(255, 255, 255)) - renderer.addCategory(QgsRendererCategory('', default_symbol, 'default')) + renderer.addCategory(QgsRendererCategory("", default_symbol, "default")) context = QgsRenderContext() renderer.startRender(context, fields) f = QgsFeature(fields) - f.setAttributes(['a']) + f.setAttributes(["a"]) symbol = renderer.originalSymbolForFeature(f, context) self.assertEqual(symbol.color(), QColor(255, 0, 0)) - f.setAttributes(['b']) + f.setAttributes(["b"]) symbol = renderer.originalSymbolForFeature(f, context) self.assertEqual(symbol.color(), QColor(0, 255, 0)) # list - f.setAttributes(['d']) + f.setAttributes(["d"]) symbol = renderer.originalSymbolForFeature(f, context) self.assertEqual(symbol.color(), QColor(255, 0, 255)) - f.setAttributes(['e']) + f.setAttributes(["e"]) symbol = renderer.originalSymbolForFeature(f, context) self.assertEqual(symbol.color(), QColor(255, 0, 255)) # hidden category - f.setAttributes(['c']) + f.setAttributes(["c"]) symbol = renderer.originalSymbolForFeature(f, context) self.assertIsNone(symbol) # no matching category - f.setAttributes(['xxx']) + f.setAttributes(["xxx"]) symbol = renderer.originalSymbolForFeature(f, context) self.assertEqual(symbol.color(), QColor(255, 255, 255)) # default symbol @@ -389,60 +419,62 @@ def testOriginalSymbolForFeature(self): def testLegendKeysWhileCounting(self): # test determining legend keys for features, while counting features fields = QgsFields() - fields.append(QgsField('x')) + fields.append(QgsField("x")) # setup renderer renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('x') + renderer.setClassAttribute("x") symbol_a = createMarkerSymbol() symbol_a.setColor(QColor(255, 0, 0)) - renderer.addCategory(QgsRendererCategory('a', symbol_a, 'a', True, '0')) + renderer.addCategory(QgsRendererCategory("a", symbol_a, "a", True, "0")) symbol_b = createMarkerSymbol() symbol_b.setColor(QColor(0, 255, 0)) - renderer.addCategory(QgsRendererCategory('b', symbol_b, 'b', True, '1')) + renderer.addCategory(QgsRendererCategory("b", symbol_b, "b", True, "1")) symbol_c = createMarkerSymbol() symbol_c.setColor(QColor(0, 0, 255)) - renderer.addCategory(QgsRendererCategory('c', symbol_c, 'c', False, '2')) + renderer.addCategory(QgsRendererCategory("c", symbol_c, "c", False, "2")) symbol_d = createMarkerSymbol() symbol_d.setColor(QColor(255, 0, 255)) - renderer.addCategory(QgsRendererCategory(['d', 'e'], symbol_d, 'de', True, '3')) + renderer.addCategory(QgsRendererCategory(["d", "e"], symbol_d, "de", True, "3")) # add default category default_symbol = createMarkerSymbol() default_symbol.setColor(QColor(255, 255, 255)) - renderer.addCategory(QgsRendererCategory('', default_symbol, 'default', True, '4')) + renderer.addCategory( + QgsRendererCategory("", default_symbol, "default", True, "4") + ) - self.assertEqual(renderer.legendKeys(), {'0', '1', '2', '3', '4'}) + self.assertEqual(renderer.legendKeys(), {"0", "1", "2", "3", "4"}) context = QgsRenderContext() context.setRendererScale(0) # simulate counting renderer.startRender(context, fields) f = QgsFeature(fields) - f.setAttributes(['a']) + f.setAttributes(["a"]) keys = renderer.legendKeysForFeature(f, context) - self.assertEqual(keys, {'0'}) + self.assertEqual(keys, {"0"}) - f.setAttributes(['b']) + f.setAttributes(["b"]) keys = renderer.legendKeysForFeature(f, context) - self.assertEqual(keys, {'1'}) + self.assertEqual(keys, {"1"}) # hidden category, should still return keys - f.setAttributes(['c']) + f.setAttributes(["c"]) keys = renderer.legendKeysForFeature(f, context) - self.assertEqual(keys, {'2'}) + self.assertEqual(keys, {"2"}) # list - f.setAttributes(['d']) + f.setAttributes(["d"]) keys = renderer.legendKeysForFeature(f, context) - self.assertEqual(keys, {'3'}) - f.setAttributes(['e']) + self.assertEqual(keys, {"3"}) + f.setAttributes(["e"]) keys = renderer.legendKeysForFeature(f, context) - self.assertEqual(keys, {'3'}) + self.assertEqual(keys, {"3"}) # no matching category - f.setAttributes(['xxx']) + f.setAttributes(["xxx"]) keys = renderer.legendKeysForFeature(f, context) self.assertFalse(keys) @@ -453,127 +485,141 @@ def testMatchToSymbols(self): Test QgsCategorizedSymbolRender.matchToSymbols """ renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('x') + renderer.setClassAttribute("x") symbol_a = createMarkerSymbol() symbol_a.setColor(QColor(255, 0, 0)) - renderer.addCategory(QgsRendererCategory('a', symbol_a, 'a')) + renderer.addCategory(QgsRendererCategory("a", symbol_a, "a")) symbol_b = createMarkerSymbol() symbol_b.setColor(QColor(0, 255, 0)) - renderer.addCategory(QgsRendererCategory('b', symbol_b, 'b')) + renderer.addCategory(QgsRendererCategory("b", symbol_b, "b")) symbol_c = createMarkerSymbol() symbol_c.setColor(QColor(0, 0, 255)) - renderer.addCategory(QgsRendererCategory('c ', symbol_c, 'c')) + renderer.addCategory(QgsRendererCategory("c ", symbol_c, "c")) - matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols(None, QgsSymbol.SymbolType.Marker) + matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols( + None, QgsSymbol.SymbolType.Marker + ) self.assertEqual(matched, 0) style = QgsStyle() symbol_a = createMarkerSymbol() symbol_a.setColor(QColor(255, 10, 10)) - self.assertTrue(style.addSymbol('a', symbol_a)) + self.assertTrue(style.addSymbol("a", symbol_a)) symbol_B = createMarkerSymbol() symbol_B.setColor(QColor(10, 255, 10)) - self.assertTrue(style.addSymbol('B ', symbol_B)) + self.assertTrue(style.addSymbol("B ", symbol_B)) symbol_b = createFillSymbol() symbol_b.setColor(QColor(10, 255, 10)) - self.assertTrue(style.addSymbol('b', symbol_b)) + self.assertTrue(style.addSymbol("b", symbol_b)) symbol_C = createLineSymbol() symbol_C.setColor(QColor(10, 255, 10)) - self.assertTrue(style.addSymbol('C', symbol_C)) + self.assertTrue(style.addSymbol("C", symbol_C)) symbol_C = createMarkerSymbol() symbol_C.setColor(QColor(10, 255, 10)) - self.assertTrue(style.addSymbol(' ----c/- ', symbol_C)) + self.assertTrue(style.addSymbol(" ----c/- ", symbol_C)) # non-matching symbol type - matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols(style, QgsSymbol.SymbolType.Line) + matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols( + style, QgsSymbol.SymbolType.Line + ) self.assertEqual(matched, 0) - self.assertEqual(unmatched_cats, ['a', 'b', 'c ']) - self.assertEqual(unmatched_symbols, [' ----c/- ', 'B ', 'C', 'a', 'b']) + self.assertEqual(unmatched_cats, ["a", "b", "c "]) + self.assertEqual(unmatched_symbols, [" ----c/- ", "B ", "C", "a", "b"]) # exact match - matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols(style, QgsSymbol.SymbolType.Marker) + matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols( + style, QgsSymbol.SymbolType.Marker + ) self.assertEqual(matched, 1) - self.assertEqual(unmatched_cats, ['b', 'c ']) - self.assertEqual(unmatched_symbols, [' ----c/- ', 'B ', 'C', 'b']) + self.assertEqual(unmatched_cats, ["b", "c "]) + self.assertEqual(unmatched_symbols, [" ----c/- ", "B ", "C", "b"]) # make sure symbol was applied context = QgsRenderContext() renderer.startRender(context, QgsFields()) - symbol, ok = renderer.symbolForValue2('a') + symbol, ok = renderer.symbolForValue2("a") self.assertTrue(ok) - self.assertEqual(symbol.color().name(), '#ff0a0a') + self.assertEqual(symbol.color().name(), "#ff0a0a") renderer.stopRender(context) # case insensitive match - matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols(style, QgsSymbol.SymbolType.Marker, False) + matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols( + style, QgsSymbol.SymbolType.Marker, False + ) self.assertEqual(matched, 2) - self.assertEqual(unmatched_cats, ['c ']) - self.assertEqual(unmatched_symbols, [' ----c/- ', 'C', 'b']) + self.assertEqual(unmatched_cats, ["c "]) + self.assertEqual(unmatched_symbols, [" ----c/- ", "C", "b"]) # make sure symbols were applied context = QgsRenderContext() renderer.startRender(context, QgsFields()) - symbol, ok = renderer.symbolForValue2('a') + symbol, ok = renderer.symbolForValue2("a") self.assertTrue(ok) - self.assertEqual(symbol.color().name(), '#ff0a0a') - symbol, ok = renderer.symbolForValue2('b') + self.assertEqual(symbol.color().name(), "#ff0a0a") + symbol, ok = renderer.symbolForValue2("b") self.assertTrue(ok) - self.assertEqual(symbol.color().name(), '#0aff0a') + self.assertEqual(symbol.color().name(), "#0aff0a") renderer.stopRender(context) # case insensitive match - matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols(style, QgsSymbol.SymbolType.Marker, False) + matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols( + style, QgsSymbol.SymbolType.Marker, False + ) self.assertEqual(matched, 2) - self.assertEqual(unmatched_cats, ['c ']) - self.assertEqual(unmatched_symbols, [' ----c/- ', 'C', 'b']) + self.assertEqual(unmatched_cats, ["c "]) + self.assertEqual(unmatched_symbols, [" ----c/- ", "C", "b"]) # make sure symbols were applied context = QgsRenderContext() renderer.startRender(context, QgsFields()) - symbol, ok = renderer.symbolForValue2('a') + symbol, ok = renderer.symbolForValue2("a") self.assertTrue(ok) - self.assertEqual(symbol.color().name(), '#ff0a0a') - symbol, ok = renderer.symbolForValue2('b') + self.assertEqual(symbol.color().name(), "#ff0a0a") + symbol, ok = renderer.symbolForValue2("b") self.assertTrue(ok) - self.assertEqual(symbol.color().name(), '#0aff0a') + self.assertEqual(symbol.color().name(), "#0aff0a") renderer.stopRender(context) # tolerant match - matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols(style, QgsSymbol.SymbolType.Marker, True, True) + matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols( + style, QgsSymbol.SymbolType.Marker, True, True + ) self.assertEqual(matched, 2) - self.assertEqual(unmatched_cats, ['b']) - self.assertEqual(unmatched_symbols, ['B ', 'C', 'b']) + self.assertEqual(unmatched_cats, ["b"]) + self.assertEqual(unmatched_symbols, ["B ", "C", "b"]) # make sure symbols were applied context = QgsRenderContext() renderer.startRender(context, QgsFields()) - symbol, ok = renderer.symbolForValue2('a') + symbol, ok = renderer.symbolForValue2("a") self.assertTrue(ok) - self.assertEqual(symbol.color().name(), '#ff0a0a') - symbol, ok = renderer.symbolForValue2('c ') + self.assertEqual(symbol.color().name(), "#ff0a0a") + symbol, ok = renderer.symbolForValue2("c ") self.assertTrue(ok) - self.assertEqual(symbol.color().name(), '#0aff0a') + self.assertEqual(symbol.color().name(), "#0aff0a") renderer.stopRender(context) # tolerant match, case insensitive - matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols(style, QgsSymbol.SymbolType.Marker, False, True) + matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols( + style, QgsSymbol.SymbolType.Marker, False, True + ) self.assertEqual(matched, 3) self.assertFalse(unmatched_cats) - self.assertEqual(unmatched_symbols, ['C', 'b']) + self.assertEqual(unmatched_symbols, ["C", "b"]) # make sure symbols were applied context = QgsRenderContext() renderer.startRender(context, QgsFields()) - symbol, ok = renderer.symbolForValue2('a') + symbol, ok = renderer.symbolForValue2("a") self.assertTrue(ok) - self.assertEqual(symbol.color().name(), '#ff0a0a') - symbol, ok = renderer.symbolForValue2('b') + self.assertEqual(symbol.color().name(), "#ff0a0a") + symbol, ok = renderer.symbolForValue2("b") self.assertTrue(ok) - self.assertEqual(symbol.color().name(), '#0aff0a') - symbol, ok = renderer.symbolForValue2('c ') + self.assertEqual(symbol.color().name(), "#0aff0a") + symbol, ok = renderer.symbolForValue2("c ") self.assertTrue(ok) - self.assertEqual(symbol.color().name(), '#0aff0a') + self.assertEqual(symbol.color().name(), "#0aff0a") renderer.stopRender(context) def testUsedAttributes(self): @@ -589,11 +635,13 @@ def testUsedAttributes(self): renderer.setClassAttribute("value - 1") self.assertEqual(renderer.usedAttributes(ctx), {"value", "value - 1"}) renderer.setClassAttribute("valuea - valueb") - self.assertEqual(renderer.usedAttributes(ctx), {"valuea", "valuea - valueb", "valueb"}) + self.assertEqual( + renderer.usedAttributes(ctx), {"valuea", "valuea - valueb", "valueb"} + ) def testPointsUsedAttributes(self): - points_shp = os.path.join(TEST_DATA_DIR, 'points.shp') - points_layer = QgsVectorLayer(points_shp, 'Points', 'ogr') + points_shp = os.path.join(TEST_DATA_DIR, "points.shp") + points_layer = QgsVectorLayer(points_shp, "Points", "ogr") QgsProject.instance().addMapLayer(points_layer) cats = [] @@ -601,21 +649,27 @@ def testPointsUsedAttributes(self): l1 = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 5) l1.setColor(QColor(255, 0, 0)) l1.setStrokeStyle(Qt.PenStyle.NoPen) - l1.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyAngle, QgsProperty.fromField("Heading")) + l1.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyAngle, QgsProperty.fromField("Heading") + ) sym1.changeSymbolLayer(0, l1) cats.append(QgsRendererCategory("B52", sym1, "B52")) sym2 = QgsMarkerSymbol() l2 = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 5) l2.setColor(QColor(0, 255, 0)) l2.setStrokeStyle(Qt.PenStyle.NoPen) - l2.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyAngle, QgsProperty.fromField("Heading")) + l2.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyAngle, QgsProperty.fromField("Heading") + ) sym2.changeSymbolLayer(0, l2) cats.append(QgsRendererCategory("Biplane", sym2, "Biplane")) sym3 = QgsMarkerSymbol() l3 = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 5) l3.setColor(QColor(0, 0, 255)) l3.setStrokeStyle(Qt.PenStyle.NoPen) - l3.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyAngle, QgsProperty.fromField("Heading")) + l3.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyAngle, QgsProperty.fromField("Heading") + ) sym3.changeSymbolLayer(0, l3) cats.append(QgsRendererCategory("Jet", sym3, "Jet")) @@ -633,11 +687,11 @@ def testPointsUsedAttributes(self): ctx.expressionContext().appendScope(points_layer.createExpressionContextScope()) # for symbol layer - self.assertCountEqual(l1.usedAttributes(ctx), {'Heading'}) + self.assertCountEqual(l1.usedAttributes(ctx), {"Heading"}) # for symbol - self.assertCountEqual(sym1.usedAttributes(ctx), {'Heading'}) + self.assertCountEqual(sym1.usedAttributes(ctx), {"Heading"}) # for symbol renderer - self.assertCountEqual(renderer.usedAttributes(ctx), {'Class', 'Heading'}) + self.assertCountEqual(renderer.usedAttributes(ctx), {"Class", "Heading"}) QgsProject.instance().removeMapLayer(points_layer) @@ -652,84 +706,114 @@ def testFilterNeedsGeometry(self): self.assertTrue(renderer.filterNeedsGeometry()) def testCategories(self): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory") - layer.setEditorWidgetSetup(1, QgsEditorWidgetSetup("ValueMap", {'map': [{'One': '1'}, {'Two': '2'}]})) + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) + layer.setEditorWidgetSetup( + 1, QgsEditorWidgetSetup("ValueMap", {"map": [{"One": "1"}, {"Two": "2"}]}) + ) - result = QgsCategorizedSymbolRenderer.createCategories([1, 2, 3], QgsMarkerSymbol(), layer, 'fldint') + result = QgsCategorizedSymbolRenderer.createCategories( + [1, 2, 3], QgsMarkerSymbol(), layer, "fldint" + ) - self.assertEqual(result[0].label(), 'One') - self.assertEqual(result[1].label(), 'Two') - self.assertEqual(result[2].label(), '(3)') + self.assertEqual(result[0].label(), "One") + self.assertEqual(result[1].label(), "Two") + self.assertEqual(result[2].label(), "(3)") def testWriteReadXml(self): # test writing renderer to xml and restoring renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('x') + renderer.setClassAttribute("x") symbol_a = createMarkerSymbol() symbol_a.setColor(QColor(255, 0, 0)) - renderer.addCategory(QgsRendererCategory('a', symbol_a, 'a')) + renderer.addCategory(QgsRendererCategory("a", symbol_a, "a")) symbol_b = createMarkerSymbol() symbol_b.setColor(QColor(0, 255, 0)) - renderer.addCategory(QgsRendererCategory('b', symbol_b, 'b')) + renderer.addCategory(QgsRendererCategory("b", symbol_b, "b")) symbol_c = createMarkerSymbol() symbol_c.setColor(QColor(0, 0, 255)) - renderer.addCategory(QgsRendererCategory('c', symbol_c, 'c', False)) + renderer.addCategory(QgsRendererCategory("c", symbol_c, "c", False)) symbol_d = createMarkerSymbol() symbol_d.setColor(QColor(255, 0, 255)) - renderer.addCategory(QgsRendererCategory(['d', 'e'], symbol_d, 'de')) + renderer.addCategory(QgsRendererCategory(["d", "e"], symbol_d, "de")) # add default category default_symbol = createMarkerSymbol() default_symbol.setColor(QColor(255, 255, 255)) - renderer.addCategory(QgsRendererCategory('', default_symbol, 'default')) + renderer.addCategory(QgsRendererCategory("", default_symbol, "default")) doc = QDomDocument("testdoc") elem = renderer.save(doc, QgsReadWriteContext()) renderer2 = QgsCategorizedSymbolRenderer.create(elem, QgsReadWriteContext()) - self.assertEqual(renderer2.classAttribute(), 'x') - self.assertEqual([l.label() for l in renderer2.categories()], ['a', 'b', 'c', 'de', 'default']) - self.assertEqual([l.value() for l in renderer2.categories()], ['a', 'b', 'c', ['d', 'e'], '']) - self.assertEqual([l.symbol().color().name() for l in renderer2.categories()], - ['#ff0000', '#00ff00', '#0000ff', '#ff00ff', '#ffffff']) + self.assertEqual(renderer2.classAttribute(), "x") + self.assertEqual( + [l.label() for l in renderer2.categories()], + ["a", "b", "c", "de", "default"], + ) + self.assertEqual( + [l.value() for l in renderer2.categories()], ["a", "b", "c", ["d", "e"], ""] + ) + self.assertEqual( + [l.symbol().color().name() for l in renderer2.categories()], + ["#ff0000", "#00ff00", "#0000ff", "#ff00ff", "#ffffff"], + ) def testConvertFromEmbedded(self): """ Test converting an embedded symbol renderer to a categorized renderer """ - points_layer = QgsVectorLayer('Point', 'Polys', 'memory') + points_layer = QgsVectorLayer("Point", "Polys", "memory") f = QgsFeature() - f.setGeometry(QgsGeometry.fromWkt('Point(-100 30)')) + f.setGeometry(QgsGeometry.fromWkt("Point(-100 30)")) f.setEmbeddedSymbol( - QgsMarkerSymbol.createSimple({'name': 'triangle', 'size': 10, 'color': '#ff0000', 'outline_style': 'no'})) + QgsMarkerSymbol.createSimple( + { + "name": "triangle", + "size": 10, + "color": "#ff0000", + "outline_style": "no", + } + ) + ) self.assertTrue(points_layer.dataProvider().addFeature(f)) - f.setGeometry(QgsGeometry.fromWkt('Point(-110 40)')) + f.setGeometry(QgsGeometry.fromWkt("Point(-110 40)")) f.setEmbeddedSymbol( - QgsMarkerSymbol.createSimple({'name': 'square', 'size': 7, 'color': '#00ff00', 'outline_style': 'no'})) + QgsMarkerSymbol.createSimple( + {"name": "square", "size": 7, "color": "#00ff00", "outline_style": "no"} + ) + ) self.assertTrue(points_layer.dataProvider().addFeature(f)) - f.setGeometry(QgsGeometry.fromWkt('Point(-90 50)')) + f.setGeometry(QgsGeometry.fromWkt("Point(-90 50)")) f.setEmbeddedSymbol(None) self.assertTrue(points_layer.dataProvider().addFeature(f)) - renderer = QgsEmbeddedSymbolRenderer(defaultSymbol=QgsMarkerSymbol.createSimple({'name': 'star', 'size': 10, 'color': '#ff00ff', 'outline_style': 'no'})) + renderer = QgsEmbeddedSymbolRenderer( + defaultSymbol=QgsMarkerSymbol.createSimple( + {"name": "star", "size": 10, "color": "#ff00ff", "outline_style": "no"} + ) + ) points_layer.setRenderer(renderer) - categorized = QgsCategorizedSymbolRenderer.convertFromRenderer(renderer, points_layer) - self.assertEqual(categorized.classAttribute(), '$id') + categorized = QgsCategorizedSymbolRenderer.convertFromRenderer( + renderer, points_layer + ) + self.assertEqual(categorized.classAttribute(), "$id") self.assertEqual(len(categorized.categories()), 3) cc = categorized.categories()[0] self.assertEqual(cc.value(), 1) - self.assertEqual(cc.label(), '1') - self.assertEqual(cc.symbol().color().name(), '#ff0000') + self.assertEqual(cc.label(), "1") + self.assertEqual(cc.symbol().color().name(), "#ff0000") cc = categorized.categories()[1] self.assertEqual(cc.value(), 2) - self.assertEqual(cc.label(), '2') - self.assertEqual(cc.symbol().color().name(), '#00ff00') + self.assertEqual(cc.label(), "2") + self.assertEqual(cc.symbol().color().name(), "#00ff00") cc = categorized.categories()[2] self.assertEqual(cc.value(), None) - self.assertEqual(cc.label(), '') - self.assertEqual(cc.symbol().color().name(), '#ff00ff') + self.assertEqual(cc.label(), "") + self.assertEqual(cc.symbol().color().name(), "#ff00ff") def test_displayString(self): """Test the displayString method""" @@ -740,42 +824,88 @@ def test_displayString(self): locale.setNumberOptions(QLocale.NumberOption.DefaultNumberOptions) QLocale().setDefault(locale) - self.assertEqual(QgsCategorizedSymbolRenderer.displayString(1234.56), "1,234.56") - self.assertEqual(QgsCategorizedSymbolRenderer.displayString(1234.56, 4), "1,234.5600") - self.assertEqual(QgsCategorizedSymbolRenderer.displayString(1234567), "1,234,567") - self.assertEqual(QgsCategorizedSymbolRenderer.displayString(1234567.0, 4), "1,234,567.0000") + self.assertEqual( + QgsCategorizedSymbolRenderer.displayString(1234.56), "1,234.56" + ) + self.assertEqual( + QgsCategorizedSymbolRenderer.displayString(1234.56, 4), "1,234.5600" + ) + self.assertEqual( + QgsCategorizedSymbolRenderer.displayString(1234567), "1,234,567" + ) + self.assertEqual( + QgsCategorizedSymbolRenderer.displayString(1234567.0, 4), "1,234,567.0000" + ) # Precision is ignored for integers - self.assertEqual(QgsCategorizedSymbolRenderer.displayString(1234567, 4), "1,234,567") + self.assertEqual( + QgsCategorizedSymbolRenderer.displayString(1234567, 4), "1,234,567" + ) # Test list - self.assertEqual(QgsCategorizedSymbolRenderer.displayString([1234567, 891234], 4), "1,234,567;891,234") - self.assertEqual(QgsCategorizedSymbolRenderer.displayString([1234567.123, 891234.123], 4), "1,234,567.1230;891,234.1230") + self.assertEqual( + QgsCategorizedSymbolRenderer.displayString([1234567, 891234], 4), + "1,234,567;891,234", + ) + self.assertEqual( + QgsCategorizedSymbolRenderer.displayString([1234567.123, 891234.123], 4), + "1,234,567.1230;891,234.1230", + ) locale.setNumberOptions(QLocale.NumberOption.OmitGroupSeparator) QLocale().setDefault(locale) - self.assertTrue(QLocale().numberOptions() & QLocale.NumberOption.OmitGroupSeparator) - self.assertEqual(QgsCategorizedSymbolRenderer.displayString([1234567, 891234], 4), "1234567;891234") - self.assertEqual(QgsCategorizedSymbolRenderer.displayString([1234567.123, 891234.123], 4), "1234567.1230;891234.1230") + self.assertTrue( + QLocale().numberOptions() & QLocale.NumberOption.OmitGroupSeparator + ) + self.assertEqual( + QgsCategorizedSymbolRenderer.displayString([1234567, 891234], 4), + "1234567;891234", + ) + self.assertEqual( + QgsCategorizedSymbolRenderer.displayString([1234567.123, 891234.123], 4), + "1234567.1230;891234.1230", + ) # Test a non-dot locale locale = QLocale(QLocale.Language.Italian) locale.setNumberOptions(QLocale.NumberOption.DefaultNumberOptions) QLocale().setDefault(locale) - self.assertEqual(QgsCategorizedSymbolRenderer.displayString(1234.56), "1.234,56") - self.assertEqual(QgsCategorizedSymbolRenderer.displayString(1234.56, 4), "1.234,5600") - self.assertEqual(QgsCategorizedSymbolRenderer.displayString(1234567), "1.234.567") - self.assertEqual(QgsCategorizedSymbolRenderer.displayString(1234567.0, 4), "1.234.567,0000") + self.assertEqual( + QgsCategorizedSymbolRenderer.displayString(1234.56), "1.234,56" + ) + self.assertEqual( + QgsCategorizedSymbolRenderer.displayString(1234.56, 4), "1.234,5600" + ) + self.assertEqual( + QgsCategorizedSymbolRenderer.displayString(1234567), "1.234.567" + ) + self.assertEqual( + QgsCategorizedSymbolRenderer.displayString(1234567.0, 4), "1.234.567,0000" + ) # Precision is ignored for integers - self.assertEqual(QgsCategorizedSymbolRenderer.displayString(1234567, 4), "1.234.567") + self.assertEqual( + QgsCategorizedSymbolRenderer.displayString(1234567, 4), "1.234.567" + ) # Test list - self.assertEqual(QgsCategorizedSymbolRenderer.displayString([1234567, 891234], 4), "1.234.567;891.234") - self.assertEqual(QgsCategorizedSymbolRenderer.displayString([1234567.123, 891234.123], 4), "1.234.567,1230;891.234,1230") + self.assertEqual( + QgsCategorizedSymbolRenderer.displayString([1234567, 891234], 4), + "1.234.567;891.234", + ) + self.assertEqual( + QgsCategorizedSymbolRenderer.displayString([1234567.123, 891234.123], 4), + "1.234.567,1230;891.234,1230", + ) locale.setNumberOptions(QLocale.NumberOption.OmitGroupSeparator) QLocale().setDefault(locale) - self.assertEqual(QgsCategorizedSymbolRenderer.displayString([1234567, 891234], 4), "1234567;891234") - self.assertEqual(QgsCategorizedSymbolRenderer.displayString([1234567.123, 891234.123], 4), "1234567,1230;891234,1230") + self.assertEqual( + QgsCategorizedSymbolRenderer.displayString([1234567, 891234], 4), + "1234567;891234", + ) + self.assertEqual( + QgsCategorizedSymbolRenderer.displayString([1234567.123, 891234.123], 4), + "1234567,1230;891234,1230", + ) QLocale().setDefault(original_locale) @@ -787,28 +917,34 @@ def test_localizedCategories(self): locale.setNumberOptions(QLocale.NumberOption.DefaultNumberOptions) QLocale().setDefault(locale) - layer = QgsVectorLayer("Point?field=flddbl:double&field=fldint:integer", "addfeat", "memory") - result = QgsCategorizedSymbolRenderer.createCategories([1234.5, 2345.6, 3456.7], QgsMarkerSymbol(), layer, 'flddouble') + layer = QgsVectorLayer( + "Point?field=flddbl:double&field=fldint:integer", "addfeat", "memory" + ) + result = QgsCategorizedSymbolRenderer.createCategories( + [1234.5, 2345.6, 3456.7], QgsMarkerSymbol(), layer, "flddouble" + ) - self.assertEqual(result[0].label(), '1,234.5') - self.assertEqual(result[1].label(), '2,345.6') - self.assertEqual(result[2].label(), '3,456.7') + self.assertEqual(result[0].label(), "1,234.5") + self.assertEqual(result[1].label(), "2,345.6") + self.assertEqual(result[2].label(), "3,456.7") # Test a non-dot locale QLocale().setDefault(QLocale(QLocale.Language.Italian)) - result = QgsCategorizedSymbolRenderer.createCategories([[1234.5, 6789.1], 2345.6, 3456.7], QgsMarkerSymbol(), layer, 'flddouble') + result = QgsCategorizedSymbolRenderer.createCategories( + [[1234.5, 6789.1], 2345.6, 3456.7], QgsMarkerSymbol(), layer, "flddouble" + ) - self.assertEqual(result[0].label(), '1.234,5;6.789,1') - self.assertEqual(result[1].label(), '2.345,6') - self.assertEqual(result[2].label(), '3.456,7') + self.assertEqual(result[0].label(), "1.234,5;6.789,1") + self.assertEqual(result[1].label(), "2.345,6") + self.assertEqual(result[2].label(), "3.456,7") # Test round trip temp_dir = QTemporaryDir() - temp_file = os.path.join(temp_dir.path(), 'project.qgs') + temp_file = os.path.join(temp_dir.path(), "project.qgs") project = QgsProject() - layer.setRenderer(QgsCategorizedSymbolRenderer('Class', result)) + layer.setRenderer(QgsCategorizedSymbolRenderer("Class", result)) project.addMapLayers([layer]) project.write(temp_file) @@ -816,77 +952,79 @@ def test_localizedCategories(self): project = QgsProject() project.read(temp_file) - results = project.mapLayersByName('addfeat')[0].renderer().categories() + results = project.mapLayersByName("addfeat")[0].renderer().categories() - self.assertEqual(result[0].label(), '1.234,5;6.789,1') - self.assertEqual(result[1].label(), '2.345,6') - self.assertEqual(result[2].label(), '3.456,7') + self.assertEqual(result[0].label(), "1.234,5;6.789,1") + self.assertEqual(result[1].label(), "2.345,6") + self.assertEqual(result[2].label(), "3.456,7") self.assertEqual(result[0].value(), [1234.5, 6789.1]) self.assertEqual(result[1].value(), 2345.6) self.assertEqual(result[2].value(), 3456.7) def test_legend_key_to_expression(self): renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('field_name') + renderer.setClassAttribute("field_name") - exp, ok = renderer.legendKeyToExpression('xxxx', None) + exp, ok = renderer.legendKeyToExpression("xxxx", None) self.assertFalse(ok) # no categories - exp, ok = renderer.legendKeyToExpression('0', None) + exp, ok = renderer.legendKeyToExpression("0", None) self.assertFalse(ok) symbol_a = createMarkerSymbol() - renderer.addCategory(QgsRendererCategory('a', symbol_a, 'a', True, '0')) + renderer.addCategory(QgsRendererCategory("a", symbol_a, "a", True, "0")) symbol_b = createMarkerSymbol() - renderer.addCategory(QgsRendererCategory(5, symbol_b, 'b', True, '1')) + renderer.addCategory(QgsRendererCategory(5, symbol_b, "b", True, "1")) symbol_c = createMarkerSymbol() - renderer.addCategory(QgsRendererCategory(5.5, symbol_c, 'c', False, '2')) + renderer.addCategory(QgsRendererCategory(5.5, symbol_c, "c", False, "2")) symbol_d = createMarkerSymbol() - renderer.addCategory(QgsRendererCategory(['d', 'e'], symbol_d, 'de', True, '3')) + renderer.addCategory(QgsRendererCategory(["d", "e"], symbol_d, "de", True, "3")) - exp, ok = renderer.legendKeyToExpression('0', None) + exp, ok = renderer.legendKeyToExpression("0", None) self.assertTrue(ok) self.assertEqual(exp, "field_name = 'a'") - exp, ok = renderer.legendKeyToExpression('1', None) + exp, ok = renderer.legendKeyToExpression("1", None) self.assertTrue(ok) self.assertEqual(exp, "field_name = 5") - exp, ok = renderer.legendKeyToExpression('2', None) + exp, ok = renderer.legendKeyToExpression("2", None) self.assertTrue(ok) self.assertEqual(exp, "field_name = 5.5") - exp, ok = renderer.legendKeyToExpression('3', None) + exp, ok = renderer.legendKeyToExpression("3", None) self.assertTrue(ok) self.assertEqual(exp, "field_name IN ('d', 'e')") - layer = QgsVectorLayer("Point?field=field_name:double&field=fldint:integer", "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=field_name:double&field=fldint:integer", "addfeat", "memory" + ) # with layer - exp, ok = renderer.legendKeyToExpression('3', layer) + exp, ok = renderer.legendKeyToExpression("3", layer) self.assertTrue(ok) self.assertEqual(exp, "\"field_name\" IN ('d', 'e')") # with expression as attribute renderer.setClassAttribute('upper("field_name")') - exp, ok = renderer.legendKeyToExpression('0', None) + exp, ok = renderer.legendKeyToExpression("0", None) self.assertTrue(ok) self.assertEqual(exp, """upper("field_name") = 'a'""") - exp, ok = renderer.legendKeyToExpression('1', None) + exp, ok = renderer.legendKeyToExpression("1", None) self.assertTrue(ok) self.assertEqual(exp, """upper("field_name") = 5""") - exp, ok = renderer.legendKeyToExpression('2', None) + exp, ok = renderer.legendKeyToExpression("2", None) self.assertTrue(ok) self.assertEqual(exp, """upper("field_name") = 5.5""") - exp, ok = renderer.legendKeyToExpression('3', None) + exp, ok = renderer.legendKeyToExpression("3", None) self.assertTrue(ok) self.assertEqual(exp, """upper("field_name") IN ('d', 'e')""") - exp, ok = renderer.legendKeyToExpression('3', layer) + exp, ok = renderer.legendKeyToExpression("3", layer) self.assertTrue(ok) self.assertEqual(exp, """upper("field_name") IN ('d', 'e')""") @@ -897,50 +1035,56 @@ def testSldRuleExport(self): self.assertTrue(vl.isValid()) self.assertTrue( - vl.dataProvider().addAttributes([ - QgsField('Text Field With Spaces', QVariant.String) - ]) + vl.dataProvider().addAttributes( + [QgsField("Text Field With Spaces", QVariant.String)] + ) ) vl.updateFields() # Create style - foo_sym = QgsFillSymbol.createSimple({'color': '#ff0000', 'outline_color': 'foo'}) - bar_sym = QgsFillSymbol.createSimple({'color': '#00ff00', 'outline_color': 'bar'}) + foo_sym = QgsFillSymbol.createSimple( + {"color": "#ff0000", "outline_color": "foo"} + ) + bar_sym = QgsFillSymbol.createSimple( + {"color": "#00ff00", "outline_color": "bar"} + ) renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('Text Field With Spaces') + renderer.setClassAttribute("Text Field With Spaces") - renderer.addCategory(QgsRendererCategory('foo', foo_sym, 'foo')) - renderer.addCategory(QgsRendererCategory('bar', bar_sym, 'bar')) + renderer.addCategory(QgsRendererCategory("foo", foo_sym, "foo")) + renderer.addCategory(QgsRendererCategory("bar", bar_sym, "bar")) vl.setRenderer(renderer) doc = QDomDocument() vl.exportSldStyle(doc, None) - self.assertNotIn('Parser Error', doc.toString()) + self.assertNotIn("Parser Error", doc.toString()) def test_to_sld(self): renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('field_name') + renderer.setClassAttribute("field_name") symbol_a = createMarkerSymbol() - renderer.addCategory(QgsRendererCategory('a', symbol_a, 'a', True, '0')) + renderer.addCategory(QgsRendererCategory("a", symbol_a, "a", True, "0")) symbol_b = createMarkerSymbol() - renderer.addCategory(QgsRendererCategory(5, symbol_b, 'b', True, '1')) + renderer.addCategory(QgsRendererCategory(5, symbol_b, "b", True, "1")) symbol_c = createMarkerSymbol() - renderer.addCategory(QgsRendererCategory(5.5, symbol_c, 'c', False, '2')) + renderer.addCategory(QgsRendererCategory(5.5, symbol_c, "c", False, "2")) symbol_d = createMarkerSymbol() - renderer.addCategory(QgsRendererCategory(['d', 'e'], symbol_d, 'de', True, '3')) + renderer.addCategory(QgsRendererCategory(["d", "e"], symbol_d, "de", True, "3")) symbol_f = createMarkerSymbol() - renderer.addCategory(QgsRendererCategory(None, symbol_f, 'f', True, '4')) + renderer.addCategory(QgsRendererCategory(None, symbol_f, "f", True, "4")) # this category should NOT be included in the SLD, as it would otherwise result # in an invalid se:rule with no symbolizer element symbol_which_is_empty_in_sld = createFillSymbol() symbol_which_is_empty_in_sld[0].setBrushStyle(Qt.BrushStyle.NoBrush) symbol_which_is_empty_in_sld[0].setStrokeStyle(Qt.PenStyle.NoPen) - renderer.addCategory(QgsRendererCategory(None, symbol_which_is_empty_in_sld, 'empty', True, '4')) + renderer.addCategory( + QgsRendererCategory(None, symbol_which_is_empty_in_sld, "empty", True, "4") + ) dom = QDomDocument() root = dom.createElement("FakeRoot") @@ -1098,12 +1242,14 @@ def test_to_sld(self): self.assertEqual(dom.toString(), expected) # with an expression for attribute - renderer.setClassAttribute('field_name + 2') + renderer.setClassAttribute("field_name + 2") dom = QDomDocument() root = dom.createElement("FakeRoot") dom.appendChild(root) renderer.toSld(dom, root, {}) - self.assertEqual(dom.toString(), """ + self.assertEqual( + dom.toString(), + """ a @@ -1256,7 +1402,8 @@ def test_to_sld(self): -""") +""", + ) if __name__ == "__main__": diff --git a/tests/src/python/test_qgscesium3dtileslayer.py b/tests/src/python/test_qgscesium3dtileslayer.py index 0e2701575783..264288afa040 100644 --- a/tests/src/python/test_qgscesium3dtileslayer.py +++ b/tests/src/python/test_qgscesium3dtileslayer.py @@ -5,6 +5,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + __author__ = "Nyall Dawson" __date__ = "27/06/2023" __copyright__ = "Copyright 2023, The QGIS Project" @@ -33,21 +34,25 @@ def test_invalid_source(self): def test_invalid_json(self): with tempfile.TemporaryDirectory() as temp_dir: tmp_file = os.path.join(temp_dir, "tileset.json") - with open(tmp_file, "wt", encoding="utf-8") as f: + with open(tmp_file, "w", encoding="utf-8") as f: f.write( """ { "featurecollection": {} } -""") +""" + ) layer = QgsTiledSceneLayer(tmp_file, "my layer", "cesiumtiles") self.assertFalse(layer.dataProvider().isValid()) - self.assertEqual(layer.error().summary(), 'JSON is not a valid Cesium 3D Tiles source (does not contain "root" value)') + self.assertEqual( + layer.error().summary(), + 'JSON is not a valid Cesium 3D Tiles source (does not contain "root" value)', + ) def test_source_bounding_volume_region(self): with tempfile.TemporaryDirectory() as temp_dir: tmp_file = os.path.join(temp_dir, "tileset.json") - with open(tmp_file, "wt", encoding="utf-8") as f: + with open(tmp_file, "w", encoding="utf-8") as f: f.write( """ { @@ -98,12 +103,8 @@ def test_source_bounding_volume_region(self): self.assertAlmostEqual( layer.dataProvider().boundingVolume().box().centerZ(), 34.105, 3 ) - self.assertAlmostEqual( - layer.dataProvider().zRange().lower(), 1.2, 3 - ) - self.assertAlmostEqual( - layer.dataProvider().zRange().upper(), 67.0099, 3 - ) + self.assertAlmostEqual(layer.dataProvider().zRange().lower(), 1.2, 3) + self.assertAlmostEqual(layer.dataProvider().zRange().upper(), 67.0099, 3) # check that version, tileset version, and z range are in html metadata self.assertIn("1.1", layer.dataProvider().htmlMetadata()) @@ -113,32 +114,45 @@ def test_source_bounding_volume_region(self): # check metadata layer.loadDefaultMetadata() self.assertEqual(layer.metadata().type(), "dataset") - self.assertEqual(layer.metadata().identifier(), 'e575c6f1') - self.assertEqual(layer.metadata().crs().authid(), 'EPSG:4978') - self.assertEqual(layer.metadata().extent().spatialExtents()[0].extentCrs.authid(), "EPSG:4979") + self.assertEqual(layer.metadata().identifier(), "e575c6f1") + self.assertEqual(layer.metadata().crs().authid(), "EPSG:4978") + self.assertEqual( + layer.metadata().extent().spatialExtents()[0].extentCrs.authid(), + "EPSG:4979", + ) self.assertAlmostEqual( - layer.metadata().extent().spatialExtents()[0].bounds.xMinimum(), -75.61444, 3 + layer.metadata().extent().spatialExtents()[0].bounds.xMinimum(), + -75.61444, + 3, ) self.assertAlmostEqual( - layer.metadata().extent().spatialExtents()[0].bounds.xMaximum(), -75.609747, 3 + layer.metadata().extent().spatialExtents()[0].bounds.xMaximum(), + -75.609747, + 3, ) self.assertAlmostEqual( - layer.metadata().extent().spatialExtents()[0].bounds.yMinimum(), 40.040721, 3 + layer.metadata().extent().spatialExtents()[0].bounds.yMinimum(), + 40.040721, + 3, ) self.assertAlmostEqual( - layer.metadata().extent().spatialExtents()[0].bounds.yMaximum(), 40.0443399, 3 + layer.metadata().extent().spatialExtents()[0].bounds.yMaximum(), + 40.0443399, + 3, ) self.assertAlmostEqual( layer.metadata().extent().spatialExtents()[0].bounds.zMinimum(), 1.2, 3 ) self.assertAlmostEqual( - layer.metadata().extent().spatialExtents()[0].bounds.zMaximum(), 67.0099999, 3 + layer.metadata().extent().spatialExtents()[0].bounds.zMaximum(), + 67.0099999, + 3, ) def test_source_bounding_volume_region_with_transform(self): with tempfile.TemporaryDirectory() as temp_dir: tmp_file = os.path.join(temp_dir, "tileset.json") - with open(tmp_file, "wt", encoding="utf-8") as f: + with open(tmp_file, "w", encoding="utf-8") as f: f.write( """ { @@ -177,7 +191,7 @@ def test_source_bounding_volume_region_with_transform(self): def test_source_bounding_volume_box(self): with tempfile.TemporaryDirectory() as temp_dir: tmp_file = os.path.join(temp_dir, "tileset.json") - with open(tmp_file, "wt", encoding="utf-8") as f: + with open(tmp_file, "w", encoding="utf-8") as f: f.write( """ { @@ -240,7 +254,7 @@ def test_source_bounding_volume_box(self): def test_source_bounding_sphere(self): with tempfile.TemporaryDirectory() as temp_dir: tmp_file = os.path.join(temp_dir, "tileset.json") - with open(tmp_file, "wt", encoding="utf-8") as f: + with open(tmp_file, "w", encoding="utf-8") as f: f.write( """ { @@ -318,7 +332,7 @@ def compare_boxes(self, box1: QgsOrientedBox3D, box2: QgsOrientedBox3D) -> bool: def test_index(self): with tempfile.TemporaryDirectory() as temp_dir: tmp_file = os.path.join(temp_dir, "tileset.json") - with open(tmp_file, "wt", encoding="utf-8") as f: + with open(tmp_file, "w", encoding="utf-8") as f: f.write( """ { @@ -1128,7 +1142,8 @@ def test_index(self): tile = index.getTile(tile_ids[2]) self.assertEqual( - tile.resources(), {"content": "file://" + temp_dir + "/LOD-2/Mesh-XR-YR.b3dm"} + tile.resources(), + {"content": "file://" + temp_dir + "/LOD-2/Mesh-XR-YR.b3dm"}, ) self.assertEqual(tile.geometricError(), 9.1) self.assertEqual(tile.baseUrl(), QUrl("file://" + tmp_file)) @@ -1155,7 +1170,8 @@ def test_index(self): tile = index.getTile(tile_ids[1]) self.assertEqual( - tile.resources(), {"content": "file://" + temp_dir + "/LOD-1/Mesh-XR-YR.b3dm"} + tile.resources(), + {"content": "file://" + temp_dir + "/LOD-1/Mesh-XR-YR.b3dm"}, ) self.assertEqual(tile.geometricError(), 3) self.assertEqual(tile.baseUrl(), QUrl("file://" + tmp_file)) @@ -1182,7 +1198,8 @@ def test_index(self): tile = index.getTile(tile_ids[0]) self.assertEqual( - tile.resources(), {"content": "file://" + temp_dir + "/LOD-0/Mesh-XR-YR.b3dm"} + tile.resources(), + {"content": "file://" + temp_dir + "/LOD-0/Mesh-XR-YR.b3dm"}, ) self.assertEqual(tile.geometricError(), 0) self.assertEqual(tile.baseUrl(), QUrl("file://" + tmp_file)) @@ -1209,7 +1226,8 @@ def test_index(self): tile = index.getTile(tile_ids[5]) self.assertEqual( - tile.resources(), {"content": "file://" + temp_dir + "/LOD-2/Mesh-XL-YR.b3dm"} + tile.resources(), + {"content": "file://" + temp_dir + "/LOD-2/Mesh-XL-YR.b3dm"}, ) self.assertEqual(tile.geometricError(), 9.1) self.assertEqual(tile.baseUrl(), QUrl("file://" + tmp_file)) @@ -1236,7 +1254,8 @@ def test_index(self): tile = index.getTile(tile_ids[4]) self.assertEqual( - tile.resources(), {"content": "file://" + temp_dir + "/LOD-1/Mesh-XL-YR.b3dm"} + tile.resources(), + {"content": "file://" + temp_dir + "/LOD-1/Mesh-XL-YR.b3dm"}, ) self.assertEqual(tile.geometricError(), 3) self.assertEqual(tile.baseUrl(), QUrl("file://" + tmp_file)) @@ -1263,7 +1282,8 @@ def test_index(self): tile = index.getTile(tile_ids[3]) self.assertEqual( - tile.resources(), {"content": "file://" + temp_dir + "/LOD-0/Mesh-XL-YR.b3dm"} + tile.resources(), + {"content": "file://" + temp_dir + "/LOD-0/Mesh-XL-YR.b3dm"}, ) self.assertEqual(tile.geometricError(), 0) self.assertEqual(tile.baseUrl(), QUrl("file://" + tmp_file)) @@ -1290,7 +1310,8 @@ def test_index(self): tile = index.getTile(tile_ids[8]) self.assertEqual( - tile.resources(), {"content": "file://" + temp_dir + "/LOD-2/Mesh-XR-YL.b3dm"} + tile.resources(), + {"content": "file://" + temp_dir + "/LOD-2/Mesh-XR-YL.b3dm"}, ) self.assertEqual(tile.geometricError(), 9.0) self.assertEqual(tile.baseUrl(), QUrl("file://" + tmp_file)) @@ -1317,7 +1338,8 @@ def test_index(self): tile = index.getTile(tile_ids[7]) self.assertEqual( - tile.resources(), {"content": "file://" + temp_dir + "/LOD-1/Mesh-XR-YL.b3dm"} + tile.resources(), + {"content": "file://" + temp_dir + "/LOD-1/Mesh-XR-YL.b3dm"}, ) self.assertEqual(tile.geometricError(), 3) self.assertEqual(tile.baseUrl(), QUrl("file://" + tmp_file)) @@ -1344,7 +1366,8 @@ def test_index(self): tile = index.getTile(tile_ids[6]) self.assertEqual( - tile.resources(), {"content": "file://" + temp_dir + "/LOD-0/Mesh-XR-YL.b3dm"} + tile.resources(), + {"content": "file://" + temp_dir + "/LOD-0/Mesh-XR-YL.b3dm"}, ) self.assertEqual(tile.geometricError(), 0) self.assertEqual(tile.baseUrl(), QUrl("file://" + tmp_file)) @@ -1371,7 +1394,8 @@ def test_index(self): tile = index.getTile(tile_ids[10]) self.assertEqual( - tile.resources(), {"content": "file://" + temp_dir + "/LOD-2/Mesh-XL-YL.b3dm"} + tile.resources(), + {"content": "file://" + temp_dir + "/LOD-2/Mesh-XL-YL.b3dm"}, ) self.assertEqual(tile.geometricError(), 9.1) self.assertEqual(tile.baseUrl(), QUrl("file://" + tmp_file)) @@ -1400,7 +1424,8 @@ def test_index(self): tile = index.getTile(tile_ids[9]) self.assertEqual( - tile.resources(), {"content": "file://" + temp_dir + "/LOD-0/Mesh-XL-YL.b3dm"} + tile.resources(), + {"content": "file://" + temp_dir + "/LOD-0/Mesh-XL-YL.b3dm"}, ) self.assertEqual(tile.geometricError(), 0) self.assertEqual(tile.baseUrl(), QUrl("file://" + tmp_file)) @@ -1458,7 +1483,8 @@ def test_index(self): tile = index.getTile(tile_ids[0]) parent_id = tile_ids[0] self.assertEqual( - tile.resources(), {"content": "file://" + temp_dir + "/LOD-2/Mesh-XR-YR.b3dm"} + tile.resources(), + {"content": "file://" + temp_dir + "/LOD-2/Mesh-XR-YR.b3dm"}, ) self.assertEqual(tile.geometricError(), 9.1) self.assertEqual( @@ -1484,7 +1510,8 @@ def test_index(self): tile = index.getTile(tile_ids[1]) self.assertEqual( - tile.resources(), {"content": "file://" + temp_dir + "/LOD-2/Mesh-XL-YR.b3dm"} + tile.resources(), + {"content": "file://" + temp_dir + "/LOD-2/Mesh-XL-YR.b3dm"}, ) self.assertEqual(tile.geometricError(), 9.1) self.assertEqual( @@ -1510,7 +1537,8 @@ def test_index(self): tile = index.getTile(tile_ids[2]) self.assertEqual( - tile.resources(), {"content": "file://" + temp_dir + "/LOD-2/Mesh-XR-YL.b3dm"} + tile.resources(), + {"content": "file://" + temp_dir + "/LOD-2/Mesh-XR-YL.b3dm"}, ) self.assertEqual(tile.geometricError(), 9.0) self.assertEqual( @@ -1536,7 +1564,8 @@ def test_index(self): tile = index.getTile(tile_ids[3]) self.assertEqual( - tile.resources(), {"content": "file://" + temp_dir + "/LOD-2/Mesh-XL-YL.b3dm"} + tile.resources(), + {"content": "file://" + temp_dir + "/LOD-2/Mesh-XL-YL.b3dm"}, ) self.assertEqual(tile.geometricError(), 9.1) self.assertEqual( @@ -1566,13 +1595,14 @@ def test_index(self): self.assertEqual(len(tile_ids), 1) tile = index.getTile(tile_ids[0]) self.assertEqual( - tile.resources(), {"content": "file://" + temp_dir + "/LOD-2/Mesh-XR-YR.b3dm"} + tile.resources(), + {"content": "file://" + temp_dir + "/LOD-2/Mesh-XR-YR.b3dm"}, ) def test_gltf_up_axis(self): with tempfile.TemporaryDirectory() as temp_dir: tmp_file = os.path.join(temp_dir, "tileset.json") - with open(tmp_file, "wt", encoding="utf-8") as f: + with open(tmp_file, "w", encoding="utf-8") as f: f.write( """ { @@ -1624,7 +1654,7 @@ def test_large_dataset(self): """ with tempfile.TemporaryDirectory() as temp_dir: tmp_file = os.path.join(temp_dir, "tileset.json") - with open(tmp_file, "wt", encoding="utf-8") as f: + with open(tmp_file, "w", encoding="utf-8") as f: f.write( """{ "asset": { diff --git a/tests/src/python/test_qgscesiumutils.py b/tests/src/python/test_qgscesiumutils.py index 21f7d45abfde..04ad40b6732f 100644 --- a/tests/src/python/test_qgscesiumutils.py +++ b/tests/src/python/test_qgscesiumutils.py @@ -7,14 +7,13 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2023 by Nyall Dawson' -__date__ = '10/07/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "(C) 2023 by Nyall Dawson" +__date__ = "10/07/2023" +__copyright__ = "Copyright 2023, The QGIS Project" import math -from qgis.core import ( - QgsCesiumUtils -) +from qgis.core import QgsCesiumUtils import unittest from qgis.testing import start_app, QgisTestCase @@ -32,8 +31,7 @@ def test_parse_region(self): self.assertTrue(QgsCesiumUtils.parseRegion([1, 2, 3, 4]).isNull()) self.assertTrue(QgsCesiumUtils.parseRegion([1, 2, 3, 4, 5, 6, 7]).isNull()) # not doubles - self.assertTrue( - QgsCesiumUtils.parseRegion([1, 'a', 3, 4, 5, 6]).isNull()) + self.assertTrue(QgsCesiumUtils.parseRegion([1, "a", 3, 4, 5, 6]).isNull()) # valid box = QgsCesiumUtils.parseRegion([1.2, 2, 3, 4.6, 5.5, 6]) @@ -52,14 +50,16 @@ def test_parse_oriented_bounding_box(self): self.assertTrue(QgsCesiumUtils.parseBox([1, 2, 3, 4]).isNull()) self.assertTrue(QgsCesiumUtils.parseBox([1, 2, 3, 4, 5, 6, 7]).isNull()) # not doubles - self.assertTrue(QgsCesiumUtils.parseBox([1, 2, 'a', 4, 5, 6, 7]).isNull()) + self.assertTrue(QgsCesiumUtils.parseBox([1, 2, "a", 4, 5, 6, 7]).isNull()) # valid box = QgsCesiumUtils.parseBox([1, 2, 3, 10, 0, 0, 0, 20, 0, 0, 0, 30]) self.assertEqual(box.centerX(), 1) self.assertEqual(box.centerY(), 2) self.assertEqual(box.centerZ(), 3) - self.assertEqual(box.halfAxes(), [10.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 30.0]) + self.assertEqual( + box.halfAxes(), [10.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 30.0] + ) def test_parse_sphere(self): sphere = QgsCesiumUtils.parseSphere([]) @@ -69,7 +69,7 @@ def test_parse_sphere(self): self.assertTrue(QgsCesiumUtils.parseSphere([1, 2, 3]).isNull()) self.assertTrue(QgsCesiumUtils.parseSphere([1, 2, 3, 4, 5, 6, 7]).isNull()) # not doubles - self.assertTrue(QgsCesiumUtils.parseSphere([1, 2, 'a', 4]).isNull()) + self.assertTrue(QgsCesiumUtils.parseSphere([1, 2, "a", 4]).isNull()) # valid sphere = QgsCesiumUtils.parseSphere([1, 2, 3, 10]) @@ -79,5 +79,5 @@ def test_parse_sphere(self): self.assertEqual(sphere.radius(), 10) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscheckablecombobox.py b/tests/src/python/test_qgscheckablecombobox.py index 9f77247495c4..fefc60757382 100644 --- a/tests/src/python/test_qgscheckablecombobox.py +++ b/tests/src/python/test_qgscheckablecombobox.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Alexander Bruy' -__date__ = '22/03/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Alexander Bruy" +__date__ = "22/03/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtCore import Qt @@ -23,35 +24,35 @@ class TestQgsCheckableComboBox(QgisTestCase): def testGettersSetters(self): - """ test widget getters/setters """ + """test widget getters/setters""" w = QgsCheckableComboBox() - w.setSeparator('|') - self.assertEqual(w.separator(), '|') - w.setDefaultText('Select items...') - self.assertEqual(w.defaultText(), 'Select items...') + w.setSeparator("|") + self.assertEqual(w.separator(), "|") + w.setDefaultText("Select items...") + self.assertEqual(w.defaultText(), "Select items...") - w.addItems(['One', 'Two', 'Three']) + w.addItems(["One", "Two", "Three"]) - w.setCheckedItems(['Two']) + w.setCheckedItems(["Two"]) self.assertEqual(len(w.checkedItems()), 1) - self.assertEqual(w.checkedItems(), ['Two']) - w.setCheckedItems(['Three']) + self.assertEqual(w.checkedItems(), ["Two"]) + w.setCheckedItems(["Three"]) self.assertEqual(len(w.checkedItems()), 2) - self.assertEqual(w.checkedItems(), ['Two', 'Three']) + self.assertEqual(w.checkedItems(), ["Two", "Three"]) w.setItemCheckState(2, Qt.CheckState.Unchecked) self.assertEqual(w.itemCheckState(2), Qt.CheckState.Unchecked) def test_ChangedSignals(self): - """ test that signals are correctly emitted when clearing""" + """test that signals are correctly emitted when clearing""" w = QgsCheckableComboBox() - w.addItems(['One', 'Two', 'Three']) + w.addItems(["One", "Two", "Three"]) checkedItemsChanged_spy = QSignalSpy(w.checkedItemsChanged) - w.setCheckedItems(['Two']) + w.setCheckedItems(["Two"]) self.assertEqual(len(checkedItemsChanged_spy), 1) @@ -61,5 +62,5 @@ def test_readonly(self): w.show() # Should not crash -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscircularstring.py b/tests/src/python/test_qgscircularstring.py index 07bdb8c429b8..de610988d45e 100644 --- a/tests/src/python/test_qgscircularstring.py +++ b/tests/src/python/test_qgscircularstring.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Loïc Bartoletti' -__date__ = '19/12/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "Loïc Bartoletti" +__date__ = "19/12/2023" +__copyright__ = "Copyright 2023, The QGIS Project" import qgis # NOQA @@ -25,8 +26,12 @@ def testFuzzyComparisons(self): # 2D # ###### epsilon = 0.001 - geom1 = QgsCircularString(QgsPoint(0.0, 0.0), QgsPoint(0.001, 0.001), QgsPoint(0.5, 0.5)) - geom2 = QgsCircularString(QgsPoint(0.0, 0.0), QgsPoint(0.002, 0.002), QgsPoint(0.5, 0.5)) + geom1 = QgsCircularString( + QgsPoint(0.0, 0.0), QgsPoint(0.001, 0.001), QgsPoint(0.5, 0.5) + ) + geom2 = QgsCircularString( + QgsPoint(0.0, 0.0), QgsPoint(0.002, 0.002), QgsPoint(0.5, 0.5) + ) self.assertNotEqual(geom1, geom2) # epsilon = 1e-8 here @@ -42,8 +47,16 @@ def testFuzzyComparisons(self): # 3DZ # ####### epsilon = 0.001 - geom1 = QgsCircularString(QgsPoint(0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001), QgsPoint(0.5, 0.5, 0.5)) - geom2 = QgsCircularString(QgsPoint(0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.002), QgsPoint(0.5, 0.5, 0.5)) + geom1 = QgsCircularString( + QgsPoint(0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.001), + QgsPoint(0.5, 0.5, 0.5), + ) + geom2 = QgsCircularString( + QgsPoint(0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.002), + QgsPoint(0.5, 0.5, 0.5), + ) self.assertNotEqual(geom1, geom2) # epsilon = 1e-8 here @@ -59,8 +72,16 @@ def testFuzzyComparisons(self): # 3DM # ####### epsilon = 0.001 - geom1 = QgsCircularString(QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.001), QgsPoint(0.5, 0.5, m=0.5)) - geom2 = QgsCircularString(QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.002), QgsPoint(0.5, 0.5, m=0.5)) + geom1 = QgsCircularString( + QgsPoint(0.0, 0.0, m=0.0), + QgsPoint(0.001, 0.001, m=0.001), + QgsPoint(0.5, 0.5, m=0.5), + ) + geom2 = QgsCircularString( + QgsPoint(0.0, 0.0, m=0.0), + QgsPoint(0.001, 0.001, m=0.002), + QgsPoint(0.5, 0.5, m=0.5), + ) self.assertNotEqual(geom1, geom2) # epsilon = 1e-8 here @@ -76,8 +97,16 @@ def testFuzzyComparisons(self): # 4D # ###### epsilon = 0.001 - geom1 = QgsCircularString(QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001, 0.001), QgsPoint(0.5, 0.5, 0.5, 0.5)) - geom2 = QgsCircularString(QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.002, 0.002), QgsPoint(0.5, 0.5, 0.5, 0.5)) + geom1 = QgsCircularString( + QgsPoint(0.0, 0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.001, 0.001), + QgsPoint(0.5, 0.5, 0.5, 0.5), + ) + geom2 = QgsCircularString( + QgsPoint(0.0, 0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.002, 0.002), + QgsPoint(0.5, 0.5, 0.5, 0.5), + ) self.assertNotEqual(geom1, geom2) # epsilon = 1e-8 here @@ -94,11 +123,18 @@ def test_simplify_by_distance(self): test simplifyByDistance """ p = QgsCircularString() - p.fromWkt('CircularString (0.58883883211678167 0.93610259854013833, 8.76977664233575993 27.04692910948904228, 31.60822802919707541 31.61461938686130324)') - self.assertEqual(p.simplifyByDistance(0.5).asWkt(3), 'LineString (0.589 0.936, -0.368 7.336, 0.467 14.185, 2.932 20.168, 6.857 25.312, 11.976 29.27, 18.362 31.883, 24.787 32.651, 31.608 31.615)') - self.assertEqual(p.simplifyByDistance(1).asWkt(3), - 'LineString (0.589 0.936, 0.467 14.185, 6.857 25.312, 18.362 31.883, 31.608 31.615)') - - -if __name__ == '__main__': + p.fromWkt( + "CircularString (0.58883883211678167 0.93610259854013833, 8.76977664233575993 27.04692910948904228, 31.60822802919707541 31.61461938686130324)" + ) + self.assertEqual( + p.simplifyByDistance(0.5).asWkt(3), + "LineString (0.589 0.936, -0.368 7.336, 0.467 14.185, 2.932 20.168, 6.857 25.312, 11.976 29.27, 18.362 31.883, 24.787 32.651, 31.608 31.615)", + ) + self.assertEqual( + p.simplifyByDistance(1).asWkt(3), + "LineString (0.589 0.936, 0.467 14.185, 6.857 25.312, 18.362 31.883, 31.608 31.615)", + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsclassificationmethod.py b/tests/src/python/test_qgsclassificationmethod.py index 911bd9d3d455..e8eab40bf224 100644 --- a/tests/src/python/test_qgsclassificationmethod.py +++ b/tests/src/python/test_qgsclassificationmethod.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Denis Rouzaud' -__date__ = '3/09/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Denis Rouzaud" +__date__ = "3/09/2019" +__copyright__ = "Copyright 2019, The QGIS Project" import random @@ -33,8 +34,9 @@ def createMemoryLayer(values): - ml = QgsVectorLayer("Point?crs=epsg:4236&field=id:integer&field=value:double", - "test_data", "memory") + ml = QgsVectorLayer( + "Point?crs=epsg:4236&field=id:integer&field=value:double", "test_data", "memory" + ) # Data as list of x, y, id, value assert ml.isValid() pr = ml.dataProvider() @@ -43,8 +45,8 @@ def createMemoryLayer(values): for value in values: id += 1 feat = QgsFeature(fields) - feat['id'] = id - feat['value'] = value + feat["id"] = id + feat["value"] = value g = QgsGeometry.fromPointXY(QgsPointXY(id / 100, id / 100)) feat.setGeometry(g) pr.addFeatures([feat]) @@ -55,42 +57,48 @@ def createMemoryLayer(values): class TestQgsClassificationMethods(QgisTestCase): def testQgsClassificationLogarithmic(self): - values = [2746.71, - 66667.49, - 77282.52, - 986567.01, - 1729508.41, - 9957836.86, - 35419826.29, - 52584164.80, - 296572842.00] + values = [ + 2746.71, + 66667.49, + 77282.52, + 986567.01, + 1729508.41, + 9957836.86, + 35419826.29, + 52584164.80, + 296572842.00, + ] vl = createMemoryLayer(values) m = QgsClassificationLogarithmic() - r = m.classes(vl, 'value', 8) + r = m.classes(vl, "value", 8) self.assertEqual(len(r), 6) - self.assertEqual(r[0].label(), f'{QLocale().toString(2746.71)} - 10^4') - self.assertEqual(QgsClassificationMethod.rangesToBreaks(r), - [10000.0, 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0]) + self.assertEqual(r[0].label(), f"{QLocale().toString(2746.71)} - 10^4") + self.assertEqual( + QgsClassificationMethod.rangesToBreaks(r), + [10000.0, 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0], + ) - self.assertEqual(len(m.classes(vl, 'value', 4)), 4) + self.assertEqual(len(m.classes(vl, "value", 4)), 4) def testQgsClassificationLogarithmicCloseMinimum(self): """See issue GH #45454: Incorrect scale range legend after applying logarithmic graduated symbology to a vector layer""" - values = [0.009900019065438, - 0.010851322017611, - 0.01755707784994, - 0.031925433036994, - 0.046422733606398] + values = [ + 0.009900019065438, + 0.010851322017611, + 0.01755707784994, + 0.031925433036994, + 0.046422733606398, + ] vl = createMemoryLayer(values) m = QgsClassificationLogarithmic() - r = m.classes(vl, 'value', 4) + r = m.classes(vl, "value", 4) classes = [(c.lowerBound(), c.upperBound()) for c in r] @@ -102,16 +110,29 @@ def testQgsClassificationLogarithmic_FilterZeroNeg(self): vl = createMemoryLayer(values) m = QgsClassificationLogarithmic() - m.setParameterValues({'ZERO_NEG_VALUES_HANDLE': QgsClassificationLogarithmic.NegativeValueHandling.Discard}) - r = m.classes(vl, 'value', 4) + m.setParameterValues( + { + "ZERO_NEG_VALUES_HANDLE": QgsClassificationLogarithmic.NegativeValueHandling.Discard + } + ) + r = m.classes(vl, "value", 4) self.assertEqual(len(r), 4) - self.assertEqual(r[0].label(), '1 - 10^1') - self.assertEqual(QgsClassificationMethod.rangesToBreaks(r), [10.0, 100.0, 1000.0, 10000.0]) + self.assertEqual(r[0].label(), "1 - 10^1") + self.assertEqual( + QgsClassificationMethod.rangesToBreaks(r), [10.0, 100.0, 1000.0, 10000.0] + ) - m.setParameterValues({'ZERO_NEG_VALUES_HANDLE': QgsClassificationLogarithmic.NegativeValueHandling.PrependBreak}) - r = m.classes(vl, 'value', 4) - self.assertEqual(r[0].label(), '-2 - 10^0') - self.assertEqual(QgsClassificationMethod.rangesToBreaks(r), [1.0, 10.0, 100.0, 1000.0, 10000.0]) + m.setParameterValues( + { + "ZERO_NEG_VALUES_HANDLE": QgsClassificationLogarithmic.NegativeValueHandling.PrependBreak + } + ) + r = m.classes(vl, "value", 4) + self.assertEqual(r[0].label(), "-2 - 10^0") + self.assertEqual( + QgsClassificationMethod.rangesToBreaks(r), + [1.0, 10.0, 100.0, 1000.0, 10000.0], + ) def testQgsClassificationJenksSimple(self): # This is a simple Natural Breaks Jenks test checking if simple calculation can be done @@ -121,10 +142,11 @@ def testQgsClassificationJenksSimple(self): vl = createMemoryLayer(values) m = QgsClassificationJenks() - r = m.classes(vl, 'value', 4) + r = m.classes(vl, "value", 4) self.assertEqual(len(r), 4) - self.assertEqual(QgsClassificationMethod.rangesToBreaks(r), - [-30.0, 16.0, 29.0, 57.0]) + self.assertEqual( + QgsClassificationMethod.rangesToBreaks(r), [-30.0, 16.0, 29.0, 57.0] + ) def testQgsClassificationJenksHighNumber(self): # This test checks if Jenkis classification does not crash when number of @@ -135,32 +157,34 @@ def testQgsClassificationJenksHighNumber(self): vl = createMemoryLayer(values) m = QgsClassificationJenks() - r = m.classes(vl, 'value', 4) + r = m.classes(vl, "value", 4) self.assertEqual(len(r), 4) - self.assertEqual(QgsClassificationMethod.rangesToBreaks(r), - [-506.0, -4.0, 499.0, 1000.0]) + self.assertEqual( + QgsClassificationMethod.rangesToBreaks(r), [-506.0, -4.0, 499.0, 1000.0] + ) def testQgsClassificationFixedInterval(self): values = [-33, -41, -43, 16, 29, 9, -35, 56, 26, -30] vl = createMemoryLayer(values) m = QgsClassificationFixedInterval() - m.setParameterValues({'INTERVAL': 10}) + m.setParameterValues({"INTERVAL": 10}) - r = m.classes(vl, 'value', 4) + r = m.classes(vl, "value", 4) self.assertEqual(len(r), 10) - self.assertEqual(QgsClassificationMethod.rangesToBreaks(r), - [-33.0, -23.0, -13.0, -3.0, 7.0, 17.0, 27.0, 37.0, 47.0, 57.0]) + self.assertEqual( + QgsClassificationMethod.rangesToBreaks(r), + [-33.0, -23.0, -13.0, -3.0, 7.0, 17.0, 27.0, 37.0, 47.0, 57.0], + ) def testQgsClassificationFixedIntervalInvalidInterval(self): values = [-33, -41, -43, 16, 29, 9, -35, 57, 26, -30] vl = createMemoryLayer(values) m = QgsClassificationFixedInterval() - m.setParameterValues({'INTERVAL': 0}) + m.setParameterValues({"INTERVAL": 0}) - r = m.classes(vl, 'value', 4) + r = m.classes(vl, "value", 4) self.assertEqual(len(r), 1) - self.assertEqual(QgsClassificationMethod.rangesToBreaks(r), - [57.0]) + self.assertEqual(QgsClassificationMethod.rangesToBreaks(r), [57.0]) def testQgsClassificationFixedIntervalLabelForRange(self): @@ -168,9 +192,9 @@ def testQgsClassificationFixedIntervalLabelForRange(self): # lowerValue, upperValue, labelFormat, expected cases = ( - (1, 2, '%1 - %2', '1 - 2'), - (1, 2, '%1', '1'), - (1, 2, '%2', '2'), + (1, 2, "%1 - %2", "1 - 2"), + (1, 2, "%1", "1"), + (1, 2, "%2", "2"), ) for lowerValue, upperValue, labelFormat, expected in cases: diff --git a/tests/src/python/test_qgscodeeditor.py b/tests/src/python/test_qgscodeeditor.py index 68372193342e..b0aa600dac49 100644 --- a/tests/src/python/test_qgscodeeditor.py +++ b/tests/src/python/test_qgscodeeditor.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '03/10/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "03/10/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import sys @@ -37,53 +38,114 @@ def setUpClass(cls): def testDefaultColors(self): # default color theme, default application theme - QgsApplication.setUITheme('default') - self.assertEqual(QgsCodeEditor.defaultColor(QgsCodeEditorColorScheme.ColorRole.Keyword).name(), '#8959a8') + QgsApplication.setUITheme("default") + self.assertEqual( + QgsCodeEditor.defaultColor( + QgsCodeEditorColorScheme.ColorRole.Keyword + ).name(), + "#8959a8", + ) # default colors should respond to application ui theme - QgsApplication.setUITheme('Night Mapping') - self.assertEqual(QgsCodeEditor.defaultColor(QgsCodeEditorColorScheme.ColorRole.Keyword).name(), '#6cbcf7') + QgsApplication.setUITheme("Night Mapping") + self.assertEqual( + QgsCodeEditor.defaultColor( + QgsCodeEditorColorScheme.ColorRole.Keyword + ).name(), + "#6cbcf7", + ) # explicit theme, should override ui theme defaults - self.assertEqual(QgsCodeEditor.defaultColor(QgsCodeEditorColorScheme.ColorRole.Keyword, 'solarized').name(), '#859900') - self.assertEqual(QgsCodeEditor.defaultColor(QgsCodeEditorColorScheme.ColorRole.Background, 'solarized').name(), '#fdf6e3') - self.assertEqual(QgsCodeEditor.defaultColor(QgsCodeEditorColorScheme.ColorRole.Keyword, 'solarized_dark').name(), '#859900') - self.assertEqual(QgsCodeEditor.defaultColor(QgsCodeEditorColorScheme.ColorRole.Background, 'solarized_dark').name(), '#002b36') + self.assertEqual( + QgsCodeEditor.defaultColor( + QgsCodeEditorColorScheme.ColorRole.Keyword, "solarized" + ).name(), + "#859900", + ) + self.assertEqual( + QgsCodeEditor.defaultColor( + QgsCodeEditorColorScheme.ColorRole.Background, "solarized" + ).name(), + "#fdf6e3", + ) + self.assertEqual( + QgsCodeEditor.defaultColor( + QgsCodeEditorColorScheme.ColorRole.Keyword, "solarized_dark" + ).name(), + "#859900", + ) + self.assertEqual( + QgsCodeEditor.defaultColor( + QgsCodeEditorColorScheme.ColorRole.Background, "solarized_dark" + ).name(), + "#002b36", + ) def testColors(self): - QgsApplication.setUITheme('default') - self.assertEqual(QgsCodeEditor.color(QgsCodeEditorColorScheme.ColorRole.Keyword).name(), '#8959a8') - QgsApplication.setUITheme('Night Mapping') - self.assertEqual(QgsCodeEditor.color(QgsCodeEditorColorScheme.ColorRole.Keyword).name(), '#6cbcf7') - - QgsSettings().setValue('codeEditor/colorScheme', 'solarized', QgsSettings.Section.Gui) - self.assertEqual(QgsCodeEditor.color(QgsCodeEditorColorScheme.ColorRole.Keyword).name(), '#859900') - self.assertEqual(QgsCodeEditor.color(QgsCodeEditorColorScheme.ColorRole.Background).name(), '#fdf6e3') - QgsSettings().setValue('codeEditor/colorScheme', 'solarized_dark', QgsSettings.Section.Gui) - self.assertEqual(QgsCodeEditor.color(QgsCodeEditorColorScheme.ColorRole.Keyword).name(), '#859900') - self.assertEqual(QgsCodeEditor.color(QgsCodeEditorColorScheme.ColorRole.Background).name(), '#002b36') - - QgsSettings().setValue('codeEditor/overrideColors', True, QgsSettings.Section.Gui) - QgsCodeEditor.setColor(QgsCodeEditorColorScheme.ColorRole.Keyword, QColor('#cc11bb')) - self.assertEqual(QgsCodeEditor.color(QgsCodeEditorColorScheme.ColorRole.Keyword).name(), '#cc11bb') + QgsApplication.setUITheme("default") + self.assertEqual( + QgsCodeEditor.color(QgsCodeEditorColorScheme.ColorRole.Keyword).name(), + "#8959a8", + ) + QgsApplication.setUITheme("Night Mapping") + self.assertEqual( + QgsCodeEditor.color(QgsCodeEditorColorScheme.ColorRole.Keyword).name(), + "#6cbcf7", + ) + + QgsSettings().setValue( + "codeEditor/colorScheme", "solarized", QgsSettings.Section.Gui + ) + self.assertEqual( + QgsCodeEditor.color(QgsCodeEditorColorScheme.ColorRole.Keyword).name(), + "#859900", + ) + self.assertEqual( + QgsCodeEditor.color(QgsCodeEditorColorScheme.ColorRole.Background).name(), + "#fdf6e3", + ) + QgsSettings().setValue( + "codeEditor/colorScheme", "solarized_dark", QgsSettings.Section.Gui + ) + self.assertEqual( + QgsCodeEditor.color(QgsCodeEditorColorScheme.ColorRole.Keyword).name(), + "#859900", + ) + self.assertEqual( + QgsCodeEditor.color(QgsCodeEditorColorScheme.ColorRole.Background).name(), + "#002b36", + ) + + QgsSettings().setValue( + "codeEditor/overrideColors", True, QgsSettings.Section.Gui + ) + QgsCodeEditor.setColor( + QgsCodeEditorColorScheme.ColorRole.Keyword, QColor("#cc11bb") + ) + self.assertEqual( + QgsCodeEditor.color(QgsCodeEditorColorScheme.ColorRole.Keyword).name(), + "#cc11bb", + ) def testFontFamily(self): f = QgsCodeEditor().getMonospaceFont() self.assertTrue(f.styleHint() & QFont.StyleHint.Monospace) - QgsSettings().setValue('codeEditor/fontfamily', getTestFont().family(), QgsSettings.Section.Gui) + QgsSettings().setValue( + "codeEditor/fontfamily", getTestFont().family(), QgsSettings.Section.Gui + ) f = QgsCodeEditor().getMonospaceFont() - self.assertEqual(f.family(), 'QGIS Vera Sans') + self.assertEqual(f.family(), "QGIS Vera Sans") - @unittest.skipIf(sys.platform == 'darwin', 'MacOS has different font logic') + @unittest.skipIf(sys.platform == "darwin", "MacOS has different font logic") def testFontSize(self): f = QgsCodeEditor().getMonospaceFont() self.assertEqual(f.pointSize(), 10) - QgsSettings().setValue('codeEditor/fontsize', 14, QgsSettings.Section.Gui) + QgsSettings().setValue("codeEditor/fontsize", 14, QgsSettings.Section.Gui) f = QgsCodeEditor().getMonospaceFont() self.assertEqual(f.pointSize(), 14) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscodeeditorcolorscheme.py b/tests/src/python/test_qgscodeeditorcolorscheme.py index d38816005d7c..f77aeb55cd4b 100644 --- a/tests/src/python/test_qgscodeeditorcolorscheme.py +++ b/tests/src/python/test_qgscodeeditorcolorscheme.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '03/10/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "03/10/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication from qgis.PyQt.QtGui import QColor @@ -30,48 +31,62 @@ def setUpClass(cls): """Run before all tests""" super().setUpClass() QCoreApplication.setOrganizationName("QGIS_Test") - QCoreApplication.setOrganizationDomain("QGIS_TestPyQgsCodeEditorColorScheme.com") + QCoreApplication.setOrganizationDomain( + "QGIS_TestPyQgsCodeEditorColorScheme.com" + ) QCoreApplication.setApplicationName("QGIS_TestPyQgsCodeEditorColorScheme") QgsSettings().clear() start_app() def testScheme(self): - scheme = QgsCodeEditorColorScheme('my id', 'my name') - self.assertEqual(scheme.id(), 'my id') - self.assertEqual(scheme.name(), 'my name') + scheme = QgsCodeEditorColorScheme("my id", "my name") + self.assertEqual(scheme.id(), "my id") + self.assertEqual(scheme.name(), "my name") scheme.setColor(QgsCodeEditorColorScheme.ColorRole.Keyword, QColor(255, 0, 0)) scheme.setColor(QgsCodeEditorColorScheme.ColorRole.Method, QColor(0, 255, 0)) - self.assertEqual(scheme.color(QgsCodeEditorColorScheme.ColorRole.Keyword).name(), '#ff0000') - self.assertEqual(scheme.color(QgsCodeEditorColorScheme.ColorRole.Method).name(), '#00ff00') + self.assertEqual( + scheme.color(QgsCodeEditorColorScheme.ColorRole.Keyword).name(), "#ff0000" + ) + self.assertEqual( + scheme.color(QgsCodeEditorColorScheme.ColorRole.Method).name(), "#00ff00" + ) def testSchemeRegistry(self): default_reg = QgsGui.codeEditorColorSchemeRegistry() self.assertGreaterEqual(len(default_reg.schemes()), 3) registry = QgsCodeEditorColorSchemeRegistry() - self.assertCountEqual(registry.schemes(), ['default', 'solarized', 'solarized_dark']) - self.assertEqual(registry.scheme('solarized').name(), 'Solarized (Light)') - self.assertEqual(registry.scheme('solarized_dark').name(), 'Solarized (Dark)') + self.assertCountEqual( + registry.schemes(), ["default", "solarized", "solarized_dark"] + ) + self.assertEqual(registry.scheme("solarized").name(), "Solarized (Light)") + self.assertEqual(registry.scheme("solarized_dark").name(), "Solarized (Dark)") # duplicate name - scheme = QgsCodeEditorColorScheme('solarized', 'my name') + scheme = QgsCodeEditorColorScheme("solarized", "my name") self.assertFalse(registry.addColorScheme(scheme)) # unique name - scheme = QgsCodeEditorColorScheme('xxxx', 'my name') + scheme = QgsCodeEditorColorScheme("xxxx", "my name") self.assertTrue(registry.addColorScheme(scheme)) - self.assertCountEqual(registry.schemes(), ['default', 'solarized', 'solarized_dark', 'xxxx']) - self.assertEqual(registry.scheme('xxxx').name(), 'my name') - - self.assertFalse(registry.removeColorScheme('yyyy')) - self.assertCountEqual(registry.schemes(), ['default', 'solarized', 'solarized_dark', 'xxxx']) - self.assertTrue(registry.removeColorScheme('xxxx')) - self.assertCountEqual(registry.schemes(), ['default', 'solarized', 'solarized_dark']) + self.assertCountEqual( + registry.schemes(), ["default", "solarized", "solarized_dark", "xxxx"] + ) + self.assertEqual(registry.scheme("xxxx").name(), "my name") + + self.assertFalse(registry.removeColorScheme("yyyy")) + self.assertCountEqual( + registry.schemes(), ["default", "solarized", "solarized_dark", "xxxx"] + ) + self.assertTrue(registry.removeColorScheme("xxxx")) + self.assertCountEqual( + registry.schemes(), ["default", "solarized", "solarized_dark"] + ) # should return default registry if matching one doesn't exist - self.assertEqual(registry.scheme('xxxx').name(), 'Default') + self.assertEqual(registry.scheme("xxxx").name(), "Default") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscodeeditorpython.py b/tests/src/python/test_qgscodeeditorpython.py index bd0a0777d381..4d91689321a8 100644 --- a/tests/src/python/test_qgscodeeditorpython.py +++ b/tests/src/python/test_qgscodeeditorpython.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Yoann Quenach de Quivillic' -__date__ = '31/03/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "Yoann Quenach de Quivillic" +__date__ = "31/03/2023" +__copyright__ = "Copyright 2023, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication, Qt @@ -18,13 +19,7 @@ from qgis.testing import start_app, QgisTestCase -COMPLETIONS_PAIRS = { - "(": ")", - "[": "]", - "{": "}", - "'": "'", - "\"": "\"" -} +COMPLETIONS_PAIRS = {"(": ")", "[": "]", "{": "}", "'": "'", '"': '"'} COMPLETIONS_SINGLE_CHARACTERS = ["`", "*"] @@ -44,7 +39,7 @@ def setUp(self): QgsSettings().clear() def testAutoSurround(self): - self.assertEqual(QgsSettings().value('pythonConsole/autoSurround'), None) + self.assertEqual(QgsSettings().value("pythonConsole/autoSurround"), None) editor = QgsCodeEditorPython() @@ -78,7 +73,10 @@ def testAutoSurround(self): text = editor.text() # Select the whole text QTest.keyClicks(editor, opening) - self.assertEqual(editor.text(), text.replace(test_string, opening + test_string + closing)) + self.assertEqual( + editor.text(), + text.replace(test_string, opening + test_string + closing), + ) # Check multiline autosurround with quotes (should insert triple quotes) test_string = "Hello\nWorld" @@ -89,12 +87,12 @@ def testAutoSurround(self): editor.setText(test_string) editor.selectAll() - QTest.keyClicks(editor, "\"") + QTest.keyClicks(editor, '"') self.assertEqual(editor.text(), f'"""{test_string}"""') # Check disabled autosurround test_string = "will not be surrounded" - QgsSettings().setValue('pythonConsole/autoSurround', False) + QgsSettings().setValue("pythonConsole/autoSurround", False) editor.setText(test_string) editor.selectAll() QTest.keyClicks(editor, "(") @@ -102,7 +100,7 @@ def testAutoSurround(self): def testAutoCloseBrackets(self): - self.assertEqual(QgsSettings().value('pythonConsole/autoCloseBracket'), None) + self.assertEqual(QgsSettings().value("pythonConsole/autoCloseBracket"), None) editor = QgsCodeEditorPython() @@ -172,7 +170,7 @@ def testAutoCloseBrackets(self): editor.clear() # Check disabled auto close brackets - QgsSettings().setValue('pythonConsole/autoCloseBracket', False) + QgsSettings().setValue("pythonConsole/autoCloseBracket", False) QTest.keyClicks(editor, "{") self.assertEqual(editor.text(), "{") @@ -184,27 +182,27 @@ def testToggleComment(self): # Check single line comment editor.setText("#Hello World") - QTest.keyClick(editor, ':', Qt.KeyboardModifier.ControlModifier) + QTest.keyClick(editor, ":", Qt.KeyboardModifier.ControlModifier) self.assertEqual(editor.text(), "Hello World") - QTest.keyClick(editor, ':', Qt.KeyboardModifier.ControlModifier) + QTest.keyClick(editor, ":", Qt.KeyboardModifier.ControlModifier) self.assertEqual(editor.text(), "# Hello World") # Check multiline comment editor.setText("Hello\nQGIS\nWorld") editor.setSelection(0, 0, 1, 4) - QTest.keyClick(editor, ':', Qt.KeyboardModifier.ControlModifier) + QTest.keyClick(editor, ":", Qt.KeyboardModifier.ControlModifier) self.assertEqual(editor.text(), "# Hello\n# QGIS\nWorld") - QTest.keyClick(editor, ':', Qt.KeyboardModifier.ControlModifier) + QTest.keyClick(editor, ":", Qt.KeyboardModifier.ControlModifier) self.assertEqual(editor.text(), "Hello\nQGIS\nWorld") # Check multiline comment with already commented lines editor.setText("Hello\n# QGIS\nWorld") editor.setSelection(0, 0, 2, 4) - QTest.keyClick(editor, ':', Qt.KeyboardModifier.ControlModifier) + QTest.keyClick(editor, ":", Qt.KeyboardModifier.ControlModifier) self.assertEqual(editor.text(), "# Hello\n# # QGIS\n# World") - QTest.keyClick(editor, ':', Qt.KeyboardModifier.ControlModifier) + QTest.keyClick(editor, ":", Qt.KeyboardModifier.ControlModifier) self.assertEqual(editor.text(), "Hello\n# QGIS\nWorld") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscolorbutton.py b/tests/src/python/test_qgscolorbutton.py index ba8ffd4f3fac..45214b9e6a0b 100644 --- a/tests/src/python/test_qgscolorbutton.py +++ b/tests/src/python/test_qgscolorbutton.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '25/05/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "25/05/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtGui import QColor from qgis.PyQt.QtTest import QSignalSpy @@ -74,34 +75,42 @@ def testLinkProjectColor(self): """ Test linking to a project color """ - project_scheme = [s for s in QgsApplication.colorSchemeRegistry().schemes() if isinstance(s, QgsProjectColorScheme)][0] - project_scheme.setColors([[QColor(255, 0, 0), 'col1'], [QColor(0, 255, 0), 'col2']]) + project_scheme = [ + s + for s in QgsApplication.colorSchemeRegistry().schemes() + if isinstance(s, QgsProjectColorScheme) + ][0] + project_scheme.setColors( + [[QColor(255, 0, 0), "col1"], [QColor(0, 255, 0), "col2"]] + ) button = QgsColorButton() spy = QSignalSpy(button.unlinked) button.setColor(QColor(0, 0, 255)) self.assertFalse(button.linkedProjectColorName()) - button.linkToProjectColor('col1') - self.assertEqual(button.linkedProjectColorName(), 'col1') - self.assertEqual(button.color().name(), '#ff0000') + button.linkToProjectColor("col1") + self.assertEqual(button.linkedProjectColorName(), "col1") + self.assertEqual(button.color().name(), "#ff0000") self.assertEqual(len(spy), 0) button.unlink() self.assertFalse(button.linkedProjectColorName()) - self.assertEqual(button.color().name(), '#0000ff') + self.assertEqual(button.color().name(), "#0000ff") self.assertEqual(len(spy), 1) - button.linkToProjectColor('col2') - self.assertEqual(button.linkedProjectColorName(), 'col2') - self.assertEqual(button.color().name(), '#00ff00') + button.linkToProjectColor("col2") + self.assertEqual(button.linkedProjectColorName(), "col2") + self.assertEqual(button.color().name(), "#00ff00") self.assertEqual(len(spy), 1) - project_scheme.setColors([[QColor(255, 0, 0), 'xcol1'], [QColor(0, 255, 0), 'xcol2']]) + project_scheme.setColors( + [[QColor(255, 0, 0), "xcol1"], [QColor(0, 255, 0), "xcol2"]] + ) # linked color no longer exists self.assertFalse(button.linkedProjectColorName()) - self.assertEqual(button.color().name(), '#0000ff') + self.assertEqual(button.color().name(), "#0000ff") self.assertEqual(len(spy), 2) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscolorramp.py b/tests/src/python/test_qgscolorramp.py index 410745e92202..9afbf64a4c7f 100644 --- a/tests/src/python/test_qgscolorramp.py +++ b/tests/src/python/test_qgscolorramp.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2015-08' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2015-08" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.PyQt.QtGui import QColor, QGradient from qgis.core import ( @@ -30,9 +31,18 @@ def testQgsGradientColorRamp(self): stop = QgsGradientStop(0.9, QColor(200, 150, 100)) self.assertEqual(stop.offset, 0.9) self.assertEqual(stop.color, QColor(200, 150, 100)) - self.assertEqual(QgsGradientStop(0.1, QColor(180, 20, 30)), QgsGradientStop(0.1, QColor(180, 20, 30))) - self.assertNotEqual(QgsGradientStop(0.1, QColor(180, 20, 30)), QgsGradientStop(0.2, QColor(180, 20, 30))) - self.assertNotEqual(QgsGradientStop(0.1, QColor(180, 20, 30)), QgsGradientStop(0.1, QColor(180, 40, 30))) + self.assertEqual( + QgsGradientStop(0.1, QColor(180, 20, 30)), + QgsGradientStop(0.1, QColor(180, 20, 30)), + ) + self.assertNotEqual( + QgsGradientStop(0.1, QColor(180, 20, 30)), + QgsGradientStop(0.2, QColor(180, 20, 30)), + ) + self.assertNotEqual( + QgsGradientStop(0.1, QColor(180, 20, 30)), + QgsGradientStop(0.1, QColor(180, 40, 30)), + ) stop2 = QgsGradientStop(stop) stop2.setColorSpec(QColor.Spec.Hsv) @@ -46,7 +56,7 @@ def testQgsGradientColorRamp(self): # test gradient with only start/end color r = QgsGradientColorRamp(QColor(200, 0, 0, 100), QColor(0, 200, 0, 200)) - self.assertEqual(r.type(), 'gradient') + self.assertEqual(r.type(), "gradient") self.assertEqual(r.color1(), QColor(200, 0, 0, 100)) self.assertEqual(r.color2(), QColor(0, 200, 0, 200)) self.assertEqual(r.isDiscrete(), False) @@ -138,9 +148,15 @@ def testQgsGradientColorRamp(self): self.assertAlmostEqual(r.color(0.5).alphaF(), 0.6, 3) # test gradient with stops - r = QgsGradientColorRamp(QColor(200, 0, 0), QColor(0, 200, 0), False, - [QgsGradientStop(0.1, QColor(180, 20, 40)), - QgsGradientStop(0.9, QColor(40, 60, 100))]) + r = QgsGradientColorRamp( + QColor(200, 0, 0), + QColor(0, 200, 0), + False, + [ + QgsGradientStop(0.1, QColor(180, 20, 40)), + QgsGradientStop(0.9, QColor(40, 60, 100)), + ], + ) self.assertEqual(r.color1(), QColor(200, 0, 0)) self.assertEqual(r.color2(), QColor(0, 200, 0)) self.assertEqual(r.isDiscrete(), False) @@ -202,20 +218,30 @@ def testQgsGradientColorRamp(self): self.assertEqual(r.color(1), QColor(0, 200, 0)) # HSV based interpolation, invalid hues - rr = QgsGradientColorRamp(QColor.fromHsvF(-1, 0, 0.6, 1), QColor.fromHsvF(0.2, 0.7, 0.8, .5)) + rr = QgsGradientColorRamp( + QColor.fromHsvF(-1, 0, 0.6, 1), QColor.fromHsvF(0.2, 0.7, 0.8, 0.5) + ) rr.setColorSpec(QColor.Spec.Hsv) - self.assertAlmostEqual(rr.color(0.5).hsvHueF(), 0.2, 3) # should take either avialable hue + self.assertAlmostEqual( + rr.color(0.5).hsvHueF(), 0.2, 3 + ) # should take either avialable hue self.assertAlmostEqual(rr.color(0.5).hsvSaturationF(), 0.350, 3) self.assertAlmostEqual(rr.color(0.5).valueF(), 0.7, 3) self.assertAlmostEqual(rr.color(0.5).alphaF(), 0.75, 3) - rr = QgsGradientColorRamp(QColor.fromHsvF(0.2, 0.7, 0.8, .5), QColor.fromHsvF(-1, 0, 0.6, 1)) + rr = QgsGradientColorRamp( + QColor.fromHsvF(0.2, 0.7, 0.8, 0.5), QColor.fromHsvF(-1, 0, 0.6, 1) + ) rr.setColorSpec(QColor.Spec.Hsv) - self.assertAlmostEqual(rr.color(0.5).hsvHueF(), 0.2, 3) # should take either avialable hue + self.assertAlmostEqual( + rr.color(0.5).hsvHueF(), 0.2, 3 + ) # should take either avialable hue self.assertAlmostEqual(rr.color(0.5).hsvSaturationF(), 0.350, 3) self.assertAlmostEqual(rr.color(0.5).valueF(), 0.7, 3) self.assertAlmostEqual(rr.color(0.5).alphaF(), 0.75, 3) # both invalid hue - rr = QgsGradientColorRamp(QColor.fromHsvF(-1, 0.7, 0.8, .5), QColor.fromHsvF(-1, 0, 0.6, 1)) + rr = QgsGradientColorRamp( + QColor.fromHsvF(-1, 0.7, 0.8, 0.5), QColor.fromHsvF(-1, 0, 0.6, 1) + ) rr.setColorSpec(QColor.Spec.Hsv) self.assertEqual(rr.color(0.5).hsvHueF(), -1) self.assertAlmostEqual(rr.color(0.5).hsvSaturationF(), 0.350, 3) @@ -223,20 +249,30 @@ def testQgsGradientColorRamp(self): self.assertAlmostEqual(rr.color(0.5).alphaF(), 0.75, 3) # HSL based interpolation, invalid hues - rr = QgsGradientColorRamp(QColor.fromHslF(-1, 0, 0.6, 1), QColor.fromHslF(0.2, 0.7, 0.8, .5)) + rr = QgsGradientColorRamp( + QColor.fromHslF(-1, 0, 0.6, 1), QColor.fromHslF(0.2, 0.7, 0.8, 0.5) + ) rr.setColorSpec(QColor.Spec.Hsl) - self.assertAlmostEqual(rr.color(0.5).hslHueF(), 0.2, 3) # should take either avialable hue + self.assertAlmostEqual( + rr.color(0.5).hslHueF(), 0.2, 3 + ) # should take either avialable hue self.assertAlmostEqual(rr.color(0.5).hslSaturationF(), 0.350, 3) self.assertAlmostEqual(rr.color(0.5).lightnessF(), 0.7, 3) self.assertAlmostEqual(rr.color(0.5).alphaF(), 0.75, 3) - rr = QgsGradientColorRamp(QColor.fromHslF(0.2, 0.7, 0.8, .5), QColor.fromHslF(-1, 0, 0.6, 1)) + rr = QgsGradientColorRamp( + QColor.fromHslF(0.2, 0.7, 0.8, 0.5), QColor.fromHslF(-1, 0, 0.6, 1) + ) rr.setColorSpec(QColor.Spec.Hsl) - self.assertAlmostEqual(rr.color(0.5).hslHueF(), 0.2, 3) # should take either avialable hue + self.assertAlmostEqual( + rr.color(0.5).hslHueF(), 0.2, 3 + ) # should take either avialable hue self.assertAlmostEqual(rr.color(0.5).hslSaturationF(), 0.350, 3) self.assertAlmostEqual(rr.color(0.5).lightnessF(), 0.7, 3) self.assertAlmostEqual(rr.color(0.5).alphaF(), 0.75, 3) # both invalid hue - rr = QgsGradientColorRamp(QColor.fromHslF(-1, 0.7, 0.8, .5), QColor.fromHslF(-1, 0, 0.6, 1)) + rr = QgsGradientColorRamp( + QColor.fromHslF(-1, 0.7, 0.8, 0.5), QColor.fromHslF(-1, 0, 0.6, 1) + ) rr.setColorSpec(QColor.Spec.Hsl) self.assertEqual(rr.color(0.5).hslHueF(), -1) self.assertAlmostEqual(rr.color(0.5).hslSaturationF(), 0.350, 3) @@ -260,9 +296,9 @@ def testQgsGradientColorRamp(self): self.assertEqual(s[0].color, QColor(100, 100, 40)) # test info - r.setInfo({'key1': 'val1', 'key2': 'val2'}) - self.assertEqual(r.info()['key1'], 'val1') - self.assertEqual(r.info()['key2'], 'val2') + r.setInfo({"key1": "val1", "key2": "val2"}) + self.assertEqual(r.info()["key1"], "val1") + self.assertEqual(r.info()["key2"], "val2") # test creating from properties r.setColorSpec(QColor.Spec.Hsv) @@ -278,8 +314,8 @@ def testQgsGradientColorRamp(self): self.assertEqual(s[0].direction(), Qgis.AngularDirection.Clockwise) c = QColor(s[0].color) self.assertEqual(c, QColor(100, 100, 40)) - self.assertEqual(fromProps.info()['key1'], 'val1') - self.assertEqual(fromProps.info()['key2'], 'val2') + self.assertEqual(fromProps.info()["key1"], "val1") + self.assertEqual(fromProps.info()["key2"], "val2") self.assertEqual(fromProps.isDiscrete(), False) self.assertEqual(fromProps.colorSpec(), QColor.Spec.Hsv) self.assertEqual(fromProps.direction(), Qgis.AngularDirection.Clockwise) @@ -295,8 +331,8 @@ def testQgsGradientColorRamp(self): self.assertEqual(s[0].direction(), Qgis.AngularDirection.Clockwise) c = QColor(s[0].color) self.assertEqual(c, QColor(100, 100, 40)) - self.assertEqual(cloned.info()['key1'], 'val1') - self.assertEqual(cloned.info()['key2'], 'val2') + self.assertEqual(cloned.info()["key1"], "val1") + self.assertEqual(cloned.info()["key2"], "val2") self.assertEqual(cloned.isDiscrete(), False) self.assertEqual(cloned.colorSpec(), QColor.Spec.Hsv) self.assertEqual(cloned.direction(), Qgis.AngularDirection.Clockwise) @@ -309,9 +345,15 @@ def testQgsGradientColorRamp(self): self.assertEqual(d.color(0.5), QColor(200, 0, 0)) self.assertEqual(d.color(1), QColor(0, 200, 0)) # then with stops - d = QgsGradientColorRamp(QColor(200, 0, 0), QColor(0, 200, 0), True, [QgsGradientStop(0.1, QColor(180, 20, 40)), - QgsGradientStop(0.9, - QColor(40, 60, 100))]) + d = QgsGradientColorRamp( + QColor(200, 0, 0), + QColor(0, 200, 0), + True, + [ + QgsGradientStop(0.1, QColor(180, 20, 40)), + QgsGradientStop(0.9, QColor(40, 60, 100)), + ], + ) self.assertEqual(d.isDiscrete(), True) self.assertEqual(d.color(0), QColor(200, 0, 0)) self.assertEqual(d.color(0.05), QColor(200, 0, 0)) @@ -323,9 +365,15 @@ def testQgsGradientColorRamp(self): # to gradient g = QGradient() - r = QgsGradientColorRamp(QColor(200, 0, 0), QColor(0, 200, 0), False, - [QgsGradientStop(0.1, QColor(180, 20, 40)), - QgsGradientStop(0.9, QColor(40, 60, 100))]) + r = QgsGradientColorRamp( + QColor(200, 0, 0), + QColor(0, 200, 0), + False, + [ + QgsGradientStop(0.1, QColor(180, 20, 40)), + QgsGradientStop(0.9, QColor(40, 60, 100)), + ], + ) r.addStopsToGradient(g, 0.5) self.assertEqual(len(g.stops()), 4) self.assertEqual(g.stops()[0], (0.0, QColor(200, 0, 0, 127))) @@ -335,32 +383,47 @@ def testQgsGradientColorRamp(self): # add to gradient, non-RGB color model g = QGradient() - rr = QgsGradientColorRamp(QColor.fromHsvF(0.2, 0.3, 0.4), QColor.fromHsvF(0.8, 1.0, 0.6)) + rr = QgsGradientColorRamp( + QColor.fromHsvF(0.2, 0.3, 0.4), QColor.fromHsvF(0.8, 1.0, 0.6) + ) rr.setColorSpec(QColor.Spec.Hsv) rr.addStopsToGradient(g, 0.5) - res = [(round(stop[0], 2), round(stop[1].hsvHueF(), 2), round(stop[1].hsvSaturationF(), 2), - round(stop[1].valueF(), 2), round(stop[1].alphaF(), 2)) for stop in g.stops()] - self.assertEqual(res, [(0.0, 0.2, 0.3, 0.4, 0.5), - (0.05, 0.23, 0.34, 0.41, 0.5), - (0.1, 0.26, 0.37, 0.42, 0.5), - (0.15, 0.29, 0.41, 0.43, 0.5), - (0.2, 0.32, 0.44, 0.44, 0.5), - (0.25, 0.35, 0.48, 0.45, 0.5), - (0.3, 0.38, 0.51, 0.46, 0.5), - (0.35, 0.41, 0.55, 0.47, 0.5), - (0.4, 0.44, 0.58, 0.48, 0.5), - (0.45, 0.47, 0.61, 0.49, 0.5), - (0.5, 0.5, 0.65, 0.5, 0.5), - (0.55, 0.53, 0.69, 0.51, 0.5), - (0.6, 0.56, 0.72, 0.52, 0.5), - (0.65, 0.59, 0.76, 0.53, 0.5), - (0.7, 0.62, 0.79, 0.54, 0.5), - (0.75, 0.65, 0.83, 0.55, 0.5), - (0.8, 0.68, 0.86, 0.56, 0.5), - (0.85, 0.71, 0.9, 0.57, 0.5), - (0.9, 0.74, 0.93, 0.58, 0.5), - (0.95, 0.77, 0.96, 0.59, 0.5), - (1.0, 0.8, 1.0, 0.6, 0.5)]) + res = [ + ( + round(stop[0], 2), + round(stop[1].hsvHueF(), 2), + round(stop[1].hsvSaturationF(), 2), + round(stop[1].valueF(), 2), + round(stop[1].alphaF(), 2), + ) + for stop in g.stops() + ] + self.assertEqual( + res, + [ + (0.0, 0.2, 0.3, 0.4, 0.5), + (0.05, 0.23, 0.34, 0.41, 0.5), + (0.1, 0.26, 0.37, 0.42, 0.5), + (0.15, 0.29, 0.41, 0.43, 0.5), + (0.2, 0.32, 0.44, 0.44, 0.5), + (0.25, 0.35, 0.48, 0.45, 0.5), + (0.3, 0.38, 0.51, 0.46, 0.5), + (0.35, 0.41, 0.55, 0.47, 0.5), + (0.4, 0.44, 0.58, 0.48, 0.5), + (0.45, 0.47, 0.61, 0.49, 0.5), + (0.5, 0.5, 0.65, 0.5, 0.5), + (0.55, 0.53, 0.69, 0.51, 0.5), + (0.6, 0.56, 0.72, 0.52, 0.5), + (0.65, 0.59, 0.76, 0.53, 0.5), + (0.7, 0.62, 0.79, 0.54, 0.5), + (0.75, 0.65, 0.83, 0.55, 0.5), + (0.8, 0.68, 0.86, 0.56, 0.5), + (0.85, 0.71, 0.9, 0.57, 0.5), + (0.9, 0.74, 0.93, 0.58, 0.5), + (0.95, 0.77, 0.96, 0.59, 0.5), + (1.0, 0.8, 1.0, 0.6, 0.5), + ], + ) # with stops stop = QgsGradientStop(0.6, QColor.fromHsvF(0.1, 0.7, 0.3, 0.4)) stop.setColorSpec(QColor.Spec.Hsl) @@ -368,36 +431,53 @@ def testQgsGradientColorRamp(self): rr.setStops([stop]) g = QGradient() rr.addStopsToGradient(g, 0.5) - res = [(round(stop[0], 2), round(stop[1].hsvHueF(), 2), round(stop[1].hsvSaturationF(), 2), - round(stop[1].valueF(), 2), round(stop[1].alphaF(), 2)) for stop in g.stops()] - self.assertEqual(res, [(0.0, 0.2, 0.3, 0.4, 0.5), - (0.05, 0.19, 0.34, 0.4, 0.47), - (0.1, 0.18, 0.38, 0.39, 0.45), - (0.15, 0.17, 0.42, 0.38, 0.42), - (0.2, 0.17, 0.46, 0.38, 0.4), - (0.25, 0.16, 0.49, 0.37, 0.37), - (0.3, 0.15, 0.53, 0.36, 0.35), - (0.35, 0.14, 0.56, 0.35, 0.33), - (0.4, 0.13, 0.59, 0.35, 0.3), - (0.45, 0.12, 0.62, 0.33, 0.27), - (0.5, 0.12, 0.65, 0.32, 0.25), - (0.55, 0.11, 0.67, 0.31, 0.22), - (0.6, 0.1, 0.7, 0.3, 0.2), - (0.65, 0.19, 0.74, 0.34, 0.24), - (0.7, 0.28, 0.78, 0.38, 0.27), - (0.75, 0.36, 0.81, 0.41, 0.31), - (0.8, 0.45, 0.85, 0.45, 0.35), - (0.85, 0.54, 0.89, 0.49, 0.39), - (0.9, 0.62, 0.93, 0.53, 0.42), - (0.95, 0.71, 0.96, 0.56, 0.46), - (1.0, 0.8, 1.0, 0.6, 0.5)]) + res = [ + ( + round(stop[0], 2), + round(stop[1].hsvHueF(), 2), + round(stop[1].hsvSaturationF(), 2), + round(stop[1].valueF(), 2), + round(stop[1].alphaF(), 2), + ) + for stop in g.stops() + ] + self.assertEqual( + res, + [ + (0.0, 0.2, 0.3, 0.4, 0.5), + (0.05, 0.19, 0.34, 0.4, 0.47), + (0.1, 0.18, 0.38, 0.39, 0.45), + (0.15, 0.17, 0.42, 0.38, 0.42), + (0.2, 0.17, 0.46, 0.38, 0.4), + (0.25, 0.16, 0.49, 0.37, 0.37), + (0.3, 0.15, 0.53, 0.36, 0.35), + (0.35, 0.14, 0.56, 0.35, 0.33), + (0.4, 0.13, 0.59, 0.35, 0.3), + (0.45, 0.12, 0.62, 0.33, 0.27), + (0.5, 0.12, 0.65, 0.32, 0.25), + (0.55, 0.11, 0.67, 0.31, 0.22), + (0.6, 0.1, 0.7, 0.3, 0.2), + (0.65, 0.19, 0.74, 0.34, 0.24), + (0.7, 0.28, 0.78, 0.38, 0.27), + (0.75, 0.36, 0.81, 0.41, 0.31), + (0.8, 0.45, 0.85, 0.45, 0.35), + (0.85, 0.54, 0.89, 0.49, 0.39), + (0.9, 0.62, 0.93, 0.53, 0.42), + (0.95, 0.71, 0.96, 0.56, 0.46), + (1.0, 0.8, 1.0, 0.6, 0.5), + ], + ) # test that stops are ordered when setting them # first add some out-of-order stops - r.setStops([QgsGradientStop(0.4, QColor(100, 100, 40)), - QgsGradientStop(0.2, QColor(200, 200, 80)), - QgsGradientStop(0.8, QColor(50, 20, 10)), - QgsGradientStop(0.6, QColor(10, 10, 4))]) + r.setStops( + [ + QgsGradientStop(0.4, QColor(100, 100, 40)), + QgsGradientStop(0.2, QColor(200, 200, 80)), + QgsGradientStop(0.8, QColor(50, 20, 10)), + QgsGradientStop(0.6, QColor(10, 10, 4)), + ] + ) s = r.stops() self.assertEqual(len(s), 4) self.assertEqual(s[0].offset, 0.2) @@ -416,9 +496,15 @@ def testQgsGradientColorRamp(self): self.assertEqual(r.color(0.2), QColor(50, 20, 10)) # test discrete invert function - r = QgsGradientColorRamp(QColor(255, 255, 255), QColor(0, 0, 0), True, - [QgsGradientStop(0.33, QColor(128, 128, 128)), - QgsGradientStop(0.66, QColor(0, 0, 0))]) + r = QgsGradientColorRamp( + QColor(255, 255, 255), + QColor(0, 0, 0), + True, + [ + QgsGradientStop(0.33, QColor(128, 128, 128)), + QgsGradientStop(0.66, QColor(0, 0, 0)), + ], + ) self.assertEqual(r.color(0.2), QColor(255, 255, 255)) self.assertEqual(r.color(0.5), QColor(128, 128, 128)) self.assertEqual(r.color(0.8), QColor(0, 0, 0)) @@ -428,18 +514,20 @@ def testQgsGradientColorRamp(self): self.assertEqual(r.color(0.8), QColor(255, 255, 255)) # test invalid value range - r = QgsGradientColorRamp(color1=QColor(0, 0, 255), color2=QColor(0, 255, 0), discrete=False) + r = QgsGradientColorRamp( + color1=QColor(0, 0, 255), color2=QColor(0, 255, 0), discrete=False + ) self.assertEqual(r.color(0), QColor(0, 0, 255)) self.assertEqual(r.color(1), QColor(0, 255, 0)) self.assertEqual(r.color(0.5).name(), QColor(0, 128, 128).name()) self.assertEqual(r.color(2), QColor(0, 255, 0)) self.assertEqual(r.color(-1), QColor(0, 0, 255)) - self.assertEqual(r.color(float('nan')), QColor(0, 255, 0)) + self.assertEqual(r.color(float("nan")), QColor(0, 255, 0)) def testQgsLimitedRandomColorRamp(self): # test random color ramp r = QgsLimitedRandomColorRamp(5) - self.assertEqual(r.type(), 'random') + self.assertEqual(r.type(), "random") self.assertEqual(r.count(), 5) self.assertEqual(r.value(0), 0) self.assertEqual(r.value(1), 0.25) @@ -519,7 +607,7 @@ def testQgsLimitedRandomColorRamp(self): def testQgsRandomColorRamp(self): # test random colors r = QgsRandomColorRamp() - self.assertEqual(r.type(), 'randomcolors') + self.assertEqual(r.type(), "randomcolors") self.assertEqual(r.count(), -1) # no color count self.assertEqual(r.value(0), 0) # all values should be 0 self.assertEqual(r.value(1), 0) @@ -535,7 +623,7 @@ def testQgsRandomColorRamp(self): # test cloning ramp cloned = r.clone() - self.assertEqual(cloned.type(), 'randomcolors') + self.assertEqual(cloned.type(), "randomcolors") # test with pregenerated colors for n in range(2, 100): @@ -550,20 +638,34 @@ def testQgsRandomColorRamp(self): def testQgsPresetSchemeColorRamp(self): # test preset color ramp r = QgsPresetSchemeColorRamp() - self.assertEqual(r.type(), 'preset') + self.assertEqual(r.type(), "preset") # should be forced to have at least one color self.assertEqual(r.count(), 1) # test getter/setter - r = QgsPresetSchemeColorRamp([QColor(255, 0, 0), QColor(0, 255, 0), QColor(0, 0, 255), QColor(0, 0, 0)]) - self.assertEqual(r.colors(), [QColor(255, 0, 0), QColor(0, 255, 0), QColor(0, 0, 255), QColor(0, 0, 0)]) - r.setColors([(QColor(255, 0, 0), '1'), (QColor(0, 255, 0), '2')]) + r = QgsPresetSchemeColorRamp( + [QColor(255, 0, 0), QColor(0, 255, 0), QColor(0, 0, 255), QColor(0, 0, 0)] + ) + self.assertEqual( + r.colors(), + [QColor(255, 0, 0), QColor(0, 255, 0), QColor(0, 0, 255), QColor(0, 0, 0)], + ) + r.setColors([(QColor(255, 0, 0), "1"), (QColor(0, 255, 0), "2")]) self.assertEqual(r.colors(), [QColor(255, 0, 0), QColor(0, 255, 0)]) - self.assertEqual(r.fetchColors(), [(QColor(255, 0, 0), '1'), (QColor(0, 255, 0), '2')]) + self.assertEqual( + r.fetchColors(), [(QColor(255, 0, 0), "1"), (QColor(0, 255, 0), "2")] + ) # test value r = QgsPresetSchemeColorRamp( - [QColor(255, 0, 0), QColor(0, 255, 0), QColor(0, 0, 255), QColor(0, 0, 0), QColor(255, 255, 255)]) + [ + QColor(255, 0, 0), + QColor(0, 255, 0), + QColor(0, 0, 255), + QColor(0, 0, 0), + QColor(255, 255, 255), + ] + ) self.assertEqual(r.value(0), 0) self.assertEqual(r.value(1), 0.25) self.assertEqual(r.value(2), 0.5) @@ -578,7 +680,7 @@ def testQgsPresetSchemeColorRamp(self): self.assertEqual(r.color(r.value(i)), r.colors()[i]) # test creating from properties - r.setColors([(QColor(255, 0, 0), '1'), (QColor(0, 255, 0), '2')]) + r.setColors([(QColor(255, 0, 0), "1"), (QColor(0, 255, 0), "2")]) props = r.properties() fromProps = QgsPresetSchemeColorRamp.create(props) self.assertEqual(fromProps.count(), 2) @@ -596,9 +698,9 @@ def testQgsPresetSchemeColorRamp(self): def testQgsColorBrewerColorRamp(self): # test color brewer color ramps - r = QgsColorBrewerColorRamp('OrRd', 6) - self.assertEqual(r.type(), 'colorbrewer') - self.assertEqual(r.schemeName(), 'OrRd') + r = QgsColorBrewerColorRamp("OrRd", 6) + self.assertEqual(r.type(), "colorbrewer") + self.assertEqual(r.schemeName(), "OrRd") self.assertEqual(r.count(), 6) self.assertEqual(r.value(0), 0) self.assertEqual(r.value(1), 0.2) @@ -617,15 +719,15 @@ def testQgsColorBrewerColorRamp(self): self.assertEqual(r.color(1.0), QColor(179, 0, 0)) # try using an invalid scheme name - bad = QgsColorBrewerColorRamp('badscheme', 6) + bad = QgsColorBrewerColorRamp("badscheme", 6) self.assertFalse(bad.color(0).isValid()) self.assertEqual(bad.value(1), 0) # test creating from properties props = r.properties() fromProps = QgsColorBrewerColorRamp.create(props) - self.assertEqual(fromProps.type(), 'colorbrewer') - self.assertEqual(fromProps.schemeName(), 'OrRd') + self.assertEqual(fromProps.type(), "colorbrewer") + self.assertEqual(fromProps.schemeName(), "OrRd") self.assertEqual(fromProps.count(), 6) self.assertEqual(fromProps.color(0), QColor(254, 240, 217)) self.assertEqual(fromProps.color(0.2), QColor(253, 212, 158)) @@ -636,8 +738,8 @@ def testQgsColorBrewerColorRamp(self): # test cloning ramp cloned = r.clone() - self.assertEqual(cloned.type(), 'colorbrewer') - self.assertEqual(cloned.schemeName(), 'OrRd') + self.assertEqual(cloned.type(), "colorbrewer") + self.assertEqual(cloned.schemeName(), "OrRd") self.assertEqual(cloned.count(), 6) self.assertEqual(cloned.color(0), QColor(254, 240, 217)) self.assertEqual(cloned.color(0.2), QColor(253, 212, 158)) @@ -647,8 +749,8 @@ def testQgsColorBrewerColorRamp(self): self.assertEqual(cloned.color(1.0), QColor(179, 0, 0)) # set scheme name - r.setSchemeName('Reds') - self.assertEqual(r.schemeName(), 'Reds') + r.setSchemeName("Reds") + self.assertEqual(r.schemeName(), "Reds") self.assertEqual(r.count(), 6) self.assertEqual(r.color(0), QColor(254, 229, 217)) self.assertEqual(r.color(0.2), QColor(252, 187, 161)) @@ -674,9 +776,11 @@ def testQgsColorBrewerColorRamp(self): # test static members names = QgsColorBrewerColorRamp.listSchemeNames() - self.assertTrue('Reds' in names and 'OrRd' in names) - self.assertEqual(len(QgsColorBrewerColorRamp.listSchemeVariants('bad scheme')), 0) - variants = QgsColorBrewerColorRamp.listSchemeVariants('Reds') + self.assertTrue("Reds" in names and "OrRd" in names) + self.assertEqual( + len(QgsColorBrewerColorRamp.listSchemeVariants("bad scheme")), 0 + ) + variants = QgsColorBrewerColorRamp.listSchemeVariants("Reds") self.assertEqual(variants, [3, 4, 5, 6, 7, 8, 9]) # test invalid value range @@ -686,7 +790,7 @@ def testQgsColorBrewerColorRamp(self): self.assertEqual(r.color(0.5), QColor(255, 255, 191)) self.assertFalse(r.color(2).isValid()) self.assertFalse(r.color(-1).isValid()) - self.assertFalse(r.color(float('nan')).isValid()) + self.assertFalse(r.color(float("nan")).isValid()) def testCptCityColorRamp(self): """Test Cpt-city color ramp""" @@ -706,16 +810,18 @@ def testCptCityColorRamp(self): self.assertEqual(r.color(0.5), QColor(245, 245, 245)) self.assertEqual(r.color(2), QColor(1, 133, 113)) self.assertEqual(r.color(-1), QColor(166, 97, 26)) - self.assertEqual(r.color(float('nan')), QColor(1, 133, 113)) + self.assertEqual(r.color(float("nan")), QColor(1, 133, 113)) def testCMYKColorRamp(self): """ Test CMYK color ramp color interpolation """ - r = QgsGradientColorRamp(QColor.fromCmykF(0, 0, 0, 0, 0), QColor.fromCmykF(1, 0.8, 0.4, 0.6, 0.2)) + r = QgsGradientColorRamp( + QColor.fromCmykF(0, 0, 0, 0, 0), QColor.fromCmykF(1, 0.8, 0.4, 0.6, 0.2) + ) r.setColorSpec(QColor.Spec.Cmyk) - stop1 = QgsGradientStop(0.4, QColor.fromCmykF(0.2, 0.4, 0.6, 0.8, 1.)) + stop1 = QgsGradientStop(0.4, QColor.fromCmykF(0.2, 0.4, 0.6, 0.8, 1.0)) stop1.setColorSpec(QColor.Spec.Cmyk) r.setStops([stop1]) self.assertAlmostEqual(r.color(0).cyanF(), 0, 3) @@ -738,12 +844,12 @@ def testCMYKColorRamp(self): self.assertAlmostEqual(r.color(0.7).yellowF(), 0.5, 3) self.assertAlmostEqual(r.color(0.7).blackF(), 0.7, 3) self.assertAlmostEqual(r.color(0.7).alphaF(), 0.6, 3) - self.assertAlmostEqual(r.color(1.).cyanF(), 1, 3) - self.assertAlmostEqual(r.color(1.).magentaF(), 0.8, 3) - self.assertAlmostEqual(r.color(1.).yellowF(), 0.4, 3) - self.assertAlmostEqual(r.color(1.).blackF(), 0.6, 3) - self.assertAlmostEqual(r.color(1.).alphaF(), 0.2, 3) + self.assertAlmostEqual(r.color(1.0).cyanF(), 1, 3) + self.assertAlmostEqual(r.color(1.0).magentaF(), 0.8, 3) + self.assertAlmostEqual(r.color(1.0).yellowF(), 0.4, 3) + self.assertAlmostEqual(r.color(1.0).blackF(), 0.6, 3) + self.assertAlmostEqual(r.color(1.0).alphaF(), 0.2, 3) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscolorramplegendnode.py b/tests/src/python/test_qgscolorramplegendnode.py index e098032eaaf2..0cc81edc38ae 100644 --- a/tests/src/python/test_qgscolorramplegendnode.py +++ b/tests/src/python/test_qgscolorramplegendnode.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2015-08' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2015-08" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.PyQt.QtCore import QSize, QSizeF, Qt from qgis.PyQt.QtGui import QColor, QImage, QPainter @@ -43,7 +44,7 @@ class TestColorRampLegend(QgsColorRampLegendNode): def data(self, role): if role == Qt.ItemDataRole.FontRole: - return QgsFontUtils.getStandardTestFont('Bold', 18) + return QgsFontUtils.getStandardTestFont("Bold", 18) else: return super().data(role) @@ -58,15 +59,18 @@ def control_path_prefix(cls): def test_settings(self): settings = QgsColorRampLegendNodeSettings() settings.setDirection(QgsColorRampLegendNodeSettings.Direction.MaximumToMinimum) - self.assertEqual(settings.direction(), QgsColorRampLegendNodeSettings.Direction.MaximumToMinimum) - settings.setMinimumLabel('min') - self.assertEqual(settings.minimumLabel(), 'min') - settings.setMaximumLabel('max') - self.assertEqual(settings.maximumLabel(), 'max') - settings.setPrefix('pref') - self.assertEqual(settings.prefix(), 'pref') - settings.setSuffix('suff') - self.assertEqual(settings.suffix(), 'suff') + self.assertEqual( + settings.direction(), + QgsColorRampLegendNodeSettings.Direction.MaximumToMinimum, + ) + settings.setMinimumLabel("min") + self.assertEqual(settings.minimumLabel(), "min") + settings.setMaximumLabel("max") + self.assertEqual(settings.maximumLabel(), "max") + settings.setPrefix("pref") + self.assertEqual(settings.prefix(), "pref") + settings.setSuffix("suff") + self.assertEqual(settings.suffix(), "suff") self.assertEqual(settings.orientation(), Qt.Orientation.Vertical) settings.setOrientation(Qt.Orientation.Horizontal) self.assertEqual(settings.orientation(), Qt.Orientation.Horizontal) @@ -86,12 +90,15 @@ def test_settings(self): self.assertIsInstance(settings.numericFormat(), QgsBearingNumericFormat) settings2 = QgsColorRampLegendNodeSettings(settings) - self.assertEqual(settings2.direction(), QgsColorRampLegendNodeSettings.Direction.MaximumToMinimum) - self.assertEqual(settings2.minimumLabel(), 'min') - self.assertEqual(settings2.maximumLabel(), 'max') + self.assertEqual( + settings2.direction(), + QgsColorRampLegendNodeSettings.Direction.MaximumToMinimum, + ) + self.assertEqual(settings2.minimumLabel(), "min") + self.assertEqual(settings2.maximumLabel(), "max") self.assertIsInstance(settings2.numericFormat(), QgsBearingNumericFormat) - self.assertEqual(settings2.prefix(), 'pref') - self.assertEqual(settings2.suffix(), 'suff') + self.assertEqual(settings2.prefix(), "pref") + self.assertEqual(settings2.suffix(), "suff") self.assertEqual(settings2.textFormat().size(), 13) self.assertEqual(settings2.orientation(), Qt.Orientation.Horizontal) @@ -100,23 +107,26 @@ def test_settings(self): self.assertFalse(settings2a.textFormat().isValid()) doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") settings.writeXml(doc, elem, QgsReadWriteContext()) settings3 = QgsColorRampLegendNodeSettings() settings3.readXml(elem, QgsReadWriteContext()) - self.assertEqual(settings3.direction(), QgsColorRampLegendNodeSettings.Direction.MaximumToMinimum) - self.assertEqual(settings3.minimumLabel(), 'min') - self.assertEqual(settings3.maximumLabel(), 'max') + self.assertEqual( + settings3.direction(), + QgsColorRampLegendNodeSettings.Direction.MaximumToMinimum, + ) + self.assertEqual(settings3.minimumLabel(), "min") + self.assertEqual(settings3.maximumLabel(), "max") self.assertIsInstance(settings3.numericFormat(), QgsBearingNumericFormat) - self.assertEqual(settings3.prefix(), 'pref') - self.assertEqual(settings3.suffix(), 'suff') + self.assertEqual(settings3.prefix(), "pref") + self.assertEqual(settings3.suffix(), "suff") self.assertEqual(settings3.textFormat().size(), 13) self.assertEqual(settings3.orientation(), Qt.Orientation.Horizontal) self.assertFalse(settings3.useContinuousLegend()) # no text format - elem = doc.createElement('test2') + elem = doc.createElement("test2") settings2.writeXml(doc, elem, QgsReadWriteContext()) settings3a = QgsColorRampLegendNodeSettings() settings3a.readXml(elem, QgsReadWriteContext()) @@ -126,30 +136,39 @@ def test_basic(self): r = QgsGradientColorRamp(QColor(200, 0, 0, 100), QColor(0, 200, 0, 200)) # need a layer in order to make legend nodes - layer = QgsVectorLayer('dummy', 'test', 'memory') + layer = QgsVectorLayer("dummy", "test", "memory") layer_tree_layer = QgsLayerTreeLayer(layer) - node = QgsColorRampLegendNode(layer_tree_layer, r, 'min_label', 'max_label', None, 'key', 'parentKey') + node = QgsColorRampLegendNode( + layer_tree_layer, r, "min_label", "max_label", None, "key", "parentKey" + ) - self.assertEqual(node.ramp().color1().name(), '#c80000') - self.assertEqual(node.ramp().color2().name(), '#00c800') - self.assertEqual(node.data(QgsLayerTreeModelLegendNode.LegendNodeRoles.RuleKeyRole), 'key') - self.assertEqual(node.data(QgsLayerTreeModelLegendNode.LegendNodeRoles.ParentRuleKeyRole), 'parentKey') + self.assertEqual(node.ramp().color1().name(), "#c80000") + self.assertEqual(node.ramp().color2().name(), "#00c800") + self.assertEqual( + node.data(QgsLayerTreeModelLegendNode.LegendNodeRoles.RuleKeyRole), "key" + ) + self.assertEqual( + node.data(QgsLayerTreeModelLegendNode.LegendNodeRoles.ParentRuleKeyRole), + "parentKey", + ) node.setIconSize(QSize(11, 12)) self.assertEqual(node.iconSize(), QSize(11, 12)) - self.assertEqual(node.data(QgsLayerTreeModelLegendNode.LegendNodeRoles.NodeTypeRole), - QgsLayerTreeModelLegendNode.NodeTypes.ColorRampLegend) + self.assertEqual( + node.data(QgsLayerTreeModelLegendNode.LegendNodeRoles.NodeTypeRole), + QgsLayerTreeModelLegendNode.NodeTypes.ColorRampLegend, + ) def test_icon(self): r = QgsGradientColorRamp(QColor(200, 0, 0, 100), QColor(0, 200, 0, 200)) # need a layer in order to make legend nodes - layer = QgsVectorLayer('dummy', 'test', 'memory') + layer = QgsVectorLayer("dummy", "test", "memory") layer_tree_layer = QgsLayerTreeLayer(layer) - node = TestColorRampLegend(layer_tree_layer, r, 'min_label', 'max_label') + node = TestColorRampLegend(layer_tree_layer, r, "min_label", "max_label") pixmap = node.data(Qt.ItemDataRole.DecorationRole) @@ -159,13 +178,20 @@ def test_icon(self): p.drawPixmap(0, 0, pixmap) p.end() - self.assertTrue(self.image_check('color_ramp_legend_node_icon', 'color_ramp_legend_node_icon', im, size_tolerance=10)) + self.assertTrue( + self.image_check( + "color_ramp_legend_node_icon", + "color_ramp_legend_node_icon", + im, + size_tolerance=10, + ) + ) def test_icon_with_settings(self): r = QgsGradientColorRamp(QColor(200, 0, 0, 100), QColor(0, 200, 0, 200)) # need a layer in order to make legend nodes - layer = QgsVectorLayer('dummy', 'test', 'memory') + layer = QgsVectorLayer("dummy", "test", "memory") layer_tree_layer = QgsLayerTreeLayer(layer) settings = QgsColorRampLegendNodeSettings() @@ -185,18 +211,25 @@ def test_icon_with_settings(self): p.drawPixmap(0, 0, pixmap) p.end() - self.assertTrue(self.image_check('color_ramp_legend_node_settings_icon', 'color_ramp_legend_node_settings_icon', im, size_tolerance=10)) + self.assertTrue( + self.image_check( + "color_ramp_legend_node_settings_icon", + "color_ramp_legend_node_settings_icon", + im, + size_tolerance=10, + ) + ) def test_icon_prefix_suffix(self): r = QgsGradientColorRamp(QColor(200, 0, 0, 100), QColor(0, 200, 0, 200)) # need a layer in order to make legend nodes - layer = QgsVectorLayer('dummy', 'test', 'memory') + layer = QgsVectorLayer("dummy", "test", "memory") layer_tree_layer = QgsLayerTreeLayer(layer) settings = QgsColorRampLegendNodeSettings() - settings.setPrefix('pref ') - settings.setSuffix(' suff') + settings.setPrefix("pref ") + settings.setSuffix(" suff") node = TestColorRampLegend(layer_tree_layer, r, settings, 5, 10) @@ -208,13 +241,20 @@ def test_icon_prefix_suffix(self): p.drawPixmap(0, 0, pixmap) p.end() - self.assertTrue(self.image_check('color_ramp_legend_node_prefix_suffix_icon', 'color_ramp_legend_node_prefix_suffix_icon', im, size_tolerance=10)) + self.assertTrue( + self.image_check( + "color_ramp_legend_node_prefix_suffix_icon", + "color_ramp_legend_node_prefix_suffix_icon", + im, + size_tolerance=10, + ) + ) def test_icon_horizontal(self): r = QgsGradientColorRamp(QColor(200, 0, 0, 100), QColor(0, 200, 0, 200)) # need a layer in order to make legend nodes - layer = QgsVectorLayer('dummy', 'test', 'memory') + layer = QgsVectorLayer("dummy", "test", "memory") layer_tree_layer = QgsLayerTreeLayer(layer) settings = QgsColorRampLegendNodeSettings() @@ -230,13 +270,20 @@ def test_icon_horizontal(self): p.drawPixmap(0, 0, pixmap) p.end() - self.assertTrue(self.image_check('color_ramp_legend_node_horizontal_icon', 'color_ramp_legend_node_horizontal_icon', im, size_tolerance=10)) + self.assertTrue( + self.image_check( + "color_ramp_legend_node_horizontal_icon", + "color_ramp_legend_node_horizontal_icon", + im, + size_tolerance=10, + ) + ) def test_icon_horizontal_flipped(self): r = QgsGradientColorRamp(QColor(200, 0, 0, 100), QColor(0, 200, 0, 200)) # need a layer in order to make legend nodes - layer = QgsVectorLayer('dummy', 'test', 'memory') + layer = QgsVectorLayer("dummy", "test", "memory") layer_tree_layer = QgsLayerTreeLayer(layer) settings = QgsColorRampLegendNodeSettings() @@ -253,20 +300,27 @@ def test_icon_horizontal_flipped(self): p.drawPixmap(0, 0, pixmap) p.end() - self.assertTrue(self.image_check('color_ramp_legend_node_flipped_horizontal_icon', 'color_ramp_legend_node_flipped_horizontal_icon', im, size_tolerance=10)) + self.assertTrue( + self.image_check( + "color_ramp_legend_node_flipped_horizontal_icon", + "color_ramp_legend_node_flipped_horizontal_icon", + im, + size_tolerance=10, + ) + ) def test_draw(self): r = QgsGradientColorRamp(QColor(200, 0, 0, 100), QColor(0, 200, 0, 200)) # need a layer in order to make legend nodes - layer = QgsVectorLayer('dummy', 'test', 'memory') + layer = QgsVectorLayer("dummy", "test", "memory") layer_tree_layer = QgsLayerTreeLayer(layer) - node = QgsColorRampLegendNode(layer_tree_layer, r, 'min_label', 'max_label') + node = QgsColorRampLegendNode(layer_tree_layer, r, "min_label", "max_label") ls = QgsLegendSettings() item_style = ls.style(QgsLegendStyle.Style.SymbolLabel) - item_style.setFont(QgsFontUtils.getStandardTestFont('Bold', 18)) + item_style.setFont(QgsFontUtils.getStandardTestFont("Bold", 18)) ls.setStyle(QgsLegendStyle.Style.SymbolLabel, item_style) item_context = QgsLayerTreeModelLegendNode.ItemContext() @@ -296,13 +350,17 @@ def test_draw(self): node.drawSymbolText(ls, item_context, symbol_size) p.end() - self.assertTrue(self.image_check('color_ramp_legend_node_draw', 'color_ramp_legend_node_draw', image)) + self.assertTrue( + self.image_check( + "color_ramp_legend_node_draw", "color_ramp_legend_node_draw", image + ) + ) def test_draw_settings(self): r = QgsGradientColorRamp(QColor(200, 0, 0, 100), QColor(0, 200, 0, 200)) # need a layer in order to make legend nodes - layer = QgsVectorLayer('dummy', 'test', 'memory') + layer = QgsVectorLayer("dummy", "test", "memory") layer_tree_layer = QgsLayerTreeLayer(layer) settings = QgsColorRampLegendNodeSettings() @@ -316,7 +374,7 @@ def test_draw_settings(self): ls = QgsLegendSettings() item_style = ls.style(QgsLegendStyle.Style.SymbolLabel) - item_style.setFont(QgsFontUtils.getStandardTestFont('Bold', 18)) + item_style.setFont(QgsFontUtils.getStandardTestFont("Bold", 18)) ls.setStyle(QgsLegendStyle.Style.SymbolLabel, item_style) item_context = QgsLayerTreeModelLegendNode.ItemContext() @@ -346,23 +404,29 @@ def test_draw_settings(self): node.drawSymbolText(ls, item_context, symbol_size) p.end() - self.assertTrue(self.image_check('color_ramp_legend_node_settings_draw', 'color_ramp_legend_node_settings_draw', image)) + self.assertTrue( + self.image_check( + "color_ramp_legend_node_settings_draw", + "color_ramp_legend_node_settings_draw", + image, + ) + ) def test_draw_prefix_suffix(self): r = QgsGradientColorRamp(QColor(200, 0, 0, 100), QColor(0, 200, 0, 200)) # need a layer in order to make legend nodes - layer = QgsVectorLayer('dummy', 'test', 'memory') + layer = QgsVectorLayer("dummy", "test", "memory") layer_tree_layer = QgsLayerTreeLayer(layer) settings = QgsColorRampLegendNodeSettings() - settings.setPrefix('pref ') - settings.setSuffix(' suff') + settings.setPrefix("pref ") + settings.setSuffix(" suff") node = QgsColorRampLegendNode(layer_tree_layer, r, settings, 5, 10) ls = QgsLegendSettings() item_style = ls.style(QgsLegendStyle.Style.SymbolLabel) - item_style.setFont(QgsFontUtils.getStandardTestFont('Bold', 18)) + item_style.setFont(QgsFontUtils.getStandardTestFont("Bold", 18)) ls.setStyle(QgsLegendStyle.Style.SymbolLabel, item_style) item_context = QgsLayerTreeModelLegendNode.ItemContext() @@ -392,18 +456,24 @@ def test_draw_prefix_suffix(self): node.drawSymbolText(ls, item_context, symbol_size) p.end() - self.assertTrue(self.image_check('color_ramp_legend_node_prefix_suffix_draw', 'color_ramp_legend_node_prefix_suffix_draw', image)) + self.assertTrue( + self.image_check( + "color_ramp_legend_node_prefix_suffix_draw", + "color_ramp_legend_node_prefix_suffix_draw", + image, + ) + ) def test_draw_text_format(self): r = QgsGradientColorRamp(QColor(200, 0, 0, 100), QColor(0, 200, 0, 200)) # need a layer in order to make legend nodes - layer = QgsVectorLayer('dummy', 'test', 'memory') + layer = QgsVectorLayer("dummy", "test", "memory") layer_tree_layer = QgsLayerTreeLayer(layer) settings = QgsColorRampLegendNodeSettings() tf = QgsTextFormat() - tf.setFont(QgsFontUtils.getStandardTestFont('Bold', 18)) + tf.setFont(QgsFontUtils.getStandardTestFont("Bold", 18)) tf.setSize(30) tf.setColor(QColor(200, 100, 50)) settings.setTextFormat(tf) @@ -411,7 +481,7 @@ def test_draw_text_format(self): ls = QgsLegendSettings() item_style = ls.style(QgsLegendStyle.Style.SymbolLabel) - item_style.setFont(QgsFontUtils.getStandardTestFont('Bold', 18)) + item_style.setFont(QgsFontUtils.getStandardTestFont("Bold", 18)) ls.setStyle(QgsLegendStyle.Style.SymbolLabel, item_style) item_context = QgsLayerTreeModelLegendNode.ItemContext() @@ -441,13 +511,19 @@ def test_draw_text_format(self): node.drawSymbolText(ls, item_context, symbol_size) p.end() - self.assertTrue(self.image_check('color_ramp_legend_node_text_format_draw', 'color_ramp_legend_node_text_format_draw', image)) + self.assertTrue( + self.image_check( + "color_ramp_legend_node_text_format_draw", + "color_ramp_legend_node_text_format_draw", + image, + ) + ) def test_draw_horizontal(self): r = QgsGradientColorRamp(QColor(200, 0, 0, 100), QColor(0, 200, 0, 200)) # need a layer in order to make legend nodes - layer = QgsVectorLayer('dummy', 'test', 'memory') + layer = QgsVectorLayer("dummy", "test", "memory") layer_tree_layer = QgsLayerTreeLayer(layer) settings = QgsColorRampLegendNodeSettings() @@ -456,7 +532,7 @@ def test_draw_horizontal(self): ls = QgsLegendSettings() item_style = ls.style(QgsLegendStyle.Style.SymbolLabel) - item_style.setFont(QgsFontUtils.getStandardTestFont('Bold', 18)) + item_style.setFont(QgsFontUtils.getStandardTestFont("Bold", 18)) ls.setStyle(QgsLegendStyle.Style.SymbolLabel, item_style) item_context = QgsLayerTreeModelLegendNode.ItemContext() @@ -486,13 +562,19 @@ def test_draw_horizontal(self): node.drawSymbolText(ls, item_context, symbol_size) p.end() - self.assertTrue(self.image_check('color_ramp_legend_node_horizontal_draw', 'color_ramp_legend_node_horizontal_draw', image)) + self.assertTrue( + self.image_check( + "color_ramp_legend_node_horizontal_draw", + "color_ramp_legend_node_horizontal_draw", + image, + ) + ) def test_draw_horizontal_reversed(self): r = QgsGradientColorRamp(QColor(200, 0, 0, 100), QColor(0, 200, 0, 200)) # need a layer in order to make legend nodes - layer = QgsVectorLayer('dummy', 'test', 'memory') + layer = QgsVectorLayer("dummy", "test", "memory") layer_tree_layer = QgsLayerTreeLayer(layer) settings = QgsColorRampLegendNodeSettings() @@ -502,7 +584,7 @@ def test_draw_horizontal_reversed(self): ls = QgsLegendSettings() item_style = ls.style(QgsLegendStyle.Style.SymbolLabel) - item_style.setFont(QgsFontUtils.getStandardTestFont('Bold', 18)) + item_style.setFont(QgsFontUtils.getStandardTestFont("Bold", 18)) ls.setStyle(QgsLegendStyle.Style.SymbolLabel, item_style) item_context = QgsLayerTreeModelLegendNode.ItemContext() @@ -532,8 +614,14 @@ def test_draw_horizontal_reversed(self): node.drawSymbolText(ls, item_context, symbol_size) p.end() - self.assertTrue(self.image_check('color_ramp_legend_node_flipped_horizontal_draw', 'color_ramp_legend_node_flipped_horizontal_draw', image)) + self.assertTrue( + self.image_check( + "color_ramp_legend_node_flipped_horizontal_draw", + "color_ramp_legend_node_flipped_horizontal_draw", + image, + ) + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscolorscheme.py b/tests/src/python/test_qgscolorscheme.py index 1a336360a634..c84af585f54e 100644 --- a/tests/src/python/test_qgscolorscheme.py +++ b/tests/src/python/test_qgscolorscheme.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '25/07/2014' -__copyright__ = 'Copyright 2014, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "25/07/2014" +__copyright__ = "Copyright 2014, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication from qgis.PyQt.QtGui import QColor @@ -32,13 +33,13 @@ def __init__(self, parent=None): def schemeName(self): return "Dummy scheme" - def fetchColors(self, context='', baseColor=QColor()): - if (context == "testscheme"): - return [[QColor(255, 255, 0), 'schemetest']] + def fetchColors(self, context="", baseColor=QColor()): + if context == "testscheme": + return [[QColor(255, 255, 0), "schemetest"]] elif baseColor.isValid(): - return [[baseColor, 'base']] + return [[baseColor, "base"]] else: - return [[QColor(255, 0, 0), 'red'], [QColor(0, 255, 0), None]] + return [[QColor(255, 0, 0), "red"], [QColor(0, 255, 0), None]] def clone(self): return DummyColorScheme() @@ -72,7 +73,7 @@ def testColorsNoBase(self): colors = dummyScheme.fetchColors() self.assertEqual(len(colors), 2) self.assertEqual(colors[0][0], QColor(255, 0, 0)) - self.assertEqual(colors[0][1], 'red') + self.assertEqual(colors[0][1], "red") self.assertEqual(colors[1][0], QColor(0, 255, 0)) self.assertEqual(colors[1][1], None) @@ -83,15 +84,15 @@ def testColorsWithBase(self): colors = dummyScheme.fetchColors(None, testColor) self.assertEqual(len(colors), 1) self.assertEqual(colors[0][0], testColor) - self.assertEqual(colors[0][1], 'base') + self.assertEqual(colors[0][1], "base") def testColorsWithScheme(self): """Test getting colors when specifying a scheme""" dummyScheme = DummyColorScheme() - colors = dummyScheme.fetchColors('testscheme') + colors = dummyScheme.fetchColors("testscheme") self.assertEqual(len(colors), 1) self.assertEqual(colors[0][0], QColor(255, 255, 0)) - self.assertEqual(colors[0][1], 'schemetest') + self.assertEqual(colors[0][1], "schemetest") def testClone(self): """Test cloning a color scheme""" @@ -102,22 +103,28 @@ def testClone(self): self.assertEqual(colors, colorsClone) def testUserScheme(self): - """ Tests for user color schemes """ + """Tests for user color schemes""" scheme = QgsUserColorScheme("user_test.gpl") - self.assertEqual(scheme.schemeName(), 'user_test.gpl') + self.assertEqual(scheme.schemeName(), "user_test.gpl") self.assertTrue(scheme.isEditable()) - self.assertFalse(scheme.flags() & QgsColorScheme.SchemeFlag.ShowInColorButtonMenu) + self.assertFalse( + scheme.flags() & QgsColorScheme.SchemeFlag.ShowInColorButtonMenu + ) scheme.setShowSchemeInMenu(True) - self.assertTrue(scheme.flags() & QgsColorScheme.SchemeFlag.ShowInColorButtonMenu) + self.assertTrue( + scheme.flags() & QgsColorScheme.SchemeFlag.ShowInColorButtonMenu + ) scheme.setShowSchemeInMenu(False) - self.assertFalse(scheme.flags() & QgsColorScheme.SchemeFlag.ShowInColorButtonMenu) + self.assertFalse( + scheme.flags() & QgsColorScheme.SchemeFlag.ShowInColorButtonMenu + ) scheme.erase() def testRecentColors(self): - """ test retrieving recent colors """ + """test retrieving recent colors""" QgsSettings().clear() # no colors diff --git a/tests/src/python/test_qgscolorschemeregistry.py b/tests/src/python/test_qgscolorschemeregistry.py index b0a4476671c3..401abaf816b2 100644 --- a/tests/src/python/test_qgscolorschemeregistry.py +++ b/tests/src/python/test_qgscolorschemeregistry.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '25/07/2014' -__copyright__ = 'Copyright 2014, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "25/07/2014" +__copyright__ = "Copyright 2014, The QGIS Project" from qgis.core import ( @@ -59,7 +60,9 @@ def testPopulateFromInstance(self): registry = QgsColorSchemeRegistry() self.assertEqual(len(registry.schemes()), 0) registry.populateFromInstance() - self.assertEqual(len(registry.schemes()), len(QgsApplication.colorSchemeRegistry().schemes())) + self.assertEqual( + len(registry.schemes()), len(QgsApplication.colorSchemeRegistry().schemes()) + ) def testRemoveScheme(self): """Test removing a scheme from a registry""" @@ -80,6 +83,7 @@ def testOwnership(self): They should be parented to the registry (on transfer) and even if there's no reference to the registry around (see the `del` below) this childship should continue to exist. """ + class TestColorScheme(QgsColorScheme): def schemeName(self): @@ -100,7 +104,7 @@ def flags(self): reg = QgsApplication.instance().colorSchemeRegistry() - self.assertIn('TestScheme', [scheme.schemeName() for scheme in reg.schemes()]) + self.assertIn("TestScheme", [scheme.schemeName() for scheme in reg.schemes()]) if __name__ == "__main__": diff --git a/tests/src/python/test_qgscolorutils.py b/tests/src/python/test_qgscolorutils.py index ad452132ff24..78bd64172545 100644 --- a/tests/src/python/test_qgscolorutils.py +++ b/tests/src/python/test_qgscolorutils.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '06/07/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "06/07/2022" +__copyright__ = "Copyright 2022, The QGIS Project" import os @@ -41,17 +42,17 @@ def test_color_xml(self): doc = QDomDocument() context = QgsReadWriteContext() - element = doc.createElement('element') + element = doc.createElement("element") # invalid color - QgsColorUtils.writeXml(QColor(), 'my_color', doc, element, context) - res = QgsColorUtils.readXml(element, 'my_color', context) + QgsColorUtils.writeXml(QColor(), "my_color", doc, element, context) + res = QgsColorUtils.readXml(element, "my_color", context) self.assertFalse(res.isValid()) # rgb color color = QColor.fromRgbF(1 / 65536, 2 / 65536, 3 / 65536, 4 / 65536) - QgsColorUtils.writeXml(color, 'my_color', doc, element, context) - res = QgsColorUtils.readXml(element, 'my_color', context) + QgsColorUtils.writeXml(color, "my_color", doc, element, context) + res = QgsColorUtils.readXml(element, "my_color", context) self.assertTrue(res.isValid()) self.assertEqual(res.spec(), QColor.Spec.Rgb) self.assertAlmostEqual(res.redF(), 1 / 65536, 5) @@ -60,8 +61,8 @@ def test_color_xml(self): self.assertAlmostEqual(res.alphaF(), 4 / 65536, 5) color = QColor.fromRgb(16, 17, 18, 20) - QgsColorUtils.writeXml(color, 'my_color', doc, element, context) - res = QgsColorUtils.readXml(element, 'my_color', context) + QgsColorUtils.writeXml(color, "my_color", doc, element, context) + res = QgsColorUtils.readXml(element, "my_color", context) self.assertTrue(res.isValid()) self.assertEqual(res.spec(), QColor.Spec.Rgb) self.assertEqual(res.red(), 16) @@ -72,8 +73,8 @@ def test_color_xml(self): # rgb extended color if TestQgsColorUtils.has_extended_rgb: color = QColor.fromRgbF(-1 / 65536, 2 / 65536, 3 / 65536, 4 / 65536) - QgsColorUtils.writeXml(color, 'my_rgb_ex_color', doc, element, context) - res = QgsColorUtils.readXml(element, 'my_rgb_ex_color', context) + QgsColorUtils.writeXml(color, "my_rgb_ex_color", doc, element, context) + res = QgsColorUtils.readXml(element, "my_rgb_ex_color", context) self.assertTrue(res.isValid()) self.assertEqual(res.spec(), QColor.Spec.ExtendedRgb) self.assertAlmostEqual(res.redF(), -1 / 65536, 5) @@ -83,8 +84,8 @@ def test_color_xml(self): # hsv color color = QColor.fromHsvF(1 / 65536, 2 / 65536, 3 / 65536, 4 / 65536) - QgsColorUtils.writeXml(color, 'my_hsv_color', doc, element, context) - res = QgsColorUtils.readXml(element, 'my_hsv_color', context) + QgsColorUtils.writeXml(color, "my_hsv_color", doc, element, context) + res = QgsColorUtils.readXml(element, "my_hsv_color", context) self.assertTrue(res.isValid()) self.assertEqual(res.spec(), QColor.Spec.Hsv) self.assertAlmostEqual(res.hueF(), 1 / 65536, 4) @@ -94,8 +95,8 @@ def test_color_xml(self): # hsl color color = QColor.fromHslF(111 / 65536, 12222 / 65536, 333 / 65536, 4 / 65536) - QgsColorUtils.writeXml(color, 'my_hsl_color', doc, element, context) - res = QgsColorUtils.readXml(element, 'my_hsl_color', context) + QgsColorUtils.writeXml(color, "my_hsl_color", doc, element, context) + res = QgsColorUtils.readXml(element, "my_hsl_color", context) self.assertTrue(res.isValid()) self.assertEqual(res.spec(), QColor.Spec.Hsl) self.assertAlmostEqual(res.hslHueF(), 111 / 65536, 5) @@ -105,8 +106,8 @@ def test_color_xml(self): # cmyk color color = QColor.fromCmykF(1 / 65536, 2 / 65536, 3 / 65536, 4 / 65536, 5 / 65536) - QgsColorUtils.writeXml(color, 'my_cmyk_color', doc, element, context) - res = QgsColorUtils.readXml(element, 'my_cmyk_color', context) + QgsColorUtils.writeXml(color, "my_cmyk_color", doc, element, context) + res = QgsColorUtils.readXml(element, "my_cmyk_color", context) self.assertTrue(res.isValid()) self.assertEqual(res.spec(), QColor.Spec.Cmyk) self.assertAlmostEqual(res.cyanF(), 1 / 65536, 4) @@ -116,7 +117,7 @@ def test_color_xml(self): self.assertAlmostEqual(res.alphaF(), 5 / 65536, 5) # missing color - res = QgsColorUtils.readXml(element, 'not there', context) + res = QgsColorUtils.readXml(element, "not there", context) self.assertFalse(res.isValid()) def test_color_string(self): @@ -185,7 +186,9 @@ def test_color_string(self): self.assertAlmostEqual(res.alphaF(), 4 / 65536, 5) # cmyk color - color = QColor.fromCmykF(1 / 65536, 2 / 65536, 3 / 65536, 4 / 65536, 255 / 65536) + color = QColor.fromCmykF( + 1 / 65536, 2 / 65536, 3 / 65536, 4 / 65536, 255 / 65536 + ) string = QgsColorUtils.colorToString(color) res = QgsColorUtils.colorFromString(string) self.assertTrue(res.isValid()) @@ -197,11 +200,11 @@ def test_color_string(self): self.assertAlmostEqual(res.alphaF(), 255 / 65536, 5) # invalid string - res = QgsColorUtils.colorFromString('') + res = QgsColorUtils.colorFromString("") self.assertFalse(res.isValid()) - res = QgsColorUtils.colorFromString('x') + res = QgsColorUtils.colorFromString("x") self.assertFalse(res.isValid()) - res = QgsColorUtils.colorFromString('2') + res = QgsColorUtils.colorFromString("2") self.assertFalse(res.isValid()) def test_color_string_compat(self): @@ -311,5 +314,5 @@ def test_icc_profile(self): self.assertTrue(not error) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscolorwidget.py b/tests/src/python/test_qgscolorwidget.py index 948797d8e935..d963f1a39c31 100644 --- a/tests/src/python/test_qgscolorwidget.py +++ b/tests/src/python/test_qgscolorwidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Julien Cabieces' -__date__ = '02/05/2024' -__copyright__ = 'Copyright 2024, The QGIS Project' + +__author__ = "Julien Cabieces" +__date__ = "02/05/2024" +__copyright__ = "Copyright 2024, The QGIS Project" from qgis.PyQt.QtGui import QColor from qgis.gui import QgsColorWidget @@ -168,5 +169,5 @@ def testSetComponentValue(self): self.assertEqual(w.componentValue(QgsColorWidget.ColorComponent.Hue), 30) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscombinedstylemodel.py b/tests/src/python/test_qgscombinedstylemodel.py index 14ad4717ec4c..9ce52a447de7 100644 --- a/tests/src/python/test_qgscombinedstylemodel.py +++ b/tests/src/python/test_qgscombinedstylemodel.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '18/03/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "18/03/2022" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication, QEvent, Qt from qgis.core import QgsStyle, QgsStyleModel, QgsTextFormat @@ -24,7 +25,9 @@ class TestQgsCombinedStyleModel(QgisTestCase): - @unittest.skipIf(QgsCombinedStyleModel is None, "QgsCombinedStyleModel not available") + @unittest.skipIf( + QgsCombinedStyleModel is None, "QgsCombinedStyleModel not available" + ) def test_model(self): model = QgsCombinedStyleModel() self.assertFalse(model.styles()) @@ -32,72 +35,107 @@ def test_model(self): style1 = QgsStyle() style1.createMemoryDatabase() - style1.setName('first style') - style1.setFileName('/home/my style1.db') + style1.setName("first style") + style1.setFileName("/home/my style1.db") model.addStyle(style1) self.assertEqual(model.styles(), [style1]) - self.assertEqual(model.headerData(0, Qt.Orientation.Horizontal), 'Name') - self.assertEqual(model.headerData(1, Qt.Orientation.Horizontal), 'Tags') + self.assertEqual(model.headerData(0, Qt.Orientation.Horizontal), "Name") + self.assertEqual(model.headerData(1, Qt.Orientation.Horizontal), "Tags") self.assertEqual(model.columnCount(), 2) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'first style') + self.assertEqual(model.data(model.index(0, 0)), "first style") self.assertTrue(model.data(model.index(0, 0), QgsStyleModel.Role.IsTitleRole)) - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.StyleName), 'first style') - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.StyleFileName), '/home/my style1.db') - - style1.addTextFormat('format 1', QgsTextFormat(), True) + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.StyleName), "first style" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.StyleFileName), + "/home/my style1.db", + ) + + style1.addTextFormat("format 1", QgsTextFormat(), True) self.assertEqual(model.rowCount(), 2) - self.assertEqual(model.data(model.index(0, 0)), 'first style') + self.assertEqual(model.data(model.index(0, 0)), "first style") self.assertTrue(model.data(model.index(0, 0), QgsStyleModel.Role.IsTitleRole)) - self.assertEqual(model.data(model.index(1, 0)), 'format 1') + self.assertEqual(model.data(model.index(1, 0)), "format 1") self.assertFalse(model.data(model.index(1, 0), QgsStyleModel.Role.IsTitleRole)) - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.StyleName), 'first style') - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.StyleFileName), '/home/my style1.db') + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.StyleName), "first style" + ) + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.StyleFileName), + "/home/my style1.db", + ) style2 = QgsStyle() style2.createMemoryDatabase() - style2.setName('second style') - style2.setFileName('/home/my style2.db') - style2.addTextFormat('format 2', QgsTextFormat(), True) - style2.addTextFormat('format 3', QgsTextFormat(), True) + style2.setName("second style") + style2.setFileName("/home/my style2.db") + style2.addTextFormat("format 2", QgsTextFormat(), True) + style2.addTextFormat("format 3", QgsTextFormat(), True) model.addStyle(style2) self.assertEqual(model.styles(), [style1, style2]) self.assertEqual(model.rowCount(), 5) - self.assertEqual(model.data(model.index(0, 0)), 'first style') + self.assertEqual(model.data(model.index(0, 0)), "first style") self.assertTrue(model.data(model.index(0, 0), QgsStyleModel.Role.IsTitleRole)) - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.StyleName), 'first style') - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.StyleFileName), '/home/my style1.db') - self.assertEqual(model.data(model.index(1, 0)), 'format 1') + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.StyleName), "first style" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.StyleFileName), + "/home/my style1.db", + ) + self.assertEqual(model.data(model.index(1, 0)), "format 1") self.assertFalse(model.data(model.index(1, 0), QgsStyleModel.Role.IsTitleRole)) - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.StyleName), 'first style') - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.StyleFileName), '/home/my style1.db') - self.assertEqual(model.data(model.index(2, 0)), 'second style') + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.StyleName), "first style" + ) + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.StyleFileName), + "/home/my style1.db", + ) + self.assertEqual(model.data(model.index(2, 0)), "second style") self.assertTrue(model.data(model.index(2, 0), QgsStyleModel.Role.IsTitleRole)) - self.assertEqual(model.data(model.index(2, 0), QgsStyleModel.Role.StyleName), 'second style') - self.assertEqual(model.data(model.index(2, 0), QgsStyleModel.Role.StyleFileName), '/home/my style2.db') - self.assertEqual(model.data(model.index(3, 0)), 'format 2') + self.assertEqual( + model.data(model.index(2, 0), QgsStyleModel.Role.StyleName), "second style" + ) + self.assertEqual( + model.data(model.index(2, 0), QgsStyleModel.Role.StyleFileName), + "/home/my style2.db", + ) + self.assertEqual(model.data(model.index(3, 0)), "format 2") self.assertFalse(model.data(model.index(3, 0), QgsStyleModel.Role.IsTitleRole)) - self.assertEqual(model.data(model.index(3, 0), QgsStyleModel.Role.StyleName), 'second style') - self.assertEqual(model.data(model.index(3, 0), QgsStyleModel.Role.StyleFileName), '/home/my style2.db') - self.assertEqual(model.data(model.index(4, 0)), 'format 3') + self.assertEqual( + model.data(model.index(3, 0), QgsStyleModel.Role.StyleName), "second style" + ) + self.assertEqual( + model.data(model.index(3, 0), QgsStyleModel.Role.StyleFileName), + "/home/my style2.db", + ) + self.assertEqual(model.data(model.index(4, 0)), "format 3") self.assertFalse(model.data(model.index(4, 0), QgsStyleModel.Role.IsTitleRole)) - self.assertEqual(model.data(model.index(4, 0), QgsStyleModel.Role.StyleName), 'second style') - self.assertEqual(model.data(model.index(4, 0), QgsStyleModel.Role.StyleFileName), '/home/my style2.db') + self.assertEqual( + model.data(model.index(4, 0), QgsStyleModel.Role.StyleName), "second style" + ) + self.assertEqual( + model.data(model.index(4, 0), QgsStyleModel.Role.StyleFileName), + "/home/my style2.db", + ) style1.deleteLater() style1 = None QCoreApplication.sendPostedEvents(None, QEvent.Type.DeferredDelete) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0)), 'second style') + self.assertEqual(model.data(model.index(0, 0)), "second style") self.assertTrue(model.data(model.index(0, 0), QgsStyleModel.Role.IsTitleRole)) - self.assertEqual(model.data(model.index(1, 0)), 'format 2') + self.assertEqual(model.data(model.index(1, 0)), "format 2") self.assertFalse(model.data(model.index(1, 0), QgsStyleModel.Role.IsTitleRole)) - self.assertEqual(model.data(model.index(2, 0)), 'format 3') + self.assertEqual(model.data(model.index(2, 0)), "format 3") self.assertFalse(model.data(model.index(2, 0), QgsStyleModel.Role.IsTitleRole)) model.removeStyle(style2) @@ -106,5 +144,5 @@ def test_model(self): model.removeStyle(style2) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscompoundcurve.py b/tests/src/python/test_qgscompoundcurve.py index 913d4744b5ce..29223c4e36c7 100644 --- a/tests/src/python/test_qgscompoundcurve.py +++ b/tests/src/python/test_qgscompoundcurve.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Loïc Bartoletti' -__date__ = '19/12/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "Loïc Bartoletti" +__date__ = "19/12/2023" +__copyright__ = "Copyright 2023, The QGIS Project" import qgis # NOQA @@ -31,12 +32,16 @@ def testFuzzyComparisons(self): geom2 = QgsCompoundCurve() line1 = QgsLineString(QgsPoint(0.0, 0.0), QgsPoint(0.001, 0.001)) - circularString1 = QgsCircularString(QgsPoint(0.0, 0.0), QgsPoint(0.001, 0.001), QgsPoint(0.5, 0.5)) + circularString1 = QgsCircularString( + QgsPoint(0.0, 0.0), QgsPoint(0.001, 0.001), QgsPoint(0.5, 0.5) + ) geom1.addCurve(line1) geom1.addCurve(circularString1) line2 = QgsLineString(QgsPoint(0.0, 0.0), QgsPoint(0.002, 0.002)) - circularString2 = QgsCircularString(QgsPoint(0.0, 0.0), QgsPoint(0.001, 0.001), QgsPoint(0.5, 0.5)) + circularString2 = QgsCircularString( + QgsPoint(0.0, 0.0), QgsPoint(0.001, 0.001), QgsPoint(0.5, 0.5) + ) geom2.addCurve(line2) geom2.addCurve(circularString2) @@ -56,12 +61,16 @@ def testFuzzyComparisons(self): geom2 = QgsCompoundCurve() line1 = QgsLineString(QgsPoint(0.0, 0.0), QgsPoint(0.001, 0.001)) - circularString1 = QgsCircularString(QgsPoint(0.0, 0.0), QgsPoint(0.001, 0.001), QgsPoint(0.5, 0.5)) + circularString1 = QgsCircularString( + QgsPoint(0.0, 0.0), QgsPoint(0.001, 0.001), QgsPoint(0.5, 0.5) + ) geom1.addCurve(line1) geom1.addCurve(circularString1) line2 = QgsLineString(QgsPoint(0.0, 0.0), QgsPoint(0.001, 0.001)) - circularString2 = QgsCircularString(QgsPoint(0.0, 0.0), QgsPoint(0.002, 0.002), QgsPoint(0.5, 0.5)) + circularString2 = QgsCircularString( + QgsPoint(0.0, 0.0), QgsPoint(0.002, 0.002), QgsPoint(0.5, 0.5) + ) geom2.addCurve(line2) geom2.addCurve(circularString2) @@ -84,12 +93,20 @@ def testFuzzyComparisons(self): geom2 = QgsCompoundCurve() line1 = QgsLineString(QgsPoint(0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001)) - circularString1 = QgsCircularString(QgsPoint(0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001), QgsPoint(0.5, 0.5, 0.5)) + circularString1 = QgsCircularString( + QgsPoint(0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.001), + QgsPoint(0.5, 0.5, 0.5), + ) geom1.addCurve(line1) geom1.addCurve(circularString1) line2 = QgsLineString(QgsPoint(0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.002)) - circularString2 = QgsCircularString(QgsPoint(0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001), QgsPoint(0.5, 0.5, 0.5)) + circularString2 = QgsCircularString( + QgsPoint(0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.001), + QgsPoint(0.5, 0.5, 0.5), + ) geom2.addCurve(line2) geom2.addCurve(circularString2) @@ -108,13 +125,25 @@ def testFuzzyComparisons(self): geom1 = QgsCompoundCurve() geom2 = QgsCompoundCurve() - line1 = QgsLineString(QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.001)) - circularString1 = QgsCircularString(QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.001), QgsPoint(0.5, 0.5, m=0.5)) + line1 = QgsLineString( + QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.001) + ) + circularString1 = QgsCircularString( + QgsPoint(0.0, 0.0, m=0.0), + QgsPoint(0.001, 0.001, m=0.001), + QgsPoint(0.5, 0.5, m=0.5), + ) geom1.addCurve(line1) geom1.addCurve(circularString1) - line2 = QgsLineString(QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.001)) - circularString2 = QgsCircularString(QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.002), QgsPoint(0.5, 0.5, m=0.5)) + line2 = QgsLineString( + QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.001) + ) + circularString2 = QgsCircularString( + QgsPoint(0.0, 0.0, m=0.0), + QgsPoint(0.001, 0.001, m=0.002), + QgsPoint(0.5, 0.5, m=0.5), + ) geom2.addCurve(line2) geom2.addCurve(circularString2) @@ -136,13 +165,25 @@ def testFuzzyComparisons(self): geom1 = QgsCompoundCurve() geom2 = QgsCompoundCurve() - line1 = QgsLineString(QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.001)) - circularString1 = QgsCircularString(QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.001), QgsPoint(0.5, 0.5, m=0.5)) + line1 = QgsLineString( + QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.001) + ) + circularString1 = QgsCircularString( + QgsPoint(0.0, 0.0, m=0.0), + QgsPoint(0.001, 0.001, m=0.001), + QgsPoint(0.5, 0.5, m=0.5), + ) geom1.addCurve(line1) geom1.addCurve(circularString1) - line2 = QgsLineString(QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.002)) - circularString2 = QgsCircularString(QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.001), QgsPoint(0.5, 0.5, m=0.5)) + line2 = QgsLineString( + QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.002) + ) + circularString2 = QgsCircularString( + QgsPoint(0.0, 0.0, m=0.0), + QgsPoint(0.001, 0.001, m=0.001), + QgsPoint(0.5, 0.5, m=0.5), + ) geom2.addCurve(line2) geom2.addCurve(circularString2) @@ -162,12 +203,20 @@ def testFuzzyComparisons(self): geom2 = QgsCompoundCurve() line1 = QgsLineString(QgsPoint(0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001)) - circularString1 = QgsCircularString(QgsPoint(0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001), QgsPoint(0.5, 0.5, 0.5)) + circularString1 = QgsCircularString( + QgsPoint(0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.001), + QgsPoint(0.5, 0.5, 0.5), + ) geom1.addCurve(line1) geom1.addCurve(circularString1) line2 = QgsLineString(QgsPoint(0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001)) - circularString2 = QgsCircularString(QgsPoint(0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.002), QgsPoint(0.5, 0.5, 0.5)) + circularString2 = QgsCircularString( + QgsPoint(0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.002), + QgsPoint(0.5, 0.5, 0.5), + ) geom2.addCurve(line2) geom2.addCurve(circularString2) @@ -189,13 +238,25 @@ def testFuzzyComparisons(self): geom1 = QgsCompoundCurve() geom2 = QgsCompoundCurve() - line1 = QgsLineString(QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001, 0.001)) - circularString1 = QgsCircularString(QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001, 0.001), QgsPoint(0.5, 0.5, 0.5, 0.5)) + line1 = QgsLineString( + QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001, 0.001) + ) + circularString1 = QgsCircularString( + QgsPoint(0.0, 0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.001, 0.001), + QgsPoint(0.5, 0.5, 0.5, 0.5), + ) geom1.addCurve(line1) geom1.addCurve(circularString1) - line2 = QgsLineString(QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.002, 0.002)) - circularString2 = QgsCircularString(QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001, 0.001), QgsPoint(0.5, 0.5, 0.5, 0.5)) + line2 = QgsLineString( + QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.002, 0.002) + ) + circularString2 = QgsCircularString( + QgsPoint(0.0, 0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.001, 0.001), + QgsPoint(0.5, 0.5, 0.5, 0.5), + ) geom2.addCurve(line2) geom2.addCurve(circularString2) @@ -214,13 +275,25 @@ def testFuzzyComparisons(self): geom1 = QgsCompoundCurve() geom2 = QgsCompoundCurve() - line1 = QgsLineString(QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001, 0.001)) - circularString1 = QgsCircularString(QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001, 0.001), QgsPoint(0.5, 0.5, 0.5, 0.5)) + line1 = QgsLineString( + QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001, 0.001) + ) + circularString1 = QgsCircularString( + QgsPoint(0.0, 0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.001, 0.001), + QgsPoint(0.5, 0.5, 0.5, 0.5), + ) geom1.addCurve(line1) geom1.addCurve(circularString1) - line2 = QgsLineString(QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001, 0.001)) - circularString2 = QgsCircularString(QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.002, 0.002), QgsPoint(0.5, 0.5, 0.5, 0.5)) + line2 = QgsLineString( + QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001, 0.001) + ) + circularString2 = QgsCircularString( + QgsPoint(0.0, 0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.002, 0.002), + QgsPoint(0.5, 0.5, 0.5, 0.5), + ) geom2.addCurve(line2) geom2.addCurve(circularString2) @@ -239,13 +312,22 @@ def test_simplify_by_distance(self): test simplifyByDistance """ p = QgsCompoundCurve() - p.fromWkt('CompoundCurve (CircularString (4.40660981021897413 0.93610259854013833, 11.01953454014598321 23.6382050218978037, 34.67607970802919226 28.41041874452553984),(34.67607970802919226 28.41041874452553984, 46.06121816058393392 30.38747871532845934, 61.74134896350363988 29.02398908029196178))') - self.assertEqual(p.simplifyByDistance(0.5).asWkt(3), 'LineString (4.407 0.936, 3.765 8.905, 5.88 16.615, 10.217 22.855, 16.706 27.525, 21.235 29.154, 26.003 29.808, 34.676 28.41, 46.061 30.387, 61.741 29.024)') - self.assertEqual(p.simplifyByDistance(0.75).asWkt(3), - 'LineString (4.407 0.936, 3.765 8.905, 5.88 16.615, 10.217 22.855, 16.706 27.525, 26.003 29.808, 34.676 28.41, 46.061 30.387, 61.741 29.024)') - self.assertEqual(p.simplifyByDistance(1).asWkt(3), - 'LineString (4.407 0.936, 3.765 8.905, 5.88 16.615, 10.217 22.855, 16.706 27.525, 26.003 29.808, 34.676 28.41, 46.061 30.387, 61.741 29.024)') - - -if __name__ == '__main__': + p.fromWkt( + "CompoundCurve (CircularString (4.40660981021897413 0.93610259854013833, 11.01953454014598321 23.6382050218978037, 34.67607970802919226 28.41041874452553984),(34.67607970802919226 28.41041874452553984, 46.06121816058393392 30.38747871532845934, 61.74134896350363988 29.02398908029196178))" + ) + self.assertEqual( + p.simplifyByDistance(0.5).asWkt(3), + "LineString (4.407 0.936, 3.765 8.905, 5.88 16.615, 10.217 22.855, 16.706 27.525, 21.235 29.154, 26.003 29.808, 34.676 28.41, 46.061 30.387, 61.741 29.024)", + ) + self.assertEqual( + p.simplifyByDistance(0.75).asWkt(3), + "LineString (4.407 0.936, 3.765 8.905, 5.88 16.615, 10.217 22.855, 16.706 27.525, 26.003 29.808, 34.676 28.41, 46.061 30.387, 61.741 29.024)", + ) + self.assertEqual( + p.simplifyByDistance(1).asWkt(3), + "LineString (4.407 0.936, 3.765 8.905, 5.88 16.615, 10.217 22.855, 16.706 27.525, 26.003 29.808, 34.676 28.41, 46.061 30.387, 61.741 29.024)", + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsconditionalformatwidgets.py b/tests/src/python/test_qgsconditionalformatwidgets.py index 51d4d60cdc2a..189bf8701f16 100644 --- a/tests/src/python/test_qgsconditionalformatwidgets.py +++ b/tests/src/python/test_qgsconditionalformatwidgets.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2019-09-25' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2019-09-25" +__copyright__ = "Copyright 2019, The QGIS Project" from qgis.PyQt.QtGui import QColor from qgis.core import QgsConditionalStyle, QgsMarkerSymbol @@ -25,20 +26,20 @@ class TestPyQgsConditionalFormatWidgets(QgisTestCase): def testEditorWidget(self): c = QgsConditionalStyle() - c.setName('') + c.setName("") w = QgsEditConditionalFormatRuleWidget() w.loadStyle(c) self.assertEqual(w.currentStyle(), c) - w.setRule('my rule') - self.assertEqual(w.currentStyle().rule(), 'my rule') + w.setRule("my rule") + self.assertEqual(w.currentStyle().rule(), "my rule") - c.setName('n') + c.setName("n") w = QgsEditConditionalFormatRuleWidget() w.loadStyle(c) self.assertEqual(w.currentStyle(), c) - c.setRule('1=1') + c.setRule("1=1") w = QgsEditConditionalFormatRuleWidget() w.loadStyle(c) self.assertEqual(w.currentStyle(), c) @@ -89,5 +90,5 @@ def testEditorWidget(self): self.assertEqual(w.currentStyle().font().underline(), True) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsconditionalstyle.py b/tests/src/python/test_qgsconditionalstyle.py index e2996e29b8fd..081311595869 100644 --- a/tests/src/python/test_qgsconditionalstyle.py +++ b/tests/src/python/test_qgsconditionalstyle.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nathan.Woodrow' -__date__ = '2015-08-11' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Nathan.Woodrow" +__date__ = "2015-08-11" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.PyQt.QtCore import QVariant from qgis.PyQt.QtGui import QColor, QFont @@ -45,19 +46,23 @@ def new_context(self): def testDefaultStyle(self): style = QgsConditionalStyle() self.assertFalse(style.isValid()) - style.setName('x') + style.setName("x") self.assertTrue(style.isValid()) self.assertFalse(style.textColor().isValid()) self.assertFalse(style.backgroundColor().isValid()) def test_MatchesReturnsTrueForSimpleMatch(self): style = QgsConditionalStyle("@value > 10") - context = QgsExpressionContextUtils.createFeatureBasedContext(QgsFeature(), QgsFields()) + context = QgsExpressionContextUtils.createFeatureBasedContext( + QgsFeature(), QgsFields() + ) self.assertTrue(style.matches(20, context)) def test_MatchesReturnsTrueForComplexMatch(self): style = QgsConditionalStyle("@value > 10 and @value = 20") - context = QgsExpressionContextUtils.createFeatureBasedContext(QgsFeature(), QgsFields()) + context = QgsExpressionContextUtils.createFeatureBasedContext( + QgsFeature(), QgsFields() + ) self.assertTrue(style.matches(20, context)) def test_MatchesTrueForFields(self): @@ -84,7 +89,9 @@ def testStyleCompression(self): style = QgsConditionalStyle.compressStyles([]) self.assertFalse(style.isValid()) # invalid styles should not be compressed - style = QgsConditionalStyle.compressStyles([QgsConditionalStyle(), QgsConditionalStyle()]) + style = QgsConditionalStyle.compressStyles( + [QgsConditionalStyle(), QgsConditionalStyle()] + ) self.assertFalse(style.isValid()) c = QgsConditionalStyle() @@ -109,16 +116,16 @@ def testEquality(self): c2 = QgsConditionalStyle() self.assertEqual(c, c2) self.assertFalse(c != c2) - c.setName('n') + c.setName("n") self.assertNotEqual(c, c2) self.assertTrue(c != c2) - c2.setName('n') + c2.setName("n") self.assertEqual(c, c2) self.assertFalse(c != c2) - c.setRule('1=1') + c.setRule("1=1") self.assertNotEqual(c, c2) self.assertTrue(c != c2) - c2.setRule('1=1') + c2.setRule("1=1") self.assertEqual(c, c2) self.assertFalse(c != c2) f = QFont() @@ -154,36 +161,62 @@ def testEquality(self): def testLayerStyles(self): styles = QgsConditionalLayerStyles() self.assertFalse(styles.rowStyles()) - self.assertFalse(styles.fieldStyles('test')) + self.assertFalse(styles.fieldStyles("test")) spy = QSignalSpy(styles.changed) - styles.setRowStyles([QgsConditionalStyle("@value > 10"), QgsConditionalStyle("@value > 20")]) + styles.setRowStyles( + [QgsConditionalStyle("@value > 10"), QgsConditionalStyle("@value > 20")] + ) self.assertEqual(len(spy), 1) - self.assertEqual(styles.rowStyles(), [QgsConditionalStyle("@value > 10"), QgsConditionalStyle("@value > 20")]) + self.assertEqual( + styles.rowStyles(), + [QgsConditionalStyle("@value > 10"), QgsConditionalStyle("@value > 20")], + ) styles.setRowStyles(styles.rowStyles()) self.assertEqual(len(spy), 1) - styles.setFieldStyles('test', [QgsConditionalStyle("@value > 30"), QgsConditionalStyle("@value > 40")]) + styles.setFieldStyles( + "test", + [QgsConditionalStyle("@value > 30"), QgsConditionalStyle("@value > 40")], + ) self.assertEqual(len(spy), 2) - self.assertEqual(styles.fieldStyles('test'), [QgsConditionalStyle("@value > 30"), QgsConditionalStyle("@value > 40")]) - styles.setFieldStyles('test', styles.fieldStyles('test')) + self.assertEqual( + styles.fieldStyles("test"), + [QgsConditionalStyle("@value > 30"), QgsConditionalStyle("@value > 40")], + ) + styles.setFieldStyles("test", styles.fieldStyles("test")) self.assertEqual(len(spy), 2) - self.assertFalse(styles.fieldStyles('test2')) - styles.setFieldStyles('test2', [QgsConditionalStyle("@value > 50")]) + self.assertFalse(styles.fieldStyles("test2")) + styles.setFieldStyles("test2", [QgsConditionalStyle("@value > 50")]) self.assertEqual(len(spy), 3) - self.assertEqual(styles.fieldStyles('test'), [QgsConditionalStyle("@value > 30"), QgsConditionalStyle("@value > 40")]) - self.assertEqual(styles.fieldStyles('test2'), [QgsConditionalStyle("@value > 50")]) + self.assertEqual( + styles.fieldStyles("test"), + [QgsConditionalStyle("@value > 30"), QgsConditionalStyle("@value > 40")], + ) + self.assertEqual( + styles.fieldStyles("test2"), [QgsConditionalStyle("@value > 50")] + ) def testRequiresGeometry(self): styles = QgsConditionalLayerStyles() styles.setRowStyles([QgsConditionalStyle("@value > 10")]) self.assertFalse(styles.rulesNeedGeometry()) - styles.setRowStyles([QgsConditionalStyle("@value > 10"), QgsConditionalStyle('$geometry IS NULL')]) + styles.setRowStyles( + [ + QgsConditionalStyle("@value > 10"), + QgsConditionalStyle("$geometry IS NULL"), + ] + ) self.assertTrue(styles.rulesNeedGeometry()) - styles.setRowStyles([QgsConditionalStyle('$geometry IS NULL'), QgsConditionalStyle("@value > 10")]) + styles.setRowStyles( + [ + QgsConditionalStyle("$geometry IS NULL"), + QgsConditionalStyle("@value > 10"), + ] + ) self.assertTrue(styles.rulesNeedGeometry()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsconnectionregistry.py b/tests/src/python/test_qgsconnectionregistry.py index ce4c0c57a14c..fa3c402d0952 100644 --- a/tests/src/python/test_qgsconnectionregistry.py +++ b/tests/src/python/test_qgsconnectionregistry.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '16/03/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "16/03/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import os import shutil @@ -44,11 +45,13 @@ def setUpClass(cls): start_app() QgsSettings().clear() - gpkg_original_path = f'{TEST_DATA_DIR}/qgis_server/test_project_wms_grouped_layers.gpkg' + gpkg_original_path = ( + f"{TEST_DATA_DIR}/qgis_server/test_project_wms_grouped_layers.gpkg" + ) cls.basetestpath = tempfile.mkdtemp() - cls.gpkg_path = f'{cls.basetestpath}/test_gpkg.gpkg' + cls.gpkg_path = f"{cls.basetestpath}/test_gpkg.gpkg" shutil.copy(gpkg_original_path, cls.gpkg_path) - vl = QgsVectorLayer(f'{cls.gpkg_path}|layername=cdb_lines', 'test', 'ogr') + vl = QgsVectorLayer(f"{cls.gpkg_path}|layername=cdb_lines", "test", "ogr") assert vl.isValid() @classmethod @@ -62,35 +65,35 @@ def testCreateConnectionBad(self): Test creating connection with bad parameters """ with self.assertRaises(QgsProviderConnectionException): - QgsApplication.connectionRegistry().createConnection('invalid') + QgsApplication.connectionRegistry().createConnection("invalid") with self.assertRaises(QgsProviderConnectionException): - QgsApplication.connectionRegistry().createConnection('invalid://') + QgsApplication.connectionRegistry().createConnection("invalid://") with self.assertRaises(QgsProviderConnectionException): - QgsApplication.connectionRegistry().createConnection('invalid://aa') + QgsApplication.connectionRegistry().createConnection("invalid://aa") def testCreateConnectionGood(self): # make a valid connection - md = QgsProviderRegistry.instance().providerMetadata('ogr') + md = QgsProviderRegistry.instance().providerMetadata("ogr") conn = md.createConnection(self.gpkg_path, {}) - md.saveConnection(conn, 'qgis_test1') + md.saveConnection(conn, "qgis_test1") - conn = QgsApplication.connectionRegistry().createConnection('ogr://adasdas') + conn = QgsApplication.connectionRegistry().createConnection("ogr://adasdas") self.assertFalse(conn.uri()) - conn = QgsApplication.connectionRegistry().createConnection('ogr://qgis_test1') + conn = QgsApplication.connectionRegistry().createConnection("ogr://qgis_test1") self.assertEqual(conn.uri(), self.gpkg_path) # case insensitive provider name - conn = QgsApplication.connectionRegistry().createConnection('OGR://qgis_test1') + conn = QgsApplication.connectionRegistry().createConnection("OGR://qgis_test1") self.assertEqual(conn.uri(), self.gpkg_path) # connection name with spaces - md.saveConnection(conn, 'qgis Test 2') - conn = QgsApplication.connectionRegistry().createConnection('OGR://qgis Test 2') + md.saveConnection(conn, "qgis Test 2") + conn = QgsApplication.connectionRegistry().createConnection("OGR://qgis Test 2") self.assertEqual(conn.uri(), self.gpkg_path) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscoordinateformatter.py b/tests/src/python/test_qgscoordinateformatter.py index 280245bb26f7..f3e62b213e26 100644 --- a/tests/src/python/test_qgscoordinateformatter.py +++ b/tests/src/python/test_qgscoordinateformatter.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '25/07/2014' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "25/07/2014" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.PyQt.QtCore import QLocale from qgis.core import Qgis, QgsCoordinateFormatter, QgsPointXY @@ -23,379 +24,1591 @@ def setUp(self): def testFormatXPair(self): """Test formatting x as pair""" - self.assertEqual(QgsCoordinateFormatter.formatX(20, QgsCoordinateFormatter.Format.FormatPair, 0), '20') - self.assertEqual(QgsCoordinateFormatter.formatX(-20, QgsCoordinateFormatter.Format.FormatPair, 0), '-20') - self.assertEqual(QgsCoordinateFormatter.formatX(20.11111111111111111, QgsCoordinateFormatter.Format.FormatPair, 3), '20.111') - self.assertEqual(QgsCoordinateFormatter.formatX(20.11161111111111111, QgsCoordinateFormatter.Format.FormatPair, 3), '20.112') - self.assertEqual(QgsCoordinateFormatter.formatX(20, QgsCoordinateFormatter.Format.FormatPair, 3), '20.000') - self.assertEqual(QgsCoordinateFormatter.formatX(float('inf'), QgsCoordinateFormatter.Format.FormatPair, 3), 'infinite') + self.assertEqual( + QgsCoordinateFormatter.formatX( + 20, QgsCoordinateFormatter.Format.FormatPair, 0 + ), + "20", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -20, QgsCoordinateFormatter.Format.FormatPair, 0 + ), + "-20", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 20.11111111111111111, QgsCoordinateFormatter.Format.FormatPair, 3 + ), + "20.111", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 20.11161111111111111, QgsCoordinateFormatter.Format.FormatPair, 3 + ), + "20.112", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 20, QgsCoordinateFormatter.Format.FormatPair, 3 + ), + "20.000", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + float("inf"), QgsCoordinateFormatter.Format.FormatPair, 3 + ), + "infinite", + ) def testFormatYPair(self): """Test formatting y as pair""" - self.assertEqual(QgsCoordinateFormatter.formatY(20, QgsCoordinateFormatter.Format.FormatPair, 0), '20') - self.assertEqual(QgsCoordinateFormatter.formatY(-20, QgsCoordinateFormatter.Format.FormatPair, 0), '-20') - self.assertEqual(QgsCoordinateFormatter.formatY(20.11111111111111111, QgsCoordinateFormatter.Format.FormatPair, 3), '20.111') - self.assertEqual(QgsCoordinateFormatter.formatY(20.11161111111111111, QgsCoordinateFormatter.Format.FormatPair, 3), '20.112') - self.assertEqual(QgsCoordinateFormatter.formatY(20, QgsCoordinateFormatter.Format.FormatPair, 3), '20.000') - self.assertEqual(QgsCoordinateFormatter.formatY(float('inf'), QgsCoordinateFormatter.Format.FormatPair, 3), 'infinite') + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20, QgsCoordinateFormatter.Format.FormatPair, 0 + ), + "20", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -20, QgsCoordinateFormatter.Format.FormatPair, 0 + ), + "-20", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20.11111111111111111, QgsCoordinateFormatter.Format.FormatPair, 3 + ), + "20.111", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20.11161111111111111, QgsCoordinateFormatter.Format.FormatPair, 3 + ), + "20.112", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20, QgsCoordinateFormatter.Format.FormatPair, 3 + ), + "20.000", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + float("inf"), QgsCoordinateFormatter.Format.FormatPair, 3 + ), + "infinite", + ) def testAsPair(self): """Test formatting x/y as pair""" - self.assertEqual(QgsCoordinateFormatter.asPair(20, 30, 0), '20,30') - self.assertEqual(QgsCoordinateFormatter.asPair(20, -30, 0), '20,-30') - self.assertEqual(QgsCoordinateFormatter.asPair(20.111, 10.999, 0), '20,11') - self.assertEqual(QgsCoordinateFormatter.asPair(20.111, 10.999, 2), '20.11,11.00') - self.assertEqual(QgsCoordinateFormatter.asPair(20, 10, 2), '20.00,10.00') - self.assertEqual(QgsCoordinateFormatter.asPair(20, -10, 2), '20.00,-10.00') + self.assertEqual(QgsCoordinateFormatter.asPair(20, 30, 0), "20,30") + self.assertEqual(QgsCoordinateFormatter.asPair(20, -30, 0), "20,-30") + self.assertEqual(QgsCoordinateFormatter.asPair(20.111, 10.999, 0), "20,11") + self.assertEqual( + QgsCoordinateFormatter.asPair(20.111, 10.999, 2), "20.11,11.00" + ) + self.assertEqual(QgsCoordinateFormatter.asPair(20, 10, 2), "20.00,10.00") + self.assertEqual(QgsCoordinateFormatter.asPair(20, -10, 2), "20.00,-10.00") - self.assertEqual(QgsCoordinateFormatter.asPair(20, -10, 2, order=Qgis.CoordinateOrder.XY), '20.00,-10.00') - self.assertEqual(QgsCoordinateFormatter.asPair(20, -10, 2, order=Qgis.CoordinateOrder.YX), '-10.00,20.00') + self.assertEqual( + QgsCoordinateFormatter.asPair(20, -10, 2, order=Qgis.CoordinateOrder.XY), + "20.00,-10.00", + ) + self.assertEqual( + QgsCoordinateFormatter.asPair(20, -10, 2, order=Qgis.CoordinateOrder.YX), + "-10.00,20.00", + ) def testFormat(self): - self.assertEqual(QgsCoordinateFormatter.format(QgsPointXY(20.1, 30.2), QgsCoordinateFormatter.Format.FormatPair, 0), '20,30') - self.assertEqual(QgsCoordinateFormatter.format(QgsPointXY(20.1, 30.2), QgsCoordinateFormatter.Format.FormatPair, 1), '20.1,30.2') - self.assertEqual(QgsCoordinateFormatter.format(QgsPointXY(20, 30), QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 0), '20°0′0″E,30°0′0″N') + self.assertEqual( + QgsCoordinateFormatter.format( + QgsPointXY(20.1, 30.2), QgsCoordinateFormatter.Format.FormatPair, 0 + ), + "20,30", + ) + self.assertEqual( + QgsCoordinateFormatter.format( + QgsPointXY(20.1, 30.2), QgsCoordinateFormatter.Format.FormatPair, 1 + ), + "20.1,30.2", + ) + self.assertEqual( + QgsCoordinateFormatter.format( + QgsPointXY(20, 30), + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 0, + ), + "20°0′0″E,30°0′0″N", + ) - self.assertEqual(QgsCoordinateFormatter.format(QgsPointXY(20.1, 30.2), QgsCoordinateFormatter.Format.FormatPair, 1, order=Qgis.CoordinateOrder.XY), '20.1,30.2') - self.assertEqual(QgsCoordinateFormatter.format(QgsPointXY(20.1, 30.2), QgsCoordinateFormatter.Format.FormatPair, 1, - order=Qgis.CoordinateOrder.YX), '30.2,20.1') self.assertEqual( - QgsCoordinateFormatter.format(QgsPointXY(20, 30), QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 0, order=Qgis.CoordinateOrder.YX), - '30°0′0″N,20°0′0″E') + QgsCoordinateFormatter.format( + QgsPointXY(20.1, 30.2), + QgsCoordinateFormatter.Format.FormatPair, + 1, + order=Qgis.CoordinateOrder.XY, + ), + "20.1,30.2", + ) + self.assertEqual( + QgsCoordinateFormatter.format( + QgsPointXY(20.1, 30.2), + QgsCoordinateFormatter.Format.FormatPair, + 1, + order=Qgis.CoordinateOrder.YX, + ), + "30.2,20.1", + ) + self.assertEqual( + QgsCoordinateFormatter.format( + QgsPointXY(20, 30), + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 0, + order=Qgis.CoordinateOrder.YX, + ), + "30°0′0″N,20°0′0″E", + ) def testFormatXFormatDegreesMinutesSeconds(self): """Test formatting x as DMS""" - self.assertEqual(QgsCoordinateFormatter.formatX(80, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "80°0′0.00″E") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 80, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "80°0′0.00″E", + ) # check precision - self.assertEqual(QgsCoordinateFormatter.formatX(80, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 4), "80°0′0.0000″E") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 80, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 4 + ), + "80°0′0.0000″E", + ) for precision in range(1, 20): - self.assertEqual(QgsCoordinateFormatter.formatX(80.123456789123456789, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, precision), "80°7′{{:.0{}f}}″E".format(precision).format(24.444440844426935655064880848)) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 80.123456789123456789, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + precision, + ), + f"80°7′{{:.0{precision}f}}″E".format(24.444440844426935655064880848), + ) # check if longitudes > 180 or <-180 wrap around - self.assertEqual(QgsCoordinateFormatter.formatX(370, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "10°0′0.00″E") - self.assertEqual(QgsCoordinateFormatter.formatX(-370, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "10°0′0.00″W") - self.assertEqual(QgsCoordinateFormatter.formatX(181, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "179°0′0.00″W") - self.assertEqual(QgsCoordinateFormatter.formatX(-181, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "179°0′0.00″E") - self.assertEqual(QgsCoordinateFormatter.formatX(359, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "1°0′0.00″W") - self.assertEqual(QgsCoordinateFormatter.formatX(-359, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "1°0′0.00″E") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 370, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "10°0′0.00″E", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -370, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "10°0′0.00″W", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 181, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "179°0′0.00″W", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -181, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "179°0′0.00″E", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 359, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "1°0′0.00″W", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -359, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "1°0′0.00″E", + ) # should be no directional suffixes for 0 degree coordinates - self.assertEqual(QgsCoordinateFormatter.formatX(0, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "0°0′0.00″") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "0°0′0.00″", + ) # should also be no directional suffix for 0 degree coordinates within specified precision - self.assertEqual(QgsCoordinateFormatter.formatX(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "0°0′0.00″") - self.assertEqual(QgsCoordinateFormatter.formatX(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5), "0°0′0.00360″W") - self.assertEqual(QgsCoordinateFormatter.formatX(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "0°0′0.00″") - self.assertEqual(QgsCoordinateFormatter.formatX(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5), "0°0′0.00360″E") + self.assertEqual( + QgsCoordinateFormatter.formatX( + -0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "0°0′0.00″", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5 + ), + "0°0′0.00360″W", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "0°0′0.00″", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5 + ), + "0°0′0.00360″E", + ) # should be no directional suffixes for 180 degree longitudes - self.assertEqual(QgsCoordinateFormatter.formatX(180, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "180°0′0.00″") - self.assertEqual(QgsCoordinateFormatter.formatX(179.999999, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "180°0′0.00″") - self.assertEqual(QgsCoordinateFormatter.formatX(179.999999, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5), "179°59′59.99640″E") - self.assertEqual(QgsCoordinateFormatter.formatX(180.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "180°0′0.00″") - self.assertEqual(QgsCoordinateFormatter.formatX(180.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5), "179°59′59.99640″W") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 180, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "180°0′0.00″", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 179.999999, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "180°0′0.00″", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 179.999999, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5 + ), + "179°59′59.99640″E", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 180.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "180°0′0.00″", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 180.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5 + ), + "179°59′59.99640″W", + ) # test rounding does not create seconds >= 60 - self.assertEqual(QgsCoordinateFormatter.formatX(99.999999, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "100°0′0.00″E") - self.assertEqual(QgsCoordinateFormatter.formatX(89.999999, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "90°0′0.00″E") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 99.999999, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "100°0′0.00″E", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 89.999999, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "90°0′0.00″E", + ) # test without direction suffix - self.assertEqual(QgsCoordinateFormatter.formatX(80, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2, QgsCoordinateFormatter.FormatFlags()), "80°0′0.00″") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 80, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "80°0′0.00″", + ) # test 0 longitude - self.assertEqual(QgsCoordinateFormatter.formatX(0, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2, QgsCoordinateFormatter.FormatFlags()), "0°0′0.00″") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "0°0′0.00″", + ) # test near zero longitude - self.assertEqual(QgsCoordinateFormatter.formatX(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2, QgsCoordinateFormatter.FormatFlags()), "0°0′0.00″") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "0°0′0.00″", + ) # should be no "-" prefix for near-zero longitude when rounding to 2 decimal places - self.assertEqual(QgsCoordinateFormatter.formatX(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2, QgsCoordinateFormatter.FormatFlags()), "0°0′0.00″") - self.assertEqual(QgsCoordinateFormatter.formatX(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5, QgsCoordinateFormatter.FormatFlags()), "0°0′0.00360″") - self.assertEqual(QgsCoordinateFormatter.formatX(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5, QgsCoordinateFormatter.FormatFlags()), "-0°0′0.00360″") + self.assertEqual( + QgsCoordinateFormatter.formatX( + -0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "0°0′0.00″", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 5, + QgsCoordinateFormatter.FormatFlags(), + ), + "0°0′0.00360″", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 5, + QgsCoordinateFormatter.FormatFlags(), + ), + "-0°0′0.00360″", + ) # test with padding - padding_and_suffix = QgsCoordinateFormatter.FormatFlags(QgsCoordinateFormatter.FormatFlag.FlagDegreesPadMinutesSeconds | QgsCoordinateFormatter.FormatFlag.FlagDegreesUseStringSuffix) - self.assertEqual(QgsCoordinateFormatter.formatX(80, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2, padding_and_suffix), "80°00′00.00″E") - self.assertEqual(QgsCoordinateFormatter.formatX(85.44, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2, padding_and_suffix), "85°26′24.00″E") - self.assertEqual(QgsCoordinateFormatter.formatX(0, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2, padding_and_suffix), "0°00′00.00″") - self.assertEqual(QgsCoordinateFormatter.formatX(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2, padding_and_suffix), "0°00′00.00″") - self.assertEqual(QgsCoordinateFormatter.formatX(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2, padding_and_suffix), "0°00′00.00″") - self.assertEqual(QgsCoordinateFormatter.formatX(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5, padding_and_suffix), "0°00′00.00360″W") - self.assertEqual(QgsCoordinateFormatter.formatX(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5, padding_and_suffix), "0°00′00.00360″E") + padding_and_suffix = QgsCoordinateFormatter.FormatFlags( + QgsCoordinateFormatter.FormatFlag.FlagDegreesPadMinutesSeconds + | QgsCoordinateFormatter.FormatFlag.FlagDegreesUseStringSuffix + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 80, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + padding_and_suffix, + ), + "80°00′00.00″E", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 85.44, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + padding_and_suffix, + ), + "85°26′24.00″E", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + padding_and_suffix, + ), + "0°00′00.00″", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + padding_and_suffix, + ), + "0°00′00.00″", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + padding_and_suffix, + ), + "0°00′00.00″", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 5, + padding_and_suffix, + ), + "0°00′00.00360″W", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 5, + padding_and_suffix, + ), + "0°00′00.00360″E", + ) def testFormatYFormatDegreesMinutesSeconds(self): """Test formatting y as DMS""" - self.assertEqual(QgsCoordinateFormatter.formatY(20, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "20°0′0.00″N") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "20°0′0.00″N", + ) # check precision - self.assertEqual(QgsCoordinateFormatter.formatY(20, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 4), "20°0′0.0000″N") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 4 + ), + "20°0′0.0000″N", + ) for precision in range(1, 20): - self.assertEqual(QgsCoordinateFormatter.formatY(20.123456789123456789, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, precision), "20°7′{{:.0{}f}}″N".format(precision).format(24.4444408444397254243086)) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20.123456789123456789, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + precision, + ), + f"20°7′{{:.0{precision}f}}″N".format(24.4444408444397254243086), + ) # check if latitudes > 90 or <-90 wrap around - self.assertEqual(QgsCoordinateFormatter.formatY(190, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "10°0′0.00″N") - self.assertEqual(QgsCoordinateFormatter.formatY(-190, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "10°0′0.00″S") - self.assertEqual(QgsCoordinateFormatter.formatY(91, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "89°0′0.00″S") - self.assertEqual(QgsCoordinateFormatter.formatY(-91, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "89°0′0.00″N") - self.assertEqual(QgsCoordinateFormatter.formatY(179, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "1°0′0.00″S") - self.assertEqual(QgsCoordinateFormatter.formatY(-179, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "1°0′0.00″N") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 190, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "10°0′0.00″N", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -190, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "10°0′0.00″S", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 91, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "89°0′0.00″S", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -91, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "89°0′0.00″N", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 179, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "1°0′0.00″S", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -179, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "1°0′0.00″N", + ) # should be no directional suffixes for 0 degree coordinates - self.assertEqual(QgsCoordinateFormatter.formatY(0, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "0°0′0.00″") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "0°0′0.00″", + ) # should also be no directional suffix for 0 degree coordinates within specified precision - self.assertEqual(QgsCoordinateFormatter.formatY(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "0°0′0.00″") - self.assertEqual(QgsCoordinateFormatter.formatY(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5), "0°0′0.00360″N") - self.assertEqual(QgsCoordinateFormatter.formatY(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "0°0′0.00″") - self.assertEqual(QgsCoordinateFormatter.formatY(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5), "0°0′0.00360″S") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "0°0′0.00″", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5 + ), + "0°0′0.00360″N", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "0°0′0.00″", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5 + ), + "0°0′0.00360″S", + ) # test rounding does not create seconds >= 60 - self.assertEqual(QgsCoordinateFormatter.formatY(89.999999, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), "90°0′0.00″N") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 89.999999, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2 + ), + "90°0′0.00″N", + ) # test without direction suffix - self.assertEqual(QgsCoordinateFormatter.formatY(20, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2, QgsCoordinateFormatter.FormatFlags()), "20°0′0.00″") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "20°0′0.00″", + ) # test 0 latitude - self.assertEqual(QgsCoordinateFormatter.formatY(0, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2, QgsCoordinateFormatter.FormatFlags()), "0°0′0.00″") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "0°0′0.00″", + ) # test near zero lat/long - self.assertEqual(QgsCoordinateFormatter.formatY(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2, QgsCoordinateFormatter.FormatFlags()), "0°0′0.00″") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "0°0′0.00″", + ) # should be no "-" prefix for near-zero latitude when rounding to 2 decimal places - self.assertEqual(QgsCoordinateFormatter.formatY(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2, QgsCoordinateFormatter.FormatFlags()), "0°0′0.00″") - self.assertEqual(QgsCoordinateFormatter.formatY(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5, QgsCoordinateFormatter.FormatFlags()), "0°0′0.00360″") - self.assertEqual(QgsCoordinateFormatter.formatY(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5, QgsCoordinateFormatter.FormatFlags()), "-0°0′0.00360″") + self.assertEqual( + QgsCoordinateFormatter.formatY( + -0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "0°0′0.00″", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 5, + QgsCoordinateFormatter.FormatFlags(), + ), + "0°0′0.00360″", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 5, + QgsCoordinateFormatter.FormatFlags(), + ), + "-0°0′0.00360″", + ) # test with padding - padding_and_suffix = QgsCoordinateFormatter.FormatFlags(QgsCoordinateFormatter.FormatFlag.FlagDegreesPadMinutesSeconds | QgsCoordinateFormatter.FormatFlag.FlagDegreesUseStringSuffix) - self.assertEqual(QgsCoordinateFormatter.formatY(20, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2, padding_and_suffix), "20°00′00.00″N") - self.assertEqual(QgsCoordinateFormatter.formatY(85.44, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2, padding_and_suffix), "85°26′24.00″N") - self.assertEqual(QgsCoordinateFormatter.formatY(0, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2, padding_and_suffix), "0°00′00.00″") - self.assertEqual(QgsCoordinateFormatter.formatY(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2, padding_and_suffix), "0°00′00.00″") - self.assertEqual(QgsCoordinateFormatter.formatY(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2, padding_and_suffix), "0°00′00.00″") - self.assertEqual(QgsCoordinateFormatter.formatY(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5, padding_and_suffix), "0°00′00.00360″S") - self.assertEqual(QgsCoordinateFormatter.formatY(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 5, padding_and_suffix), "0°00′00.00360″N") + padding_and_suffix = QgsCoordinateFormatter.FormatFlags( + QgsCoordinateFormatter.FormatFlag.FlagDegreesPadMinutesSeconds + | QgsCoordinateFormatter.FormatFlag.FlagDegreesUseStringSuffix + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + padding_and_suffix, + ), + "20°00′00.00″N", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 85.44, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + padding_and_suffix, + ), + "85°26′24.00″N", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + padding_and_suffix, + ), + "0°00′00.00″", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + padding_and_suffix, + ), + "0°00′00.00″", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + padding_and_suffix, + ), + "0°00′00.00″", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 5, + padding_and_suffix, + ), + "0°00′00.00360″S", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 5, + padding_and_suffix, + ), + "0°00′00.00360″N", + ) def testFormatXDegreesMinutes(self): """Test formatting x as DM""" - self.assertEqual(QgsCoordinateFormatter.formatX(80, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "80°0.00′E") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 80, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "80°0.00′E", + ) # check precision - self.assertEqual(QgsCoordinateFormatter.formatX(80, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 4), "80°0.0000′E") - self.assertEqual(QgsCoordinateFormatter.formatX(80.12345678, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 4), "80°7.4074′E") - self.assertEqual(QgsCoordinateFormatter.formatX(80.12345678, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 0), "80°7′E") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 80, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 4 + ), + "80°0.0000′E", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 80.12345678, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 4 + ), + "80°7.4074′E", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 80.12345678, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 0 + ), + "80°7′E", + ) # check if longitudes > 180 or <-180 wrap around - self.assertEqual(QgsCoordinateFormatter.formatX(370, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "10°0.00′E") - self.assertEqual(QgsCoordinateFormatter.formatX(-370, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "10°0.00′W") - self.assertEqual(QgsCoordinateFormatter.formatX(181, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "179°0.00′W") - self.assertEqual(QgsCoordinateFormatter.formatX(-181, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "179°0.00′E") - self.assertEqual(QgsCoordinateFormatter.formatX(359, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "1°0.00′W") - self.assertEqual(QgsCoordinateFormatter.formatX(-359, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "1°0.00′E") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 370, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "10°0.00′E", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -370, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "10°0.00′W", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 181, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "179°0.00′W", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -181, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "179°0.00′E", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 359, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "1°0.00′W", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -359, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "1°0.00′E", + ) # should be no directional suffixes for 0 degree coordinates - self.assertEqual(QgsCoordinateFormatter.formatX(0, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "0°0.00′") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "0°0.00′", + ) # should also be no directional suffix for 0 degree coordinates within specified precision - self.assertEqual(QgsCoordinateFormatter.formatX(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "0°0.00′") - self.assertEqual(QgsCoordinateFormatter.formatX(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "0°0.00′") - self.assertEqual(QgsCoordinateFormatter.formatX(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5), "0°0.00006′W") - self.assertEqual(QgsCoordinateFormatter.formatX(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5), "0°0.00006′E") + self.assertEqual( + QgsCoordinateFormatter.formatX( + -0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "0°0.00′", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "0°0.00′", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5 + ), + "0°0.00006′W", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5 + ), + "0°0.00006′E", + ) # test rounding does not create minutes >= 60 - self.assertEqual(QgsCoordinateFormatter.formatX(99.999999, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "100°0.00′E") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 99.999999, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "100°0.00′E", + ) # should be no directional suffixes for 180 degree longitudes - self.assertEqual(QgsCoordinateFormatter.formatX(180, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "180°0.00′") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 180, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "180°0.00′", + ) # should also be no directional suffix for 180 degree longitudes within specified precision - self.assertEqual(QgsCoordinateFormatter.formatX(180.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "180°0.00′") - self.assertEqual(QgsCoordinateFormatter.formatX(179.999999, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "180°0.00′") - self.assertEqual(QgsCoordinateFormatter.formatX(180.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5), "179°59.99994′W") - self.assertEqual(QgsCoordinateFormatter.formatX(179.999999, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5), "179°59.99994′E") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 180.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "180°0.00′", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 179.999999, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "180°0.00′", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 180.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5 + ), + "179°59.99994′W", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 179.999999, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5 + ), + "179°59.99994′E", + ) # test without direction suffix - self.assertEqual(QgsCoordinateFormatter.formatX(80, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2, QgsCoordinateFormatter.FormatFlags()), "80°0.00′") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 80, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "80°0.00′", + ) # test 0 longitude - self.assertEqual(QgsCoordinateFormatter.formatX(0, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2, QgsCoordinateFormatter.FormatFlags()), "0°0.00′") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "0°0.00′", + ) # test near zero longitude - self.assertEqual(QgsCoordinateFormatter.formatX(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2, QgsCoordinateFormatter.FormatFlags()), "0°0.00′") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "0°0.00′", + ) # should be no "-" prefix for near-zero longitude when rounding to 2 decimal places - self.assertEqual(QgsCoordinateFormatter.formatX(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2, QgsCoordinateFormatter.FormatFlags()), "0°0.00′") - self.assertEqual(QgsCoordinateFormatter.formatX(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5, QgsCoordinateFormatter.FormatFlags()), "0°0.00006′") - self.assertEqual(QgsCoordinateFormatter.formatX(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5, QgsCoordinateFormatter.FormatFlags()), "-0°0.00006′") + self.assertEqual( + QgsCoordinateFormatter.formatX( + -0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "0°0.00′", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 5, + QgsCoordinateFormatter.FormatFlags(), + ), + "0°0.00006′", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 5, + QgsCoordinateFormatter.FormatFlags(), + ), + "-0°0.00006′", + ) # test with padding - padding_and_suffix = QgsCoordinateFormatter.FormatFlags(QgsCoordinateFormatter.FormatFlag.FlagDegreesPadMinutesSeconds | QgsCoordinateFormatter.FormatFlag.FlagDegreesUseStringSuffix) - self.assertEqual(QgsCoordinateFormatter.formatX(80, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2, padding_and_suffix), "80°00.00′E") - self.assertEqual(QgsCoordinateFormatter.formatX(0, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2, padding_and_suffix), "0°00.00′") - self.assertEqual(QgsCoordinateFormatter.formatX(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2, padding_and_suffix), "0°00.00′") - self.assertEqual(QgsCoordinateFormatter.formatX(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2, padding_and_suffix), "0°00.00′") - self.assertEqual(QgsCoordinateFormatter.formatX(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5, padding_and_suffix), "0°00.00006′W") - self.assertEqual(QgsCoordinateFormatter.formatX(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5, padding_and_suffix), "0°00.00006′E") + padding_and_suffix = QgsCoordinateFormatter.FormatFlags( + QgsCoordinateFormatter.FormatFlag.FlagDegreesPadMinutesSeconds + | QgsCoordinateFormatter.FormatFlag.FlagDegreesUseStringSuffix + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 80, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 2, + padding_and_suffix, + ), + "80°00.00′E", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 2, + padding_and_suffix, + ), + "0°00.00′", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 2, + padding_and_suffix, + ), + "0°00.00′", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 2, + padding_and_suffix, + ), + "0°00.00′", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 5, + padding_and_suffix, + ), + "0°00.00006′W", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 5, + padding_and_suffix, + ), + "0°00.00006′E", + ) def testFormatYDegreesMinutes(self): """Test formatting y as DM""" - self.assertEqual(QgsCoordinateFormatter.formatY(20, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "20°0.00′N") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "20°0.00′N", + ) # check precision - self.assertEqual(QgsCoordinateFormatter.formatY(20, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 4), "20°0.0000′N") - self.assertEqual(QgsCoordinateFormatter.formatY(20.12345678, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 4), "20°7.4074′N") - self.assertEqual(QgsCoordinateFormatter.formatY(20.12345678, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 0), "20°7′N") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 4 + ), + "20°0.0000′N", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20.12345678, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 4 + ), + "20°7.4074′N", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20.12345678, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 0 + ), + "20°7′N", + ) # check if latitudes > 90 or <-90 wrap around - self.assertEqual(QgsCoordinateFormatter.formatY(190, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "10°0.00′N") - self.assertEqual(QgsCoordinateFormatter.formatY(-190, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "10°0.00′S") - self.assertEqual(QgsCoordinateFormatter.formatY(91, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "89°0.00′S") - self.assertEqual(QgsCoordinateFormatter.formatY(-91, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "89°0.00′N") - self.assertEqual(QgsCoordinateFormatter.formatY(179, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "1°0.00′S") - self.assertEqual(QgsCoordinateFormatter.formatY(-179, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "1°0.00′N") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 190, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "10°0.00′N", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -190, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "10°0.00′S", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 91, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "89°0.00′S", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -91, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "89°0.00′N", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 179, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "1°0.00′S", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -179, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "1°0.00′N", + ) # should be no directional suffixes for 0 degree coordinates - self.assertEqual(QgsCoordinateFormatter.formatY(0, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "0°0.00′") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "0°0.00′", + ) # should also be no directional suffix for 0 degree coordinates within specified precision - self.assertEqual(QgsCoordinateFormatter.formatY(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "0°0.00′") - self.assertEqual(QgsCoordinateFormatter.formatY(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "0°0.00′") - self.assertEqual(QgsCoordinateFormatter.formatY(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5), "0°0.00006′S") - self.assertEqual(QgsCoordinateFormatter.formatY(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5), "0°0.00006′N") + self.assertEqual( + QgsCoordinateFormatter.formatY( + -0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "0°0.00′", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "0°0.00′", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5 + ), + "0°0.00006′S", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5 + ), + "0°0.00006′N", + ) # test rounding does not create minutes >= 60 - self.assertEqual(QgsCoordinateFormatter.formatY(79.999999, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2), "80°0.00′N") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 79.999999, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2 + ), + "80°0.00′N", + ) # test without direction suffix - self.assertEqual(QgsCoordinateFormatter.formatY(20, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2, QgsCoordinateFormatter.FormatFlags()), "20°0.00′") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "20°0.00′", + ) # test 0 latitude - self.assertEqual(QgsCoordinateFormatter.formatY(0, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2, QgsCoordinateFormatter.FormatFlags()), "0°0.00′") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "0°0.00′", + ) # test near zero latitude - self.assertEqual(QgsCoordinateFormatter.formatY(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2, QgsCoordinateFormatter.FormatFlags()), "0°0.00′") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "0°0.00′", + ) # should be no "-" prefix for near-zero latitude when rounding to 2 decimal places - self.assertEqual(QgsCoordinateFormatter.formatY(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2, QgsCoordinateFormatter.FormatFlags()), "0°0.00′") - self.assertEqual(QgsCoordinateFormatter.formatY(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5, QgsCoordinateFormatter.FormatFlags()), "0°0.00006′") - self.assertEqual(QgsCoordinateFormatter.formatY(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5, QgsCoordinateFormatter.FormatFlags()), "-0°0.00006′") + self.assertEqual( + QgsCoordinateFormatter.formatY( + -0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "0°0.00′", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 5, + QgsCoordinateFormatter.FormatFlags(), + ), + "0°0.00006′", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 5, + QgsCoordinateFormatter.FormatFlags(), + ), + "-0°0.00006′", + ) # test with padding - padding_and_suffix = QgsCoordinateFormatter.FormatFlags(QgsCoordinateFormatter.FormatFlag.FlagDegreesPadMinutesSeconds | QgsCoordinateFormatter.FormatFlag.FlagDegreesUseStringSuffix) - self.assertEqual(QgsCoordinateFormatter.formatY(20, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2, padding_and_suffix), "20°00.00′N") - self.assertEqual(QgsCoordinateFormatter.formatY(0, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2, padding_and_suffix), "0°00.00′") - self.assertEqual(QgsCoordinateFormatter.formatY(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2, padding_and_suffix), "0°00.00′") - self.assertEqual(QgsCoordinateFormatter.formatY(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 2, padding_and_suffix), "0°00.00′") - self.assertEqual(QgsCoordinateFormatter.formatY(-0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5, padding_and_suffix), "0°00.00006′S") - self.assertEqual(QgsCoordinateFormatter.formatY(0.000001, QgsCoordinateFormatter.Format.FormatDegreesMinutes, 5, padding_and_suffix), "0°00.00006′N") + padding_and_suffix = QgsCoordinateFormatter.FormatFlags( + QgsCoordinateFormatter.FormatFlag.FlagDegreesPadMinutesSeconds + | QgsCoordinateFormatter.FormatFlag.FlagDegreesUseStringSuffix + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 2, + padding_and_suffix, + ), + "20°00.00′N", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 2, + padding_and_suffix, + ), + "0°00.00′", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 2, + padding_and_suffix, + ), + "0°00.00′", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 2, + padding_and_suffix, + ), + "0°00.00′", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 5, + padding_and_suffix, + ), + "0°00.00006′S", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0.000001, + QgsCoordinateFormatter.Format.FormatDegreesMinutes, + 5, + padding_and_suffix, + ), + "0°00.00006′N", + ) def testFormatXDegrees(self): """Test formatting x as decimal degrees""" - self.assertEqual(QgsCoordinateFormatter.formatX(80, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "80.00°E") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 80, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "80.00°E", + ) # check precision - self.assertEqual(QgsCoordinateFormatter.formatX(80, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 4), "80.0000°E") - self.assertEqual(QgsCoordinateFormatter.formatX(80.12345678, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 4), "80.1235°E") - self.assertEqual(QgsCoordinateFormatter.formatX(80.12345678, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 0), "80°E") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 80, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 4 + ), + "80.0000°E", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 80.12345678, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 4 + ), + "80.1235°E", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 80.12345678, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 0 + ), + "80°E", + ) # check if longitudes > 180 or <-180 wrap around - self.assertEqual(QgsCoordinateFormatter.formatX(370, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "10.00°E") - self.assertEqual(QgsCoordinateFormatter.formatX(-370, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "10.00°W") - self.assertEqual(QgsCoordinateFormatter.formatX(181, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "179.00°W") - self.assertEqual(QgsCoordinateFormatter.formatX(-181, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "179.00°E") - self.assertEqual(QgsCoordinateFormatter.formatX(359, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "1.00°W") - self.assertEqual(QgsCoordinateFormatter.formatX(-359, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "1.00°E") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 370, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "10.00°E", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -370, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "10.00°W", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 181, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "179.00°W", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -181, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "179.00°E", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 359, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "1.00°W", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -359, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "1.00°E", + ) # should be no directional suffixes for 0 degree coordinates - self.assertEqual(QgsCoordinateFormatter.formatX(0, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "0.00°") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "0.00°", + ) # should also be no directional suffix for 0 degree coordinates within specified precision - self.assertEqual(QgsCoordinateFormatter.formatX(-0.00001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "0.00°") - self.assertEqual(QgsCoordinateFormatter.formatX(0.00001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "0.00°") - self.assertEqual(QgsCoordinateFormatter.formatX(-0.00001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 5), "0.00001°W") - self.assertEqual(QgsCoordinateFormatter.formatX(0.00001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 5), "0.00001°E") + self.assertEqual( + QgsCoordinateFormatter.formatX( + -0.00001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "0.00°", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0.00001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "0.00°", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -0.00001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 5 + ), + "0.00001°W", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0.00001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 5 + ), + "0.00001°E", + ) # should be no directional suffixes for 180 degree longitudes - self.assertEqual(QgsCoordinateFormatter.formatX(180, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "180.00°") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 180, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "180.00°", + ) # should also be no directional suffix for 180 degree longitudes within specified precision - self.assertEqual(QgsCoordinateFormatter.formatX(180.000001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "180.00°") - self.assertEqual(QgsCoordinateFormatter.formatX(179.999999, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "180.00°") - self.assertEqual(QgsCoordinateFormatter.formatX(180.000001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 6), "179.999999°W") - self.assertEqual(QgsCoordinateFormatter.formatX(179.999999, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 6), "179.999999°E") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 180.000001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "180.00°", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 179.999999, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "180.00°", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 180.000001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 6 + ), + "179.999999°W", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 179.999999, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 6 + ), + "179.999999°E", + ) # test without direction suffix - self.assertEqual(QgsCoordinateFormatter.formatX(80, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2, QgsCoordinateFormatter.FormatFlags()), "80.00°") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 80, + QgsCoordinateFormatter.Format.FormatDecimalDegrees, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "80.00°", + ) # test 0 longitude - self.assertEqual(QgsCoordinateFormatter.formatX(0, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2, QgsCoordinateFormatter.FormatFlags()), "0.00°") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0, + QgsCoordinateFormatter.Format.FormatDecimalDegrees, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "0.00°", + ) # test near zero longitude - self.assertEqual(QgsCoordinateFormatter.formatX(0.000001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2, QgsCoordinateFormatter.FormatFlags()), "0.00°") + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0.000001, + QgsCoordinateFormatter.Format.FormatDecimalDegrees, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "0.00°", + ) # should be no "-" prefix for near-zero longitude when rounding to 2 decimal places - self.assertEqual(QgsCoordinateFormatter.formatX(-0.000001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2, QgsCoordinateFormatter.FormatFlags()), "0.00°") - self.assertEqual(QgsCoordinateFormatter.formatX(0.000001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 6, QgsCoordinateFormatter.FormatFlags()), "0.000001°") - self.assertEqual(QgsCoordinateFormatter.formatX(-0.000001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 6, QgsCoordinateFormatter.FormatFlags()), "-0.000001°") + self.assertEqual( + QgsCoordinateFormatter.formatX( + -0.000001, + QgsCoordinateFormatter.Format.FormatDecimalDegrees, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "0.00°", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 0.000001, + QgsCoordinateFormatter.Format.FormatDecimalDegrees, + 6, + QgsCoordinateFormatter.FormatFlags(), + ), + "0.000001°", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + -0.000001, + QgsCoordinateFormatter.Format.FormatDecimalDegrees, + 6, + QgsCoordinateFormatter.FormatFlags(), + ), + "-0.000001°", + ) def testFormatYDegrees(self): """Test formatting y as decimal degrees""" - self.assertEqual(QgsCoordinateFormatter.formatY(20, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "20.00°N") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "20.00°N", + ) # check precision - self.assertEqual(QgsCoordinateFormatter.formatY(20, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 4), "20.0000°N") - self.assertEqual(QgsCoordinateFormatter.formatY(20.12345678, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 4), "20.1235°N") - self.assertEqual(QgsCoordinateFormatter.formatY(20.12345678, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 0), "20°N") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 4 + ), + "20.0000°N", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20.12345678, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 4 + ), + "20.1235°N", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20.12345678, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 0 + ), + "20°N", + ) # check if latitudes > 90 or <-90 wrap around - self.assertEqual(QgsCoordinateFormatter.formatY(190, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "10.00°N") - self.assertEqual(QgsCoordinateFormatter.formatY(-190, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "10.00°S") - self.assertEqual(QgsCoordinateFormatter.formatY(91, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "89.00°S") - self.assertEqual(QgsCoordinateFormatter.formatY(-91, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "89.00°N") - self.assertEqual(QgsCoordinateFormatter.formatY(179, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "1.00°S") - self.assertEqual(QgsCoordinateFormatter.formatY(-179, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "1.00°N") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 190, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "10.00°N", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -190, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "10.00°S", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 91, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "89.00°S", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -91, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "89.00°N", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 179, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "1.00°S", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -179, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "1.00°N", + ) # should be no directional suffixes for 0 degree coordinates - self.assertEqual(QgsCoordinateFormatter.formatY(0, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "0.00°") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "0.00°", + ) # should also be no directional suffix for 0 degree coordinates within specified precision - self.assertEqual(QgsCoordinateFormatter.formatY(-0.00001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "0.00°") - self.assertEqual(QgsCoordinateFormatter.formatY(0.00001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "0.00°") - self.assertEqual(QgsCoordinateFormatter.formatY(-0.00001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 5), "0.00001°S") - self.assertEqual(QgsCoordinateFormatter.formatY(0.00001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 5), "0.00001°N") + self.assertEqual( + QgsCoordinateFormatter.formatY( + -0.00001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "0.00°", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0.00001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "0.00°", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -0.00001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 5 + ), + "0.00001°S", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0.00001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 5 + ), + "0.00001°N", + ) # test without direction suffix - self.assertEqual(QgsCoordinateFormatter.formatY(80, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2, QgsCoordinateFormatter.FormatFlags()), "80.00°") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 80, + QgsCoordinateFormatter.Format.FormatDecimalDegrees, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "80.00°", + ) # test 0 longitude - self.assertEqual(QgsCoordinateFormatter.formatY(0, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2, QgsCoordinateFormatter.FormatFlags()), "0.00°") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0, + QgsCoordinateFormatter.Format.FormatDecimalDegrees, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "0.00°", + ) # test near zero latitude - self.assertEqual(QgsCoordinateFormatter.formatY(0.000001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2, QgsCoordinateFormatter.FormatFlags()), "0.00°") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0.000001, + QgsCoordinateFormatter.Format.FormatDecimalDegrees, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "0.00°", + ) # should be no "-" prefix for near-zero latitude when rounding to 2 decimal places - self.assertEqual(QgsCoordinateFormatter.formatY(-0.000001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2, QgsCoordinateFormatter.FormatFlags()), "0.00°") - self.assertEqual(QgsCoordinateFormatter.formatY(0.000001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 6, QgsCoordinateFormatter.FormatFlags()), "0.000001°") - self.assertEqual(QgsCoordinateFormatter.formatY(-0.000001, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 6, QgsCoordinateFormatter.FormatFlags()), "-0.000001°") + self.assertEqual( + QgsCoordinateFormatter.formatY( + -0.000001, + QgsCoordinateFormatter.Format.FormatDecimalDegrees, + 2, + QgsCoordinateFormatter.FormatFlags(), + ), + "0.00°", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + 0.000001, + QgsCoordinateFormatter.Format.FormatDecimalDegrees, + 6, + QgsCoordinateFormatter.FormatFlags(), + ), + "0.000001°", + ) + self.assertEqual( + QgsCoordinateFormatter.formatY( + -0.000001, + QgsCoordinateFormatter.Format.FormatDecimalDegrees, + 6, + QgsCoordinateFormatter.FormatFlags(), + ), + "-0.000001°", + ) def testFormatLocale(self): """Test formatting with locales that use comma as decimal separator""" QLocale.setDefault(QLocale(QLocale.Language.Italian)) - self.assertEqual(QgsCoordinateFormatter.formatY(20, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "20,00°N") - self.assertEqual(QgsCoordinateFormatter.formatX(20, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2), "20,00°E") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "20,00°N", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 20, QgsCoordinateFormatter.Format.FormatDecimalDegrees, 2 + ), + "20,00°E", + ) - self.assertEqual(QgsCoordinateFormatter.formatY(20.12345678, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 4), "20°7′24,4444″N") - self.assertEqual(QgsCoordinateFormatter.formatX(20.12345678, QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 4), "20°7′24,4444″E") + self.assertEqual( + QgsCoordinateFormatter.formatY( + 20.12345678, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 4, + ), + "20°7′24,4444″N", + ) + self.assertEqual( + QgsCoordinateFormatter.formatX( + 20.12345678, + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 4, + ), + "20°7′24,4444″E", + ) # formatting x/y as pair - self.assertEqual(QgsCoordinateFormatter.asPair(20, 30, 0), '20 30') - self.assertEqual(QgsCoordinateFormatter.asPair(20, -30, 0), '20 -30') - self.assertEqual(QgsCoordinateFormatter.asPair(20.111, 10.999, 0), '20 11') - self.assertEqual(QgsCoordinateFormatter.asPair(20.111, 10.999, 2), '20,11 11,00') - self.assertEqual(QgsCoordinateFormatter.asPair(20, 10, 2), '20,00 10,00') - self.assertEqual(QgsCoordinateFormatter.asPair(20, -10, 2), '20,00 -10,00') + self.assertEqual(QgsCoordinateFormatter.asPair(20, 30, 0), "20 30") + self.assertEqual(QgsCoordinateFormatter.asPair(20, -30, 0), "20 -30") + self.assertEqual(QgsCoordinateFormatter.asPair(20.111, 10.999, 0), "20 11") + self.assertEqual( + QgsCoordinateFormatter.asPair(20.111, 10.999, 2), "20,11 11,00" + ) + self.assertEqual(QgsCoordinateFormatter.asPair(20, 10, 2), "20,00 10,00") + self.assertEqual(QgsCoordinateFormatter.asPair(20, -10, 2), "20,00 -10,00") - self.assertEqual(QgsCoordinateFormatter.format(QgsPointXY(20.1111, 30.2111), QgsCoordinateFormatter.Format.FormatPair, 2), '20,11 30,21') - self.assertEqual(QgsCoordinateFormatter.format(QgsPointXY(20.111, 30.211), QgsCoordinateFormatter.Format.FormatPair, 2), '20,11 30,21') - self.assertEqual(QgsCoordinateFormatter.format(QgsPointXY(20.111, 30.211), QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2), '20°6′39,60″E 30°12′39,60″N') + self.assertEqual( + QgsCoordinateFormatter.format( + QgsPointXY(20.1111, 30.2111), + QgsCoordinateFormatter.Format.FormatPair, + 2, + ), + "20,11 30,21", + ) + self.assertEqual( + QgsCoordinateFormatter.format( + QgsPointXY(20.111, 30.211), QgsCoordinateFormatter.Format.FormatPair, 2 + ), + "20,11 30,21", + ) + self.assertEqual( + QgsCoordinateFormatter.format( + QgsPointXY(20.111, 30.211), + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + ), + "20°6′39,60″E 30°12′39,60″N", + ) - self.assertEqual(QgsCoordinateFormatter.format(QgsPointXY(20.1111, 30.2111), QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, 2, QgsCoordinateFormatter.FormatFlag.FlagDegreesUseStringSuffix | QgsCoordinateFormatter.FormatFlag.FlagDegreesPadMinutesSeconds), '20°06′39,96″E 30°12′39,96″N') + self.assertEqual( + QgsCoordinateFormatter.format( + QgsPointXY(20.1111, 30.2111), + QgsCoordinateFormatter.Format.FormatDegreesMinutesSeconds, + 2, + QgsCoordinateFormatter.FormatFlag.FlagDegreesUseStringSuffix + | QgsCoordinateFormatter.FormatFlag.FlagDegreesPadMinutesSeconds, + ), + "20°06′39,96″E 30°12′39,96″N", + ) def testSeparator(self): """Test X/Y separator with different locales""" - self.assertEqual(QgsCoordinateFormatter.separator(), ',') + self.assertEqual(QgsCoordinateFormatter.separator(), ",") QLocale.setDefault(QLocale(QLocale.Language.Italian)) - self.assertEqual(QgsCoordinateFormatter.separator(), ' ') + self.assertEqual(QgsCoordinateFormatter.separator(), " ") if __name__ == "__main__": diff --git a/tests/src/python/test_qgscoordinateoperationwidget.py b/tests/src/python/test_qgscoordinateoperationwidget.py index a2f37cbb5a96..9401b3c0c205 100644 --- a/tests/src/python/test_qgscoordinateoperationwidget.py +++ b/tests/src/python/test_qgscoordinateoperationwidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '19/12/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "19/12/2019" +__copyright__ = "Copyright 2019, The QGIS Project" import os @@ -30,75 +31,85 @@ class TestQgsCoordinateOperationWidget(QgisTestCase): def testGettersSetters(self): - """ test widget getters/setters """ + """test widget getters/setters""" w = QgsCoordinateOperationWidget() self.assertFalse(w.sourceCrs().isValid()) self.assertFalse(w.destinationCrs().isValid()) self.assertFalse(w.hasSelection()) self.assertFalse(w.availableOperations()) - w.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:28355')) - self.assertEqual(w.sourceCrs().authid(), 'EPSG:28355') + w.setSourceCrs(QgsCoordinateReferenceSystem("EPSG:28355")) + self.assertEqual(w.sourceCrs().authid(), "EPSG:28355") self.assertFalse(w.destinationCrs().isValid()) - w.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:7855')) - self.assertEqual(w.sourceCrs().authid(), 'EPSG:28355') - self.assertEqual(w.destinationCrs().authid(), 'EPSG:7855') + w.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:7855")) + self.assertEqual(w.sourceCrs().authid(), "EPSG:28355") + self.assertEqual(w.destinationCrs().authid(), "EPSG:7855") def testOperations(self): w = QgsCoordinateOperationWidget() self.assertFalse(w.hasSelection()) spy = QSignalSpy(w.operationChanged) - w.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:26745')) + w.setSourceCrs(QgsCoordinateReferenceSystem("EPSG:26745")) self.assertEqual(len(spy), 0) - w.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + w.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) self.assertEqual(len(spy), 1) self.assertTrue(w.hasSelection()) self.assertGreaterEqual(len(w.availableOperations()), 3) - available_operations = QgsDatumTransform.operations(w.sourceCrs(), w.destinationCrs()) + available_operations = QgsDatumTransform.operations( + w.sourceCrs(), w.destinationCrs() + ) for op in available_operations: if op.isAvailable: default_proj = op.proj break else: - self.assertTrue(False, 'No operations available') + self.assertTrue(False, "No operations available") self.assertEqual(w.defaultOperation().proj, default_proj) self.assertEqual(w.selectedOperation().proj, default_proj) self.assertTrue(w.selectedOperation().isAvailable) op = QgsCoordinateOperationWidget.OperationDetails() - op.proj = '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' + op.proj = "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84" op.allowFallback = True w.setSelectedOperation(op) - self.assertEqual(w.selectedOperation().proj, - '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84') + self.assertEqual( + w.selectedOperation().proj, + "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84", + ) self.assertTrue(w.selectedOperation().allowFallback) self.assertEqual(len(spy), 2) w.setSelectedOperation(op) - self.assertEqual(w.selectedOperation().proj, - '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84') + self.assertEqual( + w.selectedOperation().proj, + "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84", + ) self.assertTrue(w.selectedOperation().allowFallback) self.assertEqual(len(spy), 2) - op.proj = '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' + op.proj = "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84" op.allowFallback = False w.setSelectedOperation(op) - self.assertEqual(w.selectedOperation().proj, - '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84') + self.assertEqual( + w.selectedOperation().proj, + "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84", + ) self.assertFalse(w.selectedOperation().allowFallback) self.assertEqual(len(spy), 3) op.allowFallback = True w.setSelectedOperation(op) - self.assertEqual(w.selectedOperation().proj, - '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84') + self.assertEqual( + w.selectedOperation().proj, + "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84", + ) self.assertTrue(w.selectedOperation().allowFallback) self.assertEqual(len(spy), 4) context = QgsCoordinateTransformContext() - op.proj = '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' + op.proj = "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84" w.setSelectedOperation(op) w.setSelectedOperationUsingContext(context) # should go to default, because there's nothing in the context matching these crs @@ -106,71 +117,123 @@ def testOperations(self): self.assertEqual(len(spy), 6) # put something in the context - context.addCoordinateOperation(w.sourceCrs(), w.destinationCrs(), '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84') + context.addCoordinateOperation( + w.sourceCrs(), + w.destinationCrs(), + "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84", + ) w.setSelectedOperationUsingContext(context) - self.assertEqual(w.selectedOperation().proj, - '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84') + self.assertEqual( + w.selectedOperation().proj, + "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84", + ) self.assertTrue(w.selectedOperation().allowFallback) self.assertEqual(len(spy), 7) - context.addCoordinateOperation(w.sourceCrs(), w.destinationCrs(), '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84', False) + context.addCoordinateOperation( + w.sourceCrs(), + w.destinationCrs(), + "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84", + False, + ) w.setSelectedOperationUsingContext(context) - self.assertEqual(w.selectedOperation().proj, - '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84') + self.assertEqual( + w.selectedOperation().proj, + "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84", + ) self.assertFalse(w.selectedOperation().allowFallback) self.assertEqual(len(spy), 8) - @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'), 'Depends on local environment and grid presence') + @unittest.skipIf( + os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), + "Depends on local environment and grid presence", + ) def testOperationsCruftyProj(self): w = QgsCoordinateOperationWidget() self.assertFalse(w.hasSelection()) spy = QSignalSpy(w.operationChanged) - w.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:4283')) + w.setSourceCrs(QgsCoordinateReferenceSystem("EPSG:4283")) self.assertEqual(len(spy), 0) - w.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:7844')) + w.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:7844")) self.assertEqual(len(spy), 1) self.assertTrue(w.hasSelection()) self.assertEqual(len(w.availableOperations()), 2) - self.assertEqual(QgsDatumTransform.datumTransformToProj(w.defaultOperation().sourceTransformId), '+nadgrids=GDA94_GDA2020_conformal_and_distortion.gsb') + self.assertEqual( + QgsDatumTransform.datumTransformToProj( + w.defaultOperation().sourceTransformId + ), + "+nadgrids=GDA94_GDA2020_conformal_and_distortion.gsb", + ) self.assertEqual(w.defaultOperation().destinationTransformId, -1) - self.assertEqual(QgsDatumTransform.datumTransformToProj(w.selectedOperation().sourceTransformId), '+nadgrids=GDA94_GDA2020_conformal_and_distortion.gsb') + self.assertEqual( + QgsDatumTransform.datumTransformToProj( + w.selectedOperation().sourceTransformId + ), + "+nadgrids=GDA94_GDA2020_conformal_and_distortion.gsb", + ) self.assertEqual(w.selectedOperation().destinationTransformId, -1) - self.assertEqual(QgsDatumTransform.datumTransformToProj(w.availableOperations()[1].sourceTransformId), - '+nadgrids=GDA94_GDA2020_conformal.gsb') + self.assertEqual( + QgsDatumTransform.datumTransformToProj( + w.availableOperations()[1].sourceTransformId + ), + "+nadgrids=GDA94_GDA2020_conformal.gsb", + ) self.assertEqual(w.availableOperations()[1].destinationTransformId, -1) op = QgsCoordinateOperationWidget.OperationDetails() op.sourceTransformId = w.availableOperations()[1].sourceTransformId w.setSelectedOperation(op) - self.assertEqual(QgsDatumTransform.datumTransformToProj(w.selectedOperation().sourceTransformId), '+nadgrids=GDA94_GDA2020_conformal.gsb') + self.assertEqual( + QgsDatumTransform.datumTransformToProj( + w.selectedOperation().sourceTransformId + ), + "+nadgrids=GDA94_GDA2020_conformal.gsb", + ) self.assertEqual(len(spy), 2) w.setSelectedOperation(op) - self.assertEqual(QgsDatumTransform.datumTransformToProj(w.selectedOperation().sourceTransformId), '+nadgrids=GDA94_GDA2020_conformal.gsb') + self.assertEqual( + QgsDatumTransform.datumTransformToProj( + w.selectedOperation().sourceTransformId + ), + "+nadgrids=GDA94_GDA2020_conformal.gsb", + ) self.assertEqual(len(spy), 2) op.sourceTransformId = w.availableOperations()[0].sourceTransformId op.destinationTransformId = -1 w.setSelectedOperation(op) - self.assertEqual(QgsDatumTransform.datumTransformToProj(w.selectedOperation().sourceTransformId), - '+nadgrids=GDA94_GDA2020_conformal_and_distortion.gsb') + self.assertEqual( + QgsDatumTransform.datumTransformToProj( + w.selectedOperation().sourceTransformId + ), + "+nadgrids=GDA94_GDA2020_conformal_and_distortion.gsb", + ) self.assertEqual(len(spy), 3) op.destinationTransformId = w.availableOperations()[1].sourceTransformId op.sourceTransformId = -1 w.setSelectedOperation(op) - self.assertEqual(QgsDatumTransform.datumTransformToProj(w.selectedOperation().sourceTransformId), - '+nadgrids=GDA94_GDA2020_conformal.gsb') + self.assertEqual( + QgsDatumTransform.datumTransformToProj( + w.selectedOperation().sourceTransformId + ), + "+nadgrids=GDA94_GDA2020_conformal.gsb", + ) self.assertEqual(len(spy), 4) op.destinationTransformId = w.availableOperations()[0].sourceTransformId op.sourceTransformId = -1 w.setSelectedOperation(op) - self.assertEqual(QgsDatumTransform.datumTransformToProj(w.selectedOperation().sourceTransformId), - '+nadgrids=GDA94_GDA2020_conformal_and_distortion.gsb') + self.assertEqual( + QgsDatumTransform.datumTransformToProj( + w.selectedOperation().sourceTransformId + ), + "+nadgrids=GDA94_GDA2020_conformal_and_distortion.gsb", + ) self.assertEqual(len(spy), 5) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscoordinatereferencesystem.py b/tests/src/python/test_qgscoordinatereferencesystem.py index 9b9529597355..022467602e67 100644 --- a/tests/src/python/test_qgscoordinatereferencesystem.py +++ b/tests/src/python/test_qgscoordinatereferencesystem.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2022 by Nyall Dawson' -__date__ = '06/04/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "(C) 2022 by Nyall Dawson" +__date__ = "06/04/2022" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.core import Qgis, QgsCoordinateReferenceSystem @@ -26,9 +27,15 @@ def test_axis_order(self): Test QgsCoordinateReferenceSystem.axisOrdering() (including the Python MethodCode associated with this) """ self.assertEqual(QgsCoordinateReferenceSystem().axisOrdering(), []) - self.assertEqual(QgsCoordinateReferenceSystem('EPSG:4326').axisOrdering(), [Qgis.CrsAxisDirection.North, Qgis.CrsAxisDirection.East]) - self.assertEqual(QgsCoordinateReferenceSystem('EPSG:3111').axisOrdering(), [Qgis.CrsAxisDirection.East, Qgis.CrsAxisDirection.North]) + self.assertEqual( + QgsCoordinateReferenceSystem("EPSG:4326").axisOrdering(), + [Qgis.CrsAxisDirection.North, Qgis.CrsAxisDirection.East], + ) + self.assertEqual( + QgsCoordinateReferenceSystem("EPSG:3111").axisOrdering(), + [Qgis.CrsAxisDirection.East, Qgis.CrsAxisDirection.North], + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscoordinatereferencesystemmodel.py b/tests/src/python/test_qgscoordinatereferencesystemmodel.py index b89658de0792..11d9ff794ba4 100644 --- a/tests/src/python/test_qgscoordinatereferencesystemmodel.py +++ b/tests/src/python/test_qgscoordinatereferencesystemmodel.py @@ -5,15 +5,13 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2022 by Nyall Dawson' -__date__ = '12/07/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' +__author__ = "(C) 2022 by Nyall Dawson" +__date__ = "12/07/2023" +__copyright__ = "Copyright 2023, The QGIS Project" -from qgis.PyQt.QtCore import ( - Qt, - QModelIndex -) + +from qgis.PyQt.QtCore import Qt, QModelIndex from qgis.core import ( Qgis, QgsApplication, @@ -22,7 +20,7 @@ ) from qgis.gui import ( QgsCoordinateReferenceSystemModel, - QgsCoordinateReferenceSystemProxyModel + QgsCoordinateReferenceSystemProxyModel, ) import unittest @@ -39,16 +37,17 @@ def test_model(self): # Compound, Vertical amongst others self.assertGreaterEqual(model.rowCount(QModelIndex()), 5) top_level_items = [ - model.data(model.index(row, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for row in range(model.rowCount(QModelIndex())) + model.data(model.index(row, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for row in range(model.rowCount(QModelIndex())) ] - self.assertIn('Projected', top_level_items) - self.assertIn('Geographic (2D)', top_level_items) - self.assertIn('Geographic (3D)', top_level_items) - self.assertIn('Compound', top_level_items) - self.assertIn('Vertical', top_level_items) + self.assertIn("Projected", top_level_items) + self.assertIn("Geographic (2D)", top_level_items) + self.assertIn("Geographic (3D)", top_level_items) + self.assertIn("Compound", top_level_items) + self.assertIn("Vertical", top_level_items) # projection methods should not be at top level - self.assertNotIn('Cassini', top_level_items) + self.assertNotIn("Cassini", top_level_items) # user and custom groups should not be created until required self.assertNotIn("User-defined", top_level_items) @@ -56,20 +55,27 @@ def test_model(self): # check group ids top_level_item_group_ids = [ - model.data(model.index(row, 0, QModelIndex()), QgsCoordinateReferenceSystemModel.Roles.RoleGroupId) for row in range(model.rowCount(QModelIndex())) + model.data( + model.index(row, 0, QModelIndex()), + QgsCoordinateReferenceSystemModel.Roles.RoleGroupId, + ) + for row in range(model.rowCount(QModelIndex())) ] - self.assertIn('Projected', top_level_item_group_ids) - self.assertIn('Geographic2d', top_level_item_group_ids) - self.assertIn('Geographic3d', top_level_item_group_ids) - self.assertIn('Compound', top_level_item_group_ids) - self.assertIn('Vertical', top_level_item_group_ids) + self.assertIn("Projected", top_level_item_group_ids) + self.assertIn("Geographic2d", top_level_item_group_ids) + self.assertIn("Geographic3d", top_level_item_group_ids) + self.assertIn("Compound", top_level_item_group_ids) + self.assertIn("Vertical", top_level_item_group_ids) # find WGS84 in Geographic2d group geographic_2d_index = [ model.index(row, 0, QModelIndex()) for row in range(model.rowCount(QModelIndex())) - if model.data(model.index(row, 0, QModelIndex()), - QgsCoordinateReferenceSystemModel.Roles.RoleGroupId) == 'Geographic2d' + if model.data( + model.index(row, 0, QModelIndex()), + QgsCoordinateReferenceSystemModel.Roles.RoleGroupId, + ) + == "Geographic2d" ][0] # for proj 9, there's > 1300 crs in this group @@ -78,30 +84,50 @@ def test_model(self): wgs84_index = [ model.index(row, 0, geographic_2d_index) for row in range(model.rowCount(geographic_2d_index)) - if model.data(model.index(row, 0, geographic_2d_index), - QgsCoordinateReferenceSystemModel.Roles.RoleAuthId) == 'EPSG:4326' + if model.data( + model.index(row, 0, geographic_2d_index), + QgsCoordinateReferenceSystemModel.Roles.RoleAuthId, + ) + == "EPSG:4326" ][0] # test model roles - self.assertEqual(model.data(wgs84_index, Qt.ItemDataRole.DisplayRole), 'WGS 84') - self.assertEqual(model.data(model.index(wgs84_index.row(), 1, wgs84_index.parent()), Qt.ItemDataRole.DisplayRole), 'EPSG:4326') - self.assertEqual(model.data(wgs84_index, QgsCoordinateReferenceSystemModel.Roles.RoleName), 'WGS 84') - self.assertFalse(model.data(wgs84_index, - QgsCoordinateReferenceSystemModel.Roles.RoleDeprecated)) + self.assertEqual(model.data(wgs84_index, Qt.ItemDataRole.DisplayRole), "WGS 84") + self.assertEqual( + model.data( + model.index(wgs84_index.row(), 1, wgs84_index.parent()), + Qt.ItemDataRole.DisplayRole, + ), + "EPSG:4326", + ) + self.assertEqual( + model.data(wgs84_index, QgsCoordinateReferenceSystemModel.Roles.RoleName), + "WGS 84", + ) + self.assertFalse( + model.data( + wgs84_index, QgsCoordinateReferenceSystemModel.Roles.RoleDeprecated + ) + ) # the proj and wkt roles are only available for non-standard CRS - self.assertFalse(model.data(wgs84_index, - QgsCoordinateReferenceSystemModel.Roles.RoleWkt)) - self.assertFalse(model.data(wgs84_index, - QgsCoordinateReferenceSystemModel.Roles.RoleProj)) + self.assertFalse( + model.data(wgs84_index, QgsCoordinateReferenceSystemModel.Roles.RoleWkt) + ) + self.assertFalse( + model.data(wgs84_index, QgsCoordinateReferenceSystemModel.Roles.RoleProj) + ) # check that same result is returned by authIdToIndex - self.assertEqual(model.authIdToIndex('EPSG:4326'), wgs84_index) + self.assertEqual(model.authIdToIndex("EPSG:4326"), wgs84_index) # find EPSG:4329 in Geographic3d group (also tests a deprecated CRS) geographic_3d_index = [ model.index(row, 0, QModelIndex()) for row in range(model.rowCount(QModelIndex())) - if model.data(model.index(row, 0, QModelIndex()), - QgsCoordinateReferenceSystemModel.Roles.RoleGroupId) == 'Geographic3d' + if model.data( + model.index(row, 0, QModelIndex()), + QgsCoordinateReferenceSystemModel.Roles.RoleGroupId, + ) + == "Geographic3d" ][0] # for proj 9, there's > 200 crs in this group @@ -110,34 +136,56 @@ def test_model(self): epsg_4329_index = [ model.index(row, 0, geographic_3d_index) for row in range(model.rowCount(geographic_3d_index)) - if model.data(model.index(row, 0, geographic_3d_index), - QgsCoordinateReferenceSystemModel.Roles.RoleAuthId) == 'EPSG:4329' + if model.data( + model.index(row, 0, geographic_3d_index), + QgsCoordinateReferenceSystemModel.Roles.RoleAuthId, + ) + == "EPSG:4329" ][0] # test model roles - self.assertEqual(model.data(epsg_4329_index, Qt.ItemDataRole.DisplayRole), 'WGS 84 (3D)') self.assertEqual( - model.data(model.index(epsg_4329_index.row(), 1, epsg_4329_index.parent()), - Qt.ItemDataRole.DisplayRole), 'EPSG:4329') - self.assertEqual(model.data(epsg_4329_index, - QgsCoordinateReferenceSystemModel.Roles.RoleName), - 'WGS 84 (3D)') - self.assertTrue(model.data(epsg_4329_index, - QgsCoordinateReferenceSystemModel.Roles.RoleDeprecated)) + model.data(epsg_4329_index, Qt.ItemDataRole.DisplayRole), "WGS 84 (3D)" + ) + self.assertEqual( + model.data( + model.index(epsg_4329_index.row(), 1, epsg_4329_index.parent()), + Qt.ItemDataRole.DisplayRole, + ), + "EPSG:4329", + ) + self.assertEqual( + model.data( + epsg_4329_index, QgsCoordinateReferenceSystemModel.Roles.RoleName + ), + "WGS 84 (3D)", + ) + self.assertTrue( + model.data( + epsg_4329_index, QgsCoordinateReferenceSystemModel.Roles.RoleDeprecated + ) + ) # the proj and wkt roles are only available for non-standard CRS - self.assertFalse(model.data(epsg_4329_index, - QgsCoordinateReferenceSystemModel.Roles.RoleWkt)) - self.assertFalse(model.data(epsg_4329_index, - QgsCoordinateReferenceSystemModel.Roles.RoleProj)) + self.assertFalse( + model.data(epsg_4329_index, QgsCoordinateReferenceSystemModel.Roles.RoleWkt) + ) + self.assertFalse( + model.data( + epsg_4329_index, QgsCoordinateReferenceSystemModel.Roles.RoleProj + ) + ) # check that same result is returned by authIdToIndex - self.assertEqual(model.authIdToIndex('EPSG:4329'), epsg_4329_index) + self.assertEqual(model.authIdToIndex("EPSG:4329"), epsg_4329_index) # find a vertical crs vertical_index = [ model.index(row, 0, QModelIndex()) for row in range(model.rowCount(QModelIndex())) - if model.data(model.index(row, 0, QModelIndex()), - QgsCoordinateReferenceSystemModel.Roles.RoleGroupId) == 'Vertical' + if model.data( + model.index(row, 0, QModelIndex()), + QgsCoordinateReferenceSystemModel.Roles.RoleGroupId, + ) + == "Vertical" ][0] # for proj 9, there's > 400 crs in this group @@ -146,34 +194,52 @@ def test_model(self): ahd_index = [ model.index(row, 0, vertical_index) for row in range(model.rowCount(vertical_index)) - if model.data(model.index(row, 0, vertical_index), - QgsCoordinateReferenceSystemModel.Roles.RoleAuthId) == 'EPSG:5711' + if model.data( + model.index(row, 0, vertical_index), + QgsCoordinateReferenceSystemModel.Roles.RoleAuthId, + ) + == "EPSG:5711" ][0] # test model roles - self.assertEqual(model.data(ahd_index, Qt.ItemDataRole.DisplayRole), 'AHD height') self.assertEqual( - model.data(model.index(ahd_index.row(), 1, ahd_index.parent()), - Qt.ItemDataRole.DisplayRole), 'EPSG:5711') - self.assertEqual(model.data(ahd_index, - QgsCoordinateReferenceSystemModel.Roles.RoleName), - 'AHD height') - self.assertFalse(model.data(ahd_index, - QgsCoordinateReferenceSystemModel.Roles.RoleDeprecated)) + model.data(ahd_index, Qt.ItemDataRole.DisplayRole), "AHD height" + ) + self.assertEqual( + model.data( + model.index(ahd_index.row(), 1, ahd_index.parent()), + Qt.ItemDataRole.DisplayRole, + ), + "EPSG:5711", + ) + self.assertEqual( + model.data(ahd_index, QgsCoordinateReferenceSystemModel.Roles.RoleName), + "AHD height", + ) + self.assertFalse( + model.data( + ahd_index, QgsCoordinateReferenceSystemModel.Roles.RoleDeprecated + ) + ) # the proj and wkt roles are only available for non-standard CRS - self.assertFalse(model.data(ahd_index, - QgsCoordinateReferenceSystemModel.Roles.RoleWkt)) - self.assertFalse(model.data(ahd_index, - QgsCoordinateReferenceSystemModel.Roles.RoleProj)) + self.assertFalse( + model.data(ahd_index, QgsCoordinateReferenceSystemModel.Roles.RoleWkt) + ) + self.assertFalse( + model.data(ahd_index, QgsCoordinateReferenceSystemModel.Roles.RoleProj) + ) # check that same result is returned by authIdToIndex - self.assertEqual(model.authIdToIndex('EPSG:5711'), ahd_index) + self.assertEqual(model.authIdToIndex("EPSG:5711"), ahd_index) # check projected group projected_index = [ model.index(row, 0, QModelIndex()) for row in range(model.rowCount(QModelIndex())) - if model.data(model.index(row, 0, QModelIndex()), - QgsCoordinateReferenceSystemModel.Roles.RoleGroupId) == 'Projected' + if model.data( + model.index(row, 0, QModelIndex()), + QgsCoordinateReferenceSystemModel.Roles.RoleGroupId, + ) + == "Projected" ][0] # for proj 9, there's > 50 projection methods in this group self.assertGreaterEqual(model.rowCount(projected_index), 50) @@ -182,8 +248,11 @@ def test_model(self): aea_group_index = [ model.index(row, 0, projected_index) for row in range(model.rowCount(projected_index)) - if model.data(model.index(row, 0, projected_index), - QgsCoordinateReferenceSystemModel.Roles.RoleGroupId) == 'aea' + if model.data( + model.index(row, 0, projected_index), + QgsCoordinateReferenceSystemModel.Roles.RoleGroupId, + ) + == "aea" ][0] # for proj 9, there's > 100 crs in this group self.assertGreaterEqual(model.rowCount(aea_group_index), 100) @@ -192,104 +261,180 @@ def test_model(self): epsg_3577_index = [ model.index(row, 0, aea_group_index) for row in range(model.rowCount(aea_group_index)) - if model.data(model.index(row, 0, aea_group_index), - QgsCoordinateReferenceSystemModel.Roles.RoleAuthId) == 'EPSG:3577' + if model.data( + model.index(row, 0, aea_group_index), + QgsCoordinateReferenceSystemModel.Roles.RoleAuthId, + ) + == "EPSG:3577" ][0] # test model roles - self.assertEqual(model.data(epsg_3577_index, Qt.ItemDataRole.DisplayRole), 'GDA94 / Australian Albers') self.assertEqual( - model.data(model.index(epsg_3577_index.row(), 1, epsg_3577_index.parent()), - Qt.ItemDataRole.DisplayRole), 'EPSG:3577') - self.assertEqual(model.data(epsg_3577_index, - QgsCoordinateReferenceSystemModel.Roles.RoleName), - 'GDA94 / Australian Albers') - self.assertFalse(model.data(epsg_3577_index, - QgsCoordinateReferenceSystemModel.Roles.RoleDeprecated)) + model.data(epsg_3577_index, Qt.ItemDataRole.DisplayRole), + "GDA94 / Australian Albers", + ) + self.assertEqual( + model.data( + model.index(epsg_3577_index.row(), 1, epsg_3577_index.parent()), + Qt.ItemDataRole.DisplayRole, + ), + "EPSG:3577", + ) + self.assertEqual( + model.data( + epsg_3577_index, QgsCoordinateReferenceSystemModel.Roles.RoleName + ), + "GDA94 / Australian Albers", + ) + self.assertFalse( + model.data( + epsg_3577_index, QgsCoordinateReferenceSystemModel.Roles.RoleDeprecated + ) + ) # the proj and wkt roles are only available for non-standard CRS - self.assertFalse(model.data(epsg_3577_index, - QgsCoordinateReferenceSystemModel.Roles.RoleWkt)) - self.assertFalse(model.data(epsg_3577_index, - QgsCoordinateReferenceSystemModel.Roles.RoleProj)) + self.assertFalse( + model.data(epsg_3577_index, QgsCoordinateReferenceSystemModel.Roles.RoleWkt) + ) + self.assertFalse( + model.data( + epsg_3577_index, QgsCoordinateReferenceSystemModel.Roles.RoleProj + ) + ) # check that same result is returned by authIdToIndex - self.assertEqual(model.authIdToIndex('EPSG:3577'), epsg_3577_index) + self.assertEqual(model.authIdToIndex("EPSG:3577"), epsg_3577_index) # now add a custom crs and ensure it appears in the model prev_top_level_count = model.rowCount(QModelIndex()) registry = QgsApplication.coordinateReferenceSystemRegistry() - crs = QgsCoordinateReferenceSystem.fromProj("+proj=aea +lat_1=20 +lat_2=-23 +lat_0=4 +lon_0=29 +x_0=10 +y_0=3 +datum=WGS84 +units=m +no_defs") - res = registry.addUserCrs(crs, 'my custom crs') + crs = QgsCoordinateReferenceSystem.fromProj( + "+proj=aea +lat_1=20 +lat_2=-23 +lat_0=4 +lon_0=29 +x_0=10 +y_0=3 +datum=WGS84 +units=m +no_defs" + ) + res = registry.addUserCrs(crs, "my custom crs") self.assertEqual(res, 100000) self.assertEqual(model.rowCount(QModelIndex()), prev_top_level_count + 1) top_level_items = [ - model.data(model.index(row, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for row in range(model.rowCount(QModelIndex())) + model.data(model.index(row, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for row in range(model.rowCount(QModelIndex())) ] - self.assertIn('User-defined', top_level_items) + self.assertIn("User-defined", top_level_items) self.assertNotIn("Custom", top_level_items) # check group ids top_level_item_group_ids = [ - model.data(model.index(row, 0, QModelIndex()), QgsCoordinateReferenceSystemModel.Roles.RoleGroupId) for row in range(model.rowCount(QModelIndex())) + model.data( + model.index(row, 0, QModelIndex()), + QgsCoordinateReferenceSystemModel.Roles.RoleGroupId, + ) + for row in range(model.rowCount(QModelIndex())) ] - self.assertIn('USER', top_level_item_group_ids) + self.assertIn("USER", top_level_item_group_ids) # find user crs user_index = [ model.index(row, 0, QModelIndex()) for row in range(model.rowCount(QModelIndex())) - if model.data(model.index(row, 0, QModelIndex()), - QgsCoordinateReferenceSystemModel.Roles.RoleGroupId) == 'USER' + if model.data( + model.index(row, 0, QModelIndex()), + QgsCoordinateReferenceSystemModel.Roles.RoleGroupId, + ) + == "USER" ][0] self.assertEqual(model.rowCount(user_index), 1) user_crs_index = model.index(0, 0, user_index) # test model roles - self.assertEqual(model.data(user_crs_index, Qt.ItemDataRole.DisplayRole), 'my custom crs') self.assertEqual( - model.data(model.index(user_crs_index.row(), 1, user_crs_index.parent()), - Qt.ItemDataRole.DisplayRole), 'USER:100000') - self.assertEqual(model.data(user_crs_index, - QgsCoordinateReferenceSystemModel.Roles.RoleName), - 'my custom crs') - self.assertFalse(model.data(user_crs_index, - QgsCoordinateReferenceSystemModel.Roles.RoleDeprecated)) + model.data(user_crs_index, Qt.ItemDataRole.DisplayRole), "my custom crs" + ) + self.assertEqual( + model.data( + model.index(user_crs_index.row(), 1, user_crs_index.parent()), + Qt.ItemDataRole.DisplayRole, + ), + "USER:100000", + ) + self.assertEqual( + model.data( + user_crs_index, QgsCoordinateReferenceSystemModel.Roles.RoleName + ), + "my custom crs", + ) + self.assertFalse( + model.data( + user_crs_index, QgsCoordinateReferenceSystemModel.Roles.RoleDeprecated + ) + ) # the proj and wkt roles are only available for non-standard CRS - self.assertEqual(model.data(user_crs_index, - QgsCoordinateReferenceSystemModel.Roles.RoleWkt)[:8], 'PROJCRS[') - self.assertEqual(model.data(user_crs_index, - QgsCoordinateReferenceSystemModel.Roles.RoleProj), "+proj=aea +lat_1=20 +lat_2=-23 +lat_0=4 +lon_0=29 +x_0=10 +y_0=3 +datum=WGS84 +units=m +no_defs") + self.assertEqual( + model.data(user_crs_index, QgsCoordinateReferenceSystemModel.Roles.RoleWkt)[ + :8 + ], + "PROJCRS[", + ) + self.assertEqual( + model.data( + user_crs_index, QgsCoordinateReferenceSystemModel.Roles.RoleProj + ), + "+proj=aea +lat_1=20 +lat_2=-23 +lat_0=4 +lon_0=29 +x_0=10 +y_0=3 +datum=WGS84 +units=m +no_defs", + ) # check that same result is returned by authIdToIndex - self.assertEqual(model.authIdToIndex('USER:100000'), user_crs_index) + self.assertEqual(model.authIdToIndex("USER:100000"), user_crs_index) # modify user crs - crs = QgsCoordinateReferenceSystem.fromProj("+proj=aea +lat_1=21 +lat_2=-23 +lat_0=4 +lon_0=29 +x_0=10 +y_0=3 +datum=WGS84 +units=m +no_defs") - self.assertTrue(registry.updateUserCrs(100000, crs, 'my custom crs rev 2')) + crs = QgsCoordinateReferenceSystem.fromProj( + "+proj=aea +lat_1=21 +lat_2=-23 +lat_0=4 +lon_0=29 +x_0=10 +y_0=3 +datum=WGS84 +units=m +no_defs" + ) + self.assertTrue(registry.updateUserCrs(100000, crs, "my custom crs rev 2")) user_index = [ model.index(row, 0, QModelIndex()) for row in range(model.rowCount(QModelIndex())) - if model.data(model.index(row, 0, QModelIndex()), - QgsCoordinateReferenceSystemModel.Roles.RoleGroupId) == 'USER' + if model.data( + model.index(row, 0, QModelIndex()), + QgsCoordinateReferenceSystemModel.Roles.RoleGroupId, + ) + == "USER" ][0] self.assertEqual(model.rowCount(user_index), 1) user_crs_index = model.index(0, 0, user_index) # test model roles - self.assertEqual(model.data(user_crs_index, Qt.ItemDataRole.DisplayRole), 'my custom crs rev 2') self.assertEqual( - model.data(model.index(user_crs_index.row(), 1, user_crs_index.parent()), - Qt.ItemDataRole.DisplayRole), 'USER:100000') - self.assertEqual(model.data(user_crs_index, - QgsCoordinateReferenceSystemModel.Roles.RoleName), - 'my custom crs rev 2') - self.assertFalse(model.data(user_crs_index, - QgsCoordinateReferenceSystemModel.Roles.RoleDeprecated)) + model.data(user_crs_index, Qt.ItemDataRole.DisplayRole), + "my custom crs rev 2", + ) + self.assertEqual( + model.data( + model.index(user_crs_index.row(), 1, user_crs_index.parent()), + Qt.ItemDataRole.DisplayRole, + ), + "USER:100000", + ) + self.assertEqual( + model.data( + user_crs_index, QgsCoordinateReferenceSystemModel.Roles.RoleName + ), + "my custom crs rev 2", + ) + self.assertFalse( + model.data( + user_crs_index, QgsCoordinateReferenceSystemModel.Roles.RoleDeprecated + ) + ) # the proj and wkt roles are only available for non-standard CRS - self.assertEqual(model.data(user_crs_index, - QgsCoordinateReferenceSystemModel.Roles.RoleWkt)[:8], 'PROJCRS[') - self.assertEqual(model.data(user_crs_index, - QgsCoordinateReferenceSystemModel.Roles.RoleProj), "+proj=aea +lat_1=21 +lat_2=-23 +lat_0=4 +lon_0=29 +x_0=10 +y_0=3 +datum=WGS84 +units=m +no_defs") + self.assertEqual( + model.data(user_crs_index, QgsCoordinateReferenceSystemModel.Roles.RoleWkt)[ + :8 + ], + "PROJCRS[", + ) + self.assertEqual( + model.data( + user_crs_index, QgsCoordinateReferenceSystemModel.Roles.RoleProj + ), + "+proj=aea +lat_1=21 +lat_2=-23 +lat_0=4 +lon_0=29 +x_0=10 +y_0=3 +datum=WGS84 +units=m +no_defs", + ) # remove registry.removeUserCrs(100000) @@ -298,45 +443,77 @@ def test_model(self): # add a non-standard crs (does not correspond to any db entry) prev_top_level_count = model.rowCount(QModelIndex()) crs = QgsCoordinateReferenceSystem.fromProj( - "+proj=aea +lat_1=1.5 +lat_2=-23 +lat_0=4 +lon_0=29 +x_0=10 +y_0=3 +datum=WGS84 +units=m +no_defs") + "+proj=aea +lat_1=1.5 +lat_2=-23 +lat_0=4 +lon_0=29 +x_0=10 +y_0=3 +datum=WGS84 +units=m +no_defs" + ) model.addCustomCrs(crs) self.assertEqual(model.rowCount(QModelIndex()), prev_top_level_count + 1) top_level_items = [ - model.data(model.index(row, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for row in range(model.rowCount(QModelIndex())) + model.data(model.index(row, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for row in range(model.rowCount(QModelIndex())) ] self.assertIn("Custom", top_level_items) # check group ids top_level_item_group_ids = [ - model.data(model.index(row, 0, QModelIndex()), QgsCoordinateReferenceSystemModel.Roles.RoleGroupId) for row in range(model.rowCount(QModelIndex())) + model.data( + model.index(row, 0, QModelIndex()), + QgsCoordinateReferenceSystemModel.Roles.RoleGroupId, + ) + for row in range(model.rowCount(QModelIndex())) ] - self.assertIn('CUSTOM', top_level_item_group_ids) + self.assertIn("CUSTOM", top_level_item_group_ids) custom_index = [ model.index(row, 0, QModelIndex()) for row in range(model.rowCount(QModelIndex())) - if model.data(model.index(row, 0, QModelIndex()), - QgsCoordinateReferenceSystemModel.Roles.RoleGroupId) == 'CUSTOM' + if model.data( + model.index(row, 0, QModelIndex()), + QgsCoordinateReferenceSystemModel.Roles.RoleGroupId, + ) + == "CUSTOM" ][0] self.assertEqual(model.rowCount(custom_index), 1) custom_crs_index = model.index(0, 0, custom_index) # test model roles - self.assertEqual(model.data(custom_crs_index, Qt.ItemDataRole.DisplayRole), 'Custom CRS') + self.assertEqual( + model.data(custom_crs_index, Qt.ItemDataRole.DisplayRole), "Custom CRS" + ) + self.assertFalse( + model.data( + model.index(custom_crs_index.row(), 1, custom_crs_index.parent()), + Qt.ItemDataRole.DisplayRole, + ) + ) + self.assertEqual( + model.data( + custom_crs_index, QgsCoordinateReferenceSystemModel.Roles.RoleName + ), + "Custom CRS", + ) + self.assertFalse( + model.data( + custom_crs_index, QgsCoordinateReferenceSystemModel.Roles.RoleAuthId + ) + ) self.assertFalse( - model.data(model.index(custom_crs_index.row(), 1, custom_crs_index.parent()), - Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(custom_crs_index, - QgsCoordinateReferenceSystemModel.Roles.RoleName), 'Custom CRS') - self.assertFalse(model.data(custom_crs_index, - QgsCoordinateReferenceSystemModel.Roles.RoleAuthId)) - self.assertFalse(model.data(custom_crs_index, - QgsCoordinateReferenceSystemModel.Roles.RoleDeprecated)) + model.data( + custom_crs_index, QgsCoordinateReferenceSystemModel.Roles.RoleDeprecated + ) + ) # the proj and wkt roles are only available for non-standard CRS - self.assertEqual(model.data(custom_crs_index, - QgsCoordinateReferenceSystemModel.Roles.RoleWkt)[:8], 'PROJCRS[') - self.assertEqual(model.data(custom_crs_index, - QgsCoordinateReferenceSystemModel.Roles.RoleProj), "+proj=aea +lat_1=1.5 +lat_2=-23 +lat_0=4 +lon_0=29 +x_0=10 +y_0=3 +datum=WGS84 +units=m +no_defs") + self.assertEqual( + model.data( + custom_crs_index, QgsCoordinateReferenceSystemModel.Roles.RoleWkt + )[:8], + "PROJCRS[", + ) + self.assertEqual( + model.data( + custom_crs_index, QgsCoordinateReferenceSystemModel.Roles.RoleProj + ), + "+proj=aea +lat_1=1.5 +lat_2=-23 +lat_0=4 +lon_0=29 +x_0=10 +y_0=3 +datum=WGS84 +units=m +no_defs", + ) def test_proxy_model(self): model = QgsCoordinateReferenceSystemProxyModel() @@ -344,59 +521,64 @@ def test_proxy_model(self): # Compound, Vertical amongst others self.assertGreaterEqual(model.rowCount(QModelIndex()), 5) top_level_items = [ - model.data(model.index(row, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for row in range(model.rowCount(QModelIndex())) + model.data(model.index(row, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for row in range(model.rowCount(QModelIndex())) ] - self.assertIn('Projected', top_level_items) - self.assertIn('Geographic (2D)', top_level_items) - self.assertIn('Geographic (3D)', top_level_items) - self.assertIn('Compound', top_level_items) - self.assertIn('Vertical', top_level_items) + self.assertIn("Projected", top_level_items) + self.assertIn("Geographic (2D)", top_level_items) + self.assertIn("Geographic (3D)", top_level_items) + self.assertIn("Compound", top_level_items) + self.assertIn("Vertical", top_level_items) # filter by type model.setFilters(QgsCoordinateReferenceSystemProxyModel.Filter.FilterHorizontal) top_level_items = [ - model.data(model.index(row, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for - row in range(model.rowCount(QModelIndex())) + model.data(model.index(row, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for row in range(model.rowCount(QModelIndex())) ] - self.assertIn('Projected', top_level_items) - self.assertIn('Geographic (2D)', top_level_items) - self.assertIn('Geographic (3D)', top_level_items) - self.assertNotIn('Compound', top_level_items) - self.assertNotIn('Vertical', top_level_items) + self.assertIn("Projected", top_level_items) + self.assertIn("Geographic (2D)", top_level_items) + self.assertIn("Geographic (3D)", top_level_items) + self.assertNotIn("Compound", top_level_items) + self.assertNotIn("Vertical", top_level_items) model.setFilters(QgsCoordinateReferenceSystemProxyModel.Filter.FilterVertical) top_level_items = [ - model.data(model.index(row, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for - row in range(model.rowCount(QModelIndex())) + model.data(model.index(row, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for row in range(model.rowCount(QModelIndex())) ] - self.assertNotIn('Projected', top_level_items) - self.assertNotIn('Geographic (2D)', top_level_items) - self.assertNotIn('Geographic (3D)', top_level_items) - self.assertNotIn('Compound', top_level_items) - self.assertIn('Vertical', top_level_items) + self.assertNotIn("Projected", top_level_items) + self.assertNotIn("Geographic (2D)", top_level_items) + self.assertNotIn("Geographic (3D)", top_level_items) + self.assertNotIn("Compound", top_level_items) + self.assertIn("Vertical", top_level_items) model.setFilters(QgsCoordinateReferenceSystemProxyModel.Filter.FilterCompound) top_level_items = [ - model.data(model.index(row, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for - row in range(model.rowCount(QModelIndex())) + model.data(model.index(row, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for row in range(model.rowCount(QModelIndex())) ] - self.assertNotIn('Projected', top_level_items) - self.assertNotIn('Geographic (2D)', top_level_items) - self.assertNotIn('Geographic (3D)', top_level_items) - self.assertIn('Compound', top_level_items) - self.assertNotIn('Vertical', top_level_items) - - model.setFilters(QgsCoordinateReferenceSystemProxyModel.Filters(QgsCoordinateReferenceSystemProxyModel.Filter.FilterCompound - | QgsCoordinateReferenceSystemProxyModel.Filter.FilterVertical)) + self.assertNotIn("Projected", top_level_items) + self.assertNotIn("Geographic (2D)", top_level_items) + self.assertNotIn("Geographic (3D)", top_level_items) + self.assertIn("Compound", top_level_items) + self.assertNotIn("Vertical", top_level_items) + + model.setFilters( + QgsCoordinateReferenceSystemProxyModel.Filters( + QgsCoordinateReferenceSystemProxyModel.Filter.FilterCompound + | QgsCoordinateReferenceSystemProxyModel.Filter.FilterVertical + ) + ) top_level_items = [ - model.data(model.index(row, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for - row in range(model.rowCount(QModelIndex())) + model.data(model.index(row, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for row in range(model.rowCount(QModelIndex())) ] - self.assertNotIn('Projected', top_level_items) - self.assertNotIn('Geographic (2D)', top_level_items) - self.assertNotIn('Geographic (3D)', top_level_items) - self.assertIn('Compound', top_level_items) - self.assertIn('Vertical', top_level_items) + self.assertNotIn("Projected", top_level_items) + self.assertNotIn("Geographic (2D)", top_level_items) + self.assertNotIn("Geographic (3D)", top_level_items) + self.assertIn("Compound", top_level_items) + self.assertIn("Vertical", top_level_items) model.setFilters(QgsCoordinateReferenceSystemProxyModel.Filters()) @@ -404,146 +586,230 @@ def test_proxy_model(self): geographic_2d_index = [ model.index(row, 0, QModelIndex()) for row in range(model.rowCount(QModelIndex())) - if model.data(model.index(row, 0, QModelIndex()), - QgsCoordinateReferenceSystemModel.Roles.RoleGroupId) == 'Geographic2d' + if model.data( + model.index(row, 0, QModelIndex()), + QgsCoordinateReferenceSystemModel.Roles.RoleGroupId, + ) + == "Geographic2d" ][0] wgs84_index = [ model.index(row, 0, geographic_2d_index) for row in range(model.rowCount(geographic_2d_index)) - if model.data(model.index(row, 0, geographic_2d_index), - QgsCoordinateReferenceSystemModel.Roles.RoleAuthId) == 'EPSG:4326' + if model.data( + model.index(row, 0, geographic_2d_index), + QgsCoordinateReferenceSystemModel.Roles.RoleAuthId, + ) + == "EPSG:4326" ][0] # test model roles - self.assertEqual(model.data(wgs84_index, Qt.ItemDataRole.DisplayRole), 'WGS 84') - self.assertEqual(model.data(model.index(wgs84_index.row(), 1, wgs84_index.parent()), Qt.ItemDataRole.DisplayRole), 'EPSG:4326') - self.assertEqual(model.data(wgs84_index, QgsCoordinateReferenceSystemModel.Roles.RoleName), 'WGS 84') - self.assertFalse(model.data(wgs84_index, - QgsCoordinateReferenceSystemModel.Roles.RoleDeprecated)) + self.assertEqual(model.data(wgs84_index, Qt.ItemDataRole.DisplayRole), "WGS 84") + self.assertEqual( + model.data( + model.index(wgs84_index.row(), 1, wgs84_index.parent()), + Qt.ItemDataRole.DisplayRole, + ), + "EPSG:4326", + ) + self.assertEqual( + model.data(wgs84_index, QgsCoordinateReferenceSystemModel.Roles.RoleName), + "WGS 84", + ) + self.assertFalse( + model.data( + wgs84_index, QgsCoordinateReferenceSystemModel.Roles.RoleDeprecated + ) + ) # the proj and wkt roles are only available for non-standard CRS - self.assertFalse(model.data(wgs84_index, - QgsCoordinateReferenceSystemModel.Roles.RoleWkt)) - self.assertFalse(model.data(wgs84_index, - QgsCoordinateReferenceSystemModel.Roles.RoleProj)) + self.assertFalse( + model.data(wgs84_index, QgsCoordinateReferenceSystemModel.Roles.RoleWkt) + ) + self.assertFalse( + model.data(wgs84_index, QgsCoordinateReferenceSystemModel.Roles.RoleProj) + ) # find EPSG:4329 in Geographic3d group (also tests a deprecated CRS) geographic_3d_index = [ model.index(row, 0, QModelIndex()) for row in range(model.rowCount(QModelIndex())) - if model.data(model.index(row, 0, QModelIndex()), - QgsCoordinateReferenceSystemModel.Roles.RoleGroupId) == 'Geographic3d' + if model.data( + model.index(row, 0, QModelIndex()), + QgsCoordinateReferenceSystemModel.Roles.RoleGroupId, + ) + == "Geographic3d" ][0] epsg_4329_index = [ model.index(row, 0, geographic_3d_index) for row in range(model.rowCount(geographic_3d_index)) - if model.data(model.index(row, 0, geographic_3d_index), - QgsCoordinateReferenceSystemModel.Roles.RoleAuthId) == 'EPSG:4329' + if model.data( + model.index(row, 0, geographic_3d_index), + QgsCoordinateReferenceSystemModel.Roles.RoleAuthId, + ) + == "EPSG:4329" ][0] # test model roles - self.assertEqual(model.data(epsg_4329_index, Qt.ItemDataRole.DisplayRole), 'WGS 84 (3D)') self.assertEqual( - model.data(model.index(epsg_4329_index.row(), 1, epsg_4329_index.parent()), - Qt.ItemDataRole.DisplayRole), 'EPSG:4329') - self.assertEqual(model.data(epsg_4329_index, - QgsCoordinateReferenceSystemModel.Roles.RoleName), - 'WGS 84 (3D)') - self.assertTrue(model.data(epsg_4329_index, - QgsCoordinateReferenceSystemModel.Roles.RoleDeprecated)) + model.data(epsg_4329_index, Qt.ItemDataRole.DisplayRole), "WGS 84 (3D)" + ) + self.assertEqual( + model.data( + model.index(epsg_4329_index.row(), 1, epsg_4329_index.parent()), + Qt.ItemDataRole.DisplayRole, + ), + "EPSG:4329", + ) + self.assertEqual( + model.data( + epsg_4329_index, QgsCoordinateReferenceSystemModel.Roles.RoleName + ), + "WGS 84 (3D)", + ) + self.assertTrue( + model.data( + epsg_4329_index, QgsCoordinateReferenceSystemModel.Roles.RoleDeprecated + ) + ) # the proj and wkt roles are only available for non-standard CRS - self.assertFalse(model.data(epsg_4329_index, - QgsCoordinateReferenceSystemModel.Roles.RoleWkt)) - self.assertFalse(model.data(epsg_4329_index, - QgsCoordinateReferenceSystemModel.Roles.RoleProj)) + self.assertFalse( + model.data(epsg_4329_index, QgsCoordinateReferenceSystemModel.Roles.RoleWkt) + ) + self.assertFalse( + model.data( + epsg_4329_index, QgsCoordinateReferenceSystemModel.Roles.RoleProj + ) + ) model.setFilterDeprecated(True) geographic_3d_index = [ model.index(row, 0, QModelIndex()) for row in range(model.rowCount(QModelIndex())) - if model.data(model.index(row, 0, QModelIndex()), - QgsCoordinateReferenceSystemModel.Roles.RoleGroupId) == 'Geographic3d' + if model.data( + model.index(row, 0, QModelIndex()), + QgsCoordinateReferenceSystemModel.Roles.RoleGroupId, + ) + == "Geographic3d" ][0] - self.assertFalse([ - model.index(row, 0, geographic_3d_index) - for row in range(model.rowCount(geographic_3d_index)) - if model.data(model.index(row, 0, geographic_3d_index), - QgsCoordinateReferenceSystemModel.Roles.RoleAuthId) == 'EPSG:4329' - ]) + self.assertFalse( + [ + model.index(row, 0, geographic_3d_index) + for row in range(model.rowCount(geographic_3d_index)) + if model.data( + model.index(row, 0, geographic_3d_index), + QgsCoordinateReferenceSystemModel.Roles.RoleAuthId, + ) + == "EPSG:4329" + ] + ) model.setFilterDeprecated(False) geographic_3d_index = [ model.index(row, 0, QModelIndex()) for row in range(model.rowCount(QModelIndex())) - if model.data(model.index(row, 0, QModelIndex()), - QgsCoordinateReferenceSystemModel.Roles.RoleGroupId) == 'Geographic3d' + if model.data( + model.index(row, 0, QModelIndex()), + QgsCoordinateReferenceSystemModel.Roles.RoleGroupId, + ) + == "Geographic3d" ][0] epsg_4329_index = [ model.index(row, 0, geographic_3d_index) for row in range(model.rowCount(geographic_3d_index)) - if model.data(model.index(row, 0, geographic_3d_index), - QgsCoordinateReferenceSystemModel.Roles.RoleAuthId) == 'EPSG:4329' + if model.data( + model.index(row, 0, geographic_3d_index), + QgsCoordinateReferenceSystemModel.Roles.RoleAuthId, + ) + == "EPSG:4329" ][0] self.assertTrue(epsg_4329_index.isValid()) # filter by string - model.setFilterString('GDA94') + model.setFilterString("GDA94") geographic_3d_index = [ model.index(row, 0, QModelIndex()) for row in range(model.rowCount(QModelIndex())) - if model.data(model.index(row, 0, QModelIndex()), - QgsCoordinateReferenceSystemModel.Roles.RoleGroupId) == 'Geographic3d' + if model.data( + model.index(row, 0, QModelIndex()), + QgsCoordinateReferenceSystemModel.Roles.RoleGroupId, + ) + == "Geographic3d" ][0] - self.assertFalse([ - model.index(row, 0, geographic_3d_index) - for row in range(model.rowCount(geographic_3d_index)) - if model.data(model.index(row, 0, geographic_3d_index), - QgsCoordinateReferenceSystemModel.Roles.RoleAuthId) == 'EPSG:4329' - ]) + self.assertFalse( + [ + model.index(row, 0, geographic_3d_index) + for row in range(model.rowCount(geographic_3d_index)) + if model.data( + model.index(row, 0, geographic_3d_index), + QgsCoordinateReferenceSystemModel.Roles.RoleAuthId, + ) + == "EPSG:4329" + ] + ) epsg_4939_index = [ model.index(row, 0, geographic_3d_index) for row in range(model.rowCount(geographic_3d_index)) - if model.data(model.index(row, 0, geographic_3d_index), - QgsCoordinateReferenceSystemModel.Roles.RoleAuthId) == 'EPSG:4939' + if model.data( + model.index(row, 0, geographic_3d_index), + QgsCoordinateReferenceSystemModel.Roles.RoleAuthId, + ) + == "EPSG:4939" ][0] self.assertTrue(epsg_4939_index.isValid()) epsg_4347_index = [ model.index(row, 0, geographic_3d_index) for row in range(model.rowCount(geographic_3d_index)) - if model.data(model.index(row, 0, geographic_3d_index), - QgsCoordinateReferenceSystemModel.Roles.RoleAuthId) == 'EPSG:4347' + if model.data( + model.index(row, 0, geographic_3d_index), + QgsCoordinateReferenceSystemModel.Roles.RoleAuthId, + ) + == "EPSG:4347" ][0] self.assertTrue(epsg_4347_index.isValid()) - model.setFilterString('') + model.setFilterString("") # set filtered list of crs to show - model.setFilterAuthIds({'epsg:4289', 'EPSG:4196'}) + model.setFilterAuthIds({"epsg:4289", "EPSG:4196"}) geographic_2d_index = [ model.index(row, 0, QModelIndex()) for row in range(model.rowCount(QModelIndex())) - if model.data(model.index(row, 0, QModelIndex()), - QgsCoordinateReferenceSystemModel.Roles.RoleGroupId) == 'Geographic2d' + if model.data( + model.index(row, 0, QModelIndex()), + QgsCoordinateReferenceSystemModel.Roles.RoleGroupId, + ) + == "Geographic2d" ][0] - self.assertFalse([ - model.index(row, 0, geographic_2d_index) - for row in range(model.rowCount(geographic_2d_index)) - if model.data(model.index(row, 0, geographic_2d_index), - QgsCoordinateReferenceSystemModel.Roles.RoleAuthId) == 'EPSG:4169' - ]) + self.assertFalse( + [ + model.index(row, 0, geographic_2d_index) + for row in range(model.rowCount(geographic_2d_index)) + if model.data( + model.index(row, 0, geographic_2d_index), + QgsCoordinateReferenceSystemModel.Roles.RoleAuthId, + ) + == "EPSG:4169" + ] + ) epsg_4289_index = [ model.index(row, 0, geographic_2d_index) for row in range(model.rowCount(geographic_2d_index)) - if model.data(model.index(row, 0, geographic_2d_index), - QgsCoordinateReferenceSystemModel.Roles.RoleAuthId) == 'EPSG:4289' + if model.data( + model.index(row, 0, geographic_2d_index), + QgsCoordinateReferenceSystemModel.Roles.RoleAuthId, + ) + == "EPSG:4289" ][0] self.assertTrue(epsg_4289_index.isValid()) epsg_4196_index = [ model.index(row, 0, geographic_2d_index) for row in range(model.rowCount(geographic_2d_index)) - if model.data(model.index(row, 0, geographic_2d_index), - QgsCoordinateReferenceSystemModel.Roles.RoleAuthId) == 'EPSG:4196' + if model.data( + model.index(row, 0, geographic_2d_index), + QgsCoordinateReferenceSystemModel.Roles.RoleAuthId, + ) + == "EPSG:4196" ][0] self.assertTrue(epsg_4196_index.isValid()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscoordinatereferencesystemutils.py b/tests/src/python/test_qgscoordinatereferencesystemutils.py index 845bea61a96a..fc74e375f28d 100644 --- a/tests/src/python/test_qgscoordinatereferencesystemutils.py +++ b/tests/src/python/test_qgscoordinatereferencesystemutils.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2022 by Nyall Dawson' -__date__ = '06/04/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "(C) 2022 by Nyall Dawson" +__date__ = "06/04/2022" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.core import ( @@ -27,28 +28,62 @@ def test_axis_order(self): """ Test QgsCoordinateReferenceSystem.axisOrdering() (including the Python MethodCode associated with this) """ - self.assertEqual(QgsCoordinateReferenceSystemUtils.defaultCoordinateOrderForCrs(QgsCoordinateReferenceSystem()), Qgis.CoordinateOrder.XY) - self.assertEqual(QgsCoordinateReferenceSystemUtils.defaultCoordinateOrderForCrs(QgsCoordinateReferenceSystem('EPSG:3111')), Qgis.CoordinateOrder.XY) - self.assertEqual(QgsCoordinateReferenceSystemUtils.defaultCoordinateOrderForCrs(QgsCoordinateReferenceSystem('EPSG:4326')), Qgis.CoordinateOrder.YX) + self.assertEqual( + QgsCoordinateReferenceSystemUtils.defaultCoordinateOrderForCrs( + QgsCoordinateReferenceSystem() + ), + Qgis.CoordinateOrder.XY, + ) + self.assertEqual( + QgsCoordinateReferenceSystemUtils.defaultCoordinateOrderForCrs( + QgsCoordinateReferenceSystem("EPSG:3111") + ), + Qgis.CoordinateOrder.XY, + ) + self.assertEqual( + QgsCoordinateReferenceSystemUtils.defaultCoordinateOrderForCrs( + QgsCoordinateReferenceSystem("EPSG:4326") + ), + Qgis.CoordinateOrder.YX, + ) # compound crs self.assertEqual( QgsCoordinateReferenceSystemUtils.defaultCoordinateOrderForCrs( - QgsCoordinateReferenceSystem('EPSG:5500')), - Qgis.CoordinateOrder.YX) + QgsCoordinateReferenceSystem("EPSG:5500") + ), + Qgis.CoordinateOrder.YX, + ) # vertical crs, should be no error here and just return the default self.assertEqual( QgsCoordinateReferenceSystemUtils.defaultCoordinateOrderForCrs( - QgsCoordinateReferenceSystem('EPSG:5703')), - Qgis.CoordinateOrder.XY) + QgsCoordinateReferenceSystem("EPSG:5703") + ), + Qgis.CoordinateOrder.XY, + ) def test_axis_direction_to_abbreviation(self): """ Test QgsCoordinateReferenceSystem.axisDirectionToAbbreviatedString() """ - self.assertEqual(QgsCoordinateReferenceSystemUtils.axisDirectionToAbbreviatedString(Qgis.CrsAxisDirection.North), 'N') - self.assertEqual(QgsCoordinateReferenceSystemUtils.axisDirectionToAbbreviatedString(Qgis.CrsAxisDirection.East), 'E') - self.assertEqual(QgsCoordinateReferenceSystemUtils.axisDirectionToAbbreviatedString(Qgis.CrsAxisDirection.CounterClockwise), 'CCW') + self.assertEqual( + QgsCoordinateReferenceSystemUtils.axisDirectionToAbbreviatedString( + Qgis.CrsAxisDirection.North + ), + "N", + ) + self.assertEqual( + QgsCoordinateReferenceSystemUtils.axisDirectionToAbbreviatedString( + Qgis.CrsAxisDirection.East + ), + "E", + ) + self.assertEqual( + QgsCoordinateReferenceSystemUtils.axisDirectionToAbbreviatedString( + Qgis.CrsAxisDirection.CounterClockwise + ), + "CCW", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscoordinatetransform.py b/tests/src/python/test_qgscoordinatetransform.py index 65201e5a984b..de3bb7b97c11 100644 --- a/tests/src/python/test_qgscoordinatetransform.py +++ b/tests/src/python/test_qgscoordinatetransform.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2012 by Tim Sutton' -__date__ = '20/08/2012' -__copyright__ = 'Copyright 2012, The QGIS Project' + +__author__ = "(C) 2012 by Tim Sutton" +__date__ = "20/08/2012" +__copyright__ = "Copyright 2012, The QGIS Project" from qgis.core import ( @@ -18,7 +19,7 @@ QgsProject, QgsRectangle, QgsPointXY, - QgsCsException + QgsCsException, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -31,116 +32,196 @@ class TestQgsCoordinateTransform(QgisTestCase): def testTransformBoundingBox(self): """Test that we can transform a rectangular bbox from utm56s to LonLat""" myExtent = QgsRectangle(242270, 6043737, 246330, 6045897) - myGeoCrs = QgsCoordinateReferenceSystem('EPSG:4326') - myUtmCrs = QgsCoordinateReferenceSystem('EPSG:32756') + myGeoCrs = QgsCoordinateReferenceSystem("EPSG:4326") + myUtmCrs = QgsCoordinateReferenceSystem("EPSG:32756") myXForm = QgsCoordinateTransform(myUtmCrs, myGeoCrs, QgsProject.instance()) myProjectedExtent = myXForm.transformBoundingBox(myExtent) - myExpectedExtent = ('150.1509239873580270,-35.7176936443908772 : ' - '150.1964384662953194,-35.6971885216629090') - myExpectedValues = [150.1509239873580270, -35.7176936443908772, - 150.1964384662953194, -35.6971885216629090] - myMessage = ('Expected:\n%s\nGot:\n%s\n' % - (myExpectedExtent, - myProjectedExtent.toString())) - - self.assertAlmostEqual(myExpectedValues[0], myProjectedExtent.xMinimum(), msg=myMessage) - self.assertAlmostEqual(myExpectedValues[1], myProjectedExtent.yMinimum(), msg=myMessage) - self.assertAlmostEqual(myExpectedValues[2], myProjectedExtent.xMaximum(), msg=myMessage) - self.assertAlmostEqual(myExpectedValues[3], myProjectedExtent.yMaximum(), msg=myMessage) + myExpectedExtent = ( + "150.1509239873580270,-35.7176936443908772 : " + "150.1964384662953194,-35.6971885216629090" + ) + myExpectedValues = [ + 150.1509239873580270, + -35.7176936443908772, + 150.1964384662953194, + -35.6971885216629090, + ] + myMessage = "Expected:\n{}\nGot:\n{}\n".format( + myExpectedExtent, + myProjectedExtent.toString(), + ) + + self.assertAlmostEqual( + myExpectedValues[0], myProjectedExtent.xMinimum(), msg=myMessage + ) + self.assertAlmostEqual( + myExpectedValues[1], myProjectedExtent.yMinimum(), msg=myMessage + ) + self.assertAlmostEqual( + myExpectedValues[2], myProjectedExtent.xMaximum(), msg=myMessage + ) + self.assertAlmostEqual( + myExpectedValues[3], myProjectedExtent.yMaximum(), msg=myMessage + ) def testTransformBoundingBoxSizeOverflowProtection(self): """Test transform bounding box size overflow protection (github issue #32302)""" - extent = QgsRectangle(-176.0454709164556562, 89.9999999999998153, 180.0000000000000000, 90.0000000000000000) - transform = d = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4236'), QgsCoordinateReferenceSystem('EPSG:3031'), QgsProject.instance()) + extent = QgsRectangle( + -176.0454709164556562, + 89.9999999999998153, + 180.0000000000000000, + 90.0000000000000000, + ) + transform = d = QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:4236"), + QgsCoordinateReferenceSystem("EPSG:3031"), + QgsProject.instance(), + ) # this test checks that the line below doesn't assert and crash transformedExtent = transform.transformBoundingBox(extent) def testTransformQgsRectangle_Regression17600(self): """Test that rectangle transform is in the bindings""" myExtent = QgsRectangle(-1797107, 4392148, 6025926, 6616304) - myGeoCrs = QgsCoordinateReferenceSystem('EPSG:4326') - myUtmCrs = QgsCoordinateReferenceSystem('EPSG:3857') + myGeoCrs = QgsCoordinateReferenceSystem("EPSG:4326") + myUtmCrs = QgsCoordinateReferenceSystem("EPSG:3857") myXForm = QgsCoordinateTransform(myUtmCrs, myGeoCrs, QgsProject.instance()) myTransformedExtent = myXForm.transform(myExtent) - myTransformedExtentForward = myXForm.transform(myExtent, QgsCoordinateTransform.TransformDirection.ForwardTransform) - self.assertAlmostEqual(myTransformedExtentForward.xMaximum(), myTransformedExtent.xMaximum()) - self.assertAlmostEqual(myTransformedExtentForward.xMinimum(), myTransformedExtent.xMinimum()) - self.assertAlmostEqual(myTransformedExtentForward.yMaximum(), myTransformedExtent.yMaximum()) - self.assertAlmostEqual(myTransformedExtentForward.yMinimum(), myTransformedExtent.yMinimum()) + myTransformedExtentForward = myXForm.transform( + myExtent, QgsCoordinateTransform.TransformDirection.ForwardTransform + ) + self.assertAlmostEqual( + myTransformedExtentForward.xMaximum(), myTransformedExtent.xMaximum() + ) + self.assertAlmostEqual( + myTransformedExtentForward.xMinimum(), myTransformedExtent.xMinimum() + ) + self.assertAlmostEqual( + myTransformedExtentForward.yMaximum(), myTransformedExtent.yMaximum() + ) + self.assertAlmostEqual( + myTransformedExtentForward.yMinimum(), myTransformedExtent.yMinimum() + ) self.assertAlmostEqual(myTransformedExtentForward.xMaximum(), 54.13181426773211) - self.assertAlmostEqual(myTransformedExtentForward.xMinimum(), -16.14368685298181) - self.assertAlmostEqual(myTransformedExtentForward.yMaximum(), 50.971783118386895) + self.assertAlmostEqual( + myTransformedExtentForward.xMinimum(), -16.14368685298181 + ) + self.assertAlmostEqual( + myTransformedExtentForward.yMaximum(), 50.971783118386895 + ) self.assertAlmostEqual(myTransformedExtentForward.yMinimum(), 36.66235970825241) - myTransformedExtentReverse = myXForm.transform(myTransformedExtent, QgsCoordinateTransform.TransformDirection.ReverseTransform) - self.assertAlmostEqual(myTransformedExtentReverse.xMaximum(), myExtent.xMaximum()) - self.assertAlmostEqual(myTransformedExtentReverse.xMinimum(), myExtent.xMinimum()) - self.assertAlmostEqual(myTransformedExtentReverse.yMaximum(), myExtent.yMaximum()) - self.assertAlmostEqual(myTransformedExtentReverse.yMinimum(), myExtent.yMinimum()) + myTransformedExtentReverse = myXForm.transform( + myTransformedExtent, + QgsCoordinateTransform.TransformDirection.ReverseTransform, + ) + self.assertAlmostEqual( + myTransformedExtentReverse.xMaximum(), myExtent.xMaximum() + ) + self.assertAlmostEqual( + myTransformedExtentReverse.xMinimum(), myExtent.xMinimum() + ) + self.assertAlmostEqual( + myTransformedExtentReverse.yMaximum(), myExtent.yMaximum() + ) + self.assertAlmostEqual( + myTransformedExtentReverse.yMinimum(), myExtent.yMinimum() + ) def testContextProj6(self): """ Various tests to ensure that datum transforms are correctly set respecting context """ context = QgsCoordinateTransformContext() - context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:28356'), - QgsCoordinateReferenceSystem('EPSG:4283'), - 'proj') + context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:28356"), + QgsCoordinateReferenceSystem("EPSG:4283"), + "proj", + ) - transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28354'), QgsCoordinateReferenceSystem('EPSG:28353'), context) - self.assertEqual(list(transform.context().coordinateOperations().keys()), [('EPSG:28356', 'EPSG:4283')]) + transform = QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:28354"), + QgsCoordinateReferenceSystem("EPSG:28353"), + context, + ) + self.assertEqual( + list(transform.context().coordinateOperations().keys()), + [("EPSG:28356", "EPSG:4283")], + ) # should be no coordinate operation - self.assertEqual(transform.coordinateOperation(), '') + self.assertEqual(transform.coordinateOperation(), "") # should default to allowing fallback transforms self.assertTrue(transform.allowFallbackTransforms()) - transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28356'), - QgsCoordinateReferenceSystem('EPSG:4283'), context) + transform = QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:28356"), + QgsCoordinateReferenceSystem("EPSG:4283"), + context, + ) self.assertTrue(transform.allowFallbackTransforms()) - context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:28356'), - QgsCoordinateReferenceSystem('EPSG:4283'), - 'proj', False) - transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28356'), - QgsCoordinateReferenceSystem('EPSG:4283'), context) + context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:28356"), + QgsCoordinateReferenceSystem("EPSG:4283"), + "proj", + False, + ) + transform = QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:28356"), + QgsCoordinateReferenceSystem("EPSG:4283"), + context, + ) self.assertFalse(transform.allowFallbackTransforms()) # matching source - transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:28353'), context) - self.assertEqual(transform.coordinateOperation(), '') + transform = QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:28356"), + QgsCoordinateReferenceSystem("EPSG:28353"), + context, + ) + self.assertEqual(transform.coordinateOperation(), "") # matching dest - transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28354'), - QgsCoordinateReferenceSystem('EPSG:4283'), context) - self.assertEqual(transform.coordinateOperation(), '') + transform = QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:28354"), + QgsCoordinateReferenceSystem("EPSG:4283"), + context, + ) + self.assertEqual(transform.coordinateOperation(), "") # matching src/dest pair - transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28356'), - QgsCoordinateReferenceSystem('EPSG:4283'), context) - self.assertEqual(transform.coordinateOperation(), 'proj') + transform = QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:28356"), + QgsCoordinateReferenceSystem("EPSG:4283"), + context, + ) + self.assertEqual(transform.coordinateOperation(), "proj") # test manual overwriting - transform.setCoordinateOperation('proj2') - self.assertEqual(transform.coordinateOperation(), 'proj2') + transform.setCoordinateOperation("proj2") + self.assertEqual(transform.coordinateOperation(), "proj2") transform.setAllowFallbackTransforms(False) self.assertFalse(transform.allowFallbackTransforms()) transform.setAllowFallbackTransforms(True) self.assertTrue(transform.allowFallbackTransforms()) # test that auto operation setting occurs when updating src/dest crs - transform.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:28356')) - self.assertEqual(transform.coordinateOperation(), 'proj') - transform.setCoordinateOperation('proj2') + transform.setSourceCrs(QgsCoordinateReferenceSystem("EPSG:28356")) + self.assertEqual(transform.coordinateOperation(), "proj") + transform.setCoordinateOperation("proj2") - transform.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4283')) - self.assertEqual(transform.coordinateOperation(), 'proj') - transform.setCoordinateOperation('proj2') + transform.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4283")) + self.assertEqual(transform.coordinateOperation(), "proj") + transform.setCoordinateOperation("proj2") # delayed context set transform = QgsCoordinateTransform() - self.assertEqual(transform.coordinateOperation(), '') - transform.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:28356')) - transform.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4283')) - self.assertEqual(transform.coordinateOperation(), '') + self.assertEqual(transform.coordinateOperation(), "") + transform.setSourceCrs(QgsCoordinateReferenceSystem("EPSG:28356")) + transform.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4283")) + self.assertEqual(transform.coordinateOperation(), "") transform.setContext(context) - self.assertEqual(transform.coordinateOperation(), 'proj') - self.assertEqual(list(transform.context().coordinateOperations().keys()), [('EPSG:28356', 'EPSG:4283')]) + self.assertEqual(transform.coordinateOperation(), "proj") + self.assertEqual( + list(transform.context().coordinateOperations().keys()), + [("EPSG:28356", "EPSG:4283")], + ) def testProjectContextProj6(self): """ @@ -148,16 +229,27 @@ def testProjectContextProj6(self): """ p = QgsProject() context = p.transformContext() - context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:28356'), - QgsCoordinateReferenceSystem('EPSG:3111'), 'proj') + context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:28356"), + QgsCoordinateReferenceSystem("EPSG:3111"), + "proj", + ) p.setTransformContext(context) - transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:3111'), p) - self.assertEqual(transform.coordinateOperation(), 'proj') + transform = QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:28356"), + QgsCoordinateReferenceSystem("EPSG:3111"), + p, + ) + self.assertEqual(transform.coordinateOperation(), "proj") def testTransformBoundingBoxFullWorldToWebMercator(self): extent = QgsRectangle(-180, -90, 180, 90) - transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'), QgsProject.instance()) + transform = QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsProject.instance(), + ) transformedExtent = transform.transformBoundingBox(extent) self.assertAlmostEqual(transformedExtent.xMinimum(), -20037508.343, delta=1e-3) self.assertAlmostEqual(transformedExtent.yMinimum(), -44927335.427, delta=1e-3) @@ -170,63 +262,77 @@ def test_has_vertical_component(self): # 2d to 2d transform = QgsCoordinateTransform( - QgsCoordinateReferenceSystem('EPSG:4326'), - QgsCoordinateReferenceSystem('EPSG:3857'), - QgsCoordinateTransformContext() + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsCoordinateTransformContext(), ) self.assertFalse(transform.hasVerticalComponent()) # 2d to 3d transform = QgsCoordinateTransform( - QgsCoordinateReferenceSystem('EPSG:4326'), - QgsCoordinateReferenceSystem('EPSG:7843'), - QgsCoordinateTransformContext() + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:7843"), + QgsCoordinateTransformContext(), ) self.assertFalse(transform.hasVerticalComponent()) # 3d to 2d transform = QgsCoordinateTransform( - QgsCoordinateReferenceSystem('EPSG:7843'), - QgsCoordinateReferenceSystem('EPSG:4326'), - QgsCoordinateTransformContext() + QgsCoordinateReferenceSystem("EPSG:7843"), + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateTransformContext(), ) self.assertFalse(transform.hasVerticalComponent()) # 3d to 3d transform = QgsCoordinateTransform( - QgsCoordinateReferenceSystem('EPSG:7843'), + QgsCoordinateReferenceSystem("EPSG:7843"), QgsCoordinateReferenceSystem.createCompoundCrs( - QgsCoordinateReferenceSystem('EPSG:7844'), - QgsCoordinateReferenceSystem('EPSG:9458'))[0], - QgsCoordinateTransformContext() + QgsCoordinateReferenceSystem("EPSG:7844"), + QgsCoordinateReferenceSystem("EPSG:9458"), + )[0], + QgsCoordinateTransformContext(), ) self.assertTrue(transform.hasVerticalComponent()) transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem.createCompoundCrs( - QgsCoordinateReferenceSystem('EPSG:7844'), - QgsCoordinateReferenceSystem('EPSG:5711'))[0], - QgsCoordinateReferenceSystem('EPSG:7843'), - QgsCoordinateTransformContext() + QgsCoordinateReferenceSystem("EPSG:7844"), + QgsCoordinateReferenceSystem("EPSG:5711"), + )[0], + QgsCoordinateReferenceSystem("EPSG:7843"), + QgsCoordinateTransformContext(), ) self.assertTrue(transform.hasVerticalComponent()) def test_cs_exception(self): - ct = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'), - QgsCoordinateReferenceSystem('EPSG:3857'), QgsProject.instance()) + ct = QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsProject.instance(), + ) point = QgsPointXY(-7603859, -7324441) with self.assertRaises(QgsCsException) as e: ct.transform(point) - self.assertEqual(str(e.exception), 'Forward transform (EPSG:4326 to EPSG:3857) of (-7603859.000000, -7324441.000000) Error: Invalid coordinate') + self.assertEqual( + str(e.exception), + "Forward transform (EPSG:4326 to EPSG:3857) of (-7603859.000000, -7324441.000000) Error: Invalid coordinate", + ) # reverse transform - ct = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:3857'), - QgsCoordinateReferenceSystem('EPSG:4326'), QgsProject.instance()) + ct = QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsProject.instance(), + ) point = QgsPointXY(-7603859, -7324441) with self.assertRaises(QgsCsException) as e: ct.transform(point, Qgis.TransformDirection.Reverse) - self.assertEqual(str(e.exception), 'Inverse transform (EPSG:4326 to EPSG:3857) of (-7603859.000000, -7324441.000000) Error: Invalid coordinate') + self.assertEqual( + str(e.exception), + "Inverse transform (EPSG:4326 to EPSG:3857) of (-7603859.000000, -7324441.000000) Error: Invalid coordinate", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscoordinatetransformcontext.py b/tests/src/python/test_qgscoordinatetransformcontext.py index 34eed46ffecc..5274edaffc9a 100644 --- a/tests/src/python/test_qgscoordinatetransformcontext.py +++ b/tests/src/python/test_qgscoordinatetransformcontext.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '11/5/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "11/5/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication from qgis.PyQt.QtTest import QSignalSpy @@ -39,125 +40,302 @@ def setUpClass(cls): def testSourceDestinationDatumTransformsProj6(self): context = QgsCoordinateTransformContext() self.assertEqual(context.coordinateOperations(), {}) - proj_string = '+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1' + proj_string = "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1" + self.assertFalse( + context.hasTransform( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + ) + ) + self.assertFalse( + context.mustReverseCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + ) + ) self.assertFalse( - context.hasTransform(QgsCoordinateReferenceSystem('EPSG:3111'), QgsCoordinateReferenceSystem('EPSG:4283'))) - self.assertFalse(context.mustReverseCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:4283'))) - self.assertFalse(context.mustReverseCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4283'), - QgsCoordinateReferenceSystem('EPSG:3111'))) - self.assertTrue(context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:4283'), proj_string)) + context.mustReverseCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:4283"), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) + ) self.assertTrue( - context.hasTransform(QgsCoordinateReferenceSystem('EPSG:3111'), QgsCoordinateReferenceSystem('EPSG:4283'))) + context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + proj_string, + ) + ) + self.assertTrue( + context.hasTransform( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + ) + ) self.assertFalse( - context.hasTransform(QgsCoordinateReferenceSystem('EPSG:3111'), QgsCoordinateReferenceSystem('EPSG:4326'))) + context.hasTransform( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + ) self.assertFalse( - context.hasTransform(QgsCoordinateReferenceSystem('EPSG:3113'), QgsCoordinateReferenceSystem('EPSG:4283'))) - self.assertEqual(context.coordinateOperations(), {('EPSG:3111', 'EPSG:4283'): proj_string}) - self.assertTrue(context.mustReverseCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4283'), - QgsCoordinateReferenceSystem('EPSG:3111'))) + context.hasTransform( + QgsCoordinateReferenceSystem("EPSG:3113"), + QgsCoordinateReferenceSystem("EPSG:4283"), + ) + ) + self.assertEqual( + context.coordinateOperations(), {("EPSG:3111", "EPSG:4283"): proj_string} + ) self.assertTrue( - context.allowFallbackTransform(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:4283'))) + context.mustReverseCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:4283"), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) + ) self.assertTrue( - context.allowFallbackTransform(QgsCoordinateReferenceSystem('EPSG:4283'), - QgsCoordinateReferenceSystem('EPSG:3111'))) - + context.allowFallbackTransform( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + ) + ) self.assertTrue( - context.hasTransform(QgsCoordinateReferenceSystem('EPSG:4283'), QgsCoordinateReferenceSystem('EPSG:3111'))) + context.allowFallbackTransform( + QgsCoordinateReferenceSystem("EPSG:4283"), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) + ) - self.assertEqual(context.calculateCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:4283')), proj_string) - self.assertFalse(context.mustReverseCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:4283'))) + self.assertTrue( + context.hasTransform( + QgsCoordinateReferenceSystem("EPSG:4283"), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) + ) + + self.assertEqual( + context.calculateCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + ), + proj_string, + ) + self.assertFalse( + context.mustReverseCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + ) + ) # ideally not equal, but for now it's all we can do, and return True for mustReverseCoordinateOperation here - self.assertEqual(context.calculateCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4283'), - QgsCoordinateReferenceSystem('EPSG:3111')), proj_string) - self.assertTrue(context.mustReverseCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4283'), - QgsCoordinateReferenceSystem('EPSG:3111'))) + self.assertEqual( + context.calculateCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:4283"), + QgsCoordinateReferenceSystem("EPSG:3111"), + ), + proj_string, + ) self.assertTrue( - context.allowFallbackTransform(QgsCoordinateReferenceSystem('EPSG:4283'), - QgsCoordinateReferenceSystem('EPSG:3111'))) - - proj_string_2 = 'dummy' - self.assertTrue(context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4283'), - QgsCoordinateReferenceSystem('EPSG:3111'), proj_string_2, False)) - self.assertEqual(context.calculateCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4283'), - QgsCoordinateReferenceSystem('EPSG:3111')), proj_string_2) - self.assertFalse(context.mustReverseCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4283'), - QgsCoordinateReferenceSystem('EPSG:3111'))) - context.removeCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4283'), - QgsCoordinateReferenceSystem('EPSG:3111')) - - self.assertTrue(context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4283'), - QgsCoordinateReferenceSystem('EPSG:3113'), proj_string_2, False)) + context.mustReverseCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:4283"), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) + ) + self.assertTrue( + context.allowFallbackTransform( + QgsCoordinateReferenceSystem("EPSG:4283"), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) + ) + + proj_string_2 = "dummy" + self.assertTrue( + context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:4283"), + QgsCoordinateReferenceSystem("EPSG:3111"), + proj_string_2, + False, + ) + ) + self.assertEqual( + context.calculateCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:4283"), + QgsCoordinateReferenceSystem("EPSG:3111"), + ), + proj_string_2, + ) + self.assertFalse( + context.mustReverseCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:4283"), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) + ) + context.removeCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:4283"), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) + + self.assertTrue( + context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:4283"), + QgsCoordinateReferenceSystem("EPSG:3113"), + proj_string_2, + False, + ) + ) self.assertFalse( - context.allowFallbackTransform(QgsCoordinateReferenceSystem('EPSG:4283'), - QgsCoordinateReferenceSystem('EPSG:3113'))) + context.allowFallbackTransform( + QgsCoordinateReferenceSystem("EPSG:4283"), + QgsCoordinateReferenceSystem("EPSG:3113"), + ) + ) self.assertFalse( - context.allowFallbackTransform(QgsCoordinateReferenceSystem('EPSG:3113'), - QgsCoordinateReferenceSystem('EPSG:4283'))) - - context.removeCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4283'), - QgsCoordinateReferenceSystem('EPSG:3113')) - - proj_string_2 = '+proj=pipeline +step +inv +proj=utm +zone=56 +south +ellps=GRS80 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1' - self.assertTrue(context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:28356'), - QgsCoordinateReferenceSystem('EPSG:4283'), proj_string_2)) - self.assertEqual(context.coordinateOperations(), {('EPSG:3111', 'EPSG:4283'): proj_string, - ('EPSG:28356', 'EPSG:4283'): proj_string_2}) - proj_string_3 = '+proj=pipeline +step +inv +proj=utm +zone=56 +south +ellps=GRS80 +step +proj=utm +zone=57 +south +ellps=GRS80' - self.assertTrue(context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:28356'), - QgsCoordinateReferenceSystem('EPSG:28357'), proj_string_3)) - self.assertEqual(context.coordinateOperations(), {('EPSG:3111', 'EPSG:4283'): proj_string, - ('EPSG:28356', 'EPSG:4283'): proj_string_2, - ('EPSG:28356', 'EPSG:28357'): proj_string_3}) - self.assertTrue(context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:28356'), - QgsCoordinateReferenceSystem('EPSG:28357'), - 'some other proj string')) - self.assertEqual(context.coordinateOperations(), {('EPSG:3111', 'EPSG:4283'): proj_string, - ('EPSG:28356', 'EPSG:4283'): proj_string_2, - ('EPSG:28356', 'EPSG:28357'): 'some other proj string'}) + context.allowFallbackTransform( + QgsCoordinateReferenceSystem("EPSG:3113"), + QgsCoordinateReferenceSystem("EPSG:4283"), + ) + ) + + context.removeCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:4283"), + QgsCoordinateReferenceSystem("EPSG:3113"), + ) + + proj_string_2 = "+proj=pipeline +step +inv +proj=utm +zone=56 +south +ellps=GRS80 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1" + self.assertTrue( + context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:28356"), + QgsCoordinateReferenceSystem("EPSG:4283"), + proj_string_2, + ) + ) + self.assertEqual( + context.coordinateOperations(), + { + ("EPSG:3111", "EPSG:4283"): proj_string, + ("EPSG:28356", "EPSG:4283"): proj_string_2, + }, + ) + proj_string_3 = "+proj=pipeline +step +inv +proj=utm +zone=56 +south +ellps=GRS80 +step +proj=utm +zone=57 +south +ellps=GRS80" + self.assertTrue( + context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:28356"), + QgsCoordinateReferenceSystem("EPSG:28357"), + proj_string_3, + ) + ) + self.assertEqual( + context.coordinateOperations(), + { + ("EPSG:3111", "EPSG:4283"): proj_string, + ("EPSG:28356", "EPSG:4283"): proj_string_2, + ("EPSG:28356", "EPSG:28357"): proj_string_3, + }, + ) + self.assertTrue( + context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:28356"), + QgsCoordinateReferenceSystem("EPSG:28357"), + "some other proj string", + ) + ) + self.assertEqual( + context.coordinateOperations(), + { + ("EPSG:3111", "EPSG:4283"): proj_string, + ("EPSG:28356", "EPSG:4283"): proj_string_2, + ("EPSG:28356", "EPSG:28357"): "some other proj string", + }, + ) # invalid additions - self.assertFalse(context.addCoordinateOperation(QgsCoordinateReferenceSystem(), - QgsCoordinateReferenceSystem('EPSG:28357'), 'bad proj')) - self.assertEqual(context.coordinateOperations(), {('EPSG:3111', 'EPSG:4283'): proj_string, - ('EPSG:28356', 'EPSG:4283'): proj_string_2, - ('EPSG:28356', 'EPSG:28357'): 'some other proj string'}) - self.assertFalse(context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem(), 'bad proj')) - self.assertEqual(context.coordinateOperations(), {('EPSG:3111', 'EPSG:4283'): proj_string, - ('EPSG:28356', 'EPSG:4283'): proj_string_2, - ('EPSG:28356', 'EPSG:28357'): 'some other proj string'}) + self.assertFalse( + context.addCoordinateOperation( + QgsCoordinateReferenceSystem(), + QgsCoordinateReferenceSystem("EPSG:28357"), + "bad proj", + ) + ) + self.assertEqual( + context.coordinateOperations(), + { + ("EPSG:3111", "EPSG:4283"): proj_string, + ("EPSG:28356", "EPSG:4283"): proj_string_2, + ("EPSG:28356", "EPSG:28357"): "some other proj string", + }, + ) + self.assertFalse( + context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem(), + "bad proj", + ) + ) + self.assertEqual( + context.coordinateOperations(), + { + ("EPSG:3111", "EPSG:4283"): proj_string, + ("EPSG:28356", "EPSG:4283"): proj_string_2, + ("EPSG:28356", "EPSG:28357"): "some other proj string", + }, + ) # indicate no transform required - self.assertTrue(context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:28357'), - QgsCoordinateReferenceSystem('EPSG:28356'), '')) - self.assertEqual(context.coordinateOperations(), {('EPSG:3111', 'EPSG:4283'): proj_string, - ('EPSG:28356', 'EPSG:4283'): proj_string_2, - ('EPSG:28356', 'EPSG:28357'): 'some other proj string', - ('EPSG:28357', 'EPSG:28356'): ''}) + self.assertTrue( + context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:28357"), + QgsCoordinateReferenceSystem("EPSG:28356"), + "", + ) + ) + self.assertEqual( + context.coordinateOperations(), + { + ("EPSG:3111", "EPSG:4283"): proj_string, + ("EPSG:28356", "EPSG:4283"): proj_string_2, + ("EPSG:28356", "EPSG:28357"): "some other proj string", + ("EPSG:28357", "EPSG:28356"): "", + }, + ) # remove non-existing - context.removeCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3113'), - QgsCoordinateReferenceSystem('EPSG:3111')) - self.assertEqual(context.coordinateOperations(), {('EPSG:3111', 'EPSG:4283'): proj_string, - ('EPSG:28356', 'EPSG:4283'): proj_string_2, - ('EPSG:28356', 'EPSG:28357'): 'some other proj string', - ('EPSG:28357', 'EPSG:28356'): ''}) + context.removeCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:3113"), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) + self.assertEqual( + context.coordinateOperations(), + { + ("EPSG:3111", "EPSG:4283"): proj_string, + ("EPSG:28356", "EPSG:4283"): proj_string_2, + ("EPSG:28356", "EPSG:28357"): "some other proj string", + ("EPSG:28357", "EPSG:28356"): "", + }, + ) # remove existing - context.removeCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:4283')) - self.assertEqual(context.coordinateOperations(), {('EPSG:28356', 'EPSG:4283'): proj_string_2, - ('EPSG:28356', 'EPSG:28357'): 'some other proj string', - ('EPSG:28357', 'EPSG:28356'): ''}) - context.removeCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:28356'), - QgsCoordinateReferenceSystem('EPSG:28357')) - self.assertEqual(context.coordinateOperations(), {('EPSG:28356', 'EPSG:4283'): proj_string_2, - ('EPSG:28357', 'EPSG:28356'): ''}) + context.removeCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + ) + self.assertEqual( + context.coordinateOperations(), + { + ("EPSG:28356", "EPSG:4283"): proj_string_2, + ("EPSG:28356", "EPSG:28357"): "some other proj string", + ("EPSG:28357", "EPSG:28356"): "", + }, + ) + context.removeCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:28356"), + QgsCoordinateReferenceSystem("EPSG:28357"), + ) + self.assertEqual( + context.coordinateOperations(), + { + ("EPSG:28356", "EPSG:4283"): proj_string_2, + ("EPSG:28357", "EPSG:28356"): "", + }, + ) context.clear() self.assertEqual(context.coordinateOperations(), {}) @@ -166,50 +344,95 @@ def testCalculateSourceDestProj6(self): context = QgsCoordinateTransformContext() # empty context - self.assertEqual(context.calculateCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:4283')), - '') + self.assertEqual( + context.calculateCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + ), + "", + ) # add specific source/dest pair - should take precedence - context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:28356'), - QgsCoordinateReferenceSystem('EPSG:4283'), - 'proj 1') - self.assertEqual(context.calculateCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:28356'), - QgsCoordinateReferenceSystem('EPSG:4283')), - 'proj 1') - self.assertEqual(context.calculateCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:4283')), - '') - self.assertEqual(context.calculateCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:28356'), - QgsCoordinateReferenceSystem('EPSG:3111')), - '') + context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:28356"), + QgsCoordinateReferenceSystem("EPSG:4283"), + "proj 1", + ) + self.assertEqual( + context.calculateCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:28356"), + QgsCoordinateReferenceSystem("EPSG:4283"), + ), + "proj 1", + ) + self.assertEqual( + context.calculateCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + ), + "", + ) + self.assertEqual( + context.calculateCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:28356"), + QgsCoordinateReferenceSystem("EPSG:3111"), + ), + "", + ) # check that reverse transforms are automatically supported - self.assertEqual(context.calculateCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4283'), - QgsCoordinateReferenceSystem('EPSG:28356')), - 'proj 1') + self.assertEqual( + context.calculateCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:4283"), + QgsCoordinateReferenceSystem("EPSG:28356"), + ), + "proj 1", + ) def testWriteReadXmlProj6(self): # setup a context context = QgsCoordinateTransformContext() - proj_1 = '+proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 +step +proj=cart +ellps=intl +step +proj=helmert +x=-18.944 +y=-379.364 +z=-24.063 +rx=-0.04 +ry=0.764 +rz=-6.431 +s=3.657 +convention=coordinate_frame +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1' - proj_2 = '+proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 +step +proj=cart +ellps=intl +step +proj=helmert +x=-150 +y=-250 +z=-1 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1' - proj_3 = '+proj=pipeline +step +proj=axisswap +order=2,1' + proj_1 = "+proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 +step +proj=cart +ellps=intl +step +proj=helmert +x=-18.944 +y=-379.364 +z=-24.063 +rx=-0.04 +ry=0.764 +rz=-6.431 +s=3.657 +convention=coordinate_frame +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1" + proj_2 = "+proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 +step +proj=cart +ellps=intl +step +proj=helmert +x=-150 +y=-250 +z=-1 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1" + proj_3 = "+proj=pipeline +step +proj=axisswap +order=2,1" - self.assertTrue(context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4204'), - QgsCoordinateReferenceSystem('EPSG:4326'), proj_1, True)) - self.assertTrue(context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4205'), - QgsCoordinateReferenceSystem('EPSG:4326'), proj_2, False)) + self.assertTrue( + context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:4204"), + QgsCoordinateReferenceSystem("EPSG:4326"), + proj_1, + True, + ) + ) + self.assertTrue( + context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:4205"), + QgsCoordinateReferenceSystem("EPSG:4326"), + proj_2, + False, + ) + ) # also insert a crs with no authid available - self.assertTrue(context.addCoordinateOperation( - QgsCoordinateReferenceSystem.fromProj("+proj=longlat +a=6378137 +rf=298.25722356300003 +no_defs"), - QgsCoordinateReferenceSystem('EPSG:4326'), proj_3, False)) - - self.assertEqual(context.coordinateOperations(), - {('EPSG:4204', 'EPSG:4326'): proj_1, - ('EPSG:4205', 'EPSG:4326'): proj_2, - ('', 'EPSG:4326'): proj_3}) + self.assertTrue( + context.addCoordinateOperation( + QgsCoordinateReferenceSystem.fromProj( + "+proj=longlat +a=6378137 +rf=298.25722356300003 +no_defs" + ), + QgsCoordinateReferenceSystem("EPSG:4326"), + proj_3, + False, + ) + ) + + self.assertEqual( + context.coordinateOperations(), + { + ("EPSG:4204", "EPSG:4326"): proj_1, + ("EPSG:4205", "EPSG:4326"): proj_2, + ("", "EPSG:4326"): proj_3, + }, + ) # save to xml doc = QDomDocument("testdoc") @@ -221,27 +444,60 @@ def testWriteReadXmlProj6(self): context2.readXml(elem, QgsReadWriteContext()) # check result - self.assertEqual(context2.coordinateOperations(), - {('EPSG:4204', 'EPSG:4326'): proj_1, - ('EPSG:4205', 'EPSG:4326'): proj_2, - ('', 'EPSG:4326'): proj_3}) - self.assertEqual(context2.calculateCoordinateOperation( - QgsCoordinateReferenceSystem.fromProj("+proj=longlat +a=6378137 +rf=298.25722356300003 +no_defs"), - QgsCoordinateReferenceSystem('EPSG:4326')), '+proj=pipeline +step +proj=axisswap +order=2,1') - self.assertFalse(context2.mustReverseCoordinateOperation( - QgsCoordinateReferenceSystem.fromProj("+proj=longlat +a=6378137 +rf=298.25722356300003 +no_defs"), - QgsCoordinateReferenceSystem('EPSG:4326'))) - self.assertEqual(context2.calculateCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4326'), - QgsCoordinateReferenceSystem.fromProj( - "+proj=longlat +a=6378137 +rf=298.25722356300003 +no_defs")), - '+proj=pipeline +step +proj=axisswap +order=2,1') - self.assertTrue(context2.mustReverseCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4326'), - QgsCoordinateReferenceSystem.fromProj( - "+proj=longlat +a=6378137 +rf=298.25722356300003 +no_defs"))) - self.assertTrue(context2.allowFallbackTransform(QgsCoordinateReferenceSystem('EPSG:4204'), - QgsCoordinateReferenceSystem('EPSG:4326'))) - self.assertFalse(context2.allowFallbackTransform(QgsCoordinateReferenceSystem('EPSG:4205'), - QgsCoordinateReferenceSystem('EPSG:4326'))) + self.assertEqual( + context2.coordinateOperations(), + { + ("EPSG:4204", "EPSG:4326"): proj_1, + ("EPSG:4205", "EPSG:4326"): proj_2, + ("", "EPSG:4326"): proj_3, + }, + ) + self.assertEqual( + context2.calculateCoordinateOperation( + QgsCoordinateReferenceSystem.fromProj( + "+proj=longlat +a=6378137 +rf=298.25722356300003 +no_defs" + ), + QgsCoordinateReferenceSystem("EPSG:4326"), + ), + "+proj=pipeline +step +proj=axisswap +order=2,1", + ) + self.assertFalse( + context2.mustReverseCoordinateOperation( + QgsCoordinateReferenceSystem.fromProj( + "+proj=longlat +a=6378137 +rf=298.25722356300003 +no_defs" + ), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + ) + self.assertEqual( + context2.calculateCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem.fromProj( + "+proj=longlat +a=6378137 +rf=298.25722356300003 +no_defs" + ), + ), + "+proj=pipeline +step +proj=axisswap +order=2,1", + ) + self.assertTrue( + context2.mustReverseCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem.fromProj( + "+proj=longlat +a=6378137 +rf=298.25722356300003 +no_defs" + ), + ) + ) + self.assertTrue( + context2.allowFallbackTransform( + QgsCoordinateReferenceSystem("EPSG:4204"), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + ) + self.assertFalse( + context2.allowFallbackTransform( + QgsCoordinateReferenceSystem("EPSG:4205"), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + ) def testMissingTransformsProj6(self): return # TODO -- this seems impossible to determine with existing PROJ6 api @@ -250,11 +506,11 @@ def testMissingTransformsProj6(self): elem = doc.createElement("test") contextElem = doc.createElement("transformContext") transformElem = doc.createElement("srcDest") - transformElem.setAttribute("source", 'EPSG:4204') - transformElem.setAttribute("dest", 'EPSG:4326') + transformElem.setAttribute("source", "EPSG:4204") + transformElem.setAttribute("dest", "EPSG:4326") # fake a proj string with a grid which will NEVER exist - fake_proj = '+proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +inv +proj=hgridshift +grids=this_is_not_a_real_grid.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1' + fake_proj = "+proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +inv +proj=hgridshift +grids=this_is_not_a_real_grid.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1" transformElem.setAttribute("coordinateOp", fake_proj) contextElem.appendChild(transformElem) @@ -267,7 +523,7 @@ def testMissingTransformsProj6(self): self.assertFalse(ok) # check result - self.assertEqual(errors, ['not valid']) + self.assertEqual(errors, ["not valid"]) def testProjectProj6(self): """ @@ -276,15 +532,25 @@ def testProjectProj6(self): project = QgsProject() context_changed_spy = QSignalSpy(project.transformContextChanged) context = project.transformContext() - context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:4283'), 'proj', True) + context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + "proj", + True, + ) project.setTransformContext(context) self.assertEqual(len(context_changed_spy), 1) - self.assertEqual(project.transformContext().coordinateOperations(), - {('EPSG:3111', 'EPSG:4283'): 'proj'}) + self.assertEqual( + project.transformContext().coordinateOperations(), + {("EPSG:3111", "EPSG:4283"): "proj"}, + ) context2 = project.transformContext() - context2.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:4283'), 'proj', False) + context2.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + "proj", + False, + ) project.setTransformContext(context2) self.assertEqual(len(context_changed_spy), 2) self.assertEqual(project.transformContext(), context2) @@ -294,24 +560,45 @@ def testReadWriteSettingsProj6(self): context = QgsCoordinateTransformContext() context.readSettings() - proj_1 = '+proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 +step +proj=cart +ellps=intl +step +proj=helmert +x=-18.944 +y=-379.364 +z=-24.063 +rx=-0.04 +ry=0.764 +rz=-6.431 +s=3.657 +convention=coordinate_frame +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1' - proj_2 = '+proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 +step +proj=cart +ellps=intl +step +proj=helmert +x=-150 +y=-250 +z=-1 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1' + proj_1 = "+proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 +step +proj=cart +ellps=intl +step +proj=helmert +x=-18.944 +y=-379.364 +z=-24.063 +rx=-0.04 +ry=0.764 +rz=-6.431 +s=3.657 +convention=coordinate_frame +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1" + proj_2 = "+proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 +step +proj=cart +ellps=intl +step +proj=helmert +x=-150 +y=-250 +z=-1 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1" # should be empty self.assertEqual(context.coordinateOperations(), {}) - self.assertTrue(context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4204'), - QgsCoordinateReferenceSystem('EPSG:4326'), proj_1, True)) - self.assertTrue(context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4205'), - QgsCoordinateReferenceSystem('EPSG:4326'), proj_2, False)) - - self.assertEqual(context.coordinateOperations(), - {('EPSG:4204', 'EPSG:4326'): proj_1, - ('EPSG:4205', 'EPSG:4326'): proj_2}) - self.assertTrue(context.allowFallbackTransform(QgsCoordinateReferenceSystem('EPSG:4204'), - QgsCoordinateReferenceSystem('EPSG:4326'))) - self.assertFalse(context.allowFallbackTransform(QgsCoordinateReferenceSystem('EPSG:4205'), - QgsCoordinateReferenceSystem('EPSG:4326'))) + self.assertTrue( + context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:4204"), + QgsCoordinateReferenceSystem("EPSG:4326"), + proj_1, + True, + ) + ) + self.assertTrue( + context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:4205"), + QgsCoordinateReferenceSystem("EPSG:4326"), + proj_2, + False, + ) + ) + + self.assertEqual( + context.coordinateOperations(), + {("EPSG:4204", "EPSG:4326"): proj_1, ("EPSG:4205", "EPSG:4326"): proj_2}, + ) + self.assertTrue( + context.allowFallbackTransform( + QgsCoordinateReferenceSystem("EPSG:4204"), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + ) + self.assertFalse( + context.allowFallbackTransform( + QgsCoordinateReferenceSystem("EPSG:4205"), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + ) # save to settings context.writeSettings() @@ -322,32 +609,51 @@ def testReadWriteSettingsProj6(self): context2.readSettings() # check result - self.assertEqual(context2.coordinateOperations(), - {('EPSG:4204', 'EPSG:4326'): proj_1, - ('EPSG:4205', 'EPSG:4326'): proj_2}) + self.assertEqual( + context2.coordinateOperations(), + {("EPSG:4204", "EPSG:4326"): proj_1, ("EPSG:4205", "EPSG:4326"): proj_2}, + ) - self.assertTrue(context2.allowFallbackTransform(QgsCoordinateReferenceSystem('EPSG:4204'), - QgsCoordinateReferenceSystem('EPSG:4326'))) - self.assertFalse(context2.allowFallbackTransform(QgsCoordinateReferenceSystem('EPSG:4205'), - QgsCoordinateReferenceSystem('EPSG:4326'))) + self.assertTrue( + context2.allowFallbackTransform( + QgsCoordinateReferenceSystem("EPSG:4204"), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + ) + self.assertFalse( + context2.allowFallbackTransform( + QgsCoordinateReferenceSystem("EPSG:4205"), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + ) def testEqualOperatorProj6(self): context1 = QgsCoordinateTransformContext() context2 = QgsCoordinateTransformContext() self.assertTrue(context1 == context2) - context1.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:4283'), 'p1') + context1.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + "p1", + ) self.assertFalse(context1 == context2) - context2.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:4283'), 'p1') + context2.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + "p1", + ) self.assertTrue(context1 == context2) - context2.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:4283'), 'p1', False) + context2.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + "p1", + False, + ) self.assertFalse(context1 == context2) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscore.py b/tests/src/python/test_qgscore.py index 723260cc12df..50a4fd50209f 100644 --- a/tests/src/python/test_qgscore.py +++ b/tests/src/python/test_qgscore.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Loïc Bartoletti' -__date__ = '28.6.2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Loïc Bartoletti" +__date__ = "28.6.2019" +__copyright__ = "Copyright 2019, The QGIS Project" from qgis.core import qgsDoubleNear, qgsRound @@ -40,11 +41,20 @@ def testQgsRound(self): qgsDoubleNear(qgsRound(-9.8765432198765, 7), -9.8765432, 0.0000001) qgsDoubleNear(qgsRound(9876543.2198765, 5), 9876543.219880, 0.000001) qgsDoubleNear(qgsRound(-9876543.2198765, 5), -9876543.219880, 0.000001) - qgsDoubleNear(qgsRound(9.87654321987654321, 13), 9.87654321987654, 0.0000000000001) - qgsDoubleNear(qgsRound(9.87654321987654321, 14), 9.876543219876543, 0.00000000000001) - qgsDoubleNear(qgsRound(9998.87654321987654321, 14), 9998.876543219876543, 0.00000000000001) - qgsDoubleNear(qgsRound(9999999.87654321987654321, 14), - 9999999.876543219876543, 0.00000000000001) + qgsDoubleNear( + qgsRound(9.87654321987654321, 13), 9.87654321987654, 0.0000000000001 + ) + qgsDoubleNear( + qgsRound(9.87654321987654321, 14), 9.876543219876543, 0.00000000000001 + ) + qgsDoubleNear( + qgsRound(9998.87654321987654321, 14), 9998.876543219876543, 0.00000000000001 + ) + qgsDoubleNear( + qgsRound(9999999.87654321987654321, 14), + 9999999.876543219876543, + 0.00000000000001, + ) if __name__ == "__main__": diff --git a/tests/src/python/test_qgscrsdefinitionwidget.py b/tests/src/python/test_qgscrsdefinitionwidget.py index f456bc1f1299..7226cddaf5eb 100644 --- a/tests/src/python/test_qgscrsdefinitionwidget.py +++ b/tests/src/python/test_qgscrsdefinitionwidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '12/12/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "12/12/2021" +__copyright__ = "Copyright 2021, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy from qgis.core import QgsCoordinateReferenceSystem @@ -30,13 +31,16 @@ def testWidget(self): self.assertEqual(w.format(), QgsCoordinateReferenceSystem.Format.FormatWkt) spy = QSignalSpy(w.crsChanged) - c = QgsCoordinateReferenceSystem('EPSG:3111') + c = QgsCoordinateReferenceSystem("EPSG:3111") w.setCrs(c) self.assertEqual(w.crs(), c) self.assertEqual(len(spy), 1) self.assertEqual(w.format(), QgsCoordinateReferenceSystem.Format.FormatWkt) - self.assertEqual(w.definitionString(), c.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED)) + self.assertEqual( + w.definitionString(), + c.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED), + ) # native proj string definition w.setCrs(c, QgsCoordinateReferenceSystem.Format.FormatProj) @@ -50,7 +54,10 @@ def testWidget(self): self.assertEqual(w.crs(), c) self.assertEqual(len(spy), 3) self.assertEqual(w.format(), QgsCoordinateReferenceSystem.Format.FormatWkt) - self.assertEqual(w.definitionString(), c.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED)) + self.assertEqual( + w.definitionString(), + c.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED), + ) # change format w.setFormat(QgsCoordinateReferenceSystem.Format.FormatProj) @@ -70,22 +77,32 @@ def test_definition_string(self): w = QgsCrsDefinitionWidget() w.setFormat(QgsCoordinateReferenceSystem.Format.FormatWkt) - c = QgsCoordinateReferenceSystem('EPSG:3111') + c = QgsCoordinateReferenceSystem("EPSG:3111") spy = QSignalSpy(w.crsChanged) - w.setDefinitionString(c.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED)) + w.setDefinitionString( + c.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED) + ) self.assertEqual(w.crs(), c) self.assertEqual(len(spy), 1) self.assertEqual(w.format(), QgsCoordinateReferenceSystem.Format.FormatWkt) - self.assertEqual(w.definitionString(), c.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED)) - - c2 = QgsCoordinateReferenceSystem('EPSG:3113') - w.setDefinitionString(c2.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED)) + self.assertEqual( + w.definitionString(), + c.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED), + ) + + c2 = QgsCoordinateReferenceSystem("EPSG:3113") + w.setDefinitionString( + c2.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED) + ) self.assertEqual(w.crs(), c2) self.assertEqual(len(spy), 2) self.assertEqual(w.format(), QgsCoordinateReferenceSystem.Format.FormatWkt) - self.assertEqual(w.definitionString(), c2.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED)) + self.assertEqual( + w.definitionString(), + c2.toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT_PREFERRED), + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgscrsselectionwidget.py b/tests/src/python/test_qgscrsselectionwidget.py index ab3a7708c45e..e95e5f803733 100644 --- a/tests/src/python/test_qgscrsselectionwidget.py +++ b/tests/src/python/test_qgscrsselectionwidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '12/12/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "12/12/2021" +__copyright__ = "Copyright 2021, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy from qgis.core import QgsCoordinateReferenceSystem @@ -31,7 +32,7 @@ def testWidget(self): spy = QSignalSpy(w.crsChanged) spy_valid_selection = QSignalSpy(w.hasValidSelectionChanged) - c = QgsCoordinateReferenceSystem('EPSG:3111') + c = QgsCoordinateReferenceSystem("EPSG:3111") w.setCrs(c) self.assertEqual(w.crs(), c) @@ -58,7 +59,7 @@ def testWidget(self): self.assertEqual(len(spy_valid_selection), 4) self.assertTrue(w.hasValidSelection()) - c2 = QgsCoordinateReferenceSystem('EPSG:3113') + c2 = QgsCoordinateReferenceSystem("EPSG:3113") w.setCrs(c2) self.assertEqual(w.crs(), c2) self.assertEqual(len(spy), 5) @@ -72,7 +73,7 @@ def testWidget(self): self.assertTrue(w.hasValidSelection()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() start_app() diff --git a/tests/src/python/test_qgsdatabaseschemacombobox.py b/tests/src/python/test_qgsdatabaseschemacombobox.py index 3e150677efbf..5da9de74b532 100644 --- a/tests/src/python/test_qgsdatabaseschemacombobox.py +++ b/tests/src/python/test_qgsdatabaseschemacombobox.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '8/03/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "8/03/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import os @@ -36,13 +37,17 @@ def setUpClass(cls): QCoreApplication.setApplicationName(cls.__name__) start_app() cls.postgres_conn = "service='qgis_test'" - if 'QGIS_PGTEST_DB' in os.environ: - cls.postgres_conn = os.environ['QGIS_PGTEST_DB'] - cls.uri = cls.postgres_conn + ' sslmode=disable' + if "QGIS_PGTEST_DB" in os.environ: + cls.postgres_conn = os.environ["QGIS_PGTEST_DB"] + cls.uri = cls.postgres_conn + " sslmode=disable" def testCombo(self): - """ test combobox functionality """ - conn = QgsProviderRegistry.instance().providerMetadata('postgres').createConnection(self.uri, {}) + """test combobox functionality""" + conn = ( + QgsProviderRegistry.instance() + .providerMetadata("postgres") + .createConnection(self.uri, {}) + ) self.assertTrue(conn) m = QgsDatabaseSchemaComboBox(conn) @@ -51,68 +56,74 @@ def testCombo(self): text = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] self.assertIn("CamelCase'singlequote'Schema", text) - self.assertIn('qgis_test', text) - self.assertLess(text.index("CamelCase'singlequote'Schema"), text.index('qgis_test')) + self.assertIn("qgis_test", text) + self.assertLess( + text.index("CamelCase'singlequote'Schema"), text.index("qgis_test") + ) self.assertEqual(m.currentSchema(), "CamelCase'singlequote'Schema") - m.setSchema('qgis_test') - self.assertEqual(m.currentSchema(), 'qgis_test') + m.setSchema("qgis_test") + self.assertEqual(m.currentSchema(), "qgis_test") self.assertEqual(len(spy), 1) - self.assertEqual(spy[-1][0], 'qgis_test') + self.assertEqual(spy[-1][0], "qgis_test") - m.setSchema('') + m.setSchema("") self.assertFalse(m.currentSchema()) self.assertEqual(len(spy), 2) self.assertFalse(spy[-1][0]) - m.setSchema('') + m.setSchema("") self.assertEqual(len(spy), 2) self.assertFalse(m.currentSchema()) - m.setSchema('qgis_test') + m.setSchema("qgis_test") self.assertEqual(len(spy), 3) - self.assertEqual(m.currentSchema(), 'qgis_test') - self.assertEqual(spy[-1][0], 'qgis_test') + self.assertEqual(m.currentSchema(), "qgis_test") + self.assertEqual(spy[-1][0], "qgis_test") - conn.createSchema('myNewSchema') + conn.createSchema("myNewSchema") text2 = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] # schemas are not automatically refreshed self.assertEqual(text2, text) # but setting a new connection should fix this! - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn2 = md.createConnection(self.uri, {}) - md.saveConnection(conn2, 'another') - m.setConnectionName('another', 'postgres') + md.saveConnection(conn2, "another") + m.setConnectionName("another", "postgres") # ideally there'd be no extra signal here, but it's a minor issue... self.assertEqual(len(spy), 4) - self.assertEqual(m.currentSchema(), 'qgis_test') - self.assertEqual(spy[-1][0], 'qgis_test') + self.assertEqual(m.currentSchema(), "qgis_test") + self.assertEqual(spy[-1][0], "qgis_test") text2 = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] self.assertNotEqual(text2, text) - self.assertIn('myNewSchema', text2) + self.assertIn("myNewSchema", text2) - m.setSchema('myNewSchema') + m.setSchema("myNewSchema") self.assertEqual(len(spy), 5) - self.assertEqual(m.currentSchema(), 'myNewSchema') - self.assertEqual(spy[-1][0], 'myNewSchema') + self.assertEqual(m.currentSchema(), "myNewSchema") + self.assertEqual(spy[-1][0], "myNewSchema") # no auto drop - conn.dropSchema('myNewSchema') + conn.dropSchema("myNewSchema") self.assertEqual(len(spy), 5) - self.assertEqual(m.currentSchema(), 'myNewSchema') - self.assertEqual(spy[-1][0], 'myNewSchema') + self.assertEqual(m.currentSchema(), "myNewSchema") + self.assertEqual(spy[-1][0], "myNewSchema") m.refreshSchemas() text2 = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] - self.assertNotIn('myNewSchema', text2) + self.assertNotIn("myNewSchema", text2) self.assertEqual(len(spy), 6) self.assertFalse(m.currentSchema()) self.assertFalse(spy[-1][0]) def testComboWithEmpty(self): - """ test combobox functionality with the empty row""" - conn = QgsProviderRegistry.instance().providerMetadata('postgres').createConnection(self.uri, {}) + """test combobox functionality with the empty row""" + conn = ( + QgsProviderRegistry.instance() + .providerMetadata("postgres") + .createConnection(self.uri, {}) + ) self.assertTrue(conn) m = QgsDatabaseSchemaComboBox(conn) @@ -125,68 +136,70 @@ def testComboWithEmpty(self): text = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] self.assertFalse(text[0]) self.assertIn("CamelCase'singlequote'Schema", text) - self.assertIn('qgis_test', text) - self.assertLess(text.index("CamelCase'singlequote'Schema"), text.index('qgis_test')) + self.assertIn("qgis_test", text) + self.assertLess( + text.index("CamelCase'singlequote'Schema"), text.index("qgis_test") + ) self.assertEqual(m.currentSchema(), "CamelCase'singlequote'Schema") - m.setSchema('qgis_test') - self.assertEqual(m.currentSchema(), 'qgis_test') + m.setSchema("qgis_test") + self.assertEqual(m.currentSchema(), "qgis_test") self.assertEqual(len(spy), 1) - self.assertEqual(spy[-1][0], 'qgis_test') + self.assertEqual(spy[-1][0], "qgis_test") - m.setSchema('') + m.setSchema("") self.assertEqual(m.comboBox().currentIndex(), 0) self.assertFalse(m.currentSchema()) self.assertEqual(len(spy), 2) self.assertFalse(spy[-1][0]) - m.setSchema('') + m.setSchema("") self.assertEqual(len(spy), 2) self.assertFalse(m.currentSchema()) - m.setSchema('qgis_test') + m.setSchema("qgis_test") self.assertEqual(len(spy), 3) - self.assertEqual(m.currentSchema(), 'qgis_test') - self.assertEqual(spy[-1][0], 'qgis_test') + self.assertEqual(m.currentSchema(), "qgis_test") + self.assertEqual(spy[-1][0], "qgis_test") - conn.createSchema('myNewSchema') + conn.createSchema("myNewSchema") text2 = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] # schemas are not automatically refreshed self.assertEqual(text2, text) # but setting a new connection should fix this! - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn2 = md.createConnection(self.uri, {}) - md.saveConnection(conn2, 'another') - m.setConnectionName('another', 'postgres') + md.saveConnection(conn2, "another") + m.setConnectionName("another", "postgres") # ideally there'd be no extra signal here, but it's a minor issue... self.assertEqual(len(spy), 4) - self.assertEqual(m.currentSchema(), 'qgis_test') - self.assertEqual(spy[-1][0], 'qgis_test') + self.assertEqual(m.currentSchema(), "qgis_test") + self.assertEqual(spy[-1][0], "qgis_test") text2 = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] self.assertNotEqual(text2, text) - self.assertIn('myNewSchema', text2) + self.assertIn("myNewSchema", text2) self.assertFalse(text2[0]) - m.setSchema('myNewSchema') + m.setSchema("myNewSchema") self.assertEqual(len(spy), 5) - self.assertEqual(m.currentSchema(), 'myNewSchema') - self.assertEqual(spy[-1][0], 'myNewSchema') + self.assertEqual(m.currentSchema(), "myNewSchema") + self.assertEqual(spy[-1][0], "myNewSchema") # no auto drop - conn.dropSchema('myNewSchema') + conn.dropSchema("myNewSchema") self.assertEqual(len(spy), 5) - self.assertEqual(m.currentSchema(), 'myNewSchema') - self.assertEqual(spy[-1][0], 'myNewSchema') + self.assertEqual(m.currentSchema(), "myNewSchema") + self.assertEqual(spy[-1][0], "myNewSchema") m.refreshSchemas() text2 = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] - self.assertNotIn('myNewSchema', text2) + self.assertNotIn("myNewSchema", text2) self.assertEqual(len(spy), 6) self.assertFalse(m.currentSchema()) self.assertFalse(spy[-1][0]) self.assertFalse(text2[0]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsdatabaseschemamodel.py b/tests/src/python/test_qgsdatabaseschemamodel.py index 8f09a4d1cc78..e9ea27d877b3 100644 --- a/tests/src/python/test_qgsdatabaseschemamodel.py +++ b/tests/src/python/test_qgsdatabaseschemamodel.py @@ -6,9 +6,10 @@ (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '07/03/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "07/03/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import os @@ -21,9 +22,9 @@ class TestPyQgsDatabaseSchemaModel(QgisTestCase): # Provider test cases must define the string URI for the test - uri = '' + uri = "" # Provider test cases must define the provider name (e.g. "postgres" or "ogr") - providerKey = 'postgres' + providerKey = "postgres" @classmethod def setUpClass(cls): @@ -35,77 +36,111 @@ def setUpClass(cls): QCoreApplication.setApplicationName(cls.__name__) start_app() cls.postgres_conn = "service='qgis_test'" - if 'QGIS_PGTEST_DB' in os.environ: - cls.postgres_conn = os.environ['QGIS_PGTEST_DB'] - cls.uri = cls.postgres_conn + ' sslmode=disable' + if "QGIS_PGTEST_DB" in os.environ: + cls.postgres_conn = os.environ["QGIS_PGTEST_DB"] + cls.uri = cls.postgres_conn + " sslmode=disable" def testModel(self): - conn = QgsProviderRegistry.instance().providerMetadata('postgres').createConnection(self.uri, {}) + conn = ( + QgsProviderRegistry.instance() + .providerMetadata("postgres") + .createConnection(self.uri, {}) + ) self.assertTrue(conn) model = QgsDatabaseSchemaModel(conn) self.assertGreaterEqual(model.rowCount(), 3) old_count = model.rowCount() self.assertEqual(model.columnCount(), 1) - schemas = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('public', schemas) + schemas = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("public", schemas) self.assertIn("CamelCase'singlequote'Schema", schemas) - self.assertIn('qgis_test', schemas) - self.assertEqual(model.data(model.index(schemas.index('qgis_test'), 0, QModelIndex()), Qt.ItemDataRole.ToolTipRole), 'qgis_test') - self.assertIsNone(model.data(model.index(model.rowCount(), 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) + self.assertIn("qgis_test", schemas) + self.assertEqual( + model.data( + model.index(schemas.index("qgis_test"), 0, QModelIndex()), + Qt.ItemDataRole.ToolTipRole, + ), + "qgis_test", + ) + self.assertIsNone( + model.data( + model.index(model.rowCount(), 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ) + ) model.refresh() self.assertEqual(model.rowCount(), old_count) - conn.createSchema('myNewSchema') + conn.createSchema("myNewSchema") self.assertEqual(model.rowCount(), old_count) model.refresh() self.assertEqual(model.rowCount(), old_count + 1) - schemas = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('public', schemas) + schemas = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("public", schemas) self.assertIn("CamelCase'singlequote'Schema", schemas) - self.assertIn('qgis_test', schemas) - self.assertIn('myNewSchema', schemas) + self.assertIn("qgis_test", schemas) + self.assertIn("myNewSchema", schemas) - conn.createSchema('myNewSchema2') - conn.createSchema('myNewSchema3') + conn.createSchema("myNewSchema2") + conn.createSchema("myNewSchema3") model.refresh() self.assertEqual(model.rowCount(), old_count + 3) - schemas = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('public', schemas) + schemas = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("public", schemas) self.assertIn("CamelCase'singlequote'Schema", schemas) - self.assertIn('qgis_test', schemas) - self.assertIn('myNewSchema', schemas) - self.assertIn('myNewSchema2', schemas) - self.assertIn('myNewSchema3', schemas) - - conn.createSchema('myNewSchema4') - conn.dropSchema('myNewSchema2') - conn.dropSchema('myNewSchema') + self.assertIn("qgis_test", schemas) + self.assertIn("myNewSchema", schemas) + self.assertIn("myNewSchema2", schemas) + self.assertIn("myNewSchema3", schemas) + + conn.createSchema("myNewSchema4") + conn.dropSchema("myNewSchema2") + conn.dropSchema("myNewSchema") model.refresh() self.assertEqual(model.rowCount(), old_count + 2) - schemas = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('public', schemas) + schemas = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("public", schemas) self.assertIn("CamelCase'singlequote'Schema", schemas) - self.assertIn('qgis_test', schemas) - self.assertNotIn('myNewSchema', schemas) - self.assertNotIn('myNewSchema2', schemas) - self.assertIn('myNewSchema3', schemas) - self.assertIn('myNewSchema4', schemas) - - conn.dropSchema('myNewSchema3') - conn.dropSchema('myNewSchema4') + self.assertIn("qgis_test", schemas) + self.assertNotIn("myNewSchema", schemas) + self.assertNotIn("myNewSchema2", schemas) + self.assertIn("myNewSchema3", schemas) + self.assertIn("myNewSchema4", schemas) + + conn.dropSchema("myNewSchema3") + conn.dropSchema("myNewSchema4") model.refresh() self.assertEqual(model.rowCount(), old_count) - schemas = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('public', schemas) + schemas = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("public", schemas) self.assertIn("CamelCase'singlequote'Schema", schemas) - self.assertIn('qgis_test', schemas) - self.assertNotIn('myNewSchema3', schemas) - self.assertNotIn('myNewSchema4', schemas) + self.assertIn("qgis_test", schemas) + self.assertNotIn("myNewSchema3", schemas) + self.assertNotIn("myNewSchema4", schemas) def test_model_allow_empty(self): """Test model with empty entry""" - conn = QgsProviderRegistry.instance().providerMetadata('postgres').createConnection(self.uri, {}) + conn = ( + QgsProviderRegistry.instance() + .providerMetadata("postgres") + .createConnection(self.uri, {}) + ) self.assertTrue(conn) model = QgsDatabaseSchemaModel(conn) self.assertGreaterEqual(model.rowCount(), 3) @@ -113,92 +148,190 @@ def test_model_allow_empty(self): model.setAllowEmptySchema(True) self.assertEqual(model.rowCount(), old_count + 1) - schemas = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('public', schemas) + schemas = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("public", schemas) self.assertIn("CamelCase'singlequote'Schema", schemas) - self.assertIn('qgis_test', schemas) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty)) - self.assertFalse(model.data(model.index(schemas.index('qgis_test'), 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty)) - self.assertIsNone(model.data(model.index(model.rowCount(), 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) + self.assertIn("qgis_test", schemas) + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertTrue( + model.data( + model.index(0, 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty + ) + ) + self.assertFalse( + model.data( + model.index(schemas.index("qgis_test"), 0, QModelIndex()), + QgsDatabaseSchemaModel.Role.RoleEmpty, + ) + ) + self.assertIsNone( + model.data( + model.index(model.rowCount(), 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ) + ) model.refresh() self.assertEqual(model.rowCount(), old_count + 1) - conn.createSchema('myNewSchema') + conn.createSchema("myNewSchema") self.assertEqual(model.rowCount(), old_count + 1) model.refresh() self.assertEqual(model.rowCount(), old_count + 2) - schemas = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('public', schemas) + schemas = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("public", schemas) self.assertIn("CamelCase'singlequote'Schema", schemas) - self.assertIn('qgis_test', schemas) - self.assertIn('myNewSchema', schemas) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty)) - self.assertFalse(model.data(model.index(schemas.index('qgis_test'), 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty)) + self.assertIn("qgis_test", schemas) + self.assertIn("myNewSchema", schemas) + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertTrue( + model.data( + model.index(0, 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty + ) + ) + self.assertFalse( + model.data( + model.index(schemas.index("qgis_test"), 0, QModelIndex()), + QgsDatabaseSchemaModel.Role.RoleEmpty, + ) + ) model.setAllowEmptySchema(False) self.assertEqual(model.rowCount(), old_count + 1) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty)) + self.assertTrue( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertFalse( + model.data( + model.index(0, 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty + ) + ) model.setAllowEmptySchema(True) self.assertEqual(model.rowCount(), old_count + 2) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty)) - self.assertFalse(model.data(model.index(schemas.index('qgis_test'), 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty)) + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertTrue( + model.data( + model.index(0, 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty + ) + ) + self.assertFalse( + model.data( + model.index(schemas.index("qgis_test"), 0, QModelIndex()), + QgsDatabaseSchemaModel.Role.RoleEmpty, + ) + ) - conn.createSchema('myNewSchema2') - conn.createSchema('myNewSchema3') + conn.createSchema("myNewSchema2") + conn.createSchema("myNewSchema3") model.refresh() self.assertEqual(model.rowCount(), old_count + 4) - schemas = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('public', schemas) + schemas = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("public", schemas) self.assertIn("CamelCase'singlequote'Schema", schemas) - self.assertIn('qgis_test', schemas) - self.assertIn('myNewSchema', schemas) - self.assertIn('myNewSchema2', schemas) - self.assertIn('myNewSchema3', schemas) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty)) - self.assertFalse(model.data(model.index(schemas.index('qgis_test'), 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty)) - - conn.createSchema('myNewSchema4') - conn.dropSchema('myNewSchema2') - conn.dropSchema('myNewSchema') + self.assertIn("qgis_test", schemas) + self.assertIn("myNewSchema", schemas) + self.assertIn("myNewSchema2", schemas) + self.assertIn("myNewSchema3", schemas) + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertTrue( + model.data( + model.index(0, 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty + ) + ) + self.assertFalse( + model.data( + model.index(schemas.index("qgis_test"), 0, QModelIndex()), + QgsDatabaseSchemaModel.Role.RoleEmpty, + ) + ) + + conn.createSchema("myNewSchema4") + conn.dropSchema("myNewSchema2") + conn.dropSchema("myNewSchema") model.refresh() self.assertEqual(model.rowCount(), old_count + 3) - schemas = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('public', schemas) + schemas = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("public", schemas) self.assertIn("CamelCase'singlequote'Schema", schemas) - self.assertIn('qgis_test', schemas) - self.assertNotIn('myNewSchema', schemas) - self.assertNotIn('myNewSchema2', schemas) - self.assertIn('myNewSchema3', schemas) - self.assertIn('myNewSchema4', schemas) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty)) - self.assertFalse(model.data(model.index(schemas.index('qgis_test'), 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty)) - - conn.dropSchema('myNewSchema3') - conn.dropSchema('myNewSchema4') + self.assertIn("qgis_test", schemas) + self.assertNotIn("myNewSchema", schemas) + self.assertNotIn("myNewSchema2", schemas) + self.assertIn("myNewSchema3", schemas) + self.assertIn("myNewSchema4", schemas) + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertTrue( + model.data( + model.index(0, 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty + ) + ) + self.assertFalse( + model.data( + model.index(schemas.index("qgis_test"), 0, QModelIndex()), + QgsDatabaseSchemaModel.Role.RoleEmpty, + ) + ) + + conn.dropSchema("myNewSchema3") + conn.dropSchema("myNewSchema4") model.refresh() self.assertEqual(model.rowCount(), old_count + 1) - schemas = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('public', schemas) + schemas = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("public", schemas) self.assertIn("CamelCase'singlequote'Schema", schemas) - self.assertIn('qgis_test', schemas) - self.assertNotIn('myNewSchema3', schemas) - self.assertNotIn('myNewSchema4', schemas) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty)) - self.assertFalse(model.data(model.index(schemas.index('qgis_test'), 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty)) + self.assertIn("qgis_test", schemas) + self.assertNotIn("myNewSchema3", schemas) + self.assertNotIn("myNewSchema4", schemas) + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertTrue( + model.data( + model.index(0, 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty + ) + ) + self.assertFalse( + model.data( + model.index(schemas.index("qgis_test"), 0, QModelIndex()), + QgsDatabaseSchemaModel.Role.RoleEmpty, + ) + ) model.setAllowEmptySchema(False) self.assertEqual(model.rowCount(), old_count) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty)) + self.assertTrue( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertFalse( + model.data( + model.index(0, 0, QModelIndex()), QgsDatabaseSchemaModel.Role.RoleEmpty + ) + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsdatabasetablecombobox.py b/tests/src/python/test_qgsdatabasetablecombobox.py index 9244831525fe..20e5055c2ff2 100644 --- a/tests/src/python/test_qgsdatabasetablecombobox.py +++ b/tests/src/python/test_qgsdatabasetablecombobox.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '8/03/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "8/03/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import os @@ -42,182 +43,204 @@ def setUpClass(cls): QCoreApplication.setApplicationName(cls.__name__) start_app() cls.postgres_conn = "service='qgis_test'" - if 'QGIS_PGTEST_DB' in os.environ: - cls.postgres_conn = os.environ['QGIS_PGTEST_DB'] - cls.uri = cls.postgres_conn + ' sslmode=disable' + if "QGIS_PGTEST_DB" in os.environ: + cls.postgres_conn = os.environ["QGIS_PGTEST_DB"] + cls.uri = cls.postgres_conn + " sslmode=disable" def testCombo(self): - """ test combobox functionality """ - md = QgsProviderRegistry.instance().providerMetadata('postgres') + """test combobox functionality""" + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.uri, {}) - md.saveConnection(conn, 'mycon') + md.saveConnection(conn, "mycon") - m = QgsDatabaseTableComboBox('postgres', 'mycon') + m = QgsDatabaseTableComboBox("postgres", "mycon") self.assertGreaterEqual(m.comboBox().count(), 3) text = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] - self.assertIn('information_schema.attributes', text) - self.assertIn('qgis_test.some_poly_data', text) - self.assertLess(text.index('information_schema.attributes'), text.index('qgis_test.some_poly_data')) + self.assertIn("information_schema.attributes", text) + self.assertIn("qgis_test.some_poly_data", text) + self.assertLess( + text.index("information_schema.attributes"), + text.index("qgis_test.some_poly_data"), + ) self.assertTrue(m.currentSchema()) self.assertTrue(m.currentTable()) - m.setSchema('information_schema') - m.setTable('attributes') + m.setSchema("information_schema") + m.setTable("attributes") spy = QSignalSpy(m.tableChanged) - m.setSchema('qgis_test') + m.setSchema("qgis_test") text = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] - self.assertNotIn('information_schema.attributes', text) - self.assertNotIn('attributes', text) - self.assertIn('some_poly_data', text) + self.assertNotIn("information_schema.attributes", text) + self.assertNotIn("attributes", text) + self.assertIn("some_poly_data", text) - self.assertEqual(m.currentTable(), '') - self.assertEqual(m.currentSchema(), '') + self.assertEqual(m.currentTable(), "") + self.assertEqual(m.currentSchema(), "") self.assertEqual(len(spy), 1) self.assertFalse(spy[-1][0]) - m.setTable('') - self.assertEqual(m.currentTable(), '') - self.assertEqual(m.currentSchema(), '') + m.setTable("") + self.assertEqual(m.currentTable(), "") + self.assertEqual(m.currentSchema(), "") self.assertEqual(len(spy), 1) self.assertFalse(spy[-1][0]) - m.setTable('someData') + m.setTable("someData") self.assertEqual(len(spy), 2) - self.assertEqual(m.currentSchema(), 'qgis_test') - self.assertEqual(m.currentTable(), 'someData') - self.assertEqual(spy[-1][0], 'someData') - self.assertEqual(spy[-1][1], 'qgis_test') + self.assertEqual(m.currentSchema(), "qgis_test") + self.assertEqual(m.currentTable(), "someData") + self.assertEqual(spy[-1][0], "someData") + self.assertEqual(spy[-1][1], "qgis_test") fields = QgsFields() - fields.append(QgsField('test', QVariant.String)) - conn.createVectorTable('qgis_test', 'myNewTable', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:3857'), False, {}) + fields.append(QgsField("test", QVariant.String)) + conn.createVectorTable( + "qgis_test", + "myNewTable", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:3857"), + False, + {}, + ) text2 = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] # tables are not automatically refreshed self.assertEqual(text2, text) # but setting a new connection should fix this! - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn2 = md.createConnection(self.uri, {}) - md.saveConnection(conn2, 'another') - m.setConnectionName('another', 'postgres') + md.saveConnection(conn2, "another") + m.setConnectionName("another", "postgres") # ideally there'd be no extra signal here, but it's a minor issue... self.assertEqual(len(spy), 3) - self.assertEqual(m.currentTable(), 'someData') - self.assertEqual(m.currentSchema(), 'qgis_test') - self.assertEqual(spy[-1][0], 'someData') - self.assertEqual(spy[-1][1], 'qgis_test') + self.assertEqual(m.currentTable(), "someData") + self.assertEqual(m.currentSchema(), "qgis_test") + self.assertEqual(spy[-1][0], "someData") + self.assertEqual(spy[-1][1], "qgis_test") text2 = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] self.assertNotEqual(text2, text) - self.assertIn('myNewTable', text2) + self.assertIn("myNewTable", text2) - m.setTable('myNewTable') + m.setTable("myNewTable") self.assertEqual(len(spy), 4) - self.assertEqual(m.currentTable(), 'myNewTable') - self.assertEqual(m.currentSchema(), 'qgis_test') - self.assertEqual(spy[-1][0], 'myNewTable') - self.assertEqual(spy[-1][1], 'qgis_test') + self.assertEqual(m.currentTable(), "myNewTable") + self.assertEqual(m.currentSchema(), "qgis_test") + self.assertEqual(spy[-1][0], "myNewTable") + self.assertEqual(spy[-1][1], "qgis_test") # no auto drop - conn.dropVectorTable('qgis_test', 'myNewTable') + conn.dropVectorTable("qgis_test", "myNewTable") self.assertEqual(len(spy), 4) - self.assertEqual(m.currentTable(), 'myNewTable') - self.assertEqual(m.currentSchema(), 'qgis_test') - self.assertEqual(spy[-1][0], 'myNewTable') - self.assertEqual(spy[-1][1], 'qgis_test') + self.assertEqual(m.currentTable(), "myNewTable") + self.assertEqual(m.currentSchema(), "qgis_test") + self.assertEqual(spy[-1][0], "myNewTable") + self.assertEqual(spy[-1][1], "qgis_test") m.refreshTables() text2 = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] - self.assertNotIn('myNewTable', text2) + self.assertNotIn("myNewTable", text2) self.assertEqual(len(spy), 5) self.assertFalse(m.currentSchema()) self.assertFalse(spy[-1][0]) def testComboAllSchemas(self): - """ test combobox functionality showing all schemas """ - md = QgsProviderRegistry.instance().providerMetadata('postgres') + """test combobox functionality showing all schemas""" + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.uri, {}) - md.saveConnection(conn, 'mycon2') + md.saveConnection(conn, "mycon2") - m = QgsDatabaseTableComboBox('postgres', 'mycon2') + m = QgsDatabaseTableComboBox("postgres", "mycon2") self.assertGreaterEqual(m.comboBox().count(), 3) text = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] - self.assertIn('information_schema.attributes', text) - self.assertIn('qgis_test.some_poly_data', text) - self.assertLess(text.index('information_schema.attributes'), text.index('qgis_test.some_poly_data')) + self.assertIn("information_schema.attributes", text) + self.assertIn("qgis_test.some_poly_data", text) + self.assertLess( + text.index("information_schema.attributes"), + text.index("qgis_test.some_poly_data"), + ) self.assertTrue(m.currentSchema()) self.assertTrue(m.currentTable()) spy = QSignalSpy(m.tableChanged) - m.setTable('') - self.assertEqual(m.currentTable(), '') - self.assertEqual(m.currentSchema(), '') + m.setTable("") + self.assertEqual(m.currentTable(), "") + self.assertEqual(m.currentSchema(), "") self.assertEqual(len(spy), 1) self.assertFalse(spy[-1][0]) - m.setTable('someData', 'qgis_test') + m.setTable("someData", "qgis_test") self.assertEqual(len(spy), 2) - self.assertEqual(m.currentSchema(), 'qgis_test') - self.assertEqual(m.currentTable(), 'someData') - self.assertEqual(spy[-1][0], 'someData') - self.assertEqual(spy[-1][1], 'qgis_test') + self.assertEqual(m.currentSchema(), "qgis_test") + self.assertEqual(m.currentTable(), "someData") + self.assertEqual(spy[-1][0], "someData") + self.assertEqual(spy[-1][1], "qgis_test") fields = QgsFields() - fields.append(QgsField('test', QVariant.String)) - conn.createVectorTable('qgis_test', 'myNewTable', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:3857'), False, {}) + fields.append(QgsField("test", QVariant.String)) + conn.createVectorTable( + "qgis_test", + "myNewTable", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:3857"), + False, + {}, + ) text2 = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] # tables are not automatically refreshed self.assertEqual(text2, text) # but setting a new connection should fix this! - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn2 = md.createConnection(self.uri, {}) - md.saveConnection(conn2, 'another') - m.setConnectionName('another', 'postgres') + md.saveConnection(conn2, "another") + m.setConnectionName("another", "postgres") # ideally there'd be no extra signal here, but it's a minor issue... self.assertEqual(len(spy), 3) - self.assertEqual(m.currentTable(), 'someData') - self.assertEqual(m.currentSchema(), 'qgis_test') - self.assertEqual(spy[-1][0], 'someData') - self.assertEqual(spy[-1][1], 'qgis_test') + self.assertEqual(m.currentTable(), "someData") + self.assertEqual(m.currentSchema(), "qgis_test") + self.assertEqual(spy[-1][0], "someData") + self.assertEqual(spy[-1][1], "qgis_test") text2 = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] self.assertNotEqual(text2, text) - self.assertIn('qgis_test.myNewTable', text2) + self.assertIn("qgis_test.myNewTable", text2) - m.setTable('myNewTable', 'qgis_test') + m.setTable("myNewTable", "qgis_test") self.assertEqual(len(spy), 4) - self.assertEqual(m.currentTable(), 'myNewTable') - self.assertEqual(m.currentSchema(), 'qgis_test') - self.assertEqual(spy[-1][0], 'myNewTable') - self.assertEqual(spy[-1][1], 'qgis_test') + self.assertEqual(m.currentTable(), "myNewTable") + self.assertEqual(m.currentSchema(), "qgis_test") + self.assertEqual(spy[-1][0], "myNewTable") + self.assertEqual(spy[-1][1], "qgis_test") # no auto drop - conn.dropVectorTable('qgis_test', 'myNewTable') + conn.dropVectorTable("qgis_test", "myNewTable") self.assertEqual(len(spy), 4) - self.assertEqual(m.currentTable(), 'myNewTable') - self.assertEqual(m.currentSchema(), 'qgis_test') - self.assertEqual(spy[-1][0], 'myNewTable') - self.assertEqual(spy[-1][1], 'qgis_test') + self.assertEqual(m.currentTable(), "myNewTable") + self.assertEqual(m.currentSchema(), "qgis_test") + self.assertEqual(spy[-1][0], "myNewTable") + self.assertEqual(spy[-1][1], "qgis_test") m.refreshTables() text2 = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] - self.assertNotIn('qgis_test.myNewTable', text2) + self.assertNotIn("qgis_test.myNewTable", text2) self.assertEqual(len(spy), 5) self.assertFalse(m.currentSchema()) self.assertFalse(spy[-1][0]) def testComboWithEmpty(self): - """ test combobox functionality with empty choice """ - md = QgsProviderRegistry.instance().providerMetadata('postgres') + """test combobox functionality with empty choice""" + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.uri, {}) - md.saveConnection(conn, 'mycon') + md.saveConnection(conn, "mycon") - m = QgsDatabaseTableComboBox('postgres', 'mycon') + m = QgsDatabaseTableComboBox("postgres", "mycon") old_count = m.comboBox().count() self.assertGreaterEqual(old_count, 3) @@ -226,85 +249,96 @@ def testComboWithEmpty(self): text = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] self.assertFalse(text[0]) - self.assertIn('information_schema.attributes', text) - self.assertIn('qgis_test.some_poly_data', text) - self.assertLess(text.index('information_schema.attributes'), text.index('qgis_test.some_poly_data')) + self.assertIn("information_schema.attributes", text) + self.assertIn("qgis_test.some_poly_data", text) + self.assertLess( + text.index("information_schema.attributes"), + text.index("qgis_test.some_poly_data"), + ) self.assertTrue(m.currentSchema()) self.assertTrue(m.currentTable()) - m.setSchema('information_schema') - m.setTable('attributes') + m.setSchema("information_schema") + m.setTable("attributes") spy = QSignalSpy(m.tableChanged) - m.setSchema('qgis_test') + m.setSchema("qgis_test") text = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] - self.assertNotIn('information_schema.attributes', text) - self.assertNotIn('attributes', text) - self.assertIn('some_poly_data', text) + self.assertNotIn("information_schema.attributes", text) + self.assertNotIn("attributes", text) + self.assertIn("some_poly_data", text) - self.assertEqual(m.currentTable(), '') - self.assertEqual(m.currentSchema(), '') + self.assertEqual(m.currentTable(), "") + self.assertEqual(m.currentSchema(), "") self.assertEqual(len(spy), 1) self.assertFalse(spy[-1][0]) - m.setTable('') - self.assertEqual(m.currentTable(), '') - self.assertEqual(m.currentSchema(), '') + m.setTable("") + self.assertEqual(m.currentTable(), "") + self.assertEqual(m.currentSchema(), "") self.assertEqual(len(spy), 1) self.assertFalse(spy[-1][0]) - m.setTable('someData') + m.setTable("someData") self.assertEqual(len(spy), 2) - self.assertEqual(m.currentSchema(), 'qgis_test') - self.assertEqual(m.currentTable(), 'someData') - self.assertEqual(spy[-1][0], 'someData') - self.assertEqual(spy[-1][1], 'qgis_test') + self.assertEqual(m.currentSchema(), "qgis_test") + self.assertEqual(m.currentTable(), "someData") + self.assertEqual(spy[-1][0], "someData") + self.assertEqual(spy[-1][1], "qgis_test") fields = QgsFields() - fields.append(QgsField('test', QVariant.String)) - conn.createVectorTable('qgis_test', 'myNewTable', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:3857'), False, {}) + fields.append(QgsField("test", QVariant.String)) + conn.createVectorTable( + "qgis_test", + "myNewTable", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:3857"), + False, + {}, + ) text2 = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] # tables are not automatically refreshed self.assertEqual(text2, text) # but setting a new connection should fix this! - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn2 = md.createConnection(self.uri, {}) - md.saveConnection(conn2, 'another') - m.setConnectionName('another', 'postgres') + md.saveConnection(conn2, "another") + m.setConnectionName("another", "postgres") # ideally there'd be no extra signal here, but it's a minor issue... self.assertEqual(len(spy), 3) - self.assertEqual(m.currentTable(), 'someData') - self.assertEqual(m.currentSchema(), 'qgis_test') - self.assertEqual(spy[-1][0], 'someData') - self.assertEqual(spy[-1][1], 'qgis_test') + self.assertEqual(m.currentTable(), "someData") + self.assertEqual(m.currentSchema(), "qgis_test") + self.assertEqual(spy[-1][0], "someData") + self.assertEqual(spy[-1][1], "qgis_test") text2 = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] self.assertNotEqual(text2, text) - self.assertIn('myNewTable', text2) + self.assertIn("myNewTable", text2) - m.setTable('myNewTable') + m.setTable("myNewTable") self.assertEqual(len(spy), 4) - self.assertEqual(m.currentTable(), 'myNewTable') - self.assertEqual(m.currentSchema(), 'qgis_test') - self.assertEqual(spy[-1][0], 'myNewTable') - self.assertEqual(spy[-1][1], 'qgis_test') + self.assertEqual(m.currentTable(), "myNewTable") + self.assertEqual(m.currentSchema(), "qgis_test") + self.assertEqual(spy[-1][0], "myNewTable") + self.assertEqual(spy[-1][1], "qgis_test") # no auto drop - conn.dropVectorTable('qgis_test', 'myNewTable') + conn.dropVectorTable("qgis_test", "myNewTable") self.assertEqual(len(spy), 4) - self.assertEqual(m.currentTable(), 'myNewTable') - self.assertEqual(m.currentSchema(), 'qgis_test') - self.assertEqual(spy[-1][0], 'myNewTable') - self.assertEqual(spy[-1][1], 'qgis_test') + self.assertEqual(m.currentTable(), "myNewTable") + self.assertEqual(m.currentSchema(), "qgis_test") + self.assertEqual(spy[-1][0], "myNewTable") + self.assertEqual(spy[-1][1], "qgis_test") m.refreshTables() text2 = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] - self.assertNotIn('myNewTable', text2) + self.assertNotIn("myNewTable", text2) self.assertEqual(len(spy), 5) self.assertFalse(m.currentSchema()) self.assertFalse(spy[-1][0]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsdatabasetablemodel.py b/tests/src/python/test_qgsdatabasetablemodel.py index 6f85b9963766..d3a21d3ec730 100644 --- a/tests/src/python/test_qgsdatabasetablemodel.py +++ b/tests/src/python/test_qgsdatabasetablemodel.py @@ -6,9 +6,10 @@ (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '07/03/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "07/03/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import os @@ -27,9 +28,9 @@ class TestPyQgsDatabaseTableModel(QgisTestCase): # Provider test cases must define the string URI for the test - uri = '' + uri = "" # Provider test cases must define the provider name (e.g. "postgres" or "ogr") - providerKey = 'postgres' + providerKey = "postgres" @classmethod def setUpClass(cls): @@ -41,125 +42,277 @@ def setUpClass(cls): QCoreApplication.setApplicationName(cls.__name__) start_app() cls.postgres_conn = "service='qgis_test'" - if 'QGIS_PGTEST_DB' in os.environ: - cls.postgres_conn = os.environ['QGIS_PGTEST_DB'] - cls.uri = cls.postgres_conn + ' sslmode=disable' + if "QGIS_PGTEST_DB" in os.environ: + cls.postgres_conn = os.environ["QGIS_PGTEST_DB"] + cls.uri = cls.postgres_conn + " sslmode=disable" def testModel(self): - conn = QgsProviderRegistry.instance().providerMetadata('postgres').createConnection(self.uri, {}) + conn = ( + QgsProviderRegistry.instance() + .providerMetadata("postgres") + .createConnection(self.uri, {}) + ) self.assertTrue(conn) model = QgsDatabaseTableModel(conn) self.assertGreaterEqual(model.rowCount(), 3) old_count = model.rowCount() self.assertEqual(model.columnCount(), 1) - tables = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('qgis_test.someData', tables) - self.assertIn('qgis_test.some_poly_data', tables) - self.assertIn('information_schema.attributes', tables) - self.assertEqual(model.data(model.index(tables.index('qgis_test.someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleTableName), 'someData') - self.assertEqual(model.data(model.index(tables.index('qgis_test.someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleSchema), 'qgis_test') - self.assertEqual(model.data(model.index(tables.index('qgis_test.someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleComment), 'QGIS Test Table') - self.assertEqual(model.data(model.index(tables.index('qgis_test.someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleCrs), QgsCoordinateReferenceSystem('EPSG:4326')) - self.assertEqual(model.data(model.index(tables.index('qgis_test.someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleCustomInfo), {}) - self.assertEqual(model.data(model.index(tables.index('qgis_test.someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleTableFlags), 4) - self.assertEqual(model.data(model.index(tables.index('qgis_test.someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleWkbType), QgsWkbTypes.Type.Point) - self.assertEqual(model.data(model.index(tables.index('qgis_test.some_poly_data'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleWkbType), QgsWkbTypes.Type.Polygon) - self.assertIsNone(model.data(model.index(model.rowCount(), 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) + tables = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("qgis_test.someData", tables) + self.assertIn("qgis_test.some_poly_data", tables) + self.assertIn("information_schema.attributes", tables) + self.assertEqual( + model.data( + model.index(tables.index("qgis_test.someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleTableName, + ), + "someData", + ) + self.assertEqual( + model.data( + model.index(tables.index("qgis_test.someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleSchema, + ), + "qgis_test", + ) + self.assertEqual( + model.data( + model.index(tables.index("qgis_test.someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleComment, + ), + "QGIS Test Table", + ) + self.assertEqual( + model.data( + model.index(tables.index("qgis_test.someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleCrs, + ), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + self.assertEqual( + model.data( + model.index(tables.index("qgis_test.someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleCustomInfo, + ), + {}, + ) + self.assertEqual( + model.data( + model.index(tables.index("qgis_test.someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleTableFlags, + ), + 4, + ) + self.assertEqual( + model.data( + model.index(tables.index("qgis_test.someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleWkbType, + ), + QgsWkbTypes.Type.Point, + ) + self.assertEqual( + model.data( + model.index(tables.index("qgis_test.some_poly_data"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleWkbType, + ), + QgsWkbTypes.Type.Polygon, + ) + self.assertIsNone( + model.data( + model.index(model.rowCount(), 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ) + ) model.refresh() self.assertEqual(model.rowCount(), old_count) fields = QgsFields() - fields.append(QgsField('test', QVariant.String)) - conn.createVectorTable('qgis_test', 'myNewTable', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:3857'), False, {}) + fields.append(QgsField("test", QVariant.String)) + conn.createVectorTable( + "qgis_test", + "myNewTable", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:3857"), + False, + {}, + ) self.assertEqual(model.rowCount(), old_count) model.refresh() self.assertEqual(model.rowCount(), old_count + 1) - tables = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('qgis_test.someData', tables) - self.assertIn('qgis_test.some_poly_data', tables) - self.assertIn('information_schema.attributes', tables) - self.assertIn('qgis_test.myNewTable', tables) - - conn.createVectorTable('qgis_test', 'myNewTable2', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:3857'), False, {}) - conn.createVectorTable('qgis_test', 'myNewTable3', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:3857'), False, {}) + tables = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("qgis_test.someData", tables) + self.assertIn("qgis_test.some_poly_data", tables) + self.assertIn("information_schema.attributes", tables) + self.assertIn("qgis_test.myNewTable", tables) + + conn.createVectorTable( + "qgis_test", + "myNewTable2", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:3857"), + False, + {}, + ) + conn.createVectorTable( + "qgis_test", + "myNewTable3", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:3857"), + False, + {}, + ) model.refresh() self.assertEqual(model.rowCount(), old_count + 3) - tables = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('qgis_test.someData', tables) - self.assertIn('qgis_test.some_poly_data', tables) - self.assertIn('information_schema.attributes', tables) - self.assertIn('qgis_test.myNewTable', tables) - self.assertIn('qgis_test.myNewTable2', tables) - self.assertIn('qgis_test.myNewTable3', tables) - - conn.createVectorTable('qgis_test', 'myNewTable4', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:3857'), False, {}) - conn.dropVectorTable('qgis_test', 'myNewTable2') - conn.dropVectorTable('qgis_test', 'myNewTable') + tables = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("qgis_test.someData", tables) + self.assertIn("qgis_test.some_poly_data", tables) + self.assertIn("information_schema.attributes", tables) + self.assertIn("qgis_test.myNewTable", tables) + self.assertIn("qgis_test.myNewTable2", tables) + self.assertIn("qgis_test.myNewTable3", tables) + + conn.createVectorTable( + "qgis_test", + "myNewTable4", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:3857"), + False, + {}, + ) + conn.dropVectorTable("qgis_test", "myNewTable2") + conn.dropVectorTable("qgis_test", "myNewTable") model.refresh() self.assertEqual(model.rowCount(), old_count + 2) - tables = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('qgis_test.someData', tables) - self.assertIn('qgis_test.some_poly_data', tables) - self.assertIn('information_schema.attributes', tables) - self.assertNotIn('qgis_test.myNewTable', tables) - self.assertNotIn('qgis_test.myNewTable2', tables) - self.assertIn('qgis_test.myNewTable3', tables) - self.assertIn('qgis_test.myNewTable4', tables) - - conn.dropVectorTable('qgis_test', 'myNewTable3') - conn.dropVectorTable('qgis_test', 'myNewTable4') + tables = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("qgis_test.someData", tables) + self.assertIn("qgis_test.some_poly_data", tables) + self.assertIn("information_schema.attributes", tables) + self.assertNotIn("qgis_test.myNewTable", tables) + self.assertNotIn("qgis_test.myNewTable2", tables) + self.assertIn("qgis_test.myNewTable3", tables) + self.assertIn("qgis_test.myNewTable4", tables) + + conn.dropVectorTable("qgis_test", "myNewTable3") + conn.dropVectorTable("qgis_test", "myNewTable4") model.refresh() self.assertEqual(model.rowCount(), old_count) - tables = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('qgis_test.someData', tables) - self.assertIn('qgis_test.some_poly_data', tables) - self.assertIn('information_schema.attributes', tables) - self.assertNotIn('qgis_test.myNewTable', tables) - self.assertNotIn('qgis_test.myNewTable2', tables) - self.assertNotIn('qgis_test.myNewTable3', tables) - self.assertNotIn('qgis_test.myNewTable4', tables) + tables = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("qgis_test.someData", tables) + self.assertIn("qgis_test.some_poly_data", tables) + self.assertIn("information_schema.attributes", tables) + self.assertNotIn("qgis_test.myNewTable", tables) + self.assertNotIn("qgis_test.myNewTable2", tables) + self.assertNotIn("qgis_test.myNewTable3", tables) + self.assertNotIn("qgis_test.myNewTable4", tables) def testModelSpecificSchema(self): - conn = QgsProviderRegistry.instance().providerMetadata('postgres').createConnection(self.uri, {}) + conn = ( + QgsProviderRegistry.instance() + .providerMetadata("postgres") + .createConnection(self.uri, {}) + ) self.assertTrue(conn) - model = QgsDatabaseTableModel(conn, 'qgis_test') + model = QgsDatabaseTableModel(conn, "qgis_test") self.assertGreaterEqual(model.rowCount(), 3) old_count = model.rowCount() self.assertEqual(model.columnCount(), 1) - tables = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('someData', tables) - self.assertIn('some_poly_data', tables) - self.assertNotIn('attributes', tables) - self.assertEqual(model.data(model.index(tables.index('someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleTableName), 'someData') - self.assertEqual(model.data(model.index(tables.index('someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleSchema), 'qgis_test') - self.assertEqual(model.data(model.index(tables.index('someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleComment), 'QGIS Test Table') - self.assertEqual(model.data(model.index(tables.index('someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleCrs), QgsCoordinateReferenceSystem('EPSG:4326')) - self.assertEqual(model.data(model.index(tables.index('someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleCustomInfo), {}) - self.assertEqual(model.data(model.index(tables.index('someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleTableFlags), 4) - self.assertEqual(model.data(model.index(tables.index('someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleWkbType), QgsWkbTypes.Type.Point) - self.assertEqual(model.data(model.index(tables.index('some_poly_data'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleWkbType), QgsWkbTypes.Type.Polygon) - self.assertIsNone(model.data(model.index(model.rowCount(), 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) + tables = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("someData", tables) + self.assertIn("some_poly_data", tables) + self.assertNotIn("attributes", tables) + self.assertEqual( + model.data( + model.index(tables.index("someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleTableName, + ), + "someData", + ) + self.assertEqual( + model.data( + model.index(tables.index("someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleSchema, + ), + "qgis_test", + ) + self.assertEqual( + model.data( + model.index(tables.index("someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleComment, + ), + "QGIS Test Table", + ) + self.assertEqual( + model.data( + model.index(tables.index("someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleCrs, + ), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + self.assertEqual( + model.data( + model.index(tables.index("someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleCustomInfo, + ), + {}, + ) + self.assertEqual( + model.data( + model.index(tables.index("someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleTableFlags, + ), + 4, + ) + self.assertEqual( + model.data( + model.index(tables.index("someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleWkbType, + ), + QgsWkbTypes.Type.Point, + ) + self.assertEqual( + model.data( + model.index(tables.index("some_poly_data"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleWkbType, + ), + QgsWkbTypes.Type.Polygon, + ) + self.assertIsNone( + model.data( + model.index(model.rowCount(), 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ) + ) def test_model_allow_empty(self): """Test model with empty entry""" - conn = QgsProviderRegistry.instance().providerMetadata('postgres').createConnection(self.uri, {}) + conn = ( + QgsProviderRegistry.instance() + .providerMetadata("postgres") + .createConnection(self.uri, {}) + ) self.assertTrue(conn) model = QgsDatabaseTableModel(conn) self.assertGreaterEqual(model.rowCount(), 3) @@ -169,116 +322,281 @@ def test_model_allow_empty(self): self.assertTrue(model.allowEmptyTable()) self.assertEqual(model.rowCount(), old_count + 1) self.assertEqual(model.columnCount(), 1) - tables = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('qgis_test.someData', tables) - self.assertIn('qgis_test.some_poly_data', tables) - self.assertIn('information_schema.attributes', tables) - - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty)) - self.assertFalse(model.data(model.index(tables.index('qgis_test.someData'), 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty)) - - self.assertEqual(model.data(model.index(tables.index('qgis_test.someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleTableName), 'someData') - self.assertEqual(model.data(model.index(tables.index('qgis_test.someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleSchema), 'qgis_test') - self.assertEqual(model.data(model.index(tables.index('qgis_test.someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleComment), 'QGIS Test Table') - self.assertEqual(model.data(model.index(tables.index('qgis_test.someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleCrs), QgsCoordinateReferenceSystem('EPSG:4326')) - self.assertEqual(model.data(model.index(tables.index('qgis_test.someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleCustomInfo), {}) - self.assertEqual(model.data(model.index(tables.index('qgis_test.someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleTableFlags), 4) - self.assertEqual(model.data(model.index(tables.index('qgis_test.someData'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleWkbType), QgsWkbTypes.Type.Point) - self.assertEqual(model.data(model.index(tables.index('qgis_test.some_poly_data'), 0, QModelIndex()), - QgsDatabaseTableModel.Role.RoleWkbType), QgsWkbTypes.Type.Polygon) - self.assertIsNone(model.data(model.index(model.rowCount(), 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) + tables = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("qgis_test.someData", tables) + self.assertIn("qgis_test.some_poly_data", tables) + self.assertIn("information_schema.attributes", tables) + + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertTrue( + model.data( + model.index(0, 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty + ) + ) + self.assertFalse( + model.data( + model.index(tables.index("qgis_test.someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleEmpty, + ) + ) + + self.assertEqual( + model.data( + model.index(tables.index("qgis_test.someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleTableName, + ), + "someData", + ) + self.assertEqual( + model.data( + model.index(tables.index("qgis_test.someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleSchema, + ), + "qgis_test", + ) + self.assertEqual( + model.data( + model.index(tables.index("qgis_test.someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleComment, + ), + "QGIS Test Table", + ) + self.assertEqual( + model.data( + model.index(tables.index("qgis_test.someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleCrs, + ), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + self.assertEqual( + model.data( + model.index(tables.index("qgis_test.someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleCustomInfo, + ), + {}, + ) + self.assertEqual( + model.data( + model.index(tables.index("qgis_test.someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleTableFlags, + ), + 4, + ) + self.assertEqual( + model.data( + model.index(tables.index("qgis_test.someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleWkbType, + ), + QgsWkbTypes.Type.Point, + ) + self.assertEqual( + model.data( + model.index(tables.index("qgis_test.some_poly_data"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleWkbType, + ), + QgsWkbTypes.Type.Polygon, + ) + self.assertIsNone( + model.data( + model.index(model.rowCount(), 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ) + ) model.refresh() self.assertEqual(model.rowCount(), old_count + 1) fields = QgsFields() - fields.append(QgsField('test', QVariant.String)) - conn.createVectorTable('qgis_test', 'myNewTable', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:3857'), False, {}) + fields.append(QgsField("test", QVariant.String)) + conn.createVectorTable( + "qgis_test", + "myNewTable", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:3857"), + False, + {}, + ) self.assertEqual(model.rowCount(), old_count + 1) model.refresh() self.assertEqual(model.rowCount(), old_count + 2) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty)) - self.assertFalse(model.data(model.index(tables.index('qgis_test.someData'), 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty)) + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertTrue( + model.data( + model.index(0, 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty + ) + ) + self.assertFalse( + model.data( + model.index(tables.index("qgis_test.someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleEmpty, + ) + ) - tables = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('qgis_test.someData', tables) - self.assertIn('qgis_test.some_poly_data', tables) - self.assertIn('information_schema.attributes', tables) - self.assertIn('qgis_test.myNewTable', tables) + tables = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("qgis_test.someData", tables) + self.assertIn("qgis_test.some_poly_data", tables) + self.assertIn("information_schema.attributes", tables) + self.assertIn("qgis_test.myNewTable", tables) model.setAllowEmptyTable(False) self.assertEqual(model.rowCount(), old_count + 1) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty)) + self.assertTrue( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertFalse( + model.data( + model.index(0, 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty + ) + ) model.setAllowEmptyTable(True) self.assertEqual(model.rowCount(), old_count + 2) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty)) + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertTrue( + model.data( + model.index(0, 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty + ) + ) - conn.createVectorTable('qgis_test', 'myNewTable2', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:3857'), False, {}) - conn.createVectorTable('qgis_test', 'myNewTable3', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:3857'), False, {}) + conn.createVectorTable( + "qgis_test", + "myNewTable2", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:3857"), + False, + {}, + ) + conn.createVectorTable( + "qgis_test", + "myNewTable3", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:3857"), + False, + {}, + ) model.refresh() self.assertEqual(model.rowCount(), old_count + 4) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty)) - tables = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('qgis_test.someData', tables) - self.assertIn('qgis_test.some_poly_data', tables) - self.assertIn('information_schema.attributes', tables) - self.assertIn('qgis_test.myNewTable', tables) - self.assertIn('qgis_test.myNewTable2', tables) - self.assertIn('qgis_test.myNewTable3', tables) - self.assertFalse(model.data(model.index(tables.index('qgis_test.someData'), 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty)) - - conn.createVectorTable('qgis_test', 'myNewTable4', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:3857'), False, {}) - conn.dropVectorTable('qgis_test', 'myNewTable2') - conn.dropVectorTable('qgis_test', 'myNewTable') + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertTrue( + model.data( + model.index(0, 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty + ) + ) + tables = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("qgis_test.someData", tables) + self.assertIn("qgis_test.some_poly_data", tables) + self.assertIn("information_schema.attributes", tables) + self.assertIn("qgis_test.myNewTable", tables) + self.assertIn("qgis_test.myNewTable2", tables) + self.assertIn("qgis_test.myNewTable3", tables) + self.assertFalse( + model.data( + model.index(tables.index("qgis_test.someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleEmpty, + ) + ) + + conn.createVectorTable( + "qgis_test", + "myNewTable4", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:3857"), + False, + {}, + ) + conn.dropVectorTable("qgis_test", "myNewTable2") + conn.dropVectorTable("qgis_test", "myNewTable") model.refresh() self.assertEqual(model.rowCount(), old_count + 3) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty)) - - tables = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('qgis_test.someData', tables) - self.assertIn('qgis_test.some_poly_data', tables) - self.assertIn('information_schema.attributes', tables) - self.assertNotIn('qgis_test.myNewTable', tables) - self.assertNotIn('qgis_test.myNewTable2', tables) - self.assertIn('qgis_test.myNewTable3', tables) - self.assertIn('qgis_test.myNewTable4', tables) - self.assertFalse(model.data(model.index(tables.index('qgis_test.someData'), 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty)) - - conn.dropVectorTable('qgis_test', 'myNewTable3') - conn.dropVectorTable('qgis_test', 'myNewTable4') + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertTrue( + model.data( + model.index(0, 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty + ) + ) + + tables = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("qgis_test.someData", tables) + self.assertIn("qgis_test.some_poly_data", tables) + self.assertIn("information_schema.attributes", tables) + self.assertNotIn("qgis_test.myNewTable", tables) + self.assertNotIn("qgis_test.myNewTable2", tables) + self.assertIn("qgis_test.myNewTable3", tables) + self.assertIn("qgis_test.myNewTable4", tables) + self.assertFalse( + model.data( + model.index(tables.index("qgis_test.someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleEmpty, + ) + ) + + conn.dropVectorTable("qgis_test", "myNewTable3") + conn.dropVectorTable("qgis_test", "myNewTable4") model.refresh() self.assertEqual(model.rowCount(), old_count + 1) - tables = [model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) for r in range(model.rowCount())] - self.assertIn('qgis_test.someData', tables) - self.assertIn('qgis_test.some_poly_data', tables) - self.assertIn('information_schema.attributes', tables) - self.assertNotIn('qgis_test.myNewTable', tables) - self.assertNotIn('qgis_test.myNewTable2', tables) - self.assertNotIn('qgis_test.myNewTable3', tables) - self.assertNotIn('qgis_test.myNewTable4', tables) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty)) - self.assertFalse(model.data(model.index(tables.index('qgis_test.someData'), 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty)) + tables = [ + model.data(model.index(r, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + for r in range(model.rowCount()) + ] + self.assertIn("qgis_test.someData", tables) + self.assertIn("qgis_test.some_poly_data", tables) + self.assertIn("information_schema.attributes", tables) + self.assertNotIn("qgis_test.myNewTable", tables) + self.assertNotIn("qgis_test.myNewTable2", tables) + self.assertNotIn("qgis_test.myNewTable3", tables) + self.assertNotIn("qgis_test.myNewTable4", tables) + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertTrue( + model.data( + model.index(0, 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty + ) + ) + self.assertFalse( + model.data( + model.index(tables.index("qgis_test.someData"), 0, QModelIndex()), + QgsDatabaseTableModel.Role.RoleEmpty, + ) + ) model.setAllowEmptyTable(False) self.assertEqual(model.rowCount(), old_count) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty)) + self.assertTrue( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertFalse( + model.data( + model.index(0, 0, QModelIndex()), QgsDatabaseTableModel.Role.RoleEmpty + ) + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsdataitem.py b/tests/src/python/test_qgsdataitem.py index 05ccd70073fd..32f575e0d595 100644 --- a/tests/src/python/test_qgsdataitem.py +++ b/tests/src/python/test_qgsdataitem.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Even Rouault' -__date__ = '14/11/2020 late in the night' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Even Rouault" +__date__ = "14/11/2020 late in the night" +__copyright__ = "Copyright 2020, The QGIS Project" import os @@ -25,19 +26,23 @@ class TestQgsDataItem(QgisTestCase): def test_databaseConnection(self): - dataitem = QgsDataCollectionItem(None, 'name', '/invalid_path', 'ogr') + dataitem = QgsDataCollectionItem(None, "name", "/invalid_path", "ogr") self.assertIsNone(dataitem.databaseConnection()) - dataitem = QgsDirectoryItem(None, 'name', os.path.join(unitTestDataPath(), 'provider')) + dataitem = QgsDirectoryItem( + None, "name", os.path.join(unitTestDataPath(), "provider") + ) children = dataitem.createChildren() # Check spatialite and gpkg - spatialite_item = [i for i in children if i.path().endswith('spatialite.db')][0] - geopackage_item = [i for i in children if i.path().endswith('geopackage.gpkg')][0] - textfile_item = [i for i in children if i.path().endswith('.xml')][0] + spatialite_item = [i for i in children if i.path().endswith("spatialite.db")][0] + geopackage_item = [i for i in children if i.path().endswith("geopackage.gpkg")][ + 0 + ] + textfile_item = [i for i in children if i.path().endswith(".xml")][0] self.assertIsNotNone(spatialite_item.databaseConnection()) self.assertIsNotNone(geopackage_item.databaseConnection()) self.assertIsNone(textfile_item.databaseConnection()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsdataitemguiproviderregistry.py b/tests/src/python/test_qgsdataitemguiproviderregistry.py index 3789baeae42b..55947ec4b901 100644 --- a/tests/src/python/test_qgsdataitemguiproviderregistry.py +++ b/tests/src/python/test_qgsdataitemguiproviderregistry.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '27/10/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "27/10/2018" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.gui import ( @@ -55,28 +56,28 @@ def testRegistry(self): initial_providers = registry.providers() # add a new provider - p1 = TestProvider('p1') + p1 = TestProvider("p1") registry.addProvider(p1) self.assertIn(p1, registry.providers()) - p2 = TestProvider('p2') + p2 = TestProvider("p2") registry.addProvider(p2) self.assertIn(p1, registry.providers()) self.assertIn(p2, registry.providers()) registry.removeProvider(None) - p3 = TestProvider('p3') + p3 = TestProvider("p3") # not in registry yet registry.removeProvider(p3) registry.removeProvider(p1) - self.assertNotIn('p1', [p.name() for p in registry.providers()]) + self.assertNotIn("p1", [p.name() for p in registry.providers()]) self.assertIn(p2, registry.providers()) registry.removeProvider(p2) - self.assertNotIn('p2', [p.name() for p in registry.providers()]) + self.assertNotIn("p2", [p.name() for p in registry.providers()]) self.assertEqual(registry.providers(), initial_providers) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsdataitemproviderregistry.py b/tests/src/python/test_qgsdataitemproviderregistry.py index 50f92dd39a75..c1c570b61da2 100644 --- a/tests/src/python/test_qgsdataitemproviderregistry.py +++ b/tests/src/python/test_qgsdataitemproviderregistry.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '27/10/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "27/10/2018" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.core import ( @@ -48,39 +49,39 @@ def testRegistry(self): registry = QgsDataItemProviderRegistry() initial_providers = registry.providers() self.assertTrue(initial_providers) # we expect a bunch of default providers - self.assertTrue([p.name() for p in initial_providers if p.name() == 'files']) + self.assertTrue([p.name() for p in initial_providers if p.name() == "files"]) # add a new provider - p1 = TestProvider('p1') + p1 = TestProvider("p1") registry.addProvider(p1) self.assertIn(p1, registry.providers()) - p2 = TestProvider('p2') + p2 = TestProvider("p2") registry.addProvider(p2) self.assertIn(p1, registry.providers()) self.assertIn(p2, registry.providers()) registry.removeProvider(None) - p3 = TestProvider('p3') + p3 = TestProvider("p3") # not in registry yet registry.removeProvider(p3) registry.removeProvider(p1) - self.assertNotIn('p1', [p.name() for p in registry.providers()]) + self.assertNotIn("p1", [p.name() for p in registry.providers()]) self.assertIn(p2, registry.providers()) registry.removeProvider(p2) - self.assertNotIn('p2', [p.name() for p in registry.providers()]) + self.assertNotIn("p2", [p.name() for p in registry.providers()]) self.assertEqual(registry.providers(), initial_providers) def testProviderKey(self): """Tests finding provider by name and return dataProviderKey""" registry = QgsDataItemProviderRegistry() - self.assertIsNotNone(registry.provider('PostGIS')) - self.assertIsNone(registry.provider('paper_and_pencil')) - self.assertEqual(registry.provider('PostGIS').dataProviderKey(), 'postgres') + self.assertIsNotNone(registry.provider("PostGIS")) + self.assertIsNone(registry.provider("paper_and_pencil")) + self.assertEqual(registry.provider("PostGIS").dataProviderKey(), "postgres") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsdatetimeedit.py b/tests/src/python/test_qgsdatetimeedit.py index 3d22ec221cd7..31bf86dc2f9f 100644 --- a/tests/src/python/test_qgsdatetimeedit.py +++ b/tests/src/python/test_qgsdatetimeedit.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Denis Rouzaud' -__date__ = '2018-01-04' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Denis Rouzaud" +__date__ = "2018-01-04" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, Qt, QTime from qgis.gui import QgsDateEdit, QgsDateTimeEdit, QgsTimeEdit @@ -16,14 +17,14 @@ start_app() -DATE = QDateTime.fromString('2018-01-01 01:02:03', Qt.DateFormat.ISODate) -DATE_Z = QDateTime.fromString('2018-01-01 01:02:03Z', Qt.DateFormat.ISODate) +DATE = QDateTime.fromString("2018-01-01 01:02:03", Qt.DateFormat.ISODate) +DATE_Z = QDateTime.fromString("2018-01-01 01:02:03Z", Qt.DateFormat.ISODate) class TestQgsDateTimeEdit(QgisTestCase): def testSettersGetters(self): - """ test widget handling of null values """ + """test widget handling of null values""" w = QgsDateTimeEdit() w.setAllowNull(False) @@ -34,7 +35,7 @@ def testSettersGetters(self): self.assertEqual(w.dateTime(), DATE) def testSettersGetters_DATE_Z(self): - """ test widget handling with Z time spec """ + """test widget handling with Z time spec""" w = QgsDateTimeEdit() w.setAllowNull(False) @@ -45,7 +46,7 @@ def testSettersGetters_DATE_Z(self): self.assertEqual(w.dateTime(), DATE_Z) def testNullValueHandling(self): - """ test widget handling of null values """ + """test widget handling of null values""" w = QgsDateTimeEdit() w.setAllowNull(True) @@ -65,7 +66,7 @@ def testNullValueHandling(self): class TestQgsDateEdit(QgisTestCase): def testSettersGetters(self): - """ test widget handling of null values """ + """test widget handling of null values""" w = QgsDateEdit() w.setAllowNull(False) @@ -76,7 +77,7 @@ def testSettersGetters(self): self.assertEqual(w.date(), DATE.date()) def testNullValueHandling(self): - """ test widget handling of null values """ + """test widget handling of null values""" w = QgsDateEdit() w.setAllowNull(True) @@ -96,7 +97,7 @@ def testNullValueHandling(self): class TestQgsTimeEdit(QgisTestCase): def testSettersGetters(self): - """ test widget handling of null values """ + """test widget handling of null values""" w = QgsTimeEdit() w.setAllowNull(False) @@ -107,7 +108,7 @@ def testSettersGetters(self): self.assertEqual(w.time(), DATE.time()) def testNullValueHandling(self): - """ test widget handling of null values """ + """test widget handling of null values""" w = QgsTimeEdit() w.setAllowNull(True) @@ -124,5 +125,5 @@ def testNullValueHandling(self): self.assertTrue(w.time().isValid()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsdatetimestatisticalsummary.py b/tests/src/python/test_qgsdatetimestatisticalsummary.py index 406b2890c112..084e034354c8 100644 --- a/tests/src/python/test_qgsdatetimestatisticalsummary.py +++ b/tests/src/python/test_qgsdatetimestatisticalsummary.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '07/05/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "07/05/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, QTime from qgis.core import NULL, QgsDateTimeStatisticalSummary, QgsInterval @@ -20,15 +21,17 @@ def testStats(self): # we test twice, once with values added as a list and once using values # added one-at-a-time - dates = [QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), - QDateTime(QDate(2011, 1, 5), QTime(15, 3, 1)), - QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), - QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), - QDateTime(QDate(2019, 12, 28), QTime(23, 10, 1)), - QDateTime(), - QDateTime(QDate(1998, 1, 2), QTime(1, 10, 54)), - QDateTime(), - QDateTime(QDate(2011, 1, 5), QTime(11, 10, 54))] + dates = [ + QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), + QDateTime(QDate(2011, 1, 5), QTime(15, 3, 1)), + QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), + QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), + QDateTime(QDate(2019, 12, 28), QTime(23, 10, 1)), + QDateTime(), + QDateTime(QDate(1998, 1, 2), QTime(1, 10, 54)), + QDateTime(), + QDateTime(QDate(2011, 1, 5), QTime(11, 10, 54)), + ] s = QgsDateTimeStatisticalSummary() self.assertEqual(s.statistics(), QgsDateTimeStatisticalSummary.Statistic.All) s.calculate(dates) @@ -40,13 +43,17 @@ def testStats(self): self.assertEqual(s2.count(), 9) self.assertEqual(s.countDistinct(), 6) self.assertEqual(s2.countDistinct(), 6) - self.assertEqual(set(s.distinctValues()), - {QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), - QDateTime(QDate(2011, 1, 5), QTime(15, 3, 1)), - QDateTime(QDate(2019, 12, 28), QTime(23, 10, 1)), - QDateTime(), - QDateTime(QDate(1998, 1, 2), QTime(1, 10, 54)), - QDateTime(QDate(2011, 1, 5), QTime(11, 10, 54))}) + self.assertEqual( + set(s.distinctValues()), + { + QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), + QDateTime(QDate(2011, 1, 5), QTime(15, 3, 1)), + QDateTime(QDate(2019, 12, 28), QTime(23, 10, 1)), + QDateTime(), + QDateTime(QDate(1998, 1, 2), QTime(1, 10, 54)), + QDateTime(QDate(2011, 1, 5), QTime(11, 10, 54)), + }, + ) self.assertEqual(s2.distinctValues(), s.distinctValues()) self.assertEqual(s.countMissing(), 2) self.assertEqual(s2.countMissing(), 2) @@ -60,13 +67,29 @@ def testStats(self): def testIndividualStats(self): # tests calculation of statistics one at a time, to make sure statistic calculations are not # dependent on each other - tests = [{'stat': QgsDateTimeStatisticalSummary.Statistic.Count, 'expected': 9}, - {'stat': QgsDateTimeStatisticalSummary.Statistic.CountDistinct, 'expected': 6}, - {'stat': QgsDateTimeStatisticalSummary.Statistic.CountMissing, 'expected': 2}, - {'stat': QgsDateTimeStatisticalSummary.Statistic.Min, 'expected': QDateTime(QDate(1998, 1, 2), QTime(1, 10, 54))}, - {'stat': QgsDateTimeStatisticalSummary.Statistic.Max, 'expected': QDateTime(QDate(2019, 12, 28), QTime(23, 10, 1))}, - {'stat': QgsDateTimeStatisticalSummary.Statistic.Range, 'expected': QgsInterval(693871147)}, - ] + tests = [ + {"stat": QgsDateTimeStatisticalSummary.Statistic.Count, "expected": 9}, + { + "stat": QgsDateTimeStatisticalSummary.Statistic.CountDistinct, + "expected": 6, + }, + { + "stat": QgsDateTimeStatisticalSummary.Statistic.CountMissing, + "expected": 2, + }, + { + "stat": QgsDateTimeStatisticalSummary.Statistic.Min, + "expected": QDateTime(QDate(1998, 1, 2), QTime(1, 10, 54)), + }, + { + "stat": QgsDateTimeStatisticalSummary.Statistic.Max, + "expected": QDateTime(QDate(2019, 12, 28), QTime(23, 10, 1)), + }, + { + "stat": QgsDateTimeStatisticalSummary.Statistic.Range, + "expected": QgsInterval(693871147), + }, + ] # we test twice, once with values added as a list and once using values # added one-at-a-time @@ -74,107 +97,135 @@ def testIndividualStats(self): s3 = QgsDateTimeStatisticalSummary() for t in tests: # test constructor - s2 = QgsDateTimeStatisticalSummary(t['stat']) - self.assertEqual(s2.statistics(), t['stat']) - - s.setStatistics(t['stat']) - self.assertEqual(s.statistics(), t['stat']) - s3.setStatistics(t['stat']) - - dates = [QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), - QDateTime(QDate(2011, 1, 5), QTime(15, 3, 1)), - QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), - QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), - QDateTime(QDate(2019, 12, 28), QTime(23, 10, 1)), - QDateTime(), - QDateTime(QDate(1998, 1, 2), QTime(1, 10, 54)), - QDateTime(), - QDateTime(QDate(2011, 1, 5), QTime(11, 10, 54))] + s2 = QgsDateTimeStatisticalSummary(t["stat"]) + self.assertEqual(s2.statistics(), t["stat"]) + + s.setStatistics(t["stat"]) + self.assertEqual(s.statistics(), t["stat"]) + s3.setStatistics(t["stat"]) + + dates = [ + QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), + QDateTime(QDate(2011, 1, 5), QTime(15, 3, 1)), + QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), + QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), + QDateTime(QDate(2019, 12, 28), QTime(23, 10, 1)), + QDateTime(), + QDateTime(QDate(1998, 1, 2), QTime(1, 10, 54)), + QDateTime(), + QDateTime(QDate(2011, 1, 5), QTime(11, 10, 54)), + ] s.calculate(dates) s3.reset() for d in dates: s3.addValue(d) s3.finalize() - self.assertEqual(s.statistic(t['stat']), t['expected']) - self.assertEqual(s3.statistic(t['stat']), t['expected']) + self.assertEqual(s.statistic(t["stat"]), t["expected"]) + self.assertEqual(s3.statistic(t["stat"]), t["expected"]) # display name - self.assertGreater(len(QgsDateTimeStatisticalSummary.displayName(t['stat'])), 0) + self.assertGreater( + len(QgsDateTimeStatisticalSummary.displayName(t["stat"])), 0 + ) def testVariantStats(self): - """ test with non-datetime values """ + """test with non-datetime values""" s = QgsDateTimeStatisticalSummary() self.assertEqual(s.statistics(), QgsDateTimeStatisticalSummary.Statistic.All) - s.calculate([QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), - 'asdasd', - QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), - 34, - QDateTime(QDate(2019, 12, 28), QTime(23, 10, 1)), - QDateTime(), - QDateTime(QDate(1998, 1, 2), QTime(1, 10, 54)), - QDateTime(), - QDateTime(QDate(2011, 1, 5), QTime(11, 10, 54))]) + s.calculate( + [ + QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), + "asdasd", + QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), + 34, + QDateTime(QDate(2019, 12, 28), QTime(23, 10, 1)), + QDateTime(), + QDateTime(QDate(1998, 1, 2), QTime(1, 10, 54)), + QDateTime(), + QDateTime(QDate(2011, 1, 5), QTime(11, 10, 54)), + ] + ) self.assertEqual(s.count(), 9) - self.assertEqual(set(s.distinctValues()), {QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), - QDateTime(QDate(2019, 12, 28), QTime(23, 10, 1)), - QDateTime(QDate(1998, 1, 2), QTime(1, 10, 54)), - QDateTime(QDate(2011, 1, 5), QTime(11, 10, 54)), - QDateTime()}) + self.assertEqual( + set(s.distinctValues()), + { + QDateTime(QDate(2015, 3, 4), QTime(11, 10, 54)), + QDateTime(QDate(2019, 12, 28), QTime(23, 10, 1)), + QDateTime(QDate(1998, 1, 2), QTime(1, 10, 54)), + QDateTime(QDate(2011, 1, 5), QTime(11, 10, 54)), + QDateTime(), + }, + ) self.assertEqual(s.countMissing(), 4) self.assertEqual(s.min(), QDateTime(QDate(1998, 1, 2), QTime(1, 10, 54))) self.assertEqual(s.max(), QDateTime(QDate(2019, 12, 28), QTime(23, 10, 1))) self.assertEqual(s.range(), QgsInterval(693871147)) def testDates(self): - """ test with date values """ + """test with date values""" s = QgsDateTimeStatisticalSummary() self.assertEqual(s.statistics(), QgsDateTimeStatisticalSummary.Statistic.All) - s.calculate([QDate(2015, 3, 4), - QDate(2015, 3, 4), - QDate(2019, 12, 28), - QDate(), - QDate(1998, 1, 2), - QDate(), - QDate(2011, 1, 5)]) + s.calculate( + [ + QDate(2015, 3, 4), + QDate(2015, 3, 4), + QDate(2019, 12, 28), + QDate(), + QDate(1998, 1, 2), + QDate(), + QDate(2011, 1, 5), + ] + ) self.assertEqual(s.count(), 7) - self.assertEqual(set(s.distinctValues()), { - QDateTime(QDate(2015, 3, 4), QTime()), - QDateTime(QDate(2019, 12, 28), QTime()), - QDateTime(QDate(1998, 1, 2), QTime()), - QDateTime(), - QDateTime(QDate(2011, 1, 5), QTime())}) + self.assertEqual( + set(s.distinctValues()), + { + QDateTime(QDate(2015, 3, 4), QTime()), + QDateTime(QDate(2019, 12, 28), QTime()), + QDateTime(QDate(1998, 1, 2), QTime()), + QDateTime(), + QDateTime(QDate(2011, 1, 5), QTime()), + }, + ) self.assertEqual(s.countMissing(), 2) self.assertEqual(s.min(), QDateTime(QDate(1998, 1, 2), QTime())) self.assertEqual(s.max(), QDateTime(QDate(2019, 12, 28), QTime())) self.assertEqual(s.range(), QgsInterval(693792000)) def testTimes(self): - """ test with time values """ + """test with time values""" s = QgsDateTimeStatisticalSummary() self.assertEqual(s.statistics(), QgsDateTimeStatisticalSummary.Statistic.All) - s.calculate([QTime(11, 3, 4), - QTime(15, 3, 4), - QTime(19, 12, 28), - QTime(), - QTime(8, 1, 2), - QTime(), - QTime(19, 12, 28)]) + s.calculate( + [ + QTime(11, 3, 4), + QTime(15, 3, 4), + QTime(19, 12, 28), + QTime(), + QTime(8, 1, 2), + QTime(), + QTime(19, 12, 28), + ] + ) self.assertEqual(s.count(), 7) self.assertEqual(s.countDistinct(), 5) self.assertEqual(s.countMissing(), 2) self.assertEqual(s.min().time(), QTime(8, 1, 2)) self.assertEqual(s.max().time(), QTime(19, 12, 28)) - self.assertEqual(s.statistic(QgsDateTimeStatisticalSummary.Statistic.Min), QTime(8, 1, 2)) - self.assertEqual(s.statistic(QgsDateTimeStatisticalSummary.Statistic.Max), QTime(19, 12, 28)) + self.assertEqual( + s.statistic(QgsDateTimeStatisticalSummary.Statistic.Min), QTime(8, 1, 2) + ) + self.assertEqual( + s.statistic(QgsDateTimeStatisticalSummary.Statistic.Max), QTime(19, 12, 28) + ) self.assertEqual(s.range(), QgsInterval(40286)) def testMissing(self): s = QgsDateTimeStatisticalSummary() - s.calculate([NULL, - 'not a date']) + s.calculate([NULL, "not a date"]) self.assertEqual(s.countMissing(), 2) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsdatumtransforms.py b/tests/src/python/test_qgsdatumtransforms.py index b613f2fa8070..877d8b919290 100644 --- a/tests/src/python/test_qgsdatumtransforms.py +++ b/tests/src/python/test_qgsdatumtransforms.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2019-05-25' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2019-05-25" +__copyright__ = "Copyright 2019, The QGIS Project" from qgis.core import ( QgsCoordinateReferenceSystem, @@ -26,259 +27,430 @@ class TestPyQgsDatumTransform(QgisTestCase): def testOperations(self): - ops = QgsDatumTransform.operations(QgsCoordinateReferenceSystem(), - QgsCoordinateReferenceSystem()) + ops = QgsDatumTransform.operations( + QgsCoordinateReferenceSystem(), QgsCoordinateReferenceSystem() + ) self.assertEqual(ops, []) - ops = QgsDatumTransform.operations(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem()) + ops = QgsDatumTransform.operations( + QgsCoordinateReferenceSystem("EPSG:3111"), QgsCoordinateReferenceSystem() + ) self.assertEqual(ops, []) - ops = QgsDatumTransform.operations(QgsCoordinateReferenceSystem(), - QgsCoordinateReferenceSystem('EPSG:3111')) + ops = QgsDatumTransform.operations( + QgsCoordinateReferenceSystem(), QgsCoordinateReferenceSystem("EPSG:3111") + ) self.assertEqual(ops, []) - ops = QgsDatumTransform.operations(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:3111')) + ops = QgsDatumTransform.operations( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) self.assertEqual(len(ops), 1) self.assertTrue(ops[0].name) - self.assertEqual(ops[0].proj, '+proj=noop') + self.assertEqual(ops[0].proj, "+proj=noop") self.assertEqual(ops[0].accuracy, 0.0) self.assertTrue(ops[0].isAvailable) - ops = QgsDatumTransform.operations(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:4283')) + ops = QgsDatumTransform.operations( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + ) self.assertEqual(len(ops), 1) self.assertTrue(ops[0].name) - self.assertEqual(ops[0].proj, '+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=unitconvert +xy_in=rad +xy_out=deg') + self.assertEqual( + ops[0].proj, + "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=unitconvert +xy_in=rad +xy_out=deg", + ) self.assertEqual(ops[0].accuracy, -1.0) self.assertTrue(ops[0].isAvailable) - ops = QgsDatumTransform.operations(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:28355')) + ops = QgsDatumTransform.operations( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:28355"), + ) self.assertEqual(len(ops), 1) self.assertTrue(ops[0].name) - self.assertEqual(ops[0].proj, '+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=utm +zone=55 +south +ellps=GRS80') + self.assertEqual( + ops[0].proj, + "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=utm +zone=55 +south +ellps=GRS80", + ) self.assertEqual(ops[0].accuracy, 0.0) self.assertTrue(ops[0].isAvailable) # uses a grid file - ops = QgsDatumTransform.operations(QgsCoordinateReferenceSystem('EPSG:4283'), - QgsCoordinateReferenceSystem('EPSG:7844')) + ops = QgsDatumTransform.operations( + QgsCoordinateReferenceSystem("EPSG:4283"), + QgsCoordinateReferenceSystem("EPSG:7844"), + ) self.assertGreaterEqual(len(ops), 5) - op1_index = [i for i in range(len(ops)) if ops[i].proj == '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 +step +proj=cart +ellps=GRS80 +step +proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 +rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 +convention=coordinate_frame +step +inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 +step +proj=unitconvert +xy_in=rad +xy_out=deg'][0] + op1_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 +step +proj=cart +ellps=GRS80 +step +proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 +rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 +convention=coordinate_frame +step +inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 +step +proj=unitconvert +xy_in=rad +xy_out=deg" + ][0] self.assertTrue(ops[op1_index].name) - self.assertEqual(ops[op1_index].proj, '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 +step +proj=cart +ellps=GRS80 +step +proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 +rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 +convention=coordinate_frame +step +inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 +step +proj=unitconvert +xy_in=rad +xy_out=deg') + self.assertEqual( + ops[op1_index].proj, + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 +step +proj=cart +ellps=GRS80 +step +proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 +rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 +convention=coordinate_frame +step +inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 +step +proj=unitconvert +xy_in=rad +xy_out=deg", + ) self.assertTrue(ops[op1_index].isAvailable) self.assertEqual(ops[op1_index].accuracy, 0.01) self.assertEqual(len(ops[op1_index].grids), 0) if QgsProjUtils.projVersionMajor() == 6: - op2_index = [i for i in range(len(ops)) if ops[i].proj == '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg'][0] + op2_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg" + ][0] else: - op2_index = [i for i in range(len(ops)) if ops[ - i].proj == '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_and_distortion.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg'][ - 0] + op2_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_and_distortion.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg" + ][0] self.assertTrue(ops[op2_index].name) if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual(ops[op2_index].proj, '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg') + self.assertEqual( + ops[op2_index].proj, + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg", + ) else: - self.assertEqual(ops[op2_index].proj, - '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_and_distortion.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg') + self.assertEqual( + ops[op2_index].proj, + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_and_distortion.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg", + ) self.assertEqual(ops[op2_index].accuracy, 0.05) self.assertEqual(len(ops[op2_index].grids), 1) if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual(ops[op2_index].grids[0].shortName, 'GDA94_GDA2020_conformal_and_distortion.gsb') + self.assertEqual( + ops[op2_index].grids[0].shortName, + "GDA94_GDA2020_conformal_and_distortion.gsb", + ) else: - self.assertEqual(ops[op2_index].grids[0].shortName, 'au_icsm_GDA94_GDA2020_conformal_and_distortion.tif') + self.assertEqual( + ops[op2_index].grids[0].shortName, + "au_icsm_GDA94_GDA2020_conformal_and_distortion.tif", + ) if QgsProjUtils.projVersionMajor() == 6: self.assertTrue(ops[op2_index].grids[0].packageName) - self.assertIn('http', ops[op2_index].grids[0].url) + self.assertIn("http", ops[op2_index].grids[0].url) self.assertTrue(ops[op2_index].grids[0].directDownload) self.assertTrue(ops[op2_index].grids[0].openLicense) if QgsProjUtils.projVersionMajor() == 6: - op3_index = [i for i in range(len(ops)) if ops[i].proj == '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg'][0] + op3_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg" + ][0] else: - op3_index = [i for i in range(len(ops)) if ops[ - i].proj == '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg'][ - 0] + op3_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg" + ][0] self.assertTrue(ops[op3_index].name) if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual(ops[op3_index].proj, '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg') + self.assertEqual( + ops[op3_index].proj, + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg", + ) else: - self.assertEqual(ops[op3_index].proj, - '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg') + self.assertEqual( + ops[op3_index].proj, + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg", + ) self.assertEqual(ops[op3_index].accuracy, 0.05) self.assertEqual(len(ops[op3_index].grids), 1) if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual(ops[op3_index].grids[0].shortName, 'GDA94_GDA2020_conformal.gsb') + self.assertEqual( + ops[op3_index].grids[0].shortName, "GDA94_GDA2020_conformal.gsb" + ) else: - self.assertEqual(ops[op3_index].grids[0].shortName, 'au_icsm_GDA94_GDA2020_conformal.tif') + self.assertEqual( + ops[op3_index].grids[0].shortName, "au_icsm_GDA94_GDA2020_conformal.tif" + ) if QgsProjUtils.projVersionMajor() == 6: self.assertTrue(ops[op3_index].grids[0].packageName) - self.assertIn('http', ops[op3_index].grids[0].url) + self.assertIn("http", ops[op3_index].grids[0].url) self.assertTrue(ops[op3_index].grids[0].directDownload) self.assertTrue(ops[op3_index].grids[0].openLicense) if QgsProjUtils.projVersionMajor() == 6: - op4_index = [i for i in range(len(ops)) if ops[i].proj == '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_cocos_island.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg'][0] + op4_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_cocos_island.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg" + ][0] else: - op4_index = [i for i in range(len(ops)) if ops[ - i].proj == '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_cocos_island.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg'][ - 0] + op4_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_cocos_island.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg" + ][0] self.assertTrue(ops[op4_index].name) if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual(ops[op4_index].proj, '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_cocos_island.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg') + self.assertEqual( + ops[op4_index].proj, + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_cocos_island.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg", + ) else: - self.assertEqual(ops[op4_index].proj, - '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_cocos_island.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg') + self.assertEqual( + ops[op4_index].proj, + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_cocos_island.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg", + ) self.assertEqual(ops[op4_index].accuracy, 0.05) self.assertEqual(len(ops[op4_index].grids), 1) if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual(ops[op4_index].grids[0].shortName, 'GDA94_GDA2020_conformal_cocos_island.gsb') + self.assertEqual( + ops[op4_index].grids[0].shortName, + "GDA94_GDA2020_conformal_cocos_island.gsb", + ) else: - self.assertEqual(ops[op4_index].grids[0].shortName, 'au_icsm_GDA94_GDA2020_conformal_cocos_island.tif') + self.assertEqual( + ops[op4_index].grids[0].shortName, + "au_icsm_GDA94_GDA2020_conformal_cocos_island.tif", + ) if QgsProjUtils.projVersionMajor() == 6: self.assertTrue(ops[op4_index].grids[0].packageName) - self.assertIn('http', ops[op4_index].grids[0].url) + self.assertIn("http", ops[op4_index].grids[0].url) if QgsProjUtils.projVersionMajor() == 6: - op5_index = [i for i in range(len(ops)) if ops[i].proj == '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_christmas_island.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg'][0] + op5_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_christmas_island.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg" + ][0] else: - op5_index = [i for i in range(len(ops)) if ops[ - i].proj == '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_christmas_island.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg'][ - 0] + op5_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_christmas_island.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg" + ][0] self.assertTrue(ops[op5_index].name) if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual(ops[op5_index].proj, '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_christmas_island.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg') + self.assertEqual( + ops[op5_index].proj, + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_christmas_island.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg", + ) else: - self.assertEqual(ops[op5_index].proj, - '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_christmas_island.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg') + self.assertEqual( + ops[op5_index].proj, + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_christmas_island.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg", + ) self.assertEqual(ops[op5_index].accuracy, 0.05) self.assertEqual(len(ops[op5_index].grids), 1) if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual(ops[op5_index].grids[0].shortName, 'GDA94_GDA2020_conformal_christmas_island.gsb') + self.assertEqual( + ops[op5_index].grids[0].shortName, + "GDA94_GDA2020_conformal_christmas_island.gsb", + ) else: - self.assertEqual(ops[op5_index].grids[0].shortName, 'au_icsm_GDA94_GDA2020_conformal_christmas_island.tif') + self.assertEqual( + ops[op5_index].grids[0].shortName, + "au_icsm_GDA94_GDA2020_conformal_christmas_island.tif", + ) if QgsProjUtils.projVersionMajor() == 6: self.assertTrue(ops[op5_index].grids[0].packageName) - self.assertIn('http', ops[op5_index].grids[0].url) + self.assertIn("http", ops[op5_index].grids[0].url) # uses a pivot datum (technically a proj test, but this will help me sleep at night ;) - ops = QgsDatumTransform.operations(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:7899')) + ops = QgsDatumTransform.operations( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:7899"), + ) self.assertGreaterEqual(len(ops), 3) - op1_index = [i for i in range(len(ops)) if ops[i].proj == '+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=push +v_3 +step +proj=cart +ellps=GRS80 +step +proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 +rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 +convention=coordinate_frame +step +inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80'][0] + op1_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=push +v_3 +step +proj=cart +ellps=GRS80 +step +proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 +rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 +convention=coordinate_frame +step +inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80" + ][0] self.assertTrue(ops[op1_index].name) - self.assertEqual(ops[op1_index].proj, '+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=push +v_3 +step +proj=cart +ellps=GRS80 +step +proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 +rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 +convention=coordinate_frame +step +inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80') + self.assertEqual( + ops[op1_index].proj, + "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=push +v_3 +step +proj=cart +ellps=GRS80 +step +proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 +rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 +convention=coordinate_frame +step +inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80", + ) self.assertTrue(ops[op1_index].isAvailable) self.assertEqual(ops[op1_index].accuracy, 0.01) self.assertEqual(len(ops[op1_index].grids), 0) if QgsProjUtils.projVersionMajor() == 6: - op2_index = [i for i in range(len(ops)) if ops[i].proj == '+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80'][0] + op2_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80" + ][0] else: - op2_index = [i for i in range(len(ops)) if ops[ - i].proj == '+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_and_distortion.tif +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80'][ - 0] + op2_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_and_distortion.tif +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80" + ][0] self.assertTrue(ops[op2_index].name) if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual(ops[op2_index].proj, '+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80') + self.assertEqual( + ops[op2_index].proj, + "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80", + ) else: - self.assertEqual(ops[op2_index].proj, - '+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_and_distortion.tif +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80') + self.assertEqual( + ops[op2_index].proj, + "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_and_distortion.tif +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80", + ) self.assertEqual(ops[op2_index].accuracy, 0.05) self.assertEqual(len(ops[op2_index].grids), 1) if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual(ops[op2_index].grids[0].shortName, 'GDA94_GDA2020_conformal_and_distortion.gsb') + self.assertEqual( + ops[op2_index].grids[0].shortName, + "GDA94_GDA2020_conformal_and_distortion.gsb", + ) else: - self.assertEqual(ops[op2_index].grids[0].shortName, 'au_icsm_GDA94_GDA2020_conformal_and_distortion.tif') + self.assertEqual( + ops[op2_index].grids[0].shortName, + "au_icsm_GDA94_GDA2020_conformal_and_distortion.tif", + ) if QgsProjUtils.projVersionMajor() == 6: self.assertTrue(ops[op2_index].grids[0].packageName) - self.assertIn('http', ops[op2_index].grids[0].url) + self.assertIn("http", ops[op2_index].grids[0].url) self.assertTrue(ops[op2_index].grids[0].directDownload) self.assertTrue(ops[op2_index].grids[0].openLicense) if QgsProjUtils.projVersionMajor() == 6: - op3_index = [i for i in range(len(ops)) if ops[i].proj == '+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=GDA94_GDA2020_conformal.gsb +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80'][0] + op3_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=GDA94_GDA2020_conformal.gsb +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80" + ][0] else: - op3_index = [i for i in range(len(ops)) if ops[ - i].proj == '+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal.tif +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80'][ - 0] + op3_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal.tif +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80" + ][0] self.assertTrue(ops[op3_index].name) if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual(ops[op3_index].proj, '+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=GDA94_GDA2020_conformal.gsb +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80') + self.assertEqual( + ops[op3_index].proj, + "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=GDA94_GDA2020_conformal.gsb +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80", + ) else: - self.assertEqual(ops[op3_index].proj, - '+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal.tif +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80') + self.assertEqual( + ops[op3_index].proj, + "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal.tif +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80", + ) self.assertEqual(ops[op3_index].accuracy, 0.05) self.assertEqual(len(ops[op3_index].grids), 1) if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual(ops[op3_index].grids[0].shortName, 'GDA94_GDA2020_conformal.gsb') + self.assertEqual( + ops[op3_index].grids[0].shortName, "GDA94_GDA2020_conformal.gsb" + ) else: - self.assertEqual(ops[op3_index].grids[0].shortName, 'au_icsm_GDA94_GDA2020_conformal.tif') + self.assertEqual( + ops[op3_index].grids[0].shortName, "au_icsm_GDA94_GDA2020_conformal.tif" + ) if QgsProjUtils.projVersionMajor() == 6: self.assertTrue(ops[op3_index].grids[0].packageName) - self.assertIn('http', ops[op3_index].grids[0].url) + self.assertIn("http", ops[op3_index].grids[0].url) self.assertTrue(ops[op3_index].grids[0].directDownload) self.assertTrue(ops[op3_index].grids[0].openLicense) - @unittest.skipIf(QgsProjUtils.projVersionMajor() > 9 or (QgsProjUtils.projVersionMajor() == 9 and QgsProjUtils.projVersionMinor() >= 2), 'NADCON5 support added in Proj 9.2') + @unittest.skipIf( + QgsProjUtils.projVersionMajor() > 9 + or ( + QgsProjUtils.projVersionMajor() == 9 + and QgsProjUtils.projVersionMinor() >= 2 + ), + "NADCON5 support added in Proj 9.2", + ) def testNoLasLos(self): """ Test that operations which rely on an NADCON5 grid shift file (which are unsupported by Proj... at time of writing !) are not returned """ - ops = QgsDatumTransform.operations(QgsCoordinateReferenceSystem('EPSG:4138'), - QgsCoordinateReferenceSystem('EPSG:4269')) + ops = QgsDatumTransform.operations( + QgsCoordinateReferenceSystem("EPSG:4138"), + QgsCoordinateReferenceSystem("EPSG:4269"), + ) self.assertEqual(len(ops), 2) self.assertTrue(ops[0].name) self.assertTrue(ops[0].proj) self.assertTrue(ops[1].name) self.assertTrue(ops[1].proj) - @unittest.skipIf(QgsProjUtils.projVersionMajor() < 8, 'Not a proj >= 8 build') + @unittest.skipIf(QgsProjUtils.projVersionMajor() < 8, "Not a proj >= 8 build") def testDatumEnsembles(self): """ Test datum ensemble details """ crs = QgsCoordinateReferenceSystem() self.assertFalse(crs.datumEnsemble().isValid()) - self.assertEqual(str(crs.datumEnsemble()), '') - crs = QgsCoordinateReferenceSystem('EPSG:3111') + self.assertEqual(str(crs.datumEnsemble()), "") + crs = QgsCoordinateReferenceSystem("EPSG:3111") self.assertFalse(crs.datumEnsemble().isValid()) - crs = QgsCoordinateReferenceSystem('EPSG:3857') + crs = QgsCoordinateReferenceSystem("EPSG:3857") ensemble = crs.datumEnsemble() self.assertTrue(ensemble.isValid()) - self.assertEqual(ensemble.name(), 'World Geodetic System 1984 ensemble') - self.assertEqual(ensemble.authority(), 'EPSG') - self.assertEqual(ensemble.code(), '6326') - self.assertEqual(ensemble.scope(), 'Satellite navigation.') + self.assertEqual(ensemble.name(), "World Geodetic System 1984 ensemble") + self.assertEqual(ensemble.authority(), "EPSG") + self.assertEqual(ensemble.code(), "6326") + self.assertEqual(ensemble.scope(), "Satellite navigation.") self.assertEqual(ensemble.accuracy(), 2.0) - self.assertEqual(str(ensemble), '') - self.assertEqual(ensemble.members()[0].name(), 'World Geodetic System 1984 (Transit)') - self.assertEqual(ensemble.members()[0].authority(), 'EPSG') - self.assertEqual(ensemble.members()[0].code(), '1166') - self.assertEqual(ensemble.members()[0].scope(), 'Geodesy. Navigation and positioning using GPS satellite system.') - self.assertEqual(str(ensemble.members()[0]), - '') - self.assertEqual(ensemble.members()[1].name(), 'World Geodetic System 1984 (G730)') - self.assertEqual(ensemble.members()[1].authority(), 'EPSG') - self.assertEqual(ensemble.members()[1].code(), '1152') - self.assertEqual(ensemble.members()[1].scope(), 'Geodesy. Navigation and positioning using GPS satellite system.') + self.assertEqual( + str(ensemble), + "", + ) + self.assertEqual( + ensemble.members()[0].name(), "World Geodetic System 1984 (Transit)" + ) + self.assertEqual(ensemble.members()[0].authority(), "EPSG") + self.assertEqual(ensemble.members()[0].code(), "1166") + self.assertEqual( + ensemble.members()[0].scope(), + "Geodesy. Navigation and positioning using GPS satellite system.", + ) + self.assertEqual( + str(ensemble.members()[0]), + "", + ) + self.assertEqual( + ensemble.members()[1].name(), "World Geodetic System 1984 (G730)" + ) + self.assertEqual(ensemble.members()[1].authority(), "EPSG") + self.assertEqual(ensemble.members()[1].code(), "1152") + self.assertEqual( + ensemble.members()[1].scope(), + "Geodesy. Navigation and positioning using GPS satellite system.", + ) - crs = QgsCoordinateReferenceSystem('EPSG:4936') + crs = QgsCoordinateReferenceSystem("EPSG:4936") ensemble = crs.datumEnsemble() self.assertTrue(ensemble.isValid()) - self.assertEqual(ensemble.name(), 'European Terrestrial Reference System 1989 ensemble') - self.assertEqual(ensemble.authority(), 'EPSG') - self.assertEqual(ensemble.code(), '6258') - self.assertEqual(ensemble.scope(), 'Spatial referencing.') + self.assertEqual( + ensemble.name(), "European Terrestrial Reference System 1989 ensemble" + ) + self.assertEqual(ensemble.authority(), "EPSG") + self.assertEqual(ensemble.code(), "6258") + self.assertEqual(ensemble.scope(), "Spatial referencing.") self.assertEqual(ensemble.accuracy(), 0.1) self.assertTrue(ensemble.members()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsdefaultvalue.py b/tests/src/python/test_qgsdefaultvalue.py index 90eef05358de..a3c63440c090 100644 --- a/tests/src/python/test_qgsdefaultvalue.py +++ b/tests/src/python/test_qgsdefaultvalue.py @@ -6,9 +6,9 @@ (at your option) any later version. """ -__author__ = 'Matthias Kuhn' -__date__ = '26.9.2017' -__copyright__ = 'Copyright 2017, The QGIS Project' +__author__ = "Matthias Kuhn" +__date__ = "26.9.2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.core import QgsDefaultValue @@ -19,22 +19,22 @@ class TestQgsRasterColorRampShader(unittest.TestCase): def testValid(self): self.assertFalse(QgsDefaultValue()) - self.assertTrue(QgsDefaultValue('test')) - self.assertTrue(QgsDefaultValue('abc', True)) - self.assertTrue(QgsDefaultValue('abc', False)) + self.assertTrue(QgsDefaultValue("test")) + self.assertTrue(QgsDefaultValue("abc", True)) + self.assertTrue(QgsDefaultValue("abc", False)) def setGetExpression(self): - value = QgsDefaultValue('abc', False) - self.assertEqual(value.expression(), 'abc') - value.setExpression('def') - self.assertEqual(value.expression(), 'def') + value = QgsDefaultValue("abc", False) + self.assertEqual(value.expression(), "abc") + value.setExpression("def") + self.assertEqual(value.expression(), "def") def setGetApplyOnUpdate(self): - value = QgsDefaultValue('abc', False) + value = QgsDefaultValue("abc", False) self.assertEqual(value.applyOnUpdate(), False) value.setApplyOnUpdate(True) self.assertEqual(value.applyOnUpdate(), True) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsdelimitedtextprovider.py b/tests/src/python/test_qgsdelimitedtextprovider.py index e7f8e95f395d..6c001a09f940 100644 --- a/tests/src/python/test_qgsdelimitedtextprovider.py +++ b/tests/src/python/test_qgsdelimitedtextprovider.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Chris Crook' -__date__ = '20/04/2013' -__copyright__ = 'Copyright 2013, The QGIS Project' + +__author__ = "Chris Crook" +__date__ = "20/04/2013" +__copyright__ = "Copyright 2013, The QGIS Project" # This module provides unit test for the delimited text provider. It uses data files in # the testdata/delimitedtext directory. @@ -31,7 +32,7 @@ import test_qgsdelimitedtextprovider_wanted as want # NOQA -rebuildTests = 'REBUILD_DELIMITED_TEXT_TESTS' in os.environ +rebuildTests = "REBUILD_DELIMITED_TEXT_TESTS" in os.environ from providertestbase import ProviderTestCase from qgis.core import ( @@ -87,33 +88,35 @@ def addQueryItem(self, k, v): def toString(self): urlstr = self.url.toString() querystr = self.query.toString(QUrl.ComponentFormattingOption.FullyDecoded) - if querystr != '': - urlstr += '?' + if querystr != "": + urlstr += "?" urlstr += querystr return urlstr + except: MyUrl = QUrl def normalize_query_items_order(s): - split_url = s.split('?') + split_url = s.split("?") urlstr = split_url[0] if len(split_url) == 2: - items_list = split_url[1].split('&') + items_list = split_url[1].split("&") items_map = {} for item in items_list: - split_item = item.split('=') + split_item = item.split("=") items_map[split_item[0]] = split_item[1] first_arg = True for k in sorted(items_map.keys()): if first_arg: - urlstr += '?' + urlstr += "?" first_arg = False else: - urlstr += '&' - urlstr += k + '=' + items_map[k] + urlstr += "&" + urlstr += k + "=" + items_map[k] return urlstr + # Thought we could connect to messageReceived signal but doesn't seem to be available # in python :-( Not sure why? @@ -145,10 +148,10 @@ class TestQgsDelimitedTextProviderXY(QgisTestCase, ProviderTestCase): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestQgsDelimitedTextProviderXY, cls).setUpClass() + super().setUpClass() # Create test layer - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - cls.basetestfile = os.path.join(srcpath, 'delimited_xy.csv') + srcpath = os.path.join(TEST_DATA_DIR, "provider") + cls.basetestfile = os.path.join(srcpath, "delimited_xy.csv") url = MyUrl.fromLocalFile(cls.basetestfile) url.addQueryItem("crs", "epsg:4326") @@ -159,7 +162,7 @@ def setUpClass(cls): url.addQueryItem("subsetIndex", "no") url.addQueryItem("watchFile", "no") - cls.vl = QgsVectorLayer(url.toString(), 'test', 'delimitedtext') + cls.vl = QgsVectorLayer(url.toString(), "test", "delimitedtext") assert cls.vl.isValid(), f"{cls.basetestfile} is invalid" cls.source = cls.vl.dataProvider() @@ -178,10 +181,10 @@ class TestQgsDelimitedTextProviderWKT(QgisTestCase, ProviderTestCase): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestQgsDelimitedTextProviderWKT, cls).setUpClass() + super().setUpClass() # Create test layer - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - cls.basetestfile = os.path.join(srcpath, 'delimited_wkt.csv') + srcpath = os.path.join(TEST_DATA_DIR, "provider") + cls.basetestfile = os.path.join(srcpath, "delimited_wkt.csv") url = MyUrl.fromLocalFile(cls.basetestfile) url.addQueryItem("crs", "epsg:4326") @@ -191,11 +194,11 @@ def setUpClass(cls): url.addQueryItem("subsetIndex", "no") url.addQueryItem("watchFile", "no") - cls.vl = QgsVectorLayer(url.toString(), 'test', 'delimitedtext') + cls.vl = QgsVectorLayer(url.toString(), "test", "delimitedtext") assert cls.vl.isValid(), f"{cls.basetestfile} is invalid" cls.source = cls.vl.dataProvider() - cls.basetestpolyfile = os.path.join(srcpath, 'delimited_wkt_poly.csv') + cls.basetestpolyfile = os.path.join(srcpath, "delimited_wkt_poly.csv") url = MyUrl.fromLocalFile(cls.basetestpolyfile) url.addQueryItem("crs", "epsg:4326") @@ -205,7 +208,7 @@ def setUpClass(cls): url.addQueryItem("subsetIndex", "no") url.addQueryItem("watchFile", "no") - cls.vl_poly = QgsVectorLayer(url.toString(), 'test_polygon', 'delimitedtext') + cls.vl_poly = QgsVectorLayer(url.toString(), "test_polygon", "delimitedtext") assert cls.vl_poly.isValid(), f"{cls.basetestpolyfile} is invalid" cls.poly_provider = cls.vl_poly.dataProvider() @@ -226,7 +229,7 @@ def setUpClass(cls): """Run before all tests""" super().setUpClass() # toggle full ctest output to debug flaky CI test - print('CTEST_FULL_OUTPUT') + print("CTEST_FULL_OUTPUT") cls.tmp_dir = QTemporaryDir() cls.tmp_path = cls.tmp_dir.path() cls._text_index = 0 @@ -239,16 +242,16 @@ def layerData(self, layer, request={}, offset=0): fieldTypes = [] fr = QgsFeatureRequest() if request: - if 'exact' in request and request['exact']: + if "exact" in request and request["exact"]: fr.setFlags(QgsFeatureRequest.Flag.ExactIntersect) - if 'nogeom' in request and request['nogeom']: + if "nogeom" in request and request["nogeom"]: fr.setFlags(QgsFeatureRequest.Flag.NoGeometry) - if 'fid' in request: - fr.setFilterFid(request['fid']) - elif 'extents' in request: - fr.setFilterRect(QgsRectangle(*request['extents'])) - if 'attributes' in request: - fr.setSubsetOfAttributes(request['attributes']) + if "fid" in request: + fr.setFilterFid(request["fid"]) + elif "extents" in request: + fr.setFilterRect(QgsRectangle(*request["extents"])) + if "attributes" in request: + fr.setSubsetOfAttributes(request["attributes"]) # IMPORTANT - we do not use `for f in layer.getFeatures(fr):` as we need # to verify that existing attributes and geometry are correctly cleared @@ -271,14 +274,14 @@ def layerData(self, layer, request={}, offset=0): fielddata[fidkey] = f.id() id = fielddata[fields[0]] description = fielddata[fields[1]] - fielddata['id'] = id - fielddata['description'] = description + fielddata["id"] = id + fielddata["description"] = description data[f.id() + offset] = fielddata - if 'id' not in fields: - fields.insert(0, 'id') - if 'description' not in fields: - fields.insert(1, 'description') + if "id" not in fields: + fields.insert(0, "id") + if "description" not in fields: + fields.insert(1, "description") fields.append(fidkey) fields.append(geomkey) return fields, fieldTypes, data @@ -296,21 +299,31 @@ def delimitedTextData(self, testname, filename, requests, verbose, **params): url.addQueryItem(k, params[k]) urlstr = url.toString() log = [] - with MessageLogger('DelimitedText') as logger: + with MessageLogger("DelimitedText") as logger: if verbose: print(testname) - layer = QgsVectorLayer(urlstr, 'test', 'delimitedtext') + layer = QgsVectorLayer(urlstr, "test", "delimitedtext") # decodeUri / encodeUri check - self.assertTrue(compareUrl(layer.source(), QgsProviderRegistry.instance().encodeUri('delimitedtext', QgsProviderRegistry.instance().decodeUri('delimitedtext', layer.source())))) + self.assertTrue( + compareUrl( + layer.source(), + QgsProviderRegistry.instance().encodeUri( + "delimitedtext", + QgsProviderRegistry.instance().decodeUri( + "delimitedtext", layer.source() + ), + ), + ) + ) uri = layer.dataProvider().dataSourceUri() if verbose: print(uri) basename = os.path.basename(filepath) - if not basename.startswith('test'): - basename = 'file' - uri = re.sub(r'^file\:\/\/[^\?]*', 'file://' + basename, uri) + if not basename.startswith("test"): + basename = "file" + uri = re.sub(r"^file\:\/\/[^\?]*", "file://" + basename, uri) fields = [] fieldTypes = [] data = {} @@ -334,26 +347,35 @@ def delimitedTextData(self, testname, filename, requests, verbose, **params): if verbose: print(("Request returned", len(list(rdata.keys())), "features")) for msg in logger.messages(): - filelogname = 'temp_file' if 'tmp' in filename.lower() else filename - msg = re.sub(r'file\s+.*' + re.escape(filename), 'file ' + filelogname, msg) + filelogname = "temp_file" if "tmp" in filename.lower() else filename + msg = re.sub( + r"file\s+.*" + re.escape(filename), "file " + filelogname, msg + ) msg = msg.replace(filepath, filelogname) log.append(msg) - return dict(fields=fields, fieldTypes=fieldTypes, data=data, log=log, uri=uri, geometryType=layer.geometryType()) + return dict( + fields=fields, + fieldTypes=fieldTypes, + data=data, + log=log, + uri=uri, + geometryType=layer.geometryType(), + ) def printWanted(self, testname, result): # Routine to export the result as a function definition print() print(f"def {testname}():") - data = result['data'] - log = result['log'] - fields = result['fields'] - prefix = ' ' + data = result["data"] + log = result["log"] + fields = result["fields"] + prefix = " " # Dump the data for a layer - used to construct unit tests print(prefix + "wanted={}") - print(prefix + "wanted['uri']=" + repr(result['uri'])) - print(prefix + "wanted['fieldTypes']=" + repr(result['fieldTypes'])) - print(prefix + "wanted['geometryType']=" + repr(result['geometryType'])) + print(prefix + "wanted['uri']=" + repr(result["uri"])) + print(prefix + "wanted['fieldTypes']=" + repr(result["fieldTypes"])) + print(prefix + "wanted['geometryType']=" + repr(result["geometryType"])) print(prefix + "wanted['data']={") for k in sorted(data.keys()): row = data[k] @@ -365,10 +387,10 @@ def printWanted(self, testname, result): print(prefix + "wanted['log']=[") for msg in log: - print(prefix + ' ' + repr(msg) + ',') - print(prefix + ' ]') - print(' return wanted') - print('', flush=True) + print(prefix + " " + repr(msg) + ",") + print(prefix + " ]") + print(" return wanted") + print("", flush=True) def recordDifference(self, record1, record2): # Compare a record defined as a dictionary @@ -386,7 +408,7 @@ def recordDifference(self, record1, record2): for k in list(record2.keys()): if k not in record1: return f"Output contains extra field {k}" - return '' + return "" def runTest(self, file, requests, **params): testname = inspect.stack()[1][3] @@ -398,64 +420,70 @@ def runTest(self, file, requests, **params): self.printWanted(testname, result) assert False, "Test not run - being rebuilt" try: - wanted = eval(f'want.{testname}()') + wanted = eval(f"want.{testname}()") except: self.printWanted(testname, result) assert False, f"Test results not available for {testname}" - data = result['data'] - log = result['log'] + data = result["data"] + log = result["log"] failures = [] - if normalize_query_items_order(result['uri']) != normalize_query_items_order(wanted['uri']): + if normalize_query_items_order(result["uri"]) != normalize_query_items_order( + wanted["uri"] + ): msg = "Layer Uri ({}) doesn't match expected ({})".format( - normalize_query_items_order(result['uri']), normalize_query_items_order(wanted['uri'])) - print(' ' + msg) + normalize_query_items_order(result["uri"]), + normalize_query_items_order(wanted["uri"]), + ) + print(" " + msg) failures.append(msg) - if result['fieldTypes'] != wanted['fieldTypes']: + if result["fieldTypes"] != wanted["fieldTypes"]: msg = "Layer field types ({}) doesn't match expected ({})".format( - result['fieldTypes'], wanted['fieldTypes']) + result["fieldTypes"], wanted["fieldTypes"] + ) failures.append(msg) - if result['geometryType'] != wanted['geometryType']: + if result["geometryType"] != wanted["geometryType"]: msg = "Layer geometry type ({}) doesn't match expected ({})".format( - result['geometryType'], wanted['geometryType']) + result["geometryType"], wanted["geometryType"] + ) failures.append(msg) - wanted_data = wanted['data'] + wanted_data = wanted["data"] for id in sorted(wanted_data.keys()): - print('getting wanted data') + print("getting wanted data") wrec = wanted_data[id] - print('getting received data') + print("getting received data") trec = data.get(id, {}) - print('getting description') - description = wrec['description'] - print('getting difference') + print("getting description") + description = wrec["description"] + print("getting difference") difference = self.recordDifference(wrec, trec) if not difference: - print(f' {description}: Passed') + print(f" {description}: Passed") else: - print(f' {description}: {difference}') - failures.append(description + ': ' + difference) + print(f" {description}: {difference}") + failures.append(description + ": " + difference) for id in sorted(data.keys()): if id not in wanted_data: - msg = f"Layer contains unexpected extra data with id: \"{id}\"" - print(' ' + msg) + msg = f'Layer contains unexpected extra data with id: "{id}"' + print(" " + msg) failures.append(msg) common = [] - log_wanted = wanted['log'] + log_wanted = wanted["log"] for l in log: if l in log_wanted: common.append(l) for l in log_wanted: if l not in common: - msg = 'Missing log message: ' + l - print(' ' + msg) + msg = "Missing log message: " + l + print(" " + msg) failures.append(msg) for l in log: if l not in common: - msg = 'Extra log message: ' + l - print(' ' + msg) + msg = "Extra log message: " + l + print(" " + msg) failures.append(msg) if len(log) == len(common) and len(log_wanted) == len(common): - print(' Message log correct: Passed') + print(" Message log correct: Passed") if failures: self.printWanted(testname, result) @@ -464,211 +492,261 @@ def runTest(self, file, requests, **params): def test_001_provider_defined(self): registry = QgsProviderRegistry.instance() - metadata = registry.providerMetadata('delimitedtext') + metadata = registry.providerMetadata("delimitedtext") assert metadata is not None, "Delimited text provider is not installed" def test_002_load_csv_file(self): # CSV file parsing - filename = 'test.csv' - params = {'geomType': 'none', 'type': 'csv'} + filename = "test.csv" + params = {"geomType": "none", "type": "csv"} requests = None self.runTest(filename, requests, **params) def test_003_field_naming(self): # Management of missing/duplicate/invalid field names - filename = 'testfields.csv' - params = {'geomType': 'none', 'type': 'csv'} + filename = "testfields.csv" + params = {"geomType": "none", "type": "csv"} requests = None self.runTest(filename, requests, **params) def test_004_max_fields(self): # Limiting maximum number of fields - filename = 'testfields.csv' - params = {'geomType': 'none', 'maxFields': '7', 'type': 'csv'} + filename = "testfields.csv" + params = {"geomType": "none", "maxFields": "7", "type": "csv"} requests = None self.runTest(filename, requests, **params) def test_005_load_whitespace(self): # Whitespace file parsing - filename = 'test.space' - params = {'geomType': 'none', 'type': 'whitespace'} + filename = "test.space" + params = {"geomType": "none", "type": "whitespace"} requests = None self.runTest(filename, requests, **params) def test_006_quote_escape(self): # Quote and escape file parsing - filename = 'test.pipe' - params = {'geomType': 'none', 'quote': '"', 'delimiter': '|', 'escape': '\\'} + filename = "test.pipe" + params = {"geomType": "none", "quote": '"', "delimiter": "|", "escape": "\\"} requests = None self.runTest(filename, requests, **params) def test_007_multiple_quote(self): # Multiple quote and escape characters - filename = 'test.quote' - params = {'geomType': 'none', 'quote': '\'"', 'type': 'csv', 'escape': '"\''} + filename = "test.quote" + params = {"geomType": "none", "quote": "'\"", "type": "csv", "escape": "\"'"} requests = None self.runTest(filename, requests, **params) def test_008_badly_formed_quotes(self): # Badly formed quoted fields - filename = 'test.badquote' - params = {'geomType': 'none', 'quote': '"', 'type': 'csv', 'escape': '"'} + filename = "test.badquote" + params = {"geomType": "none", "quote": '"', "type": "csv", "escape": '"'} requests = None self.runTest(filename, requests, **params) def test_009_skip_lines(self): # Skip lines - filename = 'test2.csv' - params = {'geomType': 'none', 'useHeader': 'no', 'type': 'csv', 'skipLines': '2'} + filename = "test2.csv" + params = { + "geomType": "none", + "useHeader": "no", + "type": "csv", + "skipLines": "2", + } requests = None self.runTest(filename, requests, **params) def test_010_read_coordinates(self): # Skip lines - filename = 'testpt.csv' - params = {'yField': 'geom_y', 'xField': 'geom_x', 'type': 'csv'} + filename = "testpt.csv" + params = {"yField": "geom_y", "xField": "geom_x", "type": "csv"} requests = None self.runTest(filename, requests, **params) def test_011_read_wkt(self): # Reading WKT geometry field - filename = 'testwkt.csv' - params = {'delimiter': '|', 'type': 'csv', 'wktField': 'geom_wkt'} + filename = "testwkt.csv" + params = {"delimiter": "|", "type": "csv", "wktField": "geom_wkt"} requests = None self.runTest(filename, requests, **params) def test_012_read_wkt_point(self): # Read WKT points - filename = 'testwkt.csv' - params = {'geomType': 'point', 'delimiter': '|', 'type': 'csv', 'wktField': 'geom_wkt'} + filename = "testwkt.csv" + params = { + "geomType": "point", + "delimiter": "|", + "type": "csv", + "wktField": "geom_wkt", + } requests = None self.runTest(filename, requests, **params) def test_013_read_wkt_line(self): # Read WKT linestrings - filename = 'testwkt.csv' - params = {'geomType': 'line', 'delimiter': '|', 'type': 'csv', 'wktField': 'geom_wkt'} + filename = "testwkt.csv" + params = { + "geomType": "line", + "delimiter": "|", + "type": "csv", + "wktField": "geom_wkt", + } requests = None self.runTest(filename, requests, **params) def test_014_read_wkt_polygon(self): # Read WKT polygons - filename = 'testwkt.csv' - params = {'geomType': 'polygon', 'delimiter': '|', 'type': 'csv', 'wktField': 'geom_wkt'} + filename = "testwkt.csv" + params = { + "geomType": "polygon", + "delimiter": "|", + "type": "csv", + "wktField": "geom_wkt", + } requests = None self.runTest(filename, requests, **params) def test_015_read_dms_xy(self): # Reading degrees/minutes/seconds angles - filename = 'testdms.csv' - params = {'yField': 'lat', 'xField': 'lon', 'type': 'csv', 'xyDms': 'yes'} + filename = "testdms.csv" + params = {"yField": "lat", "xField": "lon", "type": "csv", "xyDms": "yes"} requests = None self.runTest(filename, requests, **params) def test_016_decimal_point(self): # Reading degrees/minutes/seconds angles - filename = 'testdp.csv' - params = {'yField': 'geom_y', 'xField': 'geom_x', 'type': 'csv', 'delimiter': ';', 'decimalPoint': ','} + filename = "testdp.csv" + params = { + "yField": "geom_y", + "xField": "geom_x", + "type": "csv", + "delimiter": ";", + "decimalPoint": ",", + } requests = None self.runTest(filename, requests, **params) def test_017_regular_expression_1(self): # Parsing regular expression delimiter - filename = 'testre.txt' - params = {'geomType': 'none', 'trimFields': 'Y', 'delimiter': 'RE(?:GEXP)?', 'type': 'regexp'} + filename = "testre.txt" + params = { + "geomType": "none", + "trimFields": "Y", + "delimiter": "RE(?:GEXP)?", + "type": "regexp", + } requests = None self.runTest(filename, requests, **params) def test_018_regular_expression_2(self): # Parsing regular expression delimiter with capture groups - filename = 'testre.txt' - params = {'geomType': 'none', 'trimFields': 'Y', 'delimiter': '(RE)((?:GEXP)?)', 'type': 'regexp'} + filename = "testre.txt" + params = { + "geomType": "none", + "trimFields": "Y", + "delimiter": "(RE)((?:GEXP)?)", + "type": "regexp", + } requests = None self.runTest(filename, requests, **params) def test_019_regular_expression_3(self): # Parsing anchored regular expression - filename = 'testre2.txt' - params = {'geomType': 'none', 'trimFields': 'Y', 'delimiter': '^(.{5})(.{30})(.{5,})', 'type': 'regexp'} + filename = "testre2.txt" + params = { + "geomType": "none", + "trimFields": "Y", + "delimiter": "^(.{5})(.{30})(.{5,})", + "type": "regexp", + } requests = None self.runTest(filename, requests, **params) def test_020_regular_expression_4(self): # Parsing zero length re - filename = 'testre3.txt' - params = {'geomType': 'none', 'delimiter': 'x?', 'type': 'regexp'} + filename = "testre3.txt" + params = {"geomType": "none", "delimiter": "x?", "type": "regexp"} requests = None self.runTest(filename, requests, **params) def test_021_regular_expression_5(self): # Parsing zero length re 2 - filename = 'testre3.txt' - params = {'geomType': 'none', 'delimiter': '\\b', 'type': 'regexp'} + filename = "testre3.txt" + params = {"geomType": "none", "delimiter": "\\b", "type": "regexp"} requests = None self.runTest(filename, requests, **params) def test_022_utf8_encoded_file(self): # UTF8 encoded file test - filename = 'testutf8.csv' - params = {'geomType': 'none', 'delimiter': '|', 'type': 'csv', 'encoding': 'utf-8'} + filename = "testutf8.csv" + params = { + "geomType": "none", + "delimiter": "|", + "type": "csv", + "encoding": "utf-8", + } requests = None self.runTest(filename, requests, **params) def test_023_latin1_encoded_file(self): # Latin1 encoded file test - filename = 'testlatin1.csv' - params = {'geomType': 'none', 'delimiter': '|', 'type': 'csv', 'encoding': 'latin1'} + filename = "testlatin1.csv" + params = { + "geomType": "none", + "delimiter": "|", + "type": "csv", + "encoding": "latin1", + } requests = None self.runTest(filename, requests, **params) def test_024_filter_rect_xy(self): # Filter extents on XY layer - filename = 'testextpt.txt' - params = {'yField': 'y', 'delimiter': '|', 'type': 'csv', 'xField': 'x'} + filename = "testextpt.txt" + params = {"yField": "y", "delimiter": "|", "type": "csv", "xField": "x"} requests = [ - {'extents': [10, 30, 30, 50]}, - {'extents': [10, 30, 30, 50], 'exact': 1}, - {'extents': [110, 130, 130, 150]}] + {"extents": [10, 30, 30, 50]}, + {"extents": [10, 30, 30, 50], "exact": 1}, + {"extents": [110, 130, 130, 150]}, + ] self.runTest(filename, requests, **params) def test_025_filter_rect_wkt(self): # Filter extents on WKT layer - filename = 'testextw.txt' - params = {'delimiter': '|', 'type': 'csv', 'wktField': 'wkt'} + filename = "testextw.txt" + params = {"delimiter": "|", "type": "csv", "wktField": "wkt"} requests = [ - {'extents': [10, 30, 30, 50]}, - {'extents': [10, 30, 30, 50], 'exact': 1}, - {'extents': [110, 130, 130, 150]}] + {"extents": [10, 30, 30, 50]}, + {"extents": [10, 30, 30, 50], "exact": 1}, + {"extents": [110, 130, 130, 150]}, + ] self.runTest(filename, requests, **params) def test_026_filter_fid(self): # Filter on feature id - filename = 'test.csv' - params = {'geomType': 'none', 'type': 'csv'} - requests = [ - {'fid': 3}, - {'fid': 9}, - {'fid': 20}, - {'fid': 3}] + filename = "test.csv" + params = {"geomType": "none", "type": "csv"} + requests = [{"fid": 3}, {"fid": 9}, {"fid": 20}, {"fid": 3}] self.runTest(filename, requests, **params) def test_027_filter_attributes(self): # Filter on attributes - filename = 'test.csv' - params = {'geomType': 'none', 'type': 'csv'} + filename = "test.csv" + params = {"geomType": "none", "type": "csv"} requests = [ - {'attributes': [1, 3]}, - {'fid': 9}, - {'attributes': [1, 3], 'fid': 9}, - {'attributes': [3, 1], 'fid': 9}, - {'attributes': [1, 3, 7], 'fid': 9}, - {'attributes': [], 'fid': 9}] + {"attributes": [1, 3]}, + {"fid": 9}, + {"attributes": [1, 3], "fid": 9}, + {"attributes": [3, 1], "fid": 9}, + {"attributes": [1, 3, 7], "fid": 9}, + {"attributes": [], "fid": 9}, + ] self.runTest(filename, requests, **params) def test_028_substring_test(self): # CSV file parsing - filename = 'test.csv' - params = {'geomType': 'none', 'subset': 'id % 2 = 1', 'type': 'csv'} + filename = "test.csv" + params = {"geomType": "none", "subset": "id % 2 = 1", "type": "csv"} requests = None self.runTest(filename, requests, **params) @@ -681,14 +759,14 @@ def test_029_file_watcher(self): f.write("id,name\n1,rabbit\n2,pooh\n") def appendfile(layer): - with open(filename, 'a') as f: - f.write('3,tiger\n') + with open(filename, "a") as f: + f.write("3,tiger\n") # print "Appended to file - sleeping" time.sleep(1) QCoreApplication.instance().processEvents() def rewritefile(layer): - with open(filename, 'w') as f: + with open(filename, "w") as f: f.write("name,size,id\ntoad,small,5\nmole,medium,6\nbadger,big,7\n") # print "Rewritten file - sleeping" time.sleep(1) @@ -699,79 +777,92 @@ def deletefile(layer): os.remove(filename) except: open(filename, "w").close() - assert os.path.getsize(filename) == 0, f"removal and truncation of {filename} failed" + assert ( + os.path.getsize(filename) == 0 + ), f"removal and truncation of {filename} failed" # print "Deleted file - sleeping" time.sleep(1) QCoreApplication.instance().processEvents() - params = {'geomType': 'none', 'type': 'csv', 'watchFile': 'yes'} + params = {"geomType": "none", "type": "csv", "watchFile": "yes"} requests = [ - {'fid': 3}, + {"fid": 3}, {}, - {'fid': 7}, + {"fid": 7}, appendfile, - {'fid': 3}, - {'fid': 4}, + {"fid": 3}, + {"fid": 4}, {}, - {'fid': 7}, + {"fid": 7}, rewritefile, - {'fid': 2}, + {"fid": 2}, {}, - {'fid': 7}, + {"fid": 7}, deletefile, - {'fid': 2}, + {"fid": 2}, {}, rewritefile, - {'fid': 2}, + {"fid": 2}, ] self.runTest(filename, requests, **params) def test_030_filter_rect_xy_spatial_index(self): # Filter extents on XY layer with spatial index - filename = 'testextpt.txt' - params = {'yField': 'y', 'delimiter': '|', 'type': 'csv', 'xField': 'x', 'spatialIndex': 'Y'} + filename = "testextpt.txt" + params = { + "yField": "y", + "delimiter": "|", + "type": "csv", + "xField": "x", + "spatialIndex": "Y", + } requests = [ - {'extents': [10, 30, 30, 50]}, - {'extents': [10, 30, 30, 50], 'exact': 1}, - {'extents': [110, 130, 130, 150]}, + {"extents": [10, 30, 30, 50]}, + {"extents": [10, 30, 30, 50], "exact": 1}, + {"extents": [110, 130, 130, 150]}, {}, - {'extents': [-1000, -1000, 1000, 1000]} + {"extents": [-1000, -1000, 1000, 1000]}, ] self.runTest(filename, requests, **params) def test_031_filter_rect_wkt_spatial_index(self): # Filter extents on WKT layer with spatial index - filename = 'testextw.txt' - params = {'delimiter': '|', 'type': 'csv', 'wktField': 'wkt', 'spatialIndex': 'Y'} + filename = "testextw.txt" + params = { + "delimiter": "|", + "type": "csv", + "wktField": "wkt", + "spatialIndex": "Y", + } requests = [ - {'extents': [10, 30, 30, 50]}, - {'extents': [10, 30, 30, 50], 'exact': 1}, - {'extents': [110, 130, 130, 150]}, + {"extents": [10, 30, 30, 50]}, + {"extents": [10, 30, 30, 50], "exact": 1}, + {"extents": [110, 130, 130, 150]}, {}, - {'extents': [-1000, -1000, 1000, 1000]} + {"extents": [-1000, -1000, 1000, 1000]}, ] self.runTest(filename, requests, **params) def test_032_filter_rect_wkt_create_spatial_index(self): # Filter extents on WKT layer building spatial index - filename = 'testextw.txt' - params = {'delimiter': '|', 'type': 'csv', 'wktField': 'wkt'} + filename = "testextw.txt" + params = {"delimiter": "|", "type": "csv", "wktField": "wkt"} requests = [ - {'extents': [10, 30, 30, 50]}, + {"extents": [10, 30, 30, 50]}, {}, lambda layer: layer.dataProvider().createSpatialIndex(), - {'extents': [10, 30, 30, 50]}, - {'extents': [10, 30, 30, 50], 'exact': 1}, - {'extents': [110, 130, 130, 150]}, + {"extents": [10, 30, 30, 50]}, + {"extents": [10, 30, 30, 50], "exact": 1}, + {"extents": [110, 130, 130, 150]}, {}, - {'extents': [-1000, -1000, 1000, 1000]} + {"extents": [-1000, -1000, 1000, 1000]}, ] self.runTest(filename, requests, **params) def test_033_reset_subset_string(self): # CSV file parsing - filename = 'test.csv' - params = {'geomType': 'none', 'type': 'csv'} + filename = "test.csv" + params = {"geomType": "none", "type": "csv"} requests = [ {}, lambda layer: layer.dataProvider().setSubsetString("id % 2 = 1", True), @@ -789,80 +880,80 @@ def test_033_reset_subset_string(self): def test_034_csvt_file(self): # CSVT field types - filename = 'testcsvt.csv' - params = {'geomType': 'none', 'type': 'csv'} + filename = "testcsvt.csv" + params = {"geomType": "none", "type": "csv"} requests = None self.runTest(filename, requests, **params) def test_035_csvt_file2(self): # CSV field types 2 - filename = 'testcsvt2.txt' - params = {'geomType': 'none', 'type': 'csv', 'delimiter': '|'} + filename = "testcsvt2.txt" + params = {"geomType": "none", "type": "csv", "delimiter": "|"} requests = None self.runTest(filename, requests, **params) def test_036_csvt_file_invalid_types(self): # CSV field types invalid string format - filename = 'testcsvt3.csv' - params = {'geomType': 'none', 'type': 'csv'} + filename = "testcsvt3.csv" + params = {"geomType": "none", "type": "csv"} requests = None self.runTest(filename, requests, **params) def test_037_csvt_file_invalid_file(self): # CSV field types invalid file - filename = 'testcsvt4.csv' - params = {'geomType': 'none', 'type': 'csv'} + filename = "testcsvt4.csv" + params = {"geomType": "none", "type": "csv"} requests = None self.runTest(filename, requests, **params) def test_038_type_inference(self): # Skip lines - filename = 'testtypes.csv' - params = {'yField': 'lat', 'xField': 'lon', 'type': 'csv'} + filename = "testtypes.csv" + params = {"yField": "lat", "xField": "lon", "type": "csv"} requests = None self.runTest(filename, requests, **params) def test_039_issue_13749(self): # First record contains missing geometry - filename = 'test13749.csv' - params = {'yField': 'geom_y', 'xField': 'geom_x', 'type': 'csv'} + filename = "test13749.csv" + params = {"yField": "geom_y", "xField": "geom_x", "type": "csv"} requests = None self.runTest(filename, requests, **params) def test_040_issue_14666(self): # x/y containing some null geometries - filename = 'test14666.csv' - params = {'yField': 'y', 'xField': 'x', 'type': 'csv', 'delimiter': '\\t'} + filename = "test14666.csv" + params = {"yField": "y", "xField": "x", "type": "csv", "delimiter": "\\t"} requests = None self.runTest(filename, requests, **params) def test_041_no_detect_type(self): # CSV file parsing # Skip lines - filename = 'testtypes.csv' - params = {'yField': 'lat', 'xField': 'lon', 'type': 'csv', 'detectTypes': 'no'} + filename = "testtypes.csv" + params = {"yField": "lat", "xField": "lon", "type": "csv", "detectTypes": "no"} requests = None self.runTest(filename, requests, **params) def test_042_no_detect_types_csvt(self): # CSVT field types - filename = 'testcsvt.csv' - params = {'geomType': 'none', 'type': 'csv', 'detectTypes': 'no'} + filename = "testcsvt.csv" + params = {"geomType": "none", "type": "csv", "detectTypes": "no"} requests = None self.runTest(filename, requests, **params) def test_043_decodeuri(self): # URI decoding - filename = '/home/to/path/test.csv' - uri = f'file://{filename}?geomType=none' + filename = "/home/to/path/test.csv" + uri = f"file://{filename}?geomType=none" registry = QgsProviderRegistry.instance() - components = registry.decodeUri('delimitedtext', uri) - self.assertEqual(components['path'], filename) + components = registry.decodeUri("delimitedtext", uri) + self.assertEqual(components["path"], filename) def test_044_ZM(self): # Create test layer - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - basetestfile = os.path.join(srcpath, 'delimited_xyzm.csv') + srcpath = os.path.join(TEST_DATA_DIR, "provider") + basetestfile = os.path.join(srcpath, "delimited_xyzm.csv") url = MyUrl.fromLocalFile(basetestfile) url.addQueryItem("crs", "epsg:4326") @@ -875,25 +966,34 @@ def test_044_ZM(self): url.addQueryItem("subsetIndex", "no") url.addQueryItem("watchFile", "no") - vl = QgsVectorLayer(url.toString(), 'test', 'delimitedtext') + vl = QgsVectorLayer(url.toString(), "test", "delimitedtext") assert vl.isValid(), f"{basetestfile} is invalid" - assert vl.wkbType() == QgsWkbTypes.Type.PointZM, "wrong wkb type, should be PointZM" - assert vl.getFeature(2).geometry().asWkt() == "Point ZM (-71.12300000000000466 78.23000000000000398 1 2)", "wrong PointZM geometry" + assert ( + vl.wkbType() == QgsWkbTypes.Type.PointZM + ), "wrong wkb type, should be PointZM" + assert ( + vl.getFeature(2).geometry().asWkt() + == "Point ZM (-71.12300000000000466 78.23000000000000398 1 2)" + ), "wrong PointZM geometry" self.assertAlmostEqual(vl.extent().xMinimum(), -71.12300000000000466, places=4) self.assertAlmostEqual(vl.extent().yMinimum(), 66.32999999999999829, places=4) self.assertAlmostEqual(vl.extent().xMaximum(), -65.31999999999999318, places=4) self.assertAlmostEqual(vl.extent().yMaximum(), 78.29999999999999716, places=4) - self.assertAlmostEqual(vl.extent3D().xMinimum(), -71.12300000000000466, places=4) + self.assertAlmostEqual( + vl.extent3D().xMinimum(), -71.12300000000000466, places=4 + ) self.assertAlmostEqual(vl.extent3D().yMinimum(), 66.32999999999999829, places=4) self.assertEqual(vl.extent3D().zMinimum(), 1) - self.assertAlmostEqual(vl.extent3D().xMaximum(), -65.31999999999999318, places=4) + self.assertAlmostEqual( + vl.extent3D().xMaximum(), -65.31999999999999318, places=4 + ) self.assertAlmostEqual(vl.extent3D().yMaximum(), 78.29999999999999716, places=4) self.assertEqual(vl.extent3D().zMaximum(), 3) def test_045_Z(self): # Create test layer - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - basetestfile = os.path.join(srcpath, 'delimited_xyzm.csv') + srcpath = os.path.join(TEST_DATA_DIR, "provider") + basetestfile = os.path.join(srcpath, "delimited_xyzm.csv") url = MyUrl.fromLocalFile(basetestfile) url.addQueryItem("crs", "epsg:4326") @@ -905,17 +1005,40 @@ def test_045_Z(self): url.addQueryItem("subsetIndex", "no") url.addQueryItem("watchFile", "no") - vl = QgsVectorLayer(url.toString(), 'test', 'delimitedtext') + vl = QgsVectorLayer(url.toString(), "test", "delimitedtext") assert vl.isValid(), f"{basetestfile} is invalid" - assert vl.wkbType() == QgsWkbTypes.Type.PointZ, "wrong wkb type, should be PointZ" - assert vl.getFeature(2).geometry().asWkt() == "Point Z (-71.12300000000000466 78.23000000000000398 1)", "wrong PointZ geometry" - self.assertEqual(vl.extent(), QgsRectangle(-71.12300000000000466, 66.32999999999999829, -65.31999999999999318, 78.29999999999999716)) - self.assertEqual(vl.extent3D(), QgsBox3D(-71.12300000000000466, 66.32999999999999829, 1, -65.31999999999999318, 78.29999999999999716, 3)) + assert ( + vl.wkbType() == QgsWkbTypes.Type.PointZ + ), "wrong wkb type, should be PointZ" + assert ( + vl.getFeature(2).geometry().asWkt() + == "Point Z (-71.12300000000000466 78.23000000000000398 1)" + ), "wrong PointZ geometry" + self.assertEqual( + vl.extent(), + QgsRectangle( + -71.12300000000000466, + 66.32999999999999829, + -65.31999999999999318, + 78.29999999999999716, + ), + ) + self.assertEqual( + vl.extent3D(), + QgsBox3D( + -71.12300000000000466, + 66.32999999999999829, + 1, + -65.31999999999999318, + 78.29999999999999716, + 3, + ), + ) def test_046_M(self): # Create test layer - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - basetestfile = os.path.join(srcpath, 'delimited_xyzm.csv') + srcpath = os.path.join(TEST_DATA_DIR, "provider") + basetestfile = os.path.join(srcpath, "delimited_xyzm.csv") url = MyUrl.fromLocalFile(basetestfile) url.addQueryItem("crs", "epsg:4326") @@ -927,17 +1050,40 @@ def test_046_M(self): url.addQueryItem("subsetIndex", "no") url.addQueryItem("watchFile", "no") - vl = QgsVectorLayer(url.toString(), 'test', 'delimitedtext') + vl = QgsVectorLayer(url.toString(), "test", "delimitedtext") assert vl.isValid(), f"{basetestfile} is invalid" - assert vl.wkbType() == QgsWkbTypes.Type.PointM, "wrong wkb type, should be PointM" - assert vl.getFeature(2).geometry().asWkt() == "Point M (-71.12300000000000466 78.23000000000000398 2)", "wrong PointM geometry" - self.assertEqual(vl.extent(), QgsRectangle(-71.12300000000000466, 66.32999999999999829, -65.31999999999999318, 78.29999999999999716)) - self.assertEqual(vl.extent3D(), QgsBox3D(-71.12300000000000466, 66.32999999999999829, float('nan'), -65.31999999999999318, 78.29999999999999716, float('nan'))) + assert ( + vl.wkbType() == QgsWkbTypes.Type.PointM + ), "wrong wkb type, should be PointM" + assert ( + vl.getFeature(2).geometry().asWkt() + == "Point M (-71.12300000000000466 78.23000000000000398 2)" + ), "wrong PointM geometry" + self.assertEqual( + vl.extent(), + QgsRectangle( + -71.12300000000000466, + 66.32999999999999829, + -65.31999999999999318, + 78.29999999999999716, + ), + ) + self.assertEqual( + vl.extent3D(), + QgsBox3D( + -71.12300000000000466, + 66.32999999999999829, + float("nan"), + -65.31999999999999318, + 78.29999999999999716, + float("nan"), + ), + ) def test_047_datetime(self): # Create test layer - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - basetestfile = os.path.join(srcpath, 'delimited_datetime.csv') + srcpath = os.path.join(TEST_DATA_DIR, "provider") + basetestfile = os.path.join(srcpath, "delimited_datetime.csv") url = MyUrl.fromLocalFile(basetestfile) url.addQueryItem("crs", "epsg:4326") @@ -948,7 +1094,7 @@ def test_047_datetime(self): url.addQueryItem("subsetIndex", "no") url.addQueryItem("watchFile", "no") - vl = QgsVectorLayer(url.toString(), 'test', 'delimitedtext') + vl = QgsVectorLayer(url.toString(), "test", "delimitedtext") assert vl.isValid(), f"{basetestfile} is invalid" assert vl.fields().at(4).type() == QVariant.DateTime assert vl.fields().at(5).type() == QVariant.Date @@ -957,14 +1103,14 @@ def test_047_datetime(self): def test_048_csvt_file(self): # CSVT field types non lowercase - filename = 'testcsvt5.csv' - params = {'geomType': 'none', 'type': 'csv'} + filename = "testcsvt5.csv" + params = {"geomType": "none", "type": "csv"} requests = None self.runTest(filename, requests, **params) def testSpatialIndex(self): - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - basetestfile = os.path.join(srcpath, 'delimited_xyzm.csv') + srcpath = os.path.join(TEST_DATA_DIR, "provider") + basetestfile = os.path.join(srcpath, "delimited_xyzm.csv") url = MyUrl.fromLocalFile(basetestfile) url.addQueryItem("crs", "epsg:4326") @@ -973,440 +1119,602 @@ def testSpatialIndex(self): url.addQueryItem("yField", "Y") url.addQueryItem("spatialIndex", "no") - vl = QgsVectorLayer(url.toString(), 'test', 'delimitedtext') + vl = QgsVectorLayer(url.toString(), "test", "delimitedtext") self.assertTrue(vl.isValid()) - self.assertEqual(vl.hasSpatialIndex(), QgsFeatureSource.SpatialIndexPresence.SpatialIndexNotPresent) + self.assertEqual( + vl.hasSpatialIndex(), + QgsFeatureSource.SpatialIndexPresence.SpatialIndexNotPresent, + ) vl.dataProvider().createSpatialIndex() - self.assertEqual(vl.hasSpatialIndex(), QgsFeatureSource.SpatialIndexPresence.SpatialIndexPresent) + self.assertEqual( + vl.hasSpatialIndex(), + QgsFeatureSource.SpatialIndexPresence.SpatialIndexPresent, + ) def testEncodeDecodeUri(self): registry = QgsProviderRegistry.instance() # URI decoding - filename = '/home/to/path/test.csv' - parts = {'path': filename} - uri = registry.encodeUri('delimitedtext', parts) - self.assertEqual(uri, 'file://' + filename) + filename = "/home/to/path/test.csv" + parts = {"path": filename} + uri = registry.encodeUri("delimitedtext", parts) + self.assertEqual(uri, "file://" + filename) # URI encoding / decoding with unicode characters - filename = '/höme/to/path/pöints.txt' - parts = {'path': filename} - uri = registry.encodeUri('delimitedtext', parts) - self.assertEqual(uri, 'file:///h%C3%B6me/to/path/p%C3%B6ints.txt') - parts = registry.decodeUri('delimitedtext', uri) - self.assertEqual(parts['path'], filename) + filename = "/höme/to/path/pöints.txt" + parts = {"path": filename} + uri = registry.encodeUri("delimitedtext", parts) + self.assertEqual(uri, "file:///h%C3%B6me/to/path/p%C3%B6ints.txt") + parts = registry.decodeUri("delimitedtext", uri) + self.assertEqual(parts["path"], filename) def testCREndOfLineAndWorkingBuffer(self): # Test CSV file with \r (CR) endings # Test also that the logic to refill the buffer works properly - os.environ['QGIS_DELIMITED_TEXT_FILE_BUFFER_SIZE'] = '17' + os.environ["QGIS_DELIMITED_TEXT_FILE_BUFFER_SIZE"] = "17" try: - basetestfile = os.path.join(unitTestDataPath("delimitedtext"), 'test_cr_end_of_line.csv') + basetestfile = os.path.join( + unitTestDataPath("delimitedtext"), "test_cr_end_of_line.csv" + ) url = MyUrl.fromLocalFile(basetestfile) url.addQueryItem("type", "csv") url.addQueryItem("geomType", "none") - vl = QgsVectorLayer(url.toString(), 'test', 'delimitedtext') + vl = QgsVectorLayer(url.toString(), "test", "delimitedtext") assert vl.isValid(), f"{basetestfile} is invalid" fields = vl.fields() self.assertEqual(len(fields), 2) - self.assertEqual(fields[0].name(), 'col0') - self.assertEqual(fields[1].name(), 'col1') + self.assertEqual(fields[0].name(), "col0") + self.assertEqual(fields[1].name(), "col1") features = [f for f in vl.getFeatures()] self.assertEqual(len(features), 2) - self.assertEqual(features[0]['col0'], 'value00') - self.assertEqual(features[0]['col1'], 'value01') - self.assertEqual(features[1]['col0'], 'value10') - self.assertEqual(features[1]['col1'], 'value11') + self.assertEqual(features[0]["col0"], "value00") + self.assertEqual(features[0]["col1"], "value01") + self.assertEqual(features[1]["col0"], "value10") + self.assertEqual(features[1]["col1"], "value11") finally: - del os.environ['QGIS_DELIMITED_TEXT_FILE_BUFFER_SIZE'] + del os.environ["QGIS_DELIMITED_TEXT_FILE_BUFFER_SIZE"] def testSaturationOfWorkingBuffer(self): # 10 bytes is sufficient to detect the header line, but not enough for the # first record - os.environ['QGIS_DELIMITED_TEXT_FILE_BUFFER_SIZE'] = '10' + os.environ["QGIS_DELIMITED_TEXT_FILE_BUFFER_SIZE"] = "10" try: - basetestfile = os.path.join(unitTestDataPath("delimitedtext"), 'test_cr_end_of_line.csv') + basetestfile = os.path.join( + unitTestDataPath("delimitedtext"), "test_cr_end_of_line.csv" + ) url = MyUrl.fromLocalFile(basetestfile) url.addQueryItem("type", "csv") url.addQueryItem("geomType", "none") - vl = QgsVectorLayer(url.toString(), 'test', 'delimitedtext') + vl = QgsVectorLayer(url.toString(), "test", "delimitedtext") assert vl.isValid(), f"{basetestfile} is invalid" fields = vl.fields() self.assertEqual(len(fields), 2) - self.assertEqual(fields[0].name(), 'col0') - self.assertEqual(fields[1].name(), 'col1') + self.assertEqual(fields[0].name(), "col0") + self.assertEqual(fields[1].name(), "col1") features = [f for f in vl.getFeatures()] self.assertEqual(len(features), 1) - self.assertEqual(features[0]['col0'], 'value00') - self.assertEqual(features[0]['col1'], 'va') # truncated + self.assertEqual(features[0]["col0"], "value00") + self.assertEqual(features[0]["col1"], "va") # truncated finally: - del os.environ['QGIS_DELIMITED_TEXT_FILE_BUFFER_SIZE'] + del os.environ["QGIS_DELIMITED_TEXT_FILE_BUFFER_SIZE"] - def _make_test_file(self, csv_content, csvt_content='', uri_options=''): + def _make_test_file(self, csv_content, csvt_content="", uri_options=""): TestQgsDelimitedTextProviderOther._text_index += 1 - basename = f'test_type_detection_{self._text_index}' + basename = f"test_type_detection_{self._text_index}" - csv_file = os.path.join(self.tmp_path, basename + '.csv') - with open(csv_file, 'w+') as f: + csv_file = os.path.join(self.tmp_path, basename + ".csv") + with open(csv_file, "w+") as f: f.write(csv_content) if csvt_content: - csvt_file = os.path.join(self.tmp_path, basename + '.csvt') - with open(csvt_file, 'w+') as f: + csvt_file = os.path.join(self.tmp_path, basename + ".csvt") + with open(csvt_file, "w+") as f: f.write(csvt_content) - uri = f'file:///{csv_file}' + uri = f"file:///{csv_file}" if uri_options: - uri += f'?{uri_options}' + uri += f"?{uri_options}" - vl = QgsVectorLayer(uri, f'test_{basename}', 'delimitedtext') + vl = QgsVectorLayer(uri, f"test_{basename}", "delimitedtext") return vl def test_type_detection_csvt(self): """Type detection from CSVT""" - vl = self._make_test_file("f1,f2,f3,f4,f5\n1,1,1,\"1\",3\n", "Integer,Longlong,Real,String,Real\n") + vl = self._make_test_file( + 'f1,f2,f3,f4,f5\n1,1,1,"1",3\n', "Integer,Longlong,Real,String,Real\n" + ) self.assertTrue(vl.isValid()) fields = {f.name(): (f.type(), f.typeName()) for f in vl.fields()} - self.assertEqual(fields, { - 'f1': (QVariant.Int, 'integer'), - 'f2': (QVariant.LongLong, 'longlong'), - 'f3': (QVariant.Double, 'double'), - 'f4': (QVariant.String, 'text'), - 'f5': (QVariant.Double, 'double')}) + self.assertEqual( + fields, + { + "f1": (QVariant.Int, "integer"), + "f2": (QVariant.LongLong, "longlong"), + "f3": (QVariant.Double, "double"), + "f4": (QVariant.String, "text"), + "f5": (QVariant.Double, "double"), + }, + ) # Missing last field in CSVT - vl = self._make_test_file("f1,f2,f3,f4,f5\n1,1,1,\"1\",3\n", "Integer,Long,Real,String\n") + vl = self._make_test_file( + 'f1,f2,f3,f4,f5\n1,1,1,"1",3\n', "Integer,Long,Real,String\n" + ) self.assertTrue(vl.isValid()) fields = {f.name(): (f.type(), f.typeName()) for f in vl.fields()} - self.assertEqual(fields, { - 'f1': (QVariant.Int, 'integer'), - 'f2': (QVariant.LongLong, 'longlong'), - 'f3': (QVariant.Double, 'double'), - 'f4': (QVariant.String, 'text'), - 'f5': (QVariant.Int, 'integer')}) + self.assertEqual( + fields, + { + "f1": (QVariant.Int, "integer"), + "f2": (QVariant.LongLong, "longlong"), + "f3": (QVariant.Double, "double"), + "f4": (QVariant.String, "text"), + "f5": (QVariant.Int, "integer"), + }, + ) # No CSVT and detectTypes=no - vl = self._make_test_file("f1,f2,f3,f4,f5\n1,1,1,\"1\",3\n", uri_options='detectTypes=no') + vl = self._make_test_file( + 'f1,f2,f3,f4,f5\n1,1,1,"1",3\n', uri_options="detectTypes=no" + ) self.assertTrue(vl.isValid()) fields = {f.name(): (f.type(), f.typeName()) for f in vl.fields()} - self.assertEqual(fields, { - 'f1': (QVariant.String, 'text'), - 'f2': (QVariant.String, 'text'), - 'f3': (QVariant.String, 'text'), - 'f4': (QVariant.String, 'text'), - 'f5': (QVariant.String, 'text')}) + self.assertEqual( + fields, + { + "f1": (QVariant.String, "text"), + "f2": (QVariant.String, "text"), + "f3": (QVariant.String, "text"), + "f4": (QVariant.String, "text"), + "f5": (QVariant.String, "text"), + }, + ) # Test OGR generated CSVT, exported from QGIS - vl = self._make_test_file('\n'.join(( - "fid,freal,ftext,fint,flong,fdate,fbool", - '"1",1.234567,a text,"2000000000","4000000000",2021/11/12,true', - '"2",3.4567889,another text,"2147483646","4000000000",2021/11/12,false', - '"3",6.789,text,"2000000000","4000000000",2021/11/13,false', - )), "Integer64(20),Real,String,Integer(10),Integer64(20),Date,String") + vl = self._make_test_file( + "\n".join( + ( + "fid,freal,ftext,fint,flong,fdate,fbool", + '"1",1.234567,a text,"2000000000","4000000000",2021/11/12,true', + '"2",3.4567889,another text,"2147483646","4000000000",2021/11/12,false', + '"3",6.789,text,"2000000000","4000000000",2021/11/13,false', + ) + ), + "Integer64(20),Real,String,Integer(10),Integer64(20),Date,String", + ) self.assertTrue(vl.isValid()) fields = {f.name(): (f.type(), f.typeName()) for f in vl.fields()} - self.assertEqual(fields, { - 'fid': (4, 'longlong'), - 'freal': (6, 'double'), - 'ftext': (10, 'text'), - 'fint': (2, 'integer'), - 'flong': (4, 'longlong'), - 'fdate': (14, 'date'), - 'fbool': (10, 'text')}) + self.assertEqual( + fields, + { + "fid": (4, "longlong"), + "freal": (6, "double"), + "ftext": (10, "text"), + "fint": (2, "integer"), + "flong": (4, "longlong"), + "fdate": (14, "date"), + "fbool": (10, "text"), + }, + ) attrs = [f.attributes() for f in vl.getFeatures()] - self.assertEqual(attrs, [ - [1, - 1.234567, - 'a text', - 2000000000, - 4000000000, - QDate(2021, 11, 12), - 'true'], - [2, - 3.4567889, - 'another text', - 2147483646, - 4000000000, - QDate(2021, 11, 12), - 'false'], - [3, - 6.789, - 'text', - 2000000000, - 4000000000, - QDate(2021, 11, 13), - 'false'] - ]) + self.assertEqual( + attrs, + [ + [ + 1, + 1.234567, + "a text", + 2000000000, + 4000000000, + QDate(2021, 11, 12), + "true", + ], + [ + 2, + 3.4567889, + "another text", + 2147483646, + 4000000000, + QDate(2021, 11, 12), + "false", + ], + [ + 3, + 6.789, + "text", + 2000000000, + 4000000000, + QDate(2021, 11, 13), + "false", + ], + ], + ) # Try bool Integer(Boolean) - vl = self._make_test_file('\n'.join(( - "fid,freal,ftext,fint,flong,fdate,fbool", - '"1",1.234567,a text,"2000000000","4000000000",2021/11/12,true', - '"2",3.4567889,another text,"2147483646","4000000000",2021/11/12,false', - '"3",6.789,text,"2000000000","4000000000",2021/11/13,false', - )), "Integer64(20),Real,String,Integer(10),Integer64(20),Date,Integer(Boolean)") + vl = self._make_test_file( + "\n".join( + ( + "fid,freal,ftext,fint,flong,fdate,fbool", + '"1",1.234567,a text,"2000000000","4000000000",2021/11/12,true', + '"2",3.4567889,another text,"2147483646","4000000000",2021/11/12,false', + '"3",6.789,text,"2000000000","4000000000",2021/11/13,false', + ) + ), + "Integer64(20),Real,String,Integer(10),Integer64(20),Date,Integer(Boolean)", + ) self.assertTrue(vl.isValid()) fields = {f.name(): (f.type(), f.typeName()) for f in vl.fields()} - self.assertEqual(fields, { - 'fid': (4, 'longlong'), - 'freal': (6, 'double'), - 'ftext': (10, 'text'), - 'fint': (2, 'integer'), - 'flong': (4, 'longlong'), - 'fdate': (14, 'date'), - 'fbool': (1, 'bool')}) + self.assertEqual( + fields, + { + "fid": (4, "longlong"), + "freal": (6, "double"), + "ftext": (10, "text"), + "fint": (2, "integer"), + "flong": (4, "longlong"), + "fdate": (14, "date"), + "fbool": (1, "bool"), + }, + ) attrs = [f.attributes() for f in vl.getFeatures()] - self.assertEqual(attrs, [ - [1, - 1.234567, - 'a text', - 2000000000, - 4000000000, - QDate(2021, 11, 12), - True], - [2, - 3.4567889, - 'another text', - 2147483646, - 4000000000, - QDate(2021, 11, 12), - False], - [3, - 6.789, - 'text', - 2000000000, - 4000000000, - QDate(2021, 11, 13), - False] - ]) + self.assertEqual( + attrs, + [ + [ + 1, + 1.234567, + "a text", + 2000000000, + 4000000000, + QDate(2021, 11, 12), + True, + ], + [ + 2, + 3.4567889, + "another text", + 2147483646, + 4000000000, + QDate(2021, 11, 12), + False, + ], + [3, 6.789, "text", 2000000000, 4000000000, QDate(2021, 11, 13), False], + ], + ) # XY no args - vl = self._make_test_file('\n'.join(( - "X,Y,fid,freal,ftext,fint,flong,fdate,fbool", - '-106.13127068692,36.0554327720544,"4",1.234567,a text,"2000000000","4000000000",2021/11/12,true', - '-105.781333374658,35.7216962612865,"5",3.4567889,another text,"2147483646","4000000000",2021/11/12,false', - '-106.108589564828,35.407400712311,"6",6.789,text,"2000000000","4000000000",2021/11/13,false', - )), "CoordX,CoordY,Integer64(20),Real,String,Integer(10),Integer64(20),Date,Integer(Boolean)") + vl = self._make_test_file( + "\n".join( + ( + "X,Y,fid,freal,ftext,fint,flong,fdate,fbool", + '-106.13127068692,36.0554327720544,"4",1.234567,a text,"2000000000","4000000000",2021/11/12,true', + '-105.781333374658,35.7216962612865,"5",3.4567889,another text,"2147483646","4000000000",2021/11/12,false', + '-106.108589564828,35.407400712311,"6",6.789,text,"2000000000","4000000000",2021/11/13,false', + ) + ), + "CoordX,CoordY,Integer64(20),Real,String,Integer(10),Integer64(20),Date,Integer(Boolean)", + ) self.assertTrue(vl.isValid()) fields = {f.name(): (f.type(), f.typeName()) for f in vl.fields()} - self.assertEqual(fields, { - 'X': (6, 'double'), - 'Y': (6, 'double'), - 'fid': (4, 'longlong'), - 'freal': (6, 'double'), - 'ftext': (10, 'text'), - 'fint': (2, 'integer'), - 'flong': (4, 'longlong'), - 'fdate': (14, 'date'), - 'fbool': (1, 'bool')}) + self.assertEqual( + fields, + { + "X": (6, "double"), + "Y": (6, "double"), + "fid": (4, "longlong"), + "freal": (6, "double"), + "ftext": (10, "text"), + "fint": (2, "integer"), + "flong": (4, "longlong"), + "fdate": (14, "date"), + "fbool": (1, "bool"), + }, + ) attrs = [f.attributes() for f in vl.getFeatures()] - self.assertEqual(attrs, [ - [-106.13127068692, - 36.0554327720544, - 4, - 1.234567, - 'a text', - 2000000000, - 4000000000, - QDate(2021, 11, 12), - True], - [-105.781333374658, - 35.7216962612865, - 5, - 3.4567889, - 'another text', - 2147483646, - 4000000000, - QDate(2021, 11, 12), - False], - [-106.108589564828, - 35.407400712311, - 6, - 6.789, - 'text', - 2000000000, - 4000000000, - QDate(2021, 11, 13), - False]]) - - vl = self._make_test_file('\n'.join(( - "X,Y,fid,freal,ftext,fint,flong,fdate,fbool", - '-106.13127068692,36.0554327720544,"1",1.234567,a text,"2000000000","4000000000",2021/11/12,true', - '-105.781333374658,35.7216962612865,"2",3.4567889,another text,"2147483646","4000000000",2021/11/12,false', - '-106.108589564828,35.407400712311,"3",6.789,text,"2000000000","4000000000",2021/11/13,false', - )), "CoordX,CoordY,Integer64(20),Real,String,Integer(10),Integer64(20),Date,Integer(Boolean)", uri_options='xField=X&yField=Y') + self.assertEqual( + attrs, + [ + [ + -106.13127068692, + 36.0554327720544, + 4, + 1.234567, + "a text", + 2000000000, + 4000000000, + QDate(2021, 11, 12), + True, + ], + [ + -105.781333374658, + 35.7216962612865, + 5, + 3.4567889, + "another text", + 2147483646, + 4000000000, + QDate(2021, 11, 12), + False, + ], + [ + -106.108589564828, + 35.407400712311, + 6, + 6.789, + "text", + 2000000000, + 4000000000, + QDate(2021, 11, 13), + False, + ], + ], + ) + + vl = self._make_test_file( + "\n".join( + ( + "X,Y,fid,freal,ftext,fint,flong,fdate,fbool", + '-106.13127068692,36.0554327720544,"1",1.234567,a text,"2000000000","4000000000",2021/11/12,true', + '-105.781333374658,35.7216962612865,"2",3.4567889,another text,"2147483646","4000000000",2021/11/12,false', + '-106.108589564828,35.407400712311,"3",6.789,text,"2000000000","4000000000",2021/11/13,false', + ) + ), + "CoordX,CoordY,Integer64(20),Real,String,Integer(10),Integer64(20),Date,Integer(Boolean)", + uri_options="xField=X&yField=Y", + ) self.assertTrue(vl.isSpatial()) # Test Z - vl = self._make_test_file('\n'.join(( - "X,Y,Z,fid,freal,ftext,fint,flong,fdate,fbool", - '-106.13127068692,36.0554327720544,1,"1",1.234567,a text,"2000000000","4000000000",2021/11/12,true', - '-105.781333374658,35.7216962612865,123,"2",3.4567889,another text,"2147483646","4000000000",2021/11/12,false', - '-106.108589564828,35.407400712311,"456","3",6.789,text,"2000000000","4000000000",2021/11/13,false', - )), "Point(x),CoordY,Point(z),Integer64(20),Real(float32),String,Integer(10),Integer64(20),Date,Integer(Boolean)", uri_options='xField=X&yField=Y&zField=Z') + vl = self._make_test_file( + "\n".join( + ( + "X,Y,Z,fid,freal,ftext,fint,flong,fdate,fbool", + '-106.13127068692,36.0554327720544,1,"1",1.234567,a text,"2000000000","4000000000",2021/11/12,true', + '-105.781333374658,35.7216962612865,123,"2",3.4567889,another text,"2147483646","4000000000",2021/11/12,false', + '-106.108589564828,35.407400712311,"456","3",6.789,text,"2000000000","4000000000",2021/11/13,false', + ) + ), + "Point(x),CoordY,Point(z),Integer64(20),Real(float32),String,Integer(10),Integer64(20),Date,Integer(Boolean)", + uri_options="xField=X&yField=Y&zField=Z", + ) fields = {f.name(): (f.type(), f.typeName()) for f in vl.fields()} - self.assertEqual(fields, { - 'X': (6, 'double'), - 'Y': (6, 'double'), - 'Z': (6, 'double'), - 'fid': (4, 'longlong'), - 'freal': (6, 'double'), - 'ftext': (10, 'text'), - 'fint': (2, 'integer'), - 'flong': (4, 'longlong'), - 'fdate': (14, 'date'), - 'fbool': (1, 'bool')}) + self.assertEqual( + fields, + { + "X": (6, "double"), + "Y": (6, "double"), + "Z": (6, "double"), + "fid": (4, "longlong"), + "freal": (6, "double"), + "ftext": (10, "text"), + "fint": (2, "integer"), + "flong": (4, "longlong"), + "fdate": (14, "date"), + "fbool": (1, "bool"), + }, + ) geometries = [f.geometry() for f in vl.getFeatures()] - self.assertGeometriesEqual(geometries[-1], QgsGeometry.fromWkt('PointZ (-106.10858956482799442 35.40740071231100217 456)')) + self.assertGeometriesEqual( + geometries[-1], + QgsGeometry.fromWkt( + "PointZ (-106.10858956482799442 35.40740071231100217 456)" + ), + ) def test_booleans(self): """Test bool detection with user defined literals""" - vl = self._make_test_file('\n'.join(( - "id,bool_true_false,bool_0_1,bool_t_f,invalid_bool", - "2,true,1,t,nope", - "3,false,0,f,dope", - "4,TRUE,1,T,NOPE", - ))) + vl = self._make_test_file( + "\n".join( + ( + "id,bool_true_false,bool_0_1,bool_t_f,invalid_bool", + "2,true,1,t,nope", + "3,false,0,f,dope", + "4,TRUE,1,T,NOPE", + ) + ) + ) fields = {f.name(): (f.type(), f.typeName()) for f in vl.fields()} - self.assertEqual(fields, { - 'id': (2, 'integer'), - 'bool_true_false': (QVariant.Bool, 'bool'), - 'bool_0_1': (QVariant.Bool, 'bool'), - 'bool_t_f': (QVariant.Bool, 'bool'), - 'invalid_bool': (QVariant.String, 'text')}, + self.assertEqual( + fields, + { + "id": (2, "integer"), + "bool_true_false": (QVariant.Bool, "bool"), + "bool_0_1": (QVariant.Bool, "bool"), + "bool_t_f": (QVariant.Bool, "bool"), + "invalid_bool": (QVariant.String, "text"), + }, ) attrs = [f.attributes() for f in vl.getFeatures()] - self.assertEqual(attrs, [ - [2, True, True, True, 'nope'], - [3, False, False, False, 'dope'], - [4, True, True, True, 'NOPE'], - ]) - - vl = self._make_test_file('\n'.join(( - "id,bool_true_false,bool_0_1,bool_t_f,invalid_bool", - "2,true,1,t,nope", - "3,false,0,f,dope", - "4,TRUE,1,T,NOPE", - )), uri_options='booleanTrue=DOPE&booleanFalse=NoPe') + self.assertEqual( + attrs, + [ + [2, True, True, True, "nope"], + [3, False, False, False, "dope"], + [4, True, True, True, "NOPE"], + ], + ) + + vl = self._make_test_file( + "\n".join( + ( + "id,bool_true_false,bool_0_1,bool_t_f,invalid_bool", + "2,true,1,t,nope", + "3,false,0,f,dope", + "4,TRUE,1,T,NOPE", + ) + ), + uri_options="booleanTrue=DOPE&booleanFalse=NoPe", + ) fields = {f.name(): (f.type(), f.typeName()) for f in vl.fields()} - self.assertEqual(fields, { - 'id': (2, 'integer'), - 'bool_true_false': (QVariant.Bool, 'bool'), - 'bool_0_1': (QVariant.Bool, 'bool'), - 'bool_t_f': (QVariant.Bool, 'bool'), - 'invalid_bool': (QVariant.Bool, 'bool')}, + self.assertEqual( + fields, + { + "id": (2, "integer"), + "bool_true_false": (QVariant.Bool, "bool"), + "bool_0_1": (QVariant.Bool, "bool"), + "bool_t_f": (QVariant.Bool, "bool"), + "invalid_bool": (QVariant.Bool, "bool"), + }, ) attrs = [f.attributes() for f in vl.getFeatures()] - self.assertEqual(attrs, [ - [2, True, True, True, False], - [3, False, False, False, True], - [4, True, True, True, False], - ]) - - vl = self._make_test_file('\n'.join(( - "id,bool_true_false,bool_0_1,bool_t_f,invalid_bool", - "2,true,1,t,nope", - "3,false,0,f,dope", - "4,TRUE,1,T,", - )), uri_options='booleanTrue=DOPE&booleanFalse=NoPe') + self.assertEqual( + attrs, + [ + [2, True, True, True, False], + [3, False, False, False, True], + [4, True, True, True, False], + ], + ) + + vl = self._make_test_file( + "\n".join( + ( + "id,bool_true_false,bool_0_1,bool_t_f,invalid_bool", + "2,true,1,t,nope", + "3,false,0,f,dope", + "4,TRUE,1,T,", + ) + ), + uri_options="booleanTrue=DOPE&booleanFalse=NoPe", + ) attrs = [f.attributes() for f in vl.getFeatures()] - self.assertEqual(attrs, [ - [2, True, True, True, False], - [3, False, False, False, True], - [4, True, True, True, NULL], - ]) + self.assertEqual( + attrs, + [ + [2, True, True, True, False], + [3, False, False, False, True], + [4, True, True, True, NULL], + ], + ) def test_type_override(self): """Test type overrides""" - vl = self._make_test_file('\n'.join(( - "integer,bool,long,real,text", - "1,0,9189304972279762602,1.234,text", - "2,1,,5.678,another text", - ))) + vl = self._make_test_file( + "\n".join( + ( + "integer,bool,long,real,text", + "1,0,9189304972279762602,1.234,text", + "2,1,,5.678,another text", + ) + ) + ) self.assertTrue(vl.isValid()) fields = {f.name(): (f.type(), f.typeName()) for f in vl.fields()} - self.assertEqual(fields, { - 'integer': (QVariant.Int, 'integer'), - 'bool': (QVariant.Bool, 'bool'), - 'long': (QVariant.LongLong, 'longlong'), - 'real': (QVariant.Double, 'double'), - 'text': (QVariant.String, 'text')}) + self.assertEqual( + fields, + { + "integer": (QVariant.Int, "integer"), + "bool": (QVariant.Bool, "bool"), + "long": (QVariant.LongLong, "longlong"), + "real": (QVariant.Double, "double"), + "text": (QVariant.String, "text"), + }, + ) attrs = [f.attributes() for f in vl.getFeatures()] - self.assertEqual(attrs, [[1, False, 9189304972279762602, 1.234, 'text'], - [2, True, NULL, 5.678, 'another text']]) - - vl = self._make_test_file('\n'.join(( - "integer,bool,long,real,text", - "1,0,9189304972279762602,1.234,text", - "2,1,,5.678,another text", - )), uri_options='field=bool:integer&field=integer:double&field=long:double&field=real:text') + self.assertEqual( + attrs, + [ + [1, False, 9189304972279762602, 1.234, "text"], + [2, True, NULL, 5.678, "another text"], + ], + ) + + vl = self._make_test_file( + "\n".join( + ( + "integer,bool,long,real,text", + "1,0,9189304972279762602,1.234,text", + "2,1,,5.678,another text", + ) + ), + uri_options="field=bool:integer&field=integer:double&field=long:double&field=real:text", + ) self.assertTrue(vl.isValid()) fields = {f.name(): (f.type(), f.typeName()) for f in vl.fields()} - self.assertEqual(fields, { - 'integer': (QVariant.Double, 'double'), - 'bool': (QVariant.Int, 'integer'), - 'long': (QVariant.Double, 'double'), - 'real': (QVariant.String, 'text'), - 'text': (QVariant.String, 'text')}) + self.assertEqual( + fields, + { + "integer": (QVariant.Double, "double"), + "bool": (QVariant.Int, "integer"), + "long": (QVariant.Double, "double"), + "real": (QVariant.String, "text"), + "text": (QVariant.String, "text"), + }, + ) attrs = [f.attributes() for f in vl.getFeatures()] - self.assertEqual(attrs, [[1.0, 0, 9.189304972279763e+18, '1.234', 'text'], - [2.0, 1, NULL, '5.678', 'another text']]) + self.assertEqual( + attrs, + [ + [1.0, 0, 9.189304972279763e18, "1.234", "text"], + [2.0, 1, NULL, "5.678", "another text"], + ], + ) def test_regression_gh46749(self): """Test regression GH #46749""" - vl = self._make_test_file('\n'.join(( - "integer,wkt,bool", - "1,POINT(0 0),1", - "2,POINT(1 1),0", - "3,POINT(2 2),1", - )), uri_options='geomType=Point&crs=EPSG:4326&wktField=wkt') + vl = self._make_test_file( + "\n".join( + ( + "integer,wkt,bool", + "1,POINT(0 0),1", + "2,POINT(1 1),0", + "3,POINT(2 2),1", + ) + ), + uri_options="geomType=Point&crs=EPSG:4326&wktField=wkt", + ) self.assertTrue(vl.isValid()) fields = {f.name(): (f.type(), f.typeName()) for f in vl.fields()} - self.assertEqual(fields, { - 'integer': (QVariant.Int, 'integer'), - 'bool': (QVariant.Bool, 'bool'), - }) + self.assertEqual( + fields, + { + "integer": (QVariant.Int, "integer"), + "bool": (QVariant.Bool, "bool"), + }, + ) # This was crashing! features = [f for f in vl.getFeatures()] def test_absolute_relative_uri(self): context = QgsReadWriteContext() - context.setPathResolver(QgsPathResolver(os.path.join(TEST_DATA_DIR, "project.qgs"))) + context.setPathResolver( + QgsPathResolver(os.path.join(TEST_DATA_DIR, "project.qgs")) + ) - csv_path = os.path.join(TEST_DATA_DIR, 'provider', 'delimited_xy.csv') + csv_path = os.path.join(TEST_DATA_DIR, "provider", "delimited_xy.csv") url = MyUrl.fromLocalFile(csv_path) url.addQueryItem("crs", "epsg:4326") url.addQueryItem("type", "csv") @@ -1414,17 +1722,29 @@ def test_absolute_relative_uri(self): url.addQueryItem("yField", "Y") absolute_uri = url.toString() - relative_uri = 'file:./provider/delimited_xy.csv?crs=epsg:4326&type=csv&xField=X&yField=Y' + relative_uri = ( + "file:./provider/delimited_xy.csv?crs=epsg:4326&type=csv&xField=X&yField=Y" + ) meta = QgsProviderRegistry.instance().providerMetadata("delimitedtext") assert meta is not None - self.assertEqual(meta.absoluteToRelativeUri(absolute_uri, context), relative_uri) - self.assertEqual(meta.relativeToAbsoluteUri(relative_uri, context), absolute_uri) + self.assertEqual( + meta.absoluteToRelativeUri(absolute_uri, context), relative_uri + ) + self.assertEqual( + meta.relativeToAbsoluteUri(relative_uri, context), absolute_uri + ) def test_special_characters_in_filepath(self): with tempfile.TemporaryDirectory() as tmpdir: - for basename in ("test.csv", "t e s t .csv", "tèst.csv", "teẞt.csv", "Ťest.csv"): + for basename in ( + "test.csv", + "t e s t .csv", + "tèst.csv", + "teẞt.csv", + "Ťest.csv", + ): filepath = Path(tmpdir) / basename filepath.write_text("id,name\n1,name1\n2,name2\n") self.assertTrue(filepath.exists()) @@ -1433,5 +1753,5 @@ def test_special_characters_in_filepath(self): self.assertTrue(vl.isValid()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsdelimitedtextprovider_wanted.py b/tests/src/python/test_qgsdelimitedtextprovider_wanted.py index 55385d741441..978c8447d3a5 100644 --- a/tests/src/python/test_qgsdelimitedtextprovider_wanted.py +++ b/tests/src/python/test_qgsdelimitedtextprovider_wanted.py @@ -15,2095 +15,2143 @@ *************************************************************************** """ -__author__ = 'Chris Crook' -__date__ = 'May 2013' -__copyright__ = '(C) 2013, Chris Crook' +__author__ = "Chris Crook" +__date__ = "May 2013" +__copyright__ = "(C) 2013, Chris Crook" def test_002_load_csv_file(): wanted = {} - wanted['uri'] = 'file://test.csv?geomType=none&type=csv' - wanted['fieldTypes'] = ['integer', 'text', 'text', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = "file://test.csv?geomType=none&type=csv" + wanted["fieldTypes"] = ["integer", "text", "text", "text", "text"] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Basic unquoted record', - 'data': 'Some data', - 'info': 'Some info', - 'field_5': 'NULL', - '#fid': 2, - '#geometry': 'None', + "id": "1", + "description": "Basic unquoted record", + "data": "Some data", + "info": "Some info", + "field_5": "NULL", + "#fid": 2, + "#geometry": "None", }, 3: { - 'id': '2', - 'description': 'Quoted field', - 'data': 'Quoted data', - 'info': 'Unquoted', - 'field_5': 'NULL', - '#fid': 3, - '#geometry': 'None', + "id": "2", + "description": "Quoted field", + "data": "Quoted data", + "info": "Unquoted", + "field_5": "NULL", + "#fid": 3, + "#geometry": "None", }, 4: { - 'id': '3', - 'description': 'Escaped quotes', - 'data': 'Quoted "citation" data', - 'info': 'Unquoted', - 'field_5': 'NULL', - '#fid': 4, - '#geometry': 'None', + "id": "3", + "description": "Escaped quotes", + "data": 'Quoted "citation" data', + "info": "Unquoted", + "field_5": "NULL", + "#fid": 4, + "#geometry": "None", }, 5: { - 'id': '4', - 'description': 'Quoted newlines', - 'data': 'Line 1\nLine 2\n\nLine 4', - 'info': 'No data', - 'field_5': 'NULL', - '#fid': 5, - '#geometry': 'None', + "id": "4", + "description": "Quoted newlines", + "data": "Line 1\nLine 2\n\nLine 4", + "info": "No data", + "field_5": "NULL", + "#fid": 5, + "#geometry": "None", }, 9: { - 'id': '5', - 'description': 'Extra fields', - 'data': 'data', - 'info': 'info', - 'field_5': 'message', - '#fid': 9, - '#geometry': 'None', + "id": "5", + "description": "Extra fields", + "data": "data", + "info": "info", + "field_5": "message", + "#fid": 9, + "#geometry": "None", }, 10: { - 'id': '6', - 'description': 'Missing fields', - 'data': 'NULL', - 'info': 'NULL', - 'field_5': 'NULL', - '#fid': 10, - '#geometry': 'None', + "id": "6", + "description": "Missing fields", + "data": "NULL", + "info": "NULL", + "field_5": "NULL", + "#fid": 10, + "#geometry": "None", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted def test_003_field_naming(): wanted = {} - wanted['uri'] = 'file://testfields.csv?geomType=none&type=csv' - wanted['fieldTypes'] = ['integer', 'text', 'text', 'text', 'text', 'text', 'text', 'text', 'text', 'text', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = "file://testfields.csv?geomType=none&type=csv" + wanted["fieldTypes"] = [ + "integer", + "text", + "text", + "text", + "text", + "text", + "text", + "text", + "text", + "text", + "text", + "text", + ] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': '2', - 'description': 'Generation of field names', - 'data': 'Some data', - 'field_4': 'Some info', - 'data_2': 'NULL', - '28': 'NULL', - '24.5': 'NULL', - 'field_3_1': 'NULL', - 'data_1': 'NULL', - 'field_10': 'NULL', - 'field_11': 'NULL', - 'field_12': 'last data', - '#fid': 2, - '#geometry': 'None', + "id": "2", + "description": "Generation of field names", + "data": "Some data", + "field_4": "Some info", + "data_2": "NULL", + "28": "NULL", + "24.5": "NULL", + "field_3_1": "NULL", + "data_1": "NULL", + "field_10": "NULL", + "field_11": "NULL", + "field_12": "last data", + "#fid": 2, + "#geometry": "None", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted def test_004_max_fields(): wanted = {} - wanted['uri'] = 'file://testfields.csv?geomType=none&maxFields=7&type=csv' - wanted['fieldTypes'] = ['integer', 'text', 'text', 'text', 'text', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = "file://testfields.csv?geomType=none&maxFields=7&type=csv" + wanted["fieldTypes"] = ["integer", "text", "text", "text", "text", "text", "text"] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': '2', - 'description': 'Generation of field names', - 'data': 'Some data', - 'field_4': 'Some info', - 'data_1': 'NULL', - '28': 'NULL', - '24.5': 'NULL', - '#fid': 2, - '#geometry': 'None', + "id": "2", + "description": "Generation of field names", + "data": "Some data", + "field_4": "Some info", + "data_1": "NULL", + "28": "NULL", + "24.5": "NULL", + "#fid": 2, + "#geometry": "None", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted def test_005_load_whitespace(): wanted = {} - wanted['uri'] = 'file://test.space?geomType=none&type=whitespace' - wanted['fieldTypes'] = ['integer', 'text', 'text', 'text', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = "file://test.space?geomType=none&type=whitespace" + wanted["fieldTypes"] = ["integer", "text", "text", "text", "text", "text"] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Simple_whitespace_file', - 'data': 'data1', - 'info': 'info1', - 'field_5': 'NULL', - 'field_6': 'NULL', - '#fid': 2, - '#geometry': 'None', + "id": "1", + "description": "Simple_whitespace_file", + "data": "data1", + "info": "info1", + "field_5": "NULL", + "field_6": "NULL", + "#fid": 2, + "#geometry": "None", }, 3: { - 'id': '2', - 'description': 'Whitespace_at_start_of_line', - 'data': 'data2', - 'info': 'info2', - 'field_5': 'NULL', - 'field_6': 'NULL', - '#fid': 3, - '#geometry': 'None', + "id": "2", + "description": "Whitespace_at_start_of_line", + "data": "data2", + "info": "info2", + "field_5": "NULL", + "field_6": "NULL", + "#fid": 3, + "#geometry": "None", }, 4: { - 'id': '3', - 'description': 'Tab_whitespace', - 'data': 'data3', - 'info': 'info3', - 'field_5': 'NULL', - 'field_6': 'NULL', - '#fid': 4, - '#geometry': 'None', + "id": "3", + "description": "Tab_whitespace", + "data": "data3", + "info": "info3", + "field_5": "NULL", + "field_6": "NULL", + "#fid": 4, + "#geometry": "None", }, 5: { - 'id': '4', - 'description': 'Multiple_whitespace_characters', - 'data': 'data4', - 'info': 'info4', - 'field_5': 'NULL', - 'field_6': 'NULL', - '#fid': 5, - '#geometry': 'None', + "id": "4", + "description": "Multiple_whitespace_characters", + "data": "data4", + "info": "info4", + "field_5": "NULL", + "field_6": "NULL", + "#fid": 5, + "#geometry": "None", }, 6: { - 'id': '5', - 'description': 'Extra_fields', - 'data': 'data5', - 'info': 'info5', - 'field_5': 'message5', - 'field_6': 'rubbish5', - '#fid': 6, - '#geometry': 'None', + "id": "5", + "description": "Extra_fields", + "data": "data5", + "info": "info5", + "field_5": "message5", + "field_6": "rubbish5", + "#fid": 6, + "#geometry": "None", }, 7: { - 'id': '6', - 'description': 'Missing_fields', - 'data': 'NULL', - 'info': 'NULL', - 'field_5': 'NULL', - 'field_6': 'NULL', - '#fid': 7, - '#geometry': 'None', + "id": "6", + "description": "Missing_fields", + "data": "NULL", + "info": "NULL", + "field_5": "NULL", + "field_6": "NULL", + "#fid": 7, + "#geometry": "None", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted def test_006_quote_escape(): wanted = {} - wanted['uri'] = 'file://test.pipe?geomType=none"e="&delimiter=|&escape=\\' - wanted['fieldTypes'] = ['integer', 'text', 'text', 'text', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = 'file://test.pipe?geomType=none"e="&delimiter=|&escape=\\' + wanted["fieldTypes"] = ["integer", "text", "text", "text", "text", "text"] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Using pipe delimiter', - 'data': 'data 1', - 'info': 'info 1', - 'field_5': 'NULL', - 'field_6': 'NULL', - '#fid': 2, - '#geometry': 'None', + "id": "1", + "description": "Using pipe delimiter", + "data": "data 1", + "info": "info 1", + "field_5": "NULL", + "field_6": "NULL", + "#fid": 2, + "#geometry": "None", }, 3: { - 'id': '2', - 'description': 'Using backslash escape on pipe', - 'data': 'data 2 | piped', - 'info': 'info2', - 'field_5': 'NULL', - 'field_6': 'NULL', - '#fid': 3, - '#geometry': 'None', + "id": "2", + "description": "Using backslash escape on pipe", + "data": "data 2 | piped", + "info": "info2", + "field_5": "NULL", + "field_6": "NULL", + "#fid": 3, + "#geometry": "None", }, 4: { - 'id': '3', - 'description': 'Backslash escaped newline', - 'data': 'data3 \nline2 \nline3', - 'info': 'info3', - 'field_5': 'NULL', - 'field_6': 'NULL', - '#fid': 4, - '#geometry': 'None', + "id": "3", + "description": "Backslash escaped newline", + "data": "data3 \nline2 \nline3", + "info": "info3", + "field_5": "NULL", + "field_6": "NULL", + "#fid": 4, + "#geometry": "None", }, 7: { - 'id': '4', - 'description': 'Empty field', - 'data': 'NULL', - 'info': 'info4', - 'field_5': 'NULL', - 'field_6': 'NULL', - '#fid': 7, - '#geometry': 'None', + "id": "4", + "description": "Empty field", + "data": "NULL", + "info": "info4", + "field_5": "NULL", + "field_6": "NULL", + "#fid": 7, + "#geometry": "None", }, 8: { - 'id': '5', - 'description': 'Quoted field', - 'data': 'More | piped data', - 'info': 'info5', - 'field_5': 'NULL', - 'field_6': 'NULL', - '#fid': 8, - '#geometry': 'None', + "id": "5", + "description": "Quoted field", + "data": "More | piped data", + "info": "info5", + "field_5": "NULL", + "field_6": "NULL", + "#fid": 8, + "#geometry": "None", }, 9: { - 'id': '6', - 'description': 'Escaped quote', - 'data': 'Field "citation" ', - 'info': 'info6', - 'field_5': 'NULL', - 'field_6': 'NULL', - '#fid': 9, - '#geometry': 'None', + "id": "6", + "description": "Escaped quote", + "data": 'Field "citation" ', + "info": "info6", + "field_5": "NULL", + "field_6": "NULL", + "#fid": 9, + "#geometry": "None", }, 10: { - 'id': '7', - 'description': 'Missing fields', - 'data': 'NULL', - 'info': 'NULL', - 'field_5': 'NULL', - 'field_6': 'NULL', - '#fid': 10, - '#geometry': 'None', + "id": "7", + "description": "Missing fields", + "data": "NULL", + "info": "NULL", + "field_5": "NULL", + "field_6": "NULL", + "#fid": 10, + "#geometry": "None", }, 11: { - 'id': '8', - 'description': 'Extra fields', - 'data': 'data8', - 'info': 'info8', - 'field_5': 'message8', - 'field_6': 'more', - '#fid': 11, - '#geometry': 'None', + "id": "8", + "description": "Extra fields", + "data": "data8", + "info": "info8", + "field_5": "message8", + "field_6": "more", + "#fid": 11, + "#geometry": "None", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted def test_007_multiple_quote(): wanted = {} - wanted['uri'] = 'file://test.quote?geomType=none"e=\'"&type=csv&escape="\'' - wanted['fieldTypes'] = ['integer', 'text', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = "file://test.quote?geomType=none"e='\"&type=csv&escape=\"'" + wanted["fieldTypes"] = ["integer", "text", "text", "text"] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Multiple quotes 1', - 'data': 'Quoted,data1', - 'info': 'info1', - '#fid': 2, - '#geometry': 'None', + "id": "1", + "description": "Multiple quotes 1", + "data": "Quoted,data1", + "info": "info1", + "#fid": 2, + "#geometry": "None", }, 3: { - 'id': '2', - 'description': 'Multiple quotes 2', - 'data': 'Quoted,data2', - 'info': 'info2', - '#fid': 3, - '#geometry': 'None', + "id": "2", + "description": "Multiple quotes 2", + "data": "Quoted,data2", + "info": "info2", + "#fid": 3, + "#geometry": "None", }, 4: { - 'id': '3', - 'description': 'Leading and following whitespace', - 'data': 'Quoted, data3', - 'info': 'info3', - '#fid': 4, - '#geometry': 'None', + "id": "3", + "description": "Leading and following whitespace", + "data": "Quoted, data3", + "info": "info3", + "#fid": 4, + "#geometry": "None", }, 5: { - 'id': '4', - 'description': 'Embedded quotes 1', - 'data': 'Quoted \'\'"\'\' data4', - 'info': 'info4', - '#fid': 5, - '#geometry': 'None', + "id": "4", + "description": "Embedded quotes 1", + "data": "Quoted ''\"'' data4", + "info": "info4", + "#fid": 5, + "#geometry": "None", }, 6: { - 'id': '5', - 'description': 'Embedded quotes 2', - 'data': 'Quoted \'""\' data5', - 'info': 'info5', - '#fid': 6, - '#geometry': 'None', + "id": "5", + "description": "Embedded quotes 2", + "data": "Quoted '\"\"' data5", + "info": "info5", + "#fid": 6, + "#geometry": "None", }, 10: { - 'id': '9', - 'description': 'Final record', - 'data': 'date9', - 'info': 'info9', - '#fid': 10, - '#geometry': 'None', + "id": "9", + "description": "Final record", + "data": "date9", + "info": "info9", + "#fid": 10, + "#geometry": "None", }, } - wanted['log'] = [ - 'Errors in file test.quote', - '3 record(s) discarded due to invalid format', - 'The following lines were not loaded into QGIS due to errors:', - 'Invalid record format at line 7', - 'Invalid record format at line 8', - 'Invalid record format at line 9', + wanted["log"] = [ + "Errors in file test.quote", + "3 record(s) discarded due to invalid format", + "The following lines were not loaded into QGIS due to errors:", + "Invalid record format at line 7", + "Invalid record format at line 8", + "Invalid record format at line 9", ] return wanted def test_008_badly_formed_quotes(): wanted = {} - wanted['uri'] = 'file://test.badquote?geomType=none"e="&type=csv&escape="' - wanted['fieldTypes'] = ['integer', 'text', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = 'file://test.badquote?geomType=none"e="&type=csv&escape="' + wanted["fieldTypes"] = ["integer", "text", "text", "text"] + wanted["geometryType"] = 4 + wanted["data"] = { 4: { - 'id': '3', - 'description': 'Recovered after unclosed quore', - 'data': 'Data ok', - 'info': 'inf3', - '#fid': 4, - '#geometry': 'None', + "id": "3", + "description": "Recovered after unclosed quore", + "data": "Data ok", + "info": "inf3", + "#fid": 4, + "#geometry": "None", }, } - wanted['log'] = [ - 'Errors in file test.badquote', - '2 record(s) discarded due to invalid format', - 'The following lines were not loaded into QGIS due to errors:', - 'Invalid record format at line 2', - 'Invalid record format at line 5', + wanted["log"] = [ + "Errors in file test.badquote", + "2 record(s) discarded due to invalid format", + "The following lines were not loaded into QGIS due to errors:", + "Invalid record format at line 2", + "Invalid record format at line 5", ] return wanted def test_009_skip_lines(): wanted = {} - wanted['uri'] = 'file://test2.csv?geomType=none&skipLines=2&type=csv&useHeader=no' - wanted['fieldTypes'] = ['integer', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = "file://test2.csv?geomType=none&skipLines=2&type=csv&useHeader=no" + wanted["fieldTypes"] = ["integer", "text", "text"] + wanted["geometryType"] = 4 + wanted["data"] = { 3: { - 'id': '3', - 'description': 'Less data', - 'field_1': '3', - 'field_2': 'Less data', - 'field_3': 'data3', - '#fid': 3, - '#geometry': 'None', + "id": "3", + "description": "Less data", + "field_1": "3", + "field_2": "Less data", + "field_3": "data3", + "#fid": 3, + "#geometry": "None", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted def test_010_read_coordinates(): wanted = {} - wanted['uri'] = 'file://testpt.csv?yField=geom_y&xField=geom_x&type=csv' - wanted['fieldTypes'] = ['integer', 'text', 'double', 'double'] - wanted['geometryType'] = 0 - wanted['data'] = { + wanted["uri"] = "file://testpt.csv?yField=geom_y&xField=geom_x&type=csv" + wanted["fieldTypes"] = ["integer", "text", "double", "double"] + wanted["geometryType"] = 0 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Basic point', - 'geom_x': '10.5', - 'geom_y': '20.82', - '#fid': 2, - '#geometry': 'Point (10.5 20.82)', + "id": "1", + "description": "Basic point", + "geom_x": "10.5", + "geom_y": "20.82", + "#fid": 2, + "#geometry": "Point (10.5 20.82)", }, 3: { - 'id': '2', - 'description': 'Integer point', - 'geom_x': '11.0', - 'geom_y': '22.0', - '#fid': 3, - '#geometry': 'Point (11 22)', + "id": "2", + "description": "Integer point", + "geom_x": "11.0", + "geom_y": "22.0", + "#fid": 3, + "#geometry": "Point (11 22)", }, 5: { - 'id': '4', - 'description': 'Final point', - 'geom_x': '13.0', - 'geom_y': '23.0', - '#fid': 5, - '#geometry': 'Point (13 23)', + "id": "4", + "description": "Final point", + "geom_x": "13.0", + "geom_y": "23.0", + "#fid": 5, + "#geometry": "Point (13 23)", }, } - wanted['log'] = [ - 'Errors in file testpt.csv', - '1 record(s) discarded due to invalid geometry definitions', - 'The following lines were not loaded into QGIS due to errors:', - 'Invalid X or Y fields at line 4', + wanted["log"] = [ + "Errors in file testpt.csv", + "1 record(s) discarded due to invalid geometry definitions", + "The following lines were not loaded into QGIS due to errors:", + "Invalid X or Y fields at line 4", ] return wanted def test_011_read_wkt(): wanted = {} - wanted['uri'] = 'file://testwkt.csv?delimiter=|&type=csv&wktField=geom_wkt' - wanted['fieldTypes'] = ['integer', 'text'] - wanted['geometryType'] = 0 - wanted['data'] = { + wanted["uri"] = "file://testwkt.csv?delimiter=|&type=csv&wktField=geom_wkt" + wanted["fieldTypes"] = ["integer", "text"] + wanted["geometryType"] = 0 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Point wkt', - '#fid': 2, - '#geometry': 'Point (10 20)', + "id": "1", + "description": "Point wkt", + "#fid": 2, + "#geometry": "Point (10 20)", }, 3: { - 'id': '2', - 'description': 'Multipoint wkt', - '#fid': 3, - '#geometry': 'MultiPoint ((10 20),(11 21))', + "id": "2", + "description": "Multipoint wkt", + "#fid": 3, + "#geometry": "MultiPoint ((10 20),(11 21))", }, 9: { - 'id': '8', - 'description': 'EWKT prefix', - '#fid': 9, - '#geometry': 'Point (10 10)', + "id": "8", + "description": "EWKT prefix", + "#fid": 9, + "#geometry": "Point (10 10)", }, 10: { - 'id': '9', - 'description': 'Informix prefix', - '#fid': 10, - '#geometry': 'Point (10 10)', + "id": "9", + "description": "Informix prefix", + "#fid": 10, + "#geometry": "Point (10 10)", }, 11: { - 'id': '10', - 'description': 'Measure in point', - '#fid': 11, - '#geometry': 'PointM (10 20 30)', + "id": "10", + "description": "Measure in point", + "#fid": 11, + "#geometry": "PointM (10 20 30)", }, } - wanted['log'] = [ - 'Errors in file testwkt.csv', - '1 record(s) discarded due to invalid geometry definitions', - '10 record(s) discarded due to incompatible geometry types', - 'The following lines were not loaded into QGIS due to errors:', - 'Invalid WKT at line 8', + wanted["log"] = [ + "Errors in file testwkt.csv", + "1 record(s) discarded due to invalid geometry definitions", + "10 record(s) discarded due to incompatible geometry types", + "The following lines were not loaded into QGIS due to errors:", + "Invalid WKT at line 8", ] return wanted def test_012_read_wkt_point(): wanted = {} - wanted['uri'] = 'file://testwkt.csv?geomType=point&delimiter=|&type=csv&wktField=geom_wkt' - wanted['fieldTypes'] = ['integer', 'text'] - wanted['geometryType'] = 0 - wanted['data'] = { + wanted["uri"] = ( + "file://testwkt.csv?geomType=point&delimiter=|&type=csv&wktField=geom_wkt" + ) + wanted["fieldTypes"] = ["integer", "text"] + wanted["geometryType"] = 0 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Point wkt', - '#fid': 2, - '#geometry': 'Point (10 20)', + "id": "1", + "description": "Point wkt", + "#fid": 2, + "#geometry": "Point (10 20)", }, 3: { - 'id': '2', - 'description': 'Multipoint wkt', - '#fid': 3, - '#geometry': 'MultiPoint ((10 20),(11 21))', + "id": "2", + "description": "Multipoint wkt", + "#fid": 3, + "#geometry": "MultiPoint ((10 20),(11 21))", }, 9: { - 'id': '8', - 'description': 'EWKT prefix', - '#fid': 9, - '#geometry': 'Point (10 10)', + "id": "8", + "description": "EWKT prefix", + "#fid": 9, + "#geometry": "Point (10 10)", }, 10: { - 'id': '9', - 'description': 'Informix prefix', - '#fid': 10, - '#geometry': 'Point (10 10)', + "id": "9", + "description": "Informix prefix", + "#fid": 10, + "#geometry": "Point (10 10)", }, 11: { - 'id': '10', - 'description': 'Measure in point', - '#fid': 11, - '#geometry': 'PointM (10 20 30)', + "id": "10", + "description": "Measure in point", + "#fid": 11, + "#geometry": "PointM (10 20 30)", }, } - wanted['log'] = [ - 'Errors in file testwkt.csv', - '1 record(s) discarded due to invalid geometry definitions', - '10 record(s) discarded due to incompatible geometry types', - 'The following lines were not loaded into QGIS due to errors:', - 'Invalid WKT at line 8', + wanted["log"] = [ + "Errors in file testwkt.csv", + "1 record(s) discarded due to invalid geometry definitions", + "10 record(s) discarded due to incompatible geometry types", + "The following lines were not loaded into QGIS due to errors:", + "Invalid WKT at line 8", ] return wanted def test_013_read_wkt_line(): wanted = {} - wanted['uri'] = 'file://testwkt.csv?geomType=line&delimiter=|&type=csv&wktField=geom_wkt' - wanted['fieldTypes'] = ['integer', 'text'] - wanted['geometryType'] = 1 - wanted['data'] = { + wanted["uri"] = ( + "file://testwkt.csv?geomType=line&delimiter=|&type=csv&wktField=geom_wkt" + ) + wanted["fieldTypes"] = ["integer", "text"] + wanted["geometryType"] = 1 + wanted["data"] = { 4: { - 'id': '3', - 'description': 'Linestring wkt', - '#fid': 4, - '#geometry': 'LineString (10 20, 11 21)', + "id": "3", + "description": "Linestring wkt", + "#fid": 4, + "#geometry": "LineString (10 20, 11 21)", }, 5: { - 'id': '4', - 'description': 'Multiline string wkt', - '#fid': 5, - '#geometry': 'MultiLineString ((10 20, 11 21), (20 30, 21 31))', + "id": "4", + "description": "Multiline string wkt", + "#fid": 5, + "#geometry": "MultiLineString ((10 20, 11 21), (20 30, 21 31))", }, 12: { - 'id': '11', - 'description': 'Measure in line', - '#fid': 12, - '#geometry': 'LineStringM (10 20 30, 11 21 31)', + "id": "11", + "description": "Measure in line", + "#fid": 12, + "#geometry": "LineStringM (10 20 30, 11 21 31)", }, 13: { - 'id': '12', - 'description': 'Z in line', - '#fid': 13, - '#geometry': 'LineStringZ (10 20 30, 11 21 31)', + "id": "12", + "description": "Z in line", + "#fid": 13, + "#geometry": "LineStringZ (10 20 30, 11 21 31)", }, 14: { - 'id': '13', - 'description': 'Measure and Z in line', - '#fid': 14, - '#geometry': 'LineStringZM (10 20 30 40, 11 21 31 41)', + "id": "13", + "description": "Measure and Z in line", + "#fid": 14, + "#geometry": "LineStringZM (10 20 30 40, 11 21 31 41)", }, 15: { - 'id': '14', - 'description': 'CircularString', - '#fid': 15, - '#geometry': 'CircularString (268 415, 227 505, 227 406)', + "id": "14", + "description": "CircularString", + "#fid": 15, + "#geometry": "CircularString (268 415, 227 505, 227 406)", }, 17: { - 'id': '16', - 'description': 'CompoundCurve', - '#fid': 17, - '#geometry': 'CompoundCurve ((5 3, 5 13), CircularString(5 13, 7 15, 9 13), (9 13, 9 3), CircularString(9 3, 7 1, 5 3))', + "id": "16", + "description": "CompoundCurve", + "#fid": 17, + "#geometry": "CompoundCurve ((5 3, 5 13), CircularString(5 13, 7 15, 9 13), (9 13, 9 3), CircularString(9 3, 7 1, 5 3))", }, } - wanted['log'] = [ - 'Errors in file testwkt.csv', - '1 record(s) discarded due to invalid geometry definitions', - '8 record(s) discarded due to incompatible geometry types', - 'The following lines were not loaded into QGIS due to errors:', - 'Invalid WKT at line 8', + wanted["log"] = [ + "Errors in file testwkt.csv", + "1 record(s) discarded due to invalid geometry definitions", + "8 record(s) discarded due to incompatible geometry types", + "The following lines were not loaded into QGIS due to errors:", + "Invalid WKT at line 8", ] return wanted def test_014_read_wkt_polygon(): wanted = {} - wanted['uri'] = 'file://testwkt.csv?geomType=polygon&delimiter=|&type=csv&wktField=geom_wkt' - wanted['fieldTypes'] = ['integer', 'text'] - wanted['geometryType'] = 2 - wanted['data'] = { + wanted["uri"] = ( + "file://testwkt.csv?geomType=polygon&delimiter=|&type=csv&wktField=geom_wkt" + ) + wanted["fieldTypes"] = ["integer", "text"] + wanted["geometryType"] = 2 + wanted["data"] = { 6: { - 'id': '5', - 'description': 'Polygon wkt', - '#fid': 6, - '#geometry': 'Polygon ((10 10,10 20,20 20,20 10,10 10),(14 14,14 16,16 16,14 14))', + "id": "5", + "description": "Polygon wkt", + "#fid": 6, + "#geometry": "Polygon ((10 10,10 20,20 20,20 10,10 10),(14 14,14 16,16 16,14 14))", }, 7: { - 'id': '6', - 'description': 'MultiPolygon wkt', - '#fid': 7, - '#geometry': 'MultiPolygon (((10 10,10 20,20 20,20 10,10 10),(14 14,14 16,16 16,14 14)),((30 30,30 35,35 35,30 30)))', + "id": "6", + "description": "MultiPolygon wkt", + "#fid": 7, + "#geometry": "MultiPolygon (((10 10,10 20,20 20,20 10,10 10),(14 14,14 16,16 16,14 14)),((30 30,30 35,35 35,30 30)))", }, 16: { - 'id': '15', - 'description': 'CurvePolygon', - '#fid': 16, - '#geometry': 'CurvePolygon (CircularString (1 3, 3 5, 4 7, 7 3, 1 3))', + "id": "15", + "description": "CurvePolygon", + "#fid": 16, + "#geometry": "CurvePolygon (CircularString (1 3, 3 5, 4 7, 7 3, 1 3))", }, } - wanted['log'] = [ - 'Errors in file testwkt.csv', - '1 record(s) discarded due to invalid geometry definitions', - '12 record(s) discarded due to incompatible geometry types', - 'The following lines were not loaded into QGIS due to errors:', - 'Invalid WKT at line 8', + wanted["log"] = [ + "Errors in file testwkt.csv", + "1 record(s) discarded due to invalid geometry definitions", + "12 record(s) discarded due to incompatible geometry types", + "The following lines were not loaded into QGIS due to errors:", + "Invalid WKT at line 8", ] return wanted def test_015_read_dms_xy(): wanted = {} - wanted['uri'] = 'file://testdms.csv?yField=lat&xField=lon&type=csv&xyDms=yes' - wanted['fieldTypes'] = ['integer', 'text', 'text', 'text'] - wanted['geometryType'] = 0 - wanted['data'] = { + wanted["uri"] = "file://testdms.csv?yField=lat&xField=lon&type=csv&xyDms=yes" + wanted["fieldTypes"] = ["integer", "text", "text", "text"] + wanted["geometryType"] = 0 + wanted["data"] = { 3: { - 'id': '1', - 'description': 'Basic DMS string', - 'lon': '1 5 30.6', - 'lat': '35 51 20', - '#fid': 3, - '#geometry': 'Point (1.09183333 35.85555556)', + "id": "1", + "description": "Basic DMS string", + "lon": "1 5 30.6", + "lat": "35 51 20", + "#fid": 3, + "#geometry": "Point (1.09183333 35.85555556)", }, 4: { - 'id': '2', - 'description': 'Basic DMS string 2', - 'lon': '1 05 30.6005', - 'lat': '035 51 20', - '#fid': 4, - '#geometry': 'Point (1.09183347 35.85555556)', + "id": "2", + "description": "Basic DMS string 2", + "lon": "1 05 30.6005", + "lat": "035 51 20", + "#fid": 4, + "#geometry": "Point (1.09183347 35.85555556)", }, 5: { - 'id': '3', - 'description': 'Basic DMS string 3', - 'lon': '1 05 30.6', - 'lat': '35 59 9.99', - '#fid': 5, - '#geometry': 'Point (1.09183333 35.98610833)', + "id": "3", + "description": "Basic DMS string 3", + "lon": "1 05 30.6", + "lat": "35 59 9.99", + "#fid": 5, + "#geometry": "Point (1.09183333 35.98610833)", }, 7: { - 'id': '4', - 'description': 'Prefix sign 1', - 'lon': 'n1 05 30.6', - 'lat': 'e035 51 20', - '#fid': 7, - '#geometry': 'Point (1.09183333 35.85555556)', + "id": "4", + "description": "Prefix sign 1", + "lon": "n1 05 30.6", + "lat": "e035 51 20", + "#fid": 7, + "#geometry": "Point (1.09183333 35.85555556)", }, 8: { - 'id': '5', - 'description': 'Prefix sign 2', - 'lon': 'N1 05 30.6', - 'lat': 'E035 51 20', - '#fid': 8, - '#geometry': 'Point (1.09183333 35.85555556)', + "id": "5", + "description": "Prefix sign 2", + "lon": "N1 05 30.6", + "lat": "E035 51 20", + "#fid": 8, + "#geometry": "Point (1.09183333 35.85555556)", }, 9: { - 'id': '6', - 'description': 'Prefix sign 3', - 'lon': 'N 1 05 30.6', - 'lat': 'E 035 51 20', - '#fid': 9, - '#geometry': 'Point (1.09183333 35.85555556)', + "id": "6", + "description": "Prefix sign 3", + "lon": "N 1 05 30.6", + "lat": "E 035 51 20", + "#fid": 9, + "#geometry": "Point (1.09183333 35.85555556)", }, 10: { - 'id': '7', - 'description': 'Prefix sign 4', - 'lon': 'S1 05 30.6', - 'lat': 'W035 51 20', - '#fid': 10, - '#geometry': 'Point (-1.09183333 -35.85555556)', + "id": "7", + "description": "Prefix sign 4", + "lon": "S1 05 30.6", + "lat": "W035 51 20", + "#fid": 10, + "#geometry": "Point (-1.09183333 -35.85555556)", }, 11: { - 'id': '8', - 'description': 'Prefix sign 5', - 'lon': '+1 05 30.6', - 'lat': '+035 51 20', - '#fid': 11, - '#geometry': 'Point (1.09183333 35.85555556)', + "id": "8", + "description": "Prefix sign 5", + "lon": "+1 05 30.6", + "lat": "+035 51 20", + "#fid": 11, + "#geometry": "Point (1.09183333 35.85555556)", }, 12: { - 'id': '9', - 'description': 'Prefix sign 6', - 'lon': '-1 05 30.6', - 'lat': '-035 51 20', - '#fid': 12, - '#geometry': 'Point (-1.09183333 -35.85555556)', + "id": "9", + "description": "Prefix sign 6", + "lon": "-1 05 30.6", + "lat": "-035 51 20", + "#fid": 12, + "#geometry": "Point (-1.09183333 -35.85555556)", }, 14: { - 'id': '10', - 'description': 'Postfix sign 1', - 'lon': '1 05 30.6n', - 'lat': '035 51 20e', - '#fid': 14, - '#geometry': 'Point (1.09183333 35.85555556)', + "id": "10", + "description": "Postfix sign 1", + "lon": "1 05 30.6n", + "lat": "035 51 20e", + "#fid": 14, + "#geometry": "Point (1.09183333 35.85555556)", }, 15: { - 'id': '11', - 'description': 'Postfix sign 2', - 'lon': '1 05 30.6N', - 'lat': '035 51 20E', - '#fid': 15, - '#geometry': 'Point (1.09183333 35.85555556)', + "id": "11", + "description": "Postfix sign 2", + "lon": "1 05 30.6N", + "lat": "035 51 20E", + "#fid": 15, + "#geometry": "Point (1.09183333 35.85555556)", }, 16: { - 'id': '12', - 'description': 'Postfix sign 3', - 'lon': '1 05 30.6 N', - 'lat': '035 51 20 E', - '#fid': 16, - '#geometry': 'Point (1.09183333 35.85555556)', + "id": "12", + "description": "Postfix sign 3", + "lon": "1 05 30.6 N", + "lat": "035 51 20 E", + "#fid": 16, + "#geometry": "Point (1.09183333 35.85555556)", }, 17: { - 'id': '13', - 'description': 'Postfix sign 4', - 'lon': '1 05 30.6S', - 'lat': '035 51 20W', - '#fid': 17, - '#geometry': 'Point (-1.09183333 -35.85555556)', + "id": "13", + "description": "Postfix sign 4", + "lon": "1 05 30.6S", + "lat": "035 51 20W", + "#fid": 17, + "#geometry": "Point (-1.09183333 -35.85555556)", }, 18: { - 'id': '14', - 'description': 'Postfix sign 5', - 'lon': '1 05 30.6+', - 'lat': '035 51 20+', - '#fid': 18, - '#geometry': 'Point (1.09183333 35.85555556)', + "id": "14", + "description": "Postfix sign 5", + "lon": "1 05 30.6+", + "lat": "035 51 20+", + "#fid": 18, + "#geometry": "Point (1.09183333 35.85555556)", }, 19: { - 'id': '15', - 'description': 'Postfix sign 6', - 'lon': '1 05 30.6-', - 'lat': '035 51 20-', - '#fid': 19, - '#geometry': 'Point (-1.09183333 -35.85555556)', + "id": "15", + "description": "Postfix sign 6", + "lon": "1 05 30.6-", + "lat": "035 51 20-", + "#fid": 19, + "#geometry": "Point (-1.09183333 -35.85555556)", }, 21: { - 'id': '16', - 'description': 'Leading and trailing blanks 1', - 'lon': ' 1 05 30.6', - 'lat': '035 51 20 ', - '#fid': 21, - '#geometry': 'Point (1.09183333 35.85555556)', + "id": "16", + "description": "Leading and trailing blanks 1", + "lon": " 1 05 30.6", + "lat": "035 51 20 ", + "#fid": 21, + "#geometry": "Point (1.09183333 35.85555556)", }, 22: { - 'id': '17', - 'description': 'Leading and trailing blanks 2', - 'lon': ' N 1 05 30.6', - 'lat': '035 51 20 E ', - '#fid': 22, - '#geometry': 'Point (1.09183333 35.85555556)', + "id": "17", + "description": "Leading and trailing blanks 2", + "lon": " N 1 05 30.6", + "lat": "035 51 20 E ", + "#fid": 22, + "#geometry": "Point (1.09183333 35.85555556)", }, 24: { - 'id': '18', - 'description': 'Alternative characters for D,M,S', - 'lon': '1d05m30.6s S', - 'lat': "35d51'20", - '#fid': 24, - '#geometry': 'Point (-1.09183333 35.85555556)', + "id": "18", + "description": "Alternative characters for D,M,S", + "lon": "1d05m30.6s S", + "lat": "35d51'20", + "#fid": 24, + "#geometry": "Point (-1.09183333 35.85555556)", }, 25: { - 'id': '19', - 'description': 'Degrees/minutes format', - 'lon': '1 05.23', - 'lat': '4 55.03', - '#fid': 25, - '#geometry': 'Point (1.08716667 4.91716667)', + "id": "19", + "description": "Degrees/minutes format", + "lon": "1 05.23", + "lat": "4 55.03", + "#fid": 25, + "#geometry": "Point (1.08716667 4.91716667)", }, } - wanted['log'] = [ - 'Errors in file testdms.csv', - '5 record(s) discarded due to invalid geometry definitions', - 'The following lines were not loaded into QGIS due to errors:', - 'Invalid X or Y fields at line 27', - 'Invalid X or Y fields at line 28', - 'Invalid X or Y fields at line 29', - 'Invalid X or Y fields at line 30', - 'Invalid X or Y fields at line 31', + wanted["log"] = [ + "Errors in file testdms.csv", + "5 record(s) discarded due to invalid geometry definitions", + "The following lines were not loaded into QGIS due to errors:", + "Invalid X or Y fields at line 27", + "Invalid X or Y fields at line 28", + "Invalid X or Y fields at line 29", + "Invalid X or Y fields at line 30", + "Invalid X or Y fields at line 31", ] return wanted def test_016_decimal_point(): wanted = {} - wanted['uri'] = 'file://testdp.csv?yField=geom_y&xField=geom_x&type=csv&delimiter=;&decimalPoint=,' - wanted['fieldTypes'] = ['integer', 'text', 'double', 'double', 'double', 'text'] - wanted['geometryType'] = 0 - wanted['data'] = { + wanted["uri"] = ( + "file://testdp.csv?yField=geom_y&xField=geom_x&type=csv&delimiter=;&decimalPoint=," + ) + wanted["fieldTypes"] = ["integer", "text", "double", "double", "double", "text"] + wanted["geometryType"] = 0 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Comma as decimal point 1', - 'geom_x': '10.0', - 'geom_y': '20.0', - 'other': '30.0', - 'text field': 'Field with , in it', - '#fid': 2, - '#geometry': 'Point (10 20)', + "id": "1", + "description": "Comma as decimal point 1", + "geom_x": "10.0", + "geom_y": "20.0", + "other": "30.0", + "text field": "Field with , in it", + "#fid": 2, + "#geometry": "Point (10 20)", }, 3: { - 'id': '2', - 'description': 'Comma as decimal point 2', - 'geom_x': '12.0', - 'geom_y': '25.003', - 'other': '-38.55', - 'text field': 'Plain text field', - '#fid': 3, - '#geometry': 'Point (12 25.003)', + "id": "2", + "description": "Comma as decimal point 2", + "geom_x": "12.0", + "geom_y": "25.003", + "other": "-38.55", + "text field": "Plain text field", + "#fid": 3, + "#geometry": "Point (12 25.003)", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted def test_017_regular_expression_1(): wanted = {} - wanted['uri'] = 'file://testre.txt?geomType=none&trimFields=Y&delimiter=RE(?:GEXP)?&type=regexp' - wanted['fieldTypes'] = ['integer', 'text', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = ( + "file://testre.txt?geomType=none&trimFields=Y&delimiter=RE(?:GEXP)?&type=regexp" + ) + wanted["fieldTypes"] = ["integer", "text", "text", "text"] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Basic regular expression test', - 'data': 'data1', - 'info': 'info', - '#fid': 2, - '#geometry': 'None', + "id": "1", + "description": "Basic regular expression test", + "data": "data1", + "info": "info", + "#fid": 2, + "#geometry": "None", }, 3: { - 'id': '2', - 'description': 'Basic regular expression test 2', - 'data': 'data2', - 'info': 'info2', - '#fid': 3, - '#geometry': 'None', + "id": "2", + "description": "Basic regular expression test 2", + "data": "data2", + "info": "info2", + "#fid": 3, + "#geometry": "None", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted def test_018_regular_expression_2(): wanted = {} - wanted['uri'] = 'file://testre.txt?geomType=none&trimFields=Y&delimiter=(RE)((?:GEXP)?)&type=regexp' - wanted['fieldTypes'] = ['integer', 'text', 'text', 'text', 'text', 'text', 'text', 'text', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = ( + "file://testre.txt?geomType=none&trimFields=Y&delimiter=(RE)((?:GEXP)?)&type=regexp" + ) + wanted["fieldTypes"] = [ + "integer", + "text", + "text", + "text", + "text", + "text", + "text", + "text", + "text", + "text", + ] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': '1', - 'RE': 'RE', - 'GEXP': 'GEXP', - 'description': 'RE', - 'RE_1': 'RE', - 'GEXP_1': 'GEXP', - 'data': 'data1', - 'RE_2': 'RE', - 'GEXP_2': 'GEXP', - 'info': 'info', - '#fid': 2, - '#geometry': 'None', + "id": "1", + "RE": "RE", + "GEXP": "GEXP", + "description": "RE", + "RE_1": "RE", + "GEXP_1": "GEXP", + "data": "data1", + "RE_2": "RE", + "GEXP_2": "GEXP", + "info": "info", + "#fid": 2, + "#geometry": "None", }, 3: { - 'id': '2', - 'RE': 'RE', - 'GEXP': 'GEXP', - 'description': 'RE', - 'RE_1': 'RE', - 'GEXP_1': '', - 'data': 'data2', - 'RE_2': 'RE', - 'GEXP_2': '', - 'info': 'info2', - '#fid': 3, - '#geometry': 'None', + "id": "2", + "RE": "RE", + "GEXP": "GEXP", + "description": "RE", + "RE_1": "RE", + "GEXP_1": "", + "data": "data2", + "RE_2": "RE", + "GEXP_2": "", + "info": "info2", + "#fid": 3, + "#geometry": "None", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted def test_019_regular_expression_3(): wanted = {} - wanted['uri'] = 'file://testre2.txt?geomType=none&trimFields=Y&delimiter=^(.{5})(.{30})(.{5,})&type=regexp' - wanted['fieldTypes'] = ['integer', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = ( + "file://testre2.txt?geomType=none&trimFields=Y&delimiter=^(.{5})(.{30})(.{5,})&type=regexp" + ) + wanted["fieldTypes"] = ["integer", "text", "text"] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Anchored regexp', - 'information': 'Some data', - '#fid': 2, - '#geometry': 'None', + "id": "1", + "description": "Anchored regexp", + "information": "Some data", + "#fid": 2, + "#geometry": "None", }, 4: { - 'id': '3', - 'description': 'Anchored regexp recovered', - 'information': 'Some data', - '#fid': 4, - '#geometry': 'None', + "id": "3", + "description": "Anchored regexp recovered", + "information": "Some data", + "#fid": 4, + "#geometry": "None", }, } - wanted['log'] = [ - 'Errors in file testre2.txt', - '1 record(s) discarded due to invalid format', - 'The following lines were not loaded into QGIS due to errors:', - 'Invalid record format at line 3', + wanted["log"] = [ + "Errors in file testre2.txt", + "1 record(s) discarded due to invalid format", + "The following lines were not loaded into QGIS due to errors:", + "Invalid record format at line 3", ] return wanted def test_020_regular_expression_4(): wanted = {} - wanted['uri'] = 'file://testre3.txt?geomType=none&delimiter=x?&type=regexp' - wanted['fieldTypes'] = ['text', 'text', 'text', 'text', 'text', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = "file://testre3.txt?geomType=none&delimiter=x?&type=regexp" + wanted["fieldTypes"] = ["text", "text", "text", "text", "text", "text", "text"] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': 'g', - 'description': 'i', - 's': 'g', - 'm': 'i', - 'a': '.', - 'l': '.', - 'l_1': 'i', - 'field_6': 'l', - 'field_7': 'e', - '#fid': 2, - '#geometry': 'None', + "id": "g", + "description": "i", + "s": "g", + "m": "i", + "a": ".", + "l": ".", + "l_1": "i", + "field_6": "l", + "field_7": "e", + "#fid": 2, + "#geometry": "None", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted def test_021_regular_expression_5(): wanted = {} - wanted['uri'] = 'file://testre3.txt?geomType=none&delimiter=\\b&type=regexp' - wanted['fieldTypes'] = ['text', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = "file://testre3.txt?geomType=none&delimiter=\\b&type=regexp" + wanted["fieldTypes"] = ["text", "text", "text"] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': 'gi', - 'description': '..', - 'small': 'gi', - 'field_2': '..', - 'field_3': 'ile', - '#fid': 2, - '#geometry': 'None', + "id": "gi", + "description": "..", + "small": "gi", + "field_2": "..", + "field_3": "ile", + "#fid": 2, + "#geometry": "None", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted def test_022_utf8_encoded_file(): wanted = {} - wanted['uri'] = 'file://testutf8.csv?geomType=none&delimiter=|&type=csv&encoding=utf-8' - wanted['fieldTypes'] = ['integer', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = ( + "file://testutf8.csv?geomType=none&delimiter=|&type=csv&encoding=utf-8" + ) + wanted["fieldTypes"] = ["integer", "text", "text"] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': '2', - 'description': 'Correctly read UTF8 encoding', - 'name': 'Field has \u0101cc\xe8nt\xe9d text', - '#fid': 2, - '#geometry': 'None', + "id": "2", + "description": "Correctly read UTF8 encoding", + "name": "Field has \u0101cc\xe8nt\xe9d text", + "#fid": 2, + "#geometry": "None", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted def test_023_latin1_encoded_file(): wanted = {} - wanted['uri'] = 'file://testlatin1.csv?geomType=none&delimiter=|&type=csv&encoding=latin1' - wanted['fieldTypes'] = ['integer', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = ( + "file://testlatin1.csv?geomType=none&delimiter=|&type=csv&encoding=latin1" + ) + wanted["fieldTypes"] = ["integer", "text", "text"] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': '2', - 'description': 'Correctly read latin1 encoding', - 'name': 'This test is \xa9', - '#fid': 2, - '#geometry': 'None', + "id": "2", + "description": "Correctly read latin1 encoding", + "name": "This test is \xa9", + "#fid": 2, + "#geometry": "None", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted def test_024_filter_rect_xy(): wanted = {} - wanted['uri'] = 'file://testextpt.txt?yField=y&delimiter=|&type=csv&xField=x' - wanted['fieldTypes'] = ['integer', 'text', 'integer', 'integer'] - wanted['geometryType'] = 0 - wanted['data'] = { + wanted["uri"] = "file://testextpt.txt?yField=y&delimiter=|&type=csv&xField=x" + wanted["fieldTypes"] = ["integer", "text", "integer", "integer"] + wanted["geometryType"] = 0 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Inside', - 'x': '15', - 'y': '35', - '#fid': 2, - '#geometry': 'Point (15 35)', + "id": "1", + "description": "Inside", + "x": "15", + "y": "35", + "#fid": 2, + "#geometry": "Point (15 35)", }, 10: { - 'id': '9', - 'description': 'Inside 2', - 'x': '25', - 'y': '45', - '#fid': 10, - '#geometry': 'Point (25 45)', + "id": "9", + "description": "Inside 2", + "x": "25", + "y": "45", + "#fid": 10, + "#geometry": "Point (25 45)", }, 1002: { - 'id': '1', - 'description': 'Inside', - 'x': '15', - 'y': '35', - '#fid': 2, - '#geometry': 'Point (15 35)', + "id": "1", + "description": "Inside", + "x": "15", + "y": "35", + "#fid": 2, + "#geometry": "Point (15 35)", }, 1010: { - 'id': '9', - 'description': 'Inside 2', - 'x': '25', - 'y': '45', - '#fid': 10, - '#geometry': 'Point (25 45)', + "id": "9", + "description": "Inside 2", + "x": "25", + "y": "45", + "#fid": 10, + "#geometry": "Point (25 45)", }, } - wanted['log'] = [ - 'Request 2 did not return any data', + wanted["log"] = [ + "Request 2 did not return any data", ] return wanted def test_025_filter_rect_wkt(): wanted = {} - wanted['uri'] = 'file://testextw.txt?delimiter=|&type=csv&wktField=wkt' - wanted['fieldTypes'] = ['integer', 'text'] - wanted['geometryType'] = 1 - wanted['data'] = { + wanted["uri"] = "file://testextw.txt?delimiter=|&type=csv&wktField=wkt" + wanted["fieldTypes"] = ["integer", "text"] + wanted["geometryType"] = 1 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Inside', - '#fid': 2, - '#geometry': 'LineString (12 32, 28 48)', + "id": "1", + "description": "Inside", + "#fid": 2, + "#geometry": "LineString (12 32, 28 48)", }, 4: { - 'id': '3', - 'description': 'Crossing', - '#fid': 4, - '#geometry': 'LineString (5 30, 30 55)', + "id": "3", + "description": "Crossing", + "#fid": 4, + "#geometry": "LineString (5 30, 30 55)", }, 5: { - 'id': '4', - 'description': 'Bounding box overlap', - '#fid': 5, - '#geometry': 'LineString (5 30, 5 55, 30 55)', + "id": "4", + "description": "Bounding box overlap", + "#fid": 5, + "#geometry": "LineString (5 30, 5 55, 30 55)", }, 6: { - 'id': '5', - 'description': 'Crossing 2', - '#fid': 6, - '#geometry': 'LineString (25 35, 35 35)', + "id": "5", + "description": "Crossing 2", + "#fid": 6, + "#geometry": "LineString (25 35, 35 35)", }, 7: { - 'id': '6', - 'description': 'Bounding box overlap 2', - '#fid': 7, - '#geometry': 'LineString (28 29, 31 29, 31 33)', + "id": "6", + "description": "Bounding box overlap 2", + "#fid": 7, + "#geometry": "LineString (28 29, 31 29, 31 33)", }, 1002: { - 'id': '1', - 'description': 'Inside', - '#fid': 2, - '#geometry': 'LineString (12 32, 28 48)', + "id": "1", + "description": "Inside", + "#fid": 2, + "#geometry": "LineString (12 32, 28 48)", }, 1004: { - 'id': '3', - 'description': 'Crossing', - '#fid': 4, - '#geometry': 'LineString (5 30, 30 55)', + "id": "3", + "description": "Crossing", + "#fid": 4, + "#geometry": "LineString (5 30, 30 55)", }, 1006: { - 'id': '5', - 'description': 'Crossing 2', - '#fid': 6, - '#geometry': 'LineString (25 35, 35 35)', + "id": "5", + "description": "Crossing 2", + "#fid": 6, + "#geometry": "LineString (25 35, 35 35)", }, } - wanted['log'] = [ - 'Request 2 did not return any data', + wanted["log"] = [ + "Request 2 did not return any data", ] return wanted def test_026_filter_fid(): wanted = {} - wanted['uri'] = 'file://test.csv?geomType=none&type=csv' - wanted['fieldTypes'] = ['integer', 'text', 'text', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = "file://test.csv?geomType=none&type=csv" + wanted["fieldTypes"] = ["integer", "text", "text", "text", "text"] + wanted["geometryType"] = 4 + wanted["data"] = { 3: { - 'id': '2', - 'description': 'Quoted field', - 'data': 'Quoted data', - 'info': 'Unquoted', - 'field_5': 'NULL', - '#fid': 3, - '#geometry': 'None', + "id": "2", + "description": "Quoted field", + "data": "Quoted data", + "info": "Unquoted", + "field_5": "NULL", + "#fid": 3, + "#geometry": "None", }, 1009: { - 'id': '5', - 'description': 'Extra fields', - 'data': 'data', - 'info': 'info', - 'field_5': 'message', - '#fid': 9, - '#geometry': 'None', + "id": "5", + "description": "Extra fields", + "data": "data", + "info": "info", + "field_5": "message", + "#fid": 9, + "#geometry": "None", }, 3003: { - 'id': '2', - 'description': 'Quoted field', - 'data': 'Quoted data', - 'info': 'Unquoted', - 'field_5': 'NULL', - '#fid': 3, - '#geometry': 'None', + "id": "2", + "description": "Quoted field", + "data": "Quoted data", + "info": "Unquoted", + "field_5": "NULL", + "#fid": 3, + "#geometry": "None", }, } - wanted['log'] = [ - 'Request 2 did not return any data', + wanted["log"] = [ + "Request 2 did not return any data", ] return wanted def test_027_filter_attributes(): wanted = {} - wanted['uri'] = 'file://test.csv?geomType=none&type=csv' - wanted['fieldTypes'] = ['integer', 'text', 'text', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = "file://test.csv?geomType=none&type=csv" + wanted["fieldTypes"] = ["integer", "text", "text", "text", "text"] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': 'None', - 'description': 'Basic unquoted record', - 'data': 'None', - 'info': 'Some info', - 'field_5': 'None', - '#fid': 2, - '#geometry': 'None', + "id": "None", + "description": "Basic unquoted record", + "data": "None", + "info": "Some info", + "field_5": "None", + "#fid": 2, + "#geometry": "None", }, 3: { - 'id': 'None', - 'description': 'Quoted field', - 'data': 'None', - 'info': 'Unquoted', - 'field_5': 'None', - '#fid': 3, - '#geometry': 'None', + "id": "None", + "description": "Quoted field", + "data": "None", + "info": "Unquoted", + "field_5": "None", + "#fid": 3, + "#geometry": "None", }, 4: { - 'id': 'None', - 'description': 'Escaped quotes', - 'data': 'None', - 'info': 'Unquoted', - 'field_5': 'None', - '#fid': 4, - '#geometry': 'None', + "id": "None", + "description": "Escaped quotes", + "data": "None", + "info": "Unquoted", + "field_5": "None", + "#fid": 4, + "#geometry": "None", }, 5: { - 'id': 'None', - 'description': 'Quoted newlines', - 'data': 'None', - 'info': 'No data', - 'field_5': 'None', - '#fid': 5, - '#geometry': 'None', + "id": "None", + "description": "Quoted newlines", + "data": "None", + "info": "No data", + "field_5": "None", + "#fid": 5, + "#geometry": "None", }, 9: { - 'id': 'None', - 'description': 'Extra fields', - 'data': 'None', - 'info': 'info', - 'field_5': 'None', - '#fid': 9, - '#geometry': 'None', + "id": "None", + "description": "Extra fields", + "data": "None", + "info": "info", + "field_5": "None", + "#fid": 9, + "#geometry": "None", }, 10: { - 'id': 'None', - 'description': 'Missing fields', - 'data': 'None', - 'info': 'NULL', - 'field_5': 'None', - '#fid': 10, - '#geometry': 'None', + "id": "None", + "description": "Missing fields", + "data": "None", + "info": "NULL", + "field_5": "None", + "#fid": 10, + "#geometry": "None", }, 1009: { - 'id': '5', - 'description': 'Extra fields', - 'data': 'data', - 'info': 'info', - 'field_5': 'message', - '#fid': 9, - '#geometry': 'None', + "id": "5", + "description": "Extra fields", + "data": "data", + "info": "info", + "field_5": "message", + "#fid": 9, + "#geometry": "None", }, 2009: { - 'id': 'None', - 'description': 'Extra fields', - 'data': 'None', - 'info': 'info', - 'field_5': 'None', - '#fid': 9, - '#geometry': 'None', + "id": "None", + "description": "Extra fields", + "data": "None", + "info": "info", + "field_5": "None", + "#fid": 9, + "#geometry": "None", }, 3009: { - 'id': 'None', - 'description': 'Extra fields', - 'data': 'None', - 'info': 'info', - 'field_5': 'None', - '#fid': 9, - '#geometry': 'None', + "id": "None", + "description": "Extra fields", + "data": "None", + "info": "info", + "field_5": "None", + "#fid": 9, + "#geometry": "None", }, 4009: { - 'id': 'None', - 'description': 'Extra fields', - 'data': 'None', - 'info': 'info', - 'field_5': 'None', - '#fid': 9, - '#geometry': 'None', + "id": "None", + "description": "Extra fields", + "data": "None", + "info": "info", + "field_5": "None", + "#fid": 9, + "#geometry": "None", }, 5009: { - 'id': 'None', - 'description': 'None', - 'data': 'None', - 'info': 'None', - 'field_5': 'None', - '#fid': 9, - '#geometry': 'None', + "id": "None", + "description": "None", + "data": "None", + "info": "None", + "field_5": "None", + "#fid": 9, + "#geometry": "None", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted def test_028_substring_test(): wanted = {} - wanted['uri'] = 'file://test.csv?geomType=none&type=csv&subset=id%20%25%202%20%3D%201' - wanted['fieldTypes'] = ['integer', 'text', 'text', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = ( + "file://test.csv?geomType=none&type=csv&subset=id%20%25%202%20%3D%201" + ) + wanted["fieldTypes"] = ["integer", "text", "text", "text", "text"] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Basic unquoted record', - 'data': 'Some data', - 'info': 'Some info', - 'field_5': 'NULL', - '#fid': 2, - '#geometry': 'None', + "id": "1", + "description": "Basic unquoted record", + "data": "Some data", + "info": "Some info", + "field_5": "NULL", + "#fid": 2, + "#geometry": "None", }, 4: { - 'id': '3', - 'description': 'Escaped quotes', - 'data': 'Quoted "citation" data', - 'info': 'Unquoted', - 'field_5': 'NULL', - '#fid': 4, - '#geometry': 'None', + "id": "3", + "description": "Escaped quotes", + "data": 'Quoted "citation" data', + "info": "Unquoted", + "field_5": "NULL", + "#fid": 4, + "#geometry": "None", }, 9: { - 'id': '5', - 'description': 'Extra fields', - 'data': 'data', - 'info': 'info', - 'field_5': 'message', - '#fid': 9, - '#geometry': 'None', + "id": "5", + "description": "Extra fields", + "data": "data", + "info": "info", + "field_5": "message", + "#fid": 9, + "#geometry": "None", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted def test_029_file_watcher(): wanted = {} - wanted['uri'] = 'file://file?geomType=none&type=csv&watchFile=yes' - wanted['fieldTypes'] = ['integer', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = "file://file?geomType=none&type=csv&watchFile=yes" + wanted["fieldTypes"] = ["integer", "text"] + wanted["geometryType"] = 4 + wanted["data"] = { 3: { - 'id': '2', - 'description': 'pooh', - 'name': 'pooh', - '#fid': 3, - '#geometry': 'None', + "id": "2", + "description": "pooh", + "name": "pooh", + "#fid": 3, + "#geometry": "None", }, 1002: { - 'id': '1', - 'description': 'rabbit', - 'name': 'rabbit', - '#fid': 2, - '#geometry': 'None', + "id": "1", + "description": "rabbit", + "name": "rabbit", + "#fid": 2, + "#geometry": "None", }, 1003: { - 'id': '2', - 'description': 'pooh', - 'name': 'pooh', - '#fid': 3, - '#geometry': 'None', + "id": "2", + "description": "pooh", + "name": "pooh", + "#fid": 3, + "#geometry": "None", }, 4003: { - 'id': '2', - 'description': 'pooh', - 'name': 'pooh', - '#fid': 3, - '#geometry': 'None', + "id": "2", + "description": "pooh", + "name": "pooh", + "#fid": 3, + "#geometry": "None", }, 5004: { - 'id': '3', - 'description': 'tiger', - 'name': 'tiger', - '#fid': 4, - '#geometry': 'None', + "id": "3", + "description": "tiger", + "name": "tiger", + "#fid": 4, + "#geometry": "None", }, 6002: { - 'id': '1', - 'description': 'rabbit', - 'name': 'rabbit', - '#fid': 2, - '#geometry': 'None', + "id": "1", + "description": "rabbit", + "name": "rabbit", + "#fid": 2, + "#geometry": "None", }, 6003: { - 'id': '2', - 'description': 'pooh', - 'name': 'pooh', - '#fid': 3, - '#geometry': 'None', + "id": "2", + "description": "pooh", + "name": "pooh", + "#fid": 3, + "#geometry": "None", }, 6004: { - 'id': '3', - 'description': 'tiger', - 'name': 'tiger', - '#fid': 4, - '#geometry': 'None', + "id": "3", + "description": "tiger", + "name": "tiger", + "#fid": 4, + "#geometry": "None", }, 9002: { - 'id': '5', - 'description': 'toad', - 'name': 'toad', - '#fid': 2, - '#geometry': 'None', + "id": "5", + "description": "toad", + "name": "toad", + "#fid": 2, + "#geometry": "None", }, 10002: { - 'id': '5', - 'description': 'toad', - 'name': 'toad', - '#fid': 2, - '#geometry': 'None', + "id": "5", + "description": "toad", + "name": "toad", + "#fid": 2, + "#geometry": "None", }, 10003: { - 'id': '6', - 'description': 'mole', - 'name': 'mole', - '#fid': 3, - '#geometry': 'None', + "id": "6", + "description": "mole", + "name": "mole", + "#fid": 3, + "#geometry": "None", }, 10004: { - 'id': '7', - 'description': 'badger', - 'name': 'badger', - '#fid': 4, - '#geometry': 'None', + "id": "7", + "description": "badger", + "name": "badger", + "#fid": 4, + "#geometry": "None", }, 16002: { - 'id': '5', - 'description': 'toad', - 'name': 'toad', - '#fid': 2, - '#geometry': 'None', + "id": "5", + "description": "toad", + "name": "toad", + "#fid": 2, + "#geometry": "None", }, } - wanted['log'] = [ - 'Request 2 did not return any data', - 'Request 7 did not return any data', - 'Request 11 did not return any data', - 'Request 13 did not return any data', - 'Request 14 did not return any data', - 'Errors in file temp_file', - 'The file has been updated by another application - reloading', - 'Errors in file temp_file', - 'The file has been updated by another application - reloading', - 'Errors in file temp_file', - 'The file has been updated by another application - reloading', + wanted["log"] = [ + "Request 2 did not return any data", + "Request 7 did not return any data", + "Request 11 did not return any data", + "Request 13 did not return any data", + "Request 14 did not return any data", + "Errors in file temp_file", + "The file has been updated by another application - reloading", + "Errors in file temp_file", + "The file has been updated by another application - reloading", + "Errors in file temp_file", + "The file has been updated by another application - reloading", ] return wanted def test_030_filter_rect_xy_spatial_index(): wanted = {} - wanted['uri'] = 'file://testextpt.txt?spatialIndex=Y&yField=y&delimiter=|&type=csv&xField=x' - wanted['fieldTypes'] = ['integer', 'text', 'integer', 'integer'] - wanted['geometryType'] = 0 - wanted['data'] = { + wanted["uri"] = ( + "file://testextpt.txt?spatialIndex=Y&yField=y&delimiter=|&type=csv&xField=x" + ) + wanted["fieldTypes"] = ["integer", "text", "integer", "integer"] + wanted["geometryType"] = 0 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Inside', - 'x': '15', - 'y': '35', - '#fid': 2, - '#geometry': 'Point (15 35)', + "id": "1", + "description": "Inside", + "x": "15", + "y": "35", + "#fid": 2, + "#geometry": "Point (15 35)", }, 10: { - 'id': '9', - 'description': 'Inside 2', - 'x': '25', - 'y': '45', - '#fid': 10, - '#geometry': 'Point (25 45)', + "id": "9", + "description": "Inside 2", + "x": "25", + "y": "45", + "#fid": 10, + "#geometry": "Point (25 45)", }, 1002: { - 'id': '1', - 'description': 'Inside', - 'x': '15', - 'y': '35', - '#fid': 2, - '#geometry': 'Point (15 35)', + "id": "1", + "description": "Inside", + "x": "15", + "y": "35", + "#fid": 2, + "#geometry": "Point (15 35)", }, 1010: { - 'id': '9', - 'description': 'Inside 2', - 'x': '25', - 'y': '45', - '#fid': 10, - '#geometry': 'Point (25 45)', + "id": "9", + "description": "Inside 2", + "x": "25", + "y": "45", + "#fid": 10, + "#geometry": "Point (25 45)", }, 3002: { - 'id': '1', - 'description': 'Inside', - 'x': '15', - 'y': '35', - '#fid': 2, - '#geometry': 'Point (15 35)', + "id": "1", + "description": "Inside", + "x": "15", + "y": "35", + "#fid": 2, + "#geometry": "Point (15 35)", }, 3003: { - 'id': '2', - 'description': 'Outside 1', - 'x': '5', - 'y': '35', - '#fid': 3, - '#geometry': 'Point (5 35)', + "id": "2", + "description": "Outside 1", + "x": "5", + "y": "35", + "#fid": 3, + "#geometry": "Point (5 35)", }, 3004: { - 'id': '3', - 'description': 'Outside 2', - 'x': '5', - 'y': '55', - '#fid': 4, - '#geometry': 'Point (5 55)', + "id": "3", + "description": "Outside 2", + "x": "5", + "y": "55", + "#fid": 4, + "#geometry": "Point (5 55)", }, 3005: { - 'id': '4', - 'description': 'Outside 3', - 'x': '15', - 'y': '55', - '#fid': 5, - '#geometry': 'Point (15 55)', + "id": "4", + "description": "Outside 3", + "x": "15", + "y": "55", + "#fid": 5, + "#geometry": "Point (15 55)", }, 3006: { - 'id': '5', - 'description': 'Outside 4', - 'x': '35', - 'y': '55', - '#fid': 6, - '#geometry': 'Point (35 55)', + "id": "5", + "description": "Outside 4", + "x": "35", + "y": "55", + "#fid": 6, + "#geometry": "Point (35 55)", }, 3007: { - 'id': '6', - 'description': 'Outside 5', - 'x': '35', - 'y': '45', - '#fid': 7, - '#geometry': 'Point (35 45)', + "id": "6", + "description": "Outside 5", + "x": "35", + "y": "45", + "#fid": 7, + "#geometry": "Point (35 45)", }, 3008: { - 'id': '7', - 'description': 'Outside 7', - 'x': '35', - 'y': '25', - '#fid': 8, - '#geometry': 'Point (35 25)', + "id": "7", + "description": "Outside 7", + "x": "35", + "y": "25", + "#fid": 8, + "#geometry": "Point (35 25)", }, 3009: { - 'id': '8', - 'description': 'Outside 8', - 'x': '15', - 'y': '25', - '#fid': 9, - '#geometry': 'Point (15 25)', + "id": "8", + "description": "Outside 8", + "x": "15", + "y": "25", + "#fid": 9, + "#geometry": "Point (15 25)", }, 3010: { - 'id': '9', - 'description': 'Inside 2', - 'x': '25', - 'y': '45', - '#fid': 10, - '#geometry': 'Point (25 45)', + "id": "9", + "description": "Inside 2", + "x": "25", + "y": "45", + "#fid": 10, + "#geometry": "Point (25 45)", }, 4002: { - 'id': '1', - 'description': 'Inside', - 'x': '15', - 'y': '35', - '#fid': 2, - '#geometry': 'Point (15 35)', + "id": "1", + "description": "Inside", + "x": "15", + "y": "35", + "#fid": 2, + "#geometry": "Point (15 35)", }, 4003: { - 'id': '2', - 'description': 'Outside 1', - 'x': '5', - 'y': '35', - '#fid': 3, - '#geometry': 'Point (5 35)', + "id": "2", + "description": "Outside 1", + "x": "5", + "y": "35", + "#fid": 3, + "#geometry": "Point (5 35)", }, 4004: { - 'id': '3', - 'description': 'Outside 2', - 'x': '5', - 'y': '55', - '#fid': 4, - '#geometry': 'Point (5 55)', + "id": "3", + "description": "Outside 2", + "x": "5", + "y": "55", + "#fid": 4, + "#geometry": "Point (5 55)", }, 4005: { - 'id': '4', - 'description': 'Outside 3', - 'x': '15', - 'y': '55', - '#fid': 5, - '#geometry': 'Point (15 55)', + "id": "4", + "description": "Outside 3", + "x": "15", + "y": "55", + "#fid": 5, + "#geometry": "Point (15 55)", }, 4006: { - 'id': '5', - 'description': 'Outside 4', - 'x': '35', - 'y': '55', - '#fid': 6, - '#geometry': 'Point (35 55)', + "id": "5", + "description": "Outside 4", + "x": "35", + "y": "55", + "#fid": 6, + "#geometry": "Point (35 55)", }, 4007: { - 'id': '6', - 'description': 'Outside 5', - 'x': '35', - 'y': '45', - '#fid': 7, - '#geometry': 'Point (35 45)', + "id": "6", + "description": "Outside 5", + "x": "35", + "y": "45", + "#fid": 7, + "#geometry": "Point (35 45)", }, 4008: { - 'id': '7', - 'description': 'Outside 7', - 'x': '35', - 'y': '25', - '#fid': 8, - '#geometry': 'Point (35 25)', + "id": "7", + "description": "Outside 7", + "x": "35", + "y": "25", + "#fid": 8, + "#geometry": "Point (35 25)", }, 4009: { - 'id': '8', - 'description': 'Outside 8', - 'x': '15', - 'y': '25', - '#fid': 9, - '#geometry': 'Point (15 25)', + "id": "8", + "description": "Outside 8", + "x": "15", + "y": "25", + "#fid": 9, + "#geometry": "Point (15 25)", }, 4010: { - 'id': '9', - 'description': 'Inside 2', - 'x': '25', - 'y': '45', - '#fid': 10, - '#geometry': 'Point (25 45)', + "id": "9", + "description": "Inside 2", + "x": "25", + "y": "45", + "#fid": 10, + "#geometry": "Point (25 45)", }, } - wanted['log'] = [ - 'Request 2 did not return any data', + wanted["log"] = [ + "Request 2 did not return any data", ] return wanted def test_031_filter_rect_wkt_spatial_index(): wanted = {} - wanted['uri'] = 'file://testextw.txt?spatialIndex=Y&delimiter=|&type=csv&wktField=wkt' - wanted['fieldTypes'] = ['integer', 'text'] - wanted['geometryType'] = 1 - wanted['data'] = { + wanted["uri"] = ( + "file://testextw.txt?spatialIndex=Y&delimiter=|&type=csv&wktField=wkt" + ) + wanted["fieldTypes"] = ["integer", "text"] + wanted["geometryType"] = 1 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Inside', - '#fid': 2, - '#geometry': 'LineString (12 32, 28 48)', + "id": "1", + "description": "Inside", + "#fid": 2, + "#geometry": "LineString (12 32, 28 48)", }, 4: { - 'id': '3', - 'description': 'Crossing', - '#fid': 4, - '#geometry': 'LineString (5 30, 30 55)', + "id": "3", + "description": "Crossing", + "#fid": 4, + "#geometry": "LineString (5 30, 30 55)", }, 5: { - 'id': '4', - 'description': 'Bounding box overlap', - '#fid': 5, - '#geometry': 'LineString (5 30, 5 55, 30 55)', + "id": "4", + "description": "Bounding box overlap", + "#fid": 5, + "#geometry": "LineString (5 30, 5 55, 30 55)", }, 6: { - 'id': '5', - 'description': 'Crossing 2', - '#fid': 6, - '#geometry': 'LineString (25 35, 35 35)', + "id": "5", + "description": "Crossing 2", + "#fid": 6, + "#geometry": "LineString (25 35, 35 35)", }, 7: { - 'id': '6', - 'description': 'Bounding box overlap 2', - '#fid': 7, - '#geometry': 'LineString (28 29, 31 29, 31 33)', + "id": "6", + "description": "Bounding box overlap 2", + "#fid": 7, + "#geometry": "LineString (28 29, 31 29, 31 33)", }, 1002: { - 'id': '1', - 'description': 'Inside', - '#fid': 2, - '#geometry': 'LineString (12 32, 28 48)', + "id": "1", + "description": "Inside", + "#fid": 2, + "#geometry": "LineString (12 32, 28 48)", }, 1004: { - 'id': '3', - 'description': 'Crossing', - '#fid': 4, - '#geometry': 'LineString (5 30, 30 55)', + "id": "3", + "description": "Crossing", + "#fid": 4, + "#geometry": "LineString (5 30, 30 55)", }, 1006: { - 'id': '5', - 'description': 'Crossing 2', - '#fid': 6, - '#geometry': 'LineString (25 35, 35 35)', + "id": "5", + "description": "Crossing 2", + "#fid": 6, + "#geometry": "LineString (25 35, 35 35)", }, 3002: { - 'id': '1', - 'description': 'Inside', - '#fid': 2, - '#geometry': 'LineString (12 32, 28 48)', + "id": "1", + "description": "Inside", + "#fid": 2, + "#geometry": "LineString (12 32, 28 48)", }, 3003: { - 'id': '2', - 'description': 'Outside', - '#fid': 3, - '#geometry': 'LineString (0 0, 0 10)', + "id": "2", + "description": "Outside", + "#fid": 3, + "#geometry": "LineString (0 0, 0 10)", }, 3004: { - 'id': '3', - 'description': 'Crossing', - '#fid': 4, - '#geometry': 'LineString (5 30, 30 55)', + "id": "3", + "description": "Crossing", + "#fid": 4, + "#geometry": "LineString (5 30, 30 55)", }, 3005: { - 'id': '4', - 'description': 'Bounding box overlap', - '#fid': 5, - '#geometry': 'LineString (5 30, 5 55, 30 55)', + "id": "4", + "description": "Bounding box overlap", + "#fid": 5, + "#geometry": "LineString (5 30, 5 55, 30 55)", }, 3006: { - 'id': '5', - 'description': 'Crossing 2', - '#fid': 6, - '#geometry': 'LineString (25 35, 35 35)', + "id": "5", + "description": "Crossing 2", + "#fid": 6, + "#geometry": "LineString (25 35, 35 35)", }, 3007: { - 'id': '6', - 'description': 'Bounding box overlap 2', - '#fid': 7, - '#geometry': 'LineString (28 29, 31 29, 31 33)', + "id": "6", + "description": "Bounding box overlap 2", + "#fid": 7, + "#geometry": "LineString (28 29, 31 29, 31 33)", }, 4002: { - 'id': '1', - 'description': 'Inside', - '#fid': 2, - '#geometry': 'LineString (12 32, 28 48)', + "id": "1", + "description": "Inside", + "#fid": 2, + "#geometry": "LineString (12 32, 28 48)", }, 4003: { - 'id': '2', - 'description': 'Outside', - '#fid': 3, - '#geometry': 'LineString (0 0, 0 10)', + "id": "2", + "description": "Outside", + "#fid": 3, + "#geometry": "LineString (0 0, 0 10)", }, 4004: { - 'id': '3', - 'description': 'Crossing', - '#fid': 4, - '#geometry': 'LineString (5 30, 30 55)', + "id": "3", + "description": "Crossing", + "#fid": 4, + "#geometry": "LineString (5 30, 30 55)", }, 4005: { - 'id': '4', - 'description': 'Bounding box overlap', - '#fid': 5, - '#geometry': 'LineString (5 30, 5 55, 30 55)', + "id": "4", + "description": "Bounding box overlap", + "#fid": 5, + "#geometry": "LineString (5 30, 5 55, 30 55)", }, 4006: { - 'id': '5', - 'description': 'Crossing 2', - '#fid': 6, - '#geometry': 'LineString (25 35, 35 35)', + "id": "5", + "description": "Crossing 2", + "#fid": 6, + "#geometry": "LineString (25 35, 35 35)", }, 4007: { - 'id': '6', - 'description': 'Bounding box overlap 2', - '#fid': 7, - '#geometry': 'LineString (28 29, 31 29, 31 33)', + "id": "6", + "description": "Bounding box overlap 2", + "#fid": 7, + "#geometry": "LineString (28 29, 31 29, 31 33)", }, } - wanted['log'] = [ - 'Request 2 did not return any data', + wanted["log"] = [ + "Request 2 did not return any data", ] return wanted def test_032_filter_rect_wkt_create_spatial_index(): wanted = {} - wanted['uri'] = 'file://testextw.txt?delimiter=|&type=csv&wktField=wkt' - wanted['fieldTypes'] = ['integer', 'text'] - wanted['geometryType'] = 1 - wanted['data'] = { + wanted["uri"] = "file://testextw.txt?delimiter=|&type=csv&wktField=wkt" + wanted["fieldTypes"] = ["integer", "text"] + wanted["geometryType"] = 1 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Inside', - '#fid': 2, - '#geometry': 'LineString (12 32, 28 48)', + "id": "1", + "description": "Inside", + "#fid": 2, + "#geometry": "LineString (12 32, 28 48)", }, 4: { - 'id': '3', - 'description': 'Crossing', - '#fid': 4, - '#geometry': 'LineString (5 30, 30 55)', + "id": "3", + "description": "Crossing", + "#fid": 4, + "#geometry": "LineString (5 30, 30 55)", }, 5: { - 'id': '4', - 'description': 'Bounding box overlap', - '#fid': 5, - '#geometry': 'LineString (5 30, 5 55, 30 55)', + "id": "4", + "description": "Bounding box overlap", + "#fid": 5, + "#geometry": "LineString (5 30, 5 55, 30 55)", }, 6: { - 'id': '5', - 'description': 'Crossing 2', - '#fid': 6, - '#geometry': 'LineString (25 35, 35 35)', + "id": "5", + "description": "Crossing 2", + "#fid": 6, + "#geometry": "LineString (25 35, 35 35)", }, 7: { - 'id': '6', - 'description': 'Bounding box overlap 2', - '#fid': 7, - '#geometry': 'LineString (28 29, 31 29, 31 33)', + "id": "6", + "description": "Bounding box overlap 2", + "#fid": 7, + "#geometry": "LineString (28 29, 31 29, 31 33)", }, 1002: { - 'id': '1', - 'description': 'Inside', - '#fid': 2, - '#geometry': 'LineString (12 32, 28 48)', + "id": "1", + "description": "Inside", + "#fid": 2, + "#geometry": "LineString (12 32, 28 48)", }, 1003: { - 'id': '2', - 'description': 'Outside', - '#fid': 3, - '#geometry': 'LineString (0 0, 0 10)', + "id": "2", + "description": "Outside", + "#fid": 3, + "#geometry": "LineString (0 0, 0 10)", }, 1004: { - 'id': '3', - 'description': 'Crossing', - '#fid': 4, - '#geometry': 'LineString (5 30, 30 55)', + "id": "3", + "description": "Crossing", + "#fid": 4, + "#geometry": "LineString (5 30, 30 55)", }, 1005: { - 'id': '4', - 'description': 'Bounding box overlap', - '#fid': 5, - '#geometry': 'LineString (5 30, 5 55, 30 55)', + "id": "4", + "description": "Bounding box overlap", + "#fid": 5, + "#geometry": "LineString (5 30, 5 55, 30 55)", }, 1006: { - 'id': '5', - 'description': 'Crossing 2', - '#fid': 6, - '#geometry': 'LineString (25 35, 35 35)', + "id": "5", + "description": "Crossing 2", + "#fid": 6, + "#geometry": "LineString (25 35, 35 35)", }, 1007: { - 'id': '6', - 'description': 'Bounding box overlap 2', - '#fid': 7, - '#geometry': 'LineString (28 29, 31 29, 31 33)', + "id": "6", + "description": "Bounding box overlap 2", + "#fid": 7, + "#geometry": "LineString (28 29, 31 29, 31 33)", }, 3002: { - 'id': '1', - 'description': 'Inside', - '#fid': 2, - '#geometry': 'LineString (12 32, 28 48)', + "id": "1", + "description": "Inside", + "#fid": 2, + "#geometry": "LineString (12 32, 28 48)", }, 3004: { - 'id': '3', - 'description': 'Crossing', - '#fid': 4, - '#geometry': 'LineString (5 30, 30 55)', + "id": "3", + "description": "Crossing", + "#fid": 4, + "#geometry": "LineString (5 30, 30 55)", }, 3005: { - 'id': '4', - 'description': 'Bounding box overlap', - '#fid': 5, - '#geometry': 'LineString (5 30, 5 55, 30 55)', + "id": "4", + "description": "Bounding box overlap", + "#fid": 5, + "#geometry": "LineString (5 30, 5 55, 30 55)", }, 3006: { - 'id': '5', - 'description': 'Crossing 2', - '#fid': 6, - '#geometry': 'LineString (25 35, 35 35)', + "id": "5", + "description": "Crossing 2", + "#fid": 6, + "#geometry": "LineString (25 35, 35 35)", }, 3007: { - 'id': '6', - 'description': 'Bounding box overlap 2', - '#fid': 7, - '#geometry': 'LineString (28 29, 31 29, 31 33)', + "id": "6", + "description": "Bounding box overlap 2", + "#fid": 7, + "#geometry": "LineString (28 29, 31 29, 31 33)", }, 4002: { - 'id': '1', - 'description': 'Inside', - '#fid': 2, - '#geometry': 'LineString (12 32, 28 48)', + "id": "1", + "description": "Inside", + "#fid": 2, + "#geometry": "LineString (12 32, 28 48)", }, 4004: { - 'id': '3', - 'description': 'Crossing', - '#fid': 4, - '#geometry': 'LineString (5 30, 30 55)', + "id": "3", + "description": "Crossing", + "#fid": 4, + "#geometry": "LineString (5 30, 30 55)", }, 4006: { - 'id': '5', - 'description': 'Crossing 2', - '#fid': 6, - '#geometry': 'LineString (25 35, 35 35)', + "id": "5", + "description": "Crossing 2", + "#fid": 6, + "#geometry": "LineString (25 35, 35 35)", }, 6002: { - 'id': '1', - 'description': 'Inside', - '#fid': 2, - '#geometry': 'LineString (12 32, 28 48)', + "id": "1", + "description": "Inside", + "#fid": 2, + "#geometry": "LineString (12 32, 28 48)", }, 6003: { - 'id': '2', - 'description': 'Outside', - '#fid': 3, - '#geometry': 'LineString (0 0, 0 10)', + "id": "2", + "description": "Outside", + "#fid": 3, + "#geometry": "LineString (0 0, 0 10)", }, 6004: { - 'id': '3', - 'description': 'Crossing', - '#fid': 4, - '#geometry': 'LineString (5 30, 30 55)', + "id": "3", + "description": "Crossing", + "#fid": 4, + "#geometry": "LineString (5 30, 30 55)", }, 6005: { - 'id': '4', - 'description': 'Bounding box overlap', - '#fid': 5, - '#geometry': 'LineString (5 30, 5 55, 30 55)', + "id": "4", + "description": "Bounding box overlap", + "#fid": 5, + "#geometry": "LineString (5 30, 5 55, 30 55)", }, 6006: { - 'id': '5', - 'description': 'Crossing 2', - '#fid': 6, - '#geometry': 'LineString (25 35, 35 35)', + "id": "5", + "description": "Crossing 2", + "#fid": 6, + "#geometry": "LineString (25 35, 35 35)", }, 6007: { - 'id': '6', - 'description': 'Bounding box overlap 2', - '#fid': 7, - '#geometry': 'LineString (28 29, 31 29, 31 33)', + "id": "6", + "description": "Bounding box overlap 2", + "#fid": 7, + "#geometry": "LineString (28 29, 31 29, 31 33)", }, 7002: { - 'id': '1', - 'description': 'Inside', - '#fid': 2, - '#geometry': 'LineString (12 32, 28 48)', + "id": "1", + "description": "Inside", + "#fid": 2, + "#geometry": "LineString (12 32, 28 48)", }, 7003: { - 'id': '2', - 'description': 'Outside', - '#fid': 3, - '#geometry': 'LineString (0 0, 0 10)', + "id": "2", + "description": "Outside", + "#fid": 3, + "#geometry": "LineString (0 0, 0 10)", }, 7004: { - 'id': '3', - 'description': 'Crossing', - '#fid': 4, - '#geometry': 'LineString (5 30, 30 55)', + "id": "3", + "description": "Crossing", + "#fid": 4, + "#geometry": "LineString (5 30, 30 55)", }, 7005: { - 'id': '4', - 'description': 'Bounding box overlap', - '#fid': 5, - '#geometry': 'LineString (5 30, 5 55, 30 55)', + "id": "4", + "description": "Bounding box overlap", + "#fid": 5, + "#geometry": "LineString (5 30, 5 55, 30 55)", }, 7006: { - 'id': '5', - 'description': 'Crossing 2', - '#fid': 6, - '#geometry': 'LineString (25 35, 35 35)', + "id": "5", + "description": "Crossing 2", + "#fid": 6, + "#geometry": "LineString (25 35, 35 35)", }, 7007: { - 'id': '6', - 'description': 'Bounding box overlap 2', - '#fid': 7, - '#geometry': 'LineString (28 29, 31 29, 31 33)', + "id": "6", + "description": "Bounding box overlap 2", + "#fid": 7, + "#geometry": "LineString (28 29, 31 29, 31 33)", }, } - wanted['log'] = [ - 'Request 5 did not return any data', + wanted["log"] = [ + "Request 5 did not return any data", ] return wanted def test_033_reset_subset_string(): wanted = {} - wanted['uri'] = 'file://test.csv?geomType=none&type=csv' - wanted['fieldTypes'] = ['integer', 'text', 'text', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = "file://test.csv?geomType=none&type=csv" + wanted["fieldTypes"] = ["integer", "text", "text", "text", "text"] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Basic unquoted record', - 'data': 'Some data', - 'info': 'Some info', - 'field_5': 'NULL', - '#fid': 2, - '#geometry': 'None', + "id": "1", + "description": "Basic unquoted record", + "data": "Some data", + "info": "Some info", + "field_5": "NULL", + "#fid": 2, + "#geometry": "None", }, 3: { - 'id': '2', - 'description': 'Quoted field', - 'data': 'Quoted data', - 'info': 'Unquoted', - 'field_5': 'NULL', - '#fid': 3, - '#geometry': 'None', + "id": "2", + "description": "Quoted field", + "data": "Quoted data", + "info": "Unquoted", + "field_5": "NULL", + "#fid": 3, + "#geometry": "None", }, 4: { - 'id': '3', - 'description': 'Escaped quotes', - 'data': 'Quoted "citation" data', - 'info': 'Unquoted', - 'field_5': 'NULL', - '#fid': 4, - '#geometry': 'None', + "id": "3", + "description": "Escaped quotes", + "data": 'Quoted "citation" data', + "info": "Unquoted", + "field_5": "NULL", + "#fid": 4, + "#geometry": "None", }, 5: { - 'id': '4', - 'description': 'Quoted newlines', - 'data': 'Line 1\nLine 2\n\nLine 4', - 'info': 'No data', - 'field_5': 'NULL', - '#fid': 5, - '#geometry': 'None', + "id": "4", + "description": "Quoted newlines", + "data": "Line 1\nLine 2\n\nLine 4", + "info": "No data", + "field_5": "NULL", + "#fid": 5, + "#geometry": "None", }, 9: { - 'id': '5', - 'description': 'Extra fields', - 'data': 'data', - 'info': 'info', - 'field_5': 'message', - '#fid': 9, - '#geometry': 'None', + "id": "5", + "description": "Extra fields", + "data": "data", + "info": "info", + "field_5": "message", + "#fid": 9, + "#geometry": "None", }, 10: { - 'id': '6', - 'description': 'Missing fields', - 'data': 'NULL', - 'info': 'NULL', - 'field_5': 'NULL', - '#fid': 10, - '#geometry': 'None', + "id": "6", + "description": "Missing fields", + "data": "NULL", + "info": "NULL", + "field_5": "NULL", + "#fid": 10, + "#geometry": "None", }, 2002: { - 'id': '1', - 'description': 'Basic unquoted record', - 'data': 'Some data', - 'info': 'Some info', - 'field_5': 'NULL', - '#fid': 2, - '#geometry': 'None', + "id": "1", + "description": "Basic unquoted record", + "data": "Some data", + "info": "Some info", + "field_5": "NULL", + "#fid": 2, + "#geometry": "None", }, 2004: { - 'id': '3', - 'description': 'Escaped quotes', - 'data': 'Quoted "citation" data', - 'info': 'Unquoted', - 'field_5': 'NULL', - '#fid': 4, - '#geometry': 'None', + "id": "3", + "description": "Escaped quotes", + "data": 'Quoted "citation" data', + "info": "Unquoted", + "field_5": "NULL", + "#fid": 4, + "#geometry": "None", }, 2009: { - 'id': '5', - 'description': 'Extra fields', - 'data': 'data', - 'info': 'info', - 'field_5': 'message', - '#fid': 9, - '#geometry': 'None', + "id": "5", + "description": "Extra fields", + "data": "data", + "info": "info", + "field_5": "message", + "#fid": 9, + "#geometry": "None", }, 4010: { - 'id': '6', - 'description': 'Missing fields', - 'data': 'NULL', - 'info': 'NULL', - 'field_5': 'NULL', - '#fid': 10, - '#geometry': 'None', + "id": "6", + "description": "Missing fields", + "data": "NULL", + "info": "NULL", + "field_5": "NULL", + "#fid": 10, + "#geometry": "None", }, 6004: { - 'id': '3', - 'description': 'Escaped quotes', - 'data': 'Quoted "citation" data', - 'info': 'Unquoted', - 'field_5': 'NULL', - '#fid': 4, - '#geometry': 'None', + "id": "3", + "description": "Escaped quotes", + "data": 'Quoted "citation" data', + "info": "Unquoted", + "field_5": "NULL", + "#fid": 4, + "#geometry": "None", }, 8002: { - 'id': '1', - 'description': 'Basic unquoted record', - 'data': 'Some data', - 'info': 'Some info', - 'field_5': 'NULL', - '#fid': 2, - '#geometry': 'None', + "id": "1", + "description": "Basic unquoted record", + "data": "Some data", + "info": "Some info", + "field_5": "NULL", + "#fid": 2, + "#geometry": "None", }, 8004: { - 'id': '3', - 'description': 'Escaped quotes', - 'data': 'Quoted "citation" data', - 'info': 'Unquoted', - 'field_5': 'NULL', - '#fid': 4, - '#geometry': 'None', + "id": "3", + "description": "Escaped quotes", + "data": 'Quoted "citation" data', + "info": "Unquoted", + "field_5": "NULL", + "#fid": 4, + "#geometry": "None", }, 8009: { - 'id': '5', - 'description': 'Extra fields', - 'data': 'data', - 'info': 'info', - 'field_5': 'message', - '#fid': 9, - '#geometry': 'None', + "id": "5", + "description": "Extra fields", + "data": "data", + "info": "info", + "field_5": "message", + "#fid": 9, + "#geometry": "None", }, 10003: { - 'id': '2', - 'description': 'Quoted field', - 'data': 'Quoted data', - 'info': 'Unquoted', - 'field_5': 'NULL', - '#fid': 3, - '#geometry': 'None', + "id": "2", + "description": "Quoted field", + "data": "Quoted data", + "info": "Unquoted", + "field_5": "NULL", + "#fid": 3, + "#geometry": "None", }, 10005: { - 'id': '4', - 'description': 'Quoted newlines', - 'data': 'Line 1\nLine 2\n\nLine 4', - 'info': 'No data', - 'field_5': 'NULL', - '#fid': 5, - '#geometry': 'None', + "id": "4", + "description": "Quoted newlines", + "data": "Line 1\nLine 2\n\nLine 4", + "info": "No data", + "field_5": "NULL", + "#fid": 5, + "#geometry": "None", }, 10010: { - 'id': '6', - 'description': 'Missing fields', - 'data': 'NULL', - 'info': 'NULL', - 'field_5': 'NULL', - '#fid': 10, - '#geometry': 'None', + "id": "6", + "description": "Missing fields", + "data": "NULL", + "info": "NULL", + "field_5": "NULL", + "#fid": 10, + "#geometry": "None", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted @@ -2114,437 +2162,493 @@ def test_034_csvt_file(): integer,string,integer,real,string,string,string,string,string,long,longlong """ wanted = {} - wanted['uri'] = 'file://testcsvt.csv?geomType=none&type=csv' - wanted['fieldTypes'] = ['integer', 'text', 'integer', 'double', 'text', 'text', 'text', 'text', 'text', 'longlong', 'longlong', 'longlong'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = "file://testcsvt.csv?geomType=none&type=csv" + wanted["fieldTypes"] = [ + "integer", + "text", + "integer", + "double", + "text", + "text", + "text", + "text", + "text", + "longlong", + "longlong", + "longlong", + ] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Test csvt 1', - 'fint': '1', - 'freal': '1.2', - 'fstr': '1', - 'fstr_1': 'text', - 'fdatetime': '2015-03-02T12:30:00', - 'fdate': '2014-12-30', - 'ftime': '23:55', - 'flong': '-456', - 'flonglong': '-678', - 'field_12': 'NULL', - '#fid': 2, - '#geometry': 'None', + "id": "1", + "description": "Test csvt 1", + "fint": "1", + "freal": "1.2", + "fstr": "1", + "fstr_1": "text", + "fdatetime": "2015-03-02T12:30:00", + "fdate": "2014-12-30", + "ftime": "23:55", + "flong": "-456", + "flonglong": "-678", + "field_12": "NULL", + "#fid": 2, + "#geometry": "None", }, 3: { - 'id': '2', - 'description': 'Test csvt 2', - 'fint': '3', - 'freal': '1.5', - 'fstr': '99', - 'fstr_1': '23.5', - 'fdatetime': '80', - 'fdate': '2015-03-28', - 'ftime': '2014-12-30', - 'flong': 'NULL', - 'flonglong': '9189304972279762602', - 'field_12': '-3123724580211819352', - '#fid': 3, - '#geometry': 'None', + "id": "2", + "description": "Test csvt 2", + "fint": "3", + "freal": "1.5", + "fstr": "99", + "fstr_1": "23.5", + "fdatetime": "80", + "fdate": "2015-03-28", + "ftime": "2014-12-30", + "flong": "NULL", + "flonglong": "9189304972279762602", + "field_12": "-3123724580211819352", + "#fid": 3, + "#geometry": "None", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted def test_035_csvt_file2(): wanted = {} - wanted['uri'] = 'file://testcsvt2.txt?geomType=none&delimiter=|&type=csv' - wanted['fieldTypes'] = ['integer', 'text', 'integer', 'double', 'integer', 'text', 'integer'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = "file://testcsvt2.txt?geomType=none&delimiter=|&type=csv" + wanted["fieldTypes"] = [ + "integer", + "text", + "integer", + "double", + "integer", + "text", + "integer", + ] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Test csvt 1', - 'f1': '1', - 'f2': '1.2', - 'f3': '1', - 'f4': 'text', - 'f5': 'NULL', - '#fid': 2, - '#geometry': 'None', + "id": "1", + "description": "Test csvt 1", + "f1": "1", + "f2": "1.2", + "f3": "1", + "f4": "text", + "f5": "NULL", + "#fid": 2, + "#geometry": "None", }, 3: { - 'id': '2', - 'description': 'Test csvt 2', - 'f1': '3', - 'f2': '1.5', - 'f3': '99', - 'f4': '23.5', - 'f5': '80', - '#fid': 3, - '#geometry': 'None', + "id": "2", + "description": "Test csvt 2", + "f1": "3", + "f2": "1.5", + "f3": "99", + "f4": "23.5", + "f5": "80", + "#fid": 3, + "#geometry": "None", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted def test_036_csvt_file_invalid_types(): wanted = {} - wanted['uri'] = 'file://testcsvt3.csv?geomType=none&type=csv' - wanted['fieldTypes'] = ['integer', 'text', 'integer', 'double', 'integer', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = "file://testcsvt3.csv?geomType=none&type=csv" + wanted["fieldTypes"] = [ + "integer", + "text", + "integer", + "double", + "integer", + "text", + "text", + ] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Test csvt 1', - 'f1': '1', - 'f2': '1.2', - 'f3': '1', - 'f4': 'text', - 'f5': 'times', - '#fid': 2, - '#geometry': 'None', + "id": "1", + "description": "Test csvt 1", + "f1": "1", + "f2": "1.2", + "f3": "1", + "f4": "text", + "f5": "times", + "#fid": 2, + "#geometry": "None", }, 3: { - 'id': '2', - 'description': 'Test csvt 2', - 'f1': '3', - 'f2': '1.5', - 'f3': '99', - 'f4': '23.5', - 'f5': '80', - '#fid': 3, - '#geometry': 'None', + "id": "2", + "description": "Test csvt 2", + "f1": "3", + "f2": "1.5", + "f3": "99", + "f4": "23.5", + "f5": "80", + "#fid": 3, + "#geometry": "None", }, } - wanted['log'] = [ - 'Errors in file testcsvt3.csv', - 'File type string in testcsvt3.csvt is not correctly formatted', + wanted["log"] = [ + "Errors in file testcsvt3.csv", + "File type string in testcsvt3.csvt is not correctly formatted", ] return wanted def test_037_csvt_file_invalid_file(): wanted = {} - wanted['uri'] = 'file://testcsvt4.csv?geomType=none&type=csv' - wanted['fieldTypes'] = ['integer', 'text', 'integer', 'double', 'integer', 'text', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = "file://testcsvt4.csv?geomType=none&type=csv" + wanted["fieldTypes"] = [ + "integer", + "text", + "integer", + "double", + "integer", + "text", + "text", + ] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Test csvt 1', - 'f1': '1', - 'f2': '1.2', - 'f3': '1', - 'f4': 'text', - 'f5': 'times', - '#fid': 2, - '#geometry': 'None', + "id": "1", + "description": "Test csvt 1", + "f1": "1", + "f2": "1.2", + "f3": "1", + "f4": "text", + "f5": "times", + "#fid": 2, + "#geometry": "None", }, 3: { - 'id': '2', - 'description': 'Test csvt 2', - 'f1': '3', - 'f2': '1.5', - 'f3': '99', - 'f4': '23.5', - 'f5': '80', - '#fid': 3, - '#geometry': 'None', + "id": "2", + "description": "Test csvt 2", + "f1": "3", + "f2": "1.5", + "f3": "99", + "f4": "23.5", + "f5": "80", + "#fid": 3, + "#geometry": "None", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted def test_038_type_inference(): wanted = {} - wanted['uri'] = 'file://testtypes.csv?yField=lat&xField=lon&type=csv' - wanted['fieldTypes'] = ['text', 'double', 'double', 'text', 'text', 'integer', 'longlong', 'double', 'text'] - wanted['geometryType'] = 0 - wanted['data'] = { + wanted["uri"] = "file://testtypes.csv?yField=lat&xField=lon&type=csv" + wanted["fieldTypes"] = [ + "text", + "double", + "double", + "text", + "text", + "integer", + "longlong", + "double", + "text", + ] + wanted["geometryType"] = 0 + wanted["data"] = { 2: { - 'id': 'line1', - 'description': '1.0', - 'lon': '1.0', - 'lat': '1.0', - 'empty': 'NULL', - 'text': 'NULL', - 'int': '0', - 'longlong': '0', - 'real': 'NULL', - 'text2': '1', - '#fid': 2, - '#geometry': 'Point (1 1)', + "id": "line1", + "description": "1.0", + "lon": "1.0", + "lat": "1.0", + "empty": "NULL", + "text": "NULL", + "int": "0", + "longlong": "0", + "real": "NULL", + "text2": "1", + "#fid": 2, + "#geometry": "Point (1 1)", }, 3: { - 'id': 'line2', - 'description': '1.0', - 'lon': '1.0', - 'lat': '5.0', - 'empty': 'NULL', - 'text': '1', - 'int': 'NULL', - 'longlong': '9189304972279762602', - 'real': '1.3', - 'text2': '-4', - '#fid': 3, - '#geometry': 'Point (1 5)', + "id": "line2", + "description": "1.0", + "lon": "1.0", + "lat": "5.0", + "empty": "NULL", + "text": "1", + "int": "NULL", + "longlong": "9189304972279762602", + "real": "1.3", + "text2": "-4", + "#fid": 3, + "#geometry": "Point (1 5)", }, 4: { - 'id': 'line3', - 'description': '5.0', - 'lon': '5.0', - 'lat': '5.0', - 'empty': 'NULL', - 'text': '1xx', - 'int': '2', - 'longlong': '345', - 'real': '2.0', - 'text2': '1x', - '#fid': 4, - '#geometry': 'Point (5 5)', + "id": "line3", + "description": "5.0", + "lon": "5.0", + "lat": "5.0", + "empty": "NULL", + "text": "1xx", + "int": "2", + "longlong": "345", + "real": "2.0", + "text2": "1x", + "#fid": 4, + "#geometry": "Point (5 5)", }, 5: { - 'id': 'line4', - 'description': '5.0', - 'lon': '5.0', - 'lat': '1.0', - 'empty': 'NULL', - 'text': 'A string', - 'int': '-3456', - 'longlong': '-3123724580211819352', - 'real': '-123.56', - 'text2': 'NULL', - '#fid': 5, - '#geometry': 'Point (5 1)', + "id": "line4", + "description": "5.0", + "lon": "5.0", + "lat": "1.0", + "empty": "NULL", + "text": "A string", + "int": "-3456", + "longlong": "-3123724580211819352", + "real": "-123.56", + "text2": "NULL", + "#fid": 5, + "#geometry": "Point (5 1)", }, 6: { - 'id': 'line5', - 'description': '3.0', - 'lon': '3.0', - 'lat': '1.0', - 'empty': 'NULL', - 'text': 'NULL', - 'int': 'NULL', - 'longlong': 'NULL', - 'real': '0.00023', - 'text2': '23', - '#fid': 6, - '#geometry': 'Point (3 1)', + "id": "line5", + "description": "3.0", + "lon": "3.0", + "lat": "1.0", + "empty": "NULL", + "text": "NULL", + "int": "NULL", + "longlong": "NULL", + "real": "0.00023", + "text2": "23", + "#fid": 6, + "#geometry": "Point (3 1)", }, 7: { - 'id': 'line6', - 'description': '1.0', - 'lon': '1.0', - 'lat': '3.0', - 'empty': 'NULL', - 'text': '1.5', - 'int': '9', - 'longlong': '42', - 'real': '99.0', - 'text2': '0', - '#fid': 7, - '#geometry': 'Point (1 3)', + "id": "line6", + "description": "1.0", + "lon": "1.0", + "lat": "3.0", + "empty": "NULL", + "text": "1.5", + "int": "9", + "longlong": "42", + "real": "99.0", + "text2": "0", + "#fid": 7, + "#geometry": "Point (1 3)", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted def test_039_issue_13749(): wanted = {} - wanted['uri'] = 'file://test13749.csv?yField=geom_y&xField=geom_x&type=csv' - wanted['fieldTypes'] = ['integer', 'text', 'double', 'double'] - wanted['geometryType'] = 0 - wanted['data'] = { + wanted["uri"] = "file://test13749.csv?yField=geom_y&xField=geom_x&type=csv" + wanted["fieldTypes"] = ["integer", "text", "double", "double"] + wanted["geometryType"] = 0 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'No geom', - 'geom_x': 'NULL', - 'geom_y': 'NULL', - '#fid': 2, - '#geometry': 'None', + "id": "1", + "description": "No geom", + "geom_x": "NULL", + "geom_y": "NULL", + "#fid": 2, + "#geometry": "None", }, 3: { - 'id': '2', - 'description': 'Point1', - 'geom_x': '11.0', - 'geom_y': '22.0', - '#fid': 3, - '#geometry': 'Point (11 22)', + "id": "2", + "description": "Point1", + "geom_x": "11.0", + "geom_y": "22.0", + "#fid": 3, + "#geometry": "Point (11 22)", }, 4: { - 'id': '3', - 'description': 'Point2', - 'geom_x': '15.0', - 'geom_y': '23.0', - '#fid': 4, - '#geometry': 'Point (15 23)', + "id": "3", + "description": "Point2", + "geom_x": "15.0", + "geom_y": "23.0", + "#fid": 4, + "#geometry": "Point (15 23)", }, 5: { - 'id': '4', - 'description': 'Point3', - 'geom_x': '13.0', - 'geom_y': '23.0', - '#fid': 5, - '#geometry': 'Point (13 23)', + "id": "4", + "description": "Point3", + "geom_x": "13.0", + "geom_y": "23.0", + "#fid": 5, + "#geometry": "Point (13 23)", }, } - wanted['log'] = [ - 'Errors in file test13749.csv', - '1 record(s) have missing geometry definitions', + wanted["log"] = [ + "Errors in file test13749.csv", + "1 record(s) have missing geometry definitions", ] return wanted def test_040_issue_14666(): wanted = {} - wanted['uri'] = 'file://test14666.csv?yField=y&xField=x&type=csv&delimiter=\\t' - wanted['fieldTypes'] = ['integer', 'double', 'double'] - wanted['geometryType'] = 0 - wanted['data'] = { + wanted["uri"] = "file://test14666.csv?yField=y&xField=x&type=csv&delimiter=\\t" + wanted["fieldTypes"] = ["integer", "double", "double"] + wanted["geometryType"] = 0 + wanted["data"] = { 2: { - 'id': '1', - 'description': '7.15417', - 'x': '7.15417', - 'y': '50.680622', - '#fid': 2, - '#geometry': 'Point (7.1541699999999997 50.68062199999999962)', + "id": "1", + "description": "7.15417", + "x": "7.15417", + "y": "50.680622", + "#fid": 2, + "#geometry": "Point (7.1541699999999997 50.68062199999999962)", }, 3: { - 'id': '2', - 'description': '7.119219', - 'x': '7.119219', - 'y': '50.739814', - '#fid': 3, - '#geometry': 'Point (7.11921900000000019 50.73981400000000264)', + "id": "2", + "description": "7.119219", + "x": "7.119219", + "y": "50.739814", + "#fid": 3, + "#geometry": "Point (7.11921900000000019 50.73981400000000264)", }, 4: { - 'id': '3', - 'description': 'NULL', - 'x': 'NULL', - 'y': 'NULL', - '#fid': 4, - '#geometry': 'None', + "id": "3", + "description": "NULL", + "x": "NULL", + "y": "NULL", + "#fid": 4, + "#geometry": "None", }, 5: { - 'id': '4', - 'description': 'NULL', - 'x': 'NULL', - 'y': 'NULL', - '#fid': 5, - '#geometry': 'None', + "id": "4", + "description": "NULL", + "x": "NULL", + "y": "NULL", + "#fid": 5, + "#geometry": "None", }, 6: { - 'id': '5', - 'description': '7.129229', - 'x': '7.129229', - 'y': '50.703692', - '#fid': 6, - '#geometry': 'Point (7.12922899999999959 50.70369199999999665)', + "id": "5", + "description": "7.129229", + "x": "7.129229", + "y": "50.703692", + "#fid": 6, + "#geometry": "Point (7.12922899999999959 50.70369199999999665)", }, } - wanted['log'] = [ - 'Errors in file test14666.csv', - '2 record(s) have missing geometry definitions', + wanted["log"] = [ + "Errors in file test14666.csv", + "2 record(s) have missing geometry definitions", ] return wanted def test_041_no_detect_type(): wanted = {} - wanted['uri'] = 'file://testtypes.csv?yField=lat&xField=lon&type=csv&detectTypes=no' - wanted['fieldTypes'] = ['text', 'text', 'text', 'text', 'text', 'text', 'text', 'text', 'text'] - wanted['geometryType'] = 0 - wanted['data'] = { + wanted["uri"] = "file://testtypes.csv?yField=lat&xField=lon&type=csv&detectTypes=no" + wanted["fieldTypes"] = [ + "text", + "text", + "text", + "text", + "text", + "text", + "text", + "text", + "text", + ] + wanted["geometryType"] = 0 + wanted["data"] = { 2: { - 'id': 'line1', - 'description': '1.0', - 'lon': '1.0', - 'lat': '1.0', - 'empty': 'NULL', - 'text': 'NULL', - 'int': '0', - 'longlong': '0', - 'real': 'NULL', - 'text2': '1', - '#fid': 2, - '#geometry': 'Point (1 1)', + "id": "line1", + "description": "1.0", + "lon": "1.0", + "lat": "1.0", + "empty": "NULL", + "text": "NULL", + "int": "0", + "longlong": "0", + "real": "NULL", + "text2": "1", + "#fid": 2, + "#geometry": "Point (1 1)", }, 3: { - 'id': 'line2', - 'description': '1.0', - 'lon': '1.0', - 'lat': '5.0', - 'empty': 'NULL', - 'text': '1', - 'int': 'NULL', - 'longlong': '9189304972279762602', - 'real': '1.3', - 'text2': '-4', - '#fid': 3, - '#geometry': 'Point (1 5)', + "id": "line2", + "description": "1.0", + "lon": "1.0", + "lat": "5.0", + "empty": "NULL", + "text": "1", + "int": "NULL", + "longlong": "9189304972279762602", + "real": "1.3", + "text2": "-4", + "#fid": 3, + "#geometry": "Point (1 5)", }, 4: { - 'id': 'line3', - 'description': '5.0', - 'lon': '5.0', - 'lat': '5.0', - 'empty': 'NULL', - 'text': '1xx', - 'int': '2', - 'longlong': '345', - 'real': '2', - 'text2': '1x', - '#fid': 4, - '#geometry': 'Point (5 5)', + "id": "line3", + "description": "5.0", + "lon": "5.0", + "lat": "5.0", + "empty": "NULL", + "text": "1xx", + "int": "2", + "longlong": "345", + "real": "2", + "text2": "1x", + "#fid": 4, + "#geometry": "Point (5 5)", }, 5: { - 'id': 'line4', - 'description': '5.0', - 'lon': '5.0', - 'lat': '1.0', - 'empty': 'NULL', - 'text': 'A string', - 'int': '-3456', - 'longlong': '-3123724580211819352', - 'real': '-123.56', - 'text2': 'NULL', - '#fid': 5, - '#geometry': 'Point (5 1)', + "id": "line4", + "description": "5.0", + "lon": "5.0", + "lat": "1.0", + "empty": "NULL", + "text": "A string", + "int": "-3456", + "longlong": "-3123724580211819352", + "real": "-123.56", + "text2": "NULL", + "#fid": 5, + "#geometry": "Point (5 1)", }, 6: { - 'id': 'line5', - 'description': '3.0', - 'lon': '3.0', - 'lat': '1.0', - 'empty': 'NULL', - 'text': 'NULL', - 'int': 'NULL', - 'longlong': 'NULL', - 'real': '23e-5', - 'text2': '23', - '#fid': 6, - '#geometry': 'Point (3 1)', + "id": "line5", + "description": "3.0", + "lon": "3.0", + "lat": "1.0", + "empty": "NULL", + "text": "NULL", + "int": "NULL", + "longlong": "NULL", + "real": "23e-5", + "text2": "23", + "#fid": 6, + "#geometry": "Point (3 1)", }, 7: { - 'id': 'line6', - 'description': '1.0', - 'lon': '1.0', - 'lat': '3.0', - 'empty': 'NULL', - 'text': '1.5', - 'int': '9', - 'longlong': '42', - 'real': '99', - 'text2': '0', - '#fid': 7, - '#geometry': 'Point (1 3)', + "id": "line6", + "description": "1.0", + "lon": "1.0", + "lat": "3.0", + "empty": "NULL", + "text": "1.5", + "int": "9", + "longlong": "42", + "real": "99", + "text2": "0", + "#fid": 7, + "#geometry": "Point (1 3)", }, } - wanted['log'] = [ - ] + wanted["log"] = [] return wanted @@ -2553,72 +2657,84 @@ def test_042_no_detect_types_csvt(): and it is not detected)""" wanted = {} - wanted['uri'] = 'file://testcsvt.csv?geomType=none&type=csv&detectTypes=no' - wanted['fieldTypes'] = ['integer', 'text', 'integer', 'double', 'text', 'text', 'text', 'text', 'text', 'longlong', 'longlong', 'text'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = "file://testcsvt.csv?geomType=none&type=csv&detectTypes=no" + wanted["fieldTypes"] = [ + "integer", + "text", + "integer", + "double", + "text", + "text", + "text", + "text", + "text", + "longlong", + "longlong", + "text", + ] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': '1', - 'description': 'Test csvt 1', - 'fint': '1', - 'freal': '1.2', - 'fstr': '1', - 'fstr_1': 'text', - 'fdatetime': '2015-03-02T12:30:00', - 'fdate': '2014-12-30', - 'ftime': '23:55', - 'flong': '-456', - 'flonglong': '-678', - 'field_12': 'NULL', - '#fid': 2, - '#geometry': 'None', + "id": "1", + "description": "Test csvt 1", + "fint": "1", + "freal": "1.2", + "fstr": "1", + "fstr_1": "text", + "fdatetime": "2015-03-02T12:30:00", + "fdate": "2014-12-30", + "ftime": "23:55", + "flong": "-456", + "flonglong": "-678", + "field_12": "NULL", + "#fid": 2, + "#geometry": "None", }, 3: { - 'id': '2', - 'description': 'Test csvt 2', - 'fint': '3', - 'freal': '1.5', - 'fstr': '99', - 'fstr_1': '23.5', - 'fdatetime': '80', - 'fdate': '2015-03-28', - 'ftime': '2014-12-30', - 'flong': 'NULL', - 'flonglong': '9189304972279762602', - 'field_12': '-3123724580211819352', - '#fid': 3, - '#geometry': 'None', + "id": "2", + "description": "Test csvt 2", + "fint": "3", + "freal": "1.5", + "fstr": "99", + "fstr_1": "23.5", + "fdatetime": "80", + "fdate": "2015-03-28", + "ftime": "2014-12-30", + "flong": "NULL", + "flonglong": "9189304972279762602", + "field_12": "-3123724580211819352", + "#fid": 3, + "#geometry": "None", }, } - wanted['log'] = [ - ] + wanted["log"] = [] return wanted def test_048_csvt_file(): wanted = {} - wanted['uri'] = 'file://testcsvt5.csv?geomType=none&type=csv' - wanted['fieldTypes'] = ['text', 'text', 'double', 'double', 'double'] - wanted['geometryType'] = 4 - wanted['data'] = { + wanted["uri"] = "file://testcsvt5.csv?geomType=none&type=csv" + wanted["fieldTypes"] = ["text", "text", "double", "double", "double"] + wanted["geometryType"] = 4 + wanted["data"] = { 2: { - 'id': '01', - 'description': 'Test csvt 1', - 'f1': '0.3', - 'f2': '0.8', - 'f3': '1.4', - '#fid': 2, - '#geometry': 'None', + "id": "01", + "description": "Test csvt 1", + "f1": "0.3", + "f2": "0.8", + "f3": "1.4", + "#fid": 2, + "#geometry": "None", }, 3: { - 'id': '12', - 'description': 'Test csvt 2', - 'f1': '0.2', - 'f2': '78.0', - 'f3': '13.4', - '#fid': 3, - '#geometry': 'None', + "id": "12", + "description": "Test csvt 2", + "f1": "0.2", + "f2": "78.0", + "f3": "13.4", + "#fid": 3, + "#geometry": "None", }, } - wanted['log'] = [] + wanted["log"] = [] return wanted diff --git a/tests/src/python/test_qgsdistancearea.py b/tests/src/python/test_qgsdistancearea.py index 439d2c76ff1c..9deb816a985e 100644 --- a/tests/src/python/test_qgsdistancearea.py +++ b/tests/src/python/test_qgsdistancearea.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Jürgen E. Fischer' -__date__ = '19/01/2014' -__copyright__ = 'Copyright 2014, The QGIS Project' + +__author__ = "Jürgen E. Fischer" +__date__ = "19/01/2014" +__copyright__ = "Copyright 2014, The QGIS Project" import math from pprint import pprint @@ -38,29 +39,45 @@ def testCrs(self): da = QgsDistanceArea() # try setting using a CRS object - crs = QgsCoordinateReferenceSystem('EPSG:3111') + crs = QgsCoordinateReferenceSystem("EPSG:3111") da.setSourceCrs(crs, QgsProject.instance().transformContext()) self.assertEqual(da.sourceCrs().srsid(), crs.srsid()) self.assertFalse(da.ellipsoidCrs().isValid()) da.setEllipsoid("GRS80") # depends on proj version - self.assertIn(da.ellipsoidCrs().toProj(), ( - '+proj=longlat +ellps=GRS80 +no_defs', '+proj=longlat +a=6378137 +rf=298.25722210100002 +no_defs')) + self.assertIn( + da.ellipsoidCrs().toProj(), + ( + "+proj=longlat +ellps=GRS80 +no_defs", + "+proj=longlat +a=6378137 +rf=298.25722210100002 +no_defs", + ), + ) da.setEllipsoid("WGS84") - self.assertIn(da.ellipsoidCrs().toProj(), ( - '+proj=longlat +ellps=WGS84 +no_defs', '+proj=longlat +a=6378137 +rf=298.25722356300003 +no_defs')) + self.assertIn( + da.ellipsoidCrs().toProj(), + ( + "+proj=longlat +ellps=WGS84 +no_defs", + "+proj=longlat +a=6378137 +rf=298.25722356300003 +no_defs", + ), + ) def testMeasureLine(self): # +-+ # | | # +-+ + linestring = QgsGeometry.fromPolylineXY( - [QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 0), ] + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 0), + ] ) da = QgsDistanceArea() length = da.measureLength(linestring) - myMessage = f'Expected:\n{4:f}\nGot:\n{length:f}\n' + myMessage = f"Expected:\n{4:f}\nGot:\n{length:f}\n" assert length == 4, myMessage def testBearing(self): @@ -68,14 +85,33 @@ def testBearing(self): Test bearing calculation """ da = QgsDistanceArea() - self.assertAlmostEqual(da.bearing(QgsPointXY(145.047, -37.578), QgsPointXY(168.38, -16.95)), 0.84685, 5) - self.assertAlmostEqual(da.bearing(QgsPointXY(-19.57, 65.12), QgsPointXY(-2.63, 54.97)), 2.11060792, 5) + self.assertAlmostEqual( + da.bearing(QgsPointXY(145.047, -37.578), QgsPointXY(168.38, -16.95)), + 0.84685, + 5, + ) + self.assertAlmostEqual( + da.bearing(QgsPointXY(-19.57, 65.12), QgsPointXY(-2.63, 54.97)), + 2.11060792, + 5, + ) - da.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:3857'), QgsProject.instance().transformContext()) + da.setSourceCrs( + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsProject.instance().transformContext(), + ) da.setEllipsoid(da.sourceCrs().ellipsoidAcronym()) self.assertTrue(da.willUseEllipsoid()) - self.assertAlmostEqual(da.bearing(QgsPointXY(16198544, -4534850), QgsPointXY(18736872, -1877769)), 0.8723168079, 5) - self.assertAlmostEqual(da.bearing(QgsPointXY(-2074453, 9559553), QgsPointXY(-55665, 6828252)), 2.35691008, 5) + self.assertAlmostEqual( + da.bearing(QgsPointXY(16198544, -4534850), QgsPointXY(18736872, -1877769)), + 0.8723168079, + 5, + ) + self.assertAlmostEqual( + da.bearing(QgsPointXY(-2074453, 9559553), QgsPointXY(-55665, 6828252)), + 2.35691008, + 5, + ) def testMeasureLineProjected(self): # +-+ @@ -85,25 +121,41 @@ def testMeasureLineProjected(self): da_3068 = QgsDistanceArea() da_wsg84 = QgsDistanceArea() - da_3068.setSourceCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:3068'), - QgsProject.instance().transformContext()) - if (da_3068.sourceCrs().isGeographic()): + da_3068.setSourceCrs( + QgsCoordinateReferenceSystem.fromOgcWmsCrs("EPSG:3068"), + QgsProject.instance().transformContext(), + ) + if da_3068.sourceCrs().isGeographic(): da_3068.setEllipsoid(da_3068.sourceCrs().ellipsoidAcronym()) - print("setting [{}] srid [{}] description [{}]".format('Soldner Berlin', da_3068.sourceCrs().authid(), - da_3068.sourceCrs().description())) - self.assertEqual(da_3068.sourceCrs().authid(), 'EPSG:3068') - da_wsg84.setSourceCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:4326'), - QgsProject.instance().transformContext()) - if (da_wsg84.sourceCrs().isGeographic()): + print( + "setting [{}] srid [{}] description [{}]".format( + "Soldner Berlin", + da_3068.sourceCrs().authid(), + da_3068.sourceCrs().description(), + ) + ) + self.assertEqual(da_3068.sourceCrs().authid(), "EPSG:3068") + da_wsg84.setSourceCrs( + QgsCoordinateReferenceSystem.fromOgcWmsCrs("EPSG:4326"), + QgsProject.instance().transformContext(), + ) + if da_wsg84.sourceCrs().isGeographic(): da_wsg84.setEllipsoid(da_wsg84.sourceCrs().ellipsoidAcronym()) - self.assertEqual(da_wsg84.sourceCrs().authid(), 'EPSG:4326') - print("setting [{}] srid [{}] description [{}] isGeographic[{}]".format('Wsg84', - da_wsg84.sourceCrs().authid(), - da_wsg84.sourceCrs().description(), - da_wsg84.sourceCrs().isGeographic())) + self.assertEqual(da_wsg84.sourceCrs().authid(), "EPSG:4326") + print( + "setting [{}] srid [{}] description [{}] isGeographic[{}]".format( + "Wsg84", + da_wsg84.sourceCrs().authid(), + da_wsg84.sourceCrs().description(), + da_wsg84.sourceCrs().isGeographic(), + ) + ) # print(("-- projectionAcronym[{}] ellipsoidAcronym[{}] toWkt[{}] mapUnits[{}] toProj4[{}]".format(da_wsg84.sourceCrs().projectionAcronym(),da_wsg84.sourceCrs().ellipsoidAcronym(), da_wsg84.sourceCrs().toWkt(),da_wsg84.sourceCrs().mapUnits(),da_wsg84.sourceCrs().toProj()))) - print("Testing Position change for[{}] years[{}]".format('Ampelanlage - Potsdamer Platz, Verkehrsinsel', - '1924 and 1998')) + print( + "Testing Position change for[{}] years[{}]".format( + "Ampelanlage - Potsdamer Platz, Verkehrsinsel", "1924 and 1998" + ) + ) # 1924-10-24 SRID=3068;POINT(23099.49 20296.69) # 1924-10-24 SRID=4326;POINT(13.37650707988041 52.50952361017194) @@ -121,7 +173,9 @@ def testMeasureLineProjected(self): distance_wsg84_meters = 33.617302 # ST_Distance(point_wsg84_1924,point_wsg84_1998) # distance_wsg84_mapunits=0.000362 - distance_wsg84_mapunits_format = QgsDistanceArea.formatDistance(0.000362, 7, QgsUnitTypes.DistanceUnit.DistanceDegrees, True) + distance_wsg84_mapunits_format = QgsDistanceArea.formatDistance( + 0.000362, 7, QgsUnitTypes.DistanceUnit.DistanceDegrees, True + ) # ST_Azimuth(point_wsg84_1924,point_wsg84_1998) azimuth_wsg84_1924 = 3.674878 # ST_Azimuth(point_wsg84_1998,point_wsg84_1998) @@ -135,31 +189,51 @@ def testMeasureLineProjected(self): distance_qpoint = point_soldner_1924.distance(point_soldner_1998) azimuth_qpoint = point_soldner_1924.azimuth(point_soldner_1998) - point_soldner_1998_result = point_soldner_1924.project(distance_qpoint, azimuth_qpoint) + point_soldner_1998_result = point_soldner_1924.project( + distance_qpoint, azimuth_qpoint + ) point_soldner_1924_result = QgsPointXY(0, 0) point_soldner_1998_result = QgsPointXY(0, 0) # Test meter based projected point from point_1924 to point_1998 - length_1998_mapunits, point_soldner_1998_result = da_3068.measureLineProjected(point_soldner_1924, - distance_soldner_meters, - azimuth_qpoint) - self.assertEqual(point_soldner_1998_result.toString(6), point_soldner_1998.toString(6)) + length_1998_mapunits, point_soldner_1998_result = da_3068.measureLineProjected( + point_soldner_1924, distance_soldner_meters, azimuth_qpoint + ) + self.assertEqual( + point_soldner_1998_result.toString(6), point_soldner_1998.toString(6) + ) # Test degree based projected point from point_1924 1 meter due East point_wsg84_meter_result = QgsPointXY(0, 0) point_wsg84_1927_meter = QgsPointXY(13.37652180838435, 52.50952361017102) - length_meter_mapunits, point_wsg84_meter_result = da_wsg84.measureLineProjected(point_wsg84_1924, 1.0, - (math.pi / 2)) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.0000147 deg') - self.assertEqual(point_wsg84_meter_result.toString(7), point_wsg84_1927_meter.toString(7)) + length_meter_mapunits, point_wsg84_meter_result = da_wsg84.measureLineProjected( + point_wsg84_1924, 1.0, (math.pi / 2) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 7, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.0000147 deg", + ) + self.assertEqual( + point_wsg84_meter_result.toString(7), point_wsg84_1927_meter.toString(7) + ) point_wsg84_1998_result = QgsPointXY(0, 0) - length_1928_mapunits, point_wsg84_1998_result = da_wsg84.measureLineProjected(point_wsg84_1924, - distance_wsg84_meters, - azimuth_wsg84_1924) - self.assertEqual(QgsDistanceArea.formatDistance(length_1928_mapunits, 7, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - distance_wsg84_mapunits_format) - self.assertEqual(point_wsg84_1998_result.toString(7), point_wsg84_1998.toString(7)) + length_1928_mapunits, point_wsg84_1998_result = da_wsg84.measureLineProjected( + point_wsg84_1924, distance_wsg84_meters, azimuth_wsg84_1924 + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_1928_mapunits, 7, QgsUnitTypes.DistanceUnit.DistanceDegrees, True + ), + distance_wsg84_mapunits_format, + ) + self.assertEqual( + point_wsg84_1998_result.toString(7), point_wsg84_1998.toString(7) + ) def testMeasureLineProjectedWorldPoints(self): # +-+ @@ -167,386 +241,952 @@ def testMeasureLineProjectedWorldPoints(self): # +-+ + # checking returned length_mapunits/projected_points of different world points with results from SpatiaLite ST_Project da_3068 = QgsDistanceArea() - da_3068.setSourceCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:3068'), - QgsProject.instance().transformContext()) - if (da_3068.sourceCrs().isGeographic()): + da_3068.setSourceCrs( + QgsCoordinateReferenceSystem.fromOgcWmsCrs("EPSG:3068"), + QgsProject.instance().transformContext(), + ) + if da_3068.sourceCrs().isGeographic(): da_3068.setEllipsoid(da_3068.sourceCrs().ellipsoidAcronym()) - self.assertEqual(da_3068.sourceCrs().authid(), 'EPSG:3068') + self.assertEqual(da_3068.sourceCrs().authid(), "EPSG:3068") print( "setting [{}] srid [{}] description [{}] isGeographic[{}] lengthUnits[{}] projectionAcronym[{}] ellipsoidAcronym[{}]".format( - 'EPSG:3068', da_3068.sourceCrs().authid(), da_3068.sourceCrs().description(), - da_3068.sourceCrs().isGeographic(), QgsUnitTypes.toString(da_3068.lengthUnits()), - da_3068.sourceCrs().projectionAcronym(), da_3068.sourceCrs().ellipsoidAcronym())) + "EPSG:3068", + da_3068.sourceCrs().authid(), + da_3068.sourceCrs().description(), + da_3068.sourceCrs().isGeographic(), + QgsUnitTypes.toString(da_3068.lengthUnits()), + da_3068.sourceCrs().projectionAcronym(), + da_3068.sourceCrs().ellipsoidAcronym(), + ) + ) da_wsg84 = QgsDistanceArea() - da_wsg84.setSourceCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:4326'), - QgsProject.instance().transformContext()) - if (da_wsg84.sourceCrs().isGeographic()): + da_wsg84.setSourceCrs( + QgsCoordinateReferenceSystem.fromOgcWmsCrs("EPSG:4326"), + QgsProject.instance().transformContext(), + ) + if da_wsg84.sourceCrs().isGeographic(): da_wsg84.setEllipsoid(da_wsg84.sourceCrs().ellipsoidAcronym()) - self.assertEqual(da_wsg84.sourceCrs().authid(), 'EPSG:4326') + self.assertEqual(da_wsg84.sourceCrs().authid(), "EPSG:4326") print( "setting [{}] srid [{}] description [{}] isGeographic[{}] lengthUnits[{}] projectionAcronym[{}] ellipsoidAcronym[{}] ellipsoid[{}]".format( - 'EPSG:4326', da_wsg84.sourceCrs().authid(), da_wsg84.sourceCrs().description(), - da_wsg84.sourceCrs().isGeographic(), QgsUnitTypes.toString(da_wsg84.lengthUnits()), - da_wsg84.sourceCrs().projectionAcronym(), da_wsg84.sourceCrs().ellipsoidAcronym(), - da_wsg84.ellipsoid())) + "EPSG:4326", + da_wsg84.sourceCrs().authid(), + da_wsg84.sourceCrs().description(), + da_wsg84.sourceCrs().isGeographic(), + QgsUnitTypes.toString(da_wsg84.lengthUnits()), + da_wsg84.sourceCrs().projectionAcronym(), + da_wsg84.sourceCrs().ellipsoidAcronym(), + da_wsg84.ellipsoid(), + ) + ) da_4314 = QgsDistanceArea() - da_4314.setSourceCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:4314'), - QgsProject.instance().transformContext()) - if (da_4314.sourceCrs().isGeographic()): + da_4314.setSourceCrs( + QgsCoordinateReferenceSystem.fromOgcWmsCrs("EPSG:4314"), + QgsProject.instance().transformContext(), + ) + if da_4314.sourceCrs().isGeographic(): da_4314.setEllipsoid(da_4314.sourceCrs().ellipsoidAcronym()) - self.assertEqual(da_4314.sourceCrs().authid(), 'EPSG:4314') + self.assertEqual(da_4314.sourceCrs().authid(), "EPSG:4314") print( "setting [{}] srid [{}] description [{}] isGeographic[{}] lengthUnits[{}] projectionAcronym[{}] ellipsoidAcronym[{}]".format( - 'EPSG:4314', da_4314.sourceCrs().authid(), da_4314.sourceCrs().description(), - da_4314.sourceCrs().isGeographic(), QgsUnitTypes.toString(da_4314.lengthUnits()), - da_4314.sourceCrs().projectionAcronym(), da_4314.sourceCrs().ellipsoidAcronym())) + "EPSG:4314", + da_4314.sourceCrs().authid(), + da_4314.sourceCrs().description(), + da_4314.sourceCrs().isGeographic(), + QgsUnitTypes.toString(da_4314.lengthUnits()), + da_4314.sourceCrs().projectionAcronym(), + da_4314.sourceCrs().ellipsoidAcronym(), + ) + ) da_4805 = QgsDistanceArea() - da_4805.setSourceCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:4805'), - QgsProject.instance().transformContext()) - if (da_4805.sourceCrs().isGeographic()): + da_4805.setSourceCrs( + QgsCoordinateReferenceSystem.fromOgcWmsCrs("EPSG:4805"), + QgsProject.instance().transformContext(), + ) + if da_4805.sourceCrs().isGeographic(): da_4805.setEllipsoid(da_4805.sourceCrs().ellipsoidAcronym()) - self.assertEqual(da_4805.sourceCrs().authid(), 'EPSG:4805') + self.assertEqual(da_4805.sourceCrs().authid(), "EPSG:4805") print( "setting [{}] srid [{}] description [{}] isGeographic[{}] lengthUnits[{}] projectionAcronym[{}] ellipsoidAcronym[{}]".format( - 'EPSG:4805', da_4805.sourceCrs().authid(), da_4805.sourceCrs().description(), - da_4805.sourceCrs().isGeographic(), QgsUnitTypes.toString(da_4805.lengthUnits()), - da_4805.sourceCrs().projectionAcronym(), da_4805.sourceCrs().ellipsoidAcronym())) + "EPSG:4805", + da_4805.sourceCrs().authid(), + da_4805.sourceCrs().description(), + da_4805.sourceCrs().isGeographic(), + QgsUnitTypes.toString(da_4805.lengthUnits()), + da_4805.sourceCrs().projectionAcronym(), + da_4805.sourceCrs().ellipsoidAcronym(), + ) + ) # EPSG:5665 unknown, why? da_5665 = QgsDistanceArea() - da_5665.setSourceCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:5665'), - QgsProject.instance().transformContext()) - if (da_5665.sourceCrs().isGeographic()): + da_5665.setSourceCrs( + QgsCoordinateReferenceSystem.fromOgcWmsCrs("EPSG:5665"), + QgsProject.instance().transformContext(), + ) + if da_5665.sourceCrs().isGeographic(): da_5665.setEllipsoid(da_5665.sourceCrs().ellipsoidAcronym()) print( "setting [{}] srid [{}] description [{}] isGeographic[{}] lengthUnits[{}] projectionAcronym[{}] ellipsoidAcronym[{}]".format( - 'EPSG:5665', da_5665.sourceCrs().authid(), da_5665.sourceCrs().description(), - da_5665.sourceCrs().isGeographic(), QgsUnitTypes.toString(da_5665.lengthUnits()), - da_5665.sourceCrs().projectionAcronym(), da_5665.sourceCrs().ellipsoidAcronym())) + "EPSG:5665", + da_5665.sourceCrs().authid(), + da_5665.sourceCrs().description(), + da_5665.sourceCrs().isGeographic(), + QgsUnitTypes.toString(da_5665.lengthUnits()), + da_5665.sourceCrs().projectionAcronym(), + da_5665.sourceCrs().ellipsoidAcronym(), + ) + ) # self.assertEqual(da_5665.sourceCrs().authid(), 'EPSG:5665') da_25833 = QgsDistanceArea() - da_25833.setSourceCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:25833'), - QgsProject.instance().transformContext()) - if (da_25833.sourceCrs().isGeographic()): + da_25833.setSourceCrs( + QgsCoordinateReferenceSystem.fromOgcWmsCrs("EPSG:25833"), + QgsProject.instance().transformContext(), + ) + if da_25833.sourceCrs().isGeographic(): da_25833.setEllipsoid(da_25833.sourceCrs().ellipsoidAcronym()) print( "setting [{}] srid [{}] description [{}] isGeographic[{}] lengthUnits[{}] projectionAcronym[{}] ellipsoidAcronym[{}]".format( - 'EPSG:25833', da_25833.sourceCrs().authid(), da_25833.sourceCrs().description(), - da_25833.sourceCrs().isGeographic(), QgsUnitTypes.toString(da_25833.lengthUnits()), - da_25833.sourceCrs().projectionAcronym(), da_25833.sourceCrs().ellipsoidAcronym())) - self.assertEqual(da_25833.sourceCrs().authid(), 'EPSG:25833') + "EPSG:25833", + da_25833.sourceCrs().authid(), + da_25833.sourceCrs().description(), + da_25833.sourceCrs().isGeographic(), + QgsUnitTypes.toString(da_25833.lengthUnits()), + da_25833.sourceCrs().projectionAcronym(), + da_25833.sourceCrs().ellipsoidAcronym(), + ) + ) + self.assertEqual(da_25833.sourceCrs().authid(), "EPSG:25833") # Berlin - Brandenburg Gate - Quadriga point_berlin_3068 = QgsPointXY(23183.38449999984, 21047.3225000017) point_berlin_3068_project = point_berlin_3068.project(1, (math.pi / 2)) point_meter_result = QgsPointXY(0, 0) - length_meter_mapunits, point_meter_result = da_3068.measureLineProjected(point_berlin_3068, 1.0, (math.pi / 2)) + length_meter_mapunits, point_meter_result = da_3068.measureLineProjected( + point_berlin_3068, 1.0, (math.pi / 2) + ) pprint(point_meter_result) - print('-I-> Berlin 3068 length_meter_mapunits[{}] point_meter_result[{}]'.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_3068.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 1, da_3068.lengthUnits(), True), '1.0 m') - self.assertEqual(point_meter_result.toString(7), point_berlin_3068_project.toString(7)) + print( + "-I-> Berlin 3068 length_meter_mapunits[{}] point_meter_result[{}]".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_3068.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 1, da_3068.lengthUnits(), True + ), + "1.0 m", + ) + self.assertEqual( + point_meter_result.toString(7), point_berlin_3068_project.toString(7) + ) point_berlin_wsg84 = QgsPointXY(13.37770458660236, 52.51627178856762) point_berlin_wsg84_project = QgsPointXY(13.37771931736259, 52.51627178856669) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_berlin_wsg84, 1.0, - (math.pi / 2)) - print('-I-> Berlin Wsg84 length_meter_mapunits[{}] point_meter_result[{}] ellipsoid[{}]'.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 20, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt(), da_wsg84.ellipsoid())) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_berlin_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Berlin Wsg84 length_meter_mapunits[{}] point_meter_result[{}] ellipsoid[{}]".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 20, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + da_wsg84.ellipsoid(), + ) + ) # for unknown reasons, this is returning '0.00001473026 m' instead of '0.00001473026 deg' when using da_wsg84.lengthUnits() # self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits,11,da_wsg84.lengthUnits(),True), '0.00001473026 deg') - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 11, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00001473076 deg') - self.assertEqual(point_meter_result.toString(7), point_berlin_wsg84_project.toString(7)) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 11, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00001473076 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_berlin_wsg84_project.toString(7) + ) point_berlin_4314 = QgsPointXY(13.37944343021465, 52.51767872437083) point_berlin_4314_project = QgsPointXY(13.37945816324759, 52.5176787243699) - length_meter_mapunits, point_meter_result = da_4314.measureLineProjected(point_berlin_4314, 1.0, (math.pi / 2)) - print('-I-> Berlin 4314 length_meter_mapunits[{}] point_meter_result[{}]'.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_4314.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 9, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.000014733 deg') - self.assertEqual(point_meter_result.toString(7), point_berlin_4314_project.toString(7)) + length_meter_mapunits, point_meter_result = da_4314.measureLineProjected( + point_berlin_4314, 1.0, (math.pi / 2) + ) + print( + "-I-> Berlin 4314 length_meter_mapunits[{}] point_meter_result[{}]".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_4314.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 9, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.000014733 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_berlin_4314_project.toString(7) + ) point_berlin_4805 = QgsPointXY(31.04960570069176, 52.5174657497405) point_berlin_4805_project = QgsPointXY(31.04962043365347, 52.51746574973957) - length_meter_mapunits, point_meter_result = da_4805.measureLineProjected(point_berlin_4805, 1.0, (math.pi / 2)) - print('-I-> Berlin 4805 length_meter_mapunits[{}] point_meter_result[{}]'.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_4805.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 9, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.000014733 deg') - self.assertEqual(point_meter_result.toString(7), point_berlin_4805_project.toString(7)) + length_meter_mapunits, point_meter_result = da_4805.measureLineProjected( + point_berlin_4805, 1.0, (math.pi / 2) + ) + print( + "-I-> Berlin 4805 length_meter_mapunits[{}] point_meter_result[{}]".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_4805.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 9, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.000014733 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_berlin_4805_project.toString(7) + ) point_berlin_25833 = QgsPointXY(389918.0748318382, 5819698.772194743) point_berlin_25833_project = point_berlin_25833.project(1, (math.pi / 2)) - length_meter_mapunits, point_meter_result = da_25833.measureLineProjected(point_berlin_25833, 1.0, - (math.pi / 2)) - print('-I-> Berlin 25833 length_meter_mapunits[{}] point_meter_result[{}]'.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_25833.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_25833.lengthUnits(), True), - '1.0000000 m') - self.assertEqual(point_meter_result.toString(7), point_berlin_25833_project.toString(7)) + length_meter_mapunits, point_meter_result = da_25833.measureLineProjected( + point_berlin_25833, 1.0, (math.pi / 2) + ) + print( + "-I-> Berlin 25833 length_meter_mapunits[{}] point_meter_result[{}]".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_25833.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_25833.lengthUnits(), True + ), + "1.0000000 m", + ) + self.assertEqual( + point_meter_result.toString(7), point_berlin_25833_project.toString(7) + ) if da_5665.sourceCrs().authid() != "": point_berlin_5665 = QgsPointXY(3389996.871728864, 5822169.719727578) point_berlin_5665_project = point_berlin_5665.project(1, (math.pi / 2)) - length_meter_mapunits, point_meter_result = da_5665.measureLineProjected(point_berlin_5665, 1.0, - (math.pi / 2)) - print('-I-> Berlin 5665 length_meter_mapunits[{}] point_meter_result[{}]'.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_5665.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 1, da_5665.lengthUnits(), True), - '1.0 m') - self.assertEqual(point_meter_result.toString(7), point_berlin_5665_project.toString(7)) - print('\n12 points ''above over'' and on the Equator') + length_meter_mapunits, point_meter_result = da_5665.measureLineProjected( + point_berlin_5665, 1.0, (math.pi / 2) + ) + print( + "-I-> Berlin 5665 length_meter_mapunits[{}] point_meter_result[{}]".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_5665.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 1, da_5665.lengthUnits(), True + ), + "1.0 m", + ) + self.assertEqual( + point_meter_result.toString(7), point_berlin_5665_project.toString(7) + ) + print("\n12 points " "above over" " and on the Equator") point_wsg84 = QgsPointXY(25.7844, 71.1725) point_wsg84_project = QgsPointXY(25.78442775215388, 71.17249999999795) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Nordkap, Norway - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.0000278 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Nordkap, Norway - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 7, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.0000278 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(24.95995, 60.16841) point_wsg84_project = QgsPointXY(24.95996801277454, 60.16840999999877) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Helsinki, Finnland - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00001801 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Helsinki, Finnland - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00001801 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(12.599278, 55.692861) point_wsg84_project = QgsPointXY(12.59929390161872, 55.69286099999897) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Copenhagen, Denmark - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00001590 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Copenhagen, Denmark - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00001590 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(-0.001389, 51.477778) point_wsg84_project = QgsPointXY(-0.001374606184398, 51.4777779999991) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) print( - '-I-> Royal Greenwich Observatory, United Kingdom - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00001439 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + "-I-> Royal Greenwich Observatory, United Kingdom - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00001439 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(7.58769, 47.55814) point_wsg84_project = QgsPointXY(7.587703287209086, 47.55813999999922) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Basel, Switzerland - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00001329 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Basel, Switzerland - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00001329 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(11.255278, 43.775278) point_wsg84_project = QgsPointXY(11.25529042107924, 43.77527799999933) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Florenz, Italy - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00001242 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Florenz, Italy - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00001242 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(14.514722, 35.899722) point_wsg84_project = QgsPointXY(14.51473307693308, 35.89972199999949) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Valletta, Malta - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00001108 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Valletta, Malta - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00001108 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(-79.933333, 32.783333) point_wsg84_project = QgsPointXY(-79.93332232547254, 32.78333299999955) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Charlston, South Carolina - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00001067 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Charlston, South Carolina - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00001067 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(-17.6666666, 27.733333) point_wsg84_project = QgsPointXY(-17.66665645831515, 27.73333299999962) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Ferro, Spain - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00001014 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Ferro, Spain - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00001014 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(-99.133333, 19.433333) point_wsg84_project = QgsPointXY(-99.1333234776827, 19.43333299999975) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Mexico City, Mexico - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00000952 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Mexico City, Mexico - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00000952 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(-79.894444, 9.341667) point_wsg84_project = QgsPointXY(-79.89443489691369, 9.341666999999882) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Colón, Panama - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00000910 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Colón, Panama - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00000910 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(-74.075833, 4.598056) point_wsg84_project = QgsPointXY(-74.07582398803629, 4.598055999999943) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Bogotá, Colombia - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00000901 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Bogotá, Colombia - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00000901 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(0, 0) point_wsg84_project = QgsPointXY(0.000008983152841, 0) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Equator, Atlantic Ocean - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00000898 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) - print('\n12 points ''down under'' and 1 point that should be considered invalid') + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Equator, Atlantic Ocean - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00000898 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) + print( + "\n12 points " "down under" " and 1 point that should be considered invalid" + ) point_wsg84 = QgsPointXY(-78.509722, -0.218611) point_wsg84_project = QgsPointXY(-78.50971301678221, -0.218610999999997) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Quito, Ecuador - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00000898 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Quito, Ecuador - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00000898 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(106.816667, -6.2) point_wsg84_project = QgsPointXY(106.8166760356519, -6.199999999999922) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Jakarta, Indonesia - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00000904 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Jakarta, Indonesia - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00000904 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(-77.018611, -12.035) point_wsg84_project = QgsPointXY(-77.01860181630058, -12.03499999999985) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Lima, Peru - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00000918 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Lima, Peru - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00000918 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(25.466667, -10.716667) point_wsg84_project = QgsPointXY(25.46667614155322, -10.71666699999986) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Kolwezi, Congo - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00000914 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Kolwezi, Congo - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00000914 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(-70.333333, -18.483333) point_wsg84_project = QgsPointXY(-70.3333235314429, -18.48333299999976) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Arica, Chile - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00000947 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Arica, Chile - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00000947 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(-70.666667, -33.45) point_wsg84_project = QgsPointXY(-70.66665624452817, -33.44999999999953) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Santiago, Chile - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00001076 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Santiago, Chile - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00001076 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(144.9604, -37.8191) point_wsg84_project = QgsPointXY(144.96041135746983741, -37.81909999999945171) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Melbourne, Australia - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 8, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00001136 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Melbourne, Australia - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 8, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00001136 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(147.29, -42.88) point_wsg84_project = QgsPointXY(147.2900122399815, -42.87999999999934) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Hobart City,Tasmania, Australia - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00001224 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Hobart City,Tasmania, Australia - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00001224 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(168.101667, -46.899722) point_wsg84_project = QgsPointXY(168.101680123673, -46.89972199999923) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) print( - '-I-> Ryan''s Creek Aerodrome, New Zealand - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00001312 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + "-I-> Ryan" + "s Creek Aerodrome, New Zealand - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00001312 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(-69.216667, -51.633333) point_wsg84_project = QgsPointXY(-69.21665255700216, -51.6333329999991) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Río Gallegos, Argentina - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00001444 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Río Gallegos, Argentina - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00001444 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(-68.3, -54.8) point_wsg84_project = QgsPointXY(-68.29998445081456, -54.79999999999899) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) print( - '-I-> Ushuaia, Tierra del Fuego, Argentina - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00001555 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + "-I-> Ushuaia, Tierra del Fuego, Argentina - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00001555 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(-63.494444, -64.825278) point_wsg84_project = QgsPointXY(-63.49442294002932, -64.82527799999851) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Port Lockroy, Antarctica - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00002106 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Port Lockroy, Antarctica - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00002106 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(-180, -84.863272250) point_wsg84_project = QgsPointXY(-179.9999000000025, -84.8632722499922) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) - print('-I-> Someware, Antarctica - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00010000 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) + print( + "-I-> Someware, Antarctica - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00010000 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) point_wsg84 = QgsPointXY(-180, -85.0511300) point_wsg84_project = QgsPointXY(-179.9998962142197, -85.05112999999191) - length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) + length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected( + point_wsg84, 1.0, (math.pi / 2) + ) print( - '-W-> Mercator''s Last Stop, Antarctica - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format( - QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), - point_meter_result.asWkt())) - self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - '0.00010379 deg') - self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) + "-W-> Mercator" + "s Last Stop, Antarctica - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] ".format( + QgsDistanceArea.formatDistance( + length_meter_mapunits, 7, da_wsg84.lengthUnits(), True + ), + point_meter_result.asWkt(), + ) + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + length_meter_mapunits, + 8, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + "0.00010379 deg", + ) + self.assertEqual( + point_meter_result.toString(7), point_wsg84_project.toString(7) + ) def testMeasureMultiLine(self): # +-+ +-+-+ @@ -554,13 +1194,25 @@ def testMeasureMultiLine(self): # +-+ + + +-+ linestring = QgsGeometry.fromMultiPolylineXY( [ - [QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 0), ], - [QgsPointXY(3, 0), QgsPointXY(3, 1), QgsPointXY(5, 1), QgsPointXY(5, 0), QgsPointXY(6, 0), ] + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 0), + ], + [ + QgsPointXY(3, 0), + QgsPointXY(3, 1), + QgsPointXY(5, 1), + QgsPointXY(5, 0), + QgsPointXY(6, 0), + ], ] ) da = QgsDistanceArea() length = da.measureLength(linestring) - myMessage = f'Expected:\n{9:f}\nGot:\n{length:f}\n' + myMessage = f"Expected:\n{9:f}\nGot:\n{length:f}\n" assert length == 9, myMessage def testMeasurePolygon(self): @@ -570,18 +1222,25 @@ def testMeasurePolygon(self): # | | # +-+ polygon = QgsGeometry.fromPolygonXY( - [[ - QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), - QgsPointXY(0, 2), QgsPointXY(0, 0), - ]] + [ + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 2), + QgsPointXY(0, 2), + QgsPointXY(0, 0), + ] + ] ) da = QgsDistanceArea() area = da.measureArea(polygon) - assert area == 3, f'Expected:\n{3:f}\nGot:\n{area:f}\n' + assert area == 3, f"Expected:\n{3:f}\nGot:\n{area:f}\n" perimeter = da.measurePerimeter(polygon) - assert perimeter == 8, f'Expected:\n{8:f}\nGot:\n{perimeter:f}\n' + assert perimeter == 8, f"Expected:\n{8:f}\nGot:\n{perimeter:f}\n" def testMeasurePolygonWithHole(self): # +-+-+-+ @@ -593,8 +1252,20 @@ def testMeasurePolygonWithHole(self): # +-+-+-+ polygon = QgsGeometry.fromPolygonXY( [ - [QgsPointXY(0, 0), QgsPointXY(3, 0), QgsPointXY(3, 3), QgsPointXY(0, 3), QgsPointXY(0, 0)], - [QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), QgsPointXY(1, 2), QgsPointXY(1, 1)], + [ + QgsPointXY(0, 0), + QgsPointXY(3, 0), + QgsPointXY(3, 3), + QgsPointXY(0, 3), + QgsPointXY(0, 0), + ], + [ + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 2), + QgsPointXY(1, 2), + QgsPointXY(1, 1), + ], ] ) da = QgsDistanceArea() @@ -613,22 +1284,40 @@ def testMeasureMultiPolygon(self): # +-+ +-+ polygon = QgsGeometry.fromMultiPolygonXY( [ - [[QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), - QgsPointXY(0, 2), QgsPointXY(0, 0), ]], - [[QgsPointXY(4, 0), QgsPointXY(5, 0), QgsPointXY(5, 2), QgsPointXY(3, 2), QgsPointXY(3, 1), - QgsPointXY(4, 1), QgsPointXY(4, 0), ]] + [ + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 2), + QgsPointXY(0, 2), + QgsPointXY(0, 0), + ] + ], + [ + [ + QgsPointXY(4, 0), + QgsPointXY(5, 0), + QgsPointXY(5, 2), + QgsPointXY(3, 2), + QgsPointXY(3, 1), + QgsPointXY(4, 1), + QgsPointXY(4, 0), + ] + ], ] ) da = QgsDistanceArea() area = da.measureArea(polygon) - assert area == 6, f'Expected:\n{6:f}\nGot:\n{area:f}\n' + assert area == 6, f"Expected:\n{6:f}\nGot:\n{area:f}\n" perimeter = da.measurePerimeter(polygon) assert perimeter == 16, f"Expected:\n{16:f}\nGot:\n{perimeter:f}\n" def testWillUseEllipsoid(self): - """test QgsDistanceArea::willUseEllipsoid """ + """test QgsDistanceArea::willUseEllipsoid""" da = QgsDistanceArea() da.setEllipsoid("NONE") @@ -639,11 +1328,14 @@ def testWillUseEllipsoid(self): def testLengthMeasureAndUnits(self): """Test a variety of length measurements in different CRS and ellipsoid modes, to check that the - calculated lengths and units are always consistent + calculated lengths and units are always consistent """ da = QgsDistanceArea() - da.setSourceCrs(QgsCoordinateReferenceSystem.fromSrsId(3452), QgsProject.instance().transformContext()) + da.setSourceCrs( + QgsCoordinateReferenceSystem.fromSrsId(3452), + QgsProject.instance().transformContext(), + ) da.setEllipsoid("NONE") # We check both the measured length AND the units, in case the logic regarding @@ -652,8 +1344,13 @@ def testLengthMeasureAndUnits(self): units = da.lengthUnits() print(f"measured {distance} in {QgsUnitTypes.toString(units)}") - assert ((abs(distance - 2.23606797) < 0.00000001 and units == QgsUnitTypes.DistanceUnit.DistanceDegrees) - or (abs(distance - 248.52) < 0.01 and units == QgsUnitTypes.DistanceUnit.DistanceMeters)) + assert ( + abs(distance - 2.23606797) < 0.00000001 + and units == QgsUnitTypes.DistanceUnit.DistanceDegrees + ) or ( + abs(distance - 248.52) < 0.01 + and units == QgsUnitTypes.DistanceUnit.DistanceMeters + ) da.setEllipsoid("WGS84") distance = da.measureLine(QgsPointXY(1, 1), QgsPointXY(2, 3)) @@ -665,11 +1362,16 @@ def testLengthMeasureAndUnits(self): self.assertEqual(units, QgsUnitTypes.DistanceUnit.DistanceMeters) # test converting the resultant length - distance = da.convertLengthMeasurement(distance, QgsUnitTypes.DistanceUnit.DistanceNauticalMiles) + distance = da.convertLengthMeasurement( + distance, QgsUnitTypes.DistanceUnit.DistanceNauticalMiles + ) self.assertAlmostEqual(distance, 133.669, delta=0.01) # now try with a source CRS which is in feet - da.setSourceCrs(QgsCoordinateReferenceSystem.fromSrsId(27469), QgsProject.instance().transformContext()) + da.setSourceCrs( + QgsCoordinateReferenceSystem.fromSrsId(27469), + QgsProject.instance().transformContext(), + ) da.setEllipsoid("NONE") # measurement should be in feet distance = da.measureLine(QgsPointXY(1, 1), QgsPointXY(2, 3)) @@ -679,7 +1381,9 @@ def testLengthMeasureAndUnits(self): self.assertEqual(units, Qgis.DistanceUnit.FeetUSSurvey) # test converting the resultant length - distance = da.convertLengthMeasurement(distance, QgsUnitTypes.DistanceUnit.DistanceMeters) + distance = da.convertLengthMeasurement( + distance, QgsUnitTypes.DistanceUnit.DistanceMeters + ) self.assertAlmostEqual(distance, 0.6815, delta=0.001) da.setEllipsoid("WGS84") @@ -691,23 +1395,35 @@ def testLengthMeasureAndUnits(self): self.assertEqual(units, QgsUnitTypes.DistanceUnit.DistanceMeters) # test converting the resultant length - distance = da.convertLengthMeasurement(distance, QgsUnitTypes.DistanceUnit.DistanceFeet) + distance = da.convertLengthMeasurement( + distance, QgsUnitTypes.DistanceUnit.DistanceFeet + ) self.assertAlmostEqual(distance, 2.2294, delta=0.001) def testAreaMeasureAndUnits(self): """Test a variety of area measurements in different CRS and ellipsoid modes, to check that the - calculated areas and units are always consistent + calculated areas and units are always consistent """ da = QgsDistanceArea() - da.setSourceCrs(QgsCoordinateReferenceSystem.fromSrsId(3452), QgsProject.instance().transformContext()) + da.setSourceCrs( + QgsCoordinateReferenceSystem.fromSrsId(3452), + QgsProject.instance().transformContext(), + ) da.setEllipsoid("NONE") polygon = QgsGeometry.fromPolygonXY( - [[ - QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), - QgsPointXY(0, 2), QgsPointXY(0, 0), - ]] + [ + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 2), + QgsPointXY(0, 2), + QgsPointXY(0, 0), + ] + ] ) # We check both the measured area AND the units, in case the logic regarding @@ -716,8 +1432,13 @@ def testAreaMeasureAndUnits(self): units = da.areaUnits() print(f"measured {area} in {QgsUnitTypes.toString(units)}") - assert ((abs(area - 3.0) < 0.00000001 and units == QgsUnitTypes.AreaUnit.AreaSquareDegrees) - or (abs(area - 37176087091.5) < 0.1 and units == QgsUnitTypes.AreaUnit.AreaSquareMeters)) + assert ( + abs(area - 3.0) < 0.00000001 + and units == QgsUnitTypes.AreaUnit.AreaSquareDegrees + ) or ( + abs(area - 37176087091.5) < 0.1 + and units == QgsUnitTypes.AreaUnit.AreaSquareMeters + ) da.setEllipsoid("WGS84") area = da.measureArea(polygon) @@ -734,13 +1455,22 @@ def testAreaMeasureAndUnits(self): # now try with a source CRS which is in feet polygon = QgsGeometry.fromPolygonXY( - [[ - QgsPointXY(1850000, 4423000), QgsPointXY(1851000, 4423000), QgsPointXY(1851000, 4424000), - QgsPointXY(1852000, 4424000), QgsPointXY(1852000, 4425000), QgsPointXY(1851000, 4425000), - QgsPointXY(1850000, 4423000) - ]] + [ + [ + QgsPointXY(1850000, 4423000), + QgsPointXY(1851000, 4423000), + QgsPointXY(1851000, 4424000), + QgsPointXY(1852000, 4424000), + QgsPointXY(1852000, 4425000), + QgsPointXY(1851000, 4425000), + QgsPointXY(1850000, 4423000), + ] + ] + ) + da.setSourceCrs( + QgsCoordinateReferenceSystem.fromSrsId(27469), + QgsProject.instance().transformContext(), ) - da.setSourceCrs(QgsCoordinateReferenceSystem.fromSrsId(27469), QgsProject.instance().transformContext()) da.setEllipsoid("NONE") # measurement should be in square feet area = da.measureArea(polygon) @@ -768,291 +1498,591 @@ def testAreaMeasureAndUnits(self): def testFormatDistance(self): """Test formatting distances""" QLocale.setDefault(QLocale.c()) - self.assertEqual(QgsDistanceArea.formatDistance(45, 3, QgsUnitTypes.DistanceUnit.DistanceMeters), '45.000 m') - self.assertEqual(QgsDistanceArea.formatDistance(1300, 1, QgsUnitTypes.DistanceUnit.DistanceMeters, False), '1.3 km') - self.assertEqual(QgsDistanceArea.formatDistance(.005, 1, QgsUnitTypes.DistanceUnit.DistanceMeters, False), '5.0 mm') - self.assertEqual(QgsDistanceArea.formatDistance(.05, 1, QgsUnitTypes.DistanceUnit.DistanceMeters, False), '5.0 cm') - self.assertEqual(QgsDistanceArea.formatDistance(1.5, 3, QgsUnitTypes.DistanceUnit.DistanceKilometers, True), '1.500 km') - self.assertEqual(QgsDistanceArea.formatDistance(1.5, 3, QgsUnitTypes.DistanceUnit.DistanceKilometers, False), '1.500 km') - self.assertEqual(QgsDistanceArea.formatDistance(0.5, 3, QgsUnitTypes.DistanceUnit.DistanceKilometers, True), '0.500 km') - self.assertEqual(QgsDistanceArea.formatDistance(0.5, 3, QgsUnitTypes.DistanceUnit.DistanceKilometers, False), '500.000 m') - self.assertEqual(QgsDistanceArea.formatDistance(6000, 0, QgsUnitTypes.DistanceUnit.DistanceFeet, True), '6000 ft') - self.assertEqual(QgsDistanceArea.formatDistance(6000, 3, QgsUnitTypes.DistanceUnit.DistanceFeet, False), '1.136 mi') - self.assertEqual(QgsDistanceArea.formatDistance(300, 0, QgsUnitTypes.DistanceUnit.DistanceFeet, True), '300 ft') - self.assertEqual(QgsDistanceArea.formatDistance(300, 0, QgsUnitTypes.DistanceUnit.DistanceFeet, False), '300 ft') - self.assertEqual(QgsDistanceArea.formatDistance(3000, 0, QgsUnitTypes.DistanceUnit.DistanceYards, True), '3000 yd') - self.assertEqual(QgsDistanceArea.formatDistance(3000, 3, QgsUnitTypes.DistanceUnit.DistanceYards, False), '1.705 mi') - self.assertEqual(QgsDistanceArea.formatDistance(300, 0, QgsUnitTypes.DistanceUnit.DistanceYards, True), '300 yd') - self.assertEqual(QgsDistanceArea.formatDistance(300, 0, QgsUnitTypes.DistanceUnit.DistanceYards, False), '300 yd') - self.assertEqual(QgsDistanceArea.formatDistance(1.5, 3, QgsUnitTypes.DistanceUnit.DistanceMiles, True), '1.500 mi') - self.assertEqual(QgsDistanceArea.formatDistance(1.5, 3, QgsUnitTypes.DistanceUnit.DistanceMiles, False), '1.500 mi') - self.assertEqual(QgsDistanceArea.formatDistance(0.5, 3, QgsUnitTypes.DistanceUnit.DistanceMiles, True), '0.500 mi') - self.assertEqual(QgsDistanceArea.formatDistance(0.5, 0, QgsUnitTypes.DistanceUnit.DistanceMiles, False), '2640 ft') - self.assertEqual(QgsDistanceArea.formatDistance(0.5, 1, QgsUnitTypes.DistanceUnit.DistanceNauticalMiles, True), '0.5 NM') - self.assertEqual(QgsDistanceArea.formatDistance(0.5, 1, QgsUnitTypes.DistanceUnit.DistanceNauticalMiles, False), '0.5 NM') - self.assertEqual(QgsDistanceArea.formatDistance(1.5, 1, QgsUnitTypes.DistanceUnit.DistanceNauticalMiles, True), '1.5 NM') - self.assertEqual(QgsDistanceArea.formatDistance(1.5, 1, QgsUnitTypes.DistanceUnit.DistanceNauticalMiles, False), '1.5 NM') - self.assertEqual(QgsDistanceArea.formatDistance(1.5, 1, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), '1.5 deg') - self.assertEqual(QgsDistanceArea.formatDistance(1.0, 1, QgsUnitTypes.DistanceUnit.DistanceDegrees, False), '1.0 deg') - self.assertEqual(QgsDistanceArea.formatDistance(1.0, 1, QgsUnitTypes.DistanceUnit.DistanceUnknownUnit, False), '1.0') + self.assertEqual( + QgsDistanceArea.formatDistance( + 45, 3, QgsUnitTypes.DistanceUnit.DistanceMeters + ), + "45.000 m", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 1300, 1, QgsUnitTypes.DistanceUnit.DistanceMeters, False + ), + "1.3 km", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 0.005, 1, QgsUnitTypes.DistanceUnit.DistanceMeters, False + ), + "5.0 mm", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 0.05, 1, QgsUnitTypes.DistanceUnit.DistanceMeters, False + ), + "5.0 cm", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 1.5, 3, QgsUnitTypes.DistanceUnit.DistanceKilometers, True + ), + "1.500 km", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 1.5, 3, QgsUnitTypes.DistanceUnit.DistanceKilometers, False + ), + "1.500 km", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 0.5, 3, QgsUnitTypes.DistanceUnit.DistanceKilometers, True + ), + "0.500 km", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 0.5, 3, QgsUnitTypes.DistanceUnit.DistanceKilometers, False + ), + "500.000 m", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 6000, 0, QgsUnitTypes.DistanceUnit.DistanceFeet, True + ), + "6000 ft", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 6000, 3, QgsUnitTypes.DistanceUnit.DistanceFeet, False + ), + "1.136 mi", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 300, 0, QgsUnitTypes.DistanceUnit.DistanceFeet, True + ), + "300 ft", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 300, 0, QgsUnitTypes.DistanceUnit.DistanceFeet, False + ), + "300 ft", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 3000, 0, QgsUnitTypes.DistanceUnit.DistanceYards, True + ), + "3000 yd", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 3000, 3, QgsUnitTypes.DistanceUnit.DistanceYards, False + ), + "1.705 mi", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 300, 0, QgsUnitTypes.DistanceUnit.DistanceYards, True + ), + "300 yd", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 300, 0, QgsUnitTypes.DistanceUnit.DistanceYards, False + ), + "300 yd", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 1.5, 3, QgsUnitTypes.DistanceUnit.DistanceMiles, True + ), + "1.500 mi", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 1.5, 3, QgsUnitTypes.DistanceUnit.DistanceMiles, False + ), + "1.500 mi", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 0.5, 3, QgsUnitTypes.DistanceUnit.DistanceMiles, True + ), + "0.500 mi", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 0.5, 0, QgsUnitTypes.DistanceUnit.DistanceMiles, False + ), + "2640 ft", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 0.5, 1, QgsUnitTypes.DistanceUnit.DistanceNauticalMiles, True + ), + "0.5 NM", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 0.5, 1, QgsUnitTypes.DistanceUnit.DistanceNauticalMiles, False + ), + "0.5 NM", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 1.5, 1, QgsUnitTypes.DistanceUnit.DistanceNauticalMiles, True + ), + "1.5 NM", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 1.5, 1, QgsUnitTypes.DistanceUnit.DistanceNauticalMiles, False + ), + "1.5 NM", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 1.5, 1, QgsUnitTypes.DistanceUnit.DistanceDegrees, True + ), + "1.5 deg", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 1.0, 1, QgsUnitTypes.DistanceUnit.DistanceDegrees, False + ), + "1.0 deg", + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + 1.0, 1, QgsUnitTypes.DistanceUnit.DistanceUnknownUnit, False + ), + "1.0", + ) QLocale.setDefault(QLocale.system()) def testGeodesicIntersectionAtAntimeridian(self): da = QgsDistanceArea() - crs = QgsCoordinateReferenceSystem('EPSG:4326') + crs = QgsCoordinateReferenceSystem("EPSG:4326") da.setSourceCrs(crs, QgsProject.instance().transformContext()) da.setEllipsoid("WGS84") - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(0, 0), QgsPointXY(-170, 0)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(0, 0), QgsPointXY(-170, 0) + ) self.assertAlmostEqual(lat, 0, 5) self.assertAlmostEqual(fract, 0, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(-170, 0), QgsPointXY(170, 0)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(-170, 0), QgsPointXY(170, 0) + ) self.assertAlmostEqual(lat, 0, 5) self.assertAlmostEqual(fract, 0.5, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(179, 0), QgsPointXY(181, 0)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(179, 0), QgsPointXY(181, 0) + ) self.assertAlmostEqual(lat, 0, 5) self.assertAlmostEqual(fract, 0.5, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(-170, 0), QgsPointXY(170, 0)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(-170, 0), QgsPointXY(170, 0) + ) self.assertAlmostEqual(lat, 0, 5) self.assertAlmostEqual(fract, 0.5, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(180, 0), QgsPointXY(180, 0)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(180, 0), QgsPointXY(180, 0) + ) self.assertAlmostEqual(lat, 0, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(180, -10), QgsPointXY(180, -10)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(180, -10), QgsPointXY(180, -10) + ) self.assertAlmostEqual(lat, -10, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(171, 0), QgsPointXY(181, 0)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(171, 0), QgsPointXY(181, 0) + ) self.assertAlmostEqual(lat, 0, 5) self.assertAlmostEqual(fract, 0.9, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(181, 0), QgsPointXY(171, 0)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(181, 0), QgsPointXY(171, 0) + ) self.assertAlmostEqual(lat, 0, 5) self.assertAlmostEqual(fract, 0.1, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(138.26237, -20.314687), - QgsPointXY(-151.6, -77.8)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(138.26237, -20.314687), QgsPointXY(-151.6, -77.8) + ) self.assertAlmostEqual(lat, -73.89148222666744914, 5) self.assertAlmostEqual(fract, 0.007113545719515548, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(138.26237, -20.314687), - QgsPointXY(-151.6 + 360, -77.8)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(138.26237, -20.314687), QgsPointXY(-151.6 + 360, -77.8) + ) self.assertAlmostEqual(lat, -73.89148222666744914, 5) self.assertAlmostEqual(fract, 0.007113545719515548, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(-151.6, -77.8), - QgsPointXY(138.26237, -20.314687)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(-151.6, -77.8), QgsPointXY(138.26237, -20.314687) + ) self.assertAlmostEqual(lat, -73.89148222666744914, 5) self.assertAlmostEqual(fract, 0.9928864542804845, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(170.60188754234980024, -70.81368329001529105), - QgsPointXY(-164.61259948055175073, -76.66761193248410677)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(170.60188754234980024, -70.81368329001529105), + QgsPointXY(-164.61259948055175073, -76.66761193248410677), + ) self.assertAlmostEqual(lat, -73.89148222666744914, 5) self.assertAlmostEqual(fract, 0.0879577697523441, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(-164.61259948055175073, -76.66761193248410677), - QgsPointXY(170.60188754234980024, - -70.81368329001529105)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(-164.61259948055175073, -76.66761193248410677), + QgsPointXY(170.60188754234980024, -70.81368329001529105), + ) self.assertAlmostEqual(lat, -73.89148222666744914, 5) self.assertAlmostEqual(fract, 0.9120422302476558, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(178.44469761238570982, -73.47820480021761114), - QgsPointXY(-179.21026002627399976, -74.08952948682963324)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(178.44469761238570982, -73.47820480021761114), + QgsPointXY(-179.21026002627399976, -74.08952948682963324), + ) self.assertAlmostEqual(lat, -73.89148222666744914, 5) self.assertAlmostEqual(fract, 0.6713541474159178, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(-179.21026002627399976, -74.08952948682963324), - QgsPointXY(178.44469761238570982, - -73.47820480021761114)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(-179.21026002627399976, -74.08952948682963324), + QgsPointXY(178.44469761238570982, -73.47820480021761114), + ) self.assertAlmostEqual(lat, -73.89148222666744914, 5) self.assertAlmostEqual(fract, 0.3286458525840822, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(179.83103440731269984, -73.8481044794813215), - QgsPointXY(-179.93191793815378787, -73.90885909527753483)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(179.83103440731269984, -73.8481044794813215), + QgsPointXY(-179.93191793815378787, -73.90885909527753483), + ) self.assertAlmostEqual(lat, -73.89148222666744914, 5) self.assertAlmostEqual(fract, 0.7135414998986486, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(-179.93191793815378787, -73.90885909527753483), - QgsPointXY(179.83103440731269984, -73.8481044794813215)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(-179.93191793815378787, -73.90885909527753483), + QgsPointXY(179.83103440731269984, -73.8481044794813215), + ) self.assertAlmostEqual(lat, -73.89148222666744914, 5) self.assertAlmostEqual(fract, 0.28645850010135143, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(179.92498611649580198, 7.24703528617311754), - QgsPointXY(-178.20070563806575592, 16.09649962419504732)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(179.92498611649580198, 7.24703528617311754), + QgsPointXY(-178.20070563806575592, 16.09649962419504732), + ) self.assertAlmostEqual(lat, 7.6112109902580265, 5) self.assertAlmostEqual(fract, 0.04111771567489498, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(-178.20070563806575592, 16.09649962419504732), - QgsPointXY(179.92498611649580198, 7.24703528617311754)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(-178.20070563806575592, 16.09649962419504732), + QgsPointXY(179.92498611649580198, 7.24703528617311754), + ) self.assertAlmostEqual(lat, 7.6112109902580265, 5) self.assertAlmostEqual(fract, 0.958882284325105, 5) lat, fract = da.latitudeGeodesicCrossesAntimeridian( QgsPointXY(360 - 178.20070563806575592, 16.09649962419504732), - QgsPointXY(179.92498611649580198, 7.24703528617311754)) + QgsPointXY(179.92498611649580198, 7.24703528617311754), + ) self.assertAlmostEqual(lat, 7.6112109902580265, 5) self.assertAlmostEqual(fract, 0.95888228432510, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(175.76717768974583578, 8.93749416467257873), - QgsPointXY(-175.15030911497356669, 8.59851183021221033)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(175.76717768974583578, 8.93749416467257873), + QgsPointXY(-175.15030911497356669, 8.59851183021221033), + ) self.assertAlmostEqual(lat, 8.80683758146703966, 5) self.assertAlmostEqual(fract, 0.46581637044475815, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(-175.15030911497356669, 8.59851183021221033), - QgsPointXY(175.76717768974583578, - 8.93749416467257873)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(-175.15030911497356669, 8.59851183021221033), + QgsPointXY(175.76717768974583578, 8.93749416467257873), + ) self.assertAlmostEqual(lat, 8.80683758146703966, 5) self.assertAlmostEqual(fract, 0.5341836295552418, 5) # calculation should be ellipsoid dependent! - da.setEllipsoid('PARAMETER:6370997:6370997') - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(-175.15030911497356669, 8.59851183021221033), - QgsPointXY(175.76717768974583578, - 8.93749416467257873)) + da.setEllipsoid("PARAMETER:6370997:6370997") + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(-175.15030911497356669, 8.59851183021221033), + QgsPointXY(175.76717768974583578, 8.93749416467257873), + ) self.assertAlmostEqual(lat, 8.806658717133244, 5) self.assertAlmostEqual(fract, 0.5341851152000393, 5) # no ellipsoid da.setEllipsoid("NONE") - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(-175, 8), - QgsPointXY(175, - 9)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(-175, 8), QgsPointXY(175, 9) + ) self.assertAlmostEqual(lat, 8.5, 5) self.assertAlmostEqual(fract, 0.5, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(165, 8), - QgsPointXY(-175, - 9)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(165, 8), QgsPointXY(-175, 9) + ) self.assertAlmostEqual(lat, 8.75, 5) self.assertAlmostEqual(fract, 0.75, 5) - lat, fract = da.latitudeGeodesicCrossesAntimeridian(QgsPointXY(-175, 8), - QgsPointXY(165, - 9)) + lat, fract = da.latitudeGeodesicCrossesAntimeridian( + QgsPointXY(-175, 8), QgsPointXY(165, 9) + ) self.assertAlmostEqual(lat, 8.25, 5) self.assertAlmostEqual(fract, 0.25, 5) def testGeodesicLine(self): da = QgsDistanceArea() - crs = QgsCoordinateReferenceSystem('EPSG:4326') + crs = QgsCoordinateReferenceSystem("EPSG:4326") da.setSourceCrs(crs, QgsProject.instance().transformContext()) da.setEllipsoid("WGS84") - g = QgsGeometry.fromMultiPolylineXY(da.geodesicLine(QgsPointXY(105.4, 66.4), QgsPointXY(208.4, -77.8), - 1000000, True)) - self.assertEqual(g.asWkt(5), - 'MultiLineString ((105.4 66.4, 114.11119 58.36882, 119.52376 49.95732, 123.30625 41.35664, 126.19835 32.6479, 128.57411 23.87234, 130.647 15.05482, 132.55465 6.21309, 134.39916 -2.63822, 136.27014 -11.48549, 138.26237 -20.31469, 140.4956 -29.10966, 143.14591 -37.84912, 146.5073 -46.50015, 151.13295 -55.00229, 158.2045 -63.2234, 170.60189 -70.81368, 180 -73.89148),(-180 -73.89148, -164.6126 -76.66761, -151.6 -77.8))') - g = QgsGeometry.fromMultiPolylineXY(da.geodesicLine(QgsPointXY(105.4, 66.4), QgsPointXY(208.4, -77.8), - 1000000, False)) - self.assertEqual(g.asWkt(5), - 'MultiLineString ((105.4 66.4, 114.11119 58.36882, 119.52376 49.95732, 123.30625 41.35664, 126.19835 32.6479, 128.57411 23.87234, 130.647 15.05482, 132.55465 6.21309, 134.39916 -2.63822, 136.27014 -11.48549, 138.26237 -20.31469, 140.4956 -29.10966, 143.14591 -37.84912, 146.5073 -46.50015, 151.13295 -55.00229, 158.2045 -63.2234, 170.60189 -70.81368, -164.6126 -76.66761, -151.6 -77.8))') - g = QgsGeometry.fromMultiPolylineXY(da.geodesicLine(QgsPointXY(105.4, 66.4), QgsPointXY(208.4, -77.8), - 100000, True)) - self.assertEqual(g.asWkt(5), - 'MultiLineString ((105.4 66.4, 106.50684 65.62452, 107.54925 64.84137, 108.53251 64.05125, 109.46143 63.25477, 110.34036 62.45245, 111.17326 61.6448, 111.96369 60.83224, 112.7149 60.01516, 113.42984 59.19392, 114.11119 58.36882, 114.76141 57.54016, 115.38271 56.70818, 115.97713 55.87314, 116.54653 55.03522, 117.09261 54.19464, 117.61695 53.35156, 118.12096 52.50615, 118.60597 51.65855, 119.0732 50.8089, 119.52376 49.95732, 119.95868 49.10392, 120.37892 48.24881, 120.78537 47.39209, 121.17884 46.53385, 121.5601 45.67416, 121.92984 44.81311, 122.28874 43.95077, 122.6374 43.08721, 122.97639 42.22247, 123.30625 41.35664, 123.62747 40.48975, 123.94053 39.62186, 124.24585 38.75302, 124.54386 37.88326, 124.83494 37.01265, 125.11945 36.14121, 125.39773 35.26898, 125.67011 34.39599, 125.93688 33.52229, 126.19835 32.6479, 126.45477 31.77286, 126.7064 30.89719, 126.9535 30.02092, 127.19628 29.14407, 127.43498 28.26668, 127.66979 27.38877, 127.90093 26.51035, 128.12857 25.63146, 128.35291 24.75212, 128.57411 23.87234, 128.79234 22.99214, 129.00775 22.11156, 129.22051 21.23059, 129.43076 20.34927, 129.63863 19.46761, 129.84427 18.58563, 130.0478 17.70334, 130.24935 16.82077, 130.44904 15.93792, 130.647 15.05482, 130.84333 14.17148, 131.03815 13.28792, 131.23156 12.40414, 131.42367 11.52017, 131.61458 10.63603, 131.8044 9.75171, 131.99322 8.86725, 132.18114 7.98265, 132.36825 7.09792, 132.55465 6.21309, 132.74043 5.32816, 132.92567 4.44315, 133.11048 3.55808, 133.29493 2.67295, 133.47912 1.78778, 133.66313 0.90258, 133.84706 0.01736, 134.03098 -0.86785, 134.21498 -1.75305, 134.39916 -2.63822, 134.5836 -3.52335, 134.76839 -4.40843, 134.95362 -5.29344, 135.13937 -6.17837, 135.32575 -7.06321, 135.51283 -7.94794, 135.70071 -8.83255, 135.8895 -9.71702, 136.07928 -10.60134, 136.27014 -11.48549, 136.46221 -12.36947, 136.65557 -13.25325, 136.85033 -14.13682, 137.04659 -15.02017, 137.24448 -15.90328, 137.44411 -16.78614, 137.64558 -17.66872, 137.84904 -18.55102, 138.05459 -19.43301, 138.26237 -20.31469, 138.47252 -21.19602, 138.68518 -22.077, 138.90049 -22.9576, 139.1186 -23.83781, 139.33968 -24.71761, 139.56389 -25.59697, 139.7914 -26.47588, 140.0224 -27.35431, 140.25706 -28.23225, 140.4956 -29.10966, 140.73822 -29.98653, 140.98515 -30.86282, 141.2366 -31.73851, 141.49283 -32.61358, 141.75409 -33.488, 142.02065 -34.36173, 142.2928 -35.23474, 142.57084 -36.107, 142.8551 -36.97847, 143.14591 -37.84912, 143.44364 -38.71891, 143.74868 -39.58779, 144.06142 -40.45572, 144.38232 -41.32265, 144.71183 -42.18852, 145.05045 -43.0533, 145.39872 -43.91692, 145.7572 -44.77931, 146.12651 -45.64041, 146.5073 -46.50015, 146.90028 -47.35845, 147.3062 -48.21523, 147.72589 -49.0704, 148.16022 -49.92387, 148.61014 -50.77552, 149.0767 -51.62525, 149.56099 -52.47294, 150.06423 -53.31844, 150.58774 -54.16161, 151.13295 -55.00229, 151.7014 -55.84031, 152.29481 -56.67548, 152.91501 -57.50758, 153.56405 -58.33637, 154.24414 -59.16162, 154.95771 -59.98302, 155.70745 -60.80027, 156.49628 -61.61301, 157.32744 -62.42086, 158.2045 -63.2234, 159.13138 -64.02012, 160.11242 -64.8105, 161.15241 -65.59393, 162.25662 -66.36973, 163.43088 -67.13713, 164.68163 -67.89527, 166.01595 -68.64317, 167.44162 -69.37973, 168.96717 -70.10371, 170.60189 -70.81368, 172.35586 -71.50806, 174.2399 -72.18501, 176.26551 -72.8425, 178.4447 -73.4782, 180 -73.89148),(-180 -73.89148, -179.21026 -74.08953, -176.68721 -74.67356, -173.97467 -75.22708, -171.06257 -75.74654, -167.94325 -76.22808, -164.6126 -76.66761, -161.07142 -77.06086, -157.32679 -77.40349, -153.39333 -77.69129, -151.6 -77.8))') - g = QgsGeometry.fromMultiPolylineXY(da.geodesicLine(QgsPointXY(105.4, 66.4), QgsPointXY(208.4, -77.8), - 100000, False)) - self.assertEqual(g.asWkt(5), - 'MultiLineString ((105.4 66.4, 106.50684 65.62452, 107.54925 64.84137, 108.53251 64.05125, 109.46143 63.25477, 110.34036 62.45245, 111.17326 61.6448, 111.96369 60.83224, 112.7149 60.01516, 113.42984 59.19392, 114.11119 58.36882, 114.76141 57.54016, 115.38271 56.70818, 115.97713 55.87314, 116.54653 55.03522, 117.09261 54.19464, 117.61695 53.35156, 118.12096 52.50615, 118.60597 51.65855, 119.0732 50.8089, 119.52376 49.95732, 119.95868 49.10392, 120.37892 48.24881, 120.78537 47.39209, 121.17884 46.53385, 121.5601 45.67416, 121.92984 44.81311, 122.28874 43.95077, 122.6374 43.08721, 122.97639 42.22247, 123.30625 41.35664, 123.62747 40.48975, 123.94053 39.62186, 124.24585 38.75302, 124.54386 37.88326, 124.83494 37.01265, 125.11945 36.14121, 125.39773 35.26898, 125.67011 34.39599, 125.93688 33.52229, 126.19835 32.6479, 126.45477 31.77286, 126.7064 30.89719, 126.9535 30.02092, 127.19628 29.14407, 127.43498 28.26668, 127.66979 27.38877, 127.90093 26.51035, 128.12857 25.63146, 128.35291 24.75212, 128.57411 23.87234, 128.79234 22.99214, 129.00775 22.11156, 129.22051 21.23059, 129.43076 20.34927, 129.63863 19.46761, 129.84427 18.58563, 130.0478 17.70334, 130.24935 16.82077, 130.44904 15.93792, 130.647 15.05482, 130.84333 14.17148, 131.03815 13.28792, 131.23156 12.40414, 131.42367 11.52017, 131.61458 10.63603, 131.8044 9.75171, 131.99322 8.86725, 132.18114 7.98265, 132.36825 7.09792, 132.55465 6.21309, 132.74043 5.32816, 132.92567 4.44315, 133.11048 3.55808, 133.29493 2.67295, 133.47912 1.78778, 133.66313 0.90258, 133.84706 0.01736, 134.03098 -0.86785, 134.21498 -1.75305, 134.39916 -2.63822, 134.5836 -3.52335, 134.76839 -4.40843, 134.95362 -5.29344, 135.13937 -6.17837, 135.32575 -7.06321, 135.51283 -7.94794, 135.70071 -8.83255, 135.8895 -9.71702, 136.07928 -10.60134, 136.27014 -11.48549, 136.46221 -12.36947, 136.65557 -13.25325, 136.85033 -14.13682, 137.04659 -15.02017, 137.24448 -15.90328, 137.44411 -16.78614, 137.64558 -17.66872, 137.84904 -18.55102, 138.05459 -19.43301, 138.26237 -20.31469, 138.47252 -21.19602, 138.68518 -22.077, 138.90049 -22.9576, 139.1186 -23.83781, 139.33968 -24.71761, 139.56389 -25.59697, 139.7914 -26.47588, 140.0224 -27.35431, 140.25706 -28.23225, 140.4956 -29.10966, 140.73822 -29.98653, 140.98515 -30.86282, 141.2366 -31.73851, 141.49283 -32.61358, 141.75409 -33.488, 142.02065 -34.36173, 142.2928 -35.23474, 142.57084 -36.107, 142.8551 -36.97847, 143.14591 -37.84912, 143.44364 -38.71891, 143.74868 -39.58779, 144.06142 -40.45572, 144.38232 -41.32265, 144.71183 -42.18852, 145.05045 -43.0533, 145.39872 -43.91692, 145.7572 -44.77931, 146.12651 -45.64041, 146.5073 -46.50015, 146.90028 -47.35845, 147.3062 -48.21523, 147.72589 -49.0704, 148.16022 -49.92387, 148.61014 -50.77552, 149.0767 -51.62525, 149.56099 -52.47294, 150.06423 -53.31844, 150.58774 -54.16161, 151.13295 -55.00229, 151.7014 -55.84031, 152.29481 -56.67548, 152.91501 -57.50758, 153.56405 -58.33637, 154.24414 -59.16162, 154.95771 -59.98302, 155.70745 -60.80027, 156.49628 -61.61301, 157.32744 -62.42086, 158.2045 -63.2234, 159.13138 -64.02012, 160.11242 -64.8105, 161.15241 -65.59393, 162.25662 -66.36973, 163.43088 -67.13713, 164.68163 -67.89527, 166.01595 -68.64317, 167.44162 -69.37973, 168.96717 -70.10371, 170.60189 -70.81368, 172.35586 -71.50806, 174.2399 -72.18501, 176.26551 -72.8425, 178.4447 -73.4782, -179.21026 -74.08953, -176.68721 -74.67356, -173.97467 -75.22708, -171.06257 -75.74654, -167.94325 -76.22808, -164.6126 -76.66761, -161.07142 -77.06086, -157.32679 -77.40349, -153.39333 -77.69129, -151.6 -77.8))') - - g = QgsGeometry.fromMultiPolylineXY(da.geodesicLine(QgsPointXY(121.4, -76.4), QgsPointXY(-121.6, 76.8), - 1000000, True)) - self.assertEqual(g.asWkt(5), - 'MultiLineString ((121.4 -76.4, 144.24671 -70.15471, 155.62067 -62.40689, 162.18341 -54.11007, 166.52394 -45.56426, 169.70696 -36.88448, 172.23571 -28.12423, 174.38053 -19.31324, 176.30526 -10.47118, 178.12301 -1.61326, 179.92499 7.24704, 180 7.61121),(-180 7.61121, -178.20071 16.0965, -176.15151 24.92076, -173.78654 33.70222, -170.88367 42.4158, -167.0472 51.01916, -161.47936 59.42708, -152.33578 67.43298, -134.83075 74.42214, -121.6 76.8))') - g = QgsGeometry.fromMultiPolylineXY(da.geodesicLine(QgsPointXY(121.4, -76.4), QgsPointXY(-121.6, 76.8), - 1000000, False)) - self.assertEqual(g.asWkt(5), - 'MultiLineString ((121.4 -76.4, 144.24671 -70.15471, 155.62067 -62.40689, 162.18341 -54.11007, 166.52394 -45.56426, 169.70696 -36.88448, 172.23571 -28.12423, 174.38053 -19.31324, 176.30526 -10.47118, 178.12301 -1.61326, 179.92499 7.24704, -178.20071 16.0965, -176.15151 24.92076, -173.78654 33.70222, -170.88367 42.4158, -167.0472 51.01916, -161.47936 59.42708, -152.33578 67.43298, -134.83075 74.42214, -121.6 76.8))') - g = QgsGeometry.fromMultiPolylineXY(da.geodesicLine(QgsPointXY(121.4, 6.4), QgsPointXY(-121.6, 2.8), - 1000000, True)) - self.assertEqual(g.asWkt(5), - 'MultiLineString ((121.4 6.4, 130.40033 7.32484, 139.43407 8.06935, 148.49637 8.61432, 157.57946 8.9455, 166.67342 9.05419, 175.76718 8.93749, 180 8.80684),(-180 8.80684, -175.15031 8.59851, -166.08891 8.04617, -157.05629 7.29488, -148.0572 6.36403, -139.09301 5.2773, -130.16168 4.06195, -121.6 2.8))') - g = QgsGeometry.fromMultiPolylineXY(da.geodesicLine(QgsPointXY(121.4, 6.4), QgsPointXY(-121.6, 2.8), - 1000000, False)) - self.assertEqual(g.asWkt(5), - 'MultiLineString ((121.4 6.4, 130.40033 7.32484, 139.43407 8.06935, 148.49637 8.61432, 157.57946 8.9455, 166.67342 9.05419, 175.76718 8.93749, -175.15031 8.59851, -166.08891 8.04617, -157.05629 7.29488, -148.0572 6.36403, -139.09301 5.2773, -130.16168 4.06195, -121.6 2.8))') + g = QgsGeometry.fromMultiPolylineXY( + da.geodesicLine( + QgsPointXY(105.4, 66.4), QgsPointXY(208.4, -77.8), 1000000, True + ) + ) + self.assertEqual( + g.asWkt(5), + "MultiLineString ((105.4 66.4, 114.11119 58.36882, 119.52376 49.95732, 123.30625 41.35664, 126.19835 32.6479, 128.57411 23.87234, 130.647 15.05482, 132.55465 6.21309, 134.39916 -2.63822, 136.27014 -11.48549, 138.26237 -20.31469, 140.4956 -29.10966, 143.14591 -37.84912, 146.5073 -46.50015, 151.13295 -55.00229, 158.2045 -63.2234, 170.60189 -70.81368, 180 -73.89148),(-180 -73.89148, -164.6126 -76.66761, -151.6 -77.8))", + ) + g = QgsGeometry.fromMultiPolylineXY( + da.geodesicLine( + QgsPointXY(105.4, 66.4), QgsPointXY(208.4, -77.8), 1000000, False + ) + ) + self.assertEqual( + g.asWkt(5), + "MultiLineString ((105.4 66.4, 114.11119 58.36882, 119.52376 49.95732, 123.30625 41.35664, 126.19835 32.6479, 128.57411 23.87234, 130.647 15.05482, 132.55465 6.21309, 134.39916 -2.63822, 136.27014 -11.48549, 138.26237 -20.31469, 140.4956 -29.10966, 143.14591 -37.84912, 146.5073 -46.50015, 151.13295 -55.00229, 158.2045 -63.2234, 170.60189 -70.81368, -164.6126 -76.66761, -151.6 -77.8))", + ) + g = QgsGeometry.fromMultiPolylineXY( + da.geodesicLine( + QgsPointXY(105.4, 66.4), QgsPointXY(208.4, -77.8), 100000, True + ) + ) + self.assertEqual( + g.asWkt(5), + "MultiLineString ((105.4 66.4, 106.50684 65.62452, 107.54925 64.84137, 108.53251 64.05125, 109.46143 63.25477, 110.34036 62.45245, 111.17326 61.6448, 111.96369 60.83224, 112.7149 60.01516, 113.42984 59.19392, 114.11119 58.36882, 114.76141 57.54016, 115.38271 56.70818, 115.97713 55.87314, 116.54653 55.03522, 117.09261 54.19464, 117.61695 53.35156, 118.12096 52.50615, 118.60597 51.65855, 119.0732 50.8089, 119.52376 49.95732, 119.95868 49.10392, 120.37892 48.24881, 120.78537 47.39209, 121.17884 46.53385, 121.5601 45.67416, 121.92984 44.81311, 122.28874 43.95077, 122.6374 43.08721, 122.97639 42.22247, 123.30625 41.35664, 123.62747 40.48975, 123.94053 39.62186, 124.24585 38.75302, 124.54386 37.88326, 124.83494 37.01265, 125.11945 36.14121, 125.39773 35.26898, 125.67011 34.39599, 125.93688 33.52229, 126.19835 32.6479, 126.45477 31.77286, 126.7064 30.89719, 126.9535 30.02092, 127.19628 29.14407, 127.43498 28.26668, 127.66979 27.38877, 127.90093 26.51035, 128.12857 25.63146, 128.35291 24.75212, 128.57411 23.87234, 128.79234 22.99214, 129.00775 22.11156, 129.22051 21.23059, 129.43076 20.34927, 129.63863 19.46761, 129.84427 18.58563, 130.0478 17.70334, 130.24935 16.82077, 130.44904 15.93792, 130.647 15.05482, 130.84333 14.17148, 131.03815 13.28792, 131.23156 12.40414, 131.42367 11.52017, 131.61458 10.63603, 131.8044 9.75171, 131.99322 8.86725, 132.18114 7.98265, 132.36825 7.09792, 132.55465 6.21309, 132.74043 5.32816, 132.92567 4.44315, 133.11048 3.55808, 133.29493 2.67295, 133.47912 1.78778, 133.66313 0.90258, 133.84706 0.01736, 134.03098 -0.86785, 134.21498 -1.75305, 134.39916 -2.63822, 134.5836 -3.52335, 134.76839 -4.40843, 134.95362 -5.29344, 135.13937 -6.17837, 135.32575 -7.06321, 135.51283 -7.94794, 135.70071 -8.83255, 135.8895 -9.71702, 136.07928 -10.60134, 136.27014 -11.48549, 136.46221 -12.36947, 136.65557 -13.25325, 136.85033 -14.13682, 137.04659 -15.02017, 137.24448 -15.90328, 137.44411 -16.78614, 137.64558 -17.66872, 137.84904 -18.55102, 138.05459 -19.43301, 138.26237 -20.31469, 138.47252 -21.19602, 138.68518 -22.077, 138.90049 -22.9576, 139.1186 -23.83781, 139.33968 -24.71761, 139.56389 -25.59697, 139.7914 -26.47588, 140.0224 -27.35431, 140.25706 -28.23225, 140.4956 -29.10966, 140.73822 -29.98653, 140.98515 -30.86282, 141.2366 -31.73851, 141.49283 -32.61358, 141.75409 -33.488, 142.02065 -34.36173, 142.2928 -35.23474, 142.57084 -36.107, 142.8551 -36.97847, 143.14591 -37.84912, 143.44364 -38.71891, 143.74868 -39.58779, 144.06142 -40.45572, 144.38232 -41.32265, 144.71183 -42.18852, 145.05045 -43.0533, 145.39872 -43.91692, 145.7572 -44.77931, 146.12651 -45.64041, 146.5073 -46.50015, 146.90028 -47.35845, 147.3062 -48.21523, 147.72589 -49.0704, 148.16022 -49.92387, 148.61014 -50.77552, 149.0767 -51.62525, 149.56099 -52.47294, 150.06423 -53.31844, 150.58774 -54.16161, 151.13295 -55.00229, 151.7014 -55.84031, 152.29481 -56.67548, 152.91501 -57.50758, 153.56405 -58.33637, 154.24414 -59.16162, 154.95771 -59.98302, 155.70745 -60.80027, 156.49628 -61.61301, 157.32744 -62.42086, 158.2045 -63.2234, 159.13138 -64.02012, 160.11242 -64.8105, 161.15241 -65.59393, 162.25662 -66.36973, 163.43088 -67.13713, 164.68163 -67.89527, 166.01595 -68.64317, 167.44162 -69.37973, 168.96717 -70.10371, 170.60189 -70.81368, 172.35586 -71.50806, 174.2399 -72.18501, 176.26551 -72.8425, 178.4447 -73.4782, 180 -73.89148),(-180 -73.89148, -179.21026 -74.08953, -176.68721 -74.67356, -173.97467 -75.22708, -171.06257 -75.74654, -167.94325 -76.22808, -164.6126 -76.66761, -161.07142 -77.06086, -157.32679 -77.40349, -153.39333 -77.69129, -151.6 -77.8))", + ) + g = QgsGeometry.fromMultiPolylineXY( + da.geodesicLine( + QgsPointXY(105.4, 66.4), QgsPointXY(208.4, -77.8), 100000, False + ) + ) + self.assertEqual( + g.asWkt(5), + "MultiLineString ((105.4 66.4, 106.50684 65.62452, 107.54925 64.84137, 108.53251 64.05125, 109.46143 63.25477, 110.34036 62.45245, 111.17326 61.6448, 111.96369 60.83224, 112.7149 60.01516, 113.42984 59.19392, 114.11119 58.36882, 114.76141 57.54016, 115.38271 56.70818, 115.97713 55.87314, 116.54653 55.03522, 117.09261 54.19464, 117.61695 53.35156, 118.12096 52.50615, 118.60597 51.65855, 119.0732 50.8089, 119.52376 49.95732, 119.95868 49.10392, 120.37892 48.24881, 120.78537 47.39209, 121.17884 46.53385, 121.5601 45.67416, 121.92984 44.81311, 122.28874 43.95077, 122.6374 43.08721, 122.97639 42.22247, 123.30625 41.35664, 123.62747 40.48975, 123.94053 39.62186, 124.24585 38.75302, 124.54386 37.88326, 124.83494 37.01265, 125.11945 36.14121, 125.39773 35.26898, 125.67011 34.39599, 125.93688 33.52229, 126.19835 32.6479, 126.45477 31.77286, 126.7064 30.89719, 126.9535 30.02092, 127.19628 29.14407, 127.43498 28.26668, 127.66979 27.38877, 127.90093 26.51035, 128.12857 25.63146, 128.35291 24.75212, 128.57411 23.87234, 128.79234 22.99214, 129.00775 22.11156, 129.22051 21.23059, 129.43076 20.34927, 129.63863 19.46761, 129.84427 18.58563, 130.0478 17.70334, 130.24935 16.82077, 130.44904 15.93792, 130.647 15.05482, 130.84333 14.17148, 131.03815 13.28792, 131.23156 12.40414, 131.42367 11.52017, 131.61458 10.63603, 131.8044 9.75171, 131.99322 8.86725, 132.18114 7.98265, 132.36825 7.09792, 132.55465 6.21309, 132.74043 5.32816, 132.92567 4.44315, 133.11048 3.55808, 133.29493 2.67295, 133.47912 1.78778, 133.66313 0.90258, 133.84706 0.01736, 134.03098 -0.86785, 134.21498 -1.75305, 134.39916 -2.63822, 134.5836 -3.52335, 134.76839 -4.40843, 134.95362 -5.29344, 135.13937 -6.17837, 135.32575 -7.06321, 135.51283 -7.94794, 135.70071 -8.83255, 135.8895 -9.71702, 136.07928 -10.60134, 136.27014 -11.48549, 136.46221 -12.36947, 136.65557 -13.25325, 136.85033 -14.13682, 137.04659 -15.02017, 137.24448 -15.90328, 137.44411 -16.78614, 137.64558 -17.66872, 137.84904 -18.55102, 138.05459 -19.43301, 138.26237 -20.31469, 138.47252 -21.19602, 138.68518 -22.077, 138.90049 -22.9576, 139.1186 -23.83781, 139.33968 -24.71761, 139.56389 -25.59697, 139.7914 -26.47588, 140.0224 -27.35431, 140.25706 -28.23225, 140.4956 -29.10966, 140.73822 -29.98653, 140.98515 -30.86282, 141.2366 -31.73851, 141.49283 -32.61358, 141.75409 -33.488, 142.02065 -34.36173, 142.2928 -35.23474, 142.57084 -36.107, 142.8551 -36.97847, 143.14591 -37.84912, 143.44364 -38.71891, 143.74868 -39.58779, 144.06142 -40.45572, 144.38232 -41.32265, 144.71183 -42.18852, 145.05045 -43.0533, 145.39872 -43.91692, 145.7572 -44.77931, 146.12651 -45.64041, 146.5073 -46.50015, 146.90028 -47.35845, 147.3062 -48.21523, 147.72589 -49.0704, 148.16022 -49.92387, 148.61014 -50.77552, 149.0767 -51.62525, 149.56099 -52.47294, 150.06423 -53.31844, 150.58774 -54.16161, 151.13295 -55.00229, 151.7014 -55.84031, 152.29481 -56.67548, 152.91501 -57.50758, 153.56405 -58.33637, 154.24414 -59.16162, 154.95771 -59.98302, 155.70745 -60.80027, 156.49628 -61.61301, 157.32744 -62.42086, 158.2045 -63.2234, 159.13138 -64.02012, 160.11242 -64.8105, 161.15241 -65.59393, 162.25662 -66.36973, 163.43088 -67.13713, 164.68163 -67.89527, 166.01595 -68.64317, 167.44162 -69.37973, 168.96717 -70.10371, 170.60189 -70.81368, 172.35586 -71.50806, 174.2399 -72.18501, 176.26551 -72.8425, 178.4447 -73.4782, -179.21026 -74.08953, -176.68721 -74.67356, -173.97467 -75.22708, -171.06257 -75.74654, -167.94325 -76.22808, -164.6126 -76.66761, -161.07142 -77.06086, -157.32679 -77.40349, -153.39333 -77.69129, -151.6 -77.8))", + ) + + g = QgsGeometry.fromMultiPolylineXY( + da.geodesicLine( + QgsPointXY(121.4, -76.4), QgsPointXY(-121.6, 76.8), 1000000, True + ) + ) + self.assertEqual( + g.asWkt(5), + "MultiLineString ((121.4 -76.4, 144.24671 -70.15471, 155.62067 -62.40689, 162.18341 -54.11007, 166.52394 -45.56426, 169.70696 -36.88448, 172.23571 -28.12423, 174.38053 -19.31324, 176.30526 -10.47118, 178.12301 -1.61326, 179.92499 7.24704, 180 7.61121),(-180 7.61121, -178.20071 16.0965, -176.15151 24.92076, -173.78654 33.70222, -170.88367 42.4158, -167.0472 51.01916, -161.47936 59.42708, -152.33578 67.43298, -134.83075 74.42214, -121.6 76.8))", + ) + g = QgsGeometry.fromMultiPolylineXY( + da.geodesicLine( + QgsPointXY(121.4, -76.4), QgsPointXY(-121.6, 76.8), 1000000, False + ) + ) + self.assertEqual( + g.asWkt(5), + "MultiLineString ((121.4 -76.4, 144.24671 -70.15471, 155.62067 -62.40689, 162.18341 -54.11007, 166.52394 -45.56426, 169.70696 -36.88448, 172.23571 -28.12423, 174.38053 -19.31324, 176.30526 -10.47118, 178.12301 -1.61326, 179.92499 7.24704, -178.20071 16.0965, -176.15151 24.92076, -173.78654 33.70222, -170.88367 42.4158, -167.0472 51.01916, -161.47936 59.42708, -152.33578 67.43298, -134.83075 74.42214, -121.6 76.8))", + ) + g = QgsGeometry.fromMultiPolylineXY( + da.geodesicLine( + QgsPointXY(121.4, 6.4), QgsPointXY(-121.6, 2.8), 1000000, True + ) + ) + self.assertEqual( + g.asWkt(5), + "MultiLineString ((121.4 6.4, 130.40033 7.32484, 139.43407 8.06935, 148.49637 8.61432, 157.57946 8.9455, 166.67342 9.05419, 175.76718 8.93749, 180 8.80684),(-180 8.80684, -175.15031 8.59851, -166.08891 8.04617, -157.05629 7.29488, -148.0572 6.36403, -139.09301 5.2773, -130.16168 4.06195, -121.6 2.8))", + ) + g = QgsGeometry.fromMultiPolylineXY( + da.geodesicLine( + QgsPointXY(121.4, 6.4), QgsPointXY(-121.6, 2.8), 1000000, False + ) + ) + self.assertEqual( + g.asWkt(5), + "MultiLineString ((121.4 6.4, 130.40033 7.32484, 139.43407 8.06935, 148.49637 8.61432, 157.57946 8.9455, 166.67342 9.05419, 175.76718 8.93749, -175.15031 8.59851, -166.08891 8.04617, -157.05629 7.29488, -148.0572 6.36403, -139.09301 5.2773, -130.16168 4.06195, -121.6 2.8))", + ) # different ellipsoid, should be respected - da.setEllipsoid('PARAMETER:6370997:6370997') - g = QgsGeometry.fromMultiPolylineXY(da.geodesicLine(QgsPointXY(121.4, 6.4), QgsPointXY(-121.6, 2.8), - 1000000, False)) - self.assertEqual(g.asWkt(5), - 'MultiLineString ((121.4 6.4, 130.41144 7.31297, 139.45604 8.04667, 148.52889 8.58224, 157.62221 8.90571, 166.72609 9.0086, 175.82954 8.88819, -175.07842 8.54766, -166.00754 7.99595, -156.96541 7.24741, -147.95669 6.32128, -138.98271 5.24103, -130.04141 4.03364, -121.6 2.8))') + da.setEllipsoid("PARAMETER:6370997:6370997") + g = QgsGeometry.fromMultiPolylineXY( + da.geodesicLine( + QgsPointXY(121.4, 6.4), QgsPointXY(-121.6, 2.8), 1000000, False + ) + ) + self.assertEqual( + g.asWkt(5), + "MultiLineString ((121.4 6.4, 130.41144 7.31297, 139.45604 8.04667, 148.52889 8.58224, 157.62221 8.90571, 166.72609 9.0086, 175.82954 8.88819, -175.07842 8.54766, -166.00754 7.99595, -156.96541 7.24741, -147.95669 6.32128, -138.98271 5.24103, -130.04141 4.03364, -121.6 2.8))", + ) da.setEllipsoid("WGS84") # with reprojection - da.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:3857'), QgsProject.instance().transformContext()) + da.setSourceCrs( + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsProject.instance().transformContext(), + ) g = QgsGeometry.fromMultiPolylineXY( - da.geodesicLine(QgsPointXY(-13536427, 14138932), QgsPointXY(13760912, -13248201), - 1000000, False)) - self.assertEqual(g.asWkt(0), - 'MultiLineString ((-13536427 14138932, -16514348 11691516, -17948849 9406595, -18744235 7552985, -19255354 6014890, -19622372 4688888, -19909239 3505045, 19925702 2415579, 19712755 1385803, 19513769 388441, 19318507 -600065, 19117459 -1602293, 18899973 -2642347, 18651869 -3748726, 18351356 -4958346, 17960498 -6322823, 17404561 -7918366, 16514601 -9855937, 14851845 -12232940, 13760912 -13248201))') + da.geodesicLine( + QgsPointXY(-13536427, 14138932), + QgsPointXY(13760912, -13248201), + 1000000, + False, + ) + ) + self.assertEqual( + g.asWkt(0), + "MultiLineString ((-13536427 14138932, -16514348 11691516, -17948849 9406595, -18744235 7552985, -19255354 6014890, -19622372 4688888, -19909239 3505045, 19925702 2415579, 19712755 1385803, 19513769 388441, 19318507 -600065, 19117459 -1602293, 18899973 -2642347, 18651869 -3748726, 18351356 -4958346, 17960498 -6322823, 17404561 -7918366, 16514601 -9855937, 14851845 -12232940, 13760912 -13248201))", + ) g = QgsGeometry.fromMultiPolylineXY( - da.geodesicLine(QgsPointXY(-13536427, 14138932), QgsPointXY(13760912, -13248201), - 1000000, True)) - self.assertEqual(g.asWkt(0), - 'MultiLineString ((-13536427 14138932, -16514348 11691516, -17948849 9406595, -18744235 7552985, -19255354 6014890, -19622372 4688888, -19909239 3505045, -20037508 2933522),(20037508 2933522, 19925702 2415579, 19712755 1385803, 19513769 388441, 19318507 -600065, 19117459 -1602293, 18899973 -2642347, 18651869 -3748726, 18351356 -4958346, 17960498 -6322823, 17404561 -7918366, 16514601 -9855937, 14851845 -12232940, 13760912 -13248201))') + da.geodesicLine( + QgsPointXY(-13536427, 14138932), + QgsPointXY(13760912, -13248201), + 1000000, + True, + ) + ) + self.assertEqual( + g.asWkt(0), + "MultiLineString ((-13536427 14138932, -16514348 11691516, -17948849 9406595, -18744235 7552985, -19255354 6014890, -19622372 4688888, -19909239 3505045, -20037508 2933522),(20037508 2933522, 19925702 2415579, 19712755 1385803, 19513769 388441, 19318507 -600065, 19117459 -1602293, 18899973 -2642347, 18651869 -3748726, 18351356 -4958346, 17960498 -6322823, 17404561 -7918366, 16514601 -9855937, 14851845 -12232940, 13760912 -13248201))", + ) g = QgsGeometry.fromMultiPolylineXY( - da.geodesicLine(QgsPointXY(18933544, -5448034), QgsPointXY(-11638480, 3962206), - 1000000, True)) - self.assertEqual(g.asWkt(0), - 'MultiLineString ((18933544 -5448034, 20037508 -4772933),(-20037508 -4772933, -20002064 -4748323, -19015781 -3988451, -18153035 -3204936, -17383137 -2416816, -16678635 -1632067, -16015884 -852355, -15374147 -76043, -14734258 699941, -14077193 1478790, -13382634 2262546, -12627598 3050380, -11785404 3835868, -11638480 3962206))') + da.geodesicLine( + QgsPointXY(18933544, -5448034), + QgsPointXY(-11638480, 3962206), + 1000000, + True, + ) + ) + self.assertEqual( + g.asWkt(0), + "MultiLineString ((18933544 -5448034, 20037508 -4772933),(-20037508 -4772933, -20002064 -4748323, -19015781 -3988451, -18153035 -3204936, -17383137 -2416816, -16678635 -1632067, -16015884 -852355, -15374147 -76043, -14734258 699941, -14077193 1478790, -13382634 2262546, -12627598 3050380, -11785404 3835868, -11638480 3962206))", + ) def testSplitGeometryAtAntimeridian(self): da = QgsDistanceArea() - crs = QgsCoordinateReferenceSystem('EPSG:4326') + crs = QgsCoordinateReferenceSystem("EPSG:4326") da.setSourceCrs(crs, QgsProject.instance().transformContext()) da.setEllipsoid("WGS84") # noops g = da.splitGeometryAtAntimeridian(QgsGeometry()) self.assertTrue(g.isNull()) - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('Point(1 2)')) - self.assertEqual(g.asWkt(), 'Point (1 2)') - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('MultiPoint(1 2, 3 4)')) - self.assertEqual(g.asWkt(), 'MultiPoint ((1 2),(3 4))') - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('PointZ(1 2 3)')) - self.assertEqual(g.asWkt(), 'Point Z (1 2 3)') - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('PointM(1 2 3)')) - self.assertEqual(g.asWkt(), 'Point M (1 2 3)') - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('LineString EMPTY')) - self.assertEqual(g.asWkt(), 'MultiLineString EMPTY') + g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt("Point(1 2)")) + self.assertEqual(g.asWkt(), "Point (1 2)") + g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt("MultiPoint(1 2, 3 4)")) + self.assertEqual(g.asWkt(), "MultiPoint ((1 2),(3 4))") + g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt("PointZ(1 2 3)")) + self.assertEqual(g.asWkt(), "Point Z (1 2 3)") + g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt("PointM(1 2 3)")) + self.assertEqual(g.asWkt(), "Point M (1 2 3)") + g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt("LineString EMPTY")) + self.assertEqual(g.asWkt(), "MultiLineString EMPTY") # lines - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('LineString(0 0, -170 0)')) - self.assertEqual(g.asWkt(), 'MultiLineString ((0 0, -170 0))') - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('LineString(-170 0, 0 0)')) - self.assertEqual(g.asWkt(), 'MultiLineString ((-170 0, 0 0))') - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('LineString(179 0, -179 0)')) - self.assertEqual(g.asWkt(), 'MultiLineString ((179 0, 180 0),(-180 0, -179 0))') - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('LineString(179 0, 181 0)')) - self.assertEqual(g.asWkt(), 'MultiLineString ((179 0, 180 0),(-180 0, -179 0))') - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('LineString(-179 0, 179 0)')) - self.assertEqual(g.asWkt(), 'MultiLineString ((-179 0, -180 0),(180 0, 179 0))') - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('LineString(181 0, 179 0)')) - self.assertEqual(g.asWkt(), 'MultiLineString ((-179 0, -180 0),(180 0, 179 0))') - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('LineString(179 10, -179 -20)')) - self.assertEqual(g.asWkt(3), 'MultiLineString ((179 10, 180 -5.362),(-180 -5.362, -179 -20))') - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('LineString(179 -80, -179 70)')) - self.assertEqual(g.asWkt(3), 'MultiLineString ((179 -80, 180 -55.685),(-180 -55.685, -179 70))') + g = da.splitGeometryAtAntimeridian( + QgsGeometry.fromWkt("LineString(0 0, -170 0)") + ) + self.assertEqual(g.asWkt(), "MultiLineString ((0 0, -170 0))") + g = da.splitGeometryAtAntimeridian( + QgsGeometry.fromWkt("LineString(-170 0, 0 0)") + ) + self.assertEqual(g.asWkt(), "MultiLineString ((-170 0, 0 0))") + g = da.splitGeometryAtAntimeridian( + QgsGeometry.fromWkt("LineString(179 0, -179 0)") + ) + self.assertEqual(g.asWkt(), "MultiLineString ((179 0, 180 0),(-180 0, -179 0))") + g = da.splitGeometryAtAntimeridian( + QgsGeometry.fromWkt("LineString(179 0, 181 0)") + ) + self.assertEqual(g.asWkt(), "MultiLineString ((179 0, 180 0),(-180 0, -179 0))") + g = da.splitGeometryAtAntimeridian( + QgsGeometry.fromWkt("LineString(-179 0, 179 0)") + ) + self.assertEqual(g.asWkt(), "MultiLineString ((-179 0, -180 0),(180 0, 179 0))") + g = da.splitGeometryAtAntimeridian( + QgsGeometry.fromWkt("LineString(181 0, 179 0)") + ) + self.assertEqual(g.asWkt(), "MultiLineString ((-179 0, -180 0),(180 0, 179 0))") + g = da.splitGeometryAtAntimeridian( + QgsGeometry.fromWkt("LineString(179 10, -179 -20)") + ) + self.assertEqual( + g.asWkt(3), "MultiLineString ((179 10, 180 -5.362),(-180 -5.362, -179 -20))" + ) + g = da.splitGeometryAtAntimeridian( + QgsGeometry.fromWkt("LineString(179 -80, -179 70)") + ) + self.assertEqual( + g.asWkt(3), + "MultiLineString ((179 -80, 180 -55.685),(-180 -55.685, -179 70))", + ) # multiline input - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('MultiLineString((1 10, 50 30),(179 -80, -179 70))')) - self.assertEqual(g.asWkt(3), 'MultiLineString ((1 10, 50 30),(179 -80, 180 -55.685),(-180 -55.685, -179 70))') - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('MultiLineString((1 10, 50 30),(179 -80, 179.99 70))')) - self.assertEqual(g.asWkt(3), 'MultiLineString ((1 10, 50 30),(179 -80, 179.99 70))') + g = da.splitGeometryAtAntimeridian( + QgsGeometry.fromWkt("MultiLineString((1 10, 50 30),(179 -80, -179 70))") + ) + self.assertEqual( + g.asWkt(3), + "MultiLineString ((1 10, 50 30),(179 -80, 180 -55.685),(-180 -55.685, -179 70))", + ) + g = da.splitGeometryAtAntimeridian( + QgsGeometry.fromWkt("MultiLineString((1 10, 50 30),(179 -80, 179.99 70))") + ) + self.assertEqual( + g.asWkt(3), "MultiLineString ((1 10, 50 30),(179 -80, 179.99 70))" + ) # with z/m - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('LineString Z(179 -80 1, -179 70 10)')) - self.assertEqual(g.asWkt(3), - 'MultiLineString Z ((179 -80 1, 180 -55.685 2.466),(-180 -55.685 2.466, -179 70 10))') - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('LineStringM(179 -80 1, -179 70 10)')) - self.assertEqual(g.asWkt(3), - 'MultiLineString M ((179 -80 1, 180 -55.685 2.466),(-180 -55.685 2.466, -179 70 10))') - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('LineStringZM(179 -80 1 -4, -179 70 10 -30)')) - self.assertEqual(g.asWkt(3), - 'MultiLineString ZM ((179 -80 1 -4, 180 -55.685 2.466 -8.234),(-180 -55.685 2.466 -8.234, -179 70 10 -30))') g = da.splitGeometryAtAntimeridian( - QgsGeometry.fromWkt('MultiLineString Z((179 -80 1, -179 70 10),(-170 -5 1, -181 10 5))')) - self.assertEqual(g.asWkt(3), - 'MultiLineString Z ((179 -80 1, 180 -55.685 2.466),(-180 -55.685 2.466, -179 70 10),(-170 -5 1, -181 10 5))') + QgsGeometry.fromWkt("LineString Z(179 -80 1, -179 70 10)") + ) + self.assertEqual( + g.asWkt(3), + "MultiLineString Z ((179 -80 1, 180 -55.685 2.466),(-180 -55.685 2.466, -179 70 10))", + ) + g = da.splitGeometryAtAntimeridian( + QgsGeometry.fromWkt("LineStringM(179 -80 1, -179 70 10)") + ) + self.assertEqual( + g.asWkt(3), + "MultiLineString M ((179 -80 1, 180 -55.685 2.466),(-180 -55.685 2.466, -179 70 10))", + ) + g = da.splitGeometryAtAntimeridian( + QgsGeometry.fromWkt("LineStringZM(179 -80 1 -4, -179 70 10 -30)") + ) + self.assertEqual( + g.asWkt(3), + "MultiLineString ZM ((179 -80 1 -4, 180 -55.685 2.466 -8.234),(-180 -55.685 2.466 -8.234, -179 70 10 -30))", + ) + g = da.splitGeometryAtAntimeridian( + QgsGeometry.fromWkt( + "MultiLineString Z((179 -80 1, -179 70 10),(-170 -5 1, -181 10 5))" + ) + ) + self.assertEqual( + g.asWkt(3), + "MultiLineString Z ((179 -80 1, 180 -55.685 2.466),(-180 -55.685 2.466, -179 70 10),(-170 -5 1, -181 10 5))", + ) # different ellipsoid - should change intersection latitude - da.setEllipsoid('PARAMETER:6370997:6370997') - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('LineString(179 10, -179 -20)')) - self.assertEqual(g.asWkt(3), 'MultiLineString ((179 10, 180 -5.361),(-180 -5.361, -179 -20))') + da.setEllipsoid("PARAMETER:6370997:6370997") + g = da.splitGeometryAtAntimeridian( + QgsGeometry.fromWkt("LineString(179 10, -179 -20)") + ) + self.assertEqual( + g.asWkt(3), "MultiLineString ((179 10, 180 -5.361),(-180 -5.361, -179 -20))" + ) # with reprojection da.setEllipsoid("WGS84") # with reprojection - da.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:3857'), QgsProject.instance().transformContext()) + da.setSourceCrs( + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsProject.instance().transformContext(), + ) - g = da.splitGeometryAtAntimeridian(QgsGeometry.fromWkt('LineString( -13536427 14138932, 13760912 -13248201)')) - self.assertEqual(g.asWkt(1), - 'MultiLineString ((-13536427 14138932, -20037508.3 2933521.7),(20037508.3 2933521.7, 13760912 -13248201))') + g = da.splitGeometryAtAntimeridian( + QgsGeometry.fromWkt("LineString( -13536427 14138932, 13760912 -13248201)") + ) + self.assertEqual( + g.asWkt(1), + "MultiLineString ((-13536427 14138932, -20037508.3 2933521.7),(20037508.3 2933521.7, 13760912 -13248201))", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgseditformconfig.py b/tests/src/python/test_qgseditformconfig.py index 46cf2d4a9933..8396b84256a7 100644 --- a/tests/src/python/test_qgseditformconfig.py +++ b/tests/src/python/test_qgseditformconfig.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '11/04/2017' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "11/04/2017" +__copyright__ = "Copyright 2018, The QGIS Project" import http.server import os @@ -46,10 +47,10 @@ def setUpClass(cls): QgsSettings().clear() # Bring up a simple HTTP server - os.chdir(unitTestDataPath() + '') + os.chdir(unitTestDataPath() + "") handler = http.server.SimpleHTTPRequestHandler - cls.httpd = socketserver.TCPServer(('localhost', 0), handler) + cls.httpd = socketserver.TCPServer(("localhost", 0), handler) cls.port = cls.httpd.server_address[1] cls.httpd_thread = threading.Thread(target=cls.httpd.serve_forever) @@ -57,8 +58,9 @@ def setUpClass(cls): cls.httpd_thread.start() def createLayer(self): - self.layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + self.layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) f = QgsFeature() pr = self.layer.dataProvider() assert pr.addFeatures([f]) @@ -76,7 +78,7 @@ def testReadWriteXml(self): config.setReuseLastValue(1, True) doc = QDomDocument("testdoc") - elem = doc.createElement('edit') + elem = doc.createElement("edit") config.writeXml(elem, QgsReadWriteContext()) layer2 = self.createLayer() @@ -95,24 +97,37 @@ def testFormUi(self): config = layer.editFormConfig() config.setLayout(QgsEditFormConfig.EditorLayout.GeneratedLayout) - self.assertEqual(config.layout(), QgsEditFormConfig.EditorLayout.GeneratedLayout) + self.assertEqual( + config.layout(), QgsEditFormConfig.EditorLayout.GeneratedLayout + ) uiLocal = os.path.join( - unitTestDataPath(), '/qgis_local_server/layer_attribute_form.ui') + unitTestDataPath(), "/qgis_local_server/layer_attribute_form.ui" + ) config.setUiForm(uiLocal) self.assertEqual(config.layout(), QgsEditFormConfig.EditorLayout.UiFileLayout) config.setLayout(QgsEditFormConfig.EditorLayout.GeneratedLayout) - self.assertEqual(config.layout(), QgsEditFormConfig.EditorLayout.GeneratedLayout) - - uiUrl = 'http://localhost:' + \ - str(self.port) + '/qgis_local_server/layer_attribute_form.ui' + self.assertEqual( + config.layout(), QgsEditFormConfig.EditorLayout.GeneratedLayout + ) + + uiUrl = ( + "http://localhost:" + + str(self.port) + + "/qgis_local_server/layer_attribute_form.ui" + ) config.setUiForm(uiUrl) self.assertEqual(config.layout(), QgsEditFormConfig.EditorLayout.UiFileLayout) - content = QgsApplication.networkContentFetcherRegistry().fetch(uiUrl, QgsNetworkContentFetcherRegistry.FetchingMode.DownloadImmediately) + content = QgsApplication.networkContentFetcherRegistry().fetch( + uiUrl, QgsNetworkContentFetcherRegistry.FetchingMode.DownloadImmediately + ) self.assertTrue(content is not None) while True: - if content.status() in (QgsFetchedContent.ContentStatus.Finished, QgsFetchedContent.ContentStatus.Failed): + if content.status() in ( + QgsFetchedContent.ContentStatus.Finished, + QgsFetchedContent.ContentStatus.Failed, + ): break app.processEvents() self.assertEqual(content.status(), QgsFetchedContent.ContentStatus.Finished) @@ -214,13 +229,17 @@ def test_backgroundColorSerialize(self): """Test backgroundColor serialization""" layer = self.createLayer() - color_name = '#ff00ff' - container = QgsAttributeEditorContainer('container name', None, QColor('#ff00ff')) + color_name = "#ff00ff" + container = QgsAttributeEditorContainer( + "container name", None, QColor("#ff00ff") + ) doc = QDomDocument() element = container.toDomElement(doc) - container2 = QgsAttributeEditorElement.create(element, self.layer.id(), layer.fields(), QgsReadWriteContext(), None) + container2 = QgsAttributeEditorElement.create( + element, self.layer.id(), layer.fields(), QgsReadWriteContext(), None + ) self.assertEqual(container2.backgroundColor().name(), color_name) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgseditwidgets.py b/tests/src/python/test_qgseditwidgets.py index a7b835fb9867..bad5a54c7ae7 100644 --- a/tests/src/python/test_qgseditwidgets.py +++ b/tests/src/python/test_qgseditwidgets.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Matthias Kuhn' -__date__ = '20/05/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Matthias Kuhn" +__date__ = "20/05/2015" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.PyQt.QtCore import QVariant from qgis.PyQt.QtWidgets import QTextEdit @@ -35,8 +36,9 @@ def setUpClass(cls): QgsGui.editorWidgetRegistry().initEditors() def createLayerWithOnePoint(self): - self.layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + self.layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) pr = self.layer.dataProvider() f = QgsFeature() f.setAttributes(["test", 123]) @@ -47,11 +49,11 @@ def createLayerWithOnePoint(self): def doAttributeTest(self, idx, expected): reg = QgsGui.editorWidgetRegistry() - configWdg = reg.createConfigWidget('TextEdit', self.layer, idx, None) + configWdg = reg.createConfigWidget("TextEdit", self.layer, idx, None) config = configWdg.config() - editwidget = reg.create('TextEdit', self.layer, idx, config, None, None) + editwidget = reg.create("TextEdit", self.layer, idx, config, None, None) - editwidget.setValues('value', []) + editwidget.setValues("value", []) self.assertEqual(editwidget.value(), expected[0]) editwidget.setValues(123, []) @@ -63,39 +65,43 @@ def doAttributeTest(self, idx, expected): editwidget.setValues(NULL, []) self.assertEqual(editwidget.value(), expected[3]) - editwidget.setValues(float('nan'), []) + editwidget.setValues(float("nan"), []) self.assertEqual(editwidget.value(), expected[4]) def test_SetValue(self): self.createLayerWithOnePoint() - self.doAttributeTest(0, ['value', '123', NULL, NULL, NULL]) + self.doAttributeTest(0, ["value", "123", NULL, NULL, NULL]) self.doAttributeTest(1, [NULL, 123, NULL, NULL, NULL]) def testStringWithMaxLen(self): - """ tests that text edit wrappers correctly handle string fields with a maximum length """ + """tests that text edit wrappers correctly handle string fields with a maximum length""" layer = QgsVectorLayer("none?field=fldint:integer", "layer", "memory") self.assertTrue(layer.isValid()) - layer.dataProvider().addAttributes([QgsField('max', QVariant.String, 'string', 10), - QgsField('nomax', QVariant.String, 'string', 0)]) + layer.dataProvider().addAttributes( + [ + QgsField("max", QVariant.String, "string", 10), + QgsField("nomax", QVariant.String, "string", 0), + ] + ) layer.updateFields() QgsProject.instance().addMapLayer(layer) reg = QgsGui.editorWidgetRegistry() - config = {'IsMultiline': 'True'} + config = {"IsMultiline": "True"} # first test for field without character limit editor = QTextEdit() - editor.setPlainText('this_is_a_long_string') - w = reg.create('TextEdit', layer, 2, config, editor, None) - self.assertEqual(w.value(), 'this_is_a_long_string') + editor.setPlainText("this_is_a_long_string") + w = reg.create("TextEdit", layer, 2, config, editor, None) + self.assertEqual(w.value(), "this_is_a_long_string") # next test for field with character limit editor = QTextEdit() - editor.setPlainText('this_is_a_long_string') - w = reg.create('TextEdit', layer, 1, config, editor, None) + editor.setPlainText("this_is_a_long_string") + w = reg.create("TextEdit", layer, 1, config, editor, None) - self.assertEqual(w.value(), 'this_is_a_') + self.assertEqual(w.value(), "this_is_a_") QgsProject.instance().removeAllMapLayers() @@ -105,12 +111,12 @@ def test_indeterminate_state(self): """ layer = QgsVectorLayer("none?field=fld:string", "layer", "memory") reg = QgsGui.editorWidgetRegistry() - configWdg = reg.createConfigWidget('TextEdit', layer, 0, None) + configWdg = reg.createConfigWidget("TextEdit", layer, 0, None) config = configWdg.config() - editwidget = reg.create('TextEdit', layer, 0, config, None, None) + editwidget = reg.create("TextEdit", layer, 0, config, None, None) - editwidget.setValues('value', []) - self.assertEqual(editwidget.value(), 'value') + editwidget.setValues("value", []) + self.assertEqual(editwidget.value(), "value") editwidget.showIndeterminateState() self.assertFalse(editwidget.value()) self.assertFalse(editwidget.widget().toPlainText()) @@ -121,7 +127,7 @@ class TestQgsValueRelationWidget(QgisTestCase): def test_enableDisable(self): reg = QgsGui.editorWidgetRegistry() layer = QgsVectorLayer("none?field=number:integer", "layer", "memory") - wrapper = reg.create('ValueRelation', layer, 0, {}, None, None) + wrapper = reg.create("ValueRelation", layer, 0, {}, None, None) widget = wrapper.widget() @@ -136,32 +142,41 @@ def test_value_relation_set_value_not_in_map(self): Test that setting a value not in the map is correctly handled """ layer = QgsVectorLayer("none?field=text:string", "layer", "memory") - layer2 = QgsVectorLayer("none?field=code:string&field=value:string", "layer", "memory") + layer2 = QgsVectorLayer( + "none?field=code:string&field=value:string", "layer", "memory" + ) f = QgsFeature(layer2.fields()) - f.setAttributes(['a', 'AAA']) + f.setAttributes(["a", "AAA"]) layer2.dataProvider().addFeature(f) - f.setAttributes(['b', 'BBB']) + f.setAttributes(["b", "BBB"]) layer2.dataProvider().addFeature(f) QgsProject.instance().addMapLayer(layer) QgsProject.instance().addMapLayer(layer2) - config = {'Layer': layer2.id(), 'Key': 'code', 'Value': 'value', 'AllowNull': False} - wrapper = QgsGui.editorWidgetRegistry().create('ValueRelation', layer, 0, config, None, None) + config = { + "Layer": layer2.id(), + "Key": "code", + "Value": "value", + "AllowNull": False, + } + wrapper = QgsGui.editorWidgetRegistry().create( + "ValueRelation", layer, 0, config, None, None + ) widget = wrapper.widget() - wrapper.setValues('a', []) - self.assertEqual(wrapper.value(), 'a') - self.assertEqual(widget.currentText(), 'AAA') + wrapper.setValues("a", []) + self.assertEqual(wrapper.value(), "a") + self.assertEqual(widget.currentText(), "AAA") - wrapper.setValues('b', []) - self.assertEqual(wrapper.value(), 'b') - self.assertEqual(widget.currentText(), 'BBB') + wrapper.setValues("b", []) + self.assertEqual(wrapper.value(), "b") + self.assertEqual(widget.currentText(), "BBB") # set to value NOT in the layer, but this should not be lost - wrapper.setValues('c', []) - self.assertEqual(wrapper.value(), 'c') - self.assertEqual(widget.currentText(), '(c)') + wrapper.setValues("c", []) + self.assertEqual(wrapper.value(), "c") + self.assertEqual(widget.currentText(), "(c)") wrapper.setValues(NULL, []) self.assertEqual(wrapper.value(), NULL) @@ -174,37 +189,46 @@ def test_value_relation_set_value_not_in_map_with_null(self): Test that setting a value not in the map is correctly handled when null is allowed """ layer = QgsVectorLayer("none?field=text:string", "layer", "memory") - layer2 = QgsVectorLayer("none?field=code:string&field=value:string", "layer", "memory") + layer2 = QgsVectorLayer( + "none?field=code:string&field=value:string", "layer", "memory" + ) f = QgsFeature(layer2.fields()) - f.setAttributes(['a', 'AAA']) + f.setAttributes(["a", "AAA"]) layer2.dataProvider().addFeature(f) - f.setAttributes(['b', 'BBB']) + f.setAttributes(["b", "BBB"]) layer2.dataProvider().addFeature(f) QgsProject.instance().addMapLayer(layer) QgsProject.instance().addMapLayer(layer2) - config = {'Layer': layer2.id(), 'Key': 'code', 'Value': 'value', 'AllowNull': True} - wrapper = QgsGui.editorWidgetRegistry().create('ValueRelation', layer, 0, config, None, None) + config = { + "Layer": layer2.id(), + "Key": "code", + "Value": "value", + "AllowNull": True, + } + wrapper = QgsGui.editorWidgetRegistry().create( + "ValueRelation", layer, 0, config, None, None + ) widget = wrapper.widget() - wrapper.setValues('a', []) - self.assertEqual(wrapper.value(), 'a') - self.assertEqual(widget.currentText(), 'AAA') + wrapper.setValues("a", []) + self.assertEqual(wrapper.value(), "a") + self.assertEqual(widget.currentText(), "AAA") - wrapper.setValues('b', []) - self.assertEqual(wrapper.value(), 'b') - self.assertEqual(widget.currentText(), 'BBB') + wrapper.setValues("b", []) + self.assertEqual(wrapper.value(), "b") + self.assertEqual(widget.currentText(), "BBB") # set to value NOT in the map, should not be lost - wrapper.setValues('c', []) - self.assertEqual(wrapper.value(), 'c') - self.assertEqual(widget.currentText(), '(c)') + wrapper.setValues("c", []) + self.assertEqual(wrapper.value(), "c") + self.assertEqual(widget.currentText(), "(c)") # set to value NOT in the map, should not be lost wrapper.setValues(NULL, []) self.assertEqual(wrapper.value(), NULL) - self.assertEqual(widget.currentText(), '(no selection)') + self.assertEqual(widget.currentText(), "(no selection)") QgsProject.instance().removeAllMapLayers() @@ -217,9 +241,16 @@ def test_ValueMap_set_get(self): self.assertTrue(layer.isValid()) QgsProject.instance().addMapLayer(layer) reg = QgsGui.editorWidgetRegistry() - configWdg = reg.createConfigWidget('ValueMap', layer, 0, None) + configWdg = reg.createConfigWidget("ValueMap", layer, 0, None) - config = {'map': [{'two': '2'}, {'twoandhalf': '2.5'}, {'NULL text': 'NULL'}, {'nothing': self.VALUEMAP_NULL_TEXT}]} + config = { + "map": [ + {"two": "2"}, + {"twoandhalf": "2.5"}, + {"NULL text": "NULL"}, + {"nothing": self.VALUEMAP_NULL_TEXT}, + ] + } # Set a configuration containing values and NULL and check if it # is returned intact. @@ -236,26 +267,28 @@ def test_value_map_set_value_not_in_map(self): self.assertTrue(layer.isValid()) QgsProject.instance().addMapLayer(layer) - config = {'map': [{'AAAAA': 'a'}, {'BBBB': 'b'}]} - wrapper = QgsGui.editorWidgetRegistry().create('ValueMap', layer, 0, config, None, None) + config = {"map": [{"AAAAA": "a"}, {"BBBB": "b"}]} + wrapper = QgsGui.editorWidgetRegistry().create( + "ValueMap", layer, 0, config, None, None + ) widget = wrapper.widget() - wrapper.setValues('a', []) - self.assertEqual(wrapper.value(), 'a') - self.assertEqual(widget.currentText(), 'AAAAA') + wrapper.setValues("a", []) + self.assertEqual(wrapper.value(), "a") + self.assertEqual(widget.currentText(), "AAAAA") - wrapper.setValues('b', []) - self.assertEqual(wrapper.value(), 'b') - self.assertEqual(widget.currentText(), 'BBBB') + wrapper.setValues("b", []) + self.assertEqual(wrapper.value(), "b") + self.assertEqual(widget.currentText(), "BBBB") # set to value NOT in the map, should not be lost - wrapper.setValues('c', []) - self.assertEqual(wrapper.value(), 'c') - self.assertEqual(widget.currentText(), '(c)') + wrapper.setValues("c", []) + self.assertEqual(wrapper.value(), "c") + self.assertEqual(widget.currentText(), "(c)") wrapper.setValues(NULL, []) self.assertEqual(wrapper.value(), NULL) - self.assertEqual(widget.currentText(), '(NULL)') + self.assertEqual(widget.currentText(), "(NULL)") QgsProject.instance().removeAllMapLayers() @@ -267,27 +300,31 @@ def test_value_map_set_value_not_in_map_with_null(self): self.assertTrue(layer.isValid()) QgsProject.instance().addMapLayer(layer) - config = {'map': [{'AAAAA': 'a'}, {'BBBB': 'b'}, {'nothing': self.VALUEMAP_NULL_TEXT}]} - wrapper = QgsGui.editorWidgetRegistry().create('ValueMap', layer, 0, config, None, None) + config = { + "map": [{"AAAAA": "a"}, {"BBBB": "b"}, {"nothing": self.VALUEMAP_NULL_TEXT}] + } + wrapper = QgsGui.editorWidgetRegistry().create( + "ValueMap", layer, 0, config, None, None + ) widget = wrapper.widget() - wrapper.setValues('a', []) - self.assertEqual(wrapper.value(), 'a') - self.assertEqual(widget.currentText(), 'AAAAA') + wrapper.setValues("a", []) + self.assertEqual(wrapper.value(), "a") + self.assertEqual(widget.currentText(), "AAAAA") - wrapper.setValues('b', []) - self.assertEqual(wrapper.value(), 'b') - self.assertEqual(widget.currentText(), 'BBBB') + wrapper.setValues("b", []) + self.assertEqual(wrapper.value(), "b") + self.assertEqual(widget.currentText(), "BBBB") # set to value NOT in the map, should not be lost - wrapper.setValues('c', []) - self.assertEqual(wrapper.value(), 'c') - self.assertEqual(widget.currentText(), '(c)') + wrapper.setValues("c", []) + self.assertEqual(wrapper.value(), "c") + self.assertEqual(widget.currentText(), "(c)") # set to value NOT in the map, should not be lost wrapper.setValues(NULL, []) self.assertEqual(wrapper.value(), NULL) - self.assertEqual(widget.currentText(), 'nothing') + self.assertEqual(widget.currentText(), "nothing") QgsProject.instance().removeAllMapLayers() @@ -295,44 +332,54 @@ def test_value_map_set_value_not_in_map_with_null(self): class TestQgsUuidWidget(QgisTestCase): def test_create_uuid(self): - layer = QgsVectorLayer("none?field=text_no_limit:text(0)&field=text_limit:text(10)&field=text_38:text(38)", "layer", "memory") + layer = QgsVectorLayer( + "none?field=text_no_limit:text(0)&field=text_limit:text(10)&field=text_38:text(38)", + "layer", + "memory", + ) self.assertTrue(layer.isValid()) QgsProject.instance().addMapLayer(layer) # unlimited length text field - wrapper = QgsGui.editorWidgetRegistry().create('UuidGenerator', layer, 0, {}, None, None) + wrapper = QgsGui.editorWidgetRegistry().create( + "UuidGenerator", layer, 0, {}, None, None + ) _ = wrapper.widget() feature = QgsFeature(layer.fields()) wrapper.setFeature(feature) val = wrapper.value() # we can't directly check the result, as it will be random, so just check its general properties self.assertEqual(len(val), 38) - self.assertEqual(val[0], '{') - self.assertEqual(val[-1], '}') + self.assertEqual(val[0], "{") + self.assertEqual(val[-1], "}") # limited length text field, value must be truncated - wrapper = QgsGui.editorWidgetRegistry().create('UuidGenerator', layer, 1, {}, None, None) + wrapper = QgsGui.editorWidgetRegistry().create( + "UuidGenerator", layer, 1, {}, None, None + ) _ = wrapper.widget() feature = QgsFeature(layer.fields()) wrapper.setFeature(feature) val = wrapper.value() # we can't directly check the result, as it will be random, so just check its general properties self.assertEqual(len(val), 10) - self.assertNotEqual(val[0], '{') - self.assertNotEqual(val[-1], '}') + self.assertNotEqual(val[0], "{") + self.assertNotEqual(val[-1], "}") with self.assertRaises(ValueError): - val.index('-') + val.index("-") # limited length text field with length = 38, value must not be truncated - wrapper = QgsGui.editorWidgetRegistry().create('UuidGenerator', layer, 2, {}, None, None) + wrapper = QgsGui.editorWidgetRegistry().create( + "UuidGenerator", layer, 2, {}, None, None + ) _ = wrapper.widget() feature = QgsFeature(layer.fields()) wrapper.setFeature(feature) val = wrapper.value() # we can't directly check the result, as it will be random, so just check its general properties self.assertEqual(len(val), 38) - self.assertEqual(val[0], '{') - self.assertEqual(val[-1], '}') + self.assertEqual(val[0], "{") + self.assertEqual(val[-1], "}") QgsProject.instance().removeAllMapLayers() diff --git a/tests/src/python/test_qgselevationcontrollerwidget.py b/tests/src/python/test_qgselevationcontrollerwidget.py index 8c8fe3a2dc10..1de3cd94d149 100644 --- a/tests/src/python/test_qgselevationcontrollerwidget.py +++ b/tests/src/python/test_qgselevationcontrollerwidget.py @@ -5,12 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + from qgis.PyQt.QtCore import Qt from qgis.PyQt.QtTest import QSignalSpy -from qgis.core import ( - QgsDoubleRange, - QgsProject -) +from qgis.core import QgsDoubleRange, QgsProject from qgis.gui import QgsElevationControllerWidget import unittest from qgis.testing import start_app, QgisTestCase @@ -24,18 +22,15 @@ def testRange(self): w = QgsElevationControllerWidget() spy = QSignalSpy(w.rangeChanged) w.setRangeLimits(QgsDoubleRange(100.5, 1000)) - self.assertEqual(w.rangeLimits(), - QgsDoubleRange(100.5, 1000)) + self.assertEqual(w.rangeLimits(), QgsDoubleRange(100.5, 1000)) self.assertEqual(len(spy), 1) # ensure that range is losslessly maintained if the user doesn't # move the slider w.setRange(QgsDoubleRange(130.3, 920.6)) self.assertEqual(len(spy), 2) - self.assertEqual(w.range(), - QgsDoubleRange(130.3, 920.6)) - self.assertEqual(spy[-1][0], - QgsDoubleRange(130.3, 920.6)) + self.assertEqual(w.range(), QgsDoubleRange(130.3, 920.6)) + self.assertEqual(spy[-1][0], QgsDoubleRange(130.3, 920.6)) # no change = no signal w.setRange(QgsDoubleRange(130.3, 920.6)) self.assertEqual(len(spy), 2) @@ -43,43 +38,34 @@ def testRange(self): # raise signal w.setRange(QgsDoubleRange(130.300001, 920.6)) self.assertEqual(len(spy), 3) - self.assertEqual(spy[-1][0], - QgsDoubleRange(130.300001, 920.6)) + self.assertEqual(spy[-1][0], QgsDoubleRange(130.300001, 920.6)) # change visible limits to something which fits the old range # make sure this is lossless w.setRangeLimits(QgsDoubleRange(50, 1050)) - self.assertEqual(w.range(), - QgsDoubleRange(130.300001, 920.6)) + self.assertEqual(w.range(), QgsDoubleRange(130.300001, 920.6)) self.assertEqual(len(spy), 3) # change visible limits to something which fits only part of the old range w.setRangeLimits(QgsDoubleRange(160, 1050)) - self.assertEqual(w.range(), - QgsDoubleRange(160.0, 920.6)) + self.assertEqual(w.range(), QgsDoubleRange(160.0, 920.6)) self.assertEqual(len(spy), 4) - self.assertEqual(spy[-1][0], - QgsDoubleRange(160.0, 920.6)) + self.assertEqual(spy[-1][0], QgsDoubleRange(160.0, 920.6)) w.setRangeLimits(QgsDoubleRange(120, 917.5)) - self.assertEqual(w.range(), - QgsDoubleRange(160.0, 917.5)) + self.assertEqual(w.range(), QgsDoubleRange(160.0, 917.5)) self.assertEqual(len(spy), 5) self.assertEqual(spy[-1][0], QgsDoubleRange(160.0, 917.5)) w.setRangeLimits(QgsDoubleRange(171, 815.5)) - self.assertEqual(w.range(), - QgsDoubleRange(171, 815.5)) + self.assertEqual(w.range(), QgsDoubleRange(171, 815.5)) self.assertEqual(len(spy), 6) - self.assertEqual(spy[-1][0], - QgsDoubleRange(171, 815.5)) + self.assertEqual(spy[-1][0], QgsDoubleRange(171, 815.5)) # infinite range => should be ignored w.setRangeLimits(QgsDoubleRange()) - self.assertEqual(w.rangeLimits(), - QgsDoubleRange(171, 815.5)) - self.assertEqual(w.range(), - QgsDoubleRange(171, 815.5)) + self.assertEqual(w.rangeLimits(), QgsDoubleRange(171, 815.5)) + self.assertEqual(w.range(), QgsDoubleRange(171, 815.5)) self.assertEqual(len(spy), 6) def test_slider_interaction(self): @@ -100,8 +86,10 @@ def test_slider_interaction(self): # slider should have a decent integer precision: self.assertGreaterEqual(slider_range, 500) - w.slider().setRange(int(w.slider().minimum() + slider_range * 0.4), - int(w.slider().minimum() + slider_range * 0.7)) + w.slider().setRange( + int(w.slider().minimum() + slider_range * 0.4), + int(w.slider().minimum() + slider_range * 0.7), + ) self.assertEqual(len(spy), 3) self.assertAlmostEqual(spy[-1][0].lower(), 459.644, 3) self.assertAlmostEqual(spy[-1][0].upper(), 729.495, 3) @@ -130,28 +118,20 @@ def test_project_interaction(self): elevation_properties.setElevationRange(QgsDoubleRange(50, 160)) w = QgsElevationControllerWidget() spy = QSignalSpy(w.rangeChanged) - self.assertEqual(w.rangeLimits(), - QgsDoubleRange(50, 160) - ) + self.assertEqual(w.rangeLimits(), QgsDoubleRange(50, 160)) # initially selected range should be full range - self.assertEqual(w.range(), - QgsDoubleRange(50, 160) - ) + self.assertEqual(w.range(), QgsDoubleRange(50, 160)) # change range limits for project elevation_properties.setElevationRange(QgsDoubleRange(80, 130)) - self.assertEqual(w.rangeLimits(), - QgsDoubleRange(80, 130) - ) + self.assertEqual(w.rangeLimits(), QgsDoubleRange(80, 130)) self.assertEqual(w.range(), QgsDoubleRange(80, 130)) self.assertEqual(len(spy), 1) self.assertEqual(spy[-1][0], QgsDoubleRange(80, 130)) # expand out range from current value elevation_properties.setElevationRange(QgsDoubleRange(40, 190)) - self.assertEqual(w.rangeLimits(), - QgsDoubleRange(40, 190) - ) + self.assertEqual(w.rangeLimits(), QgsDoubleRange(40, 190)) # selected range should be unchanged self.assertEqual(len(spy), 1) self.assertEqual(w.range(), QgsDoubleRange(80, 130)) @@ -160,10 +140,8 @@ def test_project_interaction(self): elevation_properties.setElevationRange(QgsDoubleRange()) w = QgsElevationControllerWidget() # ensure some initial range is set, even if we are just guessing! - self.assertEqual(w.rangeLimits(), - QgsDoubleRange(0, 100) - ) + self.assertEqual(w.rangeLimits(), QgsDoubleRange(0, 100)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgselevationprofilecanvas.py b/tests/src/python/test_qgselevationprofilecanvas.py index 43d328d293e5..c23f8d923319 100644 --- a/tests/src/python/test_qgselevationprofilecanvas.py +++ b/tests/src/python/test_qgselevationprofilecanvas.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '28/3/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "28/3/2022" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.PyQt.QtCore import QEvent, QPoint, QPointF, Qt from qgis.PyQt.QtGui import QKeyEvent, QMouseEvent, QWheelEvent @@ -28,7 +29,7 @@ class TestTool(QgsPlotTool): def __init__(self, canvas): - super().__init__(canvas, 'Test') + super().__init__(canvas, "Test") self.events = [] def plotMoveEvent(self, event): @@ -57,20 +58,20 @@ class TestQgsElevationProfileCanvas(QgisTestCase): def testGettersSetters(self): canvas = QgsElevationProfileCanvas() - canvas.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) - self.assertEqual(canvas.crs().authid(), 'EPSG:3111') + canvas.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) + self.assertEqual(canvas.crs().authid(), "EPSG:3111") ls = QgsLineString() - ls.fromWkt('LineString(1 2, 3 4)') + ls.fromWkt("LineString(1 2, 3 4)") canvas.setProfileCurve(ls) - self.assertEqual(canvas.profileCurve().asWkt(), 'LineString (1 2, 3 4)') + self.assertEqual(canvas.profileCurve().asWkt(), "LineString (1 2, 3 4)") def testToFromMapCoordinates(self): """ Test converting canvas coordinates to map coordinates """ canvas = QgsElevationProfileCanvas() - canvas.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + canvas.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) canvas.setFrameStyle(0) canvas.resize(600, 400) canvas.setProject(QgsProject.instance()) @@ -83,7 +84,7 @@ def testToFromMapCoordinates(self): self.assertTrue(canvas.toCanvasCoordinates(QgsPoint(6, 3)).isEmpty()) ls = QgsLineString() - ls.fromWkt('LineString(0 2, 10 2, 10 4)') + ls.fromWkt("LineString(0 2, 10 2, 10 4)") canvas.setProfileCurve(ls) canvas.setVisiblePlotRange(0, ls.length(), 0, 100) @@ -125,7 +126,7 @@ def test_tool(self): Test some plot tool logic """ canvas = QgsElevationProfileCanvas() - canvas.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + canvas.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) canvas.setFrameStyle(0) canvas.resize(600, 400) canvas.setProject(QgsProject.instance()) @@ -133,7 +134,7 @@ def test_tool(self): self.assertEqual(canvas.width(), 600) self.assertEqual(canvas.height(), 400) ls = QgsLineString() - ls.fromWkt('LineString(0 2, 10 2, 10 4)') + ls.fromWkt("LineString(0 2, 10 2, 10 4)") canvas.setProfileCurve(ls) canvas.setVisiblePlotRange(0, ls.length(), 0, 100) @@ -143,15 +144,25 @@ def test_tool(self): canvas.setTool(tool) self.assertEqual(canvas.tool(), tool) - key_press_event = QKeyEvent(QEvent.Type.KeyPress, 54, Qt.KeyboardModifier.ShiftModifier) + key_press_event = QKeyEvent( + QEvent.Type.KeyPress, 54, Qt.KeyboardModifier.ShiftModifier + ) canvas.keyPressEvent(key_press_event) self.assertEqual(tool.events[-1].type(), QEvent.Type.KeyPress) - key_release_event = QKeyEvent(QEvent.Type.KeyRelease, 54, Qt.KeyboardModifier.ShiftModifier) + key_release_event = QKeyEvent( + QEvent.Type.KeyRelease, 54, Qt.KeyboardModifier.ShiftModifier + ) canvas.keyReleaseEvent(key_release_event) self.assertEqual(tool.events[-1].type(), QEvent.Type.KeyRelease) - mouse_dbl_click_event = QMouseEvent(QEvent.Type.MouseButtonDblClick, QPointF(300, 200), Qt.MouseButton.LeftButton, Qt.MouseButtons(), Qt.KeyboardModifier.ShiftModifier) + mouse_dbl_click_event = QMouseEvent( + QEvent.Type.MouseButtonDblClick, + QPointF(300, 200), + Qt.MouseButton.LeftButton, + Qt.MouseButtons(), + Qt.KeyboardModifier.ShiftModifier, + ) canvas.mouseDoubleClickEvent(mouse_dbl_click_event) self.assertEqual(tool.events[-1].type(), QEvent.Type.MouseButtonDblClick) self.assertIsInstance(tool.events[-1], QgsPlotMouseEvent) @@ -159,7 +170,13 @@ def test_tool(self): self.assertAlmostEqual(tool.events[-1].mapPoint().y(), 2, 4) self.assertAlmostEqual(tool.events[-1].mapPoint().z(), 49.165, delta=5) - mouse_move_event = QMouseEvent(QEvent.Type.MouseMove, QPointF(300, 200), Qt.MouseButton.LeftButton, Qt.MouseButtons(), Qt.KeyboardModifier.ShiftModifier) + mouse_move_event = QMouseEvent( + QEvent.Type.MouseMove, + QPointF(300, 200), + Qt.MouseButton.LeftButton, + Qt.MouseButtons(), + Qt.KeyboardModifier.ShiftModifier, + ) canvas.mouseMoveEvent(mouse_move_event) self.assertEqual(tool.events[-1].type(), QEvent.Type.MouseMove) self.assertIsInstance(tool.events[-1], QgsPlotMouseEvent) @@ -167,7 +184,13 @@ def test_tool(self): self.assertAlmostEqual(tool.events[-1].mapPoint().y(), 2, 4) self.assertAlmostEqual(tool.events[-1].mapPoint().z(), 49.165, delta=5) - mouse_press_event = QMouseEvent(QEvent.Type.MouseButtonPress, QPointF(300, 200), Qt.MouseButton.LeftButton, Qt.MouseButtons(), Qt.KeyboardModifier.ShiftModifier) + mouse_press_event = QMouseEvent( + QEvent.Type.MouseButtonPress, + QPointF(300, 200), + Qt.MouseButton.LeftButton, + Qt.MouseButtons(), + Qt.KeyboardModifier.ShiftModifier, + ) canvas.mousePressEvent(mouse_press_event) self.assertEqual(tool.events[-1].type(), QEvent.Type.MouseButtonPress) self.assertIsInstance(tool.events[-1], QgsPlotMouseEvent) @@ -175,7 +198,13 @@ def test_tool(self): self.assertAlmostEqual(tool.events[-1].mapPoint().y(), 2, 4) self.assertAlmostEqual(tool.events[-1].mapPoint().z(), 49.165, delta=5) - mouse_release_event = QMouseEvent(QEvent.Type.MouseButtonRelease, QPointF(300, 200), Qt.MouseButton.LeftButton, Qt.MouseButtons(), Qt.KeyboardModifier.ShiftModifier) + mouse_release_event = QMouseEvent( + QEvent.Type.MouseButtonRelease, + QPointF(300, 200), + Qt.MouseButton.LeftButton, + Qt.MouseButtons(), + Qt.KeyboardModifier.ShiftModifier, + ) canvas.mouseReleaseEvent(mouse_release_event) self.assertEqual(tool.events[-1].type(), QEvent.Type.MouseButtonRelease) self.assertIsInstance(tool.events[-1], QgsPlotMouseEvent) @@ -183,10 +212,19 @@ def test_tool(self): self.assertAlmostEqual(tool.events[-1].mapPoint().y(), 2, 4) self.assertAlmostEqual(tool.events[-1].mapPoint().z(), 49.165, delta=5) - wheel_event = QWheelEvent(QPointF(300, 200), QPointF(300, 200), QPoint(1, 2), QPoint(3, 4), Qt.MouseButton.NoButton, Qt.KeyboardModifier.NoModifier, Qt.ScrollPhase.ScrollBegin, False) + wheel_event = QWheelEvent( + QPointF(300, 200), + QPointF(300, 200), + QPoint(1, 2), + QPoint(3, 4), + Qt.MouseButton.NoButton, + Qt.KeyboardModifier.NoModifier, + Qt.ScrollPhase.ScrollBegin, + False, + ) canvas.wheelEvent(wheel_event) self.assertEqual(tool.events[-1].type(), QEvent.Type.Wheel) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgselevationutils.py b/tests/src/python/test_qgselevationutils.py index e336eadd8250..0cb0eda31b38 100644 --- a/tests/src/python/test_qgselevationutils.py +++ b/tests/src/python/test_qgselevationutils.py @@ -13,7 +13,7 @@ QgsProject, QgsRasterLayer, QgsElevationUtils, - QgsDoubleRange + QgsDoubleRange, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -34,99 +34,130 @@ def test_z_range_for_project(self): """ project = QgsProject() self.assertEqual( - QgsElevationUtils.calculateZRangeForProject(project), - QgsDoubleRange()) + QgsElevationUtils.calculateZRangeForProject(project), QgsDoubleRange() + ) - raster_layer = QgsRasterLayer(os.path.join(unitTestDataPath(), 'landsat_4326.tif')) + raster_layer = QgsRasterLayer( + os.path.join(unitTestDataPath(), "landsat_4326.tif") + ) self.assertTrue(raster_layer.isValid()) project.addMapLayer(raster_layer) self.assertEqual( - QgsElevationUtils.calculateZRangeForProject(project), - QgsDoubleRange()) + QgsElevationUtils.calculateZRangeForProject(project), QgsDoubleRange() + ) props = raster_layer.elevationProperties() props.setEnabled(True) props.setMode(Qgis.RasterElevationMode.FixedRangePerBand) - props.setFixedRangePerBand({1: QgsDoubleRange(103.1, 106.8), - 2: QgsDoubleRange(106.8, 116.8), - 3: QgsDoubleRange(116.8, 126.8)}) + props.setFixedRangePerBand( + { + 1: QgsDoubleRange(103.1, 106.8), + 2: QgsDoubleRange(106.8, 116.8), + 3: QgsDoubleRange(116.8, 126.8), + } + ) self.assertEqual( QgsElevationUtils.calculateZRangeForProject(project), - QgsDoubleRange(103.1, 126.8)) + QgsDoubleRange(103.1, 126.8), + ) - raster_layer2 = QgsRasterLayer(os.path.join(unitTestDataPath(), 'landsat_4326.tif')) + raster_layer2 = QgsRasterLayer( + os.path.join(unitTestDataPath(), "landsat_4326.tif") + ) self.assertTrue(raster_layer2.isValid()) project.addMapLayer(raster_layer2) self.assertEqual( QgsElevationUtils.calculateZRangeForProject(project), - QgsDoubleRange(103.1, 126.8)) + QgsDoubleRange(103.1, 126.8), + ) props = raster_layer2.elevationProperties() props.setEnabled(True) props.setMode(Qgis.RasterElevationMode.FixedRangePerBand) - props.setFixedRangePerBand({1: QgsDoubleRange(103.1, 106.8), - 2: QgsDoubleRange(106.8, 116.8), - 3: QgsDoubleRange(126.8, 136.8)}) + props.setFixedRangePerBand( + { + 1: QgsDoubleRange(103.1, 106.8), + 2: QgsDoubleRange(106.8, 116.8), + 3: QgsDoubleRange(126.8, 136.8), + } + ) self.assertEqual( QgsElevationUtils.calculateZRangeForProject(project), - QgsDoubleRange(103.1, 136.8)) + QgsDoubleRange(103.1, 136.8), + ) def test_significant_z_values_for_project(self): """ Test calculating significant z values for a project """ project = QgsProject() - self.assertFalse( - QgsElevationUtils.significantZValuesForProject(project)) - self.assertFalse( - QgsElevationUtils.significantZValuesForLayers([])) + self.assertFalse(QgsElevationUtils.significantZValuesForProject(project)) + self.assertFalse(QgsElevationUtils.significantZValuesForLayers([])) - raster_layer = QgsRasterLayer(os.path.join(unitTestDataPath(), 'landsat_4326.tif')) + raster_layer = QgsRasterLayer( + os.path.join(unitTestDataPath(), "landsat_4326.tif") + ) self.assertTrue(raster_layer.isValid()) project.addMapLayer(raster_layer) - self.assertFalse( - QgsElevationUtils.significantZValuesForProject(project)) - self.assertFalse( - QgsElevationUtils.significantZValuesForLayers([raster_layer])) + self.assertFalse(QgsElevationUtils.significantZValuesForProject(project)) + self.assertFalse(QgsElevationUtils.significantZValuesForLayers([raster_layer])) props = raster_layer.elevationProperties() props.setEnabled(True) props.setMode(Qgis.RasterElevationMode.FixedRangePerBand) - props.setFixedRangePerBand({1: QgsDoubleRange(103.1, 106.8), - 2: QgsDoubleRange(106.8, 116.8), - 3: QgsDoubleRange(116.8, 126.8)}) + props.setFixedRangePerBand( + { + 1: QgsDoubleRange(103.1, 106.8), + 2: QgsDoubleRange(106.8, 116.8), + 3: QgsDoubleRange(116.8, 126.8), + } + ) self.assertEqual( QgsElevationUtils.significantZValuesForProject(project), - [103.1, 106.8, 116.8, 126.8]) + [103.1, 106.8, 116.8, 126.8], + ) self.assertEqual( QgsElevationUtils.significantZValuesForLayers([raster_layer]), - [103.1, 106.8, 116.8, 126.8]) + [103.1, 106.8, 116.8, 126.8], + ) - raster_layer2 = QgsRasterLayer(os.path.join(unitTestDataPath(), 'landsat_4326.tif')) + raster_layer2 = QgsRasterLayer( + os.path.join(unitTestDataPath(), "landsat_4326.tif") + ) self.assertTrue(raster_layer2.isValid()) project.addMapLayer(raster_layer2) self.assertEqual( QgsElevationUtils.significantZValuesForProject(project), - [103.1, 106.8, 116.8, 126.8]) + [103.1, 106.8, 116.8, 126.8], + ) self.assertEqual( - QgsElevationUtils.significantZValuesForLayers([raster_layer, - raster_layer2]), - [103.1, 106.8, 116.8, 126.8]) + QgsElevationUtils.significantZValuesForLayers( + [raster_layer, raster_layer2] + ), + [103.1, 106.8, 116.8, 126.8], + ) props = raster_layer2.elevationProperties() props.setEnabled(True) props.setMode(Qgis.RasterElevationMode.FixedRangePerBand) - props.setFixedRangePerBand({1: QgsDoubleRange(103.1, 106.8), - 2: QgsDoubleRange(106.8, 116.8), - 3: QgsDoubleRange(126.8, 136.8)}) + props.setFixedRangePerBand( + { + 1: QgsDoubleRange(103.1, 106.8), + 2: QgsDoubleRange(106.8, 116.8), + 3: QgsDoubleRange(126.8, 136.8), + } + ) self.assertEqual( QgsElevationUtils.significantZValuesForProject(project), - [103.1, 106.8, 116.8, 126.8, 136.8]) + [103.1, 106.8, 116.8, 126.8, 136.8], + ) self.assertEqual( - QgsElevationUtils.significantZValuesForLayers([raster_layer, - raster_layer2]), - [103.1, 106.8, 116.8, 126.8, 136.8]) + QgsElevationUtils.significantZValuesForLayers( + [raster_layer, raster_layer2] + ), + [103.1, 106.8, 116.8, 126.8, 136.8], + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsellipsoidutils.py b/tests/src/python/test_qgsellipsoidutils.py index 118a587154b5..250318fb1939 100644 --- a/tests/src/python/test_qgsellipsoidutils.py +++ b/tests/src/python/test_qgsellipsoidutils.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '18/4/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "18/4/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.core import QgsEllipsoidUtils, QgsProjUtils @@ -33,7 +34,10 @@ def testParams(self): self.assertAlmostEqual(params.semiMinor, 6356752.314245179, 5) self.assertAlmostEqual(params.inverseFlattening, 298.257223563, 5) self.assertFalse(params.useCustomParameters) - self.assertEqual(params.crs.toProj(), '+proj=longlat +a=6378137 +rf=298.25722356300003 +no_defs') + self.assertEqual( + params.crs.toProj(), + "+proj=longlat +a=6378137 +rf=298.25722356300003 +no_defs", + ) for i in range(2): params = QgsEllipsoidUtils.ellipsoidParameters("Ganymede2000") @@ -42,7 +46,7 @@ def testParams(self): self.assertEqual(params.semiMinor, 2632345.0) self.assertEqual(params.inverseFlattening, 0) self.assertFalse(params.useCustomParameters) - self.assertEqual(params.crs.toProj(), '+proj=longlat +a=2632345 +no_defs') + self.assertEqual(params.crs.toProj(), "+proj=longlat +a=2632345 +no_defs") params = QgsEllipsoidUtils.ellipsoidParameters("ESRI:107916") self.assertTrue(params.valid) @@ -50,7 +54,7 @@ def testParams(self): self.assertEqual(params.semiMinor, 2632345.0) self.assertEqual(params.inverseFlattening, 0) self.assertFalse(params.useCustomParameters) - self.assertEqual(params.crs.toProj(), '+proj=longlat +a=2632345 +no_defs') + self.assertEqual(params.crs.toProj(), "+proj=longlat +a=2632345 +no_defs") params = QgsEllipsoidUtils.ellipsoidParameters("EPSG:7001") self.assertTrue(params.valid) @@ -58,8 +62,10 @@ def testParams(self): self.assertEqual(params.semiMinor, 6356256.909237285) self.assertEqual(params.inverseFlattening, 299.3249646) self.assertFalse(params.useCustomParameters) - self.assertEqual(params.crs.toProj(), - '+proj=longlat +a=6377563.3959999997 +rf=299.32496459999999 +no_defs') + self.assertEqual( + params.crs.toProj(), + "+proj=longlat +a=6377563.3959999997 +rf=299.32496459999999 +no_defs", + ) params = QgsEllipsoidUtils.ellipsoidParameters("EPSG:7008") self.assertTrue(params.valid) @@ -67,8 +73,10 @@ def testParams(self): self.assertEqual(params.semiMinor, 6356583.8) self.assertEqual(params.inverseFlattening, 294.9786982138982) self.assertFalse(params.useCustomParameters) - self.assertEqual(params.crs.toProj(), - '+proj=longlat +a=6378206.4000000004 +b=6356583.7999999998 +no_defs') + self.assertEqual( + params.crs.toProj(), + "+proj=longlat +a=6378206.4000000004 +b=6356583.7999999998 +no_defs", + ) # using parameters for i in range(2): @@ -78,7 +86,7 @@ def testParams(self): self.assertEqual(params.semiMinor, 2341350.0) self.assertAlmostEqual(params.inverseFlattening, 9.07223, 4) self.assertTrue(params.useCustomParameters) - self.assertEqual(params.crs.authid(), '') + self.assertEqual(params.crs.authid(), "") # invalid for i in range(2): @@ -86,110 +94,182 @@ def testParams(self): self.assertFalse(params.valid) def testAcronyms(self): - self.assertIn('EPSG:7030', QgsEllipsoidUtils.acronyms()) - self.assertIn('ESRI:107916', QgsEllipsoidUtils.acronyms()) + self.assertIn("EPSG:7030", QgsEllipsoidUtils.acronyms()) + self.assertIn("ESRI:107916", QgsEllipsoidUtils.acronyms()) def testDefinitions(self): defs = QgsEllipsoidUtils.definitions() - gany_id = 'ESRI:107916' + gany_id = "ESRI:107916" gany_defs = [d for d in defs if d.acronym == gany_id][0] self.assertEqual(gany_defs.acronym, gany_id) - self.assertEqual(gany_defs.description, - 'Ganymede 2000 IAU IAG (ESRI:107916)') + self.assertEqual(gany_defs.description, "Ganymede 2000 IAU IAG (ESRI:107916)") - if QgsProjUtils.projVersionMajor() > 8 or (QgsProjUtils.projVersionMajor() == 8 and QgsProjUtils.projVersionMinor() >= 1): - self.assertEqual(gany_defs.celestialBodyName, 'Ganymede') + if QgsProjUtils.projVersionMajor() > 8 or ( + QgsProjUtils.projVersionMajor() == 8 + and QgsProjUtils.projVersionMinor() >= 1 + ): + self.assertEqual(gany_defs.celestialBodyName, "Ganymede") self.assertTrue(gany_defs.parameters.valid) - self.assertEqual(gany_defs.parameters.semiMajor, - 2632345.0) - self.assertEqual(gany_defs.parameters.semiMinor, - 2632345.0) - self.assertEqual(gany_defs.parameters.inverseFlattening, - 0.0) + self.assertEqual(gany_defs.parameters.semiMajor, 2632345.0) + self.assertEqual(gany_defs.parameters.semiMinor, 2632345.0) + self.assertEqual(gany_defs.parameters.inverseFlattening, 0.0) self.assertFalse(gany_defs.parameters.useCustomParameters) - self.assertEqual(gany_defs.parameters.crs.authid(), '') + self.assertEqual(gany_defs.parameters.crs.authid(), "") - @unittest.skipIf(QgsProjUtils.projVersionMajor() < 8 or (QgsProjUtils.projVersionMajor() == 8 and QgsProjUtils.projVersionMinor() < 1), 'Not a proj >= 8.1 build') + @unittest.skipIf( + QgsProjUtils.projVersionMajor() < 8 + or ( + QgsProjUtils.projVersionMajor() == 8 and QgsProjUtils.projVersionMinor() < 1 + ), + "Not a proj >= 8.1 build", + ) def testCelestialBodies(self): bodies = QgsEllipsoidUtils.celestialBodies() self.assertTrue(bodies) - ganymede = [body for body in bodies if body.name() == 'Ganymede' and body.authority() == 'ESRI'][0] + ganymede = [ + body + for body in bodies + if body.name() == "Ganymede" and body.authority() == "ESRI" + ][0] self.assertTrue(ganymede.isValid()) def testMappingEllipsoidsToProj6(self): - old_qgis_ellipsoids = {'Adrastea2000': 'Adrastea2000', 'airy': 'Airy 1830', 'Amalthea2000': 'Amalthea2000', - 'Ananke2000': 'Ananke2000', - 'andrae': 'Andrae 1876 (Den., Iclnd.)', - 'Ariel2000': 'Ariel2000', - 'Atlas2000': 'Atlas2000', 'aust_SA': 'Australian Natl & S. Amer. 1969', - 'Belinda2000': 'Belinda2000', - 'bessel': 'Bessel 1841', 'bess_nam': 'Bessel 1841 (Namibia)', 'Bianca2000': 'Bianca2000', - 'Callisto2000': 'Callisto2000', 'Calypso2000': 'Calypso2000', 'Carme2000': 'Carme2000', - 'Charon2000': 'Charon2000', 'clrk66': 'Clarke 1866', 'IGNF:ELG004': 'Clarke 1866', - 'IGNF:ELG003': 'Clarke 1880 Anglais', 'IGNF:ELG010': 'Clarke 1880 IGN', - 'clrk80': 'Clarke 1880 mod.', - 'cape': 'Clarke 1880 mod.', 'CPM': 'Comm. des Poids et Mesures 1799', # spellok - 'Cordelia2000': 'Cordelia2000', - 'Cressida2000': 'Cressida2000', 'Deimos2000': 'Deimos2000', - 'delmbr': 'Delambre 1810 (Belgium)', - 'Desdemona2000': 'Desdemona2000', 'Despina2000': 'Despina2000', 'Dione2000': 'Dione2000', - 'Earth2000': 'Earth2000', 'Elara2000': 'Elara2000', 'Enceladus2000': 'Enceladus2000', - 'engelis': 'Engelis 1985', - 'Epimetheus2000': 'Epimetheus2000', 'Europa2000': 'Europa2000', - 'evrstSS': 'Everest (Sabah & Sarawak)', - 'evrst30': 'Everest 1830', 'evrst48': 'Everest 1948', 'evrst56': 'Everest 1956', - 'evrst69': 'Everest 1969', - 'fschr60': 'Fischer (Mercury Datum) 1960', 'fschr68': 'Fischer 1968', - 'GRS80': 'GRS 1980(IUGG, 1980)', - 'GRS67': 'GRS 67(IUGG 1967)', 'Galatea2000': 'Galatea2000', - 'Ganymede2000': 'Ganymede2000', - 'Helene2000': 'Helene2000', 'helmert': 'Helmert 1906', 'Himalia2000': 'Himalia2000', - 'hough': 'Hough', - 'Hyperion2000': 'Hyperion2000', 'IGNF:ELG108': 'IAG GRS 1967', - 'IGNF:ELG037': 'IAG GRS 1980', - 'IAU76': 'IAU 1976', 'Iapetus2000': 'Iapetus2000', - 'intl': 'International 1909 (Hayford)', - 'IGNF:ELG001': 'International-Hayford 1909', 'Io2000': 'Io2000', - 'Janus2000': 'Janus2000', - 'Juliet2000': 'Juliet2000', 'Jupiter2000': 'Jupiter2000', 'kaula': 'Kaula 1961', - 'krass': 'Krassovsky, 1942', - 'Larissa2000': 'Larissa2000', 'Leda2000': 'Leda2000', 'lerch': 'Lerch 1979', - 'Lysithea2000': 'Lysithea2000', - 'MERIT': 'MERIT 1983', 'Mars2000': 'Mars2000', 'mprts': 'Maupertius 1738', - 'Mercury2000': 'Mercury2000', - 'Metis2000': 'Metis2000', 'Mimas2000': 'Mimas2000', 'Miranda2000': 'Miranda2000', - 'mod_airy': 'Modified Airy', - 'fschr60m': 'Modified Fischer 1960', 'Moon2000': 'Moon2000', 'Naiad2000': 'Naiad2000', - 'NWL9D': 'Naval Weapons Lab., 1965', 'Neptune2000': 'Neptune2000', - 'Nereid2000': 'Nereid2000', - 'new_intl': 'New International 1967', 'sphere': 'Normal Sphere (r=6370997)', - 'Oberon2000': 'Oberon2000', - 'Ophelia2000': 'Ophelia2000', 'IGNF:ELG017': 'PLESSIS 1817', 'Pan2000': 'Pan2000', - 'Pandora2000': 'Pandora2000', - 'Pasiphae2000': 'Pasiphae2000', 'Phobos2000': 'Phobos2000', 'Phoebe2000': 'Phoebe2000', - 'plessis': 'Plessis 1817 (France)', 'Pluto2000': 'Pluto2000', 'Portia2000': 'Portia2000', - 'Prometheus2000': 'Prometheus2000', 'Proteus2000': 'Proteus2000', 'Puck2000': 'Puck2000', - 'Rhea2000': 'Rhea2000', - 'Rosalind2000': 'Rosalind2000', 'IGNF:ELG032': 'SPHERE PICARD', - 'Saturn2000': 'Saturn2000', - 'Sinope2000': 'Sinope2000', 'SEasia': 'Southeast Asia', - 'SGS85': 'Soviet Geodetic System 85', - 'Telesto2000': 'Telesto2000', 'Tethys2000': 'Tethys2000', 'Thalassa2000': 'Thalassa2000', - 'Thebe2000': 'Thebe2000', 'Titan2000': 'Titan2000', 'Titania2000': 'Titania2000', - 'Triton2000': 'Triton2000', - 'Umbriel2000': 'Umbriel2000', 'Uranus2000': 'Uranus2000', 'Venus2000': 'Venus2000', - 'WGS60': 'WGS 60', - 'WGS66': 'WGS 66', 'WGS72': 'WGS 72', 'WGS84': 'WGS 84', 'IGNF:ELG052': 'WGS72', - 'IGNF:ELG102': 'WGS72 (NWL-10F)', 'IGNF:ELG053': 'WGS84', 'walbeck': 'Walbeck'} + old_qgis_ellipsoids = { + "Adrastea2000": "Adrastea2000", + "airy": "Airy 1830", + "Amalthea2000": "Amalthea2000", + "Ananke2000": "Ananke2000", + "andrae": "Andrae 1876 (Den., Iclnd.)", + "Ariel2000": "Ariel2000", + "Atlas2000": "Atlas2000", + "aust_SA": "Australian Natl & S. Amer. 1969", + "Belinda2000": "Belinda2000", + "bessel": "Bessel 1841", + "bess_nam": "Bessel 1841 (Namibia)", + "Bianca2000": "Bianca2000", + "Callisto2000": "Callisto2000", + "Calypso2000": "Calypso2000", + "Carme2000": "Carme2000", + "Charon2000": "Charon2000", + "clrk66": "Clarke 1866", + "IGNF:ELG004": "Clarke 1866", + "IGNF:ELG003": "Clarke 1880 Anglais", + "IGNF:ELG010": "Clarke 1880 IGN", + "clrk80": "Clarke 1880 mod.", + "cape": "Clarke 1880 mod.", + "CPM": "Comm. des Poids et Mesures 1799", # spellok + "Cordelia2000": "Cordelia2000", + "Cressida2000": "Cressida2000", + "Deimos2000": "Deimos2000", + "delmbr": "Delambre 1810 (Belgium)", + "Desdemona2000": "Desdemona2000", + "Despina2000": "Despina2000", + "Dione2000": "Dione2000", + "Earth2000": "Earth2000", + "Elara2000": "Elara2000", + "Enceladus2000": "Enceladus2000", + "engelis": "Engelis 1985", + "Epimetheus2000": "Epimetheus2000", + "Europa2000": "Europa2000", + "evrstSS": "Everest (Sabah & Sarawak)", + "evrst30": "Everest 1830", + "evrst48": "Everest 1948", + "evrst56": "Everest 1956", + "evrst69": "Everest 1969", + "fschr60": "Fischer (Mercury Datum) 1960", + "fschr68": "Fischer 1968", + "GRS80": "GRS 1980(IUGG, 1980)", + "GRS67": "GRS 67(IUGG 1967)", + "Galatea2000": "Galatea2000", + "Ganymede2000": "Ganymede2000", + "Helene2000": "Helene2000", + "helmert": "Helmert 1906", + "Himalia2000": "Himalia2000", + "hough": "Hough", + "Hyperion2000": "Hyperion2000", + "IGNF:ELG108": "IAG GRS 1967", + "IGNF:ELG037": "IAG GRS 1980", + "IAU76": "IAU 1976", + "Iapetus2000": "Iapetus2000", + "intl": "International 1909 (Hayford)", + "IGNF:ELG001": "International-Hayford 1909", + "Io2000": "Io2000", + "Janus2000": "Janus2000", + "Juliet2000": "Juliet2000", + "Jupiter2000": "Jupiter2000", + "kaula": "Kaula 1961", + "krass": "Krassovsky, 1942", + "Larissa2000": "Larissa2000", + "Leda2000": "Leda2000", + "lerch": "Lerch 1979", + "Lysithea2000": "Lysithea2000", + "MERIT": "MERIT 1983", + "Mars2000": "Mars2000", + "mprts": "Maupertius 1738", + "Mercury2000": "Mercury2000", + "Metis2000": "Metis2000", + "Mimas2000": "Mimas2000", + "Miranda2000": "Miranda2000", + "mod_airy": "Modified Airy", + "fschr60m": "Modified Fischer 1960", + "Moon2000": "Moon2000", + "Naiad2000": "Naiad2000", + "NWL9D": "Naval Weapons Lab., 1965", + "Neptune2000": "Neptune2000", + "Nereid2000": "Nereid2000", + "new_intl": "New International 1967", + "sphere": "Normal Sphere (r=6370997)", + "Oberon2000": "Oberon2000", + "Ophelia2000": "Ophelia2000", + "IGNF:ELG017": "PLESSIS 1817", + "Pan2000": "Pan2000", + "Pandora2000": "Pandora2000", + "Pasiphae2000": "Pasiphae2000", + "Phobos2000": "Phobos2000", + "Phoebe2000": "Phoebe2000", + "plessis": "Plessis 1817 (France)", + "Pluto2000": "Pluto2000", + "Portia2000": "Portia2000", + "Prometheus2000": "Prometheus2000", + "Proteus2000": "Proteus2000", + "Puck2000": "Puck2000", + "Rhea2000": "Rhea2000", + "Rosalind2000": "Rosalind2000", + "IGNF:ELG032": "SPHERE PICARD", + "Saturn2000": "Saturn2000", + "Sinope2000": "Sinope2000", + "SEasia": "Southeast Asia", + "SGS85": "Soviet Geodetic System 85", + "Telesto2000": "Telesto2000", + "Tethys2000": "Tethys2000", + "Thalassa2000": "Thalassa2000", + "Thebe2000": "Thebe2000", + "Titan2000": "Titan2000", + "Titania2000": "Titania2000", + "Triton2000": "Triton2000", + "Umbriel2000": "Umbriel2000", + "Uranus2000": "Uranus2000", + "Venus2000": "Venus2000", + "WGS60": "WGS 60", + "WGS66": "WGS 66", + "WGS72": "WGS 72", + "WGS84": "WGS 84", + "IGNF:ELG052": "WGS72", + "IGNF:ELG102": "WGS72 (NWL-10F)", + "IGNF:ELG053": "WGS84", + "walbeck": "Walbeck", + } # ensure that all old QGIS custom ellipsoid definitions map across to new PROJ6 ones for o in old_qgis_ellipsoids: - self.assertTrue(QgsEllipsoidUtils.ellipsoidParameters(o).valid, f'no defs for {o}') + self.assertTrue( + QgsEllipsoidUtils.ellipsoidParameters(o).valid, f"no defs for {o}" + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsencodingselectiondialog.py b/tests/src/python/test_qgsencodingselectiondialog.py index 9b900080910b..f83b9d005e8b 100644 --- a/tests/src/python/test_qgsencodingselectiondialog.py +++ b/tests/src/python/test_qgsencodingselectiondialog.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '21/11/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "21/11/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import unittest @@ -21,15 +22,15 @@ class TestQgsEncodingSelectionDialog(QgisTestCase): def testGettersSetters(self): - """ test dialog getters/setters """ - dlg = QgsEncodingSelectionDialog(encoding='UTF-16') - self.assertEqual(dlg.encoding(), 'UTF-16') - dlg.setEncoding('UTF-8') - self.assertEqual(dlg.encoding(), 'UTF-8') + """test dialog getters/setters""" + dlg = QgsEncodingSelectionDialog(encoding="UTF-16") + self.assertEqual(dlg.encoding(), "UTF-16") + dlg.setEncoding("UTF-8") + self.assertEqual(dlg.encoding(), "UTF-8") # custom encoding option - dlg.setEncoding('trisolarian') - self.assertEqual(dlg.encoding(), 'trisolarian') + dlg.setEncoding("trisolarian") + self.assertEqual(dlg.encoding(), "trisolarian") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsexiftools.py b/tests/src/python/test_qgsexiftools.py index a0bd8081ffd5..1c803ba6b1a5 100644 --- a/tests/src/python/test_qgsexiftools.py +++ b/tests/src/python/test_qgsexiftools.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '09/11/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "09/11/2018" +__copyright__ = "Copyright 2018, The QGIS Project" import os import shutil @@ -27,45 +28,53 @@ class TestQgsExifUtils(QgisTestCase): def testReadTags(self): - photos_folder = os.path.join(TEST_DATA_DIR, 'photos') + photos_folder = os.path.join(TEST_DATA_DIR, "photos") # test a converted Exif rational value - elevation = QgsExifTools.readTag(os.path.join(photos_folder, '0997.JPG'), 'Exif.GPSInfo.GPSAltitude') + elevation = QgsExifTools.readTag( + os.path.join(photos_folder, "0997.JPG"), "Exif.GPSInfo.GPSAltitude" + ) self.assertEqual(elevation, 422.19101123595505) # test a converted Exif datetime value - dt = QgsExifTools.readTag(os.path.join(photos_folder, '0997.JPG'), 'Exif.Image.DateTime') + dt = QgsExifTools.readTag( + os.path.join(photos_folder, "0997.JPG"), "Exif.Image.DateTime" + ) self.assertEqual(dt, QDateTime(2018, 3, 16, 12, 19, 19)) # test a converted Xmp datetime value - dt = QgsExifTools.readTag(os.path.join(photos_folder, '0997.JPG'), 'Xmp.xmp.MetadataDate') - self.assertEqual(dt, QDateTime(QDate(2023, 2, 5), QTime(10, 16, 5, 0), Qt.TimeSpec(1))) + dt = QgsExifTools.readTag( + os.path.join(photos_folder, "0997.JPG"), "Xmp.xmp.MetadataDate" + ) + self.assertEqual( + dt, QDateTime(QDate(2023, 2, 5), QTime(10, 16, 5, 0), Qt.TimeSpec(1)) + ) def testGeoTags(self): - photos_folder = os.path.join(TEST_DATA_DIR, 'photos') + photos_folder = os.path.join(TEST_DATA_DIR, "photos") - tag, ok = QgsExifTools.getGeoTag('') + tag, ok = QgsExifTools.getGeoTag("") self.assertFalse(ok) - tag, ok = QgsExifTools.getGeoTag(os.path.join(photos_folder, '0997.JPG')) + tag, ok = QgsExifTools.getGeoTag(os.path.join(photos_folder, "0997.JPG")) self.assertTrue(ok) - self.assertEqual(tag.asWkt(6), 'Point Z (149.275167 -37.2305 422.191011)') + self.assertEqual(tag.asWkt(6), "Point Z (149.275167 -37.2305 422.191011)") - tag, ok = QgsExifTools.getGeoTag(os.path.join(photos_folder, 'geotagged.jpg')) + tag, ok = QgsExifTools.getGeoTag(os.path.join(photos_folder, "geotagged.jpg")) self.assertTrue(ok) - self.assertEqual(tag.asWkt(6), 'Point Z (149.131878 -36.220892 867)') + self.assertEqual(tag.asWkt(6), "Point Z (149.131878 -36.220892 867)") - tag, ok = QgsExifTools.getGeoTag(os.path.join(photos_folder, 'notags.JPG')) + tag, ok = QgsExifTools.getGeoTag(os.path.join(photos_folder, "notags.JPG")) self.assertFalse(ok) - tag, ok = QgsExifTools.getGeoTag(os.path.join(photos_folder, 'not_photo.jpg')) + tag, ok = QgsExifTools.getGeoTag(os.path.join(photos_folder, "not_photo.jpg")) self.assertFalse(ok) def testTagging(self): - self.assertFalse(QgsExifTools.geoTagImage('', QgsPointXY(1, 2))) - self.assertFalse(QgsExifTools.geoTagImage('not a path', QgsPointXY(1, 2))) + self.assertFalse(QgsExifTools.geoTagImage("", QgsPointXY(1, 2))) + self.assertFalse(QgsExifTools.geoTagImage("not a path", QgsPointXY(1, 2))) - src_photo = os.path.join(TEST_DATA_DIR, 'photos', 'notags.JPG') + src_photo = os.path.join(TEST_DATA_DIR, "photos", "notags.JPG") tmpFile = QTemporaryFile() tmpFile.open() @@ -76,14 +85,14 @@ def testTagging(self): self.assertTrue(QgsExifTools.geoTagImage(tmpName, QgsPointXY(1.1, 3.3))) tag, ok = QgsExifTools.getGeoTag(tmpName) self.assertTrue(ok) - self.assertEqual(tag.asWkt(6), 'Point (1.1 3.3)') + self.assertEqual(tag.asWkt(6), "Point (1.1 3.3)") os.remove(tmpName) shutil.copy(src_photo, tmpName) self.assertTrue(QgsExifTools.geoTagImage(tmpName, QgsPointXY(-1.1, -3.3))) tag, ok = QgsExifTools.getGeoTag(tmpName) self.assertTrue(ok) - self.assertEqual(tag.asWkt(6), 'Point (-1.1 -3.3)') + self.assertEqual(tag.asWkt(6), "Point (-1.1 -3.3)") os.remove(tmpName) shutil.copy(src_photo, tmpName) @@ -92,7 +101,7 @@ def testTagging(self): self.assertTrue(QgsExifTools.geoTagImage(tmpName, QgsPointXY(1.1, 3.3), deets)) tag, ok = QgsExifTools.getGeoTag(tmpName) self.assertTrue(ok) - self.assertEqual(tag.asWkt(6), 'Point Z (1.1 3.3 110.1)') + self.assertEqual(tag.asWkt(6), "Point Z (1.1 3.3 110.1)") os.remove(tmpName) shutil.copy(src_photo, tmpName) @@ -101,18 +110,20 @@ def testTagging(self): self.assertTrue(QgsExifTools.geoTagImage(tmpName, QgsPointXY(1.1, 3.3), deets)) tag, ok = QgsExifTools.getGeoTag(tmpName) self.assertTrue(ok) - self.assertEqual(tag.asWkt(6), 'Point Z (1.1 3.3 -110.1)') + self.assertEqual(tag.asWkt(6), "Point Z (1.1 3.3 -110.1)") os.remove(tmpName) shutil.copy(src_photo, tmpName) - self.assertTrue(QgsExifTools.tagImage(tmpName, 'Exif.Photo.ShutterSpeedValue', 5.333)) - self.assertTrue(QgsExifTools.tagImage(tmpName, 'Xmp.dc.Format', 'image/jpeg')) - value = QgsExifTools.readTag(tmpName, 'Exif.Photo.ShutterSpeedValue') + self.assertTrue( + QgsExifTools.tagImage(tmpName, "Exif.Photo.ShutterSpeedValue", 5.333) + ) + self.assertTrue(QgsExifTools.tagImage(tmpName, "Xmp.dc.Format", "image/jpeg")) + value = QgsExifTools.readTag(tmpName, "Exif.Photo.ShutterSpeedValue") self.assertEqual(value, 5.333) - value = QgsExifTools.readTag(tmpName, 'Xmp.dc.Format') - self.assertEqual(value, 'image/jpeg') + value = QgsExifTools.readTag(tmpName, "Xmp.dc.Format") + self.assertEqual(value, "image/jpeg") os.remove(tmpName) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsexpression.py b/tests/src/python/test_qgsexpression.py index 2ec2a60766ba..49041040b5b8 100644 --- a/tests/src/python/test_qgsexpression.py +++ b/tests/src/python/test_qgsexpression.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nathan Woodrow' -__date__ = '4/11/2012' -__copyright__ = 'Copyright 2012, The QGIS Project' + +__author__ = "Nathan Woodrow" +__date__ = "4/11/2012" +__copyright__ = "Copyright 2012, The QGIS Project" from qgis.PyQt.QtCore import QVariant from qgis.core import ( @@ -28,110 +29,119 @@ class TestQgsExpressionCustomFunctions(unittest.TestCase): - @qgsfunction(1, 'testing', register=False) + @qgsfunction(1, "testing", register=False) def testfun(values, feature, parent): - """ Function help """ + """Function help""" return f"Testing_{values[0]}" - @qgsfunction(args="auto", group='testing', register=False) + @qgsfunction(args="auto", group="testing", register=False) def expandargs(value1, value2, value3, feature, parent): return value1, value2, value3 - @qgsfunction(args=0, group='testing', register=False) + @qgsfunction(args=0, group="testing", register=False) def special(values, feature, parent): return "test" - @qgsfunction(1, 'testing', register=False) + @qgsfunction(1, "testing", register=False) def sqrt(values, feature, parent): pass - @qgsfunction(1, 'testing', register=False) + @qgsfunction(1, "testing", register=False) def help_with_docstring(values, feature, parent): """The help comes from the python docstring.""" pass - help_text = 'The help comes from a variable.' + help_text = "The help comes from a variable." - @qgsfunction(1, 'testing', register=False, helpText=help_text) + @qgsfunction(1, "testing", register=False, helpText=help_text) def help_with_variable(values, feature, parent): """This docstring is not used for the help.""" pass - @qgsfunction(1, 'testing', register=False, usesgeometry=True) + @qgsfunction(1, "testing", register=False, usesgeometry=True) def geomtest(values, feature, parent): pass - @qgsfunction(args=0, group='testing', register=False) + @qgsfunction(args=0, group="testing", register=False) def no_referenced_columns_set(values, feature, parent): return 1 - @qgsfunction(args=0, group='testing', register=False, referenced_columns=['a', 'b']) + @qgsfunction(args=0, group="testing", register=False, referenced_columns=["a", "b"]) def referenced_columns_set(values, feature, parent): return 2 - @qgsfunction(args=-1, group='testing', register=False, handlesnull=True) + @qgsfunction(args=-1, group="testing", register=False, handlesnull=True) def null_mean(values, feature, parent): vals = [val for val in values if val != NULL] return sum(vals) / len(vals) - @qgsfunction(group='testing', register=False) + @qgsfunction(group="testing", register=False) def raise_exception(feature, parent): # an undefined variable foo # noqa: F821 - @qgsfunction(group='testing', register=False) + @qgsfunction(group="testing", register=False) def simple_sum(val1, val2): return val1 + val2 - @qgsfunction(group='testing', register=False) + @qgsfunction(group="testing", register=False) def sum_vargs(val1, *args): return val1 + sum(args) - @qgsfunction(group='testing', args=-1, register=False) + @qgsfunction(group="testing", args=-1, register=False) def func_params_as_list_legacy(values, feature, parent): return values - @qgsfunction(group='testing', params_as_list=True, register=False) + @qgsfunction(group="testing", params_as_list=True, register=False) def func_params_as_list(values): return values - @qgsfunction(group='testing', register=False) + @qgsfunction(group="testing", register=False) def func_params_no_list(values): return values - @qgsfunction(group='testing', register=False) + @qgsfunction(group="testing", register=False) def func_feature(*args, feature): return (feature["a"] + sum(args)) * feature["b"] - @qgsfunction(group='testing', register=False) + @qgsfunction(group="testing", register=False) def func_layer_name_operation(operation="upper", context=None): return getattr(context.variable("layer_name"), operation)() def tearDown(self): - QgsExpression.unregisterFunction('testfun') + QgsExpression.unregisterFunction("testfun") def testCanBeRegistered(self): QgsExpression.registerFunction(self.testfun) - index = QgsExpression.functionIndex('testfun') + index = QgsExpression.functionIndex("testfun") self.assertNotEqual(index, -1) def testHelpPythonFunction(self): """Test help about python function.""" QgsExpression.registerFunction(self.help_with_variable) - html = ('

    help_with_variable function


    ' - 'The help comes from a variable.') + html = ( + "

    help_with_variable function


    " "The help comes from a variable." + ) self.assertEqual(self.help_with_variable.helpText(), html) QgsExpression.registerFunction(self.help_with_docstring) - html = ('

    help_with_docstring function


    ' - 'The help comes from the python docstring.') + html = ( + "

    help_with_docstring function


    " + "The help comes from the python docstring." + ) self.assertEqual(self.help_with_docstring.helpText(), html) def testHelpString(self): """Test add custom help string.""" - self.assertTrue(QgsExpression.addVariableHelpText("custom_variable_help", "custom help 1")) - self.assertFalse(QgsExpression.addVariableHelpText("custom_variable_help", "other help 2")) - self.assertEqual(QgsExpression.variableHelpText("custom_variable_help"), "custom help 1") + self.assertTrue( + QgsExpression.addVariableHelpText("custom_variable_help", "custom help 1") + ) + self.assertFalse( + QgsExpression.addVariableHelpText("custom_variable_help", "other help 2") + ) + self.assertEqual( + QgsExpression.variableHelpText("custom_variable_help"), "custom help 1" + ) def testAutoArgsAreExpanded(self): function = self.expandargs @@ -144,31 +154,31 @@ def testAutoArgsAreExpanded(self): def testCanUnregisterFunction(self): QgsExpression.registerFunction(self.testfun) - index = QgsExpression.functionIndex('testfun') + index = QgsExpression.functionIndex("testfun") self.assertNotEqual(index, -1) - error = QgsExpression.unregisterFunction('testfun') + error = QgsExpression.unregisterFunction("testfun") self.assertTrue(error) - index = QgsExpression.functionIndex('testfun') + index = QgsExpression.functionIndex("testfun") self.assertEqual(index, -1) def testCanEvaluateFunction(self): QgsExpression.registerFunction(self.testfun) - exp = QgsExpression('testfun(1)') + exp = QgsExpression("testfun(1)") result = exp.evaluate() - self.assertEqual('Testing_1', result) + self.assertEqual("Testing_1", result) def testZeroArgFunctionsTakeNoArgs(self): QgsExpression.registerFunction(self.special) special = self.special - self.assertEqual(special.name(), 'special') - exp = QgsExpression('special()') + self.assertEqual(special.name(), "special") + exp = QgsExpression("special()") result = exp.evaluate() - self.assertEqual('test', result) + self.assertEqual("test", result) def testDecoratorPreservesAttributes(self): func = self.testfun - self.assertEqual(func.name(), 'testfun') - self.assertEqual(func.group(), 'testing') + self.assertEqual(func.name(), "testfun") + self.assertEqual(func.group(), "testing") def testCantReregister(self): QgsExpression.registerFunction(self.testfun) @@ -191,19 +201,18 @@ def testCanRegisterGeometryFunction(self): def testReferencedColumnsNoSet(self): QgsExpression.registerFunction(self.no_referenced_columns_set) - exp = QgsExpression('no_referenced_columns_set()') - self.assertEqual(exp.referencedColumns(), - {QgsFeatureRequest.ALL_ATTRIBUTES}) + exp = QgsExpression("no_referenced_columns_set()") + self.assertEqual(exp.referencedColumns(), {QgsFeatureRequest.ALL_ATTRIBUTES}) def testReferencedColumnsSet(self): QgsExpression.registerFunction(self.referenced_columns_set) - exp = QgsExpression('referenced_columns_set()') - self.assertEqual(set(exp.referencedColumns()), {'a', 'b'}) + exp = QgsExpression("referenced_columns_set()") + self.assertEqual(set(exp.referencedColumns()), {"a", "b"}) def testHandlesNull(self): context = QgsExpressionContext() QgsExpression.registerFunction(self.null_mean) - exp = QgsExpression('null_mean(1, 2, NULL, 3)') + exp = QgsExpression("null_mean(1, 2, NULL, 3)") result = exp.evaluate(context) self.assertFalse(exp.hasEvalError()) self.assertEqual(result, 2) @@ -216,8 +225,8 @@ def testDump(self): for txt in [ "id", "idä", - "\"id abc\"", - "\"id abc\"", + '"id abc"', + '"id abc"', " abc ", " /* co */ da ", ]: @@ -225,20 +234,20 @@ def testDump(self): def testBlockComment(self): expressions = { - "'test' /* comment */": 'test', - "/* comment */'test'": 'test', - "/* comment */'test*/'": 'test*/', - "/** comment */'test*/'": 'test*/', - "/* comment **/'test*/' /* comment */": 'test*/', - "'test/*'/* comment */": 'test/*', + "'test' /* comment */": "test", + "/* comment */'test'": "test", + "/* comment */'test*/'": "test*/", + "/** comment */'test*/'": "test*/", + "/* comment **/'test*/' /* comment */": "test*/", + "'test/*'/* comment */": "test/*", """/** comment **/ - 'test*/'""": 'test*/', + 'test*/'""": "test*/", """'test*/' /** comment - **/""": 'test*/' + **/""": "test*/", } for e, exp_res in list(expressions.items()): exp = QgsExpression(e) @@ -247,12 +256,12 @@ def testBlockComment(self): def testComment(self): expressions = { - "'test' -- comment\n": 'test', - "'test--'\n": 'test--', - "'--test'\n": '--test', - "'test' -- comment": 'test', - "'test--'": 'test--', - "'--test'": '--test', + "'test' -- comment\n": "test", + "'test--'\n": "test--", + "'--test'\n": "--test", + "'test' -- comment": "test", + "'test--'": "test--", + "'--test'": "--test", } for e, exp_res in list(expressions.items()): exp = QgsExpression(e) @@ -262,9 +271,9 @@ def testComment(self): def testValid(self): e = QgsExpression() self.assertFalse(e.isValid()) - e.setExpression('asdf||#@¼') + e.setExpression("asdf||#@¼") self.assertFalse(e.isValid()) - e.setExpression('1') + e.setExpression("1") self.assertTrue(e.isValid()) def testCreateFieldEqualityExpression(self): @@ -290,8 +299,8 @@ def testCreateFieldEqualityExpression(self): # test when field name has a quote and value is a string field = "my'field" - value = '5' - res = '"my\'field" = \'5\'' + value = "5" + res = "\"my'field\" = '5'" self.assertEqual(e.createFieldEqualityExpression(field, value), res) # test when field name has a quote and value is a boolean @@ -304,7 +313,7 @@ def testCreateFieldEqualityExpression(self): field = "myfield" value = 1 type = QVariant.String - res = '"myfield" = \'1\'' + res = "\"myfield\" = '1'" self.assertEqual(e.createFieldEqualityExpression(field, value, type), res) # test with field type @@ -325,7 +334,9 @@ def testSuccessfulEvaluationReturnsNoEvalErrorString(self): self.assertEqual(exp.evalErrorString(), "") def testEvalTemplate(self): - layer = QgsVectorLayer("Point?field=a:int&field=b:string", "test eval-template", "memory") + layer = QgsVectorLayer( + "Point?field=a:int&field=b:string", "test eval-template", "memory" + ) context = layer.createExpressionContext() expression = QgsExpression("eval_template('123 [% \"b\" %] 789')") @@ -336,25 +347,25 @@ def testEvalTemplate(self): self.assertTrue(QgsFeatureRequest.ALL_ATTRIBUTES in columns) feature = QgsFeature(layer.fields()) - feature.setAttributes([1, '456']) + feature.setAttributes([1, "456"]) context.setFeature(feature) - self.assertEqual(expression.evaluate(context), '123 456 789') + self.assertEqual(expression.evaluate(context), "123 456 789") def testExceptionDuringEvalReturnsTraceback(self): QgsExpression.registerFunction(self.raise_exception) - exp = QgsExpression('raise_exception()') + exp = QgsExpression("raise_exception()") result = exp.evaluate() # The file paths and line offsets are dynamic regex = ( "name 'foo' is not defined:
    Traceback \\(most recent call last\\):\n"
    -            "  File \".*qgsfunction.py\", line [0-9]+, in func\n"
    +            '  File ".*qgsfunction.py", line [0-9]+, in func\n'
                 "    return self.function\\(\\*values, \\*\\*kwvalues\\)\n"
                 "(.*?\n)?"
    -            "  File \".*test_qgsexpression.py\", line [0-9]+, in raise_exception\n"
    +            '  File ".*test_qgsexpression.py", line [0-9]+, in raise_exception\n'
                 "    foo  # noqa: F821\n"
                 "(.*?\n)?"
    -            "NameError: name \'foo\' is not defined"
    +            "NameError: name 'foo' is not defined"
                 "\n
    " ) self.assertRegex(exp.evalErrorString(), regex) @@ -453,7 +464,9 @@ def testContext(self): QgsExpression.registerFunction(self.func_layer_name_operation) context = QgsExpressionContext() - layer = QgsVectorLayer("Point?field=a:int&field=b:string", "test context", "memory") + layer = QgsVectorLayer( + "Point?field=a:int&field=b:string", "test context", "memory" + ) context.appendScope(QgsExpressionContextUtils.layerScope(layer)) e = QgsExpression() @@ -468,22 +481,23 @@ def testLayerScopeVerticalCrs(self): layer = QgsVectorLayer("Point?field=fldtxt:string", "layer", "memory") # vertical crs info should be present in layer expression context scope - layer.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:5703')) + layer.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:5703")) scope = QgsExpressionContextUtils.layerScope(layer) - self.assertEqual(scope.variable('layer_vertical_crs'), 'EPSG:5703') - self.assertEqual(scope.variable('layer_vertical_crs_definition'), - '+vunits=m +no_defs') - self.assertEqual(scope.variable('layer_vertical_crs_description'), - 'NAVD88 height') - self.assertEqual(scope.variable('layer_vertical_crs_wkt')[:7], - 'VERTCRS') + self.assertEqual(scope.variable("layer_vertical_crs"), "EPSG:5703") + self.assertEqual( + scope.variable("layer_vertical_crs_definition"), "+vunits=m +no_defs" + ) + self.assertEqual( + scope.variable("layer_vertical_crs_description"), "NAVD88 height" + ) + self.assertEqual(scope.variable("layer_vertical_crs_wkt")[:7], "VERTCRS") layer.setVerticalCrs(QgsCoordinateReferenceSystem()) scope = QgsExpressionContextUtils.layerScope(layer) - self.assertFalse(scope.variable('layer_vertical_crs')) - self.assertFalse(scope.variable('layer_vertical_crs_definition')) - self.assertFalse(scope.variable('layer_vertical_crs_description')) - self.assertFalse(scope.variable('layer_vertical_crs_wkt')) + self.assertFalse(scope.variable("layer_vertical_crs")) + self.assertFalse(scope.variable("layer_vertical_crs_definition")) + self.assertFalse(scope.variable("layer_vertical_crs_description")) + self.assertFalse(scope.variable("layer_vertical_crs_wkt")) if __name__ == "__main__": diff --git a/tests/src/python/test_qgsexpressionbuilderwidget.py b/tests/src/python/test_qgsexpressionbuilderwidget.py index 7cb25c775077..1a8f8d7e1383 100644 --- a/tests/src/python/test_qgsexpressionbuilderwidget.py +++ b/tests/src/python/test_qgsexpressionbuilderwidget.py @@ -5,15 +5,13 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '30/07/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "30/07/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtCore import Qt, QTemporaryDir -from qgis.PyQt.QtWidgets import ( - QListView, - QListWidget -) +from qgis.PyQt.QtWidgets import QListView, QListWidget from qgis.core import ( QgsExpressionContext, QgsExpressionContextScope, @@ -25,17 +23,17 @@ from qgis.gui import QgsExpressionBuilderWidget import unittest from qgis.testing import start_app, QgisTestCase -from qgis.user import ( - default_expression_template, - expressionspath -) +from qgis.user import default_expression_template, expressionspath start_app() def createReferencingLayer(): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=foreignkey:integer", - "referencinglayer", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=foreignkey:integer", + "referencinglayer", + "memory", + ) pr = layer.dataProvider() f1 = QgsFeature() f1.setFields(layer.fields()) @@ -53,7 +51,9 @@ def createReferencingLayer(): def createReferencedLayer(): layer = QgsVectorLayer( "Point?field=x:string&field=y:integer&field=z:integer", - "referencedlayer", "memory") + "referencedlayer", + "memory", + ) pr = layer.dataProvider() f1 = QgsFeature() f1.setFields(layer.fields()) @@ -73,47 +73,49 @@ class TestQgsExpressionBuilderWidget(QgisTestCase): def setUp(self): self.referencedLayer = createReferencedLayer() self.referencingLayer = createReferencingLayer() - QgsProject.instance().addMapLayers([self.referencedLayer, self.referencingLayer]) + QgsProject.instance().addMapLayers( + [self.referencedLayer, self.referencingLayer] + ) def testFunctionPresent(self): - """ check through widget model to ensure it is initially populated with functions """ + """check through widget model to ensure it is initially populated with functions""" w = QgsExpressionBuilderWidget() m = w.expressionTree().model().sourceModel() # check that some standard expression functions are shown - items = m.findItems('lower', Qt.MatchFlag.MatchRecursive) + items = m.findItems("lower", Qt.MatchFlag.MatchRecursive) self.assertEqual(len(items), 1) - items = m.findItems('upper', Qt.MatchFlag.MatchRecursive) + items = m.findItems("upper", Qt.MatchFlag.MatchRecursive) self.assertEqual(len(items), 1) - items = m.findItems('asdasdasda#$@#$', Qt.MatchFlag.MatchRecursive) + items = m.findItems("asdasdasda#$@#$", Qt.MatchFlag.MatchRecursive) self.assertEqual(len(items), 0) def testVariables(self): - """ check through widget model to ensure it is populated with variables """ + """check through widget model to ensure it is populated with variables""" w = QgsExpressionBuilderWidget() m = w.expressionTree().model().sourceModel() s = QgsExpressionContextScope() - s.setVariable('my_var1', 'x') - s.setVariable('my_var2', 'y') + s.setVariable("my_var1", "x") + s.setVariable("my_var2", "y") c = QgsExpressionContext() c.appendScope(s) # check that variables are added when setting context w.setExpressionContext(c) - items = m.findItems('my_var1', Qt.MatchFlag.MatchRecursive) + items = m.findItems("my_var1", Qt.MatchFlag.MatchRecursive) self.assertEqual(len(items), 1) - items = m.findItems('my_var2', Qt.MatchFlag.MatchRecursive) + items = m.findItems("my_var2", Qt.MatchFlag.MatchRecursive) self.assertEqual(len(items), 1) - items = m.findItems('not_my_var', Qt.MatchFlag.MatchRecursive) + items = m.findItems("not_my_var", Qt.MatchFlag.MatchRecursive) self.assertEqual(len(items), 0) # double check that functions are still only there once - items = m.findItems('lower', Qt.MatchFlag.MatchRecursive) + items = m.findItems("lower", Qt.MatchFlag.MatchRecursive) self.assertEqual(len(items), 1) - items = m.findItems('upper', Qt.MatchFlag.MatchRecursive) + items = m.findItems("upper", Qt.MatchFlag.MatchRecursive) self.assertEqual(len(items), 1) def testLayers(self): - """ check that layers are shown in widget model""" + """check that layers are shown in widget model""" p = QgsProject.instance() layer = QgsVectorLayer("Point", "layer1", "memory") layer2 = QgsVectorLayer("Point", "layer2", "memory") @@ -123,9 +125,9 @@ def testLayers(self): m = w.expressionTree().model().sourceModel() # check that layers are shown - items = m.findItems('layer1', Qt.MatchFlag.MatchRecursive) + items = m.findItems("layer1", Qt.MatchFlag.MatchRecursive) self.assertEqual(len(items), 1) - items = m.findItems('layer2', Qt.MatchFlag.MatchRecursive) + items = m.findItems("layer2", Qt.MatchFlag.MatchRecursive) self.assertEqual(len(items), 1) # change project @@ -134,31 +136,31 @@ def testLayers(self): p2.addMapLayers([layer3]) w.setProject(p2) m = w.expressionTree().model().sourceModel() - items = m.findItems('layer1', Qt.MatchFlag.MatchRecursive) + items = m.findItems("layer1", Qt.MatchFlag.MatchRecursive) self.assertEqual(len(items), 0) - items = m.findItems('layer2', Qt.MatchFlag.MatchRecursive) + items = m.findItems("layer2", Qt.MatchFlag.MatchRecursive) self.assertEqual(len(items), 0) - items = m.findItems('layer3', Qt.MatchFlag.MatchRecursive) + items = m.findItems("layer3", Qt.MatchFlag.MatchRecursive) self.assertEqual(len(items), 1) def testRelations(self): - """ check that layers are shown in widget model""" + """check that layers are shown in widget model""" p = QgsProject.instance() # not valid, but doesn't matter for test.... rel = QgsRelation() - rel.setId('rel1') - rel.setName('Relation Number One') + rel.setId("rel1") + rel.setName("Relation Number One") rel.setReferencingLayer(self.referencingLayer.id()) rel.setReferencedLayer(self.referencedLayer.id()) - rel.addFieldPair('foreignkey', 'y') + rel.addFieldPair("foreignkey", "y") rel2 = QgsRelation() - rel2.setId('rel2') - rel2.setName('Relation Number Two') + rel2.setId("rel2") + rel2.setName("Relation Number Two") rel2.setReferencingLayer(self.referencingLayer.id()) rel2.setReferencedLayer(self.referencedLayer.id()) - rel2.addFieldPair('foreignkey', 'y') + rel2.addFieldPair("foreignkey", "y") p.relationManager().addRelation(rel) p.relationManager().addRelation(rel2) @@ -167,9 +169,9 @@ def testRelations(self): m = w.expressionTree().model().sourceModel() # check that relations are shown - items = m.findItems('Relation Number One', Qt.MatchFlag.MatchRecursive) + items = m.findItems("Relation Number One", Qt.MatchFlag.MatchRecursive) self.assertEqual(len(items), 1) - items = m.findItems('Relation Number Two', Qt.MatchFlag.MatchRecursive) + items = m.findItems("Relation Number Two", Qt.MatchFlag.MatchRecursive) self.assertEqual(len(items), 1) def testStoredExpressions(self): @@ -177,33 +179,39 @@ def testStoredExpressions(self): w = QgsExpressionBuilderWidget() - w.expressionTree().saveToUserExpressions('Stored Expression Number One', '"field_one" = 123', "An humble expression") - items = w.findExpressions('Stored Expression Number One') + w.expressionTree().saveToUserExpressions( + "Stored Expression Number One", '"field_one" = 123', "An humble expression" + ) + items = w.findExpressions("Stored Expression Number One") self.assertEqual(len(items), 1) exp = items[0] self.assertEqual(exp.getExpressionText(), '"field_one" = 123') # Add another one with the same name (overwrite) - w.expressionTree().saveToUserExpressions('Stored Expression Number One', '"field_two" = 456', "An even more humble expression") - items = w.findExpressions('Stored Expression Number One') + w.expressionTree().saveToUserExpressions( + "Stored Expression Number One", + '"field_two" = 456', + "An even more humble expression", + ) + items = w.findExpressions("Stored Expression Number One") self.assertEqual(len(items), 1) exp = items[0] self.assertEqual(exp.getExpressionText(), '"field_two" = 456') # Reload by creating a new widget w = QgsExpressionBuilderWidget() - items = w.findExpressions('Stored Expression Number One') + items = w.findExpressions("Stored Expression Number One") self.assertEqual(len(items), 1) exp = items[0] self.assertEqual(exp.getExpressionText(), '"field_two" = 456') # Test removal - w.expressionTree().removeFromUserExpressions('Stored Expression Number One') - items = w.findExpressions('Stored Expression Number One') + w.expressionTree().removeFromUserExpressions("Stored Expression Number One") + items = w.findExpressions("Stored Expression Number One") self.assertEqual(len(items), 0) def testLayerVariables(self): - """ check through widget model to ensure it is populated with layer variables """ + """check through widget model to ensure it is populated with layer variables""" w = QgsExpressionBuilderWidget() m = w.expressionTree().model().sourceModel() @@ -229,7 +237,7 @@ def testValuesList(self): w = QgsExpressionBuilderWidget() - valuesList = w.findChild(QListView, 'mValuesListView') + valuesList = w.findChild(QListView, "mValuesListView") self.assertTrue(valuesList) valuesModel = valuesList.model() @@ -237,16 +245,20 @@ def testValuesList(self): layer = QgsVectorLayer( "None?field=myarray:string[]&field=mystr:string&field=myint:integer&field=myintarray:int[]&field=mydoublearray:double[]&field=mybool:boolean(0,0)", - "arraylayer", "memory") + "arraylayer", + "memory", + ) self.assertTrue(layer.isValid()) # add some features, one has invalid geometry pr = layer.dataProvider() f1 = QgsFeature(1) - f1.setAttributes([["one 'item'", 'B'], "another 'item'", 0, [1, 2], [1.1, 2.1], True]) + f1.setAttributes( + [["one 'item'", "B"], "another 'item'", 0, [1, 2], [1.1, 2.1], True] + ) f2 = QgsFeature(2) - f2.setAttributes([['C'], "", 1, [3, 4], [-0.1, 2.0], False]) + f2.setAttributes([["C"], "", 1, [3, 4], [-0.1, 2.0], False]) f3 = QgsFeature(3) f3.setAttributes([[], "test", 2, [], [], False]) f4 = QgsFeature(4) @@ -264,11 +276,31 @@ def testValuesList(self): w.loadAllValues() - datas = sorted([(valuesModel.data(valuesModel.index(i, 0), Qt.ItemDataRole.DisplayRole), valuesModel.data(valuesModel.index(i, 0), Qt.ItemDataRole.UserRole + 1)) for i in range(4)]) - self.assertEqual(datas, [(" [array()]", "array()"), - ("C [array('C')]", "array('C')"), - ("NULL [NULL]", "NULL"), - ("one 'item', B [array('one ''item''', 'B')]", "array('one ''item''', 'B')")]) + datas = sorted( + [ + ( + valuesModel.data( + valuesModel.index(i, 0), Qt.ItemDataRole.DisplayRole + ), + valuesModel.data( + valuesModel.index(i, 0), Qt.ItemDataRole.UserRole + 1 + ), + ) + for i in range(4) + ] + ) + self.assertEqual( + datas, + [ + (" [array()]", "array()"), + ("C [array('C')]", "array('C')"), + ("NULL [NULL]", "NULL"), + ( + "one 'item', B [array('one ''item''', 'B')]", + "array('one ''item''', 'B')", + ), + ], + ) # test string items = w.expressionTree().findExpressions("mystr") @@ -280,12 +312,29 @@ def testValuesList(self): w.loadAllValues() - datas = sorted([(valuesModel.data(valuesModel.index(i, 0), Qt.ItemDataRole.DisplayRole), valuesModel.data(valuesModel.index(i, 0), Qt.ItemDataRole.UserRole + 1)) for i in range(4)]) - - self.assertEqual(datas, [("", "''"), - ("NULL [NULL]", "NULL"), - ("another 'item'", "'another ''item'''"), - ("test", "'test'")]) + datas = sorted( + [ + ( + valuesModel.data( + valuesModel.index(i, 0), Qt.ItemDataRole.DisplayRole + ), + valuesModel.data( + valuesModel.index(i, 0), Qt.ItemDataRole.UserRole + 1 + ), + ) + for i in range(4) + ] + ) + + self.assertEqual( + datas, + [ + ("", "''"), + ("NULL [NULL]", "NULL"), + ("another 'item'", "'another ''item'''"), + ("test", "'test'"), + ], + ) # test int items = w.expressionTree().findExpressions("myint") @@ -297,12 +346,23 @@ def testValuesList(self): w.loadAllValues() - datas = sorted([(valuesModel.data(valuesModel.index(i, 0), Qt.ItemDataRole.DisplayRole), valuesModel.data(valuesModel.index(i, 0), Qt.ItemDataRole.UserRole + 1)) for i in range(4)]) - - self.assertEqual(datas, [("0", "0"), - ("1", "1"), - ("2", "2"), - ("NULL [NULL]", "NULL")]) + datas = sorted( + [ + ( + valuesModel.data( + valuesModel.index(i, 0), Qt.ItemDataRole.DisplayRole + ), + valuesModel.data( + valuesModel.index(i, 0), Qt.ItemDataRole.UserRole + 1 + ), + ) + for i in range(4) + ] + ) + + self.assertEqual( + datas, [("0", "0"), ("1", "1"), ("2", "2"), ("NULL [NULL]", "NULL")] + ) # test int array items = w.expressionTree().findExpressions("myintarray") @@ -314,12 +374,28 @@ def testValuesList(self): w.loadAllValues() - datas = sorted([(valuesModel.data(valuesModel.index(i, 0), Qt.ItemDataRole.DisplayRole), valuesModel.data(valuesModel.index(i, 0), Qt.ItemDataRole.UserRole + 1)) for i in range(4)]) - self.assertEqual(datas, [(" [array()]", "array()"), - ("1, 2 [array(1, 2)]", "array(1, 2)"), - ("3, 4 [array(3, 4)]", "array(3, 4)"), - ("NULL [NULL]", "NULL"), - ]) + datas = sorted( + [ + ( + valuesModel.data( + valuesModel.index(i, 0), Qt.ItemDataRole.DisplayRole + ), + valuesModel.data( + valuesModel.index(i, 0), Qt.ItemDataRole.UserRole + 1 + ), + ) + for i in range(4) + ] + ) + self.assertEqual( + datas, + [ + (" [array()]", "array()"), + ("1, 2 [array(1, 2)]", "array(1, 2)"), + ("3, 4 [array(3, 4)]", "array(3, 4)"), + ("NULL [NULL]", "NULL"), + ], + ) # test double array items = w.expressionTree().findExpressions("mydoublearray") @@ -331,12 +407,28 @@ def testValuesList(self): w.loadAllValues() - datas = sorted([(valuesModel.data(valuesModel.index(i, 0), Qt.ItemDataRole.DisplayRole), valuesModel.data(valuesModel.index(i, 0), Qt.ItemDataRole.UserRole + 1)) for i in range(4)]) - self.assertEqual(datas, [(" [array()]", "array()"), - ("-0.1, 2 [array(-0.1, 2)]", "array(-0.1, 2)"), - ("1.1, 2.1 [array(1.1, 2.1)]", "array(1.1, 2.1)"), - ("NULL [NULL]", "NULL"), - ]) + datas = sorted( + [ + ( + valuesModel.data( + valuesModel.index(i, 0), Qt.ItemDataRole.DisplayRole + ), + valuesModel.data( + valuesModel.index(i, 0), Qt.ItemDataRole.UserRole + 1 + ), + ) + for i in range(4) + ] + ) + self.assertEqual( + datas, + [ + (" [array()]", "array()"), + ("-0.1, 2 [array(-0.1, 2)]", "array(-0.1, 2)"), + ("1.1, 2.1 [array(1.1, 2.1)]", "array(1.1, 2.1)"), + ("NULL [NULL]", "NULL"), + ], + ) # test boolean items = w.expressionTree().findExpressions("mybool") @@ -348,15 +440,26 @@ def testValuesList(self): w.loadAllValues() - datas = [(valuesModel.data(valuesModel.index(i, 0), Qt.ItemDataRole.DisplayRole), valuesModel.data(valuesModel.index(i, 0), Qt.ItemDataRole.UserRole + 1)) for i in range(4)] + datas = [ + ( + valuesModel.data(valuesModel.index(i, 0), Qt.ItemDataRole.DisplayRole), + valuesModel.data(valuesModel.index(i, 0), Qt.ItemDataRole.UserRole + 1), + ) + for i in range(4) + ] datas.remove((None, None)) datas.sort() datas.append((None, None)) - self.assertEqual(datas, [("NULL [NULL]", "NULL"), - ("false", "false"), - ("true", "true"), - (None, None)]) + self.assertEqual( + datas, + [ + ("NULL [NULL]", "NULL"), + ("false", "false"), + ("true", "true"), + (None, None), + ], + ) def testProjectFunctions(self): """ @@ -366,7 +469,7 @@ def testProjectFunctions(self): # Test function editor lists project functions project = QgsProject.instance() w = QgsExpressionBuilderWidget() - functionFileList = w.findChild(QListWidget, 'cmbFileNames') + functionFileList = w.findChild(QListWidget, "cmbFileNames") self.assertIsNotNone(functionFileList) self.assertFalse(functionFileList.selectedItems()) @@ -406,5 +509,5 @@ def my_sum_2(value1, value2): self.assertEqual(code, projectEntry) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsexpressionlineedit.py b/tests/src/python/test_qgsexpressionlineedit.py index d47845dec939..e6adefae5369 100644 --- a/tests/src/python/test_qgsexpressionlineedit.py +++ b/tests/src/python/test_qgsexpressionlineedit.py @@ -5,13 +5,15 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '20/08/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "20/08/2016" +__copyright__ = "Copyright 2016, The QGIS Project" try: from qgis.PyQt.QtTest import QSignalSpy + use_signal_spy = True except: use_signal_spy = False @@ -26,47 +28,47 @@ class TestQgsExpressionLineEdit(QgisTestCase): def testDialog(self): - """ test dialog related methods """ + """test dialog related methods""" w = QgsExpressionLineEdit() - w.setExpressionDialogTitle('test') - self.assertEqual(w.expressionDialogTitle(), 'test') + w.setExpressionDialogTitle("test") + self.assertEqual(w.expressionDialogTitle(), "test") def testSetGetExpression(self): - """ test setting and getting expression """ + """test setting and getting expression""" w = QgsExpressionLineEdit() self.assertFalse(w.expression()) - w.setExpression('1+2') - self.assertEqual(w.expression(), '1+2') + w.setExpression("1+2") + self.assertEqual(w.expression(), "1+2") result, error = w.isValidExpression() self.assertTrue(result) - w.setExpression('1+') - self.assertEqual(w.expression(), '1+') + w.setExpression("1+") + self.assertEqual(w.expression(), "1+") result, error = w.isValidExpression() self.assertFalse(result) self.assertTrue(error) # try with a multiline widget too w.setMultiLine(True) - self.assertEqual(w.expression(), '1+') - w.setExpression('1+3') - self.assertEqual(w.expression(), '1+3') + self.assertEqual(w.expression(), "1+") + w.setExpression("1+3") + self.assertEqual(w.expression(), "1+3") # and flip back again... w.setMultiLine(False) - self.assertEqual(w.expression(), '1+3') + self.assertEqual(w.expression(), "1+3") @unittest.skipIf(not use_signal_spy, "No QSignalSpy available") def test_ChangedSignals(self): - """ test that signals are correctly emitted when changing expressions""" + """test that signals are correctly emitted when changing expressions""" w = QgsExpressionLineEdit() expression_changed_spy = QSignalSpy(w.expressionChanged) - w.setExpression('1+1') + w.setExpression("1+1") self.assertEqual(len(expression_changed_spy), 1) - self.assertEqual(expression_changed_spy[0][0], '1+1') + self.assertEqual(expression_changed_spy[0][0], "1+1") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsexpressionpreviewwidget.py b/tests/src/python/test_qgsexpressionpreviewwidget.py index 3f737dbdf1d6..e6b2c135d9aa 100644 --- a/tests/src/python/test_qgsexpressionpreviewwidget.py +++ b/tests/src/python/test_qgsexpressionpreviewwidget.py @@ -8,10 +8,7 @@ from qgis.PyQt.QtWidgets import QToolButton from qgis.gui import QgsExpressionPreviewWidget -from qgis.core import ( - QgsExpressionContext, - QgsExpressionContextScope -) +from qgis.core import QgsExpressionContext, QgsExpressionContextScope import unittest from qgis.testing import start_app, QgisTestCase @@ -24,44 +21,45 @@ def test_custom_mode(self): """ Test using a custom preview generator with the widget """ + def make_context(value): res = QgsExpressionContext() scope = QgsExpressionContextScope() - scope.setVariable('test', value) - scope.setVariable('test2', value * 2) + scope.setVariable("test", value) + scope.setVariable("test2", value * 2) res.appendScope(scope) return res w = QgsExpressionPreviewWidget() - w.setCustomPreviewGenerator('Band', - [['Band 1', 1], ['Band 2', 2], ['Band 3', 3]], - make_context) + w.setCustomPreviewGenerator( + "Band", [["Band 1", 1], ["Band 2", 2], ["Band 3", 3]], make_context + ) w.setExpressionText("@test * 5") - self.assertEqual(w.currentPreviewText(), '5') + self.assertEqual(w.currentPreviewText(), "5") w.setExpressionText("@test2 * 5") - self.assertEqual(w.currentPreviewText(), '10') + self.assertEqual(w.currentPreviewText(), "10") - next_button = w.findChild(QToolButton, 'mCustomButtonNext') - prev_button = w.findChild(QToolButton, 'mCustomButtonPrev') + next_button = w.findChild(QToolButton, "mCustomButtonNext") + prev_button = w.findChild(QToolButton, "mCustomButtonPrev") self.assertFalse(prev_button.isEnabled()) self.assertTrue(next_button.isEnabled()) next_button.click() - self.assertEqual(w.currentPreviewText(), '20') + self.assertEqual(w.currentPreviewText(), "20") self.assertTrue(prev_button.isEnabled()) self.assertTrue(next_button.isEnabled()) next_button.click() - self.assertEqual(w.currentPreviewText(), '30') + self.assertEqual(w.currentPreviewText(), "30") self.assertTrue(prev_button.isEnabled()) self.assertFalse(next_button.isEnabled()) prev_button.click() - self.assertEqual(w.currentPreviewText(), '20') + self.assertEqual(w.currentPreviewText(), "20") self.assertTrue(prev_button.isEnabled()) self.assertTrue(next_button.isEnabled()) prev_button.click() - self.assertEqual(w.currentPreviewText(), '10') + self.assertEqual(w.currentPreviewText(), "10") self.assertFalse(prev_button.isEnabled()) self.assertTrue(next_button.isEnabled()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsextentgroupbox.py b/tests/src/python/test_qgsextentgroupbox.py index 5d5f713a22f3..ffbe8170df27 100644 --- a/tests/src/python/test_qgsextentgroupbox.py +++ b/tests/src/python/test_qgsextentgroupbox.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '31/05/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "31/05/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os @@ -33,19 +34,23 @@ class TestQgsExtentGroupBox(QgisTestCase): def testGettersSetters(self): - """ test widget getters/setters """ + """test widget getters/setters""" w = QgsExtentGroupBox() - w.setOriginalExtent(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('epsg:3111')) + w.setOriginalExtent( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("epsg:3111") + ) self.assertEqual(w.originalExtent(), QgsRectangle(1, 2, 3, 4)) - self.assertEqual(w.originalCrs().authid(), 'EPSG:3111') + self.assertEqual(w.originalCrs().authid(), "EPSG:3111") - w.setCurrentExtent(QgsRectangle(11, 12, 13, 14), QgsCoordinateReferenceSystem('epsg:3113')) + w.setCurrentExtent( + QgsRectangle(11, 12, 13, 14), QgsCoordinateReferenceSystem("epsg:3113") + ) self.assertEqual(w.currentExtent(), QgsRectangle(11, 12, 13, 14)) - self.assertEqual(w.currentCrs().authid(), 'EPSG:3113') + self.assertEqual(w.currentCrs().authid(), "EPSG:3113") - w.setTitleBase('abc') - self.assertEqual(w.titleBase(), 'abc') + w.setTitleBase("abc") + self.assertEqual(w.titleBase(), "abc") def test_checkstate(self): w = QgsExtentGroupBox() @@ -60,7 +65,9 @@ def test_checkstate(self): self.assertTrue(w.outputExtent().isNull()) self.assertEqual(len(spy), 0) - w.setCurrentExtent(QgsRectangle(11, 12, 13, 14), QgsCoordinateReferenceSystem('epsg:3113')) + w.setCurrentExtent( + QgsRectangle(11, 12, 13, 14), QgsCoordinateReferenceSystem("epsg:3113") + ) w.setOutputExtentFromCurrent() self.assertTrue(w.isCheckable()) self.assertTrue(w.isChecked()) @@ -84,8 +91,12 @@ def test_SettingExtent(self): spy = QSignalSpy(w.extentChanged) - w.setOriginalExtent(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('epsg:3111')) - w.setCurrentExtent(QgsRectangle(11, 12, 13, 14), QgsCoordinateReferenceSystem('epsg:3113')) + w.setOriginalExtent( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("epsg:3111") + ) + w.setCurrentExtent( + QgsRectangle(11, 12, 13, 14), QgsCoordinateReferenceSystem("epsg:3113") + ) w.setOutputExtentFromOriginal() self.assertEqual(w.outputExtent(), QgsRectangle(1, 2, 3, 4)) @@ -97,13 +108,15 @@ def test_SettingExtent(self): self.assertEqual(w.extentState(), QgsExtentGroupBox.ExtentState.CurrentExtent) self.assertEqual(len(spy), 2) - w.setOutputExtentFromUser(QgsRectangle(21, 22, 23, 24), QgsCoordinateReferenceSystem('epsg:3111')) + w.setOutputExtentFromUser( + QgsRectangle(21, 22, 23, 24), QgsCoordinateReferenceSystem("epsg:3111") + ) self.assertEqual(w.outputExtent(), QgsRectangle(21, 22, 23, 24)) self.assertEqual(w.extentState(), QgsExtentGroupBox.ExtentState.UserExtent) self.assertEqual(len(spy), 3) - shapefile = os.path.join(TEST_DATA_DIR, 'polys.shp') - layer = QgsVectorLayer(shapefile, 'Polys', 'ogr') + shapefile = os.path.join(TEST_DATA_DIR, "polys.shp") + layer = QgsVectorLayer(shapefile, "Polys", "ogr") QgsProject.instance().addMapLayer(layer) w.setOutputExtentFromLayer(None) @@ -114,8 +127,13 @@ def test_SettingExtent(self): self.assertEqual(len(spy), 3) w.setOutputExtentFromLayer(layer) - self.assertEqual(w.outputExtent().toString(4), QgsRectangle(-118.9229, 24.5079, -83.7900, 46.7262).toString(4)) - self.assertEqual(w.extentState(), QgsExtentGroupBox.ExtentState.ProjectLayerExtent) + self.assertEqual( + w.outputExtent().toString(4), + QgsRectangle(-118.9229, 24.5079, -83.7900, 46.7262).toString(4), + ) + self.assertEqual( + w.extentState(), QgsExtentGroupBox.ExtentState.ProjectLayerExtent + ) self.assertEqual(len(spy), 4) QgsProject.instance().removeAllMapLayers() @@ -126,78 +144,109 @@ def testSetOutputCrs(self): # ensure setting output crs doesn't change state of group box w.setChecked(False) - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:4326")) self.assertFalse(w.isChecked()) w.setChecked(True) - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:4326")) self.assertTrue(w.isChecked()) - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) - w.setCurrentExtent(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('epsg:4326')) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:4326")) + w.setCurrentExtent( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("epsg:4326") + ) w.setOutputExtentFromCurrent() self.assertEqual(w.outputExtent(), QgsRectangle(1, 2, 3, 4)) # with reprojection - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:3785')) - self.assertEqual(w.outputExtent().toString(4), QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString(4)) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:3785")) + self.assertEqual( + w.outputExtent().toString(4), + QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString( + 4 + ), + ) # change CRS back - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:4326")) # extent should be back to current - not a reprojection of the reprojected bounds - self.assertEqual(w.outputExtent().toString(20), QgsRectangle(1, 2, 3, 4).toString(20)) + self.assertEqual( + w.outputExtent().toString(20), QgsRectangle(1, 2, 3, 4).toString(20) + ) # repeat, this time using original extents w = QgsExtentGroupBox() - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) - w.setOriginalExtent(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('epsg:4326')) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:4326")) + w.setOriginalExtent( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("epsg:4326") + ) w.setOutputExtentFromOriginal() self.assertEqual(w.outputExtent(), QgsRectangle(1, 2, 3, 4)) # with reprojection - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:3785')) - self.assertEqual(w.outputExtent().toString(4), - QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString(4)) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:3785")) + self.assertEqual( + w.outputExtent().toString(4), + QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString( + 4 + ), + ) # change CRS back - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:4326")) # extent should be back to original - not a reprojection of the reprojected bounds - self.assertEqual(w.outputExtent().toString(20), QgsRectangle(1, 2, 3, 4).toString(20)) + self.assertEqual( + w.outputExtent().toString(20), QgsRectangle(1, 2, 3, 4).toString(20) + ) # repeat, this time using layer extent - layer = QgsVectorLayer("Polygon?crs=epsg:4326", 'memory', 'memory') + layer = QgsVectorLayer("Polygon?crs=epsg:4326", "memory", "memory") self.assertTrue(layer.isValid()) f = QgsFeature() - f.setGeometry(QgsGeometry.fromWkt('Polygon((1 2, 3 2, 3 4, 1 4, 1 2))')) + f.setGeometry(QgsGeometry.fromWkt("Polygon((1 2, 3 2, 3 4, 1 4, 1 2))")) layer.dataProvider().addFeatures([f]) QgsProject.instance().addMapLayer(layer) - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:4326")) w.setOutputExtentFromLayer(layer) self.assertEqual(w.outputExtent(), QgsRectangle(1, 2, 3, 4)) - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:3785')) - self.assertEqual(w.outputExtent().toString(4), - QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString(4)) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:3785")) + self.assertEqual( + w.outputExtent().toString(4), + QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString( + 4 + ), + ) # change CRS back - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:4326")) # extent should be back to original - not a reprojection of the reprojected bounds - self.assertEqual(w.outputExtent().toString(20), QgsRectangle(1, 2, 3, 4).toString(20)) + self.assertEqual( + w.outputExtent().toString(20), QgsRectangle(1, 2, 3, 4).toString(20) + ) # custom extent w = QgsExtentGroupBox() - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) - w.setOutputExtentFromUser(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('epsg:4326')) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:4326")) + w.setOutputExtentFromUser( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("epsg:4326") + ) self.assertEqual(w.outputExtent(), QgsRectangle(1, 2, 3, 4)) # with reprojection - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:3785')) - self.assertEqual(w.outputExtent().toString(4), - QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString(4)) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:3785")) + self.assertEqual( + w.outputExtent().toString(4), + QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString( + 4 + ), + ) # change CRS back - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:4326")) # in this case we can't retrieve the original user extent in 4326, so we have a reprojection of the reprojected bounds # just test this by restricting the test to 4 decimals - self.assertEqual(w.outputExtent().toString(4), QgsRectangle(1, 2, 3, 4).toString(4)) + self.assertEqual( + w.outputExtent().toString(4), QgsRectangle(1, 2, 3, 4).toString(4) + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsextentwidget.py b/tests/src/python/test_qgsextentwidget.py index 7af30c46839e..0fa532f6b000 100644 --- a/tests/src/python/test_qgsextentwidget.py +++ b/tests/src/python/test_qgsextentwidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '25/03/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "25/03/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import os @@ -20,10 +21,7 @@ QgsRectangle, QgsVectorLayer, ) -from qgis.gui import ( - QgsExtentWidget, - QgsExtentGroupBox -) +from qgis.gui import QgsExtentWidget, QgsExtentGroupBox import unittest from qgis.testing import start_app, QgisTestCase @@ -36,23 +34,31 @@ class TestQgsExtentWidget(QgisTestCase): def testGettersSetters(self): - """ test widget getters/setters """ + """test widget getters/setters""" w = QgsExtentWidget() - w.setOriginalExtent(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('epsg:3111')) + w.setOriginalExtent( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("epsg:3111") + ) self.assertEqual(w.originalExtent(), QgsRectangle(1, 2, 3, 4)) - self.assertEqual(w.originalCrs().authid(), 'EPSG:3111') + self.assertEqual(w.originalCrs().authid(), "EPSG:3111") - w.setCurrentExtent(QgsRectangle(11, 12, 13, 14), QgsCoordinateReferenceSystem('epsg:3113')) + w.setCurrentExtent( + QgsRectangle(11, 12, 13, 14), QgsCoordinateReferenceSystem("epsg:3113") + ) self.assertEqual(w.currentExtent(), QgsRectangle(11, 12, 13, 14)) - self.assertEqual(w.currentCrs().authid(), 'EPSG:3113') + self.assertEqual(w.currentCrs().authid(), "EPSG:3113") def testValid(self): w = QgsExtentWidget() spy = QSignalSpy(w.validationChanged) self.assertFalse(w.isValid()) - w.setOriginalExtent(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('epsg:3111')) - w.setCurrentExtent(QgsRectangle(11, 12, 13, 14), QgsCoordinateReferenceSystem('epsg:3113')) + w.setOriginalExtent( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("epsg:3111") + ) + w.setCurrentExtent( + QgsRectangle(11, 12, 13, 14), QgsCoordinateReferenceSystem("epsg:3113") + ) w.setOutputExtentFromOriginal() self.assertEqual(len(spy), 1) self.assertTrue(w.isValid()) @@ -62,8 +68,12 @@ def test_SettingExtent(self): spy = QSignalSpy(w.extentChanged) - w.setOriginalExtent(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('epsg:3111')) - w.setCurrentExtent(QgsRectangle(11, 12, 13, 14), QgsCoordinateReferenceSystem('epsg:3113')) + w.setOriginalExtent( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("epsg:3111") + ) + w.setCurrentExtent( + QgsRectangle(11, 12, 13, 14), QgsCoordinateReferenceSystem("epsg:3113") + ) w.setOutputExtentFromOriginal() self.assertEqual(w.outputExtent(), QgsRectangle(1, 2, 3, 4)) @@ -75,13 +85,15 @@ def test_SettingExtent(self): self.assertEqual(w.extentState(), QgsExtentWidget.ExtentState.CurrentExtent) self.assertEqual(len(spy), 2) - w.setOutputExtentFromUser(QgsRectangle(21, 22, 23, 24), QgsCoordinateReferenceSystem('epsg:3111')) + w.setOutputExtentFromUser( + QgsRectangle(21, 22, 23, 24), QgsCoordinateReferenceSystem("epsg:3111") + ) self.assertEqual(w.outputExtent(), QgsRectangle(21, 22, 23, 24)) self.assertEqual(w.extentState(), QgsExtentWidget.ExtentState.UserExtent) self.assertEqual(len(spy), 3) - shapefile = os.path.join(TEST_DATA_DIR, 'polys.shp') - layer = QgsVectorLayer(shapefile, 'Polys', 'ogr') + shapefile = os.path.join(TEST_DATA_DIR, "polys.shp") + layer = QgsVectorLayer(shapefile, "Polys", "ogr") QgsProject.instance().addMapLayer(layer) w.setOutputExtentFromLayer(None) @@ -92,8 +104,13 @@ def test_SettingExtent(self): self.assertEqual(len(spy), 3) w.setOutputExtentFromLayer(layer) - self.assertEqual(w.outputExtent().toString(4), QgsRectangle(-118.9229, 24.5079, -83.7900, 46.7262).toString(4)) - self.assertEqual(w.extentState(), QgsExtentWidget.ExtentState.ProjectLayerExtent) + self.assertEqual( + w.outputExtent().toString(4), + QgsRectangle(-118.9229, 24.5079, -83.7900, 46.7262).toString(4), + ) + self.assertEqual( + w.extentState(), QgsExtentWidget.ExtentState.ProjectLayerExtent + ) self.assertEqual(len(spy), 4) QgsProject.instance().removeAllMapLayers() @@ -101,80 +118,115 @@ def test_SettingExtent(self): def testSetOutputCrs(self): w = QgsExtentWidget() - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) - w.setCurrentExtent(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('epsg:4326')) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:4326")) + w.setCurrentExtent( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("epsg:4326") + ) w.setOutputExtentFromCurrent() self.assertEqual(w.outputExtent(), QgsRectangle(1, 2, 3, 4)) # with reprojection - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:3785')) - self.assertEqual(w.outputExtent().toString(4), QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString(4)) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:3785")) + self.assertEqual( + w.outputExtent().toString(4), + QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString( + 4 + ), + ) # change CRS back - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:4326")) # extent should be back to current - not a reprojection of the reprojected bounds - self.assertEqual(w.outputExtent().toString(20), QgsRectangle(1, 2, 3, 4).toString(20)) + self.assertEqual( + w.outputExtent().toString(20), QgsRectangle(1, 2, 3, 4).toString(20) + ) # repeat, this time using original extents w = QgsExtentGroupBox() - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) - w.setOriginalExtent(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('epsg:4326')) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:4326")) + w.setOriginalExtent( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("epsg:4326") + ) w.setOutputExtentFromOriginal() self.assertEqual(w.outputExtent(), QgsRectangle(1, 2, 3, 4)) # with reprojection - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:3785')) - self.assertEqual(w.outputExtent().toString(4), - QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString(4)) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:3785")) + self.assertEqual( + w.outputExtent().toString(4), + QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString( + 4 + ), + ) # change CRS back - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:4326")) # extent should be back to original - not a reprojection of the reprojected bounds - self.assertEqual(w.outputExtent().toString(20), QgsRectangle(1, 2, 3, 4).toString(20)) + self.assertEqual( + w.outputExtent().toString(20), QgsRectangle(1, 2, 3, 4).toString(20) + ) # repeat, this time using layer extent - layer = QgsVectorLayer("Polygon?crs=epsg:4326", 'memory', 'memory') + layer = QgsVectorLayer("Polygon?crs=epsg:4326", "memory", "memory") self.assertTrue(layer.isValid()) f = QgsFeature() - f.setGeometry(QgsGeometry.fromWkt('Polygon((1 2, 3 2, 3 4, 1 4, 1 2))')) + f.setGeometry(QgsGeometry.fromWkt("Polygon((1 2, 3 2, 3 4, 1 4, 1 2))")) layer.dataProvider().addFeatures([f]) QgsProject.instance().addMapLayer(layer) - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:4326")) w.setOutputExtentFromLayer(layer) self.assertEqual(w.outputExtent(), QgsRectangle(1, 2, 3, 4)) - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:3785')) - self.assertEqual(w.outputExtent().toString(4), - QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString(4)) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:3785")) + self.assertEqual( + w.outputExtent().toString(4), + QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString( + 4 + ), + ) # change CRS back - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:4326")) # extent should be back to original - not a reprojection of the reprojected bounds - self.assertEqual(w.outputExtent().toString(20), QgsRectangle(1, 2, 3, 4).toString(20)) + self.assertEqual( + w.outputExtent().toString(20), QgsRectangle(1, 2, 3, 4).toString(20) + ) # custom extent w = QgsExtentGroupBox() - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) - w.setOutputExtentFromUser(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('epsg:4326')) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:4326")) + w.setOutputExtentFromUser( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("epsg:4326") + ) self.assertEqual(w.outputExtent(), QgsRectangle(1, 2, 3, 4)) # with reprojection - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:3785')) - self.assertEqual(w.outputExtent().toString(4), - QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString(4)) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:3785")) + self.assertEqual( + w.outputExtent().toString(4), + QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString( + 4 + ), + ) # change CRS back - w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) + w.setOutputCrs(QgsCoordinateReferenceSystem("epsg:4326")) # in this case we can't retrieve the original user extent in 4326, so we have a reprojection of the reprojected bounds # just test this by restricting the test to 4 decimals - self.assertEqual(w.outputExtent().toString(4), QgsRectangle(1, 2, 3, 4).toString(4)) + self.assertEqual( + w.outputExtent().toString(4), QgsRectangle(1, 2, 3, 4).toString(4) + ) def testClear(self): w = QgsExtentWidget() - w.setNullValueAllowed(True, 'test') + w.setNullValueAllowed(True, "test") valid_spy = QSignalSpy(w.validationChanged) changed_spy = QSignalSpy(w.extentChanged) self.assertFalse(w.isValid()) - w.setOriginalExtent(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('epsg:3111')) - w.setCurrentExtent(QgsRectangle(11, 12, 13, 14), QgsCoordinateReferenceSystem('epsg:3113')) + w.setOriginalExtent( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("epsg:3111") + ) + w.setCurrentExtent( + QgsRectangle(11, 12, 13, 14), QgsCoordinateReferenceSystem("epsg:3113") + ) w.setOutputExtentFromOriginal() self.assertEqual(len(valid_spy), 1) self.assertEqual(len(changed_spy), 1) @@ -196,5 +248,5 @@ def testClear(self): self.assertEqual(w.outputExtent(), QgsRectangle(1, 2, 3, 4)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsexternalstorage_base.py b/tests/src/python/test_qgsexternalstorage_base.py index 691c32bf772e..7ac87967b703 100644 --- a/tests/src/python/test_qgsexternalstorage_base.py +++ b/tests/src/python/test_qgsexternalstorage_base.py @@ -72,7 +72,8 @@ def tearDown(self): def getNewFile(self, content, with_special_characters=False): """Return a newly created temporary file with content - if with_special_characters is True then add url reserved characters in the file name""" + if with_special_characters is True then add url reserved characters in the file name + """ f = tempfile.NamedTemporaryFile( suffix=".txt", diff --git a/tests/src/python/test_qgsexternalstorage_simplecopy.py b/tests/src/python/test_qgsexternalstorage_simplecopy.py index 6387af7b96d8..0819a2ffe950 100644 --- a/tests/src/python/test_qgsexternalstorage_simplecopy.py +++ b/tests/src/python/test_qgsexternalstorage_simplecopy.py @@ -6,9 +6,9 @@ (at your option) any later version. """ -__author__ = 'Julien Cabieces' -__date__ = '31/03/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' +__author__ = "Julien Cabieces" +__date__ = "31/03/2021" +__copyright__ = "Copyright 2021, The QGIS Project" from qgis.PyQt.QtCore import QTemporaryDir from qgis.testing import unittest @@ -16,7 +16,9 @@ from test_qgsexternalstorage_base import TestPyQgsExternalStorageBase -class TestPyQgsExternalStorageSimpleCopy(TestPyQgsExternalStorageBase, unittest.TestCase): +class TestPyQgsExternalStorageSimpleCopy( + TestPyQgsExternalStorageBase, unittest.TestCase +): storageType = "SimpleCopy" badUrl = "/nothing/here/" @@ -24,7 +26,7 @@ class TestPyQgsExternalStorageSimpleCopy(TestPyQgsExternalStorageBase, unittest. @classmethod def setUpClass(cls): """Run before all tests:""" - super(TestPyQgsExternalStorageSimpleCopy, cls).setUpClass() + super().setUpClass() unittest.TestCase.setUpClass() cls.temp_dir = QTemporaryDir() @@ -34,7 +36,7 @@ def setUpClass(cls): def tearDownClass(cls): """Run after all tests""" cls.temp_dir = None - super(TestPyQgsExternalStorageSimpleCopy, cls).tearDownClass() + super().tearDownClass() unittest.TestCase.tearDownClass() def testStoreMissingAuth(self): @@ -42,5 +44,5 @@ def testStoreMissingAuth(self): pass -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsexternalstorage_webdav.py b/tests/src/python/test_qgsexternalstorage_webdav.py index f4cd13a174c2..ab5776c2bfe0 100644 --- a/tests/src/python/test_qgsexternalstorage_webdav.py +++ b/tests/src/python/test_qgsexternalstorage_webdav.py @@ -8,9 +8,9 @@ (at your option) any later version. """ -__author__ = 'Julien Cabieces' -__date__ = '31/03/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' +__author__ = "Julien Cabieces" +__date__ = "31/03/2021" +__copyright__ = "Copyright 2021, The QGIS Project" import os @@ -32,8 +32,10 @@ def setUpClass(cls): unittest.TestCase.setUpClass() cls.url = "http://{}:{}/webdav_tests".format( - os.environ.get('QGIS_WEBDAV_HOST', 'localhost'), os.environ.get('QGIS_WEBDAV_PORT', '80')) + os.environ.get("QGIS_WEBDAV_HOST", "localhost"), + os.environ.get("QGIS_WEBDAV_PORT", "80"), + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfeature.py b/tests/src/python/test_qgsfeature.py index a7afbd5c74a8..439ed97b93c0 100644 --- a/tests/src/python/test_qgsfeature.py +++ b/tests/src/python/test_qgsfeature.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Germán Carrillo' -__date__ = '06/10/2012' -__copyright__ = 'Copyright 2012, The QGIS Project' + +__author__ = "Germán Carrillo" +__date__ = "06/10/2012" +__copyright__ = "Copyright 2012, The QGIS Project" import os @@ -41,7 +42,7 @@ def test_CreateFeature(self): feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(123, 456))) myId = feat.id() myExpectedId = 0 - myMessage = f'\nExpected: {myExpectedId}\nGot: {myId}' + myMessage = f"\nExpected: {myExpectedId}\nGot: {myId}" assert myId == myExpectedId, myMessage def test_FeatureDefaultConstructor(self): @@ -64,9 +65,9 @@ def test_FeatureDefaultConstructor(self): def test_equality(self): fields = QgsFields() - field1 = QgsField('my_field') + field1 = QgsField("my_field") fields.append(field1) - field2 = QgsField('my_field2') + field2 = QgsField("my_field2") fields.append(field2) feat = QgsFeature(fields, 0) @@ -98,16 +99,16 @@ def test_equality(self): feat2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(123, 456))) self.assertEqual(feat, feat2) - field2 = QgsField('my_field3') + field2 = QgsField("my_field3") fields.append(field2) feat2.setFields(fields) self.assertNotEqual(feat, feat2) def test_hash(self): fields = QgsFields() - field1 = QgsField('my_field') + field1 = QgsField("my_field") fields.append(field1) - field2 = QgsField('my_field2') + field2 = QgsField("my_field2") fields.append(field2) feat = QgsFeature(fields, 0) @@ -130,8 +131,8 @@ def test_hash(self): self.assertNotEqual(hash(feat), hash(feat2)) def test_ValidFeature(self): - myPath = os.path.join(unitTestDataPath(), 'points.shp') - myLayer = QgsVectorLayer(myPath, 'Points', 'ogr') + myPath = os.path.join(unitTestDataPath(), "points.shp") + myLayer = QgsVectorLayer(myPath, "Points", "ogr") provider = myLayer.dataProvider() fit = provider.getFeatures() feat = QgsFeature() @@ -149,9 +150,9 @@ def test_Validity(self): f.setValid(False) self.assertFalse(f.isValid()) fields = QgsFields() - field1 = QgsField('my_field') + field1 = QgsField("my_field") fields.append(field1) - field2 = QgsField('my_field2') + field2 = QgsField("my_field2") fields.append(field2) f.setFields(fields) f.setAttribute(0, 0) @@ -162,8 +163,8 @@ def test_Validity(self): self.assertTrue(f.isValid()) def test_Attributes(self): - myPath = os.path.join(unitTestDataPath(), 'lines.shp') - myLayer = QgsVectorLayer(myPath, 'Lines', 'ogr') + myPath = os.path.join(unitTestDataPath(), "lines.shp") + myLayer = QgsVectorLayer(myPath, "Lines", "ogr") provider = myLayer.dataProvider() fit = provider.getFeatures() feat = QgsFeature() @@ -174,7 +175,7 @@ def test_Attributes(self): # Only for printing purposes myExpectedAttributes = ["Highway", 1] - myMessage = f'\nExpected: {myExpectedAttributes}\nGot: {myAttributes}' + myMessage = f"\nExpected: {myExpectedAttributes}\nGot: {myAttributes}" assert myAttributes == myExpectedAttributes, myMessage @@ -197,7 +198,7 @@ def test_SetAttributes(self): QDate(2023, 1, 1), QTime(12, 11, 10), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), - True + True, ] feat.initAttributes(len(attributes)) feat.setAttributes(attributes) @@ -221,7 +222,7 @@ def test_setAttribute(self): QVariant("foo"), QDate(2023, 1, 1), QTime(12, 11, 10), - QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)) + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), ] self.assertEqual(feat.attributeCount(), 1) for attribute in attributes: @@ -236,41 +237,44 @@ def test_setAttribute(self): def test_SetAttributeByName(self): fields = QgsFields() - field1 = QgsField('my_field') + field1 = QgsField("my_field") fields.append(field1) - field2 = QgsField('my_field2') + field2 = QgsField("my_field2") fields.append(field2) feat = QgsFeature(fields) feat.initAttributes(2) - feat['my_field'] = 'foo' - feat['my_field2'] = 'bah' - self.assertEqual(feat.attributes(), ['foo', 'bah']) - self.assertEqual(feat.attribute('my_field'), 'foo') - self.assertEqual(feat.attribute('my_field2'), 'bah') + feat["my_field"] = "foo" + feat["my_field2"] = "bah" + self.assertEqual(feat.attributes(), ["foo", "bah"]) + self.assertEqual(feat.attribute("my_field"), "foo") + self.assertEqual(feat.attribute("my_field2"), "bah") # Test different type of attributes attributes = [ - {'name': 'int', 'value': -9585674563452}, - {'name': 'float', 'value': 34.3}, - {'name': 'bool', 'value': False}, - {'name': 'string', 'value': 'QGIS'}, - {'name': 'variant', 'value': QVariant('foo')}, - {'name': 'date', 'value': QDate(2023, 1, 1)}, - {'name': 'time', 'value': QTime(12, 11, 10)}, - {'name': 'datetime', 'value': QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10))} + {"name": "int", "value": -9585674563452}, + {"name": "float", "value": 34.3}, + {"name": "bool", "value": False}, + {"name": "string", "value": "QGIS"}, + {"name": "variant", "value": QVariant("foo")}, + {"name": "date", "value": QDate(2023, 1, 1)}, + {"name": "time", "value": QTime(12, 11, 10)}, + { + "name": "datetime", + "value": QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + }, ] fields = QgsFields() for attribute in attributes: - fields.append(QgsField(attribute['name'])) + fields.append(QgsField(attribute["name"])) feat = QgsFeature(fields) feat.initAttributes(len(attributes)) for attr in attributes: - name = attr['name'] - value = attr['value'] + name = attr["name"] + value = attr["value"] feat.setAttribute(name, value) self.assertEqual(feat.attribute(name), value) @@ -289,14 +293,14 @@ def test_DeleteAttribute(self): feat.deleteAttribute(1) myAttrs = [feat[0], feat[1]] myExpectedAttrs = ["text1", "text3"] - myMessage = f'\nExpected: {str(myExpectedAttrs)}\nGot: {str(myAttrs)}' + myMessage = f"\nExpected: {str(myExpectedAttrs)}\nGot: {str(myAttrs)}" assert myAttrs == myExpectedAttrs, myMessage def test_DeleteAttributeByName(self): fields = QgsFields() - field1 = QgsField('my_field') + field1 = QgsField("my_field") fields.append(field1) - field2 = QgsField('my_field2') + field2 = QgsField("my_field2") fields.append(field2) feat = QgsFeature(fields) @@ -304,21 +308,21 @@ def test_DeleteAttributeByName(self): feat[0] = "text1" feat[1] = "text2" with self.assertRaises(KeyError): - feat.deleteAttribute('not present') - self.assertTrue(feat.deleteAttribute('my_field')) - self.assertEqual(feat.attributes(), ['text2']) + feat.deleteAttribute("not present") + self.assertTrue(feat.deleteAttribute("my_field")) + self.assertEqual(feat.attributes(), ["text2"]) def test_SetGeometry(self): feat = QgsFeature() feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(123, 456))) myGeometry = feat.geometry() myExpectedGeometry = "!None" - myMessage = f'\nExpected: {myExpectedGeometry}\nGot: {myGeometry}' + myMessage = f"\nExpected: {myExpectedGeometry}\nGot: {myGeometry}" assert myGeometry is not None, myMessage # set from QgsAbstractGeometry feat.setGeometry(QgsPoint(12, 34)) - self.assertEqual(feat.geometry().asWkt(), 'Point (12 34)') + self.assertEqual(feat.geometry().asWkt(), "Point (12 34)") def testAttributeCount(self): f = QgsFeature() @@ -353,35 +357,45 @@ def testPadAttributes(self): def testAttributeMap(self): # start with a feature with no fields f = QgsFeature() - f.setAttributes([1, 'a', NULL]) + f.setAttributes([1, "a", NULL]) with self.assertRaises(ValueError): _ = f.attributeMap() # set fields fields = QgsFields() - field1 = QgsField('my_field') + field1 = QgsField("my_field") fields.append(field1) - field2 = QgsField('my_field2') + field2 = QgsField("my_field2") fields.append(field2) - field3 = QgsField('my_field3') + field3 = QgsField("my_field3") fields.append(field3) f.setFields(fields) - f.setAttributes([1, 'a', NULL]) - self.assertEqual(f.attributeMap(), {'my_field': 1, 'my_field2': 'a', 'my_field3': NULL}) + f.setAttributes([1, "a", NULL]) + self.assertEqual( + f.attributeMap(), {"my_field": 1, "my_field2": "a", "my_field3": NULL} + ) # unbalanced fields/attributes -- should be handled gracefully # less attributes than fields - f.setAttributes([1, 'a']) + f.setAttributes([1, "a"]) with self.assertRaises(ValueError): _ = f.attributeMap() - f.setAttributes([1, 'a', 2, 3]) + f.setAttributes([1, "a", 2, 3]) # more attributes than fields with self.assertRaises(ValueError): _ = f.attributeMap() def testUnsetFeature(self): f = QgsFeature() - f.setAttributes([1, 'a', NULL, QgsUnsetAttributeValue(), QgsUnsetAttributeValue('Autonumber')]) + f.setAttributes( + [ + 1, + "a", + NULL, + QgsUnsetAttributeValue(), + QgsUnsetAttributeValue("Autonumber"), + ] + ) with self.assertRaises(KeyError): f.isUnsetValue(-1) with self.assertRaises(KeyError): @@ -394,27 +408,35 @@ def testUnsetFeature(self): def test_geo_interface(self): fields = QgsFields() - field1 = QgsField('my_field', QVariant.String) + field1 = QgsField("my_field", QVariant.String) fields.append(field1) - field2 = QgsField('my_field2', QVariant.String) + field2 = QgsField("my_field2", QVariant.String) fields.append(field2) - field3 = QgsField('my_field3', QVariant.Int) + field3 = QgsField("my_field3", QVariant.Int) fields.append(field3) feat = QgsFeature(fields) - feat.setAttributes(['abc', 'def', 123]) + feat.setAttributes(["abc", "def", 123]) feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(123, 456))) - self.assertEqual(feat.__geo_interface__, {'geometry': {'coordinates': [123.0, 456.0], 'type': 'Point'}, - 'properties': {'my_field': 'abc', 'my_field2': 'def', 'my_field3': 123}, - 'type': 'Feature'}) + self.assertEqual( + feat.__geo_interface__, + { + "geometry": {"coordinates": [123.0, 456.0], "type": "Point"}, + "properties": {"my_field": "abc", "my_field2": "def", "my_field3": 123}, + "type": "Feature", + }, + ) feat.setAttributes([NULL, None, NULL]) - self.assertEqual(feat.__geo_interface__, { - 'geometry': {'coordinates': [123.0, 456.0], 'type': 'Point'}, - 'properties': {'my_field': None, 'my_field2': None, - 'my_field3': None}, - 'type': 'Feature'}) + self.assertEqual( + feat.__geo_interface__, + { + "geometry": {"coordinates": [123.0, 456.0], "type": "Point"}, + "properties": {"my_field": None, "my_field2": None, "my_field3": None}, + "type": "Feature", + }, + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfeatureiterator.py b/tests/src/python/test_qgsfeatureiterator.py index 488d83fedaf7..9b03a469e29e 100644 --- a/tests/src/python/test_qgsfeatureiterator.py +++ b/tests/src/python/test_qgsfeatureiterator.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Matthias Kuhn' -__date__ = '18/09/2013' -__copyright__ = 'Copyright 2013, The QGIS Project' + +__author__ = "Matthias Kuhn" +__date__ = "18/09/2013" +__copyright__ = "Copyright 2013, The QGIS Project" import os @@ -46,64 +47,114 @@ def __init__(self, methodName): def test_FilterExpression(self): # create point layer - myShpFile = os.path.join(TEST_DATA_DIR, 'points.shp') - pointLayer = QgsVectorLayer(myShpFile, 'Points', 'ogr') - - ids = [feat.id() for feat in pointLayer.getFeatures(QgsFeatureRequest().setFilterExpression('Staff > 3'))] + myShpFile = os.path.join(TEST_DATA_DIR, "points.shp") + pointLayer = QgsVectorLayer(myShpFile, "Points", "ogr") + + ids = [ + feat.id() + for feat in pointLayer.getFeatures( + QgsFeatureRequest().setFilterExpression("Staff > 3") + ) + ] expectedIds = [1, 5, 6, 7, 8] - myMessage = f'\nExpected: {repr(expectedIds)} features\nGot: {repr(ids)} features' + myMessage = ( + f"\nExpected: {repr(expectedIds)} features\nGot: {repr(ids)} features" + ) assert ids == expectedIds, myMessage pointLayer.startEditing() self.addFeatures(pointLayer) - ids = [feat.id() for feat in pointLayer.getFeatures(QgsFeatureRequest().setFilterExpression('Staff > 3'))] + ids = [ + feat.id() + for feat in pointLayer.getFeatures( + QgsFeatureRequest().setFilterExpression("Staff > 3") + ) + ] expectedIds = [-2, 1, 5, 6, 7, 8] - myMessage = f'\nExpected: {repr(expectedIds)} features\nGot: {repr(ids)} features' + myMessage = ( + f"\nExpected: {repr(expectedIds)} features\nGot: {repr(ids)} features" + ) assert ids == expectedIds, myMessage pointLayer.rollBack() - ids = [feat.id() for feat in pointLayer.getFeatures(QgsFeatureRequest().setFilterExpression('Staff > 3'))] + ids = [ + feat.id() + for feat in pointLayer.getFeatures( + QgsFeatureRequest().setFilterExpression("Staff > 3") + ) + ] expectedIds = [1, 5, 6, 7, 8] - myMessage = f'\nExpected: {repr(expectedIds)} features\nGot: {repr(ids)} features' + myMessage = ( + f"\nExpected: {repr(expectedIds)} features\nGot: {repr(ids)} features" + ) assert ids == expectedIds, myMessage def test_FilterExpressionWithAccents(self): - myShpFile = os.path.join(TEST_DATA_DIR, 'france_parts.shp') - layer = QgsVectorLayer(myShpFile, 'poly', 'ogr') + myShpFile = os.path.join(TEST_DATA_DIR, "france_parts.shp") + layer = QgsVectorLayer(myShpFile, "poly", "ogr") layer.setProviderEncoding("ISO-8859-1") - ids = [feat.id() for feat in layer.getFeatures(QgsFeatureRequest().setFilterExpression("TYPE_1 = 'Région'"))] + ids = [ + feat.id() + for feat in layer.getFeatures( + QgsFeatureRequest().setFilterExpression("TYPE_1 = 'Région'") + ) + ] expectedIds = [0, 1, 2, 3] - myMessage = f'\nExpected: {repr(expectedIds)} features\nGot: {repr(ids)} features' + myMessage = ( + f"\nExpected: {repr(expectedIds)} features\nGot: {repr(ids)} features" + ) assert ids == expectedIds, myMessage layer.setProviderEncoding("UTF-8") - ids = [feat.id() for feat in layer.getFeatures(QgsFeatureRequest().setFilterExpression("TYPE_1 = 'Région'"))] + ids = [ + feat.id() + for feat in layer.getFeatures( + QgsFeatureRequest().setFilterExpression("TYPE_1 = 'Région'") + ) + ] expectedIds = [] - myMessage = f'\nExpected: {repr(expectedIds)} features\nGot: {repr(ids)} features' + myMessage = ( + f"\nExpected: {repr(expectedIds)} features\nGot: {repr(ids)} features" + ) assert ids == expectedIds, myMessage def test_FilterFids(self): # create point layer - myShpFile = os.path.join(TEST_DATA_DIR, 'points.shp') - pointLayer = QgsVectorLayer(myShpFile, 'Points', 'ogr') - - ids = [feat.id() for feat in pointLayer.getFeatures(QgsFeatureRequest().setFilterFids([7, 8, 12, 30]))] + myShpFile = os.path.join(TEST_DATA_DIR, "points.shp") + pointLayer = QgsVectorLayer(myShpFile, "Points", "ogr") + + ids = [ + feat.id() + for feat in pointLayer.getFeatures( + QgsFeatureRequest().setFilterFids([7, 8, 12, 30]) + ) + ] expectedIds = [7, 8, 12] self.assertEqual(set(ids), set(expectedIds)) pointLayer.startEditing() self.addFeatures(pointLayer) - ids = [feat.id() for feat in pointLayer.getFeatures(QgsFeatureRequest().setFilterFids([-4, 7, 8, 12, 30]))] + ids = [ + feat.id() + for feat in pointLayer.getFeatures( + QgsFeatureRequest().setFilterFids([-4, 7, 8, 12, 30]) + ) + ] expectedIds = [-4, 7, 8, 12] self.assertEqual(set(ids), set(expectedIds)) pointLayer.rollBack() - ids = [feat.id() for feat in pointLayer.getFeatures(QgsFeatureRequest().setFilterFids([-2, 7, 8, 12, 30]))] + ids = [ + feat.id() + for feat in pointLayer.getFeatures( + QgsFeatureRequest().setFilterFids([-2, 7, 8, 12, 30]) + ) + ] expectedIds = [7, 8, 12] self.assertEqual(set(ids), set(expectedIds)) @@ -111,17 +162,19 @@ def addFeatures(self, vl): feat = QgsFeature() fields = vl.fields() feat.setFields(fields) - feat['Staff'] = 4 + feat["Staff"] = 4 vl.addFeature(feat) feat = QgsFeature() fields = vl.fields() feat.setFields(fields) - feat['Staff'] = 2 + feat["Staff"] = 2 vl.addFeature(feat) def test_VectorLayerEditing(self): - ogr_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'points.shp'), 'Points', 'ogr') + ogr_layer = QgsVectorLayer( + os.path.join(TEST_DATA_DIR, "points.shp"), "Points", "ogr" + ) self.assertTrue(ogr_layer.isValid()) request = QgsFeatureRequest() @@ -132,7 +185,9 @@ def test_VectorLayerEditing(self): iterator = ogr_layer.getFeatures(request) self.assertTrue(iterator.isValid()) - memory_layer = QgsVectorLayer("Point?field=x:string&field=y:integer&field=z:integer", "layer", "memory") + memory_layer = QgsVectorLayer( + "Point?field=x:string&field=y:integer&field=z:integer", "layer", "memory" + ) self.assertTrue(memory_layer.isValid()) request = QgsFeatureRequest() @@ -144,67 +199,103 @@ def test_VectorLayerEditing(self): self.assertTrue(iterator.isValid()) def test_ExpressionFieldNested(self): - myShpFile = os.path.join(TEST_DATA_DIR, 'points.shp') - layer = QgsVectorLayer(myShpFile, 'Points', 'ogr') + myShpFile = os.path.join(TEST_DATA_DIR, "points.shp") + layer = QgsVectorLayer(myShpFile, "Points", "ogr") self.assertTrue(layer.isValid()) - idx = layer.addExpressionField('"Staff"*2', QgsField('exp1', QVariant.LongLong)) # NOQA - idx = layer.addExpressionField('"exp1"-1', QgsField('exp2', QVariant.LongLong)) # NOQA - - fet = next(layer.getFeatures(QgsFeatureRequest().setSubsetOfAttributes(['exp2'], layer.fields()))) - self.assertEqual(fet['Class'], NULL) + idx = layer.addExpressionField( + '"Staff"*2', QgsField("exp1", QVariant.LongLong) + ) # NOQA + idx = layer.addExpressionField( + '"exp1"-1', QgsField("exp2", QVariant.LongLong) + ) # NOQA + + fet = next( + layer.getFeatures( + QgsFeatureRequest().setSubsetOfAttributes(["exp2"], layer.fields()) + ) + ) + self.assertEqual(fet["Class"], NULL) # nested virtual fields should make all these attributes be fetched - self.assertEqual(fet['Staff'], 2) - self.assertEqual(fet['exp2'], 3) - self.assertEqual(fet['exp1'], 4) + self.assertEqual(fet["Staff"], 2) + self.assertEqual(fet["exp2"], 3) + self.assertEqual(fet["exp1"], 4) def test_ExpressionFieldNestedGeometry(self): - myShpFile = os.path.join(TEST_DATA_DIR, 'points.shp') - layer = QgsVectorLayer(myShpFile, 'Points', 'ogr') + myShpFile = os.path.join(TEST_DATA_DIR, "points.shp") + layer = QgsVectorLayer(myShpFile, "Points", "ogr") self.assertTrue(layer.isValid()) - idx = layer.addExpressionField('$x*2', QgsField('exp1', QVariant.LongLong)) # NOQA - idx = layer.addExpressionField('"exp1"/1.5', QgsField('exp2', QVariant.LongLong)) # NOQA - - fet = next(layer.getFeatures( - QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry).setSubsetOfAttributes(['exp2'], layer.fields()))) + idx = layer.addExpressionField( + "$x*2", QgsField("exp1", QVariant.LongLong) + ) # NOQA + idx = layer.addExpressionField( + '"exp1"/1.5', QgsField("exp2", QVariant.LongLong) + ) # NOQA + + fet = next( + layer.getFeatures( + QgsFeatureRequest() + .setFlags(QgsFeatureRequest.Flag.NoGeometry) + .setSubsetOfAttributes(["exp2"], layer.fields()) + ) + ) # nested virtual fields should have made geometry be fetched - self.assertEqual(fet['exp2'], -156) - self.assertEqual(fet['exp1'], -234) + self.assertEqual(fet["exp2"], -156) + self.assertEqual(fet["exp1"], -234) def test_ExpressionFieldDependingOnOtherFields(self): - myShpFile = os.path.join(TEST_DATA_DIR, 'points.shp') - layer = QgsVectorLayer(myShpFile, 'Points', 'ogr') + myShpFile = os.path.join(TEST_DATA_DIR, "points.shp") + layer = QgsVectorLayer(myShpFile, "Points", "ogr") self.assertTrue(layer.isValid()) - idx = layer.addExpressionField("eval('Class')", QgsField('exp1', QVariant.String)) # NOQA + idx = layer.addExpressionField( + "eval('Class')", QgsField("exp1", QVariant.String) + ) # NOQA - fet = next(layer.getFeatures( - QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.NoGeometry).setSubsetOfAttributes(['exp1'], layer.fields()))) + fet = next( + layer.getFeatures( + QgsFeatureRequest() + .setFlags(QgsFeatureRequest.Flag.NoGeometry) + .setSubsetOfAttributes(["exp1"], layer.fields()) + ) + ) - self.assertEqual(fet['exp1'], 'Jet') + self.assertEqual(fet["exp1"], "Jet") def test_ExpressionFieldNestedCircular(self): - """ test circular virtual field definitions """ + """test circular virtual field definitions""" - myShpFile = os.path.join(TEST_DATA_DIR, 'points.shp') - layer = QgsVectorLayer(myShpFile, 'Points', 'ogr') + myShpFile = os.path.join(TEST_DATA_DIR, "points.shp") + layer = QgsVectorLayer(myShpFile, "Points", "ogr") self.assertTrue(layer.isValid()) cnt = layer.fields().count() # NOQA - idx = layer.addExpressionField('"exp3"*2', QgsField('exp1', QVariant.LongLong)) # NOQA - idx = layer.addExpressionField('"exp1"-1', QgsField('exp2', QVariant.LongLong)) # NOQA - idx = layer.addExpressionField('"exp2"*3', QgsField('exp3', QVariant.LongLong)) # NOQA + idx = layer.addExpressionField( + '"exp3"*2', QgsField("exp1", QVariant.LongLong) + ) # NOQA + idx = layer.addExpressionField( + '"exp1"-1', QgsField("exp2", QVariant.LongLong) + ) # NOQA + idx = layer.addExpressionField( + '"exp2"*3', QgsField("exp3", QVariant.LongLong) + ) # NOQA # really just testing that this doesn't hang/crash... there's no good result here! - fet = next(layer.getFeatures(QgsFeatureRequest().setSubsetOfAttributes(['exp2'], layer.fields()))) - self.assertEqual(fet['Class'], NULL) + fet = next( + layer.getFeatures( + QgsFeatureRequest().setSubsetOfAttributes(["exp2"], layer.fields()) + ) + ) + self.assertEqual(fet["Class"], NULL) def test_JoinUsingExpression(self): - """ test joining a layer using a virtual field """ + """test joining a layer using a virtual field""" joinLayer = QgsVectorLayer( "Point?field=x:string&field=y:integer&field=z:integer", - "joinlayer", "memory") + "joinlayer", + "memory", + ) pr = joinLayer.dataProvider() f1 = QgsFeature() f1.setAttributes(["foo", 246, 321]) @@ -212,13 +303,14 @@ def test_JoinUsingExpression(self): f2.setAttributes(["bar", 456, 654]) self.assertTrue(pr.addFeatures([f1, f2])) - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) pr = layer.dataProvider() f = QgsFeature() f.setAttributes(["test", 123]) self.assertTrue(pr.addFeatures([f])) - layer.addExpressionField('"fldint"*2', QgsField('exp1', QVariant.LongLong)) + layer.addExpressionField('"fldint"*2', QgsField("exp1", QVariant.LongLong)) QgsProject.instance().addMapLayers([layer, joinLayer]) @@ -243,20 +335,23 @@ def test_JoinUsingExpression(self): QgsProject.instance().removeMapLayers([layer.id(), joinLayer.id()]) def test_JoinUsingExpression2(self): - """ test joining a layer using a virtual field (the other way!) """ + """test joining a layer using a virtual field (the other way!)""" joinLayer = QgsVectorLayer( "Point?field=x:string&field=y:integer&field=z:integer", - "joinlayer", "memory") + "joinlayer", + "memory", + ) pr = joinLayer.dataProvider() f1 = QgsFeature() f1.setAttributes(["foo", 246, 321]) f2 = QgsFeature() f2.setAttributes(["bar", 456, 654]) self.assertTrue(pr.addFeatures([f1, f2])) - joinLayer.addExpressionField('"y"/2', QgsField('exp1', QVariant.LongLong)) + joinLayer.addExpressionField('"y"/2', QgsField("exp1", QVariant.LongLong)) - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) pr = layer.dataProvider() f = QgsFeature() f.setAttributes(["test", 123]) @@ -285,10 +380,12 @@ def test_JoinUsingExpression2(self): QgsProject.instance().removeMapLayers([layer.id(), joinLayer.id()]) def test_JoinUsingFeatureRequestExpression(self): - """ test requesting features using a filter expression which requires joined columns """ + """test requesting features using a filter expression which requires joined columns""" joinLayer = QgsVectorLayer( "Point?field=x:string&field=y:integer&field=z:integer", - "joinlayer", "memory") + "joinlayer", + "memory", + ) pr = joinLayer.dataProvider() f1 = QgsFeature() f1.setAttributes(["foo", 123, 321]) @@ -296,8 +393,9 @@ def test_JoinUsingFeatureRequestExpression(self): f2.setAttributes(["bar", 124, 654]) self.assertTrue(pr.addFeatures([f1, f2])) - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) pr = layer.dataProvider() f1 = QgsFeature() f1.setAttributes(["test", 123]) @@ -316,16 +414,20 @@ def test_JoinUsingFeatureRequestExpression(self): f = QgsFeature() fi = layer.getFeatures( - QgsFeatureRequest().setFlags(QgsFeatureRequest.Flag.SubsetOfAttributes).setFilterExpression('joinlayer_z=654')) + QgsFeatureRequest() + .setFlags(QgsFeatureRequest.Flag.SubsetOfAttributes) + .setFilterExpression("joinlayer_z=654") + ) self.assertTrue(fi.nextFeature(f)) - self.assertEqual(f['fldint'], 124) - self.assertEqual(f['joinlayer_z'], 654) + self.assertEqual(f["fldint"], 124) + self.assertEqual(f["joinlayer_z"], 654) QgsProject.instance().removeMapLayers([layer.id(), joinLayer.id()]) def test_FeatureRequestSortByVirtualField(self): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) pr = layer.dataProvider() f1 = QgsFeature() f1.setAttributes(["test", 123]) @@ -333,18 +435,24 @@ def test_FeatureRequestSortByVirtualField(self): f2.setAttributes(["test", 124]) self.assertTrue(pr.addFeatures([f1, f2])) - idx = layer.addExpressionField('if("fldint"=123,3,2)', QgsField('exp1', QVariant.LongLong)) # NOQA + idx = layer.addExpressionField( + 'if("fldint"=123,3,2)', QgsField("exp1", QVariant.LongLong) + ) # NOQA QgsProject.instance().addMapLayers([layer]) request = QgsFeatureRequest() - request.setOrderBy(QgsFeatureRequest.OrderBy([QgsFeatureRequest.OrderByClause('exp1', True)])) + request.setOrderBy( + QgsFeatureRequest.OrderBy([QgsFeatureRequest.OrderByClause("exp1", True)]) + ) ids = [] for feat in layer.getFeatures(request): ids.append(feat.id()) self.assertEqual(ids, [2, 1]) - request.setOrderBy(QgsFeatureRequest.OrderBy([QgsFeatureRequest.OrderByClause('exp1', False)])) + request.setOrderBy( + QgsFeatureRequest.OrderBy([QgsFeatureRequest.OrderByClause("exp1", False)]) + ) ids = [] for feat in layer.getFeatures(request): ids.append(feat.id()) @@ -353,10 +461,12 @@ def test_FeatureRequestSortByVirtualField(self): QgsProject.instance().removeMapLayers([layer.id()]) def test_FeatureRequestSortByJoinField(self): - """ test sorting requested features using a joined columns """ + """test sorting requested features using a joined columns""" joinLayer = QgsVectorLayer( "Point?field=x:string&field=y:integer&field=z:integer", - "joinlayer", "memory") + "joinlayer", + "memory", + ) pr = joinLayer.dataProvider() f1 = QgsFeature() f1.setAttributes(["foo", 123, 321]) @@ -364,8 +474,9 @@ def test_FeatureRequestSortByJoinField(self): f2.setAttributes(["bar", 124, 654]) self.assertTrue(pr.addFeatures([f1, f2])) - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) pr = layer.dataProvider() f1 = QgsFeature() f1.setAttributes(["test", 123]) @@ -383,13 +494,21 @@ def test_FeatureRequestSortByJoinField(self): layer.addJoin(join) request = QgsFeatureRequest() - request.setOrderBy(QgsFeatureRequest.OrderBy([QgsFeatureRequest.OrderByClause('joinlayer_z', True)])) + request.setOrderBy( + QgsFeatureRequest.OrderBy( + [QgsFeatureRequest.OrderByClause("joinlayer_z", True)] + ) + ) ids = [] for feat in layer.getFeatures(request): ids.append(feat.id()) self.assertEqual(ids, [1, 2]) - request.setOrderBy(QgsFeatureRequest.OrderBy([QgsFeatureRequest.OrderByClause('joinlayer_z', False)])) + request.setOrderBy( + QgsFeatureRequest.OrderBy( + [QgsFeatureRequest.OrderByClause("joinlayer_z", False)] + ) + ) ids = [] for feat in layer.getFeatures(request): ids.append(feat.id()) @@ -401,8 +520,9 @@ def test_ZFeatureRequestSortByAuxiliaryField(self): s = QgsAuxiliaryStorage() self.assertTrue(s.isValid()) - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) pr = layer.dataProvider() f1 = QgsFeature() f1.setAttributes(["test", 123]) @@ -411,16 +531,16 @@ def test_ZFeatureRequestSortByAuxiliaryField(self): self.assertTrue(pr.addFeatures([f1, f2])) # Create a new auxiliary layer with 'pk' as key - pkf = layer.fields().field(layer.fields().indexOf('fldint')) + pkf = layer.fields().field(layer.fields().indexOf("fldint")) al = s.createAuxiliaryLayer(pkf, layer) self.assertTrue(al.isValid()) layer.setAuxiliaryLayer(al) prop = QgsPropertyDefinition() - prop.setComment('test_field') + prop.setComment("test_field") prop.setDataType(QgsPropertyDefinition.DataType.DataTypeNumeric) - prop.setOrigin('user') - prop.setName('custom') + prop.setOrigin("user") + prop.setName("custom") self.assertTrue(al.addAuxiliaryField(prop)) layer.startEditing() @@ -432,13 +552,21 @@ def test_ZFeatureRequestSortByAuxiliaryField(self): layer.commitChanges() request = QgsFeatureRequest() - request.setOrderBy(QgsFeatureRequest.OrderBy([QgsFeatureRequest.OrderByClause(layer.fields()[2].name(), True)])) + request.setOrderBy( + QgsFeatureRequest.OrderBy( + [QgsFeatureRequest.OrderByClause(layer.fields()[2].name(), True)] + ) + ) ids = [] for feat in layer.getFeatures(request): ids.append(feat.id()) self.assertEqual(ids, [2, 1]) - request.setOrderBy(QgsFeatureRequest.OrderBy([QgsFeatureRequest.OrderByClause(layer.fields()[2].name(), False)])) + request.setOrderBy( + QgsFeatureRequest.OrderBy( + [QgsFeatureRequest.OrderByClause(layer.fields()[2].name(), False)] + ) + ) ids = [] for feat in layer.getFeatures(request): ids.append(feat.id()) @@ -447,95 +575,194 @@ def test_ZFeatureRequestSortByAuxiliaryField(self): QgsProject.instance().removeMapLayers([layer.id()]) def test_invalidGeometryFilter(self): - layer = QgsVectorLayer( - "Polygon?field=x:string", - "joinlayer", "memory") + layer = QgsVectorLayer("Polygon?field=x:string", "joinlayer", "memory") # add some features, one has invalid geometry pr = layer.dataProvider() f1 = QgsFeature(1) f1.setAttributes(["a"]) - f1.setGeometry(QgsGeometry.fromWkt('Polygon((0 0, 1 0, 1 1, 0 1, 0 0))')) # valid + f1.setGeometry( + QgsGeometry.fromWkt("Polygon((0 0, 1 0, 1 1, 0 1, 0 0))") + ) # valid f2 = QgsFeature(2) f2.setAttributes(["b"]) - f2.setGeometry(QgsGeometry.fromWkt('Polygon((0 0, 1 0, 0 1, 1 1, 0 0))')) # invalid + f2.setGeometry( + QgsGeometry.fromWkt("Polygon((0 0, 1 0, 0 1, 1 1, 0 0))") + ) # invalid f3 = QgsFeature(3) f3.setAttributes(["c"]) - f3.setGeometry(QgsGeometry.fromWkt('Polygon((0 0, 1 0, 1 1, 0 1, 0 0))')) # valid + f3.setGeometry( + QgsGeometry.fromWkt("Polygon((0 0, 1 0, 1 1, 0 1, 0 0))") + ) # valid self.assertTrue(pr.addFeatures([f1, f2, f3])) - res = [f['x'] for f in - layer.getFeatures(QgsFeatureRequest().setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck))] - self.assertEqual(res, ['a', 'b', 'c']) - res = [f['x'] for f in - layer.getFeatures(QgsFeatureRequest().setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid))] - self.assertEqual(res, ['a', 'c']) - res = [f['x'] for f in - layer.getFeatures(QgsFeatureRequest().setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometryAbortOnInvalid))] - self.assertEqual(res, ['a']) + res = [ + f["x"] + for f in layer.getFeatures( + QgsFeatureRequest().setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck + ) + ) + ] + self.assertEqual(res, ["a", "b", "c"]) + res = [ + f["x"] + for f in layer.getFeatures( + QgsFeatureRequest().setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid + ) + ) + ] + self.assertEqual(res, ["a", "c"]) + res = [ + f["x"] + for f in layer.getFeatures( + QgsFeatureRequest().setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometryAbortOnInvalid + ) + ) + ] + self.assertEqual(res, ["a"]) # with callback self.callback_feature_val = None def callback(feature): - self.callback_feature_val = feature['x'] - - res = [f['x'] for f in - layer.getFeatures(QgsFeatureRequest().setInvalidGeometryCheck( - QgsFeatureRequest.InvalidGeometryCheck.GeometryAbortOnInvalid).setInvalidGeometryCallback(callback))] - self.assertEqual(res, ['a']) - self.assertEqual(self.callback_feature_val, 'b') + self.callback_feature_val = feature["x"] + + res = [ + f["x"] + for f in layer.getFeatures( + QgsFeatureRequest() + .setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometryAbortOnInvalid + ) + .setInvalidGeometryCallback(callback) + ) + ] + self.assertEqual(res, ["a"]) + self.assertEqual(self.callback_feature_val, "b") # clear callback - res = [f['x'] for f in - layer.getFeatures(QgsFeatureRequest().setInvalidGeometryCheck( - QgsFeatureRequest.InvalidGeometryCheck.GeometryAbortOnInvalid).setInvalidGeometryCallback(None))] - self.assertEqual(res, ['a']) + res = [ + f["x"] + for f in layer.getFeatures( + QgsFeatureRequest() + .setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometryAbortOnInvalid + ) + .setInvalidGeometryCallback(None) + ) + ] + self.assertEqual(res, ["a"]) # check with filter fids - res = [f['x'] for f in - layer.getFeatures(QgsFeatureRequest().setFilterFid(f2.id()).setInvalidGeometryCheck( - QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck))] - self.assertEqual(res, ['b']) - res = [f['x'] for f in - layer.getFeatures(QgsFeatureRequest().setFilterFid(f2.id()).setInvalidGeometryCheck( - QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid))] + res = [ + f["x"] + for f in layer.getFeatures( + QgsFeatureRequest() + .setFilterFid(f2.id()) + .setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck + ) + ) + ] + self.assertEqual(res, ["b"]) + res = [ + f["x"] + for f in layer.getFeatures( + QgsFeatureRequest() + .setFilterFid(f2.id()) + .setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid + ) + ) + ] self.assertEqual(res, []) - res = [f['x'] for f in - layer.getFeatures(QgsFeatureRequest().setFilterFid(f2.id()).setInvalidGeometryCheck( - QgsFeatureRequest.InvalidGeometryCheck.GeometryAbortOnInvalid))] + res = [ + f["x"] + for f in layer.getFeatures( + QgsFeatureRequest() + .setFilterFid(f2.id()) + .setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometryAbortOnInvalid + ) + ) + ] self.assertEqual(res, []) f4 = QgsFeature(4) f4.setAttributes(["d"]) - f4.setGeometry(QgsGeometry.fromWkt('Polygon((0 0, 1 0, 0 1, 1 1, 0 0))')) # invalid + f4.setGeometry( + QgsGeometry.fromWkt("Polygon((0 0, 1 0, 0 1, 1 1, 0 0))") + ) # invalid # check with added features layer.startEditing() self.assertTrue(layer.addFeatures([f4])) - res = [f['x'] for f in - layer.getFeatures(QgsFeatureRequest().setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck))] - self.assertEqual(set(res), {'a', 'b', 'c', 'd'}) - res = [f['x'] for f in - layer.getFeatures(QgsFeatureRequest().setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid))] - self.assertEqual(set(res), {'a', 'c'}) - res = [f['x'] for f in - layer.getFeatures(QgsFeatureRequest().setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometryAbortOnInvalid))] - self.assertEqual(res, ['a']) + res = [ + f["x"] + for f in layer.getFeatures( + QgsFeatureRequest().setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck + ) + ) + ] + self.assertEqual(set(res), {"a", "b", "c", "d"}) + res = [ + f["x"] + for f in layer.getFeatures( + QgsFeatureRequest().setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid + ) + ) + ] + self.assertEqual(set(res), {"a", "c"}) + res = [ + f["x"] + for f in layer.getFeatures( + QgsFeatureRequest().setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometryAbortOnInvalid + ) + ) + ] + self.assertEqual(res, ["a"]) # check with features with changed geometry layer.rollBack() layer.startEditing() - layer.changeGeometry(2, QgsGeometry.fromWkt('Polygon((0 0, 1 0, 1 1, 0 1, 0 0))')) # valid - layer.changeGeometry(3, QgsGeometry.fromWkt('Polygon((0 0, 1 0, 0 1, 1 1, 0 0))')) # invalid - res = [f['x'] for f in - layer.getFeatures(QgsFeatureRequest().setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck))] - self.assertEqual(set(res), {'a', 'b', 'c'}) - res = [f['x'] for f in - layer.getFeatures(QgsFeatureRequest().setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid))] - self.assertEqual(set(res), {'a', 'b'}) - res = [f['x'] for f in - layer.getFeatures(QgsFeatureRequest().setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometryAbortOnInvalid))] - self.assertEqual(res, ['a', 'b']) + layer.changeGeometry( + 2, QgsGeometry.fromWkt("Polygon((0 0, 1 0, 1 1, 0 1, 0 0))") + ) # valid + layer.changeGeometry( + 3, QgsGeometry.fromWkt("Polygon((0 0, 1 0, 0 1, 1 1, 0 0))") + ) # invalid + res = [ + f["x"] + for f in layer.getFeatures( + QgsFeatureRequest().setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck + ) + ) + ] + self.assertEqual(set(res), {"a", "b", "c"}) + res = [ + f["x"] + for f in layer.getFeatures( + QgsFeatureRequest().setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid + ) + ) + ] + self.assertEqual(set(res), {"a", "b"}) + res = [ + f["x"] + for f in layer.getFeatures( + QgsFeatureRequest().setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometryAbortOnInvalid + ) + ) + ] + self.assertEqual(res, ["a", "b"]) layer.rollBack() def test_vertical_transformation_4978_to_4979(self): @@ -545,30 +772,25 @@ def test_vertical_transformation_4978_to_4979(self): EPSG:4978 to EPSG:4979 """ - vl = QgsVectorLayer('PointZ?crs=EPSG:4978', 'gda2020points', 'memory') + vl = QgsVectorLayer("PointZ?crs=EPSG:4978", "gda2020points", "memory") self.assertTrue(vl.isValid()) - self.assertEqual(vl.crs().authid(), 'EPSG:4978') + self.assertEqual(vl.crs().authid(), "EPSG:4978") - self.assertEqual(vl.crs3D().horizontalCrs().authid(), 'EPSG:4978') + self.assertEqual(vl.crs3D().horizontalCrs().authid(), "EPSG:4978") f = QgsFeature() - f.setGeometry(QgsPoint(134.445567853, - -23.445567853, - 5543.325)) + f.setGeometry(QgsPoint(134.445567853, -23.445567853, 5543.325)) self.assertTrue(vl.dataProvider().addFeature(f)) - dest_crs = QgsCoordinateReferenceSystem('EPSG:4979') + dest_crs = QgsCoordinateReferenceSystem("EPSG:4979") self.assertTrue(dest_crs.isValid()) - self.assertEqual(dest_crs.horizontalCrs().authid(), 'EPSG:4979') + self.assertEqual(dest_crs.horizontalCrs().authid(), "EPSG:4979") transform = QgsCoordinateTransform( - vl.crs3D(), - dest_crs, - QgsCoordinateTransformContext() + vl.crs3D(), dest_crs, QgsCoordinateTransformContext() ) - request = QgsFeatureRequest().setCoordinateTransform( - transform) + request = QgsFeatureRequest().setCoordinateTransform(transform) transformed_features = list(vl.getFeatures(request)) self.assertEqual(len(transformed_features), 1) @@ -585,43 +807,43 @@ def test_vertical_transformation_gda2020_to_AVWS(self): """ # GDA2020 vertical CRS - vl = QgsVectorLayer('PointZ?crs=EPSG:7843', 'gda2020points', 'memory') + vl = QgsVectorLayer("PointZ?crs=EPSG:7843", "gda2020points", "memory") self.assertTrue(vl.isValid()) - self.assertEqual(vl.crs().authid(), 'EPSG:7843') + self.assertEqual(vl.crs().authid(), "EPSG:7843") - self.assertEqual(vl.crs3D().horizontalCrs().authid(), 'EPSG:7843') + self.assertEqual(vl.crs3D().horizontalCrs().authid(), "EPSG:7843") f = QgsFeature() - f.setGeometry(QgsPoint(134.445567853, - -23.445567853, - 5543.325)) + f.setGeometry(QgsPoint(134.445567853, -23.445567853, 5543.325)) self.assertTrue(vl.dataProvider().addFeature(f)) # AVWS dest_crs, msg = QgsCoordinateReferenceSystem.createCompoundCrs( - QgsCoordinateReferenceSystem('EPSG:7844'), - QgsCoordinateReferenceSystem('EPSG:9458')) + QgsCoordinateReferenceSystem("EPSG:7844"), + QgsCoordinateReferenceSystem("EPSG:9458"), + ) self.assertFalse(msg) self.assertTrue(dest_crs.isValid()) - self.assertEqual(dest_crs.horizontalCrs().authid(), 'EPSG:7844') - self.assertEqual(dest_crs.verticalCrs().authid(), 'EPSG:9458') + self.assertEqual(dest_crs.horizontalCrs().authid(), "EPSG:7844") + self.assertEqual(dest_crs.verticalCrs().authid(), "EPSG:9458") available_operations = QgsDatumTransform.operations(vl.crs3D(), dest_crs) self.assertEqual(len(available_operations[0].grids), 1) - self.assertEqual(available_operations[0].grids[0].shortName, 'au_ga_AGQG_20201120.tif') + self.assertEqual( + available_operations[0].grids[0].shortName, "au_ga_AGQG_20201120.tif" + ) if not available_operations[0].isAvailable: - self.skipTest(f'Required grid {available_operations[0].grids[0].shortName} not available on system') + self.skipTest( + f"Required grid {available_operations[0].grids[0].shortName} not available on system" + ) transform = QgsCoordinateTransform( - vl.crs3D(), - dest_crs, - QgsCoordinateTransformContext() + vl.crs3D(), dest_crs, QgsCoordinateTransformContext() ) # for debugging # self.assertEqual(transform.instantiatedCoordinateOperationDetails().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +inv +proj=vgridshift +grids=au_ga_AGQG_20201120.tif +multiplier=1 +step +proj=unitconvert +xy_in=rad +xy_out=deg') - request = QgsFeatureRequest().setCoordinateTransform( - transform) + request = QgsFeatureRequest().setCoordinateTransform(transform) transformed_features = list(vl.getFeatures(request)) self.assertEqual(len(transformed_features), 1) @@ -639,43 +861,46 @@ def test_vertical_transformation_AVWS_to_gda2020(self): """ # GDA2020 vertical CRS - vl = QgsVectorLayer('PointZ?crs=EPSG:7844', 'gda2020points', 'memory') + vl = QgsVectorLayer("PointZ?crs=EPSG:7844", "gda2020points", "memory") self.assertTrue(vl.isValid()) f = QgsFeature() - f.setGeometry(QgsPoint(134.445567853, - -23.445567853, - 5524.13969)) + f.setGeometry(QgsPoint(134.445567853, -23.445567853, 5524.13969)) self.assertTrue(vl.dataProvider().addFeature(f)) # AVWS source_crs, msg = QgsCoordinateReferenceSystem.createCompoundCrs( - QgsCoordinateReferenceSystem('EPSG:7844'), - QgsCoordinateReferenceSystem('EPSG:9458')) + QgsCoordinateReferenceSystem("EPSG:7844"), + QgsCoordinateReferenceSystem("EPSG:9458"), + ) self.assertFalse(msg) self.assertTrue(source_crs.isValid()) - self.assertEqual(source_crs.horizontalCrs().authid(), 'EPSG:7844') - self.assertEqual(source_crs.verticalCrs().authid(), 'EPSG:9458') + self.assertEqual(source_crs.horizontalCrs().authid(), "EPSG:7844") + self.assertEqual(source_crs.verticalCrs().authid(), "EPSG:9458") - available_operations = QgsDatumTransform.operations(source_crs, - QgsCoordinateReferenceSystem('EPSG:7843')) + available_operations = QgsDatumTransform.operations( + source_crs, QgsCoordinateReferenceSystem("EPSG:7843") + ) self.assertEqual(len(available_operations[0].grids), 1) - self.assertEqual(available_operations[0].grids[0].shortName, 'au_ga_AGQG_20201120.tif') + self.assertEqual( + available_operations[0].grids[0].shortName, "au_ga_AGQG_20201120.tif" + ) if not available_operations[0].isAvailable: - self.skipTest(f'Required grid {available_operations[0].grids[0].shortName} not available on system') + self.skipTest( + f"Required grid {available_operations[0].grids[0].shortName} not available on system" + ) # dest CRS is GDA2020 transform = QgsCoordinateTransform( source_crs, - QgsCoordinateReferenceSystem('EPSG:7843'), - QgsCoordinateTransformContext() + QgsCoordinateReferenceSystem("EPSG:7843"), + QgsCoordinateTransformContext(), ) # for debugging # self.assertEqual(transform.instantiatedCoordinateOperationDetails().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +inv +proj=vgridshift +grids=au_ga_AGQG_20201120.tif +multiplier=1 +step +proj=unitconvert +xy_in=rad +xy_out=deg') - request = QgsFeatureRequest().setCoordinateTransform( - transform) + request = QgsFeatureRequest().setCoordinateTransform(transform) transformed_features = list(vl.getFeatures(request)) self.assertEqual(len(transformed_features), 1) @@ -693,44 +918,44 @@ def test_vertical_transformation_gda2020_to_AHD(self): """ # GDA2020 vertical CRS - vl = QgsVectorLayer('PointZ?crs=EPSG:7843', 'gda2020points', 'memory') + vl = QgsVectorLayer("PointZ?crs=EPSG:7843", "gda2020points", "memory") self.assertTrue(vl.isValid()) - self.assertEqual(vl.crs().authid(), 'EPSG:7843') + self.assertEqual(vl.crs().authid(), "EPSG:7843") - self.assertEqual(vl.crs3D().horizontalCrs().authid(), 'EPSG:7843') + self.assertEqual(vl.crs3D().horizontalCrs().authid(), "EPSG:7843") f = QgsFeature() - f.setGeometry(QgsPoint(134.445567853, - -23.445567853, - 5543.325)) + f.setGeometry(QgsPoint(134.445567853, -23.445567853, 5543.325)) self.assertTrue(vl.dataProvider().addFeature(f)) # AHD dest_crs, msg = QgsCoordinateReferenceSystem.createCompoundCrs( - QgsCoordinateReferenceSystem('EPSG:7844'), - QgsCoordinateReferenceSystem('EPSG:5711')) + QgsCoordinateReferenceSystem("EPSG:7844"), + QgsCoordinateReferenceSystem("EPSG:5711"), + ) self.assertFalse(msg) self.assertTrue(dest_crs.isValid()) - self.assertEqual(dest_crs.horizontalCrs().authid(), 'EPSG:7844') - self.assertEqual(dest_crs.verticalCrs().authid(), 'EPSG:5711') + self.assertEqual(dest_crs.horizontalCrs().authid(), "EPSG:7844") + self.assertEqual(dest_crs.verticalCrs().authid(), "EPSG:5711") - available_operations = QgsDatumTransform.operations(vl.crs3D(), - dest_crs) + available_operations = QgsDatumTransform.operations(vl.crs3D(), dest_crs) self.assertEqual(len(available_operations[0].grids), 1) - self.assertEqual(available_operations[0].grids[0].shortName, 'au_ga_AUSGeoid2020_20180201.tif') + self.assertEqual( + available_operations[0].grids[0].shortName, + "au_ga_AUSGeoid2020_20180201.tif", + ) if not available_operations[0].isAvailable: - self.skipTest(f'Required grid {available_operations[0].grids[0].shortName} not available on system') + self.skipTest( + f"Required grid {available_operations[0].grids[0].shortName} not available on system" + ) transform = QgsCoordinateTransform( - vl.crs3D(), - dest_crs, - QgsCoordinateTransformContext() + vl.crs3D(), dest_crs, QgsCoordinateTransformContext() ) # for debugging # self.assertEqual(transform.instantiatedCoordinateOperationDetails().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +inv +proj=vgridshift +grids=au_ga_AGQG_20201120.tif +multiplier=1 +step +proj=unitconvert +xy_in=rad +xy_out=deg') - request = QgsFeatureRequest().setCoordinateTransform( - transform) + request = QgsFeatureRequest().setCoordinateTransform(transform) transformed_features = list(vl.getFeatures(request)) self.assertEqual(len(transformed_features), 1) @@ -748,43 +973,47 @@ def test_vertical_transformation_AHD_to_gda2020(self): """ # GDA2020 vertical CRS - vl = QgsVectorLayer('PointZ?crs=EPSG:7844', 'gda2020points', 'memory') + vl = QgsVectorLayer("PointZ?crs=EPSG:7844", "gda2020points", "memory") self.assertTrue(vl.isValid()) f = QgsFeature() - f.setGeometry(QgsPoint(134.445567853, - -23.445567853, - 5523.598)) + f.setGeometry(QgsPoint(134.445567853, -23.445567853, 5523.598)) self.assertTrue(vl.dataProvider().addFeature(f)) # AHD source_crs, msg = QgsCoordinateReferenceSystem.createCompoundCrs( - QgsCoordinateReferenceSystem('EPSG:7844'), - QgsCoordinateReferenceSystem('EPSG:5711')) + QgsCoordinateReferenceSystem("EPSG:7844"), + QgsCoordinateReferenceSystem("EPSG:5711"), + ) self.assertFalse(msg) self.assertTrue(source_crs.isValid()) - self.assertEqual(source_crs.horizontalCrs().authid(), 'EPSG:7844') - self.assertEqual(source_crs.verticalCrs().authid(), 'EPSG:5711') + self.assertEqual(source_crs.horizontalCrs().authid(), "EPSG:7844") + self.assertEqual(source_crs.verticalCrs().authid(), "EPSG:5711") # dest CRS is GDA2020 - available_operations = QgsDatumTransform.operations(source_crs, - QgsCoordinateReferenceSystem('EPSG:7843')) + available_operations = QgsDatumTransform.operations( + source_crs, QgsCoordinateReferenceSystem("EPSG:7843") + ) self.assertEqual(len(available_operations[0].grids), 1) - self.assertEqual(available_operations[0].grids[0].shortName, 'au_ga_AUSGeoid2020_20180201.tif') + self.assertEqual( + available_operations[0].grids[0].shortName, + "au_ga_AUSGeoid2020_20180201.tif", + ) if not available_operations[0].isAvailable: - self.skipTest(f'Required grid {available_operations[0].grids[0].shortName} not available on system') + self.skipTest( + f"Required grid {available_operations[0].grids[0].shortName} not available on system" + ) transform = QgsCoordinateTransform( source_crs, - QgsCoordinateReferenceSystem('EPSG:7843'), - QgsCoordinateTransformContext() + QgsCoordinateReferenceSystem("EPSG:7843"), + QgsCoordinateTransformContext(), ) # for debugging # self.assertEqual(transform.instantiatedCoordinateOperationDetails().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +inv +proj=vgridshift +grids=au_ga_AGQG_20201120.tif +multiplier=1 +step +proj=unitconvert +xy_in=rad +xy_out=deg') - request = QgsFeatureRequest().setCoordinateTransform( - transform) + request = QgsFeatureRequest().setCoordinateTransform(transform) transformed_features = list(vl.getFeatures(request)) self.assertEqual(len(transformed_features), 1) @@ -795,5 +1024,5 @@ def test_vertical_transformation_AHD_to_gda2020(self): self.assertAlmostEqual(geom.constGet().z(), 5543.325, 3) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfeaturepicker.py b/tests/src/python/test_qgsfeaturepicker.py index b61c0b0ef7c7..97f151ae4d6a 100644 --- a/tests/src/python/test_qgsfeaturepicker.py +++ b/tests/src/python/test_qgsfeaturepicker.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Denis Rouzaud' -__date__ = '24/04/2020' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Denis Rouzaud" +__date__ = "24/04/2020" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy, QTest from qgis.PyQt.QtWidgets import QComboBox @@ -26,8 +27,9 @@ def createLayer(manyFeatures: bool = False): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "test layer", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "test layer", "memory" + ) pr = layer.dataProvider() f = QgsFeature() f.setAttributes(["test1", 123]) @@ -60,7 +62,9 @@ def testSetFeature(self): spy = QSignalSpy(w.currentFeatureChanged) spy.wait() self.assertEqual(w.findChild(QComboBox).lineEdit().text(), "test2") - self.assertTrue(w.feature().geometry().equals(QgsGeometry.fromPointXY(QgsPointXY(200, 200)))) + self.assertTrue( + w.feature().geometry().equals(QgsGeometry.fromPointXY(QgsPointXY(200, 200))) + ) def testSetAllowNull(self): layer = createLayer() @@ -69,7 +73,10 @@ def testSetAllowNull(self): w.setAllowNull(True) spy = QSignalSpy(w.featureChanged) spy.wait() - self.assertEqual(w.findChild(QComboBox).lineEdit().text(), QgsApplication.nullRepresentation()) + self.assertEqual( + w.findChild(QComboBox).lineEdit().text(), + QgsApplication.nullRepresentation(), + ) w.setAllowNull(False) spy.wait() self.assertEqual(w.findChild(QComboBox).lineEdit().text(), "test1") @@ -98,5 +105,5 @@ def testLineEdit(self): self.assertEqual(w.feature().id(), 99) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfeaturerequest.py b/tests/src/python/test_qgsfeaturerequest.py index 33660906dd17..e8640e3b9150 100644 --- a/tests/src/python/test_qgsfeaturerequest.py +++ b/tests/src/python/test_qgsfeaturerequest.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '12/06/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "12/06/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QVariant from qgis.core import ( @@ -22,7 +23,7 @@ QgsGeometry, QgsRectangle, QgsSimplifyMethod, - QgsCoordinateTransform + QgsCoordinateTransform, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -82,7 +83,9 @@ def testFilterRect(self): self.assertTrue(req.referenceGeometry().isNull()) # setting filter rect should not change attribute filter - req = QgsFeatureRequest().setFilterFid(5).setFilterRect(QgsRectangle(1, 2, 3, 4)) + req = ( + QgsFeatureRequest().setFilterFid(5).setFilterRect(QgsRectangle(1, 2, 3, 4)) + ) self.assertEqual(req.filterType(), QgsFeatureRequest.FilterType.FilterFid) self.assertEqual(req.spatialFilterType(), Qgis.SpatialFilterType.BoundingBox) self.assertEqual(req.filterFid(), 5) @@ -90,7 +93,9 @@ def testFilterRect(self): self.assertEqual(req.filterRect(), QgsRectangle(1, 2, 3, 4)) # setting attribute filter should not change filter rect - req = QgsFeatureRequest().setFilterRect(QgsRectangle(1, 2, 3, 4)).setFilterFid(5) + req = ( + QgsFeatureRequest().setFilterRect(QgsRectangle(1, 2, 3, 4)).setFilterFid(5) + ) self.assertEqual(req.filterType(), QgsFeatureRequest.FilterType.FilterFid) self.assertEqual(req.spatialFilterType(), Qgis.SpatialFilterType.BoundingBox) self.assertEqual(req.filterFid(), 5) @@ -98,7 +103,9 @@ def testFilterRect(self): self.assertEqual(req.filterRect(), QgsRectangle(1, 2, 3, 4)) # setting null rectangle should clear spatial filter - req = QgsFeatureRequest().setFilterFid(5).setFilterRect(QgsRectangle(1, 2, 3, 4)) + req = ( + QgsFeatureRequest().setFilterFid(5).setFilterRect(QgsRectangle(1, 2, 3, 4)) + ) self.assertEqual(req.filterType(), QgsFeatureRequest.FilterType.FilterFid) self.assertEqual(req.spatialFilterType(), Qgis.SpatialFilterType.BoundingBox) self.assertEqual(req.filterFid(), 5) @@ -110,49 +117,69 @@ def testFilterRect(self): # setting distance within should override filter rect req = QgsFeatureRequest().setFilterRect(QgsRectangle(1, 2, 3, 4)) - req.setDistanceWithin(QgsGeometry.fromWkt('LineString(0 0, 10 0, 11 2)'), 1.2) + req.setDistanceWithin(QgsGeometry.fromWkt("LineString(0 0, 10 0, 11 2)"), 1.2) self.assertEqual(req.filterType(), QgsFeatureRequest.FilterType.FilterNone) self.assertEqual(req.spatialFilterType(), Qgis.SpatialFilterType.DistanceWithin) self.assertEqual(req.filterFid(), -1) self.assertFalse(req.filterFids()) - self.assertEqual(req.referenceGeometry().asWkt(), 'LineString (0 0, 10 0, 11 2)') + self.assertEqual( + req.referenceGeometry().asWkt(), "LineString (0 0, 10 0, 11 2)" + ) self.assertEqual(req.distanceWithin(), 1.2) def testDistanceWithin(self): - req = QgsFeatureRequest().setDistanceWithin(QgsGeometry.fromWkt('LineString(0 0, 10 0, 11 2)'), 1.2) + req = QgsFeatureRequest().setDistanceWithin( + QgsGeometry.fromWkt("LineString(0 0, 10 0, 11 2)"), 1.2 + ) self.assertEqual(req.filterType(), QgsFeatureRequest.FilterType.FilterNone) self.assertEqual(req.spatialFilterType(), Qgis.SpatialFilterType.DistanceWithin) self.assertEqual(req.filterFid(), -1) self.assertFalse(req.filterFids()) - self.assertEqual(req.referenceGeometry().asWkt(), 'LineString (0 0, 10 0, 11 2)') + self.assertEqual( + req.referenceGeometry().asWkt(), "LineString (0 0, 10 0, 11 2)" + ) self.assertEqual(req.distanceWithin(), 1.2) # filter rect should reflect bounding box of linestring + 1.2 self.assertEqual(req.filterRect(), QgsRectangle(-1.2, -1.2, 12.2, 3.2)) # setting distance within should not change attribute filter - req = QgsFeatureRequest().setFilterFid(5).setDistanceWithin(QgsGeometry.fromWkt('LineString(0 0, 10 0, 11 2)'), 1.2) + req = ( + QgsFeatureRequest() + .setFilterFid(5) + .setDistanceWithin(QgsGeometry.fromWkt("LineString(0 0, 10 0, 11 2)"), 1.2) + ) self.assertEqual(req.filterType(), QgsFeatureRequest.FilterType.FilterFid) self.assertEqual(req.spatialFilterType(), Qgis.SpatialFilterType.DistanceWithin) self.assertEqual(req.filterFid(), 5) self.assertFalse(req.filterFids()) - self.assertEqual(req.referenceGeometry().asWkt(), 'LineString (0 0, 10 0, 11 2)') + self.assertEqual( + req.referenceGeometry().asWkt(), "LineString (0 0, 10 0, 11 2)" + ) self.assertEqual(req.distanceWithin(), 1.2) # filter rect should reflect bounding box of linestring + 1.2 self.assertEqual(req.filterRect(), QgsRectangle(-1.2, -1.2, 12.2, 3.2)) # setting attribute filter should not change distance within - req = QgsFeatureRequest().setDistanceWithin(QgsGeometry.fromWkt('LineString(0 0, 10 0, 11 2)'), 1.2).setFilterFid(5) + req = ( + QgsFeatureRequest() + .setDistanceWithin(QgsGeometry.fromWkt("LineString(0 0, 10 0, 11 2)"), 1.2) + .setFilterFid(5) + ) self.assertEqual(req.filterType(), QgsFeatureRequest.FilterType.FilterFid) self.assertEqual(req.spatialFilterType(), Qgis.SpatialFilterType.DistanceWithin) self.assertEqual(req.filterFid(), 5) self.assertFalse(req.filterFids()) - self.assertEqual(req.referenceGeometry().asWkt(), 'LineString (0 0, 10 0, 11 2)') + self.assertEqual( + req.referenceGeometry().asWkt(), "LineString (0 0, 10 0, 11 2)" + ) self.assertEqual(req.distanceWithin(), 1.2) # filter rect should reflect bounding box of linestring + 1.2 self.assertEqual(req.filterRect(), QgsRectangle(-1.2, -1.2, 12.2, 3.2)) # setting filter rect should override distance within - req = QgsFeatureRequest().setDistanceWithin(QgsGeometry.fromWkt('LineString(0 0, 10 0, 11 2)'), 1.2) + req = QgsFeatureRequest().setDistanceWithin( + QgsGeometry.fromWkt("LineString(0 0, 10 0, 11 2)"), 1.2 + ) req.setFilterRect(QgsRectangle(1, 2, 3, 4)) self.assertEqual(req.filterType(), QgsFeatureRequest.FilterType.FilterNone) self.assertEqual(req.spatialFilterType(), Qgis.SpatialFilterType.BoundingBox) @@ -162,7 +189,9 @@ def testDistanceWithin(self): self.assertTrue(req.referenceGeometry().isNull()) self.assertEqual(req.distanceWithin(), 0) - req = QgsFeatureRequest().setDistanceWithin(QgsGeometry.fromWkt('LineString(0 0, 10 0, 11 2)'), 1.2) + req = QgsFeatureRequest().setDistanceWithin( + QgsGeometry.fromWkt("LineString(0 0, 10 0, 11 2)"), 1.2 + ) req.setFilterRect(QgsRectangle()) self.assertEqual(req.filterType(), QgsFeatureRequest.FilterType.FilterNone) self.assertEqual(req.spatialFilterType(), Qgis.SpatialFilterType.NoFilter) @@ -220,21 +249,37 @@ def testFilterFids(self): self.assertTrue(req.referenceGeometry().isNull()) def testInvalidGeomCheck(self): - req = QgsFeatureRequest().setFilterFids([5, 6]).setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid) + req = ( + QgsFeatureRequest() + .setFilterFids([5, 6]) + .setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid + ) + ) self.assertEqual(req.filterType(), QgsFeatureRequest.FilterType.FilterFids) self.assertEqual(req.filterFid(), -1) self.assertCountEqual(req.filterFids(), [5, 6]) - self.assertEqual(req.invalidGeometryCheck(), QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid) - req.setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck) - self.assertEqual(req.invalidGeometryCheck(), QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck) + self.assertEqual( + req.invalidGeometryCheck(), + QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid, + ) + req.setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck + ) + self.assertEqual( + req.invalidGeometryCheck(), + QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck, + ) def testFilterExpression(self): - req = QgsFeatureRequest().setFilterExpression('a=5') - self.assertEqual(req.filterType(), QgsFeatureRequest.FilterType.FilterExpression) + req = QgsFeatureRequest().setFilterExpression("a=5") + self.assertEqual( + req.filterType(), QgsFeatureRequest.FilterType.FilterExpression + ) self.assertEqual(req.spatialFilterType(), Qgis.SpatialFilterType.NoFilter) self.assertEqual(req.filterFid(), -1) self.assertFalse(req.filterFids()) - self.assertEqual(req.filterExpression().expression(), 'a=5') + self.assertEqual(req.filterExpression().expression(), "a=5") self.assertTrue(req.filterRect().isNull()) self.assertTrue(req.referenceGeometry().isNull()) @@ -242,33 +287,37 @@ def testFilterExpression(self): req.setFilterRect(QgsRectangle(1, 2, 3, 4)) self.assertEqual(req.filterFid(), -1) self.assertFalse(req.filterFids()) - self.assertEqual(req.filterExpression().expression(), 'a=5') + self.assertEqual(req.filterExpression().expression(), "a=5") self.assertEqual(req.spatialFilterType(), Qgis.SpatialFilterType.BoundingBox) self.assertEqual(req.filterRect(), QgsRectangle(1, 2, 3, 4)) self.assertTrue(req.referenceGeometry().isNull()) - req.setFilterExpression('a=8') + req.setFilterExpression("a=8") self.assertEqual(req.filterFid(), -1) self.assertFalse(req.filterFids()) - self.assertEqual(req.filterExpression().expression(), 'a=8') + self.assertEqual(req.filterExpression().expression(), "a=8") self.assertEqual(req.spatialFilterType(), Qgis.SpatialFilterType.BoundingBox) self.assertEqual(req.filterRect(), QgsRectangle(1, 2, 3, 4)) self.assertTrue(req.referenceGeometry().isNull()) def testCombineFilter(self): req = QgsFeatureRequest() - req.combineFilterExpression('b=9') - self.assertEqual(req.filterType(), QgsFeatureRequest.FilterType.FilterExpression) + req.combineFilterExpression("b=9") + self.assertEqual( + req.filterType(), QgsFeatureRequest.FilterType.FilterExpression + ) self.assertEqual(req.filterFid(), -1) self.assertFalse(req.filterFids()) - self.assertEqual(req.filterExpression().expression(), 'b=9') + self.assertEqual(req.filterExpression().expression(), "b=9") self.assertEqual(req.spatialFilterType(), Qgis.SpatialFilterType.NoFilter) self.assertTrue(req.filterRect().isNull()) self.assertTrue(req.referenceGeometry().isNull()) - req.combineFilterExpression('a=11') - self.assertEqual(req.filterType(), QgsFeatureRequest.FilterType.FilterExpression) - self.assertEqual(req.filterExpression().expression(), '(b=9) AND (a=11)') + req.combineFilterExpression("a=11") + self.assertEqual( + req.filterType(), QgsFeatureRequest.FilterType.FilterExpression + ) + self.assertEqual(req.filterExpression().expression(), "(b=9) AND (a=11)") self.assertEqual(req.spatialFilterType(), Qgis.SpatialFilterType.NoFilter) self.assertTrue(req.filterRect().isNull()) self.assertTrue(req.referenceGeometry().isNull()) @@ -279,12 +328,12 @@ def testExpressionContext(self): context = QgsExpressionContext() scope = QgsExpressionContextScope() - scope.setVariable('a', 6) + scope.setVariable("a", 6) context.appendScope(scope) req.setExpressionContext(context) self.assertEqual(req.expressionContext().scopeCount(), 1) - self.assertEqual(req.expressionContext().variable('a'), 6) + self.assertEqual(req.expressionContext().variable("a"), 6) def testDisableFilter(self): req = QgsFeatureRequest().setFilterFid(5).disableFilter() @@ -295,13 +344,17 @@ def testDisableFilter(self): self.assertEqual(req.filterType(), QgsFeatureRequest.FilterType.FilterNone) self.assertEqual(req.spatialFilterType(), Qgis.SpatialFilterType.NoFilter) - req = QgsFeatureRequest().setFilterExpression('a=5').disableFilter() + req = QgsFeatureRequest().setFilterExpression("a=5").disableFilter() self.assertEqual(req.filterType(), QgsFeatureRequest.FilterType.FilterNone) self.assertEqual(req.spatialFilterType(), Qgis.SpatialFilterType.NoFilter) self.assertFalse(req.filterExpression()) # disable filter does not disable spatial filter - req = QgsFeatureRequest().setFilterExpression('a=5').setFilterRect(QgsRectangle(1, 2, 3, 4)) + req = ( + QgsFeatureRequest() + .setFilterExpression("a=5") + .setFilterRect(QgsRectangle(1, 2, 3, 4)) + ) req.disableFilter() self.assertEqual(req.filterType(), QgsFeatureRequest.FilterType.FilterNone) self.assertEqual(req.spatialFilterType(), Qgis.SpatialFilterType.BoundingBox) @@ -339,28 +392,34 @@ def testSubsetAttributes(self): req.setFlags(QgsFeatureRequest.Flags()) f = QgsFields() - f.append(QgsField('a', QVariant.String)) - f.append(QgsField('b', QVariant.String)) - f.append(QgsField('c', QVariant.String)) - req.setSubsetOfAttributes(['a', 'c'], f) + f.append(QgsField("a", QVariant.String)) + f.append(QgsField("b", QVariant.String)) + f.append(QgsField("c", QVariant.String)) + req.setSubsetOfAttributes(["a", "c"], f) self.assertEqual(req.subsetOfAttributes(), [0, 2]) self.assertTrue(req.flags() & QgsFeatureRequest.Flag.SubsetOfAttributes) def testSimplifyMethod(self): req = QgsFeatureRequest() - self.assertEqual(req.simplifyMethod().methodType(), QgsSimplifyMethod.MethodType.NoSimplification) + self.assertEqual( + req.simplifyMethod().methodType(), + QgsSimplifyMethod.MethodType.NoSimplification, + ) method = QgsSimplifyMethod() method.setMethodType(QgsSimplifyMethod.MethodType.PreserveTopology) req.setSimplifyMethod(method) - self.assertEqual(req.simplifyMethod().methodType(), QgsSimplifyMethod.MethodType.PreserveTopology) + self.assertEqual( + req.simplifyMethod().methodType(), + QgsSimplifyMethod.MethodType.PreserveTopology, + ) def testDestinationCrs(self): req = QgsFeatureRequest() self.assertFalse(req.destinationCrs().isValid()) context = QgsCoordinateTransformContext() - req.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857'), context) + req.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857"), context) self.assertTrue(req.destinationCrs().isValid()) - self.assertEqual(req.destinationCrs().authid(), 'EPSG:3857') + self.assertEqual(req.destinationCrs().authid(), "EPSG:3857") def testTimeout(self): req = QgsFeatureRequest() @@ -379,33 +438,47 @@ def testCoordinateTransform(self): self.assertFalse(req.coordinateTransform().isValid()) req.setCoordinateTransform( QgsCoordinateTransform( - QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:3857'), - QgsCoordinateTransformContext() + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsCoordinateTransformContext(), ) ) self.assertTrue(req.coordinateTransform().isValid()) - self.assertEqual(req.coordinateTransform().sourceCrs().authid(), 'EPSG:3111') - self.assertEqual(req.coordinateTransform().destinationCrs().authid(), 'EPSG:3857') + self.assertEqual(req.coordinateTransform().sourceCrs().authid(), "EPSG:3111") + self.assertEqual( + req.coordinateTransform().destinationCrs().authid(), "EPSG:3857" + ) def testAssignment(self): - req = QgsFeatureRequest().setFilterFids([8, 9]).setFilterRect(QgsRectangle(1, 2, 3, 4)).setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid).setLimit(6).setFlags(QgsFeatureRequest.Flag.ExactIntersect).setSubsetOfAttributes([1, 4]).setTimeout(6).setRequestMayBeNested(True) + req = ( + QgsFeatureRequest() + .setFilterFids([8, 9]) + .setFilterRect(QgsRectangle(1, 2, 3, 4)) + .setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid + ) + .setLimit(6) + .setFlags(QgsFeatureRequest.Flag.ExactIntersect) + .setSubsetOfAttributes([1, 4]) + .setTimeout(6) + .setRequestMayBeNested(True) + ) context = QgsExpressionContext() scope = QgsExpressionContextScope() - scope.setVariable('a', 6) + scope.setVariable("a", 6) context.appendScope(scope) req.setExpressionContext(context) method = QgsSimplifyMethod() method.setMethodType(QgsSimplifyMethod.MethodType.PreserveTopology) req.setSimplifyMethod(method) context = QgsCoordinateTransformContext() - req.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857'), context) + req.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857"), context) req.setCoordinateTransform( QgsCoordinateTransform( - QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:3857'), - QgsCoordinateTransformContext() + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsCoordinateTransformContext(), ) ) @@ -414,28 +487,58 @@ def testAssignment(self): self.assertCountEqual(req2.filterFids(), [8, 9]) self.assertEqual(req2.filterRect(), QgsRectangle(1, 2, 3, 4)) self.assertEqual(req2.spatialFilterType(), Qgis.SpatialFilterType.BoundingBox) - self.assertEqual(req2.invalidGeometryCheck(), QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid) + self.assertEqual( + req2.invalidGeometryCheck(), + QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid, + ) self.assertEqual(req2.expressionContext().scopeCount(), 1) - self.assertEqual(req2.expressionContext().variable('a'), 6) - self.assertEqual(req2.flags(), QgsFeatureRequest.Flag.ExactIntersect | QgsFeatureRequest.Flag.SubsetOfAttributes) + self.assertEqual(req2.expressionContext().variable("a"), 6) + self.assertEqual( + req2.flags(), + QgsFeatureRequest.Flag.ExactIntersect + | QgsFeatureRequest.Flag.SubsetOfAttributes, + ) self.assertEqual(req2.subsetOfAttributes(), [1, 4]) - self.assertEqual(req2.simplifyMethod().methodType(), QgsSimplifyMethod.MethodType.PreserveTopology) - self.assertEqual(req2.destinationCrs().authid(), 'EPSG:3857') + self.assertEqual( + req2.simplifyMethod().methodType(), + QgsSimplifyMethod.MethodType.PreserveTopology, + ) + self.assertEqual(req2.destinationCrs().authid(), "EPSG:3857") self.assertEqual(req2.timeout(), 6) self.assertTrue(req2.requestMayBeNested()) - self.assertEqual(req2.coordinateTransform().sourceCrs().authid(), 'EPSG:3111') - self.assertEqual(req2.coordinateTransform().destinationCrs().authid(), 'EPSG:3857') + self.assertEqual(req2.coordinateTransform().sourceCrs().authid(), "EPSG:3111") + self.assertEqual( + req2.coordinateTransform().destinationCrs().authid(), "EPSG:3857" + ) # copy distance within request - req = QgsFeatureRequest().setDistanceWithin(QgsGeometry.fromWkt('LineString( 0 0, 10 0, 11 2)'), 1.2) + req = QgsFeatureRequest().setDistanceWithin( + QgsGeometry.fromWkt("LineString( 0 0, 10 0, 11 2)"), 1.2 + ) req2 = QgsFeatureRequest(req) - self.assertEqual(req2.spatialFilterType(), Qgis.SpatialFilterType.DistanceWithin) - self.assertEqual(req2.referenceGeometry().asWkt(), 'LineString (0 0, 10 0, 11 2)') + self.assertEqual( + req2.spatialFilterType(), Qgis.SpatialFilterType.DistanceWithin + ) + self.assertEqual( + req2.referenceGeometry().asWkt(), "LineString (0 0, 10 0, 11 2)" + ) self.assertEqual(req2.distanceWithin(), 1.2) self.assertEqual(req2.filterRect(), QgsRectangle(-1.2, -1.2, 12.2, 3.2)) def test_compare(self): - req1 = QgsFeatureRequest().setFilterFids([8, 9]).setFilterRect(QgsRectangle(1, 2, 3, 4)).setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid).setLimit(6).setFlags(QgsFeatureRequest.Flag.ExactIntersect).setSubsetOfAttributes([1, 4]).setTimeout(6).setRequestMayBeNested(True) + req1 = ( + QgsFeatureRequest() + .setFilterFids([8, 9]) + .setFilterRect(QgsRectangle(1, 2, 3, 4)) + .setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid + ) + .setLimit(6) + .setFlags(QgsFeatureRequest.Flag.ExactIntersect) + .setSubsetOfAttributes([1, 4]) + .setTimeout(6) + .setRequestMayBeNested(True) + ) req2 = QgsFeatureRequest(req1) self.assertTrue(req1.compare(req1)) self.assertTrue(req1.compare(req2)) @@ -451,7 +554,9 @@ def test_compare(self): self.assertFalse(req3.compare(req1)) req3 = QgsFeatureRequest(req2) - req3.setInvalidGeometryCheck(QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck) + req3.setInvalidGeometryCheck( + QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck + ) self.assertFalse(req3.compare(req1)) req3 = QgsFeatureRequest(req2) @@ -475,12 +580,12 @@ def test_compare(self): self.assertFalse(req3.compare(req1)) req3 = QgsFeatureRequest(req2) - orderClause = QgsFeatureRequest.OrderByClause('a', False) + orderClause = QgsFeatureRequest.OrderByClause("a", False) order = QgsFeatureRequest.OrderBy([orderClause]) req3.setOrderBy(order) self.assertFalse(req3.compare(req1)) req4 = QgsFeatureRequest(req2) - orderClause = QgsFeatureRequest.OrderByClause('a', False) + orderClause = QgsFeatureRequest.OrderByClause("a", False) order2 = QgsFeatureRequest.OrderBy([orderClause]) req4.setOrderBy(order2) self.assertTrue(req4.compare(req3)) @@ -490,7 +595,7 @@ def test_compare(self): req3 = QgsFeatureRequest(req2) context = QgsExpressionContext() scope = QgsExpressionContextScope() - scope.setVariable('a', 6) + scope.setVariable("a", 6) context.appendScope(scope) req3.setExpressionContext(context) self.assertTrue(req3.compare(req1)) @@ -499,25 +604,23 @@ def test_compare(self): req3 = QgsFeatureRequest(req2) req2.setCoordinateTransform( QgsCoordinateTransform( - QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:3857'), - QgsCoordinateTransformContext() + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsCoordinateTransformContext(), ) ) self.assertFalse(req3.compare(req2)) - req3.setCoordinateTransform( - req2.coordinateTransform() - ) + req3.setCoordinateTransform(req2.coordinateTransform()) self.assertTrue(req3.compare(req2)) def test_order_by_equality(self): - orderClause1 = QgsFeatureRequest.OrderByClause('a', False) - orderClause2 = QgsFeatureRequest.OrderByClause('a', False) + orderClause1 = QgsFeatureRequest.OrderByClause("a", False) + orderClause2 = QgsFeatureRequest.OrderByClause("a", False) self.assertTrue(orderClause1 == orderClause2) - orderClause2 = QgsFeatureRequest.OrderByClause('b', False) + orderClause2 = QgsFeatureRequest.OrderByClause("b", False) self.assertFalse(orderClause1 == orderClause2) - orderClause2 = QgsFeatureRequest.OrderByClause('a', True) + orderClause2 = QgsFeatureRequest.OrderByClause("a", True) self.assertFalse(orderClause1 == orderClause2) order1 = QgsFeatureRequest.OrderBy([orderClause1]) @@ -534,31 +637,32 @@ def test_calculate_transform(self): """ req = QgsFeatureRequest() # no transformation - transform = req.calculateTransform(QgsCoordinateReferenceSystem('EPSG:4326')) + transform = req.calculateTransform(QgsCoordinateReferenceSystem("EPSG:4326")) self.assertFalse(transform.isValid()) # transform using destination crs - req.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857'), - QgsCoordinateTransformContext()) - transform = req.calculateTransform(QgsCoordinateReferenceSystem('EPSG:4326')) + req.setDestinationCrs( + QgsCoordinateReferenceSystem("EPSG:3857"), QgsCoordinateTransformContext() + ) + transform = req.calculateTransform(QgsCoordinateReferenceSystem("EPSG:4326")) self.assertTrue(transform.isValid()) - self.assertEqual(transform.sourceCrs().authid(), 'EPSG:4326') - self.assertEqual(transform.destinationCrs().authid(), 'EPSG:3857') + self.assertEqual(transform.sourceCrs().authid(), "EPSG:4326") + self.assertEqual(transform.destinationCrs().authid(), "EPSG:3857") # transform using a specific coordinate transform, must take precedence req.setCoordinateTransform( QgsCoordinateTransform( - QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:3857'), - QgsCoordinateTransformContext() + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsCoordinateTransformContext(), ) ) # source crs is ignored - transform = req.calculateTransform(QgsCoordinateReferenceSystem('EPSG:4326')) + transform = req.calculateTransform(QgsCoordinateReferenceSystem("EPSG:4326")) self.assertTrue(transform.isValid()) - self.assertEqual(transform.sourceCrs().authid(), 'EPSG:3111') - self.assertEqual(transform.destinationCrs().authid(), 'EPSG:3857') + self.assertEqual(transform.sourceCrs().authid(), "EPSG:3111") + self.assertEqual(transform.destinationCrs().authid(), "EPSG:3857") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfeaturesink.py b/tests/src/python/test_qgsfeaturesink.py index f95312fb2122..82279e00556d 100644 --- a/tests/src/python/test_qgsfeaturesink.py +++ b/tests/src/python/test_qgsfeaturesink.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2017 by Nyall Dawson' -__date__ = '26/04/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "(C) 2017 by Nyall Dawson" +__date__ = "26/04/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtCore import QVariant from qgis.core import ( @@ -35,8 +36,9 @@ def createLayerWithFivePoints(): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) pr = layer.dataProvider() f = QgsFeature() f.setAttributes(["test", 123]) @@ -69,13 +71,13 @@ def testFromIterator(self): store = QgsFeatureStore(layer.fields(), layer.crs()) self.assertTrue(store.addFeatures(layer.getFeatures())) - vals = [f['fldint'] for f in store.features()] + vals = [f["fldint"] for f in store.features()] self.assertEqual(vals, [123, 457, 888, -1, 0]) def testProxyFeatureSink(self): fields = QgsFields() - fields.append(QgsField('fldtxt', QVariant.String)) - fields.append(QgsField('fldint', QVariant.Int)) + fields.append(QgsField("fldtxt", QVariant.String)) + fields.append(QgsField("fldint", QVariant.Int)) store = QgsFeatureStore(fields, QgsCoordinateReferenceSystem()) proxy = QgsProxyFeatureSink(store) @@ -88,7 +90,7 @@ def testProxyFeatureSink(self): f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(100, 200))) proxy.addFeature(f) self.assertEqual(len(store), 1) - self.assertEqual(store.features()[0]['fldtxt'], 'test') + self.assertEqual(store.features()[0]["fldtxt"], "test") f2 = QgsFeature() f2.setAttributes(["test2", 457]) @@ -98,32 +100,36 @@ def testProxyFeatureSink(self): f3.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(300, 200))) proxy.addFeatures([f2, f3]) self.assertEqual(len(store), 3) - self.assertEqual(store.features()[1]['fldtxt'], 'test2') - self.assertEqual(store.features()[2]['fldtxt'], 'test3') + self.assertEqual(store.features()[1]["fldtxt"], "test2") + self.assertEqual(store.features()[2]["fldtxt"], "test3") def testRemappingSinkDefinition(self): """ Test remapping sink definitions """ fields = QgsFields() - fields.append(QgsField('fldtxt', QVariant.String)) - fields.append(QgsField('fldint', QVariant.Int)) - fields.append(QgsField('fldtxt2', QVariant.String)) + fields.append(QgsField("fldtxt", QVariant.String)) + fields.append(QgsField("fldint", QVariant.Int)) + fields.append(QgsField("fldtxt2", QVariant.String)) mapping_def = QgsRemappingSinkDefinition() mapping_def.setDestinationWkbType(QgsWkbTypes.Type.Point) self.assertEqual(mapping_def.destinationWkbType(), QgsWkbTypes.Type.Point) - mapping_def.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:4326')) - mapping_def.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) - self.assertEqual(mapping_def.sourceCrs().authid(), 'EPSG:4326') - self.assertEqual(mapping_def.destinationCrs().authid(), 'EPSG:3857') + mapping_def.setSourceCrs(QgsCoordinateReferenceSystem("EPSG:4326")) + mapping_def.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) + self.assertEqual(mapping_def.sourceCrs().authid(), "EPSG:4326") + self.assertEqual(mapping_def.destinationCrs().authid(), "EPSG:3857") mapping_def.setDestinationFields(fields) self.assertEqual(mapping_def.destinationFields(), fields) - mapping_def.addMappedField('fldtxt2', QgsProperty.fromField('fld1')) - mapping_def.addMappedField('fldint', QgsProperty.fromExpression('@myval * fldint')) + mapping_def.addMappedField("fldtxt2", QgsProperty.fromField("fld1")) + mapping_def.addMappedField( + "fldint", QgsProperty.fromExpression("@myval * fldint") + ) - self.assertEqual(mapping_def.fieldMap()['fldtxt2'].field(), 'fld1') - self.assertEqual(mapping_def.fieldMap()['fldint'].expressionString(), '@myval * fldint') + self.assertEqual(mapping_def.fieldMap()["fldtxt2"].field(), "fld1") + self.assertEqual( + mapping_def.fieldMap()["fldint"].expressionString(), "@myval * fldint" + ) mapping_def2 = QgsRemappingSinkDefinition(mapping_def) self.assertTrue(mapping_def == mapping_def2) @@ -132,19 +138,21 @@ def testRemappingSinkDefinition(self): self.assertFalse(mapping_def == mapping_def2) self.assertTrue(mapping_def != mapping_def2) mapping_def2.setDestinationWkbType(QgsWkbTypes.Type.Point) - mapping_def2.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:3111')) + mapping_def2.setSourceCrs(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertFalse(mapping_def == mapping_def2) self.assertTrue(mapping_def != mapping_def2) - mapping_def2.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:4326')) - mapping_def2.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3111')) + mapping_def2.setSourceCrs(QgsCoordinateReferenceSystem("EPSG:4326")) + mapping_def2.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertFalse(mapping_def == mapping_def2) self.assertTrue(mapping_def != mapping_def2) - mapping_def2.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + mapping_def2.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) mapping_def2.setDestinationFields(QgsFields()) self.assertFalse(mapping_def == mapping_def2) self.assertTrue(mapping_def != mapping_def2) mapping_def2.setDestinationFields(fields) - mapping_def2.addMappedField('fldint3', QgsProperty.fromExpression('@myval * fldint')) + mapping_def2.addMappedField( + "fldint3", QgsProperty.fromExpression("@myval * fldint") + ) self.assertFalse(mapping_def == mapping_def2) self.assertTrue(mapping_def != mapping_def2) mapping_def2.setFieldMap(mapping_def.fieldMap()) @@ -157,31 +165,35 @@ def testRemappingSinkDefinition(self): def2 = QgsRemappingSinkDefinition() def2.loadVariant(var) self.assertEqual(def2.destinationWkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(def2.sourceCrs().authid(), 'EPSG:4326') - self.assertEqual(def2.destinationCrs().authid(), 'EPSG:3857') - self.assertEqual(def2.destinationFields()[0].name(), 'fldtxt') - self.assertEqual(def2.destinationFields()[1].name(), 'fldint') - self.assertEqual(def2.fieldMap()['fldtxt2'].field(), 'fld1') - self.assertEqual(def2.fieldMap()['fldint'].expressionString(), '@myval * fldint') + self.assertEqual(def2.sourceCrs().authid(), "EPSG:4326") + self.assertEqual(def2.destinationCrs().authid(), "EPSG:3857") + self.assertEqual(def2.destinationFields()[0].name(), "fldtxt") + self.assertEqual(def2.destinationFields()[1].name(), "fldint") + self.assertEqual(def2.fieldMap()["fldtxt2"].field(), "fld1") + self.assertEqual( + def2.fieldMap()["fldint"].expressionString(), "@myval * fldint" + ) def testRemappingSink(self): """ Test remapping features """ fields = QgsFields() - fields.append(QgsField('fldtxt', QVariant.String)) - fields.append(QgsField('fldint', QVariant.Int)) - fields.append(QgsField('fldtxt2', QVariant.String)) + fields.append(QgsField("fldtxt", QVariant.String)) + fields.append(QgsField("fldint", QVariant.Int)) + fields.append(QgsField("fldtxt2", QVariant.String)) - store = QgsFeatureStore(fields, QgsCoordinateReferenceSystem('EPSG:3857')) + store = QgsFeatureStore(fields, QgsCoordinateReferenceSystem("EPSG:3857")) mapping_def = QgsRemappingSinkDefinition() mapping_def.setDestinationWkbType(QgsWkbTypes.Type.Point) - mapping_def.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:4326')) - mapping_def.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + mapping_def.setSourceCrs(QgsCoordinateReferenceSystem("EPSG:4326")) + mapping_def.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) mapping_def.setDestinationFields(fields) - mapping_def.addMappedField('fldtxt2', QgsProperty.fromField('fld1')) - mapping_def.addMappedField('fldint', QgsProperty.fromExpression('@myval * fldint')) + mapping_def.addMappedField("fldtxt2", QgsProperty.fromField("fld1")) + mapping_def.addMappedField( + "fldint", QgsProperty.fromExpression("@myval * fldint") + ) proxy = QgsRemappingProxyFeatureSink(mapping_def, store) self.assertEqual(proxy.destinationSink(), store) @@ -189,12 +201,12 @@ def testRemappingSink(self): self.assertEqual(len(store), 0) incoming_fields = QgsFields() - incoming_fields.append(QgsField('fld1', QVariant.String)) - incoming_fields.append(QgsField('fldint', QVariant.Int)) + incoming_fields.append(QgsField("fld1", QVariant.String)) + incoming_fields.append(QgsField("fldint", QVariant.Int)) context = QgsExpressionContext() scope = QgsExpressionContextScope() - scope.setVariable('myval', 2) + scope.setVariable("myval", 2) context.appendScope(scope) context.setFields(incoming_fields) proxy.setExpressionContext(context) @@ -206,24 +218,32 @@ def testRemappingSink(self): f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(1, 2))) self.assertTrue(proxy.addFeature(f)) self.assertEqual(len(store), 1) - self.assertEqual(store.features()[0].geometry().asWkt(1), 'Point (111319.5 222684.2)') - self.assertEqual(store.features()[0].attributes(), [None, 246, 'test']) + self.assertEqual( + store.features()[0].geometry().asWkt(1), "Point (111319.5 222684.2)" + ) + self.assertEqual(store.features()[0].attributes(), [None, 246, "test"]) f2 = QgsFeature() f2.setAttributes(["test2", 457]) - f2.setGeometry(QgsGeometry.fromWkt('LineString( 1 1, 2 2)')) + f2.setGeometry(QgsGeometry.fromWkt("LineString( 1 1, 2 2)")) f3 = QgsFeature() f3.setAttributes(["test3", 888]) f3.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(3, 4))) self.assertTrue(proxy.addFeatures([f2, f3])) self.assertEqual(len(store), 4) - self.assertEqual(store.features()[1].attributes(), [None, 914, 'test2']) - self.assertEqual(store.features()[2].attributes(), [None, 914, 'test2']) - self.assertEqual(store.features()[3].attributes(), [None, 1776, 'test3']) - self.assertEqual(store.features()[1].geometry().asWkt(1), 'Point (111319.5 111325.1)') - self.assertEqual(store.features()[2].geometry().asWkt(1), 'Point (222639 222684.2)') - self.assertEqual(store.features()[3].geometry().asWkt(1), 'Point (333958.5 445640.1)') - - -if __name__ == '__main__': + self.assertEqual(store.features()[1].attributes(), [None, 914, "test2"]) + self.assertEqual(store.features()[2].attributes(), [None, 914, "test2"]) + self.assertEqual(store.features()[3].attributes(), [None, 1776, "test3"]) + self.assertEqual( + store.features()[1].geometry().asWkt(1), "Point (111319.5 111325.1)" + ) + self.assertEqual( + store.features()[2].geometry().asWkt(1), "Point (222639 222684.2)" + ) + self.assertEqual( + store.features()[3].geometry().asWkt(1), "Point (333958.5 445640.1)" + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfeaturesource.py b/tests/src/python/test_qgsfeaturesource.py index 44e8ab43fa59..56f4b37c9e90 100644 --- a/tests/src/python/test_qgsfeaturesource.py +++ b/tests/src/python/test_qgsfeaturesource.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2017 by Nyall Dawson' -__date__ = '26/04/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "(C) 2017 by Nyall Dawson" +__date__ = "26/04/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.core import ( @@ -27,8 +28,11 @@ def createLayerWithFivePoints(): - layer = QgsVectorLayer("Point?crs=EPSG:4326&field=id:integer&field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?crs=EPSG:4326&field=id:integer&field=fldtxt:string&field=fldint:integer", + "addfeat", + "memory", + ) pr = layer.dataProvider() f = QgsFeature() f.setAttributes([1, "test", 1]) @@ -61,7 +65,9 @@ def testUniqueValues(self): layer = createLayerWithFivePoints() self.assertFalse(layer.dataProvider().uniqueValues(-1)) self.assertFalse(layer.dataProvider().uniqueValues(100)) - self.assertEqual(layer.dataProvider().uniqueValues(1), {'test', 'test2', 'test3', 'test4'}) + self.assertEqual( + layer.dataProvider().uniqueValues(1), {"test", "test2", "test3", "test4"} + ) self.assertEqual(layer.dataProvider().uniqueValues(2), {1, 3, 3, 4}) def testMinValues(self): @@ -73,7 +79,7 @@ def testMinValues(self): layer = createLayerWithFivePoints() self.assertFalse(layer.dataProvider().minimumValue(-1)) self.assertFalse(layer.dataProvider().minimumValue(100)) - self.assertEqual(layer.dataProvider().minimumValue(1), 'test') + self.assertEqual(layer.dataProvider().minimumValue(1), "test") self.assertEqual(layer.dataProvider().minimumValue(2), 1) def testMaxValues(self): @@ -85,7 +91,7 @@ def testMaxValues(self): layer = createLayerWithFivePoints() self.assertFalse(layer.dataProvider().maximumValue(-1)) self.assertFalse(layer.dataProvider().maximumValue(100)) - self.assertEqual(layer.dataProvider().maximumValue(1), 'test4') + self.assertEqual(layer.dataProvider().maximumValue(1), "test4") self.assertEqual(layer.dataProvider().maximumValue(2), 4) def testMaterialize(self): @@ -121,22 +127,29 @@ def testMaterialize(self): self.assertEqual(new_features[id].attributes(), f.attributes()) # materialize with reprojection - request = QgsFeatureRequest().setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3785'), QgsProject.instance().transformContext()) + request = QgsFeatureRequest().setDestinationCrs( + QgsCoordinateReferenceSystem("EPSG:3785"), + QgsProject.instance().transformContext(), + ) new_layer = layer.materialize(request) self.assertEqual(new_layer.fields(), layer.fields()) - self.assertEqual(new_layer.crs().authid(), 'EPSG:3785') + self.assertEqual(new_layer.crs().authid(), "EPSG:3785") self.assertEqual(new_layer.featureCount(), 5) self.assertEqual(new_layer.wkbType(), QgsWkbTypes.Type.Point) new_features = {f[0]: f for f in new_layer.getFeatures()} - expected_geometry = {1: 'Point (111319 222684)', - 2: 'Point (222639 222684)', - 3: 'Point (333958 222684)', - 4: 'Point (445278 334111)', - 5: 'Point (0 0)'} + expected_geometry = { + 1: "Point (111319 222684)", + 2: "Point (222639 222684)", + 3: "Point (333958 222684)", + 4: "Point (445278 334111)", + 5: "Point (0 0)", + } for id, f in original_features.items(): self.assertEqual(new_features[id].attributes(), f.attributes()) - self.assertEqual(new_features[id].geometry().asWkt(0), expected_geometry[id]) + self.assertEqual( + new_features[id].geometry().asWkt(0), expected_geometry[id] + ) # materialize with attribute subset request = QgsFeatureRequest().setSubsetOfAttributes([0, 2]) @@ -171,5 +184,5 @@ def testMaterialize(self): self.assertEqual(new_features[id].attributes()[0], f.attributes()[0]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfeedback.py b/tests/src/python/test_qgsfeedback.py index 5ab83be1dbf3..dfb087a60cb9 100644 --- a/tests/src/python/test_qgsfeedback.py +++ b/tests/src/python/test_qgsfeedback.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '12/02/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "12/02/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy from qgis.core import QgsFeedback @@ -49,5 +50,5 @@ def testProcessedCount(self): self.assertEqual(processed_spy[0][0], 25) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfield.py b/tests/src/python/test_qgsfield.py index 19f8608e977c..d1f0e151fbc6 100644 --- a/tests/src/python/test_qgsfield.py +++ b/tests/src/python/test_qgsfield.py @@ -5,16 +5,13 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '16/08/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "16/08/2015" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.PyQt.QtCore import QVariant -from qgis.core import ( - Qgis, - QgsField, - QgsCoordinateReferenceSystem -) +from qgis.core import Qgis, QgsField, QgsCoordinateReferenceSystem import unittest from qgis.testing import start_app, QgisTestCase @@ -28,42 +25,61 @@ def test_metadata(self): self.assertFalse(field.metadata()) # set custom metadata - field.setMetadata(Qgis.FieldMetadataProperty.CustomProperty + 2, 'test') - self.assertEqual(field.metadata(Qgis.FieldMetadataProperty.CustomProperty + 2), - 'test') + field.setMetadata(Qgis.FieldMetadataProperty.CustomProperty + 2, "test") + self.assertEqual( + field.metadata(Qgis.FieldMetadataProperty.CustomProperty + 2), "test" + ) # set standard metadata - field.setMetadata(Qgis.FieldMetadataProperty.GeometryWkbType, Qgis.WkbType.LineStringZ) - self.assertEqual(field.metadata(Qgis.FieldMetadataProperty.GeometryWkbType), - Qgis.WkbType.LineStringZ) - - self.assertEqual(field.metadata(), - {Qgis.FieldMetadataProperty.GeometryWkbType: Qgis.WkbType.LineStringZ, - Qgis.FieldMetadataProperty.CustomProperty + 2: 'test'}) - - field.setMetadata({ - Qgis.FieldMetadataProperty.GeometryCrs: QgsCoordinateReferenceSystem("EPSG:3111"), - Qgis.FieldMetadataProperty.CustomProperty + 3: 'test2' - }) - - self.assertEqual(field.metadata(), - {Qgis.FieldMetadataProperty.GeometryCrs: QgsCoordinateReferenceSystem("EPSG:3111"), - Qgis.FieldMetadataProperty.CustomProperty + 3: 'test2'}) + field.setMetadata( + Qgis.FieldMetadataProperty.GeometryWkbType, Qgis.WkbType.LineStringZ + ) + self.assertEqual( + field.metadata(Qgis.FieldMetadataProperty.GeometryWkbType), + Qgis.WkbType.LineStringZ, + ) + + self.assertEqual( + field.metadata(), + { + Qgis.FieldMetadataProperty.GeometryWkbType: Qgis.WkbType.LineStringZ, + Qgis.FieldMetadataProperty.CustomProperty + 2: "test", + }, + ) + + field.setMetadata( + { + Qgis.FieldMetadataProperty.GeometryCrs: QgsCoordinateReferenceSystem( + "EPSG:3111" + ), + Qgis.FieldMetadataProperty.CustomProperty + 3: "test2", + } + ) + + self.assertEqual( + field.metadata(), + { + Qgis.FieldMetadataProperty.GeometryCrs: QgsCoordinateReferenceSystem( + "EPSG:3111" + ), + Qgis.FieldMetadataProperty.CustomProperty + 3: "test2", + }, + ) def test_convert_compatible_exceptions(self): - field = QgsField('test', QVariant.Int) + field = QgsField("test", QVariant.Int) self.assertTrue(field.convertCompatible(5)) with self.assertRaises(ValueError): - field.convertCompatible('abc') + field.convertCompatible("abc") - field = QgsField('test', QVariant.DateTime) + field = QgsField("test", QVariant.DateTime) with self.assertRaises(ValueError): field.convertCompatible(5) with self.assertRaises(ValueError): - field.convertCompatible('abc') + field.convertCompatible("abc") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfieldcombobox.py b/tests/src/python/test_qgsfieldcombobox.py index fac5c45be5c6..d2db7893f1e4 100644 --- a/tests/src/python/test_qgsfieldcombobox.py +++ b/tests/src/python/test_qgsfieldcombobox.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '20/07/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "20/07/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtCore import QVariant from qgis.PyQt.QtTest import QSignalSpy @@ -26,8 +27,11 @@ def create_layer(): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=fldint2:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer&field=fldint2:integer", + "addfeat", + "memory", + ) assert layer.isValid() return layer @@ -42,32 +46,32 @@ def create_model(): class TestQgsFieldComboBox(QgisTestCase): def testGettersSetters(self): - """ test combobox getters/setters """ + """test combobox getters/setters""" l = create_layer() w = QgsFieldComboBox() w.setLayer(l) self.assertEqual(w.layer(), l) - w.setField('fldint') - self.assertEqual(w.currentField(), 'fldint') + w.setField("fldint") + self.assertEqual(w.currentField(), "fldint") fields = QgsFields() - fields.append(QgsField('test1', QVariant.String)) - fields.append(QgsField('test2', QVariant.String)) + fields.append(QgsField("test1", QVariant.String)) + fields.append(QgsField("test2", QVariant.String)) w.setFields(fields) self.assertIsNone(w.layer()) self.assertEqual(w.fields(), fields) def testFilter(self): - """ test setting field with filter """ + """test setting field with filter""" l = create_layer() w = QgsFieldComboBox() w.setLayer(l) w.setFilters(QgsFieldProxyModel.Filter.Int) self.assertEqual(w.layer(), l) - w.setField('fldint') - self.assertEqual(w.currentField(), 'fldint') + w.setField("fldint") + self.assertEqual(w.currentField(), "fldint") def testSignals(self): l = create_layer() @@ -75,15 +79,15 @@ def testSignals(self): w.setLayer(l) spy = QSignalSpy(w.fieldChanged) - w.setField('fldint2') + w.setField("fldint2") self.assertEqual(len(spy), 1) - self.assertEqual(spy[-1][0], 'fldint2') - w.setField('fldint2') + self.assertEqual(spy[-1][0], "fldint2") + w.setField("fldint2") self.assertEqual(len(spy), 1) - self.assertEqual(spy[-1][0], 'fldint2') - w.setField('fldint') + self.assertEqual(spy[-1][0], "fldint2") + w.setField("fldint") self.assertEqual(len(spy), 2) - self.assertEqual(spy[-1][0], 'fldint') + self.assertEqual(spy[-1][0], "fldint") w.setField(None) self.assertEqual(len(spy), 3) self.assertEqual(spy[-1][0], None) @@ -93,14 +97,14 @@ def testSignals(self): def testManualFields(self): fields = QgsFields() - fields.append(QgsField('test1', QVariant.String)) - fields.append(QgsField('test2', QVariant.String)) + fields.append(QgsField("test1", QVariant.String)) + fields.append(QgsField("test2", QVariant.String)) w = QgsFieldComboBox() w.setFields(fields) self.assertEqual(w.count(), 2) - self.assertEqual(w.itemText(0), 'test1') - self.assertEqual(w.itemText(1), 'test2') + self.assertEqual(w.itemText(0), "test1") + self.assertEqual(w.itemText(1), "test2") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfielddomain.py b/tests/src/python/test_qgsfielddomain.py index 2cf8c9875331..77e3e200660a 100644 --- a/tests/src/python/test_qgsfielddomain.py +++ b/tests/src/python/test_qgsfielddomain.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2022-01-25' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2022-01-25" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.PyQt.QtCore import QVariant from qgis.core import ( @@ -23,87 +24,78 @@ class TestPyQgsFieldDomain(unittest.TestCase): def testCodedValue(self): - c = QgsCodedValue(5, 'a') + c = QgsCodedValue(5, "a") self.assertEqual(c.code(), 5) - self.assertEqual(c.value(), 'a') + self.assertEqual(c.value(), "a") - self.assertEqual(str(c), '') + self.assertEqual(str(c), "") - self.assertEqual(c, QgsCodedValue(5, 'a')) - self.assertNotEqual(c, QgsCodedValue(5, 'aa')) - self.assertNotEqual(c, QgsCodedValue(55, 'a')) + self.assertEqual(c, QgsCodedValue(5, "a")) + self.assertNotEqual(c, QgsCodedValue(5, "aa")) + self.assertNotEqual(c, QgsCodedValue(55, "a")) def testCodedFieldDomain(self): - domain = QgsCodedFieldDomain('name', - 'desc', - QVariant.Int, - [ - QgsCodedValue(5, 'a'), - QgsCodedValue(6, 'b') - ]) + domain = QgsCodedFieldDomain( + "name", "desc", QVariant.Int, [QgsCodedValue(5, "a"), QgsCodedValue(6, "b")] + ) - self.assertEqual(str(domain), '') + self.assertEqual(str(domain), "") self.assertEqual(domain.type(), Qgis.FieldDomainType.Coded) - self.assertEqual(domain.name(), 'name') - domain.setName('n') - self.assertEqual(domain.name(), 'n') + self.assertEqual(domain.name(), "name") + domain.setName("n") + self.assertEqual(domain.name(), "n") - self.assertEqual(domain.description(), 'desc') - domain.setDescription('desc 2') - self.assertEqual(domain.description(), 'desc 2') + self.assertEqual(domain.description(), "desc") + domain.setDescription("desc 2") + self.assertEqual(domain.description(), "desc 2") self.assertEqual(domain.fieldType(), QVariant.Int) domain.setFieldType(QVariant.Double) self.assertEqual(domain.fieldType(), QVariant.Double) - self.assertEqual(domain.values(), [ - QgsCodedValue(5, 'a'), - QgsCodedValue(6, 'b') - ]) - domain.setValues([ - QgsCodedValue(51, 'aa'), - QgsCodedValue(61, 'bb') - ]) - self.assertEqual(domain.values(), [ - QgsCodedValue(51, 'aa'), - QgsCodedValue(61, 'bb') - ]) + self.assertEqual( + domain.values(), [QgsCodedValue(5, "a"), QgsCodedValue(6, "b")] + ) + domain.setValues([QgsCodedValue(51, "aa"), QgsCodedValue(61, "bb")]) + self.assertEqual( + domain.values(), [QgsCodedValue(51, "aa"), QgsCodedValue(61, "bb")] + ) domain.setSplitPolicy(Qgis.FieldDomainSplitPolicy.GeometryRatio) - self.assertEqual(domain.splitPolicy(), Qgis.FieldDomainSplitPolicy.GeometryRatio) + self.assertEqual( + domain.splitPolicy(), Qgis.FieldDomainSplitPolicy.GeometryRatio + ) domain.setMergePolicy(Qgis.FieldDomainMergePolicy.GeometryWeighted) - self.assertEqual(domain.mergePolicy(), Qgis.FieldDomainMergePolicy.GeometryWeighted) + self.assertEqual( + domain.mergePolicy(), Qgis.FieldDomainMergePolicy.GeometryWeighted + ) d2 = domain.clone() - self.assertEqual(d2.name(), 'n') - self.assertEqual(d2.description(), 'desc 2') + self.assertEqual(d2.name(), "n") + self.assertEqual(d2.description(), "desc 2") self.assertEqual(d2.fieldType(), QVariant.Double) - self.assertEqual(d2.values(), [ - QgsCodedValue(51, 'aa'), - QgsCodedValue(61, 'bb') - ]) + self.assertEqual( + d2.values(), [QgsCodedValue(51, "aa"), QgsCodedValue(61, "bb")] + ) self.assertEqual(d2.splitPolicy(), Qgis.FieldDomainSplitPolicy.GeometryRatio) self.assertEqual(d2.mergePolicy(), Qgis.FieldDomainMergePolicy.GeometryWeighted) def testRangeFieldDomain(self): - domain = QgsRangeFieldDomain('name', - 'desc', - QVariant.Int, - 1, True, 5, True) + domain = QgsRangeFieldDomain("name", "desc", QVariant.Int, 1, True, 5, True) - self.assertEqual(str(domain), '') + self.assertEqual(str(domain), "") self.assertEqual(domain.type(), Qgis.FieldDomainType.Range) - self.assertEqual(domain.name(), 'name') - domain.setName('n') - self.assertEqual(domain.name(), 'n') + self.assertEqual(domain.name(), "name") + domain.setName("n") + self.assertEqual(domain.name(), "n") - self.assertEqual(domain.description(), 'desc') - domain.setDescription('desc 2') - self.assertEqual(domain.description(), 'desc 2') + self.assertEqual(domain.description(), "desc") + domain.setDescription("desc 2") + self.assertEqual(domain.description(), "desc 2") self.assertEqual(domain.fieldType(), QVariant.Int) domain.setFieldType(QVariant.Double) @@ -121,23 +113,27 @@ def testRangeFieldDomain(self): domain.setMinimumIsInclusive(False) self.assertFalse(domain.minimumIsInclusive()) - self.assertEqual(str(domain), '') + self.assertEqual(str(domain), "") self.assertTrue(domain.maximumIsInclusive()) domain.setMaximumIsInclusive(False) self.assertFalse(domain.maximumIsInclusive()) - self.assertEqual(str(domain), '') + self.assertEqual(str(domain), "") domain.setSplitPolicy(Qgis.FieldDomainSplitPolicy.GeometryRatio) - self.assertEqual(domain.splitPolicy(), Qgis.FieldDomainSplitPolicy.GeometryRatio) + self.assertEqual( + domain.splitPolicy(), Qgis.FieldDomainSplitPolicy.GeometryRatio + ) domain.setMergePolicy(Qgis.FieldDomainMergePolicy.GeometryWeighted) - self.assertEqual(domain.mergePolicy(), Qgis.FieldDomainMergePolicy.GeometryWeighted) + self.assertEqual( + domain.mergePolicy(), Qgis.FieldDomainMergePolicy.GeometryWeighted + ) d2 = domain.clone() - self.assertEqual(d2.name(), 'n') - self.assertEqual(d2.description(), 'desc 2') + self.assertEqual(d2.name(), "n") + self.assertEqual(d2.description(), "desc 2") self.assertEqual(d2.fieldType(), QVariant.Double) self.assertEqual(d2.minimum(), -1) self.assertEqual(d2.maximum(), 55) @@ -147,44 +143,45 @@ def testRangeFieldDomain(self): self.assertEqual(d2.mergePolicy(), Qgis.FieldDomainMergePolicy.GeometryWeighted) def testGlobFieldDomain(self): - domain = QgsGlobFieldDomain('name', - 'desc', - QVariant.String, - '*a*') + domain = QgsGlobFieldDomain("name", "desc", QVariant.String, "*a*") self.assertEqual(str(domain), "") self.assertEqual(domain.type(), Qgis.FieldDomainType.Glob) - self.assertEqual(domain.name(), 'name') - domain.setName('n') - self.assertEqual(domain.name(), 'n') + self.assertEqual(domain.name(), "name") + domain.setName("n") + self.assertEqual(domain.name(), "n") - self.assertEqual(domain.description(), 'desc') - domain.setDescription('desc 2') - self.assertEqual(domain.description(), 'desc 2') + self.assertEqual(domain.description(), "desc") + domain.setDescription("desc 2") + self.assertEqual(domain.description(), "desc 2") self.assertEqual(domain.fieldType(), QVariant.String) domain.setFieldType(QVariant.Double) self.assertEqual(domain.fieldType(), QVariant.Double) - self.assertEqual(domain.glob(), '*a*') - domain.setGlob('*b*') - self.assertEqual(domain.glob(), '*b*') + self.assertEqual(domain.glob(), "*a*") + domain.setGlob("*b*") + self.assertEqual(domain.glob(), "*b*") domain.setSplitPolicy(Qgis.FieldDomainSplitPolicy.GeometryRatio) - self.assertEqual(domain.splitPolicy(), Qgis.FieldDomainSplitPolicy.GeometryRatio) + self.assertEqual( + domain.splitPolicy(), Qgis.FieldDomainSplitPolicy.GeometryRatio + ) domain.setMergePolicy(Qgis.FieldDomainMergePolicy.GeometryWeighted) - self.assertEqual(domain.mergePolicy(), Qgis.FieldDomainMergePolicy.GeometryWeighted) + self.assertEqual( + domain.mergePolicy(), Qgis.FieldDomainMergePolicy.GeometryWeighted + ) d2 = domain.clone() - self.assertEqual(d2.name(), 'n') - self.assertEqual(d2.description(), 'desc 2') + self.assertEqual(d2.name(), "n") + self.assertEqual(d2.description(), "desc 2") self.assertEqual(d2.fieldType(), QVariant.Double) - self.assertEqual(d2.glob(), '*b*') + self.assertEqual(d2.glob(), "*b*") self.assertEqual(d2.splitPolicy(), Qgis.FieldDomainSplitPolicy.GeometryRatio) self.assertEqual(d2.mergePolicy(), Qgis.FieldDomainMergePolicy.GeometryWeighted) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfielddomainwidget.py b/tests/src/python/test_qgsfielddomainwidget.py index 1917b5e941cc..bb66bbd1fea9 100644 --- a/tests/src/python/test_qgsfielddomainwidget.py +++ b/tests/src/python/test_qgsfielddomainwidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2022-01-25' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2022-01-25" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.PyQt.QtCore import QVariant from qgis.core import ( @@ -41,7 +42,7 @@ def testRangeDomainWidget(self): self.assertTrue(domain.maximumIsInclusive()) # set domain and test round trips - domain = QgsRangeFieldDomain('name', 'desc', QVariant.Int, -10, False, -1, True) + domain = QgsRangeFieldDomain("name", "desc", QVariant.Int, -10, False, -1, True) domain.setSplitPolicy(Qgis.FieldDomainSplitPolicy.GeometryRatio) domain.setMergePolicy(Qgis.FieldDomainMergePolicy.Sum) w.setFieldDomain(domain) @@ -49,14 +50,18 @@ def testRangeDomainWidget(self): domain2 = w.createFieldDomain() self.assertIsInstance(domain2, QgsRangeFieldDomain) self.assertEqual(domain2.fieldType(), QVariant.Int) - self.assertEqual(domain2.splitPolicy(), Qgis.FieldDomainSplitPolicy.GeometryRatio) + self.assertEqual( + domain2.splitPolicy(), Qgis.FieldDomainSplitPolicy.GeometryRatio + ) self.assertEqual(domain2.mergePolicy(), Qgis.FieldDomainMergePolicy.Sum) self.assertEqual(domain2.minimum(), -10.0) self.assertFalse(domain2.minimumIsInclusive()) self.assertEqual(domain2.maximum(), -1.0) self.assertTrue(domain2.maximumIsInclusive()) - domain = QgsRangeFieldDomain('name', 'desc', QVariant.Int, -10.1, True, -1.1, False) + domain = QgsRangeFieldDomain( + "name", "desc", QVariant.Int, -10.1, True, -1.1, False + ) w.setFieldDomain(domain) domain2 = w.createFieldDomain() @@ -76,10 +81,10 @@ def testGlobWidget(self): self.assertEqual(domain.fieldType(), QVariant.String) self.assertEqual(domain.splitPolicy(), Qgis.FieldDomainSplitPolicy.DefaultValue) self.assertEqual(domain.mergePolicy(), Qgis.FieldDomainMergePolicy.DefaultValue) - self.assertEqual(domain.glob(), '') + self.assertEqual(domain.glob(), "") # set domain and test round trips - domain = QgsGlobFieldDomain('name', 'desc', QVariant.Int, '*a*') + domain = QgsGlobFieldDomain("name", "desc", QVariant.Int, "*a*") domain.setSplitPolicy(Qgis.FieldDomainSplitPolicy.GeometryRatio) domain.setMergePolicy(Qgis.FieldDomainMergePolicy.Sum) w.setFieldDomain(domain) @@ -87,9 +92,11 @@ def testGlobWidget(self): domain2 = w.createFieldDomain() self.assertIsInstance(domain2, QgsGlobFieldDomain) self.assertEqual(domain2.fieldType(), QVariant.Int) - self.assertEqual(domain2.splitPolicy(), Qgis.FieldDomainSplitPolicy.GeometryRatio) + self.assertEqual( + domain2.splitPolicy(), Qgis.FieldDomainSplitPolicy.GeometryRatio + ) self.assertEqual(domain2.mergePolicy(), Qgis.FieldDomainMergePolicy.Sum) - self.assertEqual(domain2.glob(), '*a*') + self.assertEqual(domain2.glob(), "*a*") def testCodedValueWidget(self): w = QgsFieldDomainWidget(Qgis.FieldDomainType.Coded) @@ -103,7 +110,16 @@ def testCodedValueWidget(self): self.assertFalse(domain.values()) # set domain and test round trips - domain = QgsCodedFieldDomain('name', 'desc', QVariant.Int, [QgsCodedValue('1', 'aa'), QgsCodedValue('2', 'bb'), QgsCodedValue('3', 'cc')]) + domain = QgsCodedFieldDomain( + "name", + "desc", + QVariant.Int, + [ + QgsCodedValue("1", "aa"), + QgsCodedValue("2", "bb"), + QgsCodedValue("3", "cc"), + ], + ) domain.setSplitPolicy(Qgis.FieldDomainSplitPolicy.GeometryRatio) domain.setMergePolicy(Qgis.FieldDomainMergePolicy.Sum) w.setFieldDomain(domain) @@ -111,10 +127,19 @@ def testCodedValueWidget(self): domain2 = w.createFieldDomain() self.assertIsInstance(domain2, QgsCodedFieldDomain) self.assertEqual(domain2.fieldType(), QVariant.Int) - self.assertEqual(domain2.splitPolicy(), Qgis.FieldDomainSplitPolicy.GeometryRatio) + self.assertEqual( + domain2.splitPolicy(), Qgis.FieldDomainSplitPolicy.GeometryRatio + ) self.assertEqual(domain2.mergePolicy(), Qgis.FieldDomainMergePolicy.Sum) - self.assertEqual(domain2.values(), [QgsCodedValue('1', 'aa'), QgsCodedValue('2', 'bb'), QgsCodedValue('3', 'cc')]) + self.assertEqual( + domain2.values(), + [ + QgsCodedValue("1", "aa"), + QgsCodedValue("2", "bb"), + QgsCodedValue("3", "cc"), + ], + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfieldformatters.py b/tests/src/python/test_qgsfieldformatters.py index fe99d276812d..f277d8b59d98 100644 --- a/tests/src/python/test_qgsfieldformatters.py +++ b/tests/src/python/test_qgsfieldformatters.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Matthias Kuhn' -__date__ = '05/12/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Matthias Kuhn" +__date__ = "05/12/2016" +__copyright__ = "Copyright 2016, The QGIS Project" import os import tempfile @@ -37,7 +38,9 @@ QgsValueMapFieldFormatter, QgsValueRelationFieldFormatter, QgsVectorFileWriter, - QgsVectorLayer, NULL) + QgsVectorLayer, + NULL, +) import unittest from qgis.testing import start_app, QgisTestCase from qgis.utils import spatialite_connect @@ -54,48 +57,96 @@ def test_representValue(self): QgsSettings().setValue("qgis/nullValue", "NULL") layer = QgsVectorLayer( "none?field=number1:integer&field=number2:double&field=text1:string&field=number3:integer&field=number4:double&field=text2:string", - "layer", "memory") + "layer", + "memory", + ) self.assertTrue(layer.isValid()) QgsProject.instance().addMapLayer(layer) f = QgsFeature() - f.setAttributes([2, 2.5, 'NULL', None, None, None]) + f.setAttributes([2, 2.5, "NULL", None, None, None]) layer.dataProvider().addFeatures([f]) fieldFormatter = QgsValueMapFieldFormatter() # Tests with different value types occurring in the value map # old style config (pre 3.0) - config = {'map': {'two': '2', 'twoandhalf': '2.5', 'NULL text': 'NULL', - 'nothing': self.VALUEMAP_NULL_TEXT}} - self.assertEqual(fieldFormatter.representValue(layer, 0, config, None, 2), 'two') - self.assertEqual(fieldFormatter.representValue(layer, 1, config, None, 2.5), 'twoandhalf') - self.assertEqual(fieldFormatter.representValue(layer, 2, config, None, 'NULL'), 'NULL text') + config = { + "map": { + "two": "2", + "twoandhalf": "2.5", + "NULL text": "NULL", + "nothing": self.VALUEMAP_NULL_TEXT, + } + } + self.assertEqual( + fieldFormatter.representValue(layer, 0, config, None, 2), "two" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, config, None, 2.5), "twoandhalf" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 2, config, None, "NULL"), "NULL text" + ) # Tests with null values of different types, if value map contains null - self.assertEqual(fieldFormatter.representValue(layer, 3, config, None, None), 'nothing') - self.assertEqual(fieldFormatter.representValue(layer, 4, config, None, None), 'nothing') - self.assertEqual(fieldFormatter.representValue(layer, 5, config, None, None), 'nothing') + self.assertEqual( + fieldFormatter.representValue(layer, 3, config, None, None), "nothing" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 4, config, None, None), "nothing" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 5, config, None, None), "nothing" + ) # new style config (post 3.0) - config = {'map': [{'two': '2'}, - {'twoandhalf': '2.5'}, - {'NULL text': 'NULL'}, - {'nothing': self.VALUEMAP_NULL_TEXT}]} - self.assertEqual(fieldFormatter.representValue(layer, 0, config, None, 2), 'two') - self.assertEqual(fieldFormatter.representValue(layer, 1, config, None, 2.5), 'twoandhalf') - self.assertEqual(fieldFormatter.representValue(layer, 2, config, None, 'NULL'), 'NULL text') + config = { + "map": [ + {"two": "2"}, + {"twoandhalf": "2.5"}, + {"NULL text": "NULL"}, + {"nothing": self.VALUEMAP_NULL_TEXT}, + ] + } + self.assertEqual( + fieldFormatter.representValue(layer, 0, config, None, 2), "two" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, config, None, 2.5), "twoandhalf" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 2, config, None, "NULL"), "NULL text" + ) # Tests with null values of different types, if value map contains null - self.assertEqual(fieldFormatter.representValue(layer, 3, config, None, None), 'nothing') - self.assertEqual(fieldFormatter.representValue(layer, 4, config, None, None), 'nothing') - self.assertEqual(fieldFormatter.representValue(layer, 5, config, None, None), 'nothing') + self.assertEqual( + fieldFormatter.representValue(layer, 3, config, None, None), "nothing" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 4, config, None, None), "nothing" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 5, config, None, None), "nothing" + ) # Tests with fallback display for different value types config = {} - self.assertEqual(fieldFormatter.representValue(layer, 0, config, None, 2), '(2)') - self.assertEqual(fieldFormatter.representValue(layer, 1, config, None, 2.5), '(2.50000)') - self.assertEqual(fieldFormatter.representValue(layer, 2, config, None, 'NULL'), '(NULL)') + self.assertEqual( + fieldFormatter.representValue(layer, 0, config, None, 2), "(2)" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, config, None, 2.5), "(2.50000)" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 2, config, None, "NULL"), "(NULL)" + ) # Tests with fallback display for null in different types of fields - self.assertEqual(fieldFormatter.representValue(layer, 3, config, None, None), '(NULL)') - self.assertEqual(fieldFormatter.representValue(layer, 4, config, None, None), '(NULL)') - self.assertEqual(fieldFormatter.representValue(layer, 5, config, None, None), '(NULL)') + self.assertEqual( + fieldFormatter.representValue(layer, 3, config, None, None), "(NULL)" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 4, config, None, None), "(NULL)" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 5, config, None, None), "(NULL)" + ) QgsProject.instance().removeAllMapLayers() @@ -103,45 +154,60 @@ def test_representValue(self): class TestQgsValueRelationFieldFormatter(QgisTestCase): def test_representValue(self): - first_layer = QgsVectorLayer("none?field=foreign_key:integer", - "first_layer", "memory") + first_layer = QgsVectorLayer( + "none?field=foreign_key:integer", "first_layer", "memory" + ) self.assertTrue(first_layer.isValid()) - second_layer = QgsVectorLayer("none?field=pkid:integer&field=decoded:string", - "second_layer", "memory") + second_layer = QgsVectorLayer( + "none?field=pkid:integer&field=decoded:string", "second_layer", "memory" + ) self.assertTrue(second_layer.isValid()) QgsProject.instance().addMapLayer(second_layer) f = QgsFeature() f.setAttributes([123]) first_layer.dataProvider().addFeatures([f]) f = QgsFeature() - f.setAttributes([123, 'decoded_val']) + f.setAttributes([123, "decoded_val"]) second_layer.dataProvider().addFeatures([f]) fieldFormatter = QgsValueRelationFieldFormatter() # Everything valid - config = {'Layer': second_layer.id(), 'Key': 'pkid', 'Value': 'decoded'} - self.assertEqual(fieldFormatter.representValue(first_layer, 0, config, None, '123'), 'decoded_val') + config = {"Layer": second_layer.id(), "Key": "pkid", "Value": "decoded"} + self.assertEqual( + fieldFormatter.representValue(first_layer, 0, config, None, "123"), + "decoded_val", + ) # Code not find match in foreign layer - config = {'Layer': second_layer.id(), 'Key': 'pkid', 'Value': 'decoded'} - self.assertEqual(fieldFormatter.representValue(first_layer, 0, config, None, '456'), '(456)') + config = {"Layer": second_layer.id(), "Key": "pkid", "Value": "decoded"} + self.assertEqual( + fieldFormatter.representValue(first_layer, 0, config, None, "456"), "(456)" + ) # Missing Layer - config = {'Key': 'pkid', 'Value': 'decoded'} - self.assertEqual(fieldFormatter.representValue(first_layer, 0, config, None, '456'), '(456)') + config = {"Key": "pkid", "Value": "decoded"} + self.assertEqual( + fieldFormatter.representValue(first_layer, 0, config, None, "456"), "(456)" + ) # Invalid Layer - config = {'Layer': 'invalid', 'Key': 'pkid', 'Value': 'decoded'} - self.assertEqual(fieldFormatter.representValue(first_layer, 0, config, None, '456'), '(456)') + config = {"Layer": "invalid", "Key": "pkid", "Value": "decoded"} + self.assertEqual( + fieldFormatter.representValue(first_layer, 0, config, None, "456"), "(456)" + ) # Invalid Key - config = {'Layer': second_layer.id(), 'Key': 'invalid', 'Value': 'decoded'} - self.assertEqual(fieldFormatter.representValue(first_layer, 0, config, None, '456'), '(456)') + config = {"Layer": second_layer.id(), "Key": "invalid", "Value": "decoded"} + self.assertEqual( + fieldFormatter.representValue(first_layer, 0, config, None, "456"), "(456)" + ) # Invalid Value - config = {'Layer': second_layer.id(), 'Key': 'pkid', 'Value': 'invalid'} - self.assertEqual(fieldFormatter.representValue(first_layer, 0, config, None, '456'), '(456)') + config = {"Layer": second_layer.id(), "Key": "pkid", "Value": "invalid"} + self.assertEqual( + fieldFormatter.representValue(first_layer, 0, config, None, "456"), "(456)" + ) QgsProject.instance().removeMapLayer(second_layer.id()) @@ -151,86 +217,154 @@ def _test(a, b): _test([1, 2, 3], ["1", "2", "3"]) _test("{1,2,3}", ["1", "2", "3"]) - _test(['1', '2', '3'], ["1", "2", "3"]) - _test('not an array', []) - _test('[1,2,3]', ["1", "2", "3"]) - _test('{1,2,3}', ["1", "2", "3"]) + _test(["1", "2", "3"], ["1", "2", "3"]) + _test("not an array", []) + _test("[1,2,3]", ["1", "2", "3"]) + _test("{1,2,3}", ["1", "2", "3"]) _test('{"1","2","3"}', ["1", "2", "3"]) _test('["1","2","3"]', ["1", "2", "3"]) - _test(r'["a string,comma","a string\"quote", "another string[]"]', - ['a string,comma', 'a string"quote', 'another string[]']) + _test( + r'["a string,comma","a string\"quote", "another string[]"]', + ["a string,comma", 'a string"quote', "another string[]"], + ) def test_expressionRequiresFormScope(self): res = list( - QgsValueRelationFieldFormatter.expressionFormAttributes("current_value('ONE') AND current_value('TWO')")) + QgsValueRelationFieldFormatter.expressionFormAttributes( + "current_value('ONE') AND current_value('TWO')" + ) + ) res = sorted(res) - self.assertEqual(res, ['ONE', 'TWO']) + self.assertEqual(res, ["ONE", "TWO"]) - res = list(QgsValueRelationFieldFormatter.expressionFormVariables("@current_geometry")) - self.assertEqual(res, ['current_geometry']) + res = list( + QgsValueRelationFieldFormatter.expressionFormVariables("@current_geometry") + ) + self.assertEqual(res, ["current_geometry"]) self.assertFalse(QgsValueRelationFieldFormatter.expressionRequiresFormScope("")) - self.assertTrue(QgsValueRelationFieldFormatter.expressionRequiresFormScope("current_value('TWO')")) - self.assertTrue(QgsValueRelationFieldFormatter.expressionRequiresFormScope("current_value ( 'TWO' )")) - self.assertTrue(QgsValueRelationFieldFormatter.expressionRequiresFormScope("@current_geometry")) + self.assertTrue( + QgsValueRelationFieldFormatter.expressionRequiresFormScope( + "current_value('TWO')" + ) + ) + self.assertTrue( + QgsValueRelationFieldFormatter.expressionRequiresFormScope( + "current_value ( 'TWO' )" + ) + ) + self.assertTrue( + QgsValueRelationFieldFormatter.expressionRequiresFormScope( + "@current_geometry" + ) + ) - self.assertTrue(QgsValueRelationFieldFormatter.expressionIsUsable("", QgsFeature())) - self.assertFalse(QgsValueRelationFieldFormatter.expressionIsUsable("@current_geometry", QgsFeature())) - self.assertFalse(QgsValueRelationFieldFormatter.expressionIsUsable("current_value ( 'TWO' )", QgsFeature())) + self.assertTrue( + QgsValueRelationFieldFormatter.expressionIsUsable("", QgsFeature()) + ) + self.assertFalse( + QgsValueRelationFieldFormatter.expressionIsUsable( + "@current_geometry", QgsFeature() + ) + ) + self.assertFalse( + QgsValueRelationFieldFormatter.expressionIsUsable( + "current_value ( 'TWO' )", QgsFeature() + ) + ) - layer = QgsVectorLayer("none?field=pkid:integer&field=decoded:string", - "layer", "memory") + layer = QgsVectorLayer( + "none?field=pkid:integer&field=decoded:string", "layer", "memory" + ) self.assertTrue(layer.isValid()) QgsProject.instance().addMapLayer(layer) f = QgsFeature(layer.fields()) - f.setAttributes([1, 'value']) + f.setAttributes([1, "value"]) point = QgsGeometry.fromPointXY(QgsPointXY(123, 456)) f.setGeometry(point) - self.assertTrue(QgsValueRelationFieldFormatter.expressionIsUsable("current_geometry", f)) - self.assertFalse(QgsValueRelationFieldFormatter.expressionIsUsable("current_value ( 'TWO' )", f)) - self.assertTrue(QgsValueRelationFieldFormatter.expressionIsUsable("current_value ( 'pkid' )", f)) self.assertTrue( - QgsValueRelationFieldFormatter.expressionIsUsable("@current_geometry current_value ( 'pkid' )", f)) + QgsValueRelationFieldFormatter.expressionIsUsable("current_geometry", f) + ) + self.assertFalse( + QgsValueRelationFieldFormatter.expressionIsUsable( + "current_value ( 'TWO' )", f + ) + ) + self.assertTrue( + QgsValueRelationFieldFormatter.expressionIsUsable( + "current_value ( 'pkid' )", f + ) + ) + self.assertTrue( + QgsValueRelationFieldFormatter.expressionIsUsable( + "@current_geometry current_value ( 'pkid' )", f + ) + ) QgsProject.instance().removeMapLayer(layer.id()) def test_expressionRequiresParentFormScope(self): - res = list(QgsValueRelationFieldFormatter.expressionFormAttributes( - "current_value('ONE') AND current_parent_value('TWO')")) + res = list( + QgsValueRelationFieldFormatter.expressionFormAttributes( + "current_value('ONE') AND current_parent_value('TWO')" + ) + ) res = sorted(res) - self.assertEqual(res, ['ONE']) + self.assertEqual(res, ["ONE"]) - res = list(QgsValueRelationFieldFormatter.expressionParentFormAttributes( - "current_value('ONE') AND current_parent_value('TWO')")) + res = list( + QgsValueRelationFieldFormatter.expressionParentFormAttributes( + "current_value('ONE') AND current_parent_value('TWO')" + ) + ) res = sorted(res) - self.assertEqual(res, ['TWO']) + self.assertEqual(res, ["TWO"]) - res = list(QgsValueRelationFieldFormatter.expressionParentFormVariables("@current_parent_geometry")) - self.assertEqual(res, ['current_parent_geometry']) + res = list( + QgsValueRelationFieldFormatter.expressionParentFormVariables( + "@current_parent_geometry" + ) + ) + self.assertEqual(res, ["current_parent_geometry"]) - self.assertFalse(QgsValueRelationFieldFormatter.expressionRequiresParentFormScope("")) - self.assertTrue(QgsValueRelationFieldFormatter.expressionRequiresParentFormScope("current_parent_value('TWO')")) + self.assertFalse( + QgsValueRelationFieldFormatter.expressionRequiresParentFormScope("") + ) self.assertTrue( - QgsValueRelationFieldFormatter.expressionRequiresParentFormScope("current_parent_value ( 'TWO' )")) - self.assertTrue(QgsValueRelationFieldFormatter.expressionRequiresParentFormScope("@current_parent_geometry")) + QgsValueRelationFieldFormatter.expressionRequiresParentFormScope( + "current_parent_value('TWO')" + ) + ) + self.assertTrue( + QgsValueRelationFieldFormatter.expressionRequiresParentFormScope( + "current_parent_value ( 'TWO' )" + ) + ) + self.assertTrue( + QgsValueRelationFieldFormatter.expressionRequiresParentFormScope( + "@current_parent_geometry" + ) + ) class TestQgsRelationReferenceFieldFormatter(QgisTestCase): def test_representValue(self): - first_layer = QgsVectorLayer("none?field=foreign_key:integer", - "first_layer", "memory") + first_layer = QgsVectorLayer( + "none?field=foreign_key:integer", "first_layer", "memory" + ) self.assertTrue(first_layer.isValid()) - second_layer = QgsVectorLayer("none?field=pkid:integer&field=decoded:string", - "second_layer", "memory") - second_layer.setDisplayExpression('pkid') + second_layer = QgsVectorLayer( + "none?field=pkid:integer&field=decoded:string", "second_layer", "memory" + ) + second_layer.setDisplayExpression("pkid") self.assertTrue(second_layer.isValid()) QgsProject.instance().addMapLayers([first_layer, second_layer]) f = QgsFeature() f.setAttributes([123]) first_layer.dataProvider().addFeatures([f]) f = QgsFeature() - f.setAttributes([123, 'decoded_val']) + f.setAttributes([123, "decoded_val"]) second_layer.dataProvider().addFeatures([f]) relMgr = QgsProject.instance().relationManager() @@ -238,68 +372,88 @@ def test_representValue(self): fieldFormatter = QgsRelationReferenceFieldFormatter() rel = QgsRelation() - rel.setId('rel1') - rel.setName('Relation Number One') + rel.setId("rel1") + rel.setName("Relation Number One") rel.setReferencingLayer(first_layer.id()) rel.setReferencedLayer(second_layer.id()) - rel.addFieldPair('foreign_key', 'pkid') + rel.addFieldPair("foreign_key", "pkid") self.assertTrue(rel.isValid()) relMgr.addRelation(rel) # Everything valid - config = {'Relation': rel.id()} - second_layer.setDisplayExpression('decoded') - self.assertEqual(fieldFormatter.representValue(first_layer, 0, config, None, '123'), 'decoded_val') + config = {"Relation": rel.id()} + second_layer.setDisplayExpression("decoded") + self.assertEqual( + fieldFormatter.representValue(first_layer, 0, config, None, "123"), + "decoded_val", + ) # Code not find match in foreign layer - config = {'Relation': rel.id()} - second_layer.setDisplayExpression('decoded') - self.assertEqual(fieldFormatter.representValue(first_layer, 0, config, None, '456'), '456') + config = {"Relation": rel.id()} + second_layer.setDisplayExpression("decoded") + self.assertEqual( + fieldFormatter.representValue(first_layer, 0, config, None, "456"), "456" + ) # Invalid relation id - config = {'Relation': 'invalid'} - second_layer.setDisplayExpression('decoded') - self.assertEqual(fieldFormatter.representValue(first_layer, 0, config, None, '123'), '123') + config = {"Relation": "invalid"} + second_layer.setDisplayExpression("decoded") + self.assertEqual( + fieldFormatter.representValue(first_layer, 0, config, None, "123"), "123" + ) # No display expression - will default internally to the decoded string - config = {'Relation': rel.id()} + config = {"Relation": rel.id()} second_layer.setDisplayExpression(None) - self.assertEqual(fieldFormatter.representValue(first_layer, 0, config, None, '123'), 'decoded_val') + self.assertEqual( + fieldFormatter.representValue(first_layer, 0, config, None, "123"), + "decoded_val", + ) # Invalid display expression - config = {'Relation': rel.id()} - second_layer.setDisplayExpression('invalid +') - self.assertEqual(fieldFormatter.representValue(first_layer, 0, config, None, '123'), '123') + config = {"Relation": rel.id()} + second_layer.setDisplayExpression("invalid +") + self.assertEqual( + fieldFormatter.representValue(first_layer, 0, config, None, "123"), "123" + ) # Missing relation config = {} - second_layer.setDisplayExpression('decoded') - self.assertEqual(fieldFormatter.representValue(first_layer, 0, config, None, '123'), '123') + second_layer.setDisplayExpression("decoded") + self.assertEqual( + fieldFormatter.representValue(first_layer, 0, config, None, "123"), "123" + ) # Inconsistent layer provided to representValue() - config = {'Relation': rel.id()} - second_layer.setDisplayExpression('decoded') - self.assertEqual(fieldFormatter.representValue(second_layer, 0, config, None, '123'), '123') + config = {"Relation": rel.id()} + second_layer.setDisplayExpression("decoded") + self.assertEqual( + fieldFormatter.representValue(second_layer, 0, config, None, "123"), "123" + ) # Inconsistent idx provided to representValue() - config = {'Relation': rel.id()} - second_layer.setDisplayExpression('decoded') - self.assertEqual(fieldFormatter.representValue(first_layer, 1, config, None, '123'), '123') + config = {"Relation": rel.id()} + second_layer.setDisplayExpression("decoded") + self.assertEqual( + fieldFormatter.representValue(first_layer, 1, config, None, "123"), "123" + ) # Invalid relation rel = QgsRelation() - rel.setId('rel2') - rel.setName('Relation Number Two') + rel.setId("rel2") + rel.setName("Relation Number Two") rel.setReferencingLayer(first_layer.id()) - rel.addFieldPair('foreign_key', 'pkid') + rel.addFieldPair("foreign_key", "pkid") self.assertFalse(rel.isValid()) relMgr.addRelation(rel) - config = {'Relation': rel.id()} - second_layer.setDisplayExpression('decoded') - self.assertEqual(fieldFormatter.representValue(first_layer, 0, config, None, '123'), '123') + config = {"Relation": rel.id()} + second_layer.setDisplayExpression("decoded") + self.assertEqual( + fieldFormatter.representValue(first_layer, 0, config, None, "123"), "123" + ) QgsProject.instance().removeAllMapLayers() @@ -324,84 +478,223 @@ def tearDownClass(cls): super().tearDownClass() def test_representValue(self): - layer = QgsVectorLayer("point?field=int:integer&field=double:double&field=long:long", - "layer", "memory") + layer = QgsVectorLayer( + "point?field=int:integer&field=double:double&field=long:long", + "layer", + "memory", + ) self.assertTrue(layer.isValid()) QgsProject.instance().addMapLayers([layer]) fieldFormatter = QgsRangeFieldFormatter() # Precision is ignored for integers and longlongs - self.assertEqual(fieldFormatter.representValue(layer, 0, {'Precision': 1}, None, '123'), '123') - self.assertEqual(fieldFormatter.representValue(layer, 0, {'Precision': 1}, None, '123000'), '123,000') - self.assertEqual(fieldFormatter.representValue(layer, 0, {'Precision': 1}, None, '9999999'), - '9,999,999') # no scientific notation for integers! - self.assertEqual(fieldFormatter.representValue(layer, 0, {'Precision': 1}, None, None), 'NULL') - self.assertEqual(fieldFormatter.representValue(layer, 2, {'Precision': 1}, None, '123'), '123') - self.assertEqual(fieldFormatter.representValue(layer, 2, {'Precision': 1}, None, '123000'), '123,000') - self.assertEqual(fieldFormatter.representValue(layer, 2, {'Precision': 1}, None, '9999999'), - '9,999,999') # no scientific notation for long longs! - self.assertEqual(fieldFormatter.representValue(layer, 2, {'Precision': 1}, None, None), 'NULL') - - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 1}, None, None), 'NULL') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 1}, None, '123'), '123.0') - - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, None), 'NULL') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '123000'), '123,000.00') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '0'), '0.00') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '123'), '123.00') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '0.123'), '0.12') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '0.127'), '0.13') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '0'), '0.000') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '0.127'), '0.127') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '1.27e-1'), '0.127') - - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '-123'), '-123.00') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '-0.123'), '-0.12') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '-0.127'), '-0.13') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '-0.127'), '-0.127') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '-1.27e-1'), '-0.127') + self.assertEqual( + fieldFormatter.representValue(layer, 0, {"Precision": 1}, None, "123"), + "123", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 0, {"Precision": 1}, None, "123000"), + "123,000", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 0, {"Precision": 1}, None, "9999999"), + "9,999,999", + ) # no scientific notation for integers! + self.assertEqual( + fieldFormatter.representValue(layer, 0, {"Precision": 1}, None, None), + "NULL", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 2, {"Precision": 1}, None, "123"), + "123", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 2, {"Precision": 1}, None, "123000"), + "123,000", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 2, {"Precision": 1}, None, "9999999"), + "9,999,999", + ) # no scientific notation for long longs! + self.assertEqual( + fieldFormatter.representValue(layer, 2, {"Precision": 1}, None, None), + "NULL", + ) + + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 1}, None, None), + "NULL", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 1}, None, "123"), + "123.0", + ) + + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 2}, None, None), + "NULL", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 2}, None, "123000"), + "123,000.00", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 2}, None, "0"), "0.00" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 2}, None, "123"), + "123.00", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 2}, None, "0.123"), + "0.12", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 2}, None, "0.127"), + "0.13", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 3}, None, "0"), + "0.000", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 3}, None, "0.127"), + "0.127", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 3}, None, "1.27e-1"), + "0.127", + ) + + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 2}, None, "-123"), + "-123.00", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 2}, None, "-0.123"), + "-0.12", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 2}, None, "-0.127"), + "-0.13", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 3}, None, "-0.127"), + "-0.127", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 3}, None, "-1.27e-1"), + "-0.127", + ) # Check with Italian locale - QLocale.setDefault(QLocale('it')) - - self.assertEqual(fieldFormatter.representValue(layer, 0, {'Precision': 1}, None, '9999999'), - '9.999.999') # scientific notation for integers! - self.assertEqual(fieldFormatter.representValue(layer, 2, {'Precision': 1}, None, '123'), '123') - self.assertEqual(fieldFormatter.representValue(layer, 2, {'Precision': 1}, None, '123000'), '123.000') - self.assertEqual(fieldFormatter.representValue(layer, 2, {'Precision': 1}, None, '9999999'), - '9.999.999') # scientific notation for long longs! - self.assertEqual(fieldFormatter.representValue(layer, 2, {'Precision': 1}, None, None), 'NULL') - - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, None), 'NULL') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '123000'), '123.000,00') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '0'), '0,00') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '123'), '123,00') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '0.123'), '0,12') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '0.127'), '0,13') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '0'), '0,000') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '0.127'), '0,127') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '1.27e-1'), '0,127') - - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '-123'), '-123,00') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '-0.123'), '-0,12') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '-0.127'), '-0,13') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '-0.127'), '-0,127') - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '-1.27e-1'), '-0,127') + QLocale.setDefault(QLocale("it")) + + self.assertEqual( + fieldFormatter.representValue(layer, 0, {"Precision": 1}, None, "9999999"), + "9.999.999", + ) # scientific notation for integers! + self.assertEqual( + fieldFormatter.representValue(layer, 2, {"Precision": 1}, None, "123"), + "123", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 2, {"Precision": 1}, None, "123000"), + "123.000", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 2, {"Precision": 1}, None, "9999999"), + "9.999.999", + ) # scientific notation for long longs! + self.assertEqual( + fieldFormatter.representValue(layer, 2, {"Precision": 1}, None, None), + "NULL", + ) + + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 2}, None, None), + "NULL", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 2}, None, "123000"), + "123.000,00", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 2}, None, "0"), "0,00" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 2}, None, "123"), + "123,00", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 2}, None, "0.123"), + "0,12", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 2}, None, "0.127"), + "0,13", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 3}, None, "0"), + "0,000", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 3}, None, "0.127"), + "0,127", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 3}, None, "1.27e-1"), + "0,127", + ) + + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 2}, None, "-123"), + "-123,00", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 2}, None, "-0.123"), + "-0,12", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 2}, None, "-0.127"), + "-0,13", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 3}, None, "-0.127"), + "-0,127", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 3}, None, "-1.27e-1"), + "-0,127", + ) # Check with custom locale without thousand separator - custom = QLocale('en') + custom = QLocale("en") custom.setNumberOptions(QLocale.NumberOption.OmitGroupSeparator) QLocale.setDefault(custom) - self.assertEqual(fieldFormatter.representValue(layer, 0, {'Precision': 1}, None, '9999999'), - '9999999') # scientific notation for integers! - self.assertEqual(fieldFormatter.representValue(layer, 2, {'Precision': 1}, None, '123'), '123') - self.assertEqual(fieldFormatter.representValue(layer, 2, {'Precision': 1}, None, '123000'), '123000') - self.assertEqual(fieldFormatter.representValue(layer, 2, {'Precision': 1}, None, '9999999'), - '9999999') # scientific notation for long longs! - self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '123000'), '123000.00') + self.assertEqual( + fieldFormatter.representValue(layer, 0, {"Precision": 1}, None, "9999999"), + "9999999", + ) # scientific notation for integers! + self.assertEqual( + fieldFormatter.representValue(layer, 2, {"Precision": 1}, None, "123"), + "123", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 2, {"Precision": 1}, None, "123000"), + "123000", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 2, {"Precision": 1}, None, "9999999"), + "9999999", + ) # scientific notation for long longs! + self.assertEqual( + fieldFormatter.representValue(layer, 1, {"Precision": 2}, None, "123000"), + "123000.00", + ) QgsProject.instance().removeAllMapLayers() @@ -413,7 +706,9 @@ def setUpClass(cls): """Run before all tests""" super().setUpClass() QCoreApplication.setOrganizationName("QGIS_Test") - QCoreApplication.setOrganizationDomain("QGIS_TestPyQgsCheckBoxFieldFormatter.com") + QCoreApplication.setOrganizationDomain( + "QGIS_TestPyQgsCheckBoxFieldFormatter.com" + ) QCoreApplication.setApplicationName("QGIS_TestPyQgsCheckBoxFieldFormatter") QgsSettings().clear() start_app() @@ -422,7 +717,11 @@ def test_representValue(self): null_value = "NULL" QgsApplication.setNullRepresentation(null_value) - layer = QgsVectorLayer("point?field=int:integer&field=str:string&field=bool:bool", "layer", "memory") + layer = QgsVectorLayer( + "point?field=int:integer&field=str:string&field=bool:bool", + "layer", + "memory", + ) self.assertTrue(layer.isValid()) field_formatter = QgsCheckBoxFieldFormatter() @@ -430,45 +729,85 @@ def test_representValue(self): # test with integer # normal case - config = {'UncheckedState': 0, 'CheckedState': 1} - self.assertEqual(field_formatter.representValue(layer, 0, config, None, 1), 'true') - self.assertEqual(field_formatter.representValue(layer, 0, config, None, 0), 'false') - self.assertEqual(field_formatter.representValue(layer, 0, config, None, 10), "(10)") + config = {"UncheckedState": 0, "CheckedState": 1} + self.assertEqual( + field_formatter.representValue(layer, 0, config, None, 1), "true" + ) + self.assertEqual( + field_formatter.representValue(layer, 0, config, None, 0), "false" + ) + self.assertEqual( + field_formatter.representValue(layer, 0, config, None, 10), "(10)" + ) # displaying stored values - config['TextDisplayMethod'] = QgsCheckBoxFieldFormatter.TextDisplayMethod.ShowStoredValues - self.assertEqual(field_formatter.representValue(layer, 0, config, None, 1), '1') - self.assertEqual(field_formatter.representValue(layer, 0, config, None, 0), '0') - self.assertEqual(field_formatter.representValue(layer, 0, config, None, 10), "(10)") + config["TextDisplayMethod"] = ( + QgsCheckBoxFieldFormatter.TextDisplayMethod.ShowStoredValues + ) + self.assertEqual(field_formatter.representValue(layer, 0, config, None, 1), "1") + self.assertEqual(field_formatter.representValue(layer, 0, config, None, 0), "0") + self.assertEqual( + field_formatter.representValue(layer, 0, config, None, 10), "(10)" + ) # invert true/false - config = {'UncheckedState': 1, 'CheckedState': 0} - self.assertEqual(field_formatter.representValue(layer, 0, config, None, 0), 'true') - self.assertEqual(field_formatter.representValue(layer, 0, config, None, 1), 'false') + config = {"UncheckedState": 1, "CheckedState": 0} + self.assertEqual( + field_formatter.representValue(layer, 0, config, None, 0), "true" + ) + self.assertEqual( + field_formatter.representValue(layer, 0, config, None, 1), "false" + ) # displaying stored values - config['TextDisplayMethod'] = QgsCheckBoxFieldFormatter.TextDisplayMethod.ShowStoredValues - self.assertEqual(field_formatter.representValue(layer, 0, config, None, 1), '1') - self.assertEqual(field_formatter.representValue(layer, 0, config, None, 0), '0') - self.assertEqual(field_formatter.representValue(layer, 0, config, None, 10), "(10)") + config["TextDisplayMethod"] = ( + QgsCheckBoxFieldFormatter.TextDisplayMethod.ShowStoredValues + ) + self.assertEqual(field_formatter.representValue(layer, 0, config, None, 1), "1") + self.assertEqual(field_formatter.representValue(layer, 0, config, None, 0), "0") + self.assertEqual( + field_formatter.representValue(layer, 0, config, None, 10), "(10)" + ) # test with string - config = {'UncheckedState': 'nooh', 'CheckedState': 'yeah'} - self.assertEqual(field_formatter.representValue(layer, 1, config, None, 'yeah'), 'true') - self.assertEqual(field_formatter.representValue(layer, 1, config, None, 'nooh'), 'false') - self.assertEqual(field_formatter.representValue(layer, 1, config, None, 'oops'), "(oops)") + config = {"UncheckedState": "nooh", "CheckedState": "yeah"} + self.assertEqual( + field_formatter.representValue(layer, 1, config, None, "yeah"), "true" + ) + self.assertEqual( + field_formatter.representValue(layer, 1, config, None, "nooh"), "false" + ) + self.assertEqual( + field_formatter.representValue(layer, 1, config, None, "oops"), "(oops)" + ) # displaying stored values - config['TextDisplayMethod'] = QgsCheckBoxFieldFormatter.TextDisplayMethod.ShowStoredValues - self.assertEqual(field_formatter.representValue(layer, 0, config, None, 'yeah'), 'yeah') - self.assertEqual(field_formatter.representValue(layer, 0, config, None, 'nooh'), 'nooh') - self.assertEqual(field_formatter.representValue(layer, 0, config, None, 'oops'), "(oops)") + config["TextDisplayMethod"] = ( + QgsCheckBoxFieldFormatter.TextDisplayMethod.ShowStoredValues + ) + self.assertEqual( + field_formatter.representValue(layer, 0, config, None, "yeah"), "yeah" + ) + self.assertEqual( + field_formatter.representValue(layer, 0, config, None, "nooh"), "nooh" + ) + self.assertEqual( + field_formatter.representValue(layer, 0, config, None, "oops"), "(oops)" + ) # bool - config['TextDisplayMethod'] = QgsCheckBoxFieldFormatter.TextDisplayMethod.ShowTrueFalse - self.assertEqual(field_formatter.representValue(layer, 2, config, None, True), 'true') - self.assertEqual(field_formatter.representValue(layer, 2, config, None, False), 'false') - self.assertEqual(field_formatter.representValue(layer, 2, config, None, NULL), 'NULL') + config["TextDisplayMethod"] = ( + QgsCheckBoxFieldFormatter.TextDisplayMethod.ShowTrueFalse + ) + self.assertEqual( + field_formatter.representValue(layer, 2, config, None, True), "true" + ) + self.assertEqual( + field_formatter.representValue(layer, 2, config, None, False), "false" + ) + self.assertEqual( + field_formatter.representValue(layer, 2, config, None, NULL), "NULL" + ) class TestQgsFallbackFieldFormatter(QgisTestCase): @@ -499,141 +838,284 @@ def _test(layer, is_gpkg=False): fieldFormatter = QgsFallbackFieldFormatter() - QLocale.setDefault(QLocale('en')) + QLocale.setDefault(QLocale("en")) # Precision is ignored for integers and longlongs - self.assertEqual(fieldFormatter.representValue(layer, 0 + offset, {}, None, '123'), '123') - self.assertEqual(fieldFormatter.representValue(layer, 0 + offset, {}, None, '123000'), '123,000') - self.assertEqual(fieldFormatter.representValue(layer, 0 + offset, {}, None, '9999999'), '9,999,999') - self.assertEqual(fieldFormatter.representValue(layer, 0 + offset, {}, None, None), 'NULL') - self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, '123'), '123') - self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, '123000'), '123,000') - self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, '9999999'), '9,999,999') - self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, None), 'NULL') - - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, None), 'NULL') + self.assertEqual( + fieldFormatter.representValue(layer, 0 + offset, {}, None, "123"), "123" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 0 + offset, {}, None, "123000"), + "123,000", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 0 + offset, {}, None, "9999999"), + "9,999,999", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 0 + offset, {}, None, None), "NULL" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 2 + offset, {}, None, "123"), "123" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 2 + offset, {}, None, "123000"), + "123,000", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 2 + offset, {}, None, "9999999"), + "9,999,999", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 2 + offset, {}, None, None), "NULL" + ) + + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, None), "NULL" + ) if not is_gpkg: - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123'), '123.00000') + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, "123"), + "123.00000", + ) else: - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123'), '123') + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, "123"), + "123", + ) - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, None), 'NULL') + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, None), "NULL" + ) if not is_gpkg: - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123000'), '123,000.00000') + self.assertEqual( + fieldFormatter.representValue( + layer, 1 + offset, {}, None, "123000" + ), + "123,000.00000", + ) else: - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123000'), '123,000') - - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '0'), '0') - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '0.127'), '0.127') - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '1.27e-1'), '0.127') + self.assertEqual( + fieldFormatter.representValue( + layer, 1 + offset, {}, None, "123000" + ), + "123,000", + ) + + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, "0"), "0" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, "0.127"), + "0.127", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, "1.27e-1"), + "0.127", + ) if not is_gpkg: - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '-123'), '-123.00000') + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, "-123"), + "-123.00000", + ) else: - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '-123'), '-123') - - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '-0.127'), '-0.127') - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '-1.27e-1'), '-0.127') + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, "-123"), + "-123", + ) + + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, "-0.127"), + "-0.127", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, "-1.27e-1"), + "-0.127", + ) # Check with Italian locale - QLocale.setDefault(QLocale('it')) - - self.assertEqual(fieldFormatter.representValue(layer, 0 + offset, {}, None, '9999999'), - '9.999.999') # scientific notation for integers! - self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, '123'), '123') - self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, '123000'), '123.000') - self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, '9999999'), '9.999.999') - self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, None), 'NULL') - - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, None), 'NULL') + QLocale.setDefault(QLocale("it")) + + self.assertEqual( + fieldFormatter.representValue(layer, 0 + offset, {}, None, "9999999"), + "9.999.999", + ) # scientific notation for integers! + self.assertEqual( + fieldFormatter.representValue(layer, 2 + offset, {}, None, "123"), "123" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 2 + offset, {}, None, "123000"), + "123.000", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 2 + offset, {}, None, "9999999"), + "9.999.999", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 2 + offset, {}, None, None), "NULL" + ) + + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, None), "NULL" + ) if not is_gpkg: - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123000'), '123.000,00000') + self.assertEqual( + fieldFormatter.representValue( + layer, 1 + offset, {}, None, "123000" + ), + "123.000,00000", + ) else: - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123000'), '123.000') + self.assertEqual( + fieldFormatter.representValue( + layer, 1 + offset, {}, None, "123000" + ), + "123.000", + ) - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '0'), '0') + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, "0"), "0" + ) if not is_gpkg: - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123'), '123,00000') + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, "123"), + "123,00000", + ) else: - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123'), '123') - - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '0.127'), '0,127') - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '1.27e-1'), '0,127') + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, "123"), + "123", + ) + + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, "0.127"), + "0,127", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, "1.27e-1"), + "0,127", + ) if not is_gpkg: - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '-123'), '-123,00000') + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, "-123"), + "-123,00000", + ) else: - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '-123'), '-123') - - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '-0.127'), '-0,127') - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '-1.27e-1'), '-0,127') + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, "-123"), + "-123", + ) + + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, "-0.127"), + "-0,127", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, "-1.27e-1"), + "-0,127", + ) # Check with custom locale without thousand separator - custom = QLocale('en') + custom = QLocale("en") custom.setNumberOptions(QLocale.NumberOption.OmitGroupSeparator) QLocale.setDefault(custom) - self.assertEqual(fieldFormatter.representValue(layer, 0 + offset, {}, None, '9999999'), - '9999999') # scientific notation for integers! - self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, '123'), '123') - self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, '9999999'), '9999999') + self.assertEqual( + fieldFormatter.representValue(layer, 0 + offset, {}, None, "9999999"), + "9999999", + ) # scientific notation for integers! + self.assertEqual( + fieldFormatter.representValue(layer, 2 + offset, {}, None, "123"), "123" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 2 + offset, {}, None, "9999999"), + "9999999", + ) if not is_gpkg: - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123000'), '123000.00000') + self.assertEqual( + fieldFormatter.representValue( + layer, 1 + offset, {}, None, "123000" + ), + "123000.00000", + ) else: - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123000'), '123000') + self.assertEqual( + fieldFormatter.representValue( + layer, 1 + offset, {}, None, "123000" + ), + "123000", + ) # Check string - self.assertEqual(fieldFormatter.representValue(layer, 3 + offset, {}, None, '123'), '123') - self.assertEqual(fieldFormatter.representValue(layer, 3 + offset, {}, None, 'a string'), 'a string') - self.assertEqual(fieldFormatter.representValue(layer, 3 + offset, {}, None, ''), '') - self.assertEqual(fieldFormatter.representValue(layer, 3 + offset, {}, None, None), 'NULL') + self.assertEqual( + fieldFormatter.representValue(layer, 3 + offset, {}, None, "123"), "123" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 3 + offset, {}, None, "a string"), + "a string", + ) + self.assertEqual( + fieldFormatter.representValue(layer, 3 + offset, {}, None, ""), "" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 3 + offset, {}, None, None), "NULL" + ) # Check NULLs (this is what happens in real life inside QGIS) - self.assertEqual(fieldFormatter.representValue(layer, 0 + offset, {}, None, NULL), - 'NULL') - self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, NULL), - 'NULL') - self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, NULL), - 'NULL') - self.assertEqual(fieldFormatter.representValue(layer, 3 + offset, {}, None, NULL), - 'NULL') - - memory_layer = QgsVectorLayer("point?field=int:integer&field=double:double&field=long:long&field=string:string", - "layer", "memory") + self.assertEqual( + fieldFormatter.representValue(layer, 0 + offset, {}, None, NULL), "NULL" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 1 + offset, {}, None, NULL), "NULL" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 2 + offset, {}, None, NULL), "NULL" + ) + self.assertEqual( + fieldFormatter.representValue(layer, 3 + offset, {}, None, NULL), "NULL" + ) + + memory_layer = QgsVectorLayer( + "point?field=int:integer&field=double:double&field=long:long&field=string:string", + "layer", + "memory", + ) self.assertTrue(memory_layer.isValid()) _test(memory_layer) # Test a shapefile - shape_path = writeShape(memory_layer, 'test_qgsfieldformatters.shp') + shape_path = writeShape(memory_layer, "test_qgsfieldformatters.shp") - shapefile_layer = QgsVectorLayer(shape_path, 'test', 'ogr') + shapefile_layer = QgsVectorLayer(shape_path, "test", "ogr") self.assertTrue(shapefile_layer.isValid()) _test(shapefile_layer) - gpkg_path = tempfile.mktemp('.gpkg') + gpkg_path = tempfile.mktemp(".gpkg") # Test a geopackage _, _ = QgsVectorFileWriter.writeAsVectorFormat( memory_layer, gpkg_path, - 'utf-8', + "utf-8", memory_layer.crs(), - 'GPKG', + "GPKG", False, [], [], - False + False, ) - gpkg_layer = QgsVectorLayer(gpkg_path, 'test', 'ogr') + gpkg_layer = QgsVectorLayer(gpkg_path, "test", "ogr") self.assertTrue(gpkg_layer.isValid()) # No precision here @@ -644,7 +1126,7 @@ def test_representValueWithDefault(self): Check representValue behaves correctly when used on a layer which define default values """ - dbname = os.path.join(tempfile.mkdtemp(), 'test.sqlite') + dbname = os.path.join(tempfile.mkdtemp(), "test.sqlite") con = spatialite_connect(dbname, isolation_level=None) cur = con.cursor() cur.execute("BEGIN") @@ -658,19 +1140,20 @@ def test_representValueWithDefault(self): cur.execute("COMMIT") con.close() - vl = QgsVectorLayer(dbname + '|layername=test_table_default_values', 'test_table_default_values', 'ogr') + vl = QgsVectorLayer( + dbname + "|layername=test_table_default_values", + "test_table_default_values", + "ogr", + ) self.assertTrue(vl.isValid()) fieldFormatter = QgsFallbackFieldFormatter() - QLocale.setDefault(QLocale('en')) + QLocale.setDefault(QLocale("en")) - self.assertEqual(fieldFormatter.representValue(vl, 1, {}, None, NULL), - 'NULL') - self.assertEqual(fieldFormatter.representValue(vl, 1, {}, None, 4), - '4') - self.assertEqual(fieldFormatter.representValue(vl, 1, {}, None, "123"), - '123') + self.assertEqual(fieldFormatter.representValue(vl, 1, {}, None, NULL), "NULL") + self.assertEqual(fieldFormatter.representValue(vl, 1, {}, None, 4), "4") + self.assertEqual(fieldFormatter.representValue(vl, 1, {}, None, "123"), "123") # bad field index self.assertEqual(fieldFormatter.representValue(vl, 3, {}, None, 5), "") @@ -695,8 +1178,11 @@ def tearDownClass(cls): super().tearDownClass() def test_representValue(self): - layer = QgsVectorLayer("point?field=datetime:datetime&field=date:date&field=time:time", - "layer", "memory") + layer = QgsVectorLayer( + "point?field=datetime:datetime&field=date:date&field=time:time", + "layer", + "memory", + ) self.assertTrue(layer.isValid()) QgsProject.instance().addMapLayers([layer]) @@ -704,32 +1190,63 @@ def test_representValue(self): # if specific display format is set then use that config = {"display_format": "dd/MM/yyyy HH:mm:ss"} - self.assertEqual(field_formatter.representValue(layer, 0, config, None, - QDateTime(QDate(2020, 3, 4), QTime(12, 13, 14), Qt.TimeSpec.UTC)), - '04/03/2020 12:13:14') - self.assertEqual(field_formatter.representValue(layer, 0, config, None, - QDateTime(QDate(2020, 3, 4), QTime(12, 13, 14), Qt.TimeSpec.OffsetFromUTC, 3600)), - '04/03/2020 12:13:14') + self.assertEqual( + field_formatter.representValue( + layer, + 0, + config, + None, + QDateTime(QDate(2020, 3, 4), QTime(12, 13, 14), Qt.TimeSpec.UTC), + ), + "04/03/2020 12:13:14", + ) + self.assertEqual( + field_formatter.representValue( + layer, + 0, + config, + None, + QDateTime( + QDate(2020, 3, 4), + QTime(12, 13, 14), + Qt.TimeSpec.OffsetFromUTC, + 3600, + ), + ), + "04/03/2020 12:13:14", + ) config = {"display_format": "dd/MM/yyyy HH:mm:ssZ"} - self.assertEqual(field_formatter.representValue(layer, 0, config, None, - QDateTime(QDate(2020, 3, 4), QTime(12, 13, 14), Qt.TimeSpec.OffsetFromUTC, 3600)), - '04/03/2020 11:13:14Z') + self.assertEqual( + field_formatter.representValue( + layer, + 0, + config, + None, + QDateTime( + QDate(2020, 3, 4), + QTime(12, 13, 14), + Qt.TimeSpec.OffsetFromUTC, + 3600, + ), + ), + "04/03/2020 11:13:14Z", + ) locale_assertions = { QLocale(QLocale.Language.English): { - "date_format": 'M/d/yy', - "time_format": 'HH:mm:ss', - "datetime_format": 'M/d/yy HH:mm:ss', - "datetime_utc": '3/4/20 12:13:14 (UTC)', - "datetime_utc+1": '3/4/20 12:13:14 (UTC+01:00)' + "date_format": "M/d/yy", + "time_format": "HH:mm:ss", + "datetime_format": "M/d/yy HH:mm:ss", + "datetime_utc": "3/4/20 12:13:14 (UTC)", + "datetime_utc+1": "3/4/20 12:13:14 (UTC+01:00)", }, QLocale(QLocale.Language.Finnish): { - "date_format": 'd.M.yyyy', - "time_format": 'HH:mm:ss', - "datetime_format": 'd.M.yyyy HH:mm:ss', - "datetime_utc": '4.3.2020 12:13:14 (UTC)', - "datetime_utc+1": '4.3.2020 12:13:14 (UTC+01:00)' + "date_format": "d.M.yyyy", + "time_format": "HH:mm:ss", + "datetime_format": "d.M.yyyy HH:mm:ss", + "datetime_utc": "4.3.2020 12:13:14 (UTC)", + "datetime_utc+1": "4.3.2020 12:13:14 (UTC+01:00)", }, } @@ -737,26 +1254,67 @@ def test_representValue(self): QgsApplication.setLocale(locale) field_formatter = QgsDateTimeFieldFormatter() - self.assertEqual(field_formatter.defaultDisplayFormat(QVariant.Date), assertions["date_format"], locale.name()) - self.assertEqual(field_formatter.defaultDisplayFormat(QVariant.Time), assertions["time_format"], locale.name()) - self.assertEqual(field_formatter.defaultDisplayFormat(QVariant.DateTime), assertions["datetime_format"], locale.name()) + self.assertEqual( + field_formatter.defaultDisplayFormat(QVariant.Date), + assertions["date_format"], + locale.name(), + ) + self.assertEqual( + field_formatter.defaultDisplayFormat(QVariant.Time), + assertions["time_format"], + locale.name(), + ) + self.assertEqual( + field_formatter.defaultDisplayFormat(QVariant.DateTime), + assertions["datetime_format"], + locale.name(), + ) # default configuration should show timezone information config = {} - self.assertEqual(field_formatter.representValue(layer, 0, config, None, - QDateTime(QDate(2020, 3, 4), QTime(12, 13, 14), Qt.TimeSpec.UTC)), - assertions["datetime_utc"], locale.name()) - self.assertEqual(field_formatter.representValue(layer, 0, config, None, - QDateTime(QDate(2020, 3, 4), QTime(12, 13, 14), Qt.TimeSpec.OffsetFromUTC, 3600)), - assertions["datetime_utc+1"], locale.name()) - self.assertEqual(field_formatter.representValue(layer, 1, config, None, - QDate(2020, 3, 4)), - assertions["datetime_utc"].split(" ")[0], locale.name()) + self.assertEqual( + field_formatter.representValue( + layer, + 0, + config, + None, + QDateTime(QDate(2020, 3, 4), QTime(12, 13, 14), Qt.TimeSpec.UTC), + ), + assertions["datetime_utc"], + locale.name(), + ) + self.assertEqual( + field_formatter.representValue( + layer, + 0, + config, + None, + QDateTime( + QDate(2020, 3, 4), + QTime(12, 13, 14), + Qt.TimeSpec.OffsetFromUTC, + 3600, + ), + ), + assertions["datetime_utc+1"], + locale.name(), + ) + self.assertEqual( + field_formatter.representValue( + layer, 1, config, None, QDate(2020, 3, 4) + ), + assertions["datetime_utc"].split(" ")[0], + locale.name(), + ) config = {"display_format": "HH:mm:s"} - self.assertEqual(field_formatter.representValue(layer, 2, config, None, - QTime(12, 13, 14)), - assertions["datetime_utc"].split(" ")[1], locale.name()) + self.assertEqual( + field_formatter.representValue( + layer, 2, config, None, QTime(12, 13, 14) + ), + assertions["datetime_utc"].split(" ")[1], + locale.name(), + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfieldmappingwidget.py b/tests/src/python/test_qgsfieldmappingwidget.py index 1c633621cb9c..9616e8075488 100644 --- a/tests/src/python/test_qgsfieldmappingwidget.py +++ b/tests/src/python/test_qgsfieldmappingwidget.py @@ -6,15 +6,18 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '16/03/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "16/03/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import ( QCoreApplication, QItemSelectionModel, QModelIndex, - QVariant, Qt) + QVariant, + Qt, +) from qgis.PyQt.QtGui import QColor from qgis.core import QgsField, QgsFieldConstraints, QgsFields, QgsProperty, NULL from qgis.gui import QgsFieldMappingModel, QgsFieldMappingWidget @@ -38,21 +41,21 @@ def setUp(self): """Run before each test""" source_fields = QgsFields() - f = QgsField('source_field1', QVariant.String) - f.setComment('my comment') + f = QgsField("source_field1", QVariant.String) + f.setComment("my comment") self.assertTrue(source_fields.append(f)) - f = QgsField('source_field2', QVariant.Int, 'integer', 10, 8) - f.setAlias('my alias') + f = QgsField("source_field2", QVariant.Int, "integer", 10, 8) + f.setAlias("my alias") self.assertTrue(source_fields.append(f)) destination_fields = QgsFields() - f = QgsField('destination_field1', QVariant.Int, 'integer', 10, 8) - f.setComment('my comment') + f = QgsField("destination_field1", QVariant.Int, "integer", 10, 8) + f.setComment("my comment") self.assertTrue(destination_fields.append(f)) - f = QgsField('destination_field2', QVariant.String) - f.setAlias('my alias') + f = QgsField("destination_field2", QVariant.String) + f.setAlias("my alias") self.assertTrue(destination_fields.append(f)) - f = QgsField('destination_field3', QVariant.String) + f = QgsField("destination_field3", QVariant.String) self.assertTrue(destination_fields.append(f)) self.source_fields = source_fields @@ -62,6 +65,7 @@ def _showDialog(self, widget): """Used during development""" from qgis.PyQt.QtWidgets import QDialog, QVBoxLayout + d = QDialog() l = QVBoxLayout() l.addWidget(widget) @@ -80,45 +84,72 @@ def testModel(self): # source_field2 | destination_field1 # source_field1 | destination_field2 # NOT SET (NULL) | destination_field3 - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), '"source_field2"') - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 'destination_field1') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), + '"source_field2"', + ) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), + "destination_field1", + ) self.assertEqual(model.data(model.index(0, 3), Qt.ItemDataRole.DisplayRole), 10) self.assertEqual(model.data(model.index(0, 4), Qt.ItemDataRole.DisplayRole), 8) self.assertFalse(model.data(model.index(0, 6), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(0, 7), Qt.ItemDataRole.DisplayRole), 'my comment') - - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), '"source_field1"') - self.assertEqual(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), 'destination_field2 (my alias)') - self.assertEqual(model.data(model.index(1, 6), Qt.ItemDataRole.DisplayRole), 'my alias') + self.assertEqual( + model.data(model.index(0, 7), Qt.ItemDataRole.DisplayRole), "my comment" + ) + + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), + '"source_field1"', + ) + self.assertEqual( + model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), + "destination_field2 (my alias)", + ) + self.assertEqual( + model.data(model.index(1, 6), Qt.ItemDataRole.DisplayRole), "my alias" + ) self.assertFalse(model.data(model.index(1, 7), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), NULL) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 'destination_field3') + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), NULL + ) + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), + "destination_field3", + ) self.assertFalse(model.data(model.index(2, 6), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(2, 7), Qt.ItemDataRole.DisplayRole)) # Test expression scope ctx = model.contextGenerator().createExpressionContext() - self.assertIn('source_field1', ctx.fields().names()) + self.assertIn("source_field1", ctx.fields().names()) # Test add fields - model.appendField(QgsField('destination_field4', QVariant.String)) + model.appendField(QgsField("destination_field4", QVariant.String)) self.assertEqual(model.rowCount(QModelIndex()), 4) - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 'destination_field4') + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), + "destination_field4", + ) # Test remove field model.removeField(model.index(3, 0)) self.assertEqual(model.rowCount(QModelIndex()), 3) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 'destination_field3') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), + "destination_field3", + ) # Test edit fields mapping = model.mapping() - self.assertEqual(mapping[0].field.name(), 'destination_field1') - self.assertEqual(mapping[1].field.name(), 'destination_field2') - self.assertEqual(mapping[2].field.name(), 'destination_field3') - self.assertEqual(mapping[0].originalName, 'destination_field1') - self.assertEqual(mapping[1].originalName, 'destination_field2') - self.assertEqual(mapping[2].originalName, 'destination_field3') + self.assertEqual(mapping[0].field.name(), "destination_field1") + self.assertEqual(mapping[1].field.name(), "destination_field2") + self.assertEqual(mapping[2].field.name(), "destination_field3") + self.assertEqual(mapping[0].originalName, "destination_field1") + self.assertEqual(mapping[1].originalName, "destination_field2") + self.assertEqual(mapping[2].originalName, "destination_field3") # Test move up or down self.assertFalse(model.moveUp(model.index(0, 0))) @@ -128,87 +159,129 @@ def testModel(self): self.assertTrue(model.moveDown(model.index(0, 0))) mapping = model.mapping() - self.assertEqual(mapping[1].field.name(), 'destination_field1') - self.assertEqual(mapping[0].field.name(), 'destination_field2') - self.assertEqual(mapping[2].field.name(), 'destination_field3') - self.assertEqual(mapping[1].originalName, 'destination_field1') - self.assertEqual(mapping[0].originalName, 'destination_field2') - self.assertEqual(mapping[2].originalName, 'destination_field3') + self.assertEqual(mapping[1].field.name(), "destination_field1") + self.assertEqual(mapping[0].field.name(), "destination_field2") + self.assertEqual(mapping[2].field.name(), "destination_field3") + self.assertEqual(mapping[1].originalName, "destination_field1") + self.assertEqual(mapping[0].originalName, "destination_field2") + self.assertEqual(mapping[2].originalName, "destination_field3") self.assertTrue(model.moveUp(model.index(1, 0))) mapping = model.mapping() - self.assertEqual(mapping[0].field.name(), 'destination_field1') - self.assertEqual(mapping[1].field.name(), 'destination_field2') - self.assertEqual(mapping[2].field.name(), 'destination_field3') - self.assertEqual(mapping[0].originalName, 'destination_field1') - self.assertEqual(mapping[1].originalName, 'destination_field2') - self.assertEqual(mapping[2].originalName, 'destination_field3') + self.assertEqual(mapping[0].field.name(), "destination_field1") + self.assertEqual(mapping[1].field.name(), "destination_field2") + self.assertEqual(mapping[2].field.name(), "destination_field3") + self.assertEqual(mapping[0].originalName, "destination_field1") + self.assertEqual(mapping[1].originalName, "destination_field2") + self.assertEqual(mapping[2].originalName, "destination_field3") self.assertTrue(model.moveUp(model.index(2, 0))) mapping = model.mapping() - self.assertEqual(mapping[0].field.name(), 'destination_field1') - self.assertEqual(mapping[2].field.name(), 'destination_field2') - self.assertEqual(mapping[1].field.name(), 'destination_field3') - self.assertEqual(mapping[0].originalName, 'destination_field1') - self.assertEqual(mapping[2].originalName, 'destination_field2') - self.assertEqual(mapping[1].originalName, 'destination_field3') + self.assertEqual(mapping[0].field.name(), "destination_field1") + self.assertEqual(mapping[2].field.name(), "destination_field2") + self.assertEqual(mapping[1].field.name(), "destination_field3") + self.assertEqual(mapping[0].originalName, "destination_field1") + self.assertEqual(mapping[2].originalName, "destination_field2") + self.assertEqual(mapping[1].originalName, "destination_field3") def testSetSourceFields(self): """Test that changing source fields also empty expressions are updated""" model = QgsFieldMappingModel(self.source_fields, self.destination_fields) - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), NULL) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 'destination_field3') - - f = QgsField('source_field3', QVariant.String) - f.setAlias('an alias') - f.setComment('a comment') + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), NULL + ) + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), + "destination_field3", + ) + + f = QgsField("source_field3", QVariant.String) + f.setAlias("an alias") + f.setComment("a comment") fields = self.source_fields fields.append(f) model.setSourceFields(fields) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), '"source_field2"') - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 'destination_field1') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), '"source_field1"') - self.assertEqual(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), 'destination_field2 (my alias)') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), '"source_field3"') - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 'destination_field3') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), + '"source_field2"', + ) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), + "destination_field1", + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), + '"source_field1"', + ) + self.assertEqual( + model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), + "destination_field2 (my alias)", + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), + '"source_field3"', + ) + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), + "destination_field3", + ) def testProperties(self): model = QgsFieldMappingModel(self.source_fields, self.destination_fields) - model.setDestinationFields(self.destination_fields, {'destination_field1': '5', - 'destination_field2': 'source_field2', - 'destination_field3': 'source_field2 * @myvar'}) + model.setDestinationFields( + self.destination_fields, + { + "destination_field1": "5", + "destination_field2": "source_field2", + "destination_field3": "source_field2 * @myvar", + }, + ) mapping = model.mapping() - self.assertEqual(mapping[0].field.name(), 'destination_field1') - self.assertEqual(mapping[1].field.name(), 'destination_field2') - self.assertEqual(mapping[2].field.name(), 'destination_field3') - self.assertEqual(mapping[0].expression, '5') - self.assertEqual(mapping[1].expression, 'source_field2') - self.assertEqual(mapping[2].expression, 'source_field2 * @myvar') - - self.assertEqual(model.fieldPropertyMap(), {'destination_field1': QgsProperty.fromExpression('5'), - 'destination_field2': QgsProperty.fromField('source_field2'), - 'destination_field3': QgsProperty.fromExpression( - 'source_field2 * @myvar'), - }) + self.assertEqual(mapping[0].field.name(), "destination_field1") + self.assertEqual(mapping[1].field.name(), "destination_field2") + self.assertEqual(mapping[2].field.name(), "destination_field3") + self.assertEqual(mapping[0].expression, "5") + self.assertEqual(mapping[1].expression, "source_field2") + self.assertEqual(mapping[2].expression, "source_field2 * @myvar") + + self.assertEqual( + model.fieldPropertyMap(), + { + "destination_field1": QgsProperty.fromExpression("5"), + "destination_field2": QgsProperty.fromField("source_field2"), + "destination_field3": QgsProperty.fromExpression( + "source_field2 * @myvar" + ), + }, + ) model = QgsFieldMappingModel(self.source_fields, self.destination_fields) - self.assertEqual(model.fieldPropertyMap(), {'destination_field1': QgsProperty.fromField('source_field2'), - 'destination_field2': QgsProperty.fromField('source_field1'), - 'destination_field3': QgsProperty.fromExpression(''), - }) - - model.setFieldPropertyMap({ - 'destination_field1': QgsProperty.fromField('source_field1'), - 'destination_field2': QgsProperty.fromExpression('55*6'), - 'destination_field3': QgsProperty.fromValue(6), - }) - self.assertEqual(model.fieldPropertyMap(), { - 'destination_field1': QgsProperty.fromField('source_field1'), - 'destination_field2': QgsProperty.fromExpression('55*6'), - 'destination_field3': QgsProperty.fromExpression('6'), - }) + self.assertEqual( + model.fieldPropertyMap(), + { + "destination_field1": QgsProperty.fromField("source_field2"), + "destination_field2": QgsProperty.fromField("source_field1"), + "destination_field3": QgsProperty.fromExpression(""), + }, + ) + + model.setFieldPropertyMap( + { + "destination_field1": QgsProperty.fromField("source_field1"), + "destination_field2": QgsProperty.fromExpression("55*6"), + "destination_field3": QgsProperty.fromValue(6), + } + ) + self.assertEqual( + model.fieldPropertyMap(), + { + "destination_field1": QgsProperty.fromField("source_field1"), + "destination_field2": QgsProperty.fromExpression("55*6"), + "destination_field3": QgsProperty.fromExpression("6"), + }, + ) def testWidget(self): """Test widget operations""" @@ -229,21 +302,27 @@ def _compare(widget, expected): selection_model = widget.selectionModel() selection_model.clear() for i in range(0, 10, 2): - selection_model.select(widget.model().index(i, 0), QItemSelectionModel.SelectionFlag.Select) + selection_model.select( + widget.model().index(i, 0), QItemSelectionModel.SelectionFlag.Select + ) self.assertTrue(widget.moveSelectedFieldsDown()) _compare(widget, [1, 0, 3, 2, 5, 4, 7, 6, 9, 8]) selection_model.clear() for i in range(1, 10, 2): - selection_model.select(widget.model().index(i, 0), QItemSelectionModel.SelectionFlag.Select) + selection_model.select( + widget.model().index(i, 0), QItemSelectionModel.SelectionFlag.Select + ) self.assertTrue(widget.moveSelectedFieldsUp()) _compare(widget, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) selection_model.clear() for i in range(0, 10, 2): - selection_model.select(widget.model().index(i, 0), QItemSelectionModel.SelectionFlag.Select) + selection_model.select( + widget.model().index(i, 0), QItemSelectionModel.SelectionFlag.Select + ) self.assertTrue(widget.removeSelectedFields()) _compare(widget, [1, 3, 5, 7, 9]) @@ -252,33 +331,54 @@ def _compare(widget, expected): widget.setSourceFields(self.source_fields) widget.setDestinationFields(self.destination_fields) mapping = widget.mapping() - self.assertEqual(mapping[0].field.name(), 'destination_field1') - self.assertEqual(mapping[1].field.name(), 'destination_field2') - self.assertEqual(mapping[2].field.name(), 'destination_field3') - self.assertEqual(mapping[0].originalName, 'destination_field1') - self.assertEqual(mapping[1].originalName, 'destination_field2') - self.assertEqual(mapping[2].originalName, 'destination_field3') + self.assertEqual(mapping[0].field.name(), "destination_field1") + self.assertEqual(mapping[1].field.name(), "destination_field2") + self.assertEqual(mapping[2].field.name(), "destination_field3") + self.assertEqual(mapping[0].originalName, "destination_field1") + self.assertEqual(mapping[1].originalName, "destination_field2") + self.assertEqual(mapping[2].originalName, "destination_field3") # Test constraints - f = QgsField('constraint_field', QVariant.Int) + f = QgsField("constraint_field", QVariant.Int) constraints = QgsFieldConstraints() - constraints.setConstraint(QgsFieldConstraints.Constraint.ConstraintNotNull, QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) - constraints.setConstraint(QgsFieldConstraints.Constraint.ConstraintExpression, - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) - constraints.setConstraint(QgsFieldConstraints.Constraint.ConstraintUnique, QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) + constraints.setConstraint( + QgsFieldConstraints.Constraint.ConstraintNotNull, + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) + constraints.setConstraint( + QgsFieldConstraints.Constraint.ConstraintExpression, + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) + constraints.setConstraint( + QgsFieldConstraints.Constraint.ConstraintUnique, + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) f.setConstraints(constraints) fields = QgsFields() fields.append(f) widget.setDestinationFields(fields) - self.assertEqual(widget.model().data(widget.model().index(0, 5, QModelIndex()), Qt.ItemDataRole.DisplayRole), - "Constraints active") - self.assertEqual(widget.model().data(widget.model().index(0, 5, QModelIndex()), Qt.ItemDataRole.ToolTipRole), - "Unique
    Not null
    Expression") - self.assertEqual(widget.model().data(widget.model().index(0, 5, QModelIndex()), Qt.ItemDataRole.BackgroundRole), - QColor(255, 224, 178)) + self.assertEqual( + widget.model().data( + widget.model().index(0, 5, QModelIndex()), Qt.ItemDataRole.DisplayRole + ), + "Constraints active", + ) + self.assertEqual( + widget.model().data( + widget.model().index(0, 5, QModelIndex()), Qt.ItemDataRole.ToolTipRole + ), + "Unique
    Not null
    Expression", + ) + self.assertEqual( + widget.model().data( + widget.model().index(0, 5, QModelIndex()), + Qt.ItemDataRole.BackgroundRole, + ), + QColor(255, 224, 178), + ) # self._showDialog(widget) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfieldmodel.py b/tests/src/python/test_qgsfieldmodel.py index ed5a6786f2ce..fcd78281fa26 100644 --- a/tests/src/python/test_qgsfieldmodel.py +++ b/tests/src/python/test_qgsfieldmodel.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '14/11/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "14/11/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtCore import QModelIndex, Qt, QVariant from qgis.core import ( @@ -28,10 +29,11 @@ def create_layer(): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") - layer.setEditorWidgetSetup(0, QgsEditorWidgetSetup('Hidden', {})) - layer.setEditorWidgetSetup(1, QgsEditorWidgetSetup('ValueMap', {})) + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) + layer.setEditorWidgetSetup(0, QgsEditorWidgetSetup("Hidden", {})) + layer.setEditorWidgetSetup(1, QgsEditorWidgetSetup("ValueMap", {})) assert layer.isValid() return layer @@ -46,7 +48,7 @@ def create_model(): class TestQgsFieldModel(QgisTestCase): def testGettersSetters(self): - """ test model getters/setters """ + """test model getters/setters""" l = create_layer() m = QgsFieldModel() @@ -65,52 +67,52 @@ def testGettersSetters(self): self.assertFalse(m.allowEmptyFieldName()) fields = QgsFields() - fields.append(QgsField('test1', QVariant.String)) - fields.append(QgsField('test2', QVariant.String)) + fields.append(QgsField("test1", QVariant.String)) + fields.append(QgsField("test2", QVariant.String)) m.setFields(fields) self.assertIsNone(m.layer()) self.assertEqual(m.fields(), fields) def testIndexFromName(self): l, m = create_model() - i = m.indexFromName('fldtxt') + i = m.indexFromName("fldtxt") self.assertTrue(i.isValid()) self.assertEqual(i.row(), 0) - i = m.indexFromName('fldint') + i = m.indexFromName("fldint") self.assertTrue(i.isValid()) self.assertEqual(i.row(), 1) - i = m.indexFromName('not a field') + i = m.indexFromName("not a field") self.assertFalse(i.isValid()) # test with alias - i = m.indexFromName('text field') + i = m.indexFromName("text field") self.assertFalse(i.isValid()) - l.setFieldAlias(0, 'text field') - i = m.indexFromName('text field') + l.setFieldAlias(0, "text field") + i = m.indexFromName("text field") self.assertTrue(i.isValid()) self.assertEqual(i.row(), 0) - i = m.indexFromName('int field') + i = m.indexFromName("int field") self.assertFalse(i.isValid()) - l.setFieldAlias(1, 'int field') - i = m.indexFromName('int field') + l.setFieldAlias(1, "int field") + i = m.indexFromName("int field") self.assertTrue(i.isValid()) self.assertEqual(i.row(), 1) # should be case insensitive - i = m.indexFromName('FLDTXT') + i = m.indexFromName("FLDTXT") self.assertTrue(i.isValid()) self.assertEqual(i.row(), 0) - i = m.indexFromName('FLDINT') + i = m.indexFromName("FLDINT") self.assertTrue(i.isValid()) self.assertEqual(i.row(), 1) # try with expression m.setAllowExpression(True) - i = m.indexFromName('not a field') + i = m.indexFromName("not a field") # still not valid - needs expression set first self.assertFalse(i.isValid()) - m.setExpression('not a field') - i = m.indexFromName('not a field') + m.setExpression("not a field") + i = m.indexFromName("not a field") self.assertTrue(i.isValid()) self.assertEqual(i.row(), 2) @@ -122,18 +124,18 @@ def testIndexFromName(self): self.assertTrue(i.isValid()) self.assertEqual(i.row(), 0) # when null is shown, all other rows should be offset - self.assertEqual(m.indexFromName('fldtxt').row(), 1) - self.assertEqual(m.indexFromName('fldint').row(), 2) - self.assertEqual(m.indexFromName('not a field').row(), 3) - self.assertEqual(m.indexFromName('FLDTXT').row(), 1) - self.assertEqual(m.indexFromName('FLDINT').row(), 2) + self.assertEqual(m.indexFromName("fldtxt").row(), 1) + self.assertEqual(m.indexFromName("fldint").row(), 2) + self.assertEqual(m.indexFromName("not a field").row(), 3) + self.assertEqual(m.indexFromName("FLDTXT").row(), 1) + self.assertEqual(m.indexFromName("FLDINT").row(), 2) def testIsField(self): l, m = create_model() - self.assertTrue(m.isField('fldtxt')) - self.assertTrue(m.isField('fldint')) + self.assertTrue(m.isField("fldtxt")) + self.assertTrue(m.isField("fldint")) self.assertFalse(m.isField(None)) - self.assertFalse(m.isField('an expression')) + self.assertFalse(m.isField("an expression")) def testRowCount(self): l, m = create_model() @@ -141,150 +143,348 @@ def testRowCount(self): m.setAllowEmptyFieldName(True) self.assertEqual(m.rowCount(), 3) m.setAllowExpression(True) - m.setExpression('not a field') + m.setExpression("not a field") self.assertEqual(m.rowCount(), 4) - m.setExpression('not a field') + m.setExpression("not a field") self.assertEqual(m.rowCount(), 4) - m.setExpression('not a field 2') + m.setExpression("not a field 2") self.assertEqual(m.rowCount(), 4) m.removeExpression() self.assertEqual(m.rowCount(), 3) def testFieldNameRole(self): l, m = create_model() - self.assertEqual(m.data(m.indexFromName('fldtxt'), QgsFieldModel.FieldRoles.FieldNameRole), 'fldtxt') - self.assertEqual(m.data(m.indexFromName('fldint'), QgsFieldModel.FieldRoles.FieldNameRole), 'fldint') - self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.FieldNameRole)) - self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.FieldNameRole)) + self.assertEqual( + m.data(m.indexFromName("fldtxt"), QgsFieldModel.FieldRoles.FieldNameRole), + "fldtxt", + ) + self.assertEqual( + m.data(m.indexFromName("fldint"), QgsFieldModel.FieldRoles.FieldNameRole), + "fldint", + ) + self.assertFalse( + m.data( + m.indexFromName("an expression"), QgsFieldModel.FieldRoles.FieldNameRole + ) + ) + self.assertFalse( + m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.FieldNameRole) + ) m.setAllowExpression(True) - m.setExpression('an expression') - self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.FieldNameRole)) + m.setExpression("an expression") + self.assertFalse( + m.data( + m.indexFromName("an expression"), QgsFieldModel.FieldRoles.FieldNameRole + ) + ) m.setAllowEmptyFieldName(True) - self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.FieldNameRole)) + self.assertFalse( + m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.FieldNameRole) + ) def testExpressionRole(self): l, m = create_model() - self.assertEqual(m.data(m.indexFromName('fldtxt'), QgsFieldModel.FieldRoles.ExpressionRole), 'fldtxt') - self.assertEqual(m.data(m.indexFromName('fldint'), QgsFieldModel.FieldRoles.ExpressionRole), 'fldint') - self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.ExpressionRole)) - self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.ExpressionRole)) + self.assertEqual( + m.data(m.indexFromName("fldtxt"), QgsFieldModel.FieldRoles.ExpressionRole), + "fldtxt", + ) + self.assertEqual( + m.data(m.indexFromName("fldint"), QgsFieldModel.FieldRoles.ExpressionRole), + "fldint", + ) + self.assertFalse( + m.data( + m.indexFromName("an expression"), + QgsFieldModel.FieldRoles.ExpressionRole, + ) + ) + self.assertFalse( + m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.ExpressionRole) + ) m.setAllowExpression(True) - m.setExpression('an expression') - self.assertEqual(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.ExpressionRole), 'an expression') + m.setExpression("an expression") + self.assertEqual( + m.data( + m.indexFromName("an expression"), + QgsFieldModel.FieldRoles.ExpressionRole, + ), + "an expression", + ) m.setAllowEmptyFieldName(True) - self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.ExpressionRole)) + self.assertFalse( + m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.ExpressionRole) + ) def testFieldIndexRole(self): l, m = create_model() - self.assertEqual(m.data(m.indexFromName('fldtxt'), QgsFieldModel.FieldRoles.FieldIndexRole), 0) - self.assertEqual(m.data(m.indexFromName('fldint'), QgsFieldModel.FieldRoles.FieldIndexRole), 1) - self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.FieldIndexRole)) - self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.FieldIndexRole)) + self.assertEqual( + m.data(m.indexFromName("fldtxt"), QgsFieldModel.FieldRoles.FieldIndexRole), + 0, + ) + self.assertEqual( + m.data(m.indexFromName("fldint"), QgsFieldModel.FieldRoles.FieldIndexRole), + 1, + ) + self.assertFalse( + m.data( + m.indexFromName("an expression"), + QgsFieldModel.FieldRoles.FieldIndexRole, + ) + ) + self.assertFalse( + m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.FieldIndexRole) + ) m.setAllowExpression(True) - m.setExpression('an expression') - self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.FieldIndexRole)) + m.setExpression("an expression") + self.assertFalse( + m.data( + m.indexFromName("an expression"), + QgsFieldModel.FieldRoles.FieldIndexRole, + ) + ) m.setAllowEmptyFieldName(True) - self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.FieldIndexRole)) + self.assertFalse( + m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.FieldIndexRole) + ) def testIsExpressionRole(self): l, m = create_model() - self.assertFalse(m.data(m.indexFromName('fldtxt'), QgsFieldModel.FieldRoles.IsExpressionRole)) - self.assertFalse(m.data(m.indexFromName('fldint'), QgsFieldModel.FieldRoles.IsExpressionRole)) - self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.IsExpressionRole)) - self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.IsExpressionRole)) + self.assertFalse( + m.data(m.indexFromName("fldtxt"), QgsFieldModel.FieldRoles.IsExpressionRole) + ) + self.assertFalse( + m.data(m.indexFromName("fldint"), QgsFieldModel.FieldRoles.IsExpressionRole) + ) + self.assertFalse( + m.data( + m.indexFromName("an expression"), + QgsFieldModel.FieldRoles.IsExpressionRole, + ) + ) + self.assertFalse( + m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.IsExpressionRole) + ) m.setAllowExpression(True) - m.setExpression('an expression') - self.assertTrue(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.IsExpressionRole)) + m.setExpression("an expression") + self.assertTrue( + m.data( + m.indexFromName("an expression"), + QgsFieldModel.FieldRoles.IsExpressionRole, + ) + ) m.setAllowEmptyFieldName(True) - self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.IsExpressionRole)) + self.assertFalse( + m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.IsExpressionRole) + ) def testExpressionValidityRole(self): l, m = create_model() - self.assertTrue(m.data(m.indexFromName('fldtxt'), QgsFieldModel.FieldRoles.ExpressionValidityRole)) - self.assertTrue(m.data(m.indexFromName('fldint'), QgsFieldModel.FieldRoles.ExpressionValidityRole)) - self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.ExpressionValidityRole)) - self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.ExpressionValidityRole)) + self.assertTrue( + m.data( + m.indexFromName("fldtxt"), + QgsFieldModel.FieldRoles.ExpressionValidityRole, + ) + ) + self.assertTrue( + m.data( + m.indexFromName("fldint"), + QgsFieldModel.FieldRoles.ExpressionValidityRole, + ) + ) + self.assertFalse( + m.data( + m.indexFromName("an expression"), + QgsFieldModel.FieldRoles.ExpressionValidityRole, + ) + ) + self.assertFalse( + m.data( + m.indexFromName(None), QgsFieldModel.FieldRoles.ExpressionValidityRole + ) + ) m.setAllowExpression(True) - m.setExpression('an expression') - self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.ExpressionValidityRole)) + m.setExpression("an expression") + self.assertFalse( + m.data( + m.indexFromName("an expression"), + QgsFieldModel.FieldRoles.ExpressionValidityRole, + ) + ) m.setAllowEmptyFieldName(True) - self.assertTrue(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.ExpressionValidityRole)) + self.assertTrue( + m.data( + m.indexFromName(None), QgsFieldModel.FieldRoles.ExpressionValidityRole + ) + ) def testFieldTypeRole(self): l, m = create_model() - self.assertEqual(m.data(m.indexFromName('fldtxt'), QgsFieldModel.FieldRoles.FieldTypeRole), QVariant.String) - self.assertEqual(m.data(m.indexFromName('fldint'), QgsFieldModel.FieldRoles.FieldTypeRole), QVariant.Int) - self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.FieldTypeRole)) - self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.FieldTypeRole)) + self.assertEqual( + m.data(m.indexFromName("fldtxt"), QgsFieldModel.FieldRoles.FieldTypeRole), + QVariant.String, + ) + self.assertEqual( + m.data(m.indexFromName("fldint"), QgsFieldModel.FieldRoles.FieldTypeRole), + QVariant.Int, + ) + self.assertFalse( + m.data( + m.indexFromName("an expression"), QgsFieldModel.FieldRoles.FieldTypeRole + ) + ) + self.assertFalse( + m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.FieldTypeRole) + ) m.setAllowExpression(True) - m.setExpression('an expression') - self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.FieldTypeRole)) + m.setExpression("an expression") + self.assertFalse( + m.data( + m.indexFromName("an expression"), QgsFieldModel.FieldRoles.FieldTypeRole + ) + ) m.setAllowEmptyFieldName(True) - self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.FieldTypeRole)) + self.assertFalse( + m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.FieldTypeRole) + ) def testFieldOriginRole(self): l, m = create_model() - self.assertEqual(m.data(m.indexFromName('fldtxt'), QgsFieldModel.FieldRoles.FieldOriginRole), QgsFields.FieldOrigin.OriginProvider) - self.assertEqual(m.data(m.indexFromName('fldint'), QgsFieldModel.FieldRoles.FieldOriginRole), QgsFields.FieldOrigin.OriginProvider) - self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.FieldOriginRole)) - self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.FieldOriginRole)) + self.assertEqual( + m.data(m.indexFromName("fldtxt"), QgsFieldModel.FieldRoles.FieldOriginRole), + QgsFields.FieldOrigin.OriginProvider, + ) + self.assertEqual( + m.data(m.indexFromName("fldint"), QgsFieldModel.FieldRoles.FieldOriginRole), + QgsFields.FieldOrigin.OriginProvider, + ) + self.assertFalse( + m.data( + m.indexFromName("an expression"), + QgsFieldModel.FieldRoles.FieldOriginRole, + ) + ) + self.assertFalse( + m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.FieldOriginRole) + ) m.setAllowExpression(True) - m.setExpression('an expression') - self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.FieldOriginRole)) + m.setExpression("an expression") + self.assertFalse( + m.data( + m.indexFromName("an expression"), + QgsFieldModel.FieldRoles.FieldOriginRole, + ) + ) m.setAllowEmptyFieldName(True) - self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.FieldOriginRole)) + self.assertFalse( + m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.FieldOriginRole) + ) def testIsEmptyRole(self): l, m = create_model() - self.assertFalse(m.data(m.indexFromName('fldtxt'), QgsFieldModel.FieldRoles.IsEmptyRole), QgsFields.FieldOrigin.OriginProvider) - self.assertFalse(m.data(m.indexFromName('fldint'), QgsFieldModel.FieldRoles.IsEmptyRole), QgsFields.FieldOrigin.OriginProvider) - self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.IsEmptyRole)) - self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.IsEmptyRole)) + self.assertFalse( + m.data(m.indexFromName("fldtxt"), QgsFieldModel.FieldRoles.IsEmptyRole), + QgsFields.FieldOrigin.OriginProvider, + ) + self.assertFalse( + m.data(m.indexFromName("fldint"), QgsFieldModel.FieldRoles.IsEmptyRole), + QgsFields.FieldOrigin.OriginProvider, + ) + self.assertFalse( + m.data( + m.indexFromName("an expression"), QgsFieldModel.FieldRoles.IsEmptyRole + ) + ) + self.assertFalse( + m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.IsEmptyRole) + ) m.setAllowExpression(True) - m.setExpression('an expression') - self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.IsEmptyRole)) + m.setExpression("an expression") + self.assertFalse( + m.data( + m.indexFromName("an expression"), QgsFieldModel.FieldRoles.IsEmptyRole + ) + ) m.setAllowEmptyFieldName(True) - self.assertTrue(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.IsEmptyRole)) + self.assertTrue( + m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.IsEmptyRole) + ) def testDisplayRole(self): l, m = create_model() - self.assertEqual(m.data(m.indexFromName('fldtxt'), Qt.ItemDataRole.DisplayRole), 'fldtxt') - self.assertEqual(m.data(m.indexFromName('fldint'), Qt.ItemDataRole.DisplayRole), 'fldint') - self.assertFalse(m.data(m.indexFromName('an expression'), Qt.ItemDataRole.DisplayRole)) + self.assertEqual( + m.data(m.indexFromName("fldtxt"), Qt.ItemDataRole.DisplayRole), "fldtxt" + ) + self.assertEqual( + m.data(m.indexFromName("fldint"), Qt.ItemDataRole.DisplayRole), "fldint" + ) + self.assertFalse( + m.data(m.indexFromName("an expression"), Qt.ItemDataRole.DisplayRole) + ) self.assertFalse(m.data(m.indexFromName(None), Qt.ItemDataRole.DisplayRole)) m.setAllowExpression(True) - m.setExpression('an expression') - self.assertEqual(m.data(m.indexFromName('an expression'), Qt.ItemDataRole.DisplayRole), 'an expression') + m.setExpression("an expression") + self.assertEqual( + m.data(m.indexFromName("an expression"), Qt.ItemDataRole.DisplayRole), + "an expression", + ) m.setAllowEmptyFieldName(True) self.assertFalse(m.data(m.indexFromName(None), Qt.ItemDataRole.DisplayRole)) def testManualFields(self): _, m = create_model() fields = QgsFields() - fields.append(QgsField('f1', QVariant.String)) - fields.append(QgsField('f2', QVariant.String)) + fields.append(QgsField("f1", QVariant.String)) + fields.append(QgsField("f2", QVariant.String)) m.setFields(fields) self.assertEqual(m.rowCount(), 2) - self.assertEqual(m.data(m.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'f1') - self.assertEqual(m.data(m.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'f2') + self.assertEqual( + m.data(m.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), "f1" + ) + self.assertEqual( + m.data(m.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), "f2" + ) def testEditorWidgetTypeRole(self): l, m = create_model() - self.assertEqual(m.data(m.indexFromName('fldtxt'), QgsFieldModel.FieldRoles.EditorWidgetType), 'Hidden') - self.assertEqual(m.data(m.indexFromName('fldint'), QgsFieldModel.FieldRoles.EditorWidgetType), 'ValueMap') - self.assertIsNone(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.EditorWidgetType)) - self.assertIsNone(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.EditorWidgetType)) + self.assertEqual( + m.data( + m.indexFromName("fldtxt"), QgsFieldModel.FieldRoles.EditorWidgetType + ), + "Hidden", + ) + self.assertEqual( + m.data( + m.indexFromName("fldint"), QgsFieldModel.FieldRoles.EditorWidgetType + ), + "ValueMap", + ) + self.assertIsNone( + m.data( + m.indexFromName("an expression"), + QgsFieldModel.FieldRoles.EditorWidgetType, + ) + ) + self.assertIsNone( + m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.EditorWidgetType) + ) m.setAllowExpression(True) - m.setExpression('an expression') - self.assertIsNone(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.EditorWidgetType)) + m.setExpression("an expression") + self.assertIsNone( + m.data( + m.indexFromName("an expression"), + QgsFieldModel.FieldRoles.EditorWidgetType, + ) + ) m.setAllowEmptyFieldName(True) - self.assertIsNone(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.EditorWidgetType)) + self.assertIsNone( + m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.EditorWidgetType) + ) def testJoinedFieldIsEditableRole(self): - layer = QgsVectorLayer("Point?field=id_a:integer", - "addfeat", "memory") - layer2 = QgsVectorLayer("Point?field=id_b:integer&field=value_b", - "addfeat", "memory") + layer = QgsVectorLayer("Point?field=id_a:integer", "addfeat", "memory") + layer2 = QgsVectorLayer( + "Point?field=id_b:integer&field=value_b", "addfeat", "memory" + ) QgsProject.instance().addMapLayers([layer, layer2]) # editable join @@ -300,26 +500,54 @@ def testJoinedFieldIsEditableRole(self): m = QgsFieldModel() m.setLayer(layer) - self.assertIsNone(m.data(m.indexFromName('id_a'), QgsFieldModel.FieldRoles.JoinedFieldIsEditable)) - self.assertTrue(m.data(m.indexFromName('B_value_b'), QgsFieldModel.FieldRoles.JoinedFieldIsEditable)) - self.assertIsNone(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.JoinedFieldIsEditable)) - self.assertIsNone(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.JoinedFieldIsEditable)) + self.assertIsNone( + m.data( + m.indexFromName("id_a"), QgsFieldModel.FieldRoles.JoinedFieldIsEditable + ) + ) + self.assertTrue( + m.data( + m.indexFromName("B_value_b"), + QgsFieldModel.FieldRoles.JoinedFieldIsEditable, + ) + ) + self.assertIsNone( + m.data( + m.indexFromName("an expression"), + QgsFieldModel.FieldRoles.JoinedFieldIsEditable, + ) + ) + self.assertIsNone( + m.data( + m.indexFromName(None), QgsFieldModel.FieldRoles.JoinedFieldIsEditable + ) + ) m.setAllowExpression(True) - m.setExpression('an expression') - self.assertIsNone(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.JoinedFieldIsEditable)) + m.setExpression("an expression") + self.assertIsNone( + m.data( + m.indexFromName("an expression"), + QgsFieldModel.FieldRoles.JoinedFieldIsEditable, + ) + ) m.setAllowEmptyFieldName(True) - self.assertIsNone(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.JoinedFieldIsEditable)) + self.assertIsNone( + m.data( + m.indexFromName(None), QgsFieldModel.FieldRoles.JoinedFieldIsEditable + ) + ) proxy_m = QgsFieldProxyModel() - proxy_m.setFilters(QgsFieldProxyModel.Filter.AllTypes | QgsFieldProxyModel.Filter.HideReadOnly) + proxy_m.setFilters( + QgsFieldProxyModel.Filter.AllTypes | QgsFieldProxyModel.Filter.HideReadOnly + ) proxy_m.sourceFieldModel().setLayer(layer) self.assertEqual(proxy_m.rowCount(), 2) - self.assertEqual(proxy_m.data(proxy_m.index(0, 0)), 'id_a') - self.assertEqual(proxy_m.data(proxy_m.index(1, 0)), 'B_value_b') + self.assertEqual(proxy_m.data(proxy_m.index(0, 0)), "id_a") + self.assertEqual(proxy_m.data(proxy_m.index(1, 0)), "B_value_b") # not editable join - layer3 = QgsVectorLayer("Point?field=id_a:integer", - "addfeat", "memory") + layer3 = QgsVectorLayer("Point?field=id_a:integer", "addfeat", "memory") QgsProject.instance().addMapLayers([layer3]) join_info = QgsVectorLayerJoinInfo() join_info.setTargetFieldName("id_a") @@ -332,75 +560,166 @@ def testJoinedFieldIsEditableRole(self): m = QgsFieldModel() m.setLayer(layer3) - self.assertIsNone(m.data(m.indexFromName('id_a'), QgsFieldModel.FieldRoles.JoinedFieldIsEditable)) - self.assertFalse(m.data(m.indexFromName('B_value_b'), QgsFieldModel.FieldRoles.JoinedFieldIsEditable)) - self.assertIsNone(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.JoinedFieldIsEditable)) - self.assertIsNone(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.JoinedFieldIsEditable)) + self.assertIsNone( + m.data( + m.indexFromName("id_a"), QgsFieldModel.FieldRoles.JoinedFieldIsEditable + ) + ) + self.assertFalse( + m.data( + m.indexFromName("B_value_b"), + QgsFieldModel.FieldRoles.JoinedFieldIsEditable, + ) + ) + self.assertIsNone( + m.data( + m.indexFromName("an expression"), + QgsFieldModel.FieldRoles.JoinedFieldIsEditable, + ) + ) + self.assertIsNone( + m.data( + m.indexFromName(None), QgsFieldModel.FieldRoles.JoinedFieldIsEditable + ) + ) m.setAllowExpression(True) - m.setExpression('an expression') - self.assertIsNone(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.JoinedFieldIsEditable)) + m.setExpression("an expression") + self.assertIsNone( + m.data( + m.indexFromName("an expression"), + QgsFieldModel.FieldRoles.JoinedFieldIsEditable, + ) + ) m.setAllowEmptyFieldName(True) - self.assertIsNone(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.JoinedFieldIsEditable)) + self.assertIsNone( + m.data( + m.indexFromName(None), QgsFieldModel.FieldRoles.JoinedFieldIsEditable + ) + ) proxy_m = QgsFieldProxyModel() proxy_m.sourceFieldModel().setLayer(layer3) - proxy_m.setFilters(QgsFieldProxyModel.Filter.AllTypes | QgsFieldProxyModel.Filter.HideReadOnly) + proxy_m.setFilters( + QgsFieldProxyModel.Filter.AllTypes | QgsFieldProxyModel.Filter.HideReadOnly + ) self.assertEqual(proxy_m.rowCount(), 1) - self.assertEqual(proxy_m.data(proxy_m.index(0, 0)), 'id_a') + self.assertEqual(proxy_m.data(proxy_m.index(0, 0)), "id_a") - proxy_m.setFilters(QgsFieldProxyModel.Filter.AllTypes | QgsFieldProxyModel.Filter.OriginProvider) + proxy_m.setFilters( + QgsFieldProxyModel.Filter.AllTypes + | QgsFieldProxyModel.Filter.OriginProvider + ) proxy_m.sourceFieldModel().setLayer(layer) self.assertEqual(proxy_m.rowCount(), 1) - self.assertEqual(proxy_m.data(proxy_m.index(0, 0)), 'id_a') + self.assertEqual(proxy_m.data(proxy_m.index(0, 0)), "id_a") proxy_m.sourceFieldModel().setLayer(layer3) self.assertEqual(proxy_m.rowCount(), 1) - self.assertEqual(proxy_m.data(proxy_m.index(0, 0)), 'id_a') + self.assertEqual(proxy_m.data(proxy_m.index(0, 0)), "id_a") def testFieldIsWidgetEditableRole(self): l, m = create_model() - self.assertTrue(m.data(m.indexFromName('fldtxt'), QgsFieldModel.FieldRoles.FieldIsWidgetEditable)) - self.assertTrue(m.data(m.indexFromName('fldint'), QgsFieldModel.FieldRoles.FieldIsWidgetEditable)) - self.assertFalse(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.FieldIsWidgetEditable)) - self.assertFalse(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.FieldIsWidgetEditable)) + self.assertTrue( + m.data( + m.indexFromName("fldtxt"), + QgsFieldModel.FieldRoles.FieldIsWidgetEditable, + ) + ) + self.assertTrue( + m.data( + m.indexFromName("fldint"), + QgsFieldModel.FieldRoles.FieldIsWidgetEditable, + ) + ) + self.assertFalse( + m.data( + m.indexFromName("an expression"), + QgsFieldModel.FieldRoles.FieldIsWidgetEditable, + ) + ) + self.assertFalse( + m.data( + m.indexFromName(None), QgsFieldModel.FieldRoles.FieldIsWidgetEditable + ) + ) m.setAllowExpression(True) - m.setExpression('an expression') - self.assertTrue(m.data(m.indexFromName('an expression'), QgsFieldModel.FieldRoles.FieldIsWidgetEditable)) + m.setExpression("an expression") + self.assertTrue( + m.data( + m.indexFromName("an expression"), + QgsFieldModel.FieldRoles.FieldIsWidgetEditable, + ) + ) m.setAllowEmptyFieldName(True) - self.assertTrue(m.data(m.indexFromName(None), QgsFieldModel.FieldRoles.FieldIsWidgetEditable)) + self.assertTrue( + m.data( + m.indexFromName(None), QgsFieldModel.FieldRoles.FieldIsWidgetEditable + ) + ) editFormConfig = l.editFormConfig() - idx = l.fields().indexOf('fldtxt') + idx = l.fields().indexOf("fldtxt") # Make fldtxt readOnly editFormConfig.setReadOnly(idx, True) l.setEditFormConfig(editFormConfig) # It's read only, so the widget is NOT editable - self.assertFalse(m.data(m.indexFromName('fldtxt'), QgsFieldModel.FieldRoles.FieldIsWidgetEditable)) + self.assertFalse( + m.data( + m.indexFromName("fldtxt"), + QgsFieldModel.FieldRoles.FieldIsWidgetEditable, + ) + ) def testFieldTooltip(self): - f = QgsField('my_string', QVariant.String, 'string') - self.assertEqual(QgsFieldModel.fieldToolTip(f), "my_string
    string NULL") - f.setAlias('my alias') - self.assertEqual(QgsFieldModel.fieldToolTip(f), "my alias (my_string)
    string NULL") + f = QgsField("my_string", QVariant.String, "string") + self.assertEqual( + QgsFieldModel.fieldToolTip(f), + "my_string
    string NULL", + ) + f.setAlias("my alias") + self.assertEqual( + QgsFieldModel.fieldToolTip(f), + "my alias (my_string)
    string NULL", + ) f.setLength(20) - self.assertEqual(QgsFieldModel.fieldToolTip(f), "my alias (my_string)
    string(20) NULL") - f = QgsField('my_real', QVariant.Double, 'real', 8, 3) - self.assertEqual(QgsFieldModel.fieldToolTip(f), "my_real
    real(8, 3) NULL") - f.setComment('Comment text') - self.assertEqual(QgsFieldModel.fieldToolTip(f), "my_real
    real(8, 3) NULL
    Comment text") + self.assertEqual( + QgsFieldModel.fieldToolTip(f), + "my alias (my_string)
    string(20) NULL", + ) + f = QgsField("my_real", QVariant.Double, "real", 8, 3) + self.assertEqual( + QgsFieldModel.fieldToolTip(f), + "my_real
    real(8, 3) NULL", + ) + f.setComment("Comment text") + self.assertEqual( + QgsFieldModel.fieldToolTip(f), + "my_real
    real(8, 3) NULL
    Comment text", + ) def testFieldTooltipExtended(self): layer = QgsVectorLayer("Point?", "tooltip", "memory") - f = QgsField('my_real', QVariant.Double, 'real', 8, 3, 'Comment text') - layer.addExpressionField('1+1', f) + f = QgsField("my_real", QVariant.Double, "real", 8, 3, "Comment text") + layer.addExpressionField("1+1", f) layer.updateFields() - self.assertEqual(QgsFieldModel.fieldToolTipExtended(QgsField('my_string', QVariant.String, 'string'), layer), '') - self.assertEqual(QgsFieldModel.fieldToolTipExtended(f, layer), "my_real
    real(8, 3) NULL
    Comment text
    1+1") - f.setAlias('my alias') + self.assertEqual( + QgsFieldModel.fieldToolTipExtended( + QgsField("my_string", QVariant.String, "string"), layer + ), + "", + ) + self.assertEqual( + QgsFieldModel.fieldToolTipExtended(f, layer), + "my_real
    real(8, 3) NULL
    Comment text
    1+1", + ) + f.setAlias("my alias") constraints = f.constraints() constraints.setConstraint(QgsFieldConstraints.Constraint.ConstraintUnique) f.setConstraints(constraints) - self.assertEqual(QgsFieldModel.fieldToolTipExtended(f, layer), "my alias (my_real)
    real(8, 3) NULL UNIQUE
    Comment text
    1+1") + self.assertEqual( + QgsFieldModel.fieldToolTipExtended(f, layer), + "my alias (my_real)
    real(8, 3) NULL UNIQUE
    Comment text
    1+1", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfields.py b/tests/src/python/test_qgsfields.py index 0d9368a07e51..166429c880f3 100644 --- a/tests/src/python/test_qgsfields.py +++ b/tests/src/python/test_qgsfields.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '16/08/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "16/08/2015" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.PyQt.QtCore import QDate, QVariant from qgis.core import NULL, QgsVectorLayer @@ -20,8 +21,11 @@ class TestQgsFields(QgisTestCase): def test_exceptions(self): - ml = QgsVectorLayer("Point?crs=epsg:4236&field=id:integer&field=value:double", - "test_data", "memory") + ml = QgsVectorLayer( + "Point?crs=epsg:4236&field=id:integer&field=value:double", + "test_data", + "memory", + ) assert ml.isValid() fields = ml.fields() @@ -43,11 +47,11 @@ def test_exceptions(self): fields[111] # check no error - self.assertEqual("value", fields['value'].name()) - self.assertEqual("id", fields['ID'].name()) + self.assertEqual("value", fields["value"].name()) + self.assertEqual("id", fields["ID"].name()) # check exceptions raised with self.assertRaises(KeyError): - fields['arg'] + fields["arg"] # check no error fields.at(1) @@ -66,10 +70,10 @@ def test_exceptions(self): fields.field(111) # check no error - fields.field('value') + fields.field("value") # check exceptions raised with self.assertRaises(KeyError): - fields.field('bad') + fields.field("bad") # check no error fields.fieldOrigin(1) @@ -102,22 +106,23 @@ def test_names(self): + "&field=value:double" + "&field=crazy:double", "test_data", - "memory") + "memory", + ) assert ml.isValid() fields = ml.fields() - expected_fields = ['id', 'value', 'crazy'] + expected_fields = ["id", "value", "crazy"] self.assertEqual(fields.names(), expected_fields) fields.remove(1) - expected_fields = ['id', 'crazy'] + expected_fields = ["id", "crazy"] self.assertEqual(fields.names(), expected_fields) def test_convert_compatible(self): """Test convertCompatible""" - vl = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer', 'test', 'memory') + vl = QgsVectorLayer("Point?crs=epsg:4326&field=int:integer", "test", "memory") # Valid values self.assertTrue(vl.fields()[0].convertCompatible(123.0)) @@ -127,48 +132,63 @@ def test_convert_compatible(self): self.assertEqual(vl.fields()[0].convertCompatible(NULL), NULL) # Not valid with self.assertRaises(ValueError) as cm: - vl.fields()[0].convertCompatible('QGIS Rocks!') - self.assertEqual(str(cm.exception), 'Value could not be converted to field type int: Value "QGIS Rocks!" is not a number') + vl.fields()[0].convertCompatible("QGIS Rocks!") + self.assertEqual( + str(cm.exception), + 'Value could not be converted to field type int: Value "QGIS Rocks!" is not a number', + ) with self.assertRaises(ValueError) as cm: self.assertFalse(vl.fields()[0].convertCompatible(QDate(2020, 6, 30))) - self.assertEqual(str(cm.exception), - 'Value could not be converted to field type int: Could not convert value "2020-06-30" to target type "integer"') + self.assertEqual( + str(cm.exception), + 'Value could not be converted to field type int: Could not convert value "2020-06-30" to target type "integer"', + ) # Not valid: overflow with self.assertRaises(ValueError) as cm: self.assertFalse(vl.fields()[0].convertCompatible(2147483647 + 1)) - self.assertEqual(str(cm.exception), - 'Value could not be converted to field type int: Value "2147483648" is too large for integer field') + self.assertEqual( + str(cm.exception), + 'Value could not be converted to field type int: Value "2147483648" is too large for integer field', + ) # Valid: narrow cast with loss of precision (!) self.assertTrue(vl.fields()[0].convertCompatible(123.123)) - vl = QgsVectorLayer('Point?crs=epsg:4326&field=date:date', 'test', 'memory') + vl = QgsVectorLayer("Point?crs=epsg:4326&field=date:date", "test", "memory") self.assertTrue(vl.fields()[0].convertCompatible(QDate(2020, 6, 30))) # Not valid with self.assertRaises(ValueError) as cm: - self.assertFalse(vl.fields()[0].convertCompatible('QGIS Rocks!')) - self.assertEqual(str(cm.exception), - 'Value could not be converted to field type QDate: Could not convert value "QGIS Rocks!" to target type "date"') + self.assertFalse(vl.fields()[0].convertCompatible("QGIS Rocks!")) + self.assertEqual( + str(cm.exception), + 'Value could not be converted to field type QDate: Could not convert value "QGIS Rocks!" to target type "date"', + ) with self.assertRaises(ValueError) as cm: self.assertFalse(vl.fields()[0].convertCompatible(123)) - self.assertEqual(str(cm.exception), - 'Value could not be converted to field type QDate: Could not convert value "123" to target type "date"') + self.assertEqual( + str(cm.exception), + 'Value could not be converted to field type QDate: Could not convert value "123" to target type "date"', + ) # Strings can store almost anything - vl = QgsVectorLayer('Point?crs=epsg:4326&field=text:string(30)', 'test', 'memory') + vl = QgsVectorLayer( + "Point?crs=epsg:4326&field=text:string(30)", "test", "memory" + ) self.assertTrue(vl.fields()[0].convertCompatible(QDate(2020, 6, 30))) - self.assertTrue(vl.fields()[0].convertCompatible('QGIS Rocks!')) + self.assertTrue(vl.fields()[0].convertCompatible("QGIS Rocks!")) self.assertTrue(vl.fields()[0].convertCompatible(123)) self.assertTrue(vl.fields()[0].convertCompatible(123.456)) # string overflow self.assertEqual(vl.fields()[0].length(), 30) with self.assertRaises(ValueError) as cm: - self.assertTrue(vl.fields()[0].convertCompatible('x' * 31)) - self.assertEqual(str(cm.exception), - 'Value could not be converted to field type QString: String of length 31 exceeds maximum field length (30)') + self.assertTrue(vl.fields()[0].convertCompatible("x" * 31)) + self.assertEqual( + str(cm.exception), + "Value could not be converted to field type QString: String of length 31 exceeds maximum field length (30)", + ) - vl = QgsVectorLayer('Point?crs=epsg:4326&field=double:double', 'test', 'memory') + vl = QgsVectorLayer("Point?crs=epsg:4326&field=double:double", "test", "memory") # Valid values self.assertTrue(vl.fields()[0].convertCompatible(123.0)) @@ -179,14 +199,18 @@ def test_convert_compatible(self): self.assertTrue(vl.fields()[0].convertCompatible(QVariant.Double)) # Not valid with self.assertRaises(ValueError) as cm: - self.assertFalse(vl.fields()[0].convertCompatible('QGIS Rocks!')) - self.assertEqual(str(cm.exception), - 'Value could not be converted to field type double: Could not convert value "QGIS Rocks!" to target type "double"') + self.assertFalse(vl.fields()[0].convertCompatible("QGIS Rocks!")) + self.assertEqual( + str(cm.exception), + 'Value could not be converted to field type double: Could not convert value "QGIS Rocks!" to target type "double"', + ) with self.assertRaises(ValueError) as cm: self.assertFalse(vl.fields()[0].convertCompatible(QDate(2020, 6, 30))) - self.assertEqual(str(cm.exception), - 'Value could not be converted to field type double: Could not convert value "2020-06-30" to target type "double"') + self.assertEqual( + str(cm.exception), + 'Value could not be converted to field type double: Could not convert value "2020-06-30" to target type "double"', + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfieldvalidator.py b/tests/src/python/test_qgsfieldvalidator.py index ee3fbd3bb702..aa6d416355a1 100644 --- a/tests/src/python/test_qgsfieldvalidator.py +++ b/tests/src/python/test_qgsfieldvalidator.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '31/01/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "31/01/2018" +__copyright__ = "Copyright 2018, The QGIS Project" import os import shutil @@ -33,12 +34,14 @@ class TestQgsFieldValidator(QgisTestCase): def setUpClass(cls): """Run before all tests.""" super().setUpClass() - testPath = TEST_DATA_DIR + '/' + 'bug_17878.gpkg' + testPath = TEST_DATA_DIR + "/" + "bug_17878.gpkg" # Copy it tempdir = tempfile.mkdtemp() - testPathCopy = os.path.join(tempdir, 'bug_17878.gpkg') + testPathCopy = os.path.join(tempdir, "bug_17878.gpkg") shutil.copy(testPath, testPathCopy) - cls.vl = QgsVectorLayer(testPathCopy + '|layername=bug_17878', "test_data", "ogr") + cls.vl = QgsVectorLayer( + testPathCopy + "|layername=bug_17878", "test_data", "ogr" + ) assert cls.vl.isValid() @classmethod @@ -55,27 +58,29 @@ def _fld_checker(self, field): QValidator::Acceptable 2 The string is acceptable as a final result; i.e. it is valid. """ DECIMAL_SEPARATOR = QLocale().decimalPoint() - OTHER_SEPARATOR = ',' if DECIMAL_SEPARATOR == '.' else '.' + OTHER_SEPARATOR = "," if DECIMAL_SEPARATOR == "." else "." - validator = QgsFieldValidator(None, field, '0.0', '') + validator = QgsFieldValidator(None, field, "0.0", "") def _test(value, expected): ret = validator.validate(value, 0) self.assertEqual(ret[0], expected) if value: - self.assertEqual(validator.validate('-' + value, 0)[0], expected, '-' + value) + self.assertEqual( + validator.validate("-" + value, 0)[0], expected, "-" + value + ) # NOTE!!! This should ALWAYS be valid, but the behavior changed in Qt > 5.12. # accordingly here we can only run the test if in a locale with decimal separator as dot. # The previous tests were moved to test_disabled_tests.py for now, until the QgsFieldValidator # class can be reworked to fix this regression. - if DECIMAL_SEPARATOR != ',': - _test('0.1234', QValidator.State.Acceptable) + if DECIMAL_SEPARATOR != ",": + _test("0.1234", QValidator.State.Acceptable) # Apparently we accept comma only when locale say so - if DECIMAL_SEPARATOR != '.': - _test('0,1234', QValidator.State.Acceptable) + if DECIMAL_SEPARATOR != ".": + _test("0,1234", QValidator.State.Acceptable) # If precision is > 0, regexp validator is used (and it does not support sci notation) if field.precision() == 0: @@ -83,46 +88,48 @@ def _test(value, expected): # accordingly here we can only run the test if in a locale with decimal separator as dot. # The previous tests were moved to test_disabled_tests.py for now, until the QgsFieldValidator # class can be reworked to fix this regression. - if DECIMAL_SEPARATOR != ',': - _test('12345.1234e+123', QValidator.State.Acceptable) - _test('12345.1234e-123', QValidator.State.Acceptable) + if DECIMAL_SEPARATOR != ",": + _test("12345.1234e+123", QValidator.State.Acceptable) + _test("12345.1234e-123", QValidator.State.Acceptable) - if DECIMAL_SEPARATOR != '.': - _test('12345,1234e+123', QValidator.State.Acceptable) - _test('12345,1234e-123', QValidator.State.Acceptable) - _test('', QValidator.State.Acceptable) + if DECIMAL_SEPARATOR != ".": + _test("12345,1234e+123", QValidator.State.Acceptable) + _test("12345,1234e-123", QValidator.State.Acceptable) + _test("", QValidator.State.Acceptable) # Out of range - _test('12345.1234e+823', QValidator.State.Intermediate) - _test('12345.1234e-823', QValidator.State.Intermediate) - if DECIMAL_SEPARATOR != '.': - _test('12345,1234e+823', QValidator.State.Intermediate) - _test('12345,1234e-823', QValidator.State.Intermediate) + _test("12345.1234e+823", QValidator.State.Intermediate) + _test("12345.1234e-823", QValidator.State.Intermediate) + if DECIMAL_SEPARATOR != ".": + _test("12345,1234e+823", QValidator.State.Intermediate) + _test("12345,1234e-823", QValidator.State.Intermediate) # Invalid - _test('12345-1234', QValidator.State.Invalid) - _test('onetwothree', QValidator.State.Invalid) + _test("12345-1234", QValidator.State.Invalid) + _test("onetwothree", QValidator.State.Invalid) - int_field = self.vl.fields()[self.vl.fields().indexFromName('int_field')] - self.assertEqual(int_field.precision(), 0) # this is what the provider reports :( + int_field = self.vl.fields()[self.vl.fields().indexFromName("int_field")] + self.assertEqual( + int_field.precision(), 0 + ) # this is what the provider reports :( self.assertEqual(int_field.length(), 0) # not set self.assertEqual(int_field.type(), QVariant.Int) - validator = QgsFieldValidator(None, int_field, '0', '') + validator = QgsFieldValidator(None, int_field, "0", "") # Valid - _test('0', QValidator.State.Acceptable) - _test('1234', QValidator.State.Acceptable) - _test('', QValidator.State.Acceptable) + _test("0", QValidator.State.Acceptable) + _test("1234", QValidator.State.Acceptable) + _test("", QValidator.State.Acceptable) # Invalid - _test('12345-1234', QValidator.State.Invalid) - _test(f'12345{DECIMAL_SEPARATOR}1234', QValidator.State.Invalid) - _test('onetwothree', QValidator.State.Invalid) + _test("12345-1234", QValidator.State.Invalid) + _test(f"12345{DECIMAL_SEPARATOR}1234", QValidator.State.Invalid) + _test("onetwothree", QValidator.State.Invalid) def test_doubleValidator(self): """Test the double with default (system) locale""" - field = self.vl.fields()[self.vl.fields().indexFromName('double_field')] + field = self.vl.fields()[self.vl.fields().indexFromName("double_field")] self.assertEqual(field.precision(), 0) # this is what the provider reports :( self.assertEqual(field.length(), 0) # not set self.assertEqual(field.type(), QVariant.Double) @@ -131,25 +138,25 @@ def test_doubleValidator(self): def test_doubleValidatorCommaLocale(self): """Test the double with german locale""" QLocale.setDefault(QLocale(QLocale.Language.German, QLocale.Country.Germany)) - self.assertEqual(QLocale().decimalPoint(), ',') - field = self.vl.fields()[self.vl.fields().indexFromName('double_field')] + self.assertEqual(QLocale().decimalPoint(), ",") + field = self.vl.fields()[self.vl.fields().indexFromName("double_field")] self._fld_checker(field) def test_doubleValidatorDotLocale(self): """Test the double with english locale""" QLocale.setDefault(QLocale(QLocale.Language.English)) - self.assertEqual(QLocale().decimalPoint(), '.') - field = self.vl.fields()[self.vl.fields().indexFromName('double_field')] + self.assertEqual(QLocale().decimalPoint(), ".") + field = self.vl.fields()[self.vl.fields().indexFromName("double_field")] self._fld_checker(field) def test_precision(self): """Test different precision""" QLocale.setDefault(QLocale(QLocale.Language.English)) - self.assertEqual(QLocale().decimalPoint(), '.') - field = self.vl.fields()[self.vl.fields().indexFromName('double_field')] + self.assertEqual(QLocale().decimalPoint(), ".") + field = self.vl.fields()[self.vl.fields().indexFromName("double_field")] field.setPrecision(4) self._fld_checker(field) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfiledownloader.py b/tests/src/python/test_qgsfiledownloader.py index 4cb81f9bd022..36d720768c26 100644 --- a/tests/src/python/test_qgsfiledownloader.py +++ b/tests/src/python/test_qgsfiledownloader.py @@ -19,9 +19,9 @@ import unittest from qgis.testing import start_app, QgisTestCase -__author__ = 'Alessandro Pasotti' -__date__ = '08/11/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "08/11/2016" +__copyright__ = "Copyright 2016, The QGIS Project" start_app() @@ -41,11 +41,11 @@ def _make_download(self, url, destination, cancel=False): loop = QEventLoop() downloader = QgsFileDownloader(QUrl(url), destination) - downloader.downloadCompleted.connect(partial(self._set_slot, 'completed')) - downloader.downloadExited.connect(partial(self._set_slot, 'exited')) - downloader.downloadCanceled.connect(partial(self._set_slot, 'canceled')) - downloader.downloadError.connect(partial(self._set_slot, 'error')) - downloader.downloadProgress.connect(partial(self._set_slot, 'progress')) + downloader.downloadCompleted.connect(partial(self._set_slot, "completed")) + downloader.downloadExited.connect(partial(self._set_slot, "exited")) + downloader.downloadCanceled.connect(partial(self._set_slot, "canceled")) + downloader.downloadError.connect(partial(self._set_slot, "error")) + downloader.downloadProgress.connect(partial(self._set_slot, "progress")) downloader.downloadExited.connect(loop.quit) @@ -54,12 +54,14 @@ def _make_download(self, url, destination, cancel=False): loop.exec() - @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'), - 'Test with http://www.qgis.org unstable. Needs local server.') + @unittest.skipIf( + os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), + "Test with http://www.qgis.org unstable. Needs local server.", + ) def test_validDownload(self): """Tests a valid download""" destination = tempfile.mktemp() - self._make_download('http://www.qgis.org', destination) + self._make_download("http://www.qgis.org", destination) self.assertTrue(self.exited_was_called) self.assertTrue(self.completed_was_called) self.assertTrue(self.progress_was_called) @@ -71,21 +73,28 @@ def test_validDownload(self): def test_inValidDownload(self): """Tests an invalid download""" destination = tempfile.mktemp() - self._make_download('http://www.doesnotexistofthatimsure.qgis', destination) + self._make_download("http://www.doesnotexistofthatimsure.qgis", destination) self.assertTrue(self.exited_was_called) self.assertFalse(self.completed_was_called) self.assertTrue(self.progress_was_called) self.assertFalse(self.canceled_was_called) self.assertTrue(self.error_was_called) - self.assertEqual(self.error_args[1], ['Download failed: Host www.doesnotexistofthatimsure.qgis not found']) + self.assertEqual( + self.error_args[1], + ["Download failed: Host www.doesnotexistofthatimsure.qgis not found"], + ) self.assertFalse(os.path.isfile(destination)) - @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'), - 'Test with http://www.github.com unstable. Needs local server.') + @unittest.skipIf( + os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), + "Test with http://www.github.com unstable. Needs local server.", + ) def test_dowloadCanceled(self): """Tests user canceled download""" destination = tempfile.mktemp() - self._make_download('https://github.com/qgis/QGIS/archive/master.zip', destination, True) + self._make_download( + "https://github.com/qgis/QGIS/archive/master.zip", destination, True + ) self.assertTrue(self.exited_was_called) self.assertFalse(self.completed_was_called) self.assertTrue(self.canceled_was_called) @@ -94,18 +103,22 @@ def test_dowloadCanceled(self): def test_InvalidUrl(self): destination = tempfile.mktemp() - self._make_download('xyz://www', destination) + self._make_download("xyz://www", destination) self.assertTrue(self.exited_was_called) self.assertFalse(self.completed_was_called) self.assertFalse(self.canceled_was_called) self.assertTrue(self.error_was_called) self.assertFalse(os.path.isfile(destination)) - self.assertEqual(self.error_args[1], ["Download failed: Protocol \"xyz\" is unknown"]) - - @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'), - 'Test with http://www.github.com unstable. Needs local server.') + self.assertEqual( + self.error_args[1], ['Download failed: Protocol "xyz" is unknown'] + ) + + @unittest.skipIf( + os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), + "Test with http://www.github.com unstable. Needs local server.", + ) def test_InvalidFile(self): - self._make_download('https://github.com/qgis/QGIS/archive/master.zip', "") + self._make_download("https://github.com/qgis/QGIS/archive/master.zip", "") self.assertTrue(self.exited_was_called) self.assertFalse(self.completed_was_called) self.assertFalse(self.canceled_was_called) @@ -114,13 +127,15 @@ def test_InvalidFile(self): def test_BlankUrl(self): destination = tempfile.mktemp() - self._make_download('', destination) + self._make_download("", destination) self.assertTrue(self.exited_was_called) self.assertFalse(self.completed_was_called) self.assertFalse(self.canceled_was_called) self.assertTrue(self.error_was_called) self.assertFalse(os.path.isfile(destination)) - self.assertEqual(self.error_args[1], ["Download failed: Protocol \"\" is unknown"]) + self.assertEqual( + self.error_args[1], ['Download failed: Protocol "" is unknown'] + ) def ssl_compare(self, name, url, error): destination = tempfile.mktemp() @@ -132,22 +147,37 @@ def ssl_compare(self, name, url, error): self.assertTrue(self.error_was_called, msg) self.assertFalse(os.path.isfile(destination), msg) result = sorted(self.error_args[1]) - result = ';'.join(result) - self.assertTrue(result.startswith(error), msg + f"expected:\n{result}\nactual:\n{error}\n") - - @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'), 'Test with badssl.com unstable. Needs local server.') + result = ";".join(result) + self.assertTrue( + result.startswith(error), msg + f"expected:\n{result}\nactual:\n{error}\n" + ) + + @unittest.skipIf( + os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), + "Test with badssl.com unstable. Needs local server.", + ) def test_sslExpired(self): - self.ssl_compare("expired", "https://expired.badssl.com/", "SSL Errors: ;The certificate has expired") - self.ssl_compare("self-signed", "https://self-signed.badssl.com/", - "SSL Errors: ;The certificate is self-signed, and untrusted") - self.ssl_compare("untrusted-root", "https://untrusted-root.badssl.com/", - "No certificates could be verified;SSL Errors: ;The issuer certificate of a locally looked up certificate could not be found") + self.ssl_compare( + "expired", + "https://expired.badssl.com/", + "SSL Errors: ;The certificate has expired", + ) + self.ssl_compare( + "self-signed", + "https://self-signed.badssl.com/", + "SSL Errors: ;The certificate is self-signed, and untrusted", + ) + self.ssl_compare( + "untrusted-root", + "https://untrusted-root.badssl.com/", + "No certificates could be verified;SSL Errors: ;The issuer certificate of a locally looked up certificate could not be found", + ) def _set_slot(self, *args, **kwargs): # print('_set_slot(%s) called' % args[0]) - setattr(self, args[0] + '_was_called', True) - setattr(self, args[0] + '_args', args) + setattr(self, args[0] + "_was_called", True) + setattr(self, args[0] + "_args", args) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfileutils.py b/tests/src/python/test_qgsfileutils.py index 9d9c7c1bad08..3d37dc508947 100644 --- a/tests/src/python/test_qgsfileutils.py +++ b/tests/src/python/test_qgsfileutils.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '18/12/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "18/12/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os import shutil @@ -23,133 +24,303 @@ class TestQgsFileUtils(unittest.TestCase): def testExtensionsFromFilter(self): - self.assertEqual(QgsFileUtils.extensionsFromFilter(''), []) - self.assertEqual(QgsFileUtils.extensionsFromFilter('bad'), []) - self.assertEqual(QgsFileUtils.extensionsFromFilter('*'), []) - self.assertEqual(QgsFileUtils.extensionsFromFilter('*.'), []) - self.assertEqual(QgsFileUtils.extensionsFromFilter('Tiff files'), []) - self.assertEqual(QgsFileUtils.extensionsFromFilter('(*.)'), []) - self.assertEqual(QgsFileUtils.extensionsFromFilter('PNG Files (*.png)'), ['png']) - self.assertEqual(QgsFileUtils.extensionsFromFilter('PNG Files (*.PNG)'), ['PNG']) - self.assertEqual(QgsFileUtils.extensionsFromFilter('Geotiff Files (*.tiff *.tif)'), ['tiff', 'tif']) - self.assertEqual(QgsFileUtils.extensionsFromFilter('TAR.GZ Files (*.tar.gz *.tgz)'), ['tar.gz', 'tgz']) + self.assertEqual(QgsFileUtils.extensionsFromFilter(""), []) + self.assertEqual(QgsFileUtils.extensionsFromFilter("bad"), []) + self.assertEqual(QgsFileUtils.extensionsFromFilter("*"), []) + self.assertEqual(QgsFileUtils.extensionsFromFilter("*."), []) + self.assertEqual(QgsFileUtils.extensionsFromFilter("Tiff files"), []) + self.assertEqual(QgsFileUtils.extensionsFromFilter("(*.)"), []) + self.assertEqual( + QgsFileUtils.extensionsFromFilter("PNG Files (*.png)"), ["png"] + ) + self.assertEqual( + QgsFileUtils.extensionsFromFilter("PNG Files (*.PNG)"), ["PNG"] + ) + self.assertEqual( + QgsFileUtils.extensionsFromFilter("Geotiff Files (*.tiff *.tif)"), + ["tiff", "tif"], + ) + self.assertEqual( + QgsFileUtils.extensionsFromFilter("TAR.GZ Files (*.tar.gz *.tgz)"), + ["tar.gz", "tgz"], + ) def testWildcardsFromFilter(self): - self.assertEqual(QgsFileUtils.wildcardsFromFilter(''), '') - self.assertEqual(QgsFileUtils.wildcardsFromFilter('bad'), '') - self.assertEqual(QgsFileUtils.wildcardsFromFilter('*'), '') - self.assertEqual(QgsFileUtils.wildcardsFromFilter('*.'), '') - self.assertEqual(QgsFileUtils.wildcardsFromFilter('Tiff files'), '') - self.assertEqual(QgsFileUtils.wildcardsFromFilter('(*.*)'), '*.*') - self.assertEqual(QgsFileUtils.wildcardsFromFilter('PNG Files (*.png)'), '*.png') - self.assertEqual(QgsFileUtils.wildcardsFromFilter('Tif Files (*.tif)'), '*.tif') - self.assertEqual(QgsFileUtils.wildcardsFromFilter('PNG Files (*.PNG)'), '*.PNG') - self.assertEqual(QgsFileUtils.wildcardsFromFilter('Geotiff Files (*.tiff *.tif)'), '*.tiff *.tif') - self.assertEqual(QgsFileUtils.wildcardsFromFilter('Geotiff Files (*.tiff *.tif *.TIFF)'), '*.tiff *.tif *.TIFF') - self.assertEqual(QgsFileUtils.wildcardsFromFilter('EPT files (ept.json)'), 'ept.json') - self.assertEqual(QgsFileUtils.wildcardsFromFilter('EPT files (ept.json EPT.JSON)'), 'ept.json EPT.JSON') + self.assertEqual(QgsFileUtils.wildcardsFromFilter(""), "") + self.assertEqual(QgsFileUtils.wildcardsFromFilter("bad"), "") + self.assertEqual(QgsFileUtils.wildcardsFromFilter("*"), "") + self.assertEqual(QgsFileUtils.wildcardsFromFilter("*."), "") + self.assertEqual(QgsFileUtils.wildcardsFromFilter("Tiff files"), "") + self.assertEqual(QgsFileUtils.wildcardsFromFilter("(*.*)"), "*.*") + self.assertEqual(QgsFileUtils.wildcardsFromFilter("PNG Files (*.png)"), "*.png") + self.assertEqual( + QgsFileUtils.wildcardsFromFilter("Tif Files (*.tif)"), "*.tif" + ) + self.assertEqual(QgsFileUtils.wildcardsFromFilter("PNG Files (*.PNG)"), "*.PNG") + self.assertEqual( + QgsFileUtils.wildcardsFromFilter("Geotiff Files (*.tiff *.tif)"), + "*.tiff *.tif", + ) + self.assertEqual( + QgsFileUtils.wildcardsFromFilter("Geotiff Files (*.tiff *.tif *.TIFF)"), + "*.tiff *.tif *.TIFF", + ) + self.assertEqual( + QgsFileUtils.wildcardsFromFilter("EPT files (ept.json)"), "ept.json" + ) + self.assertEqual( + QgsFileUtils.wildcardsFromFilter("EPT files (ept.json EPT.JSON)"), + "ept.json EPT.JSON", + ) def testFileMatchesFilter(self): - self.assertFalse(QgsFileUtils.fileMatchesFilter('/home/me/test.tif', '')) - self.assertFalse(QgsFileUtils.fileMatchesFilter('/home/me/test.tif', 'bad')) - self.assertFalse(QgsFileUtils.fileMatchesFilter('/home/me/test.tif', '*')) - self.assertFalse(QgsFileUtils.fileMatchesFilter('/home/me/test.tif', '*.')) - self.assertFalse(QgsFileUtils.fileMatchesFilter('/home/me/test.tif', 'Tiff files')) - self.assertTrue(QgsFileUtils.fileMatchesFilter('/home/me/test.tif', '(*.*)')) - self.assertFalse(QgsFileUtils.fileMatchesFilter('/home/me/test.tif', 'PNG Files (*.png)')) - self.assertTrue(QgsFileUtils.fileMatchesFilter('/home/me/test.tif', 'Tif Files (*.tif)')) - self.assertFalse(QgsFileUtils.fileMatchesFilter('/home/me/test.tif', 'PNG Files (*.PNG)')) - self.assertFalse(QgsFileUtils.fileMatchesFilter('/home/me/test.tif', 'Tif Files (*.TIF)')) - self.assertTrue(QgsFileUtils.fileMatchesFilter('/home/me/test.tif', 'Geotiff Files (*.tiff *.tif)')) - self.assertTrue(QgsFileUtils.fileMatchesFilter('/home/me/test.tiff', 'Geotiff Files (*.tiff *.tif)')) - self.assertTrue(QgsFileUtils.fileMatchesFilter('/home/me/test.TIFF', 'Geotiff Files (*.tiff *.tif *.TIFF)')) - self.assertFalse(QgsFileUtils.fileMatchesFilter('/home/me/test.tif', 'PNG Files (*.png);;BMP Files (*.bmp)')) - self.assertTrue(QgsFileUtils.fileMatchesFilter('/home/me/test.bmp', 'PNG Files (*.png);;BMP Files (*.bmp)')) - self.assertTrue(QgsFileUtils.fileMatchesFilter('/home/me/test.png', 'PNG Files (*.png);;BMP Files (*.bmp)')) - self.assertFalse(QgsFileUtils.fileMatchesFilter('/home/me/test.png', 'EPT files (ept.json)')) - self.assertTrue(QgsFileUtils.fileMatchesFilter('/home/me/ept.json', 'EPT files (ept.json)')) - self.assertTrue(QgsFileUtils.fileMatchesFilter('/home/me/ept.json', 'EPT files (ept.json EPT.JSON)')) - self.assertTrue(QgsFileUtils.fileMatchesFilter('/home/me/EPT.JSON', 'EPT files (ept.json EPT.JSON)')) - self.assertTrue(QgsFileUtils.fileMatchesFilter('/home/me/ept.json', 'EPT files (ept.json);;Entwine files (entwine.json)')) + self.assertFalse(QgsFileUtils.fileMatchesFilter("/home/me/test.tif", "")) + self.assertFalse(QgsFileUtils.fileMatchesFilter("/home/me/test.tif", "bad")) + self.assertFalse(QgsFileUtils.fileMatchesFilter("/home/me/test.tif", "*")) + self.assertFalse(QgsFileUtils.fileMatchesFilter("/home/me/test.tif", "*.")) + self.assertFalse( + QgsFileUtils.fileMatchesFilter("/home/me/test.tif", "Tiff files") + ) + self.assertTrue(QgsFileUtils.fileMatchesFilter("/home/me/test.tif", "(*.*)")) + self.assertFalse( + QgsFileUtils.fileMatchesFilter("/home/me/test.tif", "PNG Files (*.png)") + ) self.assertTrue( - QgsFileUtils.fileMatchesFilter('/home/me/entwine.json', 'EPT files (ept.json);;Entwine files (entwine.json)')) + QgsFileUtils.fileMatchesFilter("/home/me/test.tif", "Tif Files (*.tif)") + ) + self.assertFalse( + QgsFileUtils.fileMatchesFilter("/home/me/test.tif", "PNG Files (*.PNG)") + ) self.assertFalse( - QgsFileUtils.fileMatchesFilter('/home/me/ep.json', 'EPT files (ept.json);;Entwine files (entwine.json)')) + QgsFileUtils.fileMatchesFilter("/home/me/test.tif", "Tif Files (*.TIF)") + ) + self.assertTrue( + QgsFileUtils.fileMatchesFilter( + "/home/me/test.tif", "Geotiff Files (*.tiff *.tif)" + ) + ) + self.assertTrue( + QgsFileUtils.fileMatchesFilter( + "/home/me/test.tiff", "Geotiff Files (*.tiff *.tif)" + ) + ) + self.assertTrue( + QgsFileUtils.fileMatchesFilter( + "/home/me/test.TIFF", "Geotiff Files (*.tiff *.tif *.TIFF)" + ) + ) + self.assertFalse( + QgsFileUtils.fileMatchesFilter( + "/home/me/test.tif", "PNG Files (*.png);;BMP Files (*.bmp)" + ) + ) + self.assertTrue( + QgsFileUtils.fileMatchesFilter( + "/home/me/test.bmp", "PNG Files (*.png);;BMP Files (*.bmp)" + ) + ) + self.assertTrue( + QgsFileUtils.fileMatchesFilter( + "/home/me/test.png", "PNG Files (*.png);;BMP Files (*.bmp)" + ) + ) + self.assertFalse( + QgsFileUtils.fileMatchesFilter("/home/me/test.png", "EPT files (ept.json)") + ) + self.assertTrue( + QgsFileUtils.fileMatchesFilter("/home/me/ept.json", "EPT files (ept.json)") + ) + self.assertTrue( + QgsFileUtils.fileMatchesFilter( + "/home/me/ept.json", "EPT files (ept.json EPT.JSON)" + ) + ) + self.assertTrue( + QgsFileUtils.fileMatchesFilter( + "/home/me/EPT.JSON", "EPT files (ept.json EPT.JSON)" + ) + ) + self.assertTrue( + QgsFileUtils.fileMatchesFilter( + "/home/me/ept.json", + "EPT files (ept.json);;Entwine files (entwine.json)", + ) + ) + self.assertTrue( + QgsFileUtils.fileMatchesFilter( + "/home/me/entwine.json", + "EPT files (ept.json);;Entwine files (entwine.json)", + ) + ) + self.assertFalse( + QgsFileUtils.fileMatchesFilter( + "/home/me/ep.json", "EPT files (ept.json);;Entwine files (entwine.json)" + ) + ) def testEnsureFileNameHasExtension(self): - self.assertEqual(QgsFileUtils.ensureFileNameHasExtension('', ['']), '') - self.assertEqual(QgsFileUtils.ensureFileNameHasExtension('', []), '') - self.assertEqual(QgsFileUtils.ensureFileNameHasExtension('test', []), 'test') - self.assertEqual(QgsFileUtils.ensureFileNameHasExtension('', ['.tif']), '') - self.assertEqual(QgsFileUtils.ensureFileNameHasExtension('test', ['.tif']), 'test.tif') - self.assertEqual(QgsFileUtils.ensureFileNameHasExtension('test', ['tif']), 'test.tif') - self.assertEqual(QgsFileUtils.ensureFileNameHasExtension('test.tif', []), 'test.tif') - self.assertEqual(QgsFileUtils.ensureFileNameHasExtension('test.tif', ['bmp']), 'test.tif.bmp') - self.assertEqual(QgsFileUtils.ensureFileNameHasExtension('test.tif', ['tiff']), 'test.tif.tiff') - self.assertEqual(QgsFileUtils.ensureFileNameHasExtension('test.tif', ['tiff', 'tif']), 'test.tif') - self.assertEqual(QgsFileUtils.ensureFileNameHasExtension('test.tif', ['TIFF', 'TIF']), 'test.tif') + self.assertEqual(QgsFileUtils.ensureFileNameHasExtension("", [""]), "") + self.assertEqual(QgsFileUtils.ensureFileNameHasExtension("", []), "") + self.assertEqual(QgsFileUtils.ensureFileNameHasExtension("test", []), "test") + self.assertEqual(QgsFileUtils.ensureFileNameHasExtension("", [".tif"]), "") + self.assertEqual( + QgsFileUtils.ensureFileNameHasExtension("test", [".tif"]), "test.tif" + ) + self.assertEqual( + QgsFileUtils.ensureFileNameHasExtension("test", ["tif"]), "test.tif" + ) + self.assertEqual( + QgsFileUtils.ensureFileNameHasExtension("test.tif", []), "test.tif" + ) + self.assertEqual( + QgsFileUtils.ensureFileNameHasExtension("test.tif", ["bmp"]), "test.tif.bmp" + ) + self.assertEqual( + QgsFileUtils.ensureFileNameHasExtension("test.tif", ["tiff"]), + "test.tif.tiff", + ) + self.assertEqual( + QgsFileUtils.ensureFileNameHasExtension("test.tif", ["tiff", "tif"]), + "test.tif", + ) + self.assertEqual( + QgsFileUtils.ensureFileNameHasExtension("test.tif", ["TIFF", "TIF"]), + "test.tif", + ) def testAddExtensionFromFilter(self): - self.assertEqual(QgsFileUtils.addExtensionFromFilter('test', 'TIFF Files (*.tif)'), 'test.tif') - self.assertEqual(QgsFileUtils.addExtensionFromFilter('test', 'TIFF Files (*.tif)'), 'test.tif') - self.assertEqual(QgsFileUtils.addExtensionFromFilter('test.tif', ''), 'test.tif') - self.assertEqual(QgsFileUtils.addExtensionFromFilter('test.tif', 'BMP Files (*.bmp)'), 'test.tif.bmp') - self.assertEqual(QgsFileUtils.addExtensionFromFilter('test.tif', 'TIFF Files (*.tiff)'), 'test.tif.tiff') - self.assertEqual(QgsFileUtils.addExtensionFromFilter('test.tif', 'TIFF Files (*.tif *.tiff)'), 'test.tif') - self.assertEqual(QgsFileUtils.addExtensionFromFilter('test.tif', 'TIFF Files (*.TIF *.TIFF)'), 'test.tif') - self.assertEqual(QgsFileUtils.addExtensionFromFilter('test.tif', 'All Files (*.*)'), 'test.tif') - self.assertEqual(QgsFileUtils.addExtensionFromFilter('test', 'All Files (*.*)'), 'test') + self.assertEqual( + QgsFileUtils.addExtensionFromFilter("test", "TIFF Files (*.tif)"), + "test.tif", + ) + self.assertEqual( + QgsFileUtils.addExtensionFromFilter("test", "TIFF Files (*.tif)"), + "test.tif", + ) + self.assertEqual( + QgsFileUtils.addExtensionFromFilter("test.tif", ""), "test.tif" + ) + self.assertEqual( + QgsFileUtils.addExtensionFromFilter("test.tif", "BMP Files (*.bmp)"), + "test.tif.bmp", + ) + self.assertEqual( + QgsFileUtils.addExtensionFromFilter("test.tif", "TIFF Files (*.tiff)"), + "test.tif.tiff", + ) + self.assertEqual( + QgsFileUtils.addExtensionFromFilter( + "test.tif", "TIFF Files (*.tif *.tiff)" + ), + "test.tif", + ) + self.assertEqual( + QgsFileUtils.addExtensionFromFilter( + "test.tif", "TIFF Files (*.TIF *.TIFF)" + ), + "test.tif", + ) + self.assertEqual( + QgsFileUtils.addExtensionFromFilter("test.tif", "All Files (*.*)"), + "test.tif", + ) + self.assertEqual( + QgsFileUtils.addExtensionFromFilter("test", "All Files (*.*)"), "test" + ) def testStringToSafeFilename(self): - self.assertEqual(QgsFileUtils.stringToSafeFilename('my FiLe v2.0_new.tif'), 'my FiLe v2.0_new.tif') self.assertEqual( - QgsFileUtils.stringToSafeFilename('rendered map_final? rev (12-03-1017)_real/\\?%*:|"<>.tif'), - 'rendered map_final_ rev (12-03-1017)_real__________.tif') + QgsFileUtils.stringToSafeFilename("my FiLe v2.0_new.tif"), + "my FiLe v2.0_new.tif", + ) + self.assertEqual( + QgsFileUtils.stringToSafeFilename( + 'rendered map_final? rev (12-03-1017)_real/\\?%*:|"<>.tif' + ), + "rendered map_final_ rev (12-03-1017)_real__________.tif", + ) def testFindClosestExistingPath(self): - self.assertEqual(QgsFileUtils.findClosestExistingPath(''), '') - self.assertEqual(QgsFileUtils.findClosestExistingPath('.'), '') - self.assertEqual(QgsFileUtils.findClosestExistingPath('just_a_filename'), '') - self.assertEqual(QgsFileUtils.findClosestExistingPath('just_a_filename.txt'), '') - self.assertEqual(QgsFileUtils.findClosestExistingPath( - 'a_very_unlikely_path_to_really_exist/because/no_one_would_have_a_folder_called/MapInfo is the bestest/'), - '') + self.assertEqual(QgsFileUtils.findClosestExistingPath(""), "") + self.assertEqual(QgsFileUtils.findClosestExistingPath("."), "") + self.assertEqual(QgsFileUtils.findClosestExistingPath("just_a_filename"), "") + self.assertEqual( + QgsFileUtils.findClosestExistingPath("just_a_filename.txt"), "" + ) + self.assertEqual( + QgsFileUtils.findClosestExistingPath( + "a_very_unlikely_path_to_really_exist/because/no_one_would_have_a_folder_called/MapInfo is the bestest/" + ), + "", + ) # sorry anyone not on linux! - self.assertEqual(QgsFileUtils.findClosestExistingPath('/usr/youve_been_hacked/by_the_l77t_krew'), '/usr') + self.assertEqual( + QgsFileUtils.findClosestExistingPath( + "/usr/youve_been_hacked/by_the_l77t_krew" + ), + "/usr", + ) base_path = tempfile.mkdtemp() - file = os.path.join(base_path, 'test.csv') - with open(file, 'w') as f: - f.write('\n') + file = os.path.join(base_path, "test.csv") + with open(file, "w") as f: + f.write("\n") - self.assertEqual(QgsFileUtils.findClosestExistingPath(os.path.join(base_path, 'a file name.bmp')), - base_path) # non-existent file - self.assertEqual(QgsFileUtils.findClosestExistingPath(file), base_path) # real file! - self.assertEqual(QgsFileUtils.findClosestExistingPath(os.path.join(base_path, 'non/existent/subfolder')), - base_path) + self.assertEqual( + QgsFileUtils.findClosestExistingPath( + os.path.join(base_path, "a file name.bmp") + ), + base_path, + ) # non-existent file + self.assertEqual( + QgsFileUtils.findClosestExistingPath(file), base_path + ) # real file! + self.assertEqual( + QgsFileUtils.findClosestExistingPath( + os.path.join(base_path, "non/existent/subfolder") + ), + base_path, + ) - sub_folder1 = os.path.join(base_path, 'subfolder1') + sub_folder1 = os.path.join(base_path, "subfolder1") os.mkdir(sub_folder1) - sub_folder2 = os.path.join(sub_folder1, 'subfolder2') + sub_folder2 = os.path.join(sub_folder1, "subfolder2") os.mkdir(sub_folder2) - bad_sub_folder = os.path.join(sub_folder2, 'nooo') - self.assertEqual(QgsFileUtils.findClosestExistingPath(bad_sub_folder), sub_folder2) + bad_sub_folder = os.path.join(sub_folder2, "nooo") + self.assertEqual( + QgsFileUtils.findClosestExistingPath(bad_sub_folder), sub_folder2 + ) self.assertEqual(QgsFileUtils.findClosestExistingPath(sub_folder2), sub_folder2) - self.assertEqual(QgsFileUtils.findClosestExistingPath(sub_folder2 + '/.'), sub_folder2) - self.assertEqual(QgsFileUtils.findClosestExistingPath(sub_folder2 + '/..'), sub_folder1) - self.assertEqual(QgsFileUtils.findClosestExistingPath(sub_folder2 + '/../ddddddd'), sub_folder1) - self.assertEqual(QgsFileUtils.findClosestExistingPath(sub_folder2 + '/../subfolder2'), sub_folder2) - self.assertEqual(QgsFileUtils.findClosestExistingPath(sub_folder2 + '/../subfolder2/zxcv/asfdasd'), sub_folder2) + self.assertEqual( + QgsFileUtils.findClosestExistingPath(sub_folder2 + "/."), sub_folder2 + ) + self.assertEqual( + QgsFileUtils.findClosestExistingPath(sub_folder2 + "/.."), sub_folder1 + ) + self.assertEqual( + QgsFileUtils.findClosestExistingPath(sub_folder2 + "/../ddddddd"), + sub_folder1, + ) + self.assertEqual( + QgsFileUtils.findClosestExistingPath(sub_folder2 + "/../subfolder2"), + sub_folder2, + ) + self.assertEqual( + QgsFileUtils.findClosestExistingPath( + sub_folder2 + "/../subfolder2/zxcv/asfdasd" + ), + sub_folder2, + ) def testAutoFinder(self): temp_folder = tempfile.mkdtemp() - base_folder = os.path.join(temp_folder, 'base_level') + base_folder = os.path.join(temp_folder, "base_level") os.mkdir(base_folder) - side_fold = os.path.join(temp_folder, 'sidefold') + side_fold = os.path.join(temp_folder, "sidefold") os.mkdir(side_fold) - nest = os.path.join(base_folder, 'direct_nest') + nest = os.path.join(base_folder, "direct_nest") os.mkdir(nest) - side_nest = os.path.join(side_fold, 'side_nest') + side_nest = os.path.join(side_fold, "side_nest") os.mkdir(side_nest) filename = "findme.txt" @@ -163,174 +334,250 @@ def testAutoFinder(self): files = QgsFileUtils.findFile(filename, nest, 1, 13) self.assertEqual(len(files), 0) # side nest - with open(os.path.join(side_nest, filename), 'w+'): + with open(os.path.join(side_nest, filename), "w+"): files = QgsFileUtils.findFile(os.path.join(base_folder, filename)) - self.assertEqual(files[0], os.path.join(side_nest, filename).replace(os.sep, '/')) + self.assertEqual( + files[0], os.path.join(side_nest, filename).replace(os.sep, "/") + ) # side + side nest = 2 - with open(os.path.join(side_fold, filename), 'w+'): + with open(os.path.join(side_fold, filename), "w+"): files = QgsFileUtils.findFile(filename, base_folder, 3, 4) self.assertEqual(len(files), 2) # up - with open(os.path.join(temp_folder, filename), 'w+'): + with open(os.path.join(temp_folder, filename), "w+"): files = QgsFileUtils.findFile(filename, base_folder, 3, 4) - self.assertEqual(files[0], os.path.join(temp_folder, filename).replace(os.sep, '/')) + self.assertEqual( + files[0], os.path.join(temp_folder, filename).replace(os.sep, "/") + ) # nest - with open(os.path.join(nest, filename), 'w+'): + with open(os.path.join(nest, filename), "w+"): files = QgsFileUtils.findFile(os.path.join(base_folder, filename)) - self.assertEqual(files[0], os.path.join(nest, filename).replace(os.sep, '/')) + self.assertEqual( + files[0], os.path.join(nest, filename).replace(os.sep, "/") + ) # base level - with open(os.path.join(base_folder, filename), 'w+'): + with open(os.path.join(base_folder, filename), "w+"): files = QgsFileUtils.findFile(filename, base_folder, 2, 4) - self.assertEqual(files[0], os.path.join(base_folder, filename).replace(os.sep, '/')) + self.assertEqual( + files[0], os.path.join(base_folder, filename).replace(os.sep, "/") + ) # invalid path, too deep - files = QgsFileUtils.findFile(filename, os.path.join(nest, 'nest2'), 2, 4) - self.assertEqual(files[0], os.path.join(nest, filename).replace(os.sep, '/')) + files = QgsFileUtils.findFile(filename, os.path.join(nest, "nest2"), 2, 4) + self.assertEqual(files[0], os.path.join(nest, filename).replace(os.sep, "/")) def test_represent_file_size(self): """ Test QgsFileUtils.representFileSize """ - self.assertEqual(QgsFileUtils.representFileSize(1023), '1023 B') - self.assertEqual(QgsFileUtils.representFileSize(1024), '1 KB') - self.assertEqual(QgsFileUtils.representFileSize(1048576), '1.00 MB') - self.assertEqual(QgsFileUtils.representFileSize(9876543210), '9.20 GB') + self.assertEqual(QgsFileUtils.representFileSize(1023), "1023 B") + self.assertEqual(QgsFileUtils.representFileSize(1024), "1 KB") + self.assertEqual(QgsFileUtils.representFileSize(1048576), "1.00 MB") + self.assertEqual(QgsFileUtils.representFileSize(9876543210), "9.20 GB") def test_sidecar_files_for_path(self): """ Test QgsFileUtils.sidecarFilesForPath """ # file which doesn't exist - self.assertFalse(QgsFileUtils.sidecarFilesForPath('/not a valid path')) + self.assertFalse(QgsFileUtils.sidecarFilesForPath("/not a valid path")) # a directory self.assertFalse(QgsFileUtils.sidecarFilesForPath(unitTestDataPath())) # not a spatial data file - self.assertFalse(QgsFileUtils.sidecarFilesForPath(f'{unitTestDataPath()}/kbs.qgs')) + self.assertFalse( + QgsFileUtils.sidecarFilesForPath(f"{unitTestDataPath()}/kbs.qgs") + ) # shapefile - self.assertEqual(QgsFileUtils.sidecarFilesForPath(f'{unitTestDataPath()}/lines.shp'), - {f'{unitTestDataPath()}/lines.shx', f'{unitTestDataPath()}/lines.dbf', - f'{unitTestDataPath()}/lines.prj'}) + self.assertEqual( + QgsFileUtils.sidecarFilesForPath(f"{unitTestDataPath()}/lines.shp"), + { + f"{unitTestDataPath()}/lines.shx", + f"{unitTestDataPath()}/lines.dbf", + f"{unitTestDataPath()}/lines.prj", + }, + ) # gpkg - self.assertFalse(QgsFileUtils.sidecarFilesForPath(f'{unitTestDataPath()}/points_gpkg.gpkg')) + self.assertFalse( + QgsFileUtils.sidecarFilesForPath(f"{unitTestDataPath()}/points_gpkg.gpkg") + ) # MapInfo TAB file - self.assertEqual(QgsFileUtils.sidecarFilesForPath(f'{unitTestDataPath()}/ogr_types.tab'), - {f'{unitTestDataPath()}/ogr_types.dat', f'{unitTestDataPath()}/ogr_types.id', - f'{unitTestDataPath()}/ogr_types.map'}) + self.assertEqual( + QgsFileUtils.sidecarFilesForPath(f"{unitTestDataPath()}/ogr_types.tab"), + { + f"{unitTestDataPath()}/ogr_types.dat", + f"{unitTestDataPath()}/ogr_types.id", + f"{unitTestDataPath()}/ogr_types.map", + }, + ) # GML - self.assertEqual(QgsFileUtils.sidecarFilesForPath(f'{unitTestDataPath()}/invalidgeometries.gml'), - {f'{unitTestDataPath()}/invalidgeometries.gfs'}) + self.assertEqual( + QgsFileUtils.sidecarFilesForPath( + f"{unitTestDataPath()}/invalidgeometries.gml" + ), + {f"{unitTestDataPath()}/invalidgeometries.gfs"}, + ) # netcdf - self.assertEqual(QgsFileUtils.sidecarFilesForPath(f'{unitTestDataPath()}/landsat2.nc'), - {f'{unitTestDataPath()}/landsat2.nc.aux.xml'}) + self.assertEqual( + QgsFileUtils.sidecarFilesForPath(f"{unitTestDataPath()}/landsat2.nc"), + {f"{unitTestDataPath()}/landsat2.nc.aux.xml"}, + ) # tif - self.assertEqual(QgsFileUtils.sidecarFilesForPath(f'{unitTestDataPath()}/ALLINGES_RGF93_CC46_1_1.tif'), - {f'{unitTestDataPath()}/ALLINGES_RGF93_CC46_1_1.tfw'}) + self.assertEqual( + QgsFileUtils.sidecarFilesForPath( + f"{unitTestDataPath()}/ALLINGES_RGF93_CC46_1_1.tif" + ), + {f"{unitTestDataPath()}/ALLINGES_RGF93_CC46_1_1.tfw"}, + ) def test_rename_dataset(self): """ Test QgsFileUtils.renameDataset """ base_path = tempfile.mkdtemp() - for ext in ['shp', 'dbf', 'prj', 'qml', 'shx']: - shutil.copy(f'{unitTestDataPath()}/lines.{ext}', f'{base_path}/lines.{ext}') - shutil.copy(f'{unitTestDataPath()}/lines.{ext}', f'{base_path}/lines.{ext}') - self.assertTrue(os.path.exists(f'{base_path}/lines.shp')) - - res, error = QgsFileUtils.renameDataset(f'{base_path}/lines.shp', f'{base_path}/other_lines.shp') + for ext in ["shp", "dbf", "prj", "qml", "shx"]: + shutil.copy(f"{unitTestDataPath()}/lines.{ext}", f"{base_path}/lines.{ext}") + shutil.copy(f"{unitTestDataPath()}/lines.{ext}", f"{base_path}/lines.{ext}") + self.assertTrue(os.path.exists(f"{base_path}/lines.shp")) + + res, error = QgsFileUtils.renameDataset( + f"{base_path}/lines.shp", f"{base_path}/other_lines.shp" + ) self.assertTrue(res) - for ext in ['shp', 'dbf', 'prj', 'qml', 'shx']: - self.assertTrue(os.path.exists(f'{base_path}/other_lines.{ext}')) - self.assertFalse(os.path.exists(f'{base_path}/lines.{ext}')) + for ext in ["shp", "dbf", "prj", "qml", "shx"]: + self.assertTrue(os.path.exists(f"{base_path}/other_lines.{ext}")) + self.assertFalse(os.path.exists(f"{base_path}/lines.{ext}")) # skip qml file - res, error = QgsFileUtils.renameDataset(f'{base_path}/other_lines.shp', f'{base_path}/other_lines2.shp', Qgis.FileOperationFlags()) + res, error = QgsFileUtils.renameDataset( + f"{base_path}/other_lines.shp", + f"{base_path}/other_lines2.shp", + Qgis.FileOperationFlags(), + ) self.assertTrue(res) - for ext in ['shp', 'dbf', 'prj', 'shx']: - self.assertTrue(os.path.exists(f'{base_path}/other_lines2.{ext}')) - self.assertFalse(os.path.exists(f'{base_path}/other_lines.{ext}')) - self.assertFalse(os.path.exists(f'{base_path}/other_lines2.qml')) - self.assertTrue(os.path.exists(f'{base_path}/other_lines.qml')) + for ext in ["shp", "dbf", "prj", "shx"]: + self.assertTrue(os.path.exists(f"{base_path}/other_lines2.{ext}")) + self.assertFalse(os.path.exists(f"{base_path}/other_lines.{ext}")) + self.assertFalse(os.path.exists(f"{base_path}/other_lines2.qml")) + self.assertTrue(os.path.exists(f"{base_path}/other_lines.qml")) # try changing extension -- sidecars won't be renamed - res, error = QgsFileUtils.renameDataset(f'{base_path}/other_lines2.shp', f'{base_path}/other_lines2.txt', - Qgis.FileOperationFlags()) + res, error = QgsFileUtils.renameDataset( + f"{base_path}/other_lines2.shp", + f"{base_path}/other_lines2.txt", + Qgis.FileOperationFlags(), + ) self.assertFalse(error) self.assertTrue(res) - self.assertFalse(os.path.exists(f'{base_path}/other_lines2.shp')) - self.assertTrue(os.path.exists(f'{base_path}/other_lines2.txt')) - for ext in ['dbf', 'prj', 'shx']: - self.assertTrue(os.path.exists(f'{base_path}/other_lines2.{ext}')) + self.assertFalse(os.path.exists(f"{base_path}/other_lines2.shp")) + self.assertTrue(os.path.exists(f"{base_path}/other_lines2.txt")) + for ext in ["dbf", "prj", "shx"]: + self.assertTrue(os.path.exists(f"{base_path}/other_lines2.{ext}")) - for ext in ['shp', 'dbf', 'prj', 'qml', 'shx']: - shutil.copy(f'{unitTestDataPath()}/lines.{ext}', f'{base_path}/ll.{ext}') - shutil.copy(f'{unitTestDataPath()}/lines.{ext}', f'{base_path}/ll.{ext}') + for ext in ["shp", "dbf", "prj", "qml", "shx"]: + shutil.copy(f"{unitTestDataPath()}/lines.{ext}", f"{base_path}/ll.{ext}") + shutil.copy(f"{unitTestDataPath()}/lines.{ext}", f"{base_path}/ll.{ext}") # file name clash - with open(f'{base_path}/yy.shp', 'w') as f: - f.write('') - res, error = QgsFileUtils.renameDataset(f'{base_path}/ll.shp', f'{base_path}/yy.shp', - Qgis.FileOperationFlags()) + with open(f"{base_path}/yy.shp", "w") as f: + f.write("") + res, error = QgsFileUtils.renameDataset( + f"{base_path}/ll.shp", f"{base_path}/yy.shp", Qgis.FileOperationFlags() + ) self.assertFalse(res) self.assertTrue(error) # nothing should be renamed - for ext in ['shp', 'dbf', 'prj', 'qml', 'shx']: - self.assertTrue(os.path.exists(f'{base_path}/ll.{ext}')) + for ext in ["shp", "dbf", "prj", "qml", "shx"]: + self.assertTrue(os.path.exists(f"{base_path}/ll.{ext}")) # sidecar clash - with open(f'{base_path}/yyy.shx', 'w') as f: - f.write('') - res, error = QgsFileUtils.renameDataset(f'{base_path}/ll.shp', f'{base_path}/yyy.shp') + with open(f"{base_path}/yyy.shx", "w") as f: + f.write("") + res, error = QgsFileUtils.renameDataset( + f"{base_path}/ll.shp", f"{base_path}/yyy.shp" + ) self.assertFalse(res) self.assertTrue(error) # no files should have been renamed - for ext in ['shp', 'dbf', 'prj', 'qml']: - self.assertTrue(os.path.exists(f'{base_path}/ll.{ext}')) - self.assertFalse(os.path.exists(f'{base_path}/yyy.{ext}')) - self.assertTrue(os.path.exists(f'{base_path}/ll.shx')) + for ext in ["shp", "dbf", "prj", "qml"]: + self.assertTrue(os.path.exists(f"{base_path}/ll.{ext}")) + self.assertFalse(os.path.exists(f"{base_path}/yyy.{ext}")) + self.assertTrue(os.path.exists(f"{base_path}/ll.shx")) # try renaming missing file - res, error = QgsFileUtils.renameDataset('/not a file.txt', f'{base_path}/not a file.txt', - Qgis.FileOperationFlags()) + res, error = QgsFileUtils.renameDataset( + "/not a file.txt", f"{base_path}/not a file.txt", Qgis.FileOperationFlags() + ) self.assertFalse(res) self.assertTrue(error) def testSplitPathToComponents(self): - self.assertEqual(QgsFileUtils.splitPathToComponents('/home/user/Pictures/test.png'), ["/", "home", "user", "Pictures", "test.png"]) - self.assertEqual(QgsFileUtils.splitPathToComponents('/home/user/Pictures/'), ["/", "home", "user", "Pictures"]) - self.assertEqual(QgsFileUtils.splitPathToComponents('/home/user/Pictures'), ["/", "home", "user", "Pictures"]) - self.assertEqual(QgsFileUtils.splitPathToComponents('/home/user'), ["/", "home", "user"]) - self.assertEqual(QgsFileUtils.splitPathToComponents('/home'), ["/", "home"]) - self.assertEqual(QgsFileUtils.splitPathToComponents('/'), ["/"]) - self.assertEqual(QgsFileUtils.splitPathToComponents(''), []) - self.assertEqual(QgsFileUtils.splitPathToComponents('c:/home/user'), ["c:", "home", "user"]) + self.assertEqual( + QgsFileUtils.splitPathToComponents("/home/user/Pictures/test.png"), + ["/", "home", "user", "Pictures", "test.png"], + ) + self.assertEqual( + QgsFileUtils.splitPathToComponents("/home/user/Pictures/"), + ["/", "home", "user", "Pictures"], + ) + self.assertEqual( + QgsFileUtils.splitPathToComponents("/home/user/Pictures"), + ["/", "home", "user", "Pictures"], + ) + self.assertEqual( + QgsFileUtils.splitPathToComponents("/home/user"), ["/", "home", "user"] + ) + self.assertEqual(QgsFileUtils.splitPathToComponents("/home"), ["/", "home"]) + self.assertEqual(QgsFileUtils.splitPathToComponents("/"), ["/"]) + self.assertEqual(QgsFileUtils.splitPathToComponents(""), []) + self.assertEqual( + QgsFileUtils.splitPathToComponents("c:/home/user"), ["c:", "home", "user"] + ) def testUniquePath(self): temp_dir = QTemporaryDir() temp_path = temp_dir.path() - with open(os.path.join(temp_path, 'test.txt'), 'w+') as f: + with open(os.path.join(temp_path, "test.txt"), "w+") as f: f.close() - self.assertEqual(QgsFileUtils.uniquePath(os.path.join(temp_path, 'my_test.txt')), os.path.join(temp_path, 'my_test.txt')) + self.assertEqual( + QgsFileUtils.uniquePath(os.path.join(temp_path, "my_test.txt")), + os.path.join(temp_path, "my_test.txt"), + ) - self.assertEqual(QgsFileUtils.uniquePath(os.path.join(temp_path, 'test.txt')), os.path.join(temp_path, 'test_2.txt')) + self.assertEqual( + QgsFileUtils.uniquePath(os.path.join(temp_path, "test.txt")), + os.path.join(temp_path, "test_2.txt"), + ) - with open(os.path.join(temp_path, 'test_2.txt'), 'w+') as f: + with open(os.path.join(temp_path, "test_2.txt"), "w+") as f: f.close() - self.assertEqual(QgsFileUtils.uniquePath(os.path.join(temp_path, 'test_2.txt')), os.path.join(temp_path, 'test_2_2.txt')) - self.assertEqual(QgsFileUtils.uniquePath(os.path.join(temp_path, 'test.txt')), os.path.join(temp_path, 'test_3.txt')) - self.assertEqual(QgsFileUtils.uniquePath(os.path.join(temp_path, 'test_1.txt')), os.path.join(temp_path, 'test_1.txt')) + self.assertEqual( + QgsFileUtils.uniquePath(os.path.join(temp_path, "test_2.txt")), + os.path.join(temp_path, "test_2_2.txt"), + ) + self.assertEqual( + QgsFileUtils.uniquePath(os.path.join(temp_path, "test.txt")), + os.path.join(temp_path, "test_3.txt"), + ) + self.assertEqual( + QgsFileUtils.uniquePath(os.path.join(temp_path, "test_1.txt")), + os.path.join(temp_path, "test_1.txt"), + ) - with open(os.path.join(temp_path, 'test'), 'w+') as f: + with open(os.path.join(temp_path, "test"), "w+") as f: f.close() - self.assertEqual(QgsFileUtils.uniquePath(os.path.join(temp_path, 'test')), os.path.join(temp_path, 'test_2')) + self.assertEqual( + QgsFileUtils.uniquePath(os.path.join(temp_path, "test")), + os.path.join(temp_path, "test_2"), + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfilledlinesymbollayer.py b/tests/src/python/test_qgsfilledlinesymbollayer.py index c9c226180509..fd7abf1c9db8 100644 --- a/tests/src/python/test_qgsfilledlinesymbollayer.py +++ b/tests/src/python/test_qgsfilledlinesymbollayer.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'November 2023' -__copyright__ = '(C) 2023, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "November 2023" +__copyright__ = "(C) 2023, Nyall Dawson" from typing import Optional @@ -57,9 +57,9 @@ def testRender(self): s.appendSymbolLayer(line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) - self.assertTrue(self.image_check('render', 'render', rendered_image)) + self.assertTrue(self.image_check("render", "render", rendered_image)) def testRenderFlatCap(self): s = QgsLineSymbol() @@ -72,9 +72,11 @@ def testRenderFlatCap(self): s.appendSymbolLayer(line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) - self.assertTrue(self.image_check('renderflatcap', 'renderflatcap', rendered_image)) + self.assertTrue( + self.image_check("renderflatcap", "renderflatcap", rendered_image) + ) def testRenderMiterJoin(self): s = QgsLineSymbol() @@ -87,9 +89,11 @@ def testRenderMiterJoin(self): s.appendSymbolLayer(line.clone()) - g = QgsGeometry.fromWkt('LineString(0 15, 0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 15, 0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) - self.assertTrue(self.image_check('render_miter', 'render_miter', rendered_image)) + self.assertTrue( + self.image_check("render_miter", "render_miter", rendered_image) + ) def testRenderBevelJoin(self): s = QgsLineSymbol() @@ -102,9 +106,11 @@ def testRenderBevelJoin(self): s.appendSymbolLayer(line.clone()) - g = QgsGeometry.fromWkt('LineString(2 2, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(2 2, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) - self.assertTrue(self.image_check('render_bevel', 'render_bevel', rendered_image)) + self.assertTrue( + self.image_check("render_bevel", "render_bevel", rendered_image) + ) def testLineOffset(self): s = QgsLineSymbol() @@ -117,9 +123,11 @@ def testLineOffset(self): s.appendSymbolLayer(line.clone()) - g = QgsGeometry.fromWkt('LineString(2 2, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(2 2, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) - self.assertTrue(self.image_check('render_offset', 'render_offset', rendered_image)) + self.assertTrue( + self.image_check("render_offset", "render_offset", rendered_image) + ) def renderGeometry(self, symbol, geom, buffer=20): f = QgsFeature() @@ -155,5 +163,5 @@ def renderGeometry(self, symbol, geom, buffer=20): return image -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfillsymbollayers.py b/tests/src/python/test_qgsfillsymbollayers.py index c87a52f8002a..6d0797225689 100644 --- a/tests/src/python/test_qgsfillsymbollayers.py +++ b/tests/src/python/test_qgsfillsymbollayers.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2017-01' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2017-01" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtGui import QColor, QImage, QPainter @@ -29,7 +30,7 @@ def control_path_prefix(cls): return "symbol_layer" def testSimpleLineWithOffset(self): - """ test that rendering a polygon with simple line symbol with offset results in closed line""" + """test that rendering a polygon with simple line symbol with offset results in closed line""" layer = QgsSimpleLineSymbolLayer() layer.setOffset(-1) layer.setColor(QColor(0, 0, 0)) @@ -41,7 +42,7 @@ def testSimpleLineWithOffset(self): painter = QPainter() ms = QgsMapSettings() - geom = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 0 10, 0 0))') + geom = QgsGeometry.fromWkt("Polygon((0 0, 10 0, 10 10, 0 10, 0 0))") f = QgsFeature() f.setGeometry(geom) @@ -65,14 +66,14 @@ def testSimpleLineWithOffset(self): self.assertTrue( self.image_check( - 'symbol_layer', - 'fill_simpleline_offset', + "symbol_layer", + "fill_simpleline_offset", image, color_tolerance=2, - allowed_mismatch=0 + allowed_mismatch=0, ) ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfilterlineedit.py b/tests/src/python/test_qgsfilterlineedit.py index dfa9d4a37a95..1ee0642d348f 100644 --- a/tests/src/python/test_qgsfilterlineedit.py +++ b/tests/src/python/test_qgsfilterlineedit.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '20/08/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "20/08/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.gui import QgsFilterLineEdit @@ -23,16 +24,16 @@ class TestQgsFilterLineEdit(QgisTestCase): def testGettersSetters(self): - """ test widget getters/setters """ + """test widget getters/setters""" w = QgsFilterLineEdit() - w.setNullValue('null') - self.assertEqual(w.nullValue(), 'null') - w.setValue('value') - self.assertEqual(w.value(), 'value') - self.assertEqual(w.text(), 'value') - w.setDefaultValue('default') - self.assertEqual(w.defaultValue(), 'default') + w.setNullValue("null") + self.assertEqual(w.nullValue(), "null") + w.setValue("value") + self.assertEqual(w.value(), "value") + self.assertEqual(w.text(), "value") + w.setDefaultValue("default") + self.assertEqual(w.defaultValue(), "default") w.setClearMode(QgsFilterLineEdit.ClearMode.ClearToDefault) self.assertEqual(w.clearMode(), QgsFilterLineEdit.ClearMode.ClearToDefault) w.setShowClearButton(False) @@ -41,29 +42,29 @@ def testGettersSetters(self): self.assertTrue(w.showClearButton()) def testNullValueHandling(self): - """ test widget handling of null values """ + """test widget handling of null values""" w = QgsFilterLineEdit() # start with no null value w.setValue(None) self.assertTrue(w.isNull()) - w.setValue('a') - self.assertEqual(w.text(), 'a') + w.setValue("a") + self.assertEqual(w.text(), "a") self.assertFalse(w.isNull()) # set a null value - w.setNullValue('null') - self.assertEqual(w.value(), 'a') - self.assertEqual(w.text(), 'a') + w.setNullValue("null") + self.assertEqual(w.value(), "a") + self.assertEqual(w.text(), "a") self.assertFalse(w.isNull()) w.setValue(None) self.assertTrue(w.isNull()) self.assertFalse(w.value()) - self.assertEqual(w.text(), 'null') + self.assertEqual(w.text(), "null") - w.setValue('null') - self.assertEqual(w.text(), 'null') + w.setValue("null") + self.assertEqual(w.text(), "null") # ND: I don't think this following logic is correct - should be a distinction between # the widget's representation of null and the actual value. Ie isNull() # should be false and value() should return 'null' @@ -72,10 +73,10 @@ def testNullValueHandling(self): self.assertFalse(w.value()) def testClearToNull(self): - """ test clearing widget """ + """test clearing widget""" w = QgsFilterLineEdit() - w.setValue('abc') + w.setValue("abc") w.clearValue() self.assertTrue(w.isNull()) self.assertFalse(w.value()) @@ -83,11 +84,11 @@ def testClearToNull(self): self.assertTrue(w.isNull()) self.assertFalse(w.value()) - w.setNullValue('def') - w.setValue('abc') + w.setNullValue("def") + w.setValue("abc") self.assertFalse(w.isNull()) w.clearValue() - self.assertEqual(w.text(), 'def') + self.assertEqual(w.text(), "def") self.assertTrue(w.isNull()) self.assertFalse(w.value()) @@ -96,7 +97,7 @@ def testClearToDefault(self): w = QgsFilterLineEdit() w.setClearMode(QgsFilterLineEdit.ClearMode.ClearToDefault) - w.setValue('abc') + w.setValue("abc") w.clearValue() self.assertTrue(w.isNull()) self.assertFalse(w.value()) @@ -104,37 +105,37 @@ def testClearToDefault(self): self.assertTrue(w.isNull()) self.assertFalse(w.value()) - w.setDefaultValue('def') - w.setValue('abc') + w.setDefaultValue("def") + w.setValue("abc") self.assertFalse(w.isNull()) w.clearValue() - self.assertEqual(w.value(), 'def') - self.assertEqual(w.text(), 'def') + self.assertEqual(w.value(), "def") + self.assertEqual(w.text(), "def") self.assertFalse(w.isNull()) def test_selectedText(self): - """ test that NULL value is selected on focus and not-null value is not""" - w = QgsFilterLineEdit(nullValue='my_null_value') + """test that NULL value is selected on focus and not-null value is not""" + w = QgsFilterLineEdit(nullValue="my_null_value") w.clearValue() - self.assertEqual(w.selectedText(), 'my_null_value') + self.assertEqual(w.selectedText(), "my_null_value") - w.setValue('my new value') - self.assertEqual(w.selectedText(), '') + w.setValue("my new value") + self.assertEqual(w.selectedText(), "") w.clearValue() - self.assertEqual(w.selectedText(), 'my_null_value') + self.assertEqual(w.selectedText(), "my_null_value") def test_ChangedSignals(self): - """ test that signals are correctly emitted when clearing""" + """test that signals are correctly emitted when clearing""" w = QgsFilterLineEdit() cleared_spy = QSignalSpy(w.cleared) - w.setValue('1') + w.setValue("1") w.clearValue() self.assertEqual(len(cleared_spy), 1) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfloatingwidget.py b/tests/src/python/test_qgsfloatingwidget.py index 509a16d7698c..78a1ffadd2d6 100644 --- a/tests/src/python/test_qgsfloatingwidget.py +++ b/tests/src/python/test_qgsfloatingwidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '26/04/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "26/04/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtWidgets import QGridLayout, QWidget from qgis.gui import QgsFloatingWidget @@ -20,7 +21,7 @@ class TestQgsFloatingWidget(QgisTestCase): def testAnchor(self): - """ test setting anchor point for widget """ + """test setting anchor point for widget""" main_frame = QWidget() gl = QGridLayout() main_frame.setLayout(gl) @@ -44,32 +45,119 @@ def testAnchor(self): fw.setMinimumSize(100, 50) fw.setAnchorWidget(anchor_widget) - tests = [{'anchorPoint': QgsFloatingWidget.AnchorPoint.TopLeft, 'widgetAnchorPoint': QgsFloatingWidget.AnchorPoint.TopLeft, 'x': 250, 'y': 200}, - {'anchorPoint': QgsFloatingWidget.AnchorPoint.TopMiddle, 'widgetAnchorPoint': QgsFloatingWidget.AnchorPoint.TopLeft, 'x': 200, 'y': 200}, - {'anchorPoint': QgsFloatingWidget.AnchorPoint.TopRight, 'widgetAnchorPoint': QgsFloatingWidget.AnchorPoint.TopLeft, 'x': 150, 'y': 200}, - {'anchorPoint': QgsFloatingWidget.AnchorPoint.MiddleLeft, 'widgetAnchorPoint': QgsFloatingWidget.AnchorPoint.TopLeft, 'x': 250, 'y': 175}, - {'anchorPoint': QgsFloatingWidget.AnchorPoint.Middle, 'widgetAnchorPoint': QgsFloatingWidget.AnchorPoint.TopLeft, 'x': 200, 'y': 175}, - {'anchorPoint': QgsFloatingWidget.AnchorPoint.MiddleRight, 'widgetAnchorPoint': QgsFloatingWidget.AnchorPoint.TopLeft, 'x': 150, 'y': 175}, - {'anchorPoint': QgsFloatingWidget.AnchorPoint.BottomLeft, 'widgetAnchorPoint': QgsFloatingWidget.AnchorPoint.TopLeft, 'x': 250, 'y': 150}, - {'anchorPoint': QgsFloatingWidget.AnchorPoint.BottomMiddle, 'widgetAnchorPoint': QgsFloatingWidget.AnchorPoint.TopLeft, 'x': 200, 'y': 150}, - {'anchorPoint': QgsFloatingWidget.AnchorPoint.BottomRight, 'widgetAnchorPoint': QgsFloatingWidget.AnchorPoint.TopLeft, 'x': 150, 'y': 150}, - {'anchorPoint': QgsFloatingWidget.AnchorPoint.TopLeft, 'widgetAnchorPoint': QgsFloatingWidget.AnchorPoint.TopMiddle, 'x': 400, 'y': 200}, - {'anchorPoint': QgsFloatingWidget.AnchorPoint.TopLeft, 'widgetAnchorPoint': QgsFloatingWidget.AnchorPoint.TopRight, 'x': 550, 'y': 200}, - {'anchorPoint': QgsFloatingWidget.AnchorPoint.TopLeft, 'widgetAnchorPoint': QgsFloatingWidget.AnchorPoint.MiddleLeft, 'x': 250, 'y': 300}, - {'anchorPoint': QgsFloatingWidget.AnchorPoint.TopLeft, 'widgetAnchorPoint': QgsFloatingWidget.AnchorPoint.Middle, 'x': 400, 'y': 300}, - {'anchorPoint': QgsFloatingWidget.AnchorPoint.TopLeft, 'widgetAnchorPoint': QgsFloatingWidget.AnchorPoint.MiddleRight, 'x': 550, 'y': 300}, - {'anchorPoint': QgsFloatingWidget.AnchorPoint.TopLeft, 'widgetAnchorPoint': QgsFloatingWidget.AnchorPoint.BottomLeft, 'x': 250, 'y': 400}, - {'anchorPoint': QgsFloatingWidget.AnchorPoint.TopLeft, 'widgetAnchorPoint': QgsFloatingWidget.AnchorPoint.BottomMiddle, 'x': 400, 'y': 400}, - {'anchorPoint': QgsFloatingWidget.AnchorPoint.TopLeft, 'widgetAnchorPoint': QgsFloatingWidget.AnchorPoint.BottomRight, 'x': 550, 'y': 400}] + tests = [ + { + "anchorPoint": QgsFloatingWidget.AnchorPoint.TopLeft, + "widgetAnchorPoint": QgsFloatingWidget.AnchorPoint.TopLeft, + "x": 250, + "y": 200, + }, + { + "anchorPoint": QgsFloatingWidget.AnchorPoint.TopMiddle, + "widgetAnchorPoint": QgsFloatingWidget.AnchorPoint.TopLeft, + "x": 200, + "y": 200, + }, + { + "anchorPoint": QgsFloatingWidget.AnchorPoint.TopRight, + "widgetAnchorPoint": QgsFloatingWidget.AnchorPoint.TopLeft, + "x": 150, + "y": 200, + }, + { + "anchorPoint": QgsFloatingWidget.AnchorPoint.MiddleLeft, + "widgetAnchorPoint": QgsFloatingWidget.AnchorPoint.TopLeft, + "x": 250, + "y": 175, + }, + { + "anchorPoint": QgsFloatingWidget.AnchorPoint.Middle, + "widgetAnchorPoint": QgsFloatingWidget.AnchorPoint.TopLeft, + "x": 200, + "y": 175, + }, + { + "anchorPoint": QgsFloatingWidget.AnchorPoint.MiddleRight, + "widgetAnchorPoint": QgsFloatingWidget.AnchorPoint.TopLeft, + "x": 150, + "y": 175, + }, + { + "anchorPoint": QgsFloatingWidget.AnchorPoint.BottomLeft, + "widgetAnchorPoint": QgsFloatingWidget.AnchorPoint.TopLeft, + "x": 250, + "y": 150, + }, + { + "anchorPoint": QgsFloatingWidget.AnchorPoint.BottomMiddle, + "widgetAnchorPoint": QgsFloatingWidget.AnchorPoint.TopLeft, + "x": 200, + "y": 150, + }, + { + "anchorPoint": QgsFloatingWidget.AnchorPoint.BottomRight, + "widgetAnchorPoint": QgsFloatingWidget.AnchorPoint.TopLeft, + "x": 150, + "y": 150, + }, + { + "anchorPoint": QgsFloatingWidget.AnchorPoint.TopLeft, + "widgetAnchorPoint": QgsFloatingWidget.AnchorPoint.TopMiddle, + "x": 400, + "y": 200, + }, + { + "anchorPoint": QgsFloatingWidget.AnchorPoint.TopLeft, + "widgetAnchorPoint": QgsFloatingWidget.AnchorPoint.TopRight, + "x": 550, + "y": 200, + }, + { + "anchorPoint": QgsFloatingWidget.AnchorPoint.TopLeft, + "widgetAnchorPoint": QgsFloatingWidget.AnchorPoint.MiddleLeft, + "x": 250, + "y": 300, + }, + { + "anchorPoint": QgsFloatingWidget.AnchorPoint.TopLeft, + "widgetAnchorPoint": QgsFloatingWidget.AnchorPoint.Middle, + "x": 400, + "y": 300, + }, + { + "anchorPoint": QgsFloatingWidget.AnchorPoint.TopLeft, + "widgetAnchorPoint": QgsFloatingWidget.AnchorPoint.MiddleRight, + "x": 550, + "y": 300, + }, + { + "anchorPoint": QgsFloatingWidget.AnchorPoint.TopLeft, + "widgetAnchorPoint": QgsFloatingWidget.AnchorPoint.BottomLeft, + "x": 250, + "y": 400, + }, + { + "anchorPoint": QgsFloatingWidget.AnchorPoint.TopLeft, + "widgetAnchorPoint": QgsFloatingWidget.AnchorPoint.BottomMiddle, + "x": 400, + "y": 400, + }, + { + "anchorPoint": QgsFloatingWidget.AnchorPoint.TopLeft, + "widgetAnchorPoint": QgsFloatingWidget.AnchorPoint.BottomRight, + "x": 550, + "y": 400, + }, + ] for t in tests: - fw.setAnchorPoint(t['anchorPoint']) - fw.setAnchorWidgetPoint(t['widgetAnchorPoint']) - self.assertEqual(fw.pos().x(), t['x']) - self.assertEqual(fw.pos().y(), t['y']) + fw.setAnchorPoint(t["anchorPoint"]) + fw.setAnchorWidgetPoint(t["widgetAnchorPoint"]) + self.assertEqual(fw.pos().x(), t["x"]) + self.assertEqual(fw.pos().y(), t["y"]) def testMovingResizingAnchorWidget(self): - """ test that moving or resizing the anchor widget updates the floating widget position """ + """test that moving or resizing the anchor widget updates the floating widget position""" main_frame = QWidget() gl = QGridLayout() main_frame.setLayout(gl) @@ -113,7 +201,7 @@ def testMovingResizingAnchorWidget(self): self.assertEqual(fw.pos().y(), 110) def testResizingParentWidget(self): - """ test resizing parent widget correctly repositions floating widget""" + """test resizing parent widget correctly repositions floating widget""" main_frame = QWidget() gl = QGridLayout() main_frame.setLayout(gl) @@ -152,7 +240,7 @@ def testResizingParentWidget(self): self.assertEqual(fw.pos().y(), 300) def testPositionConstrainedToParent(self): - """ test that floating widget will be placed inside parent when possible """ + """test that floating widget will be placed inside parent when possible""" main_frame = QWidget() gl = QGridLayout() main_frame.setLayout(gl) @@ -188,5 +276,5 @@ def testPositionConstrainedToParent(self): self.assertEqual(fw.pos().x(), 500) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfontbutton.py b/tests/src/python/test_qgsfontbutton.py index 9963daaa2a91..549fcaf99dbb 100644 --- a/tests/src/python/test_qgsfontbutton.py +++ b/tests/src/python/test_qgsfontbutton.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '04/06/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "04/06/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtGui import QColor from qgis.PyQt.QtTest import QSignalSpy @@ -27,8 +28,8 @@ def testGettersSetters(self): button = QgsFontButton() canvas = QgsMapCanvas() - button.setDialogTitle('test title') - self.assertEqual(button.dialogTitle(), 'test title') + button.setDialogTitle("test title") + self.assertEqual(button.dialogTitle(), "test title") button.setMapCanvas(canvas) self.assertEqual(button.mapCanvas(), canvas) @@ -38,7 +39,7 @@ def testSetGetFormat(self): s = QgsTextFormat() s.setFont(getTestFont()) - s.setNamedStyle('Italic') + s.setNamedStyle("Italic") s.setSize(5) s.setColor(QColor(255, 0, 0)) s.setOpacity(0.5) @@ -48,8 +49,8 @@ def testSetGetFormat(self): self.assertEqual(len(signal_spy), 1) r = button.textFormat() - self.assertEqual(r.font().family(), 'QGIS Vera Sans') - self.assertEqual(r.namedStyle(), 'Italic') + self.assertEqual(r.font().family(), "QGIS Vera Sans") + self.assertEqual(r.namedStyle(), "Italic") self.assertEqual(r.size(), 5) self.assertEqual(r.color(), QColor(255, 0, 0)) self.assertEqual(r.opacity(), 0.5) @@ -67,8 +68,8 @@ def testSetGetFont(self): self.assertEqual(len(signal_spy), 1) r = button.currentFont() - self.assertEqual(r.family(), 'QGIS Vera Sans') - self.assertEqual(r.styleName(), 'Roman') + self.assertEqual(r.family(), "QGIS Vera Sans") + self.assertEqual(r.styleName(), "Roman") self.assertEqual(r.pointSize(), 16) def testSetColor(self): @@ -76,7 +77,7 @@ def testSetColor(self): s = QgsTextFormat() s.setFont(getTestFont()) - s.setNamedStyle('Italic') + s.setNamedStyle("Italic") s.setSize(5) s.setColor(QColor(255, 0, 0)) s.setOpacity(0.5) @@ -87,8 +88,8 @@ def testSetColor(self): self.assertEqual(len(signal_spy), 1) r = button.textFormat() - self.assertEqual(r.font().family(), 'QGIS Vera Sans') - self.assertEqual(r.namedStyle(), 'Italic') + self.assertEqual(r.font().family(), "QGIS Vera Sans") + self.assertEqual(r.namedStyle(), "Italic") self.assertEqual(r.size(), 5) self.assertEqual(r.color().name(), QColor(0, 255, 0).name()) self.assertEqual(r.opacity(), 0.5) @@ -118,5 +119,5 @@ def testNull(self): self.assertTrue(button.textFormat().isValid()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfontmanager.py b/tests/src/python/test_qgsfontmanager.py index 779c8d3ab087..2fda631d4e21 100644 --- a/tests/src/python/test_qgsfontmanager.py +++ b/tests/src/python/test_qgsfontmanager.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '15/06/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "15/06/2022" +__copyright__ = "Copyright 2022, The QGIS Project" import os.path import tempfile @@ -46,77 +47,148 @@ def setUpClass(cls): def test_family_replacement(self): manager = QgsFontManager() self.assertFalse(manager.fontFamilyReplacements()) - self.assertEqual(manager.processFontFamilyName('xxx'), 'xxx') - - manager.addFontFamilyReplacement('comic sans', 'something better') - self.assertEqual(manager.fontFamilyReplacements(), {'comic sans': 'something better'}) - self.assertEqual(manager.processFontFamilyName('xxx'), 'xxx') - self.assertEqual(manager.processFontFamilyName('comic sans'), 'something better') + self.assertEqual(manager.processFontFamilyName("xxx"), "xxx") + + manager.addFontFamilyReplacement("comic sans", "something better") + self.assertEqual( + manager.fontFamilyReplacements(), {"comic sans": "something better"} + ) + self.assertEqual(manager.processFontFamilyName("xxx"), "xxx") + self.assertEqual( + manager.processFontFamilyName("comic sans"), "something better" + ) # process font family name should be case insensitive - self.assertEqual(manager.processFontFamilyName('Comic Sans'), 'something better') + self.assertEqual( + manager.processFontFamilyName("Comic Sans"), "something better" + ) # make sure replacements are persisted locally manager2 = QgsFontManager() - self.assertEqual(manager2.fontFamilyReplacements(), {'comic sans': 'something better'}) - self.assertEqual(manager2.processFontFamilyName('xxx'), 'xxx') - self.assertEqual(manager2.processFontFamilyName('comic sans'), 'something better') - self.assertEqual(manager2.processFontFamilyName('Comic Sans'), 'something better') - - manager.addFontFamilyReplacement('arial', 'something else better') - self.assertEqual(manager.fontFamilyReplacements(), {'arial': 'something else better', 'comic sans': 'something better'}) - self.assertEqual(manager.processFontFamilyName('xxx'), 'xxx') - self.assertEqual(manager.processFontFamilyName('comic sans'), 'something better') - self.assertEqual(manager.processFontFamilyName('Comic Sans'), 'something better') - self.assertEqual(manager.processFontFamilyName('arial'), 'something else better') - self.assertEqual(manager.processFontFamilyName('arIAl'), 'something else better') + self.assertEqual( + manager2.fontFamilyReplacements(), {"comic sans": "something better"} + ) + self.assertEqual(manager2.processFontFamilyName("xxx"), "xxx") + self.assertEqual( + manager2.processFontFamilyName("comic sans"), "something better" + ) + self.assertEqual( + manager2.processFontFamilyName("Comic Sans"), "something better" + ) + + manager.addFontFamilyReplacement("arial", "something else better") + self.assertEqual( + manager.fontFamilyReplacements(), + {"arial": "something else better", "comic sans": "something better"}, + ) + self.assertEqual(manager.processFontFamilyName("xxx"), "xxx") + self.assertEqual( + manager.processFontFamilyName("comic sans"), "something better" + ) + self.assertEqual( + manager.processFontFamilyName("Comic Sans"), "something better" + ) + self.assertEqual( + manager.processFontFamilyName("arial"), "something else better" + ) + self.assertEqual( + manager.processFontFamilyName("arIAl"), "something else better" + ) manager2 = QgsFontManager() - self.assertEqual(manager2.fontFamilyReplacements(), {'arial': 'something else better', 'comic sans': 'something better'}) - self.assertEqual(manager2.processFontFamilyName('xxx'), 'xxx') - self.assertEqual(manager2.processFontFamilyName('comic sans'), 'something better') - self.assertEqual(manager2.processFontFamilyName('Comic Sans'), 'something better') - self.assertEqual(manager2.processFontFamilyName('arial'), 'something else better') - self.assertEqual(manager2.processFontFamilyName('arIAl'), 'something else better') - - manager.addFontFamilyReplacement('arial', 'comic sans') - self.assertEqual(manager.fontFamilyReplacements(), {'arial': 'comic sans', 'comic sans': 'something better'}) - - self.assertEqual(manager.processFontFamilyName('xxx'), 'xxx') - self.assertEqual(manager.processFontFamilyName('comic sans'), 'something better') - self.assertEqual(manager.processFontFamilyName('Comic Sans'), 'something better') - self.assertEqual(manager.processFontFamilyName('arial'), 'comic sans') - self.assertEqual(manager.processFontFamilyName('arIAl'), 'comic sans') - - manager.addFontFamilyReplacement('arial', '') - self.assertEqual(manager.fontFamilyReplacements(), {'comic sans': 'something better'}) - self.assertEqual(manager.processFontFamilyName('xxx'), 'xxx') - self.assertEqual(manager.processFontFamilyName('comic sans'), 'something better') - self.assertEqual(manager.processFontFamilyName('Comic Sans'), 'something better') - self.assertEqual(manager.processFontFamilyName('arial'), 'arial') - - manager.setFontFamilyReplacements({'arial': 'something else better2', 'comic sans': 'something better2'}) - self.assertEqual(manager.fontFamilyReplacements(), {'arial': 'something else better2', 'comic sans': 'something better2'}) - self.assertEqual(manager.processFontFamilyName('xxx'), 'xxx') - self.assertEqual(manager.processFontFamilyName('comic sans'), 'something better2') - self.assertEqual(manager.processFontFamilyName('Comic Sans'), 'something better2') - self.assertEqual(manager.processFontFamilyName('arial'), 'something else better2') - self.assertEqual(manager.processFontFamilyName('arIAl'), 'something else better2') + self.assertEqual( + manager2.fontFamilyReplacements(), + {"arial": "something else better", "comic sans": "something better"}, + ) + self.assertEqual(manager2.processFontFamilyName("xxx"), "xxx") + self.assertEqual( + manager2.processFontFamilyName("comic sans"), "something better" + ) + self.assertEqual( + manager2.processFontFamilyName("Comic Sans"), "something better" + ) + self.assertEqual( + manager2.processFontFamilyName("arial"), "something else better" + ) + self.assertEqual( + manager2.processFontFamilyName("arIAl"), "something else better" + ) + + manager.addFontFamilyReplacement("arial", "comic sans") + self.assertEqual( + manager.fontFamilyReplacements(), + {"arial": "comic sans", "comic sans": "something better"}, + ) + + self.assertEqual(manager.processFontFamilyName("xxx"), "xxx") + self.assertEqual( + manager.processFontFamilyName("comic sans"), "something better" + ) + self.assertEqual( + manager.processFontFamilyName("Comic Sans"), "something better" + ) + self.assertEqual(manager.processFontFamilyName("arial"), "comic sans") + self.assertEqual(manager.processFontFamilyName("arIAl"), "comic sans") + + manager.addFontFamilyReplacement("arial", "") + self.assertEqual( + manager.fontFamilyReplacements(), {"comic sans": "something better"} + ) + self.assertEqual(manager.processFontFamilyName("xxx"), "xxx") + self.assertEqual( + manager.processFontFamilyName("comic sans"), "something better" + ) + self.assertEqual( + manager.processFontFamilyName("Comic Sans"), "something better" + ) + self.assertEqual(manager.processFontFamilyName("arial"), "arial") + + manager.setFontFamilyReplacements( + {"arial": "something else better2", "comic sans": "something better2"} + ) + self.assertEqual( + manager.fontFamilyReplacements(), + {"arial": "something else better2", "comic sans": "something better2"}, + ) + self.assertEqual(manager.processFontFamilyName("xxx"), "xxx") + self.assertEqual( + manager.processFontFamilyName("comic sans"), "something better2" + ) + self.assertEqual( + manager.processFontFamilyName("Comic Sans"), "something better2" + ) + self.assertEqual( + manager.processFontFamilyName("arial"), "something else better2" + ) + self.assertEqual( + manager.processFontFamilyName("arIAl"), "something else better2" + ) manager2 = QgsFontManager() - self.assertEqual(manager2.fontFamilyReplacements(), {'arial': 'something else better2', 'comic sans': 'something better2'}) - self.assertEqual(manager2.processFontFamilyName('xxx'), 'xxx') - self.assertEqual(manager2.processFontFamilyName('comic sans'), 'something better2') - self.assertEqual(manager2.processFontFamilyName('Comic Sans'), 'something better2') - self.assertEqual(manager2.processFontFamilyName('arial'), 'something else better2') - self.assertEqual(manager2.processFontFamilyName('arIAl'), 'something else better2') + self.assertEqual( + manager2.fontFamilyReplacements(), + {"arial": "something else better2", "comic sans": "something better2"}, + ) + self.assertEqual(manager2.processFontFamilyName("xxx"), "xxx") + self.assertEqual( + manager2.processFontFamilyName("comic sans"), "something better2" + ) + self.assertEqual( + manager2.processFontFamilyName("Comic Sans"), "something better2" + ) + self.assertEqual( + manager2.processFontFamilyName("arial"), "something else better2" + ) + self.assertEqual( + manager2.processFontFamilyName("arIAl"), "something else better2" + ) def test_replacements(self): manager = QgsApplication.fontManager() format = QgsTextFormat() - font = QFont('original family') + font = QFont("original family") format.setFont(font) - self.assertEqual(format.font().family(), 'original family') + self.assertEqual(format.font().family(), "original family") doc = QDomDocument() context = QgsReadWriteContext() @@ -126,16 +198,19 @@ def test_replacements(self): t2 = QgsTextFormat() t2.readXml(parent, context) self.assertFalse(t2.fontFound()) - self.assertEqual(context.takeMessages()[0].message(), 'Font “original family” not available on system') + self.assertEqual( + context.takeMessages()[0].message(), + "Font “original family” not available on system", + ) # with a font replacement in place test_font = getTestFont() - manager.addFontFamilyReplacement('original Family', test_font.family()) + manager.addFontFamilyReplacement("original Family", test_font.family()) t3 = QgsTextFormat() t3.readXml(parent, context) self.assertTrue(t3.fontFound()) - self.assertEqual(t3.font().family(), 'QGIS Vera Sans') + self.assertEqual(t3.font().family(), "QGIS Vera Sans") def test_install_font(self): manager = QgsFontManager() @@ -145,23 +220,28 @@ def test_install_font(self): spy_installed = QSignalSpy(manager.fontDownloaded) spy_failed = QSignalSpy(manager.fontDownloadErrorOccurred) - manager.downloadAndInstallFont(QUrl.fromLocalFile('xxxx')) + manager.downloadAndInstallFont(QUrl.fromLocalFile("xxxx")) spy_failed.wait() self.assertEqual(len(spy_failed), 1) self.assertEqual(len(spy_installed), 0) - manager.downloadAndInstallFont(QUrl.fromLocalFile(unitTestDataPath() + '/fascinate.ttf')) + manager.downloadAndInstallFont( + QUrl.fromLocalFile(unitTestDataPath() + "/fascinate.ttf") + ) spy_installed.wait() self.assertEqual(len(spy_failed), 1) self.assertEqual(len(spy_installed), 1) - self.assertEqual(spy_installed[0][0], ['Fascinate']) + self.assertEqual(spy_installed[0][0], ["Fascinate"]) - self.assertTrue(os.path.exists(os.path.join(user_font_dir, 'Fascinate'))) - self.assertEqual(manager.userFontToFamilyMap(), {os.path.join(user_font_dir, 'Fascinate'): ['Fascinate']}) + self.assertTrue(os.path.exists(os.path.join(user_font_dir, "Fascinate"))) + self.assertEqual( + manager.userFontToFamilyMap(), + {os.path.join(user_font_dir, "Fascinate"): ["Fascinate"]}, + ) - manager.removeUserFont(os.path.join(user_font_dir, 'Fascinate')) + manager.removeUserFont(os.path.join(user_font_dir, "Fascinate")) self.assertFalse(manager.userFontToFamilyMap()) - self.assertFalse(os.path.exists(os.path.join(user_font_dir, 'Fascinate'))) + self.assertFalse(os.path.exists(os.path.join(user_font_dir, "Fascinate"))) def test_install_zipped_font(self): manager = QgsFontManager() @@ -171,81 +251,221 @@ def test_install_zipped_font(self): spy_installed = QSignalSpy(manager.fontDownloaded) spy_failed = QSignalSpy(manager.fontDownloadErrorOccurred) - manager.downloadAndInstallFont(QUrl.fromLocalFile('xxxx')) + manager.downloadAndInstallFont(QUrl.fromLocalFile("xxxx")) spy_failed.wait() self.assertEqual(len(spy_failed), 1) self.assertEqual(len(spy_installed), 0) - manager.downloadAndInstallFont(QUrl.fromLocalFile(unitTestDataPath() + '/zipped_font.zip')) + manager.downloadAndInstallFont( + QUrl.fromLocalFile(unitTestDataPath() + "/zipped_font.zip") + ) spy_installed.wait() self.assertEqual(len(spy_failed), 1) self.assertEqual(len(spy_installed), 1) - self.assertEqual(spy_installed[0][0], ['Fresca']) - self.assertTrue(spy_installed[0][1].startswith('Copyright (c) 2011')) + self.assertEqual(spy_installed[0][0], ["Fresca"]) + self.assertTrue(spy_installed[0][1].startswith("Copyright (c) 2011")) - self.assertTrue(os.path.exists(os.path.join(user_font_dir, 'Fresca-Regular.ttf'))) + self.assertTrue( + os.path.exists(os.path.join(user_font_dir, "Fresca-Regular.ttf")) + ) - self.assertEqual(manager.userFontToFamilyMap(), {os.path.join(user_font_dir, 'Fresca-Regular.ttf'): ['Fresca']}) + self.assertEqual( + manager.userFontToFamilyMap(), + {os.path.join(user_font_dir, "Fresca-Regular.ttf"): ["Fresca"]}, + ) def test_font_download_urls(self): manager = QgsFontManager() - self.assertEqual(manager.urlForFontDownload('xxx'), ('', '')) - self.assertFalse(manager.detailsForFontDownload('xxx')[0].isValid()) - self.assertEqual(manager.urlForFontDownload('Alegreya SC'), ('https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-Regular.ttf', 'Alegreya SC')) - self.assertEqual(manager.urlForFontDownload('AlegreyaSC'), ('https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-Regular.ttf', 'Alegreya SC')) - self.assertEqual(manager.urlForFontDownload('alegreya_sc'), ('https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-Regular.ttf', 'Alegreya SC')) - - self.assertTrue(manager.detailsForFontDownload('Alegreya SC')[0].isValid()) - self.assertEqual(manager.detailsForFontDownload('Alegreya SC')[0].fontUrls(), ['https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-Regular.ttf', 'https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-Italic.ttf', 'https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-Medium.ttf', 'https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-MediumItalic.ttf', 'https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-Bold.ttf', 'https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-BoldItalic.ttf', 'https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-ExtraBold.ttf', 'https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-ExtraBoldItalic.ttf', 'https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-Black.ttf', 'https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-BlackItalic.ttf']) - self.assertEqual(manager.detailsForFontDownload('Alegreya SC')[0].licenseUrl(), 'https://github.com/google/fonts/raw/main/ofl/alegreyasc/OFL.txt') - - self.assertEqual(manager.urlForFontDownload('Roboto'), - ('https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf', 'Roboto')) - - self.assertEqual(manager.urlForFontDownload('Open Sans'), - ('https://github.com/google/fonts/raw/main/ofl/opensans/OpenSans%5Bwdth,wght%5D.ttf', 'Open Sans')) + self.assertEqual(manager.urlForFontDownload("xxx"), ("", "")) + self.assertFalse(manager.detailsForFontDownload("xxx")[0].isValid()) + self.assertEqual( + manager.urlForFontDownload("Alegreya SC"), + ( + "https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-Regular.ttf", + "Alegreya SC", + ), + ) + self.assertEqual( + manager.urlForFontDownload("AlegreyaSC"), + ( + "https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-Regular.ttf", + "Alegreya SC", + ), + ) + self.assertEqual( + manager.urlForFontDownload("alegreya_sc"), + ( + "https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-Regular.ttf", + "Alegreya SC", + ), + ) + + self.assertTrue(manager.detailsForFontDownload("Alegreya SC")[0].isValid()) + self.assertEqual( + manager.detailsForFontDownload("Alegreya SC")[0].fontUrls(), + [ + "https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-Regular.ttf", + "https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-Italic.ttf", + "https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-Medium.ttf", + "https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-MediumItalic.ttf", + "https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-Bold.ttf", + "https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-BoldItalic.ttf", + "https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-ExtraBold.ttf", + "https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-ExtraBoldItalic.ttf", + "https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-Black.ttf", + "https://github.com/google/fonts/raw/main/ofl/alegreyasc/AlegreyaSC-BlackItalic.ttf", + ], + ) + self.assertEqual( + manager.detailsForFontDownload("Alegreya SC")[0].licenseUrl(), + "https://github.com/google/fonts/raw/main/ofl/alegreyasc/OFL.txt", + ) + + self.assertEqual( + manager.urlForFontDownload("Roboto"), + ( + "https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf", + "Roboto", + ), + ) + + self.assertEqual( + manager.urlForFontDownload("Open Sans"), + ( + "https://github.com/google/fonts/raw/main/ofl/opensans/OpenSans%5Bwdth,wght%5D.ttf", + "Open Sans", + ), + ) # not available via github? # self.assertEqual(manager.urlForFontDownload('Open Sans Condensed'), # ('https://fonts.google.com/download?family=Open+Sans+Condensed', 'Open Sans Condensed')) - self.assertEqual(manager.urlForFontDownload('Noto Sans'), - ('https://github.com/google/fonts/raw/main/ofl/notosans/NotoSans%5Bwdth,wght%5D.ttf', 'Noto Sans')) - - self.assertEqual(manager.urlForFontDownload('Roboto Condensed'), ('https://github.com/google/fonts/raw/main/ofl/robotocondensed/RobotoCondensed%5Bwght%5D.ttf', 'Roboto Condensed')) + self.assertEqual( + manager.urlForFontDownload("Noto Sans"), + ( + "https://github.com/google/fonts/raw/main/ofl/notosans/NotoSans%5Bwdth,wght%5D.ttf", + "Noto Sans", + ), + ) + + self.assertEqual( + manager.urlForFontDownload("Roboto Condensed"), + ( + "https://github.com/google/fonts/raw/main/ofl/robotocondensed/RobotoCondensed%5Bwght%5D.ttf", + "Roboto Condensed", + ), + ) # variants for font names typically seen in vector tile styles - self.assertEqual(manager.urlForFontDownload('RobotoCondensedRegular'), ('https://github.com/google/fonts/raw/main/ofl/robotocondensed/RobotoCondensed%5Bwght%5D.ttf', 'Roboto Condensed')) - self.assertEqual(manager.urlForFontDownload('Roboto Condensed Regular'), ('https://github.com/google/fonts/raw/main/ofl/robotocondensed/RobotoCondensed%5Bwght%5D.ttf', 'Roboto Condensed')) - self.assertEqual(manager.urlForFontDownload('Roboto_Condensed_Regular'), - ('https://github.com/google/fonts/raw/main/ofl/robotocondensed/RobotoCondensed%5Bwght%5D.ttf', 'Roboto Condensed')) + self.assertEqual( + manager.urlForFontDownload("RobotoCondensedRegular"), + ( + "https://github.com/google/fonts/raw/main/ofl/robotocondensed/RobotoCondensed%5Bwght%5D.ttf", + "Roboto Condensed", + ), + ) + self.assertEqual( + manager.urlForFontDownload("Roboto Condensed Regular"), + ( + "https://github.com/google/fonts/raw/main/ofl/robotocondensed/RobotoCondensed%5Bwght%5D.ttf", + "Roboto Condensed", + ), + ) + self.assertEqual( + manager.urlForFontDownload("Roboto_Condensed_Regular"), + ( + "https://github.com/google/fonts/raw/main/ofl/robotocondensed/RobotoCondensed%5Bwght%5D.ttf", + "Roboto Condensed", + ), + ) # with style names - self.assertEqual(manager.urlForFontDownload('Roboto Black'), - ('https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf', 'Roboto')) - self.assertEqual(manager.urlForFontDownload('Roboto Black Italic'), - ('https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf', 'Roboto')) - self.assertEqual(manager.urlForFontDownload('Roboto Bold'), - ('https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf', 'Roboto')) - self.assertEqual(manager.urlForFontDownload('Roboto Bold Italic'), - ('https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf', 'Roboto')) - self.assertEqual(manager.urlForFontDownload('Roboto Italic'), - ('https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf', 'Roboto')) - self.assertEqual(manager.urlForFontDownload('Roboto Light'), - ('https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf', 'Roboto')) - self.assertEqual(manager.urlForFontDownload('Roboto Light Italic'), - ('https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf', 'Roboto')) - self.assertEqual(manager.urlForFontDownload('Roboto Medium'), - ('https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf', 'Roboto')) - self.assertEqual(manager.urlForFontDownload('Roboto Medium Italic'), - ('https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf', 'Roboto')) - self.assertEqual(manager.urlForFontDownload('Roboto Regular'), - ('https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf', 'Roboto')) - self.assertEqual(manager.urlForFontDownload('Roboto Thin'), - ('https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf', 'Roboto')) - self.assertEqual(manager.urlForFontDownload('Roboto Thin Italic'), - ('https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf', 'Roboto')) - - -if __name__ == '__main__': + self.assertEqual( + manager.urlForFontDownload("Roboto Black"), + ( + "https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf", + "Roboto", + ), + ) + self.assertEqual( + manager.urlForFontDownload("Roboto Black Italic"), + ( + "https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf", + "Roboto", + ), + ) + self.assertEqual( + manager.urlForFontDownload("Roboto Bold"), + ( + "https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf", + "Roboto", + ), + ) + self.assertEqual( + manager.urlForFontDownload("Roboto Bold Italic"), + ( + "https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf", + "Roboto", + ), + ) + self.assertEqual( + manager.urlForFontDownload("Roboto Italic"), + ( + "https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf", + "Roboto", + ), + ) + self.assertEqual( + manager.urlForFontDownload("Roboto Light"), + ( + "https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf", + "Roboto", + ), + ) + self.assertEqual( + manager.urlForFontDownload("Roboto Light Italic"), + ( + "https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf", + "Roboto", + ), + ) + self.assertEqual( + manager.urlForFontDownload("Roboto Medium"), + ( + "https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf", + "Roboto", + ), + ) + self.assertEqual( + manager.urlForFontDownload("Roboto Medium Italic"), + ( + "https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf", + "Roboto", + ), + ) + self.assertEqual( + manager.urlForFontDownload("Roboto Regular"), + ( + "https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf", + "Roboto", + ), + ) + self.assertEqual( + manager.urlForFontDownload("Roboto Thin"), + ( + "https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf", + "Roboto", + ), + ) + self.assertEqual( + manager.urlForFontDownload("Roboto Thin Italic"), + ( + "https://github.com/google/fonts/raw/main/ofl/roboto/Roboto%5Bwdth,wght%5D.ttf", + "Roboto", + ), + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsfontutils.py b/tests/src/python/test_qgsfontutils.py index 16379f865ea8..935ee6299596 100644 --- a/tests/src/python/test_qgsfontutils.py +++ b/tests/src/python/test_qgsfontutils.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Larry Shaffer' -__date__ = '2014/02/19' -__copyright__ = 'Copyright 2014, The QGIS Project' + +__author__ = "Larry Shaffer" +__date__ = "2014/02/19" +__copyright__ = "Copyright 2014, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication from qgis.core import QgsFontUtils, QgsSettings @@ -38,39 +39,39 @@ def test_loading_base_test_fonts(self): loadTestFonts() def test_loading_every_test_font(self): - QgsFontUtils.loadStandardTestFonts(['All']) + QgsFontUtils.loadStandardTestFonts(["All"]) # styles = '' # for style in QFontDatabase().styles(self._family): # styles += ' ' + style # print self._family + ' styles:' + styles res = ( - self._has_style(self._family, 'Roman') and - self._has_style(self._family, 'Oblique') and - self._has_style(self._family, 'Bold') and - self._has_style(self._family, 'Bold Oblique') + self._has_style(self._family, "Roman") + and self._has_style(self._family, "Oblique") + and self._has_style(self._family, "Bold") + and self._has_style(self._family, "Bold Oblique") ) - msg = self._family + ' test font styles could not be loaded' + msg = self._family + " test font styles could not be loaded" assert res, msg def test_get_specific_test_font(self): # default returned is Roman at 12 pt - f = QgsFontUtils.getStandardTestFont('Bold Oblique', 14) + f = QgsFontUtils.getStandardTestFont("Bold Oblique", 14) """:type: QFont""" res = ( - f.family() == self._family and - f.bold() and - f.italic() and - f.pointSize() == 14 + f.family() == self._family + and f.bold() + and f.italic() + and f.pointSize() == 14 ) - msg = self._family + ' test font Bold Oblique at 14 pt not retrieved' + msg = self._family + " test font Bold Oblique at 14 pt not retrieved" assert res, msg def testToFromMimeData(self): """ Test converting QFonts to and from mime data """ - f = QgsFontUtils.getStandardTestFont('Bold Oblique', 14) + f = QgsFontUtils.getStandardTestFont("Bold Oblique", 14) mime_data = QgsFontUtils.toMimeData(f) self.assertTrue(mime_data is not None) @@ -80,12 +81,15 @@ def testToFromMimeData(self): self.assertTrue(ok) expected = ( - res.family() == self._family and - res.bold() and - res.italic() and - res.pointSize() == 14 + res.family() == self._family + and res.bold() + and res.italic() + and res.pointSize() == 14 + ) + msg = ( + self._family + + " test font Bold Oblique at 14 pt not retrieved from mime data" ) - msg = self._family + ' test font Bold Oblique at 14 pt not retrieved from mime data' self.assertTrue(res, msg) def testRecentFonts(self): @@ -95,25 +99,69 @@ def testRecentFonts(self): # test empty list self.assertFalse(QgsFontUtils.recentFontFamilies()) - QgsFontUtils.addRecentFontFamily('Comic Sans FTW, suckers') - self.assertEqual(QgsFontUtils.recentFontFamilies(), ['Comic Sans FTW, suckers']) - QgsFontUtils.addRecentFontFamily('Arial') - self.assertEqual(QgsFontUtils.recentFontFamilies(), ['Arial', 'Comic Sans FTW, suckers']) - QgsFontUtils.addRecentFontFamily('Arial2') - QgsFontUtils.addRecentFontFamily('Arial3') - QgsFontUtils.addRecentFontFamily('Arial4') - QgsFontUtils.addRecentFontFamily('Arial5') - QgsFontUtils.addRecentFontFamily('Arial6') - QgsFontUtils.addRecentFontFamily('Arial7') - QgsFontUtils.addRecentFontFamily('Arial8') - QgsFontUtils.addRecentFontFamily('Arial9') - QgsFontUtils.addRecentFontFamily('Arial10') - self.assertEqual(QgsFontUtils.recentFontFamilies(), ['Arial10', 'Arial9', 'Arial8', 'Arial7', 'Arial6', 'Arial5', 'Arial4', 'Arial3', 'Arial2', 'Arial']) - QgsFontUtils.addRecentFontFamily('Arial9') - self.assertEqual(QgsFontUtils.recentFontFamilies(), ['Arial9', 'Arial10', 'Arial8', 'Arial7', 'Arial6', 'Arial5', 'Arial4', 'Arial3', 'Arial2', 'Arial']) - QgsFontUtils.addRecentFontFamily('Comic Sans FTW, suckers') - self.assertEqual(QgsFontUtils.recentFontFamilies(), ['Comic Sans FTW, suckers', 'Arial9', 'Arial10', 'Arial8', 'Arial7', 'Arial6', 'Arial5', 'Arial4', 'Arial3', 'Arial2']) - - -if __name__ == '__main__': + QgsFontUtils.addRecentFontFamily("Comic Sans FTW, suckers") + self.assertEqual(QgsFontUtils.recentFontFamilies(), ["Comic Sans FTW, suckers"]) + QgsFontUtils.addRecentFontFamily("Arial") + self.assertEqual( + QgsFontUtils.recentFontFamilies(), ["Arial", "Comic Sans FTW, suckers"] + ) + QgsFontUtils.addRecentFontFamily("Arial2") + QgsFontUtils.addRecentFontFamily("Arial3") + QgsFontUtils.addRecentFontFamily("Arial4") + QgsFontUtils.addRecentFontFamily("Arial5") + QgsFontUtils.addRecentFontFamily("Arial6") + QgsFontUtils.addRecentFontFamily("Arial7") + QgsFontUtils.addRecentFontFamily("Arial8") + QgsFontUtils.addRecentFontFamily("Arial9") + QgsFontUtils.addRecentFontFamily("Arial10") + self.assertEqual( + QgsFontUtils.recentFontFamilies(), + [ + "Arial10", + "Arial9", + "Arial8", + "Arial7", + "Arial6", + "Arial5", + "Arial4", + "Arial3", + "Arial2", + "Arial", + ], + ) + QgsFontUtils.addRecentFontFamily("Arial9") + self.assertEqual( + QgsFontUtils.recentFontFamilies(), + [ + "Arial9", + "Arial10", + "Arial8", + "Arial7", + "Arial6", + "Arial5", + "Arial4", + "Arial3", + "Arial2", + "Arial", + ], + ) + QgsFontUtils.addRecentFontFamily("Comic Sans FTW, suckers") + self.assertEqual( + QgsFontUtils.recentFontFamilies(), + [ + "Comic Sans FTW, suckers", + "Arial9", + "Arial10", + "Arial8", + "Arial7", + "Arial6", + "Arial5", + "Arial4", + "Arial3", + "Arial2", + ], + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsgeocoderalgorithm.py b/tests/src/python/test_qgsgeocoderalgorithm.py index cd8c9e158560..a0a17e115a03 100644 --- a/tests/src/python/test_qgsgeocoderalgorithm.py +++ b/tests/src/python/test_qgsgeocoderalgorithm.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '02/11/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "02/11/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QVariant from qgis.analysis import QgsBatchGeocodeAlgorithm @@ -41,21 +42,30 @@ def wkbType(self): return QgsWkbTypes.Type.Point def geocodeString(self, string, context, feedback): - if string == 'a': - result = QgsGeocoderResult('res 1', QgsGeometry.fromPointXY(QgsPointXY(1, 2)), - QgsCoordinateReferenceSystem('EPSG:4326')) - result.setAdditionalAttributes({'b': 123, 'c': 'xyz'}) + if string == "a": + result = QgsGeocoderResult( + "res 1", + QgsGeometry.fromPointXY(QgsPointXY(1, 2)), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + result.setAdditionalAttributes({"b": 123, "c": "xyz"}) return [result] - if string == 'b': - result1 = QgsGeocoderResult('res 1', QgsGeometry.fromPointXY(QgsPointXY(11, 12)), - QgsCoordinateReferenceSystem('EPSG:4326')) - result1.setAdditionalAttributes({'b': 123, 'c': 'xyz'}) - result1.setDescription('desc') - result1.setGroup('group') - result2 = QgsGeocoderResult('res 2', QgsGeometry.fromPointXY(QgsPointXY(13, 14)), - QgsCoordinateReferenceSystem('EPSG:3857')) - result2.setAdditionalAttributes({'d': 456}) + if string == "b": + result1 = QgsGeocoderResult( + "res 1", + QgsGeometry.fromPointXY(QgsPointXY(11, 12)), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + result1.setAdditionalAttributes({"b": 123, "c": "xyz"}) + result1.setDescription("desc") + result1.setGroup("group") + result2 = QgsGeocoderResult( + "res 2", + QgsGeometry.fromPointXY(QgsPointXY(13, 14)), + QgsCoordinateReferenceSystem("EPSG:3857"), + ) + result2.setAdditionalAttributes({"d": 456}) result2.setViewport(QgsRectangle(1, 2, 3, 4)) return [result1, result2] @@ -72,26 +82,35 @@ def wkbType(self): def appendedFields(self): fields = QgsFields() - fields.append(QgsField('parsed', QVariant.String)) - fields.append(QgsField('accuracy', QVariant.Int)) + fields.append(QgsField("parsed", QVariant.String)) + fields.append(QgsField("accuracy", QVariant.Int)) return fields def geocodeString(self, string, context, feedback): - if string == 'a': - result = QgsGeocoderResult('res 1', QgsGeometry.fromPointXY(QgsPointXY(1, 2)), - QgsCoordinateReferenceSystem('EPSG:4326')) - result.setAdditionalAttributes({'accuracy': 123, 'parsed': 'xyz'}) + if string == "a": + result = QgsGeocoderResult( + "res 1", + QgsGeometry.fromPointXY(QgsPointXY(1, 2)), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + result.setAdditionalAttributes({"accuracy": 123, "parsed": "xyz"}) return [result] - if string == 'b': - result1 = QgsGeocoderResult('res 1', QgsGeometry.fromPointXY(QgsPointXY(11, 12)), - QgsCoordinateReferenceSystem('EPSG:4326')) - result1.setAdditionalAttributes({'accuracy': 456, 'parsed': 'xyz2'}) - result1.setDescription('desc') - result1.setGroup('group') - result2 = QgsGeocoderResult('res 2', QgsGeometry.fromPointXY(QgsPointXY(13, 14)), - QgsCoordinateReferenceSystem('EPSG:3857')) - result2.setAdditionalAttributes({'d': 456}) + if string == "b": + result1 = QgsGeocoderResult( + "res 1", + QgsGeometry.fromPointXY(QgsPointXY(11, 12)), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + result1.setAdditionalAttributes({"accuracy": 456, "parsed": "xyz2"}) + result1.setDescription("desc") + result1.setGroup("group") + result2 = QgsGeocoderResult( + "res 2", + QgsGeometry.fromPointXY(QgsPointXY(13, 14)), + QgsCoordinateReferenceSystem("EPSG:3857"), + ) + result2.setAdditionalAttributes({"d": 456}) result2.setViewport(QgsRectangle(1, 2, 3, 4)) return [result1, result2] @@ -123,22 +142,24 @@ def test_algorithm(self): alg.initParameters() fields = QgsFields() - fields.append(QgsField('some_pk', QVariant.Int)) - fields.append(QgsField('address', QVariant.String)) + fields.append(QgsField("some_pk", QVariant.Int)) + fields.append(QgsField("address", QVariant.String)) f = QgsFeature(fields) f.initAttributes(2) - f['some_pk'] = 17 + f["some_pk"] = 17 - params = {'FIELD': 'address'} + params = {"FIELD": "address"} context = QgsProcessingContext() feedback = QgsProcessingFeedback() self.assertTrue(alg.prepareAlgorithm(params, context, feedback)) output_fields = alg.outputFields(fields) - self.assertEqual([f.name() for f in output_fields], ['some_pk', 'address']) - self.assertEqual([f.type() for f in output_fields], [QVariant.Int, QVariant.String]) + self.assertEqual([f.name() for f in output_fields], ["some_pk", "address"]) + self.assertEqual( + [f.type() for f in output_fields], [QVariant.Int, QVariant.String] + ) # empty field res = alg.processFeature(f, context, feedback) @@ -147,23 +168,23 @@ def test_algorithm(self): self.assertEqual(res[0].attributes(), [17, NULL]) # no result - f['address'] = 'c' + f["address"] = "c" res = alg.processFeature(f, context, feedback) self.assertEqual(len(res), 1) self.assertTrue(res[0].geometry().isNull()) - self.assertEqual(res[0].attributes(), [17, 'c']) + self.assertEqual(res[0].attributes(), [17, "c"]) - f['address'] = 'a' + f["address"] = "a" res = alg.processFeature(f, context, feedback) self.assertEqual(len(res), 1) - self.assertEqual(res[0].geometry().asWkt(), 'Point (1 2)') - self.assertEqual(res[0].attributes(), [17, 'a']) + self.assertEqual(res[0].geometry().asWkt(), "Point (1 2)") + self.assertEqual(res[0].attributes(), [17, "a"]) - f['address'] = 'b' + f["address"] = "b" res = alg.processFeature(f, context, feedback) self.assertEqual(len(res), 1) - self.assertEqual(res[0].geometry().asWkt(), 'Point (11 12)') - self.assertEqual(res[0].attributes(), [17, 'b']) + self.assertEqual(res[0].geometry().asWkt(), "Point (11 12)") + self.assertEqual(res[0].attributes(), [17, "b"]) def testAppendedFields(self): geocoder = TestGeocoderExtraFields() @@ -172,18 +193,24 @@ def testAppendedFields(self): alg.initParameters() fields = QgsFields() - fields.append(QgsField('some_pk', QVariant.Int)) - fields.append(QgsField('address', QVariant.String)) + fields.append(QgsField("some_pk", QVariant.Int)) + fields.append(QgsField("address", QVariant.String)) output_fields = alg.outputFields(fields) - self.assertEqual([f.name() for f in output_fields], ['some_pk', 'address', 'parsed', 'accuracy']) - self.assertEqual([f.type() for f in output_fields], [QVariant.Int, QVariant.String, QVariant.String, QVariant.Int]) + self.assertEqual( + [f.name() for f in output_fields], + ["some_pk", "address", "parsed", "accuracy"], + ) + self.assertEqual( + [f.type() for f in output_fields], + [QVariant.Int, QVariant.String, QVariant.String, QVariant.Int], + ) f = QgsFeature(fields) f.initAttributes(2) - f['some_pk'] = 17 + f["some_pk"] = 17 - params = {'FIELD': 'address'} + params = {"FIELD": "address"} context = QgsProcessingContext() feedback = QgsProcessingFeedback() @@ -196,47 +223,52 @@ def testAppendedFields(self): self.assertEqual(res[0].attributes(), [17, NULL, NULL, NULL]) # no result - f['address'] = 'c' + f["address"] = "c" res = alg.processFeature(f, context, feedback) self.assertEqual(len(res), 1) self.assertTrue(res[0].geometry().isNull()) - self.assertEqual(res[0].attributes(), [17, 'c', NULL, NULL]) + self.assertEqual(res[0].attributes(), [17, "c", NULL, NULL]) - f['address'] = 'a' + f["address"] = "a" res = alg.processFeature(f, context, feedback) self.assertEqual(len(res), 1) - self.assertEqual(res[0].geometry().asWkt(), 'Point (1 2)') - self.assertEqual(res[0].attributes(), [17, 'a', 'xyz', 123]) + self.assertEqual(res[0].geometry().asWkt(), "Point (1 2)") + self.assertEqual(res[0].attributes(), [17, "a", "xyz", 123]) - f['address'] = 'b' + f["address"] = "b" res = alg.processFeature(f, context, feedback) self.assertEqual(len(res), 1) - self.assertEqual(res[0].geometry().asWkt(), 'Point (11 12)') - self.assertEqual(res[0].attributes(), [17, 'b', 'xyz2', 456]) + self.assertEqual(res[0].geometry().asWkt(), "Point (11 12)") + self.assertEqual(res[0].attributes(), [17, "b", "xyz2", 456]) def testInPlace(self): geocoder = TestGeocoderExtraFields() alg = TestGeocoderAlgorithm(geocoder) - alg.initParameters({'IN_PLACE': True}) + alg.initParameters({"IN_PLACE": True}) fields = QgsFields() - fields.append(QgsField('some_pk', QVariant.Int)) - fields.append(QgsField('address', QVariant.String)) - fields.append(QgsField('parsedx', QVariant.String)) - fields.append(QgsField('accuracyx', QVariant.Int)) + fields.append(QgsField("some_pk", QVariant.Int)) + fields.append(QgsField("address", QVariant.String)) + fields.append(QgsField("parsedx", QVariant.String)) + fields.append(QgsField("accuracyx", QVariant.Int)) output_fields = alg.outputFields(fields) - self.assertEqual([f.name() for f in output_fields], ['some_pk', 'address', 'parsedx', 'accuracyx']) - self.assertEqual([f.type() for f in output_fields], - [QVariant.Int, QVariant.String, QVariant.String, QVariant.Int]) + self.assertEqual( + [f.name() for f in output_fields], + ["some_pk", "address", "parsedx", "accuracyx"], + ) + self.assertEqual( + [f.type() for f in output_fields], + [QVariant.Int, QVariant.String, QVariant.String, QVariant.Int], + ) f = QgsFeature(fields) f.initAttributes(4) - f['some_pk'] = 17 + f["some_pk"] = 17 # not storing additional attributes - params = {'FIELD': 'address'} + params = {"FIELD": "address"} context = QgsProcessingContext() feedback = QgsProcessingFeedback() @@ -248,17 +280,17 @@ def testInPlace(self): self.assertTrue(res[0].geometry().isNull()) self.assertEqual(res[0].attributes(), [17, NULL, NULL, NULL]) - f['address'] = 'a' + f["address"] = "a" res = alg.processFeature(f, context, feedback) self.assertEqual(len(res), 1) - self.assertEqual(res[0].geometry().asWkt(), 'Point (1 2)') - self.assertEqual(res[0].attributes(), [17, 'a', None, None]) + self.assertEqual(res[0].geometry().asWkt(), "Point (1 2)") + self.assertEqual(res[0].attributes(), [17, "a", None, None]) f.clearGeometry() - f['address'] = NULL + f["address"] = NULL # storing additional attributes - params = {'FIELD': 'address', 'parsed': 'parsedx', 'accuracy': 'accuracyx'} + params = {"FIELD": "address", "parsed": "parsedx", "accuracy": "accuracyx"} context = QgsProcessingContext() feedback = QgsProcessingFeedback() @@ -270,12 +302,12 @@ def testInPlace(self): self.assertTrue(res[0].geometry().isNull()) self.assertEqual(res[0].attributes(), [17, NULL, NULL, NULL]) - f['address'] = 'b' + f["address"] = "b" res = alg.processFeature(f, context, feedback) self.assertEqual(len(res), 1) - self.assertEqual(res[0].geometry().asWkt(), 'Point (11 12)') - self.assertEqual(res[0].attributes(), [17, 'b', 'xyz2', 456]) + self.assertEqual(res[0].geometry().asWkt(), "Point (11 12)") + self.assertEqual(res[0].attributes(), [17, "b", "xyz2", 456]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsgeocoderlocatorfilter.py b/tests/src/python/test_qgsgeocoderlocatorfilter.py index 762b77043c95..db55a2571f16 100644 --- a/tests/src/python/test_qgsgeocoderlocatorfilter.py +++ b/tests/src/python/test_qgsgeocoderlocatorfilter.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '02/11/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "02/11/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy from qgis.core import ( @@ -37,21 +38,30 @@ def wkbType(self): return QgsWkbTypes.Type.Point def geocodeString(self, string, context, feedback): - if string == 'a': - result = QgsGeocoderResult('res 1', QgsGeometry.fromPointXY(QgsPointXY(1, 2)), - QgsCoordinateReferenceSystem('EPSG:4326')) - result.setAdditionalAttributes({'b': 123, 'c': 'xyz'}) + if string == "a": + result = QgsGeocoderResult( + "res 1", + QgsGeometry.fromPointXY(QgsPointXY(1, 2)), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + result.setAdditionalAttributes({"b": 123, "c": "xyz"}) return [result] - if string == 'b': - result1 = QgsGeocoderResult('res 1', QgsGeometry.fromPointXY(QgsPointXY(11, 12)), - QgsCoordinateReferenceSystem('EPSG:4326')) - result1.setAdditionalAttributes({'b': 123, 'c': 'xyz'}) - result1.setDescription('desc') - result1.setGroup('group') - result2 = QgsGeocoderResult('res 2', QgsGeometry.fromPointXY(QgsPointXY(13, 14)), - QgsCoordinateReferenceSystem('EPSG:3857')) - result2.setAdditionalAttributes({'d': 456}) + if string == "b": + result1 = QgsGeocoderResult( + "res 1", + QgsGeometry.fromPointXY(QgsPointXY(11, 12)), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + result1.setAdditionalAttributes({"b": 123, "c": "xyz"}) + result1.setDescription("desc") + result1.setGroup("group") + result2 = QgsGeocoderResult( + "res 2", + QgsGeometry.fromPointXY(QgsPointXY(13, 14)), + QgsCoordinateReferenceSystem("EPSG:3857"), + ) + result2.setAdditionalAttributes({"d": 456}) result2.setViewport(QgsRectangle(1, 2, 3, 4)) return [result1, result2] @@ -63,11 +73,18 @@ class TestQgsGeocoderLocatorFilter(QgisTestCase): def test_geocode(self): geocoder = TestGeocoder() canvas = QgsMapCanvas() - filter = QgsGeocoderLocatorFilter('testgeocoder', 'my geocoder', 'pref', geocoder, canvas, QgsRectangle(-1, -1, 1, 1)) - - self.assertEqual(filter.name(), 'testgeocoder') - self.assertEqual(filter.displayName(), 'my geocoder') - self.assertEqual(filter.prefix(), 'pref') + filter = QgsGeocoderLocatorFilter( + "testgeocoder", + "my geocoder", + "pref", + geocoder, + canvas, + QgsRectangle(-1, -1, 1, 1), + ) + + self.assertEqual(filter.name(), "testgeocoder") + self.assertEqual(filter.displayName(), "my geocoder") + self.assertEqual(filter.prefix(), "pref") self.assertEqual(filter.geocoder(), geocoder) self.assertEqual(filter.boundingBox(), QgsRectangle(-1, -1, 1, 1)) @@ -77,49 +94,49 @@ def test_geocode(self): feedback = QgsFeedback() # no results - filter.fetchResults('cvxbcvb', context, feedback) + filter.fetchResults("cvxbcvb", context, feedback) self.assertEqual(len(spy), 0) # one result - filter.fetchResults('a', context, feedback) + filter.fetchResults("a", context, feedback) self.assertEqual(len(spy), 1) res = spy[-1][0] - self.assertEqual(res.displayString, 'res 1') + self.assertEqual(res.displayString, "res 1") # some sip weirdness here -- if we directly access the QgsLocatorResult object here then we get segfaults! # so instead convert back to QgsGeocoderResult. This makes the test more robust anyway... geocode_result = filter.locatorResultToGeocoderResult(res) - self.assertEqual(geocode_result.identifier(), 'res 1') - self.assertEqual(geocode_result.geometry().asWkt(), 'Point (1 2)') - self.assertEqual(geocode_result.crs().authid(), 'EPSG:4326') - self.assertEqual(geocode_result.additionalAttributes(), {'b': 123, 'c': 'xyz'}) + self.assertEqual(geocode_result.identifier(), "res 1") + self.assertEqual(geocode_result.geometry().asWkt(), "Point (1 2)") + self.assertEqual(geocode_result.crs().authid(), "EPSG:4326") + self.assertEqual(geocode_result.additionalAttributes(), {"b": 123, "c": "xyz"}) self.assertTrue(geocode_result.viewport().isNull()) self.assertFalse(geocode_result.description()) self.assertFalse(geocode_result.group()) # two possible results - filter.fetchResults('b', context, feedback) + filter.fetchResults("b", context, feedback) self.assertEqual(len(spy), 3) res1 = spy[-2][0] res2 = spy[-1][0] - self.assertEqual(res1.displayString, 'res 1') + self.assertEqual(res1.displayString, "res 1") geocode_result = filter.locatorResultToGeocoderResult(res1) - self.assertEqual(geocode_result.identifier(), 'res 1') - self.assertEqual(geocode_result.geometry().asWkt(), 'Point (11 12)') - self.assertEqual(geocode_result.crs().authid(), 'EPSG:4326') - self.assertEqual(geocode_result.additionalAttributes(), {'b': 123, 'c': 'xyz'}) + self.assertEqual(geocode_result.identifier(), "res 1") + self.assertEqual(geocode_result.geometry().asWkt(), "Point (11 12)") + self.assertEqual(geocode_result.crs().authid(), "EPSG:4326") + self.assertEqual(geocode_result.additionalAttributes(), {"b": 123, "c": "xyz"}) self.assertTrue(geocode_result.viewport().isNull()) - self.assertEqual(geocode_result.description(), 'desc') - self.assertEqual(geocode_result.group(), 'group') - self.assertEqual(res2.displayString, 'res 2') + self.assertEqual(geocode_result.description(), "desc") + self.assertEqual(geocode_result.group(), "group") + self.assertEqual(res2.displayString, "res 2") geocode_result = filter.locatorResultToGeocoderResult(res2) - self.assertEqual(geocode_result.identifier(), 'res 2') - self.assertEqual(geocode_result.geometry().asWkt(), 'Point (13 14)') - self.assertEqual(geocode_result.crs().authid(), 'EPSG:3857') - self.assertEqual(geocode_result.additionalAttributes(), {'d': 456}) + self.assertEqual(geocode_result.identifier(), "res 2") + self.assertEqual(geocode_result.geometry().asWkt(), "Point (13 14)") + self.assertEqual(geocode_result.crs().authid(), "EPSG:3857") + self.assertEqual(geocode_result.additionalAttributes(), {"d": 456}) self.assertEqual(geocode_result.viewport(), QgsRectangle(1, 2, 3, 4)) self.assertFalse(geocode_result.description()) self.assertFalse(geocode_result.group()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsgeometry.py b/tests/src/python/test_qgsgeometry.py index fefb6cbcf0a0..a398ba4246c4 100644 --- a/tests/src/python/test_qgsgeometry.py +++ b/tests/src/python/test_qgsgeometry.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Tim Sutton' -__date__ = '20/08/2012' -__copyright__ = 'Copyright 2012, The QGIS Project' + +__author__ = "Tim Sutton" +__date__ = "20/08/2012" +__copyright__ = "Copyright 2012, The QGIS Project" import csv import math @@ -75,10 +76,10 @@ def setUp(self): self.geos312 = 31200 def testBool(self): - """ Test boolean evaluation of QgsGeometry """ + """Test boolean evaluation of QgsGeometry""" g = QgsGeometry() self.assertFalse(g) - myWKT = 'Point (10 10)' + myWKT = "Point (10 10)" g = QgsGeometry.fromWkt(myWKT) self.assertTrue(g) g = QgsGeometry(None) @@ -91,13 +92,13 @@ def testIsEmpty(self): """ g = QgsGeometry() self.assertTrue(g.isEmpty()) - g = QgsGeometry.fromWkt('Point(10 10 )') + g = QgsGeometry.fromWkt("Point(10 10 )") self.assertFalse(g.isEmpty()) - g = QgsGeometry.fromWkt('MultiPoint ()') + g = QgsGeometry.fromWkt("MultiPoint ()") self.assertTrue(g.isEmpty()) def testVertexIterator(self): - g = QgsGeometry.fromWkt('Linestring(11 12, 13 14)') + g = QgsGeometry.fromWkt("Linestring(11 12, 13 14)") it = g.vertices() self.assertEqual(next(it), QgsPoint(11, 12)) self.assertEqual(next(it), QgsPoint(13, 14)) @@ -113,109 +114,121 @@ def testPartIterator(self): next(it) # single point geometry - g = QgsGeometry.fromWkt('Point (10 10)') + g = QgsGeometry.fromWkt("Point (10 10)") it = g.parts() - self.assertEqual(next(it).asWkt(), 'Point (10 10)') + self.assertEqual(next(it).asWkt(), "Point (10 10)") with self.assertRaises(StopIteration): next(it) it = g.get().parts() - self.assertEqual(next(it).asWkt(), 'Point (10 10)') + self.assertEqual(next(it).asWkt(), "Point (10 10)") with self.assertRaises(StopIteration): next(it) # multi point geometry - g = QgsGeometry.fromWkt('MultiPoint (10 10, 20 20, 10 20)') + g = QgsGeometry.fromWkt("MultiPoint (10 10, 20 20, 10 20)") it = g.parts() - self.assertEqual(next(it).asWkt(), 'Point (10 10)') - self.assertEqual(next(it).asWkt(), 'Point (20 20)') - self.assertEqual(next(it).asWkt(), 'Point (10 20)') + self.assertEqual(next(it).asWkt(), "Point (10 10)") + self.assertEqual(next(it).asWkt(), "Point (20 20)") + self.assertEqual(next(it).asWkt(), "Point (10 20)") with self.assertRaises(StopIteration): next(it) it = g.get().parts() - self.assertEqual(next(it).asWkt(), 'Point (10 10)') - self.assertEqual(next(it).asWkt(), 'Point (20 20)') - self.assertEqual(next(it).asWkt(), 'Point (10 20)') + self.assertEqual(next(it).asWkt(), "Point (10 10)") + self.assertEqual(next(it).asWkt(), "Point (20 20)") + self.assertEqual(next(it).asWkt(), "Point (10 20)") with self.assertRaises(StopIteration): next(it) # empty multi point geometry - g = QgsGeometry.fromWkt('MultiPoint ()') + g = QgsGeometry.fromWkt("MultiPoint ()") it = g.parts() with self.assertRaises(StopIteration): next(it) # single line geometry - g = QgsGeometry.fromWkt('LineString (10 10, 20 10, 30 10)') + g = QgsGeometry.fromWkt("LineString (10 10, 20 10, 30 10)") it = g.parts() - self.assertEqual(next(it).asWkt(), 'LineString (10 10, 20 10, 30 10)') + self.assertEqual(next(it).asWkt(), "LineString (10 10, 20 10, 30 10)") with self.assertRaises(StopIteration): next(it) # multi line geometry - g = QgsGeometry.fromWkt('MultiLineString ((10 10, 20 20, 10 20),(5 7, 8 9))') + g = QgsGeometry.fromWkt("MultiLineString ((10 10, 20 20, 10 20),(5 7, 8 9))") it = g.parts() - self.assertEqual(next(it).asWkt(), 'LineString (10 10, 20 20, 10 20)') - self.assertEqual(next(it).asWkt(), 'LineString (5 7, 8 9)') + self.assertEqual(next(it).asWkt(), "LineString (10 10, 20 20, 10 20)") + self.assertEqual(next(it).asWkt(), "LineString (5 7, 8 9)") with self.assertRaises(StopIteration): next(it) # empty multi line geometry - g = QgsGeometry.fromWkt('MultiLineString ()') + g = QgsGeometry.fromWkt("MultiLineString ()") it = g.parts() with self.assertRaises(StopIteration): next(it) # single polygon geometry - g = QgsGeometry.fromWkt('Polygon ((10 10, 100 10, 100 100, 10 100, 10 10),(50 50, 55 50, 55 55, 50 55, 50 50))') + g = QgsGeometry.fromWkt( + "Polygon ((10 10, 100 10, 100 100, 10 100, 10 10),(50 50, 55 50, 55 55, 50 55, 50 50))" + ) it = g.parts() - self.assertEqual(next(it).asWkt(), - 'Polygon ((10 10, 100 10, 100 100, 10 100, 10 10),(50 50, 55 50, 55 55, 50 55, 50 50))') + self.assertEqual( + next(it).asWkt(), + "Polygon ((10 10, 100 10, 100 100, 10 100, 10 10),(50 50, 55 50, 55 55, 50 55, 50 50))", + ) with self.assertRaises(StopIteration): next(it) # multi polygon geometry g = QgsGeometry.fromWkt( - 'MultiPolygon (((10 10, 100 10, 100 100, 10 100, 10 10),(50 50, 55 50, 55 55, 50 55, 50 50)),((20 2, 20 4, 22 4, 22 2, 20 2)))') + "MultiPolygon (((10 10, 100 10, 100 100, 10 100, 10 10),(50 50, 55 50, 55 55, 50 55, 50 50)),((20 2, 20 4, 22 4, 22 2, 20 2)))" + ) it = g.parts() - self.assertEqual(next(it).asWkt(), - 'Polygon ((10 10, 100 10, 100 100, 10 100, 10 10),(50 50, 55 50, 55 55, 50 55, 50 50))') - self.assertEqual(next(it).asWkt(), 'Polygon ((20 2, 20 4, 22 4, 22 2, 20 2))') + self.assertEqual( + next(it).asWkt(), + "Polygon ((10 10, 100 10, 100 100, 10 100, 10 10),(50 50, 55 50, 55 55, 50 55, 50 50))", + ) + self.assertEqual(next(it).asWkt(), "Polygon ((20 2, 20 4, 22 4, 22 2, 20 2))") with self.assertRaises(StopIteration): next(it) # empty multi polygon geometry - g = QgsGeometry.fromWkt('MultiPolygon ()') + g = QgsGeometry.fromWkt("MultiPolygon ()") it = g.parts() with self.assertRaises(StopIteration): next(it) # geometry collection - g = QgsGeometry.fromWkt('GeometryCollection( Point( 1 2), LineString( 4 5, 8 7 ))') + g = QgsGeometry.fromWkt( + "GeometryCollection( Point( 1 2), LineString( 4 5, 8 7 ))" + ) it = g.parts() - self.assertEqual(next(it).asWkt(), 'Point (1 2)') - self.assertEqual(next(it).asWkt(), 'LineString (4 5, 8 7)') + self.assertEqual(next(it).asWkt(), "Point (1 2)") + self.assertEqual(next(it).asWkt(), "LineString (4 5, 8 7)") with self.assertRaises(StopIteration): next(it) # empty geometry collection - g = QgsGeometry.fromWkt('GeometryCollection()') + g = QgsGeometry.fromWkt("GeometryCollection()") it = g.parts() with self.assertRaises(StopIteration): next(it) def testWktPointLoading(self): - myWKT = 'Point (10 10)' + myWKT = "Point (10 10)" myGeometry = QgsGeometry.fromWkt(myWKT) self.assertEqual(myGeometry.wkbType(), QgsWkbTypes.Type.Point) def testWktMultiPointLoading(self): # Standard format - wkt = 'MultiPoint ((10 15),(20 30))' + wkt = "MultiPoint ((10 15),(20 30))" geom = QgsGeometry.fromWkt(wkt) - self.assertEqual(geom.wkbType(), QgsWkbTypes.Type.MultiPoint, - (f'Expected:\n{QgsWkbTypes.Type.Point}\nGot:\n{geom.type()}\n')) + self.assertEqual( + geom.wkbType(), + QgsWkbTypes.Type.MultiPoint, + (f"Expected:\n{QgsWkbTypes.Type.Point}\nGot:\n{geom.type()}\n"), + ) self.assertEqual(geom.constGet().numGeometries(), 2) self.assertEqual(geom.constGet().geometryN(0).x(), 10) self.assertEqual(geom.constGet().geometryN(0).y(), 15) @@ -223,10 +236,13 @@ def testWktMultiPointLoading(self): self.assertEqual(geom.constGet().geometryN(1).y(), 30) # Check MS SQL format - wkt = 'MultiPoint (11 16, 21 31)' + wkt = "MultiPoint (11 16, 21 31)" geom = QgsGeometry.fromWkt(wkt) - self.assertEqual(geom.wkbType(), QgsWkbTypes.Type.MultiPoint, - (f'Expected:\n{QgsWkbTypes.Type.Point}\nGot:\n{geom.type()}\n')) + self.assertEqual( + geom.wkbType(), + QgsWkbTypes.Type.MultiPoint, + (f"Expected:\n{QgsWkbTypes.Type.Point}\nGot:\n{geom.type()}\n"), + ) self.assertEqual(geom.constGet().numGeometries(), 2) self.assertEqual(geom.constGet().geometryN(0).x(), 11) self.assertEqual(geom.constGet().geometryN(0).y(), 16) @@ -245,8 +261,9 @@ def testFromPoint(self): self.assertEqual(myPoint.constGet().z(), 5) def testFromMultiPoint(self): - myMultiPoint = QgsGeometry.fromMultiPointXY([ - (QgsPointXY(0, 0)), (QgsPointXY(1, 1))]) + myMultiPoint = QgsGeometry.fromMultiPointXY( + [(QgsPointXY(0, 0)), (QgsPointXY(1, 1))] + ) self.assertEqual(myMultiPoint.wkbType(), QgsWkbTypes.Type.MultiPoint) def testFromLine(self): @@ -255,30 +272,45 @@ def testFromLine(self): def testFromMultiLine(self): myMultiPolyline = QgsGeometry.fromMultiPolylineXY( - [[QgsPointXY(0, 0), QgsPointXY(1, 1)], [QgsPointXY(0, 1), QgsPointXY(2, 1)]]) + [[QgsPointXY(0, 0), QgsPointXY(1, 1)], [QgsPointXY(0, 1), QgsPointXY(2, 1)]] + ) self.assertEqual(myMultiPolyline.wkbType(), QgsWkbTypes.Type.MultiLineString) def testFromPolygon(self): myPolygon = QgsGeometry.fromPolygonXY( - [[QgsPointXY(1, 1), QgsPointXY(2, 2), QgsPointXY(1, 2), QgsPointXY(1, 1)]]) + [[QgsPointXY(1, 1), QgsPointXY(2, 2), QgsPointXY(1, 2), QgsPointXY(1, 1)]] + ) self.assertEqual(myPolygon.wkbType(), QgsWkbTypes.Type.Polygon) def testFromMultiPolygon(self): - myMultiPolygon = QgsGeometry.fromMultiPolygonXY([ - [[QgsPointXY(1, 1), - QgsPointXY(2, 2), - QgsPointXY(1, 2), - QgsPointXY(1, 1)]], - [[QgsPointXY(2, 2), - QgsPointXY(3, 3), - QgsPointXY(3, 1), - QgsPointXY(2, 2)]] - ]) + myMultiPolygon = QgsGeometry.fromMultiPolygonXY( + [ + [ + [ + QgsPointXY(1, 1), + QgsPointXY(2, 2), + QgsPointXY(1, 2), + QgsPointXY(1, 1), + ] + ], + [ + [ + QgsPointXY(2, 2), + QgsPointXY(3, 3), + QgsPointXY(3, 1), + QgsPointXY(2, 2), + ] + ], + ] + ) self.assertEqual(myMultiPolygon.wkbType(), QgsWkbTypes.Type.MultiPolygon) def testFromBox3D(self): myBox3D = QgsGeometry.fromBox3D(QgsBox3D(1, 2, 3, 4, 5, 6)) - self.assertEqual(myBox3D.asWkt(), "PolyhedralSurface Z (((1 2 3, 1 5 3, 4 5 3, 4 2 3, 1 2 3)),((1 2 3, 1 5 3, 1 5 6, 1 2 6, 1 2 3)),((1 2 3, 4 2 3, 4 2 6, 1 2 6, 1 2 3)),((4 5 6, 4 2 6, 1 2 6, 1 5 6, 4 5 6)),((4 5 6, 4 2 6, 4 2 3, 4 5 3, 4 5 6)),((4 5 6, 4 5 3, 1 5 3, 1 5 6, 4 5 6)))") + self.assertEqual( + myBox3D.asWkt(), + "PolyhedralSurface Z (((1 2 3, 1 5 3, 4 5 3, 4 2 3, 1 2 3)),((1 2 3, 1 5 3, 1 5 6, 1 2 6, 1 2 3)),((1 2 3, 4 2 3, 4 2 6, 1 2 6, 1 2 3)),((4 5 6, 4 2 6, 1 2 6, 1 5 6, 4 5 6)),((4 5 6, 4 2 6, 4 2 3, 4 5 3, 4 5 6)),((4 5 6, 4 5 3, 1 5 3, 1 5 6, 4 5 6)))", + ) def testLineStringPythonAdditions(self): """ @@ -463,11 +495,11 @@ def testQgsLineStringPythonConstructors(self): Test various constructors for QgsLineString in Python """ line = QgsLineString() - self.assertEqual(line.asWkt(), 'LineString EMPTY') + self.assertEqual(line.asWkt(), "LineString EMPTY") # empty array line = QgsLineString([]) - self.assertEqual(line.asWkt(), 'LineString EMPTY') + self.assertEqual(line.asWkt(), "LineString EMPTY") # invalid array with self.assertRaises(TypeError): @@ -475,35 +507,51 @@ def testQgsLineStringPythonConstructors(self): # array of QgsPoint line = QgsLineString([QgsPoint(1, 2), QgsPoint(3, 4), QgsPoint(11, 12)]) - self.assertEqual(line.asWkt(), 'LineString (1 2, 3 4, 11 12)') + self.assertEqual(line.asWkt(), "LineString (1 2, 3 4, 11 12)") # array of QgsPoint with Z - line = QgsLineString([QgsPoint(1, 2, 11), QgsPoint(3, 4, 13), QgsPoint(11, 12, 14)]) - self.assertEqual(line.asWkt(), 'LineString Z (1 2 11, 3 4 13, 11 12 14)') + line = QgsLineString( + [QgsPoint(1, 2, 11), QgsPoint(3, 4, 13), QgsPoint(11, 12, 14)] + ) + self.assertEqual(line.asWkt(), "LineString Z (1 2 11, 3 4 13, 11 12 14)") # array of QgsPoint with Z, only first has z line = QgsLineString([QgsPoint(1, 2, 11), QgsPoint(3, 4), QgsPoint(11, 12)]) - self.assertEqual(line.asWkt(), 'LineString Z (1 2 11, 3 4 nan, 11 12 nan)') + self.assertEqual(line.asWkt(), "LineString Z (1 2 11, 3 4 nan, 11 12 nan)") # array of QgsPoint with M - line = QgsLineString([QgsPoint(1, 2, None, 11), QgsPoint(3, 4, None, 13), QgsPoint(11, 12, None, 14)]) - self.assertEqual(line.asWkt(), 'LineString M (1 2 11, 3 4 13, 11 12 14)') + line = QgsLineString( + [ + QgsPoint(1, 2, None, 11), + QgsPoint(3, 4, None, 13), + QgsPoint(11, 12, None, 14), + ] + ) + self.assertEqual(line.asWkt(), "LineString M (1 2 11, 3 4 13, 11 12 14)") # array of QgsPoint with M, only first has M - line = QgsLineString([QgsPoint(1, 2, None, 11), QgsPoint(3, 4), QgsPoint(11, 12)]) - self.assertEqual(line.asWkt(), 'LineString M (1 2 11, 3 4 nan, 11 12 nan)') + line = QgsLineString( + [QgsPoint(1, 2, None, 11), QgsPoint(3, 4), QgsPoint(11, 12)] + ) + self.assertEqual(line.asWkt(), "LineString M (1 2 11, 3 4 nan, 11 12 nan)") # array of QgsPoint with ZM - line = QgsLineString([QgsPoint(1, 2, 22, 11), QgsPoint(3, 4, 23, 13), QgsPoint(11, 12, 24, 14)]) - self.assertEqual(line.asWkt(), 'LineString ZM (1 2 22 11, 3 4 23 13, 11 12 24 14)') + line = QgsLineString( + [QgsPoint(1, 2, 22, 11), QgsPoint(3, 4, 23, 13), QgsPoint(11, 12, 24, 14)] + ) + self.assertEqual( + line.asWkt(), "LineString ZM (1 2 22 11, 3 4 23 13, 11 12 24 14)" + ) # array of QgsPoint with ZM, only first has ZM line = QgsLineString([QgsPoint(1, 2, 33, 11), QgsPoint(3, 4), QgsPoint(11, 12)]) - self.assertEqual(line.asWkt(), 'LineString ZM (1 2 33 11, 3 4 nan nan, 11 12 nan nan)') + self.assertEqual( + line.asWkt(), "LineString ZM (1 2 33 11, 3 4 nan nan, 11 12 nan nan)" + ) # array of QgsPointXY line = QgsLineString([QgsPointXY(1, 2), QgsPointXY(3, 4), QgsPointXY(11, 12)]) - self.assertEqual(line.asWkt(), 'LineString (1 2, 3 4, 11 12)') + self.assertEqual(line.asWkt(), "LineString (1 2, 3 4, 11 12)") # array of array of bad values with self.assertRaises(TypeError): @@ -518,50 +566,56 @@ def testQgsLineStringPythonConstructors(self): # array of array of floats line = QgsLineString([[1, 2], [3, 4], [5, 6]]) - self.assertEqual(line.asWkt(), 'LineString (1 2, 3 4, 5 6)') + self.assertEqual(line.asWkt(), "LineString (1 2, 3 4, 5 6)") # tuple of tuple of floats line = QgsLineString(((1, 2), (3, 4), (5, 6))) - self.assertEqual(line.asWkt(), 'LineString (1 2, 3 4, 5 6)') + self.assertEqual(line.asWkt(), "LineString (1 2, 3 4, 5 6)") # sequence line = QgsLineString([[c + 10, c + 11] for c in range(5)]) - self.assertEqual(line.asWkt(), 'LineString (10 11, 11 12, 12 13, 13 14, 14 15)') + self.assertEqual(line.asWkt(), "LineString (10 11, 11 12, 12 13, 13 14, 14 15)") # array of array of 3d floats line = QgsLineString([[1, 2, 11], [3, 4, 12], [5, 6, 13]]) - self.assertEqual(line.asWkt(), 'LineString Z (1 2 11, 3 4 12, 5 6 13)') + self.assertEqual(line.asWkt(), "LineString Z (1 2 11, 3 4 12, 5 6 13)") # array of array of inconsistent 3d floats line = QgsLineString([[1, 2, 11], [3, 4], [5, 6]]) - self.assertEqual(line.asWkt(), 'LineString Z (1 2 11, 3 4 nan, 5 6 nan)') + self.assertEqual(line.asWkt(), "LineString Z (1 2 11, 3 4 nan, 5 6 nan)") # array of array of 4d floats line = QgsLineString([[1, 2, 11, 21], [3, 4, 12, 22], [5, 6, 13, 23]]) - self.assertEqual(line.asWkt(), 'LineString ZM (1 2 11 21, 3 4 12 22, 5 6 13 23)') + self.assertEqual( + line.asWkt(), "LineString ZM (1 2 11 21, 3 4 12 22, 5 6 13 23)" + ) # array of array of inconsistent 4d floats line = QgsLineString([[1, 2, 11, 21], [3, 4, 12], [5, 6]]) - self.assertEqual(line.asWkt(), 'LineString ZM (1 2 11 21, 3 4 12 nan, 5 6 nan nan)') + self.assertEqual( + line.asWkt(), "LineString ZM (1 2 11 21, 3 4 12 nan, 5 6 nan nan)" + ) # array of array of 5 floats with self.assertRaises(TypeError): - line = QgsLineString([[1, 2, 11, 21, 22], [3, 4, 12, 22, 23], [5, 6, 13, 23, 24]]) + line = QgsLineString( + [[1, 2, 11, 21, 22], [3, 4, 12, 22, 23], [5, 6, 13, 23, 24]] + ) # mixed array, because hey, why not?? :D line = QgsLineString([QgsPoint(1, 2), QgsPointXY(3, 4), [5, 6], (7, 8)]) - self.assertEqual(line.asWkt(), 'LineString (1 2, 3 4, 5 6, 7 8)') + self.assertEqual(line.asWkt(), "LineString (1 2, 3 4, 5 6, 7 8)") def testQgsMultiPointPythonConstructors(self): """ Test various constructors for QgsMultiPoint in Python """ point = QgsMultiPoint() - self.assertEqual(point.asWkt(), 'MultiPoint EMPTY') + self.assertEqual(point.asWkt(), "MultiPoint EMPTY") # empty array point = QgsMultiPoint([]) - self.assertEqual(point.asWkt(), 'MultiPoint EMPTY') + self.assertEqual(point.asWkt(), "MultiPoint EMPTY") # invalid array with self.assertRaises(TypeError): @@ -569,35 +623,51 @@ def testQgsMultiPointPythonConstructors(self): # array of QgsPoint point = QgsMultiPoint([QgsPoint(1, 2), QgsPoint(3, 4), QgsPoint(11, 12)]) - self.assertEqual(point.asWkt(), 'MultiPoint ((1 2),(3 4),(11 12))') + self.assertEqual(point.asWkt(), "MultiPoint ((1 2),(3 4),(11 12))") # array of QgsPoint with Z - point = QgsMultiPoint([QgsPoint(1, 2, 11), QgsPoint(3, 4, 13), QgsPoint(11, 12, 14)]) - self.assertEqual(point.asWkt(), 'MultiPoint Z ((1 2 11),(3 4 13),(11 12 14))') + point = QgsMultiPoint( + [QgsPoint(1, 2, 11), QgsPoint(3, 4, 13), QgsPoint(11, 12, 14)] + ) + self.assertEqual(point.asWkt(), "MultiPoint Z ((1 2 11),(3 4 13),(11 12 14))") # array of QgsPoint with Z, only first has z point = QgsMultiPoint([QgsPoint(1, 2, 11), QgsPoint(3, 4), QgsPoint(11, 12)]) - self.assertEqual(point.asWkt(), 'MultiPoint Z ((1 2 11),(3 4),(11 12))') + self.assertEqual(point.asWkt(), "MultiPoint Z ((1 2 11),(3 4),(11 12))") # array of QgsPoint with M - point = QgsMultiPoint([QgsPoint(1, 2, None, 11), QgsPoint(3, 4, None, 13), QgsPoint(11, 12, None, 14)]) - self.assertEqual(point.asWkt(), 'MultiPoint M ((1 2 11),(3 4 13),(11 12 14))') + point = QgsMultiPoint( + [ + QgsPoint(1, 2, None, 11), + QgsPoint(3, 4, None, 13), + QgsPoint(11, 12, None, 14), + ] + ) + self.assertEqual(point.asWkt(), "MultiPoint M ((1 2 11),(3 4 13),(11 12 14))") # array of QgsPoint with M, only first has M - point = QgsMultiPoint([QgsPoint(1, 2, None, 11), QgsPoint(3, 4), QgsPoint(11, 12)]) - self.assertEqual(point.asWkt(), 'MultiPoint M ((1 2 11),(3 4),(11 12))') + point = QgsMultiPoint( + [QgsPoint(1, 2, None, 11), QgsPoint(3, 4), QgsPoint(11, 12)] + ) + self.assertEqual(point.asWkt(), "MultiPoint M ((1 2 11),(3 4),(11 12))") # array of QgsPoint with ZM - point = QgsMultiPoint([QgsPoint(1, 2, 22, 11), QgsPoint(3, 4, 23, 13), QgsPoint(11, 12, 24, 14)]) - self.assertEqual(point.asWkt(), 'MultiPoint ZM ((1 2 22 11),(3 4 23 13),(11 12 24 14))') + point = QgsMultiPoint( + [QgsPoint(1, 2, 22, 11), QgsPoint(3, 4, 23, 13), QgsPoint(11, 12, 24, 14)] + ) + self.assertEqual( + point.asWkt(), "MultiPoint ZM ((1 2 22 11),(3 4 23 13),(11 12 24 14))" + ) # array of QgsPoint with ZM, only first has ZM - point = QgsMultiPoint([QgsPoint(1, 2, 33, 11), QgsPoint(3, 4), QgsPoint(11, 12)]) - self.assertEqual(point.asWkt(), 'MultiPoint ZM ((1 2 33 11),(3 4),(11 12))') + point = QgsMultiPoint( + [QgsPoint(1, 2, 33, 11), QgsPoint(3, 4), QgsPoint(11, 12)] + ) + self.assertEqual(point.asWkt(), "MultiPoint ZM ((1 2 33 11),(3 4),(11 12))") # array of QgsPointXY point = QgsMultiPoint([QgsPointXY(1, 2), QgsPointXY(3, 4), QgsPointXY(11, 12)]) - self.assertEqual(point.asWkt(), 'MultiPoint ((1 2),(3 4),(11 12))') + self.assertEqual(point.asWkt(), "MultiPoint ((1 2),(3 4),(11 12))") # array of array of bad values with self.assertRaises(TypeError): @@ -612,39 +682,45 @@ def testQgsMultiPointPythonConstructors(self): # array of array of floats point = QgsMultiPoint([[1, 2], [3, 4], [5, 6]]) - self.assertEqual(point.asWkt(), 'MultiPoint ((1 2),(3 4),(5 6))') + self.assertEqual(point.asWkt(), "MultiPoint ((1 2),(3 4),(5 6))") # tuple of tuple of floats point = QgsMultiPoint(((1, 2), (3, 4), (5, 6))) - self.assertEqual(point.asWkt(), 'MultiPoint ((1 2),(3 4),(5 6))') + self.assertEqual(point.asWkt(), "MultiPoint ((1 2),(3 4),(5 6))") # sequence point = QgsMultiPoint([[c + 10, c + 11] for c in range(5)]) - self.assertEqual(point.asWkt(), 'MultiPoint ((10 11),(11 12),(12 13),(13 14),(14 15))') + self.assertEqual( + point.asWkt(), "MultiPoint ((10 11),(11 12),(12 13),(13 14),(14 15))" + ) # array of array of 3d floats point = QgsMultiPoint([[1, 2, 11], [3, 4, 12], [5, 6, 13]]) - self.assertEqual(point.asWkt(), 'MultiPoint Z ((1 2 11),(3 4 12),(5 6 13))') + self.assertEqual(point.asWkt(), "MultiPoint Z ((1 2 11),(3 4 12),(5 6 13))") # array of array of inconsistent 3d floats point = QgsMultiPoint([[1, 2, 11], [3, 4], [5, 6]]) - self.assertEqual(point.asWkt(), 'MultiPoint Z ((1 2 11),(3 4),(5 6))') + self.assertEqual(point.asWkt(), "MultiPoint Z ((1 2 11),(3 4),(5 6))") # array of array of 4d floats point = QgsMultiPoint([[1, 2, 11, 21], [3, 4, 12, 22], [5, 6, 13, 23]]) - self.assertEqual(point.asWkt(), 'MultiPoint ZM ((1 2 11 21),(3 4 12 22),(5 6 13 23))') + self.assertEqual( + point.asWkt(), "MultiPoint ZM ((1 2 11 21),(3 4 12 22),(5 6 13 23))" + ) # array of array of inconsistent 4d floats point = QgsMultiPoint([[1, 2, 11, 21], [3, 4, 12], [5, 6]]) - self.assertEqual(point.asWkt(), 'MultiPoint ZM ((1 2 11 21),(3 4 12),(5 6))') + self.assertEqual(point.asWkt(), "MultiPoint ZM ((1 2 11 21),(3 4 12),(5 6))") # array of array of 5 floats with self.assertRaises(TypeError): - point = QgsMultiPoint([[1, 2, 11, 21, 22], [3, 4, 12, 22, 23], [5, 6, 13, 23, 24]]) + point = QgsMultiPoint( + [[1, 2, 11, 21, 22], [3, 4, 12, 22, 23], [5, 6, 13, 23, 24]] + ) # mixed array, because hey, why not?? :D point = QgsMultiPoint([QgsPoint(1, 2), QgsPointXY(3, 4), [5, 6], (7, 8)]) - self.assertEqual(point.asWkt(), 'MultiPoint ((1 2),(3 4),(5 6),(7 8))') + self.assertEqual(point.asWkt(), "MultiPoint ((1 2),(3 4),(5 6),(7 8))") def testGeometryCollectionPythonAdditions(self): """ @@ -654,7 +730,7 @@ def testGeometryCollectionPythonAdditions(self): self.assertTrue(bool(g)) self.assertEqual(len(g), 0) g = QgsMultiPoint() - g.fromWkt('MultiPoint( (1 2), (11 12))') + g.fromWkt("MultiPoint( (1 2), (11 12))") self.assertTrue(bool(g)) self.assertEqual(len(g), 2) @@ -676,7 +752,7 @@ def testGeometryCollectionPythonAdditions(self): # removeGeometry g = QgsGeometryCollection() - g.fromWkt('GeometryCollection( Point(1 2), Point(11 12), Point(33 34))') + g.fromWkt("GeometryCollection( Point(1 2), Point(11 12), Point(33 34))") with self.assertRaises(IndexError): g.removeGeometry(-1) with self.assertRaises(IndexError): @@ -688,7 +764,7 @@ def testGeometryCollectionPythonAdditions(self): with self.assertRaises(IndexError): g.removeGeometry(2) - g.fromWkt('GeometryCollection( Point(25 16 37 58), Point(26 22 47 68))') + g.fromWkt("GeometryCollection( Point(25 16 37 58), Point(26 22 47 68))") # get item with self.assertRaises(IndexError): g[-3] @@ -700,7 +776,7 @@ def testGeometryCollectionPythonAdditions(self): self.assertEqual(g[-1], QgsPoint(26, 22, 47, 68)) # del item - g.fromWkt('GeometryCollection( Point(1 2), Point(11 12), Point(33 34))') + g.fromWkt("GeometryCollection( Point(1 2), Point(11 12), Point(33 34))") with self.assertRaises(IndexError): del g[-4] with self.assertRaises(IndexError): @@ -712,7 +788,7 @@ def testGeometryCollectionPythonAdditions(self): with self.assertRaises(IndexError): del g[2] - g.fromWkt('GeometryCollection( Point(1 2), Point(11 12), Point(33 34))') + g.fromWkt("GeometryCollection( Point(1 2), Point(11 12), Point(33 34))") del g[-3] self.assertEqual(len(g), 2) self.assertEqual(g[0], QgsPoint(11, 12)) @@ -723,53 +799,66 @@ def testGeometryCollectionPythonAdditions(self): # iteration g = QgsGeometryCollection() self.assertFalse([p for p in g]) - g.fromWkt('GeometryCollection( Point(1 2), Point(11 12), LineString(33 34, 44 45))') - self.assertEqual([p.asWkt() for p in g], ['Point (1 2)', 'Point (11 12)', 'LineString (33 34, 44 45)']) + g.fromWkt( + "GeometryCollection( Point(1 2), Point(11 12), LineString(33 34, 44 45))" + ) + self.assertEqual( + [p.asWkt() for p in g], + ["Point (1 2)", "Point (11 12)", "LineString (33 34, 44 45)"], + ) g = QgsGeometryCollection() - g.fromWkt('GeometryCollection( Point(1 2), Point(11 12))') + g.fromWkt("GeometryCollection( Point(1 2), Point(11 12))") self.assertTrue(bool(g)) self.assertEqual(len(g), 2) # lineStringN g = QgsMultiLineString() - g.fromWkt('MultiLineString( (1 2, 3 4), (11 12, 13 14))') + g.fromWkt("MultiLineString( (1 2, 3 4), (11 12, 13 14))") with self.assertRaises(IndexError): g.lineStringN(-1) with self.assertRaises(IndexError): g.lineStringN(2) - self.assertEqual(g.lineStringN(0).asWkt(), 'LineString (1 2, 3 4)') - self.assertEqual(g.lineStringN(1).asWkt(), 'LineString (11 12, 13 14)') + self.assertEqual(g.lineStringN(0).asWkt(), "LineString (1 2, 3 4)") + self.assertEqual(g.lineStringN(1).asWkt(), "LineString (11 12, 13 14)") # curveN g = QgsMultiCurve() - g.fromWkt('MultiCurve( LineString(1 2, 3 4), LineString(11 12, 13 14))') + g.fromWkt("MultiCurve( LineString(1 2, 3 4), LineString(11 12, 13 14))") with self.assertRaises(IndexError): g.curveN(-1) with self.assertRaises(IndexError): g.curveN(2) - self.assertEqual(g.curveN(0).asWkt(), 'LineString (1 2, 3 4)') - self.assertEqual(g.curveN(1).asWkt(), 'LineString (11 12, 13 14)') + self.assertEqual(g.curveN(0).asWkt(), "LineString (1 2, 3 4)") + self.assertEqual(g.curveN(1).asWkt(), "LineString (11 12, 13 14)") # polygonN g = QgsMultiPolygon() - g.fromWkt('MultiPolygon( ((1 2, 3 4, 3 6, 1 2)), ((11 12, 13 14, 13 16, 11 12)))') + g.fromWkt( + "MultiPolygon( ((1 2, 3 4, 3 6, 1 2)), ((11 12, 13 14, 13 16, 11 12)))" + ) with self.assertRaises(IndexError): g.polygonN(-1) with self.assertRaises(IndexError): g.polygonN(2) - self.assertEqual(g.polygonN(0).asWkt(), 'Polygon ((1 2, 3 4, 3 6, 1 2))') - self.assertEqual(g.polygonN(1).asWkt(), 'Polygon ((11 12, 13 14, 13 16, 11 12))') + self.assertEqual(g.polygonN(0).asWkt(), "Polygon ((1 2, 3 4, 3 6, 1 2))") + self.assertEqual( + g.polygonN(1).asWkt(), "Polygon ((11 12, 13 14, 13 16, 11 12))" + ) # surfaceN g = QgsMultiSurface() - g.fromWkt('MultiSurface( Polygon((1 2, 3 4, 3 6, 1 2)), Polygon((11 12, 13 14, 13 16, 11 12)))') + g.fromWkt( + "MultiSurface( Polygon((1 2, 3 4, 3 6, 1 2)), Polygon((11 12, 13 14, 13 16, 11 12)))" + ) with self.assertRaises(IndexError): g.surfaceN(-1) with self.assertRaises(IndexError): g.surfaceN(2) - self.assertEqual(g.surfaceN(0).asWkt(), 'Polygon ((1 2, 3 4, 3 6, 1 2))') - self.assertEqual(g.surfaceN(1).asWkt(), 'Polygon ((11 12, 13 14, 13 16, 11 12))') + self.assertEqual(g.surfaceN(0).asWkt(), "Polygon ((1 2, 3 4, 3 6, 1 2))") + self.assertEqual( + g.surfaceN(1).asWkt(), "Polygon ((11 12, 13 14, 13 16, 11 12))" + ) def testCurvePolygonPythonAdditions(self): """ @@ -783,13 +872,20 @@ def testCurvePolygonPythonAdditions(self): g.interiorRing(0) g.fromWkt( - 'Polygon((0 0, 1 0, 1 1, 0 0),(0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1),(0.8 0.8, 0.9 0.8, 0.9 0.9, 0.8 0.8))') + "Polygon((0 0, 1 0, 1 1, 0 0),(0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1),(0.8 0.8, 0.9 0.8, 0.9 0.9, 0.8 0.8))" + ) with self.assertRaises(IndexError): g.interiorRing(-1) with self.assertRaises(IndexError): g.interiorRing(2) - self.assertEqual(g.interiorRing(0).asWkt(1), 'LineString (0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1)') - self.assertEqual(g.interiorRing(1).asWkt(1), 'LineString (0.8 0.8, 0.9 0.8, 0.9 0.9, 0.8 0.8)') + self.assertEqual( + g.interiorRing(0).asWkt(1), + "LineString (0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1)", + ) + self.assertEqual( + g.interiorRing(1).asWkt(1), + "LineString (0.8 0.8, 0.9 0.8, 0.9 0.9, 0.8 0.8)", + ) # removeInteriorRing g = QgsPolygon() @@ -799,18 +895,22 @@ def testCurvePolygonPythonAdditions(self): g.removeInteriorRing(0) g.fromWkt( - 'Polygon((0 0, 1 0, 1 1, 0 0),(0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1),(0.8 0.8, 0.9 0.8, 0.9 0.9, 0.8 0.8))') + "Polygon((0 0, 1 0, 1 1, 0 0),(0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1),(0.8 0.8, 0.9 0.8, 0.9 0.9, 0.8 0.8))" + ) with self.assertRaises(IndexError): g.removeInteriorRing(-1) with self.assertRaises(IndexError): g.removeInteriorRing(2) g.removeInteriorRing(1) - self.assertEqual(g.asWkt(1), 'Polygon ((0 0, 1 0, 1 1, 0 0),(0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1))') + self.assertEqual( + g.asWkt(1), + "Polygon ((0 0, 1 0, 1 1, 0 0),(0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1))", + ) with self.assertRaises(IndexError): g.removeInteriorRing(1) g.removeInteriorRing(0) - self.assertEqual(g.asWkt(1), 'Polygon ((0 0, 1 0, 1 1, 0 0))') + self.assertEqual(g.asWkt(1), "Polygon ((0 0, 1 0, 1 1, 0 0))") with self.assertRaises(IndexError): g.removeInteriorRing(0) @@ -818,273 +918,526 @@ def testPointXY(self): """ Test the QgsPointXY conversion methods """ - self.assertEqual(QgsGeometry.fromWkt('Point(11 13)').asPoint(), QgsPointXY(11, 13)) - self.assertEqual(QgsGeometry.fromWkt('Point Z(11 13 14)').asPoint(), QgsPointXY(11, 13)) - self.assertEqual(QgsGeometry.fromWkt('Point M(11 13 14)').asPoint(), QgsPointXY(11, 13)) - self.assertEqual(QgsGeometry.fromWkt('Point ZM(11 13 14 15)').asPoint(), QgsPointXY(11, 13)) + self.assertEqual( + QgsGeometry.fromWkt("Point(11 13)").asPoint(), QgsPointXY(11, 13) + ) + self.assertEqual( + QgsGeometry.fromWkt("Point Z(11 13 14)").asPoint(), QgsPointXY(11, 13) + ) + self.assertEqual( + QgsGeometry.fromWkt("Point M(11 13 14)").asPoint(), QgsPointXY(11, 13) + ) + self.assertEqual( + QgsGeometry.fromWkt("Point ZM(11 13 14 15)").asPoint(), QgsPointXY(11, 13) + ) # multipoint with single point should work too! - self.assertEqual(QgsGeometry.fromWkt('MultiPoint(11 13)').asPoint(), QgsPointXY(11, 13)) - self.assertEqual(QgsGeometry.fromWkt('MultiPoint Z(11 13 14)').asPoint(), QgsPointXY(11, 13)) - self.assertEqual(QgsGeometry.fromWkt('MultiPoint M(11 13 14)').asPoint(), QgsPointXY(11, 13)) - self.assertEqual(QgsGeometry.fromWkt('MultiPoint ZM(11 13 14 15)').asPoint(), QgsPointXY(11, 13)) + self.assertEqual( + QgsGeometry.fromWkt("MultiPoint(11 13)").asPoint(), QgsPointXY(11, 13) + ) + self.assertEqual( + QgsGeometry.fromWkt("MultiPoint Z(11 13 14)").asPoint(), QgsPointXY(11, 13) + ) + self.assertEqual( + QgsGeometry.fromWkt("MultiPoint M(11 13 14)").asPoint(), QgsPointXY(11, 13) + ) + self.assertEqual( + QgsGeometry.fromWkt("MultiPoint ZM(11 13 14 15)").asPoint(), + QgsPointXY(11, 13), + ) with self.assertRaises(TypeError): - QgsGeometry.fromWkt('MultiPoint(11 13,14 15)').asPoint() + QgsGeometry.fromWkt("MultiPoint(11 13,14 15)").asPoint() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('LineString(11 13,14 15)').asPoint() + QgsGeometry.fromWkt("LineString(11 13,14 15)").asPoint() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('Polygon((11 13,14 15, 14 13, 11 13))').asPoint() + QgsGeometry.fromWkt("Polygon((11 13,14 15, 14 13, 11 13))").asPoint() with self.assertRaises(ValueError): QgsGeometry().asPoint() # as polyline - self.assertEqual(QgsGeometry.fromWkt('LineString(11 13,14 15)').asPolyline(), - [QgsPointXY(11, 13), QgsPointXY(14, 15)]) - self.assertEqual(QgsGeometry.fromWkt('LineString Z(11 13 1,14 15 2)').asPolyline(), - [QgsPointXY(11, 13), QgsPointXY(14, 15)]) - self.assertEqual(QgsGeometry.fromWkt('LineString M(11 13 1,14 15 2)').asPolyline(), - [QgsPointXY(11, 13), QgsPointXY(14, 15)]) - self.assertEqual(QgsGeometry.fromWkt('LineString ZM(11 13 1 2,14 15 3 4)').asPolyline(), - [QgsPointXY(11, 13), QgsPointXY(14, 15)]) + self.assertEqual( + QgsGeometry.fromWkt("LineString(11 13,14 15)").asPolyline(), + [QgsPointXY(11, 13), QgsPointXY(14, 15)], + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString Z(11 13 1,14 15 2)").asPolyline(), + [QgsPointXY(11, 13), QgsPointXY(14, 15)], + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString M(11 13 1,14 15 2)").asPolyline(), + [QgsPointXY(11, 13), QgsPointXY(14, 15)], + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString ZM(11 13 1 2,14 15 3 4)").asPolyline(), + [QgsPointXY(11, 13), QgsPointXY(14, 15)], + ) with self.assertRaises(TypeError): - QgsGeometry.fromWkt('Point(11 13)').asPolyline() + QgsGeometry.fromWkt("Point(11 13)").asPolyline() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('MultiPoint(11 13,14 15)').asPolyline() + QgsGeometry.fromWkt("MultiPoint(11 13,14 15)").asPolyline() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('MultiLineString((11 13, 14 15),(1 2, 3 4))').asPolyline() + QgsGeometry.fromWkt( + "MultiLineString((11 13, 14 15),(1 2, 3 4))" + ).asPolyline() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('Polygon((11 13,14 15, 14 13, 11 13))').asPolyline() + QgsGeometry.fromWkt("Polygon((11 13,14 15, 14 13, 11 13))").asPolyline() with self.assertRaises(ValueError): QgsGeometry().asPolyline() # as polygon - self.assertEqual(QgsGeometry.fromWkt('Polygon((11 13,14 15, 11 15, 11 13))').asPolygon(), - [[QgsPointXY(11, 13), QgsPointXY(14, 15), QgsPointXY(11, 15), QgsPointXY(11, 13)]]) - self.assertEqual(QgsGeometry.fromWkt('Polygon Z((11 13 1,14 15 2, 11 15 3, 11 13 1))').asPolygon(), - [[QgsPointXY(11, 13), QgsPointXY(14, 15), QgsPointXY(11, 15), QgsPointXY(11, 13)]]) - self.assertEqual(QgsGeometry.fromWkt('Polygon M((11 13 1,14 15 2, 11 15 3, 11 13 1))').asPolygon(), - [[QgsPointXY(11, 13), QgsPointXY(14, 15), QgsPointXY(11, 15), QgsPointXY(11, 13)]]) - self.assertEqual( - QgsGeometry.fromWkt('Polygon ZM((11 13 1 11,14 15 2 12 , 11 15 3 13 , 11 13 1 11))').asPolygon(), - [[QgsPointXY(11, 13), QgsPointXY(14, 15), QgsPointXY(11, 15), QgsPointXY(11, 13)]]) + self.assertEqual( + QgsGeometry.fromWkt("Polygon((11 13,14 15, 11 15, 11 13))").asPolygon(), + [ + [ + QgsPointXY(11, 13), + QgsPointXY(14, 15), + QgsPointXY(11, 15), + QgsPointXY(11, 13), + ] + ], + ) + self.assertEqual( + QgsGeometry.fromWkt( + "Polygon Z((11 13 1,14 15 2, 11 15 3, 11 13 1))" + ).asPolygon(), + [ + [ + QgsPointXY(11, 13), + QgsPointXY(14, 15), + QgsPointXY(11, 15), + QgsPointXY(11, 13), + ] + ], + ) + self.assertEqual( + QgsGeometry.fromWkt( + "Polygon M((11 13 1,14 15 2, 11 15 3, 11 13 1))" + ).asPolygon(), + [ + [ + QgsPointXY(11, 13), + QgsPointXY(14, 15), + QgsPointXY(11, 15), + QgsPointXY(11, 13), + ] + ], + ) + self.assertEqual( + QgsGeometry.fromWkt( + "Polygon ZM((11 13 1 11,14 15 2 12 , 11 15 3 13 , 11 13 1 11))" + ).asPolygon(), + [ + [ + QgsPointXY(11, 13), + QgsPointXY(14, 15), + QgsPointXY(11, 15), + QgsPointXY(11, 13), + ] + ], + ) with self.assertRaises(TypeError): - QgsGeometry.fromWkt('Point(11 13)').asPolygon() + QgsGeometry.fromWkt("Point(11 13)").asPolygon() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('MultiPoint(11 13,14 15)').asPolygon() + QgsGeometry.fromWkt("MultiPoint(11 13,14 15)").asPolygon() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('MultiLineString((11 13, 14 15),(1 2, 3 4))').asPolygon() + QgsGeometry.fromWkt( + "MultiLineString((11 13, 14 15),(1 2, 3 4))" + ).asPolygon() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('LineString(11 13,14 15)').asPolygon() + QgsGeometry.fromWkt("LineString(11 13,14 15)").asPolygon() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('MultiPolygon(((11 13,14 15, 11 15, 11 13)))').asPolygon() + QgsGeometry.fromWkt( + "MultiPolygon(((11 13,14 15, 11 15, 11 13)))" + ).asPolygon() with self.assertRaises(ValueError): QgsGeometry().asPolygon() # as multipoint - self.assertEqual(QgsGeometry.fromWkt('MultiPoint(11 13,14 15)').asMultiPoint(), - [QgsPointXY(11, 13), QgsPointXY(14, 15)]) - self.assertEqual(QgsGeometry.fromWkt('MultiPoint Z(11 13 1,14 15 2)').asMultiPoint(), - [QgsPointXY(11, 13), QgsPointXY(14, 15)]) - self.assertEqual(QgsGeometry.fromWkt('MultiPoint M(11 13 1,14 15 2)').asMultiPoint(), - [QgsPointXY(11, 13), QgsPointXY(14, 15)]) - self.assertEqual(QgsGeometry.fromWkt('MultiPoint ZM(11 13 1 2,14 15 3 4)').asMultiPoint(), - [QgsPointXY(11, 13), QgsPointXY(14, 15)]) + self.assertEqual( + QgsGeometry.fromWkt("MultiPoint(11 13,14 15)").asMultiPoint(), + [QgsPointXY(11, 13), QgsPointXY(14, 15)], + ) + self.assertEqual( + QgsGeometry.fromWkt("MultiPoint Z(11 13 1,14 15 2)").asMultiPoint(), + [QgsPointXY(11, 13), QgsPointXY(14, 15)], + ) + self.assertEqual( + QgsGeometry.fromWkt("MultiPoint M(11 13 1,14 15 2)").asMultiPoint(), + [QgsPointXY(11, 13), QgsPointXY(14, 15)], + ) + self.assertEqual( + QgsGeometry.fromWkt("MultiPoint ZM(11 13 1 2,14 15 3 4)").asMultiPoint(), + [QgsPointXY(11, 13), QgsPointXY(14, 15)], + ) with self.assertRaises(TypeError): - QgsGeometry.fromWkt('Point(11 13)').asMultiPoint() + QgsGeometry.fromWkt("Point(11 13)").asMultiPoint() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('LineString(11 13,14 15)').asMultiPoint() + QgsGeometry.fromWkt("LineString(11 13,14 15)").asMultiPoint() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('MultiLineString((11 13, 14 15),(1 2, 3 4))').asMultiPoint() + QgsGeometry.fromWkt( + "MultiLineString((11 13, 14 15),(1 2, 3 4))" + ).asMultiPoint() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('Polygon((11 13,14 15, 14 13, 11 13))').asMultiPoint() + QgsGeometry.fromWkt("Polygon((11 13,14 15, 14 13, 11 13))").asMultiPoint() with self.assertRaises(ValueError): QgsGeometry().asMultiPoint() # as multilinestring - self.assertEqual(QgsGeometry.fromWkt('MultiLineString((11 13,14 15, 11 15, 11 13))').asMultiPolyline(), - [[QgsPointXY(11, 13), QgsPointXY(14, 15), QgsPointXY(11, 15), QgsPointXY(11, 13)]]) - self.assertEqual(QgsGeometry.fromWkt('MultiLineString Z((11 13 1,14 15 2, 11 15 3, 11 13 1))').asMultiPolyline(), - [[QgsPointXY(11, 13), QgsPointXY(14, 15), QgsPointXY(11, 15), QgsPointXY(11, 13)]]) - self.assertEqual(QgsGeometry.fromWkt('MultiLineString M((11 13 1,14 15 2, 11 15 3, 11 13 1))').asMultiPolyline(), - [[QgsPointXY(11, 13), QgsPointXY(14, 15), QgsPointXY(11, 15), QgsPointXY(11, 13)]]) - self.assertEqual(QgsGeometry.fromWkt( - 'MultiLineString ZM((11 13 1 11,14 15 2 12 , 11 15 3 13 , 11 13 1 11))').asMultiPolyline(), - [[QgsPointXY(11, 13), QgsPointXY(14, 15), QgsPointXY(11, 15), QgsPointXY(11, 13)]]) + self.assertEqual( + QgsGeometry.fromWkt( + "MultiLineString((11 13,14 15, 11 15, 11 13))" + ).asMultiPolyline(), + [ + [ + QgsPointXY(11, 13), + QgsPointXY(14, 15), + QgsPointXY(11, 15), + QgsPointXY(11, 13), + ] + ], + ) + self.assertEqual( + QgsGeometry.fromWkt( + "MultiLineString Z((11 13 1,14 15 2, 11 15 3, 11 13 1))" + ).asMultiPolyline(), + [ + [ + QgsPointXY(11, 13), + QgsPointXY(14, 15), + QgsPointXY(11, 15), + QgsPointXY(11, 13), + ] + ], + ) + self.assertEqual( + QgsGeometry.fromWkt( + "MultiLineString M((11 13 1,14 15 2, 11 15 3, 11 13 1))" + ).asMultiPolyline(), + [ + [ + QgsPointXY(11, 13), + QgsPointXY(14, 15), + QgsPointXY(11, 15), + QgsPointXY(11, 13), + ] + ], + ) + self.assertEqual( + QgsGeometry.fromWkt( + "MultiLineString ZM((11 13 1 11,14 15 2 12 , 11 15 3 13 , 11 13 1 11))" + ).asMultiPolyline(), + [ + [ + QgsPointXY(11, 13), + QgsPointXY(14, 15), + QgsPointXY(11, 15), + QgsPointXY(11, 13), + ] + ], + ) with self.assertRaises(TypeError): - QgsGeometry.fromWkt('Point(11 13)').asMultiPolyline() + QgsGeometry.fromWkt("Point(11 13)").asMultiPolyline() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('MultiPoint(11 13,14 15)').asMultiPolyline() + QgsGeometry.fromWkt("MultiPoint(11 13,14 15)").asMultiPolyline() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('Polygon((11 13, 14 15, 17 18, 11 13))').asMultiPolyline() + QgsGeometry.fromWkt( + "Polygon((11 13, 14 15, 17 18, 11 13))" + ).asMultiPolyline() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('LineString(11 13,14 15)').asPolygon() + QgsGeometry.fromWkt("LineString(11 13,14 15)").asPolygon() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('MultiPolygon(((11 13,14 15, 11 15, 11 13)))').asMultiPolyline() + QgsGeometry.fromWkt( + "MultiPolygon(((11 13,14 15, 11 15, 11 13)))" + ).asMultiPolyline() with self.assertRaises(ValueError): QgsGeometry().asPolygon() # as multipolygon - self.assertEqual(QgsGeometry.fromWkt('MultiPolygon(((11 13,14 15, 11 15, 11 13)))').asMultiPolygon(), - [[[QgsPointXY(11, 13), QgsPointXY(14, 15), QgsPointXY(11, 15), QgsPointXY(11, 13)]]]) self.assertEqual( - QgsGeometry.fromWkt('MultiPolygon Z(((11 13 1,14 15 2, 11 15 3 , 11 13 1)))').asMultiPolygon(), - [[[QgsPointXY(11, 13), QgsPointXY(14, 15), QgsPointXY(11, 15), QgsPointXY(11, 13)]]]) + QgsGeometry.fromWkt( + "MultiPolygon(((11 13,14 15, 11 15, 11 13)))" + ).asMultiPolygon(), + [ + [ + [ + QgsPointXY(11, 13), + QgsPointXY(14, 15), + QgsPointXY(11, 15), + QgsPointXY(11, 13), + ] + ] + ], + ) + self.assertEqual( + QgsGeometry.fromWkt( + "MultiPolygon Z(((11 13 1,14 15 2, 11 15 3 , 11 13 1)))" + ).asMultiPolygon(), + [ + [ + [ + QgsPointXY(11, 13), + QgsPointXY(14, 15), + QgsPointXY(11, 15), + QgsPointXY(11, 13), + ] + ] + ], + ) + self.assertEqual( + QgsGeometry.fromWkt( + "MultiPolygon M(((11 13 1,14 15 2, 11 15 3 , 11 13 1)))" + ).asMultiPolygon(), + [ + [ + [ + QgsPointXY(11, 13), + QgsPointXY(14, 15), + QgsPointXY(11, 15), + QgsPointXY(11, 13), + ] + ] + ], + ) self.assertEqual( - QgsGeometry.fromWkt('MultiPolygon M(((11 13 1,14 15 2, 11 15 3 , 11 13 1)))').asMultiPolygon(), - [[[QgsPointXY(11, 13), QgsPointXY(14, 15), QgsPointXY(11, 15), QgsPointXY(11, 13)]]]) - self.assertEqual(QgsGeometry.fromWkt( - 'MultiPolygon ZM(((11 13 1 11,14 15 2 12, 11 15 3 13, 11 13 1 11)))').asMultiPolygon(), - [[[QgsPointXY(11, 13), QgsPointXY(14, 15), QgsPointXY(11, 15), QgsPointXY(11, 13)]]]) + QgsGeometry.fromWkt( + "MultiPolygon ZM(((11 13 1 11,14 15 2 12, 11 15 3 13, 11 13 1 11)))" + ).asMultiPolygon(), + [ + [ + [ + QgsPointXY(11, 13), + QgsPointXY(14, 15), + QgsPointXY(11, 15), + QgsPointXY(11, 13), + ] + ] + ], + ) with self.assertRaises(TypeError): - QgsGeometry.fromWkt('Point(11 13)').asMultiPolygon() + QgsGeometry.fromWkt("Point(11 13)").asMultiPolygon() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('MultiPoint(11 13,14 15)').asMultiPolygon() + QgsGeometry.fromWkt("MultiPoint(11 13,14 15)").asMultiPolygon() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('Polygon((11 13, 14 15, 17 18, 11 13))').asMultiPolygon() + QgsGeometry.fromWkt( + "Polygon((11 13, 14 15, 17 18, 11 13))" + ).asMultiPolygon() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('LineString(11 13,14 15)').asPolygon() + QgsGeometry.fromWkt("LineString(11 13,14 15)").asPolygon() with self.assertRaises(TypeError): - QgsGeometry.fromWkt('MultiLineString((11 13,14 15, 11 15, 11 13))').asMultiPolygon() + QgsGeometry.fromWkt( + "MultiLineString((11 13,14 15, 11 15, 11 13))" + ).asMultiPolygon() with self.assertRaises(ValueError): QgsGeometry().asPolygon() def testReferenceGeometry(self): - """ Test parsing a whole range of valid reference wkt formats and variants, and checking + """Test parsing a whole range of valid reference wkt formats and variants, and checking expected values such as length, area, centroids, bounding boxes, etc of the resultant geometry. - Note the bulk of this test data was taken from the PostGIS WKT test data """ + Note the bulk of this test data was taken from the PostGIS WKT test data""" - with open(os.path.join(TEST_DATA_DIR, 'geom_data.csv')) as f: + with open(os.path.join(TEST_DATA_DIR, "geom_data.csv")) as f: reader = csv.DictReader(f) for i, row in enumerate(reader): # test that geometry can be created from WKT - geom = QgsGeometry.fromWkt(row['wkt']) - if row['valid_wkt']: - assert geom, f"WKT conversion {i + 1} failed: could not create geom:\n{row['wkt']}\n" + geom = QgsGeometry.fromWkt(row["wkt"]) + if row["valid_wkt"]: + assert ( + geom + ), f"WKT conversion {i + 1} failed: could not create geom:\n{row['wkt']}\n" else: - assert not geom, "Corrupt WKT {} was incorrectly converted to geometry:\n{}\n".format(i + 1, - row['wkt']) + assert ( + not geom + ), "Corrupt WKT {} was incorrectly converted to geometry:\n{}\n".format( + i + 1, row["wkt"] + ) continue # test exporting to WKT results in expected string result = geom.asWkt() - exp = row['valid_wkt'] - assert compareWkt(result, exp, - 0.000001), "WKT conversion {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, - result) + exp = row["valid_wkt"] + assert compareWkt( + result, exp, 0.000001 + ), "WKT conversion {}: mismatch Expected:\n{}\nGot:\n{}\n".format( + i + 1, exp, result + ) # test num points in geometry - exp_nodes = int(row['num_points']) - self.assertEqual(geom.constGet().nCoordinates(), exp_nodes, - "Node count {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp_nodes, - geom.constGet().nCoordinates())) + exp_nodes = int(row["num_points"]) + self.assertEqual( + geom.constGet().nCoordinates(), + exp_nodes, + "Node count {}: mismatch Expected:\n{}\nGot:\n{}\n".format( + i + 1, exp_nodes, geom.constGet().nCoordinates() + ), + ) # test num geometries in collections - exp_geometries = int(row['num_geometries']) + exp_geometries = int(row["num_geometries"]) try: - self.assertEqual(geom.constGet().numGeometries(), exp_geometries, - "Geometry count {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, - exp_geometries, - geom.constGet().numGeometries())) + self.assertEqual( + geom.constGet().numGeometries(), + exp_geometries, + "Geometry count {}: mismatch Expected:\n{}\nGot:\n{}\n".format( + i + 1, exp_geometries, geom.constGet().numGeometries() + ), + ) except: # some geometry types don't have numGeometries() - assert exp_geometries <= 1, "Geometry count {}: Expected:\n{} geometries but could not call numGeometries()\n".format( - i + 1, exp_geometries) + assert ( + exp_geometries <= 1 + ), "Geometry count {}: Expected:\n{} geometries but could not call numGeometries()\n".format( + i + 1, exp_geometries + ) # test count of rings - exp_rings = int(row['num_rings']) + exp_rings = int(row["num_rings"]) try: - self.assertEqual(geom.constGet().numInteriorRings(), exp_rings, - "Ring count {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp_rings, - geom.constGet().numInteriorRings())) + self.assertEqual( + geom.constGet().numInteriorRings(), + exp_rings, + "Ring count {}: mismatch Expected:\n{}\nGot:\n{}\n".format( + i + 1, exp_rings, geom.constGet().numInteriorRings() + ), + ) except: # some geometry types don't have numInteriorRings() - assert exp_rings <= 1, "Ring count {}: Expected:\n{} rings but could not call numInteriorRings()\n{}".format( - i + 1, exp_rings, geom.constGet()) + assert ( + exp_rings <= 1 + ), "Ring count {}: Expected:\n{} rings but could not call numInteriorRings()\n{}".format( + i + 1, exp_rings, geom.constGet() + ) # test isClosed - exp = (row['is_closed'] == '1') + exp = row["is_closed"] == "1" try: - self.assertEqual(geom.constGet().isClosed(), exp, - "isClosed {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, True, - geom.constGet().isClosed())) + self.assertEqual( + geom.constGet().isClosed(), + exp, + "isClosed {}: mismatch Expected:\n{}\nGot:\n{}\n".format( + i + 1, True, geom.constGet().isClosed() + ), + ) except: # some geometry types don't have isClosed() - assert not exp, f"isClosed {i + 1}: Expected:\n isClosed() but could not call isClosed()\n" + assert ( + not exp + ), f"isClosed {i + 1}: Expected:\n isClosed() but could not call isClosed()\n" # test geometry centroid - exp = row['centroid'] + exp = row["centroid"] result = geom.centroid().asWkt() - assert compareWkt(result, exp, 0.00001), "Centroid {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, - exp, - result) + assert compareWkt( + result, exp, 0.00001 + ), "Centroid {}: mismatch Expected:\n{}\nGot:\n{}\n".format( + i + 1, exp, result + ) # test bounding box limits bbox = geom.constGet().boundingBox() - exp = float(row['x_min']) + exp = float(row["x_min"]) result = bbox.xMinimum() - self.assertAlmostEqual(result, exp, 5, - f"Min X {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n") - exp = float(row['y_min']) + self.assertAlmostEqual( + result, + exp, + 5, + f"Min X {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) + exp = float(row["y_min"]) result = bbox.yMinimum() - self.assertAlmostEqual(result, exp, 5, - f"Min Y {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n") - exp = float(row['x_max']) + self.assertAlmostEqual( + result, + exp, + 5, + f"Min Y {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) + exp = float(row["x_max"]) result = bbox.xMaximum() - self.assertAlmostEqual(result, exp, 5, - f"Max X {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n") - exp = float(row['y_max']) + self.assertAlmostEqual( + result, + exp, + 5, + f"Max X {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) + exp = float(row["y_max"]) result = bbox.yMaximum() - self.assertAlmostEqual(result, exp, 5, - f"Max Y {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertAlmostEqual( + result, + exp, + 5, + f"Max Y {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) # test area calculation - exp = float(row['area']) + exp = float(row["area"]) result = geom.constGet().area() - self.assertAlmostEqual(result, exp, 5, - f"Area {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertAlmostEqual( + result, + exp, + 5, + f"Area {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) result = geom.area() - self.assertAlmostEqual(result, exp, 5, - f"Length {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertAlmostEqual( + result, + exp, + 5, + f"Length {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) # test length calculation - exp = float(row['length']) + exp = float(row["length"]) result = geom.constGet().length() - self.assertAlmostEqual(result, exp, 5, - f"Length {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertAlmostEqual( + result, + exp, + 5, + f"Length {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) if geom.type() != QgsWkbTypes.GeometryType.PolygonGeometry: result = geom.length() - self.assertAlmostEqual(result, exp, 5, - f"Length {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertAlmostEqual( + result, + exp, + 5, + f"Length {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) # test perimeter calculation - exp = float(row['perimeter']) + exp = float(row["perimeter"]) result = geom.constGet().perimeter() - self.assertAlmostEqual(result, exp, 5, - f"Perimeter {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertAlmostEqual( + result, + exp, + 5, + f"Perimeter {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) if geom.type() == QgsWkbTypes.GeometryType.PolygonGeometry: result = geom.length() - self.assertAlmostEqual(result, exp, 5, - f"Length {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertAlmostEqual( + result, + exp, + 5, + f"Length {i + 1}: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) def testCollection(self): - g = QgsGeometry.fromWkt('MultiLineString EMPTY') + g = QgsGeometry.fromWkt("MultiLineString EMPTY") self.assertEqual(len(g.get()), 0) self.assertTrue(g.get()) - g = QgsGeometry.fromWkt('MultiLineString((0 0, 1 1),(13 2, 14 1))') + g = QgsGeometry.fromWkt("MultiLineString((0 0, 1 1),(13 2, 14 1))") self.assertEqual(len(g.get()), 2) self.assertTrue(g.get()) - self.assertEqual(g.get().geometryN(0).asWkt(), 'LineString (0 0, 1 1)') - self.assertEqual(g.get().geometryN(1).asWkt(), 'LineString (13 2, 14 1)') + self.assertEqual(g.get().geometryN(0).asWkt(), "LineString (0 0, 1 1)") + self.assertEqual(g.get().geometryN(1).asWkt(), "LineString (13 2, 14 1)") with self.assertRaises(IndexError): g.get().geometryN(-1) with self.assertRaises(IndexError): g.get().geometryN(2) def testIntersection(self): - myLine = QgsGeometry.fromPolylineXY([ - QgsPointXY(0, 0), - QgsPointXY(1, 1), - QgsPointXY(2, 2)]) + myLine = QgsGeometry.fromPolylineXY( + [QgsPointXY(0, 0), QgsPointXY(1, 1), QgsPointXY(2, 2)] + ) myPoint = QgsGeometry.fromPointXY(QgsPointXY(1, 1)) intersectionGeom = QgsGeometry.intersection(myLine, myPoint) self.assertEqual(intersectionGeom.wkbType(), QgsWkbTypes.Type.Point) @@ -1109,11 +1462,16 @@ def testBuffer(self): def testContains(self): myPoly = QgsGeometry.fromPolygonXY( - [[QgsPointXY(0, 0), - QgsPointXY(2, 0), - QgsPointXY(2, 2), - QgsPointXY(0, 2), - QgsPointXY(0, 0)]]) + [ + [ + QgsPointXY(0, 0), + QgsPointXY(2, 0), + QgsPointXY(2, 2), + QgsPointXY(0, 2), + QgsPointXY(0, 0), + ] + ] + ) pointInside = QgsPointXY(1, 1) self.assertTrue(myPoly.contains(pointInside)) self.assertTrue(myPoly.contains(QgsGeometry.fromPointXY(pointInside))) @@ -1125,47 +1483,50 @@ def testContains(self): self.assertFalse(myPoly.contains(pointOutside.x(), pointOutside.y())) def testTouches(self): - myLine = QgsGeometry.fromPolylineXY([ - QgsPointXY(0, 0), - QgsPointXY(1, 1), - QgsPointXY(2, 2)]) - myPoly = QgsGeometry.fromPolygonXY([[ - QgsPointXY(0, 0), - QgsPointXY(1, 1), - QgsPointXY(2, 0), - QgsPointXY(0, 0)]]) + myLine = QgsGeometry.fromPolylineXY( + [QgsPointXY(0, 0), QgsPointXY(1, 1), QgsPointXY(2, 2)] + ) + myPoly = QgsGeometry.fromPolygonXY( + [[QgsPointXY(0, 0), QgsPointXY(1, 1), QgsPointXY(2, 0), QgsPointXY(0, 0)]] + ) touchesGeom = QgsGeometry.touches(myLine, myPoly) myMessage = f"Expected:\n{'True'}\nGot:\n{touchesGeom}\n" assert touchesGeom, myMessage def testOverlaps(self): - myPolyA = QgsGeometry.fromPolygonXY([[ - QgsPointXY(0, 0), - QgsPointXY(1, 3), - QgsPointXY(2, 0), - QgsPointXY(0, 0)]]) - myPolyB = QgsGeometry.fromPolygonXY([[ - QgsPointXY(0, 0), - QgsPointXY(2, 0), - QgsPointXY(2, 2), - QgsPointXY(0, 2), - QgsPointXY(0, 0)]]) + myPolyA = QgsGeometry.fromPolygonXY( + [[QgsPointXY(0, 0), QgsPointXY(1, 3), QgsPointXY(2, 0), QgsPointXY(0, 0)]] + ) + myPolyB = QgsGeometry.fromPolygonXY( + [ + [ + QgsPointXY(0, 0), + QgsPointXY(2, 0), + QgsPointXY(2, 2), + QgsPointXY(0, 2), + QgsPointXY(0, 0), + ] + ] + ) overlapsGeom = QgsGeometry.overlaps(myPolyA, myPolyB) myMessage = f"Expected:\n{'True'}\nGot:\n{overlapsGeom}\n" assert overlapsGeom, myMessage def testWithin(self): - myLine = QgsGeometry.fromPolylineXY([ - QgsPointXY(0.5, 0.5), - QgsPointXY(1, 1), - QgsPointXY(1.5, 1.5) - ]) - myPoly = QgsGeometry.fromPolygonXY([[ - QgsPointXY(0, 0), - QgsPointXY(2, 0), - QgsPointXY(2, 2), - QgsPointXY(0, 2), - QgsPointXY(0, 0)]]) + myLine = QgsGeometry.fromPolylineXY( + [QgsPointXY(0.5, 0.5), QgsPointXY(1, 1), QgsPointXY(1.5, 1.5)] + ) + myPoly = QgsGeometry.fromPolygonXY( + [ + [ + QgsPointXY(0, 0), + QgsPointXY(2, 0), + QgsPointXY(2, 2), + QgsPointXY(0, 2), + QgsPointXY(0, 0), + ] + ] + ) withinGeom = QgsGeometry.within(myLine, myPoly) myMessage = f"Expected:\n{'True'}\nGot:\n{withinGeom}\n" assert withinGeom, myMessage @@ -1178,16 +1539,20 @@ def testEquals(self): assert equalsGeom, myMessage def testCrosses(self): - myLine = QgsGeometry.fromPolylineXY([ - QgsPointXY(0, 0), - QgsPointXY(1, 1), - QgsPointXY(3, 3)]) - myPoly = QgsGeometry.fromPolygonXY([[ - QgsPointXY(1, 0), - QgsPointXY(2, 0), - QgsPointXY(2, 2), - QgsPointXY(1, 2), - QgsPointXY(1, 0)]]) + myLine = QgsGeometry.fromPolylineXY( + [QgsPointXY(0, 0), QgsPointXY(1, 1), QgsPointXY(3, 3)] + ) + myPoly = QgsGeometry.fromPolygonXY( + [ + [ + QgsPointXY(1, 0), + QgsPointXY(2, 0), + QgsPointXY(2, 2), + QgsPointXY(1, 2), + QgsPointXY(1, 0), + ] + ] + ) crossesGeom = QgsGeometry.crosses(myLine, myPoly) myMessage = f"Expected:\n{'True'}\nGot:\n{crossesGeom}\n" assert crossesGeom, myMessage @@ -1211,7 +1576,9 @@ def testSimplifyIssue4189(self): transform(simplify(transform(geom,32649),500), 4326) as simplegeom from dissolve;' """ - with open(os.path.join(unitTestDataPath('wkt'), 'simplify_error.wkt')) as myWKTFile: + with open( + os.path.join(unitTestDataPath("wkt"), "simplify_error.wkt") + ) as myWKTFile: myWKT = myWKTFile.readline() # print myWKT myGeometry = QgsGeometry().fromWkt(myWKT) @@ -1220,64 +1587,85 @@ def testSimplifyIssue4189(self): myTolerance = 0.00001 mySimpleGeometry = myGeometry.simplify(myTolerance) myEndLength = len(mySimpleGeometry.asWkt()) - myMessage = 'Before simplify: %i\nAfter simplify: %i\n : Tolerance %e' % ( - myStartLength, myEndLength, myTolerance) - myMinimumLength = len('Polygon(())') + myMessage = "Before simplify: %i\nAfter simplify: %i\n : Tolerance %e" % ( + myStartLength, + myEndLength, + myTolerance, + ) + myMinimumLength = len("Polygon(())") assert myEndLength > myMinimumLength, myMessage def testClipping(self): """Test that we can clip geometries using other geometries.""" myMemoryLayer = QgsVectorLayer( - ('LineString?crs=epsg:4326&field=name:string(20)&index=yes'), - 'clip-in', - 'memory') + ("LineString?crs=epsg:4326&field=name:string(20)&index=yes"), + "clip-in", + "memory", + ) - assert myMemoryLayer is not None, 'Provider not initialized' + assert myMemoryLayer is not None, "Provider not initialized" myProvider = myMemoryLayer.dataProvider() assert myProvider is not None myFeature1 = QgsFeature() - myFeature1.setGeometry(QgsGeometry.fromPolylineXY([ - QgsPointXY(10, 10), - QgsPointXY(20, 10), - QgsPointXY(30, 10), - QgsPointXY(40, 10), - ])) - myFeature1.setAttributes(['Johny']) + myFeature1.setGeometry( + QgsGeometry.fromPolylineXY( + [ + QgsPointXY(10, 10), + QgsPointXY(20, 10), + QgsPointXY(30, 10), + QgsPointXY(40, 10), + ] + ) + ) + myFeature1.setAttributes(["Johny"]) myFeature2 = QgsFeature() - myFeature2.setGeometry(QgsGeometry.fromPolylineXY([ - QgsPointXY(10, 10), - QgsPointXY(20, 20), - QgsPointXY(30, 30), - QgsPointXY(40, 40), - ])) - myFeature2.setAttributes(['Be']) + myFeature2.setGeometry( + QgsGeometry.fromPolylineXY( + [ + QgsPointXY(10, 10), + QgsPointXY(20, 20), + QgsPointXY(30, 30), + QgsPointXY(40, 40), + ] + ) + ) + myFeature2.setAttributes(["Be"]) myFeature3 = QgsFeature() - myFeature3.setGeometry(QgsGeometry.fromPolylineXY([ - QgsPointXY(10, 10), - QgsPointXY(10, 20), - QgsPointXY(10, 30), - QgsPointXY(10, 40), - ])) + myFeature3.setGeometry( + QgsGeometry.fromPolylineXY( + [ + QgsPointXY(10, 10), + QgsPointXY(10, 20), + QgsPointXY(10, 30), + QgsPointXY(10, 40), + ] + ) + ) - myFeature3.setAttributes(['Good']) + myFeature3.setAttributes(["Good"]) myResult, myFeatures = myProvider.addFeatures( - [myFeature1, myFeature2, myFeature3]) + [myFeature1, myFeature2, myFeature3] + ) assert myResult self.assertEqual(len(myFeatures), 3) - myClipPolygon = QgsGeometry.fromPolygonXY([[ - QgsPointXY(20, 20), - QgsPointXY(20, 30), - QgsPointXY(30, 30), - QgsPointXY(30, 20), - QgsPointXY(20, 20), - ]]) - print(f'Clip: {myClipPolygon.asWkt()}') - writeShape(myMemoryLayer, 'clipGeometryBefore.shp') + myClipPolygon = QgsGeometry.fromPolygonXY( + [ + [ + QgsPointXY(20, 20), + QgsPointXY(20, 30), + QgsPointXY(30, 30), + QgsPointXY(30, 20), + QgsPointXY(20, 20), + ] + ] + ) + print(f"Clip: {myClipPolygon.asWkt()}") + writeShape(myMemoryLayer, "clipGeometryBefore.shp") fit = myProvider.getFeatures() myFeatures = [] myFeature = QgsFeature() @@ -1287,28 +1675,26 @@ def testClipping(self): # Adds nodes where the clip and the line intersec myCombinedGeometry = myGeometry.combine(myClipPolygon) # Gives you the areas inside the clip - mySymmetricalGeometry = myGeometry.symDifference( - myCombinedGeometry) + mySymmetricalGeometry = myGeometry.symDifference(myCombinedGeometry) # Gives you areas outside the clip area # myDifferenceGeometry = myCombinedGeometry.difference( # myClipPolygon) # print 'Original: %s' % myGeometry.asWkt() # print 'Combined: %s' % myCombinedGeometry.asWkt() # print 'Difference: %s' % myDifferenceGeometry.asWkt() - print(f'Symmetrical: {mySymmetricalGeometry.asWkt()}') + print(f"Symmetrical: {mySymmetricalGeometry.asWkt()}") if Qgis.geosVersionInt() >= self.geos312: # See: https://github.com/libgeos/geos/pull/788 - myExpectedWkt = 'Polygon ((30 30, 30 20, 20 20, 20 30, 30 30))' + myExpectedWkt = "Polygon ((30 30, 30 20, 20 20, 20 30, 30 30))" elif Qgis.geosVersionInt() >= self.geos309: - myExpectedWkt = 'Polygon ((20 30, 30 30, 30 20, 20 20, 20 30))' + myExpectedWkt = "Polygon ((20 30, 30 30, 30 20, 20 20, 20 30))" else: - myExpectedWkt = 'Polygon ((20 20, 20 30, 30 30, 30 20, 20 20))' + myExpectedWkt = "Polygon ((20 20, 20 30, 30 30, 30 20, 20 20))" # There should only be one feature that intersects this clip # poly so this assertion should work. - assert compareWkt(myExpectedWkt, - mySymmetricalGeometry.asWkt()) + assert compareWkt(myExpectedWkt, mySymmetricalGeometry.asWkt()) myNewFeature = QgsFeature() myNewFeature.setAttributes(myFeature.attributes()) @@ -1316,15 +1702,16 @@ def testClipping(self): myFeatures.append(myNewFeature) myNewMemoryLayer = QgsVectorLayer( - ('Polygon?crs=epsg:4326&field=name:string(20)&index=yes'), - 'clip-out', - 'memory') + ("Polygon?crs=epsg:4326&field=name:string(20)&index=yes"), + "clip-out", + "memory", + ) myNewProvider = myNewMemoryLayer.dataProvider() myResult, myFeatures = myNewProvider.addFeatures(myFeatures) self.assertTrue(myResult) self.assertEqual(len(myFeatures), 1) - writeShape(myNewMemoryLayer, 'clipGeometryAfter.shp') + writeShape(myNewMemoryLayer, "clipGeometryAfter.shp") def testClosestVertex(self): # 2-+-+-+-+-3 @@ -1337,44 +1724,66 @@ def testClosestVertex(self): # | # 1-+-+-+-+-0 ! polyline = QgsGeometry.fromPolylineXY( - [QgsPointXY(5, 0), QgsPointXY(0, 0), QgsPointXY(0, 4), QgsPointXY(5, 4), QgsPointXY(5, 1), QgsPointXY(1, 1), - QgsPointXY(1, 3), QgsPointXY(4, 3), QgsPointXY(4, 2), QgsPointXY(2, 2)] + [ + QgsPointXY(5, 0), + QgsPointXY(0, 0), + QgsPointXY(0, 4), + QgsPointXY(5, 4), + QgsPointXY(5, 1), + QgsPointXY(1, 1), + QgsPointXY(1, 3), + QgsPointXY(4, 3), + QgsPointXY(4, 2), + QgsPointXY(2, 2), + ] ) - (point, atVertex, beforeVertex, afterVertex, dist) = polyline.closestVertex(QgsPointXY(6, 1)) + (point, atVertex, beforeVertex, afterVertex, dist) = polyline.closestVertex( + QgsPointXY(6, 1) + ) self.assertEqual(point, QgsPointXY(5, 1)) self.assertEqual(beforeVertex, 3) self.assertEqual(atVertex, 4) self.assertEqual(afterVertex, 5) self.assertEqual(dist, 1) - (dist, minDistPoint, afterVertex, leftOf) = polyline.closestSegmentWithContext(QgsPointXY(6, 2)) + (dist, minDistPoint, afterVertex, leftOf) = polyline.closestSegmentWithContext( + QgsPointXY(6, 2) + ) self.assertEqual(dist, 1) self.assertEqual(minDistPoint, QgsPointXY(5, 2)) self.assertEqual(afterVertex, 4) self.assertEqual(leftOf, -1) - (point, atVertex, beforeVertex, afterVertex, dist) = polyline.closestVertex(QgsPointXY(6, 0)) + (point, atVertex, beforeVertex, afterVertex, dist) = polyline.closestVertex( + QgsPointXY(6, 0) + ) self.assertEqual(point, QgsPointXY(5, 0)) self.assertEqual(beforeVertex, -1) self.assertEqual(atVertex, 0) self.assertEqual(afterVertex, 1) self.assertEqual(dist, 1) - (dist, minDistPoint, afterVertex, leftOf) = polyline.closestSegmentWithContext(QgsPointXY(6, 0)) + (dist, minDistPoint, afterVertex, leftOf) = polyline.closestSegmentWithContext( + QgsPointXY(6, 0) + ) self.assertEqual(dist, 1) self.assertEqual(minDistPoint, QgsPointXY(5, 0)) self.assertEqual(afterVertex, 1) self.assertEqual(leftOf, 0) - (point, atVertex, beforeVertex, afterVertex, dist) = polyline.closestVertex(QgsPointXY(0, -1)) + (point, atVertex, beforeVertex, afterVertex, dist) = polyline.closestVertex( + QgsPointXY(0, -1) + ) self.assertEqual(point, QgsPointXY(0, 0)) self.assertEqual(beforeVertex, 0) self.assertEqual(atVertex, 1) self.assertEqual(afterVertex, 2) self.assertEqual(dist, 1) - (dist, minDistPoint, afterVertex, leftOf) = polyline.closestSegmentWithContext(QgsPointXY(0, 1)) + (dist, minDistPoint, afterVertex, leftOf) = polyline.closestSegmentWithContext( + QgsPointXY(0, 1) + ) self.assertEqual(dist, 0) self.assertEqual(minDistPoint, QgsPointXY(0, 1)) self.assertEqual(afterVertex, 2) @@ -1385,18 +1794,34 @@ def testClosestVertex(self): # 0-1 4 5 8-9 polyline = QgsGeometry.fromMultiPolylineXY( [ - [QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 0), ], - [QgsPointXY(3, 0), QgsPointXY(3, 1), QgsPointXY(5, 1), QgsPointXY(5, 0), QgsPointXY(6, 0), ] + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 0), + ], + [ + QgsPointXY(3, 0), + QgsPointXY(3, 1), + QgsPointXY(5, 1), + QgsPointXY(5, 0), + QgsPointXY(6, 0), + ], ] ) - (point, atVertex, beforeVertex, afterVertex, dist) = polyline.closestVertex(QgsPointXY(5, 2)) + (point, atVertex, beforeVertex, afterVertex, dist) = polyline.closestVertex( + QgsPointXY(5, 2) + ) self.assertEqual(point, QgsPointXY(5, 1)) self.assertEqual(beforeVertex, 6) self.assertEqual(atVertex, 7) self.assertEqual(afterVertex, 8) self.assertEqual(dist, 1) - (dist, minDistPoint, afterVertex, leftOf) = polyline.closestSegmentWithContext(QgsPointXY(7, 0)) + (dist, minDistPoint, afterVertex, leftOf) = polyline.closestSegmentWithContext( + QgsPointXY(7, 0) + ) self.assertEqual(dist, 1) self.assertEqual(minDistPoint, QgsPointXY(6, 0)) self.assertEqual(afterVertex, 9) @@ -1408,22 +1833,33 @@ def testClosestVertex(self): # | | # 0-1 polygon = QgsGeometry.fromPolygonXY( - [[ - QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), - QgsPointXY(0, 2), QgsPointXY(0, 0), - ]] + [ + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 2), + QgsPointXY(0, 2), + QgsPointXY(0, 0), + ] + ] + ) + (point, atVertex, beforeVertex, afterVertex, dist) = polygon.closestVertex( + QgsPointXY(0.7, 1.1) ) - (point, atVertex, beforeVertex, afterVertex, dist) = polygon.closestVertex(QgsPointXY(0.7, 1.1)) self.assertEqual(point, QgsPointXY(1, 1)) self.assertEqual(beforeVertex, 1) self.assertEqual(atVertex, 2) self.assertEqual(afterVertex, 3) assert abs(dist - 0.1) < 0.00001, f"Expected: {dist:f}; Got:{0.1:f}" - (dist, minDistPoint, afterVertex, leftOf) = polygon.closestSegmentWithContext(QgsPointXY(0.7, 1.1)) + (dist, minDistPoint, afterVertex, leftOf) = polygon.closestSegmentWithContext( + QgsPointXY(0.7, 1.1) + ) self.assertEqual(afterVertex, 2) self.assertEqual(minDistPoint, QgsPointXY(1, 1)) - exp = 0.3 ** 2 + 0.1 ** 2 + exp = 0.3**2 + 0.1**2 assert abs(dist - exp) < 0.00001, f"Expected: {exp:f}; Got:{dist:f}" self.assertEqual(leftOf, -1) @@ -1436,18 +1872,34 @@ def testClosestVertex(self): # 0-+-+-1 polygon = QgsGeometry.fromPolygonXY( [ - [QgsPointXY(0, 0), QgsPointXY(3, 0), QgsPointXY(3, 3), QgsPointXY(0, 3), QgsPointXY(0, 0)], - [QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), QgsPointXY(1, 2), QgsPointXY(1, 1)], + [ + QgsPointXY(0, 0), + QgsPointXY(3, 0), + QgsPointXY(3, 3), + QgsPointXY(0, 3), + QgsPointXY(0, 0), + ], + [ + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 2), + QgsPointXY(1, 2), + QgsPointXY(1, 1), + ], ] ) - (point, atVertex, beforeVertex, afterVertex, dist) = polygon.closestVertex(QgsPointXY(1.1, 1.9)) + (point, atVertex, beforeVertex, afterVertex, dist) = polygon.closestVertex( + QgsPointXY(1.1, 1.9) + ) self.assertEqual(point, QgsPointXY(1, 2)) self.assertEqual(beforeVertex, 7) self.assertEqual(atVertex, 8) self.assertEqual(afterVertex, 9) assert abs(dist - 0.02) < 0.00001, f"Expected: {dist:f}; Got:{0.02:f}" - (dist, minDistPoint, afterVertex, leftOf) = polygon.closestSegmentWithContext(QgsPointXY(1.2, 1.9)) + (dist, minDistPoint, afterVertex, leftOf) = polygon.closestSegmentWithContext( + QgsPointXY(1.2, 1.9) + ) self.assertEqual(afterVertex, 8) self.assertEqual(minDistPoint, QgsPointXY(1.2, 2)) exp = 0.01 @@ -1461,31 +1913,57 @@ def testClosestVertex(self): # 0-1 7-8 polygon = QgsGeometry.fromMultiPolygonXY( [ - [[QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), - QgsPointXY(0, 2), QgsPointXY(0, 0), ]], - [[QgsPointXY(4, 0), QgsPointXY(5, 0), QgsPointXY(5, 2), QgsPointXY(3, 2), QgsPointXY(3, 1), - QgsPointXY(4, 1), QgsPointXY(4, 0), ]] + [ + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 2), + QgsPointXY(0, 2), + QgsPointXY(0, 0), + ] + ], + [ + [ + QgsPointXY(4, 0), + QgsPointXY(5, 0), + QgsPointXY(5, 2), + QgsPointXY(3, 2), + QgsPointXY(3, 1), + QgsPointXY(4, 1), + QgsPointXY(4, 0), + ] + ], ] ) - (point, atVertex, beforeVertex, afterVertex, dist) = polygon.closestVertex(QgsPointXY(4.1, 1.1)) + (point, atVertex, beforeVertex, afterVertex, dist) = polygon.closestVertex( + QgsPointXY(4.1, 1.1) + ) self.assertEqual(point, QgsPointXY(4, 1)) self.assertEqual(beforeVertex, 11) self.assertEqual(atVertex, 12) self.assertEqual(afterVertex, 13) assert abs(dist - 0.02) < 0.00001, f"Expected: {dist:f}; Got:{0.02:f}" - (dist, minDistPoint, afterVertex, leftOf) = polygon.closestSegmentWithContext(QgsPointXY(4.1, 1.1)) + (dist, minDistPoint, afterVertex, leftOf) = polygon.closestSegmentWithContext( + QgsPointXY(4.1, 1.1) + ) self.assertEqual(afterVertex, 12) self.assertEqual(minDistPoint, QgsPointXY(4, 1)) exp = 0.02 assert abs(dist - exp) < 0.00001, f"Expected: {exp:f}; Got:{dist:f}" self.assertEqual(leftOf, -1) - (point, atVertex, beforeVertex, afterVertex, dist) = polygon.closestVertex(QgsPointXY()) + (point, atVertex, beforeVertex, afterVertex, dist) = polygon.closestVertex( + QgsPointXY() + ) self.assertTrue(point.isEmpty()) self.assertEqual(dist, -1) - (point, atVertex, beforeVertex, afterVertex, dist) = QgsGeometry().closestVertex(QgsPointXY(42, 42)) + (point, atVertex, beforeVertex, afterVertex, dist) = ( + QgsGeometry().closestVertex(QgsPointXY(42, 42)) + ) self.assertTrue(point.isEmpty()) def testAdjacentVertex(self): @@ -1499,54 +1977,113 @@ def testAdjacentVertex(self): # | # 1-+-+-+-+-0 ! polyline = QgsGeometry.fromPolylineXY( - [QgsPointXY(5, 0), QgsPointXY(0, 0), QgsPointXY(0, 4), QgsPointXY(5, 4), QgsPointXY(5, 1), QgsPointXY(1, 1), - QgsPointXY(1, 3), QgsPointXY(4, 3), QgsPointXY(4, 2), QgsPointXY(2, 2)] + [ + QgsPointXY(5, 0), + QgsPointXY(0, 0), + QgsPointXY(0, 4), + QgsPointXY(5, 4), + QgsPointXY(5, 1), + QgsPointXY(1, 1), + QgsPointXY(1, 3), + QgsPointXY(4, 3), + QgsPointXY(4, 2), + QgsPointXY(2, 2), + ] ) # don't crash (before, after) = polyline.adjacentVertices(-100) - self.assertEqual(before == -1 and after, -1, "Expected (-1,-1), Got:(%d,%d)" % (before, after)) + self.assertEqual( + before == -1 and after, + -1, + "Expected (-1,-1), Got:(%d,%d)" % (before, after), + ) for i in range(0, 10): (before, after) = polyline.adjacentVertices(i) if i == 0: - self.assertEqual(before == -1 and after, 1, "Expected (0,1), Got:(%d,%d)" % (before, after)) + self.assertEqual( + before == -1 and after, + 1, + "Expected (0,1), Got:(%d,%d)" % (before, after), + ) elif i == 9: - self.assertEqual(before == i - 1 and after, -1, "Expected (0,1), Got:(%d,%d)" % (before, after)) + self.assertEqual( + before == i - 1 and after, + -1, + "Expected (0,1), Got:(%d,%d)" % (before, after), + ) else: - self.assertEqual(before == i - 1 and after, i + 1, "Expected (0,1), Got:(%d,%d)" % (before, after)) + self.assertEqual( + before == i - 1 and after, + i + 1, + "Expected (0,1), Got:(%d,%d)" % (before, after), + ) (before, after) = polyline.adjacentVertices(100) - self.assertEqual(before == -1 and after, -1, "Expected (-1,-1), Got:(%d,%d)" % (before, after)) + self.assertEqual( + before == -1 and after, + -1, + "Expected (-1,-1), Got:(%d,%d)" % (before, after), + ) # 2-3 6-+-7 # | | | | # 0-1 4 5 8-9 polyline = QgsGeometry.fromMultiPolylineXY( [ - [QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 0), ], - [QgsPointXY(3, 0), QgsPointXY(3, 1), QgsPointXY(5, 1), QgsPointXY(5, 0), QgsPointXY(6, 0), ] + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 0), + ], + [ + QgsPointXY(3, 0), + QgsPointXY(3, 1), + QgsPointXY(5, 1), + QgsPointXY(5, 0), + QgsPointXY(6, 0), + ], ] ) (before, after) = polyline.adjacentVertices(-100) - self.assertEqual(before == -1 and after, -1, "Expected (-1,-1), Got:(%d,%d)" % (before, after)) + self.assertEqual( + before == -1 and after, + -1, + "Expected (-1,-1), Got:(%d,%d)" % (before, after), + ) for i in range(0, 10): (before, after) = polyline.adjacentVertices(i) if i == 0 or i == 5: - self.assertEqual(before == -1 and after, i + 1, - "Expected (-1,%d), Got:(%d,%d)" % (i + 1, before, after)) + self.assertEqual( + before == -1 and after, + i + 1, + "Expected (-1,%d), Got:(%d,%d)" % (i + 1, before, after), + ) elif i == 4 or i == 9: - self.assertEqual(before == i - 1 and after, -1, - "Expected (%d,-1), Got:(%d,%d)" % (i - 1, before, after)) + self.assertEqual( + before == i - 1 and after, + -1, + "Expected (%d,-1), Got:(%d,%d)" % (i - 1, before, after), + ) else: - self.assertEqual(before == i - 1 and after, i + 1, - "Expected (%d,%d), Got:(%d,%d)" % (i - 1, i + 1, before, after)) + self.assertEqual( + before == i - 1 and after, + i + 1, + "Expected (%d,%d), Got:(%d,%d)" % (i - 1, i + 1, before, after), + ) (before, after) = polyline.adjacentVertices(100) - self.assertEqual(before == -1 and after, -1, "Expected (-1,-1), Got:(%d,%d)" % (before, after)) + self.assertEqual( + before == -1 and after, + -1, + "Expected (-1,-1), Got:(%d,%d)" % (before, after), + ) # 5---4 # | | @@ -1554,26 +2091,48 @@ def testAdjacentVertex(self): # | | # 0-1 polygon = QgsGeometry.fromPolygonXY( - [[ - QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), - QgsPointXY(0, 2), QgsPointXY(0, 0), - ]] + [ + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 2), + QgsPointXY(0, 2), + QgsPointXY(0, 0), + ] + ] ) (before, after) = polygon.adjacentVertices(-100) - self.assertEqual(before == -1 and after, -1, "Expected (-1,-1), Got:(%d,%d)" % (before, after)) + self.assertEqual( + before == -1 and after, + -1, + "Expected (-1,-1), Got:(%d,%d)" % (before, after), + ) for i in range(0, 7): (before, after) = polygon.adjacentVertices(i) if i == 0 or i == 6: - self.assertEqual(before == 5 and after, 1, "Expected (5,1), Got:(%d,%d)" % (before, after)) + self.assertEqual( + before == 5 and after, + 1, + "Expected (5,1), Got:(%d,%d)" % (before, after), + ) else: - self.assertEqual(before == i - 1 and after, i + 1, - "Expected (%d,%d), Got:(%d,%d)" % (i - 1, i + 1, before, after)) + self.assertEqual( + before == i - 1 and after, + i + 1, + "Expected (%d,%d), Got:(%d,%d)" % (i - 1, i + 1, before, after), + ) (before, after) = polygon.adjacentVertices(100) - self.assertEqual(before == -1 and after, -1, "Expected (-1,-1), Got:(%d,%d)" % (before, after)) + self.assertEqual( + before == -1 and after, + -1, + "Expected (-1,-1), Got:(%d,%d)" % (before, after), + ) # 3-+-+-2 # | | @@ -1584,27 +2143,58 @@ def testAdjacentVertex(self): # 0-+-+-1 polygon = QgsGeometry.fromPolygonXY( [ - [QgsPointXY(0, 0), QgsPointXY(3, 0), QgsPointXY(3, 3), QgsPointXY(0, 3), QgsPointXY(0, 0)], - [QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), QgsPointXY(1, 2), QgsPointXY(1, 1)], + [ + QgsPointXY(0, 0), + QgsPointXY(3, 0), + QgsPointXY(3, 3), + QgsPointXY(0, 3), + QgsPointXY(0, 0), + ], + [ + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 2), + QgsPointXY(1, 2), + QgsPointXY(1, 1), + ], ] ) (before, after) = polygon.adjacentVertices(-100) - self.assertEqual(before == -1 and after, -1, "Expected (-1,-1), Got:(%d,%d)" % (before, after)) + self.assertEqual( + before == -1 and after, + -1, + "Expected (-1,-1), Got:(%d,%d)" % (before, after), + ) for i in range(0, 8): (before, after) = polygon.adjacentVertices(i) if i == 0 or i == 4: - self.assertEqual(before == 3 and after, 1, "Expected (3,1), Got:(%d,%d)" % (before, after)) + self.assertEqual( + before == 3 and after, + 1, + "Expected (3,1), Got:(%d,%d)" % (before, after), + ) elif i == 5: - self.assertEqual(before == 8 and after, 6, "Expected (2,0), Got:(%d,%d)" % (before, after)) + self.assertEqual( + before == 8 and after, + 6, + "Expected (2,0), Got:(%d,%d)" % (before, after), + ) else: - self.assertEqual(before == i - 1 and after, i + 1, - "Expected (%d,%d), Got:(%d,%d)" % (i - 1, i + 1, before, after)) + self.assertEqual( + before == i - 1 and after, + i + 1, + "Expected (%d,%d), Got:(%d,%d)" % (i - 1, i + 1, before, after), + ) (before, after) = polygon.adjacentVertices(100) - self.assertEqual(before == -1 and after, -1, "Expected (-1,-1), Got:(%d,%d)" % (before, after)) + self.assertEqual( + before == -1 and after, + -1, + "Expected (-1,-1), Got:(%d,%d)" % (before, after), + ) # 5-+-4 0-+-9 # | | | | @@ -1613,29 +2203,66 @@ def testAdjacentVertex(self): # 0-1 7-8 polygon = QgsGeometry.fromMultiPolygonXY( [ - [[QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), - QgsPointXY(0, 2), QgsPointXY(0, 0), ]], - [[QgsPointXY(4, 0), QgsPointXY(5, 0), QgsPointXY(5, 2), QgsPointXY(3, 2), QgsPointXY(3, 1), - QgsPointXY(4, 1), QgsPointXY(4, 0), ]] + [ + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 2), + QgsPointXY(0, 2), + QgsPointXY(0, 0), + ] + ], + [ + [ + QgsPointXY(4, 0), + QgsPointXY(5, 0), + QgsPointXY(5, 2), + QgsPointXY(3, 2), + QgsPointXY(3, 1), + QgsPointXY(4, 1), + QgsPointXY(4, 0), + ] + ], ] ) (before, after) = polygon.adjacentVertices(-100) - self.assertEqual(before == -1 and after, -1, "Expected (-1,-1), Got:(%d,%d)" % (before, after)) + self.assertEqual( + before == -1 and after, + -1, + "Expected (-1,-1), Got:(%d,%d)" % (before, after), + ) for i in range(0, 14): (before, after) = polygon.adjacentVertices(i) if i == 0 or i == 6: - self.assertEqual(before == 5 and after, 1, "Expected (5,1), Got:(%d,%d)" % (before, after)) + self.assertEqual( + before == 5 and after, + 1, + "Expected (5,1), Got:(%d,%d)" % (before, after), + ) elif i == 7 or i == 13: - self.assertEqual(before == 12 and after, 8, "Expected (12,8), Got:(%d,%d)" % (before, after)) + self.assertEqual( + before == 12 and after, + 8, + "Expected (12,8), Got:(%d,%d)" % (before, after), + ) else: - self.assertEqual(before == i - 1 and after, i + 1, - "Expected (%d,%d), Got:(%d,%d)" % (i - 1, i + 1, before, after)) + self.assertEqual( + before == i - 1 and after, + i + 1, + "Expected (%d,%d), Got:(%d,%d)" % (i - 1, i + 1, before, after), + ) (before, after) = polygon.adjacentVertices(100) - self.assertEqual(before == -1 and after, -1, "Expected (-1,-1), Got:(%d,%d)" % (before, after)) + self.assertEqual( + before == -1 and after, + -1, + "Expected (-1,-1), Got:(%d,%d)" % (before, after), + ) def testVertexAt(self): # 2-+-+-+-+-3 @@ -1647,29 +2274,59 @@ def testVertexAt(self): # ! 5-+-+-+-4 ! # | # 1-+-+-+-+-0 ! - points = [QgsPointXY(5, 0), QgsPointXY(0, 0), QgsPointXY(0, 4), QgsPointXY(5, 4), QgsPointXY(5, 1), - QgsPointXY(1, 1), QgsPointXY(1, 3), QgsPointXY(4, 3), QgsPointXY(4, 2), QgsPointXY(2, 2)] + points = [ + QgsPointXY(5, 0), + QgsPointXY(0, 0), + QgsPointXY(0, 4), + QgsPointXY(5, 4), + QgsPointXY(5, 1), + QgsPointXY(1, 1), + QgsPointXY(1, 3), + QgsPointXY(4, 3), + QgsPointXY(4, 2), + QgsPointXY(2, 2), + ] polyline = QgsGeometry.fromPolylineXY(points) for i in range(0, len(points)): # WORKAROUND to avoid a system error # self.assertEqual(QgsPoint(points[i]), polyline.vertexAt(i), "Mismatch at %d" % i) - self.assertEqual(QgsPoint(points[i].x(), points[i].y()), polyline.vertexAt(i), "Mismatch at %d" % i) + self.assertEqual( + QgsPoint(points[i].x(), points[i].y()), + polyline.vertexAt(i), + "Mismatch at %d" % i, + ) # 2-3 6-+-7 # | | | | # 0-1 4 5 8-9 points = [ - [QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 0), ], - [QgsPointXY(3, 0), QgsPointXY(3, 1), QgsPointXY(5, 1), QgsPointXY(5, 0), QgsPointXY(6, 0), ] + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 0), + ], + [ + QgsPointXY(3, 0), + QgsPointXY(3, 1), + QgsPointXY(5, 1), + QgsPointXY(5, 0), + QgsPointXY(6, 0), + ], ] polyline = QgsGeometry.fromMultiPolylineXY(points) p = polyline.vertexAt(-100) - self.assertEqual(p, QgsPoint(math.nan, math.nan), f"Expected 0,0, Got {p.x()}.{p.y()}") + self.assertEqual( + p, QgsPoint(math.nan, math.nan), f"Expected 0,0, Got {p.x()}.{p.y()}" + ) p = polyline.vertexAt(100) - self.assertEqual(p, QgsPoint(math.nan, math.nan), f"Expected 0,0, Got {p.x()}.{p.y()}") + self.assertEqual( + p, QgsPoint(math.nan, math.nan), f"Expected 0,0, Got {p.x()}.{p.y()}" + ) i = 0 for j in range(0, len(points)): @@ -1677,7 +2334,11 @@ def testVertexAt(self): # WORKAROUND # self.assertEqual(QgsPoint(points[j][k]), polyline.vertexAt(i), "Mismatch at %d / %d,%d" % (i, j, k)) pt = points[j][k] - self.assertEqual(QgsPoint(pt.x(), pt.y()), polyline.vertexAt(i), "Mismatch at %d / %d,%d" % (i, j, k)) + self.assertEqual( + QgsPoint(pt.x(), pt.y()), + polyline.vertexAt(i), + "Mismatch at %d / %d,%d" % (i, j, k), + ) i += 1 # 5---4 @@ -1685,10 +2346,17 @@ def testVertexAt(self): # | 2-3 # | | # 0-1 - points = [[ - QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), QgsPointXY(0, 2), - QgsPointXY(0, 0), - ]] + points = [ + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 2), + QgsPointXY(0, 2), + QgsPointXY(0, 0), + ] + ] polygon = QgsGeometry.fromPolygonXY(points) p = polygon.vertexAt(-100) @@ -1703,7 +2371,11 @@ def testVertexAt(self): # WORKAROUND # self.assertEqual(QgsPoint(points[j][k]), polygon.vertexAt(i), "Mismatch at %d / %d,%d" % (i, j, k)) pt = points[j][k] - self.assertEqual(QgsPoint(pt.x(), pt.y()), polygon.vertexAt(i), "Mismatch at %d / %d,%d" % (i, j, k)) + self.assertEqual( + QgsPoint(pt.x(), pt.y()), + polygon.vertexAt(i), + "Mismatch at %d / %d,%d" % (i, j, k), + ) i += 1 # 3-+-+-2 @@ -1714,8 +2386,20 @@ def testVertexAt(self): # | | # 0-+-+-1 points = [ - [QgsPointXY(0, 0), QgsPointXY(3, 0), QgsPointXY(3, 3), QgsPointXY(0, 3), QgsPointXY(0, 0)], - [QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), QgsPointXY(1, 2), QgsPointXY(1, 1)], + [ + QgsPointXY(0, 0), + QgsPointXY(3, 0), + QgsPointXY(3, 3), + QgsPointXY(0, 3), + QgsPointXY(0, 0), + ], + [ + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 2), + QgsPointXY(1, 2), + QgsPointXY(1, 1), + ], ] polygon = QgsGeometry.fromPolygonXY(points) @@ -1731,7 +2415,11 @@ def testVertexAt(self): # WORKAROUND # self.assertEqual(QgsPoint(points[j][k]), polygon.vertexAt(i), "Mismatch at %d / %d,%d" % (i, j, k)) pt = points[j][k] - self.assertEqual(QgsPoint(pt.x(), pt.y()), polygon.vertexAt(i), "Mismatch at %d / %d,%d" % (i, j, k)) + self.assertEqual( + QgsPoint(pt.x(), pt.y()), + polygon.vertexAt(i), + "Mismatch at %d / %d,%d" % (i, j, k), + ) i += 1 # 5-+-4 0-+-9 @@ -1740,10 +2428,28 @@ def testVertexAt(self): # | | | | # 0-1 7-8 points = [ - [[QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), - QgsPointXY(0, 2), QgsPointXY(0, 0), ]], - [[QgsPointXY(4, 0), QgsPointXY(5, 0), QgsPointXY(5, 2), QgsPointXY(3, 2), QgsPointXY(3, 1), - QgsPointXY(4, 1), QgsPointXY(4, 0), ]] + [ + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 2), + QgsPointXY(0, 2), + QgsPointXY(0, 0), + ] + ], + [ + [ + QgsPointXY(4, 0), + QgsPointXY(5, 0), + QgsPointXY(5, 2), + QgsPointXY(3, 2), + QgsPointXY(3, 1), + QgsPointXY(4, 1), + QgsPointXY(4, 0), + ] + ], ] polygon = QgsGeometry.fromMultiPolygonXY(points) @@ -1762,25 +2468,44 @@ def testVertexAt(self): # WORKAROUND # self.assertEqual(QgsPoint(points[j][k][l]), p, "Got {},{} Expected {} at {} / {},{},{}".format(p.x(), p.y(), points[j][k][l].toString(), i, j, k, l)) pt = points[j][k][l] - self.assertEqual(QgsPoint(pt.x(), pt.y()), p, - "Got {},{} Expected {} at {} / {},{},{}".format(p.x(), p.y(), pt.toString(), i, j, - k, l)) + self.assertEqual( + QgsPoint(pt.x(), pt.y()), + p, + "Got {},{} Expected {} at {} / {},{},{}".format( + p.x(), p.y(), pt.toString(), i, j, k, l + ), + ) i += 1 def testMultipoint(self): # #9423 - points = [QgsPointXY(10, 30), QgsPointXY(40, 20), QgsPointXY(30, 10), QgsPointXY(20, 10)] + points = [ + QgsPointXY(10, 30), + QgsPointXY(40, 20), + QgsPointXY(30, 10), + QgsPointXY(20, 10), + ] wkt = "MultiPoint ((10 30),(40 20),(30 10),(20 10))" multipoint = QgsGeometry.fromWkt(wkt) assert multipoint.isMultipart(), "Expected MultiPoint to be multipart" - self.assertEqual(multipoint.wkbType(), QgsWkbTypes.Type.MultiPoint, "Expected wkbType to be WKBMultipoint") + self.assertEqual( + multipoint.wkbType(), + QgsWkbTypes.Type.MultiPoint, + "Expected wkbType to be WKBMultipoint", + ) i = 0 for p in multipoint.asMultiPoint(): - self.assertEqual(p, points[i], "Expected %s at %d, got %s" % (points[i].toString(), i, p.toString())) + self.assertEqual( + p, + points[i], + "Expected %s at %d, got %s" % (points[i].toString(), i, p.toString()), + ) i += 1 multipoint = QgsGeometry.fromWkt("MultiPoint ((5 5))") - self.assertEqual(multipoint.vertexAt(0), QgsPoint(5, 5), "MULTIPOINT fromWkt failed") + self.assertEqual( + multipoint.vertexAt(0), QgsPoint(5, 5), "MULTIPOINT fromWkt failed" + ) assert multipoint.insertVertex(4, 4, 0), "MULTIPOINT insert 4,4 at 0 failed" expwkt = "MultiPoint ((4 4),(5 5))" @@ -1797,8 +2522,12 @@ def testMultipoint(self): wkt = multipoint.asWkt() assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" - assert not multipoint.deleteVertex(4), "MULTIPOINT delete at 4 unexpectedly succeeded" - assert not multipoint.deleteVertex(-1), "MULTIPOINT delete at -1 unexpectedly succeeded" + assert not multipoint.deleteVertex( + 4 + ), "MULTIPOINT delete at 4 unexpectedly succeeded" + assert not multipoint.deleteVertex( + -1 + ), "MULTIPOINT delete at -1 unexpectedly succeeded" assert multipoint.deleteVertex(1), "MULTIPOINT delete at 1 failed" expwkt = "MultiPoint ((4 4),(6 6),(7 7))" @@ -1816,15 +2545,25 @@ def testMultipoint(self): assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" multipoint = QgsGeometry.fromWkt("MultiPoint ((5 5))") - self.assertEqual(multipoint.vertexAt(0), QgsPoint(5, 5), "MultiPoint fromWkt failed") + self.assertEqual( + multipoint.vertexAt(0), QgsPoint(5, 5), "MultiPoint fromWkt failed" + ) def testMoveVertex(self): - multipoint = QgsGeometry.fromWkt("MultiPoint ((5 0),(0 0),(0 4),(5 4),(5 1),(1 1),(1 3),(4 3),(4 2),(2 2))") + multipoint = QgsGeometry.fromWkt( + "MultiPoint ((5 0),(0 0),(0 4),(5 4),(5 1),(1 1),(1 3),(4 3),(4 2),(2 2))" + ) # try moving invalid vertices - assert not multipoint.moveVertex(9, 9, -1), "move vertex succeeded when it should have failed" - assert not multipoint.moveVertex(9, 9, 10), "move vertex succeeded when it should have failed" - assert not multipoint.moveVertex(9, 9, 11), "move vertex succeeded when it should have failed" + assert not multipoint.moveVertex( + 9, 9, -1 + ), "move vertex succeeded when it should have failed" + assert not multipoint.moveVertex( + 9, 9, 10 + ), "move vertex succeeded when it should have failed" + assert not multipoint.moveVertex( + 9, 9, 11 + ), "move vertex succeeded when it should have failed" for i in range(0, 10): assert multipoint.moveVertex(i + 1, -1 - i, i), "move vertex %d failed" % i @@ -1841,12 +2580,20 @@ def testMoveVertex(self): # ! 5-+-+-+-4 ! # | # 1-+-+-+-+-0 ! - polyline = QgsGeometry.fromWkt("LineString (5 0, 0 0, 0 4, 5 4, 5 1, 1 1, 1 3, 4 3, 4 2, 2 2)") + polyline = QgsGeometry.fromWkt( + "LineString (5 0, 0 0, 0 4, 5 4, 5 1, 1 1, 1 3, 4 3, 4 2, 2 2)" + ) # try moving invalid vertices - assert not polyline.moveVertex(9, 9, -1), "move vertex succeeded when it should have failed" - assert not polyline.moveVertex(9, 9, 10), "move vertex succeeded when it should have failed" - assert not polyline.moveVertex(9, 9, 11), "move vertex succeeded when it should have failed" + assert not polyline.moveVertex( + 9, 9, -1 + ), "move vertex succeeded when it should have failed" + assert not polyline.moveVertex( + 9, 9, 10 + ), "move vertex succeeded when it should have failed" + assert not polyline.moveVertex( + 9, 9, 11 + ), "move vertex succeeded when it should have failed" assert polyline.moveVertex(5.5, 4.5, 3), "move vertex failed" expwkt = "LineString (5 0, 0 0, 0 4, 5.5 4.5, 5 1, 1 1, 1 3, 4 3, 4 2, 2 2)" @@ -1885,7 +2632,8 @@ def testMoveVertex(self): # | | | | # 0-1 7-8 polygon = QgsGeometry.fromWkt( - "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))") + "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))" + ) assert not polygon.moveVertex(3, 4, -10), "move vertex unexpectedly succeeded" assert not polygon.moveVertex(3, 4, 14), "move vertex unexpectedly succeeded" @@ -1916,33 +2664,45 @@ def testDeleteVertex(self): # ! 5-+-+-+-4 # | # 1-+-+-+-+-0 - polyline = QgsGeometry.fromWkt("LineString (5 0, 0 0, 0 4, 5 4, 5 1, 1 1, 1 3, 4 3, 4 2, 2 2)") + polyline = QgsGeometry.fromWkt( + "LineString (5 0, 0 0, 0 4, 5 4, 5 1, 1 1, 1 3, 4 3, 4 2, 2 2)" + ) assert polyline.deleteVertex(3), "Delete vertex 5 4 failed" expwkt = "LineString (5 0, 0 0, 0 4, 5 1, 1 1, 1 3, 4 3, 4 2, 2 2)" wkt = polyline.asWkt() assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" assert not polyline.deleteVertex(-5), "Delete vertex -5 unexpectedly succeeded" - assert not polyline.deleteVertex(100), "Delete vertex 100 unexpectedly succeeded" + assert not polyline.deleteVertex( + 100 + ), "Delete vertex 100 unexpectedly succeeded" # 2-3 6-+-7 # | | | | # 0-1 4 5 8-9 - polyline = QgsGeometry.fromWkt("MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0),(3 0, 3 1, 5 1, 5 0, 6 0))") + polyline = QgsGeometry.fromWkt( + "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0),(3 0, 3 1, 5 1, 5 0, 6 0))" + ) assert polyline.deleteVertex(5), "Delete vertex 5 failed" expwkt = "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0), (3 1, 5 1, 5 0, 6 0))" wkt = polyline.asWkt() assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" - assert not polyline.deleteVertex(-100), "Delete vertex -100 unexpectedly succeeded" - assert not polyline.deleteVertex(100), "Delete vertex 100 unexpectedly succeeded" + assert not polyline.deleteVertex( + -100 + ), "Delete vertex -100 unexpectedly succeeded" + assert not polyline.deleteVertex( + 100 + ), "Delete vertex 100 unexpectedly succeeded" assert polyline.deleteVertex(0), "Delete vertex 0 failed" expwkt = "MultiLineString ((1 0, 1 1, 2 1, 2 0), (3 1, 5 1, 5 0, 6 0))" wkt = polyline.asWkt() assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" - polyline = QgsGeometry.fromWkt("MultiLineString ((0 0, 1 0, 1 1, 2 1,2 0),(3 0, 3 1, 5 1, 5 0, 6 0))") + polyline = QgsGeometry.fromWkt( + "MultiLineString ((0 0, 1 0, 1 1, 2 1,2 0),(3 0, 3 1, 5 1, 5 0, 6 0))" + ) for i in range(4): assert polyline.deleteVertex(5), "Delete vertex 5 failed" expwkt = "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0))" @@ -1972,7 +2732,9 @@ def testDeleteVertex(self): wkt = polygon.asWkt() assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" - assert not polygon.deleteVertex(-100), "Delete vertex -100 unexpectedly succeeded" + assert not polygon.deleteVertex( + -100 + ), "Delete vertex -100 unexpectedly succeeded" assert not polygon.deleteVertex(100), "Delete vertex 100 unexpectedly succeeded" # 5-+-4 0-+-9 @@ -1981,7 +2743,8 @@ def testDeleteVertex(self): # | | | | # 0-1 7-8 polygon = QgsGeometry.fromWkt( - "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))") + "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))" + ) assert polygon.deleteVertex(9), "Delete vertex 5 2 failed" expwkt = "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 3 2, 3 1, 4 1, 4 0)))" wkt = polygon.asWkt() @@ -1998,7 +2761,8 @@ def testDeleteVertex(self): assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" polygon = QgsGeometry.fromWkt( - "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))") + "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))" + ) for i in range(4): assert polygon.deleteVertex(0), "Delete vertex 0 failed" @@ -2014,7 +2778,8 @@ def testDeleteVertex(self): # | | # 0-+-+-+-+---+-+-+-1 polygon = QgsGeometry.fromWkt( - "Polygon ((0 0, 9 0, 9 3, 0 3, 0 0),(1 1, 2 1, 2 2, 1 2, 1 1),(3 1, 4 1, 4 2, 3 2, 3 1),(5 1, 6 1, 6 2, 5 2, 5 1),(7 1, 8 1, 8 2, 7 2, 7 1))") + "Polygon ((0 0, 9 0, 9 3, 0 3, 0 0),(1 1, 2 1, 2 2, 1 2, 1 1),(3 1, 4 1, 4 2, 3 2, 3 1),(5 1, 6 1, 6 2, 5 2, 5 1),(7 1, 8 1, 8 2, 7 2, 7 1))" + ) # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 for i in range(2): @@ -2033,7 +2798,9 @@ def testDeleteVertex(self): assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" # Remove whole outer ring, inner ring should become outer - polygon = QgsGeometry.fromWkt("Polygon ((0 0, 9 0, 9 3, 0 3, 0 0),(1 1, 2 1, 2 2, 1 2, 1 1))") + polygon = QgsGeometry.fromWkt( + "Polygon ((0 0, 9 0, 9 3, 0 3, 0 0),(1 1, 2 1, 2 2, 1 2, 1 1))" + ) for i in range(2): assert polygon.deleteVertex(0), "Delete vertex 16 failed" % i @@ -2054,17 +2821,21 @@ def testInsertVertex(self): wkt = linestring.asWkt() assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" - assert not linestring.insertVertex(3, 0, 5), "Insert vertex 3 0 at 5 should have failed" + assert not linestring.insertVertex( + 3, 0, 5 + ), "Insert vertex 3 0 at 5 should have failed" polygon = QgsGeometry.fromWkt( - "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))") + "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))" + ) assert polygon.insertVertex(0, 0, 8), "Insert vertex 0 0 at 8 failed" expwkt = "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 0 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))" wkt = polygon.asWkt() assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" polygon = QgsGeometry.fromWkt( - "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))") + "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))" + ) assert polygon.insertVertex(0, 0, 7), "Insert vertex 0 0 at 7 failed" expwkt = "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((0 0, 4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 0 0)))" wkt = polygon.asWkt() @@ -2090,7 +2861,8 @@ def testTranslate(self): assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" polygon = QgsGeometry.fromWkt( - "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))") + "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))" + ) self.assertEqual(polygon.translate(1, 2), 0, "Translate failed") expwkt = "MultiPolygon (((1 2, 2 2, 2 3, 3 3, 3 4, 1 4, 1 2)),((5 2, 6 2, 6 4, 4 4, 4 3, 5 3, 5 2)))" wkt = polygon.asWkt() @@ -2118,16 +2890,20 @@ def testTransform(self): wkt = linestring.asWkt() assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" - polygon = QgsGeometry.fromWkt("MultiPolygon(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),((4 0,5 0,5 2,3 2,3 1,4 1,4 0)))") + polygon = QgsGeometry.fromWkt( + "MultiPolygon(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),((4 0,5 0,5 2,3 2,3 1,4 1,4 0)))" + ) self.assertEqual(polygon.transform(ct), 0, "Transform failed") expwkt = "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))" wkt = polygon.asWkt() assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" # valid transform - ct = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'), - QgsCoordinateReferenceSystem('EPSG:3857'), - QgsProject.instance()) + ct = QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsProject.instance(), + ) point = QgsGeometry.fromWkt("Point (1 1)") self.assertEqual(point.transform(ct), 0, "Transform failed") @@ -2147,7 +2923,9 @@ def testTransform(self): wkt = linestring.asWkt() assert compareWkt(expwkt, wkt, tol=100), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" - polygon = QgsGeometry.fromWkt("MultiPolygon(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),((4 0,5 0,5 2,3 2,3 1,4 1,4 0)))") + polygon = QgsGeometry.fromWkt( + "MultiPolygon(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),((4 0,5 0,5 2,3 2,3 1,4 1,4 0)))" + ) self.assertEqual(polygon.transform(ct), 0, "Transform failed") expwkt = "MultiPolygon (((0 0, 111319 0, 111319 111325, 222638 111325, 222638 222684, 0 222684, 0 0)),((445277 0, 556597 0, 556597 222684, 333958 222684, 333958 111325, 445277 111325, 445277 0)))" wkt = polygon.asWkt() @@ -2155,26 +2933,53 @@ def testTransform(self): # reverse transform point = QgsGeometry.fromWkt("Point (111319 111325)") - self.assertEqual(point.transform(ct, QgsCoordinateTransform.TransformDirection.ReverseTransform), 0, "Transform failed") + self.assertEqual( + point.transform( + ct, QgsCoordinateTransform.TransformDirection.ReverseTransform + ), + 0, + "Transform failed", + ) expwkt = "Point (1 1)" wkt = point.asWkt() assert compareWkt(expwkt, wkt, tol=0.01), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" - point = QgsGeometry.fromWkt("MultiPoint ((111319 111325),(222638 222684),(333958 334111))") - self.assertEqual(point.transform(ct, QgsCoordinateTransform.TransformDirection.ReverseTransform), 0, "Transform failed") + point = QgsGeometry.fromWkt( + "MultiPoint ((111319 111325),(222638 222684),(333958 334111))" + ) + self.assertEqual( + point.transform( + ct, QgsCoordinateTransform.TransformDirection.ReverseTransform + ), + 0, + "Transform failed", + ) expwkt = "MultiPoint ((1 1),(2 2),(3 3))" wkt = point.asWkt() assert compareWkt(expwkt, wkt, tol=0.01), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" linestring = QgsGeometry.fromWkt("LineString (111319 0, 222638 0)") - self.assertEqual(linestring.transform(ct, QgsCoordinateTransform.TransformDirection.ReverseTransform), 0, "Transform failed") + self.assertEqual( + linestring.transform( + ct, QgsCoordinateTransform.TransformDirection.ReverseTransform + ), + 0, + "Transform failed", + ) expwkt = "LineString (1 0, 2 0)" wkt = linestring.asWkt() assert compareWkt(expwkt, wkt, tol=0.01), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" polygon = QgsGeometry.fromWkt( - "MultiPolygon (((0 0, 111319 0, 111319 111325, 222638 111325, 222638 222684, 0 222684, 0 0)),((445277 0, 556597 0, 556597 222684, 333958 222684, 333958 111325, 445277 111325, 445277 0)))") - self.assertEqual(polygon.transform(ct, QgsCoordinateTransform.TransformDirection.ReverseTransform), 0, "Transform failed") + "MultiPolygon (((0 0, 111319 0, 111319 111325, 222638 111325, 222638 222684, 0 222684, 0 0)),((445277 0, 556597 0, 556597 222684, 333958 222684, 333958 111325, 445277 111325, 445277 0)))" + ) + self.assertEqual( + polygon.transform( + ct, QgsCoordinateTransform.TransformDirection.ReverseTransform + ), + 0, + "Transform failed", + ) expwkt = "MultiPolygon(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),((4 0,5 0,5 2,3 2,3 1,4 1,4 0)))" wkt = polygon.asWkt() assert compareWkt(expwkt, wkt, tol=0.01), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" @@ -2186,12 +2991,17 @@ def testExtrude(self): points = [QgsPointXY(1, 2), QgsPointXY(3, 2), QgsPointXY(4, 3)] line = QgsGeometry.fromPolylineXY(points) - expected = QgsGeometry.fromWkt('Polygon ((1 2, 3 2, 4 3, 5 5, 4 4, 2 4, 1 2))') + expected = QgsGeometry.fromWkt("Polygon ((1 2, 3 2, 4 3, 5 5, 4 4, 2 4, 1 2))") self.assertEqual(line.extrude(1, 2).asWkt(), expected.asWkt()) - points2 = [[QgsPointXY(1, 2), QgsPointXY(3, 2)], [QgsPointXY(4, 3), QgsPointXY(8, 3)]] + points2 = [ + [QgsPointXY(1, 2), QgsPointXY(3, 2)], + [QgsPointXY(4, 3), QgsPointXY(8, 3)], + ] multiline = QgsGeometry.fromMultiPolylineXY(points2) - expected = QgsGeometry.fromWkt('MultiPolygon (((1 2, 3 2, 4 4, 2 4, 1 2)),((4 3, 8 3, 9 5, 5 5, 4 3)))') + expected = QgsGeometry.fromWkt( + "MultiPolygon (((1 2, 3 2, 4 4, 2 4, 1 2)),((4 3, 8 3, 9 5, 5 5, 4 3)))" + ) self.assertEqual(multiline.extrude(1, 2).asWkt(), expected.asWkt()) def testNearestPoint(self): @@ -2199,37 +3009,45 @@ def testNearestPoint(self): g1 = QgsGeometry() g2 = QgsGeometry() self.assertTrue(g1.nearestPoint(g2).isNull()) - g1 = QgsGeometry.fromWkt('LineString( 1 1, 5 1, 5 5 )') + g1 = QgsGeometry.fromWkt("LineString( 1 1, 5 1, 5 5 )") self.assertTrue(g1.nearestPoint(g2).isNull()) self.assertTrue(g2.nearestPoint(g1).isNull()) - g2 = QgsGeometry.fromWkt('Point( 6 3 )') - expWkt = 'Point( 5 3 )' + g2 = QgsGeometry.fromWkt("Point( 6 3 )") + expWkt = "Point( 5 3 )" wkt = g1.nearestPoint(g2).asWkt() self.assertTrue(compareWkt(expWkt, wkt), f"Expected:\n{expWkt}\nGot:\n{wkt}\n") - expWkt = 'Point( 6 3 )' + expWkt = "Point( 6 3 )" wkt = g2.nearestPoint(g1).asWkt() self.assertTrue(compareWkt(expWkt, wkt), f"Expected:\n{expWkt}\nGot:\n{wkt}\n") - g1 = QgsGeometry.fromWkt('Polygon ((1 1, 5 1, 5 5, 1 5, 1 1))') - g2 = QgsGeometry.fromWkt('Point( 6 3 )') - expWkt = 'Point( 5 3 )' + g1 = QgsGeometry.fromWkt("Polygon ((1 1, 5 1, 5 5, 1 5, 1 1))") + g2 = QgsGeometry.fromWkt("Point( 6 3 )") + expWkt = "Point( 5 3 )" wkt = g1.nearestPoint(g2).asWkt() self.assertTrue(compareWkt(expWkt, wkt), f"Expected:\n{expWkt}\nGot:\n{wkt}\n") - expWkt = 'Point( 6 3 )' + expWkt = "Point( 6 3 )" wkt = g2.nearestPoint(g1).asWkt() self.assertTrue(compareWkt(expWkt, wkt), f"Expected:\n{expWkt}\nGot:\n{wkt}\n") - g2 = QgsGeometry.fromWkt('Point( 2 3 )') - expWkt = 'Point( 2 3 )' + g2 = QgsGeometry.fromWkt("Point( 2 3 )") + expWkt = "Point( 2 3 )" wkt = g1.nearestPoint(g2).asWkt() self.assertTrue(compareWkt(expWkt, wkt), f"Expected:\n{expWkt}\nGot:\n{wkt}\n") # trivial point case - expWkt = 'Point (3 4)' - wkt = QgsGeometry.fromWkt('Point(3 4)').nearestPoint(QgsGeometry.fromWkt('Point(-1 -8)')).asWkt() + expWkt = "Point (3 4)" + wkt = ( + QgsGeometry.fromWkt("Point(3 4)") + .nearestPoint(QgsGeometry.fromWkt("Point(-1 -8)")) + .asWkt() + ) self.assertTrue(compareWkt(expWkt, wkt), f"Expected:\n{expWkt}\nGot:\n{wkt}\n") - wkt = QgsGeometry.fromWkt('Point(3 4)').nearestPoint(QgsGeometry.fromWkt('LineString( 1 1, 5 1, 5 5 )')).asWkt() + wkt = ( + QgsGeometry.fromWkt("Point(3 4)") + .nearestPoint(QgsGeometry.fromWkt("LineString( 1 1, 5 1, 5 5 )")) + .asWkt() + ) self.assertTrue(compareWkt(expWkt, wkt), f"Expected:\n{expWkt}\nGot:\n{wkt}\n") def testShortestLine(self): @@ -2237,35 +3055,39 @@ def testShortestLine(self): g1 = QgsGeometry() g2 = QgsGeometry() self.assertTrue(g1.shortestLine(g2).isNull()) - g1 = QgsGeometry.fromWkt('LineString( 1 1, 5 1, 5 5 )') + g1 = QgsGeometry.fromWkt("LineString( 1 1, 5 1, 5 5 )") self.assertTrue(g1.shortestLine(g2).isNull()) self.assertTrue(g2.shortestLine(g1).isNull()) - g2 = QgsGeometry.fromWkt('Point( 6 3 )') - expWkt = 'LineString( 5 3, 6 3 )' + g2 = QgsGeometry.fromWkt("Point( 6 3 )") + expWkt = "LineString( 5 3, 6 3 )" wkt = g1.shortestLine(g2).asWkt() self.assertTrue(compareWkt(expWkt, wkt), f"Expected:\n{expWkt}\nGot:\n{wkt}\n") - expWkt = 'LineString( 6 3, 5 3 )' + expWkt = "LineString( 6 3, 5 3 )" wkt = g2.shortestLine(g1).asWkt() self.assertTrue(compareWkt(expWkt, wkt), f"Expected:\n{expWkt}\nGot:\n{wkt}\n") - g1 = QgsGeometry.fromWkt('Polygon ((1 1, 5 1, 5 5, 1 5, 1 1))') - g2 = QgsGeometry.fromWkt('Point( 6 3 )') - expWkt = 'LineString( 5 3, 6 3 )' + g1 = QgsGeometry.fromWkt("Polygon ((1 1, 5 1, 5 5, 1 5, 1 1))") + g2 = QgsGeometry.fromWkt("Point( 6 3 )") + expWkt = "LineString( 5 3, 6 3 )" wkt = g1.shortestLine(g2).asWkt() self.assertTrue(compareWkt(expWkt, wkt), f"Expected:\n{expWkt}\nGot:\n{wkt}\n") - expWkt = 'LineString( 6 3, 5 3 )' + expWkt = "LineString( 6 3, 5 3 )" wkt = g2.shortestLine(g1).asWkt() self.assertTrue(compareWkt(expWkt, wkt), f"Expected:\n{expWkt}\nGot:\n{wkt}\n") - g2 = QgsGeometry.fromWkt('Point( 2 3 )') - expWkt = 'LineString( 2 3, 2 3 )' + g2 = QgsGeometry.fromWkt("Point( 2 3 )") + expWkt = "LineString( 2 3, 2 3 )" wkt = g1.shortestLine(g2).asWkt() self.assertTrue(compareWkt(expWkt, wkt), f"Expected:\n{expWkt}\nGot:\n{wkt}\n") # trivial point to point case - expWkt = 'LineString (3 4, -1 -8)' - wkt = QgsGeometry.fromWkt('Point(3 4)').shortestLine(QgsGeometry.fromWkt('Point(-1 -8)')).asWkt() + expWkt = "LineString (3 4, -1 -8)" + wkt = ( + QgsGeometry.fromWkt("Point(3 4)") + .shortestLine(QgsGeometry.fromWkt("Point(-1 -8)")) + .asWkt() + ) self.assertTrue(compareWkt(expWkt, wkt), f"Expected:\n{expWkt}\nGot:\n{wkt}\n") def testBoundingBox(self): @@ -2278,38 +3100,73 @@ def testBoundingBox(self): # ! 5-+-+-+-4 ! # | # 1-+-+-+-+-0 ! - points = [QgsPointXY(5, 0), QgsPointXY(0, 0), QgsPointXY(0, 4), QgsPointXY(5, 4), QgsPointXY(5, 1), - QgsPointXY(1, 1), QgsPointXY(1, 3), QgsPointXY(4, 3), QgsPointXY(4, 2), QgsPointXY(2, 2)] + points = [ + QgsPointXY(5, 0), + QgsPointXY(0, 0), + QgsPointXY(0, 4), + QgsPointXY(5, 4), + QgsPointXY(5, 1), + QgsPointXY(1, 1), + QgsPointXY(1, 3), + QgsPointXY(4, 3), + QgsPointXY(4, 2), + QgsPointXY(2, 2), + ] polyline = QgsGeometry.fromPolylineXY(points) expbb = QgsRectangle(0, 0, 5, 4) bb = polyline.boundingBox() - self.assertEqual(expbb, bb, f"Expected:\n{expbb.toString()}\nGot:\n{bb.toString()}\n") + self.assertEqual( + expbb, bb, f"Expected:\n{expbb.toString()}\nGot:\n{bb.toString()}\n" + ) # 2-3 6-+-7 # | | | | # 0-1 4 5 8-9 points = [ - [QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 0), ], - [QgsPointXY(3, 0), QgsPointXY(3, 1), QgsPointXY(5, 1), QgsPointXY(5, 0), QgsPointXY(6, 0), ] + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 0), + ], + [ + QgsPointXY(3, 0), + QgsPointXY(3, 1), + QgsPointXY(5, 1), + QgsPointXY(5, 0), + QgsPointXY(6, 0), + ], ] polyline = QgsGeometry.fromMultiPolylineXY(points) expbb = QgsRectangle(0, 0, 6, 1) bb = polyline.boundingBox() - self.assertEqual(expbb, bb, f"Expected:\n{expbb.toString()}\nGot:\n{bb.toString()}\n") + self.assertEqual( + expbb, bb, f"Expected:\n{expbb.toString()}\nGot:\n{bb.toString()}\n" + ) # 5---4 # | | # | 2-3 # | | # 0-1 - points = [[ - QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), QgsPointXY(0, 2), - QgsPointXY(0, 0), - ]] + points = [ + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 2), + QgsPointXY(0, 2), + QgsPointXY(0, 0), + ] + ] polygon = QgsGeometry.fromPolygonXY(points) expbb = QgsRectangle(0, 0, 2, 2) bb = polygon.boundingBox() - self.assertEqual(expbb, bb, f"Expected:\n{expbb.toString()}\nGot:\n{bb.toString()}\n") + self.assertEqual( + expbb, bb, f"Expected:\n{expbb.toString()}\nGot:\n{bb.toString()}\n" + ) # 3-+-+-2 # | | @@ -2319,13 +3176,27 @@ def testBoundingBox(self): # | | # 0-+-+-1 points = [ - [QgsPointXY(0, 0), QgsPointXY(3, 0), QgsPointXY(3, 3), QgsPointXY(0, 3), QgsPointXY(0, 0)], - [QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), QgsPointXY(1, 2), QgsPointXY(1, 1)], + [ + QgsPointXY(0, 0), + QgsPointXY(3, 0), + QgsPointXY(3, 3), + QgsPointXY(0, 3), + QgsPointXY(0, 0), + ], + [ + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 2), + QgsPointXY(1, 2), + QgsPointXY(1, 1), + ], ] polygon = QgsGeometry.fromPolygonXY(points) expbb = QgsRectangle(0, 0, 3, 3) bb = polygon.boundingBox() - self.assertEqual(expbb, bb, f"Expected:\n{expbb.toString()}\nGot:\n{bb.toString()}\n") + self.assertEqual( + expbb, bb, f"Expected:\n{expbb.toString()}\nGot:\n{bb.toString()}\n" + ) # 5-+-4 0-+-9 # | | | | @@ -2333,16 +3204,36 @@ def testBoundingBox(self): # | | | | # 0-1 7-8 points = [ - [[QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), - QgsPointXY(0, 2), QgsPointXY(0, 0), ]], - [[QgsPointXY(4, 0), QgsPointXY(5, 0), QgsPointXY(5, 2), QgsPointXY(3, 2), QgsPointXY(3, 1), - QgsPointXY(4, 1), QgsPointXY(4, 0), ]] + [ + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 2), + QgsPointXY(0, 2), + QgsPointXY(0, 0), + ] + ], + [ + [ + QgsPointXY(4, 0), + QgsPointXY(5, 0), + QgsPointXY(5, 2), + QgsPointXY(3, 2), + QgsPointXY(3, 1), + QgsPointXY(4, 1), + QgsPointXY(4, 0), + ] + ], ] polygon = QgsGeometry.fromMultiPolygonXY(points) expbb = QgsRectangle(0, 0, 5, 2) bb = polygon.boundingBox() - self.assertEqual(expbb, bb, f"Expected:\n{expbb.toString()}\nGot:\n{bb.toString()}\n") + self.assertEqual( + expbb, bb, f"Expected:\n{expbb.toString()}\nGot:\n{bb.toString()}\n" + ) # NULL points = [] @@ -2360,29 +3251,55 @@ def testBoundingBox3D(self): box3D_geom = QgsGeometry.fromBox3D(box3D) result = box3D_geom.boundingBox3D() self.assertEqual( - box3D, result, - f"Expected:\n{box3D.toString()}\nGot:\n{result.toString()}\n") + box3D, result, f"Expected:\n{box3D.toString()}\nGot:\n{result.toString()}\n" + ) # 2D polyline - points = [QgsPointXY(5, 0), QgsPointXY(0, 0), QgsPointXY(0, 4), QgsPointXY(5, 4), QgsPointXY(5, 1), - QgsPointXY(1, 1), QgsPointXY(1, 3), QgsPointXY(4, 3), QgsPointXY(4, 2), QgsPointXY(2, 2)] + points = [ + QgsPointXY(5, 0), + QgsPointXY(0, 0), + QgsPointXY(0, 4), + QgsPointXY(5, 4), + QgsPointXY(5, 1), + QgsPointXY(1, 1), + QgsPointXY(1, 3), + QgsPointXY(4, 3), + QgsPointXY(4, 2), + QgsPointXY(2, 2), + ] polyline2D = QgsGeometry.fromPolylineXY(points) expbb2D = QgsBox3D(0, 0, float("nan"), 5, 4, float("nan")) bb2D = polyline2D.boundingBox3D() self.assertEqual( - expbb2D, bb2D, f"Expected:\n{expbb2D.toString()}\nGot:\n{bb2D.toString()}\n") + expbb2D, bb2D, f"Expected:\n{expbb2D.toString()}\nGot:\n{bb2D.toString()}\n" + ) # 3D polyline - points = [QgsPoint(5, 0, -3), QgsPoint(0, 0, 5), QgsPoint(0, 4, -3), QgsPoint(5, 4, 0), QgsPoint(5, 1, 1), - QgsPoint(1, 1, 2), QgsPoint(1, 3, 5), QgsPoint(4, 3, 9), QgsPoint(4, 2, -6), QgsPoint(2, 2, 8)] + points = [ + QgsPoint(5, 0, -3), + QgsPoint(0, 0, 5), + QgsPoint(0, 4, -3), + QgsPoint(5, 4, 0), + QgsPoint(5, 1, 1), + QgsPoint(1, 1, 2), + QgsPoint(1, 3, 5), + QgsPoint(4, 3, 9), + QgsPoint(4, 2, -6), + QgsPoint(2, 2, 8), + ] polyline3D = QgsGeometry.fromPolyline(points) expbb3D = QgsBox3D(0, 0, -6, 5, 4, 9) bb3D = polyline3D.boundingBox3D() - self.assertEqual(expbb3D, bb3D, f"Expected:\n{expbb3D.toString()}\nGot:\n{bb3D.toString()}\n") + self.assertEqual( + expbb3D, bb3D, f"Expected:\n{expbb3D.toString()}\nGot:\n{bb3D.toString()}\n" + ) def testCollectGeometry(self): # collect points - geometries = [QgsGeometry.fromPointXY(QgsPointXY(0, 0)), QgsGeometry.fromPointXY(QgsPointXY(1, 1))] + geometries = [ + QgsGeometry.fromPointXY(QgsPointXY(0, 0)), + QgsGeometry.fromPointXY(QgsPointXY(1, 1)), + ] geometry = QgsGeometry.collectGeometry(geometries) expwkt = "MultiPoint ((0 0), (1 1))" wkt = geometry.asWkt() @@ -2391,9 +3308,12 @@ def testCollectGeometry(self): # collect lines points = [ [QgsPointXY(0, 0), QgsPointXY(1, 0)], - [QgsPointXY(2, 0), QgsPointXY(3, 0)] + [QgsPointXY(2, 0), QgsPointXY(3, 0)], + ] + geometries = [ + QgsGeometry.fromPolylineXY(points[0]), + QgsGeometry.fromPolylineXY(points[1]), ] - geometries = [QgsGeometry.fromPolylineXY(points[0]), QgsGeometry.fromPolylineXY(points[1])] geometry = QgsGeometry.collectGeometry(geometries) expwkt = "MultiLineString ((0 0, 1 0), (2 0, 3 0))" wkt = geometry.asWkt() @@ -2401,46 +3321,87 @@ def testCollectGeometry(self): # collect polygons points = [ - [[QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(0, 1), QgsPointXY(0, 0)]], - [[QgsPointXY(2, 0), QgsPointXY(3, 0), QgsPointXY(3, 1), QgsPointXY(2, 1), QgsPointXY(2, 0)]] + [ + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(0, 1), + QgsPointXY(0, 0), + ] + ], + [ + [ + QgsPointXY(2, 0), + QgsPointXY(3, 0), + QgsPointXY(3, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 0), + ] + ], + ] + geometries = [ + QgsGeometry.fromPolygonXY(points[0]), + QgsGeometry.fromPolygonXY(points[1]), ] - geometries = [QgsGeometry.fromPolygonXY(points[0]), QgsGeometry.fromPolygonXY(points[1])] geometry = QgsGeometry.collectGeometry(geometries) - expwkt = "MultiPolygon (((0 0, 1 0, 1 1, 0 1, 0 0)),((2 0, 3 0, 3 1, 2 1, 2 0)))" + expwkt = ( + "MultiPolygon (((0 0, 1 0, 1 1, 0 1, 0 0)),((2 0, 3 0, 3 1, 2 1, 2 0)))" + ) wkt = geometry.asWkt() assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" # collect some geometries which are already multipart - geometries = [QgsGeometry.fromWkt('LineString( 0 0, 1 1)'), - QgsGeometry.fromWkt('MultiLineString((2 2, 3 3),(4 4, 5 5))')] + geometries = [ + QgsGeometry.fromWkt("LineString( 0 0, 1 1)"), + QgsGeometry.fromWkt("MultiLineString((2 2, 3 3),(4 4, 5 5))"), + ] geometry = QgsGeometry.collectGeometry(geometries) expwkt = "MultiLineString ((0 0, 1 1),(2 2, 3 3),(4 4, 5 5))" wkt = geometry.asWkt() assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" - geometries = [QgsGeometry.fromWkt('MultiLineString((2 2, 3 3),(4 4, 5 5))'), - QgsGeometry.fromWkt('LineString( 0 0, 1 1)')] + geometries = [ + QgsGeometry.fromWkt("MultiLineString((2 2, 3 3),(4 4, 5 5))"), + QgsGeometry.fromWkt("LineString( 0 0, 1 1)"), + ] geometry = QgsGeometry.collectGeometry(geometries) expwkt = "MultiLineString ((2 2, 3 3),(4 4, 5 5),(0 0, 1 1))" wkt = geometry.asWkt() assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" - geometries = [QgsGeometry.fromWkt('Polygon((100 100, 101 100, 101 101, 100 100))'), - QgsGeometry.fromWkt('MultiPolygon (((0 0, 1 0, 1 1, 0 1, 0 0)),((2 0, 3 0, 3 1, 2 1, 2 0)))')] + geometries = [ + QgsGeometry.fromWkt("Polygon((100 100, 101 100, 101 101, 100 100))"), + QgsGeometry.fromWkt( + "MultiPolygon (((0 0, 1 0, 1 1, 0 1, 0 0)),((2 0, 3 0, 3 1, 2 1, 2 0)))" + ), + ] geometry = QgsGeometry.collectGeometry(geometries) expwkt = "MultiPolygon (((100 100, 101 100, 101 101, 100 100)),((0 0, 1 0, 1 1, 0 1, 0 0)),((2 0, 3 0, 3 1, 2 1, 2 0)))" wkt = geometry.asWkt() assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" - geometries = [QgsGeometry.fromWkt('MultiPolygon (((0 0, 1 0, 1 1, 0 1, 0 0)),((2 0, 3 0, 3 1, 2 1, 2 0)))'), - QgsGeometry.fromWkt('Polygon((100 100, 101 100, 101 101, 100 100))')] + geometries = [ + QgsGeometry.fromWkt( + "MultiPolygon (((0 0, 1 0, 1 1, 0 1, 0 0)),((2 0, 3 0, 3 1, 2 1, 2 0)))" + ), + QgsGeometry.fromWkt("Polygon((100 100, 101 100, 101 101, 100 100))"), + ] geometry = QgsGeometry.collectGeometry(geometries) expwkt = "MultiPolygon (((0 0, 1 0, 1 1, 0 1, 0 0)),((2 0, 3 0, 3 1, 2 1, 2 0)),((100 100, 101 100, 101 101, 100 100)))" wkt = geometry.asWkt() assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" - geometries = [QgsGeometry(QgsTriangle(QgsPoint(0, 0, 5), QgsPoint(1, 0, 6), QgsPoint(1, 1, 7))), - QgsGeometry(QgsTriangle(QgsPoint(100, 100, 9), QgsPoint(101, 100, -1), QgsPoint(101, 101, 4)))] + geometries = [ + QgsGeometry( + QgsTriangle(QgsPoint(0, 0, 5), QgsPoint(1, 0, 6), QgsPoint(1, 1, 7)) + ), + QgsGeometry( + QgsTriangle( + QgsPoint(100, 100, 9), QgsPoint(101, 100, -1), QgsPoint(101, 101, 4) + ) + ), + ] geometry = QgsGeometry.collectGeometry(geometries) expwkt = "MultiPolygonZ (((0 0 5, 1 0 6, 1 1 7, 0 0 5)),((100 100 9, 101 100 -1, 101 101 4, 100 100 9)))" wkt = geometry.asWkt() @@ -2452,7 +3413,7 @@ def testCollectGeometry(self): assert geometry.isNull(), "Expected geometry to be empty" # check that the resulting geometry is multi - geometry = QgsGeometry.collectGeometry([QgsGeometry.fromWkt('Point (0 0)')]) + geometry = QgsGeometry.collectGeometry([QgsGeometry.fromWkt("Point (0 0)")]) assert geometry.isMultipart(), "Expected collected geometry to be multipart" def testAddPartV2(self): @@ -2460,11 +3421,27 @@ def testAddPartV2(self): # | | | | # 0-1 4 5 8-9 line_points = [ - [QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 0), ], - [QgsPointXY(3, 0), QgsPointXY(3, 1), QgsPointXY(5, 1), QgsPointXY(5, 0), QgsPointXY(6, 0), ] + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 0), + ], + [ + QgsPointXY(3, 0), + QgsPointXY(3, 1), + QgsPointXY(5, 1), + QgsPointXY(5, 0), + QgsPointXY(6, 0), + ], ] - def polyline1_geom(): return QgsGeometry.fromPolylineXY(line_points[0]) # noqa: E704,E261 - def polyline2_geom(): return QgsGeometry.fromPolylineXY(line_points[1]) # noqa: E704,E261 + + def polyline1_geom(): + return QgsGeometry.fromPolylineXY(line_points[0]) # noqa: E704,E261 + + def polyline2_geom(): + return QgsGeometry.fromPolylineXY(line_points[1]) # noqa: E704,E261 # 5-+-4 0-+-9 # | | | | @@ -2472,16 +3449,44 @@ def polyline2_geom(): return QgsGeometry.fromPolylineXY(line_points[1]) # noqa: # | | | | # 0-1 7-8 poly_points = [ - [[QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), - QgsPointXY(0, 2), QgsPointXY(0, 0), ]], - [[QgsPointXY(4, 0), QgsPointXY(5, 0), QgsPointXY(5, 2), QgsPointXY(3, 2), QgsPointXY(3, 1), - QgsPointXY(4, 1), QgsPointXY(4, 0), ]] + [ + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 2), + QgsPointXY(0, 2), + QgsPointXY(0, 0), + ] + ], + [ + [ + QgsPointXY(4, 0), + QgsPointXY(5, 0), + QgsPointXY(5, 2), + QgsPointXY(3, 2), + QgsPointXY(3, 1), + QgsPointXY(4, 1), + QgsPointXY(4, 0), + ] + ], ] - def polygon1_geom(): return QgsGeometry.fromPolygonXY(poly_points[0]) # noqa: E704,E261 - def polygon2_geom(): return QgsGeometry.fromPolygonXY(poly_points[1]) # noqa: E704,E261 - def multi_polygon_geom(): return QgsGeometry.fromMultiPolygonXY(poly_points) # noqa: E704,E261 - def multi_polygon1_geom(): return QgsGeometry.fromMultiPolygonXY(poly_points[:1]) # noqa: E704,E261 - def multi_polygon2_geom(): return QgsGeometry.fromMultiPolygonXY(poly_points[1:]) # noqa: E704,E261 + + def polygon1_geom(): + return QgsGeometry.fromPolygonXY(poly_points[0]) # noqa: E704,E261 + + def polygon2_geom(): + return QgsGeometry.fromPolygonXY(poly_points[1]) # noqa: E704,E261 + + def multi_polygon_geom(): + return QgsGeometry.fromMultiPolygonXY(poly_points) # noqa: E704,E261 + + def multi_polygon1_geom(): + return QgsGeometry.fromMultiPolygonXY(poly_points[:1]) # noqa: E704,E261 + + def multi_polygon2_geom(): + return QgsGeometry.fromMultiPolygonXY(poly_points[1:]) # noqa: E704,E261 def multi_surface_geom(): ms = QgsMultiSurface() @@ -2512,164 +3517,225 @@ def circle_curvepolygon(): types = {} # optional geometry types for points added resul = {} # expected GeometryOperationResult - T = 'point_add_point' + T = "point_add_point" geoms[T] = QgsGeometry.fromPointXY(QgsPointXY(0, 0)) parts[T] = [QgsPointXY(1, 0)] expec[T] = "MultiPoint ((0 0), (1 0))" - T = 'point_add_point_with_Z' + T = "point_add_point_with_Z" geoms[T] = QgsGeometry(QgsPoint(0, 0, 4)) parts[T] = [QgsPoint(1, 0, 3, wkbType=QgsWkbTypes.Type.PointZ)] expec[T] = "MultiPointZ ((0 0 4), (1 0 3))" - T = 'line_add_1_point_fails' + T = "line_add_1_point_fails" geoms[T] = polyline1_geom() parts[T] = line_points[1][0:1] resul[T] = QgsGeometry.OperationResult.InvalidInputGeometryType - T = 'line_add_2_point' + T = "line_add_2_point" geoms[T] = polyline1_geom() parts[T] = line_points[1][0:2] expec[T] = "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0), (3 0, 3 1))" - T = 'add_point_with_more_points' + T = "add_point_with_more_points" geoms[T] = polyline1_geom() parts[T] = line_points[1] - expec[T] = "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0), (3 0, 3 1, 5 1, 5 0, 6 0))" + expec[T] = ( + "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0), (3 0, 3 1, 5 1, 5 0, 6 0))" + ) - T = 'line_add_points_with_Z' + T = "line_add_points_with_Z" geoms[T] = polyline1_geom() geoms[T].get().addZValue(4.0) - parts[T] = [QgsPoint(p[0], p[1], 3.0, wkbType=QgsWkbTypes.Type.PointZ) for p in line_points[1]] - expec[T] = "MultiLineString Z ((0 0 4, 1 0 4, 1 1 4, 2 1 4, 2 0 4),(3 0 3, 3 1 3, 5 1 3, 5 0 3, 6 0 3))" + parts[T] = [ + QgsPoint(p[0], p[1], 3.0, wkbType=QgsWkbTypes.Type.PointZ) + for p in line_points[1] + ] + expec[T] = ( + "MultiLineString Z ((0 0 4, 1 0 4, 1 1 4, 2 1 4, 2 0 4),(3 0 3, 3 1 3, 5 1 3, 5 0 3, 6 0 3))" + ) - T = 'linestring_add_curve' + T = "linestring_add_curve" geoms[T] = polyline1_geom() parts[T] = curve() - expec[T] = f"MultiLineString ({polyline1_geom().asWkt()[len('LineString '):]},{curve().curveToLine().asWkt()[len('LineString '):]})" + expec[T] = ( + f"MultiLineString ({polyline1_geom().asWkt()[len('LineString '):]},{curve().curveToLine().asWkt()[len('LineString '):]})" + ) - T = 'polygon_add_ring_1_point' + T = "polygon_add_ring_1_point" geoms[T] = polygon1_geom() parts[T] = poly_points[1][0][0:1] resul[T] = QgsGeometry.OperationResult.InvalidInputGeometryType - T = 'polygon_add_ring_2_points' + T = "polygon_add_ring_2_points" geoms[T] = polygon1_geom() parts[T] = poly_points[1][0][0:2] resul[T] = QgsGeometry.OperationResult.InvalidInputGeometryType - T = 'polygon_add_ring_3_points' + T = "polygon_add_ring_3_points" geoms[T] = polygon1_geom() parts[T] = poly_points[1][0][0:3] resul[T] = QgsGeometry.OperationResult.InvalidInputGeometryType - T = 'polygon_add_ring_3_points_closed' + T = "polygon_add_ring_3_points_closed" geoms[T] = polygon1_geom() parts[T] = [QgsPointXY(4, 0), QgsPointXY(5, 0), QgsPointXY(4, 0)] resul[T] = QgsGeometry.OperationResult.InvalidInputGeometryType - T = 'polygon_add_polygon' + T = "polygon_add_polygon" geoms[T] = polygon1_geom() parts[T] = poly_points[1][0] - expec[T] = "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))" + expec[T] = ( + "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))" + ) - T = 'multipolygon_add_polygon' + T = "multipolygon_add_polygon" geoms[T] = multi_polygon1_geom() parts[T] = polygon2_geom() expec[T] = multi_polygon_geom().asWkt() - T = 'multipolygon_add_multipolygon' + T = "multipolygon_add_multipolygon" geoms[T] = multi_polygon1_geom() parts[T] = multi_polygon2_geom() expec[T] = multi_polygon_geom().asWkt() - T = 'polygon_add_point_with_Z' + T = "polygon_add_point_with_Z" geoms[T] = polygon1_geom() geoms[T].get().addZValue(4.0) - parts[T] = [QgsPoint(pi[0], pi[1], 3.0, wkbType=QgsWkbTypes.Type.PointZ) for pi in poly_points[1][0]] - expec[T] = "MultiPolygonZ (((0 0 4, 1 0 4, 1 1 4, 2 1 4, 2 2 4, 0 2 4, 0 0 4)),((4 0 3, 5 0 3, 5 2 3, 3 2 3, 3 1 3, 4 1 3, 4 0 3)))" + parts[T] = [ + QgsPoint(pi[0], pi[1], 3.0, wkbType=QgsWkbTypes.Type.PointZ) + for pi in poly_points[1][0] + ] + expec[T] = ( + "MultiPolygonZ (((0 0 4, 1 0 4, 1 1 4, 2 1 4, 2 2 4, 0 2 4, 0 0 4)),((4 0 3, 5 0 3, 5 2 3, 3 2 3, 3 1 3, 4 1 3, 4 0 3)))" + ) - T = 'multisurface_add_curvepolygon' - geoms[T] = QgsGeometry.fromWkt('MultiSurface(((0 0,0 1,1 1,0 0)))') - parts[T] = QgsGeometry.fromWkt('CurvePolygon ((0 0,0 1,1 1,0 0))') - expec[T] = 'MultiSurface (Polygon ((0 0, 0 1, 1 1, 0 0)),CurvePolygon ((0 0, 0 1, 1 1, 0 0)))' + T = "multisurface_add_curvepolygon" + geoms[T] = QgsGeometry.fromWkt("MultiSurface(((0 0,0 1,1 1,0 0)))") + parts[T] = QgsGeometry.fromWkt("CurvePolygon ((0 0,0 1,1 1,0 0))") + expec[T] = ( + "MultiSurface (Polygon ((0 0, 0 1, 1 1, 0 0)),CurvePolygon ((0 0, 0 1, 1 1, 0 0)))" + ) - T = 'multisurface_add_multisurface' - geoms[T] = QgsGeometry.fromWkt('MultiSurface(((20 0,20 1,21 1,20 0)))') - parts[T] = QgsGeometry.fromWkt('MultiSurface (Polygon ((0 0, 0 1, 1 1, 0 0)),CurvePolygon ((0 0, 0 1, 1 1, 0 0)))') - expec[T] = 'MultiSurface (Polygon ((20 0, 20 1, 21 1, 20 0)),Polygon ((0 0, 0 1, 1 1, 0 0)),CurvePolygon ((0 0, 0 1, 1 1, 0 0)))' + T = "multisurface_add_multisurface" + geoms[T] = QgsGeometry.fromWkt("MultiSurface(((20 0,20 1,21 1,20 0)))") + parts[T] = QgsGeometry.fromWkt( + "MultiSurface (Polygon ((0 0, 0 1, 1 1, 0 0)),CurvePolygon ((0 0, 0 1, 1 1, 0 0)))" + ) + expec[T] = ( + "MultiSurface (Polygon ((20 0, 20 1, 21 1, 20 0)),Polygon ((0 0, 0 1, 1 1, 0 0)),CurvePolygon ((0 0, 0 1, 1 1, 0 0)))" + ) - T = 'empty_geom_add_point_with_no_default_type' + T = "empty_geom_add_point_with_no_default_type" # if not default type specified, addPart should fail geoms[T] = QgsGeometry() parts[T] = [QgsPointXY(4, 0)] resul[T] = Qgis.GeometryOperationResult.AddPartNotMultiGeometry - T = 'empty_geom_add_point' + T = "empty_geom_add_point" geoms[T] = QgsGeometry() parts[T] = [QgsPointXY(4, 0)] types[T] = QgsWkbTypes.Type.Point - expec[T] = 'MultiPoint ((4 0))' + expec[T] = "MultiPoint ((4 0))" - T = 'empty_geom_add_line' + T = "empty_geom_add_line" geoms[T] = QgsGeometry() parts[T] = poly_points[0][0] types[T] = QgsWkbTypes.Type.LineString - expec[T] = 'MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0))' + expec[T] = "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0))" - T = 'empty_geom_add_polygon' + T = "empty_geom_add_polygon" geoms[T] = QgsGeometry() parts[T] = poly_points[0][0] types[T] = QgsWkbTypes.Type.Polygon - expec[T] = 'MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)))' + expec[T] = "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)))" - T = 'multipolygon_add_curvepolygon' + T = "multipolygon_add_curvepolygon" geoms[T] = multi_polygon1_geom() parts[T] = circle_curvepolygon() - expec[T] = f"MultiPolygon ({polygon1_geom().asWkt()[len('Polygon '):]},{circle_polygon().asWkt()[len('Polygon '):]})" + expec[T] = ( + f"MultiPolygon ({polygon1_geom().asWkt()[len('Polygon '):]},{circle_polygon().asWkt()[len('Polygon '):]})" + ) - T = 'multisurface_add_curvepolygon' + T = "multisurface_add_curvepolygon" geoms[T] = multi_surface_geom() parts[T] = circle_curvepolygon() - expec[T] = 'MultiSurface (Polygon ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),CurvePolygon (CircularString (10 15, 15 10, 10 5, 5 10, 10 15)))' + expec[T] = ( + "MultiSurface (Polygon ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),CurvePolygon (CircularString (10 15, 15 10, 10 5, 5 10, 10 15)))" + ) for t in parts.keys(): with self.subTest(t=t): expected_result = resul.get(t, Qgis.GeometryOperationResult.Success) geom_type = types.get(t, QgsWkbTypes.Type.Unknown) - message = '\n' + t + message = "\n" + t if expected_result != Qgis.MessageLevel.Success: - message += ' unexpectedly succeeded' + message += " unexpectedly succeeded" else: - message += ' failed' - message_with_wkt = message + f'\nOriginal geom: {geoms[t].asWkt()}' + message += " failed" + message_with_wkt = message + f"\nOriginal geom: {geoms[t].asWkt()}" if type(parts[t]) is list: if type(parts[t][0]) is QgsPointXY: - self.assertEqual(geoms[t].addPointsXYV2(parts[t], geom_type), expected_result, message_with_wkt) + self.assertEqual( + geoms[t].addPointsXYV2(parts[t], geom_type), + expected_result, + message_with_wkt, + ) elif type(parts[t][0]) is QgsPoint: - self.assertEqual(geoms[t].addPointsV2(parts[t]), expected_result, message_with_wkt) + self.assertEqual( + geoms[t].addPointsV2(parts[t]), + expected_result, + message_with_wkt, + ) else: - self.fail(message_with_wkt + '\n could not detect what Python method to use for add part') + self.fail( + message_with_wkt + + "\n could not detect what Python method to use for add part" + ) else: if type(parts[t]) is QgsGeometry: - self.assertEqual(geoms[t].addPartGeometry(parts[t]), expected_result, message) + self.assertEqual( + geoms[t].addPartGeometry(parts[t]), expected_result, message + ) else: - self.assertEqual(geoms[t].addPartV2(parts[t], geom_type), expected_result, message_with_wkt) + self.assertEqual( + geoms[t].addPartV2(parts[t], geom_type), + expected_result, + message_with_wkt, + ) if expected_result == Qgis.GeometryOperationResult.Success: wkt = geoms[t].asWkt() - assert compareWkt(expec[t], wkt), message + f"\nExpected:\n{expec[t]}\nGot:\n{wkt}\n" + assert compareWkt(expec[t], wkt), ( + message + f"\nExpected:\n{expec[t]}\nGot:\n{wkt}\n" + ) def testAddPart(self): # 2-3 6-+-7 # | | | | # 0-1 4 5 8-9 line_points = [ - [QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 0), ], - [QgsPointXY(3, 0), QgsPointXY(3, 1), QgsPointXY(5, 1), QgsPointXY(5, 0), QgsPointXY(6, 0), ] + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 0), + ], + [ + QgsPointXY(3, 0), + QgsPointXY(3, 1), + QgsPointXY(5, 1), + QgsPointXY(5, 0), + QgsPointXY(6, 0), + ], ] - def polyline1_geom(): return QgsGeometry.fromPolylineXY(line_points[0]) # noqa: E704,E261 - def polyline2_geom(): return QgsGeometry.fromPolylineXY(line_points[1]) # noqa: E704,E261 + + def polyline1_geom(): + return QgsGeometry.fromPolylineXY(line_points[0]) # noqa: E704,E261 + + def polyline2_geom(): + return QgsGeometry.fromPolylineXY(line_points[1]) # noqa: E704,E261 # 5-+-4 0-+-9 # | | | | @@ -2677,16 +3743,44 @@ def polyline2_geom(): return QgsGeometry.fromPolylineXY(line_points[1]) # noqa: # | | | | # 0-1 7-8 poly_points = [ - [[QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), - QgsPointXY(0, 2), QgsPointXY(0, 0), ]], - [[QgsPointXY(4, 0), QgsPointXY(5, 0), QgsPointXY(5, 2), QgsPointXY(3, 2), QgsPointXY(3, 1), - QgsPointXY(4, 1), QgsPointXY(4, 0), ]] + [ + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 2), + QgsPointXY(0, 2), + QgsPointXY(0, 0), + ] + ], + [ + [ + QgsPointXY(4, 0), + QgsPointXY(5, 0), + QgsPointXY(5, 2), + QgsPointXY(3, 2), + QgsPointXY(3, 1), + QgsPointXY(4, 1), + QgsPointXY(4, 0), + ] + ], ] - def polygon1_geom(): return QgsGeometry.fromPolygonXY(poly_points[0]) # noqa: E704,E261 - def polygon2_geom(): return QgsGeometry.fromPolygonXY(poly_points[1]) # noqa: E704,E261 - def multi_polygon_geom(): return QgsGeometry.fromMultiPolygonXY(poly_points) # noqa: E704,E261 - def multi_polygon1_geom(): return QgsGeometry.fromMultiPolygonXY(poly_points[:1]) # noqa: E704,E261 - def multi_polygon2_geom(): return QgsGeometry.fromMultiPolygonXY(poly_points[1:]) # noqa: E704,E261 + + def polygon1_geom(): + return QgsGeometry.fromPolygonXY(poly_points[0]) # noqa: E704,E261 + + def polygon2_geom(): + return QgsGeometry.fromPolygonXY(poly_points[1]) # noqa: E704,E261 + + def multi_polygon_geom(): + return QgsGeometry.fromMultiPolygonXY(poly_points) # noqa: E704,E261 + + def multi_polygon1_geom(): + return QgsGeometry.fromMultiPolygonXY(poly_points[:1]) # noqa: E704,E261 + + def multi_polygon2_geom(): + return QgsGeometry.fromMultiPolygonXY(poly_points[1:]) # noqa: E704,E261 def multi_surface_geom(): ms = QgsMultiSurface() @@ -2717,153 +3811,198 @@ def circle_curvepolygon(): types = {} # optional geometry types for points added resul = {} # expected GeometryOperationResult - T = 'point_add_point' + T = "point_add_point" geoms[T] = QgsGeometry.fromPointXY(QgsPointXY(0, 0)) parts[T] = [QgsPointXY(1, 0)] expec[T] = "MultiPoint ((0 0), (1 0))" - T = 'point_add_point_with_Z' + T = "point_add_point_with_Z" geoms[T] = QgsGeometry(QgsPoint(0, 0, 4)) parts[T] = [QgsPoint(1, 0, 3, wkbType=QgsWkbTypes.Type.PointZ)] expec[T] = "MultiPointZ ((0 0 4), (1 0 3))" - T = 'line_add_1_point_fails' + T = "line_add_1_point_fails" geoms[T] = polyline1_geom() parts[T] = line_points[1][0:1] resul[T] = QgsGeometry.OperationResult.InvalidInputGeometryType - T = 'line_add_2_point' + T = "line_add_2_point" geoms[T] = polyline1_geom() parts[T] = line_points[1][0:2] expec[T] = "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0), (3 0, 3 1))" - T = 'add_point_with_more_points' + T = "add_point_with_more_points" geoms[T] = polyline1_geom() parts[T] = line_points[1] - expec[T] = "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0), (3 0, 3 1, 5 1, 5 0, 6 0))" + expec[T] = ( + "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0), (3 0, 3 1, 5 1, 5 0, 6 0))" + ) - T = 'line_add_points_with_Z' + T = "line_add_points_with_Z" geoms[T] = polyline1_geom() geoms[T].get().addZValue(4.0) - parts[T] = [QgsPoint(p[0], p[1], 3.0, wkbType=QgsWkbTypes.Type.PointZ) for p in line_points[1]] - expec[T] = "MultiLineString Z ((0 0 4, 1 0 4, 1 1 4, 2 1 4, 2 0 4),(3 0 3, 3 1 3, 5 1 3, 5 0 3, 6 0 3))" + parts[T] = [ + QgsPoint(p[0], p[1], 3.0, wkbType=QgsWkbTypes.Type.PointZ) + for p in line_points[1] + ] + expec[T] = ( + "MultiLineString Z ((0 0 4, 1 0 4, 1 1 4, 2 1 4, 2 0 4),(3 0 3, 3 1 3, 5 1 3, 5 0 3, 6 0 3))" + ) - T = 'linestring_add_curve' + T = "linestring_add_curve" geoms[T] = polyline1_geom() parts[T] = curve() - expec[T] = f"MultiLineString ({polyline1_geom().asWkt()[len('LineString '):]},{curve().curveToLine().asWkt()[len('LineString '):]})" + expec[T] = ( + f"MultiLineString ({polyline1_geom().asWkt()[len('LineString '):]},{curve().curveToLine().asWkt()[len('LineString '):]})" + ) - T = 'polygon_add_ring_1_point' + T = "polygon_add_ring_1_point" geoms[T] = polygon1_geom() parts[T] = poly_points[1][0][0:1] resul[T] = QgsGeometry.OperationResult.InvalidInputGeometryType - T = 'polygon_add_ring_2_points' + T = "polygon_add_ring_2_points" geoms[T] = polygon1_geom() parts[T] = poly_points[1][0][0:2] resul[T] = QgsGeometry.OperationResult.InvalidInputGeometryType - T = 'polygon_add_ring_3_points' + T = "polygon_add_ring_3_points" geoms[T] = polygon1_geom() parts[T] = poly_points[1][0][0:3] resul[T] = QgsGeometry.OperationResult.InvalidInputGeometryType - T = 'polygon_add_ring_3_points_closed' + T = "polygon_add_ring_3_points_closed" geoms[T] = polygon1_geom() parts[T] = [QgsPointXY(4, 0), QgsPointXY(5, 0), QgsPointXY(4, 0)] resul[T] = QgsGeometry.OperationResult.InvalidInputGeometryType - T = 'polygon_add_polygon' + T = "polygon_add_polygon" geoms[T] = polygon1_geom() parts[T] = poly_points[1][0] - expec[T] = "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))" + expec[T] = ( + "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))" + ) - T = 'multipolygon_add_polygon' + T = "multipolygon_add_polygon" geoms[T] = multi_polygon1_geom() parts[T] = polygon2_geom() expec[T] = multi_polygon_geom().asWkt() - T = 'multipolygon_add_multipolygon' + T = "multipolygon_add_multipolygon" geoms[T] = multi_polygon1_geom() parts[T] = multi_polygon2_geom() expec[T] = multi_polygon_geom().asWkt() - T = 'polygon_add_point_with_Z' + T = "polygon_add_point_with_Z" geoms[T] = polygon1_geom() geoms[T].get().addZValue(4.0) - parts[T] = [QgsPoint(pi[0], pi[1], 3.0, wkbType=QgsWkbTypes.Type.PointZ) for pi in poly_points[1][0]] - expec[T] = "MultiPolygonZ (((0 0 4, 1 0 4, 1 1 4, 2 1 4, 2 2 4, 0 2 4, 0 0 4)),((4 0 3, 5 0 3, 5 2 3, 3 2 3, 3 1 3, 4 1 3, 4 0 3)))" + parts[T] = [ + QgsPoint(pi[0], pi[1], 3.0, wkbType=QgsWkbTypes.Type.PointZ) + for pi in poly_points[1][0] + ] + expec[T] = ( + "MultiPolygonZ (((0 0 4, 1 0 4, 1 1 4, 2 1 4, 2 2 4, 0 2 4, 0 0 4)),((4 0 3, 5 0 3, 5 2 3, 3 2 3, 3 1 3, 4 1 3, 4 0 3)))" + ) - T = 'multisurface_add_curvepolygon' - geoms[T] = QgsGeometry.fromWkt('MultiSurface(((0 0,0 1,1 1,0 0)))') - parts[T] = QgsGeometry.fromWkt('CurvePolygon ((0 0,0 1,1 1,0 0))') - expec[T] = 'MultiSurface (Polygon ((0 0, 0 1, 1 1, 0 0)),CurvePolygon ((0 0, 0 1, 1 1, 0 0)))' + T = "multisurface_add_curvepolygon" + geoms[T] = QgsGeometry.fromWkt("MultiSurface(((0 0,0 1,1 1,0 0)))") + parts[T] = QgsGeometry.fromWkt("CurvePolygon ((0 0,0 1,1 1,0 0))") + expec[T] = ( + "MultiSurface (Polygon ((0 0, 0 1, 1 1, 0 0)),CurvePolygon ((0 0, 0 1, 1 1, 0 0)))" + ) - T = 'multisurface_add_multisurface' - geoms[T] = QgsGeometry.fromWkt('MultiSurface(((20 0,20 1,21 1,20 0)))') - parts[T] = QgsGeometry.fromWkt('MultiSurface (Polygon ((0 0, 0 1, 1 1, 0 0)),CurvePolygon ((0 0, 0 1, 1 1, 0 0)))') - expec[T] = 'MultiSurface (Polygon ((20 0, 20 1, 21 1, 20 0)),Polygon ((0 0, 0 1, 1 1, 0 0)),CurvePolygon ((0 0, 0 1, 1 1, 0 0)))' + T = "multisurface_add_multisurface" + geoms[T] = QgsGeometry.fromWkt("MultiSurface(((20 0,20 1,21 1,20 0)))") + parts[T] = QgsGeometry.fromWkt( + "MultiSurface (Polygon ((0 0, 0 1, 1 1, 0 0)),CurvePolygon ((0 0, 0 1, 1 1, 0 0)))" + ) + expec[T] = ( + "MultiSurface (Polygon ((20 0, 20 1, 21 1, 20 0)),Polygon ((0 0, 0 1, 1 1, 0 0)),CurvePolygon ((0 0, 0 1, 1 1, 0 0)))" + ) - T = 'empty_geom_add_point_with_no_default_type' + T = "empty_geom_add_point_with_no_default_type" # if not default type specified, addPart should fail geoms[T] = QgsGeometry() parts[T] = [QgsPointXY(4, 0)] resul[T] = Qgis.GeometryOperationResult.AddPartNotMultiGeometry - T = 'empty_geom_add_point' + T = "empty_geom_add_point" geoms[T] = QgsGeometry() parts[T] = [QgsPointXY(4, 0)] types[T] = QgsWkbTypes.GeometryType.PointGeometry - expec[T] = 'MultiPoint ((4 0))' + expec[T] = "MultiPoint ((4 0))" - T = 'empty_geom_add_line' + T = "empty_geom_add_line" geoms[T] = QgsGeometry() parts[T] = poly_points[0][0] types[T] = QgsWkbTypes.GeometryType.LineGeometry - expec[T] = 'MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0))' + expec[T] = "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0))" - T = 'empty_geom_add_polygon' + T = "empty_geom_add_polygon" geoms[T] = QgsGeometry() parts[T] = poly_points[0][0] types[T] = QgsWkbTypes.GeometryType.PolygonGeometry - expec[T] = 'MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)))' + expec[T] = "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)))" - T = 'multipolygon_add_curvepolygon' + T = "multipolygon_add_curvepolygon" geoms[T] = multi_polygon1_geom() parts[T] = circle_curvepolygon() - expec[T] = f"MultiPolygon ({polygon1_geom().asWkt()[len('Polygon '):]},{circle_polygon().asWkt()[len('Polygon '):]})" + expec[T] = ( + f"MultiPolygon ({polygon1_geom().asWkt()[len('Polygon '):]},{circle_polygon().asWkt()[len('Polygon '):]})" + ) - T = 'multisurface_add_curvepolygon' + T = "multisurface_add_curvepolygon" geoms[T] = multi_surface_geom() parts[T] = circle_curvepolygon() - expec[T] = 'MultiSurface (Polygon ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),CurvePolygon (CircularString (10 15, 15 10, 10 5, 5 10, 10 15)))' + expec[T] = ( + "MultiSurface (Polygon ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),CurvePolygon (CircularString (10 15, 15 10, 10 5, 5 10, 10 15)))" + ) for t in parts.keys(): with self.subTest(t=t): expected_result = resul.get(t, Qgis.GeometryOperationResult.Success) geom_type = types.get(t, QgsWkbTypes.GeometryType.UnknownGeometry) - message = '\n' + t + message = "\n" + t if expected_result != Qgis.MessageLevel.Success: - message += ' unexpectedly succeeded' + message += " unexpectedly succeeded" else: - message += ' failed' - message_with_wkt = message + f'\nOriginal geom: {geoms[t].asWkt()}' + message += " failed" + message_with_wkt = message + f"\nOriginal geom: {geoms[t].asWkt()}" if type(parts[t]) is list: if type(parts[t][0]) is QgsPointXY: - self.assertEqual(geoms[t].addPointsXY(parts[t], geom_type), expected_result, message_with_wkt) + self.assertEqual( + geoms[t].addPointsXY(parts[t], geom_type), + expected_result, + message_with_wkt, + ) elif type(parts[t][0]) is QgsPoint: - self.assertEqual(geoms[t].addPoints(parts[t]), expected_result, message_with_wkt) + self.assertEqual( + geoms[t].addPoints(parts[t]), + expected_result, + message_with_wkt, + ) else: - self.fail(message_with_wkt + '\n could not detect what Python method to use for add part') + self.fail( + message_with_wkt + + "\n could not detect what Python method to use for add part" + ) else: if type(parts[t]) is QgsGeometry: - self.assertEqual(geoms[t].addPartGeometry(parts[t]), expected_result, message) + self.assertEqual( + geoms[t].addPartGeometry(parts[t]), expected_result, message + ) else: - self.assertEqual(geoms[t].addPart(parts[t], geom_type), expected_result, message_with_wkt) + self.assertEqual( + geoms[t].addPart(parts[t], geom_type), + expected_result, + message_with_wkt, + ) if expected_result == Qgis.GeometryOperationResult.Success: wkt = geoms[t].asWkt() - assert compareWkt(expec[t], wkt), message + f"\nExpected:\n{expec[t]}\nGot:\n{wkt}\n" + assert compareWkt(expec[t], wkt), ( + message + f"\nExpected:\n{expec[t]}\nGot:\n{wkt}\n" + ) def testConvertToType(self): # 5-+-4 0-+-9 13-+-+-12 @@ -2874,590 +4013,905 @@ def testConvertToType(self): # | | # 10-+-+-11 points = [ - [[QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), - QgsPointXY(0, 2), QgsPointXY(0, 0)], ], - [[QgsPointXY(4, 0), QgsPointXY(5, 0), QgsPointXY(5, 2), QgsPointXY(3, 2), QgsPointXY(3, 1), - QgsPointXY(4, 1), QgsPointXY(4, 0)], ], - [[QgsPointXY(10, 0), QgsPointXY(13, 0), QgsPointXY(13, 3), QgsPointXY(10, 3), QgsPointXY(10, 0)], - [QgsPointXY(11, 1), QgsPointXY(12, 1), QgsPointXY(12, 2), QgsPointXY(11, 2), QgsPointXY(11, 1)]] + [ + [ + QgsPointXY(0, 0), + QgsPointXY(1, 0), + QgsPointXY(1, 1), + QgsPointXY(2, 1), + QgsPointXY(2, 2), + QgsPointXY(0, 2), + QgsPointXY(0, 0), + ], + ], + [ + [ + QgsPointXY(4, 0), + QgsPointXY(5, 0), + QgsPointXY(5, 2), + QgsPointXY(3, 2), + QgsPointXY(3, 1), + QgsPointXY(4, 1), + QgsPointXY(4, 0), + ], + ], + [ + [ + QgsPointXY(10, 0), + QgsPointXY(13, 0), + QgsPointXY(13, 3), + QgsPointXY(10, 3), + QgsPointXY(10, 0), + ], + [ + QgsPointXY(11, 1), + QgsPointXY(12, 1), + QgsPointXY(12, 2), + QgsPointXY(11, 2), + QgsPointXY(11, 1), + ], + ], ] # ####### TO POINT ######## # POINT TO POINT point = QgsGeometry.fromPointXY(QgsPointXY(1, 1)) wkt = point.convertToType(QgsWkbTypes.GeometryType.PointGeometry, False).asWkt() expWkt = "Point (1 1)" - assert compareWkt(expWkt, wkt), "convertToType failed: from point to point. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from point to point. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # POINT TO MultiPoint wkt = point.convertToType(QgsWkbTypes.GeometryType.PointGeometry, True).asWkt() expWkt = "MultiPoint ((1 1))" - assert compareWkt(expWkt, wkt), "convertToType failed: from point to multipoint. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from point to multipoint. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # LINE TO MultiPoint line = QgsGeometry.fromPolylineXY(points[0][0]) wkt = line.convertToType(QgsWkbTypes.GeometryType.PointGeometry, True).asWkt() expWkt = "MultiPoint ((0 0),(1 0),(1 1),(2 1),(2 2),(0 2),(0 0))" - assert compareWkt(expWkt, wkt), "convertToType failed: from line to multipoint. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from line to multipoint. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # MULTILINE TO MultiPoint multiLine = QgsGeometry.fromMultiPolylineXY(points[2]) - wkt = multiLine.convertToType(QgsWkbTypes.GeometryType.PointGeometry, True).asWkt() + wkt = multiLine.convertToType( + QgsWkbTypes.GeometryType.PointGeometry, True + ).asWkt() expWkt = "MultiPoint ((10 0),(13 0),(13 3),(10 3),(10 0),(11 1),(12 1),(12 2),(11 2),(11 1))" - assert compareWkt(expWkt, - wkt), "convertToType failed: from multiline to multipoint. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from multiline to multipoint. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # Polygon TO MultiPoint polygon = QgsGeometry.fromPolygonXY(points[0]) - wkt = polygon.convertToType(QgsWkbTypes.GeometryType.PointGeometry, True).asWkt() + wkt = polygon.convertToType( + QgsWkbTypes.GeometryType.PointGeometry, True + ).asWkt() expWkt = "MultiPoint ((0 0),(1 0),(1 1),(2 1),(2 2),(0 2),(0 0))" - assert compareWkt(expWkt, - wkt), "convertToType failed: from poylgon to multipoint. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from poylgon to multipoint. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # MultiPolygon TO MultiPoint multiPolygon = QgsGeometry.fromMultiPolygonXY(points) - wkt = multiPolygon.convertToType(QgsWkbTypes.GeometryType.PointGeometry, True).asWkt() + wkt = multiPolygon.convertToType( + QgsWkbTypes.GeometryType.PointGeometry, True + ).asWkt() expWkt = "MultiPoint ((0 0),(1 0),(1 1),(2 1),(2 2),(0 2),(0 0),(4 0),(5 0),(5 2),(3 2),(3 1),(4 1),(4 0),(10 0),(13 0),(13 3),(10 3),(10 0),(11 1),(12 1),(12 2),(11 2),(11 1))" - assert compareWkt(expWkt, - wkt), "convertToType failed: from multipoylgon to multipoint. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from multipoylgon to multipoint. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # ####### TO LINE ######## # POINT TO LINE point = QgsGeometry.fromPointXY(QgsPointXY(1, 1)) - self.assertFalse(point.convertToType(QgsWkbTypes.GeometryType.LineGeometry, - False)), "convertToType with a point should return a null geometry" + self.assertFalse( + point.convertToType(QgsWkbTypes.GeometryType.LineGeometry, False) + ), "convertToType with a point should return a null geometry" # MultiPoint TO LINE multipoint = QgsGeometry.fromMultiPointXY(points[0][0]) - wkt = multipoint.convertToType(QgsWkbTypes.GeometryType.LineGeometry, False).asWkt() + wkt = multipoint.convertToType( + QgsWkbTypes.GeometryType.LineGeometry, False + ).asWkt() expWkt = "LineString (0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)" - assert compareWkt(expWkt, wkt), "convertToType failed: from multipoint to line. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from multipoint to line. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # MultiPoint TO MULTILINE multipoint = QgsGeometry.fromMultiPointXY(points[0][0]) - wkt = multipoint.convertToType(QgsWkbTypes.GeometryType.LineGeometry, True).asWkt() + wkt = multipoint.convertToType( + QgsWkbTypes.GeometryType.LineGeometry, True + ).asWkt() expWkt = "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0))" - assert compareWkt(expWkt, - wkt), "convertToType failed: from multipoint to multiline. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from multipoint to multiline. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # MULTILINE (which has a single part) TO LINE multiLine = QgsGeometry.fromMultiPolylineXY(points[0]) - wkt = multiLine.convertToType(QgsWkbTypes.GeometryType.LineGeometry, False).asWkt() + wkt = multiLine.convertToType( + QgsWkbTypes.GeometryType.LineGeometry, False + ).asWkt() expWkt = "LineString (0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)" - assert compareWkt(expWkt, wkt), "convertToType failed: from multiline to line. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from multiline to line. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # LINE TO MULTILINE line = QgsGeometry.fromPolylineXY(points[0][0]) wkt = line.convertToType(QgsWkbTypes.GeometryType.LineGeometry, True).asWkt() expWkt = "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0))" - assert compareWkt(expWkt, wkt), "convertToType failed: from line to multiline. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from line to multiline. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # Polygon TO LINE polygon = QgsGeometry.fromPolygonXY(points[0]) - wkt = polygon.convertToType(QgsWkbTypes.GeometryType.LineGeometry, False).asWkt() + wkt = polygon.convertToType( + QgsWkbTypes.GeometryType.LineGeometry, False + ).asWkt() expWkt = "LineString (0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)" - assert compareWkt(expWkt, wkt), "convertToType failed: from polygon to line. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from polygon to line. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # Polygon TO MULTILINE polygon = QgsGeometry.fromPolygonXY(points[0]) wkt = polygon.convertToType(QgsWkbTypes.GeometryType.LineGeometry, True).asWkt() expWkt = "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0))" - assert compareWkt(expWkt, wkt), "convertToType failed: from polygon to multiline. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from polygon to multiline. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # Polygon with ring TO MULTILINE polygon = QgsGeometry.fromPolygonXY(points[2]) wkt = polygon.convertToType(QgsWkbTypes.GeometryType.LineGeometry, True).asWkt() expWkt = "MultiLineString ((10 0, 13 0, 13 3, 10 3, 10 0), (11 1, 12 1, 12 2, 11 2, 11 1))" - assert compareWkt(expWkt, - wkt), "convertToType failed: from polygon with ring to multiline. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from polygon with ring to multiline. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # MultiPolygon (which has a single part) TO LINE multiPolygon = QgsGeometry.fromMultiPolygonXY([points[0]]) - wkt = multiPolygon.convertToType(QgsWkbTypes.GeometryType.LineGeometry, False).asWkt() + wkt = multiPolygon.convertToType( + QgsWkbTypes.GeometryType.LineGeometry, False + ).asWkt() expWkt = "LineString (0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)" - assert compareWkt(expWkt, - wkt), "convertToType failed: from multipolygon to multiline. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from multipolygon to multiline. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # MultiPolygon TO MULTILINE multiPolygon = QgsGeometry.fromMultiPolygonXY(points) - wkt = multiPolygon.convertToType(QgsWkbTypes.GeometryType.LineGeometry, True).asWkt() + wkt = multiPolygon.convertToType( + QgsWkbTypes.GeometryType.LineGeometry, True + ).asWkt() expWkt = "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0), (4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0), (10 0, 13 0, 13 3, 10 3, 10 0), (11 1, 12 1, 12 2, 11 2, 11 1))" - assert compareWkt(expWkt, - wkt), "convertToType failed: from multipolygon to multiline. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from multipolygon to multiline. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # ####### TO Polygon ######## # MultiPoint TO Polygon multipoint = QgsGeometry.fromMultiPointXY(points[0][0]) - wkt = multipoint.convertToType(QgsWkbTypes.GeometryType.PolygonGeometry, False).asWkt() + wkt = multipoint.convertToType( + QgsWkbTypes.GeometryType.PolygonGeometry, False + ).asWkt() expWkt = "Polygon ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0))" - assert compareWkt(expWkt, - wkt), "convertToType failed: from multipoint to polygon. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from multipoint to polygon. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # MultiPoint TO MultiPolygon multipoint = QgsGeometry.fromMultiPointXY(points[0][0]) - wkt = multipoint.convertToType(QgsWkbTypes.GeometryType.PolygonGeometry, True).asWkt() + wkt = multipoint.convertToType( + QgsWkbTypes.GeometryType.PolygonGeometry, True + ).asWkt() expWkt = "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)))" - assert compareWkt(expWkt, - wkt), "convertToType failed: from multipoint to multipolygon. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from multipoint to multipolygon. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # LINE TO Polygon line = QgsGeometry.fromPolylineXY(points[0][0]) - wkt = line.convertToType(QgsWkbTypes.GeometryType.PolygonGeometry, False).asWkt() + wkt = line.convertToType( + QgsWkbTypes.GeometryType.PolygonGeometry, False + ).asWkt() expWkt = "Polygon ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0))" - assert compareWkt(expWkt, wkt), "convertToType failed: from line to polygon. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from line to polygon. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # LINE ( 3 vertices, with first = last ) TO Polygon - line = QgsGeometry.fromPolylineXY([QgsPointXY(1, 1), QgsPointXY(0, 0), QgsPointXY(1, 1)]) - self.assertFalse(line.convertToType(QgsWkbTypes.GeometryType.PolygonGeometry, False), - "convertToType to polygon of a 3 vertices lines with first and last vertex identical should return a null geometry") + line = QgsGeometry.fromPolylineXY( + [QgsPointXY(1, 1), QgsPointXY(0, 0), QgsPointXY(1, 1)] + ) + self.assertFalse( + line.convertToType(QgsWkbTypes.GeometryType.PolygonGeometry, False), + "convertToType to polygon of a 3 vertices lines with first and last vertex identical should return a null geometry", + ) # MULTILINE ( with a part of 3 vertices, with first = last ) TO MultiPolygon multiline = QgsGeometry.fromMultiPolylineXY( - [points[0][0], [QgsPointXY(1, 1), QgsPointXY(0, 0), QgsPointXY(1, 1)]]) - self.assertFalse(multiline.convertToType(QgsWkbTypes.GeometryType.PolygonGeometry, True), - "convertToType to polygon of a 3 vertices lines with first and last vertex identical should return a null geometry") + [points[0][0], [QgsPointXY(1, 1), QgsPointXY(0, 0), QgsPointXY(1, 1)]] + ) + self.assertFalse( + multiline.convertToType(QgsWkbTypes.GeometryType.PolygonGeometry, True), + "convertToType to polygon of a 3 vertices lines with first and last vertex identical should return a null geometry", + ) # LINE TO MultiPolygon line = QgsGeometry.fromPolylineXY(points[0][0]) wkt = line.convertToType(QgsWkbTypes.GeometryType.PolygonGeometry, True).asWkt() expWkt = "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)))" - assert compareWkt(expWkt, wkt), "convertToType failed: from line to multipolygon. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from line to multipolygon. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # MULTILINE (which has a single part) TO Polygon multiLine = QgsGeometry.fromMultiPolylineXY(points[0]) - wkt = multiLine.convertToType(QgsWkbTypes.GeometryType.PolygonGeometry, False).asWkt() + wkt = multiLine.convertToType( + QgsWkbTypes.GeometryType.PolygonGeometry, False + ).asWkt() expWkt = "Polygon ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0))" - assert compareWkt(expWkt, wkt), "convertToType failed: from multiline to polygon. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from multiline to polygon. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # MULTILINE TO MultiPolygon multiLine = QgsGeometry.fromMultiPolylineXY([points[0][0], points[1][0]]) - wkt = multiLine.convertToType(QgsWkbTypes.GeometryType.PolygonGeometry, True).asWkt() + wkt = multiLine.convertToType( + QgsWkbTypes.GeometryType.PolygonGeometry, True + ).asWkt() expWkt = "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))" - assert compareWkt(expWkt, - wkt), "convertToType failed: from multiline to multipolygon. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from multiline to multipolygon. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # Polygon TO MultiPolygon polygon = QgsGeometry.fromPolygonXY(points[0]) - wkt = polygon.convertToType(QgsWkbTypes.GeometryType.PolygonGeometry, True).asWkt() + wkt = polygon.convertToType( + QgsWkbTypes.GeometryType.PolygonGeometry, True + ).asWkt() expWkt = "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)))" - assert compareWkt(expWkt, - wkt), "convertToType failed: from polygon to multipolygon. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from polygon to multipolygon. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # MultiPolygon (which has a single part) TO Polygon multiPolygon = QgsGeometry.fromMultiPolygonXY([points[0]]) - wkt = multiPolygon.convertToType(QgsWkbTypes.GeometryType.PolygonGeometry, False).asWkt() + wkt = multiPolygon.convertToType( + QgsWkbTypes.GeometryType.PolygonGeometry, False + ).asWkt() expWkt = "Polygon ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0))" - assert compareWkt(expWkt, wkt), "convertToType failed: from multiline to polygon. Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "convertToType failed: from multiline to polygon. Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) def testRegression13053(self): - """ See https://github.com/qgis/QGIS/issues/21125 """ + """See https://github.com/qgis/QGIS/issues/21125""" p = QgsGeometry.fromWkt( - 'MULTIPOLYGON(((62.0 18.0, 62.0 19.0, 63.0 19.0, 63.0 18.0, 62.0 18.0)), ((63.0 19.0, 63.0 20.0, 64.0 20.0, 64.0 19.0, 63.0 19.0)))') + "MULTIPOLYGON(((62.0 18.0, 62.0 19.0, 63.0 19.0, 63.0 18.0, 62.0 18.0)), ((63.0 19.0, 63.0 20.0, 64.0 20.0, 64.0 19.0, 63.0 19.0)))" + ) assert p is not None - expWkt = 'MultiPolygon (((62 18, 62 19, 63 19, 63 18, 62 18)),((63 19, 63 20, 64 20, 64 19, 63 19)))' + expWkt = "MultiPolygon (((62 18, 62 19, 63 19, 63 18, 62 18)),((63 19, 63 20, 64 20, 64 19, 63 19)))" wkt = p.asWkt() - assert compareWkt(expWkt, wkt), f"testRegression13053 failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" + assert compareWkt( + expWkt, wkt + ), f"testRegression13053 failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" def testRegression13055(self): - """ See https://github.com/qgis/QGIS/issues/21127 - Testing that invalid WKT with z values but not using PolygonZ is still parsed - by QGIS. + """See https://github.com/qgis/QGIS/issues/21127 + Testing that invalid WKT with z values but not using PolygonZ is still parsed + by QGIS. """ - p = QgsGeometry.fromWkt('Polygon((0 0 0, 0 1 0, 1 1 0, 0 0 0 ))') + p = QgsGeometry.fromWkt("Polygon((0 0 0, 0 1 0, 1 1 0, 0 0 0 ))") assert p is not None - expWkt = 'PolygonZ ((0 0 0, 0 1 0, 1 1 0, 0 0 0 ))' + expWkt = "PolygonZ ((0 0 0, 0 1 0, 1 1 0, 0 0 0 ))" wkt = p.asWkt() - assert compareWkt(expWkt, wkt), f"testRegression13055 failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" + assert compareWkt( + expWkt, wkt + ), f"testRegression13055 failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" def testRegression13274(self): - """ See https://github.com/qgis/QGIS/issues/21334 - Testing that two combined linestrings produce another line string if possible + """See https://github.com/qgis/QGIS/issues/21334 + Testing that two combined linestrings produce another line string if possible """ - a = QgsGeometry.fromWkt('LineString (0 0, 1 0)') - b = QgsGeometry.fromWkt('LineString (1 0, 2 0)') + a = QgsGeometry.fromWkt("LineString (0 0, 1 0)") + b = QgsGeometry.fromWkt("LineString (1 0, 2 0)") c = a.combine(b) - expWkt = 'LineString (0 0, 1 0, 2 0)' + expWkt = "LineString (0 0, 1 0, 2 0)" wkt = c.asWkt() - assert compareWkt(expWkt, wkt), f"testRegression13274 failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" + assert compareWkt( + expWkt, wkt + ), f"testRegression13274 failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" def testReshape(self): - """ Test geometry reshaping """ + """Test geometry reshaping""" # no overlap - g = QgsGeometry.fromWkt('LineString (0 0, 5 0, 5 1, 6 1, 6 0, 7 0)') - self.assertEqual(g.reshapeGeometry(QgsLineString([QgsPoint(4, 2), QgsPoint(7, 2)])), 0) - expWkt = 'LineString (0 0, 5 0, 5 1, 6 1, 6 0, 7 0)' + g = QgsGeometry.fromWkt("LineString (0 0, 5 0, 5 1, 6 1, 6 0, 7 0)") + self.assertEqual( + g.reshapeGeometry(QgsLineString([QgsPoint(4, 2), QgsPoint(7, 2)])), 0 + ) + expWkt = "LineString (0 0, 5 0, 5 1, 6 1, 6 0, 7 0)" wkt = g.asWkt() - self.assertTrue(compareWkt(expWkt, wkt), - f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n") + self.assertTrue( + compareWkt(expWkt, wkt), + f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n", + ) - g = QgsGeometry.fromWkt('Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))') + g = QgsGeometry.fromWkt("Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))") g.reshapeGeometry(QgsLineString([QgsPoint(0, 1.5), QgsPoint(1.5, 0)])) - expWkt = 'Polygon ((0.5 1, 0 1, 0 0, 1 0, 1 0.5, 0.5 1))' + expWkt = "Polygon ((0.5 1, 0 1, 0 0, 1 0, 1 0.5, 0.5 1))" wkt = g.asWkt() - assert compareWkt(expWkt, wkt), f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" + assert compareWkt( + expWkt, wkt + ), f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" # Test reshape a geometry involving the first/last vertex (https://github.com/qgis/QGIS/issues/22422) g.reshapeGeometry(QgsLineString([QgsPoint(0.5, 1), QgsPoint(0, 0.5)])) - expWkt = 'Polygon ((0 0.5, 0 0, 1 0, 1 0.5, 0.5 1, 0 0.5))' + expWkt = "Polygon ((0 0.5, 0 0, 1 0, 1 0.5, 0.5 1, 0 0.5))" wkt = g.asWkt() - assert compareWkt(expWkt, wkt), f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" + assert compareWkt( + expWkt, wkt + ), f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" # Test reshape a polygon with a line starting or ending at the polygon's first vertex, no change expexted - g = QgsGeometry.fromWkt('Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))') + g = QgsGeometry.fromWkt("Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))") expWkt = g.asWkt() g.reshapeGeometry(QgsLineString([QgsPoint(0, 0), QgsPoint(-1, -1)])) - self.assertTrue(compareWkt(g.asWkt(), expWkt), - f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n") + self.assertTrue( + compareWkt(g.asWkt(), expWkt), + f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n", + ) # Test reshape a polygon with a line starting or ending at the polygon's first vertex - g = QgsGeometry.fromWkt('Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))') - self.assertEqual(g.reshapeGeometry(QgsLineString([QgsPoint(0, 0), QgsPoint(0.5, 0.5), QgsPoint(0, 1)])), - QgsGeometry.OperationResult.Success) - expWkt = 'Polygon ((0 0, 1 0, 1 1, 0 1, 0.5 0.5, 0 0))' + g = QgsGeometry.fromWkt("Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))") + self.assertEqual( + g.reshapeGeometry( + QgsLineString([QgsPoint(0, 0), QgsPoint(0.5, 0.5), QgsPoint(0, 1)]) + ), + QgsGeometry.OperationResult.Success, + ) + expWkt = "Polygon ((0 0, 1 0, 1 1, 0 1, 0.5 0.5, 0 0))" wkt = g.asWkt() - self.assertTrue(compareWkt(wkt, expWkt), - f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n") + self.assertTrue( + compareWkt(wkt, expWkt), + f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n", + ) # Test reshape a line from first/last vertex - g = QgsGeometry.fromWkt('LineString (0 0, 5 0, 5 1)') + g = QgsGeometry.fromWkt("LineString (0 0, 5 0, 5 1)") # extend start - self.assertEqual(g.reshapeGeometry(QgsLineString([QgsPoint(0, 0), QgsPoint(-1, 0)])), 0) - expWkt = 'LineString (-1 0, 0 0, 5 0, 5 1)' + self.assertEqual( + g.reshapeGeometry(QgsLineString([QgsPoint(0, 0), QgsPoint(-1, 0)])), 0 + ) + expWkt = "LineString (-1 0, 0 0, 5 0, 5 1)" wkt = g.asWkt() - assert compareWkt(expWkt, wkt), f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" + assert compareWkt( + expWkt, wkt + ), f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" # extend end - self.assertEqual(g.reshapeGeometry(QgsLineString([QgsPoint(5, 1), QgsPoint(10, 1), QgsPoint(10, 2)])), 0) - expWkt = 'LineString (-1 0, 0 0, 5 0, 5 1, 10 1, 10 2)' + self.assertEqual( + g.reshapeGeometry( + QgsLineString([QgsPoint(5, 1), QgsPoint(10, 1), QgsPoint(10, 2)]) + ), + 0, + ) + expWkt = "LineString (-1 0, 0 0, 5 0, 5 1, 10 1, 10 2)" wkt = g.asWkt() - assert compareWkt(expWkt, wkt), f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" + assert compareWkt( + expWkt, wkt + ), f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" # test with reversed lines - g = QgsGeometry.fromWkt('LineString (0 0, 5 0, 5 1)') + g = QgsGeometry.fromWkt("LineString (0 0, 5 0, 5 1)") # extend start - self.assertEqual(g.reshapeGeometry(QgsLineString([QgsPoint(-1, 0), QgsPoint(0, 0)])), 0) - expWkt = 'LineString (-1 0, 0 0, 5 0, 5 1)' + self.assertEqual( + g.reshapeGeometry(QgsLineString([QgsPoint(-1, 0), QgsPoint(0, 0)])), 0 + ) + expWkt = "LineString (-1 0, 0 0, 5 0, 5 1)" wkt = g.asWkt() - assert compareWkt(expWkt, wkt), f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" + assert compareWkt( + expWkt, wkt + ), f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" # extend end - self.assertEqual(g.reshapeGeometry(QgsLineString([QgsPoint(10, 2), QgsPoint(10, 1), QgsPoint(5, 1)])), 0) - expWkt = 'LineString (-1 0, 0 0, 5 0, 5 1, 10 1, 10 2)' + self.assertEqual( + g.reshapeGeometry( + QgsLineString([QgsPoint(10, 2), QgsPoint(10, 1), QgsPoint(5, 1)]) + ), + 0, + ) + expWkt = "LineString (-1 0, 0 0, 5 0, 5 1, 10 1, 10 2)" wkt = g.asWkt() - assert compareWkt(expWkt, wkt), f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" + assert compareWkt( + expWkt, wkt + ), f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" # reshape where reshape line exactly overlaps some portions of geometry - g = QgsGeometry.fromWkt('LineString (0 0, 5 0, 5 1, 6 1, 6 0, 7 0)') - self.assertEqual(g.reshapeGeometry(QgsLineString([QgsPoint(2, 0), QgsPoint(6, 0)])), 0) - expWkt = 'LineString (0 0, 2 0, 5 0, 6 0, 7 0)' + g = QgsGeometry.fromWkt("LineString (0 0, 5 0, 5 1, 6 1, 6 0, 7 0)") + self.assertEqual( + g.reshapeGeometry(QgsLineString([QgsPoint(2, 0), QgsPoint(6, 0)])), 0 + ) + expWkt = "LineString (0 0, 2 0, 5 0, 6 0, 7 0)" wkt = g.asWkt() - self.assertTrue(compareWkt(expWkt, wkt), - f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n") + self.assertTrue( + compareWkt(expWkt, wkt), + f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n", + ) - g = QgsGeometry.fromWkt('LineString (0 0, 5 0, 5 1, 6 1, 6 0, 7 0)') - self.assertEqual(g.reshapeGeometry(QgsLineString([QgsPoint(5, 0), QgsPoint(7, 0)])), 0) - expWkt = 'LineString (0 0, 5 0, 6 0, 7 0)' + g = QgsGeometry.fromWkt("LineString (0 0, 5 0, 5 1, 6 1, 6 0, 7 0)") + self.assertEqual( + g.reshapeGeometry(QgsLineString([QgsPoint(5, 0), QgsPoint(7, 0)])), 0 + ) + expWkt = "LineString (0 0, 5 0, 6 0, 7 0)" wkt = g.asWkt() - self.assertTrue(compareWkt(expWkt, wkt), - f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n") + self.assertTrue( + compareWkt(expWkt, wkt), + f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n", + ) # reshape line overlaps at both start and end - g = QgsGeometry.fromWkt('LineString (0 0, 5 0, 5 1, 6 1, 6 0, 7 0)') - self.assertEqual(g.reshapeGeometry(QgsLineString([QgsPoint(4, 0), QgsPoint(7, 0)])), 0) - expWkt = 'LineString (0 0, 4 0, 5 0, 6 0, 7 0)' + g = QgsGeometry.fromWkt("LineString (0 0, 5 0, 5 1, 6 1, 6 0, 7 0)") + self.assertEqual( + g.reshapeGeometry(QgsLineString([QgsPoint(4, 0), QgsPoint(7, 0)])), 0 + ) + expWkt = "LineString (0 0, 4 0, 5 0, 6 0, 7 0)" wkt = g.asWkt() - self.assertTrue(compareWkt(expWkt, wkt), - f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n") + self.assertTrue( + compareWkt(expWkt, wkt), + f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n", + ) # test that tolerance is correctly handled g = QgsGeometry.fromWkt( - 'LineString(152.96370660521466789 -25.60915858374441356, 152.96370887800003402 -25.60912889999996978, 152.9640088780000724 -25.60858889999996535, 152.96423077601289719 -25.60858080133134962, 152.96423675797717578 -25.60854355430449658, 152.96427575123991005 -25.60857916087011432, 152.96537884400004259 -25.60853889999992106, 152.96576355343805176 -25.60880035169972047)') - self.assertEqual(g.reshapeGeometry(QgsLineString([QgsPoint(152.9634281, -25.6079985), - QgsPoint(152.9640088780000724, -25.60858889999996535), - QgsPoint(152.96537884400004259, -25.60853889999992106), - QgsPoint(152.9655739, -25.6083169)])), 0) - expWkt = 'LineString (152.96371 -25.60916, 152.96371 -25.60913, 152.96401 -25.60859, 152.96423 -25.60858, 152.96423 -25.60858, 152.96428 -25.60858, 152.96538 -25.60854, 152.96576 -25.6088)' + "LineString(152.96370660521466789 -25.60915858374441356, 152.96370887800003402 -25.60912889999996978, 152.9640088780000724 -25.60858889999996535, 152.96423077601289719 -25.60858080133134962, 152.96423675797717578 -25.60854355430449658, 152.96427575123991005 -25.60857916087011432, 152.96537884400004259 -25.60853889999992106, 152.96576355343805176 -25.60880035169972047)" + ) + self.assertEqual( + g.reshapeGeometry( + QgsLineString( + [ + QgsPoint(152.9634281, -25.6079985), + QgsPoint(152.9640088780000724, -25.60858889999996535), + QgsPoint(152.96537884400004259, -25.60853889999992106), + QgsPoint(152.9655739, -25.6083169), + ] + ) + ), + 0, + ) + expWkt = "LineString (152.96371 -25.60916, 152.96371 -25.60913, 152.96401 -25.60859, 152.96423 -25.60858, 152.96423 -25.60858, 152.96428 -25.60858, 152.96538 -25.60854, 152.96576 -25.6088)" wkt = g.asWkt(5) - self.assertTrue(compareWkt(expWkt, wkt), - f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n") + self.assertTrue( + compareWkt(expWkt, wkt), + f"testReshape failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n", + ) def testConvertToMultiType(self): - """ Test converting geometries to multi type """ - point = QgsGeometry.fromWkt('Point (1 2)') + """Test converting geometries to multi type""" + point = QgsGeometry.fromWkt("Point (1 2)") assert point.convertToMultiType() - expWkt = 'MultiPoint ((1 2))' + expWkt = "MultiPoint ((1 2))" wkt = point.asWkt() - assert compareWkt(expWkt, wkt), "testConvertToMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # test conversion of MultiPoint assert point.convertToMultiType() - assert compareWkt(expWkt, wkt), "testConvertToMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) - line = QgsGeometry.fromWkt('LineString (1 0, 2 0)') + line = QgsGeometry.fromWkt("LineString (1 0, 2 0)") assert line.convertToMultiType() - expWkt = 'MultiLineString ((1 0, 2 0))' + expWkt = "MultiLineString ((1 0, 2 0))" wkt = line.asWkt() - assert compareWkt(expWkt, wkt), "testConvertToMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # test conversion of MultiLineString assert line.convertToMultiType() - assert compareWkt(expWkt, wkt), "testConvertToMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) - poly = QgsGeometry.fromWkt('Polygon ((1 0, 2 0, 2 1, 1 1, 1 0))') + poly = QgsGeometry.fromWkt("Polygon ((1 0, 2 0, 2 1, 1 1, 1 0))") assert poly.convertToMultiType() - expWkt = 'MultiPolygon (((1 0, 2 0, 2 1, 1 1, 1 0)))' + expWkt = "MultiPolygon (((1 0, 2 0, 2 1, 1 1, 1 0)))" wkt = poly.asWkt() - assert compareWkt(expWkt, wkt), "testConvertToMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # test conversion of MultiPolygon assert poly.convertToMultiType() - assert compareWkt(expWkt, wkt), "testConvertToMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) def testConvertToCurvedMultiType(self): - """ Test converting geometries to multi curve type """ - point = QgsGeometry.fromWkt('Point (1 2)') + """Test converting geometries to multi curve type""" + point = QgsGeometry.fromWkt("Point (1 2)") assert point.convertToCurvedMultiType() - expWkt = 'MultiPoint ((1 2))' + expWkt = "MultiPoint ((1 2))" wkt = point.asWkt() - assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # test conversion of MultiPoint assert point.convertToCurvedMultiType() - assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) - multipoint = QgsGeometry.fromWkt('MultiPoint ((1 2))') + multipoint = QgsGeometry.fromWkt("MultiPoint ((1 2))") assert multipoint.convertToCurvedMultiType() - expWkt = 'MultiPoint ((1 2))' + expWkt = "MultiPoint ((1 2))" wkt = multipoint.asWkt() - assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # test conversion of MultiPoint assert multipoint.convertToCurvedMultiType() - assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) - line = QgsGeometry.fromWkt('LineString (1 0, 2 0)') + line = QgsGeometry.fromWkt("LineString (1 0, 2 0)") assert line.convertToCurvedMultiType() - expWkt = 'MultiCurve (LineString (1 0, 2 0))' + expWkt = "MultiCurve (LineString (1 0, 2 0))" wkt = line.asWkt() - assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # test conversion of MultiCurve assert line.convertToCurvedMultiType() - assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) - circular = QgsGeometry.fromWkt('CircularString (0 0, 1 1, 2 0)') + circular = QgsGeometry.fromWkt("CircularString (0 0, 1 1, 2 0)") assert circular.convertToCurvedMultiType() - expWkt = 'MultiCurve (CircularString (0 0, 1 1, 2 0))' + expWkt = "MultiCurve (CircularString (0 0, 1 1, 2 0))" wkt = circular.asWkt() - assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # test conversion of MultiCurve assert circular.convertToCurvedMultiType() - assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) - multiline = QgsGeometry.fromWkt('MultiLineString ((1 0, 2 0))') + multiline = QgsGeometry.fromWkt("MultiLineString ((1 0, 2 0))") assert multiline.convertToCurvedMultiType() - expWkt = 'MultiCurve (LineString (1 0, 2 0))' + expWkt = "MultiCurve (LineString (1 0, 2 0))" wkt = multiline.asWkt() - assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # test conversion of MultiCurve assert multiline.convertToCurvedMultiType() - assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) - poly = QgsGeometry.fromWkt('Polygon ((1 0, 2 0, 2 1, 1 1, 1 0))') + poly = QgsGeometry.fromWkt("Polygon ((1 0, 2 0, 2 1, 1 1, 1 0))") assert poly.convertToCurvedMultiType() - expWkt = 'MultiSurface (Polygon((1 0, 2 0, 2 1, 1 1, 1 0)))' + expWkt = "MultiSurface (Polygon((1 0, 2 0, 2 1, 1 1, 1 0)))" wkt = poly.asWkt() - assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # test conversion of MultiSurface assert poly.convertToCurvedMultiType() - assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) - multipoly = QgsGeometry.fromWkt('MultiPolygon (((1 0, 2 0, 2 1, 1 1, 1 0)))') + multipoly = QgsGeometry.fromWkt("MultiPolygon (((1 0, 2 0, 2 1, 1 1, 1 0)))") assert multipoly.convertToCurvedMultiType() - expWkt = 'MultiSurface ( Polygon((1 0, 2 0, 2 1, 1 1, 1 0)))' + expWkt = "MultiSurface ( Polygon((1 0, 2 0, 2 1, 1 1, 1 0)))" wkt = multipoly.asWkt() - assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # test conversion of MultiSurface assert multipoly.convertToCurvedMultiType() - assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToCurvedMultiType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) def testConvertToSingleType(self): - """ Test converting geometries to single type """ - point = QgsGeometry.fromWkt('MultiPoint ((1 2),(2 3))') + """Test converting geometries to single type""" + point = QgsGeometry.fromWkt("MultiPoint ((1 2),(2 3))") assert point.convertToSingleType() - expWkt = 'Point (1 2)' + expWkt = "Point (1 2)" wkt = point.asWkt() - assert compareWkt(expWkt, wkt), "testConvertToSingleType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToSingleType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # test conversion of Point assert point.convertToSingleType() - assert compareWkt(expWkt, wkt), "testConvertToSingleType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToSingleType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) - line = QgsGeometry.fromWkt('MultiLineString ((1 0, 2 0),(2 3, 4 5))') + line = QgsGeometry.fromWkt("MultiLineString ((1 0, 2 0),(2 3, 4 5))") assert line.convertToSingleType() - expWkt = 'LineString (1 0, 2 0)' + expWkt = "LineString (1 0, 2 0)" wkt = line.asWkt() - assert compareWkt(expWkt, wkt), "testConvertToSingleType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToSingleType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # test conversion of LineString assert line.convertToSingleType() - assert compareWkt(expWkt, wkt), "testConvertToSingleType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToSingleType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) - poly = QgsGeometry.fromWkt('MultiPolygon (((1 0, 2 0, 2 1, 1 1, 1 0)),((2 3,2 4, 3 4, 3 3, 2 3)))') + poly = QgsGeometry.fromWkt( + "MultiPolygon (((1 0, 2 0, 2 1, 1 1, 1 0)),((2 3,2 4, 3 4, 3 3, 2 3)))" + ) assert poly.convertToSingleType() - expWkt = 'Polygon ((1 0, 2 0, 2 1, 1 1, 1 0))' + expWkt = "Polygon ((1 0, 2 0, 2 1, 1 1, 1 0))" wkt = poly.asWkt() - assert compareWkt(expWkt, wkt), "testConvertToSingleType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToSingleType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # test conversion of Polygon assert poly.convertToSingleType() - assert compareWkt(expWkt, wkt), "testConvertToSingleType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "testConvertToSingleType failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) def testAddZValue(self): - """ Test adding z dimension to geometries """ + """Test adding z dimension to geometries""" # circular string - geom = QgsGeometry.fromWkt('CircularString (1 5, 6 2, 7 3)') + geom = QgsGeometry.fromWkt("CircularString (1 5, 6 2, 7 3)") assert geom.get().addZValue(2) self.assertEqual(geom.constGet().wkbType(), QgsWkbTypes.Type.CircularStringZ) - expWkt = 'CircularStringZ (1 5 2, 6 2 2, 7 3 2)' + expWkt = "CircularStringZ (1 5 2, 6 2 2, 7 3 2)" wkt = geom.asWkt() - assert compareWkt(expWkt, wkt), "addZValue to CircularString failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "addZValue to CircularString failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # compound curve geom = QgsGeometry.fromWkt( - 'CompoundCurve ((5 3, 5 13),CircularString (5 13, 7 15, 9 13),(9 13, 9 3),CircularString (9 3, 7 1, 5 3))') + "CompoundCurve ((5 3, 5 13),CircularString (5 13, 7 15, 9 13),(9 13, 9 3),CircularString (9 3, 7 1, 5 3))" + ) assert geom.get().addZValue(2) self.assertEqual(geom.constGet().wkbType(), QgsWkbTypes.Type.CompoundCurveZ) - expWkt = 'CompoundCurveZ ((5 3 2, 5 13 2),CircularStringZ (5 13 2, 7 15 2, 9 13 2),(9 13 2, 9 3 2),CircularStringZ (9 3 2, 7 1 2, 5 3 2))' + expWkt = "CompoundCurveZ ((5 3 2, 5 13 2),CircularStringZ (5 13 2, 7 15 2, 9 13 2),(9 13 2, 9 3 2),CircularStringZ (9 3 2, 7 1 2, 5 3 2))" wkt = geom.asWkt() - assert compareWkt(expWkt, wkt), "addZValue to CompoundCurve failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "addZValue to CompoundCurve failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # curve polygon - geom = QgsGeometry.fromWkt('Polygon ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0))') + geom = QgsGeometry.fromWkt("Polygon ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0))") assert geom.get().addZValue(3) self.assertEqual(geom.constGet().wkbType(), QgsWkbTypes.Type.PolygonZ) self.assertEqual(geom.wkbType(), QgsWkbTypes.Type.PolygonZ) - expWkt = 'PolygonZ ((0 0 3, 1 0 3, 1 1 3, 2 1 3, 2 2 3, 0 2 3, 0 0 3))' + expWkt = "PolygonZ ((0 0 3, 1 0 3, 1 1 3, 2 1 3, 2 2 3, 0 2 3, 0 0 3))" wkt = geom.asWkt() - assert compareWkt(expWkt, wkt), "addZValue to CurvePolygon failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "addZValue to CurvePolygon failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # geometry collection - geom = QgsGeometry.fromWkt('MultiPoint ((1 2),(2 3))') + geom = QgsGeometry.fromWkt("MultiPoint ((1 2),(2 3))") assert geom.get().addZValue(4) self.assertEqual(geom.constGet().wkbType(), QgsWkbTypes.Type.MultiPointZ) self.assertEqual(geom.wkbType(), QgsWkbTypes.Type.MultiPointZ) - expWkt = 'MultiPointZ ((1 2 4),(2 3 4))' + expWkt = "MultiPointZ ((1 2 4),(2 3 4))" wkt = geom.asWkt() - assert compareWkt(expWkt, wkt), "addZValue to GeometryCollection failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "addZValue to GeometryCollection failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # LineString - geom = QgsGeometry.fromWkt('LineString (1 2, 2 3)') + geom = QgsGeometry.fromWkt("LineString (1 2, 2 3)") assert geom.get().addZValue(4) self.assertEqual(geom.constGet().wkbType(), QgsWkbTypes.Type.LineStringZ) self.assertEqual(geom.wkbType(), QgsWkbTypes.Type.LineStringZ) - expWkt = 'LineStringZ (1 2 4, 2 3 4)' + expWkt = "LineStringZ (1 2 4, 2 3 4)" wkt = geom.asWkt() - assert compareWkt(expWkt, wkt), "addZValue to LineString failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "addZValue to LineString failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # Point - geom = QgsGeometry.fromWkt('Point (1 2)') + geom = QgsGeometry.fromWkt("Point (1 2)") assert geom.get().addZValue(4) self.assertEqual(geom.constGet().wkbType(), QgsWkbTypes.Type.PointZ) self.assertEqual(geom.wkbType(), QgsWkbTypes.Type.PointZ) - expWkt = 'PointZ (1 2 4)' + expWkt = "PointZ (1 2 4)" wkt = geom.asWkt() - assert compareWkt(expWkt, wkt), f"addZValue to Point failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" + assert compareWkt( + expWkt, wkt + ), f"addZValue to Point failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" def testAddMValue(self): - """ Test adding m dimension to geometries """ + """Test adding m dimension to geometries""" # circular string - geom = QgsGeometry.fromWkt('CircularString (1 5, 6 2, 7 3)') + geom = QgsGeometry.fromWkt("CircularString (1 5, 6 2, 7 3)") assert geom.get().addMValue(2) self.assertEqual(geom.constGet().wkbType(), QgsWkbTypes.Type.CircularStringM) - expWkt = 'CircularStringM (1 5 2, 6 2 2, 7 3 2)' + expWkt = "CircularStringM (1 5 2, 6 2 2, 7 3 2)" wkt = geom.asWkt() - assert compareWkt(expWkt, wkt), "addMValue to CircularString failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "addMValue to CircularString failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # compound curve geom = QgsGeometry.fromWkt( - 'CompoundCurve ((5 3, 5 13),CircularString (5 13, 7 15, 9 13),(9 13, 9 3),CircularString (9 3, 7 1, 5 3))') + "CompoundCurve ((5 3, 5 13),CircularString (5 13, 7 15, 9 13),(9 13, 9 3),CircularString (9 3, 7 1, 5 3))" + ) assert geom.get().addMValue(2) self.assertEqual(geom.constGet().wkbType(), QgsWkbTypes.Type.CompoundCurveM) - expWkt = 'CompoundCurveM ((5 3 2, 5 13 2),CircularStringM (5 13 2, 7 15 2, 9 13 2),(9 13 2, 9 3 2),CircularStringM (9 3 2, 7 1 2, 5 3 2))' + expWkt = "CompoundCurveM ((5 3 2, 5 13 2),CircularStringM (5 13 2, 7 15 2, 9 13 2),(9 13 2, 9 3 2),CircularStringM (9 3 2, 7 1 2, 5 3 2))" wkt = geom.asWkt() - assert compareWkt(expWkt, wkt), "addMValue to CompoundCurve failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "addMValue to CompoundCurve failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # curve polygon - geom = QgsGeometry.fromWkt('Polygon ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0))') + geom = QgsGeometry.fromWkt("Polygon ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0))") assert geom.get().addMValue(3) self.assertEqual(geom.constGet().wkbType(), QgsWkbTypes.Type.PolygonM) - expWkt = 'PolygonM ((0 0 3, 1 0 3, 1 1 3, 2 1 3, 2 2 3, 0 2 3, 0 0 3))' + expWkt = "PolygonM ((0 0 3, 1 0 3, 1 1 3, 2 1 3, 2 2 3, 0 2 3, 0 0 3))" wkt = geom.asWkt() - assert compareWkt(expWkt, wkt), "addMValue to CurvePolygon failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "addMValue to CurvePolygon failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # geometry collection - geom = QgsGeometry.fromWkt('MultiPoint ((1 2),(2 3))') + geom = QgsGeometry.fromWkt("MultiPoint ((1 2),(2 3))") assert geom.get().addMValue(4) self.assertEqual(geom.constGet().wkbType(), QgsWkbTypes.Type.MultiPointM) - expWkt = 'MultiPointM ((1 2 4),(2 3 4))' + expWkt = "MultiPointM ((1 2 4),(2 3 4))" wkt = geom.asWkt() - assert compareWkt(expWkt, wkt), "addMValue to GeometryCollection failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "addMValue to GeometryCollection failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # LineString - geom = QgsGeometry.fromWkt('LineString (1 2, 2 3)') + geom = QgsGeometry.fromWkt("LineString (1 2, 2 3)") assert geom.get().addMValue(4) self.assertEqual(geom.constGet().wkbType(), QgsWkbTypes.Type.LineStringM) - expWkt = 'LineStringM (1 2 4, 2 3 4)' + expWkt = "LineStringM (1 2 4, 2 3 4)" wkt = geom.asWkt() - assert compareWkt(expWkt, wkt), "addMValue to LineString failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt) + assert compareWkt( + expWkt, wkt + ), "addMValue to LineString failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ) # Point - geom = QgsGeometry.fromWkt('Point (1 2)') + geom = QgsGeometry.fromWkt("Point (1 2)") assert geom.get().addMValue(4) self.assertEqual(geom.constGet().wkbType(), QgsWkbTypes.Type.PointM) - expWkt = 'PointM (1 2 4)' + expWkt = "PointM (1 2 4)" wkt = geom.asWkt() - assert compareWkt(expWkt, wkt), f"addMValue to Point failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" + assert compareWkt( + expWkt, wkt + ), f"addMValue to Point failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n" def testDistanceToVertex(self): - """ Test distanceToVertex calculation """ + """Test distanceToVertex calculation""" g = QgsGeometry() self.assertEqual(g.distanceToVertex(0), -1) - g = QgsGeometry.fromWkt('LineString ()') + g = QgsGeometry.fromWkt("LineString ()") self.assertEqual(g.distanceToVertex(0), -1) - g = QgsGeometry.fromWkt('Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))') + g = QgsGeometry.fromWkt("Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))") self.assertEqual(g.distanceToVertex(0), 0) self.assertEqual(g.distanceToVertex(1), 1) self.assertEqual(g.distanceToVertex(2), 2) @@ -3466,12 +4920,16 @@ def testDistanceToVertex(self): self.assertEqual(g.distanceToVertex(5), -1) def testTypeInformation(self): - """ Test type information """ + """Test type information""" types = [ (QgsCircularString, "CircularString", QgsWkbTypes.Type.CircularString), (QgsCompoundCurve, "CompoundCurve", QgsWkbTypes.Type.CompoundCurve), (QgsCurvePolygon, "CurvePolygon", QgsWkbTypes.Type.CurvePolygon), - (QgsGeometryCollection, "GeometryCollection", QgsWkbTypes.Type.GeometryCollection), + ( + QgsGeometryCollection, + "GeometryCollection", + QgsWkbTypes.Type.GeometryCollection, + ), (QgsLineString, "LineString", QgsWkbTypes.Type.LineString), (QgsMultiCurve, "MultiCurve", QgsWkbTypes.Type.MultiCurve), (QgsMultiLineString, "MultiLineString", QgsWkbTypes.Type.MultiLineString), @@ -3494,1637 +4952,4605 @@ def testTypeInformation(self): self.assertEqual(clone.wkbType(), geomtype[2]) def testRelates(self): - """ Test relationships between geometries. Note the bulk of these tests were taken from the PostGIS relate testdata """ - with open(os.path.join(TEST_DATA_DIR, 'relates_data.csv')) as d: + """Test relationships between geometries. Note the bulk of these tests were taken from the PostGIS relate testdata""" + with open(os.path.join(TEST_DATA_DIR, "relates_data.csv")) as d: for i, t in enumerate(d): - test_data = t.strip().split('|') + test_data = t.strip().split("|") geom1 = QgsGeometry.fromWkt(test_data[0]) - assert geom1, f"Relates {i + 1} failed: could not create geom:\n{test_data[0]}\n" + assert ( + geom1 + ), f"Relates {i + 1} failed: could not create geom:\n{test_data[0]}\n" geom2 = QgsGeometry.fromWkt(test_data[1]) - assert geom2, f"Relates {i + 1} failed: could not create geom:\n{test_data[1]}\n" - result = QgsGeometry.createGeometryEngine(geom1.constGet()).relate(geom2.constGet()) + assert ( + geom2 + ), f"Relates {i + 1} failed: could not create geom:\n{test_data[1]}\n" + result = QgsGeometry.createGeometryEngine(geom1.constGet()).relate( + geom2.constGet() + ) exp = test_data[2] - self.assertEqual(result, exp, - "Relates {} failed: mismatch Expected:\n{}\nGot:\n{}\nGeom1:\n{}\nGeom2:\n{}\n".format( - i + 1, exp, result, test_data[0], test_data[1])) + self.assertEqual( + result, + exp, + "Relates {} failed: mismatch Expected:\n{}\nGot:\n{}\nGeom1:\n{}\nGeom2:\n{}\n".format( + i + 1, exp, result, test_data[0], test_data[1] + ), + ) def testWkbTypes(self): - """ Test QgsWkbTypes methods """ + """Test QgsWkbTypes methods""" # test singleType method - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.PointZ) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.PointM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.PointZM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPoint), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPointZ), QgsWkbTypes.Type.PointZ) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPointM), QgsWkbTypes.Type.PointM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPointZM), QgsWkbTypes.Type.PointZM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.LineString), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.LineStringZ), QgsWkbTypes.Type.LineStringZ) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.LineStringM), QgsWkbTypes.Type.LineStringM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.LineStringZM), QgsWkbTypes.Type.LineStringZM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiLineString), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiLineStringZ), QgsWkbTypes.Type.LineStringZ) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiLineStringM), QgsWkbTypes.Type.LineStringM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiLineStringZM), QgsWkbTypes.Type.LineStringZM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.Polygon), QgsWkbTypes.Type.Polygon) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.Type.PolygonZ) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.Type.PolygonM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.PolygonZM), QgsWkbTypes.Type.PolygonZM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPolygon), QgsWkbTypes.Type.Polygon) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPolygonZ), QgsWkbTypes.Type.PolygonZ) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPolygonM), QgsWkbTypes.Type.PolygonM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPolygonZM), QgsWkbTypes.Type.PolygonZM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.GeometryCollection), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.GeometryCollectionZ), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.GeometryCollectionM), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.GeometryCollectionZM), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.CircularString), QgsWkbTypes.Type.CircularString) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.CircularStringZ), QgsWkbTypes.Type.CircularStringZ) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.CircularStringM), QgsWkbTypes.Type.CircularStringM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.CircularStringZM), QgsWkbTypes.Type.CircularStringZM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.CompoundCurve), QgsWkbTypes.Type.CompoundCurve) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.CompoundCurveZ), QgsWkbTypes.Type.CompoundCurveZ) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.CompoundCurveM), QgsWkbTypes.Type.CompoundCurveM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.CompoundCurveZM), QgsWkbTypes.Type.CompoundCurveZM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.CurvePolygon), QgsWkbTypes.Type.CurvePolygon) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.CurvePolygonZ), QgsWkbTypes.Type.CurvePolygonZ) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.CurvePolygonM), QgsWkbTypes.Type.CurvePolygonM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.CurvePolygonZM), QgsWkbTypes.Type.CurvePolygonZM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiCurve), QgsWkbTypes.Type.CompoundCurve) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiCurveZ), QgsWkbTypes.Type.CompoundCurveZ) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiCurveM), QgsWkbTypes.Type.CompoundCurveM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiCurveZM), QgsWkbTypes.Type.CompoundCurveZM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiSurface), QgsWkbTypes.Type.CurvePolygon) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiSurfaceZ), QgsWkbTypes.Type.CurvePolygonZ) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiSurfaceM), QgsWkbTypes.Type.CurvePolygonM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiSurfaceZM), QgsWkbTypes.Type.CurvePolygonZM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.NoGeometry), QgsWkbTypes.Type.NoGeometry) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.Point25D), QgsWkbTypes.Type.Point25D) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.LineString25D), QgsWkbTypes.Type.LineString25D) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.Polygon25D), QgsWkbTypes.Type.Polygon25D) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPoint25D), QgsWkbTypes.Type.Point25D) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiLineString25D), QgsWkbTypes.Type.LineString25D) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPolygon25D), QgsWkbTypes.Type.Polygon25D) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.PolyhedralSurface), QgsWkbTypes.Type.PolyhedralSurface) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.PolyhedralSurfaceZ), QgsWkbTypes.Type.PolyhedralSurfaceZ) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.PolyhedralSurfaceM), QgsWkbTypes.Type.PolyhedralSurfaceM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.PolyhedralSurfaceZM), QgsWkbTypes.Type.PolyhedralSurfaceZM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.TIN), QgsWkbTypes.Type.TIN) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.TINZ), QgsWkbTypes.Type.TINZ) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.TINM), QgsWkbTypes.Type.TINM) - self.assertEqual(QgsWkbTypes.singleType(QgsWkbTypes.Type.TINZM), QgsWkbTypes.Type.TINZM) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.Point + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.PointZ + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.PointM + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.PointZM + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPoint), QgsWkbTypes.Type.Point + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPointZ), + QgsWkbTypes.Type.PointZ, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPointM), + QgsWkbTypes.Type.PointM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPointZM), + QgsWkbTypes.Type.PointZM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.LineString), + QgsWkbTypes.Type.LineString, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.LineStringZ), + QgsWkbTypes.Type.LineStringZ, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.LineStringM), + QgsWkbTypes.Type.LineStringM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.LineStringZM), + QgsWkbTypes.Type.LineStringZM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiLineString), + QgsWkbTypes.Type.LineString, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiLineStringZ), + QgsWkbTypes.Type.LineStringZ, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiLineStringM), + QgsWkbTypes.Type.LineStringM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiLineStringZM), + QgsWkbTypes.Type.LineStringZM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.Polygon), QgsWkbTypes.Type.Polygon + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.Type.PolygonZ + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.Type.PolygonM + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.PolygonZM), + QgsWkbTypes.Type.PolygonZM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPolygon), + QgsWkbTypes.Type.Polygon, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPolygonZ), + QgsWkbTypes.Type.PolygonZ, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPolygonM), + QgsWkbTypes.Type.PolygonM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPolygonZM), + QgsWkbTypes.Type.PolygonZM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.GeometryCollection), + QgsWkbTypes.Type.Unknown, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.GeometryCollectionZ), + QgsWkbTypes.Type.Unknown, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.GeometryCollectionM), + QgsWkbTypes.Type.Unknown, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.GeometryCollectionZM), + QgsWkbTypes.Type.Unknown, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.CircularString), + QgsWkbTypes.Type.CircularString, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.CircularStringZ), + QgsWkbTypes.Type.CircularStringZ, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.CircularStringM), + QgsWkbTypes.Type.CircularStringM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.CircularStringZM), + QgsWkbTypes.Type.CircularStringZM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.CompoundCurve), + QgsWkbTypes.Type.CompoundCurve, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.CompoundCurveZ), + QgsWkbTypes.Type.CompoundCurveZ, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.CompoundCurveM), + QgsWkbTypes.Type.CompoundCurveM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.CompoundCurveZM), + QgsWkbTypes.Type.CompoundCurveZM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.CurvePolygon), + QgsWkbTypes.Type.CurvePolygon, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.CurvePolygonZ), + QgsWkbTypes.Type.CurvePolygonZ, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.CurvePolygonM), + QgsWkbTypes.Type.CurvePolygonM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.CurvePolygonZM), + QgsWkbTypes.Type.CurvePolygonZM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiCurve), + QgsWkbTypes.Type.CompoundCurve, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiCurveZ), + QgsWkbTypes.Type.CompoundCurveZ, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiCurveM), + QgsWkbTypes.Type.CompoundCurveM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiCurveZM), + QgsWkbTypes.Type.CompoundCurveZM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiSurface), + QgsWkbTypes.Type.CurvePolygon, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiSurfaceZ), + QgsWkbTypes.Type.CurvePolygonZ, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiSurfaceM), + QgsWkbTypes.Type.CurvePolygonM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiSurfaceZM), + QgsWkbTypes.Type.CurvePolygonZM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.NoGeometry), + QgsWkbTypes.Type.NoGeometry, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.Point25D), QgsWkbTypes.Type.Point25D + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.LineString25D), + QgsWkbTypes.Type.LineString25D, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.Polygon25D), + QgsWkbTypes.Type.Polygon25D, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPoint25D), + QgsWkbTypes.Type.Point25D, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiLineString25D), + QgsWkbTypes.Type.LineString25D, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.MultiPolygon25D), + QgsWkbTypes.Type.Polygon25D, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.PolyhedralSurface), + QgsWkbTypes.Type.PolyhedralSurface, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.PolyhedralSurfaceZ), + QgsWkbTypes.Type.PolyhedralSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.PolyhedralSurfaceM), + QgsWkbTypes.Type.PolyhedralSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.PolyhedralSurfaceZM), + QgsWkbTypes.Type.PolyhedralSurfaceZM, + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.TIN), QgsWkbTypes.Type.TIN + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.TINZ), QgsWkbTypes.Type.TINZ + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.TINM), QgsWkbTypes.Type.TINM + ) + self.assertEqual( + QgsWkbTypes.singleType(QgsWkbTypes.Type.TINZM), QgsWkbTypes.Type.TINZM + ) # test multiType method - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.MultiPointZ) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.MultiPointM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.MultiPointZM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPoint), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPointZ), QgsWkbTypes.Type.MultiPointZ) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPointM), QgsWkbTypes.Type.MultiPointM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPointZM), QgsWkbTypes.Type.MultiPointZM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.LineString), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.LineStringZ), QgsWkbTypes.Type.MultiLineStringZ) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.LineStringM), QgsWkbTypes.Type.MultiLineStringM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.LineStringZM), QgsWkbTypes.Type.MultiLineStringZM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiLineString), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiLineStringZ), QgsWkbTypes.Type.MultiLineStringZ) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiLineStringM), QgsWkbTypes.Type.MultiLineStringM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiLineStringZM), QgsWkbTypes.Type.MultiLineStringZM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.Polygon), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.PolygonZM), QgsWkbTypes.Type.MultiPolygonZM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPolygon), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPolygonZ), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPolygonM), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPolygonZM), QgsWkbTypes.Type.MultiPolygonZM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.GeometryCollection), QgsWkbTypes.Type.GeometryCollection) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.GeometryCollectionZ), QgsWkbTypes.Type.GeometryCollectionZ) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.GeometryCollectionM), QgsWkbTypes.Type.GeometryCollectionM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.GeometryCollectionZM), QgsWkbTypes.Type.GeometryCollectionZM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.CircularString), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.CircularStringZ), QgsWkbTypes.Type.MultiCurveZ) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.CircularStringM), QgsWkbTypes.Type.MultiCurveM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.CircularStringZM), QgsWkbTypes.Type.MultiCurveZM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.CompoundCurve), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.CompoundCurveZ), QgsWkbTypes.Type.MultiCurveZ) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.CompoundCurveM), QgsWkbTypes.Type.MultiCurveM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.CompoundCurveZM), QgsWkbTypes.Type.MultiCurveZM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.CurvePolygon), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.CurvePolygonZ), QgsWkbTypes.Type.MultiSurfaceZ) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.CurvePolygonM), QgsWkbTypes.Type.MultiSurfaceM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.CurvePolygonZM), QgsWkbTypes.Type.MultiSurfaceZM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiCurve), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiCurveZ), QgsWkbTypes.Type.MultiCurveZ) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiCurveM), QgsWkbTypes.Type.MultiCurveM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiCurveZM), QgsWkbTypes.Type.MultiCurveZM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiSurface), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiSurfaceZ), QgsWkbTypes.Type.MultiSurfaceZ) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiSurfaceM), QgsWkbTypes.Type.MultiSurfaceM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiSurfaceZM), QgsWkbTypes.Type.MultiSurfaceZM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.NoGeometry), QgsWkbTypes.Type.NoGeometry) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.Point25D), QgsWkbTypes.Type.MultiPoint25D) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.LineString25D), QgsWkbTypes.Type.MultiLineString25D) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.Polygon25D), QgsWkbTypes.Type.MultiPolygon25D) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPoint25D), QgsWkbTypes.Type.MultiPoint25D) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiLineString25D), QgsWkbTypes.Type.MultiLineString25D) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPolygon25D), QgsWkbTypes.Type.MultiPolygon25D) - # until we have tin types, these should return multipolygons - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.Triangle), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.TriangleZ), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.TriangleM), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.TriangleZM), QgsWkbTypes.Type.MultiPolygonZM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.PolyhedralSurface), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.PolyhedralSurfaceZ), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.PolyhedralSurfaceM), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.PolyhedralSurfaceZM), QgsWkbTypes.Type.MultiPolygonZM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.TIN), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.TINZ), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.TINM), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.multiType(QgsWkbTypes.Type.TINZM), QgsWkbTypes.Type.MultiPolygonZM) - - # test promoteNonPointTypesToMulti method - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.PointZ) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.PointM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.PointZM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPoint), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPointZ), QgsWkbTypes.Type.MultiPointZ) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPointM), QgsWkbTypes.Type.MultiPointM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPointZM), QgsWkbTypes.Type.MultiPointZM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.LineString), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.LineStringZ), QgsWkbTypes.Type.MultiLineStringZ) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.LineStringM), QgsWkbTypes.Type.MultiLineStringM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.LineStringZM), QgsWkbTypes.Type.MultiLineStringZM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiLineString), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiLineStringZ), QgsWkbTypes.Type.MultiLineStringZ) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiLineStringM), QgsWkbTypes.Type.MultiLineStringM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiLineStringZM), QgsWkbTypes.Type.MultiLineStringZM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.Polygon), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.PolygonZM), QgsWkbTypes.Type.MultiPolygonZM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPolygon), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPolygonZ), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPolygonM), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPolygonZM), QgsWkbTypes.Type.MultiPolygonZM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.GeometryCollection), QgsWkbTypes.Type.GeometryCollection) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.GeometryCollectionZ), QgsWkbTypes.Type.GeometryCollectionZ) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.GeometryCollectionM), QgsWkbTypes.Type.GeometryCollectionM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.GeometryCollectionZM), QgsWkbTypes.Type.GeometryCollectionZM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CircularString), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CircularStringZ), QgsWkbTypes.Type.MultiCurveZ) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CircularStringM), QgsWkbTypes.Type.MultiCurveM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CircularStringZM), QgsWkbTypes.Type.MultiCurveZM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CompoundCurve), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CompoundCurveZ), QgsWkbTypes.Type.MultiCurveZ) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CompoundCurveM), QgsWkbTypes.Type.MultiCurveM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CompoundCurveZM), QgsWkbTypes.Type.MultiCurveZM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CurvePolygon), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CurvePolygonZ), QgsWkbTypes.Type.MultiSurfaceZ) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CurvePolygonM), QgsWkbTypes.Type.MultiSurfaceM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CurvePolygonZM), QgsWkbTypes.Type.MultiSurfaceZM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiCurve), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiCurveZ), QgsWkbTypes.Type.MultiCurveZ) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiCurveM), QgsWkbTypes.Type.MultiCurveM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiCurveZM), QgsWkbTypes.Type.MultiCurveZM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiSurface), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiSurfaceZ), QgsWkbTypes.Type.MultiSurfaceZ) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiSurfaceM), QgsWkbTypes.Type.MultiSurfaceM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiSurfaceZM), QgsWkbTypes.Type.MultiSurfaceZM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.NoGeometry), QgsWkbTypes.Type.NoGeometry) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.Point25D), QgsWkbTypes.Type.Point25D) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.LineString25D), QgsWkbTypes.Type.MultiLineString25D) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.Polygon25D), QgsWkbTypes.Type.MultiPolygon25D) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPoint25D), QgsWkbTypes.Type.MultiPoint25D) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiLineString25D), QgsWkbTypes.Type.MultiLineString25D) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPolygon25D), QgsWkbTypes.Type.MultiPolygon25D) - # until we have tin types, these should return multipolygons - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.Triangle), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.TriangleZ), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.TriangleM), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.TriangleZM), QgsWkbTypes.Type.MultiPolygonZM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.PolyhedralSurface), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.PolyhedralSurfaceZ), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.PolyhedralSurfaceM), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.PolyhedralSurfaceZM), QgsWkbTypes.Type.MultiPolygonZM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.TIN), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.TINZ), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.TINM), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.TINZM), QgsWkbTypes.Type.MultiPolygonZM) - - # test curveType method - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.PointZ) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.PointM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.PointZM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPoint), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPointZ), QgsWkbTypes.Type.MultiPointZ) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPointM), QgsWkbTypes.Type.MultiPointM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPointZM), QgsWkbTypes.Type.MultiPointZM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.LineString), QgsWkbTypes.Type.CompoundCurve) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.LineStringZ), QgsWkbTypes.Type.CompoundCurveZ) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.LineStringM), QgsWkbTypes.Type.CompoundCurveM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.LineStringZM), QgsWkbTypes.Type.CompoundCurveZM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiLineString), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiLineStringZ), QgsWkbTypes.Type.MultiCurveZ) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiLineStringM), QgsWkbTypes.Type.MultiCurveM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiLineStringZM), QgsWkbTypes.Type.MultiCurveZM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.Polygon), QgsWkbTypes.Type.CurvePolygon) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.Type.CurvePolygonZ) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.Type.CurvePolygonM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.PolygonZM), QgsWkbTypes.Type.CurvePolygonZM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPolygon), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPolygonZ), QgsWkbTypes.Type.MultiSurfaceZ) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPolygonM), QgsWkbTypes.Type.MultiSurfaceM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPolygonZM), QgsWkbTypes.Type.MultiSurfaceZM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.GeometryCollection), QgsWkbTypes.Type.GeometryCollection) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.GeometryCollectionZ), QgsWkbTypes.Type.GeometryCollectionZ) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.GeometryCollectionM), QgsWkbTypes.Type.GeometryCollectionM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.GeometryCollectionZM), QgsWkbTypes.Type.GeometryCollectionZM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.CircularString), QgsWkbTypes.Type.CompoundCurve) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.CircularStringZ), QgsWkbTypes.Type.CompoundCurveZ) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.CircularStringM), QgsWkbTypes.Type.CompoundCurveM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.CircularStringZM), QgsWkbTypes.Type.CompoundCurveZM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.CompoundCurve), QgsWkbTypes.Type.CompoundCurve) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.CompoundCurveZ), QgsWkbTypes.Type.CompoundCurveZ) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.CompoundCurveM), QgsWkbTypes.Type.CompoundCurveM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.CompoundCurveZM), QgsWkbTypes.Type.CompoundCurveZM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.CurvePolygon), QgsWkbTypes.Type.CurvePolygon) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.CurvePolygonZ), QgsWkbTypes.Type.CurvePolygonZ) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.CurvePolygonM), QgsWkbTypes.Type.CurvePolygonM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.CurvePolygonZM), QgsWkbTypes.Type.CurvePolygonZM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiCurve), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiCurveZ), QgsWkbTypes.Type.MultiCurveZ) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiCurveM), QgsWkbTypes.Type.MultiCurveM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiCurveZM), QgsWkbTypes.Type.MultiCurveZM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiSurface), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiSurfaceZ), QgsWkbTypes.Type.MultiSurfaceZ) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiSurfaceM), QgsWkbTypes.Type.MultiSurfaceM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiSurfaceZM), QgsWkbTypes.Type.MultiSurfaceZM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.NoGeometry), QgsWkbTypes.Type.NoGeometry) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.Point25D), QgsWkbTypes.Type.MultiPoint25D) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.LineString25D), QgsWkbTypes.Type.CompoundCurveZ) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.Polygon25D), QgsWkbTypes.Type.CurvePolygonZ) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPoint25D), QgsWkbTypes.Type.MultiPoint25D) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiLineString25D), QgsWkbTypes.Type.MultiCurveZ) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPolygon25D), QgsWkbTypes.Type.MultiSurfaceZ) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.PolyhedralSurface), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.PolyhedralSurfaceZ), QgsWkbTypes.Type.MultiSurfaceZ) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.PolyhedralSurfaceM), QgsWkbTypes.Type.MultiSurfaceM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.PolyhedralSurfaceZM), QgsWkbTypes.Type.MultiSurfaceZM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.TIN), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.TINZ), QgsWkbTypes.Type.MultiSurfaceZ) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.TINM), QgsWkbTypes.Type.MultiSurfaceM) - self.assertEqual(QgsWkbTypes.curveType(QgsWkbTypes.Type.TINZM), QgsWkbTypes.Type.MultiSurfaceZM) - - # test linearType method - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.PointZ) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.PointM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.PointZM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPoint), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPointZ), QgsWkbTypes.Type.MultiPointZ) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPointM), QgsWkbTypes.Type.MultiPointM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPointZM), QgsWkbTypes.Type.MultiPointZM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.LineString), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.LineStringZ), QgsWkbTypes.Type.LineStringZ) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.LineStringM), QgsWkbTypes.Type.LineStringM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.LineStringZM), QgsWkbTypes.Type.LineStringZM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiLineString), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiLineStringZ), QgsWkbTypes.Type.MultiLineStringZ) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiLineStringM), QgsWkbTypes.Type.MultiLineStringM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiLineStringZM), QgsWkbTypes.Type.MultiLineStringZM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.Polygon), QgsWkbTypes.Type.Polygon) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.Type.PolygonZ) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.Type.PolygonM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.PolygonZM), QgsWkbTypes.Type.PolygonZM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPolygon), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPolygonZ), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPolygonM), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPolygonZM), QgsWkbTypes.Type.MultiPolygonZM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.GeometryCollection), QgsWkbTypes.Type.GeometryCollection) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.GeometryCollectionZ), QgsWkbTypes.Type.GeometryCollectionZ) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.GeometryCollectionM), QgsWkbTypes.Type.GeometryCollectionM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.GeometryCollectionZM), QgsWkbTypes.Type.GeometryCollectionZM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.CircularString), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.CircularStringZ), QgsWkbTypes.Type.LineStringZ) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.CircularStringM), QgsWkbTypes.Type.LineStringM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.CircularStringZM), QgsWkbTypes.Type.LineStringZM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.CompoundCurve), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.CompoundCurveZ), QgsWkbTypes.Type.LineStringZ) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.CompoundCurveM), QgsWkbTypes.Type.LineStringM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.CompoundCurveZM), QgsWkbTypes.Type.LineStringZM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.CurvePolygon), QgsWkbTypes.Type.Polygon) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.CurvePolygonZ), QgsWkbTypes.Type.PolygonZ) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.CurvePolygonM), QgsWkbTypes.Type.PolygonM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.CurvePolygonZM), QgsWkbTypes.Type.PolygonZM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiCurve), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiCurveZ), QgsWkbTypes.Type.MultiLineStringZ) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiCurveM), QgsWkbTypes.Type.MultiLineStringM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiCurveZM), QgsWkbTypes.Type.MultiLineStringZM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiSurface), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiSurfaceZ), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiSurfaceM), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiSurfaceZM), QgsWkbTypes.Type.MultiPolygonZM) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.NoGeometry), QgsWkbTypes.Type.NoGeometry) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.Point25D), QgsWkbTypes.Type.Point25D) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.LineString25D), QgsWkbTypes.Type.LineString25D) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.Polygon25D), QgsWkbTypes.Type.Polygon25D) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPoint25D), QgsWkbTypes.Type.MultiPoint25D) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiLineString25D), QgsWkbTypes.Type.MultiLineString25D) - self.assertEqual(QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPolygon25D), QgsWkbTypes.Type.MultiPolygon25D) - - # test flatType method - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPoint), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPointZ), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPointM), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPointZM), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.LineString), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.LineStringZ), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.LineStringM), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.LineStringZM), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiLineString), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiLineStringZ), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiLineStringM), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiLineStringZM), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.Polygon), QgsWkbTypes.Type.Polygon) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.Type.Polygon) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.Type.Polygon) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.PolygonZM), QgsWkbTypes.Type.Polygon) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPolygon), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPolygonZ), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPolygonM), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPolygonZM), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.GeometryCollection), QgsWkbTypes.Type.GeometryCollection) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.GeometryCollectionZ), QgsWkbTypes.Type.GeometryCollection) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.GeometryCollectionM), QgsWkbTypes.Type.GeometryCollection) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.GeometryCollectionZM), QgsWkbTypes.Type.GeometryCollection) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.CircularString), QgsWkbTypes.Type.CircularString) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.CircularStringZ), QgsWkbTypes.Type.CircularString) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.CircularStringM), QgsWkbTypes.Type.CircularString) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.CircularStringZM), QgsWkbTypes.Type.CircularString) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.CompoundCurve), QgsWkbTypes.Type.CompoundCurve) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.CompoundCurveZ), QgsWkbTypes.Type.CompoundCurve) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.CompoundCurveM), QgsWkbTypes.Type.CompoundCurve) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.CompoundCurveZM), QgsWkbTypes.Type.CompoundCurve) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.CurvePolygon), QgsWkbTypes.Type.CurvePolygon) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.CurvePolygonZ), QgsWkbTypes.Type.CurvePolygon) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.CurvePolygonM), QgsWkbTypes.Type.CurvePolygon) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.CurvePolygonZM), QgsWkbTypes.Type.CurvePolygon) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiCurve), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiCurveZ), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiCurveM), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiCurveZM), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiSurface), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiSurfaceZ), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiSurfaceM), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiSurfaceZM), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.NoGeometry), QgsWkbTypes.Type.NoGeometry) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.Point25D), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.LineString25D), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.Polygon25D), QgsWkbTypes.Type.Polygon) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPoint25D), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiLineString25D), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPolygon25D), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.PolyhedralSurface), QgsWkbTypes.Type.PolyhedralSurface) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.PolyhedralSurfaceZ), QgsWkbTypes.Type.PolyhedralSurface) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.PolyhedralSurfaceM), QgsWkbTypes.Type.PolyhedralSurface) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.PolyhedralSurfaceZM), QgsWkbTypes.Type.PolyhedralSurface) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.TIN), QgsWkbTypes.Type.TIN) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.TINZ), QgsWkbTypes.Type.TIN) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.TINM), QgsWkbTypes.Type.TIN) - self.assertEqual(QgsWkbTypes.flatType(QgsWkbTypes.Type.TINZM), QgsWkbTypes.Type.TIN) - - # test geometryType method - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.Unknown), QgsWkbTypes.GeometryType.UnknownGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.Point), QgsWkbTypes.GeometryType.PointGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.PointZ), QgsWkbTypes.GeometryType.PointGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.PointM), QgsWkbTypes.GeometryType.PointGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.PointZM), QgsWkbTypes.GeometryType.PointGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPoint), QgsWkbTypes.GeometryType.PointGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPointZ), QgsWkbTypes.GeometryType.PointGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPointM), QgsWkbTypes.GeometryType.PointGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPointZM), QgsWkbTypes.GeometryType.PointGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.LineString), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.LineStringZ), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.LineStringM), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.LineStringZM), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiLineString), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiLineStringZ), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiLineStringM), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiLineStringZM), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.Polygon), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.PolygonZM), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPolygon), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPolygonZ), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPolygonM), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPolygonZM), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.GeometryCollection), QgsWkbTypes.GeometryType.UnknownGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.GeometryCollectionZ), QgsWkbTypes.GeometryType.UnknownGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.GeometryCollectionM), QgsWkbTypes.GeometryType.UnknownGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.GeometryCollectionZM), QgsWkbTypes.GeometryType.UnknownGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.CircularString), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.CircularStringZ), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.CircularStringM), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.CircularStringZM), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.CompoundCurve), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.CompoundCurveZ), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.CompoundCurveM), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.CompoundCurveZM), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.CurvePolygon), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.CurvePolygonZ), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.CurvePolygonM), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.CurvePolygonZM), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiCurve), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiCurveZ), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiCurveM), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiCurveZM), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiSurface), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiSurfaceZ), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiSurfaceM), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiSurfaceZM), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.NoGeometry), QgsWkbTypes.GeometryType.NullGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.Point25D), QgsWkbTypes.GeometryType.PointGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.LineString25D), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.Polygon25D), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPoint25D), QgsWkbTypes.GeometryType.PointGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiLineString25D), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPolygon25D), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.PolyhedralSurface), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.PolyhedralSurfaceZ), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.PolyhedralSurfaceM), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.PolyhedralSurfaceZM), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.TIN), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.TINZ), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.TINM), QgsWkbTypes.GeometryType.PolygonGeometry) - self.assertEqual(QgsWkbTypes.geometryType(QgsWkbTypes.Type.TINZM), QgsWkbTypes.GeometryType.PolygonGeometry) - - # test displayString method - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.Unknown), 'Unknown') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.Point), 'Point') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.PointZ), 'PointZ') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.PointM), 'PointM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.PointZM), 'PointZM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPoint), 'MultiPoint') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPointZ), 'MultiPointZ') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPointM), 'MultiPointM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPointZM), 'MultiPointZM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.LineString), 'LineString') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.LineStringZ), 'LineStringZ') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.LineStringM), 'LineStringM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.LineStringZM), 'LineStringZM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiLineString), 'MultiLineString') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiLineStringZ), 'MultiLineStringZ') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiLineStringM), 'MultiLineStringM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiLineStringZM), 'MultiLineStringZM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.Polygon), 'Polygon') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.PolygonZ), 'PolygonZ') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.PolygonM), 'PolygonM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.PolygonZM), 'PolygonZM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPolygon), 'MultiPolygon') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPolygonZ), 'MultiPolygonZ') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPolygonM), 'MultiPolygonM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPolygonZM), 'MultiPolygonZM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.GeometryCollection), 'GeometryCollection') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.GeometryCollectionZ), 'GeometryCollectionZ') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.GeometryCollectionM), 'GeometryCollectionM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.GeometryCollectionZM), 'GeometryCollectionZM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.CircularString), 'CircularString') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.CircularStringZ), 'CircularStringZ') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.CircularStringM), 'CircularStringM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.CircularStringZM), 'CircularStringZM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.CompoundCurve), 'CompoundCurve') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.CompoundCurveZ), 'CompoundCurveZ') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.CompoundCurveM), 'CompoundCurveM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.CompoundCurveZM), 'CompoundCurveZM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.CurvePolygon), 'CurvePolygon') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.CurvePolygonZ), 'CurvePolygonZ') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.CurvePolygonM), 'CurvePolygonM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.CurvePolygonZM), 'CurvePolygonZM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiCurve), 'MultiCurve') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiCurveZ), 'MultiCurveZ') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiCurveM), 'MultiCurveM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiCurveZM), 'MultiCurveZM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiSurface), 'MultiSurface') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiSurfaceZ), 'MultiSurfaceZ') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiSurfaceM), 'MultiSurfaceM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiSurfaceZM), 'MultiSurfaceZM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.NoGeometry), 'NoGeometry') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.Point25D), 'Point25D') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.LineString25D), 'LineString25D') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.Polygon25D), 'Polygon25D') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPoint25D), 'MultiPoint25D') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiLineString25D), 'MultiLineString25D') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPolygon25D), 'MultiPolygon25D') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.PolyhedralSurface), 'PolyhedralSurface') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.PolyhedralSurfaceZ), 'PolyhedralSurfaceZ') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.PolyhedralSurfaceM), 'PolyhedralSurfaceM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.PolyhedralSurfaceZM), 'PolyhedralSurfaceZM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.TIN), 'TIN') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.TINZ), 'TINZ') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.TINM), 'TINM') - self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.TINZM), 'TINZM') - - # test parseType method - self.assertEqual(QgsWkbTypes.parseType('point( 1 2 )'), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.parseType('POINT( 1 2 )'), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.parseType(' point ( 1 2 ) '), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.parseType('point'), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.parseType('LINE STRING( 1 2, 3 4 )'), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.parseType('POINTZ( 1 2 )'), QgsWkbTypes.Type.PointZ) - self.assertEqual(QgsWkbTypes.parseType('POINT z m'), QgsWkbTypes.Type.PointZM) - self.assertEqual(QgsWkbTypes.parseType('bad'), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.parseType('POLYHEDRALSURFACE (((0 0,0 1,1 1,0 0)))'), QgsWkbTypes.Type.PolyhedralSurface) - self.assertEqual(QgsWkbTypes.parseType('POLYHEDRALSURFACE Z (((0 0 0,0 1 0,1 1 0,0 0 0)))'), QgsWkbTypes.Type.PolyhedralSurfaceZ) - self.assertEqual(QgsWkbTypes.parseType('POLYHEDRALSURFACE M (((0 0 3,0 1 3,1 1 3,0 0 3)))'), QgsWkbTypes.Type.PolyhedralSurfaceM) - self.assertEqual(QgsWkbTypes.parseType('POLYHEDRALSURFACE ZM (((0 0 3 4,0 1 3 4,1 1 3 4,0 0 3 4)))'), QgsWkbTypes.Type.PolyhedralSurfaceZM) - self.assertEqual(QgsWkbTypes.parseType('TIN (((0 0,0 1,1 1,0 0)))'), QgsWkbTypes.Type.TIN) - self.assertEqual(QgsWkbTypes.parseType('TIN Z (((0 0 0,0 1 0,1 1 0,0 0 0)))'), QgsWkbTypes.Type.TINZ) - self.assertEqual(QgsWkbTypes.parseType('TIN M (((0 0 3,0 1 3,1 1 3,0 0 3)))'), QgsWkbTypes.Type.TINM) - self.assertEqual(QgsWkbTypes.parseType('TIN ZM (((0 0 3 4,0 1 3 4,1 1 3 4,0 0 3 4)))'), QgsWkbTypes.Type.TINZM) - - # test wkbDimensions method - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.Unknown), 0) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.Point), 0) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PointZ), 0) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PointM), 0) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PointZM), 0) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPoint), 0) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPointZ), 0) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPointM), 0) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPointZM), 0) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.LineString), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.LineStringZ), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.LineStringM), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.LineStringZM), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiLineString), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiLineStringZ), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiLineStringM), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiLineStringZM), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.Polygon), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PolygonZ), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PolygonM), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PolygonZM), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPolygon), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPolygonZ), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPolygonM), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPolygonZM), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.GeometryCollection), 0) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.GeometryCollectionZ), 0) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.GeometryCollectionM), 0) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.GeometryCollectionZM), 0) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CircularString), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CircularStringZ), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CircularStringM), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CircularStringZM), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CompoundCurve), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CompoundCurveZ), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CompoundCurveM), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CompoundCurveZM), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CurvePolygon), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CurvePolygonZ), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CurvePolygonM), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CurvePolygonZM), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiCurve), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiCurveZ), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiCurveM), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiCurveZM), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiSurface), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiSurfaceZ), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiSurfaceM), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiSurfaceZM), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.NoGeometry), 0) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.Point25D), 0) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.LineString25D), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.Polygon25D), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPoint25D), 0) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiLineString25D), 1) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPolygon25D), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PolyhedralSurface), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PolyhedralSurfaceZ), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PolyhedralSurfaceM), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PolyhedralSurfaceZM), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.TIN), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.TINZ), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.TINM), 2) - self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.TINZM), 2) - - # test coordDimensions method - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.Unknown), 0) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.Point), 2) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PointZ), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PointM), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PointZM), 4) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiPoint), 2) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiPointZ), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiPointM), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiPointZM), 4) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.LineString), 2) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.LineStringZ), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.LineStringM), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.LineStringZM), 4) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiLineString), 2) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiLineStringZ), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiLineStringM), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiLineStringZM), 4) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.Polygon), 2) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PolygonZ), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PolygonM), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PolygonZM), 4) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiPolygon), 2) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiPolygonZ), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiPolygonM), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiPolygonZM), 4) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.GeometryCollection), 2) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.GeometryCollectionZ), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.GeometryCollectionM), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.GeometryCollectionZM), 4) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CircularString), 2) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CircularStringZ), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CircularStringM), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CircularStringZM), 4) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CompoundCurve), 2) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CompoundCurveZ), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CompoundCurveM), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CompoundCurveZM), 4) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CurvePolygon), 2) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CurvePolygonZ), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CurvePolygonM), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CurvePolygonZM), 4) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiCurve), 2) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiCurveZ), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiCurveM), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiCurveZM), 4) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiSurface), 2) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiSurfaceZ), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiSurfaceM), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiSurfaceZM), 4) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.NoGeometry), 0) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.MultiPoint + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.MultiPointZ + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.MultiPointM + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.PointZM), + QgsWkbTypes.Type.MultiPointZM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPoint), + QgsWkbTypes.Type.MultiPoint, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPointZ), + QgsWkbTypes.Type.MultiPointZ, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPointM), + QgsWkbTypes.Type.MultiPointM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPointZM), + QgsWkbTypes.Type.MultiPointZM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.LineString), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.LineStringZ), + QgsWkbTypes.Type.MultiLineStringZ, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.LineStringM), + QgsWkbTypes.Type.MultiLineStringM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.LineStringZM), + QgsWkbTypes.Type.MultiLineStringZM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiLineString), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiLineStringZ), + QgsWkbTypes.Type.MultiLineStringZ, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiLineStringM), + QgsWkbTypes.Type.MultiLineStringM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiLineStringZM), + QgsWkbTypes.Type.MultiLineStringZM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.Polygon), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.PolygonZ), + QgsWkbTypes.Type.MultiPolygonZ, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.PolygonM), + QgsWkbTypes.Type.MultiPolygonM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.PolygonZM), + QgsWkbTypes.Type.MultiPolygonZM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPolygon), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPolygonZ), + QgsWkbTypes.Type.MultiPolygonZ, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPolygonM), + QgsWkbTypes.Type.MultiPolygonM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPolygonZM), + QgsWkbTypes.Type.MultiPolygonZM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.GeometryCollection), + QgsWkbTypes.Type.GeometryCollection, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.GeometryCollectionZ), + QgsWkbTypes.Type.GeometryCollectionZ, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.GeometryCollectionM), + QgsWkbTypes.Type.GeometryCollectionM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.GeometryCollectionZM), + QgsWkbTypes.Type.GeometryCollectionZM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.CircularString), + QgsWkbTypes.Type.MultiCurve, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.CircularStringZ), + QgsWkbTypes.Type.MultiCurveZ, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.CircularStringM), + QgsWkbTypes.Type.MultiCurveM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.CircularStringZM), + QgsWkbTypes.Type.MultiCurveZM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.CompoundCurve), + QgsWkbTypes.Type.MultiCurve, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.CompoundCurveZ), + QgsWkbTypes.Type.MultiCurveZ, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.CompoundCurveM), + QgsWkbTypes.Type.MultiCurveM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.CompoundCurveZM), + QgsWkbTypes.Type.MultiCurveZM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.CurvePolygon), + QgsWkbTypes.Type.MultiSurface, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.CurvePolygonZ), + QgsWkbTypes.Type.MultiSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.CurvePolygonM), + QgsWkbTypes.Type.MultiSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.CurvePolygonZM), + QgsWkbTypes.Type.MultiSurfaceZM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiCurve), + QgsWkbTypes.Type.MultiCurve, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiCurveZ), + QgsWkbTypes.Type.MultiCurveZ, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiCurveM), + QgsWkbTypes.Type.MultiCurveM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiCurveZM), + QgsWkbTypes.Type.MultiCurveZM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiSurface), + QgsWkbTypes.Type.MultiSurface, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiSurfaceZ), + QgsWkbTypes.Type.MultiSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiSurfaceM), + QgsWkbTypes.Type.MultiSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiSurfaceZM), + QgsWkbTypes.Type.MultiSurfaceZM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.NoGeometry), + QgsWkbTypes.Type.NoGeometry, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.Point25D), + QgsWkbTypes.Type.MultiPoint25D, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.LineString25D), + QgsWkbTypes.Type.MultiLineString25D, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.Polygon25D), + QgsWkbTypes.Type.MultiPolygon25D, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPoint25D), + QgsWkbTypes.Type.MultiPoint25D, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiLineString25D), + QgsWkbTypes.Type.MultiLineString25D, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.MultiPolygon25D), + QgsWkbTypes.Type.MultiPolygon25D, + ) + # until we have tin types, these should return multipolygons + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.Triangle), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.TriangleZ), + QgsWkbTypes.Type.MultiPolygonZ, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.TriangleM), + QgsWkbTypes.Type.MultiPolygonM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.TriangleZM), + QgsWkbTypes.Type.MultiPolygonZM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.PolyhedralSurface), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.PolyhedralSurfaceZ), + QgsWkbTypes.Type.MultiPolygonZ, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.PolyhedralSurfaceM), + QgsWkbTypes.Type.MultiPolygonM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.PolyhedralSurfaceZM), + QgsWkbTypes.Type.MultiPolygonZM, + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.TIN), QgsWkbTypes.Type.MultiPolygon + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.TINZ), QgsWkbTypes.Type.MultiPolygonZ + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.TINM), QgsWkbTypes.Type.MultiPolygonM + ) + self.assertEqual( + QgsWkbTypes.multiType(QgsWkbTypes.Type.TINZM), + QgsWkbTypes.Type.MultiPolygonZM, + ) + + # test promoteNonPointTypesToMulti method + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.Unknown), + QgsWkbTypes.Type.Unknown, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.Point), + QgsWkbTypes.Type.Point, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.PointZ), + QgsWkbTypes.Type.PointZ, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.PointM), + QgsWkbTypes.Type.PointM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.PointZM), + QgsWkbTypes.Type.PointZM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPoint), + QgsWkbTypes.Type.MultiPoint, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPointZ), + QgsWkbTypes.Type.MultiPointZ, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPointM), + QgsWkbTypes.Type.MultiPointM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPointZM), + QgsWkbTypes.Type.MultiPointZM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.LineString), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.LineStringZ), + QgsWkbTypes.Type.MultiLineStringZ, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.LineStringM), + QgsWkbTypes.Type.MultiLineStringM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.LineStringZM), + QgsWkbTypes.Type.MultiLineStringZM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiLineString), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiLineStringZ), + QgsWkbTypes.Type.MultiLineStringZ, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiLineStringM), + QgsWkbTypes.Type.MultiLineStringM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiLineStringZM), + QgsWkbTypes.Type.MultiLineStringZM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.Polygon), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.PolygonZ), + QgsWkbTypes.Type.MultiPolygonZ, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.PolygonM), + QgsWkbTypes.Type.MultiPolygonM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.PolygonZM), + QgsWkbTypes.Type.MultiPolygonZM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPolygon), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPolygonZ), + QgsWkbTypes.Type.MultiPolygonZ, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPolygonM), + QgsWkbTypes.Type.MultiPolygonM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPolygonZM), + QgsWkbTypes.Type.MultiPolygonZM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti( + QgsWkbTypes.Type.GeometryCollection + ), + QgsWkbTypes.Type.GeometryCollection, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti( + QgsWkbTypes.Type.GeometryCollectionZ + ), + QgsWkbTypes.Type.GeometryCollectionZ, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti( + QgsWkbTypes.Type.GeometryCollectionM + ), + QgsWkbTypes.Type.GeometryCollectionM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti( + QgsWkbTypes.Type.GeometryCollectionZM + ), + QgsWkbTypes.Type.GeometryCollectionZM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CircularString), + QgsWkbTypes.Type.MultiCurve, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CircularStringZ), + QgsWkbTypes.Type.MultiCurveZ, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CircularStringM), + QgsWkbTypes.Type.MultiCurveM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CircularStringZM), + QgsWkbTypes.Type.MultiCurveZM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CompoundCurve), + QgsWkbTypes.Type.MultiCurve, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CompoundCurveZ), + QgsWkbTypes.Type.MultiCurveZ, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CompoundCurveM), + QgsWkbTypes.Type.MultiCurveM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CompoundCurveZM), + QgsWkbTypes.Type.MultiCurveZM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CurvePolygon), + QgsWkbTypes.Type.MultiSurface, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CurvePolygonZ), + QgsWkbTypes.Type.MultiSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CurvePolygonM), + QgsWkbTypes.Type.MultiSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.CurvePolygonZM), + QgsWkbTypes.Type.MultiSurfaceZM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiCurve), + QgsWkbTypes.Type.MultiCurve, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiCurveZ), + QgsWkbTypes.Type.MultiCurveZ, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiCurveM), + QgsWkbTypes.Type.MultiCurveM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiCurveZM), + QgsWkbTypes.Type.MultiCurveZM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiSurface), + QgsWkbTypes.Type.MultiSurface, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiSurfaceZ), + QgsWkbTypes.Type.MultiSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiSurfaceM), + QgsWkbTypes.Type.MultiSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiSurfaceZM), + QgsWkbTypes.Type.MultiSurfaceZM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.NoGeometry), + QgsWkbTypes.Type.NoGeometry, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.Point25D), + QgsWkbTypes.Type.Point25D, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.LineString25D), + QgsWkbTypes.Type.MultiLineString25D, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.Polygon25D), + QgsWkbTypes.Type.MultiPolygon25D, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPoint25D), + QgsWkbTypes.Type.MultiPoint25D, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti( + QgsWkbTypes.Type.MultiLineString25D + ), + QgsWkbTypes.Type.MultiLineString25D, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.MultiPolygon25D), + QgsWkbTypes.Type.MultiPolygon25D, + ) + # until we have tin types, these should return multipolygons + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.Triangle), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.TriangleZ), + QgsWkbTypes.Type.MultiPolygonZ, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.TriangleM), + QgsWkbTypes.Type.MultiPolygonM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.TriangleZM), + QgsWkbTypes.Type.MultiPolygonZM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.PolyhedralSurface), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti( + QgsWkbTypes.Type.PolyhedralSurfaceZ + ), + QgsWkbTypes.Type.MultiPolygonZ, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti( + QgsWkbTypes.Type.PolyhedralSurfaceM + ), + QgsWkbTypes.Type.MultiPolygonM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti( + QgsWkbTypes.Type.PolyhedralSurfaceZM + ), + QgsWkbTypes.Type.MultiPolygonZM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.TIN), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.TINZ), + QgsWkbTypes.Type.MultiPolygonZ, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.TINM), + QgsWkbTypes.Type.MultiPolygonM, + ) + self.assertEqual( + QgsWkbTypes.promoteNonPointTypesToMulti(QgsWkbTypes.Type.TINZM), + QgsWkbTypes.Type.MultiPolygonZM, + ) + + # test curveType method + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.Point + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.PointZ + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.PointM + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.PointZM + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPoint), + QgsWkbTypes.Type.MultiPoint, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPointZ), + QgsWkbTypes.Type.MultiPointZ, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPointM), + QgsWkbTypes.Type.MultiPointM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPointZM), + QgsWkbTypes.Type.MultiPointZM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.LineString), + QgsWkbTypes.Type.CompoundCurve, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.LineStringZ), + QgsWkbTypes.Type.CompoundCurveZ, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.LineStringM), + QgsWkbTypes.Type.CompoundCurveM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.LineStringZM), + QgsWkbTypes.Type.CompoundCurveZM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiLineString), + QgsWkbTypes.Type.MultiCurve, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiLineStringZ), + QgsWkbTypes.Type.MultiCurveZ, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiLineStringM), + QgsWkbTypes.Type.MultiCurveM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiLineStringZM), + QgsWkbTypes.Type.MultiCurveZM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.Polygon), + QgsWkbTypes.Type.CurvePolygon, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.PolygonZ), + QgsWkbTypes.Type.CurvePolygonZ, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.PolygonM), + QgsWkbTypes.Type.CurvePolygonM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.PolygonZM), + QgsWkbTypes.Type.CurvePolygonZM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPolygon), + QgsWkbTypes.Type.MultiSurface, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPolygonZ), + QgsWkbTypes.Type.MultiSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPolygonM), + QgsWkbTypes.Type.MultiSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPolygonZM), + QgsWkbTypes.Type.MultiSurfaceZM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.GeometryCollection), + QgsWkbTypes.Type.GeometryCollection, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.GeometryCollectionZ), + QgsWkbTypes.Type.GeometryCollectionZ, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.GeometryCollectionM), + QgsWkbTypes.Type.GeometryCollectionM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.GeometryCollectionZM), + QgsWkbTypes.Type.GeometryCollectionZM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.CircularString), + QgsWkbTypes.Type.CompoundCurve, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.CircularStringZ), + QgsWkbTypes.Type.CompoundCurveZ, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.CircularStringM), + QgsWkbTypes.Type.CompoundCurveM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.CircularStringZM), + QgsWkbTypes.Type.CompoundCurveZM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.CompoundCurve), + QgsWkbTypes.Type.CompoundCurve, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.CompoundCurveZ), + QgsWkbTypes.Type.CompoundCurveZ, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.CompoundCurveM), + QgsWkbTypes.Type.CompoundCurveM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.CompoundCurveZM), + QgsWkbTypes.Type.CompoundCurveZM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.CurvePolygon), + QgsWkbTypes.Type.CurvePolygon, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.CurvePolygonZ), + QgsWkbTypes.Type.CurvePolygonZ, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.CurvePolygonM), + QgsWkbTypes.Type.CurvePolygonM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.CurvePolygonZM), + QgsWkbTypes.Type.CurvePolygonZM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiCurve), + QgsWkbTypes.Type.MultiCurve, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiCurveZ), + QgsWkbTypes.Type.MultiCurveZ, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiCurveM), + QgsWkbTypes.Type.MultiCurveM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiCurveZM), + QgsWkbTypes.Type.MultiCurveZM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiSurface), + QgsWkbTypes.Type.MultiSurface, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiSurfaceZ), + QgsWkbTypes.Type.MultiSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiSurfaceM), + QgsWkbTypes.Type.MultiSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiSurfaceZM), + QgsWkbTypes.Type.MultiSurfaceZM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.NoGeometry), + QgsWkbTypes.Type.NoGeometry, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.Point25D), + QgsWkbTypes.Type.MultiPoint25D, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.LineString25D), + QgsWkbTypes.Type.CompoundCurveZ, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.Polygon25D), + QgsWkbTypes.Type.CurvePolygonZ, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPoint25D), + QgsWkbTypes.Type.MultiPoint25D, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiLineString25D), + QgsWkbTypes.Type.MultiCurveZ, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.MultiPolygon25D), + QgsWkbTypes.Type.MultiSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.PolyhedralSurface), + QgsWkbTypes.Type.MultiSurface, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.PolyhedralSurfaceZ), + QgsWkbTypes.Type.MultiSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.PolyhedralSurfaceM), + QgsWkbTypes.Type.MultiSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.PolyhedralSurfaceZM), + QgsWkbTypes.Type.MultiSurfaceZM, + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.TIN), QgsWkbTypes.Type.MultiSurface + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.TINZ), QgsWkbTypes.Type.MultiSurfaceZ + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.TINM), QgsWkbTypes.Type.MultiSurfaceM + ) + self.assertEqual( + QgsWkbTypes.curveType(QgsWkbTypes.Type.TINZM), + QgsWkbTypes.Type.MultiSurfaceZM, + ) + + # test linearType method + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.Point + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.PointZ + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.PointM + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.PointZM + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPoint), + QgsWkbTypes.Type.MultiPoint, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPointZ), + QgsWkbTypes.Type.MultiPointZ, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPointM), + QgsWkbTypes.Type.MultiPointM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPointZM), + QgsWkbTypes.Type.MultiPointZM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.LineString), + QgsWkbTypes.Type.LineString, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.LineStringZ), + QgsWkbTypes.Type.LineStringZ, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.LineStringM), + QgsWkbTypes.Type.LineStringM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.LineStringZM), + QgsWkbTypes.Type.LineStringZM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiLineString), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiLineStringZ), + QgsWkbTypes.Type.MultiLineStringZ, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiLineStringM), + QgsWkbTypes.Type.MultiLineStringM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiLineStringZM), + QgsWkbTypes.Type.MultiLineStringZM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.Polygon), QgsWkbTypes.Type.Polygon + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.Type.PolygonZ + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.Type.PolygonM + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.PolygonZM), + QgsWkbTypes.Type.PolygonZM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPolygon), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPolygonZ), + QgsWkbTypes.Type.MultiPolygonZ, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPolygonM), + QgsWkbTypes.Type.MultiPolygonM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPolygonZM), + QgsWkbTypes.Type.MultiPolygonZM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.GeometryCollection), + QgsWkbTypes.Type.GeometryCollection, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.GeometryCollectionZ), + QgsWkbTypes.Type.GeometryCollectionZ, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.GeometryCollectionM), + QgsWkbTypes.Type.GeometryCollectionM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.GeometryCollectionZM), + QgsWkbTypes.Type.GeometryCollectionZM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.CircularString), + QgsWkbTypes.Type.LineString, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.CircularStringZ), + QgsWkbTypes.Type.LineStringZ, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.CircularStringM), + QgsWkbTypes.Type.LineStringM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.CircularStringZM), + QgsWkbTypes.Type.LineStringZM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.CompoundCurve), + QgsWkbTypes.Type.LineString, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.CompoundCurveZ), + QgsWkbTypes.Type.LineStringZ, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.CompoundCurveM), + QgsWkbTypes.Type.LineStringM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.CompoundCurveZM), + QgsWkbTypes.Type.LineStringZM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.CurvePolygon), + QgsWkbTypes.Type.Polygon, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.CurvePolygonZ), + QgsWkbTypes.Type.PolygonZ, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.CurvePolygonM), + QgsWkbTypes.Type.PolygonM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.CurvePolygonZM), + QgsWkbTypes.Type.PolygonZM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiCurve), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiCurveZ), + QgsWkbTypes.Type.MultiLineStringZ, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiCurveM), + QgsWkbTypes.Type.MultiLineStringM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiCurveZM), + QgsWkbTypes.Type.MultiLineStringZM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiSurface), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiSurfaceZ), + QgsWkbTypes.Type.MultiPolygonZ, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiSurfaceM), + QgsWkbTypes.Type.MultiPolygonM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiSurfaceZM), + QgsWkbTypes.Type.MultiPolygonZM, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.NoGeometry), + QgsWkbTypes.Type.NoGeometry, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.Point25D), QgsWkbTypes.Type.Point25D + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.LineString25D), + QgsWkbTypes.Type.LineString25D, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.Polygon25D), + QgsWkbTypes.Type.Polygon25D, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPoint25D), + QgsWkbTypes.Type.MultiPoint25D, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiLineString25D), + QgsWkbTypes.Type.MultiLineString25D, + ) + self.assertEqual( + QgsWkbTypes.linearType(QgsWkbTypes.Type.MultiPolygon25D), + QgsWkbTypes.Type.MultiPolygon25D, + ) + + # test flatType method + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.Point + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.Point + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.Point + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.Point + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPoint), + QgsWkbTypes.Type.MultiPoint, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPointZ), + QgsWkbTypes.Type.MultiPoint, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPointM), + QgsWkbTypes.Type.MultiPoint, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPointZM), + QgsWkbTypes.Type.MultiPoint, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.LineString), + QgsWkbTypes.Type.LineString, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.LineStringZ), + QgsWkbTypes.Type.LineString, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.LineStringM), + QgsWkbTypes.Type.LineString, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.LineStringZM), + QgsWkbTypes.Type.LineString, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiLineString), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiLineStringZ), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiLineStringM), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiLineStringZM), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.Polygon), QgsWkbTypes.Type.Polygon + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.Type.Polygon + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.Type.Polygon + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.PolygonZM), QgsWkbTypes.Type.Polygon + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPolygon), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPolygonZ), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPolygonM), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPolygonZM), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.GeometryCollection), + QgsWkbTypes.Type.GeometryCollection, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.GeometryCollectionZ), + QgsWkbTypes.Type.GeometryCollection, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.GeometryCollectionM), + QgsWkbTypes.Type.GeometryCollection, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.GeometryCollectionZM), + QgsWkbTypes.Type.GeometryCollection, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.CircularString), + QgsWkbTypes.Type.CircularString, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.CircularStringZ), + QgsWkbTypes.Type.CircularString, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.CircularStringM), + QgsWkbTypes.Type.CircularString, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.CircularStringZM), + QgsWkbTypes.Type.CircularString, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.CompoundCurve), + QgsWkbTypes.Type.CompoundCurve, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.CompoundCurveZ), + QgsWkbTypes.Type.CompoundCurve, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.CompoundCurveM), + QgsWkbTypes.Type.CompoundCurve, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.CompoundCurveZM), + QgsWkbTypes.Type.CompoundCurve, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.CurvePolygon), + QgsWkbTypes.Type.CurvePolygon, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.CurvePolygonZ), + QgsWkbTypes.Type.CurvePolygon, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.CurvePolygonM), + QgsWkbTypes.Type.CurvePolygon, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.CurvePolygonZM), + QgsWkbTypes.Type.CurvePolygon, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiCurve), + QgsWkbTypes.Type.MultiCurve, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiCurveZ), + QgsWkbTypes.Type.MultiCurve, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiCurveM), + QgsWkbTypes.Type.MultiCurve, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiCurveZM), + QgsWkbTypes.Type.MultiCurve, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiSurface), + QgsWkbTypes.Type.MultiSurface, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiSurfaceZ), + QgsWkbTypes.Type.MultiSurface, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiSurfaceM), + QgsWkbTypes.Type.MultiSurface, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiSurfaceZM), + QgsWkbTypes.Type.MultiSurface, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.NoGeometry), + QgsWkbTypes.Type.NoGeometry, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.Point25D), QgsWkbTypes.Type.Point + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.LineString25D), + QgsWkbTypes.Type.LineString, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.Polygon25D), QgsWkbTypes.Type.Polygon + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPoint25D), + QgsWkbTypes.Type.MultiPoint, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiLineString25D), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.MultiPolygon25D), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.PolyhedralSurface), + QgsWkbTypes.Type.PolyhedralSurface, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.PolyhedralSurfaceZ), + QgsWkbTypes.Type.PolyhedralSurface, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.PolyhedralSurfaceM), + QgsWkbTypes.Type.PolyhedralSurface, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.PolyhedralSurfaceZM), + QgsWkbTypes.Type.PolyhedralSurface, + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.TIN), QgsWkbTypes.Type.TIN + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.TINZ), QgsWkbTypes.Type.TIN + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.TINM), QgsWkbTypes.Type.TIN + ) + self.assertEqual( + QgsWkbTypes.flatType(QgsWkbTypes.Type.TINZM), QgsWkbTypes.Type.TIN + ) + + # test geometryType method + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.Unknown), + QgsWkbTypes.GeometryType.UnknownGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.Point), + QgsWkbTypes.GeometryType.PointGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.PointZ), + QgsWkbTypes.GeometryType.PointGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.PointM), + QgsWkbTypes.GeometryType.PointGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.PointZM), + QgsWkbTypes.GeometryType.PointGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPoint), + QgsWkbTypes.GeometryType.PointGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPointZ), + QgsWkbTypes.GeometryType.PointGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPointM), + QgsWkbTypes.GeometryType.PointGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPointZM), + QgsWkbTypes.GeometryType.PointGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.LineString), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.LineStringZ), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.LineStringM), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.LineStringZM), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiLineString), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiLineStringZ), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiLineStringM), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiLineStringZM), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.Polygon), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.PolygonZ), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.PolygonM), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.PolygonZM), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPolygon), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPolygonZ), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPolygonM), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPolygonZM), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.GeometryCollection), + QgsWkbTypes.GeometryType.UnknownGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.GeometryCollectionZ), + QgsWkbTypes.GeometryType.UnknownGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.GeometryCollectionM), + QgsWkbTypes.GeometryType.UnknownGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.GeometryCollectionZM), + QgsWkbTypes.GeometryType.UnknownGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.CircularString), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.CircularStringZ), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.CircularStringM), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.CircularStringZM), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.CompoundCurve), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.CompoundCurveZ), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.CompoundCurveM), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.CompoundCurveZM), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.CurvePolygon), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.CurvePolygonZ), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.CurvePolygonM), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.CurvePolygonZM), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiCurve), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiCurveZ), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiCurveM), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiCurveZM), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiSurface), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiSurfaceZ), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiSurfaceM), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiSurfaceZM), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.NoGeometry), + QgsWkbTypes.GeometryType.NullGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.Point25D), + QgsWkbTypes.GeometryType.PointGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.LineString25D), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.Polygon25D), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPoint25D), + QgsWkbTypes.GeometryType.PointGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiLineString25D), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.MultiPolygon25D), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.PolyhedralSurface), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.PolyhedralSurfaceZ), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.PolyhedralSurfaceM), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.PolyhedralSurfaceZM), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.TIN), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.TINZ), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.TINM), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + self.assertEqual( + QgsWkbTypes.geometryType(QgsWkbTypes.Type.TINZM), + QgsWkbTypes.GeometryType.PolygonGeometry, + ) + + # test displayString method + self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.Unknown), "Unknown") + self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.Point), "Point") + self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.PointZ), "PointZ") + self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.PointM), "PointM") + self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.PointZM), "PointZM") + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPoint), "MultiPoint" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPointZ), "MultiPointZ" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPointM), "MultiPointM" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPointZM), "MultiPointZM" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.LineString), "LineString" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.LineStringZ), "LineStringZ" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.LineStringM), "LineStringM" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.LineStringZM), "LineStringZM" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiLineString), + "MultiLineString", + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiLineStringZ), + "MultiLineStringZ", + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiLineStringM), + "MultiLineStringM", + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiLineStringZM), + "MultiLineStringZM", + ) + self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.Polygon), "Polygon") + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.PolygonZ), "PolygonZ" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.PolygonM), "PolygonM" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.PolygonZM), "PolygonZM" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPolygon), "MultiPolygon" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPolygonZ), "MultiPolygonZ" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPolygonM), "MultiPolygonM" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPolygonZM), "MultiPolygonZM" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.GeometryCollection), + "GeometryCollection", + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.GeometryCollectionZ), + "GeometryCollectionZ", + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.GeometryCollectionM), + "GeometryCollectionM", + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.GeometryCollectionZM), + "GeometryCollectionZM", + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.CircularString), "CircularString" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.CircularStringZ), + "CircularStringZ", + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.CircularStringM), + "CircularStringM", + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.CircularStringZM), + "CircularStringZM", + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.CompoundCurve), "CompoundCurve" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.CompoundCurveZ), "CompoundCurveZ" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.CompoundCurveM), "CompoundCurveM" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.CompoundCurveZM), + "CompoundCurveZM", + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.CurvePolygon), "CurvePolygon" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.CurvePolygonZ), "CurvePolygonZ" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.CurvePolygonM), "CurvePolygonM" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.CurvePolygonZM), "CurvePolygonZM" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiCurve), "MultiCurve" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiCurveZ), "MultiCurveZ" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiCurveM), "MultiCurveM" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiCurveZM), "MultiCurveZM" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiSurface), "MultiSurface" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiSurfaceZ), "MultiSurfaceZ" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiSurfaceM), "MultiSurfaceM" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiSurfaceZM), "MultiSurfaceZM" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.NoGeometry), "NoGeometry" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.Point25D), "Point25D" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.LineString25D), "LineString25D" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.Polygon25D), "Polygon25D" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPoint25D), "MultiPoint25D" + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiLineString25D), + "MultiLineString25D", + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.MultiPolygon25D), + "MultiPolygon25D", + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.PolyhedralSurface), + "PolyhedralSurface", + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.PolyhedralSurfaceZ), + "PolyhedralSurfaceZ", + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.PolyhedralSurfaceM), + "PolyhedralSurfaceM", + ) + self.assertEqual( + QgsWkbTypes.displayString(QgsWkbTypes.Type.PolyhedralSurfaceZM), + "PolyhedralSurfaceZM", + ) + self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.TIN), "TIN") + self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.TINZ), "TINZ") + self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.TINM), "TINM") + self.assertEqual(QgsWkbTypes.displayString(QgsWkbTypes.Type.TINZM), "TINZM") + + # test parseType method + self.assertEqual(QgsWkbTypes.parseType("point( 1 2 )"), QgsWkbTypes.Type.Point) + self.assertEqual(QgsWkbTypes.parseType("POINT( 1 2 )"), QgsWkbTypes.Type.Point) + self.assertEqual( + QgsWkbTypes.parseType(" point ( 1 2 ) "), QgsWkbTypes.Type.Point + ) + self.assertEqual(QgsWkbTypes.parseType("point"), QgsWkbTypes.Type.Point) + self.assertEqual( + QgsWkbTypes.parseType("LINE STRING( 1 2, 3 4 )"), + QgsWkbTypes.Type.LineString, + ) + self.assertEqual( + QgsWkbTypes.parseType("POINTZ( 1 2 )"), QgsWkbTypes.Type.PointZ + ) + self.assertEqual(QgsWkbTypes.parseType("POINT z m"), QgsWkbTypes.Type.PointZM) + self.assertEqual(QgsWkbTypes.parseType("bad"), QgsWkbTypes.Type.Unknown) + self.assertEqual( + QgsWkbTypes.parseType("POLYHEDRALSURFACE (((0 0,0 1,1 1,0 0)))"), + QgsWkbTypes.Type.PolyhedralSurface, + ) + self.assertEqual( + QgsWkbTypes.parseType("POLYHEDRALSURFACE Z (((0 0 0,0 1 0,1 1 0,0 0 0)))"), + QgsWkbTypes.Type.PolyhedralSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.parseType("POLYHEDRALSURFACE M (((0 0 3,0 1 3,1 1 3,0 0 3)))"), + QgsWkbTypes.Type.PolyhedralSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.parseType( + "POLYHEDRALSURFACE ZM (((0 0 3 4,0 1 3 4,1 1 3 4,0 0 3 4)))" + ), + QgsWkbTypes.Type.PolyhedralSurfaceZM, + ) + self.assertEqual( + QgsWkbTypes.parseType("TIN (((0 0,0 1,1 1,0 0)))"), QgsWkbTypes.Type.TIN + ) + self.assertEqual( + QgsWkbTypes.parseType("TIN Z (((0 0 0,0 1 0,1 1 0,0 0 0)))"), + QgsWkbTypes.Type.TINZ, + ) + self.assertEqual( + QgsWkbTypes.parseType("TIN M (((0 0 3,0 1 3,1 1 3,0 0 3)))"), + QgsWkbTypes.Type.TINM, + ) + self.assertEqual( + QgsWkbTypes.parseType("TIN ZM (((0 0 3 4,0 1 3 4,1 1 3 4,0 0 3 4)))"), + QgsWkbTypes.Type.TINZM, + ) + + # test wkbDimensions method + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.Unknown), 0) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.Point), 0) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PointZ), 0) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PointM), 0) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PointZM), 0) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPoint), 0) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPointZ), 0) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPointM), 0) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPointZM), 0) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.LineString), 1) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.LineStringZ), 1) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.LineStringM), 1) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.LineStringZM), 1) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiLineString), 1) + self.assertEqual( + QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiLineStringZ), 1 + ) + self.assertEqual( + QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiLineStringM), 1 + ) + self.assertEqual( + QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiLineStringZM), 1 + ) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.Polygon), 2) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PolygonZ), 2) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PolygonM), 2) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PolygonZM), 2) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPolygon), 2) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPolygonZ), 2) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPolygonM), 2) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPolygonZM), 2) + self.assertEqual( + QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.GeometryCollection), 0 + ) + self.assertEqual( + QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.GeometryCollectionZ), 0 + ) + self.assertEqual( + QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.GeometryCollectionM), 0 + ) + self.assertEqual( + QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.GeometryCollectionZM), 0 + ) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CircularString), 1) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CircularStringZ), 1) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CircularStringM), 1) + self.assertEqual( + QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CircularStringZM), 1 + ) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CompoundCurve), 1) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CompoundCurveZ), 1) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CompoundCurveM), 1) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CompoundCurveZM), 1) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CurvePolygon), 2) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CurvePolygonZ), 2) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CurvePolygonM), 2) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.CurvePolygonZM), 2) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiCurve), 1) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiCurveZ), 1) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiCurveM), 1) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiCurveZM), 1) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiSurface), 2) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiSurfaceZ), 2) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiSurfaceM), 2) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiSurfaceZM), 2) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.NoGeometry), 0) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.Point25D), 0) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.LineString25D), 1) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.Polygon25D), 2) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPoint25D), 0) + self.assertEqual( + QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiLineString25D), 1 + ) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.MultiPolygon25D), 2) + self.assertEqual( + QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PolyhedralSurface), 2 + ) + self.assertEqual( + QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PolyhedralSurfaceZ), 2 + ) + self.assertEqual( + QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PolyhedralSurfaceM), 2 + ) + self.assertEqual( + QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.PolyhedralSurfaceZM), 2 + ) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.TIN), 2) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.TINZ), 2) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.TINM), 2) + self.assertEqual(QgsWkbTypes.wkbDimensions(QgsWkbTypes.Type.TINZM), 2) + + # test coordDimensions method + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.Unknown), 0) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.Point), 2) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PointZ), 3) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PointM), 3) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PointZM), 4) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiPoint), 2) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiPointZ), 3) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiPointM), 3) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiPointZM), 4) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.LineString), 2) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.LineStringZ), 3) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.LineStringM), 3) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.LineStringZM), 4) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiLineString), 2 + ) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiLineStringZ), 3 + ) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiLineStringM), 3 + ) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiLineStringZM), 4 + ) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.Polygon), 2) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PolygonZ), 3) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PolygonM), 3) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PolygonZM), 4) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiPolygon), 2) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiPolygonZ), 3) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiPolygonM), 3) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiPolygonZM), 4 + ) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.GeometryCollection), 2 + ) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.GeometryCollectionZ), 3 + ) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.GeometryCollectionM), 3 + ) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.GeometryCollectionZM), 4 + ) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CircularString), 2 + ) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CircularStringZ), 3 + ) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CircularStringM), 3 + ) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CircularStringZM), 4 + ) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CompoundCurve), 2) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CompoundCurveZ), 3 + ) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CompoundCurveM), 3 + ) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CompoundCurveZM), 4 + ) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CurvePolygon), 2) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CurvePolygonZ), 3) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CurvePolygonM), 3) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.CurvePolygonZM), 4 + ) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiCurve), 2) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiCurveZ), 3) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiCurveM), 3) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiCurveZM), 4) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiSurface), 2) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiSurfaceZ), 3) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiSurfaceM), 3) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiSurfaceZM), 4 + ) + self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.NoGeometry), 0) self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.Point25D), 3) self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.LineString25D), 3) self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.Polygon25D), 3) self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiPoint25D), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiLineString25D), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiPolygon25D), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PolyhedralSurface), 2) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PolyhedralSurfaceZ), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PolyhedralSurfaceM), 3) - self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PolyhedralSurfaceZM), 4) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiLineString25D), 3 + ) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.MultiPolygon25D), 3 + ) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PolyhedralSurface), 2 + ) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PolyhedralSurfaceZ), 3 + ) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PolyhedralSurfaceM), 3 + ) + self.assertEqual( + QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.PolyhedralSurfaceZM), 4 + ) self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.TIN), 2) self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.TINZ), 3) self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.TINM), 3) self.assertEqual(QgsWkbTypes.coordDimensions(QgsWkbTypes.Type.TINZM), 4) - # test isSingleType methods - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.Unknown) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.Point) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.LineString) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.Polygon) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PolyhedralSurface) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.TIN) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPoint) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiLineString) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPolygon) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.GeometryCollection) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CircularString) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CompoundCurve) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CurvePolygon) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiCurve) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiSurface) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.NoGeometry) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PointZ) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.LineStringZ) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PolygonZ) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PolyhedralSurfaceZ) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.TINZ) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPointZ) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiLineStringZ) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPolygonZ) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.GeometryCollectionZ) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CircularStringZ) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CompoundCurveZ) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CurvePolygonZ) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiCurveZ) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiSurfaceZ) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PointM) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.LineStringM) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PolygonM) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PolyhedralSurfaceM) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.TINM) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPointM) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiLineStringM) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPolygonM) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.GeometryCollectionM) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CircularStringM) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CompoundCurveM) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CurvePolygonM) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiCurveM) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiSurfaceM) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PointZM) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.LineStringZM) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PolygonZM) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PolyhedralSurfaceZM) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.TINZM) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPointZM) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiLineStringZM) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPolygonZM) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.GeometryCollectionZM) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CircularStringZM) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CompoundCurveZM) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CurvePolygonZM) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiCurveZM) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiSurfaceZM) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.Point25D) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.LineString25D) - assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.Polygon25D) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPoint25D) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiLineString25D) - assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPolygon25D) + # test isSingleType methods + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.Unknown) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.Point) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.LineString) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.Polygon) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PolyhedralSurface) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.TIN) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPoint) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiLineString) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPolygon) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.GeometryCollection) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CircularString) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CompoundCurve) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CurvePolygon) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiCurve) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiSurface) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.NoGeometry) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PointZ) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.LineStringZ) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PolygonZ) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PolyhedralSurfaceZ) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.TINZ) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPointZ) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiLineStringZ) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPolygonZ) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.GeometryCollectionZ) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CircularStringZ) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CompoundCurveZ) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CurvePolygonZ) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiCurveZ) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiSurfaceZ) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PointM) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.LineStringM) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PolygonM) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PolyhedralSurfaceM) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.TINM) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPointM) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiLineStringM) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPolygonM) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.GeometryCollectionM) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CircularStringM) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CompoundCurveM) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CurvePolygonM) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiCurveM) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiSurfaceM) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PointZM) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.LineStringZM) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PolygonZM) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.PolyhedralSurfaceZM) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.TINZM) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPointZM) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiLineStringZM) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPolygonZM) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.GeometryCollectionZM) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CircularStringZM) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CompoundCurveZM) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.CurvePolygonZM) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiCurveZM) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiSurfaceZM) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.Point25D) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.LineString25D) + assert QgsWkbTypes.isSingleType(QgsWkbTypes.Type.Polygon25D) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPoint25D) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiLineString25D) + assert not QgsWkbTypes.isSingleType(QgsWkbTypes.Type.MultiPolygon25D) + + # test isMultiType methods + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.Unknown) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.Point) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.LineString) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.Polygon) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PolyhedralSurface) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.TIN) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPoint) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiLineString) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPolygon) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.GeometryCollection) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CircularString) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CompoundCurve) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CurvePolygon) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiCurve) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiSurface) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.NoGeometry) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PointZ) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.LineStringZ) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PolygonZ) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PolyhedralSurfaceZ) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.TINZ) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPointZ) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiLineStringZ) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPolygonZ) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.GeometryCollectionZ) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CircularStringZ) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CompoundCurveZ) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CurvePolygonZ) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiCurveZ) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiSurfaceZ) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PointM) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.LineStringM) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PolygonM) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PolyhedralSurfaceM) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.TINM) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPointM) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiLineStringM) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPolygonM) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.GeometryCollectionM) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CircularStringM) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CompoundCurveM) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CurvePolygonM) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiCurveM) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiSurfaceM) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PointZM) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.LineStringZM) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PolygonZM) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PolyhedralSurfaceZM) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.TINZM) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPointZM) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiLineStringZM) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPolygonZM) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.GeometryCollectionZM) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CircularStringZM) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CompoundCurveZM) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CurvePolygonZM) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiCurveZM) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiSurfaceZM) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.Point25D) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.LineString25D) + assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.Polygon25D) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPoint25D) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiLineString25D) + assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPolygon25D) + + # test isCurvedType methods + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.Unknown) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.Point) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.LineString) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.Polygon) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PolyhedralSurface) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.TIN) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPoint) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiLineString) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPolygon) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.GeometryCollection) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CircularString) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CompoundCurve) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CurvePolygon) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiCurve) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiSurface) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.NoGeometry) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PointZ) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.LineStringZ) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PolygonZ) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PolyhedralSurfaceZ) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.TINZ) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPointZ) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiLineStringZ) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPolygonZ) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.GeometryCollectionZ) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CircularStringZ) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CompoundCurveZ) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CurvePolygonZ) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiCurveZ) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiSurfaceZ) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PointM) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.LineStringM) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PolygonM) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PolyhedralSurfaceM) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.TINM) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPointM) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiLineStringM) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPolygonM) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.GeometryCollectionM) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CircularStringM) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CompoundCurveM) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CurvePolygonM) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiCurveM) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiSurfaceM) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PointZM) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.LineStringZM) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PolygonZM) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPointZM) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiLineStringZM) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPolygonZM) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PolyhedralSurfaceZM) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.TINZM) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.GeometryCollectionZM) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CircularStringZM) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CompoundCurveZM) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CurvePolygonZM) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiCurveZM) + assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiSurfaceZM) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.Point25D) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.LineString25D) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.Polygon25D) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPoint25D) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiLineString25D) + assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPolygon25D) + + # test hasZ methods + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.Unknown) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.Point) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.LineString) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.Polygon) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.PolyhedralSurface) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.TIN) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPoint) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiLineString) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPolygon) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.GeometryCollection) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.CircularString) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.CompoundCurve) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.CurvePolygon) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiCurve) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiSurface) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.NoGeometry) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.PointZ) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.LineStringZ) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.PolygonZ) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.PolyhedralSurfaceZ) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.TINZ) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPointZ) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiLineStringZ) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPolygonZ) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.GeometryCollectionZ) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.CircularStringZ) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.CompoundCurveZ) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.CurvePolygonZ) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiCurveZ) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiSurfaceZ) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.PointM) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.LineStringM) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.PolygonM) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.PolyhedralSurfaceM) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.TINM) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPointM) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiLineStringM) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPolygonM) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.GeometryCollectionM) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.CircularStringM) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.CompoundCurveM) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.CurvePolygonM) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiCurveM) + assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiSurfaceM) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.PointZM) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.LineStringZM) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.PolygonZM) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.PolyhedralSurfaceZM) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.TINZM) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPointZM) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiLineStringZM) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPolygonZM) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.GeometryCollectionZM) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.CircularStringZM) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.CompoundCurveZM) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.CurvePolygonZM) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiCurveZM) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiSurfaceZM) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.Point25D) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.LineString25D) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.Polygon25D) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPoint25D) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiLineString25D) + assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPolygon25D) + + # test hasM methods + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.Unknown) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.Point) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.LineString) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.Polygon) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.PolyhedralSurface) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.TIN) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPoint) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiLineString) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPolygon) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.GeometryCollection) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.CircularString) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.CompoundCurve) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.CurvePolygon) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiCurve) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiSurface) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.NoGeometry) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.PointZ) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.LineStringZ) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.PolygonZ) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.PolyhedralSurfaceZ) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.TINZ) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPointZ) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiLineStringZ) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPolygonZ) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.GeometryCollectionZ) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.CircularStringZ) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.CompoundCurveZ) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.CurvePolygonZ) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiCurveZ) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiSurfaceZ) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.PointM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.LineStringM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.PolygonM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.PolyhedralSurfaceM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.TINM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPointM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiLineStringM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPolygonM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.GeometryCollectionM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.CircularStringM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.CompoundCurveM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.CurvePolygonM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiCurveM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiSurfaceM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.PointZM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.LineStringZM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.PolygonZM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.PolyhedralSurfaceZM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.TINZM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPointZM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiLineStringZM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPolygonZM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.GeometryCollectionZM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.CircularStringZM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.CompoundCurveZM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.CurvePolygonZM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiCurveZM) + assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiSurfaceZM) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.Point25D) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.LineString25D) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.Polygon25D) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPoint25D) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiLineString25D) + assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPolygon25D) + + # test adding z dimension to types + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.PointZ + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.PointZ + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.PointZM + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.PointZM + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPoint), QgsWkbTypes.Type.MultiPointZ + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPointZ), QgsWkbTypes.Type.MultiPointZ + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPointM), + QgsWkbTypes.Type.MultiPointZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPointZM), + QgsWkbTypes.Type.MultiPointZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.LineString), QgsWkbTypes.Type.LineStringZ + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.LineStringZ), QgsWkbTypes.Type.LineStringZ + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.LineStringM), + QgsWkbTypes.Type.LineStringZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.LineStringZM), + QgsWkbTypes.Type.LineStringZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiLineString), + QgsWkbTypes.Type.MultiLineStringZ, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiLineStringZ), + QgsWkbTypes.Type.MultiLineStringZ, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiLineStringM), + QgsWkbTypes.Type.MultiLineStringZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiLineStringZM), + QgsWkbTypes.Type.MultiLineStringZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.Polygon), QgsWkbTypes.Type.PolygonZ + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.Type.PolygonZ + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.Type.PolygonZM + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.PolygonZM), QgsWkbTypes.Type.PolygonZM + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPolygon), + QgsWkbTypes.Type.MultiPolygonZ, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPolygonZ), + QgsWkbTypes.Type.MultiPolygonZ, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPolygonM), + QgsWkbTypes.Type.MultiPolygonZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPolygonZM), + QgsWkbTypes.Type.MultiPolygonZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.GeometryCollection), + QgsWkbTypes.Type.GeometryCollectionZ, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.GeometryCollectionZ), + QgsWkbTypes.Type.GeometryCollectionZ, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.GeometryCollectionM), + QgsWkbTypes.Type.GeometryCollectionZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.GeometryCollectionZM), + QgsWkbTypes.Type.GeometryCollectionZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.CircularString), + QgsWkbTypes.Type.CircularStringZ, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.CircularStringZ), + QgsWkbTypes.Type.CircularStringZ, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.CircularStringM), + QgsWkbTypes.Type.CircularStringZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.CircularStringZM), + QgsWkbTypes.Type.CircularStringZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.CompoundCurve), + QgsWkbTypes.Type.CompoundCurveZ, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.CompoundCurveZ), + QgsWkbTypes.Type.CompoundCurveZ, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.CompoundCurveM), + QgsWkbTypes.Type.CompoundCurveZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.CompoundCurveZM), + QgsWkbTypes.Type.CompoundCurveZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.CurvePolygon), + QgsWkbTypes.Type.CurvePolygonZ, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.CurvePolygonZ), + QgsWkbTypes.Type.CurvePolygonZ, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.CurvePolygonM), + QgsWkbTypes.Type.CurvePolygonZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.CurvePolygonZM), + QgsWkbTypes.Type.CurvePolygonZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiCurve), QgsWkbTypes.Type.MultiCurveZ + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiCurveZ), QgsWkbTypes.Type.MultiCurveZ + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiCurveM), + QgsWkbTypes.Type.MultiCurveZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiCurveZM), + QgsWkbTypes.Type.MultiCurveZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiSurface), + QgsWkbTypes.Type.MultiSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiSurfaceZ), + QgsWkbTypes.Type.MultiSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiSurfaceM), + QgsWkbTypes.Type.MultiSurfaceZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiSurfaceZM), + QgsWkbTypes.Type.MultiSurfaceZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.NoGeometry), QgsWkbTypes.Type.NoGeometry + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.Point25D), QgsWkbTypes.Type.Point25D + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.LineString25D), + QgsWkbTypes.Type.LineString25D, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.Polygon25D), QgsWkbTypes.Type.Polygon25D + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPoint25D), + QgsWkbTypes.Type.MultiPoint25D, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiLineString25D), + QgsWkbTypes.Type.MultiLineString25D, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPolygon25D), + QgsWkbTypes.Type.MultiPolygon25D, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.PolyhedralSurface), + QgsWkbTypes.Type.PolyhedralSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.PolyhedralSurfaceZ), + QgsWkbTypes.Type.PolyhedralSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.PolyhedralSurfaceM), + QgsWkbTypes.Type.PolyhedralSurfaceZM, + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.PolyhedralSurfaceZM), + QgsWkbTypes.Type.PolyhedralSurfaceZM, + ) + self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.TIN), QgsWkbTypes.Type.TINZ) + self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.TINZ), QgsWkbTypes.Type.TINZ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.TINM), QgsWkbTypes.Type.TINZM + ) + self.assertEqual( + QgsWkbTypes.addZ(QgsWkbTypes.Type.TINZM), QgsWkbTypes.Type.TINZM + ) + + # test to25D + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.Point25D + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.Point25D + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.Point25D + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.Point25D + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPoint), + QgsWkbTypes.Type.MultiPoint25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPointZ), + QgsWkbTypes.Type.MultiPoint25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPointM), + QgsWkbTypes.Type.MultiPoint25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPointZM), + QgsWkbTypes.Type.MultiPoint25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.LineString), + QgsWkbTypes.Type.LineString25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.LineStringZ), + QgsWkbTypes.Type.LineString25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.LineStringM), + QgsWkbTypes.Type.LineString25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.LineStringZM), + QgsWkbTypes.Type.LineString25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiLineString), + QgsWkbTypes.Type.MultiLineString25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiLineStringZ), + QgsWkbTypes.Type.MultiLineString25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiLineStringM), + QgsWkbTypes.Type.MultiLineString25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiLineStringZM), + QgsWkbTypes.Type.MultiLineString25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.Polygon), QgsWkbTypes.Type.Polygon25D + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.Type.Polygon25D + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.Type.Polygon25D + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.PolygonZM), QgsWkbTypes.Type.Polygon25D + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPolygon), + QgsWkbTypes.Type.MultiPolygon25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPolygonZ), + QgsWkbTypes.Type.MultiPolygon25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPolygonM), + QgsWkbTypes.Type.MultiPolygon25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPolygonZM), + QgsWkbTypes.Type.MultiPolygon25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.GeometryCollection), + QgsWkbTypes.Type.Unknown, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.GeometryCollectionZ), + QgsWkbTypes.Type.Unknown, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.GeometryCollectionM), + QgsWkbTypes.Type.Unknown, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.GeometryCollectionZM), + QgsWkbTypes.Type.Unknown, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.CircularString), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.CircularStringZ), + QgsWkbTypes.Type.Unknown, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.CircularStringM), + QgsWkbTypes.Type.Unknown, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.CircularStringZM), + QgsWkbTypes.Type.Unknown, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.CompoundCurve), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.CompoundCurveZ), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.CompoundCurveM), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.CompoundCurveZM), + QgsWkbTypes.Type.Unknown, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.CurvePolygon), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.CurvePolygonZ), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.CurvePolygonM), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.CurvePolygonZM), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiCurve), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiCurveZ), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiCurveM), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiCurveZM), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiSurface), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiSurfaceZ), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiSurfaceM), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiSurfaceZM), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.NoGeometry), QgsWkbTypes.Type.NoGeometry + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.Point25D), QgsWkbTypes.Type.Point25D + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.LineString25D), + QgsWkbTypes.Type.LineString25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.Polygon25D), QgsWkbTypes.Type.Polygon25D + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPoint25D), + QgsWkbTypes.Type.MultiPoint25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiLineString25D), + QgsWkbTypes.Type.MultiLineString25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPolygon25D), + QgsWkbTypes.Type.MultiPolygon25D, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.PolyhedralSurface), + QgsWkbTypes.Type.Unknown, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.PolyhedralSurfaceZ), + QgsWkbTypes.Type.Unknown, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.PolyhedralSurfaceM), + QgsWkbTypes.Type.Unknown, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.PolyhedralSurfaceZM), + QgsWkbTypes.Type.Unknown, + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.TIN), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.TINZ), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.TINM), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.to25D(QgsWkbTypes.Type.TINZM), QgsWkbTypes.Type.Unknown + ) + + # test adding m dimension to types + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.PointM + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.PointZM + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.PointM + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.PointZM + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPoint), QgsWkbTypes.Type.MultiPointM + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPointZ), + QgsWkbTypes.Type.MultiPointZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPointM), QgsWkbTypes.Type.MultiPointM + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPointZM), + QgsWkbTypes.Type.MultiPointZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.LineString), QgsWkbTypes.Type.LineStringM + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.LineStringZ), + QgsWkbTypes.Type.LineStringZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.LineStringM), QgsWkbTypes.Type.LineStringM + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.LineStringZM), + QgsWkbTypes.Type.LineStringZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiLineString), + QgsWkbTypes.Type.MultiLineStringM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiLineStringZ), + QgsWkbTypes.Type.MultiLineStringZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiLineStringM), + QgsWkbTypes.Type.MultiLineStringM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiLineStringZM), + QgsWkbTypes.Type.MultiLineStringZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.Polygon), QgsWkbTypes.Type.PolygonM + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.Type.PolygonZM + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.Type.PolygonM + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.PolygonZM), QgsWkbTypes.Type.PolygonZM + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPolygon), + QgsWkbTypes.Type.MultiPolygonM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPolygonZ), + QgsWkbTypes.Type.MultiPolygonZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPolygonM), + QgsWkbTypes.Type.MultiPolygonM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPolygonZM), + QgsWkbTypes.Type.MultiPolygonZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.GeometryCollection), + QgsWkbTypes.Type.GeometryCollectionM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.GeometryCollectionZ), + QgsWkbTypes.Type.GeometryCollectionZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.GeometryCollectionM), + QgsWkbTypes.Type.GeometryCollectionM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.GeometryCollectionZM), + QgsWkbTypes.Type.GeometryCollectionZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.CircularString), + QgsWkbTypes.Type.CircularStringM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.CircularStringZ), + QgsWkbTypes.Type.CircularStringZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.CircularStringM), + QgsWkbTypes.Type.CircularStringM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.CircularStringZM), + QgsWkbTypes.Type.CircularStringZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.CompoundCurve), + QgsWkbTypes.Type.CompoundCurveM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.CompoundCurveZ), + QgsWkbTypes.Type.CompoundCurveZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.CompoundCurveM), + QgsWkbTypes.Type.CompoundCurveM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.CompoundCurveZM), + QgsWkbTypes.Type.CompoundCurveZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.CurvePolygon), + QgsWkbTypes.Type.CurvePolygonM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.CurvePolygonZ), + QgsWkbTypes.Type.CurvePolygonZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.CurvePolygonM), + QgsWkbTypes.Type.CurvePolygonM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.CurvePolygonZM), + QgsWkbTypes.Type.CurvePolygonZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiCurve), QgsWkbTypes.Type.MultiCurveM + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiCurveZ), + QgsWkbTypes.Type.MultiCurveZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiCurveM), QgsWkbTypes.Type.MultiCurveM + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiCurveZM), + QgsWkbTypes.Type.MultiCurveZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiSurface), + QgsWkbTypes.Type.MultiSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiSurfaceZ), + QgsWkbTypes.Type.MultiSurfaceZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiSurfaceM), + QgsWkbTypes.Type.MultiSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiSurfaceZM), + QgsWkbTypes.Type.MultiSurfaceZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.NoGeometry), QgsWkbTypes.Type.NoGeometry + ) + # we force upgrade 25D types to "Z" before adding the M value + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.Point25D), QgsWkbTypes.Type.PointZM + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.LineString25D), + QgsWkbTypes.Type.LineStringZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.Polygon25D), QgsWkbTypes.Type.PolygonZM + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPoint25D), + QgsWkbTypes.Type.MultiPointZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiLineString25D), + QgsWkbTypes.Type.MultiLineStringZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPolygon25D), + QgsWkbTypes.Type.MultiPolygonZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.PolyhedralSurface), + QgsWkbTypes.Type.PolyhedralSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.PolyhedralSurfaceZ), + QgsWkbTypes.Type.PolyhedralSurfaceZM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.PolyhedralSurfaceM), + QgsWkbTypes.Type.PolyhedralSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.PolyhedralSurfaceZM), + QgsWkbTypes.Type.PolyhedralSurfaceZM, + ) + self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.TIN), QgsWkbTypes.Type.TINM) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.TINZ), QgsWkbTypes.Type.TINZM + ) + self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.TINM), QgsWkbTypes.Type.TINM) + self.assertEqual( + QgsWkbTypes.addM(QgsWkbTypes.Type.TINZM), QgsWkbTypes.Type.TINZM + ) + + # test dropping z dimension from types + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.Point + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.Point + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.PointM + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.PointM + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPoint), QgsWkbTypes.Type.MultiPoint + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPointZ), QgsWkbTypes.Type.MultiPoint + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPointM), + QgsWkbTypes.Type.MultiPointM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPointZM), + QgsWkbTypes.Type.MultiPointM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.LineString), QgsWkbTypes.Type.LineString + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.LineStringZ), QgsWkbTypes.Type.LineString + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.LineStringM), + QgsWkbTypes.Type.LineStringM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.LineStringZM), + QgsWkbTypes.Type.LineStringM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiLineString), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiLineStringZ), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiLineStringM), + QgsWkbTypes.Type.MultiLineStringM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiLineStringZM), + QgsWkbTypes.Type.MultiLineStringM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.Polygon), QgsWkbTypes.Type.Polygon + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.Type.Polygon + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.Type.PolygonM + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.PolygonZM), QgsWkbTypes.Type.PolygonM + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPolygon), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPolygonZ), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPolygonM), + QgsWkbTypes.Type.MultiPolygonM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPolygonZM), + QgsWkbTypes.Type.MultiPolygonM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.GeometryCollection), + QgsWkbTypes.Type.GeometryCollection, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.GeometryCollectionZ), + QgsWkbTypes.Type.GeometryCollection, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.GeometryCollectionM), + QgsWkbTypes.Type.GeometryCollectionM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.GeometryCollectionZM), + QgsWkbTypes.Type.GeometryCollectionM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.CircularString), + QgsWkbTypes.Type.CircularString, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.CircularStringZ), + QgsWkbTypes.Type.CircularString, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.CircularStringM), + QgsWkbTypes.Type.CircularStringM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.CircularStringZM), + QgsWkbTypes.Type.CircularStringM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.CompoundCurve), + QgsWkbTypes.Type.CompoundCurve, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.CompoundCurveZ), + QgsWkbTypes.Type.CompoundCurve, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.CompoundCurveM), + QgsWkbTypes.Type.CompoundCurveM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.CompoundCurveZM), + QgsWkbTypes.Type.CompoundCurveM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.CurvePolygon), + QgsWkbTypes.Type.CurvePolygon, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.CurvePolygonZ), + QgsWkbTypes.Type.CurvePolygon, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.CurvePolygonM), + QgsWkbTypes.Type.CurvePolygonM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.CurvePolygonZM), + QgsWkbTypes.Type.CurvePolygonM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiCurve), QgsWkbTypes.Type.MultiCurve + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiCurveZ), QgsWkbTypes.Type.MultiCurve + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiCurveM), + QgsWkbTypes.Type.MultiCurveM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiCurveZM), + QgsWkbTypes.Type.MultiCurveM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiSurface), + QgsWkbTypes.Type.MultiSurface, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiSurfaceZ), + QgsWkbTypes.Type.MultiSurface, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiSurfaceM), + QgsWkbTypes.Type.MultiSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiSurfaceZM), + QgsWkbTypes.Type.MultiSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.NoGeometry), QgsWkbTypes.Type.NoGeometry + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.Point25D), QgsWkbTypes.Type.Point + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.LineString25D), + QgsWkbTypes.Type.LineString, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.Polygon25D), QgsWkbTypes.Type.Polygon + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPoint25D), + QgsWkbTypes.Type.MultiPoint, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiLineString25D), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPolygon25D), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.PolyhedralSurface), + QgsWkbTypes.Type.PolyhedralSurface, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.PolyhedralSurfaceZ), + QgsWkbTypes.Type.PolyhedralSurface, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.PolyhedralSurfaceM), + QgsWkbTypes.Type.PolyhedralSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.PolyhedralSurfaceZM), + QgsWkbTypes.Type.PolyhedralSurfaceM, + ) + self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.TIN), QgsWkbTypes.Type.TIN) + self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.TINZ), QgsWkbTypes.Type.TIN) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.TINM), QgsWkbTypes.Type.TINM + ) + self.assertEqual( + QgsWkbTypes.dropZ(QgsWkbTypes.Type.TINZM), QgsWkbTypes.Type.TINM + ) + + # test dropping m dimension from types + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.Point + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.PointZ + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.Point + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.PointZ + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPoint), QgsWkbTypes.Type.MultiPoint + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPointZ), + QgsWkbTypes.Type.MultiPointZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPointM), QgsWkbTypes.Type.MultiPoint + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPointZM), + QgsWkbTypes.Type.MultiPointZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.LineString), QgsWkbTypes.Type.LineString + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.LineStringZ), + QgsWkbTypes.Type.LineStringZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.LineStringM), QgsWkbTypes.Type.LineString + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.LineStringZM), + QgsWkbTypes.Type.LineStringZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiLineString), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiLineStringZ), + QgsWkbTypes.Type.MultiLineStringZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiLineStringM), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiLineStringZM), + QgsWkbTypes.Type.MultiLineStringZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.Polygon), QgsWkbTypes.Type.Polygon + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.Type.PolygonZ + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.Type.Polygon + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.PolygonZM), QgsWkbTypes.Type.PolygonZ + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPolygon), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPolygonZ), + QgsWkbTypes.Type.MultiPolygonZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPolygonM), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPolygonZM), + QgsWkbTypes.Type.MultiPolygonZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.GeometryCollection), + QgsWkbTypes.Type.GeometryCollection, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.GeometryCollectionZ), + QgsWkbTypes.Type.GeometryCollectionZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.GeometryCollectionM), + QgsWkbTypes.Type.GeometryCollection, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.GeometryCollectionZM), + QgsWkbTypes.Type.GeometryCollectionZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.CircularString), + QgsWkbTypes.Type.CircularString, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.CircularStringZ), + QgsWkbTypes.Type.CircularStringZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.CircularStringM), + QgsWkbTypes.Type.CircularString, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.CircularStringZM), + QgsWkbTypes.Type.CircularStringZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.CompoundCurve), + QgsWkbTypes.Type.CompoundCurve, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.CompoundCurveZ), + QgsWkbTypes.Type.CompoundCurveZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.CompoundCurveM), + QgsWkbTypes.Type.CompoundCurve, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.CompoundCurveZM), + QgsWkbTypes.Type.CompoundCurveZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.CurvePolygon), + QgsWkbTypes.Type.CurvePolygon, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.CurvePolygonZ), + QgsWkbTypes.Type.CurvePolygonZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.CurvePolygonM), + QgsWkbTypes.Type.CurvePolygon, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.CurvePolygonZM), + QgsWkbTypes.Type.CurvePolygonZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiCurve), QgsWkbTypes.Type.MultiCurve + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiCurveZ), + QgsWkbTypes.Type.MultiCurveZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiCurveM), QgsWkbTypes.Type.MultiCurve + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiCurveZM), + QgsWkbTypes.Type.MultiCurveZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiSurface), + QgsWkbTypes.Type.MultiSurface, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiSurfaceZ), + QgsWkbTypes.Type.MultiSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiSurfaceM), + QgsWkbTypes.Type.MultiSurface, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiSurfaceZM), + QgsWkbTypes.Type.MultiSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.NoGeometry), QgsWkbTypes.Type.NoGeometry + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.Point25D), QgsWkbTypes.Type.Point25D + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.LineString25D), + QgsWkbTypes.Type.LineString25D, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.Polygon25D), QgsWkbTypes.Type.Polygon25D + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPoint25D), + QgsWkbTypes.Type.MultiPoint25D, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiLineString25D), + QgsWkbTypes.Type.MultiLineString25D, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPolygon25D), + QgsWkbTypes.Type.MultiPolygon25D, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.PolyhedralSurface), + QgsWkbTypes.Type.PolyhedralSurface, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.PolyhedralSurfaceZ), + QgsWkbTypes.Type.PolyhedralSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.PolyhedralSurfaceM), + QgsWkbTypes.Type.PolyhedralSurface, + ) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.PolyhedralSurfaceZM), + QgsWkbTypes.Type.PolyhedralSurfaceZ, + ) + self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.TIN), QgsWkbTypes.Type.TIN) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.TINZ), QgsWkbTypes.Type.TINZ + ) + self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.TINM), QgsWkbTypes.Type.TIN) + self.assertEqual( + QgsWkbTypes.dropM(QgsWkbTypes.Type.TINZM), QgsWkbTypes.Type.TINZ + ) + + # Test QgsWkbTypes.zmType + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.Point, False, False), + QgsWkbTypes.Type.Point, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.Point, True, False), + QgsWkbTypes.Type.PointZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.Point, False, True), + QgsWkbTypes.Type.PointM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.Point, True, True), + QgsWkbTypes.Type.PointZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PointZ, False, False), + QgsWkbTypes.Type.Point, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PointZ, True, False), + QgsWkbTypes.Type.PointZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PointZ, False, True), + QgsWkbTypes.Type.PointM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PointZ, True, True), + QgsWkbTypes.Type.PointZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PointM, False, False), + QgsWkbTypes.Type.Point, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PointM, True, False), + QgsWkbTypes.Type.PointZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PointM, False, True), + QgsWkbTypes.Type.PointM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PointM, True, True), + QgsWkbTypes.Type.PointZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PointZM, False, False), + QgsWkbTypes.Type.Point, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PointZM, True, False), + QgsWkbTypes.Type.PointZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PointZM, False, True), + QgsWkbTypes.Type.PointM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PointZM, True, True), + QgsWkbTypes.Type.PointZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.LineString, False, False), + QgsWkbTypes.Type.LineString, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.LineString, True, False), + QgsWkbTypes.Type.LineStringZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.LineString, False, True), + QgsWkbTypes.Type.LineStringM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.LineString, True, True), + QgsWkbTypes.Type.LineStringZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringZ, False, False), + QgsWkbTypes.Type.LineString, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringZ, True, False), + QgsWkbTypes.Type.LineStringZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringZ, False, True), + QgsWkbTypes.Type.LineStringM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringZ, True, True), + QgsWkbTypes.Type.LineStringZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringM, False, False), + QgsWkbTypes.Type.LineString, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringM, True, False), + QgsWkbTypes.Type.LineStringZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringM, False, True), + QgsWkbTypes.Type.LineStringM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringM, True, True), + QgsWkbTypes.Type.LineStringZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringZM, False, False), + QgsWkbTypes.Type.LineString, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringZM, True, False), + QgsWkbTypes.Type.LineStringZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringZM, False, True), + QgsWkbTypes.Type.LineStringM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringZM, True, True), + QgsWkbTypes.Type.LineStringZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.Polygon, False, False), + QgsWkbTypes.Type.Polygon, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.Polygon, True, False), + QgsWkbTypes.Type.PolygonZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.Polygon, False, True), + QgsWkbTypes.Type.PolygonM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.Polygon, True, True), + QgsWkbTypes.Type.PolygonZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonZ, False, False), + QgsWkbTypes.Type.Polygon, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonZ, True, False), + QgsWkbTypes.Type.PolygonZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonZ, False, True), + QgsWkbTypes.Type.PolygonM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonZ, True, True), + QgsWkbTypes.Type.PolygonZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonM, False, False), + QgsWkbTypes.Type.Polygon, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonM, True, False), + QgsWkbTypes.Type.PolygonZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonM, False, True), + QgsWkbTypes.Type.PolygonM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonM, True, True), + QgsWkbTypes.Type.PolygonZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonZM, False, False), + QgsWkbTypes.Type.Polygon, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonZM, True, False), + QgsWkbTypes.Type.PolygonZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonZM, False, True), + QgsWkbTypes.Type.PolygonM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonZM, True, True), + QgsWkbTypes.Type.PolygonZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPoint, False, False), + QgsWkbTypes.Type.MultiPoint, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPoint, True, False), + QgsWkbTypes.Type.MultiPointZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPoint, False, True), + QgsWkbTypes.Type.MultiPointM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPoint, True, True), + QgsWkbTypes.Type.MultiPointZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointZ, False, False), + QgsWkbTypes.Type.MultiPoint, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointZ, True, False), + QgsWkbTypes.Type.MultiPointZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointZ, False, True), + QgsWkbTypes.Type.MultiPointM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointZ, True, True), + QgsWkbTypes.Type.MultiPointZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointM, False, False), + QgsWkbTypes.Type.MultiPoint, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointM, True, False), + QgsWkbTypes.Type.MultiPointZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointM, False, True), + QgsWkbTypes.Type.MultiPointM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointM, True, True), + QgsWkbTypes.Type.MultiPointZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointZM, False, False), + QgsWkbTypes.Type.MultiPoint, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointZM, True, False), + QgsWkbTypes.Type.MultiPointZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointZM, False, True), + QgsWkbTypes.Type.MultiPointM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointZM, True, True), + QgsWkbTypes.Type.MultiPointZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineString, False, False), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineString, True, False), + QgsWkbTypes.Type.MultiLineStringZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineString, False, True), + QgsWkbTypes.Type.MultiLineStringM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineString, True, True), + QgsWkbTypes.Type.MultiLineStringZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringZ, False, False), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringZ, True, False), + QgsWkbTypes.Type.MultiLineStringZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringZ, False, True), + QgsWkbTypes.Type.MultiLineStringM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringZ, True, True), + QgsWkbTypes.Type.MultiLineStringZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringM, False, False), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringM, True, False), + QgsWkbTypes.Type.MultiLineStringZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringM, False, True), + QgsWkbTypes.Type.MultiLineStringM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringM, True, True), + QgsWkbTypes.Type.MultiLineStringZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringZM, False, False), + QgsWkbTypes.Type.MultiLineString, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringZM, True, False), + QgsWkbTypes.Type.MultiLineStringZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringZM, False, True), + QgsWkbTypes.Type.MultiLineStringM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringZM, True, True), + QgsWkbTypes.Type.MultiLineStringZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygon, False, False), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygon, True, False), + QgsWkbTypes.Type.MultiPolygonZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygon, False, True), + QgsWkbTypes.Type.MultiPolygonM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygon, True, True), + QgsWkbTypes.Type.MultiPolygonZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonZ, False, False), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonZ, True, False), + QgsWkbTypes.Type.MultiPolygonZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonZ, False, True), + QgsWkbTypes.Type.MultiPolygonM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonZ, True, True), + QgsWkbTypes.Type.MultiPolygonZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonM, False, False), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonM, True, False), + QgsWkbTypes.Type.MultiPolygonZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonM, False, True), + QgsWkbTypes.Type.MultiPolygonM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonM, True, True), + QgsWkbTypes.Type.MultiPolygonZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonZM, False, False), + QgsWkbTypes.Type.MultiPolygon, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonZM, True, False), + QgsWkbTypes.Type.MultiPolygonZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonZM, False, True), + QgsWkbTypes.Type.MultiPolygonM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonZM, True, True), + QgsWkbTypes.Type.MultiPolygonZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollection, False, False), + QgsWkbTypes.Type.GeometryCollection, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollection, True, False), + QgsWkbTypes.Type.GeometryCollectionZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollection, False, True), + QgsWkbTypes.Type.GeometryCollectionM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollection, True, True), + QgsWkbTypes.Type.GeometryCollectionZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionZ, False, False), + QgsWkbTypes.Type.GeometryCollection, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionZ, True, False), + QgsWkbTypes.Type.GeometryCollectionZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionZ, False, True), + QgsWkbTypes.Type.GeometryCollectionM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionZ, True, True), + QgsWkbTypes.Type.GeometryCollectionZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionM, False, False), + QgsWkbTypes.Type.GeometryCollection, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionM, True, False), + QgsWkbTypes.Type.GeometryCollectionZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionM, False, True), + QgsWkbTypes.Type.GeometryCollectionM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionM, True, True), + QgsWkbTypes.Type.GeometryCollectionZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionZM, False, False), + QgsWkbTypes.Type.GeometryCollection, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionZM, True, False), + QgsWkbTypes.Type.GeometryCollectionZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionZM, False, True), + QgsWkbTypes.Type.GeometryCollectionM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionZM, True, True), + QgsWkbTypes.Type.GeometryCollectionZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularString, False, False), + QgsWkbTypes.Type.CircularString, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularString, True, False), + QgsWkbTypes.Type.CircularStringZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularString, False, True), + QgsWkbTypes.Type.CircularStringM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularString, True, True), + QgsWkbTypes.Type.CircularStringZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringZ, False, False), + QgsWkbTypes.Type.CircularString, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringZ, True, False), + QgsWkbTypes.Type.CircularStringZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringZ, False, True), + QgsWkbTypes.Type.CircularStringM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringZ, True, True), + QgsWkbTypes.Type.CircularStringZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringM, False, False), + QgsWkbTypes.Type.CircularString, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringM, True, False), + QgsWkbTypes.Type.CircularStringZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringM, False, True), + QgsWkbTypes.Type.CircularStringM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringM, True, True), + QgsWkbTypes.Type.CircularStringZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringZM, False, False), + QgsWkbTypes.Type.CircularString, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringZM, True, False), + QgsWkbTypes.Type.CircularStringZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringZM, False, True), + QgsWkbTypes.Type.CircularStringM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringZM, True, True), + QgsWkbTypes.Type.CircularStringZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurve, False, False), + QgsWkbTypes.Type.CompoundCurve, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurve, True, False), + QgsWkbTypes.Type.CompoundCurveZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurve, False, True), + QgsWkbTypes.Type.CompoundCurveM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurve, True, True), + QgsWkbTypes.Type.CompoundCurveZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveZ, False, False), + QgsWkbTypes.Type.CompoundCurve, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveZ, True, False), + QgsWkbTypes.Type.CompoundCurveZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveZ, False, True), + QgsWkbTypes.Type.CompoundCurveM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveZ, True, True), + QgsWkbTypes.Type.CompoundCurveZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveM, False, False), + QgsWkbTypes.Type.CompoundCurve, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveM, True, False), + QgsWkbTypes.Type.CompoundCurveZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveM, False, True), + QgsWkbTypes.Type.CompoundCurveM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveM, True, True), + QgsWkbTypes.Type.CompoundCurveZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveZM, False, False), + QgsWkbTypes.Type.CompoundCurve, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveZM, True, False), + QgsWkbTypes.Type.CompoundCurveZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveZM, False, True), + QgsWkbTypes.Type.CompoundCurveM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveZM, True, True), + QgsWkbTypes.Type.CompoundCurveZM, + ) - # test isMultiType methods - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.Unknown) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.Point) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.LineString) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.Polygon) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PolyhedralSurface) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.TIN) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPoint) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiLineString) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPolygon) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.GeometryCollection) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CircularString) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CompoundCurve) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CurvePolygon) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiCurve) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiSurface) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.NoGeometry) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PointZ) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.LineStringZ) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PolygonZ) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PolyhedralSurfaceZ) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.TINZ) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPointZ) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiLineStringZ) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPolygonZ) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.GeometryCollectionZ) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CircularStringZ) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CompoundCurveZ) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CurvePolygonZ) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiCurveZ) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiSurfaceZ) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PointM) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.LineStringM) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PolygonM) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PolyhedralSurfaceM) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.TINM) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPointM) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiLineStringM) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPolygonM) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.GeometryCollectionM) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CircularStringM) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CompoundCurveM) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CurvePolygonM) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiCurveM) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiSurfaceM) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PointZM) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.LineStringZM) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PolygonZM) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.PolyhedralSurfaceZM) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.TINZM) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPointZM) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiLineStringZM) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPolygonZM) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.GeometryCollectionZM) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CircularStringZM) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CompoundCurveZM) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.CurvePolygonZM) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiCurveZM) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiSurfaceZM) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.Point25D) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.LineString25D) - assert not QgsWkbTypes.isMultiType(QgsWkbTypes.Type.Polygon25D) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPoint25D) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiLineString25D) - assert QgsWkbTypes.isMultiType(QgsWkbTypes.Type.MultiPolygon25D) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurve, False, False), + QgsWkbTypes.Type.MultiCurve, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurve, True, False), + QgsWkbTypes.Type.MultiCurveZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurve, False, True), + QgsWkbTypes.Type.MultiCurveM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurve, True, True), + QgsWkbTypes.Type.MultiCurveZM, + ) - # test isCurvedType methods - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.Unknown) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.Point) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.LineString) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.Polygon) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PolyhedralSurface) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.TIN) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPoint) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiLineString) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPolygon) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.GeometryCollection) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CircularString) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CompoundCurve) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CurvePolygon) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiCurve) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiSurface) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.NoGeometry) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PointZ) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.LineStringZ) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PolygonZ) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PolyhedralSurfaceZ) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.TINZ) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPointZ) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiLineStringZ) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPolygonZ) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.GeometryCollectionZ) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CircularStringZ) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CompoundCurveZ) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CurvePolygonZ) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiCurveZ) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiSurfaceZ) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PointM) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.LineStringM) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PolygonM) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PolyhedralSurfaceM) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.TINM) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPointM) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiLineStringM) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPolygonM) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.GeometryCollectionM) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CircularStringM) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CompoundCurveM) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CurvePolygonM) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiCurveM) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiSurfaceM) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PointZM) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.LineStringZM) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PolygonZM) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPointZM) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiLineStringZM) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPolygonZM) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.PolyhedralSurfaceZM) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.TINZM) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.GeometryCollectionZM) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CircularStringZM) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CompoundCurveZM) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.CurvePolygonZM) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiCurveZM) - assert QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiSurfaceZM) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.Point25D) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.LineString25D) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.Polygon25D) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPoint25D) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiLineString25D) - assert not QgsWkbTypes.isCurvedType(QgsWkbTypes.Type.MultiPolygon25D) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveZ, False, False), + QgsWkbTypes.Type.MultiCurve, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveZ, True, False), + QgsWkbTypes.Type.MultiCurveZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveZ, False, True), + QgsWkbTypes.Type.MultiCurveM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveZ, True, True), + QgsWkbTypes.Type.MultiCurveZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveM, False, False), + QgsWkbTypes.Type.MultiCurve, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveM, True, False), + QgsWkbTypes.Type.MultiCurveZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveM, False, True), + QgsWkbTypes.Type.MultiCurveM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveM, True, True), + QgsWkbTypes.Type.MultiCurveZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveZM, False, False), + QgsWkbTypes.Type.MultiCurve, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveZM, True, False), + QgsWkbTypes.Type.MultiCurveZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveZM, False, True), + QgsWkbTypes.Type.MultiCurveM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveZM, True, True), + QgsWkbTypes.Type.MultiCurveZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygon, False, False), + QgsWkbTypes.Type.CurvePolygon, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygon, True, False), + QgsWkbTypes.Type.CurvePolygonZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygon, False, True), + QgsWkbTypes.Type.CurvePolygonM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygon, True, True), + QgsWkbTypes.Type.CurvePolygonZM, + ) + + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonZ, False, False), + QgsWkbTypes.Type.CurvePolygon, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonZ, True, False), + QgsWkbTypes.Type.CurvePolygonZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonZ, False, True), + QgsWkbTypes.Type.CurvePolygonM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonZ, True, True), + QgsWkbTypes.Type.CurvePolygonZM, + ) - # test hasZ methods - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.Unknown) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.Point) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.LineString) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.Polygon) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.PolyhedralSurface) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.TIN) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPoint) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiLineString) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPolygon) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.GeometryCollection) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.CircularString) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.CompoundCurve) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.CurvePolygon) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiCurve) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiSurface) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.NoGeometry) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.PointZ) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.LineStringZ) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.PolygonZ) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.PolyhedralSurfaceZ) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.TINZ) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPointZ) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiLineStringZ) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPolygonZ) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.GeometryCollectionZ) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.CircularStringZ) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.CompoundCurveZ) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.CurvePolygonZ) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiCurveZ) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiSurfaceZ) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.PointM) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.LineStringM) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.PolygonM) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.PolyhedralSurfaceM) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.TINM) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPointM) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiLineStringM) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPolygonM) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.GeometryCollectionM) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.CircularStringM) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.CompoundCurveM) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.CurvePolygonM) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiCurveM) - assert not QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiSurfaceM) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.PointZM) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.LineStringZM) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.PolygonZM) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.PolyhedralSurfaceZM) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.TINZM) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPointZM) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiLineStringZM) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPolygonZM) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.GeometryCollectionZM) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.CircularStringZM) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.CompoundCurveZM) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.CurvePolygonZM) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiCurveZM) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiSurfaceZM) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.Point25D) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.LineString25D) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.Polygon25D) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPoint25D) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiLineString25D) - assert QgsWkbTypes.hasZ(QgsWkbTypes.Type.MultiPolygon25D) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonM, False, False), + QgsWkbTypes.Type.CurvePolygon, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonM, True, False), + QgsWkbTypes.Type.CurvePolygonZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonM, False, True), + QgsWkbTypes.Type.CurvePolygonM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonM, True, True), + QgsWkbTypes.Type.CurvePolygonZM, + ) - # test hasM methods - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.Unknown) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.Point) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.LineString) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.Polygon) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.PolyhedralSurface) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.TIN) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPoint) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiLineString) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPolygon) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.GeometryCollection) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.CircularString) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.CompoundCurve) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.CurvePolygon) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiCurve) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiSurface) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.NoGeometry) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.PointZ) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.LineStringZ) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.PolygonZ) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.PolyhedralSurfaceZ) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.TINZ) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPointZ) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiLineStringZ) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPolygonZ) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.GeometryCollectionZ) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.CircularStringZ) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.CompoundCurveZ) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.CurvePolygonZ) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiCurveZ) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiSurfaceZ) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.PointM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.LineStringM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.PolygonM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.PolyhedralSurfaceM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.TINM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPointM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiLineStringM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPolygonM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.GeometryCollectionM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.CircularStringM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.CompoundCurveM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.CurvePolygonM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiCurveM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiSurfaceM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.PointZM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.LineStringZM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.PolygonZM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.PolyhedralSurfaceZM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.TINZM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPointZM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiLineStringZM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPolygonZM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.GeometryCollectionZM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.CircularStringZM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.CompoundCurveZM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.CurvePolygonZM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiCurveZM) - assert QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiSurfaceZM) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.Point25D) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.LineString25D) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.Polygon25D) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPoint25D) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiLineString25D) - assert not QgsWkbTypes.hasM(QgsWkbTypes.Type.MultiPolygon25D) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonZM, False, False), + QgsWkbTypes.Type.CurvePolygon, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonZM, True, False), + QgsWkbTypes.Type.CurvePolygonZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonZM, False, True), + QgsWkbTypes.Type.CurvePolygonM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonZM, True, True), + QgsWkbTypes.Type.CurvePolygonZM, + ) - # test adding z dimension to types - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.PointZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.PointZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.PointZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.PointZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPoint), QgsWkbTypes.Type.MultiPointZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPointZ), QgsWkbTypes.Type.MultiPointZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPointM), QgsWkbTypes.Type.MultiPointZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPointZM), QgsWkbTypes.Type.MultiPointZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.LineString), QgsWkbTypes.Type.LineStringZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.LineStringZ), QgsWkbTypes.Type.LineStringZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.LineStringM), QgsWkbTypes.Type.LineStringZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.LineStringZM), QgsWkbTypes.Type.LineStringZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiLineString), QgsWkbTypes.Type.MultiLineStringZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiLineStringZ), QgsWkbTypes.Type.MultiLineStringZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiLineStringM), QgsWkbTypes.Type.MultiLineStringZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiLineStringZM), QgsWkbTypes.Type.MultiLineStringZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.Polygon), QgsWkbTypes.Type.PolygonZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.Type.PolygonZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.Type.PolygonZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.PolygonZM), QgsWkbTypes.Type.PolygonZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPolygon), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPolygonZ), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPolygonM), QgsWkbTypes.Type.MultiPolygonZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPolygonZM), QgsWkbTypes.Type.MultiPolygonZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.GeometryCollection), QgsWkbTypes.Type.GeometryCollectionZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.GeometryCollectionZ), QgsWkbTypes.Type.GeometryCollectionZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.GeometryCollectionM), QgsWkbTypes.Type.GeometryCollectionZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.GeometryCollectionZM), QgsWkbTypes.Type.GeometryCollectionZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.CircularString), QgsWkbTypes.Type.CircularStringZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.CircularStringZ), QgsWkbTypes.Type.CircularStringZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.CircularStringM), QgsWkbTypes.Type.CircularStringZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.CircularStringZM), QgsWkbTypes.Type.CircularStringZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.CompoundCurve), QgsWkbTypes.Type.CompoundCurveZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.CompoundCurveZ), QgsWkbTypes.Type.CompoundCurveZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.CompoundCurveM), QgsWkbTypes.Type.CompoundCurveZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.CompoundCurveZM), QgsWkbTypes.Type.CompoundCurveZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.CurvePolygon), QgsWkbTypes.Type.CurvePolygonZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.CurvePolygonZ), QgsWkbTypes.Type.CurvePolygonZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.CurvePolygonM), QgsWkbTypes.Type.CurvePolygonZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.CurvePolygonZM), QgsWkbTypes.Type.CurvePolygonZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiCurve), QgsWkbTypes.Type.MultiCurveZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiCurveZ), QgsWkbTypes.Type.MultiCurveZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiCurveM), QgsWkbTypes.Type.MultiCurveZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiCurveZM), QgsWkbTypes.Type.MultiCurveZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiSurface), QgsWkbTypes.Type.MultiSurfaceZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiSurfaceZ), QgsWkbTypes.Type.MultiSurfaceZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiSurfaceM), QgsWkbTypes.Type.MultiSurfaceZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiSurfaceZM), QgsWkbTypes.Type.MultiSurfaceZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.NoGeometry), QgsWkbTypes.Type.NoGeometry) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.Point25D), QgsWkbTypes.Type.Point25D) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.LineString25D), QgsWkbTypes.Type.LineString25D) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.Polygon25D), QgsWkbTypes.Type.Polygon25D) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPoint25D), QgsWkbTypes.Type.MultiPoint25D) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiLineString25D), QgsWkbTypes.Type.MultiLineString25D) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.MultiPolygon25D), QgsWkbTypes.Type.MultiPolygon25D) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.PolyhedralSurface), QgsWkbTypes.Type.PolyhedralSurfaceZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.PolyhedralSurfaceZ), QgsWkbTypes.Type.PolyhedralSurfaceZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.PolyhedralSurfaceM), QgsWkbTypes.Type.PolyhedralSurfaceZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.PolyhedralSurfaceZM), QgsWkbTypes.Type.PolyhedralSurfaceZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.TIN), QgsWkbTypes.Type.TINZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.TINZ), QgsWkbTypes.Type.TINZ) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.TINM), QgsWkbTypes.Type.TINZM) - self.assertEqual(QgsWkbTypes.addZ(QgsWkbTypes.Type.TINZM), QgsWkbTypes.Type.TINZM) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurface, False, False), + QgsWkbTypes.Type.MultiSurface, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurface, True, False), + QgsWkbTypes.Type.MultiSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurface, False, True), + QgsWkbTypes.Type.MultiSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurface, True, True), + QgsWkbTypes.Type.MultiSurfaceZM, + ) - # test to25D - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.Point25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.Point25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.Point25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.Point25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPoint), QgsWkbTypes.Type.MultiPoint25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPointZ), QgsWkbTypes.Type.MultiPoint25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPointM), QgsWkbTypes.Type.MultiPoint25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPointZM), QgsWkbTypes.Type.MultiPoint25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.LineString), QgsWkbTypes.Type.LineString25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.LineStringZ), QgsWkbTypes.Type.LineString25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.LineStringM), QgsWkbTypes.Type.LineString25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.LineStringZM), QgsWkbTypes.Type.LineString25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiLineString), QgsWkbTypes.Type.MultiLineString25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiLineStringZ), QgsWkbTypes.Type.MultiLineString25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiLineStringM), QgsWkbTypes.Type.MultiLineString25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiLineStringZM), QgsWkbTypes.Type.MultiLineString25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.Polygon), QgsWkbTypes.Type.Polygon25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.Type.Polygon25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.Type.Polygon25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.PolygonZM), QgsWkbTypes.Type.Polygon25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPolygon), QgsWkbTypes.Type.MultiPolygon25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPolygonZ), QgsWkbTypes.Type.MultiPolygon25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPolygonM), QgsWkbTypes.Type.MultiPolygon25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPolygonZM), QgsWkbTypes.Type.MultiPolygon25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.GeometryCollection), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.GeometryCollectionZ), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.GeometryCollectionM), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.GeometryCollectionZM), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.CircularString), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.CircularStringZ), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.CircularStringM), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.CircularStringZM), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.CompoundCurve), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.CompoundCurveZ), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.CompoundCurveM), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.CompoundCurveZM), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.CurvePolygon), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.CurvePolygonZ), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.CurvePolygonM), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.CurvePolygonZM), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiCurve), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiCurveZ), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiCurveM), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiCurveZM), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiSurface), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiSurfaceZ), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiSurfaceM), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiSurfaceZM), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.NoGeometry), QgsWkbTypes.Type.NoGeometry) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.Point25D), QgsWkbTypes.Type.Point25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.LineString25D), QgsWkbTypes.Type.LineString25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.Polygon25D), QgsWkbTypes.Type.Polygon25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPoint25D), QgsWkbTypes.Type.MultiPoint25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiLineString25D), QgsWkbTypes.Type.MultiLineString25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.MultiPolygon25D), QgsWkbTypes.Type.MultiPolygon25D) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.PolyhedralSurface), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.PolyhedralSurfaceZ), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.PolyhedralSurfaceM), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.PolyhedralSurfaceZM), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.TIN), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.TINZ), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.TINM), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.to25D(QgsWkbTypes.Type.TINZM), QgsWkbTypes.Type.Unknown) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceZ, False, False), + QgsWkbTypes.Type.MultiSurface, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceZ, True, False), + QgsWkbTypes.Type.MultiSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceZ, False, True), + QgsWkbTypes.Type.MultiSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceZ, True, True), + QgsWkbTypes.Type.MultiSurfaceZM, + ) - # test adding m dimension to types - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.PointM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.PointZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.PointM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.PointZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPoint), QgsWkbTypes.Type.MultiPointM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPointZ), QgsWkbTypes.Type.MultiPointZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPointM), QgsWkbTypes.Type.MultiPointM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPointZM), QgsWkbTypes.Type.MultiPointZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.LineString), QgsWkbTypes.Type.LineStringM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.LineStringZ), QgsWkbTypes.Type.LineStringZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.LineStringM), QgsWkbTypes.Type.LineStringM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.LineStringZM), QgsWkbTypes.Type.LineStringZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiLineString), QgsWkbTypes.Type.MultiLineStringM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiLineStringZ), QgsWkbTypes.Type.MultiLineStringZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiLineStringM), QgsWkbTypes.Type.MultiLineStringM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiLineStringZM), QgsWkbTypes.Type.MultiLineStringZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.Polygon), QgsWkbTypes.Type.PolygonM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.Type.PolygonZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.Type.PolygonM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.PolygonZM), QgsWkbTypes.Type.PolygonZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPolygon), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPolygonZ), QgsWkbTypes.Type.MultiPolygonZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPolygonM), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPolygonZM), QgsWkbTypes.Type.MultiPolygonZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.GeometryCollection), QgsWkbTypes.Type.GeometryCollectionM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.GeometryCollectionZ), QgsWkbTypes.Type.GeometryCollectionZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.GeometryCollectionM), QgsWkbTypes.Type.GeometryCollectionM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.GeometryCollectionZM), QgsWkbTypes.Type.GeometryCollectionZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.CircularString), QgsWkbTypes.Type.CircularStringM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.CircularStringZ), QgsWkbTypes.Type.CircularStringZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.CircularStringM), QgsWkbTypes.Type.CircularStringM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.CircularStringZM), QgsWkbTypes.Type.CircularStringZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.CompoundCurve), QgsWkbTypes.Type.CompoundCurveM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.CompoundCurveZ), QgsWkbTypes.Type.CompoundCurveZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.CompoundCurveM), QgsWkbTypes.Type.CompoundCurveM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.CompoundCurveZM), QgsWkbTypes.Type.CompoundCurveZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.CurvePolygon), QgsWkbTypes.Type.CurvePolygonM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.CurvePolygonZ), QgsWkbTypes.Type.CurvePolygonZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.CurvePolygonM), QgsWkbTypes.Type.CurvePolygonM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.CurvePolygonZM), QgsWkbTypes.Type.CurvePolygonZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiCurve), QgsWkbTypes.Type.MultiCurveM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiCurveZ), QgsWkbTypes.Type.MultiCurveZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiCurveM), QgsWkbTypes.Type.MultiCurveM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiCurveZM), QgsWkbTypes.Type.MultiCurveZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiSurface), QgsWkbTypes.Type.MultiSurfaceM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiSurfaceZ), QgsWkbTypes.Type.MultiSurfaceZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiSurfaceM), QgsWkbTypes.Type.MultiSurfaceM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiSurfaceZM), QgsWkbTypes.Type.MultiSurfaceZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.NoGeometry), QgsWkbTypes.Type.NoGeometry) - # we force upgrade 25D types to "Z" before adding the M value - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.Point25D), QgsWkbTypes.Type.PointZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.LineString25D), QgsWkbTypes.Type.LineStringZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.Polygon25D), QgsWkbTypes.Type.PolygonZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPoint25D), QgsWkbTypes.Type.MultiPointZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiLineString25D), QgsWkbTypes.Type.MultiLineStringZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.MultiPolygon25D), QgsWkbTypes.Type.MultiPolygonZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.PolyhedralSurface), QgsWkbTypes.Type.PolyhedralSurfaceM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.PolyhedralSurfaceZ), QgsWkbTypes.Type.PolyhedralSurfaceZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.PolyhedralSurfaceM), QgsWkbTypes.Type.PolyhedralSurfaceM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.PolyhedralSurfaceZM), QgsWkbTypes.Type.PolyhedralSurfaceZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.TIN), QgsWkbTypes.Type.TINM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.TINZ), QgsWkbTypes.Type.TINZM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.TINM), QgsWkbTypes.Type.TINM) - self.assertEqual(QgsWkbTypes.addM(QgsWkbTypes.Type.TINZM), QgsWkbTypes.Type.TINZM) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceM, False, False), + QgsWkbTypes.Type.MultiSurface, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceM, True, False), + QgsWkbTypes.Type.MultiSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceM, False, True), + QgsWkbTypes.Type.MultiSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceM, True, True), + QgsWkbTypes.Type.MultiSurfaceZM, + ) - # test dropping z dimension from types - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.PointM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.PointM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPoint), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPointZ), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPointM), QgsWkbTypes.Type.MultiPointM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPointZM), QgsWkbTypes.Type.MultiPointM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.LineString), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.LineStringZ), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.LineStringM), QgsWkbTypes.Type.LineStringM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.LineStringZM), QgsWkbTypes.Type.LineStringM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiLineString), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiLineStringZ), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiLineStringM), QgsWkbTypes.Type.MultiLineStringM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiLineStringZM), QgsWkbTypes.Type.MultiLineStringM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.Polygon), QgsWkbTypes.Type.Polygon) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.Type.Polygon) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.Type.PolygonM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.PolygonZM), QgsWkbTypes.Type.PolygonM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPolygon), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPolygonZ), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPolygonM), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPolygonZM), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.GeometryCollection), QgsWkbTypes.Type.GeometryCollection) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.GeometryCollectionZ), QgsWkbTypes.Type.GeometryCollection) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.GeometryCollectionM), QgsWkbTypes.Type.GeometryCollectionM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.GeometryCollectionZM), QgsWkbTypes.Type.GeometryCollectionM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.CircularString), QgsWkbTypes.Type.CircularString) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.CircularStringZ), QgsWkbTypes.Type.CircularString) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.CircularStringM), QgsWkbTypes.Type.CircularStringM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.CircularStringZM), QgsWkbTypes.Type.CircularStringM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.CompoundCurve), QgsWkbTypes.Type.CompoundCurve) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.CompoundCurveZ), QgsWkbTypes.Type.CompoundCurve) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.CompoundCurveM), QgsWkbTypes.Type.CompoundCurveM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.CompoundCurveZM), QgsWkbTypes.Type.CompoundCurveM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.CurvePolygon), QgsWkbTypes.Type.CurvePolygon) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.CurvePolygonZ), QgsWkbTypes.Type.CurvePolygon) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.CurvePolygonM), QgsWkbTypes.Type.CurvePolygonM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.CurvePolygonZM), QgsWkbTypes.Type.CurvePolygonM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiCurve), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiCurveZ), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiCurveM), QgsWkbTypes.Type.MultiCurveM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiCurveZM), QgsWkbTypes.Type.MultiCurveM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiSurface), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiSurfaceZ), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiSurfaceM), QgsWkbTypes.Type.MultiSurfaceM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiSurfaceZM), QgsWkbTypes.Type.MultiSurfaceM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.NoGeometry), QgsWkbTypes.Type.NoGeometry) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.Point25D), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.LineString25D), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.Polygon25D), QgsWkbTypes.Type.Polygon) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPoint25D), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiLineString25D), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.MultiPolygon25D), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.PolyhedralSurface), QgsWkbTypes.Type.PolyhedralSurface) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.PolyhedralSurfaceZ), QgsWkbTypes.Type.PolyhedralSurface) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.PolyhedralSurfaceM), QgsWkbTypes.Type.PolyhedralSurfaceM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.PolyhedralSurfaceZM), QgsWkbTypes.Type.PolyhedralSurfaceM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.TIN), QgsWkbTypes.Type.TIN) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.TINZ), QgsWkbTypes.Type.TIN) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.TINM), QgsWkbTypes.Type.TINM) - self.assertEqual(QgsWkbTypes.dropZ(QgsWkbTypes.Type.TINZM), QgsWkbTypes.Type.TINM) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceZM, False, False), + QgsWkbTypes.Type.MultiSurface, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceZM, True, False), + QgsWkbTypes.Type.MultiSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceZM, False, True), + QgsWkbTypes.Type.MultiSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceZM, True, True), + QgsWkbTypes.Type.MultiSurfaceZM, + ) - # test dropping m dimension from types - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.Unknown), QgsWkbTypes.Type.Unknown) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.Point), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.PointZ), QgsWkbTypes.Type.PointZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.PointM), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.PointZM), QgsWkbTypes.Type.PointZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPoint), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPointZ), QgsWkbTypes.Type.MultiPointZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPointM), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPointZM), QgsWkbTypes.Type.MultiPointZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.LineString), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.LineStringZ), QgsWkbTypes.Type.LineStringZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.LineStringM), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.LineStringZM), QgsWkbTypes.Type.LineStringZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiLineString), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiLineStringZ), QgsWkbTypes.Type.MultiLineStringZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiLineStringM), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiLineStringZM), QgsWkbTypes.Type.MultiLineStringZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.Polygon), QgsWkbTypes.Type.Polygon) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.PolygonZ), QgsWkbTypes.Type.PolygonZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.PolygonM), QgsWkbTypes.Type.Polygon) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.PolygonZM), QgsWkbTypes.Type.PolygonZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPolygon), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPolygonZ), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPolygonM), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPolygonZM), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.GeometryCollection), QgsWkbTypes.Type.GeometryCollection) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.GeometryCollectionZ), QgsWkbTypes.Type.GeometryCollectionZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.GeometryCollectionM), QgsWkbTypes.Type.GeometryCollection) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.GeometryCollectionZM), QgsWkbTypes.Type.GeometryCollectionZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.CircularString), QgsWkbTypes.Type.CircularString) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.CircularStringZ), QgsWkbTypes.Type.CircularStringZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.CircularStringM), QgsWkbTypes.Type.CircularString) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.CircularStringZM), QgsWkbTypes.Type.CircularStringZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.CompoundCurve), QgsWkbTypes.Type.CompoundCurve) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.CompoundCurveZ), QgsWkbTypes.Type.CompoundCurveZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.CompoundCurveM), QgsWkbTypes.Type.CompoundCurve) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.CompoundCurveZM), QgsWkbTypes.Type.CompoundCurveZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.CurvePolygon), QgsWkbTypes.Type.CurvePolygon) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.CurvePolygonZ), QgsWkbTypes.Type.CurvePolygonZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.CurvePolygonM), QgsWkbTypes.Type.CurvePolygon) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.CurvePolygonZM), QgsWkbTypes.Type.CurvePolygonZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiCurve), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiCurveZ), QgsWkbTypes.Type.MultiCurveZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiCurveM), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiCurveZM), QgsWkbTypes.Type.MultiCurveZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiSurface), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiSurfaceZ), QgsWkbTypes.Type.MultiSurfaceZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiSurfaceM), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiSurfaceZM), QgsWkbTypes.Type.MultiSurfaceZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.NoGeometry), QgsWkbTypes.Type.NoGeometry) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.Point25D), QgsWkbTypes.Type.Point25D) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.LineString25D), QgsWkbTypes.Type.LineString25D) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.Polygon25D), QgsWkbTypes.Type.Polygon25D) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPoint25D), QgsWkbTypes.Type.MultiPoint25D) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiLineString25D), QgsWkbTypes.Type.MultiLineString25D) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.MultiPolygon25D), QgsWkbTypes.Type.MultiPolygon25D) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.PolyhedralSurface), QgsWkbTypes.Type.PolyhedralSurface) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.PolyhedralSurfaceZ), QgsWkbTypes.Type.PolyhedralSurfaceZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.PolyhedralSurfaceM), QgsWkbTypes.Type.PolyhedralSurface) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.PolyhedralSurfaceZM), QgsWkbTypes.Type.PolyhedralSurfaceZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.TIN), QgsWkbTypes.Type.TIN) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.TINZ), QgsWkbTypes.Type.TINZ) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.TINM), QgsWkbTypes.Type.TIN) - self.assertEqual(QgsWkbTypes.dropM(QgsWkbTypes.Type.TINZM), QgsWkbTypes.Type.TINZ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PolyhedralSurface, False, False), + QgsWkbTypes.Type.PolyhedralSurface, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PolyhedralSurface, True, False), + QgsWkbTypes.Type.PolyhedralSurfaceZ, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PolyhedralSurface, False, True), + QgsWkbTypes.Type.PolyhedralSurfaceM, + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.PolyhedralSurface, True, True), + QgsWkbTypes.Type.PolyhedralSurfaceZM, + ) - # Test QgsWkbTypes.zmType - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.Point, False, False), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.Point, True, False), QgsWkbTypes.Type.PointZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.Point, False, True), QgsWkbTypes.Type.PointM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.Point, True, True), QgsWkbTypes.Type.PointZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PointZ, False, False), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PointZ, True, False), QgsWkbTypes.Type.PointZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PointZ, False, True), QgsWkbTypes.Type.PointM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PointZ, True, True), QgsWkbTypes.Type.PointZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PointM, False, False), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PointM, True, False), QgsWkbTypes.Type.PointZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PointM, False, True), QgsWkbTypes.Type.PointM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PointM, True, True), QgsWkbTypes.Type.PointZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PointZM, False, False), QgsWkbTypes.Type.Point) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PointZM, True, False), QgsWkbTypes.Type.PointZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PointZM, False, True), QgsWkbTypes.Type.PointM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PointZM, True, True), QgsWkbTypes.Type.PointZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.LineString, False, False), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.LineString, True, False), QgsWkbTypes.Type.LineStringZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.LineString, False, True), QgsWkbTypes.Type.LineStringM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.LineString, True, True), QgsWkbTypes.Type.LineStringZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringZ, False, False), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringZ, True, False), QgsWkbTypes.Type.LineStringZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringZ, False, True), QgsWkbTypes.Type.LineStringM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringZ, True, True), QgsWkbTypes.Type.LineStringZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringM, False, False), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringM, True, False), QgsWkbTypes.Type.LineStringZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringM, False, True), QgsWkbTypes.Type.LineStringM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringM, True, True), QgsWkbTypes.Type.LineStringZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringZM, False, False), QgsWkbTypes.Type.LineString) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringZM, True, False), QgsWkbTypes.Type.LineStringZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringZM, False, True), QgsWkbTypes.Type.LineStringM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.LineStringZM, True, True), QgsWkbTypes.Type.LineStringZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.Polygon, False, False), QgsWkbTypes.Type.Polygon) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.Polygon, True, False), QgsWkbTypes.Type.PolygonZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.Polygon, False, True), QgsWkbTypes.Type.PolygonM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.Polygon, True, True), QgsWkbTypes.Type.PolygonZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonZ, False, False), QgsWkbTypes.Type.Polygon) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonZ, True, False), QgsWkbTypes.Type.PolygonZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonZ, False, True), QgsWkbTypes.Type.PolygonM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonZ, True, True), QgsWkbTypes.Type.PolygonZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonM, False, False), QgsWkbTypes.Type.Polygon) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonM, True, False), QgsWkbTypes.Type.PolygonZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonM, False, True), QgsWkbTypes.Type.PolygonM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonM, True, True), QgsWkbTypes.Type.PolygonZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonZM, False, False), QgsWkbTypes.Type.Polygon) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonZM, True, False), QgsWkbTypes.Type.PolygonZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonZM, False, True), QgsWkbTypes.Type.PolygonM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PolygonZM, True, True), QgsWkbTypes.Type.PolygonZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPoint, False, False), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPoint, True, False), QgsWkbTypes.Type.MultiPointZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPoint, False, True), QgsWkbTypes.Type.MultiPointM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPoint, True, True), QgsWkbTypes.Type.MultiPointZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointZ, False, False), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointZ, True, False), QgsWkbTypes.Type.MultiPointZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointZ, False, True), QgsWkbTypes.Type.MultiPointM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointZ, True, True), QgsWkbTypes.Type.MultiPointZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointM, False, False), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointM, True, False), QgsWkbTypes.Type.MultiPointZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointM, False, True), QgsWkbTypes.Type.MultiPointM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointM, True, True), QgsWkbTypes.Type.MultiPointZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointZM, False, False), QgsWkbTypes.Type.MultiPoint) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointZM, True, False), QgsWkbTypes.Type.MultiPointZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointZM, False, True), QgsWkbTypes.Type.MultiPointM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPointZM, True, True), QgsWkbTypes.Type.MultiPointZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineString, False, False), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineString, True, False), QgsWkbTypes.Type.MultiLineStringZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineString, False, True), QgsWkbTypes.Type.MultiLineStringM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineString, True, True), QgsWkbTypes.Type.MultiLineStringZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringZ, False, False), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringZ, True, False), QgsWkbTypes.Type.MultiLineStringZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringZ, False, True), QgsWkbTypes.Type.MultiLineStringM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringZ, True, True), QgsWkbTypes.Type.MultiLineStringZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringM, False, False), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringM, True, False), QgsWkbTypes.Type.MultiLineStringZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringM, False, True), QgsWkbTypes.Type.MultiLineStringM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringM, True, True), QgsWkbTypes.Type.MultiLineStringZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringZM, False, False), QgsWkbTypes.Type.MultiLineString) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringZM, True, False), QgsWkbTypes.Type.MultiLineStringZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringZM, False, True), QgsWkbTypes.Type.MultiLineStringM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiLineStringZM, True, True), QgsWkbTypes.Type.MultiLineStringZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygon, False, False), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygon, True, False), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygon, False, True), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygon, True, True), QgsWkbTypes.Type.MultiPolygonZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonZ, False, False), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonZ, True, False), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonZ, False, True), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonZ, True, True), QgsWkbTypes.Type.MultiPolygonZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonM, False, False), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonM, True, False), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonM, False, True), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonM, True, True), QgsWkbTypes.Type.MultiPolygonZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonZM, False, False), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonZM, True, False), QgsWkbTypes.Type.MultiPolygonZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonZM, False, True), QgsWkbTypes.Type.MultiPolygonM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiPolygonZM, True, True), QgsWkbTypes.Type.MultiPolygonZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollection, False, False), - QgsWkbTypes.Type.GeometryCollection) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollection, True, False), - QgsWkbTypes.Type.GeometryCollectionZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollection, False, True), - QgsWkbTypes.Type.GeometryCollectionM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollection, True, True), - QgsWkbTypes.Type.GeometryCollectionZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionZ, False, False), - QgsWkbTypes.Type.GeometryCollection) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionZ, True, False), - QgsWkbTypes.Type.GeometryCollectionZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionZ, False, True), - QgsWkbTypes.Type.GeometryCollectionM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionZ, True, True), - QgsWkbTypes.Type.GeometryCollectionZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionM, False, False), - QgsWkbTypes.Type.GeometryCollection) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionM, True, False), - QgsWkbTypes.Type.GeometryCollectionZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionM, False, True), - QgsWkbTypes.Type.GeometryCollectionM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionM, True, True), - QgsWkbTypes.Type.GeometryCollectionZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionZM, False, False), - QgsWkbTypes.Type.GeometryCollection) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionZM, True, False), - QgsWkbTypes.Type.GeometryCollectionZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionZM, False, True), - QgsWkbTypes.Type.GeometryCollectionM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.GeometryCollectionZM, True, True), - QgsWkbTypes.Type.GeometryCollectionZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularString, False, False), QgsWkbTypes.Type.CircularString) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularString, True, False), QgsWkbTypes.Type.CircularStringZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularString, False, True), QgsWkbTypes.Type.CircularStringM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularString, True, True), QgsWkbTypes.Type.CircularStringZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringZ, False, False), QgsWkbTypes.Type.CircularString) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringZ, True, False), QgsWkbTypes.Type.CircularStringZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringZ, False, True), QgsWkbTypes.Type.CircularStringM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringZ, True, True), QgsWkbTypes.Type.CircularStringZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringM, False, False), QgsWkbTypes.Type.CircularString) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringM, True, False), QgsWkbTypes.Type.CircularStringZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringM, False, True), QgsWkbTypes.Type.CircularStringM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringM, True, True), QgsWkbTypes.Type.CircularStringZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringZM, False, False), QgsWkbTypes.Type.CircularString) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringZM, True, False), QgsWkbTypes.Type.CircularStringZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringZM, False, True), QgsWkbTypes.Type.CircularStringM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CircularStringZM, True, True), QgsWkbTypes.Type.CircularStringZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurve, False, False), QgsWkbTypes.Type.CompoundCurve) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurve, True, False), QgsWkbTypes.Type.CompoundCurveZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurve, False, True), QgsWkbTypes.Type.CompoundCurveM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurve, True, True), QgsWkbTypes.Type.CompoundCurveZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveZ, False, False), QgsWkbTypes.Type.CompoundCurve) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveZ, True, False), QgsWkbTypes.Type.CompoundCurveZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveZ, False, True), QgsWkbTypes.Type.CompoundCurveM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveZ, True, True), QgsWkbTypes.Type.CompoundCurveZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveM, False, False), QgsWkbTypes.Type.CompoundCurve) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveM, True, False), QgsWkbTypes.Type.CompoundCurveZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveM, False, True), QgsWkbTypes.Type.CompoundCurveM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveM, True, True), QgsWkbTypes.Type.CompoundCurveZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveZM, False, False), QgsWkbTypes.Type.CompoundCurve) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveZM, True, False), QgsWkbTypes.Type.CompoundCurveZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveZM, False, True), QgsWkbTypes.Type.CompoundCurveM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CompoundCurveZM, True, True), QgsWkbTypes.Type.CompoundCurveZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurve, False, False), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurve, True, False), QgsWkbTypes.Type.MultiCurveZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurve, False, True), QgsWkbTypes.Type.MultiCurveM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurve, True, True), QgsWkbTypes.Type.MultiCurveZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveZ, False, False), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveZ, True, False), QgsWkbTypes.Type.MultiCurveZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveZ, False, True), QgsWkbTypes.Type.MultiCurveM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveZ, True, True), QgsWkbTypes.Type.MultiCurveZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveM, False, False), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveM, True, False), QgsWkbTypes.Type.MultiCurveZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveM, False, True), QgsWkbTypes.Type.MultiCurveM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveM, True, True), QgsWkbTypes.Type.MultiCurveZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveZM, False, False), QgsWkbTypes.Type.MultiCurve) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveZM, True, False), QgsWkbTypes.Type.MultiCurveZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveZM, False, True), QgsWkbTypes.Type.MultiCurveM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiCurveZM, True, True), QgsWkbTypes.Type.MultiCurveZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygon, False, False), QgsWkbTypes.Type.CurvePolygon) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygon, True, False), QgsWkbTypes.Type.CurvePolygonZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygon, False, True), QgsWkbTypes.Type.CurvePolygonM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygon, True, True), QgsWkbTypes.Type.CurvePolygonZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonZ, False, False), QgsWkbTypes.Type.CurvePolygon) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonZ, True, False), QgsWkbTypes.Type.CurvePolygonZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonZ, False, True), QgsWkbTypes.Type.CurvePolygonM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonZ, True, True), QgsWkbTypes.Type.CurvePolygonZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonM, False, False), QgsWkbTypes.Type.CurvePolygon) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonM, True, False), QgsWkbTypes.Type.CurvePolygonZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonM, False, True), QgsWkbTypes.Type.CurvePolygonM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonM, True, True), QgsWkbTypes.Type.CurvePolygonZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonZM, False, False), QgsWkbTypes.Type.CurvePolygon) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonZM, True, False), QgsWkbTypes.Type.CurvePolygonZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonZM, False, True), QgsWkbTypes.Type.CurvePolygonM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.CurvePolygonZM, True, True), QgsWkbTypes.Type.CurvePolygonZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurface, False, False), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurface, True, False), QgsWkbTypes.Type.MultiSurfaceZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurface, False, True), QgsWkbTypes.Type.MultiSurfaceM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurface, True, True), QgsWkbTypes.Type.MultiSurfaceZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceZ, False, False), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceZ, True, False), QgsWkbTypes.Type.MultiSurfaceZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceZ, False, True), QgsWkbTypes.Type.MultiSurfaceM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceZ, True, True), QgsWkbTypes.Type.MultiSurfaceZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceM, False, False), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceM, True, False), QgsWkbTypes.Type.MultiSurfaceZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceM, False, True), QgsWkbTypes.Type.MultiSurfaceM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceM, True, True), QgsWkbTypes.Type.MultiSurfaceZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceZM, False, False), QgsWkbTypes.Type.MultiSurface) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceZM, True, False), QgsWkbTypes.Type.MultiSurfaceZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceZM, False, True), QgsWkbTypes.Type.MultiSurfaceM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.MultiSurfaceZM, True, True), QgsWkbTypes.Type.MultiSurfaceZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PolyhedralSurface, False, False), QgsWkbTypes.Type.PolyhedralSurface) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PolyhedralSurface, True, False), QgsWkbTypes.Type.PolyhedralSurfaceZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PolyhedralSurface, False, True), QgsWkbTypes.Type.PolyhedralSurfaceM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.PolyhedralSurface, True, True), QgsWkbTypes.Type.PolyhedralSurfaceZM) - - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.TIN, False, False), QgsWkbTypes.Type.TIN) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.TIN, True, False), QgsWkbTypes.Type.TINZ) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.TIN, False, True), QgsWkbTypes.Type.TINM) - self.assertEqual(QgsWkbTypes.zmType(QgsWkbTypes.Type.TIN, True, True), QgsWkbTypes.Type.TINZM) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.TIN, False, False), QgsWkbTypes.Type.TIN + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.TIN, True, False), QgsWkbTypes.Type.TINZ + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.TIN, False, True), QgsWkbTypes.Type.TINM + ) + self.assertEqual( + QgsWkbTypes.zmType(QgsWkbTypes.Type.TIN, True, True), QgsWkbTypes.Type.TINZM + ) def testGeometryDisplayString(self): - self.assertEqual(QgsWkbTypes.geometryDisplayString(QgsWkbTypes.GeometryType.PointGeometry), 'Point') - self.assertEqual(QgsWkbTypes.geometryDisplayString(QgsWkbTypes.GeometryType.LineGeometry), 'Line') - self.assertEqual(QgsWkbTypes.geometryDisplayString(QgsWkbTypes.GeometryType.PolygonGeometry), 'Polygon') - self.assertEqual(QgsWkbTypes.geometryDisplayString(QgsWkbTypes.GeometryType.UnknownGeometry), 'Unknown geometry') - self.assertEqual(QgsWkbTypes.geometryDisplayString(QgsWkbTypes.GeometryType.NullGeometry), 'No geometry') + self.assertEqual( + QgsWkbTypes.geometryDisplayString(QgsWkbTypes.GeometryType.PointGeometry), + "Point", + ) + self.assertEqual( + QgsWkbTypes.geometryDisplayString(QgsWkbTypes.GeometryType.LineGeometry), + "Line", + ) + self.assertEqual( + QgsWkbTypes.geometryDisplayString(QgsWkbTypes.GeometryType.PolygonGeometry), + "Polygon", + ) + self.assertEqual( + QgsWkbTypes.geometryDisplayString(QgsWkbTypes.GeometryType.UnknownGeometry), + "Unknown geometry", + ) + self.assertEqual( + QgsWkbTypes.geometryDisplayString(QgsWkbTypes.GeometryType.NullGeometry), + "No geometry", + ) def testDeleteVertexCircularString(self): @@ -5221,7 +9647,9 @@ def testDeleteVertexCompoundCurve(self): wkt = "CompoundCurve ((-1 0,0 0),CircularString(0 0,1 1,2 0,1.5 -0.5,1 -1))" geom = QgsGeometry.fromWkt(wkt) assert geom.deleteVertex(1) - expected_wkt = "CompoundCurve ((-1 0, 2 0),CircularString (2 0, 1.5 -0.5, 1 -1))" + expected_wkt = ( + "CompoundCurve ((-1 0, 2 0),CircularString (2 0, 1.5 -0.5, 1 -1))" + ) self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(expected_wkt).asWkt()) wkt = "CompoundCurve (CircularString(-1 -1,-1.5 -0.5,-2 0,-1 1,0 0),CircularString(0 0,1 1,2 0,1.5 -0.5,1 -1))" @@ -5269,7 +9697,9 @@ def testDeleteVertexCurvePolygon(self): wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0,1.5 -0.5,1 -1),(1 -1,0 0)))" geom = QgsGeometry.fromWkt(wkt) assert geom.deleteVertex(2) - expected_wkt = "CurvePolygon (CompoundCurve (CircularString (0 0, 1 1, 1 -1),(1 -1, 0 0)))" + expected_wkt = ( + "CurvePolygon (CompoundCurve (CircularString (0 0, 1 1, 1 -1),(1 -1, 0 0)))" + ) self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(expected_wkt).asWkt()) wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0,1.5 -0.5,1 -1),(1 -1,0 0)))" @@ -5281,7 +9711,9 @@ def testDeleteVertexCurvePolygon(self): wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0,1.5 -0.5,1 -1),(1 -1,0 0)))" geom = QgsGeometry.fromWkt(wkt) assert geom.deleteVertex(4) - expected_wkt = "CurvePolygon (CompoundCurve (CircularString (0 0, 1 1, 2 0),(2 0, 0 0)))" + expected_wkt = ( + "CurvePolygon (CompoundCurve (CircularString (0 0, 1 1, 2 0),(2 0, 0 0)))" + ) self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(expected_wkt).asWkt()) def testConvertVertex(self): @@ -5289,31 +9721,30 @@ def testConvertVertex(self): # WKT BEFORE -> WKT AFTER A CONVERT ON POINT AT 10,10 test_setup = { # Curve - 'LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0)': 'COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0))', - 'COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0))': 'COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0))', - 'COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0))': 'COMPOUNDCURVE((0 0, 10 0, 10 10, 0 10, 0 0))', - + "LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0)": "COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0))", + "COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0))": "COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0))", + "COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0))": "COMPOUNDCURVE((0 0, 10 0, 10 10, 0 10, 0 0))", # Multicurve - 'MULTICURVE(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(5 15, 10 20, 0 20, 5 15))': 'MULTICURVE(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), LINESTRING(5 15, 10 20, 0 20, 5 15))', - 'MULTICURVE(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), LINESTRING(5 15, 10 20, 0 20, 5 15))': 'MULTICURVE(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), LINESTRING(5 15, 10 20, 0 20, 5 15))', - 'MULTICURVE(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), LINESTRING(5 15, 10 20, 0 20, 5 15))': 'MULTICURVE(COMPOUNDCURVE((0 0, 10 0, 10 10, 0 10, 0 0)), LINESTRING(5 15, 10 20, 0 20, 5 15))', - + "MULTICURVE(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(5 15, 10 20, 0 20, 5 15))": "MULTICURVE(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), LINESTRING(5 15, 10 20, 0 20, 5 15))", + "MULTICURVE(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), LINESTRING(5 15, 10 20, 0 20, 5 15))": "MULTICURVE(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), LINESTRING(5 15, 10 20, 0 20, 5 15))", + "MULTICURVE(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), LINESTRING(5 15, 10 20, 0 20, 5 15))": "MULTICURVE(COMPOUNDCURVE((0 0, 10 0, 10 10, 0 10, 0 0)), LINESTRING(5 15, 10 20, 0 20, 5 15))", # Polygon - 'CURVEPOLYGON(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(3 3, 7 3, 7 7, 3 7, 3 3))': 'CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), LINESTRING(3 3, 7 3, 7 7, 3 7, 3 3))', - 'CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE(CIRCULARSTRING(3 3, 7 3, 7 7, 3 7, 3 3)))': 'CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE(CIRCULARSTRING(3 3, 7 3, 7 7, 3 7, 3 3)))', - 'CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), COMPOUNDCURVE((3 3, 7 3), CIRCULARSTRING(7 3, 7 7, 3 7), (3 7, 3 3)))': 'CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE((3 3, 7 3), CIRCULARSTRING(7 3, 7 7, 3 7), (3 7, 3 3)))', - + "CURVEPOLYGON(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(3 3, 7 3, 7 7, 3 7, 3 3))": "CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), LINESTRING(3 3, 7 3, 7 7, 3 7, 3 3))", + "CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE(CIRCULARSTRING(3 3, 7 3, 7 7, 3 7, 3 3)))": "CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE(CIRCULARSTRING(3 3, 7 3, 7 7, 3 7, 3 3)))", + "CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), COMPOUNDCURVE((3 3, 7 3), CIRCULARSTRING(7 3, 7 7, 3 7), (3 7, 3 3)))": "CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE((3 3, 7 3), CIRCULARSTRING(7 3, 7 7, 3 7), (3 7, 3 3)))", # Multipolygon - 'MULTISURFACE(CURVEPOLYGON(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(3 3, 7 3, 7 7, 3 7, 3 3)), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))': 'MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), LINESTRING(3 3, 7 3, 7 7, 3 7, 3 3)), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))', - 'MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE(CIRCULARSTRING(3 3, 7 3, 7 7, 3 7, 3 3))), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))': 'MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE(CIRCULARSTRING(3 3, 7 3, 7 7, 3 7, 3 3))), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))', - 'MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), COMPOUNDCURVE((3 3, 7 3), CIRCULARSTRING(7 3, 7 7, 3 7), (3 7, 3 3))), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))': 'MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE((3 3, 7 3), CIRCULARSTRING(7 3, 7 7, 3 7), (3 7, 3 3))), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))', + "MULTISURFACE(CURVEPOLYGON(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(3 3, 7 3, 7 7, 3 7, 3 3)), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))": "MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), LINESTRING(3 3, 7 3, 7 7, 3 7, 3 3)), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))", + "MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE(CIRCULARSTRING(3 3, 7 3, 7 7, 3 7, 3 3))), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))": "MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE(CIRCULARSTRING(3 3, 7 3, 7 7, 3 7, 3 3))), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))", + "MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), COMPOUNDCURVE((3 3, 7 3), CIRCULARSTRING(7 3, 7 7, 3 7), (3 7, 3 3))), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))": "MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE((3 3, 7 3), CIRCULARSTRING(7 3, 7 7, 3 7), (3 7, 3 3))), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))", } for wkt_before, wkt_expected in test_setup.items(): geom = QgsGeometry.fromWkt(wkt_before) geom.toggleCircularAtVertex(geom.closestVertex(QgsPointXY(10, 10))[1]) - self.assertTrue(QgsGeometry.equals(geom, QgsGeometry.fromWkt(wkt_expected)), - f'toggleCircularAtVertex() did not create expected geometry.\nconverted wkt : {geom.asWkt()}\nexpected wkt : {wkt_expected}\ninput wkt : {wkt_before}).') + self.assertTrue( + QgsGeometry.equals(geom, QgsGeometry.fromWkt(wkt_expected)), + f"toggleCircularAtVertex() did not create expected geometry.\nconverted wkt : {geom.asWkt()}\nexpected wkt : {wkt_expected}\ninput wkt : {wkt_before}).", + ) def testSingleSidedBuffer(self): @@ -5322,32 +9753,44 @@ def testSingleSidedBuffer(self): out = geom.singleSidedBuffer(1, 8, QgsGeometry.BufferSide.SideLeft) result = out.asWkt() expected_wkt = "Polygon ((10 0, 0 0, 0 1, 10 1, 10 0))" - self.assertTrue(compareWkt(result, expected_wkt, 0.00001), - f"Merge lines: mismatch Expected:\n{expected_wkt}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, expected_wkt, 0.00001), + f"Merge lines: mismatch Expected:\n{expected_wkt}\nGot:\n{result}\n", + ) wkt = "LineString( 0 0, 10 0)" geom = QgsGeometry.fromWkt(wkt) out = geom.singleSidedBuffer(1, 8, QgsGeometry.BufferSide.SideRight) result = out.asWkt() expected_wkt = "Polygon ((0 0, 10 0, 10 -1, 0 -1, 0 0))" - self.assertTrue(compareWkt(result, expected_wkt, 0.00001), - f"Merge lines: mismatch Expected:\n{expected_wkt}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, expected_wkt, 0.00001), + f"Merge lines: mismatch Expected:\n{expected_wkt}\nGot:\n{result}\n", + ) wkt = "LineString( 0 0, 10 0, 10 10)" geom = QgsGeometry.fromWkt(wkt) - out = geom.singleSidedBuffer(1, 8, QgsGeometry.BufferSide.SideRight, QgsGeometry.JoinStyle.JoinStyleMiter) + out = geom.singleSidedBuffer( + 1, 8, QgsGeometry.BufferSide.SideRight, QgsGeometry.JoinStyle.JoinStyleMiter + ) result = out.asWkt() expected_wkt = "Polygon ((0 0, 10 0, 10 10, 11 10, 11 -1, 0 -1, 0 0))" - self.assertTrue(compareWkt(result, expected_wkt, 0.00001), - f"Merge lines: mismatch Expected:\n{expected_wkt}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, expected_wkt, 0.00001), + f"Merge lines: mismatch Expected:\n{expected_wkt}\nGot:\n{result}\n", + ) wkt = "LineString( 0 0, 10 0, 10 10)" geom = QgsGeometry.fromWkt(wkt) - out = geom.singleSidedBuffer(1, 8, QgsGeometry.BufferSide.SideRight, QgsGeometry.JoinStyle.JoinStyleBevel) + out = geom.singleSidedBuffer( + 1, 8, QgsGeometry.BufferSide.SideRight, QgsGeometry.JoinStyle.JoinStyleBevel + ) result = out.asWkt() expected_wkt = "Polygon ((0 0, 10 0, 10 10, 11 10, 11 0, 10 -1, 0 -1, 0 0))" - self.assertTrue(compareWkt(result, expected_wkt, 0.00001), - f"Merge lines: mismatch Expected:\n{expected_wkt}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, expected_wkt, 0.00001), + f"Merge lines: mismatch Expected:\n{expected_wkt}\nGot:\n{result}\n", + ) def testMisc(self): @@ -5358,7 +9801,9 @@ def testMisc(self): assert not multipolygon.addGeometry(cp) # Test that importing an invalid WKB (a MultiPolygon with a CurvePolygon) fails - geom = QgsGeometry.fromWkt('MultiSurface(((0 0,0 1,1 1,0 0)), CurvePolygon ((0 0,0 1,1 1,0 0)))') + geom = QgsGeometry.fromWkt( + "MultiSurface(((0 0,0 1,1 1,0 0)), CurvePolygon ((0 0,0 1,1 1,0 0)))" + ) wkb = geom.asWkb() wkb = bytearray(wkb) if wkb[1] == QgsWkbTypes.Type.MultiSurface: @@ -5406,237 +9851,299 @@ def testMisc(self): self.assertEqual(wkb1, wkb2) def testMergeLines(self): - """ test merging linestrings """ + """test merging linestrings""" # not a (multi)linestring - geom = QgsGeometry.fromWkt('Point(1 2)') + geom = QgsGeometry.fromWkt("Point(1 2)") result = geom.mergeLines() self.assertTrue(result.isNull()) # linestring should be returned intact - geom = QgsGeometry.fromWkt('LineString(0 0, 10 10)') + geom = QgsGeometry.fromWkt("LineString(0 0, 10 10)") result = geom.mergeLines().asWkt() - exp = 'LineString(0 0, 10 10)' - self.assertTrue(compareWkt(result, exp, 0.00001), - f"Merge lines: mismatch Expected:\n{exp}\nGot:\n{result}\n") + exp = "LineString(0 0, 10 10)" + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"Merge lines: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) # multilinestring - geom = QgsGeometry.fromWkt('MultiLineString((0 0, 10 10),(10 10, 20 20))') + geom = QgsGeometry.fromWkt("MultiLineString((0 0, 10 10),(10 10, 20 20))") result = geom.mergeLines().asWkt() - exp = 'LineString(0 0, 10 10, 20 20)' - self.assertTrue(compareWkt(result, exp, 0.00001), - f"Merge lines: mismatch Expected:\n{exp}\nGot:\n{result}\n") + exp = "LineString(0 0, 10 10, 20 20)" + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"Merge lines: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) - geom = QgsGeometry.fromWkt('MultiLineString((0 0, 10 10),(12 2, 14 4),(10 10, 20 20))') + geom = QgsGeometry.fromWkt( + "MultiLineString((0 0, 10 10),(12 2, 14 4),(10 10, 20 20))" + ) result = geom.mergeLines().asWkt() - exp = 'MultiLineString((0 0, 10 10, 20 20),(12 2, 14 4))' - self.assertTrue(compareWkt(result, exp, 0.00001), - f"Merge lines: mismatch Expected:\n{exp}\nGot:\n{result}\n") + exp = "MultiLineString((0 0, 10 10, 20 20),(12 2, 14 4))" + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"Merge lines: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) - geom = QgsGeometry.fromWkt('MultiLineString((0 0, 10 10),(12 2, 14 4))') + geom = QgsGeometry.fromWkt("MultiLineString((0 0, 10 10),(12 2, 14 4))") result = geom.mergeLines().asWkt() - exp = 'MultiLineString((0 0, 10 10),(12 2, 14 4))' - self.assertTrue(compareWkt(result, exp, 0.00001), - f"Merge lines: mismatch Expected:\n{exp}\nGot:\n{result}\n") + exp = "MultiLineString((0 0, 10 10),(12 2, 14 4))" + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"Merge lines: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) def testCurveSinuosity(self): """ Test curve straightDistance2d() and sinuosity() """ - linestring = QgsGeometry.fromWkt('LineString EMPTY') + linestring = QgsGeometry.fromWkt("LineString EMPTY") self.assertTrue(math.isnan(linestring.constGet().straightDistance2d())) self.assertTrue(math.isnan(linestring.constGet().sinuosity())) - linestring = QgsGeometry.fromWkt('LineString(0 0, 10 0)') + linestring = QgsGeometry.fromWkt("LineString(0 0, 10 0)") self.assertEqual(linestring.constGet().straightDistance2d(), 10.0) self.assertEqual(linestring.constGet().sinuosity(), 1.0) - linestring = QgsGeometry.fromWkt('LineString(0 0, 10 10, 5 0)') + linestring = QgsGeometry.fromWkt("LineString(0 0, 10 10, 5 0)") self.assertAlmostEqual(linestring.constGet().straightDistance2d(), 5.0, 4) self.assertAlmostEqual(linestring.constGet().sinuosity(), 5.06449510, 4) - linestring = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10, 0 10, 0 0)') + linestring = QgsGeometry.fromWkt("LineString(0 0, 10 0, 10 10, 0 10, 0 0)") self.assertEqual(linestring.constGet().straightDistance2d(), 0.0) self.assertTrue(math.isnan(linestring.constGet().sinuosity())) - curve = QgsGeometry.fromWkt('CircularString (20 30, 50 30, 50 90)') + curve = QgsGeometry.fromWkt("CircularString (20 30, 50 30, 50 90)") self.assertAlmostEqual(curve.constGet().straightDistance2d(), 67.08203932, 4) self.assertAlmostEqual(curve.constGet().sinuosity(), 1.57079632, 4) - curve = QgsGeometry.fromWkt('CircularString (20 30, 50 30, 20 30)') + curve = QgsGeometry.fromWkt("CircularString (20 30, 50 30, 20 30)") self.assertAlmostEqual(curve.constGet().straightDistance2d(), 0.0, 4) self.assertTrue(math.isnan(curve.constGet().sinuosity())) def testLineLocatePoint(self): - """ test QgsGeometry.lineLocatePoint() """ + """test QgsGeometry.lineLocatePoint()""" # not a linestring - point = QgsGeometry.fromWkt('Point(1 2)') + point = QgsGeometry.fromWkt("Point(1 2)") self.assertEqual(point.lineLocatePoint(point), -1) # not a point - linestring = QgsGeometry.fromWkt('LineString(0 0, 10 0)') + linestring = QgsGeometry.fromWkt("LineString(0 0, 10 0)") self.assertEqual(linestring.lineLocatePoint(linestring), -1) # valid self.assertEqual(linestring.lineLocatePoint(point), 1) - point = QgsGeometry.fromWkt('Point(9 -2)') + point = QgsGeometry.fromWkt("Point(9 -2)") self.assertEqual(linestring.lineLocatePoint(point), 9) # circular string - geom = QgsGeometry.fromWkt('CircularString (1 5, 6 2, 7 3)') - point = QgsGeometry.fromWkt('Point(9 -2)') + geom = QgsGeometry.fromWkt("CircularString (1 5, 6 2, 7 3)") + point = QgsGeometry.fromWkt("Point(9 -2)") self.assertAlmostEqual(geom.lineLocatePoint(point), 7.377, places=3) def testInterpolateAngle(self): - """ test QgsGeometry.interpolateAngle() """ + """test QgsGeometry.interpolateAngle()""" empty = QgsGeometry() # just test no crash self.assertEqual(empty.interpolateAngle(5), 0) # not a linestring - point = QgsGeometry.fromWkt('Point(1 2)') + point = QgsGeometry.fromWkt("Point(1 2)") # no meaning, just test no crash! self.assertEqual(point.interpolateAngle(5), 0) self.assertEqual(point.interpolateAngle(0), 0) - collection_with_point = QgsGeometry.fromWkt('MultiPoint((0 -49))') + collection_with_point = QgsGeometry.fromWkt("MultiPoint((0 -49))") # no meaning, just test no crash! self.assertEqual(collection_with_point.interpolateAngle(5), 0) self.assertEqual(collection_with_point.interpolateAngle(0), 0) - collection_with_point = QgsGeometry.fromWkt('MultiPoint((0 -49), (10 10))') + collection_with_point = QgsGeometry.fromWkt("MultiPoint((0 -49), (10 10))") # no meaning, just test no crash! self.assertEqual(collection_with_point.interpolateAngle(5), 0) self.assertEqual(collection_with_point.interpolateAngle(0), 0) # linestring - linestring = QgsGeometry.fromWkt('LineString(0 0, 10 0, 20 10, 20 20, 10 20)') - self.assertAlmostEqual(linestring.interpolateAngle(0), math.radians(90), places=3) - self.assertAlmostEqual(linestring.interpolateAngle(5), math.radians(90), places=3) - self.assertAlmostEqual(linestring.interpolateAngle(10), math.radians(67.5), places=3) - self.assertAlmostEqual(linestring.interpolateAngle(15), math.radians(45), places=3) - self.assertAlmostEqual(linestring.interpolateAngle(25), math.radians(0), places=3) - self.assertAlmostEqual(linestring.interpolateAngle(35), math.radians(270), places=3) + linestring = QgsGeometry.fromWkt("LineString(0 0, 10 0, 20 10, 20 20, 10 20)") + self.assertAlmostEqual( + linestring.interpolateAngle(0), math.radians(90), places=3 + ) + self.assertAlmostEqual( + linestring.interpolateAngle(5), math.radians(90), places=3 + ) + self.assertAlmostEqual( + linestring.interpolateAngle(10), math.radians(67.5), places=3 + ) + self.assertAlmostEqual( + linestring.interpolateAngle(15), math.radians(45), places=3 + ) + self.assertAlmostEqual( + linestring.interpolateAngle(25), math.radians(0), places=3 + ) + self.assertAlmostEqual( + linestring.interpolateAngle(35), math.radians(270), places=3 + ) # test first and last points in a linestring - angle should be angle of # first/last segment - linestring = QgsGeometry.fromWkt('LineString(20 0, 10 0, 10 -10)') - self.assertAlmostEqual(linestring.interpolateAngle(0), math.radians(270), places=3) - self.assertAlmostEqual(linestring.interpolateAngle(20), math.radians(180), places=3) + linestring = QgsGeometry.fromWkt("LineString(20 0, 10 0, 10 -10)") + self.assertAlmostEqual( + linestring.interpolateAngle(0), math.radians(270), places=3 + ) + self.assertAlmostEqual( + linestring.interpolateAngle(20), math.radians(180), places=3 + ) # polygon - polygon = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 20 10, 20 20, 10 20, 0 0))') + polygon = QgsGeometry.fromWkt("Polygon((0 0, 10 0, 20 10, 20 20, 10 20, 0 0))") self.assertAlmostEqual(polygon.interpolateAngle(5), math.radians(90), places=3) - self.assertAlmostEqual(polygon.interpolateAngle(10), math.radians(67.5), places=3) + self.assertAlmostEqual( + polygon.interpolateAngle(10), math.radians(67.5), places=3 + ) self.assertAlmostEqual(polygon.interpolateAngle(15), math.radians(45), places=3) self.assertAlmostEqual(polygon.interpolateAngle(25), math.radians(0), places=3) - self.assertAlmostEqual(polygon.interpolateAngle(35), math.radians(270), places=3) + self.assertAlmostEqual( + polygon.interpolateAngle(35), math.radians(270), places=3 + ) # test first/last vertex in polygon - polygon = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 0 10, 0 0))') + polygon = QgsGeometry.fromWkt("Polygon((0 0, 10 0, 10 10, 0 10, 0 0))") self.assertAlmostEqual(polygon.interpolateAngle(0), math.radians(135), places=3) - self.assertAlmostEqual(polygon.interpolateAngle(40), math.radians(135), places=3) + self.assertAlmostEqual( + polygon.interpolateAngle(40), math.radians(135), places=3 + ) # circular string - geom = QgsGeometry.fromWkt('CircularString (1 5, 6 2, 7 3)') + geom = QgsGeometry.fromWkt("CircularString (1 5, 6 2, 7 3)") self.assertAlmostEqual(geom.interpolateAngle(5), 1.6919, places=3) def testInterpolate(self): - """ test QgsGeometry.interpolate() """ + """test QgsGeometry.interpolate()""" empty = QgsGeometry() # just test no crash self.assertFalse(empty.interpolate(5)) # not a linestring - point = QgsGeometry.fromWkt('Point(1 2)') # NOQA + point = QgsGeometry.fromWkt("Point(1 2)") # NOQA # no meaning, just test no crash! self.assertFalse(empty.interpolate(5)) # linestring - linestring = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10)') - exp = 'Point(5 0)' + linestring = QgsGeometry.fromWkt("LineString(0 0, 10 0, 10 10)") + exp = "Point(5 0)" result = linestring.interpolate(5).asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"Interpolate: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"Interpolate: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) self.assertTrue(linestring.interpolate(25).isNull()) # multilinestring - linestring = QgsGeometry.fromWkt('MultiLineString((0 0, 10 0, 10 10),(20 0, 30 0, 30 10))') - exp = 'Point(5 0)' + linestring = QgsGeometry.fromWkt( + "MultiLineString((0 0, 10 0, 10 10),(20 0, 30 0, 30 10))" + ) + exp = "Point(5 0)" result = linestring.interpolate(5).asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"Interpolate: mismatch Expected:\n{exp}\nGot:\n{result}\n") - exp = 'Point(10 5)' + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"Interpolate: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) + exp = "Point(10 5)" result = linestring.interpolate(15).asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"Interpolate: mismatch Expected:\n{exp}\nGot:\n{result}\n") - exp = 'Point(10 10)' + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"Interpolate: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) + exp = "Point(10 10)" result = linestring.interpolate(20).asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"Interpolate: mismatch Expected:\n{exp}\nGot:\n{result}\n") - exp = 'Point(25 0)' + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"Interpolate: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) + exp = "Point(25 0)" result = linestring.interpolate(25).asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"Interpolate: mismatch Expected:\n{exp}\nGot:\n{result}\n") - exp = 'Point(30 0)' + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"Interpolate: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) + exp = "Point(30 0)" result = linestring.interpolate(30).asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"Interpolate: mismatch Expected:\n{exp}\nGot:\n{result}\n") - exp = 'Point(30 5)' + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"Interpolate: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) + exp = "Point(30 5)" result = linestring.interpolate(35).asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"Interpolate: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"Interpolate: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) self.assertTrue(linestring.interpolate(50).isNull()) # polygon - polygon = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 20 20, 10 20, 0 0))') # NOQA - exp = 'Point(10 5)' + polygon = QgsGeometry.fromWkt( + "Polygon((0 0, 10 0, 10 10, 20 20, 10 20, 0 0))" + ) # NOQA + exp = "Point(10 5)" result = polygon.interpolate(15).asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"Interpolate: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"Interpolate: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) self.assertTrue(polygon.interpolate(68).isNull()) # polygon with ring polygon = QgsGeometry.fromWkt( - 'Polygon((0 0, 10 0, 10 10, 20 20, 10 20, 0 0),(5 5, 6 5, 6 6, 5 6, 5 5))') # NOQA - exp = 'Point (6 5.5)' + "Polygon((0 0, 10 0, 10 10, 20 20, 10 20, 0 0),(5 5, 6 5, 6 6, 5 6, 5 5))" + ) # NOQA + exp = "Point (6 5.5)" result = polygon.interpolate(68).asWkt() - self.assertTrue(compareWkt(result, exp, 0.1), - f"Interpolate: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.1), + f"Interpolate: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) def testAngleAtVertex(self): - """ test QgsGeometry.angleAtVertex """ + """test QgsGeometry.angleAtVertex""" empty = QgsGeometry() # just test no crash self.assertEqual(empty.angleAtVertex(0), 0) # not a linestring - point = QgsGeometry.fromWkt('Point(1 2)') + point = QgsGeometry.fromWkt("Point(1 2)") # no meaning, just test no crash! self.assertEqual(point.angleAtVertex(0), 0) # linestring - linestring = QgsGeometry.fromWkt('LineString(0 0, 10 0, 20 10, 20 20, 10 20)') - self.assertAlmostEqual(linestring.angleAtVertex(1), math.radians(67.5), places=3) - self.assertAlmostEqual(linestring.angleAtVertex(2), math.radians(22.5), places=3) - self.assertAlmostEqual(linestring.angleAtVertex(3), math.radians(315.0), places=3) + linestring = QgsGeometry.fromWkt("LineString(0 0, 10 0, 20 10, 20 20, 10 20)") + self.assertAlmostEqual( + linestring.angleAtVertex(1), math.radians(67.5), places=3 + ) + self.assertAlmostEqual( + linestring.angleAtVertex(2), math.radians(22.5), places=3 + ) + self.assertAlmostEqual( + linestring.angleAtVertex(3), math.radians(315.0), places=3 + ) self.assertAlmostEqual(linestring.angleAtVertex(5), 0, places=3) self.assertAlmostEqual(linestring.angleAtVertex(-1), 0, places=3) # test first and last points in a linestring - angle should be angle of # first/last segment - linestring = QgsGeometry.fromWkt('LineString(20 0, 10 0, 10 -10)') + linestring = QgsGeometry.fromWkt("LineString(20 0, 10 0, 10 -10)") self.assertAlmostEqual(linestring.angleAtVertex(0), math.radians(270), places=3) self.assertAlmostEqual(linestring.angleAtVertex(2), math.radians(180), places=3) # closed linestring - angle at first/last vertex should be average angle linestring = QgsGeometry.fromWkt( - 'LineString (-1007697 1334641, -1007697 1334643, -1007695 1334643, -1007695 1334641, -1007696 1334641, -1007697 1334641)') + "LineString (-1007697 1334641, -1007697 1334643, -1007695 1334643, -1007695 1334641, -1007696 1334641, -1007697 1334641)" + ) self.assertAlmostEqual(linestring.angleAtVertex(0), math.radians(315), places=3) self.assertAlmostEqual(linestring.angleAtVertex(5), math.radians(315), places=3) # polygon - polygon = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 0 10, 0 0))') + polygon = QgsGeometry.fromWkt("Polygon((0 0, 10 0, 10 10, 0 10, 0 0))") self.assertAlmostEqual(polygon.angleAtVertex(0), math.radians(135.0), places=3) self.assertAlmostEqual(polygon.angleAtVertex(1), math.radians(45.0), places=3) self.assertAlmostEqual(polygon.angleAtVertex(2), math.radians(315.0), places=3) @@ -5644,61 +10151,83 @@ def testAngleAtVertex(self): self.assertAlmostEqual(polygon.angleAtVertex(4), math.radians(135.0), places=3) def testExtendLine(self): - """ test QgsGeometry.extendLine """ + """test QgsGeometry.extendLine""" empty = QgsGeometry() self.assertFalse(empty.extendLine(1, 2)) # not a linestring - point = QgsGeometry.fromWkt('Point(1 2)') + point = QgsGeometry.fromWkt("Point(1 2)") self.assertFalse(point.extendLine(1, 2)) # linestring - linestring = QgsGeometry.fromWkt('LineString(0 0, 1 0, 1 1)') + linestring = QgsGeometry.fromWkt("LineString(0 0, 1 0, 1 1)") extended = linestring.extendLine(1, 2) - exp = 'LineString(-1 0, 1 0, 1 3)' + exp = "LineString(-1 0, 1 0, 1 3)" result = extended.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"Extend line: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"Extend line: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) expbb = QgsRectangle(-1, 0, 1, 3) bb = extended.boundingBox() - self.assertEqual(expbb, bb, f"Extend line: bbox Expected:\n{expbb.toString()}\nGot:\n{bb.toString()}\n") + self.assertEqual( + expbb, + bb, + f"Extend line: bbox Expected:\n{expbb.toString()}\nGot:\n{bb.toString()}\n", + ) # multilinestring - multilinestring = QgsGeometry.fromWkt('MultiLineString((0 0, 1 0, 1 1),(11 11, 11 10, 10 10))') + multilinestring = QgsGeometry.fromWkt( + "MultiLineString((0 0, 1 0, 1 1),(11 11, 11 10, 10 10))" + ) extended = multilinestring.extendLine(1, 2) - exp = 'MultiLineString((-1 0, 1 0, 1 3),(11 12, 11 10, 8 10))' + exp = "MultiLineString((-1 0, 1 0, 1 3),(11 12, 11 10, 8 10))" result = extended.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"Extend multiline: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"Extend multiline: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) expbb = QgsRectangle(-1, 0, 11, 12) bb = extended.boundingBox() - self.assertEqual(expbb, bb, f"Extend multiline: bbox Expected:\n{expbb.toString()}\nGot:\n{bb.toString()}\n") + self.assertEqual( + expbb, + bb, + f"Extend multiline: bbox Expected:\n{expbb.toString()}\nGot:\n{bb.toString()}\n", + ) def testRemoveRings(self): empty = QgsGeometry() self.assertFalse(empty.removeInteriorRings()) # not a polygon - point = QgsGeometry.fromWkt('Point(1 2)') + point = QgsGeometry.fromWkt("Point(1 2)") self.assertFalse(point.removeInteriorRings()) # polygon - polygon = QgsGeometry.fromWkt('Polygon((0 0, 1 0, 1 1, 0 0),(0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1))') + polygon = QgsGeometry.fromWkt( + "Polygon((0 0, 1 0, 1 1, 0 0),(0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1))" + ) removed = polygon.removeInteriorRings() - exp = 'Polygon((0 0, 1 0, 1 1, 0 0))' + exp = "Polygon((0 0, 1 0, 1 1, 0 0))" result = removed.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"Extend line: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"Extend line: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) # multipolygon - multipolygon = QgsGeometry.fromWkt('MultiPolygon(((0 0, 1 0, 1 1, 0 0),(0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1)),' - '((10 0, 11 0, 11 1, 10 0),(10.1 10.1, 10.2 0.1, 10.2 0.2, 10.1 0.1)))') + multipolygon = QgsGeometry.fromWkt( + "MultiPolygon(((0 0, 1 0, 1 1, 0 0),(0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1))," + "((10 0, 11 0, 11 1, 10 0),(10.1 10.1, 10.2 0.1, 10.2 0.2, 10.1 0.1)))" + ) removed = multipolygon.removeInteriorRings() - exp = 'MultiPolygon(((0 0, 1 0, 1 1, 0 0)),((10 0, 11 0, 11 1, 10 0)))' + exp = "MultiPolygon(((0 0, 1 0, 1 1, 0 0)),((10 0, 11 0, 11 1, 10 0)))" result = removed.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"Extend line: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"Extend line: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) def testMinimumOrientedBoundingBox(self): empty = QgsGeometry() @@ -5706,18 +10235,22 @@ def testMinimumOrientedBoundingBox(self): self.assertFalse(bbox) # not a useful geometry - point = QgsGeometry.fromWkt('Point(1 2)') + point = QgsGeometry.fromWkt("Point(1 2)") bbox, area, angle, width, height = point.orientedMinimumBoundingBox() self.assertFalse(bbox) # polygon - polygon = QgsGeometry.fromWkt('Polygon((-0.1 -1.3, 2.1 1, 3 2.8, 6.7 0.2, 3 -1.8, 0.3 -2.7, -0.1 -1.3))') + polygon = QgsGeometry.fromWkt( + "Polygon((-0.1 -1.3, 2.1 1, 3 2.8, 6.7 0.2, 3 -1.8, 0.3 -2.7, -0.1 -1.3))" + ) bbox, area, angle, width, height = polygon.orientedMinimumBoundingBox() - exp = 'Polygon ((-0.628 -1.9983, 2.9769 -4.724, 6.7 0.2, 3.095 2.9257, -0.628 -1.9983))' + exp = "Polygon ((-0.628 -1.9983, 2.9769 -4.724, 6.7 0.2, 3.095 2.9257, -0.628 -1.9983))" result = bbox.asWkt(4) - self.assertTrue(compareWkt(result, exp, 0.00001), - f"Oriented MBBR: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"Oriented MBBR: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) self.assertAlmostEqual(area, 27.89886071158214, places=3) self.assertAlmostEqual(angle, 37.09283729704157, places=3) self.assertAlmostEqual(width, 4.519421040409892, places=3) @@ -5729,55 +10262,69 @@ def testOrthogonalize(self): self.assertFalse(o) # not a useful geometry - point = QgsGeometry.fromWkt('Point(1 2)') + point = QgsGeometry.fromWkt("Point(1 2)") o = point.orthogonalize() self.assertFalse(o) # polygon - polygon = QgsGeometry.fromWkt('Polygon((-0.699 0.892, -0.703 0.405, -0.022 0.361, 0.014 0.851, -0.699 0.892))') + polygon = QgsGeometry.fromWkt( + "Polygon((-0.699 0.892, -0.703 0.405, -0.022 0.361, 0.014 0.851, -0.699 0.892))" + ) o = polygon.orthogonalize() - exp = 'Polygon ((-0.69899999999999995 0.89200000000000002, -0.72568713635737736 0.38414056283699533, -0.00900222326098143 0.34648000752227009, 0.01768491457044956 0.85433944198378253, -0.69899999999999995 0.89200000000000002))' + exp = "Polygon ((-0.69899999999999995 0.89200000000000002, -0.72568713635737736 0.38414056283699533, -0.00900222326098143 0.34648000752227009, 0.01768491457044956 0.85433944198378253, -0.69899999999999995 0.89200000000000002))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"orthogonalize: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"orthogonalize: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) # polygon with ring polygon = QgsGeometry.fromWkt( - 'Polygon ((-0.698 0.892, -0.702 0.405, -0.022 0.360, 0.014 0.850, -0.698 0.892),(-0.619 0.777, -0.619 0.574, -0.515 0.567, -0.517 0.516, -0.411 0.499, -0.379 0.767, -0.619 0.777),(-0.322 0.506, -0.185 0.735, -0.046 0.428, -0.322 0.506))') + "Polygon ((-0.698 0.892, -0.702 0.405, -0.022 0.360, 0.014 0.850, -0.698 0.892),(-0.619 0.777, -0.619 0.574, -0.515 0.567, -0.517 0.516, -0.411 0.499, -0.379 0.767, -0.619 0.777),(-0.322 0.506, -0.185 0.735, -0.046 0.428, -0.322 0.506))" + ) o = polygon.orthogonalize() - exp = 'Polygon ((-0.69799999999999995 0.89200000000000002, -0.72515703079591087 0.38373993222914216, -0.00901577368860811 0.34547552423418099, 0.01814125858957143 0.85373558928902782, -0.69799999999999995 0.89200000000000002),(-0.61899999999999999 0.77700000000000002, -0.63403125159063511 0.56020458713735533, -0.53071476068518508 0.55304126003523246, -0.5343108192220235 0.5011754225601015, -0.40493624158682306 0.49220537936424585, -0.3863089084840608 0.76086661681561074, -0.61899999999999999 0.77700000000000002),(-0.32200000000000001 0.50600000000000001, -0.185 0.73499999999999999, -0.046 0.42799999999999999, -0.32200000000000001 0.50600000000000001))' + exp = "Polygon ((-0.69799999999999995 0.89200000000000002, -0.72515703079591087 0.38373993222914216, -0.00901577368860811 0.34547552423418099, 0.01814125858957143 0.85373558928902782, -0.69799999999999995 0.89200000000000002),(-0.61899999999999999 0.77700000000000002, -0.63403125159063511 0.56020458713735533, -0.53071476068518508 0.55304126003523246, -0.5343108192220235 0.5011754225601015, -0.40493624158682306 0.49220537936424585, -0.3863089084840608 0.76086661681561074, -0.61899999999999999 0.77700000000000002),(-0.32200000000000001 0.50600000000000001, -0.185 0.73499999999999999, -0.046 0.42799999999999999, -0.32200000000000001 0.50600000000000001))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"orthogonalize: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"orthogonalize: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) # multipolygon polygon = QgsGeometry.fromWkt( - 'MultiPolygon(((-0.550 -1.553, -0.182 -0.954, -0.182 -0.954, 0.186 -1.538, -0.550 -1.553)),' - '((0.506 -1.376, 0.433 -1.081, 0.765 -0.900, 0.923 -1.132, 0.923 -1.391, 0.506 -1.376)))') + "MultiPolygon(((-0.550 -1.553, -0.182 -0.954, -0.182 -0.954, 0.186 -1.538, -0.550 -1.553))," + "((0.506 -1.376, 0.433 -1.081, 0.765 -0.900, 0.923 -1.132, 0.923 -1.391, 0.506 -1.376)))" + ) o = polygon.orthogonalize() - exp = 'MultiPolygon (((-0.55000000000000004 -1.55299999999999994, -0.182 -0.95399999999999996, -0.182 -0.95399999999999996, 0.186 -1.53800000000000003, -0.55000000000000004 -1.55299999999999994)),((0.50600000000000001 -1.37599999999999989, 0.34888970623957499 -1.04704644438350125, 0.78332709454235683 -0.83955640656085295, 0.92300000000000004 -1.1319999999999999, 0.91737248858460974 -1.38514497083566535, 0.50600000000000001 -1.37599999999999989)))' + exp = "MultiPolygon (((-0.55000000000000004 -1.55299999999999994, -0.182 -0.95399999999999996, -0.182 -0.95399999999999996, 0.186 -1.53800000000000003, -0.55000000000000004 -1.55299999999999994)),((0.50600000000000001 -1.37599999999999989, 0.34888970623957499 -1.04704644438350125, 0.78332709454235683 -0.83955640656085295, 0.92300000000000004 -1.1319999999999999, 0.91737248858460974 -1.38514497083566535, 0.50600000000000001 -1.37599999999999989)))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"orthogonalize: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"orthogonalize: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) # line line = QgsGeometry.fromWkt( - 'LineString (-1.07445631048298162 -0.91619958829825165, 0.04022568180912156 -0.95572731852137571, 0.04741254184968957 -0.61794489661467789, 0.68704308546024517 -0.66106605685808595)') + "LineString (-1.07445631048298162 -0.91619958829825165, 0.04022568180912156 -0.95572731852137571, 0.04741254184968957 -0.61794489661467789, 0.68704308546024517 -0.66106605685808595)" + ) o = line.orthogonalize() - exp = 'LineString (-1.07445631048298162 -0.91619958829825165, 0.04812855116470245 -0.96433184892270418, 0.06228000950284909 -0.63427853851139493, 0.68704308546024517 -0.66106605685808595)' + exp = "LineString (-1.07445631048298162 -0.91619958829825165, 0.04812855116470245 -0.96433184892270418, 0.06228000950284909 -0.63427853851139493, 0.68704308546024517 -0.66106605685808595)" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"orthogonalize: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"orthogonalize: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) # already orthogonal polygon with a vertex on a "straight line" (https://github.com/qgis/QGIS/issues/49621) - polygon = QgsGeometry.fromWkt( - 'Polygon ((0 0, 5 0, 10 0, 10 10, 0 10, 0 0))') + polygon = QgsGeometry.fromWkt("Polygon ((0 0, 5 0, 10 0, 10 10, 0 10, 0 0))") o = polygon.orthogonalize() - exp = 'Polygon ((0 0, 5 0, 10 0, 10 10, 0 10, 0 0))' + exp = "Polygon ((0 0, 5 0, 10 0, 10 10, 0 10, 0 0))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"orthogonalize: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"orthogonalize: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) def testPolygonize(self): o = QgsGeometry.polygonize([]) @@ -5785,7 +10332,7 @@ def testPolygonize(self): empty = QgsGeometry() o = QgsGeometry.polygonize([empty]) self.assertFalse(o) - line = QgsGeometry.fromWkt('LineString EMPTY') + line = QgsGeometry.fromWkt("LineString EMPTY") o = QgsGeometry.polygonize([line]) self.assertFalse(o) @@ -5794,27 +10341,33 @@ def testPolygonize(self): o = QgsGeometry.polygonize([l1, l2]) exp = "GeometryCollection(POLYGON ((100 180, 160 20, 20 20, 100 180), (100 180, 80 60, 120 60, 100 180)),POLYGON ((100 180, 120 60, 80 60, 100 180)))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"polygonize: mismatch Expected:\n{exp}\nGot:\n{result}\n") - - lines = [QgsGeometry.fromWkt('LineString(0 0, 1 1)'), - QgsGeometry.fromWkt('LineString(0 0, 0 1)'), - QgsGeometry.fromWkt('LineString(0 1, 1 1)'), - QgsGeometry.fromWkt('LineString(1 1, 1 0)'), - QgsGeometry.fromWkt('LineString(1 0, 0 0)'), - QgsGeometry.fromWkt('LineString(5 5, 6 6)'), - QgsGeometry.fromWkt('Point(0, 0)')] + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"polygonize: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) + + lines = [ + QgsGeometry.fromWkt("LineString(0 0, 1 1)"), + QgsGeometry.fromWkt("LineString(0 0, 0 1)"), + QgsGeometry.fromWkt("LineString(0 1, 1 1)"), + QgsGeometry.fromWkt("LineString(1 1, 1 0)"), + QgsGeometry.fromWkt("LineString(1 0, 0 0)"), + QgsGeometry.fromWkt("LineString(5 5, 6 6)"), + QgsGeometry.fromWkt("Point(0, 0)"), + ] o = QgsGeometry.polygonize(lines) exp = "GeometryCollection (Polygon ((0 0, 1 1, 1 0, 0 0)),Polygon ((1 1, 0 0, 0 1, 1 1)))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"polygonize: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"polygonize: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) def testDelaunayTriangulation(self): empty = QgsGeometry() o = empty.delaunayTriangulation() self.assertFalse(o) - line = QgsGeometry.fromWkt('LineString EMPTY') + line = QgsGeometry.fromWkt("LineString EMPTY") o = line.delaunayTriangulation() self.assertFalse(o) @@ -5822,81 +10375,86 @@ def testDelaunayTriangulation(self): o = input.delaunayTriangulation() o.normalize() self.assertEqual( - o.asWkt(5), - "GeometryCollection (Polygon ((10 10, 10 20, 20 20, 10 10)))") + o.asWkt(5), "GeometryCollection (Polygon ((10 10, 10 20, 20 20, 10 10)))" + ) o = input.delaunayTriangulation(0, True) o.normalize() self.assertEqual( - o.asWkt(5), - "MultiLineString ((10 20, 20 20),(10 10, 20 20),(10 10, 10 20))" + o.asWkt(5), "MultiLineString ((10 20, 20 20),(10 10, 20 20),(10 10, 10 20))" ) input = QgsGeometry.fromWkt( - "MULTIPOINT ((50 40), (140 70), (80 100), (130 140), (30 150), (70 180), (190 110), (120 20))") + "MULTIPOINT ((50 40), (140 70), (80 100), (130 140), (30 150), (70 180), (190 110), (120 20))" + ) o = input.delaunayTriangulation() o.normalize() self.assertEqual( o.asWkt(5), - "GeometryCollection (Polygon ((130 140, 190 110, 140 70, 130 140)),Polygon ((120 20, 140 70, 190 110, 120 20)),Polygon ((80 100, 140 70, 120 20, 80 100)),Polygon ((80 100, 130 140, 140 70, 80 100)),Polygon ((70 180, 190 110, 130 140, 70 180)),Polygon ((70 180, 130 140, 80 100, 70 180)),Polygon ((50 40, 80 100, 120 20, 50 40)),Polygon ((30 150, 80 100, 50 40, 30 150)),Polygon ((30 150, 70 180, 80 100, 30 150)))" + "GeometryCollection (Polygon ((130 140, 190 110, 140 70, 130 140)),Polygon ((120 20, 140 70, 190 110, 120 20)),Polygon ((80 100, 140 70, 120 20, 80 100)),Polygon ((80 100, 130 140, 140 70, 80 100)),Polygon ((70 180, 190 110, 130 140, 70 180)),Polygon ((70 180, 130 140, 80 100, 70 180)),Polygon ((50 40, 80 100, 120 20, 50 40)),Polygon ((30 150, 80 100, 50 40, 30 150)),Polygon ((30 150, 70 180, 80 100, 30 150)))", ) o = input.delaunayTriangulation(0, True) o.normalize() self.assertEqual( o.asWkt(5), - "MultiLineString ((140 70, 190 110),(130 140, 190 110),(130 140, 140 70),(120 20, 190 110),(120 20, 140 70),(80 100, 140 70),(80 100, 130 140),(80 100, 120 20),(70 180, 190 110),(70 180, 130 140),(70 180, 80 100),(50 40, 120 20),(50 40, 80 100),(30 150, 80 100),(30 150, 70 180),(30 150, 50 40))" + "MultiLineString ((140 70, 190 110),(130 140, 190 110),(130 140, 140 70),(120 20, 190 110),(120 20, 140 70),(80 100, 140 70),(80 100, 130 140),(80 100, 120 20),(70 180, 190 110),(70 180, 130 140),(70 180, 80 100),(50 40, 120 20),(50 40, 80 100),(30 150, 80 100),(30 150, 70 180),(30 150, 50 40))", ) input = QgsGeometry.fromWkt( - "MULTIPOINT ((10 10), (10 20), (20 20), (20 10), (20 0), (10 0), (0 0), (0 10), (0 20))") + "MULTIPOINT ((10 10), (10 20), (20 20), (20 10), (20 0), (10 0), (0 0), (0 10), (0 20))" + ) o = input.delaunayTriangulation() o.normalize() self.assertEqual( o.asWkt(5), - "GeometryCollection (Polygon ((10 20, 20 20, 20 10, 10 20)),Polygon ((10 10, 20 10, 20 0, 10 10)),Polygon ((10 10, 10 20, 20 10, 10 10)),Polygon ((10 0, 10 10, 20 0, 10 0)),Polygon ((0 20, 10 20, 10 10, 0 20)),Polygon ((0 10, 10 10, 10 0, 0 10)),Polygon ((0 10, 0 20, 10 10, 0 10)),Polygon ((0 0, 0 10, 10 0, 0 0)))" + "GeometryCollection (Polygon ((10 20, 20 20, 20 10, 10 20)),Polygon ((10 10, 20 10, 20 0, 10 10)),Polygon ((10 10, 10 20, 20 10, 10 10)),Polygon ((10 0, 10 10, 20 0, 10 0)),Polygon ((0 20, 10 20, 10 10, 0 20)),Polygon ((0 10, 10 10, 10 0, 0 10)),Polygon ((0 10, 0 20, 10 10, 0 10)),Polygon ((0 0, 0 10, 10 0, 0 0)))", ) o = input.delaunayTriangulation(0, True) o.normalize() self.assertEqual( o.asWkt(5), - "MultiLineString ((20 10, 20 20),(20 0, 20 10),(10 20, 20 20),(10 20, 20 10),(10 10, 20 10),(10 10, 20 0),(10 10, 10 20),(10 0, 20 0),(10 0, 10 10),(0 20, 10 20),(0 20, 10 10),(0 10, 10 10),(0 10, 10 0),(0 10, 0 20),(0 0, 10 0),(0 0, 0 10))" + "MultiLineString ((20 10, 20 20),(20 0, 20 10),(10 20, 20 20),(10 20, 20 10),(10 10, 20 10),(10 10, 20 0),(10 10, 10 20),(10 0, 20 0),(10 0, 10 10),(0 20, 10 20),(0 20, 10 10),(0 10, 10 10),(0 10, 10 0),(0 10, 0 20),(0 0, 10 0),(0 0, 0 10))", ) input = QgsGeometry.fromWkt( - "POLYGON ((42 30, 41.96 29.61, 41.85 29.23, 41.66 28.89, 41.41 28.59, 41.11 28.34, 40.77 28.15, 40.39 28.04, 40 28, 39.61 28.04, 39.23 28.15, 38.89 28.34, 38.59 28.59, 38.34 28.89, 38.15 29.23, 38.04 29.61, 38 30, 38.04 30.39, 38.15 30.77, 38.34 31.11, 38.59 31.41, 38.89 31.66, 39.23 31.85, 39.61 31.96, 40 32, 40.39 31.96, 40.77 31.85, 41.11 31.66, 41.41 31.41, 41.66 31.11, 41.85 30.77, 41.96 30.39, 42 30))") + "POLYGON ((42 30, 41.96 29.61, 41.85 29.23, 41.66 28.89, 41.41 28.59, 41.11 28.34, 40.77 28.15, 40.39 28.04, 40 28, 39.61 28.04, 39.23 28.15, 38.89 28.34, 38.59 28.59, 38.34 28.89, 38.15 29.23, 38.04 29.61, 38 30, 38.04 30.39, 38.15 30.77, 38.34 31.11, 38.59 31.41, 38.89 31.66, 39.23 31.85, 39.61 31.96, 40 32, 40.39 31.96, 40.77 31.85, 41.11 31.66, 41.41 31.41, 41.66 31.11, 41.85 30.77, 41.96 30.39, 42 30))" + ) o = input.delaunayTriangulation(0, True) o.normalize() self.assertEqual( o.asWkt(2), - "MultiLineString ((41.96 30.39, 42 30),(41.96 29.61, 42 30),(41.96 29.61, 41.96 30.39),(41.85 30.77, 41.96 30.39),(41.85 29.23, 41.96 29.61),(41.66 31.11, 41.96 30.39),(41.66 31.11, 41.85 30.77),(41.66 28.89, 41.96 29.61),(41.66 28.89, 41.85 29.23),(41.41 31.41, 41.96 30.39),(41.41 31.41, 41.96 29.61),(41.41 31.41, 41.66 31.11),(41.41 28.59, 41.96 29.61),(41.41 28.59, 41.66 28.89),(41.41 28.59, 41.41 31.41),(41.11 31.66, 41.41 31.41),(41.11 28.34, 41.41 28.59),(40.77 31.85, 41.11 31.66),(40.77 28.15, 41.11 28.34),(40.39 31.96, 41.41 31.41),(40.39 31.96, 41.11 31.66),(40.39 31.96, 40.77 31.85),(40.39 28.04, 41.41 28.59),(40.39 28.04, 41.11 28.34),(40.39 28.04, 40.77 28.15),(40 32, 40.39 31.96),(40 28, 40.39 28.04),(39.61 31.96, 40.39 31.96),(39.61 31.96, 40 32),(39.61 28.04, 40.39 28.04),(39.61 28.04, 40 28),(39.23 31.85, 39.61 31.96),(39.23 28.15, 39.61 28.04),(38.89 31.66, 39.61 31.96),(38.89 31.66, 39.23 31.85),(38.89 28.34, 39.61 28.04),(38.89 28.34, 39.23 28.15),(38.59 31.41, 41.41 31.41),(38.59 31.41, 41.41 28.59),(38.59 31.41, 40.39 31.96),(38.59 31.41, 39.61 31.96),(38.59 31.41, 38.89 31.66),(38.59 28.59, 41.41 28.59),(38.59 28.59, 40.39 28.04),(38.59 28.59, 39.61 28.04),(38.59 28.59, 38.89 28.34),(38.59 28.59, 38.59 31.41),(38.34 31.11, 38.59 31.41),(38.34 28.89, 38.59 28.59),(38.15 30.77, 38.34 31.11),(38.15 29.23, 38.34 28.89),(38.04 30.39, 38.59 31.41),(38.04 30.39, 38.34 31.11),(38.04 30.39, 38.15 30.77),(38.04 29.61, 38.59 31.41),(38.04 29.61, 38.59 28.59),(38.04 29.61, 38.34 28.89),(38.04 29.61, 38.15 29.23),(38.04 29.61, 38.04 30.39),(38 30, 38.04 30.39),(38 30, 38.04 29.61))" + "MultiLineString ((41.96 30.39, 42 30),(41.96 29.61, 42 30),(41.96 29.61, 41.96 30.39),(41.85 30.77, 41.96 30.39),(41.85 29.23, 41.96 29.61),(41.66 31.11, 41.96 30.39),(41.66 31.11, 41.85 30.77),(41.66 28.89, 41.96 29.61),(41.66 28.89, 41.85 29.23),(41.41 31.41, 41.96 30.39),(41.41 31.41, 41.96 29.61),(41.41 31.41, 41.66 31.11),(41.41 28.59, 41.96 29.61),(41.41 28.59, 41.66 28.89),(41.41 28.59, 41.41 31.41),(41.11 31.66, 41.41 31.41),(41.11 28.34, 41.41 28.59),(40.77 31.85, 41.11 31.66),(40.77 28.15, 41.11 28.34),(40.39 31.96, 41.41 31.41),(40.39 31.96, 41.11 31.66),(40.39 31.96, 40.77 31.85),(40.39 28.04, 41.41 28.59),(40.39 28.04, 41.11 28.34),(40.39 28.04, 40.77 28.15),(40 32, 40.39 31.96),(40 28, 40.39 28.04),(39.61 31.96, 40.39 31.96),(39.61 31.96, 40 32),(39.61 28.04, 40.39 28.04),(39.61 28.04, 40 28),(39.23 31.85, 39.61 31.96),(39.23 28.15, 39.61 28.04),(38.89 31.66, 39.61 31.96),(38.89 31.66, 39.23 31.85),(38.89 28.34, 39.61 28.04),(38.89 28.34, 39.23 28.15),(38.59 31.41, 41.41 31.41),(38.59 31.41, 41.41 28.59),(38.59 31.41, 40.39 31.96),(38.59 31.41, 39.61 31.96),(38.59 31.41, 38.89 31.66),(38.59 28.59, 41.41 28.59),(38.59 28.59, 40.39 28.04),(38.59 28.59, 39.61 28.04),(38.59 28.59, 38.89 28.34),(38.59 28.59, 38.59 31.41),(38.34 31.11, 38.59 31.41),(38.34 28.89, 38.59 28.59),(38.15 30.77, 38.34 31.11),(38.15 29.23, 38.34 28.89),(38.04 30.39, 38.59 31.41),(38.04 30.39, 38.34 31.11),(38.04 30.39, 38.15 30.77),(38.04 29.61, 38.59 31.41),(38.04 29.61, 38.59 28.59),(38.04 29.61, 38.34 28.89),(38.04 29.61, 38.15 29.23),(38.04 29.61, 38.04 30.39),(38 30, 38.04 30.39),(38 30, 38.04 29.61))", ) input = QgsGeometry.fromWkt( - "POLYGON ((0 0, 0 200, 180 200, 180 0, 0 0), (20 180, 160 180, 160 20, 152.625 146.75, 20 180), (30 160, 150 30, 70 90, 30 160))") + "POLYGON ((0 0, 0 200, 180 200, 180 0, 0 0), (20 180, 160 180, 160 20, 152.625 146.75, 20 180), (30 160, 150 30, 70 90, 30 160))" + ) o = input.delaunayTriangulation(0, True) o.normalize() self.assertEqual( o.asWkt(5), - "MultiLineString ((180 0, 180 200),(160 180, 180 200),(160 20, 180 0),(152.625 146.75, 180 200),(152.625 146.75, 180 0),(152.625 146.75, 160 180),(152.625 146.75, 160 20),(150 30, 160 20),(150 30, 152.625 146.75),(70 90, 152.625 146.75),(70 90, 150 30),(30 160, 160 180),(30 160, 152.625 146.75),(30 160, 70 90),(20 180, 160 180),(20 180, 30 160),(0 200, 180 200),(0 200, 160 180),(0 200, 30 160),(0 200, 20 180),(0 0, 180 0),(0 0, 160 20),(0 0, 150 30),(0 0, 70 90),(0 0, 30 160),(0 0, 0 200))" + "MultiLineString ((180 0, 180 200),(160 180, 180 200),(160 20, 180 0),(152.625 146.75, 180 200),(152.625 146.75, 180 0),(152.625 146.75, 160 180),(152.625 146.75, 160 20),(150 30, 160 20),(150 30, 152.625 146.75),(70 90, 152.625 146.75),(70 90, 150 30),(30 160, 160 180),(30 160, 152.625 146.75),(30 160, 70 90),(20 180, 160 180),(20 180, 30 160),(0 200, 180 200),(0 200, 160 180),(0 200, 30 160),(0 200, 20 180),(0 0, 180 0),(0 0, 160 20),(0 0, 150 30),(0 0, 70 90),(0 0, 30 160),(0 0, 0 200))", ) input = QgsGeometry.fromWkt( - "MULTIPOINT ((10 10 1), (10 20 2), (20 20 3), (20 10 1.5), (20 0 2.5), (10 0 3.5), (0 0 0), (0 10 .5), (0 20 .25))") + "MULTIPOINT ((10 10 1), (10 20 2), (20 20 3), (20 10 1.5), (20 0 2.5), (10 0 3.5), (0 0 0), (0 10 .5), (0 20 .25))" + ) o = input.delaunayTriangulation() o.normalize() self.assertEqual( o.asWkt(5), - "GeometryCollection (Polygon Z ((10 20 2, 20 20 3, 20 10 1.5, 10 20 2)),Polygon Z ((10 10 1, 20 10 1.5, 20 0 2.5, 10 10 1)),Polygon Z ((10 10 1, 10 20 2, 20 10 1.5, 10 10 1)),Polygon Z ((10 0 3.5, 10 10 1, 20 0 2.5, 10 0 3.5)),Polygon Z ((0 20 0.25, 10 20 2, 10 10 1, 0 20 0.25)),Polygon Z ((0 10 0.5, 10 10 1, 10 0 3.5, 0 10 0.5)),Polygon Z ((0 10 0.5, 0 20 0.25, 10 10 1, 0 10 0.5)),Polygon Z ((0 0 0, 0 10 0.5, 10 0 3.5, 0 0 0)))" + "GeometryCollection (Polygon Z ((10 20 2, 20 20 3, 20 10 1.5, 10 20 2)),Polygon Z ((10 10 1, 20 10 1.5, 20 0 2.5, 10 10 1)),Polygon Z ((10 10 1, 10 20 2, 20 10 1.5, 10 10 1)),Polygon Z ((10 0 3.5, 10 10 1, 20 0 2.5, 10 0 3.5)),Polygon Z ((0 20 0.25, 10 20 2, 10 10 1, 0 20 0.25)),Polygon Z ((0 10 0.5, 10 10 1, 10 0 3.5, 0 10 0.5)),Polygon Z ((0 10 0.5, 0 20 0.25, 10 10 1, 0 10 0.5)),Polygon Z ((0 0 0, 0 10 0.5, 10 0 3.5, 0 0 0)))", ) o = input.delaunayTriangulation(0, True) o.normalize() self.assertEqual( o.asWkt(5), - "MultiLineString Z ((20 10 1.5, 20 20 3),(20 0 2.5, 20 10 1.5),(10 20 2, 20 20 3),(10 20 2, 20 10 1.5),(10 10 1, 20 10 1.5),(10 10 1, 20 0 2.5),(10 10 1, 10 20 2),(10 0 3.5, 20 0 2.5),(10 0 3.5, 10 10 1),(0 20 0.25, 10 20 2),(0 20 0.25, 10 10 1),(0 10 0.5, 10 10 1),(0 10 0.5, 10 0 3.5),(0 10 0.5, 0 20 0.25),(0 0 0, 10 0 3.5),(0 0 0, 0 10 0.5))" + "MultiLineString Z ((20 10 1.5, 20 20 3),(20 0 2.5, 20 10 1.5),(10 20 2, 20 20 3),(10 20 2, 20 10 1.5),(10 10 1, 20 10 1.5),(10 10 1, 20 0 2.5),(10 10 1, 10 20 2),(10 0 3.5, 20 0 2.5),(10 0 3.5, 10 10 1),(0 20 0.25, 10 20 2),(0 20 0.25, 10 10 1),(0 10 0.5, 10 10 1),(0 10 0.5, 10 0 3.5),(0 10 0.5, 0 20 0.25),(0 0 0, 10 0 3.5),(0 0 0, 0 10 0.5))", ) input = QgsGeometry.fromWkt( - "MULTIPOINT((-118.3964065 56.0557),(-118.396406 56.0475),(-118.396407 56.04),(-118.3968 56))") + "MULTIPOINT((-118.3964065 56.0557),(-118.396406 56.0475),(-118.396407 56.04),(-118.3968 56))" + ) o = input.delaunayTriangulation(0.001, True) o.normalize() # Delaunay Triangulation computation change. See: https://github.com/libgeos/geos/pull/728 @@ -5904,15 +10462,15 @@ def testDelaunayTriangulation(self): o.asWkt(5), ( "MultiLineString ((-118.39641 56.0557, -118.39641 56.0475),(-118.39641 56.04, -118.39641 56.0475),(-118.3968 56, -118.39641 56.0475),(-118.3968 56, -118.39641 56.0557),(-118.3968 56, -118.39641 56.04))", - "MultiLineString ((-118.39641 56.0557, -118.39641 56.0475),(-118.39641 56.04, -118.39641 56.0475),(-118.3968 56, -118.39641 56.04))" - ) + "MultiLineString ((-118.39641 56.0557, -118.39641 56.0475),(-118.39641 56.04, -118.39641 56.0475),(-118.3968 56, -118.39641 56.04))", + ), ) def testVoronoi(self): empty = QgsGeometry() o = empty.voronoiDiagram() self.assertFalse(o) - line = QgsGeometry.fromWkt('LineString EMPTY') + line = QgsGeometry.fromWkt("LineString EMPTY") o = line.voronoiDiagram() self.assertFalse(o) @@ -5927,72 +10485,94 @@ def testVoronoi(self): else: exp = "GeometryCollection (Polygon ((170.02400000000000091 38, 25 38, 25 295, 221.20588235294115975 210.91176470588234793, 170.02400000000000091 38)),Polygon ((400 369.65420560747662648, 400 38, 170.02400000000000091 38, 221.20588235294115975 210.91176470588234793, 400 369.65420560747662648)),Polygon ((25 295, 25 395, 400 395, 400 369.65420560747662648, 221.20588235294115975 210.91176470588234793, 25 295)))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"delaunay: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"delaunay: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) - input = QgsGeometry.fromWkt("MULTIPOINT ((280 300), (420 330), (380 230), (320 160))") + input = QgsGeometry.fromWkt( + "MULTIPOINT ((280 300), (420 330), (380 230), (320 160))" + ) o = input.voronoiDiagram() if Qgis.geosVersionInt() >= self.geos309: exp = "GeometryCollection (Polygon ((110 500, 310.35714285714283278 500, 353.515625 298.59375, 306.875 231.96428571428572241, 110 175.71428571428572241, 110 500)),Polygon ((590 -10, 589.16666666666662877 -10, 306.875 231.96428571428572241, 353.515625 298.59375, 590 204, 590 -10)),Polygon ((110 -10, 110 175.71428571428572241, 306.875 231.96428571428572241, 589.16666666666662877 -10, 110 -10)),Polygon ((590 500, 590 204, 353.515625 298.59375, 310.35714285714283278 500, 590 500)))" else: exp = "GeometryCollection (Polygon ((110 175.71428571428572241, 110 500, 310.35714285714283278 500, 353.515625 298.59375, 306.875 231.96428571428572241, 110 175.71428571428572241)),Polygon ((590 204, 590 -10, 589.16666666666662877 -10, 306.875 231.96428571428572241, 353.515625 298.59375, 590 204)),Polygon ((589.16666666666662877 -10, 110 -10, 110 175.71428571428572241, 306.875 231.96428571428572241, 589.16666666666662877 -10)),Polygon ((310.35714285714283278 500, 590 500, 590 204, 353.515625 298.59375, 310.35714285714283278 500)))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"delaunay: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"delaunay: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) - input = QgsGeometry.fromWkt("MULTIPOINT ((320 170), (366 246), (530 230), (530 300), (455 277), (490 160))") + input = QgsGeometry.fromWkt( + "MULTIPOINT ((320 170), (366 246), (530 230), (530 300), (455 277), (490 160))" + ) o = input.voronoiDiagram() if Qgis.geosVersionInt() >= self.geos309: exp = "GeometryCollection (Polygon ((110 -50, 110 349.02631578947364233, 405.31091180866962986 170.28550074738416242, 392.35294117647055145 -50, 110 -50)),Polygon ((740 -50, 392.35294117647055145 -50, 405.31091180866962986 170.28550074738416242, 429.91476778570188344 205.76082797008174907, 470.12061711079945781 217.78821879382888937, 740 63.57142857142859071, 740 -50)),Polygon ((110 510, 323.94382022471910432 510, 429.91476778570188344 205.76082797008174907, 405.31091180866962986 170.28550074738416242, 110 349.02631578947364233, 110 510)),Polygon ((424.57333333333326664 510, 499.70666666666664923 265, 470.12061711079945781 217.78821879382888937, 429.91476778570188344 205.76082797008174907, 323.94382022471910432 510, 424.57333333333326664 510)),Polygon ((740 63.57142857142859071, 470.12061711079945781 217.78821879382888937, 499.70666666666664923 265, 740 265, 740 63.57142857142859071)),Polygon ((740 510, 740 265, 499.70666666666664923 265, 424.57333333333326664 510, 740 510)))" else: exp = "GeometryCollection (Polygon ((392.35294117647055145 -50, 110 -50, 110 349.02631578947364233, 405.31091180866962986 170.28550074738416242, 392.35294117647055145 -50)),Polygon ((740 63.57142857142859071, 740 -50, 392.35294117647055145 -50, 405.31091180866962986 170.28550074738416242, 429.91476778570188344 205.76082797008174907, 470.12061711079945781 217.78821879382888937, 740 63.57142857142859071)),Polygon ((110 349.02631578947364233, 110 510, 323.94382022471910432 510, 429.91476778570188344 205.76082797008174907, 405.31091180866962986 170.28550074738416242, 110 349.02631578947364233)),Polygon ((323.94382022471910432 510, 424.57333333333326664 510, 499.70666666666664923 265, 470.12061711079945781 217.78821879382888937, 429.91476778570188344 205.76082797008174907, 323.94382022471910432 510)),Polygon ((740 265, 740 63.57142857142859071, 470.12061711079945781 217.78821879382888937, 499.70666666666664923 265, 740 265)),Polygon ((424.57333333333326664 510, 740 510, 740 265, 499.70666666666664923 265, 424.57333333333326664 510)))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"delaunay: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"delaunay: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) input = QgsGeometry.fromWkt( - "MULTIPOINT ((280 200), (406 285), (580 280), (550 190), (370 190), (360 90), (480 110), (440 160), (450 180), (480 180), (460 160), (360 210), (360 220), (370 210), (375 227))") + "MULTIPOINT ((280 200), (406 285), (580 280), (550 190), (370 190), (360 90), (480 110), (440 160), (450 180), (480 180), (460 160), (360 210), (360 220), (370 210), (375 227))" + ) o = input.voronoiDiagram() if Qgis.geosVersionInt() >= self.geos309: exp = "GeometryCollection (Polygon ((-20 585, 111.94841269841269593 585, 293.54906542056073704 315.803738317756995, 318.75 215, 323.2352941176470722 179.1176470588235361, 319.39560439560437999 144.560439560439562, -20 -102.27272727272726627, -20 585)),Polygon ((365 200, 365 215, 369.40909090909093493 219.40909090909090651, 414.21192052980131848 206.23178807947019209, 411.875 200, 365 200)),Polygon ((365 215, 365 200, 323.2352941176470722 179.1176470588235361, 318.75 215, 365 215)),Polygon ((-20 -210, -20 -102.27272727272726627, 319.39560439560437999 144.560439560439562, 388.97260273972602818 137.60273972602740855, 419.55882352941176805 102.64705882352940591, 471.66666666666674246 -210, -20 -210)),Polygon ((411.875 200, 410.29411764705884025 187.35294117647057988, 388.97260273972602818 137.60273972602740855, 319.39560439560437999 144.560439560439562, 323.2352941176470722 179.1176470588235361, 365 200, 411.875 200)),Polygon ((410.29411764705884025 187.35294117647057988, 411.875 200, 414.21192052980131848 206.23178807947019209, 431.62536593766145643 234.0192009643533595, 465 248.00476190476189231, 465 175, 450 167.5, 410.29411764705884025 187.35294117647057988)),Polygon ((293.54906542056073704 315.803738317756995, 339.65007656967839011 283.17840735068909908, 369.40909090909093493 219.40909090909090651, 365 215, 318.75 215, 293.54906542056073704 315.803738317756995)),Polygon ((501.69252873563220874 585, 492.56703910614527331 267.43296089385472669, 465 248.00476190476189231, 431.62536593766145643 234.0192009643533595, 339.65007656967839011 283.17840735068909908, 293.54906542056073704 315.803738317756995, 111.94841269841269593 585, 501.69252873563220874 585)),Polygon ((369.40909090909093493 219.40909090909090651, 339.65007656967839011 283.17840735068909908, 431.62536593766145643 234.0192009643533595, 414.21192052980131848 206.23178807947019209, 369.40909090909093493 219.40909090909090651)),Polygon ((388.97260273972602818 137.60273972602740855, 410.29411764705884025 187.35294117647057988, 450 167.5, 450 127, 419.55882352941176805 102.64705882352940591, 388.97260273972602818 137.60273972602740855)),Polygon ((465 175, 465 248.00476190476189231, 492.56703910614527331 267.43296089385472669, 505 255, 520.71428571428566556 145, 495 145, 465 175)),Polygon ((880 -210, 471.66666666666674246 -210, 419.55882352941176805 102.64705882352940591, 450 127, 495 145, 520.71428571428566556 145, 880 -169.375, 880 -210)),Polygon ((465 175, 495 145, 450 127, 450 167.5, 465 175)),Polygon ((880 585, 880 130, 505 255, 492.56703910614527331 267.43296089385472669, 501.69252873563220874 585, 880 585)),Polygon ((880 -169.375, 520.71428571428566556 145, 505 255, 880 130, 880 -169.375)))" else: exp = "GeometryCollection (Polygon ((-20 -102.27272727272726627, -20 585, 111.94841269841269593 585, 293.54906542056073704 315.803738317756995, 318.75 215, 323.2352941176470722 179.1176470588235361, 319.39560439560437999 144.560439560439562, -20 -102.27272727272726627)),Polygon ((365 200, 365 215, 369.40909090909093493 219.40909090909090651, 414.21192052980131848 206.23178807947019209, 411.875 200, 365 200)),Polygon ((365 215, 365 200, 323.2352941176470722 179.1176470588235361, 318.75 215, 365 215)),Polygon ((471.66666666666674246 -210, -20 -210, -20 -102.27272727272726627, 319.39560439560437999 144.560439560439562, 388.97260273972602818 137.60273972602738013, 419.55882352941176805 102.64705882352942012, 471.66666666666674246 -210)),Polygon ((411.875 200, 410.29411764705884025 187.35294117647057988, 388.97260273972602818 137.60273972602738013, 319.39560439560437999 144.560439560439562, 323.2352941176470722 179.1176470588235361, 365 200, 411.875 200)),Polygon ((410.29411764705884025 187.35294117647057988, 411.875 200, 414.21192052980131848 206.23178807947019209, 431.62536593766145643 234.0192009643533595, 465 248.00476190476189231, 465 175, 450 167.5, 410.29411764705884025 187.35294117647057988)),Polygon ((293.54906542056073704 315.803738317756995, 339.65007656967839011 283.17840735068909908, 369.40909090909093493 219.40909090909090651, 365 215, 318.75 215, 293.54906542056073704 315.803738317756995)),Polygon ((111.94841269841269593 585, 501.69252873563215189 585, 492.56703910614521646 267.43296089385472669, 465 248.00476190476189231, 431.62536593766145643 234.0192009643533595, 339.65007656967839011 283.17840735068909908, 293.54906542056073704 315.803738317756995, 111.94841269841269593 585)),Polygon ((369.40909090909093493 219.40909090909090651, 339.65007656967839011 283.17840735068909908, 431.62536593766145643 234.0192009643533595, 414.21192052980131848 206.23178807947019209, 369.40909090909093493 219.40909090909090651)),Polygon ((388.97260273972602818 137.60273972602738013, 410.29411764705884025 187.35294117647057988, 450 167.5, 450 127, 419.55882352941176805 102.64705882352942012, 388.97260273972602818 137.60273972602738013)),Polygon ((465 175, 465 248.00476190476189231, 492.56703910614521646 267.43296089385472669, 505 255, 520.71428571428566556 145, 495 145, 465 175)),Polygon ((880 -169.375, 880 -210, 471.66666666666674246 -210, 419.55882352941176805 102.64705882352942012, 450 127, 495 145, 520.71428571428566556 145, 880 -169.375)),Polygon ((465 175, 495 145, 450 127, 450 167.5, 465 175)),Polygon ((501.69252873563215189 585, 880 585, 880 130.00000000000005684, 505 255, 492.56703910614521646 267.43296089385472669, 501.69252873563215189 585)),Polygon ((880 130.00000000000005684, 880 -169.375, 520.71428571428566556 145, 505 255, 880 130.00000000000005684)))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"delaunay: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"delaunay: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) input = QgsGeometry.fromWkt( - "MULTIPOINT ((100 200), (105 202), (110 200), (140 230), (210 240), (220 190), (170 170), (170 260), (213 245), (220 190))") + "MULTIPOINT ((100 200), (105 202), (110 200), (140 230), (210 240), (220 190), (170 170), (170 260), (213 245), (220 190))" + ) o = input.voronoiDiagram(QgsGeometry(), 6) if Qgis.geosVersionInt() >= self.geos309: exp = "GeometryCollection (Polygon ((-20 50, -20 380, -3.75 380, 105 235, 105 115, 77.1428571428571388 50, -20 50)),Polygon ((77.1428571428571388 50, 105 115, 145 195, 178.33333333333334281 211.66666666666665719, 183.51851851851850483 208.70370370370369528, 246.99999999999997158 50, 77.1428571428571388 50)),Polygon ((20.00000000000000711 380, 176.66666666666665719 223.33333333333334281, 178.33333333333334281 211.66666666666665719, 145 195, 105 235, -3.75 380, 20.00000000000000711 380)),Polygon ((105 115, 105 235, 145 195, 105 115)),Polygon ((255 380, 176.66666666666665719 223.33333333333334281, 20.00000000000000711 380, 255 380)),Polygon ((340 380, 340 240, 183.51851851851850483 208.70370370370369528, 178.33333333333334281 211.66666666666665719, 176.66666666666665719 223.33333333333334281, 255 380, 340 380)),Polygon ((340 50, 246.99999999999997158 50, 183.51851851851850483 208.70370370370369528, 340 240, 340 50)))" else: exp = "GeometryCollection (Polygon ((77.1428571428571388 50, -20 50, -20 380, -3.75 380, 105 235, 105 115, 77.1428571428571388 50)),Polygon ((247 50, 77.1428571428571388 50, 105 115, 145 195, 178.33333333333334281 211.66666666666665719, 183.51851851851853326 208.70370370370369528, 247 50)),Polygon ((-3.75 380, 20.00000000000000711 380, 176.66666666666665719 223.33333333333334281, 178.33333333333334281 211.66666666666665719, 145 195, 105 235, -3.75 380)),Polygon ((105 115, 105 235, 145 195, 105 115)),Polygon ((20.00000000000000711 380, 255 380, 176.66666666666665719 223.33333333333334281, 20.00000000000000711 380)),Polygon ((255 380, 340 380, 340 240, 183.51851851851853326 208.70370370370369528, 178.33333333333334281 211.66666666666665719, 176.66666666666665719 223.33333333333334281, 255 380)),Polygon ((340 240, 340 50, 247 50, 183.51851851851853326 208.70370370370369528, 340 240)))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"delaunay: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"delaunay: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) input = QgsGeometry.fromWkt( - "MULTIPOINT ((170 270), (177 275), (190 230), (230 250), (210 290), (240 280), (240 250))") + "MULTIPOINT ((170 270), (177 275), (190 230), (230 250), (210 290), (240 280), (240 250))" + ) o = input.voronoiDiagram(QgsGeometry(), 10) if Qgis.geosVersionInt() >= self.geos309: exp = "GeometryCollection (Polygon ((100 360, 150 360, 200 260, 100 210, 100 360)),Polygon ((250 360, 220 270, 200 260, 150 360, 250 360)),Polygon ((100 160, 100 210, 200 260, 235 190, 247 160, 100 160)),Polygon ((220 270, 235 265, 235 190, 200 260, 220 270)),Polygon ((310 360, 310 265, 235 265, 220 270, 250 360, 310 360)),Polygon ((310 160, 247 160, 235 190, 235 265, 310 265, 310 160)))" else: exp = "GeometryCollection (Polygon ((100 210, 100 360, 150 360, 200 260, 100 210)),Polygon ((150 360, 250 360, 220 270, 200 260, 150 360)),Polygon ((247 160, 100 160, 100 210, 200 260, 235 190, 247 160)),Polygon ((220 270, 235 265, 235 190, 200 260, 220 270)),Polygon ((250 360, 310 360, 310 265, 235 265, 220 270, 250 360)),Polygon ((310 265, 310 160, 247 160, 235 190, 235 265, 310 265)))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"delaunay: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"delaunay: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) input = QgsGeometry.fromWkt( - "MULTIPOINT ((155 271), (150 360), (260 360), (271 265), (280 260), (270 370), (154 354), (150 260))") + "MULTIPOINT ((155 271), (150 360), (260 360), (271 265), (280 260), (270 370), (154 354), (150 260))" + ) o = input.voronoiDiagram(QgsGeometry(), 100) if Qgis.geosVersionInt() >= self.geos309: exp = "GeometryCollection (Polygon ((20 130, 20 310, 205 310, 215 299, 215 130, 20 130)),Polygon ((410 500, 410 338, 215 299, 205 310, 205 500, 410 500)),Polygon ((20 500, 205 500, 205 310, 20 310, 20 500)),Polygon ((410 130, 215 130, 215 299, 410 338, 410 130)))" else: exp = "GeometryCollection (Polygon ((215 130, 20 130, 20 310, 205 310, 215 299, 215 130)),Polygon ((205 500, 410 500, 410 338, 215 299, 205 310, 205 500)),Polygon ((20 310, 20 500, 205 500, 205 310, 20 310)),Polygon ((410 338, 410 130, 215 130, 215 299, 410 338)))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"delaunay: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"delaunay: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) def testDensifyByCount(self): @@ -6005,99 +10585,133 @@ def testDensifyByCount(self): o = input.densifyByCount(100) exp = "PointZ( 1 2 3 )" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) input = QgsGeometry.fromWkt( - "MULTIPOINT ((155 271), (150 360), (260 360), (271 265), (280 260), (270 370), (154 354), (150 260))") + "MULTIPOINT ((155 271), (150 360), (260 360), (271 265), (280 260), (270 370), (154 354), (150 260))" + ) o = input.densifyByCount(100) exp = "MULTIPOINT ((155 271), (150 360), (260 360), (271 265), (280 260), (270 370), (154 354), (150 260))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) # line input = QgsGeometry.fromWkt("LineString( 0 0, 10 0, 10 10 )") o = input.densifyByCount(0) exp = "LineString( 0 0, 10 0, 10 10 )" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) o = input.densifyByCount(1) exp = "LineString( 0 0, 5 0, 10 0, 10 5, 10 10 )" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) o = input.densifyByCount(3) exp = "LineString( 0 0, 2.5 0, 5 0, 7.5 0, 10 0, 10 2.5, 10 5, 10 7.5, 10 10 )" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) input = QgsGeometry.fromWkt("LineStringZ( 0 0 1, 10 0 2, 10 10 0)") o = input.densifyByCount(1) exp = "LineStringZ( 0 0 1, 5 0 1.5, 10 0 2, 10 5 1, 10 10 0 )" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) input = QgsGeometry.fromWkt("LineStringM( 0 0 0, 10 0 2, 10 10 0)") o = input.densifyByCount(1) exp = "LineStringM( 0 0 0, 5 0 1, 10 0 2, 10 5 1, 10 10 0 )" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) input = QgsGeometry.fromWkt("LineStringZM( 0 0 1 10, 10 0 2 8, 10 10 0 4)") o = input.densifyByCount(1) exp = "LineStringZM( 0 0 1 10, 5 0 1.5 9, 10 0 2 8, 10 5 1 6, 10 10 0 4 )" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) # polygon input = QgsGeometry.fromWkt("Polygon(( 0 0, 10 0, 10 10, 0 0 ))") o = input.densifyByCount(0) exp = "Polygon(( 0 0, 10 0, 10 10, 0 0 ))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) input = QgsGeometry.fromWkt("PolygonZ(( 0 0 1, 10 0 2, 10 10 0, 0 0 1 ))") o = input.densifyByCount(1) exp = "PolygonZ(( 0 0 1, 5 0 1.5, 10 0 2, 10 5 1, 10 10 0, 5 5 0.5, 0 0 1 ))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) - input = QgsGeometry.fromWkt("PolygonZM(( 0 0 1 4, 10 0 2 6, 10 10 0 8, 0 0 1 4 ))") + input = QgsGeometry.fromWkt( + "PolygonZM(( 0 0 1 4, 10 0 2 6, 10 10 0 8, 0 0 1 4 ))" + ) o = input.densifyByCount(1) exp = "PolygonZM(( 0 0 1 4, 5 0 1.5 5, 10 0 2 6, 10 5 1 7, 10 10 0 8, 5 5 0.5 6, 0 0 1 4 ))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) # (not strictly valid, but shouldn't matter! input = QgsGeometry.fromWkt( - "PolygonZM(( 0 0 1 4, 10 0 2 6, 10 10 0 8, 0 0 1 4 ), ( 0 0 1 4, 10 0 2 6, 10 10 0 8, 0 0 1 4 ) )") + "PolygonZM(( 0 0 1 4, 10 0 2 6, 10 10 0 8, 0 0 1 4 ), ( 0 0 1 4, 10 0 2 6, 10 10 0 8, 0 0 1 4 ) )" + ) o = input.densifyByCount(1) exp = "PolygonZM(( 0 0 1 4, 5 0 1.5 5, 10 0 2 6, 10 5 1 7, 10 10 0 8, 5 5 0.5 6, 0 0 1 4 ),( 0 0 1 4, 5 0 1.5 5, 10 0 2 6, 10 5 1 7, 10 10 0 8, 5 5 0.5 6, 0 0 1 4 ))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) # multi line input = QgsGeometry.fromWkt( - "MultiLineString(( 0 0, 5 0, 10 0, 10 5, 10 10), (20 0, 25 0, 30 0, 30 5, 30 10 ) )") + "MultiLineString(( 0 0, 5 0, 10 0, 10 5, 10 10), (20 0, 25 0, 30 0, 30 5, 30 10 ) )" + ) o = input.densifyByCount(1) exp = "MultiLineString(( 0 0, 2.5 0, 5 0, 7.5 0, 10 0, 10 2.5, 10 5, 10 7.5, 10 10 ),( 20 0, 22.5 0, 25 0, 27.5 0, 30 0, 30 2.5, 30 5, 30 7.5, 30 10 ))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) # multipolygon input = QgsGeometry.fromWkt( - "MultiPolygonZ((( 0 0 1, 10 0 2, 10 10 0, 0 0 1)),(( 0 0 1, 10 0 2, 10 10 0, 0 0 1 )))") + "MultiPolygonZ((( 0 0 1, 10 0 2, 10 10 0, 0 0 1)),(( 0 0 1, 10 0 2, 10 10 0, 0 0 1 )))" + ) o = input.densifyByCount(1) exp = "MultiPolygonZ((( 0 0 1, 5 0 1.5, 10 0 2, 10 5 1, 10 10 0, 5 5 0.5, 0 0 1 )),(( 0 0 1, 5 0 1.5, 10 0 2, 10 5 1, 10 10 0, 5 5 0.5, 0 0 1 )))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) def testDensifyByDistance(self): empty = QgsGeometry() @@ -6109,152 +10723,214 @@ def testDensifyByDistance(self): o = input.densifyByDistance(0.1) exp = "PointZ( 1 2 3 )" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) input = QgsGeometry.fromWkt( - "MULTIPOINT ((155 271), (150 360), (260 360), (271 265), (280 260), (270 370), (154 354), (150 260))") + "MULTIPOINT ((155 271), (150 360), (260 360), (271 265), (280 260), (270 370), (154 354), (150 260))" + ) o = input.densifyByDistance(0.1) exp = "MULTIPOINT ((155 271), (150 360), (260 360), (271 265), (280 260), (270 370), (154 354), (150 260))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) # line input = QgsGeometry.fromWkt("LineString( 0 0, 10 0, 10 10 )") o = input.densifyByDistance(100) exp = "LineString( 0 0, 10 0, 10 10 )" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) o = input.densifyByDistance(3) exp = "LineString (0 0, 2.5 0, 5 0, 7.5 0, 10 0, 10 2.5, 10 5, 10 7.5, 10 10)" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) input = QgsGeometry.fromWkt("LineStringZ( 0 0 1, 10 0 2, 10 10 0)") o = input.densifyByDistance(6) exp = "LineStringZ (0 0 1, 5 0 1.5, 10 0 2, 10 5 1, 10 10 0)" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) input = QgsGeometry.fromWkt("LineStringM( 0 0 0, 10 0 2, 10 10 0)") o = input.densifyByDistance(3) exp = "LineStringM (0 0 0, 2.5 0 0.5, 5 0 1, 7.5 0 1.5, 10 0 2, 10 2.5 1.5, 10 5 1, 10 7.5 0.5, 10 10 0)" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) input = QgsGeometry.fromWkt("LineStringZM( 0 0 1 10, 10 0 2 8, 10 10 0 4)") o = input.densifyByDistance(6) exp = "LineStringZM (0 0 1 10, 5 0 1.5 9, 10 0 2 8, 10 5 1 6, 10 10 0 4)" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) # polygon input = QgsGeometry.fromWkt("Polygon(( 0 0, 20 0, 20 20, 0 0 ))") o = input.densifyByDistance(110) exp = "Polygon(( 0 0, 20 0, 20 20, 0 0 ))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) input = QgsGeometry.fromWkt("PolygonZ(( 0 0 1, 20 0 2, 20 20 0, 0 0 1 ))") o = input.densifyByDistance(6) exp = "PolygonZ ((0 0 1, 5 0 1.25, 10 0 1.5, 15 0 1.75, 20 0 2, 20 5 1.5, 20 10 1, 20 15 0.5, 20 20 0, 16 16 0.2, 12 12 0.4, 8 8 0.6, 4 4 0.8, 0 0 1))" result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"densify by count: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) def testCentroid(self): - tests = [["POINT(10 0)", "POINT(10 0)"], - ["POINT(10 10)", "POINT(10 10)"], - ["MULTIPOINT((10 10), (20 20) )", "POINT(15 15)"], - [" MULTIPOINT((10 10), (20 20), (10 20), (20 10))", "POINT(15 15)"], - ["LINESTRING(10 10, 20 20)", "POINT(15 15)"], - ["LINESTRING(0 0, 10 0)", "POINT(5 0 )"], - ["LINESTRING (10 10, 10 10)", "POINT (10 10)"], # zero length line - ["MULTILINESTRING ((10 10, 10 10), (20 20, 20 20))", "POINT (15 15)"], # zero length multiline - ["LINESTRING (60 180, 120 100, 180 180)", "POINT (120 140)"], - ["LINESTRING (80 0, 80 120, 120 120, 120 0)", "POINT (100 68.57142857142857)"], - ["MULTILINESTRING ((0 0, 0 100), (100 0, 100 100))", "POINT (50 50)"], - [" MULTILINESTRING ((0 0, 0 200, 200 200, 200 0, 0 0),(60 180, 20 180, 20 140, 60 140, 60 180))", - "POINT (90 110)"], - [ - "MULTILINESTRING ((20 20, 60 60),(20 -20, 60 -60),(-20 -20, -60 -60),(-20 20, -60 60),(-80 0, 0 80, 80 0, 0 -80, -80 0),(-40 20, -40 -20),(-20 40, 20 40),(40 20, 40 -20),(20 -40, -20 -40))", - "POINT (0 0)"], - ["POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))", "POINT (5 5)"], - ["POLYGON ((40 160, 160 160, 160 40, 40 40, 40 160))", "POINT (100 100)"], - ["POLYGON ((0 200, 200 200, 200 0, 0 0, 0 200), (20 180, 80 180, 80 20, 20 20, 20 180))", - "POINT (115.78947368421052 100)"], - ["POLYGON ((0 0, 0 200, 200 200, 200 0, 0 0),(60 180, 20 180, 20 140, 60 140, 60 180))", - "POINT (102.5 97.5)"], - [ - "POLYGON ((0 0, 0 200, 200 200, 200 0, 0 0),(60 180, 20 180, 20 140, 60 140, 60 180),(180 60, 140 60, 140 20, 180 20, 180 60))", - "POINT (100 100)"], - [ - "MULTIPOLYGON (((0 40, 0 140, 140 140, 140 120, 20 120, 20 40, 0 40)),((0 0, 0 20, 120 20, 120 100, 140 100, 140 0, 0 0)))", - "POINT (70 70)"], - [ - "GEOMETRYCOLLECTION (POLYGON ((0 200, 20 180, 20 140, 60 140, 200 0, 0 0, 0 200)),POLYGON ((200 200, 0 200, 20 180, 60 180, 60 140, 200 0, 200 200)))", - "POINT (102.5 97.5)"], - [ - "GEOMETRYCOLLECTION (LINESTRING (80 0, 80 120, 120 120, 120 0),MULTIPOINT ((20 60), (40 80), (60 60)))", - "POINT (100 68.57142857142857)"], - ["GEOMETRYCOLLECTION (POLYGON ((0 40, 40 40, 40 0, 0 0, 0 40)),LINESTRING (80 0, 80 80, 120 40))", - "POINT (20 20)"], - [ - "GEOMETRYCOLLECTION (POLYGON ((0 40, 40 40, 40 0, 0 0, 0 40)),LINESTRING (80 0, 80 80, 120 40),MULTIPOINT ((20 60), (40 80), (60 60)))", - "POINT (20 20)"], - ["GEOMETRYCOLLECTION (POLYGON ((10 10, 10 10, 10 10, 10 10)),LINESTRING (20 20, 30 30))", - "POINT (25 25)"], - ["GEOMETRYCOLLECTION (POLYGON ((10 10, 10 10, 10 10, 10 10)),LINESTRING (20 20, 20 20))", - "POINT (15 15)"], - [ - "GEOMETRYCOLLECTION (POLYGON ((10 10, 10 10, 10 10, 10 10)),LINESTRING (20 20, 20 20),MULTIPOINT ((20 10), (10 20)) )", - "POINT (15 15)"], - # ["GEOMETRYCOLLECTION (POLYGON ((10 10, 10 10, 10 10, 10 10)),LINESTRING (20 20, 20 20),POINT EMPTY )","POINT (15 15)"], - # ["GEOMETRYCOLLECTION (POLYGON ((10 10, 10 10, 10 10, 10 10)),LINESTRING EMPTY,POINT EMPTY )","POINT (10 10)"], - [ - "GEOMETRYCOLLECTION (POLYGON ((20 100, 20 -20, 60 -20, 60 100, 20 100)),POLYGON ((-20 60, 100 60, 100 20, -20 20, -20 60)))", - "POINT (40 40)"], - ["POLYGON ((40 160, 160 160, 160 160, 40 160, 40 160))", "POINT (100 160)"], - ["POLYGON ((10 10, 100 100, 100 100, 10 10))", "POINT (55 55)"], - # ["POLYGON EMPTY","POINT EMPTY"], - # ["MULTIPOLYGON(EMPTY,((0 0,1 0,1 1,0 1, 0 0)))","POINT (0.5 0.5)"], - [ - "POLYGON((56.528666666700 25.2101666667,56.529000000000 25.2105000000,56.528833333300 25.2103333333,56.528666666700 25.2101666667))", - "POINT (56.52883333335 25.21033333335)"], - [ - "POLYGON((56.528666666700 25.2101666667,56.529000000000 25.2105000000,56.528833333300 25.2103333333,56.528666666700 25.2101666667))", - "POINT (56.528833 25.210333)"] - ] + tests = [ + ["POINT(10 0)", "POINT(10 0)"], + ["POINT(10 10)", "POINT(10 10)"], + ["MULTIPOINT((10 10), (20 20) )", "POINT(15 15)"], + [" MULTIPOINT((10 10), (20 20), (10 20), (20 10))", "POINT(15 15)"], + ["LINESTRING(10 10, 20 20)", "POINT(15 15)"], + ["LINESTRING(0 0, 10 0)", "POINT(5 0 )"], + ["LINESTRING (10 10, 10 10)", "POINT (10 10)"], # zero length line + [ + "MULTILINESTRING ((10 10, 10 10), (20 20, 20 20))", + "POINT (15 15)", + ], # zero length multiline + ["LINESTRING (60 180, 120 100, 180 180)", "POINT (120 140)"], + [ + "LINESTRING (80 0, 80 120, 120 120, 120 0)", + "POINT (100 68.57142857142857)", + ], + ["MULTILINESTRING ((0 0, 0 100), (100 0, 100 100))", "POINT (50 50)"], + [ + " MULTILINESTRING ((0 0, 0 200, 200 200, 200 0, 0 0),(60 180, 20 180, 20 140, 60 140, 60 180))", + "POINT (90 110)", + ], + [ + "MULTILINESTRING ((20 20, 60 60),(20 -20, 60 -60),(-20 -20, -60 -60),(-20 20, -60 60),(-80 0, 0 80, 80 0, 0 -80, -80 0),(-40 20, -40 -20),(-20 40, 20 40),(40 20, 40 -20),(20 -40, -20 -40))", + "POINT (0 0)", + ], + ["POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))", "POINT (5 5)"], + ["POLYGON ((40 160, 160 160, 160 40, 40 40, 40 160))", "POINT (100 100)"], + [ + "POLYGON ((0 200, 200 200, 200 0, 0 0, 0 200), (20 180, 80 180, 80 20, 20 20, 20 180))", + "POINT (115.78947368421052 100)", + ], + [ + "POLYGON ((0 0, 0 200, 200 200, 200 0, 0 0),(60 180, 20 180, 20 140, 60 140, 60 180))", + "POINT (102.5 97.5)", + ], + [ + "POLYGON ((0 0, 0 200, 200 200, 200 0, 0 0),(60 180, 20 180, 20 140, 60 140, 60 180),(180 60, 140 60, 140 20, 180 20, 180 60))", + "POINT (100 100)", + ], + [ + "MULTIPOLYGON (((0 40, 0 140, 140 140, 140 120, 20 120, 20 40, 0 40)),((0 0, 0 20, 120 20, 120 100, 140 100, 140 0, 0 0)))", + "POINT (70 70)", + ], + [ + "GEOMETRYCOLLECTION (POLYGON ((0 200, 20 180, 20 140, 60 140, 200 0, 0 0, 0 200)),POLYGON ((200 200, 0 200, 20 180, 60 180, 60 140, 200 0, 200 200)))", + "POINT (102.5 97.5)", + ], + [ + "GEOMETRYCOLLECTION (LINESTRING (80 0, 80 120, 120 120, 120 0),MULTIPOINT ((20 60), (40 80), (60 60)))", + "POINT (100 68.57142857142857)", + ], + [ + "GEOMETRYCOLLECTION (POLYGON ((0 40, 40 40, 40 0, 0 0, 0 40)),LINESTRING (80 0, 80 80, 120 40))", + "POINT (20 20)", + ], + [ + "GEOMETRYCOLLECTION (POLYGON ((0 40, 40 40, 40 0, 0 0, 0 40)),LINESTRING (80 0, 80 80, 120 40),MULTIPOINT ((20 60), (40 80), (60 60)))", + "POINT (20 20)", + ], + [ + "GEOMETRYCOLLECTION (POLYGON ((10 10, 10 10, 10 10, 10 10)),LINESTRING (20 20, 30 30))", + "POINT (25 25)", + ], + [ + "GEOMETRYCOLLECTION (POLYGON ((10 10, 10 10, 10 10, 10 10)),LINESTRING (20 20, 20 20))", + "POINT (15 15)", + ], + [ + "GEOMETRYCOLLECTION (POLYGON ((10 10, 10 10, 10 10, 10 10)),LINESTRING (20 20, 20 20),MULTIPOINT ((20 10), (10 20)) )", + "POINT (15 15)", + ], + # ["GEOMETRYCOLLECTION (POLYGON ((10 10, 10 10, 10 10, 10 10)),LINESTRING (20 20, 20 20),POINT EMPTY )","POINT (15 15)"], + # ["GEOMETRYCOLLECTION (POLYGON ((10 10, 10 10, 10 10, 10 10)),LINESTRING EMPTY,POINT EMPTY )","POINT (10 10)"], + [ + "GEOMETRYCOLLECTION (POLYGON ((20 100, 20 -20, 60 -20, 60 100, 20 100)),POLYGON ((-20 60, 100 60, 100 20, -20 20, -20 60)))", + "POINT (40 40)", + ], + ["POLYGON ((40 160, 160 160, 160 160, 40 160, 40 160))", "POINT (100 160)"], + ["POLYGON ((10 10, 100 100, 100 100, 10 10))", "POINT (55 55)"], + # ["POLYGON EMPTY","POINT EMPTY"], + # ["MULTIPOLYGON(EMPTY,((0 0,1 0,1 1,0 1, 0 0)))","POINT (0.5 0.5)"], + [ + "POLYGON((56.528666666700 25.2101666667,56.529000000000 25.2105000000,56.528833333300 25.2103333333,56.528666666700 25.2101666667))", + "POINT (56.52883333335 25.21033333335)", + ], + [ + "POLYGON((56.528666666700 25.2101666667,56.529000000000 25.2105000000,56.528833333300 25.2103333333,56.528666666700 25.2101666667))", + "POINT (56.528833 25.210333)", + ], + ] for t in tests: input = QgsGeometry.fromWkt(t[0]) o = input.centroid() exp = t[1] result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"centroid: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"centroid: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) # QGIS native algorithms are bad! if False: result = QgsGeometry(input.get().centroid()).asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - "centroid: mismatch using QgsAbstractGeometry methods Input {} \n Expected:\n{}\nGot:\n{}\n".format( - t[0], exp, result)) + self.assertTrue( + compareWkt(result, exp, 0.00001), + "centroid: mismatch using QgsAbstractGeometry methods Input {} \n Expected:\n{}\nGot:\n{}\n".format( + t[0], exp, result + ), + ) def testCompare(self): lp = [QgsPointXY(1, 1), QgsPointXY(2, 2), QgsPointXY(1, 2), QgsPointXY(1, 1)] - lp2 = [QgsPointXY(1, 1.0000001), QgsPointXY(2, 2), QgsPointXY(1, 2), QgsPointXY(1, 1)] + lp2 = [ + QgsPointXY(1, 1.0000001), + QgsPointXY(2, 2), + QgsPointXY(1, 2), + QgsPointXY(1, 1), + ] self.assertTrue(QgsGeometry.compare(lp, lp)) # line-line self.assertTrue(QgsGeometry.compare([lp], [lp])) # pylygon-polygon - self.assertTrue(QgsGeometry.compare([[lp]], [[lp]])) # multipyolygon-multipolygon + self.assertTrue( + QgsGeometry.compare([[lp]], [[lp]]) + ) # multipyolygon-multipolygon # handling empty values self.assertFalse(QgsGeometry.compare(None, None)) self.assertFalse(QgsGeometry.compare(lp, [])) # line-line self.assertFalse(QgsGeometry.compare([lp], [[]])) # pylygon-polygon - self.assertFalse(QgsGeometry.compare([[lp]], [[[]]])) # multipolygon-multipolygon + self.assertFalse( + QgsGeometry.compare([[lp]], [[[]]]) + ) # multipolygon-multipolygon # tolerance self.assertFalse(QgsGeometry.compare(lp, lp2)) self.assertTrue(QgsGeometry.compare(lp, lp2, 1e-6)) @@ -6296,27 +10972,46 @@ def testPoint(self): self.assertEqual(point_zm.m(), 4) def testSubdivide(self): - tests = [["LINESTRING (1 1,1 9,9 9,9 1)", 8, "MULTILINESTRING ((1 1,1 9,9 9,9 1))"], - ["Point (1 1)", 8, "MultiPoint ((1 1))"], - ["GeometryCollection ()", 8, "GeometryCollection EMPTY"], - ["LINESTRING (1 1,1 2,1 3,1 4,1 5,1 6,1 7,1 8,1 9)", 8, - "MultiLineString ((1 1, 1 2, 1 3, 1 4, 1 5),(1 5, 1 6, 1 7, 1 8, 1 9))"], - ["LINESTRING(0 0, 100 100, 150 150)", 8, 'MultiLineString ((0 0, 100 100, 150 150))'], - [ - 'POLYGON((132 10,119 23,85 35,68 29,66 28,49 42,32 56,22 64,32 110,40 119,36 150,57 158,75 171,92 182,114 184,132 186,146 178,176 184,179 162,184 141,190 122,190 100,185 79,186 56,186 52,178 34,168 18,147 13,132 10))', - 10, None], - ["LINESTRING (1 1,1 2,1 3,1 4,1 5,1 6,1 7,1 8,1 9)", 1, - "MultiLineString ((1 1, 1 2, 1 3, 1 4, 1 5),(1 5, 1 6, 1 7, 1 8, 1 9))"], - ["LINESTRING (1 1,1 2,1 3,1 4,1 5,1 6,1 7,1 8,1 9)", 16, - "MultiLineString ((1 1, 1 2, 1 3, 1 4, 1 5, 1 6, 1 7, 1 8, 1 9))"], - [ - "POLYGON ((0 0, 0 200, 200 200, 200 0, 0 0),(60 180, 20 180, 20 140, 60 140, 60 180),(180 60, 140 60, 140 20, 180 20, 180 60))", - 8, - "MultiPolygon (((0 0, 0 100, 100 100, 100 0, 0 0)),((100 0, 100 50, 140 50, 140 20, 150 20, 150 0, 100 0)),((150 0, 150 20, 180 20, 180 50, 200 50, 200 0, 150 0)),((100 50, 100 100, 150 100, 150 60, 140 60, 140 50, 100 50)),((150 60, 150 100, 200 100, 200 50, 180 50, 180 60, 150 60)),((0 100, 0 150, 20 150, 20 140, 50 140, 50 100, 0 100)),((50 100, 50 140, 60 140, 60 150, 100 150, 100 100, 50 100)),((0 150, 0 200, 50 200, 50 180, 20 180, 20 150, 0 150)),((50 180, 50 200, 100 200, 100 150, 60 150, 60 180, 50 180)),((100 100, 100 200, 200 200, 200 100, 100 100)))"], - [ - "POLYGON((132 10,119 23,85 35,68 29,66 28,49 42,32 56,22 64,32 110,40 119,36 150, 57 158,75 171,92 182,114 184,132 186,146 178,176 184,179 162,184 141,190 122,190 100,185 79,186 56,186 52,178 34,168 18,147 13,132 10))", - 10, None] - ] + tests = [ + ["LINESTRING (1 1,1 9,9 9,9 1)", 8, "MULTILINESTRING ((1 1,1 9,9 9,9 1))"], + ["Point (1 1)", 8, "MultiPoint ((1 1))"], + ["GeometryCollection ()", 8, "GeometryCollection EMPTY"], + [ + "LINESTRING (1 1,1 2,1 3,1 4,1 5,1 6,1 7,1 8,1 9)", + 8, + "MultiLineString ((1 1, 1 2, 1 3, 1 4, 1 5),(1 5, 1 6, 1 7, 1 8, 1 9))", + ], + [ + "LINESTRING(0 0, 100 100, 150 150)", + 8, + "MultiLineString ((0 0, 100 100, 150 150))", + ], + [ + "POLYGON((132 10,119 23,85 35,68 29,66 28,49 42,32 56,22 64,32 110,40 119,36 150,57 158,75 171,92 182,114 184,132 186,146 178,176 184,179 162,184 141,190 122,190 100,185 79,186 56,186 52,178 34,168 18,147 13,132 10))", + 10, + None, + ], + [ + "LINESTRING (1 1,1 2,1 3,1 4,1 5,1 6,1 7,1 8,1 9)", + 1, + "MultiLineString ((1 1, 1 2, 1 3, 1 4, 1 5),(1 5, 1 6, 1 7, 1 8, 1 9))", + ], + [ + "LINESTRING (1 1,1 2,1 3,1 4,1 5,1 6,1 7,1 8,1 9)", + 16, + "MultiLineString ((1 1, 1 2, 1 3, 1 4, 1 5, 1 6, 1 7, 1 8, 1 9))", + ], + [ + "POLYGON ((0 0, 0 200, 200 200, 200 0, 0 0),(60 180, 20 180, 20 140, 60 140, 60 180),(180 60, 140 60, 140 20, 180 20, 180 60))", + 8, + "MultiPolygon (((0 0, 0 100, 100 100, 100 0, 0 0)),((100 0, 100 50, 140 50, 140 20, 150 20, 150 0, 100 0)),((150 0, 150 20, 180 20, 180 50, 200 50, 200 0, 150 0)),((100 50, 100 100, 150 100, 150 60, 140 60, 140 50, 100 50)),((150 60, 150 100, 200 100, 200 50, 180 50, 180 60, 150 60)),((0 100, 0 150, 20 150, 20 140, 50 140, 50 100, 0 100)),((50 100, 50 140, 60 140, 60 150, 100 150, 100 100, 50 100)),((0 150, 0 200, 50 200, 50 180, 20 180, 20 150, 0 150)),((50 180, 50 200, 100 200, 100 150, 60 150, 60 180, 50 180)),((100 100, 100 200, 200 200, 200 100, 100 100)))", + ], + [ + "POLYGON((132 10,119 23,85 35,68 29,66 28,49 42,32 56,22 64,32 110,40 119,36 150, 57 158,75 171,92 182,114 184,132 186,146 178,176 184,179 162,184 141,190 122,190 100,185 79,186 56,186 52,178 34,168 18,147 13,132 10))", + 10, + None, + ], + ] for t in tests: input = QgsGeometry.fromWkt(t[0]) o = input.subdivide(t[1]) @@ -6330,68 +11025,222 @@ def testSubdivide(self): if t[2]: exp = t[2] result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"clipped: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"clipped: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) def testClipped(self): - tests = [["LINESTRING (1 1,1 9,9 9,9 1)", QgsRectangle(0, 0, 10, 10), "LINESTRING (1 1,1 9,9 9,9 1)"], - ["LINESTRING (-1 -9,-1 11,9 11)", QgsRectangle(0, 0, 10, 10), - "GEOMETRYCOLLECTION EMPTY"], - ["LINESTRING (-1 5,5 5,9 9)", QgsRectangle(0, 0, 10, 10), "LINESTRING (0 5,5 5,9 9)"], - ["LINESTRING (5 5,8 5,12 5)", QgsRectangle(0, 0, 10, 10), "LINESTRING (5 5,8 5,10 5)"], - ["LINESTRING (5 -1,5 5,1 2,-3 2,1 6)", QgsRectangle(0, 0, 10, 10), - "MULTILINESTRING ((5 0,5 5,1 2,0 2),(0 5,1 6))"], - ["LINESTRING (0 3,0 5,0 7)", QgsRectangle(0, 0, 10, 10), - "GEOMETRYCOLLECTION EMPTY"], - ["LINESTRING (0 3,0 5,-1 7)", QgsRectangle(0, 0, 10, 10), - "GEOMETRYCOLLECTION EMPTY"], - ["LINESTRING (0 3,0 5,2 7)", QgsRectangle(0, 0, 10, 10), "LINESTRING (0 5,2 7)"], - ["LINESTRING (2 1,0 0,1 2)", QgsRectangle(0, 0, 10, 10), "LINESTRING (2 1,0 0,1 2)"], - ["LINESTRING (3 3,0 3,0 5,2 7)", QgsRectangle(0, 0, 10, 10), "MULTILINESTRING ((3 3,0 3),(0 5,2 7))"], - ["LINESTRING (5 5,10 5,20 5)", QgsRectangle(0, 0, 10, 10), "LINESTRING (5 5,10 5)"], - ["LINESTRING (3 3,0 6,3 9)", QgsRectangle(0, 0, 10, 10), "LINESTRING (3 3,0 6,3 9)"], - ["POLYGON ((5 5,5 6,6 6,6 5,5 5))", QgsRectangle(0, 0, 10, 10), "POLYGON ((5 5,5 6,6 6,6 5,5 5))"], - ["POLYGON ((15 15,15 16,16 16,16 15,15 15))", QgsRectangle(0, 0, 10, 10), - "GEOMETRYCOLLECTION EMPTY"], - ["POLYGON ((-1 -1,-1 11,11 11,11 -1,-1 -1))", QgsRectangle(0, 0, 10, 10), - "Polygon ((0 0, 0 10, 10 10, 10 0, 0 0))"], - ["POLYGON ((-1 -1,-1 5,5 5,5 -1,-1 -1))", QgsRectangle(0, 0, 10, 10), - "Polygon ((0 0, 0 5, 5 5, 5 0, 0 0))"], - ["POLYGON ((-2 -2,-2 5,5 5,5 -2,-2 -2), (3 3,4 4,4 2,3 3))", QgsRectangle(0, 0, 10, 10), - "Polygon ((0 0, 0 5, 5 5, 5 0, 0 0),(3 3, 4 4, 4 2, 3 3))"] - ] + tests = [ + [ + "LINESTRING (1 1,1 9,9 9,9 1)", + QgsRectangle(0, 0, 10, 10), + "LINESTRING (1 1,1 9,9 9,9 1)", + ], + [ + "LINESTRING (-1 -9,-1 11,9 11)", + QgsRectangle(0, 0, 10, 10), + "GEOMETRYCOLLECTION EMPTY", + ], + [ + "LINESTRING (-1 5,5 5,9 9)", + QgsRectangle(0, 0, 10, 10), + "LINESTRING (0 5,5 5,9 9)", + ], + [ + "LINESTRING (5 5,8 5,12 5)", + QgsRectangle(0, 0, 10, 10), + "LINESTRING (5 5,8 5,10 5)", + ], + [ + "LINESTRING (5 -1,5 5,1 2,-3 2,1 6)", + QgsRectangle(0, 0, 10, 10), + "MULTILINESTRING ((5 0,5 5,1 2,0 2),(0 5,1 6))", + ], + [ + "LINESTRING (0 3,0 5,0 7)", + QgsRectangle(0, 0, 10, 10), + "GEOMETRYCOLLECTION EMPTY", + ], + [ + "LINESTRING (0 3,0 5,-1 7)", + QgsRectangle(0, 0, 10, 10), + "GEOMETRYCOLLECTION EMPTY", + ], + [ + "LINESTRING (0 3,0 5,2 7)", + QgsRectangle(0, 0, 10, 10), + "LINESTRING (0 5,2 7)", + ], + [ + "LINESTRING (2 1,0 0,1 2)", + QgsRectangle(0, 0, 10, 10), + "LINESTRING (2 1,0 0,1 2)", + ], + [ + "LINESTRING (3 3,0 3,0 5,2 7)", + QgsRectangle(0, 0, 10, 10), + "MULTILINESTRING ((3 3,0 3),(0 5,2 7))", + ], + [ + "LINESTRING (5 5,10 5,20 5)", + QgsRectangle(0, 0, 10, 10), + "LINESTRING (5 5,10 5)", + ], + [ + "LINESTRING (3 3,0 6,3 9)", + QgsRectangle(0, 0, 10, 10), + "LINESTRING (3 3,0 6,3 9)", + ], + [ + "POLYGON ((5 5,5 6,6 6,6 5,5 5))", + QgsRectangle(0, 0, 10, 10), + "POLYGON ((5 5,5 6,6 6,6 5,5 5))", + ], + [ + "POLYGON ((15 15,15 16,16 16,16 15,15 15))", + QgsRectangle(0, 0, 10, 10), + "GEOMETRYCOLLECTION EMPTY", + ], + [ + "POLYGON ((-1 -1,-1 11,11 11,11 -1,-1 -1))", + QgsRectangle(0, 0, 10, 10), + "Polygon ((0 0, 0 10, 10 10, 10 0, 0 0))", + ], + [ + "POLYGON ((-1 -1,-1 5,5 5,5 -1,-1 -1))", + QgsRectangle(0, 0, 10, 10), + "Polygon ((0 0, 0 5, 5 5, 5 0, 0 0))", + ], + [ + "POLYGON ((-2 -2,-2 5,5 5,5 -2,-2 -2), (3 3,4 4,4 2,3 3))", + QgsRectangle(0, 0, 10, 10), + "Polygon ((0 0, 0 5, 5 5, 5 0, 0 0),(3 3, 4 4, 4 2, 3 3))", + ], + ] for t in tests: input = QgsGeometry.fromWkt(t[0]) o = input.clipped(t[1]) exp = t[2] result = o.asWkt() - self.assertTrue(compareWkt(result, exp, 0.00001), - f"clipped: mismatch Expected:\n{exp}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp, 0.00001), + f"clipped: mismatch Expected:\n{exp}\nGot:\n{result}\n", + ) def testCreateWedgeBuffer(self): - tests = [[QgsPoint(1, 11), 0, 45, -22.5, 22.5, 2, 0, - 'CurvePolygon (CompoundCurve (CircularString (0.23463313526982044 12.84775906502257392, 1 13, 1.76536686473017967 12.84775906502257392),(1.76536686473017967 12.84775906502257392, 1 11),(1 11, 0.23463313526982044 12.84775906502257392)))'], - [QgsPoint(1, 11), 90, 45, 67.5, 112.5, 2, 0, - 'CurvePolygon (CompoundCurve (CircularString (2.84775906502257348 11.76536686473017923, 3 11, 2.84775906502257348 10.23463313526982077),(2.84775906502257348 10.23463313526982077, 1 11),(1 11, 2.84775906502257348 11.76536686473017923)))'], - [QgsPoint(1, 11), 180, 90, 135, 225, 2, 0, - 'CurvePolygon (CompoundCurve (CircularString (2.41421356237309492 9.58578643762690419, 1.00000000000000022 9, -0.41421356237309492 9.58578643762690419),(-0.41421356237309492 9.58578643762690419, 1 11),(1 11, 2.41421356237309492 9.58578643762690419)))'], - [QgsPoint(1, 11), 0, 200, -100, 100, 2, 0, - 'CurvePolygon (CompoundCurve (CircularString (-0.96961550602441604 10.65270364466613984, 0.99999999999999956 13, 2.96961550602441626 10.65270364466613984),(2.96961550602441626 10.65270364466613984, 1 11),(1 11, -0.96961550602441604 10.65270364466613984)))'], - [QgsPoint(1, 11), 0, 45, -22.5, 22.5, 2, 1, - 'CurvePolygon (CompoundCurve (CircularString (0.23463313526982044 12.84775906502257392, 1 13, 1.76536686473017967 12.84775906502257392),(1.76536686473017967 12.84775906502257392, 1.38268343236508984 11.92387953251128607),CircularString (1.38268343236508984 11.92387953251128607, 0.99999999999999978 12, 0.61731656763491016 11.92387953251128607),(0.61731656763491016 11.92387953251128607, 0.23463313526982044 12.84775906502257392)))'], - [QgsPoint(1, 11), 0, 200, -100, 100, 2, 1, - 'CurvePolygon (CompoundCurve (CircularString (-0.96961550602441604 10.65270364466613984, 0.99999999999999956 13, 2.96961550602441626 10.65270364466613984),(2.96961550602441626 10.65270364466613984, 1.98480775301220813 10.82635182233306992),CircularString (1.98480775301220813 10.82635182233306992, 0.99999999999999978 12, 0.01519224698779198 10.82635182233306992),(0.01519224698779198 10.82635182233306992, -0.96961550602441604 10.65270364466613984)))'], - [QgsPoint(1, 11, 3), 0, 45, -22.5, 22.5, 2, 0, - 'CurvePolygonZ (CompoundCurveZ (CircularStringZ (0.23463313526982044 12.84775906502257392 3, 1 13 3, 1.76536686473017967 12.84775906502257392 3),(1.76536686473017967 12.84775906502257392 3, 1 11 3),(1 11 3, 0.23463313526982044 12.84775906502257392 3)))'], - [QgsPoint(1, 11, m=3), 0, 45, -22.5, 22.5, 2, 0, - 'CurvePolygonM (CompoundCurveM (CircularStringM (0.23463313526982044 12.84775906502257392 3, 1 13 3, 1.76536686473017967 12.84775906502257392 3),(1.76536686473017967 12.84775906502257392 3, 1 11 3),(1 11 3, 0.23463313526982044 12.84775906502257392 3)))'], - [QgsPoint(1, 11), 0, 360, -180, 180, 2, 0, - 'CurvePolygon (CompoundCurve (CircularString (1 13, 3 11, 1 9, -1 11, 1 13)))'], - [QgsPoint(1, 11), 0, -1000, 0, 360, 2, 0, - 'CurvePolygon (CompoundCurve (CircularString (1 13, 3 11, 1 9, -1 11, 1 13)))'], - [QgsPoint(1, 11), 0, 360, -180, 180, 2, 1, - 'CurvePolygon (CompoundCurve (CircularString (1 13, 3 11, 1 9, -1 11, 1 13)),CompoundCurve (CircularString (1 12, 2 11, 1 10, 0 11, 1 12)))'], - ] + tests = [ + [ + QgsPoint(1, 11), + 0, + 45, + -22.5, + 22.5, + 2, + 0, + "CurvePolygon (CompoundCurve (CircularString (0.23463313526982044 12.84775906502257392, 1 13, 1.76536686473017967 12.84775906502257392),(1.76536686473017967 12.84775906502257392, 1 11),(1 11, 0.23463313526982044 12.84775906502257392)))", + ], + [ + QgsPoint(1, 11), + 90, + 45, + 67.5, + 112.5, + 2, + 0, + "CurvePolygon (CompoundCurve (CircularString (2.84775906502257348 11.76536686473017923, 3 11, 2.84775906502257348 10.23463313526982077),(2.84775906502257348 10.23463313526982077, 1 11),(1 11, 2.84775906502257348 11.76536686473017923)))", + ], + [ + QgsPoint(1, 11), + 180, + 90, + 135, + 225, + 2, + 0, + "CurvePolygon (CompoundCurve (CircularString (2.41421356237309492 9.58578643762690419, 1.00000000000000022 9, -0.41421356237309492 9.58578643762690419),(-0.41421356237309492 9.58578643762690419, 1 11),(1 11, 2.41421356237309492 9.58578643762690419)))", + ], + [ + QgsPoint(1, 11), + 0, + 200, + -100, + 100, + 2, + 0, + "CurvePolygon (CompoundCurve (CircularString (-0.96961550602441604 10.65270364466613984, 0.99999999999999956 13, 2.96961550602441626 10.65270364466613984),(2.96961550602441626 10.65270364466613984, 1 11),(1 11, -0.96961550602441604 10.65270364466613984)))", + ], + [ + QgsPoint(1, 11), + 0, + 45, + -22.5, + 22.5, + 2, + 1, + "CurvePolygon (CompoundCurve (CircularString (0.23463313526982044 12.84775906502257392, 1 13, 1.76536686473017967 12.84775906502257392),(1.76536686473017967 12.84775906502257392, 1.38268343236508984 11.92387953251128607),CircularString (1.38268343236508984 11.92387953251128607, 0.99999999999999978 12, 0.61731656763491016 11.92387953251128607),(0.61731656763491016 11.92387953251128607, 0.23463313526982044 12.84775906502257392)))", + ], + [ + QgsPoint(1, 11), + 0, + 200, + -100, + 100, + 2, + 1, + "CurvePolygon (CompoundCurve (CircularString (-0.96961550602441604 10.65270364466613984, 0.99999999999999956 13, 2.96961550602441626 10.65270364466613984),(2.96961550602441626 10.65270364466613984, 1.98480775301220813 10.82635182233306992),CircularString (1.98480775301220813 10.82635182233306992, 0.99999999999999978 12, 0.01519224698779198 10.82635182233306992),(0.01519224698779198 10.82635182233306992, -0.96961550602441604 10.65270364466613984)))", + ], + [ + QgsPoint(1, 11, 3), + 0, + 45, + -22.5, + 22.5, + 2, + 0, + "CurvePolygonZ (CompoundCurveZ (CircularStringZ (0.23463313526982044 12.84775906502257392 3, 1 13 3, 1.76536686473017967 12.84775906502257392 3),(1.76536686473017967 12.84775906502257392 3, 1 11 3),(1 11 3, 0.23463313526982044 12.84775906502257392 3)))", + ], + [ + QgsPoint(1, 11, m=3), + 0, + 45, + -22.5, + 22.5, + 2, + 0, + "CurvePolygonM (CompoundCurveM (CircularStringM (0.23463313526982044 12.84775906502257392 3, 1 13 3, 1.76536686473017967 12.84775906502257392 3),(1.76536686473017967 12.84775906502257392 3, 1 11 3),(1 11 3, 0.23463313526982044 12.84775906502257392 3)))", + ], + [ + QgsPoint(1, 11), + 0, + 360, + -180, + 180, + 2, + 0, + "CurvePolygon (CompoundCurve (CircularString (1 13, 3 11, 1 9, -1 11, 1 13)))", + ], + [ + QgsPoint(1, 11), + 0, + -1000, + 0, + 360, + 2, + 0, + "CurvePolygon (CompoundCurve (CircularString (1 13, 3 11, 1 9, -1 11, 1 13)))", + ], + [ + QgsPoint(1, 11), + 0, + 360, + -180, + 180, + 2, + 1, + "CurvePolygon (CompoundCurve (CircularString (1 13, 3 11, 1 9, -1 11, 1 13)),CompoundCurve (CircularString (1 12, 2 11, 1 10, 0 11, 1 12)))", + ], + ] for t in tests: point = t[0] azimuth = t[1] @@ -6401,31 +11250,59 @@ def testCreateWedgeBuffer(self): outer = t[5] inner = t[6] o1 = QgsGeometry.createWedgeBuffer(point, azimuth, width, outer, inner) - o2 = QgsGeometry.createWedgeBufferFromAngles(point, startAngle, endAngle, outer, inner) + o2 = QgsGeometry.createWedgeBufferFromAngles( + point, startAngle, endAngle, outer, inner + ) exp = t[7] result1 = o1.asWkt() result2 = o2.asWkt() - self.assertTrue(compareWkt(result1, exp, 0.01), - f"wedge buffer from azimuth: mismatch Expected:\n{exp}\nGot:\n{result1}\n") - self.assertTrue(compareWkt(result2, exp, 0.01), - f"wedge buffer from angles: mismatch Expected:\n{exp}\nGot:\n{result2}\n") + self.assertTrue( + compareWkt(result1, exp, 0.01), + f"wedge buffer from azimuth: mismatch Expected:\n{exp}\nGot:\n{result1}\n", + ) + self.assertTrue( + compareWkt(result2, exp, 0.01), + f"wedge buffer from angles: mismatch Expected:\n{exp}\nGot:\n{result2}\n", + ) def testTaperedBuffer(self): - tests = [['LineString (6 2, 9 2, 9 3, 11 5)', 1, 2, 3, - 'MultiPolygon (((5.5 2, 5.56698729810778037 2.24999999999999956, 5.75 2.43301270189221919, 6 2.5, 8.23175255221825708 2.66341629715358597, 8.20710678118654791 3, 8.31333433001913669 3.39644660940672605, 10.13397459621556074 5.49999999999999911, 10.5 5.86602540378443837, 11 6, 11.5 5.86602540378443837, 11.86602540378443926 5.5, 12 5, 11.86602540378443926 4.5, 11.5 4.13397459621556163, 9.76603613070954424 2.63321666219915951, 9.71966991411008863 1.99999999999999978, 9.62325242795870217 1.64016504294495569, 9.35983495705504431 1.37674757204129761, 9 1.28033008588991049, 6 1.5, 5.75 1.56698729810778059, 5.56698729810778037 1.75, 5.5 2)))'], - ['LineString (6 2, 9 2, 9 3, 11 5)', 1, 1, 3, - 'MultiPolygon (((5.5 2, 5.56698729810778037 2.24999999999999956, 5.75 2.43301270189221919, 6 2.5, 8.5 2.5, 8.5 3, 8.56698729810778126 3.24999999999999956, 8.75 3.43301270189221919, 10.75 5.43301270189221963, 11 5.5, 11.25 5.43301270189221874, 11.43301270189221874 5.25, 11.5 5, 11.43301270189221874 4.75, 11.25 4.56698729810778037, 9.5 2.81698729810778081, 9.5 2, 9.43301270189221874 1.75000000000000022, 9.25 1.56698729810778081, 9 1.5, 6 1.5, 5.75 1.56698729810778059, 5.56698729810778037 1.75, 5.5 2)))'], - ['LineString (6 2, 9 2, 9 3, 11 5)', 2, 1, 3, - 'MultiPolygon (((5 2, 5.13397459621556074 2.49999999999999956, 5.5 2.86602540378443837, 6 3, 8.28066508549441238 2.83300216551852069, 8.29289321881345209 3, 8.38762756430420531 3.35355339059327351, 8.64644660940672694 3.61237243569579425, 10.75 5.43301270189221963, 11 5.5, 11.25 5.43301270189221874, 11.43301270189221874 5.25, 11.5 5, 11.43301270189221874 4.75, 9.72358625835961909 2.77494218213953703, 9.78033008588991137 1.99999999999999978, 9.67578567771795583 1.60983495705504498, 9.39016504294495569 1.32421432228204461, 9 1.21966991411008951, 6 1, 5.5 1.13397459621556118, 5.13397459621556163 1.49999999999999978, 5 2)))' - ], - [ - 'MultiLineString ((2 0, 2 2, 3 2, 3 3),(2.94433781190019195 4.04721689059500989, 5.45950095969289784 4.11976967370441471),(3 3, 5.5804222648752404 2.94683301343570214))', - 1, 2, 3, - 'MultiPolygon (((2 -0.5, 1.75 -0.43301270189221935, 1.56698729810778081 -0.25000000000000011, 1.5 0.00000000000000006, 1.25 2, 1.35048094716167078 2.37499999999999956, 1.62499999999999978 2.649519052838329, 2 2.75, 2.03076923076923066 2.75384615384615383, 2 3, 2.13397459621556118 3.49999999999999956, 2.5 3.86602540378443837, 3.00000000000000044 4, 3.50000000000000044 3.86602540378443837, 3.86602540378443837 3.5, 4 3, 3.875 1.99999999999999978, 3.75777222831138413 1.56250000000000044, 3.4375 1.24222777168861631, 3 1.125, 2.64615384615384608 1.1692307692307693, 2.5 -0.00000000000000012, 2.43301270189221963 -0.24999999999999983, 2.25 -0.4330127018922193, 2 -0.5)),((2.69433781190019195 3.6142041887027907, 2.51132511000797276 3.79721689059500989, 2.44433781190019195 4.04721689059500989, 2.51132511000797232 4.29721689059500989, 2.69433781190019195 4.48022959248722952, 2.94433781190019195 4.54721689059500989, 5.45950095969289784 5.11976967370441471, 5.95950095969289784 4.98579507748885309, 6.32552636347733621 4.61976967370441471, 6.45950095969289784 4.11976967370441471, 6.3255263634773371 3.61976967370441516, 5.95950095969289784 3.25374426991997634, 5.45950095969289784 3.11976967370441471, 2.94433781190019195 3.54721689059500989, 2.69433781190019195 3.6142041887027907)),((5.5804222648752404 3.94683301343570214, 6.0804222648752404 3.81285841722014052, 6.44644766865967878 3.44683301343570214, 6.5804222648752404 2.94683301343570214, 6.44644766865967966 2.44683301343570259, 6.0804222648752404 2.08080760965126377, 5.5804222648752404 1.94683301343570214, 3 2.5, 2.75 2.56698729810778081, 2.56698729810778081 2.75, 2.5 3, 2.56698729810778037 3.24999999999999956, 2.75 3.43301270189221919, 3 3.5, 5.5804222648752404 3.94683301343570214)))'], - ['LineString (6 2, 9 2, 9 3, 11 5)', 2, 7, 3, - 'MultiPolygon (((5.13397459621556163 1.49999999999999978, 5 2, 5.13397459621556074 2.49999999999999956, 5.5 2.86602540378443837, 6.61565808125483201 3.29902749321661304, 6.86570975577233966 4.23223304703362935, 7.96891108675446347 6.74999999999999822, 9.25 8.03108891324553475, 11 8.5, 12.75000000000000178 8.03108891324553475, 14.03108891324553475 6.75, 14.5 4.99999999999999911, 14.03108891324553653 3.25000000000000133, 12.75 1.9689110867544648, 10.86920158655618174 1.1448080812814232, 10.81722403411685463 0.95082521472477743, 10.04917478527522334 0.18277596588314599, 9 -0.09834957055044669, 7.95082521472477666 0.18277596588314587, 5.5 1.13397459621556118, 5.13397459621556163 1.49999999999999978)))' - ], - ] + tests = [ + [ + "LineString (6 2, 9 2, 9 3, 11 5)", + 1, + 2, + 3, + "MultiPolygon (((5.5 2, 5.56698729810778037 2.24999999999999956, 5.75 2.43301270189221919, 6 2.5, 8.23175255221825708 2.66341629715358597, 8.20710678118654791 3, 8.31333433001913669 3.39644660940672605, 10.13397459621556074 5.49999999999999911, 10.5 5.86602540378443837, 11 6, 11.5 5.86602540378443837, 11.86602540378443926 5.5, 12 5, 11.86602540378443926 4.5, 11.5 4.13397459621556163, 9.76603613070954424 2.63321666219915951, 9.71966991411008863 1.99999999999999978, 9.62325242795870217 1.64016504294495569, 9.35983495705504431 1.37674757204129761, 9 1.28033008588991049, 6 1.5, 5.75 1.56698729810778059, 5.56698729810778037 1.75, 5.5 2)))", + ], + [ + "LineString (6 2, 9 2, 9 3, 11 5)", + 1, + 1, + 3, + "MultiPolygon (((5.5 2, 5.56698729810778037 2.24999999999999956, 5.75 2.43301270189221919, 6 2.5, 8.5 2.5, 8.5 3, 8.56698729810778126 3.24999999999999956, 8.75 3.43301270189221919, 10.75 5.43301270189221963, 11 5.5, 11.25 5.43301270189221874, 11.43301270189221874 5.25, 11.5 5, 11.43301270189221874 4.75, 11.25 4.56698729810778037, 9.5 2.81698729810778081, 9.5 2, 9.43301270189221874 1.75000000000000022, 9.25 1.56698729810778081, 9 1.5, 6 1.5, 5.75 1.56698729810778059, 5.56698729810778037 1.75, 5.5 2)))", + ], + [ + "LineString (6 2, 9 2, 9 3, 11 5)", + 2, + 1, + 3, + "MultiPolygon (((5 2, 5.13397459621556074 2.49999999999999956, 5.5 2.86602540378443837, 6 3, 8.28066508549441238 2.83300216551852069, 8.29289321881345209 3, 8.38762756430420531 3.35355339059327351, 8.64644660940672694 3.61237243569579425, 10.75 5.43301270189221963, 11 5.5, 11.25 5.43301270189221874, 11.43301270189221874 5.25, 11.5 5, 11.43301270189221874 4.75, 9.72358625835961909 2.77494218213953703, 9.78033008588991137 1.99999999999999978, 9.67578567771795583 1.60983495705504498, 9.39016504294495569 1.32421432228204461, 9 1.21966991411008951, 6 1, 5.5 1.13397459621556118, 5.13397459621556163 1.49999999999999978, 5 2)))", + ], + [ + "MultiLineString ((2 0, 2 2, 3 2, 3 3),(2.94433781190019195 4.04721689059500989, 5.45950095969289784 4.11976967370441471),(3 3, 5.5804222648752404 2.94683301343570214))", + 1, + 2, + 3, + "MultiPolygon (((2 -0.5, 1.75 -0.43301270189221935, 1.56698729810778081 -0.25000000000000011, 1.5 0.00000000000000006, 1.25 2, 1.35048094716167078 2.37499999999999956, 1.62499999999999978 2.649519052838329, 2 2.75, 2.03076923076923066 2.75384615384615383, 2 3, 2.13397459621556118 3.49999999999999956, 2.5 3.86602540378443837, 3.00000000000000044 4, 3.50000000000000044 3.86602540378443837, 3.86602540378443837 3.5, 4 3, 3.875 1.99999999999999978, 3.75777222831138413 1.56250000000000044, 3.4375 1.24222777168861631, 3 1.125, 2.64615384615384608 1.1692307692307693, 2.5 -0.00000000000000012, 2.43301270189221963 -0.24999999999999983, 2.25 -0.4330127018922193, 2 -0.5)),((2.69433781190019195 3.6142041887027907, 2.51132511000797276 3.79721689059500989, 2.44433781190019195 4.04721689059500989, 2.51132511000797232 4.29721689059500989, 2.69433781190019195 4.48022959248722952, 2.94433781190019195 4.54721689059500989, 5.45950095969289784 5.11976967370441471, 5.95950095969289784 4.98579507748885309, 6.32552636347733621 4.61976967370441471, 6.45950095969289784 4.11976967370441471, 6.3255263634773371 3.61976967370441516, 5.95950095969289784 3.25374426991997634, 5.45950095969289784 3.11976967370441471, 2.94433781190019195 3.54721689059500989, 2.69433781190019195 3.6142041887027907)),((5.5804222648752404 3.94683301343570214, 6.0804222648752404 3.81285841722014052, 6.44644766865967878 3.44683301343570214, 6.5804222648752404 2.94683301343570214, 6.44644766865967966 2.44683301343570259, 6.0804222648752404 2.08080760965126377, 5.5804222648752404 1.94683301343570214, 3 2.5, 2.75 2.56698729810778081, 2.56698729810778081 2.75, 2.5 3, 2.56698729810778037 3.24999999999999956, 2.75 3.43301270189221919, 3 3.5, 5.5804222648752404 3.94683301343570214)))", + ], + [ + "LineString (6 2, 9 2, 9 3, 11 5)", + 2, + 7, + 3, + "MultiPolygon (((5.13397459621556163 1.49999999999999978, 5 2, 5.13397459621556074 2.49999999999999956, 5.5 2.86602540378443837, 6.61565808125483201 3.29902749321661304, 6.86570975577233966 4.23223304703362935, 7.96891108675446347 6.74999999999999822, 9.25 8.03108891324553475, 11 8.5, 12.75000000000000178 8.03108891324553475, 14.03108891324553475 6.75, 14.5 4.99999999999999911, 14.03108891324553653 3.25000000000000133, 12.75 1.9689110867544648, 10.86920158655618174 1.1448080812814232, 10.81722403411685463 0.95082521472477743, 10.04917478527522334 0.18277596588314599, 9 -0.09834957055044669, 7.95082521472477666 0.18277596588314587, 5.5 1.13397459621556118, 5.13397459621556163 1.49999999999999978)))", + ], + ] for t in tests: input = QgsGeometry.fromWkt(t[0]) start = t[1] @@ -6436,13 +11313,27 @@ def testTaperedBuffer(self): exp = QgsGeometry.fromWkt(t[4]) exp.normalize() result = o.asWkt() - self.assertTrue(compareWkt(result, exp.asWkt(), 0.02), - f"tapered buffer: mismatch Expected:\n{exp.asWkt()}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp.asWkt(), 0.02), + f"tapered buffer: mismatch Expected:\n{exp.asWkt()}\nGot:\n{result}\n", + ) - curved_tests = [['CompoundCurve (CircularString (6 2, 9 2, 9 3))', 2, 7, 3, - 'MultiPolygon (((4.97 1.7, 4.97 1.72, 4.97 1.74, 4.'], - ['MultiCurve (CompoundCurve (CircularString (6 2, 9 2, 9 3)))', 2, 7, 3, - 'MultiPolygon (((4.97 1.7, 4.97 1.72, 4.97 1.74, 4.']] + curved_tests = [ + [ + "CompoundCurve (CircularString (6 2, 9 2, 9 3))", + 2, + 7, + 3, + "MultiPolygon (((4.97 1.7, 4.97 1.72, 4.97 1.74, 4.", + ], + [ + "MultiCurve (CompoundCurve (CircularString (6 2, 9 2, 9 3)))", + 2, + 7, + 3, + "MultiPolygon (((4.97 1.7, 4.97 1.72, 4.97 1.74, 4.", + ], + ] for t in curved_tests: input = QgsGeometry.fromWkt(t[0]) @@ -6455,12 +11346,19 @@ def testTaperedBuffer(self): self.assertEqual(result[:50], t[4]) def testVariableWidthBufferByM(self): - tests = [['LineString (6 2, 9 2, 9 3, 11 5)', 3, 'GeometryCollection EMPTY'], - ['LineStringM (6 2 1, 9 2 1.5, 9 3 0.5, 11 5 2)', 3, - 'MultiPolygon (((5.5 2, 5.56698729810778037 2.24999999999999956, 5.75 2.43301270189221919, 6 2.5, 8.54510095773215994 2.71209174647768014, 8.78349364905388974 3.125, 10.13397459621556074 5.49999999999999911, 10.5 5.86602540378443837, 11 6, 11.5 5.86602540378443837, 11.86602540378443926 5.5, 12 5, 11.86602540378443926 4.5, 11.5 4.13397459621556163, 9.34232758349701164 2.90707123255090094, 9.649519052838329 2.375, 9.75 1.99999999999999978, 9.649519052838329 1.62500000000000022, 9.375 1.350480947161671, 9 1.25, 6 1.5, 5.75 1.56698729810778059, 5.56698729810778037 1.75, 5.5 2)))'], - ['MultiLineStringM ((6 2 1, 9 2 1.5, 9 3 0.5, 11 5 2),(1 2 0.5, 3 2 0.2))', 3, - 'MultiPolygon (((5.5 2, 5.56698729810778037 2.24999999999999956, 5.75 2.43301270189221919, 6 2.5, 8.54510095773215994 2.71209174647768014, 8.78349364905388974 3.125, 10.13397459621556074 5.49999999999999911, 10.5 5.86602540378443837, 11 6, 11.5 5.86602540378443837, 11.86602540378443926 5.5, 12 5, 11.86602540378443926 4.5, 11.5 4.13397459621556163, 9.34232758349701164 2.90707123255090094, 9.649519052838329 2.375, 9.75 1.99999999999999978, 9.649519052838329 1.62500000000000022, 9.375 1.350480947161671, 9 1.25, 6 1.5, 5.75 1.56698729810778059, 5.56698729810778037 1.75, 5.5 2)),((0.875 1.78349364905389041, 0.78349364905389041 1.875, 0.75 2, 0.7834936490538903 2.125, 0.875 2.21650635094610982, 1 2.25, 3 2.10000000000000009, 3.04999999999999982 2.08660254037844384, 3.08660254037844384 2.04999999999999982, 3.10000000000000009 2, 3.08660254037844384 1.94999999999999996, 3.04999999999999982 1.91339745962155616, 3 1.89999999999999991, 1 1.75, 0.875 1.78349364905389041)))'] - ] + tests = [ + ["LineString (6 2, 9 2, 9 3, 11 5)", 3, "GeometryCollection EMPTY"], + [ + "LineStringM (6 2 1, 9 2 1.5, 9 3 0.5, 11 5 2)", + 3, + "MultiPolygon (((5.5 2, 5.56698729810778037 2.24999999999999956, 5.75 2.43301270189221919, 6 2.5, 8.54510095773215994 2.71209174647768014, 8.78349364905388974 3.125, 10.13397459621556074 5.49999999999999911, 10.5 5.86602540378443837, 11 6, 11.5 5.86602540378443837, 11.86602540378443926 5.5, 12 5, 11.86602540378443926 4.5, 11.5 4.13397459621556163, 9.34232758349701164 2.90707123255090094, 9.649519052838329 2.375, 9.75 1.99999999999999978, 9.649519052838329 1.62500000000000022, 9.375 1.350480947161671, 9 1.25, 6 1.5, 5.75 1.56698729810778059, 5.56698729810778037 1.75, 5.5 2)))", + ], + [ + "MultiLineStringM ((6 2 1, 9 2 1.5, 9 3 0.5, 11 5 2),(1 2 0.5, 3 2 0.2))", + 3, + "MultiPolygon (((5.5 2, 5.56698729810778037 2.24999999999999956, 5.75 2.43301270189221919, 6 2.5, 8.54510095773215994 2.71209174647768014, 8.78349364905388974 3.125, 10.13397459621556074 5.49999999999999911, 10.5 5.86602540378443837, 11 6, 11.5 5.86602540378443837, 11.86602540378443926 5.5, 12 5, 11.86602540378443926 4.5, 11.5 4.13397459621556163, 9.34232758349701164 2.90707123255090094, 9.649519052838329 2.375, 9.75 1.99999999999999978, 9.649519052838329 1.62500000000000022, 9.375 1.350480947161671, 9 1.25, 6 1.5, 5.75 1.56698729810778059, 5.56698729810778037 1.75, 5.5 2)),((0.875 1.78349364905389041, 0.78349364905389041 1.875, 0.75 2, 0.7834936490538903 2.125, 0.875 2.21650635094610982, 1 2.25, 3 2.10000000000000009, 3.04999999999999982 2.08660254037844384, 3.08660254037844384 2.04999999999999982, 3.10000000000000009 2, 3.08660254037844384 1.94999999999999996, 3.04999999999999982 1.91339745962155616, 3 1.89999999999999991, 1 1.75, 0.875 1.78349364905389041)))", + ], + ] for t in tests: input = QgsGeometry.fromWkt(t[0]) segments = t[1] @@ -6469,28 +11367,47 @@ def testVariableWidthBufferByM(self): exp = QgsGeometry.fromWkt(t[2]) exp.normalize() result = o.asWkt() - self.assertTrue(compareWkt(result, exp.asWkt(), 0.01), - f"tapered buffer: mismatch Expected:\n{exp.asWkt()}\nGot:\n{result}\n") + self.assertTrue( + compareWkt(result, exp.asWkt(), 0.01), + f"tapered buffer: mismatch Expected:\n{exp.asWkt()}\nGot:\n{result}\n", + ) def testHausdorff(self): - tests = [["POLYGON((0 0, 0 2, 1 2, 2 2, 2 0, 0 0))", - "POLYGON((0.5 0.5, 0.5 2.5, 1.5 2.5, 2.5 2.5, 2.5 0.5, 0.5 0.5))", 0.707106781186548], - ["LINESTRING (0 0, 2 1)", "LINESTRING (0 0, 2 0)", 1], - ["LINESTRING (0 0, 2 0)", "LINESTRING (0 1, 1 2, 2 1)", 2], - ["LINESTRING (0 0, 2 0)", "MULTIPOINT (0 1, 1 0, 2 1)", 1], - ["LINESTRING (130 0, 0 0, 0 150)", "LINESTRING (10 10, 10 150, 130 10)", 14.142135623730951] - ] + tests = [ + [ + "POLYGON((0 0, 0 2, 1 2, 2 2, 2 0, 0 0))", + "POLYGON((0.5 0.5, 0.5 2.5, 1.5 2.5, 2.5 2.5, 2.5 0.5, 0.5 0.5))", + 0.707106781186548, + ], + ["LINESTRING (0 0, 2 1)", "LINESTRING (0 0, 2 0)", 1], + ["LINESTRING (0 0, 2 0)", "LINESTRING (0 1, 1 2, 2 1)", 2], + ["LINESTRING (0 0, 2 0)", "MULTIPOINT (0 1, 1 0, 2 1)", 1], + [ + "LINESTRING (130 0, 0 0, 0 150)", + "LINESTRING (10 10, 10 150, 130 10)", + 14.142135623730951, + ], + ] for t in tests: g1 = QgsGeometry.fromWkt(t[0]) g2 = QgsGeometry.fromWkt(t[1]) o = g1.hausdorffDistance(g2) exp = t[2] - self.assertAlmostEqual(o, exp, 5, - f"mismatch for {t[0]} to {t[1]}, expected:\n{exp}\nGot:\n{o}\n") + self.assertAlmostEqual( + o, + exp, + 5, + f"mismatch for {t[0]} to {t[1]}, expected:\n{exp}\nGot:\n{o}\n", + ) def testHausdorffDensify(self): tests = [ - ["LINESTRING (130 0, 0 0, 0 150)", "LINESTRING (10 10, 10 150, 130 10)", 0.5, 70.0] + [ + "LINESTRING (130 0, 0 0, 0 150)", + "LINESTRING (10 10, 10 150, 130 10)", + 0.5, + 70.0, + ] ] for t in tests: g1 = QgsGeometry.fromWkt(t[0]) @@ -6498,54 +11415,101 @@ def testHausdorffDensify(self): densify = t[2] o = g1.hausdorffDistanceDensify(g2, densify) exp = t[3] - self.assertAlmostEqual(o, exp, 5, - f"mismatch for {t[0]} to {t[1]}, expected:\n{exp}\nGot:\n{o}\n") + self.assertAlmostEqual( + o, + exp, + 5, + f"mismatch for {t[0]} to {t[1]}, expected:\n{exp}\nGot:\n{o}\n", + ) def testConvertToCurves(self): tests = [ [ "LINESTRING Z (3 3 3,2.4142135623731 1.58578643762691 3,1 1 3,-0.414213562373092 1.5857864376269 3,-1 2.99999999999999 3,-0.414213562373101 4.41421356237309 3,0.999999999999991 5 3,2.41421356237309 4.4142135623731 3,3 3 3)", - "CircularStringZ (3 3 3, -1 2.99999999999998979 3, 3 3 3)", 0.00000001, 0.0000001], - ["LINESTRING(0 0,10 0,10 10,0 10,0 0)", "CompoundCurve((0 0,10 0,10 10,0 10,0 0))", 0.00000001, 0.00000001], - ["LINESTRING(0 0,10 0,10 10,0 10)", "CompoundCurve((0 0,10 0,10 10,0 10))", 0.00000001, 0.00000001], - ["LINESTRING(10 10,0 10,0 0,10 0)", "CompoundCurve((10 10,0 10,0 0,10 0))", 0.0000001, 0.00000001], - ["LINESTRING(0 0, 1 1)", "CompoundCurve((0 0, 1 1))", 0.00000001, 0.00000001], - ["GEOMETRYCOLLECTION(LINESTRING(10 10,10 11),LINESTRING(10 11,11 11),LINESTRING(11 11,10 10))", - "MultiCurve (CompoundCurve ((10 10, 10 11)),CompoundCurve ((10 11, 11 11)),CompoundCurve ((11 11, 10 10)))", - 0.000001, 0.000001], - ["GEOMETRYCOLLECTION(LINESTRING(4 4,4 8),CIRCULARSTRING(4 8,6 10,8 8),LINESTRING(8 8,8 4))", - "MultiCurve (CompoundCurve ((4 4, 4 8)),CircularString (4 8, 6 10, 8 8),CompoundCurve ((8 8, 8 4)))", - 0.0000001, 0.0000001], + "CircularStringZ (3 3 3, -1 2.99999999999998979 3, 3 3 3)", + 0.00000001, + 0.0000001, + ], + [ + "LINESTRING(0 0,10 0,10 10,0 10,0 0)", + "CompoundCurve((0 0,10 0,10 10,0 10,0 0))", + 0.00000001, + 0.00000001, + ], + [ + "LINESTRING(0 0,10 0,10 10,0 10)", + "CompoundCurve((0 0,10 0,10 10,0 10))", + 0.00000001, + 0.00000001, + ], + [ + "LINESTRING(10 10,0 10,0 0,10 0)", + "CompoundCurve((10 10,0 10,0 0,10 0))", + 0.0000001, + 0.00000001, + ], + [ + "LINESTRING(0 0, 1 1)", + "CompoundCurve((0 0, 1 1))", + 0.00000001, + 0.00000001, + ], + [ + "GEOMETRYCOLLECTION(LINESTRING(10 10,10 11),LINESTRING(10 11,11 11),LINESTRING(11 11,10 10))", + "MultiCurve (CompoundCurve ((10 10, 10 11)),CompoundCurve ((10 11, 11 11)),CompoundCurve ((11 11, 10 10)))", + 0.000001, + 0.000001, + ], + [ + "GEOMETRYCOLLECTION(LINESTRING(4 4,4 8),CIRCULARSTRING(4 8,6 10,8 8),LINESTRING(8 8,8 4))", + "MultiCurve (CompoundCurve ((4 4, 4 8)),CircularString (4 8, 6 10, 8 8),CompoundCurve ((8 8, 8 4)))", + 0.0000001, + 0.0000001, + ], [ "LINESTRING(-13151357.927248 3913656.64539871,-13151419.0845266 3913664.12016378,-13151441.323537 3913666.61175286,-13151456.8908442 3913666.61175286,-13151476.9059536 3913666.61175286,-13151496.921063 3913666.61175287,-13151521.3839744 3913666.61175287,-13151591.4368571 3913665.36595828)", "CompoundCurve ((-13151357.92724799923598766 3913656.64539870992302895, -13151419.08452660031616688 3913664.12016378017142415, -13151441.32353699952363968 3913666.61175285978242755, -13151456.8908441998064518 3913666.61175285978242755, -13151476.90595359914004803 3913666.61175285978242755, -13151496.92106300033628941 3913666.61175287002697587, -13151521.38397439941763878 3913666.61175287002697587, -13151591.43685710057616234 3913665.36595827993005514))", - 0.000001, 0.0000001], + 0.000001, + 0.0000001, + ], ["Point( 1 2 )", "Point( 1 2 )", 0.00001, 0.00001], ["MultiPoint( 1 2, 3 4 )", "MultiPoint( (1 2 ), (3 4 ))", 0.00001, 0.00001], # A polygon converts to curve [ "POLYGON((3 3,2.4142135623731 1.58578643762691,1 1,-0.414213562373092 1.5857864376269,-1 2.99999999999999,-0.414213562373101 4.41421356237309,0.999999999999991 5,2.41421356237309 4.4142135623731,3 3))", - "CurvePolygon (CircularString (3 3, -1 2.99999999999998979, 3 3))", 0.00000001, - 0.00000001], + "CurvePolygon (CircularString (3 3, -1 2.99999999999998979, 3 3))", + 0.00000001, + 0.00000001, + ], # The same polygon, even if already CURVEPOLYGON, still converts to curve [ "CURVEPOLYGON((3 3,2.4142135623731 1.58578643762691,1 1,-0.414213562373092 1.5857864376269,-1 2.99999999999999,-0.414213562373101 4.41421356237309,0.999999999999991 5,2.41421356237309 4.4142135623731,3 3))", - "CurvePolygon (CircularString (3 3, -1 2.99999999999998979, 3 3))", 0.00000001, - 0.00000001], - ["CurvePolygon (CompoundCurve (CircularString (2613627 1178798, 2613639 1178805, 2613648 1178794),(2613648 1178794, 2613627 1178798)))", - "CurvePolygon (CompoundCurve (CircularString (2613627 1178798, 2613639 1178805, 2613648 1178794),(2613648 1178794, 2613627 1178798)))", - 0.00000001, 0.000000001], - ["CurvePolygon (CompoundCurve ((2653264.45800000010058284 1213405.36899999994784594, 2653279.07700000004842877 1213383.28700000001117587, 2653278.33142686076462269 1213384.25132044195197523, 2653277.59772348683327436 1213385.22470247372984886, 2653276.87600000016391277 1213386.20699999993667006))", - "CurvePolygon (CompoundCurve ((2653264.45800000010058284 1213405.36899999994784594, 2653279.07700000004842877 1213383.28700000001117587),CircularString (2653279.07700000004842877 1213383.28700000001117587, 2653278.33142686076462269 1213384.25132044195197523, 2653276.87600000016391277 1213386.20699999993667006)))", - 0.00000001, 0.000000001] + "CurvePolygon (CircularString (3 3, -1 2.99999999999998979, 3 3))", + 0.00000001, + 0.00000001, + ], + [ + "CurvePolygon (CompoundCurve (CircularString (2613627 1178798, 2613639 1178805, 2613648 1178794),(2613648 1178794, 2613627 1178798)))", + "CurvePolygon (CompoundCurve (CircularString (2613627 1178798, 2613639 1178805, 2613648 1178794),(2613648 1178794, 2613627 1178798)))", + 0.00000001, + 0.000000001, + ], + [ + "CurvePolygon (CompoundCurve ((2653264.45800000010058284 1213405.36899999994784594, 2653279.07700000004842877 1213383.28700000001117587, 2653278.33142686076462269 1213384.25132044195197523, 2653277.59772348683327436 1213385.22470247372984886, 2653276.87600000016391277 1213386.20699999993667006))", + "CurvePolygon (CompoundCurve ((2653264.45800000010058284 1213405.36899999994784594, 2653279.07700000004842877 1213383.28700000001117587),CircularString (2653279.07700000004842877 1213383.28700000001117587, 2653278.33142686076462269 1213384.25132044195197523, 2653276.87600000016391277 1213386.20699999993667006)))", + 0.00000001, + 0.000000001, + ], ] for t in tests: g1 = QgsGeometry.fromWkt(t[0]) distance_tolerance = t[2] angle_tolerance = t[3] o = g1.convertToCurves(distance_tolerance, angle_tolerance) - self.assertTrue(compareWkt(o.asWkt(), t[1], 0.00001), - f"clipped: mismatch Expected:\n{t[1]}\nGot:\n{o.asWkt()}\n") + self.assertTrue( + compareWkt(o.asWkt(), t[1], 0.00001), + f"clipped: mismatch Expected:\n{t[1]}\nGot:\n{o.asWkt()}\n", + ) def testBoundingBoxIntersects(self): tests = [ @@ -6553,15 +11517,19 @@ def testBoundingBoxIntersects(self): ["LINESTRING (0 0, 100 100)", "LINESTRING (101 0, 102 0)", False], ["POINT(20 1)", "LINESTRING( 0 0, 100 100 )", True], ["POINT(20 1)", "POINT(21 1)", False], - ["POINT(20 1)", "POINT(20 1)", True] + ["POINT(20 1)", "POINT(20 1)", True], ] for t in tests: g1 = QgsGeometry.fromWkt(t[0]) g2 = QgsGeometry.fromWkt(t[1]) res = g1.boundingBoxIntersects(g2) - self.assertEqual(res, t[2], - "mismatch for {} to {}, expected:\n{}\nGot:\n{}\n".format(g1.asWkt(), g2.asWkt(), t[2], - res)) + self.assertEqual( + res, + t[2], + "mismatch for {} to {}, expected:\n{}\nGot:\n{}\n".format( + g1.asWkt(), g2.asWkt(), t[2], res + ), + ) def testBoundingBoxIntersectsRectangle(self): tests = [ @@ -6569,34 +11537,63 @@ def testBoundingBoxIntersectsRectangle(self): ["LINESTRING (0 0, 100 100)", QgsRectangle(101, 0, 102, 10), False], ["POINT(20 1)", QgsRectangle(0, 0, 100, 100), True], ["POINT(20 1)", QgsRectangle(21, 1, 21, 1), False], - ["POINT(20 1)", QgsRectangle(20, 1, 20, 1), True] + ["POINT(20 1)", QgsRectangle(20, 1, 20, 1), True], ] for t in tests: g1 = QgsGeometry.fromWkt(t[0]) res = g1.boundingBoxIntersects(t[1]) - self.assertEqual(res, t[2], - "mismatch for {} to {}, expected:\n{}\nGot:\n{}\n".format(g1.asWkt(), t[1].toString(), - t[2], res)) + self.assertEqual( + res, + t[2], + "mismatch for {} to {}, expected:\n{}\nGot:\n{}\n".format( + g1.asWkt(), t[1].toString(), t[2], res + ), + ) def testOffsetCurve(self): tests = [ - ["LINESTRING (0 0, 0 100, 100 100)", 1, ["LineString (-1 0, -1 101, 100 101)"]], - ["LINESTRING (0 0, 0 100, 100 100)", -1, ["LineString (1 0, 1 99, 100 99)"]], + [ + "LINESTRING (0 0, 0 100, 100 100)", + 1, + ["LineString (-1 0, -1 101, 100 101)"], + ], + [ + "LINESTRING (0 0, 0 100, 100 100)", + -1, + ["LineString (1 0, 1 99, 100 99)"], + ], ["LINESTRING (100 100, 0 100, 0 0)", 1, ["LineString (100 99, 1 99, 1 0)"]], - ["LINESTRING (100 100, 0 100, 0 0)", -1, ["LineString (100 101, -1 101, -1 0)"]], - ["LINESTRING (259329.820 5928370.79, 259324.337 5928371.758, 259319.678 5928372.33, 259317.064 5928372.498 )", 100, ["LineString (259312.4 5928272.3, 259309.5 5928272.8, 259307.5 5928273.1, 259307.5 5928273.2)", - "LineString (259312.5 5928272.6, 259312.4 5928272.3, 259309.5 5928272.8, 259307.5 5928273.1, 259313.6 5928322.7, 259313.9 5928322.7)", - "MultiLineString ((259313.3 5928272.5, 259312.5 5928272.6),(259312.4 5928272.3, 259309.5 5928272.8, 259307.5 5928273.1))"]], - ["MULTILINESTRING ((0 0, 0 100, 100 100),(100 100, 0 100, 0 0))", 1, - "MultiLineString ((-1 0, -1 101, 100 101),(100 99, 1 99, 1 0))"] + [ + "LINESTRING (100 100, 0 100, 0 0)", + -1, + ["LineString (100 101, -1 101, -1 0)"], + ], + [ + "LINESTRING (259329.820 5928370.79, 259324.337 5928371.758, 259319.678 5928372.33, 259317.064 5928372.498 )", + 100, + [ + "LineString (259312.4 5928272.3, 259309.5 5928272.8, 259307.5 5928273.1, 259307.5 5928273.2)", + "LineString (259312.5 5928272.6, 259312.4 5928272.3, 259309.5 5928272.8, 259307.5 5928273.1, 259313.6 5928322.7, 259313.9 5928322.7)", + "MultiLineString ((259313.3 5928272.5, 259312.5 5928272.6),(259312.4 5928272.3, 259309.5 5928272.8, 259307.5 5928273.1))", + ], + ], + [ + "MULTILINESTRING ((0 0, 0 100, 100 100),(100 100, 0 100, 0 0))", + 1, + "MultiLineString ((-1 0, -1 101, 100 101),(100 99, 1 99, 1 0))", + ], ] for t in tests: g1 = QgsGeometry.fromWkt(t[0]) res = g1.offsetCurve(t[1], 2, QgsGeometry.JoinStyle.JoinStyleMiter, 5) - self.assertIn(res.asWkt(1), t[2], - "mismatch for {} to {}, expected:\n{}\nGot:\n{}\n".format(t[0], t[1], - t[2], res.asWkt(1))) + self.assertIn( + res.asWkt(1), + t[2], + "mismatch for {} to {}, expected:\n{}\nGot:\n{}\n".format( + t[0], t[1], t[2], res.asWkt(1) + ), + ) def testForceRHR(self): tests = [ @@ -6604,19 +11601,27 @@ def testForceRHR(self): ["Point (100 100)", "Point (100 100)"], ["LINESTRING (0 0, 0 100, 100 100)", "LineString (0 0, 0 100, 100 100)"], ["LINESTRING (100 100, 0 100, 0 0)", "LineString (100 100, 0 100, 0 0)"], - ["POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1))", "Polygon ((-1 -1, 0 2, 4 2, 4 0, -1 -1))"], + [ + "POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1))", + "Polygon ((-1 -1, 0 2, 4 2, 4 0, -1 -1))", + ], [ "MULTIPOLYGON(Polygon((-1 -1, 4 0, 4 2, 0 2, -1 -1)),Polygon((100 100, 200 100, 200 200, 100 200, 100 100)))", - "MultiPolygon (((-1 -1, 0 2, 4 2, 4 0, -1 -1)),((100 100, 100 200, 200 200, 200 100, 100 100)))"], + "MultiPolygon (((-1 -1, 0 2, 4 2, 4 0, -1 -1)),((100 100, 100 200, 200 200, 200 100, 100 100)))", + ], [ "GeometryCollection(Polygon((-1 -1, 4 0, 4 2, 0 2, -1 -1)),Polygon((100 100, 200 100, 200 200, 100 200, 100 100)))", - "GeometryCollection (Polygon ((-1 -1, 0 2, 4 2, 4 0, -1 -1)),Polygon ((100 100, 100 200, 200 200, 200 100, 100 100)))"] + "GeometryCollection (Polygon ((-1 -1, 0 2, 4 2, 4 0, -1 -1)),Polygon ((100 100, 100 200, 200 200, 200 100, 100 100)))", + ], ] for t in tests: g1 = QgsGeometry.fromWkt(t[0]) res = g1.forceRHR() - self.assertEqual(res.asWkt(1), t[1], - f"mismatch for {t[0]}, expected:\n{t[1]}\nGot:\n{res.asWkt(1)}\n") + self.assertEqual( + res.asWkt(1), + t[1], + f"mismatch for {t[0]}, expected:\n{t[1]}\nGot:\n{res.asWkt(1)}\n", + ) def testForceCW(self): tests = [ @@ -6624,19 +11629,27 @@ def testForceCW(self): ["Point (100 100)", "Point (100 100)"], ["LINESTRING (0 0, 0 100, 100 100)", "LineString (0 0, 0 100, 100 100)"], ["LINESTRING (100 100, 0 100, 0 0)", "LineString (100 100, 0 100, 0 0)"], - ["POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1))", "Polygon ((-1 -1, 0 2, 4 2, 4 0, -1 -1))"], + [ + "POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1))", + "Polygon ((-1 -1, 0 2, 4 2, 4 0, -1 -1))", + ], [ "MULTIPOLYGON(Polygon((-1 -1, 4 0, 4 2, 0 2, -1 -1)),Polygon((100 100, 200 100, 200 200, 100 200, 100 100)))", - "MultiPolygon (((-1 -1, 0 2, 4 2, 4 0, -1 -1)),((100 100, 100 200, 200 200, 200 100, 100 100)))"], + "MultiPolygon (((-1 -1, 0 2, 4 2, 4 0, -1 -1)),((100 100, 100 200, 200 200, 200 100, 100 100)))", + ], [ "GeometryCollection(Polygon((-1 -1, 4 0, 4 2, 0 2, -1 -1)),Polygon((100 100, 200 100, 200 200, 100 200, 100 100)))", - "GeometryCollection (Polygon ((-1 -1, 0 2, 4 2, 4 0, -1 -1)),Polygon ((100 100, 100 200, 200 200, 200 100, 100 100)))"] + "GeometryCollection (Polygon ((-1 -1, 0 2, 4 2, 4 0, -1 -1)),Polygon ((100 100, 100 200, 200 200, 200 100, 100 100)))", + ], ] for t in tests: g1 = QgsGeometry.fromWkt(t[0]) res = g1.forcePolygonClockwise() - self.assertEqual(res.asWkt(1), t[1], - f"mismatch for {t[0]}, expected:\n{t[1]}\nGot:\n{res.asWkt(1)}\n") + self.assertEqual( + res.asWkt(1), + t[1], + f"mismatch for {t[0]}, expected:\n{t[1]}\nGot:\n{res.asWkt(1)}\n", + ) def testForceCCW(self): tests = [ @@ -6644,82 +11657,181 @@ def testForceCCW(self): ["Point (100 100)", "Point (100 100)"], ["LINESTRING (0 0, 0 100, 100 100)", "LineString (0 0, 0 100, 100 100)"], ["LINESTRING (100 100, 0 100, 0 0)", "LineString (100 100, 0 100, 0 0)"], - ["POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1))", "Polygon ((-1 -1, 4 0, 4 2, 0 2, -1 -1))"], + [ + "POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1))", + "Polygon ((-1 -1, 4 0, 4 2, 0 2, -1 -1))", + ], [ "MULTIPOLYGON(Polygon((-1 -1, 4 0, 4 2, 0 2, -1 -1)),Polygon((100 100, 200 100, 200 200, 100 200, 100 100)))", - "MultiPolygon (((-1 -1, 4 0, 4 2, 0 2, -1 -1)),((100 100, 200 100, 200 200, 100 200, 100 100)))"], + "MultiPolygon (((-1 -1, 4 0, 4 2, 0 2, -1 -1)),((100 100, 200 100, 200 200, 100 200, 100 100)))", + ], [ "GeometryCollection(Polygon((-1 -1, 4 0, 4 2, 0 2, -1 -1)),Polygon((100 100, 200 100, 200 200, 100 200, 100 100)))", - "GeometryCollection (Polygon ((-1 -1, 4 0, 4 2, 0 2, -1 -1)),Polygon ((100 100, 200 100, 200 200, 100 200, 100 100)))"] + "GeometryCollection (Polygon ((-1 -1, 4 0, 4 2, 0 2, -1 -1)),Polygon ((100 100, 200 100, 200 200, 100 200, 100 100)))", + ], ] for t in tests: g1 = QgsGeometry.fromWkt(t[0]) res = g1.forcePolygonCounterClockwise() - self.assertEqual(res.asWkt(1), t[1], - f"mismatch for {t[0]}, expected:\n{t[1]}\nGot:\n{res.asWkt(1)}\n") + self.assertEqual( + res.asWkt(1), + t[1], + f"mismatch for {t[0]}, expected:\n{t[1]}\nGot:\n{res.asWkt(1)}\n", + ) def testLineStringFromBezier(self): tests = [ - [QgsPoint(1, 1), QgsPoint(10, 1), QgsPoint(10, 10), QgsPoint(20, 10), 5, - 'LineString (1 1, 5.5 1.9, 8.7 4.2, 11.6 6.8, 15 9.1, 20 10)'], - [QgsPoint(1, 1), QgsPoint(10, 1), QgsPoint(10, 10), QgsPoint(1, 1), 10, - 'LineString (1 1, 3.4 1.2, 5.3 1.9, 6.7 2.7, 7.5 3.6, 7.8 4.4, 7.5 4.9, 6.7 5, 5.3 4.5, 3.4 3.2, 1 1)'], - [QgsPoint(1, 1), QgsPoint(10, 1), QgsPoint(10, 10), QgsPoint(20, 10), 10, - 'LineString (1 1, 3.4 1.3, 5.5 1.9, 7.2 2.9, 8.7 4.2, 10.1 5.5, 11.6 6.8, 13.2 8.1, 15 9.1, 17.3 9.7, 20 10)'], - [QgsPoint(1, 1), QgsPoint(10, 1), QgsPoint(10, 10), QgsPoint(20, 10), 1, - 'LineString (1 1, 20 10)'], - [QgsPoint(1, 1), QgsPoint(10, 1), QgsPoint(10, 10), QgsPoint(20, 10), 0, - 'LineString EMPTY'], - [QgsPoint(1, 1, 2), QgsPoint(10, 1), QgsPoint(10, 10), QgsPoint(20, 10), 5, - 'LineString (1 1, 5.5 1.9, 8.7 4.2, 11.6 6.8, 15 9.1, 20 10)'], - [QgsPoint(1, 1), QgsPoint(10, 1, 2), QgsPoint(10, 10), QgsPoint(20, 10), 5, - 'LineString (1 1, 5.5 1.9, 8.7 4.2, 11.6 6.8, 15 9.1, 20 10)'], - [QgsPoint(1, 1, 2), QgsPoint(10, 1), QgsPoint(10, 10, 2), QgsPoint(20, 10), 5, - 'LineString (1 1, 5.5 1.9, 8.7 4.2, 11.6 6.8, 15 9.1, 20 10)'], - [QgsPoint(1, 1, 2), QgsPoint(10, 1), QgsPoint(10, 10), QgsPoint(20, 10, 2), 5, - 'LineString (1 1, 5.5 1.9, 8.7 4.2, 11.6 6.8, 15 9.1, 20 10)'], - [QgsPoint(1, 1, 1), QgsPoint(10, 1, 2), QgsPoint(10, 10, 3), QgsPoint(20, 10, 4), 5, - 'LineString Z (1 1 1, 5.5 1.9 1.6, 8.7 4.2 2.2, 11.6 6.8 2.8, 15 9.1 3.4, 20 10 4)'], - [QgsPoint(1, 1, 1, 10), QgsPoint(10, 1, 2, 9), QgsPoint(10, 10, 3, 2), QgsPoint(20, 10, 4, 1), 5, - 'LineString ZM (1 1 1 10, 5.5 1.9 1.6 8.8, 8.7 4.2 2.2 6.7, 11.6 6.8 2.8 4.3, 15 9.1 3.4 2.2, 20 10 4 1)'] + [ + QgsPoint(1, 1), + QgsPoint(10, 1), + QgsPoint(10, 10), + QgsPoint(20, 10), + 5, + "LineString (1 1, 5.5 1.9, 8.7 4.2, 11.6 6.8, 15 9.1, 20 10)", + ], + [ + QgsPoint(1, 1), + QgsPoint(10, 1), + QgsPoint(10, 10), + QgsPoint(1, 1), + 10, + "LineString (1 1, 3.4 1.2, 5.3 1.9, 6.7 2.7, 7.5 3.6, 7.8 4.4, 7.5 4.9, 6.7 5, 5.3 4.5, 3.4 3.2, 1 1)", + ], + [ + QgsPoint(1, 1), + QgsPoint(10, 1), + QgsPoint(10, 10), + QgsPoint(20, 10), + 10, + "LineString (1 1, 3.4 1.3, 5.5 1.9, 7.2 2.9, 8.7 4.2, 10.1 5.5, 11.6 6.8, 13.2 8.1, 15 9.1, 17.3 9.7, 20 10)", + ], + [ + QgsPoint(1, 1), + QgsPoint(10, 1), + QgsPoint(10, 10), + QgsPoint(20, 10), + 1, + "LineString (1 1, 20 10)", + ], + [ + QgsPoint(1, 1), + QgsPoint(10, 1), + QgsPoint(10, 10), + QgsPoint(20, 10), + 0, + "LineString EMPTY", + ], + [ + QgsPoint(1, 1, 2), + QgsPoint(10, 1), + QgsPoint(10, 10), + QgsPoint(20, 10), + 5, + "LineString (1 1, 5.5 1.9, 8.7 4.2, 11.6 6.8, 15 9.1, 20 10)", + ], + [ + QgsPoint(1, 1), + QgsPoint(10, 1, 2), + QgsPoint(10, 10), + QgsPoint(20, 10), + 5, + "LineString (1 1, 5.5 1.9, 8.7 4.2, 11.6 6.8, 15 9.1, 20 10)", + ], + [ + QgsPoint(1, 1, 2), + QgsPoint(10, 1), + QgsPoint(10, 10, 2), + QgsPoint(20, 10), + 5, + "LineString (1 1, 5.5 1.9, 8.7 4.2, 11.6 6.8, 15 9.1, 20 10)", + ], + [ + QgsPoint(1, 1, 2), + QgsPoint(10, 1), + QgsPoint(10, 10), + QgsPoint(20, 10, 2), + 5, + "LineString (1 1, 5.5 1.9, 8.7 4.2, 11.6 6.8, 15 9.1, 20 10)", + ], + [ + QgsPoint(1, 1, 1), + QgsPoint(10, 1, 2), + QgsPoint(10, 10, 3), + QgsPoint(20, 10, 4), + 5, + "LineString Z (1 1 1, 5.5 1.9 1.6, 8.7 4.2 2.2, 11.6 6.8 2.8, 15 9.1 3.4, 20 10 4)", + ], + [ + QgsPoint(1, 1, 1, 10), + QgsPoint(10, 1, 2, 9), + QgsPoint(10, 10, 3, 2), + QgsPoint(20, 10, 4, 1), + 5, + "LineString ZM (1 1 1 10, 5.5 1.9 1.6 8.8, 8.7 4.2 2.2 6.7, 11.6 6.8 2.8 4.3, 15 9.1 3.4 2.2, 20 10 4 1)", + ], ] for t in tests: res = QgsLineString.fromBezierCurve(t[0], t[1], t[2], t[3], t[4]) - self.assertEqual(res.asWkt(1), t[5], - f"mismatch for {t[0]}, expected:\n{t[5]}\nGot:\n{res.asWkt(1)}\n") + self.assertEqual( + res.asWkt(1), + t[5], + f"mismatch for {t[0]}, expected:\n{t[5]}\nGot:\n{res.asWkt(1)}\n", + ) def testIsGeosValid(self): tests = [ - ["", False, False, ''], - ["Point (100 100)", True, True, ''], - ["MultiPoint (100 100, 100 200)", True, True, ''], - ["LINESTRING (0 0, 0 100, 100 100)", True, True, ''], - ["POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1))", True, True, ''], + ["", False, False, ""], + ["Point (100 100)", True, True, ""], + ["MultiPoint (100 100, 100 200)", True, True, ""], + ["LINESTRING (0 0, 0 100, 100 100)", True, True, ""], + ["POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1))", True, True, ""], [ "MULTIPOLYGON(Polygon((-1 -1, 4 0, 4 2, 0 2, -1 -1)),Polygon((100 100, 200 100, 200 200, 100 200, 100 100)))", - True, True, ''], - [ - 'MultiPolygon (((159865.14786298031685874 6768656.31838363595306873, 159858.97975336571107619 6769211.44824895076453686, 160486.07089751763851382 6769211.44824895076453686, 160481.95882444124436006 6768658.37442017439752817, 160163.27316101978067309 6768658.37442017439752817, 160222.89822062765597366 6769116.87056819349527359, 160132.43261294672265649 6769120.98264127038419247, 160163.27316101978067309 6768658.37442017439752817, 159865.14786298031685874 6768656.31838363595306873)))', - False, True, 'Ring self-intersection'], - ['Polygon((0 3, 3 0, 3 3, 0 0, 0 3))', False, False, 'Self-intersection'], - ['LineString(0 0)', False, False, 'LineString has less than 2 points and is not empty.'], - ['LineString Empty', True, True, ''], - ['MultiLineString((0 0))', False, False, 'QGIS geometry cannot be converted to a GEOS geometry'], - ['MultiLineString Empty', True, True, ''], + True, + True, + "", + ], + [ + "MultiPolygon (((159865.14786298031685874 6768656.31838363595306873, 159858.97975336571107619 6769211.44824895076453686, 160486.07089751763851382 6769211.44824895076453686, 160481.95882444124436006 6768658.37442017439752817, 160163.27316101978067309 6768658.37442017439752817, 160222.89822062765597366 6769116.87056819349527359, 160132.43261294672265649 6769120.98264127038419247, 160163.27316101978067309 6768658.37442017439752817, 159865.14786298031685874 6768656.31838363595306873)))", + False, + True, + "Ring self-intersection", + ], + ["Polygon((0 3, 3 0, 3 3, 0 0, 0 3))", False, False, "Self-intersection"], + [ + "LineString(0 0)", + False, + False, + "LineString has less than 2 points and is not empty.", + ], + ["LineString Empty", True, True, ""], + [ + "MultiLineString((0 0))", + False, + False, + "QGIS geometry cannot be converted to a GEOS geometry", + ], + ["MultiLineString Empty", True, True, ""], ] for t in tests: # run each check 2 times to allow for testing of cached value g1 = QgsGeometry.fromWkt(t[0]) for i in range(2): res = g1.isGeosValid() - self.assertEqual(res, t[1], - f"mismatch for {t[0]}, iter {i}, expected:\n{t[1]}\nGot:\n{res}\n") + self.assertEqual( + res, + t[1], + f"mismatch for {t[0]}, iter {i}, expected:\n{t[1]}\nGot:\n{res}\n", + ) if not res: self.assertEqual(g1.lastError(), t[3], t[0]) for i in range(2): - res = g1.isGeosValid(QgsGeometry.ValidityFlag.FlagAllowSelfTouchingHoles) - self.assertEqual(res, t[2], - f"mismatch for {t[0]}, expected:\n{t[2]}\nGot:\n{res}\n") + res = g1.isGeosValid( + QgsGeometry.ValidityFlag.FlagAllowSelfTouchingHoles + ) + self.assertEqual( + res, t[2], f"mismatch for {t[0]}, expected:\n{t[2]}\nGot:\n{res}\n" + ) def testValidateGeometry(self): tests = [ @@ -6730,47 +11842,105 @@ def testValidateGeometry(self): ["POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1))", [], [], []], [ "MULTIPOLYGON(Polygon((-1 -1, 4 0, 4 2, 0 2, -1 -1)),Polygon((100 100, 200 100, 200 200, 100 200, 100 100)))", - [], [], []], - ['POLYGON ((200 400, 400 400, 400 200, 300 200, 350 250, 250 250, 300 200, 200 200, 200 400))', - [QgsGeometry.Error('Ring self-intersection', QgsPointXY(300, 200))], [], []], - [ - 'MultiPolygon (((159865.14786298031685874 6768656.31838363595306873, 159858.97975336571107619 6769211.44824895076453686, 160486.07089751763851382 6769211.44824895076453686, 160481.95882444124436006 6768658.37442017439752817, 160163.27316101978067309 6768658.37442017439752817, 160222.89822062765597366 6769116.87056819349527359, 160132.43261294672265649 6769120.98264127038419247, 160163.27316101978067309 6768658.37442017439752817, 159865.14786298031685874 6768656.31838363595306873)))', - [QgsGeometry.Error('Ring self-intersection', - QgsPointXY(160163.27316101978067309, 6768658.37442017439752817))], [], []], - ['Polygon((0 3, 3 0, 3 3, 0 0, 0 3))', [QgsGeometry.Error('Self-intersection', QgsPointXY(1.5, 1.5))], - [QgsGeometry.Error('Self-intersection', QgsPointXY(1.5, 1.5))], - [QgsGeometry.Error('segments 0 and 2 of line 0 intersect at 1.5, 1.5', QgsPointXY(1.5, 1.5))]], + [], + [], + [], + ], + [ + "POLYGON ((200 400, 400 400, 400 200, 300 200, 350 250, 250 250, 300 200, 200 200, 200 400))", + [QgsGeometry.Error("Ring self-intersection", QgsPointXY(300, 200))], + [], + [], + ], + [ + "MultiPolygon (((159865.14786298031685874 6768656.31838363595306873, 159858.97975336571107619 6769211.44824895076453686, 160486.07089751763851382 6769211.44824895076453686, 160481.95882444124436006 6768658.37442017439752817, 160163.27316101978067309 6768658.37442017439752817, 160222.89822062765597366 6769116.87056819349527359, 160132.43261294672265649 6769120.98264127038419247, 160163.27316101978067309 6768658.37442017439752817, 159865.14786298031685874 6768656.31838363595306873)))", + [ + QgsGeometry.Error( + "Ring self-intersection", + QgsPointXY(160163.27316101978067309, 6768658.37442017439752817), + ) + ], + [], + [], + ], + [ + "Polygon((0 3, 3 0, 3 3, 0 0, 0 3))", + [QgsGeometry.Error("Self-intersection", QgsPointXY(1.5, 1.5))], + [QgsGeometry.Error("Self-intersection", QgsPointXY(1.5, 1.5))], + [ + QgsGeometry.Error( + "segments 0 and 2 of line 0 intersect at 1.5, 1.5", + QgsPointXY(1.5, 1.5), + ) + ], + ], ] for t in tests: g1 = QgsGeometry.fromWkt(t[0]) res = g1.validateGeometry(QgsGeometry.ValidationMethod.ValidatorGeos) - self.assertEqual(res, t[1], - "mismatch for {}, expected:\n{}\nGot:\n{}\n".format(t[0], t[1], - res[0].where() if res else '')) - res = g1.validateGeometry(QgsGeometry.ValidationMethod.ValidatorGeos, QgsGeometry.ValidityFlag.FlagAllowSelfTouchingHoles) - self.assertEqual(res, t[2], - "mismatch for {}, expected:\n{}\nGot:\n{}\n".format(t[0], t[2], - res[0].where() if res else '')) - res = g1.validateGeometry(QgsGeometry.ValidationMethod.ValidatorQgisInternal) - self.assertEqual(res, t[3], - "mismatch for {}, expected:\n{}\nGot:\n{}\n".format(t[0], t[3], - res[0].where() if res else '')) + self.assertEqual( + res, + t[1], + "mismatch for {}, expected:\n{}\nGot:\n{}\n".format( + t[0], t[1], res[0].where() if res else "" + ), + ) + res = g1.validateGeometry( + QgsGeometry.ValidationMethod.ValidatorGeos, + QgsGeometry.ValidityFlag.FlagAllowSelfTouchingHoles, + ) + self.assertEqual( + res, + t[2], + "mismatch for {}, expected:\n{}\nGot:\n{}\n".format( + t[0], t[2], res[0].where() if res else "" + ), + ) + res = g1.validateGeometry( + QgsGeometry.ValidationMethod.ValidatorQgisInternal + ) + self.assertEqual( + res, + t[3], + "mismatch for {}, expected:\n{}\nGot:\n{}\n".format( + t[0], t[3], res[0].where() if res else "" + ), + ) def testCollectDuplicateNodes(self): - g = QgsGeometry.fromWkt("LineString (1 1, 1 1, 1 1, 1 2, 1 3, 1 3, 1 3, 1 4, 1 5, 1 6, 1 6)") + g = QgsGeometry.fromWkt( + "LineString (1 1, 1 1, 1 1, 1 2, 1 3, 1 3, 1 3, 1 4, 1 5, 1 6, 1 6)" + ) res = g.constGet().collectDuplicateNodes() - self.assertCountEqual(res, [QgsVertexId(-1, -1, 1), QgsVertexId(-1, -1, 2), QgsVertexId(-1, -1, 5), - QgsVertexId(-1, -1, 6), QgsVertexId(-1, -1, 10)]) + self.assertCountEqual( + res, + [ + QgsVertexId(-1, -1, 1), + QgsVertexId(-1, -1, 2), + QgsVertexId(-1, -1, 5), + QgsVertexId(-1, -1, 6), + QgsVertexId(-1, -1, 10), + ], + ) g = QgsGeometry.fromWkt("LineString (1 1, 1 2, 1 3, 1 4, 1 5, 1 6)") res = g.constGet().collectDuplicateNodes() self.assertFalse(res) g = QgsGeometry.fromWkt( - "LineStringZ (1 1 1, 1 1 2, 1 1 3, 1 2 1, 1 3 1, 1 3 1, 1 3 2, 1 4 1, 1 5 1, 1 6 1, 1 6 2)") + "LineStringZ (1 1 1, 1 1 2, 1 1 3, 1 2 1, 1 3 1, 1 3 1, 1 3 2, 1 4 1, 1 5 1, 1 6 1, 1 6 2)" + ) res = g.constGet().collectDuplicateNodes() - self.assertCountEqual(res, [QgsVertexId(-1, -1, 1), QgsVertexId(-1, -1, 2), QgsVertexId(-1, -1, 5), - QgsVertexId(-1, -1, 6), QgsVertexId(-1, -1, 10)]) + self.assertCountEqual( + res, + [ + QgsVertexId(-1, -1, 1), + QgsVertexId(-1, -1, 2), + QgsVertexId(-1, -1, 5), + QgsVertexId(-1, -1, 6), + QgsVertexId(-1, -1, 10), + ], + ) # consider z values res = g.constGet().collectDuplicateNodes(useZValues=True) @@ -6795,15 +11965,18 @@ def testRandomPoints(self): with self.assertRaises(ValueError): res = g.randomPointsInPolygon(100) # no random points inside linestring - g = QgsGeometry.fromWkt('LineString(4 5, 6 6)') + g = QgsGeometry.fromWkt("LineString(4 5, 6 6)") with self.assertRaises(TypeError): res = g.randomPointsInPolygon(100) # good! - g = QgsGeometry.fromWkt('Polygon(( 5 15, 10 15, 10 20, 5 20, 5 15 ), (6 16, 8 16, 8 18, 6 16 ))') + g = QgsGeometry.fromWkt( + "Polygon(( 5 15, 10 15, 10 20, 5 20, 5 15 ), (6 16, 8 16, 8 18, 6 16 ))" + ) res = g.randomPointsInPolygon(100) self.assertEqual(len(res), 100) g = QgsGeometry.fromWkt( - 'MultiPolygon((( 5 15, 10 15, 10 20, 5 20, 5 15 ), (6 16, 8 16, 8 18, 6 16 )), (( 105 115, 110 115, 110 120, 105 120, 105 115 ), (106 116, 108 116, 108 118, 106 116 )))') + "MultiPolygon((( 5 15, 10 15, 10 20, 5 20, 5 15 ), (6 16, 8 16, 8 18, 6 16 )), (( 105 115, 110 115, 110 120, 105 120, 105 115 ), (106 116, 108 116, 108 118, 106 116 )))" + ) res = g.randomPointsInPolygon(100) self.assertEqual(len(res), 100) res2 = g.randomPointsInPolygon(100) @@ -6816,12 +11989,15 @@ def testRandomPoints(self): def testLineStringFromQPolygonF(self): line = QgsLineString.fromQPolygonF(QPolygonF()) - self.assertEqual(line.asWkt(0), 'LineString EMPTY') + self.assertEqual(line.asWkt(0), "LineString EMPTY") line = QgsLineString.fromQPolygonF(QPolygonF([QPointF(1, 2), QPointF(3, 4)])) - self.assertEqual(line.asWkt(1), 'LineString (1 2, 3 4)') + self.assertEqual(line.asWkt(1), "LineString (1 2, 3 4)") line = QgsLineString.fromQPolygonF( - QPolygonF([QPointF(1.5, 2.5), QPointF(3, 4), QPointF(3, 6.5), QPointF(1.5, 2.5)])) - self.assertEqual(line.asWkt(1), 'LineString (1.5 2.5, 3 4, 3 6.5, 1.5 2.5)') + QPolygonF( + [QPointF(1.5, 2.5), QPointF(3, 4), QPointF(3, 6.5), QPointF(1.5, 2.5)] + ) + ) + self.assertEqual(line.asWkt(1), "LineString (1.5 2.5, 3 4, 3 6.5, 1.5 2.5)") def testCoerce(self): """Test coerce function""" @@ -6829,491 +12005,1064 @@ def testCoerce(self): def coerce_to_wkt(wkt, type, defaultZ=None, defaultM=None): geom = QgsGeometry.fromWkt(wkt) if defaultZ is not None or defaultM is not None: - return [g.asWkt(2) for g in geom.coerceToType(type, defaultZ or 0, defaultM or 0)] + return [ + g.asWkt(2) + for g in geom.coerceToType(type, defaultZ or 0, defaultM or 0) + ] else: return [g.asWkt(2) for g in geom.coerceToType(type)] - self.assertEqual(coerce_to_wkt('Point (1 1)', QgsWkbTypes.Type.Point), ['Point (1 1)']) - self.assertEqual(coerce_to_wkt('LineString (1 1, 2 2, 3 3)', QgsWkbTypes.Type.LineString), - ['LineString (1 1, 2 2, 3 3)']) - self.assertEqual(coerce_to_wkt('Polygon((1 1, 2 2, 1 2, 1 1))', QgsWkbTypes.Type.Polygon), - ['Polygon ((1 1, 2 2, 1 2, 1 1))']) + self.assertEqual( + coerce_to_wkt("Point (1 1)", QgsWkbTypes.Type.Point), ["Point (1 1)"] + ) + self.assertEqual( + coerce_to_wkt("LineString (1 1, 2 2, 3 3)", QgsWkbTypes.Type.LineString), + ["LineString (1 1, 2 2, 3 3)"], + ) + self.assertEqual( + coerce_to_wkt("Polygon((1 1, 2 2, 1 2, 1 1))", QgsWkbTypes.Type.Polygon), + ["Polygon ((1 1, 2 2, 1 2, 1 1))"], + ) - self.assertEqual(coerce_to_wkt('LineString (1 1, 2 2, 3 3)', QgsWkbTypes.Type.Point), - ['Point (1 1)', 'Point (2 2)', 'Point (3 3)']) - self.assertEqual(coerce_to_wkt('LineString (1 1, 2 2, 3 3)', QgsWkbTypes.Type.Polygon), - ['Polygon ((1 1, 2 2, 3 3, 1 1))']) - self.assertEqual(coerce_to_wkt('Polygon((1 1, 2 2, 1 2, 1 1))', QgsWkbTypes.Type.Point), - ['Point (1 1)', 'Point (2 2)', 'Point (1 2)']) - self.assertEqual(coerce_to_wkt('Polygon((1 1, 2 2, 1 2, 1 1))', QgsWkbTypes.Type.LineString), - ['LineString (1 1, 2 2, 1 2, 1 1)']) + self.assertEqual( + coerce_to_wkt("LineString (1 1, 2 2, 3 3)", QgsWkbTypes.Type.Point), + ["Point (1 1)", "Point (2 2)", "Point (3 3)"], + ) + self.assertEqual( + coerce_to_wkt("LineString (1 1, 2 2, 3 3)", QgsWkbTypes.Type.Polygon), + ["Polygon ((1 1, 2 2, 3 3, 1 1))"], + ) + self.assertEqual( + coerce_to_wkt("Polygon((1 1, 2 2, 1 2, 1 1))", QgsWkbTypes.Type.Point), + ["Point (1 1)", "Point (2 2)", "Point (1 2)"], + ) + self.assertEqual( + coerce_to_wkt("Polygon((1 1, 2 2, 1 2, 1 1))", QgsWkbTypes.Type.LineString), + ["LineString (1 1, 2 2, 1 2, 1 1)"], + ) - self.assertEqual(coerce_to_wkt('Point z (1 1 3)', QgsWkbTypes.Type.Point), ['Point (1 1)']) - self.assertEqual(coerce_to_wkt('Point z (1 1 3)', QgsWkbTypes.Type.PointZ), ['Point Z (1 1 3)']) + self.assertEqual( + coerce_to_wkt("Point z (1 1 3)", QgsWkbTypes.Type.Point), ["Point (1 1)"] + ) + self.assertEqual( + coerce_to_wkt("Point z (1 1 3)", QgsWkbTypes.Type.PointZ), + ["Point Z (1 1 3)"], + ) # Adding Z back - self.assertEqual(coerce_to_wkt('Point (1 1)', QgsWkbTypes.Type.PointZ), ['Point Z (1 1 0)']) + self.assertEqual( + coerce_to_wkt("Point (1 1)", QgsWkbTypes.Type.PointZ), ["Point Z (1 1 0)"] + ) # Adding Z/M with defaults - self.assertEqual(coerce_to_wkt('Point (1 1)', QgsWkbTypes.Type.PointZ, defaultZ=222), ['Point Z (1 1 222)']) - self.assertEqual(coerce_to_wkt('Point (1 1)', QgsWkbTypes.Type.PointM, defaultM=333), ['Point M (1 1 333)']) - self.assertEqual(coerce_to_wkt('Point (1 1)', QgsWkbTypes.Type.PointZM, defaultZ=222, defaultM=333), ['Point ZM (1 1 222 333)']) + self.assertEqual( + coerce_to_wkt("Point (1 1)", QgsWkbTypes.Type.PointZ, defaultZ=222), + ["Point Z (1 1 222)"], + ) + self.assertEqual( + coerce_to_wkt("Point (1 1)", QgsWkbTypes.Type.PointM, defaultM=333), + ["Point M (1 1 333)"], + ) + self.assertEqual( + coerce_to_wkt( + "Point (1 1)", QgsWkbTypes.Type.PointZM, defaultZ=222, defaultM=333 + ), + ["Point ZM (1 1 222 333)"], + ) # Adding M back - self.assertEqual(coerce_to_wkt('Point (1 1)', QgsWkbTypes.Type.PointM), ['Point M (1 1 0)']) - self.assertEqual(coerce_to_wkt('Point m (1 1 3)', QgsWkbTypes.Type.Point), ['Point (1 1)']) - self.assertEqual(coerce_to_wkt('Point(1 3)', QgsWkbTypes.Type.MultiPoint), ['MultiPoint ((1 3))']) - self.assertEqual(coerce_to_wkt('MultiPoint((1 3), (2 2))', QgsWkbTypes.Type.MultiPoint), - ['MultiPoint ((1 3),(2 2))']) - - self.assertEqual(coerce_to_wkt('Polygon((1 1, 2 2, 3 3, 1 1))', QgsWkbTypes.Type.Polygon), - ['Polygon ((1 1, 2 2, 3 3, 1 1))']) - self.assertEqual(coerce_to_wkt('Polygon z ((1 1 1, 2 2 2, 3 3 3, 1 1 1))', QgsWkbTypes.Type.Polygon), - ['Polygon ((1 1, 2 2, 3 3, 1 1))']) - self.assertEqual(coerce_to_wkt('Polygon z ((1 1 1, 2 2 2, 3 3 3, 1 1 1))', QgsWkbTypes.Type.PolygonZ), - ['Polygon Z ((1 1 1, 2 2 2, 3 3 3, 1 1 1))']) + self.assertEqual( + coerce_to_wkt("Point (1 1)", QgsWkbTypes.Type.PointM), ["Point M (1 1 0)"] + ) + self.assertEqual( + coerce_to_wkt("Point m (1 1 3)", QgsWkbTypes.Type.Point), ["Point (1 1)"] + ) + self.assertEqual( + coerce_to_wkt("Point(1 3)", QgsWkbTypes.Type.MultiPoint), + ["MultiPoint ((1 3))"], + ) + self.assertEqual( + coerce_to_wkt("MultiPoint((1 3), (2 2))", QgsWkbTypes.Type.MultiPoint), + ["MultiPoint ((1 3),(2 2))"], + ) + + self.assertEqual( + coerce_to_wkt("Polygon((1 1, 2 2, 3 3, 1 1))", QgsWkbTypes.Type.Polygon), + ["Polygon ((1 1, 2 2, 3 3, 1 1))"], + ) + self.assertEqual( + coerce_to_wkt( + "Polygon z ((1 1 1, 2 2 2, 3 3 3, 1 1 1))", QgsWkbTypes.Type.Polygon + ), + ["Polygon ((1 1, 2 2, 3 3, 1 1))"], + ) + self.assertEqual( + coerce_to_wkt( + "Polygon z ((1 1 1, 2 2 2, 3 3 3, 1 1 1))", QgsWkbTypes.Type.PolygonZ + ), + ["Polygon Z ((1 1 1, 2 2 2, 3 3 3, 1 1 1))"], + ) # Adding Z back - self.assertEqual(coerce_to_wkt('Polygon ((1 1, 2 2, 3 3, 1 1))', QgsWkbTypes.Type.PolygonZ), - ['Polygon Z ((1 1 0, 2 2 0, 3 3 0, 1 1 0))']) + self.assertEqual( + coerce_to_wkt("Polygon ((1 1, 2 2, 3 3, 1 1))", QgsWkbTypes.Type.PolygonZ), + ["Polygon Z ((1 1 0, 2 2 0, 3 3 0, 1 1 0))"], + ) # Adding M back - self.assertEqual(coerce_to_wkt('Polygon ((1 1, 2 2, 3 3, 1 1))', QgsWkbTypes.Type.PolygonM), - ['Polygon M ((1 1 0, 2 2 0, 3 3 0, 1 1 0))']) - - self.assertEqual(coerce_to_wkt('Polygon m ((1 1 1, 2 2 2, 3 3 3, 1 1 1))', QgsWkbTypes.Type.Polygon), - ['Polygon ((1 1, 2 2, 3 3, 1 1))']) - self.assertEqual(coerce_to_wkt('Polygon m ((1 1 1, 2 2 2, 3 3 3, 1 1 1))', QgsWkbTypes.Type.PolygonM), - ['Polygon M ((1 1 1, 2 2 2, 3 3 3, 1 1 1))']) - self.assertEqual(coerce_to_wkt('Polygon((1 1, 2 2, 3 3, 1 1))', QgsWkbTypes.Type.MultiPolygon), - ['MultiPolygon (((1 1, 2 2, 3 3, 1 1)))']) - self.assertEqual( - coerce_to_wkt('MultiPolygon(((1 1, 2 2, 3 3, 1 1)), ((1 1, 2 2, 3 3, 1 1)))', QgsWkbTypes.Type.MultiPolygon), - ['MultiPolygon (((1 1, 2 2, 3 3, 1 1)),((1 1, 2 2, 3 3, 1 1)))']) - - self.assertEqual(coerce_to_wkt('LineString(1 1, 2 2, 3 3, 1 1)', QgsWkbTypes.Type.LineString), - ['LineString (1 1, 2 2, 3 3, 1 1)']) - self.assertEqual(coerce_to_wkt('LineString z (1 1 1, 2 2 2, 3 3 3, 1 1 1)', QgsWkbTypes.Type.LineString), - ['LineString (1 1, 2 2, 3 3, 1 1)']) - self.assertEqual(coerce_to_wkt('LineString z (1 1 1, 2 2 2, 3 3 3, 1 1 1)', QgsWkbTypes.Type.LineStringZ), - ['LineString Z (1 1 1, 2 2 2, 3 3 3, 1 1 1)']) - self.assertEqual(coerce_to_wkt('LineString m (1 1 1, 2 2 2, 3 3 3, 1 1 1)', QgsWkbTypes.Type.LineString), - ['LineString (1 1, 2 2, 3 3, 1 1)']) - self.assertEqual(coerce_to_wkt('LineString m (1 1 1, 2 2 2, 3 3 3, 1 1 1)', QgsWkbTypes.Type.LineStringM), - ['LineString M (1 1 1, 2 2 2, 3 3 3, 1 1 1)']) + self.assertEqual( + coerce_to_wkt("Polygon ((1 1, 2 2, 3 3, 1 1))", QgsWkbTypes.Type.PolygonM), + ["Polygon M ((1 1 0, 2 2 0, 3 3 0, 1 1 0))"], + ) + + self.assertEqual( + coerce_to_wkt( + "Polygon m ((1 1 1, 2 2 2, 3 3 3, 1 1 1))", QgsWkbTypes.Type.Polygon + ), + ["Polygon ((1 1, 2 2, 3 3, 1 1))"], + ) + self.assertEqual( + coerce_to_wkt( + "Polygon m ((1 1 1, 2 2 2, 3 3 3, 1 1 1))", QgsWkbTypes.Type.PolygonM + ), + ["Polygon M ((1 1 1, 2 2 2, 3 3 3, 1 1 1))"], + ) + self.assertEqual( + coerce_to_wkt( + "Polygon((1 1, 2 2, 3 3, 1 1))", QgsWkbTypes.Type.MultiPolygon + ), + ["MultiPolygon (((1 1, 2 2, 3 3, 1 1)))"], + ) + self.assertEqual( + coerce_to_wkt( + "MultiPolygon(((1 1, 2 2, 3 3, 1 1)), ((1 1, 2 2, 3 3, 1 1)))", + QgsWkbTypes.Type.MultiPolygon, + ), + ["MultiPolygon (((1 1, 2 2, 3 3, 1 1)),((1 1, 2 2, 3 3, 1 1)))"], + ) + + self.assertEqual( + coerce_to_wkt( + "LineString(1 1, 2 2, 3 3, 1 1)", QgsWkbTypes.Type.LineString + ), + ["LineString (1 1, 2 2, 3 3, 1 1)"], + ) + self.assertEqual( + coerce_to_wkt( + "LineString z (1 1 1, 2 2 2, 3 3 3, 1 1 1)", QgsWkbTypes.Type.LineString + ), + ["LineString (1 1, 2 2, 3 3, 1 1)"], + ) + self.assertEqual( + coerce_to_wkt( + "LineString z (1 1 1, 2 2 2, 3 3 3, 1 1 1)", + QgsWkbTypes.Type.LineStringZ, + ), + ["LineString Z (1 1 1, 2 2 2, 3 3 3, 1 1 1)"], + ) + self.assertEqual( + coerce_to_wkt( + "LineString m (1 1 1, 2 2 2, 3 3 3, 1 1 1)", QgsWkbTypes.Type.LineString + ), + ["LineString (1 1, 2 2, 3 3, 1 1)"], + ) + self.assertEqual( + coerce_to_wkt( + "LineString m (1 1 1, 2 2 2, 3 3 3, 1 1 1)", + QgsWkbTypes.Type.LineStringM, + ), + ["LineString M (1 1 1, 2 2 2, 3 3 3, 1 1 1)"], + ) # Adding Z back - self.assertEqual(coerce_to_wkt('LineString (1 1, 2 2, 3 3, 1 1)', QgsWkbTypes.Type.LineStringZ), - ['LineString Z (1 1 0, 2 2 0, 3 3 0, 1 1 0)']) + self.assertEqual( + coerce_to_wkt( + "LineString (1 1, 2 2, 3 3, 1 1)", QgsWkbTypes.Type.LineStringZ + ), + ["LineString Z (1 1 0, 2 2 0, 3 3 0, 1 1 0)"], + ) # Adding M back - self.assertEqual(coerce_to_wkt('LineString (1 1, 2 2, 3 3, 1 1)', QgsWkbTypes.Type.LineStringM), - ['LineString M (1 1 0, 2 2 0, 3 3 0, 1 1 0)']) + self.assertEqual( + coerce_to_wkt( + "LineString (1 1, 2 2, 3 3, 1 1)", QgsWkbTypes.Type.LineStringM + ), + ["LineString M (1 1 0, 2 2 0, 3 3 0, 1 1 0)"], + ) - self.assertEqual(coerce_to_wkt('LineString(1 1, 2 2, 3 3, 1 1)', QgsWkbTypes.Type.MultiLineString), - ['MultiLineString ((1 1, 2 2, 3 3, 1 1))']) - self.assertEqual(coerce_to_wkt('MultiLineString((1 1, 2 2, 3 3, 1 1), (1 1, 2 2, 3 3, 1 1))', - QgsWkbTypes.Type.MultiLineString), - ['MultiLineString ((1 1, 2 2, 3 3, 1 1),(1 1, 2 2, 3 3, 1 1))']) + self.assertEqual( + coerce_to_wkt( + "LineString(1 1, 2 2, 3 3, 1 1)", QgsWkbTypes.Type.MultiLineString + ), + ["MultiLineString ((1 1, 2 2, 3 3, 1 1))"], + ) + self.assertEqual( + coerce_to_wkt( + "MultiLineString((1 1, 2 2, 3 3, 1 1), (1 1, 2 2, 3 3, 1 1))", + QgsWkbTypes.Type.MultiLineString, + ), + ["MultiLineString ((1 1, 2 2, 3 3, 1 1),(1 1, 2 2, 3 3, 1 1))"], + ) # Test Multi -> Single - self.assertEqual(coerce_to_wkt('MultiLineString((1 1, 2 2, 3 3, 1 1), (10 1, 20 2, 30 3, 10 1))', - QgsWkbTypes.Type.LineString), - ['LineString (1 1, 2 2, 3 3, 1 1)', 'LineString (10 1, 20 2, 30 3, 10 1)']) + self.assertEqual( + coerce_to_wkt( + "MultiLineString((1 1, 2 2, 3 3, 1 1), (10 1, 20 2, 30 3, 10 1))", + QgsWkbTypes.Type.LineString, + ), + ["LineString (1 1, 2 2, 3 3, 1 1)", "LineString (10 1, 20 2, 30 3, 10 1)"], + ) # line -> points - self.assertEqual(coerce_to_wkt('LineString (1 1, 2 2, 3 3)', QgsWkbTypes.Type.Point), - ['Point (1 1)', 'Point (2 2)', 'Point (3 3)']) + self.assertEqual( + coerce_to_wkt("LineString (1 1, 2 2, 3 3)", QgsWkbTypes.Type.Point), + ["Point (1 1)", "Point (2 2)", "Point (3 3)"], + ) - self.assertEqual(coerce_to_wkt('LineString (1 1, 2 2, 3 3)', QgsWkbTypes.Type.MultiPoint), - ['MultiPoint ((1 1),(2 2),(3 3))']) + self.assertEqual( + coerce_to_wkt("LineString (1 1, 2 2, 3 3)", QgsWkbTypes.Type.MultiPoint), + ["MultiPoint ((1 1),(2 2),(3 3))"], + ) - self.assertEqual(coerce_to_wkt('MultiLineString ((1 1, 2 2),(4 4, 3 3))', QgsWkbTypes.Type.Point), - ['Point (1 1)', 'Point (2 2)', 'Point (4 4)', 'Point (3 3)']) + self.assertEqual( + coerce_to_wkt( + "MultiLineString ((1 1, 2 2),(4 4, 3 3))", QgsWkbTypes.Type.Point + ), + ["Point (1 1)", "Point (2 2)", "Point (4 4)", "Point (3 3)"], + ) - self.assertEqual(coerce_to_wkt('MultiLineString ((1 1, 2 2),(4 4, 3 3))', QgsWkbTypes.Type.MultiPoint), - ['MultiPoint ((1 1),(2 2),(4 4),(3 3))']) + self.assertEqual( + coerce_to_wkt( + "MultiLineString ((1 1, 2 2),(4 4, 3 3))", QgsWkbTypes.Type.MultiPoint + ), + ["MultiPoint ((1 1),(2 2),(4 4),(3 3))"], + ) # line -> polygon - self.assertEqual(coerce_to_wkt('LineString (1 1, 1 2, 2 2)', QgsWkbTypes.Type.Polygon), - ['Polygon ((1 1, 1 2, 2 2, 1 1))']) + self.assertEqual( + coerce_to_wkt("LineString (1 1, 1 2, 2 2)", QgsWkbTypes.Type.Polygon), + ["Polygon ((1 1, 1 2, 2 2, 1 1))"], + ) - self.assertEqual(coerce_to_wkt('LineString (1 1, 1 2, 2 2)', QgsWkbTypes.Type.MultiPolygon), - ['MultiPolygon (((1 1, 1 2, 2 2, 1 1)))']) + self.assertEqual( + coerce_to_wkt("LineString (1 1, 1 2, 2 2)", QgsWkbTypes.Type.MultiPolygon), + ["MultiPolygon (((1 1, 1 2, 2 2, 1 1)))"], + ) - self.assertEqual(coerce_to_wkt('MultiLineString ((1 1, 1 2, 2 2, 1 1),(3 3, 4 3, 4 4))', QgsWkbTypes.Type.Polygon), - ['Polygon ((1 1, 1 2, 2 2, 1 1))', 'Polygon ((3 3, 4 3, 4 4, 3 3))']) + self.assertEqual( + coerce_to_wkt( + "MultiLineString ((1 1, 1 2, 2 2, 1 1),(3 3, 4 3, 4 4))", + QgsWkbTypes.Type.Polygon, + ), + ["Polygon ((1 1, 1 2, 2 2, 1 1))", "Polygon ((3 3, 4 3, 4 4, 3 3))"], + ) - self.assertEqual(coerce_to_wkt('MultiLineString ((1 1, 1 2, 2 2, 1 1),(3 3, 4 3, 4 4))', - QgsWkbTypes.Type.MultiPolygon), - ['MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))']) + self.assertEqual( + coerce_to_wkt( + "MultiLineString ((1 1, 1 2, 2 2, 1 1),(3 3, 4 3, 4 4))", + QgsWkbTypes.Type.MultiPolygon, + ), + ["MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))"], + ) - self.assertEqual(coerce_to_wkt('CircularString (1 1, 1 2, 2 2, 2 0, 1 1)', QgsWkbTypes.Type.CurvePolygon), - ['CurvePolygon (CircularString (1 1, 1 2, 2 2, 2 0, 1 1))']) - self.assertEqual(coerce_to_wkt('CircularString (1 1, 1 2, 2 2, 2 0, 1 1)', QgsWkbTypes.Type.LineString)[0][:100], - 'LineString (1 1, 0.99 1.01, 0.98 1.02, 0.97 1.03, 0.97 1.04, 0.96 1.05, 0.95 1.06, 0.94 1.06, 0.94 1') - self.assertEqual(coerce_to_wkt('CircularString (1 1, 1 2, 2 2, 2 0, 1 1)', QgsWkbTypes.Type.Polygon)[0][:100], - 'Polygon ((1 1, 0.99 1.01, 0.98 1.02, 0.97 1.03, 0.97 1.04, 0.96 1.05, 0.95 1.06, 0.94 1.06, 0.94 1.0') + self.assertEqual( + coerce_to_wkt( + "CircularString (1 1, 1 2, 2 2, 2 0, 1 1)", + QgsWkbTypes.Type.CurvePolygon, + ), + ["CurvePolygon (CircularString (1 1, 1 2, 2 2, 2 0, 1 1))"], + ) + self.assertEqual( + coerce_to_wkt( + "CircularString (1 1, 1 2, 2 2, 2 0, 1 1)", QgsWkbTypes.Type.LineString + )[0][:100], + "LineString (1 1, 0.99 1.01, 0.98 1.02, 0.97 1.03, 0.97 1.04, 0.96 1.05, 0.95 1.06, 0.94 1.06, 0.94 1", + ) + self.assertEqual( + coerce_to_wkt( + "CircularString (1 1, 1 2, 2 2, 2 0, 1 1)", QgsWkbTypes.Type.Polygon + )[0][:100], + "Polygon ((1 1, 0.99 1.01, 0.98 1.02, 0.97 1.03, 0.97 1.04, 0.96 1.05, 0.95 1.06, 0.94 1.06, 0.94 1.0", + ) # polygon -> points - self.assertEqual(coerce_to_wkt('Polygon ((1 1, 1 2, 2 2, 1 1))', QgsWkbTypes.Type.Point), - ['Point (1 1)', 'Point (1 2)', 'Point (2 2)']) + self.assertEqual( + coerce_to_wkt("Polygon ((1 1, 1 2, 2 2, 1 1))", QgsWkbTypes.Type.Point), + ["Point (1 1)", "Point (1 2)", "Point (2 2)"], + ) - self.assertEqual(coerce_to_wkt('Polygon ((1 1, 1 2, 2 2, 1 1))', QgsWkbTypes.Type.MultiPoint), - ['MultiPoint ((1 1),(1 2),(2 2))']) + self.assertEqual( + coerce_to_wkt( + "Polygon ((1 1, 1 2, 2 2, 1 1))", QgsWkbTypes.Type.MultiPoint + ), + ["MultiPoint ((1 1),(1 2),(2 2))"], + ) self.assertEqual( - coerce_to_wkt('MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))', QgsWkbTypes.Type.Point), - ['Point (1 1)', 'Point (1 2)', 'Point (2 2)', 'Point (3 3)', 'Point (4 3)', 'Point (4 4)']) + coerce_to_wkt( + "MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))", + QgsWkbTypes.Type.Point, + ), + [ + "Point (1 1)", + "Point (1 2)", + "Point (2 2)", + "Point (3 3)", + "Point (4 3)", + "Point (4 4)", + ], + ) - self.assertEqual(coerce_to_wkt('MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))', - QgsWkbTypes.Type.MultiPoint), ['MultiPoint ((1 1),(1 2),(2 2),(3 3),(4 3),(4 4))']) + self.assertEqual( + coerce_to_wkt( + "MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))", + QgsWkbTypes.Type.MultiPoint, + ), + ["MultiPoint ((1 1),(1 2),(2 2),(3 3),(4 3),(4 4))"], + ) # polygon -> lines - self.assertEqual(coerce_to_wkt('Polygon ((1 1, 1 2, 2 2, 1 1))', QgsWkbTypes.Type.LineString), - ['LineString (1 1, 1 2, 2 2, 1 1)']) + self.assertEqual( + coerce_to_wkt( + "Polygon ((1 1, 1 2, 2 2, 1 1))", QgsWkbTypes.Type.LineString + ), + ["LineString (1 1, 1 2, 2 2, 1 1)"], + ) - self.assertEqual(coerce_to_wkt('Polygon ((1 1, 1 2, 2 2, 1 1))', QgsWkbTypes.Type.MultiLineString), - ['MultiLineString ((1 1, 1 2, 2 2, 1 1))']) + self.assertEqual( + coerce_to_wkt( + "Polygon ((1 1, 1 2, 2 2, 1 1))", QgsWkbTypes.Type.MultiLineString + ), + ["MultiLineString ((1 1, 1 2, 2 2, 1 1))"], + ) - self.assertEqual(coerce_to_wkt('MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))', - QgsWkbTypes.Type.LineString), - ['LineString (1 1, 1 2, 2 2, 1 1)', 'LineString (3 3, 4 3, 4 4, 3 3)']) + self.assertEqual( + coerce_to_wkt( + "MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))", + QgsWkbTypes.Type.LineString, + ), + ["LineString (1 1, 1 2, 2 2, 1 1)", "LineString (3 3, 4 3, 4 4, 3 3)"], + ) - self.assertEqual(coerce_to_wkt('MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))', - QgsWkbTypes.Type.MultiLineString), - ['MultiLineString ((1 1, 1 2, 2 2, 1 1),(3 3, 4 3, 4 4, 3 3))']) + self.assertEqual( + coerce_to_wkt( + "MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))", + QgsWkbTypes.Type.MultiLineString, + ), + ["MultiLineString ((1 1, 1 2, 2 2, 1 1),(3 3, 4 3, 4 4, 3 3))"], + ) # Straight to curve - self.assertEqual(coerce_to_wkt('LineString (0 0,1 1)', - QgsWkbTypes.Type.MultiCurve), - ['MultiCurve (LineString (0 0, 1 1))']) + self.assertEqual( + coerce_to_wkt("LineString (0 0,1 1)", QgsWkbTypes.Type.MultiCurve), + ["MultiCurve (LineString (0 0, 1 1))"], + ) # Polygon to PolyhedralSurface - self.assertEqual(coerce_to_wkt('Polygon ((1 1, 1 2, 2 2, 5 5, 1 1))', - QgsWkbTypes.Type.PolyhedralSurface), - ['PolyhedralSurface (((1 1, 1 2, 2 2, 5 5, 1 1)))']) - self.assertEqual(coerce_to_wkt('Polygon Z((1 1 2, 1 2 2, 2 2 3, 5 5 3, 1 1 2))', - QgsWkbTypes.Type.PolyhedralSurfaceZ), - ['PolyhedralSurface Z (((1 1 2, 1 2 2, 2 2 3, 5 5 3, 1 1 2)))']) + self.assertEqual( + coerce_to_wkt( + "Polygon ((1 1, 1 2, 2 2, 5 5, 1 1))", + QgsWkbTypes.Type.PolyhedralSurface, + ), + ["PolyhedralSurface (((1 1, 1 2, 2 2, 5 5, 1 1)))"], + ) + self.assertEqual( + coerce_to_wkt( + "Polygon Z((1 1 2, 1 2 2, 2 2 3, 5 5 3, 1 1 2))", + QgsWkbTypes.Type.PolyhedralSurfaceZ, + ), + ["PolyhedralSurface Z (((1 1 2, 1 2 2, 2 2 3, 5 5 3, 1 1 2)))"], + ) def testTriangularWaves(self): """Test triangular waves""" - self.assertEqual(QgsGeometry.fromWkt('Point (1 1)').triangularWaves(1, 2).asWkt(3), 'Point (1 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1)').triangularWaves(1, 2).asWkt(3), '') # don't crash! - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').triangularWaves(1, 2).asWkt(3), - 'LineString (1 1, 1.25 3, 1.75 -1, 2.25 3, 2.75 -1, 3.25 3, 3.75 -1, 4.25 3, 4.75 -1, 5.25 3, 5.75 -1, 6.25 3, 6.75 -1, 7.25 3, 7.75 -1, 8.25 3, 8.75 -1, 9.25 3, 9.75 -1, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').triangularWaves(5, 2).asWkt(3), - 'LineString (1 1, 2.125 3, 4.375 -1, 6.625 3, 8.875 -1, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').triangularWaves(8, 2).asWkt(3), - 'LineString (1 1, 2.125 3, 4.375 -1, 6.625 3, 8.875 -1, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').triangularWaves(8, 2, True).asWkt(3), - 'LineString (1 1, 3 3, 7 -1, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').triangularWaves(10, 2).asWkt(3), - 'LineString (1 1, 3.25 3, 7.75 -1, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').triangularWaves(20, 2).asWkt(3), - 'LineString (1 1, 3.25 3, 7.75 -1, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1, 10 10)').triangularWaves(5, 2).asWkt(3), - 'LineString (1 1, 2.125 3, 4.375 -1, 6.625 3, 8.875 -1, 8 2.125, 12 4.375, 8 6.625, 12 8.875, 10 10)') - self.assertEqual( - QgsGeometry.fromWkt('MultiLineString ((1 1, 10 1),(10 10, 0 10))').triangularWaves(5, 2).asWkt(3), - 'MultiLineString ((1 1, 2.125 3, 4.375 -1, 6.625 3, 8.875 -1, 10 1),(10 10, 8.75 8, 6.25 12, 3.75 8, 1.25 12, 0 10))') - self.assertEqual( - QgsGeometry.fromWkt('Polygon ((1 1, 10 1, 10 10, 1 10, 1 1),(3 4, 8 4, 7 7, 4 6, 3 4))').triangularWaves(5, - .5).asWkt( - 3), - 'Polygon ((1 1, 2.125 1.5, 4.375 0.5, 6.625 1.5, 8.875 0.5, 9.5 2.125, 10.5 4.375, 9.5 6.625, 10.5 8.875, 8.875 9.5, 6.625 10.5, 4.375 9.5, 2.125 10.5, 1.5 8.875, 0.5 6.625, 1.5 4.375, 0.5 2.125, 1 1),(3 4, 4.13 4.5, 6.39 3.5, 7.32 4.459, 7.554 6.919, 5.253 5.891, 3.058 5.234, 3 4))') - self.assertEqual(QgsGeometry.fromWkt( - 'MultiPolygon (((1 1, 10 1, 10 10, 1 10, 1 1)),((20 20, 20 30, 30 20, 20 20)))').triangularWaves(5, - 0.5).asWkt( - 3), - 'MultiPolygon (((1 1, 2.125 1.5, 4.375 0.5, 6.625 1.5, 8.875 0.5, 9.5 2.125, 10.5 4.375, 9.5 6.625, 10.5 8.875, 8.875 9.5, 6.625 10.5, 4.375 9.5, 2.125 10.5, 1.5 8.875, 0.5 6.625, 1.5 4.375, 0.5 2.125, 1 1)),((20 20, 19.5 21.219, 20.5 23.658, 19.5 26.097, 20.5 28.536, 21.042 29.665, 22.06 27.233, 24.491 26.216, 25.509 23.784, 27.94 22.767, 28.958 20.335, 28.536 19.5, 26.097 20.5, 23.658 19.5, 21.219 20.5, 20 20)))') + self.assertEqual( + QgsGeometry.fromWkt("Point (1 1)").triangularWaves(1, 2).asWkt(3), + "Point (1 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1)").triangularWaves(1, 2).asWkt(3), "" + ) # don't crash! + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .triangularWaves(1, 2) + .asWkt(3), + "LineString (1 1, 1.25 3, 1.75 -1, 2.25 3, 2.75 -1, 3.25 3, 3.75 -1, 4.25 3, 4.75 -1, 5.25 3, 5.75 -1, 6.25 3, 6.75 -1, 7.25 3, 7.75 -1, 8.25 3, 8.75 -1, 9.25 3, 9.75 -1, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .triangularWaves(5, 2) + .asWkt(3), + "LineString (1 1, 2.125 3, 4.375 -1, 6.625 3, 8.875 -1, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .triangularWaves(8, 2) + .asWkt(3), + "LineString (1 1, 2.125 3, 4.375 -1, 6.625 3, 8.875 -1, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .triangularWaves(8, 2, True) + .asWkt(3), + "LineString (1 1, 3 3, 7 -1, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .triangularWaves(10, 2) + .asWkt(3), + "LineString (1 1, 3.25 3, 7.75 -1, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .triangularWaves(20, 2) + .asWkt(3), + "LineString (1 1, 3.25 3, 7.75 -1, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1, 10 10)") + .triangularWaves(5, 2) + .asWkt(3), + "LineString (1 1, 2.125 3, 4.375 -1, 6.625 3, 8.875 -1, 8 2.125, 12 4.375, 8 6.625, 12 8.875, 10 10)", + ) + self.assertEqual( + QgsGeometry.fromWkt("MultiLineString ((1 1, 10 1),(10 10, 0 10))") + .triangularWaves(5, 2) + .asWkt(3), + "MultiLineString ((1 1, 2.125 3, 4.375 -1, 6.625 3, 8.875 -1, 10 1),(10 10, 8.75 8, 6.25 12, 3.75 8, 1.25 12, 0 10))", + ) + self.assertEqual( + QgsGeometry.fromWkt( + "Polygon ((1 1, 10 1, 10 10, 1 10, 1 1),(3 4, 8 4, 7 7, 4 6, 3 4))" + ) + .triangularWaves(5, 0.5) + .asWkt(3), + "Polygon ((1 1, 2.125 1.5, 4.375 0.5, 6.625 1.5, 8.875 0.5, 9.5 2.125, 10.5 4.375, 9.5 6.625, 10.5 8.875, 8.875 9.5, 6.625 10.5, 4.375 9.5, 2.125 10.5, 1.5 8.875, 0.5 6.625, 1.5 4.375, 0.5 2.125, 1 1),(3 4, 4.13 4.5, 6.39 3.5, 7.32 4.459, 7.554 6.919, 5.253 5.891, 3.058 5.234, 3 4))", + ) + self.assertEqual( + QgsGeometry.fromWkt( + "MultiPolygon (((1 1, 10 1, 10 10, 1 10, 1 1)),((20 20, 20 30, 30 20, 20 20)))" + ) + .triangularWaves(5, 0.5) + .asWkt(3), + "MultiPolygon (((1 1, 2.125 1.5, 4.375 0.5, 6.625 1.5, 8.875 0.5, 9.5 2.125, 10.5 4.375, 9.5 6.625, 10.5 8.875, 8.875 9.5, 6.625 10.5, 4.375 9.5, 2.125 10.5, 1.5 8.875, 0.5 6.625, 1.5 4.375, 0.5 2.125, 1 1)),((20 20, 19.5 21.219, 20.5 23.658, 19.5 26.097, 20.5 28.536, 21.042 29.665, 22.06 27.233, 24.491 26.216, 25.509 23.784, 27.94 22.767, 28.958 20.335, 28.536 19.5, 26.097 20.5, 23.658 19.5, 21.219 20.5, 20 20)))", + ) def testTriangularRandomizedWaves(self): """Test randomized triangular waves""" - self.assertEqual(QgsGeometry.fromWkt('Point (1 1)').triangularWavesRandomized(1, 2, 2, 3, 1).asWkt(3), - 'Point (1 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1)').triangularWavesRandomized(1, 2, 2, 3, 1).asWkt(3), - '') # don't crash! - self.assertEqual( - QgsGeometry.fromWkt('LineString (1 1, 10 1)').triangularWavesRandomized(1, 2, 2, 3, 1).asWkt(3), - 'LineString (1 1, 1.499 3.933, 2.063 -1.999, 2.681 3.397, 3.375 -1.67, 4.343 3.846, 5 -1.525, 5.721 3.23, 6.489 -1.914, 7.217 3.431, 8.187 -1.778, 9.045 3.803, 9.591 -1.518, 10 1)') - self.assertEqual( - QgsGeometry.fromWkt('LineString (1 1, 10 1)').triangularWavesRandomized(5, 6, 2, 3, 1).asWkt(3), - 'LineString (1 1, 2.499 3.933, 5.063 -1.999, 7.681 3.397, 10 1)') - self.assertEqual( - QgsGeometry.fromWkt('LineString (1 1, 10 1)').triangularWavesRandomized(8, 9, 2, 3, 1).asWkt(3), - 'LineString (1 1, 3.249 3.933, 7.313 -1.999, 10 1)') - self.assertEqual( - QgsGeometry.fromWkt('LineString (1 1, 10 1)').triangularWavesRandomized(10, 12, 1, 2, 1).asWkt(3), - 'LineString (1 1, 3.999 2.933, 9.127 -0.999, 10 1)') - self.assertEqual( - QgsGeometry.fromWkt('LineString (1 1, 10 1)').triangularWavesRandomized(20, 25, 2, 3, 1).asWkt(3), - 'LineString (1 1, 7.246 3.933, 10 1)') - self.assertEqual( - QgsGeometry.fromWkt('LineString (1 1, 10 1, 10 10)').triangularWavesRandomized(5, 6, 2, 3, 1).asWkt(3), - 'LineString (1 1, 2.499 3.933, 5.063 -1.999, 7.681 3.397, 12.67 1.375, 7.154 4.343, 12.525 7, 7.77 9.721, 10 10)') - self.assertEqual( - QgsGeometry.fromWkt('MultiLineString ((1 1, 10 1),(10 10, 0 10))').triangularWavesRandomized(5, 6, 2, 3, - 1).asWkt(3), - 'MultiLineString ((1 1, 2.499 3.933, 5.063 -1.999, 7.681 3.397, 10 1),(10 10, 8.516 7.154, 5.859 12.525, 3.138 7.77, 0.371 12.914, 0 10))') - self.assertEqual(QgsGeometry.fromWkt( - 'Polygon ((1 1, 10 1, 10 10, 1 10, 1 1),(3 4, 8 4, 7 7, 4 6, 3 4))').triangularWavesRandomized(5, 6, 0.2, - 0.5, - 1).asWkt(3), - 'Polygon ((1 1, 2.499 1.48, 5.063 0.5, 7.681 1.319, 10.401 1.375, 9.546 4.343, 10.357 7, 9.731 9.721, 7.511 10.474, 4.783 9.671, 1.813 10.434, 1.441 7.955, 0.645 5.409, 1.449 2.476, 1 1),(3 4, 4.265 4.401, 7.061 3.599, 7.195 5.595, 5.738 6.835, 3.852 4.979, 3 4))') - self.assertEqual(QgsGeometry.fromWkt( - 'MultiPolygon (((1 1, 10 1, 10 10, 1 10, 1 1)),((20 20, 20 30, 30 20, 20 20)))').triangularWavesRandomized( - 5, 6, 0.2, 0.5, 1).asWkt(3), - 'MultiPolygon (((1 1, 2.499 1.48, 5.063 0.5, 7.681 1.319, 10.401 1.375, 9.546 4.343, 10.357 7, 9.731 9.721, 7.511 10.474, 4.783 9.671, 1.813 10.434, 1.441 7.955, 0.645 5.409, 1.449 2.476, 1 1)),((20 20, 19.599 21.265, 20.401 24.061, 19.741 26.767, 20.243 29.412, 21.858 28.6, 23.135 26.317, 25.615 24.795, 27.147 22.476, 29.37 21.112, 28.683 20.471, 26.123 19.643, 23.582 20.475, 20.626 19.71, 20 20)))') + self.assertEqual( + QgsGeometry.fromWkt("Point (1 1)") + .triangularWavesRandomized(1, 2, 2, 3, 1) + .asWkt(3), + "Point (1 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1)") + .triangularWavesRandomized(1, 2, 2, 3, 1) + .asWkt(3), + "", + ) # don't crash! + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .triangularWavesRandomized(1, 2, 2, 3, 1) + .asWkt(3), + "LineString (1 1, 1.499 3.933, 2.063 -1.999, 2.681 3.397, 3.375 -1.67, 4.343 3.846, 5 -1.525, 5.721 3.23, 6.489 -1.914, 7.217 3.431, 8.187 -1.778, 9.045 3.803, 9.591 -1.518, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .triangularWavesRandomized(5, 6, 2, 3, 1) + .asWkt(3), + "LineString (1 1, 2.499 3.933, 5.063 -1.999, 7.681 3.397, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .triangularWavesRandomized(8, 9, 2, 3, 1) + .asWkt(3), + "LineString (1 1, 3.249 3.933, 7.313 -1.999, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .triangularWavesRandomized(10, 12, 1, 2, 1) + .asWkt(3), + "LineString (1 1, 3.999 2.933, 9.127 -0.999, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .triangularWavesRandomized(20, 25, 2, 3, 1) + .asWkt(3), + "LineString (1 1, 7.246 3.933, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1, 10 10)") + .triangularWavesRandomized(5, 6, 2, 3, 1) + .asWkt(3), + "LineString (1 1, 2.499 3.933, 5.063 -1.999, 7.681 3.397, 12.67 1.375, 7.154 4.343, 12.525 7, 7.77 9.721, 10 10)", + ) + self.assertEqual( + QgsGeometry.fromWkt("MultiLineString ((1 1, 10 1),(10 10, 0 10))") + .triangularWavesRandomized(5, 6, 2, 3, 1) + .asWkt(3), + "MultiLineString ((1 1, 2.499 3.933, 5.063 -1.999, 7.681 3.397, 10 1),(10 10, 8.516 7.154, 5.859 12.525, 3.138 7.77, 0.371 12.914, 0 10))", + ) + self.assertEqual( + QgsGeometry.fromWkt( + "Polygon ((1 1, 10 1, 10 10, 1 10, 1 1),(3 4, 8 4, 7 7, 4 6, 3 4))" + ) + .triangularWavesRandomized(5, 6, 0.2, 0.5, 1) + .asWkt(3), + "Polygon ((1 1, 2.499 1.48, 5.063 0.5, 7.681 1.319, 10.401 1.375, 9.546 4.343, 10.357 7, 9.731 9.721, 7.511 10.474, 4.783 9.671, 1.813 10.434, 1.441 7.955, 0.645 5.409, 1.449 2.476, 1 1),(3 4, 4.265 4.401, 7.061 3.599, 7.195 5.595, 5.738 6.835, 3.852 4.979, 3 4))", + ) + self.assertEqual( + QgsGeometry.fromWkt( + "MultiPolygon (((1 1, 10 1, 10 10, 1 10, 1 1)),((20 20, 20 30, 30 20, 20 20)))" + ) + .triangularWavesRandomized(5, 6, 0.2, 0.5, 1) + .asWkt(3), + "MultiPolygon (((1 1, 2.499 1.48, 5.063 0.5, 7.681 1.319, 10.401 1.375, 9.546 4.343, 10.357 7, 9.731 9.721, 7.511 10.474, 4.783 9.671, 1.813 10.434, 1.441 7.955, 0.645 5.409, 1.449 2.476, 1 1)),((20 20, 19.599 21.265, 20.401 24.061, 19.741 26.767, 20.243 29.412, 21.858 28.6, 23.135 26.317, 25.615 24.795, 27.147 22.476, 29.37 21.112, 28.683 20.471, 26.123 19.643, 23.582 20.475, 20.626 19.71, 20 20)))", + ) def testSquareWaves(self): """Test square waves""" - self.assertEqual(QgsGeometry.fromWkt('Point (1 1)').squareWaves(1, 2).asWkt(3), 'Point (1 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1)').squareWaves(1, 2).asWkt(3), '') # just don't crash! - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').squareWaves(1, 2).asWkt(3), - 'LineString (1 1, 1 3, 1.5 3, 1.5 -1, 2 -1, 2 3, 2.5 3, 2.5 -1, 3 -1, 3 3, 3.5 3, 3.5 -1, 4 -1, 4 3, 4.5 3, 4.5 -1, 5 -1, 5 3, 5.5 3, 5.5 -1, 6 -1, 6 3, 6.5 3, 6.5 -1, 7 -1, 7 3, 7.5 3, 7.5 -1, 8 -1, 8 3, 8.5 3, 8.5 -1, 9 -1, 9 3, 9.5 3, 9.5 -1, 10 -1, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').squareWaves(5, 2).asWkt(3), - 'LineString (1 1, 1 3, 3.25 3, 3.25 -1, 5.5 -1, 5.5 3, 7.75 3, 7.75 -1, 10 -1, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').squareWaves(8, 2).asWkt(3), - 'LineString (1 1, 1 3, 3.25 3, 3.25 -1, 5.5 -1, 5.5 3, 7.75 3, 7.75 -1, 10 -1, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').squareWaves(8, 2, True).asWkt(3), - 'LineString (1 1, 1 3, 5 3, 5 -1, 9 -1, 10 1)') # this one could possibly be improved! - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').squareWaves(10, 2).asWkt(3), - 'LineString (1 1, 1 3, 5.5 3, 5.5 -1, 10 -1, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').squareWaves(20, 2).asWkt(3), - 'LineString (1 1, 1 3, 5.5 3, 5.5 -1, 10 -1, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1, 10 10)').squareWaves(5, 2).asWkt(3), - 'LineString (1 1, 1 3, 3.25 3, 3.25 -1, 5.5 -1, 5.5 3, 7.75 3, 7.75 -1, 10 -1, 10 3, 8 3.25, 12 3.25, 12 5.5, 8 5.5, 8 7.75, 12 7.75, 12 10, 10 10)') - self.assertEqual(QgsGeometry.fromWkt('MultiLineString ((1 1, 10 1),(10 10, 0 10))').squareWaves(5, 2).asWkt(3), - 'MultiLineString ((1 1, 1 3, 3.25 3, 3.25 -1, 5.5 -1, 5.5 3, 7.75 3, 7.75 -1, 10 -1, 10 1),(10 10, 10 8, 7.5 8, 7.5 12, 5 12, 5 8, 2.5 8, 2.5 12, 0 12, 0 10))') - self.assertEqual( - QgsGeometry.fromWkt('Polygon ((1 1, 10 1, 10 10, 1 10, 1 1),(3 4, 8 4, 7 7, 4 6, 3 4))').squareWaves(5, - 0.5).asWkt( - 3), - 'Polygon ((1 1, 1 1.5, 3.25 1.5, 3.25 0.5, 5.5 0.5, 5.5 1.5, 7.75 1.5, 7.75 0.5, 10 0.5, 10 1.5, 9.5 3.25, 10.5 3.25, 10.5 5.5, 9.5 5.5, 9.5 7.75, 10.5 7.75, 10.5 10, 9.5 10, 7.75 9.5, 7.75 10.5, 5.5 10.5, 5.5 9.5, 3.25 9.5, 3.25 10.5, 1 10.5, 1 9.5, 1.5 7.75, 0.5 7.75, 0.5 5.5, 1.5 5.5, 1.5 3.25, 0.5 3.25, 0.5 1, 1 1),(3 4, 3 4.5, 5.26 4.5, 5.26 3.5, 7.52 3.5, 7.52 4.5, 6.963 5.531, 7.911 5.847, 6.009 7.197, 6.325 6.248, 4.181 5.533, 3 4))') - self.assertEqual(QgsGeometry.fromWkt( - 'MultiPolygon (((1 1, 10 1, 10 10, 1 10, 1 1)),((20 20, 20 30, 30 20, 20 20)))').squareWaves(5, 0.5).asWkt( - 3), - 'MultiPolygon (((1 1, 1 1.5, 3.25 1.5, 3.25 0.5, 5.5 0.5, 5.5 1.5, 7.75 1.5, 7.75 0.5, 10 0.5, 10 1.5, 9.5 3.25, 10.5 3.25, 10.5 5.5, 9.5 5.5, 9.5 7.75, 10.5 7.75, 10.5 10, 9.5 10, 7.75 9.5, 7.75 10.5, 5.5 10.5, 5.5 9.5, 3.25 9.5, 3.25 10.5, 1 10.5, 1 9.5, 1.5 7.75, 0.5 7.75, 0.5 5.5, 1.5 5.5, 1.5 3.25, 0.5 3.25, 0.5 1, 1 1)),((20 20, 19.5 20, 19.5 22.439, 20.5 22.439, 20.5 24.877, 19.5 24.877, 19.5 27.316, 20.5 27.316, 20.5 29.755, 19.5 29.755, 21.905 28.802, 21.198 28.095, 22.922 26.371, 23.629 27.078, 25.354 25.354, 24.646 24.646, 26.371 22.922, 27.078 23.629, 28.802 21.905, 28.095 21.198, 29.755 20.5, 29.755 19.5, 27.316 19.5, 27.316 20.5, 24.877 20.5, 24.877 19.5, 22.439 19.5, 20 20)))') + self.assertEqual( + QgsGeometry.fromWkt("Point (1 1)").squareWaves(1, 2).asWkt(3), "Point (1 1)" + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1)").squareWaves(1, 2).asWkt(3), "" + ) # just don't crash! + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)").squareWaves(1, 2).asWkt(3), + "LineString (1 1, 1 3, 1.5 3, 1.5 -1, 2 -1, 2 3, 2.5 3, 2.5 -1, 3 -1, 3 3, 3.5 3, 3.5 -1, 4 -1, 4 3, 4.5 3, 4.5 -1, 5 -1, 5 3, 5.5 3, 5.5 -1, 6 -1, 6 3, 6.5 3, 6.5 -1, 7 -1, 7 3, 7.5 3, 7.5 -1, 8 -1, 8 3, 8.5 3, 8.5 -1, 9 -1, 9 3, 9.5 3, 9.5 -1, 10 -1, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)").squareWaves(5, 2).asWkt(3), + "LineString (1 1, 1 3, 3.25 3, 3.25 -1, 5.5 -1, 5.5 3, 7.75 3, 7.75 -1, 10 -1, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)").squareWaves(8, 2).asWkt(3), + "LineString (1 1, 1 3, 3.25 3, 3.25 -1, 5.5 -1, 5.5 3, 7.75 3, 7.75 -1, 10 -1, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .squareWaves(8, 2, True) + .asWkt(3), + "LineString (1 1, 1 3, 5 3, 5 -1, 9 -1, 10 1)", + ) # this one could possibly be improved! + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)").squareWaves(10, 2).asWkt(3), + "LineString (1 1, 1 3, 5.5 3, 5.5 -1, 10 -1, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)").squareWaves(20, 2).asWkt(3), + "LineString (1 1, 1 3, 5.5 3, 5.5 -1, 10 -1, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1, 10 10)") + .squareWaves(5, 2) + .asWkt(3), + "LineString (1 1, 1 3, 3.25 3, 3.25 -1, 5.5 -1, 5.5 3, 7.75 3, 7.75 -1, 10 -1, 10 3, 8 3.25, 12 3.25, 12 5.5, 8 5.5, 8 7.75, 12 7.75, 12 10, 10 10)", + ) + self.assertEqual( + QgsGeometry.fromWkt("MultiLineString ((1 1, 10 1),(10 10, 0 10))") + .squareWaves(5, 2) + .asWkt(3), + "MultiLineString ((1 1, 1 3, 3.25 3, 3.25 -1, 5.5 -1, 5.5 3, 7.75 3, 7.75 -1, 10 -1, 10 1),(10 10, 10 8, 7.5 8, 7.5 12, 5 12, 5 8, 2.5 8, 2.5 12, 0 12, 0 10))", + ) + self.assertEqual( + QgsGeometry.fromWkt( + "Polygon ((1 1, 10 1, 10 10, 1 10, 1 1),(3 4, 8 4, 7 7, 4 6, 3 4))" + ) + .squareWaves(5, 0.5) + .asWkt(3), + "Polygon ((1 1, 1 1.5, 3.25 1.5, 3.25 0.5, 5.5 0.5, 5.5 1.5, 7.75 1.5, 7.75 0.5, 10 0.5, 10 1.5, 9.5 3.25, 10.5 3.25, 10.5 5.5, 9.5 5.5, 9.5 7.75, 10.5 7.75, 10.5 10, 9.5 10, 7.75 9.5, 7.75 10.5, 5.5 10.5, 5.5 9.5, 3.25 9.5, 3.25 10.5, 1 10.5, 1 9.5, 1.5 7.75, 0.5 7.75, 0.5 5.5, 1.5 5.5, 1.5 3.25, 0.5 3.25, 0.5 1, 1 1),(3 4, 3 4.5, 5.26 4.5, 5.26 3.5, 7.52 3.5, 7.52 4.5, 6.963 5.531, 7.911 5.847, 6.009 7.197, 6.325 6.248, 4.181 5.533, 3 4))", + ) + self.assertEqual( + QgsGeometry.fromWkt( + "MultiPolygon (((1 1, 10 1, 10 10, 1 10, 1 1)),((20 20, 20 30, 30 20, 20 20)))" + ) + .squareWaves(5, 0.5) + .asWkt(3), + "MultiPolygon (((1 1, 1 1.5, 3.25 1.5, 3.25 0.5, 5.5 0.5, 5.5 1.5, 7.75 1.5, 7.75 0.5, 10 0.5, 10 1.5, 9.5 3.25, 10.5 3.25, 10.5 5.5, 9.5 5.5, 9.5 7.75, 10.5 7.75, 10.5 10, 9.5 10, 7.75 9.5, 7.75 10.5, 5.5 10.5, 5.5 9.5, 3.25 9.5, 3.25 10.5, 1 10.5, 1 9.5, 1.5 7.75, 0.5 7.75, 0.5 5.5, 1.5 5.5, 1.5 3.25, 0.5 3.25, 0.5 1, 1 1)),((20 20, 19.5 20, 19.5 22.439, 20.5 22.439, 20.5 24.877, 19.5 24.877, 19.5 27.316, 20.5 27.316, 20.5 29.755, 19.5 29.755, 21.905 28.802, 21.198 28.095, 22.922 26.371, 23.629 27.078, 25.354 25.354, 24.646 24.646, 26.371 22.922, 27.078 23.629, 28.802 21.905, 28.095 21.198, 29.755 20.5, 29.755 19.5, 27.316 19.5, 27.316 20.5, 24.877 20.5, 24.877 19.5, 22.439 19.5, 20 20)))", + ) def testSquareRandomizedWaves(self): """Test randomized square waves""" - self.assertEqual(QgsGeometry.fromWkt('Point (1 1)').squareWavesRandomized(1, 2, 2, 3, 1).asWkt(3), - 'Point (1 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1)').squareWavesRandomized(1, 2, 2, 3, 1).asWkt(3), - '') # just don't crash! - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').squareWavesRandomized(1, 2, 2, 3, 1).asWkt(3), - 'LineString (1 1, 1 3.997, 1.966 3.997, 1.966 -1.128, 2.966 -1.128, 2.966 3.236, 3.664 3.236, 3.664 -1.388, 4.499 -1.388, 4.499 3.936, 5.422 3.936, 5.422 -1.313, 6.184 -1.313, 6.184 3.443, 6.799 3.443, 6.799 -1.534, 7.756 -1.534, 7.756 3.457, 8.472 3.457, 8.472 -1.939, 9.361 -1.939, 9.361 3.716, 10 3.716, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').squareWavesRandomized(5, 6, 2, 3, 1).asWkt(3), - 'LineString (1 1, 1 3.997, 3.966 3.997, 3.966 -1.128, 6.966 -1.128, 6.966 3.236, 9.664 3.236, 9.664 -1.388, 10 -1.388, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').squareWavesRandomized(8, 9, 2, 3, 1).asWkt(3), - 'LineString (1 1, 1 3.997, 5.466 3.997, 5.466 -1.128, 9.966 -1.128, 9.966 3.236, 10 3.236, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').squareWavesRandomized(10, 12, 1, 2, 1).asWkt(3), - 'LineString (1 1, 1 2.997, 6.933 2.997, 6.933 -0.128, 10 -0.128, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').squareWavesRandomized(20, 25, 2, 3, 1).asWkt(3), - 'LineString (1 1, 1 3.997, 10 3.997, 10 1)') - self.assertEqual( - QgsGeometry.fromWkt('LineString (1 1, 10 1, 10 10)').squareWavesRandomized(5, 6, 2, 3, 1).asWkt(3), - 'LineString (1 1, 1 3.997, 3.966 3.997, 3.966 -1.128, 6.966 -1.128, 6.966 3.236, 9.664 3.236, 9.664 -1.388, 12.388 3.499, 7.064 3.499, 7.064 6.422, 12.313 6.422, 12.313 9.184, 7.557 9.184, 7.557 10, 10 10)') - self.assertEqual( - QgsGeometry.fromWkt('MultiLineString ((1 1, 10 1),(10 10, 0 10))').squareWavesRandomized(5, 6, 2, 3, - 1).asWkt(3), - 'MultiLineString ((1 1, 1 3.997, 3.966 3.997, 3.966 -1.128, 6.966 -1.128, 6.966 3.236, 9.664 3.236, 9.664 -1.388, 10 -1.388, 10 1),(10 10, 10 7.064, 7.077 7.064, 7.077 12.313, 4.315 12.313, 4.315 7.557, 1.7 7.557, 1.7 12.534, 0 12.534, 0 10))') - self.assertEqual(QgsGeometry.fromWkt( - 'Polygon ((1 1, 10 1, 10 10, 1 10, 1 1),(3 4, 8 4, 7 7, 4 6, 3 4))').squareWavesRandomized(3, 5, 0.2, 0.5, - 1).asWkt(3), - 'Polygon ((1 1, 1 1.499, 3.433 1.499, 3.433 0.762, 5.932 0.762, 5.932 1.271, 7.828 1.271, 7.828 0.684, 9.998 0.684, 9.998 1.481, 9.519 3.344, 10.294 3.344, 10.294 5.369, 9.667 5.369, 9.667 7.098, 10.36 7.098, 10.36 9.512, 9.663 9.512, 8.557 9.663, 8.557 10.482, 6.279 10.482, 6.279 9.585, 3.976 9.585, 3.976 10.228, 1.958 10.228, 1.958 9.54, 1.46 8.629, 0.551 8.629, 0.551 6.855, 1.218 6.855, 1.218 4.685, 0.622 4.685, 0.622 2.513, 1.324 2.513, 1.324 1, 1 1),(3 4, 3 4.287, 4.642 4.287, 4.642 3.565, 6.555 3.565, 6.555 4.21, 7.586 4.577, 8.163 4.77, 7.594 6.476, 6.9 6.244, 6.122 6.355, 5.946 6.883, 4.078 6.26, 4.22 5.832, 3.205 3.898, 3 4))') - self.assertEqual(QgsGeometry.fromWkt( - 'MultiPolygon (((1 1, 10 1, 10 10, 1 10, 1 1)),((20 20, 20 30, 30 20, 20 20)))').squareWavesRandomized(3, 5, - 0.2, - 0.5, - 1).asWkt( - 3), - 'MultiPolygon (((1 1, 1 1.499, 3.433 1.499, 3.433 0.762, 5.932 0.762, 5.932 1.271, 7.828 1.271, 7.828 0.684, 9.998 0.684, 9.998 1.481, 9.519 3.344, 10.294 3.344, 10.294 5.369, 9.667 5.369, 9.667 7.098, 10.36 7.098, 10.36 9.512, 9.663 9.512, 8.557 9.663, 8.557 10.482, 6.279 10.482, 6.279 9.585, 3.976 9.585, 3.976 10.228, 1.958 10.228, 1.958 9.54, 1.46 8.629, 0.551 8.629, 0.551 6.855, 1.218 6.855, 1.218 4.685, 0.622 4.685, 0.622 2.513, 1.324 2.513, 1.324 1, 1 1)),((20 20, 19.713 20, 19.713 21.642, 20.435 21.642, 20.435 23.555, 19.79 23.555, 19.79 25.679, 20.398 25.679, 20.398 27.477, 19.666 27.477, 19.666 29.199, 20.222 29.199, 20.669 29.017, 20.988 29.336, 22.688 27.636, 22.359 27.308, 23.791 25.876, 24.117 26.202, 25.826 24.493, 25.332 23.999, 26.604 22.727, 27.204 23.327, 28.665 21.866, 28.128 21.329, 29.807 20.384, 29.807 19.722, 28.076 19.722, 28.076 20.36, 25.626 20.36, 25.626 19.652, 23.586 19.652, 23.586 20.43, 22.04 20.43, 22.04 19.758, 20 19.758, 20 20)))') + self.assertEqual( + QgsGeometry.fromWkt("Point (1 1)") + .squareWavesRandomized(1, 2, 2, 3, 1) + .asWkt(3), + "Point (1 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1)") + .squareWavesRandomized(1, 2, 2, 3, 1) + .asWkt(3), + "", + ) # just don't crash! + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .squareWavesRandomized(1, 2, 2, 3, 1) + .asWkt(3), + "LineString (1 1, 1 3.997, 1.966 3.997, 1.966 -1.128, 2.966 -1.128, 2.966 3.236, 3.664 3.236, 3.664 -1.388, 4.499 -1.388, 4.499 3.936, 5.422 3.936, 5.422 -1.313, 6.184 -1.313, 6.184 3.443, 6.799 3.443, 6.799 -1.534, 7.756 -1.534, 7.756 3.457, 8.472 3.457, 8.472 -1.939, 9.361 -1.939, 9.361 3.716, 10 3.716, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .squareWavesRandomized(5, 6, 2, 3, 1) + .asWkt(3), + "LineString (1 1, 1 3.997, 3.966 3.997, 3.966 -1.128, 6.966 -1.128, 6.966 3.236, 9.664 3.236, 9.664 -1.388, 10 -1.388, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .squareWavesRandomized(8, 9, 2, 3, 1) + .asWkt(3), + "LineString (1 1, 1 3.997, 5.466 3.997, 5.466 -1.128, 9.966 -1.128, 9.966 3.236, 10 3.236, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .squareWavesRandomized(10, 12, 1, 2, 1) + .asWkt(3), + "LineString (1 1, 1 2.997, 6.933 2.997, 6.933 -0.128, 10 -0.128, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .squareWavesRandomized(20, 25, 2, 3, 1) + .asWkt(3), + "LineString (1 1, 1 3.997, 10 3.997, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1, 10 10)") + .squareWavesRandomized(5, 6, 2, 3, 1) + .asWkt(3), + "LineString (1 1, 1 3.997, 3.966 3.997, 3.966 -1.128, 6.966 -1.128, 6.966 3.236, 9.664 3.236, 9.664 -1.388, 12.388 3.499, 7.064 3.499, 7.064 6.422, 12.313 6.422, 12.313 9.184, 7.557 9.184, 7.557 10, 10 10)", + ) + self.assertEqual( + QgsGeometry.fromWkt("MultiLineString ((1 1, 10 1),(10 10, 0 10))") + .squareWavesRandomized(5, 6, 2, 3, 1) + .asWkt(3), + "MultiLineString ((1 1, 1 3.997, 3.966 3.997, 3.966 -1.128, 6.966 -1.128, 6.966 3.236, 9.664 3.236, 9.664 -1.388, 10 -1.388, 10 1),(10 10, 10 7.064, 7.077 7.064, 7.077 12.313, 4.315 12.313, 4.315 7.557, 1.7 7.557, 1.7 12.534, 0 12.534, 0 10))", + ) + self.assertEqual( + QgsGeometry.fromWkt( + "Polygon ((1 1, 10 1, 10 10, 1 10, 1 1),(3 4, 8 4, 7 7, 4 6, 3 4))" + ) + .squareWavesRandomized(3, 5, 0.2, 0.5, 1) + .asWkt(3), + "Polygon ((1 1, 1 1.499, 3.433 1.499, 3.433 0.762, 5.932 0.762, 5.932 1.271, 7.828 1.271, 7.828 0.684, 9.998 0.684, 9.998 1.481, 9.519 3.344, 10.294 3.344, 10.294 5.369, 9.667 5.369, 9.667 7.098, 10.36 7.098, 10.36 9.512, 9.663 9.512, 8.557 9.663, 8.557 10.482, 6.279 10.482, 6.279 9.585, 3.976 9.585, 3.976 10.228, 1.958 10.228, 1.958 9.54, 1.46 8.629, 0.551 8.629, 0.551 6.855, 1.218 6.855, 1.218 4.685, 0.622 4.685, 0.622 2.513, 1.324 2.513, 1.324 1, 1 1),(3 4, 3 4.287, 4.642 4.287, 4.642 3.565, 6.555 3.565, 6.555 4.21, 7.586 4.577, 8.163 4.77, 7.594 6.476, 6.9 6.244, 6.122 6.355, 5.946 6.883, 4.078 6.26, 4.22 5.832, 3.205 3.898, 3 4))", + ) + self.assertEqual( + QgsGeometry.fromWkt( + "MultiPolygon (((1 1, 10 1, 10 10, 1 10, 1 1)),((20 20, 20 30, 30 20, 20 20)))" + ) + .squareWavesRandomized(3, 5, 0.2, 0.5, 1) + .asWkt(3), + "MultiPolygon (((1 1, 1 1.499, 3.433 1.499, 3.433 0.762, 5.932 0.762, 5.932 1.271, 7.828 1.271, 7.828 0.684, 9.998 0.684, 9.998 1.481, 9.519 3.344, 10.294 3.344, 10.294 5.369, 9.667 5.369, 9.667 7.098, 10.36 7.098, 10.36 9.512, 9.663 9.512, 8.557 9.663, 8.557 10.482, 6.279 10.482, 6.279 9.585, 3.976 9.585, 3.976 10.228, 1.958 10.228, 1.958 9.54, 1.46 8.629, 0.551 8.629, 0.551 6.855, 1.218 6.855, 1.218 4.685, 0.622 4.685, 0.622 2.513, 1.324 2.513, 1.324 1, 1 1)),((20 20, 19.713 20, 19.713 21.642, 20.435 21.642, 20.435 23.555, 19.79 23.555, 19.79 25.679, 20.398 25.679, 20.398 27.477, 19.666 27.477, 19.666 29.199, 20.222 29.199, 20.669 29.017, 20.988 29.336, 22.688 27.636, 22.359 27.308, 23.791 25.876, 24.117 26.202, 25.826 24.493, 25.332 23.999, 26.604 22.727, 27.204 23.327, 28.665 21.866, 28.128 21.329, 29.807 20.384, 29.807 19.722, 28.076 19.722, 28.076 20.36, 25.626 20.36, 25.626 19.652, 23.586 19.652, 23.586 20.43, 22.04 20.43, 22.04 19.758, 20 19.758, 20 20)))", + ) def testRoundWaves(self): """Test round waves""" - self.assertEqual(QgsGeometry.fromWkt('Point (1 1)').roundWaves(1, 2).asWkt(3), 'Point (1 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1)').roundWaves(1, 2).asWkt(3), '') # just don't crash! - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').roundWaves(1, 2).asWkt(3), - 'LineString (1 1, 1.021 0.701, 1.044 0.408, 1.07 0.127, 1.097 -0.136, 1.125 -0.375, 1.153 -0.584, 1.18 -0.757, 1.206 -0.888, 1.23 -0.971, 1.25 -1, 1.318 -0.888, 1.374 -0.584, 1.421 -0.136, 1.462 0.408, 1.5 1, 1.538 1.592, 1.579 2.136, 1.626 2.584, 1.682 2.888, 1.75 3, 1.818 2.888, 1.874 2.584, 1.921 2.136, 1.962 1.592, 2 1, 2.038 0.408, 2.079 -0.136, 2.126 -0.584, 2.182 -0.888, 2.25 -1, 2.318 -0.888, 2.374 -0.584, 2.421 -0.136, 2.462 0.408, 2.5 1, 2.538 1.592, 2.579 2.136, 2.626 2.584, 2.682 2.888, 2.75 3, 2.818 2.888, 2.874 2.584, 2.921 2.136, 2.962 1.592, 3 1, 3.038 0.408, 3.079 -0.136, 3.126 -0.584, 3.182 -0.888, 3.25 -1, 3.318 -0.888, 3.374 -0.584, 3.421 -0.136, 3.462 0.408, 3.5 1, 3.538 1.592, 3.579 2.136, 3.626 2.584, 3.682 2.888, 3.75 3, 3.818 2.888, 3.874 2.584, 3.921 2.136, 3.962 1.592, 4 1, 4.038 0.408, 4.079 -0.136, 4.126 -0.584, 4.182 -0.888, 4.25 -1, 4.318 -0.888, 4.374 -0.584, 4.421 -0.136, 4.462 0.408, 4.5 1, 4.538 1.592, 4.579 2.136, 4.626 2.584, 4.682 2.888, 4.75 3, 4.818 2.888, 4.874 2.584, 4.921 2.136, 4.962 1.592, 5 1, 5.038 0.408, 5.079 -0.136, 5.126 -0.584, 5.182 -0.888, 5.25 -1, 5.318 -0.888, 5.374 -0.584, 5.421 -0.136, 5.462 0.408, 5.5 1, 5.538 1.592, 5.579 2.136, 5.626 2.584, 5.682 2.888, 5.75 3, 5.818 2.888, 5.874 2.584, 5.921 2.136, 5.962 1.592, 6 1, 6.038 0.408, 6.079 -0.136, 6.126 -0.584, 6.182 -0.888, 6.25 -1, 6.318 -0.888, 6.374 -0.584, 6.421 -0.136, 6.462 0.408, 6.5 1, 6.538 1.592, 6.579 2.136, 6.626 2.584, 6.682 2.888, 6.75 3, 6.818 2.888, 6.874 2.584, 6.921 2.136, 6.962 1.592, 7 1, 7.038 0.408, 7.079 -0.136, 7.126 -0.584, 7.182 -0.888, 7.25 -1, 7.318 -0.888, 7.374 -0.584, 7.421 -0.136, 7.462 0.408, 7.5 1, 7.538 1.592, 7.579 2.136, 7.626 2.584, 7.682 2.888, 7.75 3, 7.818 2.888, 7.874 2.584, 7.921 2.136, 7.962 1.592, 8 1, 8.038 0.408, 8.079 -0.136, 8.126 -0.584, 8.182 -0.888, 8.25 -1, 8.318 -0.888, 8.374 -0.584, 8.421 -0.136, 8.462 0.408, 8.5 1, 8.538 1.592, 8.579 2.136, 8.626 2.584, 8.682 2.888, 8.75 3, 8.818 2.888, 8.874 2.584, 8.921 2.136, 8.962 1.592, 9 1, 9.038 0.408, 9.079 -0.136, 9.126 -0.584, 9.182 -0.888, 9.25 -1, 9.318 -0.888, 9.374 -0.584, 9.421 -0.136, 9.462 0.408, 9.5 1, 9.538 1.592, 9.579 2.136, 9.626 2.584, 9.682 2.888, 9.75 3, 9.824 2.888, 9.892 2.584, 9.948 2.136, 9.986 1.592, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').roundWaves(5, 2).asWkt(3), - 'LineString (1 1, 1.092 0.701, 1.198 0.408, 1.314 0.127, 1.437 -0.136, 1.563 -0.375, 1.689 -0.584, 1.811 -0.757, 1.927 -0.888, 2.033 -0.971, 2.125 -1, 2.431 -0.888, 2.683 -0.584, 2.895 -0.136, 3.079 0.408, 3.25 1, 3.421 1.592, 3.606 2.136, 3.817 2.584, 4.069 2.888, 4.375 3, 4.681 2.888, 4.933 2.584, 5.145 2.136, 5.329 1.592, 5.5 1, 5.671 0.408, 5.856 -0.136, 6.067 -0.584, 6.319 -0.888, 6.625 -1, 6.931 -0.888, 7.183 -0.584, 7.395 -0.136, 7.579 0.408, 7.75 1, 7.921 1.592, 8.106 2.136, 8.317 2.584, 8.569 2.888, 8.875 3, 9.208 2.888, 9.514 2.584, 9.766 2.136, 9.937 1.592, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').roundWaves(8, 2).asWkt(3), - 'LineString (1 1, 1.092 0.701, 1.198 0.408, 1.314 0.127, 1.437 -0.136, 1.563 -0.375, 1.689 -0.584, 1.811 -0.757, 1.927 -0.888, 2.033 -0.971, 2.125 -1, 2.431 -0.888, 2.683 -0.584, 2.895 -0.136, 3.079 0.408, 3.25 1, 3.421 1.592, 3.606 2.136, 3.817 2.584, 4.069 2.888, 4.375 3, 4.681 2.888, 4.933 2.584, 5.145 2.136, 5.329 1.592, 5.5 1, 5.671 0.408, 5.856 -0.136, 6.067 -0.584, 6.319 -0.888, 6.625 -1, 6.931 -0.888, 7.183 -0.584, 7.395 -0.136, 7.579 0.408, 7.75 1, 7.921 1.592, 8.106 2.136, 8.317 2.584, 8.569 2.888, 8.875 3, 9.208 2.888, 9.514 2.584, 9.766 2.136, 9.937 1.592, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').roundWaves(8, 2, True).asWkt(3), - 'LineString (1 1, 1.164 0.701, 1.352 0.408, 1.558 0.127, 1.776 -0.136, 2 -0.375, 2.224 -0.584, 2.442 -0.757, 2.648 -0.888, 2.836 -0.971, 3 -1, 3.544 -0.888, 3.992 -0.584, 4.368 -0.136, 4.696 0.408, 5 1, 5.304 1.592, 5.632 2.136, 6.008 2.584, 6.456 2.888, 7 3, 7.768 2.888, 8.524 2.584, 9.196 2.136, 9.712 1.592, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').roundWaves(10, 2).asWkt(3), - 'LineString (1 1, 1.185 0.701, 1.396 0.408, 1.628 0.127, 1.873 -0.136, 2.125 -0.375, 2.377 -0.584, 2.622 -0.757, 2.854 -0.888, 3.066 -0.971, 3.25 -1, 3.862 -0.888, 4.366 -0.584, 4.789 -0.136, 5.158 0.408, 5.5 1, 5.842 1.592, 6.211 2.136, 6.634 2.584, 7.138 2.888, 7.75 3, 8.416 2.888, 9.028 2.584, 9.532 2.136, 9.874 1.592, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').roundWaves(20, 2).asWkt(3), - 'LineString (1 1, 1.185 0.701, 1.396 0.408, 1.628 0.127, 1.873 -0.136, 2.125 -0.375, 2.377 -0.584, 2.622 -0.757, 2.854 -0.888, 3.066 -0.971, 3.25 -1, 3.862 -0.888, 4.366 -0.584, 4.789 -0.136, 5.158 0.408, 5.5 1, 5.842 1.592, 6.211 2.136, 6.634 2.584, 7.138 2.888, 7.75 3, 8.416 2.888, 9.028 2.584, 9.532 2.136, 9.874 1.592, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1, 10 10)').roundWaves(5, 2).asWkt(3), - 'LineString (1 1, 1.092 0.701, 1.198 0.408, 1.314 0.127, 1.437 -0.136, 1.563 -0.375, 1.689 -0.584, 1.811 -0.757, 1.927 -0.888, 2.033 -0.971, 2.125 -1, 2.431 -0.888, 2.683 -0.584, 2.895 -0.136, 3.079 0.408, 3.25 1, 3.421 1.592, 3.606 2.136, 3.817 2.584, 4.069 2.888, 4.375 3, 4.681 2.888, 4.933 2.584, 5.145 2.136, 5.329 1.592, 5.5 1, 5.671 0.408, 5.856 -0.136, 6.067 -0.584, 6.319 -0.888, 6.625 -1, 6.931 -0.888, 7.183 -0.584, 7.395 -0.136, 7.579 0.408, 7.75 1, 7.921 1.592, 8.106 2.136, 8.317 2.584, 8.569 2.888, 8.875 3, 9.182 2.891, 9.44 2.609, 9.668 2.22, 9.885 1.792, 10.109 1.391, 10.36 1.083, 10.656 0.936, 11.015 1.016, 11.457 1.39, 12 2.125, 11.888 2.431, 11.584 2.683, 11.136 2.895, 10.592 3.079, 10 3.25, 9.408 3.421, 8.864 3.606, 8.416 3.817, 8.112 4.069, 8 4.375, 8.112 4.681, 8.416 4.933, 8.864 5.145, 9.408 5.329, 10 5.5, 10.592 5.671, 11.136 5.856, 11.584 6.067, 11.888 6.319, 12 6.625, 11.888 6.931, 11.584 7.183, 11.136 7.395, 10.592 7.579, 10 7.75, 9.408 7.921, 8.864 8.106, 8.416 8.317, 8.112 8.569, 8 8.875, 8.112 9.208, 8.416 9.514, 8.864 9.766, 9.408 9.937, 10 10)') - self.assertEqual(QgsGeometry.fromWkt('MultiLineString ((1 1, 10 1),(10 10, 0 10))').roundWaves(5, 2).asWkt(3), - 'MultiLineString ((1 1, 1.092 0.701, 1.198 0.408, 1.314 0.127, 1.437 -0.136, 1.563 -0.375, 1.689 -0.584, 1.811 -0.757, 1.927 -0.888, 2.033 -0.971, 2.125 -1, 2.431 -0.888, 2.683 -0.584, 2.895 -0.136, 3.079 0.408, 3.25 1, 3.421 1.592, 3.606 2.136, 3.817 2.584, 4.069 2.888, 4.375 3, 4.681 2.888, 4.933 2.584, 5.145 2.136, 5.329 1.592, 5.5 1, 5.671 0.408, 5.856 -0.136, 6.067 -0.584, 6.319 -0.888, 6.625 -1, 6.931 -0.888, 7.183 -0.584, 7.395 -0.136, 7.579 0.408, 7.75 1, 7.921 1.592, 8.106 2.136, 8.317 2.584, 8.569 2.888, 8.875 3, 9.208 2.888, 9.514 2.584, 9.766 2.136, 9.937 1.592, 10 1),(10 10, 9.897 10.299, 9.78 10.592, 9.651 10.873, 9.515 11.136, 9.375 11.375, 9.235 11.584, 9.099 11.757, 8.97 11.888, 8.853 11.971, 8.75 12, 8.41 11.888, 8.13 11.584, 7.895 11.136, 7.69 10.592, 7.5 10, 7.31 9.408, 7.105 8.864, 6.87 8.416, 6.59 8.112, 6.25 8, 5.91 8.112, 5.63 8.416, 5.395 8.864, 5.19 9.408, 5 10, 4.81 10.592, 4.605 11.136, 4.37 11.584, 4.09 11.888, 3.75 12, 3.41 11.888, 3.13 11.584, 2.895 11.136, 2.69 10.592, 2.5 10, 2.31 9.408, 2.105 8.864, 1.87 8.416, 1.59 8.112, 1.25 8, 0.88 8.112, 0.54 8.416, 0.26 8.864, 0.07 9.408, 0 10))') - self.assertEqual( - QgsGeometry.fromWkt('Polygon ((1 1, 10 1, 10 10, 1 10, 1 1),(3 4, 8 4, 7 7, 4 6, 3 4))').roundWaves(5, - 0.2).asWkt( - 3), - 'Polygon ((1 1, 1.092 0.97, 1.198 0.941, 1.314 0.913, 1.437 0.886, 1.563 0.863, 1.689 0.842, 1.811 0.824, 1.927 0.811, 2.033 0.803, 2.125 0.8, 2.431 0.811, 2.683 0.842, 2.895 0.886, 3.079 0.941, 3.25 1, 3.421 1.059, 3.606 1.114, 3.817 1.158, 4.069 1.189, 4.375 1.2, 4.681 1.189, 4.933 1.158, 5.145 1.114, 5.329 1.059, 5.5 1, 5.671 0.941, 5.856 0.886, 6.067 0.842, 6.319 0.811, 6.625 0.8, 6.931 0.811, 7.183 0.842, 7.395 0.886, 7.579 0.941, 7.75 1, 7.921 1.059, 8.106 1.114, 8.317 1.158, 8.569 1.189, 8.875 1.2, 9.18 1.19, 9.426 1.169, 9.62 1.149, 9.77 1.144, 9.884 1.166, 9.971 1.227, 10.038 1.341, 10.093 1.52, 10.145 1.777, 10.2 2.125, 10.189 2.431, 10.158 2.683, 10.114 2.895, 10.059 3.079, 10 3.25, 9.941 3.421, 9.886 3.606, 9.842 3.817, 9.811 4.069, 9.8 4.375, 9.811 4.681, 9.842 4.933, 9.886 5.145, 9.941 5.329, 10 5.5, 10.059 5.671, 10.114 5.856, 10.158 6.067, 10.189 6.319, 10.2 6.625, 10.189 6.931, 10.158 7.183, 10.114 7.395, 10.059 7.579, 10 7.75, 9.941 7.921, 9.886 8.106, 9.842 8.317, 9.811 8.569, 9.8 8.875, 9.81 9.18, 9.831 9.426, 9.851 9.62, 9.856 9.77, 9.834 9.884, 9.773 9.971, 9.659 10.038, 9.48 10.093, 9.223 10.145, 8.875 10.2, 8.569 10.189, 8.317 10.158, 8.106 10.114, 7.921 10.059, 7.75 10, 7.579 9.941, 7.395 9.886, 7.183 9.842, 6.931 9.811, 6.625 9.8, 6.319 9.811, 6.067 9.842, 5.856 9.886, 5.671 9.941, 5.5 10, 5.329 10.059, 5.145 10.114, 4.933 10.158, 4.681 10.189, 4.375 10.2, 4.069 10.189, 3.817 10.158, 3.606 10.114, 3.421 10.059, 3.25 10, 3.079 9.941, 2.895 9.886, 2.683 9.842, 2.431 9.811, 2.125 9.8, 1.82 9.81, 1.574 9.831, 1.38 9.851, 1.23 9.856, 1.116 9.834, 1.029 9.773, 0.962 9.659, 0.907 9.48, 0.855 9.223, 0.8 8.875, 0.811 8.569, 0.842 8.317, 0.886 8.106, 0.941 7.921, 1 7.75, 1.059 7.579, 1.114 7.395, 1.158 7.183, 1.189 6.931, 1.2 6.625, 1.189 6.319, 1.158 6.067, 1.114 5.856, 1.059 5.671, 1 5.5, 0.941 5.329, 0.886 5.145, 0.842 4.933, 0.811 4.681, 0.8 4.375, 0.811 4.069, 0.842 3.817, 0.886 3.606, 0.941 3.421, 1 3.25, 1.059 3.079, 1.114 2.895, 1.158 2.683, 1.189 2.431, 1.2 2.125, 1.189 1.792, 1.158 1.486, 1.114 1.234, 1.059 1.063, 1 1),(3 4, 3.093 3.97, 3.199 3.941, 3.315 3.913, 3.438 3.886, 3.565 3.863, 3.692 3.842, 3.815 3.824, 3.931 3.811, 4.037 3.803, 4.13 3.8, 4.437 3.811, 4.691 3.842, 4.903 3.886, 5.088 3.941, 5.26 4, 5.432 4.059, 5.617 4.114, 5.83 4.158, 6.083 4.189, 6.39 4.2, 6.697 4.19, 6.945 4.165, 7.145 4.137, 7.306 4.116, 7.437 4.11, 7.548 4.131, 7.649 4.188, 7.749 4.292, 7.857 4.453, 7.984 4.68, 7.876 4.968, 7.767 5.199, 7.658 5.386, 7.547 5.545, 7.437 5.689, 7.327 5.833, 7.216 5.992, 7.107 6.179, 6.998 6.41, 6.89 6.698, 6.707 6.663, 6.546 6.654, 6.4 6.662, 6.26 6.679, 6.115 6.698, 5.959 6.712, 5.781 6.712, 5.573 6.691, 5.326 6.641, 5.032 6.555, 4.744 6.446, 4.518 6.334, 4.344 6.214, 4.21 6.084, 4.107 5.94, 4.023 5.781, 3.95 5.602, 3.876 5.401, 3.791 5.175, 3.684 4.921, 3.585 4.748, 3.451 4.548, 3.298 4.341, 3.142 4.151, 3 4))') - self.assertEqual(QgsGeometry.fromWkt( - 'MultiPolygon (((1 1, 10 1, 10 10, 1 10, 1 1)),((20 20, 20 30, 30 20, 20 20)))').roundWaves(5, 0.2).asWkt( - 3), - 'MultiPolygon (((1 1, 1.092 0.97, 1.198 0.941, 1.314 0.913, 1.437 0.886, 1.563 0.863, 1.689 0.842, 1.811 0.824, 1.927 0.811, 2.033 0.803, 2.125 0.8, 2.431 0.811, 2.683 0.842, 2.895 0.886, 3.079 0.941, 3.25 1, 3.421 1.059, 3.606 1.114, 3.817 1.158, 4.069 1.189, 4.375 1.2, 4.681 1.189, 4.933 1.158, 5.145 1.114, 5.329 1.059, 5.5 1, 5.671 0.941, 5.856 0.886, 6.067 0.842, 6.319 0.811, 6.625 0.8, 6.931 0.811, 7.183 0.842, 7.395 0.886, 7.579 0.941, 7.75 1, 7.921 1.059, 8.106 1.114, 8.317 1.158, 8.569 1.189, 8.875 1.2, 9.18 1.19, 9.426 1.169, 9.62 1.149, 9.77 1.144, 9.884 1.166, 9.971 1.227, 10.038 1.341, 10.093 1.52, 10.145 1.777, 10.2 2.125, 10.189 2.431, 10.158 2.683, 10.114 2.895, 10.059 3.079, 10 3.25, 9.941 3.421, 9.886 3.606, 9.842 3.817, 9.811 4.069, 9.8 4.375, 9.811 4.681, 9.842 4.933, 9.886 5.145, 9.941 5.329, 10 5.5, 10.059 5.671, 10.114 5.856, 10.158 6.067, 10.189 6.319, 10.2 6.625, 10.189 6.931, 10.158 7.183, 10.114 7.395, 10.059 7.579, 10 7.75, 9.941 7.921, 9.886 8.106, 9.842 8.317, 9.811 8.569, 9.8 8.875, 9.81 9.18, 9.831 9.426, 9.851 9.62, 9.856 9.77, 9.834 9.884, 9.773 9.971, 9.659 10.038, 9.48 10.093, 9.223 10.145, 8.875 10.2, 8.569 10.189, 8.317 10.158, 8.106 10.114, 7.921 10.059, 7.75 10, 7.579 9.941, 7.395 9.886, 7.183 9.842, 6.931 9.811, 6.625 9.8, 6.319 9.811, 6.067 9.842, 5.856 9.886, 5.671 9.941, 5.5 10, 5.329 10.059, 5.145 10.114, 4.933 10.158, 4.681 10.189, 4.375 10.2, 4.069 10.189, 3.817 10.158, 3.606 10.114, 3.421 10.059, 3.25 10, 3.079 9.941, 2.895 9.886, 2.683 9.842, 2.431 9.811, 2.125 9.8, 1.82 9.81, 1.574 9.831, 1.38 9.851, 1.23 9.856, 1.116 9.834, 1.029 9.773, 0.962 9.659, 0.907 9.48, 0.855 9.223, 0.8 8.875, 0.811 8.569, 0.842 8.317, 0.886 8.106, 0.941 7.921, 1 7.75, 1.059 7.579, 1.114 7.395, 1.158 7.183, 1.189 6.931, 1.2 6.625, 1.189 6.319, 1.158 6.067, 1.114 5.856, 1.059 5.671, 1 5.5, 0.941 5.329, 0.886 5.145, 0.842 4.933, 0.811 4.681, 0.8 4.375, 0.811 4.069, 0.842 3.817, 0.886 3.606, 0.941 3.421, 1 3.25, 1.059 3.079, 1.114 2.895, 1.158 2.683, 1.189 2.431, 1.2 2.125, 1.189 1.792, 1.158 1.486, 1.114 1.234, 1.059 1.063, 1 1)),((20 20, 20.03 20.1, 20.059 20.215, 20.087 20.34, 20.114 20.473, 20.138 20.61, 20.158 20.746, 20.176 20.879, 20.189 21.005, 20.197 21.119, 20.2 21.219, 20.189 21.551, 20.158 21.824, 20.114 22.053, 20.059 22.253, 20 22.439, 19.941 22.624, 19.886 22.824, 19.842 23.053, 19.811 23.326, 19.8 23.658, 19.811 23.99, 19.842 24.263, 19.886 24.492, 19.941 24.692, 20 24.877, 20.059 25.063, 20.114 25.263, 20.158 25.492, 20.189 25.765, 20.2 26.097, 20.189 26.428, 20.158 26.702, 20.114 26.931, 20.059 27.131, 20 27.316, 19.941 27.502, 19.886 27.701, 19.842 27.931, 19.811 28.204, 19.8 28.536, 19.812 28.865, 19.844 29.126, 19.896 29.321, 19.963 29.454, 20.043 29.529, 20.134 29.55, 20.233 29.521, 20.336 29.446, 20.442 29.327, 20.547 29.17, 20.79 28.943, 21.005 28.771, 21.198 28.641, 21.378 28.538, 21.551 28.449, 21.724 28.36, 21.904 28.257, 22.098 28.126, 22.312 27.955, 22.555 27.728, 22.781 27.486, 22.953 27.271, 23.083 27.077, 23.186 26.897, 23.276 26.724, 23.365 26.552, 23.468 26.372, 23.598 26.178, 23.77 25.963, 23.996 25.721, 24.239 25.494, 24.453 25.323, 24.647 25.192, 24.827 25.089, 25 25, 25.173 24.911, 25.353 24.808, 25.547 24.677, 25.761 24.506, 26.004 24.279, 26.23 24.037, 26.402 23.822, 26.532 23.628, 26.635 23.448, 26.724 23.276, 26.814 23.103, 26.917 22.923, 27.047 22.729, 27.219 22.514, 27.445 22.272, 27.688 22.045, 27.902 21.874, 28.096 21.743, 28.276 21.64, 28.449 21.551, 28.622 21.462, 28.802 21.359, 28.995 21.229, 29.21 21.057, 29.453 20.83, 29.533 20.562, 29.59 20.369, 29.618 20.24, 29.612 20.163, 29.565 20.129, 29.472 20.125, 29.328 20.141, 29.128 20.167, 28.866 20.19, 28.536 20.2, 28.204 20.189, 27.931 20.158, 27.701 20.114, 27.502 20.059, 27.316 20, 27.131 19.941, 26.931 19.886, 26.702 19.842, 26.428 19.811, 26.097 19.8, 25.765 19.811, 25.492 19.842, 25.263 19.886, 25.063 19.941, 24.877 20, 24.692 20.059, 24.492 20.114, 24.263 20.158, 23.99 20.189, 23.658 20.2, 23.326 20.189, 23.053 20.158, 22.824 20.114, 22.624 20.059, 22.439 20, 22.253 19.941, 22.053 19.886, 21.824 19.842, 21.551 19.811, 21.219 19.8, 21.005 19.811, 20.746 19.842, 20.473 19.886, 20.215 19.941, 20 20)))') + self.assertEqual( + QgsGeometry.fromWkt("Point (1 1)").roundWaves(1, 2).asWkt(3), "Point (1 1)" + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1)").roundWaves(1, 2).asWkt(3), "" + ) # just don't crash! + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)").roundWaves(1, 2).asWkt(3), + "LineString (1 1, 1.021 0.701, 1.044 0.408, 1.07 0.127, 1.097 -0.136, 1.125 -0.375, 1.153 -0.584, 1.18 -0.757, 1.206 -0.888, 1.23 -0.971, 1.25 -1, 1.318 -0.888, 1.374 -0.584, 1.421 -0.136, 1.462 0.408, 1.5 1, 1.538 1.592, 1.579 2.136, 1.626 2.584, 1.682 2.888, 1.75 3, 1.818 2.888, 1.874 2.584, 1.921 2.136, 1.962 1.592, 2 1, 2.038 0.408, 2.079 -0.136, 2.126 -0.584, 2.182 -0.888, 2.25 -1, 2.318 -0.888, 2.374 -0.584, 2.421 -0.136, 2.462 0.408, 2.5 1, 2.538 1.592, 2.579 2.136, 2.626 2.584, 2.682 2.888, 2.75 3, 2.818 2.888, 2.874 2.584, 2.921 2.136, 2.962 1.592, 3 1, 3.038 0.408, 3.079 -0.136, 3.126 -0.584, 3.182 -0.888, 3.25 -1, 3.318 -0.888, 3.374 -0.584, 3.421 -0.136, 3.462 0.408, 3.5 1, 3.538 1.592, 3.579 2.136, 3.626 2.584, 3.682 2.888, 3.75 3, 3.818 2.888, 3.874 2.584, 3.921 2.136, 3.962 1.592, 4 1, 4.038 0.408, 4.079 -0.136, 4.126 -0.584, 4.182 -0.888, 4.25 -1, 4.318 -0.888, 4.374 -0.584, 4.421 -0.136, 4.462 0.408, 4.5 1, 4.538 1.592, 4.579 2.136, 4.626 2.584, 4.682 2.888, 4.75 3, 4.818 2.888, 4.874 2.584, 4.921 2.136, 4.962 1.592, 5 1, 5.038 0.408, 5.079 -0.136, 5.126 -0.584, 5.182 -0.888, 5.25 -1, 5.318 -0.888, 5.374 -0.584, 5.421 -0.136, 5.462 0.408, 5.5 1, 5.538 1.592, 5.579 2.136, 5.626 2.584, 5.682 2.888, 5.75 3, 5.818 2.888, 5.874 2.584, 5.921 2.136, 5.962 1.592, 6 1, 6.038 0.408, 6.079 -0.136, 6.126 -0.584, 6.182 -0.888, 6.25 -1, 6.318 -0.888, 6.374 -0.584, 6.421 -0.136, 6.462 0.408, 6.5 1, 6.538 1.592, 6.579 2.136, 6.626 2.584, 6.682 2.888, 6.75 3, 6.818 2.888, 6.874 2.584, 6.921 2.136, 6.962 1.592, 7 1, 7.038 0.408, 7.079 -0.136, 7.126 -0.584, 7.182 -0.888, 7.25 -1, 7.318 -0.888, 7.374 -0.584, 7.421 -0.136, 7.462 0.408, 7.5 1, 7.538 1.592, 7.579 2.136, 7.626 2.584, 7.682 2.888, 7.75 3, 7.818 2.888, 7.874 2.584, 7.921 2.136, 7.962 1.592, 8 1, 8.038 0.408, 8.079 -0.136, 8.126 -0.584, 8.182 -0.888, 8.25 -1, 8.318 -0.888, 8.374 -0.584, 8.421 -0.136, 8.462 0.408, 8.5 1, 8.538 1.592, 8.579 2.136, 8.626 2.584, 8.682 2.888, 8.75 3, 8.818 2.888, 8.874 2.584, 8.921 2.136, 8.962 1.592, 9 1, 9.038 0.408, 9.079 -0.136, 9.126 -0.584, 9.182 -0.888, 9.25 -1, 9.318 -0.888, 9.374 -0.584, 9.421 -0.136, 9.462 0.408, 9.5 1, 9.538 1.592, 9.579 2.136, 9.626 2.584, 9.682 2.888, 9.75 3, 9.824 2.888, 9.892 2.584, 9.948 2.136, 9.986 1.592, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)").roundWaves(5, 2).asWkt(3), + "LineString (1 1, 1.092 0.701, 1.198 0.408, 1.314 0.127, 1.437 -0.136, 1.563 -0.375, 1.689 -0.584, 1.811 -0.757, 1.927 -0.888, 2.033 -0.971, 2.125 -1, 2.431 -0.888, 2.683 -0.584, 2.895 -0.136, 3.079 0.408, 3.25 1, 3.421 1.592, 3.606 2.136, 3.817 2.584, 4.069 2.888, 4.375 3, 4.681 2.888, 4.933 2.584, 5.145 2.136, 5.329 1.592, 5.5 1, 5.671 0.408, 5.856 -0.136, 6.067 -0.584, 6.319 -0.888, 6.625 -1, 6.931 -0.888, 7.183 -0.584, 7.395 -0.136, 7.579 0.408, 7.75 1, 7.921 1.592, 8.106 2.136, 8.317 2.584, 8.569 2.888, 8.875 3, 9.208 2.888, 9.514 2.584, 9.766 2.136, 9.937 1.592, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)").roundWaves(8, 2).asWkt(3), + "LineString (1 1, 1.092 0.701, 1.198 0.408, 1.314 0.127, 1.437 -0.136, 1.563 -0.375, 1.689 -0.584, 1.811 -0.757, 1.927 -0.888, 2.033 -0.971, 2.125 -1, 2.431 -0.888, 2.683 -0.584, 2.895 -0.136, 3.079 0.408, 3.25 1, 3.421 1.592, 3.606 2.136, 3.817 2.584, 4.069 2.888, 4.375 3, 4.681 2.888, 4.933 2.584, 5.145 2.136, 5.329 1.592, 5.5 1, 5.671 0.408, 5.856 -0.136, 6.067 -0.584, 6.319 -0.888, 6.625 -1, 6.931 -0.888, 7.183 -0.584, 7.395 -0.136, 7.579 0.408, 7.75 1, 7.921 1.592, 8.106 2.136, 8.317 2.584, 8.569 2.888, 8.875 3, 9.208 2.888, 9.514 2.584, 9.766 2.136, 9.937 1.592, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .roundWaves(8, 2, True) + .asWkt(3), + "LineString (1 1, 1.164 0.701, 1.352 0.408, 1.558 0.127, 1.776 -0.136, 2 -0.375, 2.224 -0.584, 2.442 -0.757, 2.648 -0.888, 2.836 -0.971, 3 -1, 3.544 -0.888, 3.992 -0.584, 4.368 -0.136, 4.696 0.408, 5 1, 5.304 1.592, 5.632 2.136, 6.008 2.584, 6.456 2.888, 7 3, 7.768 2.888, 8.524 2.584, 9.196 2.136, 9.712 1.592, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)").roundWaves(10, 2).asWkt(3), + "LineString (1 1, 1.185 0.701, 1.396 0.408, 1.628 0.127, 1.873 -0.136, 2.125 -0.375, 2.377 -0.584, 2.622 -0.757, 2.854 -0.888, 3.066 -0.971, 3.25 -1, 3.862 -0.888, 4.366 -0.584, 4.789 -0.136, 5.158 0.408, 5.5 1, 5.842 1.592, 6.211 2.136, 6.634 2.584, 7.138 2.888, 7.75 3, 8.416 2.888, 9.028 2.584, 9.532 2.136, 9.874 1.592, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)").roundWaves(20, 2).asWkt(3), + "LineString (1 1, 1.185 0.701, 1.396 0.408, 1.628 0.127, 1.873 -0.136, 2.125 -0.375, 2.377 -0.584, 2.622 -0.757, 2.854 -0.888, 3.066 -0.971, 3.25 -1, 3.862 -0.888, 4.366 -0.584, 4.789 -0.136, 5.158 0.408, 5.5 1, 5.842 1.592, 6.211 2.136, 6.634 2.584, 7.138 2.888, 7.75 3, 8.416 2.888, 9.028 2.584, 9.532 2.136, 9.874 1.592, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1, 10 10)") + .roundWaves(5, 2) + .asWkt(3), + "LineString (1 1, 1.092 0.701, 1.198 0.408, 1.314 0.127, 1.437 -0.136, 1.563 -0.375, 1.689 -0.584, 1.811 -0.757, 1.927 -0.888, 2.033 -0.971, 2.125 -1, 2.431 -0.888, 2.683 -0.584, 2.895 -0.136, 3.079 0.408, 3.25 1, 3.421 1.592, 3.606 2.136, 3.817 2.584, 4.069 2.888, 4.375 3, 4.681 2.888, 4.933 2.584, 5.145 2.136, 5.329 1.592, 5.5 1, 5.671 0.408, 5.856 -0.136, 6.067 -0.584, 6.319 -0.888, 6.625 -1, 6.931 -0.888, 7.183 -0.584, 7.395 -0.136, 7.579 0.408, 7.75 1, 7.921 1.592, 8.106 2.136, 8.317 2.584, 8.569 2.888, 8.875 3, 9.182 2.891, 9.44 2.609, 9.668 2.22, 9.885 1.792, 10.109 1.391, 10.36 1.083, 10.656 0.936, 11.015 1.016, 11.457 1.39, 12 2.125, 11.888 2.431, 11.584 2.683, 11.136 2.895, 10.592 3.079, 10 3.25, 9.408 3.421, 8.864 3.606, 8.416 3.817, 8.112 4.069, 8 4.375, 8.112 4.681, 8.416 4.933, 8.864 5.145, 9.408 5.329, 10 5.5, 10.592 5.671, 11.136 5.856, 11.584 6.067, 11.888 6.319, 12 6.625, 11.888 6.931, 11.584 7.183, 11.136 7.395, 10.592 7.579, 10 7.75, 9.408 7.921, 8.864 8.106, 8.416 8.317, 8.112 8.569, 8 8.875, 8.112 9.208, 8.416 9.514, 8.864 9.766, 9.408 9.937, 10 10)", + ) + self.assertEqual( + QgsGeometry.fromWkt("MultiLineString ((1 1, 10 1),(10 10, 0 10))") + .roundWaves(5, 2) + .asWkt(3), + "MultiLineString ((1 1, 1.092 0.701, 1.198 0.408, 1.314 0.127, 1.437 -0.136, 1.563 -0.375, 1.689 -0.584, 1.811 -0.757, 1.927 -0.888, 2.033 -0.971, 2.125 -1, 2.431 -0.888, 2.683 -0.584, 2.895 -0.136, 3.079 0.408, 3.25 1, 3.421 1.592, 3.606 2.136, 3.817 2.584, 4.069 2.888, 4.375 3, 4.681 2.888, 4.933 2.584, 5.145 2.136, 5.329 1.592, 5.5 1, 5.671 0.408, 5.856 -0.136, 6.067 -0.584, 6.319 -0.888, 6.625 -1, 6.931 -0.888, 7.183 -0.584, 7.395 -0.136, 7.579 0.408, 7.75 1, 7.921 1.592, 8.106 2.136, 8.317 2.584, 8.569 2.888, 8.875 3, 9.208 2.888, 9.514 2.584, 9.766 2.136, 9.937 1.592, 10 1),(10 10, 9.897 10.299, 9.78 10.592, 9.651 10.873, 9.515 11.136, 9.375 11.375, 9.235 11.584, 9.099 11.757, 8.97 11.888, 8.853 11.971, 8.75 12, 8.41 11.888, 8.13 11.584, 7.895 11.136, 7.69 10.592, 7.5 10, 7.31 9.408, 7.105 8.864, 6.87 8.416, 6.59 8.112, 6.25 8, 5.91 8.112, 5.63 8.416, 5.395 8.864, 5.19 9.408, 5 10, 4.81 10.592, 4.605 11.136, 4.37 11.584, 4.09 11.888, 3.75 12, 3.41 11.888, 3.13 11.584, 2.895 11.136, 2.69 10.592, 2.5 10, 2.31 9.408, 2.105 8.864, 1.87 8.416, 1.59 8.112, 1.25 8, 0.88 8.112, 0.54 8.416, 0.26 8.864, 0.07 9.408, 0 10))", + ) + self.assertEqual( + QgsGeometry.fromWkt( + "Polygon ((1 1, 10 1, 10 10, 1 10, 1 1),(3 4, 8 4, 7 7, 4 6, 3 4))" + ) + .roundWaves(5, 0.2) + .asWkt(3), + "Polygon ((1 1, 1.092 0.97, 1.198 0.941, 1.314 0.913, 1.437 0.886, 1.563 0.863, 1.689 0.842, 1.811 0.824, 1.927 0.811, 2.033 0.803, 2.125 0.8, 2.431 0.811, 2.683 0.842, 2.895 0.886, 3.079 0.941, 3.25 1, 3.421 1.059, 3.606 1.114, 3.817 1.158, 4.069 1.189, 4.375 1.2, 4.681 1.189, 4.933 1.158, 5.145 1.114, 5.329 1.059, 5.5 1, 5.671 0.941, 5.856 0.886, 6.067 0.842, 6.319 0.811, 6.625 0.8, 6.931 0.811, 7.183 0.842, 7.395 0.886, 7.579 0.941, 7.75 1, 7.921 1.059, 8.106 1.114, 8.317 1.158, 8.569 1.189, 8.875 1.2, 9.18 1.19, 9.426 1.169, 9.62 1.149, 9.77 1.144, 9.884 1.166, 9.971 1.227, 10.038 1.341, 10.093 1.52, 10.145 1.777, 10.2 2.125, 10.189 2.431, 10.158 2.683, 10.114 2.895, 10.059 3.079, 10 3.25, 9.941 3.421, 9.886 3.606, 9.842 3.817, 9.811 4.069, 9.8 4.375, 9.811 4.681, 9.842 4.933, 9.886 5.145, 9.941 5.329, 10 5.5, 10.059 5.671, 10.114 5.856, 10.158 6.067, 10.189 6.319, 10.2 6.625, 10.189 6.931, 10.158 7.183, 10.114 7.395, 10.059 7.579, 10 7.75, 9.941 7.921, 9.886 8.106, 9.842 8.317, 9.811 8.569, 9.8 8.875, 9.81 9.18, 9.831 9.426, 9.851 9.62, 9.856 9.77, 9.834 9.884, 9.773 9.971, 9.659 10.038, 9.48 10.093, 9.223 10.145, 8.875 10.2, 8.569 10.189, 8.317 10.158, 8.106 10.114, 7.921 10.059, 7.75 10, 7.579 9.941, 7.395 9.886, 7.183 9.842, 6.931 9.811, 6.625 9.8, 6.319 9.811, 6.067 9.842, 5.856 9.886, 5.671 9.941, 5.5 10, 5.329 10.059, 5.145 10.114, 4.933 10.158, 4.681 10.189, 4.375 10.2, 4.069 10.189, 3.817 10.158, 3.606 10.114, 3.421 10.059, 3.25 10, 3.079 9.941, 2.895 9.886, 2.683 9.842, 2.431 9.811, 2.125 9.8, 1.82 9.81, 1.574 9.831, 1.38 9.851, 1.23 9.856, 1.116 9.834, 1.029 9.773, 0.962 9.659, 0.907 9.48, 0.855 9.223, 0.8 8.875, 0.811 8.569, 0.842 8.317, 0.886 8.106, 0.941 7.921, 1 7.75, 1.059 7.579, 1.114 7.395, 1.158 7.183, 1.189 6.931, 1.2 6.625, 1.189 6.319, 1.158 6.067, 1.114 5.856, 1.059 5.671, 1 5.5, 0.941 5.329, 0.886 5.145, 0.842 4.933, 0.811 4.681, 0.8 4.375, 0.811 4.069, 0.842 3.817, 0.886 3.606, 0.941 3.421, 1 3.25, 1.059 3.079, 1.114 2.895, 1.158 2.683, 1.189 2.431, 1.2 2.125, 1.189 1.792, 1.158 1.486, 1.114 1.234, 1.059 1.063, 1 1),(3 4, 3.093 3.97, 3.199 3.941, 3.315 3.913, 3.438 3.886, 3.565 3.863, 3.692 3.842, 3.815 3.824, 3.931 3.811, 4.037 3.803, 4.13 3.8, 4.437 3.811, 4.691 3.842, 4.903 3.886, 5.088 3.941, 5.26 4, 5.432 4.059, 5.617 4.114, 5.83 4.158, 6.083 4.189, 6.39 4.2, 6.697 4.19, 6.945 4.165, 7.145 4.137, 7.306 4.116, 7.437 4.11, 7.548 4.131, 7.649 4.188, 7.749 4.292, 7.857 4.453, 7.984 4.68, 7.876 4.968, 7.767 5.199, 7.658 5.386, 7.547 5.545, 7.437 5.689, 7.327 5.833, 7.216 5.992, 7.107 6.179, 6.998 6.41, 6.89 6.698, 6.707 6.663, 6.546 6.654, 6.4 6.662, 6.26 6.679, 6.115 6.698, 5.959 6.712, 5.781 6.712, 5.573 6.691, 5.326 6.641, 5.032 6.555, 4.744 6.446, 4.518 6.334, 4.344 6.214, 4.21 6.084, 4.107 5.94, 4.023 5.781, 3.95 5.602, 3.876 5.401, 3.791 5.175, 3.684 4.921, 3.585 4.748, 3.451 4.548, 3.298 4.341, 3.142 4.151, 3 4))", + ) + self.assertEqual( + QgsGeometry.fromWkt( + "MultiPolygon (((1 1, 10 1, 10 10, 1 10, 1 1)),((20 20, 20 30, 30 20, 20 20)))" + ) + .roundWaves(5, 0.2) + .asWkt(3), + "MultiPolygon (((1 1, 1.092 0.97, 1.198 0.941, 1.314 0.913, 1.437 0.886, 1.563 0.863, 1.689 0.842, 1.811 0.824, 1.927 0.811, 2.033 0.803, 2.125 0.8, 2.431 0.811, 2.683 0.842, 2.895 0.886, 3.079 0.941, 3.25 1, 3.421 1.059, 3.606 1.114, 3.817 1.158, 4.069 1.189, 4.375 1.2, 4.681 1.189, 4.933 1.158, 5.145 1.114, 5.329 1.059, 5.5 1, 5.671 0.941, 5.856 0.886, 6.067 0.842, 6.319 0.811, 6.625 0.8, 6.931 0.811, 7.183 0.842, 7.395 0.886, 7.579 0.941, 7.75 1, 7.921 1.059, 8.106 1.114, 8.317 1.158, 8.569 1.189, 8.875 1.2, 9.18 1.19, 9.426 1.169, 9.62 1.149, 9.77 1.144, 9.884 1.166, 9.971 1.227, 10.038 1.341, 10.093 1.52, 10.145 1.777, 10.2 2.125, 10.189 2.431, 10.158 2.683, 10.114 2.895, 10.059 3.079, 10 3.25, 9.941 3.421, 9.886 3.606, 9.842 3.817, 9.811 4.069, 9.8 4.375, 9.811 4.681, 9.842 4.933, 9.886 5.145, 9.941 5.329, 10 5.5, 10.059 5.671, 10.114 5.856, 10.158 6.067, 10.189 6.319, 10.2 6.625, 10.189 6.931, 10.158 7.183, 10.114 7.395, 10.059 7.579, 10 7.75, 9.941 7.921, 9.886 8.106, 9.842 8.317, 9.811 8.569, 9.8 8.875, 9.81 9.18, 9.831 9.426, 9.851 9.62, 9.856 9.77, 9.834 9.884, 9.773 9.971, 9.659 10.038, 9.48 10.093, 9.223 10.145, 8.875 10.2, 8.569 10.189, 8.317 10.158, 8.106 10.114, 7.921 10.059, 7.75 10, 7.579 9.941, 7.395 9.886, 7.183 9.842, 6.931 9.811, 6.625 9.8, 6.319 9.811, 6.067 9.842, 5.856 9.886, 5.671 9.941, 5.5 10, 5.329 10.059, 5.145 10.114, 4.933 10.158, 4.681 10.189, 4.375 10.2, 4.069 10.189, 3.817 10.158, 3.606 10.114, 3.421 10.059, 3.25 10, 3.079 9.941, 2.895 9.886, 2.683 9.842, 2.431 9.811, 2.125 9.8, 1.82 9.81, 1.574 9.831, 1.38 9.851, 1.23 9.856, 1.116 9.834, 1.029 9.773, 0.962 9.659, 0.907 9.48, 0.855 9.223, 0.8 8.875, 0.811 8.569, 0.842 8.317, 0.886 8.106, 0.941 7.921, 1 7.75, 1.059 7.579, 1.114 7.395, 1.158 7.183, 1.189 6.931, 1.2 6.625, 1.189 6.319, 1.158 6.067, 1.114 5.856, 1.059 5.671, 1 5.5, 0.941 5.329, 0.886 5.145, 0.842 4.933, 0.811 4.681, 0.8 4.375, 0.811 4.069, 0.842 3.817, 0.886 3.606, 0.941 3.421, 1 3.25, 1.059 3.079, 1.114 2.895, 1.158 2.683, 1.189 2.431, 1.2 2.125, 1.189 1.792, 1.158 1.486, 1.114 1.234, 1.059 1.063, 1 1)),((20 20, 20.03 20.1, 20.059 20.215, 20.087 20.34, 20.114 20.473, 20.138 20.61, 20.158 20.746, 20.176 20.879, 20.189 21.005, 20.197 21.119, 20.2 21.219, 20.189 21.551, 20.158 21.824, 20.114 22.053, 20.059 22.253, 20 22.439, 19.941 22.624, 19.886 22.824, 19.842 23.053, 19.811 23.326, 19.8 23.658, 19.811 23.99, 19.842 24.263, 19.886 24.492, 19.941 24.692, 20 24.877, 20.059 25.063, 20.114 25.263, 20.158 25.492, 20.189 25.765, 20.2 26.097, 20.189 26.428, 20.158 26.702, 20.114 26.931, 20.059 27.131, 20 27.316, 19.941 27.502, 19.886 27.701, 19.842 27.931, 19.811 28.204, 19.8 28.536, 19.812 28.865, 19.844 29.126, 19.896 29.321, 19.963 29.454, 20.043 29.529, 20.134 29.55, 20.233 29.521, 20.336 29.446, 20.442 29.327, 20.547 29.17, 20.79 28.943, 21.005 28.771, 21.198 28.641, 21.378 28.538, 21.551 28.449, 21.724 28.36, 21.904 28.257, 22.098 28.126, 22.312 27.955, 22.555 27.728, 22.781 27.486, 22.953 27.271, 23.083 27.077, 23.186 26.897, 23.276 26.724, 23.365 26.552, 23.468 26.372, 23.598 26.178, 23.77 25.963, 23.996 25.721, 24.239 25.494, 24.453 25.323, 24.647 25.192, 24.827 25.089, 25 25, 25.173 24.911, 25.353 24.808, 25.547 24.677, 25.761 24.506, 26.004 24.279, 26.23 24.037, 26.402 23.822, 26.532 23.628, 26.635 23.448, 26.724 23.276, 26.814 23.103, 26.917 22.923, 27.047 22.729, 27.219 22.514, 27.445 22.272, 27.688 22.045, 27.902 21.874, 28.096 21.743, 28.276 21.64, 28.449 21.551, 28.622 21.462, 28.802 21.359, 28.995 21.229, 29.21 21.057, 29.453 20.83, 29.533 20.562, 29.59 20.369, 29.618 20.24, 29.612 20.163, 29.565 20.129, 29.472 20.125, 29.328 20.141, 29.128 20.167, 28.866 20.19, 28.536 20.2, 28.204 20.189, 27.931 20.158, 27.701 20.114, 27.502 20.059, 27.316 20, 27.131 19.941, 26.931 19.886, 26.702 19.842, 26.428 19.811, 26.097 19.8, 25.765 19.811, 25.492 19.842, 25.263 19.886, 25.063 19.941, 24.877 20, 24.692 20.059, 24.492 20.114, 24.263 20.158, 23.99 20.189, 23.658 20.2, 23.326 20.189, 23.053 20.158, 22.824 20.114, 22.624 20.059, 22.439 20, 22.253 19.941, 22.053 19.886, 21.824 19.842, 21.551 19.811, 21.219 19.8, 21.005 19.811, 20.746 19.842, 20.473 19.886, 20.215 19.941, 20 20)))", + ) def testRoundRandomizedWaves(self): """Test randomized round waves""" - self.assertEqual(QgsGeometry.fromWkt('Point (1 1)').roundWavesRandomized(1, 2, 2, 3, 1).asWkt(3), 'Point (1 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1)').roundWavesRandomized(1, 2, 2, 3, 1).asWkt(3), - '') # just don't crash! + self.assertEqual( + QgsGeometry.fromWkt("Point (1 1)") + .roundWavesRandomized(1, 2, 2, 3, 1) + .asWkt(3), + "Point (1 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1)") + .roundWavesRandomized(1, 2, 2, 3, 1) + .asWkt(3), + "", + ) # just don't crash! # very short line compared to minimum wavelength - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 2 1)').roundWavesRandomized(5, 6, 3, 5, 1).asWkt(3), - 'LineString (1 1, 1.132 1.674, 1.265 2.199, 1.396 2.573, 1.521 2.798, 1.639 2.873, 1.745 2.798, 1.838 2.573, 1.913 2.199, 1.968 1.674, 2 1)') - - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').roundWavesRandomized(1, 2, 2, 3, 1).asWkt(3), - 'LineString (1 1, 1.04 0.552, 1.085 0.113, 1.135 -0.308, 1.187 -0.702, 1.242 -1.061, 1.296 -1.374, 1.348 -1.633, 1.398 -1.829, 1.444 -1.954, 1.483 -1.997, 1.56 -1.829, 1.623 -1.374, 1.676 -0.702, 1.722 0.113, 1.765 1.001, 1.808 1.888, 1.854 2.704, 1.907 3.375, 1.97 3.831, 2.047 3.999, 2.131 3.848, 2.2 3.438, 2.259 2.834, 2.309 2.1, 2.356 1.301, 2.403 0.503, 2.454 -0.231, 2.512 -0.835, 2.581 -1.246, 2.665 -1.397, 2.76 -1.255, 2.837 -0.87, 2.903 -0.302, 2.959 0.387, 3.012 1.137, 3.065 1.886, 3.122 2.575, 3.187 3.143, 3.265 3.528, 3.359 3.67, 3.491 3.515, 3.599 3.096, 3.69 2.478, 3.77 1.728, 3.843 0.912, 3.917 0.095, 3.996 -0.655, 4.087 -1.273, 4.195 -1.692, 4.327 -1.846, 4.416 -1.696, 4.49 -1.288, 4.552 -0.686, 4.605 0.044, 4.655 0.839, 4.705 1.634, 4.759 2.364, 4.821 2.966, 4.894 3.374, 4.984 3.525, 5.082 3.391, 5.163 3.03, 5.23 2.498, 5.29 1.851, 5.344 1.147, 5.399 0.444, 5.459 -0.203, 5.526 -0.735, 5.607 -1.096, 5.705 -1.23, 5.81 -1.086, 5.896 -0.695, 5.968 -0.119, 6.031 0.581, 6.089 1.342, 6.147 2.103, 6.21 2.803, 6.282 3.379, 6.368 3.77, 6.473 3.914, 6.572 3.764, 6.653 3.358, 6.722 2.76, 6.781 2.033, 6.837 1.242, 6.892 0.451, 6.952 -0.276, 7.02 -0.875, 7.102 -1.281, 7.201 -1.431, 7.333 -1.285, 7.442 -0.889, 7.533 -0.306, 7.612 0.403, 7.686 1.174, 7.76 1.945, 7.839 2.653, 7.93 3.237, 8.039 3.633, 8.171 3.778, 8.287 3.622, 8.383 3.198, 8.464 2.573, 8.534 1.814, 8.6 0.988, 8.665 0.162, 8.735 -0.597, 8.816 -1.222, 8.912 -1.646, 9.029 -1.803, 9.103 -1.654, 9.164 -1.249, 9.216 -0.653, 9.26 0.07, 9.302 0.858, 9.343 1.645, 9.388 2.369, 9.44 2.965, 9.501 3.369, 9.575 3.518, 9.61 3.482, 9.65 3.377, 9.694 3.212, 9.74 2.994, 9.788 2.731, 9.835 2.43, 9.881 2.099, 9.925 1.745, 9.965 1.376, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').roundWavesRandomized(5, 6, 2, 3, 1).asWkt(3), - 'LineString (1 1, 1.122 0.552, 1.261 0.113, 1.414 -0.308, 1.575 -0.702, 1.742 -1.061, 1.908 -1.374, 2.069 -1.633, 2.222 -1.829, 2.362 -1.954, 2.483 -1.997, 2.832 -1.829, 3.119 -1.374, 3.36 -0.702, 3.57 0.113, 3.765 1.001, 3.96 1.888, 4.17 2.704, 4.411 3.375, 4.698 3.831, 5.047 3.999, 5.403 3.848, 5.696 3.438, 5.943 2.834, 6.157 2.1, 6.356 1.301, 6.555 0.503, 6.77 -0.231, 7.016 -0.835, 7.309 -1.246, 7.665 -1.397, 7.948 -1.399, 8.238 -1.328, 8.529 -1.191, 8.814 -0.996, 9.085 -0.75, 9.337 -0.46, 9.561 -0.132, 9.751 0.225, 9.899 0.605, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').roundWavesRandomized(8, 9, 2, 3, 1).asWkt(3), - 'LineString (1 1, 1.183 0.552, 1.393 0.113, 1.623 -0.308, 1.866 -0.702, 2.117 -1.061, 2.367 -1.374, 2.61 -1.633, 2.84 -1.829, 3.05 -1.954, 3.233 -1.997, 3.786 -1.829, 4.241 -1.374, 4.623 -0.702, 4.956 0.113, 5.265 1.001, 5.574 1.888, 5.907 2.704, 6.289 3.375, 6.744 3.831, 7.297 3.999, 7.658 3.874, 8.02 3.687, 8.376 3.445, 8.717 3.158, 9.035 2.836, 9.322 2.487, 9.57 2.119, 9.771 1.743, 9.917 1.367, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').roundWavesRandomized(10, 12, 1, 2, 1).asWkt(3), - 'LineString (1 1, 1.243 0.701, 1.522 0.409, 1.828 0.128, 2.151 -0.134, 2.483 -0.373, 2.815 -0.582, 3.139 -0.755, 3.444 -0.885, 3.723 -0.968, 3.966 -0.997, 4.664 -0.885, 5.238 -0.582, 5.72 -0.134, 6.141 0.409, 6.53 1.001, 6.92 1.592, 7.341 2.136, 7.823 2.583, 8.397 2.887, 9.094 2.999, 9.169 2.97, 9.254 2.887, 9.347 2.756, 9.446 2.583, 9.547 2.374, 9.649 2.135, 9.747 1.873, 9.841 1.592, 9.926 1.299, 10 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').roundWavesRandomized(20, 25, 2, 3, 1).asWkt(3), - 'LineString (1 1, 1.506 0.552, 2.085 0.113, 2.72 -0.308, 3.392 -0.702, 4.083 -1.061, 4.773 -1.374, 5.445 -1.633, 6.081 -1.829, 6.66 -1.954, 7.166 -1.997, 7.398 -1.954, 7.665 -1.829, 7.956 -1.633, 8.265 -1.374, 8.583 -1.061, 8.9 -0.702, 9.209 -0.308, 9.501 0.113, 9.768 0.552, 10 1)') - self.assertEqual( - QgsGeometry.fromWkt('LineString (1 1, 10 1, 10 10)').roundWavesRandomized(5, 6, 2, 3, 1).asWkt(3), - 'LineString (1 1, 1.122 0.552, 1.261 0.113, 1.414 -0.308, 1.575 -0.702, 1.742 -1.061, 1.908 -1.374, 2.069 -1.633, 2.222 -1.829, 2.362 -1.954, 2.483 -1.997, 2.832 -1.829, 3.119 -1.374, 3.36 -0.702, 3.57 0.113, 3.765 1.001, 3.96 1.888, 4.17 2.704, 4.411 3.375, 4.698 3.831, 5.047 3.999, 5.403 3.848, 5.696 3.438, 5.943 2.834, 6.157 2.1, 6.356 1.301, 6.555 0.503, 6.77 -0.231, 7.016 -0.835, 7.309 -1.246, 7.665 -1.397, 8.029 -1.257, 8.309 -0.888, 8.505 -0.365, 8.614 0.239, 8.634 0.848, 8.563 1.387, 8.399 1.783, 8.14 1.96, 7.785 1.844, 7.33 1.359, 7.485 1.763, 7.904 2.095, 8.522 2.374, 9.272 2.618, 10.088 2.843, 10.905 3.069, 11.655 3.312, 12.273 3.591, 12.692 3.923, 12.846 4.327, 12.696 4.688, 12.288 4.986, 11.686 5.236, 10.956 5.453, 10.161 5.655, 9.366 5.857, 8.636 6.075, 8.034 6.325, 7.626 6.622, 7.475 6.984, 7.609 7.354, 7.97 7.659, 8.502 7.914, 9.149 8.138, 9.853 8.344, 10.556 8.551, 11.203 8.775, 11.735 9.03, 12.096 9.335, 12.23 9.705, 12.197 9.729, 12.105 9.757, 11.959 9.788, 11.766 9.82, 11.533 9.853, 11.266 9.886, 10.973 9.918, 10.66 9.948, 10.333 9.976, 10 10)') - self.assertEqual( - QgsGeometry.fromWkt('MultiLineString ((1 1, 10 1),(10 10, 0 10))').roundWavesRandomized(5, 6, 2, 3, - 1).asWkt(3), - 'MultiLineString ((1 1, 1.122 0.552, 1.261 0.113, 1.414 -0.308, 1.575 -0.702, 1.742 -1.061, 1.908 -1.374, 2.069 -1.633, 2.222 -1.829, 2.362 -1.954, 2.483 -1.997, 2.832 -1.829, 3.119 -1.374, 3.36 -0.702, 3.57 0.113, 3.765 1.001, 3.96 1.888, 4.17 2.704, 4.411 3.375, 4.698 3.831, 5.047 3.999, 5.403 3.848, 5.696 3.438, 5.943 2.834, 6.157 2.1, 6.356 1.301, 6.555 0.503, 6.77 -0.231, 7.016 -0.835, 7.309 -1.246, 7.665 -1.397, 7.948 -1.399, 8.238 -1.328, 8.529 -1.191, 8.814 -0.996, 9.085 -0.75, 9.337 -0.46, 9.561 -0.132, 9.751 0.225, 9.899 0.605, 10 1),(10 10, 9.88 10.439, 9.743 10.869, 9.592 11.281, 9.433 11.667, 9.269 12.018, 9.106 12.325, 8.946 12.579, 8.796 12.771, 8.658 12.893, 8.538 12.936, 8.177 12.783, 7.88 12.368, 7.63 11.756, 7.412 11.014, 7.21 10.205, 7.008 9.397, 6.79 8.655, 6.541 8.043, 6.243 7.628, 5.882 7.475, 5.512 7.609, 5.207 7.97, 4.951 8.502, 4.728 9.149, 4.521 9.853, 4.314 10.556, 4.091 11.203, 3.835 11.735, 3.53 12.096, 3.16 12.23, 2.784 12.086, 2.474 11.695, 2.214 11.119, 1.987 10.419, 1.776 9.658, 1.566 8.897, 1.339 8.197, 1.079 7.621, 0.769 7.23, 0.393 7.086, 0.361 7.128, 0.324 7.249, 0.283 7.44, 0.24 7.692, 0.196 7.997, 0.152 8.345, 0.11 8.728, 0.069 9.137, 0.032 9.564, 0 10))') - self.assertEqual(QgsGeometry.fromWkt( - 'Polygon ((1 1, 10 1, 10 10, 1 10, 1 1),(3 4, 8 4, 7 7, 4 6, 3 4))').roundWavesRandomized(5, 6, 0.2, 0.3, - 1).asWkt(3), - 'Polygon ((1 1, 1.122 0.955, 1.261 0.911, 1.414 0.869, 1.575 0.83, 1.742 0.794, 1.908 0.763, 2.069 0.737, 2.222 0.717, 2.362 0.705, 2.483 0.7, 2.832 0.717, 3.119 0.763, 3.36 0.83, 3.57 0.911, 3.765 1, 3.96 1.089, 4.17 1.17, 4.411 1.238, 4.698 1.283, 5.047 1.3, 5.403 1.285, 5.696 1.244, 5.943 1.183, 6.157 1.11, 6.356 1.03, 6.555 0.95, 6.77 0.877, 7.016 0.816, 7.309 0.775, 7.665 0.76, 8.031 0.775, 8.328 0.814, 8.57 0.872, 8.767 0.945, 8.934 1.025, 9.082 1.109, 9.223 1.189, 9.37 1.262, 9.536 1.32, 9.733 1.359, 9.748 1.763, 9.79 2.095, 9.852 2.374, 9.927 2.618, 10.009 2.843, 10.09 3.069, 10.165 3.312, 10.227 3.591, 10.269 3.923, 10.285 4.327, 10.27 4.688, 10.229 4.986, 10.169 5.236, 10.096 5.453, 10.016 5.655, 9.937 5.857, 9.864 6.075, 9.803 6.325, 9.763 6.622, 9.748 6.984, 9.761 7.354, 9.797 7.659, 9.85 7.914, 9.915 8.138, 9.985 8.344, 10.056 8.551, 10.12 8.775, 10.174 9.03, 10.21 9.335, 10.223 9.705, 9.866 9.831, 9.572 9.904, 9.324 9.934, 9.106 9.93, 8.902 9.901, 8.696 9.857, 8.472 9.806, 8.213 9.758, 7.904 9.722, 7.527 9.709, 7.156 9.724, 6.851 9.764, 6.594 9.824, 6.371 9.897, 6.163 9.976, 5.956 10.055, 5.732 10.128, 5.476 10.187, 5.17 10.228, 4.799 10.243, 4.395 10.228, 4.062 10.189, 3.783 10.131, 3.54 10.06, 3.314 9.983, 3.088 9.906, 2.845 9.835, 2.566 9.776, 2.233 9.737, 1.829 9.722, 1.664 9.634, 1.502 9.554, 1.346 9.472, 1.2 9.378, 1.068 9.262, 0.951 9.112, 0.855 8.919, 0.782 8.671, 0.736 8.359, 0.72 7.971, 0.735 7.625, 0.775 7.34, 0.835 7.1, 0.907 6.892, 0.986 6.698, 1.065 6.505, 1.137 6.296, 1.196 6.056, 1.237 5.771, 1.252 5.425, 1.237 5.026, 1.196 4.698, 1.136 4.422, 1.064 4.182, 0.984 3.959, 0.905 3.736, 0.833 3.495, 0.773 3.22, 0.732 2.891, 0.717 2.492, 0.729 2.272, 0.746 2.055, 0.769 1.846, 0.796 1.651, 0.826 1.473, 0.859 1.317, 0.894 1.187, 0.93 1.088, 0.965 1.024, 1 1),(3 4, 3.116 3.969, 3.25 3.939, 3.396 3.91, 3.55 3.883, 3.709 3.858, 3.868 3.837, 4.022 3.819, 4.168 3.806, 4.301 3.797, 4.418 3.794, 4.798 3.807, 5.111 3.843, 5.374 3.896, 5.603 3.961, 5.816 4.031, 6.028 4.101, 6.258 4.165, 6.521 4.218, 6.834 4.254, 7.214 4.267, 7.322 4.323, 7.431 4.384, 7.534 4.458, 7.626 4.55, 7.701 4.668, 7.752 4.819, 7.773 5.009, 7.759 5.247, 7.704 5.539, 7.601 5.891, 7.401 6.229, 7.241 6.475, 7.106 6.64, 6.984 6.732, 6.86 6.763, 6.72 6.743, 6.552 6.682, 6.341 6.59, 6.074 6.477, 5.737 6.353, 5.36 6.24, 5.045 6.165, 4.779 6.113, 4.551 6.068, 4.347 6.015, 4.156 5.939, 3.966 5.824, 3.764 5.656, 3.539 5.418, 3.278 5.095, 3.241 5.013, 3.203 4.916, 3.166 4.807, 3.131 4.69, 3.099 4.568, 3.069 4.444, 3.044 4.323, 3.023 4.206, 3.008 4.097, 3 4))') - self.assertEqual(QgsGeometry.fromWkt( - 'MultiPolygon (((1 1, 10 1, 10 10, 1 10, 1 1)),((20 20, 20 30, 30 20, 20 20)))').roundWavesRandomized(5, 6, - 0.2, - 0.3, - 1).asWkt( - 3), - 'MultiPolygon (((1 1, 1.122 0.955, 1.261 0.911, 1.414 0.869, 1.575 0.83, 1.742 0.794, 1.908 0.763, 2.069 0.737, 2.222 0.717, 2.362 0.705, 2.483 0.7, 2.832 0.717, 3.119 0.763, 3.36 0.83, 3.57 0.911, 3.765 1, 3.96 1.089, 4.17 1.17, 4.411 1.238, 4.698 1.283, 5.047 1.3, 5.403 1.285, 5.696 1.244, 5.943 1.183, 6.157 1.11, 6.356 1.03, 6.555 0.95, 6.77 0.877, 7.016 0.816, 7.309 0.775, 7.665 0.76, 8.031 0.775, 8.328 0.814, 8.57 0.872, 8.767 0.945, 8.934 1.025, 9.082 1.109, 9.223 1.189, 9.37 1.262, 9.536 1.32, 9.733 1.359, 9.748 1.763, 9.79 2.095, 9.852 2.374, 9.927 2.618, 10.009 2.843, 10.09 3.069, 10.165 3.312, 10.227 3.591, 10.269 3.923, 10.285 4.327, 10.27 4.688, 10.229 4.986, 10.169 5.236, 10.096 5.453, 10.016 5.655, 9.937 5.857, 9.864 6.075, 9.803 6.325, 9.763 6.622, 9.748 6.984, 9.761 7.354, 9.797 7.659, 9.85 7.914, 9.915 8.138, 9.985 8.344, 10.056 8.551, 10.12 8.775, 10.174 9.03, 10.21 9.335, 10.223 9.705, 9.866 9.831, 9.572 9.904, 9.324 9.934, 9.106 9.93, 8.902 9.901, 8.696 9.857, 8.472 9.806, 8.213 9.758, 7.904 9.722, 7.527 9.709, 7.156 9.724, 6.851 9.764, 6.594 9.824, 6.371 9.897, 6.163 9.976, 5.956 10.055, 5.732 10.128, 5.476 10.187, 5.17 10.228, 4.799 10.243, 4.395 10.228, 4.062 10.189, 3.783 10.131, 3.54 10.06, 3.314 9.983, 3.088 9.906, 2.845 9.835, 2.566 9.776, 2.233 9.737, 1.829 9.722, 1.664 9.634, 1.502 9.554, 1.346 9.472, 1.2 9.378, 1.068 9.262, 0.951 9.112, 0.855 8.919, 0.782 8.671, 0.736 8.359, 0.72 7.971, 0.735 7.625, 0.775 7.34, 0.835 7.1, 0.907 6.892, 0.986 6.698, 1.065 6.505, 1.137 6.296, 1.196 6.056, 1.237 5.771, 1.252 5.425, 1.237 5.026, 1.196 4.698, 1.136 4.422, 1.064 4.182, 0.984 3.959, 0.905 3.736, 0.833 3.495, 0.773 3.22, 0.732 2.891, 0.717 2.492, 0.729 2.272, 0.746 2.055, 0.769 1.846, 0.796 1.651, 0.826 1.473, 0.859 1.317, 0.894 1.187, 0.93 1.088, 0.965 1.024, 1 1)),((20 20, 20.031 20.116, 20.061 20.25, 20.09 20.396, 20.117 20.55, 20.142 20.709, 20.163 20.868, 20.181 21.022, 20.194 21.168, 20.203 21.301, 20.206 21.418, 20.193 21.798, 20.157 22.111, 20.104 22.374, 20.039 22.603, 19.969 22.816, 19.899 23.028, 19.835 23.258, 19.782 23.521, 19.746 23.834, 19.733 24.214, 19.746 24.582, 19.783 24.885, 19.838 25.14, 19.904 25.361, 19.976 25.567, 20.048 25.773, 20.115 25.995, 20.169 26.249, 20.206 26.552, 20.22 26.92, 20.208 27.28, 20.175 27.576, 20.126 27.825, 20.067 28.041, 20.003 28.242, 19.939 28.443, 19.88 28.66, 19.831 28.909, 19.798 29.205, 19.786 29.565, 20.071 29.52, 20.288 29.461, 20.454 29.384, 20.585 29.286, 20.698 29.164, 20.809 29.015, 20.935 28.837, 21.092 28.626, 21.297 28.379, 21.566 28.092, 21.818 27.86, 22.045 27.688, 22.252 27.561, 22.446 27.463, 22.634 27.381, 22.822 27.298, 23.017 27.2, 23.224 27.073, 23.45 26.901, 23.702 26.669, 23.965 26.387, 24.163 26.136, 24.312 25.909, 24.428 25.698, 24.529 25.494, 24.63 25.29, 24.746 25.079, 24.896 24.852, 25.093 24.601, 25.356 24.319, 25.627 24.066, 25.866 23.875, 26.083 23.73, 26.285 23.615, 26.478 23.516, 26.672 23.417, 26.873 23.303, 27.09 23.158, 27.33 22.966, 27.601 22.713, 27.835 22.46, 28.011 22.234, 28.143 22.028, 28.245 21.836, 28.332 21.651, 28.419 21.465, 28.521 21.273, 28.652 21.067, 28.828 20.841, 29.063 20.588, 29.263 20.481, 29.415 20.366, 29.516 20.248, 29.563 20.131, 29.552 20.021, 29.482 19.921, 29.347 19.835, 29.146 19.768, 28.875 19.725, 28.53 19.71, 28.182 19.725, 27.896 19.766, 27.655 19.827, 27.445 19.901, 27.25 19.981, 27.056 20.061, 26.846 20.135, 26.605 20.196, 26.319 20.237, 25.971 20.252, 25.625 20.237, 25.34 20.196, 25.101 20.135, 24.893 20.061, 24.7 19.98, 24.507 19.9, 24.298 19.826, 24.059 19.765, 23.774 19.724, 23.429 19.708, 23.027 19.723, 22.696 19.763, 22.418 19.821, 22.176 19.892, 21.951 19.969, 21.727 20.046, 21.484 20.117, 21.206 20.176, 20.875 20.215, 20.474 20.23, 20.435 20.227, 20.39 20.217, 20.341 20.202, 20.29 20.182, 20.237 20.158, 20.184 20.131, 20.132 20.1, 20.083 20.068, 20.039 20.034, 20 20)))') + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 2 1)") + .roundWavesRandomized(5, 6, 3, 5, 1) + .asWkt(3), + "LineString (1 1, 1.132 1.674, 1.265 2.199, 1.396 2.573, 1.521 2.798, 1.639 2.873, 1.745 2.798, 1.838 2.573, 1.913 2.199, 1.968 1.674, 2 1)", + ) + + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .roundWavesRandomized(1, 2, 2, 3, 1) + .asWkt(3), + "LineString (1 1, 1.04 0.552, 1.085 0.113, 1.135 -0.308, 1.187 -0.702, 1.242 -1.061, 1.296 -1.374, 1.348 -1.633, 1.398 -1.829, 1.444 -1.954, 1.483 -1.997, 1.56 -1.829, 1.623 -1.374, 1.676 -0.702, 1.722 0.113, 1.765 1.001, 1.808 1.888, 1.854 2.704, 1.907 3.375, 1.97 3.831, 2.047 3.999, 2.131 3.848, 2.2 3.438, 2.259 2.834, 2.309 2.1, 2.356 1.301, 2.403 0.503, 2.454 -0.231, 2.512 -0.835, 2.581 -1.246, 2.665 -1.397, 2.76 -1.255, 2.837 -0.87, 2.903 -0.302, 2.959 0.387, 3.012 1.137, 3.065 1.886, 3.122 2.575, 3.187 3.143, 3.265 3.528, 3.359 3.67, 3.491 3.515, 3.599 3.096, 3.69 2.478, 3.77 1.728, 3.843 0.912, 3.917 0.095, 3.996 -0.655, 4.087 -1.273, 4.195 -1.692, 4.327 -1.846, 4.416 -1.696, 4.49 -1.288, 4.552 -0.686, 4.605 0.044, 4.655 0.839, 4.705 1.634, 4.759 2.364, 4.821 2.966, 4.894 3.374, 4.984 3.525, 5.082 3.391, 5.163 3.03, 5.23 2.498, 5.29 1.851, 5.344 1.147, 5.399 0.444, 5.459 -0.203, 5.526 -0.735, 5.607 -1.096, 5.705 -1.23, 5.81 -1.086, 5.896 -0.695, 5.968 -0.119, 6.031 0.581, 6.089 1.342, 6.147 2.103, 6.21 2.803, 6.282 3.379, 6.368 3.77, 6.473 3.914, 6.572 3.764, 6.653 3.358, 6.722 2.76, 6.781 2.033, 6.837 1.242, 6.892 0.451, 6.952 -0.276, 7.02 -0.875, 7.102 -1.281, 7.201 -1.431, 7.333 -1.285, 7.442 -0.889, 7.533 -0.306, 7.612 0.403, 7.686 1.174, 7.76 1.945, 7.839 2.653, 7.93 3.237, 8.039 3.633, 8.171 3.778, 8.287 3.622, 8.383 3.198, 8.464 2.573, 8.534 1.814, 8.6 0.988, 8.665 0.162, 8.735 -0.597, 8.816 -1.222, 8.912 -1.646, 9.029 -1.803, 9.103 -1.654, 9.164 -1.249, 9.216 -0.653, 9.26 0.07, 9.302 0.858, 9.343 1.645, 9.388 2.369, 9.44 2.965, 9.501 3.369, 9.575 3.518, 9.61 3.482, 9.65 3.377, 9.694 3.212, 9.74 2.994, 9.788 2.731, 9.835 2.43, 9.881 2.099, 9.925 1.745, 9.965 1.376, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .roundWavesRandomized(5, 6, 2, 3, 1) + .asWkt(3), + "LineString (1 1, 1.122 0.552, 1.261 0.113, 1.414 -0.308, 1.575 -0.702, 1.742 -1.061, 1.908 -1.374, 2.069 -1.633, 2.222 -1.829, 2.362 -1.954, 2.483 -1.997, 2.832 -1.829, 3.119 -1.374, 3.36 -0.702, 3.57 0.113, 3.765 1.001, 3.96 1.888, 4.17 2.704, 4.411 3.375, 4.698 3.831, 5.047 3.999, 5.403 3.848, 5.696 3.438, 5.943 2.834, 6.157 2.1, 6.356 1.301, 6.555 0.503, 6.77 -0.231, 7.016 -0.835, 7.309 -1.246, 7.665 -1.397, 7.948 -1.399, 8.238 -1.328, 8.529 -1.191, 8.814 -0.996, 9.085 -0.75, 9.337 -0.46, 9.561 -0.132, 9.751 0.225, 9.899 0.605, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .roundWavesRandomized(8, 9, 2, 3, 1) + .asWkt(3), + "LineString (1 1, 1.183 0.552, 1.393 0.113, 1.623 -0.308, 1.866 -0.702, 2.117 -1.061, 2.367 -1.374, 2.61 -1.633, 2.84 -1.829, 3.05 -1.954, 3.233 -1.997, 3.786 -1.829, 4.241 -1.374, 4.623 -0.702, 4.956 0.113, 5.265 1.001, 5.574 1.888, 5.907 2.704, 6.289 3.375, 6.744 3.831, 7.297 3.999, 7.658 3.874, 8.02 3.687, 8.376 3.445, 8.717 3.158, 9.035 2.836, 9.322 2.487, 9.57 2.119, 9.771 1.743, 9.917 1.367, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .roundWavesRandomized(10, 12, 1, 2, 1) + .asWkt(3), + "LineString (1 1, 1.243 0.701, 1.522 0.409, 1.828 0.128, 2.151 -0.134, 2.483 -0.373, 2.815 -0.582, 3.139 -0.755, 3.444 -0.885, 3.723 -0.968, 3.966 -0.997, 4.664 -0.885, 5.238 -0.582, 5.72 -0.134, 6.141 0.409, 6.53 1.001, 6.92 1.592, 7.341 2.136, 7.823 2.583, 8.397 2.887, 9.094 2.999, 9.169 2.97, 9.254 2.887, 9.347 2.756, 9.446 2.583, 9.547 2.374, 9.649 2.135, 9.747 1.873, 9.841 1.592, 9.926 1.299, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .roundWavesRandomized(20, 25, 2, 3, 1) + .asWkt(3), + "LineString (1 1, 1.506 0.552, 2.085 0.113, 2.72 -0.308, 3.392 -0.702, 4.083 -1.061, 4.773 -1.374, 5.445 -1.633, 6.081 -1.829, 6.66 -1.954, 7.166 -1.997, 7.398 -1.954, 7.665 -1.829, 7.956 -1.633, 8.265 -1.374, 8.583 -1.061, 8.9 -0.702, 9.209 -0.308, 9.501 0.113, 9.768 0.552, 10 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1, 10 10)") + .roundWavesRandomized(5, 6, 2, 3, 1) + .asWkt(3), + "LineString (1 1, 1.122 0.552, 1.261 0.113, 1.414 -0.308, 1.575 -0.702, 1.742 -1.061, 1.908 -1.374, 2.069 -1.633, 2.222 -1.829, 2.362 -1.954, 2.483 -1.997, 2.832 -1.829, 3.119 -1.374, 3.36 -0.702, 3.57 0.113, 3.765 1.001, 3.96 1.888, 4.17 2.704, 4.411 3.375, 4.698 3.831, 5.047 3.999, 5.403 3.848, 5.696 3.438, 5.943 2.834, 6.157 2.1, 6.356 1.301, 6.555 0.503, 6.77 -0.231, 7.016 -0.835, 7.309 -1.246, 7.665 -1.397, 8.029 -1.257, 8.309 -0.888, 8.505 -0.365, 8.614 0.239, 8.634 0.848, 8.563 1.387, 8.399 1.783, 8.14 1.96, 7.785 1.844, 7.33 1.359, 7.485 1.763, 7.904 2.095, 8.522 2.374, 9.272 2.618, 10.088 2.843, 10.905 3.069, 11.655 3.312, 12.273 3.591, 12.692 3.923, 12.846 4.327, 12.696 4.688, 12.288 4.986, 11.686 5.236, 10.956 5.453, 10.161 5.655, 9.366 5.857, 8.636 6.075, 8.034 6.325, 7.626 6.622, 7.475 6.984, 7.609 7.354, 7.97 7.659, 8.502 7.914, 9.149 8.138, 9.853 8.344, 10.556 8.551, 11.203 8.775, 11.735 9.03, 12.096 9.335, 12.23 9.705, 12.197 9.729, 12.105 9.757, 11.959 9.788, 11.766 9.82, 11.533 9.853, 11.266 9.886, 10.973 9.918, 10.66 9.948, 10.333 9.976, 10 10)", + ) + self.assertEqual( + QgsGeometry.fromWkt("MultiLineString ((1 1, 10 1),(10 10, 0 10))") + .roundWavesRandomized(5, 6, 2, 3, 1) + .asWkt(3), + "MultiLineString ((1 1, 1.122 0.552, 1.261 0.113, 1.414 -0.308, 1.575 -0.702, 1.742 -1.061, 1.908 -1.374, 2.069 -1.633, 2.222 -1.829, 2.362 -1.954, 2.483 -1.997, 2.832 -1.829, 3.119 -1.374, 3.36 -0.702, 3.57 0.113, 3.765 1.001, 3.96 1.888, 4.17 2.704, 4.411 3.375, 4.698 3.831, 5.047 3.999, 5.403 3.848, 5.696 3.438, 5.943 2.834, 6.157 2.1, 6.356 1.301, 6.555 0.503, 6.77 -0.231, 7.016 -0.835, 7.309 -1.246, 7.665 -1.397, 7.948 -1.399, 8.238 -1.328, 8.529 -1.191, 8.814 -0.996, 9.085 -0.75, 9.337 -0.46, 9.561 -0.132, 9.751 0.225, 9.899 0.605, 10 1),(10 10, 9.88 10.439, 9.743 10.869, 9.592 11.281, 9.433 11.667, 9.269 12.018, 9.106 12.325, 8.946 12.579, 8.796 12.771, 8.658 12.893, 8.538 12.936, 8.177 12.783, 7.88 12.368, 7.63 11.756, 7.412 11.014, 7.21 10.205, 7.008 9.397, 6.79 8.655, 6.541 8.043, 6.243 7.628, 5.882 7.475, 5.512 7.609, 5.207 7.97, 4.951 8.502, 4.728 9.149, 4.521 9.853, 4.314 10.556, 4.091 11.203, 3.835 11.735, 3.53 12.096, 3.16 12.23, 2.784 12.086, 2.474 11.695, 2.214 11.119, 1.987 10.419, 1.776 9.658, 1.566 8.897, 1.339 8.197, 1.079 7.621, 0.769 7.23, 0.393 7.086, 0.361 7.128, 0.324 7.249, 0.283 7.44, 0.24 7.692, 0.196 7.997, 0.152 8.345, 0.11 8.728, 0.069 9.137, 0.032 9.564, 0 10))", + ) + self.assertEqual( + QgsGeometry.fromWkt( + "Polygon ((1 1, 10 1, 10 10, 1 10, 1 1),(3 4, 8 4, 7 7, 4 6, 3 4))" + ) + .roundWavesRandomized(5, 6, 0.2, 0.3, 1) + .asWkt(3), + "Polygon ((1 1, 1.122 0.955, 1.261 0.911, 1.414 0.869, 1.575 0.83, 1.742 0.794, 1.908 0.763, 2.069 0.737, 2.222 0.717, 2.362 0.705, 2.483 0.7, 2.832 0.717, 3.119 0.763, 3.36 0.83, 3.57 0.911, 3.765 1, 3.96 1.089, 4.17 1.17, 4.411 1.238, 4.698 1.283, 5.047 1.3, 5.403 1.285, 5.696 1.244, 5.943 1.183, 6.157 1.11, 6.356 1.03, 6.555 0.95, 6.77 0.877, 7.016 0.816, 7.309 0.775, 7.665 0.76, 8.031 0.775, 8.328 0.814, 8.57 0.872, 8.767 0.945, 8.934 1.025, 9.082 1.109, 9.223 1.189, 9.37 1.262, 9.536 1.32, 9.733 1.359, 9.748 1.763, 9.79 2.095, 9.852 2.374, 9.927 2.618, 10.009 2.843, 10.09 3.069, 10.165 3.312, 10.227 3.591, 10.269 3.923, 10.285 4.327, 10.27 4.688, 10.229 4.986, 10.169 5.236, 10.096 5.453, 10.016 5.655, 9.937 5.857, 9.864 6.075, 9.803 6.325, 9.763 6.622, 9.748 6.984, 9.761 7.354, 9.797 7.659, 9.85 7.914, 9.915 8.138, 9.985 8.344, 10.056 8.551, 10.12 8.775, 10.174 9.03, 10.21 9.335, 10.223 9.705, 9.866 9.831, 9.572 9.904, 9.324 9.934, 9.106 9.93, 8.902 9.901, 8.696 9.857, 8.472 9.806, 8.213 9.758, 7.904 9.722, 7.527 9.709, 7.156 9.724, 6.851 9.764, 6.594 9.824, 6.371 9.897, 6.163 9.976, 5.956 10.055, 5.732 10.128, 5.476 10.187, 5.17 10.228, 4.799 10.243, 4.395 10.228, 4.062 10.189, 3.783 10.131, 3.54 10.06, 3.314 9.983, 3.088 9.906, 2.845 9.835, 2.566 9.776, 2.233 9.737, 1.829 9.722, 1.664 9.634, 1.502 9.554, 1.346 9.472, 1.2 9.378, 1.068 9.262, 0.951 9.112, 0.855 8.919, 0.782 8.671, 0.736 8.359, 0.72 7.971, 0.735 7.625, 0.775 7.34, 0.835 7.1, 0.907 6.892, 0.986 6.698, 1.065 6.505, 1.137 6.296, 1.196 6.056, 1.237 5.771, 1.252 5.425, 1.237 5.026, 1.196 4.698, 1.136 4.422, 1.064 4.182, 0.984 3.959, 0.905 3.736, 0.833 3.495, 0.773 3.22, 0.732 2.891, 0.717 2.492, 0.729 2.272, 0.746 2.055, 0.769 1.846, 0.796 1.651, 0.826 1.473, 0.859 1.317, 0.894 1.187, 0.93 1.088, 0.965 1.024, 1 1),(3 4, 3.116 3.969, 3.25 3.939, 3.396 3.91, 3.55 3.883, 3.709 3.858, 3.868 3.837, 4.022 3.819, 4.168 3.806, 4.301 3.797, 4.418 3.794, 4.798 3.807, 5.111 3.843, 5.374 3.896, 5.603 3.961, 5.816 4.031, 6.028 4.101, 6.258 4.165, 6.521 4.218, 6.834 4.254, 7.214 4.267, 7.322 4.323, 7.431 4.384, 7.534 4.458, 7.626 4.55, 7.701 4.668, 7.752 4.819, 7.773 5.009, 7.759 5.247, 7.704 5.539, 7.601 5.891, 7.401 6.229, 7.241 6.475, 7.106 6.64, 6.984 6.732, 6.86 6.763, 6.72 6.743, 6.552 6.682, 6.341 6.59, 6.074 6.477, 5.737 6.353, 5.36 6.24, 5.045 6.165, 4.779 6.113, 4.551 6.068, 4.347 6.015, 4.156 5.939, 3.966 5.824, 3.764 5.656, 3.539 5.418, 3.278 5.095, 3.241 5.013, 3.203 4.916, 3.166 4.807, 3.131 4.69, 3.099 4.568, 3.069 4.444, 3.044 4.323, 3.023 4.206, 3.008 4.097, 3 4))", + ) + self.assertEqual( + QgsGeometry.fromWkt( + "MultiPolygon (((1 1, 10 1, 10 10, 1 10, 1 1)),((20 20, 20 30, 30 20, 20 20)))" + ) + .roundWavesRandomized(5, 6, 0.2, 0.3, 1) + .asWkt(3), + "MultiPolygon (((1 1, 1.122 0.955, 1.261 0.911, 1.414 0.869, 1.575 0.83, 1.742 0.794, 1.908 0.763, 2.069 0.737, 2.222 0.717, 2.362 0.705, 2.483 0.7, 2.832 0.717, 3.119 0.763, 3.36 0.83, 3.57 0.911, 3.765 1, 3.96 1.089, 4.17 1.17, 4.411 1.238, 4.698 1.283, 5.047 1.3, 5.403 1.285, 5.696 1.244, 5.943 1.183, 6.157 1.11, 6.356 1.03, 6.555 0.95, 6.77 0.877, 7.016 0.816, 7.309 0.775, 7.665 0.76, 8.031 0.775, 8.328 0.814, 8.57 0.872, 8.767 0.945, 8.934 1.025, 9.082 1.109, 9.223 1.189, 9.37 1.262, 9.536 1.32, 9.733 1.359, 9.748 1.763, 9.79 2.095, 9.852 2.374, 9.927 2.618, 10.009 2.843, 10.09 3.069, 10.165 3.312, 10.227 3.591, 10.269 3.923, 10.285 4.327, 10.27 4.688, 10.229 4.986, 10.169 5.236, 10.096 5.453, 10.016 5.655, 9.937 5.857, 9.864 6.075, 9.803 6.325, 9.763 6.622, 9.748 6.984, 9.761 7.354, 9.797 7.659, 9.85 7.914, 9.915 8.138, 9.985 8.344, 10.056 8.551, 10.12 8.775, 10.174 9.03, 10.21 9.335, 10.223 9.705, 9.866 9.831, 9.572 9.904, 9.324 9.934, 9.106 9.93, 8.902 9.901, 8.696 9.857, 8.472 9.806, 8.213 9.758, 7.904 9.722, 7.527 9.709, 7.156 9.724, 6.851 9.764, 6.594 9.824, 6.371 9.897, 6.163 9.976, 5.956 10.055, 5.732 10.128, 5.476 10.187, 5.17 10.228, 4.799 10.243, 4.395 10.228, 4.062 10.189, 3.783 10.131, 3.54 10.06, 3.314 9.983, 3.088 9.906, 2.845 9.835, 2.566 9.776, 2.233 9.737, 1.829 9.722, 1.664 9.634, 1.502 9.554, 1.346 9.472, 1.2 9.378, 1.068 9.262, 0.951 9.112, 0.855 8.919, 0.782 8.671, 0.736 8.359, 0.72 7.971, 0.735 7.625, 0.775 7.34, 0.835 7.1, 0.907 6.892, 0.986 6.698, 1.065 6.505, 1.137 6.296, 1.196 6.056, 1.237 5.771, 1.252 5.425, 1.237 5.026, 1.196 4.698, 1.136 4.422, 1.064 4.182, 0.984 3.959, 0.905 3.736, 0.833 3.495, 0.773 3.22, 0.732 2.891, 0.717 2.492, 0.729 2.272, 0.746 2.055, 0.769 1.846, 0.796 1.651, 0.826 1.473, 0.859 1.317, 0.894 1.187, 0.93 1.088, 0.965 1.024, 1 1)),((20 20, 20.031 20.116, 20.061 20.25, 20.09 20.396, 20.117 20.55, 20.142 20.709, 20.163 20.868, 20.181 21.022, 20.194 21.168, 20.203 21.301, 20.206 21.418, 20.193 21.798, 20.157 22.111, 20.104 22.374, 20.039 22.603, 19.969 22.816, 19.899 23.028, 19.835 23.258, 19.782 23.521, 19.746 23.834, 19.733 24.214, 19.746 24.582, 19.783 24.885, 19.838 25.14, 19.904 25.361, 19.976 25.567, 20.048 25.773, 20.115 25.995, 20.169 26.249, 20.206 26.552, 20.22 26.92, 20.208 27.28, 20.175 27.576, 20.126 27.825, 20.067 28.041, 20.003 28.242, 19.939 28.443, 19.88 28.66, 19.831 28.909, 19.798 29.205, 19.786 29.565, 20.071 29.52, 20.288 29.461, 20.454 29.384, 20.585 29.286, 20.698 29.164, 20.809 29.015, 20.935 28.837, 21.092 28.626, 21.297 28.379, 21.566 28.092, 21.818 27.86, 22.045 27.688, 22.252 27.561, 22.446 27.463, 22.634 27.381, 22.822 27.298, 23.017 27.2, 23.224 27.073, 23.45 26.901, 23.702 26.669, 23.965 26.387, 24.163 26.136, 24.312 25.909, 24.428 25.698, 24.529 25.494, 24.63 25.29, 24.746 25.079, 24.896 24.852, 25.093 24.601, 25.356 24.319, 25.627 24.066, 25.866 23.875, 26.083 23.73, 26.285 23.615, 26.478 23.516, 26.672 23.417, 26.873 23.303, 27.09 23.158, 27.33 22.966, 27.601 22.713, 27.835 22.46, 28.011 22.234, 28.143 22.028, 28.245 21.836, 28.332 21.651, 28.419 21.465, 28.521 21.273, 28.652 21.067, 28.828 20.841, 29.063 20.588, 29.263 20.481, 29.415 20.366, 29.516 20.248, 29.563 20.131, 29.552 20.021, 29.482 19.921, 29.347 19.835, 29.146 19.768, 28.875 19.725, 28.53 19.71, 28.182 19.725, 27.896 19.766, 27.655 19.827, 27.445 19.901, 27.25 19.981, 27.056 20.061, 26.846 20.135, 26.605 20.196, 26.319 20.237, 25.971 20.252, 25.625 20.237, 25.34 20.196, 25.101 20.135, 24.893 20.061, 24.7 19.98, 24.507 19.9, 24.298 19.826, 24.059 19.765, 23.774 19.724, 23.429 19.708, 23.027 19.723, 22.696 19.763, 22.418 19.821, 22.176 19.892, 21.951 19.969, 21.727 20.046, 21.484 20.117, 21.206 20.176, 20.875 20.215, 20.474 20.23, 20.435 20.227, 20.39 20.217, 20.341 20.202, 20.29 20.182, 20.237 20.158, 20.184 20.131, 20.132 20.1, 20.083 20.068, 20.039 20.034, 20 20)))", + ) def testApplyDashPattern(self): """Test apply dash pattern""" - self.assertEqual(QgsGeometry.fromWkt('Point (1 1)').applyDashPattern([1, 2]).asWkt(3), 'Point (1 1)') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1)').applyDashPattern([1, 2]).asWkt(3), '') # don't crash! - self.assertEqual(QgsGeometry.fromWkt('LineString EMPTY').applyDashPattern([1, 2]).asWkt(3), '') # don't crash! - self.assertEqual(QgsGeometry.fromWkt('Polygon EMPTY').applyDashPattern([1, 2]).asWkt(3), '') # don't crash! + self.assertEqual( + QgsGeometry.fromWkt("Point (1 1)").applyDashPattern([1, 2]).asWkt(3), + "Point (1 1)", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1)").applyDashPattern([1, 2]).asWkt(3), + "", + ) # don't crash! + self.assertEqual( + QgsGeometry.fromWkt("LineString EMPTY").applyDashPattern([1, 2]).asWkt(3), + "", + ) # don't crash! + self.assertEqual( + QgsGeometry.fromWkt("Polygon EMPTY").applyDashPattern([1, 2]).asWkt(3), "" + ) # don't crash! # bad pattern length - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10)').applyDashPattern([1, 2, 3]).asWkt(3), '') # don't crash! - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').applyDashPattern([1, 2]).asWkt(3), - 'MultiLineString ((1 1, 2 1),(4 1, 5 1),(7 1, 8 1),(10 1, 10 1, 10 1))') + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10)") + .applyDashPattern([1, 2, 3]) + .asWkt(3), + "", + ) # don't crash! + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .applyDashPattern([1, 2]) + .asWkt(3), + "MultiLineString ((1 1, 2 1),(4 1, 5 1),(7 1, 8 1),(10 1, 10 1, 10 1))", + ) # pattern ends on gap - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').applyDashPattern([1, 2, 0.5, 0.1]).asWkt(3), - 'MultiLineString ((1 1, 2 1),(4 1, 4.5 1),(4.6 1, 5.6 1),(7.6 1, 8.1 1),(8.2 1, 9.2 1))') + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .applyDashPattern([1, 2, 0.5, 0.1]) + .asWkt(3), + "MultiLineString ((1 1, 2 1),(4 1, 4.5 1),(4.6 1, 5.6 1),(7.6 1, 8.1 1),(8.2 1, 9.2 1))", + ) # pattern ends on dash - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').applyDashPattern([1.1, 1, 0.5, 0.1]).asWkt(3), - 'MultiLineString ((1 1, 2.1 1),(3.1 1, 3.6 1),(3.7 1, 4.8 1),(5.8 1, 6.3 1),(6.4 1, 7.5 1),(8.5 1, 9 1),(9.1 1, 10 1, 10 1))') + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .applyDashPattern([1.1, 1, 0.5, 0.1]) + .asWkt(3), + "MultiLineString ((1 1, 2.1 1),(3.1 1, 3.6 1),(3.7 1, 4.8 1),(5.8 1, 6.3 1),(6.4 1, 7.5 1),(8.5 1, 9 1),(9.1 1, 10 1, 10 1))", + ) # pattern rules # start rule only - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').applyDashPattern([1, 2, 0.5, 0.1], Qgis.DashPatternLineEndingRule.FullDash).asWkt(3), - 'MultiLineString ((1 1, 2 1),(4 1, 4.5 1),(4.6 1, 5.6 1),(7.6 1, 8.1 1),(8.2 1, 9.2 1))') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').applyDashPattern([1, 2, 0.5, 0.1], Qgis.DashPatternLineEndingRule.HalfDash).asWkt(3), - 'MultiLineString ((1 1, 1.5 1),(3.5 1, 4 1),(4.1 1, 5.1 1),(7.1 1, 7.6 1),(7.7 1, 8.7 1))') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').applyDashPattern([1, 2, 0.5, 0.1], Qgis.DashPatternLineEndingRule.FullGap).asWkt(3), - 'MultiLineString ((1.1 1, 2.1 1),(4.1 1, 4.6 1),(4.7 1, 5.7 1),(7.7 1, 8.2 1),(8.3 1, 9.3 1))') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').applyDashPattern([1, 2, 0.5, 0.1], Qgis.DashPatternLineEndingRule.HalfGap).asWkt(3), - 'MultiLineString ((1.05 1, 2.05 1),(4.05 1, 4.55 1),(4.65 1, 5.65 1),(7.65 1, 8.15 1),(8.25 1, 9.25 1))') + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .applyDashPattern([1, 2, 0.5, 0.1], Qgis.DashPatternLineEndingRule.FullDash) + .asWkt(3), + "MultiLineString ((1 1, 2 1),(4 1, 4.5 1),(4.6 1, 5.6 1),(7.6 1, 8.1 1),(8.2 1, 9.2 1))", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .applyDashPattern([1, 2, 0.5, 0.1], Qgis.DashPatternLineEndingRule.HalfDash) + .asWkt(3), + "MultiLineString ((1 1, 1.5 1),(3.5 1, 4 1),(4.1 1, 5.1 1),(7.1 1, 7.6 1),(7.7 1, 8.7 1))", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .applyDashPattern([1, 2, 0.5, 0.1], Qgis.DashPatternLineEndingRule.FullGap) + .asWkt(3), + "MultiLineString ((1.1 1, 2.1 1),(4.1 1, 4.6 1),(4.7 1, 5.7 1),(7.7 1, 8.2 1),(8.3 1, 9.3 1))", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .applyDashPattern([1, 2, 0.5, 0.1], Qgis.DashPatternLineEndingRule.HalfGap) + .asWkt(3), + "MultiLineString ((1.05 1, 2.05 1),(4.05 1, 4.55 1),(4.65 1, 5.65 1),(7.65 1, 8.15 1),(8.25 1, 9.25 1))", + ) # end rule only - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').applyDashPattern([1, 2, 0.5, 0.1], endRule=Qgis.DashPatternLineEndingRule.FullDash).asWkt(3), - 'MultiLineString ((1 1, 1.841 1),(3.523 1, 3.944 1),(4.028 1, 4.869 1),(6.551 1, 6.972 1),(7.056 1, 7.897 1),(9.579 1, 10 1))') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').applyDashPattern([1, 2, 0.5, 0.1], endRule=Qgis.DashPatternLineEndingRule.HalfDash).asWkt(3), - 'MultiLineString ((1 1, 1.861 1),(3.584 1, 4.014 1),(4.1 1, 4.962 1),(6.684 1, 7.115 1),(7.201 1, 8.062 1),(9.785 1, 10 1, 10 1))') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').applyDashPattern([1, 2, 0.5, 0.1], endRule=Qgis.DashPatternLineEndingRule.FullGap).asWkt(3), - 'MultiLineString ((1 1, 1.833 1),(3.5 1, 3.917 1),(4 1, 4.833 1),(6.5 1, 6.917 1),(7 1, 7.833 1),(9.5 1, 9.917 1),(10 1, 10 1, 10 1))') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').applyDashPattern([1, 2, 0.5, 0.1], endRule=Qgis.DashPatternLineEndingRule.HalfGap).asWkt(3), - 'MultiLineString ((1 1, 1.837 1),(3.512 1, 3.93 1),(4.014 1, 4.851 1),(6.526 1, 6.944 1),(7.028 1, 7.865 1),(9.54 1, 9.958 1))') + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .applyDashPattern( + [1, 2, 0.5, 0.1], endRule=Qgis.DashPatternLineEndingRule.FullDash + ) + .asWkt(3), + "MultiLineString ((1 1, 1.841 1),(3.523 1, 3.944 1),(4.028 1, 4.869 1),(6.551 1, 6.972 1),(7.056 1, 7.897 1),(9.579 1, 10 1))", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .applyDashPattern( + [1, 2, 0.5, 0.1], endRule=Qgis.DashPatternLineEndingRule.HalfDash + ) + .asWkt(3), + "MultiLineString ((1 1, 1.861 1),(3.584 1, 4.014 1),(4.1 1, 4.962 1),(6.684 1, 7.115 1),(7.201 1, 8.062 1),(9.785 1, 10 1, 10 1))", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .applyDashPattern( + [1, 2, 0.5, 0.1], endRule=Qgis.DashPatternLineEndingRule.FullGap + ) + .asWkt(3), + "MultiLineString ((1 1, 1.833 1),(3.5 1, 3.917 1),(4 1, 4.833 1),(6.5 1, 6.917 1),(7 1, 7.833 1),(9.5 1, 9.917 1),(10 1, 10 1, 10 1))", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .applyDashPattern( + [1, 2, 0.5, 0.1], endRule=Qgis.DashPatternLineEndingRule.HalfGap + ) + .asWkt(3), + "MultiLineString ((1 1, 1.837 1),(3.512 1, 3.93 1),(4.014 1, 4.851 1),(6.526 1, 6.944 1),(7.028 1, 7.865 1),(9.54 1, 9.958 1))", + ) # start and end rules - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').applyDashPattern([1, 2, 0.5, 0.1], - Qgis.DashPatternLineEndingRule.FullDash, - Qgis.DashPatternLineEndingRule.FullDash).asWkt(3), - 'MultiLineString ((1 1, 1.841 1),(3.523 1, 3.944 1),(4.028 1, 4.869 1),(6.551 1, 6.972 1),(7.056 1, 7.897 1),(9.579 1, 10 1))') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').applyDashPattern([1, 2, 0.5, 0.1], Qgis.DashPatternLineEndingRule.HalfDash, - Qgis.DashPatternLineEndingRule.FullDash).asWkt(3), - 'MultiLineString ((1 1, 1.441 1),(3.206 1, 3.647 1),(3.735 1, 4.618 1),(6.382 1, 6.824 1),(6.912 1, 7.794 1),(9.559 1, 10 1, 10 1))') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').applyDashPattern([1, 2, 0.5, 0.1], Qgis.DashPatternLineEndingRule.FullGap, - Qgis.DashPatternLineEndingRule.FullDash).asWkt(3), - 'MultiLineString ((1.083 1, 1.917 1),(3.583 1, 4 1),(4.083 1, 4.917 1),(6.583 1, 7 1),(7.083 1, 7.917 1),(9.583 1, 10 1))') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').applyDashPattern([1, 2, 0.5, 0.1], Qgis.DashPatternLineEndingRule.HalfGap, - Qgis.DashPatternLineEndingRule.FullDash).asWkt(3), - 'MultiLineString ((1.042 1, 1.879 1),(3.553 1, 3.972 1),(4.056 1, 4.893 1),(6.567 1, 6.986 1),(7.07 1, 7.907 1),(9.581 1, 10 1))') + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .applyDashPattern( + [1, 2, 0.5, 0.1], + Qgis.DashPatternLineEndingRule.FullDash, + Qgis.DashPatternLineEndingRule.FullDash, + ) + .asWkt(3), + "MultiLineString ((1 1, 1.841 1),(3.523 1, 3.944 1),(4.028 1, 4.869 1),(6.551 1, 6.972 1),(7.056 1, 7.897 1),(9.579 1, 10 1))", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .applyDashPattern( + [1, 2, 0.5, 0.1], + Qgis.DashPatternLineEndingRule.HalfDash, + Qgis.DashPatternLineEndingRule.FullDash, + ) + .asWkt(3), + "MultiLineString ((1 1, 1.441 1),(3.206 1, 3.647 1),(3.735 1, 4.618 1),(6.382 1, 6.824 1),(6.912 1, 7.794 1),(9.559 1, 10 1, 10 1))", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .applyDashPattern( + [1, 2, 0.5, 0.1], + Qgis.DashPatternLineEndingRule.FullGap, + Qgis.DashPatternLineEndingRule.FullDash, + ) + .asWkt(3), + "MultiLineString ((1.083 1, 1.917 1),(3.583 1, 4 1),(4.083 1, 4.917 1),(6.583 1, 7 1),(7.083 1, 7.917 1),(9.583 1, 10 1))", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .applyDashPattern( + [1, 2, 0.5, 0.1], + Qgis.DashPatternLineEndingRule.HalfGap, + Qgis.DashPatternLineEndingRule.FullDash, + ) + .asWkt(3), + "MultiLineString ((1.042 1, 1.879 1),(3.553 1, 3.972 1),(4.056 1, 4.893 1),(6.567 1, 6.986 1),(7.07 1, 7.907 1),(9.581 1, 10 1))", + ) # adjustment rule - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').applyDashPattern([1, 2, 0.5, 0.1], - Qgis.DashPatternLineEndingRule.FullDash, - Qgis.DashPatternLineEndingRule.FullDash, - Qgis.DashPatternSizeAdjustment.ScaleDashOnly).asWkt(3), - 'MultiLineString ((1 1, 1.622 1),(3.622 1, 3.933 1),(4.033 1, 4.656 1),(6.656 1, 6.967 1),(7.067 1, 7.689 1),(9.689 1, 10 1, 10 1))') - - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').applyDashPattern([1, 2, 0.5, 0.1], - Qgis.DashPatternLineEndingRule.FullDash, - Qgis.DashPatternLineEndingRule.FullDash, - Qgis.DashPatternSizeAdjustment.ScaleGapOnly).asWkt(3), - 'MultiLineString ((1 1, 2 1),(3.452 1, 3.952 1),(4.024 1, 5.024 1),(6.476 1, 6.976 1),(7.048 1, 8.048 1),(9.5 1, 10 1, 10 1))') + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .applyDashPattern( + [1, 2, 0.5, 0.1], + Qgis.DashPatternLineEndingRule.FullDash, + Qgis.DashPatternLineEndingRule.FullDash, + Qgis.DashPatternSizeAdjustment.ScaleDashOnly, + ) + .asWkt(3), + "MultiLineString ((1 1, 1.622 1),(3.622 1, 3.933 1),(4.033 1, 4.656 1),(6.656 1, 6.967 1),(7.067 1, 7.689 1),(9.689 1, 10 1, 10 1))", + ) + + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .applyDashPattern( + [1, 2, 0.5, 0.1], + Qgis.DashPatternLineEndingRule.FullDash, + Qgis.DashPatternLineEndingRule.FullDash, + Qgis.DashPatternSizeAdjustment.ScaleGapOnly, + ) + .asWkt(3), + "MultiLineString ((1 1, 2 1),(3.452 1, 3.952 1),(4.024 1, 5.024 1),(6.476 1, 6.976 1),(7.048 1, 8.048 1),(9.5 1, 10 1, 10 1))", + ) # pattern offset - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').applyDashPattern([1, 2, 0.5, 0.1], - Qgis.DashPatternLineEndingRule.FullDash, - Qgis.DashPatternLineEndingRule.FullDash, - patternOffset=15).asWkt(3), - 'MultiLineString ((1 1, 1.336 1),(3.019 1, 3.439 1),(3.523 1, 4.364 1),(6.047 1, 6.467 1),(6.551 1, 7.393 1),(9.075 1, 9.495 1),(9.579 1, 10 1, 10 1))') - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1)').applyDashPattern([1, 2, 0.5, 0.1], - Qgis.DashPatternLineEndingRule.FullDash, - Qgis.DashPatternLineEndingRule.FullDash, - patternOffset=-15).asWkt(3), - 'MultiLineString ((1 1, 1.421 1),(1.505 1, 2.346 1),(4.028 1, 4.449 1),(4.533 1, 5.374 1),(7.056 1, 7.477 1),(7.561 1, 8.402 1))') + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .applyDashPattern( + [1, 2, 0.5, 0.1], + Qgis.DashPatternLineEndingRule.FullDash, + Qgis.DashPatternLineEndingRule.FullDash, + patternOffset=15, + ) + .asWkt(3), + "MultiLineString ((1 1, 1.336 1),(3.019 1, 3.439 1),(3.523 1, 4.364 1),(6.047 1, 6.467 1),(6.551 1, 7.393 1),(9.075 1, 9.495 1),(9.579 1, 10 1, 10 1))", + ) + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1)") + .applyDashPattern( + [1, 2, 0.5, 0.1], + Qgis.DashPatternLineEndingRule.FullDash, + Qgis.DashPatternLineEndingRule.FullDash, + patternOffset=-15, + ) + .asWkt(3), + "MultiLineString ((1 1, 1.421 1),(1.505 1, 2.346 1),(4.028 1, 4.449 1),(4.533 1, 5.374 1),(7.056 1, 7.477 1),(7.561 1, 8.402 1))", + ) # short line compared to pattern length - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 4 1)').applyDashPattern([1, 2, 0.5, 0.1], - Qgis.DashPatternLineEndingRule.FullDash, - Qgis.DashPatternLineEndingRule.FullDash, - Qgis.DashPatternSizeAdjustment.ScaleDashOnly).asWkt(3), - 'MultiLineString ((1 1, 1.667 1),(3.667 1, 4 1))') + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 4 1)") + .applyDashPattern( + [1, 2, 0.5, 0.1], + Qgis.DashPatternLineEndingRule.FullDash, + Qgis.DashPatternLineEndingRule.FullDash, + Qgis.DashPatternSizeAdjustment.ScaleDashOnly, + ) + .asWkt(3), + "MultiLineString ((1 1, 1.667 1),(3.667 1, 4 1))", + ) - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 2 1)').applyDashPattern([1, 2], - Qgis.DashPatternLineEndingRule.FullDash, - Qgis.DashPatternLineEndingRule.FullDash).asWkt(3), - 'MultiLineString ((1 1, 2 1))') + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 2 1)") + .applyDashPattern( + [1, 2], + Qgis.DashPatternLineEndingRule.FullDash, + Qgis.DashPatternLineEndingRule.FullDash, + ) + .asWkt(3), + "MultiLineString ((1 1, 2 1))", + ) - self.assertEqual(QgsGeometry.fromWkt('LineString (1 1, 10 1, 10 10)').applyDashPattern([1, 2, 0.5, 0.1]).asWkt(3), - 'MultiLineString ((1 1, 2 1),(4 1, 4.5 1),(4.6 1, 5.6 1),(7.6 1, 8.1 1),(8.2 1, 9.2 1),(10 2.2, 10 2.7),(10 2.8, 10 3.8),(10 5.8, 10 6.3),(10 6.4, 10 7.4),(10 9.4, 10 9.9),(10 10, 10 10, 10 10))') + self.assertEqual( + QgsGeometry.fromWkt("LineString (1 1, 10 1, 10 10)") + .applyDashPattern([1, 2, 0.5, 0.1]) + .asWkt(3), + "MultiLineString ((1 1, 2 1),(4 1, 4.5 1),(4.6 1, 5.6 1),(7.6 1, 8.1 1),(8.2 1, 9.2 1),(10 2.2, 10 2.7),(10 2.8, 10 3.8),(10 5.8, 10 6.3),(10 6.4, 10 7.4),(10 9.4, 10 9.9),(10 10, 10 10, 10 10))", + ) self.assertEqual( - QgsGeometry.fromWkt('MultiLineString ((1 1, 10 1),(10 10, 0 10))').applyDashPattern([1, 2, 0.5, 0.1]).asWkt(3), - 'MultiLineString ((1 1, 2 1),(4 1, 4.5 1),(4.6 1, 5.6 1),(7.6 1, 8.1 1),(8.2 1, 9.2 1),(10 10, 9 10),(7 10, 6.5 10),(6.4 10, 5.4 10),(3.4 10, 2.9 10),(2.8 10, 1.8 10))') + QgsGeometry.fromWkt("MultiLineString ((1 1, 10 1),(10 10, 0 10))") + .applyDashPattern([1, 2, 0.5, 0.1]) + .asWkt(3), + "MultiLineString ((1 1, 2 1),(4 1, 4.5 1),(4.6 1, 5.6 1),(7.6 1, 8.1 1),(8.2 1, 9.2 1),(10 10, 9 10),(7 10, 6.5 10),(6.4 10, 5.4 10),(3.4 10, 2.9 10),(2.8 10, 1.8 10))", + ) self.assertEqual( - QgsGeometry.fromWkt('Polygon ((1 1, 10 1, 10 10, 1 10, 1 1),(3 4, 8 4, 7 7, 4 6, 3 4))').applyDashPattern([1, 2, 0.5, 0.1]).asWkt( - 3), - 'MultiLineString ((1 1, 2 1),(4 1, 4.5 1),(4.6 1, 5.6 1),(7.6 1, 8.1 1),(8.2 1, 9.2 1),(10 2.2, 10 2.7),(10 2.8, 10 3.8),(10 5.8, 10 6.3),(10 6.4, 10 7.4),(10 9.4, 10 9.9),(10 10, 10 10, 9 10),(7 10, 6.5 10),(6.4 10, 5.4 10),(3.4 10, 2.9 10),(2.8 10, 1.8 10),(1 8.8, 1 8.3),(1 8.2, 1 7.2),(1 5.2, 1 4.7),(1 4.6, 1 3.6),(1 1.6, 1 1.1),(1 1, 1 1, 1 1),(3 4, 4 4),(6 4, 6.5 4),(6.6 4, 7.6 4),(7.494 5.518, 7.336 5.992),(7.304 6.087, 7 7, 6.964 6.988),(5.067 6.356, 4.593 6.198),(4.498 6.166, 4 6, 3.787 5.575))') - self.assertEqual(QgsGeometry.fromWkt( - 'MultiPolygon (((1 1, 10 1, 10 10, 1 10, 1 1)),((20 20, 20 30, 30 20, 20 20)))').applyDashPattern([1, 2, 0.5, 0.1]).asWkt( - 3), - 'MultiLineString ((1 1, 2 1),(4 1, 4.5 1),(4.6 1, 5.6 1),(7.6 1, 8.1 1),(8.2 1, 9.2 1),(10 2.2, 10 2.7),(10 2.8, 10 3.8),(10 5.8, 10 6.3),(10 6.4, 10 7.4),(10 9.4, 10 9.9),(10 10, 10 10, 9 10),(7 10, 6.5 10),(6.4 10, 5.4 10),(3.4 10, 2.9 10),(2.8 10, 1.8 10),(1 8.8, 1 8.3),(1 8.2, 1 7.2),(1 5.2, 1 4.7),(1 4.6, 1 3.6),(1 1.6, 1 1.1),(1 1, 1 1, 1 1),(20 20, 20 21),(20 23, 20 23.5),(20 23.6, 20 24.6),(20 26.6, 20 27.1),(20 27.2, 20 28.2),(20.141 29.859, 20.495 29.505),(20.566 29.434, 21.273 28.727),(22.687 27.313, 23.041 26.959),(23.111 26.889, 23.818 26.182),(25.233 24.767, 25.586 24.414),(25.657 24.343, 26.364 23.636),(27.778 22.222, 28.132 21.868),(28.202 21.798, 28.91 21.09),(29.542 20, 29.042 20),(28.942 20, 27.942 20),(25.942 20, 25.442 20),(25.342 20, 24.342 20),(22.342 20, 21.842 20),(21.742 20, 20.742 20))') + QgsGeometry.fromWkt( + "Polygon ((1 1, 10 1, 10 10, 1 10, 1 1),(3 4, 8 4, 7 7, 4 6, 3 4))" + ) + .applyDashPattern([1, 2, 0.5, 0.1]) + .asWkt(3), + "MultiLineString ((1 1, 2 1),(4 1, 4.5 1),(4.6 1, 5.6 1),(7.6 1, 8.1 1),(8.2 1, 9.2 1),(10 2.2, 10 2.7),(10 2.8, 10 3.8),(10 5.8, 10 6.3),(10 6.4, 10 7.4),(10 9.4, 10 9.9),(10 10, 10 10, 9 10),(7 10, 6.5 10),(6.4 10, 5.4 10),(3.4 10, 2.9 10),(2.8 10, 1.8 10),(1 8.8, 1 8.3),(1 8.2, 1 7.2),(1 5.2, 1 4.7),(1 4.6, 1 3.6),(1 1.6, 1 1.1),(1 1, 1 1, 1 1),(3 4, 4 4),(6 4, 6.5 4),(6.6 4, 7.6 4),(7.494 5.518, 7.336 5.992),(7.304 6.087, 7 7, 6.964 6.988),(5.067 6.356, 4.593 6.198),(4.498 6.166, 4 6, 3.787 5.575))", + ) + self.assertEqual( + QgsGeometry.fromWkt( + "MultiPolygon (((1 1, 10 1, 10 10, 1 10, 1 1)),((20 20, 20 30, 30 20, 20 20)))" + ) + .applyDashPattern([1, 2, 0.5, 0.1]) + .asWkt(3), + "MultiLineString ((1 1, 2 1),(4 1, 4.5 1),(4.6 1, 5.6 1),(7.6 1, 8.1 1),(8.2 1, 9.2 1),(10 2.2, 10 2.7),(10 2.8, 10 3.8),(10 5.8, 10 6.3),(10 6.4, 10 7.4),(10 9.4, 10 9.9),(10 10, 10 10, 9 10),(7 10, 6.5 10),(6.4 10, 5.4 10),(3.4 10, 2.9 10),(2.8 10, 1.8 10),(1 8.8, 1 8.3),(1 8.2, 1 7.2),(1 5.2, 1 4.7),(1 4.6, 1 3.6),(1 1.6, 1 1.1),(1 1, 1 1, 1 1),(20 20, 20 21),(20 23, 20 23.5),(20 23.6, 20 24.6),(20 26.6, 20 27.1),(20 27.2, 20 28.2),(20.141 29.859, 20.495 29.505),(20.566 29.434, 21.273 28.727),(22.687 27.313, 23.041 26.959),(23.111 26.889, 23.818 26.182),(25.233 24.767, 25.586 24.414),(25.657 24.343, 26.364 23.636),(27.778 22.222, 28.132 21.868),(28.202 21.798, 28.91 21.09),(29.542 20, 29.042 20),(28.942 20, 27.942 20),(25.942 20, 25.442 20),(25.342 20, 24.342 20),(22.342 20, 21.842 20),(21.742 20, 20.742 20))", + ) def testGeosCrash(self): # test we don't crash when geos returns a point geometry with no points - QgsGeometry.fromWkt('Polygon ((0 0, 1 1, 1 0, 0 0))').intersection(QgsGeometry.fromWkt('Point (42 0)')).isNull() + QgsGeometry.fromWkt("Polygon ((0 0, 1 1, 1 0, 0 0))").intersection( + QgsGeometry.fromWkt("Point (42 0)") + ).isNull() def testIsRectangle(self): """ @@ -7321,43 +13070,110 @@ def testIsRectangle(self): """ # non polygons self.assertFalse(QgsGeometry().isAxisParallelRectangle(0)) - self.assertFalse(QgsGeometry.fromWkt('Point(0 1)').isAxisParallelRectangle(0)) - self.assertFalse(QgsGeometry.fromWkt('LineString(0 1, 1 2)').isAxisParallelRectangle(0)) - - self.assertFalse(QgsGeometry.fromWkt('Polygon((0 0, 0 1, 1 1, 0 0))').isAxisParallelRectangle(0)) - self.assertFalse(QgsGeometry.fromWkt('Polygon((0 0, 0 1, 1 1, 0 0))').isAxisParallelRectangle(0, True)) - self.assertFalse(QgsGeometry.fromWkt('Polygon((0 0, 0 1, 1 1, 0 1))').isAxisParallelRectangle(0)) - self.assertFalse(QgsGeometry.fromWkt('Polygon((0 0, 0 1, 1 1, 0 1))').isAxisParallelRectangle(0, True)) - self.assertFalse(QgsGeometry.fromWkt('Polygon(())').isAxisParallelRectangle(0)) - - self.assertTrue(QgsGeometry.fromWkt('Polygon((0 0, 1 0, 1 1, 0 1, 0 0))').isAxisParallelRectangle(0)) - self.assertTrue(QgsGeometry.fromWkt('Polygon((0 0, 1 0, 1 1, 0 1, 0 0))').isAxisParallelRectangle(0, True)) - self.assertTrue(QgsGeometry.fromWkt('Polygon((0 0, 0 1, 1 1, 1 0, 0 0))').isAxisParallelRectangle(0)) - self.assertTrue(QgsGeometry.fromWkt('Polygon((0 0, 0 1, 1 1, 1 0, 0 0))').isAxisParallelRectangle(0, True)) + self.assertFalse(QgsGeometry.fromWkt("Point(0 1)").isAxisParallelRectangle(0)) + self.assertFalse( + QgsGeometry.fromWkt("LineString(0 1, 1 2)").isAxisParallelRectangle(0) + ) + + self.assertFalse( + QgsGeometry.fromWkt( + "Polygon((0 0, 0 1, 1 1, 0 0))" + ).isAxisParallelRectangle(0) + ) + self.assertFalse( + QgsGeometry.fromWkt( + "Polygon((0 0, 0 1, 1 1, 0 0))" + ).isAxisParallelRectangle(0, True) + ) + self.assertFalse( + QgsGeometry.fromWkt( + "Polygon((0 0, 0 1, 1 1, 0 1))" + ).isAxisParallelRectangle(0) + ) + self.assertFalse( + QgsGeometry.fromWkt( + "Polygon((0 0, 0 1, 1 1, 0 1))" + ).isAxisParallelRectangle(0, True) + ) + self.assertFalse(QgsGeometry.fromWkt("Polygon(())").isAxisParallelRectangle(0)) + + self.assertTrue( + QgsGeometry.fromWkt( + "Polygon((0 0, 1 0, 1 1, 0 1, 0 0))" + ).isAxisParallelRectangle(0) + ) + self.assertTrue( + QgsGeometry.fromWkt( + "Polygon((0 0, 1 0, 1 1, 0 1, 0 0))" + ).isAxisParallelRectangle(0, True) + ) + self.assertTrue( + QgsGeometry.fromWkt( + "Polygon((0 0, 0 1, 1 1, 1 0, 0 0))" + ).isAxisParallelRectangle(0) + ) + self.assertTrue( + QgsGeometry.fromWkt( + "Polygon((0 0, 0 1, 1 1, 1 0, 0 0))" + ).isAxisParallelRectangle(0, True) + ) # with rings - self.assertFalse(QgsGeometry.fromWkt( - 'Polygon((0 0, 1 0, 1 1, 0 1, 0 0), (0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.2, 0.1 0.1))').isAxisParallelRectangle( - 0)) + self.assertFalse( + QgsGeometry.fromWkt( + "Polygon((0 0, 1 0, 1 1, 0 1, 0 0), (0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.2, 0.1 0.1))" + ).isAxisParallelRectangle(0) + ) # densified - self.assertTrue(QgsGeometry.fromWkt('Polygon((0 0, 0.5 0.0, 1 0, 1 1, 0 1, 0 0))').densifyByCount( - 5).isAxisParallelRectangle(0)) + self.assertTrue( + QgsGeometry.fromWkt("Polygon((0 0, 0.5 0.0, 1 0, 1 1, 0 1, 0 0))") + .densifyByCount(5) + .isAxisParallelRectangle(0) + ) # not a simple rectangle - self.assertFalse(QgsGeometry.fromWkt('Polygon((0 0, 0.5 0.0, 1 0, 1 1, 0 1, 0 0))').densifyByCount( - 5).isAxisParallelRectangle(0, True)) + self.assertFalse( + QgsGeometry.fromWkt("Polygon((0 0, 0.5 0.0, 1 0, 1 1, 0 1, 0 0))") + .densifyByCount(5) + .isAxisParallelRectangle(0, True) + ) # starting mid way through a side - self.assertTrue(QgsGeometry.fromWkt('Polygon((0.5 0, 1 0, 1 1, 0 1, 0 0, 0.5 0))').densifyByCount( - 5).isAxisParallelRectangle(0)) - self.assertFalse(QgsGeometry.fromWkt('Polygon((0.5 0, 1 0, 1 1, 0 1, 0 0, 0.5 0))').densifyByCount( - 5).isAxisParallelRectangle(0, True)) + self.assertTrue( + QgsGeometry.fromWkt("Polygon((0.5 0, 1 0, 1 1, 0 1, 0 0, 0.5 0))") + .densifyByCount(5) + .isAxisParallelRectangle(0) + ) + self.assertFalse( + QgsGeometry.fromWkt("Polygon((0.5 0, 1 0, 1 1, 0 1, 0 0, 0.5 0))") + .densifyByCount(5) + .isAxisParallelRectangle(0, True) + ) # with tolerance - self.assertFalse(QgsGeometry.fromWkt('Polygon((0 0, 1 0.001, 1 1, 0 1, 0 0))').isAxisParallelRectangle(0)) - self.assertTrue(QgsGeometry.fromWkt('Polygon((0 0, 1 0.001, 1 1, 0 1, 0 0))').isAxisParallelRectangle(1)) - self.assertFalse(QgsGeometry.fromWkt('Polygon((0 0, 1 0.1, 1 1, 0 1, 0 0))').isAxisParallelRectangle(1)) - self.assertTrue(QgsGeometry.fromWkt('Polygon((0 0, 1 0.1, 1 1, 0 1, 0 0))').isAxisParallelRectangle(10)) + self.assertFalse( + QgsGeometry.fromWkt( + "Polygon((0 0, 1 0.001, 1 1, 0 1, 0 0))" + ).isAxisParallelRectangle(0) + ) + self.assertTrue( + QgsGeometry.fromWkt( + "Polygon((0 0, 1 0.001, 1 1, 0 1, 0 0))" + ).isAxisParallelRectangle(1) + ) + self.assertFalse( + QgsGeometry.fromWkt( + "Polygon((0 0, 1 0.1, 1 1, 0 1, 0 0))" + ).isAxisParallelRectangle(1) + ) self.assertTrue( - QgsGeometry.fromWkt('Polygon((0 0, 1 0.1, 1 1, 0 1, 0 0))').densifyByCount(5).isAxisParallelRectangle(10)) + QgsGeometry.fromWkt( + "Polygon((0 0, 1 0.1, 1 1, 0 1, 0 0))" + ).isAxisParallelRectangle(10) + ) + self.assertTrue( + QgsGeometry.fromWkt("Polygon((0 0, 1 0.1, 1 1, 0 1, 0 0))") + .densifyByCount(5) + .isAxisParallelRectangle(10) + ) def testTransformWithClass(self): """ @@ -7371,17 +13187,17 @@ def transformPoint(self, x, y, z, m): return True, x * 2, y + 1, z, m transformer = Transformer() - g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 0, 10 10)") self.assertTrue(g.get().transform(transformer)) - self.assertEqual(g.asWkt(0), 'LineString (0 1, 20 1, 20 11)') + self.assertEqual(g.asWkt(0), "LineString (0 1, 20 1, 20 11)") @unittest.skipIf(Qgis.geosVersionInt() < 30900, "GEOS 3.9 required") def testFrechetDistance(self): """ Test QgsGeometry.frechetDistance """ - l1 = QgsGeometry.fromWkt('LINESTRING (0 0, 100 0)') - l2 = QgsGeometry.fromWkt('LINESTRING (0 0, 50 50, 100 0)') + l1 = QgsGeometry.fromWkt("LINESTRING (0 0, 100 0)") + l2 = QgsGeometry.fromWkt("LINESTRING (0 0, 50 50, 100 0)") self.assertAlmostEqual(l1.frechetDistance(l2), 70.711, 3) self.assertAlmostEqual(l2.frechetDistance(l1), 70.711, 3) @@ -7390,8 +13206,8 @@ def testFrechetDistanceDensify(self): """ Test QgsGeometry.frechetDistanceDensify """ - l1 = QgsGeometry.fromWkt('LINESTRING (0 0, 100 0)') - l2 = QgsGeometry.fromWkt('LINESTRING (0 0, 50 50, 100 0)') + l1 = QgsGeometry.fromWkt("LINESTRING (0 0, 100 0)") + l2 = QgsGeometry.fromWkt("LINESTRING (0 0, 50 50, 100 0)") self.assertAlmostEqual(l1.frechetDistanceDensify(l2, 0.5), 50.000, 3) self.assertAlmostEqual(l2.frechetDistanceDensify(l1, 0.5), 50.000, 3) @@ -7400,19 +13216,26 @@ def testLargestEmptyCircle(self): """ Test QgsGeometry.largestEmptyCircle """ - g1 = QgsGeometry.fromWkt('POLYGON ((50 50, 150 50, 150 150, 50 150, 50 50))') - self.assertEqual(g1.largestEmptyCircle(1).asWkt(), 'LineString (100 100, 100 50)') - self.assertEqual(g1.largestEmptyCircle(0.1).asWkt(), 'LineString (100 100, 100 50)') + g1 = QgsGeometry.fromWkt("POLYGON ((50 50, 150 50, 150 150, 50 150, 50 50))") + self.assertEqual( + g1.largestEmptyCircle(1).asWkt(), "LineString (100 100, 100 50)" + ) + self.assertEqual( + g1.largestEmptyCircle(0.1).asWkt(), "LineString (100 100, 100 50)" + ) g2 = QgsGeometry.fromWkt( - 'MultiPolygon (((95.03667481662591854 163.45354523227382515, 95.03667481662591854 122.0354523227383936, 34.10757946210270575 122.0354523227383936, 34.10757946210270575 163.45354523227382515, 95.03667481662591854 163.45354523227382515)),((35.64792176039119198 76.3386308068459698, 94.52322738386308743 76.3386308068459698, 94.52322738386308743 41.25305623471882654, 35.64792176039119198 41.25305623471882654, 35.64792176039119198 76.3386308068459698)),((185.23227383863081741 108.34352078239608375, 185.23227383863081741 78.56356968215158076, 118.99755501222495013 78.56356968215158076, 118.99755501222495013 108.34352078239608375, 185.23227383863081741 108.34352078239608375)))') - self.assertEqual(g2.largestEmptyCircle(0.1).asWkt(1), 'LineString (129.3 142.5, 129.3 108.3)') + "MultiPolygon (((95.03667481662591854 163.45354523227382515, 95.03667481662591854 122.0354523227383936, 34.10757946210270575 122.0354523227383936, 34.10757946210270575 163.45354523227382515, 95.03667481662591854 163.45354523227382515)),((35.64792176039119198 76.3386308068459698, 94.52322738386308743 76.3386308068459698, 94.52322738386308743 41.25305623471882654, 35.64792176039119198 41.25305623471882654, 35.64792176039119198 76.3386308068459698)),((185.23227383863081741 108.34352078239608375, 185.23227383863081741 78.56356968215158076, 118.99755501222495013 78.56356968215158076, 118.99755501222495013 108.34352078239608375, 185.23227383863081741 108.34352078239608375)))" + ) + self.assertEqual( + g2.largestEmptyCircle(0.1).asWkt(1), "LineString (129.3 142.5, 129.3 108.3)" + ) @unittest.skipIf(Qgis.geosVersionInt() < 30600, "GEOS 3.6 required") def testMinimumClearance(self): """ Test QgsGeometry.minimumClearance """ - l1 = QgsGeometry.fromWkt('POLYGON ((0 0, 1 0, 1 1, 0.5 3.2e-4, 0 0))') + l1 = QgsGeometry.fromWkt("POLYGON ((0 0, 1 0, 1 1, 0.5 3.2e-4, 0 0))") self.assertAlmostEqual(l1.minimumClearance(), 0.00032, 5) @unittest.skipIf(Qgis.geosVersionInt() < 30600, "GEOS 3.6 required") @@ -7420,42 +13243,58 @@ def testMinimumClearanceLine(self): """ Test QgsGeometry.minimumClearanceLine """ - l1 = QgsGeometry.fromWkt('POLYGON ((0 0, 1 0, 1 1, 0.5 3.2e-4, 0 0))') - self.assertEqual(l1.minimumClearanceLine().asWkt(6), 'LineString (0.5 0.00032, 0.5 0)') + l1 = QgsGeometry.fromWkt("POLYGON ((0 0, 1 0, 1 1, 0.5 3.2e-4, 0 0))") + self.assertEqual( + l1.minimumClearanceLine().asWkt(6), "LineString (0.5 0.00032, 0.5 0)" + ) @unittest.skipIf(Qgis.geosVersionInt() < 30600, "GEOS 3.6 required") def testMinimumWidth(self): """ Test QgsGeometry.minimumWidth """ - l1 = QgsGeometry.fromWkt('POLYGON ((0 0, 1 0, 1 1, 0.5 3.2e-4, 0 0))') - self.assertEqual(l1.minimumWidth().asWkt(6), 'LineString (0.5 0.5, 1 0)') + l1 = QgsGeometry.fromWkt("POLYGON ((0 0, 1 0, 1 1, 0.5 3.2e-4, 0 0))") + self.assertEqual(l1.minimumWidth().asWkt(6), "LineString (0.5 0.5, 1 0)") def testNode(self): """ Test QgsGeometry.node """ - l1 = QgsGeometry.fromWkt('LINESTRINGZ(0 0 0, 10 10 10, 0 10 5, 10 0 3)') - self.assertEqual(l1.node().asWkt(6), - 'MultiLineString Z ((0 0 0, 5 5 4.5),(5 5 4.5, 10 10 10, 0 10 5, 5 5 4.5),(5 5 4.5, 10 0 3))') - l1 = QgsGeometry.fromWkt('MULTILINESTRING ((2 5, 2 1, 7 1), (6 1, 4 1, 2 3, 2 5))') - self.assertEqual(l1.node().asWkt(6), - 'MultiLineString ((2 5, 2 3),(2 3, 2 1, 4 1),(4 1, 6 1),(6 1, 7 1),(4 1, 2 3))') + l1 = QgsGeometry.fromWkt("LINESTRINGZ(0 0 0, 10 10 10, 0 10 5, 10 0 3)") + self.assertEqual( + l1.node().asWkt(6), + "MultiLineString Z ((0 0 0, 5 5 4.5),(5 5 4.5, 10 10 10, 0 10 5, 5 5 4.5),(5 5 4.5, 10 0 3))", + ) + l1 = QgsGeometry.fromWkt( + "MULTILINESTRING ((2 5, 2 1, 7 1), (6 1, 4 1, 2 3, 2 5))" + ) + self.assertEqual( + l1.node().asWkt(6), + "MultiLineString ((2 5, 2 3),(2 3, 2 1, 4 1),(4 1, 6 1),(6 1, 7 1),(4 1, 2 3))", + ) def testSharedPaths(self): """ Test QgsGeometry.sharedPaths """ l1 = QgsGeometry.fromWkt( - 'MULTILINESTRING((26 125,26 200,126 200,126 125,26 125),(51 150,101 150,76 175,51 150))') - l2 = QgsGeometry.fromWkt('LINESTRING(151 100,126 156.25,126 125,90 161, 76 175)') - self.assertEqual(l1.sharedPaths(l2).asWkt(6), - 'GeometryCollection (MultiLineString ((126 156.25, 126 125),(101 150, 90 161),(90 161, 76 175)),MultiLineString EMPTY)') - l1 = QgsGeometry.fromWkt('LINESTRING(76 175,90 161,126 125,126 156.25,151 100)') + "MULTILINESTRING((26 125,26 200,126 200,126 125,26 125),(51 150,101 150,76 175,51 150))" + ) + l2 = QgsGeometry.fromWkt( + "LINESTRING(151 100,126 156.25,126 125,90 161, 76 175)" + ) + self.assertEqual( + l1.sharedPaths(l2).asWkt(6), + "GeometryCollection (MultiLineString ((126 156.25, 126 125),(101 150, 90 161),(90 161, 76 175)),MultiLineString EMPTY)", + ) + l1 = QgsGeometry.fromWkt("LINESTRING(76 175,90 161,126 125,126 156.25,151 100)") l2 = QgsGeometry.fromWkt( - 'MULTILINESTRING((26 125,26 200,126 200,126 125,26 125),(51 150,101 150,76 175,51 150))') - self.assertEqual(l1.sharedPaths(l2).asWkt(6), - 'GeometryCollection (MultiLineString EMPTY,MultiLineString ((76 175, 90 161),(90 161, 101 150),(126 125, 126 156.25)))') + "MULTILINESTRING((26 125,26 200,126 200,126 125,26 125),(51 150,101 150,76 175,51 150))" + ) + self.assertEqual( + l1.sharedPaths(l2).asWkt(6), + "GeometryCollection (MultiLineString EMPTY,MultiLineString ((76 175, 90 161),(90 161, 101 150),(126 125, 126 156.25)))", + ) def renderGeometry(self, geom, use_pen, as_polygon=False, as_painter_path=False): image = QImage(200, 200, QImage.Format.Format_RGB32) @@ -7480,160 +13319,250 @@ def renderGeometry(self, geom, use_pen, as_polygon=False, as_painter_path=False) return image def testGeometryDraw(self): - '''Tests drawing geometries''' - - tests = [{'name': 'Point', - 'wkt': 'Point (40 60)', - 'reference_image': 'point', - 'use_pen': False}, - {'name': 'LineString', - 'wkt': 'LineString (20 30, 50 30, 50 90)', - 'reference_image': 'linestring', - 'as_polygon_reference_image': 'linestring_aspolygon', - 'use_pen': True}, - {'name': 'CircularString', - 'wkt': 'CircularString (20 30, 50 30, 50 90)', - 'reference_image': 'circularstring', - 'as_polygon_reference_image': 'circularstring_aspolygon', - 'use_pen': True}, - {'name': 'CurvePolygon', - 'wkt': 'CurvePolygon(CircularString (20 30, 50 30, 50 90, 10 50, 20 30))', - 'reference_image': 'curvepolygon_circularstring', - 'use_pen': False}, - {'name': 'CurvePolygonInteriorRings', - 'wkt': 'CurvePolygon(CircularString (20 30, 50 30, 50 90, 10 50, 20 30),LineString(30 45, 55 45, 30 75, 30 45))', - 'reference_image': 'curvepolygon_circularstring_interiorrings', - 'use_pen': False}, - {'name': 'CompoundCurve', - 'wkt': 'CompoundCurve(CircularString (20 30, 50 30, 50 90),LineString(50 90, 10 90))', - 'reference_image': 'compoundcurve', - 'use_pen': True, - 'as_polygon_reference_image': 'compoundcurve_aspolygon'}, - {'name': 'GeometryCollection', - 'wkt': 'GeometryCollection(LineString (20 30, 50 30, 50 70),LineString(10 90, 90 90))', - 'reference_image': 'geometrycollection', - 'use_pen': True} - ] + """Tests drawing geometries""" + + tests = [ + { + "name": "Point", + "wkt": "Point (40 60)", + "reference_image": "point", + "use_pen": False, + }, + { + "name": "LineString", + "wkt": "LineString (20 30, 50 30, 50 90)", + "reference_image": "linestring", + "as_polygon_reference_image": "linestring_aspolygon", + "use_pen": True, + }, + { + "name": "CircularString", + "wkt": "CircularString (20 30, 50 30, 50 90)", + "reference_image": "circularstring", + "as_polygon_reference_image": "circularstring_aspolygon", + "use_pen": True, + }, + { + "name": "CurvePolygon", + "wkt": "CurvePolygon(CircularString (20 30, 50 30, 50 90, 10 50, 20 30))", + "reference_image": "curvepolygon_circularstring", + "use_pen": False, + }, + { + "name": "CurvePolygonInteriorRings", + "wkt": "CurvePolygon(CircularString (20 30, 50 30, 50 90, 10 50, 20 30),LineString(30 45, 55 45, 30 75, 30 45))", + "reference_image": "curvepolygon_circularstring_interiorrings", + "use_pen": False, + }, + { + "name": "CompoundCurve", + "wkt": "CompoundCurve(CircularString (20 30, 50 30, 50 90),LineString(50 90, 10 90))", + "reference_image": "compoundcurve", + "use_pen": True, + "as_polygon_reference_image": "compoundcurve_aspolygon", + }, + { + "name": "GeometryCollection", + "wkt": "GeometryCollection(LineString (20 30, 50 30, 50 70),LineString(10 90, 90 90))", + "reference_image": "geometrycollection", + "use_pen": True, + }, + ] for test in tests: - geom = QgsGeometry.fromWkt(test['wkt']) - self.assertTrue(geom and not geom.isNull(), f"Could not create geometry {test['wkt']}") - rendered_image = self.renderGeometry(geom, test['use_pen']) + geom = QgsGeometry.fromWkt(test["wkt"]) + self.assertTrue( + geom and not geom.isNull(), f"Could not create geometry {test['wkt']}" + ) + rendered_image = self.renderGeometry(geom, test["use_pen"]) self.assertTrue( - self.image_check(test['name'], test['reference_image'], rendered_image, - control_path_prefix="geometry"), test['name']) + self.image_check( + test["name"], + test["reference_image"], + rendered_image, + control_path_prefix="geometry", + ), + test["name"], + ) - if hasattr(geom.constGet(), 'addToPainterPath'): + if hasattr(geom.constGet(), "addToPainterPath"): # also check using painter path - rendered_image = self.renderGeometry(geom, test['use_pen'], as_painter_path=True) + rendered_image = self.renderGeometry( + geom, test["use_pen"], as_painter_path=True + ) self.assertTrue( - self.image_check(test['name'], test['reference_image'], rendered_image, - control_path_prefix="geometry") + self.image_check( + test["name"], + test["reference_image"], + rendered_image, + control_path_prefix="geometry", + ) ) - if 'as_polygon_reference_image' in test: + if "as_polygon_reference_image" in test: rendered_image = self.renderGeometry(geom, False, True) self.assertTrue( - self.image_check(test['name'] + '_aspolygon', test['as_polygon_reference_image'], rendered_image, - control_path_prefix="geometry") + self.image_check( + test["name"] + "_aspolygon", + test["as_polygon_reference_image"], + rendered_image, + control_path_prefix="geometry", + ) ) def testGeometryAsQPainterPath(self): - '''Tests conversion of different geometries to QPainterPath, including bad/odd geometries.''' + """Tests conversion of different geometries to QPainterPath, including bad/odd geometries.""" empty_multipolygon = QgsMultiPolygon() empty_multipolygon.addGeometry(QgsPolygon()) empty_polygon = QgsPolygon() empty_linestring = QgsLineString() - tests = [{'name': 'LineString', - 'wkt': 'LineString (0 0,3 4,4 3)', - 'reference_image': 'linestring'}, - {'name': 'Empty LineString', - 'geom': QgsGeometry(empty_linestring), - 'reference_image': 'empty'}, - {'name': 'MultiLineString', - 'wkt': 'MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0), (3 1, 5 1, 5 0, 6 0))', - 'reference_image': 'multilinestring'}, - {'name': 'Polygon', - 'wkt': 'Polygon ((0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5))', - 'reference_image': 'polygon'}, - {'name': 'Empty Polygon', - 'geom': QgsGeometry(empty_polygon), - 'reference_image': 'empty'}, - {'name': 'MultiPolygon', - 'wkt': 'MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))', - 'reference_image': 'multipolygon'}, - {'name': 'Empty MultiPolygon', - 'geom': QgsGeometry(empty_multipolygon), - 'reference_image': 'empty'}, - {'name': 'CircularString', - 'wkt': 'CIRCULARSTRING(268 415,227 505,227 406)', - 'reference_image': 'circular_string'}, - {'name': 'CompoundCurve', - 'wkt': 'COMPOUNDCURVE((5 3, 5 13), CIRCULARSTRING(5 13, 7 15, 9 13), (9 13, 9 3), CIRCULARSTRING(9 3, 7 1, 5 3))', - 'reference_image': 'compound_curve'}, - {'name': 'CurvePolygon', - 'wkt': 'CURVEPOLYGON(CIRCULARSTRING(1 3, 3 5, 4 7, 7 3, 1 3))', - 'reference_image': 'curve_polygon'}, - {'name': 'MultiCurve', - 'wkt': 'MultiCurve((5 5,3 5,3 3,0 3),CIRCULARSTRING(0 0, 2 1,2 2))', - 'reference_image': 'multicurve'}, - {'name': 'CurvePolygon_no_arc', # refs #14028 - 'wkt': 'CURVEPOLYGON(LINESTRING(1 3, 3 5, 4 7, 7 3, 1 3))', - 'reference_image': 'curve_polygon_no_arc'}, - {'name': 'CurvePolygonInteriorRings', - 'wkt': 'CurvePolygon(CircularString (20 30, 50 30, 50 90, 10 50, 20 30),LineString(30 45, 55 45, 30 75, 30 45))', - 'reference_image': 'curvepolygon_circularstring_interiorrings'}, - {'name': 'CompoundCurve With Line', - 'wkt': 'CompoundCurve(CircularString (20 30, 50 30, 50 90),LineString(50 90, 10 90))', - 'reference_image': 'compoundcurve_with_line'}, - {'name': 'Collection LineString', - 'wkt': 'GeometryCollection( LineString (0 0,3 4,4 3) )', - 'reference_image': 'collection_linestring'}, - {'name': 'Collection MultiLineString', - 'wkt': 'GeometryCollection (LineString(0 0, 1 0, 1 1, 2 1, 2 0), LineString(3 1, 5 1, 5 0, 6 0))', - 'reference_image': 'collection_multilinestring'}, - {'name': 'Collection Polygon', - 'wkt': 'GeometryCollection(Polygon ((0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5)))', - 'reference_image': 'collection_polygon'}, - {'name': 'Collection MultiPolygon', - 'wkt': 'GeometryCollection( Polygon((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),Polygon((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))', - 'reference_image': 'collection_multipolygon'}, - {'name': 'Collection CircularString', - 'wkt': 'GeometryCollection(CIRCULARSTRING(268 415,227 505,227 406))', - 'reference_image': 'collection_circular_string'}, - {'name': 'Collection CompoundCurve', - 'wkt': 'GeometryCollection(COMPOUNDCURVE((5 3, 5 13), CIRCULARSTRING(5 13, 7 15, 9 13), (9 13, 9 3), CIRCULARSTRING(9 3, 7 1, 5 3)))', - 'reference_image': 'collection_compound_curve'}, - {'name': 'Collection CurvePolygon', - 'wkt': 'GeometryCollection(CURVEPOLYGON(CIRCULARSTRING(1 3, 3 5, 4 7, 7 3, 1 3)))', - 'reference_image': 'collection_curve_polygon'}, - {'name': 'Collection CurvePolygon_no_arc', # refs #14028 - 'wkt': 'GeometryCollection(CURVEPOLYGON(LINESTRING(1 3, 3 5, 4 7, 7 3, 1 3)))', - 'reference_image': 'collection_curve_polygon_no_arc'}, - {'name': 'Collection Mixed', - 'wkt': 'GeometryCollection(Point(1 2), MultiPoint(3 3, 2 3), LineString (0 0,3 4,4 3), MultiLineString((3 1, 3 2, 4 2)), Polygon((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)), MultiPolygon(((4 0, 5 0, 5 1, 6 1, 6 2, 4 2, 4 0)),(( 1 4, 2 4, 1 5, 1 4))))', - 'reference_image': 'collection_mixed'}, - {'name': 'MultiCurvePolygon', - 'wkt': 'MultiSurface (CurvePolygon (CompoundCurve (CircularString (-12942312 4593500, -11871048 5481118, -11363838 5065730, -11551856 4038191, -12133399 4130014),(-12133399 4130014, -12942312 4593500)),(-12120281 5175043, -12456964 4694067, -11752991 4256817, -11569346 4943300, -12120281 5175043)),Polygon ((-10856627 5625411, -11083997 4995770, -10887235 4357384, -9684796 4851477, -10069576 5428648, -10856627 5625411)))', - 'reference_image': 'multicurvepolygon_with_rings'} - ] + tests = [ + { + "name": "LineString", + "wkt": "LineString (0 0,3 4,4 3)", + "reference_image": "linestring", + }, + { + "name": "Empty LineString", + "geom": QgsGeometry(empty_linestring), + "reference_image": "empty", + }, + { + "name": "MultiLineString", + "wkt": "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0), (3 1, 5 1, 5 0, 6 0))", + "reference_image": "multilinestring", + }, + { + "name": "Polygon", + "wkt": "Polygon ((0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5))", + "reference_image": "polygon", + }, + { + "name": "Empty Polygon", + "geom": QgsGeometry(empty_polygon), + "reference_image": "empty", + }, + { + "name": "MultiPolygon", + "wkt": "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))", + "reference_image": "multipolygon", + }, + { + "name": "Empty MultiPolygon", + "geom": QgsGeometry(empty_multipolygon), + "reference_image": "empty", + }, + { + "name": "CircularString", + "wkt": "CIRCULARSTRING(268 415,227 505,227 406)", + "reference_image": "circular_string", + }, + { + "name": "CompoundCurve", + "wkt": "COMPOUNDCURVE((5 3, 5 13), CIRCULARSTRING(5 13, 7 15, 9 13), (9 13, 9 3), CIRCULARSTRING(9 3, 7 1, 5 3))", + "reference_image": "compound_curve", + }, + { + "name": "CurvePolygon", + "wkt": "CURVEPOLYGON(CIRCULARSTRING(1 3, 3 5, 4 7, 7 3, 1 3))", + "reference_image": "curve_polygon", + }, + { + "name": "MultiCurve", + "wkt": "MultiCurve((5 5,3 5,3 3,0 3),CIRCULARSTRING(0 0, 2 1,2 2))", + "reference_image": "multicurve", + }, + { + "name": "CurvePolygon_no_arc", # refs #14028 + "wkt": "CURVEPOLYGON(LINESTRING(1 3, 3 5, 4 7, 7 3, 1 3))", + "reference_image": "curve_polygon_no_arc", + }, + { + "name": "CurvePolygonInteriorRings", + "wkt": "CurvePolygon(CircularString (20 30, 50 30, 50 90, 10 50, 20 30),LineString(30 45, 55 45, 30 75, 30 45))", + "reference_image": "curvepolygon_circularstring_interiorrings", + }, + { + "name": "CompoundCurve With Line", + "wkt": "CompoundCurve(CircularString (20 30, 50 30, 50 90),LineString(50 90, 10 90))", + "reference_image": "compoundcurve_with_line", + }, + { + "name": "Collection LineString", + "wkt": "GeometryCollection( LineString (0 0,3 4,4 3) )", + "reference_image": "collection_linestring", + }, + { + "name": "Collection MultiLineString", + "wkt": "GeometryCollection (LineString(0 0, 1 0, 1 1, 2 1, 2 0), LineString(3 1, 5 1, 5 0, 6 0))", + "reference_image": "collection_multilinestring", + }, + { + "name": "Collection Polygon", + "wkt": "GeometryCollection(Polygon ((0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5)))", + "reference_image": "collection_polygon", + }, + { + "name": "Collection MultiPolygon", + "wkt": "GeometryCollection( Polygon((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),Polygon((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))", + "reference_image": "collection_multipolygon", + }, + { + "name": "Collection CircularString", + "wkt": "GeometryCollection(CIRCULARSTRING(268 415,227 505,227 406))", + "reference_image": "collection_circular_string", + }, + { + "name": "Collection CompoundCurve", + "wkt": "GeometryCollection(COMPOUNDCURVE((5 3, 5 13), CIRCULARSTRING(5 13, 7 15, 9 13), (9 13, 9 3), CIRCULARSTRING(9 3, 7 1, 5 3)))", + "reference_image": "collection_compound_curve", + }, + { + "name": "Collection CurvePolygon", + "wkt": "GeometryCollection(CURVEPOLYGON(CIRCULARSTRING(1 3, 3 5, 4 7, 7 3, 1 3)))", + "reference_image": "collection_curve_polygon", + }, + { + "name": "Collection CurvePolygon_no_arc", # refs #14028 + "wkt": "GeometryCollection(CURVEPOLYGON(LINESTRING(1 3, 3 5, 4 7, 7 3, 1 3)))", + "reference_image": "collection_curve_polygon_no_arc", + }, + { + "name": "Collection Mixed", + "wkt": "GeometryCollection(Point(1 2), MultiPoint(3 3, 2 3), LineString (0 0,3 4,4 3), MultiLineString((3 1, 3 2, 4 2)), Polygon((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)), MultiPolygon(((4 0, 5 0, 5 1, 6 1, 6 2, 4 2, 4 0)),(( 1 4, 2 4, 1 5, 1 4))))", + "reference_image": "collection_mixed", + }, + { + "name": "MultiCurvePolygon", + "wkt": "MultiSurface (CurvePolygon (CompoundCurve (CircularString (-12942312 4593500, -11871048 5481118, -11363838 5065730, -11551856 4038191, -12133399 4130014),(-12133399 4130014, -12942312 4593500)),(-12120281 5175043, -12456964 4694067, -11752991 4256817, -11569346 4943300, -12120281 5175043)),Polygon ((-10856627 5625411, -11083997 4995770, -10887235 4357384, -9684796 4851477, -10069576 5428648, -10856627 5625411)))", + "reference_image": "multicurvepolygon_with_rings", + }, + ] for test in tests: def get_geom(): - if 'geom' not in test: - geom = QgsGeometry.fromWkt(test['wkt']) - assert geom and not geom.isNull(), f"Could not create geometry {test['wkt']}" + if "geom" not in test: + geom = QgsGeometry.fromWkt(test["wkt"]) + assert ( + geom and not geom.isNull() + ), f"Could not create geometry {test['wkt']}" else: - geom = test['geom'] + geom = test["geom"] return geom geom = get_geom() rendered_image = self.renderGeometryUsingPath(geom) self.assertTrue( - self.image_check(test['name'], test['reference_image'], rendered_image, control_path_prefix="geometry_path"), - test['name']) + self.image_check( + test["name"], + test["reference_image"], + rendered_image, + control_path_prefix="geometry_path", + ), + test["name"], + ) # Note - each test is repeated with the same geometry and reference image, but with added # z and m dimensions. This tests that presence of the dimensions does not affect rendering @@ -7642,21 +13571,39 @@ def get_geom(): geom_z = get_geom() geom_z.get().addZValue(5) rendered_image = self.renderGeometryUsingPath(geom_z) - self.assertTrue(self.image_check(test['name'] + 'Z', test['reference_image'], rendered_image, - control_path_prefix="geometry_path")) + self.assertTrue( + self.image_check( + test["name"] + "Z", + test["reference_image"], + rendered_image, + control_path_prefix="geometry_path", + ) + ) # test with ZM geom_z.get().addMValue(15) rendered_image = self.renderGeometryUsingPath(geom_z) - self.assertTrue(self.image_check(test['name'] + 'ZM', test['reference_image'], rendered_image, - control_path_prefix="geometry_path")) + self.assertTrue( + self.image_check( + test["name"] + "ZM", + test["reference_image"], + rendered_image, + control_path_prefix="geometry_path", + ) + ) # test with M geom_m = get_geom() geom_m.get().addMValue(15) rendered_image = self.renderGeometryUsingPath(geom_m) - self.assertTrue(self.image_check(test['name'] + 'M', test['reference_image'], rendered_image, - control_path_prefix="geometry_path")) + self.assertTrue( + self.image_check( + test["name"] + "M", + test["reference_image"], + rendered_image, + control_path_prefix="geometry_path", + ) + ) def renderGeometryUsingPath(self, geom): image = QImage(200, 200, QImage.Format.Format_RGB32) @@ -7666,7 +13613,10 @@ def renderGeometryUsingPath(self, geom): src_bounds = geom.buffer(geom.boundingBox().width() / 10, 5).boundingBox() if src_bounds.width() and src_bounds.height(): - scale = min(dest_bounds.width() / src_bounds.width(), dest_bounds.height() / src_bounds.height()) + scale = min( + dest_bounds.width() / src_bounds.width(), + dest_bounds.height() / src_bounds.height(), + ) t = QTransform.fromScale(scale, -scale) geom.transform(t) @@ -7693,40 +13643,47 @@ def renderGeometryUsingPath(self, geom): return image def testFixedPrecision(self): - a = QgsGeometry.fromWkt('LINESTRING(0 0, 9 0)') - b = QgsGeometry.fromWkt('LINESTRING(7 0, 13.2 0)') + a = QgsGeometry.fromWkt("LINESTRING(0 0, 9 0)") + b = QgsGeometry.fromWkt("LINESTRING(7 0, 13.2 0)") geom_params = QgsGeometryParameters() geom_params.setGridSize(2) # Intersection, gridSize = 2 intersectionExpected = a.intersection(b, geom_params) - self.assertEqual(intersectionExpected.asWkt(), 'LineString (8 0, 10 0)') + self.assertEqual(intersectionExpected.asWkt(), "LineString (8 0, 10 0)") # Difference, gridSize = 2 differenceExpected = a.difference(b, geom_params) - self.assertEqual(differenceExpected.asWkt(), 'LineString (0 0, 8 0)') + self.assertEqual(differenceExpected.asWkt(), "LineString (0 0, 8 0)") # symDifference, gridSize = 2 symDifferenceExpected = a.symDifference(b, geom_params) - self.assertEqual(symDifferenceExpected.asWkt(), 'MultiLineString ((0 0, 8 0),(10 0, 14 0))') + self.assertEqual( + symDifferenceExpected.asWkt(), "MultiLineString ((0 0, 8 0),(10 0, 14 0))" + ) # For union, add a tiny float offset to the first vertex - a = QgsGeometry.fromWkt('LINESTRING(0.5 0, 9 0)') + a = QgsGeometry.fromWkt("LINESTRING(0.5 0, 9 0)") # union, gridSize = 2 combineExpected = a.combine(b, geom_params) - self.assertEqual(combineExpected.asWkt(), 'LineString (0 0, 8 0, 10 0, 14 0)') + self.assertEqual(combineExpected.asWkt(), "LineString (0 0, 8 0, 10 0, 14 0)") # Subdivide, gridSize = 1 geom_params.setGridSize(1) - a = QgsGeometry.fromWkt('POLYGON((0 0,0 10,10 10,10 6,100 5.1, 100 10, 110 10, 110 0, 100 0,100 4.9,10 5,10 0,0 0))') + a = QgsGeometry.fromWkt( + "POLYGON((0 0,0 10,10 10,10 6,100 5.1, 100 10, 110 10, 110 0, 100 0,100 4.9,10 5,10 0,0 0))" + ) subdivideExpected = a.subdivide(6, geom_params) - self.assertEqual(subdivideExpected.asWkt(), 'MultiPolygon (((0 10, 7 10, 7 0, 0 0, 0 10)),((10 0, 7 0, 7 5, 10 5, 10 0)),((10 10, 10 6, 10 5, 7 5, 7 10, 10 10)),((14 6, 14 5, 10 5, 10 6, 14 6)),((28 6, 28 5, 14 5, 14 6, 28 6)),((55 6, 55 5, 28 5, 28 6, 55 6)),((100 5, 55 5, 55 6, 100 5)),((100 10, 110 10, 110 0, 100 0, 100 5, 100 10)))') + self.assertEqual( + subdivideExpected.asWkt(), + "MultiPolygon (((0 10, 7 10, 7 0, 0 0, 0 10)),((10 0, 7 0, 7 5, 10 5, 10 0)),((10 10, 10 6, 10 5, 7 5, 7 10, 10 10)),((14 6, 14 5, 10 5, 10 6, 14 6)),((28 6, 28 5, 14 5, 14 6, 28 6)),((55 6, 55 5, 28 5, 28 6, 55 6)),((100 5, 55 5, 55 6, 100 5)),((100 10, 110 10, 110 0, 100 0, 100 5, 100 10)))", + ) def testIntersectsMultiPolygonEmptyRect(self): """Test intersection between a polygon and an empty rectangle. Fix for GH #51492.""" - ''' ogr failing test + """ ogr failing test poly = ogr.CreateGeometryFromWkt('POLYGON((0 0, 0 2, 2 2, 2 0, 0 0))') multi_poly = ogr.CreateGeometryFromWkt('MULTIPOLYGON(((0 0, 0 2, 2 2, 2 0, 0 0)))') bbox = ogr.CreateGeometryFromWkt('POLYGON((1 1, 1 1, 1 1, 1 1, 1 1))') @@ -7735,10 +13692,10 @@ def testIntersectsMultiPolygonEmptyRect(self): assert poly.Intersects(bbox) assert multi_poly.Intersects(point) assert multi_poly.Intersects(bbox) ## << fails - ''' + """ - poly = QgsGeometry.fromWkt('MULTIPOLYGON(((0 0, 0 2, 2 2, 2 0, 0 0)))') - point = QgsGeometry.fromWkt('POINT(1 1)') + poly = QgsGeometry.fromWkt("MULTIPOLYGON(((0 0, 0 2, 2 2, 2 0, 0 0)))") + point = QgsGeometry.fromWkt("POINT(1 1)") bbox = point.boundingBox() self.assertEqual(bbox.area(), 0) @@ -7777,9 +13734,9 @@ def testSplitGeometry(self): result, parts, _ = multilinestring.splitGeometry(blade, False, False, False) self.assertEqual(result, Qgis.GeometryOperationResult.Success) self.assertEqual(len(parts), 3) - self.assertTrue(compareWkt(parts[0].asWkt(), 'MultiLineString ((0 2, 1 1))')) - self.assertTrue(compareWkt(parts[1].asWkt(), 'MultiLineString ((1 1, 2 0))')) - self.assertTrue(compareWkt(parts[2].asWkt(), 'MultiLineString ((0 1, 1 0))')) + self.assertTrue(compareWkt(parts[0].asWkt(), "MultiLineString ((0 2, 1 1))")) + self.assertTrue(compareWkt(parts[1].asWkt(), "MultiLineString ((1 1, 2 0))")) + self.assertTrue(compareWkt(parts[2].asWkt(), "MultiLineString ((0 1, 1 0))")) @unittest.skipIf(Qgis.geosVersionInt() < 31200, "GEOS 3.12 required") def testCoverageValidate(self): @@ -7791,20 +13748,27 @@ def testCoverageValidate(self): self.assertEqual(valid, Qgis.CoverageValidityResult.Error) self.assertFalse(edges) - g1 = QgsGeometry.fromWkt('Point(1 2)') + g1 = QgsGeometry.fromWkt("Point(1 2)") valid, edges = g1.validateCoverage(0) self.assertEqual(valid, Qgis.CoverageValidityResult.Error) self.assertFalse(edges) - g1 = QgsGeometry.fromWkt('MULTIPOLYGON(((0 0,10 0,10.1 5,10 10,0 10,0 0)), ((10 0,20 0,20 10,10 10,10.1 5,10 0)))') + g1 = QgsGeometry.fromWkt( + "MULTIPOLYGON(((0 0,10 0,10.1 5,10 10,0 10,0 0)), ((10 0,20 0,20 10,10 10,10.1 5,10 0)))" + ) valid, edges = g1.validateCoverage(0) self.assertEqual(valid, Qgis.CoverageValidityResult.Valid) self.assertFalse(edges) - g1 = QgsGeometry.fromWkt('MULTIPOLYGON(((0 0,10 0,10.1 5,10 10,0 10,0 0)), ((9 0,20 0,20 10,10 10,10.1 5,9 0)))') + g1 = QgsGeometry.fromWkt( + "MULTIPOLYGON(((0 0,10 0,10.1 5,10 10,0 10,0 0)), ((9 0,20 0,20 10,10 10,10.1 5,9 0)))" + ) valid, edges = g1.validateCoverage(0) self.assertEqual(valid, Qgis.CoverageValidityResult.Invalid) - self.assertEqual(edges.asWkt(0), 'GeometryCollection (LineString (0 0, 10 0, 10 5),LineString (10 5, 9 0, 20 0))') + self.assertEqual( + edges.asWkt(0), + "GeometryCollection (LineString (0 0, 10 0, 10 5),LineString (10 5, 9 0, 20 0))", + ) @unittest.skipIf(Qgis.geosVersionInt() < 31200, "GEOS 3.12 required") def testCoverageDissolve(self): @@ -7815,13 +13779,17 @@ def testCoverageDissolve(self): res = g1.unionCoverage() self.assertTrue(res.isNull()) - g1 = QgsGeometry.fromWkt('Point(1 2)') + g1 = QgsGeometry.fromWkt("Point(1 2)") res = g1.unionCoverage() self.assertTrue(res.isNull()) - g1 = QgsGeometry.fromWkt('MULTIPOLYGON(((0 0,10 0,10.1 5,10 10,0 10,0 0)), ((10 0,20 0,20 10,10 10,10.1 5,10 0)))') + g1 = QgsGeometry.fromWkt( + "MULTIPOLYGON(((0 0,10 0,10.1 5,10 10,0 10,0 0)), ((10 0,20 0,20 10,10 10,10.1 5,10 0)))" + ) res = g1.unionCoverage() - self.assertEqual(res.asWkt(0), 'Polygon ((0 0, 0 10, 10 10, 20 10, 20 0, 10 0, 0 0))') + self.assertEqual( + res.asWkt(0), "Polygon ((0 0, 0 10, 10 10, 20 10, 20 0, 10 0, 0 0))" + ) @unittest.skipIf(Qgis.geosVersionInt() < 31200, "GEOS 3.12 required") def testCoverageSimplify(self): @@ -7832,19 +13800,30 @@ def testCoverageSimplify(self): res = g1.unionCoverage() self.assertTrue(res.isNull()) - g1 = QgsGeometry.fromWkt('Point(1 2)') + g1 = QgsGeometry.fromWkt("Point(1 2)") res = g1.simplifyCoverageVW(3, False) self.assertTrue(res.isNull()) - g1 = QgsGeometry.fromWkt('MULTIPOLYGON(((0 0,10 0,10.1 5,10 10,0 10,0 0)), ((10 0,20 0,20 10,10 10,10.1 5,10 0)))') + g1 = QgsGeometry.fromWkt( + "MULTIPOLYGON(((0 0,10 0,10.1 5,10 10,0 10,0 0)), ((10 0,20 0,20 10,10 10,10.1 5,10 0)))" + ) res = g1.simplifyCoverageVW(3, False) - self.assertEqual(res.asWkt(0), 'GeometryCollection (Polygon ((10 0, 10 10, 0 10, 0 0, 10 0)),Polygon ((10 0, 20 0, 20 10, 10 10, 10 0)))') + self.assertEqual( + res.asWkt(0), + "GeometryCollection (Polygon ((10 0, 10 10, 0 10, 0 0, 10 0)),Polygon ((10 0, 20 0, 20 10, 10 10, 10 0)))", + ) res = g1.simplifyCoverageVW(10, False) - self.assertEqual(res.asWkt(0), 'GeometryCollection (Polygon ((10 0, 10 10, 0 0, 10 0)),Polygon ((10 0, 20 10, 10 10, 10 0)))') + self.assertEqual( + res.asWkt(0), + "GeometryCollection (Polygon ((10 0, 10 10, 0 0, 10 0)),Polygon ((10 0, 20 10, 10 10, 10 0)))", + ) res = g1.simplifyCoverageVW(10, True) - self.assertEqual(res.asWkt(0), 'GeometryCollection (Polygon ((10 0, 10 10, 0 10, 0 0, 10 0)),Polygon ((10 0, 20 0, 20 10, 10 10, 10 0)))') + self.assertEqual( + res.asWkt(0), + "GeometryCollection (Polygon ((10 0, 10 10, 0 10, 0 0, 10 0)),Polygon ((10 0, 20 0, 20 10, 10 10, 10 0)))", + ) def testPolygonOrientation(self): """ @@ -7862,7 +13841,7 @@ def testPolygonOrientation(self): self.assertEqual(res_isCounterClockwise, False) # Not a polygon - geometry = QgsGeometry.fromWkt('Point(1 2)') + geometry = QgsGeometry.fromWkt("Point(1 2)") res_orientation = geometry.polygonOrientation() res_isClockwise = geometry.isPolygonClockwise() res_isCounterClockwise = geometry.isPolygonCounterClockwise() @@ -7872,7 +13851,7 @@ def testPolygonOrientation(self): self.assertEqual(res_isCounterClockwise, False) # Closed curve but not a polygon - geometry = QgsGeometry.fromWkt('LineString(0 0, 0 1, 1 1, 1 0, 0 0)') + geometry = QgsGeometry.fromWkt("LineString(0 0, 0 1, 1 1, 1 0, 0 0)") res_orientation = geometry.polygonOrientation() res_isClockwise = geometry.isPolygonClockwise() res_isCounterClockwise = geometry.isPolygonCounterClockwise() @@ -7882,7 +13861,7 @@ def testPolygonOrientation(self): self.assertEqual(res_isCounterClockwise, False) # Polygon Empty - geometry = QgsGeometry.fromWkt('Polygon EMPTY') + geometry = QgsGeometry.fromWkt("Polygon EMPTY") res_orientation = geometry.polygonOrientation() res_isClockwise = geometry.isPolygonClockwise() res_isCounterClockwise = geometry.isPolygonCounterClockwise() @@ -7892,7 +13871,7 @@ def testPolygonOrientation(self): self.assertEqual(res_isCounterClockwise, False) # Polygon Clockwise - geometry = QgsGeometry.fromWkt('Polygon((0 0, 0 1, 1 1, 1 0, 0 0))') + geometry = QgsGeometry.fromWkt("Polygon((0 0, 0 1, 1 1, 1 0, 0 0))") res_orientation = geometry.polygonOrientation() res_isClockwise = geometry.isPolygonClockwise() res_isCounterClockwise = geometry.isPolygonCounterClockwise() @@ -7902,7 +13881,7 @@ def testPolygonOrientation(self): self.assertEqual(res_isCounterClockwise, False) # Polygon CounterClockwise - geometry = QgsGeometry.fromWkt('Polygon((0 0, 1 0, 1 1, 0 1, 0 0))') + geometry = QgsGeometry.fromWkt("Polygon((0 0, 1 0, 1 1, 0 1, 0 0))") res_orientation = geometry.polygonOrientation() res_isClockwise = geometry.isPolygonClockwise() res_isCounterClockwise = geometry.isPolygonCounterClockwise() @@ -7912,7 +13891,7 @@ def testPolygonOrientation(self): self.assertEqual(res_isCounterClockwise, True) # MultiPolygon Empty - geometry = QgsGeometry.fromWkt('MultiPolygon EMPTY') + geometry = QgsGeometry.fromWkt("MultiPolygon EMPTY") res_orientation = geometry.polygonOrientation() res_isClockwise = geometry.isPolygonClockwise() res_isCounterClockwise = geometry.isPolygonCounterClockwise() @@ -7922,7 +13901,7 @@ def testPolygonOrientation(self): self.assertEqual(res_isCounterClockwise, False) # MultiPolygon Clockwise - geometry = QgsGeometry.fromWkt('MultiPolygon( ((0 0, 0 1, 1 1, 1 0, 0 0)) )') + geometry = QgsGeometry.fromWkt("MultiPolygon( ((0 0, 0 1, 1 1, 1 0, 0 0)) )") res_orientation = geometry.polygonOrientation() res_isClockwise = geometry.isPolygonClockwise() res_isCounterClockwise = geometry.isPolygonCounterClockwise() @@ -7932,7 +13911,9 @@ def testPolygonOrientation(self): self.assertEqual(res_isCounterClockwise, False) # MultiPolygon Clockwise with a CounterClockwise part - geometry = QgsGeometry.fromWkt('MultiPolygon( ((0 0, 0 1, 1 1, 1 0, 0 0)), ((4 4, 5 4, 5 5, 4 5, 4 4)) )') + geometry = QgsGeometry.fromWkt( + "MultiPolygon( ((0 0, 0 1, 1 1, 1 0, 0 0)), ((4 4, 5 4, 5 5, 4 5, 4 4)) )" + ) res_orientation = geometry.polygonOrientation() res_isClockwise = geometry.isPolygonClockwise() res_isCounterClockwise = geometry.isPolygonCounterClockwise() @@ -7942,7 +13923,7 @@ def testPolygonOrientation(self): self.assertEqual(res_isCounterClockwise, False) # MultiPolygon CounterClockwise - geometry = QgsGeometry.fromWkt('MultiPolygon( ((0 0, 1 0, 1 1, 0 1, 0 0)) )') + geometry = QgsGeometry.fromWkt("MultiPolygon( ((0 0, 1 0, 1 1, 0 1, 0 0)) )") res_orientation = geometry.polygonOrientation() res_isClockwise = geometry.isPolygonClockwise() res_isCounterClockwise = geometry.isPolygonCounterClockwise() @@ -7952,7 +13933,9 @@ def testPolygonOrientation(self): self.assertEqual(res_isCounterClockwise, True) # MultiPolygon CounterClockwise with a Clockwise part - geometry = QgsGeometry.fromWkt('MultiPolygon( ((0 0, 1 0, 1 1, 0 1, 0 0)), ((4 4, 4 5, 5 5, 5 4, 4 4)) ) ') + geometry = QgsGeometry.fromWkt( + "MultiPolygon( ((0 0, 1 0, 1 1, 0 1, 0 0)), ((4 4, 4 5, 5 5, 5 4, 4 4)) ) " + ) res_orientation = geometry.polygonOrientation() res_isClockwise = geometry.isPolygonClockwise() res_isCounterClockwise = geometry.isPolygonCounterClockwise() @@ -7969,7 +13952,7 @@ def testConstrainedDelaunayTriangulation(self): empty = QgsGeometry() o = empty.constrainedDelaunayTriangulation() self.assertFalse(o) - line = QgsGeometry.fromWkt('LineString EMPTY') + line = QgsGeometry.fromWkt("LineString EMPTY") o = line.constrainedDelaunayTriangulation() self.assertFalse(o) @@ -7978,12 +13961,13 @@ def testConstrainedDelaunayTriangulation(self): self.assertTrue(o.isNull()) input = QgsGeometry.fromWkt( - "POLYGON ((42 30, 41.96 29.61, 41.85 29.23, 41.66 28.89, 41.41 28.59, 41.11 28.34, 40.77 28.15, 40.39 28.04, 40 28, 39.61 28.04, 39.23 28.15, 38.89 28.34, 38.59 28.59, 38.34 28.89, 38.15 29.23, 38.04 29.61, 38 30, 38.04 30.39, 38.15 30.77, 38.34 31.11, 38.59 31.41, 38.89 31.66, 39.23 31.85, 39.61 31.96, 40 32, 40.39 31.96, 40.77 31.85, 41.11 31.66, 41.41 31.41, 41.66 31.11, 41.85 30.77, 41.96 30.39, 42 30))") + "POLYGON ((42 30, 41.96 29.61, 41.85 29.23, 41.66 28.89, 41.41 28.59, 41.11 28.34, 40.77 28.15, 40.39 28.04, 40 28, 39.61 28.04, 39.23 28.15, 38.89 28.34, 38.59 28.59, 38.34 28.89, 38.15 29.23, 38.04 29.61, 38 30, 38.04 30.39, 38.15 30.77, 38.34 31.11, 38.59 31.41, 38.89 31.66, 39.23 31.85, 39.61 31.96, 40 32, 40.39 31.96, 40.77 31.85, 41.11 31.66, 41.41 31.41, 41.66 31.11, 41.85 30.77, 41.96 30.39, 42 30))" + ) o = input.constrainedDelaunayTriangulation() o.normalize() self.assertEqual( o.asWkt(2), - "MultiPolygon (((41.96 29.61, 41.96 30.39, 42 30, 41.96 29.61)),((41.66 31.11, 41.85 30.77, 41.96 30.39, 41.66 31.11)),((41.66 28.89, 41.96 29.61, 41.85 29.23, 41.66 28.89)),((41.41 31.41, 41.96 30.39, 41.96 29.61, 41.41 31.41)),((41.41 31.41, 41.66 31.11, 41.96 30.39, 41.41 31.41)),((41.41 28.59, 41.96 29.61, 41.66 28.89, 41.41 28.59)),((41.41 28.59, 41.41 31.41, 41.96 29.61, 41.41 28.59)),((40.39 31.96, 41.11 31.66, 41.41 31.41, 40.39 31.96)),((40.39 31.96, 40.77 31.85, 41.11 31.66, 40.39 31.96)),((40.39 28.04, 41.41 28.59, 41.11 28.34, 40.39 28.04)),((40.39 28.04, 41.11 28.34, 40.77 28.15, 40.39 28.04)),((39.61 31.96, 40.39 31.96, 41.41 31.41, 39.61 31.96)),((39.61 31.96, 40 32, 40.39 31.96, 39.61 31.96)),((39.61 28.04, 40.39 28.04, 40 28, 39.61 28.04)),((38.89 31.66, 39.23 31.85, 39.61 31.96, 38.89 31.66)),((38.89 28.34, 39.61 28.04, 39.23 28.15, 38.89 28.34)),((38.59 31.41, 41.41 31.41, 41.41 28.59, 38.59 31.41)),((38.59 31.41, 39.61 31.96, 41.41 31.41, 38.59 31.41)),((38.59 31.41, 38.89 31.66, 39.61 31.96, 38.59 31.41)),((38.59 28.59, 41.41 28.59, 40.39 28.04, 38.59 28.59)),((38.59 28.59, 40.39 28.04, 39.61 28.04, 38.59 28.59)),((38.59 28.59, 39.61 28.04, 38.89 28.34, 38.59 28.59)),((38.59 28.59, 38.59 31.41, 41.41 28.59, 38.59 28.59)),((38.04 30.39, 38.59 31.41, 38.59 28.59, 38.04 30.39)),((38.04 30.39, 38.34 31.11, 38.59 31.41, 38.04 30.39)),((38.04 30.39, 38.15 30.77, 38.34 31.11, 38.04 30.39)),((38.04 29.61, 38.59 28.59, 38.34 28.89, 38.04 29.61)),((38.04 29.61, 38.34 28.89, 38.15 29.23, 38.04 29.61)),((38.04 29.61, 38.04 30.39, 38.59 28.59, 38.04 29.61)),((38 30, 38.04 30.39, 38.04 29.61, 38 30)))" + "MultiPolygon (((41.96 29.61, 41.96 30.39, 42 30, 41.96 29.61)),((41.66 31.11, 41.85 30.77, 41.96 30.39, 41.66 31.11)),((41.66 28.89, 41.96 29.61, 41.85 29.23, 41.66 28.89)),((41.41 31.41, 41.96 30.39, 41.96 29.61, 41.41 31.41)),((41.41 31.41, 41.66 31.11, 41.96 30.39, 41.41 31.41)),((41.41 28.59, 41.96 29.61, 41.66 28.89, 41.41 28.59)),((41.41 28.59, 41.41 31.41, 41.96 29.61, 41.41 28.59)),((40.39 31.96, 41.11 31.66, 41.41 31.41, 40.39 31.96)),((40.39 31.96, 40.77 31.85, 41.11 31.66, 40.39 31.96)),((40.39 28.04, 41.41 28.59, 41.11 28.34, 40.39 28.04)),((40.39 28.04, 41.11 28.34, 40.77 28.15, 40.39 28.04)),((39.61 31.96, 40.39 31.96, 41.41 31.41, 39.61 31.96)),((39.61 31.96, 40 32, 40.39 31.96, 39.61 31.96)),((39.61 28.04, 40.39 28.04, 40 28, 39.61 28.04)),((38.89 31.66, 39.23 31.85, 39.61 31.96, 38.89 31.66)),((38.89 28.34, 39.61 28.04, 39.23 28.15, 38.89 28.34)),((38.59 31.41, 41.41 31.41, 41.41 28.59, 38.59 31.41)),((38.59 31.41, 39.61 31.96, 41.41 31.41, 38.59 31.41)),((38.59 31.41, 38.89 31.66, 39.61 31.96, 38.59 31.41)),((38.59 28.59, 41.41 28.59, 40.39 28.04, 38.59 28.59)),((38.59 28.59, 40.39 28.04, 39.61 28.04, 38.59 28.59)),((38.59 28.59, 39.61 28.04, 38.89 28.34, 38.59 28.59)),((38.59 28.59, 38.59 31.41, 41.41 28.59, 38.59 28.59)),((38.04 30.39, 38.59 31.41, 38.59 28.59, 38.04 30.39)),((38.04 30.39, 38.34 31.11, 38.59 31.41, 38.04 30.39)),((38.04 30.39, 38.15 30.77, 38.34 31.11, 38.04 30.39)),((38.04 29.61, 38.59 28.59, 38.34 28.89, 38.04 29.61)),((38.04 29.61, 38.34 28.89, 38.15 29.23, 38.04 29.61)),((38.04 29.61, 38.04 30.39, 38.59 28.59, 38.04 29.61)),((38 30, 38.04 30.39, 38.04 29.61, 38 30)))", ) def testAsNumpy(self): @@ -8006,7 +13990,9 @@ def testAsNumpy(self): array_polygon = geom_polygon.as_numpy() self.assertTrue(isinstance(array_polygon, numpy.ndarray)) self.assertEqual(len(array_polygon), 1) - self.assertTrue(numpy.allclose(array_polygon[0], [[0, 0], [4, 0], [4, 4], [0, 4], [0, 0]])) + self.assertTrue( + numpy.allclose(array_polygon[0], [[0, 0], [4, 0], [4, 4], [0, 4], [0, 0]]) + ) # Test MULTIPOINT geom_multipoint = QgsGeometry.fromWkt("MULTIPOINT ((1 2), (3 4))") @@ -8018,11 +14004,15 @@ def testAsNumpy(self): self.assertTrue(numpy.allclose(array_multipoint[1], [3, 4])) # Test MULTILINESTRING - geom_multilinestring = QgsGeometry.fromWkt("MULTILINESTRING ((0 0, 1 1, 1 2), (2 2, 3 3))") + geom_multilinestring = QgsGeometry.fromWkt( + "MULTILINESTRING ((0 0, 1 1, 1 2), (2 2, 3 3))" + ) array_multilinestring = geom_multilinestring.as_numpy() self.assertTrue(isinstance(array_multilinestring, list)) self.assertEqual(len(array_multilinestring), 2) - self.assertTrue(numpy.allclose(array_multilinestring[0], [[0, 0], [1, 1], [1, 2]])) + self.assertTrue( + numpy.allclose(array_multilinestring[0], [[0, 0], [1, 1], [1, 2]]) + ) self.assertTrue(numpy.allclose(array_multilinestring[1], [[2, 2], [3, 3]])) # Test MULTIPOLYGON @@ -8033,10 +14023,19 @@ def testAsNumpy(self): self.assertTrue(isinstance(array_multipolygon, list)) self.assertEqual(len(array_multipolygon), 2) self.assertEqual(len(array_multipolygon[0]), 1) # First polygon has 1 ring - self.assertTrue(numpy.allclose(array_multipolygon[0][0], [[0, 0], [4, 0], [4, 4], [0, 4], [0, 0]])) + self.assertTrue( + numpy.allclose( + array_multipolygon[0][0], [[0, 0], [4, 0], [4, 4], [0, 4], [0, 0]] + ) + ) self.assertEqual(len(array_multipolygon[1]), 1) # Second polygon has 1 ring - self.assertTrue(numpy.allclose(array_multipolygon[1][0], [[10, 10], [14, 10], [14, 14], [10, 14], [10, 10]])) + self.assertTrue( + numpy.allclose( + array_multipolygon[1][0], + [[10, 10], [14, 10], [14, 14], [10, 14], [10, 10]], + ) + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsgeometry_avoid_intersections.py b/tests/src/python/test_qgsgeometry_avoid_intersections.py index 3921018fb382..5af105d59c1f 100644 --- a/tests/src/python/test_qgsgeometry_avoid_intersections.py +++ b/tests/src/python/test_qgsgeometry_avoid_intersections.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Martin Dobias' -__date__ = '20/08/2012' -__copyright__ = 'Copyright 2012, The QGIS Project' + +__author__ = "Martin Dobias" +__date__ = "20/08/2012" +__copyright__ = "Copyright 2012, The QGIS Project" from qgis.core import QgsFeature, QgsGeometry, QgsVectorLayer @@ -21,7 +22,7 @@ "POLYGON((11573173.43113279156386852 993520.09148781711701304,11576724.69587560556828976 993235.99030839197803289,11578337.0769300926476717 993106.99982403311878443,11579916.07919318228960037 992980.67964298592414707,11585348.82705115899443626 992546.05981434776913375,11585348.82705115899443626 991801.59352863347157836,11585802.76990830153226852 980906.96495720488019288,11585348.82705115899443626 973189.93638577638193965,11584503.3406173400580883 970315.28251079504843801,11577674.00869971700012684 971200.56627789419144392,11574530.55707954056560993 971608.05074717639945447,11570059.38887163810431957 972187.64662597852293402,11569460.82705115899443626 977275.42210006201639771,11572184.48419401608407497 986808.22210006206296384,11573092.36990830115973949 992709.47924291924573481,11573173.43113279156386852 993520.09148781711701304))", "POLYGON((11596726.68511567451059818 987803.96772218181286007,11602386.29350295476615429 987912.80634501413442194,11606709.58121678233146667 987995.94649335695430636,11611885.51540027372539043 988095.48368919338099658,11612131.4556225873529911 983176.67924291919916868,11612131.4556225873529911 973189.93638577638193965,11612131.4556225873529911 972258.57086853496730328,11605332.19643574021756649 972844.7139018839225173,11601876.97527708858251572 973142.57779487106017768,11596210.5081571489572525 973631.06633969338145107,11594881.62705115787684917 982268.79352863342501223,11596726.68511567451059818 987803.96772218181286007))", "MULTIPOLYGON(((11602386.29350295476615429 987912.80634501413442194,11602598.65562258660793304 994071.30781434779055417,11605393.122793298214674 993232.96766313433181494,11607138.08419401571154594 992709.47924291924573481,11606709.58121678233146667 987995.94649335695430636,11602386.29350295476615429 987912.80634501413442194)),((11605332.19643574021756649 972844.7139018839225173,11604868.36990830115973949 967742.62210006208624691,11603208.23603074997663498 967742.62210006208624691,11601690.76990830153226852 967742.62210006208624691,11601876.97527708858251572 973142.57779487106017768,11605332.19643574021756649 972844.7139018839225173)))", - "MULTIPOLYGON(((11576724.69587560556828976 993235.99030839197803289,11577177.85562258772552013 997702.85067149065434933,11578957.31162258610129356 997448.64267149078659713,11580355.4556225873529911 997248.9078143477672711,11579916.07919318228960037 992980.67964298592414707,11578337.0769300926476717 993106.99982403311878443,11576724.69587560556828976 993235.99030839197803289)),((11577674.00869971700012684 971200.56627789419144392,11577177.85562258772552013 966380.79352863342501223,11574519.0474593210965395 966380.79352863342501223,11574000.25562258623540401 966380.79352863342501223,11574530.55707954056560993 971608.05074717639945447,11577674.00869971700012684 971200.56627789419144392)))" + "MULTIPOLYGON(((11576724.69587560556828976 993235.99030839197803289,11577177.85562258772552013 997702.85067149065434933,11578957.31162258610129356 997448.64267149078659713,11580355.4556225873529911 997248.9078143477672711,11579916.07919318228960037 992980.67964298592414707,11578337.0769300926476717 993106.99982403311878443,11576724.69587560556828976 993235.99030839197803289)),((11577674.00869971700012684 971200.56627789419144392,11577177.85562258772552013 966380.79352863342501223,11574519.0474593210965395 966380.79352863342501223,11574000.25562258623540401 966380.79352863342501223,11574530.55707954056560993 971608.05074717639945447,11577674.00869971700012684 971200.56627789419144392)))", ] newg_wkt = "POLYGON((11556863.91276544518768787 1008143.53638577624224126,11632785.85562258586287498 1005192.9078143477672711,11633693.74133687280118465 996794.96495720488019288,11605776.25562258809804916 996794.96495720488019288,11604300.94133687205612659 962862.73638577631209046,11602712.14133687317371368 962976.22210006194654852,11603620.0270511582493782 996794.96495720488019288,11588299.4556225873529911 997929.82210006203968078,11588753.39847972989082336 961160.45067149063106626,11575362.08419401571154594 961841.36495720490347594,11577745.28419401682913303 1000199.53638577624224126,11557658.3127654455602169 1001107.42210006201639771,11556863.91276544518768787 1008143.53638577624224126))" @@ -42,7 +43,7 @@ class TestQgsGeometryAvoidIntersections(QgisTestCase): def testNoSliverPolygons(self): # create a layer with some polygons that will be used as a source for "avoid intersections" - l = QgsVectorLayer('MultiPolygon', 'test_layer', 'memory') + l = QgsVectorLayer("MultiPolygon", "test_layer", "memory") assert l.isValid() features = [] @@ -65,5 +66,5 @@ def testNoSliverPolygons(self): assert len(mpg) == 3 -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsgeometrycollection.py b/tests/src/python/test_qgsgeometrycollection.py index 7b6c71e2ecf8..29150b855153 100644 --- a/tests/src/python/test_qgsgeometrycollection.py +++ b/tests/src/python/test_qgsgeometrycollection.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Loïc Bartoletti' -__date__ = '19/12/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "Loïc Bartoletti" +__date__ = "19/12/2023" +__copyright__ = "Copyright 2023, The QGIS Project" import unittest @@ -20,7 +21,7 @@ QgsMultiPoint, QgsMultiLineString, QgsMultiPolygon, - QgsRectangle + QgsRectangle, ) from qgis.testing import start_app, QgisTestCase @@ -99,12 +100,10 @@ def testFuzzyComparisons(self): epsilon = 0.001 geom1 = QgsGeometryCollection() self.assertTrue(geom1.addGeometry(QgsPoint(0.0, 0.0, 0.0, 0.0))) - self.assertTrue( - geom1.addGeometry(QgsPoint(0.001, 0.001, 0.001, 0.001))) + self.assertTrue(geom1.addGeometry(QgsPoint(0.001, 0.001, 0.001, 0.001))) geom2 = QgsGeometryCollection() self.assertTrue(geom2.addGeometry(QgsPoint(0.0, 0.0, 0.0, 0.0))) - self.assertTrue( - geom2.addGeometry(QgsPoint(0.001, 0.001, 0.002, 0.002))) + self.assertTrue(geom2.addGeometry(QgsPoint(0.001, 0.001, 0.002, 0.002))) self.assertNotEqual(geom1, geom2) # epsilon = 1e-8 here @@ -124,94 +123,82 @@ def test_extract_parts_by_type(self): empty_collection = QgsGeometryCollection() self.assertEqual( empty_collection.extractPartsByType(Qgis.WkbType.Point).asWkt(), - 'MultiPoint EMPTY' + "MultiPoint EMPTY", ) self.assertEqual( - empty_collection.extractPartsByType( - Qgis.WkbType.MultiPoint).asWkt(), - 'MultiPoint EMPTY' + empty_collection.extractPartsByType(Qgis.WkbType.MultiPoint).asWkt(), + "MultiPoint EMPTY", ) self.assertEqual( - empty_collection.extractPartsByType( - Qgis.WkbType.MultiPointZ).asWkt(), - 'MultiPoint EMPTY' + empty_collection.extractPartsByType(Qgis.WkbType.MultiPointZ).asWkt(), + "MultiPoint EMPTY", ) self.assertEqual( - empty_collection.extractPartsByType( - Qgis.WkbType.MultiPointM).asWkt(), - 'MultiPoint EMPTY' + empty_collection.extractPartsByType(Qgis.WkbType.MultiPointM).asWkt(), + "MultiPoint EMPTY", ) self.assertEqual( - empty_collection.extractPartsByType( - Qgis.WkbType.MultiPointZM).asWkt(), - 'MultiPoint EMPTY' + empty_collection.extractPartsByType(Qgis.WkbType.MultiPointZM).asWkt(), + "MultiPoint EMPTY", ) self.assertEqual( - empty_collection.extractPartsByType( - Qgis.WkbType.LineString).asWkt(), - 'MultiLineString EMPTY' + empty_collection.extractPartsByType(Qgis.WkbType.LineString).asWkt(), + "MultiLineString EMPTY", ) self.assertEqual( empty_collection.extractPartsByType(Qgis.WkbType.Polygon).asWkt(), - 'MultiPolygon EMPTY' + "MultiPolygon EMPTY", ) # ambiguous types - self.assertIsNone( - empty_collection.extractPartsByType(Qgis.WkbType.NoGeometry) - ) - self.assertIsNone( - empty_collection.extractPartsByType(Qgis.WkbType.Unknown) - ) + self.assertIsNone(empty_collection.extractPartsByType(Qgis.WkbType.NoGeometry)) + self.assertIsNone(empty_collection.extractPartsByType(Qgis.WkbType.Unknown)) point_collection = QgsGeometryCollection() point_collection.addGeometry(QgsPoint(1, 2)) - point_collection.addGeometry( - QgsPoint(11, 22) - ) + point_collection.addGeometry(QgsPoint(11, 22)) point_collection.addGeometry(QgsPoint(3, 4)) self.assertEqual( point_collection.extractPartsByType(Qgis.WkbType.Point).asWkt(), - 'MultiPoint ((1 2),(11 22),(3 4))' + "MultiPoint ((1 2),(11 22),(3 4))", ) self.assertEqual( - point_collection.extractPartsByType( - Qgis.WkbType.MultiPoint).asWkt(), - 'MultiPoint ((1 2),(11 22),(3 4))' + point_collection.extractPartsByType(Qgis.WkbType.MultiPoint).asWkt(), + "MultiPoint ((1 2),(11 22),(3 4))", ) self.assertEqual( - point_collection.extractPartsByType( - Qgis.WkbType.MultiPointZ).asWkt(), - 'MultiPoint ((1 2),(11 22),(3 4))' + point_collection.extractPartsByType(Qgis.WkbType.MultiPointZ).asWkt(), + "MultiPoint ((1 2),(11 22),(3 4))", ) self.assertEqual( - point_collection.extractPartsByType( - Qgis.WkbType.MultiPointM).asWkt(), - 'MultiPoint ((1 2),(11 22),(3 4))' + point_collection.extractPartsByType(Qgis.WkbType.MultiPointM).asWkt(), + "MultiPoint ((1 2),(11 22),(3 4))", ) # strict dimension check self.assertEqual( - point_collection.extractPartsByType(Qgis.WkbType.MultiPointZ, - useFlatType=False).asWkt(), - 'MultiPoint EMPTY' + point_collection.extractPartsByType( + Qgis.WkbType.MultiPointZ, useFlatType=False + ).asWkt(), + "MultiPoint EMPTY", ) self.assertEqual( - point_collection.extractPartsByType(Qgis.WkbType.MultiPointM, - useFlatType=False).asWkt(), - 'MultiPoint EMPTY' + point_collection.extractPartsByType( + Qgis.WkbType.MultiPointM, useFlatType=False + ).asWkt(), + "MultiPoint EMPTY", ) self.assertEqual( - point_collection.extractPartsByType(Qgis.WkbType.MultiPointZM, - useFlatType=False).asWkt(), - 'MultiPoint EMPTY' + point_collection.extractPartsByType( + Qgis.WkbType.MultiPointZM, useFlatType=False + ).asWkt(), + "MultiPoint EMPTY", ) self.assertEqual( - point_collection.extractPartsByType( - Qgis.WkbType.LineString).asWkt(), - 'MultiLineString EMPTY' + point_collection.extractPartsByType(Qgis.WkbType.LineString).asWkt(), + "MultiLineString EMPTY", ) self.assertEqual( point_collection.extractPartsByType(Qgis.WkbType.Polygon).asWkt(), - 'MultiPolygon EMPTY' + "MultiPolygon EMPTY", ) # with z point_collection = QgsGeometryCollection() @@ -220,37 +207,36 @@ def test_extract_parts_by_type(self): point_collection.addGeometry(QgsPoint(3, 4, 5)) self.assertEqual( point_collection.extractPartsByType(Qgis.WkbType.Point).asWkt(), - 'MultiPoint Z ((1 2 3),(11 22 33),(3 4 5))' + "MultiPoint Z ((1 2 3),(11 22 33),(3 4 5))", ) self.assertEqual( - point_collection.extractPartsByType( - Qgis.WkbType.MultiPoint).asWkt(), - 'MultiPoint Z ((1 2 3),(11 22 33),(3 4 5))' + point_collection.extractPartsByType(Qgis.WkbType.MultiPoint).asWkt(), + "MultiPoint Z ((1 2 3),(11 22 33),(3 4 5))", ) self.assertEqual( - point_collection.extractPartsByType( - Qgis.WkbType.MultiPointZ).asWkt(), - 'MultiPoint Z ((1 2 3),(11 22 33),(3 4 5))' + point_collection.extractPartsByType(Qgis.WkbType.MultiPointZ).asWkt(), + "MultiPoint Z ((1 2 3),(11 22 33),(3 4 5))", ) # strict dimension check self.assertEqual( - point_collection.extractPartsByType(Qgis.WkbType.MultiPointZ, - useFlatType=False).asWkt(), - 'MultiPoint Z ((1 2 3),(11 22 33),(3 4 5))' + point_collection.extractPartsByType( + Qgis.WkbType.MultiPointZ, useFlatType=False + ).asWkt(), + "MultiPoint Z ((1 2 3),(11 22 33),(3 4 5))", ) self.assertEqual( - point_collection.extractPartsByType(Qgis.WkbType.MultiPointZM, - useFlatType=False).asWkt(), - 'MultiPoint EMPTY' + point_collection.extractPartsByType( + Qgis.WkbType.MultiPointZM, useFlatType=False + ).asWkt(), + "MultiPoint EMPTY", ) self.assertEqual( - point_collection.extractPartsByType( - Qgis.WkbType.LineString).asWkt(), - 'MultiLineString EMPTY' + point_collection.extractPartsByType(Qgis.WkbType.LineString).asWkt(), + "MultiLineString EMPTY", ) self.assertEqual( point_collection.extractPartsByType(Qgis.WkbType.Polygon).asWkt(), - 'MultiPolygon EMPTY' + "MultiPolygon EMPTY", ) # with m @@ -260,37 +246,36 @@ def test_extract_parts_by_type(self): point_collection.addGeometry(QgsPoint(3, 4, m=5)) self.assertEqual( point_collection.extractPartsByType(Qgis.WkbType.Point).asWkt(), - 'MultiPoint M ((1 2 3),(11 22 33),(3 4 5))' + "MultiPoint M ((1 2 3),(11 22 33),(3 4 5))", ) self.assertEqual( - point_collection.extractPartsByType( - Qgis.WkbType.MultiPoint).asWkt(), - 'MultiPoint M ((1 2 3),(11 22 33),(3 4 5))' + point_collection.extractPartsByType(Qgis.WkbType.MultiPoint).asWkt(), + "MultiPoint M ((1 2 3),(11 22 33),(3 4 5))", ) self.assertEqual( - point_collection.extractPartsByType( - Qgis.WkbType.MultiPointM).asWkt(), - 'MultiPoint M ((1 2 3),(11 22 33),(3 4 5))' + point_collection.extractPartsByType(Qgis.WkbType.MultiPointM).asWkt(), + "MultiPoint M ((1 2 3),(11 22 33),(3 4 5))", ) # strict dimension check self.assertEqual( - point_collection.extractPartsByType(Qgis.WkbType.MultiPointM, - useFlatType=False).asWkt(), - 'MultiPoint M ((1 2 3),(11 22 33),(3 4 5))' + point_collection.extractPartsByType( + Qgis.WkbType.MultiPointM, useFlatType=False + ).asWkt(), + "MultiPoint M ((1 2 3),(11 22 33),(3 4 5))", ) self.assertEqual( - point_collection.extractPartsByType(Qgis.WkbType.MultiPointZM, - useFlatType=False).asWkt(), - 'MultiPoint EMPTY' + point_collection.extractPartsByType( + Qgis.WkbType.MultiPointZM, useFlatType=False + ).asWkt(), + "MultiPoint EMPTY", ) self.assertEqual( - point_collection.extractPartsByType( - Qgis.WkbType.LineString).asWkt(), - 'MultiLineString EMPTY' + point_collection.extractPartsByType(Qgis.WkbType.LineString).asWkt(), + "MultiLineString EMPTY", ) self.assertEqual( point_collection.extractPartsByType(Qgis.WkbType.Polygon).asWkt(), - 'MultiPolygon EMPTY' + "MultiPolygon EMPTY", ) # with z and m @@ -300,168 +285,149 @@ def test_extract_parts_by_type(self): point_collection.addGeometry(QgsPoint(3, 4, 5, 55)) self.assertEqual( point_collection.extractPartsByType(Qgis.WkbType.Point).asWkt(), - 'MultiPoint ZM ((1 2 3 4),(11 22 33 44),(3 4 5 55))' + "MultiPoint ZM ((1 2 3 4),(11 22 33 44),(3 4 5 55))", ) self.assertEqual( - point_collection.extractPartsByType( - Qgis.WkbType.MultiPoint).asWkt(), - 'MultiPoint ZM ((1 2 3 4),(11 22 33 44),(3 4 5 55))' + point_collection.extractPartsByType(Qgis.WkbType.MultiPoint).asWkt(), + "MultiPoint ZM ((1 2 3 4),(11 22 33 44),(3 4 5 55))", ) self.assertEqual( - point_collection.extractPartsByType( - Qgis.WkbType.MultiPointM).asWkt(), - 'MultiPoint ZM ((1 2 3 4),(11 22 33 44),(3 4 5 55))' + point_collection.extractPartsByType(Qgis.WkbType.MultiPointM).asWkt(), + "MultiPoint ZM ((1 2 3 4),(11 22 33 44),(3 4 5 55))", ) # strict dimension check self.assertEqual( - point_collection.extractPartsByType(Qgis.WkbType.MultiPointZM, - useFlatType=False).asWkt(), - 'MultiPoint ZM ((1 2 3 4),(11 22 33 44),(3 4 5 55))' + point_collection.extractPartsByType( + Qgis.WkbType.MultiPointZM, useFlatType=False + ).asWkt(), + "MultiPoint ZM ((1 2 3 4),(11 22 33 44),(3 4 5 55))", ) self.assertEqual( - point_collection.extractPartsByType(Qgis.WkbType.MultiPointZ, - useFlatType=False).asWkt(), - 'MultiPoint EMPTY' + point_collection.extractPartsByType( + Qgis.WkbType.MultiPointZ, useFlatType=False + ).asWkt(), + "MultiPoint EMPTY", ) self.assertEqual( - point_collection.extractPartsByType(Qgis.WkbType.MultiPointM, - useFlatType=False).asWkt(), - 'MultiPoint EMPTY' + point_collection.extractPartsByType( + Qgis.WkbType.MultiPointM, useFlatType=False + ).asWkt(), + "MultiPoint EMPTY", ) self.assertEqual( - point_collection.extractPartsByType( - Qgis.WkbType.LineString).asWkt(), - 'MultiLineString EMPTY' + point_collection.extractPartsByType(Qgis.WkbType.LineString).asWkt(), + "MultiLineString EMPTY", ) self.assertEqual( point_collection.extractPartsByType(Qgis.WkbType.Polygon).asWkt(), - 'MultiPolygon EMPTY' + "MultiPolygon EMPTY", ) line_collection = QgsGeometryCollection() line_collection.addGeometry(QgsLineString([[1, 2], [3, 4]])) - line_collection.addGeometry( - QgsLineString( - [[11, 22], - [33, 44]] - ) - ) + line_collection.addGeometry(QgsLineString([[11, 22], [33, 44]])) self.assertEqual( - line_collection.extractPartsByType( - Qgis.WkbType.LineString).asWkt(), - 'MultiLineString ((1 2, 3 4),(11 22, 33 44))' + line_collection.extractPartsByType(Qgis.WkbType.LineString).asWkt(), + "MultiLineString ((1 2, 3 4),(11 22, 33 44))", ) self.assertEqual( - line_collection.extractPartsByType( - Qgis.WkbType.MultiLineString).asWkt(), - 'MultiLineString ((1 2, 3 4),(11 22, 33 44))' + line_collection.extractPartsByType(Qgis.WkbType.MultiLineString).asWkt(), + "MultiLineString ((1 2, 3 4),(11 22, 33 44))", ) self.assertEqual( - line_collection.extractPartsByType( - Qgis.WkbType.MultiLineStringZ).asWkt(), - 'MultiLineString ((1 2, 3 4),(11 22, 33 44))' + line_collection.extractPartsByType(Qgis.WkbType.MultiLineStringZ).asWkt(), + "MultiLineString ((1 2, 3 4),(11 22, 33 44))", ) # strict dimension check self.assertEqual( - line_collection.extractPartsByType(Qgis.WkbType.MultiLineStringZ, - useFlatType=False).asWkt(), - 'MultiLineString EMPTY' + line_collection.extractPartsByType( + Qgis.WkbType.MultiLineStringZ, useFlatType=False + ).asWkt(), + "MultiLineString EMPTY", ) self.assertEqual( - line_collection.extractPartsByType( - Qgis.WkbType.Point).asWkt(), - 'MultiPoint EMPTY' + line_collection.extractPartsByType(Qgis.WkbType.Point).asWkt(), + "MultiPoint EMPTY", ) self.assertEqual( line_collection.extractPartsByType(Qgis.WkbType.Polygon).asWkt(), - 'MultiPolygon EMPTY' + "MultiPolygon EMPTY", ) polygon_collection = QgsGeometryCollection() polygon_collection.addGeometry( - QgsPolygon(QgsLineString([[1, 2], [3, 4], [1, 4], [1, 2]]))) - polygon_collection.addGeometry(QgsPolygon( - QgsLineString([[11, 22], [13, 14], [11, 14], [11, 22]]))) + QgsPolygon(QgsLineString([[1, 2], [3, 4], [1, 4], [1, 2]])) + ) + polygon_collection.addGeometry( + QgsPolygon(QgsLineString([[11, 22], [13, 14], [11, 14], [11, 22]])) + ) self.assertEqual( - polygon_collection.extractPartsByType( - Qgis.WkbType.Polygon).asWkt(), - 'MultiPolygon (((1 2, 3 4, 1 4, 1 2)),((11 22, 13 14, 11 14, 11 22)))' + polygon_collection.extractPartsByType(Qgis.WkbType.Polygon).asWkt(), + "MultiPolygon (((1 2, 3 4, 1 4, 1 2)),((11 22, 13 14, 11 14, 11 22)))", ) self.assertEqual( - polygon_collection.extractPartsByType( - Qgis.WkbType.MultiPolygon).asWkt(), - 'MultiPolygon (((1 2, 3 4, 1 4, 1 2)),((11 22, 13 14, 11 14, 11 22)))' + polygon_collection.extractPartsByType(Qgis.WkbType.MultiPolygon).asWkt(), + "MultiPolygon (((1 2, 3 4, 1 4, 1 2)),((11 22, 13 14, 11 14, 11 22)))", ) self.assertEqual( - polygon_collection.extractPartsByType( - Qgis.WkbType.MultiPolygonZ).asWkt(), - 'MultiPolygon (((1 2, 3 4, 1 4, 1 2)),((11 22, 13 14, 11 14, 11 22)))' + polygon_collection.extractPartsByType(Qgis.WkbType.MultiPolygonZ).asWkt(), + "MultiPolygon (((1 2, 3 4, 1 4, 1 2)),((11 22, 13 14, 11 14, 11 22)))", ) # strict dimension check self.assertEqual( - polygon_collection.extractPartsByType(Qgis.WkbType.MultiPolygonZ, - useFlatType=False).asWkt(), - 'MultiPolygon EMPTY' + polygon_collection.extractPartsByType( + Qgis.WkbType.MultiPolygonZ, useFlatType=False + ).asWkt(), + "MultiPolygon EMPTY", ) self.assertEqual( - polygon_collection.extractPartsByType( - Qgis.WkbType.Point).asWkt(), - 'MultiPoint EMPTY' + polygon_collection.extractPartsByType(Qgis.WkbType.Point).asWkt(), + "MultiPoint EMPTY", ) self.assertEqual( - polygon_collection.extractPartsByType( - Qgis.WkbType.LineString).asWkt(), - 'MultiLineString EMPTY' + polygon_collection.extractPartsByType(Qgis.WkbType.LineString).asWkt(), + "MultiLineString EMPTY", ) mixed_collection = QgsGeometryCollection() mixed_collection.addGeometry( - QgsPolygon(QgsLineString([[1, 2], [3, 4], [1, 4], [1, 2]]))) - mixed_collection.addGeometry(QgsPolygon( - QgsLineString([[11, 22], [13, 14], [11, 14], [11, 22]]))) - mixed_collection.addGeometry(QgsLineString([[1, 2], [3, 4]])) - mixed_collection.addGeometry( - QgsLineString( - [(11, 22), - (33, 44)] - ) + QgsPolygon(QgsLineString([[1, 2], [3, 4], [1, 4], [1, 2]])) ) - mixed_collection.addGeometry(QgsPoint(1, 2, 3)) mixed_collection.addGeometry( - QgsPoint(11, 22, 33) + QgsPolygon(QgsLineString([[11, 22], [13, 14], [11, 14], [11, 22]])) ) + mixed_collection.addGeometry(QgsLineString([[1, 2], [3, 4]])) + mixed_collection.addGeometry(QgsLineString([(11, 22), (33, 44)])) + mixed_collection.addGeometry(QgsPoint(1, 2, 3)) + mixed_collection.addGeometry(QgsPoint(11, 22, 33)) mixed_collection.addGeometry(QgsPoint(3, 4, 5)) self.assertEqual( - mixed_collection.extractPartsByType( - Qgis.WkbType.Polygon).asWkt(), - 'MultiPolygon (((1 2, 3 4, 1 4, 1 2)),((11 22, 13 14, 11 14, 11 22)))' + mixed_collection.extractPartsByType(Qgis.WkbType.Polygon).asWkt(), + "MultiPolygon (((1 2, 3 4, 1 4, 1 2)),((11 22, 13 14, 11 14, 11 22)))", ) self.assertEqual( - mixed_collection.extractPartsByType( - Qgis.WkbType.MultiPolygon).asWkt(), - 'MultiPolygon (((1 2, 3 4, 1 4, 1 2)),((11 22, 13 14, 11 14, 11 22)))' + mixed_collection.extractPartsByType(Qgis.WkbType.MultiPolygon).asWkt(), + "MultiPolygon (((1 2, 3 4, 1 4, 1 2)),((11 22, 13 14, 11 14, 11 22)))", ) self.assertEqual( - mixed_collection.extractPartsByType( - Qgis.WkbType.MultiPolygonZ).asWkt(), - 'MultiPolygon (((1 2, 3 4, 1 4, 1 2)),((11 22, 13 14, 11 14, 11 22)))' + mixed_collection.extractPartsByType(Qgis.WkbType.MultiPolygonZ).asWkt(), + "MultiPolygon (((1 2, 3 4, 1 4, 1 2)),((11 22, 13 14, 11 14, 11 22)))", ) # strict dimension check self.assertEqual( - mixed_collection.extractPartsByType(Qgis.WkbType.MultiPolygonZ, - useFlatType=False).asWkt(), - 'MultiPolygon EMPTY' + mixed_collection.extractPartsByType( + Qgis.WkbType.MultiPolygonZ, useFlatType=False + ).asWkt(), + "MultiPolygon EMPTY", ) self.assertEqual( - mixed_collection.extractPartsByType( - Qgis.WkbType.Point).asWkt(), - 'MultiPoint Z ((1 2 3),(11 22 33),(3 4 5))' + mixed_collection.extractPartsByType(Qgis.WkbType.Point).asWkt(), + "MultiPoint Z ((1 2 3),(11 22 33),(3 4 5))", ) self.assertEqual( - mixed_collection.extractPartsByType( - Qgis.WkbType.LineString).asWkt(), - 'MultiLineString ((1 2, 3 4),(11 22, 33 44))' + mixed_collection.extractPartsByType(Qgis.WkbType.LineString).asWkt(), + "MultiLineString ((1 2, 3 4),(11 22, 33 44))", ) # shortcuts @@ -469,64 +435,52 @@ def test_extract_parts_by_type(self): mp.addGeometry(QgsPoint(1, 2, 3)) mp.addGeometry(QgsPoint(11, 22, 33)) self.assertEqual( - mp.extractPartsByType( - Qgis.WkbType.Point).asWkt(), - 'MultiPoint Z ((1 2 3),(11 22 33))' + mp.extractPartsByType(Qgis.WkbType.Point).asWkt(), + "MultiPoint Z ((1 2 3),(11 22 33))", ) self.assertEqual( - mp.extractPartsByType( - Qgis.WkbType.Point, useFlatType=False).asWkt(), - 'MultiPoint EMPTY' + mp.extractPartsByType(Qgis.WkbType.Point, useFlatType=False).asWkt(), + "MultiPoint EMPTY", ) self.assertEqual( - mp.extractPartsByType( - Qgis.WkbType.LineString).asWkt(), - 'MultiLineString EMPTY' + mp.extractPartsByType(Qgis.WkbType.LineString).asWkt(), + "MultiLineString EMPTY", ) ml = QgsMultiLineString() ml.addGeometry(QgsLineString([[1, 2, 3], [3, 4, 5]])) - ml.addGeometry( - QgsLineString( - [[11, 22, 6], [33, 44, 7]] - )) + ml.addGeometry(QgsLineString([[11, 22, 6], [33, 44, 7]])) self.assertEqual( - ml.extractPartsByType( - Qgis.WkbType.LineString).asWkt(), - 'MultiLineString Z ((1 2 3, 3 4 5),(11 22 6, 33 44 7))' + ml.extractPartsByType(Qgis.WkbType.LineString).asWkt(), + "MultiLineString Z ((1 2 3, 3 4 5),(11 22 6, 33 44 7))", ) self.assertEqual( - ml.extractPartsByType( - Qgis.WkbType.LineString, useFlatType=False).asWkt(), - 'MultiLineString EMPTY' + ml.extractPartsByType(Qgis.WkbType.LineString, useFlatType=False).asWkt(), + "MultiLineString EMPTY", ) self.assertEqual( - ml.extractPartsByType( - Qgis.WkbType.Point).asWkt(), - 'MultiPoint EMPTY' + ml.extractPartsByType(Qgis.WkbType.Point).asWkt(), "MultiPoint EMPTY" ) mp = QgsMultiPolygon() + mp.addGeometry( + QgsPolygon(QgsLineString([[1, 2, 3], [3, 4, 3], [1, 4, 3], [1, 2, 3]])) + ) mp.addGeometry( QgsPolygon( - QgsLineString([[1, 2, 3], [3, 4, 3], [1, 4, 3], [1, 2, 3]]))) - mp.addGeometry(QgsPolygon( - QgsLineString( - [[11, 22, 33], [13, 14, 33], [11, 14, 33], [11, 22, 33]]))) + QgsLineString([[11, 22, 33], [13, 14, 33], [11, 14, 33], [11, 22, 33]]) + ) + ) self.assertEqual( - mp.extractPartsByType( - Qgis.WkbType.Polygon).asWkt(), - 'MultiPolygon Z (((1 2 3, 3 4 3, 1 4 3, 1 2 3)),((11 22 33, 13 14 33, 11 14 33, 11 22 33)))' + mp.extractPartsByType(Qgis.WkbType.Polygon).asWkt(), + "MultiPolygon Z (((1 2 3, 3 4 3, 1 4 3, 1 2 3)),((11 22 33, 13 14 33, 11 14 33, 11 22 33)))", ) self.assertEqual( - mp.extractPartsByType( - Qgis.WkbType.Polygon, useFlatType=False).asWkt(), - 'MultiPolygon EMPTY' + mp.extractPartsByType(Qgis.WkbType.Polygon, useFlatType=False).asWkt(), + "MultiPolygon EMPTY", ) self.assertEqual( - mp.extractPartsByType( - Qgis.WkbType.Point).asWkt(), - 'MultiPoint EMPTY' + mp.extractPartsByType(Qgis.WkbType.Point).asWkt(), "MultiPoint EMPTY" ) def test_take_geometries(self): @@ -536,28 +490,31 @@ def test_take_geometries(self): # empty collection collection = QgsGeometryCollection() self.assertFalse(collection.takeGeometries()) - self.assertEqual(collection.asWkt(), 'GeometryCollection EMPTY') + self.assertEqual(collection.asWkt(), "GeometryCollection EMPTY") + collection.addGeometry( + QgsPolygon(QgsLineString([[1, 2, 3], [3, 4, 3], [1, 4, 3], [1, 2, 3]])) + ) collection.addGeometry( QgsPolygon( - QgsLineString([[1, 2, 3], [3, 4, 3], [1, 4, 3], [1, 2, 3]]))) - collection.addGeometry(QgsPolygon( - QgsLineString( - [[11, 22, 33], [13, 14, 33], [11, 14, 33], [11, 22, 33]]))) - self.assertEqual(collection.boundingBox(), - QgsRectangle(1, 2, 13, 22)) + QgsLineString([[11, 22, 33], [13, 14, 33], [11, 14, 33], [11, 22, 33]]) + ) + ) + self.assertEqual(collection.boundingBox(), QgsRectangle(1, 2, 13, 22)) geometries = collection.takeGeometries() # should be nothing left - self.assertEqual(collection.asWkt(), 'GeometryCollection EMPTY') + self.assertEqual(collection.asWkt(), "GeometryCollection EMPTY") self.assertEqual(collection.boundingBox(), QgsRectangle()) del collection self.assertEqual( [p.asWkt() for p in geometries], - ['Polygon Z ((1 2 3, 3 4 3, 1 4 3, 1 2 3))', - 'Polygon Z ((11 22 33, 13 14 33, 11 14 33, 11 22 33))'] + [ + "Polygon Z ((1 2 3, 3 4 3, 1 4 3, 1 2 3))", + "Polygon Z ((11 22 33, 13 14 33, 11 14 33, 11 22 33))", + ], ) def test_add_geometries(self): @@ -567,35 +524,44 @@ def test_add_geometries(self): # empty collection collection = QgsGeometryCollection() self.assertTrue(collection.addGeometries([])) - self.assertEqual(collection.asWkt(), 'GeometryCollection EMPTY') + self.assertEqual(collection.asWkt(), "GeometryCollection EMPTY") self.assertEqual(collection.boundingBox(), QgsRectangle()) self.assertTrue( - collection.addGeometries([ - QgsLineString([[1, 2, 3], [3, 4, 3], [1, 4, 3], [1, 2, 3]]), - QgsLineString( - [[11, 22, 33], [13, 14, 33], [11, 14, 33], [11, 22, 33]])]) - ) - self.assertEqual(collection.asWkt(), - 'GeometryCollection (LineString Z (1 2 3, 3 4 3, 1 4 3, 1 2 3),LineString Z (11 22 33, 13 14 33, 11 14 33, 11 22 33))') - self.assertEqual(collection.boundingBox(), - QgsRectangle(1, 2, 13, 22)) - self.assertTrue( - collection.addGeometries([ - QgsPoint(100, 200)] - )) - self.assertEqual(collection.asWkt(), 'GeometryCollection (LineString Z (1 2 3, 3 4 3, 1 4 3, 1 2 3),LineString Z (11 22 33, 13 14 33, 11 14 33, 11 22 33),Point (100 200))') - self.assertEqual(collection.boundingBox(), - QgsRectangle(1, 2, 100, 200)) + collection.addGeometries( + [ + QgsLineString([[1, 2, 3], [3, 4, 3], [1, 4, 3], [1, 2, 3]]), + QgsLineString( + [[11, 22, 33], [13, 14, 33], [11, 14, 33], [11, 22, 33]] + ), + ] + ) + ) + self.assertEqual( + collection.asWkt(), + "GeometryCollection (LineString Z (1 2 3, 3 4 3, 1 4 3, 1 2 3),LineString Z (11 22 33, 13 14 33, 11 14 33, 11 22 33))", + ) + self.assertEqual(collection.boundingBox(), QgsRectangle(1, 2, 13, 22)) + self.assertTrue(collection.addGeometries([QgsPoint(100, 200)])) + self.assertEqual( + collection.asWkt(), + "GeometryCollection (LineString Z (1 2 3, 3 4 3, 1 4 3, 1 2 3),LineString Z (11 22 33, 13 14 33, 11 14 33, 11 22 33),Point (100 200))", + ) + self.assertEqual(collection.boundingBox(), QgsRectangle(1, 2, 100, 200)) def test_simplify_by_distance(self): """ test simplifyByDistance """ p = QgsGeometryCollection() - p.fromWkt('GeometryCollection( LineString(0 0, 50 0, 70 0, 80 0, 100 0), LineString(0 0, 50 1, 60 1, 100 0) )') - self.assertEqual(p.simplifyByDistance(10).asWkt(), 'GeometryCollection (LineString (0 0, 100 0),LineString (0 0, 100 0))') + p.fromWkt( + "GeometryCollection( LineString(0 0, 50 0, 70 0, 80 0, 100 0), LineString(0 0, 50 1, 60 1, 100 0) )" + ) + self.assertEqual( + p.simplifyByDistance(10).asWkt(), + "GeometryCollection (LineString (0 0, 100 0),LineString (0 0, 100 0))", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsgeometrygeneratorsymbollayer.py b/tests/src/python/test_qgsgeometrygeneratorsymbollayer.py index 13806cb9779f..b9bdaa5d60d0 100644 --- a/tests/src/python/test_qgsgeometrygeneratorsymbollayer.py +++ b/tests/src/python/test_qgsgeometrygeneratorsymbollayer.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'December 2015' -__copyright__ = '(C) 2015, Matthias Kuhn' +__author__ = "Matthias Kuhn" +__date__ = "December 2015" +__copyright__ = "(C) 2015, Matthias Kuhn" import os @@ -67,20 +67,24 @@ class TestQgsGeometryGeneratorSymbolLayerV2(QgisTestCase): def setUp(self): self.iface = get_iface() - polys_shp = os.path.join(TEST_DATA_DIR, 'polys.shp') - points_shp = os.path.join(TEST_DATA_DIR, 'points.shp') - lines_shp = os.path.join(TEST_DATA_DIR, 'lines.shp') - self.polys_layer = QgsVectorLayer(polys_shp, 'Polygons', 'ogr') - self.points_layer = QgsVectorLayer(points_shp, 'Points', 'ogr') - self.lines_layer = QgsVectorLayer(lines_shp, 'Lines', 'ogr') + polys_shp = os.path.join(TEST_DATA_DIR, "polys.shp") + points_shp = os.path.join(TEST_DATA_DIR, "points.shp") + lines_shp = os.path.join(TEST_DATA_DIR, "lines.shp") + self.polys_layer = QgsVectorLayer(polys_shp, "Polygons", "ogr") + self.points_layer = QgsVectorLayer(points_shp, "Points", "ogr") + self.lines_layer = QgsVectorLayer(lines_shp, "Lines", "ogr") QgsProject.instance().addMapLayer(self.polys_layer) QgsProject.instance().addMapLayer(self.lines_layer) QgsProject.instance().addMapLayer(self.points_layer) # Create style - sym1 = QgsFillSymbol.createSimple({'color': '#fdbf6f', 'outline_color': 'black'}) - sym2 = QgsLineSymbol.createSimple({'color': '#fdbf6f'}) - sym3 = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'outline_color': 'black'}) + sym1 = QgsFillSymbol.createSimple( + {"color": "#fdbf6f", "outline_color": "black"} + ) + sym2 = QgsLineSymbol.createSimple({"color": "#fdbf6f"}) + sym3 = QgsMarkerSymbol.createSimple( + {"color": "#fdbf6f", "outline_color": "black"} + ) self.polys_layer.setRenderer(QgsSingleSymbolRenderer(sym1)) self.lines_layer.setRenderer(QgsSingleSymbolRenderer(sym2)) @@ -98,10 +102,12 @@ def test_basic(self): """ Test getters/setters """ - sym_layer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'centroid($geometry)'}) - self.assertEqual(sym_layer.geometryExpression(), 'centroid($geometry)') - sym_layer.setGeometryExpression('project($geometry, 4, 5)') - self.assertEqual(sym_layer.geometryExpression(), 'project($geometry, 4, 5)') + sym_layer = QgsGeometryGeneratorSymbolLayer.create( + {"geometryModifier": "centroid($geometry)"} + ) + self.assertEqual(sym_layer.geometryExpression(), "centroid($geometry)") + sym_layer.setGeometryExpression("project($geometry, 4, 5)") + self.assertEqual(sym_layer.geometryExpression(), "project($geometry, 4, 5)") sym_layer.setSymbolType(Qgis.SymbolType.Marker) self.assertEqual(sym_layer.symbolType(), Qgis.SymbolType.Marker) @@ -113,7 +119,9 @@ def test_clone(self): """ Test cloning layer """ - sym_layer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'centroid($geometry)'}) + sym_layer = QgsGeometryGeneratorSymbolLayer.create( + {"geometryModifier": "centroid($geometry)"} + ) sym_layer.setSymbolType(Qgis.SymbolType.Marker) sym_layer.setUnits(QgsUnitTypes.RenderUnit.RenderMillimeters) sym_layer.subSymbol().symbolLayer(0).setStrokeColor(QColor(0, 255, 255)) @@ -121,27 +129,31 @@ def test_clone(self): layer2 = sym_layer.clone() self.assertEqual(layer2.symbolType(), Qgis.SymbolType.Marker) self.assertEqual(layer2.units(), QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertEqual(layer2.geometryExpression(), 'centroid($geometry)') + self.assertEqual(layer2.geometryExpression(), "centroid($geometry)") self.assertEqual(layer2.subSymbol()[0].strokeColor(), QColor(0, 255, 255)) def test_properties_create(self): """ Test round trip through properties and create """ - sym_layer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'centroid($geometry)'}) + sym_layer = QgsGeometryGeneratorSymbolLayer.create( + {"geometryModifier": "centroid($geometry)"} + ) sym_layer.setSymbolType(Qgis.SymbolType.Marker) sym_layer.setUnits(QgsUnitTypes.RenderUnit.RenderMillimeters) layer2 = QgsGeometryGeneratorSymbolLayer.create(sym_layer.properties()) self.assertEqual(layer2.symbolType(), Qgis.SymbolType.Marker) self.assertEqual(layer2.units(), QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertEqual(layer2.geometryExpression(), 'centroid($geometry)') + self.assertEqual(layer2.geometryExpression(), "centroid($geometry)") def test_color(self): """ Test that subsymbol color is returned for symbol layer """ - sym_layer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'buffer($geometry, 2)'}) + sym_layer = QgsGeometryGeneratorSymbolLayer.create( + {"geometryModifier": "buffer($geometry, 2)"} + ) sym_layer.setSymbolType(Qgis.SymbolType.Fill) sym_layer.setUnits(QgsUnitTypes.RenderUnit.RenderMillimeters) sym_layer.subSymbol().symbolLayer(0).setColor(QColor(0, 255, 255)) @@ -150,7 +162,9 @@ def test_color(self): def test_marker(self): sym = self.polys_layer.renderer().symbol() - sym_layer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'centroid($geometry)'}) + sym_layer = QgsGeometryGeneratorSymbolLayer.create( + {"geometryModifier": "centroid($geometry)"} + ) sym_layer.setSymbolType(QgsSymbol.SymbolType.Marker) sym_layer.subSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) sym.changeSymbolLayer(0, sym_layer) @@ -160,21 +174,26 @@ def test_marker(self): self.assertTrue( self.render_map_settings_check( - 'geometrygenerator_marker', - 'geometrygenerator_marker', - self.mapsettings + "geometrygenerator_marker", "geometrygenerator_marker", self.mapsettings ) ) def test_mixed(self): sym = self.polys_layer.renderer().symbol() - buffer_layer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'buffer($geometry, "value"/15)', 'outline_color': 'black'}) + buffer_layer = QgsGeometryGeneratorSymbolLayer.create( + { + "geometryModifier": 'buffer($geometry, "value"/15)', + "outline_color": "black", + } + ) buffer_layer.setSymbolType(QgsSymbol.SymbolType.Fill) buffer_layer.subSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) self.assertIsNotNone(buffer_layer.subSymbol()) sym.appendSymbolLayer(buffer_layer) - marker_layer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'centroid($geometry)', 'outline_color': 'black'}) + marker_layer = QgsGeometryGeneratorSymbolLayer.create( + {"geometryModifier": "centroid($geometry)", "outline_color": "black"} + ) marker_layer.setSymbolType(QgsSymbol.SymbolType.Marker) marker_layer.subSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0)) sym.appendSymbolLayer(marker_layer) @@ -184,16 +203,19 @@ def test_mixed(self): self.assertTrue( self.render_map_settings_check( - 'geometrygenerator_mixed', - 'geometrygenerator_mixed', - self.mapsettings + "geometrygenerator_mixed", "geometrygenerator_mixed", self.mapsettings ) ) def test_buffer_lines(self): sym = self.lines_layer.renderer().symbol() - buffer_layer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'buffer($geometry, "value"/15)', 'outline_color': 'black'}) + buffer_layer = QgsGeometryGeneratorSymbolLayer.create( + { + "geometryModifier": 'buffer($geometry, "value"/15)', + "outline_color": "black", + } + ) buffer_layer.setSymbolType(QgsSymbol.SymbolType.Fill) self.assertIsNotNone(buffer_layer.subSymbol()) sym.appendSymbolLayer(buffer_layer) @@ -203,16 +225,21 @@ def test_buffer_lines(self): self.assertTrue( self.render_map_settings_check( - 'geometrygenerator_buffer_lines', - 'geometrygenerator_buffer_lines', - self.mapsettings + "geometrygenerator_buffer_lines", + "geometrygenerator_buffer_lines", + self.mapsettings, ) ) def test_buffer_points(self): sym = self.points_layer.renderer().symbol() - buffer_layer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'buffer($geometry, "staff"/15)', 'outline_color': 'black'}) + buffer_layer = QgsGeometryGeneratorSymbolLayer.create( + { + "geometryModifier": 'buffer($geometry, "staff"/15)', + "outline_color": "black", + } + ) buffer_layer.setSymbolType(QgsSymbol.SymbolType.Fill) self.assertIsNotNone(buffer_layer.subSymbol()) sym.appendSymbolLayer(buffer_layer) @@ -222,16 +249,18 @@ def test_buffer_points(self): self.assertTrue( self.render_map_settings_check( - 'geometrygenerator_buffer_points', - 'geometrygenerator_buffer_points', - self.mapsettings + "geometrygenerator_buffer_points", + "geometrygenerator_buffer_points", + self.mapsettings, ) ) def test_units_millimeters(self): sym = self.points_layer.renderer().symbol() - buffer_layer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'buffer($geometry, "staff")', 'outline_color': 'black'}) + buffer_layer = QgsGeometryGeneratorSymbolLayer.create( + {"geometryModifier": 'buffer($geometry, "staff")', "outline_color": "black"} + ) buffer_layer.setSymbolType(QgsSymbol.SymbolType.Fill) buffer_layer.setUnits(QgsUnitTypes.RenderUnit.RenderMillimeters) self.assertIsNotNone(buffer_layer.subSymbol()) @@ -242,20 +271,26 @@ def test_units_millimeters(self): self.assertTrue( self.render_map_settings_check( - 'geometrygenerator_millimeters', - 'geometrygenerator_millimeters', - self.mapsettings + "geometrygenerator_millimeters", + "geometrygenerator_millimeters", + self.mapsettings, ) ) def test_multi_poly_opacity(self): # test that multi-type features are only rendered once - multipoly = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'multipatch.shp'), 'Polygons', 'ogr') + multipoly = QgsVectorLayer( + os.path.join(TEST_DATA_DIR, "multipatch.shp"), "Polygons", "ogr" + ) - sym = QgsFillSymbol.createSimple({'color': '#77fdbf6f', 'outline_color': 'black'}) + sym = QgsFillSymbol.createSimple( + {"color": "#77fdbf6f", "outline_color": "black"} + ) - buffer_layer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'buffer($geometry, -0.01)', 'outline_color': 'black'}) + buffer_layer = QgsGeometryGeneratorSymbolLayer.create( + {"geometryModifier": "buffer($geometry, -0.01)", "outline_color": "black"} + ) buffer_layer.setSymbolType(QgsSymbol.SymbolType.Fill) buffer_layer.setSubSymbol(sym) geom_symbol = QgsFillSymbol() @@ -268,9 +303,7 @@ def test_multi_poly_opacity(self): self.assertTrue( self.render_map_settings_check( - 'geometrygenerator_opacity', - 'geometrygenerator_opacity', - mapsettings + "geometrygenerator_opacity", "geometrygenerator_opacity", mapsettings ) ) @@ -278,18 +311,26 @@ def test_generator_with_multipart_result_with_generator_subsymbol(self): """ Test that generator subsymbol of generator renders all parts of multipart geometry results """ - lines = QgsVectorLayer('MultiLineString?crs=epsg:4326', 'Lines', 'memory') + lines = QgsVectorLayer("MultiLineString?crs=epsg:4326", "Lines", "memory") self.assertTrue(lines.isValid()) f = QgsFeature() - f.setGeometry(QgsGeometry.fromWkt('MultiLineString((1 1, 2 1, 2 2),(3 1, 3 2, 4 2))')) + f.setGeometry( + QgsGeometry.fromWkt("MultiLineString((1 1, 2 1, 2 2),(3 1, 3 2, 4 2))") + ) lines.dataProvider().addFeature(f) - sym = QgsLineSymbol.createSimple({'color': '#fffdbf6f', 'outline_width': 1}) + sym = QgsLineSymbol.createSimple({"color": "#fffdbf6f", "outline_width": 1}) - parent_generator = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'segments_to_lines($geometry)'}) + parent_generator = QgsGeometryGeneratorSymbolLayer.create( + {"geometryModifier": "segments_to_lines($geometry)"} + ) parent_generator.setSymbolType(QgsSymbol.SymbolType.Line) - child_generator = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'collect_geometries(offset_curve($geometry, -2), offset_curve($geometry,2))'}) + child_generator = QgsGeometryGeneratorSymbolLayer.create( + { + "geometryModifier": "collect_geometries(offset_curve($geometry, -2), offset_curve($geometry,2))" + } + ) child_generator.setUnits(QgsUnitTypes.RenderUnit.RenderMillimeters) child_generator.setSymbolType(QgsSymbol.SymbolType.Line) child_generator.setSubSymbol(sym) @@ -308,9 +349,9 @@ def test_generator_with_multipart_result_with_generator_subsymbol(self): self.assertTrue( self.render_map_settings_check( - 'geometrygenerator_multipart_subsymbol', - 'geometrygenerator_multipart_subsymbol', - mapsettings + "geometrygenerator_multipart_subsymbol", + "geometrygenerator_multipart_subsymbol", + mapsettings, ) ) @@ -318,7 +359,9 @@ def test_no_feature(self): """ Test rendering as a pure symbol, no feature associated """ - buffer_layer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'buffer($geometry, 5)'}) + buffer_layer = QgsGeometryGeneratorSymbolLayer.create( + {"geometryModifier": "buffer($geometry, 5)"} + ) buffer_layer.setSymbolType(QgsSymbol.SymbolType.Fill) buffer_layer.setUnits(QgsUnitTypes.RenderUnit.RenderMillimeters) self.assertIsNotNone(buffer_layer.subSymbol()) @@ -336,17 +379,21 @@ def test_no_feature(self): symbol.startRender(context) - symbol.renderPolyline(QPolygonF([QPointF(50, 200), QPointF(100, 170), QPointF(350, 270)]), None, context) + symbol.renderPolyline( + QPolygonF([QPointF(50, 200), QPointF(100, 170), QPointF(350, 270)]), + None, + context, + ) symbol.stopRender(context) painter.end() self.assertTrue( self.image_check( - 'geometrygenerator_nofeature', - 'geometrygenerator_nofeature', + "geometrygenerator_nofeature", + "geometrygenerator_nofeature", image, - allowed_mismatch=0 + allowed_mismatch=0, ) ) @@ -354,7 +401,9 @@ def test_no_feature_coordinate_transform(self): """ Test rendering as a pure symbol, no feature associated, with coordinate transform """ - buffer_layer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'buffer($geometry, 5)'}) + buffer_layer = QgsGeometryGeneratorSymbolLayer.create( + {"geometryModifier": "buffer($geometry, 5)"} + ) buffer_layer.setSymbolType(QgsSymbol.SymbolType.Fill) buffer_layer.setUnits(QgsUnitTypes.RenderUnit.RenderMillimeters) self.assertIsNotNone(buffer_layer.subSymbol()) @@ -369,21 +418,31 @@ def test_no_feature_coordinate_transform(self): painter = QPainter(image) context = QgsRenderContext.fromQPainter(painter) - context.setCoordinateTransform(QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'), QgsProject.instance().transformContext())) + context.setCoordinateTransform( + QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsProject.instance().transformContext(), + ) + ) symbol.startRender(context) - symbol.renderPolyline(QPolygonF([QPointF(50, 200), QPointF(100, 170), QPointF(350, 270)]), None, context) + symbol.renderPolyline( + QPolygonF([QPointF(50, 200), QPointF(100, 170), QPointF(350, 270)]), + None, + context, + ) symbol.stopRender(context) painter.end() self.assertTrue( self.image_check( - 'geometrygenerator_nofeature', - 'geometrygenerator_nofeature', + "geometrygenerator_nofeature", + "geometrygenerator_nofeature", image, - allowed_mismatch=0 + allowed_mismatch=0, ) ) @@ -405,7 +464,8 @@ def test_subsymbol(self): # here "$geometry" must refer to the created ARROW shape, NOT the original feature line geometry! generator_layer = QgsGeometryGeneratorSymbolLayer.create( - {'geometryModifier': 'buffer($geometry, 3)'}) + {"geometryModifier": "buffer($geometry, 3)"} + ) generator_layer.setSymbolType(QgsSymbol.SymbolType.Fill) generator_layer.setUnits(QgsUnitTypes.RenderUnit.RenderMillimeters) self.assertIsNotNone(generator_layer.subSymbol()) @@ -423,9 +483,9 @@ def test_subsymbol(self): self.assertTrue( self.render_map_settings_check( - 'geometrygenerator_subsymbol', - 'geometrygenerator_subsymbol', - self.mapsettings + "geometrygenerator_subsymbol", + "geometrygenerator_subsymbol", + self.mapsettings, ) ) @@ -433,19 +493,24 @@ def test_geometry_function(self): """ The $geometry function used in a subsymbol should refer to the generated geometry """ - points = QgsVectorLayer('Point?crs=epsg:4326', 'Points', 'memory') + points = QgsVectorLayer("Point?crs=epsg:4326", "Points", "memory") self.assertTrue(points.isValid()) f = QgsFeature() - f.setGeometry(QgsGeometry.fromWkt('Point(1 2)')) + f.setGeometry(QgsGeometry.fromWkt("Point(1 2)")) points.dataProvider().addFeature(f) - font = QgsFontUtils.getStandardTestFont('Bold') - font_marker = QgsFontMarkerSymbolLayer(font.family(), 'x', 16) - font_marker.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyCharacter, QgsProperty.fromExpression('geom_to_wkt($geometry)')) + font = QgsFontUtils.getStandardTestFont("Bold") + font_marker = QgsFontMarkerSymbolLayer(font.family(), "x", 16) + font_marker.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyCharacter, + QgsProperty.fromExpression("geom_to_wkt($geometry)"), + ) subsymbol = QgsMarkerSymbol() subsymbol.changeSymbolLayer(0, font_marker) - parent_generator = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'translate($geometry, 1, 2)'}) + parent_generator = QgsGeometryGeneratorSymbolLayer.create( + {"geometryModifier": "translate($geometry, 1, 2)"} + ) parent_generator.setSymbolType(QgsSymbol.SymbolType.Marker) parent_generator.setSubSymbol(subsymbol) @@ -460,9 +525,9 @@ def test_geometry_function(self): self.assertTrue( self.render_map_settings_check( - 'geometrygenerator_function_geometry', - 'geometrygenerator_function_geometry', - mapsettings + "geometrygenerator_function_geometry", + "geometrygenerator_function_geometry", + mapsettings, ) ) @@ -471,12 +536,28 @@ def test_field_geometry(self): Use a geometry field """ - points = QgsVectorLayer('Point?crs=epsg:2154&field=other_geom:geometry(0,0)', 'Points', 'memory') - f = QgsVectorLayerUtils.createFeature(points, - QgsGeometry.fromWkt('Point(5 4)'), - {0: QgsReferencedGeometry(QgsGeometry.fromWkt('LineString(5 6, 7 8)'), QgsCoordinateReferenceSystem("EPSG:4326"))}) + points = QgsVectorLayer( + "Point?crs=epsg:2154&field=other_geom:geometry(0,0)", "Points", "memory" + ) + f = QgsVectorLayerUtils.createFeature( + points, + QgsGeometry.fromWkt("Point(5 4)"), + { + 0: QgsReferencedGeometry( + QgsGeometry.fromWkt("LineString(5 6, 7 8)"), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + }, + ) points.dataProvider().addFeature(f) - other_layer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': '"other_geom"', 'outline_color': 'black', 'SymbolType': 'Line', 'line_width': 2}) + other_layer = QgsGeometryGeneratorSymbolLayer.create( + { + "geometryModifier": '"other_geom"', + "outline_color": "black", + "SymbolType": "Line", + "line_width": 2, + } + ) points.renderer().symbol().changeSymbolLayer(0, other_layer) mapsettings = QgsMapSettings(self.mapsettings) @@ -485,9 +566,9 @@ def test_field_geometry(self): self.assertTrue( self.render_map_settings_check( - 'geometrygenerator_field_geometry', - 'geometrygenerator_field_geometry', - mapsettings + "geometrygenerator_field_geometry", + "geometrygenerator_field_geometry", + mapsettings, ) ) @@ -495,19 +576,24 @@ def test_feature_geometry(self): """ The geometry($currentfeature) expression used in a subsymbol should refer to the original FEATURE geometry """ - points = QgsVectorLayer('Point?crs=epsg:4326', 'Points', 'memory') + points = QgsVectorLayer("Point?crs=epsg:4326", "Points", "memory") self.assertTrue(points.isValid()) f = QgsFeature() - f.setGeometry(QgsGeometry.fromWkt('Point(1 2)')) + f.setGeometry(QgsGeometry.fromWkt("Point(1 2)")) points.dataProvider().addFeature(f) - font = QgsFontUtils.getStandardTestFont('Bold') - font_marker = QgsFontMarkerSymbolLayer(font.family(), 'x', 16) - font_marker.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyCharacter, QgsProperty.fromExpression('geom_to_wkt(geometry($currentfeature))')) + font = QgsFontUtils.getStandardTestFont("Bold") + font_marker = QgsFontMarkerSymbolLayer(font.family(), "x", 16) + font_marker.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyCharacter, + QgsProperty.fromExpression("geom_to_wkt(geometry($currentfeature))"), + ) subsymbol = QgsMarkerSymbol() subsymbol.changeSymbolLayer(0, font_marker) - parent_generator = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'translate($geometry, 1, 2)'}) + parent_generator = QgsGeometryGeneratorSymbolLayer.create( + {"geometryModifier": "translate($geometry, 1, 2)"} + ) parent_generator.setSymbolType(QgsSymbol.SymbolType.Marker) parent_generator.setSubSymbol(subsymbol) @@ -522,9 +608,9 @@ def test_feature_geometry(self): self.assertTrue( self.render_map_settings_check( - 'geometrygenerator_feature_geometry', - 'geometrygenerator_feature_geometry', - mapsettings + "geometrygenerator_feature_geometry", + "geometrygenerator_feature_geometry", + mapsettings, ) ) @@ -532,16 +618,21 @@ def test_clipped_results_with_z(self): """ See https://github.com/qgis/QGIS/issues/51796 """ - lines = QgsVectorLayer('LineString?crs=epsg:2154', 'Lines', 'memory') + lines = QgsVectorLayer("LineString?crs=epsg:2154", "Lines", "memory") self.assertTrue(lines.isValid()) f = QgsFeature() - f.setGeometry(QgsGeometry.fromWkt('LineStringZ (704425.82266868802253157 7060014.33574043028056622 19.51000000000000156, 704439.59844558802433312 7060023.7300771102309227 19.69000000000000128, 704441.67482289997860789 7060020.65665366966277361 19.62999999999999901, 704428.333267995971255 7060011.65915509033948183 19.42000000000000171)')) + f.setGeometry( + QgsGeometry.fromWkt( + "LineStringZ (704425.82266868802253157 7060014.33574043028056622 19.51000000000000156, 704439.59844558802433312 7060023.7300771102309227 19.69000000000000128, 704441.67482289997860789 7060020.65665366966277361 19.62999999999999901, 704428.333267995971255 7060011.65915509033948183 19.42000000000000171)" + ) + ) lines.dataProvider().addFeature(f) - subsymbol = QgsFillSymbol.createSimple({'color': '#0000ff', 'line_style': 'no'}) + subsymbol = QgsFillSymbol.createSimple({"color": "#0000ff", "line_style": "no"}) parent_generator = QgsGeometryGeneratorSymbolLayer.create( - {'geometryModifier': 'single_sided_buffer($geometry,-0.32, 1, 2)'}) + {"geometryModifier": "single_sided_buffer($geometry,-0.32, 1, 2)"} + ) parent_generator.setSymbolType(QgsSymbol.SymbolType.Fill) parent_generator.setSubSymbol(subsymbol) @@ -552,17 +643,19 @@ def test_clipped_results_with_z(self): mapsettings = QgsMapSettings(self.mapsettings) mapsettings.setDestinationCrs(lines.crs()) - mapsettings.setExtent(QgsRectangle(704433.77, 7060006.64, 704454.78, 7060027.95)) + mapsettings.setExtent( + QgsRectangle(704433.77, 7060006.64, 704454.78, 7060027.95) + ) mapsettings.setLayers([lines]) self.assertTrue( self.render_map_settings_check( - 'geometrygenerator_z_clipping', - 'geometrygenerator_z_clipping', - mapsettings + "geometrygenerator_z_clipping", + "geometrygenerator_z_clipping", + mapsettings, ) ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsgeometrypaintdevice.py b/tests/src/python/test_qgsgeometrypaintdevice.py index 36912b548527..5acf813770e6 100644 --- a/tests/src/python/test_qgsgeometrypaintdevice.py +++ b/tests/src/python/test_qgsgeometrypaintdevice.py @@ -5,23 +5,15 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2024 by Nyall Dawson' -__date__ = '21/05/2024' -__copyright__ = 'Copyright 2024, The QGIS Project' + +__author__ = "(C) 2024 by Nyall Dawson" +__date__ = "21/05/2024" +__copyright__ = "Copyright 2024, The QGIS Project" import os import unittest -from qgis.PyQt.QtCore import ( - Qt, - QSize, - QLine, - QLineF, - QPoint, - QPointF, - QRect, - QRectF -) +from qgis.PyQt.QtCore import Qt, QSize, QLine, QLineF, QPoint, QPointF, QRect, QRectF from qgis.PyQt.QtGui import ( QColor, QPainter, @@ -30,11 +22,9 @@ QPaintDevice, QPolygon, QPolygonF, - QPainterPath -) -from qgis.core import ( - QgsGeometryPaintDevice + QPainterPath, ) +from qgis.core import QgsGeometryPaintDevice from qgis.testing import start_app, QgisTestCase from utilities import unitTestDataPath, getTestFont @@ -66,56 +56,39 @@ def test_lines(self): device = QgsGeometryPaintDevice() painter = SafePainter(device) - painter.drawLines( - [QLineF(5.5, 10.7, 6.8, 12.9), - QLineF(15.5, 12.7, 3.8, 42.9)] - ) - painter.drawLine( - QLine(-4, -1, 2, 3) - ) + painter.drawLines([QLineF(5.5, 10.7, 6.8, 12.9), QLineF(15.5, 12.7, 3.8, 42.9)]) + painter.drawLine(QLine(-4, -1, 2, 3)) painter.end() result = device.geometry() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (LineString (15.5 12.7, 3.8 42.9),LineString (5.5 10.7, 6.8 12.9),LineString (-4 -1, 2 3))') - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), - 19) - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), - 43) + result.asWkt(2), + "GeometryCollection (LineString (15.5 12.7, 3.8 42.9),LineString (5.5 10.7, 6.8 12.9),LineString (-4 -1, 2 3))", + ) + + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), 19) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), 43) # with transform device = QgsGeometryPaintDevice() painter = SafePainter(device) - painter.setTransform( - QTransform.fromScale(2, 3) - ) + painter.setTransform(QTransform.fromScale(2, 3)) - painter.drawLine( - QLineF(5.5, 10.7, 6.8, 12.9) - ) - painter.drawLine( - QLineF(15.5, 12.7, 3.8, 42.9) - ) - painter.drawLine( - QLine(-4, -1, 2, 3) - ) + painter.drawLine(QLineF(5.5, 10.7, 6.8, 12.9)) + painter.drawLine(QLineF(15.5, 12.7, 3.8, 42.9)) + painter.drawLine(QLine(-4, -1, 2, 3)) painter.end() result = device.geometry() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (LineString (31 38.1, 7.6 128.7),LineString (11 32.1, 13.6 38.7),LineString (-8 -3, 4 9))') - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), - 39) self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), - 131) + result.asWkt(2), + "GeometryCollection (LineString (31 38.1, 7.6 128.7),LineString (11 32.1, 13.6 38.7),LineString (-8 -3, 4 9))", + ) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), 39) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), 131) def test_stroked_lines(self): """ @@ -128,84 +101,61 @@ def test_stroked_lines(self): pen.setCapStyle(Qt.PenCapStyle.FlatCap) painter.setPen(pen) - painter.drawLines( - [QLineF(5.5, 10.7, 6.8, 12.9), - QLineF(15.5, 12.7, 3.8, 42.9)] - ) - painter.drawLine( - QLine(-4, -1, 2, 3) - ) + painter.drawLines([QLineF(5.5, 10.7, 6.8, 12.9), QLineF(15.5, 12.7, 3.8, 42.9)]) + painter.drawLine(QLine(-4, -1, 2, 3)) painter.end() result = device.geometry() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Polygon ((4.85 11.08, 6.15 13.28, 7.45 12.52, 6.15 10.32, 4.85 11.08)),Polygon ((3.1 42.63, 4.5 43.17, 16.2 12.97, 14.8 12.43, 3.1 42.63)),Polygon ((-4.42 -0.38, 1.58 3.62, 2.42 2.38, -3.58 -1.62, -4.42 -0.38)))') - - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), - 20) self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), - 44) + result.asWkt(2), + "GeometryCollection (Polygon ((4.85 11.08, 6.15 13.28, 7.45 12.52, 6.15 10.32, 4.85 11.08)),Polygon ((3.1 42.63, 4.5 43.17, 16.2 12.97, 14.8 12.43, 3.1 42.63)),Polygon ((-4.42 -0.38, 1.58 3.62, 2.42 2.38, -3.58 -1.62, -4.42 -0.38)))", + ) + + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), 20) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), 44) # with transform device = QgsGeometryPaintDevice(usePathStroker=True) painter = SafePainter(device) painter.setPen(pen) - painter.setTransform( - QTransform.fromScale(2, 3) - ) + painter.setTransform(QTransform.fromScale(2, 3)) - painter.drawLine( - QLineF(5.5, 10.7, 6.8, 12.9) - ) - painter.drawLine( - QLineF(15.5, 12.7, 3.8, 42.9) - ) - painter.drawLine( - QLine(-4, -1, 2, 3) - ) + painter.drawLine(QLineF(5.5, 10.7, 6.8, 12.9)) + painter.drawLine(QLineF(15.5, 12.7, 3.8, 42.9)) + painter.drawLine(QLine(-4, -1, 2, 3)) painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Polygon ((9.71 33.24, 12.31 39.84, 14.89 37.56, 12.29 30.96, 9.71 33.24)),Polygon ((6.2 127.89, 9 129.51, 32.4 38.91, 29.6 37.29, 6.2 127.89)),Polygon ((-8.83 -1.13, 3.17 10.87, 4.83 7.13, -7.17 -4.87, -8.83 -1.13)))') - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), - 41) self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), - 134) + result.asWkt(2), + "GeometryCollection (Polygon ((9.71 33.24, 12.31 39.84, 14.89 37.56, 12.29 30.96, 9.71 33.24)),Polygon ((6.2 127.89, 9 129.51, 32.4 38.91, 29.6 37.29, 6.2 127.89)),Polygon ((-8.83 -1.13, 3.17 10.87, 4.83 7.13, -7.17 -4.87, -8.83 -1.13)))", + ) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), 41) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), 134) # with on the fly simplification device = QgsGeometryPaintDevice(usePathStroker=True) device.setSimplificationTolerance(5) painter = SafePainter(device) painter.setPen(pen) - painter.setTransform( - QTransform.fromScale(2, 3) - ) + painter.setTransform(QTransform.fromScale(2, 3)) - painter.drawLine( - QLineF(5.5, 10.7, 6.8, 12.9) - ) - painter.drawLine( - QLineF(15.5, 12.7, 3.8, 42.9) - ) - painter.drawLine( - QLine(-4, -1, 2, 3) - ) + painter.drawLine(QLineF(5.5, 10.7, 6.8, 12.9)) + painter.drawLine(QLineF(15.5, 12.7, 3.8, 42.9)) + painter.drawLine(QLine(-4, -1, 2, 3)) painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Polygon ((12.29 30.96, 12.31 39.84, 12.29 30.96)),Polygon ((6.2 127.89, 29.6 37.29, 6.2 127.89)),Polygon ((-7.17 -4.87, 3.17 10.87, -7.17 -4.87)))') + self.assertEqual( + result.asWkt(2), + "GeometryCollection (Polygon ((12.29 30.96, 12.31 39.84, 12.29 30.96)),Polygon ((6.2 127.89, 29.6 37.29, 6.2 127.89)),Polygon ((-7.17 -4.87, 3.17 10.87, -7.17 -4.87)))", + ) def test_points(self): """ @@ -214,61 +164,41 @@ def test_points(self): device = QgsGeometryPaintDevice() painter = SafePainter(device) - painter.drawPoints( - QPolygonF([QPointF(5.5, 10.7), - QPointF(6.8, 12.9)]) - ) - painter.drawPoint( - QPointF(15.5, 12.7) - ) - painter.drawPoint( - QPoint(-4, -1) - ) + painter.drawPoints(QPolygonF([QPointF(5.5, 10.7), QPointF(6.8, 12.9)])) + painter.drawPoint(QPointF(15.5, 12.7)) + painter.drawPoint(QPoint(-4, -1)) painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Point (15.5 12.7),Point (6.8 12.9),Point (5.5 10.7),Point (-4 -1))') - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), - 19) - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), - 13) + result.asWkt(2), + "GeometryCollection (Point (15.5 12.7),Point (6.8 12.9),Point (5.5 10.7),Point (-4 -1))", + ) + + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), 19) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), 13) # with transform device = QgsGeometryPaintDevice() painter = SafePainter(device) - painter.setTransform( - QTransform.fromScale(2, 3) - ) + painter.setTransform(QTransform.fromScale(2, 3)) - painter.drawPoints( - QPolygonF([QPointF(5.5, 10.7), - QPointF(6.8, 12.9)]) - ) - painter.drawPoint( - QPointF(15.5, 12.7) - ) - painter.drawPoint( - QPoint(-4, -1) - ) + painter.drawPoints(QPolygonF([QPointF(5.5, 10.7), QPointF(6.8, 12.9)])) + painter.drawPoint(QPointF(15.5, 12.7)) + painter.drawPoint(QPoint(-4, -1)) painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Point (31 38.1),Point (13.6 38.7),Point (11 32.1),Point (-8 -3))') self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), - 39) - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), - 41) + result.asWkt(2), + "GeometryCollection (Point (31 38.1),Point (13.6 38.7),Point (11 32.1),Point (-8 -3))", + ) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), 39) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), 41) def test_rects(self): """ @@ -277,54 +207,38 @@ def test_rects(self): device = QgsGeometryPaintDevice() painter = SafePainter(device) - painter.drawRects( - [QRectF(5.5, 10.7, 6.8, 12.9), - QRectF(15.5, 12.7, 3.8, 42.9)] - ) - painter.drawRect( - QRect(-4, -1, 2, 3) - ) + painter.drawRects([QRectF(5.5, 10.7, 6.8, 12.9), QRectF(15.5, 12.7, 3.8, 42.9)]) + painter.drawRect(QRect(-4, -1, 2, 3)) painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Polygon ((15.5 12.7, 15.5 55.6, 19.3 55.6, 19.3 12.7, 15.5 12.7)),Polygon ((5.5 10.7, 5.5 23.6, 12.3 23.6, 12.3 10.7, 5.5 10.7)),Polygon ((-4 -1, -4 1, -3 1, -3 -1, -4 -1)))') - - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), - 23) self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), - 56) + result.asWkt(2), + "GeometryCollection (Polygon ((15.5 12.7, 15.5 55.6, 19.3 55.6, 19.3 12.7, 15.5 12.7)),Polygon ((5.5 10.7, 5.5 23.6, 12.3 23.6, 12.3 10.7, 5.5 10.7)),Polygon ((-4 -1, -4 1, -3 1, -3 -1, -4 -1)))", + ) + + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), 23) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), 56) # with transform device = QgsGeometryPaintDevice() painter = SafePainter(device) - painter.setTransform( - QTransform.fromScale(2, 3) - ) + painter.setTransform(QTransform.fromScale(2, 3)) - painter.drawRects( - [QRectF(5.5, 10.7, 6.8, 12.9), - QRectF(15.5, 12.7, 3.8, 42.9)] - ) - painter.drawRect( - QRect(-4, -1, 2, 3) - ) + painter.drawRects([QRectF(5.5, 10.7, 6.8, 12.9), QRectF(15.5, 12.7, 3.8, 42.9)]) + painter.drawRect(QRect(-4, -1, 2, 3)) painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Polygon ((31 38.1, 31 166.8, 38.6 166.8, 38.6 38.1, 31 38.1)),Polygon ((11 32.1, 11 70.8, 24.6 70.8, 24.6 32.1, 11 32.1)),Polygon ((-8 -3, -8 3, -6 3, -6 -3, -8 -3)))') self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), - 46) - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), - 169) + result.asWkt(2), + "GeometryCollection (Polygon ((31 38.1, 31 166.8, 38.6 166.8, 38.6 38.1, 31 38.1)),Polygon ((11 32.1, 11 70.8, 24.6 70.8, 24.6 32.1, 11 32.1)),Polygon ((-8 -3, -8 3, -6 3, -6 -3, -8 -3)))", + ) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), 46) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), 169) def test_polygons(self): """ @@ -334,80 +248,83 @@ def test_polygons(self): painter = SafePainter(device) painter.drawPolygon( - QPolygonF([QPointF(5.5, 10.7), QPointF(6.8, 12.9), - QPointF(15.5, 12.7), QPointF(5.5, 10.7)])) - painter.drawPolyline( - QPolygonF([QPointF(-4, -1), QPointF(2, 3)]) - ) - painter.drawPolyline( - QPolygon([QPoint(14, 11), QPoint(22, 35)]) - ) + QPolygonF( + [ + QPointF(5.5, 10.7), + QPointF(6.8, 12.9), + QPointF(15.5, 12.7), + QPointF(5.5, 10.7), + ] + ) + ) + painter.drawPolyline(QPolygonF([QPointF(-4, -1), QPointF(2, 3)])) + painter.drawPolyline(QPolygon([QPoint(14, 11), QPoint(22, 35)])) painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Polygon ((5.5 10.7, 6.8 12.9, 15.5 12.7, 5.5 10.7)),LineString (14 11, 22 35),LineString (-4 -1, 2 3))') - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), - 26) - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), - 36) + result.asWkt(2), + "GeometryCollection (Polygon ((5.5 10.7, 6.8 12.9, 15.5 12.7, 5.5 10.7)),LineString (14 11, 22 35),LineString (-4 -1, 2 3))", + ) + + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), 26) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), 36) # with transform device = QgsGeometryPaintDevice() painter = SafePainter(device) - painter.setTransform( - QTransform.fromScale(2, 3) - ) + painter.setTransform(QTransform.fromScale(2, 3)) painter.drawPolygon( - QPolygonF([QPointF(5.5, 10.7), QPointF(6.8, 12.9), - QPointF(15.5, 12.7), QPointF(5.5, 10.7)])) - painter.drawPolyline( - QPolygonF([QPointF(-4, -1), QPointF(2, 3)]) - ) - painter.drawPolyline( - QPolygon([QPoint(14, 11), QPoint(22, 35)]) - ) + QPolygonF( + [ + QPointF(5.5, 10.7), + QPointF(6.8, 12.9), + QPointF(15.5, 12.7), + QPointF(5.5, 10.7), + ] + ) + ) + painter.drawPolyline(QPolygonF([QPointF(-4, -1), QPointF(2, 3)])) + painter.drawPolyline(QPolygon([QPoint(14, 11), QPoint(22, 35)])) painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Polygon ((11 32.1, 13.6 38.7, 31 38.1, 11 32.1)),LineString (28 33, 44 105),LineString (-8 -3, 4 9))') self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), - 52) - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), - 108) + result.asWkt(2), + "GeometryCollection (Polygon ((11 32.1, 13.6 38.7, 31 38.1, 11 32.1)),LineString (28 33, 44 105),LineString (-8 -3, 4 9))", + ) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), 52) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), 108) # with on the fly simplification device = QgsGeometryPaintDevice() device.setSimplificationTolerance(10) painter = SafePainter(device) - painter.setTransform( - QTransform.fromScale(2, 3) - ) + painter.setTransform(QTransform.fromScale(2, 3)) painter.drawPolygon( - QPolygonF([QPointF(5.5, 10.7), QPointF(6.8, 12.9), - QPointF(15.5, 12.7), QPointF(5.5, 10.7)])) - painter.drawPolyline( - QPolygonF([QPointF(-4, -1), QPointF(2, 3)]) - ) - painter.drawPolyline( - QPolygon([QPoint(14, 11), QPoint(22, 35)]) - ) + QPolygonF( + [ + QPointF(5.5, 10.7), + QPointF(6.8, 12.9), + QPointF(15.5, 12.7), + QPointF(5.5, 10.7), + ] + ) + ) + painter.drawPolyline(QPolygonF([QPointF(-4, -1), QPointF(2, 3)])) + painter.drawPolyline(QPolygon([QPoint(14, 11), QPoint(22, 35)])) painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Polygon ((11 32.1, 31 38.1, 11 32.1)),LineString (28 33, 44 105),LineString (-8 -3, 4 9))') + self.assertEqual( + result.asWkt(2), + "GeometryCollection (Polygon ((11 32.1, 31 38.1, 11 32.1)),LineString (28 33, 44 105),LineString (-8 -3, 4 9))", + ) def test_stroked_polygons(self): """ @@ -421,82 +338,85 @@ def test_stroked_polygons(self): painter.setPen(pen) painter.drawPolygon( - QPolygonF([QPointF(5.5, 10.7), QPointF(6.8, 12.9), - QPointF(15.5, 12.7), QPointF(5.5, 10.7)])) - painter.drawPolyline( - QPolygonF([QPointF(-4, -1), QPointF(2, 3)]) - ) - painter.drawPolyline( - QPolygon([QPoint(14, 11), QPoint(22, 35)]) - ) + QPolygonF( + [ + QPointF(5.5, 10.7), + QPointF(6.8, 12.9), + QPointF(15.5, 12.7), + QPointF(5.5, 10.7), + ] + ) + ) + painter.drawPolyline(QPolygonF([QPointF(-4, -1), QPointF(2, 3)])) + painter.drawPolyline(QPolygon([QPoint(14, 11), QPoint(22, 35)])) painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Polygon ((4.85 11.08, 6.15 13.28, 6.82 13.65, 15.52 13.45, 15.65 11.96, 5.65 9.96, 4.85 11.08),(7 11.76, 8.71 12.11, 7.22 12.14, 7 11.76)),Polygon ((13.29 11.24, 21.29 35.24, 22.71 34.76, 14.71 10.76, 13.29 11.24)),Polygon ((-4.42 -0.38, 1.58 3.62, 2.42 2.38, -3.58 -1.62, -4.42 -0.38)))') - - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), - 27) self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), - 36) + result.asWkt(2), + "GeometryCollection (Polygon ((4.85 11.08, 6.15 13.28, 6.82 13.65, 15.52 13.45, 15.65 11.96, 5.65 9.96, 4.85 11.08),(7 11.76, 8.71 12.11, 7.22 12.14, 7 11.76)),Polygon ((13.29 11.24, 21.29 35.24, 22.71 34.76, 14.71 10.76, 13.29 11.24)),Polygon ((-4.42 -0.38, 1.58 3.62, 2.42 2.38, -3.58 -1.62, -4.42 -0.38)))", + ) + + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), 27) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), 36) # with transform device = QgsGeometryPaintDevice(usePathStroker=True) painter = SafePainter(device) - painter.setTransform( - QTransform.fromScale(2, 3) - ) + painter.setTransform(QTransform.fromScale(2, 3)) painter.setPen(pen) painter.drawPolygon( - QPolygonF([QPointF(5.5, 10.7), QPointF(6.8, 12.9), - QPointF(15.5, 12.7), QPointF(5.5, 10.7)])) - painter.drawPolyline( - QPolygonF([QPointF(-4, -1), QPointF(2, 3)]) - ) - painter.drawPolyline( - QPolygon([QPoint(14, 11), QPoint(22, 35)]) - ) + QPolygonF( + [ + QPointF(5.5, 10.7), + QPointF(6.8, 12.9), + QPointF(15.5, 12.7), + QPointF(5.5, 10.7), + ] + ) + ) + painter.drawPolyline(QPolygonF([QPointF(-4, -1), QPointF(2, 3)])) + painter.drawPolyline(QPolygon([QPoint(14, 11), QPoint(22, 35)])) painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Polygon ((9.71 33.24, 12.31 39.84, 13.63 40.95, 31.03 40.35, 31.29 35.89, 11.29 29.89, 9.71 33.24),(14 35.29, 17.41 36.32, 14.44 36.42, 14 35.29)),Polygon ((26.58 33.71, 42.58 105.71, 45.42 104.29, 29.42 32.29, 26.58 33.71)),Polygon ((-8.83 -1.13, 3.17 10.87, 4.83 7.13, -7.17 -4.87, -8.83 -1.13)))') self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), - 54) - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), - 110) + result.asWkt(2), + "GeometryCollection (Polygon ((9.71 33.24, 12.31 39.84, 13.63 40.95, 31.03 40.35, 31.29 35.89, 11.29 29.89, 9.71 33.24),(14 35.29, 17.41 36.32, 14.44 36.42, 14 35.29)),Polygon ((26.58 33.71, 42.58 105.71, 45.42 104.29, 29.42 32.29, 26.58 33.71)),Polygon ((-8.83 -1.13, 3.17 10.87, 4.83 7.13, -7.17 -4.87, -8.83 -1.13)))", + ) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), 54) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), 110) # with on the fly simplification device = QgsGeometryPaintDevice(usePathStroker=True) device.setSimplificationTolerance(10) painter = SafePainter(device) - painter.setTransform( - QTransform.fromScale(2, 3) - ) + painter.setTransform(QTransform.fromScale(2, 3)) painter.setPen(pen) painter.drawPolygon( - QPolygonF([QPointF(5.5, 10.7), QPointF(6.8, 12.9), - QPointF(15.5, 12.7), QPointF(5.5, 10.7)])) - painter.drawPolyline( - QPolygonF([QPointF(-4, -1), QPointF(2, 3)]) - ) - painter.drawPolyline( - QPolygon([QPoint(14, 11), QPoint(22, 35)]) - ) + QPolygonF( + [ + QPointF(5.5, 10.7), + QPointF(6.8, 12.9), + QPointF(15.5, 12.7), + QPointF(5.5, 10.7), + ] + ) + ) + painter.drawPolyline(QPolygonF([QPointF(-4, -1), QPointF(2, 3)])) + painter.drawPolyline(QPolygon([QPoint(14, 11), QPoint(22, 35)])) painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Polygon ((29.42 32.29, 42.58 105.71, 29.42 32.29)),Polygon ((10.71 34.31, 30.71 40.31, 10.71 34.31)),Polygon ((-7.17 -4.87, 3.17 10.87, -7.17 -4.87)))') + self.assertEqual( + result.asWkt(2), + "GeometryCollection (Polygon ((29.42 32.29, 42.58 105.71, 29.42 32.29)),Polygon ((10.71 34.31, 30.71 40.31, 10.71 34.31)),Polygon ((-7.17 -4.87, 3.17 10.87, -7.17 -4.87)))", + ) def test_paths(self): """ @@ -516,52 +436,46 @@ def test_paths(self): painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Polygon ((5.5 10.7, 15.5 12.7, 13.07 3.39, 13.07 3.39, 12.99 3.27, 12.91 3.15, 12.82 3.03, 12.74 2.91, 12.65 2.8, 12.56 2.68, 12.47 2.57, 12.39 2.46, 12.3 2.35, 12.21 2.24, 12.11 2.13, 12.02 2.02, 11.93 1.92, 11.84 1.82, 11.74 1.72, 11.65 1.62, 11.55 1.52, 11.45 1.42, 11.35 1.33, 11.26 1.24, 11.16 1.14, 11.06 1.06, 10.95 0.97, 10.85 0.88, 10.75 0.8, 10.65 0.72, 10.54 0.63, 10.44 0.56, 10.33 0.48, 10.23 0.4, 5.5 10.7)))') - - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), - 10) self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), - 12) + result.asWkt(2), + "GeometryCollection (Polygon ((5.5 10.7, 15.5 12.7, 13.07 3.39, 13.07 3.39, 12.99 3.27, 12.91 3.15, 12.82 3.03, 12.74 2.91, 12.65 2.8, 12.56 2.68, 12.47 2.57, 12.39 2.46, 12.3 2.35, 12.21 2.24, 12.11 2.13, 12.02 2.02, 11.93 1.92, 11.84 1.82, 11.74 1.72, 11.65 1.62, 11.55 1.52, 11.45 1.42, 11.35 1.33, 11.26 1.24, 11.16 1.14, 11.06 1.06, 10.95 0.97, 10.85 0.88, 10.75 0.8, 10.65 0.72, 10.54 0.63, 10.44 0.56, 10.33 0.48, 10.23 0.4, 5.5 10.7)))", + ) + + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), 10) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), 12) # with transform device = QgsGeometryPaintDevice() painter = SafePainter(device) - painter.setTransform( - QTransform.fromScale(2, 3) - ) + painter.setTransform(QTransform.fromScale(2, 3)) painter.drawPath(path) painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Polygon ((11 32.1, 31 38.1, 26.14 10.18, 26.14 10.18, 25.98 9.81, 25.81 9.45, 25.64 9.09, 25.47 8.74, 25.3 8.39, 25.13 8.05, 24.95 7.71, 24.77 7.37, 24.59 7.04, 24.41 6.71, 24.23 6.39, 24.04 6.07, 23.86 5.76, 23.67 5.45, 23.48 5.15, 23.29 4.85, 23.1 4.56, 22.9 4.27, 22.71 3.99, 22.51 3.71, 22.31 3.43, 22.11 3.17, 21.91 2.9, 21.71 2.65, 21.5 2.39, 21.3 2.15, 21.09 1.9, 20.88 1.67, 20.67 1.43, 20.46 1.21, 11 32.1)))') self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), - 20) - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), - 36) + result.asWkt(2), + "GeometryCollection (Polygon ((11 32.1, 31 38.1, 26.14 10.18, 26.14 10.18, 25.98 9.81, 25.81 9.45, 25.64 9.09, 25.47 8.74, 25.3 8.39, 25.13 8.05, 24.95 7.71, 24.77 7.37, 24.59 7.04, 24.41 6.71, 24.23 6.39, 24.04 6.07, 23.86 5.76, 23.67 5.45, 23.48 5.15, 23.29 4.85, 23.1 4.56, 22.9 4.27, 22.71 3.99, 22.51 3.71, 22.31 3.43, 22.11 3.17, 21.91 2.9, 21.71 2.65, 21.5 2.39, 21.3 2.15, 21.09 1.9, 20.88 1.67, 20.67 1.43, 20.46 1.21, 11 32.1)))", + ) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), 20) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), 36) # with on the fly simplification device = QgsGeometryPaintDevice() device.setSimplificationTolerance(10) painter = SafePainter(device) - painter.setTransform( - QTransform.fromScale(2, 3) - ) + painter.setTransform(QTransform.fromScale(2, 3)) painter.drawPath(path) painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Polygon ((11 32.1, 31 38.1, 20.46 1.21, 11 32.1)))') + self.assertEqual( + result.asWkt(2), + "GeometryCollection (Polygon ((11 32.1, 31 38.1, 20.46 1.21, 11 32.1)))", + ) def test_stroked_paths(self): """ @@ -585,54 +499,48 @@ def test_stroked_paths(self): painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Polygon ((4.82 10.39, 5.35 11.44, 15.35 13.44, 16.23 12.51, 13.8 3.2, 13.69 2.97, 13.61 2.85, 13.61 2.85, 13.52 2.72, 13.52 2.72, 13.43 2.6, 13.43 2.59, 13.34 2.47, 13.34 2.47, 13.25 2.35, 13.25 2.34, 13.16 2.23, 13.16 2.22, 13.07 2.11, 13.06 2.1, 12.97 1.99, 12.97 1.98, 12.88 1.87, 12.87 1.87, 12.78 1.76, 12.78 1.75, 12.69 1.64, 12.68 1.64, 12.59 1.53, 12.58 1.52, 12.49 1.42, 12.48 1.41, 12.39 1.31, 12.38 1.3, 12.29 1.2, 12.28 1.2, 12.19 1.1, 12.18 1.09, 12.08 0.99, 12.08 0.99, 11.98 0.89, 11.97 0.88, 11.87 0.79, 11.87 0.78, 11.77 0.69, 11.76 0.68, 11.66 0.59, 11.66 0.59, 11.56 0.5, 11.55 0.49, 11.45 0.4, 11.44 0.4, 11.34 0.31, 11.33 0.3, 11.23 0.22, 11.22 0.21, 11.12 0.13, 11.11 0.12, 11 0.04, 11 0.04, 10.89 -0.04, 10.88 -0.05, 10.78 -0.13, 10.77 -0.13, 10.66 -0.21, 9.55 0.09, 4.82 10.39),(6.58 10.15, 10.51 1.58, 10.56 1.62, 10.65 1.7, 10.75 1.79, 10.84 1.87, 10.93 1.96, 11.02 2.05, 11.11 2.14, 11.2 2.23, 11.29 2.33, 11.37 2.42, 11.46 2.52, 11.55 2.62, 11.63 2.72, 11.72 2.82, 11.8 2.93, 11.88 3.03, 11.97 3.14, 12.05 3.25, 12.13 3.36, 12.21 3.47, 12.29 3.58, 12.37 3.69, 12.38 3.71, 14.47 11.73, 6.58 10.15)))') - - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), - 11) self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), - 13) + result.asWkt(2), + "GeometryCollection (Polygon ((4.82 10.39, 5.35 11.44, 15.35 13.44, 16.23 12.51, 13.8 3.2, 13.69 2.97, 13.61 2.85, 13.61 2.85, 13.52 2.72, 13.52 2.72, 13.43 2.6, 13.43 2.59, 13.34 2.47, 13.34 2.47, 13.25 2.35, 13.25 2.34, 13.16 2.23, 13.16 2.22, 13.07 2.11, 13.06 2.1, 12.97 1.99, 12.97 1.98, 12.88 1.87, 12.87 1.87, 12.78 1.76, 12.78 1.75, 12.69 1.64, 12.68 1.64, 12.59 1.53, 12.58 1.52, 12.49 1.42, 12.48 1.41, 12.39 1.31, 12.38 1.3, 12.29 1.2, 12.28 1.2, 12.19 1.1, 12.18 1.09, 12.08 0.99, 12.08 0.99, 11.98 0.89, 11.97 0.88, 11.87 0.79, 11.87 0.78, 11.77 0.69, 11.76 0.68, 11.66 0.59, 11.66 0.59, 11.56 0.5, 11.55 0.49, 11.45 0.4, 11.44 0.4, 11.34 0.31, 11.33 0.3, 11.23 0.22, 11.22 0.21, 11.12 0.13, 11.11 0.12, 11 0.04, 11 0.04, 10.89 -0.04, 10.88 -0.05, 10.78 -0.13, 10.77 -0.13, 10.66 -0.21, 9.55 0.09, 4.82 10.39),(6.58 10.15, 10.51 1.58, 10.56 1.62, 10.65 1.7, 10.75 1.79, 10.84 1.87, 10.93 1.96, 11.02 2.05, 11.11 2.14, 11.2 2.23, 11.29 2.33, 11.37 2.42, 11.46 2.52, 11.55 2.62, 11.63 2.72, 11.72 2.82, 11.8 2.93, 11.88 3.03, 11.97 3.14, 12.05 3.25, 12.13 3.36, 12.21 3.47, 12.29 3.58, 12.37 3.69, 12.38 3.71, 14.47 11.73, 6.58 10.15)))", + ) + + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), 11) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), 13) # with transform device = QgsGeometryPaintDevice(usePathStroker=True) painter = SafePainter(device) painter.setPen(pen) - painter.setTransform( - QTransform.fromScale(2, 3) - ) + painter.setTransform(QTransform.fromScale(2, 3)) painter.drawPath(path) painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Polygon ((9.64 31.16, 10.71 34.31, 30.71 40.31, 32.45 37.53, 27.59 9.61, 27.39 8.92, 27.22 8.56, 27.21 8.54, 27.05 8.17, 27.04 8.15, 26.87 7.8, 26.86 7.78, 26.69 7.42, 26.68 7.4, 26.51 7.05, 26.5 7.03, 26.32 6.69, 26.31 6.67, 26.14 6.33, 26.12 6.31, 25.95 5.97, 25.94 5.95, 25.76 5.62, 25.75 5.6, 25.57 5.27, 25.55 5.25, 25.37 4.93, 25.36 4.91, 25.18 4.59, 25.16 4.57, 24.98 4.26, 24.97 4.24, 24.78 3.93, 24.77 3.91, 24.58 3.61, 24.56 3.59, 24.37 3.29, 24.36 3.27, 24.17 2.98, 24.15 2.96, 23.96 2.67, 23.95 2.65, 23.75 2.37, 23.74 2.35, 23.54 2.07, 23.52 2.05, 23.33 1.78, 23.31 1.76, 23.11 1.49, 23.1 1.47, 22.89 1.2, 22.88 1.19, 22.67 0.93, 22.66 0.91, 22.45 0.66, 22.44 0.64, 22.23 0.39, 22.22 0.37, 22.01 0.13, 21.99 0.11, 21.78 -0.13, 21.77 -0.15, 21.56 -0.38, 21.54 -0.4, 21.33 -0.62, 19.09 0.27, 9.64 31.16),(13.16 30.45, 21.03 4.73, 21.12 4.85, 21.31 5.1, 21.49 5.36, 21.67 5.62, 21.86 5.88, 22.04 6.15, 22.22 6.42, 22.39 6.7, 22.57 6.98, 22.75 7.27, 22.92 7.56, 23.09 7.86, 23.26 8.16, 23.43 8.47, 23.6 8.78, 23.77 9.09, 23.93 9.41, 24.1 9.74, 24.26 10.07, 24.42 10.4, 24.58 10.74, 24.74 11.08, 24.76 11.12, 28.94 35.19, 13.16 30.45)))') - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), - 22) self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), - 40) + result.asWkt(2), + "GeometryCollection (Polygon ((9.64 31.16, 10.71 34.31, 30.71 40.31, 32.45 37.53, 27.59 9.61, 27.39 8.92, 27.22 8.56, 27.21 8.54, 27.05 8.17, 27.04 8.15, 26.87 7.8, 26.86 7.78, 26.69 7.42, 26.68 7.4, 26.51 7.05, 26.5 7.03, 26.32 6.69, 26.31 6.67, 26.14 6.33, 26.12 6.31, 25.95 5.97, 25.94 5.95, 25.76 5.62, 25.75 5.6, 25.57 5.27, 25.55 5.25, 25.37 4.93, 25.36 4.91, 25.18 4.59, 25.16 4.57, 24.98 4.26, 24.97 4.24, 24.78 3.93, 24.77 3.91, 24.58 3.61, 24.56 3.59, 24.37 3.29, 24.36 3.27, 24.17 2.98, 24.15 2.96, 23.96 2.67, 23.95 2.65, 23.75 2.37, 23.74 2.35, 23.54 2.07, 23.52 2.05, 23.33 1.78, 23.31 1.76, 23.11 1.49, 23.1 1.47, 22.89 1.2, 22.88 1.19, 22.67 0.93, 22.66 0.91, 22.45 0.66, 22.44 0.64, 22.23 0.39, 22.22 0.37, 22.01 0.13, 21.99 0.11, 21.78 -0.13, 21.77 -0.15, 21.56 -0.38, 21.54 -0.4, 21.33 -0.62, 19.09 0.27, 9.64 31.16),(13.16 30.45, 21.03 4.73, 21.12 4.85, 21.31 5.1, 21.49 5.36, 21.67 5.62, 21.86 5.88, 22.04 6.15, 22.22 6.42, 22.39 6.7, 22.57 6.98, 22.75 7.27, 22.92 7.56, 23.09 7.86, 23.26 8.16, 23.43 8.47, 23.6 8.78, 23.77 9.09, 23.93 9.41, 24.1 9.74, 24.26 10.07, 24.42 10.4, 24.58 10.74, 24.74 11.08, 24.76 11.12, 28.94 35.19, 13.16 30.45)))", + ) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), 22) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), 40) # with on the fly simplification device = QgsGeometryPaintDevice(usePathStroker=True) device.setSimplificationTolerance(10) painter = SafePainter(device) painter.setPen(pen) - painter.setTransform( - QTransform.fromScale(2, 3) - ) + painter.setTransform(QTransform.fromScale(2, 3)) painter.drawPath(path) painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Polygon ((9.64 31.16, 32.38 37.21, 21.83 0.32, 9.64 31.16),(13.16 30.45, 20.41 6.75, 28.5 35.05, 13.16 30.45)))') + self.assertEqual( + result.asWkt(2), + "GeometryCollection (Polygon ((9.64 31.16, 32.38 37.21, 21.83 0.32, 9.64 31.16),(13.16 30.45, 20.41 6.75, 28.5 35.05, 13.16 30.45)))", + ) def test_text(self): """ @@ -642,36 +550,37 @@ def test_text(self): """ device = QgsGeometryPaintDevice() painter = SafePainter(device) - font = getTestFont('bold') + font = getTestFont("bold") font.setPixelSize(40) painter.setFont(font) - painter.drawText(0, 0, 'abc') + painter.drawText(0, 0, "abc") painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), - 'GeometryCollection (Polygon ((57.33 -10.92, 57.33 -10.56, 57.34 -10.21, 57.36 -9.86, 57.39 -9.52, 57.42 -9.19, 57.46 -8.85, 57.51 -8.53, 57.57 -8.21, 57.63 -7.89, 57.7 -7.58, 57.78 -7.28, 57.86 -6.98, 57.96 -6.68, 58.06 -6.39, 58.16 -6.11, 58.28 -5.83, 58.4 -5.55, 58.53 -5.29, 58.67 -5.02, 58.81 -4.77, 58.97 -4.51, 59.13 -4.27, 59.29 -4.02, 59.47 -3.79, 59.65 -3.56, 59.84 -3.33, 60.04 -3.11, 60.24 -2.89, 60.45 -2.68, 60.67 -2.48, 60.9 -2.28, 61.13 -2.08, 61.37 -1.9, 61.61 -1.72, 61.86 -1.55, 62.11 -1.38, 62.37 -1.22, 62.64 -1.07, 62.91 -0.93, 63.19 -0.79, 63.47 -0.66, 63.76 -0.53, 64.05 -0.41, 64.35 -0.3, 64.66 -0.2, 64.97 -0.1, 65.28 -0.01, 65.61 0.08, 65.94 0.15, 66.27 0.22, 66.61 0.29, 66.95 0.35, 67.31 0.4, 67.66 0.44, 68.02 0.48, 68.39 0.51, 68.77 0.53, 69.15 0.55, 69.53 0.56, 69.92 0.56, 70.04 0.56, 70.15 0.56, 70.26 0.56, 70.38 0.56, 70.49 0.55, 70.6 0.55, 70.72 0.55, 70.83 0.54, 70.94 0.54, 71.06 0.53, 71.17 0.52, 71.28 0.51, 71.39 0.51, 71.51 0.5, 71.62 0.49, 71.73 0.48, 71.85 0.46, 71.96 0.45, 72.07 0.44, 72.19 0.43, 72.3 0.41, 72.41 0.4, 72.52 0.38, 72.64 0.37, 72.75 0.35, 72.86 0.33, 72.97 0.32, 73.09 0.3, 73.2 0.28, 73.31 0.26, 73.42 0.24, 73.54 0.22, 73.65 0.19, 73.76 0.17, 73.87 0.15, 73.99 0.12, 74.1 0.1, 74.21 0.07, 74.32 0.05, 74.43 0.02, 74.54 0, 74.66 -0.03, 74.77 -0.06, 74.88 -0.09, 74.99 -0.12, 75.1 -0.15, 75.21 -0.18, 75.32 -0.21, 75.43 -0.24, 75.54 -0.28, 75.65 -0.31, 75.76 -0.34, 75.87 -0.38, 75.98 -0.41, 76.09 -0.45, 76.2 -0.49, 76.31 -0.52, 76.42 -0.56, 76.53 -0.6, 76.64 -0.64, 76.64 -6.38, 76.56 -6.31, 76.47 -6.25, 76.39 -6.19, 76.3 -6.13, 76.22 -6.07, 76.13 -6.01, 76.05 -5.95, 75.96 -5.89, 75.87 -5.84, 75.78 -5.78, 75.69 -5.73, 75.61 -5.68, 75.52 -5.63, 75.43 -5.58, 75.34 -5.53, 75.25 -5.48, 75.15 -5.43, 75.06 -5.39, 74.97 -5.34, 74.88 -5.3, 74.78 -5.26, 74.69 -5.21, 74.6 -5.17, 74.5 -5.14, 74.41 -5.1, 74.31 -5.06, 74.21 -5.02, 74.12 -4.99, 74.02 -4.95, 73.92 -4.92, 73.82 -4.89, 73.73 -4.86, 73.63 -4.83, 73.53 -4.8, 73.43 -4.77, 73.33 -4.75, 73.23 -4.72, 73.13 -4.7, 73.03 -4.67, 72.92 -4.65, 72.82 -4.63, 72.72 -4.61, 72.62 -4.59, 72.51 -4.58, 72.41 -4.56, 72.31 -4.54, 72.2 -4.53, 72.1 -4.52, 71.99 -4.5, 71.89 -4.49, 71.78 -4.48, 71.68 -4.47, 71.57 -4.46, 71.46 -4.46, 71.35 -4.45, 71.25 -4.45, 71.14 -4.44, 71.03 -4.44, 70.92 -4.44, 70.81 -4.44, 70.62 -4.44, 70.43 -4.45, 70.24 -4.45, 70.05 -4.47, 69.87 -4.49, 69.69 -4.51, 69.51 -4.53, 69.34 -4.56, 69.17 -4.59, 69 -4.63, 68.83 -4.67, 68.67 -4.71, 68.51 -4.76, 68.35 -4.81, 68.2 -4.87, 68.05 -4.92, 67.9 -4.99, 67.76 -5.05, 67.61 -5.12, 67.48 -5.2, 67.34 -5.28, 67.21 -5.36, 67.08 -5.44, 66.95 -5.53, 66.82 -5.63, 66.7 -5.72, 66.58 -5.82, 66.47 -5.93, 66.35 -6.04, 66.24 -6.15, 66.14 -6.26, 66.03 -6.38, 65.93 -6.5, 65.84 -6.63, 65.74 -6.76, 65.65 -6.89, 65.57 -7.02, 65.49 -7.16, 65.41 -7.3, 65.34 -7.44, 65.26 -7.58, 65.2 -7.73, 65.13 -7.89, 65.07 -8.04, 65.02 -8.2, 64.96 -8.36, 64.92 -8.52, 64.87 -8.69, 64.83 -8.86, 64.79 -9.03, 64.76 -9.21, 64.73 -9.38, 64.7 -9.57, 64.67 -9.75, 64.65 -9.94, 64.64 -10.13, 64.63 -10.32, 64.62 -10.52, 64.61 -10.72, 64.61 -10.92, 64.61 -11.12, 64.62 -11.32, 64.63 -11.52, 64.64 -11.71, 64.65 -11.91, 64.67 -12.09, 64.7 -12.28, 64.73 -12.46, 64.76 -12.64, 64.79 -12.81, 64.83 -12.99, 64.87 -13.16, 64.92 -13.32, 64.96 -13.49, 65.02 -13.65, 65.07 -13.8, 65.13 -13.96, 65.2 -14.11, 65.26 -14.26, 65.34 -14.4, 65.41 -14.55, 65.49 -14.69, 65.57 -14.82, 65.65 -14.96, 65.74 -15.09, 65.84 -15.22, 65.93 -15.34, 66.03 -15.46, 66.14 -15.58, 66.24 -15.7, 66.35 -15.81, 66.47 -15.92, 66.58 -16.02, 66.7 -16.12, 66.82 -16.22, 66.95 -16.31, 67.08 -16.4, 67.21 -16.49, 67.34 -16.57, 67.48 -16.65, 67.61 -16.72, 67.76 -16.79, 67.9 -16.86, 68.05 -16.92, 68.2 -16.98, 68.35 -17.03, 68.51 -17.08, 68.67 -17.13, 68.83 -17.18, 69 -17.22, 69.17 -17.25, 69.34 -17.28, 69.51 -17.31, 69.69 -17.34, 69.87 -17.36, 70.05 -17.38, 70.24 -17.39, 70.43 -17.4, 70.62 -17.4, 70.81 -17.41, 70.91 -17.41, 71.02 -17.4, 71.12 -17.4, 71.22 -17.4, 71.32 -17.39, 71.42 -17.39, 71.52 -17.38, 71.62 -17.37, 71.72 -17.36, 71.82 -17.35, 71.92 -17.34, 72.02 -17.33, 72.12 -17.32, 72.22 -17.3, 72.32 -17.29, 72.42 -17.27, 72.52 -17.26, 72.62 -17.24, 72.71 -17.22, 72.81 -17.2, 72.91 -17.18, 73.01 -17.15, 73.11 -17.13, 73.2 -17.11, 73.3 -17.08, 73.4 -17.05, 73.49 -17.03, 73.59 -17, 73.69 -16.97, 73.78 -16.94, 73.88 -16.91, 73.97 -16.87, 74.07 -16.84, 74.16 -16.8, 74.26 -16.77, 74.36 -16.73, 74.45 -16.69, 74.55 -16.65, 74.64 -16.61, 74.74 -16.57, 74.83 -16.52, 74.93 -16.48, 75.02 -16.43, 75.12 -16.39, 75.21 -16.34, 75.31 -16.29, 75.41 -16.24, 75.5 -16.19, 75.6 -16.14, 75.69 -16.08, 75.79 -16.03, 75.88 -15.97, 75.98 -15.92, 76.07 -15.86, 76.17 -15.8, 76.26 -15.74, 76.36 -15.68, 76.45 -15.61, 76.55 -15.55, 76.64 -15.48, 76.64 -21.19, 76.53 -21.23, 76.42 -21.27, 76.31 -21.31, 76.2 -21.34, 76.09 -21.38, 75.98 -21.42, 75.87 -21.46, 75.76 -21.49, 75.65 -21.53, 75.53 -21.56, 75.42 -21.59, 75.31 -21.63, 75.2 -21.66, 75.09 -21.69, 74.98 -21.72, 74.87 -21.75, 74.76 -21.78, 74.65 -21.81, 74.54 -21.84, 74.43 -21.86, 74.31 -21.89, 74.2 -21.92, 74.09 -21.94, 73.98 -21.97, 73.87 -21.99, 73.76 -22.01, 73.65 -22.04, 73.54 -22.06, 73.42 -22.08, 73.31 -22.1, 73.2 -22.12, 73.09 -22.14, 72.98 -22.16, 72.87 -22.18, 72.75 -22.19, 72.64 -22.21, 72.53 -22.23, 72.42 -22.24, 72.31 -22.26, 72.19 -22.27, 72.08 -22.28, 71.97 -22.3, 71.85 -22.31, 71.74 -22.32, 71.63 -22.33, 71.52 -22.34, 71.4 -22.35, 71.29 -22.36, 71.18 -22.37, 71.06 -22.37, 70.95 -22.38, 70.84 -22.38, 70.72 -22.39, 70.61 -22.39, 70.49 -22.4, 70.38 -22.4, 70.27 -22.4, 70.15 -22.4, 70.04 -22.41, 69.92 -22.41, 69.53 -22.4, 69.15 -22.39, 68.77 -22.38, 68.39 -22.35, 68.02 -22.32, 67.66 -22.28, 67.31 -22.24, 66.95 -22.19, 66.61 -22.13, 66.27 -22.07, 65.94 -22, 65.61 -21.92, 65.28 -21.84, 64.97 -21.74, 64.66 -21.65, 64.35 -21.54, 64.05 -21.43, 63.76 -21.31, 63.47 -21.19, 63.19 -21.06, 62.91 -20.92, 62.64 -20.77, 62.37 -20.62, 62.11 -20.46, 61.86 -20.3, 61.61 -20.12, 61.37 -19.94, 61.13 -19.76, 60.9 -19.57, 60.67 -19.37, 60.45 -19.16, 60.24 -18.95, 60.04 -18.74, 59.84 -18.51, 59.65 -18.29, 59.47 -18.06, 59.29 -17.82, 59.13 -17.58, 58.97 -17.33, 58.81 -17.08, 58.67 -16.82, 58.53 -16.56, 58.4 -16.29, 58.28 -16.02, 58.16 -15.74, 58.06 -15.45, 57.96 -15.16, 57.86 -14.87, 57.78 -14.57, 57.7 -14.26, 57.63 -13.95, 57.57 -13.64, 57.51 -13.32, 57.46 -12.99, 57.42 -12.66, 57.39 -12.32, 57.36 -11.98, 57.34 -11.63, 57.33 -11.28, 57.33 -10.92)),Polygon ((1.72 -6.56, 1.72 -6.35, 1.73 -6.15, 1.74 -5.94, 1.76 -5.74, 1.78 -5.54, 1.8 -5.35, 1.83 -5.15, 1.87 -4.96, 1.91 -4.77, 1.95 -4.59, 2 -4.41, 2.06 -4.23, 2.12 -4.05, 2.18 -3.87, 2.25 -3.7, 2.32 -3.53, 2.4 -3.36, 2.48 -3.2, 2.57 -3.03, 2.66 -2.88, 2.76 -2.72, 2.86 -2.56, 2.96 -2.41, 3.07 -2.26, 3.19 -2.12, 3.31 -1.97, 3.43 -1.83, 3.56 -1.69, 3.7 -1.56, 3.84 -1.42, 3.98 -1.29, 4.12 -1.17, 4.27 -1.04, 4.42 -0.93, 4.58 -0.82, 4.73 -0.71, 4.89 -0.6, 5.06 -0.5, 5.22 -0.41, 5.39 -0.32, 5.56 -0.23, 5.74 -0.15, 5.91 -0.07, 6.09 0, 6.28 0.07, 6.46 0.13, 6.65 0.19, 6.84 0.25, 7.03 0.3, 7.23 0.34, 7.43 0.38, 7.63 0.42, 7.84 0.45, 8.05 0.48, 8.26 0.51, 8.47 0.53, 8.69 0.54, 8.91 0.55, 9.13 0.56, 9.36 0.56, 9.53 0.56, 9.69 0.56, 9.85 0.55, 10.02 0.55, 10.18 0.54, 10.34 0.53, 10.49 0.51, 10.65 0.5, 10.8 0.48, 10.95 0.46, 11.1 0.44, 11.25 0.42, 11.4 0.39, 11.54 0.37, 11.69 0.34, 11.83 0.3, 11.97 0.27, 12.11 0.24, 12.24 0.2, 12.38 0.16, 12.51 0.12, 12.64 0.08, 12.77 0.03, 12.9 -0.02, 13.03 -0.07, 13.15 -0.12, 13.27 -0.17, 13.4 -0.23, 13.51 -0.28, 13.63 -0.34, 13.75 -0.41, 13.87 -0.47, 13.98 -0.54, 14.1 -0.6, 14.21 -0.68, 14.32 -0.75, 14.43 -0.83, 14.55 -0.9, 14.66 -0.99, 14.77 -1.07, 14.87 -1.16, 14.98 -1.24, 15.09 -1.33, 15.2 -1.43, 15.3 -1.52, 15.41 -1.62, 15.51 -1.72, 15.62 -1.83, 15.72 -1.93, 15.82 -2.04, 15.92 -2.15, 16.02 -2.26, 16.12 -2.38, 16.22 -2.49, 16.32 -2.61, 16.42 -2.74, 16.51 -2.86, 16.61 -2.99, 16.7 -3.12, 16.8 -3.25, 16.8 0, 23.84 0, 23.84 -12.48, 23.84 -12.83, 23.83 -13.17, 23.82 -13.51, 23.8 -13.83, 23.77 -14.15, 23.74 -14.47, 23.7 -14.78, 23.66 -15.08, 23.61 -15.37, 23.55 -15.66, 23.49 -15.94, 23.42 -16.22, 23.35 -16.49, 23.27 -16.75, 23.19 -17.01, 23.1 -17.26, 23 -17.5, 22.9 -17.74, 22.79 -17.97, 22.68 -18.19, 22.56 -18.41, 22.43 -18.62, 22.3 -18.82, 22.16 -19.02, 22.02 -19.21, 21.87 -19.4, 21.72 -19.57, 21.56 -19.75, 21.39 -19.91, 21.22 -20.07, 21.04 -20.22, 20.85 -20.37, 20.66 -20.51, 20.46 -20.65, 20.25 -20.78, 20.04 -20.91, 19.81 -21.03, 19.58 -21.15, 19.35 -21.26, 19.1 -21.37, 18.85 -21.47, 18.59 -21.57, 18.32 -21.66, 18.05 -21.74, 17.77 -21.82, 17.48 -21.9, 17.19 -21.97, 16.88 -22.03, 16.57 -22.09, 16.25 -22.15, 15.93 -22.2, 15.6 -22.24, 15.26 -22.28, 14.91 -22.31, 14.55 -22.34, 14.19 -22.36, 13.82 -22.38, 13.45 -22.4, 13.06 -22.4, 12.67 -22.41, 12.52 -22.41, 12.37 -22.41, 12.22 -22.4, 12.07 -22.4, 11.92 -22.4, 11.77 -22.4, 11.61 -22.39, 11.46 -22.39, 11.31 -22.38, 11.16 -22.38, 11.01 -22.37, 10.86 -22.36, 10.71 -22.35, 10.56 -22.35, 10.41 -22.34, 10.26 -22.33, 10.1 -22.32, 9.95 -22.31, 9.8 -22.29, 9.65 -22.28, 9.5 -22.27, 9.35 -22.26, 9.2 -22.24, 9.05 -22.23, 8.9 -22.21, 8.74 -22.2, 8.59 -22.18, 8.44 -22.16, 8.29 -22.14, 8.14 -22.13, 7.99 -22.11, 7.84 -22.09, 7.69 -22.07, 7.54 -22.05, 7.39 -22.02, 7.24 -22, 7.09 -21.98, 6.93 -21.96, 6.78 -21.93, 6.63 -21.91, 6.48 -21.88, 6.33 -21.86, 6.18 -21.83, 6.03 -21.8, 5.88 -21.78, 5.73 -21.75, 5.58 -21.72, 5.43 -21.69, 5.28 -21.66, 5.13 -21.63, 4.98 -21.6, 4.83 -21.57, 4.69 -21.54, 4.54 -21.51, 4.39 -21.47, 4.24 -21.44, 4.09 -21.4, 3.94 -21.37, 3.79 -21.33, 3.64 -21.3, 3.64 -15.95, 3.75 -16.01, 3.86 -16.07, 3.97 -16.13, 4.09 -16.19, 4.2 -16.24, 4.31 -16.3, 4.43 -16.35, 4.54 -16.4, 4.66 -16.46, 4.78 -16.51, 4.89 -16.56, 5.01 -16.6, 5.13 -16.65, 5.25 -16.7, 5.37 -16.74, 5.49 -16.79, 5.61 -16.83, 5.73 -16.87, 5.85 -16.92, 5.97 -16.96, 6.09 -17, 6.22 -17.03, 6.34 -17.07, 6.47 -17.11, 6.59 -17.14, 6.72 -17.18, 6.84 -17.21, 6.97 -17.24, 7.1 -17.27, 7.23 -17.3, 7.36 -17.33, 7.49 -17.36, 7.62 -17.39, 7.75 -17.42, 7.88 -17.44, 8.01 -17.47, 8.14 -17.49, 8.28 -17.51, 8.41 -17.53, 8.55 -17.55, 8.68 -17.57, 8.82 -17.59, 8.96 -17.61, 9.1 -17.62, 9.24 -17.64, 9.38 -17.65, 9.52 -17.67, 9.66 -17.68, 9.8 -17.69, 9.94 -17.7, 10.09 -17.71, 10.23 -17.72, 10.37 -17.73, 10.52 -17.73, 10.67 -17.74, 10.81 -17.74, 10.96 -17.75, 11.11 -17.75, 11.26 -17.75, 11.41 -17.75, 11.59 -17.75, 11.77 -17.75, 11.95 -17.74, 12.12 -17.74, 12.29 -17.73, 12.46 -17.72, 12.62 -17.71, 12.78 -17.7, 12.94 -17.68, 13.1 -17.66, 13.25 -17.65, 13.4 -17.63, 13.54 -17.61, 13.68 -17.58, 13.82 -17.56, 13.95 -17.53, 14.08 -17.5, 14.21 -17.47, 14.34 -17.44, 14.46 -17.41, 14.58 -17.37, 14.69 -17.34, 14.8 -17.3, 14.91 -17.26, 15.02 -17.22, 15.12 -17.17, 15.22 -17.13, 15.31 -17.08, 15.4 -17.03, 15.49 -16.98, 15.58 -16.93, 15.66 -16.88, 15.74 -16.82, 15.82 -16.76, 15.89 -16.7, 15.96 -16.64, 16.03 -16.58, 16.1 -16.51, 16.16 -16.44, 16.22 -16.37, 16.27 -16.3, 16.33 -16.23, 16.38 -16.15, 16.43 -16.07, 16.47 -15.99, 16.51 -15.91, 16.55 -15.83, 16.59 -15.74, 16.62 -15.65, 16.65 -15.56, 16.68 -15.47, 16.7 -15.37, 16.73 -15.28, 16.74 -15.18, 16.76 -15.08, 16.77 -14.98, 16.78 -14.87, 16.79 -14.77, 16.8 -14.66, 16.8 -14.55, 16.8 -14, 12.67 -14, 12.3 -14, 11.93 -13.99, 11.57 -13.98, 11.22 -13.97, 10.87 -13.95, 10.53 -13.93, 10.2 -13.9, 9.87 -13.87, 9.55 -13.84, 9.24 -13.8, 8.93 -13.76, 8.63 -13.71, 8.33 -13.66, 8.05 -13.61, 7.77 -13.55, 7.49 -13.49, 7.23 -13.42, 6.97 -13.35, 6.71 -13.28, 6.47 -13.2, 6.23 -13.12, 5.99 -13.03, 5.77 -12.94, 5.55 -12.85, 5.33 -12.75, 5.13 -12.65, 4.93 -12.54, 4.73 -12.43, 4.55 -12.32, 4.37 -12.2, 4.19 -12.08, 4.03 -11.95, 3.86 -11.82, 3.71 -11.69, 3.56 -11.55, 3.41 -11.4, 3.28 -11.25, 3.14 -11.1, 3.02 -10.94, 2.9 -10.78, 2.78 -10.61, 2.67 -10.44, 2.57 -10.26, 2.47 -10.08, 2.38 -9.89, 2.3 -9.7, 2.22 -9.51, 2.14 -9.31, 2.07 -9.11, 2.01 -8.9, 1.96 -8.68, 1.91 -8.47, 1.86 -8.24, 1.82 -8.02, 1.79 -7.79, 1.77 -7.55, 1.75 -7.31, 1.73 -7.07, 1.72 -6.82, 1.72 -6.56),(8.77 -6.92, 8.77 -7.02, 8.77 -7.11, 8.78 -7.2, 8.79 -7.29, 8.8 -7.38, 8.81 -7.47, 8.83 -7.55, 8.84 -7.64, 8.87 -7.72, 8.89 -7.8, 8.91 -7.88, 8.94 -7.96, 8.97 -8.04, 9.01 -8.11, 9.04 -8.19, 9.08 -8.26, 9.12 -8.33, 9.17 -8.4, 9.21 -8.46, 9.26 -8.53, 9.31 -8.59, 9.36 -8.66, 9.42 -8.72, 9.48 -8.78, 9.54 -8.83, 9.6 -8.89, 9.66 -8.95, 9.73 -9, 9.8 -9.05, 9.88 -9.1, 9.95 -9.15, 10.03 -9.2, 10.11 -9.24, 10.19 -9.29, 10.27 -9.33, 10.36 -9.37, 10.45 -9.41, 10.54 -9.44, 10.64 -9.48, 10.73 -9.51, 10.83 -9.55, 10.94 -9.58, 11.04 -9.61, 11.15 -9.63, 11.25 -9.66, 11.37 -9.68, 11.48 -9.7, 11.59 -9.73, 11.71 -9.74, 11.83 -9.76, 11.96 -9.78, 12.08 -9.79, 12.21 -9.8, 12.34 -9.81, 12.47 -9.82, 12.61 -9.83, 12.75 -9.84, 12.88 -9.84, 13.03 -9.84, 13.17 -9.84, 16.8 -9.84, 16.8 -9.05, 16.8 -8.91, 16.79 -8.77, 16.78 -8.63, 16.77 -8.49, 16.76 -8.36, 16.74 -8.23, 16.72 -8.09, 16.7 -7.96, 16.68 -7.84, 16.65 -7.71, 16.62 -7.58, 16.58 -7.46, 16.54 -7.34, 16.5 -7.22, 16.46 -7.1, 16.41 -6.98, 16.37 -6.86, 16.31 -6.75, 16.26 -6.64, 16.2 -6.53, 16.14 -6.42, 16.07 -6.31, 16.01 -6.2, 15.94 -6.1, 15.86 -5.99, 15.79 -5.89, 15.71 -5.79, 15.63 -5.69, 15.54 -5.6, 15.45 -5.5, 15.36 -5.41, 15.27 -5.32, 15.18 -5.23, 15.08 -5.15, 14.99 -5.07, 14.89 -4.99, 14.79 -4.91, 14.69 -4.84, 14.59 -4.77, 14.49 -4.71, 14.38 -4.65, 14.28 -4.59, 14.17 -4.53, 14.06 -4.48, 13.95 -4.43, 13.84 -4.39, 13.72 -4.35, 13.61 -4.31, 13.49 -4.27, 13.38 -4.24, 13.26 -4.21, 13.14 -4.18, 13.02 -4.16, 12.89 -4.14, 12.77 -4.12, 12.64 -4.1, 12.52 -4.09, 12.39 -4.08, 12.26 -4.08, 12.13 -4.08, 12.02 -4.08, 11.92 -4.08, 11.82 -4.09, 11.72 -4.09, 11.62 -4.1, 11.52 -4.11, 11.43 -4.12, 11.33 -4.13, 11.24 -4.15, 11.15 -4.16, 11.06 -4.18, 10.97 -4.2, 10.89 -4.22, 10.8 -4.24, 10.72 -4.27, 10.64 -4.29, 10.56 -4.32, 10.48 -4.35, 10.4 -4.38, 10.33 -4.41, 10.25 -4.45, 10.18 -4.49, 10.11 -4.52, 10.04 -4.56, 9.97 -4.6, 9.91 -4.65, 9.84 -4.69, 9.78 -4.74, 9.72 -4.79, 9.66 -4.84, 9.6 -4.89, 9.54 -4.94, 9.49 -4.99, 9.43 -5.05, 9.38 -5.1, 9.34 -5.16, 9.29 -5.22, 9.24 -5.28, 9.2 -5.34, 9.16 -5.4, 9.12 -5.47, 9.09 -5.53, 9.05 -5.6, 9.02 -5.67, 8.99 -5.74, 8.96 -5.81, 8.93 -5.88, 8.91 -5.95, 8.89 -6.02, 8.86 -6.1, 8.85 -6.18, 8.83 -6.25, 8.81 -6.33, 8.8 -6.41, 8.79 -6.5, 8.78 -6.58, 8.77 -6.66, 8.77 -6.75, 8.77 -6.83, 8.77 -6.92)),Polygon ((30.34 -30.39, 30.34 0, 37.34 0, 37.34 -3.17, 37.44 -3.04, 37.54 -2.92, 37.63 -2.8, 37.73 -2.68, 37.83 -2.56, 37.93 -2.44, 38.03 -2.33, 38.13 -2.22, 38.24 -2.11, 38.34 -2, 38.44 -1.9, 38.55 -1.8, 38.65 -1.7, 38.76 -1.6, 38.86 -1.5, 38.97 -1.41, 39.08 -1.32, 39.18 -1.23, 39.29 -1.14, 39.4 -1.06, 39.51 -0.98, 39.62 -0.9, 39.74 -0.82, 39.85 -0.75, 39.96 -0.67, 40.08 -0.6, 40.19 -0.54, 40.31 -0.47, 40.42 -0.41, 40.54 -0.34, 40.66 -0.28, 40.78 -0.23, 40.9 -0.17, 41.02 -0.12, 41.14 -0.07, 41.26 -0.02, 41.39 0.03, 41.51 0.08, 41.64 0.12, 41.77 0.16, 41.9 0.2, 42.03 0.24, 42.16 0.27, 42.29 0.3, 42.43 0.34, 42.56 0.37, 42.7 0.39, 42.84 0.42, 42.98 0.44, 43.12 0.46, 43.26 0.48, 43.4 0.5, 43.54 0.51, 43.69 0.53, 43.83 0.54, 43.98 0.55, 44.13 0.55, 44.28 0.56, 44.43 0.56, 44.58 0.56, 44.85 0.56, 45.11 0.55, 45.37 0.53, 45.63 0.51, 45.89 0.47, 46.14 0.43, 46.39 0.39, 46.63 0.33, 46.88 0.27, 47.12 0.21, 47.35 0.13, 47.58 0.05, 47.81 -0.04, 48.04 -0.14, 48.26 -0.24, 48.48 -0.35, 48.7 -0.47, 48.91 -0.59, 49.12 -0.73, 49.33 -0.86, 49.54 -1.01, 49.74 -1.16, 49.93 -1.32, 50.13 -1.49, 50.32 -1.67, 50.51 -1.85, 50.69 -2.04, 50.87 -2.23, 51.05 -2.44, 51.23 -2.65, 51.4 -2.86, 51.56 -3.08, 51.72 -3.31, 51.87 -3.54, 52.02 -3.77, 52.16 -4.01, 52.3 -4.25, 52.43 -4.49, 52.55 -4.74, 52.67 -4.99, 52.78 -5.25, 52.89 -5.51, 52.99 -5.78, 53.09 -6.05, 53.18 -6.32, 53.26 -6.6, 53.34 -6.88, 53.41 -7.17, 53.48 -7.46, 53.54 -7.75, 53.59 -8.05, 53.64 -8.35, 53.69 -8.66, 53.72 -8.97, 53.76 -9.29, 53.78 -9.6, 53.8 -9.93, 53.82 -10.26, 53.83 -10.59, 53.83 -10.92, 53.83 -11.26, 53.82 -11.59, 53.8 -11.92, 53.78 -12.24, 53.76 -12.56, 53.72 -12.87, 53.69 -13.18, 53.64 -13.49, 53.59 -13.79, 53.54 -14.09, 53.48 -14.39, 53.41 -14.68, 53.34 -14.96, 53.26 -15.24, 53.18 -15.52, 53.09 -15.8, 52.99 -16.06, 52.89 -16.33, 52.78 -16.59, 52.67 -16.85, 52.55 -17.1, 52.43 -17.35, 52.3 -17.6, 52.16 -17.84, 52.02 -18.07, 51.87 -18.31, 51.72 -18.53, 51.56 -18.76, 51.4 -18.98, 51.23 -19.2, 51.05 -19.41, 50.87 -19.61, 50.69 -19.81, 50.51 -19.99, 50.32 -20.18, 50.13 -20.35, 49.93 -20.52, 49.74 -20.68, 49.54 -20.83, 49.33 -20.98, 49.12 -21.12, 48.91 -21.25, 48.7 -21.38, 48.48 -21.49, 48.26 -21.6, 48.04 -21.71, 47.81 -21.8, 47.58 -21.89, 47.35 -21.97, 47.12 -22.05, 46.88 -22.12, 46.63 -22.18, 46.39 -22.23, 46.14 -22.28, 45.89 -22.32, 45.63 -22.35, 45.37 -22.37, 45.11 -22.39, 44.85 -22.4, 44.58 -22.41, 44.43 -22.41, 44.28 -22.4, 44.13 -22.4, 43.98 -22.39, 43.83 -22.38, 43.69 -22.37, 43.54 -22.36, 43.4 -22.34, 43.26 -22.32, 43.12 -22.31, 42.98 -22.28, 42.84 -22.26, 42.7 -22.24, 42.56 -22.21, 42.43 -22.18, 42.29 -22.15, 42.16 -22.12, 42.03 -22.08, 41.9 -22.04, 41.77 -22, 41.64 -21.96, 41.51 -21.92, 41.39 -21.87, 41.26 -21.83, 41.14 -21.78, 41.02 -21.73, 40.9 -21.67, 40.78 -21.62, 40.66 -21.56, 40.54 -21.5, 40.42 -21.44, 40.31 -21.37, 40.19 -21.31, 40.08 -21.24, 39.96 -21.17, 39.85 -21.1, 39.74 -21.02, 39.62 -20.94, 39.51 -20.86, 39.4 -20.78, 39.29 -20.7, 39.18 -20.61, 39.08 -20.52, 38.97 -20.43, 38.86 -20.34, 38.76 -20.24, 38.65 -20.15, 38.55 -20.05, 38.44 -19.94, 38.34 -19.84, 38.24 -19.73, 38.13 -19.62, 38.03 -19.51, 37.93 -19.4, 37.83 -19.28, 37.73 -19.17, 37.63 -19.05, 37.54 -18.92, 37.44 -18.8, 37.34 -18.67, 37.34 -30.39, 30.34 -30.39),(37.34 -10.92, 37.35 -11.13, 37.35 -11.33, 37.36 -11.53, 37.37 -11.73, 37.38 -11.92, 37.39 -12.11, 37.41 -12.29, 37.43 -12.48, 37.45 -12.66, 37.48 -12.83, 37.5 -13.01, 37.54 -13.18, 37.57 -13.34, 37.6 -13.51, 37.64 -13.67, 37.68 -13.82, 37.73 -13.98, 37.77 -14.13, 37.82 -14.27, 37.88 -14.42, 37.93 -14.56, 37.99 -14.7, 38.05 -14.83, 38.11 -14.96, 38.17 -15.09, 38.24 -15.21, 38.31 -15.34, 38.38 -15.45, 38.46 -15.57, 38.54 -15.68, 38.62 -15.79, 38.7 -15.89, 38.79 -15.99, 38.88 -16.09, 38.97 -16.18, 39.06 -16.27, 39.15 -16.36, 39.25 -16.44, 39.35 -16.52, 39.45 -16.6, 39.56 -16.67, 39.66 -16.73, 39.77 -16.8, 39.88 -16.86, 40 -16.92, 40.11 -16.97, 40.23 -17.02, 40.35 -17.06, 40.48 -17.11, 40.6 -17.14, 40.73 -17.18, 40.86 -17.21, 40.99 -17.24, 41.13 -17.26, 41.26 -17.28, 41.4 -17.3, 41.54 -17.31, 41.69 -17.32, 41.84 -17.33, 41.98 -17.33, 42.13 -17.33, 42.28 -17.32, 42.42 -17.31, 42.57 -17.3, 42.7 -17.28, 42.84 -17.26, 42.98 -17.24, 43.11 -17.21, 43.24 -17.18, 43.37 -17.15, 43.49 -17.11, 43.61 -17.07, 43.73 -17.02, 43.85 -16.97, 43.97 -16.92, 44.08 -16.86, 44.19 -16.8, 44.3 -16.74, 44.41 -16.67, 44.51 -16.6, 44.61 -16.52, 44.71 -16.45, 44.81 -16.36, 44.9 -16.28, 44.99 -16.19, 45.08 -16.1, 45.17 -16, 45.25 -15.9, 45.33 -15.8, 45.41 -15.69, 45.49 -15.58, 45.57 -15.46, 45.64 -15.34, 45.71 -15.22, 45.77 -15.1, 45.84 -14.97, 45.9 -14.84, 45.96 -14.71, 46.02 -14.57, 46.07 -14.43, 46.12 -14.28, 46.17 -14.14, 46.21 -13.99, 46.26 -13.83, 46.3 -13.68, 46.34 -13.52, 46.37 -13.35, 46.41 -13.18, 46.44 -13.01, 46.46 -12.84, 46.49 -12.66, 46.51 -12.48, 46.53 -12.3, 46.55 -12.11, 46.56 -11.92, 46.57 -11.73, 46.58 -11.53, 46.59 -11.33, 46.59 -11.13, 46.59 -10.92, 46.59 -10.72, 46.59 -10.51, 46.58 -10.31, 46.57 -10.11, 46.56 -9.92, 46.55 -9.73, 46.53 -9.54, 46.51 -9.36, 46.49 -9.18, 46.46 -9, 46.44 -8.83, 46.41 -8.66, 46.37 -8.49, 46.34 -8.33, 46.3 -8.17, 46.26 -8.01, 46.21 -7.86, 46.17 -7.71, 46.12 -7.56, 46.07 -7.41, 46.02 -7.27, 45.96 -7.14, 45.9 -7, 45.84 -6.87, 45.77 -6.74, 45.71 -6.62, 45.64 -6.5, 45.57 -6.38, 45.49 -6.27, 45.41 -6.16, 45.33 -6.05, 45.25 -5.94, 45.17 -5.84, 45.08 -5.75, 44.99 -5.65, 44.9 -5.57, 44.81 -5.48, 44.71 -5.4, 44.61 -5.32, 44.51 -5.24, 44.41 -5.17, 44.3 -5.11, 44.19 -5.04, 44.08 -4.98, 43.97 -4.93, 43.85 -4.87, 43.73 -4.82, 43.61 -4.78, 43.49 -4.74, 43.37 -4.7, 43.24 -4.66, 43.11 -4.63, 42.98 -4.6, 42.84 -4.58, 42.7 -4.56, 42.57 -4.54, 42.42 -4.53, 42.28 -4.52, 42.13 -4.52, 41.98 -4.52, 41.84 -4.52, 41.69 -4.52, 41.54 -4.53, 41.4 -4.54, 41.26 -4.56, 41.13 -4.58, 40.99 -4.61, 40.86 -4.63, 40.73 -4.66, 40.6 -4.7, 40.48 -4.74, 40.35 -4.78, 40.23 -4.83, 40.11 -4.87, 40 -4.93, 39.88 -4.98, 39.77 -5.04, 39.66 -5.11, 39.56 -5.18, 39.45 -5.25, 39.35 -5.32, 39.25 -5.4, 39.15 -5.48, 39.06 -5.57, 38.97 -5.66, 38.88 -5.75, 38.79 -5.85, 38.7 -5.95, 38.62 -6.06, 38.54 -6.16, 38.46 -6.28, 38.39 -6.39, 38.31 -6.51, 38.24 -6.63, 38.17 -6.75, 38.11 -6.88, 38.05 -7.01, 37.99 -7.15, 37.93 -7.28, 37.88 -7.43, 37.82 -7.57, 37.77 -7.72, 37.73 -7.87, 37.68 -8.02, 37.64 -8.18, 37.6 -8.34, 37.57 -8.5, 37.54 -8.67, 37.5 -8.84, 37.48 -9.01, 37.45 -9.19, 37.43 -9.37, 37.41 -9.55, 37.39 -9.74, 37.38 -9.93, 37.37 -10.12, 37.36 -10.31, 37.35 -10.51, 37.35 -10.72, 37.34 -10.92)))') - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), - 74) - self.assertEqual( - device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), - 30) + result.asWkt(2), + "GeometryCollection (Polygon ((57.33 -10.92, 57.33 -10.56, 57.34 -10.21, 57.36 -9.86, 57.39 -9.52, 57.42 -9.19, 57.46 -8.85, 57.51 -8.53, 57.57 -8.21, 57.63 -7.89, 57.7 -7.58, 57.78 -7.28, 57.86 -6.98, 57.96 -6.68, 58.06 -6.39, 58.16 -6.11, 58.28 -5.83, 58.4 -5.55, 58.53 -5.29, 58.67 -5.02, 58.81 -4.77, 58.97 -4.51, 59.13 -4.27, 59.29 -4.02, 59.47 -3.79, 59.65 -3.56, 59.84 -3.33, 60.04 -3.11, 60.24 -2.89, 60.45 -2.68, 60.67 -2.48, 60.9 -2.28, 61.13 -2.08, 61.37 -1.9, 61.61 -1.72, 61.86 -1.55, 62.11 -1.38, 62.37 -1.22, 62.64 -1.07, 62.91 -0.93, 63.19 -0.79, 63.47 -0.66, 63.76 -0.53, 64.05 -0.41, 64.35 -0.3, 64.66 -0.2, 64.97 -0.1, 65.28 -0.01, 65.61 0.08, 65.94 0.15, 66.27 0.22, 66.61 0.29, 66.95 0.35, 67.31 0.4, 67.66 0.44, 68.02 0.48, 68.39 0.51, 68.77 0.53, 69.15 0.55, 69.53 0.56, 69.92 0.56, 70.04 0.56, 70.15 0.56, 70.26 0.56, 70.38 0.56, 70.49 0.55, 70.6 0.55, 70.72 0.55, 70.83 0.54, 70.94 0.54, 71.06 0.53, 71.17 0.52, 71.28 0.51, 71.39 0.51, 71.51 0.5, 71.62 0.49, 71.73 0.48, 71.85 0.46, 71.96 0.45, 72.07 0.44, 72.19 0.43, 72.3 0.41, 72.41 0.4, 72.52 0.38, 72.64 0.37, 72.75 0.35, 72.86 0.33, 72.97 0.32, 73.09 0.3, 73.2 0.28, 73.31 0.26, 73.42 0.24, 73.54 0.22, 73.65 0.19, 73.76 0.17, 73.87 0.15, 73.99 0.12, 74.1 0.1, 74.21 0.07, 74.32 0.05, 74.43 0.02, 74.54 0, 74.66 -0.03, 74.77 -0.06, 74.88 -0.09, 74.99 -0.12, 75.1 -0.15, 75.21 -0.18, 75.32 -0.21, 75.43 -0.24, 75.54 -0.28, 75.65 -0.31, 75.76 -0.34, 75.87 -0.38, 75.98 -0.41, 76.09 -0.45, 76.2 -0.49, 76.31 -0.52, 76.42 -0.56, 76.53 -0.6, 76.64 -0.64, 76.64 -6.38, 76.56 -6.31, 76.47 -6.25, 76.39 -6.19, 76.3 -6.13, 76.22 -6.07, 76.13 -6.01, 76.05 -5.95, 75.96 -5.89, 75.87 -5.84, 75.78 -5.78, 75.69 -5.73, 75.61 -5.68, 75.52 -5.63, 75.43 -5.58, 75.34 -5.53, 75.25 -5.48, 75.15 -5.43, 75.06 -5.39, 74.97 -5.34, 74.88 -5.3, 74.78 -5.26, 74.69 -5.21, 74.6 -5.17, 74.5 -5.14, 74.41 -5.1, 74.31 -5.06, 74.21 -5.02, 74.12 -4.99, 74.02 -4.95, 73.92 -4.92, 73.82 -4.89, 73.73 -4.86, 73.63 -4.83, 73.53 -4.8, 73.43 -4.77, 73.33 -4.75, 73.23 -4.72, 73.13 -4.7, 73.03 -4.67, 72.92 -4.65, 72.82 -4.63, 72.72 -4.61, 72.62 -4.59, 72.51 -4.58, 72.41 -4.56, 72.31 -4.54, 72.2 -4.53, 72.1 -4.52, 71.99 -4.5, 71.89 -4.49, 71.78 -4.48, 71.68 -4.47, 71.57 -4.46, 71.46 -4.46, 71.35 -4.45, 71.25 -4.45, 71.14 -4.44, 71.03 -4.44, 70.92 -4.44, 70.81 -4.44, 70.62 -4.44, 70.43 -4.45, 70.24 -4.45, 70.05 -4.47, 69.87 -4.49, 69.69 -4.51, 69.51 -4.53, 69.34 -4.56, 69.17 -4.59, 69 -4.63, 68.83 -4.67, 68.67 -4.71, 68.51 -4.76, 68.35 -4.81, 68.2 -4.87, 68.05 -4.92, 67.9 -4.99, 67.76 -5.05, 67.61 -5.12, 67.48 -5.2, 67.34 -5.28, 67.21 -5.36, 67.08 -5.44, 66.95 -5.53, 66.82 -5.63, 66.7 -5.72, 66.58 -5.82, 66.47 -5.93, 66.35 -6.04, 66.24 -6.15, 66.14 -6.26, 66.03 -6.38, 65.93 -6.5, 65.84 -6.63, 65.74 -6.76, 65.65 -6.89, 65.57 -7.02, 65.49 -7.16, 65.41 -7.3, 65.34 -7.44, 65.26 -7.58, 65.2 -7.73, 65.13 -7.89, 65.07 -8.04, 65.02 -8.2, 64.96 -8.36, 64.92 -8.52, 64.87 -8.69, 64.83 -8.86, 64.79 -9.03, 64.76 -9.21, 64.73 -9.38, 64.7 -9.57, 64.67 -9.75, 64.65 -9.94, 64.64 -10.13, 64.63 -10.32, 64.62 -10.52, 64.61 -10.72, 64.61 -10.92, 64.61 -11.12, 64.62 -11.32, 64.63 -11.52, 64.64 -11.71, 64.65 -11.91, 64.67 -12.09, 64.7 -12.28, 64.73 -12.46, 64.76 -12.64, 64.79 -12.81, 64.83 -12.99, 64.87 -13.16, 64.92 -13.32, 64.96 -13.49, 65.02 -13.65, 65.07 -13.8, 65.13 -13.96, 65.2 -14.11, 65.26 -14.26, 65.34 -14.4, 65.41 -14.55, 65.49 -14.69, 65.57 -14.82, 65.65 -14.96, 65.74 -15.09, 65.84 -15.22, 65.93 -15.34, 66.03 -15.46, 66.14 -15.58, 66.24 -15.7, 66.35 -15.81, 66.47 -15.92, 66.58 -16.02, 66.7 -16.12, 66.82 -16.22, 66.95 -16.31, 67.08 -16.4, 67.21 -16.49, 67.34 -16.57, 67.48 -16.65, 67.61 -16.72, 67.76 -16.79, 67.9 -16.86, 68.05 -16.92, 68.2 -16.98, 68.35 -17.03, 68.51 -17.08, 68.67 -17.13, 68.83 -17.18, 69 -17.22, 69.17 -17.25, 69.34 -17.28, 69.51 -17.31, 69.69 -17.34, 69.87 -17.36, 70.05 -17.38, 70.24 -17.39, 70.43 -17.4, 70.62 -17.4, 70.81 -17.41, 70.91 -17.41, 71.02 -17.4, 71.12 -17.4, 71.22 -17.4, 71.32 -17.39, 71.42 -17.39, 71.52 -17.38, 71.62 -17.37, 71.72 -17.36, 71.82 -17.35, 71.92 -17.34, 72.02 -17.33, 72.12 -17.32, 72.22 -17.3, 72.32 -17.29, 72.42 -17.27, 72.52 -17.26, 72.62 -17.24, 72.71 -17.22, 72.81 -17.2, 72.91 -17.18, 73.01 -17.15, 73.11 -17.13, 73.2 -17.11, 73.3 -17.08, 73.4 -17.05, 73.49 -17.03, 73.59 -17, 73.69 -16.97, 73.78 -16.94, 73.88 -16.91, 73.97 -16.87, 74.07 -16.84, 74.16 -16.8, 74.26 -16.77, 74.36 -16.73, 74.45 -16.69, 74.55 -16.65, 74.64 -16.61, 74.74 -16.57, 74.83 -16.52, 74.93 -16.48, 75.02 -16.43, 75.12 -16.39, 75.21 -16.34, 75.31 -16.29, 75.41 -16.24, 75.5 -16.19, 75.6 -16.14, 75.69 -16.08, 75.79 -16.03, 75.88 -15.97, 75.98 -15.92, 76.07 -15.86, 76.17 -15.8, 76.26 -15.74, 76.36 -15.68, 76.45 -15.61, 76.55 -15.55, 76.64 -15.48, 76.64 -21.19, 76.53 -21.23, 76.42 -21.27, 76.31 -21.31, 76.2 -21.34, 76.09 -21.38, 75.98 -21.42, 75.87 -21.46, 75.76 -21.49, 75.65 -21.53, 75.53 -21.56, 75.42 -21.59, 75.31 -21.63, 75.2 -21.66, 75.09 -21.69, 74.98 -21.72, 74.87 -21.75, 74.76 -21.78, 74.65 -21.81, 74.54 -21.84, 74.43 -21.86, 74.31 -21.89, 74.2 -21.92, 74.09 -21.94, 73.98 -21.97, 73.87 -21.99, 73.76 -22.01, 73.65 -22.04, 73.54 -22.06, 73.42 -22.08, 73.31 -22.1, 73.2 -22.12, 73.09 -22.14, 72.98 -22.16, 72.87 -22.18, 72.75 -22.19, 72.64 -22.21, 72.53 -22.23, 72.42 -22.24, 72.31 -22.26, 72.19 -22.27, 72.08 -22.28, 71.97 -22.3, 71.85 -22.31, 71.74 -22.32, 71.63 -22.33, 71.52 -22.34, 71.4 -22.35, 71.29 -22.36, 71.18 -22.37, 71.06 -22.37, 70.95 -22.38, 70.84 -22.38, 70.72 -22.39, 70.61 -22.39, 70.49 -22.4, 70.38 -22.4, 70.27 -22.4, 70.15 -22.4, 70.04 -22.41, 69.92 -22.41, 69.53 -22.4, 69.15 -22.39, 68.77 -22.38, 68.39 -22.35, 68.02 -22.32, 67.66 -22.28, 67.31 -22.24, 66.95 -22.19, 66.61 -22.13, 66.27 -22.07, 65.94 -22, 65.61 -21.92, 65.28 -21.84, 64.97 -21.74, 64.66 -21.65, 64.35 -21.54, 64.05 -21.43, 63.76 -21.31, 63.47 -21.19, 63.19 -21.06, 62.91 -20.92, 62.64 -20.77, 62.37 -20.62, 62.11 -20.46, 61.86 -20.3, 61.61 -20.12, 61.37 -19.94, 61.13 -19.76, 60.9 -19.57, 60.67 -19.37, 60.45 -19.16, 60.24 -18.95, 60.04 -18.74, 59.84 -18.51, 59.65 -18.29, 59.47 -18.06, 59.29 -17.82, 59.13 -17.58, 58.97 -17.33, 58.81 -17.08, 58.67 -16.82, 58.53 -16.56, 58.4 -16.29, 58.28 -16.02, 58.16 -15.74, 58.06 -15.45, 57.96 -15.16, 57.86 -14.87, 57.78 -14.57, 57.7 -14.26, 57.63 -13.95, 57.57 -13.64, 57.51 -13.32, 57.46 -12.99, 57.42 -12.66, 57.39 -12.32, 57.36 -11.98, 57.34 -11.63, 57.33 -11.28, 57.33 -10.92)),Polygon ((1.72 -6.56, 1.72 -6.35, 1.73 -6.15, 1.74 -5.94, 1.76 -5.74, 1.78 -5.54, 1.8 -5.35, 1.83 -5.15, 1.87 -4.96, 1.91 -4.77, 1.95 -4.59, 2 -4.41, 2.06 -4.23, 2.12 -4.05, 2.18 -3.87, 2.25 -3.7, 2.32 -3.53, 2.4 -3.36, 2.48 -3.2, 2.57 -3.03, 2.66 -2.88, 2.76 -2.72, 2.86 -2.56, 2.96 -2.41, 3.07 -2.26, 3.19 -2.12, 3.31 -1.97, 3.43 -1.83, 3.56 -1.69, 3.7 -1.56, 3.84 -1.42, 3.98 -1.29, 4.12 -1.17, 4.27 -1.04, 4.42 -0.93, 4.58 -0.82, 4.73 -0.71, 4.89 -0.6, 5.06 -0.5, 5.22 -0.41, 5.39 -0.32, 5.56 -0.23, 5.74 -0.15, 5.91 -0.07, 6.09 0, 6.28 0.07, 6.46 0.13, 6.65 0.19, 6.84 0.25, 7.03 0.3, 7.23 0.34, 7.43 0.38, 7.63 0.42, 7.84 0.45, 8.05 0.48, 8.26 0.51, 8.47 0.53, 8.69 0.54, 8.91 0.55, 9.13 0.56, 9.36 0.56, 9.53 0.56, 9.69 0.56, 9.85 0.55, 10.02 0.55, 10.18 0.54, 10.34 0.53, 10.49 0.51, 10.65 0.5, 10.8 0.48, 10.95 0.46, 11.1 0.44, 11.25 0.42, 11.4 0.39, 11.54 0.37, 11.69 0.34, 11.83 0.3, 11.97 0.27, 12.11 0.24, 12.24 0.2, 12.38 0.16, 12.51 0.12, 12.64 0.08, 12.77 0.03, 12.9 -0.02, 13.03 -0.07, 13.15 -0.12, 13.27 -0.17, 13.4 -0.23, 13.51 -0.28, 13.63 -0.34, 13.75 -0.41, 13.87 -0.47, 13.98 -0.54, 14.1 -0.6, 14.21 -0.68, 14.32 -0.75, 14.43 -0.83, 14.55 -0.9, 14.66 -0.99, 14.77 -1.07, 14.87 -1.16, 14.98 -1.24, 15.09 -1.33, 15.2 -1.43, 15.3 -1.52, 15.41 -1.62, 15.51 -1.72, 15.62 -1.83, 15.72 -1.93, 15.82 -2.04, 15.92 -2.15, 16.02 -2.26, 16.12 -2.38, 16.22 -2.49, 16.32 -2.61, 16.42 -2.74, 16.51 -2.86, 16.61 -2.99, 16.7 -3.12, 16.8 -3.25, 16.8 0, 23.84 0, 23.84 -12.48, 23.84 -12.83, 23.83 -13.17, 23.82 -13.51, 23.8 -13.83, 23.77 -14.15, 23.74 -14.47, 23.7 -14.78, 23.66 -15.08, 23.61 -15.37, 23.55 -15.66, 23.49 -15.94, 23.42 -16.22, 23.35 -16.49, 23.27 -16.75, 23.19 -17.01, 23.1 -17.26, 23 -17.5, 22.9 -17.74, 22.79 -17.97, 22.68 -18.19, 22.56 -18.41, 22.43 -18.62, 22.3 -18.82, 22.16 -19.02, 22.02 -19.21, 21.87 -19.4, 21.72 -19.57, 21.56 -19.75, 21.39 -19.91, 21.22 -20.07, 21.04 -20.22, 20.85 -20.37, 20.66 -20.51, 20.46 -20.65, 20.25 -20.78, 20.04 -20.91, 19.81 -21.03, 19.58 -21.15, 19.35 -21.26, 19.1 -21.37, 18.85 -21.47, 18.59 -21.57, 18.32 -21.66, 18.05 -21.74, 17.77 -21.82, 17.48 -21.9, 17.19 -21.97, 16.88 -22.03, 16.57 -22.09, 16.25 -22.15, 15.93 -22.2, 15.6 -22.24, 15.26 -22.28, 14.91 -22.31, 14.55 -22.34, 14.19 -22.36, 13.82 -22.38, 13.45 -22.4, 13.06 -22.4, 12.67 -22.41, 12.52 -22.41, 12.37 -22.41, 12.22 -22.4, 12.07 -22.4, 11.92 -22.4, 11.77 -22.4, 11.61 -22.39, 11.46 -22.39, 11.31 -22.38, 11.16 -22.38, 11.01 -22.37, 10.86 -22.36, 10.71 -22.35, 10.56 -22.35, 10.41 -22.34, 10.26 -22.33, 10.1 -22.32, 9.95 -22.31, 9.8 -22.29, 9.65 -22.28, 9.5 -22.27, 9.35 -22.26, 9.2 -22.24, 9.05 -22.23, 8.9 -22.21, 8.74 -22.2, 8.59 -22.18, 8.44 -22.16, 8.29 -22.14, 8.14 -22.13, 7.99 -22.11, 7.84 -22.09, 7.69 -22.07, 7.54 -22.05, 7.39 -22.02, 7.24 -22, 7.09 -21.98, 6.93 -21.96, 6.78 -21.93, 6.63 -21.91, 6.48 -21.88, 6.33 -21.86, 6.18 -21.83, 6.03 -21.8, 5.88 -21.78, 5.73 -21.75, 5.58 -21.72, 5.43 -21.69, 5.28 -21.66, 5.13 -21.63, 4.98 -21.6, 4.83 -21.57, 4.69 -21.54, 4.54 -21.51, 4.39 -21.47, 4.24 -21.44, 4.09 -21.4, 3.94 -21.37, 3.79 -21.33, 3.64 -21.3, 3.64 -15.95, 3.75 -16.01, 3.86 -16.07, 3.97 -16.13, 4.09 -16.19, 4.2 -16.24, 4.31 -16.3, 4.43 -16.35, 4.54 -16.4, 4.66 -16.46, 4.78 -16.51, 4.89 -16.56, 5.01 -16.6, 5.13 -16.65, 5.25 -16.7, 5.37 -16.74, 5.49 -16.79, 5.61 -16.83, 5.73 -16.87, 5.85 -16.92, 5.97 -16.96, 6.09 -17, 6.22 -17.03, 6.34 -17.07, 6.47 -17.11, 6.59 -17.14, 6.72 -17.18, 6.84 -17.21, 6.97 -17.24, 7.1 -17.27, 7.23 -17.3, 7.36 -17.33, 7.49 -17.36, 7.62 -17.39, 7.75 -17.42, 7.88 -17.44, 8.01 -17.47, 8.14 -17.49, 8.28 -17.51, 8.41 -17.53, 8.55 -17.55, 8.68 -17.57, 8.82 -17.59, 8.96 -17.61, 9.1 -17.62, 9.24 -17.64, 9.38 -17.65, 9.52 -17.67, 9.66 -17.68, 9.8 -17.69, 9.94 -17.7, 10.09 -17.71, 10.23 -17.72, 10.37 -17.73, 10.52 -17.73, 10.67 -17.74, 10.81 -17.74, 10.96 -17.75, 11.11 -17.75, 11.26 -17.75, 11.41 -17.75, 11.59 -17.75, 11.77 -17.75, 11.95 -17.74, 12.12 -17.74, 12.29 -17.73, 12.46 -17.72, 12.62 -17.71, 12.78 -17.7, 12.94 -17.68, 13.1 -17.66, 13.25 -17.65, 13.4 -17.63, 13.54 -17.61, 13.68 -17.58, 13.82 -17.56, 13.95 -17.53, 14.08 -17.5, 14.21 -17.47, 14.34 -17.44, 14.46 -17.41, 14.58 -17.37, 14.69 -17.34, 14.8 -17.3, 14.91 -17.26, 15.02 -17.22, 15.12 -17.17, 15.22 -17.13, 15.31 -17.08, 15.4 -17.03, 15.49 -16.98, 15.58 -16.93, 15.66 -16.88, 15.74 -16.82, 15.82 -16.76, 15.89 -16.7, 15.96 -16.64, 16.03 -16.58, 16.1 -16.51, 16.16 -16.44, 16.22 -16.37, 16.27 -16.3, 16.33 -16.23, 16.38 -16.15, 16.43 -16.07, 16.47 -15.99, 16.51 -15.91, 16.55 -15.83, 16.59 -15.74, 16.62 -15.65, 16.65 -15.56, 16.68 -15.47, 16.7 -15.37, 16.73 -15.28, 16.74 -15.18, 16.76 -15.08, 16.77 -14.98, 16.78 -14.87, 16.79 -14.77, 16.8 -14.66, 16.8 -14.55, 16.8 -14, 12.67 -14, 12.3 -14, 11.93 -13.99, 11.57 -13.98, 11.22 -13.97, 10.87 -13.95, 10.53 -13.93, 10.2 -13.9, 9.87 -13.87, 9.55 -13.84, 9.24 -13.8, 8.93 -13.76, 8.63 -13.71, 8.33 -13.66, 8.05 -13.61, 7.77 -13.55, 7.49 -13.49, 7.23 -13.42, 6.97 -13.35, 6.71 -13.28, 6.47 -13.2, 6.23 -13.12, 5.99 -13.03, 5.77 -12.94, 5.55 -12.85, 5.33 -12.75, 5.13 -12.65, 4.93 -12.54, 4.73 -12.43, 4.55 -12.32, 4.37 -12.2, 4.19 -12.08, 4.03 -11.95, 3.86 -11.82, 3.71 -11.69, 3.56 -11.55, 3.41 -11.4, 3.28 -11.25, 3.14 -11.1, 3.02 -10.94, 2.9 -10.78, 2.78 -10.61, 2.67 -10.44, 2.57 -10.26, 2.47 -10.08, 2.38 -9.89, 2.3 -9.7, 2.22 -9.51, 2.14 -9.31, 2.07 -9.11, 2.01 -8.9, 1.96 -8.68, 1.91 -8.47, 1.86 -8.24, 1.82 -8.02, 1.79 -7.79, 1.77 -7.55, 1.75 -7.31, 1.73 -7.07, 1.72 -6.82, 1.72 -6.56),(8.77 -6.92, 8.77 -7.02, 8.77 -7.11, 8.78 -7.2, 8.79 -7.29, 8.8 -7.38, 8.81 -7.47, 8.83 -7.55, 8.84 -7.64, 8.87 -7.72, 8.89 -7.8, 8.91 -7.88, 8.94 -7.96, 8.97 -8.04, 9.01 -8.11, 9.04 -8.19, 9.08 -8.26, 9.12 -8.33, 9.17 -8.4, 9.21 -8.46, 9.26 -8.53, 9.31 -8.59, 9.36 -8.66, 9.42 -8.72, 9.48 -8.78, 9.54 -8.83, 9.6 -8.89, 9.66 -8.95, 9.73 -9, 9.8 -9.05, 9.88 -9.1, 9.95 -9.15, 10.03 -9.2, 10.11 -9.24, 10.19 -9.29, 10.27 -9.33, 10.36 -9.37, 10.45 -9.41, 10.54 -9.44, 10.64 -9.48, 10.73 -9.51, 10.83 -9.55, 10.94 -9.58, 11.04 -9.61, 11.15 -9.63, 11.25 -9.66, 11.37 -9.68, 11.48 -9.7, 11.59 -9.73, 11.71 -9.74, 11.83 -9.76, 11.96 -9.78, 12.08 -9.79, 12.21 -9.8, 12.34 -9.81, 12.47 -9.82, 12.61 -9.83, 12.75 -9.84, 12.88 -9.84, 13.03 -9.84, 13.17 -9.84, 16.8 -9.84, 16.8 -9.05, 16.8 -8.91, 16.79 -8.77, 16.78 -8.63, 16.77 -8.49, 16.76 -8.36, 16.74 -8.23, 16.72 -8.09, 16.7 -7.96, 16.68 -7.84, 16.65 -7.71, 16.62 -7.58, 16.58 -7.46, 16.54 -7.34, 16.5 -7.22, 16.46 -7.1, 16.41 -6.98, 16.37 -6.86, 16.31 -6.75, 16.26 -6.64, 16.2 -6.53, 16.14 -6.42, 16.07 -6.31, 16.01 -6.2, 15.94 -6.1, 15.86 -5.99, 15.79 -5.89, 15.71 -5.79, 15.63 -5.69, 15.54 -5.6, 15.45 -5.5, 15.36 -5.41, 15.27 -5.32, 15.18 -5.23, 15.08 -5.15, 14.99 -5.07, 14.89 -4.99, 14.79 -4.91, 14.69 -4.84, 14.59 -4.77, 14.49 -4.71, 14.38 -4.65, 14.28 -4.59, 14.17 -4.53, 14.06 -4.48, 13.95 -4.43, 13.84 -4.39, 13.72 -4.35, 13.61 -4.31, 13.49 -4.27, 13.38 -4.24, 13.26 -4.21, 13.14 -4.18, 13.02 -4.16, 12.89 -4.14, 12.77 -4.12, 12.64 -4.1, 12.52 -4.09, 12.39 -4.08, 12.26 -4.08, 12.13 -4.08, 12.02 -4.08, 11.92 -4.08, 11.82 -4.09, 11.72 -4.09, 11.62 -4.1, 11.52 -4.11, 11.43 -4.12, 11.33 -4.13, 11.24 -4.15, 11.15 -4.16, 11.06 -4.18, 10.97 -4.2, 10.89 -4.22, 10.8 -4.24, 10.72 -4.27, 10.64 -4.29, 10.56 -4.32, 10.48 -4.35, 10.4 -4.38, 10.33 -4.41, 10.25 -4.45, 10.18 -4.49, 10.11 -4.52, 10.04 -4.56, 9.97 -4.6, 9.91 -4.65, 9.84 -4.69, 9.78 -4.74, 9.72 -4.79, 9.66 -4.84, 9.6 -4.89, 9.54 -4.94, 9.49 -4.99, 9.43 -5.05, 9.38 -5.1, 9.34 -5.16, 9.29 -5.22, 9.24 -5.28, 9.2 -5.34, 9.16 -5.4, 9.12 -5.47, 9.09 -5.53, 9.05 -5.6, 9.02 -5.67, 8.99 -5.74, 8.96 -5.81, 8.93 -5.88, 8.91 -5.95, 8.89 -6.02, 8.86 -6.1, 8.85 -6.18, 8.83 -6.25, 8.81 -6.33, 8.8 -6.41, 8.79 -6.5, 8.78 -6.58, 8.77 -6.66, 8.77 -6.75, 8.77 -6.83, 8.77 -6.92)),Polygon ((30.34 -30.39, 30.34 0, 37.34 0, 37.34 -3.17, 37.44 -3.04, 37.54 -2.92, 37.63 -2.8, 37.73 -2.68, 37.83 -2.56, 37.93 -2.44, 38.03 -2.33, 38.13 -2.22, 38.24 -2.11, 38.34 -2, 38.44 -1.9, 38.55 -1.8, 38.65 -1.7, 38.76 -1.6, 38.86 -1.5, 38.97 -1.41, 39.08 -1.32, 39.18 -1.23, 39.29 -1.14, 39.4 -1.06, 39.51 -0.98, 39.62 -0.9, 39.74 -0.82, 39.85 -0.75, 39.96 -0.67, 40.08 -0.6, 40.19 -0.54, 40.31 -0.47, 40.42 -0.41, 40.54 -0.34, 40.66 -0.28, 40.78 -0.23, 40.9 -0.17, 41.02 -0.12, 41.14 -0.07, 41.26 -0.02, 41.39 0.03, 41.51 0.08, 41.64 0.12, 41.77 0.16, 41.9 0.2, 42.03 0.24, 42.16 0.27, 42.29 0.3, 42.43 0.34, 42.56 0.37, 42.7 0.39, 42.84 0.42, 42.98 0.44, 43.12 0.46, 43.26 0.48, 43.4 0.5, 43.54 0.51, 43.69 0.53, 43.83 0.54, 43.98 0.55, 44.13 0.55, 44.28 0.56, 44.43 0.56, 44.58 0.56, 44.85 0.56, 45.11 0.55, 45.37 0.53, 45.63 0.51, 45.89 0.47, 46.14 0.43, 46.39 0.39, 46.63 0.33, 46.88 0.27, 47.12 0.21, 47.35 0.13, 47.58 0.05, 47.81 -0.04, 48.04 -0.14, 48.26 -0.24, 48.48 -0.35, 48.7 -0.47, 48.91 -0.59, 49.12 -0.73, 49.33 -0.86, 49.54 -1.01, 49.74 -1.16, 49.93 -1.32, 50.13 -1.49, 50.32 -1.67, 50.51 -1.85, 50.69 -2.04, 50.87 -2.23, 51.05 -2.44, 51.23 -2.65, 51.4 -2.86, 51.56 -3.08, 51.72 -3.31, 51.87 -3.54, 52.02 -3.77, 52.16 -4.01, 52.3 -4.25, 52.43 -4.49, 52.55 -4.74, 52.67 -4.99, 52.78 -5.25, 52.89 -5.51, 52.99 -5.78, 53.09 -6.05, 53.18 -6.32, 53.26 -6.6, 53.34 -6.88, 53.41 -7.17, 53.48 -7.46, 53.54 -7.75, 53.59 -8.05, 53.64 -8.35, 53.69 -8.66, 53.72 -8.97, 53.76 -9.29, 53.78 -9.6, 53.8 -9.93, 53.82 -10.26, 53.83 -10.59, 53.83 -10.92, 53.83 -11.26, 53.82 -11.59, 53.8 -11.92, 53.78 -12.24, 53.76 -12.56, 53.72 -12.87, 53.69 -13.18, 53.64 -13.49, 53.59 -13.79, 53.54 -14.09, 53.48 -14.39, 53.41 -14.68, 53.34 -14.96, 53.26 -15.24, 53.18 -15.52, 53.09 -15.8, 52.99 -16.06, 52.89 -16.33, 52.78 -16.59, 52.67 -16.85, 52.55 -17.1, 52.43 -17.35, 52.3 -17.6, 52.16 -17.84, 52.02 -18.07, 51.87 -18.31, 51.72 -18.53, 51.56 -18.76, 51.4 -18.98, 51.23 -19.2, 51.05 -19.41, 50.87 -19.61, 50.69 -19.81, 50.51 -19.99, 50.32 -20.18, 50.13 -20.35, 49.93 -20.52, 49.74 -20.68, 49.54 -20.83, 49.33 -20.98, 49.12 -21.12, 48.91 -21.25, 48.7 -21.38, 48.48 -21.49, 48.26 -21.6, 48.04 -21.71, 47.81 -21.8, 47.58 -21.89, 47.35 -21.97, 47.12 -22.05, 46.88 -22.12, 46.63 -22.18, 46.39 -22.23, 46.14 -22.28, 45.89 -22.32, 45.63 -22.35, 45.37 -22.37, 45.11 -22.39, 44.85 -22.4, 44.58 -22.41, 44.43 -22.41, 44.28 -22.4, 44.13 -22.4, 43.98 -22.39, 43.83 -22.38, 43.69 -22.37, 43.54 -22.36, 43.4 -22.34, 43.26 -22.32, 43.12 -22.31, 42.98 -22.28, 42.84 -22.26, 42.7 -22.24, 42.56 -22.21, 42.43 -22.18, 42.29 -22.15, 42.16 -22.12, 42.03 -22.08, 41.9 -22.04, 41.77 -22, 41.64 -21.96, 41.51 -21.92, 41.39 -21.87, 41.26 -21.83, 41.14 -21.78, 41.02 -21.73, 40.9 -21.67, 40.78 -21.62, 40.66 -21.56, 40.54 -21.5, 40.42 -21.44, 40.31 -21.37, 40.19 -21.31, 40.08 -21.24, 39.96 -21.17, 39.85 -21.1, 39.74 -21.02, 39.62 -20.94, 39.51 -20.86, 39.4 -20.78, 39.29 -20.7, 39.18 -20.61, 39.08 -20.52, 38.97 -20.43, 38.86 -20.34, 38.76 -20.24, 38.65 -20.15, 38.55 -20.05, 38.44 -19.94, 38.34 -19.84, 38.24 -19.73, 38.13 -19.62, 38.03 -19.51, 37.93 -19.4, 37.83 -19.28, 37.73 -19.17, 37.63 -19.05, 37.54 -18.92, 37.44 -18.8, 37.34 -18.67, 37.34 -30.39, 30.34 -30.39),(37.34 -10.92, 37.35 -11.13, 37.35 -11.33, 37.36 -11.53, 37.37 -11.73, 37.38 -11.92, 37.39 -12.11, 37.41 -12.29, 37.43 -12.48, 37.45 -12.66, 37.48 -12.83, 37.5 -13.01, 37.54 -13.18, 37.57 -13.34, 37.6 -13.51, 37.64 -13.67, 37.68 -13.82, 37.73 -13.98, 37.77 -14.13, 37.82 -14.27, 37.88 -14.42, 37.93 -14.56, 37.99 -14.7, 38.05 -14.83, 38.11 -14.96, 38.17 -15.09, 38.24 -15.21, 38.31 -15.34, 38.38 -15.45, 38.46 -15.57, 38.54 -15.68, 38.62 -15.79, 38.7 -15.89, 38.79 -15.99, 38.88 -16.09, 38.97 -16.18, 39.06 -16.27, 39.15 -16.36, 39.25 -16.44, 39.35 -16.52, 39.45 -16.6, 39.56 -16.67, 39.66 -16.73, 39.77 -16.8, 39.88 -16.86, 40 -16.92, 40.11 -16.97, 40.23 -17.02, 40.35 -17.06, 40.48 -17.11, 40.6 -17.14, 40.73 -17.18, 40.86 -17.21, 40.99 -17.24, 41.13 -17.26, 41.26 -17.28, 41.4 -17.3, 41.54 -17.31, 41.69 -17.32, 41.84 -17.33, 41.98 -17.33, 42.13 -17.33, 42.28 -17.32, 42.42 -17.31, 42.57 -17.3, 42.7 -17.28, 42.84 -17.26, 42.98 -17.24, 43.11 -17.21, 43.24 -17.18, 43.37 -17.15, 43.49 -17.11, 43.61 -17.07, 43.73 -17.02, 43.85 -16.97, 43.97 -16.92, 44.08 -16.86, 44.19 -16.8, 44.3 -16.74, 44.41 -16.67, 44.51 -16.6, 44.61 -16.52, 44.71 -16.45, 44.81 -16.36, 44.9 -16.28, 44.99 -16.19, 45.08 -16.1, 45.17 -16, 45.25 -15.9, 45.33 -15.8, 45.41 -15.69, 45.49 -15.58, 45.57 -15.46, 45.64 -15.34, 45.71 -15.22, 45.77 -15.1, 45.84 -14.97, 45.9 -14.84, 45.96 -14.71, 46.02 -14.57, 46.07 -14.43, 46.12 -14.28, 46.17 -14.14, 46.21 -13.99, 46.26 -13.83, 46.3 -13.68, 46.34 -13.52, 46.37 -13.35, 46.41 -13.18, 46.44 -13.01, 46.46 -12.84, 46.49 -12.66, 46.51 -12.48, 46.53 -12.3, 46.55 -12.11, 46.56 -11.92, 46.57 -11.73, 46.58 -11.53, 46.59 -11.33, 46.59 -11.13, 46.59 -10.92, 46.59 -10.72, 46.59 -10.51, 46.58 -10.31, 46.57 -10.11, 46.56 -9.92, 46.55 -9.73, 46.53 -9.54, 46.51 -9.36, 46.49 -9.18, 46.46 -9, 46.44 -8.83, 46.41 -8.66, 46.37 -8.49, 46.34 -8.33, 46.3 -8.17, 46.26 -8.01, 46.21 -7.86, 46.17 -7.71, 46.12 -7.56, 46.07 -7.41, 46.02 -7.27, 45.96 -7.14, 45.9 -7, 45.84 -6.87, 45.77 -6.74, 45.71 -6.62, 45.64 -6.5, 45.57 -6.38, 45.49 -6.27, 45.41 -6.16, 45.33 -6.05, 45.25 -5.94, 45.17 -5.84, 45.08 -5.75, 44.99 -5.65, 44.9 -5.57, 44.81 -5.48, 44.71 -5.4, 44.61 -5.32, 44.51 -5.24, 44.41 -5.17, 44.3 -5.11, 44.19 -5.04, 44.08 -4.98, 43.97 -4.93, 43.85 -4.87, 43.73 -4.82, 43.61 -4.78, 43.49 -4.74, 43.37 -4.7, 43.24 -4.66, 43.11 -4.63, 42.98 -4.6, 42.84 -4.58, 42.7 -4.56, 42.57 -4.54, 42.42 -4.53, 42.28 -4.52, 42.13 -4.52, 41.98 -4.52, 41.84 -4.52, 41.69 -4.52, 41.54 -4.53, 41.4 -4.54, 41.26 -4.56, 41.13 -4.58, 40.99 -4.61, 40.86 -4.63, 40.73 -4.66, 40.6 -4.7, 40.48 -4.74, 40.35 -4.78, 40.23 -4.83, 40.11 -4.87, 40 -4.93, 39.88 -4.98, 39.77 -5.04, 39.66 -5.11, 39.56 -5.18, 39.45 -5.25, 39.35 -5.32, 39.25 -5.4, 39.15 -5.48, 39.06 -5.57, 38.97 -5.66, 38.88 -5.75, 38.79 -5.85, 38.7 -5.95, 38.62 -6.06, 38.54 -6.16, 38.46 -6.28, 38.39 -6.39, 38.31 -6.51, 38.24 -6.63, 38.17 -6.75, 38.11 -6.88, 38.05 -7.01, 37.99 -7.15, 37.93 -7.28, 37.88 -7.43, 37.82 -7.57, 37.77 -7.72, 37.73 -7.87, 37.68 -8.02, 37.64 -8.18, 37.6 -8.34, 37.57 -8.5, 37.54 -8.67, 37.5 -8.84, 37.48 -9.01, 37.45 -9.19, 37.43 -9.37, 37.41 -9.55, 37.39 -9.74, 37.38 -9.93, 37.37 -10.12, 37.36 -10.31, 37.35 -10.51, 37.35 -10.72, 37.34 -10.92)))", + ) + + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmWidth), 74) + self.assertEqual(device.metric(QPaintDevice.PaintDeviceMetric.PdmHeight), 30) # with on the fly simplification device = QgsGeometryPaintDevice() device.setSimplificationTolerance(2) painter = SafePainter(device) - font = getTestFont('bold') + font = getTestFont("bold") font.setPixelSize(40) painter.setFont(font) - painter.drawText(0, 0, 'abc') + painter.drawText(0, 0, "abc") painter.end() result = device.geometry().clone() result.normalize() - self.assertEqual(result.asWkt(2), 'GeometryCollection (Polygon ((2.25 -3.7, 7.63 0.42, 16.8 -3.25, 16.8 0, 23.84 0, 23.84 -12.48, 19.35 -21.26, 3.64 -21.3, 3.64 -15.95, 13.54 -17.61, 16.8 -14, 4.19 -12.08, 2.25 -3.7),(9.12 -8.33, 16.8 -9.84, 16.14 -6.42, 10.04 -4.56, 9.12 -8.33)),Polygon ((57.39 -9.52, 61.13 -2.08, 76.64 -0.64, 76.64 -6.38, 68.2 -4.87, 64.61 -10.92, 68.2 -16.98, 76.64 -15.48, 76.64 -21.19, 66.61 -22.13, 59.65 -18.29, 57.39 -9.52)),Polygon ((30.34 -30.39, 30.34 0, 37.34 0, 37.34 -3.17, 42.56 0.37, 49.12 -0.73, 53.64 -8.35, 51.87 -18.31, 44.85 -22.4, 37.34 -18.67, 37.34 -30.39, 30.34 -30.39),(37.34 -10.92, 41.98 -17.33, 46.59 -10.92, 41.98 -4.52, 37.34 -10.92)))') + self.assertEqual( + result.asWkt(2), + "GeometryCollection (Polygon ((2.25 -3.7, 7.63 0.42, 16.8 -3.25, 16.8 0, 23.84 0, 23.84 -12.48, 19.35 -21.26, 3.64 -21.3, 3.64 -15.95, 13.54 -17.61, 16.8 -14, 4.19 -12.08, 2.25 -3.7),(9.12 -8.33, 16.8 -9.84, 16.14 -6.42, 10.04 -4.56, 9.12 -8.33)),Polygon ((57.39 -9.52, 61.13 -2.08, 76.64 -0.64, 76.64 -6.38, 68.2 -4.87, 64.61 -10.92, 68.2 -16.98, 76.64 -15.48, 76.64 -21.19, 66.61 -22.13, 59.65 -18.29, 57.39 -9.52)),Polygon ((30.34 -30.39, 30.34 0, 37.34 0, 37.34 -3.17, 42.56 0.37, 49.12 -0.73, 53.64 -8.35, 51.87 -18.31, 44.85 -22.4, 37.34 -18.67, 37.34 -30.39, 30.34 -30.39),(37.34 -10.92, 41.98 -17.33, 46.59 -10.92, 41.98 -4.52, 37.34 -10.92)))", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsgeometryvalidator.py b/tests/src/python/test_qgsgeometryvalidator.py index 99f0008219d0..e0b5fa0b993e 100644 --- a/tests/src/python/test_qgsgeometryvalidator.py +++ b/tests/src/python/test_qgsgeometryvalidator.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '03/10/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "03/10/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy from qgis.core import QgsGeometry, QgsGeometryValidator, QgsPointXY @@ -20,7 +21,7 @@ class TestQgsGeometryValidator(QgisTestCase): def testIssue15660(self): - """ Test crash when validating geometry (#15660) """ + """Test crash when validating geometry (#15660)""" g = QgsGeometry.fromWkt( "Polygon ((0.44256348235389709 -47.87645625696347906, -2.88231630340906797 -47.90003919913998232," "-2.88589842578005751 -48.91215450743293047, -2.8858984257800584 -48.91215450743293047," @@ -51,14 +52,17 @@ def testIssue15660(self): "-2.71083842578005996 -44.83541850743291945, -2.71083842578005729 -44.83541850743291945," "-0.86779302740823816 -44.89143693883772812, -0.86745855610774569 -44.87743669555854353," "0.29843811058281489 -44.90401226269042922, 0.20437651721061911 -46.69301920907949466," - "0.50389019278376956 -46.71008040893148916, 0.44256348235389709 -47.87645625696347906))") + "0.50389019278376956 -46.71008040893148916, 0.44256348235389709 -47.87645625696347906))" + ) self.assertTrue(g) # make sure validating this geometry doesn't crash QGIS QgsGeometryValidator.validateGeometry(g) def test_linestring_duplicate_nodes(self): - g = QgsGeometry.fromWkt("LineString (1 1, 1 1, 1 1, 1 2, 1 3, 1 3, 1 3, 1 4, 1 5, 1 6, 1 6)") + g = QgsGeometry.fromWkt( + "LineString (1 1, 1 1, 1 1, 1 2, 1 3, 1 3, 1 3, 1 4, 1 5, 1 6, 1 6)" + ) validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) @@ -66,13 +70,20 @@ def test_linestring_duplicate_nodes(self): self.assertEqual(len(spy), 3) self.assertEqual(spy[0][0].where(), QgsPointXY(1, 6)) - self.assertEqual(spy[0][0].what(), 'line 1 contains 2 duplicate node(s) starting at vertex 10') + self.assertEqual( + spy[0][0].what(), + "line 1 contains 2 duplicate node(s) starting at vertex 10", + ) self.assertEqual(spy[1][0].where(), QgsPointXY(1, 3)) - self.assertEqual(spy[1][0].what(), 'line 1 contains 3 duplicate node(s) starting at vertex 5') + self.assertEqual( + spy[1][0].what(), "line 1 contains 3 duplicate node(s) starting at vertex 5" + ) self.assertEqual(spy[2][0].where(), QgsPointXY(1, 1)) - self.assertEqual(spy[2][0].what(), 'line 1 contains 3 duplicate node(s) starting at vertex 1') + self.assertEqual( + spy[2][0].what(), "line 1 contains 3 duplicate node(s) starting at vertex 1" + ) def test_linestring_intersections(self): # no intersections @@ -108,11 +119,15 @@ def test_linestring_intersections(self): self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY(5, 5)) - self.assertEqual(spy[0][0].what(), 'segments 0 and 2 of line 0 intersect at 5, 5') + self.assertEqual( + spy[0][0].what(), "segments 0 and 2 of line 0 intersect at 5, 5" + ) # tests issue #54022 # Test number 1 - g = QgsGeometry.fromWkt("LineString (10.516394879668999 59.73620343022049894, 10.51672588102520045 59.73642831668259845, 10.51671297289430029 59.73629479296509004, 10.516394879668999 59.73620343022049894)") + g = QgsGeometry.fromWkt( + "LineString (10.516394879668999 59.73620343022049894, 10.51672588102520045 59.73642831668259845, 10.51671297289430029 59.73629479296509004, 10.516394879668999 59.73620343022049894)" + ) validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) validator.run() @@ -120,7 +135,9 @@ def test_linestring_intersections(self): self.assertEqual(len(spy), 0) # Test number 2 - g = QgsGeometry.fromWkt("LINESTRING (10.516394879668999 59.73620343022049894, 10.51672588102520045 59.73642831668259845, 10.51671297289430029 59.73619479296509004, 10.516394879668999 59.73620343022049894)") + g = QgsGeometry.fromWkt( + "LINESTRING (10.516394879668999 59.73620343022049894, 10.51672588102520045 59.73642831668259845, 10.51671297289430029 59.73619479296509004, 10.516394879668999 59.73620343022049894)" + ) validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) validator.run() @@ -129,7 +146,9 @@ def test_linestring_intersections(self): def test_ring_intersections(self): # no intersections - g = QgsGeometry.fromWkt("Polygon ((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 5 1, 1 9, 1 1), (6 9, 2 9, 6 1, 6 9))") + g = QgsGeometry.fromWkt( + "Polygon ((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 5 1, 1 9, 1 1), (6 9, 2 9, 6 1, 6 9))" + ) validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) @@ -138,7 +157,9 @@ def test_ring_intersections(self): self.assertEqual(len(spy), 0) # two interior rings intersecting - g = QgsGeometry.fromWkt("Polygon ((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 5 1, 1 9, 1 1), (2 2, 5 2, 2 9, 2 2))") + g = QgsGeometry.fromWkt( + "Polygon ((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 5 1, 1 9, 1 1), (2 2, 5 2, 2 9, 2 2))" + ) validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) @@ -147,10 +168,16 @@ def test_ring_intersections(self): self.assertEqual(len(spy), 2) self.assertEqual(spy[0][0].where(), QgsPointXY(4.5, 2)) - self.assertEqual(spy[0][0].what(), 'segment 1 of ring 1 of polygon 0 intersects segment 0 of ring 2 of polygon 0 at 4.5, 2') + self.assertEqual( + spy[0][0].what(), + "segment 1 of ring 1 of polygon 0 intersects segment 0 of ring 2 of polygon 0 at 4.5, 2", + ) self.assertEqual(spy[1][0].where(), QgsPointXY(2, 7)) - self.assertEqual(spy[1][0].what(), 'segment 1 of ring 1 of polygon 0 intersects segment 2 of ring 2 of polygon 0 at 2, 7') + self.assertEqual( + spy[1][0].what(), + "segment 1 of ring 1 of polygon 0 intersects segment 2 of ring 2 of polygon 0 at 2, 7", + ) def test_line_vertices(self): # valid line @@ -170,7 +197,7 @@ def test_line_vertices(self): self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY()) - self.assertEqual(spy[0][0].what(), 'line 0 with less than two points') + self.assertEqual(spy[0][0].what(), "line 0 with less than two points") g = QgsGeometry.fromWkt("LineString ()") @@ -180,7 +207,7 @@ def test_line_vertices(self): self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY()) - self.assertEqual(spy[0][0].what(), 'line 0 with less than two points') + self.assertEqual(spy[0][0].what(), "line 0 with less than two points") def test_ring_vertex_count(self): # valid ring @@ -200,7 +227,7 @@ def test_ring_vertex_count(self): self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY()) - self.assertEqual(spy[0][0].what(), 'ring 0 with less than four points') + self.assertEqual(spy[0][0].what(), "ring 0 with less than four points") g = QgsGeometry.fromWkt("Polygon ((0 0, 10 0, 0 0))") @@ -210,7 +237,7 @@ def test_ring_vertex_count(self): self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY()) - self.assertEqual(spy[0][0].what(), 'ring 0 with less than four points') + self.assertEqual(spy[0][0].what(), "ring 0 with less than four points") g = QgsGeometry.fromWkt("Polygon ((0 0, 10 0))") @@ -220,7 +247,7 @@ def test_ring_vertex_count(self): self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY()) - self.assertEqual(spy[0][0].what(), 'ring 0 with less than four points') + self.assertEqual(spy[0][0].what(), "ring 0 with less than four points") g = QgsGeometry.fromWkt("Polygon ((0 0))") @@ -230,7 +257,7 @@ def test_ring_vertex_count(self): self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY()) - self.assertEqual(spy[0][0].what(), 'ring 0 with less than four points') + self.assertEqual(spy[0][0].what(), "ring 0 with less than four points") g = QgsGeometry.fromWkt("Polygon (())") @@ -247,16 +274,20 @@ def test_ring_vertex_count(self): self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY()) - self.assertEqual(spy[0][0].what(), 'ring 1 with less than four points') + self.assertEqual(spy[0][0].what(), "ring 1 with less than four points") - g = QgsGeometry.fromWkt("Polygon ((0 0, 10 0, 10 10, 0 0),(1 1, 2 1, 2 2, 1 1))") + g = QgsGeometry.fromWkt( + "Polygon ((0 0, 10 0, 10 10, 0 0),(1 1, 2 1, 2 2, 1 1))" + ) validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) validator.run() self.assertEqual(len(spy), 0) - g = QgsGeometry.fromWkt("Polygon ((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 2 1, 2 2, 1 1),(3 3, 3 4, 4 4))") + g = QgsGeometry.fromWkt( + "Polygon ((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 2 1, 2 2, 1 1),(3 3, 3 4, 4 4))" + ) validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) @@ -264,7 +295,7 @@ def test_ring_vertex_count(self): self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY()) - self.assertEqual(spy[0][0].what(), 'ring 2 with less than four points') + self.assertEqual(spy[0][0].what(), "ring 2 with less than four points") def test_ring_closed(self): # valid ring @@ -284,9 +315,11 @@ def test_ring_closed(self): self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY(0, 0)) - self.assertEqual(spy[0][0].what(), 'ring 0 not closed') + self.assertEqual(spy[0][0].what(), "ring 0 not closed") - g = QgsGeometry.fromWkt("Polygon ((0 0, 10 0, 10 10, 0 0),(1 1, 2 1, 2 2, 1.1 1))") + g = QgsGeometry.fromWkt( + "Polygon ((0 0, 10 0, 10 10, 0 0),(1 1, 2 1, 2 2, 1.1 1))" + ) validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) @@ -294,9 +327,11 @@ def test_ring_closed(self): self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY(1, 1)) - self.assertEqual(spy[0][0].what(), 'ring 1 not closed') + self.assertEqual(spy[0][0].what(), "ring 1 not closed") - g = QgsGeometry.fromWkt("Polygon ((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 2 1, 2 2, 1 1),(3 3, 3 4, 4 4, 3.1 3))") + g = QgsGeometry.fromWkt( + "Polygon ((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 2 1, 2 2, 1 1),(3 3, 3 4, 4 4, 3.1 3))" + ) validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) @@ -304,7 +339,7 @@ def test_ring_closed(self): self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY(3, 3)) - self.assertEqual(spy[0][0].what(), 'ring 2 not closed') + self.assertEqual(spy[0][0].what(), "ring 2 not closed") # not closed but 2d closed g = QgsGeometry.fromWkt("POLYGONZ((1 1 0, 1 2 1, 2 2 2, 2 1 3, 1 1 4))") @@ -315,18 +350,20 @@ def test_ring_closed(self): self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY(1, 1)) - self.assertEqual(spy[0][0].what(), 'ring 0 not closed, Z mismatch: 0 vs 4') + self.assertEqual(spy[0][0].what(), "ring 0 not closed, Z mismatch: 0 vs 4") def test_multi_part_curve_nested_shell(self): # A circle inside another one - g = QgsGeometry.fromWkt("MultiSurface (CurvePolygon (CircularString (0 5, 5 0, 0 -5, -5 0, 0 5)),CurvePolygon (CircularString (0 1, 1 0, 0 -1, -1 0, 0 1)))") + g = QgsGeometry.fromWkt( + "MultiSurface (CurvePolygon (CircularString (0 5, 5 0, 0 -5, -5 0, 0 5)),CurvePolygon (CircularString (0 1, 1 0, 0 -1, -1 0, 0 1)))" + ) validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) validator.run() self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY()) - self.assertEqual(spy[0][0].what(), 'Polygon 1 lies inside polygon 0') + self.assertEqual(spy[0][0].what(), "Polygon 1 lies inside polygon 0") # converted as a straight polygon g.convertToStraightSegment() @@ -336,11 +373,13 @@ def test_multi_part_curve_nested_shell(self): self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY()) - self.assertEqual(spy[0][0].what(), 'Polygon 1 lies inside polygon 0') + self.assertEqual(spy[0][0].what(), "Polygon 1 lies inside polygon 0") def test_multi_part_curve(self): # A circle inside another one - g = QgsGeometry.fromWkt("MultiSurface (CurvePolygon (CircularString (0 5, 5 0, 0 -5, -5 0, 0 5)),CurvePolygon (CircularString (100 1, 100 0, 100 -1, 99 0, 100 1)))") + g = QgsGeometry.fromWkt( + "MultiSurface (CurvePolygon (CircularString (0 5, 5 0, 0 -5, -5 0, 0 5)),CurvePolygon (CircularString (100 1, 100 0, 100 -1, 99 0, 100 1)))" + ) validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) validator.run() @@ -354,5 +393,5 @@ def test_multi_part_curve(self): self.assertEqual(len(spy), 0) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsgeometrywidget.py b/tests/src/python/test_qgsgeometrywidget.py index 8be5ad4864b0..23cc484ad03a 100644 --- a/tests/src/python/test_qgsgeometrywidget.py +++ b/tests/src/python/test_qgsgeometrywidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '15/02/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "15/02/2023" +__copyright__ = "Copyright 2023, The QGIS Project" from qgis.PyQt.QtGui import QColor from qgis.PyQt.QtTest import QSignalSpy @@ -15,11 +16,9 @@ QgsWkbTypes, QgsGeometry, QgsReferencedGeometry, - QgsCoordinateReferenceSystem -) -from qgis.gui import ( - QgsGeometryWidget + QgsCoordinateReferenceSystem, ) +from qgis.gui import QgsGeometryWidget import unittest from qgis.testing import start_app, QgisTestCase @@ -34,47 +33,67 @@ def testGeometryValue(self): spy = QSignalSpy(widget.geometryValueChanged) self.assertTrue(widget.geometryValue().isNull()) - widget.setGeometryValue(QgsReferencedGeometry( - QgsGeometry.fromWkt('Point( 1 2)'), - QgsCoordinateReferenceSystem('EPSG:3111')) + widget.setGeometryValue( + QgsReferencedGeometry( + QgsGeometry.fromWkt("Point( 1 2)"), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) ) self.assertEqual(len(spy), 1) - self.assertEqual(spy[-1][0], QgsReferencedGeometry( - QgsGeometry.fromWkt('Point( 1 2)'), - QgsCoordinateReferenceSystem('EPSG:3111'))) + self.assertEqual( + spy[-1][0], + QgsReferencedGeometry( + QgsGeometry.fromWkt("Point( 1 2)"), + QgsCoordinateReferenceSystem("EPSG:3111"), + ), + ) - self.assertEqual(widget.geometryValue().asWkt(), 'Point (1 2)') - self.assertEqual(widget.geometryValue().crs().authid(), 'EPSG:3111') + self.assertEqual(widget.geometryValue().asWkt(), "Point (1 2)") + self.assertEqual(widget.geometryValue().crs().authid(), "EPSG:3111") # same geometry, should be no signal - widget.setGeometryValue(QgsReferencedGeometry( - QgsGeometry.fromWkt('Point( 1 2)'), - QgsCoordinateReferenceSystem('EPSG:3111')) + widget.setGeometryValue( + QgsReferencedGeometry( + QgsGeometry.fromWkt("Point( 1 2)"), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) ) self.assertEqual(len(spy), 1) # different geometry - widget.setGeometryValue(QgsReferencedGeometry( - QgsGeometry.fromWkt('Point(1 3)'), - QgsCoordinateReferenceSystem('EPSG:3111')) + widget.setGeometryValue( + QgsReferencedGeometry( + QgsGeometry.fromWkt("Point(1 3)"), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) ) self.assertEqual(len(spy), 2) - self.assertEqual(spy[-1][0], QgsReferencedGeometry( - QgsGeometry.fromWkt('Point(1 3)'), - QgsCoordinateReferenceSystem('EPSG:3111'))) - self.assertEqual(widget.geometryValue(), QgsReferencedGeometry( - QgsGeometry.fromWkt('Point(1 3)'), - QgsCoordinateReferenceSystem('EPSG:3111'))) + self.assertEqual( + spy[-1][0], + QgsReferencedGeometry( + QgsGeometry.fromWkt("Point(1 3)"), + QgsCoordinateReferenceSystem("EPSG:3111"), + ), + ) + self.assertEqual( + widget.geometryValue(), + QgsReferencedGeometry( + QgsGeometry.fromWkt("Point(1 3)"), + QgsCoordinateReferenceSystem("EPSG:3111"), + ), + ) # clear widget.clearGeometry() self.assertEqual(len(spy), 3) - self.assertEqual(spy[-1][0], QgsReferencedGeometry( - QgsGeometry(), - QgsCoordinateReferenceSystem())) - self.assertEqual(widget.geometryValue(), QgsReferencedGeometry( - QgsGeometry(), - QgsCoordinateReferenceSystem())) + self.assertEqual( + spy[-1][0], + QgsReferencedGeometry(QgsGeometry(), QgsCoordinateReferenceSystem()), + ) + self.assertEqual( + widget.geometryValue(), + QgsReferencedGeometry(QgsGeometry(), QgsCoordinateReferenceSystem()), + ) widget.clearGeometry() self.assertEqual(len(spy), 3) @@ -83,8 +102,10 @@ def test_acceptable_types(self): self.assertFalse(w.acceptedWkbTypes()) w.setAcceptedWkbTypes([QgsWkbTypes.Type.PointZ, QgsWkbTypes.Type.PointM]) - self.assertEqual(w.acceptedWkbTypes(), [QgsWkbTypes.Type.PointZ, QgsWkbTypes.Type.PointM]) + self.assertEqual( + w.acceptedWkbTypes(), [QgsWkbTypes.Type.PointZ, QgsWkbTypes.Type.PointM] + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsgooglemapsgeocoder.py b/tests/src/python/test_qgsgooglemapsgeocoder.py index c62fa37f53c9..bcae956e8c74 100644 --- a/tests/src/python/test_qgsgooglemapsgeocoder.py +++ b/tests/src/python/test_qgsgooglemapsgeocoder.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '02/11/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "02/11/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import tempfile @@ -40,15 +41,15 @@ def setUpClass(cls): # On Windows we must make sure that any backslash in the path is # replaced by a forward slash so that QUrl can process it - cls.basetestpath = tempfile.mkdtemp().replace('\\', '/') - cls.endpoint = 'http://' + cls.basetestpath + '/fake_qgis_http_endpoint' + cls.basetestpath = tempfile.mkdtemp().replace("\\", "/") + cls.endpoint = "http://" + cls.basetestpath + "/fake_qgis_http_endpoint" @classmethod def generate_url(cls, params): - res = cls.endpoint + '_' + params - res = res.replace('&', '_') - res = res.replace(' ', '_') - return 'file:' + res.replace('http://', '') + res = cls.endpoint + "_" + params + res = res.replace("&", "_") + res = res.replace(" ", "_") + return "file:" + res.replace("http://", "") @classmethod def tearDownClass(cls): @@ -61,121 +62,145 @@ def test_basic(self): """ Basic tests """ - geocoder = QgsGoogleMapsGeocoder('my key') - self.assertEqual(geocoder.apiKey(), 'my key') - geocoder.setApiKey('ggggg') - self.assertEqual(geocoder.apiKey(), 'ggggg') + geocoder = QgsGoogleMapsGeocoder("my key") + self.assertEqual(geocoder.apiKey(), "my key") + geocoder.setApiKey("ggggg") + self.assertEqual(geocoder.apiKey(), "ggggg") self.assertFalse(geocoder.region()) - geocoder.setRegion('xx') - self.assertEqual(geocoder.region(), 'xx') + geocoder.setRegion("xx") + self.assertEqual(geocoder.region(), "xx") - self.assertEqual(geocoder.requestUrl('20 green st, twaddlingham').toString(), 'https://maps.googleapis.com/maps/api/geocode/json?region=xx&sensor=false&address=20 green st, twaddlingham&key=ggggg') + self.assertEqual( + geocoder.requestUrl("20 green st, twaddlingham").toString(), + "https://maps.googleapis.com/maps/api/geocode/json?region=xx&sensor=false&address=20 green st, twaddlingham&key=ggggg", + ) def test_url(self): - geocoder = QgsGoogleMapsGeocoder('my key') + geocoder = QgsGoogleMapsGeocoder("my key") geocoder.setEndpoint(self.endpoint) - self.assertEqual(geocoder.requestUrl('20 green st, twaddlingham').toString(), - QUrl( - self.generate_url('sensor=false&address=20 green st, twaddlingham&key=my key')).toString()) - self.assertEqual(geocoder.requestUrl('20 green st, twaddlingham', QgsRectangle(3, 5, 6, 8)).toString(), - QUrl(self.generate_url( - 'bounds=5,3|8,5&sensor=false&address=20 green st, twaddlingham&key=my key')).toString()) + self.assertEqual( + geocoder.requestUrl("20 green st, twaddlingham").toString(), + QUrl( + self.generate_url( + "sensor=false&address=20 green st, twaddlingham&key=my key" + ) + ).toString(), + ) + self.assertEqual( + geocoder.requestUrl( + "20 green st, twaddlingham", QgsRectangle(3, 5, 6, 8) + ).toString(), + QUrl( + self.generate_url( + "bounds=5,3|8,5&sensor=false&address=20 green st, twaddlingham&key=my key" + ) + ).toString(), + ) - geocoder = QgsGoogleMapsGeocoder('my key', regionBias='au') + geocoder = QgsGoogleMapsGeocoder("my key", regionBias="au") geocoder.setEndpoint(self.endpoint) - self.assertEqual(geocoder.requestUrl('20 green st, twaddlingham').toString(), - QUrl(self.generate_url( - 'region=au&sensor=false&address=20 green st, twaddlingham&key=my key')).toString()) - self.assertEqual(geocoder.requestUrl('20 green st, twaddlingham', QgsRectangle(3, 5, 6, 8)).toString(), - QUrl(self.generate_url( - 'bounds=5,3|8,5®ion=au&sensor=false&address=20 green st, twaddlingham&key=my key')).toString()) + self.assertEqual( + geocoder.requestUrl("20 green st, twaddlingham").toString(), + QUrl( + self.generate_url( + "region=au&sensor=false&address=20 green st, twaddlingham&key=my key" + ) + ).toString(), + ) + self.assertEqual( + geocoder.requestUrl( + "20 green st, twaddlingham", QgsRectangle(3, 5, 6, 8) + ).toString(), + QUrl( + self.generate_url( + "bounds=5,3|8,5®ion=au&sensor=false&address=20 green st, twaddlingham&key=my key" + ) + ).toString(), + ) def test_json_to_result(self): - geocoder = QgsGoogleMapsGeocoder('my key') + geocoder = QgsGoogleMapsGeocoder("my key") geocoder.setEndpoint(self.endpoint) json = { "address_components": [ - { - "long_name": "1600", - "short_name": "1600", - "types": ["street_number"] - }, + {"long_name": "1600", "short_name": "1600", "types": ["street_number"]}, { "long_name": "Amphitheatre Pkwy", "short_name": "Amphitheatre Pkwy", - "types": ["route"] + "types": ["route"], }, { "long_name": "Mountain View", "short_name": "Mountain View", - "types": ["locality", "political"] + "types": ["locality", "political"], }, { "long_name": "Santa Clara County", "short_name": "Santa Clara County", - "types": ["administrative_area_level_2", "political"] + "types": ["administrative_area_level_2", "political"], }, { "long_name": "California", "short_name": "CA", - "types": ["administrative_area_level_1", "political"] + "types": ["administrative_area_level_1", "political"], }, { "long_name": "United States", "short_name": "US", - "types": ["country", "political"] + "types": ["country", "political"], }, - { - "long_name": "94043", - "short_name": "94043", - "types": ["postal_code"] - } + {"long_name": "94043", "short_name": "94043", "types": ["postal_code"]}, ], "formatted_address": "Toledo, OH, USA", "geometry": { - "location": { - "lat": 41.6639383, - "lng": -83.55521200000001 - }, + "location": {"lat": 41.6639383, "lng": -83.55521200000001}, "location_type": "APPROXIMATE", "viewport": { - "northeast": { - "lat": 42.1, - "lng": -87.7 - }, - "southwest": { - "lat": 42.0, - "lng": -87.7 - } - } + "northeast": {"lat": 42.1, "lng": -87.7}, + "southwest": {"lat": 42.0, "lng": -87.7}, + }, }, "place_id": "ChIJeU4e_C2HO4gRRcM6RZ_IPHw", - "types": ["locality", "political"] + "types": ["locality", "political"], } res = geocoder.jsonToResult(json) - self.assertEqual(res.identifier(), 'Toledo, OH, USA') - self.assertEqual(res.geometry().asWkt(1), 'Point (-83.6 41.7)') - self.assertEqual(res.additionalAttributes(), {'administrative_area_level_1': 'California', - 'administrative_area_level_2': 'Santa Clara County', - 'country': 'United States', - 'formatted_address': 'Toledo, OH, USA', - 'locality': 'Mountain View', 'location_type': 'APPROXIMATE', - 'place_id': 'ChIJeU4e_C2HO4gRRcM6RZ_IPHw', 'postal_code': '94043', - 'route': 'Amphitheatre Pkwy', 'street_number': '1600'}) + self.assertEqual(res.identifier(), "Toledo, OH, USA") + self.assertEqual(res.geometry().asWkt(1), "Point (-83.6 41.7)") + self.assertEqual( + res.additionalAttributes(), + { + "administrative_area_level_1": "California", + "administrative_area_level_2": "Santa Clara County", + "country": "United States", + "formatted_address": "Toledo, OH, USA", + "locality": "Mountain View", + "location_type": "APPROXIMATE", + "place_id": "ChIJeU4e_C2HO4gRRcM6RZ_IPHw", + "postal_code": "94043", + "route": "Amphitheatre Pkwy", + "street_number": "1600", + }, + ) self.assertEqual(res.viewport(), QgsRectangle(-87.7, 42, -87.7, 42.1)) - self.assertEqual(res.group(), 'California') + self.assertEqual(res.group(), "California") def test_geocode(self): - geocoder = QgsGoogleMapsGeocoder('my key') + geocoder = QgsGoogleMapsGeocoder("my key") geocoder.setEndpoint(self.endpoint) - with open(geocoder.requestUrl('20 green st, twaddlingham').toString().replace('file://', ''), 'wb') as f: - f.write(b""" + with open( + geocoder.requestUrl("20 green st, twaddlingham") + .toString() + .replace("file://", ""), + "wb", + ) as f: + f.write( + b""" { "results" : [ { @@ -244,23 +269,34 @@ def test_geocode(self): ], "status" : "OK" } - """) + """ + ) context = QgsGeocoderContext(QgsCoordinateTransformContext()) - results = geocoder.geocodeString('20 green st, twaddlingham', context) + results = geocoder.geocodeString("20 green st, twaddlingham", context) self.assertEqual(len(results), 1) - self.assertEqual(results[0].identifier(), '1600 Amphitheatre Parkway, Mountain View, CA 94043, USA') - self.assertEqual(results[0].geometry().asWkt(1), 'Point (-122.1 37.4)') - self.assertEqual(results[0].additionalAttributes(), {'administrative_area_level_1': 'California', - 'administrative_area_level_2': 'Santa Clara County', - 'country': 'United States', - 'formatted_address': '1600 Amphitheatre Parkway, Mountain View, CA 94043, USA', - 'locality': 'Mountain View', 'location_type': 'ROOFTOP', - 'place_id': 'ChIJ2eUgeAK6j4ARbn5u_wAGqWA', - 'postal_code': '94043', 'route': 'Amphitheatre Pkwy', - 'street_number': '1600'}) + self.assertEqual( + results[0].identifier(), + "1600 Amphitheatre Parkway, Mountain View, CA 94043, USA", + ) + self.assertEqual(results[0].geometry().asWkt(1), "Point (-122.1 37.4)") + self.assertEqual( + results[0].additionalAttributes(), + { + "administrative_area_level_1": "California", + "administrative_area_level_2": "Santa Clara County", + "country": "United States", + "formatted_address": "1600 Amphitheatre Parkway, Mountain View, CA 94043, USA", + "locality": "Mountain View", + "location_type": "ROOFTOP", + "place_id": "ChIJ2eUgeAK6j4ARbn5u_wAGqWA", + "postal_code": "94043", + "route": "Amphitheatre Pkwy", + "street_number": "1600", + }, + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsgpslogger.py b/tests/src/python/test_qgsgpslogger.py index fca8b7e64ca7..6d66c0bf48e9 100644 --- a/tests/src/python/test_qgsgpslogger.py +++ b/tests/src/python/test_qgsgpslogger.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '10/11/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "10/11/2022" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.PyQt.QtCore import QBuffer, QCoreApplication, QDateTime from qgis.PyQt.QtTest import QSignalSpy @@ -41,7 +42,7 @@ def __init__(self): assert self.connect() def send_message(self, message): - msg = (message + '\r\n').encode() + msg = (message + "\r\n").encode() spy = QSignalSpy(self.stateChanged) @@ -67,43 +68,79 @@ def setUpClass(cls): start_app() settings = QgsSettings() - settings.setValue('/gps/leap-seconds', 48) - settings.setValue('/gps/timestamp-offset-from-utc', 3000) - settings.setValue('/gps/timestamp-time-spec', 'OffsetFromUTC') + settings.setValue("/gps/leap-seconds", 48) + settings.setValue("/gps/timestamp-offset-from-utc", 3000) + settings.setValue("/gps/timestamp-time-spec", "OffsetFromUTC") def test_setters(self): logger = QgsVectorLayerGpsLogger(None) self.assertIsNone(logger.tracksLayer()) self.assertIsNone(logger.pointsLayer()) - tracks_layer = QgsVectorLayer('LineString', 'tracks', 'memory') + tracks_layer = QgsVectorLayer("LineString", "tracks", "memory") self.assertTrue(tracks_layer.isValid()) logger.setTracksLayer(tracks_layer) - points_layer = QgsVectorLayer('Point', 'points', 'memory') + points_layer = QgsVectorLayer("Point", "points", "memory") self.assertTrue(points_layer.isValid()) logger.setPointsLayer(points_layer) self.assertEqual(logger.pointsLayer(), points_layer) self.assertEqual(logger.tracksLayer(), tracks_layer) - logger.setDestinationField(Qgis.GpsInformationComponent.Timestamp, 'point_time_field') - self.assertEqual(logger.destinationField(Qgis.GpsInformationComponent.Timestamp), 'point_time_field') - - logger.setDestinationField(Qgis.GpsInformationComponent.TrackDistanceSinceLastPoint, 'point_distance_from_previous_field') - self.assertEqual(logger.destinationField(Qgis.GpsInformationComponent.TrackDistanceSinceLastPoint), 'point_distance_from_previous_field') - - logger.setDestinationField(Qgis.GpsInformationComponent.TrackTimeSinceLastPoint, 'point_delta_from_previous_field') - self.assertEqual(logger.destinationField(Qgis.GpsInformationComponent.TrackTimeSinceLastPoint), 'point_delta_from_previous_field') - - logger.setDestinationField(Qgis.GpsInformationComponent.TrackStartTime, 'track_start_time') - self.assertEqual(logger.destinationField(Qgis.GpsInformationComponent.TrackStartTime), 'track_start_time') - - logger.setDestinationField(Qgis.GpsInformationComponent.TrackStartTime, 'track_end_time') - self.assertEqual(logger.destinationField(Qgis.GpsInformationComponent.TrackStartTime), 'track_end_time') - - logger.setDestinationField(Qgis.GpsInformationComponent.TotalTrackLength, 'track_length') - self.assertEqual(logger.destinationField(Qgis.GpsInformationComponent.TotalTrackLength), 'track_length') + logger.setDestinationField( + Qgis.GpsInformationComponent.Timestamp, "point_time_field" + ) + self.assertEqual( + logger.destinationField(Qgis.GpsInformationComponent.Timestamp), + "point_time_field", + ) + + logger.setDestinationField( + Qgis.GpsInformationComponent.TrackDistanceSinceLastPoint, + "point_distance_from_previous_field", + ) + self.assertEqual( + logger.destinationField( + Qgis.GpsInformationComponent.TrackDistanceSinceLastPoint + ), + "point_distance_from_previous_field", + ) + + logger.setDestinationField( + Qgis.GpsInformationComponent.TrackTimeSinceLastPoint, + "point_delta_from_previous_field", + ) + self.assertEqual( + logger.destinationField( + Qgis.GpsInformationComponent.TrackTimeSinceLastPoint + ), + "point_delta_from_previous_field", + ) + + logger.setDestinationField( + Qgis.GpsInformationComponent.TrackStartTime, "track_start_time" + ) + self.assertEqual( + logger.destinationField(Qgis.GpsInformationComponent.TrackStartTime), + "track_start_time", + ) + + logger.setDestinationField( + Qgis.GpsInformationComponent.TrackStartTime, "track_end_time" + ) + self.assertEqual( + logger.destinationField(Qgis.GpsInformationComponent.TrackStartTime), + "track_end_time", + ) + + logger.setDestinationField( + Qgis.GpsInformationComponent.TotalTrackLength, "track_length" + ) + self.assertEqual( + logger.destinationField(Qgis.GpsInformationComponent.TotalTrackLength), + "track_length", + ) def test_current_geometry(self): gps_connection = GpsReplay() @@ -111,7 +148,9 @@ def test_current_geometry(self): logger = QgsGpsLogger(gps_connection) spy = QSignalSpy(logger.stateChanged) - gps_connection.send_message('$GPRMC,084111.185,A,6938.6531,N,01856.8527,E,0.16,2.00,220120,,,A*6E') + gps_connection.send_message( + "$GPRMC,084111.185,A,6938.6531,N,01856.8527,E,0.16,2.00,220120,,,A*6E" + ) self.assertEqual(len(spy), 1) # not enough vertices for these types yet: @@ -127,29 +166,35 @@ def test_current_geometry(self): # can create points res, err = logger.currentGeometry(QgsWkbTypes.Type.Point) self.assertFalse(err) - self.assertEqual(res.asWkt(4), 'Point (18.9475 69.6442)') + self.assertEqual(res.asWkt(4), "Point (18.9475 69.6442)") res, err = logger.currentGeometry(QgsWkbTypes.Type.PointZ) self.assertFalse(err) - self.assertEqual(res.asWkt(4), 'Point Z (18.9475 69.6442 0)') + self.assertEqual(res.asWkt(4), "Point Z (18.9475 69.6442 0)") # make elevation available - gps_connection.send_message("$GPGGA,084112.185,6939.6532,N,01856.8526,E,1,04,1.4,35.0,M,29.4,M,,0000*63") + gps_connection.send_message( + "$GPGGA,084112.185,6939.6532,N,01856.8526,E,1,04,1.4,35.0,M,29.4,M,,0000*63" + ) res, err = logger.currentGeometry(QgsWkbTypes.Type.PointZ) self.assertFalse(err) - self.assertEqual(res.asWkt(4), 'Point Z (18.9475 69.6609 35)') + self.assertEqual(res.asWkt(4), "Point Z (18.9475 69.6609 35)") res, err = logger.currentGeometry(QgsWkbTypes.Type.MultiPointZ) self.assertFalse(err) - self.assertEqual(res.asWkt(4), 'MultiPoint Z ((18.9475 69.6609 35))') + self.assertEqual(res.asWkt(4), "MultiPoint Z ((18.9475 69.6609 35))") res, err = logger.currentGeometry(QgsWkbTypes.Type.LineString) self.assertFalse(err) - self.assertEqual(res.asWkt(4), 'LineString (18.9475 69.6442, 18.9475 69.6609)') + self.assertEqual(res.asWkt(4), "LineString (18.9475 69.6442, 18.9475 69.6609)") res, err = logger.currentGeometry(QgsWkbTypes.Type.LineStringZ) self.assertFalse(err) - self.assertEqual(res.asWkt(4), 'LineString Z (18.9475 69.6442 0, 18.9475 69.6609 35)') + self.assertEqual( + res.asWkt(4), "LineString Z (18.9475 69.6442 0, 18.9475 69.6609 35)" + ) res, err = logger.currentGeometry(QgsWkbTypes.Type.MultiLineStringZ) self.assertFalse(err) - self.assertEqual(res.asWkt(4), 'MultiLineString Z ((18.9475 69.6442 0, 18.9475 69.6609 35))') + self.assertEqual( + res.asWkt(4), "MultiLineString Z ((18.9475 69.6442 0, 18.9475 69.6609 35))" + ) # note enough vertices for polygons yet res, err = logger.currentGeometry(QgsWkbTypes.Type.Polygon) @@ -157,41 +202,63 @@ def test_current_geometry(self): res, err = logger.currentGeometry(QgsWkbTypes.Type.PolygonZ) self.assertTrue(err) - gps_connection.send_message("$GPGGA,084112.185,6939.6532,N,01866.8526,E,1,04,1.4,35.0,M,29.4,M,,0000*63") + gps_connection.send_message( + "$GPGGA,084112.185,6939.6532,N,01866.8526,E,1,04,1.4,35.0,M,29.4,M,,0000*63" + ) res, err = logger.currentGeometry(QgsWkbTypes.Type.PointZ) self.assertFalse(err) - self.assertEqual(res.asWkt(4), 'Point Z (19.1142 69.6609 35)') + self.assertEqual(res.asWkt(4), "Point Z (19.1142 69.6609 35)") res, err = logger.currentGeometry(QgsWkbTypes.Type.MultiPointZ) self.assertFalse(err) - self.assertEqual(res.asWkt(4), 'MultiPoint Z ((19.1142 69.6609 35))') + self.assertEqual(res.asWkt(4), "MultiPoint Z ((19.1142 69.6609 35))") res, err = logger.currentGeometry(QgsWkbTypes.Type.LineString) self.assertFalse(err) - self.assertEqual(res.asWkt(4), 'LineString (18.9475 69.6442, 18.9475 69.6609, 19.1142 69.6609)') + self.assertEqual( + res.asWkt(4), + "LineString (18.9475 69.6442, 18.9475 69.6609, 19.1142 69.6609)", + ) res, err = logger.currentGeometry(QgsWkbTypes.Type.LineStringZ) self.assertFalse(err) - self.assertEqual(res.asWkt(4), 'LineString Z (18.9475 69.6442 0, 18.9475 69.6609 35, 19.1142 69.6609 35)') + self.assertEqual( + res.asWkt(4), + "LineString Z (18.9475 69.6442 0, 18.9475 69.6609 35, 19.1142 69.6609 35)", + ) res, err = logger.currentGeometry(QgsWkbTypes.Type.MultiLineStringZ) self.assertFalse(err) - self.assertEqual(res.asWkt(4), 'MultiLineString Z ((18.9475 69.6442 0, 18.9475 69.6609 35, 19.1142 69.6609 35))') + self.assertEqual( + res.asWkt(4), + "MultiLineString Z ((18.9475 69.6442 0, 18.9475 69.6609 35, 19.1142 69.6609 35))", + ) res, err = logger.currentGeometry(QgsWkbTypes.Type.Polygon) self.assertFalse(err) - self.assertEqual(res.asWkt(4), 'Polygon ((18.9475 69.6442, 18.9475 69.6609, 19.1142 69.6609, 18.9475 69.6442))') + self.assertEqual( + res.asWkt(4), + "Polygon ((18.9475 69.6442, 18.9475 69.6609, 19.1142 69.6609, 18.9475 69.6442))", + ) res, err = logger.currentGeometry(QgsWkbTypes.Type.PolygonZ) self.assertFalse(err) - self.assertEqual(res.asWkt(4), 'Polygon Z ((18.9475 69.6442 0, 18.9475 69.6609 35, 19.1142 69.6609 35, 18.9475 69.6442 0))') + self.assertEqual( + res.asWkt(4), + "Polygon Z ((18.9475 69.6442 0, 18.9475 69.6609 35, 19.1142 69.6609 35, 18.9475 69.6442 0))", + ) res, err = logger.currentGeometry(QgsWkbTypes.Type.MultiPolygonZ) self.assertFalse(err) - self.assertEqual(res.asWkt(4), 'MultiPolygon Z (((18.9475 69.6442 0, 18.9475 69.6609 35, 19.1142 69.6609 35, 18.9475 69.6442 0)))') + self.assertEqual( + res.asWkt(4), + "MultiPolygon Z (((18.9475 69.6442 0, 18.9475 69.6609 35, 19.1142 69.6609 35, 18.9475 69.6442 0)))", + ) def test_point_recording(self): points_layer = QgsVectorLayer( - 'PointZ?crs=EPSG:28355&field=timestamp:datetime&field=distance:double&field=seconds:double', 'points', - 'memory') + "PointZ?crs=EPSG:28355&field=timestamp:datetime&field=distance:double&field=seconds:double", + "points", + "memory", + ) self.assertTrue(points_layer.isValid()) - self.assertEqual(points_layer.crs().authid(), 'EPSG:28355') + self.assertEqual(points_layer.crs().authid(), "EPSG:28355") gps_connection = GpsReplay() @@ -199,13 +266,19 @@ def test_point_recording(self): logger.setPointsLayer(points_layer) spy = QSignalSpy(logger.stateChanged) - logger.setDestinationField(Qgis.GpsInformationComponent.Timestamp, 'timestamp') - logger.setDestinationField(Qgis.GpsInformationComponent.TrackDistanceSinceLastPoint, 'distance') - logger.setDestinationField(Qgis.GpsInformationComponent.TrackTimeSinceLastPoint, 'seconds') + logger.setDestinationField(Qgis.GpsInformationComponent.Timestamp, "timestamp") + logger.setDestinationField( + Qgis.GpsInformationComponent.TrackDistanceSinceLastPoint, "distance" + ) + logger.setDestinationField( + Qgis.GpsInformationComponent.TrackTimeSinceLastPoint, "seconds" + ) points_layer.startEditing() - gps_connection.send_message('$GPRMC,084111.185,A,6938.6531,N,01856.8527,E,0.16,2.00,220120,,,A*6E') + gps_connection.send_message( + "$GPRMC,084111.185,A,6938.6531,N,01856.8527,E,0.16,2.00,220120,,,A*6E" + ) self.assertEqual(len(spy), 1) self.assertEqual(points_layer.featureCount(), 1) @@ -213,10 +286,11 @@ def test_point_recording(self): exp = QDateTime(2020, 1, 22, 9, 31, 59, 185) exp.setOffsetFromUtc(3000) self.assertEqual(f.attributes(), [exp, None, None]) - self.assertEqual(f.geometry().asWkt(-3), 'Point Z (-1297000 21436000 0)') + self.assertEqual(f.geometry().asWkt(-3), "Point Z (-1297000 21436000 0)") gps_connection.send_message( - '$GPRMC,084113.185,A,6938.9152,N,01856.8526,E,0.05,2.00,220120,,,A*6C') + "$GPRMC,084113.185,A,6938.9152,N,01856.8526,E,0.05,2.00,220120,,,A*6C" + ) self.assertEqual(len(spy), 2) self.assertEqual(points_layer.featureCount(), 2) @@ -229,10 +303,11 @@ def test_point_recording(self): exp = QDateTime(2020, 1, 22, 9, 32, 1, 185) exp.setOffsetFromUtc(3000) self.assertEqual(f.attributes(), [exp, 0.004368333651276768, 2.0]) - self.assertEqual(f.geometry().asWkt(-3), 'Point Z (-1297000 21435000 0)') + self.assertEqual(f.geometry().asWkt(-3), "Point Z (-1297000 21435000 0)") gps_connection.send_message( - '$GPRMC,084117.185,A,6939.3152,N,01856.8526,E,0.05,2.00,220120,,,A*6C') + "$GPRMC,084117.185,A,6939.3152,N,01856.8526,E,0.05,2.00,220120,,,A*6C" + ) self.assertEqual(len(spy), 3) self.assertEqual(points_layer.featureCount(), 3) @@ -249,13 +324,16 @@ def test_point_recording(self): exp = QDateTime(2020, 1, 22, 9, 32, 5, 185) exp.setOffsetFromUtc(3000) self.assertEqual(f.attributes(), [exp, 0.006666666666660603, 4.0]) - self.assertEqual(f.geometry().asWkt(-3), 'Point Z (-1296000 21435000 0)') + self.assertEqual(f.geometry().asWkt(-3), "Point Z (-1296000 21435000 0)") # stop recording distance - logger.setDestinationField(Qgis.GpsInformationComponent.TrackDistanceSinceLastPoint, None) + logger.setDestinationField( + Qgis.GpsInformationComponent.TrackDistanceSinceLastPoint, None + ) gps_connection.send_message( - '$GPRMC,084118.185,A,6939.1152,N,01856.8526,E,0.05,2.00,220120,,,A*6C') + "$GPRMC,084118.185,A,6939.1152,N,01856.8526,E,0.05,2.00,220120,,,A*6C" + ) self.assertEqual(len(spy), 4) self.assertEqual(points_layer.featureCount(), 4) @@ -276,13 +354,16 @@ def test_point_recording(self): exp = QDateTime(2020, 1, 22, 9, 32, 6, 185) exp.setOffsetFromUtc(3000) self.assertEqual(f.attributes(), [exp, NULL, 1.0]) - self.assertEqual(f.geometry().asWkt(-3), 'Point Z (-1297000 21435000 0)') + self.assertEqual(f.geometry().asWkt(-3), "Point Z (-1297000 21435000 0)") # stop recording time since previous - logger.setDestinationField(Qgis.GpsInformationComponent.TrackTimeSinceLastPoint, None) + logger.setDestinationField( + Qgis.GpsInformationComponent.TrackTimeSinceLastPoint, None + ) gps_connection.send_message( - '$GPRMC,084119.185,A,6939.3152,N,01856.8526,E,0.05,2.00,220120,,,A*6C') + "$GPRMC,084119.185,A,6939.3152,N,01856.8526,E,0.05,2.00,220120,,,A*6C" + ) self.assertEqual(len(spy), 5) self.assertEqual(points_layer.featureCount(), 5) @@ -307,13 +388,14 @@ def test_point_recording(self): exp = QDateTime(2020, 1, 22, 9, 32, 7, 185) exp.setOffsetFromUtc(3000) self.assertEqual(f.attributes(), [exp, NULL, NULL]) - self.assertEqual(f.geometry().asWkt(-3), 'Point Z (-1296000 21435000 0)') + self.assertEqual(f.geometry().asWkt(-3), "Point Z (-1296000 21435000 0)") # stop recording timestamp logger.setDestinationField(Qgis.GpsInformationComponent.Timestamp, None) gps_connection.send_message( - '$GPRMC,084120.185,A,6939.4152,N,01856.8526,E,0.05,2.00,220120,,,A*6C') + "$GPRMC,084120.185,A,6939.4152,N,01856.8526,E,0.05,2.00,220120,,,A*6C" + ) self.assertEqual(len(spy), 6) self.assertEqual(points_layer.featureCount(), 6) @@ -340,7 +422,7 @@ def test_point_recording(self): self.assertEqual(f.attributes(), [exp, NULL, NULL]) f = next(features) self.assertEqual(f.attributes(), [NULL, NULL, NULL]) - self.assertEqual(f.geometry().asWkt(-3), 'Point Z (-1296000 21435000 0)') + self.assertEqual(f.geometry().asWkt(-3), "Point Z (-1296000 21435000 0)") # points should be written to layer's edit buffer self.assertTrue(logger.writeToEditBuffer()) @@ -351,15 +433,18 @@ def test_point_recording(self): self.assertFalse(logger.writeToEditBuffer()) gps_connection.send_message( - '$GPRMC,084129.185,A,6939.4152,N,01856.8526,E,0.05,2.00,220120,,,A*6C') + "$GPRMC,084129.185,A,6939.4152,N,01856.8526,E,0.05,2.00,220120,,,A*6C" + ) self.assertEqual(points_layer.dataProvider().featureCount(), 1) def test_point_recording_no_z(self): points_layer = QgsVectorLayer( - 'Point?crs=EPSG:28355&field=timestamp:datetime&field=distance:double&field=seconds:double', 'points', - 'memory') + "Point?crs=EPSG:28355&field=timestamp:datetime&field=distance:double&field=seconds:double", + "points", + "memory", + ) self.assertTrue(points_layer.isValid()) - self.assertEqual(points_layer.crs().authid(), 'EPSG:28355') + self.assertEqual(points_layer.crs().authid(), "EPSG:28355") gps_connection = GpsReplay() @@ -367,13 +452,19 @@ def test_point_recording_no_z(self): logger.setPointsLayer(points_layer) spy = QSignalSpy(logger.stateChanged) - logger.setDestinationField(Qgis.GpsInformationComponent.Timestamp, 'timestamp') - logger.setDestinationField(Qgis.GpsInformationComponent.TrackDistanceSinceLastPoint, 'distance') - logger.setDestinationField(Qgis.GpsInformationComponent.TrackTimeSinceLastPoint, 'seconds') + logger.setDestinationField(Qgis.GpsInformationComponent.Timestamp, "timestamp") + logger.setDestinationField( + Qgis.GpsInformationComponent.TrackDistanceSinceLastPoint, "distance" + ) + logger.setDestinationField( + Qgis.GpsInformationComponent.TrackTimeSinceLastPoint, "seconds" + ) points_layer.startEditing() - gps_connection.send_message('$GPRMC,084111.185,A,6938.6531,N,01856.8527,E,0.16,2.00,220120,,,A*6E') + gps_connection.send_message( + "$GPRMC,084111.185,A,6938.6531,N,01856.8527,E,0.16,2.00,220120,,,A*6E" + ) self.assertEqual(len(spy), 1) self.assertEqual(points_layer.featureCount(), 1) @@ -382,17 +473,19 @@ def test_point_recording_no_z(self): exp.setOffsetFromUtc(3000) self.assertEqual(f.attributes(), [exp, None, None]) # should be no z value in geometry, to match layer dimensionality - self.assertEqual(f.geometry().asWkt(-3), 'Point (-1297000 21436000)') + self.assertEqual(f.geometry().asWkt(-3), "Point (-1297000 21436000)") def test_point_recording_m_value_epoch(self): points_layer = QgsVectorLayer( - 'PointM?crs=EPSG:28355&field=timestamp:datetime&field=distance:double&field=seconds:double', 'points', - 'memory') + "PointM?crs=EPSG:28355&field=timestamp:datetime&field=distance:double&field=seconds:double", + "points", + "memory", + ) self.assertTrue(points_layer.isValid()) - self.assertEqual(points_layer.crs().authid(), 'EPSG:28355') + self.assertEqual(points_layer.crs().authid(), "EPSG:28355") - QgsSettings().setValue('gps/store-attribute-in-m-values', True) - QgsSettings().setValue('gps/m-value-attribute', 'Timestamp') + QgsSettings().setValue("gps/store-attribute-in-m-values", True) + QgsSettings().setValue("gps/m-value-attribute", "Timestamp") gps_connection = GpsReplay() @@ -401,7 +494,9 @@ def test_point_recording_m_value_epoch(self): spy = QSignalSpy(logger.stateChanged) points_layer.startEditing() - gps_connection.send_message('$GPRMC,084111.185,A,6938.6531,N,01856.8527,E,0.16,2.00,220120,,,A*6E') + gps_connection.send_message( + "$GPRMC,084111.185,A,6938.6531,N,01856.8527,E,0.16,2.00,220120,,,A*6E" + ) self.assertEqual(len(spy), 1) self.assertEqual(logger.lastMValue(), 1579682471185.0) @@ -410,21 +505,27 @@ def test_point_recording_m_value_epoch(self): f = next(points_layer.getFeatures()) exp = QDateTime(2020, 1, 22, 9, 31, 59, 185) exp.setOffsetFromUtc(3000) - self.assertEqual(f.geometry().asWkt(-3), 'Point M (-1297000 21436000 1579682471000)') + self.assertEqual( + f.geometry().asWkt(-3), "Point M (-1297000 21436000 1579682471000)" + ) gps_connection.send_message( - '$GPRMC,084113.185,A,6938.9152,N,01856.8526,E,0.05,2.00,220120,,,A*6C') + "$GPRMC,084113.185,A,6938.9152,N,01856.8526,E,0.05,2.00,220120,,,A*6C" + ) self.assertEqual(len(spy), 2) - self.assertEqual(logger.lastMValue(), 1579682473185.) + self.assertEqual(logger.lastMValue(), 1579682473185.0) self.assertEqual(points_layer.featureCount(), 2) features = points_layer.getFeatures() next(features) f = next(features) - self.assertEqual(f.geometry().asWkt(-3), 'Point M (-1297000 21435000 1579682473000)') + self.assertEqual( + f.geometry().asWkt(-3), "Point M (-1297000 21435000 1579682473000)" + ) gps_connection.send_message( - '$GPRMC,084117.185,A,6939.3152,N,01856.8526,E,0.05,Z2.00,220120,,,A*6C') + "$GPRMC,084117.185,A,6939.3152,N,01856.8526,E,0.05,Z2.00,220120,,,A*6C" + ) self.assertEqual(len(spy), 3) self.assertEqual(logger.lastMValue(), 1579682477185.0) @@ -433,20 +534,23 @@ def test_point_recording_m_value_epoch(self): next(features) next(features) f = next(features) - self.assertEqual(f.geometry().asWkt(-3), 'Point M (-1296000 21435000 1579682477000)') - QgsSettings().setValue('gps/store-attribute-in-m-values', False) + self.assertEqual( + f.geometry().asWkt(-3), "Point M (-1296000 21435000 1579682477000)" + ) + QgsSettings().setValue("gps/store-attribute-in-m-values", False) def test_point_recording_m_value_altitude(self): points_layer = QgsVectorLayer( - 'PointZM?crs=EPSG:28355&field=timestamp:datetime&field=distance:double&field=seconds:double', - 'points', - 'memory') + "PointZM?crs=EPSG:28355&field=timestamp:datetime&field=distance:double&field=seconds:double", + "points", + "memory", + ) self.assertTrue(points_layer.isValid()) - self.assertEqual(points_layer.crs().authid(), 'EPSG:28355') + self.assertEqual(points_layer.crs().authid(), "EPSG:28355") self.assertEqual(points_layer.wkbType(), QgsWkbTypes.Type.PointZM) - QgsSettings().setValue('gps/store-attribute-in-m-values', True) - QgsSettings().setValue('gps/m-value-attribute', 'Altitude') + QgsSettings().setValue("gps/store-attribute-in-m-values", True) + QgsSettings().setValue("gps/m-value-attribute", "Altitude") gps_connection = GpsReplay() @@ -455,7 +559,9 @@ def test_point_recording_m_value_altitude(self): spy = QSignalSpy(logger.stateChanged) points_layer.startEditing() - gps_connection.send_message('$GPRMC,084111.185,A,6938.6531,N,01856.8527,E,0.16,2.00,220120,,,A*6E') + gps_connection.send_message( + "$GPRMC,084111.185,A,6938.6531,N,01856.8527,E,0.16,2.00,220120,,,A*6E" + ) self.assertEqual(len(spy), 1) self.assertEqual(logger.lastMValue(), 0) @@ -463,25 +569,32 @@ def test_point_recording_m_value_altitude(self): f = next(points_layer.getFeatures()) exp = QDateTime(2020, 1, 22, 9, 31, 59, 185) exp.setOffsetFromUtc(3000) - self.assertEqual(f.geometry().asWkt(-3), 'Point ZM (-1297000 21436000 0 0)') + self.assertEqual(f.geometry().asWkt(-3), "Point ZM (-1297000 21436000 0 0)") - gps_connection.send_message("$GPGGA,084112.185,6938.9152,N,01856.8526,E,1,04,1.4,3335.0,M,29.4,M,,0000*63") + gps_connection.send_message( + "$GPGGA,084112.185,6938.9152,N,01856.8526,E,1,04,1.4,3335.0,M,29.4,M,,0000*63" + ) self.assertEqual(len(spy), 2) self.assertEqual(logger.lastMValue(), 3335.0) self.assertEqual(points_layer.featureCount(), 2) features = points_layer.getFeatures() f = next(features) - self.assertEqual(f.geometry().asWkt(-3), 'Point ZM (-1297000 21436000 0 0)') + self.assertEqual(f.geometry().asWkt(-3), "Point ZM (-1297000 21436000 0 0)") f = next(features) - self.assertEqual(f.geometry().asWkt(-3), 'Point ZM (-1297000 21435000 3000 3000)') - QgsSettings().setValue('gps/store-attribute-in-m-values', False) + self.assertEqual( + f.geometry().asWkt(-3), "Point ZM (-1297000 21435000 3000 3000)" + ) + QgsSettings().setValue("gps/store-attribute-in-m-values", False) def test_track_recording(self): line_layer = QgsVectorLayer( - 'LineStringZ?crs=EPSG:28355&field=start:datetime&field=end:string&field=length:double', 'lines', 'memory') + "LineStringZ?crs=EPSG:28355&field=start:datetime&field=end:string&field=length:double", + "lines", + "memory", + ) self.assertTrue(line_layer.isValid()) - self.assertEqual(line_layer.crs().authid(), 'EPSG:28355') + self.assertEqual(line_layer.crs().authid(), "EPSG:28355") gps_connection = GpsReplay() @@ -489,24 +602,30 @@ def test_track_recording(self): logger.setTracksLayer(line_layer) spy = QSignalSpy(logger.stateChanged) - logger.setDestinationField(Qgis.GpsInformationComponent.TotalTrackLength, 'length') - logger.setDestinationField(Qgis.GpsInformationComponent.TrackStartTime, 'start') - logger.setDestinationField(Qgis.GpsInformationComponent.TrackEndTime, 'end') + logger.setDestinationField( + Qgis.GpsInformationComponent.TotalTrackLength, "length" + ) + logger.setDestinationField(Qgis.GpsInformationComponent.TrackStartTime, "start") + logger.setDestinationField(Qgis.GpsInformationComponent.TrackEndTime, "end") line_layer.startEditing() - gps_connection.send_message('$GPRMC,084111.185,A,6938.6531,N,01856.8527,E,0.16,2.00,220120,,,A*6E') + gps_connection.send_message( + "$GPRMC,084111.185,A,6938.6531,N,01856.8527,E,0.16,2.00,220120,,,A*6E" + ) self.assertEqual(len(spy), 1) # should be no features until track is ended self.assertEqual(line_layer.featureCount(), 0) gps_connection.send_message( - '$GPRMC,084113.185,A,6938.9152,N,01856.8526,E,0.05,2.00,220120,,,A*6C') + "$GPRMC,084113.185,A,6938.9152,N,01856.8526,E,0.05,2.00,220120,,,A*6C" + ) self.assertEqual(len(spy), 2) gps_connection.send_message( - '$GPRMC,084118.185,A,6938.9152,N,01857.8526,E,0.05,2.00,220120,,,A*6C') + "$GPRMC,084118.185,A,6938.9152,N,01857.8526,E,0.05,2.00,220120,,,A*6C" + ) self.assertEqual(len(spy), 3) self.assertEqual(line_layer.featureCount(), 0) @@ -517,11 +636,13 @@ def test_track_recording(self): f = next(line_layer.getFeatures()) exp = QDateTime(2020, 1, 22, 9, 31, 59, 185) exp.setOffsetFromUtc(3000) - self.assertEqual(f.attributes(), - [exp, '2020-01-22T09:32:06+00:50', - 0.021035000317942486]) - self.assertEqual(f.geometry().asWkt(-2), - 'LineString Z (-1297400 21435500 0, -1297000 21435200 0, -1297400 21434700 0)') + self.assertEqual( + f.attributes(), [exp, "2020-01-22T09:32:06+00:50", 0.021035000317942486] + ) + self.assertEqual( + f.geometry().asWkt(-2), + "LineString Z (-1297400 21435500 0, -1297000 21435200 0, -1297400 21434700 0)", + ) self.assertFalse(logger.currentTrack()) @@ -533,17 +654,22 @@ def test_track_recording(self): self.assertFalse(logger.writeToEditBuffer()) gps_connection.send_message( - '$GPRMC,084129.185,A,6939.4152,N,01856.8526,E,0.05,2.00,220120,,,A*6C') + "$GPRMC,084129.185,A,6939.4152,N,01856.8526,E,0.05,2.00,220120,,,A*6C" + ) gps_connection.send_message( - '$GPRMC,084129.185,A,6939.4152,N,01956.8526,E,0.05,2.00,220120,,,A*6C') + "$GPRMC,084129.185,A,6939.4152,N,01956.8526,E,0.05,2.00,220120,,,A*6C" + ) logger.endCurrentTrack() self.assertEqual(line_layer.dataProvider().featureCount(), 1) def test_track_recording_no_z(self): line_layer = QgsVectorLayer( - 'LineString?crs=EPSG:28355&field=start:datetime&field=end:string&field=length:double', 'lines', 'memory') + "LineString?crs=EPSG:28355&field=start:datetime&field=end:string&field=length:double", + "lines", + "memory", + ) self.assertTrue(line_layer.isValid()) - self.assertEqual(line_layer.crs().authid(), 'EPSG:28355') + self.assertEqual(line_layer.crs().authid(), "EPSG:28355") gps_connection = GpsReplay() @@ -551,24 +677,30 @@ def test_track_recording_no_z(self): logger.setTracksLayer(line_layer) spy = QSignalSpy(logger.stateChanged) - logger.setDestinationField(Qgis.GpsInformationComponent.TotalTrackLength, 'length') - logger.setDestinationField(Qgis.GpsInformationComponent.TrackStartTime, 'start') - logger.setDestinationField(Qgis.GpsInformationComponent.TrackEndTime, 'end') + logger.setDestinationField( + Qgis.GpsInformationComponent.TotalTrackLength, "length" + ) + logger.setDestinationField(Qgis.GpsInformationComponent.TrackStartTime, "start") + logger.setDestinationField(Qgis.GpsInformationComponent.TrackEndTime, "end") line_layer.startEditing() - gps_connection.send_message('$GPRMC,084111.185,A,6938.6531,N,01856.8527,E,0.16,2.00,220120,,,A*6E') + gps_connection.send_message( + "$GPRMC,084111.185,A,6938.6531,N,01856.8527,E,0.16,2.00,220120,,,A*6E" + ) self.assertEqual(len(spy), 1) # should be no features until track is ended self.assertEqual(line_layer.featureCount(), 0) gps_connection.send_message( - '$GPRMC,084113.185,A,6938.9152,N,01856.8526,E,0.05,2.00,220120,,,A*6C') + "$GPRMC,084113.185,A,6938.9152,N,01856.8526,E,0.05,2.00,220120,,,A*6C" + ) self.assertEqual(len(spy), 2) gps_connection.send_message( - '$GPRMC,084118.185,A,6938.9152,N,01857.8526,E,0.05,2.00,220120,,,A*6C') + "$GPRMC,084118.185,A,6938.9152,N,01857.8526,E,0.05,2.00,220120,,,A*6C" + ) self.assertEqual(len(spy), 3) self.assertEqual(line_layer.featureCount(), 0) @@ -579,20 +711,25 @@ def test_track_recording_no_z(self): f = next(line_layer.getFeatures()) exp = QDateTime(2020, 1, 22, 9, 31, 59, 185) exp.setOffsetFromUtc(3000) - self.assertEqual(f.attributes(), - [exp, '2020-01-22T09:32:06+00:50', - 0.021035000317942486]) - self.assertEqual(f.geometry().asWkt(-2), - 'LineString (-1297400 21435500, -1297000 21435200, -1297400 21434700)') + self.assertEqual( + f.attributes(), [exp, "2020-01-22T09:32:06+00:50", 0.021035000317942486] + ) + self.assertEqual( + f.geometry().asWkt(-2), + "LineString (-1297400 21435500, -1297000 21435200, -1297400 21434700)", + ) def test_track_recording_z_m_timestamp(self): line_layer = QgsVectorLayer( - 'LineStringZM?crs=EPSG:28355&field=start:datetime&field=end:string&field=length:double', 'lines', 'memory') + "LineStringZM?crs=EPSG:28355&field=start:datetime&field=end:string&field=length:double", + "lines", + "memory", + ) self.assertTrue(line_layer.isValid()) - self.assertEqual(line_layer.crs().authid(), 'EPSG:28355') + self.assertEqual(line_layer.crs().authid(), "EPSG:28355") - QgsSettings().setValue('gps/store-attribute-in-m-values', True) - QgsSettings().setValue('gps/m-value-attribute', 'Timestamp') + QgsSettings().setValue("gps/store-attribute-in-m-values", True) + QgsSettings().setValue("gps/m-value-attribute", "Timestamp") gps_connection = GpsReplay() @@ -600,24 +737,30 @@ def test_track_recording_z_m_timestamp(self): logger.setTracksLayer(line_layer) spy = QSignalSpy(logger.stateChanged) - logger.setDestinationField(Qgis.GpsInformationComponent.TotalTrackLength, 'length') - logger.setDestinationField(Qgis.GpsInformationComponent.TrackStartTime, 'start') - logger.setDestinationField(Qgis.GpsInformationComponent.TrackEndTime, 'end') + logger.setDestinationField( + Qgis.GpsInformationComponent.TotalTrackLength, "length" + ) + logger.setDestinationField(Qgis.GpsInformationComponent.TrackStartTime, "start") + logger.setDestinationField(Qgis.GpsInformationComponent.TrackEndTime, "end") line_layer.startEditing() - gps_connection.send_message('$GPRMC,084111.185,A,6938.6531,N,01856.8527,E,0.16,2.00,220120,,,A*6E') + gps_connection.send_message( + "$GPRMC,084111.185,A,6938.6531,N,01856.8527,E,0.16,2.00,220120,,,A*6E" + ) self.assertEqual(len(spy), 1) # should be no features until track is ended self.assertEqual(line_layer.featureCount(), 0) gps_connection.send_message( - '$GPRMC,084113.185,A,6938.9152,N,01856.8526,E,0.05,2.00,220120,,,A*6C') + "$GPRMC,084113.185,A,6938.9152,N,01856.8526,E,0.05,2.00,220120,,,A*6C" + ) self.assertEqual(len(spy), 2) gps_connection.send_message( - '$GPRMC,084118.185,A,6938.9152,N,01857.8526,E,0.05,2.00,220120,,,A*6C') + "$GPRMC,084118.185,A,6938.9152,N,01857.8526,E,0.05,2.00,220120,,,A*6C" + ) self.assertEqual(len(spy), 3) self.assertEqual(line_layer.featureCount(), 0) @@ -628,12 +771,14 @@ def test_track_recording_z_m_timestamp(self): f = next(line_layer.getFeatures()) exp = QDateTime(2020, 1, 22, 9, 31, 59, 185) exp.setOffsetFromUtc(3000) - self.assertEqual(f.attributes(), - [exp, '2020-01-22T09:32:06+00:50', - 0.021035000317942486]) - self.assertEqual(f.geometry().asWkt(-2), - 'LineString ZM (-1297400 21435500 0 1579682471200, -1297000 21435200 0 1579682473200, -1297400 21434700 0 1579682478200)') + self.assertEqual( + f.attributes(), [exp, "2020-01-22T09:32:06+00:50", 0.021035000317942486] + ) + self.assertEqual( + f.geometry().asWkt(-2), + "LineString ZM (-1297400 21435500 0 1579682471200, -1297000 21435200 0 1579682473200, -1297400 21434700 0 1579682478200)", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsgraduatedsymbolrenderer.py b/tests/src/python/test_qgsgraduatedsymbolrenderer.py index f3b0a3662af6..202b27d8c58b 100644 --- a/tests/src/python/test_qgsgraduatedsymbolrenderer.py +++ b/tests/src/python/test_qgsgraduatedsymbolrenderer.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Chris Crook' -__date__ = '3/10/2014' -__copyright__ = 'Copyright 2014, The QGIS Project' + +__author__ = "Chris Crook" +__date__ = "3/10/2014" +__copyright__ = "Copyright 2014, The QGIS Project" from qgis.PyQt.QtCore import Qt from qgis.PyQt.QtGui import QColor @@ -37,24 +38,21 @@ def createMarkerSymbol(): - symbol = QgsMarkerSymbol.createSimple({ - "color": "100,150,50", - "name": "square", - "size": "3.0" - }) + symbol = QgsMarkerSymbol.createSimple( + {"color": "100,150,50", "name": "square", "size": "3.0"} + ) return symbol def createFillSymbol(): - symbol = QgsFillSymbol.createSimple({ - "color": "100,150,50" - }) + symbol = QgsFillSymbol.createSimple({"color": "100,150,50"}) return symbol def createMemoryLayer(values): - ml = QgsVectorLayer("Point?crs=epsg:4236&field=id:integer&field=value:double", - "test_data", "memory") + ml = QgsVectorLayer( + "Point?crs=epsg:4236&field=id:integer&field=value:double", "test_data", "memory" + ) # Data as list of x, y, id, value assert ml.isValid() pr = ml.dataProvider() @@ -62,8 +60,8 @@ def createMemoryLayer(values): for id, value in enumerate(values): x = id * 10.0 feat = QgsFeature(fields) - feat['id'] = id - feat['value'] = value + feat["id"] = id + feat["value"] = value g = QgsGeometry.fromPointXY(QgsPointXY(x, x)) feat.setGeometry(g) pr.addFeatures([feat]) @@ -72,10 +70,7 @@ def createMemoryLayer(values): def createColorRamp(): - return QgsGradientColorRamp( - QColor(255, 0, 0), - QColor(0, 0, 255) - ) + return QgsGradientColorRamp(QColor(255, 0, 0), QColor(0, 0, 255)) def createLabelFormat(): @@ -103,28 +98,36 @@ def dumpRangeLabels(ranges): def dumpLabelFormat(format): return ( - ':' + format.format() + - ':' + str(format.precision()) + - ':' + str(format.trimTrailingZeroes()) + - ':') + ":" + + format.format() + + ":" + + str(format.precision()) + + ":" + + str(format.trimTrailingZeroes()) + + ":" + ) def dumpRangeList(rlist, breaksOnly=False, labelsOnly=False): - rstr = '(' + rstr = "(" format = "{0:.4f}-{1:.4f}" if not breaksOnly: format = format + ":{2}:{3}:{4}:" if labelsOnly: - format = '{2}' + format = "{2}" for r in rlist: - rstr = rstr + format.format( - r.lowerValue(), - r.upperValue(), - r.label(), - r.symbol().dump(), - r.renderState(), - ) + "," - return rstr + ')' + rstr = ( + rstr + + format.format( + r.lowerValue(), + r.upperValue(), + r.label(), + r.symbol().dump(), + r.renderState(), + ) + + "," + ) + return rstr + ")" # Crude dump for deterministic ramp - just dumps colors at a range of values @@ -132,22 +135,22 @@ def dumpRangeList(rlist, breaksOnly=False, labelsOnly=False): def dumpColorRamp(ramp): if ramp is None: - return ':None:' - rampstr = ':' + return ":None:" + rampstr = ":" for x in (0.0, 0.33, 0.66, 1.0): - rampstr = rampstr + ramp.color(x).name() + ':' + rampstr = rampstr + ramp.color(x).name() + ":" return rampstr def dumpGraduatedRenderer(r): - rstr = ':' - rstr = rstr + r.classAttribute() + ':' - rstr = rstr + str(r.mode()) + ':' + rstr = ":" + rstr = rstr + r.classAttribute() + ":" + rstr = rstr + str(r.mode()) + ":" symbol = r.sourceSymbol() if symbol is None: - rstr = rstr + 'None' + ':' + rstr = rstr + "None" + ":" else: - rstr = rstr + symbol.dump() + ':' + rstr = rstr + symbol.dump() + ":" rstr = rstr + dumpColorRamp(r.sourceColorRamp()) rstr = rstr + dumpRangeList(r.ranges()) return rstr @@ -184,12 +187,20 @@ def testQgsRendererRange_1(self): range.setRenderState(False) self.assertFalse(range.renderState(), "Render state getter/setter failed") range.setSymbol(symbol.clone()) - self.assertEqual(symbol.dump(), range.symbol().dump(), "Symbol getter/setter failed") + self.assertEqual( + symbol.dump(), range.symbol().dump(), "Symbol getter/setter failed" + ) range2 = QgsRendererRange(lower, upper, symbol.clone(), label, False) - self.assertEqual(range2.lowerValue(), lower, "Lower value from constructor failed") - self.assertEqual(range2.upperValue(), upper, "Upper value from constructor failed") + self.assertEqual( + range2.lowerValue(), lower, "Lower value from constructor failed" + ) + self.assertEqual( + range2.upperValue(), upper, "Upper value from constructor failed" + ) self.assertEqual(range2.label(), label, "Label from constructor failed") - self.assertEqual(range2.symbol().dump(), symbol.dump(), "Symbol from constructor failed") + self.assertEqual( + range2.symbol().dump(), symbol.dump(), "Symbol from constructor failed" + ) self.assertFalse(range2.renderState(), "Render state getter/setter failed") def testQgsRendererRangeLabelFormat_1(self): @@ -201,19 +212,37 @@ def testQgsRendererRangeLabelFormat_1(self): format.setFormat(template) self.assertEqual(format.format(), template, "Format getter/setter failed") format.setPrecision(precision) - self.assertEqual(format.precision(), precision, "Precision getter/setter failed") + self.assertEqual( + format.precision(), precision, "Precision getter/setter failed" + ) format.setTrimTrailingZeroes(True) - self.assertTrue(format.trimTrailingZeroes(), "TrimTrailingZeroes getter/setter failed") + self.assertTrue( + format.trimTrailingZeroes(), "TrimTrailingZeroes getter/setter failed" + ) format.setTrimTrailingZeroes(False) - self.assertFalse(format.trimTrailingZeroes(), "TrimTrailingZeroes getter/setter failed") + self.assertFalse( + format.trimTrailingZeroes(), "TrimTrailingZeroes getter/setter failed" + ) minprecision = -6 maxprecision = 15 - self.assertEqual(QgsRendererRangeLabelFormat.MIN_PRECISION, minprecision, "Minimum precision != -6") - self.assertEqual(QgsRendererRangeLabelFormat.MAX_PRECISION, maxprecision, "Maximum precision != 15") + self.assertEqual( + QgsRendererRangeLabelFormat.MIN_PRECISION, + minprecision, + "Minimum precision != -6", + ) + self.assertEqual( + QgsRendererRangeLabelFormat.MAX_PRECISION, + maxprecision, + "Maximum precision != 15", + ) format.setPrecision(-10) - self.assertEqual(format.precision(), minprecision, "Minimum precision not enforced") + self.assertEqual( + format.precision(), minprecision, "Minimum precision not enforced" + ) format.setPrecision(20) - self.assertEqual(format.precision(), maxprecision, "Maximum precision not enforced") + self.assertEqual( + format.precision(), maxprecision, "Maximum precision not enforced" + ) def testQgsRendererRangeLabelFormat_2(self): """Test QgsRendererRangeLabelFormat number format""" @@ -221,32 +250,36 @@ def testQgsRendererRangeLabelFormat_2(self): # Tests have precision, trim, value, expected # (Note: Not sure what impact of locale is on these tests) tests = ( - (2, False, 1.0, '1.00'), - (2, True, 1.0, '1'), - (2, False, 1.234, '1.23'), - (2, True, 1.234, '1.23'), - (2, False, 1.236, '1.24'), - (2, False, -1.236, '-1.24'), - (2, False, -0.004, '0.00'), - (2, True, 1.002, '1'), - (2, True, 1.006, '1.01'), - (2, True, 1.096, '1.1'), - (3, True, 1.096, '1.096'), - (-2, True, 1496.45, '1500'), - (-2, True, 149.45, '100'), - (-2, True, 79.45, '100'), - (-2, True, 49.45, '0'), - (-2, True, -49.45, '0'), - (-2, True, -149.45, '-100'), + (2, False, 1.0, "1.00"), + (2, True, 1.0, "1"), + (2, False, 1.234, "1.23"), + (2, True, 1.234, "1.23"), + (2, False, 1.236, "1.24"), + (2, False, -1.236, "-1.24"), + (2, False, -0.004, "0.00"), + (2, True, 1.002, "1"), + (2, True, 1.006, "1.01"), + (2, True, 1.096, "1.1"), + (3, True, 1.096, "1.096"), + (-2, True, 1496.45, "1500"), + (-2, True, 149.45, "100"), + (-2, True, 79.45, "100"), + (-2, True, 49.45, "0"), + (-2, True, -49.45, "0"), + (-2, True, -149.45, "-100"), ) for f in tests: precision, trim, value, expected = f format.setPrecision(precision) format.setTrimTrailingZeroes(trim) result = format.formatNumber(value) - self.assertEqual(result, expected, - "Number format error {}:{}:{} => {}".format( - precision, trim, value, result)) + self.assertEqual( + result, + expected, + "Number format error {}:{}:{} => {}".format( + precision, trim, value, result + ), + ) # Label tests - label format, expected result. # Labels will be evaluated with lower=1.23 upper=2.34, precision=2 @@ -268,8 +301,9 @@ def testQgsRendererRangeLabelFormat_2(self): label, expected = t format.setFormat(label) result = format.labelForLowerUpper(lower, upper) - self.assertEqual(result, expected, "Label format error {} => {}".format( - label, result)) + self.assertEqual( + result, expected, f"Label format error {label} => {result}" + ) range = QgsRendererRange() range.setLowerValue(lower) @@ -277,22 +311,29 @@ def testQgsRendererRangeLabelFormat_2(self): label = ltests[0][0] format.setFormat(label) result = format.labelForRange(range) - self.assertEqual(result, ltests[0][1], "Label for range error {} => {}".format( - label, result)) + self.assertEqual( + result, ltests[0][1], f"Label for range error {label} => {result}" + ) def testQgsGraduatedSymbolRenderer_1(self): - """Test QgsGraduatedSymbolRenderer: Basic get/set functions """ + """Test QgsGraduatedSymbolRenderer: Basic get/set functions""" # Create a renderer renderer = QgsGraduatedSymbolRenderer() symbol = createMarkerSymbol() renderer.setSourceSymbol(symbol.clone()) - self.assertEqual(symbol.dump(), renderer.sourceSymbol().dump(), "Get/set renderer source symbol") + self.assertEqual( + symbol.dump(), + renderer.sourceSymbol().dump(), + "Get/set renderer source symbol", + ) attr = '"value"*"value"' renderer.setClassAttribute(attr) - self.assertEqual(attr, renderer.classAttribute(), "Get/set renderer class attribute") + self.assertEqual( + attr, renderer.classAttribute(), "Get/set renderer class attribute" + ) for m in ( QgsGraduatedSymbolRenderer.Mode.Custom, @@ -310,23 +351,28 @@ def testQgsGraduatedSymbolRenderer_1(self): self.assertEqual( dumpLabelFormat(format), dumpLabelFormat(renderer.labelFormat()), - "Get/set renderer label format") + "Get/set renderer label format", + ) ramp = createColorRamp() renderer.setSourceColorRamp(ramp) self.assertEqual( dumpColorRamp(ramp), dumpColorRamp(renderer.sourceColorRamp()), - "Get/set renderer color ramp") + "Get/set renderer color ramp", + ) renderer.setSourceColorRamp(ramp) self.assertEqual( dumpColorRamp(ramp), dumpColorRamp(renderer.sourceColorRamp()), - "Get/set renderer color ramp") + "Get/set renderer color ramp", + ) # test for classificatio with varying size - renderer.setGraduatedMethod(QgsGraduatedSymbolRenderer.GraduatedMethod.GraduatedSize) + renderer.setGraduatedMethod( + QgsGraduatedSymbolRenderer.GraduatedMethod.GraduatedSize + ) renderer.setSourceColorRamp(None) renderer.addClassLowerUpper(0, 2) renderer.addClassLowerUpper(2, 4) @@ -334,13 +380,13 @@ def testQgsGraduatedSymbolRenderer_1(self): renderer.setSymbolSizes(2, 13) self.assertEqual(renderer.maxSymbolSize(), 13) self.assertEqual(renderer.minSymbolSize(), 2) - refSizes = [2, (13 + 2) * .5, 13] + refSizes = [2, (13 + 2) * 0.5, 13] ctx = QgsRenderContext() for idx, symbol in enumerate(renderer.symbols(ctx)): self.assertEqual(symbol.size(), refSizes[idx]) def testQgsGraduatedSymbolRenderer_2(self): - """Test QgsGraduatedSymbolRenderer: Adding /removing/editing classes """ + """Test QgsGraduatedSymbolRenderer: Adding /removing/editing classes""" # Create a renderer renderer = QgsGraduatedSymbolRenderer() symbol = createMarkerSymbol() @@ -351,7 +397,7 @@ def testQgsGraduatedSymbolRenderer_2(self): renderer.addClass(symbol.clone()) renderer.addClass(symbol.clone()) - renderer.updateRangeLabel(1, 'Second range') + renderer.updateRangeLabel(1, "Second range") renderer.updateRangeLowerValue(1, 10.0) renderer.updateRangeUpperValue(1, 25.0) renderer.updateRangeRenderState(1, False) @@ -360,7 +406,7 @@ def testQgsGraduatedSymbolRenderer_2(self): # Add as a rangeobject symbol.setColor(QColor(0, 255, 0)) - range = QgsRendererRange(20.0, 25.5, symbol.clone(), 'Third range', False) + range = QgsRendererRange(20.0, 25.5, symbol.clone(), "Third range", False) renderer.addClassRange(range) # Add classification method label and precision @@ -370,16 +416,18 @@ def testQgsGraduatedSymbolRenderer_2(self): # Add class by lower and upper renderer.addClassLowerUpper(25.5, 30.5) # (Update label for sorting tests) - renderer.updateRangeLabel(3, 'Another range') + renderer.updateRangeLabel(3, "Another range") self.assertEqual( dumpRangeLabels(renderer.ranges()), - '(0.0 - 0.0,Second range,Third range,Another range,)', - 'Added ranges labels not correct') + "(0.0 - 0.0,Second range,Third range,Another range,)", + "Added ranges labels not correct", + ) self.assertEqual( dumpRangeBreaks(renderer.ranges()), - '(0.0000-0.0000,10.0000-25.0000,20.0000-25.5000,25.5000-30.5000,)', - 'Added ranges lower/upper values not correct') + "(0.0000-0.0000,10.0000-25.0000,20.0000-25.5000,25.5000-30.5000,)", + "Added ranges lower/upper values not correct", + ) # Check that clone function works @@ -387,7 +435,7 @@ def testQgsGraduatedSymbolRenderer_2(self): self.assertEqual( dumpGraduatedRenderer(renderer), dumpGraduatedRenderer(renderer2), - "clone function doesn't replicate renderer properly" + "clone function doesn't replicate renderer properly", ) # Check save and reload from Dom works @@ -398,7 +446,7 @@ def testQgsGraduatedSymbolRenderer_2(self): self.assertEqual( dumpGraduatedRenderer(renderer), dumpGraduatedRenderer(renderer2), - "Save/create from DOM doesn't replicate renderer properly" + "Save/create from DOM doesn't replicate renderer properly", ) # Check classification method label and precision properly created from DOM @@ -410,29 +458,35 @@ def testQgsGraduatedSymbolRenderer_2(self): renderer.sortByLabel() self.assertEqual( dumpRangeList(renderer.ranges(), labelsOnly=True), - '(0.0 - 0.0,Another range,Second range,Third range,)', - 'sortByLabel not correct') + "(0.0 - 0.0,Another range,Second range,Third range,)", + "sortByLabel not correct", + ) renderer.sortByValue() self.assertEqual( dumpRangeBreaks(renderer.ranges()), - '(0.0000-0.0000,10.0000-25.0000,20.0000-25.5000,25.5000-30.5000,)', - 'sortByValue not correct') + "(0.0000-0.0000,10.0000-25.0000,20.0000-25.5000,25.5000-30.5000,)", + "sortByValue not correct", + ) renderer.sortByValue(Qt.SortOrder.DescendingOrder) self.assertEqual( dumpRangeBreaks(renderer.ranges()), - '(25.5000-30.5000,20.0000-25.5000,10.0000-25.0000,0.0000-0.0000,)', - 'sortByValue descending not correct') + "(25.5000-30.5000,20.0000-25.5000,10.0000-25.0000,0.0000-0.0000,)", + "sortByValue descending not correct", + ) # Check deleting renderer.deleteClass(2) self.assertEqual( dumpRangeBreaks(renderer.ranges()), - '(25.5000-30.5000,20.0000-25.5000,0.0000-0.0000,)', - 'deleteClass not correct') + "(25.5000-30.5000,20.0000-25.5000,0.0000-0.0000,)", + "deleteClass not correct", + ) renderer.deleteAllClasses() - self.assertEqual(len(renderer.ranges()), 0, "deleteAllClasses didn't delete all") + self.assertEqual( + len(renderer.ranges()), 0, "deleteAllClasses didn't delete all" + ) # void addClass( QgsSymbol* symbol ); # //! \note available in python bindings as addClassRange @@ -443,7 +497,7 @@ def testQgsGraduatedSymbolRenderer_2(self): # void deleteAllClasses(); def testQgsGraduatedSymbolRenderer_3(self): - """Test QgsGraduatedSymbolRenderer: Reading attribute data, calculating classes """ + """Test QgsGraduatedSymbolRenderer: Reading attribute data, calculating classes""" # Create a renderer renderer = QgsGraduatedSymbolRenderer() @@ -458,20 +512,23 @@ def testQgsGraduatedSymbolRenderer_3(self): renderer.updateClasses(ml, renderer.EqualInterval, 3) self.assertEqual( dumpRangeBreaks(renderer.ranges()), - '(0.5000-2.0000,2.0000-3.5000,3.5000-5.0000,)', - 'Equal interval classification not correct') + "(0.5000-2.0000,2.0000-3.5000,3.5000-5.0000,)", + "Equal interval classification not correct", + ) # Quantile classes renderer.updateClasses(ml, renderer.Quantile, 3) self.assertEqual( dumpRangeBreaks(renderer.ranges()), - '(0.5000-1.0000,1.0000-1.2000,1.2000-5.0000,)', - 'Quantile classification not correct') + "(0.5000-1.0000,1.0000-1.2000,1.2000-5.0000,)", + "Quantile classification not correct", + ) renderer.updateClasses(ml, renderer.Quantile, 4) self.assertEqual( dumpRangeBreaks(renderer.ranges()), - '(0.5000-1.0000,1.0000-1.1000,1.1000-1.2000,1.2000-5.0000,)', - 'Quantile classification not correct') + "(0.5000-1.0000,1.0000-1.1000,1.1000-1.2000,1.2000-5.0000,)", + "Quantile classification not correct", + ) def testUsedAttributes(self): renderer = QgsGraduatedSymbolRenderer() @@ -486,7 +543,9 @@ def testUsedAttributes(self): renderer.setClassAttribute("value - 1") self.assertEqual(renderer.usedAttributes(ctx), {"value", "value - 1"}) renderer.setClassAttribute("valuea - valueb") - self.assertEqual(renderer.usedAttributes(ctx), {"valuea", "valuea - valueb", "valueb"}) + self.assertEqual( + renderer.usedAttributes(ctx), {"valuea", "valuea - valueb", "valueb"} + ) def testFilterNeedsGeometry(self): renderer = QgsGraduatedSymbolRenderer() @@ -500,87 +559,97 @@ def testFilterNeedsGeometry(self): def test_legend_keys(self): renderer = QgsGraduatedSymbolRenderer() - renderer.setClassAttribute('field_name') + renderer.setClassAttribute("field_name") self.assertFalse(renderer.legendKeys()) symbol_a = createMarkerSymbol() - renderer.addClassRange(QgsRendererRange(1, 2, symbol_a, 'a', True, '0')) + renderer.addClassRange(QgsRendererRange(1, 2, symbol_a, "a", True, "0")) symbol_b = createMarkerSymbol() - renderer.addClassRange(QgsRendererRange(5, 6, symbol_b, 'b', True, '1')) + renderer.addClassRange(QgsRendererRange(5, 6, symbol_b, "b", True, "1")) symbol_c = createMarkerSymbol() - renderer.addClassRange(QgsRendererRange(15.5, 16.5, symbol_c, 'c', False, '2')) + renderer.addClassRange(QgsRendererRange(15.5, 16.5, symbol_c, "c", False, "2")) - self.assertEqual(renderer.legendKeys(), {'0', '1', '2'}) + self.assertEqual(renderer.legendKeys(), {"0", "1", "2"}) def test_legend_key_to_expression(self): renderer = QgsGraduatedSymbolRenderer() - renderer.setClassAttribute('field_name') + renderer.setClassAttribute("field_name") - exp, ok = renderer.legendKeyToExpression('xxxx', None) + exp, ok = renderer.legendKeyToExpression("xxxx", None) self.assertFalse(ok) # no categories - exp, ok = renderer.legendKeyToExpression('0', None) + exp, ok = renderer.legendKeyToExpression("0", None) self.assertFalse(ok) symbol_a = createMarkerSymbol() - renderer.addClassRange(QgsRendererRange(1, 2, symbol_a, 'a', True, '0')) + renderer.addClassRange(QgsRendererRange(1, 2, symbol_a, "a", True, "0")) symbol_b = createMarkerSymbol() - renderer.addClassRange(QgsRendererRange(5, 6, symbol_b, 'b', True, '1')) + renderer.addClassRange(QgsRendererRange(5, 6, symbol_b, "b", True, "1")) symbol_c = createMarkerSymbol() - renderer.addClassRange(QgsRendererRange(15.5, 16.5, symbol_c, 'c', False, '2')) + renderer.addClassRange(QgsRendererRange(15.5, 16.5, symbol_c, "c", False, "2")) - exp, ok = renderer.legendKeyToExpression('0', None) + exp, ok = renderer.legendKeyToExpression("0", None) self.assertTrue(ok) self.assertEqual(exp, "(field_name >= 1) AND (field_name <= 2)") - exp, ok = renderer.legendKeyToExpression('1', None) + exp, ok = renderer.legendKeyToExpression("1", None) self.assertTrue(ok) self.assertEqual(exp, "(field_name >= 5) AND (field_name <= 6)") - exp, ok = renderer.legendKeyToExpression('2', None) + exp, ok = renderer.legendKeyToExpression("2", None) self.assertTrue(ok) self.assertEqual(exp, "(field_name >= 15.5) AND (field_name <= 16.5)") - exp, ok = renderer.legendKeyToExpression('3', None) + exp, ok = renderer.legendKeyToExpression("3", None) self.assertFalse(ok) - layer = QgsVectorLayer("Point?field=field_name:double&field=fldint:integer", "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=field_name:double&field=fldint:integer", "addfeat", "memory" + ) # with layer - exp, ok = renderer.legendKeyToExpression('2', layer) + exp, ok = renderer.legendKeyToExpression("2", layer) self.assertTrue(ok) self.assertEqual(exp, """("field_name" >= 15.5) AND ("field_name" <= 16.5)""") # with expression as attribute renderer.setClassAttribute('log("field_name")') - exp, ok = renderer.legendKeyToExpression('0', None) + exp, ok = renderer.legendKeyToExpression("0", None) self.assertTrue(ok) - self.assertEqual(exp, """(log("field_name") >= 1) AND (log("field_name") <= 2)""") + self.assertEqual( + exp, """(log("field_name") >= 1) AND (log("field_name") <= 2)""" + ) - exp, ok = renderer.legendKeyToExpression('1', None) + exp, ok = renderer.legendKeyToExpression("1", None) self.assertTrue(ok) - self.assertEqual(exp, """(log("field_name") >= 5) AND (log("field_name") <= 6)""") + self.assertEqual( + exp, """(log("field_name") >= 5) AND (log("field_name") <= 6)""" + ) - exp, ok = renderer.legendKeyToExpression('2', None) + exp, ok = renderer.legendKeyToExpression("2", None) self.assertTrue(ok) - self.assertEqual(exp, """(log("field_name") >= 15.5) AND (log("field_name") <= 16.5)""") + self.assertEqual( + exp, """(log("field_name") >= 15.5) AND (log("field_name") <= 16.5)""" + ) - exp, ok = renderer.legendKeyToExpression('2', layer) + exp, ok = renderer.legendKeyToExpression("2", layer) self.assertTrue(ok) - self.assertEqual(exp, """(log("field_name") >= 15.5) AND (log("field_name") <= 16.5)""") + self.assertEqual( + exp, """(log("field_name") >= 15.5) AND (log("field_name") <= 16.5)""" + ) def test_to_sld(self): renderer = QgsGraduatedSymbolRenderer() - renderer.setClassAttribute('field_name') + renderer.setClassAttribute("field_name") symbol_a = createMarkerSymbol() - renderer.addClassRange(QgsRendererRange(1, 2, symbol_a, 'a', True, '0')) + renderer.addClassRange(QgsRendererRange(1, 2, symbol_a, "a", True, "0")) symbol_b = createMarkerSymbol() - renderer.addClassRange(QgsRendererRange(5, 6, symbol_b, 'b', True, '1')) + renderer.addClassRange(QgsRendererRange(5, 6, symbol_b, "b", True, "1")) symbol_c = createMarkerSymbol() - renderer.addClassRange(QgsRendererRange(15.5, 16.5, symbol_c, 'c', False, '2')) + renderer.addClassRange(QgsRendererRange(15.5, 16.5, symbol_c, "c", False, "2")) # this category should NOT be included in the SLD, as it would otherwise result # in an invalid se:rule with no symbolizer element @@ -588,7 +657,8 @@ def test_to_sld(self): symbol_which_is_empty_in_sld[0].setBrushStyle(Qt.BrushStyle.NoBrush) symbol_which_is_empty_in_sld[0].setStrokeStyle(Qt.PenStyle.NoPen) renderer.addClassRange( - QgsRendererRange(25.5, 26.5, symbol_which_is_empty_in_sld, 'd', False, '2')) + QgsRendererRange(25.5, 26.5, symbol_which_is_empty_in_sld, "d", False, "2") + ) dom = QDomDocument() root = dom.createElement("FakeRoot") diff --git a/tests/src/python/test_qgsgraph.py b/tests/src/python/test_qgsgraph.py index 5e6b5d916f12..ff06a85c1875 100644 --- a/tests/src/python/test_qgsgraph.py +++ b/tests/src/python/test_qgsgraph.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '08/11/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "08/11/2021" +__copyright__ = "Copyright 2021, The QGIS Project" from qgis.analysis import QgsGraph @@ -240,7 +241,9 @@ def test_remove_edge(self): self.assertEqual(graph.vertex(v1).incomingEdges(), [edge_2]) self.assertFalse(graph.vertex(v1).outgoingEdges()) self.assertFalse(graph.vertex(v2).incomingEdges()) - self.assertCountEqual(graph.vertex(v2).outgoingEdges(), [edge_2, edge_3, edge_4]) + self.assertCountEqual( + graph.vertex(v2).outgoingEdges(), [edge_2, edge_3, edge_4] + ) with self.assertRaises(IndexError): graph.removeEdge(edge_1) @@ -327,5 +330,5 @@ def test_find_opposite_edge(self): self.assertEqual(graph.findOppositeEdge(edge_5), -1) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsgrouplayer.py b/tests/src/python/test_qgsgrouplayer.py index bd0ea6c9443c..39d494fd7e00 100644 --- a/tests/src/python/test_qgsgrouplayer.py +++ b/tests/src/python/test_qgsgrouplayer.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '22/11/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "22/11/2021" +__copyright__ = "Copyright 2021, The QGIS Project" import os from tempfile import TemporaryDirectory @@ -44,18 +45,18 @@ class TestQgsGroupLayer(QgisTestCase): @classmethod def control_path_prefix(cls): - return 'group_layer' + return "group_layer" def test_children(self): options = QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) - group_layer = QgsGroupLayer('test', options) + group_layer = QgsGroupLayer("test", options) self.assertTrue(group_layer.isValid()) self.assertFalse(group_layer.childLayers()) # add some child layers - layer1 = QgsVectorLayer('Point?crs=epsg:3111', 'Point', 'memory') - layer2 = QgsVectorLayer('Point?crs=epsg:4326', 'Point', 'memory') + layer1 = QgsVectorLayer("Point?crs=epsg:3111", "Point", "memory") + layer2 = QgsVectorLayer("Point?crs=epsg:4326", "Point", "memory") group_layer.setChildLayers([layer1, layer2]) self.assertEqual(group_layer.childLayers(), [layer1, layer2]) @@ -69,10 +70,10 @@ def test_children(self): def test_clone(self): options = QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) - group_layer = QgsGroupLayer('test', options) + group_layer = QgsGroupLayer("test", options) self.assertTrue(group_layer.isValid()) - layer1 = QgsVectorLayer('Point?crs=epsg:3111', 'Point', 'memory') - layer2 = QgsVectorLayer('Point?crs=epsg:4326', 'Point', 'memory') + layer1 = QgsVectorLayer("Point?crs=epsg:3111", "Point", "memory") + layer2 = QgsVectorLayer("Point?crs=epsg:4326", "Point", "memory") group_layer.setChildLayers([layer1, layer2]) group_cloned = group_layer.clone() @@ -82,24 +83,24 @@ def test_clone(self): def test_crs(self): # group layer should inherit first child layer crs options = QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) - group_layer = QgsGroupLayer('test', options) + group_layer = QgsGroupLayer("test", options) self.assertTrue(group_layer.isValid()) - layer1 = QgsVectorLayer('Point?crs=epsg:3111', 'Point', 'memory') - layer2 = QgsVectorLayer('Point?crs=epsg:4326', 'Point', 'memory') + layer1 = QgsVectorLayer("Point?crs=epsg:3111", "Point", "memory") + layer2 = QgsVectorLayer("Point?crs=epsg:4326", "Point", "memory") self.assertFalse(group_layer.crs().isValid()) group_layer.setChildLayers([layer1, layer2]) - self.assertEqual(group_layer.crs().authid(), 'EPSG:3111') + self.assertEqual(group_layer.crs().authid(), "EPSG:3111") group_layer.setChildLayers([layer2, layer1]) - self.assertEqual(group_layer.crs().authid(), 'EPSG:4326') + self.assertEqual(group_layer.crs().authid(), "EPSG:4326") def test_extent(self): options = QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) - group_layer = QgsGroupLayer('test', options) + group_layer = QgsGroupLayer("test", options) self.assertTrue(group_layer.isValid()) - layer1 = QgsVectorLayer('Point?crs=epsg:3111', 'Point', 'memory') + layer1 = QgsVectorLayer("Point?crs=epsg:3111", "Point", "memory") f = QgsFeature() f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(2478778, 2487236))) layer1.startEditing() @@ -113,7 +114,7 @@ def test_extent(self): self.assertAlmostEqual(extent.yMinimum(), 2487236, -2) self.assertAlmostEqual(extent.yMaximum(), 2487236, -2) - layer2 = QgsVectorLayer('Point?crs=epsg:4326', 'Point', 'memory') + layer2 = QgsVectorLayer("Point?crs=epsg:4326", "Point", "memory") f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(142.178, -35.943))) layer2.startEditing() layer2.addFeature(f) @@ -132,18 +133,18 @@ def test_save_restore(self): """ p = QgsProject() - layer1 = QgsVectorLayer('Point?crs=epsg:3111', 'L1', 'memory') - layer2 = QgsVectorLayer('Point?crs=epsg:4326', 'L2', 'memory') - layer3 = QgsVectorLayer('Point?crs=epsg:3111', 'L3', 'memory') + layer1 = QgsVectorLayer("Point?crs=epsg:3111", "L1", "memory") + layer2 = QgsVectorLayer("Point?crs=epsg:4326", "L2", "memory") + layer3 = QgsVectorLayer("Point?crs=epsg:3111", "L3", "memory") p.addMapLayer(layer1) p.addMapLayer(layer2) p.addMapLayer(layer3) options = QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) - group_layer1 = QgsGroupLayer('group 1', options) + group_layer1 = QgsGroupLayer("group 1", options) group_layer1.setChildLayers([layer1, layer2, layer3]) - group_layer2 = QgsGroupLayer('group 2', options) + group_layer2 = QgsGroupLayer("group 2", options) group_layer2.setChildLayers([layer3, layer1]) drop_shadow = QgsDropShadowEffect() @@ -153,7 +154,7 @@ def test_save_restore(self): p.addMapLayer(group_layer2, False) with TemporaryDirectory() as d: - path = os.path.join(d, 'group_layers.qgs') + path = os.path.join(d, "group_layers.qgs") p.setFileName(path) p.write() @@ -161,14 +162,19 @@ def test_save_restore(self): p2 = QgsProject() p2.read(path) - restored_layer1 = p2.mapLayersByName('L1')[0] - restored_layer2 = p2.mapLayersByName('L2')[0] - restored_layer3 = p2.mapLayersByName('L3')[0] - restored_group_1 = p2.mapLayersByName('group 1')[0] - restored_group_2 = p2.mapLayersByName('group 2')[0] + restored_layer1 = p2.mapLayersByName("L1")[0] + restored_layer2 = p2.mapLayersByName("L2")[0] + restored_layer3 = p2.mapLayersByName("L3")[0] + restored_group_1 = p2.mapLayersByName("group 1")[0] + restored_group_2 = p2.mapLayersByName("group 2")[0] - self.assertEqual(restored_group_1.childLayers(), [restored_layer1, restored_layer2, restored_layer3]) - self.assertEqual(restored_group_2.childLayers(), [restored_layer3, restored_layer1]) + self.assertEqual( + restored_group_1.childLayers(), + [restored_layer1, restored_layer2, restored_layer3], + ) + self.assertEqual( + restored_group_2.childLayers(), [restored_layer3, restored_layer1] + ) self.assertIsInstance(restored_group_2.paintEffect(), QgsDropShadowEffect) @@ -176,15 +182,15 @@ def test_render_group_opacity(self): """ Test rendering layers as a group with opacity """ - vl1 = QgsVectorLayer(TEST_DATA_DIR + '/lines.shp') + vl1 = QgsVectorLayer(TEST_DATA_DIR + "/lines.shp") self.assertTrue(vl1.isValid()) - vl2 = QgsVectorLayer(TEST_DATA_DIR + '/points.shp') + vl2 = QgsVectorLayer(TEST_DATA_DIR + "/points.shp") self.assertTrue(vl2.isValid()) - vl3 = QgsVectorLayer(TEST_DATA_DIR + '/polys.shp') + vl3 = QgsVectorLayer(TEST_DATA_DIR + "/polys.shp") self.assertTrue(vl3.isValid()) options = QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) - group_layer = QgsGroupLayer('group', options) + group_layer = QgsGroupLayer("group", options) group_layer.setChildLayers([vl1, vl2, vl3]) # render group with 50% opacity group_layer.setOpacity(0.5) @@ -197,31 +203,39 @@ def test_render_group_opacity(self): mapsettings.setLayers([group_layer]) self.assertTrue( - self.render_map_settings_check('group_opacity', 'group_opacity', mapsettings) + self.render_map_settings_check( + "group_opacity", "group_opacity", mapsettings + ) ) def test_render_group_blend_mode(self): """ Test rendering layers as a group limits child layer blend mode scope """ - vl1 = QgsVectorLayer(TEST_DATA_DIR + '/lines.shp') + vl1 = QgsVectorLayer(TEST_DATA_DIR + "/lines.shp") self.assertTrue(vl1.isValid()) - vl2 = QgsVectorLayer(TEST_DATA_DIR + '/points.shp') + vl2 = QgsVectorLayer(TEST_DATA_DIR + "/points.shp") self.assertTrue(vl2.isValid()) options = QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) - group_layer = QgsGroupLayer('group', options) + group_layer = QgsGroupLayer("group", options) group_layer.setChildLayers([vl2, vl1]) vl1.setBlendMode(QPainter.CompositionMode.CompositionMode_DestinationIn) - self.assertEqual(vl1.blendMode(), QPainter.CompositionMode.CompositionMode_DestinationIn) + self.assertEqual( + vl1.blendMode(), QPainter.CompositionMode.CompositionMode_DestinationIn + ) # temporarily remove layer from group and check blend mode group_layer.setChildLayers([vl2]) # blend mode must be reset to a non-clipping mode - self.assertEqual(vl1.blendMode(), QPainter.CompositionMode.CompositionMode_SourceOver) + self.assertEqual( + vl1.blendMode(), QPainter.CompositionMode.CompositionMode_SourceOver + ) # readd layer to group group_layer.setChildLayers([vl2, vl1]) # group blend mode should be restored - self.assertEqual(vl1.blendMode(), QPainter.CompositionMode.CompositionMode_DestinationIn) + self.assertEqual( + vl1.blendMode(), QPainter.CompositionMode.CompositionMode_DestinationIn + ) mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(600, 400)) @@ -231,20 +245,22 @@ def test_render_group_blend_mode(self): mapsettings.setLayers([group_layer]) self.assertTrue( - self.render_map_settings_check('group_child_blend_mode', 'group_child_blend_mode', mapsettings) + self.render_map_settings_check( + "group_child_blend_mode", "group_child_blend_mode", mapsettings + ) ) def test_render_paint_effect(self): """ Test rendering layers as a group with paint effect """ - vl1 = QgsVectorLayer(TEST_DATA_DIR + '/lines.shp') + vl1 = QgsVectorLayer(TEST_DATA_DIR + "/lines.shp") self.assertTrue(vl1.isValid()) - vl2 = QgsVectorLayer(TEST_DATA_DIR + '/points.shp') + vl2 = QgsVectorLayer(TEST_DATA_DIR + "/points.shp") self.assertTrue(vl2.isValid()) options = QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) - group_layer = QgsGroupLayer('group', options) + group_layer = QgsGroupLayer("group", options) group_layer.setChildLayers([vl2, vl1]) drop_shadow = QgsDropShadowEffect() @@ -266,20 +282,22 @@ def test_render_paint_effect(self): mapsettings.setLayers([group_layer]) self.assertTrue( - self.render_map_settings_check('group_paint_effect', 'group_paint_effect', mapsettings) + self.render_map_settings_check( + "group_paint_effect", "group_paint_effect", mapsettings + ) ) def test_render_magnification(self): """ Test rendering layers with magnification """ - vl1 = QgsVectorLayer(TEST_DATA_DIR + '/points.shp') + vl1 = QgsVectorLayer(TEST_DATA_DIR + "/points.shp") self.assertTrue(vl1.isValid()) - rl1 = QgsRasterLayer(TEST_DATA_DIR + '/raster_layer.tiff') + rl1 = QgsRasterLayer(TEST_DATA_DIR + "/raster_layer.tiff") self.assertTrue(rl1.isValid()) options = QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) - group_layer = QgsGroupLayer('group', options) + group_layer = QgsGroupLayer("group", options) group_layer.setChildLayers([rl1, vl1]) color_effect = QgsColorEffect() @@ -299,9 +317,11 @@ def test_render_magnification(self): mapsettings.setLayers([group_layer]) self.assertTrue( - self.render_map_settings_check('group_magnification', 'group_magnification', mapsettings) + self.render_map_settings_check( + "group_magnification", "group_magnification", mapsettings + ) ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgshashlinesymbollayer.py b/tests/src/python/test_qgshashlinesymbollayer.py index b503421babc1..f169198865f5 100644 --- a/tests/src/python/test_qgshashlinesymbollayer.py +++ b/tests/src/python/test_qgshashlinesymbollayer.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'March 2019' -__copyright__ = '(C) 2019, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "March 2019" +__copyright__ = "(C) 2019, Nyall Dawson" import os @@ -110,28 +110,30 @@ def testHashAngle(self): s.appendSymbolLayer(hash_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'line_hash_angle', - 'line_hash_angle', + "line_hash_angle", + "line_hash_angle", rendered_image, color_tolerance=2, - allowed_mismatch=20) + allowed_mismatch=20, + ) ) s.symbolLayer(0).setRotateSymbols(False) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'line_hash_no_rotate', - 'line_hash_no_rotate', + "line_hash_no_rotate", + "line_hash_no_rotate", rendered_image, color_tolerance=2, - allowed_mismatch=20) + allowed_mismatch=20, + ) ) def testHashAverageAngleInterval(self): @@ -153,15 +155,16 @@ def testHashAverageAngleInterval(self): s.appendSymbolLayer(hash_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'line_hash_average_angle', - 'line_hash_average_angle', + "line_hash_average_angle", + "line_hash_average_angle", rendered_image, color_tolerance=2, - allowed_mismatch=20) + allowed_mismatch=20, + ) ) def testHashAverageAngleCentralPoint(self): @@ -182,15 +185,16 @@ def testHashAverageAngleCentralPoint(self): s.appendSymbolLayer(hash_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'line_hash_center_average_angle', - 'line_hash_center_average_angle', + "line_hash_center_average_angle", + "line_hash_center_average_angle", rendered_image, color_tolerance=2, - allowed_mismatch=20) + allowed_mismatch=20, + ) ) def testHashAverageAngleClosedRing(self): @@ -212,15 +216,16 @@ def testHashAverageAngleClosedRing(self): s.appendSymbolLayer(hash_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 0 10, 10 10, 10 0, 0 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 0 10, 10 10, 10 0, 0 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'line_hash_ring_average_angle', - 'line_hash_ring_average_angle', + "line_hash_ring_average_angle", + "line_hash_ring_average_angle", rendered_image, color_tolerance=2, - allowed_mismatch=20) + allowed_mismatch=20, + ) ) def testHashPlacement(self): @@ -241,41 +246,48 @@ def testHashPlacement(self): s.appendSymbolLayer(hash_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'line_hash_vertex', - 'line_hash_vertex', + "line_hash_vertex", + "line_hash_vertex", rendered_image, color_tolerance=2, - allowed_mismatch=20) + allowed_mismatch=20, + ) ) - s.symbolLayer(0).setPlacement(QgsTemplatedLineSymbolLayerBase.Placement.FirstVertex) + s.symbolLayer(0).setPlacement( + QgsTemplatedLineSymbolLayerBase.Placement.FirstVertex + ) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'line_hash_first', - 'line_hash_first', + "line_hash_first", + "line_hash_first", rendered_image, color_tolerance=2, - allowed_mismatch=20) + allowed_mismatch=20, + ) ) - s.symbolLayer(0).setPlacement(QgsTemplatedLineSymbolLayerBase.Placement.LastVertex) + s.symbolLayer(0).setPlacement( + QgsTemplatedLineSymbolLayerBase.Placement.LastVertex + ) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'line_hash_last', - 'line_hash_last', + "line_hash_last", + "line_hash_last", rendered_image, color_tolerance=2, - allowed_mismatch=20) + allowed_mismatch=20, + ) ) def testRingFilter(self): @@ -296,48 +308,70 @@ def testRingFilter(self): hash_line.setAverageAngleLength(0) s.appendSymbolLayer(hash_line.clone()) - self.assertEqual(s.symbolLayer(0).ringFilter(), QgsLineSymbolLayer.RenderRingFilter.AllRings) - s.symbolLayer(0).setRingFilter(QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly) - self.assertEqual(s.symbolLayer(0).ringFilter(), QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly) + self.assertEqual( + s.symbolLayer(0).ringFilter(), QgsLineSymbolLayer.RenderRingFilter.AllRings + ) + s.symbolLayer(0).setRingFilter( + QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly + ) + self.assertEqual( + s.symbolLayer(0).ringFilter(), + QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly, + ) s2 = s.clone() - self.assertEqual(s2.symbolLayer(0).ringFilter(), QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly) + self.assertEqual( + s2.symbolLayer(0).ringFilter(), + QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly, + ) doc = QDomDocument() context = QgsReadWriteContext() - element = QgsSymbolLayerUtils.saveSymbol('test', s, doc, context) + element = QgsSymbolLayerUtils.saveSymbol("test", s, doc, context) s2 = QgsSymbolLayerUtils.loadSymbol(element, context) - self.assertEqual(s2.symbolLayer(0).ringFilter(), QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly) + self.assertEqual( + s2.symbolLayer(0).ringFilter(), + QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly, + ) # rendering test s3 = QgsFillSymbol() s3.deleteSymbolLayer(0) - s3.appendSymbolLayer( - hash_line.clone()) - s3.symbolLayer(0).setRingFilter(QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly) + s3.appendSymbolLayer(hash_line.clone()) + s3.symbolLayer(0).setRingFilter( + QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly + ) - g = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))') + g = QgsGeometry.fromWkt( + "Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))" + ) rendered_image = self.renderGeometry(s3, g) self.assertTrue( self.image_check( - 'hashline_exterioronly', - 'hashline_exterioronly', + "hashline_exterioronly", + "hashline_exterioronly", rendered_image, color_tolerance=2, - allowed_mismatch=20) + allowed_mismatch=20, + ) ) - s3.symbolLayer(0).setRingFilter(QgsLineSymbolLayer.RenderRingFilter.InteriorRingsOnly) - g = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))') + s3.symbolLayer(0).setRingFilter( + QgsLineSymbolLayer.RenderRingFilter.InteriorRingsOnly + ) + g = QgsGeometry.fromWkt( + "Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))" + ) rendered_image = self.renderGeometry(s3, g) self.assertTrue( self.image_check( - 'hashline_interioronly', - 'hashline_interioronly', + "hashline_interioronly", + "hashline_interioronly", rendered_image, color_tolerance=2, - allowed_mismatch=20) + allowed_mismatch=20, + ) ) def testLineOffset(self): @@ -359,27 +393,29 @@ def testLineOffset(self): s.appendSymbolLayer(hash_line.clone()) s.symbolLayer(0).setOffset(3) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'line_offset_positive', - 'line_offset_positive', + "line_offset_positive", + "line_offset_positive", rendered_image, color_tolerance=2, - allowed_mismatch=20) + allowed_mismatch=20, + ) ) s.symbolLayer(0).setOffset(-3) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'line_offset_negative', - 'line_offset_negative', + "line_offset_negative", + "line_offset_negative", rendered_image, color_tolerance=2, - allowed_mismatch=20) + allowed_mismatch=20, + ) ) def testPointNumInterval(self): @@ -400,18 +436,21 @@ def testPointNumInterval(self): s.appendSymbolLayer(hash_line.clone()) - s.symbolLayer(0).setDataDefinedProperty(QgsSymbolLayer.Property.PropertyLineDistance, QgsProperty.fromExpression( - "@geometry_point_num * 2")) + s.symbolLayer(0).setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyLineDistance, + QgsProperty.fromExpression("@geometry_point_num * 2"), + ) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'line_dd_size', - 'line_dd_size', + "line_dd_size", + "line_dd_size", rendered_image, color_tolerance=2, - allowed_mismatch=20) + allowed_mismatch=20, + ) ) def testSegmentCenter(self): @@ -431,20 +470,21 @@ def testSegmentCenter(self): s.appendSymbolLayer(hash_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 0 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 0, 0 10)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'line_hash_segmentcenter', - 'line_hash_segmentcenter', + "line_hash_segmentcenter", + "line_hash_segmentcenter", rendered_image, color_tolerance=2, - allowed_mismatch=20) + allowed_mismatch=20, + ) ) def testOpacityWithDataDefinedColor(self): - line_shp = os.path.join(TEST_DATA_DIR, 'lines.shp') - line_layer = QgsVectorLayer(line_shp, 'Lines', 'ogr') + line_shp = os.path.join(TEST_DATA_DIR, "lines.shp") + line_layer = QgsVectorLayer(line_shp, "Lines", "ogr") self.assertTrue(line_layer.isValid()) s = QgsLineSymbol() @@ -452,8 +492,10 @@ def testOpacityWithDataDefinedColor(self): hash_line = QgsHashedLineSymbolLayer(True) simple_line = QgsSimpleLineSymbolLayer() simple_line.setColor(QColor(0, 255, 0)) - simple_line.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyStrokeColor, QgsProperty.fromExpression( - "if(Name='Arterial', 'red', 'green')")) + simple_line.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyStrokeColor, + QgsProperty.fromExpression("if(Name='Arterial', 'red', 'green')"), + ) simple_line.setWidth(1) line_symbol = QgsLineSymbol() @@ -478,15 +520,13 @@ def testOpacityWithDataDefinedColor(self): # Test rendering self.assertTrue( self.render_map_settings_check( - 'hashline_opacityddcolor', - 'hashline_opacityddcolor', - ms + "hashline_opacityddcolor", "hashline_opacityddcolor", ms ) ) def testDataDefinedOpacity(self): - line_shp = os.path.join(TEST_DATA_DIR, 'lines.shp') - line_layer = QgsVectorLayer(line_shp, 'Lines', 'ogr') + line_shp = os.path.join(TEST_DATA_DIR, "lines.shp") + line_layer = QgsVectorLayer(line_shp, "Lines", "ogr") self.assertTrue(line_layer.isValid()) s = QgsLineSymbol() @@ -494,8 +534,10 @@ def testDataDefinedOpacity(self): hash_line = QgsHashedLineSymbolLayer(True) simple_line = QgsSimpleLineSymbolLayer() simple_line.setColor(QColor(0, 255, 0)) - simple_line.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyStrokeColor, QgsProperty.fromExpression( - "if(Name='Arterial', 'red', 'green')")) + simple_line.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyStrokeColor, + QgsProperty.fromExpression("if(Name='Arterial', 'red', 'green')"), + ) simple_line.setWidth(1) line_symbol = QgsLineSymbol() @@ -506,7 +548,10 @@ def testDataDefinedOpacity(self): hash_line.setAverageAngleLength(0) s.appendSymbolLayer(hash_line.clone()) - s.setDataDefinedProperty(QgsSymbol.Property.PropertyOpacity, QgsProperty.fromExpression("if(\"Value\" = 1, 25, 50)")) + s.setDataDefinedProperty( + QgsSymbol.Property.PropertyOpacity, + QgsProperty.fromExpression('if("Value" = 1, 25, 50)'), + ) line_layer.setRenderer(QgsSingleSymbolRenderer(s)) @@ -519,9 +564,7 @@ def testDataDefinedOpacity(self): # Test rendering self.assertTrue( self.render_map_settings_check( - 'hashline_ddopacity', - 'hashline_ddopacity', - ms + "hashline_ddopacity", "hashline_ddopacity", ms ) ) @@ -559,5 +602,5 @@ def renderGeometry(self, symbol, geom, buffer=20): return image -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsheatmaprenderer.py b/tests/src/python/test_qgsheatmaprenderer.py index d34439addf82..660031e599b0 100644 --- a/tests/src/python/test_qgsheatmaprenderer.py +++ b/tests/src/python/test_qgsheatmaprenderer.py @@ -24,7 +24,7 @@ QgsVectorLayer, QgsMapSettings, QgsExpressionContext, - QgsExpressionContextScope + QgsExpressionContextScope, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -40,7 +40,7 @@ class TestQgsHeatmapRenderer(QgisTestCase): @classmethod def control_path_prefix(cls): - return 'heatmap_renderer' + return "heatmap_renderer" def test_clone(self): """ @@ -49,34 +49,39 @@ def test_clone(self): renderer = QgsHeatmapRenderer() renderer.setColorRamp( - QgsGradientColorRamp(QColor(255, 0, 0), QColor(255, 200, 100))) + QgsGradientColorRamp(QColor(255, 0, 0), QColor(255, 200, 100)) + ) legend_settings = QgsColorRampLegendNodeSettings() - legend_settings.setMaximumLabel('my max') - legend_settings.setMinimumLabel('my min') + legend_settings.setMaximumLabel("my max") + legend_settings.setMinimumLabel("my min") renderer.setLegendSettings(legend_settings) renderer.setDataDefinedProperty( QgsFeatureRenderer.Property.HeatmapRadius, - QgsProperty.fromField('radius_field') + QgsProperty.fromField("radius_field"), ) renderer.setDataDefinedProperty( QgsFeatureRenderer.Property.HeatmapMaximum, - QgsProperty.fromField('max_field') + QgsProperty.fromField("max_field"), ) renderer2 = renderer.clone() self.assertEqual(renderer2.colorRamp().color1(), QColor(255, 0, 0)) self.assertEqual(renderer2.colorRamp().color2(), QColor(255, 200, 100)) - self.assertEqual(renderer2.legendSettings().minimumLabel(), 'my min') - self.assertEqual(renderer2.legendSettings().maximumLabel(), 'my max') + self.assertEqual(renderer2.legendSettings().minimumLabel(), "my min") + self.assertEqual(renderer2.legendSettings().maximumLabel(), "my max") self.assertEqual( - renderer2.dataDefinedProperties().property(QgsFeatureRenderer.Property.HeatmapRadius).field(), - 'radius_field' + renderer2.dataDefinedProperties() + .property(QgsFeatureRenderer.Property.HeatmapRadius) + .field(), + "radius_field", ) self.assertEqual( - renderer2.dataDefinedProperties().property(QgsFeatureRenderer.Property.HeatmapMaximum).field(), - 'max_field' + renderer2.dataDefinedProperties() + .property(QgsFeatureRenderer.Property.HeatmapMaximum) + .field(), + "max_field", ) def test_write_read_xml(self): @@ -86,20 +91,21 @@ def test_write_read_xml(self): renderer = QgsHeatmapRenderer() renderer.setColorRamp( - QgsGradientColorRamp(QColor(255, 0, 0), QColor(255, 200, 100))) + QgsGradientColorRamp(QColor(255, 0, 0), QColor(255, 200, 100)) + ) legend_settings = QgsColorRampLegendNodeSettings() - legend_settings.setMaximumLabel('my max') - legend_settings.setMinimumLabel('my min') + legend_settings.setMaximumLabel("my max") + legend_settings.setMinimumLabel("my min") renderer.setLegendSettings(legend_settings) renderer.setDataDefinedProperty( QgsFeatureRenderer.Property.HeatmapRadius, - QgsProperty.fromField('radius_field') + QgsProperty.fromField("radius_field"), ) renderer.setDataDefinedProperty( QgsFeatureRenderer.Property.HeatmapMaximum, - QgsProperty.fromField('max_field') + QgsProperty.fromField("max_field"), ) doc = QDomDocument("testdoc") @@ -108,28 +114,35 @@ def test_write_read_xml(self): renderer2 = QgsFeatureRenderer.load(elem, QgsReadWriteContext()) self.assertEqual(renderer2.colorRamp().color1(), QColor(255, 0, 0)) self.assertEqual(renderer2.colorRamp().color2(), QColor(255, 200, 100)) - self.assertEqual(renderer2.legendSettings().minimumLabel(), 'my min') - self.assertEqual(renderer2.legendSettings().maximumLabel(), 'my max') + self.assertEqual(renderer2.legendSettings().minimumLabel(), "my min") + self.assertEqual(renderer2.legendSettings().maximumLabel(), "my max") self.assertEqual( - renderer2.dataDefinedProperties().property(QgsFeatureRenderer.Property.HeatmapRadius).field(), - 'radius_field' + renderer2.dataDefinedProperties() + .property(QgsFeatureRenderer.Property.HeatmapRadius) + .field(), + "radius_field", ) self.assertEqual( - renderer2.dataDefinedProperties().property(QgsFeatureRenderer.Property.HeatmapMaximum).field(), - 'max_field' + renderer2.dataDefinedProperties() + .property(QgsFeatureRenderer.Property.HeatmapMaximum) + .field(), + "max_field", ) def test_render(self): """ Test heatmap rendering """ - layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'points.shp'), 'Points', 'ogr') + layer = QgsVectorLayer( + os.path.join(TEST_DATA_DIR, "points.shp"), "Points", "ogr" + ) self.assertTrue(layer.isValid()) renderer = QgsHeatmapRenderer() renderer.setColorRamp( - QgsGradientColorRamp(QColor(255, 0, 0), QColor(255, 200, 100))) + QgsGradientColorRamp(QColor(255, 0, 0), QColor(255, 200, 100)) + ) renderer.setRadius(20) renderer.setRadiusUnit(Qgis.RenderUnit.Millimeters) layer.setRenderer(renderer) @@ -142,26 +155,28 @@ def test_render(self): self.assertTrue( self.render_map_settings_check( - 'Render heatmap', - 'render_heatmap', - mapsettings) + "Render heatmap", "render_heatmap", mapsettings + ) ) def test_data_defined_radius(self): """ Test heatmap rendering with data defined radius """ - layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'points.shp'), 'Points', 'ogr') + layer = QgsVectorLayer( + os.path.join(TEST_DATA_DIR, "points.shp"), "Points", "ogr" + ) self.assertTrue(layer.isValid()) renderer = QgsHeatmapRenderer() renderer.setColorRamp( - QgsGradientColorRamp(QColor(255, 0, 0), QColor(255, 200, 100))) + QgsGradientColorRamp(QColor(255, 0, 0), QColor(255, 200, 100)) + ) renderer.setRadius(20) renderer.setRadiusUnit(Qgis.RenderUnit.Millimeters) renderer.setDataDefinedProperty( QgsFeatureRenderer.Property.HeatmapRadius, - QgsProperty.fromExpression('@my_var * 2') + QgsProperty.fromExpression("@my_var * 2"), ) layer.setRenderer(renderer) @@ -172,33 +187,37 @@ def test_data_defined_radius(self): mapsettings.setExtent(layer.extent()) mapsettings.setLayers([layer]) scope = QgsExpressionContextScope() - scope.setVariable('my_var', 20) + scope.setVariable("my_var", 20) context = QgsExpressionContext() context.appendScope(scope) mapsettings.setExpressionContext(context) self.assertTrue( self.render_map_settings_check( - 'Render heatmap with data defined radius', - 'data_defined_radius', - mapsettings) + "Render heatmap with data defined radius", + "data_defined_radius", + mapsettings, + ) ) def test_data_defined_maximum(self): """ Test heatmap rendering with data defined maximum value """ - layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'points.shp'), 'Points', 'ogr') + layer = QgsVectorLayer( + os.path.join(TEST_DATA_DIR, "points.shp"), "Points", "ogr" + ) self.assertTrue(layer.isValid()) renderer = QgsHeatmapRenderer() renderer.setColorRamp( - QgsGradientColorRamp(QColor(255, 0, 0), QColor(255, 200, 100))) + QgsGradientColorRamp(QColor(255, 0, 0), QColor(255, 200, 100)) + ) renderer.setRadius(20) renderer.setRadiusUnit(Qgis.RenderUnit.Millimeters) renderer.setDataDefinedProperty( QgsFeatureRenderer.Property.HeatmapMaximum, - QgsProperty.fromExpression('@my_var * 2') + QgsProperty.fromExpression("@my_var * 2"), ) layer.setRenderer(renderer) @@ -209,16 +228,17 @@ def test_data_defined_maximum(self): mapsettings.setExtent(layer.extent()) mapsettings.setLayers([layer]) scope = QgsExpressionContextScope() - scope.setVariable('my_var', 0.5) + scope.setVariable("my_var", 0.5) context = QgsExpressionContext() context.appendScope(scope) mapsettings.setExpressionContext(context) self.assertTrue( self.render_map_settings_check( - 'Render heatmap with data defined maximum', - 'data_defined_maximum', - mapsettings) + "Render heatmap with data defined maximum", + "data_defined_maximum", + mapsettings, + ) ) diff --git a/tests/src/python/test_qgshelp.py b/tests/src/python/test_qgshelp.py index e7f0eda09efe..3c4296414022 100644 --- a/tests/src/python/test_qgshelp.py +++ b/tests/src/python/test_qgshelp.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Julien Cabieces' -__date__ = '2022-09-21' -__copyright__ = 'Copyright 2022, Julien Cabieces' + +__author__ = "Julien Cabieces" +__date__ = "2022-09-21" +__copyright__ = "Copyright 2022, Julien Cabieces" from qgis.PyQt.QtCore import QCoreApplication from qgis.core import QgsSettings @@ -45,7 +46,7 @@ def testOpenUrl(self): Tests returned url according to help key """ - server_url = f'http://localhost:{TestQgsHelp.port}/' + server_url = f"http://localhost:{TestQgsHelp.port}/" QgsSettings().setValue( "help/helpSearchPath", @@ -56,16 +57,26 @@ def testOpenUrl(self): ) handler = mockedwebserver.SequentialHandler() - handler.add('HEAD', '/first_search_path/first_url.html', 200, {}) - handler.add('HEAD', '/first_search_path/second_url.html', 400, {}) - handler.add('HEAD', '/second_search_path/second_url.html', 200, {}) - handler.add('HEAD', '/first_search_path/error_url.html', 404, {}) - handler.add('HEAD', '/second_search_path/error_url.html', 404, {}) + handler.add("HEAD", "/first_search_path/first_url.html", 200, {}) + handler.add("HEAD", "/first_search_path/second_url.html", 400, {}) + handler.add("HEAD", "/second_search_path/second_url.html", 200, {}) + handler.add("HEAD", "/first_search_path/error_url.html", 404, {}) + handler.add("HEAD", "/second_search_path/error_url.html", 404, {}) with mockedwebserver.install_http_handler(handler): - self.assertEqual(server_url + "first_search_path/first_url.html", QgsHelp.helpUrl("first_url.html").toDisplayString()) - self.assertEqual(server_url + "second_search_path/second_url.html", QgsHelp.helpUrl("second_url.html").toDisplayString()) - self.assertTrue(QgsHelp.helpUrl("error_url.html").toDisplayString().endswith("nohelp.html")) - - -if __name__ == '__main__': + self.assertEqual( + server_url + "first_search_path/first_url.html", + QgsHelp.helpUrl("first_url.html").toDisplayString(), + ) + self.assertEqual( + server_url + "second_search_path/second_url.html", + QgsHelp.helpUrl("second_url.html").toDisplayString(), + ) + self.assertTrue( + QgsHelp.helpUrl("error_url.html") + .toDisplayString() + .endswith("nohelp.html") + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgshighlight.py b/tests/src/python/test_qgshighlight.py index 2181318fc4ff..4be0579acfa5 100644 --- a/tests/src/python/test_qgshighlight.py +++ b/tests/src/python/test_qgshighlight.py @@ -5,6 +5,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + __author__ = "Matthias Kuhn" __date__ = "8.11.2017" __copyright__ = "Copyright 2017, The QGIS Project" @@ -116,9 +117,7 @@ def test_polygon_very_transparent(self): symbol.setOpacity(0.3) layer.setRenderer(QgsSingleSymbolRenderer(symbol)) self.assertTrue(layer.isValid()) - self.assertTrue( - self.run_test_for_layer(layer, "polygons", use_feature=False) - ) + self.assertTrue(self.run_test_for_layer(layer, "polygons", use_feature=False)) self.assertTrue( self.run_test_for_layer( layer, diff --git a/tests/src/python/test_qgshillshaderenderer.py b/tests/src/python/test_qgshillshaderenderer.py index 2998cc69876f..8e19db45b854 100644 --- a/tests/src/python/test_qgshillshaderenderer.py +++ b/tests/src/python/test_qgshillshaderenderer.py @@ -29,15 +29,13 @@ class TestQgsHillshadeRenderer(QgisTestCase): def test_renderer(self): - path = os.path.join(unitTestDataPath(), - 'landsat.tif') + path = os.path.join(unitTestDataPath(), "landsat.tif") info = QFileInfo(path) base_name = info.baseName() layer = QgsRasterLayer(path, base_name) - self.assertTrue(layer.isValid(), f'Raster not loaded: {path}') + self.assertTrue(layer.isValid(), f"Raster not loaded: {path}") - renderer = QgsHillshadeRenderer(layer.dataProvider(), - 1, 90, 45) + renderer = QgsHillshadeRenderer(layer.dataProvider(), 1, 90, 45) self.assertEqual(renderer.azimuth(), 90) self.assertEqual(renderer.altitude(), 45) @@ -54,8 +52,7 @@ def test_hillshade_invalid_layer(self): """ Test hillshade raster render band with a broken layer path """ - renderer = QgsHillshadeRenderer(None, - 1, 90, 45) + renderer = QgsHillshadeRenderer(None, 1, 90, 45) self.assertEqual(renderer.azimuth(), 90) self.assertEqual(renderer.altitude(), 45) @@ -66,5 +63,5 @@ def test_hillshade_invalid_layer(self): self.assertEqual(renderer.inputBand(), 10) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgshistoryproviderregistry.py b/tests/src/python/test_qgshistoryproviderregistry.py index 96fd965b75dd..a8a5190dddf0 100644 --- a/tests/src/python/test_qgshistoryproviderregistry.py +++ b/tests/src/python/test_qgshistoryproviderregistry.py @@ -5,17 +5,13 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '18/10/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "18/10/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt import sip -from qgis.PyQt.QtCore import ( - QDate, - QDateTime, - QTime, - QModelIndex -) +from qgis.PyQt.QtCore import QDate, QDateTime, QTime, QModelIndex from qgis.PyQt.QtTest import QSignalSpy from qgis.core import Qgis @@ -26,7 +22,7 @@ QgsGui, QgsHistoryEntryNode, QgsHistoryEntryGroup, - QgsHistoryEntryModel + QgsHistoryEntryModel, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -47,7 +43,7 @@ def data(self, role): class TestHistoryProvider(QgsAbstractHistoryProvider): def id(self) -> str: - return 'test_provider' + return "test_provider" def createNodeForEntry(self, entry, context): return TestEntryNode(entry.entry) @@ -55,28 +51,28 @@ def createNodeForEntry(self, entry, context): def updateNodeForEntry(self, node, entry, context): node.val = entry.entry - new_child_node = TestEntryNode('my child') + new_child_node = TestEntryNode("my child") node.addChild(new_child_node) - new_child_node = TestEntryNode('my child 2') + new_child_node = TestEntryNode("my child 2") node.addChild(new_child_node) class TestHistoryProvider2(QgsAbstractHistoryProvider): def id(self) -> str: - return 'test_provider2' + return "test_provider2" class TestNode(QgsHistoryEntryNode): def data(self, role): - return 'test' + return "test" class TestGroup(QgsHistoryEntryGroup): def data(self, role): - return 'test' + return "test" class TestQgsHistoryProviderRegistry(QgisTestCase): @@ -94,24 +90,25 @@ def test_entry(self): entry = QgsHistoryEntry() self.assertFalse(entry.isValid()) - entry = QgsHistoryEntry('my provider', QDateTime(2021, 1, 2, 3, 4, 5), - {'somevar': 5}) + entry = QgsHistoryEntry( + "my provider", QDateTime(2021, 1, 2, 3, 4, 5), {"somevar": 5} + ) self.assertTrue(entry.isValid()) - self.assertEqual(entry.providerId, 'my provider') + self.assertEqual(entry.providerId, "my provider") self.assertEqual(entry.timestamp, QDateTime(2021, 1, 2, 3, 4, 5)) - self.assertEqual(entry.entry, {'somevar': 5}) + self.assertEqual(entry.entry, {"somevar": 5}) - self.assertEqual(str(entry), - '') + self.assertEqual( + str(entry), "" + ) - entry = QgsHistoryEntry({'somevar': 7}) + entry = QgsHistoryEntry({"somevar": 7}) self.assertTrue(entry.isValid()) self.assertFalse(entry.providerId) - self.assertEqual(entry.timestamp.date(), - QDateTime.currentDateTime().date()) - self.assertEqual(entry.entry, {'somevar': 7}) + self.assertEqual(entry.timestamp.date(), QDateTime.currentDateTime().date()) + self.assertEqual(entry.entry, {"somevar": 7}) def test_registry_providers(self): """ @@ -123,21 +120,20 @@ def test_registry_providers(self): provider1 = TestHistoryProvider() provider2 = TestHistoryProvider2() self.assertTrue(reg.addProvider(provider1)) - self.assertEqual(reg.providerIds(), ['test_provider']) + self.assertEqual(reg.providerIds(), ["test_provider"]) # already registered self.assertFalse(reg.addProvider(provider1)) self.assertTrue(reg.addProvider(provider2)) - self.assertCountEqual(reg.providerIds(), - ['test_provider', 'test_provider2']) + self.assertCountEqual(reg.providerIds(), ["test_provider", "test_provider2"]) - self.assertFalse(reg.removeProvider('x')) - self.assertTrue(reg.removeProvider('test_provider')) + self.assertFalse(reg.removeProvider("x")) + self.assertTrue(reg.removeProvider("test_provider")) self.assertTrue(sip.isdeleted(provider1)) - self.assertEqual(reg.providerIds(), ['test_provider2']) + self.assertEqual(reg.providerIds(), ["test_provider2"]) def test_registry_entries(self): """ @@ -149,169 +145,189 @@ def test_registry_entries(self): added_spy = QSignalSpy(reg.entryAdded) updated_spy = QSignalSpy(reg.entryUpdated) - id_1, ok = reg.addEntry('my provider', - {'some var': 5, 'other_var': [1, 2, 3], - 'final_var': {'a': 'b'}}, - QgsHistoryProviderRegistry.HistoryEntryOptions()) + id_1, ok = reg.addEntry( + "my provider", + {"some var": 5, "other_var": [1, 2, 3], "final_var": {"a": "b"}}, + QgsHistoryProviderRegistry.HistoryEntryOptions(), + ) self.assertTrue(ok) self.assertEqual(len(added_spy), 1) self.assertEqual(added_spy[-1][0], id_1) - self.assertEqual(added_spy[-1][1].providerId, 'my provider') + self.assertEqual(added_spy[-1][1].providerId, "my provider") self.assertEqual(added_spy[-1][1].id, id_1) - self.assertEqual(added_spy[-1][1].entry, - {'some var': 5, 'other_var': [1, 2, 3], - 'final_var': {'a': 'b'}}) - - id_2, ok = reg.addEntry('my provider 2', {'some var': 6}, - QgsHistoryProviderRegistry.HistoryEntryOptions()) + self.assertEqual( + added_spy[-1][1].entry, + {"some var": 5, "other_var": [1, 2, 3], "final_var": {"a": "b"}}, + ) + + id_2, ok = reg.addEntry( + "my provider 2", + {"some var": 6}, + QgsHistoryProviderRegistry.HistoryEntryOptions(), + ) self.assertTrue(ok) self.assertEqual(len(added_spy), 2) self.assertEqual(added_spy[-1][0], id_2) - self.assertEqual(added_spy[-1][1].providerId, 'my provider 2') + self.assertEqual(added_spy[-1][1].providerId, "my provider 2") self.assertEqual(added_spy[-1][1].id, id_2) - self.assertEqual(added_spy[-1][1].entry, {'some var': 6}) + self.assertEqual(added_spy[-1][1].entry, {"some var": 6}) self.assertEqual(len(reg.queryEntries()), 2) - self.assertEqual(reg.queryEntries()[0].providerId, 'my provider') + self.assertEqual(reg.queryEntries()[0].providerId, "my provider") self.assertEqual(reg.queryEntries()[0].id, id_1) - self.assertEqual(reg.queryEntries()[0].timestamp.date(), - QDateTime.currentDateTime().date()) - self.assertEqual(reg.queryEntries()[0].entry, - {'some var': 5, 'other_var': [1, 2, 3], - 'final_var': {'a': 'b'}}) - - self.assertEqual(reg.queryEntries()[1].providerId, 'my provider 2') + self.assertEqual( + reg.queryEntries()[0].timestamp.date(), QDateTime.currentDateTime().date() + ) + self.assertEqual( + reg.queryEntries()[0].entry, + {"some var": 5, "other_var": [1, 2, 3], "final_var": {"a": "b"}}, + ) + + self.assertEqual(reg.queryEntries()[1].providerId, "my provider 2") self.assertEqual(reg.queryEntries()[1].id, id_2) - self.assertEqual(reg.queryEntries()[1].timestamp.date(), - QDateTime.currentDateTime().date()) - self.assertEqual(reg.queryEntries()[1].entry, {'some var': 6}) + self.assertEqual( + reg.queryEntries()[1].timestamp.date(), QDateTime.currentDateTime().date() + ) + self.assertEqual(reg.queryEntries()[1].entry, {"some var": 6}) entry, ok = reg.entry(1111) self.assertFalse(ok) entry, ok = reg.entry(id_1) self.assertTrue(ok) - self.assertEqual(entry.providerId, 'my provider') + self.assertEqual(entry.providerId, "my provider") self.assertEqual(entry.id, id_1) - self.assertEqual(entry.timestamp.date(), - QDateTime.currentDateTime().date()) - self.assertEqual(entry.entry, {'some var': 5, 'other_var': [1, 2, 3], - 'final_var': {'a': 'b'}}) + self.assertEqual(entry.timestamp.date(), QDateTime.currentDateTime().date()) + self.assertEqual( + entry.entry, + {"some var": 5, "other_var": [1, 2, 3], "final_var": {"a": "b"}}, + ) entry, ok = reg.entry(id_2) self.assertTrue(ok) - self.assertEqual(entry.providerId, 'my provider 2') + self.assertEqual(entry.providerId, "my provider 2") self.assertEqual(entry.id, id_2) - self.assertEqual(entry.timestamp.date(), - QDateTime.currentDateTime().date()) - self.assertEqual(entry.entry, {'some var': 6}) + self.assertEqual(entry.timestamp.date(), QDateTime.currentDateTime().date()) + self.assertEqual(entry.entry, {"some var": 6}) - entry = QgsHistoryEntry('my provider 3', - QDateTime(2021, 1, 2, 3, 4, 5), {'var': 7}) + entry = QgsHistoryEntry( + "my provider 3", QDateTime(2021, 1, 2, 3, 4, 5), {"var": 7} + ) id_3, ok = reg.addEntry(entry) self.assertTrue(ok) self.assertEqual(len(added_spy), 3) self.assertEqual(added_spy[-1][0], id_3) - self.assertEqual(added_spy[-1][1].providerId, 'my provider 3') + self.assertEqual(added_spy[-1][1].providerId, "my provider 3") self.assertEqual(added_spy[-1][1].id, id_3) - self.assertEqual(added_spy[-1][1].entry, {'var': 7}) + self.assertEqual(added_spy[-1][1].entry, {"var": 7}) self.assertEqual(len(reg.queryEntries()), 3) - self.assertEqual(reg.queryEntries()[0].providerId, 'my provider') + self.assertEqual(reg.queryEntries()[0].providerId, "my provider") self.assertEqual(reg.queryEntries()[0].id, id_1) - self.assertEqual(reg.queryEntries()[0].timestamp.date(), - QDateTime.currentDateTime().date()) - self.assertEqual(reg.queryEntries()[0].entry, - {'some var': 5, 'other_var': [1, 2, 3], - 'final_var': {'a': 'b'}}) - self.assertEqual(reg.queryEntries()[1].providerId, 'my provider 2') + self.assertEqual( + reg.queryEntries()[0].timestamp.date(), QDateTime.currentDateTime().date() + ) + self.assertEqual( + reg.queryEntries()[0].entry, + {"some var": 5, "other_var": [1, 2, 3], "final_var": {"a": "b"}}, + ) + self.assertEqual(reg.queryEntries()[1].providerId, "my provider 2") self.assertEqual(reg.queryEntries()[1].id, id_2) - self.assertEqual(reg.queryEntries()[1].timestamp.date(), - QDateTime.currentDateTime().date()) - self.assertEqual(reg.queryEntries()[1].entry, {'some var': 6}) - self.assertEqual(reg.queryEntries()[2].providerId, 'my provider 3') + self.assertEqual( + reg.queryEntries()[1].timestamp.date(), QDateTime.currentDateTime().date() + ) + self.assertEqual(reg.queryEntries()[1].entry, {"some var": 6}) + self.assertEqual(reg.queryEntries()[2].providerId, "my provider 3") self.assertEqual(reg.queryEntries()[2].id, id_3) - self.assertEqual(reg.queryEntries()[2].timestamp.date(), - QDate(2021, 1, 2)) - self.assertEqual(reg.queryEntries()[2].entry, {'var': 7}) + self.assertEqual(reg.queryEntries()[2].timestamp.date(), QDate(2021, 1, 2)) + self.assertEqual(reg.queryEntries()[2].entry, {"var": 7}) # query by provider - entries = reg.queryEntries(providerId='my provider') + entries = reg.queryEntries(providerId="my provider") self.assertEqual(len(entries), 1) - self.assertEqual(entries[0].providerId, 'my provider') + self.assertEqual(entries[0].providerId, "my provider") self.assertEqual(entries[0].id, id_1) - self.assertEqual(entries[0].timestamp.date(), - QDateTime.currentDateTime().date()) - self.assertEqual(entries[0].entry, - {'some var': 5, 'other_var': [1, 2, 3], - 'final_var': {'a': 'b'}}) - - entries = reg.queryEntries(providerId='my provider 2') + self.assertEqual( + entries[0].timestamp.date(), QDateTime.currentDateTime().date() + ) + self.assertEqual( + entries[0].entry, + {"some var": 5, "other_var": [1, 2, 3], "final_var": {"a": "b"}}, + ) + + entries = reg.queryEntries(providerId="my provider 2") self.assertEqual(len(entries), 1) - self.assertEqual(entries[0].providerId, 'my provider 2') + self.assertEqual(entries[0].providerId, "my provider 2") self.assertEqual(entries[0].id, id_2) - self.assertEqual(entries[0].timestamp.date(), - QDateTime.currentDateTime().date()) - self.assertEqual(entries[0].entry, {'some var': 6}) + self.assertEqual( + entries[0].timestamp.date(), QDateTime.currentDateTime().date() + ) + self.assertEqual(entries[0].entry, {"some var": 6}) # query by date - entries = reg.queryEntries(start=QDateTime(3022, 1, 2, 3, 4, - 5)) # this test will break in 3022, sorry + entries = reg.queryEntries( + start=QDateTime(3022, 1, 2, 3, 4, 5) + ) # this test will break in 3022, sorry self.assertEqual(len(entries), 0) entries = reg.queryEntries(end=QDateTime(2020, 1, 2, 3, 4, 5)) self.assertEqual(len(entries), 0) entries = reg.queryEntries(start=QDateTime(2021, 3, 2, 3, 4, 5)) self.assertEqual(len(entries), 2) - self.assertCountEqual([e.providerId for e in entries], - ['my provider', 'my provider 2']) + self.assertCountEqual( + [e.providerId for e in entries], ["my provider", "my provider 2"] + ) entries = reg.queryEntries(end=QDateTime(2021, 3, 2, 3, 4, 5)) self.assertEqual(len(entries), 1) - self.assertEqual(entries[0].providerId, 'my provider 3') + self.assertEqual(entries[0].providerId, "my provider 3") # update an entry - self.assertTrue(reg.updateEntry(id_1, {'new_props': 54})) + self.assertTrue(reg.updateEntry(id_1, {"new_props": 54})) self.assertEqual(len(updated_spy), 1) self.assertEqual(updated_spy[-1][0], id_1) - self.assertEqual(updated_spy[-1][1], {'new_props': 54}) + self.assertEqual(updated_spy[-1][1], {"new_props": 54}) entry, ok = reg.entry(id_1) - self.assertEqual(entry.providerId, 'my provider') + self.assertEqual(entry.providerId, "my provider") self.assertEqual(entry.id, id_1) - self.assertEqual(entry.timestamp.date(), - QDateTime.currentDateTime().date()) - self.assertEqual(entry.entry, {'new_props': 54}) + self.assertEqual(entry.timestamp.date(), QDateTime.currentDateTime().date()) + self.assertEqual(entry.entry, {"new_props": 54}) clear_spy = QSignalSpy(reg.historyCleared) - self.assertTrue( - reg.clearHistory(Qgis.HistoryProviderBackend.LocalProfile)) + self.assertTrue(reg.clearHistory(Qgis.HistoryProviderBackend.LocalProfile)) self.assertEqual(len(clear_spy), 1) self.assertFalse(reg.queryEntries()) # bulk add entries - self.assertTrue(reg.addEntries([ - QgsHistoryEntry('my provider 4', QDateTime(2021, 1, 2, 3, 4, 5), - {'var': 7}), - QgsHistoryEntry('my provider 5', QDateTime(2021, 1, 2, 3, 4, 5), - {'var': 8}) - ])) + self.assertTrue( + reg.addEntries( + [ + QgsHistoryEntry( + "my provider 4", QDateTime(2021, 1, 2, 3, 4, 5), {"var": 7} + ), + QgsHistoryEntry( + "my provider 5", QDateTime(2021, 1, 2, 3, 4, 5), {"var": 8} + ), + ] + ) + ) self.assertEqual(len(reg.queryEntries()), 2) self.assertEqual(len(added_spy), 5) - self.assertEqual(added_spy[-2][1].providerId, 'my provider 4') + self.assertEqual(added_spy[-2][1].providerId, "my provider 4") self.assertEqual(added_spy[-2][1].id, 1) - self.assertEqual(added_spy[-2][1].entry, {'var': 7}) - self.assertEqual(added_spy[-1][1].providerId, 'my provider 5') + self.assertEqual(added_spy[-2][1].entry, {"var": 7}) + self.assertEqual(added_spy[-1][1].providerId, "my provider 5") self.assertEqual(added_spy[-1][1].id, 2) - self.assertEqual(added_spy[-1][1].entry, {'var': 8}) + self.assertEqual(added_spy[-1][1].entry, {"var": 8}) - self.assertEqual(reg.queryEntries()[0].providerId, 'my provider 4') + self.assertEqual(reg.queryEntries()[0].providerId, "my provider 4") self.assertEqual(reg.queryEntries()[0].id, 1) - self.assertEqual(reg.queryEntries()[0].entry, {'var': 7}) + self.assertEqual(reg.queryEntries()[0].entry, {"var": 7}) - self.assertEqual(reg.queryEntries()[1].providerId, 'my provider 5') + self.assertEqual(reg.queryEntries()[1].providerId, "my provider 5") self.assertEqual(reg.queryEntries()[1].id, 2) - self.assertEqual(reg.queryEntries()[1].entry, {'var': 8}) + self.assertEqual(reg.queryEntries()[1].entry, {"var": 8}) def test_nodes(self): node = TestNode() @@ -388,109 +404,113 @@ def test_model(self): registry = QgsHistoryProviderRegistry() provider = TestHistoryProvider() registry.addProvider(provider) - registry.addEntry(provider.id(), {'a': 1}) - registry.addEntry(provider.id(), {'a': 2}) - registry.addEntry(provider.id(), {'a': 3}) + registry.addEntry(provider.id(), {"a": 1}) + registry.addEntry(provider.id(), {"a": 2}) + registry.addEntry(provider.id(), {"a": 3}) model = QgsHistoryEntryModel(provider.id(), registry=registry) # find Today group self.assertEqual(model.rowCount(), 1) date_group_1_index = model.index(0, 0, QModelIndex()) - self.assertEqual(model.data(date_group_1_index), 'Today') + self.assertEqual(model.data(date_group_1_index), "Today") self.assertEqual(model.rowCount(date_group_1_index), 3) entry_1_index = model.index(2, 0, date_group_1_index) - self.assertEqual(model.data(entry_1_index), {'a': 1}) + self.assertEqual(model.data(entry_1_index), {"a": 1}) entry_2_index = model.index(1, 0, date_group_1_index) - self.assertEqual(model.data(entry_2_index), {'a': 2}) + self.assertEqual(model.data(entry_2_index), {"a": 2}) entry_3_index = model.index(0, 0, date_group_1_index) - self.assertEqual(model.data(entry_3_index), {'a': 3}) + self.assertEqual(model.data(entry_3_index), {"a": 3}) # an entry from yesterday yesterday = QDateTime.currentDateTime().addDays(-1) - yesterday_entry = QgsHistoryEntry(provider.id(), yesterday, {'a': 4}) + yesterday_entry = QgsHistoryEntry(provider.id(), yesterday, {"a": 4}) registry.addEntry(yesterday_entry) self.assertEqual(model.rowCount(), 2) yesterday_index = model.index(1, 0, QModelIndex()) - self.assertEqual(model.data(yesterday_index), 'Yesterday') + self.assertEqual(model.data(yesterday_index), "Yesterday") self.assertEqual(model.rowCount(yesterday_index), 1) entry_4_index = model.index(0, 0, yesterday_index) - self.assertEqual(model.data(entry_4_index), {'a': 4}) + self.assertEqual(model.data(entry_4_index), {"a": 4}) # another entry from yesterday - yesterday_entry2 = QgsHistoryEntry(provider.id(), yesterday, {'a': 5}) + yesterday_entry2 = QgsHistoryEntry(provider.id(), yesterday, {"a": 5}) registry.addEntry(yesterday_entry2) - self.assertEqual(model.data(yesterday_index), 'Yesterday') + self.assertEqual(model.data(yesterday_index), "Yesterday") self.assertEqual(model.rowCount(yesterday_index), 2) - self.assertEqual(model.data(entry_4_index), {'a': 4}) + self.assertEqual(model.data(entry_4_index), {"a": 4}) entry_5_index = model.index(0, 0, yesterday_index) - self.assertEqual(model.data(entry_5_index), {'a': 5}) - self.assertEqual(model.data(entry_4_index), {'a': 4}) + self.assertEqual(model.data(entry_5_index), {"a": 5}) + self.assertEqual(model.data(entry_4_index), {"a": 4}) # an entry from an earlier month - earlier_entry = QgsHistoryEntry(provider.id(), QDateTime(QDate(2020, 6, 3), QTime(12, 13, 14)), {'a': 6}) + earlier_entry = QgsHistoryEntry( + provider.id(), QDateTime(QDate(2020, 6, 3), QTime(12, 13, 14)), {"a": 6} + ) earlier_entry_id, _ = registry.addEntry(earlier_entry) self.assertEqual(model.rowCount(), 3) june2020_index = model.index(2, 0, QModelIndex()) - self.assertEqual(model.data(date_group_1_index), 'Today') - self.assertEqual(model.data(yesterday_index), 'Yesterday') - self.assertEqual(model.data(june2020_index), 'June 2020') + self.assertEqual(model.data(date_group_1_index), "Today") + self.assertEqual(model.data(yesterday_index), "Yesterday") + self.assertEqual(model.data(june2020_index), "June 2020") self.assertEqual(model.rowCount(june2020_index), 1) entry_6_index = model.index(0, 0, june2020_index) - self.assertEqual(model.data(entry_6_index), {'a': 6}) + self.assertEqual(model.data(entry_6_index), {"a": 6}) # an entry from an earlier month which is later than the previous one - earlier_entry2 = QgsHistoryEntry(provider.id(), QDateTime(QDate(2020, 10, 3), QTime(12, 13, 14)), {'a': 7}) + earlier_entry2 = QgsHistoryEntry( + provider.id(), QDateTime(QDate(2020, 10, 3), QTime(12, 13, 14)), {"a": 7} + ) registry.addEntry(earlier_entry2) self.assertEqual(model.rowCount(), 4) october2020_index = model.index(2, 0, QModelIndex()) - self.assertEqual(model.data(date_group_1_index), 'Today') - self.assertEqual(model.data(yesterday_index), 'Yesterday') - self.assertEqual(model.data(june2020_index), 'June 2020') - self.assertEqual(model.data(october2020_index), 'October 2020') + self.assertEqual(model.data(date_group_1_index), "Today") + self.assertEqual(model.data(yesterday_index), "Yesterday") + self.assertEqual(model.data(june2020_index), "June 2020") + self.assertEqual(model.data(october2020_index), "October 2020") self.assertEqual(model.rowCount(october2020_index), 1) entry_7_index = model.index(0, 0, october2020_index) - self.assertEqual(model.data(entry_7_index), {'a': 7}) + self.assertEqual(model.data(entry_7_index), {"a": 7}) # an entry from last week last_week = QDateTime.currentDateTime().addDays(-7) - last_week_entry = QgsHistoryEntry(provider.id(), last_week, {'a': 'last_week'}) + last_week_entry = QgsHistoryEntry(provider.id(), last_week, {"a": "last_week"}) registry.addEntry(last_week_entry) self.assertEqual(model.rowCount(), 5) last_week_index = model.index(2, 0, QModelIndex()) - self.assertEqual(model.data(date_group_1_index), 'Today') - self.assertEqual(model.data(yesterday_index), 'Yesterday') - self.assertEqual(model.data(june2020_index), 'June 2020') - self.assertEqual(model.data(october2020_index), 'October 2020') - self.assertEqual(model.data(last_week_index), 'Last 7 days') + self.assertEqual(model.data(date_group_1_index), "Today") + self.assertEqual(model.data(yesterday_index), "Yesterday") + self.assertEqual(model.data(june2020_index), "June 2020") + self.assertEqual(model.data(october2020_index), "October 2020") + self.assertEqual(model.data(last_week_index), "Last 7 days") self.assertEqual(model.rowCount(last_week_index), 1) entry_last_week_index = model.index(0, 0, last_week_index) - self.assertEqual(model.data(entry_last_week_index), {'a': 'last_week'}) + self.assertEqual(model.data(entry_last_week_index), {"a": "last_week"}) # update an entry - registry.updateEntry(earlier_entry_id, {'a': 8}) + registry.updateEntry(earlier_entry_id, {"a": 8}) entry_6_index = model.index(0, 0, june2020_index) - self.assertEqual(model.data(entry_6_index), {'a': 8}) + self.assertEqual(model.data(entry_6_index), {"a": 8}) self.assertEqual(model.rowCount(entry_6_index), 2) entry_6a_index = model.index(0, 0, entry_6_index) - self.assertEqual(model.data(entry_6a_index), 'my child') + self.assertEqual(model.data(entry_6a_index), "my child") entry_6b_index = model.index(1, 0, entry_6_index) - self.assertEqual(model.data(entry_6b_index), 'my child 2') + self.assertEqual(model.data(entry_6b_index), "my child 2") # clear registry.clearHistory(Qgis.HistoryProviderBackend.LocalProfile) self.assertEqual(model.rowCount(), 0) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsimagecache.py b/tests/src/python/test_qgsimagecache.py index 7344cc89c624..d146925db3e4 100644 --- a/tests/src/python/test_qgsimagecache.py +++ b/tests/src/python/test_qgsimagecache.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2018 by Nyall Dawson' -__date__ = '02/10/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "(C) 2018 by Nyall Dawson" +__date__ = "02/10/2018" +__copyright__ = "Copyright 2018, The QGIS Project" import http.server import os @@ -16,9 +17,7 @@ import time from qgis.PyQt.QtCore import QCoreApplication, QSize -from qgis.core import ( - QgsApplication -) +from qgis.core import QgsApplication import unittest from qgis.testing import start_app, QgisTestCase @@ -46,10 +45,10 @@ def setUpClass(cls): super().setUpClass() # Bring up a simple HTTP server, for remote SVG tests - os.chdir(unitTestDataPath() + '') + os.chdir(unitTestDataPath() + "") handler = SlowHTTPRequestHandler - cls.httpd = socketserver.TCPServer(('localhost', 0), handler) + cls.httpd = socketserver.TCPServer(("localhost", 0), handler) cls.port = cls.httpd.server_address[1] cls.httpd_thread = threading.Thread(target=cls.httpd.serve_forever) @@ -70,49 +69,95 @@ def waitForFetch(self): def testRemoteImage(self): """Test fetching remote image.""" - url = f'http://localhost:{str(TestQgsImageCache.port)}/qgis_local_server/sample_image.png' - image, in_cache = QgsApplication.imageCache().pathAsImage(url, QSize(100, 100), True, 1.0) + url = f"http://localhost:{str(TestQgsImageCache.port)}/qgis_local_server/sample_image.png" + image, in_cache = QgsApplication.imageCache().pathAsImage( + url, QSize(100, 100), True, 1.0 + ) # first should be waiting image - self.assertTrue(self.image_check('Remote Image', 'waiting_image', image, use_checkerboard_background=True)) + self.assertTrue( + self.image_check( + "Remote Image", "waiting_image", image, use_checkerboard_background=True + ) + ) self.assertFalse(QgsApplication.imageCache().originalSize(url).isValid()) self.waitForFetch() # second should be correct image - image, in_cache = QgsApplication.imageCache().pathAsImage(url, QSize(100, 100), True, 1.0) + image, in_cache = QgsApplication.imageCache().pathAsImage( + url, QSize(100, 100), True, 1.0 + ) self.assertTrue( - self.image_check('Remote Image', 'remote_image', image, use_checkerboard_background=True)) - self.assertEqual(QgsApplication.imageCache().originalSize(url), QSize(511, 800), 1.0) + self.image_check( + "Remote Image", "remote_image", image, use_checkerboard_background=True + ) + ) + self.assertEqual( + QgsApplication.imageCache().originalSize(url), QSize(511, 800), 1.0 + ) def testRemoteImageMissing(self): """Test fetching remote image with bad url""" - url = f'http://localhost:{str(TestQgsImageCache.port)}/qgis_local_server/xxx.png' # oooo naughty - image, in_cache = QgsApplication.imageCache().pathAsImage(url, QSize(100, 100), True, 1.0) + url = f"http://localhost:{str(TestQgsImageCache.port)}/qgis_local_server/xxx.png" # oooo naughty + image, in_cache = QgsApplication.imageCache().pathAsImage( + url, QSize(100, 100), True, 1.0 + ) - self.assertTrue(self.image_check('Remote image missing', 'waiting_image', image, use_checkerboard_background=True)) + self.assertTrue( + self.image_check( + "Remote image missing", + "waiting_image", + image, + use_checkerboard_background=True, + ) + ) def testRemoteImageBlocking(self): """Test fetching remote image.""" # remote not yet requested so not in cache - url = f'http://localhost:{str(TestQgsImageCache.port)}/qgis_local_server/logo_2017.png' - image, in_cache = QgsApplication.imageCache().pathAsImage(url, QSize(100, 100), True, 1.0, blocking=1) + url = f"http://localhost:{str(TestQgsImageCache.port)}/qgis_local_server/logo_2017.png" + image, in_cache = QgsApplication.imageCache().pathAsImage( + url, QSize(100, 100), True, 1.0, blocking=1 + ) # first should be correct image - self.assertTrue(self.image_check('Remote image sync', 'remote_image_blocking', image, use_checkerboard_background=True)) + self.assertTrue( + self.image_check( + "Remote image sync", + "remote_image_blocking", + image, + use_checkerboard_background=True, + ) + ) # remote probably in cache - url = f'http://localhost:{str(TestQgsImageCache.port)}/qgis_local_server/sample_image.png' - image, in_cache = QgsApplication.imageCache().pathAsImage(url, QSize(100, 100), True, 1.0, blocking=1) + url = f"http://localhost:{str(TestQgsImageCache.port)}/qgis_local_server/sample_image.png" + image, in_cache = QgsApplication.imageCache().pathAsImage( + url, QSize(100, 100), True, 1.0, blocking=1 + ) - self.assertTrue(self.image_check('Remote Image', 'remote_image', image, use_checkerboard_background=True)) + self.assertTrue( + self.image_check( + "Remote Image", "remote_image", image, use_checkerboard_background=True + ) + ) # remote probably in cache - url = f'http://localhost:{str(TestQgsImageCache.port)}/qgis_local_server/xxx.png' # oooo naughty - image, in_cache = QgsApplication.imageCache().pathAsImage(url, QSize(100, 100), True, 1.0, blocking=1) + url = f"http://localhost:{str(TestQgsImageCache.port)}/qgis_local_server/xxx.png" # oooo naughty + image, in_cache = QgsApplication.imageCache().pathAsImage( + url, QSize(100, 100), True, 1.0, blocking=1 + ) - self.assertTrue(self.image_check('Remote image missing', 'waiting_image', image, use_checkerboard_background=True)) + self.assertTrue( + self.image_check( + "Remote image missing", + "waiting_image", + image, + use_checkerboard_background=True, + ) + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsimagesourcelineedit.py b/tests/src/python/test_qgsimagesourcelineedit.py index 8373cfc1fe40..d8eff2fdac94 100644 --- a/tests/src/python/test_qgsimagesourcelineedit.py +++ b/tests/src/python/test_qgsimagesourcelineedit.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '5/12/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "5/12/2018" +__copyright__ = "Copyright 2018, The QGIS Project" import os @@ -24,56 +25,56 @@ class TestQgsImageSourceLineEdit(QgisTestCase): def testGettersSetters(self): - """ test widget getters/setters """ + """test widget getters/setters""" w = QgsImageSourceLineEdit() spy = QSignalSpy(w.sourceChanged) - w.setSource('source') - self.assertEqual(w.source(), 'source') + w.setSource("source") + self.assertEqual(w.source(), "source") self.assertEqual(len(spy), 1) - self.assertEqual(spy[0][0], 'source') + self.assertEqual(spy[0][0], "source") # no signal for same value - w.setSource('source') - self.assertEqual(w.source(), 'source') + w.setSource("source") + self.assertEqual(w.source(), "source") self.assertEqual(len(spy), 1) - w.setSource('another') - self.assertEqual(w.source(), 'another') + w.setSource("another") + self.assertEqual(w.source(), "another") self.assertEqual(len(spy), 2) - self.assertEqual(spy[1][0], 'another') + self.assertEqual(spy[1][0], "another") def testEmbedding(self): - """Test embedding large SVGs """ + """Test embedding large SVGs""" w = QgsImageSourceLineEdit() spy = QSignalSpy(w.sourceChanged) - w.setSource('source') - self.assertEqual(w.source(), 'source') + w.setSource("source") + self.assertEqual(w.source(), "source") self.assertEqual(len(spy), 1) - self.assertEqual(spy[0][0], 'source') + self.assertEqual(spy[0][0], "source") - b64 = 'base64:' + ''.join(['x'] * 1000000) + b64 = "base64:" + "".join(["x"] * 1000000) w.setSource(b64) self.assertEqual(w.source(), b64) self.assertEqual(len(spy), 2) self.assertEqual(spy[1][0], b64) - w.setSource(os.path.join(unitTestDataPath(), 'landsat.tif')) - self.assertEqual(w.source(), os.path.join(unitTestDataPath(), 'landsat.tif')) + w.setSource(os.path.join(unitTestDataPath(), "landsat.tif")) + self.assertEqual(w.source(), os.path.join(unitTestDataPath(), "landsat.tif")) self.assertEqual(len(spy), 3) - self.assertEqual(spy[2][0], os.path.join(unitTestDataPath(), 'landsat.tif')) + self.assertEqual(spy[2][0], os.path.join(unitTestDataPath(), "landsat.tif")) w.setSource(b64) self.assertEqual(w.source(), b64) self.assertEqual(len(spy), 4) self.assertEqual(spy[3][0], b64) - w.setSource('') - self.assertEqual(w.source(), '') + w.setSource("") + self.assertEqual(w.source(), "") self.assertEqual(len(spy), 5) - self.assertEqual(spy[4][0], '') + self.assertEqual(spy[4][0], "") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsinputcontroller.py b/tests/src/python/test_qgsinputcontroller.py index 312e6cbf3551..30b6478ecd52 100644 --- a/tests/src/python/test_qgsinputcontroller.py +++ b/tests/src/python/test_qgsinputcontroller.py @@ -7,15 +7,16 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2022 by Nyall Dawson' -__date__ = '14/07/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "(C) 2022 by Nyall Dawson" +__date__ = "14/07/2022" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, Qt, QTime, QTimeZone, QVariant from qgis.gui import ( QgsInputControllerManager, QgsAbstract2DMapController, - QgsAbstract3DMapController + QgsAbstract3DMapController, ) from qgis.testing import start_app, unittest @@ -28,7 +29,7 @@ class Dummy2dController(QgsAbstract2DMapController): def deviceId(self): - return 'dummy2d' + return "dummy2d" def clone(self): return Dummy2dController() @@ -37,7 +38,7 @@ def clone(self): class Dummy3dController(QgsAbstract3DMapController): def deviceId(self): - return 'dummy3d' + return "dummy3d" def clone(self): return Dummy3dController() @@ -51,23 +52,23 @@ def test_registration(self): self.assertFalse(manager.available3DMapControllers()) manager.register2DMapController(Dummy2dController()) - self.assertEqual(manager.available2DMapControllers(), ['dummy2d']) + self.assertEqual(manager.available2DMapControllers(), ["dummy2d"]) self.assertFalse(manager.available3DMapControllers()) - new_controller = manager.create2DMapController('dummy2d') + new_controller = manager.create2DMapController("dummy2d") self.assertIsInstance(new_controller, Dummy2dController) - self.assertEqual(new_controller.deviceId(), 'dummy2d') - self.assertIsNone(manager.create2DMapController('nope')) + self.assertEqual(new_controller.deviceId(), "dummy2d") + self.assertIsNone(manager.create2DMapController("nope")) manager.register3DMapController(Dummy3dController()) - self.assertEqual(manager.available2DMapControllers(), ['dummy2d']) - self.assertEqual(manager.available3DMapControllers(), ['dummy3d']) + self.assertEqual(manager.available2DMapControllers(), ["dummy2d"]) + self.assertEqual(manager.available3DMapControllers(), ["dummy3d"]) - new_controller = manager.create3DMapController('dummy3d') + new_controller = manager.create3DMapController("dummy3d") self.assertIsInstance(new_controller, Dummy3dController) - self.assertEqual(new_controller.deviceId(), 'dummy3d') - self.assertIsNone(manager.create3DMapController('nope')) + self.assertEqual(new_controller.deviceId(), "dummy3d") + self.assertIsNone(manager.create3DMapController("nope")) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsinterpolatedlinesymbollayers.py b/tests/src/python/test_qgsinterpolatedlinesymbollayers.py index 0b9979849340..37824be22152 100644 --- a/tests/src/python/test_qgsinterpolatedlinesymbollayers.py +++ b/tests/src/python/test_qgsinterpolatedlinesymbollayers.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Vincent Cloares' -__date__ = '2021-04' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Vincent Cloares" +__date__ = "2021-04" +__copyright__ = "Copyright 2020, The QGIS Project" import unittest @@ -38,14 +39,28 @@ class TestQgsInterpolatedLineSymbolLayers(QgisTestCase): def control_path_prefix(cls): return "symbol_interpolatedline" - def render_image(self, - interpolated_width: QgsInterpolatedLineWidth, - interpolated_color: QgsInterpolatedLineColor) -> QImage: + def render_image( + self, + interpolated_width: QgsInterpolatedLineWidth, + interpolated_color: QgsInterpolatedLineColor, + ) -> QImage: layer = QgsInterpolatedLineSymbolLayer() - layer.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyLineStartWidthValue, QgsProperty.fromExpression('5')) - layer.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyLineEndWidthValue, QgsProperty.fromExpression('1')) - layer.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyLineStartColorValue, QgsProperty.fromExpression('2')) - layer.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyLineEndColorValue, QgsProperty.fromExpression('6')) + layer.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyLineStartWidthValue, + QgsProperty.fromExpression("5"), + ) + layer.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyLineEndWidthValue, + QgsProperty.fromExpression("1"), + ) + layer.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyLineStartColorValue, + QgsProperty.fromExpression("2"), + ) + layer.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyLineEndColorValue, + QgsProperty.fromExpression("6"), + ) layer.setInterpolatedWidth(interpolated_width) layer.setInterpolatedColor(interpolated_color) @@ -56,7 +71,7 @@ def render_image(self, painter = QPainter() ms = QgsMapSettings() - geom = QgsGeometry.fromWkt('LineString (0 0, 10 0, 10 10, 0 10, 0 5)') + geom = QgsGeometry.fromWkt("LineString (0 0, 10 0, 10 10, 0 10, 0 5)") f = QgsFeature() f.setGeometry(geom) @@ -92,21 +107,20 @@ def testFixedColorFixedWidth(self): interpolated_width.setIsVariableWidth(False) interpolated_width.setFixedStrokeWidth(5) interpolated_color.setColor(QColor(255, 0, 0)) - interpolated_color.setColoringMethod(QgsInterpolatedLineColor.ColoringMethod.SingleColor) - - rendered_image = self.render_image( - interpolated_width, - interpolated_color + interpolated_color.setColoringMethod( + QgsInterpolatedLineColor.ColoringMethod.SingleColor ) + rendered_image = self.render_image(interpolated_width, interpolated_color) + self.assertTrue( self.image_check( - 'interpolatedlinesymbollayer_1', - 'interpolatedlinesymbollayer_1', + "interpolatedlinesymbollayer_1", + "interpolatedlinesymbollayer_1", rendered_image, - 'expected_interpolatedlinesymbollayer_1', + "expected_interpolatedlinesymbollayer_1", color_tolerance=2, - allowed_mismatch=0 + allowed_mismatch=0, ) ) @@ -121,13 +135,27 @@ def testRenderNoFeature(self): interpolated_width.setIsVariableWidth(False) interpolated_width.setFixedStrokeWidth(5) interpolated_color.setColor(QColor(255, 0, 0)) - interpolated_color.setColoringMethod(QgsInterpolatedLineColor.ColoringMethod.SingleColor) + interpolated_color.setColoringMethod( + QgsInterpolatedLineColor.ColoringMethod.SingleColor + ) layer = QgsInterpolatedLineSymbolLayer() - layer.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyLineStartWidthValue, QgsProperty.fromExpression('5')) - layer.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyLineEndWidthValue, QgsProperty.fromExpression('1')) - layer.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyLineStartColorValue, QgsProperty.fromExpression('2')) - layer.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyLineEndColorValue, QgsProperty.fromExpression('6')) + layer.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyLineStartWidthValue, + QgsProperty.fromExpression("5"), + ) + layer.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyLineEndWidthValue, + QgsProperty.fromExpression("1"), + ) + layer.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyLineStartColorValue, + QgsProperty.fromExpression("2"), + ) + layer.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyLineEndColorValue, + QgsProperty.fromExpression("6"), + ) layer.setInterpolatedWidth(interpolated_width) layer.setInterpolatedColor(interpolated_color) @@ -142,19 +170,23 @@ def testRenderNoFeature(self): symbol.startRender(context) - symbol.renderPolyline(QPolygonF([QPointF(30, 50), QPointF(100, 70), QPointF(150, 30)]), None, context) + symbol.renderPolyline( + QPolygonF([QPointF(30, 50), QPointF(100, 70), QPointF(150, 30)]), + None, + context, + ) symbol.stopRender(context) painter.end() self.assertTrue( self.image_check( - 'interpolatedlinesymbollayer_no_feature', - 'interpolatedlinesymbollayer_no_feature', + "interpolatedlinesymbollayer_no_feature", + "interpolatedlinesymbollayer_no_feature", image, - 'expected_interpolatedlinesymbollayer_no_feature', + "expected_interpolatedlinesymbollayer_no_feature", color_tolerance=2, - allowed_mismatch=0 + allowed_mismatch=0, ) ) @@ -169,25 +201,28 @@ def testVaryingColorFixedWidth(self): interpolated_width.setIsVariableWidth(False) interpolated_width.setFixedStrokeWidth(5) - color_ramp = QgsColorRampShader(0, 7, QgsStyle.defaultStyle().colorRamp('Viridis'), - QgsColorRampShader.Type.Interpolated) + color_ramp = QgsColorRampShader( + 0, + 7, + QgsStyle.defaultStyle().colorRamp("Viridis"), + QgsColorRampShader.Type.Interpolated, + ) color_ramp.classifyColorRamp(10) interpolated_color.setColor(color_ramp) - interpolated_color.setColoringMethod(QgsInterpolatedLineColor.ColoringMethod.ColorRamp) - - rendered_image = self.render_image( - interpolated_width, - interpolated_color + interpolated_color.setColoringMethod( + QgsInterpolatedLineColor.ColoringMethod.ColorRamp ) + rendered_image = self.render_image(interpolated_width, interpolated_color) + self.assertTrue( self.image_check( - 'interpolatedlinesymbollayer_2', - 'interpolatedlinesymbollayer_2', + "interpolatedlinesymbollayer_2", + "interpolatedlinesymbollayer_2", rendered_image, - 'expected_interpolatedlinesymbollayer_2', + "expected_interpolatedlinesymbollayer_2", color_tolerance=2, - allowed_mismatch=0 + allowed_mismatch=0, ) ) @@ -206,21 +241,20 @@ def testFixedColorVaryingWidth(self): interpolated_width.setMinimumWidth(1) interpolated_width.setMaximumWidth(10) interpolated_color.setColor(QColor(0, 255, 0)) - interpolated_color.setColoringMethod(QgsInterpolatedLineColor.ColoringMethod.SingleColor) - - rendered_image = self.render_image( - interpolated_width, - interpolated_color + interpolated_color.setColoringMethod( + QgsInterpolatedLineColor.ColoringMethod.SingleColor ) + rendered_image = self.render_image(interpolated_width, interpolated_color) + self.assertTrue( self.image_check( - 'interpolatedlinesymbollayer_3', - 'interpolatedlinesymbollayer_3', + "interpolatedlinesymbollayer_3", + "interpolatedlinesymbollayer_3", rendered_image, - 'expected_interpolatedlinesymbollayer_3', + "expected_interpolatedlinesymbollayer_3", color_tolerance=2, - allowed_mismatch=0 + allowed_mismatch=0, ) ) @@ -238,25 +272,28 @@ def testVaryingColorVaryingWidth(self): interpolated_width.setMaximumValue(8) interpolated_width.setMinimumWidth(1) interpolated_width.setMaximumWidth(10) - color_ramp = QgsColorRampShader(0, 7, QgsStyle.defaultStyle().colorRamp('Viridis'), - QgsColorRampShader.Type.Interpolated) + color_ramp = QgsColorRampShader( + 0, + 7, + QgsStyle.defaultStyle().colorRamp("Viridis"), + QgsColorRampShader.Type.Interpolated, + ) color_ramp.classifyColorRamp(10) interpolated_color.setColor(color_ramp) - interpolated_color.setColoringMethod(QgsInterpolatedLineColor.ColoringMethod.ColorRamp) - - rendered_image = self.render_image( - interpolated_width, - interpolated_color + interpolated_color.setColoringMethod( + QgsInterpolatedLineColor.ColoringMethod.ColorRamp ) + rendered_image = self.render_image(interpolated_width, interpolated_color) + self.assertTrue( self.image_check( - 'interpolatedlinesymbollayer_4', - 'interpolatedlinesymbollayer_4', + "interpolatedlinesymbollayer_4", + "interpolatedlinesymbollayer_4", rendered_image, - 'expected_interpolatedlinesymbollayer_4', + "expected_interpolatedlinesymbollayer_4", color_tolerance=2, - allowed_mismatch=0 + allowed_mismatch=0, ) ) @@ -274,25 +311,28 @@ def testVaryingColorVaryingWidthDiscrete(self): interpolated_width.setMaximumValue(8) interpolated_width.setMinimumWidth(1) interpolated_width.setMaximumWidth(10) - color_ramp = QgsColorRampShader(2, 7, QgsStyle.defaultStyle().colorRamp('RdGy'), - QgsColorRampShader.Type.Discrete) + color_ramp = QgsColorRampShader( + 2, + 7, + QgsStyle.defaultStyle().colorRamp("RdGy"), + QgsColorRampShader.Type.Discrete, + ) color_ramp.classifyColorRamp(5) interpolated_color.setColor(color_ramp) - interpolated_color.setColoringMethod(QgsInterpolatedLineColor.ColoringMethod.ColorRamp) - - rendered_image = self.render_image( - interpolated_width, - interpolated_color + interpolated_color.setColoringMethod( + QgsInterpolatedLineColor.ColoringMethod.ColorRamp ) + rendered_image = self.render_image(interpolated_width, interpolated_color) + self.assertTrue( self.image_check( - 'interpolatedlinesymbollayer_5', - 'interpolatedlinesymbollayer_5', + "interpolatedlinesymbollayer_5", + "interpolatedlinesymbollayer_5", rendered_image, - 'expected_interpolatedlinesymbollayer_5', + "expected_interpolatedlinesymbollayer_5", color_tolerance=2, - allowed_mismatch=0 + allowed_mismatch=0, ) ) @@ -310,28 +350,31 @@ def testVaryingColorVaryingWidthExact(self): interpolated_width.setMaximumValue(8) interpolated_width.setMinimumWidth(1) interpolated_width.setMaximumWidth(10) - color_ramp = QgsColorRampShader(0, 10, QgsStyle.defaultStyle().colorRamp('Viridis'), - QgsColorRampShader.Type.Exact) + color_ramp = QgsColorRampShader( + 0, + 10, + QgsStyle.defaultStyle().colorRamp("Viridis"), + QgsColorRampShader.Type.Exact, + ) color_ramp.classifyColorRamp(10) interpolated_color.setColor(color_ramp) - interpolated_color.setColoringMethod(QgsInterpolatedLineColor.ColoringMethod.ColorRamp) - - rendered_image = self.render_image( - interpolated_width, - interpolated_color + interpolated_color.setColoringMethod( + QgsInterpolatedLineColor.ColoringMethod.ColorRamp ) + rendered_image = self.render_image(interpolated_width, interpolated_color) + self.assertTrue( self.image_check( - 'interpolatedlinesymbollayer_6', - 'interpolatedlinesymbollayer_6', + "interpolatedlinesymbollayer_6", + "interpolatedlinesymbollayer_6", rendered_image, - 'expected_interpolatedlinesymbollayer_6', + "expected_interpolatedlinesymbollayer_6", color_tolerance=2, - allowed_mismatch=0 + allowed_mismatch=0, ) ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsinterval.py b/tests/src/python/test_qgsinterval.py index 276681fc304d..69fa06a13c54 100644 --- a/tests/src/python/test_qgsinterval.py +++ b/tests/src/python/test_qgsinterval.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '10/05/2016' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "10/05/2016" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.core import QgsInterval, QgsUnitTypes @@ -17,7 +18,7 @@ class TestQgsInterval(unittest.TestCase): def testIntervalConstructor(self): - """ Test QgsInterval constructor """ + """Test QgsInterval constructor""" # invalid interval i = QgsInterval() @@ -44,11 +45,16 @@ def test_repr(self): """ Test __repr__ implementation """ - self.assertEqual(repr(QgsInterval()), '') - self.assertEqual(repr(QgsInterval(5)), '') - self.assertEqual(repr(QgsInterval(1, QgsUnitTypes.TemporalUnit.TemporalMonths)), '') + self.assertEqual(repr(QgsInterval()), "") + self.assertEqual(repr(QgsInterval(5)), "") + self.assertEqual( + repr(QgsInterval(1, QgsUnitTypes.TemporalUnit.TemporalMonths)), + "", + ) self.assertEqual( - repr(QgsInterval(720, QgsUnitTypes.TemporalUnit.TemporalHours)), '') + repr(QgsInterval(720, QgsUnitTypes.TemporalUnit.TemporalHours)), + "", + ) def testSettersGetters(self): # setters and getters @@ -132,70 +138,70 @@ def testEquality(self): self.assertEqual(i1, i2) def testFromString(self): - i = QgsInterval.fromString('1 Year 1 Month 1 Week 1 Hour 1 Minute') + i = QgsInterval.fromString("1 Year 1 Month 1 Week 1 Hour 1 Minute") self.assertTrue(i.isValid()) self.assertEqual(i.seconds(), 34758060) - i = QgsInterval.fromString('1 Year, 1 Month, 1 Week, 1 Hour, 1 Minute') + i = QgsInterval.fromString("1 Year, 1 Month, 1 Week, 1 Hour, 1 Minute") self.assertTrue(i.isValid()) self.assertEqual(i.seconds(), 34758060) - i = QgsInterval.fromString('1 Year; 1 Month; 1 Week; 1 Hour; 1 Minute') + i = QgsInterval.fromString("1 Year; 1 Month; 1 Week; 1 Hour; 1 Minute") self.assertTrue(i.isValid()) self.assertEqual(i.seconds(), 34758060) - i = QgsInterval.fromString('1 Year. 1 Month. 1 Week. 1 Hour. 1 Minute.') + i = QgsInterval.fromString("1 Year. 1 Month. 1 Week. 1 Hour. 1 Minute.") self.assertTrue(i.isValid()) self.assertEqual(i.seconds(), 34758060) - i = QgsInterval.fromString('1 Year. 1 Month. 1 Week. 01:01:00 ') + i = QgsInterval.fromString("1 Year. 1 Month. 1 Week. 01:01:00 ") self.assertTrue(i.isValid()) self.assertEqual(i.seconds(), 34758060) - i = QgsInterval.fromString('1 Year. 1 Mon. 1 Week. 01:01:00 ') + i = QgsInterval.fromString("1 Year. 1 Mon. 1 Week. 01:01:00 ") self.assertTrue(i.isValid()) self.assertEqual(i.seconds(), 34758060) - i = QgsInterval.fromString('2 Years') + i = QgsInterval.fromString("2 Years") self.assertTrue(i.isValid()) self.assertEqual(i.years(), 2) - i = QgsInterval.fromString('20000 Years') + i = QgsInterval.fromString("20000 Years") self.assertTrue(i.isValid()) self.assertEqual(i.years(), 20000) - i = QgsInterval.fromString('30 month') + i = QgsInterval.fromString("30 month") self.assertTrue(i.isValid()) self.assertEqual(i.months(), 30) - i = QgsInterval.fromString(' 40 MONTHS ') + i = QgsInterval.fromString(" 40 MONTHS ") self.assertTrue(i.isValid()) self.assertEqual(i.months(), 40) - i = QgsInterval.fromString('2.5 weeks') + i = QgsInterval.fromString("2.5 weeks") self.assertTrue(i.isValid()) self.assertEqual(i.weeks(), 2.5) - i = QgsInterval.fromString('2.5 WEEK') + i = QgsInterval.fromString("2.5 WEEK") self.assertTrue(i.isValid()) self.assertEqual(i.weeks(), 2.5) - i = QgsInterval.fromString('1 Day') + i = QgsInterval.fromString("1 Day") self.assertTrue(i.isValid()) self.assertEqual(i.seconds(), 24 * 60 * 60) - i = QgsInterval.fromString('101.5 Days') + i = QgsInterval.fromString("101.5 Days") self.assertTrue(i.isValid()) self.assertEqual(i.seconds(), 101.5 * 24 * 60 * 60) - i = QgsInterval.fromString('2 dAys') + i = QgsInterval.fromString("2 dAys") self.assertTrue(i.isValid()) self.assertEqual(i.seconds(), 48 * 60 * 60) - i = QgsInterval.fromString('1 hours') + i = QgsInterval.fromString("1 hours") self.assertTrue(i.isValid()) self.assertEqual(i.hours(), 1) - i = QgsInterval.fromString('1.7 HoURS ') + i = QgsInterval.fromString("1.7 HoURS ") self.assertTrue(i.isValid()) self.assertEqual(i.hours(), 1.7) - i = QgsInterval.fromString('2 minutes') + i = QgsInterval.fromString("2 minutes") self.assertTrue(i.isValid()) self.assertEqual(i.minutes(), 2) - i = QgsInterval.fromString('123 MiNuTe ') + i = QgsInterval.fromString("123 MiNuTe ") self.assertTrue(i.isValid()) self.assertEqual(i.minutes(), 123) - i = QgsInterval.fromString('5 Seconds') + i = QgsInterval.fromString("5 Seconds") self.assertTrue(i.isValid()) self.assertEqual(i.seconds(), 5) - i = QgsInterval.fromString('5 second') + i = QgsInterval.fromString("5 second") self.assertTrue(i.isValid()) self.assertEqual(i.seconds(), 5) - i = QgsInterval.fromString('bad') + i = QgsInterval.fromString("bad") self.assertFalse(i.isValid()) def testFromUnits(self): @@ -219,10 +225,14 @@ def testFromUnits(self): def testIntervalDurationUnitSetting(self): i = QgsInterval() self.assertEqual(i.originalDuration(), 0.0) - self.assertEqual(i.originalUnit(), QgsUnitTypes.TemporalUnit.TemporalUnknownUnit) + self.assertEqual( + i.originalUnit(), QgsUnitTypes.TemporalUnit.TemporalUnknownUnit + ) i = QgsInterval(2, QgsUnitTypes.TemporalUnit.TemporalMilliseconds) self.assertEqual(i.originalDuration(), 2.0) - self.assertEqual(i.originalUnit(), QgsUnitTypes.TemporalUnit.TemporalMilliseconds) + self.assertEqual( + i.originalUnit(), QgsUnitTypes.TemporalUnit.TemporalMilliseconds + ) i = QgsInterval(34.56, QgsUnitTypes.TemporalUnit.TemporalSeconds) self.assertEqual(i.originalDuration(), 34.56) self.assertEqual(i.originalUnit(), QgsUnitTypes.TemporalUnit.TemporalSeconds) @@ -287,12 +297,16 @@ def testIntervalDurationUnitSetting(self): i = QgsInterval(0, 0, 0, 0, 0, 1, 1) self.assertEqual(i.originalDuration(), 0.0) - self.assertEqual(i.originalUnit(), QgsUnitTypes.TemporalUnit.TemporalUnknownUnit) + self.assertEqual( + i.originalUnit(), QgsUnitTypes.TemporalUnit.TemporalUnknownUnit + ) def testSettersDurationUnitChange(self): i = QgsInterval() self.assertEqual(i.originalDuration(), 0.0) - self.assertEqual(i.originalUnit(), QgsUnitTypes.TemporalUnit.TemporalUnknownUnit) + self.assertEqual( + i.originalUnit(), QgsUnitTypes.TemporalUnit.TemporalUnknownUnit + ) i.setYears(1) self.assertEqual(i.originalDuration(), 1.0) self.assertEqual(i.originalUnit(), QgsUnitTypes.TemporalUnit.TemporalYears) @@ -318,7 +332,9 @@ def testSettersDurationUnitChange(self): def testGettersDurationUnitChange(self): i = QgsInterval() self.assertEqual(i.originalDuration(), 0.0) - self.assertEqual(i.originalUnit(), QgsUnitTypes.TemporalUnit.TemporalUnknownUnit) + self.assertEqual( + i.originalUnit(), QgsUnitTypes.TemporalUnit.TemporalUnknownUnit + ) i.setYears(1) self.assertEqual(i.years(), 1.0) i.setMonths(3) @@ -340,5 +356,5 @@ def testGettersDurationUnitChange(self): self.assertEqual(i.months(), 1.5) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsissue7244.py b/tests/src/python/test_qgsissue7244.py index 79580e70d028..56337ae7e914 100644 --- a/tests/src/python/test_qgsissue7244.py +++ b/tests/src/python/test_qgsissue7244.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Vincent Mora' -__date__ = '09/07/2013' -__copyright__ = 'Copyright 2013, The QGIS Project' + +__author__ = "Vincent Mora" +__date__ = "09/07/2013" +__copyright__ = "Copyright 2013, The QGIS Project" import os @@ -87,27 +88,39 @@ def tearDown(self): def test_SplitMultipolygon(self): """Split multipolygon""" - layer = QgsVectorLayer("dbname=test.sqlite table=test_mpg (geometry)", "test_mpg", "spatialite") + layer = QgsVectorLayer( + "dbname=test.sqlite table=test_mpg (geometry)", "test_mpg", "spatialite" + ) assert layer.isValid() assert layer.isSpatial() layer.featureCount() == 1 or die("wrong number of features") layer.startEditing() - layer.splitFeatures([QgsPointXY(0.5, -0.5), QgsPointXY(0.5, 1.5)], 0) == 0 or die("error in split of one polygon of multipolygon") - layer.splitFeatures([QgsPointXY(2.5, -0.5), QgsPointXY(2.5, 4)], 0) == 0 or die("error in split of two polygons of multipolygon at a time") + layer.splitFeatures( + [QgsPointXY(0.5, -0.5), QgsPointXY(0.5, 1.5)], 0 + ) == 0 or die("error in split of one polygon of multipolygon") + layer.splitFeatures([QgsPointXY(2.5, -0.5), QgsPointXY(2.5, 4)], 0) == 0 or die( + "error in split of two polygons of multipolygon at a time" + ) layer.commitChanges() or die("this commit should work") layer.featureCount() == 7 or die("wrong number of features after 2 split") def test_SplitTruToCreateCutEdge(self): """Try to creat a cut edge""" - layer = QgsVectorLayer("dbname=test.sqlite table=test_pg (geometry)", "test_pg", "spatialite") + layer = QgsVectorLayer( + "dbname=test.sqlite table=test_pg (geometry)", "test_pg", "spatialite" + ) assert layer.isValid() assert layer.isSpatial() layer.featureCount() == 1 or die("wrong number of features") layer.startEditing() - layer.splitFeatures([QgsPointXY(1.5, -0.5), QgsPointXY(1.5, 1.5)], 0) == 0 or die("error when trying to create an invalid polygon in split") + layer.splitFeatures( + [QgsPointXY(1.5, -0.5), QgsPointXY(1.5, 1.5)], 0 + ) == 0 or die("error when trying to create an invalid polygon in split") layer.commitChanges() or die("this commit should work") - layer.featureCount() == 1 or die("wrong number of features, polygon should be unafected by cut") + layer.featureCount() == 1 or die( + "wrong number of features, polygon should be unafected by cut" + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsjsonedit.py b/tests/src/python/test_qgsjsonedit.py index e62808973722..734d5753b579 100644 --- a/tests/src/python/test_qgsjsonedit.py +++ b/tests/src/python/test_qgsjsonedit.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Damiano Lombardi' -__date__ = '2021-05-10' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Damiano Lombardi" +__date__ = "2021-05-10" +__copyright__ = "Copyright 2021, The QGIS Project" from qgis.gui import QgsJsonEditWidget @@ -20,7 +21,7 @@ class TestQgsJsonEdit(QgisTestCase): def testSettersGetters(self): - """ test widget handling of null values """ + """test widget handling of null values""" w = QgsJsonEditWidget() jsonText = '{"someText": "JSON edit widget test"}' @@ -29,5 +30,5 @@ def testSettersGetters(self): self.assertEqual(w.jsonText(), jsonText) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsjsonutils.py b/tests/src/python/test_qgsjsonutils.py index 46f69797d656..2677e6e41f00 100644 --- a/tests/src/python/test_qgsjsonutils.py +++ b/tests/src/python/test_qgsjsonutils.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '3/05/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "3/05/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtCore import QT_VERSION_STR, QLocale, Qt, QVariant from qgis.core import ( @@ -32,8 +33,9 @@ start_app() -if int(QT_VERSION_STR.split('.')[0]) < 6: +if int(QT_VERSION_STR.split(".")[0]) < 6: from qgis.PyQt.QtCore import QTextCodec + codec = QTextCodec.codecForName("System") @@ -45,14 +47,14 @@ def testStringToFeatureList(self): fields.append(QgsField("name", QVariant.String)) # empty string - if int(QT_VERSION_STR.split('.')[0]) >= 6: + if int(QT_VERSION_STR.split(".")[0]) >= 6: features = QgsJsonUtils.stringToFeatureList("", fields) else: features = QgsJsonUtils.stringToFeatureList("", fields, codec) self.assertEqual(features, []) # bad string - if int(QT_VERSION_STR.split('.')[0]) >= 6: + if int(QT_VERSION_STR.split(".")[0]) >= 6: features = QgsJsonUtils.stringToFeatureList("asdasdas", fields) else: features = QgsJsonUtils.stringToFeatureList("asdasdas", fields, codec) @@ -60,7 +62,7 @@ def testStringToFeatureList(self): # geojson string with 1 feature s = '{\n"type": "Feature","geometry": {"type": "Point","coordinates": [125, 10]},"properties": {"name": "Dinagat Islands"}}' - if int(QT_VERSION_STR.split('.')[0]) >= 6: + if int(QT_VERSION_STR.split(".")[0]) >= 6: features = QgsJsonUtils.stringToFeatureList(s, fields) else: features = QgsJsonUtils.stringToFeatureList(s, fields, codec) @@ -70,11 +72,11 @@ def testStringToFeatureList(self): point = features[0].geometry().constGet() self.assertEqual(point.x(), 125.0) self.assertEqual(point.y(), 10.0) - self.assertEqual(features[0]['name'], "Dinagat Islands") + self.assertEqual(features[0]["name"], "Dinagat Islands") # geojson string with 2 features s = '{ "type": "FeatureCollection","features":[{\n"type": "Feature","geometry": {"type": "Point","coordinates": [125, 10]},"properties": {"name": "Dinagat Islands"}}, {\n"type": "Feature","geometry": {"type": "Point","coordinates": [110, 20]},"properties": {"name": "Henry Gale Island"}}]}' - if int(QT_VERSION_STR.split('.')[0]) >= 6: + if int(QT_VERSION_STR.split(".")[0]) >= 6: features = QgsJsonUtils.stringToFeatureList(s, fields) else: features = QgsJsonUtils.stringToFeatureList(s, fields, codec) @@ -84,13 +86,13 @@ def testStringToFeatureList(self): point = features[0].geometry().constGet() self.assertEqual(point.x(), 125.0) self.assertEqual(point.y(), 10.0) - self.assertEqual(features[0]['name'], "Dinagat Islands") + self.assertEqual(features[0]["name"], "Dinagat Islands") self.assertFalse(features[1].geometry().isNull()) self.assertEqual(features[1].geometry().wkbType(), QgsWkbTypes.Type.Point) point = features[1].geometry().constGet() self.assertEqual(point.x(), 110.0) self.assertEqual(point.y(), 20.0) - self.assertEqual(features[1]['name'], "Henry Gale Island") + self.assertEqual(features[1]["name"], "Henry Gale Island") def testStringToFeatureListWithDatetimeProperty_regression44160(self): """Test that milliseconds and time zone information is parsed from datetime properties""" @@ -100,17 +102,32 @@ def testStringToFeatureListWithDatetimeProperty_regression44160(self): date = "2020-01-01T" def geojson_with_time(timepart): - return '{"type": "Feature","geometry": {"type": "Point","coordinates": [0,0]},"properties": {"some_time_field": "' + date + timepart + '"}}' + return ( + '{"type": "Feature","geometry": {"type": "Point","coordinates": [0,0]},"properties": {"some_time_field": "' + + date + + timepart + + '"}}' + ) # No milliseconds - features = QgsJsonUtils.stringToFeatureList(geojson_with_time('22:00:10'), fields) + features = QgsJsonUtils.stringToFeatureList( + geojson_with_time("22:00:10"), fields + ) self.assertEqual(len(features), 1) - self.assertEqual(features[0]['some_time_field'].toString(Qt.DateFormat.ISODateWithMs), f"{date}22:00:10.000") + self.assertEqual( + features[0]["some_time_field"].toString(Qt.DateFormat.ISODateWithMs), + f"{date}22:00:10.000", + ) # milliseconds - features = QgsJsonUtils.stringToFeatureList(geojson_with_time('22:00:10.123'), fields) + features = QgsJsonUtils.stringToFeatureList( + geojson_with_time("22:00:10.123"), fields + ) self.assertEqual(len(features), 1) - self.assertEqual(features[0]['some_time_field'].toString(Qt.DateFormat.ISODateWithMs), f"{date}22:00:10.123") + self.assertEqual( + features[0]["some_time_field"].toString(Qt.DateFormat.ISODateWithMs), + f"{date}22:00:10.123", + ) def testStringToFeatureListWithTimeProperty_regression44160(self): """Test that milliseconds and time zone information is parsed from time properties""" @@ -118,30 +135,44 @@ def testStringToFeatureListWithTimeProperty_regression44160(self): fields.append(QgsField("some_time_field", QVariant.Time)) def geojson_with_time(timepart): - return '{"type": "Feature","geometry": {"type": "Point","coordinates": [0,0]},"properties": {"some_time_field": "' + timepart + '"}}' + return ( + '{"type": "Feature","geometry": {"type": "Point","coordinates": [0,0]},"properties": {"some_time_field": "' + + timepart + + '"}}' + ) # No milliseconds - features = QgsJsonUtils.stringToFeatureList(geojson_with_time('22:00:10'), fields) + features = QgsJsonUtils.stringToFeatureList( + geojson_with_time("22:00:10"), fields + ) self.assertEqual(len(features), 1) - self.assertEqual(features[0]['some_time_field'].toString(Qt.DateFormat.ISODateWithMs), "22:00:10.000") + self.assertEqual( + features[0]["some_time_field"].toString(Qt.DateFormat.ISODateWithMs), + "22:00:10.000", + ) # milliseconds - features = QgsJsonUtils.stringToFeatureList(geojson_with_time('22:00:10.123'), fields) + features = QgsJsonUtils.stringToFeatureList( + geojson_with_time("22:00:10.123"), fields + ) self.assertEqual(len(features), 1) - self.assertEqual(features[0]['some_time_field'].toString(Qt.DateFormat.ISODateWithMs), "22:00:10.123") + self.assertEqual( + features[0]["some_time_field"].toString(Qt.DateFormat.ISODateWithMs), + "22:00:10.123", + ) def testStringToFields(self): """test retrieving fields from GeoJSON strings""" # empty string - if int(QT_VERSION_STR.split('.')[0]) >= 6: + if int(QT_VERSION_STR.split(".")[0]) >= 6: fields = QgsJsonUtils.stringToFields("") else: fields = QgsJsonUtils.stringToFields("", codec) self.assertEqual(fields.count(), 0) # bad string - if int(QT_VERSION_STR.split('.')[0]) >= 6: + if int(QT_VERSION_STR.split(".")[0]) >= 6: fields = QgsJsonUtils.stringToFields("asdasdas") else: fields = QgsJsonUtils.stringToFields("asdasdas", codec) @@ -149,7 +180,7 @@ def testStringToFields(self): # geojson string s = '{\n"type": "Feature","geometry": {"type": "Point","coordinates": [125, 10]},"properties": {"name": "Dinagat Islands","height":5.5}}' - if int(QT_VERSION_STR.split('.')[0]) >= 6: + if int(QT_VERSION_STR.split(".")[0]) >= 6: fields = QgsJsonUtils.stringToFields(s) else: fields = QgsJsonUtils.stringToFields(s, codec) @@ -161,7 +192,7 @@ def testStringToFields(self): # geojson string with 2 features s = '{ "type": "FeatureCollection","features":[{\n"type": "Feature","geometry": {"type": "Point","coordinates": [125, 10]},"properties": {"name": "Dinagat Islands","height":5.5}}, {\n"type": "Feature","geometry": {"type": "Point","coordinates": [110, 20]},"properties": {"name": "Henry Gale Island","height":6.5}}]}' - if int(QT_VERSION_STR.split('.')[0]) >= 6: + if int(QT_VERSION_STR.split(".")[0]) >= 6: fields = QgsJsonUtils.stringToFields(s) else: fields = QgsJsonUtils.stringToFields(s, codec) @@ -172,33 +203,42 @@ def testStringToFields(self): self.assertEqual(fields[1].type(), QVariant.Double) def testEncodeValue(self): - """ test encoding various values for use in GeoJSON strings """ - self.assertEqual(QgsJsonUtils.encodeValue(NULL), 'null') - self.assertEqual(QgsJsonUtils.encodeValue(5), '5') - self.assertEqual(QgsJsonUtils.encodeValue(5.9), '5.9') - self.assertEqual(QgsJsonUtils.encodeValue(5999999999), '5999999999') - self.assertEqual(QgsJsonUtils.encodeValue('string'), '"string"') - self.assertEqual(QgsJsonUtils.encodeValue('str\ning'), '"str\\ning"') - self.assertEqual(QgsJsonUtils.encodeValue('str\ring'), '"str\\ring"') - self.assertEqual(QgsJsonUtils.encodeValue('str\bing'), '"str\\bing"') - self.assertEqual(QgsJsonUtils.encodeValue('str\ting'), '"str\\ting"') - self.assertEqual(QgsJsonUtils.encodeValue('str\\ing'), '"str\\\\ing"') - self.assertEqual(QgsJsonUtils.encodeValue('str\\ning'), '"str\\\\ning"') - self.assertEqual(QgsJsonUtils.encodeValue('str\n\\\\ing'), '"str\\n\\\\\\\\ing"') - self.assertEqual(QgsJsonUtils.encodeValue('str/ing'), '"str\\/ing"') - self.assertEqual(QgsJsonUtils.encodeValue([5, 6]), '[5,6]') - self.assertEqual(QgsJsonUtils.encodeValue(['a', 'b', 'c']), '["a","b","c"]') - self.assertEqual(QgsJsonUtils.encodeValue(['a', 3, 'c']), '["a",3,"c"]') - self.assertEqual(QgsJsonUtils.encodeValue(['a', 'c\nd']), '["a","c\\nd"]') + """test encoding various values for use in GeoJSON strings""" + self.assertEqual(QgsJsonUtils.encodeValue(NULL), "null") + self.assertEqual(QgsJsonUtils.encodeValue(5), "5") + self.assertEqual(QgsJsonUtils.encodeValue(5.9), "5.9") + self.assertEqual(QgsJsonUtils.encodeValue(5999999999), "5999999999") + self.assertEqual(QgsJsonUtils.encodeValue("string"), '"string"') + self.assertEqual(QgsJsonUtils.encodeValue("str\ning"), '"str\\ning"') + self.assertEqual(QgsJsonUtils.encodeValue("str\ring"), '"str\\ring"') + self.assertEqual(QgsJsonUtils.encodeValue("str\bing"), '"str\\bing"') + self.assertEqual(QgsJsonUtils.encodeValue("str\ting"), '"str\\ting"') + self.assertEqual(QgsJsonUtils.encodeValue("str\\ing"), '"str\\\\ing"') + self.assertEqual(QgsJsonUtils.encodeValue("str\\ning"), '"str\\\\ning"') + self.assertEqual( + QgsJsonUtils.encodeValue("str\n\\\\ing"), '"str\\n\\\\\\\\ing"' + ) + self.assertEqual(QgsJsonUtils.encodeValue("str/ing"), '"str\\/ing"') + self.assertEqual(QgsJsonUtils.encodeValue([5, 6]), "[5,6]") + self.assertEqual(QgsJsonUtils.encodeValue(["a", "b", "c"]), '["a","b","c"]') + self.assertEqual(QgsJsonUtils.encodeValue(["a", 3, "c"]), '["a",3,"c"]') + self.assertEqual(QgsJsonUtils.encodeValue(["a", "c\nd"]), '["a","c\\nd"]') # handle differences due to Qt5 version, where compact output now lacks \n - enc_str = QgsJsonUtils.encodeValue({'key': 'value', 'key2': 5}) - self.assertTrue(enc_str == '{"key":"value",\n"key2":5}' or enc_str == '{"key":"value","key2":5}') - enc_str = QgsJsonUtils.encodeValue({'key': [1, 2, 3], 'key2': {'nested': 'nested\\result'}}) + enc_str = QgsJsonUtils.encodeValue({"key": "value", "key2": 5}) + self.assertTrue( + enc_str == '{"key":"value",\n"key2":5}' + or enc_str == '{"key":"value","key2":5}' + ) + enc_str = QgsJsonUtils.encodeValue( + {"key": [1, 2, 3], "key2": {"nested": "nested\\result"}} + ) self.assertTrue( - enc_str == '{"key":[1,2,3],\n"key2":{"nested":"nested\\\\result"}}' or enc_str == '{"key":[1,2,3],"key2":{"nested":"nested\\\\result"}}') + enc_str == '{"key":[1,2,3],\n"key2":{"nested":"nested\\\\result"}}' + or enc_str == '{"key":[1,2,3],"key2":{"nested":"nested\\\\result"}}' + ) def testExportAttributes(self): - """ test exporting feature's attributes to JSON object """ + """test exporting feature's attributes to JSON object""" fields = QgsFields() # test empty attributes @@ -213,7 +253,7 @@ def testExportAttributes(self): feature = QgsFeature(fields, 5) feature.setGeometry(QgsGeometry(QgsPoint(5, 6))) - feature.setAttributes(['Valsier Peninsula', 6.8, 198]) + feature.setAttributes(["Valsier Peninsula", 6.8, 198]) expected = """{"name":"Valsier Peninsula", "cost":6.8, @@ -221,13 +261,16 @@ def testExportAttributes(self): self.assertEqual(QgsJsonUtils.exportAttributes(feature), expected) # test using field formatters - source = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "parent", "memory") + source = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "parent", "memory" + ) pf1 = QgsFeature() pf1.setFields(source.fields()) pf1.setAttributes(["test1", 1]) - setup = QgsEditorWidgetSetup('ValueMap', {"map": {"one": 1, "two": 2, "three": 3}}) + setup = QgsEditorWidgetSetup( + "ValueMap", {"map": {"one": 1, "two": 2, "three": 3}} + ) source.setEditorWidgetSetup(1, setup) expected = """{"fldtxt":"test1", @@ -235,7 +278,7 @@ def testExportAttributes(self): self.assertEqual(QgsJsonUtils.exportAttributes(pf1, source), expected) def testJSONExporter(self): - """ test converting features to GeoJSON """ + """test converting features to GeoJSON""" fields = QgsFields() fields.append(QgsField("name", QVariant.String)) fields.append(QgsField("cost", QVariant.Double)) @@ -243,7 +286,7 @@ def testJSONExporter(self): feature = QgsFeature(fields, 5) feature.setGeometry(QgsGeometry(QgsPoint(5, 6))) - feature.setAttributes(['Valsier Peninsula', 6.8, 198]) + feature.setAttributes(["Valsier Peninsula", 6.8, 198]) exporter = QgsJsonExporter() @@ -511,7 +554,9 @@ def testJSONExporter(self): }, "type": "Feature" }""" - self.assertEqual(exporter.exportFeature(feature, id="mylayer.29", indent=2), expected) + self.assertEqual( + exporter.exportFeature(feature, id="mylayer.29", indent=2), expected + ) # test injecting extra attributes expected = """{ @@ -526,8 +571,12 @@ def testJSONExporter(self): }, "type": "Feature" }""" - self.assertEqual(exporter.exportFeature(feature, extraProperties={"extra": "val1", "extra2": 2}, indent=2), - expected) + self.assertEqual( + exporter.exportFeature( + feature, extraProperties={"extra": "val1", "extra2": 2}, indent=2 + ), + expected, + ) exporter.setIncludeAttributes(False) expected = """{ @@ -548,18 +597,25 @@ def testJSONExporter(self): "type": "Feature" }""" - exp_f = exporter.exportFeature(feature, extraProperties={"extra": "val1", - "extra2": {"nested_map": 5, "nested_map2": "val"}, - "extra3": [1, 2, 3]}, indent=2) + exp_f = exporter.exportFeature( + feature, + extraProperties={ + "extra": "val1", + "extra2": {"nested_map": 5, "nested_map2": "val"}, + "extra3": [1, 2, 3], + }, + indent=2, + ) self.assertEqual(exp_f, expected) exporter.setIncludeGeometry(True) def testExportFeatureFieldFormatter(self): - """ Test exporting a feature with formatting fields """ + """Test exporting a feature with formatting fields""" # source layer - source = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "parent", "memory") + source = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "parent", "memory" + ) pr = source.dataProvider() pf1 = QgsFeature(123) pf1.setFields(source.fields()) @@ -569,7 +625,9 @@ def testExportFeatureFieldFormatter(self): pf2.setAttributes(["test2", 2]) assert pr.addFeatures([pf1, pf2]) - setup = QgsEditorWidgetSetup('ValueMap', {"map": {"one": 1, "two": 2, "three": 3}}) + setup = QgsEditorWidgetSetup( + "ValueMap", {"map": {"one": 1, "two": 2, "three": 3}} + ) source.setEditorWidgetSetup(1, setup) exporter = QgsJsonExporter() @@ -587,30 +645,31 @@ def testExportFeatureFieldFormatter(self): self.assertEqual(exporter.exportFeature(pf1, indent=2), expected) def testExportFeatureCrs(self): - """ Test CRS transform when exporting features """ + """Test CRS transform when exporting features""" exporter = QgsJsonExporter() self.assertFalse(exporter.sourceCrs().isValid()) # test layer - layer = QgsVectorLayer("Point?crs=epsg:3111&field=fldtxt:string", - "parent", "memory") + layer = QgsVectorLayer( + "Point?crs=epsg:3111&field=fldtxt:string", "parent", "memory" + ) exporter = QgsJsonExporter(layer) self.assertTrue(exporter.sourceCrs().isValid()) - self.assertEqual(exporter.sourceCrs().authid(), 'EPSG:3111') + self.assertEqual(exporter.sourceCrs().authid(), "EPSG:3111") - exporter.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + exporter.setSourceCrs(QgsCoordinateReferenceSystem("EPSG:3857")) self.assertTrue(exporter.sourceCrs().isValid()) - self.assertEqual(exporter.sourceCrs().authid(), 'EPSG:3857') + self.assertEqual(exporter.sourceCrs().authid(), "EPSG:3857") # vector layer CRS should override exporter.setVectorLayer(layer) - self.assertEqual(exporter.sourceCrs().authid(), 'EPSG:3111') + self.assertEqual(exporter.sourceCrs().authid(), "EPSG:3111") # test that exported feature is reprojected feature = QgsFeature(layer.fields(), 5) feature.setGeometry(QgsGeometry(QgsPoint(2502577, 2403869))) - feature.setAttributes(['test point']) + feature.setAttributes(["test point"]) # low precision, only need rough coordinate to check and don't want to deal with rounding errors exporter.setPrecision(1) @@ -631,11 +690,14 @@ def testExportFeatureCrs(self): self.assertEqual(exporter.exportFeature(feature, indent=2), expected) def testExportFeatureRelations(self): - """ Test exporting a feature with relations """ + """Test exporting a feature with relations""" # parent layer - parent = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=foreignkey:integer", - "parent", "memory") + parent = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer&field=foreignkey:integer", + "parent", + "memory", + ) pr = parent.dataProvider() pf1 = QgsFeature(432) pf1.setFields(parent.fields()) @@ -648,7 +710,9 @@ def testExportFeatureRelations(self): # child layer child = QgsVectorLayer( "Point?field=x:string&field=y:integer&field=z:integer", - "referencedlayer", "memory") + "referencedlayer", + "memory", + ) pr = child.dataProvider() f1 = QgsFeature() f1.setFields(child.fields()) @@ -664,11 +728,11 @@ def testExportFeatureRelations(self): QgsProject.instance().addMapLayers([child, parent]) rel = QgsRelation() - rel.setId('rel1') - rel.setName('relation one') + rel.setId("rel1") + rel.setName("relation one") rel.setReferencingLayer(child.id()) rel.setReferencedLayer(parent.id()) - rel.addFieldPair('y', 'foreignkey') + rel.addFieldPair("y", "foreignkey") QgsProject.instance().relationManager().addRelation(rel) @@ -724,9 +788,13 @@ def testExportFeatureRelations(self): self.assertEqual(exporter.exportFeature(pf2, indent=2), expected) # with field formatter - setup = QgsEditorWidgetSetup('ValueMap', {"map": {"apples": 123, "bananas": 124}}) + setup = QgsEditorWidgetSetup( + "ValueMap", {"map": {"apples": 123, "bananas": 124}} + ) child.setEditorWidgetSetup(1, setup) - parent.setEditorWidgetSetup(1, QgsEditorWidgetSetup('ValueMap', {"map": {"sixty-seven": 67}})) + parent.setEditorWidgetSetup( + 1, QgsEditorWidgetSetup("ValueMap", {"map": {"sixty-seven": 67}}) + ) expected = """{ "geometry": null, "id": 432, @@ -814,7 +882,7 @@ def testExportFeatureRelations(self): self.assertEqual(exporter.exportFeature(pf2, indent=2), expected) def testExportFeatures(self): - """ Test exporting feature collections """ + """Test exporting feature collections""" fields = QgsFields() fields.append(QgsField("name", QVariant.String)) @@ -823,7 +891,7 @@ def testExportFeatures(self): feature = QgsFeature(fields, 5) feature.setGeometry(QgsGeometry(QgsPoint(5, 6))) - feature.setAttributes(['Valsier Peninsula', 6.8, 198]) + feature.setAttributes(["Valsier Peninsula", 6.8, 198]) exporter = QgsJsonExporter() @@ -854,7 +922,7 @@ def testExportFeatures(self): # multiple features feature2 = QgsFeature(fields, 6) feature2.setGeometry(QgsGeometry(QgsPoint(7, 8))) - feature2.setAttributes(['Henry Gale Island', 9.7, 38]) + feature2.setAttributes(["Henry Gale Island", 9.7, 38]) expected = """{ "features": [ @@ -896,18 +964,21 @@ def testExportFeatures(self): self.assertEqual(exporter.exportFeatures([feature, feature2], 2), expected) def testExportFeaturesWithLocale_regression20053(self): - """ Test exporting feature export with range widgets and locale different than C + """Test exporting feature export with range widgets and locale different than C Regression: https://github.com/qgis/QGIS/issues/27875 - decimal separator in csv files """ - source = QgsVectorLayer("Point?field=name:string&field=cost:double&field=population:int&field=date:date", - "parent", "memory") + source = QgsVectorLayer( + "Point?field=name:string&field=cost:double&field=population:int&field=date:date", + "parent", + "memory", + ) self.assertTrue(source.isValid()) fields = source.fields() feature = QgsFeature(fields, 5) feature.setGeometry(QgsGeometry(QgsPoint(5, 6))) - feature.setAttributes(['Valsier Peninsula', 6.8, 198000, '2018-09-10']) + feature.setAttributes(["Valsier Peninsula", 6.8, 198000, "2018-09-10"]) exporter = QgsJsonExporter() @@ -936,28 +1007,31 @@ def testExportFeaturesWithLocale_regression20053(self): }""" self.assertEqual(exporter.exportFeatures([feature], 2), expected) - setup = QgsEditorWidgetSetup('Range', { - 'AllowNull': True, - 'Max': 2147483647, - 'Min': -2147483648, - 'Precision': 4, - 'Step': 1, - 'Style': 'SpinBox' - } + setup = QgsEditorWidgetSetup( + "Range", + { + "AllowNull": True, + "Max": 2147483647, + "Min": -2147483648, + "Precision": 4, + "Step": 1, + "Style": "SpinBox", + }, ) source.setEditorWidgetSetup(1, setup) source.setEditorWidgetSetup(2, setup) - QLocale.setDefault(QLocale('it')) + QLocale.setDefault(QLocale("it")) exporter.setVectorLayer(source) self.assertEqual(exporter.exportFeatures([feature], 2), expected) def testExportFieldAlias(self): - """ Test exporting a feature with fields' alias """ + """Test exporting a feature with fields' alias""" # source layer - source = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "parent", "memory") + source = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "parent", "memory" + ) pr = source.dataProvider() pf1 = QgsFeature() pf1.setFields(source.fields()) diff --git a/tests/src/python/test_qgslabelingenginerule.py b/tests/src/python/test_qgslabelingenginerule.py index 1ee5363722b5..f568a33a625f 100644 --- a/tests/src/python/test_qgslabelingenginerule.py +++ b/tests/src/python/test_qgslabelingenginerule.py @@ -5,6 +5,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + import os import tempfile @@ -22,7 +23,7 @@ QgsVectorLayer, QgsMapUnitScale, QgsReadWriteContext, - QgsLabelingEngineSettings + QgsLabelingEngineSettings, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -33,10 +34,10 @@ class TestRule(QgsAbstractLabelingEngineRule): def id(self): - return 'test' + return "test" def displayType(self): - return 'my type' + return "my type" def prepare(self, context): pass @@ -62,33 +63,33 @@ def testRegistry(self): for rule_id in registry.ruleIds(): self.assertEqual(registry.create(rule_id).id(), rule_id) - self.assertIsNone(registry.create('bad')) - self.assertFalse(registry.displayType('bad')) + self.assertIsNone(registry.create("bad")) + self.assertFalse(registry.displayType("bad")) - self.assertIn('minimumDistanceLabelToFeature', registry.ruleIds()) + self.assertIn("minimumDistanceLabelToFeature", registry.ruleIds()) self.assertFalse(registry.addRule(None)) self.assertTrue(registry.addRule(TestRule())) - self.assertIn('test', registry.ruleIds()) - self.assertIsInstance(registry.create('test'), TestRule) - self.assertEqual(registry.displayType('test'), 'my type') + self.assertIn("test", registry.ruleIds()) + self.assertIsInstance(registry.create("test"), TestRule) + self.assertEqual(registry.displayType("test"), "my type") # no duplicates self.assertFalse(registry.addRule(TestRule())) - registry.removeRule('test') + registry.removeRule("test") - self.assertNotIn('test', registry.ruleIds()) - self.assertIsNone(registry.create('test')) + self.assertNotIn("test", registry.ruleIds()) + self.assertIsNone(registry.create("test")) - registry.removeRule('test') + registry.removeRule("test") def testMinimumDistanceLabelToFeature(self): p = QgsProject() - vl = QgsVectorLayer('Point', 'layer 1', 'memory') - vl2 = QgsVectorLayer('Point', 'layer 2', 'memory') + vl = QgsVectorLayer("Point", "layer 1", "memory") + vl2 = QgsVectorLayer("Point", "layer 2", "memory") p.addMapLayers([vl, vl2]) rule = QgsLabelingEngineRuleMinimumDistanceLabelToFeature() @@ -98,9 +99,12 @@ def testMinimumDistanceLabelToFeature(self): rule.setDistanceUnit(Qgis.RenderUnit.Inches) rule.setDistanceUnitScale(QgsMapUnitScale(15, 25)) rule.setCost(6.6) - rule.setName('my rule') + rule.setName("my rule") rule.setActive(False) - self.assertEqual(rule.__repr__(), '') + self.assertEqual( + rule.__repr__(), + "", + ) self.assertEqual(rule.labeledLayer(), vl) self.assertEqual(rule.targetLayer(), vl2) @@ -109,7 +113,7 @@ def testMinimumDistanceLabelToFeature(self): self.assertEqual(rule.distanceUnitScale().minScale, 15) self.assertEqual(rule.distanceUnitScale().maxScale, 25) self.assertEqual(rule.cost(), 6.6) - self.assertEqual(rule.name(), 'my rule') + self.assertEqual(rule.name(), "my rule") self.assertFalse(rule.active()) rule2 = rule.clone() @@ -120,7 +124,7 @@ def testMinimumDistanceLabelToFeature(self): self.assertEqual(rule2.distanceUnitScale().minScale, 15) self.assertEqual(rule2.distanceUnitScale().maxScale, 25) self.assertEqual(rule2.cost(), 6.6) - self.assertEqual(rule2.name(), 'my rule') + self.assertEqual(rule2.name(), "my rule") self.assertFalse(rule2.active()) doc = QDomDocument("testdoc") @@ -140,8 +144,8 @@ def testMinimumDistanceLabelToFeature(self): def testMinimumDistanceLabelToLabel(self): p = QgsProject() - vl = QgsVectorLayer('Point', 'layer 1', 'memory') - vl2 = QgsVectorLayer('Point', 'layer 2', 'memory') + vl = QgsVectorLayer("Point", "layer 1", "memory") + vl2 = QgsVectorLayer("Point", "layer 2", "memory") p.addMapLayers([vl, vl2]) rule = QgsLabelingEngineRuleMinimumDistanceLabelToLabel() @@ -150,8 +154,11 @@ def testMinimumDistanceLabelToLabel(self): rule.setDistance(14) rule.setDistanceUnit(Qgis.RenderUnit.Inches) rule.setDistanceUnitScale(QgsMapUnitScale(15, 25)) - rule.setName('my rule') - self.assertEqual(rule.__repr__(), '') + rule.setName("my rule") + self.assertEqual( + rule.__repr__(), + "", + ) self.assertEqual(rule.labeledLayer(), vl) self.assertEqual(rule.targetLayer(), vl2) @@ -159,7 +166,7 @@ def testMinimumDistanceLabelToLabel(self): self.assertEqual(rule.distanceUnit(), Qgis.RenderUnit.Inches) self.assertEqual(rule.distanceUnitScale().minScale, 15) self.assertEqual(rule.distanceUnitScale().maxScale, 25) - self.assertEqual(rule.name(), 'my rule') + self.assertEqual(rule.name(), "my rule") self.assertTrue(rule.active()) rule2 = rule.clone() @@ -169,7 +176,7 @@ def testMinimumDistanceLabelToLabel(self): self.assertEqual(rule2.distanceUnit(), Qgis.RenderUnit.Inches) self.assertEqual(rule2.distanceUnitScale().minScale, 15) self.assertEqual(rule2.distanceUnitScale().maxScale, 25) - self.assertEqual(rule2.name(), 'my rule') + self.assertEqual(rule2.name(), "my rule") self.assertTrue(rule2.active()) doc = QDomDocument("testdoc") @@ -188,8 +195,8 @@ def testMinimumDistanceLabelToLabel(self): def testMaximumDistanceLabelToFeature(self): p = QgsProject() - vl = QgsVectorLayer('Point', 'layer 1', 'memory') - vl2 = QgsVectorLayer('Point', 'layer 2', 'memory') + vl = QgsVectorLayer("Point", "layer 1", "memory") + vl2 = QgsVectorLayer("Point", "layer 2", "memory") p.addMapLayers([vl, vl2]) rule = QgsLabelingEngineRuleMaximumDistanceLabelToFeature() @@ -199,8 +206,11 @@ def testMaximumDistanceLabelToFeature(self): rule.setDistanceUnit(Qgis.RenderUnit.Inches) rule.setDistanceUnitScale(QgsMapUnitScale(15, 25)) rule.setCost(6.6) - rule.setName('my rule') - self.assertEqual(rule.__repr__(), '') + rule.setName("my rule") + self.assertEqual( + rule.__repr__(), + "", + ) self.assertEqual(rule.labeledLayer(), vl) self.assertEqual(rule.targetLayer(), vl2) @@ -209,7 +219,7 @@ def testMaximumDistanceLabelToFeature(self): self.assertEqual(rule.distanceUnitScale().minScale, 15) self.assertEqual(rule.distanceUnitScale().maxScale, 25) self.assertEqual(rule.cost(), 6.6) - self.assertEqual(rule.name(), 'my rule') + self.assertEqual(rule.name(), "my rule") rule2 = rule.clone() self.assertEqual(rule2.labeledLayer(), vl) @@ -219,7 +229,7 @@ def testMaximumDistanceLabelToFeature(self): self.assertEqual(rule2.distanceUnitScale().minScale, 15) self.assertEqual(rule2.distanceUnitScale().maxScale, 25) self.assertEqual(rule2.cost(), 6.6) - self.assertEqual(rule2.name(), 'my rule') + self.assertEqual(rule2.name(), "my rule") doc = QDomDocument("testdoc") elem = doc.createElement("test") @@ -238,24 +248,27 @@ def testMaximumDistanceLabelToFeature(self): def testAvoidLabelOverlapWithFeature(self): p = QgsProject() - vl = QgsVectorLayer('Point', 'layer 1', 'memory') - vl2 = QgsVectorLayer('Point', 'layer 2', 'memory') + vl = QgsVectorLayer("Point", "layer 1", "memory") + vl2 = QgsVectorLayer("Point", "layer 2", "memory") p.addMapLayers([vl, vl2]) rule = QgsLabelingEngineRuleAvoidLabelOverlapWithFeature() rule.setLabeledLayer(vl) rule.setTargetLayer(vl2) - rule.setName('my rule') - self.assertEqual(rule.__repr__(), '') + rule.setName("my rule") + self.assertEqual( + rule.__repr__(), + "", + ) self.assertEqual(rule.labeledLayer(), vl) self.assertEqual(rule.targetLayer(), vl2) - self.assertEqual(rule.name(), 'my rule') + self.assertEqual(rule.name(), "my rule") rule2 = rule.clone() self.assertEqual(rule2.labeledLayer(), vl) self.assertEqual(rule2.targetLayer(), vl2) - self.assertEqual(rule2.name(), 'my rule') + self.assertEqual(rule2.name(), "my rule") doc = QDomDocument("testdoc") elem = doc.createElement("test") @@ -272,8 +285,8 @@ def test_settings(self): Test attaching rules to QgsLabelingEngineSettings """ p = QgsProject() - vl = QgsVectorLayer('Point', 'layer 1', 'memory') - vl2 = QgsVectorLayer('Point', 'layer 2', 'memory') + vl = QgsVectorLayer("Point", "layer 1", "memory") + vl2 = QgsVectorLayer("Point", "layer 2", "memory") p.addMapLayers([vl, vl2]) self.assertFalse(p.labelingEngineSettings().rules()) @@ -282,61 +295,76 @@ def test_settings(self): rule.setLabeledLayer(vl) rule.setTargetLayer(vl2) rule.setCost(6.6) - rule.setName('first rule') + rule.setName("first rule") label_engine_settings = p.labelingEngineSettings() label_engine_settings.addRule(rule) - self.assertEqual([r.id() for r in label_engine_settings.rules()], ['maximumDistanceLabelToFeature']) + self.assertEqual( + [r.id() for r in label_engine_settings.rules()], + ["maximumDistanceLabelToFeature"], + ) rule2 = QgsLabelingEngineRuleAvoidLabelOverlapWithFeature() rule2.setLabeledLayer(vl2) rule2.setTargetLayer(vl) - rule2.setName('the second rule of labeling') + rule2.setName("the second rule of labeling") rule2.setActive(False) label_engine_settings.addRule(rule2) - self.assertEqual([r.id() for r in label_engine_settings.rules()], ['maximumDistanceLabelToFeature', 'avoidLabelOverlapWithFeature']) + self.assertEqual( + [r.id() for r in label_engine_settings.rules()], + ["maximumDistanceLabelToFeature", "avoidLabelOverlapWithFeature"], + ) p.setLabelingEngineSettings(label_engine_settings) label_engine_settings = p.labelingEngineSettings() - self.assertEqual([r.id() for r in label_engine_settings.rules()], - ['maximumDistanceLabelToFeature', - 'avoidLabelOverlapWithFeature']) - self.assertEqual([r.name() for r in label_engine_settings.rules()], - ['first rule', - 'the second rule of labeling']) - self.assertEqual([r.active() for r in label_engine_settings.rules()], - [True, False]) + self.assertEqual( + [r.id() for r in label_engine_settings.rules()], + ["maximumDistanceLabelToFeature", "avoidLabelOverlapWithFeature"], + ) + self.assertEqual( + [r.name() for r in label_engine_settings.rules()], + ["first rule", "the second rule of labeling"], + ) + self.assertEqual( + [r.active() for r in label_engine_settings.rules()], [True, False] + ) # save, restore project with tempfile.TemporaryDirectory() as temp_dir: - self.assertTrue(p.write(os.path.join(temp_dir, 'p.qgs'))) + self.assertTrue(p.write(os.path.join(temp_dir, "p.qgs"))) p2 = QgsProject() - self.assertTrue(p2.read(os.path.join(temp_dir, 'p.qgs'))) + self.assertTrue(p2.read(os.path.join(temp_dir, "p.qgs"))) label_engine_settings = p2.labelingEngineSettings() - self.assertEqual([r.id() for r in label_engine_settings.rules()], - ['maximumDistanceLabelToFeature', - 'avoidLabelOverlapWithFeature']) - self.assertEqual([r.name() for r in label_engine_settings.rules()], - ['first rule', - 'the second rule of labeling']) self.assertEqual( - [r.active() for r in label_engine_settings.rules()], - [True, False]) + [r.id() for r in label_engine_settings.rules()], + ["maximumDistanceLabelToFeature", "avoidLabelOverlapWithFeature"], + ) + self.assertEqual( + [r.name() for r in label_engine_settings.rules()], + ["first rule", "the second rule of labeling"], + ) + self.assertEqual( + [r.active() for r in label_engine_settings.rules()], [True, False] + ) # check layers, settings rule1 = label_engine_settings.rules()[0] - self.assertIsInstance(rule1, QgsLabelingEngineRuleMaximumDistanceLabelToFeature) + self.assertIsInstance( + rule1, QgsLabelingEngineRuleMaximumDistanceLabelToFeature + ) self.assertEqual(rule1.cost(), 6.6) - self.assertEqual(rule1.labeledLayer().name(), 'layer 1') - self.assertEqual(rule1.targetLayer().name(), 'layer 2') + self.assertEqual(rule1.labeledLayer().name(), "layer 1") + self.assertEqual(rule1.targetLayer().name(), "layer 2") rule2 = label_engine_settings.rules()[1] - self.assertIsInstance(rule2, QgsLabelingEngineRuleAvoidLabelOverlapWithFeature) - self.assertEqual(rule2.labeledLayer().name(), 'layer 2') - self.assertEqual(rule2.targetLayer().name(), 'layer 1') + self.assertIsInstance( + rule2, QgsLabelingEngineRuleAvoidLabelOverlapWithFeature + ) + self.assertEqual(rule2.labeledLayer().name(), "layer 2") + self.assertEqual(rule2.targetLayer().name(), "layer 1") # test setRules rule = QgsLabelingEngineRuleMinimumDistanceLabelToFeature() @@ -345,9 +373,11 @@ def test_settings(self): rule.setCost(6.6) label_engine_settings.setRules([rule]) - self.assertEqual([r.id() for r in label_engine_settings.rules()], - ['minimumDistanceLabelToFeature']) + self.assertEqual( + [r.id() for r in label_engine_settings.rules()], + ["minimumDistanceLabelToFeature"], + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslabellinesettings.py b/tests/src/python/test_qgslabellinesettings.py index c2ecb027f0a2..07629031aa97 100644 --- a/tests/src/python/test_qgslabellinesettings.py +++ b/tests/src/python/test_qgslabellinesettings.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2019-12-07' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2019-12-07" +__copyright__ = "Copyright 2019, The QGIS Project" import os @@ -36,9 +37,18 @@ def test_line_settings(self): """ settings = QgsLabelLineSettings() settings.setPlacementFlags(QgsLabeling.LinePlacementFlag.OnLine) - self.assertEqual(settings.placementFlags(), QgsLabeling.LinePlacementFlag.OnLine) - settings.setPlacementFlags(QgsLabeling.LinePlacementFlag.OnLine | QgsLabeling.LinePlacementFlag.MapOrientation) - self.assertEqual(settings.placementFlags(), QgsLabeling.LinePlacementFlag.OnLine | QgsLabeling.LinePlacementFlag.MapOrientation) + self.assertEqual( + settings.placementFlags(), QgsLabeling.LinePlacementFlag.OnLine + ) + settings.setPlacementFlags( + QgsLabeling.LinePlacementFlag.OnLine + | QgsLabeling.LinePlacementFlag.MapOrientation + ) + self.assertEqual( + settings.placementFlags(), + QgsLabeling.LinePlacementFlag.OnLine + | QgsLabeling.LinePlacementFlag.MapOrientation, + ) settings.setMergeLines(True) self.assertTrue(settings.mergeLines()) @@ -49,24 +59,36 @@ def test_line_settings(self): self.assertTrue(settings.addDirectionSymbol()) settings.setAddDirectionSymbol(False) self.assertFalse(settings.addDirectionSymbol()) - settings.setLeftDirectionSymbol('left') - self.assertEqual(settings.leftDirectionSymbol(), 'left') - settings.setRightDirectionSymbol('right') - self.assertEqual(settings.rightDirectionSymbol(), 'right') + settings.setLeftDirectionSymbol("left") + self.assertEqual(settings.leftDirectionSymbol(), "left") + settings.setRightDirectionSymbol("right") + self.assertEqual(settings.rightDirectionSymbol(), "right") settings.setReverseDirectionSymbol(True) self.assertTrue(settings.reverseDirectionSymbol()) settings.setReverseDirectionSymbol(False) self.assertFalse(settings.reverseDirectionSymbol()) - settings.setDirectionSymbolPlacement(QgsLabelLineSettings.DirectionSymbolPlacement.SymbolBelow) - self.assertEqual(settings.directionSymbolPlacement(), QgsLabelLineSettings.DirectionSymbolPlacement.SymbolBelow) - settings.setDirectionSymbolPlacement(QgsLabelLineSettings.DirectionSymbolPlacement.SymbolAbove) - self.assertEqual(settings.directionSymbolPlacement(), QgsLabelLineSettings.DirectionSymbolPlacement.SymbolAbove) + settings.setDirectionSymbolPlacement( + QgsLabelLineSettings.DirectionSymbolPlacement.SymbolBelow + ) + self.assertEqual( + settings.directionSymbolPlacement(), + QgsLabelLineSettings.DirectionSymbolPlacement.SymbolBelow, + ) + settings.setDirectionSymbolPlacement( + QgsLabelLineSettings.DirectionSymbolPlacement.SymbolAbove + ) + self.assertEqual( + settings.directionSymbolPlacement(), + QgsLabelLineSettings.DirectionSymbolPlacement.SymbolAbove, + ) settings.setOverrunDistance(5.6) self.assertEqual(settings.overrunDistance(), 5.6) settings.setOverrunDistanceUnit(QgsUnitTypes.RenderUnit.RenderInches) - self.assertEqual(settings.overrunDistanceUnit(), QgsUnitTypes.RenderUnit.RenderInches) + self.assertEqual( + settings.overrunDistanceUnit(), QgsUnitTypes.RenderUnit.RenderInches + ) scale = QgsMapUnitScale(1, 2) settings.setOverrunDistanceMapUnitScale(scale) self.assertEqual(settings.overrunDistanceMapUnitScale().minScale, 1) @@ -77,9 +99,20 @@ def test_line_settings(self): # check that compatibility code works pal_settings = QgsPalLayerSettings() - pal_settings.placementFlags = QgsPalLayerSettings.LinePlacementFlags.OnLine | QgsPalLayerSettings.LinePlacementFlags.MapOrientation - self.assertEqual(pal_settings.placementFlags, QgsPalLayerSettings.LinePlacementFlags.OnLine | QgsPalLayerSettings.LinePlacementFlags.MapOrientation) - self.assertEqual(pal_settings.lineSettings().placementFlags(), QgsLabeling.LinePlacementFlag.OnLine | QgsLabeling.LinePlacementFlag.MapOrientation) + pal_settings.placementFlags = ( + QgsPalLayerSettings.LinePlacementFlags.OnLine + | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + ) + self.assertEqual( + pal_settings.placementFlags, + QgsPalLayerSettings.LinePlacementFlags.OnLine + | QgsPalLayerSettings.LinePlacementFlags.MapOrientation, + ) + self.assertEqual( + pal_settings.lineSettings().placementFlags(), + QgsLabeling.LinePlacementFlag.OnLine + | QgsLabeling.LinePlacementFlag.MapOrientation, + ) pal_settings.mergeLines = True self.assertTrue(pal_settings.mergeLines) @@ -95,12 +128,12 @@ def test_line_settings(self): self.assertFalse(pal_settings.addDirectionSymbol) self.assertFalse(pal_settings.lineSettings().addDirectionSymbol()) - pal_settings.leftDirectionSymbol = 'l' - self.assertEqual(pal_settings.leftDirectionSymbol, 'l') - self.assertEqual(pal_settings.lineSettings().leftDirectionSymbol(), 'l') - pal_settings.rightDirectionSymbol = 'r' - self.assertEqual(pal_settings.rightDirectionSymbol, 'r') - self.assertEqual(pal_settings.lineSettings().rightDirectionSymbol(), 'r') + pal_settings.leftDirectionSymbol = "l" + self.assertEqual(pal_settings.leftDirectionSymbol, "l") + self.assertEqual(pal_settings.lineSettings().leftDirectionSymbol(), "l") + pal_settings.rightDirectionSymbol = "r" + self.assertEqual(pal_settings.rightDirectionSymbol, "r") + self.assertEqual(pal_settings.lineSettings().rightDirectionSymbol(), "r") pal_settings.reverseDirectionSymbol = True self.assertTrue(pal_settings.reverseDirectionSymbol) @@ -109,47 +142,74 @@ def test_line_settings(self): self.assertFalse(pal_settings.reverseDirectionSymbol) self.assertFalse(pal_settings.lineSettings().reverseDirectionSymbol()) - pal_settings.placeDirectionSymbol = QgsPalLayerSettings.DirectionSymbols.SymbolAbove + pal_settings.placeDirectionSymbol = ( + QgsPalLayerSettings.DirectionSymbols.SymbolAbove + ) self.assertEqual(pal_settings.placeDirectionSymbol, 1) - self.assertEqual(pal_settings.lineSettings().directionSymbolPlacement(), QgsLabelLineSettings.DirectionSymbolPlacement.SymbolAbove) + self.assertEqual( + pal_settings.lineSettings().directionSymbolPlacement(), + QgsLabelLineSettings.DirectionSymbolPlacement.SymbolAbove, + ) pal_settings.overrunDistance = 4.2 self.assertEqual(pal_settings.overrunDistance, 4.2) self.assertEqual(pal_settings.lineSettings().overrunDistance(), 4.2) pal_settings.overrunDistanceUnit = QgsUnitTypes.RenderUnit.RenderInches - self.assertEqual(pal_settings.overrunDistanceUnit, QgsUnitTypes.RenderUnit.RenderInches) - self.assertEqual(pal_settings.lineSettings().overrunDistanceUnit(), QgsUnitTypes.RenderUnit.RenderInches) + self.assertEqual( + pal_settings.overrunDistanceUnit, QgsUnitTypes.RenderUnit.RenderInches + ) + self.assertEqual( + pal_settings.lineSettings().overrunDistanceUnit(), + QgsUnitTypes.RenderUnit.RenderInches, + ) pal_settings.overrunDistanceMapUnitScale = scale self.assertEqual(pal_settings.overrunDistanceMapUnitScale.minScale, 1) self.assertEqual(pal_settings.overrunDistanceMapUnitScale.maxScale, 2) - self.assertEqual(pal_settings.lineSettings().overrunDistanceMapUnitScale().minScale, 1) - self.assertEqual(pal_settings.lineSettings().overrunDistanceMapUnitScale().maxScale, 2) + self.assertEqual( + pal_settings.lineSettings().overrunDistanceMapUnitScale().minScale, 1 + ) + self.assertEqual( + pal_settings.lineSettings().overrunDistanceMapUnitScale().maxScale, 2 + ) def testUpdateDataDefinedProps(self): settings = QgsLabelLineSettings() settings.setPlacementFlags(QgsLabeling.LinePlacementFlag.OnLine) settings.setOverrunDistance(5.6) settings.setLineAnchorPercent(0.3) - self.assertEqual(settings.placementFlags(), QgsLabeling.LinePlacementFlag.OnLine) + self.assertEqual( + settings.placementFlags(), QgsLabeling.LinePlacementFlag.OnLine + ) self.assertEqual(settings.overrunDistance(), 5.6) self.assertEqual(settings.lineAnchorPercent(), 0.3) props = QgsPropertyCollection() - props.setProperty(QgsPalLayerSettings.Property.LinePlacementOptions, QgsProperty.fromExpression('@placement')) - props.setProperty(QgsPalLayerSettings.Property.OverrunDistance, QgsProperty.fromExpression('@dist')) - props.setProperty(QgsPalLayerSettings.Property.LineAnchorPercent, QgsProperty.fromExpression('@line_anchor')) + props.setProperty( + QgsPalLayerSettings.Property.LinePlacementOptions, + QgsProperty.fromExpression("@placement"), + ) + props.setProperty( + QgsPalLayerSettings.Property.OverrunDistance, + QgsProperty.fromExpression("@dist"), + ) + props.setProperty( + QgsPalLayerSettings.Property.LineAnchorPercent, + QgsProperty.fromExpression("@line_anchor"), + ) context = QgsExpressionContext() scope = QgsExpressionContextScope() - scope.setVariable('placement', 'AL,LO') - scope.setVariable('dist', '11.2') - scope.setVariable('line_anchor', '0.6') + scope.setVariable("placement", "AL,LO") + scope.setVariable("dist", "11.2") + scope.setVariable("line_anchor", "0.6") context.appendScope(scope) settings.updateDataDefinedProperties(props, context) - self.assertEqual(settings.placementFlags(), QgsLabeling.LinePlacementFlag.AboveLine) + self.assertEqual( + settings.placementFlags(), QgsLabeling.LinePlacementFlag.AboveLine + ) self.assertEqual(settings.overrunDistance(), 11.2) self.assertEqual(settings.lineAnchorPercent(), 0.6) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslabelobstaclesettings.py b/tests/src/python/test_qgslabelobstaclesettings.py index 18a076288a00..0b1769b39552 100644 --- a/tests/src/python/test_qgslabelobstaclesettings.py +++ b/tests/src/python/test_qgslabelobstaclesettings.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2019-12-07' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2019-12-07" +__copyright__ = "Copyright 2019, The QGIS Project" from qgis.core import ( @@ -41,7 +42,9 @@ def test_obstacle_settings(self): self.assertEqual(settings.factor(), 0.1) settings.setType(QgsLabelObstacleSettings.ObstacleType.PolygonWhole) - self.assertEqual(settings.type(), QgsLabelObstacleSettings.ObstacleType.PolygonWhole) + self.assertEqual( + settings.type(), QgsLabelObstacleSettings.ObstacleType.PolygonWhole + ) # check that compatibility code works pal_settings = QgsPalLayerSettings() @@ -57,8 +60,13 @@ def test_obstacle_settings(self): self.assertEqual(pal_settings.obstacleSettings().factor(), 0.2) pal_settings.obstacleType = QgsPalLayerSettings.ObstacleType.PolygonWhole - self.assertEqual(pal_settings.obstacleType, QgsPalLayerSettings.ObstacleType.PolygonWhole) - self.assertEqual(pal_settings.obstacleSettings().type(), QgsLabelObstacleSettings.ObstacleType.PolygonWhole) + self.assertEqual( + pal_settings.obstacleType, QgsPalLayerSettings.ObstacleType.PolygonWhole + ) + self.assertEqual( + pal_settings.obstacleSettings().type(), + QgsLabelObstacleSettings.ObstacleType.PolygonWhole, + ) def testUpdateDataDefinedProps(self): settings = QgsLabelObstacleSettings() @@ -66,10 +74,13 @@ def testUpdateDataDefinedProps(self): self.assertEqual(settings.factor(), 0.1) props = QgsPropertyCollection() - props.setProperty(QgsPalLayerSettings.Property.ObstacleFactor, QgsProperty.fromExpression('@factor')) + props.setProperty( + QgsPalLayerSettings.Property.ObstacleFactor, + QgsProperty.fromExpression("@factor"), + ) context = QgsExpressionContext() scope = QgsExpressionContextScope() - scope.setVariable('factor', 9) + scope.setVariable("factor", 9) context.appendScope(scope) settings.updateDataDefinedProperties(props, context) self.assertAlmostEqual(settings.factor(), 1.8, 3) @@ -77,9 +88,9 @@ def testUpdateDataDefinedProps(self): def testObstacleGeom(self): settings = QgsLabelObstacleSettings() self.assertTrue(settings.obstacleGeometry().isNull()) - settings.setObstacleGeometry(QgsGeometry.fromWkt('LineString( 0 0, 1 1)')) - self.assertEqual(settings.obstacleGeometry().asWkt(), 'LineString (0 0, 1 1)') + settings.setObstacleGeometry(QgsGeometry.fromWkt("LineString( 0 0, 1 1)")) + self.assertEqual(settings.obstacleGeometry().asWkt(), "LineString (0 0, 1 1)") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslabelplacementsettings.py b/tests/src/python/test_qgslabelplacementsettings.py index 613cdc8ce315..44240fb8aff2 100644 --- a/tests/src/python/test_qgslabelplacementsettings.py +++ b/tests/src/python/test_qgslabelplacementsettings.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2024-02-02' -__copyright__ = 'Copyright 2024, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2024-02-02" +__copyright__ = "Copyright 2024, The QGIS Project" from qgis.core import Qgis, QgsPalLayerSettings @@ -28,15 +29,19 @@ def test_placement_settings(self): pal_settings = QgsPalLayerSettings() pal_settings.displayAll = True self.assertTrue(pal_settings.displayAll) - self.assertEqual(pal_settings.placementSettings().overlapHandling(), - Qgis.LabelOverlapHandling.AllowOverlapIfRequired) + self.assertEqual( + pal_settings.placementSettings().overlapHandling(), + Qgis.LabelOverlapHandling.AllowOverlapIfRequired, + ) self.assertTrue(pal_settings.placementSettings().allowDegradedPlacement()) pal_settings.displayAll = False self.assertFalse(pal_settings.displayAll) - self.assertEqual(pal_settings.placementSettings().overlapHandling(), - Qgis.LabelOverlapHandling.PreventOverlap) + self.assertEqual( + pal_settings.placementSettings().overlapHandling(), + Qgis.LabelOverlapHandling.PreventOverlap, + ) self.assertFalse(pal_settings.placementSettings().allowDegradedPlacement()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslabelsettingswidget.py b/tests/src/python/test_qgslabelsettingswidget.py index 6d2d623775f3..66ff67fac056 100644 --- a/tests/src/python/test_qgslabelsettingswidget.py +++ b/tests/src/python/test_qgslabelsettingswidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '04/02/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "04/02/2019" +__copyright__ = "Copyright 2019, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy from qgis.core import ( @@ -26,20 +27,24 @@ class TestQgsLabelSettingsWidget(QgisTestCase): def testBase(self): - """ test base class """ + """test base class""" w = QgsLabelSettingsWidgetBase() spy = QSignalSpy(w.changed) props = QgsPropertyCollection() - props.setProperty(QgsPalLayerSettings.Property.ObstacleFactor, QgsProperty.fromValue(5)) - props.setProperty(QgsPalLayerSettings.Property.IsObstacle, QgsProperty.fromValue(True)) + props.setProperty( + QgsPalLayerSettings.Property.ObstacleFactor, QgsProperty.fromValue(5) + ) + props.setProperty( + QgsPalLayerSettings.Property.IsObstacle, QgsProperty.fromValue(True) + ) w.setDataDefinedProperties(props) self.assertEqual(len(spy), 0) dd_props = w.dataDefinedProperties() prop = dd_props.property(QgsPalLayerSettings.Property.ObstacleFactor) - self.assertEqual(prop.asExpression(), '5') + self.assertEqual(prop.asExpression(), "5") prop = dd_props.property(QgsPalLayerSettings.Property.IsObstacle) - self.assertEqual(prop.asExpression(), 'TRUE') + self.assertEqual(prop.asExpression(), "TRUE") def testObstacles(self): w = QgsLabelObstacleSettingsWidget() @@ -51,17 +56,23 @@ def testObstacles(self): self.assertEqual(len(spy), 0) settings = w.settings() self.assertEqual(settings.factor(), 0.4) - self.assertEqual(settings.type(), QgsLabelObstacleSettings.ObstacleType.PolygonBoundary) + self.assertEqual( + settings.type(), QgsLabelObstacleSettings.ObstacleType.PolygonBoundary + ) settings.setFactor(1.2) settings.setType(QgsLabelObstacleSettings.ObstacleType.PolygonInterior) w.setSettings(settings) self.assertEqual(len(spy), 0) settings = w.settings() self.assertEqual(settings.factor(), 1.2) - self.assertEqual(settings.type(), QgsLabelObstacleSettings.ObstacleType.PolygonInterior) + self.assertEqual( + settings.type(), QgsLabelObstacleSettings.ObstacleType.PolygonInterior + ) props = QgsPropertyCollection() - props.setProperty(QgsPalLayerSettings.Property.ObstacleFactor, QgsProperty.fromValue(5)) + props.setProperty( + QgsPalLayerSettings.Property.ObstacleFactor, QgsProperty.fromValue(5) + ) w.setDataDefinedProperties(props) props = QgsPropertyCollection() @@ -70,8 +81,8 @@ def testObstacles(self): self.assertTrue(props.isActive(QgsPalLayerSettings.Property.ObstacleFactor)) props = w.dataDefinedProperties() prop = props.property(QgsPalLayerSettings.Property.ObstacleFactor) - self.assertEqual(prop.asExpression(), '5') + self.assertEqual(prop.asExpression(), "5") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslabelthinningsettings.py b/tests/src/python/test_qgslabelthinningsettings.py index 071bb09243a9..9d56f3e8042c 100644 --- a/tests/src/python/test_qgslabelthinningsettings.py +++ b/tests/src/python/test_qgslabelthinningsettings.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2019-12-07' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2019-12-07" +__copyright__ = "Copyright 2019, The QGIS Project" from qgis.core import QgsLabelThinningSettings, QgsPalLayerSettings @@ -53,5 +54,5 @@ def test_thinning_settings(self): self.assertEqual(pal_settings.thinningSettings().minimumFeatureSize(), 4.6) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayerdefinition.py b/tests/src/python/test_qgslayerdefinition.py index b5f12373eb5d..26a7ea2d2ac7 100644 --- a/tests/src/python/test_qgslayerdefinition.py +++ b/tests/src/python/test_qgslayerdefinition.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Hugo Mercier' -__date__ = '07/01/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Hugo Mercier" +__date__ = "07/01/2016" +__copyright__ = "Copyright 2016, The QGIS Project" import os import shutil @@ -106,7 +107,11 @@ def testVectorAndRaster(self): layers = QgsProject.instance().mapLayers() self.assertEqual(len(layers), 0) - (result, errMsg) = QgsLayerDefinition.loadLayerDefinition(TEST_DATA_DIR + '/vector_and_raster.qlr', QgsProject.instance(), QgsProject.instance().layerTreeRoot()) + (result, errMsg) = QgsLayerDefinition.loadLayerDefinition( + TEST_DATA_DIR + "/vector_and_raster.qlr", + QgsProject.instance(), + QgsProject.instance().layerTreeRoot(), + ) self.assertTrue(result) layers = QgsProject.instance().mapLayers() @@ -119,7 +124,11 @@ def testInvalidSource(self): layers = QgsProject.instance().mapLayers() self.assertEqual(len(layers), 0) - (result, errMsg) = QgsLayerDefinition.loadLayerDefinition(TEST_DATA_DIR + '/invalid_source.qlr', QgsProject.instance(), QgsProject.instance().layerTreeRoot()) + (result, errMsg) = QgsLayerDefinition.loadLayerDefinition( + TEST_DATA_DIR + "/invalid_source.qlr", + QgsProject.instance(), + QgsProject.instance().layerTreeRoot(), + ) self.assertTrue(result) self.assertFalse(errMsg) @@ -133,8 +142,8 @@ def test_path_storage(self): Test storage of relative/absolute paths """ temp_dir = QTemporaryDir() - gpkg_path = temp_dir.filePath('points_gpkg.gpkg') - shutil.copy(TEST_DATA_DIR + '/points_gpkg.gpkg', gpkg_path) + gpkg_path = temp_dir.filePath("points_gpkg.gpkg") + shutil.copy(TEST_DATA_DIR + "/points_gpkg.gpkg", gpkg_path) p = QgsProject() vl = QgsVectorLayer(gpkg_path) @@ -142,26 +151,34 @@ def test_path_storage(self): p.addMapLayer(vl) # write qlr with relative paths - ok, err = QgsLayerDefinition.exportLayerDefinition(temp_dir.filePath('relative.qlr'), [p.layerTreeRoot()], Qgis.FilePathType.Relative) + ok, err = QgsLayerDefinition.exportLayerDefinition( + temp_dir.filePath("relative.qlr"), + [p.layerTreeRoot()], + Qgis.FilePathType.Relative, + ) self.assertTrue(ok) - with open(temp_dir.filePath('relative.qlr')) as f: + with open(temp_dir.filePath("relative.qlr")) as f: lines = f.readlines() - self.assertIn('source="./points_gpkg.gpkg"', '\n'.join(lines)) + self.assertIn('source="./points_gpkg.gpkg"', "\n".join(lines)) # write qlr with absolute paths - ok, err = QgsLayerDefinition.exportLayerDefinition(temp_dir.filePath('absolute.qlr'), [p.layerTreeRoot()], Qgis.FilePathType.Absolute) + ok, err = QgsLayerDefinition.exportLayerDefinition( + temp_dir.filePath("absolute.qlr"), + [p.layerTreeRoot()], + Qgis.FilePathType.Absolute, + ) self.assertTrue(ok) - with open(temp_dir.filePath('absolute.qlr')) as f: + with open(temp_dir.filePath("absolute.qlr")) as f: lines = f.readlines() - self.assertIn(f'source="{gpkg_path}"', '\n'.join(lines)) + self.assertIn(f'source="{gpkg_path}"', "\n".join(lines)) def testWidgetConfig(self): temp = QTemporaryDir() temp_path = temp.path() - temp_qlr = os.path.join(temp_path, 'widget_config.qlr') + temp_qlr = os.path.join(temp_path, "widget_config.qlr") qlr = """ @@ -242,20 +259,22 @@ def testWidgetConfig(self): """ - with open(temp_qlr, 'w+') as f: + with open(temp_qlr, "w+") as f: f.write(qlr) - (result, errMsg) = QgsLayerDefinition.loadLayerDefinition(temp_qlr, QgsProject.instance(), QgsProject.instance().layerTreeRoot()) + (result, errMsg) = QgsLayerDefinition.loadLayerDefinition( + temp_qlr, QgsProject.instance(), QgsProject.instance().layerTreeRoot() + ) self.assertTrue(result) self.assertFalse(errMsg) - vl = QgsProject.instance().mapLayersByName('NewMemory')[0] + vl = QgsProject.instance().mapLayersByName("NewMemory")[0] field = vl.fields().at(0) config = field.editorWidgetSetup().config() - self.assertFalse(config['Description']) - self.assertFalse(config['FilterExpression']) + self.assertFalse(config["Description"]) + self.assertFalse(config["FilterExpression"]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayermetadata.py b/tests/src/python/test_qgslayermetadata.py index d9802e8afd6a..041e8b5b1b0c 100644 --- a/tests/src/python/test_qgslayermetadata.py +++ b/tests/src/python/test_qgslayermetadata.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '11/04/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "11/04/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, QRegularExpression, QTime from qgis.PyQt.QtXml import QDomDocument @@ -32,54 +33,62 @@ class TestQgsLayerMetadata(QgisTestCase): def testGettersSetters(self): m = QgsLayerMetadata() - m.setIdentifier('identifier') - self.assertEqual(m.identifier(), 'identifier') + m.setIdentifier("identifier") + self.assertEqual(m.identifier(), "identifier") - m.setParentIdentifier('parent identifier') - self.assertEqual(m.parentIdentifier(), 'parent identifier') + m.setParentIdentifier("parent identifier") + self.assertEqual(m.parentIdentifier(), "parent identifier") - m.setLanguage('en-us') - self.assertEqual(m.language(), 'en-us') + m.setLanguage("en-us") + self.assertEqual(m.language(), "en-us") - m.setType('type') - self.assertEqual(m.type(), 'type') + m.setType("type") + self.assertEqual(m.type(), "type") - m.setTitle('title') - self.assertEqual(m.title(), 'title') + m.setTitle("title") + self.assertEqual(m.title(), "title") - m.setCategories(['category']) - self.assertEqual(m.categories(), ['category']) + m.setCategories(["category"]) + self.assertEqual(m.categories(), ["category"]) - m.setAbstract('abstract') - self.assertEqual(m.abstract(), 'abstract') + m.setAbstract("abstract") + self.assertEqual(m.abstract(), "abstract") - m.setFees('fees') - self.assertEqual(m.fees(), 'fees') + m.setFees("fees") + self.assertEqual(m.fees(), "fees") - m.setConstraints([QgsLayerMetadata.Constraint('constraint a'), QgsLayerMetadata.Constraint('constraint b')]) - m.addConstraint(QgsLayerMetadata.Constraint('constraint c')) - self.assertEqual(m.constraints()[0].constraint, 'constraint a') - self.assertEqual(m.constraints()[1].constraint, 'constraint b') - self.assertEqual(m.constraints()[2].constraint, 'constraint c') + m.setConstraints( + [ + QgsLayerMetadata.Constraint("constraint a"), + QgsLayerMetadata.Constraint("constraint b"), + ] + ) + m.addConstraint(QgsLayerMetadata.Constraint("constraint c")) + self.assertEqual(m.constraints()[0].constraint, "constraint a") + self.assertEqual(m.constraints()[1].constraint, "constraint b") + self.assertEqual(m.constraints()[2].constraint, "constraint c") - m.setRights(['right a', 'right b']) - self.assertEqual(m.rights(), ['right a', 'right b']) + m.setRights(["right a", "right b"]) + self.assertEqual(m.rights(), ["right a", "right b"]) - m.setLicenses(['l a', 'l b']) - self.assertEqual(m.licenses(), ['l a', 'l b']) + m.setLicenses(["l a", "l b"]) + self.assertEqual(m.licenses(), ["l a", "l b"]) - m.setHistory(['loaded into QGIS']) - self.assertEqual(m.history(), ['loaded into QGIS']) - m.setHistory(['accidentally deleted some features']) - self.assertEqual(m.history(), ['accidentally deleted some features']) - m.addHistoryItem('panicked and deleted more') - self.assertEqual(m.history(), ['accidentally deleted some features', 'panicked and deleted more']) + m.setHistory(["loaded into QGIS"]) + self.assertEqual(m.history(), ["loaded into QGIS"]) + m.setHistory(["accidentally deleted some features"]) + self.assertEqual(m.history(), ["accidentally deleted some features"]) + m.addHistoryItem("panicked and deleted more") + self.assertEqual( + m.history(), + ["accidentally deleted some features", "panicked and deleted more"], + ) - m.setEncoding('encoding') - self.assertEqual(m.encoding(), 'encoding') + m.setEncoding("encoding") + self.assertEqual(m.encoding(), "encoding") m.setCrs(QgsCoordinateReferenceSystem.fromEpsgId(3111)) - self.assertEqual(m.crs().authid(), 'EPSG:3111') + self.assertEqual(m.crs().authid(), "EPSG:3111") def testEquality(self): # spatial extent @@ -108,22 +117,28 @@ def testEquality(self): dates = [ QgsDateTimeRange( QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)), - QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))), + QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)), + ), QgsDateTimeRange( QDateTime(QDate(2010, 12, 17), QTime(9, 30, 47)), - QDateTime(QDate(2020, 12, 17), QTime(9, 30, 47))) + QDateTime(QDate(2020, 12, 17), QTime(9, 30, 47)), + ), ] extent.setTemporalExtents(dates) extent_copy = QgsLayerMetadata.Extent(extent) self.assertEqual(extent, extent_copy) - extent_copy.setTemporalExtents([ - QgsDateTimeRange( - QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)), - QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))), - QgsDateTimeRange( - QDateTime(QDate(2010, 12, 17), QTime(9, 30, 48)), - QDateTime(QDate(2020, 12, 17), QTime(9, 30, 49))) - ]) + extent_copy.setTemporalExtents( + [ + QgsDateTimeRange( + QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)), + QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)), + ), + QgsDateTimeRange( + QDateTime(QDate(2010, 12, 17), QTime(9, 30, 48)), + QDateTime(QDate(2020, 12, 17), QTime(9, 30, 49)), + ), + ] + ) self.assertNotEqual(extent, extent_copy) extent_copy = QgsLayerMetadata.Extent(extent) extent3 = QgsLayerMetadata.SpatialExtent() @@ -132,10 +147,10 @@ def testEquality(self): extent_copy.setSpatialExtents([extent1, extent3]) self.assertNotEqual(extent, extent_copy) - constraint = QgsLayerMetadata.Constraint('c', 'type1') - self.assertEqual(constraint, QgsLayerMetadata.Constraint('c', 'type1')) - self.assertNotEqual(constraint, QgsLayerMetadata.Constraint('c2', 'type1')) - self.assertNotEqual(constraint, QgsLayerMetadata.Constraint('c', 'type2')) + constraint = QgsLayerMetadata.Constraint("c", "type1") + self.assertEqual(constraint, QgsLayerMetadata.Constraint("c", "type1")) + self.assertNotEqual(constraint, QgsLayerMetadata.Constraint("c2", "type1")) + self.assertNotEqual(constraint, QgsLayerMetadata.Constraint("c", "type2")) def testExtent(self): e = QgsLayerMetadata.Extent() @@ -143,99 +158,116 @@ def testExtent(self): se.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3111) se.bounds = QgsBox3d(1, 2, 3, 4, 5, 6) e.setSpatialExtents([se]) - e.setTemporalExtents([QgsDateTimeRange(QDateTime(QDate(2017, 1, 3), QTime(11, 34, 56)), QDateTime(QDate(2018, 1, 3), QTime(12, 35, 57)))]) + e.setTemporalExtents( + [ + QgsDateTimeRange( + QDateTime(QDate(2017, 1, 3), QTime(11, 34, 56)), + QDateTime(QDate(2018, 1, 3), QTime(12, 35, 57)), + ) + ] + ) m = QgsLayerMetadata() m.setExtent(e) extents = m.extent().spatialExtents() - self.assertEqual(extents[0].extentCrs.authid(), 'EPSG:3111') + self.assertEqual(extents[0].extentCrs.authid(), "EPSG:3111") self.assertEqual(extents[0].bounds.xMinimum(), 1.0) self.assertEqual(extents[0].bounds.yMinimum(), 2.0) self.assertEqual(extents[0].bounds.zMinimum(), 3.0) self.assertEqual(extents[0].bounds.xMaximum(), 4.0) self.assertEqual(extents[0].bounds.yMaximum(), 5.0) self.assertEqual(extents[0].bounds.zMaximum(), 6.0) - self.assertEqual(m.extent().temporalExtents()[0].begin(), QDateTime(QDate(2017, 1, 3), QTime(11, 34, 56))) - self.assertEqual(m.extent().temporalExtents()[0].end(), QDateTime(QDate(2018, 1, 3), QTime(12, 35, 57))) + self.assertEqual( + m.extent().temporalExtents()[0].begin(), + QDateTime(QDate(2017, 1, 3), QTime(11, 34, 56)), + ) + self.assertEqual( + m.extent().temporalExtents()[0].end(), + QDateTime(QDate(2018, 1, 3), QTime(12, 35, 57)), + ) def createTestMetadata(self): """ Returns a standard metadata which can be tested with checkExpectedMetadata """ m = QgsLayerMetadata() - m.setIdentifier('1234') - m.setParentIdentifier('xyz') - m.setLanguage('en-CA') - m.setType('dataset') - m.setTitle('roads') - m.setAbstract('my roads') - m.setFees('None') - m.setConstraints([QgsLayerMetadata.Constraint('None', 'access')]) - m.setRights(['Copyright foo 2017']) - m.setLicenses(['WTFPL']) - m.setHistory(['history a', 'history b']) - m.setKeywords({ - 'GEMET': ['kw1', 'kw2'], - 'gmd:topicCategory': ['natural'], - }) - m.setEncoding('utf-8') - m.setCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:4326')) + m.setIdentifier("1234") + m.setParentIdentifier("xyz") + m.setLanguage("en-CA") + m.setType("dataset") + m.setTitle("roads") + m.setAbstract("my roads") + m.setFees("None") + m.setConstraints([QgsLayerMetadata.Constraint("None", "access")]) + m.setRights(["Copyright foo 2017"]) + m.setLicenses(["WTFPL"]) + m.setHistory(["history a", "history b"]) + m.setKeywords( + { + "GEMET": ["kw1", "kw2"], + "gmd:topicCategory": ["natural"], + } + ) + m.setEncoding("utf-8") + m.setCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs("EPSG:4326")) e = QgsLayerMetadata.Extent() se = QgsLayerMetadata.SpatialExtent() - se.extentCrs = QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:4326') + se.extentCrs = QgsCoordinateReferenceSystem.fromOgcWmsCrs("EPSG:4326") se.bounds = QgsBox3d(-180, -90, 0, 180, 90, 0) e.setSpatialExtents([se]) dates = [ QgsDateTimeRange( QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)), - QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))), + QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)), + ), QgsDateTimeRange( QDateTime(QDate(2010, 12, 17), QTime(9, 30, 47)), - QDateTime(QDate(2020, 12, 17), QTime(9, 30, 47))) + QDateTime(QDate(2020, 12, 17), QTime(9, 30, 47)), + ), ] e.setTemporalExtents(dates) m.setExtent(e) c = QgsLayerMetadata.Contact() - c.name = 'John Smith' - c.organization = 'ACME' - c.position = 'staff' - c.voice = '1500 515 555' - c.fax = 'xx.xxx.xxx.xxxx' - c.email = 'foo@example.org' - c.role = 'pointOfContact' + c.name = "John Smith" + c.organization = "ACME" + c.position = "staff" + c.voice = "1500 515 555" + c.fax = "xx.xxx.xxx.xxxx" + c.email = "foo@example.org" + c.role = "pointOfContact" address = QgsLayerMetadata.Address() - address.type = 'postal' - address.address = '123 Main Street' - address.city = 'anycity' - address.administrativeArea = 'anyprovince' - address.postalCode = '90210' - address.country = 'Canada' + address.type = "postal" + address.address = "123 Main Street" + address.city = "anycity" + address.administrativeArea = "anyprovince" + address.postalCode = "90210" + address.country = "Canada" c.addresses = [address] m.setContacts([c]) l = QgsLayerMetadata.Link() - l.name = 'geonode:roads' - l.type = 'OGC:WMS' - l.description = 'my GeoNode road layer' - l.url = 'http://example.org/wms' + l.name = "geonode:roads" + l.type = "OGC:WMS" + l.description = "my GeoNode road layer" + l.url = "http://example.org/wms" l2 = QgsLayerMetadata.Link() - l2.name = 'geonode:roads' - l2.type = 'OGC:WFS' - l2.description = 'my GeoNode road layer' - l2.url = 'http://example.org/wfs' + l2.name = "geonode:roads" + l2.type = "OGC:WFS" + l2.description = "my GeoNode road layer" + l2.url = "http://example.org/wfs" l3 = QgsLayerMetadata.Link() - l3.name = 'roads' - l3.type = 'WWW:LINK' - l3.description = 'full dataset download' - l3.url = 'http://example.org/roads.tgz' - l3.format = 'ESRI Shapefile' - l3.mimeType = 'application/gzip' - l3.size = '283676' + l3.name = "roads" + l3.type = "WWW:LINK" + l3.description = "full dataset download" + l3.url = "http://example.org/roads.tgz" + l3.format = "ESRI Shapefile" + l3.mimeType = "application/gzip" + l3.size = "283676" m.setLinks([l, l2, l3]) @@ -245,63 +277,69 @@ def checkExpectedMetadata(self, m): """ Checks that a metadata object matches that returned by createTestMetadata """ - self.assertEqual(m.identifier(), '1234') - self.assertEqual(m.parentIdentifier(), 'xyz') - self.assertEqual(m.language(), 'en-CA') - self.assertEqual(m.type(), 'dataset') - self.assertEqual(m.title(), 'roads') - self.assertEqual(m.abstract(), 'my roads') - self.assertEqual(m.fees(), 'None') - self.assertEqual(m.constraints()[0].constraint, 'None') - self.assertEqual(m.constraints()[0].type, 'access') - self.assertEqual(m.rights(), ['Copyright foo 2017']) - self.assertEqual(m.licenses(), ['WTFPL']) - self.assertEqual(m.history(), ['history a', 'history b']) - self.assertEqual(m.encoding(), 'utf-8') + self.assertEqual(m.identifier(), "1234") + self.assertEqual(m.parentIdentifier(), "xyz") + self.assertEqual(m.language(), "en-CA") + self.assertEqual(m.type(), "dataset") + self.assertEqual(m.title(), "roads") + self.assertEqual(m.abstract(), "my roads") + self.assertEqual(m.fees(), "None") + self.assertEqual(m.constraints()[0].constraint, "None") + self.assertEqual(m.constraints()[0].type, "access") + self.assertEqual(m.rights(), ["Copyright foo 2017"]) + self.assertEqual(m.licenses(), ["WTFPL"]) + self.assertEqual(m.history(), ["history a", "history b"]) + self.assertEqual(m.encoding(), "utf-8") self.assertEqual( - m.keywords(), - {'GEMET': ['kw1', 'kw2'], 'gmd:topicCategory': ['natural']}) - self.assertEqual(m.crs().authid(), 'EPSG:4326') + m.keywords(), {"GEMET": ["kw1", "kw2"], "gmd:topicCategory": ["natural"]} + ) + self.assertEqual(m.crs().authid(), "EPSG:4326") extent = m.extent().spatialExtents()[0] - self.assertEqual(extent.extentCrs.authid(), 'EPSG:4326') + self.assertEqual(extent.extentCrs.authid(), "EPSG:4326") self.assertEqual(extent.bounds.xMinimum(), -180.0) self.assertEqual(extent.bounds.yMinimum(), -90.0) self.assertEqual(extent.bounds.xMaximum(), 180.0) self.assertEqual(extent.bounds.yMaximum(), 90.0) - self.assertEqual(m.extent().temporalExtents()[0].begin(), QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))) + self.assertEqual( + m.extent().temporalExtents()[0].begin(), + QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)), + ) self.assertTrue(m.extent().temporalExtents()[0].isInstant()) self.assertFalse(m.extent().temporalExtents()[1].isInstant()) - self.assertEqual(m.extent().temporalExtents()[1].end(), QDateTime(QDate(2020, 12, 17), QTime(9, 30, 47))) - - self.assertEqual(m.contacts()[0].name, 'John Smith') - self.assertEqual(m.contacts()[0].organization, 'ACME') - self.assertEqual(m.contacts()[0].position, 'staff') - self.assertEqual(m.contacts()[0].voice, '1500 515 555') - self.assertEqual(m.contacts()[0].fax, 'xx.xxx.xxx.xxxx') - self.assertEqual(m.contacts()[0].email, 'foo@example.org') - self.assertEqual(m.contacts()[0].role, 'pointOfContact') - self.assertEqual(m.contacts()[0].addresses[0].type, 'postal') - self.assertEqual(m.contacts()[0].addresses[0].address, '123 Main Street') - self.assertEqual(m.contacts()[0].addresses[0].city, 'anycity') - self.assertEqual(m.contacts()[0].addresses[0].administrativeArea, 'anyprovince') - self.assertEqual(m.contacts()[0].addresses[0].postalCode, '90210') - self.assertEqual(m.contacts()[0].addresses[0].country, 'Canada') - self.assertEqual(m.links()[0].name, 'geonode:roads') - self.assertEqual(m.links()[0].type, 'OGC:WMS') - self.assertEqual(m.links()[0].description, 'my GeoNode road layer') - self.assertEqual(m.links()[0].url, 'http://example.org/wms') - self.assertEqual(m.links()[1].name, 'geonode:roads') - self.assertEqual(m.links()[1].type, 'OGC:WFS') - self.assertEqual(m.links()[1].description, 'my GeoNode road layer') - self.assertEqual(m.links()[1].url, 'http://example.org/wfs') - self.assertEqual(m.links()[2].name, 'roads') - self.assertEqual(m.links()[2].type, 'WWW:LINK') - self.assertEqual(m.links()[2].description, 'full dataset download') - self.assertEqual(m.links()[2].url, 'http://example.org/roads.tgz') - self.assertEqual(m.links()[2].format, 'ESRI Shapefile') - self.assertEqual(m.links()[2].mimeType, 'application/gzip') - self.assertEqual(m.links()[2].size, '283676') + self.assertEqual( + m.extent().temporalExtents()[1].end(), + QDateTime(QDate(2020, 12, 17), QTime(9, 30, 47)), + ) + + self.assertEqual(m.contacts()[0].name, "John Smith") + self.assertEqual(m.contacts()[0].organization, "ACME") + self.assertEqual(m.contacts()[0].position, "staff") + self.assertEqual(m.contacts()[0].voice, "1500 515 555") + self.assertEqual(m.contacts()[0].fax, "xx.xxx.xxx.xxxx") + self.assertEqual(m.contacts()[0].email, "foo@example.org") + self.assertEqual(m.contacts()[0].role, "pointOfContact") + self.assertEqual(m.contacts()[0].addresses[0].type, "postal") + self.assertEqual(m.contacts()[0].addresses[0].address, "123 Main Street") + self.assertEqual(m.contacts()[0].addresses[0].city, "anycity") + self.assertEqual(m.contacts()[0].addresses[0].administrativeArea, "anyprovince") + self.assertEqual(m.contacts()[0].addresses[0].postalCode, "90210") + self.assertEqual(m.contacts()[0].addresses[0].country, "Canada") + self.assertEqual(m.links()[0].name, "geonode:roads") + self.assertEqual(m.links()[0].type, "OGC:WMS") + self.assertEqual(m.links()[0].description, "my GeoNode road layer") + self.assertEqual(m.links()[0].url, "http://example.org/wms") + self.assertEqual(m.links()[1].name, "geonode:roads") + self.assertEqual(m.links()[1].type, "OGC:WFS") + self.assertEqual(m.links()[1].description, "my GeoNode road layer") + self.assertEqual(m.links()[1].url, "http://example.org/wfs") + self.assertEqual(m.links()[2].name, "roads") + self.assertEqual(m.links()[2].type, "WWW:LINK") + self.assertEqual(m.links()[2].description, "full dataset download") + self.assertEqual(m.links()[2].url, "http://example.org/roads.tgz") + self.assertEqual(m.links()[2].format, "ESRI Shapefile") + self.assertEqual(m.links()[2].mimeType, "application/gzip") + self.assertEqual(m.links()[2].size, "283676") def testStandard(self): m = self.createTestMetadata() @@ -311,7 +349,7 @@ def testSaveReadFromLayer(self): """ Test saving and reading metadata from a layer """ - vl = QgsVectorLayer('Point', 'test', 'memory') + vl = QgsVectorLayer("Point", "test", "memory") self.assertTrue(vl.isValid()) # save metadata to layer @@ -353,71 +391,71 @@ def testValidateNative(self): # spellok # corrupt metadata piece by piece... m = self.createTestMetadata() - m.setIdentifier('') + m.setIdentifier("") res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'identifier') + self.assertEqual(list[0].section, "identifier") m = self.createTestMetadata() - m.setLanguage('') + m.setLanguage("") res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'language') + self.assertEqual(list[0].section, "language") m = self.createTestMetadata() - m.setType('') + m.setType("") res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'type') + self.assertEqual(list[0].section, "type") m = self.createTestMetadata() - m.setTitle('') + m.setTitle("") res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'title') + self.assertEqual(list[0].section, "title") m = self.createTestMetadata() - m.setAbstract('') + m.setAbstract("") res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'abstract') + self.assertEqual(list[0].section, "abstract") m = self.createTestMetadata() m.setLicenses([]) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'license') + self.assertEqual(list[0].section, "license") m = self.createTestMetadata() m.setCrs(QgsCoordinateReferenceSystem()) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'crs') + self.assertEqual(list[0].section, "crs") m = self.createTestMetadata() m.setContacts([]) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'contacts') + self.assertEqual(list[0].section, "contacts") m = self.createTestMetadata() m.setLinks([]) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'links') + self.assertEqual(list[0].section, "links") m = self.createTestMetadata() - m.setKeywords({'': ['kw1', 'kw2']}) + m.setKeywords({"": ["kw1", "kw2"]}) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'keywords') + self.assertEqual(list[0].section, "keywords") self.assertEqual(list[0].identifier, 0) m = self.createTestMetadata() - m.setKeywords({'AA': []}) + m.setKeywords({"AA": []}) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'keywords') + self.assertEqual(list[0].section, "keywords") self.assertEqual(list[0].identifier, 0) m = self.createTestMetadata() @@ -428,7 +466,7 @@ def testValidateNative(self): # spellok m.setExtent(e) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'extent') + self.assertEqual(list[0].section, "extent") self.assertEqual(list[0].identifier, 0) m = self.createTestMetadata() @@ -439,43 +477,43 @@ def testValidateNative(self): # spellok m.setExtent(e) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'extent') + self.assertEqual(list[0].section, "extent") self.assertEqual(list[0].identifier, 0) m = self.createTestMetadata() c = m.contacts()[0] - c.name = '' + c.name = "" m.setContacts([c]) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'contacts') + self.assertEqual(list[0].section, "contacts") self.assertEqual(list[0].identifier, 0) m = self.createTestMetadata() l = m.links()[0] - l.name = '' + l.name = "" m.setLinks([l]) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'links') + self.assertEqual(list[0].section, "links") self.assertEqual(list[0].identifier, 0) m = self.createTestMetadata() l = m.links()[0] - l.type = '' + l.type = "" m.setLinks([l]) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'links') + self.assertEqual(list[0].section, "links") self.assertEqual(list[0].identifier, 0) m = self.createTestMetadata() l = m.links()[0] - l.url = '' + l.url = "" m.setLinks([l]) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'links') + self.assertEqual(list[0].section, "links") self.assertEqual(list[0].identifier, 0) def testCombine(self): @@ -483,192 +521,224 @@ def testCombine(self): m2 = QgsLayerMetadata() # should be retained - m1.setIdentifier('i1') + m1.setIdentifier("i1") m1.combine(m2) - self.assertEqual(m1.identifier(), 'i1') + self.assertEqual(m1.identifier(), "i1") # should be overwritten m1.setIdentifier(None) - m2.setIdentifier('i2') + m2.setIdentifier("i2") m1.combine(m2) - self.assertEqual(m1.identifier(), 'i2') + self.assertEqual(m1.identifier(), "i2") # should be overwritten - m1.setIdentifier('i1') - m2.setIdentifier('i2') + m1.setIdentifier("i1") + m2.setIdentifier("i2") m1.combine(m2) - self.assertEqual(m1.identifier(), 'i2') + self.assertEqual(m1.identifier(), "i2") - m1.setParentIdentifier('pi1') + m1.setParentIdentifier("pi1") m2.setParentIdentifier(None) m1.combine(m2) - self.assertEqual(m1.parentIdentifier(), 'pi1') + self.assertEqual(m1.parentIdentifier(), "pi1") m1.setParentIdentifier(None) - m2.setParentIdentifier('pi2') + m2.setParentIdentifier("pi2") m1.combine(m2) - self.assertEqual(m1.parentIdentifier(), 'pi2') + self.assertEqual(m1.parentIdentifier(), "pi2") - m1.setLanguage('l1') + m1.setLanguage("l1") m2.setLanguage(None) m1.combine(m2) - self.assertEqual(m1.language(), 'l1') + self.assertEqual(m1.language(), "l1") m1.setLanguage(None) - m2.setLanguage('l2') + m2.setLanguage("l2") m1.combine(m2) - self.assertEqual(m1.language(), 'l2') + self.assertEqual(m1.language(), "l2") - m1.setType('ty1') + m1.setType("ty1") m2.setType(None) m1.combine(m2) - self.assertEqual(m1.type(), 'ty1') + self.assertEqual(m1.type(), "ty1") m1.setType(None) - m2.setType('ty2') + m2.setType("ty2") m1.combine(m2) - self.assertEqual(m1.type(), 'ty2') + self.assertEqual(m1.type(), "ty2") - m1.setTitle('t1') + m1.setTitle("t1") m2.setTitle(None) m1.combine(m2) - self.assertEqual(m1.title(), 't1') + self.assertEqual(m1.title(), "t1") m1.setTitle(None) - m2.setTitle('t2') + m2.setTitle("t2") m1.combine(m2) - self.assertEqual(m1.title(), 't2') + self.assertEqual(m1.title(), "t2") - m1.setAbstract('a1') + m1.setAbstract("a1") m2.setAbstract(None) m1.combine(m2) - self.assertEqual(m1.abstract(), 'a1') + self.assertEqual(m1.abstract(), "a1") m1.setAbstract(None) - m2.setAbstract('a2') + m2.setAbstract("a2") m1.combine(m2) - self.assertEqual(m1.abstract(), 'a2') + self.assertEqual(m1.abstract(), "a2") - m1.setHistory(['h1', 'hh1']) + m1.setHistory(["h1", "hh1"]) m2.setHistory([]) m1.combine(m2) - self.assertEqual(m1.history(), ['h1', 'hh1']) + self.assertEqual(m1.history(), ["h1", "hh1"]) m1.setHistory([]) - m2.setHistory(['h2', 'hh2']) + m2.setHistory(["h2", "hh2"]) m1.combine(m2) - self.assertEqual(m1.history(), ['h2', 'hh2']) + self.assertEqual(m1.history(), ["h2", "hh2"]) - m1.setKeywords({'words': ['k1', 'kk1']}) + m1.setKeywords({"words": ["k1", "kk1"]}) m2.setKeywords({}) m1.combine(m2) - self.assertEqual(m1.keywords(), {'words': ['k1', 'kk1']}) + self.assertEqual(m1.keywords(), {"words": ["k1", "kk1"]}) m1.setKeywords({}) - m2.setKeywords({'words': ['k2', 'kk2']}) + m2.setKeywords({"words": ["k2", "kk2"]}) m1.combine(m2) - self.assertEqual(m1.keywords(), {'words': ['k2', 'kk2']}) + self.assertEqual(m1.keywords(), {"words": ["k2", "kk2"]}) - m1.setContacts([QgsLayerMetadata.Contact('c1'), QgsLayerMetadata.Contact('cc1')]) + m1.setContacts( + [QgsLayerMetadata.Contact("c1"), QgsLayerMetadata.Contact("cc1")] + ) m2.setContacts([]) m1.combine(m2) - self.assertEqual(m1.contacts(), [QgsLayerMetadata.Contact('c1'), QgsLayerMetadata.Contact('cc1')]) + self.assertEqual( + m1.contacts(), + [QgsLayerMetadata.Contact("c1"), QgsLayerMetadata.Contact("cc1")], + ) m1.setContacts([]) - m2.setContacts([QgsLayerMetadata.Contact('c2'), QgsLayerMetadata.Contact('cc2')]) + m2.setContacts( + [QgsLayerMetadata.Contact("c2"), QgsLayerMetadata.Contact("cc2")] + ) m1.combine(m2) - self.assertEqual(m1.contacts(), [QgsLayerMetadata.Contact('c2'), QgsLayerMetadata.Contact('cc2')]) + self.assertEqual( + m1.contacts(), + [QgsLayerMetadata.Contact("c2"), QgsLayerMetadata.Contact("cc2")], + ) - m1.setLinks([QgsLayerMetadata.Link('l1'), QgsLayerMetadata.Link('ll1')]) + m1.setLinks([QgsLayerMetadata.Link("l1"), QgsLayerMetadata.Link("ll1")]) m2.setLinks([]) m1.combine(m2) - self.assertEqual(m1.links(), [QgsLayerMetadata.Link('l1'), QgsLayerMetadata.Link('ll1')]) + self.assertEqual( + m1.links(), [QgsLayerMetadata.Link("l1"), QgsLayerMetadata.Link("ll1")] + ) m1.setLinks([]) - m2.setLinks([QgsLayerMetadata.Link('l2'), QgsLayerMetadata.Link('ll2')]) + m2.setLinks([QgsLayerMetadata.Link("l2"), QgsLayerMetadata.Link("ll2")]) m1.combine(m2) - self.assertEqual(m1.links(), [QgsLayerMetadata.Link('l2'), QgsLayerMetadata.Link('ll2')]) + self.assertEqual( + m1.links(), [QgsLayerMetadata.Link("l2"), QgsLayerMetadata.Link("ll2")] + ) - m1.setFees('f1') + m1.setFees("f1") m2.setFees(None) m1.combine(m2) - self.assertEqual(m1.fees(), 'f1') + self.assertEqual(m1.fees(), "f1") m1.setFees(None) - m2.setFees('f2') + m2.setFees("f2") m1.combine(m2) - self.assertEqual(m1.fees(), 'f2') + self.assertEqual(m1.fees(), "f2") - m1.setConstraints([QgsLayerMetadata.Constraint('c1'), QgsLayerMetadata.Constraint('cc1')]) + m1.setConstraints( + [QgsLayerMetadata.Constraint("c1"), QgsLayerMetadata.Constraint("cc1")] + ) m2.setConstraints([]) m1.combine(m2) - self.assertEqual(m1.constraints(), [QgsLayerMetadata.Constraint('c1'), QgsLayerMetadata.Constraint('cc1')]) + self.assertEqual( + m1.constraints(), + [QgsLayerMetadata.Constraint("c1"), QgsLayerMetadata.Constraint("cc1")], + ) m1.setConstraints([]) - m2.setConstraints([QgsLayerMetadata.Constraint('c2'), QgsLayerMetadata.Constraint('cc2')]) + m2.setConstraints( + [QgsLayerMetadata.Constraint("c2"), QgsLayerMetadata.Constraint("cc2")] + ) m1.combine(m2) - self.assertEqual(m1.constraints(), [QgsLayerMetadata.Constraint('c2'), QgsLayerMetadata.Constraint('cc2')]) + self.assertEqual( + m1.constraints(), + [QgsLayerMetadata.Constraint("c2"), QgsLayerMetadata.Constraint("cc2")], + ) - m1.setRights(['r1', 'rr1']) + m1.setRights(["r1", "rr1"]) m2.setRights([]) m1.combine(m2) - self.assertEqual(m1.rights(), ['r1', 'rr1']) + self.assertEqual(m1.rights(), ["r1", "rr1"]) m1.setRights([]) - m2.setRights(['r2', 'rr2']) + m2.setRights(["r2", "rr2"]) m1.combine(m2) - self.assertEqual(m1.rights(), ['r2', 'rr2']) + self.assertEqual(m1.rights(), ["r2", "rr2"]) - m1.setLicenses(['li1', 'lli1']) + m1.setLicenses(["li1", "lli1"]) m2.setLicenses([]) m1.combine(m2) - self.assertEqual(m1.licenses(), ['li1', 'lli1']) + self.assertEqual(m1.licenses(), ["li1", "lli1"]) m1.setLicenses([]) - m2.setLicenses(['li2', 'lli2']) + m2.setLicenses(["li2", "lli2"]) m1.combine(m2) - self.assertEqual(m1.licenses(), ['li2', 'lli2']) + self.assertEqual(m1.licenses(), ["li2", "lli2"]) - m1.setEncoding('e1') + m1.setEncoding("e1") m2.setEncoding(None) m1.combine(m2) - self.assertEqual(m1.encoding(), 'e1') + self.assertEqual(m1.encoding(), "e1") m1.setEncoding(None) - m2.setEncoding('e2') + m2.setEncoding("e2") m1.combine(m2) - self.assertEqual(m1.encoding(), 'e2') + self.assertEqual(m1.encoding(), "e2") - m1.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) + m1.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) m2.setCrs(QgsCoordinateReferenceSystem()) m1.combine(m2) - self.assertEqual(m1.crs().authid(), 'EPSG:3111') + self.assertEqual(m1.crs().authid(), "EPSG:3111") m1.setCrs(QgsCoordinateReferenceSystem()) - m2.setCrs(QgsCoordinateReferenceSystem('EPSG:3113')) + m2.setCrs(QgsCoordinateReferenceSystem("EPSG:3113")) m1.combine(m2) - self.assertEqual(m1.crs().authid(), 'EPSG:3113') + self.assertEqual(m1.crs().authid(), "EPSG:3113") s = QgsLayerMetadata.SpatialExtent() s.bounds = QgsBox3d(1, 2, 3, 4, 5, 6) m1.extent().setSpatialExtents([s]) m2.extent().setSpatialExtents([]) m1.combine(m2) - self.assertEqual(m1.extent().spatialExtents()[0].bounds, QgsBox3d(1, 2, 3, 4, 5, 6)) + self.assertEqual( + m1.extent().spatialExtents()[0].bounds, QgsBox3d(1, 2, 3, 4, 5, 6) + ) s.bounds = QgsBox3d(11, 12, 13, 14, 15, 16) m1.extent().setSpatialExtents([]) m2.extent().setSpatialExtents([s]) m1.combine(m2) - self.assertEqual(m1.extent().spatialExtents()[0].bounds, QgsBox3d(11, 12, 13, 14, 15, 16)) + self.assertEqual( + m1.extent().spatialExtents()[0].bounds, QgsBox3d(11, 12, 13, 14, 15, 16) + ) - s = QgsDateTimeRange(QDateTime(2020, 1, 1, 0, 0, 0), QDateTime(2020, 2, 1, 0, 0, 0)) + s = QgsDateTimeRange( + QDateTime(2020, 1, 1, 0, 0, 0), QDateTime(2020, 2, 1, 0, 0, 0) + ) m1.extent().setTemporalExtents([s]) m2.extent().setTemporalExtents([]) m1.combine(m2) self.assertEqual(m1.extent().temporalExtents()[0], s) - s = QgsDateTimeRange(QDateTime(2021, 1, 1, 0, 0, 0), QDateTime(2021, 2, 1, 0, 0, 0)) + s = QgsDateTimeRange( + QDateTime(2021, 1, 1, 0, 0, 0), QDateTime(2021, 2, 1, 0, 0, 0) + ) m1.extent().setTemporalExtents([]) m2.extent().setTemporalExtents([s]) m1.combine(m2) @@ -679,28 +749,28 @@ def testContainsAndMatches(self): m = self.createTestMetadata() - self.assertFalse(m.contains('XXXX')) - self.assertTrue(m.contains('23')) - relist = [QRegularExpression('XXXX')] + self.assertFalse(m.contains("XXXX")) + self.assertTrue(m.contains("23")) + relist = [QRegularExpression("XXXX")] self.assertFalse(m.matches(relist)) - relist = [QRegularExpression('23')] + relist = [QRegularExpression("23")] self.assertTrue(m.matches(relist)) - self.assertTrue(m.contains('W1')) - relist = [QRegularExpression('w1'), QRegularExpression('XXXX')] + self.assertTrue(m.contains("W1")) + relist = [QRegularExpression("w1"), QRegularExpression("XXXX")] self.assertTrue(m.matches(relist)) - self.assertTrue(m.contains('uRal')) - relist = [QRegularExpression('ural'), QRegularExpression('XXXX')] + self.assertTrue(m.contains("uRal")) + relist = [QRegularExpression("ural"), QRegularExpression("XXXX")] self.assertTrue(m.matches(relist)) - self.assertTrue(m.contains('My Ro')) - relist = [QRegularExpression('my ro'), QRegularExpression('XXXX')] + self.assertTrue(m.contains("My Ro")) + relist = [QRegularExpression("my ro"), QRegularExpression("XXXX")] self.assertTrue(m.matches(relist)) - self.assertFalse(m.contains('')) - self.assertFalse(m.contains(' ')) + self.assertFalse(m.contains("")) + self.assertFalse(m.contains(" ")) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayermetadataprovider_ogr.py b/tests/src/python/test_qgslayermetadataprovider_ogr.py index a32306efb4db..aadd5f67cf17 100644 --- a/tests/src/python/test_qgslayermetadataprovider_ogr.py +++ b/tests/src/python/test_qgslayermetadataprovider_ogr.py @@ -7,9 +7,9 @@ """ -__author__ = 'elpaso@itopen.it' -__date__ = '2022-08-19' -__copyright__ = 'Copyright 2022, ItOpen' +__author__ = "elpaso@itopen.it" +__date__ = "2022-08-19" +__copyright__ = "Copyright 2022, ItOpen" import os import shutil @@ -24,15 +24,19 @@ ) -class TestPostgresLayerMetadataProvider(unittest.TestCase, LayerMetadataProviderTestBase): +class TestPostgresLayerMetadataProvider( + unittest.TestCase, LayerMetadataProviderTestBase +): def getMetadataProviderId(self) -> str: - return 'ogr' + return "ogr" def getLayer(self) -> QgsVectorLayer: - return QgsVectorLayer(f'{self.getConnectionUri()}|layername=geopackage', "someData", 'ogr') + return QgsVectorLayer( + f"{self.getConnectionUri()}|layername=geopackage", "someData", "ogr" + ) def getConnectionUri(self) -> str: @@ -43,13 +47,13 @@ def setUp(self): super().setUp() self.temp_dir = QTemporaryDir() self.temp_path = self.temp_dir.path() - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - shutil.copy(os.path.join(srcpath, 'geopackage.gpkg'), self.temp_path) - self.conn = os.path.join(self.temp_path, 'geopackage.gpkg') - md = QgsProviderRegistry.instance().providerMetadata('ogr') + srcpath = os.path.join(TEST_DATA_DIR, "provider") + shutil.copy(os.path.join(srcpath, "geopackage.gpkg"), self.temp_path) + self.conn = os.path.join(self.temp_path, "geopackage.gpkg") + md = QgsProviderRegistry.instance().providerMetadata("ogr") conn = md.createConnection(self.getConnectionUri(), {}) - conn.store('OGR Metadata Enabled Connection') + conn.store("OGR Metadata Enabled Connection") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayermetadataprovider_postgres.py b/tests/src/python/test_qgslayermetadataprovider_postgres.py index cada961cc74d..2d0108ffef66 100644 --- a/tests/src/python/test_qgslayermetadataprovider_postgres.py +++ b/tests/src/python/test_qgslayermetadataprovider_postgres.py @@ -7,9 +7,9 @@ """ -__author__ = 'elpaso@itopen.it' -__date__ = '2022-08-19' -__copyright__ = 'Copyright 2022, ItOpen' +__author__ = "elpaso@itopen.it" +__date__ = "2022-08-19" +__copyright__ = "Copyright 2022, ItOpen" import os @@ -19,43 +19,49 @@ from qgslayermetadataprovidertestbase import LayerMetadataProviderTestBase -class TestPostgresLayerMetadataProvider(unittest.TestCase, LayerMetadataProviderTestBase): +class TestPostgresLayerMetadataProvider( + unittest.TestCase, LayerMetadataProviderTestBase +): def getMetadataProviderId(self) -> str: - return 'postgres' + return "postgres" def getLayer(self): - return QgsVectorLayer(f'{self.getConnectionUri()} type=Point table="qgis_test"."someData" (geom) sql=', "someData", 'postgres') + return QgsVectorLayer( + f'{self.getConnectionUri()} type=Point table="qgis_test"."someData" (geom) sql=', + "someData", + "postgres", + ) def getConnectionUri(self) -> str: - dbconn = 'service=qgis_test' + dbconn = "service=qgis_test" - if 'QGIS_PGTEST_DB' in os.environ: - dbconn = os.environ['QGIS_PGTEST_DB'] + if "QGIS_PGTEST_DB" in os.environ: + dbconn = os.environ["QGIS_PGTEST_DB"] return dbconn def clearMetadataTable(self): - self.conn.execSql('DROP TABLE IF EXISTS qgis_test.qgis_layer_metadata') - self.conn.execSql('DROP TABLE IF EXISTS public.qgis_layer_metadata') + self.conn.execSql("DROP TABLE IF EXISTS qgis_test.qgis_layer_metadata") + self.conn.execSql("DROP TABLE IF EXISTS public.qgis_layer_metadata") def setUp(self): super().setUp() - dbconn = 'service=qgis_test' + dbconn = "service=qgis_test" - if 'QGIS_PGTEST_DB' in os.environ: - dbconn = os.environ['QGIS_PGTEST_DB'] + if "QGIS_PGTEST_DB" in os.environ: + dbconn = os.environ["QGIS_PGTEST_DB"] - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.getConnectionUri(), {}) - conn.setConfiguration({'metadataInDatabase': True}) - conn.store('PG Metadata Enabled Connection') + conn.setConfiguration({"metadataInDatabase": True}) + conn.store("PG Metadata Enabled Connection") self.conn = conn self.clearMetadataTable() @@ -65,5 +71,5 @@ def tearDown(self): self.clearMetadataTable() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayermetadataprovider_postgresraster.py b/tests/src/python/test_qgslayermetadataprovider_postgresraster.py index a3eae1f8077b..58a3b9160bf5 100644 --- a/tests/src/python/test_qgslayermetadataprovider_postgresraster.py +++ b/tests/src/python/test_qgslayermetadataprovider_postgresraster.py @@ -7,9 +7,9 @@ """ -__author__ = 'elpaso@itopen.it' -__date__ = '2022-08-19' -__copyright__ = 'Copyright 2022, ItOpen' +__author__ = "elpaso@itopen.it" +__date__ = "2022-08-19" +__copyright__ = "Copyright 2022, ItOpen" import os @@ -19,47 +19,53 @@ from qgslayermetadataprovidertestbase import LayerMetadataProviderTestBase -class TestPostgresLayerMetadataProvider(unittest.TestCase, LayerMetadataProviderTestBase): +class TestPostgresLayerMetadataProvider( + unittest.TestCase, LayerMetadataProviderTestBase +): def getMetadataProviderId(self): - return 'postgres' + return "postgres" def getLayer(self): - return QgsRasterLayer(f'{self.getConnectionUri()} table="qgis_test"."Raster1" (Rast)', "someData", 'postgresraster') + return QgsRasterLayer( + f'{self.getConnectionUri()} table="qgis_test"."Raster1" (Rast)', + "someData", + "postgresraster", + ) def getConnectionUri(self) -> str: - dbconn = 'service=qgis_test' + dbconn = "service=qgis_test" - if 'QGIS_PGTEST_DB' in os.environ: - dbconn = os.environ['QGIS_PGTEST_DB'] + if "QGIS_PGTEST_DB" in os.environ: + dbconn = os.environ["QGIS_PGTEST_DB"] return dbconn def clearMetadataTable(self): - self.conn.execSql('DROP TABLE IF EXISTS qgis_test.qgis_layer_metadata') - self.conn.execSql('DROP TABLE IF EXISTS public.qgis_layer_metadata') + self.conn.execSql("DROP TABLE IF EXISTS qgis_test.qgis_layer_metadata") + self.conn.execSql("DROP TABLE IF EXISTS public.qgis_layer_metadata") def setUp(self): super().setUp() - dbconn = 'service=qgis_test' + dbconn = "service=qgis_test" - if 'QGIS_PGTEST_DB' in os.environ: - dbconn = os.environ['QGIS_PGTEST_DB'] + if "QGIS_PGTEST_DB" in os.environ: + dbconn = os.environ["QGIS_PGTEST_DB"] - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.getConnectionUri(), {}) - conn.execSql('DROP TABLE IF EXISTS qgis_test.qgis_layer_metadata') - conn.setConfiguration({'metadataInDatabase': True}) - conn.store('PG Metadata Enabled Connection') + conn.execSql("DROP TABLE IF EXISTS qgis_test.qgis_layer_metadata") + conn.setConfiguration({"metadataInDatabase": True}) + conn.store("PG Metadata Enabled Connection") self.conn = conn self.clearMetadataTable() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayermetadataprovider_python.py b/tests/src/python/test_qgslayermetadataprovider_python.py index a30a2b44c4c3..a3048106d356 100644 --- a/tests/src/python/test_qgslayermetadataprovider_python.py +++ b/tests/src/python/test_qgslayermetadataprovider_python.py @@ -7,9 +7,9 @@ """ -__author__ = 'elpaso@itopen.it' -__date__ = '2022-08-19' -__copyright__ = 'Copyright 2022, ItOpen' +__author__ = "elpaso@itopen.it" +__date__ = "2022-08-19" +__copyright__ = "Copyright 2022, ItOpen" import os import shutil @@ -52,9 +52,9 @@ def __init__(self): super().__init__() def id(self): - return 'python' + return "python" - def search(self, searchString='', geographicExtent=QgsRectangle(), feedback=None): + def search(self, searchString="", geographicExtent=QgsRectangle(), feedback=None): xml_md = """ @@ -94,22 +94,22 @@ def search(self, searchString='', geographicExtent=QgsRectangle(), feedback=None assert metadata.readMetadataXml(doc.documentElement()) result = QgsLayerMetadataProviderResult(metadata) - result.setStandardUri('http://mrcc.com/qgis.dtd') + result.setStandardUri("http://mrcc.com/qgis.dtd") result.setLayerType(QgsMapLayerType.VectorLayer) - result.setUri(os.path.join(temp_path, 'geopackage.gpkg')) - result.setAuthid('EPSG:4326') - result.setDataProviderName('ogr') + result.setUri(os.path.join(temp_path, "geopackage.gpkg")) + result.setAuthid("EPSG:4326") + result.setDataProviderName("ogr") result.setGeometryType(QgsWkbTypes.GeometryType.PointGeometry) poly = QgsPolygon() poly.fromWkt(QgsRectangle(0, 0, 1, 1).asWktPolygon()) result.setGeographicExtent(poly) - assert result.identifier() == 'MD012345' + assert result.identifier() == "MD012345" results = QgsLayerMetadataSearchResults() results.addMetadata(result) - results.addError('Bad news from PythonLayerMetadataProvider :(') + results.addError("Bad news from PythonLayerMetadataProvider :(") return results @@ -122,22 +122,24 @@ class TestPythonLayerMetadataProvider(QgisTestCase): def setUp(self): super().setUp() - srcpath = os.path.join(TEST_DATA_DIR, 'provider') - self.conn = os.path.join(temp_path, 'geopackage.gpkg') + srcpath = os.path.join(TEST_DATA_DIR, "provider") + self.conn = os.path.join(temp_path, "geopackage.gpkg") # Create a truncated file so that we get an exception later - open(self.conn, "wb").write(open(os.path.join(srcpath, 'geopackage.gpkg'), "rb").read(8192)) + open(self.conn, "wb").write( + open(os.path.join(srcpath, "geopackage.gpkg"), "rb").read(8192) + ) - shutil.copy(os.path.join(srcpath, 'spatialite.db'), temp_path) - self.conn_sl = os.path.join(temp_path, 'spatialite.db') + shutil.copy(os.path.join(srcpath, "spatialite.db"), temp_path) + self.conn_sl = os.path.join(temp_path, "spatialite.db") def test_metadataRegistryApi(self): reg = QGIS_APP.layerMetadataProviderRegistry() - self.assertIsNone(reg.layerMetadataProviderFromId('python')) + self.assertIsNone(reg.layerMetadataProviderFromId("python")) reg.registerLayerMetadataProvider(PythonLayerMetadataProvider()) - self.assertIsNotNone(reg.layerMetadataProviderFromId('python')) + self.assertIsNotNone(reg.layerMetadataProviderFromId("python")) - md_provider = reg.layerMetadataProviderFromId('python') + md_provider = reg.layerMetadataProviderFromId("python") results = md_provider.search(QgsMetadataSearchContext()) self.assertEqual(len(results.metadata()), 1) @@ -145,29 +147,29 @@ def test_metadataRegistryApi(self): result = results.metadata()[0] - self.assertEqual(result.abstract(), 'QGIS Some Data') - self.assertEqual(result.identifier(), 'MD012345') - self.assertEqual(result.title(), 'QGIS Test Title') + self.assertEqual(result.abstract(), "QGIS Some Data") + self.assertEqual(result.identifier(), "MD012345") + self.assertEqual(result.title(), "QGIS Test Title") self.assertEqual(result.layerType(), QgsMapLayerType.VectorLayer) - self.assertEqual(result.authid(), 'EPSG:4326') + self.assertEqual(result.authid(), "EPSG:4326") self.assertEqual(result.geometryType(), QgsWkbTypes.GeometryType.PointGeometry) - self.assertEqual(result.dataProviderName(), 'ogr') - self.assertEqual(result.standardUri(), 'http://mrcc.com/qgis.dtd') + self.assertEqual(result.dataProviderName(), "ogr") + self.assertEqual(result.standardUri(), "http://mrcc.com/qgis.dtd") reg.unregisterLayerMetadataProvider(md_provider) - self.assertIsNone(reg.layerMetadataProviderFromId('python')) + self.assertIsNone(reg.layerMetadataProviderFromId("python")) def testExceptions(self): def _spatialite(path): - md = QgsProviderRegistry.instance().providerMetadata('spatialite') + md = QgsProviderRegistry.instance().providerMetadata("spatialite") conn = md.createConnection(path, {}) conn.searchLayerMetadata(QgsMetadataSearchContext()) def _ogr(path): - md = QgsProviderRegistry.instance().providerMetadata('ogr') + md = QgsProviderRegistry.instance().providerMetadata("ogr") conn = md.createConnection(path, {}) os.chmod(path, S_IREAD | S_IRGRP | S_IROTH) conn.searchLayerMetadata(QgsMetadataSearchContext()) @@ -179,5 +181,5 @@ def _ogr(path): os.chmod(self.conn_sl, S_IWUSR | S_IREAD) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayermetadataresultsmodel.py b/tests/src/python/test_qgslayermetadataresultsmodel.py index 282e8e0b35de..f4bfceabb43e 100644 --- a/tests/src/python/test_qgslayermetadataresultsmodel.py +++ b/tests/src/python/test_qgslayermetadataresultsmodel.py @@ -7,9 +7,9 @@ """ -__author__ = 'elpaso@itopen.it' -__date__ = '2022-08-19' -__copyright__ = 'Copyright 2022, ItOpen' +__author__ = "elpaso@itopen.it" +__date__ = "2022-08-19" +__copyright__ = "Copyright 2022, ItOpen" import os import unittest @@ -43,8 +43,7 @@ class TestQgsLayerMetadataResultModels(TestCase): - """Base test for layer metadata provider models - """ + """Base test for layer metadata provider models""" @classmethod def setUpClass(cls): @@ -60,56 +59,87 @@ def setUp(self): self.temp_dir = QTemporaryDir() self.temp_path = self.temp_dir.path() - self.temp_gpkg = os.path.join(self.temp_path, 'test.gpkg') + self.temp_gpkg = os.path.join(self.temp_path, "test.gpkg") - ds = ogr.GetDriverByName('GPKG').CreateDataSource(self.temp_gpkg) + ds = ogr.GetDriverByName("GPKG").CreateDataSource(self.temp_gpkg) - md = QgsProviderRegistry.instance().providerMetadata('ogr') + md = QgsProviderRegistry.instance().providerMetadata("ogr") self.assertIsNotNone(md) - self.assertTrue(bool(md.providerCapabilities() & QgsProviderMetadata.ProviderCapability.SaveLayerMetadata)) + self.assertTrue( + bool( + md.providerCapabilities() + & QgsProviderMetadata.ProviderCapability.SaveLayerMetadata + ) + ) self.conn = md.createConnection(self.temp_gpkg, {}) - self.conn.store('test_conn') + self.conn.store("test_conn") for i in range(NUM_LAYERS): - lyr = ds.CreateLayer(f"layer_{i}", geom_type=ogr.wkbPoint, options=['SPATIAL_INDEX=NO']) - lyr.CreateField(ogr.FieldDefn('text_field', ogr.OFTString)) + lyr = ds.CreateLayer( + f"layer_{i}", geom_type=ogr.wkbPoint, options=["SPATIAL_INDEX=NO"] + ) + lyr.CreateField(ogr.FieldDefn("text_field", ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) - f['text_field'] = 'foo' - f.SetGeometry(ogr.CreateGeometryFromWkt(f'POINT({i} {i + 0.01})')) + f["text_field"] = "foo" + f.SetGeometry(ogr.CreateGeometryFromWkt(f"POINT({i} {i + 0.01})")) lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) - f['text_field'] = 'bar' - f.SetGeometry(ogr.CreateGeometryFromWkt(f'POINT({i + 0.03} {i + 0.04})')) + f["text_field"] = "bar" + f.SetGeometry(ogr.CreateGeometryFromWkt(f"POINT({i + 0.03} {i + 0.04})")) lyr.CreateFeature(f) f = None ds = None fields = QgsFields() - fields.append(QgsField('name', QVariant.String)) - self.conn.createVectorTable('', 'aspatial', fields, QgsWkbTypes.Type.NoGeometry, QgsCoordinateReferenceSystem(), False, {}) - self.conn.createVectorTable('', 'linestring', fields, QgsWkbTypes.Type.LineString, QgsCoordinateReferenceSystem(), False, {}) - vl = QgsVectorLayer(self.conn.tableUri('', 'linestring')) + fields.append(QgsField("name", QVariant.String)) + self.conn.createVectorTable( + "", + "aspatial", + fields, + QgsWkbTypes.Type.NoGeometry, + QgsCoordinateReferenceSystem(), + False, + {}, + ) + self.conn.createVectorTable( + "", + "linestring", + fields, + QgsWkbTypes.Type.LineString, + QgsCoordinateReferenceSystem(), + False, + {}, + ) + vl = QgsVectorLayer(self.conn.tableUri("", "linestring")) self.assertTrue(vl.isValid()) self.assertTrue(vl.startEditing()) f = QgsFeature(vl.fields()) - f.setAttribute('name', 'one') - f.setGeometry(QgsGeometry.fromWkt('LINESTRING(0 0, 1 1, 2 2)')) + f.setAttribute("name", "one") + f.setGeometry(QgsGeometry.fromWkt("LINESTRING(0 0, 1 1, 2 2)")) vl.addFeatures([f]) self.assertTrue(vl.commitChanges()) - self.conn.createVectorTable('', 'polygon', fields, QgsWkbTypes.Type.Polygon, QgsCoordinateReferenceSystem(), False, {}) - vl = QgsVectorLayer(self.conn.tableUri('', 'polygon')) + self.conn.createVectorTable( + "", + "polygon", + fields, + QgsWkbTypes.Type.Polygon, + QgsCoordinateReferenceSystem(), + False, + {}, + ) + vl = QgsVectorLayer(self.conn.tableUri("", "polygon")) self.assertTrue(vl.isValid()) self.assertTrue(vl.startEditing()) f = QgsFeature(vl.fields()) - f.setAttribute('name', 'one') - f.setGeometry(QgsGeometry.fromWkt('POLYGON((0 0, 1 1, 0 2, 0 0))')) + f.setAttribute("name", "one") + f.setGeometry(QgsGeometry.fromWkt("POLYGON((0 0, 1 1, 0 2, 0 0))")) vl.addFeatures([f]) self.assertTrue(vl.commitChanges()) for t in self.conn.tables(): - layer_uri = self.conn.tableUri('', t.tableName()) - vl = QgsVectorLayer(layer_uri, t.tableName(), 'ogr') + layer_uri = self.conn.tableUri("", t.tableName()) + vl = QgsVectorLayer(layer_uri, t.tableName(), "ogr") self.assertTrue(vl.isValid()) metadata = vl.metadata() ext = QgsLayerMetadata.Extent() @@ -127,36 +157,56 @@ def testModels(self): model = QgsLayerMetadataResultsModel(search_context) proxy_model = QgsLayerMetadataResultsProxyModel() proxy_model.setSourceModel(model) - tester = QAbstractItemModelTester(proxy_model, QAbstractItemModelTester.FailureReportingMode.Fatal) + tester = QAbstractItemModelTester( + proxy_model, QAbstractItemModelTester.FailureReportingMode.Fatal + ) model.reload() - proxy_model.setFilterString('_1') + proxy_model.setFilterString("_1") self.assertEqual(proxy_model.rowCount(), 11) - proxy_model.setFilterString('_11') + proxy_model.setFilterString("_11") self.assertEqual(proxy_model.rowCount(), 1) - metadata = proxy_model.data(proxy_model.index(0, 0), QgsLayerMetadataResultsModel.Roles.Metadata) - self.assertEqual(metadata.identifier(), 'layer_11') - proxy_model.setFilterString('') + metadata = proxy_model.data( + proxy_model.index(0, 0), QgsLayerMetadataResultsModel.Roles.Metadata + ) + self.assertEqual(metadata.identifier(), "layer_11") + proxy_model.setFilterString("") self.assertEqual(proxy_model.rowCount(), len(self.conn.tables())) proxy_model.setFilterExtent(QgsRectangle(0, 0, 2, 2.001)) - self.assertEqual({proxy_model.data(proxy_model.index(i, 0)) for i in range(proxy_model.rowCount())}, {'layer_0', 'layer_1', 'linestring', 'polygon'}) + self.assertEqual( + { + proxy_model.data(proxy_model.index(i, 0)) + for i in range(proxy_model.rowCount()) + }, + {"layer_0", "layer_1", "linestring", "polygon"}, + ) self.assertEqual(proxy_model.rowCount(), 4) model.reload() self.assertEqual(proxy_model.rowCount(), 4) proxy_model.setFilterExtent(QgsRectangle()) - metadata = proxy_model.data(proxy_model.index(0, 0), QgsLayerMetadataResultsModel.Roles.Metadata) - self.assertEqual(metadata.identifier(), 'layer_0') + metadata = proxy_model.data( + proxy_model.index(0, 0), QgsLayerMetadataResultsModel.Roles.Metadata + ) + self.assertEqual(metadata.identifier(), "layer_0") proxy_model.sort(0, Qt.SortOrder.DescendingOrder) - metadata = proxy_model.data(proxy_model.index(0, 0), QgsLayerMetadataResultsModel.Roles.Metadata) - self.assertEqual(metadata.identifier(), 'polygon') + metadata = proxy_model.data( + proxy_model.index(0, 0), QgsLayerMetadataResultsModel.Roles.Metadata + ) + self.assertEqual(metadata.identifier(), "polygon") proxy_model.setFilterGeometryType(QgsWkbTypes.GeometryType.PolygonGeometry) proxy_model.setFilterGeometryTypeEnabled(True) - self.assertEqual({proxy_model.data(proxy_model.index(i, 0)) for i in range(proxy_model.rowCount())}, {'polygon'}) + self.assertEqual( + { + proxy_model.data(proxy_model.index(i, 0)) + for i in range(proxy_model.rowCount()) + }, + {"polygon"}, + ) proxy_model.setFilterGeometryTypeEnabled(False) self.assertEqual(proxy_model.rowCount(), len(self.conn.tables())) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayertree.py b/tests/src/python/test_qgslayertree.py index 6bb75941a30b..90cdd41d900d 100644 --- a/tests/src/python/test_qgslayertree.py +++ b/tests/src/python/test_qgslayertree.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Matthias Kuhn' -__date__ = '22.3.2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Matthias Kuhn" +__date__ = "22.3.2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os from tempfile import TemporaryDirectory @@ -39,21 +40,22 @@ def __init__(self, methodName): QgisTestCase.__init__(self, methodName) def testCustomLayerOrder(self): - """ test project layer order""" + """test project layer order""" prj = QgsProject() - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") - layer3 = QgsVectorLayer("Point?field=fldtxt:string", - "layer3", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") + layer3 = QgsVectorLayer("Point?field=fldtxt:string", "layer3", "memory") prj.addMapLayers([layer, layer2, layer3]) - layer_order_changed_spy = QSignalSpy(prj.layerTreeRoot().customLayerOrderChanged) + layer_order_changed_spy = QSignalSpy( + prj.layerTreeRoot().customLayerOrderChanged + ) prj.layerTreeRoot().setCustomLayerOrder([layer2, layer]) self.assertEqual(len(layer_order_changed_spy), 1) prj.layerTreeRoot().setCustomLayerOrder([layer2, layer]) - self.assertEqual(len(layer_order_changed_spy), 1) # no signal, order not changed + self.assertEqual( + len(layer_order_changed_spy), 1 + ) # no signal, order not changed self.assertEqual(prj.layerTreeRoot().customLayerOrder(), [layer2, layer]) prj.layerTreeRoot().setCustomLayerOrder([layer]) @@ -68,23 +70,24 @@ def testCustomLayerOrder(self): self.assertEqual(len(layer_order_changed_spy), 4) # save and restore - file_name = os.path.join(QDir.tempPath(), 'proj.qgs') + file_name = os.path.join(QDir.tempPath(), "proj.qgs") prj.setFileName(file_name) prj.write() prj2 = QgsProject() prj2.setFileName(file_name) prj2.read() - self.assertEqual([l.id() for l in prj2.layerTreeRoot().customLayerOrder()], [layer2.id(), layer3.id()]) + self.assertEqual( + [l.id() for l in prj2.layerTreeRoot().customLayerOrder()], + [layer2.id(), layer3.id()], + ) # clear project prj.clear() self.assertEqual(prj.layerTreeRoot().customLayerOrder(), []) def testCustomLayerOrderChanged(self): - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") layer_tree = QgsLayerTree() layer_order_changed_spy = QSignalSpy(layer_tree.customLayerOrderChanged) @@ -103,33 +106,32 @@ def testCustomLayerOrderChanged(self): self.assertEqual(len(layer_order_changed_spy), 4) def testNodeCustomProperties(self): - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") layer1_node = QgsLayerTreeLayer(layer) spy = QSignalSpy(layer1_node.customPropertyChanged) - self.assertFalse(layer1_node.customProperty('test')) - self.assertNotIn('test', layer1_node.customProperties()) + self.assertFalse(layer1_node.customProperty("test")) + self.assertNotIn("test", layer1_node.customProperties()) - layer1_node.setCustomProperty('test', 'value') + layer1_node.setCustomProperty("test", "value") self.assertEqual(len(spy), 1) # set to same value, should be no extra signal - layer1_node.setCustomProperty('test', 'value') + layer1_node.setCustomProperty("test", "value") self.assertEqual(len(spy), 1) - self.assertIn('test', layer1_node.customProperties()) - self.assertEqual(layer1_node.customProperty('test'), 'value') - layer1_node.setCustomProperty('test', 'value2') + self.assertIn("test", layer1_node.customProperties()) + self.assertEqual(layer1_node.customProperty("test"), "value") + layer1_node.setCustomProperty("test", "value2") self.assertEqual(len(spy), 2) - self.assertIn('test', layer1_node.customProperties()) - self.assertEqual(layer1_node.customProperty('test'), 'value2') + self.assertIn("test", layer1_node.customProperties()) + self.assertEqual(layer1_node.customProperty("test"), "value2") - layer1_node.removeCustomProperty('test') + layer1_node.removeCustomProperty("test") self.assertEqual(len(spy), 3) - self.assertFalse(layer1_node.customProperty('test')) - self.assertNotIn('test', layer1_node.customProperties()) + self.assertFalse(layer1_node.customProperty("test")) + self.assertNotIn("test", layer1_node.customProperties()) # already removed, should be no extra signal - layer1_node.removeCustomProperty('test') + layer1_node.removeCustomProperty("test") self.assertEqual(len(spy), 3) def test_layer_tree_group_layer(self): @@ -137,7 +139,7 @@ def test_layer_tree_group_layer(self): Test setting a group layer on a QgsLayerTreeGroup """ options = QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) - group_layer = QgsGroupLayer('group', options) + group_layer = QgsGroupLayer("group", options) group_node = QgsLayerTreeGroup() self.assertFalse(group_node.groupLayer()) @@ -153,7 +155,7 @@ def test_layer_tree_group_layer(self): def test_copy_layer_tree_group(self): # copying layer tree group should also copy group layer setting options = QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) - group_layer = QgsGroupLayer('group', options) + group_layer = QgsGroupLayer("group", options) group_node = QgsLayerTreeGroup() group_node.setGroupLayer(group_layer) @@ -178,11 +180,9 @@ def test_convert_group_to_group_layer(self): group_node.setGroupLayer(None) # add some child layers to node - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") group_node.addLayer(layer) - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") group_node.addLayer(layer2) group_layer = group_node.convertToGroupLayer(options) @@ -194,14 +194,12 @@ def test_restore_group_node_group_layer(self): Test that group node's QgsGroupLayers are restored with projects """ p = QgsProject() - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") p.addMapLayer(layer, False) - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") p.addMapLayer(layer2, False) - group_node = p.layerTreeRoot().addGroup('my group') + group_node = p.layerTreeRoot().addGroup("my group") group_node.addLayer(layer) group_node.addLayer(layer2) options = QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) @@ -209,7 +207,7 @@ def test_restore_group_node_group_layer(self): p.addMapLayer(group_layer, False) with TemporaryDirectory() as d: - path = os.path.join(d, 'group_layers.qgs') + path = os.path.join(d, "group_layers.qgs") p.setFileName(path) p.write() @@ -218,47 +216,44 @@ def test_restore_group_node_group_layer(self): p2.read(path) restored_group_node = p2.layerTreeRoot().children()[0] - self.assertEqual(restored_group_node.name(), 'my group') + self.assertEqual(restored_group_node.name(), "my group") restored_group_layer = restored_group_node.groupLayer() self.assertIsNotNone(restored_group_layer) - self.assertEqual(restored_group_layer.childLayers()[0].name(), 'layer2') - self.assertEqual(restored_group_layer.childLayers()[1].name(), 'layer1') + self.assertEqual(restored_group_layer.childLayers()[0].name(), "layer2") + self.assertEqual(restored_group_layer.childLayers()[1].name(), "layer1") def test_group_layer_updates_from_node(self): """ Test that group layer child layers are synced correctly from the group node """ - group_node = QgsLayerTreeGroup('my group') + group_node = QgsLayerTreeGroup("my group") options = QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) group_layer = group_node.convertToGroupLayer(options) self.assertFalse(group_layer.childLayers()) - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") group_node.addLayer(layer) self.assertEqual(group_layer.childLayers(), [layer]) - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") group_node.insertLayer(0, layer2) self.assertEqual(group_layer.childLayers(), [layer, layer2]) - layer3 = QgsVectorLayer("Point?field=fldtxt:string", - "layer3", "memory") - layer4 = QgsVectorLayer("Point?field=fldtxt:string", - "layer4", "memory") + layer3 = QgsVectorLayer("Point?field=fldtxt:string", "layer3", "memory") + layer4 = QgsVectorLayer("Point?field=fldtxt:string", "layer4", "memory") layer3_node = QgsLayerTreeLayer(layer3) layer4_node = QgsLayerTreeLayer(layer4) group_node.insertChildNodes(1, [layer3_node, layer4_node]) self.assertEqual(group_layer.childLayers(), [layer, layer4, layer3, layer2]) - layer5 = QgsVectorLayer("Point?field=fldtxt:string", - "layer5", "memory") + layer5 = QgsVectorLayer("Point?field=fldtxt:string", "layer5", "memory") layer5_node = QgsLayerTreeLayer(layer5) group_node.addChildNode(layer5_node) - self.assertEqual(group_layer.childLayers(), [layer5, layer, layer4, layer3, layer2]) + self.assertEqual( + group_layer.childLayers(), [layer5, layer, layer4, layer3, layer2] + ) group_node.removeChildNode(layer3_node) self.assertEqual(group_layer.childLayers(), [layer5, layer, layer4, layer2]) @@ -276,19 +271,16 @@ def test_group_layer_updates_from_node_visibility(self): """ Test that group layer child layers are synced correctly from the group node when layer visibility is changed """ - group_node = QgsLayerTreeGroup('my group') + group_node = QgsLayerTreeGroup("my group") options = QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) group_layer = group_node.convertToGroupLayer(options) self.assertFalse(group_layer.childLayers()) - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") group_node.addLayer(layer) - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") layer2_node = group_node.addLayer(layer2) - layer3 = QgsVectorLayer("Point?field=fldtxt:string", - "layer3", "memory") + layer3 = QgsVectorLayer("Point?field=fldtxt:string", "layer3", "memory") group_node.addLayer(layer3) self.assertEqual(group_layer.childLayers(), [layer3, layer2, layer]) @@ -302,34 +294,31 @@ def test_group_layer_nested(self): """ Test group node with child nodes converted to group layer """ - group_node = QgsLayerTreeGroup('my group') + group_node = QgsLayerTreeGroup("my group") options = QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) group_layer = group_node.convertToGroupLayer(options) self.assertFalse(group_layer.childLayers()) - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") group_node.addLayer(layer) - group2 = group_node.addGroup('child group 1') - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") + group2 = group_node.addGroup("child group 1") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") group_node.addLayer(layer2) - layer3 = QgsVectorLayer("Point?field=fldtxt:string", - "layer3", "memory") + layer3 = QgsVectorLayer("Point?field=fldtxt:string", "layer3", "memory") layer3_node = group2.addLayer(layer3) - group3 = group2.addGroup('grand child group 1') - group4 = group2.addGroup('grand child group 2') + group3 = group2.addGroup("grand child group 1") + group4 = group2.addGroup("grand child group 2") - layer4 = QgsVectorLayer("Point?field=fldtxt:string", - "layer4", "memory") + layer4 = QgsVectorLayer("Point?field=fldtxt:string", "layer4", "memory") layer4_node = group3.addLayer(layer4) - layer5 = QgsVectorLayer("Point?field=fldtxt:string", - "layer5", "memory") + layer5 = QgsVectorLayer("Point?field=fldtxt:string", "layer5", "memory") layer5_node = group4.addLayer(layer5) - self.assertEqual(group_layer.childLayers(), [layer2, layer5, layer4, layer3, layer]) + self.assertEqual( + group_layer.childLayers(), [layer2, layer5, layer4, layer3, layer] + ) layer5_node.setItemVisibilityChecked(False) self.assertEqual(group_layer.childLayers(), [layer2, layer4, layer3, layer]) @@ -337,33 +326,33 @@ def test_group_layer_nested(self): group2.setItemVisibilityChecked(False) self.assertEqual(group_layer.childLayers(), [layer2, layer]) group2.setItemVisibilityCheckedRecursive(True) - self.assertEqual(group_layer.childLayers(), [layer2, layer5, layer4, layer3, layer]) + self.assertEqual( + group_layer.childLayers(), [layer2, layer5, layer4, layer3, layer] + ) def test_layer_order_with_group_layer(self): """ Test retrieving layer order with group layers present """ p = QgsProject() - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") p.addMapLayer(layer, False) - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") p.addMapLayer(layer2, False) - layer3 = QgsVectorLayer("Point?field=fldtxt:string", - "layer3", "memory") + layer3 = QgsVectorLayer("Point?field=fldtxt:string", "layer3", "memory") p.addMapLayer(layer3, False) - layer4 = QgsVectorLayer("Point?field=fldtxt:string", - "layer4", "memory") + layer4 = QgsVectorLayer("Point?field=fldtxt:string", "layer4", "memory") p.addMapLayer(layer4, False) p.layerTreeRoot().addLayer(layer) - group_node = p.layerTreeRoot().addGroup('my group') + group_node = p.layerTreeRoot().addGroup("my group") group_node.addLayer(layer2) group_node.addLayer(layer3) p.layerTreeRoot().addLayer(layer4) - self.assertEqual(p.layerTreeRoot().layerOrder(), [layer, layer2, layer3, layer4]) + self.assertEqual( + p.layerTreeRoot().layerOrder(), [layer, layer2, layer3, layer4] + ) options = QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) group_layer = group_node.convertToGroupLayer(options) @@ -376,31 +365,31 @@ def test_nested_groups(self): Test logic relating to nested groups with group layers """ p = QgsProject() - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") p.addMapLayer(layer, False) - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") p.addMapLayer(layer2, False) - layer3 = QgsVectorLayer("Point?field=fldtxt:string", - "layer3", "memory") + layer3 = QgsVectorLayer("Point?field=fldtxt:string", "layer3", "memory") p.addMapLayer(layer3, False) - layer4 = QgsVectorLayer("Point?field=fldtxt:string", - "layer4", "memory") + layer4 = QgsVectorLayer("Point?field=fldtxt:string", "layer4", "memory") p.addMapLayer(layer4, False) - group_node = p.layerTreeRoot().addGroup('my group') + group_node = p.layerTreeRoot().addGroup("my group") group_node.addLayer(layer) group_node.addLayer(layer2) - child_group = group_node.addGroup('child') + child_group = group_node.addGroup("child") layer3_node = child_group.addLayer(layer3) - grandchild_group = child_group.addGroup('grandchild') + grandchild_group = child_group.addGroup("grandchild") layer4_node = grandchild_group.addLayer(layer4) - self.assertEqual(p.layerTreeRoot().layerOrder(), [layer, layer2, layer3, layer4]) - self.assertEqual(p.layerTreeRoot().checkedLayers(), [layer, layer2, layer3, layer4]) + self.assertEqual( + p.layerTreeRoot().layerOrder(), [layer, layer2, layer3, layer4] + ) + self.assertEqual( + p.layerTreeRoot().checkedLayers(), [layer, layer2, layer3, layer4] + ) spy = QSignalSpy(p.layerTreeRoot().layerOrderChanged) @@ -416,7 +405,9 @@ def test_nested_groups(self): grandchild_group_layer = grandchild_group.convertToGroupLayer(options) self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) - self.assertEqual(group_layer.childLayers(), [grandchild_group_layer, layer3, layer2, layer]) + self.assertEqual( + group_layer.childLayers(), [grandchild_group_layer, layer3, layer2, layer] + ) self.assertEqual(grandchild_group_layer.childLayers(), [layer4]) self.assertGreater(len(spy), spy_count) spy_count = len(spy) @@ -424,7 +415,9 @@ def test_nested_groups(self): layer4_node.setItemVisibilityChecked(False) self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) - self.assertEqual(group_layer.childLayers(), [grandchild_group_layer, layer3, layer2, layer]) + self.assertEqual( + group_layer.childLayers(), [grandchild_group_layer, layer3, layer2, layer] + ) self.assertEqual(grandchild_group_layer.childLayers(), []) self.assertGreater(len(spy), spy_count) spy_count = len(spy) @@ -432,7 +425,9 @@ def test_nested_groups(self): layer4_node.setItemVisibilityChecked(True) self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) - self.assertEqual(group_layer.childLayers(), [grandchild_group_layer, layer3, layer2, layer]) + self.assertEqual( + group_layer.childLayers(), [grandchild_group_layer, layer3, layer2, layer] + ) self.assertEqual(grandchild_group_layer.childLayers(), [layer4]) self.assertGreater(len(spy), spy_count) spy_count = len(spy) @@ -447,7 +442,9 @@ def test_nested_groups(self): grandchild_group.setItemVisibilityChecked(True) self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) - self.assertEqual(group_layer.childLayers(), [grandchild_group_layer, layer3, layer2, layer]) + self.assertEqual( + group_layer.childLayers(), [grandchild_group_layer, layer3, layer2, layer] + ) self.assertEqual(grandchild_group_layer.childLayers(), [layer4]) self.assertGreater(len(spy), spy_count) spy_count = len(spy) @@ -456,7 +453,9 @@ def test_nested_groups(self): self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [child_group_layer, layer2, layer]) - self.assertEqual(child_group_layer.childLayers(), [grandchild_group_layer, layer3]) + self.assertEqual( + child_group_layer.childLayers(), [grandchild_group_layer, layer3] + ) self.assertEqual(grandchild_group_layer.childLayers(), [layer4]) self.assertGreater(len(spy), spy_count) spy_count = len(spy) @@ -465,7 +464,9 @@ def test_nested_groups(self): self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [child_group_layer, layer2, layer]) - self.assertEqual(child_group_layer.childLayers(), [grandchild_group_layer, layer3]) + self.assertEqual( + child_group_layer.childLayers(), [grandchild_group_layer, layer3] + ) self.assertEqual(grandchild_group_layer.childLayers(), []) self.assertGreater(len(spy), spy_count) spy_count = len(spy) @@ -474,7 +475,9 @@ def test_nested_groups(self): self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [child_group_layer, layer2, layer]) - self.assertEqual(child_group_layer.childLayers(), [grandchild_group_layer, layer3]) + self.assertEqual( + child_group_layer.childLayers(), [grandchild_group_layer, layer3] + ) self.assertEqual(grandchild_group_layer.childLayers(), [layer4]) self.assertGreater(len(spy), spy_count) spy_count = len(spy) @@ -491,7 +494,9 @@ def test_nested_groups(self): self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [child_group_layer, layer2, layer]) - self.assertEqual(child_group_layer.childLayers(), [grandchild_group_layer, layer3]) + self.assertEqual( + child_group_layer.childLayers(), [grandchild_group_layer, layer3] + ) self.assertEqual(grandchild_group_layer.childLayers(), [layer4]) self.assertGreater(len(spy), spy_count) spy_count = len(spy) @@ -509,7 +514,9 @@ def test_nested_groups(self): self.assertEqual(p.layerTreeRoot().layerOrder(), [group_layer]) self.assertEqual(p.layerTreeRoot().checkedLayers(), [group_layer]) self.assertEqual(group_layer.childLayers(), [child_group_layer, layer2, layer]) - self.assertEqual(child_group_layer.childLayers(), [grandchild_group_layer, layer3]) + self.assertEqual( + child_group_layer.childLayers(), [grandchild_group_layer, layer3] + ) self.assertEqual(grandchild_group_layer.childLayers(), [layer4]) self.assertGreater(len(spy), spy_count) spy_count = len(spy) @@ -530,40 +537,54 @@ def test_nested_groups(self): spy_count = len(spy) group_node.setGroupLayer(None) - self.assertEqual(p.layerTreeRoot().layerOrder(), [layer, layer2, layer3, layer4]) - self.assertEqual(p.layerTreeRoot().checkedLayers(), [layer, layer2, layer3, layer4]) + self.assertEqual( + p.layerTreeRoot().layerOrder(), [layer, layer2, layer3, layer4] + ) + self.assertEqual( + p.layerTreeRoot().checkedLayers(), [layer, layer2, layer3, layer4] + ) self.assertGreater(len(spy), spy_count) def test_reorder_group_layers(self): - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") - layer3 = QgsVectorLayer("Point?field=fldtxt:string", - "layer3", "memory") - layer4 = QgsVectorLayer("Point?field=fldtxt:string", - "layer4", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") + layer3 = QgsVectorLayer("Point?field=fldtxt:string", "layer3", "memory") + layer4 = QgsVectorLayer("Point?field=fldtxt:string", "layer4", "memory") group = QgsLayerTreeGroup() group.addLayer(layer) group.addLayer(layer2) group.addLayer(layer3) group.addLayer(layer4) - self.assertEqual([l.layer() for l in group.children()], [layer, layer2, layer3, layer4]) + self.assertEqual( + [l.layer() for l in group.children()], [layer, layer2, layer3, layer4] + ) group.reorderGroupLayers([]) - self.assertEqual([l.layer() for l in group.children()], [layer, layer2, layer3, layer4]) + self.assertEqual( + [l.layer() for l in group.children()], [layer, layer2, layer3, layer4] + ) group.reorderGroupLayers([layer4, layer2]) - self.assertEqual([l.layer() for l in group.children()], [layer4, layer2, layer, layer3]) + self.assertEqual( + [l.layer() for l in group.children()], [layer4, layer2, layer, layer3] + ) group.reorderGroupLayers([layer3]) - self.assertEqual([l.layer() for l in group.children()], [layer3, layer4, layer2, layer]) + self.assertEqual( + [l.layer() for l in group.children()], [layer3, layer4, layer2, layer] + ) - group.addChildNode(QgsLayerTreeGroup('test')) + group.addChildNode(QgsLayerTreeGroup("test")) group.reorderGroupLayers([layer, layer3]) - self.assertEqual([l.layer() if isinstance(l, QgsLayerTreeLayer) else 'group' for l in group.children()], [layer, layer3, layer4, layer2, 'group']) + self.assertEqual( + [ + l.layer() if isinstance(l, QgsLayerTreeLayer) else "group" + for l in group.children() + ], + [layer, layer3, layer4, layer2, "group"], + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayertreefilterproxymodel.py b/tests/src/python/test_qgslayertreefilterproxymodel.py index 2c3d5c46e8bf..65a751c52383 100644 --- a/tests/src/python/test_qgslayertreefilterproxymodel.py +++ b/tests/src/python/test_qgslayertreefilterproxymodel.py @@ -19,7 +19,7 @@ QgsRendererCategory, QgsMarkerSymbol, QgsMapLayerLegend, - QgsLayerTreeFilterProxyModel + QgsLayerTreeFilterProxyModel, ) from qgis.testing import start_app, QgisTestCase from utilities import unitTestDataPath @@ -37,16 +37,11 @@ def __init__(self, methodName): # setup a dummy project self.project = QgsProject() - self.layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") - self.layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") - self.layer3 = QgsVectorLayer("Point?field=fldtxt:string", - "layer3", "memory") - self.layer4 = QgsVectorLayer("Point?field=fldtxt:string", - "layer4", "memory") - self.layer5 = QgsVectorLayer("Point?field=fldtxt:string", - "layer5", "memory") + self.layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") + self.layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") + self.layer3 = QgsVectorLayer("Point?field=fldtxt:string", "layer3", "memory") + self.layer4 = QgsVectorLayer("Point?field=fldtxt:string", "layer4", "memory") + self.layer5 = QgsVectorLayer("Point?field=fldtxt:string", "layer5", "memory") self.project.addMapLayers([self.layer, self.layer2, self.layer3]) self.model = QgsLayerTreeModel(self.project.layerTreeRoot()) @@ -63,14 +58,15 @@ def test_filter(self): for r in range(self.model.rowCount()): items.append(self.model.data(self.model.index(r, 0))) - self.assertEqual(items, ['layer1', 'layer2', 'layer3']) + self.assertEqual(items, ["layer1", "layer2", "layer3"]) proxy_items = [] for r in range(proxy_model.rowCount()): proxy_items.append( - proxy_model.data(proxy_model.index(r, 0), Qt.ItemDataRole.DisplayRole)) + proxy_model.data(proxy_model.index(r, 0), Qt.ItemDataRole.DisplayRole) + ) - self.assertEqual(proxy_items, ['layer1', 'layer2', 'layer3']) + self.assertEqual(proxy_items, ["layer1", "layer2", "layer3"]) self.layer3.setFlags(self.layer.Private) @@ -82,14 +78,15 @@ def test_filter(self): proxy_items = [] for r in range(proxy_model.rowCount()): proxy_items.append( - proxy_model.data(proxy_model.index(r, 0), Qt.ItemDataRole.DisplayRole)) + proxy_model.data(proxy_model.index(r, 0), Qt.ItemDataRole.DisplayRole) + ) - self.assertEqual(proxy_items, ['layer1', 'layer2']) + self.assertEqual(proxy_items, ["layer1", "layer2"]) proxy_model.setShowPrivateLayers(True) self.assertEqual(proxy_model.rowCount(), 3) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayertreemapcanvasbridge.py b/tests/src/python/test_qgslayertreemapcanvasbridge.py index e86f4eec47df..bb088f769c2d 100644 --- a/tests/src/python/test_qgslayertreemapcanvasbridge.py +++ b/tests/src/python/test_qgslayertreemapcanvasbridge.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '8/03/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "8/03/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.core import ( QgsProject, @@ -34,16 +35,13 @@ def __init__(self, methodName): QgisTestCase.__init__(self, methodName) def testLayerOrderUpdatedThroughBridge(self): - """ test that project layer order is updated when layer tree changes """ + """test that project layer order is updated when layer tree changes""" prj = QgsProject.instance() prj.clear() - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") - layer3 = QgsVectorLayer("Point?field=fldtxt:string", - "layer3", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") + layer3 = QgsVectorLayer("Point?field=fldtxt:string", "layer3", "memory") prj.addMapLayers([layer, layer2, layer3]) @@ -54,14 +52,22 @@ def testLayerOrderUpdatedThroughBridge(self): prj.layerTreeRoot().setHasCustomLayerOrder(True) prj.layerTreeRoot().setCustomLayerOrder([layer3, layer, layer2]) app.processEvents() - self.assertEqual([l for l in prj.layerTreeRoot().customLayerOrder()], [layer3, layer, layer2]) - self.assertEqual([l for l in prj.layerTreeRoot().layerOrder()], [layer3, layer, layer2]) + self.assertEqual( + [l for l in prj.layerTreeRoot().customLayerOrder()], [layer3, layer, layer2] + ) + self.assertEqual( + [l for l in prj.layerTreeRoot().layerOrder()], [layer3, layer, layer2] + ) # no custom layer order prj.layerTreeRoot().setHasCustomLayerOrder(False) app.processEvents() - self.assertEqual([l for l in prj.layerTreeRoot().customLayerOrder()], [layer3, layer, layer2]) - self.assertEqual([l for l in prj.layerTreeRoot().layerOrder()], [layer, layer2, layer3]) + self.assertEqual( + [l for l in prj.layerTreeRoot().customLayerOrder()], [layer3, layer, layer2] + ) + self.assertEqual( + [l for l in prj.layerTreeRoot().layerOrder()], [layer, layer2, layer3] + ) # mess around with the layer tree order root = prj.layerTreeRoot() @@ -72,25 +78,26 @@ def testLayerOrderUpdatedThroughBridge(self): parent.removeChildNode(layer_node) app.processEvents() # make sure project respects this - self.assertEqual([l for l in prj.layerTreeRoot().layerOrder()], [layer2, layer, layer3]) + self.assertEqual( + [l for l in prj.layerTreeRoot().layerOrder()], [layer2, layer, layer3] + ) # make sure project order includes ALL layers, not just visible ones layer_node = root.findLayer(layer) layer_node.setItemVisibilityChecked(False) app.processEvents() - self.assertEqual([l for l in prj.layerTreeRoot().layerOrder()], [layer2, layer, layer3]) + self.assertEqual( + [l for l in prj.layerTreeRoot().layerOrder()], [layer2, layer, layer3] + ) def testCustomLayerOrderUpdatedFromProject(self): - """ test that setting project layer order is reflected in custom layer order panel """ + """test that setting project layer order is reflected in custom layer order panel""" prj = QgsProject.instance() prj.clear() - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") - layer3 = QgsVectorLayer("Point?field=fldtxt:string", - "layer3", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") + layer3 = QgsVectorLayer("Point?field=fldtxt:string", "layer3", "memory") prj.addMapLayers([layer, layer2, layer3]) canvas = QgsMapCanvas() @@ -101,12 +108,16 @@ def testCustomLayerOrderUpdatedFromProject(self): prj.layerTreeRoot().setHasCustomLayerOrder(True) prj.layerTreeRoot().setCustomLayerOrder([layer3, layer, layer2]) app.processEvents() - self.assertEqual([l for l in prj.layerTreeRoot().customLayerOrder()], [layer3, layer, layer2]) + self.assertEqual( + [l for l in prj.layerTreeRoot().customLayerOrder()], [layer3, layer, layer2] + ) # no custom layer order prj.layerTreeRoot().setHasCustomLayerOrder(False) app.processEvents() - self.assertEqual([l for l in prj.layerTreeRoot().layerOrder()], [layer, layer2, layer3]) + self.assertEqual( + [l for l in prj.layerTreeRoot().layerOrder()], [layer, layer2, layer3] + ) # mess around with the project layer order prj.layerTreeRoot().setCustomLayerOrder([layer3, layer, layer2]) @@ -116,7 +127,9 @@ def testCustomLayerOrderUpdatedFromProject(self): # try reordering through bridge prj.layerTreeRoot().setHasCustomLayerOrder(False) app.processEvents() - self.assertEqual([l for l in prj.layerTreeRoot().layerOrder()], [layer, layer2, layer3]) + self.assertEqual( + [l for l in prj.layerTreeRoot().layerOrder()], [layer, layer2, layer3] + ) root = prj.layerTreeRoot() layer_node = root.findLayer(layer2) cloned_node = layer_node.clone() @@ -125,22 +138,22 @@ def testCustomLayerOrderUpdatedFromProject(self): parent.removeChildNode(layer_node) app.processEvents() # make sure project respects this - self.assertEqual([l for l in prj.layerTreeRoot().layerOrder()], [layer2, layer, layer3]) + self.assertEqual( + [l for l in prj.layerTreeRoot().layerOrder()], [layer2, layer, layer3] + ) self.assertFalse(prj.layerTreeRoot().hasCustomLayerOrder()) def testNonSpatialLayer(self): - """ test that non spatial layers are not passed to canvas """ + """test that non spatial layers are not passed to canvas""" prj = QgsProject.instance() prj.clear() - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") - layer3 = QgsVectorLayer("Point?field=fldtxt:string", - "layer3", "memory") - non_spatial = QgsVectorLayer("None?field=fldtxt:string", - "non_spatial", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") + layer3 = QgsVectorLayer("Point?field=fldtxt:string", "layer3", "memory") + non_spatial = QgsVectorLayer( + "None?field=fldtxt:string", "non_spatial", "memory" + ) prj.addMapLayers([layer, layer2, layer3, non_spatial]) @@ -164,5 +177,5 @@ def testNonSpatialLayer(self): self.assertEqual(canvas.mapSettings().layers(), [layer, layer2, layer3]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayertreeview.py b/tests/src/python/test_qgslayertreeview.py index be624e9fe09e..a3e993bf12a5 100644 --- a/tests/src/python/test_qgslayertreeview.py +++ b/tests/src/python/test_qgslayertreeview.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '02.04.2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "02.04.2018" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.PyQt.QtCore import QStringListModel, QItemSelectionModel from qgis.PyQt.QtTest import QAbstractItemModelTester, QSignalSpy @@ -19,7 +20,7 @@ QgsCategorizedSymbolRenderer, QgsRendererCategory, QgsMarkerSymbol, - QgsMapLayerLegend + QgsMapLayerLegend, ) from qgis.gui import QgsLayerTreeView, QgsLayerTreeViewDefaultActions import unittest @@ -40,16 +41,11 @@ def __init__(self, methodName): # setup a dummy project self.project = QgsProject() - self.layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") - self.layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") - self.layer3 = QgsVectorLayer("Point?field=fldtxt:string", - "layer3", "memory") - self.layer4 = QgsVectorLayer("Point?field=fldtxt:string", - "layer4", "memory") - self.layer5 = QgsVectorLayer("Point?field=fldtxt:string", - "layer5", "memory") + self.layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") + self.layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") + self.layer3 = QgsVectorLayer("Point?field=fldtxt:string", "layer3", "memory") + self.layer4 = QgsVectorLayer("Point?field=fldtxt:string", "layer4", "memory") + self.layer5 = QgsVectorLayer("Point?field=fldtxt:string", "layer5", "memory") self.project.addMapLayers([self.layer, self.layer2, self.layer3]) self.model = QgsLayerTreeModel(self.project.layerTreeRoot()) self.tester = QAbstractItemModelTester(self.model) @@ -65,7 +61,7 @@ def nodeOrder(self, group): groupname = node.name() nodeorder.append(groupname) for child in self.nodeOrder(node.children()): - nodeorder.append(groupname + '-' + child) + nodeorder.append(groupname + "-" + child) elif QgsLayerTree.isLayer(node): nodeorder.append(node.layer().name()) return nodeorder @@ -109,15 +105,12 @@ def testDefaultActions(self): # show in overview action view.setCurrentLayer(self.layer) - self.assertEqual( - view.currentNode().customProperty('overview', 0), False) + self.assertEqual(view.currentNode().customProperty("overview", 0), False) show_in_overview = actions.actionShowInOverview() show_in_overview.trigger() - self.assertEqual( - view.currentNode().customProperty('overview', 0), True) + self.assertEqual(view.currentNode().customProperty("overview", 0), True) show_in_overview.trigger() - self.assertEqual( - view.currentNode().customProperty('overview', 0), False) + self.assertEqual(view.currentNode().customProperty("overview", 0), False) def testMoveOutOfGroupActionLayer(self): """Test move out of group action on layer""" @@ -130,26 +123,32 @@ def testMoveOutOfGroupActionLayer(self): view.setModel(self.model) proxy_tester = QAbstractItemModelTester(view.model()) actions = QgsLayerTreeViewDefaultActions(view) - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - self.layer.name(), - self.layer2.name(), - self.layer3.name(), - groupname, - groupname + '-' + self.layer4.name(), - groupname + '-' + self.layer5.name(), - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + groupname, + groupname + "-" + self.layer4.name(), + groupname + "-" + self.layer5.name(), + ], + ) view.setCurrentLayer(self.layer5) moveOutOfGroup = actions.actionMoveOutOfGroup() moveOutOfGroup.trigger() - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - self.layer.name(), - self.layer2.name(), - self.layer3.name(), - self.layer5.name(), - groupname, - groupname + '-' + self.layer4.name(), - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + self.layer5.name(), + groupname, + groupname + "-" + self.layer4.name(), + ], + ) def testMoveToTopActionLayer(self): """Test move to top action on layer""" @@ -158,13 +157,17 @@ def testMoveToTopActionLayer(self): view.setModel(self.model) proxy_tester = QAbstractItemModelTester(view.model()) actions = QgsLayerTreeViewDefaultActions(view) - self.assertEqual(self.project.layerTreeRoot().layerOrder(), [ - self.layer, self.layer2, self.layer3]) + self.assertEqual( + self.project.layerTreeRoot().layerOrder(), + [self.layer, self.layer2, self.layer3], + ) view.setCurrentLayer(self.layer3) movetotop = actions.actionMoveToTop() movetotop.trigger() - self.assertEqual(self.project.layerTreeRoot().layerOrder(), [ - self.layer3, self.layer, self.layer2]) + self.assertEqual( + self.project.layerTreeRoot().layerOrder(), + [self.layer3, self.layer, self.layer2], + ) def testMoveToTopActionGroup(self): """Test move to top action on group""" @@ -177,27 +180,33 @@ def testMoveToTopActionGroup(self): view.setModel(self.model) proxy_tester = QAbstractItemModelTester(view.model()) actions = QgsLayerTreeViewDefaultActions(view) - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - self.layer.name(), - self.layer2.name(), - self.layer3.name(), - groupname, - groupname + '-' + self.layer4.name(), - groupname + '-' + self.layer5.name(), - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + groupname, + groupname + "-" + self.layer4.name(), + groupname + "-" + self.layer5.name(), + ], + ) nodeLayerIndex = view.node2index(group) view.setCurrentIndex(nodeLayerIndex) movetotop = actions.actionMoveToTop() movetotop.trigger() - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - groupname, - groupname + '-' + self.layer4.name(), - groupname + '-' + self.layer5.name(), - self.layer.name(), - self.layer2.name(), - self.layer3.name(), - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + groupname, + groupname + "-" + self.layer4.name(), + groupname + "-" + self.layer5.name(), + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + ], + ) def testMoveToTopActionEmbeddedGroup(self): """Test move to top action on embeddedgroup layer""" @@ -210,26 +219,32 @@ def testMoveToTopActionEmbeddedGroup(self): view.setModel(self.model) proxy_tester = QAbstractItemModelTester(view.model()) actions = QgsLayerTreeViewDefaultActions(view) - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - self.layer.name(), - self.layer2.name(), - self.layer3.name(), - groupname, - groupname + '-' + self.layer4.name(), - groupname + '-' + self.layer5.name(), - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + groupname, + groupname + "-" + self.layer4.name(), + groupname + "-" + self.layer5.name(), + ], + ) view.setCurrentLayer(self.layer5) movetotop = actions.actionMoveToTop() movetotop.trigger() - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - self.layer.name(), - self.layer2.name(), - self.layer3.name(), - groupname, - groupname + '-' + self.layer5.name(), - groupname + '-' + self.layer4.name(), - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + groupname, + groupname + "-" + self.layer5.name(), + groupname + "-" + self.layer4.name(), + ], + ) def testMoveToTopActionLayerAndGroup(self): """Test move to top action for a group and it's layer simultaneously""" @@ -242,14 +257,17 @@ def testMoveToTopActionLayerAndGroup(self): view.setModel(self.model) proxy_tester = QAbstractItemModelTester(view.model()) actions = QgsLayerTreeViewDefaultActions(view) - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - self.layer.name(), - self.layer2.name(), - self.layer3.name(), - groupname, - groupname + '-' + self.layer4.name(), - groupname + '-' + self.layer5.name(), - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + groupname, + groupname + "-" + self.layer4.name(), + groupname + "-" + self.layer5.name(), + ], + ) selectionMode = view.selectionMode() view.setSelectionMode(QgsLayerTreeView.SelectionMode.MultiSelection) @@ -259,14 +277,17 @@ def testMoveToTopActionLayerAndGroup(self): view.setSelectionMode(selectionMode) movetotop = actions.actionMoveToTop() movetotop.trigger() - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - groupname, - groupname + '-' + self.layer5.name(), - groupname + '-' + self.layer4.name(), - self.layer.name(), - self.layer2.name(), - self.layer3.name(), - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + groupname, + groupname + "-" + self.layer5.name(), + groupname + "-" + self.layer4.name(), + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + ], + ) def testMoveToBottomActionLayer(self): """Test move to bottom action on layer""" @@ -275,13 +296,17 @@ def testMoveToBottomActionLayer(self): view.setModel(self.model) proxy_tester = QAbstractItemModelTester(view.model()) actions = QgsLayerTreeViewDefaultActions(view) - self.assertEqual(self.project.layerTreeRoot().layerOrder(), [ - self.layer, self.layer2, self.layer3]) + self.assertEqual( + self.project.layerTreeRoot().layerOrder(), + [self.layer, self.layer2, self.layer3], + ) view.setCurrentLayer(self.layer) movetobottom = actions.actionMoveToBottom() movetobottom.trigger() - self.assertEqual(self.project.layerTreeRoot().layerOrder(), [ - self.layer2, self.layer3, self.layer]) + self.assertEqual( + self.project.layerTreeRoot().layerOrder(), + [self.layer2, self.layer3, self.layer], + ) def testMoveToBottomActionGroup(self): """Test move to bottom action on group""" @@ -294,27 +319,33 @@ def testMoveToBottomActionGroup(self): view.setModel(self.model) proxy_tester = QAbstractItemModelTester(view.model()) actions = QgsLayerTreeViewDefaultActions(view) - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - groupname, - groupname + '-' + self.layer4.name(), - groupname + '-' + self.layer5.name(), - self.layer.name(), - self.layer2.name(), - self.layer3.name(), - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + groupname, + groupname + "-" + self.layer4.name(), + groupname + "-" + self.layer5.name(), + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + ], + ) nodeLayerIndex = view.node2index(group) view.setCurrentIndex(nodeLayerIndex) movetobottom = actions.actionMoveToBottom() movetobottom.trigger() - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - self.layer.name(), - self.layer2.name(), - self.layer3.name(), - groupname, - groupname + '-' + self.layer4.name(), - groupname + '-' + self.layer5.name(), - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + groupname, + groupname + "-" + self.layer4.name(), + groupname + "-" + self.layer5.name(), + ], + ) def testMoveToBottomActionEmbeddedGroup(self): """Test move to bottom action on embeddedgroup layer""" @@ -327,26 +358,32 @@ def testMoveToBottomActionEmbeddedGroup(self): view.setModel(self.model) proxy_tester = QAbstractItemModelTester(view.model()) actions = QgsLayerTreeViewDefaultActions(view) - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - self.layer.name(), - self.layer2.name(), - self.layer3.name(), - groupname, - groupname + '-' + self.layer4.name(), - groupname + '-' + self.layer5.name(), - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + groupname, + groupname + "-" + self.layer4.name(), + groupname + "-" + self.layer5.name(), + ], + ) view.setCurrentLayer(self.layer4) movetobottom = actions.actionMoveToBottom() movetobottom.trigger() - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - self.layer.name(), - self.layer2.name(), - self.layer3.name(), - groupname, - groupname + '-' + self.layer5.name(), - groupname + '-' + self.layer4.name(), - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + groupname, + groupname + "-" + self.layer5.name(), + groupname + "-" + self.layer4.name(), + ], + ) def testMoveToBottomActionLayerAndGroup(self): """Test move to top action for a group and it's layer simultaneously""" @@ -359,14 +396,17 @@ def testMoveToBottomActionLayerAndGroup(self): view.setModel(self.model) proxy_tester = QAbstractItemModelTester(view.model()) actions = QgsLayerTreeViewDefaultActions(view) - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - groupname, - groupname + '-' + self.layer4.name(), - groupname + '-' + self.layer5.name(), - self.layer.name(), - self.layer2.name(), - self.layer3.name(), - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + groupname, + groupname + "-" + self.layer4.name(), + groupname + "-" + self.layer5.name(), + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + ], + ) selectionMode = view.selectionMode() view.setSelectionMode(QgsLayerTreeView.SelectionMode.MultiSelection) @@ -376,14 +416,17 @@ def testMoveToBottomActionLayerAndGroup(self): view.setSelectionMode(selectionMode) movetobottom = actions.actionMoveToBottom() movetobottom.trigger() - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - self.layer.name(), - self.layer2.name(), - self.layer3.name(), - groupname, - groupname + '-' + self.layer5.name(), - groupname + '-' + self.layer4.name(), - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + groupname, + groupname + "-" + self.layer5.name(), + groupname + "-" + self.layer4.name(), + ], + ) def testAddGroupActionLayer(self): """Test add group action on single layer""" @@ -396,27 +439,33 @@ def testAddGroupActionLayer(self): view.setModel(self.model) proxy_tester = QAbstractItemModelTester(view.model()) actions = QgsLayerTreeViewDefaultActions(view) - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - groupname, - groupname + '-' + self.layer4.name(), - groupname + '-' + self.layer5.name(), - self.layer.name(), - self.layer2.name(), - self.layer3.name(), - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + groupname, + groupname + "-" + self.layer4.name(), + groupname + "-" + self.layer5.name(), + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + ], + ) view.setCurrentLayer(self.layer2) addgroup = actions.actionAddGroup() addgroup.trigger() - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - groupname, - groupname + '-' + self.layer4.name(), - groupname + '-' + self.layer5.name(), - self.layer.name(), - self.groupname + '1', - self.groupname + '1' + '-' + self.layer2.name(), - self.layer3.name() - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + groupname, + groupname + "-" + self.layer4.name(), + groupname + "-" + self.layer5.name(), + self.layer.name(), + self.groupname + "1", + self.groupname + "1" + "-" + self.layer2.name(), + self.layer3.name(), + ], + ) def testAddGroupActionLayers(self): """Test add group action on several layers""" @@ -430,14 +479,17 @@ def testAddGroupActionLayers(self): view.setModel(self.model) proxy_tester = QAbstractItemModelTester(view.model()) actions = QgsLayerTreeViewDefaultActions(view) - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - groupname, - groupname + '-' + self.layer4.name(), - groupname + '-' + self.layer5.name(), - self.layer.name(), - self.layer2.name(), - self.layer3.name(), - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + groupname, + groupname + "-" + self.layer4.name(), + groupname + "-" + self.layer5.name(), + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + ], + ) selectionMode = view.selectionMode() view.setSelectionMode(QgsLayerTreeView.SelectionMode.MultiSelection) @@ -447,15 +499,18 @@ def testAddGroupActionLayers(self): addgroup = actions.actionAddGroup() addgroup.trigger() - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - groupname, - groupname + '-' + self.layer4.name(), - groupname + '-' + self.layer5.name(), - self.groupname + '1', - self.groupname + '1' + '-' + self.layer.name(), - self.groupname + '1' + '-' + self.layer2.name(), - self.layer3.name() - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + groupname, + groupname + "-" + self.layer4.name(), + groupname + "-" + self.layer5.name(), + self.groupname + "1", + self.groupname + "1" + "-" + self.layer.name(), + self.groupname + "1" + "-" + self.layer2.name(), + self.layer3.name(), + ], + ) def testAddGroupActionGroup(self): """Test add group action on single group""" @@ -468,28 +523,34 @@ def testAddGroupActionGroup(self): view.setModel(self.model) proxy_tester = QAbstractItemModelTester(view.model()) actions = QgsLayerTreeViewDefaultActions(view) - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - groupname, - groupname + '-' + self.layer4.name(), - groupname + '-' + self.layer5.name(), - self.layer.name(), - self.layer2.name(), - self.layer3.name(), - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + groupname, + groupname + "-" + self.layer4.name(), + groupname + "-" + self.layer5.name(), + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + ], + ) nodeLayerIndex = view.node2index(group) view.setCurrentIndex(nodeLayerIndex) addgroup = actions.actionAddGroup() addgroup.trigger() - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - groupname, - groupname + '-' + self.layer4.name(), - groupname + '-' + self.layer5.name(), - groupname + '-' + self.subgroupname + '1', - self.layer.name(), - self.layer2.name(), - self.layer3.name() - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + groupname, + groupname + "-" + self.layer4.name(), + groupname + "-" + self.layer5.name(), + groupname + "-" + self.subgroupname + "1", + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + ], + ) def testAddGroupActionGroups(self): """Test add group action on several groups""" @@ -505,15 +566,18 @@ def testAddGroupActionGroups(self): view.setModel(self.model) proxy_tester = QAbstractItemModelTester(view.model()) actions = QgsLayerTreeViewDefaultActions(view) - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - groupname2, - groupname2 + '-' + self.layer5.name(), - groupname, - groupname + '-' + self.layer4.name(), - self.layer.name(), - self.layer2.name(), - self.layer3.name(), - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + groupname2, + groupname2 + "-" + self.layer5.name(), + groupname, + groupname + "-" + self.layer4.name(), + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + ], + ) selectionMode = view.selectionMode() view.setSelectionMode(QgsLayerTreeView.SelectionMode.MultiSelection) @@ -525,41 +589,51 @@ def testAddGroupActionGroups(self): addgroup = actions.actionAddGroup() addgroup.trigger() - self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ - self.groupname + '1', - self.groupname + '1' + '-' + groupname, - self.groupname + '1' + '-' + groupname + '-' + self.layer4.name(), - self.groupname + '1' + '-' + groupname2, - self.groupname + '1' + '-' + groupname2 + '-' + self.layer5.name(), - self.layer.name(), - self.layer2.name(), - self.layer3.name() - ]) + self.assertEqual( + self.nodeOrder(self.project.layerTreeRoot().children()), + [ + self.groupname + "1", + self.groupname + "1" + "-" + groupname, + self.groupname + "1" + "-" + groupname + "-" + self.layer4.name(), + self.groupname + "1" + "-" + groupname2, + self.groupname + "1" + "-" + groupname2 + "-" + self.layer5.name(), + self.layer.name(), + self.layer2.name(), + self.layer3.name(), + ], + ) def testSetLayerVisible(self): view = QgsLayerTreeView() view.setModel(self.model) proxy_tester = QAbstractItemModelTester(view.model()) - self.project.layerTreeRoot().findLayer( - self.layer).setItemVisibilityChecked(True) - self.project.layerTreeRoot().findLayer( - self.layer2).setItemVisibilityChecked(True) - self.assertTrue(self.project.layerTreeRoot().findLayer( - self.layer).itemVisibilityChecked()) - self.assertTrue(self.project.layerTreeRoot().findLayer( - self.layer2).itemVisibilityChecked()) + self.project.layerTreeRoot().findLayer(self.layer).setItemVisibilityChecked( + True + ) + self.project.layerTreeRoot().findLayer(self.layer2).setItemVisibilityChecked( + True + ) + self.assertTrue( + self.project.layerTreeRoot().findLayer(self.layer).itemVisibilityChecked() + ) + self.assertTrue( + self.project.layerTreeRoot().findLayer(self.layer2).itemVisibilityChecked() + ) view.setLayerVisible(None, True) view.setLayerVisible(self.layer, True) - self.assertTrue(self.project.layerTreeRoot().findLayer( - self.layer).itemVisibilityChecked()) + self.assertTrue( + self.project.layerTreeRoot().findLayer(self.layer).itemVisibilityChecked() + ) view.setLayerVisible(self.layer2, False) - self.assertFalse(self.project.layerTreeRoot().findLayer( - self.layer2).itemVisibilityChecked()) + self.assertFalse( + self.project.layerTreeRoot().findLayer(self.layer2).itemVisibilityChecked() + ) view.setLayerVisible(self.layer2, True) - self.assertTrue(self.project.layerTreeRoot().findLayer( - self.layer2).itemVisibilityChecked()) + self.assertTrue( + self.project.layerTreeRoot().findLayer(self.layer2).itemVisibilityChecked() + ) def testProxyModel(self): """Test proxy model filtering and private layers""" @@ -577,13 +651,13 @@ def testProxyModel(self): for r in range(tree_model.rowCount()): items.append(tree_model.data(tree_model.index(r, 0))) - self.assertEqual(items, ['layer1', 'layer2', 'layer3']) + self.assertEqual(items, ["layer1", "layer2", "layer3"]) proxy_items = [] for r in range(proxy_model.rowCount()): proxy_items.append(proxy_model.data(proxy_model.index(r, 0))) - self.assertEqual(proxy_items, ['layer1', 'layer2', 'layer3']) + self.assertEqual(proxy_items, ["layer1", "layer2", "layer3"]) self.layer3.setFlags(self.layer.Private) self.assertEqual(tree_model.rowCount(), 3) @@ -593,7 +667,7 @@ def testProxyModel(self): for r in range(proxy_model.rowCount()): proxy_items.append(proxy_model.data(proxy_model.index(r, 0))) - self.assertEqual(proxy_items, ['layer1', 'layer2']) + self.assertEqual(proxy_items, ["layer1", "layer2"]) view.setShowPrivateLayers(True) @@ -603,7 +677,7 @@ def testProxyModel(self): for r in range(proxy_model.rowCount()): proxy_items.append(proxy_model.data(proxy_model.index(r, 0))) - self.assertEqual(proxy_items, ['layer1', 'layer2', 'layer3']) + self.assertEqual(proxy_items, ["layer1", "layer2", "layer3"]) view.setShowPrivateLayers(False) @@ -613,10 +687,10 @@ def testProxyModel(self): for r in range(proxy_model.rowCount()): proxy_items.append(proxy_model.data(proxy_model.index(r, 0))) - self.assertEqual(proxy_items, ['layer1', 'layer2']) + self.assertEqual(proxy_items, ["layer1", "layer2"]) # Test filters - proxy_model.setFilterText('layer2') + proxy_model.setFilterText("layer2") self.assertEqual(proxy_model.rowCount(), 1) @@ -624,7 +698,7 @@ def testProxyModel(self): for r in range(proxy_model.rowCount()): proxy_items.append(proxy_model.data(proxy_model.index(r, 0))) - self.assertEqual(proxy_items, ['layer2']) + self.assertEqual(proxy_items, ["layer2"]) # test valid layer filtering broken_layer = QgsVectorLayer("xxxx", "broken", "ogr") @@ -636,21 +710,21 @@ def testProxyModel(self): proxy_items = [] for r in range(proxy_model.rowCount()): proxy_items.append(proxy_model.data(proxy_model.index(r, 0))) - self.assertEqual(proxy_items, ['broken', 'layer1', 'layer2']) + self.assertEqual(proxy_items, ["broken", "layer1", "layer2"]) proxy_model.setHideValidLayers(True) proxy_items = [] for r in range(proxy_model.rowCount()): proxy_items.append(proxy_model.data(proxy_model.index(r, 0))) - self.assertEqual(proxy_items, ['broken']) + self.assertEqual(proxy_items, ["broken"]) proxy_model.setHideValidLayers(False) proxy_items = [] for r in range(proxy_model.rowCount()): proxy_items.append(proxy_model.data(proxy_model.index(r, 0))) - self.assertEqual(proxy_items, ['broken', 'layer1', 'layer2']) + self.assertEqual(proxy_items, ["broken", "layer1", "layer2"]) self.project.removeMapLayer(broken_layer) @@ -678,7 +752,7 @@ def testNode2IndexMethods(self): proxy_index = proxy_model.index(1, 0) node2 = view.index2node(proxy_index) - self.assertEqual(node2.name(), 'layer2') + self.assertEqual(node2.name(), "layer2") proxy_layer2_index = view.node2index(node2) self.assertEqual(proxy_layer2_index, view.node2index(node2)) @@ -688,16 +762,13 @@ def testNode2IndexMethods(self): self.assertEqual(tree_layer2_index, view.node2sourceIndex(node2)) def test_selected_legend_nodes(self): - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") - cat1 = QgsRendererCategory(1, QgsMarkerSymbol.createSimple({}), 'cat 1') - cat2 = QgsRendererCategory(2, QgsMarkerSymbol.createSimple({}), - 'cat 2') - cat3 = QgsRendererCategory(1, QgsMarkerSymbol.createSimple({}), - 'cat 3') + cat1 = QgsRendererCategory(1, QgsMarkerSymbol.createSimple({}), "cat 1") + cat2 = QgsRendererCategory(2, QgsMarkerSymbol.createSimple({}), "cat 2") + cat3 = QgsRendererCategory(1, QgsMarkerSymbol.createSimple({}), "cat 3") - renderer = QgsCategorizedSymbolRenderer('fldtext', [cat1, cat2, cat3]) + renderer = QgsCategorizedSymbolRenderer("fldtext", [cat1, cat2, cat3]) layer.setRenderer(renderer) layer.setLegend(QgsMapLayerLegend.defaultVectorLegend(layer)) @@ -730,11 +801,19 @@ def test_selected_legend_nodes(self): self.assertFalse(view.selectedLegendNodes()) - view.selectionModel().select(view.proxyModel().mapFromSource(index), QItemSelectionModel.SelectionFlag.ClearAndSelect) - view.selectionModel().select(view.proxyModel().mapFromSource(index2), QItemSelectionModel.SelectionFlag.Select) + view.selectionModel().select( + view.proxyModel().mapFromSource(index), + QItemSelectionModel.SelectionFlag.ClearAndSelect, + ) + view.selectionModel().select( + view.proxyModel().mapFromSource(index2), + QItemSelectionModel.SelectionFlag.Select, + ) - self.assertCountEqual(view.selectedLegendNodes(), [legend_nodes[0], legend_nodes[2]]) + self.assertCountEqual( + view.selectedLegendNodes(), [legend_nodes[0], legend_nodes[2]] + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayout.py b/tests/src/python/test_qgslayout.py index 7e021e4592a4..becfb0c9164a 100644 --- a/tests/src/python/test_qgslayout.py +++ b/tests/src/python/test_qgslayout.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '18/07/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "18/07/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os import shutil @@ -60,20 +61,25 @@ def tearDownClass(cls): def testReadWriteXml(self): p = QgsProject() l = QgsPrintLayout(p) - l.setName('my layout') + l.setName("my layout") l.setUnits(QgsUnitTypes.LayoutUnit.LayoutInches) collection = l.pageCollection() # add a page page = QgsLayoutItemPage(l) - page.setPageSize('A6') + page.setPageSize("A6") collection.addPage(page) grid = l.gridSettings() - grid.setResolution(QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutPoints)) - - g1 = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), - l.pageCollection().page(0)) + grid.setResolution( + QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutPoints) + ) + + g1 = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + l.pageCollection().page(0), + ) l.guides().addGuide(g1) snapper = l.snapper() @@ -81,10 +87,10 @@ def testReadWriteXml(self): # add some items item1 = QgsLayoutItemMap(l) - item1.setId('xxyyxx') + item1.setId("xxyyxx") l.addItem(item1) item2 = QgsLayoutItemMap(l) - item2.setId('zzyyzz') + item2.setId("zzyyzz") l.addItem(item2) l.setReferenceMap(item2) @@ -94,7 +100,7 @@ def testReadWriteXml(self): l2 = QgsPrintLayout(p) self.assertTrue(l2.readXml(elem, doc, QgsReadWriteContext())) - self.assertEqual(l2.name(), 'my layout') + self.assertEqual(l2.name(), "my layout") self.assertEqual(l2.units(), QgsUnitTypes.LayoutUnit.LayoutInches) collection2 = l2.pageCollection() @@ -102,20 +108,27 @@ def testReadWriteXml(self): self.assertAlmostEqual(collection2.page(0).pageSize().width(), 105, 4) self.assertEqual(collection2.page(0).pageSize().height(), 148) self.assertEqual(l2.gridSettings().resolution().length(), 5.0) - self.assertEqual(l2.gridSettings().resolution().units(), QgsUnitTypes.LayoutUnit.LayoutPoints) - self.assertEqual(l2.guides().guidesOnPage(0)[0].orientation(), Qt.Orientation.Horizontal) + self.assertEqual( + l2.gridSettings().resolution().units(), QgsUnitTypes.LayoutUnit.LayoutPoints + ) + self.assertEqual( + l2.guides().guidesOnPage(0)[0].orientation(), Qt.Orientation.Horizontal + ) self.assertEqual(l2.guides().guidesOnPage(0)[0].position().length(), 5.0) - self.assertEqual(l2.guides().guidesOnPage(0)[0].position().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters) + self.assertEqual( + l2.guides().guidesOnPage(0)[0].position().units(), + QgsUnitTypes.LayoutUnit.LayoutCentimeters, + ) self.assertEqual(l2.snapper().snapTolerance(), 7) # check restored items new_item1 = l2.itemByUuid(item1.uuid()) self.assertTrue(new_item1) - self.assertEqual(new_item1.id(), 'xxyyxx') + self.assertEqual(new_item1.id(), "xxyyxx") new_item2 = l2.itemByUuid(item2.uuid()) self.assertTrue(new_item2) - self.assertEqual(new_item2.id(), 'zzyyzz') - self.assertEqual(l2.referenceMap().id(), 'zzyyzz') + self.assertEqual(new_item2.id(), "zzyyzz") + self.assertEqual(l2.referenceMap().id(), "zzyyzz") def testAddItemsFromXml(self): p = QgsProject() @@ -123,14 +136,22 @@ def testAddItemsFromXml(self): # add some items item1 = QgsLayoutItemLabel(l) - item1.setId('xxyyxx') - item1.attemptMove(QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item1.attemptResize(QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item1.setId("xxyyxx") + item1.attemptMove( + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item1.attemptResize( + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addItem(item1) item2 = QgsLayoutItemLabel(l) - item2.setId('zzyyzz') - item2.attemptMove(QgsLayoutPoint(1.4, 1.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - item2.attemptResize(QgsLayoutSize(2.8, 2.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + item2.setId("zzyyzz") + item2.attemptMove( + QgsLayoutPoint(1.4, 1.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) + item2.attemptResize( + QgsLayoutSize(2.8, 2.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) l.addItem(item2) doc = QDomDocument("testdoc") @@ -141,16 +162,28 @@ def testAddItemsFromXml(self): new_items = l2.addItemsFromXml(elem, doc, QgsReadWriteContext()) self.assertEqual(len(new_items), 2) items = l2.items() - self.assertTrue([i for i in items if i.id() == 'xxyyxx']) - self.assertTrue([i for i in items if i.id() == 'zzyyzz']) + self.assertTrue([i for i in items if i.id() == "xxyyxx"]) + self.assertTrue([i for i in items if i.id() == "zzyyzz"]) self.assertIn(new_items[0], l2.items()) self.assertIn(new_items[1], l2.items()) - new_item1 = [i for i in items if i.id() == 'xxyyxx'][0] - new_item2 = [i for i in items if i.id() == 'zzyyzz'][0] - self.assertEqual(new_item1.positionWithUnits(), QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(new_item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(new_item2.positionWithUnits(), QgsLayoutPoint(1.4, 1.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - self.assertEqual(new_item2.sizeWithUnits(), QgsLayoutSize(2.8, 2.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + new_item1 = [i for i in items if i.id() == "xxyyxx"][0] + new_item2 = [i for i in items if i.id() == "zzyyzz"][0] + self.assertEqual( + new_item1.positionWithUnits(), + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + new_item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + new_item2.positionWithUnits(), + QgsLayoutPoint(1.4, 1.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + self.assertEqual( + new_item2.sizeWithUnits(), + QgsLayoutSize(2.8, 2.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) # test with a group group = QgsLayoutItemGroup(l) @@ -163,8 +196,8 @@ def testAddItemsFromXml(self): new_items = l3.addItemsFromXml(elem, doc, QgsReadWriteContext()) self.assertEqual(len(new_items), 3) items = l3.items() - self.assertTrue([i for i in items if i.id() == 'xxyyxx']) - self.assertTrue([i for i in items if i.id() == 'zzyyzz']) + self.assertTrue([i for i in items if i.id() == "xxyyxx"]) + self.assertTrue([i for i in items if i.id() == "zzyyzz"]) self.assertIn(new_items[0], l3.items()) self.assertIn(new_items[1], l3.items()) self.assertIn(new_items[2], l3.items()) @@ -177,52 +210,94 @@ def testAddItemsFromXml(self): # test restoring at set position l3 = QgsLayout(p) - new_items = l3.addItemsFromXml(elem, doc, QgsReadWriteContext(), QPointF(10, 30)) + new_items = l3.addItemsFromXml( + elem, doc, QgsReadWriteContext(), QPointF(10, 30) + ) self.assertEqual(len(new_items), 3) items = l3.items() - new_item1 = [i for i in items if i.id() == 'xxyyxx'][0] - new_item2 = [i for i in items if i.id() == 'zzyyzz'][0] - self.assertEqual(new_item1.positionWithUnits(), QgsLayoutPoint(10, 30, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(new_item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(new_item2.positionWithUnits(), QgsLayoutPoint(2.0, 4.0, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - self.assertEqual(new_item2.sizeWithUnits(), QgsLayoutSize(2.8, 2.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + new_item1 = [i for i in items if i.id() == "xxyyxx"][0] + new_item2 = [i for i in items if i.id() == "zzyyzz"][0] + self.assertEqual( + new_item1.positionWithUnits(), + QgsLayoutPoint(10, 30, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + new_item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + new_item2.positionWithUnits(), + QgsLayoutPoint(2.0, 4.0, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + self.assertEqual( + new_item2.sizeWithUnits(), + QgsLayoutSize(2.8, 2.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) # paste in place l4 = QgsLayout(p) page = QgsLayoutItemPage(l) - page.setPageSize('A3') + page.setPageSize("A3") l4.pageCollection().addPage(page) page = QgsLayoutItemPage(l) - page.setPageSize('A6') + page.setPageSize("A6") l4.pageCollection().addPage(page) - new_items = l4.addItemsFromXml(elem, doc, QgsReadWriteContext(), QPointF(10, 30), True) + new_items = l4.addItemsFromXml( + elem, doc, QgsReadWriteContext(), QPointF(10, 30), True + ) self.assertEqual(len(new_items), 3) - new_item1 = [i for i in new_items if i.id() == 'xxyyxx'][0] - new_item2 = [i for i in new_items if i.id() == 'zzyyzz'][0] - self.assertEqual(new_item1.pagePositionWithUnits(), QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(new_item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + new_item1 = [i for i in new_items if i.id() == "xxyyxx"][0] + new_item2 = [i for i in new_items if i.id() == "zzyyzz"][0] + self.assertEqual( + new_item1.pagePositionWithUnits(), + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + new_item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertEqual(new_item1.page(), 0) - self.assertEqual(new_item2.pagePositionWithUnits(), QgsLayoutPoint(1.4, 1.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - self.assertEqual(new_item2.sizeWithUnits(), QgsLayoutSize(2.8, 2.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + new_item2.pagePositionWithUnits(), + QgsLayoutPoint(1.4, 1.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + self.assertEqual( + new_item2.sizeWithUnits(), + QgsLayoutSize(2.8, 2.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) self.assertEqual(new_item2.page(), 0) # paste in place, page 2 - new_items = l4.addItemsFromXml(elem, doc, QgsReadWriteContext(), QPointF(10, 550), True) + new_items = l4.addItemsFromXml( + elem, doc, QgsReadWriteContext(), QPointF(10, 550), True + ) self.assertEqual(len(new_items), 3) - new_item1 = [i for i in new_items if i.id() == 'xxyyxx'][0] - new_item2 = [i for i in new_items if i.id() == 'zzyyzz'][0] - self.assertEqual(new_item1.pagePositionWithUnits(), QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + new_item1 = [i for i in new_items if i.id() == "xxyyxx"][0] + new_item2 = [i for i in new_items if i.id() == "zzyyzz"][0] + self.assertEqual( + new_item1.pagePositionWithUnits(), + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertEqual(new_item1.page(), 1) - self.assertEqual(new_item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(new_item2.pagePositionWithUnits(), QgsLayoutPoint(1.4, 1.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + new_item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + new_item2.pagePositionWithUnits(), + QgsLayoutPoint(1.4, 1.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) self.assertEqual(new_item2.page(), 1) - self.assertEqual(new_item2.sizeWithUnits(), QgsLayoutSize(2.8, 2.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + new_item2.sizeWithUnits(), + QgsLayoutSize(2.8, 2.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) # TODO - test restoring multiframe def testSaveLoadTemplate(self): - tmpfile = os.path.join(self.basetestpath, 'testTemplate.qpt') + tmpfile = os.path.join(self.basetestpath, "testTemplate.qpt") p = QgsProject() l = QgsLayout(p) @@ -230,36 +305,59 @@ def testSaveLoadTemplate(self): # add some items item1 = QgsLayoutItemLabel(l) - item1.setId('xxyyxx') - item1.attemptMove(QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item1.attemptResize(QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item1.setId("xxyyxx") + item1.attemptMove( + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item1.attemptResize( + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addItem(item1) item2 = QgsLayoutItemLabel(l) - item2.setId('zzyyzz') - item2.attemptMove(QgsLayoutPoint(1.4, 1.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - item2.attemptResize(QgsLayoutSize(2.8, 2.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + item2.setId("zzyyzz") + item2.attemptMove( + QgsLayoutPoint(1.4, 1.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) + item2.attemptResize( + QgsLayoutSize(2.8, 2.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) l.addItem(item2) # multiframe multiframe1 = QgsLayoutItemHtml(l) - multiframe1.setHtml('mf1') + multiframe1.setHtml("mf1") l.addMultiFrame(multiframe1) frame1 = QgsLayoutFrame(l, multiframe1) - frame1.setId('frame1') - frame1.attemptMove(QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - frame1.attemptResize(QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + frame1.setId("frame1") + frame1.attemptMove( + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + frame1.attemptResize( + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) multiframe1.addFrame(frame1) multiframe2 = QgsLayoutItemHtml(l) - multiframe2.setHtml('mf2') + multiframe2.setHtml("mf2") l.addMultiFrame(multiframe2) frame2 = QgsLayoutFrame(l, multiframe2) - frame2.setId('frame2') - frame2.attemptMove(QgsLayoutPoint(1.4, 1.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - frame2.attemptResize(QgsLayoutSize(2.8, 2.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + frame2.setId("frame2") + frame2.attemptMove( + QgsLayoutPoint(1.4, 1.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) + frame2.attemptResize( + QgsLayoutSize(2.8, 2.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) multiframe2.addFrame(frame2) - uuids = {item1.uuid(), item2.uuid(), frame1.uuid(), frame2.uuid(), multiframe1.uuid(), multiframe2.uuid()} + uuids = { + item1.uuid(), + item2.uuid(), + frame1.uuid(), + frame2.uuid(), + multiframe1.uuid(), + multiframe2.uuid(), + } original_uuids = {item1.uuid(), item2.uuid(), frame1.uuid(), frame2.uuid()} self.assertTrue(l.saveAsTemplate(tmpfile, QgsReadWriteContext())) @@ -277,12 +375,12 @@ def testSaveLoadTemplate(self): items = l2.items() multiframes = l2.multiFrames() self.assertEqual(len(multiframes), 2) - self.assertTrue([i for i in items if i.id() == 'xxyyxx']) - self.assertTrue([i for i in items if i.id() == 'zzyyzz']) - self.assertTrue([i for i in items if i.id() == 'frame1']) - self.assertTrue([i for i in items if i.id() == 'frame2']) - self.assertTrue([i for i in multiframes if i.html() == 'mf1']) - self.assertTrue([i for i in multiframes if i.html() == 'mf2']) + self.assertTrue([i for i in items if i.id() == "xxyyxx"]) + self.assertTrue([i for i in items if i.id() == "zzyyzz"]) + self.assertTrue([i for i in items if i.id() == "frame1"]) + self.assertTrue([i for i in items if i.id() == "frame2"]) + self.assertTrue([i for i in multiframes if i.html() == "mf1"]) + self.assertTrue([i for i in multiframes if i.html() == "mf2"]) self.assertIn(new_items[0], l2.items()) self.assertIn(new_items[1], l2.items()) self.assertIn(new_items[2], l2.items()) @@ -298,14 +396,22 @@ def testSaveLoadTemplate(self): self.assertNotIn(new_items[3].uuid(), uuids) uuids.add(new_items[3].uuid()) - self.assertNotIn(multiframes[0].uuid(), [multiframe1.uuid(), multiframe2.uuid()]) - self.assertNotIn(multiframes[1].uuid(), [multiframe1.uuid(), multiframe2.uuid()]) - new_multiframe1 = [i for i in multiframes if i.html() == 'mf1'][0] + self.assertNotIn( + multiframes[0].uuid(), [multiframe1.uuid(), multiframe2.uuid()] + ) + self.assertNotIn( + multiframes[1].uuid(), [multiframe1.uuid(), multiframe2.uuid()] + ) + new_multiframe1 = [i for i in multiframes if i.html() == "mf1"][0] self.assertEqual(new_multiframe1.layout(), l2) - new_multiframe2 = [i for i in multiframes if i.html() == 'mf2'][0] + new_multiframe2 = [i for i in multiframes if i.html() == "mf2"][0] self.assertEqual(new_multiframe2.layout(), l2) - new_frame1 = sip.cast([i for i in items if i.id() == 'frame1'][0], QgsLayoutFrame) - new_frame2 = sip.cast([i for i in items if i.id() == 'frame2'][0], QgsLayoutFrame) + new_frame1 = sip.cast( + [i for i in items if i.id() == "frame1"][0], QgsLayoutFrame + ) + new_frame2 = sip.cast( + [i for i in items if i.id() == "frame2"][0], QgsLayoutFrame + ) self.assertEqual(new_frame1.multiFrame(), new_multiframe1) self.assertEqual(new_multiframe1.frames()[0].uuid(), new_frame1.uuid()) self.assertEqual(new_frame2.multiFrame(), new_multiframe2) @@ -319,14 +425,18 @@ def testSaveLoadTemplate(self): self.assertEqual(len(items), 8) multiframes2 = l2.multiFrames() self.assertEqual(len(multiframes2), 4) - multiframes2 = [m for m in l2.multiFrames() if not m.uuid() in [new_multiframe1.uuid(), new_multiframe2.uuid()]] + multiframes2 = [ + m + for m in l2.multiFrames() + if not m.uuid() in [new_multiframe1.uuid(), new_multiframe2.uuid()] + ] self.assertEqual(len(multiframes2), 2) - self.assertTrue([i for i in items if i.id() == 'xxyyxx']) - self.assertTrue([i for i in items if i.id() == 'zzyyzz']) - self.assertTrue([i for i in items if i.id() == 'frame1']) - self.assertTrue([i for i in items if i.id() == 'frame2']) - self.assertTrue([i for i in multiframes2 if i.html() == 'mf1']) - self.assertTrue([i for i in multiframes2 if i.html() == 'mf2']) + self.assertTrue([i for i in items if i.id() == "xxyyxx"]) + self.assertTrue([i for i in items if i.id() == "zzyyzz"]) + self.assertTrue([i for i in items if i.id() == "frame1"]) + self.assertTrue([i for i in items if i.id() == "frame2"]) + self.assertTrue([i for i in multiframes2 if i.html() == "mf1"]) + self.assertTrue([i for i in multiframes2 if i.html() == "mf2"]) self.assertIn(new_items[0], l2.items()) self.assertIn(new_items[1], l2.items()) self.assertIn(new_items[2], l2.items()) @@ -344,19 +454,41 @@ def testSaveLoadTemplate(self): self.assertNotIn(new_items2[3].uuid(), uuids) uuids.add(new_items[3].uuid()) - self.assertNotIn(multiframes2[0].uuid(), - [multiframe1.uuid(), multiframe2.uuid(), new_multiframe1.uuid(), new_multiframe2.uuid()]) - self.assertNotIn(multiframes2[1].uuid(), - [multiframe1.uuid(), multiframe2.uuid(), new_multiframe1.uuid(), new_multiframe2.uuid()]) - - new_multiframe1b = [i for i in multiframes2 if i.html() == 'mf1'][0] + self.assertNotIn( + multiframes2[0].uuid(), + [ + multiframe1.uuid(), + multiframe2.uuid(), + new_multiframe1.uuid(), + new_multiframe2.uuid(), + ], + ) + self.assertNotIn( + multiframes2[1].uuid(), + [ + multiframe1.uuid(), + multiframe2.uuid(), + new_multiframe1.uuid(), + new_multiframe2.uuid(), + ], + ) + + new_multiframe1b = [i for i in multiframes2 if i.html() == "mf1"][0] self.assertEqual(new_multiframe1b.layout(), l2) - new_multiframe2b = [i for i in multiframes2 if i.html() == 'mf2'][0] + new_multiframe2b = [i for i in multiframes2 if i.html() == "mf2"][0] self.assertEqual(new_multiframe2b.layout(), l2) - new_frame1b = sip.cast([i for i in items if i.id() == 'frame1' and i.uuid() != new_frame1.uuid()][0], - QgsLayoutFrame) - new_frame2b = sip.cast([i for i in items if i.id() == 'frame2' and i.uuid() != new_frame2.uuid()][0], - QgsLayoutFrame) + new_frame1b = sip.cast( + [i for i in items if i.id() == "frame1" and i.uuid() != new_frame1.uuid()][ + 0 + ], + QgsLayoutFrame, + ) + new_frame2b = sip.cast( + [i for i in items if i.id() == "frame2" and i.uuid() != new_frame2.uuid()][ + 0 + ], + QgsLayoutFrame, + ) self.assertEqual(new_frame1b.multiFrame(), new_multiframe1b) self.assertEqual(new_multiframe1b.frames()[0].uuid(), new_frame1b.uuid()) self.assertEqual(new_frame2b.multiFrame(), new_multiframe2b) @@ -369,21 +501,37 @@ def testSaveLoadTemplate(self): self.assertEqual(len(new_items3), 5) # includes page self.assertEqual(len(new_multiframes), 2) items = l2.items() - self.assertTrue([i for i in items if isinstance(i, QgsLayoutItem) and i.id() == 'xxyyxx']) - self.assertTrue([i for i in items if isinstance(i, QgsLayoutItem) and i.id() == 'zzyyzz']) - self.assertTrue([i for i in items if isinstance(i, QgsLayoutItem) and i.id() == 'frame1']) - self.assertTrue([i for i in items if isinstance(i, QgsLayoutItem) and i.id() == 'frame2']) + self.assertTrue( + [i for i in items if isinstance(i, QgsLayoutItem) and i.id() == "xxyyxx"] + ) + self.assertTrue( + [i for i in items if isinstance(i, QgsLayoutItem) and i.id() == "zzyyzz"] + ) + self.assertTrue( + [i for i in items if isinstance(i, QgsLayoutItem) and i.id() == "frame1"] + ) + self.assertTrue( + [i for i in items if isinstance(i, QgsLayoutItem) and i.id() == "frame2"] + ) self.assertIn(new_items3[0], l2.items()) self.assertIn(new_items3[1], l2.items()) self.assertIn(new_items3[2], l2.items()) self.assertIn(new_items3[3], l2.items()) - new_multiframe1 = [i for i in new_multiframes if i.html() == 'mf1'][0] - new_multiframe2 = [i for i in new_multiframes if i.html() == 'mf2'][0] - - new_frame1 = sip.cast([i for i in items if isinstance(i, QgsLayoutItem) and i.id() == 'frame1'][0], - QgsLayoutFrame) - new_frame2 = sip.cast([i for i in items if isinstance(i, QgsLayoutItem) and i.id() == 'frame2'][0], - QgsLayoutFrame) + new_multiframe1 = [i for i in new_multiframes if i.html() == "mf1"][0] + new_multiframe2 = [i for i in new_multiframes if i.html() == "mf2"][0] + + new_frame1 = sip.cast( + [i for i in items if isinstance(i, QgsLayoutItem) and i.id() == "frame1"][ + 0 + ], + QgsLayoutFrame, + ) + new_frame2 = sip.cast( + [i for i in items if isinstance(i, QgsLayoutItem) and i.id() == "frame2"][ + 0 + ], + QgsLayoutFrame, + ) self.assertEqual(new_frame1.multiFrame(), new_multiframe1) self.assertEqual(new_multiframe1.frames()[0].uuid(), new_frame1.uuid()) self.assertEqual(new_frame2.multiFrame(), new_multiframe2) @@ -456,18 +604,30 @@ def testLayoutItemAt(self): # add some items item1 = QgsLayoutItemMap(l) - item1.attemptMove(QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item1.attemptResize(QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item1.attemptMove( + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item1.attemptResize( + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addItem(item1) item2 = QgsLayoutItemMap(l) - item2.attemptMove(QgsLayoutPoint(6, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item2.attemptResize(QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item2.attemptMove( + QgsLayoutPoint(6, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item2.attemptResize( + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addItem(item2) item3 = QgsLayoutItemMap(l) - item3.attemptMove(QgsLayoutPoint(8, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item3.attemptResize(QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item3.attemptMove( + QgsLayoutPoint(8, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item3.attemptResize( + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) item3.setLocked(True) l.addItem(item3) @@ -489,25 +649,37 @@ def testLayoutItemAt(self): def testLayoutItemAtLockedGroup(self): """Test issue #57331 - layoutItemAt should not return locked groups - when ignoreLocked is True""" + when ignoreLocked is True""" p = QgsProject() l = QgsLayout(p) # add some items item1 = QgsLayoutItemMap(l) - item1.attemptMove(QgsLayoutPoint(0, 0, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item1.attemptResize(QgsLayoutSize(10, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item1.attemptMove( + QgsLayoutPoint(0, 0, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item1.attemptResize( + QgsLayoutSize(10, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addLayoutItem(item1) item2 = QgsLayoutItemMap(l) - item2.attemptMove(QgsLayoutPoint(5, 0, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item2.attemptResize(QgsLayoutSize(10, 5, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item2.attemptMove( + QgsLayoutPoint(5, 0, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item2.attemptResize( + QgsLayoutSize(10, 5, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addLayoutItem(item2) item3 = QgsLayoutItemMap(l) - item3.attemptMove(QgsLayoutPoint(5, 5, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item3.attemptResize(QgsLayoutSize(10, 5, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item3.attemptMove( + QgsLayoutPoint(5, 5, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item3.attemptResize( + QgsLayoutSize(10, 5, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addLayoutItem(item3) self.assertEqual(l.layoutItemAt(QPointF(2, 2), True), item1) @@ -630,7 +802,13 @@ def testStacking(self): def testConverGroupedHtmlLabelItem(self): p = QgsProject.instance() - p.read(os.path.join(TEST_DATA_DIR, 'projects', 'test-project-print_layout_with_group-qgis_330.qgz')) + p.read( + os.path.join( + TEST_DATA_DIR, + "projects", + "test-project-print_layout_with_group-qgis_330.qgz", + ) + ) lm = p.layoutManager() self.assertEqual(len(lm.printLayouts()), 1) @@ -638,9 +816,11 @@ def testConverGroupedHtmlLabelItem(self): self.assertEqual(len(layout.multiFrames()), 1) multi_frame = layout.multiFrames()[0] - self.assertEqual(multi_frame.html(), 'Lorem ipsum - Lorem ipsum, Lorem ipsum.') + self.assertEqual( + multi_frame.html(), "Lorem ipsum - Lorem ipsum, Lorem ipsum." + ) self.assertTrue(multi_frame.frame(0).isGroupMember()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutaligner.py b/tests/src/python/test_qgslayoutaligner.py index 7722a4b5df65..c0742fc72b96 100644 --- a/tests/src/python/test_qgslayoutaligner.py +++ b/tests/src/python/test_qgslayoutaligner.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '3/10/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "3/10/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.core import ( @@ -34,68 +35,200 @@ def testAlign(self): # add some items item1 = QgsLayoutItemPicture(l) - item1.attemptMove(QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item1.attemptResize(QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item1.attemptMove( + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item1.attemptResize( + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addItem(item1) item2 = QgsLayoutItemPicture(l) - item2.attemptMove(QgsLayoutPoint(6, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item2.attemptResize(QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item2.attemptMove( + QgsLayoutPoint(6, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item2.attemptResize( + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) item2.setReferencePoint(QgsLayoutItem.ReferencePoint.LowerMiddle) l.addItem(item2) # NOTE: item3 has measurement units specified in Centimeters, see below! item3 = QgsLayoutItemPicture(l) - item3.attemptMove(QgsLayoutPoint(0.8, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - item3.attemptResize(QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + item3.attemptMove( + QgsLayoutPoint(0.8, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) + item3.attemptResize( + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) item3.setReferencePoint(QgsLayoutItem.ReferencePoint.UpperRight) l.addItem(item3) - QgsLayoutAligner.alignItems(l, [item1, item2, item3], QgsLayoutAligner.Alignment.AlignLeft) - self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.positionWithUnits(), QgsLayoutPoint(9, 19, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.positionWithUnits(), QgsLayoutPoint(2.2, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - - QgsLayoutAligner.alignItems(l, [item1, item2, item3], QgsLayoutAligner.Alignment.AlignHCenter) - self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.positionWithUnits(), QgsLayoutPoint(13, 19, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.positionWithUnits(), QgsLayoutPoint(2.2, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - - QgsLayoutAligner.alignItems(l, [item1, item2, item3], QgsLayoutAligner.Alignment.AlignRight) - self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.positionWithUnits(), QgsLayoutPoint(17, 19, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.positionWithUnits(), QgsLayoutPoint(2.2, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - - QgsLayoutAligner.alignItems(l, [item1, item2, item3], QgsLayoutAligner.Alignment.AlignTop) - self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.positionWithUnits(), QgsLayoutPoint(17, 17, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.positionWithUnits(), QgsLayoutPoint(2.2, 0.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - - QgsLayoutAligner.alignItems(l, [item1, item2, item3], QgsLayoutAligner.Alignment.AlignVCenter) - self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.positionWithUnits(), QgsLayoutPoint(17, 20.5, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.positionWithUnits(), QgsLayoutPoint(2.2, 0.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - - QgsLayoutAligner.alignItems(l, [item1, item2, item3], QgsLayoutAligner.Alignment.AlignBottom) - self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.positionWithUnits(), QgsLayoutPoint(17, 24, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.positionWithUnits(), QgsLayoutPoint(2.2, 0.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + QgsLayoutAligner.alignItems( + l, [item1, item2, item3], QgsLayoutAligner.Alignment.AlignLeft + ) + self.assertEqual( + item1.positionWithUnits(), + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.positionWithUnits(), + QgsLayoutPoint(9, 19, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.positionWithUnits(), + QgsLayoutPoint(2.2, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + + QgsLayoutAligner.alignItems( + l, [item1, item2, item3], QgsLayoutAligner.Alignment.AlignHCenter + ) + self.assertEqual( + item1.positionWithUnits(), + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.positionWithUnits(), + QgsLayoutPoint(13, 19, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.positionWithUnits(), + QgsLayoutPoint(2.2, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + + QgsLayoutAligner.alignItems( + l, [item1, item2, item3], QgsLayoutAligner.Alignment.AlignRight + ) + self.assertEqual( + item1.positionWithUnits(), + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.positionWithUnits(), + QgsLayoutPoint(17, 19, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.positionWithUnits(), + QgsLayoutPoint(2.2, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + + QgsLayoutAligner.alignItems( + l, [item1, item2, item3], QgsLayoutAligner.Alignment.AlignTop + ) + self.assertEqual( + item1.positionWithUnits(), + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.positionWithUnits(), + QgsLayoutPoint(17, 17, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.positionWithUnits(), + QgsLayoutPoint(2.2, 0.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + + QgsLayoutAligner.alignItems( + l, [item1, item2, item3], QgsLayoutAligner.Alignment.AlignVCenter + ) + self.assertEqual( + item1.positionWithUnits(), + QgsLayoutPoint(4, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.positionWithUnits(), + QgsLayoutPoint(17, 20.5, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.positionWithUnits(), + QgsLayoutPoint(2.2, 0.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + + QgsLayoutAligner.alignItems( + l, [item1, item2, item3], QgsLayoutAligner.Alignment.AlignBottom + ) + self.assertEqual( + item1.positionWithUnits(), + QgsLayoutPoint(4, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.positionWithUnits(), + QgsLayoutPoint(17, 24, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.positionWithUnits(), + QgsLayoutPoint(2.2, 0.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) def testDistribute(self): p = QgsProject() @@ -103,108 +236,257 @@ def testDistribute(self): # add some items item1 = QgsLayoutItemPicture(l) - item1.attemptMove(QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item1.attemptResize(QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item1.attemptMove( + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item1.attemptResize( + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addItem(item1) item2 = QgsLayoutItemPicture(l) - item2.attemptMove(QgsLayoutPoint(7, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item2.attemptResize(QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item2.attemptMove( + QgsLayoutPoint(7, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item2.attemptResize( + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) item2.setReferencePoint(QgsLayoutItem.ReferencePoint.LowerMiddle) l.addItem(item2) # NOTE: item3 has measurement units specified in Centimeters, see below! item3 = QgsLayoutItemPicture(l) - item3.attemptMove(QgsLayoutPoint(0.8, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - item3.attemptResize(QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + item3.attemptMove( + QgsLayoutPoint(0.8, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) + item3.attemptResize( + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) item3.setReferencePoint(QgsLayoutItem.ReferencePoint.UpperRight) l.addItem(item3) - QgsLayoutAligner.distributeItems(l, [item1, item2, item3], QgsLayoutAligner.Distribution.DistributeLeft) + QgsLayoutAligner.distributeItems( + l, [item1, item2, item3], QgsLayoutAligner.Distribution.DistributeLeft + ) self.assertAlmostEqual(item1.positionWithUnits().x(), 4.0, 3) - self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item1.positionWithUnits(), + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item2.positionWithUnits().x(), 11.0, 3) - self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item3.positionWithUnits().x(), 2.6, 3) - self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - - QgsLayoutAligner.distributeItems(l, [item1, item2, item3], QgsLayoutAligner.Distribution.DistributeHCenter) + self.assertEqual( + item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + + QgsLayoutAligner.distributeItems( + l, [item1, item2, item3], QgsLayoutAligner.Distribution.DistributeHCenter + ) self.assertAlmostEqual(item1.positionWithUnits().x(), 5.0, 3) - self.assertEqual(item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item2.positionWithUnits().x(), 11.0, 3) - self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item3.positionWithUnits().x(), 2.6, 3) - self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - - QgsLayoutAligner.distributeItems(l, [item1, item2, item3], QgsLayoutAligner.Distribution.DistributeRight) + self.assertEqual( + item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + + QgsLayoutAligner.distributeItems( + l, [item1, item2, item3], QgsLayoutAligner.Distribution.DistributeRight + ) self.assertAlmostEqual(item1.positionWithUnits().x(), 3.0, 3) - self.assertEqual(item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item2.positionWithUnits().x(), 11.0, 3) - self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item3.positionWithUnits().x(), 2.6, 3) - self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - - QgsLayoutAligner.distributeItems(l, [item1, item2, item3], QgsLayoutAligner.Distribution.DistributeTop) + self.assertEqual( + item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + + QgsLayoutAligner.distributeItems( + l, [item1, item2, item3], QgsLayoutAligner.Distribution.DistributeTop + ) self.assertAlmostEqual(item1.positionWithUnits().y(), 8.0, 3) - self.assertEqual(item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item2.positionWithUnits().y(), 19.0, 3) - self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item3.positionWithUnits().y(), 1.2, 3) - self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - - QgsLayoutAligner.distributeItems(l, [item1, item2, item3], QgsLayoutAligner.Distribution.DistributeVCenter) + self.assertEqual( + item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + + QgsLayoutAligner.distributeItems( + l, [item1, item2, item3], QgsLayoutAligner.Distribution.DistributeVCenter + ) self.assertAlmostEqual(item1.positionWithUnits().y(), 8.0, 3) - self.assertEqual(item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item2.positionWithUnits().y(), 21.5, 3) - self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item3.positionWithUnits().y(), 1.2, 3) - self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - - QgsLayoutAligner.distributeItems(l, [item1, item2, item3], QgsLayoutAligner.Distribution.DistributeBottom) + self.assertEqual( + item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + + QgsLayoutAligner.distributeItems( + l, [item1, item2, item3], QgsLayoutAligner.Distribution.DistributeBottom + ) self.assertAlmostEqual(item1.positionWithUnits().y(), 8.0, 3) - self.assertEqual(item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item2.positionWithUnits().y(), 24.0, 3) - self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item3.positionWithUnits().y(), 1.2, 3) - self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - - QgsLayoutAligner.distributeItems(l, [item1, item2, item3], QgsLayoutAligner.Distribution.DistributeHSpace) + self.assertEqual( + item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + + QgsLayoutAligner.distributeItems( + l, [item1, item2, item3], QgsLayoutAligner.Distribution.DistributeHSpace + ) self.assertAlmostEqual(item1.positionWithUnits().x(), 3.0, 3) - self.assertEqual(item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item2.positionWithUnits().x(), 14.5, 3) - self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item3.positionWithUnits().x(), 2.6, 3) - self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - - QgsLayoutAligner.distributeItems(l, [item1, item2, item3], QgsLayoutAligner.Distribution.DistributeVSpace) + self.assertEqual( + item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + + QgsLayoutAligner.distributeItems( + l, [item1, item2, item3], QgsLayoutAligner.Distribution.DistributeVSpace + ) self.assertAlmostEqual(item1.positionWithUnits().y(), 8.0, 3) - self.assertEqual(item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item2.positionWithUnits().y(), 28.0, 3) - self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item3.positionWithUnits().y(), 1.15, 3) - self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) def testResize(self): p = QgsProject() @@ -212,55 +494,127 @@ def testResize(self): # add some items item1 = QgsLayoutItemPicture(l) - item1.attemptMove(QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item1.attemptResize(QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item1.attemptMove( + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item1.attemptResize( + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addItem(item1) item2 = QgsLayoutItemPicture(l) - item2.attemptMove(QgsLayoutPoint(7, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item2.attemptResize(QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item2.attemptMove( + QgsLayoutPoint(7, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item2.attemptResize( + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) item2.setReferencePoint(QgsLayoutItem.ReferencePoint.LowerMiddle) l.addItem(item2) # NOTE: item3 has measurement units specified in Centimeters, see below! item3 = QgsLayoutItemPicture(l) - item3.attemptMove(QgsLayoutPoint(0.8, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - item3.attemptResize(QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + item3.attemptMove( + QgsLayoutPoint(0.8, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) + item3.attemptResize( + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) item3.setReferencePoint(QgsLayoutItem.ReferencePoint.UpperRight) l.addItem(item3) - QgsLayoutAligner.resizeItems(l, [item1, item2, item3], QgsLayoutAligner.Resize.ResizeNarrowest) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(10, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.0, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + QgsLayoutAligner.resizeItems( + l, [item1, item2, item3], QgsLayoutAligner.Resize.ResizeNarrowest + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(10, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.0, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) l.undoStack().stack().undo() - QgsLayoutAligner.resizeItems(l, [item1, item2, item3], QgsLayoutAligner.Resize.ResizeWidest) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(18, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + QgsLayoutAligner.resizeItems( + l, [item1, item2, item3], QgsLayoutAligner.Resize.ResizeWidest + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(18, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) l.undoStack().stack().undo() - QgsLayoutAligner.resizeItems(l, [item1, item2, item3], QgsLayoutAligner.Resize.ResizeShortest) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 0.9, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + QgsLayoutAligner.resizeItems( + l, [item1, item2, item3], QgsLayoutAligner.Resize.ResizeShortest + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 0.9, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) l.undoStack().stack().undo() - QgsLayoutAligner.resizeItems(l, [item1, item2, item3], QgsLayoutAligner.Resize.ResizeTallest) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 16, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 16, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + QgsLayoutAligner.resizeItems( + l, [item1, item2, item3], QgsLayoutAligner.Resize.ResizeTallest + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 16, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 16, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) l.undoStack().stack().undo() - item2.attemptResize(QgsLayoutSize(10, 19, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - QgsLayoutAligner.resizeItems(l, [item1, item2, item3], QgsLayoutAligner.Resize.ResizeToSquare) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 18, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(19, 19, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + item2.attemptResize( + QgsLayoutSize(10, 19, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + QgsLayoutAligner.resizeItems( + l, [item1, item2, item3], QgsLayoutAligner.Resize.ResizeToSquare + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 18, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(19, 19, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) l.undoStack().stack().undo() QgsLayoutAligner.resizeItems(l, [item1], QgsLayoutAligner.Resize.ResizeToSquare) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 18, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 18, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutatlas.py b/tests/src/python/test_qgslayoutatlas.py index 6fb87160de9c..b5b36a6cacfe 100644 --- a/tests/src/python/test_qgslayoutatlas.py +++ b/tests/src/python/test_qgslayoutatlas.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '19/12/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "19/12/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import glob import os @@ -59,10 +60,12 @@ def control_path_prefix(cls): def testCase(self): self.TEST_DATA_DIR = unitTestDataPath() tmppath = tempfile.mkdtemp() - for file in glob.glob(os.path.join(self.TEST_DATA_DIR, 'france_parts.*')): + for file in glob.glob(os.path.join(self.TEST_DATA_DIR, "france_parts.*")): shutil.copy(os.path.join(self.TEST_DATA_DIR, file), tmppath) vectorFileInfo = QFileInfo(tmppath + "/france_parts.shp") - mVectorLayer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") + mVectorLayer = QgsVectorLayer( + vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr" + ) QgsProject.instance().addMapLayers([mVectorLayer]) self.layers = [mVectorLayer] @@ -70,14 +73,14 @@ def testCase(self): # create layout with layout map # select epsg:2154 - crs = QgsCoordinateReferenceSystem('epsg:2154') + crs = QgsCoordinateReferenceSystem("epsg:2154") QgsProject.instance().setCrs(crs) self.layout = QgsPrintLayout(QgsProject.instance()) self.layout.initializeDefaults() # fix the renderer, fill with green - props = {"color": "0,127,0", 'outline_color': 'black'} + props = {"color": "0,127,0", "outline_color": "black"} fillSymbol = QgsFillSymbol.createSimple(props) renderer = QgsSingleSymbolRenderer(fillSymbol) mVectorLayer.setRenderer(renderer) @@ -105,14 +108,14 @@ def testCase(self): self.overview.setExtent(nextent) # set the fill symbol of the overview map - props2 = {"color": "127,0,0,127", 'outline_color': 'black'} + props2 = {"color": "127,0,0,127", "outline_color": "black"} fillSymbol2 = QgsFillSymbol.createSimple(props2) self.overview.overview().setFrameSymbol(fillSymbol2) # header label self.mLabel1 = QgsLayoutItemLabel(self.layout) self.layout.addLayoutItem(self.mLabel1) - self.mLabel1.setText("[% \"NAME_1\" %] area") + self.mLabel1.setText('[% "NAME_1" %] area') self.mLabel1.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel1.adjustSizeToText() self.mLabel1.attemptSetSceneRect(QRectF(150, 5, 60, 15)) @@ -122,7 +125,9 @@ def testCase(self): # feature number label self.mLabel2 = QgsLayoutItemLabel(self.layout) self.layout.addLayoutItem(self.mLabel2) - self.mLabel2.setText("# [%@atlas_featurenumber || ' / ' || @atlas_totalfeatures%]") + self.mLabel2.setText( + "# [%@atlas_featurenumber || ' / ' || @atlas_totalfeatures%]" + ) self.mLabel2.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel2.adjustSizeToText() self.mLabel2.attemptSetSceneRect(QRectF(150, 200, 60, 15)) @@ -142,7 +147,9 @@ def testCase(self): def testReadWriteXml(self): p = QgsProject() vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") - vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") + vector_layer = QgsVectorLayer( + vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr" + ) self.assertTrue(vector_layer.isValid()) p.addMapLayer(vector_layer) @@ -150,14 +157,14 @@ def testReadWriteXml(self): atlas = l.atlas() atlas.setEnabled(True) atlas.setHideCoverage(True) - atlas.setFilenameExpression('filename exp') + atlas.setFilenameExpression("filename exp") atlas.setCoverageLayer(vector_layer) - atlas.setPageNameExpression('page name') + atlas.setPageNameExpression("page name") atlas.setSortFeatures(True) atlas.setSortAscending(False) - atlas.setSortExpression('sort exp') + atlas.setSortExpression("sort exp") atlas.setFilterFeatures(True) - atlas.setFilterExpression('filter exp') + atlas.setFilterExpression("filter exp") doc = QDomDocument("testdoc") elem = l.writeXml(doc, QgsReadWriteContext()) @@ -167,19 +174,21 @@ def testReadWriteXml(self): atlas2 = l2.atlas() self.assertTrue(atlas2.enabled()) self.assertTrue(atlas2.hideCoverage()) - self.assertEqual(atlas2.filenameExpression(), 'filename exp') + self.assertEqual(atlas2.filenameExpression(), "filename exp") self.assertEqual(atlas2.coverageLayer(), vector_layer) - self.assertEqual(atlas2.pageNameExpression(), 'page name') + self.assertEqual(atlas2.pageNameExpression(), "page name") self.assertTrue(atlas2.sortFeatures()) self.assertFalse(atlas2.sortAscending()) - self.assertEqual(atlas2.sortExpression(), 'sort exp') + self.assertEqual(atlas2.sortExpression(), "sort exp") self.assertTrue(atlas2.filterFeatures()) - self.assertEqual(atlas2.filterExpression(), 'filter exp') + self.assertEqual(atlas2.filterExpression(), "filter exp") def testIteration(self): p = QgsProject() vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") - vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") + vector_layer = QgsVectorLayer( + vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr" + ) self.assertTrue(vector_layer.isValid()) p.addMapLayer(vector_layer) @@ -196,7 +205,7 @@ def testIteration(self): self.assertEqual(len(atlas_feature_changed_spy), 1) self.assertEqual(len(context_changed_spy), 1) self.assertEqual(atlas.currentFeatureNumber(), 0) - self.assertEqual(l.reportContext().feature()[4], 'Basse-Normandie') + self.assertEqual(l.reportContext().feature()[4], "Basse-Normandie") self.assertEqual(l.reportContext().layer(), vector_layer) f1 = l.reportContext().feature() @@ -204,21 +213,21 @@ def testIteration(self): self.assertEqual(len(atlas_feature_changed_spy), 2) self.assertEqual(len(context_changed_spy), 2) self.assertEqual(atlas.currentFeatureNumber(), 1) - self.assertEqual(l.reportContext().feature()[4], 'Bretagne') + self.assertEqual(l.reportContext().feature()[4], "Bretagne") f2 = l.reportContext().feature() self.assertTrue(atlas.next()) self.assertEqual(len(atlas_feature_changed_spy), 3) self.assertEqual(len(context_changed_spy), 3) self.assertEqual(atlas.currentFeatureNumber(), 2) - self.assertEqual(l.reportContext().feature()[4], 'Pays de la Loire') + self.assertEqual(l.reportContext().feature()[4], "Pays de la Loire") f3 = l.reportContext().feature() self.assertTrue(atlas.next()) self.assertEqual(len(atlas_feature_changed_spy), 4) self.assertEqual(len(context_changed_spy), 4) self.assertEqual(atlas.currentFeatureNumber(), 3) - self.assertEqual(l.reportContext().feature()[4], 'Centre') + self.assertEqual(l.reportContext().feature()[4], "Centre") f4 = l.reportContext().feature() self.assertFalse(atlas.next()) @@ -226,19 +235,19 @@ def testIteration(self): self.assertEqual(len(atlas_feature_changed_spy), 5) self.assertEqual(len(context_changed_spy), 5) self.assertEqual(atlas.currentFeatureNumber(), 2) - self.assertEqual(l.reportContext().feature()[4], 'Pays de la Loire') + self.assertEqual(l.reportContext().feature()[4], "Pays de la Loire") self.assertTrue(atlas.last()) self.assertEqual(len(atlas_feature_changed_spy), 6) self.assertEqual(len(context_changed_spy), 6) self.assertEqual(atlas.currentFeatureNumber(), 3) - self.assertEqual(l.reportContext().feature()[4], 'Centre') + self.assertEqual(l.reportContext().feature()[4], "Centre") self.assertTrue(atlas.previous()) self.assertEqual(len(atlas_feature_changed_spy), 7) self.assertEqual(len(context_changed_spy), 7) self.assertEqual(atlas.currentFeatureNumber(), 2) - self.assertEqual(l.reportContext().feature()[4], 'Pays de la Loire') + self.assertEqual(l.reportContext().feature()[4], "Pays de la Loire") self.assertTrue(atlas.previous()) self.assertTrue(atlas.previous()) @@ -250,19 +259,21 @@ def testIteration(self): self.assertEqual(len(atlas_feature_changed_spy), 10) self.assertTrue(atlas.seekTo(f1)) - self.assertEqual(l.reportContext().feature()[4], 'Basse-Normandie') + self.assertEqual(l.reportContext().feature()[4], "Basse-Normandie") self.assertTrue(atlas.seekTo(f4)) - self.assertEqual(l.reportContext().feature()[4], 'Centre') + self.assertEqual(l.reportContext().feature()[4], "Centre") self.assertTrue(atlas.seekTo(f3)) - self.assertEqual(l.reportContext().feature()[4], 'Pays de la Loire') + self.assertEqual(l.reportContext().feature()[4], "Pays de la Loire") self.assertTrue(atlas.seekTo(f2)) - self.assertEqual(l.reportContext().feature()[4], 'Bretagne') + self.assertEqual(l.reportContext().feature()[4], "Bretagne") self.assertFalse(atlas.seekTo(QgsFeature(5))) def testUpdateFeature(self): p = QgsProject() vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") - vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") + vector_layer = QgsVectorLayer( + vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr" + ) self.assertTrue(vector_layer.isValid()) p.addMapLayer(vector_layer) @@ -274,20 +285,26 @@ def testUpdateFeature(self): self.assertTrue(atlas.beginRender()) self.assertTrue(atlas.first()) self.assertEqual(atlas.currentFeatureNumber(), 0) - self.assertEqual(l.reportContext().feature()[4], 'Basse-Normandie') + self.assertEqual(l.reportContext().feature()[4], "Basse-Normandie") self.assertEqual(l.reportContext().layer(), vector_layer) vector_layer.startEditing() - self.assertTrue(vector_layer.changeAttributeValue(l.reportContext().feature().id(), 4, 'Nah, Canberra mate!')) - self.assertEqual(l.reportContext().feature()[4], 'Basse-Normandie') + self.assertTrue( + vector_layer.changeAttributeValue( + l.reportContext().feature().id(), 4, "Nah, Canberra mate!" + ) + ) + self.assertEqual(l.reportContext().feature()[4], "Basse-Normandie") l.atlas().refreshCurrentFeature() - self.assertEqual(l.reportContext().feature()[4], 'Nah, Canberra mate!') + self.assertEqual(l.reportContext().feature()[4], "Nah, Canberra mate!") vector_layer.rollBack() def testFileName(self): p = QgsProject() vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") - vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") + vector_layer = QgsVectorLayer( + vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr" + ) self.assertTrue(vector_layer.isValid()) p.addMapLayer(vector_layer) @@ -300,31 +317,49 @@ def testFileName(self): self.assertTrue(atlas.beginRender()) self.assertEqual(atlas.count(), 4) atlas.first() - self.assertEqual(atlas.currentFilename(), 'output_Basse-Normandie') - self.assertEqual(atlas.filePath('/tmp/output/', 'png'), '/tmp/output/output_Basse-Normandie.png') - self.assertEqual(atlas.filePath('/tmp/output/', '.png'), '/tmp/output/output_Basse-Normandie.png') - self.assertEqual(atlas.filePath('/tmp/output/', 'svg'), '/tmp/output/output_Basse-Normandie.svg') + self.assertEqual(atlas.currentFilename(), "output_Basse-Normandie") + self.assertEqual( + atlas.filePath("/tmp/output/", "png"), + "/tmp/output/output_Basse-Normandie.png", + ) + self.assertEqual( + atlas.filePath("/tmp/output/", ".png"), + "/tmp/output/output_Basse-Normandie.png", + ) + self.assertEqual( + atlas.filePath("/tmp/output/", "svg"), + "/tmp/output/output_Basse-Normandie.svg", + ) atlas.next() - self.assertEqual(atlas.currentFilename(), 'output_Bretagne') - self.assertEqual(atlas.filePath('/tmp/output/', 'png'), '/tmp/output/output_Bretagne.png') + self.assertEqual(atlas.currentFilename(), "output_Bretagne") + self.assertEqual( + atlas.filePath("/tmp/output/", "png"), "/tmp/output/output_Bretagne.png" + ) atlas.next() - self.assertEqual(atlas.currentFilename(), 'output_Pays de la Loire') - self.assertEqual(atlas.filePath('/tmp/output/', 'png'), '/tmp/output/output_Pays de la Loire.png') + self.assertEqual(atlas.currentFilename(), "output_Pays de la Loire") + self.assertEqual( + atlas.filePath("/tmp/output/", "png"), + "/tmp/output/output_Pays de la Loire.png", + ) atlas.next() - self.assertEqual(atlas.currentFilename(), 'output_Centre') - self.assertEqual(atlas.filePath('/tmp/output/', 'png'), '/tmp/output/output_Centre.png') + self.assertEqual(atlas.currentFilename(), "output_Centre") + self.assertEqual( + atlas.filePath("/tmp/output/", "png"), "/tmp/output/output_Centre.png" + ) # try changing expression, filename should be updated instantly atlas.setFilenameExpression("'export_' || \"NAME_1\"") - self.assertEqual(atlas.currentFilename(), 'export_Centre') + self.assertEqual(atlas.currentFilename(), "export_Centre") atlas.endRender() def testNameForPage(self): p = QgsProject() vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") - vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") + vector_layer = QgsVectorLayer( + vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr" + ) self.assertTrue(vector_layer.isValid()) p.addMapLayer(vector_layer) @@ -332,13 +367,13 @@ def testNameForPage(self): atlas = l.atlas() atlas.setEnabled(True) atlas.setCoverageLayer(vector_layer) - atlas.setPageNameExpression("\"NAME_1\"") + atlas.setPageNameExpression('"NAME_1"') self.assertTrue(atlas.beginRender()) - self.assertEqual(atlas.nameForPage(0), 'Basse-Normandie') - self.assertEqual(atlas.nameForPage(1), 'Bretagne') - self.assertEqual(atlas.nameForPage(2), 'Pays de la Loire') - self.assertEqual(atlas.nameForPage(3), 'Centre') + self.assertEqual(atlas.nameForPage(0), "Basse-Normandie") + self.assertEqual(atlas.nameForPage(1), "Bretagne") + self.assertEqual(atlas.nameForPage(2), "Pays de la Loire") + self.assertEqual(atlas.nameForPage(3), "Centre") def filename_test(self): self.atlas.setFilenameExpression("'output_' || @atlas_featurenumber") @@ -351,11 +386,15 @@ def filename_test(self): # using feature attribute (refs https://github.com/qgis/QGIS/issues/27379) - self.atlas.setFilenameExpression("'output_' || attribute(@atlas_feature,'NAME_1')") - expected = ['output_Basse-Normandie', - 'output_Bretagne', - 'output_Pays de la Loire', - 'output_Centre'] + self.atlas.setFilenameExpression( + "'output_' || attribute(@atlas_feature,'NAME_1')" + ) + expected = [ + "output_Basse-Normandie", + "output_Bretagne", + "output_Pays de la Loire", + "output_Centre", + ] self.atlas.beginRender() for i in range(0, self.atlas.count()): self.atlas.seekTo(i) @@ -364,7 +403,13 @@ def filename_test(self): def autoscale_render_test(self): self.atlas_map.setExtent( - QgsRectangle(332719.06221504929, 6765214.5887386119, 560957.85090677091, 6993453.3774303338)) + QgsRectangle( + 332719.06221504929, + 6765214.5887386119, + 560957.85090677091, + 6993453.3774303338, + ) + ) self.atlas_map.setAtlasDriven(True) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.AtlasScalingMode.Auto) @@ -378,9 +423,7 @@ def autoscale_render_test(self): self.assertTrue( self.render_layout_check( - 'atlas_autoscale%d' % (i + 1), - self.layout, - allowed_mismatch=200 + "atlas_autoscale%d" % (i + 1), self.layout, allowed_mismatch=200 ) ) self.atlas.endRender() @@ -390,7 +433,9 @@ def autoscale_render_test(self): self.atlas_map.setAtlasMargin(0) def fixedscale_render_test(self): - self.atlas_map.setExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) + self.atlas_map.setExtent( + QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620) + ) self.atlas_map.setAtlasDriven(True) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.AtlasScalingMode.Fixed) @@ -402,16 +447,16 @@ def fixedscale_render_test(self): self.assertTrue( self.render_layout_check( - 'atlas_fixedscale%d' % (i + 1), - self.layout, - allowed_mismatch=200 + "atlas_fixedscale%d" % (i + 1), self.layout, allowed_mismatch=200 ) ) self.atlas.endRender() def predefinedscales_render_test(self): - self.atlas_map.setExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) + self.atlas_map.setExtent( + QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620) + ) self.atlas_map.setAtlasDriven(True) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.AtlasScalingMode.Predefined) @@ -428,15 +473,17 @@ def predefinedscales_render_test(self): self.assertTrue( self.render_layout_check( - 'atlas_predefinedscales%d' % (i + 1), + "atlas_predefinedscales%d" % (i + 1), self.layout, - allowed_mismatch=200 + allowed_mismatch=200, ) ) self.atlas.endRender() def hidden_render_test(self): - self.atlas_map.setExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) + self.atlas_map.setExtent( + QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620) + ) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.AtlasScalingMode.Fixed) self.atlas.setHideCoverage(True) @@ -448,9 +495,7 @@ def hidden_render_test(self): self.assertTrue( self.render_layout_check( - 'atlas_hiding%d' % (i + 1), - self.layout, - allowed_mismatch=200 + "atlas_hiding%d" % (i + 1), self.layout, allowed_mismatch=200 ) ) self.atlas.endRender() @@ -458,7 +503,9 @@ def hidden_render_test(self): self.atlas.setHideCoverage(False) def sorting_render_test(self): - self.atlas_map.setExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) + self.atlas_map.setExtent( + QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620) + ) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.AtlasScalingMode.Fixed) self.atlas.setHideCoverage(False) @@ -474,23 +521,25 @@ def sorting_render_test(self): self.assertTrue( self.render_layout_check( - 'atlas_sorting%d' % (i + 1), - self.layout, - allowed_mismatch=200 + "atlas_sorting%d" % (i + 1), self.layout, allowed_mismatch=200 ) ) self.atlas.endRender() def filtering_render_test(self): - self.atlas_map.setExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) + self.atlas_map.setExtent( + QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620) + ) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.AtlasScalingMode.Fixed) self.atlas.setHideCoverage(False) self.atlas.setSortFeatures(False) self.atlas.setFilterFeatures(True) - self.atlas.setFeatureFilter("substr(NAME_1,1,1)='P'") # select only 'Pays de la loire' + self.atlas.setFeatureFilter( + "substr(NAME_1,1,1)='P'" + ) # select only 'Pays de la loire' self.atlas.beginRender() @@ -500,16 +549,16 @@ def filtering_render_test(self): self.assertTrue( self.render_layout_check( - 'atlas_filtering%d' % (i + 1), - self.layout, - allowed_mismatch=200 + "atlas_filtering%d" % (i + 1), self.layout, allowed_mismatch=200 ) ) self.atlas.endRender() def test_clipping(self): vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") - vectorLayer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") + vectorLayer = QgsVectorLayer( + vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr" + ) p = QgsProject() p.addMapLayers([vectorLayer]) @@ -517,14 +566,14 @@ def test_clipping(self): # create layout with layout map # select epsg:2154 - crs = QgsCoordinateReferenceSystem('epsg:2154') + crs = QgsCoordinateReferenceSystem("epsg:2154") p.setCrs(crs) layout = QgsPrintLayout(p) layout.initializeDefaults() # fix the renderer, fill with green - props = {"color": "0,127,0", 'outline_style': 'no'} + props = {"color": "0,127,0", "outline_style": "no"} fillSymbol = QgsFillSymbol.createSimple(props) renderer = QgsSingleSymbolRenderer(fillSymbol) vectorLayer.setRenderer(renderer) @@ -542,7 +591,13 @@ def test_clipping(self): atlas.setEnabled(True) atlas_map.setExtent( - QgsRectangle(332719.06221504929, 6765214.5887386119, 560957.85090677091, 6993453.3774303338)) + QgsRectangle( + 332719.06221504929, + 6765214.5887386119, + 560957.85090677091, + 6993453.3774303338, + ) + ) atlas_map.setAtlasDriven(True) atlas_map.setAtlasScalingMode(QgsLayoutItemMap.AtlasScalingMode.Auto) @@ -557,9 +612,7 @@ def test_clipping(self): self.assertTrue( self.render_layout_check( - 'atlas_clipping%d' % (i + 1), - layout, - allowed_mismatch=200 + "atlas_clipping%d" % (i + 1), layout, allowed_mismatch=200 ) ) @@ -571,7 +624,11 @@ def legend_test(self): self.atlas_map.setAtlasMargin(0.10) # add a point layer - ptLayer = QgsVectorLayer("Point?crs=epsg:4326&field=attr:int(1)&field=label:string(20)", "points", "memory") + ptLayer = QgsVectorLayer( + "Point?crs=epsg:4326&field=attr:int(1)&field=label:string(20)", + "points", + "memory", + ) pr = ptLayer.dataProvider() f1 = QgsFeature(1) @@ -587,8 +644,25 @@ def legend_test(self): pr.addFeatures([f1, f2]) # categorized symbology - r = QgsCategorizedSymbolRenderer("attr", [QgsRendererCategory(1, QgsMarkerSymbol.createSimple({"color": "255,0,0", 'outline_color': 'black'}), "red"), - QgsRendererCategory(2, QgsMarkerSymbol.createSimple({"color": "0,0,255", 'outline_color': 'black'}), "blue")]) + r = QgsCategorizedSymbolRenderer( + "attr", + [ + QgsRendererCategory( + 1, + QgsMarkerSymbol.createSimple( + {"color": "255,0,0", "outline_color": "black"} + ), + "red", + ), + QgsRendererCategory( + 2, + QgsMarkerSymbol.createSimple( + {"color": "0,0,255", "outline_color": "black"} + ), + "blue", + ), + ], + ) ptLayer.setRenderer(r) QgsProject.instance().addMapLayer(ptLayer) @@ -601,10 +675,18 @@ def legend_test(self): # add a legend legend = QgsLayoutItemLegend(self.layout) - legend.rstyle(QgsLegendStyle.Style.Title).setFont(QgsFontUtils.getStandardTestFont('Bold', 20)) - legend.rstyle(QgsLegendStyle.Style.Group).setFont(QgsFontUtils.getStandardTestFont('Bold', 18)) - legend.rstyle(QgsLegendStyle.Style.Subgroup).setFont(QgsFontUtils.getStandardTestFont('Bold', 18)) - legend.rstyle(QgsLegendStyle.Style.SymbolLabel).setFont(QgsFontUtils.getStandardTestFont('Bold', 14)) + legend.rstyle(QgsLegendStyle.Style.Title).setFont( + QgsFontUtils.getStandardTestFont("Bold", 20) + ) + legend.rstyle(QgsLegendStyle.Style.Group).setFont( + QgsFontUtils.getStandardTestFont("Bold", 18) + ) + legend.rstyle(QgsLegendStyle.Style.Subgroup).setFont( + QgsFontUtils.getStandardTestFont("Bold", 18) + ) + legend.rstyle(QgsLegendStyle.Style.SymbolLabel).setFont( + QgsFontUtils.getStandardTestFont("Bold", 14) + ) legend.setTitle("Legend") legend.attemptMove(QgsLayoutPoint(200, 100)) @@ -618,12 +700,7 @@ def legend_test(self): self.atlas.seekTo(0) self.mLabel1.adjustSizeToText() - self.assertTrue( - self.render_layout_check( - 'atlas_legend', - self.layout - ) - ) + self.assertTrue(self.render_layout_check("atlas_legend", self.layout)) self.atlas.endRender() @@ -637,10 +714,12 @@ def rotation_test(self): # Then we will make it the object layer for the atlas, # rotate the map and test that the bounding rectangle # is smaller than the bounds without rotation. - polygonLayer = QgsVectorLayer('Polygon', 'test_polygon', 'memory') + polygonLayer = QgsVectorLayer("Polygon", "test_polygon", "memory") poly = QgsFeature(polygonLayer.fields()) points = [(10, 15), (15, 10), (45, 40), (40, 45)] - poly.setGeometry(QgsGeometry.fromPolygonXY([[QgsPointXY(x[0], x[1]) for x in points]])) + poly.setGeometry( + QgsGeometry.fromPolygonXY([[QgsPointXY(x[0], x[1]) for x in points]]) + ) polygonLayer.dataProvider().addFeatures([poly]) QgsProject.instance().addMapLayer(polygonLayer) @@ -681,18 +760,26 @@ def rotation_test(self): QgsProject.instance().removeMapLayer(polygonLayer) def test_datadefined_margin(self): - polygonLayer = QgsVectorLayer('Polygon?field=margin:int', 'test_polygon', 'memory') + polygonLayer = QgsVectorLayer( + "Polygon?field=margin:int", "test_polygon", "memory" + ) poly = QgsFeature(polygonLayer.fields()) poly.setAttributes([0]) - poly.setGeometry(QgsGeometry.fromWkt('Polygon((30 30, 40 30, 40 40, 30 40, 30 30))')) + poly.setGeometry( + QgsGeometry.fromWkt("Polygon((30 30, 40 30, 40 40, 30 40, 30 30))") + ) polygonLayer.dataProvider().addFeatures([poly]) poly = QgsFeature(polygonLayer.fields()) poly.setAttributes([10]) - poly.setGeometry(QgsGeometry.fromWkt('Polygon((10 10, 20 10, 20 20, 10 20, 10 10))')) + poly.setGeometry( + QgsGeometry.fromWkt("Polygon((10 10, 20 10, 20 20, 10 20, 10 10))") + ) polygonLayer.dataProvider().addFeatures([poly]) poly = QgsFeature(polygonLayer.fields()) poly.setAttributes([20]) - poly.setGeometry(QgsGeometry.fromWkt('Polygon((50 50, 60 50, 60 60, 50 60, 50 50))')) + poly.setGeometry( + QgsGeometry.fromWkt("Polygon((50 50, 60 50, 60 60, 50 60, 50 50))") + ) polygonLayer.dataProvider().addFeatures([poly]) QgsProject.instance().addMapLayer(polygonLayer) @@ -712,7 +799,10 @@ def test_datadefined_margin(self): map.setAtlasDriven(True) map.setAtlasScalingMode(QgsLayoutItemMap.AtlasScalingMode.Auto) map.setAtlasMargin(77.0) - map.dataDefinedProperties().setProperty(QgsLayoutObject.DataDefinedProperty.MapAtlasMargin, QgsProperty.fromExpression('margin/2')) + map.dataDefinedProperties().setProperty( + QgsLayoutObject.DataDefinedProperty.MapAtlasMargin, + QgsProperty.fromExpression("margin/2"), + ) atlas.beginRender() atlas.first() @@ -730,9 +820,9 @@ def testChangedSignal(self): atlas = layout.atlas() s = QSignalSpy(atlas.changed) - atlas.setPageNameExpression('1+2') + atlas.setPageNameExpression("1+2") self.assertEqual(len(s), 1) - atlas.setPageNameExpression('1+2') + atlas.setPageNameExpression("1+2") self.assertEqual(len(s), 1) atlas.setSortFeatures(True) @@ -745,9 +835,9 @@ def testChangedSignal(self): atlas.setSortAscending(False) self.assertEqual(len(s), 3) - atlas.setSortExpression('1+2') + atlas.setSortExpression("1+2") self.assertEqual(len(s), 4) - atlas.setSortExpression('1+2') + atlas.setSortExpression("1+2") self.assertEqual(len(s), 4) atlas.setFilterFeatures(True) @@ -755,9 +845,9 @@ def testChangedSignal(self): atlas.setFilterFeatures(True) self.assertEqual(len(s), 5) - atlas.setFilterExpression('1+2') + atlas.setFilterExpression("1+2") self.assertEqual(len(s), 6) - atlas.setFilterExpression('1+2') + atlas.setFilterExpression("1+2") self.assertEqual(len(s), 6) atlas.setHideCoverage(True) @@ -765,11 +855,11 @@ def testChangedSignal(self): atlas.setHideCoverage(True) self.assertEqual(len(s), 7) - atlas.setFilenameExpression('1+2') + atlas.setFilenameExpression("1+2") self.assertEqual(len(s), 8) - atlas.setFilenameExpression('1+2') + atlas.setFilenameExpression("1+2") self.assertEqual(len(s), 8) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutatlasclippingsettings.py b/tests/src/python/test_qgslayoutatlasclippingsettings.py index e6191b22f109..3439be6582aa 100644 --- a/tests/src/python/test_qgslayoutatlasclippingsettings.py +++ b/tests/src/python/test_qgslayoutatlasclippingsettings.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 Nyall Dawson' -__date__ = '03/07/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 Nyall Dawson" +__date__ = "03/07/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy from qgis.PyQt.QtXml import QDomDocument @@ -46,10 +47,17 @@ def testSettings(self): settings.setEnabled(True) self.assertEqual(len(spy), 1) - settings.setFeatureClippingType(QgsMapClippingRegion.FeatureClippingType.NoClipping) - self.assertEqual(settings.featureClippingType(), QgsMapClippingRegion.FeatureClippingType.NoClipping) + settings.setFeatureClippingType( + QgsMapClippingRegion.FeatureClippingType.NoClipping + ) + self.assertEqual( + settings.featureClippingType(), + QgsMapClippingRegion.FeatureClippingType.NoClipping, + ) self.assertEqual(len(spy), 2) - settings.setFeatureClippingType(QgsMapClippingRegion.FeatureClippingType.NoClipping) + settings.setFeatureClippingType( + QgsMapClippingRegion.FeatureClippingType.NoClipping + ) self.assertEqual(len(spy), 2) self.assertFalse(settings.forceLabelsInsideFeature()) @@ -59,10 +67,12 @@ def testSettings(self): settings.setForceLabelsInsideFeature(True) self.assertEqual(len(spy), 3) - l1 = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") - l2 = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + l1 = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) + l2 = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) p.addMapLayers([l1, l2]) self.assertFalse(settings.layersToClip()) settings.setLayersToClip([l1, l2]) @@ -82,10 +92,12 @@ def testSettings(self): def testSaveRestore(self): p = QgsProject() - l1 = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") - l2 = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + l1 = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) + l2 = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) p.addMapLayers([l1, l2]) l = QgsLayout(p) @@ -93,7 +105,9 @@ def testSaveRestore(self): settings = map.atlasClippingSettings() settings.setEnabled(True) - settings.setFeatureClippingType(QgsMapClippingRegion.FeatureClippingType.NoClipping) + settings.setFeatureClippingType( + QgsMapClippingRegion.FeatureClippingType.NoClipping + ) settings.setForceLabelsInsideFeature(True) settings.setRestrictToLayers(True) settings.setLayersToClip([l2]) @@ -108,14 +122,19 @@ def testSaveRestore(self): self.assertFalse(map2.atlasClippingSettings().enabled()) # restore from xml - self.assertTrue(map2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext())) + self.assertTrue( + map2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext()) + ) self.assertTrue(map2.atlasClippingSettings().enabled()) - self.assertEqual(map2.atlasClippingSettings().featureClippingType(), QgsMapClippingRegion.FeatureClippingType.NoClipping) + self.assertEqual( + map2.atlasClippingSettings().featureClippingType(), + QgsMapClippingRegion.FeatureClippingType.NoClipping, + ) self.assertTrue(map2.atlasClippingSettings().forceLabelsInsideFeature()) self.assertEqual(map2.atlasClippingSettings().layersToClip(), [l2]) self.assertTrue(map2.atlasClippingSettings().restrictToLayers()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutcombobox.py b/tests/src/python/test_qgslayoutcombobox.py index 078005be68c2..c1aea3e146b9 100644 --- a/tests/src/python/test_qgslayoutcombobox.py +++ b/tests/src/python/test_qgslayoutcombobox.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2019 by Nyall Dawson' -__date__ = '11/03/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "(C) 2019 by Nyall Dawson" +__date__ = "11/03/2019" +__copyright__ = "Copyright 2019, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy from qgis.core import ( @@ -42,22 +43,22 @@ def testCombo(self): project = QgsProject() manager = QgsLayoutManager(project) layout = QgsPrintLayout(project) - layout.setName('ccc') + layout.setName("ccc") self.assertTrue(manager.addLayout(layout)) layout2 = QgsPrintLayout(project) - layout2.setName('bbb') + layout2.setName("bbb") self.assertTrue(manager.addLayout(layout2)) r = QgsReport(project) - r.setName('ddd') + r.setName("ddd") manager.addLayout(r) combo = QgsLayoutComboBox(None, manager) spy = QSignalSpy(combo.layoutChanged) self.assertEqual(combo.count(), 3) - self.assertEqual(combo.itemText(0), 'bbb') - self.assertEqual(combo.itemText(1), 'ccc') - self.assertEqual(combo.itemText(2), 'ddd') + self.assertEqual(combo.itemText(0), "bbb") + self.assertEqual(combo.itemText(1), "ccc") + self.assertEqual(combo.itemText(2), "ddd") self.assertEqual(combo.layout(0), layout2) self.assertEqual(combo.layout(1), layout) @@ -78,25 +79,27 @@ def testCombo(self): combo.setAllowEmptyLayout(True) self.assertEqual(combo.count(), 4) - self.assertEqual(combo.itemText(0), '') - self.assertEqual(combo.itemText(1), 'bbb') - self.assertEqual(combo.itemText(2), 'ccc') - self.assertEqual(combo.itemText(3), 'ddd') + self.assertEqual(combo.itemText(0), "") + self.assertEqual(combo.itemText(1), "bbb") + self.assertEqual(combo.itemText(2), "ccc") + self.assertEqual(combo.itemText(3), "ddd") combo.setCurrentLayout(None) self.assertEqual(combo.currentIndex(), 0) combo.setFilters(QgsLayoutManagerProxyModel.Filter.FilterPrintLayouts) self.assertEqual(combo.count(), 3) - self.assertEqual(combo.itemText(0), '') - self.assertEqual(combo.itemText(1), 'bbb') - self.assertEqual(combo.itemText(2), 'ccc') + self.assertEqual(combo.itemText(0), "") + self.assertEqual(combo.itemText(1), "bbb") + self.assertEqual(combo.itemText(2), "ccc") combo.setFilters(QgsLayoutManagerProxyModel.Filter.FilterReports) - self.assertEqual(combo.filters(), QgsLayoutManagerProxyModel.Filter.FilterReports) + self.assertEqual( + combo.filters(), QgsLayoutManagerProxyModel.Filter.FilterReports + ) self.assertEqual(combo.count(), 2) - self.assertEqual(combo.itemText(0), '') - self.assertEqual(combo.itemText(1), 'ddd') + self.assertEqual(combo.itemText(0), "") + self.assertEqual(combo.itemText(1), "ddd") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutelevationprofile.py b/tests/src/python/test_qgslayoutelevationprofile.py index 0465eeafef41..8a709dcaa03a 100644 --- a/tests/src/python/test_qgslayoutelevationprofile.py +++ b/tests/src/python/test_qgslayoutelevationprofile.py @@ -5,22 +5,16 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2023 by Nyall Dawson' -__date__ = '13/01/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "(C) 2023 by Nyall Dawson" +__date__ = "13/01/2023" +__copyright__ = "Copyright 2023, The QGIS Project" import os import tempfile -from qgis.PyQt.QtCore import ( - Qt, - QRectF -) -from qgis.PyQt.QtGui import ( - QColor, - QImage, - QPainter -) +from qgis.PyQt.QtCore import Qt, QRectF +from qgis.PyQt.QtGui import QColor, QImage, QPainter from qgis.PyQt.QtTest import QSignalSpy from qgis.core import ( @@ -43,7 +37,7 @@ QgsVectorLayer, QgsSimpleFillSymbolLayer, QgsLayoutItemShape, - QgsMarkerSymbol + QgsMarkerSymbol, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -63,7 +57,7 @@ def control_path_prefix(cls): @classmethod def setUpClass(cls): - super(TestQgsLayoutItemElevationProfile, cls).setUpClass() + super().setUpClass() cls.item_class = QgsLayoutItemElevationProfile def test_opacity(self): @@ -79,7 +73,8 @@ def test_opacity(self): curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) profile_item.setProfileCurve(curve) profile_item.setCrs(QgsCoordinateReferenceSystem()) @@ -89,9 +84,12 @@ def test_opacity(self): profile_item.plot().xAxis().setGridIntervalMajor(10) profile_item.plot().xAxis().setGridIntervalMinor(5) - profile_item.plot().xAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffaaff', 'width': 2})) + profile_item.plot().xAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffaaff", "width": 2}) + ) profile_item.plot().xAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) format = QgsTextFormat() format.setFont(QgsFontUtils.getStandardTestFont("Bold")) @@ -103,28 +101,28 @@ def test_opacity(self): profile_item.plot().yAxis().setGridIntervalMajor(10) profile_item.plot().yAxis().setGridIntervalMinor(5) - profile_item.plot().yAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + profile_item.plot().yAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) profile_item.plot().yAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#aaffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#aaffaa", "width": 2}) + ) profile_item.plot().yAxis().setTextFormat(format) profile_item.plot().yAxis().setLabelInterval(10) profile_item.plot().setChartBorderSymbol( - QgsFillSymbol.createSimple({'style': 'no', 'color': '#aaffaa', 'width_border': 2})) + QgsFillSymbol.createSimple( + {"style": "no", "color": "#aaffaa", "width_border": 2} + ) + ) profile_item.setItemOpacity(0.3) - self.assertFalse( - profile_item.requiresRasterization() - ) - self.assertTrue( - profile_item.containsAdvancedEffects() - ) + self.assertFalse(profile_item.requiresRasterization()) + self.assertTrue(profile_item.containsAdvancedEffects()) - self.assertTrue( - self.render_layout_check('opacity', layout) - ) + self.assertTrue(self.render_layout_check("opacity", layout)) def test_opacity_rendering_designer_preview(self): """ @@ -141,7 +139,8 @@ def test_opacity_rendering_designer_preview(self): curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) profile_item.setProfileCurve(curve) profile_item.setCrs(QgsCoordinateReferenceSystem()) @@ -151,9 +150,12 @@ def test_opacity_rendering_designer_preview(self): profile_item.plot().xAxis().setGridIntervalMajor(10) profile_item.plot().xAxis().setGridIntervalMinor(5) - profile_item.plot().xAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffaaff', 'width': 2})) + profile_item.plot().xAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffaaff", "width": 2}) + ) profile_item.plot().xAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) format = QgsTextFormat() format.setFont(QgsFontUtils.getStandardTestFont("Bold")) @@ -165,23 +167,31 @@ def test_opacity_rendering_designer_preview(self): profile_item.plot().yAxis().setGridIntervalMajor(10) profile_item.plot().yAxis().setGridIntervalMinor(5) - profile_item.plot().yAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + profile_item.plot().yAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) profile_item.plot().yAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#aaffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#aaffaa", "width": 2}) + ) profile_item.plot().yAxis().setTextFormat(format) profile_item.plot().yAxis().setLabelInterval(10) profile_item.plot().setChartBorderSymbol( - QgsFillSymbol.createSimple({'style': 'no', 'color': '#aaffaa', 'width_border': 2})) + QgsFillSymbol.createSimple( + {"style": "no", "color": "#aaffaa", "width_border": 2} + ) + ) profile_item.setItemOpacity(0.3) page_item = l.pageCollection().page(0) - paper_rect = QRectF(page_item.pos().x(), - page_item.pos().y(), - page_item.rect().width(), - page_item.rect().height()) + paper_rect = QRectF( + page_item.pos().x(), + page_item.pos().y(), + page_item.rect().width(), + page_item.rect().height(), + ) im = QImage(1122, 794, QImage.Format.Format_ARGB32) im.fill(Qt.GlobalColor.transparent) @@ -193,7 +203,11 @@ def test_opacity_rendering_designer_preview(self): painter = QPainter(im) painter.setRenderHint(QPainter.RenderHint.Antialiasing, True) - l.render(painter, QRectF(0, 0, painter.device().width(), painter.device().height()), paper_rect) + l.render( + painter, + QRectF(0, 0, painter.device().width(), painter.device().height()), + paper_rect, + ) painter.end() # we have to wait for the preview image to refresh, then redraw @@ -204,12 +218,14 @@ def test_opacity_rendering_designer_preview(self): im.fill(Qt.GlobalColor.transparent) painter = QPainter(im) painter.setRenderHint(QPainter.RenderHint.Antialiasing, True) - l.render(painter, QRectF(0, 0, painter.device().width(), painter.device().height()), paper_rect) + l.render( + painter, + QRectF(0, 0, painter.device().width(), painter.device().height()), + paper_rect, + ) painter.end() - self.assertTrue(self.image_check('opacity', - 'opacity', - im, allowed_mismatch=0)) + self.assertTrue(self.image_check("opacity", "opacity", im, allowed_mismatch=0)) def test_blend_mode(self): """ @@ -235,7 +251,8 @@ def test_blend_mode(self): curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) profile_item.setProfileCurve(curve) profile_item.setCrs(QgsCoordinateReferenceSystem()) @@ -245,9 +262,12 @@ def test_blend_mode(self): profile_item.plot().xAxis().setGridIntervalMajor(10) profile_item.plot().xAxis().setGridIntervalMinor(5) - profile_item.plot().xAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffaaff', 'width': 2})) + profile_item.plot().xAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffaaff", "width": 2}) + ) profile_item.plot().xAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) format = QgsTextFormat() format.setFont(QgsFontUtils.getStandardTestFont("Bold")) @@ -259,15 +279,21 @@ def test_blend_mode(self): profile_item.plot().yAxis().setGridIntervalMajor(10) profile_item.plot().yAxis().setGridIntervalMinor(5) - profile_item.plot().yAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + profile_item.plot().yAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) profile_item.plot().yAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#aaffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#aaffaa", "width": 2}) + ) profile_item.plot().yAxis().setTextFormat(format) profile_item.plot().yAxis().setLabelInterval(10) profile_item.plot().setChartBorderSymbol( - QgsFillSymbol.createSimple({'style': 'no', 'color': '#aaffaa', 'width_border': 2})) + QgsFillSymbol.createSimple( + {"style": "no", "color": "#aaffaa", "width_border": 2} + ) + ) profile_item.setBlendMode(QPainter.CompositionMode.CompositionMode_Darken) @@ -300,7 +326,8 @@ def test_blend_mode_designer_preview(self): curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) profile_item.setProfileCurve(curve) profile_item.setCrs(QgsCoordinateReferenceSystem()) @@ -310,9 +337,12 @@ def test_blend_mode_designer_preview(self): profile_item.plot().xAxis().setGridIntervalMajor(10) profile_item.plot().xAxis().setGridIntervalMinor(5) - profile_item.plot().xAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffaaff', 'width': 2})) + profile_item.plot().xAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffaaff", "width": 2}) + ) profile_item.plot().xAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) format = QgsTextFormat() format.setFont(QgsFontUtils.getStandardTestFont("Bold")) @@ -324,15 +354,21 @@ def test_blend_mode_designer_preview(self): profile_item.plot().yAxis().setGridIntervalMajor(10) profile_item.plot().yAxis().setGridIntervalMinor(5) - profile_item.plot().yAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + profile_item.plot().yAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) profile_item.plot().yAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#aaffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#aaffaa", "width": 2}) + ) profile_item.plot().yAxis().setTextFormat(format) profile_item.plot().yAxis().setLabelInterval(10) profile_item.plot().setChartBorderSymbol( - QgsFillSymbol.createSimple({'style': 'no', 'color': '#aaffaa', 'width_border': 2})) + QgsFillSymbol.createSimple( + {"style": "no", "color": "#aaffaa", "width_border": 2} + ) + ) profile_item.setBlendMode(QPainter.CompositionMode.CompositionMode_Darken) @@ -368,13 +404,15 @@ def test_blend_mode_designer_preview(self): im.fill(Qt.GlobalColor.transparent) painter = QPainter(im) painter.setRenderHint(QPainter.RenderHint.Antialiasing, True) - layout.render(painter, QRectF(0, 0, painter.device().width(), painter.device().height()), paper_rect) + layout.render( + painter, + QRectF(0, 0, painter.device().width(), painter.device().height()), + paper_rect, + ) painter.end() self.assertTrue( - self.image_check( - "blendmode", "blendmode", im, allowed_mismatch=0 - ) + self.image_check("blendmode", "blendmode", im, allowed_mismatch=0) ) def test_layers(self): @@ -385,15 +423,21 @@ def test_layers(self): self.assertFalse(profile.layers()) - layer1 = QgsVectorLayer(os.path.join(unitTestDataPath(), 'france_parts.shp'), 'france', "ogr") + layer1 = QgsVectorLayer( + os.path.join(unitTestDataPath(), "france_parts.shp"), "france", "ogr" + ) self.assertTrue(layer1.isValid()) project.addMapLayers([layer1]) - layer2 = QgsRasterLayer(os.path.join(unitTestDataPath(), 'landsat.tif'), 'landsat', "gdal") + layer2 = QgsRasterLayer( + os.path.join(unitTestDataPath(), "landsat.tif"), "landsat", "gdal" + ) self.assertTrue(layer2.isValid()) project.addMapLayers([layer2]) - layer3 = QgsVectorLayer(os.path.join(unitTestDataPath(), 'lines.shp'), 'lines', "ogr") + layer3 = QgsVectorLayer( + os.path.join(unitTestDataPath(), "lines.shp"), "lines", "ogr" + ) self.assertTrue(layer3.isValid()) project.addMapLayers([layer3]) @@ -404,15 +448,21 @@ def test_layers(self): # test that layers are written/restored with tempfile.TemporaryDirectory() as temp_dir: - self.assertTrue(project.write(os.path.join(temp_dir, 'p.qgs'))) + self.assertTrue(project.write(os.path.join(temp_dir, "p.qgs"))) p2 = QgsProject() - self.assertTrue(p2.read(os.path.join(temp_dir, 'p.qgs'))) + self.assertTrue(p2.read(os.path.join(temp_dir, "p.qgs"))) layout2 = p2.layoutManager().printLayouts()[0] - profile2 = [i for i in layout2.items() if isinstance(i, QgsLayoutItemElevationProfile)][0] - - self.assertEqual([m.id() for m in profile2.layers()], [layer2.id(), layer3.id()]) + profile2 = [ + i + for i in layout2.items() + if isinstance(i, QgsLayoutItemElevationProfile) + ][0] + + self.assertEqual( + [m.id() for m in profile2.layers()], [layer2.id(), layer3.id()] + ) def test_settings(self): project = QgsProject() @@ -423,24 +473,28 @@ def test_settings(self): # test that default settings are written/restored with tempfile.TemporaryDirectory() as temp_dir: - self.assertTrue(project.write(os.path.join(temp_dir, 'p.qgs'))) + self.assertTrue(project.write(os.path.join(temp_dir, "p.qgs"))) p2 = QgsProject() - self.assertTrue(p2.read(os.path.join(temp_dir, 'p.qgs'))) + self.assertTrue(p2.read(os.path.join(temp_dir, "p.qgs"))) layout2 = p2.layoutManager().printLayouts()[0] - profile2 = [i for i in layout2.items() if isinstance(i, QgsLayoutItemElevationProfile)][0] + profile2 = [ + i + for i in layout2.items() + if isinstance(i, QgsLayoutItemElevationProfile) + ][0] self.assertFalse(profile2.crs().isValid()) self.assertEqual(profile2.tolerance(), 0) self.assertIsNone(profile2.profileCurve()) - curve = QgsGeometry.fromWkt('LineString(0 0, 10 10)') + curve = QgsGeometry.fromWkt("LineString(0 0, 10 10)") profile.setProfileCurve(curve.constGet().clone()) - self.assertEqual(profile.profileCurve().asWkt(), 'LineString (0 0, 10 10)') + self.assertEqual(profile.profileCurve().asWkt(), "LineString (0 0, 10 10)") - profile.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) - self.assertEqual(profile.crs(), QgsCoordinateReferenceSystem('EPSG:3857')) + profile.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) + self.assertEqual(profile.crs(), QgsCoordinateReferenceSystem("EPSG:3857")) profile.setTolerance(101) self.assertEqual(profile.tolerance(), 101) @@ -448,17 +502,21 @@ def test_settings(self): # test that settings are written/restored with tempfile.TemporaryDirectory() as temp_dir: - self.assertTrue(project.write(os.path.join(temp_dir, 'p.qgs'))) + self.assertTrue(project.write(os.path.join(temp_dir, "p.qgs"))) p2 = QgsProject() - self.assertTrue(p2.read(os.path.join(temp_dir, 'p.qgs'))) + self.assertTrue(p2.read(os.path.join(temp_dir, "p.qgs"))) layout2 = p2.layoutManager().printLayouts()[0] - profile2 = [i for i in layout2.items() if isinstance(i, QgsLayoutItemElevationProfile)][0] + profile2 = [ + i + for i in layout2.items() + if isinstance(i, QgsLayoutItemElevationProfile) + ][0] - self.assertEqual(profile2.crs(), QgsCoordinateReferenceSystem('EPSG:3857')) + self.assertEqual(profile2.crs(), QgsCoordinateReferenceSystem("EPSG:3857")) self.assertEqual(profile2.tolerance(), 101) - self.assertEqual(profile2.profileCurve().asWkt(), 'LineString (0 0, 10 10)') + self.assertEqual(profile2.profileCurve().asWkt(), "LineString (0 0, 10 10)") self.assertEqual(profile2.distanceUnit(), Qgis.DistanceUnit.Kilometers) def test_request(self): @@ -471,18 +529,18 @@ def test_request(self): layout.addLayoutItem(profile) project.layoutManager().addLayout(layout) - curve = QgsGeometry.fromWkt('LineString(0 0, 10 10)') + curve = QgsGeometry.fromWkt("LineString(0 0, 10 10)") profile.setProfileCurve(curve.constGet().clone()) - profile.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + profile.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) profile.setTolerance(101) - QgsExpressionContextUtils.setLayoutItemVariable(profile, 'my_var', 202) + QgsExpressionContextUtils.setLayoutItemVariable(profile, "my_var", 202) req = profile.profileRequest() self.assertEqual(req.tolerance(), 101) - self.assertEqual(req.profileCurve().asWkt(), 'LineString (0 0, 10 10)') - self.assertEqual(req.crs(), QgsCoordinateReferenceSystem('EPSG:3857')) - self.assertEqual(req.expressionContext().variable('my_var'), '202') + self.assertEqual(req.profileCurve().asWkt(), "LineString (0 0, 10 10)") + self.assertEqual(req.crs(), QgsCoordinateReferenceSystem("EPSG:3857")) + self.assertEqual(req.expressionContext().variable("my_var"), "202") project.elevationProperties().setTerrainProvider(QgsFlatTerrainProvider()) @@ -493,16 +551,17 @@ def test_draw(self): """ Test rendering the layout profile item """ - vl = QgsVectorLayer('PolygonZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("PolygonZ?crs=EPSG:27700", "lines", "memory") vl.setCrs(QgsCoordinateReferenceSystem()) self.assertTrue(vl.isValid()) for line in [ - 'PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))', - 'PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))', - 'PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))', - 'PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))', - 'PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))']: + "PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))", + "PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))", + "PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))", + "PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))", + "PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -510,7 +569,9 @@ def test_draw(self): vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) vl.elevationProperties().setExtrusionEnabled(True) vl.elevationProperties().setExtrusionHeight(7) - fill_symbol = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_style': 'no'}) + fill_symbol = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_style": "no"} + ) vl.elevationProperties().setRespectLayerSymbology(False) vl.elevationProperties().setProfileFillSymbol(fill_symbol) @@ -525,7 +586,8 @@ def test_draw(self): curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) profile_item.setProfileCurve(curve) profile_item.setCrs(QgsCoordinateReferenceSystem()) @@ -535,9 +597,12 @@ def test_draw(self): profile_item.plot().xAxis().setGridIntervalMajor(10) profile_item.plot().xAxis().setGridIntervalMinor(5) - profile_item.plot().xAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffaaff', 'width': 2})) + profile_item.plot().xAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffaaff", "width": 2}) + ) profile_item.plot().xAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) format = QgsTextFormat() format.setFont(QgsFontUtils.getStandardTestFont("Bold")) @@ -549,35 +614,40 @@ def test_draw(self): profile_item.plot().yAxis().setGridIntervalMajor(10) profile_item.plot().yAxis().setGridIntervalMinor(5) - profile_item.plot().yAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + profile_item.plot().yAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) profile_item.plot().yAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#aaffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#aaffaa", "width": 2}) + ) profile_item.plot().yAxis().setTextFormat(format) profile_item.plot().yAxis().setLabelInterval(10) profile_item.plot().setChartBorderSymbol( - QgsFillSymbol.createSimple({'style': 'no', 'color': '#aaffaa', 'width_border': 2})) + QgsFillSymbol.createSimple( + {"style": "no", "color": "#aaffaa", "width_border": 2} + ) + ) profile_item.setLayers([vl]) - self.assertTrue(self.render_layout_check( - 'vector_layer', layout - )) + self.assertTrue(self.render_layout_check("vector_layer", layout)) def test_draw_distance_units(self): """ Test rendering the layout profile item with distance unit change """ - vl = QgsVectorLayer('PolygonZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("PolygonZ?crs=EPSG:27700", "lines", "memory") self.assertTrue(vl.isValid()) for line in [ - 'PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))', - 'PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))', - 'PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))', - 'PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))', - 'PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))']: + "PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))", + "PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))", + "PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))", + "PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))", + "PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -585,7 +655,9 @@ def test_draw_distance_units(self): vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) vl.elevationProperties().setExtrusionEnabled(True) vl.elevationProperties().setExtrusionHeight(7) - fill_symbol = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_style': 'no'}) + fill_symbol = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_style": "no"} + ) vl.elevationProperties().setRespectLayerSymbology(False) vl.elevationProperties().setProfileFillSymbol(fill_symbol) @@ -600,7 +672,8 @@ def test_draw_distance_units(self): curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) profile_item.setProfileCurve(curve) profile_item.setCrs(vl.crs()) @@ -609,12 +682,17 @@ def test_draw_distance_units(self): profile_item.plot().setYMaximum(14) profile_item.setDistanceUnit(Qgis.DistanceUnit.Kilometers) - profile_item.plot().xAxis().setLabelSuffixPlacement(Qgis.PlotAxisSuffixPlacement.LastLabel) + profile_item.plot().xAxis().setLabelSuffixPlacement( + Qgis.PlotAxisSuffixPlacement.LastLabel + ) profile_item.plot().xAxis().setGridIntervalMajor(0.010) profile_item.plot().xAxis().setGridIntervalMinor(0.005) - profile_item.plot().xAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffaaff', 'width': 2})) + profile_item.plot().xAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffaaff", "width": 2}) + ) profile_item.plot().xAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) format = QgsTextFormat() format.setFont(QgsFontUtils.getStandardTestFont("Bold")) @@ -626,44 +704,49 @@ def test_draw_distance_units(self): profile_item.plot().yAxis().setGridIntervalMajor(10) profile_item.plot().yAxis().setGridIntervalMinor(5) - profile_item.plot().yAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + profile_item.plot().yAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) profile_item.plot().yAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#aaffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#aaffaa", "width": 2}) + ) profile_item.plot().yAxis().setTextFormat(format) profile_item.plot().yAxis().setLabelInterval(10) profile_item.plot().setChartBorderSymbol( - QgsFillSymbol.createSimple({'style': 'no', 'color': '#aaffaa', 'width_border': 2})) + QgsFillSymbol.createSimple( + {"style": "no", "color": "#aaffaa", "width_border": 2} + ) + ) profile_item.setLayers([vl]) - self.assertTrue(self.render_layout_check( - 'distance_units', layout - )) + self.assertTrue(self.render_layout_check("distance_units", layout)) def test_draw_map_units(self): """ Test rendering the layout profile item using symbols with map unit sizes """ - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") vl.setCrs(QgsCoordinateReferenceSystem()) self.assertTrue(vl.isValid()) for line in [ - 'LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)', - 'LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)', - 'LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)', - 'LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)', - 'LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)']: + "LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)", + "LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)", + "LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)", + "LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)", + "LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) marker_symbol = QgsMarkerSymbol.createSimple( - {'name': 'square', 'size': 4, 'color': '#00ff00', - 'outline_style': 'no'}) + {"name": "square", "size": 4, "color": "#00ff00", "outline_style": "no"} + ) marker_symbol.setSizeUnit(Qgis.RenderUnit.MapUnits) vl.elevationProperties().setRespectLayerSymbology(False) vl.elevationProperties().setProfileMarkerSymbol(marker_symbol) @@ -679,7 +762,8 @@ def test_draw_map_units(self): curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) profile_item.setProfileCurve(curve) profile_item.setCrs(QgsCoordinateReferenceSystem()) @@ -689,9 +773,12 @@ def test_draw_map_units(self): profile_item.plot().xAxis().setGridIntervalMajor(10) profile_item.plot().xAxis().setGridIntervalMinor(5) - profile_item.plot().xAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffaaff', 'width': 2})) + profile_item.plot().xAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffaaff", "width": 2}) + ) profile_item.plot().xAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) format = QgsTextFormat() format.setFont(QgsFontUtils.getStandardTestFont("Bold")) @@ -703,36 +790,41 @@ def test_draw_map_units(self): profile_item.plot().yAxis().setGridIntervalMajor(10) profile_item.plot().yAxis().setGridIntervalMinor(5) - profile_item.plot().yAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + profile_item.plot().yAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) profile_item.plot().yAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#aaffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#aaffaa", "width": 2}) + ) profile_item.plot().yAxis().setTextFormat(format) profile_item.plot().yAxis().setLabelInterval(10) profile_item.plot().setChartBorderSymbol( - QgsFillSymbol.createSimple({'style': 'no', 'color': '#aaffaa', 'width_border': 2})) + QgsFillSymbol.createSimple( + {"style": "no", "color": "#aaffaa", "width_border": 2} + ) + ) profile_item.setLayers([vl]) - self.assertTrue(self.render_layout_check( - 'vector_layer_map_units', layout - )) + self.assertTrue(self.render_layout_check("vector_layer_map_units", layout)) def test_draw_zero_label_interval(self): """ Test rendering the layout profile item with 0 label intervals """ - vl = QgsVectorLayer('PolygonZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("PolygonZ?crs=EPSG:27700", "lines", "memory") vl.setCrs(QgsCoordinateReferenceSystem()) self.assertTrue(vl.isValid()) for line in [ - 'PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))', - 'PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))', - 'PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))', - 'PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))', - 'PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))']: + "PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))", + "PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))", + "PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))", + "PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))", + "PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -740,7 +832,9 @@ def test_draw_zero_label_interval(self): vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) vl.elevationProperties().setExtrusionEnabled(True) vl.elevationProperties().setExtrusionHeight(7) - fill_symbol = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_style': 'no'}) + fill_symbol = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_style": "no"} + ) vl.elevationProperties().setRespectLayerSymbology(False) vl.elevationProperties().setProfileFillSymbol(fill_symbol) @@ -755,7 +849,8 @@ def test_draw_zero_label_interval(self): curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) profile_item.setProfileCurve(curve) profile_item.setCrs(QgsCoordinateReferenceSystem()) @@ -765,9 +860,12 @@ def test_draw_zero_label_interval(self): profile_item.plot().xAxis().setGridIntervalMajor(10) profile_item.plot().xAxis().setGridIntervalMinor(5) - profile_item.plot().xAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffaaff', 'width': 2})) + profile_item.plot().xAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffaaff", "width": 2}) + ) profile_item.plot().xAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) format = QgsTextFormat() format.setFont(QgsFontUtils.getStandardTestFont("Bold")) @@ -779,42 +877,47 @@ def test_draw_zero_label_interval(self): profile_item.plot().yAxis().setGridIntervalMajor(10) profile_item.plot().yAxis().setGridIntervalMinor(5) - profile_item.plot().yAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + profile_item.plot().yAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) profile_item.plot().yAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#aaffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#aaffaa", "width": 2}) + ) profile_item.plot().yAxis().setTextFormat(format) profile_item.plot().yAxis().setLabelInterval(0) profile_item.plot().setChartBorderSymbol( - QgsFillSymbol.createSimple({'style': 'no', 'color': '#aaffaa', 'width_border': 2})) + QgsFillSymbol.createSimple( + {"style": "no", "color": "#aaffaa", "width_border": 2} + ) + ) profile_item.setLayers([vl]) - self.assertTrue(self.render_layout_check( - 'zero_label_interval', layout - )) + self.assertTrue(self.render_layout_check("zero_label_interval", layout)) def test_draw_map_units_tolerance(self): """ Test rendering the layout profile item using symbols with map unit sizes """ - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") vl.setCrs(QgsCoordinateReferenceSystem()) self.assertTrue(vl.isValid()) for line in [ - 'LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)', - 'LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)', - 'LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)', - 'LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)', - 'LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)']: + "LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)", + "LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)", + "LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)", + "LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)", + "LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) - line_symbol = QgsLineSymbol.createSimple({'color': '#ff00ff', 'width': '0.8'}) + line_symbol = QgsLineSymbol.createSimple({"color": "#ff00ff", "width": "0.8"}) line_symbol.setWidthUnit(Qgis.RenderUnit.MapUnits) vl.elevationProperties().setProfileLineSymbol(line_symbol) vl.elevationProperties().setRespectLayerSymbology(False) @@ -830,7 +933,8 @@ def test_draw_map_units_tolerance(self): curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) profile_item.setProfileCurve(curve) profile_item.setCrs(QgsCoordinateReferenceSystem()) @@ -840,9 +944,12 @@ def test_draw_map_units_tolerance(self): profile_item.plot().xAxis().setGridIntervalMajor(10) profile_item.plot().xAxis().setGridIntervalMinor(5) - profile_item.plot().xAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffaaff', 'width': 2})) + profile_item.plot().xAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffaaff", "width": 2}) + ) profile_item.plot().xAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) format = QgsTextFormat() format.setFont(QgsFontUtils.getStandardTestFont("Bold")) @@ -854,23 +961,29 @@ def test_draw_map_units_tolerance(self): profile_item.plot().yAxis().setGridIntervalMajor(10) profile_item.plot().yAxis().setGridIntervalMinor(5) - profile_item.plot().yAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + profile_item.plot().yAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) profile_item.plot().yAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#aaffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#aaffaa", "width": 2}) + ) profile_item.plot().yAxis().setTextFormat(format) profile_item.plot().yAxis().setLabelInterval(10) profile_item.plot().setChartBorderSymbol( - QgsFillSymbol.createSimple({'style': 'no', 'color': '#aaffaa', 'width_border': 2})) + QgsFillSymbol.createSimple( + {"style": "no", "color": "#aaffaa", "width_border": 2} + ) + ) profile_item.setTolerance(1) profile_item.setLayers([vl]) - self.assertTrue(self.render_layout_check( - 'vector_layer_map_units_tolerance', layout - )) + self.assertTrue( + self.render_layout_check("vector_layer_map_units_tolerance", layout) + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutexporter.py b/tests/src/python/test_qgslayoutexporter.py index a316bba7db12..16d3aa7851be 100644 --- a/tests/src/python/test_qgslayoutexporter.py +++ b/tests/src/python/test_qgslayoutexporter.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '11/12/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "11/12/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os import subprocess @@ -76,7 +77,7 @@ # * Poppler w/o Cairo does not always correctly render vectors in PDF to image # * muPDF renders correctly, but slightly shifts colors for util in [ - 'pdftocairo', + "pdftocairo", # 'mudraw', ]: PDFUTIL = getExecutablePath(util) @@ -85,39 +86,63 @@ # noinspection PyUnboundLocalVariable if not PDFUTIL: - raise Exception('PDF-to-image utility not found on PATH: ' - 'install Poppler (with Cairo)') + raise Exception( + "PDF-to-image utility not found on PATH: " "install Poppler (with Cairo)" + ) def pdfToPng(pdf_file_path, rendered_file_path, page, dpi=96): - if PDFUTIL.strip().endswith('pdftocairo'): + if PDFUTIL.strip().endswith("pdftocairo"): filebase = os.path.join( os.path.dirname(rendered_file_path), - os.path.splitext(os.path.basename(rendered_file_path))[0] + os.path.splitext(os.path.basename(rendered_file_path))[0], ) call = [ - PDFUTIL, '-png', '-singlefile', '-r', str(dpi), - '-x', '0', '-y', '0', '-f', str(page), '-l', str(page), - pdf_file_path, filebase + PDFUTIL, + "-png", + "-singlefile", + "-r", + str(dpi), + "-x", + "0", + "-y", + "0", + "-f", + str(page), + "-l", + str(page), + pdf_file_path, + filebase, ] - elif PDFUTIL.strip().endswith('mudraw'): + elif PDFUTIL.strip().endswith("mudraw"): call = [ - PDFUTIL, '-c', 'rgba', - '-r', str(dpi), '-f', str(page), '-l', str(page), + PDFUTIL, + "-c", + "rgba", + "-r", + str(dpi), + "-f", + str(page), + "-l", + str(page), # '-b', '8', - '-o', rendered_file_path, pdf_file_path + "-o", + rendered_file_path, + pdf_file_path, ] else: - return False, '' + return False, "" print(f"exportToPdf call: {' '.join(call)}") try: subprocess.check_call(call) except subprocess.CalledProcessError as e: - assert False, ("exportToPdf failed!\n" - "cmd: {}\n" - "returncode: {}\n" - "message: {}".format(e.cmd, e.returncode, e.message)) + assert False, ( + "exportToPdf failed!\n" + "cmd: {}\n" + "returncode: {}\n" + "message: {}".format(e.cmd, e.returncode, e.message) + ) def svgToPng(svg_file_path, rendered_file_path, width): @@ -133,7 +158,7 @@ def svgToPng(svg_file_path, rendered_file_path, width): svgr.render(p) p.end() - res = image.save(rendered_file_path, 'png') + res = image.save(rendered_file_path, "png") if not res: os.unlink(rendered_file_path) @@ -184,9 +209,13 @@ def testRenderPage(self): painter.end() self.assertTrue( - self.image_check('layoutexporter_renderpage', 'layoutexporter_renderpage', output_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "layoutexporter_renderpage", + "layoutexporter_renderpage", + output_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testRenderPageToImage(self): @@ -217,12 +246,18 @@ def testRenderPageToImage(self): image = exporter.renderPageToImage(0, size) self.assertFalse(image.isNull()) - rendered_file_path = os.path.join(self.basetestpath, 'test_rendertoimagepage.png') + rendered_file_path = os.path.join( + self.basetestpath, "test_rendertoimagepage.png" + ) image.save(rendered_file_path, "PNG") self.assertTrue( - self.image_check('layoutexporter_rendertoimagepage', 'layoutexporter_rendertoimagepage', image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "layoutexporter_rendertoimagepage", + "layoutexporter_rendertoimagepage", + image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testRenderRegion(self): @@ -230,7 +265,11 @@ def testRenderRegion(self): l.initializeDefaults() # add a guide, to ensure it is not included in export - g1 = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(15, QgsUnitTypes.LayoutUnit.LayoutMillimeters), l.pageCollection().page(0)) + g1 = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(15, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + l.pageCollection().page(0), + ) l.guides().addGuide(g1) # add some items @@ -258,9 +297,13 @@ def testRenderRegion(self): painter.end() self.assertTrue( - self.image_check('layoutexporter_renderregion', 'layoutexporter_renderregion', output_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "layoutexporter_renderregion", + "layoutexporter_renderregion", + output_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testRenderRegionToImage(self): @@ -285,9 +328,13 @@ def testRenderRegionToImage(self): self.assertFalse(image.isNull()) self.assertTrue( - self.image_check('layoutexporter_rendertoimageregionsize', 'layoutexporter_rendertoimageregionsize', image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "layoutexporter_rendertoimageregionsize", + "layoutexporter_rendertoimageregionsize", + image, + color_tolerance=2, + allowed_mismatch=20, + ) ) # using layout dpi @@ -296,9 +343,13 @@ def testRenderRegionToImage(self): self.assertFalse(image.isNull()) self.assertTrue( - self.image_check('layoutexporter_rendertoimageregiondpi', 'layoutexporter_rendertoimageregiondpi', image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "layoutexporter_rendertoimageregiondpi", + "layoutexporter_rendertoimageregiondpi", + image, + color_tolerance=2, + allowed_mismatch=20, + ) ) # overriding dpi @@ -306,26 +357,32 @@ def testRenderRegionToImage(self): self.assertFalse(image.isNull()) self.assertTrue( - self.image_check('layoutexporter_rendertoimageregionoverridedpi', 'layoutexporter_rendertoimageregionoverridedpi', image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "layoutexporter_rendertoimageregionoverridedpi", + "layoutexporter_rendertoimageregionoverridedpi", + image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testExportToImage(self): md = QgsProject.instance().metadata() - md.setTitle('proj title') - md.setAuthor('proj author') - md.setCreationDateTime(QDateTime(QDate(2011, 5, 3), QTime(9, 4, 5), QTimeZone(36000))) - md.setIdentifier('proj identifier') - md.setAbstract('proj abstract') - md.setKeywords({'kw': ['kw1', 'kw2'], 'KWx': ['kw3', 'kw4']}) + md.setTitle("proj title") + md.setAuthor("proj author") + md.setCreationDateTime( + QDateTime(QDate(2011, 5, 3), QTime(9, 4, 5), QTimeZone(36000)) + ) + md.setIdentifier("proj identifier") + md.setAbstract("proj abstract") + md.setKeywords({"kw": ["kw1", "kw2"], "KWx": ["kw3", "kw4"]}) QgsProject.instance().setMetadata(md) l = QgsLayout(QgsProject.instance()) l.initializeDefaults() # add a second page page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") l.pageCollection().addPage(page2) # add some items @@ -355,110 +412,167 @@ def testExportToImage(self): settings = QgsLayoutExporter.ImageExportSettings() settings.dpi = 80 - rendered_file_path = os.path.join(self.basetestpath, 'test_exporttoimagedpi.png') - self.assertEqual(exporter.exportToImage(rendered_file_path, settings), QgsLayoutExporter.ExportResult.Success) + rendered_file_path = os.path.join( + self.basetestpath, "test_exporttoimagedpi.png" + ) + self.assertEqual( + exporter.exportToImage(rendered_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) image = QImage(rendered_file_path) self.assertTrue( - self.image_check('layoutexporter_exporttoimagedpi_page1', 'layoutexporter_exporttoimagedpi_page1', image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "layoutexporter_exporttoimagedpi_page1", + "layoutexporter_exporttoimagedpi_page1", + image, + color_tolerance=2, + allowed_mismatch=20, + ) ) - page2_path = os.path.join(self.basetestpath, 'test_exporttoimagedpi_2.png') + page2_path = os.path.join(self.basetestpath, "test_exporttoimagedpi_2.png") image = QImage(page2_path) self.assertTrue( - self.image_check('layoutexporter_exporttoimagedpi_page2', 'layoutexporter_exporttoimagedpi_page2', image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "layoutexporter_exporttoimagedpi_page2", + "layoutexporter_exporttoimagedpi_page2", + image, + color_tolerance=2, + allowed_mismatch=20, + ) ) for f in (rendered_file_path, page2_path): d = gdal.Open(f) metadata = d.GetMetadata() - self.assertEqual(metadata['Author'], 'proj author') - self.assertEqual(metadata['Created'], '2011-05-03T09:04:05+10:00') - self.assertEqual(metadata['Keywords'], 'KWx: kw3,kw4;kw: kw1,kw2') - self.assertEqual(metadata['Subject'], 'proj abstract') - self.assertEqual(metadata['Title'], 'proj title') + self.assertEqual(metadata["Author"], "proj author") + self.assertEqual(metadata["Created"], "2011-05-03T09:04:05+10:00") + self.assertEqual(metadata["Keywords"], "KWx: kw3,kw4;kw: kw1,kw2") + self.assertEqual(metadata["Subject"], "proj abstract") + self.assertEqual(metadata["Title"], "proj title") # crop to contents settings.cropToContents = True settings.cropMargins = QgsMargins(10, 20, 30, 40) - rendered_file_path = os.path.join(self.basetestpath, 'test_exporttoimagecropped.png') - self.assertEqual(exporter.exportToImage(rendered_file_path, settings), QgsLayoutExporter.ExportResult.Success) + rendered_file_path = os.path.join( + self.basetestpath, "test_exporttoimagecropped.png" + ) + self.assertEqual( + exporter.exportToImage(rendered_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) image = QImage(rendered_file_path) self.assertTrue( - self.image_check('layoutexporter_exporttoimagecropped_page1', 'layoutexporter_exporttoimagecropped_page1', image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "layoutexporter_exporttoimagecropped_page1", + "layoutexporter_exporttoimagecropped_page1", + image, + color_tolerance=2, + allowed_mismatch=20, + ) ) - page2_path = os.path.join(self.basetestpath, 'test_exporttoimagecropped_2.png') + page2_path = os.path.join(self.basetestpath, "test_exporttoimagecropped_2.png") image = QImage(page2_path) self.assertTrue( - self.image_check('layoutexporter_exporttoimagecropped_page2', 'layoutexporter_exporttoimagecropped_page2', image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "layoutexporter_exporttoimagecropped_page2", + "layoutexporter_exporttoimagecropped_page2", + image, + color_tolerance=2, + allowed_mismatch=20, + ) ) # specific pages settings.cropToContents = False settings.pages = [1] - rendered_file_path = os.path.join(self.basetestpath, 'test_exporttoimagepages.png') - self.assertEqual(exporter.exportToImage(rendered_file_path, settings), QgsLayoutExporter.ExportResult.Success) + rendered_file_path = os.path.join( + self.basetestpath, "test_exporttoimagepages.png" + ) + self.assertEqual( + exporter.exportToImage(rendered_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) self.assertFalse(os.path.exists(rendered_file_path)) - page2_path = os.path.join(self.basetestpath, 'test_exporttoimagepages_2.png') + page2_path = os.path.join(self.basetestpath, "test_exporttoimagepages_2.png") image = QImage(page2_path) self.assertTrue( - self.image_check('layoutexporter_exporttoimagedpi_page2', 'layoutexporter_exporttoimagedpi_page2', image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "layoutexporter_exporttoimagedpi_page2", + "layoutexporter_exporttoimagedpi_page2", + image, + color_tolerance=2, + allowed_mismatch=20, + ) ) # image size settings.imageSize = QSize(600, 851) - rendered_file_path = os.path.join(self.basetestpath, 'test_exporttoimagesize.png') - self.assertEqual(exporter.exportToImage(rendered_file_path, settings), QgsLayoutExporter.ExportResult.Success) + rendered_file_path = os.path.join( + self.basetestpath, "test_exporttoimagesize.png" + ) + self.assertEqual( + exporter.exportToImage(rendered_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) self.assertFalse(os.path.exists(rendered_file_path)) - page2_path = os.path.join(self.basetestpath, 'test_exporttoimagesize_2.png') + page2_path = os.path.join(self.basetestpath, "test_exporttoimagesize_2.png") image = QImage(page2_path) self.assertTrue( - self.image_check('layoutexporter_exporttoimagesize_page2', 'layoutexporter_exporttoimagesize_page2', image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "layoutexporter_exporttoimagesize_page2", + "layoutexporter_exporttoimagesize_page2", + image, + color_tolerance=2, + allowed_mismatch=20, + ) ) # image size with incorrect aspect ratio # this can happen as a result of data defined page sizes settings.imageSize = QSize(851, 600) - rendered_file_path = os.path.join(self.basetestpath, 'test_exporttoimagesizebadaspect.png') - self.assertEqual(exporter.exportToImage(rendered_file_path, settings), QgsLayoutExporter.ExportResult.Success) + rendered_file_path = os.path.join( + self.basetestpath, "test_exporttoimagesizebadaspect.png" + ) + self.assertEqual( + exporter.exportToImage(rendered_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) - page2_path = os.path.join(self.basetestpath, 'test_exporttoimagesizebadaspect_2.png') + page2_path = os.path.join( + self.basetestpath, "test_exporttoimagesizebadaspect_2.png" + ) image = QImage(page2_path) self.assertTrue( - self.image_check('layoutexporter_exporttoimagesize_badaspect', 'layoutexporter_exporttoimagedpi_page2', image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "layoutexporter_exporttoimagesize_badaspect", + "layoutexporter_exporttoimagedpi_page2", + image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testExportToPdf(self): md = QgsProject.instance().metadata() - projTitle = 'proj titlea /<é' - projAuthor = 'proj author /<é' + projTitle = "proj titlea /<é" + projAuthor = "proj author /<é" md.setTitle(projTitle) md.setAuthor(projAuthor) - md.setCreationDateTime(QDateTime(QDate(2011, 5, 3), QTime(9, 4, 5), QTimeZone(36000))) - md.setIdentifier('proj identifier') - md.setAbstract('proj abstract') - md.setKeywords({'kw': ['kw1', 'kw2'], 'KWx': ['kw3', 'kw4']}) + md.setCreationDateTime( + QDateTime(QDate(2011, 5, 3), QTime(9, 4, 5), QTimeZone(36000)) + ) + md.setIdentifier("proj identifier") + md.setAbstract("proj abstract") + md.setKeywords({"kw": ["kw1", "kw2"], "KWx": ["kw3", "kw4"]}) QgsProject.instance().setMetadata(md) l = QgsLayout(QgsProject.instance()) @@ -466,7 +580,7 @@ def testExportToPdf(self): # add a second page page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") l.pageCollection().addPage(page2) # add some items @@ -499,40 +613,51 @@ def testExportToPdf(self): settings.forceVectorOutput = False settings.exportMetadata = True - pdf_file_path = os.path.join(self.basetestpath, 'test_exporttopdfdpi.pdf') - self.assertEqual(exporter.exportToPdf(pdf_file_path, settings), QgsLayoutExporter.ExportResult.Success) + pdf_file_path = os.path.join(self.basetestpath, "test_exporttopdfdpi.pdf") + self.assertEqual( + exporter.exportToPdf(pdf_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) self.assertTrue(os.path.exists(pdf_file_path)) - rendered_page_1 = os.path.join(self.basetestpath, 'test_exporttopdfdpi.png') + rendered_page_1 = os.path.join(self.basetestpath, "test_exporttopdfdpi.png") dpi = 80 pdfToPng(pdf_file_path, rendered_page_1, dpi=dpi, page=1) - rendered_page_2 = os.path.join(self.basetestpath, 'test_exporttopdfdpi2.png') + rendered_page_2 = os.path.join(self.basetestpath, "test_exporttopdfdpi2.png") pdfToPng(pdf_file_path, rendered_page_2, dpi=dpi, page=2) image = QImage(rendered_page_1) self.assertTrue( - self.image_check('layoutexporter_exporttopdfdpi_page1', 'layoutexporter_exporttopdfdpi_page1', image, - color_tolerance=2, - allowed_mismatch=20, - size_tolerance=1) + self.image_check( + "layoutexporter_exporttopdfdpi_page1", + "layoutexporter_exporttopdfdpi_page1", + image, + color_tolerance=2, + allowed_mismatch=20, + size_tolerance=1, + ) ) image = QImage(rendered_page_2) self.assertTrue( - self.image_check('layoutexporter_exporttopdfdpi_page2', 'layoutexporter_exporttopdfdpi_page2', image, - color_tolerance=2, - allowed_mismatch=20, - size_tolerance=1) + self.image_check( + "layoutexporter_exporttopdfdpi_page2", + "layoutexporter_exporttopdfdpi_page2", + image, + color_tolerance=2, + allowed_mismatch=20, + size_tolerance=1, + ) ) d = gdal.Open(pdf_file_path) metadata = d.GetMetadata() - self.assertEqual(metadata['AUTHOR'], projAuthor) - self.assertEqual(metadata['CREATION_DATE'], "D:20110503090405+10'0'") - self.assertEqual(metadata['KEYWORDS'], 'KWx: kw3,kw4;kw: kw1,kw2') - self.assertEqual(metadata['SUBJECT'], 'proj abstract') - self.assertEqual(metadata['TITLE'], projTitle) + self.assertEqual(metadata["AUTHOR"], projAuthor) + self.assertEqual(metadata["CREATION_DATE"], "D:20110503090405+10'0'") + self.assertEqual(metadata["KEYWORDS"], "KWx: kw3,kw4;kw: kw1,kw2") + self.assertEqual(metadata["SUBJECT"], "proj abstract") + self.assertEqual(metadata["TITLE"], projTitle) qgisId = f"QGIS {Qgis.version()}" - self.assertEqual(metadata['CREATOR'], qgisId) + self.assertEqual(metadata["CREATOR"], qgisId) # check XMP metadata xmpMetadata = d.GetMetadata("xml:XMP") @@ -540,40 +665,66 @@ def testExportToPdf(self): xmp = xmpMetadata[0] self.assertTrue(xmp) xmpDoc = etree.fromstring(xmp) - namespaces = dict([node for _, node in etree.iterparse(StringIO(xmp), events=['start-ns'])]) + namespaces = dict( + [node for _, node in etree.iterparse(StringIO(xmp), events=["start-ns"])] + ) - title = xmpDoc.findall("rdf:RDF/rdf:Description/dc:title/rdf:Alt/rdf:li", namespaces) + title = xmpDoc.findall( + "rdf:RDF/rdf:Description/dc:title/rdf:Alt/rdf:li", namespaces + ) self.assertEqual(len(title), 1) self.assertEqual(title[0].text, projTitle) - creator = xmpDoc.findall("rdf:RDF/rdf:Description/dc:creator/rdf:Seq/rdf:li", namespaces) + creator = xmpDoc.findall( + "rdf:RDF/rdf:Description/dc:creator/rdf:Seq/rdf:li", namespaces + ) self.assertEqual(len(creator), 1) self.assertEqual(creator[0].text, projAuthor) producer = xmpDoc.findall("rdf:RDF/rdf:Description[@pdf:Producer]", namespaces) self.assertEqual(len(producer), 1) - self.assertEqual(producer[0].attrib["{" + namespaces["pdf"] + "}" + "Producer"], qgisId) + self.assertEqual( + producer[0].attrib["{" + namespaces["pdf"] + "}" + "Producer"], qgisId + ) - producer2 = xmpDoc.findall("rdf:RDF/rdf:Description[@xmp:CreatorTool]", namespaces) + producer2 = xmpDoc.findall( + "rdf:RDF/rdf:Description[@xmp:CreatorTool]", namespaces + ) self.assertEqual(len(producer2), 1) - self.assertEqual(producer2[0].attrib["{" + namespaces["xmp"] + "}" + "CreatorTool"], qgisId) + self.assertEqual( + producer2[0].attrib["{" + namespaces["xmp"] + "}" + "CreatorTool"], qgisId + ) - creationDateTags = xmpDoc.findall("rdf:RDF/rdf:Description[@xmp:CreateDate]", namespaces) + creationDateTags = xmpDoc.findall( + "rdf:RDF/rdf:Description[@xmp:CreateDate]", namespaces + ) self.assertEqual(len(creationDateTags), 1) - creationDate = creationDateTags[0].attrib["{" + namespaces["xmp"] + "}" + "CreateDate"] + creationDate = creationDateTags[0].attrib[ + "{" + namespaces["xmp"] + "}" + "CreateDate" + ] self.assertEqual(creationDate, "2011-05-03T09:04:05+10:00") - metadataDateTags = xmpDoc.findall("rdf:RDF/rdf:Description[@xmp:MetadataDate]", namespaces) + metadataDateTags = xmpDoc.findall( + "rdf:RDF/rdf:Description[@xmp:MetadataDate]", namespaces + ) self.assertEqual(len(metadataDateTags), 1) - metadataDate = metadataDateTags[0].attrib["{" + namespaces["xmp"] + "}" + "MetadataDate"] + metadataDate = metadataDateTags[0].attrib[ + "{" + namespaces["xmp"] + "}" + "MetadataDate" + ] self.assertEqual(metadataDate, "2011-05-03T09:04:05+10:00") - modifyDateTags = xmpDoc.findall("rdf:RDF/rdf:Description[@xmp:ModifyDate]", namespaces) + modifyDateTags = xmpDoc.findall( + "rdf:RDF/rdf:Description[@xmp:ModifyDate]", namespaces + ) self.assertEqual(len(modifyDateTags), 1) - modifyDate = modifyDateTags[0].attrib["{" + namespaces["xmp"] + "}" + "ModifyDate"] + modifyDate = modifyDateTags[0].attrib[ + "{" + namespaces["xmp"] + "}" + "ModifyDate" + ] self.assertEqual(modifyDate, "2011-05-03T09:04:05+10:00") - docIdTags = xmpDoc.findall("rdf:RDF/rdf:Description[@xmpMM:DocumentID]", namespaces) + docIdTags = xmpDoc.findall( + "rdf:RDF/rdf:Description[@xmpMM:DocumentID]", namespaces + ) self.assertEqual(len(docIdTags), 1) docId = docIdTags[0].attrib["{" + namespaces["xmpMM"] + "}" + "DocumentID"] uuidValid = True @@ -585,12 +736,14 @@ def testExportToPdf(self): def testExportToPdfGeoreference(self): md = QgsProject.instance().metadata() - md.setTitle('proj title') - md.setAuthor('proj author') - md.setCreationDateTime(QDateTime(QDate(2011, 5, 3), QTime(9, 4, 5), QTimeZone(36000))) - md.setIdentifier('proj identifier') - md.setAbstract('proj abstract') - md.setKeywords({'kw': ['kw1', 'kw2'], 'KWx': ['kw3', 'kw4']}) + md.setTitle("proj title") + md.setAuthor("proj author") + md.setCreationDateTime( + QDateTime(QDate(2011, 5, 3), QTime(9, 4, 5), QTimeZone(36000)) + ) + md.setIdentifier("proj identifier") + md.setAbstract("proj abstract") + md.setKeywords({"kw": ["kw1", "kw2"], "KWx": ["kw3", "kw4"]}) QgsProject.instance().setMetadata(md) l = QgsLayout(QgsProject.instance()) @@ -600,7 +753,7 @@ def testExportToPdfGeoreference(self): map = QgsLayoutItemMap(l) map.attemptSetSceneRect(QRectF(30, 60, 200, 100)) extent = QgsRectangle(333218, 1167809, 348781, 1180875) - map.setCrs(QgsCoordinateReferenceSystem('EPSG:3148')) + map.setCrs(QgsCoordinateReferenceSystem("EPSG:3148")) map.setExtent(extent) l.addLayoutItem(map) @@ -613,8 +766,13 @@ def testExportToPdfGeoreference(self): settings.appendGeoreference = True settings.exportMetadata = False - pdf_file_path = os.path.join(self.basetestpath, 'test_exporttopdf_georeference.pdf') - self.assertEqual(exporter.exportToPdf(pdf_file_path, settings), QgsLayoutExporter.ExportResult.Success) + pdf_file_path = os.path.join( + self.basetestpath, "test_exporttopdf_georeference.pdf" + ) + self.assertEqual( + exporter.exportToPdf(pdf_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) self.assertTrue(os.path.exists(pdf_file_path)) d = gdal.Open(pdf_file_path) @@ -630,7 +788,7 @@ def testExportToPdfGeoreference(self): # check that the metadata has _not_ been added to the exported PDF metadata = d.GetMetadata() - self.assertNotIn('AUTHOR', metadata) + self.assertNotIn("AUTHOR", metadata) exporter = QgsLayoutExporter(l) # setup settings @@ -641,8 +799,13 @@ def testExportToPdfGeoreference(self): settings.appendGeoreference = False settings.exportMetadata = False - pdf_file_path = os.path.join(self.basetestpath, 'test_exporttopdf_nogeoreference.pdf') - self.assertEqual(exporter.exportToPdf(pdf_file_path, settings), QgsLayoutExporter.ExportResult.Success) + pdf_file_path = os.path.join( + self.basetestpath, "test_exporttopdf_nogeoreference.pdf" + ) + self.assertEqual( + exporter.exportToPdf(pdf_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) self.assertTrue(os.path.exists(pdf_file_path)) d = gdal.Open(pdf_file_path) @@ -659,7 +822,7 @@ def testExportToPdfSkipFirstPage(self): # add a second page page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") l.pageCollection().addPage(page2) item2 = QgsLayoutItemShape(l) @@ -681,37 +844,50 @@ def testExportToPdfSkipFirstPage(self): settings.forceVectorOutput = False settings.exportMetadata = True - pdf_file_path = os.path.join(self.basetestpath, 'test_exporttopdfdpi_skip_first.pdf') - self.assertEqual(exporter.exportToPdf(pdf_file_path, settings), QgsLayoutExporter.ExportResult.Success) + pdf_file_path = os.path.join( + self.basetestpath, "test_exporttopdfdpi_skip_first.pdf" + ) + self.assertEqual( + exporter.exportToPdf(pdf_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) self.assertTrue(os.path.exists(pdf_file_path)) - rendered_page_1 = os.path.join(self.basetestpath, 'test_exporttopdfdpi_skip_first.png') + rendered_page_1 = os.path.join( + self.basetestpath, "test_exporttopdfdpi_skip_first.png" + ) dpi = 80 pdfToPng(pdf_file_path, rendered_page_1, dpi=dpi, page=1) image = QImage(rendered_page_1) self.assertTrue( - self.image_check('test_exporttopdfdpi_skip_first', 'layoutexporter_exporttopdfdpi_page2', image, - color_tolerance=2, - allowed_mismatch=20, - size_tolerance=1) + self.image_check( + "test_exporttopdfdpi_skip_first", + "layoutexporter_exporttopdfdpi_page2", + image, + color_tolerance=2, + allowed_mismatch=20, + size_tolerance=1, + ) ) def testExportToSvg(self): md = QgsProject.instance().metadata() - md.setTitle('proj title') - md.setAuthor('proj author') - md.setCreationDateTime(QDateTime(QDate(2011, 5, 3), QTime(9, 4, 5), QTimeZone(36000))) - md.setIdentifier('proj identifier') - md.setAbstract('proj abstract') - md.setKeywords({'kw': ['kw1', 'kw2']}) + md.setTitle("proj title") + md.setAuthor("proj author") + md.setCreationDateTime( + QDateTime(QDate(2011, 5, 3), QTime(9, 4, 5), QTimeZone(36000)) + ) + md.setIdentifier("proj identifier") + md.setAbstract("proj abstract") + md.setKeywords({"kw": ["kw1", "kw2"]}) QgsProject.instance().setMetadata(md) l = QgsLayout(QgsProject.instance()) l.initializeDefaults() # add a second page page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") l.pageCollection().addPage(page2) # add some items @@ -743,9 +919,12 @@ def testExportToSvg(self): settings.forceVectorOutput = False settings.exportMetadata = True - svg_file_path = os.path.join(self.basetestpath, 'test_exporttosvgdpi.svg') - svg_file_path_2 = os.path.join(self.basetestpath, 'test_exporttosvgdpi_2.svg') - self.assertEqual(exporter.exportToSvg(svg_file_path, settings), QgsLayoutExporter.ExportResult.Success) + svg_file_path = os.path.join(self.basetestpath, "test_exporttosvgdpi.svg") + svg_file_path_2 = os.path.join(self.basetestpath, "test_exporttosvgdpi_2.svg") + self.assertEqual( + exporter.exportToSvg(svg_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) self.assertTrue(os.path.exists(svg_file_path)) self.assertTrue(os.path.exists(svg_file_path_2)) @@ -754,42 +933,54 @@ def checkMetadata(f, expected): # ideally we'd check the path too - but that's very complex given that # the output from Qt svg generator isn't valid XML, and no Python standard library # xml parser handles invalid xml... - self.assertEqual('proj title' in open(f).read(), expected) - self.assertEqual('proj author' in open(f).read(), expected) - self.assertEqual('proj identifier' in open(f).read(), expected) - self.assertEqual('2011-05-03' in open(f).read(), expected) - self.assertEqual('proj abstract' in open(f).read(), expected) - self.assertEqual('kw1' in open(f).read(), expected) - self.assertEqual('kw2' in open(f).read(), expected) - self.assertEqual('xmlns:cc="http://creativecommons.org/ns#"' in open(f).read(), expected) + self.assertEqual("proj title" in open(f).read(), expected) + self.assertEqual("proj author" in open(f).read(), expected) + self.assertEqual("proj identifier" in open(f).read(), expected) + self.assertEqual("2011-05-03" in open(f).read(), expected) + self.assertEqual("proj abstract" in open(f).read(), expected) + self.assertEqual("kw1" in open(f).read(), expected) + self.assertEqual("kw2" in open(f).read(), expected) + self.assertEqual( + 'xmlns:cc="http://creativecommons.org/ns#"' in open(f).read(), expected + ) for f in [svg_file_path, svg_file_path_2]: checkMetadata(f, True) - rendered_page_1 = os.path.join(self.basetestpath, 'test_exporttosvgdpi.png') + rendered_page_1 = os.path.join(self.basetestpath, "test_exporttosvgdpi.png") svgToPng(svg_file_path, rendered_page_1, width=936) - rendered_page_2 = os.path.join(self.basetestpath, 'test_exporttosvgdpi2.png') + rendered_page_2 = os.path.join(self.basetestpath, "test_exporttosvgdpi2.png") svgToPng(svg_file_path_2, rendered_page_2, width=467) image = QImage(rendered_page_1) self.assertTrue( - self.image_check('exporttosvgdpi_page1', 'layoutexporter_exporttopdfdpi_page1', image, - color_tolerance=2, - allowed_mismatch=20, - size_tolerance=1) + self.image_check( + "exporttosvgdpi_page1", + "layoutexporter_exporttopdfdpi_page1", + image, + color_tolerance=2, + allowed_mismatch=20, + size_tolerance=1, + ) ) image = QImage(rendered_page_2) self.assertTrue( - self.image_check('exporttosvgdpi_page2', - 'layoutexporter_exporttopdfdpi_page2', image, - color_tolerance=2, - allowed_mismatch=20, - size_tolerance=1) + self.image_check( + "exporttosvgdpi_page2", + "layoutexporter_exporttopdfdpi_page2", + image, + color_tolerance=2, + allowed_mismatch=20, + size_tolerance=1, + ) ) # no metadata settings.exportMetadata = False - self.assertEqual(exporter.exportToSvg(svg_file_path, settings), QgsLayoutExporter.ExportResult.Success) + self.assertEqual( + exporter.exportToSvg(svg_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) for f in [svg_file_path, svg_file_path_2]: checkMetadata(f, False) @@ -797,30 +988,45 @@ def checkMetadata(f, expected): settings.exportAsLayers = True settings.exportMetadata = True - svg_file_path = os.path.join(self.basetestpath, 'test_exporttosvglayered.svg') - svg_file_path_2 = os.path.join(self.basetestpath, 'test_exporttosvglayered_2.svg') - self.assertEqual(exporter.exportToSvg(svg_file_path, settings), QgsLayoutExporter.ExportResult.Success) + svg_file_path = os.path.join(self.basetestpath, "test_exporttosvglayered.svg") + svg_file_path_2 = os.path.join( + self.basetestpath, "test_exporttosvglayered_2.svg" + ) + self.assertEqual( + exporter.exportToSvg(svg_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) self.assertTrue(os.path.exists(svg_file_path)) self.assertTrue(os.path.exists(svg_file_path_2)) - rendered_page_1 = os.path.join(self.basetestpath, 'test_exporttosvglayered.png') + rendered_page_1 = os.path.join(self.basetestpath, "test_exporttosvglayered.png") svgToPng(svg_file_path, rendered_page_1, width=936) - rendered_page_2 = os.path.join(self.basetestpath, 'test_exporttosvglayered2.png') + rendered_page_2 = os.path.join( + self.basetestpath, "test_exporttosvglayered2.png" + ) svgToPng(svg_file_path_2, rendered_page_2, width=467) image = QImage(rendered_page_1) self.assertTrue( - self.image_check('exporttosvglayered_page1', 'layoutexporter_exporttopdfdpi_page1', image, - color_tolerance=2, - allowed_mismatch=20, - size_tolerance=1) + self.image_check( + "exporttosvglayered_page1", + "layoutexporter_exporttopdfdpi_page1", + image, + color_tolerance=2, + allowed_mismatch=20, + size_tolerance=1, + ) ) image = QImage(rendered_page_2) self.assertTrue( - self.image_check('exporttosvglayered_page2', 'layoutexporter_exporttopdfdpi_page2', image, - color_tolerance=2, - allowed_mismatch=20, - size_tolerance=1) + self.image_check( + "exporttosvglayered_page2", + "layoutexporter_exporttopdfdpi_page2", + image, + color_tolerance=2, + allowed_mismatch=20, + size_tolerance=1, + ) ) for f in [svg_file_path, svg_file_path_2]: @@ -829,7 +1035,10 @@ def checkMetadata(f, expected): # layered no metadata settings.exportAsLayers = True settings.exportMetadata = False - self.assertEqual(exporter.exportToSvg(svg_file_path, settings), QgsLayoutExporter.ExportResult.Success) + self.assertEqual( + exporter.exportToSvg(svg_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) for f in [svg_file_path, svg_file_path_2]: checkMetadata(f, False) @@ -841,13 +1050,15 @@ def testExportToSvgTextRenderFormat(self): mapitem = QgsLayoutItemMap(l) mapitem.attemptSetSceneRect(QRectF(110, 120, 200, 250)) mapitem.zoomToExtent(QgsRectangle(1, 1, 10, 10)) - mapitem.setScale(666) # unlikely to appear in the SVG by accident... unless... oh no! RUN! + mapitem.setScale( + 666 + ) # unlikely to appear in the SVG by accident... unless... oh no! RUN! l.addItem(mapitem) item1 = QgsLayoutItemScaleBar(l) item1.attemptSetSceneRect(QRectF(10, 20, 100, 150)) item1.setLinkedMap(mapitem) - item1.setStyle('Numeric') + item1.setStyle("Numeric") l.addItem(item1) exporter = QgsLayoutExporter(l) @@ -856,29 +1067,41 @@ def testExportToSvgTextRenderFormat(self): settings.dpi = 80 settings.forceVectorOutput = False settings.exportMetadata = True - settings.textRenderFormat = QgsRenderContext.TextRenderFormat.TextFormatAlwaysText + settings.textRenderFormat = ( + QgsRenderContext.TextRenderFormat.TextFormatAlwaysText + ) - svg_file_path = os.path.join(self.basetestpath, 'test_exporttosvgtextformattext.svg') - self.assertEqual(exporter.exportToSvg(svg_file_path, settings), QgsLayoutExporter.ExportResult.Success) + svg_file_path = os.path.join( + self.basetestpath, "test_exporttosvgtextformattext.svg" + ) + self.assertEqual( + exporter.exportToSvg(svg_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) self.assertTrue(os.path.exists(svg_file_path)) # expect svg to contain a text object with the scale with open(svg_file_path) as f: - lines = ''.join(f.readlines()) - self.assertIn('1:666<', lines) + lines = "".join(f.readlines()) + self.assertIn("1:666<", lines) # force use of outlines os.unlink(svg_file_path) - settings.textRenderFormat = QgsRenderContext.TextRenderFormat.TextFormatAlwaysOutlines - self.assertEqual(exporter.exportToSvg(svg_file_path, settings), QgsLayoutExporter.ExportResult.Success) + settings.textRenderFormat = ( + QgsRenderContext.TextRenderFormat.TextFormatAlwaysOutlines + ) + self.assertEqual( + exporter.exportToSvg(svg_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) self.assertTrue(os.path.exists(svg_file_path)) # expect svg NOT to contain a text object with the scale with open(svg_file_path) as f: - lines = ''.join(f.readlines()) - self.assertNotIn('1:666<', lines) + lines = "".join(f.readlines()) + self.assertNotIn("1:666<", lines) def testPrint(self): l = QgsLayout(QgsProject.instance()) @@ -886,7 +1109,7 @@ def testPrint(self): # add a second page page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") l.pageCollection().addPage(page2) # add some items @@ -917,34 +1140,44 @@ def testPrint(self): settings.dpi = 80 settings.rasterizeWholeImage = False - pdf_file_path = os.path.join(self.basetestpath, 'test_printdpi.pdf') + pdf_file_path = os.path.join(self.basetestpath, "test_printdpi.pdf") # make a qprinter directed to pdf printer = QPrinter() printer.setOutputFileName(pdf_file_path) printer.setOutputFormat(QPrinter.OutputFormat.PdfFormat) - self.assertEqual(exporter.print(printer, settings), QgsLayoutExporter.ExportResult.Success) + self.assertEqual( + exporter.print(printer, settings), QgsLayoutExporter.ExportResult.Success + ) self.assertTrue(os.path.exists(pdf_file_path)) - rendered_page_1 = os.path.join(self.basetestpath, 'test_exporttopdfdpi.png') + rendered_page_1 = os.path.join(self.basetestpath, "test_exporttopdfdpi.png") dpi = 80 pdfToPng(pdf_file_path, rendered_page_1, dpi=dpi, page=1) - rendered_page_2 = os.path.join(self.basetestpath, 'test_exporttopdfdpi2.png') + rendered_page_2 = os.path.join(self.basetestpath, "test_exporttopdfdpi2.png") pdfToPng(pdf_file_path, rendered_page_2, dpi=dpi, page=2) image = QImage(rendered_page_1) self.assertTrue( - self.image_check('printdpi_page1', 'layoutexporter_exporttopdfdpi_page1', image, - color_tolerance=2, - allowed_mismatch=20, - size_tolerance=1) + self.image_check( + "printdpi_page1", + "layoutexporter_exporttopdfdpi_page1", + image, + color_tolerance=2, + allowed_mismatch=20, + size_tolerance=1, + ) ) image = QImage(rendered_page_2) self.assertTrue( - self.image_check('printdpi_page2', 'layoutexporter_exporttopdfdpi_page2', image, - color_tolerance=2, - allowed_mismatch=20, - size_tolerance=1) + self.image_check( + "printdpi_page2", + "layoutexporter_exporttopdfdpi_page2", + image, + color_tolerance=2, + allowed_mismatch=20, + size_tolerance=1, + ) ) def testExportWorldFile(self): @@ -964,16 +1197,28 @@ def testExportWorldFile(self): settings.dpi = 80 settings.generateWorldFile = False - rendered_file_path = os.path.join(self.basetestpath, 'test_exportwithworldfile.png') - world_file_path = os.path.join(self.basetestpath, 'test_exportwithworldfile.pgw') - self.assertEqual(exporter.exportToImage(rendered_file_path, settings), QgsLayoutExporter.ExportResult.Success) + rendered_file_path = os.path.join( + self.basetestpath, "test_exportwithworldfile.png" + ) + world_file_path = os.path.join( + self.basetestpath, "test_exportwithworldfile.pgw" + ) + self.assertEqual( + exporter.exportToImage(rendered_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) self.assertTrue(os.path.exists(rendered_file_path)) self.assertFalse(os.path.exists(world_file_path)) # with world file settings.generateWorldFile = True - rendered_file_path = os.path.join(self.basetestpath, 'test_exportwithworldfile.png') - self.assertEqual(exporter.exportToImage(rendered_file_path, settings), QgsLayoutExporter.ExportResult.Success) + rendered_file_path = os.path.join( + self.basetestpath, "test_exportwithworldfile.png" + ) + self.assertEqual( + exporter.exportToImage(rendered_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) self.assertTrue(os.path.exists(rendered_file_path)) self.assertTrue(os.path.exists(world_file_path)) @@ -991,7 +1236,7 @@ def testExcludePagesImage(self): l.initializeDefaults() # add a second page page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") l.pageCollection().addPage(page2) exporter = QgsLayoutExporter(l) @@ -1000,34 +1245,47 @@ def testExcludePagesImage(self): settings.dpi = 80 settings.generateWorldFile = False - rendered_file_path = os.path.join(self.basetestpath, 'test_exclude_export.png') + rendered_file_path = os.path.join(self.basetestpath, "test_exclude_export.png") details = QgsLayoutExporter.PageExportDetails() details.directory = self.basetestpath - details.baseName = 'test_exclude_export' - details.extension = 'png' + details.baseName = "test_exclude_export" + details.extension = "png" details.page = 0 - self.assertEqual(exporter.exportToImage(rendered_file_path, settings), QgsLayoutExporter.ExportResult.Success) + self.assertEqual( + exporter.exportToImage(rendered_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) self.assertTrue(os.path.exists(exporter.generateFileName(details))) details.page = 1 self.assertTrue(os.path.exists(exporter.generateFileName(details))) # exclude a page l.pageCollection().page(0).setExcludeFromExports(True) - rendered_file_path = os.path.join(self.basetestpath, 'test_exclude_export_excluded.png') - details.baseName = 'test_exclude_export_excluded' + rendered_file_path = os.path.join( + self.basetestpath, "test_exclude_export_excluded.png" + ) + details.baseName = "test_exclude_export_excluded" details.page = 0 - self.assertEqual(exporter.exportToImage(rendered_file_path, settings), QgsLayoutExporter.ExportResult.Success) + self.assertEqual( + exporter.exportToImage(rendered_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) self.assertFalse(os.path.exists(exporter.generateFileName(details))) details.page = 1 self.assertTrue(os.path.exists(exporter.generateFileName(details))) # exclude second page l.pageCollection().page(1).setExcludeFromExports(True) - rendered_file_path = os.path.join(self.basetestpath, 'test_exclude_export_excluded_all.png') - details.baseName = 'test_exclude_export_excluded_all' + rendered_file_path = os.path.join( + self.basetestpath, "test_exclude_export_excluded_all.png" + ) + details.baseName = "test_exclude_export_excluded_all" details.page = 0 - self.assertEqual(exporter.exportToImage(rendered_file_path, settings), QgsLayoutExporter.ExportResult.Success) + self.assertEqual( + exporter.exportToImage(rendered_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) self.assertFalse(os.path.exists(exporter.generateFileName(details))) details.page = 1 self.assertFalse(os.path.exists(exporter.generateFileName(details))) @@ -1036,31 +1294,39 @@ def testPageFileName(self): l = QgsLayout(QgsProject.instance()) exporter = QgsLayoutExporter(l) details = QgsLayoutExporter.PageExportDetails() - details.directory = '/tmp/output' - details.baseName = 'my_maps' - details.extension = 'png' + details.directory = "/tmp/output" + details.baseName = "my_maps" + details.extension = "png" details.page = 0 - self.assertEqual(exporter.generateFileName(details), '/tmp/output/my_maps.png') + self.assertEqual(exporter.generateFileName(details), "/tmp/output/my_maps.png") details.page = 1 - self.assertEqual(exporter.generateFileName(details), '/tmp/output/my_maps_2.png') + self.assertEqual( + exporter.generateFileName(details), "/tmp/output/my_maps_2.png" + ) details.page = 2 - self.assertEqual(exporter.generateFileName(details), '/tmp/output/my_maps_3.png') + self.assertEqual( + exporter.generateFileName(details), "/tmp/output/my_maps_3.png" + ) def prepareIteratorLayout(self): - layer_path = os.path.join(TEST_DATA_DIR, 'france_parts.shp') - layer = QgsVectorLayer(layer_path, 'test', "ogr") + layer_path = os.path.join(TEST_DATA_DIR, "france_parts.shp") + layer = QgsVectorLayer(layer_path, "test", "ogr") project = QgsProject() project.addMapLayers([layer]) # select epsg:2154 - crs = QgsCoordinateReferenceSystem('epsg:2154') + crs = QgsCoordinateReferenceSystem("epsg:2154") project.setCrs(crs) layout = QgsPrintLayout(project) layout.initializeDefaults() # fix the renderer, fill with green - props = {"color": "0,127,0", "outline_width": "4", "outline_color": '255,255,255'} + props = { + "color": "0,127,0", + "outline_width": "4", + "outline_color": "255,255,255", + } fillSymbol = QgsFillSymbol.createSimple(props) renderer = QgsSingleSymbolRenderer(fillSymbol) layer.setRenderer(renderer) @@ -1078,7 +1344,13 @@ def prepareIteratorLayout(self): atlas.setEnabled(True) atlas_map.setExtent( - QgsRectangle(332719.06221504929, 6765214.5887386119, 560957.85090677091, 6993453.3774303338)) + QgsRectangle( + 332719.06221504929, + 6765214.5887386119, + 560957.85090677091, + 6993453.3774303338, + ) + ) atlas_map.setAtlasDriven(True) atlas_map.setAtlasScalingMode(QgsLayoutItemMap.AtlasScalingMode.Auto) @@ -1095,26 +1367,44 @@ def testIteratorToImages(self): settings = QgsLayoutExporter.ImageExportSettings() settings.dpi = 80 - result, error = QgsLayoutExporter.exportToImage(atlas, self.basetestpath + '/', 'png', settings) + result, error = QgsLayoutExporter.exportToImage( + atlas, self.basetestpath + "/", "png", settings + ) self.assertEqual(result, QgsLayoutExporter.ExportResult.Success, error) - page1_path = os.path.join(self.basetestpath, 'test_exportiteratortoimage_Basse-Normandie.png') + page1_path = os.path.join( + self.basetestpath, "test_exportiteratortoimage_Basse-Normandie.png" + ) image = QImage(page1_path) self.assertTrue( - self.image_check('iteratortoimage1', 'layoutexporter_iteratortoimage1', image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "iteratortoimage1", + "layoutexporter_iteratortoimage1", + image, + color_tolerance=2, + allowed_mismatch=20, + ) + ) + page2_path = os.path.join( + self.basetestpath, "test_exportiteratortoimage_Bretagne.png" ) - page2_path = os.path.join(self.basetestpath, 'test_exportiteratortoimage_Bretagne.png') image = QImage(page2_path) self.assertTrue( - self.image_check('iteratortoimage2', 'layoutexporter_iteratortoimage2', image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "iteratortoimage2", + "layoutexporter_iteratortoimage2", + image, + color_tolerance=2, + allowed_mismatch=20, + ) + ) + page3_path = os.path.join( + self.basetestpath, "test_exportiteratortoimage_Centre.png" ) - page3_path = os.path.join(self.basetestpath, 'test_exportiteratortoimage_Centre.png') self.assertTrue(os.path.exists(page3_path)) - page4_path = os.path.join(self.basetestpath, 'test_exportiteratortoimage_Pays de la Loire.png') + page4_path = os.path.join( + self.basetestpath, "test_exportiteratortoimage_Pays de la Loire.png" + ) self.assertTrue(os.path.exists(page4_path)) def testIteratorToSvgs(self): @@ -1127,32 +1417,54 @@ def testIteratorToSvgs(self): settings.dpi = 80 settings.forceVectorOutput = False - result, error = QgsLayoutExporter.exportToSvg(atlas, self.basetestpath + '/', settings) + result, error = QgsLayoutExporter.exportToSvg( + atlas, self.basetestpath + "/", settings + ) self.assertEqual(result, QgsLayoutExporter.ExportResult.Success, error) - page1_path = os.path.join(self.basetestpath, 'test_exportiteratortosvg_Basse-Normandie.svg') - rendered_page_1 = os.path.join(self.basetestpath, 'test_exportiteratortosvg_Basse-Normandie.png') + page1_path = os.path.join( + self.basetestpath, "test_exportiteratortosvg_Basse-Normandie.svg" + ) + rendered_page_1 = os.path.join( + self.basetestpath, "test_exportiteratortosvg_Basse-Normandie.png" + ) svgToPng(page1_path, rendered_page_1, width=935) image = QImage(rendered_page_1) self.assertTrue( - self.image_check('iteratortosvg1', 'layoutexporter_iteratortoimage1', image, - color_tolerance=2, - allowed_mismatch=20, - size_tolerance=2) + self.image_check( + "iteratortosvg1", + "layoutexporter_iteratortoimage1", + image, + color_tolerance=2, + allowed_mismatch=20, + size_tolerance=2, + ) + ) + page2_path = os.path.join( + self.basetestpath, "test_exportiteratortosvg_Bretagne.svg" + ) + rendered_page_2 = os.path.join( + self.basetestpath, "test_exportiteratortosvg_Bretagne.png" ) - page2_path = os.path.join(self.basetestpath, 'test_exportiteratortosvg_Bretagne.svg') - rendered_page_2 = os.path.join(self.basetestpath, 'test_exportiteratortosvg_Bretagne.png') svgToPng(page2_path, rendered_page_2, width=935) image = QImage(rendered_page_2) self.assertTrue( - self.image_check('iteratortosvg2', 'layoutexporter_iteratortoimage2', image, - color_tolerance=2, - allowed_mismatch=20, - size_tolerance=2) + self.image_check( + "iteratortosvg2", + "layoutexporter_iteratortoimage2", + image, + color_tolerance=2, + allowed_mismatch=20, + size_tolerance=2, + ) + ) + page3_path = os.path.join( + self.basetestpath, "test_exportiteratortosvg_Centre.svg" ) - page3_path = os.path.join(self.basetestpath, 'test_exportiteratortosvg_Centre.svg') self.assertTrue(os.path.exists(page3_path)) - page4_path = os.path.join(self.basetestpath, 'test_exportiteratortosvg_Pays de la Loire.svg') + page4_path = os.path.join( + self.basetestpath, "test_exportiteratortosvg_Pays de la Loire.svg" + ) self.assertTrue(os.path.exists(page4_path)) def testIteratorToPdfs(self): @@ -1166,32 +1478,54 @@ def testIteratorToPdfs(self): settings.rasterizeWholeImage = False settings.forceVectorOutput = False - result, error = QgsLayoutExporter.exportToPdfs(atlas, self.basetestpath + '/', settings) + result, error = QgsLayoutExporter.exportToPdfs( + atlas, self.basetestpath + "/", settings + ) self.assertEqual(result, QgsLayoutExporter.ExportResult.Success, error) - page1_path = os.path.join(self.basetestpath, 'test_exportiteratortopdf_Basse-Normandie.pdf') - rendered_page_1 = os.path.join(self.basetestpath, 'test_exportiteratortopdf_Basse-Normandie.png') + page1_path = os.path.join( + self.basetestpath, "test_exportiteratortopdf_Basse-Normandie.pdf" + ) + rendered_page_1 = os.path.join( + self.basetestpath, "test_exportiteratortopdf_Basse-Normandie.png" + ) pdfToPng(page1_path, rendered_page_1, dpi=80, page=1) image = QImage(rendered_page_1) self.assertTrue( - self.image_check('iteratortopdf1', 'layoutexporter_iteratortoimage1', image, - color_tolerance=2, - allowed_mismatch=20, - size_tolerance=2) + self.image_check( + "iteratortopdf1", + "layoutexporter_iteratortoimage1", + image, + color_tolerance=2, + allowed_mismatch=20, + size_tolerance=2, + ) + ) + page2_path = os.path.join( + self.basetestpath, "test_exportiteratortopdf_Bretagne.pdf" + ) + rendered_page_2 = os.path.join( + self.basetestpath, "test_exportiteratortopdf_Bretagne.png" ) - page2_path = os.path.join(self.basetestpath, 'test_exportiteratortopdf_Bretagne.pdf') - rendered_page_2 = os.path.join(self.basetestpath, 'test_exportiteratortopdf_Bretagne.png') pdfToPng(page2_path, rendered_page_2, dpi=80, page=1) image = QImage(rendered_page_2) self.assertTrue( - self.image_check('iteratortopdf2', 'layoutexporter_iteratortoimage2', image, - color_tolerance=2, - allowed_mismatch=20, - size_tolerance=2) + self.image_check( + "iteratortopdf2", + "layoutexporter_iteratortoimage2", + image, + color_tolerance=2, + allowed_mismatch=20, + size_tolerance=2, + ) + ) + page3_path = os.path.join( + self.basetestpath, "test_exportiteratortopdf_Centre.pdf" ) - page3_path = os.path.join(self.basetestpath, 'test_exportiteratortopdf_Centre.pdf') self.assertTrue(os.path.exists(page3_path)) - page4_path = os.path.join(self.basetestpath, 'test_exportiteratortopdf_Pays de la Loire.pdf') + page4_path = os.path.join( + self.basetestpath, "test_exportiteratortopdf_Pays de la Loire.pdf" + ) self.assertTrue(os.path.exists(page4_path)) def testIteratorToPdf(self): @@ -1204,34 +1538,52 @@ def testIteratorToPdf(self): settings.rasterizeWholeImage = False settings.forceVectorOutput = False - pdf_path = os.path.join(self.basetestpath, 'test_exportiteratortopdf_single.pdf') + pdf_path = os.path.join( + self.basetestpath, "test_exportiteratortopdf_single.pdf" + ) result, error = QgsLayoutExporter.exportToPdf(atlas, pdf_path, settings) self.assertEqual(result, QgsLayoutExporter.ExportResult.Success, error) - rendered_page_1 = os.path.join(self.basetestpath, 'test_exportiteratortopdf_single1.png') + rendered_page_1 = os.path.join( + self.basetestpath, "test_exportiteratortopdf_single1.png" + ) pdfToPng(pdf_path, rendered_page_1, dpi=80, page=1) image = QImage(rendered_page_1) self.assertTrue( - self.image_check('iteratortopdfsingle1', 'layoutexporter_iteratortoimage1', image, - color_tolerance=2, - allowed_mismatch=20, - size_tolerance=2) + self.image_check( + "iteratortopdfsingle1", + "layoutexporter_iteratortoimage1", + image, + color_tolerance=2, + allowed_mismatch=20, + size_tolerance=2, + ) ) - rendered_page_2 = os.path.join(self.basetestpath, 'test_exportiteratortopdf_single2.png') + rendered_page_2 = os.path.join( + self.basetestpath, "test_exportiteratortopdf_single2.png" + ) pdfToPng(pdf_path, rendered_page_2, dpi=80, page=2) image = QImage(rendered_page_2) self.assertTrue( - self.image_check('iteratortopdfsingle2', 'layoutexporter_iteratortoimage2', image, - color_tolerance=2, - allowed_mismatch=20, - size_tolerance=2) + self.image_check( + "iteratortopdfsingle2", + "layoutexporter_iteratortoimage2", + image, + color_tolerance=2, + allowed_mismatch=20, + size_tolerance=2, + ) ) - rendered_page_3 = os.path.join(self.basetestpath, 'test_exportiteratortopdf_single3.png') + rendered_page_3 = os.path.join( + self.basetestpath, "test_exportiteratortopdf_single3.png" + ) pdfToPng(pdf_path, rendered_page_3, dpi=80, page=3) self.assertTrue(os.path.exists(rendered_page_3)) - rendered_page_4 = os.path.join(self.basetestpath, 'test_exportiteratortopdf_single4.png') + rendered_page_4 = os.path.join( + self.basetestpath, "test_exportiteratortopdf_single4.png" + ) pdfToPng(pdf_path, rendered_page_4, dpi=80, page=4) self.assertTrue(os.path.exists(rendered_page_4)) @@ -1244,7 +1596,7 @@ def testPrintIterator(self): settings.dpi = 80 settings.rasterizeWholeImage = False - pdf_path = os.path.join(self.basetestpath, 'test_printiterator.pdf') + pdf_path = os.path.join(self.basetestpath, "test_printiterator.pdf") # make a qprinter directed to pdf printer = QPrinter() printer.setOutputFileName(pdf_path) @@ -1253,30 +1605,38 @@ def testPrintIterator(self): result, error = QgsLayoutExporter.print(atlas, printer, settings) self.assertEqual(result, QgsLayoutExporter.ExportResult.Success, error) - rendered_page_1 = os.path.join(self.basetestpath, 'test_printiterator1.png') + rendered_page_1 = os.path.join(self.basetestpath, "test_printiterator1.png") pdfToPng(pdf_path, rendered_page_1, dpi=80, page=1) image = QImage(rendered_page_1) self.assertTrue( - self.image_check('printeriterator1', 'layoutexporter_iteratortoimage1', image, - color_tolerance=2, - allowed_mismatch=20, - size_tolerance=2) + self.image_check( + "printeriterator1", + "layoutexporter_iteratortoimage1", + image, + color_tolerance=2, + allowed_mismatch=20, + size_tolerance=2, + ) ) - rendered_page_2 = os.path.join(self.basetestpath, 'test_printiterator2.png') + rendered_page_2 = os.path.join(self.basetestpath, "test_printiterator2.png") pdfToPng(pdf_path, rendered_page_2, dpi=80, page=2) image = QImage(rendered_page_2) self.assertTrue( - self.image_check('printiterator2', 'layoutexporter_iteratortoimage2', image, - color_tolerance=2, - allowed_mismatch=20, - size_tolerance=2) + self.image_check( + "printiterator2", + "layoutexporter_iteratortoimage2", + image, + color_tolerance=2, + allowed_mismatch=20, + size_tolerance=2, + ) ) - rendered_page_3 = os.path.join(self.basetestpath, 'test_printiterator3.png') + rendered_page_3 = os.path.join(self.basetestpath, "test_printiterator3.png") pdfToPng(pdf_path, rendered_page_3, dpi=80, page=3) self.assertTrue(os.path.exists(rendered_page_3)) - rendered_page_4 = os.path.join(self.basetestpath, 'test_printiterator4.png') + rendered_page_4 = os.path.join(self.basetestpath, "test_printiterator4.png") pdfToPng(pdf_path, rendered_page_4, dpi=80, page=4) self.assertTrue(os.path.exists(rendered_page_4)) @@ -1321,23 +1681,31 @@ def testExportReport(self): settings = QgsLayoutExporter.ImageExportSettings() settings.dpi = 80 - report_path = os.path.join(self.basetestpath, 'test_report') - result, error = QgsLayoutExporter.exportToImage(r, report_path, 'png', settings) + report_path = os.path.join(self.basetestpath, "test_report") + result, error = QgsLayoutExporter.exportToImage(r, report_path, "png", settings) self.assertEqual(result, QgsLayoutExporter.ExportResult.Success, error) - page1_path = os.path.join(self.basetestpath, 'test_report_0001.png') + page1_path = os.path.join(self.basetestpath, "test_report_0001.png") image = QImage(page1_path) self.assertTrue( - self.image_check('report_page1', 'layoutexporter_report_page1', image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "report_page1", + "layoutexporter_report_page1", + image, + color_tolerance=2, + allowed_mismatch=20, + ) ) - page2_path = os.path.join(self.basetestpath, 'test_report_0002.png') + page2_path = os.path.join(self.basetestpath, "test_report_0002.png") image = QImage(page2_path) self.assertTrue( - self.image_check('report_page2', 'layoutexporter_report_page2', image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "report_page2", + "layoutexporter_report_page2", + image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testRequiresRasterization(self): @@ -1389,7 +1757,7 @@ def testLabelingResults(self): Test QgsLayoutExporter.labelingResults() """ settings = QgsPalLayerSettings() - settings.fieldName = "\"id\"" + settings.fieldName = '"id"' settings.isExpression = True settings.placement = QgsPalLayerSettings.Placement.OverPoint settings.priority = 10 @@ -1398,13 +1766,19 @@ def testLabelingResults(self): vl = QgsVectorLayer("Point?crs=epsg:4326&field=id:integer", "vl", "memory") f = QgsFeature() f.setAttributes([1]) - f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(-6.250851540391068, 53.335006994584944))) + f.setGeometry( + QgsGeometry.fromPointXY(QgsPointXY(-6.250851540391068, 53.335006994584944)) + ) self.assertTrue(vl.dataProvider().addFeature(f)) f.setAttributes([8888]) - f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(-21.950014487179544, 64.150023619739216))) + f.setGeometry( + QgsGeometry.fromPointXY(QgsPointXY(-21.950014487179544, 64.150023619739216)) + ) self.assertTrue(vl.dataProvider().addFeature(f)) f.setAttributes([33333]) - f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(-0.118667702475932, 51.5019405883275))) + f.setGeometry( + QgsGeometry.fromPointXY(QgsPointXY(-0.118667702475932, 51.5019405883275)) + ) self.assertTrue(vl.dataProvider().addFeature(f)) vl.updateExtents() @@ -1432,16 +1806,21 @@ def testLabelingResults(self): settings = QgsLayoutExporter.ImageExportSettings() settings.dpi = 80 - rendered_file_path = os.path.join(self.basetestpath, 'test_exportlabelresults.png') - self.assertEqual(exporter.exportToImage(rendered_file_path, settings), QgsLayoutExporter.ExportResult.Success) + rendered_file_path = os.path.join( + self.basetestpath, "test_exportlabelresults.png" + ) + self.assertEqual( + exporter.exportToImage(rendered_file_path, settings), + QgsLayoutExporter.ExportResult.Success, + ) results = exporter.labelingResults() self.assertEqual(len(results), 1) labels = results[map.uuid()].allLabels() self.assertEqual(len(labels), 3) - self.assertCountEqual([l.labelText for l in labels], ['1', '33333', '8888']) + self.assertCountEqual([l.labelText for l in labels], ["1", "33333", "8888"]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutframe.py b/tests/src/python/test_qgslayoutframe.py index 003b745963c4..f307a10e6604 100644 --- a/tests/src/python/test_qgslayoutframe.py +++ b/tests/src/python/test_qgslayoutframe.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2017 by Nyall Dawson' -__date__ = '23/10/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "(C) 2017 by Nyall Dawson" +__date__ = "23/10/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.core import QgsLayoutFrame, QgsLayoutItemHtml import unittest @@ -22,7 +23,7 @@ class TestQgsLayoutFrame(QgisTestCase, LayoutItemTestCase): @classmethod def setUpClass(cls): - super(TestQgsLayoutFrame, cls).setUpClass() + super().setUpClass() cls.mf = None @classmethod @@ -31,5 +32,5 @@ def createItem(cls, layout): return QgsLayoutFrame(layout, cls.mf) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutgridsettings.py b/tests/src/python/test_qgslayoutgridsettings.py index 5819ddfe263b..d1c413684dff 100644 --- a/tests/src/python/test_qgslayoutgridsettings.py +++ b/tests/src/python/test_qgslayoutgridsettings.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '05/07/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "05/07/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtGui import QColor, QPen from qgis.PyQt.QtXml import QDomDocument @@ -59,7 +60,9 @@ def testReadWriteXml(self): self.assertTrue(s.writeXml(elem, doc, QgsReadWriteContext())) s2 = QgsLayoutGridSettings(l) - self.assertTrue(s2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext())) + self.assertTrue( + s2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext()) + ) self.assertEqual(s2.resolution().length(), 5.0) self.assertEqual(s2.resolution().units(), QgsUnitTypes.LayoutUnit.LayoutPoints) @@ -116,5 +119,5 @@ def testUndoRedo(self): self.assertEqual(g.resolution().units(), QgsUnitTypes.LayoutUnit.LayoutInches) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutguides.py b/tests/src/python/test_qgslayoutguides.py index 7050309cf6a6..4f5276d099e1 100644 --- a/tests/src/python/test_qgslayoutguides.py +++ b/tests/src/python/test_qgslayoutguides.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '05/07/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "05/07/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt import sip from qgis.PyQt.QtCore import QModelIndex, Qt @@ -36,10 +37,16 @@ def testGuideGettersSetters(self): p = QgsProject() l = QgsLayout(p) l.initializeDefaults() # add a page - g = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), None) + g = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + None, + ) self.assertEqual(g.orientation(), Qt.Orientation.Horizontal) self.assertEqual(g.position().length(), 5.0) - self.assertEqual(g.position().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters) + self.assertEqual( + g.position().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) g.setLayout(l) self.assertEqual(g.layout(), l) @@ -60,11 +67,14 @@ def testUpdateGuide(self): l.initializeDefaults() # add a page # add a second page page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") l.pageCollection().addPage(page2) - g = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), - l.pageCollection().page(0)) + g = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + l.pageCollection().page(0), + ) g.setLayout(l) g.update() @@ -75,7 +85,9 @@ def testUpdateGuide(self): self.assertEqual(g.item().line().y2(), 50) self.assertEqual(g.layoutPosition(), 50) - g.setPosition(QgsLayoutMeasurement(15, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + g.setPosition( + QgsLayoutMeasurement(15, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) g.update() self.assertTrue(g.item().isVisible()) self.assertEqual(g.item().line().x1(), 0) @@ -85,11 +97,16 @@ def testUpdateGuide(self): self.assertEqual(g.layoutPosition(), 15) # guide on page2 - g1 = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), - l.pageCollection().page(1)) + g1 = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + l.pageCollection().page(1), + ) g1.setLayout(l) g1.update() - g1.setPosition(QgsLayoutMeasurement(15, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + g1.setPosition( + QgsLayoutMeasurement(15, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) g1.update() self.assertTrue(g1.item().isVisible()) self.assertEqual(g1.item().line().x1(), 0) @@ -99,8 +116,11 @@ def testUpdateGuide(self): self.assertEqual(g1.layoutPosition(), 235) # vertical guide - g2 = QgsLayoutGuide(Qt.Orientation.Vertical, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), - l.pageCollection().page(0)) + g2 = QgsLayoutGuide( + Qt.Orientation.Vertical, + QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + l.pageCollection().page(0), + ) g2.setLayout(l) g2.update() self.assertTrue(g2.item().isVisible()) @@ -119,13 +139,18 @@ def testUpdateGuide(self): self.assertTrue(g.item().isVisible()) # throw it off the bottom of the page - g.setPosition(QgsLayoutMeasurement(1115, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + g.setPosition( + QgsLayoutMeasurement(1115, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) g.update() self.assertFalse(g.item().isVisible()) # guide on page2 - g3 = QgsLayoutGuide(Qt.Orientation.Vertical, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), - l.pageCollection().page(1)) + g3 = QgsLayoutGuide( + Qt.Orientation.Vertical, + QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + l.pageCollection().page(1), + ) g3.setLayout(l) g3.update() self.assertTrue(g3.item().isVisible()) @@ -143,48 +168,103 @@ def testCollection(self): # no guides initially self.assertEqual(guides.rowCount(QModelIndex()), 0) - self.assertFalse(guides.data(QModelIndex(), QgsLayoutGuideCollection.Roles.OrientationRole)) + self.assertFalse( + guides.data(QModelIndex(), QgsLayoutGuideCollection.Roles.OrientationRole) + ) self.assertFalse(guides.guides(Qt.Orientation.Horizontal)) self.assertFalse(guides.guides(Qt.Orientation.Vertical)) # add a guide - g1 = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), - l.pageCollection().page(0)) + g1 = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + l.pageCollection().page(0), + ) guides.addGuide(g1) self.assertEqual(guides.rowCount(QModelIndex()), 1) - self.assertEqual(guides.data(guides.index(0, 0), QgsLayoutGuideCollection.Roles.OrientationRole), Qt.Orientation.Horizontal) - self.assertEqual(guides.data(guides.index(0, 0), QgsLayoutGuideCollection.Roles.PositionRole), 5) - self.assertEqual(guides.data(guides.index(0, 0), QgsLayoutGuideCollection.Roles.UnitsRole), - QgsUnitTypes.LayoutUnit.LayoutCentimeters) - self.assertEqual(guides.data(guides.index(0, 0), QgsLayoutGuideCollection.Roles.PageRole), 0) + self.assertEqual( + guides.data( + guides.index(0, 0), QgsLayoutGuideCollection.Roles.OrientationRole + ), + Qt.Orientation.Horizontal, + ) + self.assertEqual( + guides.data( + guides.index(0, 0), QgsLayoutGuideCollection.Roles.PositionRole + ), + 5, + ) + self.assertEqual( + guides.data(guides.index(0, 0), QgsLayoutGuideCollection.Roles.UnitsRole), + QgsUnitTypes.LayoutUnit.LayoutCentimeters, + ) + self.assertEqual( + guides.data(guides.index(0, 0), QgsLayoutGuideCollection.Roles.PageRole), 0 + ) self.assertEqual(guides.guides(Qt.Orientation.Horizontal), [g1]) self.assertFalse(guides.guides(Qt.Orientation.Vertical)) self.assertEqual(guides.guidesOnPage(0), [g1]) self.assertEqual(guides.guidesOnPage(1), []) - g2 = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(15), l.pageCollection().page(0)) + g2 = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(15), + l.pageCollection().page(0), + ) guides.addGuide(g2) self.assertEqual(guides.rowCount(QModelIndex()), 2) - self.assertEqual(guides.data(guides.index(1, 0), QgsLayoutGuideCollection.Roles.OrientationRole), Qt.Orientation.Horizontal) - self.assertEqual(guides.data(guides.index(1, 0), QgsLayoutGuideCollection.Roles.PositionRole), 15) - self.assertEqual(guides.data(guides.index(1, 0), QgsLayoutGuideCollection.Roles.UnitsRole), - QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(guides.data(guides.index(1, 0), QgsLayoutGuideCollection.Roles.PageRole), 0) + self.assertEqual( + guides.data( + guides.index(1, 0), QgsLayoutGuideCollection.Roles.OrientationRole + ), + Qt.Orientation.Horizontal, + ) + self.assertEqual( + guides.data( + guides.index(1, 0), QgsLayoutGuideCollection.Roles.PositionRole + ), + 15, + ) + self.assertEqual( + guides.data(guides.index(1, 0), QgsLayoutGuideCollection.Roles.UnitsRole), + QgsUnitTypes.LayoutUnit.LayoutMillimeters, + ) + self.assertEqual( + guides.data(guides.index(1, 0), QgsLayoutGuideCollection.Roles.PageRole), 0 + ) self.assertEqual(guides.guides(Qt.Orientation.Horizontal), [g1, g2]) self.assertFalse(guides.guides(Qt.Orientation.Vertical)) self.assertEqual(guides.guidesOnPage(0), [g1, g2]) page2 = QgsLayoutItemPage(l) - page2.setPageSize('A3') + page2.setPageSize("A3") l.pageCollection().addPage(page2) - g3 = QgsLayoutGuide(Qt.Orientation.Vertical, QgsLayoutMeasurement(35), l.pageCollection().page(1)) + g3 = QgsLayoutGuide( + Qt.Orientation.Vertical, + QgsLayoutMeasurement(35), + l.pageCollection().page(1), + ) guides.addGuide(g3) self.assertEqual(guides.rowCount(QModelIndex()), 3) - self.assertEqual(guides.data(guides.index(2, 0), QgsLayoutGuideCollection.Roles.OrientationRole), Qt.Orientation.Vertical) - self.assertEqual(guides.data(guides.index(2, 0), QgsLayoutGuideCollection.Roles.PositionRole), 35) - self.assertEqual(guides.data(guides.index(2, 0), QgsLayoutGuideCollection.Roles.UnitsRole), - QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(guides.data(guides.index(2, 0), QgsLayoutGuideCollection.Roles.PageRole), 1) + self.assertEqual( + guides.data( + guides.index(2, 0), QgsLayoutGuideCollection.Roles.OrientationRole + ), + Qt.Orientation.Vertical, + ) + self.assertEqual( + guides.data( + guides.index(2, 0), QgsLayoutGuideCollection.Roles.PositionRole + ), + 35, + ) + self.assertEqual( + guides.data(guides.index(2, 0), QgsLayoutGuideCollection.Roles.UnitsRole), + QgsUnitTypes.LayoutUnit.LayoutMillimeters, + ) + self.assertEqual( + guides.data(guides.index(2, 0), QgsLayoutGuideCollection.Roles.PageRole), 1 + ) self.assertEqual(guides.guides(Qt.Orientation.Horizontal), [g1, g2]) self.assertEqual(guides.guides(Qt.Orientation.Horizontal, 0), [g1, g2]) self.assertEqual(guides.guides(Qt.Orientation.Horizontal, 1), []) @@ -201,12 +281,23 @@ def testDeleteRows(self): l.initializeDefaults() guides = l.guides() - g1 = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), - l.pageCollection().page(0)) + g1 = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + l.pageCollection().page(0), + ) guides.addGuide(g1) - g2 = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(15), l.pageCollection().page(0)) + g2 = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(15), + l.pageCollection().page(0), + ) guides.addGuide(g2) - g3 = QgsLayoutGuide(Qt.Orientation.Vertical, QgsLayoutMeasurement(35), l.pageCollection().page(0)) + g3 = QgsLayoutGuide( + Qt.Orientation.Vertical, + QgsLayoutMeasurement(35), + l.pageCollection().page(0), + ) guides.addGuide(g3) self.assertTrue(guides.removeRows(1, 1)) @@ -222,7 +313,7 @@ def testQgsLayoutGuideProxyModel(self): l = QgsLayout(p) l.initializeDefaults() # add a page page2 = QgsLayoutItemPage(l) - page2.setPageSize('A3') + page2.setPageSize("A3") l.pageCollection().addPage(page2) guides = l.guides() @@ -239,27 +330,58 @@ def testQgsLayoutGuideProxyModel(self): self.assertEqual(vert_filter.rowCount(QModelIndex()), 0) # add some guides - g1 = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), - l.pageCollection().page(0)) + g1 = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + l.pageCollection().page(0), + ) guides.addGuide(g1) - g2 = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(15), l.pageCollection().page(1)) + g2 = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(15), + l.pageCollection().page(1), + ) guides.addGuide(g2) - g3 = QgsLayoutGuide(Qt.Orientation.Vertical, QgsLayoutMeasurement(35), l.pageCollection().page(0)) + g3 = QgsLayoutGuide( + Qt.Orientation.Vertical, + QgsLayoutMeasurement(35), + l.pageCollection().page(0), + ) guides.addGuide(g3) self.assertEqual(hoz_filter.rowCount(QModelIndex()), 1) - self.assertEqual(hoz_filter.data(hoz_filter.index(0, 0), QgsLayoutGuideCollection.Roles.PositionRole), 5) + self.assertEqual( + hoz_filter.data( + hoz_filter.index(0, 0), QgsLayoutGuideCollection.Roles.PositionRole + ), + 5, + ) self.assertEqual(hoz_page_1_filter.rowCount(QModelIndex()), 1) - self.assertEqual(hoz_page_1_filter.data(hoz_page_1_filter.index(0, 0), QgsLayoutGuideCollection.Roles.PositionRole), - 15) + self.assertEqual( + hoz_page_1_filter.data( + hoz_page_1_filter.index(0, 0), + QgsLayoutGuideCollection.Roles.PositionRole, + ), + 15, + ) self.assertEqual(vert_filter.rowCount(QModelIndex()), 1) - self.assertEqual(vert_filter.data(vert_filter.index(0, 0), QgsLayoutGuideCollection.Roles.PositionRole), 35) + self.assertEqual( + vert_filter.data( + vert_filter.index(0, 0), QgsLayoutGuideCollection.Roles.PositionRole + ), + 35, + ) # change page hoz_page_1_filter.setPage(0) self.assertEqual(hoz_page_1_filter.rowCount(QModelIndex()), 1) - self.assertEqual(hoz_page_1_filter.data(hoz_page_1_filter.index(0, 0), QgsLayoutGuideCollection.Roles.PositionRole), - 5) + self.assertEqual( + hoz_page_1_filter.data( + hoz_page_1_filter.index(0, 0), + QgsLayoutGuideCollection.Roles.PositionRole, + ), + 5, + ) def testRemoveGuide(self): p = QgsProject() @@ -268,8 +390,11 @@ def testRemoveGuide(self): guides = l.guides() # add a guide - g1 = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), - l.pageCollection().page(0)) + g1 = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + l.pageCollection().page(0), + ) guides.addGuide(g1) self.assertEqual(guides.guides(Qt.Orientation.Horizontal), [g1]) guides.removeGuide(None) @@ -284,11 +409,17 @@ def testClear(self): guides = l.guides() # add a guide - g1 = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), - l.pageCollection().page(0)) + g1 = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + l.pageCollection().page(0), + ) guides.addGuide(g1) - g2 = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), - l.pageCollection().page(0)) + g2 = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + l.pageCollection().page(0), + ) guides.addGuide(g2) self.assertEqual(guides.guides(Qt.Orientation.Horizontal), [g1, g2]) guides.clear() @@ -299,18 +430,32 @@ def testApplyToOtherPages(self): l = QgsLayout(p) l.initializeDefaults() page2 = QgsLayoutItemPage(l) - page2.setPageSize('A6') + page2.setPageSize("A6") l.pageCollection().addPage(page2) guides = l.guides() # add some guides - g1 = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(5), l.pageCollection().page(0)) + g1 = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(5), + l.pageCollection().page(0), + ) guides.addGuide(g1) - g2 = QgsLayoutGuide(Qt.Orientation.Vertical, QgsLayoutMeasurement(6), l.pageCollection().page(0)) + g2 = QgsLayoutGuide( + Qt.Orientation.Vertical, QgsLayoutMeasurement(6), l.pageCollection().page(0) + ) guides.addGuide(g2) - g3 = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(190), l.pageCollection().page(0)) + g3 = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(190), + l.pageCollection().page(0), + ) guides.addGuide(g3) - g4 = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(1), l.pageCollection().page(1)) + g4 = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(1), + l.pageCollection().page(1), + ) guides.addGuide(g4) # apply guides from page 0 - should delete g4 @@ -321,9 +466,13 @@ def testApplyToOtherPages(self): # g3 is outside of page 2 bounds - should not be copied self.assertEqual(len(guides.guides(Qt.Orientation.Horizontal, 1)), 1) - self.assertEqual(guides.guides(Qt.Orientation.Horizontal, 1)[0].position().length(), 5) + self.assertEqual( + guides.guides(Qt.Orientation.Horizontal, 1)[0].position().length(), 5 + ) self.assertEqual(len(guides.guides(Qt.Orientation.Vertical, 1)), 1) - self.assertEqual(guides.guides(Qt.Orientation.Vertical, 1)[0].position().length(), 6) + self.assertEqual( + guides.guides(Qt.Orientation.Vertical, 1)[0].position().length(), 6 + ) # apply guides from page 1 to 0 guides.applyGuidesToAllOtherPages(1) @@ -331,9 +480,13 @@ def testApplyToOtherPages(self): self.assertTrue(sip.isdeleted(g2)) self.assertTrue(sip.isdeleted(g3)) self.assertEqual(len(guides.guides(Qt.Orientation.Horizontal, 0)), 1) - self.assertEqual(guides.guides(Qt.Orientation.Horizontal, 0)[0].position().length(), 5) + self.assertEqual( + guides.guides(Qt.Orientation.Horizontal, 0)[0].position().length(), 5 + ) self.assertEqual(len(guides.guides(Qt.Orientation.Vertical, 0)), 1) - self.assertEqual(guides.guides(Qt.Orientation.Vertical, 0)[0].position().length(), 6) + self.assertEqual( + guides.guides(Qt.Orientation.Vertical, 0)[0].position().length(), 6 + ) def testSetVisible(self): p = QgsProject() @@ -342,9 +495,15 @@ def testSetVisible(self): guides = l.guides() # add some guides - g1 = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(5), l.pageCollection().page(0)) + g1 = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(5), + l.pageCollection().page(0), + ) guides.addGuide(g1) - g2 = QgsLayoutGuide(Qt.Orientation.Vertical, QgsLayoutMeasurement(6), l.pageCollection().page(0)) + g2 = QgsLayoutGuide( + Qt.Orientation.Vertical, QgsLayoutMeasurement(6), l.pageCollection().page(0) + ) guides.addGuide(g2) guides.setVisible(False) @@ -361,10 +520,17 @@ def testReadWriteXml(self): guides = l.guides() # add some guides - g1 = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), - l.pageCollection().page(0)) + g1 = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + l.pageCollection().page(0), + ) guides.addGuide(g1) - g2 = QgsLayoutGuide(Qt.Orientation.Vertical, QgsLayoutMeasurement(6, QgsUnitTypes.LayoutUnit.LayoutInches), l.pageCollection().page(0)) + g2 = QgsLayoutGuide( + Qt.Orientation.Vertical, + QgsLayoutMeasurement(6, QgsUnitTypes.LayoutUnit.LayoutInches), + l.pageCollection().page(0), + ) guides.addGuide(g2) guides.setVisible(False) @@ -377,16 +543,22 @@ def testReadWriteXml(self): l2.initializeDefaults() guides2 = l2.guides() - self.assertTrue(guides2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext())) + self.assertTrue( + guides2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext()) + ) guide_list = guides2.guidesOnPage(0) self.assertEqual(len(guide_list), 2) self.assertEqual(guide_list[0].orientation(), Qt.Orientation.Horizontal) self.assertEqual(guide_list[0].position().length(), 5.0) - self.assertEqual(guide_list[0].position().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters) + self.assertEqual( + guide_list[0].position().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) self.assertEqual(guide_list[1].orientation(), Qt.Orientation.Vertical) self.assertEqual(guide_list[1].position().length(), 6.0) - self.assertEqual(guide_list[1].position().units(), QgsUnitTypes.LayoutUnit.LayoutInches) + self.assertEqual( + guide_list[1].position().units(), QgsUnitTypes.LayoutUnit.LayoutInches + ) def testGuideLayoutPosition(self): p = QgsProject() @@ -395,16 +567,21 @@ def testGuideLayoutPosition(self): guides = l.guides() # add some guides - g1 = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(1, QgsUnitTypes.LayoutUnit.LayoutCentimeters), - l.pageCollection().page(0)) + g1 = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(1, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + l.pageCollection().page(0), + ) guides.addGuide(g1) # set position in layout units (mm) guides.setGuideLayoutPosition(g1, 50) self.assertEqual(g1.position().length(), 5.0) - self.assertEqual(g1.position().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters) + self.assertEqual( + g1.position().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayouthtml.py b/tests/src/python/test_qgslayouthtml.py index b5d51d02086d..cf5ba4be219c 100644 --- a/tests/src/python/test_qgslayouthtml.py +++ b/tests/src/python/test_qgslayouthtml.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '20/11/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "20/11/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os @@ -17,7 +18,7 @@ QgsLayoutFrame, QgsLayoutItemHtml, QgsLayoutMultiFrame, - QgsProject + QgsProject, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -57,10 +58,7 @@ def testTable(self): layout_html.addFrame(html_frame) layout_html.setUrl(self.htmlUrl()) - result = self.render_layout_check( - 'composerhtml_table', - self.layout - ) + result = self.render_layout_check("composerhtml_table", self.layout) self.layout.removeMultiFrame(layout_html) self.assertTrue(result) @@ -71,25 +69,17 @@ def testTableMultiFrame(self): html_frame = QgsLayoutFrame(self.layout, layout_html) html_frame.attemptSetSceneRect(QRectF(10, 10, 100, 50)) layout_html.addFrame(html_frame) - layout_html.setResizeMode( - QgsLayoutMultiFrame.ResizeMode.RepeatUntilFinished) + layout_html.setResizeMode(QgsLayoutMultiFrame.ResizeMode.RepeatUntilFinished) layout_html.setUseSmartBreaks(False) layout_html.setUrl(self.htmlUrl()) layout_html.frame(0).setFrameEnabled(True) self.assertTrue( - self.render_layout_check( - 'composerhtml_multiframe1', - self.layout - ) + self.render_layout_check("composerhtml_multiframe1", self.layout) ) self.assertTrue( - self.render_layout_check( - 'composerhtml_multiframe2', - self.layout, - page=1 - ) + self.render_layout_check("composerhtml_multiframe2", self.layout, page=1) ) self.layout.removeMultiFrame(layout_html) @@ -101,25 +91,19 @@ def testHtmlSmartBreaks(self): html_frame = QgsLayoutFrame(self.layout, layout_html) html_frame.attemptSetSceneRect(QRectF(10, 10, 100, 52)) layout_html.addFrame(html_frame) - layout_html.setResizeMode( - QgsLayoutMultiFrame.ResizeMode.RepeatUntilFinished) + layout_html.setResizeMode(QgsLayoutMultiFrame.ResizeMode.RepeatUntilFinished) layout_html.setUseSmartBreaks(True) layout_html.setUrl(self.htmlUrl()) layout_html.frame(0).setFrameEnabled(True) self.assertTrue( self.render_layout_check( - 'composerhtml_smartbreaks1', - self.layout, - allowed_mismatch=200 + "composerhtml_smartbreaks1", self.layout, allowed_mismatch=200 ) ) self.assertTrue( self.render_layout_check( - 'composerhtml_smartbreaks2', - self.layout, - page=1, - allowed_mismatch=200 + "composerhtml_smartbreaks2", self.layout, page=1, allowed_mismatch=200 ) ) @@ -127,5 +111,5 @@ def testHtmlSmartBreaks(self): layout_html = None -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutitem.py b/tests/src/python/test_qgslayoutitem.py index 978e157ffa68..376e3467981c 100644 --- a/tests/src/python/test_qgslayoutitem.py +++ b/tests/src/python/test_qgslayoutitem.py @@ -5,21 +5,15 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2017 by Nyall Dawson' -__date__ = '17/01/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "(C) 2017 by Nyall Dawson" +__date__ = "17/01/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os -from qgis.PyQt.QtCore import ( - Qt, - QRectF -) -from qgis.PyQt.QtGui import ( - QColor, - QPainter, - QImage -) +from qgis.PyQt.QtCore import Qt, QRectF +from qgis.PyQt.QtGui import QColor, QPainter, QImage from qgis.PyQt.QtTest import QSignalSpy from qgis.core import ( QgsLayout, @@ -37,7 +31,7 @@ QgsFillSymbol, QgsSimpleFillSymbolLayer, QgsLayoutRenderContext, - QgsLayoutItemElevationProfile + QgsLayoutItemElevationProfile, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -50,13 +44,13 @@ class LayoutItemTestCase: - ''' - This is a collection of generic tests for QgsLayoutItem subclasses. - To make use of it, subclass it and set self.item_class to a QgsLayoutItem subclass you want to test. - ''' + """ + This is a collection of generic tests for QgsLayoutItem subclasses. + To make use of it, subclass it and set self.item_class to a QgsLayoutItem subclass you want to test. + """ def make_item(self, layout): - if hasattr(self, 'item_class'): + if hasattr(self, "item_class"): return self.item_class(layout) else: return self.createItem(layout) @@ -73,7 +67,7 @@ class TestQgsLayoutItem(QgisTestCase): @classmethod def control_path_prefix(cls): - return 'composer_effects' + return "composer_effects" def testDataDefinedFrameColor(self): layout = QgsLayout(QgsProject.instance()) @@ -85,9 +79,14 @@ def testDataDefinedFrameColor(self): self.assertEqual(item.frameStrokeColor(), QColor(255, 0, 0)) self.assertEqual(item.pen().color().name(), QColor(255, 0, 0).name()) - item.dataDefinedProperties().setProperty(QgsLayoutObject.DataDefinedProperty.FrameColor, QgsProperty.fromExpression("'blue'")) + item.dataDefinedProperties().setProperty( + QgsLayoutObject.DataDefinedProperty.FrameColor, + QgsProperty.fromExpression("'blue'"), + ) item.refreshDataDefinedProperty() - self.assertEqual(item.frameStrokeColor(), QColor(255, 0, 0)) # should not change + self.assertEqual( + item.frameStrokeColor(), QColor(255, 0, 0) + ) # should not change self.assertEqual(item.pen().color().name(), QColor(0, 0, 255).name()) def testFrameWidth(self): @@ -96,12 +95,22 @@ def testFrameWidth(self): item = QgsLayoutItemMap(layout) item.setFrameEnabled(True) - item.setFrameStrokeWidth(QgsLayoutMeasurement(10, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item.frameStrokeWidth(), QgsLayoutMeasurement(10, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item.setFrameStrokeWidth( + QgsLayoutMeasurement(10, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + self.assertEqual( + item.frameStrokeWidth(), + QgsLayoutMeasurement(10, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertEqual(item.pen().width(), 10.0) - item.setFrameStrokeWidth(QgsLayoutMeasurement(10, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - self.assertEqual(item.frameStrokeWidth(), QgsLayoutMeasurement(10, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + item.setFrameStrokeWidth( + QgsLayoutMeasurement(10, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) + self.assertEqual( + item.frameStrokeWidth(), + QgsLayoutMeasurement(10, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) self.assertEqual(item.pen().width(), 100.0) def testDataDefinedBackgroundColor(self): @@ -113,9 +122,14 @@ def testDataDefinedBackgroundColor(self): self.assertEqual(item.backgroundColor(), QColor(255, 0, 0)) self.assertEqual(item.brush().color().name(), QColor(255, 0, 0).name()) - item.dataDefinedProperties().setProperty(QgsLayoutObject.DataDefinedProperty.BackgroundColor, QgsProperty.fromExpression("'blue'")) + item.dataDefinedProperties().setProperty( + QgsLayoutObject.DataDefinedProperty.BackgroundColor, + QgsProperty.fromExpression("'blue'"), + ) item.refreshDataDefinedProperty() - self.assertEqual(item.backgroundColor(False), QColor(255, 0, 0)) # should not change + self.assertEqual( + item.backgroundColor(False), QColor(255, 0, 0) + ) # should not change self.assertEqual(item.backgroundColor(True).name(), item.brush().color().name()) self.assertEqual(item.brush().color().name(), QColor(0, 0, 255).name()) @@ -153,64 +167,78 @@ def testFrameBleed(self): item.setFrameEnabled(False) self.assertEqual(item.estimatedFrameBleed(), 0) - item.setFrameStrokeWidth(QgsLayoutMeasurement(10, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item.setFrameStrokeWidth( + QgsLayoutMeasurement(10, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) item.setFrameEnabled(False) self.assertEqual(item.estimatedFrameBleed(), 0) item.setFrameEnabled(True) self.assertEqual(item.estimatedFrameBleed(), 5) # only half bleeds out! - item.setFrameStrokeWidth(QgsLayoutMeasurement(10, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + item.setFrameStrokeWidth( + QgsLayoutMeasurement(10, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) self.assertEqual(item.estimatedFrameBleed(), 50) # only half bleeds out! def testRectWithFrame(self): layout = QgsLayout(QgsProject.instance()) item = QgsLayoutItemMap(layout) - item.attemptMove(QgsLayoutPoint(6, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item.attemptResize(QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item.attemptMove( + QgsLayoutPoint(6, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item.attemptResize( + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) item.setFrameEnabled(False) self.assertEqual(item.rectWithFrame(), QRectF(0, 0, 18, 12)) - item.setFrameStrokeWidth(QgsLayoutMeasurement(10, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item.setFrameStrokeWidth( + QgsLayoutMeasurement(10, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) item.setFrameEnabled(False) self.assertEqual(item.rectWithFrame(), QRectF(0, 0, 18, 12)) item.setFrameEnabled(True) self.assertEqual(item.rectWithFrame(), QRectF(-5.0, -5.0, 28.0, 22.0)) - item.setFrameStrokeWidth(QgsLayoutMeasurement(10, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + item.setFrameStrokeWidth( + QgsLayoutMeasurement(10, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) self.assertEqual(item.rectWithFrame(), QRectF(-50.0, -50.0, 118.0, 112.0)) def testDisplayName(self): layout = QgsLayout(QgsProject.instance()) item = QgsLayoutItemShape(layout) - self.assertEqual(item.displayName(), '') - item.setId('a') - self.assertEqual(item.displayName(), 'a') - self.assertEqual(item.id(), 'a') + self.assertEqual(item.displayName(), "") + item.setId("a") + self.assertEqual(item.displayName(), "a") + self.assertEqual(item.id(), "a") def testCasting(self): """ Test that sip correctly casts stuff """ p = QgsProject() - p.read(os.path.join(TEST_DATA_DIR, 'layouts', 'layout_casting.qgs')) + p.read(os.path.join(TEST_DATA_DIR, "layouts", "layout_casting.qgs")) layout = p.layoutManager().layouts()[0] # check a method which often fails casting - map = layout.itemById('map') + map = layout.itemById("map") self.assertIsInstance(map, QgsLayoutItemMap) - label = layout.itemById('label') + label = layout.itemById("label") self.assertIsInstance(label, QgsLayoutItemLabel) # another method -- sometimes this fails casting for different(?) reasons # make sure we start from a new project so sip hasn't remembered item instances p2 = QgsProject() - p2.read(os.path.join(TEST_DATA_DIR, 'layouts', 'layout_casting.qgs')) + p2.read(os.path.join(TEST_DATA_DIR, "layouts", "layout_casting.qgs")) layout = p2.layoutManager().layouts()[0] items = layout.items() - map2 = [i for i in items if isinstance(i, QgsLayoutItem) and i.id() == 'map'][0] + map2 = [i for i in items if isinstance(i, QgsLayoutItem) and i.id() == "map"][0] self.assertIsInstance(map2, QgsLayoutItemMap) - label2 = [i for i in items if isinstance(i, QgsLayoutItem) and i.id() == 'label'][0] + label2 = [ + i for i in items if isinstance(i, QgsLayoutItem) and i.id() == "label" + ][0] self.assertIsInstance(label2, QgsLayoutItemLabel) def testContainsAdvancedEffectsAndRasterization(self): @@ -224,11 +252,16 @@ def testContainsAdvancedEffectsAndRasterization(self): self.assertTrue(item.containsAdvancedEffects()) # but not the WHOLE layout self.assertFalse(item.requiresRasterization()) - item.dataDefinedProperties().setProperty(QgsLayoutObject.DataDefinedProperty.Opacity, QgsProperty.fromExpression('100')) + item.dataDefinedProperties().setProperty( + QgsLayoutObject.DataDefinedProperty.Opacity, + QgsProperty.fromExpression("100"), + ) item.refresh() self.assertFalse(item.containsAdvancedEffects()) self.assertFalse(item.requiresRasterization()) - item.dataDefinedProperties().setProperty(QgsLayoutObject.DataDefinedProperty.Opacity, QgsProperty()) + item.dataDefinedProperties().setProperty( + QgsLayoutObject.DataDefinedProperty.Opacity, QgsProperty() + ) item.refresh() self.assertTrue(item.containsAdvancedEffects()) self.assertFalse(item.requiresRasterization()) @@ -275,10 +308,12 @@ def test_blend_mode_rendering_designer_preview(self): item2.setBlendMode(QPainter.CompositionMode.CompositionMode_Multiply) page_item = l.pageCollection().page(0) - paper_rect = QRectF(page_item.pos().x(), - page_item.pos().y(), - page_item.rect().width(), - page_item.rect().height()) + paper_rect = QRectF( + page_item.pos().x(), + page_item.pos().y(), + page_item.rect().width(), + page_item.rect().height(), + ) im = QImage(1122, 794, QImage.Format.Format_ARGB32) im.fill(Qt.GlobalColor.transparent) @@ -287,12 +322,21 @@ def test_blend_mode_rendering_designer_preview(self): painter = QPainter(im) painter.setRenderHint(QPainter.RenderHint.Antialiasing, True) - l.render(painter, QRectF(0, 0, painter.device().width(), painter.device().height()), paper_rect) + l.render( + painter, + QRectF(0, 0, painter.device().width(), painter.device().height()), + paper_rect, + ) painter.end() - self.assertTrue(self.image_check('blend_modes_preview_mode', - 'composereffects_blend', - im, allowed_mismatch=0)) + self.assertTrue( + self.image_check( + "blend_modes_preview_mode", + "composereffects_blend", + im, + allowed_mismatch=0, + ) + ) def test_blend_mode_rendering_export(self): """ @@ -326,12 +370,7 @@ def test_blend_mode_rendering_export(self): item2.setBlendMode(QPainter.CompositionMode.CompositionMode_Multiply) - self.assertTrue( - self.render_layout_check( - "composereffects_blend", - l - ) - ) + self.assertTrue(self.render_layout_check("composereffects_blend", l)) def test_blend_mode_rendering_export_no_advanced_effects(self): """ @@ -342,7 +381,9 @@ def test_blend_mode_rendering_export_no_advanced_effects(self): """ p = QgsProject() l = QgsLayout(p) - l.renderContext().setFlag(QgsLayoutRenderContext.Flag.FlagUseAdvancedEffects, False) + l.renderContext().setFlag( + QgsLayoutRenderContext.Flag.FlagUseAdvancedEffects, False + ) l.initializeDefaults() item1 = QgsLayoutItemShape(l) @@ -370,10 +411,7 @@ def test_blend_mode_rendering_export_no_advanced_effects(self): item2.setBlendMode(QPainter.CompositionMode.CompositionMode_Multiply) self.assertTrue( - self.render_layout_check( - "composereffects_blend_no_advanced_effects", - l - ) + self.render_layout_check("composereffects_blend_no_advanced_effects", l) ) def test_blend_mode_rendering_export_force_vector(self): @@ -385,7 +423,9 @@ def test_blend_mode_rendering_export_force_vector(self): """ p = QgsProject() l = QgsLayout(p) - l.renderContext().setFlag(QgsLayoutRenderContext.Flag.FlagForceVectorOutput, True) + l.renderContext().setFlag( + QgsLayoutRenderContext.Flag.FlagForceVectorOutput, True + ) l.initializeDefaults() item1 = QgsLayoutItemShape(l) @@ -413,12 +453,9 @@ def test_blend_mode_rendering_export_force_vector(self): item2.setBlendMode(QPainter.CompositionMode.CompositionMode_Multiply) self.assertTrue( - self.render_layout_check( - "composereffects_blend_no_advanced_effects", - l - ) + self.render_layout_check("composereffects_blend_no_advanced_effects", l) ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutitemcombobox.py b/tests/src/python/test_qgslayoutitemcombobox.py index afdd68dc3d58..de2f5672fc10 100644 --- a/tests/src/python/test_qgslayoutitemcombobox.py +++ b/tests/src/python/test_qgslayoutitemcombobox.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2019 by Nyall Dawson' -__date__ = '11/03/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "(C) 2019 by Nyall Dawson" +__date__ = "11/03/2019" +__copyright__ = "Copyright 2019, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy from qgis.core import ( @@ -82,7 +83,7 @@ def testCombo(self): self.assertIsNone(combo.currentItem()) self.assertEqual(len(spy), 2) self.assertEqual(combo.currentIndex(), 0) - self.assertEqual(combo.itemText(0), '') + self.assertEqual(combo.itemText(0), "") combo.setAllowEmptyItem(False) self.assertEqual(combo.currentIndex(), -1) @@ -99,7 +100,7 @@ def testCombo(self): self.assertEqual(combo.currentIndex(), -1) label1 = QgsLayoutItemLabel(layout) - label1.setId('llll') + label1.setId("llll") # don't add to layout yet! combo.setItem(label1) self.assertIsNone(combo.currentItem()) @@ -115,7 +116,7 @@ def testCombo(self): layout.addLayoutItem(label1) self.assertEqual(combo.currentIndex(), 0) self.assertEqual(combo.count(), 1) - self.assertEqual(combo.itemText(0), 'llll') + self.assertEqual(combo.itemText(0), "llll") self.assertEqual(len(spy), 10) self.assertEqual(combo.currentLayout(), layout) self.assertEqual(combo.currentItem(), label1) @@ -134,8 +135,8 @@ def testCombo(self): combo.setAllowEmptyItem(True) self.assertEqual(combo.currentIndex(), 1) self.assertEqual(combo.count(), 2) - self.assertEqual(combo.itemText(0), '') - self.assertEqual(combo.itemText(1), 'llll') + self.assertEqual(combo.itemText(0), "") + self.assertEqual(combo.itemText(1), "llll") self.assertEqual(len(spy), 13) self.assertEqual(combo.currentLayout(), layout) self.assertEqual(combo.currentItem(), label1) @@ -153,13 +154,13 @@ def testCombo(self): self.assertEqual(combo.currentIndex(), 1) label2 = QgsLayoutItemLabel(layout) - label2.setId('mmmm') + label2.setId("mmmm") layout.addLayoutItem(label2) self.assertEqual(combo.currentIndex(), 1) self.assertEqual(combo.count(), 3) - self.assertEqual(combo.itemText(0), '') - self.assertEqual(combo.itemText(1), 'llll') - self.assertEqual(combo.itemText(2), 'mmmm') + self.assertEqual(combo.itemText(0), "") + self.assertEqual(combo.itemText(1), "llll") + self.assertEqual(combo.itemText(2), "mmmm") self.assertEqual(len(spy), 15) self.assertEqual(combo.currentLayout(), layout) self.assertEqual(combo.currentItem(), label1) @@ -177,65 +178,65 @@ def testCombo(self): self.assertEqual(len(spy), 17) self.assertEqual(combo.currentIndex(), 1) - label1.setId('nnnn') - self.assertEqual(combo.itemText(0), '') - self.assertEqual(combo.itemText(1), 'mmmm') - self.assertEqual(combo.itemText(2), 'nnnn') + label1.setId("nnnn") + self.assertEqual(combo.itemText(0), "") + self.assertEqual(combo.itemText(1), "mmmm") + self.assertEqual(combo.itemText(2), "nnnn") self.assertIsNone(combo.item(0)) self.assertEqual(combo.item(1), label2) self.assertEqual(combo.item(2), label1) self.assertEqual(combo.currentItem(), label1) combo.setAllowEmptyItem(False) - self.assertEqual(combo.itemText(0), 'mmmm') - self.assertEqual(combo.itemText(1), 'nnnn') + self.assertEqual(combo.itemText(0), "mmmm") + self.assertEqual(combo.itemText(1), "nnnn") self.assertEqual(combo.item(0), label2) self.assertEqual(combo.item(1), label1) self.assertEqual(combo.currentItem(), label1) combo.setItem(label2) - label2.setId('oooo') - self.assertEqual(combo.itemText(0), 'nnnn') - self.assertEqual(combo.itemText(1), 'oooo') + label2.setId("oooo") + self.assertEqual(combo.itemText(0), "nnnn") + self.assertEqual(combo.itemText(1), "oooo") self.assertEqual(combo.item(0), label1) self.assertEqual(combo.item(1), label2) self.assertEqual(combo.currentItem(), label2) combo.setAllowEmptyItem(True) layout.removeLayoutItem(label1) - self.assertEqual(combo.itemText(0), '') - self.assertEqual(combo.itemText(1), 'oooo') + self.assertEqual(combo.itemText(0), "") + self.assertEqual(combo.itemText(1), "oooo") self.assertIsNone(combo.item(0)) self.assertEqual(combo.item(1), label2) self.assertEqual(combo.currentItem(), label2) map = QgsLayoutItemMap(layout) layout.addLayoutItem(map) - map.setId('pppp') - self.assertEqual(combo.itemText(0), '') - self.assertEqual(combo.itemText(1), 'oooo') - self.assertEqual(combo.itemText(2), 'pppp') + map.setId("pppp") + self.assertEqual(combo.itemText(0), "") + self.assertEqual(combo.itemText(1), "oooo") + self.assertEqual(combo.itemText(2), "pppp") self.assertIsNone(combo.item(0)) self.assertEqual(combo.item(1), label2) self.assertEqual(combo.item(2), map) self.assertEqual(combo.currentItem(), label2) combo.setItemType(QgsLayoutItemRegistry.ItemType.LayoutMap) - self.assertEqual(combo.itemText(0), '') - self.assertEqual(combo.itemText(1), 'pppp') + self.assertEqual(combo.itemText(0), "") + self.assertEqual(combo.itemText(1), "pppp") self.assertIsNone(combo.item(0)) self.assertEqual(combo.item(1), map) self.assertIsNone(combo.currentItem()) combo.setItemType(QgsLayoutItemRegistry.ItemType.LayoutLabel) - self.assertEqual(combo.itemText(0), '') - self.assertEqual(combo.itemText(1), 'oooo') + self.assertEqual(combo.itemText(0), "") + self.assertEqual(combo.itemText(1), "oooo") self.assertIsNone(combo.item(0)) self.assertEqual(combo.item(1), label2) self.assertIsNone(combo.currentItem()) combo.setItemType(QgsLayoutItemRegistry.ItemType.LayoutAttributeTable) - self.assertEqual(combo.itemText(0), '') + self.assertEqual(combo.itemText(0), "") self.assertIsNone(combo.item(0)) self.assertIsNone(combo.currentItem()) @@ -249,18 +250,18 @@ def testCombo(self): combo.setItemFlags(QgsLayoutItem.Flag.FlagProvidesClipPath) self.assertEqual(combo.count(), 0) shape = QgsLayoutItemShape(layout) - shape.setId('shape 1') + shape.setId("shape 1") layout.addLayoutItem(shape) self.assertEqual(combo.count(), 1) shape2 = QgsLayoutItemShape(layout) - shape2.setId('shape 2') + shape2.setId("shape 2") layout.addLayoutItem(shape2) self.assertEqual(combo.count(), 2) - self.assertEqual(combo.itemText(0), 'shape 1') - self.assertEqual(combo.itemText(1), 'shape 2') + self.assertEqual(combo.itemText(0), "shape 1") + self.assertEqual(combo.itemText(1), "shape 2") combo.setItemFlags(QgsLayoutItem.Flags()) self.assertEqual(combo.count(), 4) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutitempropertiesdialog.py b/tests/src/python/test_qgslayoutitempropertiesdialog.py index 026abafda24e..1d5d04e3aa87 100644 --- a/tests/src/python/test_qgslayoutitempropertiesdialog.py +++ b/tests/src/python/test_qgslayoutitempropertiesdialog.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '18/07/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "18/07/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import unittest @@ -28,7 +29,7 @@ class TestQgsLayoutItemPropertiesDialog(QgisTestCase): def testGettersSetters(self): - """ test dialog getters/setters """ + """test dialog getters/setters""" dlg = QgsLayoutItemPropertiesDialog() l = QgsLayout(QgsProject.instance()) @@ -38,19 +39,29 @@ def testGettersSetters(self): dlg.setItemPosition(QgsLayoutPoint(5, 6, QgsUnitTypes.LayoutUnit.LayoutPixels)) self.assertEqual(dlg.itemPosition().x(), 5.0) self.assertEqual(dlg.itemPosition().y(), 6.0) - self.assertEqual(dlg.itemPosition().units(), QgsUnitTypes.LayoutUnit.LayoutPixels) + self.assertEqual( + dlg.itemPosition().units(), QgsUnitTypes.LayoutUnit.LayoutPixels + ) dlg.setItemSize(QgsLayoutSize(15, 16, QgsUnitTypes.LayoutUnit.LayoutInches)) self.assertEqual(dlg.itemSize().width(), 15.0) self.assertEqual(dlg.itemSize().height(), 16.0) self.assertEqual(dlg.itemSize().units(), QgsUnitTypes.LayoutUnit.LayoutInches) - for p in [QgsLayoutItem.ReferencePoint.UpperLeft, QgsLayoutItem.ReferencePoint.UpperMiddle, QgsLayoutItem.ReferencePoint.UpperRight, - QgsLayoutItem.ReferencePoint.MiddleLeft, QgsLayoutItem.ReferencePoint.Middle, QgsLayoutItem.ReferencePoint.MiddleRight, - QgsLayoutItem.ReferencePoint.LowerLeft, QgsLayoutItem.ReferencePoint.LowerMiddle, QgsLayoutItem.ReferencePoint.LowerRight]: + for p in [ + QgsLayoutItem.ReferencePoint.UpperLeft, + QgsLayoutItem.ReferencePoint.UpperMiddle, + QgsLayoutItem.ReferencePoint.UpperRight, + QgsLayoutItem.ReferencePoint.MiddleLeft, + QgsLayoutItem.ReferencePoint.Middle, + QgsLayoutItem.ReferencePoint.MiddleRight, + QgsLayoutItem.ReferencePoint.LowerLeft, + QgsLayoutItem.ReferencePoint.LowerMiddle, + QgsLayoutItem.ReferencePoint.LowerRight, + ]: dlg.setReferencePoint(p) self.assertEqual(dlg.referencePoint(), p) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutlabel.py b/tests/src/python/test_qgslayoutlabel.py index 8763444faabb..932df5219851 100644 --- a/tests/src/python/test_qgslayoutlabel.py +++ b/tests/src/python/test_qgslayoutlabel.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2017 by Nyall Dawson' -__date__ = '23/10/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "(C) 2017 by Nyall Dawson" +__date__ = "23/10/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, QFileInfo from qgis.PyQt.QtTest import QSignalSpy @@ -32,13 +33,15 @@ class TestQgsLayoutItemLabel(QgisTestCase, LayoutItemTestCase): @classmethod def setUpClass(cls): - super(TestQgsLayoutItemLabel, cls).setUpClass() + super().setUpClass() cls.item_class = QgsLayoutItemLabel def testCase(self): TEST_DATA_DIR = unitTestDataPath() vectorFileInfo = QFileInfo(TEST_DATA_DIR + "/france_parts.shp") - mVectorLayer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") + mVectorLayer = QgsVectorLayer( + vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr" + ) QgsProject.instance().addMapLayers([mVectorLayer]) @@ -55,7 +58,9 @@ def testCase(self): def evaluation_test(self, layout, label): # $CURRENT_DATE evaluation label.setText("__$CURRENT_DATE__") - self.assertEqual(label.currentText(), ("__" + QDate.currentDate().toString() + "__")) + self.assertEqual( + label.currentText(), ("__" + QDate.currentDate().toString() + "__") + ) # $CURRENT_DATE() evaluation label.setText("__$CURRENT_DATE(dd)(ok)__") @@ -87,7 +92,7 @@ def feature_evaluation_test(self, layout, label, mVectorLayer): def page_evaluation_test(self, layout, label, mVectorLayer): page = QgsLayoutItemPage(layout) - page.setPageSize('A4') + page.setPageSize("A4") layout.pageCollection().addPage(page) label.setText("[%@layout_page||'/'||@layout_numpages%]") self.assertEqual(label.currentText(), "1/2") @@ -102,27 +107,29 @@ def test_convert_to_static(self): label = QgsLayoutItemLabel(layout) layout.addLayoutItem(label) - layout.setName('my layout') + layout.setName("my layout") # no text yet label.convertToStaticText() self.assertFalse(label.text()) spy = QSignalSpy(label.changed) - label.setText('already static text') + label.setText("already static text") self.assertEqual(len(spy), 1) label.convertToStaticText() - self.assertEqual(label.text(), 'already static text') + self.assertEqual(label.text(), "already static text") self.assertEqual(len(spy), 1) - label.setText('with [% 1+2+3 %] some [% @layout_name %] dynamic bits') + label.setText("with [% 1+2+3 %] some [% @layout_name %] dynamic bits") self.assertEqual(len(spy), 2) - self.assertEqual(label.text(), 'with [% 1+2+3 %] some [% @layout_name %] dynamic bits') + self.assertEqual( + label.text(), "with [% 1+2+3 %] some [% @layout_name %] dynamic bits" + ) label.convertToStaticText() - self.assertEqual(label.text(), 'with 6 some my layout dynamic bits') + self.assertEqual(label.text(), "with 6 some my layout dynamic bits") self.assertEqual(len(spy), 3) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutlegend.py b/tests/src/python/test_qgslayoutlegend.py index 953fa8742b05..ddfe530baed9 100644 --- a/tests/src/python/test_qgslayoutlegend.py +++ b/tests/src/python/test_qgslayoutlegend.py @@ -5,22 +5,16 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2017 by Nyall Dawson' -__date__ = '24/10/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "(C) 2017 by Nyall Dawson" +__date__ = "24/10/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os from time import sleep -from qgis.PyQt.QtCore import ( - Qt, - QRectF -) -from qgis.PyQt.QtGui import ( - QColor, - QImage, - QPainter -) +from qgis.PyQt.QtCore import Qt, QRectF +from qgis.PyQt.QtGui import QColor, QImage, QPainter from qgis.PyQt.QtXml import QDomDocument from qgis.core import ( @@ -60,7 +54,7 @@ QgsTextFormat, QgsFeatureRequest, QgsLayoutItemShape, - QgsSimpleFillSymbolLayer + QgsSimpleFillSymbolLayer, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -76,7 +70,7 @@ class TestQgsLayoutItemLegend(QgisTestCase, LayoutItemTestCase): @classmethod def setUpClass(cls): - super(TestQgsLayoutItemLegend, cls).setUpClass() + super().setUpClass() cls.item_class = QgsLayoutItemLegend @classmethod @@ -102,24 +96,23 @@ def test_opacity(self): text_format.setFont(QgsFontUtils.getStandardTestFont("Bold")) text_format.setSize(16) - for legend_item in [QgsLegendStyle.Style.Title, QgsLegendStyle.Style.Group, QgsLegendStyle.Style.Subgroup, - QgsLegendStyle.Style.Symbol, QgsLegendStyle.Style.SymbolLabel]: + for legend_item in [ + QgsLegendStyle.Style.Title, + QgsLegendStyle.Style.Group, + QgsLegendStyle.Style.Subgroup, + QgsLegendStyle.Style.Symbol, + QgsLegendStyle.Style.SymbolLabel, + ]: style = legend.style(legend_item) style.setTextFormat(text_format) legend.setStyle(legend_item, style) legend.setItemOpacity(0.3) - self.assertFalse( - legend.requiresRasterization() - ) - self.assertTrue( - legend.containsAdvancedEffects() - ) + self.assertFalse(legend.requiresRasterization()) + self.assertTrue(legend.containsAdvancedEffects()) - self.assertTrue( - self.render_layout_check('composerlegend_opacity', layout) - ) + self.assertTrue(self.render_layout_check("composerlegend_opacity", layout)) def test_opacity_rendering_designer_preview(self): """ @@ -142,8 +135,13 @@ def test_opacity_rendering_designer_preview(self): text_format.setFont(QgsFontUtils.getStandardTestFont("Bold")) text_format.setSize(16) - for legend_item in [QgsLegendStyle.Style.Title, QgsLegendStyle.Style.Group, QgsLegendStyle.Style.Subgroup, - QgsLegendStyle.Style.Symbol, QgsLegendStyle.Style.SymbolLabel]: + for legend_item in [ + QgsLegendStyle.Style.Title, + QgsLegendStyle.Style.Group, + QgsLegendStyle.Style.Subgroup, + QgsLegendStyle.Style.Symbol, + QgsLegendStyle.Style.SymbolLabel, + ]: style = legend.style(legend_item) style.setTextFormat(text_format) legend.setStyle(legend_item, style) @@ -151,10 +149,12 @@ def test_opacity_rendering_designer_preview(self): legend.setItemOpacity(0.3) page_item = l.pageCollection().page(0) - paper_rect = QRectF(page_item.pos().x(), - page_item.pos().y(), - page_item.rect().width(), - page_item.rect().height()) + paper_rect = QRectF( + page_item.pos().x(), + page_item.pos().y(), + page_item.rect().width(), + page_item.rect().height(), + ) im = QImage(1122, 794, QImage.Format.Format_ARGB32) im.fill(Qt.GlobalColor.transparent) @@ -163,12 +163,21 @@ def test_opacity_rendering_designer_preview(self): painter = QPainter(im) painter.setRenderHint(QPainter.RenderHint.Antialiasing, True) - l.render(painter, QRectF(0, 0, painter.device().width(), painter.device().height()), paper_rect) + l.render( + painter, + QRectF(0, 0, painter.device().width(), painter.device().height()), + paper_rect, + ) painter.end() - self.assertTrue(self.image_check('composerlegend_opacity', - 'composerlegend_opacity', - im, allowed_mismatch=0)) + self.assertTrue( + self.image_check( + "composerlegend_opacity", + "composerlegend_opacity", + im, + allowed_mismatch=0, + ) + ) def test_blend_mode(self): """ @@ -285,7 +294,10 @@ def test_blend_mode_designer_preview(self): self.assertTrue( self.image_check( - "composerlegend_blendmode", "composerlegend_blendmode", im, allowed_mismatch=0 + "composerlegend_blendmode", + "composerlegend_blendmode", + im, + allowed_mismatch=0, ) ) @@ -295,13 +307,19 @@ def testInitialSizeSymbolMapUnits(self): """ QgsProject.instance().removeAllMapLayers() - point_path = os.path.join(TEST_DATA_DIR, 'points.shp') - point_layer = QgsVectorLayer(point_path, 'points', 'ogr') + point_path = os.path.join(TEST_DATA_DIR, "points.shp") + point_layer = QgsVectorLayer(point_path, "points", "ogr") QgsProject.instance().clear() QgsProject.instance().addMapLayers([point_layer]) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#ff0000', 'outline_style': 'no', 'size': '5', 'size_unit': 'MapUnit'}) + { + "color": "#ff0000", + "outline_style": "no", + "size": "5", + "size_unit": "MapUnit", + } + ) point_layer.setRenderer(QgsSingleSymbolRenderer(marker_symbol)) @@ -323,15 +341,11 @@ def testInitialSizeSymbolMapUnits(self): legend.setFrameEnabled(True) legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundColor(QColor(200, 200, 200)) - legend.setTitle('') + legend.setTitle("") layout.addLayoutItem(legend) legend.setLinkedMap(map) - self.assertTrue( - self.render_layout_check( - 'composer_legend_mapunits', layout - ) - ) + self.assertTrue(self.render_layout_check("composer_legend_mapunits", layout)) # resize with non-top-left reference point legend.setResizeToContents(False) @@ -357,8 +371,8 @@ def testResizeWithMapContent(self): """ Test legend resizes to match map content """ - point_path = os.path.join(TEST_DATA_DIR, 'points.shp') - point_layer = QgsVectorLayer(point_path, 'points', 'ogr') + point_path = os.path.join(TEST_DATA_DIR, "points.shp") + point_layer = QgsVectorLayer(point_path, "points", "ogr") QgsProject.instance().addMapLayers([point_layer]) s = QgsMapSettings() @@ -379,23 +393,32 @@ def testResizeWithMapContent(self): legend.setFrameEnabled(True) legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundColor(QColor(200, 200, 200)) - legend.setTitle('') + legend.setTitle("") legend.setLegendFilterByMapEnabled(True) layout.addLayoutItem(legend) legend.setLinkedMap(map) - legend.setStyleFont(QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.SymbolLabel, QgsFontUtils.getStandardTestFont('Bold', 16)) + legend.setStyleFont( + QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.SymbolLabel, + QgsFontUtils.getStandardTestFont("Bold", 16), + ) map.setExtent(QgsRectangle(-102.51, 41.16, -102.36, 41.30)) self.assertTrue( - self.render_layout_check( - 'composer_legend_size_content', layout - ) + self.render_layout_check("composer_legend_size_content", layout) ) QgsProject.instance().removeMapLayers([point_layer.id()]) @@ -404,12 +427,14 @@ def testResizeWithMapContentNoDoublePaint(self): """ Test legend resizes to match map content """ - poly_path = os.path.join(TEST_DATA_DIR, 'polys.shp') - poly_layer = QgsVectorLayer(poly_path, 'polys', 'ogr') + poly_path = os.path.join(TEST_DATA_DIR, "polys.shp") + poly_layer = QgsVectorLayer(poly_path, "polys", "ogr") p = QgsProject() p.addMapLayers([poly_layer]) - fill_symbol = QgsFillSymbol.createSimple({'color': '255,0,0,125', 'outline_style': 'no'}) + fill_symbol = QgsFillSymbol.createSimple( + {"color": "255,0,0,125", "outline_style": "no"} + ) poly_layer.setRenderer(QgsSingleSymbolRenderer(fill_symbol)) s = QgsMapSettings() @@ -430,7 +455,7 @@ def testResizeWithMapContentNoDoublePaint(self): legend.setFrameEnabled(True) legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundEnabled(False) - legend.setTitle('') + legend.setTitle("") layout.addLayoutItem(legend) legend.setLinkedMap(map) @@ -438,7 +463,7 @@ def testResizeWithMapContentNoDoublePaint(self): self.assertTrue( self.render_layout_check( - 'composer_legend_size_content_no_double_paint', layout + "composer_legend_size_content_no_double_paint", layout ) ) @@ -446,20 +471,24 @@ def test_private_layers(self): """ Test legend does not contain private layers by default """ - point_path = os.path.join(TEST_DATA_DIR, 'points.shp') - point_layer1 = QgsVectorLayer(point_path, 'points 1', 'ogr') - point_layer2 = QgsVectorLayer(point_path, 'points 2', 'ogr') + point_path = os.path.join(TEST_DATA_DIR, "points.shp") + point_layer1 = QgsVectorLayer(point_path, "points 1", "ogr") + point_layer2 = QgsVectorLayer(point_path, "points 2", "ogr") point_layer2.setFlags(QgsMapLayer.LayerFlag.Private) p = QgsProject() p.addMapLayers([point_layer1, point_layer2]) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#ff0000', 'outline_style': 'no', 'size': '5', 'size_unit': 'MapUnit'}) + { + "color": "#ff0000", + "outline_style": "no", + "size": "5", + "size_unit": "MapUnit", + } + ) - point_layer1.setRenderer( - QgsSingleSymbolRenderer(marker_symbol.clone())) - point_layer2.setRenderer( - QgsSingleSymbolRenderer(marker_symbol.clone())) + point_layer1.setRenderer(QgsSingleSymbolRenderer(marker_symbol.clone())) + point_layer2.setRenderer(QgsSingleSymbolRenderer(marker_symbol.clone())) layout = QgsLayout(p) layout.initializeDefaults() @@ -470,27 +499,36 @@ def test_private_layers(self): legend.setFrameEnabled(True) legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundColor(QColor(200, 200, 200)) - legend.setTitle('') + legend.setTitle("") layout.addLayoutItem(legend) - legend.setStyleFont(QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.SymbolLabel, QgsFontUtils.getStandardTestFont('Bold', 16)) + legend.setStyleFont( + QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.SymbolLabel, + QgsFontUtils.getStandardTestFont("Bold", 16), + ) self.assertTrue( - self.render_layout_check( - 'composer_legend_private_layers', layout - ) + self.render_layout_check("composer_legend_private_layers", layout) ) def testResizeDisabled(self): """ Test that test legend does not resize if auto size is disabled """ - point_path = os.path.join(TEST_DATA_DIR, 'points.shp') - point_layer = QgsVectorLayer(point_path, 'points', 'ogr') + point_path = os.path.join(TEST_DATA_DIR, "points.shp") + point_layer = QgsVectorLayer(point_path, "points", "ogr") QgsProject.instance().addMapLayers([point_layer]) s = QgsMapSettings() @@ -511,14 +549,25 @@ def testResizeDisabled(self): legend.setFrameEnabled(True) legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundColor(QColor(200, 200, 200)) - legend.setTitle('') + legend.setTitle("") legend.setLegendFilterByMapEnabled(True) - legend.setStyleFont(QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.SymbolLabel, QgsFontUtils.getStandardTestFont('Bold', 16)) + legend.setStyleFont( + QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.SymbolLabel, + QgsFontUtils.getStandardTestFont("Bold", 16), + ) # disable auto resizing legend.setResizeToContents(False) @@ -528,11 +577,7 @@ def testResizeDisabled(self): map.setExtent(QgsRectangle(-102.51, 41.16, -102.36, 41.30)) - self.assertTrue( - self.render_layout_check( - 'composer_legend_noresize', layout - ) - ) + self.assertTrue(self.render_layout_check("composer_legend_noresize", layout)) QgsProject.instance().removeMapLayers([point_layer.id()]) @@ -541,8 +586,8 @@ def testResizeDisabledCrop(self): Test that if legend resizing is disabled, and legend is too small, then content is cropped """ - point_path = os.path.join(TEST_DATA_DIR, 'points.shp') - point_layer = QgsVectorLayer(point_path, 'points', 'ogr') + point_path = os.path.join(TEST_DATA_DIR, "points.shp") + point_layer = QgsVectorLayer(point_path, "points", "ogr") QgsProject.instance().addMapLayers([point_layer]) s = QgsMapSettings() @@ -563,14 +608,25 @@ def testResizeDisabledCrop(self): legend.setFrameEnabled(True) legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundColor(QColor(200, 200, 200)) - legend.setTitle('') + legend.setTitle("") legend.setLegendFilterByMapEnabled(True) - legend.setStyleFont(QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.SymbolLabel, QgsFontUtils.getStandardTestFont('Bold', 16)) + legend.setStyleFont( + QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.SymbolLabel, + QgsFontUtils.getStandardTestFont("Bold", 16), + ) # disable auto resizing legend.setResizeToContents(False) @@ -581,9 +637,7 @@ def testResizeDisabledCrop(self): map.setExtent(QgsRectangle(-102.51, 41.16, -102.36, 41.30)) self.assertTrue( - self.render_layout_check( - 'composer_legend_noresize_crop', layout - ) + self.render_layout_check("composer_legend_noresize_crop", layout) ) QgsProject.instance().removeMapLayers([point_layer.id()]) @@ -595,14 +649,17 @@ def testDataDefinedTitle(self): legend = QgsLayoutItemLegend(layout) layout.addLayoutItem(legend) - legend.setTitle('original') - self.assertEqual(legend.title(), 'original') - self.assertEqual(legend.legendSettings().title(), 'original') + legend.setTitle("original") + self.assertEqual(legend.title(), "original") + self.assertEqual(legend.legendSettings().title(), "original") - legend.dataDefinedProperties().setProperty(QgsLayoutObject.DataDefinedProperty.LegendTitle, QgsProperty.fromExpression("'new'")) + legend.dataDefinedProperties().setProperty( + QgsLayoutObject.DataDefinedProperty.LegendTitle, + QgsProperty.fromExpression("'new'"), + ) legend.refreshDataDefinedProperty() - self.assertEqual(legend.title(), 'original') - self.assertEqual(legend.legendSettings().title(), 'new') + self.assertEqual(legend.title(), "original") + self.assertEqual(legend.legendSettings().title(), "new") def testDataDefinedColumnCount(self): layout = QgsLayout(QgsProject.instance()) @@ -616,7 +673,10 @@ def testDataDefinedColumnCount(self): self.assertEqual(legend.columnCount(), 2) self.assertEqual(legend.legendSettings().columnCount(), 2) - legend.dataDefinedProperties().setProperty(QgsLayoutObject.DataDefinedProperty.LegendColumnCount, QgsProperty.fromExpression("5")) + legend.dataDefinedProperties().setProperty( + QgsLayoutObject.DataDefinedProperty.LegendColumnCount, + QgsProperty.fromExpression("5"), + ) legend.refreshDataDefinedProperty() self.assertEqual(legend.columnCount(), 2) self.assertEqual(legend.legendSettings().columnCount(), 5) @@ -630,7 +690,7 @@ def testLegendScopeVariables(self): layout.addLayoutItem(legend) legend.setColumnCount(2) - legend.setWrapString('d') + legend.setWrapString("d") legend.setLegendFilterOutAtlas(True) expc = legend.createExpressionContext() @@ -639,7 +699,7 @@ def testLegendScopeVariables(self): exp2 = QgsExpression("@legend_column_count") self.assertEqual(exp2.evaluate(expc), 2) exp3 = QgsExpression("@legend_wrap_string") - self.assertEqual(exp3.evaluate(expc), 'd') + self.assertEqual(exp3.evaluate(expc), "d") exp4 = QgsExpression("@legend_split_layers") self.assertEqual(exp4.evaluate(expc), False) exp5 = QgsExpression("@legend_filter_out_atlas") @@ -660,10 +720,10 @@ def testExpressionInText(self): """ Test expressions embedded in legend node text """ - point_path = os.path.join(TEST_DATA_DIR, 'points.shp') - point_layer = QgsVectorLayer(point_path, 'points', 'ogr') + point_path = os.path.join(TEST_DATA_DIR, "points.shp") + point_layer = QgsVectorLayer(point_path, "points", "ogr") layout = QgsPrintLayout(QgsProject.instance()) - layout.setName('LAYOUT') + layout.setName("LAYOUT") layout.initializeDefaults() map = QgsLayoutItemMap(layout) @@ -679,13 +739,24 @@ def testExpressionInText(self): legend.setFrameEnabled(True) legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundColor(QColor(200, 200, 200)) - legend.setTitle('') + legend.setTitle("") legend.setLegendFilterByMapEnabled(False) - legend.setStyleFont(QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.SymbolLabel, QgsFontUtils.getStandardTestFont('Bold', 16)) + legend.setStyleFont( + QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.SymbolLabel, + QgsFontUtils.getStandardTestFont("Bold", 16), + ) legend.setAutoUpdateModel(False) @@ -693,25 +764,26 @@ def testExpressionInText(self): s = QgsMapSettings() s.setLayers([point_layer]) - group = legend.model().rootGroup().addGroup("Group [% 1 + 5 %] [% @layout_name %]") + group = ( + legend.model().rootGroup().addGroup("Group [% 1 + 5 %] [% @layout_name %]") + ) layer_tree_layer = group.addLayer(point_layer) - layer_tree_layer.setCustomProperty("legend/title-label", - 'bbbb [% 1+2 %] xx [% @layout_name %] [% @layer_name %]') - QgsMapLayerLegendUtils.setLegendNodeUserLabel(layer_tree_layer, 0, 'xxxx') + layer_tree_layer.setCustomProperty( + "legend/title-label", + "bbbb [% 1+2 %] xx [% @layout_name %] [% @layer_name %]", + ) + QgsMapLayerLegendUtils.setLegendNodeUserLabel(layer_tree_layer, 0, "xxxx") legend.model().refreshLayerLegend(layer_tree_layer) legend.model().layerLegendNodes(layer_tree_layer)[0].setUserLabel( - 'bbbb [% 1+2 %] xx [% @layout_name %] [% @layer_name %]') + "bbbb [% 1+2 %] xx [% @layout_name %] [% @layer_name %]" + ) layout.addLayoutItem(legend) legend.setLinkedMap(map) map.setExtent(QgsRectangle(-102.51, 41.16, -102.36, 41.30)) - self.assertTrue( - self.render_layout_check( - 'composer_legend_expressions', layout - ) - ) + self.assertTrue(self.render_layout_check("composer_legend_expressions", layout)) QgsProject.instance().removeMapLayers([point_layer.id()]) @@ -720,8 +792,8 @@ def testSymbolExpressions(self): Test expressions embedded in legend node text """ QgsProject.instance().clear() - point_path = os.path.join(TEST_DATA_DIR, 'points.shp') - point_layer = QgsVectorLayer(point_path, 'points', 'ogr') + point_path = os.path.join(TEST_DATA_DIR, "points.shp") + point_layer = QgsVectorLayer(point_path, "points", "ogr") layout = QgsPrintLayout(QgsProject.instance()) layout.initializeDefaults() @@ -740,13 +812,13 @@ def testSymbolExpressions(self): counterTask.waitForFinished() legend.model().refreshLayerLegend(legendlayer) legendnodes = legend.model().layerLegendNodes(legendlayer) - legendnodes[0].setUserLabel('[% @symbol_id %]') - legendnodes[1].setUserLabel('[% @symbol_count %]') + legendnodes[0].setUserLabel("[% @symbol_id %]") + legendnodes[1].setUserLabel("[% @symbol_count %]") legendnodes[2].setUserLabel('[% sum("Pilots") %]') label1 = legendnodes[0].evaluateLabel() label2 = legendnodes[1].evaluateLabel() label3 = legendnodes[2].evaluateLabel() - self.assertEqual(label1, '0') + self.assertEqual(label1, "0") # self.assertEqual(label2, '5') # self.assertEqual(label3, '12') @@ -756,7 +828,7 @@ def testSymbolExpressions(self): label2 = legendnodes[1].evaluateLabel() label3 = legendnodes[2].evaluateLabel() - self.assertEqual(label1, ' @symbol_id 0') + self.assertEqual(label1, " @symbol_id 0") # self.assertEqual(label2, '@symbol_count 1') # self.assertEqual(label3, 'sum("Pilots") 2') @@ -766,10 +838,10 @@ def testSymbolExpressionRender(self): """ Test expressions embedded in legend node text """ - point_path = os.path.join(TEST_DATA_DIR, 'points.shp') - point_layer = QgsVectorLayer(point_path, 'points', 'ogr') + point_path = os.path.join(TEST_DATA_DIR, "points.shp") + point_layer = QgsVectorLayer(point_path, "points", "ogr") layout = QgsPrintLayout(QgsProject.instance()) - layout.setName('LAYOUT') + layout.setName("LAYOUT") layout.initializeDefaults() map = QgsLayoutItemMap(layout) @@ -785,13 +857,24 @@ def testSymbolExpressionRender(self): legend.setFrameEnabled(True) legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundColor(QColor(200, 200, 200)) - legend.setTitle('') + legend.setTitle("") legend.setLegendFilterByMapEnabled(False) - legend.setStyleFont(QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.SymbolLabel, QgsFontUtils.getStandardTestFont('Bold', 16)) + legend.setStyleFont( + QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.SymbolLabel, + QgsFontUtils.getStandardTestFont("Bold", 16), + ) legend.setAutoUpdateModel(False) @@ -799,34 +882,42 @@ def testSymbolExpressionRender(self): s = QgsMapSettings() s.setLayers([point_layer]) - group = legend.model().rootGroup().addGroup("Group [% 1 + 5 %] [% @layout_name %]") + group = ( + legend.model().rootGroup().addGroup("Group [% 1 + 5 %] [% @layout_name %]") + ) layer_tree_layer = group.addLayer(point_layer) counterTask = point_layer.countSymbolFeatures() counterTask.waitForFinished() - layer_tree_layer.setCustomProperty("legend/title-label", - 'bbbb [% 1+2 %] xx [% @layout_name %] [% @layer_name %]') - QgsMapLayerLegendUtils.setLegendNodeUserLabel(layer_tree_layer, 0, 'xxxx') + layer_tree_layer.setCustomProperty( + "legend/title-label", + "bbbb [% 1+2 %] xx [% @layout_name %] [% @layer_name %]", + ) + QgsMapLayerLegendUtils.setLegendNodeUserLabel(layer_tree_layer, 0, "xxxx") legend.model().refreshLayerLegend(layer_tree_layer) - layer_tree_layer.setLabelExpression('Concat(@symbol_id, @symbol_label, count("Class"))') - legend.model().layerLegendNodes(layer_tree_layer)[0].setUserLabel(' sym 1') - legend.model().layerLegendNodes(layer_tree_layer)[1].setUserLabel('[%@symbol_count %]') - legend.model().layerLegendNodes(layer_tree_layer)[2].setUserLabel('[% count("Class") %]') + layer_tree_layer.setLabelExpression( + 'Concat(@symbol_id, @symbol_label, count("Class"))' + ) + legend.model().layerLegendNodes(layer_tree_layer)[0].setUserLabel(" sym 1") + legend.model().layerLegendNodes(layer_tree_layer)[1].setUserLabel( + "[%@symbol_count %]" + ) + legend.model().layerLegendNodes(layer_tree_layer)[2].setUserLabel( + '[% count("Class") %]' + ) layout.addLayoutItem(legend) legend.setLinkedMap(map) legend.updateLegend() map.setExtent(QgsRectangle(-102.51, 41.16, -102.36, 41.30)) self.assertTrue( - self.render_layout_check( - 'composer_legend_symbol_expression', layout - ) + self.render_layout_check("composer_legend_symbol_expression", layout) ) QgsProject.instance().removeMapLayers([point_layer.id()]) def testThemes(self): layout = QgsPrintLayout(QgsProject.instance()) - layout.setName('LAYOUT') + layout.setName("LAYOUT") map = QgsLayoutItemMap(layout) layout.addLayoutItem(map) @@ -836,22 +927,22 @@ def testThemes(self): legend.setLinkedMap(map) self.assertFalse(legend.themeName()) - map.setFollowVisibilityPresetName('theme1') + map.setFollowVisibilityPresetName("theme1") map.setFollowVisibilityPreset(True) - self.assertEqual(legend.themeName(), 'theme1') - map.setFollowVisibilityPresetName('theme2') - self.assertEqual(legend.themeName(), 'theme2') + self.assertEqual(legend.themeName(), "theme1") + map.setFollowVisibilityPresetName("theme2") + self.assertEqual(legend.themeName(), "theme2") map.setFollowVisibilityPreset(False) self.assertFalse(legend.themeName()) # with theme set before linking map map2 = QgsLayoutItemMap(layout) - map2.setFollowVisibilityPresetName('theme3') + map2.setFollowVisibilityPresetName("theme3") map2.setFollowVisibilityPreset(True) legend.setLinkedMap(map2) - self.assertEqual(legend.themeName(), 'theme3') - map2.setFollowVisibilityPresetName('theme2') - self.assertEqual(legend.themeName(), 'theme2') + self.assertEqual(legend.themeName(), "theme3") + map2.setFollowVisibilityPresetName("theme2") + self.assertEqual(legend.themeName(), "theme2") # replace with map with no theme map3 = QgsLayoutItemMap(layout) @@ -864,59 +955,79 @@ def testLegendRenderWithMapTheme(self): """ QgsProject.instance().removeAllMapLayers() - point_path = os.path.join(TEST_DATA_DIR, 'points.shp') - point_layer = QgsVectorLayer(point_path, 'points', 'ogr') - line_path = os.path.join(TEST_DATA_DIR, 'lines.shp') - line_layer = QgsVectorLayer(line_path, 'lines', 'ogr') + point_path = os.path.join(TEST_DATA_DIR, "points.shp") + point_layer = QgsVectorLayer(point_path, "points", "ogr") + line_path = os.path.join(TEST_DATA_DIR, "lines.shp") + line_layer = QgsVectorLayer(line_path, "lines", "ogr") QgsProject.instance().clear() QgsProject.instance().addMapLayers([point_layer, line_layer]) - marker_symbol = QgsMarkerSymbol.createSimple({'color': '#ff0000', 'outline_style': 'no', 'size': '5'}) + marker_symbol = QgsMarkerSymbol.createSimple( + {"color": "#ff0000", "outline_style": "no", "size": "5"} + ) point_layer.setRenderer(QgsSingleSymbolRenderer(marker_symbol)) point_layer.styleManager().addStyleFromLayer("red") - line_symbol = QgsLineSymbol.createSimple({'color': '#ff0000', 'line_width': '2'}) + line_symbol = QgsLineSymbol.createSimple( + {"color": "#ff0000", "line_width": "2"} + ) line_layer.setRenderer(QgsSingleSymbolRenderer(line_symbol)) line_layer.styleManager().addStyleFromLayer("red") red_record = QgsMapThemeCollection.MapThemeRecord() point_red_record = QgsMapThemeCollection.MapThemeLayerRecord(point_layer) point_red_record.usingCurrentStyle = True - point_red_record.currentStyle = 'red' + point_red_record.currentStyle = "red" red_record.addLayerRecord(point_red_record) line_red_record = QgsMapThemeCollection.MapThemeLayerRecord(line_layer) line_red_record.usingCurrentStyle = True - line_red_record.currentStyle = 'red' + line_red_record.currentStyle = "red" red_record.addLayerRecord(line_red_record) - QgsProject.instance().mapThemeCollection().insert('red', red_record) + QgsProject.instance().mapThemeCollection().insert("red", red_record) - marker_symbol1 = QgsMarkerSymbol.createSimple({'color': '#0000ff', 'outline_style': 'no', 'size': '5'}) + marker_symbol1 = QgsMarkerSymbol.createSimple( + {"color": "#0000ff", "outline_style": "no", "size": "5"} + ) marker_symbol2 = QgsMarkerSymbol.createSimple( - {'color': '#0000ff', 'name': 'diamond', 'outline_style': 'no', 'size': '5'}) + {"color": "#0000ff", "name": "diamond", "outline_style": "no", "size": "5"} + ) marker_symbol3 = QgsMarkerSymbol.createSimple( - {'color': '#0000ff', 'name': 'rectangle', 'outline_style': 'no', 'size': '5'}) + { + "color": "#0000ff", + "name": "rectangle", + "outline_style": "no", + "size": "5", + } + ) - point_layer.setRenderer(QgsCategorizedSymbolRenderer('Class', [QgsRendererCategory('B52', marker_symbol1, ''), - QgsRendererCategory('Biplane', marker_symbol2, - ''), - QgsRendererCategory('Jet', marker_symbol3, ''), - ])) + point_layer.setRenderer( + QgsCategorizedSymbolRenderer( + "Class", + [ + QgsRendererCategory("B52", marker_symbol1, ""), + QgsRendererCategory("Biplane", marker_symbol2, ""), + QgsRendererCategory("Jet", marker_symbol3, ""), + ], + ) + ) point_layer.styleManager().addStyleFromLayer("blue") - line_symbol = QgsLineSymbol.createSimple({'color': '#0000ff', 'line_width': '2'}) + line_symbol = QgsLineSymbol.createSimple( + {"color": "#0000ff", "line_width": "2"} + ) line_layer.setRenderer(QgsSingleSymbolRenderer(line_symbol)) line_layer.styleManager().addStyleFromLayer("blue") blue_record = QgsMapThemeCollection.MapThemeRecord() point_blue_record = QgsMapThemeCollection.MapThemeLayerRecord(point_layer) point_blue_record.usingCurrentStyle = True - point_blue_record.currentStyle = 'blue' + point_blue_record.currentStyle = "blue" blue_record.addLayerRecord(point_blue_record) line_blue_record = QgsMapThemeCollection.MapThemeLayerRecord(line_layer) line_blue_record.usingCurrentStyle = True - line_blue_record.currentStyle = 'blue' + line_blue_record.currentStyle = "blue" blue_record.addLayerRecord(line_blue_record) - QgsProject.instance().mapThemeCollection().insert('blue', blue_record) + QgsProject.instance().mapThemeCollection().insert("blue", blue_record) layout = QgsLayout(QgsProject.instance()) layout.initializeDefaults() @@ -928,7 +1039,7 @@ def testLegendRenderWithMapTheme(self): layout.addLayoutItem(map1) map1.setExtent(point_layer.extent()) map1.setFollowVisibilityPreset(True) - map1.setFollowVisibilityPresetName('red') + map1.setFollowVisibilityPresetName("red") map2 = QgsLayoutItemMap(layout) map2.attemptSetSceneRect(QRectF(20, 120, 80, 80)) @@ -937,7 +1048,7 @@ def testLegendRenderWithMapTheme(self): layout.addLayoutItem(map2) map2.setExtent(point_layer.extent()) map2.setFollowVisibilityPreset(True) - map2.setFollowVisibilityPresetName('blue') + map2.setFollowVisibilityPresetName("blue") legend = QgsLayoutItemLegend(layout) legend.setTitle("Legend") @@ -945,14 +1056,25 @@ def testLegendRenderWithMapTheme(self): legend.setFrameEnabled(True) legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundColor(QColor(200, 200, 200)) - legend.setTitle('') + legend.setTitle("") layout.addLayoutItem(legend) legend.setLinkedMap(map1) - legend.setStyleFont(QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.SymbolLabel, QgsFontUtils.getStandardTestFont('Bold', 16)) + legend.setStyleFont( + QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.SymbolLabel, + QgsFontUtils.getStandardTestFont("Bold", 16), + ) legend2 = QgsLayoutItemLegend(layout) legend2.setTitle("Legend") @@ -960,21 +1082,28 @@ def testLegendRenderWithMapTheme(self): legend2.setFrameEnabled(True) legend2.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend2.setBackgroundColor(QColor(200, 200, 200)) - legend2.setTitle('') + legend2.setTitle("") layout.addLayoutItem(legend2) legend2.setLinkedMap(map2) - legend2.setStyleFont(QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend2.setStyleFont(QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend2.setStyleFont(QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend2.setStyleFont(QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend2.setStyleFont(QgsLegendStyle.Style.SymbolLabel, QgsFontUtils.getStandardTestFont('Bold', 16)) - - self.assertTrue( - self.render_layout_check( - 'composer_legend_theme', layout - ) + legend2.setStyleFont( + QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend2.setStyleFont( + QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend2.setStyleFont( + QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend2.setStyleFont( + QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend2.setStyleFont( + QgsLegendStyle.Style.SymbolLabel, + QgsFontUtils.getStandardTestFont("Bold", 16), ) + self.assertTrue(self.render_layout_check("composer_legend_theme", layout)) + QgsProject.instance().clear() def testLegendRenderLinkedMapScale(self): @@ -983,12 +1112,14 @@ def testLegendRenderLinkedMapScale(self): """ QgsProject.instance().removeAllMapLayers() - line_path = os.path.join(TEST_DATA_DIR, 'lines.shp') - line_layer = QgsVectorLayer(line_path, 'lines', 'ogr') + line_path = os.path.join(TEST_DATA_DIR, "lines.shp") + line_layer = QgsVectorLayer(line_path, "lines", "ogr") QgsProject.instance().clear() QgsProject.instance().addMapLayers([line_layer]) - line_symbol = QgsLineSymbol.createSimple({'color': '#ff0000', 'width_unit': 'mapunits', 'width': '0.0001'}) + line_symbol = QgsLineSymbol.createSimple( + {"color": "#ff0000", "width_unit": "mapunits", "width": "0.0001"} + ) line_layer.setRenderer(QgsSingleSymbolRenderer(line_symbol)) layout = QgsLayout(QgsProject.instance()) @@ -1016,15 +1147,26 @@ def testLegendRenderLinkedMapScale(self): legend.setFrameEnabled(True) legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundColor(QColor(200, 200, 200)) - legend.setTitle('') + legend.setTitle("") layout.addLayoutItem(legend) legend.setLinkedMap(map1) - legend.setStyleFont(QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.SymbolLabel, QgsFontUtils.getStandardTestFont('Bold', 16)) + legend.setStyleFont( + QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.SymbolLabel, + QgsFontUtils.getStandardTestFont("Bold", 16), + ) legend2 = QgsLayoutItemLegend(layout) legend2.setTitle("Legend") @@ -1032,22 +1174,29 @@ def testLegendRenderLinkedMapScale(self): legend2.setFrameEnabled(True) legend2.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend2.setBackgroundColor(QColor(200, 200, 200)) - legend2.setTitle('') + legend2.setTitle("") layout.addLayoutItem(legend2) legend2.setLinkedMap(map2) - legend2.setStyleFont(QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend2.setStyleFont(QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend2.setStyleFont(QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend2.setStyleFont(QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend2.setStyleFont(QgsLegendStyle.Style.SymbolLabel, QgsFontUtils.getStandardTestFont('Bold', 16)) - - self.assertTrue( - self.render_layout_check( - 'composer_legend_scale_map', layout - ) + legend2.setStyleFont( + QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend2.setStyleFont( + QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend2.setStyleFont( + QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend2.setStyleFont( + QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend2.setStyleFont( + QgsLegendStyle.Style.SymbolLabel, + QgsFontUtils.getStandardTestFont("Bold", 16), ) + self.assertTrue(self.render_layout_check("composer_legend_scale_map", layout)) + QgsProject.instance().clear() def testReferencePoint(self): @@ -1056,13 +1205,19 @@ def testReferencePoint(self): """ QgsProject.instance().removeAllMapLayers() - point_path = os.path.join(TEST_DATA_DIR, 'points.shp') - point_layer = QgsVectorLayer(point_path, 'points', 'ogr') + point_path = os.path.join(TEST_DATA_DIR, "points.shp") + point_layer = QgsVectorLayer(point_path, "points", "ogr") QgsProject.instance().clear() QgsProject.instance().addMapLayers([point_layer]) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#ff0000', 'outline_style': 'no', 'size': '5', 'size_unit': 'MapUnit'}) + { + "color": "#ff0000", + "outline_style": "no", + "size": "5", + "size_unit": "MapUnit", + } + ) point_layer.setRenderer(QgsSingleSymbolRenderer(marker_symbol)) @@ -1079,7 +1234,10 @@ def testReferencePoint(self): map.zoomToExtent(point_layer.extent()) legend = QgsLayoutItemLegend(layout) - legend.setStyleFont(QgsLegendStyle.Style.SymbolLabel, QgsFontUtils.getStandardTestFont('Bold', 16)) + legend.setStyleFont( + QgsLegendStyle.Style.SymbolLabel, + QgsFontUtils.getStandardTestFont("Bold", 16), + ) legend.setReferencePoint(QgsLayoutItem.ReferencePoint.LowerLeft) legend.setResizeToContents(True) legend.setTitle("Legend") @@ -1088,14 +1246,12 @@ def testReferencePoint(self): legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundEnabled(False) legend.setBackgroundColor(QColor(200, 200, 200)) - legend.setTitle('') + legend.setTitle("") layout.addLayoutItem(legend) legend.setLinkedMap(map) self.assertTrue( - self.render_layout_check( - 'composer_legend_reference_point', layout - ) + self.render_layout_check("composer_legend_reference_point", layout) ) # re-render with filtering to trigger mapHitTest which ends up by calling adjustBoxSize(). @@ -1106,37 +1262,47 @@ def testReferencePoint(self): marker_symbol.setSize(10) self.assertTrue( - self.render_layout_check( - 'composer_legend_reference_point_newsize', layout - ) + self.render_layout_check("composer_legend_reference_point_newsize", layout) ) QgsProject.instance().clear() def test_rulebased_child_filter(self): - point_path = os.path.join(TEST_DATA_DIR, 'points.shp') - point_layer = QgsVectorLayer(point_path, 'points', 'ogr') + point_path = os.path.join(TEST_DATA_DIR, "points.shp") + point_layer = QgsVectorLayer(point_path, "points", "ogr") root_rule = QgsRuleBasedRenderer.Rule(None) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#ff0000', 'outline_style': 'no', 'size': '8'}) + {"color": "#ff0000", "outline_style": "no", "size": "8"} + ) - less_than_two_rule = QgsRuleBasedRenderer.Rule(marker_symbol, filterExp='"Importance" <=2', label='lessthantwo') + less_than_two_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Importance" <=2', label="lessthantwo" + ) root_rule.appendChild(less_than_two_rule) else_rule = QgsRuleBasedRenderer.Rule(None, elseRule=True) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#00ffff', 'outline_style': 'no', 'size': '4'}) - one_rule = QgsRuleBasedRenderer.Rule(marker_symbol, filterExp='"Pilots" = 1', label='1') + {"color": "#00ffff", "outline_style": "no", "size": "4"} + ) + one_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Pilots" = 1', label="1" + ) else_rule.appendChild(one_rule) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#ff8888', 'outline_style': 'no', 'size': '4'}) - two_rule = QgsRuleBasedRenderer.Rule(marker_symbol, filterExp='"Pilots" = 2', label='2') + {"color": "#ff8888", "outline_style": "no", "size": "4"} + ) + two_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Pilots" = 2', label="2" + ) else_rule.appendChild(two_rule) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#8888ff', 'outline_style': 'no', 'size': '4'}) - three_rule = QgsRuleBasedRenderer.Rule(marker_symbol, filterExp='"Pilots" = 3', label='3') + {"color": "#8888ff", "outline_style": "no", "size": "4"} + ) + three_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Pilots" = 3', label="3" + ) else_rule.appendChild(three_rule) root_rule.appendChild(else_rule) @@ -1154,7 +1320,7 @@ def test_rulebased_child_filter(self): map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(19, 17, 185, 165)) map.setFrameEnabled(True) - map.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + map.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) map.setLayers([point_layer]) layout.addLayoutItem(map) @@ -1164,15 +1330,25 @@ def test_rulebased_child_filter(self): legend.setFrameEnabled(True) legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundColor(QColor(200, 200, 200)) - legend.setTitle('') + legend.setTitle("") legend.setLegendFilterByMapEnabled(True) - legend.setStyleFont(QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.SymbolLabel, - QgsFontUtils.getStandardTestFont('Bold', 16)) + legend.setStyleFont( + QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.SymbolLabel, + QgsFontUtils.getStandardTestFont("Bold", 16), + ) layout.addLayoutItem(legend) legend.setLinkedMap(map) @@ -1180,11 +1356,7 @@ def test_rulebased_child_filter(self): map.setExtent(QgsRectangle(-119.778, 18.158, -82.444, 51.514)) - self.assertTrue( - self.render_layout_check( - 'composer_legend_elseChild', layout - ) - ) + self.assertTrue(self.render_layout_check("composer_legend_elseChild", layout)) def test_filter_by_map_items(self): p = QgsProject() @@ -1193,15 +1365,15 @@ def test_filter_by_map_items(self): layout.initializeDefaults() map1 = QgsLayoutItemMap(layout) - map1.setId('map 1') + map1.setId("map 1") layout.addLayoutItem(map1) map2 = QgsLayoutItemMap(layout) - map2.setId('map 2') + map2.setId("map 2") layout.addLayoutItem(map2) map3 = QgsLayoutItemMap(layout) - map3.setId('map 3') + map3.setId("map 3") layout.addLayoutItem(map3) legend = QgsLayoutItemLegend(layout) @@ -1217,44 +1389,60 @@ def test_filter_by_map_items(self): l2 = QgsLayout(p) self.assertTrue(l2.readXml(elem, doc, QgsReadWriteContext())) - map1_restore = [i for i in l2.items() if isinstance(i, QgsLayoutItemMap) and i.id() == 'map 1'][0] - map3_restore = [i for i in l2.items() if isinstance(i, QgsLayoutItemMap) and i.id() == 'map 3'][0] - legend_restore = [i for i in l2.items() if isinstance(i, QgsLayoutItemLegend)][0] - - self.assertEqual(legend_restore.filterByMapItems(), [map1_restore, map3_restore]) + map1_restore = [ + i + for i in l2.items() + if isinstance(i, QgsLayoutItemMap) and i.id() == "map 1" + ][0] + map3_restore = [ + i + for i in l2.items() + if isinstance(i, QgsLayoutItemMap) and i.id() == "map 3" + ][0] + legend_restore = [i for i in l2.items() if isinstance(i, QgsLayoutItemLegend)][ + 0 + ] + + self.assertEqual( + legend_restore.filterByMapItems(), [map1_restore, map3_restore] + ) def test_filter_by_map_content_rendering(self): - point_path = os.path.join(TEST_DATA_DIR, 'points.shp') - point_layer = QgsVectorLayer(point_path, 'points', 'ogr') + point_path = os.path.join(TEST_DATA_DIR, "points.shp") + point_layer = QgsVectorLayer(point_path, "points", "ogr") root_rule = QgsRuleBasedRenderer.Rule(None) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#ff0000', 'outline_style': 'no', 'size': '8'}) + {"color": "#ff0000", "outline_style": "no", "size": "8"} + ) - less_than_two_rule = QgsRuleBasedRenderer.Rule(marker_symbol, - filterExp='"Importance" <=2', - label='lessthantwo') + less_than_two_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Importance" <=2', label="lessthantwo" + ) root_rule.appendChild(less_than_two_rule) else_rule = QgsRuleBasedRenderer.Rule(None, elseRule=True) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#00ffff', 'outline_style': 'no', 'size': '4'}) - one_rule = QgsRuleBasedRenderer.Rule(marker_symbol, - filterExp='"Pilots" = 1', - label='1') + {"color": "#00ffff", "outline_style": "no", "size": "4"} + ) + one_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Pilots" = 1', label="1" + ) else_rule.appendChild(one_rule) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#ff8888', 'outline_style': 'no', 'size': '4'}) - two_rule = QgsRuleBasedRenderer.Rule(marker_symbol, - filterExp='"Pilots" = 2', - label='2') + {"color": "#ff8888", "outline_style": "no", "size": "4"} + ) + two_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Pilots" = 2', label="2" + ) else_rule.appendChild(two_rule) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#8888ff', 'outline_style': 'no', 'size': '4'}) - three_rule = QgsRuleBasedRenderer.Rule(marker_symbol, - filterExp='"Pilots" = 3', - label='3') + {"color": "#8888ff", "outline_style": "no", "size": "4"} + ) + three_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Pilots" = 3', label="3" + ) else_rule.appendChild(three_rule) root_rule.appendChild(else_rule) @@ -1270,7 +1458,7 @@ def test_filter_by_map_content_rendering(self): map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(19, 17, 100, 165)) map.setFrameEnabled(True) - map.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + map.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) map.setLayers([point_layer]) map.zoomToExtent(QgsRectangle(-120, 14, -100, 18)) map.setMapRotation(45) @@ -1280,7 +1468,7 @@ def test_filter_by_map_content_rendering(self): map2 = QgsLayoutItemMap(layout) map2.attemptSetSceneRect(QRectF(150, 117, 100, 165)) map2.setFrameEnabled(True) - map2.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + map2.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) map2.setLayers([point_layer]) map2.setExtent(QgsRectangle(-12309930, 3091263, -11329181, 3977074)) @@ -1295,55 +1483,65 @@ def test_filter_by_map_content_rendering(self): legend.setFrameEnabled(True) legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundColor(QColor(200, 200, 200)) - legend.setTitle('') + legend.setTitle("") - legend.setStyleFont(QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.SymbolLabel, - QgsFontUtils.getStandardTestFont('Bold', 16)) - - self.assertTrue( - self.render_layout_check( - 'legend_multiple_filter_maps', layout - ) + legend.setStyleFont( + QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont("Bold", 16) ) + legend.setStyleFont( + QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.SymbolLabel, + QgsFontUtils.getStandardTestFont("Bold", 16), + ) + + self.assertTrue(self.render_layout_check("legend_multiple_filter_maps", layout)) def test_filter_by_map_content_rendering_different_layers(self): - point_path = os.path.join(TEST_DATA_DIR, 'points.shp') - point_layer = QgsVectorLayer(point_path, 'points', 'ogr') + point_path = os.path.join(TEST_DATA_DIR, "points.shp") + point_layer = QgsVectorLayer(point_path, "points", "ogr") - point_layer2 = QgsVectorLayer(point_path, 'points2', 'ogr') + point_layer2 = QgsVectorLayer(point_path, "points2", "ogr") root_rule = QgsRuleBasedRenderer.Rule(None) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#ff0000', 'outline_style': 'no', 'size': '8'}) + {"color": "#ff0000", "outline_style": "no", "size": "8"} + ) - less_than_two_rule = QgsRuleBasedRenderer.Rule(marker_symbol, - filterExp='"Importance" <=2', - label='lessthantwo') + less_than_two_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Importance" <=2', label="lessthantwo" + ) root_rule.appendChild(less_than_two_rule) else_rule = QgsRuleBasedRenderer.Rule(None, elseRule=True) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#00ffff', 'outline_style': 'no', 'size': '4'}) - one_rule = QgsRuleBasedRenderer.Rule(marker_symbol, - filterExp='"Pilots" = 1', - label='1') + {"color": "#00ffff", "outline_style": "no", "size": "4"} + ) + one_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Pilots" = 1', label="1" + ) else_rule.appendChild(one_rule) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#ff8888', 'outline_style': 'no', 'size': '4'}) - two_rule = QgsRuleBasedRenderer.Rule(marker_symbol, - filterExp='"Pilots" = 2', - label='2') + {"color": "#ff8888", "outline_style": "no", "size": "4"} + ) + two_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Pilots" = 2', label="2" + ) else_rule.appendChild(two_rule) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#8888ff', 'outline_style': 'no', 'size': '4'}) - three_rule = QgsRuleBasedRenderer.Rule(marker_symbol, - filterExp='"Pilots" = 3', - label='3') + {"color": "#8888ff", "outline_style": "no", "size": "4"} + ) + three_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Pilots" = 3', label="3" + ) else_rule.appendChild(three_rule) root_rule.appendChild(else_rule) @@ -1352,7 +1550,8 @@ def test_filter_by_map_content_rendering_different_layers(self): point_layer.setRenderer(renderer) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#003366', 'outline_style': 'no', 'size': '8'}) + {"color": "#003366", "outline_style": "no", "size": "8"} + ) point_layer2.setRenderer(QgsSingleSymbolRenderer(marker_symbol)) p = QgsProject() @@ -1364,7 +1563,7 @@ def test_filter_by_map_content_rendering_different_layers(self): map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(19, 17, 100, 165)) map.setFrameEnabled(True) - map.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + map.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) map.setLayers([point_layer]) map.zoomToExtent(QgsRectangle(-120, 14, -100, 18)) map.setMapRotation(45) @@ -1374,7 +1573,7 @@ def test_filter_by_map_content_rendering_different_layers(self): map2 = QgsLayoutItemMap(layout) map2.attemptSetSceneRect(QRectF(150, 117, 100, 165)) map2.setFrameEnabled(True) - map2.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + map2.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) map2.setLayers([point_layer2]) map2.setExtent(QgsRectangle(-12309930, 3091263, -11329181, 3977074)) @@ -1389,18 +1588,28 @@ def test_filter_by_map_content_rendering_different_layers(self): legend.setFrameEnabled(True) legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundColor(QColor(200, 200, 200)) - legend.setTitle('') + legend.setTitle("") - legend.setStyleFont(QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.SymbolLabel, - QgsFontUtils.getStandardTestFont('Bold', 16)) + legend.setStyleFont( + QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.SymbolLabel, + QgsFontUtils.getStandardTestFont("Bold", 16), + ) self.assertTrue( self.render_layout_check( - 'legend_multiple_filter_maps_different_layers', layout + "legend_multiple_filter_maps_different_layers", layout ) ) @@ -1408,66 +1617,79 @@ def test_atlas_legend_clipping(self): """Test issue GH #54654""" p = QgsProject() - self.assertTrue(p.read(os.path.join(TEST_DATA_DIR, 'layouts', 'atlas_legend_clipping.qgs'))) + self.assertTrue( + p.read(os.path.join(TEST_DATA_DIR, "layouts", "atlas_legend_clipping.qgs")) + ) - layout = p.layoutManager().layoutByName('layout1') + layout = p.layoutManager().layoutByName("layout1") layer = list(p.mapLayers().values())[0] feature = layer.getFeature(3) req = QgsFeatureRequest() - req.setFilterExpression('value = 11') + req.setFilterExpression("value = 11") feature = next(layer.getFeatures(req)) layout.reportContext().setFeature(feature) legend = layout.items()[0] - legend.setStyleFont(QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont('Bold', 20)) - legend.setStyleFont(QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont('Bold', 20)) - legend.setStyleFont(QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont('Bold', 20)) - legend.setStyleFont(QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont('Bold', 20)) - legend.setStyleFont(QgsLegendStyle.Style.SymbolLabel, - QgsFontUtils.getStandardTestFont('Bold', 20)) + legend.setStyleFont( + QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont("Bold", 20) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont("Bold", 20) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont("Bold", 20) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont("Bold", 20) + ) + legend.setStyleFont( + QgsLegendStyle.Style.SymbolLabel, + QgsFontUtils.getStandardTestFont("Bold", 20), + ) legend.refresh() - self.assertTrue( - self.render_layout_check( - 'atlas_legend_clipping', layout - ) - ) + self.assertTrue(self.render_layout_check("atlas_legend_clipping", layout)) def test_filter_by_map_content_rendering_different_layers_in_atlas(self): - point_path = os.path.join(TEST_DATA_DIR, 'points.shp') - point_layer = QgsVectorLayer(point_path, 'points', 'ogr') + point_path = os.path.join(TEST_DATA_DIR, "points.shp") + point_layer = QgsVectorLayer(point_path, "points", "ogr") - point_layer2 = QgsVectorLayer(point_path, 'points2', 'ogr') + point_layer2 = QgsVectorLayer(point_path, "points2", "ogr") root_rule = QgsRuleBasedRenderer.Rule(None) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#ff0000', 'outline_style': 'no', 'size': '8'}) + {"color": "#ff0000", "outline_style": "no", "size": "8"} + ) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#00ffff', 'outline_style': 'no', 'size': '4'}) - one_rule = QgsRuleBasedRenderer.Rule(marker_symbol, - filterExp='"Pilots" = 1', - label='1') + {"color": "#00ffff", "outline_style": "no", "size": "4"} + ) + one_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Pilots" = 1', label="1" + ) root_rule.appendChild(one_rule) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#ff8888', 'outline_style': 'no', 'size': '4'}) - two_rule = QgsRuleBasedRenderer.Rule(marker_symbol, - filterExp='"Pilots" = 2', - label='2') + {"color": "#ff8888", "outline_style": "no", "size": "4"} + ) + two_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Pilots" = 2', label="2" + ) root_rule.appendChild(two_rule) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#8888ff', 'outline_style': 'no', 'size': '4'}) - three_rule = QgsRuleBasedRenderer.Rule(marker_symbol, - filterExp='"Pilots" = 3', - label='3') + {"color": "#8888ff", "outline_style": "no", "size": "4"} + ) + three_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Pilots" = 3', label="3" + ) root_rule.appendChild(three_rule) renderer = QgsRuleBasedRenderer(root_rule) point_layer.setRenderer(renderer) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#003366', 'outline_style': 'no', 'size': '8'}) + {"color": "#003366", "outline_style": "no", "size": "8"} + ) point_layer2.setRenderer(QgsSingleSymbolRenderer(marker_symbol)) p = QgsProject() @@ -1479,9 +1701,16 @@ def test_filter_by_map_content_rendering_different_layers_in_atlas(self): map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(19, 17, 100, 165)) map.setFrameEnabled(True) - map.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + map.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) map.setLayers([point_layer]) - map.zoomToExtent(QgsRectangle(-108.52403736600929562, 22.4408089916287814, -97.776639147740255, 29.00866345834875304)) + map.zoomToExtent( + QgsRectangle( + -108.52403736600929562, + 22.4408089916287814, + -97.776639147740255, + 29.00866345834875304, + ) + ) map.setMapRotation(45) layout.addLayoutItem(map) @@ -1489,7 +1718,7 @@ def test_filter_by_map_content_rendering_different_layers_in_atlas(self): map2 = QgsLayoutItemMap(layout) map2.attemptSetSceneRect(QRectF(150, 117, 100, 165)) map2.setFrameEnabled(True) - map2.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + map2.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) map2.setLayers([point_layer2]) map2.setExtent(QgsRectangle(-12309930, 3091263, -11329181, 3977074)) @@ -1505,28 +1734,42 @@ def test_filter_by_map_content_rendering_different_layers_in_atlas(self): legend.setFrameEnabled(True) legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundColor(QColor(200, 200, 200)) - legend.setTitle('') - - legend.setStyleFont(QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont('Bold', 16)) - legend.setStyleFont(QgsLegendStyle.Style.SymbolLabel, - QgsFontUtils.getStandardTestFont('Bold', 16)) + legend.setTitle("") + + legend.setStyleFont( + QgsLegendStyle.Style.Title, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Group, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Subgroup, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.Symbol, QgsFontUtils.getStandardTestFont("Bold", 16) + ) + legend.setStyleFont( + QgsLegendStyle.Style.SymbolLabel, + QgsFontUtils.getStandardTestFont("Bold", 16), + ) legend.setLegendFilterOutAtlas(True) atlas_layer = QgsVectorLayer( - "Polygon?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + "Polygon?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) layout.reportContext().setLayer(atlas_layer) f = QgsFeature() - f.setGeometry(QgsGeometry.fromWkt('Polygon ((-115.422 42.22, -118.202 36.246, -103.351 22.06, -102.314 22.682, -116.542 37.159, -113.348 41.846, -98.747 39.98, -93.313 47.281, -94.225 47.861, -99.95 41.39, -114.51 43.34, -115.422 42.22))')) + f.setGeometry( + QgsGeometry.fromWkt( + "Polygon ((-115.422 42.22, -118.202 36.246, -103.351 22.06, -102.314 22.682, -116.542 37.159, -113.348 41.846, -98.747 39.98, -93.313 47.281, -94.225 47.861, -99.95 41.39, -114.51 43.34, -115.422 42.22))" + ) + ) layout.reportContext().setFeature(f) legend.refresh() self.assertTrue( self.render_layout_check( - 'legend_multiple_filter_maps_different_layers_atlas', layout + "legend_multiple_filter_maps_different_layers_atlas", layout ) ) @@ -1534,14 +1777,17 @@ def testGeomGeneratorPoints(self): """ Test legend behavior when geometry generator on points is involved """ - point_path = os.path.join(TEST_DATA_DIR, 'points.shp') - point_layer = QgsVectorLayer(point_path, 'points', 'ogr') + point_path = os.path.join(TEST_DATA_DIR, "points.shp") + point_layer = QgsVectorLayer(point_path, "points", "ogr") QgsProject.instance().addMapLayers([point_layer]) - sub_symbol = QgsFillSymbol.createSimple({'color': '#8888ff', 'outline_style': 'no'}) + sub_symbol = QgsFillSymbol.createSimple( + {"color": "#8888ff", "outline_style": "no"} + ) sym = QgsMarkerSymbol() buffer_layer = QgsGeometryGeneratorSymbolLayer.create( - {'geometryModifier': 'buffer($geometry, 0.05)'}) + {"geometryModifier": "buffer($geometry, 0.05)"} + ) buffer_layer.setSymbolType(QgsSymbol.SymbolType.Fill) buffer_layer.setSubSymbol(sub_symbol) sym.changeSymbolLayer(0, buffer_layer) @@ -1564,7 +1810,7 @@ def testGeomGeneratorPoints(self): legend.setFrameEnabled(True) legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundColor(QColor(200, 200, 200)) - legend.setTitle('') + legend.setTitle("") legend.setLegendFilterByMapEnabled(True) legend.setSymbolWidth(20) legend.setSymbolHeight(10) @@ -1573,8 +1819,13 @@ def testGeomGeneratorPoints(self): text_format.setFont(QgsFontUtils.getStandardTestFont("Bold")) text_format.setSize(16) - for legend_item in [QgsLegendStyle.Style.Title, QgsLegendStyle.Style.Group, QgsLegendStyle.Style.Subgroup, - QgsLegendStyle.Style.Symbol, QgsLegendStyle.Style.SymbolLabel]: + for legend_item in [ + QgsLegendStyle.Style.Title, + QgsLegendStyle.Style.Group, + QgsLegendStyle.Style.Subgroup, + QgsLegendStyle.Style.Symbol, + QgsLegendStyle.Style.SymbolLabel, + ]: style = legend.style(legend_item) style.setTextFormat(text_format) legend.setStyle(legend_item, style) @@ -1588,9 +1839,7 @@ def testGeomGeneratorPoints(self): map.setExtent(QgsRectangle(-102.51, 41.16, -102.36, 41.30)) self.assertTrue( - self.render_layout_check( - 'composer_legend_geomgenerator_point', layout - ) + self.render_layout_check("composer_legend_geomgenerator_point", layout) ) QgsProject.instance().removeMapLayers([point_layer.id()]) @@ -1598,14 +1847,17 @@ def testGeomGeneratorLines(self): """ Test legend behavior when geometry generator on lines is involved """ - line_path = os.path.join(TEST_DATA_DIR, 'lines.shp') - line_layer = QgsVectorLayer(line_path, 'lines', 'ogr') + line_path = os.path.join(TEST_DATA_DIR, "lines.shp") + line_layer = QgsVectorLayer(line_path, "lines", "ogr") QgsProject.instance().addMapLayers([line_layer]) - sub_symbol = QgsFillSymbol.createSimple({'color': '#8888ff', 'outline_style': 'no'}) + sub_symbol = QgsFillSymbol.createSimple( + {"color": "#8888ff", "outline_style": "no"} + ) sym = QgsLineSymbol() buffer_layer = QgsGeometryGeneratorSymbolLayer.create( - {'geometryModifier': 'buffer($geometry, 0.2)'}) + {"geometryModifier": "buffer($geometry, 0.2)"} + ) buffer_layer.setSymbolType(QgsSymbol.SymbolType.Fill) buffer_layer.setSubSymbol(sub_symbol) sym.changeSymbolLayer(0, buffer_layer) @@ -1629,7 +1881,7 @@ def testGeomGeneratorLines(self): legend.setFrameEnabled(True) legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundColor(QColor(200, 200, 200)) - legend.setTitle('') + legend.setTitle("") legend.setLegendFilterByMapEnabled(True) legend.setSymbolWidth(20) legend.setSymbolHeight(10) @@ -1638,8 +1890,13 @@ def testGeomGeneratorLines(self): text_format.setFont(QgsFontUtils.getStandardTestFont("Bold")) text_format.setSize(16) - for legend_item in [QgsLegendStyle.Style.Title, QgsLegendStyle.Style.Group, QgsLegendStyle.Style.Subgroup, - QgsLegendStyle.Style.Symbol, QgsLegendStyle.Style.SymbolLabel]: + for legend_item in [ + QgsLegendStyle.Style.Title, + QgsLegendStyle.Style.Group, + QgsLegendStyle.Style.Subgroup, + QgsLegendStyle.Style.Symbol, + QgsLegendStyle.Style.SymbolLabel, + ]: style = legend.style(legend_item) style.setTextFormat(text_format) legend.setStyle(legend_item, style) @@ -1653,13 +1910,11 @@ def testGeomGeneratorLines(self): map.setExtent(QgsRectangle(-100.3127, 35.7607, -98.5259, 36.5145)) self.assertTrue( - self.render_layout_check( - 'composer_legend_geomgenerator_line', layout - ) + self.render_layout_check("composer_legend_geomgenerator_line", layout) ) QgsProject.instance().removeMapLayers([line_layer.id()]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutmanager.py b/tests/src/python/test_qgslayoutmanager.py index 5fe015817c09..3a84de2dee28 100644 --- a/tests/src/python/test_qgslayoutmanager.py +++ b/tests/src/python/test_qgslayoutmanager.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2017 by Nyall Dawson' -__date__ = '15/03/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "(C) 2017 by Nyall Dawson" +__date__ = "15/03/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy from qgis.PyQt.QtXml import QDomDocument @@ -41,7 +42,7 @@ def tearDown(self): def testAddLayout(self): project = QgsProject() layout = QgsPrintLayout(project) - layout.setName('test layout') + layout.setName("test layout") manager = QgsLayoutManager(project) @@ -49,36 +50,36 @@ def testAddLayout(self): layout_added_spy = QSignalSpy(manager.layoutAdded) self.assertTrue(manager.addLayout(layout)) self.assertEqual(len(layout_about_to_be_added_spy), 1) - self.assertEqual(layout_about_to_be_added_spy[0][0], 'test layout') + self.assertEqual(layout_about_to_be_added_spy[0][0], "test layout") self.assertEqual(len(layout_added_spy), 1) - self.assertEqual(layout_added_spy[0][0], 'test layout') + self.assertEqual(layout_added_spy[0][0], "test layout") # adding it again should fail self.assertFalse(manager.addLayout(layout)) # try adding a second layout layout2 = QgsPrintLayout(project) - layout2.setName('test layout2') + layout2.setName("test layout2") self.assertTrue(manager.addLayout(layout2)) self.assertEqual(len(layout_added_spy), 2) - self.assertEqual(layout_about_to_be_added_spy[1][0], 'test layout2') + self.assertEqual(layout_about_to_be_added_spy[1][0], "test layout2") self.assertEqual(len(layout_about_to_be_added_spy), 2) - self.assertEqual(layout_added_spy[1][0], 'test layout2') + self.assertEqual(layout_added_spy[1][0], "test layout2") # adding a layout with duplicate name should fail layout3 = QgsPrintLayout(project) - layout3.setName('test layout2') + layout3.setName("test layout2") self.assertFalse(manager.addLayout(layout3)) def testLayouts(self): project = QgsProject() manager = QgsLayoutManager(project) layout = QgsPrintLayout(project) - layout.setName('test layout') + layout.setName("test layout") layout2 = QgsPrintLayout(project) - layout2.setName('test layout2') + layout2.setName("test layout2") layout3 = QgsPrintLayout(project) - layout3.setName('test layout3') + layout3.setName("test layout3") manager.addLayout(layout) self.assertEqual(manager.layouts(), [layout]) @@ -89,20 +90,20 @@ def testLayouts(self): def aboutToBeRemoved(self, name): # composition should still exist at this time - self.assertEqual(name, 'test composition') - self.assertTrue(self.manager.compositionByName('test composition')) + self.assertEqual(name, "test composition") + self.assertTrue(self.manager.compositionByName("test composition")) self.aboutFired = True def layoutAboutToBeRemoved(self, name): # layout should still exist at this time - self.assertEqual(name, 'test layout') - self.assertTrue(self.manager.layoutByName('test layout')) + self.assertEqual(name, "test layout") + self.assertTrue(self.manager.layoutByName("test layout")) self.aboutFired = True def testRemoveLayout(self): project = QgsProject() layout = QgsPrintLayout(project) - layout.setName('test layout') + layout.setName("test layout") self.manager = QgsLayoutManager(project) layout_removed_spy = QSignalSpy(self.manager.layoutRemoved) @@ -120,9 +121,9 @@ def testRemoveLayout(self): self.assertTrue(self.manager.removeLayout(layout)) self.assertEqual(len(self.manager.layouts()), 0) self.assertEqual(len(layout_removed_spy), 1) - self.assertEqual(layout_removed_spy[0][0], 'test layout') + self.assertEqual(layout_removed_spy[0][0], "test layout") self.assertEqual(len(layout_about_to_be_removed_spy), 1) - self.assertEqual(layout_about_to_be_removed_spy[0][0], 'test layout') + self.assertEqual(layout_about_to_be_removed_spy[0][0], "test layout") self.assertTrue(self.aboutFired) self.manager = None @@ -132,11 +133,11 @@ def testClear(self): # add a bunch of layouts layout = QgsPrintLayout(project) - layout.setName('test layout') + layout.setName("test layout") layout2 = QgsPrintLayout(project) - layout2.setName('test layout2') + layout2.setName("test layout2") layout3 = QgsPrintLayout(project) - layout3.setName('test layout3') + layout3.setName("test layout3") manager.addLayout(layout) manager.addLayout(layout2) @@ -155,20 +156,20 @@ def testLayoutsByName(self): # add a bunch of layouts layout = QgsPrintLayout(project) - layout.setName('test layout') + layout.setName("test layout") layout2 = QgsPrintLayout(project) - layout2.setName('test layout2') + layout2.setName("test layout2") layout3 = QgsPrintLayout(project) - layout3.setName('test layout3') + layout3.setName("test layout3") manager.addLayout(layout) manager.addLayout(layout2) manager.addLayout(layout3) - self.assertFalse(manager.layoutByName('asdf')) - self.assertEqual(manager.layoutByName('test layout'), layout) - self.assertEqual(manager.layoutByName('test layout2'), layout2) - self.assertEqual(manager.layoutByName('test layout3'), layout3) + self.assertFalse(manager.layoutByName("asdf")) + self.assertEqual(manager.layoutByName("test layout"), layout) + self.assertEqual(manager.layoutByName("test layout2"), layout2) + self.assertEqual(manager.layoutByName("test layout3"), layout3) def testReadWriteXml(self): """ @@ -179,11 +180,11 @@ def testReadWriteXml(self): # add a bunch of layouts layout = QgsPrintLayout(project) - layout.setName('test layout') + layout.setName("test layout") layout2 = QgsPrintLayout(project) - layout2.setName('test layout2') + layout2.setName("test layout2") layout3 = QgsPrintLayout(project) - layout3.setName('test layout3') + layout3.setName("test layout3") manager.addLayout(layout) manager.addLayout(layout2) @@ -201,7 +202,7 @@ def testReadWriteXml(self): self.assertEqual(len(manager2.layouts()), 3) names = [c.name() for c in manager2.layouts()] - self.assertCountEqual(names, ['test layout', 'test layout2', 'test layout3']) + self.assertCountEqual(names, ["test layout", "test layout2", "test layout3"]) def testDuplicateLayout(self): """ @@ -210,69 +211,86 @@ def testDuplicateLayout(self): project = QgsProject() manager = QgsLayoutManager(project) doc = QDomDocument("testdoc") - self.assertFalse(manager.duplicateLayout(None, 'dest')) + self.assertFalse(manager.duplicateLayout(None, "dest")) layout = QgsPrintLayout(project) - layout.setName('test layout') + layout.setName("test layout") layout.initializeDefaults() manager.addLayout(layout) # duplicate name - self.assertFalse(manager.duplicateLayout(layout, 'test layout')) - result = manager.duplicateLayout(layout, 'dupe layout') + self.assertFalse(manager.duplicateLayout(layout, "test layout")) + result = manager.duplicateLayout(layout, "dupe layout") self.assertTrue(result) # make sure result in stored in manager - self.assertEqual(result, manager.layoutByName('dupe layout')) - self.assertEqual(result.name(), 'dupe layout') + self.assertEqual(result, manager.layoutByName("dupe layout")) + self.assertEqual(result.name(), "dupe layout") self.assertEqual(result.pageCollection().pageCount(), 1) def testGenerateUniqueTitle(self): project = QgsProject() manager = QgsLayoutManager(project) - self.assertEqual(manager.generateUniqueTitle(QgsMasterLayoutInterface.Type.PrintLayout), 'Layout 1') - self.assertEqual(manager.generateUniqueTitle(QgsMasterLayoutInterface.Type.Report), 'Report 1') + self.assertEqual( + manager.generateUniqueTitle(QgsMasterLayoutInterface.Type.PrintLayout), + "Layout 1", + ) + self.assertEqual( + manager.generateUniqueTitle(QgsMasterLayoutInterface.Type.Report), + "Report 1", + ) layout = QgsPrintLayout(project) layout.setName(manager.generateUniqueTitle()) manager.addLayout(layout) - self.assertEqual(manager.generateUniqueTitle(), 'Layout 2') - self.assertEqual(manager.generateUniqueTitle(QgsMasterLayoutInterface.Type.Report), 'Report 1') + self.assertEqual(manager.generateUniqueTitle(), "Layout 2") + self.assertEqual( + manager.generateUniqueTitle(QgsMasterLayoutInterface.Type.Report), + "Report 1", + ) layout2 = QgsPrintLayout(project) layout2.setName(manager.generateUniqueTitle()) manager.addLayout(layout2) - self.assertEqual(manager.generateUniqueTitle(), 'Layout 3') + self.assertEqual(manager.generateUniqueTitle(), "Layout 3") report1 = QgsReport(project) - report1.setName(manager.generateUniqueTitle(QgsMasterLayoutInterface.Type.Report)) + report1.setName( + manager.generateUniqueTitle(QgsMasterLayoutInterface.Type.Report) + ) manager.addLayout(report1) - self.assertEqual(manager.generateUniqueTitle(QgsMasterLayoutInterface.Type.Report), 'Report 2') + self.assertEqual( + manager.generateUniqueTitle(QgsMasterLayoutInterface.Type.Report), + "Report 2", + ) manager.clear() - self.assertEqual(manager.generateUniqueTitle(), 'Layout 1') - self.assertEqual(manager.generateUniqueTitle(QgsMasterLayoutInterface.Type.Report), 'Report 1') + self.assertEqual(manager.generateUniqueTitle(), "Layout 1") + self.assertEqual( + manager.generateUniqueTitle(QgsMasterLayoutInterface.Type.Report), + "Report 1", + ) def testRenameSignal(self): project = QgsProject() manager = QgsLayoutManager(project) layout = QgsPrintLayout(project) - layout.setName('c1') + layout.setName("c1") manager.addLayout(layout) layout2 = QgsPrintLayout(project) - layout2.setName('c2') + layout2.setName("c2") manager.addLayout(layout2) layout_renamed_spy = QSignalSpy(manager.layoutRenamed) - layout.setName('d1') + layout.setName("d1") self.assertEqual(len(layout_renamed_spy), 1) # self.assertEqual(layout_renamed_spy[0][0], layout) - self.assertEqual(layout_renamed_spy[0][1], 'd1') - layout2.setName('d2') + self.assertEqual(layout_renamed_spy[0][1], "d1") + layout2.setName("d2") self.assertEqual(len(layout_renamed_spy), 2) # self.assertEqual(layout_renamed_spy[1][0], layout2) - self.assertEqual(layout_renamed_spy[1][1], 'd2') + self.assertEqual(layout_renamed_spy[1][1], "d2") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutmanagermodel.py b/tests/src/python/test_qgslayoutmanagermodel.py index ad1043a64693..22910a1f5d56 100644 --- a/tests/src/python/test_qgslayoutmanagermodel.py +++ b/tests/src/python/test_qgslayoutmanagermodel.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2019 by Nyall Dawson' -__date__ = '11/03/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "(C) 2019 by Nyall Dawson" +__date__ = "11/03/2019" +__copyright__ = "Copyright 2019, The QGIS Project" from qgis.PyQt.QtCore import QModelIndex, Qt from qgis.core import ( @@ -43,99 +44,258 @@ def testModel(self): manager = QgsLayoutManager(project) model = QgsLayoutManagerModel(manager) self.assertEqual(model.rowCount(QModelIndex()), 0) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) self.assertEqual(model.layoutFromIndex(model.index(0, 0, QModelIndex())), None) self.assertEqual(model.indexFromLayout(None), QModelIndex()) layout = QgsPrintLayout(project) - layout.setName('test layout') + layout.setName("test layout") self.assertEqual(model.indexFromLayout(layout), QModelIndex()) self.assertTrue(manager.addLayout(layout)) self.assertEqual(model.rowCount(QModelIndex()), 1) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'test layout') - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout) - self.assertEqual(model.layoutFromIndex(model.index(0, 0, QModelIndex())), layout) - self.assertEqual(model.indexFromLayout(layout), model.index(0, 0, QModelIndex())) - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "test layout", + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout, + ) + self.assertEqual( + model.layoutFromIndex(model.index(0, 0, QModelIndex())), layout + ) + self.assertEqual( + model.indexFromLayout(layout), model.index(0, 0, QModelIndex()) + ) + self.assertEqual( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + model.data( + model.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) self.assertEqual(model.layoutFromIndex(model.index(1, 0, QModelIndex())), None) - layout.setName('test Layout') - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'test Layout') + layout.setName("test Layout") + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "test Layout", + ) layout2 = QgsPrintLayout(project) - layout2.setName('test layout2') + layout2.setName("test layout2") self.assertTrue(manager.addLayout(layout2)) self.assertEqual(model.rowCount(QModelIndex()), 2) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'test Layout') - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout) - self.assertEqual(model.layoutFromIndex(model.index(0, 0, QModelIndex())), layout) - self.assertEqual(model.indexFromLayout(layout), model.index(0, 0, QModelIndex())) - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'test layout2') - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout2) - self.assertEqual(model.layoutFromIndex(model.index(1, 0, QModelIndex())), layout2) - self.assertEqual(model.indexFromLayout(layout2), model.index(1, 0, QModelIndex())) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "test Layout", + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout, + ) + self.assertEqual( + model.layoutFromIndex(model.index(0, 0, QModelIndex())), layout + ) + self.assertEqual( + model.indexFromLayout(layout), model.index(0, 0, QModelIndex()) + ) + self.assertEqual( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "test layout2", + ) + self.assertEqual( + model.data( + model.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout2, + ) + self.assertEqual( + model.layoutFromIndex(model.index(1, 0, QModelIndex())), layout2 + ) + self.assertEqual( + model.indexFromLayout(layout2), model.index(1, 0, QModelIndex()) + ) manager.removeLayout(layout) self.assertEqual(model.rowCount(QModelIndex()), 1) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'test layout2') - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout2) - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) - self.assertEqual(model.layoutFromIndex(model.index(0, 0, QModelIndex())), layout2) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "test layout2", + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout2, + ) + self.assertEqual( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + model.data( + model.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) + self.assertEqual( + model.layoutFromIndex(model.index(0, 0, QModelIndex())), layout2 + ) self.assertEqual(model.layoutFromIndex(model.index(1, 0, QModelIndex())), None) - self.assertEqual(model.indexFromLayout(layout2), model.index(0, 0, QModelIndex())) + self.assertEqual( + model.indexFromLayout(layout2), model.index(0, 0, QModelIndex()) + ) manager.clear() self.assertEqual(model.rowCount(QModelIndex()), 0) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) self.assertEqual(model.layoutFromIndex(model.index(0, 0, QModelIndex())), None) # with empty row model.setAllowEmptyLayout(True) self.assertEqual(model.rowCount(QModelIndex()), 1) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) self.assertEqual(model.layoutFromIndex(model.index(0, 0, QModelIndex())), None) layout = QgsPrintLayout(project) - layout.setName('test layout') + layout.setName("test layout") self.assertTrue(manager.addLayout(layout)) self.assertEqual(model.rowCount(QModelIndex()), 2) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'test layout') - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout) - self.assertEqual(model.data(model.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(model.data(model.index(2, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) + self.assertEqual( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "test layout", + ) + self.assertEqual( + model.data( + model.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout, + ) + self.assertEqual( + model.data(model.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + model.data( + model.index(2, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) self.assertEqual(model.layoutFromIndex(model.index(0, 0, QModelIndex())), None) - self.assertEqual(model.layoutFromIndex(model.index(1, 0, QModelIndex())), layout) - self.assertEqual(model.indexFromLayout(layout), model.index(1, 0, QModelIndex())) + self.assertEqual( + model.layoutFromIndex(model.index(1, 0, QModelIndex())), layout + ) + self.assertEqual( + model.indexFromLayout(layout), model.index(1, 0, QModelIndex()) + ) layout2 = QgsPrintLayout(project) - layout2.setName('test layout2') + layout2.setName("test layout2") self.assertTrue(manager.addLayout(layout2)) self.assertEqual(model.rowCount(QModelIndex()), 3) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'test layout') - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout) - self.assertEqual(model.data(model.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'test layout2') - self.assertEqual(model.data(model.index(2, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout2) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) + self.assertEqual( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "test layout", + ) + self.assertEqual( + model.data( + model.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout, + ) + self.assertEqual( + model.data(model.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "test layout2", + ) + self.assertEqual( + model.data( + model.index(2, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout2, + ) self.assertEqual(model.layoutFromIndex(model.index(0, 0, QModelIndex())), None) - self.assertEqual(model.layoutFromIndex(model.index(1, 0, QModelIndex())), layout) - self.assertEqual(model.layoutFromIndex(model.index(2, 0, QModelIndex())), layout2) - self.assertEqual(model.indexFromLayout(layout), model.index(1, 0, QModelIndex())) - self.assertEqual(model.indexFromLayout(layout2), model.index(2, 0, QModelIndex())) + self.assertEqual( + model.layoutFromIndex(model.index(1, 0, QModelIndex())), layout + ) + self.assertEqual( + model.layoutFromIndex(model.index(2, 0, QModelIndex())), layout2 + ) + self.assertEqual( + model.indexFromLayout(layout), model.index(1, 0, QModelIndex()) + ) + self.assertEqual( + model.indexFromLayout(layout2), model.index(2, 0, QModelIndex()) + ) manager.clear() self.assertEqual(model.rowCount(QModelIndex()), 1) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) self.assertEqual(model.layoutFromIndex(model.index(0, 0, QModelIndex())), None) def testProxyModel(self): @@ -145,111 +305,346 @@ def testProxyModel(self): proxy = QgsLayoutManagerProxyModel() proxy.setSourceModel(model) self.assertEqual(proxy.rowCount(QModelIndex()), 0) - self.assertEqual(proxy.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(proxy.data(model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) + self.assertEqual( + proxy.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + proxy.data( + model.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) layout = QgsPrintLayout(project) - layout.setName('ccc') + layout.setName("ccc") self.assertTrue(manager.addLayout(layout)) self.assertEqual(proxy.rowCount(QModelIndex()), 1) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'ccc') - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout) - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) + self.assertEqual( + proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "ccc", + ) + self.assertEqual( + proxy.data( + proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout, + ) + self.assertEqual( + proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) layout2 = QgsPrintLayout(project) - layout2.setName('bbb') + layout2.setName("bbb") self.assertTrue(manager.addLayout(layout2)) self.assertEqual(proxy.rowCount(QModelIndex()), 2) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'bbb') - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout2) - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'ccc') - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout) - - layout.setName('aaa') - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'aaa') - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout) - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'bbb') - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout2) + self.assertEqual( + proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "bbb", + ) + self.assertEqual( + proxy.data( + proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout2, + ) + self.assertEqual( + proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "ccc", + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout, + ) + + layout.setName("aaa") + self.assertEqual( + proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "aaa", + ) + self.assertEqual( + proxy.data( + proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout, + ) + self.assertEqual( + proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "bbb", + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout2, + ) model.setAllowEmptyLayout(True) self.assertEqual(proxy.rowCount(QModelIndex()), 3) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'aaa') - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout) - self.assertEqual(proxy.data(proxy.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'bbb') - self.assertEqual(proxy.data(proxy.index(2, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout2) + self.assertEqual( + proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + proxy.data( + proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) + self.assertEqual( + proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "aaa", + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout, + ) + self.assertEqual( + proxy.data(proxy.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "bbb", + ) + self.assertEqual( + proxy.data( + proxy.index(2, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout2, + ) r = QgsReport(project) - r.setName('bbb2') + r.setName("bbb2") manager.addLayout(r) self.assertEqual(proxy.rowCount(QModelIndex()), 4) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'aaa') - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout) - self.assertEqual(proxy.data(proxy.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'bbb') - self.assertEqual(proxy.data(proxy.index(2, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout2) - self.assertEqual(proxy.data(proxy.index(3, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'bbb2') - self.assertEqual(proxy.data(proxy.index(3, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), r) - - proxy.setFilterString('xx') + self.assertEqual( + proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + proxy.data( + proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) + self.assertEqual( + proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "aaa", + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout, + ) + self.assertEqual( + proxy.data(proxy.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "bbb", + ) + self.assertEqual( + proxy.data( + proxy.index(2, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout2, + ) + self.assertEqual( + proxy.data(proxy.index(3, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "bbb2", + ) + self.assertEqual( + proxy.data( + proxy.index(3, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + r, + ) + + proxy.setFilterString("xx") self.assertEqual(proxy.rowCount(QModelIndex()), 1) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) - proxy.setFilterString('bb') + self.assertEqual( + proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + proxy.data( + proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) + proxy.setFilterString("bb") self.assertEqual(proxy.rowCount(QModelIndex()), 3) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'bbb') - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout2) - self.assertEqual(proxy.data(proxy.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'bbb2') - self.assertEqual(proxy.data(proxy.index(2, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), r) - proxy.setFilterString('') + self.assertEqual( + proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + proxy.data( + proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) + self.assertEqual( + proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "bbb", + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout2, + ) + self.assertEqual( + proxy.data(proxy.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "bbb2", + ) + self.assertEqual( + proxy.data( + proxy.index(2, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + r, + ) + proxy.setFilterString("") proxy.setFilters(QgsLayoutManagerProxyModel.Filter.FilterPrintLayouts) - self.assertEqual(proxy.filters(), QgsLayoutManagerProxyModel.Filter.FilterPrintLayouts) + self.assertEqual( + proxy.filters(), QgsLayoutManagerProxyModel.Filter.FilterPrintLayouts + ) self.assertEqual(proxy.rowCount(QModelIndex()), 3) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'aaa') - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout) - self.assertEqual(proxy.data(proxy.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'bbb') - self.assertEqual(proxy.data(proxy.index(2, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout2) - proxy.setFilterString('bb') + self.assertEqual( + proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + proxy.data( + proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) + self.assertEqual( + proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "aaa", + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout, + ) + self.assertEqual( + proxy.data(proxy.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "bbb", + ) + self.assertEqual( + proxy.data( + proxy.index(2, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout2, + ) + proxy.setFilterString("bb") self.assertEqual(proxy.rowCount(QModelIndex()), 2) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'bbb') - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), layout2) - proxy.setFilterString('') + self.assertEqual( + proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + proxy.data( + proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) + self.assertEqual( + proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "bbb", + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + layout2, + ) + proxy.setFilterString("") proxy.setFilters(QgsLayoutManagerProxyModel.Filter.FilterReports) - self.assertEqual(proxy.filters(), QgsLayoutManagerProxyModel.Filter.FilterReports) + self.assertEqual( + proxy.filters(), QgsLayoutManagerProxyModel.Filter.FilterReports + ) self.assertEqual(proxy.rowCount(QModelIndex()), 2) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'bbb2') - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), r) - - proxy.setFilterString('bb') + self.assertEqual( + proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + proxy.data( + proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) + self.assertEqual( + proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "bbb2", + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + r, + ) + + proxy.setFilterString("bb") self.assertEqual(proxy.rowCount(QModelIndex()), 2) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'bbb2') - self.assertEqual(proxy.data(proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), r) - proxy.setFilterString('aaa') + self.assertEqual( + proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + proxy.data( + proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) + self.assertEqual( + proxy.data(proxy.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "bbb2", + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + r, + ) + proxy.setFilterString("aaa") self.assertEqual(proxy.rowCount(QModelIndex()), 1) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(proxy.data(proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole), None) - proxy.setFilterString('') - - proxy.setFilters(QgsLayoutManagerProxyModel.Filter.FilterPrintLayouts | QgsLayoutManagerProxyModel.Filter.FilterReports) - self.assertEqual(proxy.filters(), QgsLayoutManagerProxyModel.Filter.FilterPrintLayouts | QgsLayoutManagerProxyModel.Filter.FilterReports) + self.assertEqual( + proxy.data(proxy.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + None, + ) + self.assertEqual( + proxy.data( + proxy.index(0, 0, QModelIndex()), QgsLayoutManagerModel.Role.LayoutRole + ), + None, + ) + proxy.setFilterString("") + + proxy.setFilters( + QgsLayoutManagerProxyModel.Filter.FilterPrintLayouts + | QgsLayoutManagerProxyModel.Filter.FilterReports + ) + self.assertEqual( + proxy.filters(), + QgsLayoutManagerProxyModel.Filter.FilterPrintLayouts + | QgsLayoutManagerProxyModel.Filter.FilterReports, + ) self.assertEqual(proxy.rowCount(QModelIndex()), 4) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutmap.py b/tests/src/python/test_qgslayoutmap.py index 50382bec0956..938d58d02094 100644 --- a/tests/src/python/test_qgslayoutmap.py +++ b/tests/src/python/test_qgslayoutmap.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2017 Nyall Dawson' -__date__ = '20/10/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "(C) 2017 Nyall Dawson" +__date__ = "20/10/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os @@ -17,11 +18,7 @@ QRectF, QSizeF, ) -from qgis.PyQt.QtGui import ( - QColor, - QPainter, - QImage -) +from qgis.PyQt.QtGui import QColor, QPainter, QImage from qgis.PyQt.QtTest import QSignalSpy from qgis.PyQt.QtXml import QDomDocument from qgis.core import ( @@ -74,24 +71,27 @@ def control_path_prefix(cls): @classmethod def setUpClass(cls): - super(TestQgsLayoutMap, cls).setUpClass() + super().setUpClass() cls.item_class = QgsLayoutItemMap def __init__(self, methodName): """Run once on class initialization.""" QgisTestCase.__init__(self, methodName) - myPath = os.path.join(TEST_DATA_DIR, 'rgb256x256.png') + myPath = os.path.join(TEST_DATA_DIR, "rgb256x256.png") rasterFileInfo = QFileInfo(myPath) - self.raster_layer = QgsRasterLayer(rasterFileInfo.filePath(), - rasterFileInfo.completeBaseName()) + self.raster_layer = QgsRasterLayer( + rasterFileInfo.filePath(), rasterFileInfo.completeBaseName() + ) rasterRenderer = QgsMultiBandColorRenderer( - self.raster_layer.dataProvider(), 1, 2, 3) + self.raster_layer.dataProvider(), 1, 2, 3 + ) self.raster_layer.setRenderer(rasterRenderer) - myPath = os.path.join(TEST_DATA_DIR, 'points.shp') + myPath = os.path.join(TEST_DATA_DIR, "points.shp") vector_file_info = QFileInfo(myPath) - self.vector_layer = QgsVectorLayer(vector_file_info.filePath(), - vector_file_info.completeBaseName(), 'ogr') + self.vector_layer = QgsVectorLayer( + vector_file_info.filePath(), vector_file_info.completeBaseName(), "ogr" + ) assert self.vector_layer.isValid() # pipe = mRasterLayer.pipe() @@ -125,16 +125,10 @@ def test_opacity(self): map.setItemOpacity(0.3) - self.assertFalse( - map.requiresRasterization() - ) - self.assertTrue( - map.containsAdvancedEffects() - ) + self.assertFalse(map.requiresRasterization()) + self.assertTrue(map.containsAdvancedEffects()) - self.assertTrue( - self.render_layout_check('composermap_opacity', layout) - ) + self.assertTrue(self.render_layout_check("composermap_opacity", layout)) def test_opacity_rendering_designer_preview(self): """ @@ -156,10 +150,12 @@ def test_opacity_rendering_designer_preview(self): map.setItemOpacity(0.3) page_item = l.pageCollection().page(0) - paper_rect = QRectF(page_item.pos().x(), - page_item.pos().y(), - page_item.rect().width(), - page_item.rect().height()) + paper_rect = QRectF( + page_item.pos().x(), + page_item.pos().y(), + page_item.rect().width(), + page_item.rect().height(), + ) im = QImage(1122, 794, QImage.Format.Format_ARGB32) im.fill(Qt.GlobalColor.transparent) @@ -170,7 +166,11 @@ def test_opacity_rendering_designer_preview(self): spy = QSignalSpy(map.previewRefreshed) - l.render(painter, QRectF(0, 0, painter.device().width(), painter.device().height()), paper_rect) + l.render( + painter, + QRectF(0, 0, painter.device().width(), painter.device().height()), + paper_rect, + ) painter.end() # we have to wait for the preview image to refresh, then redraw @@ -181,12 +181,18 @@ def test_opacity_rendering_designer_preview(self): im.fill(Qt.GlobalColor.transparent) painter = QPainter(im) painter.setRenderHint(QPainter.RenderHint.Antialiasing, True) - l.render(painter, QRectF(0, 0, painter.device().width(), painter.device().height()), paper_rect) + l.render( + painter, + QRectF(0, 0, painter.device().width(), painter.device().height()), + paper_rect, + ) painter.end() - self.assertTrue(self.image_check('composermap_opacity', - 'composermap_opacity', - im, allowed_mismatch=0)) + self.assertTrue( + self.image_check( + "composermap_opacity", "composermap_opacity", im, allowed_mismatch=0 + ) + ) def test_blend_mode(self): """ @@ -217,13 +223,9 @@ def test_blend_mode(self): map.setBlendMode(QPainter.CompositionMode.CompositionMode_Darken) - self.assertTrue( - map.requiresRasterization() - ) + self.assertTrue(map.requiresRasterization()) - self.assertTrue( - self.render_layout_check('composermap_blend_mode', layout) - ) + self.assertTrue(self.render_layout_check("composermap_blend_mode", layout)) def test_blend_mode_designer_preview(self): """ @@ -256,10 +258,12 @@ def test_blend_mode_designer_preview(self): map.setBlendMode(QPainter.CompositionMode.CompositionMode_Darken) page_item = layout.pageCollection().page(0) - paper_rect = QRectF(page_item.pos().x(), - page_item.pos().y(), - page_item.rect().width(), - page_item.rect().height()) + paper_rect = QRectF( + page_item.pos().x(), + page_item.pos().y(), + page_item.rect().width(), + page_item.rect().height(), + ) im = QImage(1122, 794, QImage.Format.Format_ARGB32) im.fill(Qt.GlobalColor.transparent) @@ -270,7 +274,11 @@ def test_blend_mode_designer_preview(self): spy = QSignalSpy(map.previewRefreshed) - layout.render(painter, QRectF(0, 0, painter.device().width(), painter.device().height()), paper_rect) + layout.render( + painter, + QRectF(0, 0, painter.device().width(), painter.device().height()), + paper_rect, + ) painter.end() # we have to wait for the preview image to refresh, then redraw @@ -281,12 +289,21 @@ def test_blend_mode_designer_preview(self): im.fill(Qt.GlobalColor.transparent) painter = QPainter(im) painter.setRenderHint(QPainter.RenderHint.Antialiasing, True) - layout.render(painter, QRectF(0, 0, painter.device().width(), painter.device().height()), paper_rect) + layout.render( + painter, + QRectF(0, 0, painter.device().width(), painter.device().height()), + paper_rect, + ) painter.end() - self.assertTrue(self.image_check('composermap_blend_mode', - 'composermap_blend_mode', - im, allowed_mismatch=0)) + self.assertTrue( + self.image_check( + "composermap_blend_mode", + "composermap_blend_mode", + im, + allowed_mismatch=0, + ) + ) def testMapCrs(self): # create layout with layout map @@ -296,7 +313,7 @@ def testMapCrs(self): layout.initializeDefaults() # check that new maps inherit project CRS - QgsProject.instance().setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + QgsProject.instance().setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(20, 20, 200, 100)) map.setFrameEnabled(True) @@ -305,31 +322,27 @@ def testMapCrs(self): map.setLayers([self.vector_layer]) layout.addLayoutItem(map) - self.assertEqual(map.crs().authid(), 'EPSG:4326') + self.assertEqual(map.crs().authid(), "EPSG:4326") self.assertFalse(map.presetCrs().isValid()) # overwrite CRS - map.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) - self.assertEqual(map.crs().authid(), 'EPSG:3857') - self.assertEqual(map.presetCrs().authid(), 'EPSG:3857') + map.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) + self.assertEqual(map.crs().authid(), "EPSG:3857") + self.assertEqual(map.presetCrs().authid(), "EPSG:3857") - self.assertTrue( - self.render_layout_check('composermap_crs3857', layout) - ) + self.assertTrue(self.render_layout_check("composermap_crs3857", layout)) # overwrite CRS - map.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) - self.assertEqual(map.presetCrs().authid(), 'EPSG:4326') - self.assertEqual(map.crs().authid(), 'EPSG:4326') + map.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) + self.assertEqual(map.presetCrs().authid(), "EPSG:4326") + self.assertEqual(map.crs().authid(), "EPSG:4326") rectangle = QgsRectangle(-124, 17, -78, 52) map.zoomToExtent(rectangle) - self.assertTrue( - self.render_layout_check('composermap_crs4326', layout) - ) + self.assertTrue(self.render_layout_check("composermap_crs4326", layout)) # change back to project CRS map.setCrs(QgsCoordinateReferenceSystem()) - self.assertEqual(map.crs().authid(), 'EPSG:4326') + self.assertEqual(map.crs().authid(), "EPSG:4326") self.assertFalse(map.presetCrs().isValid()) def testContainsAdvancedEffects(self): @@ -341,7 +354,9 @@ def testContainsAdvancedEffects(self): self.assertFalse(map.containsAdvancedEffects()) self.vector_layer.setBlendMode(QPainter.CompositionMode.CompositionMode_Darken) result = map.containsAdvancedEffects() - self.vector_layer.setBlendMode(QPainter.CompositionMode.CompositionMode_SourceOver) + self.vector_layer.setBlendMode( + QPainter.CompositionMode.CompositionMode_SourceOver + ) self.assertTrue(result) def testRasterization(self): @@ -361,7 +376,9 @@ def testRasterization(self): map.setBackgroundColor(QColor(1, 1, 1, 1)) self.assertTrue(map.requiresRasterization()) - self.vector_layer.setBlendMode(QPainter.CompositionMode.CompositionMode_SourceOver) + self.vector_layer.setBlendMode( + QPainter.CompositionMode.CompositionMode_SourceOver + ) def testLabelMargin(self): """ @@ -392,14 +409,16 @@ def testLabelMargin(self): p = QgsProject() engine_settings = QgsLabelingEngineSettings() - engine_settings.setFlag(QgsLabelingEngineSettings.Flag.UsePartialCandidates, False) + engine_settings.setFlag( + QgsLabelingEngineSettings.Flag.UsePartialCandidates, False + ) engine_settings.setFlag(QgsLabelingEngineSettings.Flag.DrawLabelRectOnly, True) p.setLabelingEngineSettings(engine_settings) p.addMapLayer(vl) layout = QgsLayout(p) layout.initializeDefaults() - p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + p.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(10, 10, 180, 180)) map.setFrameEnabled(True) @@ -407,36 +426,37 @@ def testLabelMargin(self): map.setLayers([vl]) layout.addLayoutItem(map) - self.assertTrue( - self.render_layout_check('composermap_label_nomargin', layout) - ) + self.assertTrue(self.render_layout_check("composermap_label_nomargin", layout)) - map.setLabelMargin(QgsLayoutMeasurement(15, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertTrue( - self.render_layout_check('composermap_label_margin', layout) + map.setLabelMargin( + QgsLayoutMeasurement(15, QgsUnitTypes.LayoutUnit.LayoutMillimeters) ) + self.assertTrue(self.render_layout_check("composermap_label_margin", layout)) - map.setLabelMargin(QgsLayoutMeasurement(3, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - self.assertTrue( - self.render_layout_check('composermap_label_cm_margin', layout) + map.setLabelMargin( + QgsLayoutMeasurement(3, QgsUnitTypes.LayoutUnit.LayoutCentimeters) ) + self.assertTrue(self.render_layout_check("composermap_label_cm_margin", layout)) map.setMapRotation(45) map.zoomToExtent(vl.extent()) map.setScale(map.scale() * 1.2) - map.setLabelMargin(QgsLayoutMeasurement(3, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + map.setLabelMargin( + QgsLayoutMeasurement(3, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) self.assertTrue( - self.render_layout_check('composermap_rotated_label_margin', layout) + self.render_layout_check("composermap_rotated_label_margin", layout) ) # data defined map.setMapRotation(0) map.zoomToExtent(vl.extent()) - map.dataDefinedProperties().setProperty(QgsLayoutObject.DataDefinedProperty.MapLabelMargin, QgsProperty.fromExpression('1+3')) - map.refresh() - self.assertTrue( - self.render_layout_check('composermap_dd_label_margin', layout) + map.dataDefinedProperties().setProperty( + QgsLayoutObject.DataDefinedProperty.MapLabelMargin, + QgsProperty.fromExpression("1+3"), ) + map.refresh() + self.assertTrue(self.render_layout_check("composermap_dd_label_margin", layout)) def testPartialLabels(self): """ @@ -467,14 +487,16 @@ def testPartialLabels(self): p = QgsProject() engine_settings = QgsLabelingEngineSettings() - engine_settings.setFlag(QgsLabelingEngineSettings.Flag.UsePartialCandidates, False) + engine_settings.setFlag( + QgsLabelingEngineSettings.Flag.UsePartialCandidates, False + ) engine_settings.setFlag(QgsLabelingEngineSettings.Flag.DrawLabelRectOnly, True) p.setLabelingEngineSettings(engine_settings) p.addMapLayer(vl) layout = QgsLayout(p) layout.initializeDefaults() - p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + p.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(10, 10, 180, 180)) map.setFrameEnabled(True) @@ -483,18 +505,18 @@ def testPartialLabels(self): layout.addLayoutItem(map) # default should always be to hide partial labels - self.assertFalse(map.mapFlags() & QgsLayoutItemMap.MapItemFlag.ShowPartialLabels) + self.assertFalse( + map.mapFlags() & QgsLayoutItemMap.MapItemFlag.ShowPartialLabels + ) # hiding partial labels (the default) map.setMapFlags(QgsLayoutItemMap.MapItemFlags()) - self.assertTrue( - self.render_layout_check('composermap_label_nomargin', layout) - ) + self.assertTrue(self.render_layout_check("composermap_label_nomargin", layout)) # showing partial labels map.setMapFlags(QgsLayoutItemMap.MapItemFlag.ShowPartialLabels) self.assertTrue( - self.render_layout_check('composermap_show_partial_labels', layout) + self.render_layout_check("composermap_show_partial_labels", layout) ) def testBlockingItems(self): @@ -532,44 +554,52 @@ def testBlockingItems(self): p.addMapLayer(vl) layout = QgsLayout(p) layout.initializeDefaults() - p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + p.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(10, 10, 180, 180)) map.setFrameEnabled(True) map.zoomToExtent(vl.extent()) map.setLayers([vl]) - map.setId('map') + map.setId("map") layout.addLayoutItem(map) map2 = QgsLayoutItemMap(layout) map2.attemptSetSceneRect(QRectF(0, 5, 50, 80)) map2.setFrameEnabled(True) map2.setBackgroundEnabled(False) - map2.setId('map2') + map2.setId("map2") layout.addLayoutItem(map2) map3 = QgsLayoutItemMap(layout) map3.attemptSetSceneRect(QRectF(150, 160, 50, 50)) map3.setFrameEnabled(True) map3.setBackgroundEnabled(False) - map3.setId('map3') + map3.setId("map3") layout.addLayoutItem(map3) map.addLabelBlockingItem(map2) map.addLabelBlockingItem(map3) map.setMapFlags(QgsLayoutItemMap.MapItemFlags()) - self.assertTrue( - self.render_layout_check('composermap_label_blockers', layout) - ) + self.assertTrue(self.render_layout_check("composermap_label_blockers", layout)) doc = QDomDocument("testdoc") elem = layout.writeXml(doc, QgsReadWriteContext()) l2 = QgsLayout(p) self.assertTrue(l2.readXml(elem, doc, QgsReadWriteContext())) - map_restore = [i for i in l2.items() if isinstance(i, QgsLayoutItemMap) and i.id() == 'map'][0] - map2_restore = [i for i in l2.items() if isinstance(i, QgsLayoutItemMap) and i.id() == 'map2'][0] - map3_restore = [i for i in l2.items() if isinstance(i, QgsLayoutItemMap) and i.id() == 'map3'][0] + map_restore = [ + i for i in l2.items() if isinstance(i, QgsLayoutItemMap) and i.id() == "map" + ][0] + map2_restore = [ + i + for i in l2.items() + if isinstance(i, QgsLayoutItemMap) and i.id() == "map2" + ][0] + map3_restore = [ + i + for i in l2.items() + if isinstance(i, QgsLayoutItemMap) and i.id() == "map3" + ][0] self.assertTrue(map_restore.isLabelBlockingItem(map2_restore)) self.assertTrue(map_restore.isLabelBlockingItem(map3_restore)) @@ -581,54 +611,60 @@ def testTheme(self): spy = QSignalSpy(map.themeChanged) - map.setFollowVisibilityPresetName('theme') + map.setFollowVisibilityPresetName("theme") self.assertFalse(map.followVisibilityPreset()) - self.assertEqual(map.followVisibilityPresetName(), 'theme') + self.assertEqual(map.followVisibilityPresetName(), "theme") # should not be emitted - followVisibilityPreset is False self.assertEqual(len(spy), 0) - map.setFollowVisibilityPresetName('theme2') - self.assertEqual(map.followVisibilityPresetName(), 'theme2') + map.setFollowVisibilityPresetName("theme2") + self.assertEqual(map.followVisibilityPresetName(), "theme2") self.assertEqual(len(spy), 0) - map.setFollowVisibilityPresetName('') + map.setFollowVisibilityPresetName("") map.setFollowVisibilityPreset(True) # should not be emitted - followVisibilityPresetName is empty self.assertEqual(len(spy), 0) self.assertFalse(map.followVisibilityPresetName()) self.assertTrue(map.followVisibilityPreset()) - map.setFollowVisibilityPresetName('theme') + map.setFollowVisibilityPresetName("theme") self.assertEqual(len(spy), 1) - self.assertEqual(spy[-1][0], 'theme') - map.setFollowVisibilityPresetName('theme') + self.assertEqual(spy[-1][0], "theme") + map.setFollowVisibilityPresetName("theme") self.assertEqual(len(spy), 1) - map.setFollowVisibilityPresetName('theme2') + map.setFollowVisibilityPresetName("theme2") self.assertEqual(len(spy), 2) - self.assertEqual(spy[-1][0], 'theme2') + self.assertEqual(spy[-1][0], "theme2") map.setFollowVisibilityPreset(False) self.assertEqual(len(spy), 3) self.assertFalse(spy[-1][0]) map.setFollowVisibilityPreset(False) self.assertEqual(len(spy), 3) - map.setFollowVisibilityPresetName('theme3') + map.setFollowVisibilityPresetName("theme3") self.assertEqual(len(spy), 3) map.setFollowVisibilityPreset(True) self.assertEqual(len(spy), 4) - self.assertEqual(spy[-1][0], 'theme3') + self.assertEqual(spy[-1][0], "theme3") map.setFollowVisibilityPreset(True) self.assertEqual(len(spy), 4) # data defined theme - map.dataDefinedProperties().setProperty(QgsLayoutObject.DataDefinedProperty.MapStylePreset, QgsProperty.fromValue('theme4')) + map.dataDefinedProperties().setProperty( + QgsLayoutObject.DataDefinedProperty.MapStylePreset, + QgsProperty.fromValue("theme4"), + ) map.refresh() self.assertEqual(len(spy), 5) - self.assertEqual(spy[-1][0], 'theme4') + self.assertEqual(spy[-1][0], "theme4") map.refresh() self.assertEqual(len(spy), 5) - map.dataDefinedProperties().setProperty(QgsLayoutObject.DataDefinedProperty.MapStylePreset, QgsProperty.fromValue('theme6')) + map.dataDefinedProperties().setProperty( + QgsLayoutObject.DataDefinedProperty.MapStylePreset, + QgsProperty.fromValue("theme6"), + ) map.refresh() self.assertEqual(len(spy), 6) - self.assertEqual(spy[-1][0], 'theme6') + self.assertEqual(spy[-1][0], "theme6") def testClipping(self): format = QgsTextFormat() @@ -644,7 +680,12 @@ def testClipping(self): vl = QgsVectorLayer("Polygon?crs=epsg:4326&field=id:integer", "vl", "memory") - props = {"color": "127,255,127", 'outline_style': 'solid', 'outline_width': '1', 'outline_color': '0,0,255'} + props = { + "color": "127,255,127", + "outline_style": "solid", + "outline_width": "1", + "outline_color": "0,0,255", + } fillSymbol = QgsFillSymbol.createSimple(props) renderer = QgsSingleSymbolRenderer(fillSymbol) vl.setRenderer(renderer) @@ -663,7 +704,7 @@ def testClipping(self): p.addMapLayer(vl) layout = QgsLayout(p) layout.initializeDefaults() - p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + p.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(10, 10, 180, 180)) map.setFrameEnabled(False) @@ -675,19 +716,19 @@ def testClipping(self): layout.addLayoutItem(shape) shape.setShapeType(QgsLayoutItemShape.Shape.Ellipse) shape.attemptSetSceneRect(QRectF(10, 10, 180, 180)) - props = {"color": "0,0,0,0", 'outline_style': 'no'} + props = {"color": "0,0,0,0", "outline_style": "no"} fillSymbol = QgsFillSymbol.createSimple(props) shape.setSymbol(fillSymbol) map.itemClippingSettings().setEnabled(True) map.itemClippingSettings().setSourceItem(shape) map.itemClippingSettings().setForceLabelsInsideClipPath(False) - map.itemClippingSettings().setFeatureClippingType(QgsMapClippingRegion.FeatureClippingType.ClipToIntersection) - - self.assertTrue( - self.render_layout_check('composermap_itemclip', layout) + map.itemClippingSettings().setFeatureClippingType( + QgsMapClippingRegion.FeatureClippingType.ClipToIntersection ) + self.assertTrue(self.render_layout_check("composermap_itemclip", layout)) + def testClippingForceLabelsInside(self): format = QgsTextFormat() format.setFont(QgsFontUtils.getStandardTestFont("Bold")) @@ -702,7 +743,12 @@ def testClippingForceLabelsInside(self): vl = QgsVectorLayer("Polygon?crs=epsg:4326&field=id:integer", "vl", "memory") - props = {"color": "127,255,127", 'outline_style': 'solid', 'outline_width': '1', 'outline_color': '0,0,255'} + props = { + "color": "127,255,127", + "outline_style": "solid", + "outline_width": "1", + "outline_color": "0,0,255", + } fillSymbol = QgsFillSymbol.createSimple(props) renderer = QgsSingleSymbolRenderer(fillSymbol) vl.setRenderer(renderer) @@ -721,7 +767,7 @@ def testClippingForceLabelsInside(self): p.addMapLayer(vl) layout = QgsLayout(p) layout.initializeDefaults() - p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + p.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(10, 10, 180, 180)) map.setFrameEnabled(False) @@ -733,17 +779,19 @@ def testClippingForceLabelsInside(self): layout.addLayoutItem(shape) shape.setShapeType(QgsLayoutItemShape.Shape.Ellipse) shape.attemptSetSceneRect(QRectF(10, 10, 180, 180)) - props = {"color": "0,0,0,0", 'outline_style': 'no'} + props = {"color": "0,0,0,0", "outline_style": "no"} fillSymbol = QgsFillSymbol.createSimple(props) shape.setSymbol(fillSymbol) map.itemClippingSettings().setEnabled(True) map.itemClippingSettings().setSourceItem(shape) map.itemClippingSettings().setForceLabelsInsideClipPath(True) - map.itemClippingSettings().setFeatureClippingType(QgsMapClippingRegion.FeatureClippingType.ClipPainterOnly) + map.itemClippingSettings().setFeatureClippingType( + QgsMapClippingRegion.FeatureClippingType.ClipPainterOnly + ) self.assertTrue( - self.render_layout_check('composermap_itemclip_force_labels_inside', layout) + self.render_layout_check("composermap_itemclip_force_labels_inside", layout) ) def testClippingOverview(self): @@ -760,7 +808,12 @@ def testClippingOverview(self): vl = QgsVectorLayer("Polygon?crs=epsg:4326&field=id:integer", "vl", "memory") - props = {"color": "127,255,127", 'outline_style': 'solid', 'outline_width': '1', 'outline_color': '0,0,255'} + props = { + "color": "127,255,127", + "outline_style": "solid", + "outline_width": "1", + "outline_color": "0,0,255", + } fillSymbol = QgsFillSymbol.createSimple(props) renderer = QgsSingleSymbolRenderer(fillSymbol) vl.setRenderer(renderer) @@ -783,7 +836,7 @@ def testClippingOverview(self): p.addMapLayer(vl2) layout = QgsLayout(p) layout.initializeDefaults() - p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + p.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(10, 10, 180, 180)) map.setFrameEnabled(False) @@ -801,7 +854,12 @@ def testClippingOverview(self): layout.addLayoutItem(map2) overview = QgsLayoutItemMapOverview("t", map2) overview.setLinkedMap(map) - props = {"color": "0,0,0,0", 'outline_style': 'solid', 'outline_width': '1', 'outline_color': '0,0,255'} + props = { + "color": "0,0,0,0", + "outline_style": "solid", + "outline_width": "1", + "outline_color": "0,0,255", + } fillSymbol = QgsFillSymbol.createSimple(props) overview.setFrameSymbol(fillSymbol) @@ -811,17 +869,19 @@ def testClippingOverview(self): layout.addLayoutItem(shape) shape.setShapeType(QgsLayoutItemShape.Shape.Ellipse) shape.attemptSetSceneRect(QRectF(10, 10, 180, 180)) - props = {"color": "0,0,0,0", 'outline_style': 'no'} + props = {"color": "0,0,0,0", "outline_style": "no"} fillSymbol = QgsFillSymbol.createSimple(props) shape.setSymbol(fillSymbol) map.itemClippingSettings().setEnabled(True) map.itemClippingSettings().setSourceItem(shape) map.itemClippingSettings().setForceLabelsInsideClipPath(False) - map.itemClippingSettings().setFeatureClippingType(QgsMapClippingRegion.FeatureClippingType.ClipToIntersection) + map.itemClippingSettings().setFeatureClippingType( + QgsMapClippingRegion.FeatureClippingType.ClipToIntersection + ) self.assertTrue( - self.render_layout_check('composermap_itemclip_overview', layout) + self.render_layout_check("composermap_itemclip_overview", layout) ) def testClippingHideClipSource(self): @@ -841,7 +901,12 @@ def testClippingHideClipSource(self): vl = QgsVectorLayer("Polygon?crs=epsg:4326&field=id:integer", "vl", "memory") - props = {"color": "127,255,127", 'outline_style': 'solid', 'outline_width': '1', 'outline_color': '0,0,255'} + props = { + "color": "127,255,127", + "outline_style": "solid", + "outline_width": "1", + "outline_color": "0,0,255", + } fillSymbol = QgsFillSymbol.createSimple(props) renderer = QgsSingleSymbolRenderer(fillSymbol) vl.setRenderer(renderer) @@ -860,7 +925,7 @@ def testClippingHideClipSource(self): p.addMapLayer(vl) layout = QgsLayout(p) layout.initializeDefaults() - p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + p.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(10, 10, 180, 180)) map.setFrameEnabled(False) @@ -876,10 +941,12 @@ def testClippingHideClipSource(self): map.itemClippingSettings().setEnabled(True) map.itemClippingSettings().setSourceItem(shape) map.itemClippingSettings().setForceLabelsInsideClipPath(False) - map.itemClippingSettings().setFeatureClippingType(QgsMapClippingRegion.FeatureClippingType.ClipToIntersection) + map.itemClippingSettings().setFeatureClippingType( + QgsMapClippingRegion.FeatureClippingType.ClipToIntersection + ) self.assertTrue( - self.render_layout_check('composermap_itemclip_nodrawsource', layout) + self.render_layout_check("composermap_itemclip_nodrawsource", layout) ) def testClippingBackgroundFrame(self): @@ -888,7 +955,12 @@ def testClippingBackgroundFrame(self): """ vl = QgsVectorLayer("Polygon?crs=epsg:4326&field=id:integer", "vl", "memory") - props = {"color": "127,255,127", 'outline_style': 'solid', 'outline_width': '1', 'outline_color': '0,0,255'} + props = { + "color": "127,255,127", + "outline_style": "solid", + "outline_width": "1", + "outline_color": "0,0,255", + } fillSymbol = QgsFillSymbol.createSimple(props) renderer = QgsSingleSymbolRenderer(fillSymbol) vl.setRenderer(renderer) @@ -904,11 +976,13 @@ def testClippingBackgroundFrame(self): p.addMapLayer(vl) layout = QgsLayout(p) layout.initializeDefaults() - p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + p.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(10, 10, 180, 180)) map.setFrameEnabled(True) - map.setFrameStrokeWidth(QgsLayoutMeasurement(2, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + map.setFrameStrokeWidth( + QgsLayoutMeasurement(2, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) map.setBackgroundEnabled(True) map.setBackgroundColor(QColor(200, 255, 200)) map.zoomToExtent(vl.extent()) @@ -922,10 +996,12 @@ def testClippingBackgroundFrame(self): map.itemClippingSettings().setEnabled(True) map.itemClippingSettings().setSourceItem(shape) - map.itemClippingSettings().setFeatureClippingType(QgsMapClippingRegion.FeatureClippingType.ClipPainterOnly) + map.itemClippingSettings().setFeatureClippingType( + QgsMapClippingRegion.FeatureClippingType.ClipPainterOnly + ) self.assertTrue( - self.render_layout_check('composermap_itemclip_background', layout) + self.render_layout_check("composermap_itemclip_background", layout) ) def testMainAnnotationLayer(self): @@ -934,19 +1010,22 @@ def testMainAnnotationLayer(self): """ p = QgsProject() - vl = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string", - "layer", "memory") - sym3 = QgsFillSymbol.createSimple({'color': '#b200b2'}) + vl = QgsVectorLayer( + "Polygon?crs=epsg:4326&field=fldtxt:string", "layer", "memory" + ) + sym3 = QgsFillSymbol.createSimple({"color": "#b200b2"}) vl.renderer().setSymbol(sym3) p.addMapLayer(vl) layout = QgsLayout(p) layout.initializeDefaults() - p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + p.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(10, 10, 180, 180)) map.setFrameEnabled(True) - map.setFrameStrokeWidth(QgsLayoutMeasurement(2, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + map.setFrameStrokeWidth( + QgsLayoutMeasurement(2, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) map.setBackgroundEnabled(True) map.setBackgroundColor(QColor(200, 255, 200)) map.zoomToExtent(QgsRectangle(10, 30, 20, 35)) @@ -960,21 +1039,19 @@ def testMainAnnotationLayer(self): # no annotation yet... self.assertTrue( - self.render_layout_check('composermap_annotation_empty', layout) + self.render_layout_check("composermap_annotation_empty", layout) ) annotation_layer = p.mainAnnotationLayer() - annotation_layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + annotation_layer.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) annotation_geom = QgsGeometry.fromRect(QgsRectangle(12, 30, 18, 33)) annotation = QgsAnnotationPolygonItem(annotation_geom.constGet().clone()) - sym3 = QgsFillSymbol.createSimple({'color': '#ff0000', 'outline_style': 'no'}) + sym3 = QgsFillSymbol.createSimple({"color": "#ff0000", "outline_style": "no"}) annotation.setSymbol(sym3) annotation_layer.addItem(annotation) # annotation must be drawn above map layers - self.assertTrue( - self.render_layout_check('composermap_annotation_item', layout) - ) + self.assertTrue(self.render_layout_check("composermap_annotation_item", layout)) def testCrsChanged(self): """ @@ -982,34 +1059,37 @@ def testCrsChanged(self): """ p = QgsProject() layout = QgsLayout(p) - p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + p.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) map = QgsLayoutItemMap(layout) spy = QSignalSpy(map.crsChanged) # map has no explicit crs set, so follows project crs => signal should be emitted # when project crs is changed - p.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) + p.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertEqual(len(spy), 1) - p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + p.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) self.assertEqual(len(spy), 2) # set explicit crs on map item - map.setCrs(QgsCoordinateReferenceSystem('EPSG:28356')) + map.setCrs(QgsCoordinateReferenceSystem("EPSG:28356")) self.assertEqual(len(spy), 3) - map.setCrs(QgsCoordinateReferenceSystem('EPSG:28356')) + map.setCrs(QgsCoordinateReferenceSystem("EPSG:28356")) self.assertEqual(len(spy), 3) - map.setCrs(QgsCoordinateReferenceSystem('EPSG:28355')) + map.setCrs(QgsCoordinateReferenceSystem("EPSG:28355")) self.assertEqual(len(spy), 4) # should not care about project crs changes anymore.. - p.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) + p.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertEqual(len(spy), 4) # set back to project crs map.setCrs(QgsCoordinateReferenceSystem()) self.assertEqual(len(spy), 5) - map.setCrs(QgsCoordinateReferenceSystem('EPSG:28355')) + map.setCrs(QgsCoordinateReferenceSystem("EPSG:28355")) self.assertEqual(len(spy), 6) # data defined crs - map.dataDefinedProperties().setProperty(QgsLayoutObject.DataDefinedProperty.MapCrs, QgsProperty.fromValue('EPSG:4283')) + map.dataDefinedProperties().setProperty( + QgsLayoutObject.DataDefinedProperty.MapCrs, + QgsProperty.fromValue("EPSG:4283"), + ) self.assertEqual(len(spy), 6) map.refresh() self.assertEqual(len(spy), 7) @@ -1026,5 +1106,5 @@ def testMapSettingsDpiTarget(self): self.assertEqual(ms.dpiTarget(), 111.1) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutmapgrid.py b/tests/src/python/test_qgslayoutmapgrid.py index 9b7bea23d734..a6ec279bd93e 100644 --- a/tests/src/python/test_qgslayoutmapgrid.py +++ b/tests/src/python/test_qgslayoutmapgrid.py @@ -5,6 +5,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + __author__ = "(C) 2017 by Nyall Dawson" __date__ = "20/10/2017" __copyright__ = "Copyright 2012, The QGIS Project" @@ -23,7 +24,7 @@ QgsProject, QgsProperty, QgsRectangle, - QgsTextFormat + QgsTextFormat, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -67,22 +68,28 @@ def testGrid(self): map.grid().setAnnotationTextFormat(format) map.grid().setAnnotationPrecision(0) map.grid().setAnnotationDisplay( - QgsLayoutItemMapGrid.DisplayMode.HideAll, QgsLayoutItemMapGrid.BorderSide.Left + QgsLayoutItemMapGrid.DisplayMode.HideAll, + QgsLayoutItemMapGrid.BorderSide.Left, ) map.grid().setAnnotationPosition( - QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, QgsLayoutItemMapGrid.BorderSide.Right + QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, + QgsLayoutItemMapGrid.BorderSide.Right, ) map.grid().setAnnotationDisplay( - QgsLayoutItemMapGrid.DisplayMode.HideAll, QgsLayoutItemMapGrid.BorderSide.Top + QgsLayoutItemMapGrid.DisplayMode.HideAll, + QgsLayoutItemMapGrid.BorderSide.Top, ) map.grid().setAnnotationPosition( - QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, QgsLayoutItemMapGrid.BorderSide.Bottom + QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, + QgsLayoutItemMapGrid.BorderSide.Bottom, ) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, QgsLayoutItemMapGrid.BorderSide.Right + QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, + QgsLayoutItemMapGrid.BorderSide.Right, ) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, QgsLayoutItemMapGrid.BorderSide.Bottom + QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, + QgsLayoutItemMapGrid.BorderSide.Bottom, ) map.grid().setBlendMode(QPainter.CompositionMode.CompositionMode_Overlay) map.updateBoundingRect() @@ -208,8 +215,9 @@ def testZebraStyle(self): map.updateBoundingRect() self.assertTrue( - self.render_layout_check("composermap_zebrastyle", layout, - allowed_mismatch=100) + self.render_layout_check( + "composermap_zebrastyle", layout, allowed_mismatch=100 + ) ) def testZebraStyleSides(self): @@ -238,31 +246,40 @@ def testZebraStyleSides(self): map.grid().setEnabled(True) map.grid().setFrameSideFlag(QgsLayoutItemMapGrid.FrameSideFlag.FrameLeft, True) - map.grid().setFrameSideFlag(QgsLayoutItemMapGrid.FrameSideFlag.FrameRight, False) + map.grid().setFrameSideFlag( + QgsLayoutItemMapGrid.FrameSideFlag.FrameRight, False + ) map.grid().setFrameSideFlag(QgsLayoutItemMapGrid.FrameSideFlag.FrameTop, False) - map.grid().setFrameSideFlag(QgsLayoutItemMapGrid.FrameSideFlag.FrameBottom, False) + map.grid().setFrameSideFlag( + QgsLayoutItemMapGrid.FrameSideFlag.FrameBottom, False + ) map.updateBoundingRect() self.assertTrue( - self.render_layout_check("composermap_zebrastyle_left", layout, - allowed_mismatch=100) + self.render_layout_check( + "composermap_zebrastyle_left", layout, allowed_mismatch=100 + ) ) map.grid().setFrameSideFlag(QgsLayoutItemMapGrid.FrameSideFlag.FrameTop, True) map.updateBoundingRect() self.assertTrue( - self.render_layout_check("composermap_zebrastyle_lefttop", layout, - allowed_mismatch=100) + self.render_layout_check( + "composermap_zebrastyle_lefttop", layout, allowed_mismatch=100 + ) ) map.grid().setFrameSideFlag(QgsLayoutItemMapGrid.FrameSideFlag.FrameRight, True) map.updateBoundingRect() self.assertTrue( - self.render_layout_check("composermap_zebrastyle_lefttopright", layout, - allowed_mismatch=100) + self.render_layout_check( + "composermap_zebrastyle_lefttopright", layout, allowed_mismatch=100 + ) ) - map.grid().setFrameSideFlag(QgsLayoutItemMapGrid.FrameSideFlag.FrameBottom, True) + map.grid().setFrameSideFlag( + QgsLayoutItemMapGrid.FrameSideFlag.FrameBottom, True + ) map.grid().setFrameStyle(QgsLayoutItemMapGrid.FrameStyle.NoFrame) def testInteriorTicks(self): @@ -289,8 +306,9 @@ def testInteriorTicks(self): map.updateBoundingRect() self.assertTrue( - self.render_layout_check("composermap_interiorticks", layout, - allowed_mismatch=100) + self.render_layout_check( + "composermap_interiorticks", layout, allowed_mismatch=100 + ) ) def testAnnotationsVariations(self): @@ -380,27 +398,32 @@ def testAnnotationsVariations(self): map.grid().setAnnotationPosition(pos, QgsLayoutItemMapGrid.BorderSide.Top) map.grid().setAnnotationPosition(pos, QgsLayoutItemMapGrid.BorderSide.Right) - map.grid().setAnnotationPosition(pos, QgsLayoutItemMapGrid.BorderSide.Bottom) + map.grid().setAnnotationPosition( + pos, QgsLayoutItemMapGrid.BorderSide.Bottom + ) map.grid().setAnnotationPosition(pos, QgsLayoutItemMapGrid.BorderSide.Left) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.Vertical, QgsLayoutItemMapGrid.BorderSide.Top + QgsLayoutItemMapGrid.AnnotationDirection.Vertical, + QgsLayoutItemMapGrid.BorderSide.Top, ) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, QgsLayoutItemMapGrid.BorderSide.Right + QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, + QgsLayoutItemMapGrid.BorderSide.Right, ) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.BoundaryDirection, QgsLayoutItemMapGrid.BorderSide.Bottom + QgsLayoutItemMapGrid.AnnotationDirection.BoundaryDirection, + QgsLayoutItemMapGrid.BorderSide.Bottom, ) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.VerticalDescending, QgsLayoutItemMapGrid.BorderSide.Left + QgsLayoutItemMapGrid.AnnotationDirection.VerticalDescending, + QgsLayoutItemMapGrid.BorderSide.Left, ) map.updateBoundingRect() self.assertTrue( - self.render_layout_check("composermap_annotations_variations", - layout) + self.render_layout_check("composermap_annotations_variations", layout) ) def testAnnotationsVariationsRotated(self): @@ -493,27 +516,34 @@ def testAnnotationsVariationsRotated(self): map.grid().setAnnotationPosition(pos, QgsLayoutItemMapGrid.BorderSide.Top) map.grid().setAnnotationPosition(pos, QgsLayoutItemMapGrid.BorderSide.Right) - map.grid().setAnnotationPosition(pos, QgsLayoutItemMapGrid.BorderSide.Bottom) + map.grid().setAnnotationPosition( + pos, QgsLayoutItemMapGrid.BorderSide.Bottom + ) map.grid().setAnnotationPosition(pos, QgsLayoutItemMapGrid.BorderSide.Left) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.AboveTick, QgsLayoutItemMapGrid.BorderSide.Top + QgsLayoutItemMapGrid.AnnotationDirection.AboveTick, + QgsLayoutItemMapGrid.BorderSide.Top, ) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.OnTick, QgsLayoutItemMapGrid.BorderSide.Right + QgsLayoutItemMapGrid.AnnotationDirection.OnTick, + QgsLayoutItemMapGrid.BorderSide.Right, ) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.UnderTick, QgsLayoutItemMapGrid.BorderSide.Bottom + QgsLayoutItemMapGrid.AnnotationDirection.UnderTick, + QgsLayoutItemMapGrid.BorderSide.Bottom, ) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.BoundaryDirection, QgsLayoutItemMapGrid.BorderSide.Left + QgsLayoutItemMapGrid.AnnotationDirection.BoundaryDirection, + QgsLayoutItemMapGrid.BorderSide.Left, ) map.updateBoundingRect() self.assertTrue( - self.render_layout_check("composermap_annotations_variations_rotated", - layout) + self.render_layout_check( + "composermap_annotations_variations_rotated", layout + ) ) def testAnnotationsVariationsRotatedThresholds(self): @@ -578,7 +608,9 @@ def testAnnotationsVariationsRotatedThresholds(self): map.grid().setAnnotationEnabled(True) map.grid().setGridLineColor(QColor(0, 255, 0)) map.grid().setGridLineWidth(0.5) - map.grid().setRotatedTicksLengthMode(QgsLayoutItemMapGrid.TickLengthMode.NormalizedTicks) + map.grid().setRotatedTicksLengthMode( + QgsLayoutItemMapGrid.TickLengthMode.NormalizedTicks + ) map.grid().setAnnotationFont(getTestFont("Bold", 15)) map.grid().setAnnotationFontColor(QColor(0, 0, 255, 150)) map.grid().setAnnotationPrecision(0) @@ -588,20 +620,26 @@ def testAnnotationsVariationsRotatedThresholds(self): map.grid().setAnnotationPosition(pos, QgsLayoutItemMapGrid.BorderSide.Top) map.grid().setAnnotationPosition(pos, QgsLayoutItemMapGrid.BorderSide.Right) - map.grid().setAnnotationPosition(pos, QgsLayoutItemMapGrid.BorderSide.Bottom) + map.grid().setAnnotationPosition( + pos, QgsLayoutItemMapGrid.BorderSide.Bottom + ) map.grid().setAnnotationPosition(pos, QgsLayoutItemMapGrid.BorderSide.Left) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.OnTick, QgsLayoutItemMapGrid.BorderSide.Top + QgsLayoutItemMapGrid.AnnotationDirection.OnTick, + QgsLayoutItemMapGrid.BorderSide.Top, ) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.OnTick, QgsLayoutItemMapGrid.BorderSide.Right + QgsLayoutItemMapGrid.AnnotationDirection.OnTick, + QgsLayoutItemMapGrid.BorderSide.Right, ) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.OnTick, QgsLayoutItemMapGrid.BorderSide.Bottom + QgsLayoutItemMapGrid.AnnotationDirection.OnTick, + QgsLayoutItemMapGrid.BorderSide.Bottom, ) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.OnTick, QgsLayoutItemMapGrid.BorderSide.Left + QgsLayoutItemMapGrid.AnnotationDirection.OnTick, + QgsLayoutItemMapGrid.BorderSide.Left, ) if limit_rot: @@ -615,8 +653,9 @@ def testAnnotationsVariationsRotatedThresholds(self): map.updateBoundingRect() self.assertTrue( - self.render_layout_check("composermap_annotations_variations_rotated_thresholds", - layout) + self.render_layout_check( + "composermap_annotations_variations_rotated_thresholds", layout + ) ) def testExpressionContext(self): @@ -659,44 +698,48 @@ def testDataDefinedEnabled(self): map.grid().setAnnotationTextFormat(format) map.grid().setAnnotationPrecision(0) map.grid().setAnnotationDisplay( - QgsLayoutItemMapGrid.DisplayMode.HideAll, QgsLayoutItemMapGrid.BorderSide.Left + QgsLayoutItemMapGrid.DisplayMode.HideAll, + QgsLayoutItemMapGrid.BorderSide.Left, ) map.grid().setAnnotationPosition( - QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, QgsLayoutItemMapGrid.BorderSide.Right + QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, + QgsLayoutItemMapGrid.BorderSide.Right, ) map.grid().setAnnotationDisplay( - QgsLayoutItemMapGrid.DisplayMode.HideAll, QgsLayoutItemMapGrid.BorderSide.Top + QgsLayoutItemMapGrid.DisplayMode.HideAll, + QgsLayoutItemMapGrid.BorderSide.Top, ) map.grid().setAnnotationPosition( - QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, QgsLayoutItemMapGrid.BorderSide.Bottom + QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, + QgsLayoutItemMapGrid.BorderSide.Bottom, ) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, QgsLayoutItemMapGrid.BorderSide.Right + QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, + QgsLayoutItemMapGrid.BorderSide.Right, ) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, QgsLayoutItemMapGrid.BorderSide.Bottom + QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, + QgsLayoutItemMapGrid.BorderSide.Bottom, ) map.grid().setBlendMode(QPainter.CompositionMode.CompositionMode_Overlay) map.updateBoundingRect() map.grid().dataDefinedProperties().setProperty( - QgsLayoutObject.DataDefinedProperty.MapGridEnabled, QgsProperty.fromValue(True) + QgsLayoutObject.DataDefinedProperty.MapGridEnabled, + QgsProperty.fromValue(True), ) map.grid().refresh() - self.assertTrue( - self.render_layout_check("composermap_grid", - layout) - ) + self.assertTrue(self.render_layout_check("composermap_grid", layout)) map.grid().dataDefinedProperties().setProperty( - QgsLayoutObject.DataDefinedProperty.MapGridEnabled, QgsProperty.fromValue(False) + QgsLayoutObject.DataDefinedProperty.MapGridEnabled, + QgsProperty.fromValue(False), ) map.grid().refresh() self.assertTrue( - self.render_layout_check("composermap_datadefined_disabled", - layout) + self.render_layout_check("composermap_datadefined_disabled", layout) ) def testDataDefinedIntervalOffset(self): @@ -719,22 +762,25 @@ def testDataDefinedIntervalOffset(self): map.updateBoundingRect() map.grid().dataDefinedProperties().setProperty( - QgsLayoutObject.DataDefinedProperty.MapGridIntervalX, QgsProperty.fromValue(1500) + QgsLayoutObject.DataDefinedProperty.MapGridIntervalX, + QgsProperty.fromValue(1500), ) map.grid().dataDefinedProperties().setProperty( - QgsLayoutObject.DataDefinedProperty.MapGridIntervalY, QgsProperty.fromValue(2500) + QgsLayoutObject.DataDefinedProperty.MapGridIntervalY, + QgsProperty.fromValue(2500), ) map.grid().dataDefinedProperties().setProperty( - QgsLayoutObject.DataDefinedProperty.MapGridOffsetX, QgsProperty.fromValue(500) + QgsLayoutObject.DataDefinedProperty.MapGridOffsetX, + QgsProperty.fromValue(500), ) map.grid().dataDefinedProperties().setProperty( - QgsLayoutObject.DataDefinedProperty.MapGridOffsetY, QgsProperty.fromValue(250) + QgsLayoutObject.DataDefinedProperty.MapGridOffsetY, + QgsProperty.fromValue(250), ) map.grid().refresh() self.assertTrue( - self.render_layout_check("composermap_datadefined_intervaloffset", - layout) + self.render_layout_check("composermap_datadefined_intervaloffset", layout) ) def testDataDefinedFrameSize(self): @@ -764,16 +810,17 @@ def testDataDefinedFrameSize(self): map.updateBoundingRect() map.grid().dataDefinedProperties().setProperty( - QgsLayoutObject.DataDefinedProperty.MapGridFrameSize, QgsProperty.fromValue(20) + QgsLayoutObject.DataDefinedProperty.MapGridFrameSize, + QgsProperty.fromValue(20), ) map.grid().dataDefinedProperties().setProperty( - QgsLayoutObject.DataDefinedProperty.MapGridFrameMargin, QgsProperty.fromValue(10) + QgsLayoutObject.DataDefinedProperty.MapGridFrameMargin, + QgsProperty.fromValue(10), ) map.grid().refresh() self.assertTrue( - self.render_layout_check("composermap_datadefined_framesizemargin", - layout) + self.render_layout_check("composermap_datadefined_framesizemargin", layout) ) def testDataDefinedCrossSize(self): @@ -800,13 +847,13 @@ def testDataDefinedCrossSize(self): map.updateBoundingRect() map.grid().dataDefinedProperties().setProperty( - QgsLayoutObject.DataDefinedProperty.MapGridCrossSize, QgsProperty.fromValue(4) + QgsLayoutObject.DataDefinedProperty.MapGridCrossSize, + QgsProperty.fromValue(4), ) map.grid().refresh() self.assertTrue( - self.render_layout_check("composermap_datadefined_crosssize", - layout) + self.render_layout_check("composermap_datadefined_crosssize", layout) ) def testDataDefinedFrameThickness(self): @@ -836,13 +883,13 @@ def testDataDefinedFrameThickness(self): map.updateBoundingRect() map.grid().dataDefinedProperties().setProperty( - QgsLayoutObject.DataDefinedProperty.MapGridFrameLineThickness, QgsProperty.fromValue(4) + QgsLayoutObject.DataDefinedProperty.MapGridFrameLineThickness, + QgsProperty.fromValue(4), ) map.grid().refresh() self.assertTrue( - self.render_layout_check("composermap_datadefined_framethickness", - layout) + self.render_layout_check("composermap_datadefined_framethickness", layout) ) def testDataDefinedAnnotationDistance(self): @@ -869,34 +916,42 @@ def testDataDefinedAnnotationDistance(self): map.grid().setAnnotationPrecision(0) map.grid().setAnnotationDisplay( - QgsLayoutItemMapGrid.DisplayMode.HideAll, QgsLayoutItemMapGrid.BorderSide.Left + QgsLayoutItemMapGrid.DisplayMode.HideAll, + QgsLayoutItemMapGrid.BorderSide.Left, ) map.grid().setAnnotationPosition( - QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, QgsLayoutItemMapGrid.BorderSide.Right + QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, + QgsLayoutItemMapGrid.BorderSide.Right, ) map.grid().setAnnotationDisplay( - QgsLayoutItemMapGrid.DisplayMode.HideAll, QgsLayoutItemMapGrid.BorderSide.Top + QgsLayoutItemMapGrid.DisplayMode.HideAll, + QgsLayoutItemMapGrid.BorderSide.Top, ) map.grid().setAnnotationPosition( - QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, QgsLayoutItemMapGrid.BorderSide.Bottom + QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, + QgsLayoutItemMapGrid.BorderSide.Bottom, ) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, QgsLayoutItemMapGrid.BorderSide.Right + QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, + QgsLayoutItemMapGrid.BorderSide.Right, ) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, QgsLayoutItemMapGrid.BorderSide.Bottom + QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, + QgsLayoutItemMapGrid.BorderSide.Bottom, ) map.grid().setBlendMode(QPainter.CompositionMode.CompositionMode_Overlay) map.updateBoundingRect() map.grid().dataDefinedProperties().setProperty( - QgsLayoutObject.DataDefinedProperty.MapGridLabelDistance, QgsProperty.fromValue(10) + QgsLayoutObject.DataDefinedProperty.MapGridLabelDistance, + QgsProperty.fromValue(10), ) map.grid().refresh() self.assertTrue( - self.render_layout_check("composermap_datadefined_annotationdistance", - layout) + self.render_layout_check( + "composermap_datadefined_annotationdistance", layout + ) ) def testDataDefinedTicksAndAnnotationDisplay(self): @@ -930,7 +985,9 @@ def testDataDefinedTicksAndAnnotationDisplay(self): map.grid().setRotatedTicksEnabled(True) map.grid().setRotatedAnnotationsEnabled(True) - map.grid().setAnnotationDirection(QgsLayoutItemMapGrid.AnnotationDirection.OnTick) + map.grid().setAnnotationDirection( + QgsLayoutItemMapGrid.AnnotationDirection.OnTick + ) map.grid().dataDefinedProperties().setProperty( QgsLayoutObject.DataDefinedProperty.MapGridAnnotationDisplayLeft, @@ -945,26 +1002,32 @@ def testDataDefinedTicksAndAnnotationDisplay(self): QgsProperty.fromValue("disabled"), ) map.grid().dataDefinedProperties().setProperty( - QgsLayoutObject.DataDefinedProperty.MapGridAnnotationDisplayBottom, QgsProperty.fromValue("ALL") + QgsLayoutObject.DataDefinedProperty.MapGridAnnotationDisplayBottom, + QgsProperty.fromValue("ALL"), ) map.grid().dataDefinedProperties().setProperty( - QgsLayoutObject.DataDefinedProperty.MapGridFrameDivisionsLeft, QgsProperty.fromValue("X_ONLY") + QgsLayoutObject.DataDefinedProperty.MapGridFrameDivisionsLeft, + QgsProperty.fromValue("X_ONLY"), ) map.grid().dataDefinedProperties().setProperty( - QgsLayoutObject.DataDefinedProperty.MapGridFrameDivisionsRight, QgsProperty.fromValue("y_only") + QgsLayoutObject.DataDefinedProperty.MapGridFrameDivisionsRight, + QgsProperty.fromValue("y_only"), ) map.grid().dataDefinedProperties().setProperty( - QgsLayoutObject.DataDefinedProperty.MapGridFrameDivisionsTop, QgsProperty.fromValue("DISABLED") + QgsLayoutObject.DataDefinedProperty.MapGridFrameDivisionsTop, + QgsProperty.fromValue("DISABLED"), ) map.grid().dataDefinedProperties().setProperty( - QgsLayoutObject.DataDefinedProperty.MapGridFrameDivisionsBottom, QgsProperty.fromValue("all") + QgsLayoutObject.DataDefinedProperty.MapGridFrameDivisionsBottom, + QgsProperty.fromValue("all"), ) map.grid().refresh() self.assertTrue( - self.render_layout_check("composermap_datadefined_ticksandannotationdisplay", - layout) + self.render_layout_check( + "composermap_datadefined_ticksandannotationdisplay", layout + ) ) def testDynamicInterval(self): @@ -992,55 +1055,49 @@ def testDynamicInterval(self): map.grid().setAnnotationPrecision(0) map.grid().setAnnotationDisplay( - QgsLayoutItemMapGrid.DisplayMode.HideAll, QgsLayoutItemMapGrid.BorderSide.Left + QgsLayoutItemMapGrid.DisplayMode.HideAll, + QgsLayoutItemMapGrid.BorderSide.Left, ) map.grid().setAnnotationPosition( - QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, QgsLayoutItemMapGrid.BorderSide.Right + QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, + QgsLayoutItemMapGrid.BorderSide.Right, ) map.grid().setAnnotationDisplay( - QgsLayoutItemMapGrid.DisplayMode.HideAll, QgsLayoutItemMapGrid.BorderSide.Top + QgsLayoutItemMapGrid.DisplayMode.HideAll, + QgsLayoutItemMapGrid.BorderSide.Top, ) map.grid().setAnnotationPosition( - QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, QgsLayoutItemMapGrid.BorderSide.Bottom + QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, + QgsLayoutItemMapGrid.BorderSide.Bottom, ) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, QgsLayoutItemMapGrid.BorderSide.Right + QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, + QgsLayoutItemMapGrid.BorderSide.Right, ) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, QgsLayoutItemMapGrid.BorderSide.Bottom + QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, + QgsLayoutItemMapGrid.BorderSide.Bottom, ) map.grid().setBlendMode(QPainter.CompositionMode.CompositionMode_Overlay) map.updateBoundingRect() map.grid().refresh() - self.assertTrue( - self.render_layout_check("composermap_dynamic_5_10", - layout) - ) + self.assertTrue(self.render_layout_check("composermap_dynamic_5_10", layout)) map.setScale(map.scale() * 1.1) - self.assertTrue( - self.render_layout_check("composermap_dynamic_5_10_2", - layout) - ) + self.assertTrue(self.render_layout_check("composermap_dynamic_5_10_2", layout)) map.setScale(map.scale() * 1.8) - self.assertTrue( - self.render_layout_check("composermap_dynamic_5_10_3", - layout) - ) + self.assertTrue(self.render_layout_check("composermap_dynamic_5_10_3", layout)) map.grid().setMinimumIntervalWidth(10) map.grid().setMaximumIntervalWidth(40) map.grid().refresh() - self.assertTrue( - self.render_layout_check("composermap_dynamic_5_10_4", - layout) - ) + self.assertTrue(self.render_layout_check("composermap_dynamic_5_10_4", layout)) def testCrsChanged(self): """ @@ -1078,7 +1135,8 @@ def testCrsChanged(self): self.assertEqual(len(spy), 6) # data defined crs map.dataDefinedProperties().setProperty( - QgsLayoutObject.DataDefinedProperty.MapCrs, QgsProperty.fromValue("EPSG:4283") + QgsLayoutObject.DataDefinedProperty.MapCrs, + QgsProperty.fromValue("EPSG:4283"), ) self.assertEqual(len(spy), 6) map.refresh() @@ -1090,7 +1148,8 @@ def testCrsChanged(self): grid.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) self.assertEqual(len(spy), 8) map.dataDefinedProperties().setProperty( - QgsLayoutObject.DataDefinedProperty.MapCrs, QgsProperty.fromValue("EPSG:3111") + QgsLayoutObject.DataDefinedProperty.MapCrs, + QgsProperty.fromValue("EPSG:3111"), ) map.refresh() self.assertEqual(len(spy), 8) @@ -1121,28 +1180,35 @@ def testCopyGrid(self): map.grid().setAnnotationPrecision(0) map.grid().setAnnotationDisplay( - QgsLayoutItemMapGrid.DisplayMode.HideAll, QgsLayoutItemMapGrid.BorderSide.Left + QgsLayoutItemMapGrid.DisplayMode.HideAll, + QgsLayoutItemMapGrid.BorderSide.Left, ) map.grid().setAnnotationPosition( - QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, QgsLayoutItemMapGrid.BorderSide.Right + QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, + QgsLayoutItemMapGrid.BorderSide.Right, ) map.grid().setAnnotationDisplay( - QgsLayoutItemMapGrid.DisplayMode.HideAll, QgsLayoutItemMapGrid.BorderSide.Top + QgsLayoutItemMapGrid.DisplayMode.HideAll, + QgsLayoutItemMapGrid.BorderSide.Top, ) map.grid().setAnnotationPosition( - QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, QgsLayoutItemMapGrid.BorderSide.Bottom + QgsLayoutItemMapGrid.AnnotationPosition.OutsideMapFrame, + QgsLayoutItemMapGrid.BorderSide.Bottom, ) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, QgsLayoutItemMapGrid.BorderSide.Right + QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, + QgsLayoutItemMapGrid.BorderSide.Right, ) map.grid().setAnnotationDirection( - QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, QgsLayoutItemMapGrid.BorderSide.Bottom + QgsLayoutItemMapGrid.AnnotationDirection.Horizontal, + QgsLayoutItemMapGrid.BorderSide.Bottom, ) map.grid().setBlendMode(QPainter.CompositionMode.CompositionMode_Overlay) map.updateBoundingRect() map.grid().dataDefinedProperties().setProperty( - QgsLayoutObject.DataDefinedProperty.MapGridLabelDistance, QgsProperty.fromValue(10) + QgsLayoutObject.DataDefinedProperty.MapGridLabelDistance, + QgsProperty.fromValue(10), ) map.grid().refresh() @@ -1154,8 +1220,9 @@ def testCopyGrid(self): map.grids().addGrid(grid) map.grid().refresh() self.assertTrue( - self.render_layout_check("composermap_datadefined_annotationdistance", - layout) + self.render_layout_check( + "composermap_datadefined_annotationdistance", layout + ) ) diff --git a/tests/src/python/test_qgslayoutmapitemclippingsettings.py b/tests/src/python/test_qgslayoutmapitemclippingsettings.py index 7b8e821d9323..a8bfa209c55f 100644 --- a/tests/src/python/test_qgslayoutmapitemclippingsettings.py +++ b/tests/src/python/test_qgslayoutmapitemclippingsettings.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 Nyall Dawson' -__date__ = '03/07/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 Nyall Dawson" +__date__ = "03/07/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication, QEvent, QRectF from qgis.PyQt.QtTest import QSignalSpy @@ -50,10 +51,17 @@ def testSettings(self): settings.setEnabled(True) self.assertEqual(len(spy), 1) - settings.setFeatureClippingType(QgsMapClippingRegion.FeatureClippingType.NoClipping) - self.assertEqual(settings.featureClippingType(), QgsMapClippingRegion.FeatureClippingType.NoClipping) + settings.setFeatureClippingType( + QgsMapClippingRegion.FeatureClippingType.NoClipping + ) + self.assertEqual( + settings.featureClippingType(), + QgsMapClippingRegion.FeatureClippingType.NoClipping, + ) self.assertEqual(len(spy), 2) - settings.setFeatureClippingType(QgsMapClippingRegion.FeatureClippingType.NoClipping) + settings.setFeatureClippingType( + QgsMapClippingRegion.FeatureClippingType.NoClipping + ) self.assertEqual(len(spy), 2) self.assertFalse(settings.forceLabelsInsideClipPath()) @@ -111,7 +119,9 @@ def testSaveRestore(self): settings = map.itemClippingSettings() settings.setEnabled(True) - settings.setFeatureClippingType(QgsMapClippingRegion.FeatureClippingType.NoClipping) + settings.setFeatureClippingType( + QgsMapClippingRegion.FeatureClippingType.NoClipping + ) settings.setForceLabelsInsideClipPath(True) settings.setSourceItem(shape) @@ -123,7 +133,7 @@ def testSaveRestore(self): self.assertTrue(shape.writeXml(elem_shape, doc, QgsReadWriteContext())) layout2 = QgsPrintLayout(p) - layout2.setName('test2') + layout2.setName("test2") p.layoutManager().addLayout(layout2) map2 = QgsLayoutItemMap(layout2) layout2.addLayoutItem(map2) @@ -133,11 +143,18 @@ def testSaveRestore(self): self.assertFalse(map2.itemClippingSettings().enabled()) # restore from xml - self.assertTrue(map2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext())) - self.assertTrue(shape2.readXml(elem_shape.firstChildElement(), doc, QgsReadWriteContext())) + self.assertTrue( + map2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext()) + ) + self.assertTrue( + shape2.readXml(elem_shape.firstChildElement(), doc, QgsReadWriteContext()) + ) self.assertTrue(map2.itemClippingSettings().enabled()) - self.assertEqual(map2.itemClippingSettings().featureClippingType(), QgsMapClippingRegion.FeatureClippingType.NoClipping) + self.assertEqual( + map2.itemClippingSettings().featureClippingType(), + QgsMapClippingRegion.FeatureClippingType.NoClipping, + ) self.assertTrue(map2.itemClippingSettings().forceLabelsInsideClipPath()) self.assertIsNone(map2.itemClippingSettings().sourceItem()) @@ -166,7 +183,7 @@ def testClippedMapExtent(self): settings.setSourceItem(shape) geom = settings.clippedMapExtent() - self.assertEqual(geom.asWkt(), 'Polygon ((-5 80, 135 80, 65 180, -5 80))') + self.assertEqual(geom.asWkt(), "Polygon ((-5 80, 135 80, 65 180, -5 80))") def testToMapClippingRegion(self): # - we position a map and a triangle in a layout at specific layout/scene coordinates @@ -187,13 +204,19 @@ def testToMapClippingRegion(self): settings = map.itemClippingSettings() settings.setEnabled(True) - settings.setFeatureClippingType(QgsMapClippingRegion.FeatureClippingType.NoClipping) + settings.setFeatureClippingType( + QgsMapClippingRegion.FeatureClippingType.NoClipping + ) settings.setSourceItem(shape) region = settings.toMapClippingRegion() - self.assertEqual(region.geometry().asWkt(), 'Polygon ((-5 80, 135 80, 65 180, -5 80))') - self.assertEqual(region.featureClip(), QgsMapClippingRegion.FeatureClippingType.NoClipping) + self.assertEqual( + region.geometry().asWkt(), "Polygon ((-5 80, 135 80, 65 180, -5 80))" + ) + self.assertEqual( + region.featureClip(), QgsMapClippingRegion.FeatureClippingType.NoClipping + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutmapoverview.py b/tests/src/python/test_qgslayoutmapoverview.py index 9bf573851147..caa67851dc64 100644 --- a/tests/src/python/test_qgslayoutmapoverview.py +++ b/tests/src/python/test_qgslayoutmapoverview.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2017 Nyall Dawson' -__date__ = '20/10/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "(C) 2017 Nyall Dawson" +__date__ = "20/10/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os from typing import Optional @@ -31,7 +32,7 @@ QgsRectangle, QgsSingleSymbolRenderer, QgsSymbolLayer, - QgsVectorLayer + QgsVectorLayer, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -47,7 +48,7 @@ class TestQgsLayoutMap(QgisTestCase, LayoutItemTestCase): @classmethod def setUpClass(cls): - super(TestQgsLayoutMap, cls).setUpClass() + super().setUpClass() cls.item_class = QgsLayoutItemMap @classmethod @@ -57,18 +58,21 @@ def control_path_prefix(cls): def __init__(self, methodName): """Run once on class initialization.""" QgisTestCase.__init__(self, methodName) - myPath = os.path.join(TEST_DATA_DIR, 'rgb256x256.png') + myPath = os.path.join(TEST_DATA_DIR, "rgb256x256.png") rasterFileInfo = QFileInfo(myPath) - self.raster_layer = QgsRasterLayer(rasterFileInfo.filePath(), - rasterFileInfo.completeBaseName()) + self.raster_layer = QgsRasterLayer( + rasterFileInfo.filePath(), rasterFileInfo.completeBaseName() + ) rasterRenderer = QgsMultiBandColorRenderer( - self.raster_layer.dataProvider(), 1, 2, 3) + self.raster_layer.dataProvider(), 1, 2, 3 + ) self.raster_layer.setRenderer(rasterRenderer) - myPath = os.path.join(TEST_DATA_DIR, 'points.shp') + myPath = os.path.join(TEST_DATA_DIR, "points.shp") vector_file_info = QFileInfo(myPath) - self.vector_layer = QgsVectorLayer(vector_file_info.filePath(), - vector_file_info.completeBaseName(), 'ogr') + self.vector_layer = QgsVectorLayer( + vector_file_info.filePath(), vector_file_info.completeBaseName(), "ogr" + ) assert self.vector_layer.isValid() QgsProject.instance().addMapLayers([self.raster_layer, self.vector_layer]) @@ -96,9 +100,9 @@ def testOverviewMap(self): overviewMap.overview().setLinkedMap(self.map) self.assertTrue(overviewMap.overviews().hasEnabledItems()) - result = self.render_layout_check("composermap_overview", - self.layout, - color_tolerance=6) + result = self.render_layout_check( + "composermap_overview", self.layout, color_tolerance=6 + ) self.layout.removeLayoutItem(overviewMap) self.assertTrue(result) @@ -115,10 +119,11 @@ def testOverviewMapBlend(self): myRectangle2 = QgsRectangle(0, -256, 256, 0) overviewMap.setExtent(myRectangle2) overviewMap.overview().setLinkedMap(self.map) - overviewMap.overview().setBlendMode(QPainter.CompositionMode.CompositionMode_Multiply) + overviewMap.overview().setBlendMode( + QPainter.CompositionMode.CompositionMode_Multiply + ) - result = self.render_layout_check("composermap_overview_blending", - self.layout) + result = self.render_layout_check("composermap_overview_blending", self.layout) self.layout.removeLayoutItem(overviewMap) self.assertTrue(result) @@ -137,8 +142,7 @@ def testOverviewMapInvert(self): overviewMap.overview().setLinkedMap(self.map) overviewMap.overview().setInverted(True) - result = self.render_layout_check("composermap_overview_invert", - self.layout) + result = self.render_layout_check("composermap_overview_invert", self.layout) self.layout.removeLayoutItem(overviewMap) self.assertTrue(result) @@ -158,8 +162,7 @@ def testOverviewMapCenter(self): overviewMap.overview().setInverted(False) overviewMap.overview().setCentered(True) - result = self.render_layout_check("composermap_overview_center", - self.layout) + result = self.render_layout_check("composermap_overview_center", self.layout) self.layout.removeLayoutItem(overviewMap) self.assertTrue(result) @@ -188,21 +191,38 @@ def testAsMapLayer(self): for g in geoms: g.normalize() - self.assertEqual([g.asWkt() for g in geoms], ['Polygon ((96 -152, 96 -120, 160 -120, 160 -152, 96 -152))']) + self.assertEqual( + [g.asWkt() for g in geoms], + ["Polygon ((96 -152, 96 -120, 160 -120, 160 -152, 96 -152))"], + ) # check that layer has correct renderer - fill_symbol = QgsFillSymbol.createSimple({'color': '#00ff00', 'outline_color': '#ff0000', 'outline_width': '10'}) + fill_symbol = QgsFillSymbol.createSimple( + {"color": "#00ff00", "outline_color": "#ff0000", "outline_width": "10"} + ) overviewMap.overview().setFrameSymbol(fill_symbol) layer = overviewMap.overview().asMapLayer() self.assertIsInstance(layer.renderer(), QgsSingleSymbolRenderer) - self.assertEqual(layer.renderer().symbol().symbolLayer(0).properties()['color'], '0,255,0,255,rgb:0,1,0,1') - self.assertEqual(layer.renderer().symbol().symbolLayer(0).properties()['outline_color'], '255,0,0,255,rgb:1,0,0,1') + self.assertEqual( + layer.renderer().symbol().symbolLayer(0).properties()["color"], + "0,255,0,255,rgb:0,1,0,1", + ) + self.assertEqual( + layer.renderer().symbol().symbolLayer(0).properties()["outline_color"], + "255,0,0,255,rgb:1,0,0,1", + ) # test layer blend mode - self.assertEqual(layer.blendMode(), QPainter.CompositionMode.CompositionMode_SourceOver) - overviewMap.overview().setBlendMode(QPainter.CompositionMode.CompositionMode_Clear) + self.assertEqual( + layer.blendMode(), QPainter.CompositionMode.CompositionMode_SourceOver + ) + overviewMap.overview().setBlendMode( + QPainter.CompositionMode.CompositionMode_Clear + ) layer = overviewMap.overview().asMapLayer() - self.assertEqual(layer.blendMode(), QPainter.CompositionMode.CompositionMode_Clear) + self.assertEqual( + layer.blendMode(), QPainter.CompositionMode.CompositionMode_Clear + ) # should have no effect overviewMap.setMapRotation(45) @@ -210,22 +230,33 @@ def testAsMapLayer(self): geoms = [f.geometry() for f in layer.getFeatures()] for g in geoms: g.normalize() - self.assertEqual([g.asWkt() for g in geoms], ['Polygon ((96 -152, 96 -120, 160 -120, 160 -152, 96 -152))']) + self.assertEqual( + [g.asWkt() for g in geoms], + ["Polygon ((96 -152, 96 -120, 160 -120, 160 -152, 96 -152))"], + ) map.setMapRotation(15) layer = overviewMap.overview().asMapLayer() geoms = [f.geometry() for f in layer.getFeatures()] for g in geoms: g.normalize() - self.assertEqual([g.asWkt(0) for g in geoms], ['Polygon ((93 -129, 155 -112, 163 -143, 101 -160, 93 -129))']) + self.assertEqual( + [g.asWkt(0) for g in geoms], + ["Polygon ((93 -129, 155 -112, 163 -143, 101 -160, 93 -129))"], + ) # with reprojection - map.setCrs(QgsCoordinateReferenceSystem('EPSG:3875')) + map.setCrs(QgsCoordinateReferenceSystem("EPSG:3875")) layer = overviewMap.overview().asMapLayer() geoms = [f.geometry() for f in layer.getFeatures()] for g in geoms: g.normalize() - self.assertEqual([g.asWkt(0) for g in geoms], ['Polygon ((93 -129, 96 -128, 99 -127, 102 -126, 105 -126, 108 -125, 111 -124, 114 -123, 116 -123, 119 -122, 122 -121, 125 -120, 128 -119, 131 -119, 134 -118, 137 -117, 140 -116, 143 -115, 146 -115, 149 -114, 152 -113, 155 -112, 155 -114, 156 -115, 156 -117, 156 -118, 157 -120, 157 -121, 158 -123, 158 -124, 158 -126, 159 -127, 159 -128, 160 -130, 160 -131, 160 -133, 161 -134, 161 -136, 161 -137, 162 -139, 162 -140, 163 -142, 163 -143, 160 -144, 157 -145, 154 -146, 151 -146, 148 -147, 145 -148, 142 -149, 140 -149, 137 -150, 134 -151, 131 -152, 128 -153, 125 -153, 122 -154, 119 -155, 116 -156, 113 -157, 110 -157, 107 -158, 104 -159, 101 -160, 101 -158, 100 -157, 100 -155, 100 -154, 99 -152, 99 -151, 98 -149, 98 -148, 98 -146, 97 -145, 97 -144, 96 -142, 96 -141, 96 -139, 95 -138, 95 -136, 95 -135, 94 -133, 94 -132, 93 -130, 93 -129))']) + self.assertEqual( + [g.asWkt(0) for g in geoms], + [ + "Polygon ((93 -129, 96 -128, 99 -127, 102 -126, 105 -126, 108 -125, 111 -124, 114 -123, 116 -123, 119 -122, 122 -121, 125 -120, 128 -119, 131 -119, 134 -118, 137 -117, 140 -116, 143 -115, 146 -115, 149 -114, 152 -113, 155 -112, 155 -114, 156 -115, 156 -117, 156 -118, 157 -120, 157 -121, 158 -123, 158 -124, 158 -126, 159 -127, 159 -128, 160 -130, 160 -131, 160 -133, 161 -134, 161 -136, 161 -137, 162 -139, 162 -140, 163 -142, 163 -143, 160 -144, 157 -145, 154 -146, 151 -146, 148 -147, 145 -148, 142 -149, 140 -149, 137 -150, 134 -151, 131 -152, 128 -153, 125 -153, 122 -154, 119 -155, 116 -156, 113 -157, 110 -157, 107 -158, 104 -159, 101 -160, 101 -158, 100 -157, 100 -155, 100 -154, 99 -152, 99 -151, 98 -149, 98 -148, 98 -146, 97 -145, 97 -144, 96 -142, 96 -141, 96 -139, 95 -138, 95 -136, 95 -135, 94 -133, 94 -132, 93 -130, 93 -129))" + ], + ) map.setCrs(overviewMap.crs()) # with invert @@ -234,7 +265,12 @@ def testAsMapLayer(self): geoms = [f.geometry() for f in layer.getFeatures()] for g in geoms: g.normalize() - self.assertEqual([g.asWkt(0) for g in geoms], ['Polygon ((-53 -128, 128 53, 309 -128, 128 -309, -53 -128),(93 -129, 101 -160, 163 -143, 155 -112, 93 -129))']) + self.assertEqual( + [g.asWkt(0) for g in geoms], + [ + "Polygon ((-53 -128, 128 53, 309 -128, 128 -309, -53 -128),(93 -129, 101 -160, 163 -143, 155 -112, 93 -129))" + ], + ) def test_StackingPosition(self): l = QgsLayout(QgsProject.instance()) @@ -243,10 +279,20 @@ def test_StackingPosition(self): overviewMap = QgsLayoutItemMap(l) overviewMap.attemptSetSceneRect(QRectF(20, 130, 70, 70)) l.addLayoutItem(overviewMap) - overviewMap.overview().setStackingPosition(QgsLayoutItemMapItem.StackingPosition.StackBelowMap) - self.assertEqual(overviewMap.overview().stackingPosition(), QgsLayoutItemMapItem.StackingPosition.StackBelowMap) - overviewMap.overview().setStackingPosition(QgsLayoutItemMapItem.StackingPosition.StackBelowMapLayer) - self.assertEqual(overviewMap.overview().stackingPosition(), QgsLayoutItemMapItem.StackingPosition.StackBelowMapLayer) + overviewMap.overview().setStackingPosition( + QgsLayoutItemMapItem.StackingPosition.StackBelowMap + ) + self.assertEqual( + overviewMap.overview().stackingPosition(), + QgsLayoutItemMapItem.StackingPosition.StackBelowMap, + ) + overviewMap.overview().setStackingPosition( + QgsLayoutItemMapItem.StackingPosition.StackBelowMapLayer + ) + self.assertEqual( + overviewMap.overview().stackingPosition(), + QgsLayoutItemMapItem.StackingPosition.StackBelowMapLayer, + ) overviewMap.overview().setStackingLayer(self.raster_layer) self.assertEqual(overviewMap.overview().stackingLayer(), self.raster_layer) @@ -267,44 +313,108 @@ def test_ModifyMapLayerList(self): l.addLayoutItem(map) self.assertFalse(overviewMap.overviews().modifyMapLayerList([])) - self.assertEqual(overviewMap.overviews().modifyMapLayerList([self.raster_layer, self.vector_layer]), [self.raster_layer, self.vector_layer]) + self.assertEqual( + overviewMap.overviews().modifyMapLayerList( + [self.raster_layer, self.vector_layer] + ), + [self.raster_layer, self.vector_layer], + ) overviewMap.overview().setLinkedMap(map) - overviewMap.overview().setStackingPosition(QgsLayoutItemMapItem.StackingPosition.StackBelowMap) - self.assertEqual(overviewMap.overviews().modifyMapLayerList([self.raster_layer, self.vector_layer]), - [self.raster_layer, self.vector_layer, overviewMap.overview().asMapLayer()]) - overviewMap.overview().setStackingPosition(QgsLayoutItemMapItem.StackingPosition.StackBelowMapLayer) - self.assertEqual(overviewMap.overviews().modifyMapLayerList([self.raster_layer, self.vector_layer]), - [self.raster_layer, self.vector_layer]) + overviewMap.overview().setStackingPosition( + QgsLayoutItemMapItem.StackingPosition.StackBelowMap + ) + self.assertEqual( + overviewMap.overviews().modifyMapLayerList( + [self.raster_layer, self.vector_layer] + ), + [self.raster_layer, self.vector_layer, overviewMap.overview().asMapLayer()], + ) + overviewMap.overview().setStackingPosition( + QgsLayoutItemMapItem.StackingPosition.StackBelowMapLayer + ) + self.assertEqual( + overviewMap.overviews().modifyMapLayerList( + [self.raster_layer, self.vector_layer] + ), + [self.raster_layer, self.vector_layer], + ) overviewMap.overview().setStackingLayer(self.raster_layer) - self.assertEqual(overviewMap.overviews().modifyMapLayerList([self.raster_layer, self.vector_layer]), - [self.raster_layer, overviewMap.overview().asMapLayer(), self.vector_layer]) + self.assertEqual( + overviewMap.overviews().modifyMapLayerList( + [self.raster_layer, self.vector_layer] + ), + [self.raster_layer, overviewMap.overview().asMapLayer(), self.vector_layer], + ) overviewMap.overview().setStackingLayer(self.vector_layer) - self.assertEqual(overviewMap.overviews().modifyMapLayerList([self.raster_layer, self.vector_layer]), - [self.raster_layer, self.vector_layer, overviewMap.overview().asMapLayer()]) - overviewMap.overview().setStackingPosition(QgsLayoutItemMapItem.StackingPosition.StackAboveMapLayer) + self.assertEqual( + overviewMap.overviews().modifyMapLayerList( + [self.raster_layer, self.vector_layer] + ), + [self.raster_layer, self.vector_layer, overviewMap.overview().asMapLayer()], + ) + overviewMap.overview().setStackingPosition( + QgsLayoutItemMapItem.StackingPosition.StackAboveMapLayer + ) overviewMap.overview().setStackingLayer(None) - self.assertEqual(overviewMap.overviews().modifyMapLayerList([self.raster_layer, self.vector_layer]), - [self.raster_layer, self.vector_layer]) + self.assertEqual( + overviewMap.overviews().modifyMapLayerList( + [self.raster_layer, self.vector_layer] + ), + [self.raster_layer, self.vector_layer], + ) overviewMap.overview().setStackingLayer(self.raster_layer) - self.assertEqual(overviewMap.overviews().modifyMapLayerList([self.raster_layer, self.vector_layer]), - [overviewMap.overview().asMapLayer(), self.raster_layer, self.vector_layer]) + self.assertEqual( + overviewMap.overviews().modifyMapLayerList( + [self.raster_layer, self.vector_layer] + ), + [overviewMap.overview().asMapLayer(), self.raster_layer, self.vector_layer], + ) overviewMap.overview().setStackingLayer(self.vector_layer) - self.assertEqual(overviewMap.overviews().modifyMapLayerList([self.raster_layer, self.vector_layer]), - [self.raster_layer, overviewMap.overview().asMapLayer(), self.vector_layer]) - overviewMap.overview().setStackingPosition(QgsLayoutItemMapItem.StackingPosition.StackBelowMapLabels) - self.assertEqual(overviewMap.overviews().modifyMapLayerList([self.raster_layer, self.vector_layer]), - [overviewMap.overview().asMapLayer(), self.raster_layer, self.vector_layer]) - overviewMap.overview().setStackingPosition(QgsLayoutItemMapItem.StackingPosition.StackAboveMapLabels) - self.assertEqual(overviewMap.overviews().modifyMapLayerList([self.raster_layer, self.vector_layer]), - [self.raster_layer, self.vector_layer]) + self.assertEqual( + overviewMap.overviews().modifyMapLayerList( + [self.raster_layer, self.vector_layer] + ), + [self.raster_layer, overviewMap.overview().asMapLayer(), self.vector_layer], + ) + overviewMap.overview().setStackingPosition( + QgsLayoutItemMapItem.StackingPosition.StackBelowMapLabels + ) + self.assertEqual( + overviewMap.overviews().modifyMapLayerList( + [self.raster_layer, self.vector_layer] + ), + [overviewMap.overview().asMapLayer(), self.raster_layer, self.vector_layer], + ) + overviewMap.overview().setStackingPosition( + QgsLayoutItemMapItem.StackingPosition.StackAboveMapLabels + ) + self.assertEqual( + overviewMap.overviews().modifyMapLayerList( + [self.raster_layer, self.vector_layer] + ), + [self.raster_layer, self.vector_layer], + ) # two overviews - overviewMap.overview().setStackingPosition(QgsLayoutItemMapItem.StackingPosition.StackBelowMap) - overviewMap.overviews().addOverview(QgsLayoutItemMapOverview('x', overviewMap)) + overviewMap.overview().setStackingPosition( + QgsLayoutItemMapItem.StackingPosition.StackBelowMap + ) + overviewMap.overviews().addOverview(QgsLayoutItemMapOverview("x", overviewMap)) overviewMap.overviews().overview(1).setLinkedMap(map) - overviewMap.overviews().overview(1).setStackingPosition(QgsLayoutItemMapItem.StackingPosition.StackBelowMapLabels) - self.assertEqual(overviewMap.overviews().modifyMapLayerList([self.raster_layer, self.vector_layer]), - [overviewMap.overviews().overview(1).asMapLayer(), self.raster_layer, self.vector_layer, overviewMap.overview().asMapLayer()]) + overviewMap.overviews().overview(1).setStackingPosition( + QgsLayoutItemMapItem.StackingPosition.StackBelowMapLabels + ) + self.assertEqual( + overviewMap.overviews().modifyMapLayerList( + [self.raster_layer, self.vector_layer] + ), + [ + overviewMap.overviews().overview(1).asMapLayer(), + self.raster_layer, + self.vector_layer, + overviewMap.overview().asMapLayer(), + ], + ) def testOverviewStacking(self): l = QgsLayout(QgsProject.instance()) @@ -327,27 +437,41 @@ def testOverviewStacking(self): overviewMap.setExtent(myRectangle2) overviewMap.overview().setLinkedMap(map) overviewMap.overview().setInverted(True) - overviewMap.overview().setStackingPosition(QgsLayoutItemMapItem.StackingPosition.StackBelowMapLayer) + overviewMap.overview().setStackingPosition( + QgsLayoutItemMapItem.StackingPosition.StackBelowMapLayer + ) overviewMap.overview().setStackingLayer(self.raster_layer) - self.assertTrue(self.render_layout_check("composermap_overview_belowmap", - l, color_tolerance=6)) + self.assertTrue( + self.render_layout_check( + "composermap_overview_belowmap", l, color_tolerance=6 + ) + ) - overviewMap.overview().setStackingPosition(QgsLayoutItemMapItem.StackingPosition.StackAboveMapLayer) + overviewMap.overview().setStackingPosition( + QgsLayoutItemMapItem.StackingPosition.StackAboveMapLayer + ) overviewMap.overview().setStackingLayer(self.raster_layer) - self.assertTrue(self.render_layout_check("composermap_overview_abovemap", - l, color_tolerance=6)) + self.assertTrue( + self.render_layout_check( + "composermap_overview_abovemap", l, color_tolerance=6 + ) + ) def testOverviewExpressionContextStacking(self): - atlas_layer = QgsVectorLayer("Point?crs=epsg:4326&field=attr:int(1)&field=label:string(20)", "points", "memory") + atlas_layer = QgsVectorLayer( + "Point?crs=epsg:4326&field=attr:int(1)&field=label:string(20)", + "points", + "memory", + ) atlas_feature1 = QgsFeature(atlas_layer.fields()) - atlas_feature1.setAttributes([5, 'a']) + atlas_feature1.setAttributes([5, "a"]) atlas_feature1.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(55, 55))) atlas_layer.dataProvider().addFeature(atlas_feature1) atlas_feature2 = QgsFeature(atlas_layer.fields()) - atlas_feature2.setAttributes([15, 'b']) + atlas_feature2.setAttributes([15, "b"]) atlas_feature2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(55, 55))) atlas_layer.dataProvider().addFeature(atlas_feature2) @@ -370,25 +494,40 @@ def testOverviewExpressionContextStacking(self): myRectangle2 = QgsRectangle(-20, -276, 276, 20) overviewMap.setExtent(myRectangle2) overviewMap.overview().setLinkedMap(map) - overviewMap.overview().setStackingPosition(QgsLayoutItemMapItem.StackingPosition.StackAboveMapLayer) + overviewMap.overview().setStackingPosition( + QgsLayoutItemMapItem.StackingPosition.StackAboveMapLayer + ) overviewMap.overview().setStackingLayer(atlas_layer) - fill_symbol = QgsFillSymbol.createSimple({'color': '#0000ff', 'outline_style': 'no'}) - fill_symbol[0].setDataDefinedProperty(QgsSymbolLayer.Property.PropertyFillColor, QgsProperty.fromExpression('case when label=\'a\' then \'red\' else \'green\' end')) + fill_symbol = QgsFillSymbol.createSimple( + {"color": "#0000ff", "outline_style": "no"} + ) + fill_symbol[0].setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyFillColor, + QgsProperty.fromExpression( + "case when label='a' then 'red' else 'green' end" + ), + ) overviewMap.overview().setFrameSymbol(fill_symbol) l.reportContext().setLayer(atlas_layer) l.reportContext().setFeature(atlas_feature1) - self.assertTrue(self.render_layout_check("composermap_overview_atlas_1", - l, color_tolerance=6)) + self.assertTrue( + self.render_layout_check( + "composermap_overview_atlas_1", l, color_tolerance=6 + ) + ) l.reportContext().setFeature(atlas_feature2) - self.assertTrue(self.render_layout_check("composermap_overview_atlas_2", - l, color_tolerance=6)) + self.assertTrue( + self.render_layout_check( + "composermap_overview_atlas_2", l, color_tolerance=6 + ) + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutmarker.py b/tests/src/python/test_qgslayoutmarker.py index c3dea5d96c0a..012c0afbbaa0 100644 --- a/tests/src/python/test_qgslayoutmarker.py +++ b/tests/src/python/test_qgslayoutmarker.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 by Nyall Dawson' -__date__ = '05/04/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 by Nyall Dawson" +__date__ = "05/04/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QRectF, Qt from qgis.PyQt.QtXml import QDomDocument @@ -23,7 +24,7 @@ QgsProject, QgsReadWriteContext, QgsRectangle, - QgsUnitTypes + QgsUnitTypes, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -43,7 +44,7 @@ def control_path_prefix(cls): @classmethod def setUpClass(cls): - super(TestQgsLayoutMarker, cls).setUpClass() + super().setUpClass() cls.item_class = QgsLayoutItemMarker def __init__(self, methodName): @@ -67,7 +68,7 @@ def testDisplayName(self): layout = QgsLayout(QgsProject.instance()) marker = QgsLayoutItemMarker(layout) self.assertEqual(marker.displayName(), "") - marker.setId('id') + marker.setId("id") self.assertEqual(marker.displayName(), "id") def testType(self): @@ -75,15 +76,16 @@ def testType(self): layout = QgsLayout(QgsProject.instance()) marker = QgsLayoutItemMarker(layout) - self.assertEqual( - marker.type(), QgsLayoutItemRegistry.ItemType.LayoutMarker) + self.assertEqual(marker.type(), QgsLayoutItemRegistry.ItemType.LayoutMarker) def testRender(self): """Test marker rendering.""" layout = QgsLayout(QgsProject.instance()) layout.initializeDefaults() marker = QgsLayoutItemMarker(layout) - marker.attemptMove(QgsLayoutPoint(100, 50, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + marker.attemptMove( + QgsLayoutPoint(100, 50, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) props = {} props["color"] = "0,255,255" props["outline_width"] = "4" @@ -94,12 +96,7 @@ def testRender(self): marker.setSymbol(style) layout.addLayoutItem(marker) - self.assertTrue( - self.render_layout_check( - 'layout_marker_render', - layout - ) - ) + self.assertTrue(self.render_layout_check("layout_marker_render", layout)) def testReadWriteXml(self): pr = QgsProject() @@ -128,15 +125,21 @@ def testReadWriteXml(self): self.assertTrue(marker.writeXml(elem, doc, QgsReadWriteContext())) marker2 = QgsLayoutItemMarker(l) - self.assertTrue(marker2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext())) + self.assertTrue( + marker2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext()) + ) marker2.finalizeRestoreFromXml() - self.assertEqual(marker2.symbol().symbolLayer(0).color().name(), '#008000') - self.assertEqual(marker2.symbol().symbolLayer(0).strokeStyle(), Qt.PenStyle.NoPen) + self.assertEqual(marker2.symbol().symbolLayer(0).color().name(), "#008000") + self.assertEqual( + marker2.symbol().symbolLayer(0).strokeStyle(), Qt.PenStyle.NoPen + ) self.assertEqual(marker2.symbol().symbolLayer(0).size(), 4.4) self.assertEqual(marker2.linkedMap(), map) - self.assertEqual(marker2.northMode(), QgsLayoutNorthArrowHandler.NorthMode.TrueNorth) + self.assertEqual( + marker2.northMode(), QgsLayoutNorthArrowHandler.NorthMode.TrueNorth + ) self.assertEqual(marker2.northOffset(), 15.0) def testBounds(self): @@ -144,7 +147,9 @@ def testBounds(self): l = QgsLayout(pr) shape = QgsLayoutItemMarker(l) - shape.attemptMove(QgsLayoutPoint(10, 20, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + shape.attemptMove( + QgsLayoutPoint(10, 20, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) props = {} props["shape"] = "square" props["size"] = "6" @@ -226,7 +231,9 @@ def testTrueNorth(self): map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(0, 0, 10, 10)) map.setCrs(QgsCoordinateReferenceSystem.fromEpsgId(3575)) - map.setExtent(QgsRectangle(-2126029.962, -2200807.749, -119078.102, -757031.156)) + map.setExtent( + QgsRectangle(-2126029.962, -2200807.749, -119078.102, -757031.156) + ) layout.addLayoutItem(map) marker = QgsLayoutItemMarker(layout) @@ -239,7 +246,9 @@ def testTrueNorth(self): self.assertAlmostEqual(marker.northArrowRotation(), 37.20, 1) # shift map - map.setExtent(QgsRectangle(2120672.293, -3056394.691, 2481640.226, -2796718.780)) + map.setExtent( + QgsRectangle(2120672.293, -3056394.691, 2481640.226, -2796718.780) + ) self.assertAlmostEqual(marker.northArrowRotation(), -38.18, 1) # rotate map @@ -258,7 +267,9 @@ def testRenderWithNorthRotation(self): map.setExtent(QgsRectangle(0, -256, 256, 0)) marker = QgsLayoutItemMarker(layout) - marker.attemptMove(QgsLayoutPoint(100, 50, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + marker.attemptMove( + QgsLayoutPoint(100, 50, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) props = {} props["color"] = "0,255,255" props["outline_style"] = "no" @@ -280,13 +291,8 @@ def testRenderWithNorthRotation(self): marker.setSymbol(style) layout.addLayoutItem(marker) - self.assertTrue( - self.render_layout_check( - 'layout_marker_render_north', - layout - ) - ) + self.assertTrue(self.render_layout_check("layout_marker_render_north", layout)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutnortharrowhandler.py b/tests/src/python/test_qgslayoutnortharrowhandler.py index 20609a83d35a..f5044de2d5b7 100644 --- a/tests/src/python/test_qgslayoutnortharrowhandler.py +++ b/tests/src/python/test_qgslayoutnortharrowhandler.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 by Nyall Dawson' -__date__ = '05/04/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 by Nyall Dawson" +__date__ = "05/04/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QRectF from qgis.PyQt.QtTest import QSignalSpy @@ -125,7 +126,9 @@ def testTrueNorth(self): map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(0, 0, 10, 10)) map.setCrs(QgsCoordinateReferenceSystem.fromEpsgId(3575)) - map.setExtent(QgsRectangle(-2126029.962, -2200807.749, -119078.102, -757031.156)) + map.setExtent( + QgsRectangle(-2126029.962, -2200807.749, -119078.102, -757031.156) + ) layout.addLayoutItem(map) handler = QgsLayoutNorthArrowHandler(layout) @@ -141,7 +144,9 @@ def testTrueNorth(self): self.assertAlmostEqual(spy[-1][0], 37.20, 1) # shift map - map.setExtent(QgsRectangle(2120672.293, -3056394.691, 2481640.226, -2796718.780)) + map.setExtent( + QgsRectangle(2120672.293, -3056394.691, 2481640.226, -2796718.780) + ) self.assertAlmostEqual(handler.arrowRotation(), -38.18, 1) self.assertEqual(len(spy), 2) self.assertAlmostEqual(spy[-1][0], -38.18, 1) @@ -159,5 +164,5 @@ def testTrueNorth(self): self.assertAlmostEqual(spy[-1][0], -38.18 + 35, 1) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutpage.py b/tests/src/python/test_qgslayoutpage.py index 4189bdf86ec9..a9f4403da0eb 100644 --- a/tests/src/python/test_qgslayoutpage.py +++ b/tests/src/python/test_qgslayoutpage.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2017 by Nyall Dawson' -__date__ = '23/10/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "(C) 2017 by Nyall Dawson" +__date__ = "23/10/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtCore import Qt from qgis.PyQt.QtXml import QDomDocument @@ -31,7 +32,7 @@ class TestQgsLayoutPage(QgisTestCase, LayoutItemTestCase): @classmethod def setUpClass(cls): - super(TestQgsLayoutPage, cls).setUpClass() + super().setUpClass() cls.item_class = QgsLayoutItemPage def testDefaults(self): @@ -48,8 +49,10 @@ def testDefaults(self): fill.setStrokeWidth(6) p.setPageStyleSymbol(fill_symbol) - self.assertEqual(p.pageStyleSymbol().symbolLayer(0).color().name(), '#00ff00') - self.assertEqual(p.pageStyleSymbol().symbolLayer(0).strokeColor().name(), '#ff0000') + self.assertEqual(p.pageStyleSymbol().symbolLayer(0).color().name(), "#00ff00") + self.assertEqual( + p.pageStyleSymbol().symbolLayer(0).strokeColor().name(), "#ff0000" + ) def testReadWriteSettings(self): p = QgsProject() @@ -64,14 +67,14 @@ def testReadWriteSettings(self): fill.setStrokeWidth(6) page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") page.setPageStyleSymbol(fill_symbol.clone()) self.assertEqual(collection.pageNumber(page), -1) collection.addPage(page) # add a second page page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") fill_symbol.setColor(Qt.GlobalColor.blue) page2.setPageStyleSymbol(fill_symbol.clone()) collection.addPage(page2) @@ -83,16 +86,30 @@ def testReadWriteSettings(self): l2 = QgsLayout(p) collection2 = l2.pageCollection() - self.assertTrue(collection2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext())) + self.assertTrue( + collection2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext()) + ) self.assertEqual(collection2.pageCount(), 2) - self.assertEqual(collection2.page(0).pageStyleSymbol().symbolLayer(0).color().name(), '#00ff00') - self.assertEqual(collection2.page(0).pageStyleSymbol().symbolLayer(0).strokeColor().name(), '#ff0000') - - self.assertEqual(collection2.page(1).pageStyleSymbol().symbolLayer(0).color().name(), '#0000ff') - self.assertEqual(collection2.page(1).pageStyleSymbol().symbolLayer(0).strokeColor().name(), '#ff0000') - - -if __name__ == '__main__': + self.assertEqual( + collection2.page(0).pageStyleSymbol().symbolLayer(0).color().name(), + "#00ff00", + ) + self.assertEqual( + collection2.page(0).pageStyleSymbol().symbolLayer(0).strokeColor().name(), + "#ff0000", + ) + + self.assertEqual( + collection2.page(1).pageStyleSymbol().symbolLayer(0).color().name(), + "#0000ff", + ) + self.assertEqual( + collection2.page(1).pageStyleSymbol().symbolLayer(0).strokeColor().name(), + "#ff0000", + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutpagecollection.py b/tests/src/python/test_qgslayoutpagecollection.py index 5f84219d694c..e66a5f64c77f 100644 --- a/tests/src/python/test_qgslayoutpagecollection.py +++ b/tests/src/python/test_qgslayoutpagecollection.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '18/07/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "18/07/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt import sip from qgis.PyQt.QtCore import QCoreApplication, QEvent, QPointF, QRectF, Qt @@ -61,8 +62,12 @@ def testSymbol(self): fill.setStrokeColor(Qt.GlobalColor.red) fill.setStrokeWidth(6) collection.setPageStyleSymbol(fill_symbol) - self.assertEqual(collection.pageStyleSymbol().symbolLayer(0).color().name(), '#00ff00') - self.assertEqual(collection.pageStyleSymbol().symbolLayer(0).strokeColor().name(), '#ff0000') + self.assertEqual( + collection.pageStyleSymbol().symbolLayer(0).color().name(), "#00ff00" + ) + self.assertEqual( + collection.pageStyleSymbol().symbolLayer(0).strokeColor().name(), "#ff0000" + ) def testPages(self): """ @@ -80,7 +85,7 @@ def testPages(self): # add a page page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") self.assertEqual(collection.pageNumber(page), -1) collection.addPage(page) @@ -96,7 +101,7 @@ def testPages(self): # add a second page page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") collection.addPage(page2) self.assertEqual(collection.pageCount(), 2) @@ -108,7 +113,7 @@ def testPages(self): # insert a page page3 = QgsLayoutItemPage(l) - page3.setPageSize('A3') + page3.setPageSize("A3") collection.insertPage(page3, 1) self.assertIn(page3, l.items()) @@ -149,11 +154,11 @@ def testDeletePages(self): # add a page page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") collection.addPage(page) # add a second page page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") collection.addPage(page2) page_about_to_be_removed_spy = QSignalSpy(collection.pageAboutToBeRemoved) @@ -171,10 +176,14 @@ def testDeletePages(self): self.assertEqual(collection.pageCount(), 2) self.assertEqual(len(page_about_to_be_removed_spy), 0) - self.assertEqual(l.layoutBounds(ignorePages=False), QRectF(0.0, 0.0, 210.0, 517.0)) + self.assertEqual( + l.layoutBounds(ignorePages=False), QRectF(0.0, 0.0, 210.0, 517.0) + ) collection.deletePage(page) self.assertEqual(collection.pageCount(), 1) - self.assertEqual(l.layoutBounds(ignorePages=False), QRectF(0.0, 0.0, 148.0, 210.0)) + self.assertEqual( + l.layoutBounds(ignorePages=False), QRectF(0.0, 0.0, 148.0, 210.0) + ) self.assertNotIn(page, collection.pages()) QCoreApplication.sendPostedEvents(None, QEvent.Type.DeferredDelete) self.assertTrue(sip.isdeleted(page)) @@ -202,11 +211,11 @@ def testClear(self): # add a page page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") collection.addPage(page) # add a second page page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") collection.addPage(page2) page_about_to_be_removed_spy = QSignalSpy(collection.pageAboutToBeRemoved) @@ -259,7 +268,7 @@ def testMaxPageWidthAndSize(self): # add a page page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") collection.addPage(page) self.assertEqual(collection.maximumPageWidth(), 210.0) self.assertEqual(collection.maximumPageSize().width(), 210.0) @@ -267,7 +276,7 @@ def testMaxPageWidthAndSize(self): # add a second page page2 = QgsLayoutItemPage(l) - page2.setPageSize('A3') + page2.setPageSize("A3") collection.addPage(page2) self.assertEqual(collection.maximumPageWidth(), 297.0) self.assertEqual(collection.maximumPageSize().width(), 297.0) @@ -293,19 +302,21 @@ def testUniformPageSizes(self): # add a page page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") collection.addPage(page) self.assertTrue(collection.hasUniformPageSizes()) # add a second page page2 = QgsLayoutItemPage(l) - page2.setPageSize(QgsLayoutSize(21.0, 29.7, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + page2.setPageSize( + QgsLayoutSize(21.0, 29.7, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) collection.addPage(page2) self.assertTrue(collection.hasUniformPageSizes()) # add a page with other units page3 = QgsLayoutItemPage(l) - page3.setPageSize('A5') + page3.setPageSize("A5") collection.addPage(page3) self.assertFalse(collection.hasUniformPageSizes()) @@ -319,7 +330,7 @@ def testReflow(self): # add a page page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") collection.addPage(page) # should be positioned at origin @@ -328,7 +339,7 @@ def testReflow(self): # second page page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") collection.addPage(page2) self.assertEqual(page.pos().x(), 0) @@ -338,7 +349,7 @@ def testReflow(self): # third page, slotted in middle page3 = QgsLayoutItemPage(l) - page3.setPageSize('A3') + page3.setPageSize("A3") collection.insertPage(page3, 1) self.assertEqual(page.pos().x(), 0) @@ -371,10 +382,10 @@ def testInsertPageWithItems(self): # add a page page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") collection.addPage(page) page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") collection.addPage(page2) # item on pages @@ -393,7 +404,7 @@ def testInsertPageWithItems(self): # third page, slotted in middle page3 = QgsLayoutItemPage(l) - page3.setPageSize('A3') + page3.setPageSize("A3") collection.insertPage(page3, 0) # check item position @@ -409,13 +420,13 @@ def testDeletePageWithItems(self): # add a page page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") collection.addPage(page) page2 = QgsLayoutItemPage(l) - page2.setPageSize('A4') + page2.setPageSize("A4") collection.addPage(page2) page3 = QgsLayoutItemPage(l) - page3.setPageSize('A4') + page3.setPageSize("A4") collection.addPage(page3) # item on pages @@ -447,13 +458,13 @@ def testDeletePageWithItems2(self): # add a page page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") collection.addPage(page) page2 = QgsLayoutItemPage(l) - page2.setPageSize('A4') + page2.setPageSize("A4") collection.addPage(page2) page3 = QgsLayoutItemPage(l) - page3.setPageSize('A4') + page3.setPageSize("A4") collection.addPage(page3) # item on pages @@ -485,13 +496,13 @@ def testDataDefinedSize(self): # add some pages page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") collection.addPage(page) page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") collection.addPage(page2) page3 = QgsLayoutItemPage(l) - page3.setPageSize('A5') + page3.setPageSize("A5") collection.addPage(page3) self.assertEqual(page.pos().x(), 0) @@ -501,7 +512,10 @@ def testDataDefinedSize(self): self.assertEqual(page3.pos().x(), 0) self.assertEqual(page3.pos().y(), 527) - page.dataDefinedProperties().setProperty(QgsLayoutObject.DataDefinedProperty.ItemHeight, QgsProperty.fromExpression('50*3')) + page.dataDefinedProperties().setProperty( + QgsLayoutObject.DataDefinedProperty.ItemHeight, + QgsProperty.fromExpression("50*3"), + ) page.refresh() collection.reflow() self.assertEqual(page.pos().x(), 0) @@ -511,7 +525,10 @@ def testDataDefinedSize(self): self.assertEqual(page3.pos().x(), 0) self.assertEqual(page3.pos().y(), 380) - page2.dataDefinedProperties().setProperty(QgsLayoutObject.DataDefinedProperty.ItemHeight, QgsProperty.fromExpression('50-20')) + page2.dataDefinedProperties().setProperty( + QgsLayoutObject.DataDefinedProperty.ItemHeight, + QgsProperty.fromExpression("50-20"), + ) page2.refresh() collection.reflow() self.assertEqual(page.pos().x(), 0) @@ -531,7 +548,7 @@ def testPositionOnPage(self): # add a page page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") collection.addPage(page) self.assertEqual(collection.pageNumberForPoint(QPointF(-100, -100)), 0) @@ -540,14 +557,22 @@ def testPositionOnPage(self): self.assertEqual(collection.pageNumberForPoint(QPointF(-100, 270)), 0) self.assertEqual(collection.pageNumberForPoint(QPointF(-100, 1270)), 0) - self.assertEqual(collection.positionOnPage(QPointF(-100, -100)), QPointF(-100, -100)) - self.assertEqual(collection.positionOnPage(QPointF(-100, -1)), QPointF(-100, -1)) + self.assertEqual( + collection.positionOnPage(QPointF(-100, -100)), QPointF(-100, -100) + ) + self.assertEqual( + collection.positionOnPage(QPointF(-100, -1)), QPointF(-100, -1) + ) self.assertEqual(collection.positionOnPage(QPointF(-100, 1)), QPointF(-100, 1)) - self.assertEqual(collection.positionOnPage(QPointF(-100, 270)), QPointF(-100, 270)) - self.assertEqual(collection.positionOnPage(QPointF(-100, 1270)), QPointF(-100, 973)) + self.assertEqual( + collection.positionOnPage(QPointF(-100, 270)), QPointF(-100, 270) + ) + self.assertEqual( + collection.positionOnPage(QPointF(-100, 1270)), QPointF(-100, 973) + ) page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") collection.addPage(page2) self.assertEqual(collection.pageNumberForPoint(QPointF(-100, -100)), 0) @@ -557,12 +582,22 @@ def testPositionOnPage(self): self.assertEqual(collection.pageNumberForPoint(QPointF(-100, 370)), 1) self.assertEqual(collection.pageNumberForPoint(QPointF(-100, 1270)), 1) - self.assertEqual(collection.positionOnPage(QPointF(-100, -100)), QPointF(-100, -100)) - self.assertEqual(collection.positionOnPage(QPointF(-100, -1)), QPointF(-100, -1)) + self.assertEqual( + collection.positionOnPage(QPointF(-100, -100)), QPointF(-100, -100) + ) + self.assertEqual( + collection.positionOnPage(QPointF(-100, -1)), QPointF(-100, -1) + ) self.assertEqual(collection.positionOnPage(QPointF(-100, 1)), QPointF(-100, 1)) - self.assertEqual(collection.positionOnPage(QPointF(-100, 270)), QPointF(-100, 270)) - self.assertEqual(collection.positionOnPage(QPointF(-100, 370)), QPointF(-100, 63)) - self.assertEqual(collection.positionOnPage(QPointF(-100, 1270)), QPointF(-100, 753)) + self.assertEqual( + collection.positionOnPage(QPointF(-100, 270)), QPointF(-100, 270) + ) + self.assertEqual( + collection.positionOnPage(QPointF(-100, 370)), QPointF(-100, 63) + ) + self.assertEqual( + collection.positionOnPage(QPointF(-100, 1270)), QPointF(-100, 753) + ) def testPredictionPageNumberForPoint(self): """ @@ -627,7 +662,7 @@ def testPageAtPoint(self): # add a page page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") collection.addPage(page) self.assertFalse(collection.pageAtPoint(QPointF(10, -1))) @@ -639,7 +674,7 @@ def testPageAtPoint(self): self.assertFalse(collection.pageAtPoint(QPointF(10, 1000))) page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") collection.addPage(page2) self.assertEqual(collection.pageAtPoint(QPointF(1, 1)), page) @@ -660,43 +695,91 @@ def testPagePositionToLayout(self): collection = l.pageCollection() # invalid pages - self.assertEqual(collection.pagePositionToLayoutPosition(-1, QgsLayoutPoint(1, 1)), QPointF(1, 1)) - self.assertEqual(collection.pagePositionToLayoutPosition(0, QgsLayoutPoint(1, 1)), QPointF(1, 1)) - self.assertEqual(collection.pagePositionToLayoutPosition(100, QgsLayoutPoint(1, 1)), QPointF(1, 1)) + self.assertEqual( + collection.pagePositionToLayoutPosition(-1, QgsLayoutPoint(1, 1)), + QPointF(1, 1), + ) + self.assertEqual( + collection.pagePositionToLayoutPosition(0, QgsLayoutPoint(1, 1)), + QPointF(1, 1), + ) + self.assertEqual( + collection.pagePositionToLayoutPosition(100, QgsLayoutPoint(1, 1)), + QPointF(1, 1), + ) # add a page page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") collection.addPage(page) # invalid pages - self.assertEqual(collection.pagePositionToLayoutPosition(-1, QgsLayoutPoint(1, 1)), QPointF(1, 1)) - self.assertEqual(collection.pagePositionToLayoutPosition(1, QgsLayoutPoint(1, 1)), QPointF(1, 1)) + self.assertEqual( + collection.pagePositionToLayoutPosition(-1, QgsLayoutPoint(1, 1)), + QPointF(1, 1), + ) + self.assertEqual( + collection.pagePositionToLayoutPosition(1, QgsLayoutPoint(1, 1)), + QPointF(1, 1), + ) # valid page - self.assertEqual(collection.pagePositionToLayoutPosition(0, QgsLayoutPoint(1, 1)), QPointF(1, 1)) - self.assertEqual(collection.pagePositionToLayoutPosition(0, QgsLayoutPoint(5, 6)), QPointF(5, 6)) self.assertEqual( - collection.pagePositionToLayoutPosition(0, QgsLayoutPoint(5, 6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)), - QPointF(50, 60)) + collection.pagePositionToLayoutPosition(0, QgsLayoutPoint(1, 1)), + QPointF(1, 1), + ) + self.assertEqual( + collection.pagePositionToLayoutPosition(0, QgsLayoutPoint(5, 6)), + QPointF(5, 6), + ) + self.assertEqual( + collection.pagePositionToLayoutPosition( + 0, QgsLayoutPoint(5, 6, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ), + QPointF(50, 60), + ) page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") collection.addPage(page2) # invalid pages - self.assertEqual(collection.pagePositionToLayoutPosition(-1, QgsLayoutPoint(1, 1)), QPointF(1, 1)) - self.assertEqual(collection.pagePositionToLayoutPosition(3, QgsLayoutPoint(1, 1)), QPointF(1, 1)) + self.assertEqual( + collection.pagePositionToLayoutPosition(-1, QgsLayoutPoint(1, 1)), + QPointF(1, 1), + ) + self.assertEqual( + collection.pagePositionToLayoutPosition(3, QgsLayoutPoint(1, 1)), + QPointF(1, 1), + ) # valid pages - self.assertEqual(collection.pagePositionToLayoutPosition(0, QgsLayoutPoint(1, 1)), QPointF(1, 1)) - self.assertEqual(collection.pagePositionToLayoutPosition(0, QgsLayoutPoint(5, 6)), QPointF(5, 6)) self.assertEqual( - collection.pagePositionToLayoutPosition(0, QgsLayoutPoint(5, 6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)), - QPointF(50, 60)) - self.assertEqual(collection.pagePositionToLayoutPosition(1, QgsLayoutPoint(1, 1)), QPointF(1, 308.0)) - self.assertEqual(collection.pagePositionToLayoutPosition(1, QgsLayoutPoint(5, 6)), QPointF(5, 313.0)) + collection.pagePositionToLayoutPosition(0, QgsLayoutPoint(1, 1)), + QPointF(1, 1), + ) + self.assertEqual( + collection.pagePositionToLayoutPosition(0, QgsLayoutPoint(5, 6)), + QPointF(5, 6), + ) self.assertEqual( - collection.pagePositionToLayoutPosition(1, QgsLayoutPoint(0.5, 0.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)), - QPointF(5, 313.0)) + collection.pagePositionToLayoutPosition( + 0, QgsLayoutPoint(5, 6, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ), + QPointF(50, 60), + ) + self.assertEqual( + collection.pagePositionToLayoutPosition(1, QgsLayoutPoint(1, 1)), + QPointF(1, 308.0), + ) + self.assertEqual( + collection.pagePositionToLayoutPosition(1, QgsLayoutPoint(5, 6)), + QPointF(5, 313.0), + ) + self.assertEqual( + collection.pagePositionToLayoutPosition( + 1, QgsLayoutPoint(0.5, 0.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ), + QPointF(5, 313.0), + ) def testPagePositionToAbsolute(self): """ @@ -707,40 +790,91 @@ def testPagePositionToAbsolute(self): collection = l.pageCollection() # invalid pages - self.assertEqual(collection.pagePositionToAbsolute(-1, QgsLayoutPoint(1, 1)), QgsLayoutPoint(1, 1)) - self.assertEqual(collection.pagePositionToAbsolute(0, QgsLayoutPoint(1, 1)), QgsLayoutPoint(1, 1)) - self.assertEqual(collection.pagePositionToAbsolute(100, QgsLayoutPoint(1, 1)), QgsLayoutPoint(1, 1)) + self.assertEqual( + collection.pagePositionToAbsolute(-1, QgsLayoutPoint(1, 1)), + QgsLayoutPoint(1, 1), + ) + self.assertEqual( + collection.pagePositionToAbsolute(0, QgsLayoutPoint(1, 1)), + QgsLayoutPoint(1, 1), + ) + self.assertEqual( + collection.pagePositionToAbsolute(100, QgsLayoutPoint(1, 1)), + QgsLayoutPoint(1, 1), + ) # add a page page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") collection.addPage(page) # invalid pages - self.assertEqual(collection.pagePositionToAbsolute(-1, QgsLayoutPoint(1, 1)), QgsLayoutPoint(1, 1)) - self.assertEqual(collection.pagePositionToAbsolute(1, QgsLayoutPoint(1, 1)), QgsLayoutPoint(1, 1)) + self.assertEqual( + collection.pagePositionToAbsolute(-1, QgsLayoutPoint(1, 1)), + QgsLayoutPoint(1, 1), + ) + self.assertEqual( + collection.pagePositionToAbsolute(1, QgsLayoutPoint(1, 1)), + QgsLayoutPoint(1, 1), + ) # valid page - self.assertEqual(collection.pagePositionToAbsolute(0, QgsLayoutPoint(1, 1)), QgsLayoutPoint(1, 1)) - self.assertEqual(collection.pagePositionToAbsolute(0, QgsLayoutPoint(5, 6)), QgsLayoutPoint(5, 6)) - self.assertEqual(collection.pagePositionToAbsolute(0, QgsLayoutPoint(5, 6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)), - QgsLayoutPoint(5, 6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + collection.pagePositionToAbsolute(0, QgsLayoutPoint(1, 1)), + QgsLayoutPoint(1, 1), + ) + self.assertEqual( + collection.pagePositionToAbsolute(0, QgsLayoutPoint(5, 6)), + QgsLayoutPoint(5, 6), + ) + self.assertEqual( + collection.pagePositionToAbsolute( + 0, QgsLayoutPoint(5, 6, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ), + QgsLayoutPoint(5, 6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") collection.addPage(page2) # invalid pages - self.assertEqual(collection.pagePositionToAbsolute(-1, QgsLayoutPoint(1, 1)), QgsLayoutPoint(1, 1)) - self.assertEqual(collection.pagePositionToAbsolute(3, QgsLayoutPoint(1, 1)), QgsLayoutPoint(1, 1)) + self.assertEqual( + collection.pagePositionToAbsolute(-1, QgsLayoutPoint(1, 1)), + QgsLayoutPoint(1, 1), + ) + self.assertEqual( + collection.pagePositionToAbsolute(3, QgsLayoutPoint(1, 1)), + QgsLayoutPoint(1, 1), + ) # valid pages - self.assertEqual(collection.pagePositionToAbsolute(0, QgsLayoutPoint(1, 1)), QgsLayoutPoint(1, 1)) - self.assertEqual(collection.pagePositionToAbsolute(0, QgsLayoutPoint(5, 6)), QgsLayoutPoint(5, 6)) - self.assertEqual(collection.pagePositionToAbsolute(0, QgsLayoutPoint(5, 6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)), - QgsLayoutPoint(5, 6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - self.assertEqual(collection.pagePositionToAbsolute(1, QgsLayoutPoint(1, 1)), QgsLayoutPoint(1, 308.0)) - self.assertEqual(collection.pagePositionToAbsolute(1, QgsLayoutPoint(5, 6)), QgsLayoutPoint(5, 313.0)) - self.assertEqual(collection.pagePositionToAbsolute(1, QgsLayoutPoint(0.5, 0.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)), - QgsLayoutPoint(0.5, 31.3, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + collection.pagePositionToAbsolute(0, QgsLayoutPoint(1, 1)), + QgsLayoutPoint(1, 1), + ) + self.assertEqual( + collection.pagePositionToAbsolute(0, QgsLayoutPoint(5, 6)), + QgsLayoutPoint(5, 6), + ) + self.assertEqual( + collection.pagePositionToAbsolute( + 0, QgsLayoutPoint(5, 6, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ), + QgsLayoutPoint(5, 6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + self.assertEqual( + collection.pagePositionToAbsolute(1, QgsLayoutPoint(1, 1)), + QgsLayoutPoint(1, 308.0), + ) + self.assertEqual( + collection.pagePositionToAbsolute(1, QgsLayoutPoint(5, 6)), + QgsLayoutPoint(5, 313.0), + ) + self.assertEqual( + collection.pagePositionToAbsolute( + 1, QgsLayoutPoint(0.5, 0.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ), + QgsLayoutPoint(0.5, 31.3, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) def testVisiblePages(self): p = QgsProject() @@ -752,7 +886,7 @@ def testVisiblePages(self): # add a page page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") collection.addPage(page) self.assertFalse(collection.visiblePages(QRectF(-10, -10, 5, 5))) @@ -763,7 +897,7 @@ def testVisiblePages(self): self.assertEqual(collection.visiblePageNumbers(QRectF(200, 200, 115, 115)), [0]) page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") collection.addPage(page2) self.assertFalse(collection.visiblePages(QRectF(-10, -10, 5, 5))) @@ -775,8 +909,12 @@ def testVisiblePages(self): self.assertEqual(collection.visiblePages(QRectF(200, 200, 115, 615)), [page]) self.assertEqual(collection.visiblePageNumbers(QRectF(200, 200, 115, 115)), [0]) - self.assertEqual(collection.visiblePages(QRectF(100, 200, 115, 615)), [page, page2]) - self.assertEqual(collection.visiblePageNumbers(QRectF(100, 200, 115, 115)), [0, 1]) + self.assertEqual( + collection.visiblePages(QRectF(100, 200, 115, 615)), [page, page2] + ) + self.assertEqual( + collection.visiblePageNumbers(QRectF(100, 200, 115, 115)), [0, 1] + ) self.assertEqual(collection.visiblePages(QRectF(100, 310, 115, 615)), [page2]) self.assertEqual(collection.visiblePageNumbers(QRectF(100, 310, 115, 115)), [1]) @@ -787,10 +925,10 @@ def testTakePage(self): # add some pages page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") collection.addPage(page) page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") collection.addPage(page2) self.assertEqual(collection.pageCount(), 2) @@ -826,14 +964,14 @@ def testReadWriteXml(self): # add a page page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") self.assertEqual(collection.pageNumber(page), -1) collection.addPage(page) # add a second page page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") collection.addPage(page2) doc = QDomDocument("testdoc") @@ -843,7 +981,9 @@ def testReadWriteXml(self): l2 = QgsLayout(p) collection2 = l2.pageCollection() - self.assertTrue(collection2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext())) + self.assertTrue( + collection2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext()) + ) self.assertEqual(collection2.pageCount(), 2) self.assertEqual(collection2.page(0).pageSize().width(), 210) @@ -851,8 +991,12 @@ def testReadWriteXml(self): self.assertEqual(collection2.page(1).pageSize().width(), 148) self.assertEqual(collection2.page(1).pageSize().height(), 210) - self.assertEqual(collection2.pageStyleSymbol().symbolLayer(0).color().name(), '#00ff00') - self.assertEqual(collection2.pageStyleSymbol().symbolLayer(0).strokeColor().name(), '#ff0000') + self.assertEqual( + collection2.pageStyleSymbol().symbolLayer(0).color().name(), "#00ff00" + ) + self.assertEqual( + collection2.pageStyleSymbol().symbolLayer(0).strokeColor().name(), "#ff0000" + ) def testUndoRedo(self): p = QgsProject() @@ -861,7 +1005,7 @@ def testUndoRedo(self): # add a page page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") collection.addPage(page) self.assertEqual(collection.pageCount(), 1) @@ -875,7 +1019,7 @@ def testUndoRedo(self): # add a second page page2 = QgsLayoutItemPage(l) - page2.setPageSize('A5') + page2.setPageSize("A5") collection.addPage(page2) # delete page @@ -909,15 +1053,23 @@ def testResizeToContents(self): l = QgsLayout(p) # no items -- no crash! - l.pageCollection().resizeToContents(QgsMargins(1, 2, 3, 4), QgsUnitTypes.LayoutUnit.LayoutCentimeters) + l.pageCollection().resizeToContents( + QgsMargins(1, 2, 3, 4), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) page = QgsLayoutItemPage(l) page.setPageSize("A5", QgsLayoutItemPage.Orientation.Landscape) l.pageCollection().addPage(page) # no items, no change - l.pageCollection().resizeToContents(QgsMargins(1, 2, 3, 4), QgsUnitTypes.LayoutUnit.LayoutCentimeters) + l.pageCollection().resizeToContents( + QgsMargins(1, 2, 3, 4), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) self.assertEqual(l.pageCollection().pageCount(), 1) - self.assertAlmostEqual(l.pageCollection().page(0).sizeWithUnits().width(), 210.0, 2) - self.assertAlmostEqual(l.pageCollection().page(0).sizeWithUnits().height(), 148.0, 2) + self.assertAlmostEqual( + l.pageCollection().page(0).sizeWithUnits().width(), 210.0, 2 + ) + self.assertAlmostEqual( + l.pageCollection().page(0).sizeWithUnits().height(), 148.0, 2 + ) p = QgsProject() l = QgsLayout(p) @@ -941,12 +1093,21 @@ def testResizeToContents(self): shape4.setVisibility(False) # resize with no existing pages - l.pageCollection().resizeToContents(QgsMargins(1, 2, 3, 4), QgsUnitTypes.LayoutUnit.LayoutCentimeters) + l.pageCollection().resizeToContents( + QgsMargins(1, 2, 3, 4), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) self.assertEqual(l.pageCollection().pageCount(), 1) - self.assertAlmostEqual(l.pageCollection().page(0).sizeWithUnits().width(), 290.3, 2) - self.assertAlmostEqual(l.pageCollection().page(0).sizeWithUnits().height(), 380.36, 2) - self.assertAlmostEqual(l.pageCollection().page(0).sizeWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) + self.assertAlmostEqual( + l.pageCollection().page(0).sizeWithUnits().width(), 290.3, 2 + ) + self.assertAlmostEqual( + l.pageCollection().page(0).sizeWithUnits().height(), 380.36, 2 + ) + self.assertAlmostEqual( + l.pageCollection().page(0).sizeWithUnits().units(), + QgsUnitTypes.LayoutUnit.LayoutMillimeters, + ) self.assertAlmostEqual(shape1.positionWithUnits().x(), 90.15, 2) self.assertAlmostEqual(shape1.positionWithUnits().y(), 20.21, 2) @@ -963,24 +1124,39 @@ def testResizeToContents(self): l.pageCollection().addPage(page2) # add some guides - g1 = QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(2.5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), - l.pageCollection().page(0)) + g1 = QgsLayoutGuide( + Qt.Orientation.Horizontal, + QgsLayoutMeasurement(2.5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + l.pageCollection().page(0), + ) l.guides().addGuide(g1) - g2 = QgsLayoutGuide(Qt.Orientation.Vertical, QgsLayoutMeasurement(4.5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), - l.pageCollection().page(0)) + g2 = QgsLayoutGuide( + Qt.Orientation.Vertical, + QgsLayoutMeasurement(4.5, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + l.pageCollection().page(0), + ) l.guides().addGuide(g2) # second page should be removed - l.pageCollection().resizeToContents(QgsMargins(0, 0, 0, 0), QgsUnitTypes.LayoutUnit.LayoutCentimeters) + l.pageCollection().resizeToContents( + QgsMargins(0, 0, 0, 0), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) self.assertEqual(l.pageCollection().pageCount(), 1) - self.assertAlmostEqual(l.pageCollection().page(0).sizeWithUnits().width(), 250.3, 2) - self.assertAlmostEqual(l.pageCollection().page(0).sizeWithUnits().height(), 320.36, 2) - self.assertAlmostEqual(l.pageCollection().page(0).sizeWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) + self.assertAlmostEqual( + l.pageCollection().page(0).sizeWithUnits().width(), 250.3, 2 + ) + self.assertAlmostEqual( + l.pageCollection().page(0).sizeWithUnits().height(), 320.36, 2 + ) + self.assertAlmostEqual( + l.pageCollection().page(0).sizeWithUnits().units(), + QgsUnitTypes.LayoutUnit.LayoutMillimeters, + ) self.assertAlmostEqual(g1.position().length(), 0.5, 2) self.assertAlmostEqual(g2.position().length(), 3.5, 2) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutpicture.py b/tests/src/python/test_qgslayoutpicture.py index 0f0d88c9033d..ed5d161ca54d 100644 --- a/tests/src/python/test_qgslayoutpicture.py +++ b/tests/src/python/test_qgslayoutpicture.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2017 by Nyall Dawson' -__date__ = '23/10/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "(C) 2017 by Nyall Dawson" +__date__ = "23/10/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import http.server import os @@ -24,7 +25,7 @@ QgsLayoutItemPicture, QgsProject, QgsReadWriteContext, - QgsRectangle + QgsRectangle, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -44,14 +45,14 @@ def control_path_prefix(cls): @classmethod def setUpClass(cls): - super(TestQgsLayoutPicture, cls).setUpClass() + super().setUpClass() cls.item_class = QgsLayoutItemPicture # Bring up a simple HTTP server, for remote picture tests - os.chdir(unitTestDataPath() + '') + os.chdir(unitTestDataPath() + "") handler = http.server.SimpleHTTPRequestHandler - cls.httpd = socketserver.TCPServer(('localhost', 0), handler) + cls.httpd = socketserver.TCPServer(("localhost", 0), handler) cls.port = cls.httpd.server_address[1] cls.httpd_thread = threading.Thread(target=cls.httpd.serve_forever) @@ -119,14 +120,18 @@ def testReadWriteXml(self): self.assertTrue(pic.writeXml(elem, doc, QgsReadWriteContext())) pic2 = QgsLayoutItemPicture(l) - self.assertTrue(pic2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext())) + self.assertTrue( + pic2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext()) + ) self.assertEqual(pic2.mode(), QgsLayoutItemPicture.Format.FormatRaster) pic.setMode(QgsLayoutItemPicture.Format.FormatSVG) elem = doc.createElement("test2") self.assertTrue(pic.writeXml(elem, doc, QgsReadWriteContext())) pic3 = QgsLayoutItemPicture(l) - self.assertTrue(pic3.readXml(elem.firstChildElement(), doc, QgsReadWriteContext())) + self.assertTrue( + pic3.readXml(elem.firstChildElement(), doc, QgsReadWriteContext()) + ) self.assertEqual(pic3.mode(), QgsLayoutItemPicture.Format.FormatSVG) def testResizeZoom(self): @@ -134,22 +139,19 @@ def testResizeZoom(self): self.picture.setResizeMode(QgsLayoutItemPicture.ResizeMode.Zoom) self.assertTrue( - self.render_layout_check( - 'composerpicture_resize_zoom', - self.layout - ) + self.render_layout_check("composerpicture_resize_zoom", self.layout) ) def testRemoteImage(self): """Test fetching remote picture.""" self.picture.setPicturePath( - 'http://localhost:' + str(TestQgsLayoutPicture.port) + '/qgis_local_server/logo.png') - - res = self.render_layout_check( - 'composerpicture_remote', - self.layout + "http://localhost:" + + str(TestQgsLayoutPicture.port) + + "/qgis_local_server/logo.png" ) + res = self.render_layout_check("composerpicture_remote", self.layout) + self.picture.setPicturePath(self.pngImage) self.assertTrue(res) @@ -212,7 +214,9 @@ def testTrueNorth(self): map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(0, 0, 10, 10)) map.setCrs(QgsCoordinateReferenceSystem.fromEpsgId(3575)) - map.setExtent(QgsRectangle(-2126029.962, -2200807.749, -119078.102, -757031.156)) + map.setExtent( + QgsRectangle(-2126029.962, -2200807.749, -119078.102, -757031.156) + ) layout.addLayoutItem(map) picture = QgsLayoutItemPicture(layout) @@ -225,7 +229,9 @@ def testTrueNorth(self): self.assertAlmostEqual(picture.pictureRotation(), 37.20, 1) # shift map - map.setExtent(QgsRectangle(2120672.293, -3056394.691, 2481640.226, -2796718.780)) + map.setExtent( + QgsRectangle(2120672.293, -3056394.691, 2481640.226, -2796718.780) + ) self.assertAlmostEqual(picture.pictureRotation(), -38.18, 1) # rotate map @@ -252,5 +258,5 @@ def testMissingImage(self): self.assertEqual(picture.mode(), QgsLayoutItemPicture.Format.FormatRaster) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutpolygon.py b/tests/src/python/test_qgslayoutpolygon.py index 115e41868a21..fb7696ffc04c 100644 --- a/tests/src/python/test_qgslayoutpolygon.py +++ b/tests/src/python/test_qgslayoutpolygon.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2016 by Paul Blottiere' -__date__ = '14/03/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "(C) 2016 by Paul Blottiere" +__date__ = "14/03/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtCore import QPointF, QRectF from qgis.PyQt.QtGui import QImage, QPainter, QPolygonF @@ -26,7 +27,7 @@ QgsLayoutItemMap, QgsRectangle, Qgis, - QgsGeometryGeneratorSymbolLayer + QgsGeometryGeneratorSymbolLayer, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -46,7 +47,7 @@ def control_path_prefix(cls): @classmethod def setUpClass(cls): - super(TestQgsLayoutPolygon, cls).setUpClass() + super().setUpClass() cls.item_class = QgsLayoutItemPolygon def __init__(self, methodName): @@ -107,17 +108,15 @@ def testType(self): """Test if type is valid""" self.assertEqual( - self.polygon.type(), QgsLayoutItemRegistry.ItemType.LayoutPolygon) + self.polygon.type(), QgsLayoutItemRegistry.ItemType.LayoutPolygon + ) def testDefaultStyle(self): """Test polygon rendering with default style.""" self.polygon.setDisplayNodes(False) self.assertTrue( - self.render_layout_check( - 'composerpolygon_defaultstyle', - self.layout - ) + self.render_layout_check("composerpolygon_defaultstyle", self.layout) ) def testDisplayNodes(self): @@ -125,18 +124,12 @@ def testDisplayNodes(self): self.polygon.setDisplayNodes(True) self.assertTrue( - self.render_layout_check( - 'composerpolygon_displaynodes', - self.layout - ) + self.render_layout_check("composerpolygon_displaynodes", self.layout) ) self.polygon.setDisplayNodes(False) self.assertTrue( - self.render_layout_check( - 'composerpolygon_defaultstyle', - self.layout - ) + self.render_layout_check("composerpolygon_defaultstyle", self.layout) ) def testSelectedNode(self): @@ -146,19 +139,13 @@ def testSelectedNode(self): self.polygon.setSelectedNode(3) self.assertTrue( - self.render_layout_check( - 'composerpolygon_selectednode', - self.layout - ) + self.render_layout_check("composerpolygon_selectednode", self.layout) ) self.polygon.deselectNode() self.polygon.setDisplayNodes(False) self.assertTrue( - self.render_layout_check( - 'composerpolygon_defaultstyle', - self.layout - ) + self.render_layout_check("composerpolygon_defaultstyle", self.layout) ) def testRemoveNode(self): @@ -168,10 +155,7 @@ def testRemoveNode(self): self.assertEqual(rc, False) self.assertTrue( - self.render_layout_check( - 'composerpolygon_defaultstyle', - self.layout - ) + self.render_layout_check("composerpolygon_defaultstyle", self.layout) ) self.assertEqual(self.polygon.nodesSize(), 4) @@ -220,10 +204,7 @@ def testAddNodeWithoutCheckingArea(self): self.assertEqual(self.polygon.nodesSize(), 5) self.assertTrue( - self.render_layout_check( - 'composerpolygon_addnode', - self.layout - ) + self.render_layout_check("composerpolygon_addnode", self.layout) ) def testMoveNode(self): @@ -236,10 +217,7 @@ def testMoveNode(self): self.assertEqual(rc, True) self.assertTrue( - self.render_layout_check( - 'composerpolygon_movenode', - self.layout - ) + self.render_layout_check("composerpolygon_movenode", self.layout) ) def testNodeAtPosition(self): @@ -258,13 +236,11 @@ def testNodeAtPosition(self): self.assertEqual(rc, -1) # default searching radius is 10 - rc = polygon.nodeAtPosition( - QPointF(100.0, 210.0), False) + rc = polygon.nodeAtPosition(QPointF(100.0, 210.0), False) self.assertEqual(rc, 3) # default searching radius is 10 - rc = polygon.nodeAtPosition( - QPointF(100.0, 210.0), True, 10.1) + rc = polygon.nodeAtPosition(QPointF(100.0, 210.0), True, 10.1) self.assertEqual(rc, 3) def testReadWriteXml(self): @@ -294,11 +270,13 @@ def testReadWriteXml(self): self.assertTrue(shape.writeXml(elem, doc, QgsReadWriteContext())) shape2 = QgsLayoutItemPolygon(l) - self.assertTrue(shape2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext())) + self.assertTrue( + shape2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext()) + ) self.assertEqual(shape2.nodes(), shape.nodes()) - self.assertEqual(shape2.symbol().symbolLayer(0).color().name(), '#008000') - self.assertEqual(shape2.symbol().symbolLayer(0).strokeColor().name(), '#ff0000') + self.assertEqual(shape2.symbol().symbolLayer(0).color().name(), "#008000") + self.assertEqual(shape2.symbol().symbolLayer(0).strokeColor().name(), "#ff0000") def testBounds(self): pr = QgsProject() @@ -346,28 +324,43 @@ def testClipPath(self): shape = QgsLayoutItemPolygon(p, l) # must be a closed polygon, in scene coordinates! - self.assertEqual(shape.clipPath().asWkt(), 'Polygon ((50 30, 100 10, 200 100, 50 30))') - self.assertTrue(int(shape.itemFlags() & QgsLayoutItem.Flag.FlagProvidesClipPath)) + self.assertEqual( + shape.clipPath().asWkt(), "Polygon ((50 30, 100 10, 200 100, 50 30))" + ) + self.assertTrue( + int(shape.itemFlags() & QgsLayoutItem.Flag.FlagProvidesClipPath) + ) spy = QSignalSpy(shape.clipPathChanged) self.assertTrue(shape.addNode(QPointF(150, 110), False)) - self.assertEqual(shape.clipPath().asWkt(), 'Polygon ((50 30, 100 10, 200 100, 150 110, 50 30))') + self.assertEqual( + shape.clipPath().asWkt(), + "Polygon ((50 30, 100 10, 200 100, 150 110, 50 30))", + ) self.assertEqual(len(spy), 1) shape.removeNode(3) self.assertEqual(len(spy), 2) - self.assertEqual(shape.clipPath().asWkt(), 'Polygon ((50 30, 100 10, 200 100, 50 30))') + self.assertEqual( + shape.clipPath().asWkt(), "Polygon ((50 30, 100 10, 200 100, 50 30))" + ) shape.moveNode(2, QPointF(180, 100)) self.assertEqual(len(spy), 3) - self.assertEqual(shape.clipPath().asWkt(), 'Polygon ((50 30, 100 10, 180 100, 50 30))') + self.assertEqual( + shape.clipPath().asWkt(), "Polygon ((50 30, 100 10, 180 100, 50 30))" + ) shape.setNodes(p) self.assertEqual(len(spy), 4) - self.assertEqual(shape.clipPath().asWkt(), 'Polygon ((100 40, 150 20, 250 110, 100 40))') + self.assertEqual( + shape.clipPath().asWkt(), "Polygon ((100 40, 150 20, 250 110, 100 40))" + ) shape.attemptSetSceneRect(QRectF(30, 10, 100, 200)) - self.assertEqual(shape.clipPath().asWkt(), 'Polygon ((30 30, 80 10, 180 100, 30 30))') + self.assertEqual( + shape.clipPath().asWkt(), "Polygon ((30 30, 80 10, 180 100, 30 30))" + ) # bit gross - this needs fixing in the item. It shouldn't rely on a draw operation to update the # path as a result of a move/resize im = QImage() @@ -405,23 +398,20 @@ def test_generator(self): sub_symbol = QgsFillSymbol.createSimple(props) line_symbol = QgsFillSymbol() - generator = QgsGeometryGeneratorSymbolLayer.create({ - 'geometryModifier': "geom_from_wkt('POLYGON((10 10,287 10,287 200,10 200,10 10))')", - 'SymbolType': 'Fill', - }) + generator = QgsGeometryGeneratorSymbolLayer.create( + { + "geometryModifier": "geom_from_wkt('POLYGON((10 10,287 10,287 200,10 200,10 10))')", + "SymbolType": "Fill", + } + ) generator.setUnits(Qgis.RenderUnit.Millimeters) generator.setSubSymbol(sub_symbol) line_symbol.changeSymbolLayer(0, generator) shape.setSymbol(line_symbol) - self.assertTrue( - self.render_layout_check( - 'polygon_generator', - layout - ) - ) + self.assertTrue(self.render_layout_check("polygon_generator", layout)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutpolyline.py b/tests/src/python/test_qgslayoutpolyline.py index 85350384e7e4..e585ef43a825 100644 --- a/tests/src/python/test_qgslayoutpolyline.py +++ b/tests/src/python/test_qgslayoutpolyline.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2016 by Paul Blottiere' -__date__ = '14/03/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "(C) 2016 by Paul Blottiere" +__date__ = "14/03/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtCore import QPointF, QRectF from qgis.PyQt.QtGui import QPolygonF @@ -22,7 +23,7 @@ QgsProject, QgsReadWriteContext, QgsGeometryGeneratorSymbolLayer, - QgsRectangle + QgsRectangle, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -42,7 +43,7 @@ def control_path_prefix(cls): @classmethod def setUpClass(cls): - super(TestQgsLayoutPolyline, cls).setUpClass() + super().setUpClass() cls.item_class = QgsLayoutItemPolyline def __init__(self, methodName): @@ -60,8 +61,7 @@ def __init__(self, methodName): polygon.append(QPointF(200.0, 100.0)) polygon.append(QPointF(100.0, 200.0)) - self.polyline = QgsLayoutItemPolyline( - polygon, self.layout) + self.polyline = QgsLayoutItemPolyline(polygon, self.layout) self.layout.addLayoutItem(self.polyline) # style @@ -101,17 +101,15 @@ def testType(self): """Test if type is valid""" self.assertEqual( - self.polyline.type(), QgsLayoutItemRegistry.ItemType.LayoutPolyline) + self.polyline.type(), QgsLayoutItemRegistry.ItemType.LayoutPolyline + ) def testDefaultStyle(self): """Test polygon rendering with default style.""" self.polyline.setDisplayNodes(False) self.assertTrue( - self.render_layout_check( - 'composerpolyline_defaultstyle', - self.layout - ) + self.render_layout_check("composerpolyline_defaultstyle", self.layout) ) def testDisplayNodes(self): @@ -119,18 +117,12 @@ def testDisplayNodes(self): self.polyline.setDisplayNodes(True) self.assertTrue( - self.render_layout_check( - 'composerpolyline_displaynodes', - self.layout - ) + self.render_layout_check("composerpolyline_displaynodes", self.layout) ) self.polyline.setDisplayNodes(False) self.assertTrue( - self.render_layout_check( - 'composerpolyline_defaultstyle', - self.layout - ) + self.render_layout_check("composerpolyline_defaultstyle", self.layout) ) def testSelectedNode(self): @@ -140,19 +132,13 @@ def testSelectedNode(self): self.polyline.setSelectedNode(3) self.assertTrue( - self.render_layout_check( - 'composerpolyline_selectednode', - self.layout - ) + self.render_layout_check("composerpolyline_selectednode", self.layout) ) self.polyline.deselectNode() self.polyline.setDisplayNodes(False) self.assertTrue( - self.render_layout_check( - 'composerpolyline_defaultstyle', - self.layout - ) + self.render_layout_check("composerpolyline_defaultstyle", self.layout) ) def testEndArrow(self): @@ -160,10 +146,7 @@ def testEndArrow(self): self.polyline.setArrowHeadWidth(30.0) self.assertTrue( - self.render_layout_check( - 'composerpolyline_endArrow', - self.layout - ) + self.render_layout_check("composerpolyline_endArrow", self.layout) ) self.polyline.setEndMarker(QgsLayoutItemPolyline.MarkerMode.NoMarker) @@ -174,10 +157,7 @@ def testRemoveNode(self): self.assertEqual(rc, False) self.assertTrue( - self.render_layout_check( - 'composerpolyline_defaultstyle', - self.layout - ) + self.render_layout_check("composerpolyline_defaultstyle", self.layout) ) self.assertEqual(self.polyline.nodesSize(), 4) @@ -186,10 +166,7 @@ def testRemoveNode(self): self.assertEqual(self.polyline.nodesSize(), 3) self.assertTrue( - self.render_layout_check( - 'composerpolyline_removednode', - self.layout - ) + self.render_layout_check("composerpolyline_removednode", self.layout) ) def testAddNode(self): @@ -236,10 +213,7 @@ def testAddNodeWithoutCheckingArea(self): self.assertEqual(self.polyline.nodesSize(), 5) self.assertTrue( - self.render_layout_check( - 'composerpolyline_addnode', - self.layout - ) + self.render_layout_check("composerpolyline_addnode", self.layout) ) def testMoveNode(self): @@ -252,10 +226,7 @@ def testMoveNode(self): self.assertEqual(rc, True) self.assertTrue( - self.render_layout_check( - 'composerpolyline_movenode', - self.layout - ) + self.render_layout_check("composerpolyline_movenode", self.layout) ) def testNodeAtPosition(self): @@ -266,13 +237,11 @@ def testNodeAtPosition(self): self.assertEqual(rc, -1) # default searching radius is 10 - rc = self.polyline.nodeAtPosition( - QPointF(100.0, 210.0), False) + rc = self.polyline.nodeAtPosition(QPointF(100.0, 210.0), False) self.assertEqual(rc, 3) # default searching radius is 10 - rc = self.polyline.nodeAtPosition( - QPointF(100.0, 210.0), True, 10.1) + rc = self.polyline.nodeAtPosition(QPointF(100.0, 210.0), True, 10.1) self.assertEqual(rc, 3) def testReadWriteXml(self): @@ -299,10 +268,12 @@ def testReadWriteXml(self): self.assertTrue(shape.writeXml(elem, doc, QgsReadWriteContext())) shape2 = QgsLayoutItemPolyline(l) - self.assertTrue(shape2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext())) + self.assertTrue( + shape2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext()) + ) self.assertEqual(shape2.nodes(), shape.nodes()) - self.assertEqual(shape2.symbol().symbolLayer(0).color().name(), '#ff0000') + self.assertEqual(shape2.symbol().symbolLayer(0).color().name(), "#ff0000") def testBounds(self): pr = QgsProject() @@ -355,12 +326,7 @@ def testHorizontalLine(self): style = QgsLineSymbol.createSimple(props) shape.setSymbol(style) - self.assertTrue( - self.render_layout_check( - 'composerpolyline_hozline', - l - ) - ) + self.assertTrue(self.render_layout_check("composerpolyline_hozline", l)) def testVerticalLine(self): pr = QgsProject() @@ -381,12 +347,7 @@ def testVerticalLine(self): style = QgsLineSymbol.createSimple(props) shape.setSymbol(style) - self.assertTrue( - self.render_layout_check( - 'composerpolyline_vertline', - l - ) - ) + self.assertTrue(self.render_layout_check("composerpolyline_vertline", l)) def test_generator(self): project = QgsProject() @@ -412,23 +373,20 @@ def test_generator(self): sub_symbol = QgsLineSymbol.createSimple(props) line_symbol = QgsLineSymbol() - generator = QgsGeometryGeneratorSymbolLayer.create({ - 'geometryModifier': "geom_from_wkt('POLYGON((10 10,287 10,287 200,10 200,10 10))')", - 'SymbolType': 'Line', - }) + generator = QgsGeometryGeneratorSymbolLayer.create( + { + "geometryModifier": "geom_from_wkt('POLYGON((10 10,287 10,287 200,10 200,10 10))')", + "SymbolType": "Line", + } + ) generator.setUnits(Qgis.RenderUnit.Millimeters) generator.setSubSymbol(sub_symbol) line_symbol.changeSymbolLayer(0, generator) shape.setSymbol(line_symbol) - self.assertTrue( - self.render_layout_check( - 'polyline_generator', - layout - ) - ) + self.assertTrue(self.render_layout_check("polyline_generator", layout)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutscalebar.py b/tests/src/python/test_qgslayoutscalebar.py index 0af5e9149ab3..f61b948d9a7d 100644 --- a/tests/src/python/test_qgslayoutscalebar.py +++ b/tests/src/python/test_qgslayoutscalebar.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2017 by Nyall Dawson' -__date__ = '23/10/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "(C) 2017 by Nyall Dawson" +__date__ = "23/10/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.core import QgsLayoutItemScaleBar import unittest @@ -22,9 +23,9 @@ class TestQgsLayoutScaleBar(QgisTestCase, LayoutItemTestCase): @classmethod def setUpClass(cls): - super(TestQgsLayoutScaleBar, cls).setUpClass() + super().setUpClass() cls.item_class = QgsLayoutItemScaleBar -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutshape.py b/tests/src/python/test_qgslayoutshape.py index 25a951149dc6..a49292f3355e 100644 --- a/tests/src/python/test_qgslayoutshape.py +++ b/tests/src/python/test_qgslayoutshape.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2017 by Nyall Dawson' -__date__ = '23/10/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "(C) 2017 by Nyall Dawson" +__date__ = "23/10/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtCore import QRectF from qgis.PyQt.QtTest import QSignalSpy @@ -24,7 +25,7 @@ QgsLayoutItemMap, Qgis, QgsGeometryGeneratorSymbolLayer, - QgsRectangle + QgsRectangle, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -38,7 +39,7 @@ class TestQgsLayoutShape(QgisTestCase, LayoutItemTestCase): @classmethod def setUpClass(cls): - super(TestQgsLayoutShape, cls).setUpClass() + super().setUpClass() cls.item_class = QgsLayoutItemShape @classmethod @@ -54,25 +55,44 @@ def testClipPath(self): shape.attemptSetSceneRect(QRectF(30, 10, 100, 200)) # must be a closed polygon, in scene coordinates! - self.assertEqual(shape.clipPath().asWkt(), 'Polygon ((30 10, 130 10, 130 210, 30 210, 30 10))') - self.assertTrue(int(shape.itemFlags() & QgsLayoutItem.Flag.FlagProvidesClipPath)) + self.assertEqual( + shape.clipPath().asWkt(), + "Polygon ((30 10, 130 10, 130 210, 30 210, 30 10))", + ) + self.assertTrue( + int(shape.itemFlags() & QgsLayoutItem.Flag.FlagProvidesClipPath) + ) spy = QSignalSpy(shape.clipPathChanged) - shape.setCornerRadius(QgsLayoutMeasurement(10, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertTrue(shape.clipPath().asWkt(0).startswith('Polygon ((30 20, 30 20, 30 19, 30 19, 30 19, 30 19')) + shape.setCornerRadius( + QgsLayoutMeasurement(10, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + self.assertTrue( + shape.clipPath() + .asWkt(0) + .startswith("Polygon ((30 20, 30 20, 30 19, 30 19, 30 19, 30 19") + ) self.assertEqual(len(spy), 1) shape.setShapeType(QgsLayoutItemShape.Shape.Ellipse) self.assertEqual(len(spy), 2) - self.assertTrue(shape.clipPath().asWkt(0).startswith('Polygon ((130 110, 130 111, 130 113, 130 114')) + self.assertTrue( + shape.clipPath() + .asWkt(0) + .startswith("Polygon ((130 110, 130 111, 130 113, 130 114") + ) shape.setShapeType(QgsLayoutItemShape.Shape.Triangle) self.assertEqual(len(spy), 3) - self.assertEqual(shape.clipPath().asWkt(), 'Polygon ((30 210, 130 210, 80 10, 30 210))') + self.assertEqual( + shape.clipPath().asWkt(), "Polygon ((30 210, 130 210, 80 10, 30 210))" + ) shape.attemptSetSceneRect(QRectF(50, 20, 80, 120)) self.assertEqual(len(spy), 4) - self.assertEqual(shape.clipPath().asWkt(), 'Polygon ((50 140, 130 140, 90 20, 50 140))') + self.assertEqual( + shape.clipPath().asWkt(), "Polygon ((50 140, 130 140, 90 20, 50 140))" + ) def testBoundingRectForStrokeSizeOnRestore(self): """ @@ -87,7 +107,9 @@ def testBoundingRectForStrokeSizeOnRestore(self): self.assertEqual(shape.boundingRect(), QRectF(-0.15, -0.15, 100.3, 200.3)) # set a symbol with very wide stroke - s = QgsFillSymbol.createSimple({'outline_color': '#ff0000', 'outline_width': '40', 'color': '#ff5588'}) + s = QgsFillSymbol.createSimple( + {"outline_color": "#ff0000", "outline_width": "40", "color": "#ff5588"} + ) shape.setSymbol(s) # bounding rect for item should include stroke self.assertEqual(shape.boundingRect(), QRectF(-20.0, -20.0, 140.0, 240.0)) @@ -135,23 +157,20 @@ def test_generator(self): sub_symbol = QgsFillSymbol.createSimple(props) line_symbol = QgsFillSymbol() - generator = QgsGeometryGeneratorSymbolLayer.create({ - 'geometryModifier': "geom_from_wkt('POLYGON((10 10,287 10,287 200,10 200,10 10))')", - 'SymbolType': 'Fill', - }) + generator = QgsGeometryGeneratorSymbolLayer.create( + { + "geometryModifier": "geom_from_wkt('POLYGON((10 10,287 10,287 200,10 200,10 10))')", + "SymbolType": "Fill", + } + ) generator.setUnits(Qgis.RenderUnit.Millimeters) generator.setSubSymbol(sub_symbol) line_symbol.changeSymbolLayer(0, generator) shape.setSymbol(line_symbol) - self.assertTrue( - self.render_layout_check( - 'layoutshape_generator', - layout - ) - ) + self.assertTrue(self.render_layout_check("layoutshape_generator", layout)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutsnapper.py b/tests/src/python/test_qgslayoutsnapper.py index 9594ca79a509..cdd7396259aa 100644 --- a/tests/src/python/test_qgslayoutsnapper.py +++ b/tests/src/python/test_qgslayoutsnapper.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '05/07/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "05/07/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtCore import QPointF, QRectF, Qt from qgis.PyQt.QtWidgets import QGraphicsLineItem @@ -61,11 +62,13 @@ def testSnapPointToGrid(self): l = QgsLayout(p) # need a page to snap to grid page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") l.pageCollection().addPage(page) s = QgsLayoutSnapper(l) - l.gridSettings().setResolution(QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + l.gridSettings().setResolution( + QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) s.setSnapToGrid(True) s.setSnapTolerance(1) @@ -130,11 +133,13 @@ def testSnapPointsToGrid(self): l = QgsLayout(p) # need a page to snap to grid page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") l.pageCollection().addPage(page) s = QgsLayoutSnapper(l) - l.gridSettings().setResolution(QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + l.gridSettings().setResolution( + QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) s.setSnapToGrid(True) s.setSnapTolerance(1) @@ -144,17 +149,23 @@ def testSnapPointsToGrid(self): self.assertTrue(snappedY) self.assertEqual(delta, QPointF(-1, -0.5)) - point, snappedX, snappedY = s.snapPointsToGrid([QPointF(9, 2), QPointF(12, 6)], 1) + point, snappedX, snappedY = s.snapPointsToGrid( + [QPointF(9, 2), QPointF(12, 6)], 1 + ) self.assertTrue(snappedX) self.assertTrue(snappedY) self.assertEqual(point, QPointF(1, -1)) - point, snappedX, snappedY = s.snapPointsToGrid([QPointF(9, 2), QPointF(12, 7)], 1) + point, snappedX, snappedY = s.snapPointsToGrid( + [QPointF(9, 2), QPointF(12, 7)], 1 + ) self.assertTrue(snappedX) self.assertFalse(snappedY) self.assertEqual(point, QPointF(1, 0)) - point, snappedX, snappedY = s.snapPointsToGrid([QPointF(8, 2), QPointF(12, 6)], 1) + point, snappedX, snappedY = s.snapPointsToGrid( + [QPointF(8, 2), QPointF(12, 6)], 1 + ) self.assertFalse(snappedX) self.assertTrue(snappedY) self.assertEqual(point, QPointF(0, -1)) @@ -171,7 +182,7 @@ def testSnapPointsToGrid(self): point, snappedX, snappedY = s.snapPointsToGrid([QPointF(0.5, 0.5)], 1) self.assertTrue(snappedX) self.assertTrue(snappedY) - self.assertEqual(point, QPointF(-.5, -.5)) + self.assertEqual(point, QPointF(-0.5, -0.5)) point, snappedX, snappedY = s.snapPointsToGrid([QPointF(0.5, 0.5)], 3) self.assertFalse(snappedX) self.assertFalse(snappedY) @@ -188,7 +199,7 @@ def testSnapPointToGuides(self): p = QgsProject() l = QgsLayout(p) page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") l.pageCollection().addPage(page) s = QgsLayoutSnapper(l) guides = l.guides() @@ -200,7 +211,9 @@ def testSnapPointToGuides(self): point, snapped = s.snapPointToGuides(0.5, Qt.Orientation.Vertical, 1) self.assertFalse(snapped) - guides.addGuide(QgsLayoutGuide(Qt.Orientation.Vertical, QgsLayoutMeasurement(1), page)) + guides.addGuide( + QgsLayoutGuide(Qt.Orientation.Vertical, QgsLayoutMeasurement(1), page) + ) point, snapped = s.snapPointToGuides(0.5, Qt.Orientation.Vertical, 1) self.assertTrue(snapped) self.assertEqual(point, 1) @@ -218,7 +231,9 @@ def testSnapPointToGuides(self): # snap to hoz point, snapped = s.snapPointToGuides(0.5, Qt.Orientation.Horizontal, 1) self.assertFalse(snapped) - guides.addGuide(QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(1), page)) + guides.addGuide( + QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(1), page) + ) point, snapped = s.snapPointToGuides(0.5, Qt.Orientation.Horizontal, 1) self.assertTrue(snapped) self.assertEqual(point, 1) @@ -231,7 +246,7 @@ def testSnapPointsToGuides(self): p = QgsProject() l = QgsLayout(p) page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") l.pageCollection().addPage(page) s = QgsLayoutSnapper(l) guides = l.guides() @@ -243,7 +258,9 @@ def testSnapPointsToGuides(self): delta, snapped = s.snapPointsToGuides([0.5], Qt.Orientation.Vertical, 1) self.assertFalse(snapped) - guides.addGuide(QgsLayoutGuide(Qt.Orientation.Vertical, QgsLayoutMeasurement(1), page)) + guides.addGuide( + QgsLayoutGuide(Qt.Orientation.Vertical, QgsLayoutMeasurement(1), page) + ) point, snapped = s.snapPointsToGuides([0.7], Qt.Orientation.Vertical, 1) self.assertTrue(snapped) self.assertAlmostEqual(point, 0.3, 5) @@ -266,14 +283,18 @@ def testSnapPointsToGuides(self): # snap to hoz point, snapped = s.snapPointsToGuides([0.5], Qt.Orientation.Horizontal, 1) self.assertFalse(snapped) - guides.addGuide(QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(1), page)) + guides.addGuide( + QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(1), page) + ) point, snapped = s.snapPointsToGuides([0.7], Qt.Orientation.Horizontal, 1) self.assertTrue(snapped) self.assertAlmostEqual(point, 0.3, 5) point, snapped = s.snapPointsToGuides([0.7, 1.2], Qt.Orientation.Horizontal, 1) self.assertTrue(snapped) self.assertAlmostEqual(point, -0.2, 5) - point, snapped = s.snapPointsToGuides([0.7, 0.9, 1.2], Qt.Orientation.Horizontal, 1) + point, snapped = s.snapPointsToGuides( + [0.7, 0.9, 1.2], Qt.Orientation.Horizontal, 1 + ) self.assertTrue(snapped) self.assertAlmostEqual(point, 0.1, 5) @@ -285,7 +306,7 @@ def testSnapPointToItems(self): p = QgsProject() l = QgsLayout(p) page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") # l.pageCollection().addPage(page) s = QgsLayoutSnapper(l) guides = l.guides() @@ -302,12 +323,18 @@ def testSnapPointToItems(self): point, snapped = s.snapPointToItems(0.5, Qt.Orientation.Horizontal, 1, [], line) self.assertFalse(line.isVisible()) - guides.addGuide(QgsLayoutGuide(Qt.Orientation.Vertical, QgsLayoutMeasurement(1), page)) + guides.addGuide( + QgsLayoutGuide(Qt.Orientation.Vertical, QgsLayoutMeasurement(1), page) + ) # add an item item1 = QgsLayoutItemMap(l) - item1.attemptMove(QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item1.attemptResize(QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item1.attemptMove( + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item1.attemptResize( + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addItem(item1) point, snapped = s.snapPointToItems(3.5, Qt.Orientation.Horizontal, 1, [], line) @@ -377,7 +404,7 @@ def testSnapPointsToItems(self): p = QgsProject() l = QgsLayout(p) page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") # l.pageCollection().addPage(page) s = QgsLayoutSnapper(l) guides = l.guides() @@ -391,37 +418,55 @@ def testSnapPointsToItems(self): line = QGraphicsLineItem() line.setVisible(True) - point, snapped = s.snapPointsToItems([0.5], Qt.Orientation.Horizontal, 1, [], line) + point, snapped = s.snapPointsToItems( + [0.5], Qt.Orientation.Horizontal, 1, [], line + ) self.assertFalse(line.isVisible()) - guides.addGuide(QgsLayoutGuide(Qt.Orientation.Vertical, QgsLayoutMeasurement(1), page)) + guides.addGuide( + QgsLayoutGuide(Qt.Orientation.Vertical, QgsLayoutMeasurement(1), page) + ) # add an item item1 = QgsLayoutItemMap(l) - item1.attemptMove(QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item1.attemptResize(QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item1.attemptMove( + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item1.attemptResize( + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addItem(item1) - point, snapped = s.snapPointsToItems([3.5], Qt.Orientation.Horizontal, 1, [], line) + point, snapped = s.snapPointsToItems( + [3.5], Qt.Orientation.Horizontal, 1, [], line + ) self.assertTrue(snapped) self.assertEqual(point, 0.5) self.assertTrue(line.isVisible()) point, snapped = s.snapPointsToItems([4.5], Qt.Orientation.Horizontal, 1, []) self.assertTrue(snapped) self.assertEqual(point, -0.5) - point, snapped = s.snapPointsToItems([4.6, 4.5], Qt.Orientation.Horizontal, 1, []) + point, snapped = s.snapPointsToItems( + [4.6, 4.5], Qt.Orientation.Horizontal, 1, [] + ) self.assertTrue(snapped) self.assertEqual(point, -0.5) - point, snapped = s.snapPointsToItems([4.6, 4.5, 3.7], Qt.Orientation.Horizontal, 1, []) + point, snapped = s.snapPointsToItems( + [4.6, 4.5, 3.7], Qt.Orientation.Horizontal, 1, [] + ) self.assertTrue(snapped) self.assertAlmostEqual(point, 0.3, 5) # ignoring item - point, snapped = s.snapPointsToItems([4.5], Qt.Orientation.Horizontal, 1, [item1]) + point, snapped = s.snapPointsToItems( + [4.5], Qt.Orientation.Horizontal, 1, [item1] + ) self.assertFalse(snapped) # outside tolerance - point, snapped = s.snapPointsToItems([5.5], Qt.Orientation.Horizontal, 1, [], line) + point, snapped = s.snapPointsToItems( + [5.5], Qt.Orientation.Horizontal, 1, [], line + ) self.assertFalse(snapped) self.assertFalse(line.isVisible()) @@ -436,7 +481,9 @@ def testSnapPointsToItems(self): self.assertEqual(point, -0.5) # snap to top - point, snapped = s.snapPointsToItems([7.5], Qt.Orientation.Vertical, 1, [], line) + point, snapped = s.snapPointsToItems( + [7.5], Qt.Orientation.Vertical, 1, [], line + ) self.assertTrue(snapped) self.assertEqual(point, 0.5) self.assertTrue(line.isVisible()) @@ -445,7 +492,9 @@ def testSnapPointsToItems(self): self.assertEqual(point, -0.5) # outside tolerance - point, snapped = s.snapPointsToItems([5.5], Qt.Orientation.Vertical, 1, [], line) + point, snapped = s.snapPointsToItems( + [5.5], Qt.Orientation.Vertical, 1, [], line + ) self.assertFalse(snapped) self.assertFalse(line.isVisible()) @@ -462,7 +511,9 @@ def testSnapPointsToItems(self): # snapping off s.setSnapToItems(False) line.setVisible(True) - point, snapped = s.snapPointsToItems([20.5], Qt.Orientation.Vertical, 1, [], line) + point, snapped = s.snapPointsToItems( + [20.5], Qt.Orientation.Vertical, 1, [], line + ) self.assertFalse(snapped) self.assertFalse(line.isVisible()) @@ -475,13 +526,15 @@ def testSnapPoint(self): p = QgsProject() l = QgsLayout(p) page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") l.pageCollection().addPage(page) s = QgsLayoutSnapper(l) guides = l.guides() # first test snapping to grid - l.gridSettings().setResolution(QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + l.gridSettings().setResolution( + QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) s.setSnapToGrid(True) s.setSnapTolerance(1) @@ -498,14 +551,18 @@ def testSnapPoint(self): # test that guide takes precedence s.setSnapToGrid(True) s.setSnapToGuides(True) - guides.addGuide(QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(0.5), page)) + guides.addGuide( + QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(0.5), page) + ) point, snapped = s.snapPoint(QPointF(1, 1), 1) self.assertTrue(snapped) self.assertEqual(point, QPointF(0, 0.5)) # add an item item1 = QgsLayoutItemMap(l) - item1.attemptMove(QgsLayoutPoint(121, 1.1, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item1.attemptMove( + QgsLayoutPoint(121, 1.1, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addItem(item1) # test that guide takes precedence over item @@ -530,13 +587,15 @@ def testSnapRect(self): p = QgsProject() l = QgsLayout(p) page = QgsLayoutItemPage(l) - page.setPageSize('A4') + page.setPageSize("A4") l.pageCollection().addPage(page) s = QgsLayoutSnapper(l) guides = l.guides() # first test snapping to grid - l.gridSettings().setResolution(QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + l.gridSettings().setResolution( + QgsLayoutMeasurement(5, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) s.setSnapToItems(False) s.setSnapToGrid(True) s.setSnapTolerance(1) @@ -557,14 +616,18 @@ def testSnapRect(self): # test that guide takes precedence s.setSnapToGrid(True) s.setSnapToGuides(True) - guides.addGuide(QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(0.5), page)) + guides.addGuide( + QgsLayoutGuide(Qt.Orientation.Horizontal, QgsLayoutMeasurement(0.5), page) + ) rect, snapped = s.snapRect(QRectF(1, 1, 2, 3), 1) self.assertTrue(snapped) self.assertEqual(rect, QRectF(0.0, 0.5, 2.0, 3.0)) # add an item item1 = QgsLayoutItemMap(l) - item1.attemptMove(QgsLayoutPoint(121, 1.1, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item1.attemptMove( + QgsLayoutPoint(121, 1.1, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addItem(item1) # test that guide takes precedence over item @@ -604,7 +667,9 @@ def testReadWriteXml(self): l2.initializeDefaults() snapper2 = l2.snapper() - self.assertTrue(snapper2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext())) + self.assertTrue( + snapper2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext()) + ) self.assertTrue(snapper2.snapToGrid()) self.assertEqual(snapper2.snapTolerance(), 1) self.assertTrue(snapper2.snapToGuides()) @@ -619,11 +684,13 @@ def testReadWriteXml(self): elem = doc.createElement("test") self.assertTrue(snapper.writeXml(elem, doc, QgsReadWriteContext())) - self.assertTrue(snapper2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext())) + self.assertTrue( + snapper2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext()) + ) self.assertFalse(snapper2.snapToGrid()) self.assertFalse(snapper2.snapToGuides()) self.assertFalse(snapper2.snapToItems()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayouttable.py b/tests/src/python/test_qgslayouttable.py index ed49bd1668f8..451771b85cbb 100644 --- a/tests/src/python/test_qgslayouttable.py +++ b/tests/src/python/test_qgslayouttable.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2022 by Nyall Dawson' -__date__ = '13/06/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "(C) 2022 by Nyall Dawson" +__date__ = "13/06/2022" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.core import QgsLayoutTableColumn import unittest @@ -24,11 +25,13 @@ class TestQgsLayoutTable(QgisTestCase): def test_column(self): """Test initial size of legend with a symbol size in map units""" col = QgsLayoutTableColumn() - col.setAttribute('attribute') - self.assertEqual(col.__repr__(), '') - col.setHeading('heading') - self.assertEqual(col.__repr__(), '') + col.setAttribute("attribute") + self.assertEqual(col.__repr__(), "") + col.setHeading("heading") + self.assertEqual( + col.__repr__(), '' + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutunitscombobox.py b/tests/src/python/test_qgslayoutunitscombobox.py index 21312692a921..671674404c5a 100644 --- a/tests/src/python/test_qgslayoutunitscombobox.py +++ b/tests/src/python/test_qgslayoutunitscombobox.py @@ -5,16 +5,14 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '18/07/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "18/07/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy from qgis.PyQt.QtWidgets import QDoubleSpinBox -from qgis.core import ( - QgsLayoutMeasurementConverter, - QgsUnitTypes -) +from qgis.core import QgsLayoutMeasurementConverter, QgsUnitTypes from qgis.gui import QgsLayoutUnitsComboBox import unittest from qgis.testing import start_app, QgisTestCase @@ -25,14 +23,14 @@ class TestQgsLayoutUnitsComboBox(QgisTestCase): def testGettersSetters(self): - """ test widget getters/setters """ + """test widget getters/setters""" w = QgsLayoutUnitsComboBox() w.setUnit(QgsUnitTypes.LayoutUnit.LayoutPixels) self.assertEqual(w.unit(), QgsUnitTypes.LayoutUnit.LayoutPixels) def test_ChangedSignals(self): - """ test that signals are correctly emitted when setting unit""" + """test that signals are correctly emitted when setting unit""" w = QgsLayoutUnitsComboBox() spy = QSignalSpy(w.changed) @@ -42,7 +40,7 @@ def test_ChangedSignals(self): self.assertEqual(spy[0][0], QgsUnitTypes.LayoutUnit.LayoutPixels) def testLinkedWidgets(self): - """ test linking spin boxes to combobox""" + """test linking spin boxes to combobox""" w = QgsLayoutUnitsComboBox() self.assertFalse(w.converter()) c = QgsLayoutMeasurementConverter() @@ -73,5 +71,5 @@ def testLinkedWidgets(self): self.assertAlmostEqual(spin2.value(), 0.05, 2) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslayoutview.py b/tests/src/python/test_qgslayoutview.py index 86f59b3d73cf..64c64376a7a8 100644 --- a/tests/src/python/test_qgslayoutview.py +++ b/tests/src/python/test_qgslayoutview.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '05/07/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "05/07/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt import sip from qgis.PyQt.QtCore import QByteArray, QMimeData, QRectF @@ -37,7 +38,7 @@ class TestQgsLayoutView(QgisTestCase): def testScaleSafe(self): - """ test scaleSafe method """ + """test scaleSafe method""" view = QgsLayoutView() view.fitInView(QRectF(0, 0, 10, 10)) @@ -419,16 +420,28 @@ def testAlign(self): # add some items item1 = QgsLayoutItemPicture(l) - item1.attemptMove(QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item1.attemptResize(QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item1.attemptMove( + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item1.attemptResize( + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addItem(item1) item2 = QgsLayoutItemPicture(l) - item2.attemptMove(QgsLayoutPoint(6, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item2.attemptResize(QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item2.attemptMove( + QgsLayoutPoint(6, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item2.attemptResize( + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addItem(item2) item3 = QgsLayoutItemPicture(l) - item3.attemptMove(QgsLayoutPoint(0.8, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - item3.attemptResize(QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + item3.attemptMove( + QgsLayoutPoint(0.8, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) + item3.attemptResize( + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) l.addItem(item3) view = QgsLayoutView() @@ -441,52 +454,160 @@ def testAlign(self): item3.setSelected(True) view.alignSelectedItems(QgsLayoutAligner.Alignment.AlignLeft) - self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.positionWithUnits(), QgsLayoutPoint(4, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.positionWithUnits(), QgsLayoutPoint(0.4, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + item1.positionWithUnits(), + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.positionWithUnits(), + QgsLayoutPoint(4, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.positionWithUnits(), + QgsLayoutPoint(0.4, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) view.alignSelectedItems(QgsLayoutAligner.Alignment.AlignHCenter) - self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.positionWithUnits(), QgsLayoutPoint(8, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.positionWithUnits(), QgsLayoutPoint(0.4, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + item1.positionWithUnits(), + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.positionWithUnits(), + QgsLayoutPoint(8, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.positionWithUnits(), + QgsLayoutPoint(0.4, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) view.alignSelectedItems(QgsLayoutAligner.Alignment.AlignRight) - self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.positionWithUnits(), QgsLayoutPoint(12, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.positionWithUnits(), QgsLayoutPoint(0.4, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + item1.positionWithUnits(), + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.positionWithUnits(), + QgsLayoutPoint(12, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.positionWithUnits(), + QgsLayoutPoint(0.4, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) view.alignSelectedItems(QgsLayoutAligner.Alignment.AlignTop) - self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.positionWithUnits(), QgsLayoutPoint(12, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.positionWithUnits(), QgsLayoutPoint(0.4, 0.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + item1.positionWithUnits(), + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.positionWithUnits(), + QgsLayoutPoint(12, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.positionWithUnits(), + QgsLayoutPoint(0.4, 0.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) view.alignSelectedItems(QgsLayoutAligner.Alignment.AlignVCenter) - self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.positionWithUnits(), QgsLayoutPoint(12, 11.5, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.positionWithUnits(), QgsLayoutPoint(0.4, 0.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + item1.positionWithUnits(), + QgsLayoutPoint(4, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.positionWithUnits(), + QgsLayoutPoint(12, 11.5, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.positionWithUnits(), + QgsLayoutPoint(0.4, 0.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) view.alignSelectedItems(QgsLayoutAligner.Alignment.AlignBottom) - self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.positionWithUnits(), QgsLayoutPoint(12, 15, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.positionWithUnits(), QgsLayoutPoint(0.4, 0.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + item1.positionWithUnits(), + QgsLayoutPoint(4, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.positionWithUnits(), + QgsLayoutPoint(12, 15, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.positionWithUnits(), + QgsLayoutPoint(0.4, 0.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) def testDistribute(self): p = QgsProject() @@ -494,16 +615,28 @@ def testDistribute(self): # add some items item1 = QgsLayoutItemPicture(l) - item1.attemptMove(QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item1.attemptResize(QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item1.attemptMove( + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item1.attemptResize( + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addItem(item1) item2 = QgsLayoutItemPicture(l) - item2.attemptMove(QgsLayoutPoint(7, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item2.attemptResize(QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item2.attemptMove( + QgsLayoutPoint(7, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item2.attemptResize( + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addItem(item2) item3 = QgsLayoutItemPicture(l) - item3.attemptMove(QgsLayoutPoint(0.8, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - item3.attemptResize(QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + item3.attemptMove( + QgsLayoutPoint(0.8, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) + item3.attemptResize( + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) l.addItem(item3) view = QgsLayoutView() @@ -516,69 +649,160 @@ def testDistribute(self): item3.setSelected(True) view.distributeSelectedItems(QgsLayoutAligner.Distribution.DistributeLeft) - self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item1.positionWithUnits(), + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item2.positionWithUnits().x(), 6.0, 3) - self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item3.positionWithUnits().x(), 0.8, 3) - self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) view.distributeSelectedItems(QgsLayoutAligner.Distribution.DistributeHCenter) self.assertAlmostEqual(item1.positionWithUnits().x(), 5.0, 3) - self.assertEqual(item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item2.positionWithUnits().x(), 6.0, 3) - self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item3.positionWithUnits().x(), 0.8, 3) - self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) view.distributeSelectedItems(QgsLayoutAligner.Distribution.DistributeRight) self.assertAlmostEqual(item1.positionWithUnits().x(), 3.0, 3) - self.assertEqual(item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item2.positionWithUnits().x(), 6.0, 3) - self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item3.positionWithUnits().x(), 0.8, 3) - self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) view.distributeSelectedItems(QgsLayoutAligner.Distribution.DistributeTop) self.assertAlmostEqual(item1.positionWithUnits().y(), 8.0, 3) - self.assertEqual(item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item2.positionWithUnits().y(), 10.0, 3) - self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item3.positionWithUnits().y(), 1.2, 3) - self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) view.distributeSelectedItems(QgsLayoutAligner.Distribution.DistributeVCenter) self.assertAlmostEqual(item1.positionWithUnits().y(), 8.0, 3) - self.assertEqual(item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item2.positionWithUnits().y(), 12.5, 3) - self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item3.positionWithUnits().y(), 1.2, 3) - self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) view.distributeSelectedItems(QgsLayoutAligner.Distribution.DistributeBottom) self.assertAlmostEqual(item1.positionWithUnits().y(), 8.0, 3) - self.assertEqual(item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item1.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item2.positionWithUnits().y(), 15.0, 3) - self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + self.assertEqual( + item2.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutMillimeters + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) self.assertAlmostEqual(item3.positionWithUnits().y(), 1.2, 3) - self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + item3.positionWithUnits().units(), QgsUnitTypes.LayoutUnit.LayoutCentimeters + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) def testResize(self): p = QgsProject() @@ -586,16 +810,28 @@ def testResize(self): # add some items item1 = QgsLayoutItemPicture(l) - item1.attemptMove(QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item1.attemptResize(QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item1.attemptMove( + QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item1.attemptResize( + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addItem(item1) item2 = QgsLayoutItemPicture(l) - item2.attemptMove(QgsLayoutPoint(7, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - item2.attemptResize(QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item2.attemptMove( + QgsLayoutPoint(7, 10, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) + item2.attemptResize( + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) l.addItem(item2) item3 = QgsLayoutItemPicture(l) - item3.attemptMove(QgsLayoutPoint(0.8, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) - item3.attemptResize(QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + item3.attemptMove( + QgsLayoutPoint(0.8, 1.2, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) + item3.attemptResize( + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters) + ) l.addItem(item3) view = QgsLayoutView() @@ -608,34 +844,81 @@ def testResize(self): item3.setSelected(True) view.resizeSelectedItems(QgsLayoutAligner.Resize.ResizeNarrowest) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(10, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.0, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(10, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.0, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) l.undoStack().stack().undo() view.resizeSelectedItems(QgsLayoutAligner.Resize.ResizeWidest) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(18, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 12, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(18, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) l.undoStack().stack().undo() view.resizeSelectedItems(QgsLayoutAligner.Resize.ResizeShortest) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 0.9, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 9, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 0.9, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) l.undoStack().stack().undo() view.resizeSelectedItems(QgsLayoutAligner.Resize.ResizeTallest) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 16, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 16, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 16, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(10, 16, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) l.undoStack().stack().undo() - item2.attemptResize(QgsLayoutSize(10, 19, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) + item2.attemptResize( + QgsLayoutSize(10, 19, QgsUnitTypes.LayoutUnit.LayoutMillimeters) + ) view.resizeSelectedItems(QgsLayoutAligner.Resize.ResizeToSquare) - self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 18, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(19, 19, QgsUnitTypes.LayoutUnit.LayoutMillimeters)) - self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters)) + self.assertEqual( + item1.sizeWithUnits(), + QgsLayoutSize(18, 18, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item2.sizeWithUnits(), + QgsLayoutSize(19, 19, QgsUnitTypes.LayoutUnit.LayoutMillimeters), + ) + self.assertEqual( + item3.sizeWithUnits(), + QgsLayoutSize(1.8, 1.8, QgsUnitTypes.LayoutUnit.LayoutCentimeters), + ) def testDeleteItems(self): p = QgsProject() @@ -643,13 +926,13 @@ def testDeleteItems(self): # add some items item1 = QgsLayoutItemLabel(l) - item1.setText('label 1') + item1.setText("label 1") l.addLayoutItem(item1) item2 = QgsLayoutItemLabel(l) - item2.setText('label 2') + item2.setText("label 2") l.addLayoutItem(item2) item3 = QgsLayoutItemLabel(l) - item3.setText('label 2') + item3.setText("label 2") l.addLayoutItem(item3) view = QgsLayoutView() @@ -679,33 +962,33 @@ def testCopyPaste(self): # add an item item1 = QgsLayoutItemLabel(l) - item1.setText('label 1') + item1.setText("label 1") l.addLayoutItem(item1) item1.setSelected(True) item2 = QgsLayoutItemLabel(l) - item2.setText('label 2') + item2.setText("label 2") l.addLayoutItem(item2) item2.setSelected(True) # multiframes multiframe1 = QgsLayoutItemHtml(l) - multiframe1.setHtml('mf1') + multiframe1.setHtml("mf1") l.addMultiFrame(multiframe1) frame1 = QgsLayoutFrame(l, multiframe1) - frame1.setId('frame1a') + frame1.setId("frame1a") multiframe1.addFrame(frame1) frame1b = QgsLayoutFrame(l, multiframe1) - frame1b.setId('frame1b') + frame1b.setId("frame1b") multiframe1.addFrame(frame1b) # not selected frame1c = QgsLayoutFrame(l, multiframe1) - frame1c.setId('frame1b') + frame1c.setId("frame1b") multiframe1.addFrame(frame1c) # not selected multiframe2 = QgsLayoutItemHtml(l) - multiframe2.setHtml('mf2') + multiframe2.setHtml("mf2") l.addMultiFrame(multiframe2) frame2 = QgsLayoutFrame(l, multiframe2) - frame2.setId('frame2') + frame2.setId("frame2") multiframe2.addFrame(frame2) frame1.setSelected(True) @@ -721,21 +1004,37 @@ def testCopyPaste(self): pasted = view.pasteItems(QgsLayoutView.PasteMode.PasteModeCursor) self.assertEqual(len(pasted), 4) - new_multiframes = [m for m in l.multiFrames() if m not in [multiframe1, multiframe2]] + new_multiframes = [ + m for m in l.multiFrames() if m not in [multiframe1, multiframe2] + ] self.assertEqual(len(new_multiframes), 2) self.assertIn(pasted[0], l.items()) self.assertIn(pasted[1], l.items()) - labels = [p for p in pasted if p.type() == QgsLayoutItemRegistry.ItemType.LayoutLabel] - self.assertIn(sip.cast(labels[0], QgsLayoutItemLabel).text(), ('label 1', 'label 2')) - self.assertIn(sip.cast(labels[1], QgsLayoutItemLabel).text(), ('label 1', 'label 2')) - frames = [p for p in pasted if p.type() == QgsLayoutItemRegistry.ItemType.LayoutFrame] + labels = [ + p for p in pasted if p.type() == QgsLayoutItemRegistry.ItemType.LayoutLabel + ] + self.assertIn( + sip.cast(labels[0], QgsLayoutItemLabel).text(), ("label 1", "label 2") + ) + self.assertIn( + sip.cast(labels[1], QgsLayoutItemLabel).text(), ("label 1", "label 2") + ) + frames = [ + p for p in pasted if p.type() == QgsLayoutItemRegistry.ItemType.LayoutFrame + ] pasted_frame1 = sip.cast(frames[0], QgsLayoutFrame) pasted_frame2 = sip.cast(frames[1], QgsLayoutFrame) self.assertIn(pasted_frame1.multiFrame(), new_multiframes) - self.assertIn(new_multiframes[0].frames()[0].uuid(), (pasted_frame1.uuid(), pasted_frame2.uuid())) + self.assertIn( + new_multiframes[0].frames()[0].uuid(), + (pasted_frame1.uuid(), pasted_frame2.uuid()), + ) self.assertIn(pasted_frame2.multiFrame(), new_multiframes) - self.assertIn(new_multiframes[1].frames()[0].uuid(), (pasted_frame1.uuid(), pasted_frame2.uuid())) + self.assertIn( + new_multiframes[1].frames()[0].uuid(), + (pasted_frame1.uuid(), pasted_frame2.uuid()), + ) self.assertEqual(frame1.multiFrame(), multiframe1) self.assertCountEqual(multiframe1.frames(), [frame1, frame1b, frame1c]) @@ -752,7 +1051,7 @@ def testCopyPaste(self): pasted = view2.pasteItems(QgsLayoutView.PasteMode.PasteModeCursor) self.assertEqual(len(pasted), 1) self.assertIn(pasted[0], l2.items()) - self.assertEqual(sip.cast(pasted[0], QgsLayoutItemLabel).text(), 'label 2') + self.assertEqual(sip.cast(pasted[0], QgsLayoutItemLabel).text(), "label 2") def testCutPaste(self): p = QgsProject() @@ -766,11 +1065,11 @@ def testCutPaste(self): # add an item item1 = QgsLayoutItemLabel(l) - item1.setText('label 1') + item1.setText("label 1") l.addLayoutItem(item1) item1.setSelected(True) item2 = QgsLayoutItemLabel(l) - item2.setText('label 2') + item2.setText("label 2") l.addLayoutItem(item2) item2.setSelected(True) @@ -788,9 +1087,13 @@ def testCutPaste(self): self.assertEqual(len(l.items()), len_before) self.assertIn(pasted[0], l.items()) self.assertIn(pasted[1], l.items()) - self.assertIn(sip.cast(pasted[0], QgsLayoutItemLabel).text(), ('label 1', 'label 2')) - self.assertIn(sip.cast(pasted[1], QgsLayoutItemLabel).text(), ('label 1', 'label 2')) + self.assertIn( + sip.cast(pasted[0], QgsLayoutItemLabel).text(), ("label 1", "label 2") + ) + self.assertIn( + sip.cast(pasted[1], QgsLayoutItemLabel).text(), ("label 1", "label 2") + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslegendpatchshape.py b/tests/src/python/test_qgslegendpatchshape.py index 7a2a64208df6..a68713b3bfc0 100644 --- a/tests/src/python/test_qgslegendpatchshape.py +++ b/tests/src/python/test_qgslegendpatchshape.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 by Nyall Dawson' -__date__ = '05/04/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 by Nyall Dawson" +__date__ = "05/04/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QSize, QSizeF from qgis.PyQt.QtGui import QColor, QImage, QPainter @@ -40,22 +41,32 @@ def control_path_prefix(cls): def setUp(self): # Create some simple symbols - self.fill_symbol = QgsFillSymbol.createSimple({'color': '#ffffff', 'outline_color': 'black'}) - self.line_symbol = QgsLineSymbol.createSimple({'color': '#ffffff', 'line_width': '3'}) - self.marker_symbol = QgsMarkerSymbol.createSimple({'color': '#ffffff', 'size': '3', 'outline_color': 'black'}) + self.fill_symbol = QgsFillSymbol.createSimple( + {"color": "#ffffff", "outline_color": "black"} + ) + self.line_symbol = QgsLineSymbol.createSimple( + {"color": "#ffffff", "line_width": "3"} + ) + self.marker_symbol = QgsMarkerSymbol.createSimple( + {"color": "#ffffff", "size": "3", "outline_color": "black"} + ) def testBasic(self): - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString( 0 0, 1 1)'), False) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, + QgsGeometry.fromWkt("LineString( 0 0, 1 1)"), + False, + ) self.assertFalse(shape.isNull()) self.assertEqual(shape.symbolType(), QgsSymbol.SymbolType.Line) - self.assertEqual(shape.geometry().asWkt(), 'LineString (0 0, 1 1)') + self.assertEqual(shape.geometry().asWkt(), "LineString (0 0, 1 1)") self.assertFalse(shape.preserveAspectRatio()) shape.setSymbolType(QgsSymbol.SymbolType.Marker) self.assertEqual(shape.symbolType(), QgsSymbol.SymbolType.Marker) - shape.setGeometry(QgsGeometry.fromWkt('Multipoint( 1 1, 2 2)')) - self.assertEqual(shape.geometry().asWkt(), 'MultiPoint ((1 1),(2 2))') + shape.setGeometry(QgsGeometry.fromWkt("Multipoint( 1 1, 2 2)")) + self.assertEqual(shape.geometry().asWkt(), "MultiPoint ((1 1),(2 2))") shape.setPreserveAspectRatio(True) self.assertTrue(shape.preserveAspectRatio()) @@ -66,200 +77,598 @@ def testBasic(self): @staticmethod def polys_to_list(polys): - return [[[[round(p.x(), 3), round(p.y(), 3)] for p in ring] for ring in poly] for poly in polys] + return [ + [[[round(p.x(), 3), round(p.y(), 3)] for p in ring] for ring in poly] + for poly in polys + ] def testNull(self): shape = QgsLegendPatchShape() self.assertTrue(shape.isNull()) - shape.setGeometry(QgsGeometry.fromWkt('Multipoint( 1 1, 2 2)')) + shape.setGeometry(QgsGeometry.fromWkt("Multipoint( 1 1, 2 2)")) self.assertFalse(shape.isNull()) shape.setGeometry(QgsGeometry()) self.assertTrue(shape.isNull()) def testDefault(self): - self.assertEqual(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.SymbolType.Hybrid, QSizeF(1, 1)), []) - self.assertEqual(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.SymbolType.Hybrid, QSizeF(10, 10)), []) + self.assertEqual( + QgsStyle.defaultStyle().defaultPatchAsQPolygonF( + QgsSymbol.SymbolType.Hybrid, QSizeF(1, 1) + ), + [], + ) + self.assertEqual( + QgsStyle.defaultStyle().defaultPatchAsQPolygonF( + QgsSymbol.SymbolType.Hybrid, QSizeF(10, 10) + ), + [], + ) # markers - self.assertEqual(self.polys_to_list(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(1, 1))), [[[[0.5, 0.5]]]]) - self.assertEqual(self.polys_to_list(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(2, 2))), - [[[[1.0, 1.0]]]]) - self.assertEqual(self.polys_to_list(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(10, 2))), [[[[5.0, 1.0]]]]) + self.assertEqual( + self.polys_to_list( + QgsStyle.defaultStyle().defaultPatchAsQPolygonF( + QgsSymbol.SymbolType.Marker, QSizeF(1, 1) + ) + ), + [[[[0.5, 0.5]]]], + ) + self.assertEqual( + self.polys_to_list( + QgsStyle.defaultStyle().defaultPatchAsQPolygonF( + QgsSymbol.SymbolType.Marker, QSizeF(2, 2) + ) + ), + [[[[1.0, 1.0]]]], + ) + self.assertEqual( + self.polys_to_list( + QgsStyle.defaultStyle().defaultPatchAsQPolygonF( + QgsSymbol.SymbolType.Marker, QSizeF(10, 2) + ) + ), + [[[[5.0, 1.0]]]], + ) # lines - self.assertEqual(self.polys_to_list(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(1, 1))), [[[[0.0, 0.5], [1.0, 0.5]]]]) - self.assertEqual(self.polys_to_list(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(10, 2))), [[[[0.0, 1.0], [10.0, 1.0]]]]) - self.assertEqual(self.polys_to_list(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(9, 3))), [[[[0.0, 1.5], [9.0, 1.5]]]]) + self.assertEqual( + self.polys_to_list( + QgsStyle.defaultStyle().defaultPatchAsQPolygonF( + QgsSymbol.SymbolType.Line, QSizeF(1, 1) + ) + ), + [[[[0.0, 0.5], [1.0, 0.5]]]], + ) + self.assertEqual( + self.polys_to_list( + QgsStyle.defaultStyle().defaultPatchAsQPolygonF( + QgsSymbol.SymbolType.Line, QSizeF(10, 2) + ) + ), + [[[[0.0, 1.0], [10.0, 1.0]]]], + ) + self.assertEqual( + self.polys_to_list( + QgsStyle.defaultStyle().defaultPatchAsQPolygonF( + QgsSymbol.SymbolType.Line, QSizeF(9, 3) + ) + ), + [[[[0.0, 1.5], [9.0, 1.5]]]], + ) # fills - self.assertEqual(self.polys_to_list(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(1, 1))), [[[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]]]]) - self.assertEqual(self.polys_to_list(QgsStyle.defaultStyle().defaultPatchAsQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(10, 2))), [[[[0.0, 0.0], [10.0, 0.0], [10.0, 2.0], [0.0, 2.0], [0.0, 0.0]]]]) + self.assertEqual( + self.polys_to_list( + QgsStyle.defaultStyle().defaultPatchAsQPolygonF( + QgsSymbol.SymbolType.Fill, QSizeF(1, 1) + ) + ), + [[[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]]]], + ) + self.assertEqual( + self.polys_to_list( + QgsStyle.defaultStyle().defaultPatchAsQPolygonF( + QgsSymbol.SymbolType.Fill, QSizeF(10, 2) + ) + ), + [[[[0.0, 0.0], [10.0, 0.0], [10.0, 2.0], [0.0, 2.0], [0.0, 0.0]]]], + ) def testMarkers(self): # shouldn't matter what a point geometry is, it will always be rendered in center of symbol patch - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt('Point( 5 5 )'), False) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(1, 1))), [[[[0.5, 0.5]]]]) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(10, 2))), [[[[5.0, 1.0]]]]) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt("Point( 5 5 )"), False + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(1, 1)) + ), + [[[[0.5, 0.5]]]], + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(10, 2)) + ), + [[[[5.0, 1.0]]]], + ) # requesting different symbol type, should return default - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(1, 1))), [[[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]]]]) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(1, 1)) + ), + [[[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]]]], + ) # ... but a multipoint WILL change the result! - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt('MultiPoint((5 5), (1 2))'), False) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(1, 1))), [[[[1.0, 0.0], [0.0, 1.0]]]]) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(10, 2))), [[[[10.0, 0.0], [0.0, 2.0]]]]) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Marker, + QgsGeometry.fromWkt("MultiPoint((5 5), (1 2))"), + False, + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(1, 1)) + ), + [[[[1.0, 0.0], [0.0, 1.0]]]], + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(10, 2)) + ), + [[[[10.0, 0.0], [0.0, 2.0]]]], + ) - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt('MultiPoint((5 5), (1 2), (4 3))'), False) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(1, 1))), [[[[1.0, 0.0], [0.0, 1.0], [0.75, 0.667]]]]) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(10, 2))), [[[[10.0, 0.0], [0.0, 2.0], [7.5, 1.333]]]]) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Marker, + QgsGeometry.fromWkt("MultiPoint((5 5), (1 2), (4 3))"), + False, + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(1, 1)) + ), + [[[[1.0, 0.0], [0.0, 1.0], [0.75, 0.667]]]], + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(10, 2)) + ), + [[[[10.0, 0.0], [0.0, 2.0], [7.5, 1.333]]]], + ) def testPreserveAspect(self): # wider - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt('MultiPoint((5 5), (1 2))')) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(1, 1))), [[[[1.0, 0.125], [0.0, 0.875]]]]) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(10, 2))), [[[[6.333, 0.0], [3.667, 2.0]]]]) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(2, 10))), [[[[2.0, 4.25], [0.0, 5.75]]]]) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt("MultiPoint((5 5), (1 2))") + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(1, 1)) + ), + [[[[1.0, 0.125], [0.0, 0.875]]]], + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(10, 2)) + ), + [[[[6.333, 0.0], [3.667, 2.0]]]], + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(2, 10)) + ), + [[[[2.0, 4.25], [0.0, 5.75]]]], + ) # higher - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt('MultiPoint((5 5), (2 1))')) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(1, 1))), [[[[0.875, 0.0], [0.125, 1.0]]]]) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(10, 2))), [[[[5.75, 0.0], [4.25, 2.0]]]]) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(2, 10))), [[[[2.0, 3.667], [0.0, 6.333]]]]) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt("MultiPoint((5 5), (2 1))") + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(1, 1)) + ), + [[[[0.875, 0.0], [0.125, 1.0]]]], + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(10, 2)) + ), + [[[[5.75, 0.0], [4.25, 2.0]]]], + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Marker, QSizeF(2, 10)) + ), + [[[[2.0, 3.667], [0.0, 6.333]]]], + ) def testLines(self): - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString(5 5, 1 2)'), False) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(1, 1))), [[[[1.0, 0.0], [0.0, 1.0]]]]) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(10, 2))), [[[[10.0, 0.0], [0.0, 2.0]]]]) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, + QgsGeometry.fromWkt("LineString(5 5, 1 2)"), + False, + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(1, 1)) + ), + [[[[1.0, 0.0], [0.0, 1.0]]]], + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(10, 2)) + ), + [[[[10.0, 0.0], [0.0, 2.0]]]], + ) - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString(1 5, 6 5)'), False) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(1, 1))), [[[[0.0, 0.5], [1.0, 0.5]]]]) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(10, 2))), [[[[0.0, 1], [10.0, 1.0]]]]) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, + QgsGeometry.fromWkt("LineString(1 5, 6 5)"), + False, + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(1, 1)) + ), + [[[[0.0, 0.5], [1.0, 0.5]]]], + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(10, 2)) + ), + [[[[0.0, 1], [10.0, 1.0]]]], + ) - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString(1 5, 1 10)'), False) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(1, 1))), [[[[0.5, 0.0], [0.5, 1.0]]]]) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(10, 2))), [[[[5, 0.0], [5, 2.0]]]]) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, + QgsGeometry.fromWkt("LineString(1 5, 1 10)"), + False, + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(1, 1)) + ), + [[[[0.5, 0.0], [0.5, 1.0]]]], + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(10, 2)) + ), + [[[[5, 0.0], [5, 2.0]]]], + ) # requesting different symbol type, should return default - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(1, 1))), [[[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]]]]) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(1, 1)) + ), + [[[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]]]], + ) # circularstring - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('CircularString(5 5, 1 2, 3 4)'), False) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(1, 1)))[0][0][:5], - [[0.342, 0.026], [0.35, 0.023], [0.359, 0.02], [0.367, 0.018], [0.375, 0.016]]) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(10, 2)))[0][0][:5], - [[3.419, 0.051], [3.647, 0.042], [3.875, 0.036], [4.104, 0.034], [4.332, 0.036]]) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, + QgsGeometry.fromWkt("CircularString(5 5, 1 2, 3 4)"), + False, + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(1, 1)) + )[0][0][:5], + [ + [0.342, 0.026], + [0.35, 0.023], + [0.359, 0.02], + [0.367, 0.018], + [0.375, 0.016], + ], + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(10, 2)) + )[0][0][:5], + [ + [3.419, 0.051], + [3.647, 0.042], + [3.875, 0.036], + [4.104, 0.034], + [4.332, 0.036], + ], + ) # multilinestring - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('MultiLineString((5 5, 1 2),(3 6, 4 2))'), False) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(1, 1))), [[[[1.0, 0.25], [0.0, 1.0]]], [[[0.5, 0.0], [0.75, 1.0]]]]) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(10, 2))), [[[[10.0, 0.5], [0.0, 2.0]]], [[[5.0, 0.0], [7.5, 2.0]]]]) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, + QgsGeometry.fromWkt("MultiLineString((5 5, 1 2),(3 6, 4 2))"), + False, + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(1, 1)) + ), + [[[[1.0, 0.25], [0.0, 1.0]]], [[[0.5, 0.0], [0.75, 1.0]]]], + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(10, 2)) + ), + [[[[10.0, 0.5], [0.0, 2.0]]], [[[5.0, 0.0], [7.5, 2.0]]]], + ) def testFills(self): - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Fill, QgsGeometry.fromWkt('Polygon((5 5, 1 2, 3 4, 5 5))'), False) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(1, 1))), [[[[1.0, 0.0], [0.0, 1.0], [0.5, 0.333], [1.0, 0.0]]]]) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(10, 2))), [[[[10.0, 0.0], [0.0, 2.0], [5.0, 0.667], [10.0, 0.0]]]]) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Fill, + QgsGeometry.fromWkt("Polygon((5 5, 1 2, 3 4, 5 5))"), + False, + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(1, 1)) + ), + [[[[1.0, 0.0], [0.0, 1.0], [0.5, 0.333], [1.0, 0.0]]]], + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(10, 2)) + ), + [[[[10.0, 0.0], [0.0, 2.0], [5.0, 0.667], [10.0, 0.0]]]], + ) # requesting different symbol type, should return default - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(1, 1))), [[[[0.0, 0.5], [1.0, 0.5]]]]) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Line, QSizeF(1, 1)) + ), + [[[[0.0, 0.5], [1.0, 0.5]]]], + ) # rings - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Fill, QgsGeometry.fromWkt('Polygon((5 5, 1 2, 3 4, 5 5), (4.5 4.5, 4.4 4.4, 4.5 4.4, 4.5 4.5))'), False) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(1, 1))), - [[[[1.0, 0.0], [0.0, 1.0], [0.5, 0.333], [1.0, 0.0]], [[0.875, 0.167], [0.85, 0.2], [0.875, 0.2], [0.875, 0.167]]]]) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(10, 2))), - [[[[10.0, 0.0], [0.0, 2.0], [5.0, 0.667], [10.0, 0.0]], [[8.75, 0.333], [8.5, 0.4], [8.75, 0.4], [8.75, 0.333]]]]) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Fill, + QgsGeometry.fromWkt( + "Polygon((5 5, 1 2, 3 4, 5 5), (4.5 4.5, 4.4 4.4, 4.5 4.4, 4.5 4.5))" + ), + False, + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(1, 1)) + ), + [ + [ + [[1.0, 0.0], [0.0, 1.0], [0.5, 0.333], [1.0, 0.0]], + [[0.875, 0.167], [0.85, 0.2], [0.875, 0.2], [0.875, 0.167]], + ] + ], + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(10, 2)) + ), + [ + [ + [[10.0, 0.0], [0.0, 2.0], [5.0, 0.667], [10.0, 0.0]], + [[8.75, 0.333], [8.5, 0.4], [8.75, 0.4], [8.75, 0.333]], + ] + ], + ) # circular - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Fill, QgsGeometry.fromWkt('CurvePolygon(CircularString(5 5, 3 4, 1 2, 3 0, 5 5))'), False) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(1, 1)))[0][0][:5], - [[0.746, -0.0], [0.722, 0.009], [0.698, 0.018], [0.675, 0.028], [0.651, 0.038]]) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(10, 2)))[0][0][:5], - [[7.459, -0.0], [6.83, 0.04], [6.201, 0.09], [5.574, 0.151], [4.947, 0.223]]) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Fill, + QgsGeometry.fromWkt( + "CurvePolygon(CircularString(5 5, 3 4, 1 2, 3 0, 5 5))" + ), + False, + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(1, 1)) + )[0][0][:5], + [ + [0.746, -0.0], + [0.722, 0.009], + [0.698, 0.018], + [0.675, 0.028], + [0.651, 0.038], + ], + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(10, 2)) + )[0][0][:5], + [ + [7.459, -0.0], + [6.83, 0.04], + [6.201, 0.09], + [5.574, 0.151], + [4.947, 0.223], + ], + ) # multipolygon - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Fill, QgsGeometry.fromWkt('MultiPolygon(((5 5, 1 2, 3 4, 5 5), (4.5 4.5, 4.4 4.4, 4.5 4.4, 4.5 4.5)),((10 11, 11 11, 11 10, 10 11)))'), False) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(1, 1))), [[[[0.4, 0.667], [0.0, 1.0], [0.2, 0.778], [0.4, 0.667]], [[0.35, 0.722], [0.34, 0.733], [0.35, 0.733], [0.35, 0.722]]], [[[0.9, 0.0], [1.0, 0.0], [1.0, 0.111], [0.9, 0.0]]]]) - self.assertEqual(self.polys_to_list(shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(10, 2))), [[[[4.0, 1.333], [0.0, 2.0], [2.0, 1.556], [4.0, 1.333]], [[3.5, 1.444], [3.4, 1.467], [3.5, 1.467], [3.5, 1.444]]], [[[9.0, 0.0], [10.0, 0.0], [10.0, 0.222], [9.0, 0.0]]]]) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Fill, + QgsGeometry.fromWkt( + "MultiPolygon(((5 5, 1 2, 3 4, 5 5), (4.5 4.5, 4.4 4.4, 4.5 4.4, 4.5 4.5)),((10 11, 11 11, 11 10, 10 11)))" + ), + False, + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(1, 1)) + ), + [ + [ + [[0.4, 0.667], [0.0, 1.0], [0.2, 0.778], [0.4, 0.667]], + [[0.35, 0.722], [0.34, 0.733], [0.35, 0.733], [0.35, 0.722]], + ], + [[[0.9, 0.0], [1.0, 0.0], [1.0, 0.111], [0.9, 0.0]]], + ], + ) + self.assertEqual( + self.polys_to_list( + shape.toQPolygonF(QgsSymbol.SymbolType.Fill, QSizeF(10, 2)) + ), + [ + [ + [[4.0, 1.333], [0.0, 2.0], [2.0, 1.556], [4.0, 1.333]], + [[3.5, 1.444], [3.4, 1.467], [3.5, 1.467], [3.5, 1.444]], + ], + [[[9.0, 0.0], [10.0, 0.0], [10.0, 0.222], [9.0, 0.0]]], + ], + ) def testScaledGeometry(self): """ Test scaling geometry """ - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString(5 5, 1 2)')) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt("LineString(5 5, 1 2)") + ) - self.assertEqual(shape.scaledGeometry(QSizeF(20, 30)).asWkt(1), 'LineString (20 7.5, 0 22.5)') - self.assertEqual(shape.scaledGeometry(QSizeF(200, 300)).asWkt(1), 'LineString (200 75, 0 225)') + self.assertEqual( + shape.scaledGeometry(QSizeF(20, 30)).asWkt(1), "LineString (20 7.5, 0 22.5)" + ) + self.assertEqual( + shape.scaledGeometry(QSizeF(200, 300)).asWkt(1), + "LineString (200 75, 0 225)", + ) shape.setScaleToOutputSize(False) - self.assertEqual(shape.scaledGeometry(QSizeF(20, 30)).asWkt(1), 'LineString (5 5, 1 2)') - self.assertEqual(shape.scaledGeometry(QSizeF(200, 300)).asWkt(1), 'LineString (5 5, 1 2)') + self.assertEqual( + shape.scaledGeometry(QSizeF(20, 30)).asWkt(1), "LineString (5 5, 1 2)" + ) + self.assertEqual( + shape.scaledGeometry(QSizeF(200, 300)).asWkt(1), "LineString (5 5, 1 2)" + ) def testRenderMarker(self): - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt('MultiPoint((5 5), (3 4), (1 2))'), False) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Marker, + QgsGeometry.fromWkt("MultiPoint((5 5), (3 4), (1 2))"), + False, + ) rendered_image = self.renderPatch(shape) self.assertTrue( - self.image_check('Marker', 'marker_multipoint', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "Marker", + "marker_multipoint", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testRenderMarkerPreserve(self): - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt('MultiPoint((5 5), (3 4), (1 2))'), True) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Marker, + QgsGeometry.fromWkt("MultiPoint((5 5), (3 4), (1 2))"), + True, + ) rendered_image = self.renderPatch(shape) self.assertTrue( - self.image_check('Marker Preserve', 'marker_multipoint_preserve', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "Marker Preserve", + "marker_multipoint_preserve", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testRenderLine(self): - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString(5 5, 3 4, 1 2)'), False) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, + QgsGeometry.fromWkt("LineString(5 5, 3 4, 1 2)"), + False, + ) rendered_image = self.renderPatch(shape) self.assertTrue( - self.image_check('Line', 'line', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "Line", "line", rendered_image, color_tolerance=2, allowed_mismatch=20 + ) ) def testRenderLinePreserve(self): - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString(5 5, 3 4, 1 2)'), True) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, + QgsGeometry.fromWkt("LineString(5 5, 3 4, 1 2)"), + True, + ) rendered_image = self.renderPatch(shape) self.assertTrue( - self.image_check('Line Preserve', 'line_preserve', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "Line Preserve", + "line_preserve", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testRenderMultiLine(self): - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('MultiLineString((5 5, 3 4, 1 2), ( 6 6, 6 0))'), True) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, + QgsGeometry.fromWkt("MultiLineString((5 5, 3 4, 1 2), ( 6 6, 6 0))"), + True, + ) rendered_image = self.renderPatch(shape) self.assertTrue( - self.image_check('Multiline', 'multiline', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "Multiline", + "multiline", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testRenderPolygon(self): - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Fill, QgsGeometry.fromWkt('Polygon((1 1 , 6 1, 6 6, 1 1),(4 2, 5 3, 4 3, 4 2))'), False) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Fill, + QgsGeometry.fromWkt("Polygon((1 1 , 6 1, 6 6, 1 1),(4 2, 5 3, 4 3, 4 2))"), + False, + ) rendered_image = self.renderPatch(shape) self.assertTrue( - self.image_check('Polygon', 'polygon', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "Polygon", + "polygon", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testRenderMultiPolygon(self): - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Fill, QgsGeometry.fromWkt('MultiPolygon(((1 1 , 6 1, 6 6, 1 1),(4 2, 5 3, 4 3, 4 2)),((1 5, 2 5, 1 6, 1 5)))'), False) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Fill, + QgsGeometry.fromWkt( + "MultiPolygon(((1 1 , 6 1, 6 6, 1 1),(4 2, 5 3, 4 3, 4 2)),((1 5, 2 5, 1 6, 1 5)))" + ), + False, + ) rendered_image = self.renderPatch(shape) self.assertTrue( - self.image_check('MultiPolygon', 'multipolygon', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "MultiPolygon", + "multipolygon", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testReadWriteXml(self): doc = QDomDocument("testdoc") - elem = doc.createElement('test') - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('MultiLineString((5 5, 3 4, 1 2), ( 6 6, 6 0))'), False) + elem = doc.createElement("test") + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, + QgsGeometry.fromWkt("MultiLineString((5 5, 3 4, 1 2), ( 6 6, 6 0))"), + False, + ) shape.writeXml(elem, doc, QgsReadWriteContext()) @@ -267,7 +676,9 @@ def testReadWriteXml(self): s2.readXml(elem, QgsReadWriteContext()) self.assertFalse(s2.isNull()) - self.assertEqual(s2.geometry().asWkt(), 'MultiLineString ((5 5, 3 4, 1 2),(6 6, 6 0))') + self.assertEqual( + s2.geometry().asWkt(), "MultiLineString ((5 5, 3 4, 1 2),(6 6, 6 0))" + ) self.assertFalse(s2.preserveAspectRatio()) self.assertEqual(s2.symbolType(), QgsSymbol.SymbolType.Line) @@ -287,16 +698,22 @@ def renderPatch(self, patch): image.fill(QColor(0, 0, 0)) if patch.symbolType() == QgsSymbol.SymbolType.Fill: - self.fill_symbol.drawPreviewIcon(painter, QSize(200, 200), None, False, None, patch) + self.fill_symbol.drawPreviewIcon( + painter, QSize(200, 200), None, False, None, patch + ) elif patch.symbolType() == QgsSymbol.SymbolType.Line: - self.line_symbol.drawPreviewIcon(painter, QSize(200, 200), None, False, None, patch) + self.line_symbol.drawPreviewIcon( + painter, QSize(200, 200), None, False, None, patch + ) elif patch.symbolType() == QgsSymbol.SymbolType.Marker: - self.marker_symbol.drawPreviewIcon(painter, QSize(200, 200), None, False, None, patch) + self.marker_symbol.drawPreviewIcon( + painter, QSize(200, 200), None, False, None, patch + ) finally: painter.end() return image -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslegendpatchshapebutton.py b/tests/src/python/test_qgslegendpatchshapebutton.py index 73d08dd927ed..3a8a30d93a3a 100644 --- a/tests/src/python/test_qgslegendpatchshapebutton.py +++ b/tests/src/python/test_qgslegendpatchshapebutton.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 by Nyall Dawson' -__date__ = '20/04/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 by Nyall Dawson" +__date__ = "20/04/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy from qgis.core import QgsGeometry, QgsLegendPatchShape, QgsSymbol @@ -24,25 +25,35 @@ class TestQgsLegendPatchShapeButton(QgisTestCase): def testWidget(self): - widget = QgsLegendPatchShapeButton(dialogTitle='title') + widget = QgsLegendPatchShapeButton(dialogTitle="title") self.assertTrue(widget.shape().isNull()) - self.assertEqual(widget.dialogTitle(), 'title') - widget.setDialogTitle('title2') - self.assertEqual(widget.dialogTitle(), 'title2') + self.assertEqual(widget.dialogTitle(), "title") + widget.setDialogTitle("title2") + self.assertEqual(widget.dialogTitle(), "title2") widget.setSymbolType(QgsSymbol.SymbolType.Fill) self.assertEqual(widget.symbolType(), QgsSymbol.SymbolType.Fill) self.assertTrue(widget.shape().isNull()) - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Fill, QgsGeometry.fromWkt('Polygon((5 5, 1 2, 3 4, 5 5))'), False) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Fill, + QgsGeometry.fromWkt("Polygon((5 5, 1 2, 3 4, 5 5))"), + False, + ) widget.setShape(shape) - self.assertEqual(widget.shape().geometry().asWkt(), 'Polygon ((5 5, 1 2, 3 4, 5 5))') + self.assertEqual( + widget.shape().geometry().asWkt(), "Polygon ((5 5, 1 2, 3 4, 5 5))" + ) self.assertFalse(widget.shape().preserveAspectRatio()) self.assertEqual(widget.shape().symbolType(), QgsSymbol.SymbolType.Fill) # try to set incompatible shape - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString( 0 0, 1 1)'), True) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, + QgsGeometry.fromWkt("LineString( 0 0, 1 1)"), + True, + ) widget.setShape(shape) # should be back to default self.assertTrue(widget.shape().isNull()) @@ -50,15 +61,23 @@ def testWidget(self): # change type widget.setSymbolType(QgsSymbol.SymbolType.Line) self.assertEqual(widget.symbolType(), QgsSymbol.SymbolType.Line) - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString( 0 0, 1 1)'), True) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, + QgsGeometry.fromWkt("LineString( 0 0, 1 1)"), + True, + ) widget.setShape(shape) - self.assertEqual(widget.shape().geometry().asWkt(), 'LineString (0 0, 1 1)') + self.assertEqual(widget.shape().geometry().asWkt(), "LineString (0 0, 1 1)") widget.setToDefault() self.assertTrue(widget.shape().isNull()) def testSignals(self): - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Fill, QgsGeometry.fromWkt('Polygon((5 5, 1 2, 3 4, 5 5))'), False) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Fill, + QgsGeometry.fromWkt("Polygon((5 5, 1 2, 3 4, 5 5))"), + False, + ) widget = QgsLegendPatchShapeButton() spy = QSignalSpy(widget.changed) @@ -67,21 +86,29 @@ def testSignals(self): widget.setShape(shape) self.assertEqual(len(spy), 1) - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString( 0 0, 1 1)'), True) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, + QgsGeometry.fromWkt("LineString( 0 0, 1 1)"), + True, + ) widget.setShape(shape) self.assertEqual(len(spy), 2) self.assertTrue(widget.shape().isNull()) widget.setSymbolType(QgsSymbol.SymbolType.Line) self.assertEqual(len(spy), 3) - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString( 0 0, 1 2)'), True) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, + QgsGeometry.fromWkt("LineString( 0 0, 1 2)"), + True, + ) widget.setShape(shape) self.assertEqual(len(spy), 4) - self.assertEqual(widget.shape().geometry().asWkt(), 'LineString (0 0, 1 2)') + self.assertEqual(widget.shape().geometry().asWkt(), "LineString (0 0, 1 2)") widget.setToDefault() self.assertEqual(len(spy), 5) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslegendpatchshapewidget.py b/tests/src/python/test_qgslegendpatchshapewidget.py index 6f4e6183302d..69241a7d90ea 100644 --- a/tests/src/python/test_qgslegendpatchshapewidget.py +++ b/tests/src/python/test_qgslegendpatchshapewidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 by Nyall Dawson' -__date__ = '20/04/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 by Nyall Dawson" +__date__ = "20/04/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy from qgis.core import QgsGeometry, QgsLegendPatchShape, QgsSymbol @@ -24,33 +25,53 @@ class TestQgsLegendPatchShapeWidget(QgisTestCase): def testWidget(self): - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString( 0 0, 1 1)'), False) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, + QgsGeometry.fromWkt("LineString( 0 0, 1 1)"), + False, + ) widget = QgsLegendPatchShapeWidget(None, shape) - self.assertEqual(widget.shape().geometry().asWkt(), 'LineString (0 0, 1 1)') + self.assertEqual(widget.shape().geometry().asWkt(), "LineString (0 0, 1 1)") self.assertFalse(widget.shape().preserveAspectRatio()) self.assertEqual(widget.shape().symbolType(), QgsSymbol.SymbolType.Line) - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString( 0 0, 1 1)'), True) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, + QgsGeometry.fromWkt("LineString( 0 0, 1 1)"), + True, + ) widget = QgsLegendPatchShapeWidget(None, shape) - self.assertEqual(widget.shape().geometry().asWkt(), 'LineString (0 0, 1 1)') + self.assertEqual(widget.shape().geometry().asWkt(), "LineString (0 0, 1 1)") self.assertTrue(widget.shape().preserveAspectRatio()) self.assertEqual(widget.shape().symbolType(), QgsSymbol.SymbolType.Line) - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Fill, QgsGeometry.fromWkt('Polygon((5 5, 1 2, 3 4, 5 5))'), False) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Fill, + QgsGeometry.fromWkt("Polygon((5 5, 1 2, 3 4, 5 5))"), + False, + ) widget = QgsLegendPatchShapeWidget(None, shape) - self.assertEqual(widget.shape().geometry().asWkt(), 'Polygon ((5 5, 1 2, 3 4, 5 5))') + self.assertEqual( + widget.shape().geometry().asWkt(), "Polygon ((5 5, 1 2, 3 4, 5 5))" + ) self.assertFalse(widget.shape().preserveAspectRatio()) self.assertEqual(widget.shape().symbolType(), QgsSymbol.SymbolType.Fill) - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt('MultiPoint((5 5), (1 2))')) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt("MultiPoint((5 5), (1 2))") + ) widget = QgsLegendPatchShapeWidget(None, shape) - self.assertEqual(widget.shape().geometry().asWkt(), 'MultiPoint ((5 5),(1 2))') + self.assertEqual(widget.shape().geometry().asWkt(), "MultiPoint ((5 5),(1 2))") self.assertTrue(widget.shape().preserveAspectRatio()) self.assertEqual(widget.shape().symbolType(), QgsSymbol.SymbolType.Marker) def testSignals(self): - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString( 0 0, 1 1)'), False) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, + QgsGeometry.fromWkt("LineString( 0 0, 1 1)"), + False, + ) widget = QgsLegendPatchShapeWidget(None, shape) spy = QSignalSpy(widget.changed) @@ -58,27 +79,39 @@ def testSignals(self): self.assertEqual(len(spy), 0) self.assertFalse(widget.shape().preserveAspectRatio()) - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString( 0 0, 1 1)'), True) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, + QgsGeometry.fromWkt("LineString( 0 0, 1 1)"), + True, + ) widget.setShape(shape) self.assertEqual(len(spy), 1) self.assertTrue(widget.shape().preserveAspectRatio()) - self.assertEqual(widget.shape().geometry().asWkt(), 'LineString (0 0, 1 1)') + self.assertEqual(widget.shape().geometry().asWkt(), "LineString (0 0, 1 1)") self.assertEqual(widget.shape().symbolType(), QgsSymbol.SymbolType.Line) - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString( 0 0, 1 2)'), True) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, + QgsGeometry.fromWkt("LineString( 0 0, 1 2)"), + True, + ) widget.setShape(shape) self.assertEqual(len(spy), 2) self.assertTrue(widget.shape().preserveAspectRatio()) - self.assertEqual(widget.shape().geometry().asWkt(), 'LineString (0 0, 1 2)') + self.assertEqual(widget.shape().geometry().asWkt(), "LineString (0 0, 1 2)") self.assertEqual(widget.shape().symbolType(), QgsSymbol.SymbolType.Line) - shape = QgsLegendPatchShape(QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt('MultiPoint((5 5), (1 2))'), True) + shape = QgsLegendPatchShape( + QgsSymbol.SymbolType.Marker, + QgsGeometry.fromWkt("MultiPoint((5 5), (1 2))"), + True, + ) widget.setShape(shape) self.assertEqual(len(spy), 3) self.assertTrue(widget.shape().preserveAspectRatio()) - self.assertEqual(widget.shape().geometry().asWkt(), 'MultiPoint ((5 5),(1 2))') + self.assertEqual(widget.shape().geometry().asWkt(), "MultiPoint ((5 5),(1 2))") self.assertEqual(widget.shape().symbolType(), QgsSymbol.SymbolType.Marker) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslegendrenderer.py b/tests/src/python/test_qgslegendrenderer.py index 8873b55da3d5..acd78e339883 100644 --- a/tests/src/python/test_qgslegendrenderer.py +++ b/tests/src/python/test_qgslegendrenderer.py @@ -9,9 +9,9 @@ """ -__author__ = 'elpaso@itopen.it' -__date__ = '2020-04-29' -__copyright__ = 'Copyright 2020, ItOpen' +__author__ = "elpaso@itopen.it" +__date__ = "2020-04-29" +__copyright__ = "Copyright 2020, ItOpen" import os @@ -36,16 +36,20 @@ class TestPyQgsLegendRenderer(QgisTestCase): def test_json_export(self): project = QgsProject() - self.assertTrue(project.read(os.path.join(unitTestDataPath('qgis_server'), 'test_project.qgs'))) + self.assertTrue( + project.read( + os.path.join(unitTestDataPath("qgis_server"), "test_project.qgs") + ) + ) model = QgsLegendModel(project.layerTreeRoot()) ctx = QgsRenderContext() settings = QgsLegendSettings() renderer = QgsLegendRenderer(model, settings) - nodes = renderer.exportLegendToJson(ctx)['nodes'].toVariant() + nodes = renderer.exportLegendToJson(ctx)["nodes"].toVariant() self.assertEqual(len(nodes), 9) - self.assertEqual(nodes[0]['type'], 'layer') - self.assertEqual(nodes[0]['title'], 'testlayer') + self.assertEqual(nodes[0]["type"], "layer") + self.assertEqual(nodes[0]["title"], "testlayer") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslinearreferencingsymbollayer.py b/tests/src/python/test_qgslinearreferencingsymbollayer.py index 37a5ba0253ac..42718c7bf1ef 100644 --- a/tests/src/python/test_qgslinearreferencingsymbollayer.py +++ b/tests/src/python/test_qgslinearreferencingsymbollayer.py @@ -14,6 +14,7 @@ * * *************************************************************************** """ + import unittest from qgis.PyQt.QtCore import QPointF, QSize @@ -32,7 +33,7 @@ QgsMarkerSymbol, QgsFillSymbol, QgsVectorLayer, - QgsSingleSymbolRenderer + QgsSingleSymbolRenderer, ) from qgis.testing import start_app, QgisTestCase @@ -46,18 +47,18 @@ class TestQgsSimpleLineSymbolLayer(QgisTestCase): @classmethod def control_path_prefix(cls): - return 'symbol_linearref' + return "symbol_linearref" def test_distance_2d(self): s = QgsLineSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.IntervalCartesian2D) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.IntervalCartesian2D) linear_ref.setInterval(1) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -66,29 +67,32 @@ def test_distance_2d(self): s.appendSymbolLayer(linear_ref) - rendered_image = self.renderGeometry(s, - QgsGeometry.fromWkt( - 'MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))')) + rendered_image = self.renderGeometry( + s, + QgsGeometry.fromWkt( + "MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))" + ), + ) self.assertTrue( self.image_check( - 'distance_2d', - 'distance_2d', + "distance_2d", + "distance_2d", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_render_using_label_engine(self): s = QgsLineSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.IntervalCartesian2D) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.IntervalCartesian2D) linear_ref.setInterval(1) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -97,9 +101,11 @@ def test_render_using_label_engine(self): s.appendSymbolLayer(linear_ref) - layer = QgsVectorLayer('LineString', 'test', 'memory') + layer = QgsVectorLayer("LineString", "test", "memory") feature = QgsFeature() - geom = QgsGeometry.fromWkt('MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))') + geom = QgsGeometry.fromWkt( + "MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))" + ) feature.setGeometry(geom) layer.dataProvider().addFeature(feature) layer.setRenderer(QgsSingleSymbolRenderer(s)) @@ -114,21 +120,21 @@ def test_render_using_label_engine(self): self.assertTrue( self.render_map_settings_check( - 'labeling_engine', - 'labeling_engine', + "labeling_engine", + "labeling_engine", ms, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_distance_2d_with_z(self): s = QgsLineSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.IntervalCartesian2D) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.IntervalCartesian2D) linear_ref.setInterval(1) linear_ref.setLabelSource(Qgis.LinearReferencingLabelSource.Z) @@ -137,7 +143,7 @@ def test_distance_2d_with_z(self): number_format.setShowTrailingZeros(False) linear_ref.setNumericFormat(number_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -146,26 +152,29 @@ def test_distance_2d_with_z(self): s.appendSymbolLayer(linear_ref) - rendered_image = self.renderGeometry(s, - QgsGeometry.fromWkt( - 'MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))')) + rendered_image = self.renderGeometry( + s, + QgsGeometry.fromWkt( + "MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))" + ), + ) self.assertTrue( self.image_check( - 'distance_with_z', - 'distance_with_z', + "distance_with_z", + "distance_with_z", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_distance_2d_with_m(self): s = QgsLineSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.IntervalCartesian2D) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.IntervalCartesian2D) linear_ref.setInterval(1) linear_ref.setLabelSource(Qgis.LinearReferencingLabelSource.M) @@ -174,7 +183,7 @@ def test_distance_2d_with_m(self): number_format.setShowTrailingZeros(False) linear_ref.setNumericFormat(number_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -183,26 +192,29 @@ def test_distance_2d_with_m(self): s.appendSymbolLayer(linear_ref) - rendered_image = self.renderGeometry(s, - QgsGeometry.fromWkt( - 'MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))')) + rendered_image = self.renderGeometry( + s, + QgsGeometry.fromWkt( + "MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))" + ), + ) self.assertTrue( self.image_check( - 'distance_with_m', - 'distance_with_m', + "distance_with_m", + "distance_with_m", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_interpolate_by_z_with_distance(self): s = QgsLineSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.IntervalZ) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.IntervalZ) linear_ref.setInterval(0.3) linear_ref.setLabelSource(Qgis.LinearReferencingLabelSource.CartesianDistance2D) @@ -211,7 +223,7 @@ def test_interpolate_by_z_with_distance(self): number_format.setShowTrailingZeros(False) linear_ref.setNumericFormat(number_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -220,26 +232,29 @@ def test_interpolate_by_z_with_distance(self): s.appendSymbolLayer(linear_ref) - rendered_image = self.renderGeometry(s, - QgsGeometry.fromWkt( - 'MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))')) + rendered_image = self.renderGeometry( + s, + QgsGeometry.fromWkt( + "MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))" + ), + ) self.assertTrue( self.image_check( - 'placement_by_z_distance', - 'placement_by_z_distance', + "placement_by_z_distance", + "placement_by_z_distance", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_interpolate_by_z_with_z(self): s = QgsLineSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.IntervalZ) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.IntervalZ) linear_ref.setInterval(0.3) linear_ref.setLabelSource(Qgis.LinearReferencingLabelSource.Z) @@ -248,7 +263,7 @@ def test_interpolate_by_z_with_z(self): number_format.setShowTrailingZeros(False) linear_ref.setNumericFormat(number_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -257,26 +272,29 @@ def test_interpolate_by_z_with_z(self): s.appendSymbolLayer(linear_ref) - rendered_image = self.renderGeometry(s, - QgsGeometry.fromWkt( - 'MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))')) + rendered_image = self.renderGeometry( + s, + QgsGeometry.fromWkt( + "MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))" + ), + ) self.assertTrue( self.image_check( - 'placement_by_z_z', - 'placement_by_z_z', + "placement_by_z_z", + "placement_by_z_z", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_interpolate_by_z_with_m(self): s = QgsLineSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.IntervalZ) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.IntervalZ) linear_ref.setInterval(0.3) linear_ref.setLabelSource(Qgis.LinearReferencingLabelSource.M) @@ -285,7 +303,7 @@ def test_interpolate_by_z_with_m(self): number_format.setShowTrailingZeros(False) linear_ref.setNumericFormat(number_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -294,26 +312,29 @@ def test_interpolate_by_z_with_m(self): s.appendSymbolLayer(linear_ref) - rendered_image = self.renderGeometry(s, - QgsGeometry.fromWkt( - 'MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))')) + rendered_image = self.renderGeometry( + s, + QgsGeometry.fromWkt( + "MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))" + ), + ) self.assertTrue( self.image_check( - 'placement_by_z_m', - 'placement_by_z_m', + "placement_by_z_m", + "placement_by_z_m", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_interpolate_by_m_with_distance(self): s = QgsLineSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.IntervalM) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.IntervalM) linear_ref.setInterval(0.3) linear_ref.setLabelSource(Qgis.LinearReferencingLabelSource.CartesianDistance2D) @@ -322,7 +343,7 @@ def test_interpolate_by_m_with_distance(self): number_format.setShowTrailingZeros(False) linear_ref.setNumericFormat(number_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -331,26 +352,29 @@ def test_interpolate_by_m_with_distance(self): s.appendSymbolLayer(linear_ref) - rendered_image = self.renderGeometry(s, - QgsGeometry.fromWkt( - 'MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))')) + rendered_image = self.renderGeometry( + s, + QgsGeometry.fromWkt( + "MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))" + ), + ) self.assertTrue( self.image_check( - 'placement_by_m_distance', - 'placement_by_m_distance', + "placement_by_m_distance", + "placement_by_m_distance", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_interpolate_by_m_with_z(self): s = QgsLineSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.IntervalM) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.IntervalM) linear_ref.setInterval(0.3) linear_ref.setLabelSource(Qgis.LinearReferencingLabelSource.Z) @@ -359,7 +383,7 @@ def test_interpolate_by_m_with_z(self): number_format.setShowTrailingZeros(False) linear_ref.setNumericFormat(number_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -368,26 +392,29 @@ def test_interpolate_by_m_with_z(self): s.appendSymbolLayer(linear_ref) - rendered_image = self.renderGeometry(s, - QgsGeometry.fromWkt( - 'MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))')) + rendered_image = self.renderGeometry( + s, + QgsGeometry.fromWkt( + "MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))" + ), + ) self.assertTrue( self.image_check( - 'placement_by_m_z', - 'placement_by_m_z', + "placement_by_m_z", + "placement_by_m_z", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_interpolate_by_m_with_m(self): s = QgsLineSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.IntervalM) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.IntervalM) linear_ref.setInterval(0.3) linear_ref.setLabelSource(Qgis.LinearReferencingLabelSource.M) @@ -396,7 +423,7 @@ def test_interpolate_by_m_with_m(self): number_format.setShowTrailingZeros(False) linear_ref.setNumericFormat(number_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -405,26 +432,29 @@ def test_interpolate_by_m_with_m(self): s.appendSymbolLayer(linear_ref) - rendered_image = self.renderGeometry(s, - QgsGeometry.fromWkt( - 'MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))')) + rendered_image = self.renderGeometry( + s, + QgsGeometry.fromWkt( + "MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))" + ), + ) self.assertTrue( self.image_check( - 'placement_by_m_m', - 'placement_by_m_m', + "placement_by_m_m", + "placement_by_m_m", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_at_vertex_with_distance(self): s = QgsLineSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.Vertex) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.Vertex) linear_ref.setLabelSource(Qgis.LinearReferencingLabelSource.CartesianDistance2D) number_format = QgsBasicNumericFormat() @@ -432,7 +462,7 @@ def test_at_vertex_with_distance(self): number_format.setShowTrailingZeros(False) linear_ref.setNumericFormat(number_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -441,26 +471,29 @@ def test_at_vertex_with_distance(self): s.appendSymbolLayer(linear_ref) - rendered_image = self.renderGeometry(s, - QgsGeometry.fromWkt( - 'MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))')) + rendered_image = self.renderGeometry( + s, + QgsGeometry.fromWkt( + "MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))" + ), + ) self.assertTrue( self.image_check( - 'vertex_distance', - 'vertex_distance', + "vertex_distance", + "vertex_distance", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_at_vertex_with_z(self): s = QgsLineSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.Vertex) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.Vertex) linear_ref.setLabelSource(Qgis.LinearReferencingLabelSource.Z) number_format = QgsBasicNumericFormat() @@ -468,7 +501,7 @@ def test_at_vertex_with_z(self): number_format.setShowTrailingZeros(False) linear_ref.setNumericFormat(number_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -477,26 +510,29 @@ def test_at_vertex_with_z(self): s.appendSymbolLayer(linear_ref) - rendered_image = self.renderGeometry(s, - QgsGeometry.fromWkt( - 'MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))')) + rendered_image = self.renderGeometry( + s, + QgsGeometry.fromWkt( + "MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))" + ), + ) self.assertTrue( self.image_check( - 'vertex_z', - 'vertex_z', + "vertex_z", + "vertex_z", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_at_vertex_with_m(self): s = QgsLineSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.Vertex) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.Vertex) linear_ref.setLabelSource(Qgis.LinearReferencingLabelSource.M) number_format = QgsBasicNumericFormat() @@ -504,7 +540,7 @@ def test_at_vertex_with_m(self): number_format.setShowTrailingZeros(False) linear_ref.setNumericFormat(number_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -513,29 +549,32 @@ def test_at_vertex_with_m(self): s.appendSymbolLayer(linear_ref) - rendered_image = self.renderGeometry(s, - QgsGeometry.fromWkt( - 'MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))')) + rendered_image = self.renderGeometry( + s, + QgsGeometry.fromWkt( + "MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))" + ), + ) self.assertTrue( self.image_check( - 'vertex_m', - 'vertex_m', + "vertex_m", + "vertex_m", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_distance_2d_skip_multiples(self): s = QgsLineSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.IntervalCartesian2D) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.IntervalCartesian2D) linear_ref.setInterval(1) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -545,29 +584,32 @@ def test_distance_2d_skip_multiples(self): s.appendSymbolLayer(linear_ref) - rendered_image = self.renderGeometry(s, - QgsGeometry.fromWkt( - 'MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))')) + rendered_image = self.renderGeometry( + s, + QgsGeometry.fromWkt( + "MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))" + ), + ) self.assertTrue( self.image_check( - 'skip_multiples', - 'skip_multiples', + "skip_multiples", + "skip_multiples", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_distance_2d_numeric_format(self): s = QgsLineSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.IntervalCartesian2D) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.IntervalCartesian2D) linear_ref.setInterval(1) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -581,29 +623,32 @@ def test_distance_2d_numeric_format(self): s.appendSymbolLayer(linear_ref) - rendered_image = self.renderGeometry(s, - QgsGeometry.fromWkt( - 'MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))')) + rendered_image = self.renderGeometry( + s, + QgsGeometry.fromWkt( + "MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))" + ), + ) self.assertTrue( self.image_check( - 'numeric_format', - 'numeric_format', + "numeric_format", + "numeric_format", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_distance_2d_no_rotate(self): s = QgsLineSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.IntervalCartesian2D) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.IntervalCartesian2D) linear_ref.setInterval(1) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -614,29 +659,32 @@ def test_distance_2d_no_rotate(self): s.appendSymbolLayer(linear_ref) - rendered_image = self.renderGeometry(s, - QgsGeometry.fromWkt( - 'MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))')) + rendered_image = self.renderGeometry( + s, + QgsGeometry.fromWkt( + "MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))" + ), + ) self.assertTrue( self.image_check( - 'no_rotate', - 'no_rotate', + "no_rotate", + "no_rotate", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_distance_2d_marker(self): s = QgsLineSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.IntervalCartesian2D) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.IntervalCartesian2D) linear_ref.setInterval(1) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -646,35 +694,43 @@ def test_distance_2d_marker(self): linear_ref.setShowMarker(True) linear_ref.setSubSymbol( QgsMarkerSymbol.createSimple( - {'color': '#00ff00', 'outline_style': 'no', 'size': '8', 'name': 'arrow'} + { + "color": "#00ff00", + "outline_style": "no", + "size": "8", + "name": "arrow", + } ) ) s.appendSymbolLayer(linear_ref) - rendered_image = self.renderGeometry(s, - QgsGeometry.fromWkt( - 'MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))')) + rendered_image = self.renderGeometry( + s, + QgsGeometry.fromWkt( + "MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))" + ), + ) self.assertTrue( self.image_check( - 'marker', - 'marker', + "marker", + "marker", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_distance_2d_marker_no_rotate(self): s = QgsLineSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.IntervalCartesian2D) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.IntervalCartesian2D) linear_ref.setInterval(1) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -684,36 +740,44 @@ def test_distance_2d_marker_no_rotate(self): linear_ref.setShowMarker(True) linear_ref.setSubSymbol( QgsMarkerSymbol.createSimple( - {'color': '#00ff00', 'outline_style': 'no', 'size': '8', 'name': 'arrow'} + { + "color": "#00ff00", + "outline_style": "no", + "size": "8", + "name": "arrow", + } ) ) linear_ref.setRotateLabels(False) s.appendSymbolLayer(linear_ref) - rendered_image = self.renderGeometry(s, - QgsGeometry.fromWkt( - 'MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))')) + rendered_image = self.renderGeometry( + s, + QgsGeometry.fromWkt( + "MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4))" + ), + ) self.assertTrue( self.image_check( - 'marker_no_rotate', - 'marker_no_rotate', + "marker_no_rotate", + "marker_no_rotate", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_multiline(self): s = QgsLineSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.IntervalCartesian2D) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.IntervalCartesian2D) linear_ref.setInterval(1) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -722,30 +786,33 @@ def test_multiline(self): s.appendSymbolLayer(linear_ref) - rendered_image = self.renderGeometry(s, - QgsGeometry.fromWkt( - 'MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4),' - '(16 12 0.2 1.2, 19 12 0.7 0.2))')) + rendered_image = self.renderGeometry( + s, + QgsGeometry.fromWkt( + "MultiLineStringZM ((6 2 0.2 1.2, 9 2 0.7 0.2, 9 3 0.4 0, 11 5 0.8 0.4)," + "(16 12 0.2 1.2, 19 12 0.7 0.2))" + ), + ) self.assertTrue( self.image_check( - 'multiline', - 'multiline', + "multiline", + "multiline", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_polygon(self): s = QgsFillSymbol.createSimple( - {'outline_color': '#ff0000', 'outline_width': '2'}) + {"outline_color": "#ff0000", "outline_width": "2"} + ) linear_ref = QgsLinearReferencingSymbolLayer() - linear_ref.setPlacement( - Qgis.LinearReferencingPlacement.IntervalCartesian2D) + linear_ref.setPlacement(Qgis.LinearReferencingPlacement.IntervalCartesian2D) linear_ref.setInterval(1) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) text_format = QgsTextFormat.fromQFont(font) text_format.setColor(QColor(255, 255, 255)) linear_ref.setTextFormat(text_format) @@ -754,16 +821,19 @@ def test_polygon(self): s.appendSymbolLayer(linear_ref) - rendered_image = self.renderGeometry(s, - QgsGeometry.fromWkt( - 'Polygon ((6 1, 10 1, 10 -3, 6 -3, 6 1),(7 0, 7 -2, 9 -2, 9 0, 7 0))')) + rendered_image = self.renderGeometry( + s, + QgsGeometry.fromWkt( + "Polygon ((6 1, 10 1, 10 -3, 6 -3, 6 1),(7 0, 7 -2, 9 -2, 9 0, 7 0))" + ), + ) self.assertTrue( self.image_check( - 'polygon', - 'polygon', + "polygon", + "polygon", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -800,5 +870,5 @@ def renderGeometry(self, symbol, geom): return image -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslineburstsymbollayer.py b/tests/src/python/test_qgslineburstsymbollayer.py index ccb8a5e92886..842e76ef0def 100644 --- a/tests/src/python/test_qgslineburstsymbollayer.py +++ b/tests/src/python/test_qgslineburstsymbollayer.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'October 2021' -__copyright__ = '(C) 2021, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "October 2021" +__copyright__ = "(C) 2021, Nyall Dawson" from qgis.PyQt.QtCore import Qt from qgis.PyQt.QtGui import QColor, QImage, QPainter @@ -60,12 +60,16 @@ def testTwoColor(self): s.appendSymbolLayer(line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('lineburst_two_color', 'lineburst_two_color', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "lineburst_two_color", + "lineburst_two_color", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testDataDefinedColors(self): @@ -76,17 +80,27 @@ def testDataDefinedColors(self): line.setColor(QColor(255, 0, 0)) line.setColor2(QColor(0, 255, 0)) line.setWidth(8) - line.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyStrokeColor, QgsProperty.fromExpression("'orange'")) - line.setDataDefinedProperty(QgsSymbolLayer.Property.PropertySecondaryColor, QgsProperty.fromExpression("'purple'")) + line.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyStrokeColor, + QgsProperty.fromExpression("'orange'"), + ) + line.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertySecondaryColor, + QgsProperty.fromExpression("'purple'"), + ) s.appendSymbolLayer(line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('lineburst_datadefined_color', 'lineburst_datadefined_color', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "lineburst_datadefined_color", + "lineburst_datadefined_color", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testColorRamp(self): @@ -95,18 +109,28 @@ def testColorRamp(self): line = QgsLineburstSymbolLayer() line.setGradientColorType(Qgis.GradientColorSource.ColorRamp) - line.setColorRamp(QgsGradientColorRamp(QColor(200, 0, 0), QColor(0, 200, 0), False, - [QgsGradientStop(0.5, QColor(0, 0, 200))])) + line.setColorRamp( + QgsGradientColorRamp( + QColor(200, 0, 0), + QColor(0, 200, 0), + False, + [QgsGradientStop(0.5, QColor(0, 0, 200))], + ) + ) line.setWidth(8) s.appendSymbolLayer(line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('lineburst_colorramp', 'lineburst_colorramp', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "lineburst_colorramp", + "lineburst_colorramp", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testRenderClosedRing(self): @@ -120,12 +144,16 @@ def testRenderClosedRing(self): s.appendSymbolLayer(line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10, 0 10, 0 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 0, 10 10, 0 10, 0 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('lineburst_closed', 'lineburst_closed', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "lineburst_closed", + "lineburst_closed", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testRenderFlatCap(self): @@ -140,12 +168,16 @@ def testRenderFlatCap(self): s.appendSymbolLayer(line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('lineburst_flatcap', 'lineburst_flatcap', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "lineburst_flatcap", + "lineburst_flatcap", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testRenderSquareCap(self): @@ -160,12 +192,16 @@ def testRenderSquareCap(self): s.appendSymbolLayer(line.clone()) - g = QgsGeometry.fromWkt('LineString(2 2, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(2 2, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('lineburst_squarecap', 'lineburst_squarecap', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "lineburst_squarecap", + "lineburst_squarecap", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testRenderMiterJoin(self): @@ -180,12 +216,16 @@ def testRenderMiterJoin(self): s.appendSymbolLayer(line.clone()) - g = QgsGeometry.fromWkt('LineString(0 15, 0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 15, 0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('lineburst_miterjoin', 'lineburst_miterjoin', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "lineburst_miterjoin", + "lineburst_miterjoin", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testRenderBevelJoin(self): @@ -200,12 +240,16 @@ def testRenderBevelJoin(self): s.appendSymbolLayer(line.clone()) - g = QgsGeometry.fromWkt('LineString(2 2, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(2 2, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('lineburst_beveljoin', 'lineburst_beveljoin', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "lineburst_beveljoin", + "lineburst_beveljoin", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testLineOffset(self): @@ -220,12 +264,16 @@ def testLineOffset(self): s.appendSymbolLayer(line.clone()) - g = QgsGeometry.fromWkt('LineString(2 2, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(2 2, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('lineburst_offset', 'lineburst_offset', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "lineburst_offset", + "lineburst_offset", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def renderGeometry(self, symbol, geom, buffer=20): @@ -262,5 +310,5 @@ def renderGeometry(self, symbol, geom, buffer=20): return image -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslinesegment.py b/tests/src/python/test_qgslinesegment.py index 8e780aeba92c..8abec0be8e0c 100644 --- a/tests/src/python/test_qgslinesegment.py +++ b/tests/src/python/test_qgslinesegment.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '13/04/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "13/04/2018" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.core import QgsLineSegment2D, QgsPointXY @@ -118,5 +119,5 @@ def testReverse(self): self.assertEqual(segment.end(), QgsPointXY(1, 2)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslinestring.py b/tests/src/python/test_qgslinestring.py index 3b2d68e4ba9d..48bf479b8b86 100644 --- a/tests/src/python/test_qgslinestring.py +++ b/tests/src/python/test_qgslinestring.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Loïc Bartoletti' -__date__ = '12/09/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "Loïc Bartoletti" +__date__ = "12/09/2023" +__copyright__ = "Copyright 2023, The QGIS Project" import unittest import math @@ -38,15 +39,30 @@ def testMeasureLine(self): line = QgsLineString([[0, 0], [2, 0], [4, 0]]) m_line = line.measuredLine(10, 20) - self.assertEqual(m_line, QgsLineString([QgsPoint(0, 0, m=10), QgsPoint(2, 0, m=15), QgsPoint(4, 0, m=20)])) + self.assertEqual( + m_line, + QgsLineString( + [QgsPoint(0, 0, m=10), QgsPoint(2, 0, m=15), QgsPoint(4, 0, m=20)] + ), + ) line = QgsLineString([[0, 0], [9, 0], [10, 0]]) m_line = line.measuredLine(10, 20) - self.assertEqual(m_line, QgsLineString([QgsPoint(0, 0, m=10), QgsPoint(9, 0, m=19), QgsPoint(10, 0, m=20)])) + self.assertEqual( + m_line, + QgsLineString( + [QgsPoint(0, 0, m=10), QgsPoint(9, 0, m=19), QgsPoint(10, 0, m=20)] + ), + ) line = QgsLineString([[0, 0], [0, 0], [0, 0]]) m_line = line.measuredLine(10, 20) - self.assertEqual(m_line, QgsLineString([QgsPoint(0, 0, m=10), QgsPoint(0, 0, m=15), QgsPoint(0, 0, m=20)])) + self.assertEqual( + m_line, + QgsLineString( + [QgsPoint(0, 0, m=10), QgsPoint(0, 0, m=15), QgsPoint(0, 0, m=20)] + ), + ) def testFuzzyComparisons(self): ###### @@ -87,8 +103,12 @@ def testFuzzyComparisons(self): # 3DM # ####### epsilon = 0.001 - geom1 = QgsLineString(QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.001)) - geom2 = QgsLineString(QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.002)) + geom1 = QgsLineString( + QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.001) + ) + geom2 = QgsLineString( + QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.002) + ) self.assertNotEqual(geom1, geom2) # epsilon = 1e-8 here @@ -104,8 +124,12 @@ def testFuzzyComparisons(self): # 4D # ###### epsilon = 0.001 - geom1 = QgsLineString(QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001, 0.001)) - geom2 = QgsLineString(QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.002, 0.002, 0.002, 0.002)) + geom1 = QgsLineString( + QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001, 0.001) + ) + geom2 = QgsLineString( + QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.002, 0.002, 0.002, 0.002) + ) self.assertNotEqual(geom1, geom2) # epsilon = 1e-8 here @@ -124,22 +148,26 @@ def testInterpolateM(self): self.assertIsNone(line.interpolateM()) # not m - line.fromWkt('LineString (10 6, 20 6)') + line.fromWkt("LineString (10 6, 20 6)") self.assertIsNone(line.interpolateM()) # single point - line.fromWkt('LineStringM (10 6 0)') - self.assertEqual(line.interpolateM().asWkt(), 'LineString M (10 6 0)') + line.fromWkt("LineStringM (10 6 0)") + self.assertEqual(line.interpolateM().asWkt(), "LineString M (10 6 0)") # valid cases - line.fromWkt('LineStringM (10 6 0, 20 6 10)') - self.assertEqual(line.interpolateM().asWkt(), 'LineString M (10 6 0, 20 6 10)') + line.fromWkt("LineStringM (10 6 0, 20 6 10)") + self.assertEqual(line.interpolateM().asWkt(), "LineString M (10 6 0, 20 6 10)") - line.fromWkt('LineStringM (10 6 1, 20 6 0, 10 10 1)') - self.assertEqual(line.interpolateM().asWkt(), 'LineString M (10 6 1, 20 6 0, 10 10 1)') + line.fromWkt("LineStringM (10 6 1, 20 6 0, 10 10 1)") + self.assertEqual( + line.interpolateM().asWkt(), "LineString M (10 6 1, 20 6 0, 10 10 1)" + ) - line.fromWkt('LineStringZM (10 6 1 5, 20 6 0 6, 10 10 1 7)') - self.assertEqual(line.interpolateM().asWkt(), 'LineString ZM (10 6 1 5, 20 6 0 6, 10 10 1 7)') + line.fromWkt("LineStringZM (10 6 1 5, 20 6 0 6, 10 10 1 7)") + self.assertEqual( + line.interpolateM().asWkt(), "LineString ZM (10 6 1 5, 20 6 0 6, 10 10 1 7)" + ) # no valid m values line = QgsLineString([[10, 6, 1, math.nan], [20, 6, 2, math.nan]]) @@ -148,76 +176,229 @@ def testInterpolateM(self): # missing m values at start of line line = QgsLineString([[10, 6, 1, math.nan], [20, 6, 2, 13], [20, 10, 5, 17]]) - self.assertEqual(line.interpolateM().asWkt(), 'LineString ZM (10 6 1 13, 20 6 2 13, 20 10 5 17)') - - line = QgsLineString([[10, 6, 1, math.nan], [20, 6, 2, math.nan], [20, 10, 5, 17]]) - self.assertEqual(line.interpolateM().asWkt(), 'LineString ZM (10 6 1 17, 20 6 2 17, 20 10 5 17)') - - line = QgsLineString([[10, 6, 1, math.nan], [20, 6, 2, math.nan], [20, 10, 5, 17], [22, 10, 15, 19]]) - self.assertEqual(line.interpolateM().asWkt(), 'LineString ZM (10 6 1 17, 20 6 2 17, 20 10 5 17, 22 10 15 19)') + self.assertEqual( + line.interpolateM().asWkt(), + "LineString ZM (10 6 1 13, 20 6 2 13, 20 10 5 17)", + ) + + line = QgsLineString( + [[10, 6, 1, math.nan], [20, 6, 2, math.nan], [20, 10, 5, 17]] + ) + self.assertEqual( + line.interpolateM().asWkt(), + "LineString ZM (10 6 1 17, 20 6 2 17, 20 10 5 17)", + ) + + line = QgsLineString( + [ + [10, 6, 1, math.nan], + [20, 6, 2, math.nan], + [20, 10, 5, 17], + [22, 10, 15, 19], + ] + ) + self.assertEqual( + line.interpolateM().asWkt(), + "LineString ZM (10 6 1 17, 20 6 2 17, 20 10 5 17, 22 10 15 19)", + ) # missing m values at end of line line = QgsLineString([[20, 6, 2, 13], [20, 10, 5, 17], [10, 6, 1, math.nan]]) - self.assertEqual(line.interpolateM().asWkt(), 'LineString ZM (20 6 2 13, 20 10 5 17, 10 6 1 17)') - - line = QgsLineString([[20, 10, 5, 17], [10, 6, 1, math.nan], [20, 6, 2, math.nan]]) - self.assertEqual(line.interpolateM().asWkt(), 'LineString ZM (20 10 5 17, 10 6 1 17, 20 6 2 17)') - - line = QgsLineString([[20, 10, 5, 17], [22, 10, 15, 19], [10, 6, 1, math.nan], [20, 6, 2, math.nan]]) - self.assertEqual(line.interpolateM().asWkt(), 'LineString ZM (20 10 5 17, 22 10 15 19, 10 6 1 19, 20 6 2 19)') + self.assertEqual( + line.interpolateM().asWkt(), + "LineString ZM (20 6 2 13, 20 10 5 17, 10 6 1 17)", + ) + + line = QgsLineString( + [[20, 10, 5, 17], [10, 6, 1, math.nan], [20, 6, 2, math.nan]] + ) + self.assertEqual( + line.interpolateM().asWkt(), + "LineString ZM (20 10 5 17, 10 6 1 17, 20 6 2 17)", + ) + + line = QgsLineString( + [ + [20, 10, 5, 17], + [22, 10, 15, 19], + [10, 6, 1, math.nan], + [20, 6, 2, math.nan], + ] + ) + self.assertEqual( + line.interpolateM().asWkt(), + "LineString ZM (20 10 5 17, 22 10 15 19, 10 6 1 19, 20 6 2 19)", + ) # missing m values in middle of line - line = QgsLineString([[20, 10, 5, 17], [30, 10, 12, math.nan], [30, 40, 17, 27]]) + line = QgsLineString( + [[20, 10, 5, 17], [30, 10, 12, math.nan], [30, 40, 17, 27]] + ) # 2d distance - self.assertEqual(line.interpolateM(False).asWkt(), 'LineString ZM (20 10 5 17, 30 10 12 19.5, 30 40 17 27)') + self.assertEqual( + line.interpolateM(False).asWkt(), + "LineString ZM (20 10 5 17, 30 10 12 19.5, 30 40 17 27)", + ) # 3d distance - self.assertEqual(line.interpolateM(True).asWkt(2), 'LineString ZM (20 10 5 17, 30 10 12 19.86, 30 40 17 27)') - - line = QgsLineString([[20, 10, 5, 17], [30, 10, 12, math.nan], [30, 40, 17, math.nan], [20, 40, 19, 27]]) + self.assertEqual( + line.interpolateM(True).asWkt(2), + "LineString ZM (20 10 5 17, 30 10 12 19.86, 30 40 17 27)", + ) + + line = QgsLineString( + [ + [20, 10, 5, 17], + [30, 10, 12, math.nan], + [30, 40, 17, math.nan], + [20, 40, 19, 27], + ] + ) # 2d distance - self.assertEqual(line.interpolateM(False).asWkt(), 'LineString ZM (20 10 5 17, 30 10 12 19, 30 40 17 25, 20 40 19 27)') + self.assertEqual( + line.interpolateM(False).asWkt(), + "LineString ZM (20 10 5 17, 30 10 12 19, 30 40 17 25, 20 40 19 27)", + ) # 3d distance - self.assertEqual(line.interpolateM(True).asWkt(2), 'LineString ZM (20 10 5 17, 30 10 12 19.31, 30 40 17 25.07, 20 40 19 27)') - - line = QgsLineString([[20, 10, 5, 17], [30, 10, 12, math.nan], [30, 40, 17, math.nan], [20, 40, 19, math.nan], [20, 50, 21, 29]]) + self.assertEqual( + line.interpolateM(True).asWkt(2), + "LineString ZM (20 10 5 17, 30 10 12 19.31, 30 40 17 25.07, 20 40 19 27)", + ) + + line = QgsLineString( + [ + [20, 10, 5, 17], + [30, 10, 12, math.nan], + [30, 40, 17, math.nan], + [20, 40, 19, math.nan], + [20, 50, 21, 29], + ] + ) # 2d distance - self.assertEqual(line.interpolateM(False).asWkt(), 'LineString ZM (20 10 5 17, 30 10 12 19, 30 40 17 25, 20 40 19 27, 20 50 21 29)') + self.assertEqual( + line.interpolateM(False).asWkt(), + "LineString ZM (20 10 5 17, 30 10 12 19, 30 40 17 25, 20 40 19 27, 20 50 21 29)", + ) # 3d distance - self.assertEqual(line.interpolateM(True).asWkt(2), 'LineString ZM (20 10 5 17, 30 10 12 19.32, 30 40 17 25.12, 20 40 19 27.06, 20 50 21 29)') + self.assertEqual( + line.interpolateM(True).asWkt(2), + "LineString ZM (20 10 5 17, 30 10 12 19.32, 30 40 17 25.12, 20 40 19 27.06, 20 50 21 29)", + ) # multiple missing chunks - line = QgsLineString([[20, 10, 5, 17], [30, 10, 12, math.nan], [30, 40, 17, math.nan], [20, 40, 19, 27], [20, 50, 21, math.nan], [25, 50, 22, 30]]) + line = QgsLineString( + [ + [20, 10, 5, 17], + [30, 10, 12, math.nan], + [30, 40, 17, math.nan], + [20, 40, 19, 27], + [20, 50, 21, math.nan], + [25, 50, 22, 30], + ] + ) # 2d distance - self.assertEqual(line.interpolateM(False).asWkt(), 'LineString ZM (20 10 5 17, 30 10 12 19, 30 40 17 25, 20 40 19 27, 20 50 21 29, 25 50 22 30)') + self.assertEqual( + line.interpolateM(False).asWkt(), + "LineString ZM (20 10 5 17, 30 10 12 19, 30 40 17 25, 20 40 19 27, 20 50 21 29, 25 50 22 30)", + ) # 3d distance - self.assertEqual(line.interpolateM(True).asWkt(2), 'LineString ZM (20 10 5 17, 30 10 12 19.31, 30 40 17 25.07, 20 40 19 27, 20 50 21 29, 25 50 22 30)') - - line = QgsLineString([[20, 10, 5, 17], [30, 10, 12, math.nan], [30, 40, 17, math.nan], [20, 40, 19, 27], [20, 50, 21, math.nan], [25, 50, 22, math.nan], [25, 55, 22, math.nan], [30, 55, 22, 37]]) + self.assertEqual( + line.interpolateM(True).asWkt(2), + "LineString ZM (20 10 5 17, 30 10 12 19.31, 30 40 17 25.07, 20 40 19 27, 20 50 21 29, 25 50 22 30)", + ) + + line = QgsLineString( + [ + [20, 10, 5, 17], + [30, 10, 12, math.nan], + [30, 40, 17, math.nan], + [20, 40, 19, 27], + [20, 50, 21, math.nan], + [25, 50, 22, math.nan], + [25, 55, 22, math.nan], + [30, 55, 22, 37], + ] + ) # 2d distance - self.assertEqual(line.interpolateM(False).asWkt(), 'LineString ZM (20 10 5 17, 30 10 12 19, 30 40 17 25, 20 40 19 27, 20 50 21 31, 25 50 22 33, 25 55 22 35, 30 55 22 37)') + self.assertEqual( + line.interpolateM(False).asWkt(), + "LineString ZM (20 10 5 17, 30 10 12 19, 30 40 17 25, 20 40 19 27, 20 50 21 31, 25 50 22 33, 25 55 22 35, 30 55 22 37)", + ) # 3d distance - self.assertEqual(line.interpolateM(True).asWkt(2), 'LineString ZM (20 10 5 17, 30 10 12 19.31, 30 40 17 25.07, 20 40 19 27, 20 50 21 31.03, 25 50 22 33.05, 25 55 22 35.02, 30 55 22 37)') + self.assertEqual( + line.interpolateM(True).asWkt(2), + "LineString ZM (20 10 5 17, 30 10 12 19.31, 30 40 17 25.07, 20 40 19 27, 20 50 21 31.03, 25 50 22 33.05, 25 55 22 35.02, 30 55 22 37)", + ) # missing at start and middle - line = QgsLineString([[10, 10, 1, math.nan], [10, 12, 2, math.nan], [20, 10, 5, 17], [30, 10, 12, math.nan], [30, 40, 17, math.nan], [20, 40, 19, math.nan], [20, 50, 21, 29]]) + line = QgsLineString( + [ + [10, 10, 1, math.nan], + [10, 12, 2, math.nan], + [20, 10, 5, 17], + [30, 10, 12, math.nan], + [30, 40, 17, math.nan], + [20, 40, 19, math.nan], + [20, 50, 21, 29], + ] + ) # 2d distance - self.assertEqual(line.interpolateM(False).asWkt(), 'LineString ZM (10 10 1 17, 10 12 2 17, 20 10 5 17, 30 10 12 19, 30 40 17 25, 20 40 19 27, 20 50 21 29)') + self.assertEqual( + line.interpolateM(False).asWkt(), + "LineString ZM (10 10 1 17, 10 12 2 17, 20 10 5 17, 30 10 12 19, 30 40 17 25, 20 40 19 27, 20 50 21 29)", + ) # 3d distance - self.assertEqual(line.interpolateM(True).asWkt(2), 'LineString ZM (10 10 1 17, 10 12 2 17, 20 10 5 17, 30 10 12 19.72, 30 40 17 25.27, 20 40 19 27.14, 20 50 21 29)') + self.assertEqual( + line.interpolateM(True).asWkt(2), + "LineString ZM (10 10 1 17, 10 12 2 17, 20 10 5 17, 30 10 12 19.72, 30 40 17 25.27, 20 40 19 27.14, 20 50 21 29)", + ) # missing at middle and end - line = QgsLineString([[20, 10, 5, 17], [30, 10, 12, math.nan], [30, 40, 17, math.nan], [20, 40, 19, 27], [20, 50, 21, math.nan], [25, 50, 22, math.nan], [25, 55, 22, math.nan]]) + line = QgsLineString( + [ + [20, 10, 5, 17], + [30, 10, 12, math.nan], + [30, 40, 17, math.nan], + [20, 40, 19, 27], + [20, 50, 21, math.nan], + [25, 50, 22, math.nan], + [25, 55, 22, math.nan], + ] + ) # 2d distance - self.assertEqual(line.interpolateM(False).asWkt(), 'LineString ZM (20 10 5 17, 30 10 12 19, 30 40 17 25, 20 40 19 27, 20 50 21 27, 25 50 22 27, 25 55 22 27)') + self.assertEqual( + line.interpolateM(False).asWkt(), + "LineString ZM (20 10 5 17, 30 10 12 19, 30 40 17 25, 20 40 19 27, 20 50 21 27, 25 50 22 27, 25 55 22 27)", + ) # 3d distance - self.assertEqual(line.interpolateM(True).asWkt(2), 'LineString ZM (20 10 5 17, 30 10 12 19.31, 30 40 17 25.07, 20 40 19 27, 20 50 21 27, 25 50 22 27, 25 55 22 27)') + self.assertEqual( + line.interpolateM(True).asWkt(2), + "LineString ZM (20 10 5 17, 30 10 12 19.31, 30 40 17 25.07, 20 40 19 27, 20 50 21 27, 25 50 22 27, 25 55 22 27)", + ) # missing at start, middle, end - line = QgsLineString([[5, 10, 15, math.nan], [6, 11, 16, math.nan], [20, 10, 5, 17], [30, 10, 12, math.nan], [30, 40, 17, math.nan], [20, 40, 19, 27], [20, 50, 21, math.nan], [25, 50, 22, math.nan], [25, 55, 22, math.nan]]) + line = QgsLineString( + [ + [5, 10, 15, math.nan], + [6, 11, 16, math.nan], + [20, 10, 5, 17], + [30, 10, 12, math.nan], + [30, 40, 17, math.nan], + [20, 40, 19, 27], + [20, 50, 21, math.nan], + [25, 50, 22, math.nan], + [25, 55, 22, math.nan], + ] + ) # 2d distance - self.assertEqual(line.interpolateM(False).asWkt(), 'LineString ZM (5 10 15 17, 6 11 16 17, 20 10 5 17, 30 10 12 19, 30 40 17 25, 20 40 19 27, 20 50 21 27, 25 50 22 27, 25 55 22 27)') + self.assertEqual( + line.interpolateM(False).asWkt(), + "LineString ZM (5 10 15 17, 6 11 16 17, 20 10 5 17, 30 10 12 19, 30 40 17 25, 20 40 19 27, 20 50 21 27, 25 50 22 27, 25 55 22 27)", + ) # 3d distance - self.assertEqual(line.interpolateM(True).asWkt(2), 'LineString ZM (5 10 15 17, 6 11 16 17, 20 10 5 17, 30 10 12 19.05, 30 40 17 25, 20 40 19 27, 20 50 21 27, 25 50 22 27, 25 55 22 27)') + self.assertEqual( + line.interpolateM(True).asWkt(2), + "LineString ZM (5 10 15 17, 6 11 16 17, 20 10 5 17, 30 10 12 19.05, 30 40 17 25, 20 40 19 27, 20 50 21 27, 25 50 22 27, 25 55 22 27)", + ) def testLineLocatePointByM(self): line = QgsLineString() @@ -226,17 +407,17 @@ def testLineLocatePointByM(self): self.assertFalse(res) # not m - line.fromWkt('LineString (10 6, 20 6)') + line.fromWkt("LineString (10 6, 20 6)") res, x, y, z, distance = line.lineLocatePointByM(5) self.assertFalse(res) # single point - line.fromWkt('LineStringM (10 6 0)') + line.fromWkt("LineStringM (10 6 0)") res, x, y, z, distance = line.lineLocatePointByM(5) self.assertFalse(res) # valid cases - line.fromWkt('LineStringM (10 6 0, 20 6 10)') + line.fromWkt("LineStringM (10 6 0, 20 6 10)") res, x, y, z, distance = line.lineLocatePointByM(0) self.assertTrue(res) self.assertEqual(x, 10) @@ -267,7 +448,7 @@ def testLineLocatePointByM(self): res, x, y, z, distance = line.lineLocatePointByM(-5) self.assertFalse(res) - line.fromWkt('LineStringM (10 6 1, 20 6 0)') + line.fromWkt("LineStringM (10 6 1, 20 6 0)") res, x, y, z, distance = line.lineLocatePointByM(1.0) self.assertTrue(res) self.assertEqual(x, 10) @@ -280,19 +461,19 @@ def testLineLocatePointByM(self): self.assertEqual(y, 6) self.assertEqual(distance, 10) - res, x, y, z, distance = line.lineLocatePointByM(.5) + res, x, y, z, distance = line.lineLocatePointByM(0.5) self.assertTrue(res) self.assertEqual(x, 15) self.assertEqual(y, 6) self.assertEqual(distance, 5) - res, x, y, z, distance = line.lineLocatePointByM(.3) + res, x, y, z, distance = line.lineLocatePointByM(0.3) self.assertTrue(res) self.assertEqual(x, 17) self.assertEqual(y, 6) self.assertEqual(distance, 7) - line.fromWkt('LineStringM (10 6 10, 20 6 0, 20 16 -10)') + line.fromWkt("LineStringM (10 6 10, 20 6 0, 20 16 -10)") res, x, y, z, distance = line.lineLocatePointByM(5) self.assertTrue(res) self.assertEqual(x, 15) @@ -338,7 +519,7 @@ def testLineLocatePointByM(self): self.assertEqual(distance, 20) # with nan m value to fill in - line.fromWkt('LineStringM (10 6 10, 20 6 0, 20 16 -10, 30 16 -10)') + line.fromWkt("LineStringM (10 6 10, 20 6 0, 20 16 -10, 30 16 -10)") line.setMAt(1, math.nan) line.setMAt(2, math.nan) res, x, y, z, distance = line.lineLocatePointByM(5) @@ -354,14 +535,14 @@ def testLineLocatePointByM(self): self.assertEqual(distance, 15) # m value on constant m segment - line.fromWkt('LineStringM (10 6 10, 20 6 1, 20 16 1, 30 16 -10)') + line.fromWkt("LineStringM (10 6 10, 20 6 1, 20 16 1, 30 16 -10)") res, x, y, z, distance = line.lineLocatePointByM(1) self.assertTrue(res) self.assertEqual(x, 20) self.assertEqual(y, 11) self.assertAlmostEqual(distance, 15, 3) - line.fromWkt('LineStringM (10 6 10, 20 6 1, 20 16 1, 26 16 1)') + line.fromWkt("LineStringM (10 6 10, 20 6 1, 20 16 1, 26 16 1)") res, x, y, z, distance = line.lineLocatePointByM(1) self.assertTrue(res) self.assertEqual(x, 20) @@ -374,37 +555,45 @@ def test_simplify_by_distance(self): """ p = QgsLineString() # should never become < 2 vertices - p.fromWkt('LineString(1 1, 1.001 1.001)') - self.assertEqual(p.simplifyByDistance(0.5).asWkt(3), 'LineString (1 1, 1.001 1.001)') - p.fromWkt('LineString (4.40700000000000003 0.93600000000000005, 3.76500000000000012 8.90499999999999936, 5.87999999999999989 16.61499999999999844, 10.21700000000000053 22.85500000000000043, 16.70599999999999952 27.52499999999999858, 26.00300000000000011 29.80799999999999983, 34.67600000000000193 28.41000000000000014, 46.06099999999999994 30.38700000000000045, 61.74099999999999966 29.02400000000000091)') - self.assertEqual(p.simplifyByDistance(0.75).asWkt(3), - 'LineString (4.407 0.936, 3.765 8.905, 5.88 16.615, 10.217 22.855, 16.706 27.525, 26.003 29.808, 34.676 28.41, 46.061 30.387, 61.741 29.024)') - self.assertEqual(p.simplifyByDistance(2).asWkt(3), - 'LineString (4.407 0.936, 5.88 16.615, 16.706 27.525, 61.741 29.024)') + p.fromWkt("LineString(1 1, 1.001 1.001)") + self.assertEqual( + p.simplifyByDistance(0.5).asWkt(3), "LineString (1 1, 1.001 1.001)" + ) + p.fromWkt( + "LineString (4.40700000000000003 0.93600000000000005, 3.76500000000000012 8.90499999999999936, 5.87999999999999989 16.61499999999999844, 10.21700000000000053 22.85500000000000043, 16.70599999999999952 27.52499999999999858, 26.00300000000000011 29.80799999999999983, 34.67600000000000193 28.41000000000000014, 46.06099999999999994 30.38700000000000045, 61.74099999999999966 29.02400000000000091)" + ) + self.assertEqual( + p.simplifyByDistance(0.75).asWkt(3), + "LineString (4.407 0.936, 3.765 8.905, 5.88 16.615, 10.217 22.855, 16.706 27.525, 26.003 29.808, 34.676 28.41, 46.061 30.387, 61.741 29.024)", + ) + self.assertEqual( + p.simplifyByDistance(2).asWkt(3), + "LineString (4.407 0.936, 5.88 16.615, 16.706 27.525, 61.741 29.024)", + ) # ported geos tests - p.fromWkt('LINESTRING (0 5, 1 5, 2 5, 5 5)') - self.assertEqual(p.simplifyByDistance(10).asWkt(), - 'LineString (0 5, 5 5)') - p.fromWkt('LINESTRING (1 0, 2 0, 2 2, 0 2, 0 0, 1 0)') - self.assertEqual(p.simplifyByDistance(0).asWkt(), - 'LineString (2 0, 2 2, 0 2, 0 0, 2 0)') + p.fromWkt("LINESTRING (0 5, 1 5, 2 5, 5 5)") + self.assertEqual(p.simplifyByDistance(10).asWkt(), "LineString (0 5, 5 5)") + p.fromWkt("LINESTRING (1 0, 2 0, 2 2, 0 2, 0 0, 1 0)") + self.assertEqual( + p.simplifyByDistance(0).asWkt(), "LineString (2 0, 2 2, 0 2, 0 0, 2 0)" + ) def test_orientation(self): """ test orientation. From https://github.com/qgis/QGIS/issues/58333 """ geom = QgsLineString() - geom.fromWkt('LineString (1 1, 2 1, 2 2, 1 2, 1 1)') + geom.fromWkt("LineString (1 1, 2 1, 2 2, 1 2, 1 1)") self.assertEqual(geom.sumUpArea(), 1.0) self.assertEqual(geom.orientation(), Qgis.AngularDirection.CounterClockwise) - geom.fromWkt('LineString (1 1, 1 2, 2 2, 2 1, 1 1)') + geom.fromWkt("LineString (1 1, 1 2, 2 2, 2 1, 1 1)") self.assertEqual(geom.sumUpArea(), -1.0) self.assertEqual(geom.orientation(), Qgis.AngularDirection.Clockwise) geom = geom.reversed() - self.assertEqual(geom.asWkt(), 'LineString (1 1, 2 1, 2 2, 1 2, 1 1)') + self.assertEqual(geom.asWkt(), "LineString (1 1, 2 1, 2 2, 1 2, 1 1)") self.assertEqual(geom.sumUpArea(), 1.0) self.assertEqual(geom.orientation(), Qgis.AngularDirection.CounterClockwise) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslinesymbollayers.py b/tests/src/python/test_qgslinesymbollayers.py index 1decec67e69e..0090f85e967e 100644 --- a/tests/src/python/test_qgslinesymbollayers.py +++ b/tests/src/python/test_qgslinesymbollayers.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2017-01' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2017-01" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtGui import QColor, QImage, QPainter from qgis.core import ( @@ -34,7 +35,7 @@ def control_path_prefix(cls): return "symbol_layer" def testSimpleLineWithOffset(self): - """ test that rendering a simple line symbol with offset""" + """test that rendering a simple line symbol with offset""" layer = QgsSimpleLineSymbolLayer(QColor(0, 0, 0)) layer.setOffset(1) @@ -45,7 +46,7 @@ def testSimpleLineWithOffset(self): painter = QPainter() ms = QgsMapSettings() - geom = QgsGeometry.fromWkt('LineString (0 0, 10 0, 10 10, 0 10, 0 0)') + geom = QgsGeometry.fromWkt("LineString (0 0, 10 0, 10 10, 0 10, 0 0)") f = QgsFeature() f.setGeometry(geom) @@ -69,16 +70,16 @@ def testSimpleLineWithOffset(self): self.assertTrue( self.image_check( - 'symbol_layer', - 'simpleline_offset', + "symbol_layer", + "simpleline_offset", image, color_tolerance=2, - allowed_mismatch=0 + allowed_mismatch=0, ) ) def testSimpleLineWithCustomDashPattern(self): - """ test that rendering a simple line symbol with custom dash pattern""" + """test that rendering a simple line symbol with custom dash pattern""" layer = QgsSimpleLineSymbolLayer(QColor(0, 0, 0)) layer.setWidth(0.5) layer.setCustomDashVector([2, 5]) @@ -91,7 +92,7 @@ def testSimpleLineWithCustomDashPattern(self): painter = QPainter() ms = QgsMapSettings() - geom = QgsGeometry.fromWkt('LineString (0 0, 10 0, 10 10, 0 10, 0 0)') + geom = QgsGeometry.fromWkt("LineString (0 0, 10 0, 10 10, 0 10, 0 0)") f = QgsFeature() f.setGeometry(geom) @@ -115,16 +116,16 @@ def testSimpleLineWithCustomDashPattern(self): self.assertTrue( self.image_check( - 'simpleline_customdashpattern', - 'simpleline_customdashpattern', + "simpleline_customdashpattern", + "simpleline_customdashpattern", image, color_tolerance=2, - allowed_mismatch=0 + allowed_mismatch=0, ) ) def testSimpleLineWithCustomDashPatternHairline(self): - """ test that rendering a simple line symbol with custom dash pattern""" + """test that rendering a simple line symbol with custom dash pattern""" layer = QgsSimpleLineSymbolLayer(QColor(0, 0, 0)) layer.setWidth(0) layer.setCustomDashVector([3, 3, 2, 2]) @@ -137,7 +138,7 @@ def testSimpleLineWithCustomDashPatternHairline(self): painter = QPainter() ms = QgsMapSettings() - geom = QgsGeometry.fromWkt('LineString (0 0, 10 0, 10 10, 0 10, 0 0)') + geom = QgsGeometry.fromWkt("LineString (0 0, 10 0, 10 10, 0 10, 0 0)") f = QgsFeature() f.setGeometry(geom) @@ -161,14 +162,14 @@ def testSimpleLineWithCustomDashPatternHairline(self): self.assertTrue( self.image_check( - 'simpleline_customdashpattern_hairline', - 'simpleline_customdashpattern_hairline', + "simpleline_customdashpattern_hairline", + "simpleline_customdashpattern_hairline", image, color_tolerance=2, - allowed_mismatch=0 + allowed_mismatch=0, ) ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslocaldefaultsettings.py b/tests/src/python/test_qgslocaldefaultsettings.py index f1fad2806bf0..bc35fa09bcbf 100644 --- a/tests/src/python/test_qgslocaldefaultsettings.py +++ b/tests/src/python/test_qgslocaldefaultsettings.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '09/01/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "09/01/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication from qgis.core import ( @@ -42,45 +43,71 @@ def testBearingFormat(self): format = QgsBearingNumericFormat() format.setNumberDecimalPlaces(9) - format.setDirectionFormat(QgsBearingNumericFormat.FormatDirectionOption.UseRange0To360) + format.setDirectionFormat( + QgsBearingNumericFormat.FormatDirectionOption.UseRange0To360 + ) s.setBearingFormat(format) self.assertEqual(s.bearingFormat().numberDecimalPlaces(), 9) - self.assertEqual(s.bearingFormat().directionFormat(), QgsBearingNumericFormat.FormatDirectionOption.UseRange0To360) + self.assertEqual( + s.bearingFormat().directionFormat(), + QgsBearingNumericFormat.FormatDirectionOption.UseRange0To360, + ) format = QgsBearingNumericFormat() format.setNumberDecimalPlaces(3) - format.setDirectionFormat(QgsBearingNumericFormat.FormatDirectionOption.UseRangeNegative180ToPositive180) + format.setDirectionFormat( + QgsBearingNumericFormat.FormatDirectionOption.UseRangeNegative180ToPositive180 + ) s.setBearingFormat(format) self.assertEqual(s.bearingFormat().numberDecimalPlaces(), 3) - self.assertEqual(s.bearingFormat().directionFormat(), QgsBearingNumericFormat.FormatDirectionOption.UseRangeNegative180ToPositive180) + self.assertEqual( + s.bearingFormat().directionFormat(), + QgsBearingNumericFormat.FormatDirectionOption.UseRangeNegative180ToPositive180, + ) # new settings object, should persist. s2 = QgsLocalDefaultSettings() self.assertEqual(s2.bearingFormat().numberDecimalPlaces(), 3) - self.assertEqual(s2.bearingFormat().directionFormat(), QgsBearingNumericFormat.FormatDirectionOption.UseRangeNegative180ToPositive180) + self.assertEqual( + s2.bearingFormat().directionFormat(), + QgsBearingNumericFormat.FormatDirectionOption.UseRangeNegative180ToPositive180, + ) def testGeographicCoordinateFormat(self): s = QgsLocalDefaultSettings() format = QgsGeographicCoordinateNumericFormat() - format.setAngleFormat(QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutes) + format.setAngleFormat( + QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutes + ) s.setGeographicCoordinateFormat(format) - self.assertEqual(s.geographicCoordinateFormat().angleFormat(), QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutes) + self.assertEqual( + s.geographicCoordinateFormat().angleFormat(), + QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutes, + ) format = QgsGeographicCoordinateNumericFormat() format.setNumberDecimalPlaces(3) - format.setAngleFormat(QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds) + format.setAngleFormat( + QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds + ) s.setGeographicCoordinateFormat(format) self.assertEqual(s.geographicCoordinateFormat().numberDecimalPlaces(), 3) - self.assertEqual(s.geographicCoordinateFormat().angleFormat(), QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds) + self.assertEqual( + s.geographicCoordinateFormat().angleFormat(), + QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds, + ) # new settings object, should persist. s2 = QgsLocalDefaultSettings() self.assertEqual(s2.geographicCoordinateFormat().numberDecimalPlaces(), 3) - self.assertEqual(s2.geographicCoordinateFormat().angleFormat(), QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds) + self.assertEqual( + s2.geographicCoordinateFormat().angleFormat(), + QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds, + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslocalizeddatapathregistry.py b/tests/src/python/test_qgslocalizeddatapathregistry.py index d9e05990d9d0..da9a06dfc328 100644 --- a/tests/src/python/test_qgslocalizeddatapathregistry.py +++ b/tests/src/python/test_qgslocalizeddatapathregistry.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Denis Rouzaud' -__date__ = '13/05/2020' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Denis Rouzaud" +__date__ = "13/05/2020" +__copyright__ = "Copyright 2019, The QGIS Project" import os import shutil @@ -28,8 +29,8 @@ start_app() MAP_PATH = "data/world_map.gpkg" -BASE_PATH = QgsApplication.pkgDataPath() + '/resources' -ABSOLUTE_PATH = f'{BASE_PATH}/{MAP_PATH}' +BASE_PATH = QgsApplication.pkgDataPath() + "/resources" +ABSOLUTE_PATH = f"{BASE_PATH}/{MAP_PATH}" class TestQgsLocalizedDataPathRegistry(QgisTestCase): @@ -54,23 +55,38 @@ def tearDown(self): QgsApplication.localizedDataPathRegistry().unregisterPath(BASE_PATH) def testQgsLocalizedDataPathRegistry(self): - self.assertEqual(QgsApplication.localizedDataPathRegistry().localizedPath(ABSOLUTE_PATH), MAP_PATH) - self.assertEqual(QgsApplication.localizedDataPathRegistry().globalPath(MAP_PATH), ABSOLUTE_PATH) + self.assertEqual( + QgsApplication.localizedDataPathRegistry().localizedPath(ABSOLUTE_PATH), + MAP_PATH, + ) + self.assertEqual( + QgsApplication.localizedDataPathRegistry().globalPath(MAP_PATH), + ABSOLUTE_PATH, + ) def testOrderOfPreference(self): - os.mkdir(f'{self.temp_path}/data') - alt_dir = f'{self.temp_path}/{MAP_PATH}' + os.mkdir(f"{self.temp_path}/data") + alt_dir = f"{self.temp_path}/{MAP_PATH}" Path(alt_dir).touch() QgsApplication.localizedDataPathRegistry().registerPath(self.temp_path, 0) - self.assertEqual(QDir.toNativeSeparators(QgsApplication.localizedDataPathRegistry().globalPath(MAP_PATH)), QDir.toNativeSeparators(alt_dir)) + self.assertEqual( + QDir.toNativeSeparators( + QgsApplication.localizedDataPathRegistry().globalPath(MAP_PATH) + ), + QDir.toNativeSeparators(alt_dir), + ) QgsApplication.localizedDataPathRegistry().unregisterPath(self.temp_path) def testWithResolver(self): - self.assertEqual(QgsPathResolver().readPath('localized:' + MAP_PATH), ABSOLUTE_PATH) - self.assertEqual(QgsPathResolver().writePath(ABSOLUTE_PATH), 'localized:' + MAP_PATH) + self.assertEqual( + QgsPathResolver().readPath("localized:" + MAP_PATH), ABSOLUTE_PATH + ) + self.assertEqual( + QgsPathResolver().writePath(ABSOLUTE_PATH), "localized:" + MAP_PATH + ) def testProject(self): - layer = QgsVectorLayer(f'{ABSOLUTE_PATH}|layername=countries', 'Test', 'ogr') + layer = QgsVectorLayer(f"{ABSOLUTE_PATH}|layername=countries", "Test", "ogr") # write p = QgsProject() @@ -81,7 +97,10 @@ def testProject(self): found = False with open(fh.name) as fh: for line in fh: - if 'localized:data/world_map.gpkg|layername=countries' in line: + if ( + "localized:data/world_map.gpkg|layername=countries" + in line + ): found = True break self.assertTrue(found) @@ -91,10 +110,13 @@ def testProject(self): p2.setFileName(fh.name) p2.read() self.assertTrue(len(p2.mapLayers())) - self.assertEqual(p2.mapLayers()[layer.id()].source(), f'{BASE_PATH}/{MAP_PATH}|layername=countries') + self.assertEqual( + p2.mapLayers()[layer.id()].source(), + f"{BASE_PATH}/{MAP_PATH}|layername=countries", + ) os.remove(fh.name) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslocator.py b/tests/src/python/test_qgslocator.py index 6fc6b2d7993d..c838aebc0ae9 100644 --- a/tests/src/python/test_qgslocator.py +++ b/tests/src/python/test_qgslocator.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2017 by Nyall Dawson' -__date__ = '6/05/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "(C) 2017 by Nyall Dawson" +__date__ = "6/05/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from time import sleep @@ -31,7 +32,9 @@ class test_filter(QgsLocatorFilter): - def __init__(self, identifier, prefix=None, groupResult=False, groupScore=False, parent=None): + def __init__( + self, identifier, prefix=None, groupResult=False, groupScore=False, parent=None + ): super().__init__(parent) self.identifier = identifier self._prefix = prefix @@ -39,16 +42,21 @@ def __init__(self, identifier, prefix=None, groupResult=False, groupScore=False, self.groupScore = groupScore def clone(self): - return test_filter(self.identifier, prefix=self.prefix, groupResult=self.groupResult, groupScore=self.groupScore) + return test_filter( + self.identifier, + prefix=self.prefix, + groupResult=self.groupResult, + groupScore=self.groupScore, + ) def name(self): - return 'test_' + self.identifier + return "test_" + self.identifier def displayName(self): - return 'test_' + self.identifier + return "test_" + self.identifier def description(self): - return 'test_description' + return "test_description" def prefix(self): return self._prefix @@ -63,11 +71,11 @@ def fetchResults(self, string, context, feedback): result.displayString = self.identifier + str(i) if self.groupResult: if i in (0, 1, 3, 5, 6): - result.group = 'group a' + result.group = "group a" if self.groupScore: result.groupScore = 1 elif i in (4, 8): - result.group = 'group b' + result.group = "group b" if self.groupScore: result.groupScore = 10 self.resultFetched.emit(result) @@ -76,11 +84,11 @@ def triggerResult(self, result): pass def priority(self): - if self.identifier == 'a': + if self.identifier == "a": return QgsLocatorFilter.Priority.High - elif self.identifier == 'b': + elif self.identifier == "b": return QgsLocatorFilter.Priority.Medium - elif self.identifier == 'c': + elif self.identifier == "c": return QgsLocatorFilter.Priority.Low else: return QgsLocatorFilter.Priority.Medium @@ -90,8 +98,8 @@ class TestQgsLocator(QgisTestCase): def testRegisteringFilters(self): l = QgsLocator() - filter_a = test_filter('a') - filter_b = test_filter('b') + filter_a = test_filter("a") + filter_b = test_filter("b") l.registerFilter(filter_a) l.registerFilter(filter_b) @@ -104,8 +112,8 @@ def testRegisteringFilters(self): # try manually deregistering l = QgsLocator() - filter_c = test_filter('c') - filter_d = test_filter('d') + filter_c = test_filter("c") + filter_d = test_filter("d") l.registerFilter(filter_c) l.registerFilter(filter_d) self.assertEqual(set(l.filters()), {filter_c, filter_d}) @@ -129,30 +137,30 @@ def got_hit(result): # one filter l = QgsLocator() - filter_a = test_filter('a') + filter_a = test_filter("a") l.registerFilter(filter_a) l.foundResult.connect(got_hit) - l.fetchResults('a', context) + l.fetchResults("a", context) for i in range(100): sleep(0.002) QCoreApplication.processEvents() - self.assertEqual(set(got_hit._results_), {'a0', 'a1', 'a2'}) + self.assertEqual(set(got_hit._results_), {"a0", "a1", "a2"}) # two filters - filter_b = test_filter('b') + filter_b = test_filter("b") l.registerFilter(filter_b) got_hit._results_ = [] - l.fetchResults('a', context) + l.fetchResults("a", context) for i in range(100): sleep(0.002) QCoreApplication.processEvents() - self.assertEqual(set(got_hit._results_), {'a0', 'a1', 'a2', 'b0', 'b1', 'b2'}) + self.assertEqual(set(got_hit._results_), {"a0", "a1", "a2", "b0", "b1", "b2"}) def testFetchingResultsDelayed(self): @@ -165,31 +173,31 @@ def got_hit(result): # one filter l = QgsLocator() - filter_a = test_filter('a') + filter_a = test_filter("a") filter_a.setFetchResultsDelay(100) l.registerFilter(filter_a) l.foundResult.connect(got_hit) - l.fetchResults('a', context) + l.fetchResults("a", context) for i in range(500): sleep(0.002) QCoreApplication.processEvents() - self.assertEqual(set(got_hit._results_), {'a0', 'a1', 'a2'}) + self.assertEqual(set(got_hit._results_), {"a0", "a1", "a2"}) # two filters - filter_b = test_filter('b') + filter_b = test_filter("b") l.registerFilter(filter_b) got_hit._results_ = [] - l.fetchResults('a', context) + l.fetchResults("a", context) for i in range(500): sleep(0.002) QCoreApplication.processEvents() - self.assertEqual(set(got_hit._results_), {'a0', 'a1', 'a2', 'b0', 'b1', 'b2'}) + self.assertEqual(set(got_hit._results_), {"a0", "a1", "a2", "b0", "b1", "b2"}) def testDeleteWhileFetchingResults(self): """ @@ -204,11 +212,11 @@ def got_hit(result): context = QgsLocatorContext() l = QgsLocator() - filter_a = test_filter('a') + filter_a = test_filter("a") l.registerFilter(filter_a) l.foundResult.connect(got_hit) - l.fetchResults('a', context) + l.fetchResults("a", context) del l def testCancelWhileFetchingResults(self): @@ -224,11 +232,11 @@ def got_hit(result): context = QgsLocatorContext() l = QgsLocator() - filter_a = test_filter('a') + filter_a = test_filter("a") l.registerFilter(filter_a) l.foundResult.connect(got_hit) - l.fetchResults('a', context) + l.fetchResults("a", context) l.cancel() def testPrefixes(self): @@ -246,96 +254,96 @@ def got_hit(result): l = QgsLocator() # filter with prefix - filter_a = test_filter('a', 'aaa') + filter_a = test_filter("a", "aaa") l.registerFilter(filter_a) - self.assertEqual(filter_a.prefix(), 'aaa') - self.assertEqual(filter_a.activePrefix(), 'aaa') + self.assertEqual(filter_a.prefix(), "aaa") + self.assertEqual(filter_a.activePrefix(), "aaa") self.assertEqual(filter_a.useWithoutPrefix(), True) l.foundResult.connect(got_hit) - l.fetchResults('aaa a', context) + l.fetchResults("aaa a", context) for i in range(100): sleep(0.002) QCoreApplication.processEvents() - self.assertEqual(set(got_hit._results_), {'a0', 'a1', 'a2'}) + self.assertEqual(set(got_hit._results_), {"a0", "a1", "a2"}) got_hit._results_ = [] - l.fetchResults('bbb b', context) + l.fetchResults("bbb b", context) for i in range(100): sleep(0.002) QCoreApplication.processEvents() - self.assertEqual(set(got_hit._results_), {'a0', 'a1', 'a2'}) + self.assertEqual(set(got_hit._results_), {"a0", "a1", "a2"}) got_hit._results_ = [] filter_a.setUseWithoutPrefix(False) self.assertEqual(filter_a.useWithoutPrefix(), False) - l.fetchResults('bbb b', context) + l.fetchResults("bbb b", context) for i in range(100): sleep(0.002) QCoreApplication.processEvents() self.assertEqual(got_hit._results_, []) got_hit._results_ = [] - l.fetchResults('AaA a', context) + l.fetchResults("AaA a", context) for i in range(100): sleep(0.002) QCoreApplication.processEvents() - self.assertEqual(set(got_hit._results_), {'a0', 'a1', 'a2'}) + self.assertEqual(set(got_hit._results_), {"a0", "a1", "a2"}) # test with two filters - filter_b = test_filter('b', 'bbb') + filter_b = test_filter("b", "bbb") l.registerFilter(filter_b) - self.assertEqual(filter_b.prefix(), 'bbb') - self.assertEqual(filter_b.activePrefix(), 'bbb') + self.assertEqual(filter_b.prefix(), "bbb") + self.assertEqual(filter_b.activePrefix(), "bbb") got_hit._results_ = [] - l.fetchResults('bbb b', context) + l.fetchResults("bbb b", context) for i in range(100): sleep(0.002) QCoreApplication.processEvents() - self.assertEqual(set(got_hit._results_), {'b0', 'b1', 'b2'}) + self.assertEqual(set(got_hit._results_), {"b0", "b1", "b2"}) l.deregisterFilter(filter_b) # test with two filters with same prefix - filter_b = test_filter('b', 'aaa') + filter_b = test_filter("b", "aaa") l.registerFilter(filter_b) - self.assertEqual(filter_b.prefix(), 'aaa') - self.assertEqual(filter_b.activePrefix(), 'aaa') + self.assertEqual(filter_b.prefix(), "aaa") + self.assertEqual(filter_b.activePrefix(), "aaa") got_hit._results_ = [] - l.fetchResults('aaa b', context) + l.fetchResults("aaa b", context) for i in range(100): sleep(0.002) QCoreApplication.processEvents() - self.assertEqual(set(got_hit._results_), {'a0', 'a1', 'a2', 'b0', 'b1', 'b2'}) + self.assertEqual(set(got_hit._results_), {"a0", "a1", "a2", "b0", "b1", "b2"}) l.deregisterFilter(filter_b) # filter with invalid prefix (less than 3 char) - filter_c = test_filter('c', 'bb') + filter_c = test_filter("c", "bb") l.registerFilter(filter_c) - self.assertEqual(filter_c.prefix(), 'bb') - self.assertEqual(filter_c.activePrefix(), '') + self.assertEqual(filter_c.prefix(), "bb") + self.assertEqual(filter_c.activePrefix(), "") got_hit._results_ = [] - l.fetchResults('b', context) + l.fetchResults("b", context) for i in range(100): sleep(0.002) QCoreApplication.processEvents() - self.assertEqual(set(got_hit._results_), {'c0', 'c1', 'c2'}) + self.assertEqual(set(got_hit._results_), {"c0", "c1", "c2"}) l.deregisterFilter(filter_c) # filter with custom prefix - QgsSettings().setValue("locator-filters/items/test_custom/prefix", 'xyz') - filter_c = test_filter('custom', 'abc') + QgsSettings().setValue("locator-filters/items/test_custom/prefix", "xyz") + filter_c = test_filter("custom", "abc") l.registerFilter(filter_c) - self.assertEqual(filter_c.prefix(), 'abc') - self.assertEqual(filter_c.activePrefix(), 'xyz') + self.assertEqual(filter_c.prefix(), "abc") + self.assertEqual(filter_c.activePrefix(), "xyz") got_hit._results_ = [] - l.fetchResults('b', context) + l.fetchResults("b", context) for i in range(100): sleep(0.002) QCoreApplication.processEvents() - self.assertEqual(set(got_hit._results_), {'custom0', 'custom1', 'custom2'}) + self.assertEqual(set(got_hit._results_), {"custom0", "custom1", "custom2"}) filter_c.setUseWithoutPrefix(False) got_hit._results_ = [] - l.fetchResults('XyZ b', context) + l.fetchResults("XyZ b", context) for i in range(100): sleep(0.002) QCoreApplication.processEvents() - self.assertEqual(set(got_hit._results_), {'custom0', 'custom1', 'custom2'}) + self.assertEqual(set(got_hit._results_), {"custom0", "custom1", "custom2"}) l.deregisterFilter(filter_c) del l @@ -346,12 +354,12 @@ def testModel(self): p.setSourceModel(m) l = QgsLocator() - filter_a = test_filter('a') + filter_a = test_filter("a") l.registerFilter(filter_a) l.foundResult.connect(m.addResult) context = QgsLocatorContext() - l.fetchResults('a', context) + l.fetchResults("a", context) for i in range(100): sleep(0.002) @@ -359,31 +367,47 @@ def testModel(self): # 4 results - one is locator name self.assertEqual(p.rowCount(), 4) - self.assertEqual(p.data(p.index(0, 0)), 'test_a') - self.assertEqual(p.data(p.index(0, 0), QgsLocatorModel.CustomRole.ResultType), 0) - self.assertEqual(p.data(p.index(0, 0), QgsLocatorModel.CustomRole.ResultFilterName), 'test_a') - self.assertEqual(p.data(p.index(1, 0)), 'a0') - self.assertEqual(p.data(p.index(1, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(1, 0), QgsLocatorModel.CustomRole.ResultFilterName), 'test_a') - self.assertEqual(p.data(p.index(2, 0)), 'a1') - self.assertEqual(p.data(p.index(2, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(2, 0), QgsLocatorModel.CustomRole.ResultFilterName), 'test_a') - self.assertEqual(p.data(p.index(3, 0)), 'a2') - self.assertEqual(p.data(p.index(3, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(3, 0), QgsLocatorModel.CustomRole.ResultFilterName), 'test_a') + self.assertEqual(p.data(p.index(0, 0)), "test_a") + self.assertEqual( + p.data(p.index(0, 0), QgsLocatorModel.CustomRole.ResultType), 0 + ) + self.assertEqual( + p.data(p.index(0, 0), QgsLocatorModel.CustomRole.ResultFilterName), "test_a" + ) + self.assertEqual(p.data(p.index(1, 0)), "a0") + self.assertEqual( + p.data(p.index(1, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual( + p.data(p.index(1, 0), QgsLocatorModel.CustomRole.ResultFilterName), "test_a" + ) + self.assertEqual(p.data(p.index(2, 0)), "a1") + self.assertEqual( + p.data(p.index(2, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual( + p.data(p.index(2, 0), QgsLocatorModel.CustomRole.ResultFilterName), "test_a" + ) + self.assertEqual(p.data(p.index(3, 0)), "a2") + self.assertEqual( + p.data(p.index(3, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual( + p.data(p.index(3, 0), QgsLocatorModel.CustomRole.ResultFilterName), "test_a" + ) m.clear() self.assertEqual(p.rowCount(), 0) - l.fetchResults('b', context) + l.fetchResults("b", context) for i in range(100): sleep(0.002) QCoreApplication.processEvents() self.assertEqual(p.rowCount(), 4) - self.assertEqual(p.data(p.index(1, 0)), 'a0') - self.assertEqual(p.data(p.index(2, 0)), 'a1') - self.assertEqual(p.data(p.index(3, 0)), 'a2') + self.assertEqual(p.data(p.index(1, 0)), "a0") + self.assertEqual(p.data(p.index(2, 0)), "a1") + self.assertEqual(p.data(p.index(3, 0)), "a2") m.deferredClear() # should not be immediately cleared! @@ -396,94 +420,186 @@ def testModel(self): # test with groups self.assertEqual(p.rowCount(), 0) - filter_b = test_filter('b', None, groupResult=True, groupScore=False) + filter_b = test_filter("b", None, groupResult=True, groupScore=False) l.registerFilter(filter_b) - l.fetchResults('c', context) + l.fetchResults("c", context) for i in range(200): sleep(0.002) QCoreApplication.processEvents() - self.assertEqual(p.rowCount(), 16) # 1 title a + 3 results + 1 title b + 2 groups + 9 results - self.assertEqual(p.data(p.index(0, 0)), 'test_a') - self.assertEqual(p.data(p.index(0, 0), QgsLocatorModel.CustomRole.ResultType), 0) - self.assertEqual(p.data(p.index(1, 0)), 'a0') - self.assertEqual(p.data(p.index(1, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(2, 0)), 'a1') - self.assertEqual(p.data(p.index(2, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(3, 0)), 'a2') - self.assertEqual(p.data(p.index(3, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(4, 0)), 'test_b') - self.assertEqual(p.data(p.index(4, 0), QgsLocatorModel.CustomRole.ResultType), 0) - self.assertEqual(p.data(p.index(4, 0), QgsLocatorModel.CustomRole.ResultFilterName), 'test_b') - self.assertEqual(p.data(p.index(5, 0)).strip(), 'group a') - self.assertEqual(p.data(p.index(5, 0), QgsLocatorModel.CustomRole.ResultType), 1) - self.assertEqual(p.data(p.index(5, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), 0) - self.assertEqual(p.data(p.index(6, 0)), 'b0') - self.assertEqual(p.data(p.index(6, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(6, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), 0) - self.assertEqual(p.data(p.index(7, 0)), 'b1') - self.assertEqual(p.data(p.index(7, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(8, 0)), 'b3') - self.assertEqual(p.data(p.index(8, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(9, 0)), 'b5') - self.assertEqual(p.data(p.index(9, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(10, 0)), 'b6') - self.assertEqual(p.data(p.index(10, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(11, 0)).strip(), 'group b') - self.assertEqual(p.data(p.index(11, 0), QgsLocatorModel.CustomRole.ResultType), 1) - self.assertEqual(p.data(p.index(11, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), 0) - self.assertEqual(p.data(p.index(12, 0)), 'b4') - self.assertEqual(p.data(p.index(12, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(12, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), 0) - self.assertEqual(p.data(p.index(13, 0)), 'b8') - self.assertEqual(p.data(p.index(13, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(14, 0)), 'b2') - self.assertEqual(p.data(p.index(14, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(15, 0)), 'b7') - self.assertEqual(p.data(p.index(15, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(15, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), QgsLocatorModel.NoGroup) + self.assertEqual( + p.rowCount(), 16 + ) # 1 title a + 3 results + 1 title b + 2 groups + 9 results + self.assertEqual(p.data(p.index(0, 0)), "test_a") + self.assertEqual( + p.data(p.index(0, 0), QgsLocatorModel.CustomRole.ResultType), 0 + ) + self.assertEqual(p.data(p.index(1, 0)), "a0") + self.assertEqual( + p.data(p.index(1, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual(p.data(p.index(2, 0)), "a1") + self.assertEqual( + p.data(p.index(2, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual(p.data(p.index(3, 0)), "a2") + self.assertEqual( + p.data(p.index(3, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual(p.data(p.index(4, 0)), "test_b") + self.assertEqual( + p.data(p.index(4, 0), QgsLocatorModel.CustomRole.ResultType), 0 + ) + self.assertEqual( + p.data(p.index(4, 0), QgsLocatorModel.CustomRole.ResultFilterName), "test_b" + ) + self.assertEqual(p.data(p.index(5, 0)).strip(), "group a") + self.assertEqual( + p.data(p.index(5, 0), QgsLocatorModel.CustomRole.ResultType), 1 + ) + self.assertEqual( + p.data(p.index(5, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), 0 + ) + self.assertEqual(p.data(p.index(6, 0)), "b0") + self.assertEqual( + p.data(p.index(6, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual( + p.data(p.index(6, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), 0 + ) + self.assertEqual(p.data(p.index(7, 0)), "b1") + self.assertEqual( + p.data(p.index(7, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual(p.data(p.index(8, 0)), "b3") + self.assertEqual( + p.data(p.index(8, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual(p.data(p.index(9, 0)), "b5") + self.assertEqual( + p.data(p.index(9, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual(p.data(p.index(10, 0)), "b6") + self.assertEqual( + p.data(p.index(10, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual(p.data(p.index(11, 0)).strip(), "group b") + self.assertEqual( + p.data(p.index(11, 0), QgsLocatorModel.CustomRole.ResultType), 1 + ) + self.assertEqual( + p.data(p.index(11, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), 0 + ) + self.assertEqual(p.data(p.index(12, 0)), "b4") + self.assertEqual( + p.data(p.index(12, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual( + p.data(p.index(12, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), 0 + ) + self.assertEqual(p.data(p.index(13, 0)), "b8") + self.assertEqual( + p.data(p.index(13, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual(p.data(p.index(14, 0)), "b2") + self.assertEqual( + p.data(p.index(14, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual(p.data(p.index(15, 0)), "b7") + self.assertEqual( + p.data(p.index(15, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual( + p.data(p.index(15, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), + QgsLocatorModel.NoGroup, + ) # test with groups and group score m.clear() self.assertEqual(p.rowCount(), 0) - filter_b = test_filter('c', None, groupResult=True, groupScore=True) + filter_b = test_filter("c", None, groupResult=True, groupScore=True) l.registerFilter(filter_b) - l.fetchResults('c', context) + l.fetchResults("c", context) for i in range(200): sleep(0.002) QCoreApplication.processEvents() - self.assertEqual(p.rowCount(), 28) # 4 for filter a, 12 for b, + 1 title c + 2 groups + 9 results - self.assertEqual(p.data(p.index(16, 0)), 'test_c') - self.assertEqual(p.data(p.index(16, 0), QgsLocatorModel.CustomRole.ResultType), 0) - self.assertEqual(p.data(p.index(16, 0), QgsLocatorModel.CustomRole.ResultFilterName), 'test_c') - self.assertEqual(p.data(p.index(17, 0)).strip(), 'group b') - self.assertEqual(p.data(p.index(17, 0), QgsLocatorModel.CustomRole.ResultType), 1) - self.assertEqual(p.data(p.index(17, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), 10) - self.assertEqual(p.data(p.index(18, 0)), 'c4') - self.assertEqual(p.data(p.index(18, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(18, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), 10) - self.assertEqual(p.data(p.index(19, 0)), 'c8') - self.assertEqual(p.data(p.index(19, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(20, 0)).strip(), 'group a') - self.assertEqual(p.data(p.index(20, 0), QgsLocatorModel.CustomRole.ResultType), 1) - self.assertEqual(p.data(p.index(20, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), 1) - self.assertEqual(p.data(p.index(21, 0)), 'c0') - self.assertEqual(p.data(p.index(21, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(21, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), 1) - self.assertEqual(p.data(p.index(22, 0)), 'c1') - self.assertEqual(p.data(p.index(22, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(23, 0)), 'c3') - self.assertEqual(p.data(p.index(23, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(24, 0)), 'c5') - self.assertEqual(p.data(p.index(24, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(25, 0)), 'c6') - self.assertEqual(p.data(p.index(25, 0), QgsLocatorModel.CustomRole.ResultType), 2) + self.assertEqual( + p.rowCount(), 28 + ) # 4 for filter a, 12 for b, + 1 title c + 2 groups + 9 results + self.assertEqual(p.data(p.index(16, 0)), "test_c") + self.assertEqual( + p.data(p.index(16, 0), QgsLocatorModel.CustomRole.ResultType), 0 + ) + self.assertEqual( + p.data(p.index(16, 0), QgsLocatorModel.CustomRole.ResultFilterName), + "test_c", + ) + self.assertEqual(p.data(p.index(17, 0)).strip(), "group b") + self.assertEqual( + p.data(p.index(17, 0), QgsLocatorModel.CustomRole.ResultType), 1 + ) + self.assertEqual( + p.data(p.index(17, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), + 10, + ) + self.assertEqual(p.data(p.index(18, 0)), "c4") + self.assertEqual( + p.data(p.index(18, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual( + p.data(p.index(18, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), + 10, + ) + self.assertEqual(p.data(p.index(19, 0)), "c8") + self.assertEqual( + p.data(p.index(19, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual(p.data(p.index(20, 0)).strip(), "group a") + self.assertEqual( + p.data(p.index(20, 0), QgsLocatorModel.CustomRole.ResultType), 1 + ) + self.assertEqual( + p.data(p.index(20, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), 1 + ) + self.assertEqual(p.data(p.index(21, 0)), "c0") + self.assertEqual( + p.data(p.index(21, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual( + p.data(p.index(21, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), 1 + ) + self.assertEqual(p.data(p.index(22, 0)), "c1") + self.assertEqual( + p.data(p.index(22, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual(p.data(p.index(23, 0)), "c3") + self.assertEqual( + p.data(p.index(23, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual(p.data(p.index(24, 0)), "c5") + self.assertEqual( + p.data(p.index(24, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual(p.data(p.index(25, 0)), "c6") + self.assertEqual( + p.data(p.index(25, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) # no groups - self.assertEqual(p.data(p.index(26, 0)), 'c2') - self.assertEqual(p.data(p.index(26, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(26, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), QgsLocatorModel.NoGroup) - self.assertEqual(p.data(p.index(27, 0)), 'c7') - self.assertEqual(p.data(p.index(27, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(p.data(p.index(27, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), QgsLocatorModel.NoGroup) + self.assertEqual(p.data(p.index(26, 0)), "c2") + self.assertEqual( + p.data(p.index(26, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual( + p.data(p.index(26, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), + QgsLocatorModel.NoGroup, + ) + self.assertEqual(p.data(p.index(27, 0)), "c7") + self.assertEqual( + p.data(p.index(27, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual( + p.data(p.index(27, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), + QgsLocatorModel.NoGroup, + ) def testAutoModel(self): """ @@ -493,10 +609,10 @@ def testAutoModel(self): l = QgsLocator() m = QgsLocatorAutomaticModel(l) - filter_a = test_filter('a') + filter_a = test_filter("a") l.registerFilter(filter_a) - m.search('a') + m.search("a") for i in range(100): sleep(0.002) @@ -504,21 +620,40 @@ def testAutoModel(self): # 4 results - one is locator name self.assertEqual(m.rowCount(), 4) - self.assertEqual(m.data(m.index(0, 0)), 'test_a') - self.assertEqual(m.data(m.index(0, 0), QgsLocatorModel.CustomRole.ResultType), 0) - self.assertEqual(m.data(m.index(0, 0), QgsLocatorModel.CustomRole.ResultFilterName), 'test_a') - self.assertEqual(m.data(m.index(1, 0)), 'a0') - self.assertEqual(m.data(m.index(1, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(m.data(m.index(1, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), QgsLocatorModel.NoGroup) - self.assertEqual(m.data(m.index(1, 0), QgsLocatorModel.CustomRole.ResultFilterName), 'test_a') - self.assertEqual(m.data(m.index(2, 0)), 'a1') - self.assertEqual(m.data(m.index(2, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(m.data(m.index(2, 0), QgsLocatorModel.CustomRole.ResultFilterName), 'test_a') - self.assertEqual(m.data(m.index(3, 0)), 'a2') - self.assertEqual(m.data(m.index(3, 0), QgsLocatorModel.CustomRole.ResultType), 2) - self.assertEqual(m.data(m.index(3, 0), QgsLocatorModel.CustomRole.ResultFilterName), 'test_a') - - m.search('a') + self.assertEqual(m.data(m.index(0, 0)), "test_a") + self.assertEqual( + m.data(m.index(0, 0), QgsLocatorModel.CustomRole.ResultType), 0 + ) + self.assertEqual( + m.data(m.index(0, 0), QgsLocatorModel.CustomRole.ResultFilterName), "test_a" + ) + self.assertEqual(m.data(m.index(1, 0)), "a0") + self.assertEqual( + m.data(m.index(1, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual( + m.data(m.index(1, 0), QgsLocatorModel.CustomRole.ResultFilterGroupScore), + QgsLocatorModel.NoGroup, + ) + self.assertEqual( + m.data(m.index(1, 0), QgsLocatorModel.CustomRole.ResultFilterName), "test_a" + ) + self.assertEqual(m.data(m.index(2, 0)), "a1") + self.assertEqual( + m.data(m.index(2, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual( + m.data(m.index(2, 0), QgsLocatorModel.CustomRole.ResultFilterName), "test_a" + ) + self.assertEqual(m.data(m.index(3, 0)), "a2") + self.assertEqual( + m.data(m.index(3, 0), QgsLocatorModel.CustomRole.ResultType), 2 + ) + self.assertEqual( + m.data(m.index(3, 0), QgsLocatorModel.CustomRole.ResultFilterName), "test_a" + ) + + m.search("a") for i in range(100): sleep(0.002) @@ -526,17 +661,17 @@ def testAutoModel(self): # 4 results - one is locator name self.assertEqual(m.rowCount(), 4) - self.assertEqual(m.data(m.index(0, 0)), 'test_a') - self.assertEqual(m.data(m.index(1, 0)), 'a0') - self.assertEqual(m.data(m.index(2, 0)), 'a1') - self.assertEqual(m.data(m.index(3, 0)), 'a2') + self.assertEqual(m.data(m.index(0, 0)), "test_a") + self.assertEqual(m.data(m.index(1, 0)), "a0") + self.assertEqual(m.data(m.index(2, 0)), "a1") + self.assertEqual(m.data(m.index(3, 0)), "a2") def testStringMatches(self): - self.assertFalse(QgsLocatorFilter.stringMatches('xxx', 'yyyy')) - self.assertTrue(QgsLocatorFilter.stringMatches('axxxy', 'xxx')) - self.assertTrue(QgsLocatorFilter.stringMatches('aXXXXy', 'xxx')) - self.assertFalse(QgsLocatorFilter.stringMatches('aXXXXy', '')) + self.assertFalse(QgsLocatorFilter.stringMatches("xxx", "yyyy")) + self.assertTrue(QgsLocatorFilter.stringMatches("axxxy", "xxx")) + self.assertTrue(QgsLocatorFilter.stringMatches("aXXXXy", "xxx")) + self.assertFalse(QgsLocatorFilter.stringMatches("aXXXXy", "")) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgslogger.py b/tests/src/python/test_qgslogger.py index afa70645a977..9708e870b13c 100644 --- a/tests/src/python/test_qgslogger.py +++ b/tests/src/python/test_qgslogger.py @@ -5,17 +5,18 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Tim Sutton' -__date__ = '20/08/2012' -__copyright__ = 'Copyright 2012, The QGIS Project' + +__author__ = "Tim Sutton" +__date__ = "20/08/2012" +__copyright__ = "Copyright 2012, The QGIS Project" import os import tempfile (myFileHandle, myFilename) = tempfile.mkstemp() -os.environ['QGIS_DEBUG'] = '2' -os.environ['QGIS_LOG_FILE'] = myFilename +os.environ["QGIS_DEBUG"] = "2" +os.environ["QGIS_LOG_FILE"] = myFilename from qgis.core import QgsLogger from qgis.testing import unittest @@ -34,24 +35,28 @@ def testLogger(self): myFile.write("QGIS Logger Unit Test\n") myFile.close() myLogger = QgsLogger() - myLogger.debug('This is a debug') - myLogger.warning('This is a warning') - myLogger.critical('This is critical') + myLogger.debug("This is a debug") + myLogger.warning("This is a warning") + myLogger.critical("This is critical") # myLogger.fatal('Aaaargh...fatal'); #kills QGIS not testable myFile = open(myFilename) myText = myFile.readlines() myFile.close() - myExpectedText = ['QGIS Logger Unit Test\n', - 'This is a debug\n', - 'This is a warning\n', - 'This is critical\n'] - myMessage = ('Expected:\n---\n%s\n---\nGot:\n---\n%s\n---\n' % - (myExpectedText, myText)) + myExpectedText = [ + "QGIS Logger Unit Test\n", + "This is a debug\n", + "This is a warning\n", + "This is critical\n", + ] + myMessage = "Expected:\n---\n{}\n---\nGot:\n---\n{}\n---\n".format( + myExpectedText, + myText, + ) self.assertEqual(myText, myExpectedText, myMessage) finally: pass os.remove(myFilename) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmapboxglconverter.py b/tests/src/python/test_qgsmapboxglconverter.py index 92c784fdd74f..32113720931e 100644 --- a/tests/src/python/test_qgsmapboxglconverter.py +++ b/tests/src/python/test_qgsmapboxglconverter.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 by Nyall Dawson' -__date__ = '29/07/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 by Nyall Dawson" +__date__ = "29/07/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import json @@ -57,513 +58,836 @@ def setUpClass(cls): def testNoLayer(self): c = QgsMapBoxGlStyleConverter() - self.assertEqual(c.convert({'x': 'y'}), QgsMapBoxGlStyleConverter.Result.NoLayerList) - self.assertEqual(c.errorMessage(), 'Could not find layers list in JSON') + self.assertEqual( + c.convert({"x": "y"}), QgsMapBoxGlStyleConverter.Result.NoLayerList + ) + self.assertEqual(c.errorMessage(), "Could not find layers list in JSON") self.assertIsNone(c.renderer()) self.assertIsNone(c.labeling()) def testInterpolateExpression(self): - self.assertEqual(QgsMapBoxGlStyleConverter.interpolateExpression(5, 13, 27, 29, 1), - 'scale_linear(@vector_tile_zoom,5,13,27,29)') - self.assertEqual(QgsMapBoxGlStyleConverter.interpolateExpression(5, 13, 27, 29, 1.5), - 'scale_exponential(@vector_tile_zoom,5,13,27,29,1.5)') + self.assertEqual( + QgsMapBoxGlStyleConverter.interpolateExpression(5, 13, 27, 29, 1), + "scale_linear(@vector_tile_zoom,5,13,27,29)", + ) + self.assertEqual( + QgsMapBoxGlStyleConverter.interpolateExpression(5, 13, 27, 29, 1.5), + "scale_exponential(@vector_tile_zoom,5,13,27,29,1.5)", + ) # same values, return nice and simple expression! - self.assertEqual(QgsMapBoxGlStyleConverter.interpolateExpression(5, 13, 27, 27, 1.5), - '27') - self.assertEqual(QgsMapBoxGlStyleConverter.interpolateExpression(5, 13, 27, 27, 1.5, 2), - '54') + self.assertEqual( + QgsMapBoxGlStyleConverter.interpolateExpression(5, 13, 27, 27, 1.5), "27" + ) + self.assertEqual( + QgsMapBoxGlStyleConverter.interpolateExpression(5, 13, 27, 27, 1.5, 2), "54" + ) def testColorAsHslaComponents(self): - self.assertEqual(QgsMapBoxGlStyleConverter.colorAsHslaComponents(QColor.fromHsl(30, 50, 70)), (30, 19, 27, 255)) + self.assertEqual( + QgsMapBoxGlStyleConverter.colorAsHslaComponents(QColor.fromHsl(30, 50, 70)), + (30, 19, 27, 255), + ) def testParseInterpolateColorByZoom(self): conversion_context = QgsMapBoxGlStyleConversionContext() - props, default_col = QgsMapBoxGlStyleConverter.parseInterpolateColorByZoom({}, conversion_context) - self.assertEqual(props.isActive(), - False) - props, default_col = QgsMapBoxGlStyleConverter.parseInterpolateColorByZoom({'base': 1, - 'stops': [[0, '#f1f075'], - [150, '#b52e3e'], - [250, '#e55e5e']] - }, - conversion_context) - self.assertEqual(props.expressionString(), - 'CASE WHEN @vector_tile_zoom < 0 THEN color_hsla(59, 81, 70, 255) WHEN @vector_tile_zoom >= 0 AND @vector_tile_zoom < 150 THEN color_hsla(scale_linear(@vector_tile_zoom,0,150,59,352), scale_linear(@vector_tile_zoom,0,150,81,59), scale_linear(@vector_tile_zoom,0,150,70,44), 255) WHEN @vector_tile_zoom >= 150 AND @vector_tile_zoom < 250 THEN color_hsla(scale_linear(@vector_tile_zoom,150,250,352,0), scale_linear(@vector_tile_zoom,150,250,59,72), scale_linear(@vector_tile_zoom,150,250,44,63), 255) WHEN @vector_tile_zoom >= 250 THEN color_hsla(0, 72, 63, 255) ELSE color_hsla(0, 72, 63, 255) END') - self.assertEqual(default_col.name(), '#f1f075') - props, default_col = QgsMapBoxGlStyleConverter.parseInterpolateColorByZoom({'base': 2, - 'stops': [[0, '#f1f075'], - [150, '#b52e3e'], - [250, '#e55e5e']] - }, - conversion_context) - self.assertEqual(props.expressionString(), - ('CASE WHEN @vector_tile_zoom < 0 THEN color_hsla(59, 81, 70, 255) ' - 'WHEN @vector_tile_zoom >= 0 AND @vector_tile_zoom < 150 THEN color_hsla(scale_exponential(@vector_tile_zoom,0,150,59,352,2), scale_exponential(@vector_tile_zoom,0,150,81,59,2), scale_exponential(@vector_tile_zoom,0,150,70,44,2), 255) ' - 'WHEN @vector_tile_zoom >= 150 AND @vector_tile_zoom < 250 THEN color_hsla(scale_exponential(@vector_tile_zoom,150,250,352,0,2), scale_exponential(@vector_tile_zoom,150,250,59,72,2), scale_exponential(@vector_tile_zoom,150,250,44,63,2), 255) ' - 'WHEN @vector_tile_zoom >= 250 THEN color_hsla(0, 72, 63, 255) ELSE color_hsla(0, 72, 63, 255) END')) - self.assertEqual(default_col.name(), '#f1f075') - - props, default_col = QgsMapBoxGlStyleConverter.parseInterpolateColorByZoom({'base': 1, - "stops": [["9", - [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "trunk" - ], - "rgb(255,230,160)", - "rgb(255,255,255)" - ] - ], - [ - "15", - [ - "match", - [ - "get", - "class" - ], - [ - "motorway", - "trunk" - ], - "rgb(255, 224, 138)", - "rgb(255,255,255)" - ] - ] - ] - }, conversion_context) - self.assertEqual(props.expressionString(), - "CASE WHEN @vector_tile_zoom >= 9 AND @vector_tile_zoom < 15 THEN color_hsla(scale_linear(@vector_tile_zoom,9,15,color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,230,160,255) ELSE color_rgba(255,255,255,255) END,'hsl_hue'),color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'hsl_hue')), scale_linear(@vector_tile_zoom,9,15,color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,230,160,255) ELSE color_rgba(255,255,255,255) END,'hsl_saturation'),color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'hsl_saturation')), scale_linear(@vector_tile_zoom,9,15,color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,230,160,255) ELSE color_rgba(255,255,255,255) END,'lightness'),color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'lightness')), scale_linear(@vector_tile_zoom,9,15,color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,230,160,255) ELSE color_rgba(255,255,255,255) END,'alpha'),color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'alpha'))) WHEN @vector_tile_zoom >= 15 THEN color_hsla(color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'hsl_hue'), color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'hsl_saturation'), color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'lightness'), color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'alpha')) ELSE color_hsla(color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'hsl_hue'), color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'hsl_saturation'), color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'lightness'), color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'alpha')) END") + props, default_col = QgsMapBoxGlStyleConverter.parseInterpolateColorByZoom( + {}, conversion_context + ) + self.assertEqual(props.isActive(), False) + props, default_col = QgsMapBoxGlStyleConverter.parseInterpolateColorByZoom( + {"base": 1, "stops": [[0, "#f1f075"], [150, "#b52e3e"], [250, "#e55e5e"]]}, + conversion_context, + ) + self.assertEqual( + props.expressionString(), + "CASE WHEN @vector_tile_zoom < 0 THEN color_hsla(59, 81, 70, 255) WHEN @vector_tile_zoom >= 0 AND @vector_tile_zoom < 150 THEN color_hsla(scale_linear(@vector_tile_zoom,0,150,59,352), scale_linear(@vector_tile_zoom,0,150,81,59), scale_linear(@vector_tile_zoom,0,150,70,44), 255) WHEN @vector_tile_zoom >= 150 AND @vector_tile_zoom < 250 THEN color_hsla(scale_linear(@vector_tile_zoom,150,250,352,0), scale_linear(@vector_tile_zoom,150,250,59,72), scale_linear(@vector_tile_zoom,150,250,44,63), 255) WHEN @vector_tile_zoom >= 250 THEN color_hsla(0, 72, 63, 255) ELSE color_hsla(0, 72, 63, 255) END", + ) + self.assertEqual(default_col.name(), "#f1f075") + props, default_col = QgsMapBoxGlStyleConverter.parseInterpolateColorByZoom( + {"base": 2, "stops": [[0, "#f1f075"], [150, "#b52e3e"], [250, "#e55e5e"]]}, + conversion_context, + ) + self.assertEqual( + props.expressionString(), + ( + "CASE WHEN @vector_tile_zoom < 0 THEN color_hsla(59, 81, 70, 255) " + "WHEN @vector_tile_zoom >= 0 AND @vector_tile_zoom < 150 THEN color_hsla(scale_exponential(@vector_tile_zoom,0,150,59,352,2), scale_exponential(@vector_tile_zoom,0,150,81,59,2), scale_exponential(@vector_tile_zoom,0,150,70,44,2), 255) " + "WHEN @vector_tile_zoom >= 150 AND @vector_tile_zoom < 250 THEN color_hsla(scale_exponential(@vector_tile_zoom,150,250,352,0,2), scale_exponential(@vector_tile_zoom,150,250,59,72,2), scale_exponential(@vector_tile_zoom,150,250,44,63,2), 255) " + "WHEN @vector_tile_zoom >= 250 THEN color_hsla(0, 72, 63, 255) ELSE color_hsla(0, 72, 63, 255) END" + ), + ) + self.assertEqual(default_col.name(), "#f1f075") + + props, default_col = QgsMapBoxGlStyleConverter.parseInterpolateColorByZoom( + { + "base": 1, + "stops": [ + [ + "9", + [ + "match", + ["get", "class"], + ["motorway", "trunk"], + "rgb(255,230,160)", + "rgb(255,255,255)", + ], + ], + [ + "15", + [ + "match", + ["get", "class"], + ["motorway", "trunk"], + "rgb(255, 224, 138)", + "rgb(255,255,255)", + ], + ], + ], + }, + conversion_context, + ) + self.assertEqual( + props.expressionString(), + "CASE WHEN @vector_tile_zoom >= 9 AND @vector_tile_zoom < 15 THEN color_hsla(scale_linear(@vector_tile_zoom,9,15,color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,230,160,255) ELSE color_rgba(255,255,255,255) END,'hsl_hue'),color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'hsl_hue')), scale_linear(@vector_tile_zoom,9,15,color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,230,160,255) ELSE color_rgba(255,255,255,255) END,'hsl_saturation'),color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'hsl_saturation')), scale_linear(@vector_tile_zoom,9,15,color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,230,160,255) ELSE color_rgba(255,255,255,255) END,'lightness'),color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'lightness')), scale_linear(@vector_tile_zoom,9,15,color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,230,160,255) ELSE color_rgba(255,255,255,255) END,'alpha'),color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'alpha'))) WHEN @vector_tile_zoom >= 15 THEN color_hsla(color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'hsl_hue'), color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'hsl_saturation'), color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'lightness'), color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'alpha')) ELSE color_hsla(color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'hsl_hue'), color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'hsl_saturation'), color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'lightness'), color_part(CASE WHEN \"class\" IN ('motorway', 'trunk') THEN color_rgba(255,224,138,255) ELSE color_rgba(255,255,255,255) END,'alpha')) END", + ) def testParseStops(self): conversion_context = QgsMapBoxGlStyleConversionContext() - self.assertEqual(QgsMapBoxGlStyleConverter.parseStops(1, [[1, 10], [2, 20], [5, 100]], 1, conversion_context), - 'CASE WHEN @vector_tile_zoom >= 1 AND @vector_tile_zoom <= 2 THEN scale_linear(@vector_tile_zoom,1,2,10,20) WHEN @vector_tile_zoom > 2 AND @vector_tile_zoom <= 5 THEN scale_linear(@vector_tile_zoom,2,5,20,100) WHEN @vector_tile_zoom > 5 THEN 100 END') - self.assertEqual(QgsMapBoxGlStyleConverter.parseStops(1.5, [[1, 10], [2, 20], [5, 100]], 1, conversion_context), - 'CASE WHEN @vector_tile_zoom >= 1 AND @vector_tile_zoom <= 2 THEN scale_exponential(@vector_tile_zoom,1,2,10,20,1.5) WHEN @vector_tile_zoom > 2 AND @vector_tile_zoom <= 5 THEN scale_exponential(@vector_tile_zoom,2,5,20,100,1.5) WHEN @vector_tile_zoom > 5 THEN 100 END') - self.assertEqual(QgsMapBoxGlStyleConverter.parseStops(1, [[1, 10], [2, 20], [5, 100]], 8, conversion_context), - 'CASE WHEN @vector_tile_zoom >= 1 AND @vector_tile_zoom <= 2 THEN (scale_linear(@vector_tile_zoom,1,2,10,20)) * 8 WHEN @vector_tile_zoom > 2 AND @vector_tile_zoom <= 5 THEN (scale_linear(@vector_tile_zoom,2,5,20,100)) * 8 WHEN @vector_tile_zoom > 5 THEN 800 END') - self.assertEqual(QgsMapBoxGlStyleConverter.parseStops(1.5, [[1, 10], [2, 20], [5, 100]], 8, conversion_context), - ('CASE WHEN @vector_tile_zoom >= 1 AND @vector_tile_zoom <= 2 THEN (scale_exponential(@vector_tile_zoom,1,2,10,20,1.5)) * 8 ' - 'WHEN @vector_tile_zoom > 2 AND @vector_tile_zoom <= 5 THEN (scale_exponential(@vector_tile_zoom,2,5,20,100,1.5)) * 8 ' - 'WHEN @vector_tile_zoom > 5 THEN 800 END')) + self.assertEqual( + QgsMapBoxGlStyleConverter.parseStops( + 1, [[1, 10], [2, 20], [5, 100]], 1, conversion_context + ), + "CASE WHEN @vector_tile_zoom >= 1 AND @vector_tile_zoom <= 2 THEN scale_linear(@vector_tile_zoom,1,2,10,20) WHEN @vector_tile_zoom > 2 AND @vector_tile_zoom <= 5 THEN scale_linear(@vector_tile_zoom,2,5,20,100) WHEN @vector_tile_zoom > 5 THEN 100 END", + ) + self.assertEqual( + QgsMapBoxGlStyleConverter.parseStops( + 1.5, [[1, 10], [2, 20], [5, 100]], 1, conversion_context + ), + "CASE WHEN @vector_tile_zoom >= 1 AND @vector_tile_zoom <= 2 THEN scale_exponential(@vector_tile_zoom,1,2,10,20,1.5) WHEN @vector_tile_zoom > 2 AND @vector_tile_zoom <= 5 THEN scale_exponential(@vector_tile_zoom,2,5,20,100,1.5) WHEN @vector_tile_zoom > 5 THEN 100 END", + ) + self.assertEqual( + QgsMapBoxGlStyleConverter.parseStops( + 1, [[1, 10], [2, 20], [5, 100]], 8, conversion_context + ), + "CASE WHEN @vector_tile_zoom >= 1 AND @vector_tile_zoom <= 2 THEN (scale_linear(@vector_tile_zoom,1,2,10,20)) * 8 WHEN @vector_tile_zoom > 2 AND @vector_tile_zoom <= 5 THEN (scale_linear(@vector_tile_zoom,2,5,20,100)) * 8 WHEN @vector_tile_zoom > 5 THEN 800 END", + ) + self.assertEqual( + QgsMapBoxGlStyleConverter.parseStops( + 1.5, [[1, 10], [2, 20], [5, 100]], 8, conversion_context + ), + ( + "CASE WHEN @vector_tile_zoom >= 1 AND @vector_tile_zoom <= 2 THEN (scale_exponential(@vector_tile_zoom,1,2,10,20,1.5)) * 8 " + "WHEN @vector_tile_zoom > 2 AND @vector_tile_zoom <= 5 THEN (scale_exponential(@vector_tile_zoom,2,5,20,100,1.5)) * 8 " + "WHEN @vector_tile_zoom > 5 THEN 800 END" + ), + ) def testParseMatchList(self): conversion_context = QgsMapBoxGlStyleConversionContext() - res, default_color, default_number = QgsMapBoxGlStyleConverter.parseMatchList([ - "match", - ["get", "type"], - ["Air Transport", "Airport"], - "#e6e6e6", - ["Education"], - "#f7eaca", - ["Medical Care"], - "#f3d8e7", - ["Road Transport"], - "#f7f3ca", - ["Water Transport"], - "#d8e6f3", - "#e7e7e7" - ], QgsMapBoxGlStyleConverter.PropertyType.Color, conversion_context, 2.5, 200) - self.assertEqual(res.asExpression(), - 'CASE WHEN "type" IN (\'Air Transport\',\'Airport\') THEN \'#e6e6e6\' WHEN "type" IS \'Education\' THEN \'#f7eaca\' WHEN "type" IS \'Medical Care\' THEN \'#f3d8e7\' WHEN "type" IS \'Road Transport\' THEN \'#f7f3ca\' WHEN "type" IS \'Water Transport\' THEN \'#d8e6f3\' ELSE \'#e7e7e7\' END') - self.assertEqual(default_color.name(), '#e7e7e7') - - res, default_color, default_number = QgsMapBoxGlStyleConverter.parseMatchList([ - "match", - ["get", "type"], - ["Normal"], - 0.25, - ["Index"], - 0.5, - 0.2 - ], QgsMapBoxGlStyleConverter.PropertyType.Numeric, conversion_context, 2.5, 200) - self.assertEqual(res.asExpression(), - 'CASE WHEN "type" IS \'Normal\' THEN 0.625 WHEN "type" IS \'Index\' THEN 1.25 ELSE 0.5 END') + res, default_color, default_number = QgsMapBoxGlStyleConverter.parseMatchList( + [ + "match", + ["get", "type"], + ["Air Transport", "Airport"], + "#e6e6e6", + ["Education"], + "#f7eaca", + ["Medical Care"], + "#f3d8e7", + ["Road Transport"], + "#f7f3ca", + ["Water Transport"], + "#d8e6f3", + "#e7e7e7", + ], + QgsMapBoxGlStyleConverter.PropertyType.Color, + conversion_context, + 2.5, + 200, + ) + self.assertEqual( + res.asExpression(), + "CASE WHEN \"type\" IN ('Air Transport','Airport') THEN '#e6e6e6' WHEN \"type\" IS 'Education' THEN '#f7eaca' WHEN \"type\" IS 'Medical Care' THEN '#f3d8e7' WHEN \"type\" IS 'Road Transport' THEN '#f7f3ca' WHEN \"type\" IS 'Water Transport' THEN '#d8e6f3' ELSE '#e7e7e7' END", + ) + self.assertEqual(default_color.name(), "#e7e7e7") + + res, default_color, default_number = QgsMapBoxGlStyleConverter.parseMatchList( + ["match", ["get", "type"], ["Normal"], 0.25, ["Index"], 0.5, 0.2], + QgsMapBoxGlStyleConverter.PropertyType.Numeric, + conversion_context, + 2.5, + 200, + ) + self.assertEqual( + res.asExpression(), + "CASE WHEN \"type\" IS 'Normal' THEN 0.625 WHEN \"type\" IS 'Index' THEN 1.25 ELSE 0.5 END", + ) self.assertEqual(default_number, 0.5) - res, default_color, default_number = QgsMapBoxGlStyleConverter.parseMatchList([ - "match", + res, default_color, default_number = QgsMapBoxGlStyleConverter.parseMatchList( [ - "get", - "luminosity" + "match", + ["get", "luminosity"], + -15, + "rgb(200,210,213)", + -14, + "rgb(203,213,216)", + -13, + "rgb(207,215,218)", + -12, + "rgb(210,218,221)", + -11, + "rgb(213,221,224)", + -10, + "rgb(217,224,226)", + -9, + "rgb(220,227,229)", + -8, + "rgb(224,230,231)", + -7, + "rgb(227,232,234)", + -6, + "rgb(231,235,237)", + -5, + "rgb(234,238,239)", + -4, + "rgb(238,241,242)", + -3, + "rgb(241,244,245)", + -2, + "rgb(245,247,247)", + -1, + "rgb(248,249,250)", + "rgb(252, 252, 252)", ], - -15, - "rgb(200,210,213)", - -14, - "rgb(203,213,216)", - -13, - "rgb(207,215,218)", - -12, - "rgb(210,218,221)", - -11, - "rgb(213,221,224)", - -10, - "rgb(217,224,226)", - -9, - "rgb(220,227,229)", - -8, - "rgb(224,230,231)", - -7, - "rgb(227,232,234)", - -6, - "rgb(231,235,237)", - -5, - "rgb(234,238,239)", - -4, - "rgb(238,241,242)", - -3, - "rgb(241,244,245)", - -2, - "rgb(245,247,247)", - -1, - "rgb(248,249,250)", - "rgb(252, 252, 252)" - ], QgsMapBoxGlStyleConverter.PropertyType.Color, conversion_context, 2.5, 200) - self.assertEqual(res.asExpression(), 'CASE WHEN "luminosity" IS -15 THEN \'#c8d2d5\' WHEN "luminosity" IS -14 THEN \'#cbd5d8\' WHEN "luminosity" IS -13 THEN \'#cfd7da\' WHEN "luminosity" IS -12 THEN \'#d2dadd\' WHEN "luminosity" IS -11 THEN \'#d5dde0\' WHEN "luminosity" IS -10 THEN \'#d9e0e2\' WHEN "luminosity" IS -9 THEN \'#dce3e5\' WHEN "luminosity" IS -8 THEN \'#e0e6e7\' WHEN "luminosity" IS -7 THEN \'#e3e8ea\' WHEN "luminosity" IS -6 THEN \'#e7ebed\' WHEN "luminosity" IS -5 THEN \'#eaeeef\' WHEN "luminosity" IS -4 THEN \'#eef1f2\' WHEN "luminosity" IS -3 THEN \'#f1f4f5\' WHEN "luminosity" IS -2 THEN \'#f5f7f7\' WHEN "luminosity" IS -1 THEN \'#f8f9fa\' ELSE \'#fcfcfc\' END') + QgsMapBoxGlStyleConverter.PropertyType.Color, + conversion_context, + 2.5, + 200, + ) + self.assertEqual( + res.asExpression(), + "CASE WHEN \"luminosity\" IS -15 THEN '#c8d2d5' WHEN \"luminosity\" IS -14 THEN '#cbd5d8' WHEN \"luminosity\" IS -13 THEN '#cfd7da' WHEN \"luminosity\" IS -12 THEN '#d2dadd' WHEN \"luminosity\" IS -11 THEN '#d5dde0' WHEN \"luminosity\" IS -10 THEN '#d9e0e2' WHEN \"luminosity\" IS -9 THEN '#dce3e5' WHEN \"luminosity\" IS -8 THEN '#e0e6e7' WHEN \"luminosity\" IS -7 THEN '#e3e8ea' WHEN \"luminosity\" IS -6 THEN '#e7ebed' WHEN \"luminosity\" IS -5 THEN '#eaeeef' WHEN \"luminosity\" IS -4 THEN '#eef1f2' WHEN \"luminosity\" IS -3 THEN '#f1f4f5' WHEN \"luminosity\" IS -2 THEN '#f5f7f7' WHEN \"luminosity\" IS -1 THEN '#f8f9fa' ELSE '#fcfcfc' END", + ) self.assertTrue(qgsDoubleNear(default_number, 0.0)) - res, default_color, default_number = QgsMapBoxGlStyleConverter.parseMatchList([ - "match", + res, default_color, default_number = QgsMapBoxGlStyleConverter.parseMatchList( [ - "get", - "class" + "match", + ["get", "class"], + "scree", + "rgba(0, 0, 0, 1)", + "hsl(35, 86%, 38%)", ], - "scree", - "rgba(0, 0, 0, 1)", - "hsl(35, 86%, 38%)" - ], QgsMapBoxGlStyleConverter.PropertyType.Color, conversion_context, 2.5, 200) - self.assertEqual(res.asExpression(), '''CASE WHEN "class" IS 'scree' THEN '#000000' ELSE '#b26e0e' END''') + QgsMapBoxGlStyleConverter.PropertyType.Color, + conversion_context, + 2.5, + 200, + ) + self.assertEqual( + res.asExpression(), + """CASE WHEN "class" IS 'scree' THEN '#000000' ELSE '#b26e0e' END""", + ) self.assertTrue(qgsDoubleNear(default_number, 0.0)) def testParseStepList(self): conversion_context = QgsMapBoxGlStyleConversionContext() - res, default_color, default_number = QgsMapBoxGlStyleConverter.parseStepList([ - "step", - ["zoom"], - 0, - 7, ["match", ["get", "capital"], [2, 4], 1, 0], - 8, ["case", [">", 14, ["get", "rank"]], 1, 0], - 9, ["case", [">", 15, ["get", "rank"]], 1, 0], - 10, ["case", [">", 18, ["get", "rank"]], 1, 0], - 11, ["case", [">", 28, ["get", "rank"]], 1, 0], - 12, 1, - 13, 0 - ], QgsMapBoxGlStyleConverter.PropertyType.Opacity, conversion_context, 100, 255) - self.assertEqual(res.asExpression(), 'CASE WHEN @vector_tile_zoom >= 13 THEN (0) WHEN @vector_tile_zoom >= 12 THEN (255) WHEN @vector_tile_zoom >= 11 THEN (CASE WHEN ("28" > "rank") THEN 1 ELSE 0 END) WHEN @vector_tile_zoom >= 10 THEN (CASE WHEN ("18" > "rank") THEN 1 ELSE 0 END) WHEN @vector_tile_zoom >= 9 THEN (CASE WHEN ("15" > "rank") THEN 1 ELSE 0 END) WHEN @vector_tile_zoom >= 8 THEN (CASE WHEN ("14" > "rank") THEN 1 ELSE 0 END) WHEN @vector_tile_zoom >= 7 THEN (CASE WHEN "capital" IN (2,4) THEN 255 ELSE 0 END) ELSE (0) END') + res, default_color, default_number = QgsMapBoxGlStyleConverter.parseStepList( + [ + "step", + ["zoom"], + 0, + 7, + ["match", ["get", "capital"], [2, 4], 1, 0], + 8, + ["case", [">", 14, ["get", "rank"]], 1, 0], + 9, + ["case", [">", 15, ["get", "rank"]], 1, 0], + 10, + ["case", [">", 18, ["get", "rank"]], 1, 0], + 11, + ["case", [">", 28, ["get", "rank"]], 1, 0], + 12, + 1, + 13, + 0, + ], + QgsMapBoxGlStyleConverter.PropertyType.Opacity, + conversion_context, + 100, + 255, + ) + self.assertEqual( + res.asExpression(), + 'CASE WHEN @vector_tile_zoom >= 13 THEN (0) WHEN @vector_tile_zoom >= 12 THEN (255) WHEN @vector_tile_zoom >= 11 THEN (CASE WHEN ("28" > "rank") THEN 1 ELSE 0 END) WHEN @vector_tile_zoom >= 10 THEN (CASE WHEN ("18" > "rank") THEN 1 ELSE 0 END) WHEN @vector_tile_zoom >= 9 THEN (CASE WHEN ("15" > "rank") THEN 1 ELSE 0 END) WHEN @vector_tile_zoom >= 8 THEN (CASE WHEN ("14" > "rank") THEN 1 ELSE 0 END) WHEN @vector_tile_zoom >= 7 THEN (CASE WHEN "capital" IN (2,4) THEN 255 ELSE 0 END) ELSE (0) END', + ) def testParseValueList(self): conversion_context = QgsMapBoxGlStyleConversionContext() - res, default_color, default_number = QgsMapBoxGlStyleConverter.parseValueList([ - "match", - ["get", "type"], - ["Air Transport", "Airport"], - "#e6e6e6", - ["Education"], - "#f7eaca", - ["Medical Care"], - "#f3d8e7", - ["Road Transport"], - "#f7f3ca", - ["Water Transport"], - "#d8e6f3", - "#e7e7e7" - ], QgsMapBoxGlStyleConverter.PropertyType.Color, conversion_context, 2.5, 200) - self.assertEqual(res.asExpression(), - 'CASE WHEN "type" IN (\'Air Transport\',\'Airport\') THEN \'#e6e6e6\' WHEN "type" IS \'Education\' THEN \'#f7eaca\' WHEN "type" IS \'Medical Care\' THEN \'#f3d8e7\' WHEN "type" IS \'Road Transport\' THEN \'#f7f3ca\' WHEN "type" IS \'Water Transport\' THEN \'#d8e6f3\' ELSE \'#e7e7e7\' END') - self.assertEqual(default_color.name(), '#e7e7e7') - - res, default_color, default_number = QgsMapBoxGlStyleConverter.parseValueList([ - "interpolate", - ["linear"], - ["zoom"], - 10, - 0.1, - 15, - 0.3, - 18, - 0.6 - ], QgsMapBoxGlStyleConverter.PropertyType.Numeric, conversion_context, 2.5, 200) - self.assertEqual(res.asExpression(), - 'CASE WHEN @vector_tile_zoom >= 10 AND @vector_tile_zoom <= 15 THEN (scale_linear(@vector_tile_zoom,10,15,0.1,0.3)) * 2.5 WHEN @vector_tile_zoom > 15 AND @vector_tile_zoom <= 18 THEN (scale_linear(@vector_tile_zoom,15,18,0.3,0.6)) * 2.5 WHEN @vector_tile_zoom > 18 THEN 1.5 END') + res, default_color, default_number = QgsMapBoxGlStyleConverter.parseValueList( + [ + "match", + ["get", "type"], + ["Air Transport", "Airport"], + "#e6e6e6", + ["Education"], + "#f7eaca", + ["Medical Care"], + "#f3d8e7", + ["Road Transport"], + "#f7f3ca", + ["Water Transport"], + "#d8e6f3", + "#e7e7e7", + ], + QgsMapBoxGlStyleConverter.PropertyType.Color, + conversion_context, + 2.5, + 200, + ) + self.assertEqual( + res.asExpression(), + "CASE WHEN \"type\" IN ('Air Transport','Airport') THEN '#e6e6e6' WHEN \"type\" IS 'Education' THEN '#f7eaca' WHEN \"type\" IS 'Medical Care' THEN '#f3d8e7' WHEN \"type\" IS 'Road Transport' THEN '#f7f3ca' WHEN \"type\" IS 'Water Transport' THEN '#d8e6f3' ELSE '#e7e7e7' END", + ) + self.assertEqual(default_color.name(), "#e7e7e7") + + res, default_color, default_number = QgsMapBoxGlStyleConverter.parseValueList( + ["interpolate", ["linear"], ["zoom"], 10, 0.1, 15, 0.3, 18, 0.6], + QgsMapBoxGlStyleConverter.PropertyType.Numeric, + conversion_context, + 2.5, + 200, + ) + self.assertEqual( + res.asExpression(), + "CASE WHEN @vector_tile_zoom >= 10 AND @vector_tile_zoom <= 15 THEN (scale_linear(@vector_tile_zoom,10,15,0.1,0.3)) * 2.5 WHEN @vector_tile_zoom > 15 AND @vector_tile_zoom <= 18 THEN (scale_linear(@vector_tile_zoom,15,18,0.3,0.6)) * 2.5 WHEN @vector_tile_zoom > 18 THEN 1.5 END", + ) self.assertEqual(default_number, 0.25) # nested match list - res, default_color, default_number = QgsMapBoxGlStyleConverter.parseValueList([ - "match", - ["get", "is_route"], - [5, 10], - "hsl(16,91%,80%)", - [6, 7, 8], - "hsl(55,91%,80%)", + res, default_color, default_number = QgsMapBoxGlStyleConverter.parseValueList( [ "match", - ["get", "class"], - ["motorway", "trunk", "motorway_construction", "trunk_construction"], - "hsl(41,93%,73%)", + ["get", "is_route"], + [5, 10], + "hsl(16,91%,80%)", + [6, 7, 8], + "hsl(55,91%,80%)", [ - "rail", "rail_construction", "path", "path_construction", - "footway", "footway_construction", "track", "track_construction", - "trail", "trail_construction" + "match", + ["get", "class"], + [ + "motorway", + "trunk", + "motorway_construction", + "trunk_construction", + ], + "hsl(41,93%,73%)", + [ + "rail", + "rail_construction", + "path", + "path_construction", + "footway", + "footway_construction", + "track", + "track_construction", + "trail", + "trail_construction", + ], + [ + "match", + ["get", "subclass"], + "covered_bridge", + "rgb(255,255,255)", + "rgb(238,238,240)", + ], + "rgba(255,255,255,1)", ], - ["match", ["get", "subclass"], "covered_bridge", "rgb(255,255,255)", "rgb(238,238,240)"], - "rgba(255,255,255,1)" - ] - ], QgsMapBoxGlStyleConverter.PropertyType.Color, conversion_context, 2.5, 200) - self.assertEqual(res.asExpression(), - '''CASE WHEN "is_route" IN (5,10) THEN '#fab69e' WHEN "is_route" IN (6,7,8) THEN '#faf39e' ELSE CASE WHEN "class" IN ('motorway','trunk','motorway_construction','trunk_construction') THEN '#fad27a' WHEN "class" IN ('rail','rail_construction','path','path_construction','footway','footway_construction','track','track_construction','trail','trail_construction') THEN CASE WHEN "subclass" IS 'covered_bridge' THEN '#ffffff' ELSE '#eeeef0' END ELSE '#ffffff' END END''') + ], + QgsMapBoxGlStyleConverter.PropertyType.Color, + conversion_context, + 2.5, + 200, + ) + self.assertEqual( + res.asExpression(), + """CASE WHEN "is_route" IN (5,10) THEN '#fab69e' WHEN "is_route" IN (6,7,8) THEN '#faf39e' ELSE CASE WHEN "class" IN ('motorway','trunk','motorway_construction','trunk_construction') THEN '#fad27a' WHEN "class" IN ('rail','rail_construction','path','path_construction','footway','footway_construction','track','track_construction','trail','trail_construction') THEN CASE WHEN "subclass" IS 'covered_bridge' THEN '#ffffff' ELSE '#eeeef0' END ELSE '#ffffff' END END""", + ) def testInterpolateByZoom(self): conversion_context = QgsMapBoxGlStyleConversionContext() - prop, default_val = QgsMapBoxGlStyleConverter.parseInterpolateByZoom({'base': 1, - 'stops': [[0, 11], - [150, 15], - [250, 22]] - }, conversion_context) - self.assertEqual(prop.expressionString(), - 'CASE WHEN @vector_tile_zoom >= 0 AND @vector_tile_zoom <= 150 THEN scale_linear(@vector_tile_zoom,0,150,11,15) WHEN @vector_tile_zoom > 150 AND @vector_tile_zoom <= 250 THEN scale_linear(@vector_tile_zoom,150,250,15,22) WHEN @vector_tile_zoom > 250 THEN 22 END') + prop, default_val = QgsMapBoxGlStyleConverter.parseInterpolateByZoom( + {"base": 1, "stops": [[0, 11], [150, 15], [250, 22]]}, conversion_context + ) + self.assertEqual( + prop.expressionString(), + "CASE WHEN @vector_tile_zoom >= 0 AND @vector_tile_zoom <= 150 THEN scale_linear(@vector_tile_zoom,0,150,11,15) WHEN @vector_tile_zoom > 150 AND @vector_tile_zoom <= 250 THEN scale_linear(@vector_tile_zoom,150,250,15,22) WHEN @vector_tile_zoom > 250 THEN 22 END", + ) self.assertEqual(default_val, 11.0) - prop, default_val = QgsMapBoxGlStyleConverter.parseInterpolateByZoom({'base': 1, - 'stops': [[0, 11], - [150, 15]] - }, conversion_context) - self.assertEqual(prop.expressionString(), - 'scale_linear(@vector_tile_zoom,0,150,11,15)') + prop, default_val = QgsMapBoxGlStyleConverter.parseInterpolateByZoom( + {"base": 1, "stops": [[0, 11], [150, 15]]}, conversion_context + ) + self.assertEqual( + prop.expressionString(), "scale_linear(@vector_tile_zoom,0,150,11,15)" + ) self.assertEqual(default_val, 11.0) - prop, default_val = QgsMapBoxGlStyleConverter.parseInterpolateByZoom({'base': 2, - 'stops': [[0, 11], - [150, 15]] - }, conversion_context) - self.assertEqual(prop.expressionString(), 'scale_exponential(@vector_tile_zoom,0,150,11,15,2)') + prop, default_val = QgsMapBoxGlStyleConverter.parseInterpolateByZoom( + {"base": 2, "stops": [[0, 11], [150, 15]]}, conversion_context + ) + self.assertEqual( + prop.expressionString(), + "scale_exponential(@vector_tile_zoom,0,150,11,15,2)", + ) self.assertEqual(default_val, 11.0) - prop, default_val = QgsMapBoxGlStyleConverter.parseInterpolateByZoom({'base': 2, - 'stops': [[0, 11], - [150, 15]] - }, conversion_context, multiplier=5) - self.assertEqual(prop.expressionString(), '(scale_exponential(@vector_tile_zoom,0,150,11,15,2)) * 5') + prop, default_val = QgsMapBoxGlStyleConverter.parseInterpolateByZoom( + {"base": 2, "stops": [[0, 11], [150, 15]]}, conversion_context, multiplier=5 + ) + self.assertEqual( + prop.expressionString(), + "(scale_exponential(@vector_tile_zoom,0,150,11,15,2)) * 5", + ) self.assertEqual(default_val, 55.0) def testInterpolateOpacityByZoom(self): conversion_context = QgsMapBoxGlStyleConversionContext() - self.assertEqual(QgsMapBoxGlStyleConverter.parseInterpolateOpacityByZoom({'base': 1, - 'stops': [[0, 0.1], - [150, 0.15], - [250, 0.2]] - }, 255, - conversion_context).expressionString(), - "CASE WHEN @vector_tile_zoom < 0 THEN set_color_part(@symbol_color, 'alpha', 25.5) WHEN @vector_tile_zoom >= 0 AND @vector_tile_zoom < 150 THEN set_color_part(@symbol_color, 'alpha', scale_linear(@vector_tile_zoom,0,150,25.5,38.25)) WHEN @vector_tile_zoom >= 150 AND @vector_tile_zoom < 250 THEN set_color_part(@symbol_color, 'alpha', scale_linear(@vector_tile_zoom,150,250,38.25,51)) WHEN @vector_tile_zoom >= 250 THEN set_color_part(@symbol_color, 'alpha', 51) END") - self.assertEqual(QgsMapBoxGlStyleConverter.parseInterpolateOpacityByZoom({'base': 1, - 'stops': [[0, 0.1], - [150, 0.15], - [250, 0.2]] - }, 100, - conversion_context).expressionString(), - "CASE WHEN @vector_tile_zoom < 0 THEN set_color_part(@symbol_color, 'alpha', 10) WHEN @vector_tile_zoom >= 0 AND @vector_tile_zoom < 150 THEN set_color_part(@symbol_color, 'alpha', scale_linear(@vector_tile_zoom,0,150,10,15)) WHEN @vector_tile_zoom >= 150 AND @vector_tile_zoom < 250 THEN set_color_part(@symbol_color, 'alpha', scale_linear(@vector_tile_zoom,150,250,15,20)) WHEN @vector_tile_zoom >= 250 THEN set_color_part(@symbol_color, 'alpha', 20) END") - self.assertEqual(QgsMapBoxGlStyleConverter.parseInterpolateOpacityByZoom({'base': 1, - 'stops': [[0, 0.1], - [150, 0.15]] - }, 255, - conversion_context).expressionString(), - "set_color_part(@symbol_color, 'alpha', scale_linear(@vector_tile_zoom,0,150,25.5,38.25))") - self.assertEqual(QgsMapBoxGlStyleConverter.parseInterpolateOpacityByZoom({'base': 2, - 'stops': [[0, 0.1], - [150, 0.15]] - }, 255, - conversion_context).expressionString(), - "set_color_part(@symbol_color, 'alpha', scale_exponential(@vector_tile_zoom,0,150,25.5,38.25,2))") - self.assertEqual(QgsMapBoxGlStyleConverter.parseInterpolateOpacityByZoom({'base': 2, - 'stops': [[0, 0.1], - [150, 0.1]] - }, 255, - conversion_context).expressionString(), - "set_color_part(@symbol_color, 'alpha', 25.5)") - - self.assertEqual(QgsMapBoxGlStyleConverter.parseInterpolateOpacityByZoom({'base': 2, - 'stops': [ - [10, 0], - [11, ["match", ["get", "class"], ["path"], 0.5, 0]], - [13, ["match", ["get", "class"], ["path"], 1, 0.5]]] - }, 255, - conversion_context).expressionString(), - ('''CASE WHEN @vector_tile_zoom < 10 THEN set_color_part(@symbol_color, 'alpha', 0) ''' - '''WHEN @vector_tile_zoom >= 10 AND @vector_tile_zoom < 11 THEN set_color_part(@symbol_color, 'alpha', scale_exponential(@vector_tile_zoom,10,11,(0) * 255,(CASE WHEN "class" = 'path' THEN 0.5 ELSE 0 END) * 255,2)) ''' - '''WHEN @vector_tile_zoom >= 11 AND @vector_tile_zoom < 13 THEN set_color_part(@symbol_color, 'alpha', scale_exponential(@vector_tile_zoom,11,13,(CASE WHEN "class" = 'path' THEN 0.5 ELSE 0 END) * 255,(CASE WHEN "class" = 'path' THEN 1 ELSE 0.5 END) * 255,2)) ''' - '''WHEN @vector_tile_zoom >= 13 THEN set_color_part(@symbol_color, 'alpha', (CASE WHEN "class" = 'path' THEN 1 ELSE 0.5 END) * 255) END''')) + self.assertEqual( + QgsMapBoxGlStyleConverter.parseInterpolateOpacityByZoom( + {"base": 1, "stops": [[0, 0.1], [150, 0.15], [250, 0.2]]}, + 255, + conversion_context, + ).expressionString(), + "CASE WHEN @vector_tile_zoom < 0 THEN set_color_part(@symbol_color, 'alpha', 25.5) WHEN @vector_tile_zoom >= 0 AND @vector_tile_zoom < 150 THEN set_color_part(@symbol_color, 'alpha', scale_linear(@vector_tile_zoom,0,150,25.5,38.25)) WHEN @vector_tile_zoom >= 150 AND @vector_tile_zoom < 250 THEN set_color_part(@symbol_color, 'alpha', scale_linear(@vector_tile_zoom,150,250,38.25,51)) WHEN @vector_tile_zoom >= 250 THEN set_color_part(@symbol_color, 'alpha', 51) END", + ) + self.assertEqual( + QgsMapBoxGlStyleConverter.parseInterpolateOpacityByZoom( + {"base": 1, "stops": [[0, 0.1], [150, 0.15], [250, 0.2]]}, + 100, + conversion_context, + ).expressionString(), + "CASE WHEN @vector_tile_zoom < 0 THEN set_color_part(@symbol_color, 'alpha', 10) WHEN @vector_tile_zoom >= 0 AND @vector_tile_zoom < 150 THEN set_color_part(@symbol_color, 'alpha', scale_linear(@vector_tile_zoom,0,150,10,15)) WHEN @vector_tile_zoom >= 150 AND @vector_tile_zoom < 250 THEN set_color_part(@symbol_color, 'alpha', scale_linear(@vector_tile_zoom,150,250,15,20)) WHEN @vector_tile_zoom >= 250 THEN set_color_part(@symbol_color, 'alpha', 20) END", + ) + self.assertEqual( + QgsMapBoxGlStyleConverter.parseInterpolateOpacityByZoom( + {"base": 1, "stops": [[0, 0.1], [150, 0.15]]}, 255, conversion_context + ).expressionString(), + "set_color_part(@symbol_color, 'alpha', scale_linear(@vector_tile_zoom,0,150,25.5,38.25))", + ) + self.assertEqual( + QgsMapBoxGlStyleConverter.parseInterpolateOpacityByZoom( + {"base": 2, "stops": [[0, 0.1], [150, 0.15]]}, 255, conversion_context + ).expressionString(), + "set_color_part(@symbol_color, 'alpha', scale_exponential(@vector_tile_zoom,0,150,25.5,38.25,2))", + ) + self.assertEqual( + QgsMapBoxGlStyleConverter.parseInterpolateOpacityByZoom( + {"base": 2, "stops": [[0, 0.1], [150, 0.1]]}, 255, conversion_context + ).expressionString(), + "set_color_part(@symbol_color, 'alpha', 25.5)", + ) + + self.assertEqual( + QgsMapBoxGlStyleConverter.parseInterpolateOpacityByZoom( + { + "base": 2, + "stops": [ + [10, 0], + [11, ["match", ["get", "class"], ["path"], 0.5, 0]], + [13, ["match", ["get", "class"], ["path"], 1, 0.5]], + ], + }, + 255, + conversion_context, + ).expressionString(), + ( + """CASE WHEN @vector_tile_zoom < 10 THEN set_color_part(@symbol_color, 'alpha', 0) """ + """WHEN @vector_tile_zoom >= 10 AND @vector_tile_zoom < 11 THEN set_color_part(@symbol_color, 'alpha', scale_exponential(@vector_tile_zoom,10,11,(0) * 255,(CASE WHEN "class" = 'path' THEN 0.5 ELSE 0 END) * 255,2)) """ + """WHEN @vector_tile_zoom >= 11 AND @vector_tile_zoom < 13 THEN set_color_part(@symbol_color, 'alpha', scale_exponential(@vector_tile_zoom,11,13,(CASE WHEN "class" = 'path' THEN 0.5 ELSE 0 END) * 255,(CASE WHEN "class" = 'path' THEN 1 ELSE 0.5 END) * 255,2)) """ + """WHEN @vector_tile_zoom >= 13 THEN set_color_part(@symbol_color, 'alpha', (CASE WHEN "class" = 'path' THEN 1 ELSE 0.5 END) * 255) END""" + ), + ) def testInterpolateListByZoom(self): conversion_context = QgsMapBoxGlStyleConversionContext() - prop, default_color, default_val = QgsMapBoxGlStyleConverter.parseInterpolateListByZoom([ - "interpolate", - ["linear"], - ["zoom"], - 10, - 0.1, - 15, - 0.3, - 18, - 0.6 - ], QgsMapBoxGlStyleConverter.PropertyType.Opacity, conversion_context, 2) - self.assertEqual(prop.expressionString(), - "CASE WHEN @vector_tile_zoom < 10 THEN set_color_part(@symbol_color, 'alpha', 25.5) WHEN @vector_tile_zoom >= 10 AND @vector_tile_zoom < 15 THEN set_color_part(@symbol_color, 'alpha', scale_linear(@vector_tile_zoom,10,15,25.5,76.5)) WHEN @vector_tile_zoom >= 15 AND @vector_tile_zoom < 18 THEN set_color_part(@symbol_color, 'alpha', scale_linear(@vector_tile_zoom,15,18,76.5,153)) WHEN @vector_tile_zoom >= 18 THEN set_color_part(@symbol_color, 'alpha', 153) END") - - prop, default_color, default_val = QgsMapBoxGlStyleConverter.parseInterpolateListByZoom([ - "interpolate", - ["linear"], - ["zoom"], - 10, - 0.1, - 15, - 0.3, - 18, - 0.6 - ], QgsMapBoxGlStyleConverter.PropertyType.Numeric, conversion_context, 2) - self.assertEqual(prop.expressionString(), - "CASE WHEN @vector_tile_zoom >= 10 AND @vector_tile_zoom <= 15 THEN (scale_linear(@vector_tile_zoom,10,15,0.1,0.3)) * 2 WHEN @vector_tile_zoom > 15 AND @vector_tile_zoom <= 18 THEN (scale_linear(@vector_tile_zoom,15,18,0.3,0.6)) * 2 WHEN @vector_tile_zoom > 18 THEN 1.2 END") + prop, default_color, default_val = ( + QgsMapBoxGlStyleConverter.parseInterpolateListByZoom( + ["interpolate", ["linear"], ["zoom"], 10, 0.1, 15, 0.3, 18, 0.6], + QgsMapBoxGlStyleConverter.PropertyType.Opacity, + conversion_context, + 2, + ) + ) + self.assertEqual( + prop.expressionString(), + "CASE WHEN @vector_tile_zoom < 10 THEN set_color_part(@symbol_color, 'alpha', 25.5) WHEN @vector_tile_zoom >= 10 AND @vector_tile_zoom < 15 THEN set_color_part(@symbol_color, 'alpha', scale_linear(@vector_tile_zoom,10,15,25.5,76.5)) WHEN @vector_tile_zoom >= 15 AND @vector_tile_zoom < 18 THEN set_color_part(@symbol_color, 'alpha', scale_linear(@vector_tile_zoom,15,18,76.5,153)) WHEN @vector_tile_zoom >= 18 THEN set_color_part(@symbol_color, 'alpha', 153) END", + ) + + prop, default_color, default_val = ( + QgsMapBoxGlStyleConverter.parseInterpolateListByZoom( + ["interpolate", ["linear"], ["zoom"], 10, 0.1, 15, 0.3, 18, 0.6], + QgsMapBoxGlStyleConverter.PropertyType.Numeric, + conversion_context, + 2, + ) + ) + self.assertEqual( + prop.expressionString(), + "CASE WHEN @vector_tile_zoom >= 10 AND @vector_tile_zoom <= 15 THEN (scale_linear(@vector_tile_zoom,10,15,0.1,0.3)) * 2 WHEN @vector_tile_zoom > 15 AND @vector_tile_zoom <= 18 THEN (scale_linear(@vector_tile_zoom,15,18,0.3,0.6)) * 2 WHEN @vector_tile_zoom > 18 THEN 1.2 END", + ) self.assertEqual(default_val, 0.2) - prop, default_color, default_val = QgsMapBoxGlStyleConverter.parseInterpolateListByZoom([ - "interpolate", - ["exponential", 1.5], - ["zoom"], - 5, - 0, - 6, - ["match", ["get", "class"], ["ice", "glacier"], 0.3, 0], - 10, - ["match", ["get", "class"], ["ice", "glacier"], 0.2, 0], - 11, - ["match", ["get", "class"], ["ice", "glacier"], 0.2, 0.3], - 14, - ["match", ["get", "class"], ["ice", "glacier"], 0, 0.3] - ], QgsMapBoxGlStyleConverter.PropertyType.Numeric, conversion_context, 2) - self.assertEqual(prop.expressionString(), - ('''CASE WHEN @vector_tile_zoom >= 5 AND @vector_tile_zoom <= 6 THEN (scale_exponential(@vector_tile_zoom,5,6,0,CASE WHEN "class" IN ('ice', 'glacier') THEN 0.3 ELSE 0 END,1.5)) * 2 ''' - '''WHEN @vector_tile_zoom > 6 AND @vector_tile_zoom <= 10 THEN (scale_exponential(@vector_tile_zoom,6,10,CASE WHEN "class" IN ('ice', 'glacier') THEN 0.3 ELSE 0 END,CASE WHEN "class" IN ('ice', 'glacier') THEN 0.2 ELSE 0 END,1.5)) * 2 ''' - '''WHEN @vector_tile_zoom > 10 AND @vector_tile_zoom <= 11 THEN (scale_exponential(@vector_tile_zoom,10,11,CASE WHEN "class" IN ('ice', 'glacier') THEN 0.2 ELSE 0 END,CASE WHEN "class" IN ('ice', 'glacier') THEN 0.2 ELSE 0.3 END,1.5)) * 2 ''' - '''WHEN @vector_tile_zoom > 11 AND @vector_tile_zoom <= 14 THEN (scale_exponential(@vector_tile_zoom,11,14,CASE WHEN "class" IN ('ice', 'glacier') THEN 0.2 ELSE 0.3 END,CASE WHEN "class" IN ('ice', 'glacier') THEN 0 ELSE 0.3 END,1.5)) * 2 ''' - '''WHEN @vector_tile_zoom > 14 THEN ( ( CASE WHEN "class" IN ('ice', 'glacier') THEN 0 ELSE 0.3 END ) * 2 ) END''')) - - prop, default_col, default_val = QgsMapBoxGlStyleConverter.parseInterpolateListByZoom([ - "interpolate", - ["exponential", 1], - ["zoom"], - 12, ["case", ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], 0.75, 0], - 13, ["case", ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], 0.75, 0], - 14, ["case", ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], 1, 0], - 14.5, [ - "case", ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], 1.5, [ - "case", ["==", ["%", ["to-number", ["get", "ele"]], 20], 0], 0.75, 0] - ], - 15, [ - "case", ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], 1.75, [ - "case", ["==", ["%", ["to-number", ["get", "ele"]], 20], 0], 1, 0 - ] - ], - 16.5, ["case", ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], 2, [ - "case", ["==", ["%", ["to-number", ["get", "ele"]], 10], 0], 1, 0 - ] - ] - ], QgsMapBoxGlStyleConverter.PropertyType.Numeric, conversion_context, 0.264583) - self.assertEqual(prop.expressionString(), 'CASE WHEN @vector_tile_zoom >= 12 AND @vector_tile_zoom <= 13 THEN (CASE WHEN (to_real("ele") % 100 IS 0) THEN 0.75 ELSE 0 END) * 0.264583 WHEN @vector_tile_zoom > 13 AND @vector_tile_zoom <= 14 THEN (scale_linear(@vector_tile_zoom,13,14,CASE WHEN (to_real("ele") % 100 IS 0) THEN 0.75 ELSE 0 END,CASE WHEN (to_real("ele") % 100 IS 0) THEN 1 ELSE 0 END)) * 0.264583 WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 14.5 THEN (scale_linear(@vector_tile_zoom,14,14.5,CASE WHEN (to_real("ele") % 100 IS 0) THEN 1 ELSE 0 END,CASE WHEN (to_real("ele") % 100 IS 0) THEN 1.5 ELSE CASE WHEN (to_real("ele") % 20 IS 0) THEN 0.75 ELSE 0 END END)) * 0.264583 WHEN @vector_tile_zoom > 14.5 AND @vector_tile_zoom <= 15 THEN (scale_linear(@vector_tile_zoom,14.5,15,CASE WHEN (to_real("ele") % 100 IS 0) THEN 1.5 ELSE CASE WHEN (to_real("ele") % 20 IS 0) THEN 0.75 ELSE 0 END END,CASE WHEN (to_real("ele") % 100 IS 0) THEN 1.75 ELSE CASE WHEN (to_real("ele") % 20 IS 0) THEN 1 ELSE 0 END END)) * 0.264583 WHEN @vector_tile_zoom > 15 AND @vector_tile_zoom <= 16.5 THEN (scale_linear(@vector_tile_zoom,15,16.5,CASE WHEN (to_real("ele") % 100 IS 0) THEN 1.75 ELSE CASE WHEN (to_real("ele") % 20 IS 0) THEN 1 ELSE 0 END END,CASE WHEN (to_real("ele") % 100 IS 0) THEN 2 ELSE CASE WHEN (to_real("ele") % 10 IS 0) THEN 1 ELSE 0 END END)) * 0.264583 WHEN @vector_tile_zoom > 16.5 THEN ( ( CASE WHEN (to_real("ele") % 100 IS 0) THEN 2 ELSE CASE WHEN (to_real("ele") % 10 IS 0) THEN 1 ELSE 0 END END ) * 0.264583 ) END') + prop, default_color, default_val = ( + QgsMapBoxGlStyleConverter.parseInterpolateListByZoom( + [ + "interpolate", + ["exponential", 1.5], + ["zoom"], + 5, + 0, + 6, + ["match", ["get", "class"], ["ice", "glacier"], 0.3, 0], + 10, + ["match", ["get", "class"], ["ice", "glacier"], 0.2, 0], + 11, + ["match", ["get", "class"], ["ice", "glacier"], 0.2, 0.3], + 14, + ["match", ["get", "class"], ["ice", "glacier"], 0, 0.3], + ], + QgsMapBoxGlStyleConverter.PropertyType.Numeric, + conversion_context, + 2, + ) + ) + self.assertEqual( + prop.expressionString(), + ( + """CASE WHEN @vector_tile_zoom >= 5 AND @vector_tile_zoom <= 6 THEN (scale_exponential(@vector_tile_zoom,5,6,0,CASE WHEN "class" IN ('ice', 'glacier') THEN 0.3 ELSE 0 END,1.5)) * 2 """ + """WHEN @vector_tile_zoom > 6 AND @vector_tile_zoom <= 10 THEN (scale_exponential(@vector_tile_zoom,6,10,CASE WHEN "class" IN ('ice', 'glacier') THEN 0.3 ELSE 0 END,CASE WHEN "class" IN ('ice', 'glacier') THEN 0.2 ELSE 0 END,1.5)) * 2 """ + """WHEN @vector_tile_zoom > 10 AND @vector_tile_zoom <= 11 THEN (scale_exponential(@vector_tile_zoom,10,11,CASE WHEN "class" IN ('ice', 'glacier') THEN 0.2 ELSE 0 END,CASE WHEN "class" IN ('ice', 'glacier') THEN 0.2 ELSE 0.3 END,1.5)) * 2 """ + """WHEN @vector_tile_zoom > 11 AND @vector_tile_zoom <= 14 THEN (scale_exponential(@vector_tile_zoom,11,14,CASE WHEN "class" IN ('ice', 'glacier') THEN 0.2 ELSE 0.3 END,CASE WHEN "class" IN ('ice', 'glacier') THEN 0 ELSE 0.3 END,1.5)) * 2 """ + """WHEN @vector_tile_zoom > 14 THEN ( ( CASE WHEN "class" IN ('ice', 'glacier') THEN 0 ELSE 0.3 END ) * 2 ) END""" + ), + ) + + prop, default_col, default_val = ( + QgsMapBoxGlStyleConverter.parseInterpolateListByZoom( + [ + "interpolate", + ["exponential", 1], + ["zoom"], + 12, + [ + "case", + ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], + 0.75, + 0, + ], + 13, + [ + "case", + ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], + 0.75, + 0, + ], + 14, + [ + "case", + ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], + 1, + 0, + ], + 14.5, + [ + "case", + ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], + 1.5, + [ + "case", + ["==", ["%", ["to-number", ["get", "ele"]], 20], 0], + 0.75, + 0, + ], + ], + 15, + [ + "case", + ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], + 1.75, + [ + "case", + ["==", ["%", ["to-number", ["get", "ele"]], 20], 0], + 1, + 0, + ], + ], + 16.5, + [ + "case", + ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], + 2, + [ + "case", + ["==", ["%", ["to-number", ["get", "ele"]], 10], 0], + 1, + 0, + ], + ], + ], + QgsMapBoxGlStyleConverter.PropertyType.Numeric, + conversion_context, + 0.264583, + ) + ) + self.assertEqual( + prop.expressionString(), + 'CASE WHEN @vector_tile_zoom >= 12 AND @vector_tile_zoom <= 13 THEN (CASE WHEN (to_real("ele") % 100 IS 0) THEN 0.75 ELSE 0 END) * 0.264583 WHEN @vector_tile_zoom > 13 AND @vector_tile_zoom <= 14 THEN (scale_linear(@vector_tile_zoom,13,14,CASE WHEN (to_real("ele") % 100 IS 0) THEN 0.75 ELSE 0 END,CASE WHEN (to_real("ele") % 100 IS 0) THEN 1 ELSE 0 END)) * 0.264583 WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 14.5 THEN (scale_linear(@vector_tile_zoom,14,14.5,CASE WHEN (to_real("ele") % 100 IS 0) THEN 1 ELSE 0 END,CASE WHEN (to_real("ele") % 100 IS 0) THEN 1.5 ELSE CASE WHEN (to_real("ele") % 20 IS 0) THEN 0.75 ELSE 0 END END)) * 0.264583 WHEN @vector_tile_zoom > 14.5 AND @vector_tile_zoom <= 15 THEN (scale_linear(@vector_tile_zoom,14.5,15,CASE WHEN (to_real("ele") % 100 IS 0) THEN 1.5 ELSE CASE WHEN (to_real("ele") % 20 IS 0) THEN 0.75 ELSE 0 END END,CASE WHEN (to_real("ele") % 100 IS 0) THEN 1.75 ELSE CASE WHEN (to_real("ele") % 20 IS 0) THEN 1 ELSE 0 END END)) * 0.264583 WHEN @vector_tile_zoom > 15 AND @vector_tile_zoom <= 16.5 THEN (scale_linear(@vector_tile_zoom,15,16.5,CASE WHEN (to_real("ele") % 100 IS 0) THEN 1.75 ELSE CASE WHEN (to_real("ele") % 20 IS 0) THEN 1 ELSE 0 END END,CASE WHEN (to_real("ele") % 100 IS 0) THEN 2 ELSE CASE WHEN (to_real("ele") % 10 IS 0) THEN 1 ELSE 0 END END)) * 0.264583 WHEN @vector_tile_zoom > 16.5 THEN ( ( CASE WHEN (to_real("ele") % 100 IS 0) THEN 2 ELSE CASE WHEN (to_real("ele") % 10 IS 0) THEN 1 ELSE 0 END END ) * 0.264583 ) END', + ) def testParseExpression(self): conversion_context = QgsMapBoxGlStyleConversionContext() - self.assertEqual(QgsMapBoxGlStyleConverter.parseExpression([ - "all", - ["==", ["get", "level"], 0], - ["match", ["get", "type"], ["Restricted"], True, False] - ], conversion_context), - '''(level IS 0) AND ("type" = 'Restricted')''') - - self.assertEqual(QgsMapBoxGlStyleConverter.parseExpression([ - "match", ["get", "type"], ["Restricted"], True, False - ], conversion_context), - '''"type" = 'Restricted\'''') - - self.assertEqual(QgsMapBoxGlStyleConverter.parseExpression([ - "match", ["get", "type"], ["Restricted"], "r", ["Local"], "l", ["Secondary", "Main"], "m", "n" - ], conversion_context), - '''CASE WHEN "type" = 'Restricted' THEN 'r' WHEN "type" = 'Local' THEN 'l' WHEN "type" IN ('Secondary', 'Main') THEN 'm' ELSE 'n' END''') - - self.assertEqual(QgsMapBoxGlStyleConverter.parseExpression([ - "all", - ["==", ["get", "level"], 0], - ["match", ["get", "type"], ["Restricted", "Temporary"], True, False] - ], conversion_context), - '''(level IS 0) AND ("type" IN ('Restricted', 'Temporary'))''') - self.assertEqual(QgsMapBoxGlStyleConverter.parseExpression([ - "any", - ["match", ["get", "level"], [1], True, False], - ["match", ["get", "type"], ["Local"], True, False] - ], conversion_context), - '''("level" = 1) OR ("type" = 'Local')''') - self.assertEqual(QgsMapBoxGlStyleConverter.parseExpression([ - "none", - ["match", ["get", "level"], [1], True, False], - ["match", ["get", "type"], ["Local"], True, False] - ], conversion_context), - '''NOT ("level" = 1) AND NOT ("type" = 'Local')''') - self.assertEqual(QgsMapBoxGlStyleConverter.parseExpression([ - "match", - ["get", "type"], - ["Primary", "Motorway"], - False, - True - ], conversion_context), - '''CASE WHEN "type" IN ('Primary', 'Motorway') THEN FALSE ELSE TRUE END''') - self.assertEqual(QgsMapBoxGlStyleConverter.parseExpression(["==", "_symbol", 0], conversion_context), - '''"_symbol" IS 0''') - - self.assertEqual(QgsMapBoxGlStyleConverter.parseExpression(["all", ["==", "_symbol", 8], ["!in", "Viz", 3]], - conversion_context), - '''("_symbol" IS 8) AND (("Viz" IS NULL OR "Viz" NOT IN (3)))''') - - self.assertEqual(QgsMapBoxGlStyleConverter.parseExpression(["get", "name"], - conversion_context), - '''"name"''') - - self.assertEqual(QgsMapBoxGlStyleConverter.parseExpression(["to-boolean", ["get", "name"]], - conversion_context), - '''to_bool("name")''') - self.assertEqual(QgsMapBoxGlStyleConverter.parseExpression(["to-string", ["get", "name"]], - conversion_context), - '''to_string("name")''') - self.assertEqual(QgsMapBoxGlStyleConverter.parseExpression(["to-number", ["get", "elevation"]], - conversion_context), - '''to_real("elevation")''') - self.assertEqual(QgsMapBoxGlStyleConverter.parseExpression(["%", 100, 20], - conversion_context), - '''100 % 20''') - self.assertEqual(QgsMapBoxGlStyleConverter.parseExpression(["match", ["get", "subclass"], "funicular", "rgba(243,243,246,0)", "rgb(243,243,246)"], conversion_context, True), '''CASE WHEN ("subclass" = 'funicular') THEN color_rgba(243,243,246,0) ELSE color_rgba(243,243,246,255) END''') - - self.assertEqual(QgsMapBoxGlStyleConverter.parseExpression(["case", ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], 0.75, 0], conversion_context, False), '''CASE WHEN (to_real("ele") % 100 IS 0) THEN 0.75 ELSE 0 END''') - - self.assertEqual(QgsMapBoxGlStyleConverter.parseExpression(["concat", ["get", "numero"], ["get", "indice_de_repetition"]], conversion_context, False), '''concat("numero", "indice_de_repetition")''') - - self.assertEqual(QgsMapBoxGlStyleConverter.parseExpression(["in", ["get", "subclass"], ["literal", ["allotments", "forest", "glacier"]]], conversion_context, True), '''"subclass" IN ('allotments', 'forest', 'glacier')''') + self.assertEqual( + QgsMapBoxGlStyleConverter.parseExpression( + [ + "all", + ["==", ["get", "level"], 0], + ["match", ["get", "type"], ["Restricted"], True, False], + ], + conversion_context, + ), + """(level IS 0) AND ("type" = 'Restricted')""", + ) + + self.assertEqual( + QgsMapBoxGlStyleConverter.parseExpression( + ["match", ["get", "type"], ["Restricted"], True, False], + conversion_context, + ), + """"type" = 'Restricted\'""", + ) + + self.assertEqual( + QgsMapBoxGlStyleConverter.parseExpression( + [ + "match", + ["get", "type"], + ["Restricted"], + "r", + ["Local"], + "l", + ["Secondary", "Main"], + "m", + "n", + ], + conversion_context, + ), + """CASE WHEN "type" = 'Restricted' THEN 'r' WHEN "type" = 'Local' THEN 'l' WHEN "type" IN ('Secondary', 'Main') THEN 'm' ELSE 'n' END""", + ) + + self.assertEqual( + QgsMapBoxGlStyleConverter.parseExpression( + [ + "all", + ["==", ["get", "level"], 0], + [ + "match", + ["get", "type"], + ["Restricted", "Temporary"], + True, + False, + ], + ], + conversion_context, + ), + """(level IS 0) AND ("type" IN ('Restricted', 'Temporary'))""", + ) + self.assertEqual( + QgsMapBoxGlStyleConverter.parseExpression( + [ + "any", + ["match", ["get", "level"], [1], True, False], + ["match", ["get", "type"], ["Local"], True, False], + ], + conversion_context, + ), + """("level" = 1) OR ("type" = 'Local')""", + ) + self.assertEqual( + QgsMapBoxGlStyleConverter.parseExpression( + [ + "none", + ["match", ["get", "level"], [1], True, False], + ["match", ["get", "type"], ["Local"], True, False], + ], + conversion_context, + ), + """NOT ("level" = 1) AND NOT ("type" = 'Local')""", + ) + self.assertEqual( + QgsMapBoxGlStyleConverter.parseExpression( + ["match", ["get", "type"], ["Primary", "Motorway"], False, True], + conversion_context, + ), + """CASE WHEN "type" IN ('Primary', 'Motorway') THEN FALSE ELSE TRUE END""", + ) + self.assertEqual( + QgsMapBoxGlStyleConverter.parseExpression( + ["==", "_symbol", 0], conversion_context + ), + """"_symbol" IS 0""", + ) + + self.assertEqual( + QgsMapBoxGlStyleConverter.parseExpression( + ["all", ["==", "_symbol", 8], ["!in", "Viz", 3]], conversion_context + ), + """("_symbol" IS 8) AND (("Viz" IS NULL OR "Viz" NOT IN (3)))""", + ) + + self.assertEqual( + QgsMapBoxGlStyleConverter.parseExpression( + ["get", "name"], conversion_context + ), + '''"name"''', + ) + + self.assertEqual( + QgsMapBoxGlStyleConverter.parseExpression( + ["to-boolean", ["get", "name"]], conversion_context + ), + """to_bool("name")""", + ) + self.assertEqual( + QgsMapBoxGlStyleConverter.parseExpression( + ["to-string", ["get", "name"]], conversion_context + ), + """to_string("name")""", + ) + self.assertEqual( + QgsMapBoxGlStyleConverter.parseExpression( + ["to-number", ["get", "elevation"]], conversion_context + ), + """to_real("elevation")""", + ) + self.assertEqual( + QgsMapBoxGlStyleConverter.parseExpression( + ["%", 100, 20], conversion_context + ), + """100 % 20""", + ) + self.assertEqual( + QgsMapBoxGlStyleConverter.parseExpression( + [ + "match", + ["get", "subclass"], + "funicular", + "rgba(243,243,246,0)", + "rgb(243,243,246)", + ], + conversion_context, + True, + ), + """CASE WHEN ("subclass" = 'funicular') THEN color_rgba(243,243,246,0) ELSE color_rgba(243,243,246,255) END""", + ) + + self.assertEqual( + QgsMapBoxGlStyleConverter.parseExpression( + ["case", ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], 0.75, 0], + conversion_context, + False, + ), + """CASE WHEN (to_real("ele") % 100 IS 0) THEN 0.75 ELSE 0 END""", + ) + + self.assertEqual( + QgsMapBoxGlStyleConverter.parseExpression( + ["concat", ["get", "numero"], ["get", "indice_de_repetition"]], + conversion_context, + False, + ), + """concat("numero", "indice_de_repetition")""", + ) + + self.assertEqual( + QgsMapBoxGlStyleConverter.parseExpression( + [ + "in", + ["get", "subclass"], + ["literal", ["allotments", "forest", "glacier"]], + ], + conversion_context, + True, + ), + """"subclass" IN ('allotments', 'forest', 'glacier')""", + ) # fix last (default) value of a match can be a match self.assertEqual( QgsMapBoxGlStyleConverter.parseExpression( - ["match", ["get", "is_route"], [5, 10], "hsl(16,91%,80%)", [6, 7, 8], "hsl(55,91%,80%)", ["match", ["get", "class"], ["motorway", "trunk", "motorway_construction", "trunk_construction"], "hsl(41,93%,73%)", ["rail", "rail_construction", "path", "path_construction", "footway", "footway_construction", "track", "track_construction", "trail", "trail_construction"], ["match", ["get", "subclass"], "covered_bridge", "rgb(255,255,255)", "rgb(238,238,240)"], "rgba(255,255,255,1)"]], - conversion_context, True + [ + "match", + ["get", "is_route"], + [5, 10], + "hsl(16,91%,80%)", + [6, 7, 8], + "hsl(55,91%,80%)", + [ + "match", + ["get", "class"], + [ + "motorway", + "trunk", + "motorway_construction", + "trunk_construction", + ], + "hsl(41,93%,73%)", + [ + "rail", + "rail_construction", + "path", + "path_construction", + "footway", + "footway_construction", + "track", + "track_construction", + "trail", + "trail_construction", + ], + [ + "match", + ["get", "subclass"], + "covered_bridge", + "rgb(255,255,255)", + "rgb(238,238,240)", + ], + "rgba(255,255,255,1)", + ], + ], + conversion_context, + True, ), - '''CASE WHEN "is_route" IN (5, 10) THEN color_rgba(250,182,158,255) WHEN "is_route" IN (6, 7, 8) THEN color_rgba(250,243,158,255) ELSE CASE WHEN "class" IN ('motorway', 'trunk', 'motorway_construction', 'trunk_construction') THEN color_rgba(250,210,122,255) WHEN "class" IN ('rail', 'rail_construction', 'path', 'path_construction', 'footway', 'footway_construction', 'track', 'track_construction', 'trail', 'trail_construction') THEN CASE WHEN ("subclass" = 'covered_bridge') THEN color_rgba(255,255,255,255) ELSE color_rgba(238,238,240,255) END ELSE color_rgba(255,255,255,255) END END''' + """CASE WHEN "is_route" IN (5, 10) THEN color_rgba(250,182,158,255) WHEN "is_route" IN (6, 7, 8) THEN color_rgba(250,243,158,255) ELSE CASE WHEN "class" IN ('motorway', 'trunk', 'motorway_construction', 'trunk_construction') THEN color_rgba(250,210,122,255) WHEN "class" IN ('rail', 'rail_construction', 'path', 'path_construction', 'footway', 'footway_construction', 'track', 'track_construction', 'trail', 'trail_construction') THEN CASE WHEN ("subclass" = 'covered_bridge') THEN color_rgba(255,255,255,255) ELSE color_rgba(238,238,240,255) END ELSE color_rgba(255,255,255,255) END END""", ) self.assertEqual( QgsMapBoxGlStyleConverter.parseExpression( - ["step", ["zoom"], "", 16, ["case", ["has", "flstnrnen"], ["concat", ["get", "flstnrzae"], "/", ["get", "flstnrnen"]], ["get", "flstnrzae"]]], - conversion_context, True + [ + "step", + ["zoom"], + "", + 16, + [ + "case", + ["has", "flstnrnen"], + ["concat", ["get", "flstnrzae"], "/", ["get", "flstnrnen"]], + ["get", "flstnrzae"], + ], + ], + conversion_context, + True, ), - '''CASE WHEN @vector_tile_zoom >= 16 THEN (CASE WHEN ("flstnrnen" IS NOT NULL) THEN concat("flstnrzae", '/', "flstnrnen") ELSE "flstnrzae" END) ELSE ('') END''' + """CASE WHEN @vector_tile_zoom >= 16 THEN (CASE WHEN ("flstnrnen" IS NOT NULL) THEN concat("flstnrzae", '/', "flstnrnen") ELSE "flstnrzae" END) ELSE ('') END""", ) def testConvertLabels(self): @@ -571,14 +895,11 @@ def testConvertLabels(self): style = { "layout": { "text-field": "{name_en}", - "text-font": [ - "Open Sans Semibold", - "Arial Unicode MS Bold" - ], + "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"], "text-max-width": 8, "text-anchor": "top", "text-size": 11, - "icon-size": 1 + "icon-size": 1, }, "type": "symbol", "id": "poi_label", @@ -586,57 +907,58 @@ def testConvertLabels(self): "text-color": "#666", "text-halo-width": 1.5, "text-halo-color": "rgba(255,255,255,0.95)", - "text-halo-blur": 1 + "text-halo-blur": 1, }, - "source-layer": "poi_label" + "source-layer": "poi_label", } - renderer, has_renderer, labeling, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + renderer, has_renderer, labeling, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertFalse(has_renderer) self.assertTrue(has_labeling) - self.assertEqual(labeling.labelSettings().fieldName, 'name_en') + self.assertEqual(labeling.labelSettings().fieldName, "name_en") self.assertFalse(labeling.labelSettings().isExpression) style = { "layout": { "text-field": "name_en", - "text-font": [ - "Open Sans Semibold", - "Arial Unicode MS Bold" - ], + "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"], "text-max-width": 8, "text-anchor": "top", "text-size": 11, - "icon-size": 1 + "icon-size": 1, }, "type": "symbol", "id": "poi_label", "paint": { "text-color": "#666", "text-halo-width": 1.5, - "text-halo-color": "rgba(255,255,255,0.95)" + "text-halo-color": "rgba(255,255,255,0.95)", }, - "source-layer": "poi_label" + "source-layer": "poi_label", } - renderer, has_renderer, labeling, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + renderer, has_renderer, labeling, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertFalse(has_renderer) self.assertTrue(has_labeling) - self.assertEqual(labeling.labelSettings().fieldName, 'name_en') + self.assertEqual(labeling.labelSettings().fieldName, "name_en") self.assertFalse(labeling.labelSettings().isExpression) style = { "layout": { - "text-field": ["format", - "foo", {"font-scale": 1.2}, - "bar", {"font-scale": 0.8} - ], - "text-font": [ - "Open Sans Semibold", - "Arial Unicode MS Bold" + "text-field": [ + "format", + "foo", + {"font-scale": 1.2}, + "bar", + {"font-scale": 0.8}, ], + "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"], "text-max-width": 8, "text-anchor": "top", "text-size": 11, - "icon-size": 1 + "icon-size": 1, }, "type": "symbol", "id": "poi_label", @@ -644,11 +966,13 @@ def testConvertLabels(self): "text-color": "#666", "text-halo-width": 1.5, "text-halo-color": "rgba(255,255,255,0.95)", - "text-halo-blur": 1 + "text-halo-blur": 1, }, - "source-layer": "poi_label" + "source-layer": "poi_label", } - renderer, has_renderer, labeling, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + renderer, has_renderer, labeling, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertFalse(has_renderer) self.assertTrue(has_labeling) self.assertEqual(labeling.labelSettings().fieldName, 'concat("foo","bar")') @@ -657,14 +981,11 @@ def testConvertLabels(self): style = { "layout": { "text-field": "{name_en} - {name_fr}", - "text-font": [ - "Open Sans Semibold", - "Arial Unicode MS Bold" - ], + "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"], "text-max-width": 8, "text-anchor": "top", "text-size": 11, - "icon-size": 1 + "icon-size": 1, }, "type": "symbol", "id": "poi_label", @@ -672,30 +993,34 @@ def testConvertLabels(self): "text-color": "#666", "text-halo-width": 1.5, "text-halo-color": "rgba(255,255,255,0.95)", - "text-halo-blur": 1 + "text-halo-blur": 1, }, - "source-layer": "poi_label" + "source-layer": "poi_label", } - renderer, has_renderer, labeling, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + renderer, has_renderer, labeling, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertFalse(has_renderer) self.assertTrue(has_labeling) - self.assertEqual(labeling.labelSettings().fieldName, '''concat("name_en",' - ',"name_fr")''') + self.assertEqual( + labeling.labelSettings().fieldName, """concat("name_en",' - ',"name_fr")""" + ) self.assertTrue(labeling.labelSettings().isExpression) style = { "layout": { - "text-field": ["format", - "{name_en} - {name_fr}", {"font-scale": 1.2}, - "bar", {"font-scale": 0.8} - ], - "text-font": [ - "Open Sans Semibold", - "Arial Unicode MS Bold" + "text-field": [ + "format", + "{name_en} - {name_fr}", + {"font-scale": 1.2}, + "bar", + {"font-scale": 0.8}, ], + "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"], "text-max-width": 8, "text-anchor": "top", "text-size": 11, - "icon-size": 1 + "icon-size": 1, }, "type": "symbol", "id": "poi_label", @@ -703,27 +1028,29 @@ def testConvertLabels(self): "text-color": "#666", "text-halo-width": 1.5, "text-halo-color": "rgba(255,255,255,0.95)", - "text-halo-blur": 1 + "text-halo-blur": 1, }, - "source-layer": "poi_label" + "source-layer": "poi_label", } - renderer, has_renderer, labeling, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + renderer, has_renderer, labeling, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertFalse(has_renderer) self.assertTrue(has_labeling) - self.assertEqual(labeling.labelSettings().fieldName, '''concat(concat("name_en",' - ',"name_fr"),"bar")''') + self.assertEqual( + labeling.labelSettings().fieldName, + """concat(concat("name_en",' - ',"name_fr"),"bar")""", + ) self.assertTrue(labeling.labelSettings().isExpression) style = { "layout": { "text-field": ["to-string", ["get", "name"]], - "text-font": [ - "Open Sans Semibold", - "Arial Unicode MS Bold" - ], + "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"], "text-max-width": 8, "text-anchor": "top", "text-size": 11, - "icon-size": 1 + "icon-size": 1, }, "type": "symbol", "id": "poi_label", @@ -731,29 +1058,28 @@ def testConvertLabels(self): "text-color": "#666", "text-halo-width": 1.5, "text-halo-color": "rgba(255,255,255,0.95)", - "text-halo-blur": 1 + "text-halo-blur": 1, }, - "source-layer": "poi_label" + "source-layer": "poi_label", } - renderer, has_renderer, labeling, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + renderer, has_renderer, labeling, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertFalse(has_renderer) self.assertTrue(has_labeling) - self.assertEqual(labeling.labelSettings().fieldName, '''to_string("name")''') + self.assertEqual(labeling.labelSettings().fieldName, """to_string("name")""") self.assertTrue(labeling.labelSettings().isExpression) # text-transform style = { "layout": { "text-field": "name_en", - "text-font": [ - "Open Sans Semibold", - "Arial Unicode MS Bold" - ], + "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"], "text-transform": "uppercase", "text-max-width": 8, "text-anchor": "top", "text-size": 11, - "icon-size": 1 + "icon-size": 1, }, "type": "symbol", "id": "poi_label", @@ -761,11 +1087,13 @@ def testConvertLabels(self): "text-color": "#666", "text-halo-width": 1.5, "text-halo-color": "rgba(255,255,255,0.95)", - "text-halo-blur": 1 + "text-halo-blur": 1, }, - "source-layer": "poi_label" + "source-layer": "poi_label", } - renderer, has_renderer, labeling, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + renderer, has_renderer, labeling, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertFalse(has_renderer) self.assertTrue(has_labeling) self.assertEqual(labeling.labelSettings().fieldName, 'upper("name_en")') @@ -773,19 +1101,19 @@ def testConvertLabels(self): style = { "layout": { - "text-field": ["format", - "{name_en} - {name_fr}", {"font-scale": 1.2}, - "bar", {"font-scale": 0.8} - ], - "text-font": [ - "Open Sans Semibold", - "Arial Unicode MS Bold" + "text-field": [ + "format", + "{name_en} - {name_fr}", + {"font-scale": 1.2}, + "bar", + {"font-scale": 0.8}, ], + "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"], "text-transform": "lowercase", "text-max-width": 8, "text-anchor": "top", "text-size": 11, - "icon-size": 1 + "icon-size": 1, }, "type": "symbol", "id": "poi_label", @@ -793,15 +1121,19 @@ def testConvertLabels(self): "text-color": "#666", "text-halo-width": 1.5, "text-halo-color": "rgba(255,255,255,0.95)", - "text-halo-blur": 1 + "text-halo-blur": 1, }, - "source-layer": "poi_label" + "source-layer": "poi_label", } - renderer, has_renderer, labeling, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + renderer, has_renderer, labeling, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertFalse(has_renderer) self.assertTrue(has_labeling) - self.assertEqual(labeling.labelSettings().fieldName, - '''lower(concat(concat("name_en",' - ',"name_fr"),"bar"))''') + self.assertEqual( + labeling.labelSettings().fieldName, + """lower(concat(concat("name_en",' - ',"name_fr"),"bar"))""", + ) self.assertTrue(labeling.labelSettings().isExpression) def testHaloMaxSize(self): @@ -818,23 +1150,30 @@ def testHaloMaxSize(self): (16, 3, 3, None), (16, 5, 4, None), (12, ["get", "some_field_1"], None, 'min(24/4, "some_field_1")'), - (["get", "some_field_2"], 4, None, f'min("some_field_2"*{BUFFER_SIZE_SCALE:.0f}/4, {BUFFER_SIZE_SCALE * 4:.0f})'), - (["get", "some_field_3"], ["get", "some_field_4"], None, f'min("some_field_3"*{BUFFER_SIZE_SCALE:.0f}/4, "some_field_4")'), + ( + ["get", "some_field_2"], + 4, + None, + f'min("some_field_2"*{BUFFER_SIZE_SCALE:.0f}/4, {BUFFER_SIZE_SCALE * 4:.0f})', + ), + ( + ["get", "some_field_3"], + ["get", "some_field_4"], + None, + f'min("some_field_3"*{BUFFER_SIZE_SCALE:.0f}/4, "some_field_4")', + ), ) - for (text_size, halo_size, expected_size, expected_data_defined) in data: + for text_size, halo_size, expected_size, expected_data_defined in data: style = { "layout": { "text-field": "name_en", - "text-font": [ - "Open Sans Semibold", - "Arial Unicode MS Bold" - ], + "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"], "text-transform": "uppercase", "text-max-width": 8, "text-anchor": "top", "text-size": text_size, - "icon-size": 1 + "icon-size": 1, }, "type": "symbol", "id": "poi_label", @@ -842,11 +1181,13 @@ def testHaloMaxSize(self): "text-color": "#666", "text-halo-width": halo_size, "text-halo-color": "rgba(255,255,255,0.95)", - "text-halo-blur": 1 + "text-halo-blur": 1, }, - "source-layer": "poi_label" + "source-layer": "poi_label", } - renderer, has_renderer, labeling, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + renderer, has_renderer, labeling, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertFalse(has_renderer) self.assertTrue(has_labeling) if expected_size: @@ -856,21 +1197,21 @@ def testHaloMaxSize(self): if expected_data_defined: ls = labeling.labelSettings() dd = ls.dataDefinedProperties() - self.assertEqual(dd.property(QgsPalLayerSettings.Property.BufferSize).asExpression(), expected_data_defined) + self.assertEqual( + dd.property(QgsPalLayerSettings.Property.BufferSize).asExpression(), + expected_data_defined, + ) def testFontFamilyReplacement(self): context = QgsMapBoxGlStyleConversionContext() style = { "layout": { "text-field": "{name_en}", - "text-font": [ - "not a font", - "also not a font" - ], + "text-font": ["not a font", "also not a font"], "text-max-width": 8, "text-anchor": "top", "text-size": 11, - "icon-size": 1 + "icon-size": 1, }, "type": "symbol", "id": "poi_label", @@ -878,41 +1219,55 @@ def testFontFamilyReplacement(self): "text-color": "#666", "text-halo-width": 1.5, "text-halo-color": "rgba(255,255,255,0.95)", - "text-halo-blur": 1 + "text-halo-blur": 1, }, - "source-layer": "poi_label" + "source-layer": "poi_label", } - renderer, has_renderer, labeling, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + renderer, has_renderer, labeling, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertFalse(has_renderer) self.assertTrue(has_labeling) test_font = getTestFont() - self.assertNotEqual(labeling.labelSettings().format().font().family(), test_font.family()) + self.assertNotEqual( + labeling.labelSettings().format().font().family(), test_font.family() + ) # with a font replacement - QgsApplication.fontManager().addFontFamilyReplacement('not a font', test_font.family()) - renderer, has_renderer, labeling, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + QgsApplication.fontManager().addFontFamilyReplacement( + "not a font", test_font.family() + ) + renderer, has_renderer, labeling, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertFalse(has_renderer) self.assertTrue(has_labeling) - self.assertEqual(labeling.labelSettings().format().font().family(), test_font.family()) + self.assertEqual( + labeling.labelSettings().format().font().family(), test_font.family() + ) def testDataDefinedIconRotate(self): - """ Test icon-rotate property that depends on a data attribute """ + """Test icon-rotate property that depends on a data attribute""" context = QgsMapBoxGlStyleConversionContext() image = QImage(QSize(1, 1), QImage.Format.Format_ARGB32) - context.setSprites(image, {"foo": {"x": 0, "y": 0, "width": 1, "height": 1, "pixelRatio": 1}}) + context.setSprites( + image, {"foo": {"x": 0, "y": 0, "width": 1, "height": 1, "pixelRatio": 1}} + ) style = { "layout": { "icon-image": "{foo}", "icon-rotate": ["get", "ROTATION"], "text-size": 11, - "icon-size": 1 + "icon-size": 1, }, "type": "symbol", "id": "poi_label", - "source-layer": "poi_label" + "source-layer": "poi_label", } - renderer, has_renderer, labeling, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + renderer, has_renderer, labeling, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertTrue(has_renderer) self.assertFalse(has_labeling) dd_props = renderer.symbol().symbolLayers()[0].dataDefinedProperties() @@ -920,29 +1275,31 @@ def testDataDefinedIconRotate(self): self.assertEqual(prop.asExpression(), '"ROTATION"') def testScaledIcon(self): - """ Test icon-size property that depends on a data attribute """ + """Test icon-size property that depends on a data attribute""" context = QgsMapBoxGlStyleConversionContext() image = QImage(QSize(1, 1), QImage.Format.Format_ARGB32) - context.setSprites(image, {"foo": {"x": 0, "y": 0, "width": 2, "height": 2, "pixelRatio": 1}}) + context.setSprites( + image, {"foo": {"x": 0, "y": 0, "width": 2, "height": 2, "pixelRatio": 1}} + ) style = { - "layout": { - "icon-image": "{foo}", - "text-size": 11, - "icon-size": 2 - }, + "layout": {"icon-image": "{foo}", "text-size": 11, "icon-size": 2}, "type": "symbol", "id": "poi_label", - "source-layer": "poi_label" + "source-layer": "poi_label", } - renderer, has_renderer, labeling, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + renderer, has_renderer, labeling, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertTrue(has_renderer) self.assertFalse(has_labeling) size = renderer.symbol().symbolLayers()[0].size() self.assertEqual(size, 4) image = QImage(QSize(1, 1), QImage.Format.Format_ARGB32) - context.setSprites(image, {"foo": {"x": 0, "y": 0, "width": 2, "height": 2, "pixelRatio": 1}}) + context.setSprites( + image, {"foo": {"x": 0, "y": 0, "width": 2, "height": 2, "pixelRatio": 1}} + ) style = { "id": "landcover_pt", "type": "symbol", @@ -950,25 +1307,42 @@ def testScaledIcon(self): "source-layer": "landcover_pt", "minzoom": 14.0, "layout": { - "icon-size": ["interpolate", ["exponential", 1.6], ["zoom"], 14, 0.2, 18, 1], + "icon-size": [ + "interpolate", + ["exponential", 1.6], + ["zoom"], + 14, + 0.2, + 18, + 1, + ], "text-font": [], "icon-image": "{foo}", "visibility": "visible", "icon-allow-overlap": False, "icon-pitch-alignment": "map", "icon-ignore-placement": False, - "icon-rotation-alignment": "map" + "icon-rotation-alignment": "map", }, - "paint": {"icon-opacity": {"stops": [[14, 0.4], [18, 0.6]]}} + "paint": {"icon-opacity": {"stops": [[14, 0.4], [18, 0.6]]}}, } - renderer, has_renderer, labeling, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + renderer, has_renderer, labeling, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertTrue(has_renderer) dd_properties = renderer.symbol().symbolLayers()[0].dataDefinedProperties() - self.assertEqual(dd_properties.property(QgsSymbolLayer.Property.PropertyWidth).asExpression(), - '''with_variable('marker_size',CASE WHEN "foo" = 'foo' THEN 2 END,(scale_exponential(@vector_tile_zoom,14,18,0.2,1,1.6))*@marker_size)''') + self.assertEqual( + dd_properties.property( + QgsSymbolLayer.Property.PropertyWidth + ).asExpression(), + """with_variable('marker_size',CASE WHEN "foo" = 'foo' THEN 2 END,(scale_exponential(@vector_tile_zoom,14,18,0.2,1,1.6))*@marker_size)""", + ) image = QImage(QSize(1, 1), QImage.Format.Format_ARGB32) - context.setSprites(image, {"arrow_blue": {"x": 0, "y": 0, "width": 2, "height": 2, "pixelRatio": 1}}) + context.setSprites( + image, + {"arrow_blue": {"x": 0, "y": 0, "width": 2, "height": 2, "pixelRatio": 1}}, + ) style = { "id": "contour_line_pt_100", "type": "symbol", @@ -976,14 +1350,44 @@ def testScaledIcon(self): "source-layer": "contour_line_pt", "minzoom": 13.0, "layout": { - "icon-size": ["interpolate", ["linear"], ["zoom"], 13, 0.6, 14, 0.7, 16, 0.9], + "icon-size": [ + "interpolate", + ["linear"], + ["zoom"], + 13, + 0.6, + 14, + 0.7, + 16, + 0.9, + ], "text-font": ["Frutiger Neue Italic"], - "text-size": ["interpolate", ["exponential", 2], ["zoom"], 13, 10, 14, 10.5, 16, 14], + "text-size": [ + "interpolate", + ["exponential", 2], + ["zoom"], + 13, + 10, + 14, + 10.5, + 16, + 14, + ], "icon-image": ["case", ["has", "lake_depth"], "arrow_blue", ""], - "text-field": ["case", ["has", "lake_depth"], ["get", "lake_depth"], ["get", "ele"]], + "text-field": [ + "case", + ["has", "lake_depth"], + ["get", "lake_depth"], + ["get", "ele"], + ], "visibility": "visible", "icon-anchor": "center", - "icon-offset": ["case", ["has", "lake_depth"], ["literal", [-20, 0]], ["literal", [0, 0]]], + "icon-offset": [ + "case", + ["has", "lake_depth"], + ["literal", [-20, 0]], + ["literal", [0, 0]], + ], "icon-rotate": ["get", "direction"], "text-anchor": "center", "text-rotate": ["get", "direction"], @@ -996,21 +1400,29 @@ def testScaledIcon(self): "text-letter-spacing": 0.1, "icon-pitch-alignment": "map", "icon-rotation-alignment": "map", - "text-rotation-alignment": "map" - } + "text-rotation-alignment": "map", + }, } - renderer, has_renderer, labeling, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + renderer, has_renderer, labeling, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertTrue(has_renderer) dd_properties = renderer.symbol().symbolLayers()[0].dataDefinedProperties() - self.assertEqual(dd_properties.property(QgsSymbolLayer.Property.PropertyWidth).asExpression(), - '''with_variable('marker_size',CASE WHEN "lake_depth" IS NOT NULL THEN 2 ELSE 2 END,(CASE WHEN @vector_tile_zoom >= 13 AND @vector_tile_zoom <= 14 THEN scale_linear(@vector_tile_zoom,13,14,0.6,0.7) WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 16 THEN scale_linear(@vector_tile_zoom,14,16,0.7,0.9) WHEN @vector_tile_zoom > 16 THEN 0.9 END)*@marker_size)''') + self.assertEqual( + dd_properties.property( + QgsSymbolLayer.Property.PropertyWidth + ).asExpression(), + """with_variable('marker_size',CASE WHEN "lake_depth" IS NOT NULL THEN 2 ELSE 2 END,(CASE WHEN @vector_tile_zoom >= 13 AND @vector_tile_zoom <= 14 THEN scale_linear(@vector_tile_zoom,13,14,0.6,0.7) WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 16 THEN scale_linear(@vector_tile_zoom,14,16,0.7,0.9) WHEN @vector_tile_zoom > 16 THEN 0.9 END)*@marker_size)""", + ) def testScaledLabelShieldIcon(self): - """ Test icon-size property for label shields that depends on a data attribute """ + """Test icon-size property for label shields that depends on a data attribute""" context = QgsMapBoxGlStyleConversionContext() image = QImage(QSize(1, 1), QImage.Format.Format_ARGB32) - context.setSprites(image, {"foo": {"x": 0, "y": 0, "width": 2, "height": 2, "pixelRatio": 1}}) + context.setSprites( + image, {"foo": {"x": 0, "y": 0, "width": 2, "height": 2, "pixelRatio": 1}} + ) style = { "layout": { "visibility": "visible", @@ -1020,30 +1432,38 @@ def testScaledLabelShieldIcon(self): "text-rotation-alignment": "viewport", "icon-rotation-alignment": "viewport", "icon-image": "{foo}", - "icon-size": { - "stops": [[13, 0.25], [16, 0.45], [17, 0.7]] - } + "icon-size": {"stops": [[13, 0.25], [16, 0.45], [17, 0.7]]}, }, "paint": { "text-color": "rgba(47, 47, 47, 1)", }, "type": "symbol", "id": "poi_label", - "source-layer": "poi_label" + "source-layer": "poi_label", } - renderer, has_renderer, labeling, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + renderer, has_renderer, labeling, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertTrue(has_renderer) size = renderer.symbol().symbolLayers()[0].size() self.assertEqual(size, 0.5) dd_properties = renderer.symbol().symbolLayers()[0].dataDefinedProperties() - self.assertEqual(dd_properties.property(QgsSymbolLayer.Property.PropertyWidth).asExpression(), - "with_variable('marker_size',CASE WHEN \"foo\" = 'foo' THEN 2 END,(CASE WHEN @vector_tile_zoom >= 13 AND @vector_tile_zoom <= 16 THEN scale_linear(@vector_tile_zoom,13,16,0.25,0.45) WHEN @vector_tile_zoom > 16 AND @vector_tile_zoom <= 17 THEN scale_linear(@vector_tile_zoom,16,17,0.45,0.7) WHEN @vector_tile_zoom > 17 THEN 0.7 END)*@marker_size)") + self.assertEqual( + dd_properties.property( + QgsSymbolLayer.Property.PropertyWidth + ).asExpression(), + "with_variable('marker_size',CASE WHEN \"foo\" = 'foo' THEN 2 END,(CASE WHEN @vector_tile_zoom >= 13 AND @vector_tile_zoom <= 16 THEN scale_linear(@vector_tile_zoom,13,16,0.25,0.45) WHEN @vector_tile_zoom > 16 AND @vector_tile_zoom <= 17 THEN scale_linear(@vector_tile_zoom,16,17,0.45,0.7) WHEN @vector_tile_zoom > 17 THEN 0.7 END)*@marker_size)", + ) self.assertTrue(has_labeling) ls = labeling.labelSettings() tf = ls.format() self.assertEqual(tf.background().size(), QSizeF(1, 1)) - self.assertEqual(ls.dataDefinedProperties().property(QgsPalLayerSettings.Property.ShapeSizeX).asExpression(), - "with_variable('marker_size',CASE WHEN \"foo\" = 'foo' THEN 2 END,(CASE WHEN @vector_tile_zoom >= 13 AND @vector_tile_zoom <= 16 THEN scale_linear(@vector_tile_zoom,13,16,0.25,0.45) WHEN @vector_tile_zoom > 16 AND @vector_tile_zoom <= 17 THEN scale_linear(@vector_tile_zoom,16,17,0.45,0.7) WHEN @vector_tile_zoom > 17 THEN 0.7 END)*@marker_size)") + self.assertEqual( + ls.dataDefinedProperties() + .property(QgsPalLayerSettings.Property.ShapeSizeX) + .asExpression(), + "with_variable('marker_size',CASE WHEN \"foo\" = 'foo' THEN 2 END,(CASE WHEN @vector_tile_zoom >= 13 AND @vector_tile_zoom <= 16 THEN scale_linear(@vector_tile_zoom,13,16,0.25,0.45) WHEN @vector_tile_zoom > 16 AND @vector_tile_zoom <= 17 THEN scale_linear(@vector_tile_zoom,16,17,0.45,0.7) WHEN @vector_tile_zoom > 17 THEN 0.7 END)*@marker_size)", + ) def testCircleLayer(self): context = QgsMapBoxGlStyleConversionContext() @@ -1057,47 +1477,60 @@ def testCircleLayer(self): "circle-color": "rgba(22, 22, 22, 1)", "circle-opacity": 0.6, "circle-radius": 33, - "circle-translate": [11, 22] - } + "circle-translate": [11, 22], + }, } - has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseCircleLayer(style, context) + has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseCircleLayer( + style, context + ) self.assertTrue(has_renderer) - self.assertEqual(rendererStyle.geometryType(), QgsWkbTypes.GeometryType.PointGeometry) + self.assertEqual( + rendererStyle.geometryType(), QgsWkbTypes.GeometryType.PointGeometry + ) properties = rendererStyle.symbol().symbolLayers()[0].properties() expected_properties = { - 'angle': '0', - 'cap_style': 'square', - 'color': '22,22,22,153,rgb:0.08627450980392157,0.08627450980392157,0.08627450980392157,0.59999999999999998', - 'horizontal_anchor_point': '1', - 'joinstyle': 'bevel', - 'name': 'circle', - 'offset': '11,22', - 'offset_map_unit_scale': '3x:0,0,0,0,0,0', - 'offset_unit': 'Pixel', - 'outline_color': '46,46,46,128,rgb:0.1803921568627451,0.1803921568627451,0.1803921568627451,0.50000762951094835', - 'outline_style': 'solid', - 'outline_width': '3', - 'outline_width_map_unit_scale': '3x:0,0,0,0,0,0', - 'outline_width_unit': 'Pixel', - 'scale_method': 'diameter', - 'size': '66', - 'size_map_unit_scale': '3x:0,0,0,0,0,0', - 'size_unit': 'Pixel', - 'vertical_anchor_point': '1'} + "angle": "0", + "cap_style": "square", + "color": "22,22,22,153,rgb:0.08627450980392157,0.08627450980392157,0.08627450980392157,0.59999999999999998", + "horizontal_anchor_point": "1", + "joinstyle": "bevel", + "name": "circle", + "offset": "11,22", + "offset_map_unit_scale": "3x:0,0,0,0,0,0", + "offset_unit": "Pixel", + "outline_color": "46,46,46,128,rgb:0.1803921568627451,0.1803921568627451,0.1803921568627451,0.50000762951094835", + "outline_style": "solid", + "outline_width": "3", + "outline_width_map_unit_scale": "3x:0,0,0,0,0,0", + "outline_width_unit": "Pixel", + "scale_method": "diameter", + "size": "66", + "size_map_unit_scale": "3x:0,0,0,0,0,0", + "size_unit": "Pixel", + "vertical_anchor_point": "1", + } self.assertEqual(properties, expected_properties) def testParseArrayStops(self): conversion_context = QgsMapBoxGlStyleConversionContext() exp = QgsMapBoxGlStyleConverter.parseArrayStops({}, conversion_context, 1) - self.assertEqual(exp, '') + self.assertEqual(exp, "") - exp = QgsMapBoxGlStyleConverter.parseArrayStops([[0, [0, 1]], [2, [3, 4]]], conversion_context, 1) - self.assertEqual(exp, - 'CASE WHEN @vector_tile_zoom <= 2 THEN array(0,1) WHEN @vector_tile_zoom > 2 THEN array(3,4) END') + exp = QgsMapBoxGlStyleConverter.parseArrayStops( + [[0, [0, 1]], [2, [3, 4]]], conversion_context, 1 + ) + self.assertEqual( + exp, + "CASE WHEN @vector_tile_zoom <= 2 THEN array(0,1) WHEN @vector_tile_zoom > 2 THEN array(3,4) END", + ) - exp = QgsMapBoxGlStyleConverter.parseArrayStops([[0, [0, 1]], [2, [3, 4]]], conversion_context, 2) - self.assertEqual(exp, - 'CASE WHEN @vector_tile_zoom <= 2 THEN array(0,2) WHEN @vector_tile_zoom > 2 THEN array(6,8) END') + exp = QgsMapBoxGlStyleConverter.parseArrayStops( + [[0, [0, 1]], [2, [3, 4]]], conversion_context, 2 + ) + self.assertEqual( + exp, + "CASE WHEN @vector_tile_zoom <= 2 THEN array(0,2) WHEN @vector_tile_zoom > 2 THEN array(6,8) END", + ) def testParseLineDashArray(self): conversion_context = QgsMapBoxGlStyleConversionContext() @@ -1108,44 +1541,64 @@ def testParseLineDashArray(self): "source-layer": "water line (intermittent)", "filter": ["==", "_symbol", 3], "minzoom": 10, - "layout": { - "line-join": "round" - }, + "layout": {"line-join": "round"}, "paint": { "line-color": "#aad3df", - "line-dasharray": { - "stops": [[10, [1, 1]], [17, [0.3, 0.2]]] - }, + "line-dasharray": {"stops": [[10, [1, 1]], [17, [0.3, 0.2]]]}, "line-width": { "base": 1.2, - "stops": [[10, 1.5], [11, 2], [12, 3], [13, 5], [14, 6], [16, 10], [17, 12]] - } - } + "stops": [ + [10, 1.5], + [11, 2], + [12, 3], + [13, 5], + [14, 6], + [16, 10], + [17, 12], + ], + }, + }, } - has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseLineLayer(style, conversion_context) + has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseLineLayer( + style, conversion_context + ) self.assertTrue(has_renderer) - self.assertEqual(rendererStyle.geometryType(), QgsWkbTypes.GeometryType.LineGeometry) + self.assertEqual( + rendererStyle.geometryType(), QgsWkbTypes.GeometryType.LineGeometry + ) self.assertTrue(rendererStyle.symbol()[0].useCustomDashPattern()) dd_properties = rendererStyle.symbol().symbolLayers()[0].dataDefinedProperties() - self.assertEqual(dd_properties.property(QgsSymbolLayer.Property.PropertyStrokeWidth).asExpression(), - ('CASE WHEN @vector_tile_zoom >= 10 AND @vector_tile_zoom <= 11 THEN scale_exponential(@vector_tile_zoom,10,11,1.5,2,1.2) ' - 'WHEN @vector_tile_zoom > 11 AND @vector_tile_zoom <= 12 THEN scale_exponential(@vector_tile_zoom,11,12,2,3,1.2) ' - 'WHEN @vector_tile_zoom > 12 AND @vector_tile_zoom <= 13 THEN scale_exponential(@vector_tile_zoom,12,13,3,5,1.2) ' - 'WHEN @vector_tile_zoom > 13 AND @vector_tile_zoom <= 14 THEN scale_exponential(@vector_tile_zoom,13,14,5,6,1.2) ' - 'WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 16 THEN scale_exponential(@vector_tile_zoom,14,16,6,10,1.2) ' - 'WHEN @vector_tile_zoom > 16 AND @vector_tile_zoom <= 17 THEN scale_exponential(@vector_tile_zoom,16,17,10,12,1.2) ' - 'WHEN @vector_tile_zoom > 17 THEN 12 END')) - self.assertEqual(dd_properties.property(QgsSymbolLayer.Property.PropertyCustomDash).asExpression(), - ('array_to_string(array_foreach(' - 'CASE WHEN @vector_tile_zoom <= 17 THEN array(1,1) WHEN @vector_tile_zoom > 17 THEN array(0.3,0.2) END,' - '@element * (' - 'CASE WHEN @vector_tile_zoom >= 10 AND @vector_tile_zoom <= 11 THEN scale_exponential(@vector_tile_zoom,10,11,1.5,2,1.2) ' - 'WHEN @vector_tile_zoom > 11 AND @vector_tile_zoom <= 12 THEN scale_exponential(@vector_tile_zoom,11,12,2,3,1.2) ' - 'WHEN @vector_tile_zoom > 12 AND @vector_tile_zoom <= 13 THEN scale_exponential(@vector_tile_zoom,12,13,3,5,1.2) ' - 'WHEN @vector_tile_zoom > 13 AND @vector_tile_zoom <= 14 THEN scale_exponential(@vector_tile_zoom,13,14,5,6,1.2) ' - 'WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 16 THEN scale_exponential(@vector_tile_zoom,14,16,6,10,1.2) ' - 'WHEN @vector_tile_zoom > 16 AND @vector_tile_zoom <= 17 THEN scale_exponential(@vector_tile_zoom,16,17,10,12,1.2) ' - "WHEN @vector_tile_zoom > 17 THEN 12 END)), ';')")) + self.assertEqual( + dd_properties.property( + QgsSymbolLayer.Property.PropertyStrokeWidth + ).asExpression(), + ( + "CASE WHEN @vector_tile_zoom >= 10 AND @vector_tile_zoom <= 11 THEN scale_exponential(@vector_tile_zoom,10,11,1.5,2,1.2) " + "WHEN @vector_tile_zoom > 11 AND @vector_tile_zoom <= 12 THEN scale_exponential(@vector_tile_zoom,11,12,2,3,1.2) " + "WHEN @vector_tile_zoom > 12 AND @vector_tile_zoom <= 13 THEN scale_exponential(@vector_tile_zoom,12,13,3,5,1.2) " + "WHEN @vector_tile_zoom > 13 AND @vector_tile_zoom <= 14 THEN scale_exponential(@vector_tile_zoom,13,14,5,6,1.2) " + "WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 16 THEN scale_exponential(@vector_tile_zoom,14,16,6,10,1.2) " + "WHEN @vector_tile_zoom > 16 AND @vector_tile_zoom <= 17 THEN scale_exponential(@vector_tile_zoom,16,17,10,12,1.2) " + "WHEN @vector_tile_zoom > 17 THEN 12 END" + ), + ) + self.assertEqual( + dd_properties.property( + QgsSymbolLayer.Property.PropertyCustomDash + ).asExpression(), + ( + "array_to_string(array_foreach(" + "CASE WHEN @vector_tile_zoom <= 17 THEN array(1,1) WHEN @vector_tile_zoom > 17 THEN array(0.3,0.2) END," + "@element * (" + "CASE WHEN @vector_tile_zoom >= 10 AND @vector_tile_zoom <= 11 THEN scale_exponential(@vector_tile_zoom,10,11,1.5,2,1.2) " + "WHEN @vector_tile_zoom > 11 AND @vector_tile_zoom <= 12 THEN scale_exponential(@vector_tile_zoom,11,12,2,3,1.2) " + "WHEN @vector_tile_zoom > 12 AND @vector_tile_zoom <= 13 THEN scale_exponential(@vector_tile_zoom,12,13,3,5,1.2) " + "WHEN @vector_tile_zoom > 13 AND @vector_tile_zoom <= 14 THEN scale_exponential(@vector_tile_zoom,13,14,5,6,1.2) " + "WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 16 THEN scale_exponential(@vector_tile_zoom,14,16,6,10,1.2) " + "WHEN @vector_tile_zoom > 16 AND @vector_tile_zoom <= 17 THEN scale_exponential(@vector_tile_zoom,16,17,10,12,1.2) " + "WHEN @vector_tile_zoom > 17 THEN 12 END)), ';')" + ), + ) def testParseLineDashArrayOddNumber(self): conversion_context = QgsMapBoxGlStyleConversionContext() @@ -1156,41 +1609,63 @@ def testParseLineDashArrayOddNumber(self): "source-layer": "water line (intermittent)", "filter": ["==", "_symbol", 3], "minzoom": 10, - "layout": { - "line-join": "round" - }, + "layout": {"line-join": "round"}, "paint": { "line-color": "#aad3df", "line-dasharray": [1, 2, 3], "line-width": { "base": 1.2, - "stops": [[10, 1.5], [11, 2], [12, 3], [13, 5], [14, 6], [16, 10], [17, 12]] - } - } + "stops": [ + [10, 1.5], + [11, 2], + [12, 3], + [13, 5], + [14, 6], + [16, 10], + [17, 12], + ], + }, + }, } - has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseLineLayer(style, conversion_context) + has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseLineLayer( + style, conversion_context + ) self.assertTrue(has_renderer) - self.assertEqual(rendererStyle.geometryType(), QgsWkbTypes.GeometryType.LineGeometry) + self.assertEqual( + rendererStyle.geometryType(), QgsWkbTypes.GeometryType.LineGeometry + ) self.assertTrue(rendererStyle.symbol()[0].useCustomDashPattern()) self.assertEqual(rendererStyle.symbol()[0].customDashVector(), [6.0, 3.0]) dd_properties = rendererStyle.symbol().symbolLayers()[0].dataDefinedProperties() - self.assertEqual(dd_properties.property(QgsSymbolLayer.Property.PropertyStrokeWidth).asExpression(), - ('CASE WHEN @vector_tile_zoom >= 10 AND @vector_tile_zoom <= 11 THEN scale_exponential(@vector_tile_zoom,10,11,1.5,2,1.2) ' - 'WHEN @vector_tile_zoom > 11 AND @vector_tile_zoom <= 12 THEN scale_exponential(@vector_tile_zoom,11,12,2,3,1.2) ' - 'WHEN @vector_tile_zoom > 12 AND @vector_tile_zoom <= 13 THEN scale_exponential(@vector_tile_zoom,12,13,3,5,1.2) ' - 'WHEN @vector_tile_zoom > 13 AND @vector_tile_zoom <= 14 THEN scale_exponential(@vector_tile_zoom,13,14,5,6,1.2) ' - 'WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 16 THEN scale_exponential(@vector_tile_zoom,14,16,6,10,1.2) ' - 'WHEN @vector_tile_zoom > 16 AND @vector_tile_zoom <= 17 THEN scale_exponential(@vector_tile_zoom,16,17,10,12,1.2) ' - 'WHEN @vector_tile_zoom > 17 THEN 12 END')) - self.assertEqual(dd_properties.property(QgsSymbolLayer.Property.PropertyCustomDash).asExpression(), - ('array_to_string(array_foreach(array(4,2),@element * (' - 'CASE WHEN @vector_tile_zoom >= 10 AND @vector_tile_zoom <= 11 THEN scale_exponential(@vector_tile_zoom,10,11,1.5,2,1.2) ' - 'WHEN @vector_tile_zoom > 11 AND @vector_tile_zoom <= 12 THEN scale_exponential(@vector_tile_zoom,11,12,2,3,1.2) ' - 'WHEN @vector_tile_zoom > 12 AND @vector_tile_zoom <= 13 THEN scale_exponential(@vector_tile_zoom,12,13,3,5,1.2) ' - 'WHEN @vector_tile_zoom > 13 AND @vector_tile_zoom <= 14 THEN scale_exponential(@vector_tile_zoom,13,14,5,6,1.2) ' - 'WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 16 THEN scale_exponential(@vector_tile_zoom,14,16,6,10,1.2) ' - 'WHEN @vector_tile_zoom > 16 AND @vector_tile_zoom <= 17 THEN scale_exponential(@vector_tile_zoom,16,17,10,12,1.2) ' - "WHEN @vector_tile_zoom > 17 THEN 12 END)), ';')")) + self.assertEqual( + dd_properties.property( + QgsSymbolLayer.Property.PropertyStrokeWidth + ).asExpression(), + ( + "CASE WHEN @vector_tile_zoom >= 10 AND @vector_tile_zoom <= 11 THEN scale_exponential(@vector_tile_zoom,10,11,1.5,2,1.2) " + "WHEN @vector_tile_zoom > 11 AND @vector_tile_zoom <= 12 THEN scale_exponential(@vector_tile_zoom,11,12,2,3,1.2) " + "WHEN @vector_tile_zoom > 12 AND @vector_tile_zoom <= 13 THEN scale_exponential(@vector_tile_zoom,12,13,3,5,1.2) " + "WHEN @vector_tile_zoom > 13 AND @vector_tile_zoom <= 14 THEN scale_exponential(@vector_tile_zoom,13,14,5,6,1.2) " + "WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 16 THEN scale_exponential(@vector_tile_zoom,14,16,6,10,1.2) " + "WHEN @vector_tile_zoom > 16 AND @vector_tile_zoom <= 17 THEN scale_exponential(@vector_tile_zoom,16,17,10,12,1.2) " + "WHEN @vector_tile_zoom > 17 THEN 12 END" + ), + ) + self.assertEqual( + dd_properties.property( + QgsSymbolLayer.Property.PropertyCustomDash + ).asExpression(), + ( + "array_to_string(array_foreach(array(4,2),@element * (" + "CASE WHEN @vector_tile_zoom >= 10 AND @vector_tile_zoom <= 11 THEN scale_exponential(@vector_tile_zoom,10,11,1.5,2,1.2) " + "WHEN @vector_tile_zoom > 11 AND @vector_tile_zoom <= 12 THEN scale_exponential(@vector_tile_zoom,11,12,2,3,1.2) " + "WHEN @vector_tile_zoom > 12 AND @vector_tile_zoom <= 13 THEN scale_exponential(@vector_tile_zoom,12,13,3,5,1.2) " + "WHEN @vector_tile_zoom > 13 AND @vector_tile_zoom <= 14 THEN scale_exponential(@vector_tile_zoom,13,14,5,6,1.2) " + "WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 16 THEN scale_exponential(@vector_tile_zoom,14,16,6,10,1.2) " + "WHEN @vector_tile_zoom > 16 AND @vector_tile_zoom <= 17 THEN scale_exponential(@vector_tile_zoom,16,17,10,12,1.2) " + "WHEN @vector_tile_zoom > 17 THEN 12 END)), ';')" + ), + ) def testParseLineDashArraySingleNumber(self): conversion_context = QgsMapBoxGlStyleConversionContext() @@ -1201,26 +1676,44 @@ def testParseLineDashArraySingleNumber(self): "source-layer": "water line (intermittent)", "filter": ["==", "_symbol", 3], "minzoom": 10, - "layout": { - "line-join": "round" - }, + "layout": {"line-join": "round"}, "paint": { "line-color": "#aad3df", "line-dasharray": [3], "line-width": { "base": 1.2, - "stops": [[10, 1.5], [11, 2], [12, 3], [13, 5], [14, 6], [16, 10], [17, 12]] - } - } + "stops": [ + [10, 1.5], + [11, 2], + [12, 3], + [13, 5], + [14, 6], + [16, 10], + [17, 12], + ], + }, + }, } - has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseLineLayer(style, conversion_context) + has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseLineLayer( + style, conversion_context + ) self.assertTrue(has_renderer) - self.assertEqual(rendererStyle.geometryType(), QgsWkbTypes.GeometryType.LineGeometry) + self.assertEqual( + rendererStyle.geometryType(), QgsWkbTypes.GeometryType.LineGeometry + ) self.assertFalse(rendererStyle.symbol()[0].useCustomDashPattern()) dd_properties = rendererStyle.symbol().symbolLayers()[0].dataDefinedProperties() - self.assertEqual(dd_properties.property(QgsSymbolLayer.Property.PropertyStrokeWidth).asExpression(), - 'CASE WHEN @vector_tile_zoom >= 10 AND @vector_tile_zoom <= 11 THEN scale_exponential(@vector_tile_zoom,10,11,1.5,2,1.2) WHEN @vector_tile_zoom > 11 AND @vector_tile_zoom <= 12 THEN scale_exponential(@vector_tile_zoom,11,12,2,3,1.2) WHEN @vector_tile_zoom > 12 AND @vector_tile_zoom <= 13 THEN scale_exponential(@vector_tile_zoom,12,13,3,5,1.2) WHEN @vector_tile_zoom > 13 AND @vector_tile_zoom <= 14 THEN scale_exponential(@vector_tile_zoom,13,14,5,6,1.2) WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 16 THEN scale_exponential(@vector_tile_zoom,14,16,6,10,1.2) WHEN @vector_tile_zoom > 16 AND @vector_tile_zoom <= 17 THEN scale_exponential(@vector_tile_zoom,16,17,10,12,1.2) WHEN @vector_tile_zoom > 17 THEN 12 END') - self.assertFalse(dd_properties.property(QgsSymbolLayer.Property.PropertyCustomDash).isActive()) + self.assertEqual( + dd_properties.property( + QgsSymbolLayer.Property.PropertyStrokeWidth + ).asExpression(), + "CASE WHEN @vector_tile_zoom >= 10 AND @vector_tile_zoom <= 11 THEN scale_exponential(@vector_tile_zoom,10,11,1.5,2,1.2) WHEN @vector_tile_zoom > 11 AND @vector_tile_zoom <= 12 THEN scale_exponential(@vector_tile_zoom,11,12,2,3,1.2) WHEN @vector_tile_zoom > 12 AND @vector_tile_zoom <= 13 THEN scale_exponential(@vector_tile_zoom,12,13,3,5,1.2) WHEN @vector_tile_zoom > 13 AND @vector_tile_zoom <= 14 THEN scale_exponential(@vector_tile_zoom,13,14,5,6,1.2) WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 16 THEN scale_exponential(@vector_tile_zoom,14,16,6,10,1.2) WHEN @vector_tile_zoom > 16 AND @vector_tile_zoom <= 17 THEN scale_exponential(@vector_tile_zoom,16,17,10,12,1.2) WHEN @vector_tile_zoom > 17 THEN 12 END", + ) + self.assertFalse( + dd_properties.property( + QgsSymbolLayer.Property.PropertyCustomDash + ).isActive() + ) def testParseLineDashArrayLiteral(self): conversion_context = QgsMapBoxGlStyleConversionContext() @@ -1230,42 +1723,194 @@ def testParseLineDashArrayLiteral(self): "source": "base_v1.0.0", "source-layer": "transportation", "minzoom": 8.0, - "layout": {"line-cap": "butt", "line-join": "miter", "visibility": "visible"}, + "layout": { + "line-cap": "butt", + "line-join": "miter", + "visibility": "visible", + }, "paint": { "line-blur": 0.4, "line-color": "hsl(0,80%,60%)", "line-width": [ - "interpolate", ["linear"], ["zoom"], 8, 0.5, 10, 1.2, 12, ["match", ["get", "class"], ["rail"], ["match", ["get", "subclass"], ["rail", "narrow_gauge", "rack_rail"], ["match", ["get", "service"], ["yard", "siding"], 0.25, 1], 1], 1], 14, ["match", ["get", "class"], ["rail", "rail_construction"], ["match", ["get", "subclass"], ["rail", "narrow_gauge", "rack_rail"], ["match", ["get", "service"], ["yard", "siding"], 0.25, 1.5], 1.5], 1.5], 18, - ["match", ["get", "class"], ["rail", "rail_construction"], ["match", ["get", "subclass"], ["rail", "narrow_gauge", "rack_rail"], ["match", ["get", "service"], ["yard", "siding"], 1, 2], 1.5], 1.5] + "interpolate", + ["linear"], + ["zoom"], + 8, + 0.5, + 10, + 1.2, + 12, + [ + "match", + ["get", "class"], + ["rail"], + [ + "match", + ["get", "subclass"], + ["rail", "narrow_gauge", "rack_rail"], + ["match", ["get", "service"], ["yard", "siding"], 0.25, 1], + 1, + ], + 1, + ], + 14, + [ + "match", + ["get", "class"], + ["rail", "rail_construction"], + [ + "match", + ["get", "subclass"], + ["rail", "narrow_gauge", "rack_rail"], + [ + "match", + ["get", "service"], + ["yard", "siding"], + 0.25, + 1.5, + ], + 1.5, + ], + 1.5, + ], + 18, + [ + "match", + ["get", "class"], + ["rail", "rail_construction"], + [ + "match", + ["get", "subclass"], + ["rail", "narrow_gauge", "rack_rail"], + ["match", ["get", "service"], ["yard", "siding"], 1, 2], + 1.5, + ], + 1.5, + ], ], "line-opacity": [ - "interpolate", ["linear"], ["zoom"], 8, 0, 8.5, ["match", ["get", "class"], ["rail"], 1, 0], 13, ["match", ["get", "subclass"], ["rail", "subway", "funicular", "narrow_gauge", "rack_rail"], ["match", ["get", "is_route"], 99, 1, 0], 0], 14, - ["match", ["get", "class"], ["rail_construction", "transit_construction"], 0.8, ["match", ["get", "subclass"], ["rail", "narrow_gauge", "funicular", "subway", "rack_rail"], ["match", ["get", "service"], ["yard", "siding"], 0, 1], 0]], 14.5, ["match", ["get", "class"], ["rail_construction", "transit_construction"], 0.8, 1] + "interpolate", + ["linear"], + ["zoom"], + 8, + 0, + 8.5, + ["match", ["get", "class"], ["rail"], 1, 0], + 13, + [ + "match", + ["get", "subclass"], + ["rail", "subway", "funicular", "narrow_gauge", "rack_rail"], + ["match", ["get", "is_route"], 99, 1, 0], + 0, + ], + 14, + [ + "match", + ["get", "class"], + ["rail_construction", "transit_construction"], + 0.8, + [ + "match", + ["get", "subclass"], + [ + "rail", + "narrow_gauge", + "funicular", + "subway", + "rack_rail", + ], + ["match", ["get", "service"], ["yard", "siding"], 0, 1], + 0, + ], + ], + 14.5, + [ + "match", + ["get", "class"], + ["rail_construction", "transit_construction"], + 0.8, + 1, + ], + ], + "line-dasharray": [ + "step", + ["zoom"], + ["literal", [3, 1.875]], + 14, + ["literal", [4, 2.5]], + 15, + ["literal", [5, 3.125]], + 16, + ["literal", [6, 3.75]], ], - "line-dasharray": ["step", ["zoom"], ["literal", [3, 1.875]], 14, ["literal", [4, 2.5]], 15, ["literal", [5, 3.125]], 16, ["literal", [6, 3.75]]] }, - "filter": ["all", ["==", ["get", "brunnel"], "tunnel"], ["in", ["get", "class"], ["literal", ["cable_car", "gondola", "rail", "rail_construction", "transit", "transit_construction"]]], ["==", ["geometry-type"], "LineString"]] + "filter": [ + "all", + ["==", ["get", "brunnel"], "tunnel"], + [ + "in", + ["get", "class"], + [ + "literal", + [ + "cable_car", + "gondola", + "rail", + "rail_construction", + "transit", + "transit_construction", + ], + ], + ], + ["==", ["geometry-type"], "LineString"], + ], } - has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseLineLayer(style, conversion_context) + has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseLineLayer( + style, conversion_context + ) self.assertTrue(has_renderer) - self.assertEqual(rendererStyle.geometryType(), QgsWkbTypes.GeometryType.LineGeometry) + self.assertEqual( + rendererStyle.geometryType(), QgsWkbTypes.GeometryType.LineGeometry + ) self.assertFalse(rendererStyle.symbol()[0].useCustomDashPattern()) dd_properties = rendererStyle.symbol().symbolLayers()[0].dataDefinedProperties() - self.assertEqual(dd_properties.property(QgsSymbolLayer.Property.CustomDash).asExpression(), - '''array_to_string(array_foreach(CASE WHEN @vector_tile_zoom >= 16 THEN (array(6,3.75)) WHEN @vector_tile_zoom >= 15 THEN (array(5,3.125)) WHEN @vector_tile_zoom >= 14 THEN (array(4,2.5)) ELSE (array(3,1.875)) END,@element * (CASE WHEN @vector_tile_zoom >= 8 AND @vector_tile_zoom <= 10 THEN scale_linear(@vector_tile_zoom,8,10,0.5,1.2) WHEN @vector_tile_zoom > 10 AND @vector_tile_zoom <= 12 THEN scale_linear(@vector_tile_zoom,10,12,1.2,CASE WHEN "class" = 'rail' THEN CASE WHEN "subclass" IN ('rail', 'narrow_gauge', 'rack_rail') THEN CASE WHEN "service" IN ('yard', 'siding') THEN 0.25 ELSE 1 END ELSE 1 END ELSE 1 END) WHEN @vector_tile_zoom > 12 AND @vector_tile_zoom <= 14 THEN scale_linear(@vector_tile_zoom,12,14,CASE WHEN "class" = 'rail' THEN CASE WHEN "subclass" IN ('rail', 'narrow_gauge', 'rack_rail') THEN CASE WHEN "service" IN ('yard', 'siding') THEN 0.25 ELSE 1 END ELSE 1 END ELSE 1 END,CASE WHEN "class" IN ('rail', 'rail_construction') THEN CASE WHEN "subclass" IN ('rail', 'narrow_gauge', 'rack_rail') THEN CASE WHEN "service" IN ('yard', 'siding') THEN 0.25 ELSE 1.5 END ELSE 1.5 END ELSE 1.5 END) WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 18 THEN scale_linear(@vector_tile_zoom,14,18,CASE WHEN "class" IN ('rail', 'rail_construction') THEN CASE WHEN "subclass" IN ('rail', 'narrow_gauge', 'rack_rail') THEN CASE WHEN "service" IN ('yard', 'siding') THEN 0.25 ELSE 1.5 END ELSE 1.5 END ELSE 1.5 END,CASE WHEN "class" IN ('rail', 'rail_construction') THEN CASE WHEN "subclass" IN ('rail', 'narrow_gauge', 'rack_rail') THEN CASE WHEN "service" IN ('yard', 'siding') THEN 1 ELSE 2 END ELSE 1.5 END ELSE 1.5 END) WHEN @vector_tile_zoom > 18 THEN ( ( CASE WHEN "class" IN ('rail', 'rail_construction') THEN CASE WHEN "subclass" IN ('rail', 'narrow_gauge', 'rack_rail') THEN CASE WHEN "service" IN ('yard', 'siding') THEN 1 ELSE 2 END ELSE 1.5 END ELSE 1.5 END ) * 1 ) END)), ';')''') - self.assertTrue(dd_properties.property(QgsSymbolLayer.Property.PropertyCustomDash).isActive()) + self.assertEqual( + dd_properties.property(QgsSymbolLayer.Property.CustomDash).asExpression(), + """array_to_string(array_foreach(CASE WHEN @vector_tile_zoom >= 16 THEN (array(6,3.75)) WHEN @vector_tile_zoom >= 15 THEN (array(5,3.125)) WHEN @vector_tile_zoom >= 14 THEN (array(4,2.5)) ELSE (array(3,1.875)) END,@element * (CASE WHEN @vector_tile_zoom >= 8 AND @vector_tile_zoom <= 10 THEN scale_linear(@vector_tile_zoom,8,10,0.5,1.2) WHEN @vector_tile_zoom > 10 AND @vector_tile_zoom <= 12 THEN scale_linear(@vector_tile_zoom,10,12,1.2,CASE WHEN "class" = 'rail' THEN CASE WHEN "subclass" IN ('rail', 'narrow_gauge', 'rack_rail') THEN CASE WHEN "service" IN ('yard', 'siding') THEN 0.25 ELSE 1 END ELSE 1 END ELSE 1 END) WHEN @vector_tile_zoom > 12 AND @vector_tile_zoom <= 14 THEN scale_linear(@vector_tile_zoom,12,14,CASE WHEN "class" = 'rail' THEN CASE WHEN "subclass" IN ('rail', 'narrow_gauge', 'rack_rail') THEN CASE WHEN "service" IN ('yard', 'siding') THEN 0.25 ELSE 1 END ELSE 1 END ELSE 1 END,CASE WHEN "class" IN ('rail', 'rail_construction') THEN CASE WHEN "subclass" IN ('rail', 'narrow_gauge', 'rack_rail') THEN CASE WHEN "service" IN ('yard', 'siding') THEN 0.25 ELSE 1.5 END ELSE 1.5 END ELSE 1.5 END) WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 18 THEN scale_linear(@vector_tile_zoom,14,18,CASE WHEN "class" IN ('rail', 'rail_construction') THEN CASE WHEN "subclass" IN ('rail', 'narrow_gauge', 'rack_rail') THEN CASE WHEN "service" IN ('yard', 'siding') THEN 0.25 ELSE 1.5 END ELSE 1.5 END ELSE 1.5 END,CASE WHEN "class" IN ('rail', 'rail_construction') THEN CASE WHEN "subclass" IN ('rail', 'narrow_gauge', 'rack_rail') THEN CASE WHEN "service" IN ('yard', 'siding') THEN 1 ELSE 2 END ELSE 1.5 END ELSE 1.5 END) WHEN @vector_tile_zoom > 18 THEN ( ( CASE WHEN "class" IN ('rail', 'rail_construction') THEN CASE WHEN "subclass" IN ('rail', 'narrow_gauge', 'rack_rail') THEN CASE WHEN "service" IN ('yard', 'siding') THEN 1 ELSE 2 END ELSE 1.5 END ELSE 1.5 END ) * 1 ) END)), ';')""", + ) + self.assertTrue( + dd_properties.property( + QgsSymbolLayer.Property.PropertyCustomDash + ).isActive() + ) conversion_context = QgsMapBoxGlStyleConversionContext() style["paint"].pop("line-width") - has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseLineLayer(style, conversion_context) + has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseLineLayer( + style, conversion_context + ) self.assertTrue(has_renderer) - self.assertEqual(rendererStyle.geometryType(), QgsWkbTypes.GeometryType.LineGeometry) + self.assertEqual( + rendererStyle.geometryType(), QgsWkbTypes.GeometryType.LineGeometry + ) self.assertFalse(rendererStyle.symbol()[0].useCustomDashPattern()) dd_properties = rendererStyle.symbol().symbolLayers()[0].dataDefinedProperties() - self.assertEqual(dd_properties.property(QgsSymbolLayer.Property.PropertyStrokeWidth).asExpression(), '') - self.assertEqual(dd_properties.property(QgsSymbolLayer.Property.CustomDash).asExpression(), - '''array_to_string(CASE WHEN @vector_tile_zoom >= 16 THEN (array(6,3.75)) WHEN @vector_tile_zoom >= 15 THEN (array(5,3.125)) WHEN @vector_tile_zoom >= 14 THEN (array(4,2.5)) ELSE (array(3,1.875)) END, ';')''') - self.assertTrue(dd_properties.property(QgsSymbolLayer.Property.PropertyCustomDash).isActive()) + self.assertEqual( + dd_properties.property( + QgsSymbolLayer.Property.PropertyStrokeWidth + ).asExpression(), + "", + ) + self.assertEqual( + dd_properties.property(QgsSymbolLayer.Property.CustomDash).asExpression(), + """array_to_string(CASE WHEN @vector_tile_zoom >= 16 THEN (array(6,3.75)) WHEN @vector_tile_zoom >= 15 THEN (array(5,3.125)) WHEN @vector_tile_zoom >= 14 THEN (array(4,2.5)) ELSE (array(3,1.875)) END, ';')""", + ) + self.assertTrue( + dd_properties.property( + QgsSymbolLayer.Property.PropertyCustomDash + ).isActive() + ) def testParseLineNoWidth(self): conversion_context = QgsMapBoxGlStyleConversionContext() @@ -1276,25 +1921,35 @@ def testParseLineNoWidth(self): "source-layer": "water line (intermittent)", "paint": { "line-color": "#aad3df", - } + }, } - has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseLineLayer(style, conversion_context) + has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseLineLayer( + style, conversion_context + ) self.assertTrue(has_renderer) - self.assertEqual(rendererStyle.geometryType(), QgsWkbTypes.GeometryType.LineGeometry) + self.assertEqual( + rendererStyle.geometryType(), QgsWkbTypes.GeometryType.LineGeometry + ) self.assertEqual(rendererStyle.symbol()[0].width(), 1.0) conversion_context.setPixelSizeConversionFactor(0.5) - has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseLineLayer(style, conversion_context) + has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseLineLayer( + style, conversion_context + ) self.assertTrue(has_renderer) - self.assertEqual(rendererStyle.geometryType(), QgsWkbTypes.GeometryType.LineGeometry) + self.assertEqual( + rendererStyle.geometryType(), QgsWkbTypes.GeometryType.LineGeometry + ) self.assertEqual(rendererStyle.symbol()[0].width(), 0.5) def testLinePattern(self): - """ Test line-pattern property """ + """Test line-pattern property""" context = QgsMapBoxGlStyleConversionContext() image = QImage(QSize(1, 1), QImage.Format.Format_ARGB32) - context.setSprites(image, {"foo": {"x": 0, "y": 0, "width": 1, "height": 1, "pixelRatio": 1}}) + context.setSprites( + image, {"foo": {"x": 0, "y": 0, "width": 1, "height": 1, "pixelRatio": 1}} + ) style = { "id": "mountain range/ridge", "type": "line", @@ -1302,18 +1957,22 @@ def testLinePattern(self): "source-layer": "mountain range", "filter": ["==", "_symbol", 1], "minzoom": 13, - "layout": { - "line-join": "round" - }, + "layout": {"line-join": "round"}, "paint": { "line-pattern": {"stops": [[13, "foo"], [15, "foo"]]}, - "line-width": {"stops": [[14, 20], [15, 40]]} - } + "line-width": {"stops": [[14, 20], [15, 40]]}, + }, } - has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseLineLayer(style, context) + has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseLineLayer( + style, context + ) self.assertTrue(has_renderer) - self.assertEqual(rendererStyle.geometryType(), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(rendererStyle.symbol().symbolLayers()[0].layerType(), 'RasterLine') + self.assertEqual( + rendererStyle.geometryType(), QgsWkbTypes.GeometryType.LineGeometry + ) + self.assertEqual( + rendererStyle.symbol().symbolLayers()[0].layerType(), "RasterLine" + ) dd_props = rendererStyle.symbol().symbolLayers()[0].dataDefinedProperties() prop = dd_props.property(QgsSymbolLayer.Property.PropertyFile) self.assertTrue(prop.isActive()) @@ -1329,36 +1988,67 @@ def testParseLineOpactity(self): "layout": {"visibility": "visible"}, "paint": { "line-blur": 0.25, - "line-color": ["match", ["get", "class"], "scree", "rgba(0, 0, 0, 1)", "hsl(35, 86%, 38%)"], + "line-color": [ + "match", + ["get", "class"], + "scree", + "rgba(0, 0, 0, 1)", + "hsl(35, 86%, 38%)", + ], "line-width": [ "interpolate", ["exponential", 1], ["zoom"], 11, - ["case", ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], 0.75, 0], + [ + "case", + ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], + 0.75, + 0, + ], 12, - ["case", ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], 1, 0], + [ + "case", + ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], + 1, + 0, + ], 14, [ "case", ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], 1.5, - ["case", ["==", ["%", ["to-number", ["get", "ele"]], 20], 0], 0.75, 0] + [ + "case", + ["==", ["%", ["to-number", ["get", "ele"]], 20], 0], + 0.75, + 0, + ], ], 15, [ "case", ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], 2, - ["case", ["==", ["%", ["to-number", ["get", "ele"]], 20], 0], 1, 0] + [ + "case", + ["==", ["%", ["to-number", ["get", "ele"]], 20], 0], + 1, + 0, + ], ], 18, [ "case", ["==", ["%", ["to-number", ["get", "ele"]], 100], 0], 3, - ["case", ["==", ["%", ["to-number", ["get", "ele"]], 10], 0], 1.5, 0] - ] + [ + "case", + ["==", ["%", ["to-number", ["get", "ele"]], 10], 0], + 1.5, + 0, + ], + ], ], "line-opacity": [ "interpolate", @@ -1367,22 +2057,32 @@ def testParseLineOpactity(self): 11, ["match", ["get", "class"], "scree", 0.2, 0.3], 16, - ["match", ["get", "class"], "scree", 0.2, 0.3] - ] + ["match", ["get", "class"], "scree", 0.2, 0.3], + ], }, - "filter": ["all", ["!in", "class", "rock", "ice", "water"]] + "filter": ["all", ["!in", "class", "rock", "ice", "water"]], } - has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseLineLayer(style, conversion_context) + has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseLineLayer( + style, conversion_context + ) self.assertTrue(has_renderer) - self.assertEqual(rendererStyle.geometryType(), QgsWkbTypes.GeometryType.LineGeometry) + self.assertEqual( + rendererStyle.geometryType(), QgsWkbTypes.GeometryType.LineGeometry + ) symbol = rendererStyle.symbol() dd_properties_layer = symbol.symbolLayers()[0].dataDefinedProperties() - self.assertEqual(dd_properties_layer.property(QgsSymbolLayer.Property.StrokeColor).asExpression(), - '''CASE WHEN "class" IS 'scree' THEN '#000000' ELSE '#b26e0e' END''') + self.assertEqual( + dd_properties_layer.property( + QgsSymbolLayer.Property.StrokeColor + ).asExpression(), + """CASE WHEN "class" IS 'scree' THEN '#000000' ELSE '#b26e0e' END""", + ) dd_properties = symbol.dataDefinedProperties() - self.assertEqual(dd_properties.property(QgsSymbol.Property.Opacity).asExpression(), - '''(CASE WHEN ("class" = 'scree') THEN 0.2 ELSE 0.3 END) * 100''') + self.assertEqual( + dd_properties.property(QgsSymbol.Property.Opacity).asExpression(), + """(CASE WHEN ("class" = 'scree') THEN 0.2 ELSE 0.3 END) * 100""", + ) def testLabelWithLiteral(self): context = QgsMapBoxGlStyleConversionContext() @@ -1394,12 +2094,16 @@ def testLabelWithLiteral(self): "paint": { "text-color": "rgba(47, 47, 47, 1)", }, - "type": "symbol" + "type": "symbol", } - rendererStyle, has_renderer, labeling_style, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + rendererStyle, has_renderer, labeling_style, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertTrue(has_labeling) self.assertTrue(labeling_style.labelSettings().isExpression) - self.assertEqual(labeling_style.labelSettings().fieldName, 'concat(\'Quarry \',"substance")') + self.assertEqual( + labeling_style.labelSettings().fieldName, "concat('Quarry ',\"substance\")" + ) def testLabelWithLiteral2(self): context = QgsMapBoxGlStyleConversionContext() @@ -1411,12 +2115,16 @@ def testLabelWithLiteral2(self): "paint": { "text-color": "rgba(47, 47, 47, 1)", }, - "type": "symbol" + "type": "symbol", } - rendererStyle, has_renderer, labeling_style, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + rendererStyle, has_renderer, labeling_style, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertTrue(has_labeling) self.assertTrue(labeling_style.labelSettings().isExpression) - self.assertEqual(labeling_style.labelSettings().fieldName, 'concat("substance",\' Quarry\')') + self.assertEqual( + labeling_style.labelSettings().fieldName, "concat(\"substance\",' Quarry')" + ) def testLabelWithLiteral3(self): context = QgsMapBoxGlStyleConversionContext() @@ -1428,12 +2136,17 @@ def testLabelWithLiteral3(self): "paint": { "text-color": "rgba(47, 47, 47, 1)", }, - "type": "symbol" + "type": "symbol", } - rendererStyle, has_renderer, labeling_style, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + rendererStyle, has_renderer, labeling_style, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertTrue(has_labeling) self.assertTrue(labeling_style.labelSettings().isExpression) - self.assertEqual(labeling_style.labelSettings().fieldName, 'concat(\'A \',"substance",\' Quarry\')') + self.assertEqual( + labeling_style.labelSettings().fieldName, + "concat('A ',\"substance\",' Quarry')", + ) def testLabelWithField(self): context = QgsMapBoxGlStyleConversionContext() @@ -1445,12 +2158,14 @@ def testLabelWithField(self): "paint": { "text-color": "rgba(47, 47, 47, 1)", }, - "type": "symbol" + "type": "symbol", } - rendererStyle, has_renderer, labeling_style, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + rendererStyle, has_renderer, labeling_style, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertTrue(has_labeling) self.assertFalse(labeling_style.labelSettings().isExpression) - self.assertEqual(labeling_style.labelSettings().fieldName, 'substance') + self.assertEqual(labeling_style.labelSettings().fieldName, "substance") def testLabelRotation(self): context = QgsMapBoxGlStyleConversionContext() @@ -1458,14 +2173,16 @@ def testLabelRotation(self): "layout": { "visibility": "visible", "text-field": "{substance}", - "text-rotate": 123 + "text-rotate": 123, }, "paint": { "text-color": "rgba(47, 47, 47, 1)", }, - "type": "symbol" + "type": "symbol", } - rendererStyle, has_renderer, labeling_style, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + rendererStyle, has_renderer, labeling_style, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertTrue(has_labeling) self.assertEqual(labeling_style.labelSettings().angleOffset, 123) @@ -1474,28 +2191,28 @@ def testLabelRotation(self): "layout": { "visibility": "visible", "text-field": "{substance}", - "text-rotate": ["get", "direction"] + "text-rotate": ["get", "direction"], }, "paint": { "text-color": "rgba(47, 47, 47, 1)", }, - "type": "symbol" + "type": "symbol", } - rendererStyle, has_renderer, labeling_style, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + rendererStyle, has_renderer, labeling_style, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertTrue(has_labeling) ls = labeling_style.labelSettings() ddp = ls.dataDefinedProperties() - self.assertEqual(ddp.property(QgsPalLayerSettings.Property.LabelRotation).asExpression(), '"direction"') + self.assertEqual( + ddp.property(QgsPalLayerSettings.Property.LabelRotation).asExpression(), + '"direction"', + ) def test_parse_zoom_levels(self): context = QgsMapBoxGlStyleConversionContext() style = { - "sources": { - "Basemaps": { - "type": "vector", - "url": "https://xxxxxx" - } - }, + "sources": {"Basemaps": {"type": "vector", "url": "https://xxxxxx"}}, "layers": [ { "id": "water", @@ -1504,21 +2221,16 @@ def test_parse_zoom_levels(self): "minzoom": 3, "maxzoom": 11, "type": "fill", - "paint": { - "fill-color": "#00ffff" - } + "paint": {"fill-color": "#00ffff"}, }, { "layout": { "text-field": "{name_en}", - "text-font": [ - "Open Sans Semibold", - "Arial Unicode MS Bold" - ], + "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"], "text-max-width": 8, "text-anchor": "top", "text-size": 11, - "icon-size": 1 + "icon-size": 1, }, "type": "symbol", "id": "poi_label", @@ -1528,11 +2240,11 @@ def test_parse_zoom_levels(self): "text-color": "#666", "text-halo-width": 1.5, "text-halo-color": "rgba(255,255,255,0.95)", - "text-halo-blur": 1 + "text-halo-blur": 1, }, - "source-layer": "poi_label" - } - ] + "source-layer": "poi_label", + }, + ], } converter = QgsMapBoxGlStyleConverter() @@ -1557,10 +2269,7 @@ def test_parse_raster_source(self): context = QgsMapBoxGlStyleConversionContext() style = { "sources": { - "Basemaps": { - "type": "vector", - "url": "https://xxxxxx" - }, + "Basemaps": {"type": "vector", "url": "https://xxxxxx"}, "Texture-Relief": { "tiles": [ "https://yyyyyy/v1/tiles/texturereliefshade/EPSG:3857/{z}/{x}/{y}.webp" @@ -1570,47 +2279,30 @@ def test_parse_raster_source(self): "maxzoom": 20, "tileSize": 256, "attribution": "© 2022", - } + }, }, "layers": [ { - "layout": { - "visibility": "visible" - }, + "layout": {"visibility": "visible"}, "paint": { "raster-brightness-min": 0, "raster-opacity": { "stops": [ - [ - 1, - 0.35 - ], - [ - 7, - 0.35 - ], - [ - 8, - 0.65 - ], - [ - 15, - 0.65 - ], - [ - 16, - 0.3 - ] + [1, 0.35], + [7, 0.35], + [8, 0.65], + [15, 0.65], + [16, 0.3], ] }, "raster-resampling": "nearest", - "raster-contrast": 0 + "raster-contrast": 0, }, "id": "texture-relief-combined", "source": "Texture-Relief", - "type": "raster" + "type": "raster", }, - ] + ], } converter = QgsMapBoxGlStyleConverter() @@ -1622,56 +2314,65 @@ def test_parse_raster_source(self): raster_source = sources[0] self.assertIsInstance(raster_source, QgsMapBoxGlStyleRasterSource) - self.assertEqual(raster_source.name(), 'Texture-Relief') + self.assertEqual(raster_source.name(), "Texture-Relief") self.assertEqual(raster_source.type(), Qgis.MapBoxGlStyleSourceType.Raster) - self.assertEqual(raster_source.attribution(), '© 2022') + self.assertEqual(raster_source.attribution(), "© 2022") self.assertEqual(raster_source.minimumZoom(), 3) self.assertEqual(raster_source.maximumZoom(), 20) self.assertEqual(raster_source.tileSize(), 256) - self.assertEqual(raster_source.tiles(), ['https://yyyyyy/v1/tiles/texturereliefshade/EPSG:3857/{z}/{x}/{y}.webp']) + self.assertEqual( + raster_source.tiles(), + ["https://yyyyyy/v1/tiles/texturereliefshade/EPSG:3857/{z}/{x}/{y}.webp"], + ) # convert to raster layer rl = raster_source.toRasterLayer() self.assertIsInstance(rl, QgsRasterLayer) - self.assertEqual(rl.source(), 'tilePixelRation=1&type=xyz&url=https://yyyyyy/v1/tiles/texturereliefshade/EPSG:3857/%7Bz%7D/%7Bx%7D/%7By%7D.webp&zmax=20&zmin=3') - self.assertEqual(rl.providerType(), 'wms') + self.assertEqual( + rl.source(), + "tilePixelRation=1&type=xyz&url=https://yyyyyy/v1/tiles/texturereliefshade/EPSG:3857/%7Bz%7D/%7Bx%7D/%7By%7D.webp&zmax=20&zmin=3", + ) + self.assertEqual(rl.providerType(), "wms") # raster sublayers sub_layers = converter.createSubLayers() self.assertEqual(len(sub_layers), 1) raster_layer = sub_layers[0] self.assertIsInstance(raster_layer, QgsRasterLayer) - self.assertEqual(raster_layer.name(), 'Texture-Relief') - self.assertEqual(raster_layer.source(), 'tilePixelRation=1&type=xyz&url=https://yyyyyy/v1/tiles/texturereliefshade/EPSG:3857/%7Bz%7D/%7Bx%7D/%7By%7D.webp&zmax=20&zmin=3') - self.assertEqual(raster_layer.pipe().dataDefinedProperties().property(QgsRasterPipe.Property.RendererOpacity).asExpression(), 'CASE WHEN @vector_tile_zoom >= 1 AND @vector_tile_zoom <= 7 THEN 35 WHEN @vector_tile_zoom > 7 AND @vector_tile_zoom <= 8 THEN (scale_linear(@vector_tile_zoom,7,8,0.35,0.65)) * 100 WHEN @vector_tile_zoom > 8 AND @vector_tile_zoom <= 15 THEN 65 WHEN @vector_tile_zoom > 15 AND @vector_tile_zoom <= 16 THEN (scale_linear(@vector_tile_zoom,15,16,0.65,0.3)) * 100 WHEN @vector_tile_zoom > 16 THEN 30 END') + self.assertEqual(raster_layer.name(), "Texture-Relief") + self.assertEqual( + raster_layer.source(), + "tilePixelRation=1&type=xyz&url=https://yyyyyy/v1/tiles/texturereliefshade/EPSG:3857/%7Bz%7D/%7Bx%7D/%7By%7D.webp&zmax=20&zmin=3", + ) + self.assertEqual( + raster_layer.pipe() + .dataDefinedProperties() + .property(QgsRasterPipe.Property.RendererOpacity) + .asExpression(), + "CASE WHEN @vector_tile_zoom >= 1 AND @vector_tile_zoom <= 7 THEN 35 WHEN @vector_tile_zoom > 7 AND @vector_tile_zoom <= 8 THEN (scale_linear(@vector_tile_zoom,7,8,0.35,0.65)) * 100 WHEN @vector_tile_zoom > 8 AND @vector_tile_zoom <= 15 THEN 65 WHEN @vector_tile_zoom > 15 AND @vector_tile_zoom <= 16 THEN (scale_linear(@vector_tile_zoom,15,16,0.65,0.3)) * 100 WHEN @vector_tile_zoom > 16 THEN 30 END", + ) def testLabelWithStops(self): context = QgsMapBoxGlStyleConversionContext() style = { "layout": { "visibility": "visible", - "text-field": { - "stops": [ - [ - 6, - "" - ], - [ - 15, - "my {class} and {stuff}" - ] - ] - } + "text-field": {"stops": [[6, ""], [15, "my {class} and {stuff}"]]}, }, "paint": { "text-color": "rgba(47, 47, 47, 1)", }, - "type": "symbol" + "type": "symbol", } - rendererStyle, has_renderer, labeling_style, has_labeling = QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + rendererStyle, has_renderer, labeling_style, has_labeling = ( + QgsMapBoxGlStyleConverter.parseSymbolLayer(style, context) + ) self.assertTrue(has_labeling) self.assertTrue(labeling_style.labelSettings().isExpression) - self.assertEqual(labeling_style.labelSettings().fieldName, 'CASE WHEN @vector_tile_zoom > 6 AND @vector_tile_zoom < 15 THEN concat(\'my \',"class",\' and \',"stuff") WHEN @vector_tile_zoom >= 15 THEN concat(\'my \',"class",\' and \',"stuff") ELSE \'\' END') + self.assertEqual( + labeling_style.labelSettings().fieldName, + "CASE WHEN @vector_tile_zoom > 6 AND @vector_tile_zoom < 15 THEN concat('my ',\"class\",' and ',\"stuff\") WHEN @vector_tile_zoom >= 15 THEN concat('my ',\"class\",' and ',\"stuff\") ELSE '' END", + ) def testFillStroke(self): context = QgsMapBoxGlStyleConversionContext() @@ -1683,9 +2384,11 @@ def testFillStroke(self): "layout": {}, "paint": { "fill-color": "rgb(71,179,18)", - } + }, } - has_renderer, renderer = QgsMapBoxGlStyleConverter.parseFillLayer(style, context) + has_renderer, renderer = QgsMapBoxGlStyleConverter.parseFillLayer( + style, context + ) self.assertTrue(has_renderer) # mapbox fill strokes are always 1 px wide @@ -1694,7 +2397,7 @@ def testFillStroke(self): self.assertEqual(renderer.symbol()[0].strokeStyle(), Qt.PenStyle.SolidLine) # if "fill-outline-color" is not specified, then MapBox specs state the # stroke color matches the value of fill-color if unspecified. - self.assertEqual(renderer.symbol()[0].strokeColor().name(), '#47b312') + self.assertEqual(renderer.symbol()[0].strokeColor().name(), "#47b312") self.assertEqual(renderer.symbol()[0].strokeColor().alpha(), 255) # explicit outline color @@ -1707,13 +2410,15 @@ def testFillStroke(self): "paint": { "fill-color": "rgb(71,179,18)", "fill-outline-color": "rgb(255,0,0)", - } + }, } - has_renderer, renderer = QgsMapBoxGlStyleConverter.parseFillLayer(style, context) + has_renderer, renderer = QgsMapBoxGlStyleConverter.parseFillLayer( + style, context + ) self.assertTrue(has_renderer) self.assertEqual(renderer.symbol()[0].strokeStyle(), Qt.PenStyle.SolidLine) - self.assertEqual(renderer.symbol()[0].strokeColor().name(), '#ff0000') + self.assertEqual(renderer.symbol()[0].strokeColor().name(), "#ff0000") self.assertEqual(renderer.symbol()[0].strokeColor().alpha(), 255) # semi-transparent fill color @@ -1725,9 +2430,11 @@ def testFillStroke(self): "layout": {}, "paint": { "fill-color": "rgb(71,179,18,0.25)", - } + }, } - has_renderer, renderer = QgsMapBoxGlStyleConverter.parseFillLayer(style, context) + has_renderer, renderer = QgsMapBoxGlStyleConverter.parseFillLayer( + style, context + ) self.assertTrue(has_renderer) # if the outline color is semi-transparent, then drawing the default 1px stroke # will result in a double rendering of strokes for adjacent polygons, @@ -1743,73 +2450,41 @@ def testFillOpacityWithStops(self): "type": "fill", "source": "esri", "source-layer": "Land", - "filter": [ - "==", - "_symbol", - 0 - ], + "filter": ["==", "_symbol", 0], "minzoom": 0, "layout": {}, "paint": { "fill-opacity": { - "stops": [ - [ - 0, - 0.1 - ], - [ - 8, - 0.2 - ], - [ - 14, - 0.32 - ], - [ - 15, - 0.6 - ], - [ - 17, - 0.8 - ] - ] + "stops": [[0, 0.1], [8, 0.2], [14, 0.32], [15, 0.6], [17, 0.8]] }, "fill-color": { "stops": [ - [ - 0, - "#e1e3d0" - ], - [ - 8, - "#e1e3d0" - ], - [ - 14, - "#E1E3D0" - ], - [ - 15, - "#ecede3" - ], - [ - 17, - "#f1f2ea" - ] + [0, "#e1e3d0"], + [8, "#e1e3d0"], + [14, "#E1E3D0"], + [15, "#ecede3"], + [17, "#f1f2ea"], ] - } - } + }, + }, } - has_renderer, renderer = QgsMapBoxGlStyleConverter.parseFillLayer(style, context) + has_renderer, renderer = QgsMapBoxGlStyleConverter.parseFillLayer( + style, context + ) self.assertTrue(has_renderer) dd_props = renderer.symbol().dataDefinedProperties() prop = dd_props.property(QgsSymbol.Property.PropertyOpacity) - self.assertEqual(prop.asExpression(), 'CASE WHEN @vector_tile_zoom >= 0 AND @vector_tile_zoom <= 8 THEN (scale_linear(@vector_tile_zoom,0,8,0.1,0.2)) * 100 WHEN @vector_tile_zoom > 8 AND @vector_tile_zoom <= 14 THEN (scale_linear(@vector_tile_zoom,8,14,0.2,0.32)) * 100 WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 15 THEN (scale_linear(@vector_tile_zoom,14,15,0.32,0.6)) * 100 WHEN @vector_tile_zoom > 15 AND @vector_tile_zoom <= 17 THEN (scale_linear(@vector_tile_zoom,15,17,0.6,0.8)) * 100 WHEN @vector_tile_zoom > 17 THEN 80 END') + self.assertEqual( + prop.asExpression(), + "CASE WHEN @vector_tile_zoom >= 0 AND @vector_tile_zoom <= 8 THEN (scale_linear(@vector_tile_zoom,0,8,0.1,0.2)) * 100 WHEN @vector_tile_zoom > 8 AND @vector_tile_zoom <= 14 THEN (scale_linear(@vector_tile_zoom,8,14,0.2,0.32)) * 100 WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 15 THEN (scale_linear(@vector_tile_zoom,14,15,0.32,0.6)) * 100 WHEN @vector_tile_zoom > 15 AND @vector_tile_zoom <= 17 THEN (scale_linear(@vector_tile_zoom,15,17,0.6,0.8)) * 100 WHEN @vector_tile_zoom > 17 THEN 80 END", + ) dd_props = renderer.symbol()[0].dataDefinedProperties() prop = dd_props.property(QgsSymbolLayer.Property.PropertyFillColor) - self.assertEqual(prop.asExpression(), 'CASE WHEN @vector_tile_zoom < 0 THEN color_hsla(66, 25, 85, 255) WHEN @vector_tile_zoom >= 0 AND @vector_tile_zoom < 8 THEN color_hsla(66, 25, 85, 255) WHEN @vector_tile_zoom >= 8 AND @vector_tile_zoom < 14 THEN color_hsla(66, 25, 85, 255) WHEN @vector_tile_zoom >= 14 AND @vector_tile_zoom < 15 THEN color_hsla(66, scale_linear(@vector_tile_zoom,14,15,25,21), scale_linear(@vector_tile_zoom,14,15,85,90), 255) WHEN @vector_tile_zoom >= 15 AND @vector_tile_zoom < 17 THEN color_hsla(scale_linear(@vector_tile_zoom,15,17,66,67), scale_linear(@vector_tile_zoom,15,17,21,23), scale_linear(@vector_tile_zoom,15,17,90,93), 255) WHEN @vector_tile_zoom >= 17 THEN color_hsla(67, 23, 93, 255) ELSE color_hsla(67, 23, 93, 255) END') + self.assertEqual( + prop.asExpression(), + "CASE WHEN @vector_tile_zoom < 0 THEN color_hsla(66, 25, 85, 255) WHEN @vector_tile_zoom >= 0 AND @vector_tile_zoom < 8 THEN color_hsla(66, 25, 85, 255) WHEN @vector_tile_zoom >= 8 AND @vector_tile_zoom < 14 THEN color_hsla(66, 25, 85, 255) WHEN @vector_tile_zoom >= 14 AND @vector_tile_zoom < 15 THEN color_hsla(66, scale_linear(@vector_tile_zoom,14,15,25,21), scale_linear(@vector_tile_zoom,14,15,85,90), 255) WHEN @vector_tile_zoom >= 15 AND @vector_tile_zoom < 17 THEN color_hsla(scale_linear(@vector_tile_zoom,15,17,66,67), scale_linear(@vector_tile_zoom,15,17,21,23), scale_linear(@vector_tile_zoom,15,17,90,93), 255) WHEN @vector_tile_zoom >= 17 THEN color_hsla(67, 23, 93, 255) ELSE color_hsla(67, 23, 93, 255) END", + ) def testFillColorDDHasBrush(self): context = QgsMapBoxGlStyleConversionContext() @@ -1820,72 +2495,56 @@ def testFillColorDDHasBrush(self): "source": "base_v1.0.0", "source-layer": "building", "minzoom": 14.0, - "layout": { - "visibility": "visible" - }, + "layout": {"visibility": "visible"}, "paint": { "fill-color": [ "interpolate", - [ - "linear" - ], - [ - "zoom" - ], + ["linear"], + ["zoom"], 14, [ "match", - [ - "get", - "class" - ], - [ - "roof", - "cooling_tower" - ], + ["get", "class"], + ["roof", "cooling_tower"], "rgb(210, 210, 214)", - "rgba(184, 184, 188, 1)" + "rgba(184, 184, 188, 1)", ], 16, [ "match", - [ - "get", - "class" - ], - [ - "roof", - "cooling_tower" - ], + ["get", "class"], + ["roof", "cooling_tower"], "rgb(210, 210, 214)", - "rgba(184, 184, 188, 1)" - ] + "rgba(184, 184, 188, 1)", + ], ], - "fill-opacity": 1 + "fill-opacity": 1, }, - "filter": [ - "all", - [ - "!=", - "class", - "covered_bridge" - ] - ] + "filter": ["all", ["!=", "class", "covered_bridge"]], } - has_renderer, renderer = QgsMapBoxGlStyleConverter.parseFillLayer(style, context) + has_renderer, renderer = QgsMapBoxGlStyleConverter.parseFillLayer( + style, context + ) self.assertTrue(has_renderer) self.assertEqual(renderer.symbol()[0].brushStyle(), Qt.BrushStyle.SolidPattern) dd_props = renderer.symbol()[0].dataDefinedProperties() prop = dd_props.property(QgsSymbolLayer.Property.PropertyFillColor) - self.assertEqual(prop.asExpression(), 'CASE WHEN @vector_tile_zoom >= 14 AND @vector_tile_zoom < 16 THEN color_hsla(color_part(CASE WHEN "class" IN (\'roof\', \'cooling_tower\') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,\'hsl_hue\'), color_part(CASE WHEN "class" IN (\'roof\', \'cooling_tower\') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,\'hsl_saturation\'), color_part(CASE WHEN "class" IN (\'roof\', \'cooling_tower\') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,\'lightness\'), color_part(CASE WHEN "class" IN (\'roof\', \'cooling_tower\') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,\'alpha\')) WHEN @vector_tile_zoom >= 16 THEN color_hsla(color_part(CASE WHEN "class" IN (\'roof\', \'cooling_tower\') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,\'hsl_hue\'), color_part(CASE WHEN "class" IN (\'roof\', \'cooling_tower\') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,\'hsl_saturation\'), color_part(CASE WHEN "class" IN (\'roof\', \'cooling_tower\') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,\'lightness\'), color_part(CASE WHEN "class" IN (\'roof\', \'cooling_tower\') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,\'alpha\')) ELSE color_hsla(color_part(CASE WHEN "class" IN (\'roof\', \'cooling_tower\') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,\'hsl_hue\'), color_part(CASE WHEN "class" IN (\'roof\', \'cooling_tower\') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,\'hsl_saturation\'), color_part(CASE WHEN "class" IN (\'roof\', \'cooling_tower\') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,\'lightness\'), color_part(CASE WHEN "class" IN (\'roof\', \'cooling_tower\') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,\'alpha\')) END') + self.assertEqual( + prop.asExpression(), + "CASE WHEN @vector_tile_zoom >= 14 AND @vector_tile_zoom < 16 THEN color_hsla(color_part(CASE WHEN \"class\" IN ('roof', 'cooling_tower') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,'hsl_hue'), color_part(CASE WHEN \"class\" IN ('roof', 'cooling_tower') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,'hsl_saturation'), color_part(CASE WHEN \"class\" IN ('roof', 'cooling_tower') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,'lightness'), color_part(CASE WHEN \"class\" IN ('roof', 'cooling_tower') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,'alpha')) WHEN @vector_tile_zoom >= 16 THEN color_hsla(color_part(CASE WHEN \"class\" IN ('roof', 'cooling_tower') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,'hsl_hue'), color_part(CASE WHEN \"class\" IN ('roof', 'cooling_tower') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,'hsl_saturation'), color_part(CASE WHEN \"class\" IN ('roof', 'cooling_tower') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,'lightness'), color_part(CASE WHEN \"class\" IN ('roof', 'cooling_tower') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,'alpha')) ELSE color_hsla(color_part(CASE WHEN \"class\" IN ('roof', 'cooling_tower') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,'hsl_hue'), color_part(CASE WHEN \"class\" IN ('roof', 'cooling_tower') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,'hsl_saturation'), color_part(CASE WHEN \"class\" IN ('roof', 'cooling_tower') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,'lightness'), color_part(CASE WHEN \"class\" IN ('roof', 'cooling_tower') THEN color_rgba(210,210,214,255) ELSE color_rgba(184,184,188,255) END,'alpha')) END", + ) def testRetrieveSprite(self): context = QgsMapBoxGlStyleConversionContext() - sprite_image_file = f'{TEST_DATA_DIR}/vector_tile/sprites/swisstopo-sprite@2x.png' - with open(sprite_image_file, 'rb') as f: + sprite_image_file = ( + f"{TEST_DATA_DIR}/vector_tile/sprites/swisstopo-sprite@2x.png" + ) + with open(sprite_image_file, "rb") as f: sprite_image = QImage() sprite_image.loadFromData(f.read()) - sprite_definition_file = f'{TEST_DATA_DIR}/vector_tile/sprites/swisstopo-sprite@2x.json' + sprite_definition_file = ( + f"{TEST_DATA_DIR}/vector_tile/sprites/swisstopo-sprite@2x.json" + ) with open(sprite_definition_file) as f: sprite_definition = json.load(f) context.setSprites(sprite_image, sprite_definition) @@ -1893,33 +2552,29 @@ def testRetrieveSprite(self): # swisstopo - lightbasemap - sinkhole icon_image = [ "match", - [ - "get", - "class" - ], + ["get", "class"], "sinkhole", "arrow_brown", - [ - "sinkhole_rock", - "sinkhole_scree" - ], + ["sinkhole_rock", "sinkhole_scree"], "arrow_grey", - [ - "sinkhole_ice", - "sinkhole_water" - ], + ["sinkhole_ice", "sinkhole_water"], "arrow_blue", - "" + "", ] - sprite, size, sprite_property, sprite_size_property = QgsMapBoxGlStyleConverter.retrieveSpriteAsBase64WithProperties(icon_image, context) - self.assertEqual(sprite_property, 'CASE WHEN "class" IN (\'sinkhole\') THEN \'base64:iVBORw0KGgoAAAANSUhEUgAAAAwAAAAgCAYAAAAmG5mqAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAArklEQVQ4jWNmQAPxrgr1EzIMDiS4KjQwMDAwXLz34SCyPBO6BkJgVMOohlEN9NTA2JWit8NUTcidGMWnb73bybT60NM+Yk1ffehpH9PpW293nb71bicxpp++9XYXE0wnMaYzMEA9TcgWmOlwDYRsQZaDa8BlC7LpKBpw2YIuhqIB3RZ00zE0oJuIzUYWTDcjbEE3nYGBgYEZXYCBgYHhw5c/r649/Hz82dvvd9HlANtvdC5jaNf5AAAAAElFTkSuQmCC\' WHEN "class" IN (\'sinkhole_rock\',\'sinkhole_scree\') THEN \'base64:iVBORw0KGgoAAAANSUhEUgAAAAwAAAAgCAYAAAAmG5mqAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAAoUlEQVQ4je2PMRLCIBBFv8QzcAbOwNB7LD1BzmNSaeUl8AJ/GDoKOhvDJGsyUFmxJct7DwaIMcZcnXMPY8wNAEIIz/VeSaA2HehAB/4JnKy1d631peUyyUl578dWu/d+VCRnklOLneSsFrLFDnw/Xass9gLUKutdAY4qa/sGOKrIsw0gK9L+A0jjXvG88+ZSkXYAGOQBAOScGWN8pZTecvcBJ6N45xp02+cAAAAASUVORK5CYII=\' WHEN "class" IN (\'sinkhole_ice\',\'sinkhole_water\') THEN \'base64:iVBORw0KGgoAAAANSUhEUgAAAAwAAAAgCAYAAAAmG5mqAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAAq0lEQVQ4jWNgQAOSXmn1xlPO/jeecva/pFdaPbo8E7oAITCqYVTDqAZ6amBUzZ6yg0/T0p0YxZ+uH9/J9HLf0j5iTX+5b2kf06frx3d9un58JzGmf7p+fBcTTCcxpjMwQD1NyBaY6XANhGxBloNrwGULsukoGnDZgi6GogHdFnTTMTSgm4jNRhYsbobbgm46AwMDAzO6AAMDA8OfL+9ffb1/+fjPN0/uossBAN+ec6mo5jjFAAAAAElFTkSuQmCC\' ELSE \'\' END') + sprite, size, sprite_property, sprite_size_property = ( + QgsMapBoxGlStyleConverter.retrieveSpriteAsBase64WithProperties( + icon_image, context + ) + ) + self.assertEqual( + sprite_property, + "CASE WHEN \"class\" IN ('sinkhole') THEN 'base64:iVBORw0KGgoAAAANSUhEUgAAAAwAAAAgCAYAAAAmG5mqAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAArklEQVQ4jWNmQAPxrgr1EzIMDiS4KjQwMDAwXLz34SCyPBO6BkJgVMOohlEN9NTA2JWit8NUTcidGMWnb73bybT60NM+Yk1ffehpH9PpW293nb71bicxpp++9XYXE0wnMaYzMEA9TcgWmOlwDYRsQZaDa8BlC7LpKBpw2YIuhqIB3RZ00zE0oJuIzUYWTDcjbEE3nYGBgYEZXYCBgYHhw5c/r649/Hz82dvvd9HlANtvdC5jaNf5AAAAAElFTkSuQmCC' WHEN \"class\" IN ('sinkhole_rock','sinkhole_scree') THEN 'base64:iVBORw0KGgoAAAANSUhEUgAAAAwAAAAgCAYAAAAmG5mqAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAAoUlEQVQ4je2PMRLCIBBFv8QzcAbOwNB7LD1BzmNSaeUl8AJ/GDoKOhvDJGsyUFmxJct7DwaIMcZcnXMPY8wNAEIIz/VeSaA2HehAB/4JnKy1d631peUyyUl578dWu/d+VCRnklOLneSsFrLFDnw/Xass9gLUKutdAY4qa/sGOKrIsw0gK9L+A0jjXvG88+ZSkXYAGOQBAOScGWN8pZTecvcBJ6N45xp02+cAAAAASUVORK5CYII=' WHEN \"class\" IN ('sinkhole_ice','sinkhole_water') THEN 'base64:iVBORw0KGgoAAAANSUhEUgAAAAwAAAAgCAYAAAAmG5mqAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAAq0lEQVQ4jWNgQAOSXmn1xlPO/jeecva/pFdaPbo8E7oAITCqYVTDqAZ6amBUzZ6yg0/T0p0YxZ+uH9/J9HLf0j5iTX+5b2kf06frx3d9un58JzGmf7p+fBcTTCcxpjMwQD1NyBaY6XANhGxBloNrwGULsukoGnDZgi6GogHdFnTTMTSgm4jNRhYsbobbgm46AwMDAzO6AAMDA8OfL+9ffb1/+fjPN0/uossBAN+ec6mo5jjFAAAAAElFTkSuQmCC' ELSE '' END", + ) # swisstopo - lightbasemap - place_village icon_image = [ "step", - [ - "zoom" - ], + ["zoom"], "circle_dark_grey_4", 6, "circle_dark_grey_4", @@ -1928,40 +2583,41 @@ def testRetrieveSprite(self): 10, "circle_dark_grey_8", 12, - "circle_dark_grey_10" + "circle_dark_grey_10", ] - sprite, size, sprite_property, sprite_size_property = QgsMapBoxGlStyleConverter.retrieveSpriteAsBase64WithProperties(icon_image, context) - self.assertEqual(sprite_property, "CASE WHEN @vector_tile_zoom >= 12 THEN 'base64:iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAA9hAAAPYQGoP6dpAAACDUlEQVQ4jZ2VsaraYBTH/8mFTAfJ4NBBJBAHcdCMHTLkES7oA6Rv0D5BvU9gQRyKQ/MCgt3qpGBcdImLyRAhg4hgwIDHxSUd2s/eek24+ptCkvP7zjk5nEjIoFgsPhNRQ1VVi4gMAGBmL0mSyel08vb7/c9bcdL1DSIyqtXqDyHJgpm9IAg+MbOXKdQ0ra1p2lcA0HUdpmnCMAxUKhUAQBiG8DwPrutivV4DAKIoakdR9PLmRE3T2pZlpZZlpd1uNz0ej2kWx+Mx7Xa7qXi/VCp9flOmeDidTjNF10yn04tUtOgJAOr1+i9FUT40m020Wq281v1HuVwGM8P3fRQKhY/b7fa7LL6mruuwbfvdMoFt29B1HURkFIvFZ1mkapomiOhuIRHBNE1xbciqqloAYBi5U5KLiFVV1bpkKEbjEUQsETXkhy23kWQx6WEYPmwRsczsyUmSTADA87y8mFxEbJIkk0uGs9kMzHy3jJkxGo3+ZRjH8ZCZl2EYwnGcu4WO42C324GZl3EcD2UACILABoDBYADXdd8tc10Xg8EArx1PAHA+n3cAJFVVrfF4jNPphFqtBkVRMsvs9/vo9XoAgDAMv8RxPLwIgT8NFdLVaoXFYoHD4QBJkkBEOJ/P8H0fo9EInU4H8/n8IttsNt+EJ2vBOkTUyCuXmZdBENi5C/Y1f5eGcesXwMyeKPGa3yGWS8B8xv1iAAAAAElFTkSuQmCC' WHEN @vector_tile_zoom >= 10 THEN 'base64:iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAA9hAAAPYQGoP6dpAAABs0lEQVQ4jY2TMW/iMBiG37iM5hQhDwyZUIYTQmruF+AtkTKU+yeMt9Dh/sDdDezlH9At3liQbksGJJYE3ZAhSBbKQaQiS8Rd6opSaHk3W8/7+vtsfxZORCn1GGN3tm1zSqkHAFVVJWVZzqSUj1VVJce8dbxwHGfouu6v01AjrfU2y7L7PM//vAvo9XpTxtgdAPi+jyAI4LouACBNU0RRBCEEAEBKOV0sFt/fnMw512EY6jiO9SXFcazDMNScc+04zvC1Z8655px/aD4O4Zzrfr//n1LqEcbYwJTted6l9l/leR5834dlWV8YYwNi2zYHgCAIPjUbGda2bU7MU5kLu0aGpZTekqtd52UR8zHSNL3aZdiqqhJSluUMAKIoujrAsGVZzoiUclrX9U4IgSRJPrECSZJACIG6rndFUTzcKKWKw+Hw1Gq1gvl8jm63i3a7fdE8Go2glEKWZT82m010AwDb7fYvpfRbo9H4KoTAer1Gs9kEpRRKKSyXS0wmE4zHYyilIKV8TNN0CJwZpk6n85MQ0jxXQV3Xu9VqdZ/n+W+zZ51CL+M8ODfORVE87Pf7f8f8M97/C1rlJ2QfAAAAAElFTkSuQmCC' WHEN @vector_tile_zoom >= 8 THEN 'base64:iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAACXBIWXMAAA9hAAAPYQGoP6dpAAABEElEQVQokXWSMW7CQBBFnx1EtcVKNFOmcIkU9xQsN0gk99kbkJ4TcIvNARA5AtxgkFyafkW1xZZITpEYUdiv/l8z8/8UPCEiXkQ+jTE1QM5ZY4whxvg9aAqA2Wxml8vl0VrrGCGldGrb9uN+v6cCoK7rk7V2vVqtaJqGqqowxqCqhBC4XC6klE6qukFEvHOu3+12/RTb7bZ3zvUi4ksR8QBN04xtA4D3/nFjORxY1/WkoaoqAIwxb+WkapyizDkrgKpOqrquA/5iLmOMAeBwOEwaQggAxBjDS85ZrbWb2+32er1eWSwWGGOYz+eoKvv9foj13HXd13NxP9ba9diElNK5bdv3R3ED/6/hR14jDJpfqBeVnGzOJRAAAAAASUVORK5CYII=' WHEN @vector_tile_zoom >= 6 THEN 'base64:iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAAv0lEQVQYlYXOIQqDYBiH8b/6IW8wOPiCAxFXTIZ1i97AbFsw7wbCbjHwAMZdwcU11wwG0aLtRcQgwlYXhP0O8PAoACCljG3bvhqGcRZCmMxctm17Y+ZSkVLGvu8/sKOqqkjzPO9ORG4QBMiyDEmSYBgG9H0PIjopYRh+AKAoCliWBQBomgZpmmLbNlb30j8UzTTNiIjccRzhOA7WdUWe5+i6DtM0vf5PLstSz/P81nX9KIQ4qKpKzPys6/rCzOUX/GBLMm760HoAAAAASUVORK5CYII=' ELSE 'base64:iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAAv0lEQVQYlYXOIQqDYBiH8b/6IW8wOPiCAxFXTIZ1i97AbFsw7wbCbjHwAMZdwcU11wwG0aLtRcQgwlYXhP0O8PAoACCljG3bvhqGcRZCmMxctm17Y+ZSkVLGvu8/sKOqqkjzPO9ORG4QBMiyDEmSYBgG9H0PIjopYRh+AKAoCliWBQBomgZpmmLbNlb30j8UzTTNiIjccRzhOA7WdUWe5+i6DtM0vf5PLstSz/P81nX9KIQ4qKpKzPys6/rCzOUX/GBLMm760HoAAAAASUVORK5CYII=' END") + sprite, size, sprite_property, sprite_size_property = ( + QgsMapBoxGlStyleConverter.retrieveSpriteAsBase64WithProperties( + icon_image, context + ) + ) + self.assertEqual( + sprite_property, + "CASE WHEN @vector_tile_zoom >= 12 THEN 'base64:iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAA9hAAAPYQGoP6dpAAACDUlEQVQ4jZ2VsaraYBTH/8mFTAfJ4NBBJBAHcdCMHTLkES7oA6Rv0D5BvU9gQRyKQ/MCgt3qpGBcdImLyRAhg4hgwIDHxSUd2s/eek24+ptCkvP7zjk5nEjIoFgsPhNRQ1VVi4gMAGBmL0mSyel08vb7/c9bcdL1DSIyqtXqDyHJgpm9IAg+MbOXKdQ0ra1p2lcA0HUdpmnCMAxUKhUAQBiG8DwPrutivV4DAKIoakdR9PLmRE3T2pZlpZZlpd1uNz0ej2kWx+Mx7Xa7qXi/VCp9flOmeDidTjNF10yn04tUtOgJAOr1+i9FUT40m020Wq281v1HuVwGM8P3fRQKhY/b7fa7LL6mruuwbfvdMoFt29B1HURkFIvFZ1mkapomiOhuIRHBNE1xbciqqloAYBi5U5KLiFVV1bpkKEbjEUQsETXkhy23kWQx6WEYPmwRsczsyUmSTADA87y8mFxEbJIkk0uGs9kMzHy3jJkxGo3+ZRjH8ZCZl2EYwnGcu4WO42C324GZl3EcD2UACILABoDBYADXdd8tc10Xg8EArx1PAHA+n3cAJFVVrfF4jNPphFqtBkVRMsvs9/vo9XoAgDAMv8RxPLwIgT8NFdLVaoXFYoHD4QBJkkBEOJ/P8H0fo9EInU4H8/n8IttsNt+EJ2vBOkTUyCuXmZdBENi5C/Y1f5eGcesXwMyeKPGa3yGWS8B8xv1iAAAAAElFTkSuQmCC' WHEN @vector_tile_zoom >= 10 THEN 'base64:iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAA9hAAAPYQGoP6dpAAABs0lEQVQ4jY2TMW/iMBiG37iM5hQhDwyZUIYTQmruF+AtkTKU+yeMt9Dh/sDdDezlH9At3liQbksGJJYE3ZAhSBbKQaQiS8Rd6opSaHk3W8/7+vtsfxZORCn1GGN3tm1zSqkHAFVVJWVZzqSUj1VVJce8dbxwHGfouu6v01AjrfU2y7L7PM//vAvo9XpTxtgdAPi+jyAI4LouACBNU0RRBCEEAEBKOV0sFt/fnMw512EY6jiO9SXFcazDMNScc+04zvC1Z8655px/aD4O4Zzrfr//n1LqEcbYwJTted6l9l/leR5834dlWV8YYwNi2zYHgCAIPjUbGda2bU7MU5kLu0aGpZTekqtd52UR8zHSNL3aZdiqqhJSluUMAKIoujrAsGVZzoiUclrX9U4IgSRJPrECSZJACIG6rndFUTzcKKWKw+Hw1Gq1gvl8jm63i3a7fdE8Go2glEKWZT82m010AwDb7fYvpfRbo9H4KoTAer1Gs9kEpRRKKSyXS0wmE4zHYyilIKV8TNN0CJwZpk6n85MQ0jxXQV3Xu9VqdZ/n+W+zZ51CL+M8ODfORVE87Pf7f8f8M97/C1rlJ2QfAAAAAElFTkSuQmCC' WHEN @vector_tile_zoom >= 8 THEN 'base64:iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAACXBIWXMAAA9hAAAPYQGoP6dpAAABEElEQVQokXWSMW7CQBBFnx1EtcVKNFOmcIkU9xQsN0gk99kbkJ4TcIvNARA5AtxgkFyafkW1xZZITpEYUdiv/l8z8/8UPCEiXkQ+jTE1QM5ZY4whxvg9aAqA2Wxml8vl0VrrGCGldGrb9uN+v6cCoK7rk7V2vVqtaJqGqqowxqCqhBC4XC6klE6qukFEvHOu3+12/RTb7bZ3zvUi4ksR8QBN04xtA4D3/nFjORxY1/WkoaoqAIwxb+WkapyizDkrgKpOqrquA/5iLmOMAeBwOEwaQggAxBjDS85ZrbWb2+32er1eWSwWGGOYz+eoKvv9foj13HXd13NxP9ba9diElNK5bdv3R3ED/6/hR14jDJpfqBeVnGzOJRAAAAAASUVORK5CYII=' WHEN @vector_tile_zoom >= 6 THEN 'base64:iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAAv0lEQVQYlYXOIQqDYBiH8b/6IW8wOPiCAxFXTIZ1i97AbFsw7wbCbjHwAMZdwcU11wwG0aLtRcQgwlYXhP0O8PAoACCljG3bvhqGcRZCmMxctm17Y+ZSkVLGvu8/sKOqqkjzPO9ORG4QBMiyDEmSYBgG9H0PIjopYRh+AKAoCliWBQBomgZpmmLbNlb30j8UzTTNiIjccRzhOA7WdUWe5+i6DtM0vf5PLstSz/P81nX9KIQ4qKpKzPys6/rCzOUX/GBLMm760HoAAAAASUVORK5CYII=' ELSE 'base64:iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAAv0lEQVQYlYXOIQqDYBiH8b/6IW8wOPiCAxFXTIZ1i97AbFsw7wbCbjHwAMZdwcU11wwG0aLtRcQgwlYXhP0O8PAoACCljG3bvhqGcRZCmMxctm17Y+ZSkVLGvu8/sKOqqkjzPO9ORG4QBMiyDEmSYBgG9H0PIjopYRh+AKAoCliWBQBomgZpmmLbNlb30j8UzTTNiIjccRzhOA7WdUWe5+i6DtM0vf5PLstSz/P81nX9KIQ4qKpKzPys6/rCzOUX/GBLMm760HoAAAAASUVORK5CYII=' END", + ) # swisstopo - lightbasemap - lake_elevation icon_image = [ "case", - [ - "has", - "lake_depth" - ], + ["has", "lake_depth"], "arrow_line_blue", - [ - "==", - [ - "length", - [ - "to-string", - [ - "get", - "ele" - ] - ] - ], - 3 - ], + ["==", ["length", ["to-string", ["get", "ele"]]], 3], "line_blue_short", - "line_blue_long" + "line_blue_long", ] - sprite, size, sprite_property, sprite_size_property = QgsMapBoxGlStyleConverter.retrieveSpriteAsBase64WithProperties(icon_image, context) - self.assertEqual(sprite_property, "CASE WHEN \"lake_depth\" IS NOT NULL THEN 'base64:iVBORw0KGgoAAAANSUhEUgAAADAAAAAmCAYAAACCjRgBAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAA3UlEQVRYhe3WMQrCMBgF4Nfo7C0cnDt5Ar2LnsWpHsE72A6umTo5ZBBxcVEEIeggCHVxCKWtLUj/BN63tfzD/16gTYSW4iQv2s72SUkvQERERER/FCd54evNs0rwt1EGkMYA0hhAGgNIYwBpDCAtGi+S7WgynTUNWaPTw3o572upLtRlt1n9GmozI0VZozNrdFo3YI1OrdFZn0t1oYDmhn1uH/gGqDsF39sHnK9QVdO+tw84AcqnEEL7QOk/4DYeQvsAMHQf3FMIoX0AGJRfvB/36/O016/b+SixUFcfqsZi6d4Ghu0AAAAASUVORK5CYII=' WHEN length(to_string(\"ele\")) IS 3 THEN 'base64:iVBORw0KGgoAAAANSUhEUgAAACQAAAAECAYAAADmrJ2uAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAAGElEQVQokWM0nnL2P8MgAkwD7YBRQCoAANWHApf/BqmbAAAAAElFTkSuQmCC' ELSE 'base64:iVBORw0KGgoAAAANSUhEUgAAADAAAAAECAYAAADI6bw8AAAACXBIWXMAAA9hAAAPYQGoP6dpAAAAGElEQVQokWM0nnL2P8MQBkwD7YBRMNQBAMaFApc4aKj/AAAAAElFTkSuQmCC' END") - self.assertEqual(sprite_size_property, "CASE WHEN \"lake_depth\" IS NOT NULL THEN 24 WHEN length(to_string(\"ele\")) IS 3 THEN 18 ELSE 24 END") + sprite, size, sprite_property, sprite_size_property = ( + QgsMapBoxGlStyleConverter.retrieveSpriteAsBase64WithProperties( + icon_image, context + ) + ) + self.assertEqual( + sprite_property, + "CASE WHEN \"lake_depth\" IS NOT NULL THEN 'base64:iVBORw0KGgoAAAANSUhEUgAAADAAAAAmCAYAAACCjRgBAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAA3UlEQVRYhe3WMQrCMBgF4Nfo7C0cnDt5Ar2LnsWpHsE72A6umTo5ZBBxcVEEIeggCHVxCKWtLUj/BN63tfzD/16gTYSW4iQv2s72SUkvQERERER/FCd54evNs0rwt1EGkMYA0hhAGgNIYwBpDCAtGi+S7WgynTUNWaPTw3o572upLtRlt1n9GmozI0VZozNrdFo3YI1OrdFZn0t1oYDmhn1uH/gGqDsF39sHnK9QVdO+tw84AcqnEEL7QOk/4DYeQvsAMHQf3FMIoX0AGJRfvB/36/O016/b+SixUFcfqsZi6d4Ghu0AAAAASUVORK5CYII=' WHEN length(to_string(\"ele\")) IS 3 THEN 'base64:iVBORw0KGgoAAAANSUhEUgAAACQAAAAECAYAAADmrJ2uAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAAGElEQVQokWM0nnL2P8MgAkwD7YBRQCoAANWHApf/BqmbAAAAAElFTkSuQmCC' ELSE 'base64:iVBORw0KGgoAAAANSUhEUgAAADAAAAAECAYAAADI6bw8AAAACXBIWXMAAA9hAAAPYQGoP6dpAAAAGElEQVQokWM0nnL2P8MQBkwD7YBRMNQBAMaFApc4aKj/AAAAAElFTkSuQmCC' END", + ) + self.assertEqual( + sprite_size_property, + 'CASE WHEN "lake_depth" IS NOT NULL THEN 24 WHEN length(to_string("ele")) IS 3 THEN 18 ELSE 24 END', + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmapcanvas.py b/tests/src/python/test_qgsmapcanvas.py index 214d2c209c8b..5cfa0e3ee39a 100644 --- a/tests/src/python/test_qgsmapcanvas.py +++ b/tests/src/python/test_qgsmapcanvas.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '24/1/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "24/1/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import time import os @@ -38,7 +39,7 @@ QgsSingleSymbolRenderer, QgsTemporalController, QgsTemporalNavigationObject, - QgsVectorLayer + QgsVectorLayer, ) from qgis.gui import QgsMapCanvas, QgsMapToolPan, QgsMapToolZoom, QgsMapToolEmitPoint import unittest @@ -62,16 +63,17 @@ def testGettersSetters(self): self.assertTrue(canvas.previewJobsEnabled()) def testDeferredUpdate(self): - """ test that map canvas doesn't auto refresh on deferred layer update """ + """test that map canvas doesn't auto refresh on deferred layer update""" canvas = QgsMapCanvas() - canvas.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + canvas.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) canvas.setFrameStyle(0) canvas.resize(600, 400) self.assertEqual(canvas.width(), 600) self.assertEqual(canvas.height(), 400) - layer = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string", - "layer", "memory") + layer = QgsVectorLayer( + "Polygon?crs=epsg:4326&field=fldtxt:string", "layer", "memory" + ) canvas.setLayers([layer]) canvas.setExtent(QgsRectangle(10, 30, 20, 35)) @@ -82,9 +84,13 @@ def testDeferredUpdate(self): canvas.waitWhileRendering() rendered_image = self.canvas_to_image(canvas) self.assertTrue( - self.image_check('empty_canvas', 'empty_canvas', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "empty_canvas", + "empty_canvas", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) # add polygon to layer @@ -101,9 +107,13 @@ def testDeferredUpdate(self): # canvas should still be empty rendered_image = self.canvas_to_image(canvas) self.assertTrue( - self.image_check('empty_canvas', 'empty_canvas', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "empty_canvas", + "empty_canvas", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) # refresh canvas @@ -113,23 +123,28 @@ def testDeferredUpdate(self): # now we expect the canvas check to fail (since they'll be a new polygon rendered over it) rendered_image = self.canvas_to_image(canvas) self.assertFalse( - self.image_check('empty_canvas', 'empty_canvas', rendered_image, - color_tolerance=2, - allowed_mismatch=20, - expect_fail=True) + self.image_check( + "empty_canvas", + "empty_canvas", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + expect_fail=True, + ) ) def testRefreshOnTimer(self): - """ test that map canvas refreshes with auto refreshing layers """ + """test that map canvas refreshes with auto refreshing layers""" canvas = QgsMapCanvas() - canvas.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + canvas.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) canvas.setFrameStyle(0) canvas.resize(600, 400) self.assertEqual(canvas.width(), 600) self.assertEqual(canvas.height(), 400) - layer = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string", - "layer", "memory") + layer = QgsVectorLayer( + "Polygon?crs=epsg:4326&field=fldtxt:string", "layer", "memory" + ) canvas.setLayers([layer]) canvas.setExtent(QgsRectangle(10, 30, 20, 35)) @@ -141,9 +156,13 @@ def testRefreshOnTimer(self): canvas.waitWhileRendering() rendered_image = self.canvas_to_image(canvas) self.assertTrue( - self.image_check('empty_canvas', 'empty_canvas', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "empty_canvas", + "empty_canvas", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) # add polygon to layer @@ -179,10 +198,14 @@ def testRefreshOnTimer(self): # now canvas should look different... rendered_image = self.canvas_to_image(canvas) self.assertFalse( - self.image_check('empty_canvas', 'empty_canvas', rendered_image, - color_tolerance=2, - allowed_mismatch=20, - expect_fail=True) + self.image_check( + "empty_canvas", + "empty_canvas", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + expect_fail=True, + ) ) # switch off auto refresh @@ -193,14 +216,15 @@ def testRefreshOnTimer(self): self.assertFalse(canvas.isDrawing()) def testCancelAndDestroy(self): - """ test that nothing goes wrong if we destroy a canvas while a job is canceling """ + """test that nothing goes wrong if we destroy a canvas while a job is canceling""" canvas = QgsMapCanvas() - canvas.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + canvas.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) canvas.setFrameStyle(0) canvas.resize(600, 400) - layer = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string", - "layer", "memory") + layer = QgsVectorLayer( + "Polygon?crs=epsg:4326&field=fldtxt:string", "layer", "memory" + ) # add a ton of features for i in range(5000): @@ -222,21 +246,22 @@ def testCancelAndDestroy(self): def testMapTheme(self): canvas = QgsMapCanvas() - canvas.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + canvas.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) canvas.setFrameStyle(0) canvas.resize(600, 400) self.assertEqual(canvas.width(), 600) self.assertEqual(canvas.height(), 400) - layer = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string", - "layer", "memory") + layer = QgsVectorLayer( + "Polygon?crs=epsg:4326&field=fldtxt:string", "layer", "memory" + ) # add a polygon to layer f = QgsFeature() f.setGeometry(QgsGeometry.fromRect(QgsRectangle(5, 25, 25, 45))) self.assertTrue(layer.dataProvider().addFeatures([f])) # create a style - sym1 = QgsFillSymbol.createSimple({'color': '#ffb200'}) + sym1 = QgsFillSymbol.createSimple({"color": "#ffb200"}) renderer = QgsSingleSymbolRenderer(sym1) layer.setRenderer(renderer) @@ -250,35 +275,47 @@ def testMapTheme(self): canvas.waitWhileRendering() rendered_image = self.canvas_to_image(canvas) self.assertTrue( - self.image_check('theme1', 'theme1', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "theme1", + "theme1", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) # add some styles - layer.styleManager().addStyleFromLayer('style1') - sym2 = QgsFillSymbol.createSimple({'color': '#00b2ff'}) + layer.styleManager().addStyleFromLayer("style1") + sym2 = QgsFillSymbol.createSimple({"color": "#00b2ff"}) renderer2 = QgsSingleSymbolRenderer(sym2) layer.setRenderer(renderer2) - layer.styleManager().addStyleFromLayer('style2') + layer.styleManager().addStyleFromLayer("style2") canvas.refresh() canvas.waitWhileRendering() rendered_image = self.canvas_to_image(canvas) self.assertTrue( - self.image_check('theme2', 'theme2', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "theme2", + "theme2", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) - layer.styleManager().setCurrentStyle('style1') + layer.styleManager().setCurrentStyle("style1") canvas.refresh() canvas.waitWhileRendering() rendered_image = self.canvas_to_image(canvas) self.assertTrue( - self.image_check('theme1', 'theme1', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "theme1", + "theme1", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) # OK, so all good with setting/rendering map styles @@ -287,48 +324,57 @@ def testMapTheme(self): # make some themes... theme1 = QgsMapThemeCollection.MapThemeRecord() record1 = QgsMapThemeCollection.MapThemeLayerRecord(layer) - record1.currentStyle = 'style1' + record1.currentStyle = "style1" record1.usingCurrentStyle = True theme1.setLayerRecords([record1]) theme2 = QgsMapThemeCollection.MapThemeRecord() record2 = QgsMapThemeCollection.MapThemeLayerRecord(layer) - record2.currentStyle = 'style2' + record2.currentStyle = "style2" record2.usingCurrentStyle = True theme2.setLayerRecords([record2]) - QgsProject.instance().mapThemeCollection().insert('theme1', theme1) - QgsProject.instance().mapThemeCollection().insert('theme2', theme2) + QgsProject.instance().mapThemeCollection().insert("theme1", theme1) + QgsProject.instance().mapThemeCollection().insert("theme2", theme2) - canvas.setTheme('theme2') + canvas.setTheme("theme2") canvas.refresh() canvas.waitWhileRendering() rendered_image = self.canvas_to_image(canvas) self.assertTrue( - self.image_check('theme2', 'theme2', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "theme2", + "theme2", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) - canvas.setTheme('theme1') + canvas.setTheme("theme1") canvas.refresh() canvas.waitWhileRendering() rendered_image = self.canvas_to_image(canvas) self.assertTrue( - self.image_check('theme1', 'theme1', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "theme1", + "theme1", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) # add another layer - layer2 = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string", - "layer2", "memory") + layer2 = QgsVectorLayer( + "Polygon?crs=epsg:4326&field=fldtxt:string", "layer2", "memory" + ) f = QgsFeature() f.setGeometry(QgsGeometry.fromRect(QgsRectangle(5, 25, 25, 45))) self.assertTrue(layer2.dataProvider().addFeatures([f])) # create a style - sym1 = QgsFillSymbol.createSimple({'color': '#b2ff00'}) + sym1 = QgsFillSymbol.createSimple({"color": "#b2ff00"}) renderer = QgsSingleSymbolRenderer(sym1) layer2.setRenderer(renderer) @@ -337,61 +383,81 @@ def testMapTheme(self): canvas.waitWhileRendering() rendered_image = self.canvas_to_image(canvas) self.assertTrue( - self.image_check('theme1', 'theme1', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "theme1", + "theme1", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) # test again - this time refresh all layers canvas.refreshAllLayers() canvas.waitWhileRendering() rendered_image = self.canvas_to_image(canvas) self.assertTrue( - self.image_check('theme1', 'theme1', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "theme1", + "theme1", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) # add layer 2 to theme1 record3 = QgsMapThemeCollection.MapThemeLayerRecord(layer2) theme1.setLayerRecords([record3]) - QgsProject.instance().mapThemeCollection().update('theme1', theme1) + QgsProject.instance().mapThemeCollection().update("theme1", theme1) canvas.refresh() canvas.waitWhileRendering() rendered_image = self.canvas_to_image(canvas) self.assertTrue( - self.image_check('theme3', 'theme3', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "theme3", + "theme3", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) # change the appearance of an active style - layer2.styleManager().addStyleFromLayer('original') - layer2.styleManager().addStyleFromLayer('style4') - record3.currentStyle = 'style4' + layer2.styleManager().addStyleFromLayer("original") + layer2.styleManager().addStyleFromLayer("style4") + record3.currentStyle = "style4" record3.usingCurrentStyle = True theme1.setLayerRecords([record3]) - QgsProject.instance().mapThemeCollection().update('theme1', theme1) + QgsProject.instance().mapThemeCollection().update("theme1", theme1) canvas.refresh() canvas.waitWhileRendering() rendered_image = self.canvas_to_image(canvas) self.assertTrue( - self.image_check('theme3', 'theme3', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "theme3", + "theme3", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) - layer2.styleManager().setCurrentStyle('style4') - sym3 = QgsFillSymbol.createSimple({'color': '#b200b2'}) + layer2.styleManager().setCurrentStyle("style4") + sym3 = QgsFillSymbol.createSimple({"color": "#b200b2"}) layer2.renderer().setSymbol(sym3) canvas.refresh() canvas.waitWhileRendering() rendered_image = self.canvas_to_image(canvas) self.assertTrue( - self.image_check('theme4', 'theme4', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "theme4", + "theme4", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) # try setting layers while a theme is in place @@ -402,66 +468,79 @@ def testMapTheme(self): canvas.waitWhileRendering() rendered_image = self.canvas_to_image(canvas) self.assertTrue( - self.image_check('theme4', 'theme4', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "theme4", + "theme4", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) # setLayerStyleOverrides while theme is in place - canvas.setLayerStyleOverrides({layer2.id(): 'original'}) + canvas.setLayerStyleOverrides({layer2.id(): "original"}) # should be no change... setLayerStyleOverrides should be ignored if canvas is following a theme! canvas.refresh() canvas.waitWhileRendering() rendered_image = self.canvas_to_image(canvas) self.assertTrue( - self.image_check('theme4', 'theme4', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "theme4", + "theme4", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) # clear theme - canvas.setTheme('') + canvas.setTheme("") canvas.refresh() canvas.waitWhileRendering() # should be different - we should now render project layers rendered_image = self.canvas_to_image(canvas) self.assertFalse( - self.image_check('theme4', 'theme4', rendered_image, - color_tolerance=2, - allowed_mismatch=20, - expect_fail=True) + self.image_check( + "theme4", + "theme4", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + expect_fail=True, + ) ) # set canvas to theme1 - canvas.setTheme('theme1') + canvas.setTheme("theme1") canvas.refresh() canvas.waitWhileRendering() - self.assertEqual(canvas.theme(), 'theme1') + self.assertEqual(canvas.theme(), "theme1") themeLayers = theme1.layerRecords() # rename the active theme - QgsProject.instance().mapThemeCollection().renameMapTheme('theme1', 'theme5') + QgsProject.instance().mapThemeCollection().renameMapTheme("theme1", "theme5") # canvas theme should now be set to theme5 canvas.refresh() canvas.waitWhileRendering() - self.assertEqual(canvas.theme(), 'theme5') + self.assertEqual(canvas.theme(), "theme5") # theme5 should render as theme1 - theme5 = QgsProject.instance().mapThemeCollection().mapThemeState('theme5') + theme5 = QgsProject.instance().mapThemeCollection().mapThemeState("theme5") theme5Layers = theme5.layerRecords() - self.assertEqual(themeLayers, theme5Layers, 'themes are different') + self.assertEqual(themeLayers, theme5Layers, "themes are different") # self.assertTrue(self.canvasImageCheck('theme5', 'theme5', canvas)) def testMainAnnotationLayerRendered(self): - """ test that main annotation layer is rendered above all other layers """ + """test that main annotation layer is rendered above all other layers""" canvas = QgsMapCanvas() - canvas.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + canvas.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) canvas.setFrameStyle(0) canvas.resize(600, 400) self.assertEqual(canvas.width(), 600) self.assertEqual(canvas.height(), 400) - layer = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string", - "layer", "memory") - sym3 = QgsFillSymbol.createSimple({'color': '#b200b2'}) + layer = QgsVectorLayer( + "Polygon?crs=epsg:4326&field=fldtxt:string", "layer", "memory" + ) + sym3 = QgsFillSymbol.createSimple({"color": "#b200b2"}) layer.renderer().setSymbol(sym3) canvas.setLayers([layer]) @@ -473,9 +552,13 @@ def testMainAnnotationLayerRendered(self): canvas.waitWhileRendering() rendered_image = self.canvas_to_image(canvas) self.assertTrue( - self.image_check('empty_canvas', 'empty_canvas', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "empty_canvas", + "empty_canvas", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) # add polygon to layer @@ -490,17 +573,21 @@ def testMainAnnotationLayerRendered(self): # no annotation yet... rendered_image = self.canvas_to_image(canvas) self.assertFalse( - self.image_check('main_annotation_layer', 'main_annotation_layer', rendered_image, - color_tolerance=2, - allowed_mismatch=20, - expect_fail=True) + self.image_check( + "main_annotation_layer", + "main_annotation_layer", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + expect_fail=True, + ) ) annotation_layer = QgsProject.instance().mainAnnotationLayer() - annotation_layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + annotation_layer.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) annotation_geom = QgsGeometry.fromRect(QgsRectangle(12, 30, 18, 33)) annotation = QgsAnnotationPolygonItem(annotation_geom.constGet().clone()) - sym3 = QgsFillSymbol.createSimple({'color': '#ff0000', 'outline_style': 'no'}) + sym3 = QgsFillSymbol.createSimple({"color": "#ff0000", "outline_style": "no"}) annotation.setSymbol(sym3) annotation_layer.addItem(annotation) @@ -513,10 +600,14 @@ def testMainAnnotationLayerRendered(self): # should NOT be shown, as ShowMainAnnotationLayer flag not set self.assertFalse( - self.image_check('main_annotation_layer', 'main_annotation_layer', rendered_image, - color_tolerance=2, - allowed_mismatch=20, - expect_fail=True) + self.image_check( + "main_annotation_layer", + "main_annotation_layer", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + expect_fail=True, + ) ) canvas.setFlags(Qgis.MapCanvasFlag.ShowMainAnnotationLayer) @@ -525,9 +616,13 @@ def testMainAnnotationLayerRendered(self): rendered_image = self.canvas_to_image(canvas) # now annotation should be rendered self.assertTrue( - self.image_check('main_annotation_layer', 'main_annotation_layer', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "main_annotation_layer", + "main_annotation_layer", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) annotation_layer.clear() @@ -536,7 +631,7 @@ def canvas_to_image(self, canvas: QgsMapCanvas) -> QImage: Returns a QImage from a canvas """ with tempfile.TemporaryDirectory() as temp_dir: - tmpfile = os.path.join(temp_dir, 'test_image.png') + tmpfile = os.path.join(temp_dir, "test_image.png") canvas.saveAsImage(tmpfile) im = QImage(tmpfile) return im @@ -546,14 +641,16 @@ def testSaveCanvasVariablesToProject(self): Ensure that temporary canvas atlas variables are not written to project """ c1 = QgsMapCanvas() - c1.setObjectName('c1') - c1.expressionContextScope().setVariable('atlas_featurenumber', 1111) - c1.expressionContextScope().setVariable('atlas_pagename', 'bb') - c1.expressionContextScope().setVariable('atlas_feature', QgsFeature(1)) - c1.expressionContextScope().setVariable('atlas_featureid', 22) - c1.expressionContextScope().setVariable('atlas_geometry', QgsGeometry.fromWkt('Point( 1 2 )')) - c1.expressionContextScope().setVariable('vara', 1111) - c1.expressionContextScope().setVariable('varb', 'bb') + c1.setObjectName("c1") + c1.expressionContextScope().setVariable("atlas_featurenumber", 1111) + c1.expressionContextScope().setVariable("atlas_pagename", "bb") + c1.expressionContextScope().setVariable("atlas_feature", QgsFeature(1)) + c1.expressionContextScope().setVariable("atlas_featureid", 22) + c1.expressionContextScope().setVariable( + "atlas_geometry", QgsGeometry.fromWkt("Point( 1 2 )") + ) + c1.expressionContextScope().setVariable("vara", 1111) + c1.expressionContextScope().setVariable("varb", "bb") doc = QDomDocument("testdoc") elem = doc.createElement("qgis") @@ -561,27 +658,29 @@ def testSaveCanvasVariablesToProject(self): c1.writeProject(doc) c2 = QgsMapCanvas() - c2.setObjectName('c1') + c2.setObjectName("c1") c2.readProject(doc) - self.assertCountEqual(c2.expressionContextScope().variableNames(), ['vara', 'varb']) - self.assertEqual(c2.expressionContextScope().variable('vara'), 1111) - self.assertEqual(c2.expressionContextScope().variable('varb'), 'bb') + self.assertCountEqual( + c2.expressionContextScope().variableNames(), ["vara", "varb"] + ) + self.assertEqual(c2.expressionContextScope().variable("vara"), 1111) + self.assertEqual(c2.expressionContextScope().variable("varb"), "bb") def testSaveMultipleCanvasesToProject(self): # test saving/restoring canvas state to project with multiple canvases c1 = QgsMapCanvas() - c1.setObjectName('c1') - c1.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3111')) + c1.setObjectName("c1") + c1.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3111")) c1.setRotation(45) - c1.expressionContextScope().setVariable('vara', 1111) - c1.expressionContextScope().setVariable('varb', 'bb') + c1.expressionContextScope().setVariable("vara", 1111) + c1.expressionContextScope().setVariable("varb", "bb") c2 = QgsMapCanvas() - c2.setObjectName('c2') - c2.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + c2.setObjectName("c2") + c2.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) c2.setRotation(65) - c2.expressionContextScope().setVariable('vara', 2222) - c2.expressionContextScope().setVariable('varc', 'cc') + c2.expressionContextScope().setVariable("vara", 2222) + c2.expressionContextScope().setVariable("varc", "cc") doc = QDomDocument("testdoc") elem = doc.createElement("qgis") @@ -590,22 +689,26 @@ def testSaveMultipleCanvasesToProject(self): c2.writeProject(doc) c3 = QgsMapCanvas() - c3.setObjectName('c1') + c3.setObjectName("c1") c4 = QgsMapCanvas() - c4.setObjectName('c2') + c4.setObjectName("c2") c3.readProject(doc) c4.readProject(doc) - self.assertEqual(c3.mapSettings().destinationCrs().authid(), 'EPSG:3111') + self.assertEqual(c3.mapSettings().destinationCrs().authid(), "EPSG:3111") self.assertEqual(c3.rotation(), 45) - self.assertEqual(set(c3.expressionContextScope().variableNames()), {'vara', 'varb'}) - self.assertEqual(c3.expressionContextScope().variable('vara'), 1111) - self.assertEqual(c3.expressionContextScope().variable('varb'), 'bb') - self.assertEqual(c4.mapSettings().destinationCrs().authid(), 'EPSG:4326') + self.assertEqual( + set(c3.expressionContextScope().variableNames()), {"vara", "varb"} + ) + self.assertEqual(c3.expressionContextScope().variable("vara"), 1111) + self.assertEqual(c3.expressionContextScope().variable("varb"), "bb") + self.assertEqual(c4.mapSettings().destinationCrs().authid(), "EPSG:4326") self.assertEqual(c4.rotation(), 65) - self.assertEqual(set(c4.expressionContextScope().variableNames()), {'vara', 'varc'}) - self.assertEqual(c4.expressionContextScope().variable('vara'), 2222) - self.assertEqual(c4.expressionContextScope().variable('varc'), 'cc') + self.assertEqual( + set(c4.expressionContextScope().variableNames()), {"vara", "varc"} + ) + self.assertEqual(c4.expressionContextScope().variable("vara"), 2222) + self.assertEqual(c4.expressionContextScope().variable("varc"), "cc") def testLockedScale(self): """Test zoom/pan/center operations when scale lock is on""" @@ -647,7 +750,10 @@ def testLockedScale(self): self.assertEqual(round(c.center().x(), 1), 6.5) self.assertEqual(round(c.center().y(), 1), 46.6) self.assertEqual(round(c.scale()), 2500000) - self.assertTrue(c.magnificationFactor() > (14 / dpr) and c.magnificationFactor() < (16 / dpr)) + self.assertTrue( + c.magnificationFactor() > (14 / dpr) + and c.magnificationFactor() < (16 / dpr) + ) # out ... c.zoomWithCenter(300, 200, False) self.assertEqual(round(c.center().x(), 1), 6.5) @@ -688,26 +794,47 @@ def testLockedScale(self): def test_rendered_items(self): canvas = QgsMapCanvas() - canvas.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + canvas.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) canvas.setFrameStyle(0) canvas.resize(600, 400) canvas.setCachingEnabled(True) self.assertEqual(canvas.width(), 600) self.assertEqual(canvas.height(), 400) - layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) + layer = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) self.assertTrue(layer.isValid()) - layer2 = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) + layer2 = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) self.assertTrue(layer2.isValid()) item = QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(11.5, 13), QgsPoint(12, 13), QgsPoint(12, 13.5), QgsPoint(11.5, 13)]))) + QgsPolygon( + QgsLineString( + [ + QgsPoint(11.5, 13), + QgsPoint(12, 13), + QgsPoint(12, 13.5), + QgsPoint(11.5, 13), + ] + ) + ) + ) item.setSymbol( - QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2'})) + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black", "outline_width": "2"} + ) + ) item.setZIndex(1) i1_id = layer.addItem(item) - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])) + item = QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]) + ) item.setZIndex(2) i2_id = layer.addItem(item) @@ -715,8 +842,8 @@ def test_rendered_items(self): item.setZIndex(3) i3_id = layer2.addItem(item) - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) - layer2.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) + layer2.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) canvas.setLayers([layer, layer2]) canvas.setExtent(QgsRectangle(10, 10, 18, 18)) @@ -728,7 +855,9 @@ def test_rendered_items(self): canvas.waitWhileRendering() results = canvas.renderedItemResults() - self.assertCountEqual([i.itemId() for i in results.renderedItems()], [i1_id, i2_id, i3_id]) + self.assertCountEqual( + [i.itemId() for i in results.renderedItems()], [i1_id, i2_id, i3_id] + ) # turn off a layer -- the other layer will be rendered direct from the cached version canvas.setLayers([layer2]) @@ -750,33 +879,56 @@ def test_rendered_items(self): results = canvas.renderedItemResults() # both layer1 and layer2 items should be present in results -- even though NEITHER of these layers were re-rendered, # and instead we used precached renders of both layers - self.assertCountEqual([i.itemId() for i in results.renderedItems()], [i1_id, i2_id, i3_id]) + self.assertCountEqual( + [i.itemId() for i in results.renderedItems()], [i1_id, i2_id, i3_id] + ) def test_rendered_item_results_remove_outdated(self): """ Test that outdated results are removed from rendered item result caches """ canvas = QgsMapCanvas() - canvas.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + canvas.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) canvas.setFrameStyle(0) canvas.resize(600, 400) canvas.setCachingEnabled(True) self.assertEqual(canvas.width(), 600) self.assertEqual(canvas.height(), 400) - layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) + layer = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) self.assertTrue(layer.isValid()) - layer2 = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) + layer2 = QgsAnnotationLayer( + "test", + QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()), + ) self.assertTrue(layer2.isValid()) item = QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(11.5, 13), QgsPoint(12, 13), QgsPoint(12, 13.5), QgsPoint(11.5, 13)]))) + QgsPolygon( + QgsLineString( + [ + QgsPoint(11.5, 13), + QgsPoint(12, 13), + QgsPoint(12, 13.5), + QgsPoint(11.5, 13), + ] + ) + ) + ) item.setSymbol( - QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2'})) + QgsFillSymbol.createSimple( + {"color": "200,100,100", "outline_color": "black", "outline_width": "2"} + ) + ) item.setZIndex(1) i1_id = layer.addItem(item) - item = QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])) + item = QgsAnnotationLineItem( + QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]) + ) item.setZIndex(2) i2_id = layer.addItem(item) @@ -784,8 +936,8 @@ def test_rendered_item_results_remove_outdated(self): item.setZIndex(3) i3_id = layer2.addItem(item) - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) - layer2.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) + layer2.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) canvas.setLayers([layer, layer2]) canvas.setExtent(QgsRectangle(10, 10, 18, 18)) @@ -797,13 +949,25 @@ def test_rendered_item_results_remove_outdated(self): canvas.waitWhileRendering() results = canvas.renderedItemResults() - self.assertCountEqual([i.itemId() for i in results.renderedItems()], [i1_id, i2_id, i3_id]) + self.assertCountEqual( + [i.itemId() for i in results.renderedItems()], [i1_id, i2_id, i3_id] + ) # now try modifying an annotation in the layer -- it will redraw, and we don't want to reuse any previously # cached rendered item results for this layer! item = QgsAnnotationPolygonItem( - QgsPolygon(QgsLineString([QgsPoint(11.5, 13), QgsPoint(12.5, 13), QgsPoint(12.5, 13.5), QgsPoint(11.5, 13)]))) + QgsPolygon( + QgsLineString( + [ + QgsPoint(11.5, 13), + QgsPoint(12.5, 13), + QgsPoint(12.5, 13.5), + QgsPoint(11.5, 13), + ] + ) + ) + ) item.setZIndex(1) layer.replaceItem(i1_id, item) while not canvas.isDrawing(): @@ -818,10 +982,14 @@ def test_rendered_item_results_remove_outdated(self): canvas.waitWhileRendering() results = canvas.renderedItemResults() - items_in_bounds = results.renderedAnnotationItemsInBounds(QgsRectangle(10, 10, 15, 15)) + items_in_bounds = results.renderedAnnotationItemsInBounds( + QgsRectangle(10, 10, 15, 15) + ) self.assertCountEqual([i.itemId() for i in items_in_bounds], [i1_id, i2_id]) - items_in_bounds = results.renderedAnnotationItemsInBounds(QgsRectangle(15, 15, 20, 20)) + items_in_bounds = results.renderedAnnotationItemsInBounds( + QgsRectangle(15, 15, 20, 20) + ) self.assertCountEqual([i.itemId() for i in items_in_bounds], [i3_id]) def test_temporal_animation(self): @@ -834,20 +1002,32 @@ def test_temporal_animation(self): controller = QgsTemporalController() canvas.setTemporalController(controller) - controller.updateTemporalRange.emit(QgsDateTimeRange(QDateTime(QDate(2020, 1, 2), QTime(1, 2, 3)), - QDateTime(QDate(2020, 1, 4), QTime(1, 2, 3)))) + controller.updateTemporalRange.emit( + QgsDateTimeRange( + QDateTime(QDate(2020, 1, 2), QTime(1, 2, 3)), + QDateTime(QDate(2020, 1, 4), QTime(1, 2, 3)), + ) + ) # should be no change self.assertEqual(canvas.mapSettings().frameRate(), -1) self.assertEqual(canvas.mapSettings().currentFrame(), -1) temporal_no = QgsTemporalNavigationObject() - temporal_no.setTemporalExtents(QgsDateTimeRange(QDateTime(QDate(2020, 1, 2), QTime(1, 2, 3)), - QDateTime(QDate(2020, 1, 4), QTime(1, 2, 3)))) + temporal_no.setTemporalExtents( + QgsDateTimeRange( + QDateTime(QDate(2020, 1, 2), QTime(1, 2, 3)), + QDateTime(QDate(2020, 1, 4), QTime(1, 2, 3)), + ) + ) temporal_no.setFrameDuration(QgsInterval(0, 0, 0, 0, 1, 0, 0)) canvas.setTemporalController(temporal_no) - controller.updateTemporalRange.emit(QgsDateTimeRange(QDateTime(QDate(2020, 1, 2), QTime(1, 2, 3)), - QDateTime(QDate(2020, 1, 4), QTime(1, 2, 3)))) + controller.updateTemporalRange.emit( + QgsDateTimeRange( + QDateTime(QDate(2020, 1, 2), QTime(1, 2, 3)), + QDateTime(QDate(2020, 1, 4), QTime(1, 2, 3)), + ) + ) # should be no change self.assertEqual(canvas.mapSettings().frameRate(), -1) self.assertEqual(canvas.mapSettings().currentFrame(), -1) @@ -861,7 +1041,9 @@ def test_temporal_animation(self): self.assertEqual(canvas.mapSettings().frameRate(), -1) self.assertEqual(canvas.mapSettings().currentFrame(), -1) - temporal_no.setNavigationMode(QgsTemporalNavigationObject.NavigationMode.Animated) + temporal_no.setNavigationMode( + QgsTemporalNavigationObject.NavigationMode.Animated + ) self.assertEqual(canvas.mapSettings().frameRate(), 30) self.assertEqual(canvas.mapSettings().currentFrame(), 6) @@ -870,15 +1052,21 @@ def test_temporal_animation(self): self.assertEqual(canvas.mapSettings().currentFrame(), 6) # switch off animation mode - temporal_no.setNavigationMode(QgsTemporalNavigationObject.NavigationMode.FixedRange) + temporal_no.setNavigationMode( + QgsTemporalNavigationObject.NavigationMode.FixedRange + ) self.assertEqual(canvas.mapSettings().frameRate(), -1) self.assertEqual(canvas.mapSettings().currentFrame(), -1) - temporal_no.setNavigationMode(QgsTemporalNavigationObject.NavigationMode.Animated) + temporal_no.setNavigationMode( + QgsTemporalNavigationObject.NavigationMode.Animated + ) self.assertEqual(canvas.mapSettings().frameRate(), 30) self.assertEqual(canvas.mapSettings().currentFrame(), 7) - temporal_no.setNavigationMode(QgsTemporalNavigationObject.NavigationMode.NavigationOff) + temporal_no.setNavigationMode( + QgsTemporalNavigationObject.NavigationMode.NavigationOff + ) self.assertEqual(canvas.mapSettings().frameRate(), -1) self.assertEqual(canvas.mapSettings().currentFrame(), -1) @@ -887,7 +1075,7 @@ def test_crs_change_signals(self): Test behavior of signals when crs is changed """ canvas = QgsMapCanvas() - canvas.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + canvas.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) canvas.setFrameStyle(0) canvas.resize(600, 400) self.assertEqual(canvas.width(), 600) @@ -903,11 +1091,15 @@ def on_extent_changed(): TestQgsMapCanvas.new_extent = None TestQgsMapCanvas.new_crs = None - canvas.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + canvas.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) - self.assertAlmostEqual(TestQgsMapCanvas.new_extent.xMinimum(), 1008988, places=-3) + self.assertAlmostEqual( + TestQgsMapCanvas.new_extent.xMinimum(), 1008988, places=-3 + ) - self.assertEqual(TestQgsMapCanvas.new_crs, QgsCoordinateReferenceSystem('EPSG:3857')) + self.assertEqual( + TestQgsMapCanvas.new_crs, QgsCoordinateReferenceSystem("EPSG:3857") + ) def test_set_map_tool(self): @@ -924,9 +1116,18 @@ def increment(tool, section): # Keep track of how many times each tool is activated, deactivated, and reactivated for tool in [moveTool, zoomTool, emitTool]: counter[tool] = {"activated": 0, "deactivated": 0, "reactivated": 0} - tool.activated.connect(lambda tool=tool: increment(tool, "activated"), Qt.ConnectionType.DirectConnection) - tool.deactivated.connect(lambda tool=tool: increment(tool, "deactivated"), Qt.ConnectionType.DirectConnection) - tool.reactivated.connect(lambda tool=tool: increment(tool, "reactivated"), Qt.ConnectionType.DirectConnection) + tool.activated.connect( + lambda tool=tool: increment(tool, "activated"), + Qt.ConnectionType.DirectConnection, + ) + tool.deactivated.connect( + lambda tool=tool: increment(tool, "deactivated"), + Qt.ConnectionType.DirectConnection, + ) + tool.reactivated.connect( + lambda tool=tool: increment(tool, "reactivated"), + Qt.ConnectionType.DirectConnection, + ) canvas.setMapTool(moveTool) canvas.setMapTool(zoomTool) @@ -952,5 +1153,5 @@ def increment(tool, section): self.assertEqual(counter[emitTool]["reactivated"], 1) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmapcanvasannotationitem.py b/tests/src/python/test_qgsmapcanvasannotationitem.py index 18f03e8b7091..4b6aa29eb6e9 100644 --- a/tests/src/python/test_qgsmapcanvasannotationitem.py +++ b/tests/src/python/test_qgsmapcanvasannotationitem.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '24/1/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "24/1/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtCore import QPointF, QSizeF from qgis.core import ( @@ -33,15 +34,15 @@ class TestQgsMapCanvasAnnotationItem(QgisTestCase): def testPosition(self): - """ test that map canvas annotation item syncs position correctly """ + """test that map canvas annotation item syncs position correctly""" a = QgsTextAnnotation() a.setFrameSizeMm(QSizeF(300 / 3.7795275, 200 / 3.7795275)) a.setFrameOffsetFromReferencePointMm(QPointF(40 / 3.7795275, 50 / 3.7795275)) a.setMapPosition(QgsPointXY(12, 34)) - a.setMapPositionCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + a.setMapPositionCrs(QgsCoordinateReferenceSystem("EPSG:4326")) canvas = QgsMapCanvas() - canvas.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + canvas.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) canvas.setFrameStyle(0) canvas.resize(600, 400) canvas.show() @@ -76,14 +77,16 @@ def testPosition(self): self.assertAlmostEqual(i.pos().y(), 160, 1) def testSize(self): - """ test that map canvas annotation item size is correct """ + """test that map canvas annotation item size is correct""" a = QgsTextAnnotation() a.setFrameSizeMm(QSizeF(300 / 3.7795275, 200 / 3.7795275)) a.setHasFixedMapPosition(False) - a.setFillSymbol(QgsFillSymbol.createSimple({'color': 'blue', 'width_border': '0'})) + a.setFillSymbol( + QgsFillSymbol.createSimple({"color": "blue", "width_border": "0"}) + ) canvas = QgsMapCanvas() - canvas.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + canvas.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) canvas.setFrameStyle(0) canvas.resize(600, 400) canvas.show() @@ -116,31 +119,32 @@ def testSize(self): self.assertAlmostEqual(i.boundingRect().height(), 229.166, -1) def testVisibility(self): - """ test that map canvas annotation item visibility follows layer""" + """test that map canvas annotation item visibility follows layer""" a = QgsTextAnnotation() canvas = QgsMapCanvas() i = QgsMapCanvasAnnotationItem(a, canvas) self.assertTrue(i.isVisible()) - layer = QgsVectorLayer("Point?crs=EPSG:3111&field=fldtxt:string", - 'test', "memory") + layer = QgsVectorLayer( + "Point?crs=EPSG:3111&field=fldtxt:string", "test", "memory" + ) a.setMapLayer(layer) self.assertFalse(i.isVisible()) canvas.setLayers([layer]) self.assertTrue(i.isVisible()) def testSettingFeature(self): - """ test that feature is set when item moves """ + """test that feature is set when item moves""" a = QgsTextAnnotation() a.setFrameSizeMm(QSizeF(300 / 3.7795275, 200 / 3.7795275)) a.setFrameOffsetFromReferencePointMm(QPointF(40 / 3.7795275, 50 / 3.7795275)) a.setHasFixedMapPosition(True) a.setMapPosition(QgsPointXY(12, 34)) - a.setMapPositionCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + a.setMapPositionCrs(QgsCoordinateReferenceSystem("EPSG:4326")) canvas = QgsMapCanvas() - canvas.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + canvas.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) canvas.setFrameStyle(0) canvas.resize(600, 400) @@ -148,24 +152,27 @@ def testSettingFeature(self): i = QgsMapCanvasAnnotationItem(a, canvas) # NOQA - layer = QgsVectorLayer("Point?crs=EPSG:4326&field=station:string&field=suburb:string", - 'test', "memory") + layer = QgsVectorLayer( + "Point?crs=EPSG:4326&field=station:string&field=suburb:string", + "test", + "memory", + ) canvas.setLayers([layer]) f = QgsFeature(layer.fields()) f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(14, 31))) f.setValid(True) - f.setAttributes(['hurstbridge', 'somewhere']) + f.setAttributes(["hurstbridge", "somewhere"]) self.assertTrue(layer.dataProvider().addFeatures([f])) a.setMapLayer(layer) self.assertFalse(a.associatedFeature().isValid()) a.setMapPosition(QgsPointXY(14, 31)) self.assertTrue(a.associatedFeature().isValid()) - self.assertEqual(a.associatedFeature().attributes()[0], 'hurstbridge') + self.assertEqual(a.associatedFeature().attributes()[0], "hurstbridge") a.setMapPosition(QgsPointXY(17, 31)) self.assertFalse(a.associatedFeature().isValid()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmapclippingregion.py b/tests/src/python/test_qgsmapclippingregion.py index 8ebb0ce33470..612cc5827392 100644 --- a/tests/src/python/test_qgsmapclippingregion.py +++ b/tests/src/python/test_qgsmapclippingregion.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2020-06' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2020-06" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.core import QgsGeometry, QgsMapClippingRegion, QgsVectorLayer @@ -17,20 +18,36 @@ class TestQgsMapClippingRegion(unittest.TestCase): def testGetSet(self): - region = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon((0 0, 1 0, 1 1, 0 1, 0 0))')) - self.assertEqual(region.geometry().asWkt(), 'Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))') - - region.setGeometry(QgsGeometry.fromWkt('Polygon((10 0, 11 0, 11 1, 10 1, 10 0))')) - self.assertEqual(region.geometry().asWkt(), 'Polygon ((10 0, 11 0, 11 1, 10 1, 10 0))') - - self.assertEqual(region.featureClip(), QgsMapClippingRegion.FeatureClippingType.ClipToIntersection) + region = QgsMapClippingRegion( + QgsGeometry.fromWkt("Polygon((0 0, 1 0, 1 1, 0 1, 0 0))") + ) + self.assertEqual( + region.geometry().asWkt(), "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))" + ) + + region.setGeometry( + QgsGeometry.fromWkt("Polygon((10 0, 11 0, 11 1, 10 1, 10 0))") + ) + self.assertEqual( + region.geometry().asWkt(), "Polygon ((10 0, 11 0, 11 1, 10 1, 10 0))" + ) + + self.assertEqual( + region.featureClip(), + QgsMapClippingRegion.FeatureClippingType.ClipToIntersection, + ) region.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipPainterOnly) - self.assertEqual(region.featureClip(), QgsMapClippingRegion.FeatureClippingType.ClipPainterOnly) - - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") - layer2 = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + self.assertEqual( + region.featureClip(), + QgsMapClippingRegion.FeatureClippingType.ClipPainterOnly, + ) + + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) + layer2 = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) self.assertEqual(len(region.restrictedLayers()), 0) region.setRestrictedLayers([layer, layer2]) self.assertCountEqual(region.restrictedLayers(), [layer, layer2]) @@ -40,14 +57,19 @@ def testGetSet(self): self.assertTrue(region.restrictToLayers()) def testAppliesToLayer(self): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") - layer2 = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") - layer3 = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") - - region = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon((0 0, 1 0, 1 1, 0 1, 0 0))')) + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) + layer2 = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) + layer3 = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) + + region = QgsMapClippingRegion( + QgsGeometry.fromWkt("Polygon((0 0, 1 0, 1 1, 0 1, 0 0))") + ) # should apply to all layers by default self.assertTrue(region.appliesToLayer(layer)) self.assertTrue(region.appliesToLayer(layer2)) @@ -69,5 +91,5 @@ def testAppliesToLayer(self): self.assertFalse(region.appliesToLayer(layer3)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmapclippingutils.py b/tests/src/python/test_qgsmapclippingutils.py index 487d7fd2ed03..36f8940c1dd3 100644 --- a/tests/src/python/test_qgsmapclippingutils.py +++ b/tests/src/python/test_qgsmapclippingutils.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2020-06' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2020-06" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.core import ( @@ -32,13 +33,19 @@ class TestQgsMapClippingUtils(QgisTestCase): def testClippingRegionsForLayer(self): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") - layer2 = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") - - region = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon((0 0, 1 0, 1 1, 0 1, 0 0))')) - region2 = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon((0 0, 0.1 0, 0.1 2, 0 2, 0 0))')) + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) + layer2 = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) + + region = QgsMapClippingRegion( + QgsGeometry.fromWkt("Polygon((0 0, 1 0, 1 1, 0 1, 0 0))") + ) + region2 = QgsMapClippingRegion( + QgsGeometry.fromWkt("Polygon((0 0, 0.1 0, 0.1 2, 0 2, 0 0))") + ) region2.setRestrictedLayers([layer]) region2.setRestrictToLayers(True) ms = QgsMapSettings() @@ -48,17 +55,27 @@ def testClippingRegionsForLayer(self): regions = QgsMapClippingUtils.collectClippingRegionsForLayer(rc, layer) self.assertEqual(len(regions), 2) - self.assertEqual(regions[0].geometry().asWkt(1), 'Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))') - self.assertEqual(regions[1].geometry().asWkt(1), 'Polygon ((0 0, 0.1 0, 0.1 2, 0 2, 0 0))') + self.assertEqual( + regions[0].geometry().asWkt(1), "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))" + ) + self.assertEqual( + regions[1].geometry().asWkt(1), "Polygon ((0 0, 0.1 0, 0.1 2, 0 2, 0 0))" + ) regions = QgsMapClippingUtils.collectClippingRegionsForLayer(rc, layer2) self.assertEqual(len(regions), 1) - self.assertEqual(regions[0].geometry().asWkt(1), 'Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))') + self.assertEqual( + regions[0].geometry().asWkt(1), "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))" + ) def testCalculateFeatureRequestGeometry(self): - region = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon((0 0, 1 0, 1 1, 0 1, 0 0))')) + region = QgsMapClippingRegion( + QgsGeometry.fromWkt("Polygon((0 0, 1 0, 1 1, 0 1, 0 0))") + ) region.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.NoClipping) - region2 = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon((0 0, 0.1 0, 0.1 2, 0 2, 0 0))')) + region2 = QgsMapClippingRegion( + QgsGeometry.fromWkt("Polygon((0 0, 0.1 0, 0.1 2, 0 2, 0 0))") + ) region2.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.NoClipping) rc = QgsRenderContext() @@ -67,145 +84,266 @@ def testCalculateFeatureRequestGeometry(self): self.assertFalse(should_clip) self.assertTrue(geom.isNull()) - geom, should_clip = QgsMapClippingUtils.calculateFeatureRequestGeometry([region], rc) + geom, should_clip = QgsMapClippingUtils.calculateFeatureRequestGeometry( + [region], rc + ) geom.normalize() self.assertTrue(should_clip) - self.assertEqual(geom.asWkt(1), 'Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))') + self.assertEqual(geom.asWkt(1), "Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))") - geom, should_clip = QgsMapClippingUtils.calculateFeatureRequestGeometry([region, region2], rc) + geom, should_clip = QgsMapClippingUtils.calculateFeatureRequestGeometry( + [region, region2], rc + ) geom.normalize() self.assertTrue(should_clip) - self.assertEqual(geom.asWkt(1), 'Polygon ((0 0, 0 1, 0.1 1, 0.1 0, 0 0))') + self.assertEqual(geom.asWkt(1), "Polygon ((0 0, 0 1, 0.1 1, 0.1 0, 0 0))") - rc.setCoordinateTransform(QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:3857'), QgsCoordinateReferenceSystem('EPSG:4326'), QgsProject.instance())) - geom, should_clip = QgsMapClippingUtils.calculateFeatureRequestGeometry([region, region2], rc) + rc.setCoordinateTransform( + QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsProject.instance(), + ) + ) + geom, should_clip = QgsMapClippingUtils.calculateFeatureRequestGeometry( + [region, region2], rc + ) geom.normalize() self.assertTrue(should_clip) - self.assertEqual(geom.asWkt(0), 'Polygon ((0 0, 0 111325, 11132 111325, 11132 0, 0 0))') + self.assertEqual( + geom.asWkt(0), "Polygon ((0 0, 0 111325, 11132 111325, 11132 0, 0 0))" + ) def testCalculateFeatureIntersectionGeometry(self): - region = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon((0 0, 1 0, 1 1, 0 1, 0 0))')) - region.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipToIntersection) - region2 = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon((0 0, 0.1 0, 0.1 2, 0 2, 0 0))')) + region = QgsMapClippingRegion( + QgsGeometry.fromWkt("Polygon((0 0, 1 0, 1 1, 0 1, 0 0))") + ) + region.setFeatureClip( + QgsMapClippingRegion.FeatureClippingType.ClipToIntersection + ) + region2 = QgsMapClippingRegion( + QgsGeometry.fromWkt("Polygon((0 0, 0.1 0, 0.1 2, 0 2, 0 0))") + ) region2.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.NoClipping) - region3 = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon((0 0, 0.1 0, 0.1 2, 0 2, 0 0))')) - region3.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipToIntersection) + region3 = QgsMapClippingRegion( + QgsGeometry.fromWkt("Polygon((0 0, 0.1 0, 0.1 2, 0 2, 0 0))") + ) + region3.setFeatureClip( + QgsMapClippingRegion.FeatureClippingType.ClipToIntersection + ) rc = QgsRenderContext() - geom, should_clip = QgsMapClippingUtils.calculateFeatureIntersectionGeometry([], rc) + geom, should_clip = QgsMapClippingUtils.calculateFeatureIntersectionGeometry( + [], rc + ) self.assertFalse(should_clip) self.assertTrue(geom.isNull()) - geom, should_clip = QgsMapClippingUtils.calculateFeatureIntersectionGeometry([region], rc) + geom, should_clip = QgsMapClippingUtils.calculateFeatureIntersectionGeometry( + [region], rc + ) geom.normalize() self.assertTrue(should_clip) - self.assertEqual(geom.asWkt(1), 'Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))') + self.assertEqual(geom.asWkt(1), "Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))") # region2 is a Intersects type clipping region, should not apply here - geom, should_clip = QgsMapClippingUtils.calculateFeatureIntersectionGeometry([region2], rc) + geom, should_clip = QgsMapClippingUtils.calculateFeatureIntersectionGeometry( + [region2], rc + ) self.assertFalse(should_clip) self.assertTrue(geom.isNull()) - geom, should_clip = QgsMapClippingUtils.calculateFeatureIntersectionGeometry([region, region2], rc) + geom, should_clip = QgsMapClippingUtils.calculateFeatureIntersectionGeometry( + [region, region2], rc + ) self.assertTrue(should_clip) - self.assertEqual(geom.asWkt(1), 'Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))') + self.assertEqual(geom.asWkt(1), "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))") - geom, should_clip = QgsMapClippingUtils.calculateFeatureIntersectionGeometry([region, region2, region3], rc) + geom, should_clip = QgsMapClippingUtils.calculateFeatureIntersectionGeometry( + [region, region2, region3], rc + ) geom.normalize() self.assertTrue(should_clip) - self.assertEqual(geom.asWkt(1), 'Polygon ((0 0, 0 1, 0.1 1, 0.1 0, 0 0))') + self.assertEqual(geom.asWkt(1), "Polygon ((0 0, 0 1, 0.1 1, 0.1 0, 0 0))") - rc.setCoordinateTransform(QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:3857'), QgsCoordinateReferenceSystem('EPSG:4326'), QgsProject.instance())) - geom, should_clip = QgsMapClippingUtils.calculateFeatureIntersectionGeometry([region, region3], rc) + rc.setCoordinateTransform( + QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsProject.instance(), + ) + ) + geom, should_clip = QgsMapClippingUtils.calculateFeatureIntersectionGeometry( + [region, region3], rc + ) geom.normalize() self.assertTrue(should_clip) - self.assertEqual(geom.asWkt(0), 'Polygon ((0 0, 0 111325, 11132 111325, 11132 0, 0 0))') + self.assertEqual( + geom.asWkt(0), "Polygon ((0 0, 0 111325, 11132 111325, 11132 0, 0 0))" + ) def testPainterClipPath(self): - region = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon((0 0, 1 0, 1 1, 0 1, 0 0))')) + region = QgsMapClippingRegion( + QgsGeometry.fromWkt("Polygon((0 0, 1 0, 1 1, 0 1, 0 0))") + ) region.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipPainterOnly) - region2 = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon((0 0, 0.1 0, 0.1 2, 0 2, 0 0))')) + region2 = QgsMapClippingRegion( + QgsGeometry.fromWkt("Polygon((0 0, 0.1 0, 0.1 2, 0 2, 0 0))") + ) region2.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.NoClipping) - region3 = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon((0 0, 0.1 0, 0.1 2, 0 2, 0 0))')) + region3 = QgsMapClippingRegion( + QgsGeometry.fromWkt("Polygon((0 0, 0.1 0, 0.1 2, 0 2, 0 0))") + ) region3.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipPainterOnly) rc = QgsRenderContext() - for t in [QgsMapLayerType.VectorLayer, QgsMapLayerType.RasterLayer, QgsMapLayerType.MeshLayer, QgsMapLayerType.VectorTileLayer]: - path, should_clip = QgsMapClippingUtils.calculatePainterClipRegion([], rc, t) + for t in [ + QgsMapLayerType.VectorLayer, + QgsMapLayerType.RasterLayer, + QgsMapLayerType.MeshLayer, + QgsMapLayerType.VectorTileLayer, + ]: + path, should_clip = QgsMapClippingUtils.calculatePainterClipRegion( + [], rc, t + ) self.assertFalse(should_clip) self.assertEqual(path.elementCount(), 0) - for t in [QgsMapLayerType.VectorLayer, QgsMapLayerType.RasterLayer, QgsMapLayerType.MeshLayer, QgsMapLayerType.VectorTileLayer]: - path, should_clip = QgsMapClippingUtils.calculatePainterClipRegion([region], rc, t) + for t in [ + QgsMapLayerType.VectorLayer, + QgsMapLayerType.RasterLayer, + QgsMapLayerType.MeshLayer, + QgsMapLayerType.VectorTileLayer, + ]: + path, should_clip = QgsMapClippingUtils.calculatePainterClipRegion( + [region], rc, t + ) self.assertTrue(should_clip) - self.assertEqual(QgsGeometry.fromQPolygonF(path.toFillPolygon()).asWkt(1), 'Polygon ((0 1, 1 1, 1 0, 0 0, 0 1))') + self.assertEqual( + QgsGeometry.fromQPolygonF(path.toFillPolygon()).asWkt(1), + "Polygon ((0 1, 1 1, 1 0, 0 0, 0 1))", + ) # region2 is a Intersects type clipping region, should not apply for vector layers - path, should_clip = QgsMapClippingUtils.calculatePainterClipRegion([region2], rc, QgsMapLayerType.VectorLayer) + path, should_clip = QgsMapClippingUtils.calculatePainterClipRegion( + [region2], rc, QgsMapLayerType.VectorLayer + ) self.assertFalse(should_clip) self.assertEqual(path.elementCount(), 0) - for t in [QgsMapLayerType.RasterLayer, QgsMapLayerType.MeshLayer, QgsMapLayerType.VectorTileLayer]: - path, should_clip = QgsMapClippingUtils.calculatePainterClipRegion([region2], rc, t) + for t in [ + QgsMapLayerType.RasterLayer, + QgsMapLayerType.MeshLayer, + QgsMapLayerType.VectorTileLayer, + ]: + path, should_clip = QgsMapClippingUtils.calculatePainterClipRegion( + [region2], rc, t + ) self.assertTrue(should_clip) - self.assertEqual(QgsGeometry.fromQPolygonF(path.toFillPolygon()).asWkt(1), 'Polygon ((0 1, 0.1 1, 0.1 -1, 0 -1, 0 1))') - - for t in [QgsMapLayerType.VectorLayer, QgsMapLayerType.RasterLayer, QgsMapLayerType.MeshLayer, QgsMapLayerType.VectorTileLayer]: - path, should_clip = QgsMapClippingUtils.calculatePainterClipRegion([region, region2, region3], rc, t) + self.assertEqual( + QgsGeometry.fromQPolygonF(path.toFillPolygon()).asWkt(1), + "Polygon ((0 1, 0.1 1, 0.1 -1, 0 -1, 0 1))", + ) + + for t in [ + QgsMapLayerType.VectorLayer, + QgsMapLayerType.RasterLayer, + QgsMapLayerType.MeshLayer, + QgsMapLayerType.VectorTileLayer, + ]: + path, should_clip = QgsMapClippingUtils.calculatePainterClipRegion( + [region, region2, region3], rc, t + ) self.assertTrue(should_clip) geom = QgsGeometry.fromQPolygonF(path.toFillPolygon()) geom.normalize() - self.assertEqual(geom.asWkt(1), 'Polygon ((0 0, 0 1, 0.1 1, 0.1 0, 0 0))') + self.assertEqual(geom.asWkt(1), "Polygon ((0 0, 0 1, 0.1 1, 0.1 0, 0 0))") rc.setMapToPixel(QgsMapToPixel(5, 10, 11, 200, 150, 0)) - for t in [QgsMapLayerType.VectorLayer, QgsMapLayerType.RasterLayer, QgsMapLayerType.MeshLayer, QgsMapLayerType.VectorTileLayer]: - path, should_clip = QgsMapClippingUtils.calculatePainterClipRegion([region, region3], rc, t) + for t in [ + QgsMapLayerType.VectorLayer, + QgsMapLayerType.RasterLayer, + QgsMapLayerType.MeshLayer, + QgsMapLayerType.VectorTileLayer, + ]: + path, should_clip = QgsMapClippingUtils.calculatePainterClipRegion( + [region, region3], rc, t + ) self.assertTrue(should_clip) - self.assertEqual(QgsGeometry.fromQPolygonF(path.toFillPolygon()).asWkt(0), 'Polygon ((98 77, 98 77, 98 77, 98 77, 98 77))') + self.assertEqual( + QgsGeometry.fromQPolygonF(path.toFillPolygon()).asWkt(0), + "Polygon ((98 77, 98 77, 98 77, 98 77, 98 77))", + ) def testLabelIntersectionGeometry(self): - region = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon((0 0, 1 0, 1 1, 0 1, 0 0))')) - region.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipToIntersection) - region2 = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon((0 0, 0.1 0, 0.1 2, 0 2, 0 0))')) + region = QgsMapClippingRegion( + QgsGeometry.fromWkt("Polygon((0 0, 1 0, 1 1, 0 1, 0 0))") + ) + region.setFeatureClip( + QgsMapClippingRegion.FeatureClippingType.ClipToIntersection + ) + region2 = QgsMapClippingRegion( + QgsGeometry.fromWkt("Polygon((0 0, 0.1 0, 0.1 2, 0 2, 0 0))") + ) region2.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.NoClipping) - region3 = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon((0 0, 0.1 0, 0.1 2, 0 2, 0 0))')) + region3 = QgsMapClippingRegion( + QgsGeometry.fromWkt("Polygon((0 0, 0.1 0, 0.1 2, 0 2, 0 0))") + ) region3.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipPainterOnly) rc = QgsRenderContext() - geom, should_clip = QgsMapClippingUtils.calculateLabelIntersectionGeometry([], rc) + geom, should_clip = QgsMapClippingUtils.calculateLabelIntersectionGeometry( + [], rc + ) self.assertFalse(should_clip) self.assertTrue(geom.isNull()) - geom, should_clip = QgsMapClippingUtils.calculateLabelIntersectionGeometry([region], rc) + geom, should_clip = QgsMapClippingUtils.calculateLabelIntersectionGeometry( + [region], rc + ) self.assertTrue(should_clip) - self.assertEqual(geom.asWkt(1), 'Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))') + self.assertEqual(geom.asWkt(1), "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))") # region2 is a Intersects type clipping region, should not apply here - geom, should_clip = QgsMapClippingUtils.calculateLabelIntersectionGeometry([region2], rc) + geom, should_clip = QgsMapClippingUtils.calculateLabelIntersectionGeometry( + [region2], rc + ) self.assertFalse(should_clip) self.assertTrue(geom.isNull()) - geom, should_clip = QgsMapClippingUtils.calculateLabelIntersectionGeometry([region, region2], rc) + geom, should_clip = QgsMapClippingUtils.calculateLabelIntersectionGeometry( + [region, region2], rc + ) self.assertTrue(should_clip) - self.assertEqual(geom.asWkt(1), 'Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))') + self.assertEqual(geom.asWkt(1), "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))") # region3 is a PainterClip type clipping region, MUST be applied for labels - geom, should_clip = QgsMapClippingUtils.calculateLabelIntersectionGeometry([region, region2, region3], rc) + geom, should_clip = QgsMapClippingUtils.calculateLabelIntersectionGeometry( + [region, region2, region3], rc + ) geom.normalize() self.assertTrue(should_clip) - self.assertEqual(geom.asWkt(1), 'Polygon ((0 0, 0 1, 0.1 1, 0.1 0, 0 0))') + self.assertEqual(geom.asWkt(1), "Polygon ((0 0, 0 1, 0.1 1, 0.1 0, 0 0))") rc.setCoordinateTransform( - QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:3857'), QgsCoordinateReferenceSystem('EPSG:4326'), - QgsProject.instance())) - geom, should_clip = QgsMapClippingUtils.calculateLabelIntersectionGeometry([region, region3], rc) + QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsProject.instance(), + ) + ) + geom, should_clip = QgsMapClippingUtils.calculateLabelIntersectionGeometry( + [region, region3], rc + ) geom.normalize() self.assertTrue(should_clip) - self.assertEqual(geom.asWkt(0), 'Polygon ((0 0, 0 111325, 11132 111325, 11132 0, 0 0))') + self.assertEqual( + geom.asWkt(0), "Polygon ((0 0, 0 111325, 11132 111325, 11132 0, 0 0))" + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmaphittest.py b/tests/src/python/test_qgsmaphittest.py index 4386a8aa4b6b..48fe4ee47f6a 100644 --- a/tests/src/python/test_qgsmaphittest.py +++ b/tests/src/python/test_qgsmaphittest.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2023 by Nyall Dawson' -__date__ = '08/03/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "(C) 2023 by Nyall Dawson" +__date__ = "08/03/2023" +__copyright__ = "Copyright 2023, The QGIS Project" import os @@ -22,7 +23,7 @@ QgsApplication, QgsVectorLayer, QgsMapHitTestTask, - QgsLayerTreeFilterSettings + QgsLayerTreeFilterSettings, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -35,37 +36,41 @@ class TestQgsMapHitTest(QgisTestCase): def test_hit_test(self): - point_path = os.path.join(TEST_DATA_DIR, 'points.shp') - point_layer = QgsVectorLayer(point_path, 'points', 'ogr') + point_path = os.path.join(TEST_DATA_DIR, "points.shp") + point_layer = QgsVectorLayer(point_path, "points", "ogr") root_rule = QgsRuleBasedRenderer.Rule(None) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#ff0000', 'outline_style': 'no', 'size': '8'}) + {"color": "#ff0000", "outline_style": "no", "size": "8"} + ) - less_than_two_rule = QgsRuleBasedRenderer.Rule(marker_symbol, - filterExp='"Importance" <=2', - label='lessthantwo') + less_than_two_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Importance" <=2', label="lessthantwo" + ) root_rule.appendChild(less_than_two_rule) else_rule = QgsRuleBasedRenderer.Rule(None, elseRule=True) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#00ffff', 'outline_style': 'no', 'size': '4'}) - one_rule = QgsRuleBasedRenderer.Rule(marker_symbol, - filterExp='"Pilots" = 1', - label='1') + {"color": "#00ffff", "outline_style": "no", "size": "4"} + ) + one_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Pilots" = 1', label="1" + ) else_rule.appendChild(one_rule) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#ff8888', 'outline_style': 'no', 'size': '4'}) - two_rule = QgsRuleBasedRenderer.Rule(marker_symbol, - filterExp='"Pilots" = 2', - label='2') + {"color": "#ff8888", "outline_style": "no", "size": "4"} + ) + two_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Pilots" = 2', label="2" + ) else_rule.appendChild(two_rule) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#8888ff', 'outline_style': 'no', 'size': '4'}) - three_rule = QgsRuleBasedRenderer.Rule(marker_symbol, - filterExp='"Pilots" = 3', - label='3') + {"color": "#8888ff", "outline_style": "no", "size": "4"} + ) + three_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Pilots" = 3', label="3" + ) else_rule.appendChild(three_rule) root_rule.appendChild(else_rule) @@ -75,8 +80,7 @@ def test_hit_test(self): map_settings = QgsMapSettings() map_settings.setOutputDpi(96) - map_settings.setDestinationCrs( - QgsCoordinateReferenceSystem('EPSG:3857')) + map_settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) map_settings.setOutputSize(QSize(1221, 750)) map_settings.setExtent(QgsRectangle(-12360166, 3146940, -11269206, 3816372)) map_settings.setLayers([point_layer]) @@ -84,51 +88,62 @@ def test_hit_test(self): map_hit_test = QgsMapHitTest(map_settings) map_hit_test.run() self.assertEqual(list(map_hit_test.results().keys()), [point_layer.id()]) - self.assertCountEqual(map_hit_test.results()[point_layer.id()], [ - one_rule.ruleKey(), three_rule.ruleKey(), else_rule.ruleKey(), root_rule.ruleKey() - ]) + self.assertCountEqual( + map_hit_test.results()[point_layer.id()], + [ + one_rule.ruleKey(), + three_rule.ruleKey(), + else_rule.ruleKey(), + root_rule.ruleKey(), + ], + ) map_settings.setExtent(QgsRectangle(-11226365, 4873483, -10573781, 5273920)) map_hit_test = QgsMapHitTest(map_settings) map_hit_test.run() self.assertEqual(list(map_hit_test.results().keys()), [point_layer.id()]) - self.assertCountEqual(map_hit_test.results()[point_layer.id()], [ - two_rule.ruleKey(), else_rule.ruleKey(), root_rule.ruleKey() - ]) + self.assertCountEqual( + map_hit_test.results()[point_layer.id()], + [two_rule.ruleKey(), else_rule.ruleKey(), root_rule.ruleKey()], + ) def test_hit_test_task(self): - point_path = os.path.join(TEST_DATA_DIR, 'points.shp') - point_layer = QgsVectorLayer(point_path, 'points', 'ogr') + point_path = os.path.join(TEST_DATA_DIR, "points.shp") + point_layer = QgsVectorLayer(point_path, "points", "ogr") root_rule = QgsRuleBasedRenderer.Rule(None) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#ff0000', 'outline_style': 'no', 'size': '8'}) + {"color": "#ff0000", "outline_style": "no", "size": "8"} + ) - less_than_two_rule = QgsRuleBasedRenderer.Rule(marker_symbol, - filterExp='"Importance" <=2', - label='lessthantwo') + less_than_two_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Importance" <=2', label="lessthantwo" + ) root_rule.appendChild(less_than_two_rule) else_rule = QgsRuleBasedRenderer.Rule(None, elseRule=True) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#00ffff', 'outline_style': 'no', 'size': '4'}) - one_rule = QgsRuleBasedRenderer.Rule(marker_symbol, - filterExp='"Pilots" = 1', - label='1') + {"color": "#00ffff", "outline_style": "no", "size": "4"} + ) + one_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Pilots" = 1', label="1" + ) else_rule.appendChild(one_rule) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#ff8888', 'outline_style': 'no', 'size': '4'}) - two_rule = QgsRuleBasedRenderer.Rule(marker_symbol, - filterExp='"Pilots" = 2', - label='2') + {"color": "#ff8888", "outline_style": "no", "size": "4"} + ) + two_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Pilots" = 2', label="2" + ) else_rule.appendChild(two_rule) marker_symbol = QgsMarkerSymbol.createSimple( - {'color': '#8888ff', 'outline_style': 'no', 'size': '4'}) - three_rule = QgsRuleBasedRenderer.Rule(marker_symbol, - filterExp='"Pilots" = 3', - label='3') + {"color": "#8888ff", "outline_style": "no", "size": "4"} + ) + three_rule = QgsRuleBasedRenderer.Rule( + marker_symbol, filterExp='"Pilots" = 3', label="3" + ) else_rule.appendChild(three_rule) root_rule.appendChild(else_rule) @@ -138,8 +153,7 @@ def test_hit_test_task(self): map_settings = QgsMapSettings() map_settings.setOutputDpi(96) - map_settings.setDestinationCrs( - QgsCoordinateReferenceSystem('EPSG:3857')) + map_settings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) map_settings.setOutputSize(QSize(1221, 750)) map_settings.setExtent(QgsRectangle(-12360166, 3146940, -11269206, 3816372)) map_settings.setLayers([point_layer]) @@ -155,10 +169,16 @@ def catch_results(): map_hit_test_task.waitForFinished() self.assertEqual(list(TestQgsMapHitTest.results.keys()), [point_layer.id()]) - self.assertCountEqual(TestQgsMapHitTest.results[point_layer.id()], [ - one_rule.ruleKey(), three_rule.ruleKey(), else_rule.ruleKey(), root_rule.ruleKey() - ]) - - -if __name__ == '__main__': + self.assertCountEqual( + TestQgsMapHitTest.results[point_layer.id()], + [ + one_rule.ruleKey(), + three_rule.ruleKey(), + else_rule.ruleKey(), + root_rule.ruleKey(), + ], + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmaplayer.py b/tests/src/python/test_qgsmaplayer.py index 0cf9cfed33cd..d70956270d08 100644 --- a/tests/src/python/test_qgsmaplayer.py +++ b/tests/src/python/test_qgsmaplayer.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '1/02/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "1/02/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import glob import os @@ -29,7 +30,7 @@ QgsRasterLayer, QgsReadWriteContext, QgsVectorLayer, - QgsCoordinateReferenceSystem + QgsCoordinateReferenceSystem, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -52,9 +53,8 @@ def testUniqueId(self): layers = [] for i in range(1000): layer = QgsVectorLayer( - 'Point?crs=epsg:4326&field=name:string(20)', - 'test', - 'memory') + "Point?crs=epsg:4326&field=name:string(20)", "test", "memory" + ) layers.append(layer) # make sure all ids are unique @@ -68,12 +68,13 @@ def copyLayerViaXmlReadWrite(self, source, dest): doc = QDomDocument("testdoc") elem = doc.createElement("maplayer") self.assertTrue(source.writeLayerXml(elem, doc, QgsReadWriteContext())) - self.assertTrue(dest.readLayerXml(elem, QgsReadWriteContext()), QgsProject.instance()) + self.assertTrue( + dest.readLayerXml(elem, QgsReadWriteContext()), QgsProject.instance() + ) def testGettersSetters(self): # test auto refresh getters/setters - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer", "memory") self.assertFalse(layer.hasAutoRefreshEnabled()) self.assertEqual(layer.autoRefreshInterval(), 0) layer.setAutoRefreshInterval(5) @@ -95,16 +96,15 @@ def test_crs(self): layer.setCrs(QgsCoordinateReferenceSystem()) self.assertEqual(len(spy), 1) - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) - self.assertEqual(layer.crs().authid(), 'EPSG:3111') + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) + self.assertEqual(layer.crs().authid(), "EPSG:3111") self.assertEqual(len(spy), 2) - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertEqual(len(spy), 2) - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer", "memory") self.copyLayerViaXmlReadWrite(layer, layer2) - self.assertEqual(layer2.crs().authid(), 'EPSG:3111') + self.assertEqual(layer2.crs().authid(), "EPSG:3111") def test_vertical_crs(self): layer = QgsVectorLayer("Point?field=fldtxt:string", "layer", "memory") @@ -113,31 +113,29 @@ def test_vertical_crs(self): spy = QSignalSpy(layer.verticalCrsChanged) # not a vertical crs - ok, err = layer.setVerticalCrs( - QgsCoordinateReferenceSystem('EPSG:3111')) + ok, err = layer.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertFalse(ok) - self.assertEqual(err, 'Specified CRS is a Projected CRS, not a Vertical CRS') + self.assertEqual(err, "Specified CRS is a Projected CRS, not a Vertical CRS") self.assertFalse(layer.verticalCrs().isValid()) - ok, err = layer.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:5703')) + ok, err = layer.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:5703")) self.assertTrue(ok) - self.assertEqual(layer.verticalCrs().authid(), 'EPSG:5703') + self.assertEqual(layer.verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy), 1) # try overwriting with same crs, should be no new signal - ok, err = layer.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:5703')) + ok, err = layer.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:5703")) self.assertTrue(ok) self.assertEqual(len(spy), 1) # check that vertical crs is saved/restored - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer", "memory") spy2 = QSignalSpy(layer2.verticalCrsChanged) self.copyLayerViaXmlReadWrite(layer, layer2) - self.assertEqual(layer2.verticalCrs().authid(), 'EPSG:5703') + self.assertEqual(layer2.verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy2), 1) self.copyLayerViaXmlReadWrite(layer, layer2) - self.assertEqual(layer2.verticalCrs().authid(), 'EPSG:5703') + self.assertEqual(layer2.verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy2), 1) layer.setVerticalCrs(QgsCoordinateReferenceSystem()) @@ -154,13 +152,13 @@ def test_vertical_crs_with_compound_project_crs(self): self.assertFalse(layer.verticalCrs().isValid()) spy = QSignalSpy(layer.verticalCrsChanged) - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:5500')) - self.assertEqual(layer.crs().authid(), 'EPSG:5500') + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:5500")) + self.assertEqual(layer.crs().authid(), "EPSG:5500") # verticalCrs() should return the vertical part of the # compound CRS - self.assertEqual(layer.verticalCrs().authid(), 'EPSG:5703') + self.assertEqual(layer.verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy), 1) - other_vert_crs = QgsCoordinateReferenceSystem('ESRI:115700') + other_vert_crs = QgsCoordinateReferenceSystem("ESRI:115700") self.assertTrue(other_vert_crs.isValid()) self.assertEqual(other_vert_crs.type(), Qgis.CrsType.Vertical) @@ -169,34 +167,41 @@ def test_vertical_crs_with_compound_project_crs(self): # precedence ok, err = layer.setVerticalCrs(other_vert_crs) self.assertFalse(ok) - self.assertEqual(err, 'Layer CRS is a Compound CRS, specified Vertical CRS will be ignored') - self.assertEqual(layer.verticalCrs().authid(), 'EPSG:5703') + self.assertEqual( + err, "Layer CRS is a Compound CRS, specified Vertical CRS will be ignored" + ) + self.assertEqual(layer.verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy), 1) # setting the vertical crs to the vertical component of the compound crs # IS permitted, even though it effectively has no impact... - ok, err = layer.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:5703')) + ok, err = layer.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:5703")) self.assertTrue(ok) - self.assertEqual(layer.verticalCrs().authid(), 'EPSG:5703') + self.assertEqual(layer.verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy), 1) # reset horizontal crs to a non-compound crs, now the manually # specified vertical crs should take precedence - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) - self.assertEqual(layer.verticalCrs().authid(), 'EPSG:5703') + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) + self.assertEqual(layer.verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy), 1) # invalid combinations - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4979')) - ok, err = layer.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:5711')) + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:4979")) + ok, err = layer.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:5711")) self.assertFalse(ok) - self.assertEqual(err, 'Layer CRS is a Geographic 3D CRS, specified Vertical CRS will be ignored') - self.assertEqual(layer.crs3D().authid(), 'EPSG:4979') - - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4978')) - ok, err = layer.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:5711')) + self.assertEqual( + err, + "Layer CRS is a Geographic 3D CRS, specified Vertical CRS will be ignored", + ) + self.assertEqual(layer.crs3D().authid(), "EPSG:4979") + + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:4978")) + ok, err = layer.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:5711")) self.assertFalse(ok) - self.assertEqual(err, 'Layer CRS is a Geocentric CRS, specified Vertical CRS will be ignored') - self.assertEqual(layer.crs3D().authid(), 'EPSG:4978') + self.assertEqual( + err, "Layer CRS is a Geocentric CRS, specified Vertical CRS will be ignored" + ) + self.assertEqual(layer.crs3D().authid(), "EPSG:4978") def test_vertical_crs_with_projected3d_project_crs(self): """ @@ -209,45 +214,47 @@ def test_vertical_crs_with_projected3d_project_crs(self): spy = QSignalSpy(layer.verticalCrsChanged) - projected3d_crs = QgsCoordinateReferenceSystem.fromWkt("PROJCRS[\"NAD83(HARN) / Oregon GIC Lambert (ft)\",\n" - " BASEGEOGCRS[\"NAD83(HARN)\",\n" - " DATUM[\"NAD83 (High Accuracy Reference Network)\",\n" - " ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n" - " LENGTHUNIT[\"metre\",1]]],\n" - " PRIMEM[\"Greenwich\",0,\n" - " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" - " ID[\"EPSG\",4957]],\n" - " CONVERSION[\"unnamed\",\n" - " METHOD[\"Lambert Conic Conformal (2SP)\",\n" - " ID[\"EPSG\",9802]],\n" - " PARAMETER[\"Latitude of false origin\",41.75,\n" - " ANGLEUNIT[\"degree\",0.0174532925199433],\n" - " ID[\"EPSG\",8821]],\n" - " PARAMETER[\"Longitude of false origin\",-120.5,\n" - " ANGLEUNIT[\"degree\",0.0174532925199433],\n" - " ID[\"EPSG\",8822]],\n" - " PARAMETER[\"Latitude of 1st standard parallel\",43,\n" - " ANGLEUNIT[\"degree\",0.0174532925199433],\n" - " ID[\"EPSG\",8823]],\n" - " PARAMETER[\"Latitude of 2nd standard parallel\",45.5,\n" - " ANGLEUNIT[\"degree\",0.0174532925199433],\n" - " ID[\"EPSG\",8824]],\n" - " PARAMETER[\"Easting at false origin\",1312335.958,\n" - " LENGTHUNIT[\"foot\",0.3048],\n" - " ID[\"EPSG\",8826]],\n" - " PARAMETER[\"Northing at false origin\",0,\n" - " LENGTHUNIT[\"foot\",0.3048],\n" - " ID[\"EPSG\",8827]]],\n" - " CS[Cartesian,3],\n" - " AXIS[\"easting\",east,\n" - " ORDER[1],\n" - " LENGTHUNIT[\"foot\",0.3048]],\n" - " AXIS[\"northing\",north,\n" - " ORDER[2],\n" - " LENGTHUNIT[\"foot\",0.3048]],\n" - " AXIS[\"ellipsoidal height (h)\",up,\n" - " ORDER[3],\n" - " LENGTHUNIT[\"foot\",0.3048]]]") + projected3d_crs = QgsCoordinateReferenceSystem.fromWkt( + 'PROJCRS["NAD83(HARN) / Oregon GIC Lambert (ft)",\n' + ' BASEGEOGCRS["NAD83(HARN)",\n' + ' DATUM["NAD83 (High Accuracy Reference Network)",\n' + ' ELLIPSOID["GRS 1980",6378137,298.257222101,\n' + ' LENGTHUNIT["metre",1]]],\n' + ' PRIMEM["Greenwich",0,\n' + ' ANGLEUNIT["degree",0.0174532925199433]],\n' + ' ID["EPSG",4957]],\n' + ' CONVERSION["unnamed",\n' + ' METHOD["Lambert Conic Conformal (2SP)",\n' + ' ID["EPSG",9802]],\n' + ' PARAMETER["Latitude of false origin",41.75,\n' + ' ANGLEUNIT["degree",0.0174532925199433],\n' + ' ID["EPSG",8821]],\n' + ' PARAMETER["Longitude of false origin",-120.5,\n' + ' ANGLEUNIT["degree",0.0174532925199433],\n' + ' ID["EPSG",8822]],\n' + ' PARAMETER["Latitude of 1st standard parallel",43,\n' + ' ANGLEUNIT["degree",0.0174532925199433],\n' + ' ID["EPSG",8823]],\n' + ' PARAMETER["Latitude of 2nd standard parallel",45.5,\n' + ' ANGLEUNIT["degree",0.0174532925199433],\n' + ' ID["EPSG",8824]],\n' + ' PARAMETER["Easting at false origin",1312335.958,\n' + ' LENGTHUNIT["foot",0.3048],\n' + ' ID["EPSG",8826]],\n' + ' PARAMETER["Northing at false origin",0,\n' + ' LENGTHUNIT["foot",0.3048],\n' + ' ID["EPSG",8827]]],\n' + " CS[Cartesian,3],\n" + ' AXIS["easting",east,\n' + " ORDER[1],\n" + ' LENGTHUNIT["foot",0.3048]],\n' + ' AXIS["northing",north,\n' + " ORDER[2],\n" + ' LENGTHUNIT["foot",0.3048]],\n' + ' AXIS["ellipsoidal height (h)",up,\n' + " ORDER[3],\n" + ' LENGTHUNIT["foot",0.3048]]]' + ) self.assertTrue(projected3d_crs.isValid()) layer.setCrs(projected3d_crs) self.assertEqual(layer.crs().toWkt(), projected3d_crs.toWkt()) @@ -256,7 +263,7 @@ def test_vertical_crs_with_projected3d_project_crs(self): # verticalCrs() should return invalid crs self.assertFalse(layer.verticalCrs().isValid()) self.assertEqual(len(spy), 0) - other_vert_crs = QgsCoordinateReferenceSystem('ESRI:115700') + other_vert_crs = QgsCoordinateReferenceSystem("ESRI:115700") self.assertTrue(other_vert_crs.isValid()) self.assertEqual(other_vert_crs.type(), Qgis.CrsType.Vertical) @@ -265,7 +272,10 @@ def test_vertical_crs_with_projected3d_project_crs(self): # precedence ok, err = layer.setVerticalCrs(other_vert_crs) self.assertFalse(ok) - self.assertEqual(err, 'Layer CRS is a Projected 3D CRS, specified Vertical CRS will be ignored') + self.assertEqual( + err, + "Layer CRS is a Projected 3D CRS, specified Vertical CRS will be ignored", + ) self.assertFalse(layer.verticalCrs().isValid()) self.assertEqual(len(spy), 0) self.assertEqual(layer.crs3D().toWkt(), projected3d_crs.toWkt()) @@ -278,67 +288,66 @@ def test_crs_3d(self): spy = QSignalSpy(layer.crs3DChanged) # set layer crs to a 2d crs - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) - self.assertEqual(layer.crs3D().authid(), 'EPSG:3111') + self.assertEqual(layer.crs3D().authid(), "EPSG:3111") self.assertEqual(len(spy), 1) # don't change, no new signals - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) - self.assertEqual(layer.crs3D().authid(), 'EPSG:3111') + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) + self.assertEqual(layer.crs3D().authid(), "EPSG:3111") self.assertEqual(len(spy), 1) # change 2d crs, should be new signals - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:3113')) - self.assertEqual(layer.crs3D().authid(), 'EPSG:3113') + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:3113")) + self.assertEqual(layer.crs3D().authid(), "EPSG:3113") self.assertEqual(len(spy), 2) # change vertical crs: # not a vertical crs, no change - ok, err = layer.setVerticalCrs( - QgsCoordinateReferenceSystem('EPSG:3111')) + ok, err = layer.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertFalse(ok) - self.assertEqual(layer.crs3D().authid(), 'EPSG:3113') + self.assertEqual(layer.crs3D().authid(), "EPSG:3113") self.assertEqual(len(spy), 2) # valid vertical crs - ok, err = layer.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:5703')) + ok, err = layer.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:5703")) self.assertTrue(ok) self.assertEqual(layer.crs3D().type(), Qgis.CrsType.Compound) # crs3D should be a compound crs - self.assertEqual(layer.crs3D().horizontalCrs().authid(), 'EPSG:3113') - self.assertEqual(layer.crs3D().verticalCrs().authid(), 'EPSG:5703') + self.assertEqual(layer.crs3D().horizontalCrs().authid(), "EPSG:3113") + self.assertEqual(layer.crs3D().verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy), 3) # try overwriting with same crs, should be no new signal - ok, err = layer.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:5703')) + ok, err = layer.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:5703")) self.assertTrue(ok) self.assertEqual(len(spy), 3) # set 2d crs to a compound crs - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:5500')) - self.assertEqual(layer.crs().authid(), 'EPSG:5500') - self.assertEqual(layer.crs3D().authid(), 'EPSG:5500') + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:5500")) + self.assertEqual(layer.crs().authid(), "EPSG:5500") + self.assertEqual(layer.crs3D().authid(), "EPSG:5500") self.assertEqual(len(spy), 4) - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:5500')) - self.assertEqual(layer.crs().authid(), 'EPSG:5500') - self.assertEqual(layer.crs3D().authid(), 'EPSG:5500') + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:5500")) + self.assertEqual(layer.crs().authid(), "EPSG:5500") + self.assertEqual(layer.crs3D().authid(), "EPSG:5500") self.assertEqual(len(spy), 4) # remove vertical crs, should be no change because compound crs is causing vertical crs to be ignored layer.setVerticalCrs(QgsCoordinateReferenceSystem()) - self.assertEqual(layer.crs3D().authid(), 'EPSG:5500') + self.assertEqual(layer.crs3D().authid(), "EPSG:5500") self.assertEqual(len(spy), 4) - layer.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:5703')) - self.assertEqual(layer.crs3D().authid(), 'EPSG:5500') + layer.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:5703")) + self.assertEqual(layer.crs3D().authid(), "EPSG:5500") self.assertEqual(len(spy), 4) # set crs back to 2d crs, should be new signal - layer.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) - self.assertEqual(layer.crs3D().horizontalCrs().authid(), 'EPSG:3111') - self.assertEqual(layer.crs3D().verticalCrs().authid(), 'EPSG:5703') + layer.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) + self.assertEqual(layer.crs3D().horizontalCrs().authid(), "EPSG:3111") + self.assertEqual(layer.crs3D().verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy), 5) # check that crs3D is handled correctly during save/restore @@ -346,39 +355,36 @@ def test_crs_3d(self): spy2 = QSignalSpy(layer2.crs3DChanged) self.copyLayerViaXmlReadWrite(layer, layer2) - self.assertEqual(layer2.crs3D().horizontalCrs().authid(), 'EPSG:3111') - self.assertEqual(layer2.crs3D().verticalCrs().authid(), 'EPSG:5703') + self.assertEqual(layer2.crs3D().horizontalCrs().authid(), "EPSG:3111") + self.assertEqual(layer2.crs3D().verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy2), 1) self.copyLayerViaXmlReadWrite(layer, layer2) - self.assertEqual(layer2.crs3D().horizontalCrs().authid(), 'EPSG:3111') - self.assertEqual(layer2.crs3D().verticalCrs().authid(), 'EPSG:5703') + self.assertEqual(layer2.crs3D().horizontalCrs().authid(), "EPSG:3111") + self.assertEqual(layer2.crs3D().verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy2), 1) def testLayerNotes(self): """ Test layer notes """ - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer", "memory") self.assertFalse(QgsLayerNotesUtils.layerHasNotes(layer)) self.assertFalse(QgsLayerNotesUtils.layerNotes(layer)) - QgsLayerNotesUtils.setLayerNotes(layer, 'my notes') + QgsLayerNotesUtils.setLayerNotes(layer, "my notes") self.assertTrue(QgsLayerNotesUtils.layerHasNotes(layer)) - self.assertEqual(QgsLayerNotesUtils.layerNotes(layer), 'my notes') - QgsLayerNotesUtils.setLayerNotes(layer, 'my notes 2') - self.assertEqual(QgsLayerNotesUtils.layerNotes(layer), 'my notes 2') + self.assertEqual(QgsLayerNotesUtils.layerNotes(layer), "my notes") + QgsLayerNotesUtils.setLayerNotes(layer, "my notes 2") + self.assertEqual(QgsLayerNotesUtils.layerNotes(layer), "my notes 2") QgsLayerNotesUtils.removeNotes(layer) self.assertFalse(QgsLayerNotesUtils.layerHasNotes(layer)) self.assertFalse(QgsLayerNotesUtils.layerNotes(layer)) def testSaveRestoreAutoRefresh(self): - """ test saving/restoring auto refresh to xml """ - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer", "memory") - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer", "memory") + """test saving/restoring auto refresh to xml""" + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer", "memory") self.copyLayerViaXmlReadWrite(layer, layer2) self.assertFalse(layer2.hasAutoRefreshEnabled()) self.assertEqual(layer2.autoRefreshInterval(), 0) @@ -397,94 +403,103 @@ def testReadWriteMetadata(self): layer = QgsVectorLayer("Point?field=fldtxt:string", "layer", "memory") m = layer.metadata() # Only abstract, more tests are done in test_qgslayermetadata.py - m.setAbstract('My abstract') + m.setAbstract("My abstract") layer.setMetadata(m) - self.assertTrue(layer.metadata().abstract(), 'My abstract') - destination = tempfile.NamedTemporaryFile(suffix='.qmd').name + self.assertTrue(layer.metadata().abstract(), "My abstract") + destination = tempfile.NamedTemporaryFile(suffix=".qmd").name message, status = layer.saveNamedMetadata(destination) self.assertTrue(status, message) layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer", "memory") message, status = layer2.loadNamedMetadata(destination) self.assertTrue(status) - self.assertTrue(layer2.metadata().abstract(), 'My abstract') + self.assertTrue(layer2.metadata().abstract(), "My abstract") def testSaveNamedStyle(self): layer = QgsVectorLayer("Point?field=fldtxt:string", "layer", "memory") dir = QTemporaryDir() dir_path = dir.path() - style_path = os.path.join(dir_path, 'my.qml') + style_path = os.path.join(dir_path, "my.qml") _, result = layer.saveNamedStyle(style_path) self.assertTrue(result) self.assertTrue(os.path.exists(style_path)) def testStyleUri(self): # shapefile - layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'points.shp'), "layer", "ogr") + layer = QgsVectorLayer( + os.path.join(TEST_DATA_DIR, "points.shp"), "layer", "ogr" + ) uri = layer.styleURI() - self.assertEqual(uri, os.path.join(TEST_DATA_DIR, 'points.qml')) + self.assertEqual(uri, os.path.join(TEST_DATA_DIR, "points.qml")) # geopackage without and with layername - layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'provider', 'bug_17795.gpkg'), "layer", "ogr") + layer = QgsVectorLayer( + os.path.join(TEST_DATA_DIR, "provider", "bug_17795.gpkg"), "layer", "ogr" + ) uri = layer.styleURI() - self.assertEqual(uri, os.path.join(TEST_DATA_DIR, 'provider', 'bug_17795.qml')) + self.assertEqual(uri, os.path.join(TEST_DATA_DIR, "provider", "bug_17795.qml")) - layer = QgsVectorLayer(f"{os.path.join(TEST_DATA_DIR, 'provider', 'bug_17795.gpkg')}|layername=bug_17795", "layer", "ogr") + layer = QgsVectorLayer( + f"{os.path.join(TEST_DATA_DIR, 'provider', 'bug_17795.gpkg')}|layername=bug_17795", + "layer", + "ogr", + ) uri = layer.styleURI() - self.assertEqual(uri, os.path.join(TEST_DATA_DIR, 'provider', 'bug_17795.qml')) + self.assertEqual(uri, os.path.join(TEST_DATA_DIR, "provider", "bug_17795.qml")) # delimited text uri = f"file://{os.path.join(TEST_DATA_DIR, 'delimitedtext', 'test.csv')}?type=csv&detectTypes=yes&geomType=none" layer = QgsVectorLayer(uri, "layer", "delimitedtext") uri = layer.styleURI() - self.assertEqual(uri, os.path.join(TEST_DATA_DIR, 'delimitedtext', 'test.qml')) + self.assertEqual(uri, os.path.join(TEST_DATA_DIR, "delimitedtext", "test.qml")) def testIsTemporary(self): # test if a layer is correctly marked as temporary dir = QTemporaryDir() dir_path = dir.path() - for file in glob.glob(os.path.join(TEST_DATA_DIR, 'france_parts.*')): + for file in glob.glob(os.path.join(TEST_DATA_DIR, "france_parts.*")): shutil.copy(os.path.join(TEST_DATA_DIR, file), dir_path) - not_temp_source = os.path.join(TEST_DATA_DIR, 'france_parts.*') - temp_source = os.path.join(dir_path, 'france_parts.shp') + not_temp_source = os.path.join(TEST_DATA_DIR, "france_parts.*") + temp_source = os.path.join(dir_path, "france_parts.shp") - vl = QgsVectorLayer('invalid', 'test') + vl = QgsVectorLayer("invalid", "test") self.assertFalse(vl.isValid()) self.assertFalse(vl.isTemporary()) - vl = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'france_parts.shp'), 'test') + vl = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "france_parts.shp"), "test") self.assertTrue(vl.isValid()) self.assertFalse(vl.isTemporary()) - vl = QgsVectorLayer(temp_source, 'test') + vl = QgsVectorLayer(temp_source, "test") self.assertTrue(vl.isValid()) self.assertTrue(vl.isTemporary()) # memory layers are temp - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer", "memory") self.assertTrue(vl.isValid()) self.assertTrue(vl.isTemporary()) - rl = QgsRasterLayer('invalid', 'test') + rl = QgsRasterLayer("invalid", "test") self.assertFalse(rl.isValid()) self.assertFalse(rl.isTemporary()) - not_temp_source = os.path.join(TEST_DATA_DIR, 'float1-16.tif') + not_temp_source = os.path.join(TEST_DATA_DIR, "float1-16.tif") shutil.copy(not_temp_source, dir_path) - temp_source = os.path.join(dir_path, 'float1-16.tif') + temp_source = os.path.join(dir_path, "float1-16.tif") - rl = QgsRasterLayer(not_temp_source, 'test') + rl = QgsRasterLayer(not_temp_source, "test") self.assertTrue(rl.isValid()) self.assertFalse(rl.isTemporary()) - rl = QgsRasterLayer(temp_source, 'test') + rl = QgsRasterLayer(temp_source, "test") self.assertTrue(rl.isValid()) self.assertTrue(rl.isTemporary()) def testQgsMapLayerProject(self): - layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'points.shp'), "layer", "ogr") + layer = QgsVectorLayer( + os.path.join(TEST_DATA_DIR, "points.shp"), "layer", "ogr" + ) self.assertIsNone(layer.project()) project = QgsProject() project.addMapLayer(layer) @@ -501,41 +516,53 @@ def testRetainLayerMetadataWhenChangingDataSource(self): """ Test that we retain existing layer metadata when a layer's source is changed """ - vl = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'points.shp'), "layer", "ogr") + vl = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "points.shp"), "layer", "ogr") metadata = QgsLayerMetadata() - metadata.setRights(['original right 1', 'original right 2']) - metadata.setAbstract('original abstract') + metadata.setRights(["original right 1", "original right 2"]) + metadata.setAbstract("original abstract") vl.setMetadata(metadata) # now change layer datasource to one which has embedded provider medata - datasource = os.path.join(unitTestDataPath(), 'gdb_metadata.gdb') - vl.setDataSource(datasource, 'test', 'ogr') + datasource = os.path.join(unitTestDataPath(), "gdb_metadata.gdb") + vl.setDataSource(datasource, "test", "ogr") self.assertTrue(vl.isValid()) # these settings weren't present in the original layer metadata, so should have been taken from the GDB file - self.assertEqual(vl.metadata().identifier(), 'Test') - self.assertEqual(vl.metadata().title(), 'Title') - self.assertEqual(vl.metadata().type(), 'dataset') - self.assertEqual(vl.metadata().language(), 'ENG') - self.assertEqual(vl.metadata().keywords(), {'Search keys': ['Tags']}) - self.assertEqual(vl.metadata().constraints()[0].type, 'Limitations of use') - self.assertEqual(vl.metadata().constraints()[0].constraint, 'This is the use limitation') - self.assertEqual(vl.metadata().extent().spatialExtents()[0].bounds.xMinimum(), 1) - self.assertEqual(vl.metadata().extent().spatialExtents()[0].bounds.xMaximum(), 2) - self.assertEqual(vl.metadata().extent().spatialExtents()[0].bounds.yMinimum(), 3) - self.assertEqual(vl.metadata().extent().spatialExtents()[0].bounds.yMaximum(), 4) + self.assertEqual(vl.metadata().identifier(), "Test") + self.assertEqual(vl.metadata().title(), "Title") + self.assertEqual(vl.metadata().type(), "dataset") + self.assertEqual(vl.metadata().language(), "ENG") + self.assertEqual(vl.metadata().keywords(), {"Search keys": ["Tags"]}) + self.assertEqual(vl.metadata().constraints()[0].type, "Limitations of use") + self.assertEqual( + vl.metadata().constraints()[0].constraint, "This is the use limitation" + ) + self.assertEqual( + vl.metadata().extent().spatialExtents()[0].bounds.xMinimum(), 1 + ) + self.assertEqual( + vl.metadata().extent().spatialExtents()[0].bounds.xMaximum(), 2 + ) + self.assertEqual( + vl.metadata().extent().spatialExtents()[0].bounds.yMinimum(), 3 + ) + self.assertEqual( + vl.metadata().extent().spatialExtents()[0].bounds.yMaximum(), 4 + ) # these setting WERE present, so must be retained - self.assertIn('original abstract', vl.metadata().abstract()) - self.assertEqual(vl.metadata().rights(), ['original right 1', 'original right 2']) + self.assertIn("original abstract", vl.metadata().abstract()) + self.assertEqual( + vl.metadata().rights(), ["original right 1", "original right 2"] + ) def testMapTips(self): - rl = QgsRasterLayer(os.path.join(TEST_DATA_DIR, 'float1-16.tif'), 'test') + rl = QgsRasterLayer(os.path.join(TEST_DATA_DIR, "float1-16.tif"), "test") self.assertFalse(rl.hasMapTips()) - rl.setMapTipTemplate('some template') - self.assertEqual(rl.mapTipTemplate(), 'some template') + rl.setMapTipTemplate("some template") + self.assertEqual(rl.mapTipTemplate(), "some template") self.assertTrue(rl.hasMapTips()) rl.setMapTipTemplate(None) @@ -551,5 +578,5 @@ def testError(self): self.assertEqual(vl.error().summary(), "") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmaplayeraction.py b/tests/src/python/test_qgsmaplayeraction.py index f09fb1550305..19a1637a0c2f 100644 --- a/tests/src/python/test_qgsmaplayeraction.py +++ b/tests/src/python/test_qgsmaplayeraction.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '24/02/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "24/02/2018" +__copyright__ = "Copyright 2018, The QGIS Project" import os @@ -27,63 +28,93 @@ def __init__(self, methodName): """Run once on class initialization.""" QgisTestCase.__init__(self, methodName) - self.vector_layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=flddate:datetime", - "test_layer", "memory") + self.vector_layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer&field=flddate:datetime", + "test_layer", + "memory", + ) assert self.vector_layer.isValid() - self.vector_layer2 = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=flddate:datetime", - "test_layer", "memory") + self.vector_layer2 = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer&field=flddate:datetime", + "test_layer", + "memory", + ) assert self.vector_layer2.isValid() - raster_path = os.path.join(unitTestDataPath(), 'landsat.tif') - self.raster_layer = QgsRasterLayer(raster_path, 'raster') + raster_path = os.path.join(unitTestDataPath(), "landsat.tif") + self.raster_layer = QgsRasterLayer(raster_path, "raster") assert self.raster_layer.isValid() def testCanRunUsingLayer(self): """ Test that actions correctly indicate when they can run for a layer """ - action_all_layers = QgsMapLayerAction('action1', None) + action_all_layers = QgsMapLayerAction("action1", None) self.assertTrue(action_all_layers.canRunUsingLayer(None)) self.assertTrue(action_all_layers.canRunUsingLayer(self.vector_layer)) self.assertTrue(action_all_layers.canRunUsingLayer(self.raster_layer)) - action_vector_layers_only = QgsMapLayerAction('action2', None, QgsMapLayer.LayerType.VectorLayer) + action_vector_layers_only = QgsMapLayerAction( + "action2", None, QgsMapLayer.LayerType.VectorLayer + ) self.assertFalse(action_vector_layers_only.canRunUsingLayer(None)) self.assertTrue(action_vector_layers_only.canRunUsingLayer(self.vector_layer)) self.assertFalse(action_vector_layers_only.canRunUsingLayer(self.raster_layer)) - action_raster_layers_only = QgsMapLayerAction('action3', None, QgsMapLayer.LayerType.RasterLayer) + action_raster_layers_only = QgsMapLayerAction( + "action3", None, QgsMapLayer.LayerType.RasterLayer + ) self.assertFalse(action_raster_layers_only.canRunUsingLayer(None)) self.assertFalse(action_raster_layers_only.canRunUsingLayer(self.vector_layer)) self.assertTrue(action_raster_layers_only.canRunUsingLayer(self.raster_layer)) - action_specific_layer_only = QgsMapLayerAction('action4', None, self.vector_layer) + action_specific_layer_only = QgsMapLayerAction( + "action4", None, self.vector_layer + ) self.assertFalse(action_specific_layer_only.canRunUsingLayer(None)) self.assertTrue(action_specific_layer_only.canRunUsingLayer(self.vector_layer)) - self.assertFalse(action_specific_layer_only.canRunUsingLayer(self.vector_layer2)) + self.assertFalse( + action_specific_layer_only.canRunUsingLayer(self.vector_layer2) + ) self.assertFalse(action_specific_layer_only.canRunUsingLayer(self.raster_layer)) - action_specific_raster_layer_only = QgsMapLayerAction('action4', None, self.raster_layer) + action_specific_raster_layer_only = QgsMapLayerAction( + "action4", None, self.raster_layer + ) self.assertFalse(action_specific_raster_layer_only.canRunUsingLayer(None)) - self.assertFalse(action_specific_raster_layer_only.canRunUsingLayer(self.vector_layer)) - self.assertFalse(action_specific_raster_layer_only.canRunUsingLayer(self.vector_layer2)) - self.assertTrue(action_specific_raster_layer_only.canRunUsingLayer(self.raster_layer)) - - action_editable_layer_only = QgsMapLayerAction('action1', None, flags=QgsMapLayerAction.Flag.EnabledOnlyWhenEditable) + self.assertFalse( + action_specific_raster_layer_only.canRunUsingLayer(self.vector_layer) + ) + self.assertFalse( + action_specific_raster_layer_only.canRunUsingLayer(self.vector_layer2) + ) + self.assertTrue( + action_specific_raster_layer_only.canRunUsingLayer(self.raster_layer) + ) + + action_editable_layer_only = QgsMapLayerAction( + "action1", None, flags=QgsMapLayerAction.Flag.EnabledOnlyWhenEditable + ) self.assertFalse(action_editable_layer_only.canRunUsingLayer(None)) self.assertFalse(action_editable_layer_only.canRunUsingLayer(self.vector_layer)) - self.assertFalse(action_editable_layer_only.canRunUsingLayer(self.vector_layer2)) + self.assertFalse( + action_editable_layer_only.canRunUsingLayer(self.vector_layer2) + ) self.assertFalse(action_editable_layer_only.canRunUsingLayer(self.raster_layer)) self.vector_layer.startEditing() self.assertFalse(action_editable_layer_only.canRunUsingLayer(None)) self.assertTrue(action_editable_layer_only.canRunUsingLayer(self.vector_layer)) - self.assertFalse(action_editable_layer_only.canRunUsingLayer(self.vector_layer2)) + self.assertFalse( + action_editable_layer_only.canRunUsingLayer(self.vector_layer2) + ) self.assertFalse(action_editable_layer_only.canRunUsingLayer(self.raster_layer)) self.vector_layer.commitChanges() self.assertFalse(action_editable_layer_only.canRunUsingLayer(None)) self.assertFalse(action_editable_layer_only.canRunUsingLayer(self.vector_layer)) - self.assertFalse(action_editable_layer_only.canRunUsingLayer(self.vector_layer2)) + self.assertFalse( + action_editable_layer_only.canRunUsingLayer(self.vector_layer2) + ) self.assertFalse(action_editable_layer_only.canRunUsingLayer(self.raster_layer)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmaplayercombobox.py b/tests/src/python/test_qgsmaplayercombobox.py index fd85df01bd76..e9da996dc689 100644 --- a/tests/src/python/test_qgsmaplayercombobox.py +++ b/tests/src/python/test_qgsmaplayercombobox.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '14/06/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "14/06/2019" +__copyright__ = "Copyright 2019, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication, QEvent from qgis.PyQt.QtTest import QSignalSpy @@ -25,93 +26,111 @@ def create_layer(name): - layer = QgsVectorLayer("Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - name, "memory") + layer = QgsVectorLayer( + "Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", name, "memory" + ) return layer def create_mesh_layer(name): - layer = QgsMeshLayer("1.0, 2.0\n2.0, 2.0\n3.0, 2.0\n---\n0, 1, 3", name, "mesh_memory") + layer = QgsMeshLayer( + "1.0, 2.0\n2.0, 2.0\n3.0, 2.0\n---\n0, 1, 3", name, "mesh_memory" + ) return layer class TestQgsMapLayerComboBox(QgisTestCase): def testGettersSetters(self): - """ test combo getters/setters """ + """test combo getters/setters""" m = QgsMapLayerComboBox() - l1 = create_layer('l1') + l1 = create_layer("l1") QgsProject.instance().addMapLayer(l1) - l2 = create_layer('l2') + l2 = create_layer("l2") QgsProject.instance().addMapLayer(l2) m.setFilters(Qgis.LayerFilter.LineLayer | Qgis.LayerFilter.WritableLayer) - self.assertEqual(m.filters(), Qgis.LayerFilters(Qgis.LayerFilter.LineLayer | Qgis.LayerFilter.WritableLayer)) + self.assertEqual( + m.filters(), + Qgis.LayerFilters( + Qgis.LayerFilter.LineLayer | Qgis.LayerFilter.WritableLayer + ), + ) m.setExceptedLayerList([l2]) self.assertEqual(m.exceptedLayerList(), [l2]) - m.setExcludedProviders(['a', 'b']) - self.assertEqual(m.excludedProviders(), ['a', 'b']) + m.setExcludedProviders(["a", "b"]) + self.assertEqual(m.excludedProviders(), ["a", "b"]) def testMeshLayer(self): m = QgsMapLayerComboBox() l1 = create_mesh_layer("l1") QgsProject.instance().addMapLayer(l1) - l2 = create_layer('l2') + l2 = create_layer("l2") QgsProject.instance().addMapLayer(l2) m.setFilters(Qgis.LayerFilter.MeshLayer) self.assertEqual(m.filters(), Qgis.LayerFilter.MeshLayer) self.assertEqual(m.count(), 1) - self.assertEqual(m.itemText(0), 'l1') + self.assertEqual(m.itemText(0), "l1") def testFilterGeometryType(self): - """ test filtering by geometry type """ + """test filtering by geometry type""" QgsProject.instance().clear() m = QgsMapLayerComboBox() - l1 = QgsVectorLayer("Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - 'layer 1', "memory") + l1 = QgsVectorLayer( + "Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", + "layer 1", + "memory", + ) QgsProject.instance().addMapLayer(l1) - l2 = QgsVectorLayer("Polygon?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - 'layer 2', "memory") + l2 = QgsVectorLayer( + "Polygon?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", + "layer 2", + "memory", + ) QgsProject.instance().addMapLayer(l2) - l3 = QgsVectorLayer("None?field=fldtxt:string&field=fldint:integer", - 'layer 3', "memory") + l3 = QgsVectorLayer( + "None?field=fldtxt:string&field=fldint:integer", "layer 3", "memory" + ) QgsProject.instance().addMapLayer(l3) - l4 = QgsVectorLayer("LineString?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - 'layer 4', "memory") + l4 = QgsVectorLayer( + "LineString?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", + "layer 4", + "memory", + ) QgsProject.instance().addMapLayer(l4) m.setFilters(Qgis.LayerFilter.PolygonLayer) self.assertEqual(m.count(), 1) - self.assertEqual(m.itemText(0), 'layer 2') + self.assertEqual(m.itemText(0), "layer 2") m.setFilters(Qgis.LayerFilter.PointLayer) self.assertEqual(m.count(), 1) - self.assertEqual(m.itemText(0), 'layer 1') + self.assertEqual(m.itemText(0), "layer 1") m.setFilters(Qgis.LayerFilter.LineLayer) self.assertEqual(m.count(), 1) - self.assertEqual(m.itemText(0), 'layer 4') + self.assertEqual(m.itemText(0), "layer 4") m.setFilters(Qgis.LayerFilter.NoGeometry) self.assertEqual(m.count(), 1) - self.assertEqual(m.itemText(0), 'layer 3') + self.assertEqual(m.itemText(0), "layer 3") m.setFilters(Qgis.LayerFilter.HasGeometry) self.assertEqual(m.count(), 3) - self.assertEqual(m.itemText(0), 'layer 1') - self.assertEqual(m.itemText(1), 'layer 2') - self.assertEqual(m.itemText(2), 'layer 4') + self.assertEqual(m.itemText(0), "layer 1") + self.assertEqual(m.itemText(1), "layer 2") + self.assertEqual(m.itemText(2), "layer 4") m.setFilters(Qgis.LayerFilter.VectorLayer) self.assertEqual(m.count(), 4) - self.assertEqual(m.itemText(0), 'layer 1') - self.assertEqual(m.itemText(1), 'layer 2') - self.assertEqual(m.itemText(2), 'layer 3') - self.assertEqual(m.itemText(3), 'layer 4') + self.assertEqual(m.itemText(0), "layer 1") + self.assertEqual(m.itemText(1), "layer 2") + self.assertEqual(m.itemText(2), "layer 3") + self.assertEqual(m.itemText(3), "layer 4") m.setFilters(Qgis.LayerFilter.PluginLayer) self.assertEqual(m.count(), 0) @@ -120,46 +139,62 @@ def testFilterGeometryType(self): self.assertEqual(m.count(), 0) def testFilterByLayer(self): - """ test filtering by layer""" + """test filtering by layer""" QgsProject.instance().clear() m = QgsMapLayerComboBox() - l1 = QgsVectorLayer("Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - 'layer 1', "memory") + l1 = QgsVectorLayer( + "Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", + "layer 1", + "memory", + ) QgsProject.instance().addMapLayer(l1) - l2 = QgsVectorLayer("Polygon?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - 'lAyEr 2', "memory") + l2 = QgsVectorLayer( + "Polygon?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", + "lAyEr 2", + "memory", + ) QgsProject.instance().addMapLayer(l2) - l3 = QgsVectorLayer("None?field=fldtxt:string&field=fldint:integer", - 'another', "memory") + l3 = QgsVectorLayer( + "None?field=fldtxt:string&field=fldint:integer", "another", "memory" + ) QgsProject.instance().addMapLayer(l3) - l4 = QgsVectorLayer("LineString?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - 'final layer', "memory") + l4 = QgsVectorLayer( + "LineString?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", + "final layer", + "memory", + ) QgsProject.instance().addMapLayer(l4) self.assertEqual(m.count(), 4) - self.assertEqual(m.itemText(0), 'another') - self.assertEqual(m.itemText(1), 'final layer') - self.assertEqual(m.itemText(2), 'layer 1') - self.assertEqual(m.itemText(3), 'lAyEr 2') + self.assertEqual(m.itemText(0), "another") + self.assertEqual(m.itemText(1), "final layer") + self.assertEqual(m.itemText(2), "layer 1") + self.assertEqual(m.itemText(3), "lAyEr 2") m.setExceptedLayerList([l1, l3]) self.assertEqual(m.count(), 2) - self.assertEqual(m.itemText(0), 'final layer') - self.assertEqual(m.itemText(1), 'lAyEr 2') + self.assertEqual(m.itemText(0), "final layer") + self.assertEqual(m.itemText(1), "lAyEr 2") m.setExceptedLayerList([l2, l4]) self.assertEqual(m.count(), 2) - self.assertEqual(m.itemText(0), 'another') - self.assertEqual(m.itemText(1), 'layer 1') + self.assertEqual(m.itemText(0), "another") + self.assertEqual(m.itemText(1), "layer 1") def testSignals(self): QgsProject.instance().clear() m = QgsMapLayerComboBox() - l1 = QgsVectorLayer("Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - 'layer 1', "memory") + l1 = QgsVectorLayer( + "Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", + "layer 1", + "memory", + ) QgsProject.instance().addMapLayer(l1) - l2 = QgsVectorLayer("Polygon?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - 'lAyEr 2', "memory") + l2 = QgsVectorLayer( + "Polygon?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", + "lAyEr 2", + "memory", + ) QgsProject.instance().addMapLayer(l2) spy = QSignalSpy(m.layerChanged) @@ -183,7 +218,7 @@ def testSignals(self): self.assertIsNone(m.currentLayer()) m.setEditable(True) - m.setCurrentText('aaa') + m.setCurrentText("aaa") self.assertIsNone(m.currentLayer()) m.setLayer(l1) @@ -192,81 +227,81 @@ def testSignals(self): def testAdditionalLayers(self): QgsProject.instance().clear() - l1 = create_layer('l1') - l2 = create_layer('l2') + l1 = create_layer("l1") + l2 = create_layer("l2") QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerComboBox() self.assertEqual(m.count(), 2) - l3 = create_layer('l3') - l4 = create_layer('l4') + l3 = create_layer("l3") + l4 = create_layer("l4") m.setAdditionalLayers([l3, l4]) self.assertEqual(m.count(), 4) - m.setAdditionalItems(['a', 'b']) + m.setAdditionalItems(["a", "b"]) self.assertEqual(m.count(), 6) - self.assertEqual(m.itemText(0), 'l1') - self.assertEqual(m.itemText(1), 'l2') - self.assertEqual(m.itemText(2), 'l3') - self.assertEqual(m.itemText(3), 'l4') - self.assertEqual(m.itemText(4), 'a') - self.assertEqual(m.itemText(5), 'b') + self.assertEqual(m.itemText(0), "l1") + self.assertEqual(m.itemText(1), "l2") + self.assertEqual(m.itemText(2), "l3") + self.assertEqual(m.itemText(3), "l4") + self.assertEqual(m.itemText(4), "a") + self.assertEqual(m.itemText(5), "b") m.setAllowEmptyLayer(True) self.assertEqual(m.count(), 7) self.assertFalse(m.itemText(0)) - self.assertEqual(m.itemText(1), 'l1') - self.assertEqual(m.itemText(2), 'l2') - self.assertEqual(m.itemText(3), 'l3') - self.assertEqual(m.itemText(4), 'l4') - self.assertEqual(m.itemText(5), 'a') - self.assertEqual(m.itemText(6), 'b') + self.assertEqual(m.itemText(1), "l1") + self.assertEqual(m.itemText(2), "l2") + self.assertEqual(m.itemText(3), "l3") + self.assertEqual(m.itemText(4), "l4") + self.assertEqual(m.itemText(5), "a") + self.assertEqual(m.itemText(6), "b") l3.deleteLater() QCoreApplication.sendPostedEvents(None, QEvent.Type.DeferredDelete) self.assertEqual(m.count(), 6) self.assertFalse(m.itemText(0)) - self.assertEqual(m.itemText(1), 'l1') - self.assertEqual(m.itemText(2), 'l2') - self.assertEqual(m.itemText(3), 'l4') - self.assertEqual(m.itemText(4), 'a') - self.assertEqual(m.itemText(5), 'b') - - l5 = create_layer('l5') - l6 = create_layer('l6') + self.assertEqual(m.itemText(1), "l1") + self.assertEqual(m.itemText(2), "l2") + self.assertEqual(m.itemText(3), "l4") + self.assertEqual(m.itemText(4), "a") + self.assertEqual(m.itemText(5), "b") + + l5 = create_layer("l5") + l6 = create_layer("l6") m.setAdditionalLayers([l5, l6, l4]) self.assertEqual(m.count(), 8) self.assertFalse(m.itemText(0)) - self.assertEqual(m.itemText(1), 'l1') - self.assertEqual(m.itemText(2), 'l2') - self.assertEqual(m.itemText(3), 'l4') - self.assertEqual(m.itemText(4), 'l5') - self.assertEqual(m.itemText(5), 'l6') - self.assertEqual(m.itemText(6), 'a') - self.assertEqual(m.itemText(7), 'b') + self.assertEqual(m.itemText(1), "l1") + self.assertEqual(m.itemText(2), "l2") + self.assertEqual(m.itemText(3), "l4") + self.assertEqual(m.itemText(4), "l5") + self.assertEqual(m.itemText(5), "l6") + self.assertEqual(m.itemText(6), "a") + self.assertEqual(m.itemText(7), "b") m.setAdditionalLayers([l5, l4]) self.assertEqual(m.count(), 7) self.assertFalse(m.itemText(0)) - self.assertEqual(m.itemText(1), 'l1') - self.assertEqual(m.itemText(2), 'l2') - self.assertEqual(m.itemText(3), 'l4') - self.assertEqual(m.itemText(4), 'l5') - self.assertEqual(m.itemText(5), 'a') - self.assertEqual(m.itemText(6), 'b') + self.assertEqual(m.itemText(1), "l1") + self.assertEqual(m.itemText(2), "l2") + self.assertEqual(m.itemText(3), "l4") + self.assertEqual(m.itemText(4), "l5") + self.assertEqual(m.itemText(5), "a") + self.assertEqual(m.itemText(6), "b") QgsProject.instance().removeMapLayers([l1.id(), l2.id()]) self.assertEqual(m.count(), 5) self.assertFalse(m.itemText(0)) - self.assertEqual(m.itemText(1), 'l4') - self.assertEqual(m.itemText(2), 'l5') - self.assertEqual(m.itemText(3), 'a') - self.assertEqual(m.itemText(4), 'b') + self.assertEqual(m.itemText(1), "l4") + self.assertEqual(m.itemText(2), "l5") + self.assertEqual(m.itemText(3), "a") + self.assertEqual(m.itemText(4), "b") def testProject(self): QgsProject.instance().clear() - lA = create_layer('lA') - lB = create_layer('lB') + lA = create_layer("lA") + lB = create_layer("lB") projectA = QgsProject.instance() projectB = QgsProject() @@ -286,5 +321,5 @@ def testProject(self): QgsProject.instance().clear() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmaplayerfactory.py b/tests/src/python/test_qgsmaplayerfactory.py index bd44f3cc41e3..70def080e2a5 100644 --- a/tests/src/python/test_qgsmaplayerfactory.py +++ b/tests/src/python/test_qgsmaplayerfactory.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '10/03/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "10/03/2021" +__copyright__ = "Copyright 2021, The QGIS Project" import os @@ -37,16 +38,39 @@ def testTypeFromString(self): """ Test QgsMapLayerFactory.typeFromString """ - self.assertEqual(QgsMapLayerFactory.typeFromString('xxx')[1], False) - self.assertEqual(QgsMapLayerFactory.typeFromString('')[1], False) - self.assertEqual(QgsMapLayerFactory.typeFromString('vector'), (QgsMapLayerType.VectorLayer, True)) - self.assertEqual(QgsMapLayerFactory.typeFromString('VECTOR'), (QgsMapLayerType.VectorLayer, True)) - self.assertEqual(QgsMapLayerFactory.typeFromString('raster'), (QgsMapLayerType.RasterLayer, True)) - self.assertEqual(QgsMapLayerFactory.typeFromString('mesh'), (QgsMapLayerType.MeshLayer, True)) - self.assertEqual(QgsMapLayerFactory.typeFromString('vector-tile'), (QgsMapLayerType.VectorTileLayer, True)) - self.assertEqual(QgsMapLayerFactory.typeFromString('point-cloud'), (QgsMapLayerType.PointCloudLayer, True)) - self.assertEqual(QgsMapLayerFactory.typeFromString('plugin'), (QgsMapLayerType.PluginLayer, True)) - self.assertEqual(QgsMapLayerFactory.typeFromString('annotation'), (QgsMapLayerType.AnnotationLayer, True)) + self.assertEqual(QgsMapLayerFactory.typeFromString("xxx")[1], False) + self.assertEqual(QgsMapLayerFactory.typeFromString("")[1], False) + self.assertEqual( + QgsMapLayerFactory.typeFromString("vector"), + (QgsMapLayerType.VectorLayer, True), + ) + self.assertEqual( + QgsMapLayerFactory.typeFromString("VECTOR"), + (QgsMapLayerType.VectorLayer, True), + ) + self.assertEqual( + QgsMapLayerFactory.typeFromString("raster"), + (QgsMapLayerType.RasterLayer, True), + ) + self.assertEqual( + QgsMapLayerFactory.typeFromString("mesh"), (QgsMapLayerType.MeshLayer, True) + ) + self.assertEqual( + QgsMapLayerFactory.typeFromString("vector-tile"), + (QgsMapLayerType.VectorTileLayer, True), + ) + self.assertEqual( + QgsMapLayerFactory.typeFromString("point-cloud"), + (QgsMapLayerType.PointCloudLayer, True), + ) + self.assertEqual( + QgsMapLayerFactory.typeFromString("plugin"), + (QgsMapLayerType.PluginLayer, True), + ) + self.assertEqual( + QgsMapLayerFactory.typeFromString("annotation"), + (QgsMapLayerType.AnnotationLayer, True), + ) def testTypeToString(self): """ @@ -54,69 +78,124 @@ def testTypeToString(self): """ # test via round trips... self.assertEqual( - QgsMapLayerFactory.typeFromString(QgsMapLayerFactory.typeToString(QgsMapLayerType.VectorLayer))[0], - QgsMapLayerType.VectorLayer) + QgsMapLayerFactory.typeFromString( + QgsMapLayerFactory.typeToString(QgsMapLayerType.VectorLayer) + )[0], + QgsMapLayerType.VectorLayer, + ) self.assertEqual( - QgsMapLayerFactory.typeFromString(QgsMapLayerFactory.typeToString(QgsMapLayerType.RasterLayer))[0], - QgsMapLayerType.RasterLayer) + QgsMapLayerFactory.typeFromString( + QgsMapLayerFactory.typeToString(QgsMapLayerType.RasterLayer) + )[0], + QgsMapLayerType.RasterLayer, + ) self.assertEqual( - QgsMapLayerFactory.typeFromString(QgsMapLayerFactory.typeToString(QgsMapLayerType.MeshLayer))[0], - QgsMapLayerType.MeshLayer) + QgsMapLayerFactory.typeFromString( + QgsMapLayerFactory.typeToString(QgsMapLayerType.MeshLayer) + )[0], + QgsMapLayerType.MeshLayer, + ) self.assertEqual( - QgsMapLayerFactory.typeFromString(QgsMapLayerFactory.typeToString(QgsMapLayerType.VectorTileLayer))[0], - QgsMapLayerType.VectorTileLayer) + QgsMapLayerFactory.typeFromString( + QgsMapLayerFactory.typeToString(QgsMapLayerType.VectorTileLayer) + )[0], + QgsMapLayerType.VectorTileLayer, + ) self.assertEqual( - QgsMapLayerFactory.typeFromString(QgsMapLayerFactory.typeToString(QgsMapLayerType.PointCloudLayer))[0], - QgsMapLayerType.PointCloudLayer) + QgsMapLayerFactory.typeFromString( + QgsMapLayerFactory.typeToString(QgsMapLayerType.PointCloudLayer) + )[0], + QgsMapLayerType.PointCloudLayer, + ) self.assertEqual( - QgsMapLayerFactory.typeFromString(QgsMapLayerFactory.typeToString(QgsMapLayerType.PluginLayer))[0], - QgsMapLayerType.PluginLayer) + QgsMapLayerFactory.typeFromString( + QgsMapLayerFactory.typeToString(QgsMapLayerType.PluginLayer) + )[0], + QgsMapLayerType.PluginLayer, + ) self.assertEqual( - QgsMapLayerFactory.typeFromString(QgsMapLayerFactory.typeToString(QgsMapLayerType.AnnotationLayer))[0], - QgsMapLayerType.AnnotationLayer) + QgsMapLayerFactory.typeFromString( + QgsMapLayerFactory.typeToString(QgsMapLayerType.AnnotationLayer) + )[0], + QgsMapLayerType.AnnotationLayer, + ) def testCreateLayer(self): # create vector options = QgsMapLayerFactory.LayerOptions(QgsCoordinateTransformContext()) - ml = QgsMapLayerFactory.createLayer(os.path.join(unitTestDataPath(), 'lines.shp'), 'lines', QgsMapLayerType.VectorLayer, options, 'ogr') + ml = QgsMapLayerFactory.createLayer( + os.path.join(unitTestDataPath(), "lines.shp"), + "lines", + QgsMapLayerType.VectorLayer, + options, + "ogr", + ) self.assertTrue(ml.isValid()) self.assertIsInstance(ml, QgsVectorLayer) - self.assertEqual(ml.name(), 'lines') + self.assertEqual(ml.name(), "lines") # create raster - ml = QgsMapLayerFactory.createLayer(os.path.join(unitTestDataPath(), 'landsat.tif'), 'rl', QgsMapLayerType.RasterLayer, options, 'gdal') + ml = QgsMapLayerFactory.createLayer( + os.path.join(unitTestDataPath(), "landsat.tif"), + "rl", + QgsMapLayerType.RasterLayer, + options, + "gdal", + ) self.assertTrue(ml.isValid()) self.assertIsInstance(ml, QgsRasterLayer) - self.assertEqual(ml.name(), 'rl') + self.assertEqual(ml.name(), "rl") # create mesh - ml = QgsMapLayerFactory.createLayer(os.path.join(unitTestDataPath(), 'mesh', 'lines.2dm'), 'ml', QgsMapLayerType.MeshLayer, options, 'mdal') + ml = QgsMapLayerFactory.createLayer( + os.path.join(unitTestDataPath(), "mesh", "lines.2dm"), + "ml", + QgsMapLayerType.MeshLayer, + options, + "mdal", + ) self.assertTrue(ml.isValid()) self.assertIsInstance(ml, QgsMeshLayer) - self.assertEqual(ml.name(), 'ml') + self.assertEqual(ml.name(), "ml") # create point cloud - ml = QgsMapLayerFactory.createLayer(os.path.join(unitTestDataPath(), 'point_clouds', 'ept', 'rgb', 'ept.json'), 'pcl', QgsMapLayerType.PointCloudLayer, options, 'ept') + ml = QgsMapLayerFactory.createLayer( + os.path.join(unitTestDataPath(), "point_clouds", "ept", "rgb", "ept.json"), + "pcl", + QgsMapLayerType.PointCloudLayer, + options, + "ept", + ) self.assertTrue(ml.isValid()) self.assertIsInstance(ml, QgsPointCloudLayer) - self.assertEqual(ml.name(), 'pcl') + self.assertEqual(ml.name(), "pcl") # annotation layer - ml = QgsMapLayerFactory.createLayer('', 'al', QgsMapLayerType.AnnotationLayer, options) + ml = QgsMapLayerFactory.createLayer( + "", "al", QgsMapLayerType.AnnotationLayer, options + ) self.assertTrue(ml.isValid()) self.assertIsInstance(ml, QgsAnnotationLayer) - self.assertEqual(ml.name(), 'al') + self.assertEqual(ml.name(), "al") # vector tile layer ds = QgsDataSourceUri() ds.setParam("type", "xyz") - ds.setParam("url", f"file://{os.path.join(unitTestDataPath(), 'vector_tile')}/{{z}}-{{x}}-{{y}}.pbf") + ds.setParam( + "url", + f"file://{os.path.join(unitTestDataPath(), 'vector_tile')}/{{z}}-{{x}}-{{y}}.pbf", + ) ds.setParam("zmax", "1") - ml = QgsMapLayerFactory.createLayer(ds.encodedUri().data().decode(), 'vtl', QgsMapLayerType.VectorTileLayer, options) + ml = QgsMapLayerFactory.createLayer( + ds.encodedUri().data().decode(), + "vtl", + QgsMapLayerType.VectorTileLayer, + options, + ) self.assertTrue(ml.isValid()) self.assertIsInstance(ml, QgsVectorTileLayer) - self.assertEqual(ml.name(), 'vtl') + self.assertEqual(ml.name(), "vtl") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmaplayermodel.py b/tests/src/python/test_qgsmaplayermodel.py index 3e29a74049cc..a52dfee7a435 100644 --- a/tests/src/python/test_qgsmaplayermodel.py +++ b/tests/src/python/test_qgsmaplayermodel.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '16/11/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "16/11/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication, QEvent, QModelIndex, Qt from qgis.core import ( @@ -23,15 +24,16 @@ def create_layer(name): - layer = QgsVectorLayer("Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - name, "memory") + layer = QgsVectorLayer( + "Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", name, "memory" + ) return layer class TestQgsMapLayerModel(QgisTestCase): def testGettersSetters(self): - """ test model getters/setters """ + """test model getters/setters""" m = QgsMapLayerModel() m.setItemsCheckable(True) @@ -49,8 +51,8 @@ def testGettersSetters(self): m.setShowCrs(False) self.assertFalse(m.showCrs()) - m.setAdditionalItems(['a', 'b']) - self.assertEqual(m.additionalItems(), ['a', 'b']) + m.setAdditionalItems(["a", "b"]) + self.assertEqual(m.additionalItems(), ["a", "b"]) m.setAdditionalItems([]) self.assertFalse(m.additionalItems()) @@ -60,11 +62,11 @@ def testAddingRemovingLayers(self): self.assertEqual(m.rowCount(QModelIndex()), 0) - l1 = create_layer('l1') + l1 = create_layer("l1") QgsProject.instance().addMapLayer(l1) self.assertEqual(m.rowCount(QModelIndex()), 1) self.assertEqual(m.layerFromIndex(m.index(0, 0)), l1) - l2 = create_layer('l2') + l2 = create_layer("l2") QgsProject.instance().addMapLayer(l2) self.assertEqual(m.rowCount(QModelIndex()), 2) self.assertEqual(m.layerFromIndex(m.index(0, 0)), l1) @@ -76,8 +78,8 @@ def testAddingRemovingLayers(self): self.assertEqual(m.rowCount(QModelIndex()), 0) # try creating a model when layers already exist in registry - l1 = create_layer('l1') - l2 = create_layer('l2') + l1 = create_layer("l1") + l2 = create_layer("l2") QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerModel() self.assertEqual(m.rowCount(QModelIndex()), 2) @@ -85,8 +87,8 @@ def testAddingRemovingLayers(self): self.assertEqual(m.rowCount(QModelIndex()), 0) def testCheckAll(self): - l1 = create_layer('l1') - l2 = create_layer('l2') + l1 = create_layer("l1") + l2 = create_layer("l2") QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerModel() m.setItemsCheckable(True) @@ -104,8 +106,8 @@ def testCheckAll(self): QgsProject.instance().removeMapLayers([l1.id(), l2.id()]) def testAllowEmpty(self): - l1 = create_layer('l1') - l2 = create_layer('l2') + l1 = create_layer("l1") + l2 = create_layer("l2") QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerModel() self.assertEqual(m.rowCount(QModelIndex()), 2) @@ -119,129 +121,131 @@ def testAllowEmpty(self): # add layers after allow empty is true m.setAllowEmptyLayer(True) - l3 = create_layer('l3') + l3 = create_layer("l3") QgsProject.instance().addMapLayers([l3]) self.assertEqual(m.rowCount(QModelIndex()), 4) self.assertFalse(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), 'l1') - self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), 'l2') - self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), 'l3') + self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), "l1") + self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), "l2") + self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), "l3") self.assertIsNone(m.data(m.index(0, 0), Qt.ItemDataRole.DecorationRole)) # set icon and text for empty item - m.setAllowEmptyLayer(True, 'empty', QgsApplication.getThemeIcon('/mItemBookmark.svg')) - self.assertEqual(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole), 'empty') + m.setAllowEmptyLayer( + True, "empty", QgsApplication.getThemeIcon("/mItemBookmark.svg") + ) + self.assertEqual(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole), "empty") self.assertFalse(m.data(m.index(0, 0), Qt.ItemDataRole.DecorationRole).isNull()) QgsProject.instance().removeMapLayers([l1.id(), l2.id(), l3.id()]) def testAdditionalItems(self): - l1 = create_layer('l1') - l2 = create_layer('l2') + l1 = create_layer("l1") + l2 = create_layer("l2") QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerModel() self.assertEqual(m.rowCount(QModelIndex()), 2) - m.setAdditionalItems(['a', 'b']) + m.setAdditionalItems(["a", "b"]) self.assertEqual(m.rowCount(QModelIndex()), 4) - self.assertEqual(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole), 'l1') - self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), 'l2') - self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), 'b') + self.assertEqual(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole), "l1") + self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), "l2") + self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), "a") + self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), "b") m.setAllowEmptyLayer(True) self.assertEqual(m.rowCount(QModelIndex()), 5) self.assertFalse(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), 'l1') - self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), 'l2') - self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(m.data(m.index(4, 0), Qt.ItemDataRole.DisplayRole), 'b') + self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), "l1") + self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), "l2") + self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), "a") + self.assertEqual(m.data(m.index(4, 0), Qt.ItemDataRole.DisplayRole), "b") QgsProject.instance().removeMapLayers([l1.id(), l2.id()]) self.assertEqual(m.rowCount(QModelIndex()), 3) self.assertFalse(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), 'b') + self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), "a") + self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), "b") def testAdditionalLayers(self): - l1 = create_layer('l1') - l2 = create_layer('l2') + l1 = create_layer("l1") + l2 = create_layer("l2") QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerModel() self.assertEqual(m.rowCount(QModelIndex()), 2) - l3 = create_layer('l3') - l4 = create_layer('l4') + l3 = create_layer("l3") + l4 = create_layer("l4") m.setAdditionalLayers([l3, l4]) self.assertEqual(m.rowCount(QModelIndex()), 4) - m.setAdditionalItems(['a', 'b']) + m.setAdditionalItems(["a", "b"]) self.assertEqual(m.rowCount(QModelIndex()), 6) - self.assertEqual(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole), 'l1') - self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), 'l2') - self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), 'l3') - self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), 'l4') - self.assertEqual(m.data(m.index(4, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(m.data(m.index(5, 0), Qt.ItemDataRole.DisplayRole), 'b') + self.assertEqual(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole), "l1") + self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), "l2") + self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), "l3") + self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), "l4") + self.assertEqual(m.data(m.index(4, 0), Qt.ItemDataRole.DisplayRole), "a") + self.assertEqual(m.data(m.index(5, 0), Qt.ItemDataRole.DisplayRole), "b") m.setAllowEmptyLayer(True) self.assertEqual(m.rowCount(QModelIndex()), 7) self.assertFalse(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), 'l1') - self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), 'l2') - self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), 'l3') - self.assertEqual(m.data(m.index(4, 0), Qt.ItemDataRole.DisplayRole), 'l4') - self.assertEqual(m.data(m.index(5, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(m.data(m.index(6, 0), Qt.ItemDataRole.DisplayRole), 'b') + self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), "l1") + self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), "l2") + self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), "l3") + self.assertEqual(m.data(m.index(4, 0), Qt.ItemDataRole.DisplayRole), "l4") + self.assertEqual(m.data(m.index(5, 0), Qt.ItemDataRole.DisplayRole), "a") + self.assertEqual(m.data(m.index(6, 0), Qt.ItemDataRole.DisplayRole), "b") l3.deleteLater() QCoreApplication.sendPostedEvents(None, QEvent.Type.DeferredDelete) self.assertEqual(m.rowCount(QModelIndex()), 6) self.assertFalse(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), 'l1') - self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), 'l2') - self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), 'l4') - self.assertEqual(m.data(m.index(4, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(m.data(m.index(5, 0), Qt.ItemDataRole.DisplayRole), 'b') - - l5 = create_layer('l5') - l6 = create_layer('l6') + self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), "l1") + self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), "l2") + self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), "l4") + self.assertEqual(m.data(m.index(4, 0), Qt.ItemDataRole.DisplayRole), "a") + self.assertEqual(m.data(m.index(5, 0), Qt.ItemDataRole.DisplayRole), "b") + + l5 = create_layer("l5") + l6 = create_layer("l6") m.setAdditionalLayers([l5, l6, l4]) self.assertEqual(m.rowCount(QModelIndex()), 8) self.assertFalse(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), 'l1') - self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), 'l2') - self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), 'l5') - self.assertEqual(m.data(m.index(4, 0), Qt.ItemDataRole.DisplayRole), 'l6') - self.assertEqual(m.data(m.index(5, 0), Qt.ItemDataRole.DisplayRole), 'l4') - self.assertEqual(m.data(m.index(6, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(m.data(m.index(7, 0), Qt.ItemDataRole.DisplayRole), 'b') + self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), "l1") + self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), "l2") + self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), "l5") + self.assertEqual(m.data(m.index(4, 0), Qt.ItemDataRole.DisplayRole), "l6") + self.assertEqual(m.data(m.index(5, 0), Qt.ItemDataRole.DisplayRole), "l4") + self.assertEqual(m.data(m.index(6, 0), Qt.ItemDataRole.DisplayRole), "a") + self.assertEqual(m.data(m.index(7, 0), Qt.ItemDataRole.DisplayRole), "b") m.setAdditionalLayers([l5, l4]) self.assertEqual(m.rowCount(QModelIndex()), 7) self.assertFalse(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), 'l1') - self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), 'l2') - self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), 'l5') - self.assertEqual(m.data(m.index(4, 0), Qt.ItemDataRole.DisplayRole), 'l4') - self.assertEqual(m.data(m.index(5, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(m.data(m.index(6, 0), Qt.ItemDataRole.DisplayRole), 'b') + self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), "l1") + self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), "l2") + self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), "l5") + self.assertEqual(m.data(m.index(4, 0), Qt.ItemDataRole.DisplayRole), "l4") + self.assertEqual(m.data(m.index(5, 0), Qt.ItemDataRole.DisplayRole), "a") + self.assertEqual(m.data(m.index(6, 0), Qt.ItemDataRole.DisplayRole), "b") QgsProject.instance().removeMapLayers([l1.id(), l2.id()]) self.assertEqual(m.rowCount(QModelIndex()), 5) self.assertFalse(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), 'l5') - self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), 'l4') - self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(m.data(m.index(4, 0), Qt.ItemDataRole.DisplayRole), 'b') + self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), "l5") + self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), "l4") + self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), "a") + self.assertEqual(m.data(m.index(4, 0), Qt.ItemDataRole.DisplayRole), "b") def testIndexFromLayer(self): - l1 = create_layer('l1') - l2 = create_layer('l2') + l1 = create_layer("l1") + l2 = create_layer("l2") QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerModel() - l3 = create_layer('l3') # not in registry + l3 = create_layer("l3") # not in registry self.assertEqual(m.indexFromLayer(l1).row(), 0) self.assertEqual(m.layerFromIndex(m.indexFromLayer(l1)), l1) @@ -256,8 +260,8 @@ def testIndexFromLayer(self): QgsProject.instance().removeMapLayers([l1.id(), l2.id()]) def testProject(self): - lA = create_layer('lA') - lB = create_layer('lB') + lA = create_layer("lA") + lB = create_layer("lB") projectA = QgsProject.instance() projectB = QgsProject() @@ -276,80 +280,109 @@ def testProject(self): QgsProject.instance().removeAllMapLayers() def testDisplayRole(self): - l1 = create_layer('l1') - l2 = create_layer('l2') + l1 = create_layer("l1") + l2 = create_layer("l2") QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerModel() - self.assertEqual(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole), 'l1') - self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), 'l2') + self.assertEqual(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole), "l1") + self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), "l2") m.setAllowEmptyLayer(True) self.assertFalse(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), 'l1') - self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), 'l2') + self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), "l1") + self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), "l2") QgsProject.instance().removeMapLayers([l1.id(), l2.id()]) def testDisplayRoleShowCrs(self): - l1 = create_layer('l1') - l2 = create_layer('l2') - l3 = QgsVectorLayer("NoGeometry?field=fldtxt:string&field=fldint:integer", - 'no geom', "memory") + l1 = create_layer("l1") + l2 = create_layer("l2") + l3 = QgsVectorLayer( + "NoGeometry?field=fldtxt:string&field=fldint:integer", "no geom", "memory" + ) QgsProject.instance().addMapLayers([l1, l2, l3]) m = QgsMapLayerModel() m.setShowCrs(True) - self.assertEqual(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole), 'l1 [EPSG:3111]') - self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), 'l2 [EPSG:3111]') - self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), 'no geom') + self.assertEqual( + m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole), "l1 [EPSG:3111]" + ) + self.assertEqual( + m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), "l2 [EPSG:3111]" + ) + self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), "no geom") m.setAllowEmptyLayer(True) self.assertFalse(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), 'l1 [EPSG:3111]') - self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), 'l2 [EPSG:3111]') - self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), 'no geom') + self.assertEqual( + m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), "l1 [EPSG:3111]" + ) + self.assertEqual( + m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), "l2 [EPSG:3111]" + ) + self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), "no geom") - m.setAdditionalItems(['a']) - self.assertEqual(m.data(m.index(4, 0), Qt.ItemDataRole.DisplayRole), 'a') + m.setAdditionalItems(["a"]) + self.assertEqual(m.data(m.index(4, 0), Qt.ItemDataRole.DisplayRole), "a") QgsProject.instance().removeMapLayers([l1.id(), l2.id(), l3.id()]) def testLayerIdRole(self): - l1 = create_layer('l1') - l2 = create_layer('l2') + l1 = create_layer("l1") + l2 = create_layer("l2") QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerModel() - self.assertEqual(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id()) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id()) + self.assertEqual( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id() + ) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id() + ) m.setAllowEmptyLayer(True) - self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id()) - self.assertEqual(m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id()) - - m.setAdditionalItems(['a']) - self.assertFalse(m.data(m.index(3, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) + self.assertFalse( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id() + ) + self.assertEqual( + m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id() + ) + + m.setAdditionalItems(["a"]) + self.assertFalse( + m.data(m.index(3, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) QgsProject.instance().removeMapLayers([l1.id(), l2.id()]) def testLayerRole(self): - l1 = create_layer('l1') - l2 = create_layer('l2') + l1 = create_layer("l1") + l2 = create_layer("l2") QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerModel() - self.assertEqual(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l1) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l2) + self.assertEqual( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l1 + ) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l2 + ) m.setAllowEmptyLayer(True) self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerRole)) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l1) - self.assertEqual(m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l2) - - m.setAdditionalItems(['a']) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l1 + ) + self.assertEqual( + m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l2 + ) + + m.setAdditionalItems(["a"]) self.assertFalse(m.data(m.index(3, 0), QgsMapLayerModel.ItemDataRole.LayerRole)) QgsProject.instance().removeMapLayers([l1.id(), l2.id()]) def testIsEmptyRole(self): - l1 = create_layer('l1') - l2 = create_layer('l2') + l1 = create_layer("l1") + l2 = create_layer("l2") QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerModel() self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.EmptyRole)) @@ -359,34 +392,52 @@ def testIsEmptyRole(self): self.assertFalse(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.EmptyRole)) self.assertFalse(m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.EmptyRole)) - m.setAdditionalItems(['a']) + m.setAdditionalItems(["a"]) self.assertFalse(m.data(m.index(3, 0), QgsMapLayerModel.ItemDataRole.EmptyRole)) QgsProject.instance().removeMapLayers([l1.id(), l2.id()]) def testIsAdditionalRole(self): - l1 = create_layer('l1') - l2 = create_layer('l2') + l1 = create_layer("l1") + l2 = create_layer("l2") QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerModel() - self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.AdditionalRole)) - self.assertFalse(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.AdditionalRole)) + self.assertFalse( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.AdditionalRole) + ) + self.assertFalse( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.AdditionalRole) + ) m.setAllowEmptyLayer(True) - self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.AdditionalRole)) - self.assertFalse(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.AdditionalRole)) - self.assertFalse(m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.AdditionalRole)) - - m.setAdditionalItems(['a']) - self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.AdditionalRole)) - self.assertFalse(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.AdditionalRole)) - self.assertFalse(m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.AdditionalRole)) - self.assertTrue(m.data(m.index(3, 0), QgsMapLayerModel.ItemDataRole.AdditionalRole)) + self.assertFalse( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.AdditionalRole) + ) + self.assertFalse( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.AdditionalRole) + ) + self.assertFalse( + m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.AdditionalRole) + ) + + m.setAdditionalItems(["a"]) + self.assertFalse( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.AdditionalRole) + ) + self.assertFalse( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.AdditionalRole) + ) + self.assertFalse( + m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.AdditionalRole) + ) + self.assertTrue( + m.data(m.index(3, 0), QgsMapLayerModel.ItemDataRole.AdditionalRole) + ) QgsProject.instance().removeMapLayers([l1.id(), l2.id()]) def testCheckStateRole(self): - l1 = create_layer('l1') - l2 = create_layer('l2') + l1 = create_layer("l1") + l2 = create_layer("l2") QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerModel() @@ -409,14 +460,14 @@ def testCheckStateRole(self): self.assertTrue(m.data(m.index(1, 0), Qt.ItemDataRole.CheckStateRole)) self.assertTrue(m.data(m.index(2, 0), Qt.ItemDataRole.CheckStateRole)) - m.setAdditionalItems(['a']) + m.setAdditionalItems(["a"]) self.assertFalse(m.data(m.index(3, 0), Qt.ItemDataRole.CheckStateRole)) QgsProject.instance().removeMapLayers([l1.id(), l2.id()]) def testFlags(self): - l1 = create_layer('l1') - l2 = create_layer('l2') + l1 = create_layer("l1") + l2 = create_layer("l2") QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerModel() @@ -450,7 +501,7 @@ def testFlags(self): self.assertTrue(m.flags(m.index(2, 0)) & Qt.ItemFlag.ItemIsUserCheckable) self.assertFalse(m.flags(m.index(2, 0)) & Qt.ItemFlag.ItemIsDragEnabled) - m.setAdditionalItems(['a']) + m.setAdditionalItems(["a"]) self.assertFalse(m.flags(m.index(3, 0)) & Qt.ItemFlag.ItemIsUserCheckable) self.assertFalse(m.flags(m.index(3, 0)) & Qt.ItemFlag.ItemIsDragEnabled) @@ -472,7 +523,7 @@ def testFlags(self): self.assertFalse(m.flags(m.index(2, 0)) & Qt.ItemFlag.ItemIsUserCheckable) self.assertTrue(m.flags(m.index(2, 0)) & Qt.ItemFlag.ItemIsDragEnabled) - m.setAdditionalItems(['a']) + m.setAdditionalItems(["a"]) self.assertFalse(m.flags(m.index(3, 0)) & Qt.ItemFlag.ItemIsUserCheckable) self.assertFalse(m.flags(m.index(3, 0)) & Qt.ItemFlag.ItemIsDragEnabled) @@ -481,8 +532,8 @@ def testFlags(self): QgsProject.instance().removeMapLayers([l1.id(), l2.id()]) def testSetData(self): - l1 = create_layer('l1') - l2 = create_layer('l2') + l1 = create_layer("l1") + l2 = create_layer("l2") QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerModel() @@ -499,121 +550,239 @@ def testSetData(self): self.assertFalse(m.setData(m.index(0, 0), True, Qt.ItemDataRole.CheckStateRole)) self.assertTrue(m.setData(m.index(1, 0), True, Qt.ItemDataRole.CheckStateRole)) - m.setAdditionalItems(['a']) + m.setAdditionalItems(["a"]) self.assertFalse(m.setData(m.index(3, 0), True, Qt.ItemDataRole.CheckStateRole)) QgsProject.instance().removeMapLayers([l1.id(), l2.id()]) def testSetDataId(self): - l1 = create_layer('l1') - l2 = create_layer('l2') + l1 = create_layer("l1") + l2 = create_layer("l2") QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerModel() - self.assertEqual(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id()) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id()) - - self.assertTrue(m.setData(m.index(0, 0), l2.id(), QgsMapLayerModel.ItemDataRole.LayerIdRole)) - self.assertEqual(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id()) - self.assertEqual(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l2) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id()) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l2) - - self.assertTrue(m.setData(m.index(1, 0), l1.id(), QgsMapLayerModel.ItemDataRole.LayerIdRole)) - self.assertEqual(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id()) - self.assertEqual(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l2) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id()) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l1) + self.assertEqual( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id() + ) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id() + ) + + self.assertTrue( + m.setData(m.index(0, 0), l2.id(), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) + self.assertEqual( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id() + ) + self.assertEqual( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l2 + ) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id() + ) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l2 + ) + + self.assertTrue( + m.setData(m.index(1, 0), l1.id(), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) + self.assertEqual( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id() + ) + self.assertEqual( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l2 + ) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id() + ) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l1 + ) m.setAllowEmptyLayer(True) - self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) + self.assertFalse( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerRole)) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id()) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l2) - self.assertEqual(m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id()) - self.assertEqual(m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l1) - self.assertTrue(m.setData(m.index(1, 0), l1.id(), QgsMapLayerModel.ItemDataRole.LayerIdRole)) - self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id() + ) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l2 + ) + self.assertEqual( + m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id() + ) + self.assertEqual( + m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l1 + ) + self.assertTrue( + m.setData(m.index(1, 0), l1.id(), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) + self.assertFalse( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerRole)) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id()) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l1) - self.assertEqual(m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id()) - self.assertEqual(m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l1) - self.assertTrue(m.setData(m.index(2, 0), l2.id(), QgsMapLayerModel.ItemDataRole.LayerIdRole)) - self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id() + ) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l1 + ) + self.assertEqual( + m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id() + ) + self.assertEqual( + m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l1 + ) + self.assertTrue( + m.setData(m.index(2, 0), l2.id(), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) + self.assertFalse( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerRole)) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id()) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l1) - self.assertEqual(m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id()) - self.assertEqual(m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l2) - - m.setAdditionalItems(['a']) - self.assertFalse(m.setData(m.index(3, 0), True, QgsMapLayerModel.ItemDataRole.LayerRole)) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id() + ) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l1 + ) + self.assertEqual( + m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id() + ) + self.assertEqual( + m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerRole), l2 + ) + + m.setAdditionalItems(["a"]) + self.assertFalse( + m.setData(m.index(3, 0), True, QgsMapLayerModel.ItemDataRole.LayerRole) + ) QgsProject.instance().removeMapLayers([l1.id(), l2.id()]) def testInsertRows(self): - l1 = create_layer('l1') - l2 = create_layer('l2') + l1 = create_layer("l1") + l2 = create_layer("l2") QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerModel() self.assertEqual(m.rowCount(), 2) - self.assertEqual(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id()) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id()) + self.assertEqual( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id() + ) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id() + ) self.assertTrue(m.insertRows(0, 2)) self.assertEqual(m.rowCount(), 4) - self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) - self.assertFalse(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) - self.assertEqual(m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id()) - self.assertEqual(m.data(m.index(3, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id()) + self.assertFalse( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) + self.assertFalse( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) + self.assertEqual( + m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id() + ) + self.assertEqual( + m.data(m.index(3, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id() + ) self.assertTrue(m.insertRows(3, 1)) self.assertEqual(m.rowCount(), 5) - self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) - self.assertFalse(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) - self.assertEqual(m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id()) - self.assertFalse(m.data(m.index(3, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) - self.assertEqual(m.data(m.index(4, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id()) + self.assertFalse( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) + self.assertFalse( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) + self.assertEqual( + m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id() + ) + self.assertFalse( + m.data(m.index(3, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) + self.assertEqual( + m.data(m.index(4, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id() + ) self.assertTrue(m.insertRows(5, 2)) self.assertEqual(m.rowCount(), 7) - self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) - self.assertFalse(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) - self.assertEqual(m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id()) - self.assertFalse(m.data(m.index(3, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) - self.assertEqual(m.data(m.index(4, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id()) - self.assertFalse(m.data(m.index(5, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) - self.assertFalse(m.data(m.index(6, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) + self.assertFalse( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) + self.assertFalse( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) + self.assertEqual( + m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id() + ) + self.assertFalse( + m.data(m.index(3, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) + self.assertEqual( + m.data(m.index(4, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id() + ) + self.assertFalse( + m.data(m.index(5, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) + self.assertFalse( + m.data(m.index(6, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) m = QgsMapLayerModel() m.setAllowEmptyLayer(True) self.assertEqual(m.rowCount(), 3) - self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id()) - self.assertEqual(m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id()) + self.assertFalse( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id() + ) + self.assertEqual( + m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id() + ) self.assertTrue(m.insertRows(2, 2)) self.assertEqual(m.rowCount(), 5) - self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id()) - self.assertFalse(m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) - self.assertFalse(m.data(m.index(3, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) - self.assertEqual(m.data(m.index(4, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id()) + self.assertFalse( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id() + ) + self.assertFalse( + m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) + self.assertFalse( + m.data(m.index(3, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) + self.assertEqual( + m.data(m.index(4, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id() + ) QgsProject.instance().removeMapLayers([l1.id(), l2.id()]) def testRemoveRows(self): - l1 = create_layer('l1') - l2 = create_layer('l2') + l1 = create_layer("l1") + l2 = create_layer("l2") QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerModel() self.assertEqual(m.rowCount(), 2) - self.assertEqual(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id()) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id()) + self.assertEqual( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id() + ) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id() + ) self.assertTrue(m.removeRows(0, 1)) self.assertEqual(m.rowCount(), 1) - self.assertEqual(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id()) + self.assertEqual( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id() + ) self.assertTrue(m.removeRows(0, 1)) self.assertEqual(m.rowCount(), 0) @@ -632,47 +801,67 @@ def testRemoveRows(self): self.assertEqual(m.rowCount(), 3) self.assertTrue(m.removeRows(2, 1)) self.assertEqual(m.rowCount(), 2) - self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id()) + self.assertFalse( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id() + ) self.assertFalse(m.removeRows(2, 1)) self.assertEqual(m.rowCount(), 2) self.assertTrue(m.removeRows(1, 1)) self.assertEqual(m.rowCount(), 1) - self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) + self.assertFalse( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) m = QgsMapLayerModel() m.setAllowEmptyLayer(True) self.assertEqual(m.rowCount(), 3) self.assertFalse(m.removeRows(3, 2)) self.assertTrue(m.removeRows(1, 2)) self.assertEqual(m.rowCount(), 1) - self.assertFalse(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole)) + self.assertFalse( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole) + ) self.assertFalse(m.removeRows(1, 1)) self.assertFalse(m.removeRows(0, 1)) QgsProject.instance().removeMapLayers([l1.id(), l2.id()]) def testMime(self): - l1 = create_layer('l1') - l2 = create_layer('l2') + l1 = create_layer("l1") + l2 = create_layer("l2") QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerModel() - self.assertEqual(m.mimeTypes(), ['application/qgis.layermodeldata']) + self.assertEqual(m.mimeTypes(), ["application/qgis.layermodeldata"]) data = m.mimeData([m.index(0, 0)]) self.assertTrue(data) - self.assertFalse(m.canDropMimeData(data, Qt.DropAction.MoveAction, 0, 0, QModelIndex())) + self.assertFalse( + m.canDropMimeData(data, Qt.DropAction.MoveAction, 0, 0, QModelIndex()) + ) m.setItemsCanBeReordered(True) - self.assertTrue(m.canDropMimeData(data, Qt.DropAction.MoveAction, 0, 0, QModelIndex())) + self.assertTrue( + m.canDropMimeData(data, Qt.DropAction.MoveAction, 0, 0, QModelIndex()) + ) - self.assertTrue(m.dropMimeData(data, Qt.DropAction.MoveAction, 2, 0, QModelIndex())) + self.assertTrue( + m.dropMimeData(data, Qt.DropAction.MoveAction, 2, 0, QModelIndex()) + ) self.assertEqual(m.rowCount(), 3) - self.assertEqual(m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id()) - self.assertEqual(m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id()) - self.assertEqual(m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id()) + self.assertEqual( + m.data(m.index(0, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id() + ) + self.assertEqual( + m.data(m.index(1, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l2.id() + ) + self.assertEqual( + m.data(m.index(2, 0), QgsMapLayerModel.ItemDataRole.LayerIdRole), l1.id() + ) QgsProject.instance().removeMapLayers([l1.id(), l2.id()]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmaplayerproxymodel.py b/tests/src/python/test_qgsmaplayerproxymodel.py index 0256fcd4ff75..d302b2f7b50f 100644 --- a/tests/src/python/test_qgsmaplayerproxymodel.py +++ b/tests/src/python/test_qgsmaplayerproxymodel.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '22/08/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "22/08/2018" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.core import ( @@ -25,28 +26,36 @@ def create_layer(name): - layer = QgsVectorLayer("Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - name, "memory") + layer = QgsVectorLayer( + "Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", name, "memory" + ) return layer def create_mesh_layer(name): - layer = QgsMeshLayer("1.0, 2.0\n2.0, 2.0\n3.0, 2.0\n---\n0, 1, 3", name, "mesh_memory") + layer = QgsMeshLayer( + "1.0, 2.0\n2.0, 2.0\n3.0, 2.0\n---\n0, 1, 3", name, "mesh_memory" + ) return layer class TestQgsMapLayerProxyModel(QgisTestCase): def testGettersSetters(self): - """ test model getters/setters """ + """test model getters/setters""" m = QgsMapLayerProxyModel() - l1 = create_layer('l1') + l1 = create_layer("l1") QgsProject.instance().addMapLayer(l1) - l2 = create_layer('l2') + l2 = create_layer("l2") QgsProject.instance().addMapLayer(l2) m.setFilters(Qgis.LayerFilter.LineLayer | Qgis.LayerFilter.WritableLayer) - self.assertEqual(m.filters(), Qgis.LayerFilters(Qgis.LayerFilter.LineLayer | Qgis.LayerFilter.WritableLayer)) + self.assertEqual( + m.filters(), + Qgis.LayerFilters( + Qgis.LayerFilter.LineLayer | Qgis.LayerFilter.WritableLayer + ), + ) m.setExceptedLayerIds([l2.id()]) self.assertEqual(m.exceptedLayerIds(), [l2.id()]) @@ -57,24 +66,24 @@ def testGettersSetters(self): m.setLayerAllowlist([l2]) self.assertEqual(m.layerAllowlist(), [l2]) - m.setExcludedProviders(['a', 'b']) - self.assertEqual(m.excludedProviders(), ['a', 'b']) + m.setExcludedProviders(["a", "b"]) + self.assertEqual(m.excludedProviders(), ["a", "b"]) - m.setFilterString('c') - self.assertEqual(m.filterString(), 'c') + m.setFilterString("c") + self.assertEqual(m.filterString(), "c") def testMeshLayer(self): m = QgsMapLayerProxyModel() l1 = create_mesh_layer("l1") QgsProject.instance().addMapLayer(l1) - l2 = create_layer('l2') + l2 = create_layer("l2") QgsProject.instance().addMapLayer(l2) m.setFilters(Qgis.LayerFilter.MeshLayer) self.assertEqual(m.filters(), Qgis.LayerFilter.MeshLayer) self.assertEqual(m.rowCount(), 1) - self.assertEqual(m.data(m.index(0, 0)), 'l1') + self.assertEqual(m.data(m.index(0, 0)), "l1") self.assertTrue(m.acceptsLayer(l1)) self.assertFalse(m.acceptsLayer(l2)) @@ -86,56 +95,68 @@ def testAnnotationLayer(self): QgsProject.instance().clear() m = QgsMapLayerProxyModel() - options = QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()) - l1 = QgsAnnotationLayer('annotation 1', options) + options = QgsAnnotationLayer.LayerOptions( + QgsProject.instance().transformContext() + ) + l1 = QgsAnnotationLayer("annotation 1", options) QgsProject.instance().addMapLayer(l1) - l2 = create_layer('l2') + l2 = create_layer("l2") QgsProject.instance().addMapLayer(l2) m.setFilters(Qgis.LayerFilter.AnnotationLayer) self.assertEqual(m.filters(), Qgis.LayerFilter.AnnotationLayer) self.assertEqual(m.rowCount(), 1) - self.assertEqual(m.data(m.index(0, 0)), 'annotation 1') + self.assertEqual(m.data(m.index(0, 0)), "annotation 1") self.assertTrue(m.acceptsLayer(l1)) self.assertFalse(m.acceptsLayer(l2)) m.setFilters(Qgis.LayerFilter.VectorLayer) self.assertEqual(m.rowCount(), 1) - self.assertEqual(m.data(m.index(0, 0)), 'l2') + self.assertEqual(m.data(m.index(0, 0)), "l2") self.assertFalse(m.acceptsLayer(l1)) self.assertTrue(m.acceptsLayer(l2)) m.setFilters(Qgis.LayerFilter.All) self.assertEqual(m.rowCount(), 2) - self.assertEqual(m.data(m.index(0, 0)), 'annotation 1') - self.assertEqual(m.data(m.index(1, 0)), 'l2') + self.assertEqual(m.data(m.index(0, 0)), "annotation 1") + self.assertEqual(m.data(m.index(1, 0)), "l2") self.assertTrue(m.acceptsLayer(l1)) self.assertTrue(m.acceptsLayer(l2)) def testFilterGeometryType(self): - """ test filtering by geometry type """ + """test filtering by geometry type""" QgsProject.instance().clear() m = QgsMapLayerProxyModel() - l1 = QgsVectorLayer("Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - 'layer 1', "memory") + l1 = QgsVectorLayer( + "Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", + "layer 1", + "memory", + ) QgsProject.instance().addMapLayer(l1) - l2 = QgsVectorLayer("Polygon?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - 'layer 2', "memory") + l2 = QgsVectorLayer( + "Polygon?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", + "layer 2", + "memory", + ) QgsProject.instance().addMapLayer(l2) - l3 = QgsVectorLayer("None?field=fldtxt:string&field=fldint:integer", - 'layer 3', "memory") + l3 = QgsVectorLayer( + "None?field=fldtxt:string&field=fldint:integer", "layer 3", "memory" + ) QgsProject.instance().addMapLayer(l3) - l4 = QgsVectorLayer("LineString?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - 'layer 4', "memory") + l4 = QgsVectorLayer( + "LineString?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", + "layer 4", + "memory", + ) QgsProject.instance().addMapLayer(l4) m.setFilters(Qgis.LayerFilter.PolygonLayer) self.assertEqual(m.rowCount(), 1) - self.assertEqual(m.data(m.index(0, 0)), 'layer 2') + self.assertEqual(m.data(m.index(0, 0)), "layer 2") self.assertFalse(m.acceptsLayer(l1)) self.assertTrue(m.acceptsLayer(l2)) @@ -144,7 +165,7 @@ def testFilterGeometryType(self): m.setFilters(Qgis.LayerFilter.PointLayer) self.assertEqual(m.rowCount(), 1) - self.assertEqual(m.data(m.index(0, 0)), 'layer 1') + self.assertEqual(m.data(m.index(0, 0)), "layer 1") self.assertTrue(m.acceptsLayer(l1)) self.assertFalse(m.acceptsLayer(l2)) @@ -153,7 +174,7 @@ def testFilterGeometryType(self): m.setFilters(Qgis.LayerFilter.LineLayer) self.assertEqual(m.rowCount(), 1) - self.assertEqual(m.data(m.index(0, 0)), 'layer 4') + self.assertEqual(m.data(m.index(0, 0)), "layer 4") self.assertFalse(m.acceptsLayer(l1)) self.assertFalse(m.acceptsLayer(l2)) @@ -162,7 +183,7 @@ def testFilterGeometryType(self): m.setFilters(Qgis.LayerFilter.NoGeometry) self.assertEqual(m.rowCount(), 1) - self.assertEqual(m.data(m.index(0, 0)), 'layer 3') + self.assertEqual(m.data(m.index(0, 0)), "layer 3") self.assertFalse(m.acceptsLayer(l1)) self.assertFalse(m.acceptsLayer(l2)) @@ -171,9 +192,9 @@ def testFilterGeometryType(self): m.setFilters(Qgis.LayerFilter.HasGeometry) self.assertEqual(m.rowCount(), 3) - self.assertEqual(m.data(m.index(0, 0)), 'layer 1') - self.assertEqual(m.data(m.index(1, 0)), 'layer 2') - self.assertEqual(m.data(m.index(2, 0)), 'layer 4') + self.assertEqual(m.data(m.index(0, 0)), "layer 1") + self.assertEqual(m.data(m.index(1, 0)), "layer 2") + self.assertEqual(m.data(m.index(2, 0)), "layer 4") self.assertTrue(m.acceptsLayer(l1)) self.assertTrue(m.acceptsLayer(l2)) @@ -182,10 +203,10 @@ def testFilterGeometryType(self): m.setFilters(Qgis.LayerFilter.VectorLayer) self.assertEqual(m.rowCount(), 4) - self.assertEqual(m.data(m.index(0, 0)), 'layer 1') - self.assertEqual(m.data(m.index(1, 0)), 'layer 2') - self.assertEqual(m.data(m.index(2, 0)), 'layer 3') - self.assertEqual(m.data(m.index(3, 0)), 'layer 4') + self.assertEqual(m.data(m.index(0, 0)), "layer 1") + self.assertEqual(m.data(m.index(1, 0)), "layer 2") + self.assertEqual(m.data(m.index(2, 0)), "layer 3") + self.assertEqual(m.data(m.index(3, 0)), "layer 4") self.assertTrue(m.acceptsLayer(l1)) self.assertTrue(m.acceptsLayer(l2)) @@ -209,58 +230,78 @@ def testFilterGeometryType(self): self.assertFalse(m.acceptsLayer(l4)) def testFilterString(self): - """ test filtering by string""" + """test filtering by string""" QgsProject.instance().clear() m = QgsMapLayerProxyModel() - l1 = QgsVectorLayer("Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - 'layer 1', "memory") + l1 = QgsVectorLayer( + "Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", + "layer 1", + "memory", + ) QgsProject.instance().addMapLayer(l1) - l2 = QgsVectorLayer("Polygon?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - 'lAyEr 2', "memory") + l2 = QgsVectorLayer( + "Polygon?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", + "lAyEr 2", + "memory", + ) QgsProject.instance().addMapLayer(l2) - l3 = QgsVectorLayer("None?field=fldtxt:string&field=fldint:integer", - 'another', "memory") + l3 = QgsVectorLayer( + "None?field=fldtxt:string&field=fldint:integer", "another", "memory" + ) QgsProject.instance().addMapLayer(l3) - l4 = QgsVectorLayer("LineString?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - 'final layer', "memory") + l4 = QgsVectorLayer( + "LineString?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", + "final layer", + "memory", + ) QgsProject.instance().addMapLayer(l4) - m.setFilterString('layer') + m.setFilterString("layer") self.assertEqual(m.rowCount(), 3) - self.assertEqual(m.data(m.index(0, 0)), 'final layer') - self.assertEqual(m.data(m.index(1, 0)), 'layer 1') - self.assertEqual(m.data(m.index(2, 0)), 'lAyEr 2') + self.assertEqual(m.data(m.index(0, 0)), "final layer") + self.assertEqual(m.data(m.index(1, 0)), "layer 1") + self.assertEqual(m.data(m.index(2, 0)), "lAyEr 2") self.assertTrue(m.acceptsLayer(l1)) self.assertTrue(m.acceptsLayer(l2)) self.assertFalse(m.acceptsLayer(l3)) self.assertTrue(m.acceptsLayer(l4)) - m.setFilterString('') + m.setFilterString("") self.assertEqual(m.rowCount(), 4) def testFilterByLayer(self): - """ test filtering by layer""" + """test filtering by layer""" QgsProject.instance().clear() m = QgsMapLayerProxyModel() - l1 = QgsVectorLayer("Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - 'layer 1', "memory") + l1 = QgsVectorLayer( + "Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", + "layer 1", + "memory", + ) QgsProject.instance().addMapLayer(l1) - l2 = QgsVectorLayer("Polygon?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - 'lAyEr 2', "memory") + l2 = QgsVectorLayer( + "Polygon?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", + "lAyEr 2", + "memory", + ) QgsProject.instance().addMapLayer(l2) - l3 = QgsVectorLayer("None?field=fldtxt:string&field=fldint:integer", - 'another', "memory") + l3 = QgsVectorLayer( + "None?field=fldtxt:string&field=fldint:integer", "another", "memory" + ) QgsProject.instance().addMapLayer(l3) - l4 = QgsVectorLayer("LineString?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", - 'final layer', "memory") + l4 = QgsVectorLayer( + "LineString?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", + "final layer", + "memory", + ) QgsProject.instance().addMapLayer(l4) self.assertEqual(m.rowCount(), 4) - self.assertEqual(m.data(m.index(0, 0)), 'another') - self.assertEqual(m.data(m.index(1, 0)), 'final layer') - self.assertEqual(m.data(m.index(2, 0)), 'layer 1') - self.assertEqual(m.data(m.index(3, 0)), 'lAyEr 2') + self.assertEqual(m.data(m.index(0, 0)), "another") + self.assertEqual(m.data(m.index(1, 0)), "final layer") + self.assertEqual(m.data(m.index(2, 0)), "layer 1") + self.assertEqual(m.data(m.index(3, 0)), "lAyEr 2") self.assertTrue(m.acceptsLayer(l1)) self.assertTrue(m.acceptsLayer(l2)) @@ -269,8 +310,8 @@ def testFilterByLayer(self): m.setExceptedLayerList([l1, l3]) self.assertEqual(m.rowCount(), 2) - self.assertEqual(m.data(m.index(0, 0)), 'final layer') - self.assertEqual(m.data(m.index(1, 0)), 'lAyEr 2') + self.assertEqual(m.data(m.index(0, 0)), "final layer") + self.assertEqual(m.data(m.index(1, 0)), "lAyEr 2") self.assertFalse(m.acceptsLayer(l1)) self.assertTrue(m.acceptsLayer(l2)) @@ -279,8 +320,8 @@ def testFilterByLayer(self): m.setExceptedLayerIds([l2.id(), l4.id()]) self.assertEqual(m.rowCount(), 2) - self.assertEqual(m.data(m.index(0, 0)), 'another') - self.assertEqual(m.data(m.index(1, 0)), 'layer 1') + self.assertEqual(m.data(m.index(0, 0)), "another") + self.assertEqual(m.data(m.index(1, 0)), "layer 1") self.assertTrue(m.acceptsLayer(l1)) self.assertFalse(m.acceptsLayer(l2)) @@ -289,7 +330,7 @@ def testFilterByLayer(self): m.setLayerAllowlist([l1]) self.assertEqual(m.rowCount(), 1) - self.assertEqual(m.data(m.index(0, 0)), 'layer 1') + self.assertEqual(m.data(m.index(0, 0)), "layer 1") self.assertTrue(m.acceptsLayer(l1)) self.assertFalse(m.acceptsLayer(l2)) @@ -298,7 +339,7 @@ def testFilterByLayer(self): m.setExceptedLayerIds([]) self.assertEqual(m.rowCount(), 1) - self.assertEqual(m.data(m.index(0, 0)), 'layer 1') + self.assertEqual(m.data(m.index(0, 0)), "layer 1") self.assertTrue(m.acceptsLayer(l1)) self.assertFalse(m.acceptsLayer(l2)) @@ -307,8 +348,8 @@ def testFilterByLayer(self): m.setLayerAllowlist([l2, l3]) self.assertEqual(m.rowCount(), 2) - self.assertEqual(m.data(m.index(0, 0)), 'another') - self.assertEqual(m.data(m.index(1, 0)), 'lAyEr 2') + self.assertEqual(m.data(m.index(0, 0)), "another") + self.assertEqual(m.data(m.index(1, 0)), "lAyEr 2") self.assertFalse(m.acceptsLayer(l1)) self.assertTrue(m.acceptsLayer(l2)) @@ -324,5 +365,5 @@ def testFilterByLayer(self): self.assertTrue(m.acceptsLayer(l4)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmaplayerserverproperties.py b/tests/src/python/test_qgsmaplayerserverproperties.py index 060bc69eef80..e2ae9f8fe8fb 100644 --- a/tests/src/python/test_qgsmaplayerserverproperties.py +++ b/tests/src/python/test_qgsmaplayerserverproperties.py @@ -9,9 +9,9 @@ (at your option) any later version. """ -__author__ = 'Etienne Trimaille' -__date__ = '21/06/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' +__author__ = "Etienne Trimaille" +__date__ = "21/06/2021" +__copyright__ = "Copyright 2021, The QGIS Project" from qgis.core import QgsMapLayerServerProperties, QgsVectorLayer import unittest @@ -23,9 +23,9 @@ class TestQgsMapLayerServerConfig(QgisTestCase): def test_deprecated_function(self): - """ Test deprecated function about metadata url in QgsMapLayer. """ + """Test deprecated function about metadata url in QgsMapLayer.""" # Remove in QGIS 4.0 - layer = QgsVectorLayer('Point?field=fldtxt:string', 'layer_1', 'memory') + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer_1", "memory") self.assertEqual("", layer.metadataUrl()) self.assertEqual("", layer.metadataUrlType()) @@ -40,7 +40,9 @@ def test_deprecated_function(self): self.assertEqual(1, len(layer.serverProperties().metadataUrls())) # Access from server properties - self.assertEqual("https://my.other.url", layer.serverProperties().metadataUrls()[0].url) + self.assertEqual( + "https://my.other.url", layer.serverProperties().metadataUrls()[0].url + ) self.assertEqual("text/xml", layer.serverProperties().metadataUrls()[0].format) self.assertEqual("FGDC", layer.serverProperties().metadataUrls()[0].type) @@ -50,10 +52,12 @@ def test_deprecated_function(self): self.assertEqual("FGDC", layer.metadataUrlType()) def test_read_write(self): - """ Test read write the structure about metadata url. """ - layer = QgsVectorLayer('Point?field=fldtxt:string', 'layer_1', 'memory') + """Test read write the structure about metadata url.""" + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer_1", "memory") - url = QgsMapLayerServerProperties.MetadataUrl("https://my.url", "FGDC", "text/xml") + url = QgsMapLayerServerProperties.MetadataUrl( + "https://my.url", "FGDC", "text/xml" + ) self.assertEqual("https://my.url", url.url) self.assertEqual("text/xml", url.format) @@ -62,9 +66,13 @@ def test_read_write(self): layer.serverProperties().addMetadataUrl(url) self.assertEqual(1, len(layer.serverProperties().metadataUrls())) - self.assertEqual("https://my.url", layer.serverProperties().metadataUrls()[0].url) + self.assertEqual( + "https://my.url", layer.serverProperties().metadataUrls()[0].url + ) - replace_url = QgsMapLayerServerProperties.MetadataUrl("new.url", "FGDC", "text/xml") + replace_url = QgsMapLayerServerProperties.MetadataUrl( + "new.url", "FGDC", "text/xml" + ) properties = layer.serverProperties() properties.setMetadataUrls([replace_url]) @@ -72,20 +80,28 @@ def test_read_write(self): self.assertEqual("new.url", layer.serverProperties().metadataUrls()[0].url) def test_metadata_url(self): - """ Test the metadata url struct. """ - url = QgsMapLayerServerProperties.MetadataUrl("https://my.url", "FGDC", "text/xml") - - other = QgsMapLayerServerProperties.MetadataUrl("https://my.url", "FGDC", "text/html") + """Test the metadata url struct.""" + url = QgsMapLayerServerProperties.MetadataUrl( + "https://my.url", "FGDC", "text/xml" + ) + + other = QgsMapLayerServerProperties.MetadataUrl( + "https://my.url", "FGDC", "text/html" + ) self.assertFalse(url == other) - other = QgsMapLayerServerProperties.MetadataUrl("https://url", "FGDC", "text/xml") + other = QgsMapLayerServerProperties.MetadataUrl( + "https://url", "FGDC", "text/xml" + ) self.assertFalse(url == other) - other = QgsMapLayerServerProperties.MetadataUrl("https://my.url", "FGDC", "text/xml") + other = QgsMapLayerServerProperties.MetadataUrl( + "https://my.url", "FGDC", "text/xml" + ) self.assertTrue(url == other) def test_wfs_title(self): - layer = QgsVectorLayer('Point?field=fldtxt:string', 'layer_1', 'memory') + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer_1", "memory") self.assertEqual("", layer.title()) self.assertEqual("", layer.serverProperties().title()) @@ -112,5 +128,5 @@ def test_wfs_title(self): self.assertEqual("title2", layer.serverProperties().wfsTitle()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmaplayerstore.py b/tests/src/python/test_qgsmaplayerstore.py index 7ace94d978d4..3b58f346d16b 100644 --- a/tests/src/python/test_qgsmaplayerstore.py +++ b/tests/src/python/test_qgsmaplayerstore.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2017-05' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2017-05" +__copyright__ = "Copyright 2017, The QGIS Project" import os from time import sleep @@ -41,55 +42,55 @@ def setUp(self): pass def test_addMapLayer(self): - """ test adding individual map layers to store""" + """test adding individual map layers to store""" store = QgsMapLayerStore() - l1 = createLayer('test') + l1 = createLayer("test") self.assertEqual(store.addMapLayer(l1), l1) - self.assertEqual(len(store.mapLayersByName('test')), 1) + self.assertEqual(len(store.mapLayersByName("test")), 1) self.assertEqual(store.count(), 1) self.assertEqual(len(store), 1) # adding a second layer should leave existing layers intact - l2 = createLayer('test2') + l2 = createLayer("test2") self.assertEqual(store.addMapLayer(l2), l2) - self.assertEqual(len(store.mapLayersByName('test')), 1) - self.assertEqual(len(store.mapLayersByName('test2')), 1) + self.assertEqual(len(store.mapLayersByName("test")), 1) + self.assertEqual(len(store.mapLayersByName("test2")), 1) self.assertEqual(store.count(), 2) self.assertEqual(len(store), 2) def test_addMapLayerAlreadyAdded(self): - """ test that already added layers can't be readded to store """ + """test that already added layers can't be readded to store""" store = QgsMapLayerStore() - l1 = createLayer('test') + l1 = createLayer("test") store.addMapLayer(l1) - self.assertEqual(len(store.mapLayersByName('test')), 1) + self.assertEqual(len(store.mapLayersByName("test")), 1) self.assertEqual(store.count(), 1) self.assertEqual(store.addMapLayer(l1), None) - self.assertEqual(len(store.mapLayersByName('test')), 1) + self.assertEqual(len(store.mapLayersByName("test")), 1) self.assertEqual(store.count(), 1) self.assertEqual(len(store), 1) def test_addMapLayerInvalid(self): - """ test that invalid map layers can't be added to store """ + """test that invalid map layers can't be added to store""" store = QgsMapLayerStore() - vl = QgsVectorLayer("Point?field=x:string", 'test', "xxx") + vl = QgsVectorLayer("Point?field=x:string", "test", "xxx") self.assertEqual(store.addMapLayer(vl), vl) - self.assertEqual(len(store.mapLayersByName('test')), 1) + self.assertEqual(len(store.mapLayersByName("test")), 1) self.assertEqual(store.count(), 1) self.assertEqual(store.validCount(), 0) def test_addMapLayerSignals(self): - """ test that signals are correctly emitted when adding map layer""" + """test that signals are correctly emitted when adding map layer""" store = QgsMapLayerStore() layer_was_added_spy = QSignalSpy(store.layerWasAdded) layers_added_spy = QSignalSpy(store.layersAdded) - l1 = createLayer('test') + l1 = createLayer("test") store.addMapLayer(l1) # can't seem to actually test the data which was emitted, so best we can do is test @@ -97,7 +98,7 @@ def test_addMapLayerSignals(self): self.assertEqual(len(layer_was_added_spy), 1) self.assertEqual(len(layers_added_spy), 1) - store.addMapLayer(createLayer('test2')) + store.addMapLayer(createLayer("test2")) self.assertEqual(len(layer_was_added_spy), 2) self.assertEqual(len(layers_added_spy), 2) @@ -108,59 +109,59 @@ def test_addMapLayerSignals(self): self.assertEqual(len(layers_added_spy), 2) def test_addMapLayers(self): - """ test adding multiple map layers to store """ + """test adding multiple map layers to store""" store = QgsMapLayerStore() - l1 = createLayer('test') - l2 = createLayer('test2') + l1 = createLayer("test") + l2 = createLayer("test2") self.assertEqual(set(store.addMapLayers([l1, l2])), {l1, l2}) - self.assertEqual(len(store.mapLayersByName('test')), 1) - self.assertEqual(len(store.mapLayersByName('test2')), 1) + self.assertEqual(len(store.mapLayersByName("test")), 1) + self.assertEqual(len(store.mapLayersByName("test2")), 1) self.assertEqual(store.count(), 2) # adding more layers should leave existing layers intact - l3 = createLayer('test3') - l4 = createLayer('test4') + l3 = createLayer("test3") + l4 = createLayer("test4") self.assertEqual(set(store.addMapLayers([l3, l4])), {l3, l4}) - self.assertEqual(len(store.mapLayersByName('test')), 1) - self.assertEqual(len(store.mapLayersByName('test2')), 1) - self.assertEqual(len(store.mapLayersByName('test3')), 1) - self.assertEqual(len(store.mapLayersByName('test4')), 1) + self.assertEqual(len(store.mapLayersByName("test")), 1) + self.assertEqual(len(store.mapLayersByName("test2")), 1) + self.assertEqual(len(store.mapLayersByName("test3")), 1) + self.assertEqual(len(store.mapLayersByName("test4")), 1) self.assertEqual(store.count(), 4) store.removeAllMapLayers() def test_addMapLayersInvalid(self): - """ test that invalid map layers can be added to store """ + """test that invalid map layers can be added to store""" store = QgsMapLayerStore() - vl = QgsVectorLayer("Point?field=x:string", 'test', "xxx") + vl = QgsVectorLayer("Point?field=x:string", "test", "xxx") self.assertEqual(store.addMapLayers([vl]), [vl]) - self.assertEqual(len(store.mapLayersByName('test')), 1) + self.assertEqual(len(store.mapLayersByName("test")), 1) self.assertEqual(store.count(), 1) self.assertEqual(store.validCount(), 0) def test_addMapLayersAlreadyAdded(self): - """ test that already added layers can't be readded to store """ + """test that already added layers can't be readded to store""" store = QgsMapLayerStore() - l1 = createLayer('test') + l1 = createLayer("test") self.assertEqual(store.addMapLayers([l1]), [l1]) - self.assertEqual(len(store.mapLayersByName('test')), 1) + self.assertEqual(len(store.mapLayersByName("test")), 1) self.assertEqual(store.count(), 1) self.assertEqual(store.addMapLayers([l1]), []) - self.assertEqual(len(store.mapLayersByName('test')), 1) + self.assertEqual(len(store.mapLayersByName("test")), 1) self.assertEqual(store.count(), 1) def test_addMapLayersSignals(self): - """ test that signals are correctly emitted when adding map layers""" + """test that signals are correctly emitted when adding map layers""" store = QgsMapLayerStore() layer_was_added_spy = QSignalSpy(store.layerWasAdded) layers_added_spy = QSignalSpy(store.layersAdded) - l1 = createLayer('test') - l2 = createLayer('test2') + l1 = createLayer("test") + l2 = createLayer("test2") store.addMapLayers([l1, l2]) # can't seem to actually test the data which was emitted, so best we can do is test @@ -168,7 +169,7 @@ def test_addMapLayersSignals(self): self.assertEqual(len(layer_was_added_spy), 2) self.assertEqual(len(layers_added_spy), 1) - store.addMapLayers([createLayer('test3'), createLayer('test4')]) + store.addMapLayers([createLayer("test3"), createLayer("test4")]) self.assertEqual(len(layer_was_added_spy), 4) self.assertEqual(len(layers_added_spy), 2) @@ -179,81 +180,81 @@ def test_addMapLayersSignals(self): self.assertEqual(len(layers_added_spy), 2) def test_mapLayerById(self): - """ test retrieving map layer by ID """ + """test retrieving map layer by ID""" store = QgsMapLayerStore() # test no crash with empty store - self.assertEqual(store.mapLayer('bad'), None) + self.assertEqual(store.mapLayer("bad"), None) self.assertEqual(store.mapLayer(None), None) - l1 = createLayer('test') - l2 = createLayer('test2') + l1 = createLayer("test") + l2 = createLayer("test2") store.addMapLayers([l1, l2]) - self.assertEqual(store.mapLayer('bad'), None) + self.assertEqual(store.mapLayer("bad"), None) self.assertEqual(store.mapLayer(None), None) self.assertEqual(store.mapLayer(l1.id()), l1) self.assertEqual(store.mapLayer(l2.id()), l2) def test_mapLayersByName(self): - """ test retrieving map layer by name """ + """test retrieving map layer by name""" store = QgsMapLayerStore() # test no crash with empty store - self.assertEqual(store.mapLayersByName('bad'), []) + self.assertEqual(store.mapLayersByName("bad"), []) self.assertEqual(store.mapLayersByName(None), []) - l1 = createLayer('test') - l2 = createLayer('test2') + l1 = createLayer("test") + l2 = createLayer("test2") store.addMapLayers([l1, l2]) - self.assertEqual(store.mapLayersByName('bad'), []) + self.assertEqual(store.mapLayersByName("bad"), []) self.assertEqual(store.mapLayersByName(None), []) - self.assertEqual(store.mapLayersByName('test'), [l1]) - self.assertEqual(store.mapLayersByName('test2'), [l2]) + self.assertEqual(store.mapLayersByName("test"), [l1]) + self.assertEqual(store.mapLayersByName("test2"), [l2]) # duplicate name # little bit of a hack - we don't want a duplicate ID and since IDs are currently based on time we wait a bit here sleep(0.1) - l3 = createLayer('test') + l3 = createLayer("test") store.addMapLayer(l3) - self.assertEqual(set(store.mapLayersByName('test')), {l1, l3}) + self.assertEqual(set(store.mapLayersByName("test")), {l1, l3}) def test_mapLayers(self): - """ test retrieving map layers list """ + """test retrieving map layers list""" store = QgsMapLayerStore() # test no crash with empty store self.assertEqual(store.mapLayers(), {}) - l1 = createLayer('test') - l2 = createLayer('test2') + l1 = createLayer("test") + l2 = createLayer("test2") store.addMapLayers([l1, l2]) self.assertEqual(store.mapLayers(), {l1.id(): l1, l2.id(): l2}) def test_removeMapLayersById(self): - """ test removing map layers by ID """ + """test removing map layers by ID""" store = QgsMapLayerStore() # test no crash with empty store - store.removeMapLayersById(['bad']) + store.removeMapLayersById(["bad"]) store.removeMapLayersById([None]) - l1 = createLayer('test') - l2 = createLayer('test2') - l3 = createLayer('test3') + l1 = createLayer("test") + l2 = createLayer("test2") + l3 = createLayer("test3") store.addMapLayers([l1, l2, l3]) self.assertEqual(store.count(), 3) # remove bad layers - store.removeMapLayersById(['bad']) + store.removeMapLayersById(["bad"]) self.assertEqual(store.count(), 3) store.removeMapLayersById([None]) self.assertEqual(store.count(), 3) @@ -275,20 +276,20 @@ def test_removeMapLayersById(self): self.assertTrue(sip.isdeleted(l2)) # try removing a layer not in the store - l4 = createLayer('test4') + l4 = createLayer("test4") store.removeMapLayersById([l4.id()]) self.assertFalse(sip.isdeleted(l4)) def test_removeMapLayersByLayer(self): - """ test removing map layers by layer""" + """test removing map layers by layer""" store = QgsMapLayerStore() # test no crash with empty store store.removeMapLayers([None]) - l1 = createLayer('test') - l2 = createLayer('test2') - l3 = createLayer('test3') + l1 = createLayer("test") + l2 = createLayer("test2") + l3 = createLayer("test3") store.addMapLayers([l1, l2, l3]) self.assertEqual(store.count(), 3) @@ -311,21 +312,21 @@ def test_removeMapLayersByLayer(self): self.assertTrue(sip.isdeleted(l3)) def test_removeMapLayerById(self): - """ test removing a map layer by ID """ + """test removing a map layer by ID""" store = QgsMapLayerStore() # test no crash with empty store - store.removeMapLayer('bad') + store.removeMapLayer("bad") store.removeMapLayer(None) - l1 = createLayer('test') - l2 = createLayer('test2') + l1 = createLayer("test") + l2 = createLayer("test2") store.addMapLayers([l1, l2]) self.assertEqual(store.count(), 2) # remove bad layers - store.removeMapLayer('bad') + store.removeMapLayer("bad") self.assertEqual(store.count(), 2) store.removeMapLayer(None) self.assertEqual(store.count(), 2) @@ -347,20 +348,20 @@ def test_removeMapLayerById(self): self.assertTrue(sip.isdeleted(l2)) # try removing a layer not in the store - l3 = createLayer('test3') + l3 = createLayer("test3") store.removeMapLayer(l3.id()) self.assertFalse(sip.isdeleted(l3)) def test_removeMapLayerByLayer(self): - """ test removing a map layer by layer """ + """test removing a map layer by layer""" store = QgsMapLayerStore() # test no crash with empty store - store.removeMapLayer('bad') + store.removeMapLayer("bad") store.removeMapLayer(None) - l1 = createLayer('test') - l2 = createLayer('test2') + l1 = createLayer("test") + l2 = createLayer("test2") store.addMapLayers([l1, l2]) self.assertEqual(store.count(), 2) @@ -368,7 +369,7 @@ def test_removeMapLayerByLayer(self): # remove bad layers store.removeMapLayer(None) self.assertEqual(store.count(), 2) - l3 = createLayer('test3') + l3 = createLayer("test3") store.removeMapLayer(l3) self.assertEqual(store.count(), 2) @@ -385,38 +386,40 @@ def test_removeMapLayerByLayer(self): self.assertTrue(sip.isdeleted(l2)) # try removing a layer not in the store - l3 = createLayer('test3') + l3 = createLayer("test3") store.removeMapLayer(l3) self.assertFalse(sip.isdeleted(l3)) def test_removeAllMapLayers(self): - """ test removing all map layers from store """ + """test removing all map layers from store""" store = QgsMapLayerStore() - l1 = createLayer('test') - l2 = createLayer('test2') + l1 = createLayer("test") + l2 = createLayer("test2") store.addMapLayers([l1, l2]) self.assertEqual(store.count(), 2) store.removeAllMapLayers() self.assertEqual(store.count(), 0) - self.assertEqual(store.mapLayersByName('test'), []) - self.assertEqual(store.mapLayersByName('test2'), []) + self.assertEqual(store.mapLayersByName("test"), []) + self.assertEqual(store.mapLayersByName("test2"), []) def test_addRemoveLayersSignals(self): - """ test that signals are correctly emitted when removing map layers""" + """test that signals are correctly emitted when removing map layers""" store = QgsMapLayerStore() layers_will_be_removed_spy = QSignalSpy(store.layersWillBeRemoved) layer_will_be_removed_spy_str = QSignalSpy(store.layerWillBeRemoved[str]) - layer_will_be_removed_spy_layer = QSignalSpy(store.layerWillBeRemoved[QgsMapLayer]) + layer_will_be_removed_spy_layer = QSignalSpy( + store.layerWillBeRemoved[QgsMapLayer] + ) layers_removed_spy = QSignalSpy(store.layersRemoved) layer_removed_spy = QSignalSpy(store.layerRemoved) remove_all_spy = QSignalSpy(store.allLayersRemoved) - l1 = createLayer('l1') - l2 = createLayer('l2') - l3 = createLayer('l3') - l4 = createLayer('l4') + l1 = createLayer("l1") + l2 = createLayer("l2") + l3 = createLayer("l3") + l4 = createLayer("l4") store.addMapLayers([l1, l2, l3, l4]) # remove 1 layer @@ -451,7 +454,7 @@ def test_addRemoveLayersSignals(self): self.assertEqual(len(remove_all_spy), 1) # remove some layers which aren't in the store - store.removeMapLayersById(['asdasd']) + store.removeMapLayersById(["asdasd"]) self.assertEqual(len(layers_will_be_removed_spy), 3) self.assertEqual(len(layer_will_be_removed_spy_str), 4) self.assertEqual(len(layer_will_be_removed_spy_layer), 4) @@ -459,7 +462,7 @@ def test_addRemoveLayersSignals(self): self.assertEqual(len(layer_removed_spy), 4) self.assertEqual(len(remove_all_spy), 1) - l5 = createLayer('test5') + l5 = createLayer("test5") store.removeMapLayer(l5) self.assertEqual(len(layers_will_be_removed_spy), 3) self.assertEqual(len(layer_will_be_removed_spy_str), 4) @@ -472,17 +475,17 @@ def test_RemoveLayerShouldNotSegFault(self): store = QgsMapLayerStore() # Should not segfault - store.removeMapLayersById(['not_exists']) - store.removeMapLayer('not_exists2') + store.removeMapLayersById(["not_exists"]) + store.removeMapLayer("not_exists2") # check also that the removal of an unexistent layer does not insert a null layer for k, layer in list(store.mapLayers().items()): - assert (layer is not None) + assert layer is not None def testTakeLayer(self): # test taking ownership of a layer from the store - l1 = createLayer('l1') - l2 = createLayer('l2') + l1 = createLayer("l1") + l2 = createLayer("l2") store = QgsMapLayerStore() # add one layer to store @@ -520,12 +523,12 @@ def testTransferLayers(self): store1.transferLayersFromStore(None) store1.transferLayersFromStore(store1) - l1 = createLayer('l1') - l2 = createLayer('l2') + l1 = createLayer("l1") + l2 = createLayer("l2") store1.addMapLayer(l1) store1.addMapLayer(l2) - l3 = createLayer('l3') + l3 = createLayer("l3") store2.addMapLayer(l3) store2.transferLayersFromStore(store1) @@ -545,8 +548,8 @@ def testLayerDataSourceReset(self): p = QgsProject() store = p.layerStore() - vl1 = createLayer('valid') - vl2 = QgsVectorLayer('/not_a_valid_path.shp', 'invalid', 'ogr') + vl1 = createLayer("valid") + vl2 = QgsVectorLayer("/not_a_valid_path.shp", "invalid", "ogr") self.assertTrue(vl1.isValid()) self.assertFalse(vl2.isValid()) store.addMapLayers([vl1, vl2]) @@ -560,17 +563,20 @@ def testLayerDataSourceReset(self): doc = QDomDocument() doc.setContent( - f'ogrfixed{vl2.id()}') + f'ogrfixed{vl2.id()}' + ) layer_node = QDomNode(doc.firstChild()) self.assertTrue(vl2.writeXml(layer_node, doc, QgsReadWriteContext())) datasource_node = doc.createElement("datasource") - datasource_node.appendChild(doc.createTextNode(os.path.join(TEST_DATA_DIR, 'points.shp'))) + datasource_node.appendChild( + doc.createTextNode(os.path.join(TEST_DATA_DIR, "points.shp")) + ) layer_node.appendChild(datasource_node) p.readLayer(layer_node) self.assertEqual(store.validCount(), 2) self.assertEqual(len(store.mapLayers()), 2) - self.assertEqual(store.mapLayers()[vl2.id()].name(), 'fixed') + self.assertEqual(store.mapLayers()[vl2.id()].name(), "fixed") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmaplayerutils.py b/tests/src/python/test_qgsmaplayerutils.py index 51c471214a2d..3046600cedef 100644 --- a/tests/src/python/test_qgsmaplayerutils.py +++ b/tests/src/python/test_qgsmaplayerutils.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2021-05' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2021-05" +__copyright__ = "Copyright 2021, The QGIS Project" from qgis.core import ( @@ -32,133 +33,255 @@ class TestQgsMapLayerUtils(QgisTestCase): def testCombinedExtent(self): - extent = QgsMapLayerUtils.combinedExtent([], QgsCoordinateReferenceSystem(), QgsCoordinateTransformContext()) + extent = QgsMapLayerUtils.combinedExtent( + [], QgsCoordinateReferenceSystem(), QgsCoordinateTransformContext() + ) self.assertTrue(extent.isEmpty()) - layer1 = QgsVectorLayer(unitTestDataPath() + '/points.shp', 'l1') + layer1 = QgsVectorLayer(unitTestDataPath() + "/points.shp", "l1") self.assertTrue(layer1.isValid()) # one layer - extent = QgsMapLayerUtils.combinedExtent([layer1], QgsCoordinateReferenceSystem(), QgsCoordinateTransformContext()) - self.assertEqual(extent.toString(3), '-118.889,22.800 : -83.333,46.872') + extent = QgsMapLayerUtils.combinedExtent( + [layer1], QgsCoordinateReferenceSystem(), QgsCoordinateTransformContext() + ) + self.assertEqual(extent.toString(3), "-118.889,22.800 : -83.333,46.872") - extent = QgsMapLayerUtils.combinedExtent([layer1], QgsCoordinateReferenceSystem('EPSG:4326'), - QgsCoordinateTransformContext()) - self.assertEqual(extent.toString(3), '-118.889,22.800 : -83.333,46.872') - extent = QgsMapLayerUtils.combinedExtent([layer1], QgsCoordinateReferenceSystem('EPSG:3857'), - QgsCoordinateTransformContext()) - self.assertEqual(extent.toString(0), '-13234651,2607875 : -9276624,5921203') + extent = QgsMapLayerUtils.combinedExtent( + [layer1], + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateTransformContext(), + ) + self.assertEqual(extent.toString(3), "-118.889,22.800 : -83.333,46.872") + extent = QgsMapLayerUtils.combinedExtent( + [layer1], + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsCoordinateTransformContext(), + ) + self.assertEqual(extent.toString(0), "-13234651,2607875 : -9276624,5921203") # two layers - layer2 = QgsRasterLayer(unitTestDataPath() + '/landsat-f32-b1.tif', 'l2') + layer2 = QgsRasterLayer(unitTestDataPath() + "/landsat-f32-b1.tif", "l2") self.assertTrue(layer2.isValid()) - extent = QgsMapLayerUtils.combinedExtent([layer1, layer2], QgsCoordinateReferenceSystem('EPSG:4326'), - QgsCoordinateTransformContext()) - self.assertEqual(extent.toString(3), '-118.889,22.800 : 18.046,46.872') - extent = QgsMapLayerUtils.combinedExtent([layer2, layer1], QgsCoordinateReferenceSystem('EPSG:4326'), - QgsCoordinateTransformContext()) - self.assertEqual(extent.toString(3), '-118.889,22.800 : 18.046,46.872') - extent = QgsMapLayerUtils.combinedExtent([layer1, layer2], QgsCoordinateReferenceSystem('EPSG:3857'), - QgsCoordinateTransformContext()) - self.assertEqual(extent.toString(0), '-13234651,2607875 : 2008833,5921203') - extent = QgsMapLayerUtils.combinedExtent([layer2, layer1], QgsCoordinateReferenceSystem('EPSG:3857'), - QgsCoordinateTransformContext()) - self.assertEqual(extent.toString(0), '-13234651,2607875 : 2008833,5921203') + extent = QgsMapLayerUtils.combinedExtent( + [layer1, layer2], + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateTransformContext(), + ) + self.assertEqual(extent.toString(3), "-118.889,22.800 : 18.046,46.872") + extent = QgsMapLayerUtils.combinedExtent( + [layer2, layer1], + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateTransformContext(), + ) + self.assertEqual(extent.toString(3), "-118.889,22.800 : 18.046,46.872") + extent = QgsMapLayerUtils.combinedExtent( + [layer1, layer2], + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsCoordinateTransformContext(), + ) + self.assertEqual(extent.toString(0), "-13234651,2607875 : 2008833,5921203") + extent = QgsMapLayerUtils.combinedExtent( + [layer2, layer1], + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsCoordinateTransformContext(), + ) + self.assertEqual(extent.toString(0), "-13234651,2607875 : 2008833,5921203") def test_layerSourceMatchesPath(self): """ Test QgsMapLayerUtils.layerSourceMatchesPath() """ - self.assertFalse(QgsMapLayerUtils.layerSourceMatchesPath(None, '')) - self.assertFalse(QgsMapLayerUtils.layerSourceMatchesPath(None, 'aaaaa')) + self.assertFalse(QgsMapLayerUtils.layerSourceMatchesPath(None, "")) + self.assertFalse(QgsMapLayerUtils.layerSourceMatchesPath(None, "aaaaa")) # shapefile - layer1 = QgsVectorLayer(unitTestDataPath() + '/points.shp', 'l1') - self.assertFalse(QgsMapLayerUtils.layerSourceMatchesPath(layer1, '')) - self.assertFalse(QgsMapLayerUtils.layerSourceMatchesPath(layer1, 'aaaaa')) - self.assertTrue(QgsMapLayerUtils.layerSourceMatchesPath(layer1, unitTestDataPath() + '/points.shp')) + layer1 = QgsVectorLayer(unitTestDataPath() + "/points.shp", "l1") + self.assertFalse(QgsMapLayerUtils.layerSourceMatchesPath(layer1, "")) + self.assertFalse(QgsMapLayerUtils.layerSourceMatchesPath(layer1, "aaaaa")) + self.assertTrue( + QgsMapLayerUtils.layerSourceMatchesPath( + layer1, unitTestDataPath() + "/points.shp" + ) + ) # geopackage with layers - layer1 = QgsVectorLayer(unitTestDataPath() + '/mixed_layers.gpkg|layername=lines', 'l1') - self.assertFalse(QgsMapLayerUtils.layerSourceMatchesPath(layer1, '')) - self.assertFalse(QgsMapLayerUtils.layerSourceMatchesPath(layer1, 'aaaaa')) - self.assertTrue(QgsMapLayerUtils.layerSourceMatchesPath(layer1, unitTestDataPath() + '/mixed_layers.gpkg')) - layer2 = QgsVectorLayer(unitTestDataPath() + '/mixed_layers.gpkg|layername=points', 'l1') - self.assertTrue(QgsMapLayerUtils.layerSourceMatchesPath(layer2, unitTestDataPath() + '/mixed_layers.gpkg')) + layer1 = QgsVectorLayer( + unitTestDataPath() + "/mixed_layers.gpkg|layername=lines", "l1" + ) + self.assertFalse(QgsMapLayerUtils.layerSourceMatchesPath(layer1, "")) + self.assertFalse(QgsMapLayerUtils.layerSourceMatchesPath(layer1, "aaaaa")) + self.assertTrue( + QgsMapLayerUtils.layerSourceMatchesPath( + layer1, unitTestDataPath() + "/mixed_layers.gpkg" + ) + ) + layer2 = QgsVectorLayer( + unitTestDataPath() + "/mixed_layers.gpkg|layername=points", "l1" + ) + self.assertTrue( + QgsMapLayerUtils.layerSourceMatchesPath( + layer2, unitTestDataPath() + "/mixed_layers.gpkg" + ) + ) # raster layer from gpkg - rl = QgsRasterLayer(f'GPKG:{unitTestDataPath()}/mixed_layers.gpkg:band1') - self.assertFalse(QgsMapLayerUtils.layerSourceMatchesPath(rl, '')) - self.assertFalse(QgsMapLayerUtils.layerSourceMatchesPath(rl, 'aaaaa')) - self.assertTrue(QgsMapLayerUtils.layerSourceMatchesPath(rl, unitTestDataPath() + '/mixed_layers.gpkg')) + rl = QgsRasterLayer(f"GPKG:{unitTestDataPath()}/mixed_layers.gpkg:band1") + self.assertFalse(QgsMapLayerUtils.layerSourceMatchesPath(rl, "")) + self.assertFalse(QgsMapLayerUtils.layerSourceMatchesPath(rl, "aaaaa")) + self.assertTrue( + QgsMapLayerUtils.layerSourceMatchesPath( + rl, unitTestDataPath() + "/mixed_layers.gpkg" + ) + ) def test_updateLayerSourcePath(self): """ Test QgsMapLayerUtils.updateLayerSourcePath() """ - self.assertFalse(QgsMapLayerUtils.updateLayerSourcePath(None, '')) - self.assertFalse(QgsMapLayerUtils.updateLayerSourcePath(None, 'aaaaa')) + self.assertFalse(QgsMapLayerUtils.updateLayerSourcePath(None, "")) + self.assertFalse(QgsMapLayerUtils.updateLayerSourcePath(None, "aaaaa")) # shapefile - layer1 = QgsVectorLayer(unitTestDataPath() + '/points.shp', 'l1') - self.assertTrue(QgsMapLayerUtils.updateLayerSourcePath(layer1, unitTestDataPath() + '/points22.shp')) - self.assertEqual(layer1.source(), unitTestDataPath() + '/points22.shp') + layer1 = QgsVectorLayer(unitTestDataPath() + "/points.shp", "l1") + self.assertTrue( + QgsMapLayerUtils.updateLayerSourcePath( + layer1, unitTestDataPath() + "/points22.shp" + ) + ) + self.assertEqual(layer1.source(), unitTestDataPath() + "/points22.shp") # geopackage with layers - layer1 = QgsVectorLayer(unitTestDataPath() + '/mixed_layers.gpkg|layername=lines', 'l1') - self.assertTrue(QgsMapLayerUtils.updateLayerSourcePath(layer1, unitTestDataPath() + '/mixed_layers22.gpkg')) - self.assertEqual(layer1.source(), unitTestDataPath() + '/mixed_layers22.gpkg|layername=lines') - layer2 = QgsVectorLayer(unitTestDataPath() + '/mixed_layers.gpkg|layername=points', 'l1') - self.assertTrue(QgsMapLayerUtils.updateLayerSourcePath(layer2, unitTestDataPath() + '/mixed_layers22.gpkg')) - self.assertEqual(layer2.source(), unitTestDataPath() + '/mixed_layers22.gpkg|layername=points') + layer1 = QgsVectorLayer( + unitTestDataPath() + "/mixed_layers.gpkg|layername=lines", "l1" + ) + self.assertTrue( + QgsMapLayerUtils.updateLayerSourcePath( + layer1, unitTestDataPath() + "/mixed_layers22.gpkg" + ) + ) + self.assertEqual( + layer1.source(), unitTestDataPath() + "/mixed_layers22.gpkg|layername=lines" + ) + layer2 = QgsVectorLayer( + unitTestDataPath() + "/mixed_layers.gpkg|layername=points", "l1" + ) + self.assertTrue( + QgsMapLayerUtils.updateLayerSourcePath( + layer2, unitTestDataPath() + "/mixed_layers22.gpkg" + ) + ) + self.assertEqual( + layer2.source(), + unitTestDataPath() + "/mixed_layers22.gpkg|layername=points", + ) # raster layer from gpkg - rl = QgsRasterLayer(f'GPKG:{unitTestDataPath()}/mixed_layers.gpkg:band1') - self.assertTrue(QgsMapLayerUtils.updateLayerSourcePath(rl, unitTestDataPath() + '/mixed_layers22.gpkg')) - self.assertEqual(rl.source(), f'GPKG:{unitTestDataPath()}/mixed_layers22.gpkg:band1') + rl = QgsRasterLayer(f"GPKG:{unitTestDataPath()}/mixed_layers.gpkg:band1") + self.assertTrue( + QgsMapLayerUtils.updateLayerSourcePath( + rl, unitTestDataPath() + "/mixed_layers22.gpkg" + ) + ) + self.assertEqual( + rl.source(), f"GPKG:{unitTestDataPath()}/mixed_layers22.gpkg:band1" + ) # a layer from a provider which doesn't use file based paths - layer = QgsVectorLayer("Point?field=x:string", 'my layer', "memory") + layer = QgsVectorLayer("Point?field=x:string", "my layer", "memory") old_source = layer.source() self.assertTrue(layer.isValid()) - self.assertFalse(QgsMapLayerUtils.updateLayerSourcePath(layer, unitTestDataPath() + '/mixed_layers22.gpkg')) + self.assertFalse( + QgsMapLayerUtils.updateLayerSourcePath( + layer, unitTestDataPath() + "/mixed_layers22.gpkg" + ) + ) self.assertEqual(layer.source(), old_source) def test_sort_layers_by_type(self): - vl1 = QgsVectorLayer("Point?field=x:string", 'vector 1', "memory") - vl2 = QgsVectorLayer("Point?field=x:string", 'vector 2', "memory") - options = QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()) - al1 = QgsAnnotationLayer('annotations 1', options) - al2 = QgsAnnotationLayer('annotations 2', options) - rl1 = QgsRasterLayer(f'GPKG:{unitTestDataPath()}/mixed_layers.gpkg:band1', 'raster 1') + vl1 = QgsVectorLayer("Point?field=x:string", "vector 1", "memory") + vl2 = QgsVectorLayer("Point?field=x:string", "vector 2", "memory") + options = QgsAnnotationLayer.LayerOptions( + QgsProject.instance().transformContext() + ) + al1 = QgsAnnotationLayer("annotations 1", options) + al2 = QgsAnnotationLayer("annotations 2", options) + rl1 = QgsRasterLayer( + f"GPKG:{unitTestDataPath()}/mixed_layers.gpkg:band1", "raster 1" + ) options = QgsGroupLayer.LayerOptions(QgsProject.instance().transformContext()) - gp1 = QgsGroupLayer('group 1', options) - - self.assertEqual(QgsMapLayerUtils.sortLayersByType([vl1, rl1, gp1, vl2, al2, al1], []), [vl1, rl1, gp1, vl2, al2, al1]) - self.assertEqual(QgsMapLayerUtils.sortLayersByType([vl1, rl1, gp1, vl2, al2, al1], [QgsMapLayerType.VectorLayer]), [vl1, vl2, rl1, gp1, al2, al1]) - self.assertEqual(QgsMapLayerUtils.sortLayersByType([vl1, rl1, gp1, vl2, al2, al1], [QgsMapLayerType.RasterLayer, QgsMapLayerType.VectorLayer]), - [rl1, vl1, vl2, gp1, al2, al1]) - self.assertEqual(QgsMapLayerUtils.sortLayersByType([vl1, rl1, gp1, vl2, al2, al1], [QgsMapLayerType.GroupLayer, QgsMapLayerType.VectorLayer]), - [gp1, vl1, vl2, rl1, al2, al1]) - self.assertEqual(QgsMapLayerUtils.sortLayersByType([vl1, rl1, gp1, vl2, al2, al1], [QgsMapLayerType.GroupLayer, - QgsMapLayerType.VectorLayer, - QgsMapLayerType.AnnotationLayer]), - [gp1, vl1, vl2, al2, al1, rl1]) - self.assertEqual(QgsMapLayerUtils.sortLayersByType([vl1, rl1, gp1, vl2, al2, al1], [QgsMapLayerType.GroupLayer, - QgsMapLayerType.VectorLayer, - QgsMapLayerType.RasterLayer, - QgsMapLayerType.AnnotationLayer]), - [gp1, vl1, vl2, rl1, al2, al1]) - self.assertEqual(QgsMapLayerUtils.sortLayersByType([vl1, rl1, gp1, vl2], [QgsMapLayerType.GroupLayer, - QgsMapLayerType.VectorLayer, - QgsMapLayerType.RasterLayer]), - [gp1, vl1, vl2, rl1]) - self.assertEqual(QgsMapLayerUtils.sortLayersByType([vl1, rl1, gp1, vl2], [QgsMapLayerType.AnnotationLayer]), - [vl1, rl1, gp1, vl2]) + gp1 = QgsGroupLayer("group 1", options) + + self.assertEqual( + QgsMapLayerUtils.sortLayersByType([vl1, rl1, gp1, vl2, al2, al1], []), + [vl1, rl1, gp1, vl2, al2, al1], + ) + self.assertEqual( + QgsMapLayerUtils.sortLayersByType( + [vl1, rl1, gp1, vl2, al2, al1], [QgsMapLayerType.VectorLayer] + ), + [vl1, vl2, rl1, gp1, al2, al1], + ) + self.assertEqual( + QgsMapLayerUtils.sortLayersByType( + [vl1, rl1, gp1, vl2, al2, al1], + [QgsMapLayerType.RasterLayer, QgsMapLayerType.VectorLayer], + ), + [rl1, vl1, vl2, gp1, al2, al1], + ) + self.assertEqual( + QgsMapLayerUtils.sortLayersByType( + [vl1, rl1, gp1, vl2, al2, al1], + [QgsMapLayerType.GroupLayer, QgsMapLayerType.VectorLayer], + ), + [gp1, vl1, vl2, rl1, al2, al1], + ) + self.assertEqual( + QgsMapLayerUtils.sortLayersByType( + [vl1, rl1, gp1, vl2, al2, al1], + [ + QgsMapLayerType.GroupLayer, + QgsMapLayerType.VectorLayer, + QgsMapLayerType.AnnotationLayer, + ], + ), + [gp1, vl1, vl2, al2, al1, rl1], + ) + self.assertEqual( + QgsMapLayerUtils.sortLayersByType( + [vl1, rl1, gp1, vl2, al2, al1], + [ + QgsMapLayerType.GroupLayer, + QgsMapLayerType.VectorLayer, + QgsMapLayerType.RasterLayer, + QgsMapLayerType.AnnotationLayer, + ], + ), + [gp1, vl1, vl2, rl1, al2, al1], + ) + self.assertEqual( + QgsMapLayerUtils.sortLayersByType( + [vl1, rl1, gp1, vl2], + [ + QgsMapLayerType.GroupLayer, + QgsMapLayerType.VectorLayer, + QgsMapLayerType.RasterLayer, + ], + ), + [gp1, vl1, vl2, rl1], + ) + self.assertEqual( + QgsMapLayerUtils.sortLayersByType( + [vl1, rl1, gp1, vl2], [QgsMapLayerType.AnnotationLayer] + ), + [vl1, rl1, gp1, vl2], + ) def test_launder_layer_name(self): - self.assertEqual(QgsMapLayerUtils.launderLayerName('abc Def4_a.h%'), 'abc_def4_ah') + self.assertEqual( + QgsMapLayerUtils.launderLayerName("abc Def4_a.h%"), "abc_def4_ah" + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmaprenderer.py b/tests/src/python/test_qgsmaprenderer.py index c44bb629c3bd..1074338c7024 100644 --- a/tests/src/python/test_qgsmaprenderer.py +++ b/tests/src/python/test_qgsmaprenderer.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '1/02/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "1/02/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from random import uniform @@ -41,8 +42,7 @@ def setUp(self): pass def checkRendererUseCachedLabels(self, job_type): - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") settings = QgsMapSettings() settings.setExtent(QgsRectangle(5, 25, 25, 45)) @@ -63,7 +63,7 @@ def checkRendererUseCachedLabels(self, job_type): job.start() job.waitForFinished() self.assertFalse(job.usedCachedLabels()) - self.assertTrue(cache.hasCacheImage('_labels_')) + self.assertTrue(cache.hasCacheImage("_labels_")) self.assertTrue(job.takeLabelingResults()) # second job should use label cache @@ -72,7 +72,7 @@ def checkRendererUseCachedLabels(self, job_type): job.start() job.waitForFinished() self.assertTrue(job.usedCachedLabels()) - self.assertTrue(cache.hasCacheImage('_labels_')) + self.assertTrue(cache.hasCacheImage("_labels_")) self.assertTrue(job.takeLabelingResults()) # one last run - no cache @@ -83,8 +83,7 @@ def checkRendererUseCachedLabels(self, job_type): self.assertTrue(job.takeLabelingResults()) def checkRepaintNonLabeledLayerDoesNotInvalidateLabelCache(self, job_type): - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") settings = QgsMapSettings() settings.setExtent(QgsRectangle(5, 25, 25, 45)) settings.setOutputSize(QSize(600, 400)) @@ -97,13 +96,13 @@ def checkRepaintNonLabeledLayerDoesNotInvalidateLabelCache(self, job_type): job.start() job.waitForFinished() self.assertFalse(job.usedCachedLabels()) - self.assertTrue(cache.hasCacheImage('_labels_')) + self.assertTrue(cache.hasCacheImage("_labels_")) self.assertTrue(cache.hasCacheImage(layer.id())) - self.assertEqual(cache.dependentLayers('_labels_'), []) + self.assertEqual(cache.dependentLayers("_labels_"), []) # trigger repaint on layer - should not invalidate label cache because layer is not labeled layer.triggerRepaint() - self.assertTrue(cache.hasCacheImage('_labels_')) + self.assertTrue(cache.hasCacheImage("_labels_")) self.assertFalse(cache.hasCacheImage(layer.id())) self.assertTrue(job.takeLabelingResults()) @@ -113,12 +112,11 @@ def checkRepaintNonLabeledLayerDoesNotInvalidateLabelCache(self, job_type): job.start() job.waitForFinished() self.assertTrue(job.usedCachedLabels()) - self.assertTrue(cache.hasCacheImage('_labels_')) + self.assertTrue(cache.hasCacheImage("_labels_")) self.assertTrue(job.takeLabelingResults()) def checkRepaintLabeledLayerInvalidatesLabelCache(self, job_type): - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") labelSettings = QgsPalLayerSettings() labelSettings.fieldName = "fldtxt" @@ -137,14 +135,14 @@ def checkRepaintLabeledLayerInvalidatesLabelCache(self, job_type): job.start() job.waitForFinished() self.assertFalse(job.usedCachedLabels()) - self.assertTrue(cache.hasCacheImage('_labels_')) + self.assertTrue(cache.hasCacheImage("_labels_")) self.assertTrue(job.takeLabelingResults()) - self.assertEqual(cache.dependentLayers('_labels_'), [layer]) + self.assertEqual(cache.dependentLayers("_labels_"), [layer]) # trigger repaint on layer - should invalidate cache and block use of cached labels layer.triggerRepaint() - self.assertFalse(cache.hasCacheImage('_labels_')) + self.assertFalse(cache.hasCacheImage("_labels_")) # second job should not use label cache, since layer was repainted job = job_type(settings) @@ -154,13 +152,12 @@ def checkRepaintLabeledLayerInvalidatesLabelCache(self, job_type): # shouldn't use cache self.assertFalse(job.usedCachedLabels()) # but results should have been cached - self.assertTrue(cache.hasCacheImage('_labels_')) + self.assertTrue(cache.hasCacheImage("_labels_")) self.assertTrue(job.takeLabelingResults()) def checkAddingNewLabeledLayerInvalidatesLabelCache(self, job_type): - """ adding a new labeled layer should invalidate any previous label caches""" - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + """adding a new labeled layer should invalidate any previous label caches""" + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") labelSettings = QgsPalLayerSettings() labelSettings.fieldName = "fldtxt" @@ -179,14 +176,13 @@ def checkAddingNewLabeledLayerInvalidatesLabelCache(self, job_type): job.start() job.waitForFinished() self.assertFalse(job.usedCachedLabels()) - self.assertTrue(cache.hasCacheImage('_labels_')) + self.assertTrue(cache.hasCacheImage("_labels_")) self.assertTrue(job.takeLabelingResults()) - self.assertEqual(cache.dependentLayers('_labels_'), [layer]) + self.assertEqual(cache.dependentLayers("_labels_"), [layer]) # add another labeled layer - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") layer2.setLabeling(QgsVectorLayerSimpleLabeling(labelSettings)) layer2.setLabelsEnabled(True) settings.setLayers([layer, layer2]) @@ -199,14 +195,13 @@ def checkAddingNewLabeledLayerInvalidatesLabelCache(self, job_type): # shouldn't use cache self.assertFalse(job.usedCachedLabels()) # but results should have been cached - self.assertTrue(cache.hasCacheImage('_labels_')) - self.assertEqual(set(cache.dependentLayers('_labels_')), {layer, layer2}) + self.assertTrue(cache.hasCacheImage("_labels_")) + self.assertEqual(set(cache.dependentLayers("_labels_")), {layer, layer2}) self.assertTrue(job.takeLabelingResults()) def checkAddingNewNonLabeledLayerKeepsLabelCache(self, job_type): - """ adding a new non-labeled layer should keep any previous label caches""" - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + """adding a new non-labeled layer should keep any previous label caches""" + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") labelSettings = QgsPalLayerSettings() labelSettings.fieldName = "fldtxt" @@ -225,14 +220,13 @@ def checkAddingNewNonLabeledLayerKeepsLabelCache(self, job_type): job.start() job.waitForFinished() self.assertFalse(job.usedCachedLabels()) - self.assertTrue(cache.hasCacheImage('_labels_')) + self.assertTrue(cache.hasCacheImage("_labels_")) self.assertTrue(job.takeLabelingResults()) - self.assertEqual(cache.dependentLayers('_labels_'), [layer]) + self.assertEqual(cache.dependentLayers("_labels_"), [layer]) # add another, non-labeled layer - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") settings.setLayers([layer, layer2]) # second job should use label cache, since new layer was not labeled @@ -243,22 +237,20 @@ def checkAddingNewNonLabeledLayerKeepsLabelCache(self, job_type): # should use cache self.assertTrue(job.usedCachedLabels()) # results should have been cached - self.assertTrue(cache.hasCacheImage('_labels_')) - self.assertEqual(set(cache.dependentLayers('_labels_')), {layer}) + self.assertTrue(cache.hasCacheImage("_labels_")) + self.assertEqual(set(cache.dependentLayers("_labels_")), {layer}) self.assertTrue(job.takeLabelingResults()) def checkRemovingLabeledLayerInvalidatesLabelCache(self, job_type): - """ removing a previously labeled layer should invalidate any previous label caches""" - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + """removing a previously labeled layer should invalidate any previous label caches""" + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") labelSettings = QgsPalLayerSettings() labelSettings.fieldName = "fldtxt" layer.setLabeling(QgsVectorLayerSimpleLabeling(labelSettings)) layer.setLabelsEnabled(True) - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") layer2.setLabeling(QgsVectorLayerSimpleLabeling(labelSettings)) layer2.setLabelsEnabled(True) @@ -274,10 +266,10 @@ def checkRemovingLabeledLayerInvalidatesLabelCache(self, job_type): job.start() job.waitForFinished() self.assertFalse(job.usedCachedLabels()) - self.assertTrue(cache.hasCacheImage('_labels_')) + self.assertTrue(cache.hasCacheImage("_labels_")) self.assertTrue(job.takeLabelingResults()) - self.assertEqual(set(cache.dependentLayers('_labels_')), {layer, layer2}) + self.assertEqual(set(cache.dependentLayers("_labels_")), {layer, layer2}) # remove a previously labeled layer settings.setLayers([layer2]) @@ -290,22 +282,20 @@ def checkRemovingLabeledLayerInvalidatesLabelCache(self, job_type): # shouldn't use cache self.assertFalse(job.usedCachedLabels()) # but results should have been cached - self.assertTrue(cache.hasCacheImage('_labels_')) - self.assertEqual(set(cache.dependentLayers('_labels_')), {layer2}) + self.assertTrue(cache.hasCacheImage("_labels_")) + self.assertEqual(set(cache.dependentLayers("_labels_")), {layer2}) self.assertTrue(job.takeLabelingResults()) def checkRemovingNonLabeledLayerKeepsLabelCache(self, job_type): - """ removing a previously used non-labeled layer should keep any previous label caches""" - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + """removing a previously used non-labeled layer should keep any previous label caches""" + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") labelSettings = QgsPalLayerSettings() labelSettings.fieldName = "fldtxt" layer.setLabeling(QgsVectorLayerSimpleLabeling(labelSettings)) layer.setLabelsEnabled(True) - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") settings = QgsMapSettings() settings.setExtent(QgsRectangle(5, 25, 25, 45)) @@ -319,10 +309,10 @@ def checkRemovingNonLabeledLayerKeepsLabelCache(self, job_type): job.start() job.waitForFinished() self.assertFalse(job.usedCachedLabels()) - self.assertTrue(cache.hasCacheImage('_labels_')) + self.assertTrue(cache.hasCacheImage("_labels_")) self.assertTrue(job.takeLabelingResults()) - self.assertEqual(set(cache.dependentLayers('_labels_')), {layer}) + self.assertEqual(set(cache.dependentLayers("_labels_")), {layer}) # remove a previously labeled layer settings.setLayers([layer]) @@ -335,22 +325,20 @@ def checkRemovingNonLabeledLayerKeepsLabelCache(self, job_type): # should use cache self.assertTrue(job.usedCachedLabels()) # results should have been cached - self.assertTrue(cache.hasCacheImage('_labels_')) - self.assertEqual(set(cache.dependentLayers('_labels_')), {layer}) + self.assertTrue(cache.hasCacheImage("_labels_")) + self.assertEqual(set(cache.dependentLayers("_labels_")), {layer}) self.assertTrue(job.takeLabelingResults()) def checkLabeledLayerWithBlendModesCannotBeCached(self, job_type): - """ any labeled layer utilising blending modes cannot be cached""" - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + """any labeled layer utilising blending modes cannot be cached""" + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") labelSettings = QgsPalLayerSettings() labelSettings.fieldName = "fldtxt" layer.setLabeling(QgsVectorLayerSimpleLabeling(labelSettings)) layer.setLabelsEnabled(True) - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") labelSettings2 = QgsPalLayerSettings() labelSettings2.fieldName = "fldtxt" format2 = QgsTextFormat() @@ -371,7 +359,7 @@ def checkLabeledLayerWithBlendModesCannotBeCached(self, job_type): job.start() job.waitForFinished() self.assertFalse(job.usedCachedLabels()) - self.assertFalse(cache.hasCacheImage('_labels_')) + self.assertFalse(cache.hasCacheImage("_labels_")) self.assertTrue(job.takeLabelingResults()) # second job should also not be able to use label cache @@ -382,13 +370,12 @@ def checkLabeledLayerWithBlendModesCannotBeCached(self, job_type): # shouldn't use cache self.assertFalse(job.usedCachedLabels()) # and results should not have been cached - self.assertFalse(cache.hasCacheImage('_labels_')) + self.assertFalse(cache.hasCacheImage("_labels_")) self.assertTrue(job.takeLabelingResults()) def checkCancel(self, job_type): """test canceling a render job""" - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") # add a ton of random points for i in range(2000): @@ -431,7 +418,7 @@ def checkCancel(self, job_type): self.assertEqual(len(finished_spy), 1) def runRendererChecks(self, renderer): - """ runs all checks on the specified renderer """ + """runs all checks on the specified renderer""" self.checkRendererUseCachedLabels(renderer) self.checkRepaintNonLabeledLayerDoesNotInvalidateLabelCache(renderer) self.checkRepaintLabeledLayerInvalidatesLabelCache(renderer) @@ -443,15 +430,15 @@ def runRendererChecks(self, renderer): self.checkCancel(renderer) def testParallelRenderer(self): - """ run test suite on QgsMapRendererParallelJob""" + """run test suite on QgsMapRendererParallelJob""" self.runRendererChecks(QgsMapRendererParallelJob) def testSequentialRenderer(self): - """ run test suite on QgsMapRendererSequentialJob""" + """run test suite on QgsMapRendererSequentialJob""" self.runRendererChecks(QgsMapRendererSequentialJob) def testCustomPainterRenderer(self): - """ run test suite on QgsMapRendererCustomPainterJob""" + """run test suite on QgsMapRendererCustomPainterJob""" im = QImage(200, 200, QImage.Format.Format_RGB32) p = QPainter(im) @@ -462,5 +449,5 @@ def create_job(settings): p.end() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmaprenderercache.py b/tests/src/python/test_qgsmaprenderercache.py index 840dee5a5152..2c76fb109d52 100644 --- a/tests/src/python/test_qgsmaprenderercache.py +++ b/tests/src/python/test_qgsmaprenderercache.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '1/02/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "1/02/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from time import sleep @@ -31,37 +32,37 @@ class TestQgsMapRendererCache(QgisTestCase): def testSetCacheImages(self): cache = QgsMapRendererCache() # not set image - im = cache.cacheImage('littlehands') + im = cache.cacheImage("littlehands") self.assertTrue(im.isNull()) - self.assertFalse(cache.hasCacheImage('littlehands')) + self.assertFalse(cache.hasCacheImage("littlehands")) # set image im = QImage(200, 200, QImage.Format.Format_RGB32) - cache.setCacheImage('littlehands', im) + cache.setCacheImage("littlehands", im) self.assertFalse(im.isNull()) - self.assertEqual(cache.cacheImage('littlehands'), im) - self.assertTrue(cache.hasCacheImage('littlehands')) + self.assertEqual(cache.cacheImage("littlehands"), im) + self.assertTrue(cache.hasCacheImage("littlehands")) # test another not set image when cache has images - self.assertTrue(cache.cacheImage('bad').isNull()) - self.assertFalse(cache.hasCacheImage('bad')) + self.assertTrue(cache.cacheImage("bad").isNull()) + self.assertFalse(cache.hasCacheImage("bad")) # clear cache image - cache.clearCacheImage('not in cache') # no crash! - cache.clearCacheImage('littlehands') - im = cache.cacheImage('littlehands') + cache.clearCacheImage("not in cache") # no crash! + cache.clearCacheImage("littlehands") + im = cache.cacheImage("littlehands") self.assertTrue(im.isNull()) - self.assertFalse(cache.hasCacheImage('littlehands')) + self.assertFalse(cache.hasCacheImage("littlehands")) # clear whole cache im = QImage(200, 200, QImage.Format.Format_RGB32) - cache.setCacheImage('littlehands', im) + cache.setCacheImage("littlehands", im) self.assertFalse(im.isNull()) - self.assertTrue(cache.hasCacheImage('littlehands')) + self.assertTrue(cache.hasCacheImage("littlehands")) cache.clear() - im = cache.cacheImage('littlehands') + im = cache.cacheImage("littlehands") self.assertTrue(im.isNull()) - self.assertFalse(cache.hasCacheImage('littlehands')) + self.assertFalse(cache.hasCacheImage("littlehands")) def testInit(self): cache = QgsMapRendererCache() @@ -70,89 +71,84 @@ def testInit(self): # add a cache image im = QImage(200, 200, QImage.Format.Format_RGB32) - cache.setCacheImage('layer', im) - self.assertFalse(cache.cacheImage('layer').isNull()) - self.assertTrue(cache.hasCacheImage('layer')) + cache.setCacheImage("layer", im) + self.assertFalse(cache.cacheImage("layer").isNull()) + self.assertTrue(cache.hasCacheImage("layer")) # re init, without changing extent or scale self.assertTrue(cache.init(extent, 1000)) # image should still be in cache - self.assertFalse(cache.cacheImage('layer').isNull()) - self.assertTrue(cache.hasCacheImage('layer')) + self.assertFalse(cache.cacheImage("layer").isNull()) + self.assertTrue(cache.hasCacheImage("layer")) # reinit with different scale self.assertFalse(cache.init(extent, 2000)) # cache should be cleared - self.assertTrue(cache.cacheImage('layer').isNull()) - self.assertFalse(cache.hasCacheImage('layer')) + self.assertTrue(cache.cacheImage("layer").isNull()) + self.assertFalse(cache.hasCacheImage("layer")) # readd image to cache - cache.setCacheImage('layer', im) - self.assertFalse(cache.cacheImage('layer').isNull()) - self.assertTrue(cache.hasCacheImage('layer')) + cache.setCacheImage("layer", im) + self.assertFalse(cache.cacheImage("layer").isNull()) + self.assertTrue(cache.hasCacheImage("layer")) # change extent self.assertFalse(cache.init(QgsRectangle(11, 12, 13, 14), 2000)) # cache should be cleared - self.assertTrue(cache.cacheImage('layer').isNull()) - self.assertFalse(cache.hasCacheImage('layer')) + self.assertTrue(cache.cacheImage("layer").isNull()) + self.assertFalse(cache.hasCacheImage("layer")) def testRequestRepaintSimple(self): - """ test requesting repaint with a single dependent layer """ - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer", "memory") + """test requesting repaint with a single dependent layer""" + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer", "memory") QgsProject.instance().addMapLayers([layer]) self.assertTrue(layer.isValid()) # add image to cache cache = QgsMapRendererCache() im = QImage(200, 200, QImage.Format.Format_RGB32) - cache.setCacheImage('xxx', im, [layer]) - self.assertFalse(cache.cacheImage('xxx').isNull()) - self.assertTrue(cache.hasCacheImage('xxx')) + cache.setCacheImage("xxx", im, [layer]) + self.assertFalse(cache.cacheImage("xxx").isNull()) + self.assertTrue(cache.hasCacheImage("xxx")) # trigger repaint on layer layer.triggerRepaint() # cache image should be cleared - self.assertTrue(cache.cacheImage('xxx').isNull()) - self.assertFalse(cache.hasCacheImage('xxx')) + self.assertTrue(cache.cacheImage("xxx").isNull()) + self.assertFalse(cache.hasCacheImage("xxx")) QgsProject.instance().removeMapLayer(layer.id()) # test that cache is also cleared on deferred update - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer", "memory") - cache.setCacheImage('xxx', im, [layer]) + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer", "memory") + cache.setCacheImage("xxx", im, [layer]) layer.triggerRepaint(True) - self.assertFalse(cache.hasCacheImage('xxx')) + self.assertFalse(cache.hasCacheImage("xxx")) def testInvalidateCacheForLayer(self): - """ test invalidating the cache for a layer """ - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer", "memory") + """test invalidating the cache for a layer""" + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer", "memory") QgsProject.instance().addMapLayers([layer]) self.assertTrue(layer.isValid()) # add image to cache cache = QgsMapRendererCache() im = QImage(200, 200, QImage.Format.Format_RGB32) - cache.setCacheImage('xxx', im, [layer]) - self.assertFalse(cache.cacheImage('xxx').isNull()) - self.assertTrue(cache.hasCacheImage('xxx')) + cache.setCacheImage("xxx", im, [layer]) + self.assertFalse(cache.cacheImage("xxx").isNull()) + self.assertTrue(cache.hasCacheImage("xxx")) # invalidate cache for layer cache.invalidateCacheForLayer(layer) # cache image should be cleared - self.assertTrue(cache.cacheImage('xxx').isNull()) - self.assertFalse(cache.hasCacheImage('xxx')) + self.assertTrue(cache.cacheImage("xxx").isNull()) + self.assertFalse(cache.hasCacheImage("xxx")) QgsProject.instance().removeMapLayer(layer.id()) def testRequestRepaintMultiple(self): - """ test requesting repaint with multiple dependent layers """ - layer1 = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") + """test requesting repaint with multiple dependent layers""" + layer1 = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") QgsProject.instance().addMapLayers([layer1, layer2]) self.assertTrue(layer1.isValid()) self.assertTrue(layer2.isValid()) @@ -160,9 +156,9 @@ def testRequestRepaintMultiple(self): # add image to cache - no dependent layers cache = QgsMapRendererCache() im1 = QImage(200, 200, QImage.Format.Format_RGB32) - cache.setCacheImage('nolayer', im1) - self.assertFalse(cache.cacheImage('nolayer').isNull()) - self.assertTrue(cache.hasCacheImage('nolayer')) + cache.setCacheImage("nolayer", im1) + self.assertFalse(cache.cacheImage("nolayer").isNull()) + self.assertTrue(cache.hasCacheImage("nolayer")) # trigger repaint on layer layer1.triggerRepaint() @@ -170,124 +166,119 @@ def testRequestRepaintMultiple(self): layer2.triggerRepaint() layer2.triggerRepaint() # cache image should still exist - it's not dependent on layers - self.assertFalse(cache.cacheImage('nolayer').isNull()) - self.assertTrue(cache.hasCacheImage('nolayer')) + self.assertFalse(cache.cacheImage("nolayer").isNull()) + self.assertTrue(cache.hasCacheImage("nolayer")) # image depends on 1 layer im_l1 = QImage(200, 200, QImage.Format.Format_RGB32) - cache.setCacheImage('im1', im_l1, [layer1]) + cache.setCacheImage("im1", im_l1, [layer1]) # image depends on 2 layers im_l1_l2 = QImage(200, 200, QImage.Format.Format_RGB32) - cache.setCacheImage('im1_im2', im_l1_l2, [layer1, layer2]) + cache.setCacheImage("im1_im2", im_l1_l2, [layer1, layer2]) # image depends on 2nd layer alone im_l2 = QImage(200, 200, QImage.Format.Format_RGB32) - cache.setCacheImage('im2', im_l2, [layer2]) + cache.setCacheImage("im2", im_l2, [layer2]) - self.assertFalse(cache.cacheImage('im1').isNull()) - self.assertTrue(cache.hasCacheImage('im1')) - self.assertFalse(cache.cacheImage('im1_im2').isNull()) - self.assertTrue(cache.hasCacheImage('im1_im2')) - self.assertFalse(cache.cacheImage('im2').isNull()) - self.assertTrue(cache.hasCacheImage('im2')) + self.assertFalse(cache.cacheImage("im1").isNull()) + self.assertTrue(cache.hasCacheImage("im1")) + self.assertFalse(cache.cacheImage("im1_im2").isNull()) + self.assertTrue(cache.hasCacheImage("im1_im2")) + self.assertFalse(cache.cacheImage("im2").isNull()) + self.assertTrue(cache.hasCacheImage("im2")) # trigger repaint layer 1 (check twice - don't want disconnect errors) for i in range(2): layer1.triggerRepaint() # should be cleared - self.assertTrue(cache.cacheImage('im1').isNull()) - self.assertFalse(cache.hasCacheImage('im1')) - self.assertTrue(cache.cacheImage('im1_im2').isNull()) - self.assertFalse(cache.hasCacheImage('im1_im2')) + self.assertTrue(cache.cacheImage("im1").isNull()) + self.assertFalse(cache.hasCacheImage("im1")) + self.assertTrue(cache.cacheImage("im1_im2").isNull()) + self.assertFalse(cache.hasCacheImage("im1_im2")) # should be retained - self.assertTrue(cache.hasCacheImage('im2')) - self.assertFalse(cache.cacheImage('im2').isNull()) - self.assertEqual(cache.cacheImage('im2'), im_l2) - self.assertTrue(cache.hasCacheImage('nolayer')) - self.assertFalse(cache.cacheImage('nolayer').isNull()) - self.assertEqual(cache.cacheImage('nolayer'), im1) + self.assertTrue(cache.hasCacheImage("im2")) + self.assertFalse(cache.cacheImage("im2").isNull()) + self.assertEqual(cache.cacheImage("im2"), im_l2) + self.assertTrue(cache.hasCacheImage("nolayer")) + self.assertFalse(cache.cacheImage("nolayer").isNull()) + self.assertEqual(cache.cacheImage("nolayer"), im1) # trigger repaint layer 2 for i in range(2): layer2.triggerRepaint() # should be cleared - self.assertFalse(cache.hasCacheImage('im1')) - self.assertTrue(cache.cacheImage('im1').isNull()) - self.assertFalse(cache.hasCacheImage('im1_im2')) - self.assertTrue(cache.cacheImage('im1_im2').isNull()) - self.assertFalse(cache.hasCacheImage('im2')) - self.assertTrue(cache.cacheImage('im2').isNull()) + self.assertFalse(cache.hasCacheImage("im1")) + self.assertTrue(cache.cacheImage("im1").isNull()) + self.assertFalse(cache.hasCacheImage("im1_im2")) + self.assertTrue(cache.cacheImage("im1_im2").isNull()) + self.assertFalse(cache.hasCacheImage("im2")) + self.assertTrue(cache.cacheImage("im2").isNull()) # should be retained - self.assertTrue(cache.hasCacheImage('nolayer')) - self.assertFalse(cache.cacheImage('nolayer').isNull()) - self.assertEqual(cache.cacheImage('nolayer'), im1) + self.assertTrue(cache.hasCacheImage("nolayer")) + self.assertFalse(cache.cacheImage("nolayer").isNull()) + self.assertEqual(cache.cacheImage("nolayer"), im1) def testDependentLayers(self): # bad layer tests cache = QgsMapRendererCache() - self.assertEqual(cache.dependentLayers('not a layer'), []) + self.assertEqual(cache.dependentLayers("not a layer"), []) - layer1 = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") + layer1 = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") im = QImage(200, 200, QImage.Format.Format_RGB32) - cache.setCacheImage('no depends', im, []) - self.assertEqual(cache.dependentLayers('no depends'), []) - cache.setCacheImage('depends', im, [layer1, layer2]) - self.assertEqual(set(cache.dependentLayers('depends')), {layer1, layer2}) + cache.setCacheImage("no depends", im, []) + self.assertEqual(cache.dependentLayers("no depends"), []) + cache.setCacheImage("depends", im, [layer1, layer2]) + self.assertEqual(set(cache.dependentLayers("depends")), {layer1, layer2}) def testLayerRemoval(self): """test that cached image is cleared when a dependent layer is removed""" cache = QgsMapRendererCache() - layer1 = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") + layer1 = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") im = QImage(200, 200, QImage.Format.Format_RGB32) - cache.setCacheImage('depends', im, [layer1, layer2]) - cache.setCacheImage('depends2', im, [layer1]) - cache.setCacheImage('depends3', im, [layer2]) - cache.setCacheImage('no depends', im, []) - self.assertTrue(cache.hasCacheImage('depends')) - self.assertTrue(cache.hasCacheImage('depends2')) - self.assertTrue(cache.hasCacheImage('depends3')) - self.assertTrue(cache.hasCacheImage('no depends')) + cache.setCacheImage("depends", im, [layer1, layer2]) + cache.setCacheImage("depends2", im, [layer1]) + cache.setCacheImage("depends3", im, [layer2]) + cache.setCacheImage("no depends", im, []) + self.assertTrue(cache.hasCacheImage("depends")) + self.assertTrue(cache.hasCacheImage("depends2")) + self.assertTrue(cache.hasCacheImage("depends3")) + self.assertTrue(cache.hasCacheImage("no depends")) # try deleting a layer layer2 = None - self.assertFalse(cache.hasCacheImage('depends')) - self.assertTrue(cache.hasCacheImage('depends2')) - self.assertFalse(cache.hasCacheImage('depends3')) - self.assertTrue(cache.hasCacheImage('no depends')) + self.assertFalse(cache.hasCacheImage("depends")) + self.assertTrue(cache.hasCacheImage("depends2")) + self.assertFalse(cache.hasCacheImage("depends3")) + self.assertTrue(cache.hasCacheImage("no depends")) layer1 = None - self.assertFalse(cache.hasCacheImage('depends')) - self.assertFalse(cache.hasCacheImage('depends2')) - self.assertFalse(cache.hasCacheImage('depends3')) - self.assertTrue(cache.hasCacheImage('no depends')) + self.assertFalse(cache.hasCacheImage("depends")) + self.assertFalse(cache.hasCacheImage("depends2")) + self.assertFalse(cache.hasCacheImage("depends3")) + self.assertTrue(cache.hasCacheImage("no depends")) def testClearOnLayerAutoRefresh(self): - """ test that cache is cleared when layer auto refresh is triggered """ + """test that cache is cleared when layer auto refresh is triggered""" cache = QgsMapRendererCache() - layer1 = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer1 = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") im = QImage(200, 200, QImage.Format.Format_RGB32) - cache.setCacheImage('l1', im, [layer1]) - self.assertTrue(cache.hasCacheImage('l1')) + cache.setCacheImage("l1", im, [layer1]) + self.assertTrue(cache.hasCacheImage("l1")) layer1.setAutoRefreshInterval(100) layer1.setAutoRefreshEnabled(True) - self.assertTrue(cache.hasCacheImage('l1')) + self.assertTrue(cache.hasCacheImage("l1")) # wait a second... sleep(1) for i in range(100): QCoreApplication.processEvents() # cache should be cleared - self.assertFalse(cache.hasCacheImage('l1')) + self.assertFalse(cache.hasCacheImage("l1")) def testSetCacheImageDifferentParams(self): """ @@ -296,25 +287,31 @@ def testSetCacheImageDifferentParams(self): cache = QgsMapRendererCache() cache.updateParameters(QgsRectangle(1, 1, 3, 3), QgsMapToPixel(5)) im = QImage(200, 200, QImage.Format.Format_RGB32) - cache.setCacheImage('im1', im, []) + cache.setCacheImage("im1", im, []) - self.assertEqual(cache.cacheImage('im1').width(), 200) + self.assertEqual(cache.cacheImage("im1").width(), 200) # if existing cached image exists with matching parameters, we don't store a new image -- old # one should still be retained im = QImage(201, 201, QImage.Format.Format_RGB32) - cache.setCacheImageWithParameters('im1', im, QgsRectangle(1, 1, 3, 4), QgsMapToPixel(5), []) - self.assertEqual(cache.cacheImage('im1').width(), 200) - cache.setCacheImageWithParameters('im1', im, QgsRectangle(1, 1, 3, 3), QgsMapToPixel(6), []) - self.assertEqual(cache.cacheImage('im1').width(), 200) + cache.setCacheImageWithParameters( + "im1", im, QgsRectangle(1, 1, 3, 4), QgsMapToPixel(5), [] + ) + self.assertEqual(cache.cacheImage("im1").width(), 200) + cache.setCacheImageWithParameters( + "im1", im, QgsRectangle(1, 1, 3, 3), QgsMapToPixel(6), [] + ) + self.assertEqual(cache.cacheImage("im1").width(), 200) # replace with matching parameters - cache.setCacheImageWithParameters('im1', im, QgsRectangle(1, 1, 3, 3), QgsMapToPixel(5), []) - self.assertEqual(cache.cacheImage('im1').width(), 201) + cache.setCacheImageWithParameters( + "im1", im, QgsRectangle(1, 1, 3, 3), QgsMapToPixel(5), [] + ) + self.assertEqual(cache.cacheImage("im1").width(), 201) im = QImage(202, 202, QImage.Format.Format_RGB32) - cache.setCacheImage('im1', im, []) - self.assertEqual(cache.cacheImage('im1').width(), 202) + cache.setCacheImage("im1", im, []) + self.assertEqual(cache.cacheImage("im1").width(), 202) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmapthemecollection.py b/tests/src/python/test_qgsmapthemecollection.py index ef147f0e69ee..58a80aa6288e 100644 --- a/tests/src/python/test_qgsmapthemecollection.py +++ b/tests/src/python/test_qgsmapthemecollection.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '8/03/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "8/03/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy from qgis.core import QgsMapThemeCollection, QgsProject, QgsVectorLayer @@ -35,35 +36,36 @@ def testThemeChanged(self): theme_changed_spy = QSignalSpy(collection.mapThemeChanged) themes_changed_spy = QSignalSpy(collection.mapThemesChanged) - collection.insert('theme1', record) + collection.insert("theme1", record) self.assertEqual(len(theme_changed_spy), 1) - self.assertEqual(theme_changed_spy[-1][0], 'theme1') + self.assertEqual(theme_changed_spy[-1][0], "theme1") self.assertEqual(len(themes_changed_spy), 1) # reinsert - collection.insert('theme1', record) + collection.insert("theme1", record) self.assertEqual(len(theme_changed_spy), 2) - self.assertEqual(theme_changed_spy[-1][0], 'theme1') + self.assertEqual(theme_changed_spy[-1][0], "theme1") self.assertEqual(len(themes_changed_spy), 2) # update - collection.update('theme1', record) + collection.update("theme1", record) self.assertEqual(len(theme_changed_spy), 3) - self.assertEqual(theme_changed_spy[-1][0], 'theme1') + self.assertEqual(theme_changed_spy[-1][0], "theme1") self.assertEqual(len(themes_changed_spy), 3) # remove invalid collection.removeMapTheme( - 'i wish i was a slave to an age old trade... like riding around on rail cars and working long days') + "i wish i was a slave to an age old trade... like riding around on rail cars and working long days" + ) self.assertEqual(len(theme_changed_spy), 3) self.assertEqual(len(themes_changed_spy), 3) # remove valid - collection.removeMapTheme('theme1') + collection.removeMapTheme("theme1") self.assertEqual(len(theme_changed_spy), 3) # not changed - removed! self.assertEqual(len(themes_changed_spy), 4) # reinsert - collection.insert('theme1', record) + collection.insert("theme1", record) self.assertEqual(len(theme_changed_spy), 4) self.assertEqual(len(themes_changed_spy), 5) @@ -73,36 +75,35 @@ def testThemeChanged(self): self.assertEqual(len(themes_changed_spy), 6) # check that mapThemeChanged is emitted if layer is removed - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") project.addMapLayers([layer, layer2]) # record for layer1 record.addLayerRecord(QgsMapThemeCollection.MapThemeLayerRecord(layer)) - collection.insert('theme1', record) + collection.insert("theme1", record) self.assertEqual(len(theme_changed_spy), 5) self.assertEqual(len(themes_changed_spy), 7) # now kill layer 2 project.removeMapLayer(layer2) - self.assertEqual(len(theme_changed_spy), 5) # signal should not be emitted - layer is not in record + self.assertEqual( + len(theme_changed_spy), 5 + ) # signal should not be emitted - layer is not in record # now kill layer 1 project.removeMapLayer(layer) app.processEvents() - self.assertEqual(len(theme_changed_spy), 6) # signal should be emitted - layer is in record + self.assertEqual( + len(theme_changed_spy), 6 + ) # signal should be emitted - layer is in record def testMasterLayerOrder(self): - """ test master layer order""" + """test master layer order""" prj = QgsProject.instance() prj.clear() - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") - layer3 = QgsVectorLayer("Point?field=fldtxt:string", - "layer3", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") + layer3 = QgsVectorLayer("Point?field=fldtxt:string", "layer3", "memory") prj.addMapLayers([layer, layer2, layer3]) prj.layerTreeRoot().setHasCustomLayerOrder(True) @@ -112,42 +113,84 @@ def testMasterLayerOrder(self): prj.layerTreeRoot().setCustomLayerOrder([layer, layer2, layer3]) # make some themes... theme1 = QgsMapThemeCollection.MapThemeRecord() - theme1.setLayerRecords([QgsMapThemeCollection.MapThemeLayerRecord(layer3), - QgsMapThemeCollection.MapThemeLayerRecord(layer)]) + theme1.setLayerRecords( + [ + QgsMapThemeCollection.MapThemeLayerRecord(layer3), + QgsMapThemeCollection.MapThemeLayerRecord(layer), + ] + ) theme2 = QgsMapThemeCollection.MapThemeRecord() - theme2.setLayerRecords([QgsMapThemeCollection.MapThemeLayerRecord(layer3), - QgsMapThemeCollection.MapThemeLayerRecord(layer2), - QgsMapThemeCollection.MapThemeLayerRecord(layer)]) + theme2.setLayerRecords( + [ + QgsMapThemeCollection.MapThemeLayerRecord(layer3), + QgsMapThemeCollection.MapThemeLayerRecord(layer2), + QgsMapThemeCollection.MapThemeLayerRecord(layer), + ] + ) theme3 = QgsMapThemeCollection.MapThemeRecord() - theme3.setLayerRecords([QgsMapThemeCollection.MapThemeLayerRecord(layer2), - QgsMapThemeCollection.MapThemeLayerRecord(layer)]) + theme3.setLayerRecords( + [ + QgsMapThemeCollection.MapThemeLayerRecord(layer2), + QgsMapThemeCollection.MapThemeLayerRecord(layer), + ] + ) - prj.mapThemeCollection().insert('theme1', theme1) - prj.mapThemeCollection().insert('theme2', theme2) - prj.mapThemeCollection().insert('theme3', theme3) + prj.mapThemeCollection().insert("theme1", theme1) + prj.mapThemeCollection().insert("theme2", theme2) + prj.mapThemeCollection().insert("theme3", theme3) # order of layers in theme should respect master order - self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme1'), [layer, layer3]) - self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme2'), [layer, layer2, layer3]) - self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme3'), [layer, layer2]) + self.assertEqual( + prj.mapThemeCollection().mapThemeVisibleLayers("theme1"), [layer, layer3] + ) + self.assertEqual( + prj.mapThemeCollection().mapThemeVisibleLayers("theme2"), + [layer, layer2, layer3], + ) + self.assertEqual( + prj.mapThemeCollection().mapThemeVisibleLayers("theme3"), [layer, layer2] + ) # also check ids! - self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme1'), [layer.id(), layer3.id()]) - self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme2'), - [layer.id(), layer2.id(), layer3.id()]) - self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme3'), [layer.id(), layer2.id()]) + self.assertEqual( + prj.mapThemeCollection().mapThemeVisibleLayerIds("theme1"), + [layer.id(), layer3.id()], + ) + self.assertEqual( + prj.mapThemeCollection().mapThemeVisibleLayerIds("theme2"), + [layer.id(), layer2.id(), layer3.id()], + ) + self.assertEqual( + prj.mapThemeCollection().mapThemeVisibleLayerIds("theme3"), + [layer.id(), layer2.id()], + ) # reset master order prj.layerTreeRoot().setCustomLayerOrder([layer2, layer3, layer]) - self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme1'), [layer3, layer]) - self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme2'), [layer2, layer3, layer]) - self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme3'), [layer2, layer]) - self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme1'), [layer3.id(), layer.id()]) - self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme2'), - [layer2.id(), layer3.id(), layer.id()]) - self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme3'), [layer2.id(), layer.id()]) + self.assertEqual( + prj.mapThemeCollection().mapThemeVisibleLayers("theme1"), [layer3, layer] + ) + self.assertEqual( + prj.mapThemeCollection().mapThemeVisibleLayers("theme2"), + [layer2, layer3, layer], + ) + self.assertEqual( + prj.mapThemeCollection().mapThemeVisibleLayers("theme3"), [layer2, layer] + ) + self.assertEqual( + prj.mapThemeCollection().mapThemeVisibleLayerIds("theme1"), + [layer3.id(), layer.id()], + ) + self.assertEqual( + prj.mapThemeCollection().mapThemeVisibleLayerIds("theme2"), + [layer2.id(), layer3.id(), layer.id()], + ) + self.assertEqual( + prj.mapThemeCollection().mapThemeVisibleLayerIds("theme3"), + [layer2.id(), layer.id()], + ) # check that layers include those hidden in the layer tree canvas = QgsMapCanvas() @@ -157,52 +200,80 @@ def testMasterLayerOrder(self): layer_node.setItemVisibilityChecked(False) app.processEvents() prj.layerTreeRoot().setHasCustomLayerOrder(False) - self.assertEqual(prj.mapThemeCollection().masterLayerOrder(), [layer, layer2, layer3]) - - self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme1'), [layer, layer3]) - self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme2'), [layer, layer2, layer3]) - self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme3'), [layer, layer2]) - self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme1'), [layer.id(), layer3.id()]) - self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme2'), - [layer.id(), layer2.id(), layer3.id()]) - self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme3'), [layer.id(), layer2.id()]) + self.assertEqual( + prj.mapThemeCollection().masterLayerOrder(), [layer, layer2, layer3] + ) + + self.assertEqual( + prj.mapThemeCollection().mapThemeVisibleLayers("theme1"), [layer, layer3] + ) + self.assertEqual( + prj.mapThemeCollection().mapThemeVisibleLayers("theme2"), + [layer, layer2, layer3], + ) + self.assertEqual( + prj.mapThemeCollection().mapThemeVisibleLayers("theme3"), [layer, layer2] + ) + self.assertEqual( + prj.mapThemeCollection().mapThemeVisibleLayerIds("theme1"), + [layer.id(), layer3.id()], + ) + self.assertEqual( + prj.mapThemeCollection().mapThemeVisibleLayerIds("theme2"), + [layer.id(), layer2.id(), layer3.id()], + ) + self.assertEqual( + prj.mapThemeCollection().mapThemeVisibleLayerIds("theme3"), + [layer.id(), layer2.id()], + ) def testMasterVisibleLayers(self): - """ test master visible layers""" + """test master visible layers""" prj = QgsProject.instance() prj.clear() - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") - layer3 = QgsVectorLayer("Point?field=fldtxt:string", - "layer3", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") + layer3 = QgsVectorLayer("Point?field=fldtxt:string", "layer3", "memory") prj.addMapLayers([layer, layer2, layer3]) # general setup... prj.layerTreeRoot().setHasCustomLayerOrder(True) prj.layerTreeRoot().setCustomLayerOrder([layer2, layer]) - self.assertEqual(prj.mapThemeCollection().masterVisibleLayers(), [layer2, layer]) + self.assertEqual( + prj.mapThemeCollection().masterVisibleLayers(), [layer2, layer] + ) prj.layerTreeRoot().setCustomLayerOrder([layer3, layer, layer2]) - self.assertEqual(prj.mapThemeCollection().masterVisibleLayers(), [layer3, layer, layer2]) + self.assertEqual( + prj.mapThemeCollection().masterVisibleLayers(), [layer3, layer, layer2] + ) # hide some layers root = prj.layerTreeRoot() layer_node = root.findLayer(layer2) layer_node.setItemVisibilityChecked(False) - self.assertEqual(prj.mapThemeCollection().masterVisibleLayers(), [layer3, layer]) + self.assertEqual( + prj.mapThemeCollection().masterVisibleLayers(), [layer3, layer] + ) layer_node.setItemVisibilityChecked(True) - self.assertEqual(prj.mapThemeCollection().masterVisibleLayers(), [layer3, layer, layer2]) + self.assertEqual( + prj.mapThemeCollection().masterVisibleLayers(), [layer3, layer, layer2] + ) layer_node.setItemVisibilityChecked(False) prj.layerTreeRoot().setCustomLayerOrder([layer, layer2, layer3]) - self.assertEqual(prj.mapThemeCollection().masterVisibleLayers(), [layer, layer3]) + self.assertEqual( + prj.mapThemeCollection().masterVisibleLayers(), [layer, layer3] + ) # test with no project layer order set, should respect tree order prj.layerTreeRoot().setCustomLayerOrder([]) - self.assertEqual(prj.mapThemeCollection().masterVisibleLayers(), [layer, layer3]) + self.assertEqual( + prj.mapThemeCollection().masterVisibleLayers(), [layer, layer3] + ) layer_node.setItemVisibilityChecked(True) - self.assertEqual(prj.mapThemeCollection().masterVisibleLayers(), [layer, layer2, layer3]) + self.assertEqual( + prj.mapThemeCollection().masterVisibleLayers(), [layer, layer2, layer3] + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmapunitscale.py b/tests/src/python/test_qgsmapunitscale.py index e99ea1711074..9932ca010fcf 100644 --- a/tests/src/python/test_qgsmapunitscale.py +++ b/tests/src/python/test_qgsmapunitscale.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2015-09' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2015-09" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.PyQt.QtCore import QSize from qgis.core import ( @@ -139,7 +140,7 @@ def testEncodeDecode(self): self.assertEqual(s, r) # check old style encoding - encode = '9,78.3' + encode = "9,78.3" r = QgsSymbolLayerUtils.decodeMapUnitScale(encode) self.assertAlmostEqual(r.minScale, 1.0 / 9, 3) self.assertAlmostEqual(r.maxScale, 1.0 / 78.3, 3) @@ -149,5 +150,5 @@ def testEncodeDecode(self): self.assertEqual(r.maxSizeMM, 0) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmargins.py b/tests/src/python/test_qgsmargins.py index 6229c78d072a..2f308dfd40a4 100644 --- a/tests/src/python/test_qgsmargins.py +++ b/tests/src/python/test_qgsmargins.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2017-01' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2017-01" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.core import QgsMargins @@ -35,8 +36,9 @@ def testGetSet(self): self.assertEqual(margins, QgsMargins(5.5, 0.0, 5.5, 0.0)) def test_repr(self): - self.assertEqual(str(QgsMargins(12.1, 14.1, 16.1, 18.1)), - '') + self.assertEqual( + str(QgsMargins(12.1, 14.1, 16.1, 18.1)), "" + ) def testOperators(self): m1 = QgsMargins(12.1, 14.1, 16.1, 18.1) @@ -105,19 +107,19 @@ def testToString(self): # null margin self.assertFalse(QgsMargins().toString()) - self.assertEqual(QgsMargins(1, 2, 3, 4).toString(), '1,2,3,4') - self.assertEqual(QgsMargins(1, -2, 3, -4).toString(), '1,-2,3,-4') + self.assertEqual(QgsMargins(1, 2, 3, 4).toString(), "1,2,3,4") + self.assertEqual(QgsMargins(1, -2, 3, -4).toString(), "1,-2,3,-4") def testFromString(self): - self.assertTrue(QgsMargins.fromString('').isNull()) - self.assertTrue(QgsMargins.fromString('not good').isNull()) - self.assertTrue(QgsMargins.fromString('1,2,3').isNull()) - self.assertTrue(QgsMargins.fromString('1,2,3,4,5').isNull()) + self.assertTrue(QgsMargins.fromString("").isNull()) + self.assertTrue(QgsMargins.fromString("not good").isNull()) + self.assertTrue(QgsMargins.fromString("1,2,3").isNull()) + self.assertTrue(QgsMargins.fromString("1,2,3,4,5").isNull()) - self.assertEqual(QgsMargins.fromString('1,2,3,4'), QgsMargins(1, 2, 3, 4)) - self.assertEqual(QgsMargins.fromString('1,-2,3,-4'), QgsMargins(1, -2, 3, -4)) + self.assertEqual(QgsMargins.fromString("1,2,3,4"), QgsMargins(1, 2, 3, 4)) + self.assertEqual(QgsMargins.fromString("1,-2,3,-4"), QgsMargins(1, -2, 3, -4)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmarkerlinesymbollayer.py b/tests/src/python/test_qgsmarkerlinesymbollayer.py index 220a900ba13c..31409ca9fd6e 100644 --- a/tests/src/python/test_qgsmarkerlinesymbollayer.py +++ b/tests/src/python/test_qgsmarkerlinesymbollayer.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'November 2018' -__copyright__ = '(C) 2018, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "November 2018" +__copyright__ = "(C) 2018, Nyall Dawson" import os @@ -82,7 +82,9 @@ def testWidth(self): marker_line = QgsMarkerLineSymbolLayer(True) marker_line.setPlacement(QgsMarkerLineSymbolLayer.Placement.FirstVertex) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 10) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 10 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -100,33 +102,46 @@ def testWidth(self): def testMultiplePlacements(self): line_symbol = QgsLineSymbol() line_symbol.deleteSymbolLayer(0) - line_symbol.appendSymbolLayer( - QgsMarkerLineSymbolLayer()) - line_symbol[0].setPlacements(Qgis.MarkerLinePlacements(Qgis.MarkerLinePlacement.FirstVertex | Qgis.MarkerLinePlacement.LastVertex)) + line_symbol.appendSymbolLayer(QgsMarkerLineSymbolLayer()) + line_symbol[0].setPlacements( + Qgis.MarkerLinePlacements( + Qgis.MarkerLinePlacement.FirstVertex + | Qgis.MarkerLinePlacement.LastVertex + ) + ) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() marker_symbol.changeSymbolLayer(0, marker) line_symbol[0].setSubSymbol(marker_symbol) - g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10, 0 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 0, 10 10, 0 10)") rendered_image = self.renderGeometry(line_symbol, g) self.assertTrue( - self.image_check('markerline_multiple_placement', 'markerline_multiple_placement', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_multiple_placement", + "markerline_multiple_placement", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testFirstVertexNoRespectMultipart(self): line_symbol = QgsLineSymbol() line_symbol.deleteSymbolLayer(0) - line_symbol.appendSymbolLayer( - QgsMarkerLineSymbolLayer()) - line_symbol[0].setPlacements(Qgis.MarkerLinePlacements(Qgis.MarkerLinePlacement.FirstVertex)) + line_symbol.appendSymbolLayer(QgsMarkerLineSymbolLayer()) + line_symbol[0].setPlacements( + Qgis.MarkerLinePlacements(Qgis.MarkerLinePlacement.FirstVertex) + ) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -134,22 +149,31 @@ def testFirstVertexNoRespectMultipart(self): line_symbol[0].setSubSymbol(marker_symbol) line_symbol[0].setPlaceOnEveryPart(True) - g = QgsGeometry.fromWkt('MultiLineString((0 0, 10 0, 10 10, 0 10),(3 3, 7 3, 7 7, 3 7))') + g = QgsGeometry.fromWkt( + "MultiLineString((0 0, 10 0, 10 10, 0 10),(3 3, 7 3, 7 7, 3 7))" + ) rendered_image = self.renderGeometry(line_symbol, g) self.assertTrue( - self.image_check('markerline_first_no_respect_multipart', 'markerline_first_no_respect_multipart', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_first_no_respect_multipart", + "markerline_first_no_respect_multipart", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testFirstVertexRespectMultipart(self): line_symbol = QgsLineSymbol() line_symbol.deleteSymbolLayer(0) - line_symbol.appendSymbolLayer( - QgsMarkerLineSymbolLayer()) - line_symbol[0].setPlacements(Qgis.MarkerLinePlacements(Qgis.MarkerLinePlacement.FirstVertex)) + line_symbol.appendSymbolLayer(QgsMarkerLineSymbolLayer()) + line_symbol[0].setPlacements( + Qgis.MarkerLinePlacements(Qgis.MarkerLinePlacement.FirstVertex) + ) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -157,22 +181,31 @@ def testFirstVertexRespectMultipart(self): line_symbol[0].setSubSymbol(marker_symbol) line_symbol[0].setPlaceOnEveryPart(False) - g = QgsGeometry.fromWkt('MultiLineString((0 0, 10 0, 10 10, 0 10),(3 3, 7 3, 7 7, 3 7))') + g = QgsGeometry.fromWkt( + "MultiLineString((0 0, 10 0, 10 10, 0 10),(3 3, 7 3, 7 7, 3 7))" + ) rendered_image = self.renderGeometry(line_symbol, g) self.assertTrue( - self.image_check('markerline_first_respect_multipart', 'markerline_first_respect_multipart', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_first_respect_multipart", + "markerline_first_respect_multipart", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testLastVertexNoRespectMultipart(self): line_symbol = QgsLineSymbol() line_symbol.deleteSymbolLayer(0) - line_symbol.appendSymbolLayer( - QgsMarkerLineSymbolLayer()) - line_symbol[0].setPlacements(Qgis.MarkerLinePlacements(Qgis.MarkerLinePlacement.LastVertex)) + line_symbol.appendSymbolLayer(QgsMarkerLineSymbolLayer()) + line_symbol[0].setPlacements( + Qgis.MarkerLinePlacements(Qgis.MarkerLinePlacement.LastVertex) + ) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -180,22 +213,31 @@ def testLastVertexNoRespectMultipart(self): line_symbol[0].setSubSymbol(marker_symbol) line_symbol[0].setPlaceOnEveryPart(True) - g = QgsGeometry.fromWkt('MultiLineString((0 0, 10 0, 10 10, 0 10),(3 3, 7 3, 7 7, 3 7))') + g = QgsGeometry.fromWkt( + "MultiLineString((0 0, 10 0, 10 10, 0 10),(3 3, 7 3, 7 7, 3 7))" + ) rendered_image = self.renderGeometry(line_symbol, g) self.assertTrue( - self.image_check('markerline_last_no_respect_multipart', 'markerline_last_no_respect_multipart', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_last_no_respect_multipart", + "markerline_last_no_respect_multipart", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testLastVertexRespectMultipart(self): line_symbol = QgsLineSymbol() line_symbol.deleteSymbolLayer(0) - line_symbol.appendSymbolLayer( - QgsMarkerLineSymbolLayer()) - line_symbol[0].setPlacements(Qgis.MarkerLinePlacements(Qgis.MarkerLinePlacement.LastVertex)) + line_symbol.appendSymbolLayer(QgsMarkerLineSymbolLayer()) + line_symbol[0].setPlacements( + Qgis.MarkerLinePlacements(Qgis.MarkerLinePlacement.LastVertex) + ) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -203,22 +245,34 @@ def testLastVertexRespectMultipart(self): line_symbol[0].setSubSymbol(marker_symbol) line_symbol[0].setPlaceOnEveryPart(False) - g = QgsGeometry.fromWkt('MultiLineString((0 0, 10 0, 10 10, 0 10),(3 3, 7 3, 7 7, 3 7))') + g = QgsGeometry.fromWkt( + "MultiLineString((0 0, 10 0, 10 10, 0 10),(3 3, 7 3, 7 7, 3 7))" + ) rendered_image = self.renderGeometry(line_symbol, g) self.assertTrue( - self.image_check('markerline_last_respect_multipart', 'markerline_last_respect_multipart', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_last_respect_multipart", + "markerline_last_respect_multipart", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testFirstLastVertexNoRespectMultipart(self): line_symbol = QgsLineSymbol() line_symbol.deleteSymbolLayer(0) - line_symbol.appendSymbolLayer( - QgsMarkerLineSymbolLayer()) - line_symbol[0].setPlacements(Qgis.MarkerLinePlacements(Qgis.MarkerLinePlacement.FirstVertex | Qgis.MarkerLinePlacement.LastVertex)) + line_symbol.appendSymbolLayer(QgsMarkerLineSymbolLayer()) + line_symbol[0].setPlacements( + Qgis.MarkerLinePlacements( + Qgis.MarkerLinePlacement.FirstVertex + | Qgis.MarkerLinePlacement.LastVertex + ) + ) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -226,22 +280,34 @@ def testFirstLastVertexNoRespectMultipart(self): line_symbol[0].setSubSymbol(marker_symbol) line_symbol[0].setPlaceOnEveryPart(True) - g = QgsGeometry.fromWkt('MultiLineString((0 0, 10 0, 10 10, 0 10),(3 3, 7 3, 7 7, 3 7))') + g = QgsGeometry.fromWkt( + "MultiLineString((0 0, 10 0, 10 10, 0 10),(3 3, 7 3, 7 7, 3 7))" + ) rendered_image = self.renderGeometry(line_symbol, g) self.assertTrue( - self.image_check('markerline_first_last_no_respect_multipart', 'markerline_first_last_no_respect_multipart', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_first_last_no_respect_multipart", + "markerline_first_last_no_respect_multipart", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testFirstLastVertexRespectMultipart(self): line_symbol = QgsLineSymbol() line_symbol.deleteSymbolLayer(0) - line_symbol.appendSymbolLayer( - QgsMarkerLineSymbolLayer()) - line_symbol[0].setPlacements(Qgis.MarkerLinePlacements(Qgis.MarkerLinePlacement.FirstVertex | Qgis.MarkerLinePlacement.LastVertex)) + line_symbol.appendSymbolLayer(QgsMarkerLineSymbolLayer()) + line_symbol[0].setPlacements( + Qgis.MarkerLinePlacements( + Qgis.MarkerLinePlacement.FirstVertex + | Qgis.MarkerLinePlacement.LastVertex + ) + ) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -249,56 +315,76 @@ def testFirstLastVertexRespectMultipart(self): line_symbol[0].setSubSymbol(marker_symbol) line_symbol[0].setPlaceOnEveryPart(False) - g = QgsGeometry.fromWkt('MultiLineString((0 0, 10 0, 10 10, 0 10),(3 3, 7 3, 7 7, 3 7))') + g = QgsGeometry.fromWkt( + "MultiLineString((0 0, 10 0, 10 10, 0 10),(3 3, 7 3, 7 7, 3 7))" + ) rendered_image = self.renderGeometry(line_symbol, g) self.assertTrue( - self.image_check('markerline_first_last_respect_multipart', 'markerline_first_last_respect_multipart', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_first_last_respect_multipart", + "markerline_first_last_respect_multipart", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testInnerVerticesLine(self): line_symbol = QgsLineSymbol() line_symbol.deleteSymbolLayer(0) - line_symbol.appendSymbolLayer( - QgsMarkerLineSymbolLayer()) - line_symbol[0].setPlacements(Qgis.MarkerLinePlacements(Qgis.MarkerLinePlacement.InnerVertices)) + line_symbol.appendSymbolLayer(QgsMarkerLineSymbolLayer()) + line_symbol[0].setPlacements( + Qgis.MarkerLinePlacements(Qgis.MarkerLinePlacement.InnerVertices) + ) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() marker_symbol.changeSymbolLayer(0, marker) line_symbol[0].setSubSymbol(marker_symbol) - g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10, 0 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 0, 10 10, 0 10)") rendered_image = self.renderGeometry(line_symbol, g) self.assertTrue( - self.image_check('markerline_inner_vertices_line', 'markerline_inner_vertices_line', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_inner_vertices_line", + "markerline_inner_vertices_line", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testInnerVerticesPolygon(self): fill_symbol = QgsFillSymbol() fill_symbol.deleteSymbolLayer(0) - fill_symbol.appendSymbolLayer( - QgsMarkerLineSymbolLayer()) - fill_symbol[0].setPlacements(Qgis.MarkerLinePlacements(Qgis.MarkerLinePlacement.InnerVertices)) + fill_symbol.appendSymbolLayer(QgsMarkerLineSymbolLayer()) + fill_symbol[0].setPlacements( + Qgis.MarkerLinePlacements(Qgis.MarkerLinePlacement.InnerVertices) + ) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() marker_symbol.changeSymbolLayer(0, marker) fill_symbol[0].setSubSymbol(marker_symbol) - g = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 0 10, 0 0))') + g = QgsGeometry.fromWkt("Polygon((0 0, 10 0, 10 10, 0 10, 0 0))") rendered_image = self.renderGeometry(fill_symbol, g) self.assertTrue( - self.image_check('markerline_inner_vertices_polygon', 'markerline_inner_vertices_polygon', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_inner_vertices_polygon", + "markerline_inner_vertices_polygon", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testRingFilter(self): @@ -308,7 +394,9 @@ def testRingFilter(self): marker_line = QgsMarkerLineSymbolLayer(True) marker_line.setPlacement(QgsMarkerLineSymbolLayer.Placement.FirstVertex) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -316,61 +404,98 @@ def testRingFilter(self): marker_line.setSubSymbol(marker_symbol) s.appendSymbolLayer(marker_line.clone()) - self.assertEqual(s.symbolLayer(0).ringFilter(), QgsLineSymbolLayer.RenderRingFilter.AllRings) - s.symbolLayer(0).setRingFilter(QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly) - self.assertEqual(s.symbolLayer(0).ringFilter(), QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly) + self.assertEqual( + s.symbolLayer(0).ringFilter(), QgsLineSymbolLayer.RenderRingFilter.AllRings + ) + s.symbolLayer(0).setRingFilter( + QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly + ) + self.assertEqual( + s.symbolLayer(0).ringFilter(), + QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly, + ) s2 = s.clone() - self.assertEqual(s2.symbolLayer(0).ringFilter(), QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly) + self.assertEqual( + s2.symbolLayer(0).ringFilter(), + QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly, + ) doc = QDomDocument() context = QgsReadWriteContext() - element = QgsSymbolLayerUtils.saveSymbol('test', s, doc, context) + element = QgsSymbolLayerUtils.saveSymbol("test", s, doc, context) s2 = QgsSymbolLayerUtils.loadSymbol(element, context) - self.assertEqual(s2.symbolLayer(0).ringFilter(), QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly) + self.assertEqual( + s2.symbolLayer(0).ringFilter(), + QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly, + ) # rendering test s3 = QgsFillSymbol() s3.deleteSymbolLayer(0) - s3.appendSymbolLayer( - QgsMarkerLineSymbolLayer()) - s3.symbolLayer(0).setRingFilter(QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly) + s3.appendSymbolLayer(QgsMarkerLineSymbolLayer()) + s3.symbolLayer(0).setRingFilter( + QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly + ) s3.symbolLayer(0).setAverageAngleLength(0) - g = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))') + g = QgsGeometry.fromWkt( + "Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))" + ) rendered_image = self.renderGeometry(s3, g) self.assertTrue( - self.image_check('markerline_exterioronly', 'markerline_exterioronly', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_exterioronly", + "markerline_exterioronly", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) - s3.symbolLayer(0).setRingFilter(QgsLineSymbolLayer.RenderRingFilter.InteriorRingsOnly) - g = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))') + s3.symbolLayer(0).setRingFilter( + QgsLineSymbolLayer.RenderRingFilter.InteriorRingsOnly + ) + g = QgsGeometry.fromWkt( + "Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))" + ) rendered_image = self.renderGeometry(s3, g) self.assertTrue( - self.image_check('markerline_interioronly', 'markerline_interioronly', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_interioronly", + "markerline_interioronly", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testRingNumberVariable(self): # test test geometry_ring_num variable s3 = QgsFillSymbol() s3.deleteSymbolLayer(0) - s3.appendSymbolLayer( - QgsMarkerLineSymbolLayer()) - s3.symbolLayer(0).subSymbol()[0].setDataDefinedProperty(QgsSymbolLayer.Property.PropertyFillColor, - QgsProperty.fromExpression('case when @geometry_ring_num=0 then \'green\' when @geometry_ring_num=1 then \'blue\' when @geometry_ring_num=2 then \'red\' end')) + s3.appendSymbolLayer(QgsMarkerLineSymbolLayer()) + s3.symbolLayer(0).subSymbol()[0].setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyFillColor, + QgsProperty.fromExpression( + "case when @geometry_ring_num=0 then 'green' when @geometry_ring_num=1 then 'blue' when @geometry_ring_num=2 then 'red' end" + ), + ) s3.symbolLayer(0).setAverageAngleLength(0) - g = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))') + g = QgsGeometry.fromWkt( + "Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))" + ) rendered_image = self.renderGeometry(s3, g) self.assertTrue( - self.image_check('markerline_ring_num', 'markerline_ring_num', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_ring_num", + "markerline_ring_num", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testPartNum(self): @@ -378,15 +503,20 @@ def testPartNum(self): s = QgsLineSymbol() s.deleteSymbolLayer(0) - sym_layer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'segments_to_lines($geometry)'}) + sym_layer = QgsGeometryGeneratorSymbolLayer.create( + {"geometryModifier": "segments_to_lines($geometry)"} + ) sym_layer.setSymbolType(QgsSymbol.SymbolType.Line) s.appendSymbolLayer(sym_layer) marker_line = QgsMarkerLineSymbolLayer(False) marker_line.setPlacement(QgsMarkerLineSymbolLayer.Placement.FirstVertex) - f = QgsFontUtils.getStandardTestFont('Bold', 24) - marker = QgsFontMarkerSymbolLayer(f.family(), 'x', 24, QColor(255, 255, 0)) - marker.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyCharacter, QgsProperty.fromExpression('@geometry_part_num')) + f = QgsFontUtils.getStandardTestFont("Bold", 24) + marker = QgsFontMarkerSymbolLayer(f.family(), "x", 24, QColor(255, 255, 0)) + marker.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyCharacter, + QgsProperty.fromExpression("@geometry_part_num"), + ) marker_symbol = QgsMarkerSymbol() marker_symbol.changeSymbolLayer(0, marker) marker_line.setSubSymbol(marker_symbol) @@ -396,24 +526,34 @@ def testPartNum(self): sym_layer.setSubSymbol(line_symbol) # rendering test - g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10, 0 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 0, 10 10, 0 10)") rendered_image = self.renderGeometry(s, g, buffer=4) self.assertTrue( - self.image_check('part_num_variable', 'part_num_variable', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "part_num_variable", + "part_num_variable", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) - marker.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyCharacter, - QgsProperty.fromExpression('@geometry_part_count')) + marker.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyCharacter, + QgsProperty.fromExpression("@geometry_part_count"), + ) # rendering test - g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10, 0 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 0, 10 10, 0 10)") rendered_image = self.renderGeometry(s, g, buffer=4) self.assertTrue( - self.image_check('part_count_variable', 'part_count_variable', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "part_count_variable", + "part_count_variable", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testPartNumPolygon(self): @@ -422,9 +562,12 @@ def testPartNumPolygon(self): marker_line = QgsMarkerLineSymbolLayer(False) marker_line.setPlacement(QgsMarkerLineSymbolLayer.Placement.FirstVertex) - f = QgsFontUtils.getStandardTestFont('Bold', 24) - marker = QgsFontMarkerSymbolLayer(f.family(), 'x', 24, QColor(255, 255, 0)) - marker.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyCharacter, QgsProperty.fromExpression('@geometry_part_num')) + f = QgsFontUtils.getStandardTestFont("Bold", 24) + marker = QgsFontMarkerSymbolLayer(f.family(), "x", 24, QColor(255, 255, 0)) + marker.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyCharacter, + QgsProperty.fromExpression("@geometry_part_num"), + ) marker_symbol = QgsMarkerSymbol() marker_symbol.changeSymbolLayer(0, marker) marker_line.setSubSymbol(marker_symbol) @@ -432,12 +575,18 @@ def testPartNumPolygon(self): s.changeSymbolLayer(0, marker_line) # rendering test - a polygon with a smaller part first - g = QgsGeometry.fromWkt('MultiPolygon(((0 0, 2 0, 2 2, 0 0)),((10 0, 10 10, 0 10, 10 0)))') + g = QgsGeometry.fromWkt( + "MultiPolygon(((0 0, 2 0, 2 2, 0 0)),((10 0, 10 10, 0 10, 10 0)))" + ) rendered_image = self.renderGeometry(s, g, buffer=4) self.assertTrue( - self.image_check('poly_part_num_variable', 'poly_part_num_variable', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "poly_part_num_variable", + "poly_part_num_variable", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testCompoundCurve(self): @@ -447,7 +596,9 @@ def testCompoundCurve(self): marker_line = QgsMarkerLineSymbolLayer(True) marker_line.setPlacement(QgsMarkerLineSymbolLayer.Placement.Vertex) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -468,13 +619,19 @@ def testCompoundCurve(self): s.appendSymbolLayer(marker_line2.clone()) # rendering test - g = QgsGeometry.fromWkt('CompoundCurve (CircularString (2606642.3863534671254456 1228883.61571401031687856, 2606656.45901552261784673 1228882.30281259422190487, 2606652.60236761253327131 1228873.80998155777342618, 2606643.65822671446949244 1228875.45110832806676626, 2606642.3863534671254456 1228883.65674217976629734))') + g = QgsGeometry.fromWkt( + "CompoundCurve (CircularString (2606642.3863534671254456 1228883.61571401031687856, 2606656.45901552261784673 1228882.30281259422190487, 2606652.60236761253327131 1228873.80998155777342618, 2606643.65822671446949244 1228875.45110832806676626, 2606642.3863534671254456 1228883.65674217976629734))" + ) self.assertFalse(g.isNull()) rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_compoundcurve', 'markerline_compoundcurve', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_compoundcurve", + "markerline_compoundcurve", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testCompoundCurveInnerVertices(self): @@ -484,7 +641,9 @@ def testCompoundCurveInnerVertices(self): marker_line = QgsMarkerLineSymbolLayer(True) marker_line.setPlacement(QgsMarkerLineSymbolLayer.Placement.InnerVertices) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -494,13 +653,19 @@ def testCompoundCurveInnerVertices(self): s.appendSymbolLayer(marker_line.clone()) # rendering test - g = QgsGeometry.fromWkt('CompoundCurve (CircularString (2606642.3863534671254456 1228883.61571401031687856, 2606656.45901552261784673 1228882.30281259422190487, 2606652.60236761253327131 1228873.80998155777342618, 2606643.65822671446949244 1228875.45110832806676626, 2606642.3863534671254456 1228883.65674217976629734))') + g = QgsGeometry.fromWkt( + "CompoundCurve (CircularString (2606642.3863534671254456 1228883.61571401031687856, 2606656.45901552261784673 1228882.30281259422190487, 2606652.60236761253327131 1228873.80998155777342618, 2606643.65822671446949244 1228875.45110832806676626, 2606642.3863534671254456 1228883.65674217976629734))" + ) self.assertFalse(g.isNull()) rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_compoundcurve_inner_vertices', 'markerline_compoundcurve_inner_vertices', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_compoundcurve_inner_vertices", + "markerline_compoundcurve_inner_vertices", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testMultiCurve(self): @@ -510,7 +675,9 @@ def testMultiCurve(self): marker_line = QgsMarkerLineSymbolLayer(True) marker_line.setPlacement(QgsMarkerLineSymbolLayer.Placement.Vertex) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -531,13 +698,19 @@ def testMultiCurve(self): s.appendSymbolLayer(marker_line2.clone()) # rendering test - g = QgsGeometry.fromWkt('MultiCurve (CompoundCurve (CircularString (2606668.74491960229352117 1228910.0701227153185755, 2606667.84593895543366671 1228899.48981202743016183, 2606678.70285907341167331 1228879.78139015776105225, 2606701.64743852475658059 1228866.43043032777495682, 2606724.96578619908541441 1228864.70617623627185822)),LineString (2606694.16802780656144023 1228913.44624055083841085, 2606716.84054400492459536 1228890.51009044284000993, 2606752.43112175865098834 1228906.59175890940241516))') + g = QgsGeometry.fromWkt( + "MultiCurve (CompoundCurve (CircularString (2606668.74491960229352117 1228910.0701227153185755, 2606667.84593895543366671 1228899.48981202743016183, 2606678.70285907341167331 1228879.78139015776105225, 2606701.64743852475658059 1228866.43043032777495682, 2606724.96578619908541441 1228864.70617623627185822)),LineString (2606694.16802780656144023 1228913.44624055083841085, 2606716.84054400492459536 1228890.51009044284000993, 2606752.43112175865098834 1228906.59175890940241516))" + ) self.assertFalse(g.isNull()) rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_multicurve', 'markerline_multicurve', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_multicurve", + "markerline_multicurve", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testCurvePolygon(self): @@ -547,7 +720,9 @@ def testCurvePolygon(self): marker_line = QgsMarkerLineSymbolLayer(True) marker_line.setPlacement(QgsMarkerLineSymbolLayer.Placement.Vertex) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -568,13 +743,19 @@ def testCurvePolygon(self): s.appendSymbolLayer(marker_line2.clone()) # rendering test - g = QgsGeometry.fromWkt('CurvePolygon (CompoundCurve (CircularString (2606711.1353147104382515 1228875.77055342611856759, 2606715.00784672703593969 1228870.79158369055949152, 2606721.16240653907880187 1228873.35022091586142778),(2606721.16240653907880187 1228873.35022091586142778, 2606711.1353147104382515 1228875.77055342611856759)))') + g = QgsGeometry.fromWkt( + "CurvePolygon (CompoundCurve (CircularString (2606711.1353147104382515 1228875.77055342611856759, 2606715.00784672703593969 1228870.79158369055949152, 2606721.16240653907880187 1228873.35022091586142778),(2606721.16240653907880187 1228873.35022091586142778, 2606711.1353147104382515 1228875.77055342611856759)))" + ) self.assertFalse(g.isNull()) rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_curvepolygon', 'markerline_curvepolygon', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_curvepolygon", + "markerline_curvepolygon", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testMultiSurve(self): @@ -584,7 +765,9 @@ def testMultiSurve(self): marker_line = QgsMarkerLineSymbolLayer(True) marker_line.setPlacement(QgsMarkerLineSymbolLayer.Placement.Vertex) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -605,13 +788,19 @@ def testMultiSurve(self): s.appendSymbolLayer(marker_line2.clone()) # rendering test - g = QgsGeometry.fromWkt('MultiSurface (CurvePolygon (CompoundCurve (CircularString (2606664.83926784340292215 1228868.83649749564938247, 2606666.84044930292293429 1228872.22980518848635256, 2606668.05855975672602654 1228875.62311288132332265, 2606674.45363963954150677 1228870.05460794945247471, 2606680.58769585331901908 1228866.00874108518473804, 2606680.7182076876051724 1228865.05165429995395243, 2606679.97864062618464231 1228864.61661485210061073, 2606671.93041084241122007 1228867.87941071065142751, 2606664.83926784340292215 1228868.79299355088733137),(2606664.83926784340292215 1228868.79299355088733137, 2606664.83926784340292215 1228868.83649749564938247))),Polygon ((2606677.23432376980781555 1228875.74241803237237036, 2606674.27243852382525802 1228874.75512295053340495, 2606675.61874999897554517 1228871.97274590120650828, 2606678.84989754017442465 1228870.35717213083989918, 2606680.64497950719669461 1228873.31905737658962607, 2606677.23432376980781555 1228875.74241803237237036)))') + g = QgsGeometry.fromWkt( + "MultiSurface (CurvePolygon (CompoundCurve (CircularString (2606664.83926784340292215 1228868.83649749564938247, 2606666.84044930292293429 1228872.22980518848635256, 2606668.05855975672602654 1228875.62311288132332265, 2606674.45363963954150677 1228870.05460794945247471, 2606680.58769585331901908 1228866.00874108518473804, 2606680.7182076876051724 1228865.05165429995395243, 2606679.97864062618464231 1228864.61661485210061073, 2606671.93041084241122007 1228867.87941071065142751, 2606664.83926784340292215 1228868.79299355088733137),(2606664.83926784340292215 1228868.79299355088733137, 2606664.83926784340292215 1228868.83649749564938247))),Polygon ((2606677.23432376980781555 1228875.74241803237237036, 2606674.27243852382525802 1228874.75512295053340495, 2606675.61874999897554517 1228871.97274590120650828, 2606678.84989754017442465 1228870.35717213083989918, 2606680.64497950719669461 1228873.31905737658962607, 2606677.23432376980781555 1228875.74241803237237036)))" + ) self.assertFalse(g.isNull()) rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_multisurface', 'markerline_multisurface', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_multisurface", + "markerline_multisurface", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testMultiSurfaceOnePart(self): @@ -621,7 +810,9 @@ def testMultiSurfaceOnePart(self): marker_line = QgsMarkerLineSymbolLayer(True) marker_line.setPlacement(QgsMarkerLineSymbolLayer.Placement.Vertex) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -642,13 +833,19 @@ def testMultiSurfaceOnePart(self): s.appendSymbolLayer(marker_line2.clone()) # rendering test - g = QgsGeometry.fromWkt('MultiSurface (CurvePolygon (CompoundCurve (CircularString (2606664.83926784340292215 1228868.83649749564938247, 2606666.84044930292293429 1228872.22980518848635256, 2606668.05855975672602654 1228875.62311288132332265, 2606674.45363963954150677 1228870.05460794945247471, 2606680.58769585331901908 1228866.00874108518473804, 2606680.7182076876051724 1228865.05165429995395243, 2606679.97864062618464231 1228864.61661485210061073, 2606671.93041084241122007 1228867.87941071065142751, 2606664.83926784340292215 1228868.79299355088733137),(2606664.83926784340292215 1228868.79299355088733137, 2606664.83926784340292215 1228868.83649749564938247))))') + g = QgsGeometry.fromWkt( + "MultiSurface (CurvePolygon (CompoundCurve (CircularString (2606664.83926784340292215 1228868.83649749564938247, 2606666.84044930292293429 1228872.22980518848635256, 2606668.05855975672602654 1228875.62311288132332265, 2606674.45363963954150677 1228870.05460794945247471, 2606680.58769585331901908 1228866.00874108518473804, 2606680.7182076876051724 1228865.05165429995395243, 2606679.97864062618464231 1228864.61661485210061073, 2606671.93041084241122007 1228867.87941071065142751, 2606664.83926784340292215 1228868.79299355088733137),(2606664.83926784340292215 1228868.79299355088733137, 2606664.83926784340292215 1228868.83649749564938247))))" + ) self.assertFalse(g.isNull()) rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_one_part_multisurface', 'markerline_one_part_multisurface', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_one_part_multisurface", + "markerline_one_part_multisurface", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testMarkerAverageAngle(self): @@ -658,7 +855,9 @@ def testMarkerAverageAngle(self): marker_line = QgsMarkerLineSymbolLayer(True) marker_line.setPlacement(QgsTemplatedLineSymbolLayerBase.Placement.Interval) marker_line.setInterval(6) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -670,12 +869,16 @@ def testMarkerAverageAngle(self): s.appendSymbolLayer(marker_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_average_angle', 'markerline_average_angle', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_average_angle", + "markerline_average_angle", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testMarkerAverageAngleRing(self): @@ -685,7 +888,9 @@ def testMarkerAverageAngleRing(self): marker_line = QgsMarkerLineSymbolLayer(True) marker_line.setPlacement(QgsTemplatedLineSymbolLayerBase.Placement.Interval) marker_line.setInterval(6) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -697,12 +902,16 @@ def testMarkerAverageAngleRing(self): s.appendSymbolLayer(marker_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 0 10, 10 10, 10 0, 0 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 0 10, 10 10, 10 0, 0 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_ring_average_angle', 'markerline_ring_average_angle', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_ring_average_angle", + "markerline_ring_average_angle", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testMarkerAverageAngleCenter(self): @@ -711,7 +920,9 @@ def testMarkerAverageAngleCenter(self): marker_line = QgsMarkerLineSymbolLayer(True) marker_line.setPlacement(QgsTemplatedLineSymbolLayerBase.Placement.CentralPoint) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -723,12 +934,16 @@ def testMarkerAverageAngleCenter(self): s.appendSymbolLayer(marker_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_center_average_angle', 'markerline_center_average_angle', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_center_average_angle", + "markerline_center_average_angle", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testRingNoDupe(self): @@ -750,12 +965,16 @@ def testRingNoDupe(self): s.appendSymbolLayer(marker_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 0 10, 10 10, 10 0, 0 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 0 10, 10 10, 10 0, 0 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_ring_no_dupes', 'markerline_ring_no_dupes', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_ring_no_dupes", + "markerline_ring_no_dupes", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testSinglePoint(self): @@ -777,12 +996,16 @@ def testSinglePoint(self): s.appendSymbolLayer(marker_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 0 10, 10 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 0 10, 10 10)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_single', 'markerline_single', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_single", + "markerline_single", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testNoPoint(self): @@ -804,12 +1027,16 @@ def testNoPoint(self): s.appendSymbolLayer(marker_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 0 10, 10 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 0 10, 10 10)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_none', 'markerline_none', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_none", + "markerline_none", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testFirstVertexOffsetPercentage(self): @@ -831,12 +1058,16 @@ def testFirstVertexOffsetPercentage(self): s.appendSymbolLayer(marker_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 0 10, 10 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 0 10, 10 10)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_first_offset_percent', 'markerline_first_offset_percent', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_first_offset_percent", + "markerline_first_offset_percent", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testClosedRingFirstVertexOffsetLarge(self): @@ -861,12 +1092,16 @@ def testClosedRingFirstVertexOffsetLarge(self): s.appendSymbolLayer(marker_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 0 10, 10 10, 0 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 0 10, 10 10, 0 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_first_large_offset', 'markerline_first_large_offset', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_first_large_offset", + "markerline_first_large_offset", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testClosedRingFirstVertexOffsetNegative(self): @@ -891,12 +1126,16 @@ def testClosedRingFirstVertexOffsetNegative(self): s.appendSymbolLayer(marker_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 0 10, 10 10, 0 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 0 10, 10 10, 0 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_first_negative_offset', 'markerline_first_negative_offset', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_first_negative_offset", + "markerline_first_negative_offset", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testIntervalOffsetPercentage(self): @@ -919,12 +1158,16 @@ def testIntervalOffsetPercentage(self): s.appendSymbolLayer(marker_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 0 10, 10 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 0 10, 10 10)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_interval_offset_percent', 'markerline_interval_offset_percent', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_interval_offset_percent", + "markerline_interval_offset_percent", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testClosedRingIntervalOffsetLarge(self): @@ -950,12 +1193,16 @@ def testClosedRingIntervalOffsetLarge(self): s.appendSymbolLayer(marker_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 0 10, 10 10, 0 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 0 10, 10 10, 0 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_interval_large_offset', 'markerline_interval_large_offset', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_interval_large_offset", + "markerline_interval_large_offset", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testClosedRingIntervalOffsetNegative(self): @@ -981,12 +1228,16 @@ def testClosedRingIntervalOffsetNegative(self): s.appendSymbolLayer(marker_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 0 10, 10 10, 0 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 0 10, 10 10, 0 0)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_interval_large_offset', 'markerline_interval_large_offset', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_interval_large_offset", + "markerline_interval_large_offset", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testCenterSegment(self): @@ -994,8 +1245,12 @@ def testCenterSegment(self): s.deleteSymbolLayer(0) marker_line = QgsMarkerLineSymbolLayer(True) - marker_line.setPlacement(QgsTemplatedLineSymbolLayerBase.Placement.SegmentCenter) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker_line.setPlacement( + QgsTemplatedLineSymbolLayerBase.Placement.SegmentCenter + ) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -1006,12 +1261,16 @@ def testCenterSegment(self): s.appendSymbolLayer(marker_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 0 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 0, 0 10)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_segmentcenter', 'markerline_segmentcenter', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_segmentcenter", + "markerline_segmentcenter", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testMarkerDataDefinedAngleLine(self): @@ -1035,12 +1294,16 @@ def testMarkerDataDefinedAngleLine(self): s.appendSymbolLayer(marker_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 20 20)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 20 20)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_center_angle_dd', 'markerline_center_angle_dd', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_center_angle_dd", + "markerline_center_angle_dd", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) # Now with DD @@ -1059,19 +1322,23 @@ def testMarkerDataDefinedAngleLine(self): marker_symbol = QgsMarkerSymbol() marker_symbol.changeSymbolLayer(0, marker) # This is the same value of the reference test - marker_symbol.setDataDefinedAngle(QgsProperty.fromExpression('90')) + marker_symbol.setDataDefinedAngle(QgsProperty.fromExpression("90")) marker_line.setSubSymbol(marker_symbol) line_symbol = QgsLineSymbol() line_symbol.changeSymbolLayer(0, marker_line) s.appendSymbolLayer(marker_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 20 20)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 20 20)") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_center_angle_dd', 'markerline_center_angle_dd', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_center_angle_dd", + "markerline_center_angle_dd", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testDataDefinedAnglePolygon(self): @@ -1080,7 +1347,9 @@ def testDataDefinedAnglePolygon(self): marker_line = QgsMarkerLineSymbolLayer(True) marker_line.setPlacement(QgsMarkerLineSymbolLayer.Placement.SegmentCenter) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker.setAngle(90) @@ -1090,28 +1359,34 @@ def testDataDefinedAnglePolygon(self): s.appendSymbolLayer(marker_line.clone()) - g = QgsGeometry.fromWkt('Polygon (LineString (0 5, 5 0, 10 5, 5 10, 0 5))') + g = QgsGeometry.fromWkt("Polygon (LineString (0 5, 5 0, 10 5, 5 10, 0 5))") self.assertFalse(g.isNull()) # rendering test with non data-defined angle rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_datadefinedanglepolygon', 'markerline_datadefinedanglepolygon', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_datadefinedanglepolygon", + "markerline_datadefinedanglepolygon", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) s = QgsFillSymbol() marker_line = QgsMarkerLineSymbolLayer(True) marker_line.setPlacement(QgsMarkerLineSymbolLayer.Placement.SegmentCenter) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker.setAngle(38) marker_symbol = QgsMarkerSymbol() marker_symbol.changeSymbolLayer(0, marker) - marker_symbol.setDataDefinedAngle(QgsProperty.fromExpression('90')) + marker_symbol.setDataDefinedAngle(QgsProperty.fromExpression("90")) marker_line.setSubSymbol(marker_symbol) s.appendSymbolLayer(marker_line.clone()) @@ -1119,28 +1394,38 @@ def testDataDefinedAnglePolygon(self): # rendering test with data-defined angle rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('markerline_datadefinedanglepolygon', 'markerline_datadefinedanglepolygon', rendered_image, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "markerline_datadefinedanglepolygon", + "markerline_datadefinedanglepolygon", + rendered_image, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testOpacityWithDataDefinedColor(self): - line_shp = os.path.join(TEST_DATA_DIR, 'lines.shp') - line_layer = QgsVectorLayer(line_shp, 'Lines', 'ogr') + line_shp = os.path.join(TEST_DATA_DIR, "lines.shp") + line_layer = QgsVectorLayer(line_shp, "Lines", "ogr") self.assertTrue(line_layer.isValid()) s = QgsLineSymbol() s.deleteSymbolLayer(0) marker_line = QgsMarkerLineSymbolLayer(True) marker_line.setPlacement(QgsTemplatedLineSymbolLayerBase.Placement.CentralPoint) - simple_marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Circle, 10) + simple_marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Circle, 10 + ) simple_marker.setColor(QColor(0, 255, 0)) simple_marker.setStrokeColor(QColor(255, 0, 0)) simple_marker.setStrokeWidth(1) - simple_marker.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyFillColor, QgsProperty.fromExpression( - "if(Name='Arterial', 'red', 'green')")) - simple_marker.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyStrokeColor, QgsProperty.fromExpression( - "if(Name='Arterial', 'magenta', 'blue')")) + simple_marker.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyFillColor, + QgsProperty.fromExpression("if(Name='Arterial', 'red', 'green')"), + ) + simple_marker.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyStrokeColor, + QgsProperty.fromExpression("if(Name='Arterial', 'magenta', 'blue')"), + ) marker_symbol = QgsMarkerSymbol() marker_symbol.changeSymbolLayer(0, simple_marker) @@ -1162,29 +1447,33 @@ def testOpacityWithDataDefinedColor(self): # Test rendering self.assertTrue( self.render_map_settings_check( - 'markerline_opacityddcolor', - 'markerline_opacityddcolor', - ms + "markerline_opacityddcolor", "markerline_opacityddcolor", ms ) ) def testDataDefinedOpacity(self): - line_shp = os.path.join(TEST_DATA_DIR, 'lines.shp') - line_layer = QgsVectorLayer(line_shp, 'Lines', 'ogr') + line_shp = os.path.join(TEST_DATA_DIR, "lines.shp") + line_layer = QgsVectorLayer(line_shp, "Lines", "ogr") self.assertTrue(line_layer.isValid()) s = QgsLineSymbol() s.deleteSymbolLayer(0) marker_line = QgsMarkerLineSymbolLayer(True) marker_line.setPlacement(QgsTemplatedLineSymbolLayerBase.Placement.CentralPoint) - simple_marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Circle, 10) + simple_marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Circle, 10 + ) simple_marker.setColor(QColor(0, 255, 0)) simple_marker.setStrokeColor(QColor(255, 0, 0)) simple_marker.setStrokeWidth(1) - simple_marker.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyFillColor, QgsProperty.fromExpression( - "if(Name='Arterial', 'red', 'green')")) - simple_marker.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyStrokeColor, QgsProperty.fromExpression( - "if(Name='Arterial', 'magenta', 'blue')")) + simple_marker.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyFillColor, + QgsProperty.fromExpression("if(Name='Arterial', 'red', 'green')"), + ) + simple_marker.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyStrokeColor, + QgsProperty.fromExpression("if(Name='Arterial', 'magenta', 'blue')"), + ) marker_symbol = QgsMarkerSymbol() marker_symbol.changeSymbolLayer(0, simple_marker) @@ -1192,7 +1481,10 @@ def testDataDefinedOpacity(self): marker_line.setSubSymbol(marker_symbol) s.appendSymbolLayer(marker_line.clone()) - s.setDataDefinedProperty(QgsSymbol.Property.PropertyOpacity, QgsProperty.fromExpression("if(\"Value\" = 1, 25, 50)")) + s.setDataDefinedProperty( + QgsSymbol.Property.PropertyOpacity, + QgsProperty.fromExpression('if("Value" = 1, 25, 50)'), + ) line_layer.setRenderer(QgsSingleSymbolRenderer(s)) @@ -1205,9 +1497,7 @@ def testDataDefinedOpacity(self): # Test rendering self.assertTrue( self.render_map_settings_check( - 'markerline_ddopacity', - 'markerline_ddopacity', - ms + "markerline_ddopacity", "markerline_ddopacity", ms ) ) @@ -1245,5 +1535,5 @@ def renderGeometry(self, symbol, geom, buffer=20): return image -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmaskrendersettings.py b/tests/src/python/test_qgsmaskrendersettings.py index 808c836dd7d1..0f3c99e0e0ba 100644 --- a/tests/src/python/test_qgsmaskrendersettings.py +++ b/tests/src/python/test_qgsmaskrendersettings.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2024-06' -__copyright__ = 'Copyright 2024, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2024-06" +__copyright__ = "Copyright 2024, The QGIS Project" from qgis.core import QgsMaskRenderSettings @@ -23,5 +24,5 @@ def testGetSet(self): self.assertEqual(settings.simplifyTolerance(), 10) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmatrix4x4.py b/tests/src/python/test_qgsmatrix4x4.py index c5891bdcf3df..2f2df20da260 100644 --- a/tests/src/python/test_qgsmatrix4x4.py +++ b/tests/src/python/test_qgsmatrix4x4.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2023 by Martin Dobias' -__date__ = '18/07/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "(C) 2023 by Martin Dobias" +__date__ = "18/07/2023" +__copyright__ = "Copyright 2023, The QGIS Project" from qgis.core import ( Qgis, @@ -27,54 +28,62 @@ class TestQgsMatrix4x4(QgisTestCase): def test_basic(self): m0 = QgsMatrix4x4() - self.assertEqual(m0.data(), [1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1.]) + self.assertEqual( + m0.data(), + [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + ], + ) - m1 = QgsMatrix4x4(1, 2, 3, 4, - 5, 6, 7, 8, - 9, 10, 11, 12, - 0, 0, 0, 1) + m1 = QgsMatrix4x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 0, 1) self.assertEqual(m1.data(), [1, 5, 9, 0, 2, 6, 10, 0, 3, 7, 11, 0, 4, 8, 12, 1]) self.assertEqual(m1.map(QgsVector3D(10, 20, 30)), QgsVector3D(144, 388, 632)) self.assertEqual(m1 * QgsVector3D(10, 20, 30), QgsVector3D(144, 388, 632)) - m2 = QgsMatrix4x4(2, 0, 0, 0, - 0, 2, 0, 0, - 0, 0, 2, 0, - 0, 0, 0, 1) + m2 = QgsMatrix4x4(2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1) m3 = m1 * m2 - self.assertEqual(m3.data(), [2, 10, 18, 0, 4, 12, 20, 0, 6, 14, 22, 0, 4, 8, 12, 1]) + self.assertEqual( + m3.data(), [2, 10, 18, 0, 4, 12, 20, 0, 6, 14, 22, 0, 4, 8, 12, 1] + ) def test_repr(self): self.assertEqual( - str(QgsMatrix4x4(1, 2, 3, 4, - 5, 6, 7, 8, - 9, 10, 11, 12, - 13, 14, 15, 16)), - '' + str(QgsMatrix4x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)), + "", ) def test_equality(self): self.assertEqual( - QgsMatrix4x4(1, 2, 3, 4, - 5, 6, 7, 8, - 9, 10, 11, 12, - 13, 14, 15, 16), - QgsMatrix4x4(1, 2, 3, 4, - 5, 6, 7, 8, - 9, 10, 11, 12, - 13, 14, 15, 16) + QgsMatrix4x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), + QgsMatrix4x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), ) for i in range(16): self.assertNotEqual( - QgsMatrix4x4(1, 2, 3, 4, - 5, 6, 7, 8, - 9, 10, 11, 12, - 13, 14, 15, 16), - QgsMatrix4x4(*[j if k != i else 0 for k, j in enumerate([1, 2, 3, 4, - 5, 6, 7, 8, - 9, 10, 11, 12, - 13, 14, 15, 16])]) + QgsMatrix4x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), + QgsMatrix4x4( + *[ + j if k != i else 0 + for k, j in enumerate( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] + ) + ] + ), ) def test_translate(self): @@ -83,16 +92,53 @@ def test_translate(self): """ m = QgsMatrix4x4() m.translate(QgsVector3D(1, 2, 3)) - self.assertEqual(m.data(), [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 2.0, 3.0, 1.0]) + self.assertEqual( + m.data(), + [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 1.0, + 2.0, + 3.0, + 1.0, + ], + ) - m = QgsMatrix4x4(1, 2, 3, 4, - 5, 6, 7, 8, - 9, 10, 11, 12, - 0, 0, 0, 1) + m = QgsMatrix4x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 0, 1) m.translate(QgsVector3D(1, 2, 3)) - self.assertEqual(m.data(), [1.0, 5.0, 9.0, 0.0, 2.0, 6.0, 10.0, 0.0, 3.0, 7.0, 11.0, 0.0, 18.0, 46.0, 74.0, 1.0]) + self.assertEqual( + m.data(), + [ + 1.0, + 5.0, + 9.0, + 0.0, + 2.0, + 6.0, + 10.0, + 0.0, + 3.0, + 7.0, + 11.0, + 0.0, + 18.0, + 46.0, + 74.0, + 1.0, + ], + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmediawidget.py b/tests/src/python/test_qgsmediawidget.py index 83889986f1e2..57b9903e4c7a 100644 --- a/tests/src/python/test_qgsmediawidget.py +++ b/tests/src/python/test_qgsmediawidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Mathieu Pellerin' -__date__ = '25/01/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "Mathieu Pellerin" +__date__ = "25/01/2023" +__copyright__ = "Copyright 2023, The QGIS Project" from qgis.gui import QgsMediaWidget @@ -25,9 +26,9 @@ def testMediaPath(self): """ mw = QgsMediaWidget() - self.assertEqual(mw.mediaPath(), '') - mw.setMediaPath('/home/my.mp3') - self.assertEqual(mw.mediaPath(), '/home/my.mp3') + self.assertEqual(mw.mediaPath(), "") + mw.setMediaPath("/home/my.mp3") + self.assertEqual(mw.mediaPath(), "/home/my.mp3") def testMode(self): """ @@ -49,5 +50,5 @@ def testLinkProjectColor(self): self.assertEqual(mw.videoHeight(), 222) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmergedfeaturerenderer.py b/tests/src/python/test_qgsmergedfeaturerenderer.py index 2f038631e215..ec6aecf7a025 100644 --- a/tests/src/python/test_qgsmergedfeaturerenderer.py +++ b/tests/src/python/test_qgsmergedfeaturerenderer.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '30/12/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "30/12/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import os @@ -44,15 +45,19 @@ def control_path_prefix(cls): def test_legend_keys(self): symbol1 = QgsFillSymbol() symbol2 = QgsFillSymbol() - sub_renderer = QgsCategorizedSymbolRenderer('cat', [QgsRendererCategory('cat1', symbol1, 'cat1', True, '0'), - QgsRendererCategory('cat2', symbol2, 'cat2', True, '1') - ]) + sub_renderer = QgsCategorizedSymbolRenderer( + "cat", + [ + QgsRendererCategory("cat1", symbol1, "cat1", True, "0"), + QgsRendererCategory("cat2", symbol2, "cat2", True, "1"), + ], + ) renderer = QgsMergedFeatureRenderer(sub_renderer) - self.assertEqual(renderer.legendKeys(), {'0', '1'}) + self.assertEqual(renderer.legendKeys(), {"0", "1"}) def testSinglePolys(self): - source = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'polys_overlapping.shp')) + source = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "polys_overlapping.shp")) self.assertTrue(source.isValid()) map_settings = QgsMapSettings() map_settings.setExtent(source.extent()) @@ -70,13 +75,19 @@ def testSinglePolys(self): map_settings.setOutputDpi(96) self.assertTrue( - self.render_map_settings_check('single_subrenderer', 'single_subrenderer', map_settings, - color_tolerance=2, - allowed_mismatch=20) + self.render_map_settings_check( + "single_subrenderer", + "single_subrenderer", + map_settings, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testCategorizedPolys(self): - source = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'polys_overlapping_with_cat.shp')) + source = QgsVectorLayer( + os.path.join(TEST_DATA_DIR, "polys_overlapping_with_cat.shp") + ) self.assertTrue(source.isValid()) map_settings = QgsMapSettings() map_settings.setExtent(source.extent()) @@ -97,20 +108,28 @@ def testCategorizedPolys(self): symbol2 = QgsFillSymbol() symbol2.changeSymbolLayer(0, layer) - sub_renderer = QgsCategorizedSymbolRenderer('cat', [QgsRendererCategory('cat1', symbol1, 'cat1'), - QgsRendererCategory('cat2', symbol2, 'cat2') - ]) + sub_renderer = QgsCategorizedSymbolRenderer( + "cat", + [ + QgsRendererCategory("cat1", symbol1, "cat1"), + QgsRendererCategory("cat2", symbol2, "cat2"), + ], + ) source.setRenderer(QgsMergedFeatureRenderer(sub_renderer)) map_settings.setOutputDpi(96) self.assertTrue( - self.render_map_settings_check('polys_categorizedrenderer', 'polys_categorizedrenderer', map_settings, - color_tolerance=2, - allowed_mismatch=20) + self.render_map_settings_check( + "polys_categorizedrenderer", + "polys_categorizedrenderer", + map_settings, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testSingleLines(self): - source = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'lines_touching.shp')) + source = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "lines_touching.shp")) self.assertTrue(source.isValid()) map_settings = QgsMapSettings() map_settings.setExtent(source.extent().buffered(2)) @@ -124,7 +143,9 @@ def testSingleLines(self): layer2 = QgsMarkerLineSymbolLayer() layer2.setPlacement(QgsTemplatedLineSymbolLayerBase.Placement.FirstVertex) - marker = QgsMarkerSymbol.createSimple({'size': '4', 'color': '255,0,0', 'outline_style': 'no'}) + marker = QgsMarkerSymbol.createSimple( + {"size": "4", "color": "255,0,0", "outline_style": "no"} + ) layer2.setSubSymbol(marker) symbol.appendSymbolLayer(layer2) @@ -133,13 +154,17 @@ def testSingleLines(self): map_settings.setOutputDpi(96) self.assertTrue( - self.render_map_settings_check('lines_single_subrenderer', 'lines_single_subrenderer', map_settings, - color_tolerance=2, - allowed_mismatch=20) + self.render_map_settings_check( + "lines_single_subrenderer", + "lines_single_subrenderer", + map_settings, + color_tolerance=2, + allowed_mismatch=20, + ) ) def testLinesCategorized(self): - source = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'lines_touching.shp')) + source = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "lines_touching.shp")) self.assertTrue(source.isValid()) map_settings = QgsMapSettings() map_settings.setExtent(source.extent().buffered(2)) @@ -154,7 +179,9 @@ def testLinesCategorized(self): layer2 = QgsMarkerLineSymbolLayer() layer2.setPlacement(QgsTemplatedLineSymbolLayerBase.Placement.FirstVertex) - marker = QgsMarkerSymbol.createSimple({'size': '4', 'color': '255,0,0', 'outline_style': 'no'}) + marker = QgsMarkerSymbol.createSimple( + {"size": "4", "color": "255,0,0", "outline_style": "no"} + ) layer2.setSubSymbol(marker) symbol1.appendSymbolLayer(layer2) @@ -162,36 +189,48 @@ def testLinesCategorized(self): symbol2.changeSymbolLayer(0, layer.clone()) layer2 = QgsMarkerLineSymbolLayer() layer2.setPlacement(QgsTemplatedLineSymbolLayerBase.Placement.FirstVertex) - marker = QgsMarkerSymbol.createSimple({'size': '4', 'color': '0,255,0', 'outline_style': 'no'}) + marker = QgsMarkerSymbol.createSimple( + {"size": "4", "color": "0,255,0", "outline_style": "no"} + ) layer2.setSubSymbol(marker) symbol2.appendSymbolLayer(layer2) - sub_renderer = QgsCategorizedSymbolRenderer('cat', [QgsRendererCategory('cat1', symbol1, 'cat1'), - QgsRendererCategory('cat2', symbol2, 'cat2') - ]) + sub_renderer = QgsCategorizedSymbolRenderer( + "cat", + [ + QgsRendererCategory("cat1", symbol1, "cat1"), + QgsRendererCategory("cat2", symbol2, "cat2"), + ], + ) source.setRenderer(QgsMergedFeatureRenderer(sub_renderer)) map_settings.setOutputDpi(96) self.assertTrue( - self.render_map_settings_check('lines_categorized_subrenderer', 'lines_categorized_subrenderer', map_settings, - color_tolerance=2, - allowed_mismatch=20) + self.render_map_settings_check( + "lines_categorized_subrenderer", + "lines_categorized_subrenderer", + map_settings, + color_tolerance=2, + allowed_mismatch=20, + ) ) def test_legend_key_to_expression(self): - sym1 = QgsFillSymbol.createSimple({'color': '#fdbf6f', 'outline_color': 'black'}) + sym1 = QgsFillSymbol.createSimple( + {"color": "#fdbf6f", "outline_color": "black"} + ) sub_renderer = QgsSingleSymbolRenderer(sym1) renderer = QgsMergedFeatureRenderer(sub_renderer) - exp, ok = renderer.legendKeyToExpression('0', None) + exp, ok = renderer.legendKeyToExpression("0", None) self.assertTrue(ok) - self.assertEqual(exp, 'TRUE') + self.assertEqual(exp, "TRUE") - exp, ok = renderer.legendKeyToExpression('xxxx', None) + exp, ok = renderer.legendKeyToExpression("xxxx", None) self.assertFalse(ok) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmesh3dsymbol.py b/tests/src/python/test_qgsmesh3dsymbol.py index 7d20e164c1a8..5f4fab240e37 100644 --- a/tests/src/python/test_qgsmesh3dsymbol.py +++ b/tests/src/python/test_qgsmesh3dsymbol.py @@ -5,13 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + from qgis.PyQt.QtCore import Qt from qgis.PyQt.QtGui import QColor -from qgis.core import ( - Qgis, - QgsProperty, - QgsAbstract3DSymbol -) +from qgis.core import Qgis, QgsProperty, QgsAbstract3DSymbol from qgis._3d import ( QgsMesh3DSymbol, Qgs3DTypes, @@ -41,11 +38,9 @@ def test_getters_and_setters(self): self.assertEqual(symbol.cullingMode(), Qgs3DTypes.Front) # Test altitude clamping - self.assertEqual(symbol.altitudeClamping(), - Qgis.AltitudeClamping.Relative) + self.assertEqual(symbol.altitudeClamping(), Qgis.AltitudeClamping.Relative) symbol.setAltitudeClamping(Qgis.AltitudeClamping.Absolute) - self.assertEqual(symbol.altitudeClamping(), - Qgis.AltitudeClamping.Absolute) + self.assertEqual(symbol.altitudeClamping(), Qgis.AltitudeClamping.Absolute) # Test height self.assertEqual(symbol.height(), 0.0) @@ -91,11 +86,13 @@ def test_getters_and_setters(self): self.assertTrue(symbol.isVerticalMagnitudeRelative()) # Test rendering style - self.assertEqual(symbol.renderingStyle(), - QgsMesh3DSymbol.RenderingStyle.SingleColor) + self.assertEqual( + symbol.renderingStyle(), QgsMesh3DSymbol.RenderingStyle.SingleColor + ) symbol.setRenderingStyle(QgsMesh3DSymbol.RenderingStyle.ColorRamp) - self.assertEqual(symbol.renderingStyle(), - QgsMesh3DSymbol.RenderingStyle.ColorRamp) + self.assertEqual( + symbol.renderingStyle(), QgsMesh3DSymbol.RenderingStyle.ColorRamp + ) default_color = QColor(Qt.GlobalColor.darkGreen) self.assertEqual(symbol.singleMeshColor(), default_color) @@ -126,8 +123,15 @@ def test_getters_and_setters(self): symbol.setLevelOfDetailIndex(1) self.assertEqual(symbol.levelOfDetailIndex(), 1) - symbol.dataDefinedProperties().setProperty(QgsAbstract3DSymbol.Property.Height, QgsProperty.fromExpression('1+2')) - self.assertEqual(symbol.dataDefinedProperties().property(QgsAbstract3DSymbol.Property.Height).asExpression(), '1+2') + symbol.dataDefinedProperties().setProperty( + QgsAbstract3DSymbol.Property.Height, QgsProperty.fromExpression("1+2") + ) + self.assertEqual( + symbol.dataDefinedProperties() + .property(QgsAbstract3DSymbol.Property.Height) + .asExpression(), + "1+2", + ) def test_equality(self): symbol1 = QgsMesh3DSymbol() @@ -249,9 +253,11 @@ def test_equality(self): symbol2.setLevelOfDetailIndex(0) self.assertEqual(symbol1, symbol2) - symbol2.dataDefinedProperties().setProperty(QgsAbstract3DSymbol.Property.Height, QgsProperty.fromExpression('1+2')) + symbol2.dataDefinedProperties().setProperty( + QgsAbstract3DSymbol.Property.Height, QgsProperty.fromExpression("1+2") + ) self.assertNotEqual(symbol1, symbol2) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmeshlayer.py b/tests/src/python/test_qgsmeshlayer.py index ac023360fddf..7ec446be73ab 100644 --- a/tests/src/python/test_qgsmeshlayer.py +++ b/tests/src/python/test_qgsmeshlayer.py @@ -6,10 +6,7 @@ (at your option) any later version. """ -from qgis.core import ( - QgsMeshLayer, - QgsMeshDatasetIndex -) +from qgis.core import QgsMeshLayer, QgsMeshDatasetIndex import unittest from qgis.testing import start_app, QgisTestCase @@ -23,46 +20,49 @@ def test_dataset_group_metadata(self): Test datasetGroupMetadata """ layer = QgsMeshLayer( - self.get_test_data_path('mesh/netcdf_parent_quantity.nc').as_posix(), - 'mesh', - 'mdal' + self.get_test_data_path("mesh/netcdf_parent_quantity.nc").as_posix(), + "mesh", + "mdal", ) self.assertTrue(layer.isValid()) self.assertEqual( layer.datasetGroupMetadata(QgsMeshDatasetIndex(0)).name(), - 'air_temperature_height:10') + "air_temperature_height:10", + ) self.assertEqual( - layer.datasetGroupMetadata( - QgsMeshDatasetIndex(0)).parentQuantityName(), - 'air_temperature_height') + layer.datasetGroupMetadata(QgsMeshDatasetIndex(0)).parentQuantityName(), + "air_temperature_height", + ) self.assertEqual( layer.datasetGroupMetadata(QgsMeshDatasetIndex(1)).name(), - 'air_temperature_height:20') + "air_temperature_height:20", + ) self.assertEqual( - layer.datasetGroupMetadata( - QgsMeshDatasetIndex(1)).parentQuantityName(), - 'air_temperature_height') + layer.datasetGroupMetadata(QgsMeshDatasetIndex(1)).parentQuantityName(), + "air_temperature_height", + ) self.assertEqual( layer.datasetGroupMetadata(QgsMeshDatasetIndex(2)).name(), - 'air_temperature_height:30') + "air_temperature_height:30", + ) self.assertEqual( - layer.datasetGroupMetadata( - QgsMeshDatasetIndex(2)).parentQuantityName(), - 'air_temperature_height') + layer.datasetGroupMetadata(QgsMeshDatasetIndex(2)).parentQuantityName(), + "air_temperature_height", + ) self.assertEqual( layer.datasetGroupMetadata(QgsMeshDatasetIndex(3)).name(), - 'air_temperature_height:5') + "air_temperature_height:5", + ) self.assertEqual( - layer.datasetGroupMetadata( - QgsMeshDatasetIndex(3)).parentQuantityName(), - 'air_temperature_height') - self.assertFalse( - layer.datasetGroupMetadata(QgsMeshDatasetIndex(4)).name()) + layer.datasetGroupMetadata(QgsMeshDatasetIndex(3)).parentQuantityName(), + "air_temperature_height", + ) + self.assertFalse(layer.datasetGroupMetadata(QgsMeshDatasetIndex(4)).name()) self.assertFalse( - layer.datasetGroupMetadata( - QgsMeshDatasetIndex(4)).parentQuantityName()) + layer.datasetGroupMetadata(QgsMeshDatasetIndex(4)).parentQuantityName() + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmeshlayerelevationproperties.py b/tests/src/python/test_qgsmeshlayerelevationproperties.py index e462cf0cd5f0..417295b1f17c 100644 --- a/tests/src/python/test_qgsmeshlayerelevationproperties.py +++ b/tests/src/python/test_qgsmeshlayerelevationproperties.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '09/11/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "09/11/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtXml import QDomDocument from qgis.core import ( @@ -16,7 +17,7 @@ QgsLineSymbol, QgsMeshLayerElevationProperties, QgsReadWriteContext, - QgsDoubleRange + QgsDoubleRange, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -28,8 +29,7 @@ class TestQgsMeshLayerElevationProperties(QgisTestCase): def testBasic(self): props = QgsMeshLayerElevationProperties(None) - self.assertEqual(props.mode(), - Qgis.MeshElevationMode.FromVertices) + self.assertEqual(props.mode(), Qgis.MeshElevationMode.FromVertices) self.assertEqual(props.zScale(), 1) self.assertEqual(props.zOffset(), 0) @@ -46,40 +46,46 @@ def testBasic(self): self.assertEqual(props.zScale(), 2) self.assertEqual(props.zOffset(), 0.5) self.assertTrue(props.hasElevation()) - self.assertEqual(props.profileSymbology(), Qgis.ProfileSurfaceSymbology.FillBelow) + self.assertEqual( + props.profileSymbology(), Qgis.ProfileSurfaceSymbology.FillBelow + ) self.assertEqual(props.elevationLimit(), 909) - sym = QgsLineSymbol.createSimple({'outline_color': '#ff4433', 'outline_width': 0.5}) + sym = QgsLineSymbol.createSimple( + {"outline_color": "#ff4433", "outline_width": 0.5} + ) props.setProfileLineSymbol(sym) - self.assertEqual(props.profileLineSymbol().color().name(), '#ff4433') + self.assertEqual(props.profileLineSymbol().color().name(), "#ff4433") - sym = QgsFillSymbol.createSimple({'color': '#ff44ff'}) + sym = QgsFillSymbol.createSimple({"color": "#ff44ff"}) props.setProfileFillSymbol(sym) - self.assertEqual(props.profileFillSymbol().color().name(), '#ff44ff') + self.assertEqual(props.profileFillSymbol().color().name(), "#ff44ff") doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsMeshLayerElevationProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.mode(), - Qgis.MeshElevationMode.FromVertices) + self.assertEqual(props2.mode(), Qgis.MeshElevationMode.FromVertices) self.assertEqual(props2.zScale(), 2) self.assertEqual(props2.zOffset(), 0.5) - self.assertEqual(props2.profileLineSymbol().color().name(), '#ff4433') - self.assertEqual(props2.profileFillSymbol().color().name(), '#ff44ff') - self.assertEqual(props2.profileSymbology(), Qgis.ProfileSurfaceSymbology.FillBelow) + self.assertEqual(props2.profileLineSymbol().color().name(), "#ff4433") + self.assertEqual(props2.profileFillSymbol().color().name(), "#ff44ff") + self.assertEqual( + props2.profileSymbology(), Qgis.ProfileSurfaceSymbology.FillBelow + ) self.assertEqual(props2.elevationLimit(), 909) props2 = props.clone() - self.assertEqual(props2.mode(), - Qgis.MeshElevationMode.FromVertices) + self.assertEqual(props2.mode(), Qgis.MeshElevationMode.FromVertices) self.assertEqual(props2.zScale(), 2) self.assertEqual(props2.zOffset(), 0.5) - self.assertEqual(props2.profileLineSymbol().color().name(), '#ff4433') - self.assertEqual(props2.profileFillSymbol().color().name(), '#ff44ff') - self.assertEqual(props2.profileSymbology(), Qgis.ProfileSurfaceSymbology.FillBelow) + self.assertEqual(props2.profileLineSymbol().color().name(), "#ff4433") + self.assertEqual(props2.profileFillSymbol().color().name(), "#ff44ff") + self.assertEqual( + props2.profileSymbology(), Qgis.ProfileSurfaceSymbology.FillBelow + ) self.assertEqual(props2.elevationLimit(), 909) def test_basic_fixed_range(self): @@ -95,8 +101,7 @@ def test_basic_fixed_range(self): props.setZOffset(0.5) props.setZScale(2) self.assertEqual(props.fixedRange(), QgsDoubleRange(103.1, 106.8)) - self.assertEqual(props.calculateZRange(None), - QgsDoubleRange(103.1, 106.8)) + self.assertEqual(props.calculateZRange(None), QgsDoubleRange(103.1, 106.8)) self.assertEqual(props.significantZValues(None), [103.1, 106.8]) self.assertFalse(props.isVisibleInZRange(QgsDoubleRange(3.1, 6.8))) self.assertTrue(props.isVisibleInZRange(QgsDoubleRange(3.1, 104.8))) @@ -104,45 +109,45 @@ def test_basic_fixed_range(self): self.assertFalse(props.isVisibleInZRange(QgsDoubleRange(114.8, 124.8))) doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsMeshLayerElevationProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.mode(), - Qgis.MeshElevationMode.FixedElevationRange) + self.assertEqual(props2.mode(), Qgis.MeshElevationMode.FixedElevationRange) self.assertEqual(props2.fixedRange(), QgsDoubleRange(103.1, 106.8)) props2 = props.clone() - self.assertEqual(props2.mode(), - Qgis.MeshElevationMode.FixedElevationRange) + self.assertEqual(props2.mode(), Qgis.MeshElevationMode.FixedElevationRange) self.assertEqual(props2.fixedRange(), QgsDoubleRange(103.1, 106.8)) # include lower, exclude upper - props.setFixedRange(QgsDoubleRange(103.1, 106.8, - includeLower=True, - includeUpper=False)) - elem = doc.createElement('test') + props.setFixedRange( + QgsDoubleRange(103.1, 106.8, includeLower=True, includeUpper=False) + ) + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsMeshLayerElevationProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.fixedRange(), QgsDoubleRange(103.1, 106.8, - includeLower=True, - includeUpper=False)) + self.assertEqual( + props2.fixedRange(), + QgsDoubleRange(103.1, 106.8, includeLower=True, includeUpper=False), + ) # exclude lower, include upper - props.setFixedRange(QgsDoubleRange(103.1, 106.8, - includeLower=False, - includeUpper=True)) - elem = doc.createElement('test') + props.setFixedRange( + QgsDoubleRange(103.1, 106.8, includeLower=False, includeUpper=True) + ) + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsMeshLayerElevationProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.fixedRange(), QgsDoubleRange(103.1, 106.8, - includeLower=False, - includeUpper=True)) + self.assertEqual( + props2.fixedRange(), + QgsDoubleRange(103.1, 106.8, includeLower=False, includeUpper=True), + ) def test_basic_fixed_range_per_group(self): """ @@ -152,19 +157,26 @@ def test_basic_fixed_range_per_group(self): self.assertFalse(props.fixedRangePerGroup()) props.setMode(Qgis.MeshElevationMode.FixedRangePerGroup) - props.setFixedRangePerGroup({1: QgsDoubleRange(103.1, 106.8), - 2: QgsDoubleRange(106.8, 116.8), - 3: QgsDoubleRange(116.8, 126.8)}) + props.setFixedRangePerGroup( + { + 1: QgsDoubleRange(103.1, 106.8), + 2: QgsDoubleRange(106.8, 116.8), + 3: QgsDoubleRange(116.8, 126.8), + } + ) # fixed ranges should not be affected by scale/offset props.setZOffset(0.5) props.setZScale(2) - self.assertEqual(props.fixedRangePerGroup(), {1: QgsDoubleRange(103.1, 106.8), - 2: QgsDoubleRange(106.8, 116.8), - 3: QgsDoubleRange(116.8, 126.8)}) - self.assertEqual(props.calculateZRange(None), - QgsDoubleRange(103.1, 126.8)) - self.assertEqual(props.significantZValues(None), - [103.1, 106.8, 116.8, 126.8]) + self.assertEqual( + props.fixedRangePerGroup(), + { + 1: QgsDoubleRange(103.1, 106.8), + 2: QgsDoubleRange(106.8, 116.8), + 3: QgsDoubleRange(116.8, 126.8), + }, + ) + self.assertEqual(props.calculateZRange(None), QgsDoubleRange(103.1, 126.8)) + self.assertEqual(props.significantZValues(None), [103.1, 106.8, 116.8, 126.8]) self.assertFalse(props.isVisibleInZRange(QgsDoubleRange(3.1, 6.8))) self.assertTrue(props.isVisibleInZRange(QgsDoubleRange(3.1, 104.8))) self.assertTrue(props.isVisibleInZRange(QgsDoubleRange(104.8, 114.8))) @@ -172,50 +184,60 @@ def test_basic_fixed_range_per_group(self): self.assertFalse(props.isVisibleInZRange(QgsDoubleRange(128.8, 134.8))) doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsMeshLayerElevationProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.mode(), - Qgis.MeshElevationMode.FixedRangePerGroup) - self.assertEqual(props2.fixedRangePerGroup(), {1: QgsDoubleRange(103.1, 106.8), - 2: QgsDoubleRange(106.8, 116.8), - 3: QgsDoubleRange(116.8, 126.8)}) + self.assertEqual(props2.mode(), Qgis.MeshElevationMode.FixedRangePerGroup) + self.assertEqual( + props2.fixedRangePerGroup(), + { + 1: QgsDoubleRange(103.1, 106.8), + 2: QgsDoubleRange(106.8, 116.8), + 3: QgsDoubleRange(116.8, 126.8), + }, + ) props2 = props.clone() - self.assertEqual(props2.mode(), - Qgis.MeshElevationMode.FixedRangePerGroup) - self.assertEqual(props2.fixedRangePerGroup(), {1: QgsDoubleRange(103.1, 106.8), - 2: QgsDoubleRange(106.8, 116.8), - 3: QgsDoubleRange(116.8, 126.8)}) + self.assertEqual(props2.mode(), Qgis.MeshElevationMode.FixedRangePerGroup) + self.assertEqual( + props2.fixedRangePerGroup(), + { + 1: QgsDoubleRange(103.1, 106.8), + 2: QgsDoubleRange(106.8, 116.8), + 3: QgsDoubleRange(116.8, 126.8), + }, + ) # include lower, exclude upper - props.setFixedRangePerGroup({1: QgsDoubleRange(103.1, 106.8, - includeLower=True, - includeUpper=False)}) - elem = doc.createElement('test') + props.setFixedRangePerGroup( + {1: QgsDoubleRange(103.1, 106.8, includeLower=True, includeUpper=False)} + ) + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsMeshLayerElevationProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.fixedRangePerGroup(), {1: QgsDoubleRange(103.1, 106.8, - includeLower=True, - includeUpper=False)}) + self.assertEqual( + props2.fixedRangePerGroup(), + {1: QgsDoubleRange(103.1, 106.8, includeLower=True, includeUpper=False)}, + ) # exclude lower, include upper - props.setFixedRangePerGroup({1: QgsDoubleRange(103.1, 106.8, - includeLower=False, - includeUpper=True)}) - elem = doc.createElement('test') + props.setFixedRangePerGroup( + {1: QgsDoubleRange(103.1, 106.8, includeLower=False, includeUpper=True)} + ) + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsMeshLayerElevationProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.fixedRangePerGroup(), {1: QgsDoubleRange(103.1, 106.8, - includeLower=False, - includeUpper=True)}) + self.assertEqual( + props2.fixedRangePerGroup(), + {1: QgsDoubleRange(103.1, 106.8, includeLower=False, includeUpper=True)}, + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmeshlayerlabeling.py b/tests/src/python/test_qgsmeshlayerlabeling.py index 38be76702a0a..38eb1d8bbd2d 100644 --- a/tests/src/python/test_qgsmeshlayerlabeling.py +++ b/tests/src/python/test_qgsmeshlayerlabeling.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Stefanos Natsis' -__date__ = '2024-01' -__copyright__ = 'Copyright 2024, The QGIS Project' + +__author__ = "Stefanos Natsis" +__date__ = "2024-01" +__copyright__ = "Copyright 2024, The QGIS Project" import os @@ -20,7 +21,7 @@ QgsFontUtils, QgsMapSettings, QgsMeshLayer, - QgsMeshLayerSimpleLabeling + QgsMeshLayerSimpleLabeling, ) import unittest from utilities import unitTestDataPath @@ -36,14 +37,16 @@ def control_path_prefix(cls): return "mesh_labeling" def testSimpleLabelVertices(self): - ml = QgsMeshLayer(os.path.join(unitTestDataPath(), 'mesh', 'quad_flower.2dm'), 'mdal', 'mdal') + ml = QgsMeshLayer( + os.path.join(unitTestDataPath(), "mesh", "quad_flower.2dm"), "mdal", "mdal" + ) self.assertTrue(ml.isValid()) - ml.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + ml.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) ms = QgsMapSettings() ms.setOutputSize(QSize(400, 400)) ms.setOutputDpi(96) - ms.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + ms.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) ms.setExtent(ml.extent().buffered(200)) ms.setLayers([ml]) @@ -51,7 +54,7 @@ def testSimpleLabelVertices(self): s.fieldName = "$vertex_index" s.isExpression = True f = s.format() - f.setFont(QgsFontUtils.getStandardTestFont('Bold')) + f.setFont(QgsFontUtils.getStandardTestFont("Bold")) f.setSize(20) f.buffer().setEnabled(True) s.setFormat(f) @@ -62,9 +65,7 @@ def testSimpleLabelVertices(self): self.assertTrue( self.render_map_settings_check( - 'simple_label_vertices', - 'simple_label_vertices', - ms + "simple_label_vertices", "simple_label_vertices", ms ) ) @@ -72,21 +73,21 @@ def testSimpleLabelVertices(self): self.assertTrue( self.render_map_settings_check( - 'simple_label_disabled', - 'simple_label_disabled', - ms + "simple_label_disabled", "simple_label_disabled", ms ) ) def testSimpleLabelFaces(self): - ml = QgsMeshLayer(os.path.join(unitTestDataPath(), 'mesh', 'quad_flower.2dm'), 'mdal', 'mdal') + ml = QgsMeshLayer( + os.path.join(unitTestDataPath(), "mesh", "quad_flower.2dm"), "mdal", "mdal" + ) self.assertTrue(ml.isValid()) - ml.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + ml.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) ms = QgsMapSettings() ms.setOutputSize(QSize(400, 400)) ms.setOutputDpi(96) - ms.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + ms.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) ms.setExtent(ml.extent().buffered(200)) ms.setLayers([ml]) @@ -94,7 +95,7 @@ def testSimpleLabelFaces(self): s.fieldName = "$face_index" s.isExpression = True f = s.format() - f.setFont(QgsFontUtils.getStandardTestFont('Bold')) + f.setFont(QgsFontUtils.getStandardTestFont("Bold")) f.setSize(20) f.buffer().setEnabled(True) s.setFormat(f) @@ -105,9 +106,7 @@ def testSimpleLabelFaces(self): self.assertTrue( self.render_map_settings_check( - 'simple_label_faces', - 'simple_label_faces', - ms + "simple_label_faces", "simple_label_faces", ms ) ) @@ -115,12 +114,10 @@ def testSimpleLabelFaces(self): self.assertTrue( self.render_map_settings_check( - 'simple_label_disabled', - 'simple_label_disabled', - ms + "simple_label_disabled", "simple_label_disabled", ms ) ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmeshlayerprofilegenerator.py b/tests/src/python/test_qgsmeshlayerprofilegenerator.py index eb11f8476118..f4bff5cc9247 100644 --- a/tests/src/python/test_qgsmeshlayerprofilegenerator.py +++ b/tests/src/python/test_qgsmeshlayerprofilegenerator.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '18/03/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "18/03/2022" +__copyright__ = "Copyright 2022, The QGIS Project" import os @@ -32,19 +33,23 @@ class TestQgsMeshLayerProfileGenerator(QgisTestCase): def testGeneration(self): - ml = QgsMeshLayer(os.path.join(unitTestDataPath(), '3d', 'elev_mesh.2dm'), 'mdal', 'mdal') + ml = QgsMeshLayer( + os.path.join(unitTestDataPath(), "3d", "elev_mesh.2dm"), "mdal", "mdal" + ) self.assertTrue(ml.isValid()) - ml.setCrs(QgsCoordinateReferenceSystem('EPSG:27700')) + ml.setCrs(QgsCoordinateReferenceSystem("EPSG:27700")) curve = QgsLineString() - curve.fromWkt('LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)') + curve.fromWkt( + "LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)" + ) req = QgsProfileRequest(curve) generator = ml.createProfileGenerator(req) self.assertIsNotNone(generator) # set correct crs for linestring and re-try - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = ml.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) @@ -63,39 +68,57 @@ def testGeneration(self): self.assertEqual(len(features), 1) self.assertEqual(features[0].layerIdentifier, ml.id()) self.assertEqual(features[0].geometry.constGet().numPoints(), 102) - self.assertEqual(features[0].geometry.constGet().pointN(0).asWkt(-2), 'Point Z (-348100 6633700 200)') - self.assertEqual(features[0].geometry.constGet().pointN(101).asWkt(-2), 'Point Z (-345800 6631600 100)') + self.assertEqual( + features[0].geometry.constGet().pointN(0).asWkt(-2), + "Point Z (-348100 6633700 200)", + ) + self.assertEqual( + features[0].geometry.constGet().pointN(101).asWkt(-2), + "Point Z (-345800 6631600 100)", + ) features = r.asFeatures(Qgis.ProfileExportType.Profile2D) self.assertEqual(len(features), 1) self.assertEqual(features[0].layerIdentifier, ml.id()) self.assertEqual(features[0].geometry.constGet().numPoints(), 102) - self.assertEqual(features[0].geometry.constGet().pointN(0).asWkt(-2), 'Point (0 200)') - self.assertEqual(features[0].geometry.constGet().pointN(101).asWkt(-2), 'Point (3400 100)') + self.assertEqual( + features[0].geometry.constGet().pointN(0).asWkt(-2), "Point (0 200)" + ) + self.assertEqual( + features[0].geometry.constGet().pointN(101).asWkt(-2), "Point (3400 100)" + ) features = r.asFeatures(Qgis.ProfileExportType.DistanceVsElevationTable) self.assertEqual(len(features), 102) self.assertEqual(features[0].layerIdentifier, ml.id()) - self.assertAlmostEqual(features[0].attributes['distance'], 0.0, 0) - self.assertAlmostEqual(features[0].attributes['elevation'], 153.0, 0) - self.assertEqual(features[0].geometry.asWkt(-2), 'Point Z (-348100 6633700 200)') - self.assertEqual(features[-1].geometry.asWkt(-2), 'Point Z (-345800 6631600 100)') - self.assertAlmostEqual(features[-1].attributes['distance'], 3393.263, 0) - self.assertAlmostEqual(features[-1].attributes['elevation'], 98.780, 0) + self.assertAlmostEqual(features[0].attributes["distance"], 0.0, 0) + self.assertAlmostEqual(features[0].attributes["elevation"], 153.0, 0) + self.assertEqual( + features[0].geometry.asWkt(-2), "Point Z (-348100 6633700 200)" + ) + self.assertEqual( + features[-1].geometry.asWkt(-2), "Point Z (-345800 6631600 100)" + ) + self.assertAlmostEqual(features[-1].attributes["distance"], 3393.263, 0) + self.assertAlmostEqual(features[-1].attributes["elevation"], 98.780, 0) def testStepSize(self): - ml = QgsMeshLayer(os.path.join(unitTestDataPath(), '3d', 'elev_mesh.2dm'), 'mdal', 'mdal') + ml = QgsMeshLayer( + os.path.join(unitTestDataPath(), "3d", "elev_mesh.2dm"), "mdal", "mdal" + ) self.assertTrue(ml.isValid()) - ml.setCrs(QgsCoordinateReferenceSystem('EPSG:27700')) + ml.setCrs(QgsCoordinateReferenceSystem("EPSG:27700")) curve = QgsLineString() - curve.fromWkt('LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)') + curve.fromWkt( + "LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)" + ) req = QgsProfileRequest(curve) # set a smaller step size then would be automatically calculated req.setStepDistance(10) # set correct crs for linestring and re-try - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = ml.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) @@ -114,33 +137,51 @@ def testStepSize(self): self.assertEqual(len(features), 1) self.assertEqual(features[0].layerIdentifier, ml.id()) self.assertEqual(features[0].geometry.constGet().numPoints(), 216) - self.assertEqual(features[0].geometry.constGet().pointN(0).asWkt(-2), 'Point Z (-348100 6633700 200)') - self.assertEqual(features[0].geometry.constGet().pointN(215).asWkt(-2), 'Point Z (-345800 6631600 100)') + self.assertEqual( + features[0].geometry.constGet().pointN(0).asWkt(-2), + "Point Z (-348100 6633700 200)", + ) + self.assertEqual( + features[0].geometry.constGet().pointN(215).asWkt(-2), + "Point Z (-345800 6631600 100)", + ) features = r.asFeatures(Qgis.ProfileExportType.Profile2D) self.assertEqual(len(features), 1) self.assertEqual(features[0].layerIdentifier, ml.id()) self.assertEqual(features[0].geometry.constGet().numPoints(), 216) - self.assertEqual(features[0].geometry.constGet().pointN(0).asWkt(-2), 'Point (0 200)') - self.assertEqual(features[0].geometry.constGet().pointN(215).asWkt(-2), 'Point (3400 100)') + self.assertEqual( + features[0].geometry.constGet().pointN(0).asWkt(-2), "Point (0 200)" + ) + self.assertEqual( + features[0].geometry.constGet().pointN(215).asWkt(-2), "Point (3400 100)" + ) features = r.asFeatures(Qgis.ProfileExportType.DistanceVsElevationTable) self.assertEqual(len(features), 216) self.assertEqual(features[0].layerIdentifier, ml.id()) - self.assertAlmostEqual(features[0].attributes['distance'], 0.0, 0) - self.assertAlmostEqual(features[0].attributes['elevation'], 152.87, 0) - self.assertEqual(features[0].geometry.asWkt(-2), 'Point Z (-348100 6633700 200)') - self.assertEqual(features[-1].geometry.asWkt(-2), 'Point Z (-345800 6631600 100)') - self.assertAlmostEqual(features[-1].attributes['distance'], 3393.263, 0) - self.assertAlmostEqual(features[-1].attributes['elevation'], 98.780, 0) + self.assertAlmostEqual(features[0].attributes["distance"], 0.0, 0) + self.assertAlmostEqual(features[0].attributes["elevation"], 152.87, 0) + self.assertEqual( + features[0].geometry.asWkt(-2), "Point Z (-348100 6633700 200)" + ) + self.assertEqual( + features[-1].geometry.asWkt(-2), "Point Z (-345800 6631600 100)" + ) + self.assertAlmostEqual(features[-1].attributes["distance"], 3393.263, 0) + self.assertAlmostEqual(features[-1].attributes["elevation"], 98.780, 0) def testSnapping(self): - ml = QgsMeshLayer(os.path.join(unitTestDataPath(), '3d', 'elev_mesh.2dm'), 'mdal', 'mdal') + ml = QgsMeshLayer( + os.path.join(unitTestDataPath(), "3d", "elev_mesh.2dm"), "mdal", "mdal" + ) self.assertTrue(ml.isValid()) - ml.setCrs(QgsCoordinateReferenceSystem('EPSG:27700')) + ml.setCrs(QgsCoordinateReferenceSystem("EPSG:27700")) curve = QgsLineString() - curve.fromWkt('LineString (321621.3770066662109457 129734.87810317709227093, 321894.21278918092139065 129858.49142702402605209)') + curve.fromWkt( + "LineString (321621.3770066662109457 129734.87810317709227093, 321894.21278918092139065 129858.49142702402605209)" + ) req = QgsProfileRequest(curve) generator = ml.createProfileGenerator(req) @@ -173,12 +214,16 @@ def testSnapping(self): self.assertFalse(res.isValid()) def testIdentify(self): - ml = QgsMeshLayer(os.path.join(unitTestDataPath(), '3d', 'elev_mesh.2dm'), 'mdal', 'mdal') + ml = QgsMeshLayer( + os.path.join(unitTestDataPath(), "3d", "elev_mesh.2dm"), "mdal", "mdal" + ) self.assertTrue(ml.isValid()) - ml.setCrs(QgsCoordinateReferenceSystem('EPSG:27700')) + ml.setCrs(QgsCoordinateReferenceSystem("EPSG:27700")) curve = QgsLineString() - curve.fromWkt('LineString (321621.3770066662109457 129734.87810317709227093, 321894.21278918092139065 129858.49142702402605209)') + curve.fromWkt( + "LineString (321621.3770066662109457 129734.87810317709227093, 321894.21278918092139065 129858.49142702402605209)" + ) req = QgsProfileRequest(curve) generator = ml.createProfileGenerator(req) @@ -198,18 +243,22 @@ def testIdentify(self): res = r.identify(QgsProfilePoint(0, 70), context) self.assertEqual(len(res), 1) self.assertEqual(res[0].layer(), ml) - self.assertEqual(res[0].results(), [{'distance': 0.0, 'elevation': 71.8236528075051}]) + self.assertEqual( + res[0].results(), [{"distance": 0.0, "elevation": 71.8236528075051}] + ) context.maximumSurfaceDistanceDelta = 0 context.maximumSurfaceElevationDelta = 5 res = r.identify(QgsProfilePoint(200, 79), context) self.assertEqual(len(res), 1) self.assertEqual(res[0].layer(), ml) - self.assertEqual(res[0].results(), [{'distance': 200.0, 'elevation': 75.84131736154015}]) + self.assertEqual( + res[0].results(), [{"distance": 200.0, "elevation": 75.84131736154015}] + ) res = r.identify(QgsProfilePoint(200, 85), context) self.assertFalse(res) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmeshlayerrenderer.py b/tests/src/python/test_qgsmeshlayerrenderer.py index 2668064018f7..ef4aa7b2ab8e 100644 --- a/tests/src/python/test_qgsmeshlayerrenderer.py +++ b/tests/src/python/test_qgsmeshlayerrenderer.py @@ -10,12 +10,7 @@ import unittest from qgis.PyQt.QtCore import QSize -from qgis.core import ( - Qgis, - QgsDoubleRange, - QgsMapSettings, - QgsMeshLayer -) +from qgis.core import Qgis, QgsDoubleRange, QgsMapSettings, QgsMeshLayer from qgis.testing import start_app, QgisTestCase from utilities import unitTestDataPath @@ -35,17 +30,15 @@ def test_render_fixed_elevation_range_with_z_range_filter(self): map settings has a z range filtrer """ mesh_layer = QgsMeshLayer( - os.path.join(unitTestDataPath(), 'mesh', 'quad_flower.2dm'), - 'mdal', 'mdal') + os.path.join(unitTestDataPath(), "mesh", "quad_flower.2dm"), "mdal", "mdal" + ) self.assertTrue(mesh_layer.isValid()) # set layer as elevation enabled mesh_layer.elevationProperties().setMode( Qgis.MeshElevationMode.FixedElevationRange ) - mesh_layer.elevationProperties().setFixedRange( - QgsDoubleRange(33, 38) - ) + mesh_layer.elevationProperties().setFixedRange(QgsDoubleRange(33, 38)) map_settings = QgsMapSettings() map_settings.setOutputSize(QSize(400, 400)) @@ -58,27 +51,30 @@ def test_render_fixed_elevation_range_with_z_range_filter(self): map_settings.setZRange(QgsDoubleRange()) self.assertTrue( self.render_map_settings_check( - 'No Z range filter on map settings, fixed elevation range layer', - 'elevation_no_filter', - map_settings) + "No Z range filter on map settings, fixed elevation range layer", + "elevation_no_filter", + map_settings, + ) ) # map settings range includes layer's range map_settings.setZRange(QgsDoubleRange(30, 35)) self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings includes layers fixed range', - 'fixed_elevation_range_included', - map_settings) + "Z range filter on map settings includes layers fixed range", + "fixed_elevation_range_included", + map_settings, + ) ) # map settings range excludes layer's range map_settings.setZRange(QgsDoubleRange(130, 135)) self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings outside of layers fixed range', - 'fixed_elevation_range_excluded', - map_settings) + "Z range filter on map settings outside of layers fixed range", + "fixed_elevation_range_excluded", + map_settings, + ) ) def test_render_fixed_range_per_group_with_z_range_filter(self): @@ -87,21 +83,20 @@ def test_render_fixed_range_per_group_with_z_range_filter(self): map settings has a z range filter """ layer = QgsMeshLayer( - self.get_test_data_path( - 'mesh/netcdf_parent_quantity.nc').as_posix(), - 'mesh', - 'mdal' + self.get_test_data_path("mesh/netcdf_parent_quantity.nc").as_posix(), + "mesh", + "mdal", ) self.assertTrue(layer.isValid()) # set layer as elevation enabled - layer.elevationProperties().setMode( - Qgis.MeshElevationMode.FixedRangePerGroup - ) + layer.elevationProperties().setMode(Qgis.MeshElevationMode.FixedRangePerGroup) layer.elevationProperties().setFixedRangePerGroup( - {1: QgsDoubleRange(33, 38), - 2: QgsDoubleRange(35, 40), - 3: QgsDoubleRange(40, 48)} + { + 1: QgsDoubleRange(33, 38), + 2: QgsDoubleRange(35, 40), + 3: QgsDoubleRange(40, 48), + } ) map_settings = QgsMapSettings() @@ -115,38 +110,42 @@ def test_render_fixed_range_per_group_with_z_range_filter(self): map_settings.setZRange(QgsDoubleRange()) self.assertTrue( self.render_map_settings_check( - 'No Z range filter on map settings, elevation range per group', - 'elevation_range_per_group_no_filter', - map_settings) + "No Z range filter on map settings, elevation range per group", + "elevation_range_per_group_no_filter", + map_settings, + ) ) # map settings range matches group 3 only map_settings.setZRange(QgsDoubleRange(40.5, 49.5)) self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings matches group 3 only', - 'elevation_range_per_group_match3', - map_settings) + "Z range filter on map settings matches group 3 only", + "elevation_range_per_group_match3", + map_settings, + ) ) # map settings range matches group 1 and 2 map_settings.setZRange(QgsDoubleRange(33, 39.5)) self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings matches group 1 and 2', - 'elevation_range_per_group_match1and2', - map_settings) + "Z range filter on map settings matches group 1 and 2", + "elevation_range_per_group_match1and2", + map_settings, + ) ) # map settings range excludes layer's range map_settings.setZRange(QgsDoubleRange(130, 135)) self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings outside of layer group ranges', - 'fixed_elevation_range_excluded', - map_settings) + "Z range filter on map settings outside of layer group ranges", + "fixed_elevation_range_excluded", + map_settings, + ) ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmessagelog.py b/tests/src/python/test_qgsmessagelog.py index 31c639e09ebd..be5dd085b288 100644 --- a/tests/src/python/test_qgsmessagelog.py +++ b/tests/src/python/test_qgsmessagelog.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '18/06/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "18/06/2018" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy from qgis.core import ( @@ -34,19 +35,23 @@ def testSignals(self): app_spy = QSignalSpy(app_log.messageReceived) app_spy_received = QSignalSpy(app_log.messageReceived[bool]) - QgsMessageLog.logMessage('test', 'tag', Qgis.MessageLevel.Info, notifyUser=True) + QgsMessageLog.logMessage("test", "tag", Qgis.MessageLevel.Info, notifyUser=True) self.assertEqual(len(app_spy), 1) - self.assertEqual(app_spy[-1], ['test', 'tag', Qgis.MessageLevel.Info]) + self.assertEqual(app_spy[-1], ["test", "tag", Qgis.MessageLevel.Info]) # info message, so messageReceived(bool) should not be emitted self.assertEqual(len(app_spy_received), 0) - QgsMessageLog.logMessage('test', 'tag', Qgis.MessageLevel.Warning, notifyUser=True) + QgsMessageLog.logMessage( + "test", "tag", Qgis.MessageLevel.Warning, notifyUser=True + ) self.assertEqual(len(app_spy), 2) - self.assertEqual(app_spy[-1], ['test', 'tag', Qgis.MessageLevel.Warning]) + self.assertEqual(app_spy[-1], ["test", "tag", Qgis.MessageLevel.Warning]) # warning message, so messageReceived(bool) should be emitted self.assertEqual(len(app_spy_received), 1) - QgsMessageLog.logMessage('test', 'tag', Qgis.MessageLevel.Warning, notifyUser=False) + QgsMessageLog.logMessage( + "test", "tag", Qgis.MessageLevel.Warning, notifyUser=False + ) self.assertEqual(len(app_spy), 3) # notifyUser was False self.assertEqual(len(app_spy_received), 1) @@ -57,35 +62,45 @@ def testBlocker(self): spy = QSignalSpy(app_log.messageReceived) spy_received = QSignalSpy(app_log.messageReceived[bool]) - QgsMessageLog.logMessage('test', 'tag', Qgis.MessageLevel.Warning, notifyUser=True) + QgsMessageLog.logMessage( + "test", "tag", Qgis.MessageLevel.Warning, notifyUser=True + ) self.assertEqual(len(spy), 1) - self.assertEqual(spy[-1], ['test', 'tag', Qgis.MessageLevel.Warning]) + self.assertEqual(spy[-1], ["test", "tag", Qgis.MessageLevel.Warning]) self.assertEqual(len(spy_received), 1) # block notifications b = QgsMessageLogNotifyBlocker() - QgsMessageLog.logMessage('test', 'tag', Qgis.MessageLevel.Warning, notifyUser=True) + QgsMessageLog.logMessage( + "test", "tag", Qgis.MessageLevel.Warning, notifyUser=True + ) self.assertEqual(len(spy), 2) # should not be blocked self.assertEqual(len(spy_received), 1) # should be blocked # another blocker b2 = QgsMessageLogNotifyBlocker() - QgsMessageLog.logMessage('test', 'tag', Qgis.MessageLevel.Warning, notifyUser=True) + QgsMessageLog.logMessage( + "test", "tag", Qgis.MessageLevel.Warning, notifyUser=True + ) self.assertEqual(len(spy), 3) # should not be blocked self.assertEqual(len(spy_received), 1) # should be blocked del b # still blocked because of b2 - QgsMessageLog.logMessage('test', 'tag', Qgis.MessageLevel.Warning, notifyUser=True) + QgsMessageLog.logMessage( + "test", "tag", Qgis.MessageLevel.Warning, notifyUser=True + ) self.assertEqual(len(spy), 4) # should not be blocked self.assertEqual(len(spy_received), 1) # should be blocked del b2 # not blocked - QgsMessageLog.logMessage('test', 'tag', Qgis.MessageLevel.Warning, notifyUser=True) + QgsMessageLog.logMessage( + "test", "tag", Qgis.MessageLevel.Warning, notifyUser=True + ) self.assertEqual(len(spy), 5) # should not be blocked self.assertEqual(len(spy_received), 2) # should not be blocked -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmetadatabase.py b/tests/src/python/test_qgsmetadatabase.py index f1562bd7a03e..8b709e2e2e54 100644 --- a/tests/src/python/test_qgsmetadatabase.py +++ b/tests/src/python/test_qgsmetadatabase.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '19/03/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "19/03/2018" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, QTime from qgis.PyQt.QtXml import QDomDocument @@ -33,106 +34,121 @@ class TestQgsMetadataBase(QgisTestCase): def testGettersSetters(self): m = TestMetadata() - m.setIdentifier('identifier') - self.assertEqual(m.identifier(), 'identifier') - - m.setParentIdentifier('parent identifier') - self.assertEqual(m.parentIdentifier(), 'parent identifier') + m.setIdentifier("identifier") + self.assertEqual(m.identifier(), "identifier") - m.setLanguage('en-us') - self.assertEqual(m.language(), 'en-us') + m.setParentIdentifier("parent identifier") + self.assertEqual(m.parentIdentifier(), "parent identifier") - m.setType('type') - self.assertEqual(m.type(), 'type') + m.setLanguage("en-us") + self.assertEqual(m.language(), "en-us") - m.setTitle('title') - self.assertEqual(m.title(), 'title') + m.setType("type") + self.assertEqual(m.type(), "type") - m.setCategories(['category']) - self.assertEqual(m.categories(), ['category']) + m.setTitle("title") + self.assertEqual(m.title(), "title") - m.setAbstract('abstract') - self.assertEqual(m.abstract(), 'abstract') + m.setCategories(["category"]) + self.assertEqual(m.categories(), ["category"]) - m.setHistory(['loaded into QGIS']) - self.assertEqual(m.history(), ['loaded into QGIS']) - m.setHistory(['accidentally deleted some features']) - self.assertEqual(m.history(), ['accidentally deleted some features']) - m.addHistoryItem('panicked and deleted more') - self.assertEqual(m.history(), ['accidentally deleted some features', 'panicked and deleted more']) + m.setAbstract("abstract") + self.assertEqual(m.abstract(), "abstract") - m.setDateTime(Qgis.MetadataDateType.Published, QDateTime(QDate(2022, 1, 2), QTime(12, 13, 14))) - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Published), QDateTime(QDate(2022, 1, 2), QTime(12, 13, 14))) - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Created), - QDateTime()) - m.setDateTime(Qgis.MetadataDateType.Created, - QDateTime(QDate(2020, 1, 2), QTime(12, 13, 14))) - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Published), QDateTime(QDate(2022, 1, 2), QTime(12, 13, 14))) - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Created), - QDateTime(QDate(2020, 1, 2), QTime(12, 13, 14))) + m.setHistory(["loaded into QGIS"]) + self.assertEqual(m.history(), ["loaded into QGIS"]) + m.setHistory(["accidentally deleted some features"]) + self.assertEqual(m.history(), ["accidentally deleted some features"]) + m.addHistoryItem("panicked and deleted more") + self.assertEqual( + m.history(), + ["accidentally deleted some features", "panicked and deleted more"], + ) + + m.setDateTime( + Qgis.MetadataDateType.Published, + QDateTime(QDate(2022, 1, 2), QTime(12, 13, 14)), + ) + self.assertEqual( + m.dateTime(Qgis.MetadataDateType.Published), + QDateTime(QDate(2022, 1, 2), QTime(12, 13, 14)), + ) + self.assertEqual(m.dateTime(Qgis.MetadataDateType.Created), QDateTime()) + m.setDateTime( + Qgis.MetadataDateType.Created, + QDateTime(QDate(2020, 1, 2), QTime(12, 13, 14)), + ) + self.assertEqual( + m.dateTime(Qgis.MetadataDateType.Published), + QDateTime(QDate(2022, 1, 2), QTime(12, 13, 14)), + ) + self.assertEqual( + m.dateTime(Qgis.MetadataDateType.Created), + QDateTime(QDate(2020, 1, 2), QTime(12, 13, 14)), + ) def testEquality(self): a = QgsAbstractMetadataBase.Address() - a.type = 'postal' - a.address = '13 north rd' - a.city = 'huxleys haven' - a.administrativeArea = 'land of the queens' - a.postalCode = '4123' - a.country = 'straya!' + a.type = "postal" + a.address = "13 north rd" + a.city = "huxleys haven" + a.administrativeArea = "land of the queens" + a.postalCode = "4123" + a.country = "straya!" a2 = QgsAbstractMetadataBase.Address(a) self.assertEqual(a, a2) - a2.type = 'postal2' + a2.type = "postal2" self.assertNotEqual(a, a2) a2 = QgsAbstractMetadataBase.Address(a) - a2.address = 'address2' + a2.address = "address2" self.assertNotEqual(a, a2) a2 = QgsAbstractMetadataBase.Address(a) - a2.city = 'city' + a2.city = "city" self.assertNotEqual(a, a2) a2 = QgsAbstractMetadataBase.Address(a) - a2.administrativeArea = 'area2' + a2.administrativeArea = "area2" self.assertNotEqual(a, a2) a2 = QgsAbstractMetadataBase.Address(a) - a2.postalCode = 'postal2' + a2.postalCode = "postal2" self.assertNotEqual(a, a2) a2 = QgsAbstractMetadataBase.Address(a) - a2.country = 'country2' + a2.country = "country2" self.assertNotEqual(a, a2) c = QgsAbstractMetadataBase.Contact() - c.name = 'name' - c.organization = 'org' - c.position = 'pos' - c.voice = '1500 515 555' - c.fax = 'fax' - c.email = 'email' - c.role = 'role' + c.name = "name" + c.organization = "org" + c.position = "pos" + c.voice = "1500 515 555" + c.fax = "fax" + c.email = "email" + c.role = "role" a = QgsAbstractMetadataBase.Address() - a.type = 'postal' + a.type = "postal" a2 = QgsAbstractMetadataBase.Address() - a2.type = 'street' + a2.type = "street" c.addresses = [a, a2] c2 = QgsAbstractMetadataBase.Contact(c) self.assertEqual(c, c2) - c2.name = 'name2' + c2.name = "name2" self.assertNotEqual(c, c2) c2 = QgsAbstractMetadataBase.Contact(c) - c2.organization = 'org2' + c2.organization = "org2" self.assertNotEqual(c, c2) c2 = QgsAbstractMetadataBase.Contact(c) - c2.position = 'pos2' + c2.position = "pos2" self.assertNotEqual(c, c2) c2 = QgsAbstractMetadataBase.Contact(c) - c2.voice = 'voice2' + c2.voice = "voice2" self.assertNotEqual(c, c2) c2 = QgsAbstractMetadataBase.Contact(c) - c2.fax = 'fax2' + c2.fax = "fax2" self.assertNotEqual(c, c2) c2 = QgsAbstractMetadataBase.Contact(c) - c2.email = 'email2' + c2.email = "email2" self.assertNotEqual(c, c2) c2 = QgsAbstractMetadataBase.Contact(c) - c2.role = 'role2' + c2.role = "role2" self.assertNotEqual(c, c2) c2 = QgsAbstractMetadataBase.Contact(c) c2.addresses = [a2] @@ -140,219 +156,242 @@ def testEquality(self): # link l = QgsAbstractMetadataBase.Link() - l.name = 'name' - l.type = 'type' - l.description = 'desc' - l.url = 'url' - l.format = 'format' - l.mimeType = 'mime' - l.size = '112' + l.name = "name" + l.type = "type" + l.description = "desc" + l.url = "url" + l.format = "format" + l.mimeType = "mime" + l.size = "112" l2 = QgsAbstractMetadataBase.Link(l) self.assertEqual(l, l2) l2 = QgsAbstractMetadataBase.Link(l) - l2.name = 'name2' + l2.name = "name2" self.assertNotEqual(l, l2) l2 = QgsAbstractMetadataBase.Link(l) - l2.type = 'type2' + l2.type = "type2" self.assertNotEqual(l, l2) l2 = QgsAbstractMetadataBase.Link(l) - l2.description = 'desc2' + l2.description = "desc2" self.assertNotEqual(l, l2) l2 = QgsAbstractMetadataBase.Link(l) - l2.url = 'url2' + l2.url = "url2" self.assertNotEqual(l, l2) l2 = QgsAbstractMetadataBase.Link(l) - l2.format = 'format2' + l2.format = "format2" self.assertNotEqual(l, l2) l2 = QgsAbstractMetadataBase.Link(l) - l2.mimeType = 'mime2' + l2.mimeType = "mime2" self.assertNotEqual(l, l2) l2 = QgsAbstractMetadataBase.Link(l) - l2.size = '113' + l2.size = "113" self.assertNotEqual(l, l2) def testKeywords(self): m = TestMetadata() - m.setKeywords({'gmd:topicCategory': ['natural']}) - self.assertEqual(m.keywords(), {'gmd:topicCategory': ['natural']}) - self.assertEqual(m.categories(), ['natural']) - self.assertTrue(m.removeKeywords('gmd:topicCategory')) - - m.setKeywords({'vocab a': ['keyword a', 'other a'], - 'vocab b': ['keyword b', 'other b']}) - self.assertEqual(m.keywords(), {'vocab a': ['keyword a', 'other a'], - 'vocab b': ['keyword b', 'other b']}) - self.assertEqual(m.keywordVocabularies(), ['vocab a', 'vocab b']) - self.assertEqual(m.keywords('vocab a'), ['keyword a', 'other a']) - self.assertEqual(m.keywords('vocab b'), ['keyword b', 'other b']) - self.assertEqual(m.keywords('not valid'), []) - - m.addKeywords('vocab c', ['keyword c']) - self.assertEqual(m.keywords(), {'vocab a': ['keyword a', 'other a'], - 'vocab b': ['keyword b', 'other b'], - 'vocab c': ['keyword c']}) + m.setKeywords({"gmd:topicCategory": ["natural"]}) + self.assertEqual(m.keywords(), {"gmd:topicCategory": ["natural"]}) + self.assertEqual(m.categories(), ["natural"]) + self.assertTrue(m.removeKeywords("gmd:topicCategory")) + + m.setKeywords( + {"vocab a": ["keyword a", "other a"], "vocab b": ["keyword b", "other b"]} + ) + self.assertEqual( + m.keywords(), + {"vocab a": ["keyword a", "other a"], "vocab b": ["keyword b", "other b"]}, + ) + self.assertEqual(m.keywordVocabularies(), ["vocab a", "vocab b"]) + self.assertEqual(m.keywords("vocab a"), ["keyword a", "other a"]) + self.assertEqual(m.keywords("vocab b"), ["keyword b", "other b"]) + self.assertEqual(m.keywords("not valid"), []) + + m.addKeywords("vocab c", ["keyword c"]) + self.assertEqual( + m.keywords(), + { + "vocab a": ["keyword a", "other a"], + "vocab b": ["keyword b", "other b"], + "vocab c": ["keyword c"], + }, + ) # replace existing using addKeywords - m.addKeywords('vocab c', ['c']) - self.assertEqual(m.keywords(), {'vocab a': ['keyword a', 'other a'], - 'vocab b': ['keyword b', 'other b'], - 'vocab c': ['c']}) + m.addKeywords("vocab c", ["c"]) + self.assertEqual( + m.keywords(), + { + "vocab a": ["keyword a", "other a"], + "vocab b": ["keyword b", "other b"], + "vocab c": ["c"], + }, + ) # replace existing using setKeywords - m.setKeywords({'x': ['x'], 'y': ['y']}) - self.assertEqual(m.keywords(), {'x': ['x'], - 'y': ['y']}) + m.setKeywords({"x": ["x"], "y": ["y"]}) + self.assertEqual(m.keywords(), {"x": ["x"], "y": ["y"]}) def testAddress(self): a = QgsAbstractMetadataBase.Address() - a.type = 'postal' - a.address = '13 north rd' - a.city = 'huxleys haven' - a.administrativeArea = 'land of the queens' - a.postalCode = '4123' - a.country = 'straya!' - self.assertEqual(a.type, 'postal') - self.assertEqual(a.address, '13 north rd') - self.assertEqual(a.city, 'huxleys haven') - self.assertEqual(a.administrativeArea, 'land of the queens') - self.assertEqual(a.postalCode, '4123') - self.assertEqual(a.country, 'straya!') + a.type = "postal" + a.address = "13 north rd" + a.city = "huxleys haven" + a.administrativeArea = "land of the queens" + a.postalCode = "4123" + a.country = "straya!" + self.assertEqual(a.type, "postal") + self.assertEqual(a.address, "13 north rd") + self.assertEqual(a.city, "huxleys haven") + self.assertEqual(a.administrativeArea, "land of the queens") + self.assertEqual(a.postalCode, "4123") + self.assertEqual(a.country, "straya!") def testContact(self): c = QgsAbstractMetadataBase.Contact() - c.name = 'Prince Gristle' - c.organization = 'Bergen co' - c.position = 'prince' - c.voice = '1500 515 555' - c.fax = 'who the f*** still uses fax?' - c.email = 'limpbiskitrulez69@hotmail.com' - c.role = 'person to blame when all goes wrong' + c.name = "Prince Gristle" + c.organization = "Bergen co" + c.position = "prince" + c.voice = "1500 515 555" + c.fax = "who the f*** still uses fax?" + c.email = "limpbiskitrulez69@hotmail.com" + c.role = "person to blame when all goes wrong" a = QgsAbstractMetadataBase.Address() - a.type = 'postal' + a.type = "postal" a2 = QgsAbstractMetadataBase.Address() - a2.type = 'street' + a2.type = "street" c.addresses = [a, a2] - self.assertEqual(c.name, 'Prince Gristle') - self.assertEqual(c.organization, 'Bergen co') - self.assertEqual(c.position, 'prince') - self.assertEqual(c.voice, '1500 515 555') - self.assertEqual(c.fax, 'who the f*** still uses fax?') - self.assertEqual(c.email, 'limpbiskitrulez69@hotmail.com') - self.assertEqual(c.role, 'person to blame when all goes wrong') - self.assertEqual(c.addresses[0].type, 'postal') - self.assertEqual(c.addresses[1].type, 'street') + self.assertEqual(c.name, "Prince Gristle") + self.assertEqual(c.organization, "Bergen co") + self.assertEqual(c.position, "prince") + self.assertEqual(c.voice, "1500 515 555") + self.assertEqual(c.fax, "who the f*** still uses fax?") + self.assertEqual(c.email, "limpbiskitrulez69@hotmail.com") + self.assertEqual(c.role, "person to blame when all goes wrong") + self.assertEqual(c.addresses[0].type, "postal") + self.assertEqual(c.addresses[1].type, "street") m = TestMetadata() c2 = QgsAbstractMetadataBase.Contact(c) - c2.name = 'Bridgette' + c2.name = "Bridgette" m.setContacts([c, c2]) - self.assertEqual(m.contacts()[0].name, 'Prince Gristle') - self.assertEqual(m.contacts()[1].name, 'Bridgette') + self.assertEqual(m.contacts()[0].name, "Prince Gristle") + self.assertEqual(m.contacts()[1].name, "Bridgette") # add contact c3 = QgsAbstractMetadataBase.Contact(c) - c3.name = 'Princess Poppy' + c3.name = "Princess Poppy" m.addContact(c3) self.assertEqual(len(m.contacts()), 3) - self.assertEqual(m.contacts()[2].name, 'Princess Poppy') + self.assertEqual(m.contacts()[2].name, "Princess Poppy") def testLinks(self): l = QgsAbstractMetadataBase.Link() - l.name = 'Trashbat' - l.type = 'fashion' - l.description = 'registered in the cook islands!' - l.url = 'http://trashbat.co.uk' - l.format = 'whois' - l.mimeType = 'text/string' - l.size = '112' - self.assertEqual(l.name, 'Trashbat') - self.assertEqual(l.type, 'fashion') - self.assertEqual(l.description, 'registered in the cook islands!') - self.assertEqual(l.url, 'http://trashbat.co.uk') - self.assertEqual(l.format, 'whois') - self.assertEqual(l.mimeType, 'text/string') - self.assertEqual(l.size, '112') + l.name = "Trashbat" + l.type = "fashion" + l.description = "registered in the cook islands!" + l.url = "http://trashbat.co.uk" + l.format = "whois" + l.mimeType = "text/string" + l.size = "112" + self.assertEqual(l.name, "Trashbat") + self.assertEqual(l.type, "fashion") + self.assertEqual(l.description, "registered in the cook islands!") + self.assertEqual(l.url, "http://trashbat.co.uk") + self.assertEqual(l.format, "whois") + self.assertEqual(l.mimeType, "text/string") + self.assertEqual(l.size, "112") m = TestMetadata() l2 = QgsAbstractMetadataBase.Link(l) - l2.name = 'Trashbat2' + l2.name = "Trashbat2" m.setLinks([l, l2]) - self.assertEqual(m.links()[0].name, 'Trashbat') - self.assertEqual(m.links()[1].name, 'Trashbat2') + self.assertEqual(m.links()[0].name, "Trashbat") + self.assertEqual(m.links()[1].name, "Trashbat2") # add link l3 = QgsAbstractMetadataBase.Link(l) - l3.name = 'Trashbat3' + l3.name = "Trashbat3" m.addLink(l3) self.assertEqual(len(m.links()), 3) - self.assertEqual(m.links()[2].name, 'Trashbat3') + self.assertEqual(m.links()[2].name, "Trashbat3") def createTestMetadata(self): """ Returns a standard metadata which can be tested with checkExpectedMetadata """ m = TestMetadata() - m.setIdentifier('1234') - m.setParentIdentifier('xyz') - m.setLanguage('en-CA') - m.setType('dataset') - m.setTitle('roads') - m.setAbstract('my roads') - m.setHistory(['history a', 'history b']) - m.setKeywords({ - 'GEMET': ['kw1', 'kw2'], - 'gmd:topicCategory': ['natural'], - }) + m.setIdentifier("1234") + m.setParentIdentifier("xyz") + m.setLanguage("en-CA") + m.setType("dataset") + m.setTitle("roads") + m.setAbstract("my roads") + m.setHistory(["history a", "history b"]) + m.setKeywords( + { + "GEMET": ["kw1", "kw2"], + "gmd:topicCategory": ["natural"], + } + ) c = QgsAbstractMetadataBase.Contact() - c.name = 'John Smith' - c.organization = 'ACME' - c.position = 'staff' - c.voice = '1500 515 555' - c.fax = 'xx.xxx.xxx.xxxx' - c.email = 'foo@example.org' - c.role = 'pointOfContact' + c.name = "John Smith" + c.organization = "ACME" + c.position = "staff" + c.voice = "1500 515 555" + c.fax = "xx.xxx.xxx.xxxx" + c.email = "foo@example.org" + c.role = "pointOfContact" address = QgsAbstractMetadataBase.Address() - address.type = 'postal' - address.address = '123 Main Street' - address.city = 'anycity' - address.administrativeArea = 'anyprovince' - address.postalCode = '90210' - address.country = 'Canada' + address.type = "postal" + address.address = "123 Main Street" + address.city = "anycity" + address.administrativeArea = "anyprovince" + address.postalCode = "90210" + address.country = "Canada" c.addresses = [address] m.setContacts([c]) l = QgsAbstractMetadataBase.Link() - l.name = 'geonode:roads' - l.type = 'OGC:WMS' - l.description = 'my GeoNode road layer' - l.url = 'http://example.org/wms' + l.name = "geonode:roads" + l.type = "OGC:WMS" + l.description = "my GeoNode road layer" + l.url = "http://example.org/wms" l2 = QgsAbstractMetadataBase.Link() - l2.name = 'geonode:roads' - l2.type = 'OGC:WFS' - l2.description = 'my GeoNode road layer' - l2.url = 'http://example.org/wfs' + l2.name = "geonode:roads" + l2.type = "OGC:WFS" + l2.description = "my GeoNode road layer" + l2.url = "http://example.org/wfs" l3 = QgsAbstractMetadataBase.Link() - l3.name = 'roads' - l3.type = 'WWW:LINK' - l3.description = 'full dataset download' - l3.url = 'http://example.org/roads.tgz' - l3.format = 'ESRI Shapefile' - l3.mimeType = 'application/gzip' - l3.size = '283676' + l3.name = "roads" + l3.type = "WWW:LINK" + l3.description = "full dataset download" + l3.url = "http://example.org/roads.tgz" + l3.format = "ESRI Shapefile" + l3.mimeType = "application/gzip" + l3.size = "283676" m.setLinks([l, l2, l3]) - m.setDateTime(Qgis.MetadataDateType.Created, QDateTime(QDate(2020, 1, 2), QTime(11, 12, 13))) - m.setDateTime(Qgis.MetadataDateType.Published, - QDateTime(QDate(2020, 1, 3), QTime(11, 12, 13))) - m.setDateTime(Qgis.MetadataDateType.Revised, - QDateTime(QDate(2020, 1, 4), QTime(11, 12, 13))) - m.setDateTime(Qgis.MetadataDateType.Superseded, - QDateTime(QDate(2020, 1, 5), QTime(11, 12, 13))) + m.setDateTime( + Qgis.MetadataDateType.Created, + QDateTime(QDate(2020, 1, 2), QTime(11, 12, 13)), + ) + m.setDateTime( + Qgis.MetadataDateType.Published, + QDateTime(QDate(2020, 1, 3), QTime(11, 12, 13)), + ) + m.setDateTime( + Qgis.MetadataDateType.Revised, + QDateTime(QDate(2020, 1, 4), QTime(11, 12, 13)), + ) + m.setDateTime( + Qgis.MetadataDateType.Superseded, + QDateTime(QDate(2020, 1, 5), QTime(11, 12, 13)), + ) return m @@ -360,53 +399,62 @@ def checkExpectedMetadata(self, m): """ Checks that a metadata object matches that returned by createTestMetadata """ - self.assertEqual(m.identifier(), '1234') - self.assertEqual(m.parentIdentifier(), 'xyz') - self.assertEqual(m.language(), 'en-CA') - self.assertEqual(m.type(), 'dataset') - self.assertEqual(m.title(), 'roads') - self.assertEqual(m.abstract(), 'my roads') - self.assertEqual(m.history(), ['history a', 'history b']) + self.assertEqual(m.identifier(), "1234") + self.assertEqual(m.parentIdentifier(), "xyz") + self.assertEqual(m.language(), "en-CA") + self.assertEqual(m.type(), "dataset") + self.assertEqual(m.title(), "roads") + self.assertEqual(m.abstract(), "my roads") + self.assertEqual(m.history(), ["history a", "history b"]) self.assertEqual( - m.keywords(), - {'GEMET': ['kw1', 'kw2'], 'gmd:topicCategory': ['natural']}) - - self.assertEqual(m.contacts()[0].name, 'John Smith') - self.assertEqual(m.contacts()[0].organization, 'ACME') - self.assertEqual(m.contacts()[0].position, 'staff') - self.assertEqual(m.contacts()[0].voice, '1500 515 555') - self.assertEqual(m.contacts()[0].fax, 'xx.xxx.xxx.xxxx') - self.assertEqual(m.contacts()[0].email, 'foo@example.org') - self.assertEqual(m.contacts()[0].role, 'pointOfContact') - self.assertEqual(m.contacts()[0].addresses[0].type, 'postal') - self.assertEqual(m.contacts()[0].addresses[0].address, '123 Main Street') - self.assertEqual(m.contacts()[0].addresses[0].city, 'anycity') - self.assertEqual(m.contacts()[0].addresses[0].administrativeArea, 'anyprovince') - self.assertEqual(m.contacts()[0].addresses[0].postalCode, '90210') - self.assertEqual(m.contacts()[0].addresses[0].country, 'Canada') - self.assertEqual(m.links()[0].name, 'geonode:roads') - self.assertEqual(m.links()[0].type, 'OGC:WMS') - self.assertEqual(m.links()[0].description, 'my GeoNode road layer') - self.assertEqual(m.links()[0].url, 'http://example.org/wms') - self.assertEqual(m.links()[1].name, 'geonode:roads') - self.assertEqual(m.links()[1].type, 'OGC:WFS') - self.assertEqual(m.links()[1].description, 'my GeoNode road layer') - self.assertEqual(m.links()[1].url, 'http://example.org/wfs') - self.assertEqual(m.links()[2].name, 'roads') - self.assertEqual(m.links()[2].type, 'WWW:LINK') - self.assertEqual(m.links()[2].description, 'full dataset download') - self.assertEqual(m.links()[2].url, 'http://example.org/roads.tgz') - self.assertEqual(m.links()[2].format, 'ESRI Shapefile') - self.assertEqual(m.links()[2].mimeType, 'application/gzip') - self.assertEqual(m.links()[2].size, '283676') - - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Created), QDateTime(QDate(2020, 1, 2), QTime(11, 12, 13))) - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Published), - QDateTime(QDate(2020, 1, 3), QTime(11, 12, 13))) - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Revised), - QDateTime(QDate(2020, 1, 4), QTime(11, 12, 13))) - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Superseded), - QDateTime(QDate(2020, 1, 5), QTime(11, 12, 13))) + m.keywords(), {"GEMET": ["kw1", "kw2"], "gmd:topicCategory": ["natural"]} + ) + + self.assertEqual(m.contacts()[0].name, "John Smith") + self.assertEqual(m.contacts()[0].organization, "ACME") + self.assertEqual(m.contacts()[0].position, "staff") + self.assertEqual(m.contacts()[0].voice, "1500 515 555") + self.assertEqual(m.contacts()[0].fax, "xx.xxx.xxx.xxxx") + self.assertEqual(m.contacts()[0].email, "foo@example.org") + self.assertEqual(m.contacts()[0].role, "pointOfContact") + self.assertEqual(m.contacts()[0].addresses[0].type, "postal") + self.assertEqual(m.contacts()[0].addresses[0].address, "123 Main Street") + self.assertEqual(m.contacts()[0].addresses[0].city, "anycity") + self.assertEqual(m.contacts()[0].addresses[0].administrativeArea, "anyprovince") + self.assertEqual(m.contacts()[0].addresses[0].postalCode, "90210") + self.assertEqual(m.contacts()[0].addresses[0].country, "Canada") + self.assertEqual(m.links()[0].name, "geonode:roads") + self.assertEqual(m.links()[0].type, "OGC:WMS") + self.assertEqual(m.links()[0].description, "my GeoNode road layer") + self.assertEqual(m.links()[0].url, "http://example.org/wms") + self.assertEqual(m.links()[1].name, "geonode:roads") + self.assertEqual(m.links()[1].type, "OGC:WFS") + self.assertEqual(m.links()[1].description, "my GeoNode road layer") + self.assertEqual(m.links()[1].url, "http://example.org/wfs") + self.assertEqual(m.links()[2].name, "roads") + self.assertEqual(m.links()[2].type, "WWW:LINK") + self.assertEqual(m.links()[2].description, "full dataset download") + self.assertEqual(m.links()[2].url, "http://example.org/roads.tgz") + self.assertEqual(m.links()[2].format, "ESRI Shapefile") + self.assertEqual(m.links()[2].mimeType, "application/gzip") + self.assertEqual(m.links()[2].size, "283676") + + self.assertEqual( + m.dateTime(Qgis.MetadataDateType.Created), + QDateTime(QDate(2020, 1, 2), QTime(11, 12, 13)), + ) + self.assertEqual( + m.dateTime(Qgis.MetadataDateType.Published), + QDateTime(QDate(2020, 1, 3), QTime(11, 12, 13)), + ) + self.assertEqual( + m.dateTime(Qgis.MetadataDateType.Revised), + QDateTime(QDate(2020, 1, 4), QTime(11, 12, 13)), + ) + self.assertEqual( + m.dateTime(Qgis.MetadataDateType.Superseded), + QDateTime(QDate(2020, 1, 5), QTime(11, 12, 13)), + ) def testStandard(self): m = self.createTestMetadata() @@ -441,95 +489,95 @@ def testValidateNative(self): # spellok # corrupt metadata piece by piece... m = self.createTestMetadata() - m.setIdentifier('') + m.setIdentifier("") res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'identifier') + self.assertEqual(list[0].section, "identifier") m = self.createTestMetadata() - m.setLanguage('') + m.setLanguage("") res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'language') + self.assertEqual(list[0].section, "language") m = self.createTestMetadata() - m.setType('') + m.setType("") res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'type') + self.assertEqual(list[0].section, "type") m = self.createTestMetadata() - m.setTitle('') + m.setTitle("") res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'title') + self.assertEqual(list[0].section, "title") m = self.createTestMetadata() - m.setAbstract('') + m.setAbstract("") res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'abstract') + self.assertEqual(list[0].section, "abstract") m = self.createTestMetadata() m.setContacts([]) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'contacts') + self.assertEqual(list[0].section, "contacts") m = self.createTestMetadata() m.setLinks([]) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'links') + self.assertEqual(list[0].section, "links") m = self.createTestMetadata() - m.setKeywords({'': ['kw1', 'kw2']}) + m.setKeywords({"": ["kw1", "kw2"]}) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'keywords') + self.assertEqual(list[0].section, "keywords") self.assertEqual(list[0].identifier, 0) m = self.createTestMetadata() - m.setKeywords({'AA': []}) + m.setKeywords({"AA": []}) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'keywords') + self.assertEqual(list[0].section, "keywords") self.assertEqual(list[0].identifier, 0) m = self.createTestMetadata() c = m.contacts()[0] - c.name = '' + c.name = "" m.setContacts([c]) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'contacts') + self.assertEqual(list[0].section, "contacts") self.assertEqual(list[0].identifier, 0) m = self.createTestMetadata() l = m.links()[0] - l.name = '' + l.name = "" m.setLinks([l]) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'links') + self.assertEqual(list[0].section, "links") self.assertEqual(list[0].identifier, 0) m = self.createTestMetadata() l = m.links()[0] - l.type = '' + l.type = "" m.setLinks([l]) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'links') + self.assertEqual(list[0].section, "links") self.assertEqual(list[0].identifier, 0) m = self.createTestMetadata() l = m.links()[0] - l.url = '' + l.url = "" m.setLinks([l]) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'links') + self.assertEqual(list[0].section, "links") self.assertEqual(list[0].identifier, 0) def testCombine(self): @@ -537,125 +585,173 @@ def testCombine(self): m2 = TestMetadata() # should be retained - m1.setIdentifier('i1') + m1.setIdentifier("i1") m1.combine(m2) - self.assertEqual(m1.identifier(), 'i1') + self.assertEqual(m1.identifier(), "i1") # should be overwritten m1.setIdentifier(None) - m2.setIdentifier('i2') + m2.setIdentifier("i2") m1.combine(m2) - self.assertEqual(m1.identifier(), 'i2') + self.assertEqual(m1.identifier(), "i2") # should be overwritten - m1.setIdentifier('i1') - m2.setIdentifier('i2') + m1.setIdentifier("i1") + m2.setIdentifier("i2") m1.combine(m2) - self.assertEqual(m1.identifier(), 'i2') + self.assertEqual(m1.identifier(), "i2") - m1.setParentIdentifier('pi1') + m1.setParentIdentifier("pi1") m2.setParentIdentifier(None) m1.combine(m2) - self.assertEqual(m1.parentIdentifier(), 'pi1') + self.assertEqual(m1.parentIdentifier(), "pi1") m1.setParentIdentifier(None) - m2.setParentIdentifier('pi2') + m2.setParentIdentifier("pi2") m1.combine(m2) - self.assertEqual(m1.parentIdentifier(), 'pi2') + self.assertEqual(m1.parentIdentifier(), "pi2") - m1.setLanguage('l1') + m1.setLanguage("l1") m2.setLanguage(None) m1.combine(m2) - self.assertEqual(m1.language(), 'l1') + self.assertEqual(m1.language(), "l1") m1.setLanguage(None) - m2.setLanguage('l2') + m2.setLanguage("l2") m1.combine(m2) - self.assertEqual(m1.language(), 'l2') + self.assertEqual(m1.language(), "l2") - m1.setType('ty1') + m1.setType("ty1") m2.setType(None) m1.combine(m2) - self.assertEqual(m1.type(), 'ty1') + self.assertEqual(m1.type(), "ty1") m1.setType(None) - m2.setType('ty2') + m2.setType("ty2") m1.combine(m2) - self.assertEqual(m1.type(), 'ty2') + self.assertEqual(m1.type(), "ty2") - m1.setTitle('t1') + m1.setTitle("t1") m2.setTitle(None) m1.combine(m2) - self.assertEqual(m1.title(), 't1') + self.assertEqual(m1.title(), "t1") m1.setTitle(None) - m2.setTitle('t2') + m2.setTitle("t2") m1.combine(m2) - self.assertEqual(m1.title(), 't2') + self.assertEqual(m1.title(), "t2") - m1.setAbstract('a1') + m1.setAbstract("a1") m2.setAbstract(None) m1.combine(m2) - self.assertEqual(m1.abstract(), 'a1') + self.assertEqual(m1.abstract(), "a1") m1.setAbstract(None) - m2.setAbstract('a2') + m2.setAbstract("a2") m1.combine(m2) - self.assertEqual(m1.abstract(), 'a2') + self.assertEqual(m1.abstract(), "a2") - m1.setHistory(['h1', 'hh1']) + m1.setHistory(["h1", "hh1"]) m2.setHistory([]) m1.combine(m2) - self.assertEqual(m1.history(), ['h1', 'hh1']) + self.assertEqual(m1.history(), ["h1", "hh1"]) m1.setHistory([]) - m2.setHistory(['h2', 'hh2']) + m2.setHistory(["h2", "hh2"]) m1.combine(m2) - self.assertEqual(m1.history(), ['h2', 'hh2']) + self.assertEqual(m1.history(), ["h2", "hh2"]) - m1.setKeywords({'words': ['k1', 'kk1']}) + m1.setKeywords({"words": ["k1", "kk1"]}) m2.setKeywords({}) m1.combine(m2) - self.assertEqual(m1.keywords(), {'words': ['k1', 'kk1']}) + self.assertEqual(m1.keywords(), {"words": ["k1", "kk1"]}) m1.setKeywords({}) - m2.setKeywords({'words': ['k2', 'kk2']}) + m2.setKeywords({"words": ["k2", "kk2"]}) m1.combine(m2) - self.assertEqual(m1.keywords(), {'words': ['k2', 'kk2']}) - - m1.setContacts([QgsAbstractMetadataBase.Contact('c1'), QgsAbstractMetadataBase.Contact('cc1')]) + self.assertEqual(m1.keywords(), {"words": ["k2", "kk2"]}) + + m1.setContacts( + [ + QgsAbstractMetadataBase.Contact("c1"), + QgsAbstractMetadataBase.Contact("cc1"), + ] + ) m2.setContacts([]) m1.combine(m2) - self.assertEqual(m1.contacts(), [QgsAbstractMetadataBase.Contact('c1'), QgsAbstractMetadataBase.Contact('cc1')]) + self.assertEqual( + m1.contacts(), + [ + QgsAbstractMetadataBase.Contact("c1"), + QgsAbstractMetadataBase.Contact("cc1"), + ], + ) m1.setContacts([]) - m2.setContacts([QgsAbstractMetadataBase.Contact('c2'), QgsAbstractMetadataBase.Contact('cc2')]) + m2.setContacts( + [ + QgsAbstractMetadataBase.Contact("c2"), + QgsAbstractMetadataBase.Contact("cc2"), + ] + ) m1.combine(m2) - self.assertEqual(m1.contacts(), [QgsAbstractMetadataBase.Contact('c2'), QgsAbstractMetadataBase.Contact('cc2')]) - - m1.setLinks([QgsAbstractMetadataBase.Link('l1'), QgsAbstractMetadataBase.Link('ll1')]) + self.assertEqual( + m1.contacts(), + [ + QgsAbstractMetadataBase.Contact("c2"), + QgsAbstractMetadataBase.Contact("cc2"), + ], + ) + + m1.setLinks( + [QgsAbstractMetadataBase.Link("l1"), QgsAbstractMetadataBase.Link("ll1")] + ) m2.setLinks([]) m1.combine(m2) - self.assertEqual(m1.links(), [QgsAbstractMetadataBase.Link('l1'), QgsAbstractMetadataBase.Link('ll1')]) + self.assertEqual( + m1.links(), + [QgsAbstractMetadataBase.Link("l1"), QgsAbstractMetadataBase.Link("ll1")], + ) m1.setLinks([]) - m2.setLinks([QgsAbstractMetadataBase.Link('l2'), QgsAbstractMetadataBase.Link('ll2')]) + m2.setLinks( + [QgsAbstractMetadataBase.Link("l2"), QgsAbstractMetadataBase.Link("ll2")] + ) m1.combine(m2) - self.assertEqual(m1.links(), [QgsAbstractMetadataBase.Link('l2'), QgsAbstractMetadataBase.Link('ll2')]) - - m1.setDateTime(Qgis.MetadataDateType.Created, QDateTime(QDate(2020, 1, 2), QTime(1, 2, 3))) - m1.setDateTime(Qgis.MetadataDateType.Revised, QDateTime(QDate(2020, 1, 3), QTime(1, 2, 3))) - - m2.setDateTime(Qgis.MetadataDateType.Revised, QDateTime(QDate(2020, 1, 4), QTime(1, 2, 3))) - m2.setDateTime(Qgis.MetadataDateType.Superseded, QDateTime(QDate(2020, 1, 5), QTime(1, 2, 3))) + self.assertEqual( + m1.links(), + [QgsAbstractMetadataBase.Link("l2"), QgsAbstractMetadataBase.Link("ll2")], + ) + + m1.setDateTime( + Qgis.MetadataDateType.Created, QDateTime(QDate(2020, 1, 2), QTime(1, 2, 3)) + ) + m1.setDateTime( + Qgis.MetadataDateType.Revised, QDateTime(QDate(2020, 1, 3), QTime(1, 2, 3)) + ) + + m2.setDateTime( + Qgis.MetadataDateType.Revised, QDateTime(QDate(2020, 1, 4), QTime(1, 2, 3)) + ) + m2.setDateTime( + Qgis.MetadataDateType.Superseded, + QDateTime(QDate(2020, 1, 5), QTime(1, 2, 3)), + ) m1.combine(m2) - self.assertEqual(m1.dateTime(Qgis.MetadataDateType.Created), QDateTime(QDate(2020, 1, 2), QTime(1, 2, 3))) - self.assertEqual(m1.dateTime(Qgis.MetadataDateType.Revised), - QDateTime(QDate(2020, 1, 4), QTime(1, 2, 3))) - self.assertEqual(m1.dateTime(Qgis.MetadataDateType.Superseded), - QDateTime(QDate(2020, 1, 5), QTime(1, 2, 3))) + self.assertEqual( + m1.dateTime(Qgis.MetadataDateType.Created), + QDateTime(QDate(2020, 1, 2), QTime(1, 2, 3)), + ) + self.assertEqual( + m1.dateTime(Qgis.MetadataDateType.Revised), + QDateTime(QDate(2020, 1, 4), QTime(1, 2, 3)), + ) + self.assertEqual( + m1.dateTime(Qgis.MetadataDateType.Superseded), + QDateTime(QDate(2020, 1, 5), QTime(1, 2, 3)), + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmetadatautils.py b/tests/src/python/test_qgsmetadatautils.py index edcece09d0b5..3af7a34d95ea 100644 --- a/tests/src/python/test_qgsmetadatautils.py +++ b/tests/src/python/test_qgsmetadatautils.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2021-04-29' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2021-04-29" +__copyright__ = "Copyright 2021, The QGIS Project" from qgis.PyQt.QtCore import QDateTime from qgis.PyQt.QtXml import QDomDocument @@ -27,100 +28,167 @@ def testConvertEsri(self): """ Test ESRI metadata conversion """ - src = TEST_DATA_DIR + '/esri_metadata.xml' + src = TEST_DATA_DIR + "/esri_metadata.xml" doc = QDomDocument() with open(src) as f: - doc.setContent('\n'.join(f.readlines())) + doc.setContent("\n".join(f.readlines())) metadata = QgsMetadataUtils.convertFromEsri(doc) - self.assertEqual(metadata.title(), 'Baseline roads and tracks Queensland') - self.assertEqual(metadata.identifier(), 'Baseline_roads_and_tracks') - self.assertEqual(metadata.abstract(), - 'This dataset represents street centrelines of Queensland. \n\nTo provide the digital road network of Queensland. \n\nThis is supplementary info') - self.assertEqual(metadata.language(), 'ENG') - self.assertEqual(metadata.keywords(), {'Search keys': ['road'], 'gmd:topicCategory': ['TRANSPORTATION Land']}) - self.assertEqual(metadata.categories(), ['TRANSPORTATION Land']) - self.assertEqual(metadata.extent().temporalExtents()[0].begin(), QDateTime(2016, 6, 28, 0, 0)) - self.assertEqual(metadata.crs().authid(), 'EPSG:4283') - self.assertEqual(metadata.extent().spatialExtents()[0].bounds.xMinimum(), 137.921721) - self.assertEqual(metadata.extent().spatialExtents()[0].bounds.xMaximum(), 153.551682) - self.assertEqual(metadata.extent().spatialExtents()[0].bounds.yMinimum(), -29.177948) - self.assertEqual(metadata.extent().spatialExtents()[0].bounds.yMaximum(), -9.373145) - self.assertEqual(metadata.extent().spatialExtents()[0].extentCrs.authid(), 'EPSG:4283') - - self.assertEqual(metadata.dateTime(Qgis.MetadataDateType.Created), QDateTime(2022, 11, 1, 0, 0)) - self.assertEqual(metadata.dateTime(Qgis.MetadataDateType.Published), QDateTime(2016, 6, 28, 0, 0)) - self.assertEqual(metadata.dateTime(Qgis.MetadataDateType.Revised), QDateTime(2022, 11, 5, 0, 0)) - self.assertEqual(metadata.dateTime(Qgis.MetadataDateType.Superseded), QDateTime(2022, 11, 12, 0, 0)) - - self.assertEqual(metadata.licenses(), ['This material is licensed under a CC4']) - self.assertEqual(metadata.rights(), ['The State of Queensland (Department of Natural Resources and Mines)', - '© State of Queensland (Department of Natural Resources and Mines) 2016']) - self.assertIn('Unrestricted to all levels of government and community.', metadata.constraints()[0].constraint) - self.assertEqual(metadata.constraints()[0].type, 'Security constraints') - self.assertIn('Dataset is wholly created and owned by Natural Resources and Mines for the State of Queensland', - metadata.constraints()[1].constraint) - self.assertEqual(metadata.constraints()[1].type, 'Limitations of use') - - self.assertEqual(metadata.links()[0].type, 'Download Service') - self.assertEqual(metadata.links()[0].name, 'Queensland Spatial Catalog') - self.assertEqual(metadata.links()[0].url, 'http://qldspatial.information.qld.gov.au/catalog/custom/') - - self.assertEqual(metadata.history(), [ - 'The street records of the State Digital Road Network (SDRN) baseline dataset have been generated from road casement boundaries of the QLD Digital Cadastre Database (DCDB)and updated where more accurate source data has been available. Other sources used in the maintenance of the streets dataset include aerial imagery, QLD Department of Transport and Main Roads State Controlled Roads dataset, supplied datasets from other State Government Departments, Local Government data, field work using GPS, and user feedback. ', - 'Data source: Land parcel boundaries Queensland', - 'Data source: QLD Department of Transport and Main Roads State Controlled Roads', - 'Data source: Local Government data', 'Data source: field work', - 'Data source: other State Government Departments']) - - self.assertEqual(metadata.contacts()[0].name, 'Name') - self.assertEqual(metadata.contacts()[0].email, 'someone@gov.au') - self.assertEqual(metadata.contacts()[0].voice, '77777777') - self.assertEqual(metadata.contacts()[0].role, 'Point of contact') - self.assertEqual(metadata.contacts()[0].organization, 'Department of Natural Resources and Mines') + self.assertEqual(metadata.title(), "Baseline roads and tracks Queensland") + self.assertEqual(metadata.identifier(), "Baseline_roads_and_tracks") + self.assertEqual( + metadata.abstract(), + "This dataset represents street centrelines of Queensland. \n\nTo provide the digital road network of Queensland. \n\nThis is supplementary info", + ) + self.assertEqual(metadata.language(), "ENG") + self.assertEqual( + metadata.keywords(), + {"Search keys": ["road"], "gmd:topicCategory": ["TRANSPORTATION Land"]}, + ) + self.assertEqual(metadata.categories(), ["TRANSPORTATION Land"]) + self.assertEqual( + metadata.extent().temporalExtents()[0].begin(), QDateTime(2016, 6, 28, 0, 0) + ) + self.assertEqual(metadata.crs().authid(), "EPSG:4283") + self.assertEqual( + metadata.extent().spatialExtents()[0].bounds.xMinimum(), 137.921721 + ) + self.assertEqual( + metadata.extent().spatialExtents()[0].bounds.xMaximum(), 153.551682 + ) + self.assertEqual( + metadata.extent().spatialExtents()[0].bounds.yMinimum(), -29.177948 + ) + self.assertEqual( + metadata.extent().spatialExtents()[0].bounds.yMaximum(), -9.373145 + ) + self.assertEqual( + metadata.extent().spatialExtents()[0].extentCrs.authid(), "EPSG:4283" + ) + + self.assertEqual( + metadata.dateTime(Qgis.MetadataDateType.Created), + QDateTime(2022, 11, 1, 0, 0), + ) + self.assertEqual( + metadata.dateTime(Qgis.MetadataDateType.Published), + QDateTime(2016, 6, 28, 0, 0), + ) + self.assertEqual( + metadata.dateTime(Qgis.MetadataDateType.Revised), + QDateTime(2022, 11, 5, 0, 0), + ) + self.assertEqual( + metadata.dateTime(Qgis.MetadataDateType.Superseded), + QDateTime(2022, 11, 12, 0, 0), + ) + + self.assertEqual(metadata.licenses(), ["This material is licensed under a CC4"]) + self.assertEqual( + metadata.rights(), + [ + "The State of Queensland (Department of Natural Resources and Mines)", + "© State of Queensland (Department of Natural Resources and Mines) 2016", + ], + ) + self.assertIn( + "Unrestricted to all levels of government and community.", + metadata.constraints()[0].constraint, + ) + self.assertEqual(metadata.constraints()[0].type, "Security constraints") + self.assertIn( + "Dataset is wholly created and owned by Natural Resources and Mines for the State of Queensland", + metadata.constraints()[1].constraint, + ) + self.assertEqual(metadata.constraints()[1].type, "Limitations of use") + + self.assertEqual(metadata.links()[0].type, "Download Service") + self.assertEqual(metadata.links()[0].name, "Queensland Spatial Catalog") + self.assertEqual( + metadata.links()[0].url, + "http://qldspatial.information.qld.gov.au/catalog/custom/", + ) + + self.assertEqual( + metadata.history(), + [ + "The street records of the State Digital Road Network (SDRN) baseline dataset have been generated from road casement boundaries of the QLD Digital Cadastre Database (DCDB)and updated where more accurate source data has been available. Other sources used in the maintenance of the streets dataset include aerial imagery, QLD Department of Transport and Main Roads State Controlled Roads dataset, supplied datasets from other State Government Departments, Local Government data, field work using GPS, and user feedback. ", + "Data source: Land parcel boundaries Queensland", + "Data source: QLD Department of Transport and Main Roads State Controlled Roads", + "Data source: Local Government data", + "Data source: field work", + "Data source: other State Government Departments", + ], + ) + + self.assertEqual(metadata.contacts()[0].name, "Name") + self.assertEqual(metadata.contacts()[0].email, "someone@gov.au") + self.assertEqual(metadata.contacts()[0].voice, "77777777") + self.assertEqual(metadata.contacts()[0].role, "Point of contact") + self.assertEqual( + metadata.contacts()[0].organization, + "Department of Natural Resources and Mines", + ) def testConvertEsriOld(self): """ Test ESRI metadata conversion of older xml format """ - src = TEST_DATA_DIR + '/esri_metadata2.xml' + src = TEST_DATA_DIR + "/esri_metadata2.xml" doc = QDomDocument() with open(src) as f: - doc.setContent('\n'.join(f.readlines())) + doc.setContent("\n".join(f.readlines())) metadata = QgsMetadataUtils.convertFromEsri(doc) - self.assertEqual(metadata.title(), 'QLD_STRUCTURAL_FRAMEWORK_OUTLINE') - self.assertEqual(metadata.identifier(), 'QLD_STRUCTURAL_FRAMEWORK_OUTLINE') - self.assertEqual(metadata.abstract(), - 'abstract pt 1 \n\npurpose pt 1\n\nsupp info pt 1') - self.assertEqual(metadata.language(), 'EN') - self.assertEqual(metadata.keywords(), {'gmd:topicCategory': ['GEOSCIENCES Geology']}) - self.assertEqual(metadata.categories(), ['GEOSCIENCES Geology']) - self.assertEqual(metadata.extent().temporalExtents()[0].begin(), QDateTime(2012, 7, 1, 0, 0)) - self.assertEqual(metadata.extent().spatialExtents()[0].bounds.xMinimum(), 137.9947) - self.assertEqual(metadata.extent().spatialExtents()[0].bounds.xMaximum(), 153.55183) - self.assertEqual(metadata.extent().spatialExtents()[0].bounds.yMinimum(), -29.17849) - self.assertEqual(metadata.extent().spatialExtents()[0].bounds.yMaximum(), -9.2296) - - self.assertEqual(metadata.rights(), ['Creative Commons Attribution 3.0 Australia (CC BY)']) - self.assertIn('Unrestricted to all levels of government and community.', - metadata.constraints()[0].constraint) - self.assertEqual(metadata.constraints()[0].type, 'Access') - - self.assertEqual(metadata.links()[0].type, 'Local Area Network') - self.assertEqual(metadata.links()[0].name, 'Shapefile') - self.assertEqual(metadata.links()[0].url, 'file://some.shp') - - self.assertEqual(metadata.contacts()[0].name, 'org') - self.assertEqual(metadata.contacts()[0].email, 'someone@gov.au') - self.assertEqual(metadata.contacts()[0].voice, '777') - self.assertEqual(metadata.contacts()[0].role, 'Point of contact') - self.assertEqual(metadata.contacts()[0].organization, 'org') - self.assertEqual(metadata.contacts()[0].addresses[0].type, 'mailing address') - self.assertEqual(metadata.contacts()[0].addresses[0].city, 'BRISBANE CITY EAST') - self.assertEqual(metadata.contacts()[0].addresses[1].type, 'physical address') - self.assertEqual(metadata.contacts()[0].addresses[1].city, 'BRISBANE CITY EAST') - - -if __name__ == '__main__': + self.assertEqual(metadata.title(), "QLD_STRUCTURAL_FRAMEWORK_OUTLINE") + self.assertEqual(metadata.identifier(), "QLD_STRUCTURAL_FRAMEWORK_OUTLINE") + self.assertEqual( + metadata.abstract(), "abstract pt 1 \n\npurpose pt 1\n\nsupp info pt 1" + ) + self.assertEqual(metadata.language(), "EN") + self.assertEqual( + metadata.keywords(), {"gmd:topicCategory": ["GEOSCIENCES Geology"]} + ) + self.assertEqual(metadata.categories(), ["GEOSCIENCES Geology"]) + self.assertEqual( + metadata.extent().temporalExtents()[0].begin(), QDateTime(2012, 7, 1, 0, 0) + ) + self.assertEqual( + metadata.extent().spatialExtents()[0].bounds.xMinimum(), 137.9947 + ) + self.assertEqual( + metadata.extent().spatialExtents()[0].bounds.xMaximum(), 153.55183 + ) + self.assertEqual( + metadata.extent().spatialExtents()[0].bounds.yMinimum(), -29.17849 + ) + self.assertEqual( + metadata.extent().spatialExtents()[0].bounds.yMaximum(), -9.2296 + ) + + self.assertEqual( + metadata.rights(), ["Creative Commons Attribution 3.0 Australia (CC BY)"] + ) + self.assertIn( + "Unrestricted to all levels of government and community.", + metadata.constraints()[0].constraint, + ) + self.assertEqual(metadata.constraints()[0].type, "Access") + + self.assertEqual(metadata.links()[0].type, "Local Area Network") + self.assertEqual(metadata.links()[0].name, "Shapefile") + self.assertEqual(metadata.links()[0].url, "file://some.shp") + + self.assertEqual(metadata.contacts()[0].name, "org") + self.assertEqual(metadata.contacts()[0].email, "someone@gov.au") + self.assertEqual(metadata.contacts()[0].voice, "777") + self.assertEqual(metadata.contacts()[0].role, "Point of contact") + self.assertEqual(metadata.contacts()[0].organization, "org") + self.assertEqual(metadata.contacts()[0].addresses[0].type, "mailing address") + self.assertEqual(metadata.contacts()[0].addresses[0].city, "BRISBANE CITY EAST") + self.assertEqual(metadata.contacts()[0].addresses[1].type, "physical address") + self.assertEqual(metadata.contacts()[0].addresses[1].city, "BRISBANE CITY EAST") + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmetadatawidget.py b/tests/src/python/test_qgsmetadatawidget.py index d153ec45c3f1..3d33fa4787a9 100644 --- a/tests/src/python/test_qgsmetadatawidget.py +++ b/tests/src/python/test_qgsmetadatawidget.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '20/03/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "20/03/2018" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, QTime from qgis.core import ( @@ -38,83 +39,92 @@ def testLayerMode(self): w = QgsMetadataWidget() m = QgsLayerMetadata() - m.setIdentifier('1234') - m.setParentIdentifier('xyz') - m.setLanguage('en-CA') - m.setType('dataset') - m.setTitle('roads') - m.setAbstract('my roads') - m.setFees('None') - m.setConstraints([QgsLayerMetadata.Constraint('None', 'access')]) - m.setRights(['Copyright foo 2017']) - m.setLicenses(['WTFPL']) - m.setHistory(['history a', 'history b']) - m.setKeywords({ - 'GEMET': ['kw1', 'kw2'], - 'gmd:topicCategory': ['natural'], - }) + m.setIdentifier("1234") + m.setParentIdentifier("xyz") + m.setLanguage("en-CA") + m.setType("dataset") + m.setTitle("roads") + m.setAbstract("my roads") + m.setFees("None") + m.setConstraints([QgsLayerMetadata.Constraint("None", "access")]) + m.setRights(["Copyright foo 2017"]) + m.setLicenses(["WTFPL"]) + m.setHistory(["history a", "history b"]) + m.setKeywords( + { + "GEMET": ["kw1", "kw2"], + "gmd:topicCategory": ["natural"], + } + ) # m.setEncoding('utf-8') - m.setCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:4326')) + m.setCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs("EPSG:4326")) e = QgsLayerMetadata.Extent() se = QgsLayerMetadata.SpatialExtent() - se.extentCrs = QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:4326') + se.extentCrs = QgsCoordinateReferenceSystem.fromOgcWmsCrs("EPSG:4326") se.bounds = QgsBox3d(-180, -90, 0, 180, 90, 0) e.setSpatialExtents([se]) dates = [ QgsDateTimeRange( QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)), - QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))) + QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)), + ) ] e.setTemporalExtents(dates) m.setExtent(e) c = QgsLayerMetadata.Contact() - c.name = 'John Smith' - c.organization = 'ACME' - c.position = 'staff' - c.voice = '1500 515 555' - c.fax = 'xx.xxx.xxx.xxxx' - c.email = 'foo@example.org' - c.role = 'pointOfContact' + c.name = "John Smith" + c.organization = "ACME" + c.position = "staff" + c.voice = "1500 515 555" + c.fax = "xx.xxx.xxx.xxxx" + c.email = "foo@example.org" + c.role = "pointOfContact" address = QgsLayerMetadata.Address() - address.type = 'postal' - address.address = '123 Main Street' - address.city = 'anycity' - address.administrativeArea = 'anyprovince' - address.postalCode = '90210' - address.country = 'Canada' + address.type = "postal" + address.address = "123 Main Street" + address.city = "anycity" + address.administrativeArea = "anyprovince" + address.postalCode = "90210" + address.country = "Canada" c.addresses = [address] m.setContacts([c]) l = QgsLayerMetadata.Link() - l.name = 'geonode:roads' - l.type = 'OGC:WMS' - l.description = 'my GeoNode road layer' - l.url = 'http://example.org/wms' + l.name = "geonode:roads" + l.type = "OGC:WMS" + l.description = "my GeoNode road layer" + l.url = "http://example.org/wms" l2 = QgsLayerMetadata.Link() - l2.name = 'geonode:roads' - l2.type = 'OGC:WFS' - l2.description = 'my GeoNode road layer' - l2.url = 'http://example.org/wfs' + l2.name = "geonode:roads" + l2.type = "OGC:WFS" + l2.description = "my GeoNode road layer" + l2.url = "http://example.org/wfs" l3 = QgsLayerMetadata.Link() - l3.name = 'roads' - l3.type = 'WWW:LINK' - l3.description = 'full dataset download' - l3.url = 'http://example.org/roads.tgz' - l3.format = 'ESRI Shapefile' - l3.mimeType = 'application/gzip' - l3.size = '283676' + l3.name = "roads" + l3.type = "WWW:LINK" + l3.description = "full dataset download" + l3.url = "http://example.org/roads.tgz" + l3.format = "ESRI Shapefile" + l3.mimeType = "application/gzip" + l3.size = "283676" m.setLinks([l, l2, l3]) - m.setDateTime(Qgis.MetadataDateType.Published, QDateTime(QDate(2020, 1, 2), QTime(3, 4, 5))) - m.setDateTime(Qgis.MetadataDateType.Revised, - QDateTime(QDate(2020, 1, 3), QTime(3, 4, 5))) - m.setDateTime(Qgis.MetadataDateType.Superseded, - QDateTime(QDate(2020, 1, 4), QTime(3, 4, 5))) + m.setDateTime( + Qgis.MetadataDateType.Published, + QDateTime(QDate(2020, 1, 2), QTime(3, 4, 5)), + ) + m.setDateTime( + Qgis.MetadataDateType.Revised, QDateTime(QDate(2020, 1, 3), QTime(3, 4, 5)) + ) + m.setDateTime( + Qgis.MetadataDateType.Superseded, + QDateTime(QDate(2020, 1, 4), QTime(3, 4, 5)), + ) # set widget metadata w.setMetadata(m) @@ -123,67 +133,77 @@ def testLayerMode(self): m = w.metadata() self.assertIsInstance(m, QgsLayerMetadata) - self.assertEqual(m.identifier(), '1234') - self.assertEqual(m.parentIdentifier(), 'xyz') - self.assertEqual(m.language(), 'en-CA') - self.assertEqual(m.type(), 'dataset') - self.assertEqual(m.title(), 'roads') - self.assertEqual(m.abstract(), 'my roads') - self.assertEqual(m.fees(), 'None') - self.assertEqual(m.constraints()[0].constraint, 'None') - self.assertEqual(m.constraints()[0].type, 'access') - self.assertEqual(m.rights(), ['Copyright foo 2017']) - self.assertEqual(m.licenses(), ['WTFPL']) - self.assertEqual(m.history(), ['history a', 'history b']) + self.assertEqual(m.identifier(), "1234") + self.assertEqual(m.parentIdentifier(), "xyz") + self.assertEqual(m.language(), "en-CA") + self.assertEqual(m.type(), "dataset") + self.assertEqual(m.title(), "roads") + self.assertEqual(m.abstract(), "my roads") + self.assertEqual(m.fees(), "None") + self.assertEqual(m.constraints()[0].constraint, "None") + self.assertEqual(m.constraints()[0].type, "access") + self.assertEqual(m.rights(), ["Copyright foo 2017"]) + self.assertEqual(m.licenses(), ["WTFPL"]) + self.assertEqual(m.history(), ["history a", "history b"]) # self.assertEqual(m.encoding(), 'utf-8') self.assertEqual( - m.keywords(), - {'GEMET': ['kw1', 'kw2'], 'gmd:topicCategory': ['natural']}) - self.assertEqual(m.crs().authid(), 'EPSG:4326') + m.keywords(), {"GEMET": ["kw1", "kw2"], "gmd:topicCategory": ["natural"]} + ) + self.assertEqual(m.crs().authid(), "EPSG:4326") extent = m.extent().spatialExtents()[0] - self.assertEqual(extent.extentCrs.authid(), 'EPSG:4326') + self.assertEqual(extent.extentCrs.authid(), "EPSG:4326") self.assertEqual(extent.bounds.xMinimum(), -180.0) self.assertEqual(extent.bounds.yMinimum(), -90.0) self.assertEqual(extent.bounds.xMaximum(), 180.0) self.assertEqual(extent.bounds.yMaximum(), 90.0) - self.assertEqual(m.extent().temporalExtents()[0].begin(), QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))) + self.assertEqual( + m.extent().temporalExtents()[0].begin(), + QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)), + ) self.assertTrue(m.extent().temporalExtents()[0].isInstant()) - self.assertEqual(m.contacts()[0].name, 'John Smith') - self.assertEqual(m.contacts()[0].organization, 'ACME') - self.assertEqual(m.contacts()[0].position, 'staff') - self.assertEqual(m.contacts()[0].voice, '1500 515 555') - self.assertEqual(m.contacts()[0].fax, 'xx.xxx.xxx.xxxx') - self.assertEqual(m.contacts()[0].email, 'foo@example.org') - self.assertEqual(m.contacts()[0].role, 'pointOfContact') - self.assertEqual(m.contacts()[0].addresses[0].type, 'postal') - self.assertEqual(m.contacts()[0].addresses[0].address, '123 Main Street') - self.assertEqual(m.contacts()[0].addresses[0].city, 'anycity') - self.assertEqual(m.contacts()[0].addresses[0].administrativeArea, 'anyprovince') - self.assertEqual(m.contacts()[0].addresses[0].postalCode, '90210') - self.assertEqual(m.contacts()[0].addresses[0].country, 'Canada') - self.assertEqual(m.links()[0].name, 'geonode:roads') - self.assertEqual(m.links()[0].type, 'OGC:WMS') - self.assertEqual(m.links()[0].description, 'my GeoNode road layer') - self.assertEqual(m.links()[0].url, 'http://example.org/wms') - self.assertEqual(m.links()[1].name, 'geonode:roads') - self.assertEqual(m.links()[1].type, 'OGC:WFS') - self.assertEqual(m.links()[1].description, 'my GeoNode road layer') - self.assertEqual(m.links()[1].url, 'http://example.org/wfs') - self.assertEqual(m.links()[2].name, 'roads') - self.assertEqual(m.links()[2].type, 'WWW:LINK') - self.assertEqual(m.links()[2].description, 'full dataset download') - self.assertEqual(m.links()[2].url, 'http://example.org/roads.tgz') - self.assertEqual(m.links()[2].format, 'ESRI Shapefile') - self.assertEqual(m.links()[2].mimeType, 'application/gzip') - self.assertEqual(m.links()[2].size, '283676') - - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Published), QDateTime(QDate(2020, 1, 2), QTime(3, 4, 5))) - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Revised), - QDateTime(QDate(2020, 1, 3), QTime(3, 4, 5))) - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Superseded), - QDateTime(QDate(2020, 1, 4), QTime(3, 4, 5))) + self.assertEqual(m.contacts()[0].name, "John Smith") + self.assertEqual(m.contacts()[0].organization, "ACME") + self.assertEqual(m.contacts()[0].position, "staff") + self.assertEqual(m.contacts()[0].voice, "1500 515 555") + self.assertEqual(m.contacts()[0].fax, "xx.xxx.xxx.xxxx") + self.assertEqual(m.contacts()[0].email, "foo@example.org") + self.assertEqual(m.contacts()[0].role, "pointOfContact") + self.assertEqual(m.contacts()[0].addresses[0].type, "postal") + self.assertEqual(m.contacts()[0].addresses[0].address, "123 Main Street") + self.assertEqual(m.contacts()[0].addresses[0].city, "anycity") + self.assertEqual(m.contacts()[0].addresses[0].administrativeArea, "anyprovince") + self.assertEqual(m.contacts()[0].addresses[0].postalCode, "90210") + self.assertEqual(m.contacts()[0].addresses[0].country, "Canada") + self.assertEqual(m.links()[0].name, "geonode:roads") + self.assertEqual(m.links()[0].type, "OGC:WMS") + self.assertEqual(m.links()[0].description, "my GeoNode road layer") + self.assertEqual(m.links()[0].url, "http://example.org/wms") + self.assertEqual(m.links()[1].name, "geonode:roads") + self.assertEqual(m.links()[1].type, "OGC:WFS") + self.assertEqual(m.links()[1].description, "my GeoNode road layer") + self.assertEqual(m.links()[1].url, "http://example.org/wfs") + self.assertEqual(m.links()[2].name, "roads") + self.assertEqual(m.links()[2].type, "WWW:LINK") + self.assertEqual(m.links()[2].description, "full dataset download") + self.assertEqual(m.links()[2].url, "http://example.org/roads.tgz") + self.assertEqual(m.links()[2].format, "ESRI Shapefile") + self.assertEqual(m.links()[2].mimeType, "application/gzip") + self.assertEqual(m.links()[2].size, "283676") + + self.assertEqual( + m.dateTime(Qgis.MetadataDateType.Published), + QDateTime(QDate(2020, 1, 2), QTime(3, 4, 5)), + ) + self.assertEqual( + m.dateTime(Qgis.MetadataDateType.Revised), + QDateTime(QDate(2020, 1, 3), QTime(3, 4, 5)), + ) + self.assertEqual( + m.dateTime(Qgis.MetadataDateType.Superseded), + QDateTime(QDate(2020, 1, 4), QTime(3, 4, 5)), + ) def testDates(self): """ @@ -193,71 +213,81 @@ def testDates(self): m = QgsLayerMetadata() - m.setDateTime(Qgis.MetadataDateType.Created, - QDateTime(QDate(2020, 1, 2), QTime(3, 4, 5))) - m.setDateTime(Qgis.MetadataDateType.Superseded, - QDateTime(QDate(2020, 1, 4), QTime(3, 4, 5))) + m.setDateTime( + Qgis.MetadataDateType.Created, QDateTime(QDate(2020, 1, 2), QTime(3, 4, 5)) + ) + m.setDateTime( + Qgis.MetadataDateType.Superseded, + QDateTime(QDate(2020, 1, 4), QTime(3, 4, 5)), + ) # set widget metadata w.setMetadata(m) m = w.metadata() - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Created), - QDateTime(QDate(2020, 1, 2), QTime(3, 4, 5))) - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Published), - QDateTime()) - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Revised), - QDateTime()) - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Superseded), - QDateTime(QDate(2020, 1, 4), QTime(3, 4, 5))) + self.assertEqual( + m.dateTime(Qgis.MetadataDateType.Created), + QDateTime(QDate(2020, 1, 2), QTime(3, 4, 5)), + ) + self.assertEqual(m.dateTime(Qgis.MetadataDateType.Published), QDateTime()) + self.assertEqual(m.dateTime(Qgis.MetadataDateType.Revised), QDateTime()) + self.assertEqual( + m.dateTime(Qgis.MetadataDateType.Superseded), + QDateTime(QDate(2020, 1, 4), QTime(3, 4, 5)), + ) # with project metadata w = QgsMetadataWidget() m = QgsProjectMetadata() - m.setDateTime(Qgis.MetadataDateType.Created, - QDateTime(QDate(2020, 1, 2), QTime(3, 4, 5))) - m.setDateTime(Qgis.MetadataDateType.Superseded, - QDateTime(QDate(2020, 1, 4), QTime(3, 4, 5))) + m.setDateTime( + Qgis.MetadataDateType.Created, QDateTime(QDate(2020, 1, 2), QTime(3, 4, 5)) + ) + m.setDateTime( + Qgis.MetadataDateType.Superseded, + QDateTime(QDate(2020, 1, 4), QTime(3, 4, 5)), + ) # set widget metadata w.setMetadata(m) m = w.metadata() - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Created), - QDateTime(QDate(2020, 1, 2), QTime(3, 4, 5))) - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Published), - QDateTime()) - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Revised), - QDateTime()) - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Superseded), - QDateTime(QDate(2020, 1, 4), QTime(3, 4, 5))) + self.assertEqual( + m.dateTime(Qgis.MetadataDateType.Created), + QDateTime(QDate(2020, 1, 2), QTime(3, 4, 5)), + ) + self.assertEqual(m.dateTime(Qgis.MetadataDateType.Published), QDateTime()) + self.assertEqual(m.dateTime(Qgis.MetadataDateType.Revised), QDateTime()) + self.assertEqual( + m.dateTime(Qgis.MetadataDateType.Superseded), + QDateTime(QDate(2020, 1, 4), QTime(3, 4, 5)), + ) w = QgsMetadataWidget() m = QgsProjectMetadata() - m.setDateTime(Qgis.MetadataDateType.Created, - QDateTime()) - m.setDateTime(Qgis.MetadataDateType.Superseded, - QDateTime(QDate(2020, 1, 4), QTime(3, 4, 5))) + m.setDateTime(Qgis.MetadataDateType.Created, QDateTime()) + m.setDateTime( + Qgis.MetadataDateType.Superseded, + QDateTime(QDate(2020, 1, 4), QTime(3, 4, 5)), + ) # set widget metadata w.setMetadata(m) m = w.metadata() - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Created), - QDateTime()) - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Published), - QDateTime()) - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Revised), - QDateTime()) - self.assertEqual(m.dateTime(Qgis.MetadataDateType.Superseded), - QDateTime(QDate(2020, 1, 4), QTime(3, 4, 5))) + self.assertEqual(m.dateTime(Qgis.MetadataDateType.Created), QDateTime()) + self.assertEqual(m.dateTime(Qgis.MetadataDateType.Published), QDateTime()) + self.assertEqual(m.dateTime(Qgis.MetadataDateType.Revised), QDateTime()) + self.assertEqual( + m.dateTime(Qgis.MetadataDateType.Superseded), + QDateTime(QDate(2020, 1, 4), QTime(3, 4, 5)), + ) def testProjectMode(self): """ @@ -267,60 +297,62 @@ def testProjectMode(self): w = QgsMetadataWidget() m = QgsProjectMetadata() - m.setIdentifier('1234') - m.setParentIdentifier('xyz') - m.setLanguage('en-CA') - m.setType('project') - m.setTitle('roads') - m.setAbstract('my roads') - m.setHistory(['history a', 'history b']) - m.setKeywords({ - 'GEMET': ['kw1', 'kw2'], - 'gmd:topicCategory': ['natural'], - }) + m.setIdentifier("1234") + m.setParentIdentifier("xyz") + m.setLanguage("en-CA") + m.setType("project") + m.setTitle("roads") + m.setAbstract("my roads") + m.setHistory(["history a", "history b"]) + m.setKeywords( + { + "GEMET": ["kw1", "kw2"], + "gmd:topicCategory": ["natural"], + } + ) c = QgsAbstractMetadataBase.Contact() - c.name = 'John Smith' - c.organization = 'ACME' - c.position = 'staff' - c.voice = '1500 515 555' - c.fax = 'xx.xxx.xxx.xxxx' - c.email = 'foo@example.org' - c.role = 'pointOfContact' + c.name = "John Smith" + c.organization = "ACME" + c.position = "staff" + c.voice = "1500 515 555" + c.fax = "xx.xxx.xxx.xxxx" + c.email = "foo@example.org" + c.role = "pointOfContact" address = QgsAbstractMetadataBase.Address() - address.type = 'postal' - address.address = '123 Main Street' - address.city = 'anycity' - address.administrativeArea = 'anyprovince' - address.postalCode = '90210' - address.country = 'Canada' + address.type = "postal" + address.address = "123 Main Street" + address.city = "anycity" + address.administrativeArea = "anyprovince" + address.postalCode = "90210" + address.country = "Canada" c.addresses = [address] m.setContacts([c]) l = QgsAbstractMetadataBase.Link() - l.name = 'geonode:roads' - l.type = 'OGC:WMS' - l.description = 'my GeoNode road layer' - l.url = 'http://example.org/wms' + l.name = "geonode:roads" + l.type = "OGC:WMS" + l.description = "my GeoNode road layer" + l.url = "http://example.org/wms" l2 = QgsAbstractMetadataBase.Link() - l2.name = 'geonode:roads' - l2.type = 'OGC:WFS' - l2.description = 'my GeoNode road layer' - l2.url = 'http://example.org/wfs' + l2.name = "geonode:roads" + l2.type = "OGC:WFS" + l2.description = "my GeoNode road layer" + l2.url = "http://example.org/wfs" l3 = QgsAbstractMetadataBase.Link() - l3.name = 'roads' - l3.type = 'WWW:LINK' - l3.description = 'full dataset download' - l3.url = 'http://example.org/roads.tgz' - l3.format = 'ESRI Shapefile' - l3.mimeType = 'application/gzip' - l3.size = '283676' + l3.name = "roads" + l3.type = "WWW:LINK" + l3.description = "full dataset download" + l3.url = "http://example.org/roads.tgz" + l3.format = "ESRI Shapefile" + l3.mimeType = "application/gzip" + l3.size = "283676" m.setLinks([l, l2, l3]) - m.setAuthor('my author') + m.setAuthor("my author") m.setCreationDateTime(QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))) # set widget metadata @@ -330,49 +362,51 @@ def testProjectMode(self): m = w.metadata() self.assertIsInstance(m, QgsProjectMetadata) - self.assertEqual(m.identifier(), '1234') - self.assertEqual(m.parentIdentifier(), 'xyz') - self.assertEqual(m.language(), 'en-CA') - self.assertEqual(m.type(), 'project') - self.assertEqual(m.title(), 'roads') - self.assertEqual(m.abstract(), 'my roads') - self.assertEqual(m.history(), ['history a', 'history b']) + self.assertEqual(m.identifier(), "1234") + self.assertEqual(m.parentIdentifier(), "xyz") + self.assertEqual(m.language(), "en-CA") + self.assertEqual(m.type(), "project") + self.assertEqual(m.title(), "roads") + self.assertEqual(m.abstract(), "my roads") + self.assertEqual(m.history(), ["history a", "history b"]) self.assertEqual( - m.keywords(), - {'GEMET': ['kw1', 'kw2'], 'gmd:topicCategory': ['natural']}) - - self.assertEqual(m.contacts()[0].name, 'John Smith') - self.assertEqual(m.contacts()[0].organization, 'ACME') - self.assertEqual(m.contacts()[0].position, 'staff') - self.assertEqual(m.contacts()[0].voice, '1500 515 555') - self.assertEqual(m.contacts()[0].fax, 'xx.xxx.xxx.xxxx') - self.assertEqual(m.contacts()[0].email, 'foo@example.org') - self.assertEqual(m.contacts()[0].role, 'pointOfContact') - self.assertEqual(m.contacts()[0].addresses[0].type, 'postal') - self.assertEqual(m.contacts()[0].addresses[0].address, '123 Main Street') - self.assertEqual(m.contacts()[0].addresses[0].city, 'anycity') - self.assertEqual(m.contacts()[0].addresses[0].administrativeArea, 'anyprovince') - self.assertEqual(m.contacts()[0].addresses[0].postalCode, '90210') - self.assertEqual(m.contacts()[0].addresses[0].country, 'Canada') - self.assertEqual(m.links()[0].name, 'geonode:roads') - self.assertEqual(m.links()[0].type, 'OGC:WMS') - self.assertEqual(m.links()[0].description, 'my GeoNode road layer') - self.assertEqual(m.links()[0].url, 'http://example.org/wms') - self.assertEqual(m.links()[1].name, 'geonode:roads') - self.assertEqual(m.links()[1].type, 'OGC:WFS') - self.assertEqual(m.links()[1].description, 'my GeoNode road layer') - self.assertEqual(m.links()[1].url, 'http://example.org/wfs') - self.assertEqual(m.links()[2].name, 'roads') - self.assertEqual(m.links()[2].type, 'WWW:LINK') - self.assertEqual(m.links()[2].description, 'full dataset download') - self.assertEqual(m.links()[2].url, 'http://example.org/roads.tgz') - self.assertEqual(m.links()[2].format, 'ESRI Shapefile') - self.assertEqual(m.links()[2].mimeType, 'application/gzip') - self.assertEqual(m.links()[2].size, '283676') - - self.assertEqual(m.author(), 'my author') - self.assertEqual(m.creationDateTime(), QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))) - - -if __name__ == '__main__': + m.keywords(), {"GEMET": ["kw1", "kw2"], "gmd:topicCategory": ["natural"]} + ) + + self.assertEqual(m.contacts()[0].name, "John Smith") + self.assertEqual(m.contacts()[0].organization, "ACME") + self.assertEqual(m.contacts()[0].position, "staff") + self.assertEqual(m.contacts()[0].voice, "1500 515 555") + self.assertEqual(m.contacts()[0].fax, "xx.xxx.xxx.xxxx") + self.assertEqual(m.contacts()[0].email, "foo@example.org") + self.assertEqual(m.contacts()[0].role, "pointOfContact") + self.assertEqual(m.contacts()[0].addresses[0].type, "postal") + self.assertEqual(m.contacts()[0].addresses[0].address, "123 Main Street") + self.assertEqual(m.contacts()[0].addresses[0].city, "anycity") + self.assertEqual(m.contacts()[0].addresses[0].administrativeArea, "anyprovince") + self.assertEqual(m.contacts()[0].addresses[0].postalCode, "90210") + self.assertEqual(m.contacts()[0].addresses[0].country, "Canada") + self.assertEqual(m.links()[0].name, "geonode:roads") + self.assertEqual(m.links()[0].type, "OGC:WMS") + self.assertEqual(m.links()[0].description, "my GeoNode road layer") + self.assertEqual(m.links()[0].url, "http://example.org/wms") + self.assertEqual(m.links()[1].name, "geonode:roads") + self.assertEqual(m.links()[1].type, "OGC:WFS") + self.assertEqual(m.links()[1].description, "my GeoNode road layer") + self.assertEqual(m.links()[1].url, "http://example.org/wfs") + self.assertEqual(m.links()[2].name, "roads") + self.assertEqual(m.links()[2].type, "WWW:LINK") + self.assertEqual(m.links()[2].description, "full dataset download") + self.assertEqual(m.links()[2].url, "http://example.org/roads.tgz") + self.assertEqual(m.links()[2].format, "ESRI Shapefile") + self.assertEqual(m.links()[2].mimeType, "application/gzip") + self.assertEqual(m.links()[2].size, "283676") + + self.assertEqual(m.author(), "my author") + self.assertEqual( + m.creationDateTime(), QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)) + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmssqlsqlquerybuilder.py b/tests/src/python/test_qgsmssqlsqlquerybuilder.py index daba771aaf7f..544c3c99224d 100644 --- a/tests/src/python/test_qgsmssqlsqlquerybuilder.py +++ b/tests/src/python/test_qgsmssqlsqlquerybuilder.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '25/08/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "25/08/2022" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.core import QgsProviderRegistry import unittest @@ -23,22 +24,28 @@ class TestQgsMsSqlQueryBuilder(QgisTestCase): def test_quoted_identifier(self): # we don't need a valid database to test this - md = QgsProviderRegistry.instance().providerMetadata('mssql') - conn = md.createConnection('', {}) + md = QgsProviderRegistry.instance().providerMetadata("mssql") + conn = md.createConnection("", {}) builder = conn.queryBuilder() - self.assertEqual(builder.quoteIdentifier('a'), '[a]') - self.assertEqual(builder.quoteIdentifier('a table'), '[a table]') - self.assertEqual(builder.quoteIdentifier('a TABLE'), '[a TABLE]') + self.assertEqual(builder.quoteIdentifier("a"), "[a]") + self.assertEqual(builder.quoteIdentifier("a table"), "[a table]") + self.assertEqual(builder.quoteIdentifier("a TABLE"), "[a TABLE]") self.assertEqual(builder.quoteIdentifier('a "TABLE"'), '[a "TABLE"]') def test_limit_query(self): # we don't need a valid database to test this - md = QgsProviderRegistry.instance().providerMetadata('mssql') - conn = md.createConnection('', {}) + md = QgsProviderRegistry.instance().providerMetadata("mssql") + conn = md.createConnection("", {}) builder = conn.queryBuilder() - self.assertEqual(builder.createLimitQueryForTable('my_schema', 'my_table', 99), 'SELECT TOP 99 * FROM [my_schema].[my_table]') - self.assertEqual(builder.createLimitQueryForTable(None, 'my_table', 99), 'SELECT TOP 99 * FROM [my_table]') + self.assertEqual( + builder.createLimitQueryForTable("my_schema", "my_table", 99), + "SELECT TOP 99 * FROM [my_schema].[my_table]", + ) + self.assertEqual( + builder.createLimitQueryForTable(None, "my_table", 99), + "SELECT TOP 99 * FROM [my_table]", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmultiedittoolbutton.py b/tests/src/python/test_qgsmultiedittoolbutton.py index 61da7101e575..3b9254ea86d7 100644 --- a/tests/src/python/test_qgsmultiedittoolbutton.py +++ b/tests/src/python/test_qgsmultiedittoolbutton.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '16/03/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "16/03/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.gui import QgsMultiEditToolButton @@ -59,5 +60,5 @@ def test_state_logic(self): self.assertEqual(w.state(), QgsMultiEditToolButton.State.Default) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmultilinestring.py b/tests/src/python/test_qgsmultilinestring.py index f0e487d74cc8..f57664982027 100644 --- a/tests/src/python/test_qgsmultilinestring.py +++ b/tests/src/python/test_qgsmultilinestring.py @@ -5,18 +5,14 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Loïc Bartoletti' -__date__ = '12/12/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "Loïc Bartoletti" +__date__ = "12/12/2023" +__copyright__ = "Copyright 2023, The QGIS Project" import qgis # NOQA -from qgis.core import ( - QgsMultiLineString, - QgsLineString, - QgsPoint, - QgsRectangle -) +from qgis.core import QgsMultiLineString, QgsLineString, QgsPoint, QgsRectangle import unittest from qgis.testing import start_app, QgisTestCase @@ -40,26 +36,49 @@ def testConstruct(self): value = QgsLineString([[1, 2], [10, 2], [10, 10]]) p = QgsMultiLineString([value]) - self.assertEqual(p.asWkt(), 'MultiLineString ((1 2, 10 2, 10 10))') + self.assertEqual(p.asWkt(), "MultiLineString ((1 2, 10 2, 10 10))") # constructor should have made internal copy del value - self.assertEqual(p.asWkt(), 'MultiLineString ((1 2, 10 2, 10 10))') + self.assertEqual(p.asWkt(), "MultiLineString ((1 2, 10 2, 10 10))") - p = QgsMultiLineString([QgsLineString([[1, 2], [10, 2], [10, 10], [1, 2]]), - QgsLineString([[100, 2], [110, 2], [110, 10], [100, 2]])]) - self.assertEqual(p.asWkt(), 'MultiLineString ((1 2, 10 2, 10 10, 1 2),(100 2, 110 2, 110 10, 100 2))') + p = QgsMultiLineString( + [ + QgsLineString([[1, 2], [10, 2], [10, 10], [1, 2]]), + QgsLineString([[100, 2], [110, 2], [110, 10], [100, 2]]), + ] + ) + self.assertEqual( + p.asWkt(), + "MultiLineString ((1 2, 10 2, 10 10, 1 2),(100 2, 110 2, 110 10, 100 2))", + ) # with z - p = QgsMultiLineString([QgsLineString([[1, 2, 3], [10, 2, 3], [10, 10, 3], [1, 2, 3]]), - QgsLineString([[100, 2, 4], [110, 2, 4], [110, 10, 4], [100, 2, 4]])]) - self.assertEqual(p.asWkt(), - 'MultiLineString Z ((1 2 3, 10 2 3, 10 10 3, 1 2 3),(100 2 4, 110 2 4, 110 10 4, 100 2 4))') + p = QgsMultiLineString( + [ + QgsLineString([[1, 2, 3], [10, 2, 3], [10, 10, 3], [1, 2, 3]]), + QgsLineString([[100, 2, 4], [110, 2, 4], [110, 10, 4], [100, 2, 4]]), + ] + ) + self.assertEqual( + p.asWkt(), + "MultiLineString Z ((1 2 3, 10 2 3, 10 10 3, 1 2 3),(100 2 4, 110 2 4, 110 10 4, 100 2 4))", + ) # with zm - p = QgsMultiLineString([QgsLineString([[1, 2, 3, 5], [10, 2, 3, 5], [10, 10, 3, 5], [1, 2, 3, 5]]), - QgsLineString([[100, 2, 4, 6], [110, 2, 4, 6], [110, 10, 4, 6], [100, 2, 4, 6]])]) - self.assertEqual(p.asWkt(), - 'MultiLineString ZM ((1 2 3 5, 10 2 3 5, 10 10 3 5, 1 2 3 5),(100 2 4 6, 110 2 4 6, 110 10 4 6, 100 2 4 6))') + p = QgsMultiLineString( + [ + QgsLineString( + [[1, 2, 3, 5], [10, 2, 3, 5], [10, 10, 3, 5], [1, 2, 3, 5]] + ), + QgsLineString( + [[100, 2, 4, 6], [110, 2, 4, 6], [110, 10, 4, 6], [100, 2, 4, 6]] + ), + ] + ) + self.assertEqual( + p.asWkt(), + "MultiLineString ZM ((1 2 3 5, 10 2 3 5, 10 10 3 5, 1 2 3 5),(100 2 4 6, 110 2 4 6, 110 10 4 6, 100 2 4 6))", + ) def testMeasureLine(self): multiline = QgsMultiLineString() @@ -68,26 +87,42 @@ def testMeasureLine(self): multiline.addGeometry(QgsLineString([[0, 0], [2, 0], [4, 0]])) m_line = multiline.measuredLine(10, 20) - self.assertEqual(m_line.geometryN(0), QgsLineString([QgsPoint(0, 0, m=10), QgsPoint(2, 0, m=15), QgsPoint(4, 0, m=20)])) + self.assertEqual( + m_line.geometryN(0), + QgsLineString( + [QgsPoint(0, 0, m=10), QgsPoint(2, 0, m=15), QgsPoint(4, 0, m=20)] + ), + ) multiline = QgsMultiLineString() multiline.addGeometry(QgsLineString([[0, 0], [9, 0], [10, 0]])) m_line = multiline.measuredLine(10, 20) - self.assertEqual(m_line.geometryN(0), QgsLineString([QgsPoint(0, 0, m=10), QgsPoint(9, 0, m=19), QgsPoint(10, 0, m=20)])) + self.assertEqual( + m_line.geometryN(0), + QgsLineString( + [QgsPoint(0, 0, m=10), QgsPoint(9, 0, m=19), QgsPoint(10, 0, m=20)] + ), + ) multiline = QgsMultiLineString() multiline.addGeometry(QgsLineString([[1, 0], [3, 0], [4, 0]])) multiline.addGeometry(QgsLineString([[0, 0], [9, 0], [10, 0]])) m_line = multiline.measuredLine(10, 20) self.assertEqual(m_line.numGeometries(), 2) - self.assertEqual(m_line.asWkt(0), "MultiLineString M ((1 0 10, 3 0 12, 4 0 12),(0 0 12, 9 0 19, 10 0 20))") + self.assertEqual( + m_line.asWkt(0), + "MultiLineString M ((1 0 10, 3 0 12, 4 0 12),(0 0 12, 9 0 19, 10 0 20))", + ) multiline = QgsMultiLineString() multiline.addGeometry(QgsLineString([[1, 0], [1, 0], [1, 0]])) multiline.addGeometry(QgsLineString([[2, 2], [2, 2], [2, 2]])) m_line = multiline.measuredLine(10, 20) self.assertEqual(m_line.numGeometries(), 2) - self.assertEqual(m_line.asWkt(0), "MultiLineString M ((1 0 nan, 1 0 nan, 1 0 nan),(2 2 nan, 2 2 nan, 2 2 nan))") + self.assertEqual( + m_line.asWkt(0), + "MultiLineString M ((1 0 nan, 1 0 nan, 1 0 nan),(2 2 nan, 2 2 nan, 2 2 nan))", + ) def testFuzzyComparisons(self): ###### @@ -148,13 +183,17 @@ def testFuzzyComparisons(self): epsilon = 0.001 geom1 = QgsMultiLineString() line1 = QgsLineString(QgsPoint(4.0, 5.0, m=6.0), QgsPoint(9.0, 8.0, m=7.0)) - line2 = QgsLineString(QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.001)) + line2 = QgsLineString( + QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.001) + ) geom1.addGeometry(line1) geom1.addGeometry(line2) geom2 = QgsMultiLineString() line1 = QgsLineString(QgsPoint(4.0, 5.0, m=6.0), QgsPoint(9.0, 8.0, m=7.0)) - line2 = QgsLineString(QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.002)) + line2 = QgsLineString( + QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.002) + ) geom2.addGeometry(line1) geom2.addGeometry(line2) @@ -173,14 +212,22 @@ def testFuzzyComparisons(self): ###### epsilon = 0.001 geom1 = QgsMultiLineString() - line1 = QgsLineString(QgsPoint(3.0, 4.0, 5.0, 6.0), QgsPoint(10.0, 9.0, 8.0, 7.0)) - line2 = QgsLineString(QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001, 0.001)) + line1 = QgsLineString( + QgsPoint(3.0, 4.0, 5.0, 6.0), QgsPoint(10.0, 9.0, 8.0, 7.0) + ) + line2 = QgsLineString( + QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001, 0.001) + ) geom1.addGeometry(line1) geom1.addGeometry(line2) geom2 = QgsMultiLineString() - line1 = QgsLineString(QgsPoint(3.0, 4.0, 5.0, 6.0), QgsPoint(10.0, 9.0, 8.0, 7.0)) - line2 = QgsLineString(QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001, 0.002)) + line1 = QgsLineString( + QgsPoint(3.0, 4.0, 5.0, 6.0), QgsPoint(10.0, 9.0, 8.0, 7.0) + ) + line2 = QgsLineString( + QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001, 0.002) + ) geom2.addGeometry(line1) geom2.addGeometry(line2) @@ -201,46 +248,55 @@ def test_add_geometries(self): # empty collection collection = QgsMultiLineString() self.assertTrue(collection.addGeometries([])) - self.assertEqual(collection.asWkt(), 'MultiLineString EMPTY') + self.assertEqual(collection.asWkt(), "MultiLineString EMPTY") self.assertEqual(collection.boundingBox(), QgsRectangle()) self.assertTrue( - collection.addGeometries([ - QgsLineString([[1, 2, 3], [3, 4, 3], [1, 4, 3], [1, 2, 3]]), - QgsLineString( - [[11, 22, 33], [13, 14, 33], [11, 14, 33], [11, 22, 33]])]) + collection.addGeometries( + [ + QgsLineString([[1, 2, 3], [3, 4, 3], [1, 4, 3], [1, 2, 3]]), + QgsLineString( + [[11, 22, 33], [13, 14, 33], [11, 14, 33], [11, 22, 33]] + ), + ] + ) + ) + self.assertEqual( + collection.asWkt(), + "MultiLineString Z ((1 2 3, 3 4 3, 1 4 3, 1 2 3),(11 22 33, 13 14 33, 11 14 33, 11 22 33))", ) - self.assertEqual(collection.asWkt(), - 'MultiLineString Z ((1 2 3, 3 4 3, 1 4 3, 1 2 3),(11 22 33, 13 14 33, 11 14 33, 11 22 33))') - self.assertEqual(collection.boundingBox(), - QgsRectangle(1, 2, 13, 22)) + self.assertEqual(collection.boundingBox(), QgsRectangle(1, 2, 13, 22)) # can't add non-linestrings - self.assertFalse( - collection.addGeometries([ - QgsPoint(100, 200)] - )) - self.assertEqual(collection.asWkt(), - 'MultiLineString Z ((1 2 3, 3 4 3, 1 4 3, 1 2 3),(11 22 33, 13 14 33, 11 14 33, 11 22 33))') - self.assertEqual(collection.boundingBox(), - QgsRectangle(1, 2, 13, 22)) + self.assertFalse(collection.addGeometries([QgsPoint(100, 200)])) + self.assertEqual( + collection.asWkt(), + "MultiLineString Z ((1 2 3, 3 4 3, 1 4 3, 1 2 3),(11 22 33, 13 14 33, 11 14 33, 11 22 33))", + ) + self.assertEqual(collection.boundingBox(), QgsRectangle(1, 2, 13, 22)) self.assertTrue( - collection.addGeometries([ - QgsLineString([[100, 2, 3], [300, 4, 3]])]) + collection.addGeometries([QgsLineString([[100, 2, 3], [300, 4, 3]])]) ) - self.assertEqual(collection.asWkt(), 'MultiLineString Z ((1 2 3, 3 4 3, 1 4 3, 1 2 3),(11 22 33, 13 14 33, 11 14 33, 11 22 33),(100 2 3, 300 4 3))') - self.assertEqual(collection.boundingBox(), - QgsRectangle(1, 2, 300, 22)) + self.assertEqual( + collection.asWkt(), + "MultiLineString Z ((1 2 3, 3 4 3, 1 4 3, 1 2 3),(11 22 33, 13 14 33, 11 14 33, 11 22 33),(100 2 3, 300 4 3))", + ) + self.assertEqual(collection.boundingBox(), QgsRectangle(1, 2, 300, 22)) def test_simplify_by_distance(self): """ test simplifyByDistance """ p = QgsMultiLineString() - p.fromWkt('MultiLineString( (0 0, 50 0, 70 0, 80 0, 100 0), (0 0, 50 1, 60 1, 100 0) )') - self.assertEqual(p.simplifyByDistance(10).asWkt(), 'MultiLineString ((0 0, 100 0),(0 0, 100 0))') + p.fromWkt( + "MultiLineString( (0 0, 50 0, 70 0, 80 0, 100 0), (0 0, 50 1, 60 1, 100 0) )" + ) + self.assertEqual( + p.simplifyByDistance(10).asWkt(), + "MultiLineString ((0 0, 100 0),(0 0, 100 0))", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmultipoint.py b/tests/src/python/test_qgsmultipoint.py index 84018148cfab..78b1cb4cc84e 100644 --- a/tests/src/python/test_qgsmultipoint.py +++ b/tests/src/python/test_qgsmultipoint.py @@ -5,18 +5,14 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Loïc Bartoletti' -__date__ = '19/12/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "Loïc Bartoletti" +__date__ = "19/12/2023" +__copyright__ = "Copyright 2023, The QGIS Project" import qgis # NOQA -from qgis.core import ( - QgsMultiPoint, - QgsPoint, - QgsRectangle, - QgsLineString -) +from qgis.core import QgsMultiPoint, QgsPoint, QgsRectangle, QgsLineString import unittest from qgis.testing import start_app, QgisTestCase @@ -117,46 +113,40 @@ def test_add_geometries(self): # empty collection collection = QgsMultiPoint() self.assertTrue(collection.addGeometries([])) - self.assertEqual(collection.asWkt(), 'MultiPoint EMPTY') + self.assertEqual(collection.asWkt(), "MultiPoint EMPTY") self.assertEqual(collection.boundingBox(), QgsRectangle()) self.assertTrue( - collection.addGeometries([ - QgsPoint(1, 2, 3), - QgsPoint(11, 22, 33)]) + collection.addGeometries([QgsPoint(1, 2, 3), QgsPoint(11, 22, 33)]) ) - self.assertEqual(collection.asWkt(), - 'MultiPoint Z ((1 2 3),(11 22 33))') - self.assertEqual(collection.boundingBox(), - QgsRectangle(1, 2, 11, 22)) + self.assertEqual(collection.asWkt(), "MultiPoint Z ((1 2 3),(11 22 33))") + self.assertEqual(collection.boundingBox(), QgsRectangle(1, 2, 11, 22)) # can't add non-points self.assertFalse( - collection.addGeometries([ - QgsLineString([[100, 200], [200, 200]])] - )) - self.assertEqual(collection.asWkt(), - 'MultiPoint Z ((1 2 3),(11 22 33))') - self.assertEqual(collection.boundingBox(), - QgsRectangle(1, 2, 11, 22)) + collection.addGeometries([QgsLineString([[100, 200], [200, 200]])]) + ) + self.assertEqual(collection.asWkt(), "MultiPoint Z ((1 2 3),(11 22 33))") + self.assertEqual(collection.boundingBox(), QgsRectangle(1, 2, 11, 22)) - self.assertTrue( - collection.addGeometries([ - QgsPoint(100, 2, 3)]) + self.assertTrue(collection.addGeometries([QgsPoint(100, 2, 3)])) + self.assertEqual( + collection.asWkt(), "MultiPoint Z ((1 2 3),(11 22 33),(100 2 3))" ) - self.assertEqual(collection.asWkt(), 'MultiPoint Z ((1 2 3),(11 22 33),(100 2 3))') - self.assertEqual(collection.boundingBox(), - QgsRectangle(1, 2, 100, 22)) + self.assertEqual(collection.boundingBox(), QgsRectangle(1, 2, 100, 22)) def test_simplify_by_distance(self): """ test simplifyByDistance """ p = QgsMultiPoint() - p.fromWkt('MultiPoint( 0 0, 50 0, 70 0, 80 0, 100 0)') + p.fromWkt("MultiPoint( 0 0, 50 0, 70 0, 80 0, 100 0)") # this is just a clone - self.assertEqual(p.simplifyByDistance(10).asWkt(), 'MultiPoint ((0 0),(50 0),(70 0),(80 0),(100 0))') + self.assertEqual( + p.simplifyByDistance(10).asWkt(), + "MultiPoint ((0 0),(50 0),(70 0),(80 0),(100 0))", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsmultipolygon.py b/tests/src/python/test_qgsmultipolygon.py index e482bc0fa97a..292a5fcb23fe 100644 --- a/tests/src/python/test_qgsmultipolygon.py +++ b/tests/src/python/test_qgsmultipolygon.py @@ -5,19 +5,14 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Loïc Bartoletti' -__date__ = '19/12/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "Loïc Bartoletti" +__date__ = "19/12/2023" +__copyright__ = "Copyright 2023, The QGIS Project" import qgis # NOQA -from qgis.core import ( - QgsMultiPolygon, - QgsPolygon, - QgsLineString, - QgsPoint, - QgsRectangle -) +from qgis.core import QgsMultiPolygon, QgsPolygon, QgsLineString, QgsPoint, QgsRectangle import unittest from qgis.testing import start_app, QgisTestCase @@ -32,27 +27,62 @@ def test_constructor(self): value = QgsPolygon(QgsLineString([[1, 2], [10, 2], [10, 10], [1, 2]])) p = QgsMultiPolygon([value]) - self.assertEqual(p.asWkt(), 'MultiPolygon (((1 2, 10 2, 10 10, 1 2)))') + self.assertEqual(p.asWkt(), "MultiPolygon (((1 2, 10 2, 10 10, 1 2)))") # constructor should have made internal copy del value - self.assertEqual(p.asWkt(), 'MultiPolygon (((1 2, 10 2, 10 10, 1 2)))') + self.assertEqual(p.asWkt(), "MultiPolygon (((1 2, 10 2, 10 10, 1 2)))") - p = QgsMultiPolygon([QgsPolygon(QgsLineString([[1, 2], [10, 2], [10, 10], [1, 2]])), - QgsPolygon(QgsLineString([[100, 2], [110, 2], [110, 10], [100, 2]]))]) - self.assertEqual(p.asWkt(), 'MultiPolygon (((1 2, 10 2, 10 10, 1 2)),((100 2, 110 2, 110 10, 100 2)))') + p = QgsMultiPolygon( + [ + QgsPolygon(QgsLineString([[1, 2], [10, 2], [10, 10], [1, 2]])), + QgsPolygon(QgsLineString([[100, 2], [110, 2], [110, 10], [100, 2]])), + ] + ) + self.assertEqual( + p.asWkt(), + "MultiPolygon (((1 2, 10 2, 10 10, 1 2)),((100 2, 110 2, 110 10, 100 2)))", + ) # with z - p = QgsMultiPolygon([QgsPolygon(QgsLineString([[1, 2, 3], [10, 2, 3], [10, 10, 3], [1, 2, 3]])), - QgsPolygon(QgsLineString([[100, 2, 4], [110, 2, 4], [110, 10, 4], [100, 2, 4]]))]) - self.assertEqual(p.asWkt(), - 'MultiPolygon Z (((1 2 3, 10 2 3, 10 10 3, 1 2 3)),((100 2 4, 110 2 4, 110 10 4, 100 2 4)))') + p = QgsMultiPolygon( + [ + QgsPolygon( + QgsLineString([[1, 2, 3], [10, 2, 3], [10, 10, 3], [1, 2, 3]]) + ), + QgsPolygon( + QgsLineString([[100, 2, 4], [110, 2, 4], [110, 10, 4], [100, 2, 4]]) + ), + ] + ) + self.assertEqual( + p.asWkt(), + "MultiPolygon Z (((1 2 3, 10 2 3, 10 10 3, 1 2 3)),((100 2 4, 110 2 4, 110 10 4, 100 2 4)))", + ) # with zm - p = QgsMultiPolygon([QgsPolygon(QgsLineString([[1, 2, 3, 5], [10, 2, 3, 5], [10, 10, 3, 5], [1, 2, 3, 5]])), - QgsPolygon( - QgsLineString([[100, 2, 4, 6], [110, 2, 4, 6], [110, 10, 4, 6], [100, 2, 4, 6]]))]) - self.assertEqual(p.asWkt(), - 'MultiPolygon ZM (((1 2 3 5, 10 2 3 5, 10 10 3 5, 1 2 3 5)),((100 2 4 6, 110 2 4 6, 110 10 4 6, 100 2 4 6)))') + p = QgsMultiPolygon( + [ + QgsPolygon( + QgsLineString( + [[1, 2, 3, 5], [10, 2, 3, 5], [10, 10, 3, 5], [1, 2, 3, 5]] + ) + ), + QgsPolygon( + QgsLineString( + [ + [100, 2, 4, 6], + [110, 2, 4, 6], + [110, 10, 4, 6], + [100, 2, 4, 6], + ] + ) + ), + ] + ) + self.assertEqual( + p.asWkt(), + "MultiPolygon ZM (((1 2 3 5, 10 2 3 5, 10 10 3 5, 1 2 3 5)),((100 2 4 6, 110 2 4 6, 110 10 4 6, 100 2 4 6)))", + ) def testFuzzyComparisons(self): ###### @@ -64,19 +94,51 @@ def testFuzzyComparisons(self): p1 = QgsPolygon() p1.setExteriorRing( - QgsLineString([QgsPoint(5.0, 5.0), QgsPoint(6.0, 5.0), QgsPoint(6.0, 6.0), QgsPoint(5.0, 5.0)])) + QgsLineString( + [ + QgsPoint(5.0, 5.0), + QgsPoint(6.0, 5.0), + QgsPoint(6.0, 6.0), + QgsPoint(5.0, 5.0), + ] + ) + ) p2 = QgsPolygon() p2.setExteriorRing( - QgsLineString([QgsPoint(0.0, 0.0), QgsPoint(0.001, 0.001), QgsPoint(0.003, 0.003), QgsPoint(0.0, 0.0)])) + QgsLineString( + [ + QgsPoint(0.0, 0.0), + QgsPoint(0.001, 0.001), + QgsPoint(0.003, 0.003), + QgsPoint(0.0, 0.0), + ] + ) + ) self.assertTrue(geom1.addGeometry(p1)) self.assertTrue(geom1.addGeometry(p2)) p1 = QgsPolygon() p1.setExteriorRing( - QgsLineString([QgsPoint(5.0, 5.0), QgsPoint(6.0, 5.0), QgsPoint(6.0, 6.0), QgsPoint(5.0, 5.0)])) + QgsLineString( + [ + QgsPoint(5.0, 5.0), + QgsPoint(6.0, 5.0), + QgsPoint(6.0, 6.0), + QgsPoint(5.0, 5.0), + ] + ) + ) p2 = QgsPolygon() p2.setExteriorRing( - QgsLineString([QgsPoint(0.0, 0.0), QgsPoint(0.002, 0.002), QgsPoint(0.003, 0.003), QgsPoint(0.0, 0.0)])) + QgsLineString( + [ + QgsPoint(0.0, 0.0), + QgsPoint(0.002, 0.002), + QgsPoint(0.003, 0.003), + QgsPoint(0.0, 0.0), + ] + ) + ) self.assertTrue(geom2.addGeometry(p1)) self.assertTrue(geom2.addGeometry(p2)) @@ -98,22 +160,52 @@ def testFuzzyComparisons(self): geom2 = QgsMultiPolygon() p1 = QgsPolygon() - p1.setExteriorRing(QgsLineString( - [QgsPoint(5.0, 5.0, 5.0), QgsPoint(6.0, 5.0, 5.0), QgsPoint(6.0, 6.0, 5.0), QgsPoint(5.0, 5.0, 5.0)])) + p1.setExteriorRing( + QgsLineString( + [ + QgsPoint(5.0, 5.0, 5.0), + QgsPoint(6.0, 5.0, 5.0), + QgsPoint(6.0, 6.0, 5.0), + QgsPoint(5.0, 5.0, 5.0), + ] + ) + ) p2 = QgsPolygon() - p2.setExteriorRing(QgsLineString( - [QgsPoint(0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001), QgsPoint(0.003, 0.003, 0.003), - QgsPoint(0.0, 0.0, 0.0)])) + p2.setExteriorRing( + QgsLineString( + [ + QgsPoint(0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.001), + QgsPoint(0.003, 0.003, 0.003), + QgsPoint(0.0, 0.0, 0.0), + ] + ) + ) self.assertTrue(geom1.addGeometry(p1)) self.assertTrue(geom1.addGeometry(p2)) p1 = QgsPolygon() - p1.setExteriorRing(QgsLineString( - [QgsPoint(5.0, 5.0, 5.0), QgsPoint(6.0, 5.0, 5.0), QgsPoint(6.0, 6.0, 5.0), QgsPoint(5.0, 5.0, 5.0)])) + p1.setExteriorRing( + QgsLineString( + [ + QgsPoint(5.0, 5.0, 5.0), + QgsPoint(6.0, 5.0, 5.0), + QgsPoint(6.0, 6.0, 5.0), + QgsPoint(5.0, 5.0, 5.0), + ] + ) + ) p2 = QgsPolygon() - p2.setExteriorRing(QgsLineString( - [QgsPoint(0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.002), QgsPoint(0.003, 0.003, 0.003), - QgsPoint(0.0, 0.0, 0.0)])) + p2.setExteriorRing( + QgsLineString( + [ + QgsPoint(0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.002), + QgsPoint(0.003, 0.003, 0.003), + QgsPoint(0.0, 0.0, 0.0), + ] + ) + ) self.assertTrue(geom2.addGeometry(p1)) self.assertTrue(geom2.addGeometry(p2)) @@ -135,24 +227,52 @@ def testFuzzyComparisons(self): geom2 = QgsMultiPolygon() p1 = QgsPolygon() - p1.setExteriorRing(QgsLineString( - [QgsPoint(5.0, 5.0, m=5.0), QgsPoint(6.0, 5.0, m=5.0), QgsPoint(6.0, 6.0, m=5.0), - QgsPoint(5.0, 5.0, m=5.0)])) + p1.setExteriorRing( + QgsLineString( + [ + QgsPoint(5.0, 5.0, m=5.0), + QgsPoint(6.0, 5.0, m=5.0), + QgsPoint(6.0, 6.0, m=5.0), + QgsPoint(5.0, 5.0, m=5.0), + ] + ) + ) p2 = QgsPolygon() - p2.setExteriorRing(QgsLineString( - [QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.001), QgsPoint(0.003, 0.003, m=0.003), - QgsPoint(0.0, 0.0, m=0.0)])) + p2.setExteriorRing( + QgsLineString( + [ + QgsPoint(0.0, 0.0, m=0.0), + QgsPoint(0.001, 0.001, m=0.001), + QgsPoint(0.003, 0.003, m=0.003), + QgsPoint(0.0, 0.0, m=0.0), + ] + ) + ) self.assertTrue(geom1.addGeometry(p1)) self.assertTrue(geom1.addGeometry(p2)) p1 = QgsPolygon() - p1.setExteriorRing(QgsLineString( - [QgsPoint(5.0, 5.0, m=5.0), QgsPoint(6.0, 5.0, m=5.0), QgsPoint(6.0, 6.0, m=5.0), - QgsPoint(5.0, 5.0, m=5.0)])) + p1.setExteriorRing( + QgsLineString( + [ + QgsPoint(5.0, 5.0, m=5.0), + QgsPoint(6.0, 5.0, m=5.0), + QgsPoint(6.0, 6.0, m=5.0), + QgsPoint(5.0, 5.0, m=5.0), + ] + ) + ) p2 = QgsPolygon() - p2.setExteriorRing(QgsLineString( - [QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.002), QgsPoint(0.003, 0.003, m=0.003), - QgsPoint(0.0, 0.0, m=0.0)])) + p2.setExteriorRing( + QgsLineString( + [ + QgsPoint(0.0, 0.0, m=0.0), + QgsPoint(0.001, 0.001, m=0.002), + QgsPoint(0.003, 0.003, m=0.003), + QgsPoint(0.0, 0.0, m=0.0), + ] + ) + ) self.assertTrue(geom2.addGeometry(p1)) self.assertTrue(geom2.addGeometry(p2)) @@ -174,24 +294,52 @@ def testFuzzyComparisons(self): geom2 = QgsMultiPolygon() p1 = QgsPolygon() - p1.setExteriorRing(QgsLineString( - [QgsPoint(5.0, 5.0, 5.0, 5.0), QgsPoint(6.0, 5.0, 5.0, 5.0), QgsPoint(6.0, 6.0, 5.0, 5.0), - QgsPoint(5.0, 5.0, 5.0, 5.0)])) + p1.setExteriorRing( + QgsLineString( + [ + QgsPoint(5.0, 5.0, 5.0, 5.0), + QgsPoint(6.0, 5.0, 5.0, 5.0), + QgsPoint(6.0, 6.0, 5.0, 5.0), + QgsPoint(5.0, 5.0, 5.0, 5.0), + ] + ) + ) p2 = QgsPolygon() - p2.setExteriorRing(QgsLineString( - [QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001, 0.001), QgsPoint(0.003, 0.003, 0.003, 0.003), - QgsPoint(0.0, 0.0, 0.0, 0.0)])) + p2.setExteriorRing( + QgsLineString( + [ + QgsPoint(0.0, 0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.001, 0.001), + QgsPoint(0.003, 0.003, 0.003, 0.003), + QgsPoint(0.0, 0.0, 0.0, 0.0), + ] + ) + ) self.assertTrue(geom1.addGeometry(p1)) self.assertTrue(geom1.addGeometry(p2)) p1 = QgsPolygon() - p1.setExteriorRing(QgsLineString( - [QgsPoint(5.0, 5.0, 5.0, 5.0), QgsPoint(6.0, 5.0, 5.0, 5.0), QgsPoint(6.0, 6.0, 5.0, 5.0), - QgsPoint(5.0, 5.0, 5.0, 5.0)])) + p1.setExteriorRing( + QgsLineString( + [ + QgsPoint(5.0, 5.0, 5.0, 5.0), + QgsPoint(6.0, 5.0, 5.0, 5.0), + QgsPoint(6.0, 6.0, 5.0, 5.0), + QgsPoint(5.0, 5.0, 5.0, 5.0), + ] + ) + ) p2 = QgsPolygon() - p2.setExteriorRing(QgsLineString( - [QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.002, 0.002), QgsPoint(0.003, 0.003, 0.003, 0.003), - QgsPoint(0.0, 0.0, 0.0, 0.0)])) + p2.setExteriorRing( + QgsLineString( + [ + QgsPoint(0.0, 0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.002, 0.002), + QgsPoint(0.003, 0.003, 0.003, 0.003), + QgsPoint(0.0, 0.0, 0.0, 0.0), + ] + ) + ) self.assertTrue(geom2.addGeometry(p1)) self.assertTrue(geom2.addGeometry(p2)) @@ -212,47 +360,71 @@ def test_add_geometries(self): # empty collection collection = QgsMultiPolygon() self.assertTrue(collection.addGeometries([])) - self.assertEqual(collection.asWkt(), 'MultiPolygon EMPTY') + self.assertEqual(collection.asWkt(), "MultiPolygon EMPTY") self.assertEqual(collection.boundingBox(), QgsRectangle()) self.assertTrue( - collection.addGeometries([ - QgsPolygon(QgsLineString([[1, 2, 3], [3, 4, 3], [1, 4, 3], [1, 2, 3]])), - QgsPolygon(QgsLineString( - [[11, 22, 33], [13, 14, 33], [11, 14, 33], [11, 22, 33]]))]) + collection.addGeometries( + [ + QgsPolygon( + QgsLineString([[1, 2, 3], [3, 4, 3], [1, 4, 3], [1, 2, 3]]) + ), + QgsPolygon( + QgsLineString( + [[11, 22, 33], [13, 14, 33], [11, 14, 33], [11, 22, 33]] + ) + ), + ] + ) + ) + self.assertEqual( + collection.asWkt(), + "MultiPolygon Z (((1 2 3, 3 4 3, 1 4 3, 1 2 3)),((11 22 33, 13 14 33, 11 14 33, 11 22 33)))", ) - self.assertEqual(collection.asWkt(), - 'MultiPolygon Z (((1 2 3, 3 4 3, 1 4 3, 1 2 3)),((11 22 33, 13 14 33, 11 14 33, 11 22 33)))') - self.assertEqual(collection.boundingBox(), - QgsRectangle(1, 2, 13, 22)) + self.assertEqual(collection.boundingBox(), QgsRectangle(1, 2, 13, 22)) # can't add non-polygons - self.assertFalse( - collection.addGeometries([ - QgsPoint(100, 200)] - )) - self.assertEqual(collection.asWkt(), - 'MultiPolygon Z (((1 2 3, 3 4 3, 1 4 3, 1 2 3)),((11 22 33, 13 14 33, 11 14 33, 11 22 33)))') - self.assertEqual(collection.boundingBox(), - QgsRectangle(1, 2, 13, 22)) + self.assertFalse(collection.addGeometries([QgsPoint(100, 200)])) + self.assertEqual( + collection.asWkt(), + "MultiPolygon Z (((1 2 3, 3 4 3, 1 4 3, 1 2 3)),((11 22 33, 13 14 33, 11 14 33, 11 22 33)))", + ) + self.assertEqual(collection.boundingBox(), QgsRectangle(1, 2, 13, 22)) self.assertTrue( - collection.addGeometries([ - QgsPolygon(QgsLineString([[100, 2, 3], [300, 4, 3], [300, 100, 3], [100, 2, 3]]))]) + collection.addGeometries( + [ + QgsPolygon( + QgsLineString( + [[100, 2, 3], [300, 4, 3], [300, 100, 3], [100, 2, 3]] + ) + ) + ] + ) + ) + self.assertEqual( + collection.asWkt(), + "MultiPolygon Z (((1 2 3, 3 4 3, 1 4 3, 1 2 3)),((11 22 33, 13 14 33, 11 14 33, 11 22 33)),((100 2 3, 300 4 3, 300 100 3, 100 2 3)))", ) - self.assertEqual(collection.asWkt(), 'MultiPolygon Z (((1 2 3, 3 4 3, 1 4 3, 1 2 3)),((11 22 33, 13 14 33, 11 14 33, 11 22 33)),((100 2 3, 300 4 3, 300 100 3, 100 2 3)))') - self.assertEqual(collection.boundingBox(), - QgsRectangle(1, 2, 300, 100)) + self.assertEqual(collection.boundingBox(), QgsRectangle(1, 2, 300, 100)) def test_simplify_by_distance(self): """ test simplifyByDistance """ p = QgsMultiPolygon() - p.fromWkt('MultiPolygon (((4.33843532846714908 1.48149845255473167, 4.47478429197079919 8.6398190364963412, 5.8382739270072932 16.47988443795619418, 10.61048764963503288 22.88828572262772809, 17.63245927007298519 27.72867392700729283, 27.04053775182481445 30.11478078832115912, 34.81242867153284237 28.34224426277371478, 42.51614510948904524 23.97907743065692188, 44.83407748905109713 17.84337407299268818, 44.15233267153284658 9.52608729927005982, 42.44797062773722018 1.75419637956203189, 37.26671001459853727 -4.65420490510949492, 29.5629935766423344 -6.63126487591242153, 18.51872753284671091 -7.31300969343067209, 7.1335890802919657 -5.13142627737227031, 5.15652910948904619 -1.9272256350365069, 4.33843532846714908 1.48149845255473167),(20.31173353218648003 19.78274965689762155, 17.28447821560356346 9.99697084282726678, 21.22695025580456729 4.57607178755088739, 26.01423773319150001 3.23844734533983569, 28.33748018545281155 3.87205892322928236, 32.20955093922164991 5.6320910840332985, 34.60319467791511983 8.37774125488756738, 35.23680625580456649 12.24981200865641284, 34.6735959643472782 15.84027761669661771, 32.13914965278949154 19.43074322473681548, 26.92945445680959438 22.03559082272676761, 22.98698241660859054 21.04997281267651488, 20.31173353218648003 19.78274965689762155)),((55.16037031610606789 15.48827118453581164, 57.8356192005281855 18.16352006895792215, 64.10133369299049377 20.27555866192274436, 70.71905461761360812 18.86753293327952719, 74.09831636635732366 16.4034879081538989, 75.71754595429702306 11.33459528503832558, 74.30952022565381299 6.47690652121922739, 69.38143017540255642 2.6752370538825474, 61.63728866786486549 1.90082290312877689, 56.4979947583171338 2.60483576745038192, 53.11873300957341826 6.82891295338003346, 52.83712786384477056 12.32021329508857832, 55.16037031610606789 15.48827118453581164)))') - self.assertEqual(p.simplifyByDistance(1).asWkt(3), 'MultiPolygon (((4.338 1.481, 5.838 16.48, 10.61 22.888, 17.632 27.729, 27.041 30.115, 34.812 28.342, 42.516 23.979, 44.834 17.843, 44.152 9.526, 42.448 1.754, 37.267 -4.654, 18.519 -7.313, 7.134 -5.131, 4.338 1.481),(20.312 19.783, 17.284 9.997, 21.227 4.576, 26.014 3.238, 32.21 5.632, 34.603 8.378, 35.237 12.25, 32.139 19.431, 26.929 22.036, 20.312 19.783)),((57.836 18.164, 64.101 20.276, 70.719 18.868, 74.098 16.403, 75.718 11.335, 74.31 6.477, 69.381 2.675, 56.498 2.605, 53.119 6.829, 52.837 12.32, 57.836 18.164)))') - self.assertEqual(p.simplifyByDistance(2).asWkt(3), 'MultiPolygon (((4.338 1.481, 5.838 16.48, 17.632 27.729, 27.041 30.115, 42.516 23.979, 44.152 9.526, 37.267 -4.654, 18.519 -7.313, 7.134 -5.131, 4.338 1.481),(20.312 19.783, 17.284 9.997, 21.227 4.576, 32.21 5.632, 35.237 12.25, 32.139 19.431, 26.929 22.036, 20.312 19.783)),((55.16 15.488, 64.101 20.276, 70.719 18.868, 75.718 11.335, 74.31 6.477, 69.381 2.675, 56.498 2.605, 53.119 6.829, 55.16 15.488)))') + p.fromWkt( + "MultiPolygon (((4.33843532846714908 1.48149845255473167, 4.47478429197079919 8.6398190364963412, 5.8382739270072932 16.47988443795619418, 10.61048764963503288 22.88828572262772809, 17.63245927007298519 27.72867392700729283, 27.04053775182481445 30.11478078832115912, 34.81242867153284237 28.34224426277371478, 42.51614510948904524 23.97907743065692188, 44.83407748905109713 17.84337407299268818, 44.15233267153284658 9.52608729927005982, 42.44797062773722018 1.75419637956203189, 37.26671001459853727 -4.65420490510949492, 29.5629935766423344 -6.63126487591242153, 18.51872753284671091 -7.31300969343067209, 7.1335890802919657 -5.13142627737227031, 5.15652910948904619 -1.9272256350365069, 4.33843532846714908 1.48149845255473167),(20.31173353218648003 19.78274965689762155, 17.28447821560356346 9.99697084282726678, 21.22695025580456729 4.57607178755088739, 26.01423773319150001 3.23844734533983569, 28.33748018545281155 3.87205892322928236, 32.20955093922164991 5.6320910840332985, 34.60319467791511983 8.37774125488756738, 35.23680625580456649 12.24981200865641284, 34.6735959643472782 15.84027761669661771, 32.13914965278949154 19.43074322473681548, 26.92945445680959438 22.03559082272676761, 22.98698241660859054 21.04997281267651488, 20.31173353218648003 19.78274965689762155)),((55.16037031610606789 15.48827118453581164, 57.8356192005281855 18.16352006895792215, 64.10133369299049377 20.27555866192274436, 70.71905461761360812 18.86753293327952719, 74.09831636635732366 16.4034879081538989, 75.71754595429702306 11.33459528503832558, 74.30952022565381299 6.47690652121922739, 69.38143017540255642 2.6752370538825474, 61.63728866786486549 1.90082290312877689, 56.4979947583171338 2.60483576745038192, 53.11873300957341826 6.82891295338003346, 52.83712786384477056 12.32021329508857832, 55.16037031610606789 15.48827118453581164)))" + ) + self.assertEqual( + p.simplifyByDistance(1).asWkt(3), + "MultiPolygon (((4.338 1.481, 5.838 16.48, 10.61 22.888, 17.632 27.729, 27.041 30.115, 34.812 28.342, 42.516 23.979, 44.834 17.843, 44.152 9.526, 42.448 1.754, 37.267 -4.654, 18.519 -7.313, 7.134 -5.131, 4.338 1.481),(20.312 19.783, 17.284 9.997, 21.227 4.576, 26.014 3.238, 32.21 5.632, 34.603 8.378, 35.237 12.25, 32.139 19.431, 26.929 22.036, 20.312 19.783)),((57.836 18.164, 64.101 20.276, 70.719 18.868, 74.098 16.403, 75.718 11.335, 74.31 6.477, 69.381 2.675, 56.498 2.605, 53.119 6.829, 52.837 12.32, 57.836 18.164)))", + ) + self.assertEqual( + p.simplifyByDistance(2).asWkt(3), + "MultiPolygon (((4.338 1.481, 5.838 16.48, 17.632 27.729, 27.041 30.115, 42.516 23.979, 44.152 9.526, 37.267 -4.654, 18.519 -7.313, 7.134 -5.131, 4.338 1.481),(20.312 19.783, 17.284 9.997, 21.227 4.576, 32.21 5.632, 35.237 12.25, 32.139 19.431, 26.929 22.036, 20.312 19.783)),((55.16 15.488, 64.101 20.276, 70.719 18.868, 75.718 11.335, 74.31 6.477, 69.381 2.675, 56.498 2.605, 53.119 6.829, 55.16 15.488)))", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsnetworkaccessmanager.py b/tests/src/python/test_qgsnetworkaccessmanager.py index 242d1b34215d..551db0e20110 100644 --- a/tests/src/python/test_qgsnetworkaccessmanager.py +++ b/tests/src/python/test_qgsnetworkaccessmanager.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2022 by Nyall Dawson' -__date__ = '27/04/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "(C) 2022 by Nyall Dawson" +__date__ = "27/04/2022" +__copyright__ = "Copyright 2022, The QGIS Project" import http.server import os @@ -36,10 +37,10 @@ class TestQgsNetworkAccessManager(QgisTestCase): def setUpClass(cls): super().setUpClass() # Bring up a simple HTTP server - os.chdir(unitTestDataPath() + '') + os.chdir(unitTestDataPath() + "") handler = http.server.SimpleHTTPRequestHandler - cls.httpd = socketserver.TCPServer(('localhost', 0), handler) + cls.httpd = socketserver.TCPServer(("localhost", 0), handler) cls.port = cls.httpd.server_address[1] cls.httpd_thread = threading.Thread(target=cls.httpd.serve_forever) @@ -48,7 +49,11 @@ def setUpClass(cls): def test_request_preprocessor(self): """Test request preprocessor.""" - url = 'http://localhost:' + str(TestQgsNetworkAccessManager.port) + '/qgis_local_server/index.html' + url = ( + "http://localhost:" + + str(TestQgsNetworkAccessManager.port) + + "/qgis_local_server/index.html" + ) TestQgsNetworkAccessManager.preprocessed = False @@ -87,12 +92,16 @@ def _preprocessor(request): def _on_reply_ready_read(self, reply): _bytes = reply.peek(reply.bytesAvailable()) - self.assertEqual(_bytes.data().decode()[:14], ' 180 or <-180 wrap around f.setNumberDecimalPlaces(2) - self.assertEqual(f.formatDouble(370, context), - "10°0′0.00″E") - self.assertEqual(f.formatDouble(-370, context), - "10°0′0.00″W") - self.assertEqual(f.formatDouble(181, context), - "179°0′0.00″W") - self.assertEqual(f.formatDouble(-181, context), - "179°0′0.00″E") - self.assertEqual(f.formatDouble(359, context), - "1°0′0.00″W") - self.assertEqual(f.formatDouble(-359, context), - "1°0′0.00″E") + self.assertEqual(f.formatDouble(370, context), "10°0′0.00″E") + self.assertEqual(f.formatDouble(-370, context), "10°0′0.00″W") + self.assertEqual(f.formatDouble(181, context), "179°0′0.00″W") + self.assertEqual(f.formatDouble(-181, context), "179°0′0.00″E") + self.assertEqual(f.formatDouble(359, context), "1°0′0.00″W") + self.assertEqual(f.formatDouble(-359, context), "1°0′0.00″E") # should be no directional suffixes for 0 degree coordinates - self.assertEqual(f.formatDouble(0, context), - "0°0′0.00″") + self.assertEqual(f.formatDouble(0, context), "0°0′0.00″") # should also be no directional suffix for 0 degree coordinates within specified precision - self.assertEqual(f.formatDouble(-0.000001, context), - "0°0′0.00″") + self.assertEqual(f.formatDouble(-0.000001, context), "0°0′0.00″") f.setNumberDecimalPlaces(5) - self.assertEqual( - f.formatDouble(-0.000001, context), - "0°0′0.00360″W") + self.assertEqual(f.formatDouble(-0.000001, context), "0°0′0.00360″W") f.setNumberDecimalPlaces(2) - self.assertEqual( - f.formatDouble(0.000001, context), - "0°0′0.00″") + self.assertEqual(f.formatDouble(0.000001, context), "0°0′0.00″") f.setNumberDecimalPlaces(5) - self.assertEqual( - f.formatDouble(0.000001, context), - "0°0′0.00360″E") + self.assertEqual(f.formatDouble(0.000001, context), "0°0′0.00360″E") # should be no directional suffixes for 180 degree longitudes f.setNumberDecimalPlaces(2) - self.assertEqual(f.formatDouble(180, context), - "180°0′0.00″") - self.assertEqual( - f.formatDouble(179.999999, context), - "180°0′0.00″") + self.assertEqual(f.formatDouble(180, context), "180°0′0.00″") + self.assertEqual(f.formatDouble(179.999999, context), "180°0′0.00″") f.setNumberDecimalPlaces(5) - self.assertEqual( - f.formatDouble(179.999999, context), - "179°59′59.99640″E") + self.assertEqual(f.formatDouble(179.999999, context), "179°59′59.99640″E") f.setNumberDecimalPlaces(2) - self.assertEqual( - f.formatDouble(180.000001, context), - "180°0′0.00″") + self.assertEqual(f.formatDouble(180.000001, context), "180°0′0.00″") f.setNumberDecimalPlaces(5) - self.assertEqual( - f.formatDouble(180.000001, context), - "179°59′59.99640″W") + self.assertEqual(f.formatDouble(180.000001, context), "179°59′59.99640″W") # test rounding does not create seconds >= 60 f.setNumberDecimalPlaces(2) - self.assertEqual( - f.formatDouble(99.999999, context), - "100°0′0.00″E") - self.assertEqual( - f.formatDouble(89.999999, context), - "90°0′0.00″E") + self.assertEqual(f.formatDouble(99.999999, context), "100°0′0.00″E") + self.assertEqual(f.formatDouble(89.999999, context), "90°0′0.00″E") # test without direction suffix f.setShowDirectionalSuffix(False) @@ -902,12 +1007,10 @@ def testGeographicCoordinateFormatLongitudeDms(self): # test near zero longitude self.assertEqual(f.formatDouble(0.000001, context), "0°0′0.00″") # should be no "-" prefix for near-zero longitude when rounding to 2 decimal places - self.assertEqual( - f.formatDouble(-0.000001, context), "0°0′0.00″") + self.assertEqual(f.formatDouble(-0.000001, context), "0°0′0.00″") f.setNumberDecimalPlaces(5) self.assertEqual(f.formatDouble(0.000001, context), "0°0′0.00360″") - self.assertEqual( - f.formatDouble(-0.000001, context), "-0°0′0.00360″") + self.assertEqual(f.formatDouble(-0.000001, context), "-0°0′0.00360″") # test with padding f.setShowLeadingZeros(True) @@ -916,12 +1019,10 @@ def testGeographicCoordinateFormatLongitudeDms(self): self.assertEqual(f.formatDouble(80, context), "80°00′00.00″E") self.assertEqual(f.formatDouble(85.44, context), "85°26′24.00″E") self.assertEqual(f.formatDouble(0, context), "0°00′00.00″") - self.assertEqual( - f.formatDouble(-0.000001, context), "0°00′00.00″") + self.assertEqual(f.formatDouble(-0.000001, context), "0°00′00.00″") self.assertEqual(f.formatDouble(0.000001, context), "0°00′00.00″") f.setNumberDecimalPlaces(5) - self.assertEqual( - f.formatDouble(-0.000001, context), "0°00′00.00360″W") + self.assertEqual(f.formatDouble(-0.000001, context), "0°00′00.00360″W") self.assertEqual(f.formatDouble(0.000001, context), "0°00′00.00360″E") # with degree padding @@ -948,7 +1049,7 @@ def testGeographicCoordinateFormatLongitudeDms(self): self.assertEqual(f.formatDouble(-5.44, context), "5°26′24″W") self.assertEqual(f.formatDouble(-5.44101, context), "5°26′27.64″W") - context.setDecimalSeparator('☕') + context.setDecimalSeparator("☕") self.assertEqual(f.formatDouble(5.44, context), "5°26′24″E") self.assertEqual(f.formatDouble(-5.44, context), "5°26′24″W") self.assertEqual(f.formatDouble(-5.44101, context), "5°26′27☕64″W") @@ -960,7 +1061,9 @@ def testGeographicCoordinateFormatLatitudeDms(self): context = QgsNumericFormatContext() context.setInterpretation(QgsNumericFormatContext.Interpretation.Latitude) - f.setAngleFormat(QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds) + f.setAngleFormat( + QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds + ) f.setNumberDecimalPlaces(2) f.setShowDirectionalSuffix(True) f.setShowTrailingZeros(True) @@ -1045,7 +1148,7 @@ def testGeographicCoordinateFormatLatitudeDms(self): self.assertEqual(f.formatDouble(-5.44, context), "5°26′24″S") self.assertEqual(f.formatDouble(-5.44101, context), "5°26′27.64″S") - context.setDecimalSeparator('☕') + context.setDecimalSeparator("☕") self.assertEqual(f.formatDouble(5.44, context), "5°26′24″N") self.assertEqual(f.formatDouble(-5.44, context), "5°26′24″S") self.assertEqual(f.formatDouble(-5.44101, context), "5°26′27☕64″S") @@ -1057,7 +1160,9 @@ def testGeographicCoordinateFormatLongitudeMinutes(self): context = QgsNumericFormatContext() context.setInterpretation(QgsNumericFormatContext.Interpretation.Longitude) - f.setAngleFormat(QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutes) + f.setAngleFormat( + QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutes + ) f.setNumberDecimalPlaces(2) f.setShowDirectionalSuffix(True) f.setShowTrailingZeros(True) @@ -1153,7 +1258,7 @@ def testGeographicCoordinateFormatLongitudeMinutes(self): self.assertEqual(f.formatDouble(-5.44, context), "5°26.4′W") self.assertEqual(f.formatDouble(-5.44101, context), "5°26.46′W") - context.setDecimalSeparator('☕') + context.setDecimalSeparator("☕") self.assertEqual(f.formatDouble(5.44, context), "5°26☕4′E") self.assertEqual(f.formatDouble(-5.44, context), "5°26☕4′W") self.assertEqual(f.formatDouble(-5.44101, context), "5°26☕46′W") @@ -1165,7 +1270,9 @@ def testGeographicCoordinateFormatLatitudeMinutes(self): context = QgsNumericFormatContext() context.setInterpretation(QgsNumericFormatContext.Interpretation.Latitude) - f.setAngleFormat(QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutes) + f.setAngleFormat( + QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutes + ) f.setNumberDecimalPlaces(2) f.setShowDirectionalSuffix(True) f.setShowTrailingZeros(True) @@ -1246,7 +1353,7 @@ def testGeographicCoordinateFormatLatitudeMinutes(self): self.assertEqual(f.formatDouble(-5.44, context), "5°26.4′S") self.assertEqual(f.formatDouble(-5.44101, context), "5°26.46′S") - context.setDecimalSeparator('☕') + context.setDecimalSeparator("☕") self.assertEqual(f.formatDouble(5.44, context), "5°26☕4′N") self.assertEqual(f.formatDouble(-5.44, context), "5°26☕4′S") self.assertEqual(f.formatDouble(-5.44101, context), "5°26☕46′S") @@ -1258,7 +1365,9 @@ def testGeographicCoordinateFormatLongitudeDegrees(self): context = QgsNumericFormatContext() context.setInterpretation(QgsNumericFormatContext.Interpretation.Longitude) - f.setAngleFormat(QgsGeographicCoordinateNumericFormat.AngleFormat.DecimalDegrees) + f.setAngleFormat( + QgsGeographicCoordinateNumericFormat.AngleFormat.DecimalDegrees + ) f.setNumberDecimalPlaces(2) f.setShowDirectionalSuffix(True) f.setShowTrailingZeros(True) @@ -1340,7 +1449,7 @@ def testGeographicCoordinateFormatLongitudeDegrees(self): self.assertEqual(f.formatDouble(-5.44, context), "5.44°W") self.assertEqual(f.formatDouble(-5.44101, context), "5.44°W") - context.setDecimalSeparator('☕') + context.setDecimalSeparator("☕") self.assertEqual(f.formatDouble(5.44, context), "5☕44°E") self.assertEqual(f.formatDouble(-5.44, context), "5☕44°W") self.assertEqual(f.formatDouble(-5.44101, context), "5☕44°W") @@ -1352,7 +1461,9 @@ def testGeographicCoordinateFormatLatitudeDegrees(self): context = QgsNumericFormatContext() context.setInterpretation(QgsNumericFormatContext.Interpretation.Latitude) - f.setAngleFormat(QgsGeographicCoordinateNumericFormat.AngleFormat.DecimalDegrees) + f.setAngleFormat( + QgsGeographicCoordinateNumericFormat.AngleFormat.DecimalDegrees + ) f.setNumberDecimalPlaces(2) f.setShowDirectionalSuffix(True) f.setShowTrailingZeros(True) @@ -1419,30 +1530,30 @@ def testGeographicCoordinateFormatLatitudeDegrees(self): self.assertEqual(f.formatDouble(-5.44, context), "5.44°S") self.assertEqual(f.formatDouble(-5.44101, context), "5.44°S") - context.setDecimalSeparator('☕') + context.setDecimalSeparator("☕") self.assertEqual(f.formatDouble(5.44, context), "5☕44°N") self.assertEqual(f.formatDouble(-5.44, context), "5☕44°S") self.assertEqual(f.formatDouble(-5.44101, context), "5☕44°S") def testExpressionBasedFormat(self): - """ test expression based formatter """ + """test expression based formatter""" f = QgsExpressionBasedNumericFormat() - self.assertEqual(f.expression(), '@value') + self.assertEqual(f.expression(), "@value") f.setExpression("@value || @suffix") self.assertEqual(f.expression(), "@value || @suffix") context = QgsNumericFormatContext() scope = QgsExpressionContextScope() exp_context = QgsExpressionContext() - scope.setVariable('suffix', 'm') + scope.setVariable("suffix", "m") exp_context.appendScope(scope) context.setExpressionContext(exp_context) - self.assertEqual(f.formatDouble(0, context), '0m') - self.assertEqual(f.formatDouble(5, context), '5m') - self.assertEqual(f.formatDouble(5.5, context), '5.5m') - self.assertEqual(f.formatDouble(-5, context), '-5m') - self.assertEqual(f.formatDouble(-5.5, context), '-5.5m') + self.assertEqual(f.formatDouble(0, context), "0m") + self.assertEqual(f.formatDouble(5, context), "5m") + self.assertEqual(f.formatDouble(5.5, context), "5.5m") + self.assertEqual(f.formatDouble(-5, context), "-5m") + self.assertEqual(f.formatDouble(-5.5, context), "-5.5m") f2 = f.clone() self.assertIsInstance(f2, QgsExpressionBasedNumericFormat) @@ -1464,27 +1575,34 @@ def testRegistry(self): for f in registry.formats(): self.assertEqual(registry.format(f).id(), f) - self.assertIn('default', registry.formats()) + self.assertIn("default", registry.formats()) registry.addFormat(TestFormat()) - self.assertIn('test', registry.formats()) - self.assertTrue(isinstance(registry.format('test'), TestFormat)) - self.assertTrue(isinstance(registry.create('test', {}, QgsReadWriteContext()), TestFormat)) - - registry.removeFormat('test') - - self.assertNotIn('test', registry.formats()) - self.assertTrue(isinstance(registry.format('test'), QgsFallbackNumericFormat)) - self.assertTrue(isinstance(registry.create('test', {}, QgsReadWriteContext()), QgsFallbackNumericFormat)) + self.assertIn("test", registry.formats()) + self.assertTrue(isinstance(registry.format("test"), TestFormat)) + self.assertTrue( + isinstance(registry.create("test", {}, QgsReadWriteContext()), TestFormat) + ) + + registry.removeFormat("test") + + self.assertNotIn("test", registry.formats()) + self.assertTrue(isinstance(registry.format("test"), QgsFallbackNumericFormat)) + self.assertTrue( + isinstance( + registry.create("test", {}, QgsReadWriteContext()), + QgsFallbackNumericFormat, + ) + ) self.assertTrue(isinstance(registry.fallbackFormat(), QgsFallbackNumericFormat)) - self.assertEqual(registry.visibleName('default'), 'General') - self.assertEqual(registry.visibleName('basic'), 'Number') + self.assertEqual(registry.visibleName("default"), "General") + self.assertEqual(registry.visibleName("basic"), "Number") - self.assertEqual(registry.sortKey('default'), 0) - self.assertEqual(registry.sortKey('basic'), 1) - self.assertEqual(registry.sortKey('currency'), 100) + self.assertEqual(registry.sortKey("default"), 0) + self.assertEqual(registry.sortKey("basic"), 1) + self.assertEqual(registry.sortKey("currency"), 100) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsnumericformatgui.py b/tests/src/python/test_qgsnumericformatgui.py index 99ce8369a1ff..ff845c588e58 100644 --- a/tests/src/python/test_qgsnumericformatgui.py +++ b/tests/src/python/test_qgsnumericformatgui.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '6/01/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "6/01/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy from qgis.core import ( @@ -41,13 +42,13 @@ def __init__(self): self.xx = 1 def id(self): - return 'test' + return "test" def formatDouble(self, value, context): - return 'xxx' + str(value) + return "xxx" + str(value) def visibleName(self): - return 'Test' + return "Test" def clone(self): res = TestFormat() @@ -56,11 +57,11 @@ def clone(self): def create(self, configuration, context): res = TestFormat() - res.xx = configuration['xx'] + res.xx = configuration["xx"] return res def configuration(self, context): - return {'xx': self.xx} + return {"xx": self.xx} class TestFormatWidget(QgsNumericFormatWidget): @@ -94,7 +95,7 @@ def testRegistry(self): self.assertFalse(reg.formatConfigurationWidget(None)) self.assertFalse(reg.formatConfigurationWidget(TestFormat())) - reg.addFormatConfigurationWidgetFactory('test', TestWidgetFactory()) + reg.addFormatConfigurationWidgetFactory("test", TestWidgetFactory()) original = TestFormat() original.xx = 55 w = reg.formatConfigurationWidget(original) @@ -103,9 +104,9 @@ def testRegistry(self): self.assertIsInstance(w.format(), TestFormat) self.assertEqual(w.format().xx, 55) - reg.removeFormatConfigurationWidgetFactory('test') + reg.removeFormatConfigurationWidgetFactory("test") self.assertFalse(reg.formatConfigurationWidget(TestFormat())) - reg.removeFormatConfigurationWidgetFactory('test') + reg.removeFormatConfigurationWidgetFactory("test") def testSelectorWidget(self): w = QgsNumericFormatSelectorWidget() @@ -123,7 +124,9 @@ def testSelectorWidget(self): self.assertEqual(len(spy), 3) QgsApplication.numericFormatRegistry().addFormat(TestFormat()) - QgsGui.numericFormatGuiRegistry().addFormatConfigurationWidgetFactory('test', TestWidgetFactory()) + QgsGui.numericFormatGuiRegistry().addFormatConfigurationWidgetFactory( + "test", TestWidgetFactory() + ) original = TestFormat() original.xx = 55 @@ -146,7 +149,9 @@ def testBasicFormat(self): self.assertIsInstance(new, QgsBasicNumericFormat) self.assertEqual(new.showPlusSign(), original.showPlusSign()) - self.assertEqual(new.showThousandsSeparator(), original.showThousandsSeparator()) + self.assertEqual( + new.showThousandsSeparator(), original.showThousandsSeparator() + ) self.assertEqual(new.numberDecimalPlaces(), original.numberDecimalPlaces()) self.assertEqual(new.showTrailingZeros(), original.showTrailingZeros()) @@ -158,15 +163,17 @@ def testCurrencyFormat(self): original.setShowThousandsSeparator(False) original.setNumberDecimalPlaces(4) original.setShowTrailingZeros(True) - original.setPrefix('$$') - original.setSuffix('AUD') + original.setPrefix("$$") + original.setSuffix("AUD") w.setFormat(original) new = w.format() self.assertIsInstance(new, QgsCurrencyNumericFormat) self.assertEqual(new.showPlusSign(), original.showPlusSign()) - self.assertEqual(new.showThousandsSeparator(), original.showThousandsSeparator()) + self.assertEqual( + new.showThousandsSeparator(), original.showThousandsSeparator() + ) self.assertEqual(new.numberDecimalPlaces(), original.numberDecimalPlaces()) self.assertEqual(new.showTrailingZeros(), original.showTrailingZeros()) self.assertEqual(new.prefix(), original.prefix()) @@ -178,7 +185,9 @@ def testBearingFormat(self): original = QgsBearingNumericFormat() original.setNumberDecimalPlaces(4) original.setShowTrailingZeros(True) - original.setDirectionFormat(QgsBearingNumericFormat.FormatDirectionOption.UseRange0To360) + original.setDirectionFormat( + QgsBearingNumericFormat.FormatDirectionOption.UseRange0To360 + ) w.setFormat(original) new = w.format() @@ -194,7 +203,9 @@ def testGeographicCoordinateFormat(self): original = QgsGeographicCoordinateNumericFormat() original.setNumberDecimalPlaces(4) original.setShowTrailingZeros(True) - original.setAngleFormat(QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutes) + original.setAngleFormat( + QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutes + ) original.setShowDirectionalSuffix(True) original.setShowLeadingZeros(True) original.setShowDegreeLeadingZeros(True) @@ -208,7 +219,9 @@ def testGeographicCoordinateFormat(self): self.assertEqual(new.showDirectionalSuffix(), original.showDirectionalSuffix()) self.assertEqual(new.angleFormat(), original.angleFormat()) self.assertEqual(new.showLeadingZeros(), original.showLeadingZeros()) - self.assertEqual(new.showDegreeLeadingZeros(), original.showDegreeLeadingZeros()) + self.assertEqual( + new.showDegreeLeadingZeros(), original.showDegreeLeadingZeros() + ) def testPercentageFormat(self): w = QgsNumericFormatSelectorWidget() @@ -216,7 +229,9 @@ def testPercentageFormat(self): original = QgsPercentageNumericFormat() original.setNumberDecimalPlaces(4) original.setShowTrailingZeros(True) - original.setInputValues(QgsPercentageNumericFormat.InputValues.ValuesAreFractions) + original.setInputValues( + QgsPercentageNumericFormat.InputValues.ValuesAreFractions + ) w.setFormat(original) new = w.format() @@ -253,5 +268,5 @@ def testDefaultFormat(self): self.assertIsInstance(new, QgsFallbackNumericFormat) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsobjectcustomproperties.py b/tests/src/python/test_qgsobjectcustomproperties.py index 31b45990f5f1..7ed3b4933570 100644 --- a/tests/src/python/test_qgsobjectcustomproperties.py +++ b/tests/src/python/test_qgsobjectcustomproperties.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '02/06/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "02/06/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtXml import QDomDocument from qgis.core import QgsObjectCustomProperties @@ -20,61 +21,61 @@ class TestQgsObjectCustomProperties(QgisTestCase): def testSimple(self): - """ test storing/retrieving properties """ + """test storing/retrieving properties""" props = QgsObjectCustomProperties() self.assertFalse(props.keys()) - self.assertFalse(props.contains('a')) - self.assertFalse(props.value('a')) - self.assertEqual(props.value('a', defaultValue=6), 6) + self.assertFalse(props.contains("a")) + self.assertFalse(props.value("a")) + self.assertEqual(props.value("a", defaultValue=6), 6) # remove non-present key, no crash - props.remove('a') - - props.setValue('a', 7) - self.assertEqual(props.keys(), ['a']) - self.assertTrue(props.contains('a')) - self.assertFalse(props.contains('b')) - self.assertEqual(props.value('a', defaultValue=6), 7) - self.assertEqual(props.value('b', defaultValue='yy'), 'yy') - props.setValue('b', 'xx') - self.assertCountEqual(props.keys(), ['a', 'b']) - self.assertTrue(props.contains('a')) - self.assertTrue(props.contains('b')) - self.assertEqual(props.value('a', defaultValue=6), 7) - self.assertEqual(props.value('b', defaultValue='yy'), 'xx') - - props.remove('a') - self.assertCountEqual(props.keys(), ['b']) - self.assertFalse(props.contains('a')) - self.assertTrue(props.contains('b')) - self.assertEqual(props.value('a', defaultValue=6), 6) - self.assertEqual(props.value('b', defaultValue='yy'), 'xx') - - props.remove('b') + props.remove("a") + + props.setValue("a", 7) + self.assertEqual(props.keys(), ["a"]) + self.assertTrue(props.contains("a")) + self.assertFalse(props.contains("b")) + self.assertEqual(props.value("a", defaultValue=6), 7) + self.assertEqual(props.value("b", defaultValue="yy"), "yy") + props.setValue("b", "xx") + self.assertCountEqual(props.keys(), ["a", "b"]) + self.assertTrue(props.contains("a")) + self.assertTrue(props.contains("b")) + self.assertEqual(props.value("a", defaultValue=6), 7) + self.assertEqual(props.value("b", defaultValue="yy"), "xx") + + props.remove("a") + self.assertCountEqual(props.keys(), ["b"]) + self.assertFalse(props.contains("a")) + self.assertTrue(props.contains("b")) + self.assertEqual(props.value("a", defaultValue=6), 6) + self.assertEqual(props.value("b", defaultValue="yy"), "xx") + + props.remove("b") self.assertFalse(props.keys()) - self.assertFalse(props.contains('a')) - self.assertFalse(props.contains('b')) - self.assertEqual(props.value('a', defaultValue=6), 6) - self.assertEqual(props.value('b', defaultValue='yy'), 'yy') + self.assertFalse(props.contains("a")) + self.assertFalse(props.contains("b")) + self.assertEqual(props.value("a", defaultValue=6), 6) + self.assertEqual(props.value("b", defaultValue="yy"), "yy") def testSaveRestore(self): doc = QDomDocument() - elem = doc.createElement('test') + elem = doc.createElement("test") props = QgsObjectCustomProperties() - props.setValue('a', '7') - props.setValue('b', 'xx') + props.setValue("a", "7") + props.setValue("b", "xx") props.writeXml(elem, doc) props2 = QgsObjectCustomProperties() props2.readXml(elem) - self.assertCountEqual(props2.keys(), ['a', 'b']) - self.assertTrue(props2.contains('a')) - self.assertTrue(props2.contains('b')) - self.assertEqual(props2.value('a', defaultValue=6), '7') - self.assertEqual(props2.value('b', defaultValue='yy'), 'xx') + self.assertCountEqual(props2.keys(), ["a", "b"]) + self.assertTrue(props2.contains("a")) + self.assertTrue(props2.contains("b")) + self.assertEqual(props2.value("a", defaultValue=6), "7") + self.assertEqual(props2.value("b", defaultValue="yy"), "xx") def testCompatibilityRestore(self): # for pre 3.20 @@ -85,12 +86,12 @@ def testCompatibilityRestore(self): props = QgsObjectCustomProperties() props.readXml(doc.documentElement()) - self.assertCountEqual(props.keys(), ['a', 'b']) - self.assertTrue(props.contains('a')) - self.assertTrue(props.contains('b')) - self.assertEqual(props.value('a', defaultValue=6), '7') - self.assertEqual(props.value('b', defaultValue='yy'), 'xx') + self.assertCountEqual(props.keys(), ["a", "b"]) + self.assertTrue(props.contains("a")) + self.assertTrue(props.contains("b")) + self.assertEqual(props.value("a", defaultValue=6), "7") + self.assertEqual(props.value("b", defaultValue="yy"), "xx") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsogcutils.py b/tests/src/python/test_qgsogcutils.py index 28616d75781d..25f94e3e07b7 100644 --- a/tests/src/python/test_qgsogcutils.py +++ b/tests/src/python/test_qgsogcutils.py @@ -9,9 +9,10 @@ (at your option) any later version. """ -__author__ = 'René-Luc Dhont' -__date__ = '21/06/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "René-Luc Dhont" +__date__ = "21/06/2019" +__copyright__ = "Copyright 2019, The QGIS Project" from qgis.PyQt.QtCore import QVariant from qgis.PyQt.QtXml import QDomDocument @@ -28,12 +29,12 @@ def test_expressionFromOgcFilterWithInt(self): """ Test expressionFromOgcFilter with Int type field """ - vl = QgsVectorLayer('Point', 'vl', 'memory') - vl.dataProvider().addAttributes([QgsField('id', QVariant.Int)]) + vl = QgsVectorLayer("Point", "vl", "memory") + vl.dataProvider().addAttributes([QgsField("id", QVariant.Int)]) vl.updateFields() # Literals are Integer 1 and 3 - f = ''' + f = """ @@ -46,15 +47,15 @@ def test_expressionFromOgcFilterWithInt(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id > 1 AND id < 3') + self.assertEqual(e.expression(), "id > 1 AND id < 3") # Literals are Double 1.0 and 3.0 - f = ''' + f = """ @@ -67,15 +68,15 @@ def test_expressionFromOgcFilterWithInt(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id > 1 AND id < 3') + self.assertEqual(e.expression(), "id > 1 AND id < 3") # Literals are Double 1.5 and 3.5 - f = ''' + f = """ @@ -88,15 +89,15 @@ def test_expressionFromOgcFilterWithInt(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id > 2 AND id < 4') + self.assertEqual(e.expression(), "id > 2 AND id < 4") # Literals are Scientific notation 15e-01 and 35e-01 - f = ''' + f = """ @@ -109,23 +110,23 @@ def test_expressionFromOgcFilterWithInt(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id > 2 AND id < 4') + self.assertEqual(e.expression(), "id > 2 AND id < 4") def test_expressionFromOgcFilterWithLonglong(self): """ Test expressionFromOgcFilter with LongLong type field """ - vl = QgsVectorLayer('Point', 'vl', 'memory') - vl.dataProvider().addAttributes([QgsField('id', QVariant.LongLong)]) + vl = QgsVectorLayer("Point", "vl", "memory") + vl.dataProvider().addAttributes([QgsField("id", QVariant.LongLong)]) vl.updateFields() # Literals are Integer 1 and 3 - f = ''' + f = """ @@ -138,14 +139,14 @@ def test_expressionFromOgcFilterWithLonglong(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id > 1 AND id < 3') + self.assertEqual(e.expression(), "id > 1 AND id < 3") # Literals are Double 1.0 and 3.0 - f = ''' + f = """ @@ -158,15 +159,15 @@ def test_expressionFromOgcFilterWithLonglong(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id > 1 AND id < 3') + self.assertEqual(e.expression(), "id > 1 AND id < 3") # Literals are Double 1.5 and 3.5 - f = ''' + f = """ @@ -179,15 +180,15 @@ def test_expressionFromOgcFilterWithLonglong(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id > 2 AND id < 4') + self.assertEqual(e.expression(), "id > 2 AND id < 4") # Literals are Scientific notation 15e-01 and 35e-01 - f = ''' + f = """ @@ -200,52 +201,52 @@ def test_expressionFromOgcFilterWithLonglong(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id > 2 AND id < 4') + self.assertEqual(e.expression(), "id > 2 AND id < 4") # Literal is empty - f = ''' + f = """ id - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id = \'\'') + self.assertEqual(e.expression(), "id = ''") - f = ''' + f = """ id - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id = \'\'') + self.assertEqual(e.expression(), "id = ''") def test_expressionFromOgcFilterWithDouble(self): """ Test expressionFromOgcFilter with Double type field """ - vl = QgsVectorLayer('Point', 'vl', 'memory') - vl.dataProvider().addAttributes([QgsField('id', QVariant.Double)]) + vl = QgsVectorLayer("Point", "vl", "memory") + vl.dataProvider().addAttributes([QgsField("id", QVariant.Double)]) vl.updateFields() # Literals are Integer 1 and 3 - f = ''' + f = """ @@ -258,15 +259,15 @@ def test_expressionFromOgcFilterWithDouble(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id > 1 AND id < 3') + self.assertEqual(e.expression(), "id > 1 AND id < 3") # Literals are Double 1.0 and 3.0 - f = ''' + f = """ @@ -279,15 +280,15 @@ def test_expressionFromOgcFilterWithDouble(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id > 1 AND id < 3') + self.assertEqual(e.expression(), "id > 1 AND id < 3") # Literals are Double 1.5 and 3.5 - f = ''' + f = """ @@ -300,15 +301,15 @@ def test_expressionFromOgcFilterWithDouble(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id > 1.5 AND id < 3.5') + self.assertEqual(e.expression(), "id > 1.5 AND id < 3.5") # Literals are Scientific notation 15e-01 and 35e-01 - f = ''' + f = """ @@ -321,52 +322,52 @@ def test_expressionFromOgcFilterWithDouble(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id > 1.5 AND id < 3.5') + self.assertEqual(e.expression(), "id > 1.5 AND id < 3.5") # Literal is empty - f = ''' + f = """ id - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id = \'\'') + self.assertEqual(e.expression(), "id = ''") - f = ''' + f = """ id - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id = \'\'') + self.assertEqual(e.expression(), "id = ''") def test_expressionFromOgcFilterWithString(self): """ Test expressionFromOgcFilter with String type field """ - vl = QgsVectorLayer('Point', 'vl', 'memory') - vl.dataProvider().addAttributes([QgsField('id', QVariant.String)]) + vl = QgsVectorLayer("Point", "vl", "memory") + vl.dataProvider().addAttributes([QgsField("id", QVariant.String)]) vl.updateFields() # Literals are Integer 1 and 3 - f = ''' + f = """ @@ -379,15 +380,15 @@ def test_expressionFromOgcFilterWithString(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id > \'1\' AND id < \'3\'') + self.assertEqual(e.expression(), "id > '1' AND id < '3'") # Literals are Double 1.0 and 3.0 - f = ''' + f = """ @@ -400,15 +401,15 @@ def test_expressionFromOgcFilterWithString(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id > \'1.0\' AND id < \'3.0\'') + self.assertEqual(e.expression(), "id > '1.0' AND id < '3.0'") # Literals are Double 1.5 and 3.5 - f = ''' + f = """ @@ -421,15 +422,15 @@ def test_expressionFromOgcFilterWithString(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id > \'1.5\' AND id < \'3.5\'') + self.assertEqual(e.expression(), "id > '1.5' AND id < '3.5'") # Literals are Scientific notation 15e-01 and 35e-01 - f = ''' + f = """ @@ -442,52 +443,58 @@ def test_expressionFromOgcFilterWithString(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id > \'15e-01\' AND id < \'35e-01\'') + self.assertEqual(e.expression(), "id > '15e-01' AND id < '35e-01'") # Literal is empty - f = ''' + f = """ id - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id = \'\'') + self.assertEqual(e.expression(), "id = ''") - f = ''' + f = """ id - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'id = \'\'') + self.assertEqual(e.expression(), "id = ''") def test_expressionFromOgcFilterWithAndOrPropertyIsLike(self): """ Test expressionFromOgcFilter with And, Or and PropertyIsLike with wildCard """ - vl = QgsVectorLayer('Point', 'vl', 'memory') - vl.dataProvider().addAttributes([QgsField('id', QVariant.LongLong), QgsField('THEME', QVariant.String), QgsField('PROGRAMME', QVariant.String)]) + vl = QgsVectorLayer("Point", "vl", "memory") + vl.dataProvider().addAttributes( + [ + QgsField("id", QVariant.LongLong), + QgsField("THEME", QVariant.String), + QgsField("PROGRAMME", QVariant.String), + ] + ) vl.updateFields() - f = ''' + f = """ @@ -514,23 +521,26 @@ def test_expressionFromOgcFilterWithAndOrPropertyIsLike(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), 'THEME LIKE \'%Phytoplancton total%\' AND (PROGRAMME ILIKE \'REPHY;%\' OR PROGRAMME ILIKE \'%;REPHY\' OR PROGRAMME ILIKE \'%;REPHY;%\' OR PROGRAMME ILIKE \'^REPHY$\')') + self.assertEqual( + e.expression(), + "THEME LIKE '%Phytoplancton total%' AND (PROGRAMME ILIKE 'REPHY;%' OR PROGRAMME ILIKE '%;REPHY' OR PROGRAMME ILIKE '%;REPHY;%' OR PROGRAMME ILIKE '^REPHY$')", + ) def test_expressionFromOgcFilterWithDateTime(self): """ Test expressionFromOgcFilter with Date/Time type field """ # test with datetime type - vl = QgsVectorLayer('Point', 'vl', 'memory') - vl.dataProvider().addAttributes([QgsField('datetime', QVariant.DateTime)]) + vl = QgsVectorLayer("Point", "vl", "memory") + vl.dataProvider().addAttributes([QgsField("datetime", QVariant.DateTime)]) vl.updateFields() - f = ''' + f = """ @@ -543,19 +553,22 @@ def test_expressionFromOgcFilterWithDateTime(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) - self.assertEqual(e.expression(), "datetime > '1998-07-12T00:00:00' AND datetime < '2018-07-15T00:00:00'") + self.assertEqual( + e.expression(), + "datetime > '1998-07-12T00:00:00' AND datetime < '2018-07-15T00:00:00'", + ) # test with date type - vl = QgsVectorLayer('Point', 'vl', 'memory') - vl.dataProvider().addAttributes([QgsField('date', QVariant.Date)]) + vl = QgsVectorLayer("Point", "vl", "memory") + vl.dataProvider().addAttributes([QgsField("date", QVariant.Date)]) vl.updateFields() - f = ''' + f = """ @@ -568,19 +581,19 @@ def test_expressionFromOgcFilterWithDateTime(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) self.assertEqual(e.expression(), "date > '1998-07-12' AND date < '2018-07-15'") # test with time type - vl = QgsVectorLayer('Point', 'vl', 'memory') - vl.dataProvider().addAttributes([QgsField('time', QVariant.Time)]) + vl = QgsVectorLayer("Point", "vl", "memory") + vl.dataProvider().addAttributes([QgsField("time", QVariant.Time)]) vl.updateFields() - f = ''' + f = """ @@ -593,13 +606,13 @@ def test_expressionFromOgcFilterWithDateTime(self): - ''' - d = QDomDocument('filter') + """ + d = QDomDocument("filter") d.setContent(f, True) e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl) self.assertEqual(e.expression(), "time > '11:01:02' AND time < '12:03:04'") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsopacitywidget.py b/tests/src/python/test_qgsopacitywidget.py index 222f9d2c088a..64a7d25295c4 100644 --- a/tests/src/python/test_qgsopacitywidget.py +++ b/tests/src/python/test_qgsopacitywidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '30/05/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "30/05/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy @@ -21,7 +22,7 @@ class TestQgsOpacityWidget(QgisTestCase): def testGettersSetters(self): - """ test widget getters/setters """ + """test widget getters/setters""" w = QgsOpacityWidget() w.setOpacity(0.2) @@ -34,7 +35,7 @@ def testGettersSetters(self): self.assertEqual(w.opacity(), 1.0) def test_ChangedSignals(self): - """ test that signals are correctly emitted when setting opacity""" + """test that signals are correctly emitted when setting opacity""" w = QgsOpacityWidget() @@ -50,5 +51,5 @@ def test_ChangedSignals(self): self.assertEqual(spy[1][0], 1.0) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsoptional.py b/tests/src/python/test_qgsoptional.py index ea5ae2aefbdc..3c28221a7176 100644 --- a/tests/src/python/test_qgsoptional.py +++ b/tests/src/python/test_qgsoptional.py @@ -1,4 +1,4 @@ -''' +""" test_qgsoptional.py -------------------------------------- Date : September 2016 @@ -12,8 +12,7 @@ * (at your option) any later version. * * * ***************************************************************************/ -''' - +""" from qgis.core import QgsExpression, QgsOptionalExpression from qgis.testing import unittest @@ -34,27 +33,27 @@ def testQgsOptionalExpression(self): self.assertFalse(opt.enabled()) self.assertFalse(opt) - opt = QgsOptionalExpression(QgsExpression('true')) + opt = QgsOptionalExpression(QgsExpression("true")) self.assertTrue(opt.enabled()) - self.assertEqual(opt.data().expression(), 'true') + self.assertEqual(opt.data().expression(), "true") self.assertTrue(opt) opt.setEnabled(False) self.assertFalse(opt.enabled()) self.assertFalse(opt) # boolean operator not yet working in python # self.assertFalse(opt) - self.assertEqual(opt.data().expression(), 'true') + self.assertEqual(opt.data().expression(), "true") opt.setEnabled(True) self.assertTrue(opt.enabled()) # self.assertTrue(opt) - self.assertEqual(opt.data().expression(), 'true') - opt.setData(QgsExpression('xyz')) + self.assertEqual(opt.data().expression(), "true") + opt.setData(QgsExpression("xyz")) self.assertTrue(opt.enabled()) - self.assertEqual(opt.data().expression(), 'xyz') + self.assertEqual(opt.data().expression(), "xyz") - opt = QgsOptionalExpression(QgsExpression('true'), False) + opt = QgsOptionalExpression(QgsExpression("true"), False) self.assertFalse(opt.enabled()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsorientedbox3d.py b/tests/src/python/test_qgsorientedbox3d.py index ef6c1228a754..217831e97798 100644 --- a/tests/src/python/test_qgsorientedbox3d.py +++ b/tests/src/python/test_qgsorientedbox3d.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2023 by Nyall Dawson' -__date__ = '10/07/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "(C) 2023 by Nyall Dawson" +__date__ = "10/07/2023" +__copyright__ = "Copyright 2023, The QGIS Project" import math from qgis.core import ( @@ -19,7 +20,7 @@ QgsMatrix4x4, QgsOrientedBox3D, QgsVector3D, - QgsBox3D + QgsBox3D, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -42,14 +43,21 @@ def test_oriented_bounding_box(self): self.assertEqual(box.centerY(), 2) self.assertEqual(box.centerZ(), 3) self.assertEqual(box.center(), QgsVector3D(1, 2, 3)) - self.assertEqual(box.halfAxes(), [10.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 30.0]) + self.assertEqual( + box.halfAxes(), [10.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 30.0] + ) - box = QgsOrientedBox3D(QgsVector3D(1, 2, 3), [QgsVector3D(10, 0, 0), QgsVector3D(0, 20, 0), QgsVector3D(0, 0, 30)]) + box = QgsOrientedBox3D( + QgsVector3D(1, 2, 3), + [QgsVector3D(10, 0, 0), QgsVector3D(0, 20, 0), QgsVector3D(0, 0, 30)], + ) self.assertEqual(box.centerX(), 1) self.assertEqual(box.centerY(), 2) self.assertEqual(box.centerZ(), 3) self.assertEqual(box.center(), QgsVector3D(1, 2, 3)) - self.assertEqual(box.halfAxes(), [10.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 30.0]) + self.assertEqual( + box.halfAxes(), [10.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 30.0] + ) box = QgsOrientedBox3D([1, 2, 3], [1, 0, 0, 0, 1, 0, 0, 0, 1]) self.assertEqual(box.centerX(), 1) @@ -58,80 +66,104 @@ def test_oriented_bounding_box(self): self.assertEqual(box.halfAxes(), [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]) # 45 degree y axis rotation - box = QgsOrientedBox3D([1, 2, 3], - [math.cos(math.pi / 4), 0, math.sin(math.pi / 4), - 0, 1, 0, - -math.sin(math.pi / 4), 0, math.cos(math.pi / 4)]) + box = QgsOrientedBox3D( + [1, 2, 3], + [ + math.cos(math.pi / 4), + 0, + math.sin(math.pi / 4), + 0, + 1, + 0, + -math.sin(math.pi / 4), + 0, + math.cos(math.pi / 4), + ], + ) self.assertEqual(box.centerX(), 1) self.assertEqual(box.centerY(), 2) self.assertEqual(box.centerZ(), 3) - self.assertEqual(box.halfAxes(), [0.7071067811865476, 0.0, 0.7071067811865475, 0.0, 1.0, 0.0, -0.7071067811865475, 0.0, 0.7071067811865476]) + self.assertEqual( + box.halfAxes(), + [ + 0.7071067811865476, + 0.0, + 0.7071067811865475, + 0.0, + 1.0, + 0.0, + -0.7071067811865475, + 0.0, + 0.7071067811865476, + ], + ) def test_repr(self): box = QgsOrientedBox3D([1, 2, 3], [10, 11, 12, 21, 20, 22, 31, 32, 30]) - self.assertEqual(str(box), '') + self.assertEqual( + str(box), + "", + ) def test_equality(self): self.assertEqual( QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]), - QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]) + QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]), ) self.assertNotEqual( QgsOrientedBox3D([11, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]), - QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]) + QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]), ) self.assertNotEqual( QgsOrientedBox3D([1, 12, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]), - QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]) + QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]), ) self.assertNotEqual( QgsOrientedBox3D([1, 2, 13], [10, 0, 0, 0, 20, 0, 0, 0, 30]), - QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]) + QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]), ) self.assertNotEqual( QgsOrientedBox3D([1, 2, 3], [110, 0, 0, 0, 20, 0, 0, 0, 30]), - QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]) + QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]), ) self.assertNotEqual( QgsOrientedBox3D([1, 2, 3], [10, 10, 0, 0, 20, 0, 0, 0, 30]), - QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]) + QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]), ) self.assertNotEqual( QgsOrientedBox3D([1, 2, 3], [10, 0, 10, 0, 20, 0, 0, 0, 30]), - QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]) + QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]), ) self.assertNotEqual( QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 10, 20, 0, 0, 0, 30]), - QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]) + QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]), ) self.assertNotEqual( QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 120, 0, 0, 0, 30]), - QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]) + QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]), ) self.assertNotEqual( QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 10, 0, 0, 30]), - QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]) + QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]), ) self.assertNotEqual( QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 10, 0, 30]), - QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]) + QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]), ) self.assertNotEqual( QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 10, 30]), - QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]) + QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]), ) self.assertNotEqual( QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 310]), - QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]) + QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]), ) def test_from_box3d(self): - box = QgsOrientedBox3D.fromBox3D( - QgsBox3D(5.0, 6.0, 7.0, 11.0, 13.0, 15.0) + box = QgsOrientedBox3D.fromBox3D(QgsBox3D(5.0, 6.0, 7.0, 11.0, 13.0, 15.0)) + self.assertEqual( + box, QgsOrientedBox3D([8, 9.5, 11], [3, 0, 0, 0, 3.5, 0, 0, 0, 4]) ) - self.assertEqual(box, - QgsOrientedBox3D([8, 9.5, 11], - [3, 0, 0, 0, 3.5, 0, 0, 0, 4])) def test_box_extent(self): box = QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]) @@ -153,10 +185,20 @@ def test_box_extent(self): self.assertEqual(bounds.zMaximum(), 4) # 45 degree y axis rotation - box = QgsOrientedBox3D([1, 2, 3], - [math.cos(math.pi / 4), 0, math.sin(math.pi / 4), - 0, 1, 0, - -math.sin(math.pi / 4), 0, math.cos(math.pi / 4)]) + box = QgsOrientedBox3D( + [1, 2, 3], + [ + math.cos(math.pi / 4), + 0, + math.sin(math.pi / 4), + 0, + 1, + 0, + -math.sin(math.pi / 4), + 0, + math.cos(math.pi / 4), + ], + ) bounds = box.extent() self.assertAlmostEqual(bounds.xMinimum(), 1 - math.sqrt(2), 5) self.assertAlmostEqual(bounds.xMaximum(), 1 + math.sqrt(2), 5) @@ -167,43 +209,63 @@ def test_box_extent(self): def test_corners(self): box = QgsOrientedBox3D([1, 2, 3], [1, 0, 0, 0, 1, 0, 0, 0, 1]) - self.assertEqual(box.corners(), - [QgsVector3D(2, 3, 4), - QgsVector3D(0, 3, 4), - QgsVector3D(2, 1, 4), - QgsVector3D(0, 1, 4), - QgsVector3D(2, 3, 2), - QgsVector3D(0, 3, 2), - QgsVector3D(2, 1, 2), - QgsVector3D(0, 1, 2)]) + self.assertEqual( + box.corners(), + [ + QgsVector3D(2, 3, 4), + QgsVector3D(0, 3, 4), + QgsVector3D(2, 1, 4), + QgsVector3D(0, 1, 4), + QgsVector3D(2, 3, 2), + QgsVector3D(0, 3, 2), + QgsVector3D(2, 1, 2), + QgsVector3D(0, 1, 2), + ], + ) box = QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30]) - self.assertEqual(box.corners(), - [QgsVector3D(11, 22, 33), - QgsVector3D(-9, 22, 33), - QgsVector3D(11, -18, 33), - QgsVector3D(-9, -18, 33), - QgsVector3D(11, 22, -27), - QgsVector3D(-9, 22, -27), - QgsVector3D(11, -18, -27), - QgsVector3D(-9, -18, -27)]) + self.assertEqual( + box.corners(), + [ + QgsVector3D(11, 22, 33), + QgsVector3D(-9, 22, 33), + QgsVector3D(11, -18, 33), + QgsVector3D(-9, -18, 33), + QgsVector3D(11, 22, -27), + QgsVector3D(-9, 22, -27), + QgsVector3D(11, -18, -27), + QgsVector3D(-9, -18, -27), + ], + ) # 45 degree y axis rotation - box = QgsOrientedBox3D([1, 2, 3], - [math.cos(math.pi / 4), 0, - math.sin(math.pi / 4), - 0, 1, 0, - -math.sin(math.pi / 4), 0, - math.cos(math.pi / 4)]) - self.assertEqual(box.corners(), - [QgsVector3D(1, 3, 4.41421356237309492), - QgsVector3D(-0.41421356237309492, 3, 3), - QgsVector3D(1, 1, 4.41421356237309492), - QgsVector3D(-0.41421356237309492, 1, 3), - QgsVector3D(2.41421356237309492, 3, 3), - QgsVector3D(0.99999999999999989, 3, 1.58578643762690508), - QgsVector3D(2.41421356237309492, 1, 3), - QgsVector3D(0.99999999999999989, 1, 1.58578643762690508)]) + box = QgsOrientedBox3D( + [1, 2, 3], + [ + math.cos(math.pi / 4), + 0, + math.sin(math.pi / 4), + 0, + 1, + 0, + -math.sin(math.pi / 4), + 0, + math.cos(math.pi / 4), + ], + ) + self.assertEqual( + box.corners(), + [ + QgsVector3D(1, 3, 4.41421356237309492), + QgsVector3D(-0.41421356237309492, 3, 3), + QgsVector3D(1, 1, 4.41421356237309492), + QgsVector3D(-0.41421356237309492, 1, 3), + QgsVector3D(2.41421356237309492, 3, 3), + QgsVector3D(0.99999999999999989, 3, 1.58578643762690508), + QgsVector3D(2.41421356237309492, 1, 3), + QgsVector3D(0.99999999999999989, 1, 1.58578643762690508), + ], + ) def test_size(self): box = QgsOrientedBox3D([1, 2, 3], [1, 0, 0, 0, 1, 0, 0, 0, 1]) @@ -216,10 +278,17 @@ def test_size(self): self.assertEqual(box.size(), QgsVector3D(20, 40, 60)) def test_reprojectedExtent(self): - box = QgsOrientedBox3D([-2694341., -4296866., 3854579.], [-8.867, -14.142, 12.771, 104.740, -65.681, 0., 50.287, 80.192, 123.717]) + box = QgsOrientedBox3D( + [-2694341.0, -4296866.0, 3854579.0], + [-8.867, -14.142, 12.771, 104.740, -65.681, 0.0, 50.287, 80.192, 123.717], + ) # from ECEF (XYZ) to lon,lat,alt (deg,deg,m) - ct = QgsCoordinateTransform(QgsCoordinateReferenceSystem("EPSG:4978"), QgsCoordinateReferenceSystem("EPSG:4979"), QgsCoordinateTransformContext()) + ct = QgsCoordinateTransform( + QgsCoordinateReferenceSystem("EPSG:4978"), + QgsCoordinateReferenceSystem("EPSG:4979"), + QgsCoordinateTransformContext(), + ) aabb = box.reprojectedExtent(ct) # a box roughly around 37.42 N / 122.09 E @@ -234,21 +303,19 @@ def test_transformed(self): box = QgsOrientedBox3D([1, 2, 3], [1, 0, 0, 0, 1, 0, 0, 0, 1]) # translate by (10, 20, 30) - m_move = QgsMatrix4x4(1, 0, 0, 10, - 0, 1, 0, 20, - 0, 0, 1, 30, - 0, 0, 0, 1) + m_move = QgsMatrix4x4(1, 0, 0, 10, 0, 1, 0, 20, 0, 0, 1, 30, 0, 0, 0, 1) # scale (4*X, 5*Y, 6*Z) - m_scale = QgsMatrix4x4(4, 0, 0, 0, - 0, 5, 0, 0, - 0, 0, 6, 0, - 0, 0, 0, 1) + m_scale = QgsMatrix4x4(4, 0, 0, 0, 0, 5, 0, 0, 0, 0, 6, 0, 0, 0, 0, 1) box_moved = box.transformed(m_move) - self.assertEqual(box_moved, QgsOrientedBox3D([11, 22, 33], [1, 0, 0, 0, 1, 0, 0, 0, 1])) + self.assertEqual( + box_moved, QgsOrientedBox3D([11, 22, 33], [1, 0, 0, 0, 1, 0, 0, 0, 1]) + ) box_scaled = box.transformed(m_scale) - self.assertEqual(box_scaled, QgsOrientedBox3D([4, 10, 18], [4, 0, 0, 0, 5, 0, 0, 0, 6])) + self.assertEqual( + box_scaled, QgsOrientedBox3D([4, 10, 18], [4, 0, 0, 0, 5, 0, 0, 0, 6]) + ) def test_intersects(self): a1 = QgsOrientedBox3D([0, 0, 0], [1, 0, 0, 0, 1, 0, 0, 0, 1]) @@ -270,52 +337,121 @@ def test_intersects(self): self.assertTrue(b3.intersects(a3)) # Intersecting boxes (x-axis rotation) - a1 = QgsOrientedBox3D(QgsVector3D(0, 0, 0), [QgsVector3D(1, 0, 0), QgsVector3D(0, 0, -1), QgsVector3D(0, 1, 0)]) - b1 = QgsOrientedBox3D(QgsVector3D(1, 1, 1), [QgsVector3D(1, 0, 0), QgsVector3D(0, 1, 0), QgsVector3D(0, 0, 1)]) + a1 = QgsOrientedBox3D( + QgsVector3D(0, 0, 0), + [QgsVector3D(1, 0, 0), QgsVector3D(0, 0, -1), QgsVector3D(0, 1, 0)], + ) + b1 = QgsOrientedBox3D( + QgsVector3D(1, 1, 1), + [QgsVector3D(1, 0, 0), QgsVector3D(0, 1, 0), QgsVector3D(0, 0, 1)], + ) self.assertTrue(a1.intersects(b1)) self.assertTrue(b1.intersects(a1)) # Intersecting boxes (45 degree x-axis rotation) - a1 = QgsOrientedBox3D(QgsVector3D(0, 0, 0), [QgsVector3D(1, 0, 0), QgsVector3D(0, 0.7071, -0.7071), QgsVector3D(0, 0.7071, 0.7071)]) - b1 = QgsOrientedBox3D(QgsVector3D(1, 1, 1), [QgsVector3D(1, 0, 0), QgsVector3D(0, 1, 0), QgsVector3D(0, 0, 1)]) + a1 = QgsOrientedBox3D( + QgsVector3D(0, 0, 0), + [ + QgsVector3D(1, 0, 0), + QgsVector3D(0, 0.7071, -0.7071), + QgsVector3D(0, 0.7071, 0.7071), + ], + ) + b1 = QgsOrientedBox3D( + QgsVector3D(1, 1, 1), + [QgsVector3D(1, 0, 0), QgsVector3D(0, 1, 0), QgsVector3D(0, 0, 1)], + ) self.assertTrue(a1.intersects(b1)) self.assertTrue(b1.intersects(a1)) # Non-intersecting boxes (45 degree x-axis rotation) - a1 = QgsOrientedBox3D(QgsVector3D(0, -1, -.6), - [QgsVector3D(1, 0, 0), QgsVector3D(0, 0.7071, -0.7071), - QgsVector3D(0, 0.7071, 0.7071)]) - b1 = QgsOrientedBox3D(QgsVector3D(1, 1, 1), - [QgsVector3D(1, 0, 0), QgsVector3D(0, 1, 0), - QgsVector3D(0, 0, 1)]) + a1 = QgsOrientedBox3D( + QgsVector3D(0, -1, -0.6), + [ + QgsVector3D(1, 0, 0), + QgsVector3D(0, 0.7071, -0.7071), + QgsVector3D(0, 0.7071, 0.7071), + ], + ) + b1 = QgsOrientedBox3D( + QgsVector3D(1, 1, 1), + [QgsVector3D(1, 0, 0), QgsVector3D(0, 1, 0), QgsVector3D(0, 0, 1)], + ) self.assertFalse(a1.intersects(b1)) self.assertFalse(b1.intersects(a1)) # Intersecting boxes (45 degree y-axis rotation) - a1 = QgsOrientedBox3D(QgsVector3D(0, 0, 0), [QgsVector3D(0.7071, 0, 0.7071), QgsVector3D(0, 1, 0), - QgsVector3D(-0.7071, 0, 0.7071)]) - b1 = QgsOrientedBox3D(QgsVector3D(1, 1, 1), [QgsVector3D(1, 0, 0), QgsVector3D(0, 1, 0), QgsVector3D(0, 0, 1)]) + a1 = QgsOrientedBox3D( + QgsVector3D(0, 0, 0), + [ + QgsVector3D(0.7071, 0, 0.7071), + QgsVector3D(0, 1, 0), + QgsVector3D(-0.7071, 0, 0.7071), + ], + ) + b1 = QgsOrientedBox3D( + QgsVector3D(1, 1, 1), + [QgsVector3D(1, 0, 0), QgsVector3D(0, 1, 0), QgsVector3D(0, 0, 1)], + ) self.assertTrue(a1.intersects(b1)) self.assertTrue(b1.intersects(a1)) # Non-intersecting boxes with non-zero centers (45 degrees rotation around z-axis) - a1 = QgsOrientedBox3D(QgsVector3D(1, 1, 1), [QgsVector3D(0.7071, 0.7071, 0), QgsVector3D(-0.7071, 0.7071, 0), QgsVector3D(0, 0, 1)]) - b1 = QgsOrientedBox3D(QgsVector3D(4, 4, 4), [QgsVector3D(1, 0, 0), QgsVector3D(0, 1, 0), QgsVector3D(0, 0, 1)]) + a1 = QgsOrientedBox3D( + QgsVector3D(1, 1, 1), + [ + QgsVector3D(0.7071, 0.7071, 0), + QgsVector3D(-0.7071, 0.7071, 0), + QgsVector3D(0, 0, 1), + ], + ) + b1 = QgsOrientedBox3D( + QgsVector3D(4, 4, 4), + [QgsVector3D(1, 0, 0), QgsVector3D(0, 1, 0), QgsVector3D(0, 0, 1)], + ) self.assertFalse(a1.intersects(b1)) self.assertFalse(b1.intersects(a1)) # Non-intersecting boxes with non-zero centers and rotations - a1 = QgsOrientedBox3D(QgsVector3D(1, 1, 1), [QgsVector3D(0.7071, 0, 0.7071), QgsVector3D(0, 3, 0), QgsVector3D(-0.7071 * 2, 0, 0.7071 * 2)]) - b1 = QgsOrientedBox3D(QgsVector3D(4, 4, 4), [QgsVector3D(0.7071 * 2, 0.7071 * 2, 0), QgsVector3D(-0.7071, 0.7071, 0), QgsVector3D(0, 0, 2.1)]) + a1 = QgsOrientedBox3D( + QgsVector3D(1, 1, 1), + [ + QgsVector3D(0.7071, 0, 0.7071), + QgsVector3D(0, 3, 0), + QgsVector3D(-0.7071 * 2, 0, 0.7071 * 2), + ], + ) + b1 = QgsOrientedBox3D( + QgsVector3D(4, 4, 4), + [ + QgsVector3D(0.7071 * 2, 0.7071 * 2, 0), + QgsVector3D(-0.7071, 0.7071, 0), + QgsVector3D(0, 0, 2.1), + ], + ) self.assertFalse(a1.intersects(b1)) self.assertFalse(b1.intersects(a1)) # Intersecting boxes with non-zero centers and rotations - a1 = QgsOrientedBox3D(QgsVector3D(1, 1, 1), [QgsVector3D(0.7071, 0, 0.7071), QgsVector3D(0, 3, 0), QgsVector3D(-0.7071 * 2, 0, 0.7071 * 2)]) - b1 = QgsOrientedBox3D(QgsVector3D(4, 4, 4), [QgsVector3D(0.7071 * 2, 0.7071 * 2, 0), QgsVector3D(-0.7071, 0.7071, 0), QgsVector3D(0, 0, 3)]) + a1 = QgsOrientedBox3D( + QgsVector3D(1, 1, 1), + [ + QgsVector3D(0.7071, 0, 0.7071), + QgsVector3D(0, 3, 0), + QgsVector3D(-0.7071 * 2, 0, 0.7071 * 2), + ], + ) + b1 = QgsOrientedBox3D( + QgsVector3D(4, 4, 4), + [ + QgsVector3D(0.7071 * 2, 0.7071 * 2, 0), + QgsVector3D(-0.7071, 0.7071, 0), + QgsVector3D(0, 0, 3), + ], + ) self.assertTrue(a1.intersects(b1)) self.assertTrue(b1.intersects(a1)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsoverlaywidgetlayout.py b/tests/src/python/test_qgsoverlaywidgetlayout.py index 287fb73c335d..1e33d8129096 100644 --- a/tests/src/python/test_qgsoverlaywidgetlayout.py +++ b/tests/src/python/test_qgsoverlaywidgetlayout.py @@ -5,17 +5,16 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '24/1/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "24/1/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import unittest from qgis.PyQt.QtCore import Qt, QPoint from qgis.PyQt.QtWidgets import QWidget -from qgis.gui import ( - QgsOverlayWidgetLayout -) +from qgis.gui import QgsOverlayWidgetLayout from qgis.testing import start_app, QgisTestCase app = start_app() @@ -28,9 +27,7 @@ def testLayout(self): parent.setFixedSize(600, 400) layout = QgsOverlayWidgetLayout() - layout.setContentsMargins( - 5, 6, 7, 8 - ) + layout.setContentsMargins(5, 6, 7, 8) parent.setLayout(layout) parent.show() self.assertEqual(parent.rect().right(), 599) @@ -41,11 +38,11 @@ def testLayout(self): layout.addWidget(child_left_1, Qt.Edge.LeftEdge) child_left_1.show() self.assertEqual( - child_left_1.mapToParent(child_left_1.rect().topLeft()), - QPoint(5, 6)) + child_left_1.mapToParent(child_left_1.rect().topLeft()), QPoint(5, 6) + ) self.assertEqual( - child_left_1.mapToParent(child_left_1.rect().bottomRight()), - QPoint(34, 390)) + child_left_1.mapToParent(child_left_1.rect().bottomRight()), QPoint(34, 390) + ) child_left_2 = QWidget() child_left_2.setFixedWidth(40) @@ -53,18 +50,18 @@ def testLayout(self): child_left_2.show() self.assertEqual( - child_left_1.mapToParent(child_left_1.rect().topLeft()), - QPoint(5, 6)) + child_left_1.mapToParent(child_left_1.rect().topLeft()), QPoint(5, 6) + ) self.assertEqual( - child_left_1.mapToParent(child_left_1.rect().bottomRight()), - QPoint(34, 390)) + child_left_1.mapToParent(child_left_1.rect().bottomRight()), QPoint(34, 390) + ) self.assertEqual( - child_left_2.mapToParent(child_left_2.rect().topLeft()), - QPoint(35, 6)) + child_left_2.mapToParent(child_left_2.rect().topLeft()), QPoint(35, 6) + ) self.assertEqual( - child_left_2.mapToParent(child_left_2.rect().bottomRight()), - QPoint(74, 390)) + child_left_2.mapToParent(child_left_2.rect().bottomRight()), QPoint(74, 390) + ) layout.setHorizontalSpacing(12) child_right_1 = QWidget() @@ -77,29 +74,31 @@ def testLayout(self): child_right_2.show() self.assertEqual( - child_left_1.mapToParent(child_left_1.rect().topLeft()), - QPoint(5, 6)) + child_left_1.mapToParent(child_left_1.rect().topLeft()), QPoint(5, 6) + ) self.assertEqual( - child_left_1.mapToParent(child_left_1.rect().bottomRight()), - QPoint(34, 390)) + child_left_1.mapToParent(child_left_1.rect().bottomRight()), QPoint(34, 390) + ) self.assertEqual( - child_left_2.mapToParent(child_left_2.rect().topLeft()), - QPoint(47, 6)) + child_left_2.mapToParent(child_left_2.rect().topLeft()), QPoint(47, 6) + ) self.assertEqual( - child_left_2.mapToParent(child_left_2.rect().bottomRight()), - QPoint(86, 390)) + child_left_2.mapToParent(child_left_2.rect().bottomRight()), QPoint(86, 390) + ) self.assertEqual( - child_right_1.mapToParent(child_right_1.rect().topLeft()), - QPoint(552, 6)) + child_right_1.mapToParent(child_right_1.rect().topLeft()), QPoint(552, 6) + ) self.assertEqual( child_right_1.mapToParent(child_right_1.rect().bottomRight()), - QPoint(591, 390)) + QPoint(591, 390), + ) self.assertEqual( - child_right_2.mapToParent(child_right_2.rect().topLeft()), - QPoint(460, 6)) + child_right_2.mapToParent(child_right_2.rect().topLeft()), QPoint(460, 6) + ) self.assertEqual( child_right_2.mapToParent(child_right_2.rect().bottomRight()), - QPoint(539, 390)) + QPoint(539, 390), + ) layout.setVerticalSpacing(13) child_top_1 = QWidget() @@ -112,41 +111,43 @@ def testLayout(self): child_top_2.show() self.assertEqual( - child_left_1.mapToParent(child_left_1.rect().topLeft()), - QPoint(5, 6)) + child_left_1.mapToParent(child_left_1.rect().topLeft()), QPoint(5, 6) + ) self.assertEqual( - child_left_1.mapToParent(child_left_1.rect().bottomRight()), - QPoint(34, 390)) + child_left_1.mapToParent(child_left_1.rect().bottomRight()), QPoint(34, 390) + ) self.assertEqual( - child_left_2.mapToParent(child_left_2.rect().topLeft()), - QPoint(47, 6)) + child_left_2.mapToParent(child_left_2.rect().topLeft()), QPoint(47, 6) + ) self.assertEqual( - child_left_2.mapToParent(child_left_2.rect().bottomRight()), - QPoint(86, 390)) + child_left_2.mapToParent(child_left_2.rect().bottomRight()), QPoint(86, 390) + ) self.assertEqual( - child_right_1.mapToParent(child_right_1.rect().topLeft()), - QPoint(552, 6)) + child_right_1.mapToParent(child_right_1.rect().topLeft()), QPoint(552, 6) + ) self.assertEqual( child_right_1.mapToParent(child_right_1.rect().bottomRight()), - QPoint(591, 390)) + QPoint(591, 390), + ) self.assertEqual( - child_right_2.mapToParent(child_right_2.rect().topLeft()), - QPoint(460, 6)) + child_right_2.mapToParent(child_right_2.rect().topLeft()), QPoint(460, 6) + ) self.assertEqual( child_right_2.mapToParent(child_right_2.rect().bottomRight()), - QPoint(539, 390)) + QPoint(539, 390), + ) self.assertEqual( - child_top_1.mapToParent(child_top_1.rect().topLeft()), - QPoint(99, 6)) + child_top_1.mapToParent(child_top_1.rect().topLeft()), QPoint(99, 6) + ) self.assertEqual( - child_top_1.mapToParent(child_top_1.rect().bottomRight()), - QPoint(447, 25)) + child_top_1.mapToParent(child_top_1.rect().bottomRight()), QPoint(447, 25) + ) self.assertEqual( - child_top_2.mapToParent(child_top_2.rect().topLeft()), - QPoint(99, 39)) + child_top_2.mapToParent(child_top_2.rect().topLeft()), QPoint(99, 39) + ) self.assertEqual( - child_top_2.mapToParent(child_top_2.rect().bottomRight()), - QPoint(447, 68)) + child_top_2.mapToParent(child_top_2.rect().bottomRight()), QPoint(447, 68) + ) child_bottom_1 = QWidget() child_bottom_1.setFixedHeight(20) @@ -158,54 +159,58 @@ def testLayout(self): child_bottom_2.show() self.assertEqual( - child_left_1.mapToParent(child_left_1.rect().topLeft()), - QPoint(5, 6)) + child_left_1.mapToParent(child_left_1.rect().topLeft()), QPoint(5, 6) + ) self.assertEqual( - child_left_1.mapToParent(child_left_1.rect().bottomRight()), - QPoint(34, 390)) + child_left_1.mapToParent(child_left_1.rect().bottomRight()), QPoint(34, 390) + ) self.assertEqual( - child_left_2.mapToParent(child_left_2.rect().topLeft()), - QPoint(47, 6)) + child_left_2.mapToParent(child_left_2.rect().topLeft()), QPoint(47, 6) + ) self.assertEqual( - child_left_2.mapToParent(child_left_2.rect().bottomRight()), - QPoint(86, 390)) + child_left_2.mapToParent(child_left_2.rect().bottomRight()), QPoint(86, 390) + ) self.assertEqual( - child_right_1.mapToParent(child_right_1.rect().topLeft()), - QPoint(552, 6)) + child_right_1.mapToParent(child_right_1.rect().topLeft()), QPoint(552, 6) + ) self.assertEqual( child_right_1.mapToParent(child_right_1.rect().bottomRight()), - QPoint(591, 390)) + QPoint(591, 390), + ) self.assertEqual( - child_right_2.mapToParent(child_right_2.rect().topLeft()), - QPoint(460, 6)) + child_right_2.mapToParent(child_right_2.rect().topLeft()), QPoint(460, 6) + ) self.assertEqual( child_right_2.mapToParent(child_right_2.rect().bottomRight()), - QPoint(539, 390)) + QPoint(539, 390), + ) self.assertEqual( - child_top_1.mapToParent(child_top_1.rect().topLeft()), - QPoint(99, 6)) + child_top_1.mapToParent(child_top_1.rect().topLeft()), QPoint(99, 6) + ) self.assertEqual( - child_top_1.mapToParent(child_top_1.rect().bottomRight()), - QPoint(447, 25)) + child_top_1.mapToParent(child_top_1.rect().bottomRight()), QPoint(447, 25) + ) self.assertEqual( - child_top_2.mapToParent(child_top_2.rect().topLeft()), - QPoint(99, 39)) + child_top_2.mapToParent(child_top_2.rect().topLeft()), QPoint(99, 39) + ) self.assertEqual( - child_top_2.mapToParent(child_top_2.rect().bottomRight()), - QPoint(447, 68)) + child_top_2.mapToParent(child_top_2.rect().bottomRight()), QPoint(447, 68) + ) self.assertEqual( - child_bottom_1.mapToParent(child_bottom_1.rect().topLeft()), - QPoint(99, 371)) + child_bottom_1.mapToParent(child_bottom_1.rect().topLeft()), QPoint(99, 371) + ) self.assertEqual( child_bottom_1.mapToParent(child_bottom_1.rect().bottomRight()), - QPoint(447, 390)) + QPoint(447, 390), + ) self.assertEqual( - child_bottom_2.mapToParent(child_bottom_2.rect().topLeft()), - QPoint(99, 328)) + child_bottom_2.mapToParent(child_bottom_2.rect().topLeft()), QPoint(99, 328) + ) self.assertEqual( child_bottom_2.mapToParent(child_bottom_2.rect().bottomRight()), - QPoint(447, 357)) + QPoint(447, 357), + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsowsconnection.py b/tests/src/python/test_qgsowsconnection.py index 730294173b88..05946cc58af4 100644 --- a/tests/src/python/test_qgsowsconnection.py +++ b/tests/src/python/test_qgsowsconnection.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '12.09.2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "12.09.2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication from qgis.core import QgsDataSourceUri, QgsOwsConnection, QgsSettings @@ -29,69 +30,69 @@ def setUpClass(cls): # setup some fake connections settings = QgsSettings() - key = '/connections/ows/items/wms/connections/items/test/' - settings.setValue(key + 'url', 'aaa.bbb.com') - settings.setValue(key + 'http-header', {'referer': 'my_ref'}) - settings.setValue(key + 'ignore-get-map-uri', True) - settings.setValue(key + 'ignore-get-feature-info-uri', True) - settings.setValue(key + 'smooth-pixmap-transform', True) - settings.setValue(key + 'dpi-mode', 4) - settings.setValue(key + 'ignore-axis-orientation', True) - settings.setValue(key + 'invert-axis-orientation', True) - settings.setValue(key + 'feature-count', 9) - - key = '/connections/ows/items/wfs/connections/items/test/' - settings.setValue(key + 'url', 'ccc.ddd.com') - settings.setValue(key + 'version', '1.1.0') - settings.setValue(key + 'max-num-features', '47') - settings.setValue(key + 'ignore-axis-orientation', True) - settings.setValue(key + 'invert-axis-orientation', True) + key = "/connections/ows/items/wms/connections/items/test/" + settings.setValue(key + "url", "aaa.bbb.com") + settings.setValue(key + "http-header", {"referer": "my_ref"}) + settings.setValue(key + "ignore-get-map-uri", True) + settings.setValue(key + "ignore-get-feature-info-uri", True) + settings.setValue(key + "smooth-pixmap-transform", True) + settings.setValue(key + "dpi-mode", 4) + settings.setValue(key + "ignore-axis-orientation", True) + settings.setValue(key + "invert-axis-orientation", True) + settings.setValue(key + "feature-count", 9) + + key = "/connections/ows/items/wfs/connections/items/test/" + settings.setValue(key + "url", "ccc.ddd.com") + settings.setValue(key + "version", "1.1.0") + settings.setValue(key + "max-num-features", "47") + settings.setValue(key + "ignore-axis-orientation", True) + settings.setValue(key + "invert-axis-orientation", True) def testWmsConnection(self): - c = QgsOwsConnection('WMS', 'test') + c = QgsOwsConnection("WMS", "test") uri = c.uri() - self.assertEqual(uri.param('url'), 'aaa.bbb.com') - self.assertEqual(uri.httpHeader('referer'), 'my_ref') - self.assertEqual(uri.param('IgnoreGetMapUrl'), '1') - self.assertEqual(uri.param('IgnoreGetFeatureInfoUrl'), '1') - self.assertEqual(uri.param('SmoothPixmapTransform'), '1') - self.assertEqual(uri.param('dpiMode'), '4') - self.assertEqual(uri.param('IgnoreAxisOrientation'), '1') - self.assertEqual(uri.param('InvertAxisOrientation'), '1') - self.assertEqual(uri.param('featureCount'), '9') + self.assertEqual(uri.param("url"), "aaa.bbb.com") + self.assertEqual(uri.httpHeader("referer"), "my_ref") + self.assertEqual(uri.param("IgnoreGetMapUrl"), "1") + self.assertEqual(uri.param("IgnoreGetFeatureInfoUrl"), "1") + self.assertEqual(uri.param("SmoothPixmapTransform"), "1") + self.assertEqual(uri.param("dpiMode"), "4") + self.assertEqual(uri.param("IgnoreAxisOrientation"), "1") + self.assertEqual(uri.param("InvertAxisOrientation"), "1") + self.assertEqual(uri.param("featureCount"), "9") def testWmsSettings(self): uri = QgsDataSourceUri() - QgsOwsConnection.addWmsWcsConnectionSettings(uri, 'wms', 'test') + QgsOwsConnection.addWmsWcsConnectionSettings(uri, "wms", "test") - self.assertEqual(uri.httpHeader('referer'), 'my_ref') - self.assertEqual(uri.param('IgnoreGetMapUrl'), '1') - self.assertEqual(uri.param('IgnoreGetFeatureInfoUrl'), '1') - self.assertEqual(uri.param('SmoothPixmapTransform'), '1') - self.assertEqual(uri.param('dpiMode'), '4') - self.assertEqual(uri.param('IgnoreAxisOrientation'), '1') - self.assertEqual(uri.param('InvertAxisOrientation'), '1') - self.assertEqual(uri.param('featureCount'), '9') + self.assertEqual(uri.httpHeader("referer"), "my_ref") + self.assertEqual(uri.param("IgnoreGetMapUrl"), "1") + self.assertEqual(uri.param("IgnoreGetFeatureInfoUrl"), "1") + self.assertEqual(uri.param("SmoothPixmapTransform"), "1") + self.assertEqual(uri.param("dpiMode"), "4") + self.assertEqual(uri.param("IgnoreAxisOrientation"), "1") + self.assertEqual(uri.param("InvertAxisOrientation"), "1") + self.assertEqual(uri.param("featureCount"), "9") def testWfsConnection(self): - c = QgsOwsConnection('WFS', 'test') + c = QgsOwsConnection("WFS", "test") uri = c.uri() - self.assertEqual(uri.param('url'), 'ccc.ddd.com') - self.assertEqual(uri.param('version'), '1.1.0') - self.assertEqual(uri.param('maxNumFeatures'), '47') - self.assertEqual(uri.param('IgnoreAxisOrientation'), '1') - self.assertEqual(uri.param('InvertAxisOrientation'), '1') + self.assertEqual(uri.param("url"), "ccc.ddd.com") + self.assertEqual(uri.param("version"), "1.1.0") + self.assertEqual(uri.param("maxNumFeatures"), "47") + self.assertEqual(uri.param("IgnoreAxisOrientation"), "1") + self.assertEqual(uri.param("InvertAxisOrientation"), "1") def testWfsSettings(self): uri = QgsDataSourceUri() - QgsOwsConnection.addWfsConnectionSettings(uri, 'wfs', 'test') + QgsOwsConnection.addWfsConnectionSettings(uri, "wfs", "test") - self.assertEqual(uri.param('version'), '1.1.0') - self.assertEqual(uri.param('maxNumFeatures'), '47') - self.assertEqual(uri.param('IgnoreAxisOrientation'), '1') - self.assertEqual(uri.param('InvertAxisOrientation'), '1') + self.assertEqual(uri.param("version"), "1.1.0") + self.assertEqual(uri.param("maxNumFeatures"), "47") + self.assertEqual(uri.param("IgnoreAxisOrientation"), "1") + self.assertEqual(uri.param("InvertAxisOrientation"), "1") if __name__ == "__main__": diff --git a/tests/src/python/test_qgspalettedrasterrenderer.py b/tests/src/python/test_qgspalettedrasterrenderer.py index eec66491e060..7ae2b85fa713 100644 --- a/tests/src/python/test_qgspalettedrasterrenderer.py +++ b/tests/src/python/test_qgspalettedrasterrenderer.py @@ -23,7 +23,7 @@ QgsLimitedRandomColorRamp, QgsMapSettings, QgsPalettedRasterRenderer, - QgsRasterLayer + QgsRasterLayer, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -38,53 +38,57 @@ class TestQgsPalettedRasterRenderer(QgisTestCase): def testPaletted(self): - """ test paletted raster renderer with raster with color table""" - path = os.path.join(unitTestDataPath('raster'), - 'with_color_table.tif') + """test paletted raster renderer with raster with color table""" + path = os.path.join(unitTestDataPath("raster"), "with_color_table.tif") info = QFileInfo(path) base_name = info.baseName() layer = QgsRasterLayer(path, base_name) - self.assertTrue(layer.isValid(), f'Raster not loaded: {path}') - - renderer = QgsPalettedRasterRenderer(layer.dataProvider(), 1, - [QgsPalettedRasterRenderer.Class(1, QColor(0, 255, 0), 'class 2'), - QgsPalettedRasterRenderer.Class(3, QColor(255, 0, 0), 'class 1')]) + self.assertTrue(layer.isValid(), f"Raster not loaded: {path}") + + renderer = QgsPalettedRasterRenderer( + layer.dataProvider(), + 1, + [ + QgsPalettedRasterRenderer.Class(1, QColor(0, 255, 0), "class 2"), + QgsPalettedRasterRenderer.Class(3, QColor(255, 0, 0), "class 1"), + ], + ) self.assertEqual(renderer.nColors(), 2) self.assertEqual(renderer.usesBands(), [1]) self.assertEqual(renderer.inputBand(), 1) # test labels - self.assertEqual(renderer.label(1), 'class 2') - self.assertEqual(renderer.label(3), 'class 1') + self.assertEqual(renderer.label(1), "class 2") + self.assertEqual(renderer.label(3), "class 1") self.assertFalse(renderer.label(101)) # test legend symbology - should be sorted by value legend = renderer.legendSymbologyItems() - self.assertEqual(legend[0][0], 'class 2') - self.assertEqual(legend[1][0], 'class 1') - self.assertEqual(legend[0][1].name(), '#00ff00') - self.assertEqual(legend[1][1].name(), '#ff0000') + self.assertEqual(legend[0][0], "class 2") + self.assertEqual(legend[1][0], "class 1") + self.assertEqual(legend[0][1].name(), "#00ff00") + self.assertEqual(legend[1][1].name(), "#ff0000") # test retrieving classes classes = renderer.classes() self.assertEqual(classes[0].value, 1) self.assertEqual(classes[1].value, 3) - self.assertEqual(classes[0].label, 'class 2') - self.assertEqual(classes[1].label, 'class 1') - self.assertEqual(classes[0].color.name(), '#00ff00') - self.assertEqual(classes[1].color.name(), '#ff0000') + self.assertEqual(classes[0].label, "class 2") + self.assertEqual(classes[1].label, "class 1") + self.assertEqual(classes[0].color.name(), "#00ff00") + self.assertEqual(classes[1].color.name(), "#ff0000") # test set label # bad index - renderer.setLabel(1212, 'bad') - renderer.setLabel(3, 'new class') - self.assertEqual(renderer.label(3), 'new class') + renderer.setLabel(1212, "bad") + renderer.setLabel(3, "new class") + self.assertEqual(renderer.label(3), "new class") # color ramp r = QgsLimitedRandomColorRamp(5) renderer.setSourceColorRamp(r) - self.assertEqual(renderer.sourceColorRamp().type(), 'random') + self.assertEqual(renderer.sourceColorRamp().type(), "random") self.assertEqual(renderer.sourceColorRamp().count(), 5) # clone @@ -92,29 +96,31 @@ def testPaletted(self): classes = new_renderer.classes() self.assertEqual(classes[0].value, 1) self.assertEqual(classes[1].value, 3) - self.assertEqual(classes[0].label, 'class 2') - self.assertEqual(classes[1].label, 'new class') - self.assertEqual(classes[0].color.name(), '#00ff00') - self.assertEqual(classes[1].color.name(), '#ff0000') - self.assertEqual(new_renderer.sourceColorRamp().type(), 'random') + self.assertEqual(classes[0].label, "class 2") + self.assertEqual(classes[1].label, "new class") + self.assertEqual(classes[0].color.name(), "#00ff00") + self.assertEqual(classes[1].color.name(), "#ff0000") + self.assertEqual(new_renderer.sourceColorRamp().type(), "random") self.assertEqual(new_renderer.sourceColorRamp().count(), 5) # write to xml and read - doc = QDomDocument('testdoc') - elem = doc.createElement('qgis') + doc = QDomDocument("testdoc") + elem = doc.createElement("qgis") renderer.writeXml(doc, elem) - restored = QgsPalettedRasterRenderer.create(elem.firstChild().toElement(), layer.dataProvider()) + restored = QgsPalettedRasterRenderer.create( + elem.firstChild().toElement(), layer.dataProvider() + ) self.assertTrue(restored) self.assertEqual(restored.usesBands(), [1]) classes = restored.classes() self.assertTrue(classes) self.assertEqual(classes[0].value, 1) self.assertEqual(classes[1].value, 3) - self.assertEqual(classes[0].label, 'class 2') - self.assertEqual(classes[1].label, 'new class') - self.assertEqual(classes[0].color.name(), '#00ff00') - self.assertEqual(classes[1].color.name(), '#ff0000') - self.assertEqual(restored.sourceColorRamp().type(), 'random') + self.assertEqual(classes[0].label, "class 2") + self.assertEqual(classes[1].label, "new class") + self.assertEqual(classes[0].color.name(), "#00ff00") + self.assertEqual(classes[1].color.name(), "#ff0000") + self.assertEqual(restored.sourceColorRamp().type(), "random") self.assertEqual(restored.sourceColorRamp().count(), 5) # render test @@ -124,18 +130,20 @@ def testPaletted(self): ms.setExtent(layer.extent()) self.assertTrue( - self.render_map_settings_check( - 'paletted_renderer', - 'paletted_renderer', - ms) + self.render_map_settings_check("paletted_renderer", "paletted_renderer", ms) ) def testPalettedBandInvalidLayer(self): - """ test paletted raster render band with a broken layer path""" - renderer = QgsPalettedRasterRenderer(None, 2, - [QgsPalettedRasterRenderer.Class(137, QColor(0, 255, 0), 'class 2'), - QgsPalettedRasterRenderer.Class(138, QColor(255, 0, 0), 'class 1'), - QgsPalettedRasterRenderer.Class(139, QColor(0, 0, 255), 'class 1')]) + """test paletted raster render band with a broken layer path""" + renderer = QgsPalettedRasterRenderer( + None, + 2, + [ + QgsPalettedRasterRenderer.Class(137, QColor(0, 255, 0), "class 2"), + QgsPalettedRasterRenderer.Class(138, QColor(255, 0, 0), "class 1"), + QgsPalettedRasterRenderer.Class(139, QColor(0, 0, 255), "class 1"), + ], + ) self.assertEqual(renderer.inputBand(), 2) @@ -144,18 +152,22 @@ def testPalettedBandInvalidLayer(self): self.assertEqual(renderer.inputBand(), 10) def testPalettedBand(self): - """ test paletted raster render band""" - path = os.path.join(unitTestDataPath(), - 'landsat_4326.tif') + """test paletted raster render band""" + path = os.path.join(unitTestDataPath(), "landsat_4326.tif") info = QFileInfo(path) base_name = info.baseName() layer = QgsRasterLayer(path, base_name) - self.assertTrue(layer.isValid(), f'Raster not loaded: {path}') - - renderer = QgsPalettedRasterRenderer(layer.dataProvider(), 2, - [QgsPalettedRasterRenderer.Class(137, QColor(0, 255, 0), 'class 2'), - QgsPalettedRasterRenderer.Class(138, QColor(255, 0, 0), 'class 1'), - QgsPalettedRasterRenderer.Class(139, QColor(0, 0, 255), 'class 1')]) + self.assertTrue(layer.isValid(), f"Raster not loaded: {path}") + + renderer = QgsPalettedRasterRenderer( + layer.dataProvider(), + 2, + [ + QgsPalettedRasterRenderer.Class(137, QColor(0, 255, 0), "class 2"), + QgsPalettedRasterRenderer.Class(138, QColor(255, 0, 0), "class 1"), + QgsPalettedRasterRenderer.Class(139, QColor(0, 0, 255), "class 1"), + ], + ) self.assertEqual(renderer.inputBand(), 2) self.assertFalse(renderer.setInputBand(0)) @@ -173,15 +185,19 @@ def testPalettedBand(self): self.assertTrue( self.render_map_settings_check( - 'paletted_renderer_band2', - 'paletted_renderer_band2', - ms) + "paletted_renderer_band2", "paletted_renderer_band2", ms + ) ) - renderer = QgsPalettedRasterRenderer(layer.dataProvider(), 3, - [QgsPalettedRasterRenderer.Class(120, QColor(0, 255, 0), 'class 2'), - QgsPalettedRasterRenderer.Class(123, QColor(255, 0, 0), 'class 1'), - QgsPalettedRasterRenderer.Class(124, QColor(0, 0, 255), 'class 1')]) + renderer = QgsPalettedRasterRenderer( + layer.dataProvider(), + 3, + [ + QgsPalettedRasterRenderer.Class(120, QColor(0, 255, 0), "class 2"), + QgsPalettedRasterRenderer.Class(123, QColor(255, 0, 0), "class 1"), + QgsPalettedRasterRenderer.Class(124, QColor(0, 0, 255), "class 1"), + ], + ) layer.setRenderer(renderer) ms = QgsMapSettings() @@ -190,196 +206,212 @@ def testPalettedBand(self): self.assertTrue( self.render_map_settings_check( - 'paletted_renderer_band3', - 'paletted_renderer_band3', - ms) + "paletted_renderer_band3", "paletted_renderer_band3", ms + ) ) def testPalettedColorTableToClassData(self): - entries = [QgsColorRampShader.ColorRampItem(5, QColor(255, 0, 0), 'item1'), - QgsColorRampShader.ColorRampItem(3, QColor(0, 255, 0), 'item2'), - QgsColorRampShader.ColorRampItem(6, QColor(0, 0, 255), 'item3'), - ] + entries = [ + QgsColorRampShader.ColorRampItem(5, QColor(255, 0, 0), "item1"), + QgsColorRampShader.ColorRampItem(3, QColor(0, 255, 0), "item2"), + QgsColorRampShader.ColorRampItem(6, QColor(0, 0, 255), "item3"), + ] classes = QgsPalettedRasterRenderer.colorTableToClassData(entries) self.assertEqual(classes[0].value, 5) self.assertEqual(classes[1].value, 3) self.assertEqual(classes[2].value, 6) - self.assertEqual(classes[0].label, 'item1') - self.assertEqual(classes[1].label, 'item2') - self.assertEqual(classes[2].label, 'item3') - self.assertEqual(classes[0].color.name(), '#ff0000') - self.assertEqual(classes[1].color.name(), '#00ff00') - self.assertEqual(classes[2].color.name(), '#0000ff') + self.assertEqual(classes[0].label, "item1") + self.assertEqual(classes[1].label, "item2") + self.assertEqual(classes[2].label, "item3") + self.assertEqual(classes[0].color.name(), "#ff0000") + self.assertEqual(classes[1].color.name(), "#00ff00") + self.assertEqual(classes[2].color.name(), "#0000ff") # test #13263 - path = os.path.join(unitTestDataPath('raster'), - 'hub13263.vrt') + path = os.path.join(unitTestDataPath("raster"), "hub13263.vrt") info = QFileInfo(path) base_name = info.baseName() layer = QgsRasterLayer(path, base_name) - self.assertTrue(layer.isValid(), f'Raster not loaded: {path}') - classes = QgsPalettedRasterRenderer.colorTableToClassData(layer.dataProvider().colorTable(1)) + self.assertTrue(layer.isValid(), f"Raster not loaded: {path}") + classes = QgsPalettedRasterRenderer.colorTableToClassData( + layer.dataProvider().colorTable(1) + ) self.assertEqual(len(classes), 4) - classes = QgsPalettedRasterRenderer.colorTableToClassData(layer.dataProvider().colorTable(15)) + classes = QgsPalettedRasterRenderer.colorTableToClassData( + layer.dataProvider().colorTable(15) + ) self.assertEqual(len(classes), 256) def testLoadPalettedColorDataFromString(self): """ Test interpreting a bunch of color data format strings """ - esri_clr_format = '1 255 255 0\n2 64 0 128\n3 255 32 32\n4 0 255 0\n5 0 0 255' - esri_clr_format_win = '1 255 255 0\r\n2 64 0 128\r\n3 255 32 32\r\n4 0 255 0\r\n5 0 0 255' - esri_clr_format_tab = '1\t255\t255\t0\n2\t64\t0\t128\n3\t255\t32\t32\n4\t0\t255\t0\n5\t0\t0\t255' - esri_clr_spaces = '1 255 255 0\n2 64 0 128\n3 255 32 32\n4 0 255 0\n5 0 0 255' - gdal_clr_comma = '1,255,255,0\n2,64,0,128\n3,255,32,32\n4,0,255,0\n5,0,0,255' - gdal_clr_colon = '1:255:255:0\n2:64:0:128\n3:255:32:32\n4:0:255:0\n5:0:0:255' - for f in [esri_clr_format, - esri_clr_format_win, - esri_clr_format_tab, - esri_clr_spaces, - gdal_clr_comma, - gdal_clr_colon]: + esri_clr_format = "1 255 255 0\n2 64 0 128\n3 255 32 32\n4 0 255 0\n5 0 0 255" + esri_clr_format_win = ( + "1 255 255 0\r\n2 64 0 128\r\n3 255 32 32\r\n4 0 255 0\r\n5 0 0 255" + ) + esri_clr_format_tab = ( + "1\t255\t255\t0\n2\t64\t0\t128\n3\t255\t32\t32\n4\t0\t255\t0\n5\t0\t0\t255" + ) + esri_clr_spaces = "1 255 255 0\n2 64 0 128\n3 255 32 32\n4 0 255 0\n5 0 0 255" + gdal_clr_comma = "1,255,255,0\n2,64,0,128\n3,255,32,32\n4,0,255,0\n5,0,0,255" + gdal_clr_colon = "1:255:255:0\n2:64:0:128\n3:255:32:32\n4:0:255:0\n5:0:0:255" + for f in [ + esri_clr_format, + esri_clr_format_win, + esri_clr_format_tab, + esri_clr_spaces, + gdal_clr_comma, + gdal_clr_colon, + ]: classes = QgsPalettedRasterRenderer.classDataFromString(f) self.assertEqual(len(classes), 5) self.assertEqual(classes[0].value, 1) - self.assertEqual(classes[0].color.name(), '#ffff00') + self.assertEqual(classes[0].color.name(), "#ffff00") self.assertEqual(classes[1].value, 2) - self.assertEqual(classes[1].color.name(), '#400080') + self.assertEqual(classes[1].color.name(), "#400080") self.assertEqual(classes[2].value, 3) - self.assertEqual(classes[2].color.name(), '#ff2020') + self.assertEqual(classes[2].color.name(), "#ff2020") self.assertEqual(classes[3].value, 4) - self.assertEqual(classes[3].color.name(), '#00ff00') + self.assertEqual(classes[3].color.name(), "#00ff00") self.assertEqual(classes[4].value, 5) - self.assertEqual(classes[4].color.name(), '#0000ff') + self.assertEqual(classes[4].color.name(), "#0000ff") - grass_named_colors = '0 white\n1 yellow\n3 black\n6 blue\n9 magenta\n11 aqua\n13 grey\n14 gray\n15 orange\n19 brown\n21 purple\n22 violet\n24 indigo\n90 green\n180 cyan\n270 red\n' + grass_named_colors = "0 white\n1 yellow\n3 black\n6 blue\n9 magenta\n11 aqua\n13 grey\n14 gray\n15 orange\n19 brown\n21 purple\n22 violet\n24 indigo\n90 green\n180 cyan\n270 red\n" classes = QgsPalettedRasterRenderer.classDataFromString(grass_named_colors) self.assertEqual(len(classes), 16) self.assertEqual(classes[0].value, 0) - self.assertEqual(classes[0].color.name(), '#ffffff') + self.assertEqual(classes[0].color.name(), "#ffffff") self.assertEqual(classes[1].value, 1) - self.assertEqual(classes[1].color.name(), '#ffff00') + self.assertEqual(classes[1].color.name(), "#ffff00") self.assertEqual(classes[2].value, 3) - self.assertEqual(classes[2].color.name(), '#000000') + self.assertEqual(classes[2].color.name(), "#000000") self.assertEqual(classes[3].value, 6) - self.assertEqual(classes[3].color.name(), '#0000ff') + self.assertEqual(classes[3].color.name(), "#0000ff") self.assertEqual(classes[4].value, 9) - self.assertEqual(classes[4].color.name(), '#ff00ff') + self.assertEqual(classes[4].color.name(), "#ff00ff") self.assertEqual(classes[5].value, 11) - self.assertEqual(classes[5].color.name(), '#00ffff') + self.assertEqual(classes[5].color.name(), "#00ffff") self.assertEqual(classes[6].value, 13) - self.assertEqual(classes[6].color.name(), '#808080') + self.assertEqual(classes[6].color.name(), "#808080") self.assertEqual(classes[7].value, 14) - self.assertEqual(classes[7].color.name(), '#808080') + self.assertEqual(classes[7].color.name(), "#808080") self.assertEqual(classes[8].value, 15) - self.assertEqual(classes[8].color.name(), '#ffa500') + self.assertEqual(classes[8].color.name(), "#ffa500") self.assertEqual(classes[9].value, 19) - self.assertEqual(classes[9].color.name(), '#a52a2a') + self.assertEqual(classes[9].color.name(), "#a52a2a") self.assertEqual(classes[10].value, 21) - self.assertEqual(classes[10].color.name(), '#800080') + self.assertEqual(classes[10].color.name(), "#800080") self.assertEqual(classes[11].value, 22) - self.assertEqual(classes[11].color.name(), '#ee82ee') + self.assertEqual(classes[11].color.name(), "#ee82ee") self.assertEqual(classes[12].value, 24) - self.assertEqual(classes[12].color.name(), '#4b0082') + self.assertEqual(classes[12].color.name(), "#4b0082") self.assertEqual(classes[13].value, 90) - self.assertEqual(classes[13].color.name(), '#008000') + self.assertEqual(classes[13].color.name(), "#008000") self.assertEqual(classes[14].value, 180) - self.assertEqual(classes[14].color.name(), '#00ffff') + self.assertEqual(classes[14].color.name(), "#00ffff") self.assertEqual(classes[15].value, 270) - self.assertEqual(classes[15].color.name(), '#ff0000') + self.assertEqual(classes[15].color.name(), "#ff0000") - gdal_alpha = '1:255:255:0:0\n2:64:0:128:50\n3:255:32:32:122\n4:0:255:0:200\n5:0:0:255:255' + gdal_alpha = "1:255:255:0:0\n2:64:0:128:50\n3:255:32:32:122\n4:0:255:0:200\n5:0:0:255:255" classes = QgsPalettedRasterRenderer.classDataFromString(gdal_alpha) self.assertEqual(len(classes), 5) self.assertEqual(classes[0].value, 1) - self.assertEqual(classes[0].color.name(), '#ffff00') + self.assertEqual(classes[0].color.name(), "#ffff00") self.assertEqual(classes[0].color.alpha(), 0) self.assertEqual(classes[1].value, 2) - self.assertEqual(classes[1].color.name(), '#400080') + self.assertEqual(classes[1].color.name(), "#400080") self.assertEqual(classes[1].color.alpha(), 50) self.assertEqual(classes[2].value, 3) - self.assertEqual(classes[2].color.name(), '#ff2020') + self.assertEqual(classes[2].color.name(), "#ff2020") self.assertEqual(classes[2].color.alpha(), 122) self.assertEqual(classes[3].value, 4) - self.assertEqual(classes[3].color.name(), '#00ff00') + self.assertEqual(classes[3].color.name(), "#00ff00") self.assertEqual(classes[3].color.alpha(), 200) self.assertEqual(classes[4].value, 5) - self.assertEqual(classes[4].color.name(), '#0000ff') + self.assertEqual(classes[4].color.name(), "#0000ff") self.assertEqual(classes[4].color.alpha(), 255) # qgis style, with labels - qgis_style = '3 255 0 0 255 class 1\n4 0 255 0 200 class 2' + qgis_style = "3 255 0 0 255 class 1\n4 0 255 0 200 class 2" classes = QgsPalettedRasterRenderer.classDataFromString(qgis_style) self.assertEqual(len(classes), 2) self.assertEqual(classes[0].value, 3) - self.assertEqual(classes[0].color.name(), '#ff0000') + self.assertEqual(classes[0].color.name(), "#ff0000") self.assertEqual(classes[0].color.alpha(), 255) - self.assertEqual(classes[0].label, 'class 1') + self.assertEqual(classes[0].label, "class 1") self.assertEqual(classes[1].value, 4) - self.assertEqual(classes[1].color.name(), '#00ff00') + self.assertEqual(classes[1].color.name(), "#00ff00") self.assertEqual(classes[1].color.alpha(), 200) - self.assertEqual(classes[1].label, 'class 2') + self.assertEqual(classes[1].label, "class 2") # some bad inputs - bad = '' + bad = "" classes = QgsPalettedRasterRenderer.classDataFromString(bad) self.assertEqual(len(classes), 0) - bad = '\n\n\n' + bad = "\n\n\n" classes = QgsPalettedRasterRenderer.classDataFromString(bad) self.assertEqual(len(classes), 0) - bad = 'x x x x' + bad = "x x x x" classes = QgsPalettedRasterRenderer.classDataFromString(bad) self.assertEqual(len(classes), 0) - bad = '1 255 0 0\n2 255 255\n3 255 0 255' + bad = "1 255 0 0\n2 255 255\n3 255 0 255" classes = QgsPalettedRasterRenderer.classDataFromString(bad) self.assertEqual(len(classes), 2) - bad = '1 255 a 0' + bad = "1 255 a 0" classes = QgsPalettedRasterRenderer.classDataFromString(bad) self.assertEqual(len(classes), 1) def testLoadPalettedClassDataFromFile(self): # bad file - classes = QgsPalettedRasterRenderer.classDataFromFile('ajdhjashjkdh kjahjkdhk') + classes = QgsPalettedRasterRenderer.classDataFromFile("ajdhjashjkdh kjahjkdhk") self.assertEqual(len(classes), 0) # good file! - path = os.path.join(unitTestDataPath('raster'), - 'test.clr') + path = os.path.join(unitTestDataPath("raster"), "test.clr") classes = QgsPalettedRasterRenderer.classDataFromFile(path) self.assertEqual(len(classes), 10) self.assertEqual(classes[0].value, 1) - self.assertEqual(classes[0].color.name(), '#000000') + self.assertEqual(classes[0].color.name(), "#000000") self.assertEqual(classes[0].color.alpha(), 255) self.assertEqual(classes[1].value, 2) - self.assertEqual(classes[1].color.name(), '#c8c8c8') + self.assertEqual(classes[1].color.name(), "#c8c8c8") self.assertEqual(classes[2].value, 3) - self.assertEqual(classes[2].color.name(), '#006e00') + self.assertEqual(classes[2].color.name(), "#006e00") self.assertEqual(classes[3].value, 4) - self.assertEqual(classes[3].color.name(), '#6e4100') + self.assertEqual(classes[3].color.name(), "#6e4100") self.assertEqual(classes[4].value, 5) - self.assertEqual(classes[4].color.name(), '#0000ff') + self.assertEqual(classes[4].color.name(), "#0000ff") self.assertEqual(classes[4].color.alpha(), 255) self.assertEqual(classes[5].value, 6) - self.assertEqual(classes[5].color.name(), '#0059ff') + self.assertEqual(classes[5].color.name(), "#0059ff") self.assertEqual(classes[6].value, 7) - self.assertEqual(classes[6].color.name(), '#00aeff') + self.assertEqual(classes[6].color.name(), "#00aeff") self.assertEqual(classes[7].value, 8) - self.assertEqual(classes[7].color.name(), '#00fff6') + self.assertEqual(classes[7].color.name(), "#00fff6") self.assertEqual(classes[8].value, 9) - self.assertEqual(classes[8].color.name(), '#eeff00') + self.assertEqual(classes[8].color.name(), "#eeff00") self.assertEqual(classes[9].value, 10) - self.assertEqual(classes[9].color.name(), '#ffb600') + self.assertEqual(classes[9].color.name(), "#ffb600") def testPalettedClassDataToString(self): - classes = [QgsPalettedRasterRenderer.Class(1, QColor(0, 255, 0), 'class 2'), - QgsPalettedRasterRenderer.Class(3, QColor(255, 0, 0), 'class 1')] - self.assertEqual(QgsPalettedRasterRenderer.classDataToString(classes), - '1 0 255 0 255 class 2\n3 255 0 0 255 class 1') + classes = [ + QgsPalettedRasterRenderer.Class(1, QColor(0, 255, 0), "class 2"), + QgsPalettedRasterRenderer.Class(3, QColor(255, 0, 0), "class 1"), + ] + self.assertEqual( + QgsPalettedRasterRenderer.classDataToString(classes), + "1 0 255 0 255 class 2\n3 255 0 0 255 class 1", + ) # must be sorted by value to work OK in ArcMap - classes = [QgsPalettedRasterRenderer.Class(4, QColor(0, 255, 0), 'class 2'), - QgsPalettedRasterRenderer.Class(3, QColor(255, 0, 0), 'class 1')] - self.assertEqual(QgsPalettedRasterRenderer.classDataToString(classes), - '3 255 0 0 255 class 1\n4 0 255 0 255 class 2') + classes = [ + QgsPalettedRasterRenderer.Class(4, QColor(0, 255, 0), "class 2"), + QgsPalettedRasterRenderer.Class(3, QColor(255, 0, 0), "class 1"), + ] + self.assertEqual( + QgsPalettedRasterRenderer.classDataToString(classes), + "3 255 0 0 255 class 1\n4 0 255 0 255 class 2", + ) def testPalettedClassDataFromLayer(self): # no layer @@ -387,67 +419,104 @@ def testPalettedClassDataFromLayer(self): self.assertFalse(classes) # 10 class layer - path = os.path.join(unitTestDataPath('raster'), - 'with_color_table.tif') + path = os.path.join(unitTestDataPath("raster"), "with_color_table.tif") info = QFileInfo(path) base_name = info.baseName() layer10 = QgsRasterLayer(path, base_name) - classes = QgsPalettedRasterRenderer.classDataFromRaster(layer10.dataProvider(), 1) + classes = QgsPalettedRasterRenderer.classDataFromRaster( + layer10.dataProvider(), 1 + ) self.assertEqual(len(classes), 10) self.assertEqual(classes[0].value, 1) - self.assertEqual(classes[0].label, '1') + self.assertEqual(classes[0].label, "1") self.assertEqual(classes[1].value, 2) - self.assertEqual(classes[1].label, '2') + self.assertEqual(classes[1].label, "2") self.assertEqual(classes[2].value, 3) - self.assertEqual(classes[2].label, '3') + self.assertEqual(classes[2].label, "3") self.assertEqual(classes[3].value, 4) - self.assertEqual(classes[3].label, '4') + self.assertEqual(classes[3].label, "4") self.assertEqual(classes[4].value, 5) - self.assertEqual(classes[4].label, '5') + self.assertEqual(classes[4].label, "5") self.assertEqual(classes[5].value, 6) - self.assertEqual(classes[5].label, '6') + self.assertEqual(classes[5].label, "6") self.assertEqual(classes[6].value, 7) - self.assertEqual(classes[6].label, '7') + self.assertEqual(classes[6].label, "7") self.assertEqual(classes[7].value, 8) - self.assertEqual(classes[7].label, '8') + self.assertEqual(classes[7].label, "8") self.assertEqual(classes[8].value, 9) - self.assertEqual(classes[8].label, '9') + self.assertEqual(classes[8].label, "9") self.assertEqual(classes[9].value, 10) - self.assertEqual(classes[9].label, '10') + self.assertEqual(classes[9].label, "10") # bad band - self.assertFalse(QgsPalettedRasterRenderer.classDataFromRaster(layer10.dataProvider(), 10101010)) + self.assertFalse( + QgsPalettedRasterRenderer.classDataFromRaster( + layer10.dataProvider(), 10101010 + ) + ) # with ramp r = QgsGradientColorRamp(QColor(200, 0, 0, 100), QColor(0, 200, 0, 200)) - classes = QgsPalettedRasterRenderer.classDataFromRaster(layer10.dataProvider(), 1, r) + classes = QgsPalettedRasterRenderer.classDataFromRaster( + layer10.dataProvider(), 1, r + ) self.assertEqual(len(classes), 10) - self.assertEqual(classes[0].color.name(), '#c80000') - self.assertEqual(classes[1].color.name(), '#b21600') - self.assertEqual(classes[2].color.name(), '#9c2c00') - self.assertIn(classes[3].color.name(), ('#854200', '#854300')) - self.assertEqual(classes[4].color.name(), '#6f5900') - self.assertEqual(classes[5].color.name(), '#596f00') - self.assertIn(classes[6].color.name(), ('#428500', '#438500')) - self.assertEqual(classes[7].color.name(), '#2c9c00') - self.assertEqual(classes[8].color.name(), '#16b200') - self.assertEqual(classes[9].color.name(), '#00c800') + self.assertEqual(classes[0].color.name(), "#c80000") + self.assertEqual(classes[1].color.name(), "#b21600") + self.assertEqual(classes[2].color.name(), "#9c2c00") + self.assertIn(classes[3].color.name(), ("#854200", "#854300")) + self.assertEqual(classes[4].color.name(), "#6f5900") + self.assertEqual(classes[5].color.name(), "#596f00") + self.assertIn(classes[6].color.name(), ("#428500", "#438500")) + self.assertEqual(classes[7].color.name(), "#2c9c00") + self.assertEqual(classes[8].color.name(), "#16b200") + self.assertEqual(classes[9].color.name(), "#00c800") # 30 class layer - path = os.path.join(unitTestDataPath('raster'), - 'unique_1.tif') + path = os.path.join(unitTestDataPath("raster"), "unique_1.tif") info = QFileInfo(path) base_name = info.baseName() layer10 = QgsRasterLayer(path, base_name) - classes = QgsPalettedRasterRenderer.classDataFromRaster(layer10.dataProvider(), 1) + classes = QgsPalettedRasterRenderer.classDataFromRaster( + layer10.dataProvider(), 1 + ) self.assertEqual(len(classes), 30) - expected = [11, 21, 22, 24, 31, 82, 2002, 2004, 2014, 2019, 2027, 2029, 2030, 2080, 2081, 2082, 2088, 2092, - 2097, 2098, 2099, 2105, 2108, 2110, 2114, 2118, 2126, 2152, 2184, 2220] + expected = [ + 11, + 21, + 22, + 24, + 31, + 82, + 2002, + 2004, + 2014, + 2019, + 2027, + 2029, + 2030, + 2080, + 2081, + 2082, + 2088, + 2092, + 2097, + 2098, + 2099, + 2105, + 2108, + 2110, + 2114, + 2118, + 2126, + 2152, + 2184, + 2220, + ] self.assertEqual([c.value for c in classes], expected) # bad layer - path = os.path.join(unitTestDataPath('raster'), - 'hub13263.vrt') + path = os.path.join(unitTestDataPath("raster"), "hub13263.vrt") info = QFileInfo(path) base_name = info.baseName() layer = QgsRasterLayer(path, base_name) @@ -455,18 +524,22 @@ def testPalettedClassDataFromLayer(self): self.assertFalse(classes) def testPalettedRendererWithNegativeColorValue(self): - """ test paletted raster renderer with negative values in color table""" + """test paletted raster renderer with negative values in color table""" - path = os.path.join(unitTestDataPath('raster'), - 'hub13263.vrt') + path = os.path.join(unitTestDataPath("raster"), "hub13263.vrt") info = QFileInfo(path) base_name = info.baseName() layer = QgsRasterLayer(path, base_name) - self.assertTrue(layer.isValid(), f'Raster not loaded: {path}') - - renderer = QgsPalettedRasterRenderer(layer.dataProvider(), 1, - [QgsPalettedRasterRenderer.Class(-1, QColor(0, 255, 0), 'class 2'), - QgsPalettedRasterRenderer.Class(3, QColor(255, 0, 0), 'class 1')]) + self.assertTrue(layer.isValid(), f"Raster not loaded: {path}") + + renderer = QgsPalettedRasterRenderer( + layer.dataProvider(), + 1, + [ + QgsPalettedRasterRenderer.Class(-1, QColor(0, 255, 0), "class 2"), + QgsPalettedRasterRenderer.Class(3, QColor(255, 0, 0), "class 1"), + ], + ) self.assertEqual(renderer.nColors(), 2) self.assertEqual(renderer.usesBands(), [1]) @@ -475,10 +548,10 @@ def testPalettedRendererWithFloats(self): """Tests for https://github.com/qgis/QGIS/issues/39058""" tempdir = QTemporaryDir() - temppath = os.path.join(tempdir.path(), 'paletted.tif') + temppath = os.path.join(tempdir.path(), "paletted.tif") # Create a float raster with unique values up to 65536 + one extra row - driver = gdal.GetDriverByName('GTiff') + driver = gdal.GetDriverByName("GTiff") outRaster = driver.Create(temppath, 256, 256 + 1, 1, gdal.GDT_Float32) outband = outRaster.GetRasterBand(1) data = [] @@ -490,7 +563,7 @@ def testPalettedRendererWithFloats(self): outRaster.FlushCache() del outRaster - layer = QgsRasterLayer(temppath, 'paletted') + layer = QgsRasterLayer(temppath, "paletted") self.assertTrue(layer.isValid()) self.assertEqual(layer.dataProvider().dataType(1), Qgis.DataType.Float32) classes = QgsPalettedRasterRenderer.classDataFromRaster(layer.dataProvider(), 1) @@ -502,5 +575,5 @@ def testPalettedRendererWithFloats(self): self.assertEqual(sorted(class_values), list(range(65536))) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspallabeling_base.py b/tests/src/python/test_qgspallabeling_base.py index 8e0cae8acf80..c19e46cf2742 100644 --- a/tests/src/python/test_qgspallabeling_base.py +++ b/tests/src/python/test_qgspallabeling_base.py @@ -10,10 +10,9 @@ (at your option) any later version. """ - -__author__ = 'Larry Shaffer' -__date__ = '07/09/2013' -__copyright__ = 'Copyright 2013, The QGIS Project' +__author__ = "Larry Shaffer" +__date__ = "07/09/2013" +__copyright__ = "Copyright 2013, The QGIS Project" import os import sys @@ -49,14 +48,16 @@ unitTestDataPath, ) -start_app(sys.platform != 'darwin') # No cleanup on mac os x, it crashes the pallabelingcanvas test on exit +start_app( + sys.platform != "darwin" +) # No cleanup on mac os x, it crashes the pallabelingcanvas test on exit FONTSLOADED = loadTestFonts() # noinspection PyPep8Naming,PyShadowingNames class TestQgsPalLabeling(QgisTestCase): - _PalDataDir = os.path.join(unitTestDataPath(), 'labeling') + _PalDataDir = os.path.join(unitTestDataPath(), "labeling") _TestFont = getTestFont() # Roman at 12 pt """:type: QFont""" _MapRegistry = None @@ -70,12 +71,12 @@ def setUpClass(cls): """Run before all tests""" super().setUpClass() - cls._TestFunction = '' - cls._TestGroup = '' - cls._TestGroupPrefix = '' - cls._TestGroupAbbr = '' - cls._TestGroupCanvasAbbr = '' - cls._TestImage = '' + cls._TestFunction = "" + cls._TestGroup = "" + cls._TestGroupPrefix = "" + cls._TestGroupAbbr = "" + cls._TestGroupCanvasAbbr = "" + cls._TestImage = "" cls._TestMapSettings = None cls._Mismatch = 0 cls._Mismatches = dict() @@ -101,7 +102,9 @@ def setUp(self): def setDefaultEngineSettings(cls): """Restore default settings for pal labeling""" settings = QgsLabelingEngineSettings() - settings.setPlacementVersion(QgsLabelingEngineSettings.PlacementEngineVersion.PlacementEngineVersion2) + settings.setPlacementVersion( + QgsLabelingEngineSettings.PlacementEngineVersion.PlacementEngineVersion2 + ) cls._MapSettings.setLabelingEngineSettings(settings) @classmethod @@ -132,11 +135,11 @@ def loadFeatureLayer(cls, table, chk=False): options = QgsVectorLayer.LayerOptions() options.forceReadOnly = True vlayer = QgsVectorLayer( - f'{cls._PalDataDir}/{table}.geojson', table, 'ogr', options) + f"{cls._PalDataDir}/{table}.geojson", table, "ogr", options + ) assert vlayer.isValid() # .qml should contain only style for symbology - vlayer.loadNamedStyle(os.path.join(cls._PalDataDir, - f'{table}.qml')) + vlayer.loadNamedStyle(os.path.join(cls._PalDataDir, f"{table}.qml")) # qDebug('render_lyr = {0}'.format(repr(vlayer))) cls._MapRegistry.addMapLayer(vlayer) # place new layer on top of render stack @@ -155,7 +158,8 @@ def aoiExtent(cls): options = QgsVectorLayer.LayerOptions() options.forceReadOnly = True aoilayer = QgsVectorLayer( - f'{cls._PalDataDir}/aoi.geojson', 'aoi', 'ogr', options) + f"{cls._PalDataDir}/aoi.geojson", "aoi", "ogr", options + ) assert aoilayer.isValid() return aoilayer.extent() @@ -166,7 +170,7 @@ def getBaseMapSettings(cls): """ ms = QgsMapSettings() # default for labeling test data: WGS 84 / UTM zone 13N - crs = QgsCoordinateReferenceSystem('epsg:32613') + crs = QgsCoordinateReferenceSystem("epsg:32613") ms.setBackgroundColor(QColor(152, 219, 249)) ms.setOutputSize(QSize(420, 280)) ms.setOutputDpi(72) @@ -202,7 +206,7 @@ def configTest(self, prefix, abbr): # insert test's Class.function marker into debug output stream # this helps visually track down the start of a test's debug output - testid = self.id().split('.') + testid = self.id().split(".") self._TestGroup = testid[1] self._TestFunction = testid[2] @@ -211,13 +215,13 @@ def configTest(self, prefix, abbr): def defaultLayerSettings(self): lyr = QgsPalLayerSettings() - lyr.fieldName = 'text' # default in test data sources + lyr.fieldName = "text" # default in test data sources font = self.getTestFont() font.setPointSize(32) format = QgsTextFormat() format.setFont(font) format.setColor(QColor(0, 0, 0)) - format.setNamedStyle('Roman') + format.setNamedStyle("Roman") format.setSize(32) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.buffer().setJoinStyle(Qt.PenJoinStyle.BevelJoin) @@ -237,7 +241,14 @@ def settingsDict(lyr): for attr in dir(lyr): if attr[0].islower() and not attr.startswith("__"): value = getattr(lyr, attr) - if isinstance(value, (QgsGeometry, QgsStringReplacementCollection, QgsCoordinateTransform)): + if isinstance( + value, + ( + QgsGeometry, + QgsStringReplacementCollection, + QgsCoordinateTransform, + ), + ): continue # ignore these objects if not isinstance(value, Callable): res[attr] = value @@ -248,10 +259,10 @@ def checkTest(self, **kwargs): pass def testSplitToLines(self): - self.assertEqual(QgsPalLabeling.splitToLines('', ''), ['']) - self.assertEqual(QgsPalLabeling.splitToLines('abc def', ''), ['abc def']) - self.assertEqual(QgsPalLabeling.splitToLines('abc def', ' '), ['abc', 'def']) - self.assertEqual(QgsPalLabeling.splitToLines('abc\ndef', ' '), ['abc', 'def']) + self.assertEqual(QgsPalLabeling.splitToLines("", ""), [""]) + self.assertEqual(QgsPalLabeling.splitToLines("abc def", ""), ["abc def"]) + self.assertEqual(QgsPalLabeling.splitToLines("abc def", " "), ["abc", "def"]) + self.assertEqual(QgsPalLabeling.splitToLines("abc\ndef", " "), ["abc", "def"]) class TestPALConfig(TestQgsPalLabeling): @@ -260,7 +271,7 @@ class TestPALConfig(TestQgsPalLabeling): def setUpClass(cls): TestQgsPalLabeling.setUpClass() - cls.layer = TestQgsPalLabeling.loadFeatureLayer('point') + cls.layer = TestQgsPalLabeling.loadFeatureLayer("point") @classmethod def tearDownClass(cls): @@ -269,7 +280,7 @@ def tearDownClass(cls): def setUp(self): """Run before each test.""" - self.configTest('pal_base', 'base') + self.configTest("pal_base", "base") def tearDown(self): """Run after each test.""" @@ -277,9 +288,9 @@ def tearDown(self): def test_default_pal_disabled(self): # Verify PAL labeling is disabled for layer by default - palset = self.layer.customProperty('labeling', '') - msg = f'\nExpected: Empty string\nGot: {palset}' - self.assertEqual(palset, '', msg) + palset = self.layer.customProperty("labeling", "") + msg = f"\nExpected: Empty string\nGot: {palset}" + self.assertEqual(palset, "", msg) def test_settings_no_labeling(self): self.layer.setLabeling(None) @@ -289,11 +300,11 @@ def test_layer_pal_activated(self): # Verify, via engine, that PAL labeling can be activated for layer lyr = self.defaultLayerSettings() self.layer.setLabeling(QgsVectorLayerSimpleLabeling(lyr)) - msg = '\nLayer labeling not activated, as reported by labelingEngine' + msg = "\nLayer labeling not activated, as reported by labelingEngine" self.assertTrue(QgsPalLabeling.staticWillUseLayer(self.layer), msg) # also test for vector tile layer - tile_layer = QgsVectorTileLayer('x', 'y') + tile_layer = QgsVectorTileLayer("x", "y") self.assertFalse(QgsPalLabeling.staticWillUseLayer(tile_layer)) st = QgsVectorTileBasicLabelingStyle() @@ -319,25 +330,39 @@ def test_write_read_settings(self): lyr2dict = self.settingsDict(lyr2) # print(lyr2dict) - msg = '\nLayer settings read not same as settings written' + msg = "\nLayer settings read not same as settings written" self.assertDictEqual(lyr1dict, lyr2dict, msg) def test_default_partials_labels_enabled(self): # Verify ShowingPartialsLabels is enabled for PAL by default engine_settings = QgsLabelingEngineSettings() - self.assertTrue(engine_settings.testFlag(QgsLabelingEngineSettings.Flag.UsePartialCandidates)) + self.assertTrue( + engine_settings.testFlag( + QgsLabelingEngineSettings.Flag.UsePartialCandidates + ) + ) def test_partials_labels_activate(self): engine_settings = QgsLabelingEngineSettings() # Enable partials labels engine_settings.setFlag(QgsLabelingEngineSettings.Flag.UsePartialCandidates) - self.assertTrue(engine_settings.testFlag(QgsLabelingEngineSettings.Flag.UsePartialCandidates)) + self.assertTrue( + engine_settings.testFlag( + QgsLabelingEngineSettings.Flag.UsePartialCandidates + ) + ) def test_partials_labels_deactivate(self): engine_settings = QgsLabelingEngineSettings() # Disable partials labels - engine_settings.setFlag(QgsLabelingEngineSettings.Flag.UsePartialCandidates, False) - self.assertFalse(engine_settings.testFlag(QgsLabelingEngineSettings.Flag.UsePartialCandidates)) + engine_settings.setFlag( + QgsLabelingEngineSettings.Flag.UsePartialCandidates, False + ) + self.assertFalse( + engine_settings.testFlag( + QgsLabelingEngineSettings.Flag.UsePartialCandidates + ) + ) # noinspection PyPep8Naming,PyShadowingNames @@ -345,26 +370,25 @@ def runSuite(module, tests): """This allows for a list of test names to be selectively run. Also, ensures unittest verbose output comes at end, after debug output""" loader = unittest.defaultTestLoader - if 'PAL_SUITE' in os.environ: + if "PAL_SUITE" in os.environ: if tests: suite = loader.loadTestsFromNames(tests, module) else: raise Exception( - "\n\n####__ 'PAL_SUITE' set, but no tests specified __####\n") + "\n\n####__ 'PAL_SUITE' set, but no tests specified __####\n" + ) else: suite = loader.loadTestsFromModule(module) - verb = 2 if 'PAL_VERBOSE' in os.environ else 0 + verb = 2 if "PAL_VERBOSE" in os.environ else 0 res = unittest.TextTestRunner(verbosity=verb).run(suite) return res -if __name__ == '__main__': +if __name__ == "__main__": # NOTE: unless PAL_SUITE env var is set all test class methods will be run # ex: 'TestGroup(Point|Line|Curved|Polygon|Feature).test_method' - suite = [ - 'TestPALConfig.test_write_read_settings' - ] + suite = ["TestPALConfig.test_write_read_settings"] res = runSuite(sys.modules[__name__], suite) sys.exit(not res.wasSuccessful()) diff --git a/tests/src/python/test_qgspallabeling_canvas.py b/tests/src/python/test_qgspallabeling_canvas.py index 626d51a141e8..8e347c470421 100644 --- a/tests/src/python/test_qgspallabeling_canvas.py +++ b/tests/src/python/test_qgspallabeling_canvas.py @@ -10,9 +10,9 @@ (at your option) any later version. """ -__author__ = 'Larry Shaffer' -__date__ = '07/09/2013' -__copyright__ = 'Copyright 2013, The QGIS Project' +__author__ = "Larry Shaffer" +__date__ = "07/09/2013" +__copyright__ = "Copyright 2013, The QGIS Project" import sys @@ -59,7 +59,7 @@ def checkTest(self, **kwargs): self._Test, color_tolerance=0, allowed_mismatch=0, - control_path_prefix='expected_' + self._TestGroupPrefix + control_path_prefix="expected_" + self._TestGroupPrefix, ) ) @@ -69,7 +69,7 @@ class TestCanvasBasePoint(TestCanvasBase): @classmethod def setUpClass(cls): TestCanvasBase.setUpClass() - cls.layer = TestQgsPalLabeling.loadFeatureLayer('point') + cls.layer = TestQgsPalLabeling.loadFeatureLayer("point") class TestCanvasPoint(TestCanvasBasePoint, TestPointBase): @@ -77,7 +77,7 @@ class TestCanvasPoint(TestCanvasBasePoint, TestPointBase): def setUp(self): """Run before each test.""" super().setUp() - self.configTest('pal_canvas', 'sp') + self.configTest("pal_canvas", "sp") class TestCanvasBaseLine(TestCanvasBase): @@ -85,7 +85,7 @@ class TestCanvasBaseLine(TestCanvasBase): @classmethod def setUpClass(cls): TestCanvasBase.setUpClass() - cls.layer = TestQgsPalLabeling.loadFeatureLayer('line') + cls.layer = TestQgsPalLabeling.loadFeatureLayer("line") class TestCanvasLine(TestCanvasBaseLine, TestLineBase): @@ -93,14 +93,12 @@ class TestCanvasLine(TestCanvasBaseLine, TestLineBase): def setUp(self): """Run before each test.""" super().setUp() - self.configTest('pal_canvas_line', 'sp') + self.configTest("pal_canvas_line", "sp") -if __name__ == '__main__': +if __name__ == "__main__": # NOTE: unless PAL_SUITE env var is set all test class methods will be run # SEE: test_qgspallabeling_tests.suiteTests() to define suite - suite = ( - ['TestCanvasPoint.' + t for t in suiteTests()['sp_suite']] - ) + suite = ["TestCanvasPoint." + t for t in suiteTests()["sp_suite"]] res = runSuite(sys.modules[__name__], suite) sys.exit(not res.wasSuccessful()) diff --git a/tests/src/python/test_qgspallabeling_layout.py b/tests/src/python/test_qgspallabeling_layout.py index 374ecc806eab..37b3f5ed9aba 100644 --- a/tests/src/python/test_qgspallabeling_layout.py +++ b/tests/src/python/test_qgspallabeling_layout.py @@ -10,9 +10,9 @@ (at your option) any later version. """ -__author__ = 'Larry Shaffer' -__date__ = '2014/02/21' -__copyright__ = 'Copyright 2013, The QGIS Project' +__author__ = "Larry Shaffer" +__date__ = "2014/02/21" +__copyright__ = "Copyright 2013, The QGIS Project" import os import subprocess @@ -43,7 +43,7 @@ # * Poppler w/o Cairo does not always correctly render vectors in PDF to image # * muPDF renders correctly, but slightly shifts colors for util in [ - 'pdftocairo', + "pdftocairo", # 'mudraw', ]: PDFUTIL = getExecutablePath(util) @@ -52,13 +52,14 @@ # noinspection PyUnboundLocalVariable if not PDFUTIL: - raise Exception('PDF-to-image utility not found on PATH: ' - 'install Poppler (with Cairo)') + raise Exception( + "PDF-to-image utility not found on PATH: " "install Poppler (with Cairo)" + ) # output kind enum # noinspection PyClassHasNoInit -class OutputKind(): +class OutputKind: Img, Svg, Pdf = list(range(3)) @@ -73,9 +74,9 @@ def setUpClass(cls): if not cls._BaseSetup: TestQgsPalLabeling.setUpClass() # the blue background (set via layer style) to match renderchecker's - TestQgsPalLabeling.loadFeatureLayer('background', True) + TestQgsPalLabeling.loadFeatureLayer("background", True) cls._TestKind = 0 # OutputKind.(Img|Svg|Pdf) - cls._test_base_name = '' + cls._test_base_name = "" @classmethod def tearDownClass(cls): @@ -112,7 +113,10 @@ def _set_up_composition(self, width, height, dpi, engine_settings): """:type: QgsLayoutItemMap""" self._cmap.setFrameEnabled(False) self._cmap.setLayers(self._TestMapSettings.layers()) - if self._TestMapSettings.labelingEngineSettings().flags() & QgsLabelingEngineSettings.Flag.UsePartialCandidates: + if ( + self._TestMapSettings.labelingEngineSettings().flags() + & QgsLabelingEngineSettings.Flag.UsePartialCandidates + ): self._cmap.setMapFlags(QgsLayoutItemMap.MapItemFlag.ShowPartialLabels) self._c.addLayoutItem(self._cmap) # now expand map to fill page and set its extent @@ -124,8 +128,7 @@ def _set_up_composition(self, width, height, dpi, engine_settings): # noinspection PyUnusedLocal def _get_layout_image(self, width, height, dpi): - image = QImage(QSize(width, height), - self._TestMapSettings.outputImageFormat()) + image = QImage(QSize(width, height), self._TestMapSettings.outputImageFormat()) image.fill(QColor(152, 219, 249).rgb()) image.setDotsPerMeterX(int(dpi / 25.4 * 1000)) image.setDotsPerMeterY(int(dpi / 25.4 * 1000)) @@ -133,7 +136,7 @@ def _get_layout_image(self, width, height, dpi): p = QPainter(image) p.setRenderHint( QPainter.RenderHint.Antialiasing, - self._TestMapSettings.testFlag(QgsMapSettings.Flag.Antialiasing) + self._TestMapSettings.testFlag(QgsMapSettings.Flag.Antialiasing), ) exporter = QgsLayoutExporter(self._c) exporter.renderPage(p, 0) @@ -145,7 +148,7 @@ def _get_layout_image(self, width, height, dpi): return image def _get_layout_svg_image(self, width, height, dpi): - svgpath = getTempfilePath('svg') + svgpath = getTempfilePath("svg") temp_size = os.path.getsize(svgpath) svg_g = QSvgGenerator() @@ -162,7 +165,7 @@ def _get_layout_svg_image(self, width, height, dpi): sp.end() if temp_size == os.path.getsize(svgpath): - return False, '' + return False, "" image = QImage(width, height, self._TestMapSettings.outputImageFormat()) image.fill(QColor(152, 219, 249).rgb()) @@ -173,7 +176,7 @@ def _get_layout_svg_image(self, width, height, dpi): p = QPainter(image) p.setRenderHint( QPainter.RenderHint.Antialiasing, - self._TestMapSettings.testFlag(QgsMapSettings.Flag.Antialiasing) + self._TestMapSettings.testFlag(QgsMapSettings.Flag.Antialiasing), ) p.setRenderHint(QPainter.RenderHint.TextAntialiasing) svgr.render(p) @@ -182,7 +185,7 @@ def _get_layout_svg_image(self, width, height, dpi): return image def _get_layout_pdf_image(self, width, height, dpi): - pdfpath = getTempfilePath('pdf') + pdfpath = getTempfilePath("pdf") temp_size = os.path.getsize(pdfpath) exporter = QgsLayoutExporter(self._c) @@ -191,32 +194,53 @@ def _get_layout_pdf_image(self, width, height, dpi): exporter.exportToPdf(pdfpath, settings) if temp_size == os.path.getsize(pdfpath): - return False, '' + return False, "" - filepath = getTempfilePath('png') + filepath = getTempfilePath("png") # Poppler (pdftocairo or pdftoppm): # PDFUTIL -png -singlefile -r 72 -x 0 -y 0 -W 420 -H 280 in.pdf pngbase # muPDF (mudraw): # PDFUTIL -c rgb[a] -r 72 -w 420 -h 280 -o out.png in.pdf - if PDFUTIL.strip().endswith('pdftocairo'): + if PDFUTIL.strip().endswith("pdftocairo"): filebase = os.path.join( os.path.dirname(filepath), - os.path.splitext(os.path.basename(filepath))[0] + os.path.splitext(os.path.basename(filepath))[0], ) call = [ - PDFUTIL, '-png', '-singlefile', '-r', str(dpi), - '-x', '0', '-y', '0', '-W', str(width), '-H', str(height), - pdfpath, filebase + PDFUTIL, + "-png", + "-singlefile", + "-r", + str(dpi), + "-x", + "0", + "-y", + "0", + "-W", + str(width), + "-H", + str(height), + pdfpath, + filebase, ] - elif PDFUTIL.strip().endswith('mudraw'): + elif PDFUTIL.strip().endswith("mudraw"): call = [ - PDFUTIL, '-c', 'rgba', - '-r', str(dpi), '-w', str(width), '-h', str(height), + PDFUTIL, + "-c", + "rgba", + "-r", + str(dpi), + "-w", + str(width), + "-h", + str(height), # '-b', '8', - '-o', filepath, pdfpath + "-o", + filepath, + pdfpath, ] else: - return False, '' + return False, "" qDebug(f"_get_layout_pdf_image call: {' '.join(call)}") res = False @@ -224,14 +248,16 @@ def _get_layout_pdf_image(self, width, height, dpi): subprocess.check_call(call) res = True except subprocess.CalledProcessError as e: - qDebug("_get_layout_pdf_image failed!\n" - "cmd: {}\n" - "returncode: {}\n" - "message: {}".format(e.cmd, e.returncode, e.message)) + qDebug( + "_get_layout_pdf_image failed!\n" + "cmd: {}\n" + "returncode: {}\n" + "message: {}".format(e.cmd, e.returncode, e.message) + ) if not res: os.unlink(filepath) - filepath = '' + filepath = "" return QImage(filepath) @@ -255,13 +281,13 @@ def checkTest(self, **kwargs): self.assertTrue( self.image_check( - f'{self._test_base_name}{self._TestGroupPrefix}_{self._Test}', + f"{self._test_base_name}{self._TestGroupPrefix}_{self._Test}", self._Test, image, self._Test, color_tolerance=0, allowed_mismatch=0, - control_path_prefix='expected_' + self._TestGroupPrefix + control_path_prefix="expected_" + self._TestGroupPrefix, ) ) @@ -271,7 +297,7 @@ class TestLayoutPointBase(TestLayoutBase): @classmethod def setUpClass(cls): TestLayoutBase.setUpClass() - cls.layer = TestQgsPalLabeling.loadFeatureLayer('point') + cls.layer = TestQgsPalLabeling.loadFeatureLayer("point") class TestLayoutImagePoint(TestLayoutPointBase, TestPointBase): @@ -280,8 +306,8 @@ def setUp(self): """Run before each test.""" super().setUp() self._TestKind = OutputKind.Img - self._test_base_name = 'layout_image' - self.configTest('pal_composer', 'sp_img') + self._test_base_name = "layout_image" + self.configTest("pal_composer", "sp_img") class TestLayoutImageVsCanvasPoint(TestLayoutPointBase, TestPointBase): @@ -290,8 +316,8 @@ def setUp(self): """Run before each test.""" super().setUp() self._TestKind = OutputKind.Img - self._test_base_name = 'layout_image_v_canvas' - self.configTest('pal_canvas', 'sp') + self._test_base_name = "layout_image_v_canvas" + self.configTest("pal_canvas", "sp") class TestLayoutSvgPoint(TestLayoutPointBase, TestPointBase): @@ -300,12 +326,11 @@ def setUp(self): """Run before each test.""" super().setUp() self._TestKind = OutputKind.Svg - self._test_base_name = 'layout_svg' - self.configTest('pal_composer', 'sp_svg') + self._test_base_name = "layout_svg" + self.configTest("pal_composer", "sp_svg") class TestLayoutSvgVsLayoutPoint(TestLayoutPointBase, TestPointBase): - """ Compare only to layout image, which is already compared to canvas point """ @@ -314,8 +339,8 @@ def setUp(self): """Run before each test.""" super().setUp() self._TestKind = OutputKind.Svg - self._test_base_name = 'layout_svg_v_img' - self.configTest('pal_composer', 'sp_img') + self._test_base_name = "layout_svg_v_img" + self.configTest("pal_composer", "sp_img") class TestLayoutPdfPoint(TestLayoutPointBase, TestPointBase): @@ -323,13 +348,12 @@ class TestLayoutPdfPoint(TestLayoutPointBase, TestPointBase): def setUp(self): """Run before each test.""" super().setUp() - self._test_base_name = 'layout_pdf' + self._test_base_name = "layout_pdf" self._TestKind = OutputKind.Pdf - self.configTest('pal_composer', 'sp_pdf') + self.configTest("pal_composer", "sp_pdf") class TestLayoutPdfVsLayoutPoint(TestLayoutPointBase, TestPointBase): - """ Compare only to layout image, which is already compared to canvas point """ @@ -337,9 +361,9 @@ class TestLayoutPdfVsLayoutPoint(TestLayoutPointBase, TestPointBase): def setUp(self): """Run before each test.""" super().setUp() - self._test_base_name = 'layout_pdf_v_img' + self._test_base_name = "layout_pdf_v_img" self._TestKind = OutputKind.Pdf - self.configTest('pal_composer', 'sp_img') + self.configTest("pal_composer", "sp_img") class TestLayoutLineBase(TestLayoutBase): @@ -347,7 +371,7 @@ class TestLayoutLineBase(TestLayoutBase): @classmethod def setUpClass(cls): TestLayoutBase.setUpClass() - cls.layer = TestQgsPalLabeling.loadFeatureLayer('line') + cls.layer = TestQgsPalLabeling.loadFeatureLayer("line") class TestLayoutImageLine(TestLayoutLineBase, TestLineBase): @@ -355,9 +379,9 @@ class TestLayoutImageLine(TestLayoutLineBase, TestLineBase): def setUp(self): """Run before each test.""" super().setUp() - self._test_base_name = 'layout_img' + self._test_base_name = "layout_img" self._TestKind = OutputKind.Img - self.configTest('pal_composer_line', 'sp_img') + self.configTest("pal_composer_line", "sp_img") class TestLayoutImageVsCanvasLine(TestLayoutLineBase, TestLineBase): @@ -365,9 +389,9 @@ class TestLayoutImageVsCanvasLine(TestLayoutLineBase, TestLineBase): def setUp(self): """Run before each test.""" super().setUp() - self._test_base_name = 'layout_img_v_canvas' + self._test_base_name = "layout_img_v_canvas" self._TestKind = OutputKind.Img - self.configTest('pal_canvas_line', 'sp') + self.configTest("pal_canvas_line", "sp") class TestLayoutSvgLine(TestLayoutLineBase, TestLineBase): @@ -375,13 +399,12 @@ class TestLayoutSvgLine(TestLayoutLineBase, TestLineBase): def setUp(self): """Run before each test.""" super().setUp() - self._test_base_name = 'layout_svg' + self._test_base_name = "layout_svg" self._TestKind = OutputKind.Svg - self.configTest('pal_composer_line', 'sp_svg') + self.configTest("pal_composer_line", "sp_svg") class TestLayoutSvgVsLayoutLine(TestLayoutLineBase, TestLineBase): - """ Compare only to layout image, which is already compared to canvas line """ @@ -389,9 +412,9 @@ class TestLayoutSvgVsLayoutLine(TestLayoutLineBase, TestLineBase): def setUp(self): """Run before each test.""" super().setUp() - self._test_base_name = 'layout_svg_v_img' + self._test_base_name = "layout_svg_v_img" self._TestKind = OutputKind.Svg - self.configTest('pal_composer_line', 'sp_img') + self.configTest("pal_composer_line", "sp_img") class TestLayoutPdfLine(TestLayoutLineBase, TestLineBase): @@ -399,13 +422,12 @@ class TestLayoutPdfLine(TestLayoutLineBase, TestLineBase): def setUp(self): """Run before each test.""" super().setUp() - self._test_base_name = 'layout_pdf' + self._test_base_name = "layout_pdf" self._TestKind = OutputKind.Pdf - self.configTest('pal_composer_line', 'sp_pdf') + self.configTest("pal_composer_line", "sp_pdf") class TestLayoutPdfVsLayoutLine(TestLayoutLineBase, TestLineBase): - """ Compare only to layout image, which is already compared to canvas line """ @@ -414,20 +436,20 @@ def setUp(self): """Run before each test.""" super().setUp() self._TestKind = OutputKind.Pdf - self._test_base_name = 'layout_pdf_v_img' - self.configTest('pal_composer_line', 'sp_img') + self._test_base_name = "layout_pdf_v_img" + self.configTest("pal_composer_line", "sp_img") -if __name__ == '__main__': +if __name__ == "__main__": # NOTE: unless PAL_SUITE env var is set all test class methods will be run # SEE: test_qgspallabeling_tests.suiteTests() to define suite st = suiteTests() - sp_i = ['TestLayoutImagePoint.' + t for t in st['sp_suite']] - sp_ivs = ['TestLayoutImageVsCanvasPoint.' + t for t in st['sp_vs_suite']] - sp_s = ['TestLayoutSvgPoint.' + t for t in st['sp_suite']] - sp_svs = ['TestLayoutSvgVsLayoutPoint.' + t for t in st['sp_vs_suite']] - sp_p = ['TestLayoutPdfPoint.' + t for t in st['sp_suite']] - sp_pvs = ['TestLayoutPdfVsLayoutPoint.' + t for t in st['sp_vs_suite']] + sp_i = ["TestLayoutImagePoint." + t for t in st["sp_suite"]] + sp_ivs = ["TestLayoutImageVsCanvasPoint." + t for t in st["sp_vs_suite"]] + sp_s = ["TestLayoutSvgPoint." + t for t in st["sp_suite"]] + sp_svs = ["TestLayoutSvgVsLayoutPoint." + t for t in st["sp_vs_suite"]] + sp_p = ["TestLayoutPdfPoint." + t for t in st["sp_suite"]] + sp_pvs = ["TestLayoutPdfVsLayoutPoint." + t for t in st["sp_vs_suite"]] suite = [] # extended separately for finer control of PAL_SUITE (comment-out undesired) diff --git a/tests/src/python/test_qgspallabeling_placement.py b/tests/src/python/test_qgspallabeling_placement.py index 0b3181ef50c5..5b09ecd2d73d 100644 --- a/tests/src/python/test_qgspallabeling_placement.py +++ b/tests/src/python/test_qgspallabeling_placement.py @@ -9,9 +9,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2015-08-24' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2015-08-24" +__copyright__ = "Copyright 2015, The QGIS Project" import sys @@ -28,7 +29,7 @@ QgsLabelingEngineRuleMinimumDistanceLabelToFeature, QgsLabelingEngineRuleMaximumDistanceLabelToFeature, QgsLabelingEngineRuleAvoidLabelOverlapWithFeature, - QgsLabelingEngineRuleMinimumDistanceLabelToLabel + QgsLabelingEngineRuleMinimumDistanceLabelToLabel, ) from test_qgspallabeling_base import TestQgsPalLabeling, runSuite @@ -46,16 +47,18 @@ def setUp(self): """Run before each test.""" super().setUp() self.removeAllLayers() - self.configTest('pal_placement', 'sp') + self.configTest("pal_placement", "sp") # render only rectangles of the placed labels engine_settings = QgsLabelingEngineSettings() - engine_settings.setPlacementVersion(QgsLabelingEngineSettings.PlacementEngineVersion.PlacementEngineVersion2) + engine_settings.setPlacementVersion( + QgsLabelingEngineSettings.PlacementEngineVersion.PlacementEngineVersion2 + ) engine_settings.setFlag(QgsLabelingEngineSettings.Flag.DrawLabelRectOnly) self._MapSettings.setLabelingEngineSettings(engine_settings) def checkTest(self, **kwargs): - if kwargs.get('apply_simple_labeling', True): + if kwargs.get("apply_simple_labeling", True): self.layer.setLabeling(QgsVectorLayerSimpleLabeling(self.lyr)) ms = self._MapSettings # class settings @@ -70,10 +73,11 @@ def checkTest(self, **kwargs): self._Test, color_tolerance=0, allowed_mismatch=0, - control_path_prefix='expected_' + self._TestGroupPrefix + control_path_prefix="expected_" + self._TestGroupPrefix, ) ) + # noinspection PyPep8Naming @@ -86,7 +90,7 @@ def setUpClass(cls): def test_point_placement_around(self): # Default point label placement - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.checkTest() self.removeMapLayer(self.layer) @@ -94,7 +98,7 @@ def test_point_placement_around(self): def test_point_placement_around_obstacle(self): # Default point label placement with obstacle - self.layer = TestQgsPalLabeling.loadFeatureLayer('point2') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point2") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.checkTest() self.removeMapLayer(self.layer) @@ -102,8 +106,8 @@ def test_point_placement_around_obstacle(self): def test_point_placement_narrow_polygon_obstacle(self): # Default point label placement with narrow polygon obstacle - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') - polyLayer = TestQgsPalLabeling.loadFeatureLayer('narrow_polygon') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") + polyLayer = TestQgsPalLabeling.loadFeatureLayer("narrow_polygon") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.checkTest() self.removeMapLayer(self.layer) @@ -112,23 +116,20 @@ def test_point_placement_narrow_polygon_obstacle(self): def test_point_placement_around_obstacle_large_symbol(self): # Default point label placement with obstacle and large symbols - self.layer = TestQgsPalLabeling.loadFeatureLayer('point3') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point3") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.checkTest() self.removeMapLayer(self.layer) self.layer = None - def test_point_placement_around_max_distance_show_candidates( - self): + def test_point_placement_around_max_distance_show_candidates(self): """ Around point placement with max distance, showing candidates """ - self.layer = TestQgsPalLabeling.loadFeatureLayer('point3') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point3") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) label_settings = self._TestMapSettings.labelingEngineSettings() - label_settings.setFlag( - Qgis.LabelingFlag.DrawCandidates - ) + label_settings.setFlag(Qgis.LabelingFlag.DrawCandidates) label_settings.setMaximumLineCandidatesPerCm(1) self._TestMapSettings.setLabelingEngineSettings(label_settings) @@ -144,23 +145,22 @@ def test_point_placement_around_max_distance_show_candidates( self.removeMapLayer(self.layer) self.layer = None - def test_point_placement_around_no_max_distance( - self): + def test_point_placement_around_no_max_distance(self): """ Around point placement without max distance. In this case no label can be placed for the point """ - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') - poly_layer = TestQgsPalLabeling.loadFeatureLayer('polygon_with_bump') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") + poly_layer = TestQgsPalLabeling.loadFeatureLayer("polygon_with_bump") obstacle_label_settings = QgsPalLayerSettings() obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = 2 obstacle_label_settings.obstacleSettings().setType( - QgsLabelObstacleSettings.ObstacleType.PolygonInterior) - poly_layer.setLabeling( - QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + QgsLabelObstacleSettings.ObstacleType.PolygonInterior + ) + poly_layer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) poly_layer.setLabelsEnabled(True) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -179,24 +179,23 @@ def test_point_placement_around_no_max_distance( self.removeMapLayer(poly_layer) self.layer = None - def test_point_placement_around_max_distance( - self): + def test_point_placement_around_max_distance(self): """ Around point placement with max distance. In this case the label can be placed for the point at up to 80mm from the point """ - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') - poly_layer = TestQgsPalLabeling.loadFeatureLayer('polygon_with_bump') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") + poly_layer = TestQgsPalLabeling.loadFeatureLayer("polygon_with_bump") obstacle_label_settings = QgsPalLayerSettings() obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = 2 obstacle_label_settings.obstacleSettings().setType( - QgsLabelObstacleSettings.ObstacleType.PolygonInterior) - poly_layer.setLabeling( - QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + QgsLabelObstacleSettings.ObstacleType.PolygonInterior + ) + poly_layer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) poly_layer.setLabelsEnabled(True) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -215,17 +214,14 @@ def test_point_placement_around_max_distance( self.removeMapLayer(poly_layer) self.layer = None - def test_point_placement_cartographic_max_distance_show_candidates( - self): + def test_point_placement_cartographic_max_distance_show_candidates(self): """ Cartographic placement with max distance, showing candidates """ - self.layer = TestQgsPalLabeling.loadFeatureLayer('point3') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point3") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) label_settings = self._TestMapSettings.labelingEngineSettings() - label_settings.setFlag( - Qgis.LabelingFlag.DrawCandidates - ) + label_settings.setFlag(Qgis.LabelingFlag.DrawCandidates) label_settings.setMaximumLineCandidatesPerCm(1) self._TestMapSettings.setLabelingEngineSettings(label_settings) @@ -241,8 +237,7 @@ def test_point_placement_cartographic_max_distance_show_candidates( self.removeMapLayer(self.layer) self.layer = None - def test_point_placement_cartographic_no_max_distance_prefer_ordering( - self): + def test_point_placement_cartographic_no_max_distance_prefer_ordering(self): """ Cartographic placement without max distance, prefer ordering @@ -251,7 +246,7 @@ def test_point_placement_cartographic_no_max_distance_prefer_ordering( we are not allowing a maximum distance and accordingly the label cannot be placed in the preferred bottom left location. """ - self.layer = TestQgsPalLabeling.loadFeatureLayer('point3') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point3") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.fieldName = "'testing'" @@ -259,12 +254,14 @@ def test_point_placement_cartographic_no_max_distance_prefer_ordering( self.lyr.placement = Qgis.LabelPlacement.OrderedPositionsAroundPoint self.lyr.pointSettings().setMaximumDistance(0) self.lyr.pointSettings().setPredefinedPositionOrder( - [Qgis.LabelPredefinedPointPosition.BottomLeft, - Qgis.LabelPredefinedPointPosition.TopLeft, - ] + [ + Qgis.LabelPredefinedPointPosition.BottomLeft, + Qgis.LabelPredefinedPointPosition.TopLeft, + ] ) self.lyr.placementSettings().setPrioritization( - Qgis.LabelPrioritization.PreferPositionOrdering) + Qgis.LabelPrioritization.PreferPositionOrdering + ) f = self.lyr.format() f.setSize(30) self.lyr.setFormat(f) @@ -282,7 +279,7 @@ def test_point_placement_cartographic_max_distance_prefer_ordering(self): it means pushing it right out toward the maximum distance of 80mm from the point itself """ - self.layer = TestQgsPalLabeling.loadFeatureLayer('point3') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point3") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.fieldName = "'testing'" @@ -290,12 +287,14 @@ def test_point_placement_cartographic_max_distance_prefer_ordering(self): self.lyr.placement = Qgis.LabelPlacement.OrderedPositionsAroundPoint self.lyr.pointSettings().setMaximumDistance(80) self.lyr.pointSettings().setPredefinedPositionOrder( - [Qgis.LabelPredefinedPointPosition.BottomLeft, - Qgis.LabelPredefinedPointPosition.TopLeft, - ] + [ + Qgis.LabelPredefinedPointPosition.BottomLeft, + Qgis.LabelPredefinedPointPosition.TopLeft, + ] ) self.lyr.placementSettings().setPrioritization( - Qgis.LabelPrioritization.PreferPositionOrdering) + Qgis.LabelPrioritization.PreferPositionOrdering + ) f = self.lyr.format() f.setSize(30) self.lyr.setFormat(f) @@ -314,7 +313,7 @@ def test_point_placement_cartographic_max_distance_prefer_closer(self): bottom left mode. But we are using "prefer closer" prioritization, so the closer candidate (top left) should be used instead. """ - self.layer = TestQgsPalLabeling.loadFeatureLayer('point3') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point3") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.fieldName = "'testing'" @@ -322,12 +321,14 @@ def test_point_placement_cartographic_max_distance_prefer_closer(self): self.lyr.placement = Qgis.LabelPlacement.OrderedPositionsAroundPoint self.lyr.pointSettings().setMaximumDistance(80) self.lyr.pointSettings().setPredefinedPositionOrder( - [Qgis.LabelPredefinedPointPosition.BottomLeft, - Qgis.LabelPredefinedPointPosition.TopLeft, - ] + [ + Qgis.LabelPredefinedPointPosition.BottomLeft, + Qgis.LabelPredefinedPointPosition.TopLeft, + ] ) self.lyr.placementSettings().setPrioritization( - Qgis.LabelPrioritization.PreferCloser) + Qgis.LabelPrioritization.PreferCloser + ) f = self.lyr.format() f.setSize(30) self.lyr.setFormat(f) @@ -338,7 +339,7 @@ def test_point_placement_cartographic_max_distance_prefer_closer(self): def test_line_with_no_candidate_show_all(self): # A line too short to have any candidates, yet we need to show all labels for the layer - self.layer = TestQgsPalLabeling.loadFeatureLayer('line_short') + self.layer = TestQgsPalLabeling.loadFeatureLayer("line_short") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.layer.setLabelsEnabled(True) self.lyr.displayAll = True @@ -354,7 +355,7 @@ def test_polygon_placement_with_hole(self): # Note for this test, the mask is used to check only pixels outside of the polygon. # We don't care where in the polygon the label is, just that it # is INSIDE the polygon - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_with_hole') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_with_hole") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Horizontal self.checkTest() @@ -363,8 +364,8 @@ def test_polygon_placement_with_hole(self): def test_polygon_placement_with_hole_and_point(self): # Testing that hole from a feature is not treated as an obstacle for other feature's labels - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') - polyLayer = TestQgsPalLabeling.loadFeatureLayer('polygon_with_hole') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") + polyLayer = TestQgsPalLabeling.loadFeatureLayer("polygon_with_hole") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.checkTest() self.removeMapLayer(self.layer) @@ -373,8 +374,10 @@ def test_polygon_placement_with_hole_and_point(self): def test_polygon_placement_with_obstacle(self): # Horizontal label placement for polygon and a line obstacle - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_rect') - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('polygon_with_hole_line_obstacle') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_rect") + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer( + "polygon_with_hole_line_obstacle" + ) obstacle_label_settings = QgsPalLayerSettings() obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False @@ -393,7 +396,7 @@ def test_polygon_placement_bumps(self): # Horizontal label placement for polygon with bumps, checking that # labels are placed close to the pole of inaccessibility (max distance # to rings) - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_with_bump') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_with_bump") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Horizontal self.checkTest() @@ -406,7 +409,7 @@ def test_polygon_placement_small_bump(self): # when that position is far from the polygon's centroid # i.e. when label candidates have close-ish max distance to rings # then we pick the one closest to the polygon's centroid - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_small_bump') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_small_bump") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Horizontal self.checkTest() @@ -418,7 +421,7 @@ def test_polygon_multiple_labels(self): # Note for this test, the mask is used to check only pixels outside of the polygon. # We don't care where in the polygon the label is, just that it # is INSIDE the polygon - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_rule_based') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_rule_based") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.checkTest(apply_simple_labeling=False) self.removeMapLayer(self.layer) @@ -426,8 +429,8 @@ def test_polygon_multiple_labels(self): def test_multipolygon_obstacle(self): # Test that all parts of multipolygon are used as an obstacle - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') - polyLayer = TestQgsPalLabeling.loadFeatureLayer('multi_polygon') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") + polyLayer = TestQgsPalLabeling.loadFeatureLayer("multi_polygon") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.checkTest() self.removeMapLayer(self.layer) @@ -436,7 +439,7 @@ def test_multipolygon_obstacle(self): def test_point_offset_center_placement(self): # Test point offset from point, center placement - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OverPoint self.lyr.quadOffset = QgsPalLayerSettings.QuadrantPosition.QuadrantOver @@ -446,7 +449,7 @@ def test_point_offset_center_placement(self): def test_point_offset_below_left_placement(self): # Test point offset from point, below left placement - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OverPoint self.lyr.quadOffset = QgsPalLayerSettings.QuadrantPosition.QuadrantBelowLeft @@ -456,9 +459,9 @@ def test_point_offset_below_left_placement(self): def test_obstacle_collision_but_showing_all(self): # Test the when a collision occurs and the Show All labels setting is active, Show All wins - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('line') + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("line") obstacle_label_settings = QgsPalLayerSettings() obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False @@ -479,8 +482,8 @@ def test_obstacle_collision_but_showing_all(self): def test_point_point_obstacle_obstacle_factor_greater_equal(self): # Test point label but obstacle exists with a greater than obstacle factor vs label priority => NO LABEL - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_obstacle1') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("point_ordered_obstacle1") for label_priority in range(0, 11): for obstacle_weight in range(label_priority + 1, 11): @@ -488,14 +491,24 @@ def test_point_point_obstacle_obstacle_factor_greater_equal(self): obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = obstacle_weight * 0.2 - obstacleLayer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + obstacleLayer.setLabeling( + QgsVectorLayerSimpleLabeling(obstacle_label_settings) + ) obstacleLayer.setLabelsEnabled(True) - self.assertEqual(self._MapSettings.labelingEngineSettings().placementVersion(), QgsLabelingEngineSettings.PlacementEngineVersion.PlacementEngineVersion2) + self.assertEqual( + self._MapSettings.labelingEngineSettings().placementVersion(), + QgsLabelingEngineSettings.PlacementEngineVersion.PlacementEngineVersion2, + ) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) - self.assertEqual(self._TestMapSettings.labelingEngineSettings().placementVersion(), QgsLabelingEngineSettings.PlacementEngineVersion.PlacementEngineVersion2) + self.assertEqual( + self._TestMapSettings.labelingEngineSettings().placementVersion(), + QgsLabelingEngineSettings.PlacementEngineVersion.PlacementEngineVersion2, + ) self.lyr.placement = QgsPalLayerSettings.Placement.OverPoint - self.lyr.quadOffset = QgsPalLayerSettings.QuadrantPosition.QuadrantAboveRight + self.lyr.quadOffset = ( + QgsPalLayerSettings.QuadrantPosition.QuadrantAboveRight + ) self.lyr.priority = label_priority self.checkTest() self.removeMapLayer(obstacleLayer) @@ -504,8 +517,8 @@ def test_point_point_obstacle_obstacle_factor_greater_equal(self): def test_point_point_obstacle_obstacle_factor_less(self): # Test point label but obstacle exists with an equal or lower obstacle factor vs label priority => LABEL - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_obstacle1') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("point_ordered_obstacle1") for label_priority in range(0, 11): for obstacle_weight in range(0, label_priority + 1): @@ -513,12 +526,16 @@ def test_point_point_obstacle_obstacle_factor_less(self): obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = obstacle_weight * 0.2 - obstacleLayer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + obstacleLayer.setLabeling( + QgsVectorLayerSimpleLabeling(obstacle_label_settings) + ) obstacleLayer.setLabelsEnabled(True) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OverPoint - self.lyr.quadOffset = QgsPalLayerSettings.QuadrantPosition.QuadrantAboveRight + self.lyr.quadOffset = ( + QgsPalLayerSettings.QuadrantPosition.QuadrantAboveRight + ) self.lyr.priority = label_priority self.checkTest() self.removeMapLayer(obstacleLayer) @@ -527,8 +544,8 @@ def test_point_point_obstacle_obstacle_factor_less(self): def test_point_line_obstacle_obstacle_factor_greater_equal(self): # Test point label but line obstacle exists with a greater obstacle factor vs label priority => NO LABEL - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('line') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("line") for label_priority in range(0, 11): for obstacle_weight in range(label_priority + 1, 11): @@ -536,12 +553,16 @@ def test_point_line_obstacle_obstacle_factor_greater_equal(self): obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = obstacle_weight * 0.2 - obstacleLayer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + obstacleLayer.setLabeling( + QgsVectorLayerSimpleLabeling(obstacle_label_settings) + ) obstacleLayer.setLabelsEnabled(True) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OverPoint - self.lyr.quadOffset = QgsPalLayerSettings.QuadrantPosition.QuadrantAboveLeft + self.lyr.quadOffset = ( + QgsPalLayerSettings.QuadrantPosition.QuadrantAboveLeft + ) self.lyr.priority = label_priority self.checkTest() self.removeMapLayer(obstacleLayer) @@ -550,8 +571,8 @@ def test_point_line_obstacle_obstacle_factor_greater_equal(self): def test_point_line_obstacle_obstacle_factor_less(self): # Test point label but line obstacle exists with an equal or lower obstacle factor vs label priority => LABEL - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('line') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("line") for label_priority in range(0, 11): for obstacle_weight in range(0, label_priority + 1): @@ -559,12 +580,16 @@ def test_point_line_obstacle_obstacle_factor_less(self): obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = obstacle_weight * 0.2 - obstacleLayer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + obstacleLayer.setLabeling( + QgsVectorLayerSimpleLabeling(obstacle_label_settings) + ) obstacleLayer.setLabelsEnabled(True) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OverPoint - self.lyr.quadOffset = QgsPalLayerSettings.QuadrantPosition.QuadrantAboveLeft + self.lyr.quadOffset = ( + QgsPalLayerSettings.QuadrantPosition.QuadrantAboveLeft + ) self.lyr.priority = label_priority self.checkTest() self.removeMapLayer(obstacleLayer) @@ -573,8 +598,8 @@ def test_point_line_obstacle_obstacle_factor_less(self): def test_point_polygon_obstacle_obstacle_factor_greater_equal(self): # Test point label but polygon obstacle exists with a greater obstacle factor vs label priority => NO LABEL - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('narrow_polygon') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("narrow_polygon") for label_priority in range(0, 11): for obstacle_weight in range(label_priority + 1, 11): @@ -582,12 +607,16 @@ def test_point_polygon_obstacle_obstacle_factor_greater_equal(self): obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = obstacle_weight * 0.2 - obstacleLayer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + obstacleLayer.setLabeling( + QgsVectorLayerSimpleLabeling(obstacle_label_settings) + ) obstacleLayer.setLabelsEnabled(True) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OverPoint - self.lyr.quadOffset = QgsPalLayerSettings.QuadrantPosition.QuadrantBelowRight + self.lyr.quadOffset = ( + QgsPalLayerSettings.QuadrantPosition.QuadrantBelowRight + ) self.lyr.priority = label_priority self.checkTest() self.removeMapLayer(obstacleLayer) @@ -596,8 +625,8 @@ def test_point_polygon_obstacle_obstacle_factor_greater_equal(self): def test_point_polygon_obstacle_obstacle_factor_less(self): # Test point label but polygon obstacle exists with an equal or lower obstacle factor vs label priority => LABEL - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('narrow_polygon') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("narrow_polygon") for label_priority in range(0, 11): for obstacle_weight in range(0, label_priority + 1): @@ -605,12 +634,16 @@ def test_point_polygon_obstacle_obstacle_factor_less(self): obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = obstacle_weight * 0.2 - obstacleLayer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + obstacleLayer.setLabeling( + QgsVectorLayerSimpleLabeling(obstacle_label_settings) + ) obstacleLayer.setLabelsEnabled(True) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OverPoint - self.lyr.quadOffset = QgsPalLayerSettings.QuadrantPosition.QuadrantBelowRight + self.lyr.quadOffset = ( + QgsPalLayerSettings.QuadrantPosition.QuadrantBelowRight + ) self.lyr.priority = label_priority self.checkTest() self.removeMapLayer(obstacleLayer) @@ -619,9 +652,9 @@ def test_point_polygon_obstacle_obstacle_factor_less(self): def test_line_point_obstacle_obstacle_factor_greater_equal(self): # Test line label but obstacle exists with a greater obstacle factor vs label priority => NO LABEL - self.layer = TestQgsPalLabeling.loadFeatureLayer('line_short') + self.layer = TestQgsPalLabeling.loadFeatureLayer("line_short") self.layer.setLabelsEnabled(True) - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('point') + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("point") for label_priority in range(0, 11): for obstacle_weight in range(label_priority + 1, 11): @@ -629,7 +662,9 @@ def test_line_point_obstacle_obstacle_factor_greater_equal(self): obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = obstacle_weight * 0.2 - obstacleLayer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + obstacleLayer.setLabeling( + QgsVectorLayerSimpleLabeling(obstacle_label_settings) + ) obstacleLayer.setLabelsEnabled(True) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -642,9 +677,9 @@ def test_line_point_obstacle_obstacle_factor_greater_equal(self): def test_line_point_obstacle_obstacle_factor_less(self): # Test line label but obstacle exists with an equal or lower obstacle factor vs label priority => LABEL - self.layer = TestQgsPalLabeling.loadFeatureLayer('line_short') + self.layer = TestQgsPalLabeling.loadFeatureLayer("line_short") self.layer.setLabelsEnabled(True) - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('point') + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("point") for label_priority in range(0, 11): for obstacle_weight in range(0, label_priority + 1): @@ -652,7 +687,9 @@ def test_line_point_obstacle_obstacle_factor_less(self): obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = obstacle_weight * 0.2 - obstacleLayer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + obstacleLayer.setLabeling( + QgsVectorLayerSimpleLabeling(obstacle_label_settings) + ) obstacleLayer.setLabelsEnabled(True) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -665,9 +702,9 @@ def test_line_point_obstacle_obstacle_factor_less(self): def test_line_line_obstacle_obstacle_factor_greater_equal(self): # Test line label but obstacle exists with a greater obstacle factor vs label priority => NO LABEL - self.layer = TestQgsPalLabeling.loadFeatureLayer('line_short') + self.layer = TestQgsPalLabeling.loadFeatureLayer("line_short") self.layer.setLabelsEnabled(True) - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('line') + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("line") for label_priority in range(0, 11): for obstacle_weight in range(label_priority + 1, 11): @@ -675,7 +712,9 @@ def test_line_line_obstacle_obstacle_factor_greater_equal(self): obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = obstacle_weight * 0.2 - obstacleLayer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + obstacleLayer.setLabeling( + QgsVectorLayerSimpleLabeling(obstacle_label_settings) + ) obstacleLayer.setLabelsEnabled(True) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -688,9 +727,9 @@ def test_line_line_obstacle_obstacle_factor_greater_equal(self): def test_line_line_obstacle_obstacle_factor_less(self): # Test line label but obstacle exists with an equal or lower obstacle factor vs label priority => LABEL - self.layer = TestQgsPalLabeling.loadFeatureLayer('line_short') + self.layer = TestQgsPalLabeling.loadFeatureLayer("line_short") self.layer.setLabelsEnabled(True) - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('line') + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("line") for label_priority in range(0, 11): for obstacle_weight in range(0, label_priority + 1): @@ -698,7 +737,9 @@ def test_line_line_obstacle_obstacle_factor_less(self): obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = obstacle_weight * 0.2 - obstacleLayer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + obstacleLayer.setLabeling( + QgsVectorLayerSimpleLabeling(obstacle_label_settings) + ) obstacleLayer.setLabelsEnabled(True) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -711,9 +752,9 @@ def test_line_line_obstacle_obstacle_factor_less(self): def test_line_polygon_obstacle_obstacle_factor_greater_equal(self): # Test line label but obstacle exists with a greater obstacle factor vs label priority => NO LABEL - self.layer = TestQgsPalLabeling.loadFeatureLayer('line_short') + self.layer = TestQgsPalLabeling.loadFeatureLayer("line_short") self.layer.setLabelsEnabled(True) - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('polygon_center') + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("polygon_center") for label_priority in range(0, 11): for obstacle_weight in range(label_priority + 1, 11): @@ -721,7 +762,9 @@ def test_line_polygon_obstacle_obstacle_factor_greater_equal(self): obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = obstacle_weight * 0.2 - obstacleLayer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + obstacleLayer.setLabeling( + QgsVectorLayerSimpleLabeling(obstacle_label_settings) + ) obstacleLayer.setLabelsEnabled(True) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -734,9 +777,9 @@ def test_line_polygon_obstacle_obstacle_factor_greater_equal(self): def test_line_polygon_obstacle_obstacle_factor_less(self): # Test line label but obstacle exists with an equal or lower obstacle factor vs label priority => LABEL - self.layer = TestQgsPalLabeling.loadFeatureLayer('line_short') + self.layer = TestQgsPalLabeling.loadFeatureLayer("line_short") self.layer.setLabelsEnabled(True) - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('polygon_center') + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("polygon_center") for label_priority in range(0, 11): for obstacle_weight in range(0, label_priority + 1): @@ -744,7 +787,9 @@ def test_line_polygon_obstacle_obstacle_factor_less(self): obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = obstacle_weight * 0.2 - obstacleLayer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + obstacleLayer.setLabeling( + QgsVectorLayerSimpleLabeling(obstacle_label_settings) + ) obstacleLayer.setLabelsEnabled(True) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -757,9 +802,9 @@ def test_line_polygon_obstacle_obstacle_factor_less(self): def test_polygon_point_obstacle_obstacle_factor_greater_equal(self): # Test polygon label but obstacle exists with a greater obstacle factor vs label priority => NO LABEL - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_center') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_center") self.layer.setLabelsEnabled(True) - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('point') + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("point") for label_priority in range(0, 11): for obstacle_weight in range(label_priority + 1, 11): @@ -767,7 +812,9 @@ def test_polygon_point_obstacle_obstacle_factor_greater_equal(self): obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = obstacle_weight * 0.2 - obstacleLayer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + obstacleLayer.setLabeling( + QgsVectorLayerSimpleLabeling(obstacle_label_settings) + ) obstacleLayer.setLabelsEnabled(True) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -780,9 +827,9 @@ def test_polygon_point_obstacle_obstacle_factor_greater_equal(self): def test_polygon_point_obstacle_obstacle_factor_less(self): # Test line label but obstacle exists with an equal or lower obstacle factor vs label priority => LABEL - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_center') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_center") self.layer.setLabelsEnabled(True) - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('point') + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("point") for label_priority in range(0, 11): for obstacle_weight in range(0, label_priority + 1): @@ -790,7 +837,9 @@ def test_polygon_point_obstacle_obstacle_factor_less(self): obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = obstacle_weight * 0.2 - obstacleLayer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + obstacleLayer.setLabeling( + QgsVectorLayerSimpleLabeling(obstacle_label_settings) + ) obstacleLayer.setLabelsEnabled(True) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -803,9 +852,9 @@ def test_polygon_point_obstacle_obstacle_factor_less(self): def test_polygon_line_obstacle_obstacle_factor_greater_equal(self): # Test polygon label but obstacle exists with a greater obstacle factor vs label priority => NO LABEL - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_center') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_center") self.layer.setLabelsEnabled(True) - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('line_placement_4') + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("line_placement_4") for label_priority in range(0, 11): for obstacle_weight in range(label_priority + 1, 11): @@ -813,7 +862,9 @@ def test_polygon_line_obstacle_obstacle_factor_greater_equal(self): obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = obstacle_weight * 0.2 - obstacleLayer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + obstacleLayer.setLabeling( + QgsVectorLayerSimpleLabeling(obstacle_label_settings) + ) obstacleLayer.setLabelsEnabled(True) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -826,9 +877,9 @@ def test_polygon_line_obstacle_obstacle_factor_greater_equal(self): def test_polygon_line_obstacle_obstacle_factor_less(self): # Test line label but obstacle exists with an equal or lower obstacle factor vs label priority => LABEL - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_center') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_center") self.layer.setLabelsEnabled(True) - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('line_placement_4') + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("line_placement_4") for label_priority in range(0, 11): for obstacle_weight in range(0, label_priority + 1): @@ -836,7 +887,9 @@ def test_polygon_line_obstacle_obstacle_factor_less(self): obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = obstacle_weight * 0.2 - obstacleLayer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + obstacleLayer.setLabeling( + QgsVectorLayerSimpleLabeling(obstacle_label_settings) + ) obstacleLayer.setLabelsEnabled(True) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -849,9 +902,9 @@ def test_polygon_line_obstacle_obstacle_factor_less(self): def test_polygon_polygon_obstacle_obstacle_factor_greater_equal(self): # Test polygon label but obstacle exists with a greater obstacle factor vs label priority => NO LABEL - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_center') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_center") self.layer.setLabelsEnabled(True) - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('polygon_small') + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("polygon_small") for label_priority in range(0, 11): for obstacle_weight in range(label_priority + 1, 11): @@ -859,8 +912,12 @@ def test_polygon_polygon_obstacle_obstacle_factor_greater_equal(self): obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = obstacle_weight * 0.2 - obstacle_label_settings.obstacleSettings().setType(QgsLabelObstacleSettings.ObstacleType.PolygonInterior) - obstacleLayer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + obstacle_label_settings.obstacleSettings().setType( + QgsLabelObstacleSettings.ObstacleType.PolygonInterior + ) + obstacleLayer.setLabeling( + QgsVectorLayerSimpleLabeling(obstacle_label_settings) + ) obstacleLayer.setLabelsEnabled(True) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -873,9 +930,9 @@ def test_polygon_polygon_obstacle_obstacle_factor_greater_equal(self): def test_polygon_polygon_obstacle_obstacle_factor_less(self): # Test line label but obstacle exists with an equal or lower obstacle factor vs label priority => LABEL - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_center') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_center") self.layer.setLabelsEnabled(True) - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('polygon_small') + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("polygon_small") for label_priority in range(0, 11): for obstacle_weight in range(0, label_priority + 1): @@ -883,8 +940,12 @@ def test_polygon_polygon_obstacle_obstacle_factor_less(self): obstacle_label_settings.obstacle = True obstacle_label_settings.drawLabels = False obstacle_label_settings.obstacleFactor = obstacle_weight * 0.2 - obstacle_label_settings.obstacleSettings().setType(QgsLabelObstacleSettings.ObstacleType.PolygonInterior) - obstacleLayer.setLabeling(QgsVectorLayerSimpleLabeling(obstacle_label_settings)) + obstacle_label_settings.obstacleSettings().setType( + QgsLabelObstacleSettings.ObstacleType.PolygonInterior + ) + obstacleLayer.setLabeling( + QgsVectorLayerSimpleLabeling(obstacle_label_settings) + ) obstacleLayer.setLabelsEnabled(True) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -897,7 +958,7 @@ def test_polygon_polygon_obstacle_obstacle_factor_less(self): def test_point_ordered_placement1(self): # Test ordered placements for point - self.layer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_placement') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point_ordered_placement") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OrderedPositionsAroundPoint self.lyr.dist = 2 @@ -907,8 +968,8 @@ def test_point_ordered_placement1(self): def test_point_ordered_placement2(self): # Test ordered placements for point (1 obstacle) - self.layer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_placement') - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_obstacle1') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point_ordered_placement") + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("point_ordered_obstacle1") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OrderedPositionsAroundPoint self.lyr.dist = 2 @@ -919,8 +980,8 @@ def test_point_ordered_placement2(self): def test_point_ordered_placement3(self): # Test ordered placements for point (2 obstacle) - self.layer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_placement') - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_obstacle2') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point_ordered_placement") + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("point_ordered_obstacle2") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OrderedPositionsAroundPoint self.lyr.dist = 2 @@ -931,8 +992,8 @@ def test_point_ordered_placement3(self): def test_point_ordered_placement4(self): # Test ordered placements for point (3 obstacle) - self.layer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_placement') - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_obstacle3') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point_ordered_placement") + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer("point_ordered_obstacle3") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OrderedPositionsAroundPoint self.lyr.dist = 2 @@ -943,52 +1004,73 @@ def test_point_ordered_placement4(self): def test_point_dd_ordered_placement(self): # Test ordered placements for point with data defined order - self.layer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_placement') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point_ordered_placement") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OrderedPositionsAroundPoint self.lyr.dist = 2 - self.lyr.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.PredefinedPositionOrder, QgsProperty.fromExpression("'T,B'")) + self.lyr.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.PredefinedPositionOrder, + QgsProperty.fromExpression("'T,B'"), + ) self.checkTest() self.removeMapLayer(self.layer) - self.lyr.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.PredefinedPositionOrder, QgsProperty()) + self.lyr.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.PredefinedPositionOrder, QgsProperty() + ) self.layer = None def test_point_dd_ordered_placement1(self): # Test ordered placements for point with data defined order and obstacle - self.layer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_placement') - obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_obstacle_top') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point_ordered_placement") + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer( + "point_ordered_obstacle_top" + ) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OrderedPositionsAroundPoint self.lyr.dist = 2 - self.lyr.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.PredefinedPositionOrder, QgsProperty.fromExpression("'T,B'")) + self.lyr.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.PredefinedPositionOrder, + QgsProperty.fromExpression("'T,B'"), + ) self.checkTest() self.removeMapLayer(obstacleLayer) self.removeMapLayer(self.layer) - self.lyr.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.PredefinedPositionOrder, QgsProperty()) + self.lyr.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.PredefinedPositionOrder, QgsProperty() + ) self.layer = None def test_point_ordered_placement_over_point(self): # Test ordered placements using over point placement - self.layer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_placement') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point_ordered_placement") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OrderedPositionsAroundPoint self.lyr.dist = 2 - self.lyr.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.PredefinedPositionOrder, QgsProperty.fromExpression("'O'")) + self.lyr.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.PredefinedPositionOrder, + QgsProperty.fromExpression("'O'"), + ) self.checkTest() self.removeMapLayer(self.layer) - self.lyr.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.PredefinedPositionOrder, QgsProperty()) + self.lyr.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.PredefinedPositionOrder, QgsProperty() + ) self.layer = None def test_point_ordered_symbol_bound_offset(self): # Test ordered placements for point using symbol bounds offset - self.layer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_placement') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point_ordered_placement") # Make a big symbol - symbol = QgsMarkerSymbol.createSimple({'color': '31,120,180,255', - 'outline_color': '0,0,0,0', - 'outline_style': 'solid', - 'size': '10', - 'name': 'rectangle', - 'size_unit': 'MM'}) + symbol = QgsMarkerSymbol.createSimple( + { + "color": "31,120,180,255", + "outline_color": "0,0,0,0", + "outline_style": "solid", + "size": "10", + "name": "rectangle", + "size_unit": "MM", + } + ) renderer = QgsSingleSymbolRenderer(symbol) self.layer.setRenderer(renderer) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -1001,7 +1083,7 @@ def test_point_ordered_symbol_bound_offset(self): def test_polygon_placement_perimeter(self): # Default polygon perimeter placement - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_perimeter') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_perimeter") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Line self.lyr.placementFlags = QgsPalLayerSettings.LinePlacementFlags.AboveLine @@ -1011,7 +1093,7 @@ def test_polygon_placement_perimeter(self): def test_small_polygon_placement_perimeter(self): # Default polygon perimeter placement for small polygon - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_small') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_small") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Line self.checkTest() @@ -1020,7 +1102,7 @@ def test_small_polygon_placement_perimeter(self): def test_small_polygon_large_label(self): # Default polygon placement for small polygon with a large label - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_small') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_small") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OverPoint self.lyr.format().setSize(30) @@ -1030,7 +1112,7 @@ def test_small_polygon_large_label(self): def test_small_polygon_large_label_force_inside(self): # Default polygon placement for small polygon with a large label, with only placement of inside labels - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_small') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_small") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OverPoint self.lyr.fitInPolygonOnly = True @@ -1041,10 +1123,15 @@ def test_small_polygon_large_label_force_inside(self): def test_small_polygon_large_label_allow_outside(self): # Default polygon placement for small polygon with a large label, allowing outside placement # we expect this to sit outside, because it CAN'T fit - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_small') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_small") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OverPoint - self.lyr.setPolygonPlacementFlags(Qgis.LabelPolygonPlacementFlags(QgsLabeling.PolygonPlacementFlag.AllowPlacementOutsideOfPolygon | QgsLabeling.PolygonPlacementFlag.AllowPlacementInsideOfPolygon)) + self.lyr.setPolygonPlacementFlags( + Qgis.LabelPolygonPlacementFlags( + QgsLabeling.PolygonPlacementFlag.AllowPlacementOutsideOfPolygon + | QgsLabeling.PolygonPlacementFlag.AllowPlacementInsideOfPolygon + ) + ) self.checkTest() self.removeMapLayer(self.layer) self.layer = None @@ -1052,10 +1139,15 @@ def test_small_polygon_large_label_allow_outside(self): def test_small_polygon_small_label_inside_and_outside(self): # Default polygon placement for small polygon with a small label, allowing outside placement # we expect this to sit inside, because it CAN fit - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_small') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_small") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OverPoint - self.lyr.setPolygonPlacementFlags(Qgis.LabelPolygonPlacementFlags(QgsLabeling.PolygonPlacementFlag.AllowPlacementOutsideOfPolygon | QgsLabeling.PolygonPlacementFlag.AllowPlacementInsideOfPolygon)) + self.lyr.setPolygonPlacementFlags( + Qgis.LabelPolygonPlacementFlags( + QgsLabeling.PolygonPlacementFlag.AllowPlacementOutsideOfPolygon + | QgsLabeling.PolygonPlacementFlag.AllowPlacementInsideOfPolygon + ) + ) f = self.lyr.format() f.setSize(8) self.lyr.setFormat(f) @@ -1066,10 +1158,14 @@ def test_small_polygon_small_label_inside_and_outside(self): def test_small_polygon_small_label_outside_only(self): # Default polygon placement for small polygon with a small label, allowing outside placement only # we expect this to sit outside, cos we are blocking inside placement - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_small') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_small") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OverPoint - self.lyr.setPolygonPlacementFlags(Qgis.LabelPolygonPlacementFlags(QgsLabeling.PolygonPlacementFlag.AllowPlacementOutsideOfPolygon)) + self.lyr.setPolygonPlacementFlags( + Qgis.LabelPolygonPlacementFlags( + QgsLabeling.PolygonPlacementFlag.AllowPlacementOutsideOfPolygon + ) + ) f = self.lyr.format() f.setSize(8) self.lyr.setFormat(f) @@ -1079,10 +1175,12 @@ def test_small_polygon_small_label_outside_only(self): def test_small_polygon_small_data_defined_allow_outside(self): # Default data defined allow outside mode - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_small') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_small") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Horizontal - self.lyr.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.PolygonLabelOutside, QgsProperty.fromValue(1)) + self.lyr.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.PolygonLabelOutside, QgsProperty.fromValue(1) + ) f = self.lyr.format() f.setSize(8) self.lyr.setFormat(f) @@ -1092,10 +1190,13 @@ def test_small_polygon_small_data_defined_allow_outside(self): def test_small_polygon_small_data_defined_force_outside(self): # Default data defined allow outside mode - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_small') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_small") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Horizontal - self.lyr.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.PolygonLabelOutside, QgsProperty.fromValue('force')) + self.lyr.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.PolygonLabelOutside, + QgsProperty.fromValue("force"), + ) f = self.lyr.format() f.setSize(8) self.lyr.setFormat(f) @@ -1105,10 +1206,12 @@ def test_small_polygon_small_data_defined_force_outside(self): def test_small_polygon_small_data_defined_allow_outside_large(self): # Default data defined allow outside mode - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_small') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_small") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Horizontal - self.lyr.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.PolygonLabelOutside, QgsProperty.fromValue(1)) + self.lyr.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.PolygonLabelOutside, QgsProperty.fromValue(1) + ) f = self.lyr.format() f.setSize(20) self.lyr.setFormat(f) @@ -1118,7 +1221,7 @@ def test_small_polygon_small_data_defined_allow_outside_large(self): def test_small_polygon_small_label_outside_mode(self): # Forced outside placement for polygon - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_small') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_small") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OutsidePolygons f = self.lyr.format() @@ -1130,7 +1233,7 @@ def test_small_polygon_small_label_outside_mode(self): def test_small_polygon_small_label_outside_mode_distance(self): # Forced outside placement for polygon with distance - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_small') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_small") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OutsidePolygons self.lyr.dist = 10 @@ -1143,7 +1246,7 @@ def test_small_polygon_small_label_outside_mode_distance(self): def test_small_polygon_perimeter_only_fit(self): # Polygon perimeter placement for small polygon when set to only show labels which fit in polygon - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_small') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_small") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Line self.lyr.fitInPolygonOnly = True @@ -1153,7 +1256,7 @@ def test_small_polygon_perimeter_only_fit(self): def test_small_polygon_curvedperimeter_only_fit(self): # Polygon perimeter placement for small polygon when set to only show labels which fit in polygon - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_small') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_small") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.PerimeterCurved self.lyr.fitInPolygonOnly = True @@ -1163,7 +1266,7 @@ def test_small_polygon_curvedperimeter_only_fit(self): def test_small_polygon_over_point_only_fit(self): # Polygon over point placement for small polygon when set to only show labels which fit in polygon - self.layer = TestQgsPalLabeling.loadFeatureLayer('polygon_small') + self.layer = TestQgsPalLabeling.loadFeatureLayer("polygon_small") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.OverPoint self.lyr.fitInPolygonOnly = True @@ -1174,10 +1277,14 @@ def test_small_polygon_over_point_only_fit(self): def test_prefer_line_curved_above_instead_of_below(self): # Test that labeling a line using curved labels when both above and below placement are allowed that above # is preferred - self.layer = TestQgsPalLabeling.loadFeatureLayer('line') + self.layer = TestQgsPalLabeling.loadFeatureLayer("line") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Curved - self.lyr.placementFlags = QgsPalLayerSettings.LinePlacementFlags.AboveLine | QgsPalLayerSettings.LinePlacementFlags.BelowLine | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + self.lyr.placementFlags = ( + QgsPalLayerSettings.LinePlacementFlags.AboveLine + | QgsPalLayerSettings.LinePlacementFlags.BelowLine + | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + ) self.checkTest() self.removeMapLayer(self.layer) self.layer = None @@ -1185,10 +1292,14 @@ def test_prefer_line_curved_above_instead_of_below(self): def test_prefer_line_curved_above_instead_of_online(self): # Test that labeling a line using curved labels when both above and online placement are allowed that above # is preferred - self.layer = TestQgsPalLabeling.loadFeatureLayer('line') + self.layer = TestQgsPalLabeling.loadFeatureLayer("line") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Curved - self.lyr.placementFlags = QgsPalLayerSettings.LinePlacementFlags.AboveLine | QgsPalLayerSettings.LinePlacementFlags.OnLine | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + self.lyr.placementFlags = ( + QgsPalLayerSettings.LinePlacementFlags.AboveLine + | QgsPalLayerSettings.LinePlacementFlags.OnLine + | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + ) self.checkTest() self.removeMapLayer(self.layer) self.layer = None @@ -1196,10 +1307,14 @@ def test_prefer_line_curved_above_instead_of_online(self): def test_prefer_line_curved_below_instead_of_online(self): # Test that labeling a line using curved labels when both below and online placement are allowed that below # is preferred - self.layer = TestQgsPalLabeling.loadFeatureLayer('line') + self.layer = TestQgsPalLabeling.loadFeatureLayer("line") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Curved - self.lyr.placementFlags = QgsPalLayerSettings.LinePlacementFlags.BelowLine | QgsPalLayerSettings.LinePlacementFlags.OnLine | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + self.lyr.placementFlags = ( + QgsPalLayerSettings.LinePlacementFlags.BelowLine + | QgsPalLayerSettings.LinePlacementFlags.OnLine + | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + ) self.checkTest() self.removeMapLayer(self.layer) self.layer = None @@ -1207,10 +1322,14 @@ def test_prefer_line_curved_below_instead_of_online(self): def test_prefer_line_above_instead_of_below(self): # Test that labeling a line using parallel labels when both above and below placement are allowed that above # is preferred - self.layer = TestQgsPalLabeling.loadFeatureLayer('line') + self.layer = TestQgsPalLabeling.loadFeatureLayer("line") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Line - self.lyr.placementFlags = QgsPalLayerSettings.LinePlacementFlags.AboveLine | QgsPalLayerSettings.LinePlacementFlags.BelowLine | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + self.lyr.placementFlags = ( + QgsPalLayerSettings.LinePlacementFlags.AboveLine + | QgsPalLayerSettings.LinePlacementFlags.BelowLine + | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + ) self.checkTest() self.removeMapLayer(self.layer) self.layer = None @@ -1218,10 +1337,14 @@ def test_prefer_line_above_instead_of_below(self): def test_prefer_line_above_instead_of_online(self): # Test that labeling a line using parallel labels when both above and online placement are allowed that above # is preferred - self.layer = TestQgsPalLabeling.loadFeatureLayer('line') + self.layer = TestQgsPalLabeling.loadFeatureLayer("line") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Line - self.lyr.placementFlags = QgsPalLayerSettings.LinePlacementFlags.AboveLine | QgsPalLayerSettings.LinePlacementFlags.OnLine | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + self.lyr.placementFlags = ( + QgsPalLayerSettings.LinePlacementFlags.AboveLine + | QgsPalLayerSettings.LinePlacementFlags.OnLine + | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + ) self.checkTest() self.removeMapLayer(self.layer) self.layer = None @@ -1229,10 +1352,14 @@ def test_prefer_line_above_instead_of_online(self): def test_prefer_line_below_instead_of_online(self): # Test that labeling a line using parallel labels when both below and online placement are allowed that below # is preferred - self.layer = TestQgsPalLabeling.loadFeatureLayer('line') + self.layer = TestQgsPalLabeling.loadFeatureLayer("line") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Line - self.lyr.placementFlags = QgsPalLayerSettings.LinePlacementFlags.BelowLine | QgsPalLayerSettings.LinePlacementFlags.OnLine | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + self.lyr.placementFlags = ( + QgsPalLayerSettings.LinePlacementFlags.BelowLine + | QgsPalLayerSettings.LinePlacementFlags.OnLine + | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + ) self.checkTest() self.removeMapLayer(self.layer) self.layer = None @@ -1240,7 +1367,7 @@ def test_prefer_line_below_instead_of_online(self): def test_prefer_longer_lines_over_shorter(self): # Test that labeling a line using parallel labels will tend to place the labels over the longer straight parts of # the line - self.layer = TestQgsPalLabeling.loadFeatureLayer('line_placement_1') + self.layer = TestQgsPalLabeling.loadFeatureLayer("line_placement_1") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Line self.checkTest() @@ -1249,7 +1376,7 @@ def test_prefer_longer_lines_over_shorter(self): def test_prefer_more_horizontal_lines(self): # Test that labeling a line using parallel labels will tend to place the labels over more horizontal sections - self.layer = TestQgsPalLabeling.loadFeatureLayer('line_placement_2') + self.layer = TestQgsPalLabeling.loadFeatureLayer("line_placement_2") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Line self.checkTest() @@ -1258,7 +1385,7 @@ def test_prefer_more_horizontal_lines(self): def test_label_line_over_small_angles(self): # Test that labeling a line using parallel labels will place labels near center of straightish line - self.layer = TestQgsPalLabeling.loadFeatureLayer('line_placement_3') + self.layer = TestQgsPalLabeling.loadFeatureLayer("line_placement_3") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Line self.checkTest() @@ -1267,7 +1394,7 @@ def test_label_line_over_small_angles(self): def test_label_line_toward_center(self): # Test that labeling a line using parallel labels will try to place labels as close to center of line as possible - self.layer = TestQgsPalLabeling.loadFeatureLayer('line_placement_4') + self.layer = TestQgsPalLabeling.loadFeatureLayer("line_placement_4") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Line self.checkTest() @@ -1276,7 +1403,7 @@ def test_label_line_toward_center(self): def test_label_line_avoid_jaggy(self): # Test that labeling a line using parallel labels won't place labels over jaggy bits of line - self.layer = TestQgsPalLabeling.loadFeatureLayer('line_placement_5') + self.layer = TestQgsPalLabeling.loadFeatureLayer("line_placement_5") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Line self.checkTest() @@ -1285,7 +1412,7 @@ def test_label_line_avoid_jaggy(self): def test_label_curved_zero_width_char(self): # Test that curved label work with zero-width characters - self.layer = TestQgsPalLabeling.loadFeatureLayer('line') + self.layer = TestQgsPalLabeling.loadFeatureLayer("line") self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self.lyr.placement = QgsPalLayerSettings.Placement.Curved self.lyr.placementFlags = QgsPalLayerSettings.LinePlacementFlags.OnLine @@ -1296,9 +1423,8 @@ def test_label_curved_zero_width_char(self): self.layer = None def test_label_rule_min_distance_label_to_feature(self): - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') - feature_layer = TestQgsPalLabeling.loadFeatureLayer( - 'multi_polygon') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") + feature_layer = TestQgsPalLabeling.loadFeatureLayer("multi_polygon") feature_layer.setLabelsEnabled(False) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -1327,9 +1453,8 @@ def test_label_rule_min_distance_label_to_feature_too_close(self): Label can't be placed, there's no candidates available which satisfy the rule """ - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') - feature_layer = TestQgsPalLabeling.loadFeatureLayer( - 'multi_polygon') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") + feature_layer = TestQgsPalLabeling.loadFeatureLayer("multi_polygon") feature_layer.setLabelsEnabled(False) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -1358,9 +1483,8 @@ def test_label_rule_min_distance_label_to_feature_too_close_low_cost(self): Label can't be placed without incurring the cost, but still CAN be placed """ - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') - feature_layer = TestQgsPalLabeling.loadFeatureLayer( - 'multi_polygon') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") + feature_layer = TestQgsPalLabeling.loadFeatureLayer("multi_polygon") feature_layer.setLabelsEnabled(False) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -1388,9 +1512,8 @@ def test_label_rule_max_distance_label_to_feature(self): # worse placement position below point should be used, because # above point placements are too far from the polygon and violate # the rule - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') - feature_layer = TestQgsPalLabeling.loadFeatureLayer( - 'polygon_with_hole') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") + feature_layer = TestQgsPalLabeling.loadFeatureLayer("polygon_with_hole") feature_layer.setLabelsEnabled(False) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -1417,9 +1540,8 @@ def test_label_rule_max_distance_label_to_feature(self): def test_label_rule_max_distance_label_to_feature_too_far(self): # label can't be placed, because all candidates are too far from # the polygon layer - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') - feature_layer = TestQgsPalLabeling.loadFeatureLayer( - 'polygon_with_hole') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") + feature_layer = TestQgsPalLabeling.loadFeatureLayer("polygon_with_hole") feature_layer.setLabelsEnabled(False) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -1448,9 +1570,8 @@ def test_label_rule_max_distance_label_to_feature_too_far_low_cost(self): All candidates violate the rule, but it's low cost and won't prevent label placement """ - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') - feature_layer = TestQgsPalLabeling.loadFeatureLayer( - 'polygon_with_hole') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") + feature_layer = TestQgsPalLabeling.loadFeatureLayer("polygon_with_hole") feature_layer.setLabelsEnabled(False) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -1475,9 +1596,8 @@ def test_label_rule_max_distance_label_to_feature_too_far_low_cost(self): self.layer = None def test_label_rule_avoid_overlap_with_feature(self): - self.layer = TestQgsPalLabeling.loadFeatureLayer('point') - feature_layer = TestQgsPalLabeling.loadFeatureLayer( - 'multi_polygon') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point") + feature_layer = TestQgsPalLabeling.loadFeatureLayer("multi_polygon") feature_layer.setLabelsEnabled(False) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) @@ -1499,15 +1619,13 @@ def test_label_rule_avoid_overlap_with_feature(self): self.layer = None def test_label_rule_min_distance_label_to_label(self): - self.layer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_obstacle2') - feature_layer = TestQgsPalLabeling.loadFeatureLayer( - 'point') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point_ordered_obstacle2") + feature_layer = TestQgsPalLabeling.loadFeatureLayer("point") feature_layer.setLabelsEnabled(True) feature_label_labeling = QgsPalLayerSettings(self.lyr) feature_label_labeling.fieldName = "'label'" feature_label_labeling.isExpression = True - feature_layer.setLabeling(QgsVectorLayerSimpleLabeling( - feature_label_labeling)) + feature_layer.setLabeling(QgsVectorLayerSimpleLabeling(feature_label_labeling)) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self._TestMapSettings.setLayers([self.layer, feature_layer]) @@ -1529,15 +1647,13 @@ def test_label_rule_min_distance_label_to_label(self): self.layer = None def test_label_rule_min_distance_label_to_label_small(self): - self.layer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_obstacle2') - feature_layer = TestQgsPalLabeling.loadFeatureLayer( - 'point') + self.layer = TestQgsPalLabeling.loadFeatureLayer("point_ordered_obstacle2") + feature_layer = TestQgsPalLabeling.loadFeatureLayer("point") feature_layer.setLabelsEnabled(True) feature_label_labeling = QgsPalLayerSettings(self.lyr) feature_label_labeling.fieldName = "'label'" feature_label_labeling.isExpression = True - feature_layer.setLabeling(QgsVectorLayerSimpleLabeling( - feature_label_labeling)) + feature_layer.setLabeling(QgsVectorLayerSimpleLabeling(feature_label_labeling)) self._TestMapSettings = self.cloneMapSettings(self._MapSettings) self._TestMapSettings.setLayers([self.layer, feature_layer]) @@ -1545,7 +1661,7 @@ def test_label_rule_min_distance_label_to_label_small(self): rule = QgsLabelingEngineRuleMinimumDistanceLabelToLabel() rule.setLabeledLayer(self.layer) rule.setTargetLayer(feature_layer) - rule.setDistance(.1) + rule.setDistance(0.1) engine_settings = self._TestMapSettings.labelingEngineSettings() engine_settings.setRules([rule]) @@ -1559,9 +1675,9 @@ def test_label_rule_min_distance_label_to_label_small(self): self.layer = None -if __name__ == '__main__': +if __name__ == "__main__": # NOTE: unless PAL_SUITE env var is set all test class methods will be run # SEE: test_qgspallabeling_tests.suiteTests() to define suite - suite = ('TestPointPlacement') + suite = "TestPointPlacement" res = runSuite(sys.modules[__name__], suite) sys.exit(not res.wasSuccessful()) diff --git a/tests/src/python/test_qgspallabeling_server.py b/tests/src/python/test_qgspallabeling_server.py index 42e8d282a389..48141c7d60bb 100644 --- a/tests/src/python/test_qgspallabeling_server.py +++ b/tests/src/python/test_qgspallabeling_server.py @@ -10,17 +10,14 @@ (at your option) any later version. """ -__author__ = 'Larry Shaffer' -__date__ = '07/12/2013' -__copyright__ = 'Copyright 2013, The QGIS Project' +__author__ = "Larry Shaffer" +__date__ = "07/12/2013" +__copyright__ = "Copyright 2013, The QGIS Project" import sys from qgis.PyQt.QtGui import QImage -from qgis.core import ( - QgsProject, - QgsVectorLayerSimpleLabeling -) +from qgis.core import QgsProject, QgsVectorLayerSimpleLabeling from qgis.server import ( QgsBufferServerRequest, @@ -37,7 +34,7 @@ class TestServerBase(TestQgsPalLabeling): _TestProj = None """:type: QgsProject""" - _TestProjName = '' + _TestProjName = "" layer = None """:type: QgsVectorLayer""" params = dict() @@ -53,7 +50,7 @@ def setUpClass(cls): cls._TestProj = QgsProject() # the blue background (set via layer style) to match renderchecker's - background_layer = TestQgsPalLabeling.loadFeatureLayer('background', True) + background_layer = TestQgsPalLabeling.loadFeatureLayer("background", True) if background_layer: cls._TestProj.addMapLayer(background_layer) @@ -72,30 +69,37 @@ def get_request_params(self) -> str: dpi = str(int(ms.outputDpi())) lyrs = [str(layer.name()) for layer in ms.layers()] lyrs.reverse() - return "?" + "&".join(["%s=%s" % i for i in list({ - 'SERVICE': 'WMS', - 'VERSION': '1.3.0', - 'REQUEST': 'GetMap', - # layer stacking order for rendering: bottom,to,top - 'LAYERS': ','.join(lyrs), # or 'name,name' - 'STYLES': ',', - # authid str or QgsCoordinateReferenceSystem obj - 'CRS': str(ms.destinationCrs().authid()), - # self.aoiExtent(), - 'BBOX': str(ms.extent().toString(True).replace(' : ', ',')), - 'FORMAT': 'image/png', # or: 'image/png; mode=8bit' - 'WIDTH': str(osize.width()), - 'HEIGHT': str(osize.height()), - 'DPI': dpi, - 'MAP_RESOLUTION': dpi, - 'FORMAT_OPTIONS': f'dpi:{dpi}', - 'TRANSPARENT': 'FALSE', - 'IgnoreGetMapUrl': '1' - }.items())]) + return "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + # layer stacking order for rendering: bottom,to,top + "LAYERS": ",".join(lyrs), # or 'name,name' + "STYLES": ",", + # authid str or QgsCoordinateReferenceSystem obj + "CRS": str(ms.destinationCrs().authid()), + # self.aoiExtent(), + "BBOX": str(ms.extent().toString(True).replace(" : ", ",")), + "FORMAT": "image/png", # or: 'image/png; mode=8bit' + "WIDTH": str(osize.width()), + "HEIGHT": str(osize.height()), + "DPI": dpi, + "MAP_RESOLUTION": dpi, + "FORMAT_OPTIONS": f"dpi:{dpi}", + "TRANSPARENT": "FALSE", + "IgnoreGetMapUrl": "1", + }.items() + ) + ] + ) def _result(self, data): headers = {} - for line in data[0].decode('UTF-8').split("\n"): + for line in data[0].decode("UTF-8").split("\n"): if line != "": header = line.split(":") self.assertEqual(len(header), 2, line) @@ -103,7 +107,13 @@ def _result(self, data): return data[1], headers - def _execute_request_project(self, qs: str, project: QgsProject, requestMethod=QgsServerRequest.GetMethod, data=None): + def _execute_request_project( + self, + qs: str, + project: QgsProject, + requestMethod=QgsServerRequest.GetMethod, + data=None, + ): request = QgsBufferServerRequest(qs, requestMethod, {}, data) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) @@ -131,7 +141,7 @@ def checkTest(self, **kwargs): self._Test, color_tolerance=0, allowed_mismatch=0, - control_path_prefix='expected_' + self._TestGroupPrefix + control_path_prefix="expected_" + self._TestGroupPrefix, ) ) @@ -141,7 +151,7 @@ class TestServerBasePoint(TestServerBase): @classmethod def setUpClass(cls): TestServerBase.setUpClass() - cls.layer = TestQgsPalLabeling.loadFeatureLayer('point') + cls.layer = TestQgsPalLabeling.loadFeatureLayer("point") cls._TestProj.addMapLayer(cls.layer) @@ -149,7 +159,7 @@ class TestServerPoint(TestServerBasePoint, TestPointBase): def setUp(self): super().setUp() - self.configTest('pal_server', 'sp') + self.configTest("pal_server", "sp") def test_partials_labels_disabled(self): # these are ALWAYS enabled for server @@ -160,7 +170,7 @@ class TestServerVsCanvasPoint(TestServerBasePoint, TestPointBase): def setUp(self): super().setUp() - self.configTest('pal_canvas', 'sp') + self.configTest("pal_canvas", "sp") def test_partials_labels_disabled(self): # these are ALWAYS enabled for server @@ -172,7 +182,7 @@ class TestServerBaseLine(TestServerBase): @classmethod def setUpClass(cls): TestServerBase.setUpClass() - cls.layer = TestQgsPalLabeling.loadFeatureLayer('line') + cls.layer = TestQgsPalLabeling.loadFeatureLayer("line") cls._TestProj.addMapLayer(cls.layer) @@ -181,22 +191,21 @@ class TestServerLine(TestServerBaseLine, TestLineBase): def setUp(self): """Run before each test.""" super().setUp() - self.configTest('pal_server_line', 'sp') + self.configTest("pal_server_line", "sp") class TestServerVsCanvasLine(TestServerBaseLine, TestLineBase): def setUp(self): super().setUp() - self.configTest('pal_canvas_line', 'sp') + self.configTest("pal_canvas_line", "sp") -if __name__ == '__main__': +if __name__ == "__main__": # NOTE: unless PAL_SUITE env var is set all test class methods will be run # SEE: test_qgspallabeling_tests.suiteTests() to define suite - suite = ( - ['TestServerPoint.' + t for t in suiteTests()['sp_suite']] + - ['TestServerVsCanvasPoint.' + t for t in suiteTests()['sp_vs_suite']] - ) + suite = ["TestServerPoint." + t for t in suiteTests()["sp_suite"]] + [ + "TestServerVsCanvasPoint." + t for t in suiteTests()["sp_vs_suite"] + ] res = runSuite(sys.modules[__name__], suite) sys.exit(not res.wasSuccessful()) diff --git a/tests/src/python/test_qgspallabeling_tests.py b/tests/src/python/test_qgspallabeling_tests.py index cb25f00bd0e3..f7b6c714b404 100644 --- a/tests/src/python/test_qgspallabeling_tests.py +++ b/tests/src/python/test_qgspallabeling_tests.py @@ -9,9 +9,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Larry Shaffer' -__date__ = '07/16/2013' -__copyright__ = 'Copyright 2013, The QGIS Project' + +__author__ = "Larry Shaffer" +__date__ = "07/16/2013" +__copyright__ = "Copyright 2013, The QGIS Project" import os @@ -57,8 +58,8 @@ def checkTest(self, **kwargs): def test_default_label(self): # Default label placement, with text size in points - self._Mismatches['TestCanvasPoint'] = 776 - self._ColorTols['TestComposerPdfPoint'] = 2 + self._Mismatches["TestCanvasPoint"] = 776 + self._ColorTols["TestComposerPdfPoint"] = 2 self.checkTest() def test_text_size_map_unit(self): @@ -70,13 +71,13 @@ def test_text_size_map_unit(self): font = QFont(self._TestFont) format.setFont(font) self.lyr.setFormat(format) - self._Mismatches['TestCanvasPoint'] = 776 - self._ColorTols['TestComposerPdfPoint'] = 2 + self._Mismatches["TestCanvasPoint"] = 776 + self._ColorTols["TestComposerPdfPoint"] = 2 self.checkTest() def test_text_color(self): - self._Mismatches['TestCanvasPoint'] = 774 - self._ColorTols['TestComposerPdfPoint'] = 2 + self._Mismatches["TestCanvasPoint"] = 774 + self._ColorTols["TestComposerPdfPoint"] = 2 # Label color change format = self.lyr.format() format.setColor(Qt.GlobalColor.blue) @@ -84,19 +85,19 @@ def test_text_color(self): self.checkTest() def test_background_rect(self): - self._Mismatches['TestComposerImageVsCanvasPoint'] = 800 - self._Mismatches['TestComposerImagePoint'] = 800 + self._Mismatches["TestComposerImageVsCanvasPoint"] = 800 + self._Mismatches["TestComposerImagePoint"] = 800 format = self.lyr.format() format.background().setEnabled(True) self.lyr.setFormat(format) - self._Mismatches['TestCanvasPoint'] = 776 - self._ColorTols['TestComposerPdfPoint'] = 1 + self._Mismatches["TestCanvasPoint"] = 776 + self._ColorTols["TestComposerPdfPoint"] = 1 self.checkTest() def test_background_rect_w_offset(self): # Label rectangular background - self._Mismatches['TestComposerImageVsCanvasPoint'] = 800 - self._Mismatches['TestComposerImagePoint'] = 800 + self._Mismatches["TestComposerImageVsCanvasPoint"] = 800 + self._Mismatches["TestComposerImagePoint"] = 800 # verify fix for issues # https://github.com/qgis/QGIS/issues/17705 # http://gis.stackexchange.com/questions/86900 @@ -113,8 +114,8 @@ def test_background_rect_w_offset(self): self.lyr.setFormat(format) - self._Mismatches['TestCanvasPoint'] = 774 - self._ColorTols['TestComposerPdfPoint'] = 2 + self._Mismatches["TestCanvasPoint"] = 774 + self._ColorTols["TestComposerPdfPoint"] = 2 self.checkTest() def test_background_svg(self): @@ -127,17 +128,16 @@ def test_background_svg(self): format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeSVG) - svg = os.path.join( - svgSymbolsPath(), 'backgrounds', 'background_square.svg') + svg = os.path.join(svgSymbolsPath(), "backgrounds", "background_square.svg") format.background().setSvgFile(svg) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeBuffer) format.background().setSize(QSizeF(100.0, 0.0)) self.lyr.setFormat(format) - self._Mismatches['TestComposerPdfVsComposerPoint'] = 580 - self._Mismatches['TestCanvasPoint'] = 776 - self._ColorTols['TestComposerPdfPoint'] = 2 + self._Mismatches["TestComposerPdfVsComposerPoint"] = 580 + self._Mismatches["TestCanvasPoint"] = 776 + self._ColorTols["TestComposerPdfPoint"] = 2 self.checkTest() def test_background_svg_w_offset(self): @@ -150,8 +150,7 @@ def test_background_svg_w_offset(self): format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeSVG) - svg = os.path.join( - svgSymbolsPath(), 'backgrounds', 'background_square.svg') + svg = os.path.join(svgSymbolsPath(), "backgrounds", "background_square.svg") format.background().setSvgFile(svg) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeBuffer) @@ -161,9 +160,9 @@ def test_background_svg_w_offset(self): self.lyr.setFormat(format) - self._Mismatches['TestComposerPdfVsComposerPoint'] = 760 - self._Mismatches['TestCanvasPoint'] = 776 - self._ColorTols['TestComposerPdfPoint'] = 2 + self._Mismatches["TestComposerPdfVsComposerPoint"] = 760 + self._Mismatches["TestCanvasPoint"] = 776 + self._ColorTols["TestComposerPdfPoint"] = 2 self.checkTest() def test_partials_labels_enabled(self): @@ -175,10 +174,12 @@ def test_partials_labels_enabled(self): self.lyr.setFormat(format) # Enable partials labels engine_settings = QgsLabelingEngineSettings() - engine_settings.setFlag(QgsLabelingEngineSettings.Flag.UsePartialCandidates, True) + engine_settings.setFlag( + QgsLabelingEngineSettings.Flag.UsePartialCandidates, True + ) self._TestMapSettings.setLabelingEngineSettings(engine_settings) - self._Mismatches['TestCanvasPoint'] = 779 - self._ColorTols['TestComposerPdfPoint'] = 2 + self._Mismatches["TestCanvasPoint"] = 779 + self._ColorTols["TestComposerPdfPoint"] = 2 self.checkTest() def test_partials_labels_disabled(self): @@ -190,7 +191,9 @@ def test_partials_labels_disabled(self): self.lyr.setFormat(format) # Disable partials labels engine_settings = QgsLabelingEngineSettings() - engine_settings.setFlag(QgsLabelingEngineSettings.Flag.UsePartialCandidates, False) + engine_settings.setFlag( + QgsLabelingEngineSettings.Flag.UsePartialCandidates, False + ) self._TestMapSettings.setLabelingEngineSettings(engine_settings) self.checkTest() @@ -281,13 +284,19 @@ def test_line_placement_below_line_orientation(self): def test_line_placement_above_map_orientation(self): # Line placement, above, follow map orientation self.lyr.placement = QgsPalLayerSettings.Placement.Line - self.lyr.placementFlags = QgsPalLayerSettings.LinePlacementFlags.AboveLine | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + self.lyr.placementFlags = ( + QgsPalLayerSettings.LinePlacementFlags.AboveLine + | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + ) self.checkTest() def test_line_placement_below_map_orientation(self): # Line placement, below, follow map orientation self.lyr.placement = QgsPalLayerSettings.Placement.Line - self.lyr.placementFlags = QgsPalLayerSettings.LinePlacementFlags.BelowLine | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + self.lyr.placementFlags = ( + QgsPalLayerSettings.LinePlacementFlags.BelowLine + | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + ) self.checkTest() def test_curved_placement_online(self): @@ -299,13 +308,19 @@ def test_curved_placement_online(self): def test_curved_placement_above(self): # Curved placement, on line self.lyr.placement = QgsPalLayerSettings.Placement.Curved - self.lyr.placementFlags = QgsPalLayerSettings.LinePlacementFlags.AboveLine | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + self.lyr.placementFlags = ( + QgsPalLayerSettings.LinePlacementFlags.AboveLine + | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + ) self.checkTest() def test_curved_placement_below(self): # Curved placement, on line self.lyr.placement = QgsPalLayerSettings.Placement.Curved - self.lyr.placementFlags = QgsPalLayerSettings.LinePlacementFlags.BelowLine | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + self.lyr.placementFlags = ( + QgsPalLayerSettings.LinePlacementFlags.BelowLine + | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + ) self.checkTest() def test_curved_placement_online_html(self): @@ -315,7 +330,7 @@ def test_curved_placement_online_html(self): format = self.lyr.format() format.setAllowHtmlFormatting(True) self.lyr.setFormat(format) - self.lyr.fieldName = "'aaaaaa'" + self.lyr.fieldName = '\'aaaaaa\'' self.lyr.isExpression = True self.checkTest() @@ -326,7 +341,9 @@ def test_length_expression(self): QgsProject.instance().setCrs(QgsCoordinateReferenceSystem("EPSG:32613")) QgsProject.instance().setEllipsoid("WGS84") - QgsProject.instance().setDistanceUnits(QgsUnitTypes.DistanceUnit.DistanceKilometers) + QgsProject.instance().setDistanceUnits( + QgsUnitTypes.DistanceUnit.DistanceKilometers + ) ctxt = QgsExpressionContext() ctxt.appendScope(QgsExpressionContextUtils.projectScope(QgsProject.instance())) @@ -334,7 +351,10 @@ def test_length_expression(self): self._TestMapSettings.setExpressionContext(ctxt) self.lyr.placement = QgsPalLayerSettings.Placement.Curved - self.lyr.placementFlags = QgsPalLayerSettings.LinePlacementFlags.AboveLine | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + self.lyr.placementFlags = ( + QgsPalLayerSettings.LinePlacementFlags.AboveLine + | QgsPalLayerSettings.LinePlacementFlags.MapOrientation + ) self.checkTest() @@ -363,11 +383,8 @@ def suiteTests(): # extended separately for finer control of PAL_SUITE (comment-out undesired) sp_vs_suite.extend(sp_suite) - return { - 'sp_suite': sp_suite, - 'sp_vs_suite': sp_vs_suite - } + return {"sp_suite": sp_suite, "sp_vs_suite": sp_vs_suite} -if __name__ == '__main__': +if __name__ == "__main__": pass diff --git a/tests/src/python/test_qgspanelwidget.py b/tests/src/python/test_qgspanelwidget.py index 742bc3c9c4e7..8fb97da6f7cf 100644 --- a/tests/src/python/test_qgspanelwidget.py +++ b/tests/src/python/test_qgspanelwidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '16/08/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "16/08/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtWidgets import QDialog, QWidget from qgis.gui import QgsPanelWidget @@ -20,7 +21,7 @@ class TestQgsPanelWidget(QgisTestCase): def testFindParentPanel(self): - """ test QgsPanelWidget.findParentPanel """ + """test QgsPanelWidget.findParentPanel""" # no widget self.assertFalse(QgsPanelWidget.findParentPanel(None)) @@ -52,5 +53,5 @@ def testFindParentPanel(self): self.assertFalse(QgsPanelWidget.findParentPanel(n3)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspanelwidgetstack.py b/tests/src/python/test_qgspanelwidgetstack.py index 4e53059242a4..26a0689f9961 100644 --- a/tests/src/python/test_qgspanelwidgetstack.py +++ b/tests/src/python/test_qgspanelwidgetstack.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '05/10/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "05/10/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy from qgis.gui import QgsPanelWidget, QgsPanelWidgetStack @@ -20,7 +21,7 @@ class TestQgsPanelWidgetStack(QgisTestCase): def testMainPanel(self): - """ test mainPanel methods """ + """test mainPanel methods""" s = QgsPanelWidgetStack() @@ -39,7 +40,7 @@ def testMainPanel(self): self.assertFalse(s.takeMainPanel()) def testAddingPanels(self): - """ test adding panels to stack """ + """test adding panels to stack""" s = QgsPanelWidgetStack() mp = QgsPanelWidget() @@ -54,7 +55,7 @@ def testAddingPanels(self): self.assertEqual(s.currentPanel(), p2) def testAcceptCurrentPanel(self): - """ test accepting current panel """ + """test accepting current panel""" s = QgsPanelWidgetStack() # call on empty stack @@ -85,7 +86,7 @@ def testAcceptCurrentPanel(self): self.assertEqual(len(p1_accept_spy), 1) def testAcceptAllPanel(self): - """ test accepting all panels """ + """test accepting all panels""" s = QgsPanelWidgetStack() # call on empty stack s.acceptAllPanels() @@ -116,7 +117,7 @@ def testAcceptAllPanel(self): self.assertEqual(len(p3_accept_spy), 1) def testClear(self): - """ test clearing stack """ + """test clearing stack""" s = QgsPanelWidgetStack() # call on empty stack s.clear() @@ -137,7 +138,7 @@ def testClear(self): self.assertFalse(s.mainPanel()) def testTakeMainAcceptsAll(self): - """ test that taking the main panel accepts all open child panels""" + """test that taking the main panel accepts all open child panels""" s = QgsPanelWidgetStack() mp = QgsPanelWidget() s.setMainPanel(mp) @@ -158,5 +159,5 @@ def testTakeMainAcceptsAll(self): self.assertEqual(len(p3_accept_spy), 1) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspathresolver.py b/tests/src/python/test_qgspathresolver.py index 503c226cfbc7..8429bc0f997d 100644 --- a/tests/src/python/test_qgspathresolver.py +++ b/tests/src/python/test_qgspathresolver.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '22/07/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "22/07/2019" +__copyright__ = "Copyright 2019, The QGIS Project" import gc import os @@ -32,9 +33,9 @@ class TestQgsPathResolver(QgisTestCase): def testCustomPreprocessor(self): - self.assertEqual(QgsPathResolver().readPath('aaaaa'), 'aaaaa') + self.assertEqual(QgsPathResolver().readPath("aaaaa"), "aaaaa") with self.assertRaises(KeyError): - QgsPathResolver().removePathPreprocessor('bad') + QgsPathResolver().removePathPreprocessor("bad") def run_test(): def my_processor(path): @@ -42,17 +43,17 @@ def my_processor(path): id = QgsPathResolver.setPathPreprocessor(my_processor) self.assertTrue(id) - self.assertEqual(QgsPathResolver().readPath('aaaaa'), 'AAAAA') + self.assertEqual(QgsPathResolver().readPath("aaaaa"), "AAAAA") return id id = run_test() gc.collect() # my_processor should be out of scope and cleaned up, unless things are working # correctly and ownership was transferred - self.assertEqual(QgsPathResolver().readPath('aaaaa'), 'AAAAA') + self.assertEqual(QgsPathResolver().readPath("aaaaa"), "AAAAA") QgsPathResolver().removePathPreprocessor(id) - self.assertEqual(QgsPathResolver().readPath('aaaaa'), 'aaaaa') + self.assertEqual(QgsPathResolver().readPath("aaaaa"), "aaaaa") # expect key error with self.assertRaises(KeyError): @@ -62,24 +63,24 @@ def testChainedPreprocessors(self): """ Test that chaining preprocessors works correctly """ - self.assertEqual(QgsPathResolver().readPath('aaaaa'), 'aaaaa') + self.assertEqual(QgsPathResolver().readPath("aaaaa"), "aaaaa") def run_test(): def my_processor(path): - return 'x' + path + 'x' + return "x" + path + "x" def my_processor2(path): - return 'y' + path + 'y' + return "y" + path + "y" id = QgsPathResolver.setPathPreprocessor(my_processor) self.assertTrue(id) - self.assertEqual(QgsPathResolver().readPath('aaaaa'), 'xaaaaax') + self.assertEqual(QgsPathResolver().readPath("aaaaa"), "xaaaaax") id2 = QgsPathResolver.setPathPreprocessor(my_processor2) self.assertTrue(id2) - self.assertEqual(QgsPathResolver().readPath('aaaaa'), 'yxaaaaaxy') + self.assertEqual(QgsPathResolver().readPath("aaaaa"), "yxaaaaaxy") return id, id2 @@ -87,17 +88,17 @@ def my_processor2(path): gc.collect() # my_processor should be out of scope and cleaned up, unless things are working # correctly and ownership was transferred - self.assertEqual(QgsPathResolver().readPath('aaaaa'), 'yxaaaaaxy') + self.assertEqual(QgsPathResolver().readPath("aaaaa"), "yxaaaaaxy") QgsPathResolver().removePathPreprocessor(id) - self.assertEqual(QgsPathResolver().readPath('aaaaa'), 'yaaaaay') + self.assertEqual(QgsPathResolver().readPath("aaaaa"), "yaaaaay") # expect key error with self.assertRaises(KeyError): QgsPathResolver().removePathPreprocessor(id) QgsPathResolver().removePathPreprocessor(id2) - self.assertEqual(QgsPathResolver().readPath('aaaaa'), 'aaaaa') + self.assertEqual(QgsPathResolver().readPath("aaaaa"), "aaaaa") with self.assertRaises(KeyError): QgsPathResolver().removePathPreprocessor(id2) @@ -106,32 +107,32 @@ def testLoadLayerWithPreprocessor(self): """ Test that custom path preprocessor is used when loading layers """ - lines_shp_path = os.path.join(TEST_DATA_DIR, 'moooooo.shp') + lines_shp_path = os.path.join(TEST_DATA_DIR, "moooooo.shp") - lines_layer = QgsVectorLayer(lines_shp_path, 'Lines', 'ogr') + lines_layer = QgsVectorLayer(lines_shp_path, "Lines", "ogr") self.assertFalse(lines_layer.isValid()) p = QgsProject() p.addMapLayer(lines_layer) # save project to a temporary file temp_path = tempfile.mkdtemp() - temp_project_path = os.path.join(temp_path, 'temp.qgs') + temp_project_path = os.path.join(temp_path, "temp.qgs") self.assertTrue(p.write(temp_project_path)) p2 = QgsProject() self.assertTrue(p2.read(temp_project_path)) - l = p2.mapLayersByName('Lines')[0] - self.assertEqual(l.name(), 'Lines') + l = p2.mapLayersByName("Lines")[0] + self.assertEqual(l.name(), "Lines") self.assertFalse(l.isValid()) # custom processor to fix path def my_processor(path): - return path.replace('moooooo', 'lines') + return path.replace("moooooo", "lines") QgsPathResolver.setPathPreprocessor(my_processor) p3 = QgsProject() self.assertTrue(p3.read(temp_project_path)) - l = p3.mapLayersByName('Lines')[0] - self.assertEqual(l.name(), 'Lines') + l = p3.mapLayersByName("Lines")[0] + self.assertEqual(l.name(), "Lines") # layer should have correct path now self.assertTrue(l.isValid()) @@ -140,21 +141,49 @@ def testInbuiltPath(self): Test resolving and saving inbuilt data paths """ path = "inbuilt:/data/world_map.shp" - self.assertEqual(QgsPathResolver().readPath(path), QgsApplication.pkgDataPath() + '/resources/data/world_map.shp') - - self.assertEqual(QgsPathResolver().writePath(QgsApplication.pkgDataPath() + '/resources/data/world_map.shp'), 'inbuilt:/data/world_map.shp') + self.assertEqual( + QgsPathResolver().readPath(path), + QgsApplication.pkgDataPath() + "/resources/data/world_map.shp", + ) + + self.assertEqual( + QgsPathResolver().writePath( + QgsApplication.pkgDataPath() + "/resources/data/world_map.shp" + ), + "inbuilt:/data/world_map.shp", + ) def testRelativeProject(self): """Test relative project paths can still resolve, regression #33200""" curdir = os.getcwd() - os.chdir(os.path.join(TEST_DATA_DIR, 'qgis_server')) - resolver = QgsPathResolver('./test_project.qgs') - self.assertEqual(resolver.readPath('./testlayer.shp').replace("\\", "/"), os.path.join(TEST_DATA_DIR, 'qgis_server', 'testlayer.shp').replace("\\", "/")) - self.assertEqual(resolver.readPath('testlayer.shp').replace("\\", "/"), os.path.join(TEST_DATA_DIR, 'qgis_server', 'testlayer.shp').replace("\\", "/")) - resolver = QgsPathResolver('test_project.qgs') - self.assertEqual(resolver.readPath('./testlayer.shp').replace("\\", "/"), os.path.join(TEST_DATA_DIR, 'qgis_server', 'testlayer.shp').replace("\\", "/")) - self.assertEqual(resolver.readPath('testlayer.shp').replace("\\", "/"), os.path.join(TEST_DATA_DIR, 'qgis_server', 'testlayer.shp').replace("\\", "/")) + os.chdir(os.path.join(TEST_DATA_DIR, "qgis_server")) + resolver = QgsPathResolver("./test_project.qgs") + self.assertEqual( + resolver.readPath("./testlayer.shp").replace("\\", "/"), + os.path.join(TEST_DATA_DIR, "qgis_server", "testlayer.shp").replace( + "\\", "/" + ), + ) + self.assertEqual( + resolver.readPath("testlayer.shp").replace("\\", "/"), + os.path.join(TEST_DATA_DIR, "qgis_server", "testlayer.shp").replace( + "\\", "/" + ), + ) + resolver = QgsPathResolver("test_project.qgs") + self.assertEqual( + resolver.readPath("./testlayer.shp").replace("\\", "/"), + os.path.join(TEST_DATA_DIR, "qgis_server", "testlayer.shp").replace( + "\\", "/" + ), + ) + self.assertEqual( + resolver.readPath("testlayer.shp").replace("\\", "/"), + os.path.join(TEST_DATA_DIR, "qgis_server", "testlayer.shp").replace( + "\\", "/" + ), + ) os.chdir(curdir) def __test__path_writer(self, path): @@ -171,15 +200,18 @@ def testPathWriter(self): readerId = QgsPathResolver.setPathPreprocessor(self.__test_path_reader) writerId = QgsPathResolver.setPathWriter(self.__test__path_writer) - uri = os.path.join(TEST_DATA_DIR, 'points_gpkg.gpkg') + "|layername=points_gpkg|subset=1=1 /* foo */" + uri = ( + os.path.join(TEST_DATA_DIR, "points_gpkg.gpkg") + + "|layername=points_gpkg|subset=1=1 /* foo */" + ) - lines_layer = QgsVectorLayer(uri, 'Points', 'ogr') + lines_layer = QgsVectorLayer(uri, "Points", "ogr") self.assertTrue(lines_layer.isValid()) p = QgsProject() p.addMapLayer(lines_layer) # save project to a temporary file temp_path = tempfile.mkdtemp() - temp_project_path = os.path.join(temp_path, 'temp.qgs') + temp_project_path = os.path.join(temp_path, "temp.qgs") self.assertTrue(p.write(temp_project_path)) with open(temp_project_path) as f: @@ -187,7 +219,7 @@ def testPathWriter(self): p2 = QgsProject() self.assertTrue(p2.read(temp_project_path)) - l = p2.mapLayersByName('Points')[0] + l = p2.mapLayersByName("Points")[0] self.assertEqual(l.isValid(), True) self.assertEqual(l.source(), uri) @@ -195,5 +227,5 @@ def testPathWriter(self): QgsPathResolver.removePathWriter(writerId) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspdfrenderer.py b/tests/src/python/test_qgspdfrenderer.py index 4b9e756f01be..dc469830fe9a 100644 --- a/tests/src/python/test_qgspdfrenderer.py +++ b/tests/src/python/test_qgspdfrenderer.py @@ -11,17 +11,9 @@ import os import unittest -from qgis.PyQt.QtCore import ( - Qt, - QRectF -) -from qgis.PyQt.QtGui import ( - QImage, - QPainter -) -from qgis.core import ( - QgsPdfRenderer -) +from qgis.PyQt.QtCore import Qt, QRectF +from qgis.PyQt.QtGui import QImage, QPainter +from qgis.core import QgsPdfRenderer from qgis.testing import start_app, QgisTestCase from utilities import unitTestDataPath @@ -39,7 +31,7 @@ def control_path_prefix(cls): def test_non_pdf(self): """Test an invalid PDF""" - pdf_path = os.path.join(TEST_DATA_DIR, 'points.shp') + pdf_path = os.path.join(TEST_DATA_DIR, "points.shp") renderer = QgsPdfRenderer(pdf_path) self.assertEqual(renderer.pageCount(), 0) self.assertEqual(renderer.pageMediaBox(0), QRectF()) @@ -47,44 +39,36 @@ def test_non_pdf(self): image = QImage(600, 423, QImage.Format.Format_ARGB32_Premultiplied) image.fill(Qt.GlobalColor.transparent) painter = QPainter(image) - renderer.render( - painter, - QRectF(0, 0, 600, 423), - pageIndex=0) + renderer.render(painter, QRectF(0, 0, 600, 423), pageIndex=0) painter.end() def test_pdf_properties(self): """Test PDF properties""" - pdf_path = os.path.join(TEST_DATA_DIR, 'sample_pdf.pdf') + pdf_path = os.path.join(TEST_DATA_DIR, "sample_pdf.pdf") renderer = QgsPdfRenderer(pdf_path) self.assertEqual(renderer.pageCount(), 2) self.assertEqual(renderer.pageMediaBox(-1), QRectF()) - self.assertEqual(renderer.pageMediaBox(0), - QRectF(0.0, 0.0, 842.0, 595.0)) - self.assertEqual(renderer.pageMediaBox(1), - QRectF(0.0, 0.0, 420.0, 595.0)) + self.assertEqual(renderer.pageMediaBox(0), QRectF(0.0, 0.0, 842.0, 595.0)) + self.assertEqual(renderer.pageMediaBox(1), QRectF(0.0, 0.0, 420.0, 595.0)) self.assertEqual(renderer.pageMediaBox(2), QRectF()) def test_pdf_render(self): """Test rendering PDF""" - pdf_path = os.path.join(TEST_DATA_DIR, 'sample_pdf.pdf') + pdf_path = os.path.join(TEST_DATA_DIR, "sample_pdf.pdf") renderer = QgsPdfRenderer(pdf_path) image = QImage(600, 423, QImage.Format.Format_ARGB32_Premultiplied) image.fill(Qt.GlobalColor.transparent) painter = QPainter(image) - renderer.render( - painter, - QRectF(0, 0, 600, 423), - pageIndex=0) + renderer.render(painter, QRectF(0, 0, 600, 423), pageIndex=0) painter.end() self.assertTrue( self.image_check( - 'Render PDF page 1', - 'render_page1', + "Render PDF page 1", + "render_page1", image, - 'expected_render_page1', + "expected_render_page1", ) ) @@ -93,18 +77,15 @@ def test_pdf_render(self): image = QImage(423, 600, QImage.Format.Format_ARGB32_Premultiplied) image.fill(Qt.GlobalColor.transparent) painter = QPainter(image) - renderer.render( - painter, - QRectF(0, 0, 423, 600), - pageIndex=1) + renderer.render(painter, QRectF(0, 0, 423, 600), pageIndex=1) painter.end() self.assertTrue( self.image_check( - 'Render PDF page 2', - 'render_page2', + "Render PDF page 2", + "render_page2", image, - 'expected_render_page2', + "expected_render_page2", ) ) diff --git a/tests/src/python/test_qgspercentagewidget.py b/tests/src/python/test_qgspercentagewidget.py index a8c4ed16ca36..611821ecc857 100644 --- a/tests/src/python/test_qgspercentagewidget.py +++ b/tests/src/python/test_qgspercentagewidget.py @@ -6,7 +6,6 @@ (at your option) any later version. """ - from qgis.PyQt.QtTest import QSignalSpy from qgis.gui import QgsPercentageWidget import unittest @@ -18,7 +17,7 @@ class TestQgsPercentageWidget(QgisTestCase): def testGettersSetters(self): - """ test widget getters/setters """ + """test widget getters/setters""" w = QgsPercentageWidget() w.setValue(0.2) @@ -31,7 +30,7 @@ def testGettersSetters(self): self.assertEqual(w.value(), 1.0) def test_ChangedSignals(self): - """ test that signals are correctly emitted when setting value""" + """test that signals are correctly emitted when setting value""" w = QgsPercentageWidget() @@ -47,5 +46,5 @@ def test_ChangedSignals(self): self.assertEqual(spy[1][0], 1.0) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsplot.py b/tests/src/python/test_qgsplot.py index d8ef579ebe3a..ebad19dbc91b 100644 --- a/tests/src/python/test_qgsplot.py +++ b/tests/src/python/test_qgsplot.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '28/3/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "28/3/2022" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.PyQt.QtCore import QDir, QSizeF, Qt from qgis.PyQt.QtGui import QColor, QImage, QPainter @@ -24,7 +25,7 @@ QgsRenderContext, QgsSymbolLayer, QgsTextFormat, - Qgis + Qgis, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -36,32 +37,46 @@ class TestQgsPlot(QgisTestCase): @classmethod def control_path_prefix(cls): - return 'plot' + return "plot" def testPlot(self): plot = Qgs2DPlot() plot.setSize(QSizeF(600, 500)) - sym1 = QgsFillSymbol.createSimple({'color': '#fdbf6f', 'outline_style': 'no'}) + sym1 = QgsFillSymbol.createSimple({"color": "#fdbf6f", "outline_style": "no"}) plot.setChartBackgroundSymbol(sym1) sym2 = QgsFillSymbol.createSimple( - {'outline_color': '#0000ff', 'style': 'no', 'outline_style': 'solid', 'outline_width': 1}) + { + "outline_color": "#0000ff", + "style": "no", + "outline_style": "solid", + "outline_width": 1, + } + ) plot.setChartBorderSymbol(sym2) - sym3 = QgsLineSymbol.createSimple({'outline_color': '#00ffff', 'outline_width': 1}) + sym3 = QgsLineSymbol.createSimple( + {"outline_color": "#00ffff", "outline_width": 1} + ) plot.xAxis().setGridMajorSymbol(sym3) - sym4 = QgsLineSymbol.createSimple({'outline_color': '#ff00ff', 'outline_width': 0.5}) + sym4 = QgsLineSymbol.createSimple( + {"outline_color": "#ff00ff", "outline_width": 0.5} + ) plot.xAxis().setGridMinorSymbol(sym4) - sym3 = QgsLineSymbol.createSimple({'outline_color': '#0066ff', 'outline_width': 1}) + sym3 = QgsLineSymbol.createSimple( + {"outline_color": "#0066ff", "outline_width": 1} + ) plot.yAxis().setGridMajorSymbol(sym3) - sym4 = QgsLineSymbol.createSimple({'outline_color': '#ff4433', 'outline_width': 0.5}) + sym4 = QgsLineSymbol.createSimple( + {"outline_color": "#ff4433", "outline_width": 0.5} + ) plot.yAxis().setGridMinorSymbol(sym4) - font = QgsFontUtils.getStandardTestFont('Bold', 16) + font = QgsFontUtils.getStandardTestFont("Bold", 16) x_axis_format = QgsTextFormat.fromQFont(font) x_axis_format.setColor(QColor(255, 0, 0)) plot.xAxis().setTextFormat(x_axis_format) @@ -71,7 +86,7 @@ def testPlot(self): x_axis_number_format.setShowTrailingZeros(True) plot.xAxis().setNumericFormat(x_axis_number_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) y_axis_format = QgsTextFormat.fromQFont(font) y_axis_format.setColor(QColor(0, 255, 0)) plot.yAxis().setTextFormat(y_axis_format) @@ -96,7 +111,7 @@ def testPlot(self): plot.render(rc) painter.end() - assert self.image_check('plot_2d_base', 'plot_2d_base', im) + assert self.image_check("plot_2d_base", "plot_2d_base", im) plot_rect = plot.interiorPlotArea(rc) self.assertAlmostEqual(plot_rect.left(), 64.8, 0) @@ -108,26 +123,40 @@ def testPlotSuffixAll(self): plot = Qgs2DPlot() plot.setSize(QSizeF(600, 500)) - sym1 = QgsFillSymbol.createSimple({'color': '#fdbf6f', 'outline_style': 'no'}) + sym1 = QgsFillSymbol.createSimple({"color": "#fdbf6f", "outline_style": "no"}) plot.setChartBackgroundSymbol(sym1) sym2 = QgsFillSymbol.createSimple( - {'outline_color': '#0000ff', 'style': 'no', 'outline_style': 'solid', 'outline_width': 1}) + { + "outline_color": "#0000ff", + "style": "no", + "outline_style": "solid", + "outline_width": 1, + } + ) plot.setChartBorderSymbol(sym2) - sym3 = QgsLineSymbol.createSimple({'outline_color': '#00ffff', 'outline_width': 1}) + sym3 = QgsLineSymbol.createSimple( + {"outline_color": "#00ffff", "outline_width": 1} + ) plot.xAxis().setGridMajorSymbol(sym3) - sym4 = QgsLineSymbol.createSimple({'outline_color': '#ff00ff', 'outline_width': 0.5}) + sym4 = QgsLineSymbol.createSimple( + {"outline_color": "#ff00ff", "outline_width": 0.5} + ) plot.xAxis().setGridMinorSymbol(sym4) - sym3 = QgsLineSymbol.createSimple({'outline_color': '#0066ff', 'outline_width': 1}) + sym3 = QgsLineSymbol.createSimple( + {"outline_color": "#0066ff", "outline_width": 1} + ) plot.yAxis().setGridMajorSymbol(sym3) - sym4 = QgsLineSymbol.createSimple({'outline_color': '#ff4433', 'outline_width': 0.5}) + sym4 = QgsLineSymbol.createSimple( + {"outline_color": "#ff4433", "outline_width": 0.5} + ) plot.yAxis().setGridMinorSymbol(sym4) - font = QgsFontUtils.getStandardTestFont('Bold', 16) + font = QgsFontUtils.getStandardTestFont("Bold", 16) x_axis_format = QgsTextFormat.fromQFont(font) x_axis_format.setColor(QColor(255, 0, 0)) plot.xAxis().setTextFormat(x_axis_format) @@ -137,7 +166,7 @@ def testPlotSuffixAll(self): x_axis_number_format.setShowTrailingZeros(True) plot.xAxis().setNumericFormat(x_axis_number_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) y_axis_format = QgsTextFormat.fromQFont(font) y_axis_format.setColor(QColor(0, 255, 0)) plot.yAxis().setTextFormat(y_axis_format) @@ -152,9 +181,9 @@ def testPlotSuffixAll(self): plot.setYMinimum(2) plot.setYMaximum(12) - plot.xAxis().setLabelSuffix('x') + plot.xAxis().setLabelSuffix("x") plot.xAxis().setLabelSuffixPlacement(Qgis.PlotAxisSuffixPlacement.EveryLabel) - plot.yAxis().setLabelSuffix('y') + plot.yAxis().setLabelSuffix("y") plot.yAxis().setLabelSuffixPlacement(Qgis.PlotAxisSuffixPlacement.EveryLabel) im = QImage(600, 500, QImage.Format.Format_ARGB32) @@ -167,7 +196,9 @@ def testPlotSuffixAll(self): plot.render(rc) painter.end() - assert self.image_check('plot_2d_base_suffix_all', 'plot_2d_base_suffix_all', im) + assert self.image_check( + "plot_2d_base_suffix_all", "plot_2d_base_suffix_all", im + ) plot_rect = plot.interiorPlotArea(rc) self.assertAlmostEqual(plot_rect.left(), 80.46, 0) @@ -179,26 +210,40 @@ def testPlotSuffixFirst(self): plot = Qgs2DPlot() plot.setSize(QSizeF(600, 500)) - sym1 = QgsFillSymbol.createSimple({'color': '#fdbf6f', 'outline_style': 'no'}) + sym1 = QgsFillSymbol.createSimple({"color": "#fdbf6f", "outline_style": "no"}) plot.setChartBackgroundSymbol(sym1) sym2 = QgsFillSymbol.createSimple( - {'outline_color': '#0000ff', 'style': 'no', 'outline_style': 'solid', 'outline_width': 1}) + { + "outline_color": "#0000ff", + "style": "no", + "outline_style": "solid", + "outline_width": 1, + } + ) plot.setChartBorderSymbol(sym2) - sym3 = QgsLineSymbol.createSimple({'outline_color': '#00ffff', 'outline_width': 1}) + sym3 = QgsLineSymbol.createSimple( + {"outline_color": "#00ffff", "outline_width": 1} + ) plot.xAxis().setGridMajorSymbol(sym3) - sym4 = QgsLineSymbol.createSimple({'outline_color': '#ff00ff', 'outline_width': 0.5}) + sym4 = QgsLineSymbol.createSimple( + {"outline_color": "#ff00ff", "outline_width": 0.5} + ) plot.xAxis().setGridMinorSymbol(sym4) - sym3 = QgsLineSymbol.createSimple({'outline_color': '#0066ff', 'outline_width': 1}) + sym3 = QgsLineSymbol.createSimple( + {"outline_color": "#0066ff", "outline_width": 1} + ) plot.yAxis().setGridMajorSymbol(sym3) - sym4 = QgsLineSymbol.createSimple({'outline_color': '#ff4433', 'outline_width': 0.5}) + sym4 = QgsLineSymbol.createSimple( + {"outline_color": "#ff4433", "outline_width": 0.5} + ) plot.yAxis().setGridMinorSymbol(sym4) - font = QgsFontUtils.getStandardTestFont('Bold', 16) + font = QgsFontUtils.getStandardTestFont("Bold", 16) x_axis_format = QgsTextFormat.fromQFont(font) x_axis_format.setColor(QColor(255, 0, 0)) plot.xAxis().setTextFormat(x_axis_format) @@ -208,7 +253,7 @@ def testPlotSuffixFirst(self): x_axis_number_format.setShowTrailingZeros(True) plot.xAxis().setNumericFormat(x_axis_number_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) y_axis_format = QgsTextFormat.fromQFont(font) y_axis_format.setColor(QColor(0, 255, 0)) plot.yAxis().setTextFormat(y_axis_format) @@ -223,9 +268,9 @@ def testPlotSuffixFirst(self): plot.setYMinimum(2) plot.setYMaximum(12) - plot.xAxis().setLabelSuffix('x') + plot.xAxis().setLabelSuffix("x") plot.xAxis().setLabelSuffixPlacement(Qgis.PlotAxisSuffixPlacement.FirstLabel) - plot.yAxis().setLabelSuffix('y') + plot.yAxis().setLabelSuffix("y") plot.yAxis().setLabelSuffixPlacement(Qgis.PlotAxisSuffixPlacement.FirstLabel) im = QImage(600, 500, QImage.Format.Format_ARGB32) @@ -238,7 +283,9 @@ def testPlotSuffixFirst(self): plot.render(rc) painter.end() - assert self.image_check('plot_2d_base_suffix_first', 'plot_2d_base_suffix_first', im) + assert self.image_check( + "plot_2d_base_suffix_first", "plot_2d_base_suffix_first", im + ) plot_rect = plot.interiorPlotArea(rc) self.assertAlmostEqual(plot_rect.left(), 64.82, 0) @@ -250,26 +297,40 @@ def testPlotSuffixLast(self): plot = Qgs2DPlot() plot.setSize(QSizeF(600, 500)) - sym1 = QgsFillSymbol.createSimple({'color': '#fdbf6f', 'outline_style': 'no'}) + sym1 = QgsFillSymbol.createSimple({"color": "#fdbf6f", "outline_style": "no"}) plot.setChartBackgroundSymbol(sym1) sym2 = QgsFillSymbol.createSimple( - {'outline_color': '#0000ff', 'style': 'no', 'outline_style': 'solid', 'outline_width': 1}) + { + "outline_color": "#0000ff", + "style": "no", + "outline_style": "solid", + "outline_width": 1, + } + ) plot.setChartBorderSymbol(sym2) - sym3 = QgsLineSymbol.createSimple({'outline_color': '#00ffff', 'outline_width': 1}) + sym3 = QgsLineSymbol.createSimple( + {"outline_color": "#00ffff", "outline_width": 1} + ) plot.xAxis().setGridMajorSymbol(sym3) - sym4 = QgsLineSymbol.createSimple({'outline_color': '#ff00ff', 'outline_width': 0.5}) + sym4 = QgsLineSymbol.createSimple( + {"outline_color": "#ff00ff", "outline_width": 0.5} + ) plot.xAxis().setGridMinorSymbol(sym4) - sym3 = QgsLineSymbol.createSimple({'outline_color': '#0066ff', 'outline_width': 1}) + sym3 = QgsLineSymbol.createSimple( + {"outline_color": "#0066ff", "outline_width": 1} + ) plot.yAxis().setGridMajorSymbol(sym3) - sym4 = QgsLineSymbol.createSimple({'outline_color': '#ff4433', 'outline_width': 0.5}) + sym4 = QgsLineSymbol.createSimple( + {"outline_color": "#ff4433", "outline_width": 0.5} + ) plot.yAxis().setGridMinorSymbol(sym4) - font = QgsFontUtils.getStandardTestFont('Bold', 16) + font = QgsFontUtils.getStandardTestFont("Bold", 16) x_axis_format = QgsTextFormat.fromQFont(font) x_axis_format.setColor(QColor(255, 0, 0)) plot.xAxis().setTextFormat(x_axis_format) @@ -279,7 +340,7 @@ def testPlotSuffixLast(self): x_axis_number_format.setShowTrailingZeros(True) plot.xAxis().setNumericFormat(x_axis_number_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) y_axis_format = QgsTextFormat.fromQFont(font) y_axis_format.setColor(QColor(0, 255, 0)) plot.yAxis().setTextFormat(y_axis_format) @@ -294,9 +355,9 @@ def testPlotSuffixLast(self): plot.setYMinimum(2) plot.setYMaximum(12) - plot.xAxis().setLabelSuffix('x') + plot.xAxis().setLabelSuffix("x") plot.xAxis().setLabelSuffixPlacement(Qgis.PlotAxisSuffixPlacement.LastLabel) - plot.yAxis().setLabelSuffix('y') + plot.yAxis().setLabelSuffix("y") plot.yAxis().setLabelSuffixPlacement(Qgis.PlotAxisSuffixPlacement.LastLabel) im = QImage(600, 500, QImage.Format.Format_ARGB32) @@ -309,7 +370,9 @@ def testPlotSuffixLast(self): plot.render(rc) painter.end() - assert self.image_check('plot_2d_base_suffix_last', 'plot_2d_base_suffix_last', im) + assert self.image_check( + "plot_2d_base_suffix_last", "plot_2d_base_suffix_last", im + ) plot_rect = plot.interiorPlotArea(rc) self.assertAlmostEqual(plot_rect.left(), 80.46, 0) @@ -321,26 +384,40 @@ def testPlotSuffixFirstAndLast(self): plot = Qgs2DPlot() plot.setSize(QSizeF(600, 500)) - sym1 = QgsFillSymbol.createSimple({'color': '#fdbf6f', 'outline_style': 'no'}) + sym1 = QgsFillSymbol.createSimple({"color": "#fdbf6f", "outline_style": "no"}) plot.setChartBackgroundSymbol(sym1) sym2 = QgsFillSymbol.createSimple( - {'outline_color': '#0000ff', 'style': 'no', 'outline_style': 'solid', 'outline_width': 1}) + { + "outline_color": "#0000ff", + "style": "no", + "outline_style": "solid", + "outline_width": 1, + } + ) plot.setChartBorderSymbol(sym2) - sym3 = QgsLineSymbol.createSimple({'outline_color': '#00ffff', 'outline_width': 1}) + sym3 = QgsLineSymbol.createSimple( + {"outline_color": "#00ffff", "outline_width": 1} + ) plot.xAxis().setGridMajorSymbol(sym3) - sym4 = QgsLineSymbol.createSimple({'outline_color': '#ff00ff', 'outline_width': 0.5}) + sym4 = QgsLineSymbol.createSimple( + {"outline_color": "#ff00ff", "outline_width": 0.5} + ) plot.xAxis().setGridMinorSymbol(sym4) - sym3 = QgsLineSymbol.createSimple({'outline_color': '#0066ff', 'outline_width': 1}) + sym3 = QgsLineSymbol.createSimple( + {"outline_color": "#0066ff", "outline_width": 1} + ) plot.yAxis().setGridMajorSymbol(sym3) - sym4 = QgsLineSymbol.createSimple({'outline_color': '#ff4433', 'outline_width': 0.5}) + sym4 = QgsLineSymbol.createSimple( + {"outline_color": "#ff4433", "outline_width": 0.5} + ) plot.yAxis().setGridMinorSymbol(sym4) - font = QgsFontUtils.getStandardTestFont('Bold', 16) + font = QgsFontUtils.getStandardTestFont("Bold", 16) x_axis_format = QgsTextFormat.fromQFont(font) x_axis_format.setColor(QColor(255, 0, 0)) plot.xAxis().setTextFormat(x_axis_format) @@ -350,7 +427,7 @@ def testPlotSuffixFirstAndLast(self): x_axis_number_format.setShowTrailingZeros(True) plot.xAxis().setNumericFormat(x_axis_number_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) y_axis_format = QgsTextFormat.fromQFont(font) y_axis_format.setColor(QColor(0, 255, 0)) plot.yAxis().setTextFormat(y_axis_format) @@ -365,10 +442,14 @@ def testPlotSuffixFirstAndLast(self): plot.setYMinimum(2) plot.setYMaximum(12) - plot.xAxis().setLabelSuffix('x') - plot.xAxis().setLabelSuffixPlacement(Qgis.PlotAxisSuffixPlacement.FirstAndLastLabels) - plot.yAxis().setLabelSuffix('y') - plot.yAxis().setLabelSuffixPlacement(Qgis.PlotAxisSuffixPlacement.FirstAndLastLabels) + plot.xAxis().setLabelSuffix("x") + plot.xAxis().setLabelSuffixPlacement( + Qgis.PlotAxisSuffixPlacement.FirstAndLastLabels + ) + plot.yAxis().setLabelSuffix("y") + plot.yAxis().setLabelSuffixPlacement( + Qgis.PlotAxisSuffixPlacement.FirstAndLastLabels + ) im = QImage(600, 500, QImage.Format.Format_ARGB32) im.fill(Qt.GlobalColor.white) @@ -380,7 +461,11 @@ def testPlotSuffixFirstAndLast(self): plot.render(rc) painter.end() - assert self.image_check('plot_2d_base_suffix_first_and_last', 'plot_2d_base_suffix_first_and_last', im) + assert self.image_check( + "plot_2d_base_suffix_first_and_last", + "plot_2d_base_suffix_first_and_last", + im, + ) plot_rect = plot.interiorPlotArea(rc) self.assertAlmostEqual(plot_rect.left(), 80.46, 0) @@ -392,30 +477,44 @@ def testPlotIntervals(self): plot = Qgs2DPlot() plot.setSize(QSizeF(600, 500)) - sym1 = QgsFillSymbol.createSimple({'color': '#fdbf6f', 'outline_style': 'no'}) + sym1 = QgsFillSymbol.createSimple({"color": "#fdbf6f", "outline_style": "no"}) plot.setChartBackgroundSymbol(sym1) sym2 = QgsFillSymbol.createSimple( - {'outline_color': '#0000ff', 'style': 'no', 'outline_style': 'solid', 'outline_width': 1}) + { + "outline_color": "#0000ff", + "style": "no", + "outline_style": "solid", + "outline_width": 1, + } + ) plot.setChartBorderSymbol(sym2) - sym3 = QgsLineSymbol.createSimple({'outline_color': '#00ffff', 'outline_width': 1}) + sym3 = QgsLineSymbol.createSimple( + {"outline_color": "#00ffff", "outline_width": 1} + ) plot.xAxis().setGridMajorSymbol(sym3) - sym4 = QgsLineSymbol.createSimple({'outline_color': '#ff00ff', 'outline_width': 0.5}) + sym4 = QgsLineSymbol.createSimple( + {"outline_color": "#ff00ff", "outline_width": 0.5} + ) plot.xAxis().setGridMinorSymbol(sym4) - sym3 = QgsLineSymbol.createSimple({'outline_color': '#0066ff', 'outline_width': 1}) + sym3 = QgsLineSymbol.createSimple( + {"outline_color": "#0066ff", "outline_width": 1} + ) plot.yAxis().setGridMajorSymbol(sym3) - sym4 = QgsLineSymbol.createSimple({'outline_color': '#ff4433', 'outline_width': 0.5}) + sym4 = QgsLineSymbol.createSimple( + {"outline_color": "#ff4433", "outline_width": 0.5} + ) plot.yAxis().setGridMinorSymbol(sym4) - font = QgsFontUtils.getStandardTestFont('Bold', 16) + font = QgsFontUtils.getStandardTestFont("Bold", 16) x_axis_format = QgsTextFormat.fromQFont(font) plot.xAxis().setTextFormat(x_axis_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) y_axis_format = QgsTextFormat.fromQFont(font) plot.yAxis().setTextFormat(y_axis_format) @@ -444,43 +543,87 @@ def testPlotIntervals(self): plot.render(rc) painter.end() - assert self.image_check('plot_2d_intervals', 'plot_2d_intervals', im) + assert self.image_check("plot_2d_intervals", "plot_2d_intervals", im) def testPlotDataDefinedProperties(self): plot = Qgs2DPlot() plot.setSize(QSizeF(600, 500)) - sym1 = QgsFillSymbol.createSimple({'color': '#ffffff', 'outline_style': 'no'}) + sym1 = QgsFillSymbol.createSimple({"color": "#ffffff", "outline_style": "no"}) plot.setChartBackgroundSymbol(sym1) sym2 = QgsFillSymbol.createSimple( - {'outline_color': '#000000', 'style': 'no', 'outline_style': 'solid', 'outline_width': 1}) + { + "outline_color": "#000000", + "style": "no", + "outline_style": "solid", + "outline_width": 1, + } + ) plot.setChartBorderSymbol(sym2) - sym3 = QgsLineSymbol.createSimple({'outline_color': '#00ffff', 'outline_width': 1, 'capstyle': 'flat'}) - sym3[0].setDataDefinedProperty(QgsSymbolLayer.Property.PropertyStrokeWidth, QgsProperty.fromExpression('case when @plot_axis_value = 10 then 3 else 1 end')) + sym3 = QgsLineSymbol.createSimple( + {"outline_color": "#00ffff", "outline_width": 1, "capstyle": "flat"} + ) + sym3[0].setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyStrokeWidth, + QgsProperty.fromExpression( + "case when @plot_axis_value = 10 then 3 else 1 end" + ), + ) plot.xAxis().setGridMajorSymbol(sym3) - sym4 = QgsLineSymbol.createSimple({'outline_color': '#ff00ff', 'outline_width': 0.5, 'capstyle': 'flat'}) - sym4[0].setDataDefinedProperty(QgsSymbolLayer.Property.PropertyStrokeWidth, QgsProperty.fromExpression('case when @plot_axis_value = 6 then 3 else 0.5 end')) + sym4 = QgsLineSymbol.createSimple( + {"outline_color": "#ff00ff", "outline_width": 0.5, "capstyle": "flat"} + ) + sym4[0].setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyStrokeWidth, + QgsProperty.fromExpression( + "case when @plot_axis_value = 6 then 3 else 0.5 end" + ), + ) plot.xAxis().setGridMinorSymbol(sym4) - sym3 = QgsLineSymbol.createSimple({'outline_color': '#0066ff', 'outline_width': 1, 'capstyle': 'flat'}) - sym3[0].setDataDefinedProperty(QgsSymbolLayer.Property.PropertyStrokeWidth, QgsProperty.fromExpression('case when @plot_axis_value = 5 then 3 else 0.5 end')) + sym3 = QgsLineSymbol.createSimple( + {"outline_color": "#0066ff", "outline_width": 1, "capstyle": "flat"} + ) + sym3[0].setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyStrokeWidth, + QgsProperty.fromExpression( + "case when @plot_axis_value = 5 then 3 else 0.5 end" + ), + ) plot.yAxis().setGridMajorSymbol(sym3) - sym4 = QgsLineSymbol.createSimple({'outline_color': '#ff4433', 'outline_width': 0.5, 'capstyle': 'flat'}) - sym4[0].setDataDefinedProperty(QgsSymbolLayer.Property.PropertyStrokeWidth, QgsProperty.fromExpression('case when @plot_axis_value = 9 then 3 else 0.5 end')) + sym4 = QgsLineSymbol.createSimple( + {"outline_color": "#ff4433", "outline_width": 0.5, "capstyle": "flat"} + ) + sym4[0].setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyStrokeWidth, + QgsProperty.fromExpression( + "case when @plot_axis_value = 9 then 3 else 0.5 end" + ), + ) plot.yAxis().setGridMinorSymbol(sym4) - font = QgsFontUtils.getStandardTestFont('Bold', 16) + font = QgsFontUtils.getStandardTestFont("Bold", 16) x_axis_format = QgsTextFormat.fromQFont(font) - x_axis_format.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.Color, QgsProperty.fromExpression('case when @plot_axis_value %3 = 0 then \'#ff0000\' else \'#000000\' end')) + x_axis_format.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Color, + QgsProperty.fromExpression( + "case when @plot_axis_value %3 = 0 then '#ff0000' else '#000000' end" + ), + ) plot.xAxis().setTextFormat(x_axis_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) y_axis_format = QgsTextFormat.fromQFont(font) - y_axis_format.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.Color, QgsProperty.fromExpression('case when @plot_axis_value %4 = 0 then \'#0000ff\' else \'#000000\' end')) + y_axis_format.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Color, + QgsProperty.fromExpression( + "case when @plot_axis_value %4 = 0 then '#0000ff' else '#000000' end" + ), + ) plot.yAxis().setTextFormat(y_axis_format) plot.setXMinimum(3) @@ -499,7 +642,7 @@ def testPlotDataDefinedProperties(self): plot.render(rc) painter.end() - assert self.image_check('plot_2d_data_defined', 'plot_2d_data_defined', im) + assert self.image_check("plot_2d_data_defined", "plot_2d_data_defined", im) plot_rect = plot.interiorPlotArea(rc) self.assertAlmostEqual(plot_rect.left(), 44.71, 0) @@ -511,11 +654,11 @@ def testOptimiseIntervals(self): plot = Qgs2DPlot() plot.setSize(QSizeF(600, 500)) - font = QgsFontUtils.getStandardTestFont('Bold', 16) + font = QgsFontUtils.getStandardTestFont("Bold", 16) x_axis_format = QgsTextFormat.fromQFont(font) plot.xAxis().setTextFormat(x_axis_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) y_axis_format = QgsTextFormat.fromQFont(font) plot.yAxis().setTextFormat(y_axis_format) @@ -592,26 +735,40 @@ def test_read_write(self): plot = Qgs2DPlot() plot.setSize(QSizeF(600, 500)) - sym1 = QgsFillSymbol.createSimple({'color': '#fdbf6f', 'outline_style': 'no'}) + sym1 = QgsFillSymbol.createSimple({"color": "#fdbf6f", "outline_style": "no"}) plot.setChartBackgroundSymbol(sym1) sym2 = QgsFillSymbol.createSimple( - {'outline_color': '#0000ff', 'style': 'no', 'outline_style': 'solid', 'outline_width': 1}) + { + "outline_color": "#0000ff", + "style": "no", + "outline_style": "solid", + "outline_width": 1, + } + ) plot.setChartBorderSymbol(sym2) - sym3 = QgsLineSymbol.createSimple({'outline_color': '#00ffff', 'outline_width': 1}) + sym3 = QgsLineSymbol.createSimple( + {"outline_color": "#00ffff", "outline_width": 1} + ) plot.xAxis().setGridMajorSymbol(sym3) - sym4 = QgsLineSymbol.createSimple({'outline_color': '#ff00ff', 'outline_width': 0.5}) + sym4 = QgsLineSymbol.createSimple( + {"outline_color": "#ff00ff", "outline_width": 0.5} + ) plot.xAxis().setGridMinorSymbol(sym4) - sym3 = QgsLineSymbol.createSimple({'outline_color': '#0066ff', 'outline_width': 1}) + sym3 = QgsLineSymbol.createSimple( + {"outline_color": "#0066ff", "outline_width": 1} + ) plot.yAxis().setGridMajorSymbol(sym3) - sym4 = QgsLineSymbol.createSimple({'outline_color': '#ff4433', 'outline_width': 0.5}) + sym4 = QgsLineSymbol.createSimple( + {"outline_color": "#ff4433", "outline_width": 0.5} + ) plot.yAxis().setGridMinorSymbol(sym4) - font = QgsFontUtils.getStandardTestFont('Bold', 16) + font = QgsFontUtils.getStandardTestFont("Bold", 16) x_axis_format = QgsTextFormat.fromQFont(font) x_axis_format.setColor(QColor(255, 0, 0)) plot.xAxis().setTextFormat(x_axis_format) @@ -621,7 +778,7 @@ def test_read_write(self): x_axis_number_format.setShowTrailingZeros(True) plot.xAxis().setNumericFormat(x_axis_number_format) - font = QgsFontUtils.getStandardTestFont('Bold', 18) + font = QgsFontUtils.getStandardTestFont("Bold", 18) y_axis_format = QgsTextFormat.fromQFont(font) y_axis_format.setColor(QColor(0, 255, 0)) plot.yAxis().setTextFormat(y_axis_format) @@ -644,15 +801,15 @@ def test_read_write(self): plot.xAxis().setLabelInterval(32) plot.yAxis().setLabelInterval(23) - plot.xAxis().setLabelSuffix('km') - plot.xAxis().setLabelSuffixPlacement( - Qgis.PlotAxisSuffixPlacement.LastLabel) - plot.yAxis().setLabelSuffix('m') + plot.xAxis().setLabelSuffix("km") + plot.xAxis().setLabelSuffixPlacement(Qgis.PlotAxisSuffixPlacement.LastLabel) + plot.yAxis().setLabelSuffix("m") plot.yAxis().setLabelSuffixPlacement( - Qgis.PlotAxisSuffixPlacement.FirstAndLastLabels) + Qgis.PlotAxisSuffixPlacement.FirstAndLastLabels + ) doc = QDomDocument() - elem = doc.createElement('test') + elem = doc.createElement("test") plot.writeXml(elem, doc, QgsReadWriteContext()) res = Qgs2DPlot() @@ -674,24 +831,27 @@ def test_read_write(self): self.assertEqual(res.xAxis().numericFormat().numberDecimalPlaces(), 1) self.assertTrue(res.yAxis().numericFormat().showPlusSign()) - self.assertEqual(res.xAxis().textFormat().color().name(), '#ff0000') - self.assertEqual(res.yAxis().textFormat().color().name(), '#00ff00') + self.assertEqual(res.xAxis().textFormat().color().name(), "#ff0000") + self.assertEqual(res.yAxis().textFormat().color().name(), "#00ff00") - self.assertEqual(res.chartBackgroundSymbol().color().name(), '#fdbf6f') - self.assertEqual(res.chartBorderSymbol().color().name(), '#0000ff') + self.assertEqual(res.chartBackgroundSymbol().color().name(), "#fdbf6f") + self.assertEqual(res.chartBorderSymbol().color().name(), "#0000ff") - self.assertEqual(res.xAxis().gridMinorSymbol().color().name(), '#ff00ff') - self.assertEqual(res.xAxis().gridMajorSymbol().color().name(), '#00ffff') - self.assertEqual(res.yAxis().gridMinorSymbol().color().name(), '#ff4433') - self.assertEqual(res.yAxis().gridMajorSymbol().color().name(), '#0066ff') + self.assertEqual(res.xAxis().gridMinorSymbol().color().name(), "#ff00ff") + self.assertEqual(res.xAxis().gridMajorSymbol().color().name(), "#00ffff") + self.assertEqual(res.yAxis().gridMinorSymbol().color().name(), "#ff4433") + self.assertEqual(res.yAxis().gridMajorSymbol().color().name(), "#0066ff") - self.assertEqual(res.xAxis().labelSuffix(), 'km') - self.assertEqual(res.xAxis().labelSuffixPlacement(), - Qgis.PlotAxisSuffixPlacement.LastLabel) - self.assertEqual(res.yAxis().labelSuffix(), 'm') - self.assertEqual(res.yAxis().labelSuffixPlacement(), - Qgis.PlotAxisSuffixPlacement.FirstAndLastLabels) + self.assertEqual(res.xAxis().labelSuffix(), "km") + self.assertEqual( + res.xAxis().labelSuffixPlacement(), Qgis.PlotAxisSuffixPlacement.LastLabel + ) + self.assertEqual(res.yAxis().labelSuffix(), "m") + self.assertEqual( + res.yAxis().labelSuffixPlacement(), + Qgis.PlotAxisSuffixPlacement.FirstAndLastLabels, + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspoint.py b/tests/src/python/test_qgspoint.py index 7366779b31a2..bfcfd629fa45 100644 --- a/tests/src/python/test_qgspoint.py +++ b/tests/src/python/test_qgspoint.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Tim Sutton' -__date__ = '20/08/2012' -__copyright__ = 'Copyright 2012, The QGIS Project' + +__author__ = "Tim Sutton" +__date__ = "20/08/2012" +__copyright__ = "Copyright 2012, The QGIS Project" from qgis.PyQt.QtCore import QPointF from qgis.core import QgsPoint, QgsPointXY, QgsWkbTypes @@ -32,7 +33,7 @@ def test_Point(self): self.assertEqual(myExpectedValue, myActualValue) def test_pointToString(self): - myExpectedValue = '10, 10' + myExpectedValue = "10, 10" myActualValue = self.mPoint.toString() self.assertEqual(myExpectedValue, myActualValue) @@ -50,36 +51,76 @@ def test_hash(self): def test_issue_32443(self): p = QgsPoint() - self.assertTrue(p.wkbType() == QgsWkbTypes.Type.Point and p.x() != p.x() and p.y() != p.y()) + self.assertTrue( + p.wkbType() == QgsWkbTypes.Type.Point and p.x() != p.x() and p.y() != p.y() + ) # ctor from QgsPointXY should be available p = QgsPoint(QgsPointXY(1, 2)) - self.assertTrue(p.wkbType() == QgsWkbTypes.Type.Point and p.x() == 1 and p.y() == 2) + self.assertTrue( + p.wkbType() == QgsWkbTypes.Type.Point and p.x() == 1 and p.y() == 2 + ) # ctor from QPointF should be available p = QgsPoint(QPointF(1, 2)) - self.assertTrue(p.wkbType() == QgsWkbTypes.Type.Point and p.x() == 1 and p.y() == 2) + self.assertTrue( + p.wkbType() == QgsWkbTypes.Type.Point and p.x() == 1 and p.y() == 2 + ) p = QgsPoint(1, 2) - self.assertTrue(p.wkbType() == QgsWkbTypes.Type.Point and p.x() == 1 and p.y() == 2) + self.assertTrue( + p.wkbType() == QgsWkbTypes.Type.Point and p.x() == 1 and p.y() == 2 + ) p = QgsPoint(1, 2, 3) - self.assertTrue(p.wkbType() == QgsWkbTypes.Type.PointZ and p.x() == 1 and p.y() == 2 and p.z() == 3) + self.assertTrue( + p.wkbType() == QgsWkbTypes.Type.PointZ + and p.x() == 1 + and p.y() == 2 + and p.z() == 3 + ) p = QgsPoint(1, 2, z=3) - self.assertTrue(p.wkbType() == QgsWkbTypes.Type.PointZ and p.x() == 1 and p.y() == 2 and p.z() == 3) + self.assertTrue( + p.wkbType() == QgsWkbTypes.Type.PointZ + and p.x() == 1 + and p.y() == 2 + and p.z() == 3 + ) p = QgsPoint(1, 2, m=3) - self.assertTrue(p.wkbType() == QgsWkbTypes.Type.PointM and p.x() == 1 and p.y() == 2 and p.m() == 3) + self.assertTrue( + p.wkbType() == QgsWkbTypes.Type.PointM + and p.x() == 1 + and p.y() == 2 + and p.m() == 3 + ) p = QgsPoint(1, 2, wkbType=QgsWkbTypes.Type.PointM) - self.assertTrue(p.wkbType() == QgsWkbTypes.Type.PointM and p.x() == 1 and p.y() == 2 and p.m() != p.m()) + self.assertTrue( + p.wkbType() == QgsWkbTypes.Type.PointM + and p.x() == 1 + and p.y() == 2 + and p.m() != p.m() + ) p = QgsPoint(1, 2, 3, 4) - self.assertTrue(p.wkbType() == QgsWkbTypes.Type.PointZM and p.x() == 1 and p.y() == 2 and p.z() == 3 and p.m() == 4) + self.assertTrue( + p.wkbType() == QgsWkbTypes.Type.PointZM + and p.x() == 1 + and p.y() == 2 + and p.z() == 3 + and p.m() == 4 + ) p = QgsPoint(1, 2, m=4, z=3) - self.assertTrue(p.wkbType() == QgsWkbTypes.Type.PointZM and p.x() == 1 and p.y() == 2 and p.z() == 3 and p.m() == 4) + self.assertTrue( + p.wkbType() == QgsWkbTypes.Type.PointZM + and p.x() == 1 + and p.y() == 2 + and p.z() == 3 + and p.m() == 4 + ) def test_empty_QgsPointXY(self): p = QgsPoint(QgsPointXY()) @@ -92,7 +133,7 @@ def testInvalidConstructorArguments(self): """Test GH #34557""" with self.assertRaises(TypeError): - point_0 = QgsPoint('a string') + point_0 = QgsPoint("a string") with self.assertRaises(TypeError): point_a = QgsPoint(10, 20) @@ -172,13 +213,11 @@ def test_simplify_by_distance(self): test simplifyByDistance """ # for points this is just a clone - p = QgsPoint(1.1, - 2.2) - self.assertEqual(p.simplifyByDistance(0.5), QgsPoint(1.1, - 2.2)) + p = QgsPoint(1.1, 2.2) + self.assertEqual(p.simplifyByDistance(0.5), QgsPoint(1.1, 2.2)) p = QgsPoint(1.1, 2.2, 3.3, 4.4) self.assertEqual(p.simplifyByDistance(0.5), QgsPoint(1.1, 2.2, 3.3, 4.4)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspointcloudattributebyramprenderer.py b/tests/src/python/test_qgspointcloudattributebyramprenderer.py index c4572d3b1bcd..b12f89d592b8 100644 --- a/tests/src/python/test_qgspointcloudattributebyramprenderer.py +++ b/tests/src/python/test_qgspointcloudattributebyramprenderer.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '09/11/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "09/11/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QDir, QSize, Qt from qgis.PyQt.QtXml import QDomDocument @@ -44,11 +45,16 @@ class TestQgsPointCloudAttributeByRampRenderer(QgisTestCase): @classmethod def control_path_prefix(cls): - return 'pointcloudrenderer' + return "pointcloudrenderer" - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testSetLayer(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/norgb/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/norgb/ept.json", "test", "ept" + ) self.assertTrue(layer.isValid()) # test that a point cloud with no RGB attributes is automatically assigned the ramp renderer @@ -60,8 +66,8 @@ def testSetLayer(self): def testBasic(self): renderer = QgsPointCloudAttributeByRampRenderer() - renderer.setAttribute('attr') - self.assertEqual(renderer.attribute(), 'attr') + renderer.setAttribute("attr") + self.assertEqual(renderer.attribute(), "attr") renderer.setMinimum(5) self.assertEqual(renderer.minimum(), 5) renderer.setMaximum(15) @@ -80,93 +86,120 @@ def testBasic(self): rr = renderer.clone() self.assertEqual(rr.maximumScreenError(), 18) - self.assertEqual(rr.maximumScreenErrorUnit(), QgsUnitTypes.RenderUnit.RenderInches) + self.assertEqual( + rr.maximumScreenErrorUnit(), QgsUnitTypes.RenderUnit.RenderInches + ) self.assertEqual(rr.pointSize(), 13) self.assertEqual(rr.pointSizeUnit(), QgsUnitTypes.RenderUnit.RenderPoints) self.assertEqual(rr.pointSizeMapUnitScale().minScale, 1000) self.assertEqual(rr.pointSizeMapUnitScale().maxScale, 2000) - self.assertEqual(rr.attribute(), 'attr') + self.assertEqual(rr.attribute(), "attr") self.assertEqual(rr.minimum(), 5) self.assertEqual(rr.maximum(), 15) self.assertEqual(rr.colorRampShader().minimumValue(), 20) self.assertEqual(rr.colorRampShader().maximumValue(), 30) cloned_shader = rr.colorRampShader() original_shader = renderer.colorRampShader() - self.assertEqual(cloned_shader.sourceColorRamp().color1().name(), - original_shader.sourceColorRamp().color1().name()) - self.assertEqual(cloned_shader.sourceColorRamp().color2().name(), - original_shader.sourceColorRamp().color2().name()) + self.assertEqual( + cloned_shader.sourceColorRamp().color1().name(), + original_shader.sourceColorRamp().color1().name(), + ) + self.assertEqual( + cloned_shader.sourceColorRamp().color2().name(), + original_shader.sourceColorRamp().color2().name(), + ) doc = QDomDocument("testdoc") elem = renderer.save(doc, QgsReadWriteContext()) r2 = QgsPointCloudAttributeByRampRenderer.create(elem, QgsReadWriteContext()) self.assertEqual(r2.maximumScreenError(), 18) - self.assertEqual(r2.maximumScreenErrorUnit(), QgsUnitTypes.RenderUnit.RenderInches) + self.assertEqual( + r2.maximumScreenErrorUnit(), QgsUnitTypes.RenderUnit.RenderInches + ) self.assertEqual(r2.pointSize(), 13) self.assertEqual(r2.pointSizeUnit(), QgsUnitTypes.RenderUnit.RenderPoints) self.assertEqual(r2.pointSizeMapUnitScale().minScale, 1000) self.assertEqual(r2.pointSizeMapUnitScale().maxScale, 2000) - self.assertEqual(r2.attribute(), 'attr') + self.assertEqual(r2.attribute(), "attr") self.assertEqual(r2.minimum(), 5) self.assertEqual(r2.maximum(), 15) restored_shader = r2.colorRampShader() self.assertEqual(restored_shader.minimumValue(), 20) self.assertEqual(restored_shader.maximumValue(), 30) - self.assertEqual(restored_shader.sourceColorRamp().color1().name(), - original_shader.sourceColorRamp().color1().name()) - self.assertEqual(restored_shader.sourceColorRamp().color2().name(), - original_shader.sourceColorRamp().color2().name()) + self.assertEqual( + restored_shader.sourceColorRamp().color1().name(), + original_shader.sourceColorRamp().color1().name(), + ) + self.assertEqual( + restored_shader.sourceColorRamp().color2().name(), + original_shader.sourceColorRamp().color2().name(), + ) def testUsedAttributes(self): renderer = QgsPointCloudAttributeByRampRenderer() - renderer.setAttribute('attr') + renderer.setAttribute("attr") rc = QgsRenderContext() prc = QgsPointCloudRenderContext(rc, QgsVector3D(), QgsVector3D(), 1, 0) - self.assertEqual(renderer.usedAttributes(prc), {'attr'}) + self.assertEqual(renderer.usedAttributes(prc), {"attr"}) def testLegend(self): renderer = QgsPointCloudAttributeByRampRenderer() - renderer.setAttribute('Intensity') + renderer.setAttribute("Intensity") renderer.setMinimum(200) renderer.setMaximum(800) ramp = QgsStyle.defaultStyle().colorRamp("Viridis") shader = QgsColorRampShader(200, 800, ramp.clone()) - shader.setClassificationMode(QgsColorRampShader.ClassificationMode.EqualInterval) + shader.setClassificationMode( + QgsColorRampShader.ClassificationMode.EqualInterval + ) shader.classifyColorRamp(classes=4) renderer.setColorRampShader(shader) - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) layer_tree_layer = QgsLayerTreeLayer(layer) nodes = renderer.createLegendNodes(layer_tree_layer) self.assertEqual(len(nodes), 2) self.assertIsInstance(nodes[0], QgsSimpleLegendNode) - self.assertEqual(nodes[0].data(Qt.ItemDataRole.DisplayRole), 'Intensity') + self.assertEqual(nodes[0].data(Qt.ItemDataRole.DisplayRole), "Intensity") self.assertIsInstance(nodes[1], QgsColorRampLegendNode) - self.assertEqual(nodes[1].ramp().color1().name(), '#440154') - self.assertEqual(nodes[1].ramp().color2().name(), '#fde725') + self.assertEqual(nodes[1].ramp().color1().name(), "#440154") + self.assertEqual(nodes[1].ramp().color2().name(), "#fde725") shader = QgsColorRampShader(200, 600, ramp.clone()) - shader.setClassificationMode(QgsColorRampShader.ClassificationMode.EqualInterval) + shader.setClassificationMode( + QgsColorRampShader.ClassificationMode.EqualInterval + ) shader.setColorRampType(QgsColorRampShader.Type.Exact) shader.classifyColorRamp(classes=2) renderer.setColorRampShader(shader) nodes = renderer.createLegendNodes(layer_tree_layer) self.assertEqual(len(nodes), 3) - self.assertEqual(nodes[0].data(Qt.ItemDataRole.DisplayRole), 'Intensity') - self.assertEqual(nodes[1].data(Qt.ItemDataRole.DisplayRole), '200') - self.assertEqual(nodes[2].data(Qt.ItemDataRole.DisplayRole), '600') - - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + self.assertEqual(nodes[0].data(Qt.ItemDataRole.DisplayRole), "Intensity") + self.assertEqual(nodes[1].data(Qt.ItemDataRole.DisplayRole), "200") + self.assertEqual(nodes[2].data(Qt.ItemDataRole.DisplayRole), "600") + + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRender(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) renderer = QgsPointCloudAttributeByRampRenderer() - renderer.setAttribute('Intensity') + renderer.setAttribute("Intensity") renderer.setMinimum(200) renderer.setMaximum(1000) ramp = QgsStyle.defaultStyle().colorRamp("Viridis") @@ -187,16 +220,23 @@ def testRender(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('ramp_render', 'ramp_render', mapsettings) + self.render_map_settings_check("ramp_render", "ramp_render", mapsettings) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderX(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) renderer = QgsPointCloudAttributeByRampRenderer() - renderer.setAttribute('X') + renderer.setAttribute("X") renderer.setMinimum(498062.00000) renderer.setMaximum(498067.39000) ramp = QgsStyle.defaultStyle().colorRamp("Viridis") @@ -217,16 +257,23 @@ def testRenderX(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('ramp_xrender', 'ramp_xrender', mapsettings) + self.render_map_settings_check("ramp_xrender", "ramp_xrender", mapsettings) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderY(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) renderer = QgsPointCloudAttributeByRampRenderer() - renderer.setAttribute('Y') + renderer.setAttribute("Y") renderer.setMinimum(7050992.84000) renderer.setMaximum(7050997.04000) ramp = QgsStyle.defaultStyle().colorRamp("Viridis") @@ -247,16 +294,23 @@ def testRenderY(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('ramp_yrender', 'ramp_yrender', mapsettings) + self.render_map_settings_check("ramp_yrender", "ramp_yrender", mapsettings) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderZ(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) renderer = QgsPointCloudAttributeByRampRenderer() - renderer.setAttribute('Z') + renderer.setAttribute("Z") renderer.setMinimum(74.34000) renderer.setMaximum(75) ramp = QgsStyle.defaultStyle().colorRamp("Viridis") @@ -277,16 +331,23 @@ def testRenderZ(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('ramp_zrender', 'ramp_zrender', mapsettings) + self.render_map_settings_check("ramp_zrender", "ramp_zrender", mapsettings) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderCrsTransform(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) renderer = QgsPointCloudAttributeByRampRenderer() - renderer.setAttribute('Intensity') + renderer.setAttribute("Intensity") renderer.setMinimum(200) renderer.setMaximum(1000) ramp = QgsStyle.defaultStyle().colorRamp("Viridis") @@ -301,21 +362,32 @@ def testRenderCrsTransform(self): mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) - mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) - mapsettings.setExtent(QgsRectangle(152.980508492, -26.662023491, 152.980586020, -26.662071137)) + mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) + mapsettings.setExtent( + QgsRectangle(152.980508492, -26.662023491, 152.980586020, -26.662071137) + ) mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('ramp_render_crs_transform', 'ramp_render_crs_transform', mapsettings) + self.render_map_settings_check( + "ramp_render_crs_transform", "ramp_render_crs_transform", mapsettings + ) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderPointSize(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) renderer = QgsPointCloudAttributeByRampRenderer() - renderer.setAttribute('Intensity') + renderer.setAttribute("Intensity") renderer.setMinimum(200) renderer.setMaximum(1000) ramp = QgsStyle.defaultStyle().colorRamp("Viridis") @@ -324,7 +396,7 @@ def testRenderPointSize(self): renderer.setColorRampShader(shader) layer.setRenderer(renderer) - layer.renderer().setPointSize(.15) + layer.renderer().setPointSize(0.15) layer.renderer().setPointSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) mapsettings = QgsMapSettings() @@ -335,16 +407,25 @@ def testRenderPointSize(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('ramp_pointsize', 'ramp_pointsize', mapsettings) + self.render_map_settings_check( + "ramp_pointsize", "ramp_pointsize", mapsettings + ) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderZRange(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) renderer = QgsPointCloudAttributeByRampRenderer() - renderer.setAttribute('Intensity') + renderer.setAttribute("Intensity") renderer.setMinimum(200) renderer.setMaximum(1000) ramp = QgsStyle.defaultStyle().colorRamp("Viridis") @@ -365,16 +446,23 @@ def testRenderZRange(self): mapsettings.setZRange(QgsDoubleRange(74.7, 75)) self.assertTrue( - self.render_map_settings_check('ramp_zfilter', 'ramp_zfilter', mapsettings) + self.render_map_settings_check("ramp_zfilter", "ramp_zfilter", mapsettings) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderTopToBottom(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) renderer = QgsPointCloudAttributeByRampRenderer() - renderer.setAttribute('Intensity') + renderer.setAttribute("Intensity") renderer.setMinimum(200) renderer.setMaximum(1000) ramp = QgsStyle.defaultStyle().colorRamp("Viridis") @@ -396,16 +484,25 @@ def testRenderTopToBottom(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('ramp_top_to_bottom', 'ramp_top_to_bottom', mapsettings) + self.render_map_settings_check( + "ramp_top_to_bottom", "ramp_top_to_bottom", mapsettings + ) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderBottomToTop(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) renderer = QgsPointCloudAttributeByRampRenderer() - renderer.setAttribute('Intensity') + renderer.setAttribute("Intensity") renderer.setMinimum(200) renderer.setMaximum(1000) ramp = QgsStyle.defaultStyle().colorRamp("Viridis") @@ -427,16 +524,25 @@ def testRenderBottomToTop(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('ramp_bottom_to_top', 'ramp_bottom_to_top', mapsettings) + self.render_map_settings_check( + "ramp_bottom_to_top", "ramp_bottom_to_top", mapsettings + ) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderTriangles(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) renderer = QgsPointCloudAttributeByRampRenderer() - renderer.setAttribute('Intensity') + renderer.setAttribute("Intensity") renderer.setMinimum(200) renderer.setMaximum(1000) ramp = QgsStyle.defaultStyle().colorRamp("Viridis") @@ -458,9 +564,11 @@ def testRenderTriangles(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('ramp_triangles', 'ramp_triangles', mapsettings) + self.render_map_settings_check( + "ramp_triangles", "ramp_triangles", mapsettings + ) ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspointcloudattributecombobox.py b/tests/src/python/test_qgspointcloudattributecombobox.py index ee4273f3bcd3..5d16bf1db3da 100644 --- a/tests/src/python/test_qgspointcloudattributecombobox.py +++ b/tests/src/python/test_qgspointcloudattributecombobox.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '09/11/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "09/11/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy from qgis.core import ( @@ -28,24 +29,37 @@ def create_attributes(): collection = QgsPointCloudAttributeCollection() - collection.push_back(QgsPointCloudAttribute('x', QgsPointCloudAttribute.DataType.Float)) - collection.push_back(QgsPointCloudAttribute('y', QgsPointCloudAttribute.DataType.Float)) - collection.push_back(QgsPointCloudAttribute('z', QgsPointCloudAttribute.DataType.Float)) - collection.push_back(QgsPointCloudAttribute('cat', QgsPointCloudAttribute.DataType.Char)) - collection.push_back(QgsPointCloudAttribute('red', QgsPointCloudAttribute.DataType.Int32)) + collection.push_back( + QgsPointCloudAttribute("x", QgsPointCloudAttribute.DataType.Float) + ) + collection.push_back( + QgsPointCloudAttribute("y", QgsPointCloudAttribute.DataType.Float) + ) + collection.push_back( + QgsPointCloudAttribute("z", QgsPointCloudAttribute.DataType.Float) + ) + collection.push_back( + QgsPointCloudAttribute("cat", QgsPointCloudAttribute.DataType.Char) + ) + collection.push_back( + QgsPointCloudAttribute("red", QgsPointCloudAttribute.DataType.Int32) + ) return collection class TestQgsPointCloudAttributeComboBox(QgisTestCase): def testGettersSetters(self): - """ test combobox getters/setters """ + """test combobox getters/setters""" w = QgsPointCloudAttributeComboBox() w.setAttributes(create_attributes()) - self.assertEqual([a.name() for a in w.attributes().attributes()], ['x', 'y', 'z', 'cat', 'red']) + self.assertEqual( + [a.name() for a in w.attributes().attributes()], + ["x", "y", "z", "cat", "red"], + ) - w.setAttribute('red') - self.assertEqual(w.currentAttribute(), 'red') + w.setAttribute("red") + self.assertEqual(w.currentAttribute(), "red") self.assertIsNone(w.layer()) @@ -54,15 +68,15 @@ def testSignals(self): w.setAttributes(create_attributes()) spy = QSignalSpy(w.attributeChanged) - w.setAttribute('z') + w.setAttribute("z") self.assertEqual(len(spy), 1) - self.assertEqual(spy[-1][0], 'z') - w.setAttribute('z') + self.assertEqual(spy[-1][0], "z") + w.setAttribute("z") self.assertEqual(len(spy), 1) - self.assertEqual(spy[-1][0], 'z') - w.setAttribute('red') + self.assertEqual(spy[-1][0], "z") + w.setAttribute("red") self.assertEqual(len(spy), 2) - self.assertEqual(spy[-1][0], 'red') + self.assertEqual(spy[-1][0], "red") w.setAttribute(None) self.assertEqual(len(spy), 3) self.assertEqual(spy[-1][0], None) @@ -70,31 +84,69 @@ def testSignals(self): self.assertEqual(len(spy), 3) self.assertEqual(spy[-1][0], None) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testSetLayer(self): cb = QgsPointCloudAttributeComboBox() self.assertIsNone(cb.layer()) - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) cb.setLayer(layer) self.assertEqual(cb.layer(), layer) - self.assertEqual([cb.itemText(i) for i in range(cb.count())], ['X', 'Y', 'Z', 'Intensity', 'ReturnNumber', 'NumberOfReturns', 'ScanDirectionFlag', 'EdgeOfFlightLine', 'Classification', 'ScanAngleRank', 'UserData', 'PointSourceId', 'GpsTime', 'Red', 'Green', 'Blue']) + self.assertEqual( + [cb.itemText(i) for i in range(cb.count())], + [ + "X", + "Y", + "Z", + "Intensity", + "ReturnNumber", + "NumberOfReturns", + "ScanDirectionFlag", + "EdgeOfFlightLine", + "Classification", + "ScanAngleRank", + "UserData", + "PointSourceId", + "GpsTime", + "Red", + "Green", + "Blue", + ], + ) def testFilter(self): cb = QgsPointCloudAttributeComboBox() cb.setAttributes(create_attributes()) - self.assertEqual([cb.itemText(i) for i in range(cb.count())], ['x', 'y', 'z', 'cat', 'red']) + self.assertEqual( + [cb.itemText(i) for i in range(cb.count())], ["x", "y", "z", "cat", "red"] + ) cb.setFilters(QgsPointCloudAttributeProxyModel.Filter.Numeric) - self.assertEqual([cb.itemText(i) for i in range(cb.count())], ['x', 'y', 'z', 'red']) + self.assertEqual( + [cb.itemText(i) for i in range(cb.count())], ["x", "y", "z", "red"] + ) self.assertEqual(cb.filters(), QgsPointCloudAttributeProxyModel.Filter.Numeric) cb.setFilters(QgsPointCloudAttributeProxyModel.Filter.Char) - self.assertEqual([cb.itemText(i) for i in range(cb.count())], ['cat']) + self.assertEqual([cb.itemText(i) for i in range(cb.count())], ["cat"]) self.assertEqual(cb.filters(), QgsPointCloudAttributeProxyModel.Filter.Char) - cb.setFilters(QgsPointCloudAttributeProxyModel.Filter.Char | QgsPointCloudAttributeProxyModel.Filter.Int32) - self.assertEqual([cb.itemText(i) for i in range(cb.count())], ['cat', 'red']) - self.assertEqual(cb.filters(), QgsPointCloudAttributeProxyModel.Filter.Char | QgsPointCloudAttributeProxyModel.Filter.Int32) - - -if __name__ == '__main__': + cb.setFilters( + QgsPointCloudAttributeProxyModel.Filter.Char + | QgsPointCloudAttributeProxyModel.Filter.Int32 + ) + self.assertEqual([cb.itemText(i) for i in range(cb.count())], ["cat", "red"]) + self.assertEqual( + cb.filters(), + QgsPointCloudAttributeProxyModel.Filter.Char + | QgsPointCloudAttributeProxyModel.Filter.Int32, + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspointcloudattributemodel.py b/tests/src/python/test_qgspointcloudattributemodel.py index a4d34b02b2fa..a482f6740eee 100644 --- a/tests/src/python/test_qgspointcloudattributemodel.py +++ b/tests/src/python/test_qgspointcloudattributemodel.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '09/11/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "09/11/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import Qt from qgis.core import ( @@ -28,18 +29,28 @@ def create_attributes(): collection = QgsPointCloudAttributeCollection() - collection.push_back(QgsPointCloudAttribute('x', QgsPointCloudAttribute.DataType.Float)) - collection.push_back(QgsPointCloudAttribute('y', QgsPointCloudAttribute.DataType.Float)) - collection.push_back(QgsPointCloudAttribute('z', QgsPointCloudAttribute.DataType.Float)) - collection.push_back(QgsPointCloudAttribute('cat', QgsPointCloudAttribute.DataType.Char)) - collection.push_back(QgsPointCloudAttribute('red', QgsPointCloudAttribute.DataType.Int32)) + collection.push_back( + QgsPointCloudAttribute("x", QgsPointCloudAttribute.DataType.Float) + ) + collection.push_back( + QgsPointCloudAttribute("y", QgsPointCloudAttribute.DataType.Float) + ) + collection.push_back( + QgsPointCloudAttribute("z", QgsPointCloudAttribute.DataType.Float) + ) + collection.push_back( + QgsPointCloudAttribute("cat", QgsPointCloudAttribute.DataType.Char) + ) + collection.push_back( + QgsPointCloudAttribute("red", QgsPointCloudAttribute.DataType.Int32) + ) return collection class TestQgsFieldModel(QgisTestCase): def testGettersSetters(self): - """ test model getters/setters """ + """test model getters/setters""" m = QgsPointCloudAttributeModel() self.assertEqual(m.attributes().count(), 0) @@ -50,30 +61,33 @@ def testGettersSetters(self): attributes = create_attributes() m.setAttributes(attributes) - self.assertEqual([a.name() for a in m.attributes().attributes()], ['x', 'y', 'z', 'cat', 'red']) + self.assertEqual( + [a.name() for a in m.attributes().attributes()], + ["x", "y", "z", "cat", "red"], + ) def testIndexFromName(self): m = QgsPointCloudAttributeModel() - i = m.indexFromName('fldtxt') + i = m.indexFromName("fldtxt") self.assertFalse(i.isValid()) m.setAttributes(create_attributes()) - i = m.indexFromName('fldtxt') + i = m.indexFromName("fldtxt") self.assertFalse(i.isValid()) - i = m.indexFromName('y') + i = m.indexFromName("y") self.assertTrue(i.isValid()) self.assertEqual(i.row(), 1) - i = m.indexFromName('') + i = m.indexFromName("") self.assertFalse(i.isValid()) m.setAllowEmptyAttributeName(True) - i = m.indexFromName('fldtxt') + i = m.indexFromName("fldtxt") self.assertFalse(i.isValid()) - i = m.indexFromName('y') + i = m.indexFromName("y") self.assertTrue(i.isValid()) self.assertEqual(i.row(), 2) - i = m.indexFromName('') + i = m.indexFromName("") self.assertTrue(i.isValid()) self.assertEqual(i.row(), 0) @@ -91,250 +105,884 @@ def testAttributeNameRole(self): m = QgsPointCloudAttributeModel() m.setAttributes(create_attributes()) - self.assertEqual(m.data(m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'x') - self.assertEqual(m.data(m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'y') - self.assertEqual(m.data(m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'z') - self.assertEqual(m.data(m.index(3, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'cat') - self.assertEqual(m.data(m.index(4, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'red') - self.assertEqual(m.data(m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), None) + self.assertEqual( + m.data( + m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole + ), + "x", + ) + self.assertEqual( + m.data( + m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole + ), + "y", + ) + self.assertEqual( + m.data( + m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole + ), + "z", + ) + self.assertEqual( + m.data( + m.index(3, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole + ), + "cat", + ) + self.assertEqual( + m.data( + m.index(4, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole + ), + "red", + ) + self.assertEqual( + m.data( + m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole + ), + None, + ) m.setAllowEmptyAttributeName(True) - self.assertEqual(m.data(m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), None) - self.assertEqual(m.data(m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'x') - self.assertEqual(m.data(m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'y') - self.assertEqual(m.data(m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'red') + self.assertEqual( + m.data( + m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole + ), + None, + ) + self.assertEqual( + m.data( + m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole + ), + "x", + ) + self.assertEqual( + m.data( + m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole + ), + "y", + ) + self.assertEqual( + m.data( + m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole + ), + "red", + ) def testAttributeIndexRole(self): m = QgsPointCloudAttributeModel() m.setAttributes(create_attributes()) - self.assertEqual(m.data(m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole), 0) - self.assertEqual(m.data(m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole), 1) - self.assertEqual(m.data(m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole), 2) - self.assertEqual(m.data(m.index(3, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole), 3) - self.assertEqual(m.data(m.index(4, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole), 4) - self.assertEqual(m.data(m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole), None) + self.assertEqual( + m.data( + m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole + ), + 0, + ) + self.assertEqual( + m.data( + m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole + ), + 1, + ) + self.assertEqual( + m.data( + m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole + ), + 2, + ) + self.assertEqual( + m.data( + m.index(3, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole + ), + 3, + ) + self.assertEqual( + m.data( + m.index(4, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole + ), + 4, + ) + self.assertEqual( + m.data( + m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole + ), + None, + ) m.setAllowEmptyAttributeName(True) - self.assertEqual(m.data(m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole), None) - self.assertEqual(m.data(m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole), 0) - self.assertEqual(m.data(m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole), 1) - self.assertEqual(m.data(m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole), 4) + self.assertEqual( + m.data( + m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole + ), + None, + ) + self.assertEqual( + m.data( + m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole + ), + 0, + ) + self.assertEqual( + m.data( + m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole + ), + 1, + ) + self.assertEqual( + m.data( + m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeIndexRole + ), + 4, + ) def testSizeRole(self): m = QgsPointCloudAttributeModel() m.setAttributes(create_attributes()) - self.assertEqual(m.data(m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole), 4) - self.assertEqual(m.data(m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole), 4) - self.assertEqual(m.data(m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole), 4) - self.assertEqual(m.data(m.index(3, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole), 1) - self.assertEqual(m.data(m.index(4, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole), 4) - self.assertEqual(m.data(m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole), None) + self.assertEqual( + m.data( + m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole + ), + 4, + ) + self.assertEqual( + m.data( + m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole + ), + 4, + ) + self.assertEqual( + m.data( + m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole + ), + 4, + ) + self.assertEqual( + m.data( + m.index(3, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole + ), + 1, + ) + self.assertEqual( + m.data( + m.index(4, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole + ), + 4, + ) + self.assertEqual( + m.data( + m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole + ), + None, + ) m.setAllowEmptyAttributeName(True) - self.assertEqual(m.data(m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole), None) - self.assertEqual(m.data(m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole), 4) - self.assertEqual(m.data(m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole), 4) - self.assertEqual(m.data(m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole), 4) + self.assertEqual( + m.data( + m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole + ), + None, + ) + self.assertEqual( + m.data( + m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole + ), + 4, + ) + self.assertEqual( + m.data( + m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole + ), + 4, + ) + self.assertEqual( + m.data( + m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeSizeRole + ), + 4, + ) def testTypeRole(self): m = QgsPointCloudAttributeModel() m.setAttributes(create_attributes()) - self.assertEqual(m.data(m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole), QgsPointCloudAttribute.DataType.Float) - self.assertEqual(m.data(m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole), QgsPointCloudAttribute.DataType.Float) - self.assertEqual(m.data(m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole), QgsPointCloudAttribute.DataType.Float) - self.assertEqual(m.data(m.index(3, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole), QgsPointCloudAttribute.DataType.Char) - self.assertEqual(m.data(m.index(4, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole), QgsPointCloudAttribute.DataType.Int32) - self.assertEqual(m.data(m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole), None) + self.assertEqual( + m.data( + m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole + ), + QgsPointCloudAttribute.DataType.Float, + ) + self.assertEqual( + m.data( + m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole + ), + QgsPointCloudAttribute.DataType.Float, + ) + self.assertEqual( + m.data( + m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole + ), + QgsPointCloudAttribute.DataType.Float, + ) + self.assertEqual( + m.data( + m.index(3, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole + ), + QgsPointCloudAttribute.DataType.Char, + ) + self.assertEqual( + m.data( + m.index(4, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole + ), + QgsPointCloudAttribute.DataType.Int32, + ) + self.assertEqual( + m.data( + m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole + ), + None, + ) m.setAllowEmptyAttributeName(True) - self.assertEqual(m.data(m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole), None) - self.assertEqual(m.data(m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole), QgsPointCloudAttribute.DataType.Float) - self.assertEqual(m.data(m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole), QgsPointCloudAttribute.DataType.Float) - self.assertEqual(m.data(m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole), QgsPointCloudAttribute.DataType.Int32) + self.assertEqual( + m.data( + m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole + ), + None, + ) + self.assertEqual( + m.data( + m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole + ), + QgsPointCloudAttribute.DataType.Float, + ) + self.assertEqual( + m.data( + m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole + ), + QgsPointCloudAttribute.DataType.Float, + ) + self.assertEqual( + m.data( + m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeTypeRole + ), + QgsPointCloudAttribute.DataType.Int32, + ) def testIsEmptyRole(self): m = QgsPointCloudAttributeModel() m.setAttributes(create_attributes()) - self.assertFalse(m.data(m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole)) - self.assertFalse(m.data(m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole)) - self.assertFalse(m.data(m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole)) - self.assertFalse(m.data(m.index(3, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole)) - self.assertFalse(m.data(m.index(4, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole)) - self.assertFalse(m.data(m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole)) + self.assertFalse( + m.data(m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole) + ) + self.assertFalse( + m.data(m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole) + ) + self.assertFalse( + m.data(m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole) + ) + self.assertFalse( + m.data(m.index(3, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole) + ) + self.assertFalse( + m.data(m.index(4, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole) + ) + self.assertFalse( + m.data(m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole) + ) m.setAllowEmptyAttributeName(True) - self.assertTrue(m.data(m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole)) - self.assertFalse(m.data(m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole)) - self.assertFalse(m.data(m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole)) - self.assertFalse(m.data(m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole)) + self.assertTrue( + m.data(m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole) + ) + self.assertFalse( + m.data(m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole) + ) + self.assertFalse( + m.data(m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole) + ) + self.assertFalse( + m.data(m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.IsEmptyRole) + ) def testIsNumericRole(self): m = QgsPointCloudAttributeModel() m.setAttributes(create_attributes()) - self.assertTrue(m.data(m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole)) - self.assertTrue(m.data(m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole)) - self.assertTrue(m.data(m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole)) - self.assertFalse(m.data(m.index(3, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole)) - self.assertTrue(m.data(m.index(4, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole)) - self.assertFalse(m.data(m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole)) + self.assertTrue( + m.data(m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole) + ) + self.assertTrue( + m.data(m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole) + ) + self.assertTrue( + m.data(m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole) + ) + self.assertFalse( + m.data(m.index(3, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole) + ) + self.assertTrue( + m.data(m.index(4, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole) + ) + self.assertFalse( + m.data(m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole) + ) m.setAllowEmptyAttributeName(True) - self.assertFalse(m.data(m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole)) - self.assertTrue(m.data(m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole)) - self.assertTrue(m.data(m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole)) - self.assertTrue(m.data(m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole)) + self.assertFalse( + m.data(m.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole) + ) + self.assertTrue( + m.data(m.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole) + ) + self.assertTrue( + m.data(m.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole) + ) + self.assertTrue( + m.data(m.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.IsNumericRole) + ) def testDisplayRole(self): m = QgsPointCloudAttributeModel() m.setAttributes(create_attributes()) - self.assertEqual(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole), 'x') - self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), 'y') - self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), 'z') - self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), 'cat') - self.assertEqual(m.data(m.index(4, 0), Qt.ItemDataRole.DisplayRole), 'red') + self.assertEqual(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole), "x") + self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), "y") + self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), "z") + self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.DisplayRole), "cat") + self.assertEqual(m.data(m.index(4, 0), Qt.ItemDataRole.DisplayRole), "red") self.assertEqual(m.data(m.index(5, 0), Qt.ItemDataRole.DisplayRole), None) m.setAllowEmptyAttributeName(True) self.assertEqual(m.data(m.index(0, 0), Qt.ItemDataRole.DisplayRole), None) - self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), 'x') - self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), 'y') - self.assertEqual(m.data(m.index(5, 0), Qt.ItemDataRole.DisplayRole), 'red') + self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.DisplayRole), "x") + self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.DisplayRole), "y") + self.assertEqual(m.data(m.index(5, 0), Qt.ItemDataRole.DisplayRole), "red") def testTooltip(self): m = QgsPointCloudAttributeModel() m.setAttributes(create_attributes()) - self.assertEqual(m.data(m.index(0, 0), Qt.ItemDataRole.ToolTipRole), "x
    Float") - self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.ToolTipRole), "y
    Float") - self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.ToolTipRole), "z
    Float") - self.assertEqual(m.data(m.index(3, 0), Qt.ItemDataRole.ToolTipRole), "cat
    Character") - self.assertEqual(m.data(m.index(4, 0), Qt.ItemDataRole.ToolTipRole), "red
    Integer") + self.assertEqual( + m.data(m.index(0, 0), Qt.ItemDataRole.ToolTipRole), + "x
    Float", + ) + self.assertEqual( + m.data(m.index(1, 0), Qt.ItemDataRole.ToolTipRole), + "y
    Float", + ) + self.assertEqual( + m.data(m.index(2, 0), Qt.ItemDataRole.ToolTipRole), + "z
    Float", + ) + self.assertEqual( + m.data(m.index(3, 0), Qt.ItemDataRole.ToolTipRole), + "cat
    Character", + ) + self.assertEqual( + m.data(m.index(4, 0), Qt.ItemDataRole.ToolTipRole), + "red
    Integer", + ) self.assertEqual(m.data(m.index(5, 0), Qt.ItemDataRole.ToolTipRole), None) m.setAllowEmptyAttributeName(True) self.assertEqual(m.data(m.index(0, 0), Qt.ItemDataRole.ToolTipRole), None) - self.assertEqual(m.data(m.index(1, 0), Qt.ItemDataRole.ToolTipRole), "x
    Float") - self.assertEqual(m.data(m.index(2, 0), Qt.ItemDataRole.ToolTipRole), "y
    Float") - self.assertEqual(m.data(m.index(5, 0), Qt.ItemDataRole.ToolTipRole), "red
    Integer") - - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + self.assertEqual( + m.data(m.index(1, 0), Qt.ItemDataRole.ToolTipRole), + "x
    Float", + ) + self.assertEqual( + m.data(m.index(2, 0), Qt.ItemDataRole.ToolTipRole), + "y
    Float", + ) + self.assertEqual( + m.data(m.index(5, 0), Qt.ItemDataRole.ToolTipRole), + "red
    Integer", + ) + + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testSetLayer(self): m = QgsPointCloudAttributeModel() self.assertIsNone(m.layer()) - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) m.setLayer(layer) self.assertEqual(m.layer(), layer) - self.assertEqual([a.name() for a in m.attributes().attributes()], ['X', 'Y', 'Z', 'Intensity', 'ReturnNumber', 'NumberOfReturns', 'ScanDirectionFlag', 'EdgeOfFlightLine', 'Classification', 'ScanAngleRank', 'UserData', 'PointSourceId', 'GpsTime', 'Red', 'Green', 'Blue']) + self.assertEqual( + [a.name() for a in m.attributes().attributes()], + [ + "X", + "Y", + "Z", + "Intensity", + "ReturnNumber", + "NumberOfReturns", + "ScanDirectionFlag", + "EdgeOfFlightLine", + "Classification", + "ScanAngleRank", + "UserData", + "PointSourceId", + "GpsTime", + "Red", + "Green", + "Blue", + ], + ) def testProxyModel(self): m = QgsPointCloudAttributeModel() attributes = create_attributes() - attributes.push_back(QgsPointCloudAttribute('green', QgsPointCloudAttribute.DataType.Short)) - attributes.push_back(QgsPointCloudAttribute('intensity', QgsPointCloudAttribute.DataType.Double)) + attributes.push_back( + QgsPointCloudAttribute("green", QgsPointCloudAttribute.DataType.Short) + ) + attributes.push_back( + QgsPointCloudAttribute("intensity", QgsPointCloudAttribute.DataType.Double) + ) m.setAttributes(attributes) proxy = QgsPointCloudAttributeProxyModel(m) self.assertEqual(proxy.rowCount(), 7) - self.assertEqual(proxy.data(proxy.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'x') - self.assertEqual(proxy.data(proxy.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'y') - self.assertEqual(proxy.data(proxy.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'z') - self.assertEqual(proxy.data(proxy.index(3, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'cat') - self.assertEqual(proxy.data(proxy.index(4, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'red') - self.assertEqual(proxy.data(proxy.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'green') - self.assertEqual(proxy.data(proxy.index(6, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'intensity') - self.assertEqual(proxy.data(proxy.index(7, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), None) + self.assertEqual( + proxy.data( + proxy.index(0, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "x", + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "y", + ) + self.assertEqual( + proxy.data( + proxy.index(2, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "z", + ) + self.assertEqual( + proxy.data( + proxy.index(3, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "cat", + ) + self.assertEqual( + proxy.data( + proxy.index(4, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "red", + ) + self.assertEqual( + proxy.data( + proxy.index(5, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "green", + ) + self.assertEqual( + proxy.data( + proxy.index(6, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "intensity", + ) + self.assertEqual( + proxy.data( + proxy.index(7, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + None, + ) m.setAllowEmptyAttributeName(True) self.assertEqual(proxy.rowCount(), 8) - self.assertEqual(proxy.data(proxy.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), None) - self.assertEqual(proxy.data(proxy.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'x') - self.assertEqual(proxy.data(proxy.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'y') - self.assertEqual(proxy.data(proxy.index(7, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'intensity') + self.assertEqual( + proxy.data( + proxy.index(0, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + None, + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "x", + ) + self.assertEqual( + proxy.data( + proxy.index(2, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "y", + ) + self.assertEqual( + proxy.data( + proxy.index(7, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "intensity", + ) m.setAllowEmptyAttributeName(False) proxy.setFilters(QgsPointCloudAttributeProxyModel.Filter.Char) self.assertEqual(proxy.rowCount(), 1) - self.assertEqual(proxy.data(proxy.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'cat') - self.assertEqual(proxy.data(proxy.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), None) + self.assertEqual( + proxy.data( + proxy.index(0, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "cat", + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + None, + ) m.setAllowEmptyAttributeName(True) self.assertEqual(proxy.rowCount(), 2) - self.assertEqual(proxy.data(proxy.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), None) - self.assertEqual(proxy.data(proxy.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'cat') + self.assertEqual( + proxy.data( + proxy.index(0, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + None, + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "cat", + ) m.setAllowEmptyAttributeName(False) proxy.setFilters(QgsPointCloudAttributeProxyModel.Filter.Short) self.assertEqual(proxy.rowCount(), 1) - self.assertEqual(proxy.data(proxy.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'green') - self.assertEqual(proxy.data(proxy.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), None) + self.assertEqual( + proxy.data( + proxy.index(0, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "green", + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + None, + ) m.setAllowEmptyAttributeName(True) self.assertEqual(proxy.rowCount(), 2) - self.assertEqual(proxy.data(proxy.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), None) - self.assertEqual(proxy.data(proxy.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'green') + self.assertEqual( + proxy.data( + proxy.index(0, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + None, + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "green", + ) m.setAllowEmptyAttributeName(False) proxy.setFilters(QgsPointCloudAttributeProxyModel.Filter.Int32) self.assertEqual(proxy.rowCount(), 1) - self.assertEqual(proxy.data(proxy.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'red') - self.assertEqual(proxy.data(proxy.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), None) + self.assertEqual( + proxy.data( + proxy.index(0, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "red", + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + None, + ) m.setAllowEmptyAttributeName(True) self.assertEqual(proxy.rowCount(), 2) - self.assertEqual(proxy.data(proxy.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), None) - self.assertEqual(proxy.data(proxy.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'red') + self.assertEqual( + proxy.data( + proxy.index(0, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + None, + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "red", + ) m.setAllowEmptyAttributeName(False) proxy.setFilters(QgsPointCloudAttributeProxyModel.Filter.Float) self.assertEqual(proxy.rowCount(), 3) - self.assertEqual(proxy.data(proxy.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'x') - self.assertEqual(proxy.data(proxy.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'y') - self.assertEqual(proxy.data(proxy.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'z') - self.assertEqual(proxy.data(proxy.index(3, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), None) + self.assertEqual( + proxy.data( + proxy.index(0, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "x", + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "y", + ) + self.assertEqual( + proxy.data( + proxy.index(2, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "z", + ) + self.assertEqual( + proxy.data( + proxy.index(3, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + None, + ) m.setAllowEmptyAttributeName(True) self.assertEqual(proxy.rowCount(), 4) - self.assertEqual(proxy.data(proxy.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), None) - self.assertEqual(proxy.data(proxy.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'x') - self.assertEqual(proxy.data(proxy.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'y') - self.assertEqual(proxy.data(proxy.index(3, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'z') + self.assertEqual( + proxy.data( + proxy.index(0, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + None, + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "x", + ) + self.assertEqual( + proxy.data( + proxy.index(2, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "y", + ) + self.assertEqual( + proxy.data( + proxy.index(3, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "z", + ) m.setAllowEmptyAttributeName(False) proxy.setFilters(QgsPointCloudAttributeProxyModel.Filter.Double) self.assertEqual(proxy.rowCount(), 1) - self.assertEqual(proxy.data(proxy.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'intensity') - self.assertEqual(proxy.data(proxy.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), None) + self.assertEqual( + proxy.data( + proxy.index(0, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "intensity", + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + None, + ) m.setAllowEmptyAttributeName(True) self.assertEqual(proxy.rowCount(), 2) - self.assertEqual(proxy.data(proxy.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), None) - self.assertEqual(proxy.data(proxy.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'intensity') + self.assertEqual( + proxy.data( + proxy.index(0, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + None, + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "intensity", + ) m.setAllowEmptyAttributeName(False) - proxy.setFilters(QgsPointCloudAttributeProxyModel.Filter.Double | QgsPointCloudAttributeProxyModel.Filter.Int32) + proxy.setFilters( + QgsPointCloudAttributeProxyModel.Filter.Double + | QgsPointCloudAttributeProxyModel.Filter.Int32 + ) self.assertEqual(proxy.rowCount(), 2) - self.assertEqual(proxy.data(proxy.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'red') - self.assertEqual(proxy.data(proxy.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'intensity') - self.assertEqual(proxy.data(proxy.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), None) + self.assertEqual( + proxy.data( + proxy.index(0, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "red", + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "intensity", + ) + self.assertEqual( + proxy.data( + proxy.index(2, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + None, + ) m.setAllowEmptyAttributeName(True) self.assertEqual(proxy.rowCount(), 3) - self.assertEqual(proxy.data(proxy.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), None) - self.assertEqual(proxy.data(proxy.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'red') - self.assertEqual(proxy.data(proxy.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'intensity') + self.assertEqual( + proxy.data( + proxy.index(0, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + None, + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "red", + ) + self.assertEqual( + proxy.data( + proxy.index(2, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "intensity", + ) m.setAllowEmptyAttributeName(False) proxy.setFilters(QgsPointCloudAttributeProxyModel.Filter.Numeric) self.assertEqual(proxy.rowCount(), 6) - self.assertEqual(proxy.data(proxy.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'x') - self.assertEqual(proxy.data(proxy.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'y') - self.assertEqual(proxy.data(proxy.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'z') - self.assertEqual(proxy.data(proxy.index(3, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'red') - self.assertEqual(proxy.data(proxy.index(4, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'green') - self.assertEqual(proxy.data(proxy.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'intensity') - self.assertEqual(proxy.data(proxy.index(6, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), None) + self.assertEqual( + proxy.data( + proxy.index(0, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "x", + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "y", + ) + self.assertEqual( + proxy.data( + proxy.index(2, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "z", + ) + self.assertEqual( + proxy.data( + proxy.index(3, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "red", + ) + self.assertEqual( + proxy.data( + proxy.index(4, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "green", + ) + self.assertEqual( + proxy.data( + proxy.index(5, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "intensity", + ) + self.assertEqual( + proxy.data( + proxy.index(6, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + None, + ) m.setAllowEmptyAttributeName(True) self.assertEqual(proxy.rowCount(), 7) - self.assertEqual(proxy.data(proxy.index(0, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), None) - self.assertEqual(proxy.data(proxy.index(1, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'x') - self.assertEqual(proxy.data(proxy.index(2, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'y') - self.assertEqual(proxy.data(proxy.index(3, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'z') - self.assertEqual(proxy.data(proxy.index(4, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'red') - self.assertEqual(proxy.data(proxy.index(5, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'green') - self.assertEqual(proxy.data(proxy.index(6, 0), QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole), 'intensity') - - -if __name__ == '__main__': + self.assertEqual( + proxy.data( + proxy.index(0, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + None, + ) + self.assertEqual( + proxy.data( + proxy.index(1, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "x", + ) + self.assertEqual( + proxy.data( + proxy.index(2, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "y", + ) + self.assertEqual( + proxy.data( + proxy.index(3, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "z", + ) + self.assertEqual( + proxy.data( + proxy.index(4, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "red", + ) + self.assertEqual( + proxy.data( + proxy.index(5, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "green", + ) + self.assertEqual( + proxy.data( + proxy.index(6, 0), + QgsPointCloudAttributeModel.FieldRoles.AttributeNameRole, + ), + "intensity", + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspointcloudclassifiedrenderer.py b/tests/src/python/test_qgspointcloudclassifiedrenderer.py index 90fc50a84285..3d6be8273afa 100644 --- a/tests/src/python/test_qgspointcloudclassifiedrenderer.py +++ b/tests/src/python/test_qgspointcloudclassifiedrenderer.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '09/11/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "09/11/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QSize, Qt from qgis.PyQt.QtGui import QColor @@ -44,19 +45,23 @@ class TestQgsPointCloudClassifiedRenderer(QgisTestCase): @classmethod def control_path_prefix(cls): - return 'pointcloudrenderer' + return "pointcloudrenderer" def testBasic(self): renderer = QgsPointCloudClassifiedRenderer() - renderer.setAttribute('attr') - self.assertEqual(renderer.attribute(), 'attr') - - renderer.setCategories([QgsPointCloudCategory(3, QColor(255, 0, 0), 'cat 3'), - QgsPointCloudCategory(7, QColor(0, 255, 0), 'cat 7')]) + renderer.setAttribute("attr") + self.assertEqual(renderer.attribute(), "attr") + + renderer.setCategories( + [ + QgsPointCloudCategory(3, QColor(255, 0, 0), "cat 3"), + QgsPointCloudCategory(7, QColor(0, 255, 0), "cat 7"), + ] + ) self.assertEqual(len(renderer.categories()), 2) - self.assertEqual(renderer.categories()[0].label(), 'cat 3') - self.assertEqual(renderer.categories()[1].label(), 'cat 7') + self.assertEqual(renderer.categories()[0].label(), "cat 3") + self.assertEqual(renderer.categories()[1].label(), "cat 7") renderer.setMaximumScreenError(18) renderer.setMaximumScreenErrorUnit(QgsUnitTypes.RenderUnit.RenderInches) @@ -66,63 +71,88 @@ def testBasic(self): rr = renderer.clone() self.assertEqual(rr.maximumScreenError(), 18) - self.assertEqual(rr.maximumScreenErrorUnit(), QgsUnitTypes.RenderUnit.RenderInches) + self.assertEqual( + rr.maximumScreenErrorUnit(), QgsUnitTypes.RenderUnit.RenderInches + ) self.assertEqual(rr.pointSize(), 13) self.assertEqual(rr.pointSizeUnit(), QgsUnitTypes.RenderUnit.RenderPoints) self.assertEqual(rr.pointSizeMapUnitScale().minScale, 1000) self.assertEqual(rr.pointSizeMapUnitScale().maxScale, 2000) - self.assertEqual(rr.attribute(), 'attr') + self.assertEqual(rr.attribute(), "attr") self.assertEqual(len(rr.categories()), 2) - self.assertEqual(rr.categories()[0].label(), 'cat 3') - self.assertEqual(rr.categories()[1].label(), 'cat 7') + self.assertEqual(rr.categories()[0].label(), "cat 3") + self.assertEqual(rr.categories()[1].label(), "cat 7") doc = QDomDocument("testdoc") elem = renderer.save(doc, QgsReadWriteContext()) r2 = QgsPointCloudClassifiedRenderer.create(elem, QgsReadWriteContext()) self.assertEqual(r2.maximumScreenError(), 18) - self.assertEqual(r2.maximumScreenErrorUnit(), QgsUnitTypes.RenderUnit.RenderInches) + self.assertEqual( + r2.maximumScreenErrorUnit(), QgsUnitTypes.RenderUnit.RenderInches + ) self.assertEqual(r2.pointSize(), 13) self.assertEqual(r2.pointSizeUnit(), QgsUnitTypes.RenderUnit.RenderPoints) self.assertEqual(r2.pointSizeMapUnitScale().minScale, 1000) self.assertEqual(r2.pointSizeMapUnitScale().maxScale, 2000) - self.assertEqual(r2.attribute(), 'attr') + self.assertEqual(r2.attribute(), "attr") self.assertEqual(len(r2.categories()), 2) - self.assertEqual(r2.categories()[0].label(), 'cat 3') - self.assertEqual(r2.categories()[1].label(), 'cat 7') + self.assertEqual(r2.categories()[0].label(), "cat 3") + self.assertEqual(r2.categories()[1].label(), "cat 7") def testUsedAttributes(self): renderer = QgsPointCloudClassifiedRenderer() - renderer.setAttribute('attr') + renderer.setAttribute("attr") rc = QgsRenderContext() prc = QgsPointCloudRenderContext(rc, QgsVector3D(), QgsVector3D(), 1, 0) - self.assertEqual(renderer.usedAttributes(prc), {'attr'}) + self.assertEqual(renderer.usedAttributes(prc), {"attr"}) def testLegend(self): renderer = QgsPointCloudClassifiedRenderer() - renderer.setAttribute('Classification') - renderer.setCategories([QgsPointCloudCategory(3, QColor(255, 0, 0), 'cat 3'), - QgsPointCloudCategory(7, QColor(0, 255, 0), 'cat 7')]) + renderer.setAttribute("Classification") + renderer.setCategories( + [ + QgsPointCloudCategory(3, QColor(255, 0, 0), "cat 3"), + QgsPointCloudCategory(7, QColor(0, 255, 0), "cat 7"), + ] + ) - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) layer_tree_layer = QgsLayerTreeLayer(layer) nodes = renderer.createLegendNodes(layer_tree_layer) self.assertEqual(len(nodes), 2) - self.assertEqual(nodes[0].data(Qt.ItemDataRole.DisplayRole), 'cat 3') - self.assertEqual(nodes[0].data(QgsLayerTreeModelLegendNode.LegendNodeRoles.RuleKeyRole), '3') - self.assertEqual(nodes[1].data(Qt.ItemDataRole.DisplayRole), 'cat 7') - self.assertEqual(nodes[1].data(QgsLayerTreeModelLegendNode.LegendNodeRoles.RuleKeyRole), '7') + self.assertEqual(nodes[0].data(Qt.ItemDataRole.DisplayRole), "cat 3") + self.assertEqual( + nodes[0].data(QgsLayerTreeModelLegendNode.LegendNodeRoles.RuleKeyRole), "3" + ) + self.assertEqual(nodes[1].data(Qt.ItemDataRole.DisplayRole), "cat 7") + self.assertEqual( + nodes[1].data(QgsLayerTreeModelLegendNode.LegendNodeRoles.RuleKeyRole), "7" + ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRender(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) - categories = QgsPointCloudRendererRegistry.classificationAttributeCategories(layer) - renderer = QgsPointCloudClassifiedRenderer('Classification', categories) + categories = QgsPointCloudRendererRegistry.classificationAttributeCategories( + layer + ) + renderer = QgsPointCloudClassifiedRenderer("Classification", categories) layer.setRenderer(renderer) layer.renderer().setPointSize(2) @@ -136,16 +166,27 @@ def testRender(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('classified_render', 'classified_render', mapsettings) + self.render_map_settings_check( + "classified_render", "classified_render", mapsettings + ) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderCrsTransform(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) - categories = QgsPointCloudRendererRegistry.classificationAttributeCategories(layer) - renderer = QgsPointCloudClassifiedRenderer('Classification', categories) + categories = QgsPointCloudRendererRegistry.classificationAttributeCategories( + layer + ) + renderer = QgsPointCloudClassifiedRenderer("Classification", categories) layer.setRenderer(renderer) layer.renderer().setPointSize(2) @@ -154,24 +195,39 @@ def testRenderCrsTransform(self): mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) - mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) - mapsettings.setExtent(QgsRectangle(152.980508492, -26.662023491, 152.980586020, -26.662071137)) + mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) + mapsettings.setExtent( + QgsRectangle(152.980508492, -26.662023491, 152.980586020, -26.662071137) + ) mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('classified_render_crs_transform', 'classified_render_crs_transform', mapsettings) + self.render_map_settings_check( + "classified_render_crs_transform", + "classified_render_crs_transform", + mapsettings, + ) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderPointSize(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) - categories = QgsPointCloudRendererRegistry.classificationAttributeCategories(layer) - renderer = QgsPointCloudClassifiedRenderer('Classification', categories) + categories = QgsPointCloudRendererRegistry.classificationAttributeCategories( + layer + ) + renderer = QgsPointCloudClassifiedRenderer("Classification", categories) layer.setRenderer(renderer) - layer.renderer().setPointSize(.15) + layer.renderer().setPointSize(0.15) layer.renderer().setPointSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) mapsettings = QgsMapSettings() @@ -182,23 +238,34 @@ def testRenderPointSize(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('classified_pointsize', 'classified_pointsize', mapsettings) + self.render_map_settings_check( + "classified_pointsize", "classified_pointsize", mapsettings + ) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderClassificationOverridePointSizes(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) - categories = QgsPointCloudRendererRegistry.classificationAttributeCategories(layer) + categories = QgsPointCloudRendererRegistry.classificationAttributeCategories( + layer + ) categories[0].setPointSize(1) - categories[2].setPointSize(.3) - categories[3].setPointSize(.5) + categories[2].setPointSize(0.3) + categories[3].setPointSize(0.5) - renderer = QgsPointCloudClassifiedRenderer('Classification', categories) + renderer = QgsPointCloudClassifiedRenderer("Classification", categories) layer.setRenderer(renderer) - layer.renderer().setPointSize(.15) + layer.renderer().setPointSize(0.15) layer.renderer().setPointSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) mapsettings = QgsMapSettings() @@ -209,16 +276,29 @@ def testRenderClassificationOverridePointSizes(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('classified_override_pointsize', 'classified_override_pointsize', mapsettings) + self.render_map_settings_check( + "classified_override_pointsize", + "classified_override_pointsize", + mapsettings, + ) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderZRange(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) - categories = QgsPointCloudRendererRegistry.classificationAttributeCategories(layer) - renderer = QgsPointCloudClassifiedRenderer('Classification', categories) + categories = QgsPointCloudRendererRegistry.classificationAttributeCategories( + layer + ) + renderer = QgsPointCloudClassifiedRenderer("Classification", categories) layer.setRenderer(renderer) layer.renderer().setPointSize(2) @@ -233,16 +313,27 @@ def testRenderZRange(self): mapsettings.setZRange(QgsDoubleRange(74.7, 75)) self.assertTrue( - self.render_map_settings_check('classified_zfilter', 'classified_zfilter', mapsettings) + self.render_map_settings_check( + "classified_zfilter", "classified_zfilter", mapsettings + ) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderOrderedTopToBottom(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) - categories = QgsPointCloudRendererRegistry.classificationAttributeCategories(layer) - renderer = QgsPointCloudClassifiedRenderer('Classification', categories) + categories = QgsPointCloudRendererRegistry.classificationAttributeCategories( + layer + ) + renderer = QgsPointCloudClassifiedRenderer("Classification", categories) layer.setRenderer(renderer) layer.renderer().setPointSize(6) @@ -257,16 +348,27 @@ def testRenderOrderedTopToBottom(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('classified_top_to_bottom', 'classified_top_to_bottom', mapsettings) + self.render_map_settings_check( + "classified_top_to_bottom", "classified_top_to_bottom", mapsettings + ) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderOrderedBottomToTop(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) - categories = QgsPointCloudRendererRegistry.classificationAttributeCategories(layer) - renderer = QgsPointCloudClassifiedRenderer('Classification', categories) + categories = QgsPointCloudRendererRegistry.classificationAttributeCategories( + layer + ) + renderer = QgsPointCloudClassifiedRenderer("Classification", categories) layer.setRenderer(renderer) layer.renderer().setPointSize(6) @@ -281,21 +383,32 @@ def testRenderOrderedBottomToTop(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('classified_bottom_to_top', 'classified_bottom_to_top', mapsettings) + self.render_map_settings_check( + "classified_bottom_to_top", "classified_bottom_to_top", mapsettings + ) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderFiltered(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) - categories = QgsPointCloudRendererRegistry.classificationAttributeCategories(layer) - renderer = QgsPointCloudClassifiedRenderer('Classification', categories) + categories = QgsPointCloudRendererRegistry.classificationAttributeCategories( + layer + ) + renderer = QgsPointCloudClassifiedRenderer("Classification", categories) layer.setRenderer(renderer) layer.renderer().setPointSize(2) layer.renderer().setPointSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - layer.setSubsetString('NumberOfReturns > 1') + layer.setSubsetString("NumberOfReturns > 1") mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) @@ -305,22 +418,37 @@ def testRenderFiltered(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('classified_render_filtered', 'classified_render_filtered', mapsettings) + self.render_map_settings_check( + "classified_render_filtered", "classified_render_filtered", mapsettings + ) ) - layer.setSubsetString('') + layer.setSubsetString("") self.assertTrue( - self.render_map_settings_check('classified_render_unfiltered', 'classified_render_unfiltered', mapsettings) + self.render_map_settings_check( + "classified_render_unfiltered", + "classified_render_unfiltered", + mapsettings, + ) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderTriangles(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) - categories = QgsPointCloudRendererRegistry.classificationAttributeCategories(layer) - renderer = QgsPointCloudClassifiedRenderer('Classification', categories) + categories = QgsPointCloudRendererRegistry.classificationAttributeCategories( + layer + ) + renderer = QgsPointCloudClassifiedRenderer("Classification", categories) renderer.setRenderAsTriangles(True) layer.setRenderer(renderer) @@ -335,9 +463,11 @@ def testRenderTriangles(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('classified_triangles', 'classified_triangles', mapsettings) + self.render_map_settings_check( + "classified_triangles", "classified_triangles", mapsettings + ) ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspointcloudelevationproperties.py b/tests/src/python/test_qgspointcloudelevationproperties.py index b63ba69ee01a..76ea56abb40d 100644 --- a/tests/src/python/test_qgspointcloudelevationproperties.py +++ b/tests/src/python/test_qgspointcloudelevationproperties.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '09/11/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "09/11/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtGui import QColor from qgis.PyQt.QtTest import QSignalSpy @@ -52,15 +53,17 @@ def testBasic(self): self.assertEqual(props.zScale(), 2) self.assertEqual(props.zOffset(), 0.5) self.assertEqual(props.maximumScreenError(), 0.4) - self.assertEqual(props.maximumScreenErrorUnit(), QgsUnitTypes.RenderUnit.RenderInches) + self.assertEqual( + props.maximumScreenErrorUnit(), QgsUnitTypes.RenderUnit.RenderInches + ) self.assertEqual(props.pointSymbol(), Qgis.PointCloudSymbol.Circle) - self.assertEqual(props.pointColor().name(), '#ff00ff') + self.assertEqual(props.pointColor().name(), "#ff00ff") self.assertEqual(props.pointSize(), 1.2) self.assertEqual(props.pointSizeUnit(), QgsUnitTypes.RenderUnit.RenderPoints) self.assertFalse(props.respectLayerColors()) doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsPointCloudLayerElevationProperties(None) @@ -68,9 +71,11 @@ def testBasic(self): self.assertEqual(props2.zScale(), 2) self.assertEqual(props2.zOffset(), 0.5) self.assertEqual(props2.maximumScreenError(), 0.4) - self.assertEqual(props2.maximumScreenErrorUnit(), QgsUnitTypes.RenderUnit.RenderInches) + self.assertEqual( + props2.maximumScreenErrorUnit(), QgsUnitTypes.RenderUnit.RenderInches + ) self.assertEqual(props2.pointSymbol(), Qgis.PointCloudSymbol.Circle) - self.assertEqual(props2.pointColor().name(), '#ff00ff') + self.assertEqual(props2.pointColor().name(), "#ff00ff") self.assertEqual(props2.pointSize(), 1.2) self.assertEqual(props2.pointSizeUnit(), QgsUnitTypes.RenderUnit.RenderPoints) self.assertFalse(props2.respectLayerColors()) @@ -79,16 +84,23 @@ def testBasic(self): self.assertEqual(props2.zScale(), 2) self.assertEqual(props2.zOffset(), 0.5) self.assertEqual(props2.maximumScreenError(), 0.4) - self.assertEqual(props2.maximumScreenErrorUnit(), QgsUnitTypes.RenderUnit.RenderInches) + self.assertEqual( + props2.maximumScreenErrorUnit(), QgsUnitTypes.RenderUnit.RenderInches + ) self.assertEqual(props2.pointSymbol(), Qgis.PointCloudSymbol.Circle) - self.assertEqual(props2.pointColor().name(), '#ff00ff') + self.assertEqual(props2.pointColor().name(), "#ff00ff") self.assertEqual(props2.pointSize(), 1.2) self.assertEqual(props2.pointSizeUnit(), QgsUnitTypes.RenderUnit.RenderPoints) self.assertFalse(props2.respectLayerColors()) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def test_signals(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/rgb/ept.json", "test", "ept" + ) self.assertTrue(layer.isValid()) props = layer.elevationProperties() @@ -104,21 +116,24 @@ def test_signals(self): layer.setRenderer(QgsPointCloudClassifiedRenderer()) self.assertEqual(len(spy), 1) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def test_layer_calculations(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/rgb/ept.json", "test", "ept" + ) self.assertTrue(layer.isValid()) props = layer.elevationProperties() self.assertEqual(props.calculateZRange(layer), QgsDoubleRange(0.98, 1.25)) - self.assertEqual(props.significantZValues(layer), - [0.98, 1.25]) + self.assertEqual(props.significantZValues(layer), [0.98, 1.25]) props.setZScale(2) props.setZOffset(0.1) - self.assertEqual(props.significantZValues(layer), - [2.06, 2.6]) + self.assertEqual(props.significantZValues(layer), [2.06, 2.6]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspointcloudextentrenderer.py b/tests/src/python/test_qgspointcloudextentrenderer.py index 56eef3c94194..15685f82b8c3 100644 --- a/tests/src/python/test_qgspointcloudextentrenderer.py +++ b/tests/src/python/test_qgspointcloudextentrenderer.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '04/12/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "04/12/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QDir, QSize, Qt from qgis.PyQt.QtGui import QColor @@ -38,35 +39,52 @@ def control_path_prefix(cls): return "pointcloudrenderer" def testBasic(self): - renderer = QgsPointCloudExtentRenderer(QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_color': 'black'})) - self.assertEqual(renderer.fillSymbol()[0].color().name(), '#ff00ff') + renderer = QgsPointCloudExtentRenderer( + QgsFillSymbol.createSimple({"color": "#ff00ff", "outline_color": "black"}) + ) + self.assertEqual(renderer.fillSymbol()[0].color().name(), "#ff00ff") - renderer.setFillSymbol(QgsFillSymbol.createSimple({'color': '#00ffff', 'outline_color': 'black'})) - self.assertEqual(renderer.fillSymbol()[0].color().name(), '#00ffff') + renderer.setFillSymbol( + QgsFillSymbol.createSimple({"color": "#00ffff", "outline_color": "black"}) + ) + self.assertEqual(renderer.fillSymbol()[0].color().name(), "#00ffff") rr = renderer.clone() - self.assertEqual(rr.fillSymbol()[0].color().name(), '#00ffff') + self.assertEqual(rr.fillSymbol()[0].color().name(), "#00ffff") doc = QDomDocument("testdoc") elem = renderer.save(doc, QgsReadWriteContext()) r2 = QgsPointCloudExtentRenderer.create(elem, QgsReadWriteContext()) - self.assertEqual(r2.fillSymbol()[0].color().name(), '#00ffff') + self.assertEqual(r2.fillSymbol()[0].color().name(), "#00ffff") def testLegend(self): renderer = QgsPointCloudExtentRenderer() - renderer.setFillSymbol(QgsFillSymbol.createSimple({'color': '#00ffff', 'outline_color': 'black'})) + renderer.setFillSymbol( + QgsFillSymbol.createSimple({"color": "#00ffff", "outline_color": "black"}) + ) - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) layer_tree_layer = QgsLayerTreeLayer(layer) nodes = renderer.createLegendNodes(layer_tree_layer) self.assertEqual(len(nodes), 1) - self.assertEqual(nodes[0].data(Qt.ItemDataRole.DisplayRole), 'test') + self.assertEqual(nodes[0].data(Qt.ItemDataRole.DisplayRole), "test") self.assertTrue(nodes[0].isEmbeddedInParent()) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRender(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) renderer = QgsPointCloudExtentRenderer() @@ -80,12 +98,21 @@ def testRender(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('extent_render', 'extent_render', mapsettings) + self.render_map_settings_check( + "extent_render", "extent_render", mapsettings + ) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderCrsTransform(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) renderer = QgsPointCloudExtentRenderer() @@ -95,14 +122,22 @@ def testRenderCrsTransform(self): mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) - mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) - mapsettings.setExtent(QgsRectangle(152.980508492, -26.662023491, 152.980586020, -26.662071137).buffered(0.00001)) + mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) + mapsettings.setExtent( + QgsRectangle( + 152.980508492, -26.662023491, 152.980586020, -26.662071137 + ).buffered(0.00001) + ) mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('extent_render_crs_transform', 'extent_render_crs_transform', mapsettings) + self.render_map_settings_check( + "extent_render_crs_transform", + "extent_render_crs_transform", + mapsettings, + ) ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspointcloudlayerprofilegenerator.py b/tests/src/python/test_qgspointcloudlayerprofilegenerator.py index 3b3213b96b33..fc9a57fe76aa 100644 --- a/tests/src/python/test_qgspointcloudlayerprofilegenerator.py +++ b/tests/src/python/test_qgspointcloudlayerprofilegenerator.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '18/03/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "18/03/2022" +__copyright__ = "Copyright 2022, The QGIS Project" import os @@ -25,7 +26,7 @@ QgsProfileSnapContext, QgsProviderRegistry, QgsUnitTypes, - QgsCoordinateReferenceSystem + QgsCoordinateReferenceSystem, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -45,17 +46,32 @@ def control_path_prefix(cls): def round_dict(val, places): return {round(k, places): round(val[k], places) for k in sorted(val.keys())} - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testProfileGeneration(self): pcl = QgsPointCloudLayer( - os.path.join(unitTestDataPath(), 'point_clouds', 'ept', 'lone-star-laszip', 'ept.json'), 'test', 'ept') + os.path.join( + unitTestDataPath(), + "point_clouds", + "ept", + "lone-star-laszip", + "ept.json", + ), + "test", + "ept", + ) self.assertTrue(pcl.isValid()) pcl.elevationProperties().setMaximumScreenError(30) - pcl.elevationProperties().setMaximumScreenErrorUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) + pcl.elevationProperties().setMaximumScreenErrorUnit( + QgsUnitTypes.RenderUnit.RenderMillimeters + ) curve = QgsLineString() curve.fromWkt( - 'LineString (515387.94696552358800545 4918366.65919817332178354, 515389.15378401038469747 4918366.63842081092298031)') + "LineString (515387.94696552358800545 4918366.65919817332178354, 515389.15378401038469747 4918366.63842081092298031)" + ) req = QgsProfileRequest(curve) req.setCrs(pcl.crs()) # zero tolerance => no points @@ -72,181 +88,411 @@ def testProfileGeneration(self): self.assertTrue(generator.generateProfile(context)) results = generator.takeResults() - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {0.0: 2325.1, 0.1: 2325.2, 0.2: 2332.4, 0.3: 2325.1, 0.4: 2325.1, 0.5: 2325.1, 0.6: 2331.4, - 0.7: 2330.6, 0.9: 2332.7, 1.0: 2325.4, 1.1: 2325.6, 1.2: 2325.6}) - - self.assertCountEqual([g.asWkt(1) for g in results.asGeometries()], - ['Point Z (515389.1 4918366.7 2326.1)', 'Point Z (515389.1 4918366.6 2325.6)', - 'Point Z (515389 4918366.6 2325.3)', 'Point Z (515388.2 4918366.6 2325.2)', - 'Point Z (515388.3 4918366.7 2325.1)', 'Point Z (515387.9 4918366.7 2325.2)', - 'Point Z (515388.7 4918366.6 2330.5)', 'Point Z (515388.6 4918366.6 2331.2)', - 'Point Z (515388.9 4918366.6 2332.7)', 'Point Z (515388.9 4918366.7 2332.7)', - 'Point Z (515388.6 4918366.6 2331.4)', 'Point Z (515388.2 4918366.7 2332.2)', - 'Point Z (515388.2 4918366.7 2332.6)', 'Point Z (515388.2 4918366.6 2335)', - 'Point Z (515388.6 4918366.6 2334.6)', 'Point Z (515389.1 4918366.6 2326.1)', - 'Point Z (515389.1 4918366.6 2325.4)', 'Point Z (515389.1 4918366.6 2325.5)', - 'Point Z (515389 4918366.6 2325.2)', 'Point Z (515388.3 4918366.6 2325.1)', - 'Point Z (515388.6 4918366.6 2330.9)', 'Point Z (515388.7 4918366.6 2330.5)', - 'Point Z (515388.6 4918366.6 2330.4)', 'Point Z (515389.1 4918366.6 2325.5)', - 'Point Z (515389.1 4918366.6 2325.9)', 'Point Z (515389.1 4918366.6 2325.8)', - 'Point Z (515389.1 4918366.7 2325.6)', 'Point Z (515389.1 4918366.6 2325.4)', - 'Point Z (515389.1 4918366.7 2325.2)', 'Point Z (515389.1 4918366.6 2326)', - 'Point Z (515389.1 4918366.6 2326)', 'Point Z (515389.1 4918366.6 2325.4)', - 'Point Z (515389.1 4918366.7 2325.3)', 'Point Z (515389 4918366.6 2325.3)', - 'Point Z (515389.1 4918366.7 2325.2)', 'Point Z (515389 4918366.6 2325.4)', - 'Point Z (515389 4918366.6 2325.4)', 'Point Z (515389 4918366.7 2325.2)', - 'Point Z (515389 4918366.7 2325.4)', 'Point Z (515388.6 4918366.6 2325.2)', - 'Point Z (515388.6 4918366.7 2325.2)', 'Point Z (515388.5 4918366.7 2325.2)', - 'Point Z (515388.5 4918366.7 2325.2)', 'Point Z (515388.4 4918366.6 2325.1)', - 'Point Z (515388.3 4918366.6 2325.1)', 'Point Z (515388.3 4918366.7 2325.1)', - 'Point Z (515388.2 4918366.6 2325.1)', 'Point Z (515388.2 4918366.6 2325.2)', - 'Point Z (515388.2 4918366.6 2325.2)', 'Point Z (515388.2 4918366.7 2325.2)', - 'Point Z (515388.1 4918366.6 2325.2)', 'Point Z (515388.1 4918366.6 2325.2)', - 'Point Z (515388 4918366.7 2325.2)', 'Point Z (515388 4918366.6 2325.1)', - 'Point Z (515388 4918366.6 2325.2)', 'Point Z (515388.7 4918366.6 2330.6)', - 'Point Z (515388.7 4918366.6 2330.5)', 'Point Z (515388.6 4918366.7 2331)', - 'Point Z (515388.7 4918366.7 2330.9)', 'Point Z (515388.6 4918366.6 2330.9)', - 'Point Z (515388.6 4918366.6 2330.8)', 'Point Z (515388.7 4918366.7 2330.7)', - 'Point Z (515388.6 4918366.7 2330.6)', 'Point Z (515389.1 4918366.6 2325.5)', - 'Point Z (515389.1 4918366.6 2325.5)', 'Point Z (515389.1 4918366.7 2325.5)', - 'Point Z (515389.1 4918366.7 2325.2)', 'Point Z (515389.1 4918366.6 2325.4)', - 'Point Z (515389.1 4918366.7 2325.2)', 'Point Z (515389.1 4918366.7 2325.5)', - 'Point Z (515389.1 4918366.6 2325.4)', 'Point Z (515389.1 4918366.7 2325.3)', - 'Point Z (515389.1 4918366.7 2325.2)', 'Point Z (515389.1 4918366.7 2325.2)', - 'Point Z (515389.1 4918366.6 2325.3)', 'Point Z (515389.1 4918366.7 2325.4)', - 'Point Z (515389.1 4918366.6 2325.3)', 'Point Z (515389 4918366.7 2325.3)', - 'Point Z (515389 4918366.7 2325.3)', 'Point Z (515389.1 4918366.7 2325.3)', - 'Point Z (515389 4918366.7 2325.4)', 'Point Z (515389 4918366.7 2325.3)', - 'Point Z (515389 4918366.6 2325.2)', 'Point Z (515389 4918366.6 2325.4)', - 'Point Z (515389 4918366.6 2325.3)', 'Point Z (515389 4918366.6 2325.3)', - 'Point Z (515389 4918366.7 2325.2)', 'Point Z (515389 4918366.7 2325.2)', - 'Point Z (515389 4918366.6 2325.4)', 'Point Z (515389 4918366.6 2325.3)', - 'Point Z (515389 4918366.7 2325.3)', 'Point Z (515389 4918366.7 2325.2)', - 'Point Z (515389 4918366.6 2325.3)', 'Point Z (515389 4918366.7 2325.3)', - 'Point Z (515389 4918366.7 2325.2)', 'Point Z (515388.6 4918366.7 2325.2)', - 'Point Z (515388.6 4918366.7 2325.2)', 'Point Z (515388.5 4918366.7 2325.1)', - 'Point Z (515388.4 4918366.6 2325.1)', 'Point Z (515388.4 4918366.7 2325.1)', - 'Point Z (515388.4 4918366.6 2325.1)', 'Point Z (515388.4 4918366.7 2325.1)', - 'Point Z (515388.4 4918366.6 2325.1)', 'Point Z (515388.3 4918366.6 2325.1)', - 'Point Z (515388.3 4918366.6 2325.1)', 'Point Z (515388.2 4918366.7 2325.1)', - 'Point Z (515388.2 4918366.6 2325.2)', 'Point Z (515388.2 4918366.7 2325.2)', - 'Point Z (515388.3 4918366.7 2325.1)', 'Point Z (515388.1 4918366.7 2325.2)', - 'Point Z (515388.1 4918366.7 2325.1)', 'Point Z (515388.1 4918366.7 2325.1)', - 'Point Z (515388.1 4918366.7 2325.2)', 'Point Z (515388 4918366.6 2325.1)', - 'Point Z (515389.1 4918366.6 2325.8)', 'Point Z (515389.1 4918366.6 2325.8)', - 'Point Z (515389.1 4918366.7 2325.8)', 'Point Z (515389.1 4918366.7 2325.6)', - 'Point Z (515389.1 4918366.6 2325.5)', 'Point Z (515389.1 4918366.6 2325.9)', - 'Point Z (515389.1 4918366.6 2325.9)', 'Point Z (515389.1 4918366.6 2325.9)', - 'Point Z (515389.2 4918366.7 2325.6)', 'Point Z (515389.1 4918366.7 2325.8)', - 'Point Z (515389.1 4918366.7 2325.5)', 'Point Z (515389.1 4918366.6 2326)', - 'Point Z (515389.1 4918366.6 2326)', 'Point Z (515389.1 4918366.7 2326)', - 'Point Z (515388.7 4918366.6 2330.6)', 'Point Z (515388.7 4918366.6 2330.6)', - 'Point Z (515388.7 4918366.6 2330.5)', 'Point Z (515388.7 4918366.7 2331)', - 'Point Z (515388.7 4918366.7 2330.7)', 'Point Z (515388.7 4918366.7 2330.8)', - 'Point Z (515388.7 4918366.7 2330.6)', 'Point Z (515388.7 4918366.7 2330.9)', - 'Point Z (515388.7 4918366.7 2330.8)', 'Point Z (515388.6 4918366.6 2331.1)', - 'Point Z (515388.6 4918366.7 2331.3)', 'Point Z (515388.6 4918366.7 2331.3)', - 'Point Z (515388.3 4918366.6 2334.7)', 'Point Z (515388.6 4918366.6 2331.1)', - 'Point Z (515388.6 4918366.6 2331)', 'Point Z (515388.6 4918366.7 2331)', - 'Point Z (515388.6 4918366.6 2331.3)', 'Point Z (515388.6 4918366.7 2331.2)', - 'Point Z (515388.6 4918366.6 2331.3)', 'Point Z (515388.6 4918366.7 2331.4)', - 'Point Z (515388.2 4918366.6 2332.4)', 'Point Z (515388.2 4918366.7 2332.2)', - 'Point Z (515388.2 4918366.7 2332.3)', 'Point Z (515388.2 4918366.7 2332.7)', - 'Point Z (515388.2 4918366.7 2332.7)', 'Point Z (515388.2 4918366.7 2332.7)', - 'Point Z (515388.2 4918366.7 2332.6)', 'Point Z (515388.2 4918366.6 2332.5)', - 'Point Z (515388.2 4918366.6 2332.5)', 'Point Z (515388.3 4918366.6 2334.7)', - 'Point Z (515388.3 4918366.7 2334.7)', 'Point Z (515388.2 4918366.7 2335.1)', - 'Point Z (515388.6 4918366.6 2331.2)', 'Point Z (515388.6 4918366.6 2331.1)', - 'Point Z (515388.6 4918366.7 2331.1)', 'Point Z (515388.6 4918366.7 2331.1)', - 'Point Z (515388.6 4918366.6 2331.3)', 'Point Z (515388.6 4918366.7 2331.3)', - 'Point Z (515388.6 4918366.6 2331.1)', 'Point Z (515388.6 4918366.7 2331.3)', - 'Point Z (515388.6 4918366.7 2331.2)', 'Point Z (515388.6 4918366.7 2331.4)', - 'Point Z (515388.6 4918366.7 2331.4)', 'Point Z (515388.2 4918366.6 2332.3)', - 'Point Z (515388.2 4918366.7 2332.4)', 'Point Z (515388.2 4918366.7 2332.4)', - 'Point Z (515388.2 4918366.7 2332.7)', 'Point Z (515388.2 4918366.6 2332.6)', - 'Point Z (515388.2 4918366.7 2332.6)', 'Point Z (515388.2 4918366.6 2332.5)', - 'Point Z (515388.2 4918366.6 2332.5)', 'Point Z (515388.2 4918366.7 2332.4)', - 'Point Z (515388.2 4918366.7 2332.6)', 'Point Z (515388.3 4918366.7 2334.7)']) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 0.0: 2325.1, + 0.1: 2325.2, + 0.2: 2332.4, + 0.3: 2325.1, + 0.4: 2325.1, + 0.5: 2325.1, + 0.6: 2331.4, + 0.7: 2330.6, + 0.9: 2332.7, + 1.0: 2325.4, + 1.1: 2325.6, + 1.2: 2325.6, + }, + ) + + self.assertCountEqual( + [g.asWkt(1) for g in results.asGeometries()], + [ + "Point Z (515389.1 4918366.7 2326.1)", + "Point Z (515389.1 4918366.6 2325.6)", + "Point Z (515389 4918366.6 2325.3)", + "Point Z (515388.2 4918366.6 2325.2)", + "Point Z (515388.3 4918366.7 2325.1)", + "Point Z (515387.9 4918366.7 2325.2)", + "Point Z (515388.7 4918366.6 2330.5)", + "Point Z (515388.6 4918366.6 2331.2)", + "Point Z (515388.9 4918366.6 2332.7)", + "Point Z (515388.9 4918366.7 2332.7)", + "Point Z (515388.6 4918366.6 2331.4)", + "Point Z (515388.2 4918366.7 2332.2)", + "Point Z (515388.2 4918366.7 2332.6)", + "Point Z (515388.2 4918366.6 2335)", + "Point Z (515388.6 4918366.6 2334.6)", + "Point Z (515389.1 4918366.6 2326.1)", + "Point Z (515389.1 4918366.6 2325.4)", + "Point Z (515389.1 4918366.6 2325.5)", + "Point Z (515389 4918366.6 2325.2)", + "Point Z (515388.3 4918366.6 2325.1)", + "Point Z (515388.6 4918366.6 2330.9)", + "Point Z (515388.7 4918366.6 2330.5)", + "Point Z (515388.6 4918366.6 2330.4)", + "Point Z (515389.1 4918366.6 2325.5)", + "Point Z (515389.1 4918366.6 2325.9)", + "Point Z (515389.1 4918366.6 2325.8)", + "Point Z (515389.1 4918366.7 2325.6)", + "Point Z (515389.1 4918366.6 2325.4)", + "Point Z (515389.1 4918366.7 2325.2)", + "Point Z (515389.1 4918366.6 2326)", + "Point Z (515389.1 4918366.6 2326)", + "Point Z (515389.1 4918366.6 2325.4)", + "Point Z (515389.1 4918366.7 2325.3)", + "Point Z (515389 4918366.6 2325.3)", + "Point Z (515389.1 4918366.7 2325.2)", + "Point Z (515389 4918366.6 2325.4)", + "Point Z (515389 4918366.6 2325.4)", + "Point Z (515389 4918366.7 2325.2)", + "Point Z (515389 4918366.7 2325.4)", + "Point Z (515388.6 4918366.6 2325.2)", + "Point Z (515388.6 4918366.7 2325.2)", + "Point Z (515388.5 4918366.7 2325.2)", + "Point Z (515388.5 4918366.7 2325.2)", + "Point Z (515388.4 4918366.6 2325.1)", + "Point Z (515388.3 4918366.6 2325.1)", + "Point Z (515388.3 4918366.7 2325.1)", + "Point Z (515388.2 4918366.6 2325.1)", + "Point Z (515388.2 4918366.6 2325.2)", + "Point Z (515388.2 4918366.6 2325.2)", + "Point Z (515388.2 4918366.7 2325.2)", + "Point Z (515388.1 4918366.6 2325.2)", + "Point Z (515388.1 4918366.6 2325.2)", + "Point Z (515388 4918366.7 2325.2)", + "Point Z (515388 4918366.6 2325.1)", + "Point Z (515388 4918366.6 2325.2)", + "Point Z (515388.7 4918366.6 2330.6)", + "Point Z (515388.7 4918366.6 2330.5)", + "Point Z (515388.6 4918366.7 2331)", + "Point Z (515388.7 4918366.7 2330.9)", + "Point Z (515388.6 4918366.6 2330.9)", + "Point Z (515388.6 4918366.6 2330.8)", + "Point Z (515388.7 4918366.7 2330.7)", + "Point Z (515388.6 4918366.7 2330.6)", + "Point Z (515389.1 4918366.6 2325.5)", + "Point Z (515389.1 4918366.6 2325.5)", + "Point Z (515389.1 4918366.7 2325.5)", + "Point Z (515389.1 4918366.7 2325.2)", + "Point Z (515389.1 4918366.6 2325.4)", + "Point Z (515389.1 4918366.7 2325.2)", + "Point Z (515389.1 4918366.7 2325.5)", + "Point Z (515389.1 4918366.6 2325.4)", + "Point Z (515389.1 4918366.7 2325.3)", + "Point Z (515389.1 4918366.7 2325.2)", + "Point Z (515389.1 4918366.7 2325.2)", + "Point Z (515389.1 4918366.6 2325.3)", + "Point Z (515389.1 4918366.7 2325.4)", + "Point Z (515389.1 4918366.6 2325.3)", + "Point Z (515389 4918366.7 2325.3)", + "Point Z (515389 4918366.7 2325.3)", + "Point Z (515389.1 4918366.7 2325.3)", + "Point Z (515389 4918366.7 2325.4)", + "Point Z (515389 4918366.7 2325.3)", + "Point Z (515389 4918366.6 2325.2)", + "Point Z (515389 4918366.6 2325.4)", + "Point Z (515389 4918366.6 2325.3)", + "Point Z (515389 4918366.6 2325.3)", + "Point Z (515389 4918366.7 2325.2)", + "Point Z (515389 4918366.7 2325.2)", + "Point Z (515389 4918366.6 2325.4)", + "Point Z (515389 4918366.6 2325.3)", + "Point Z (515389 4918366.7 2325.3)", + "Point Z (515389 4918366.7 2325.2)", + "Point Z (515389 4918366.6 2325.3)", + "Point Z (515389 4918366.7 2325.3)", + "Point Z (515389 4918366.7 2325.2)", + "Point Z (515388.6 4918366.7 2325.2)", + "Point Z (515388.6 4918366.7 2325.2)", + "Point Z (515388.5 4918366.7 2325.1)", + "Point Z (515388.4 4918366.6 2325.1)", + "Point Z (515388.4 4918366.7 2325.1)", + "Point Z (515388.4 4918366.6 2325.1)", + "Point Z (515388.4 4918366.7 2325.1)", + "Point Z (515388.4 4918366.6 2325.1)", + "Point Z (515388.3 4918366.6 2325.1)", + "Point Z (515388.3 4918366.6 2325.1)", + "Point Z (515388.2 4918366.7 2325.1)", + "Point Z (515388.2 4918366.6 2325.2)", + "Point Z (515388.2 4918366.7 2325.2)", + "Point Z (515388.3 4918366.7 2325.1)", + "Point Z (515388.1 4918366.7 2325.2)", + "Point Z (515388.1 4918366.7 2325.1)", + "Point Z (515388.1 4918366.7 2325.1)", + "Point Z (515388.1 4918366.7 2325.2)", + "Point Z (515388 4918366.6 2325.1)", + "Point Z (515389.1 4918366.6 2325.8)", + "Point Z (515389.1 4918366.6 2325.8)", + "Point Z (515389.1 4918366.7 2325.8)", + "Point Z (515389.1 4918366.7 2325.6)", + "Point Z (515389.1 4918366.6 2325.5)", + "Point Z (515389.1 4918366.6 2325.9)", + "Point Z (515389.1 4918366.6 2325.9)", + "Point Z (515389.1 4918366.6 2325.9)", + "Point Z (515389.2 4918366.7 2325.6)", + "Point Z (515389.1 4918366.7 2325.8)", + "Point Z (515389.1 4918366.7 2325.5)", + "Point Z (515389.1 4918366.6 2326)", + "Point Z (515389.1 4918366.6 2326)", + "Point Z (515389.1 4918366.7 2326)", + "Point Z (515388.7 4918366.6 2330.6)", + "Point Z (515388.7 4918366.6 2330.6)", + "Point Z (515388.7 4918366.6 2330.5)", + "Point Z (515388.7 4918366.7 2331)", + "Point Z (515388.7 4918366.7 2330.7)", + "Point Z (515388.7 4918366.7 2330.8)", + "Point Z (515388.7 4918366.7 2330.6)", + "Point Z (515388.7 4918366.7 2330.9)", + "Point Z (515388.7 4918366.7 2330.8)", + "Point Z (515388.6 4918366.6 2331.1)", + "Point Z (515388.6 4918366.7 2331.3)", + "Point Z (515388.6 4918366.7 2331.3)", + "Point Z (515388.3 4918366.6 2334.7)", + "Point Z (515388.6 4918366.6 2331.1)", + "Point Z (515388.6 4918366.6 2331)", + "Point Z (515388.6 4918366.7 2331)", + "Point Z (515388.6 4918366.6 2331.3)", + "Point Z (515388.6 4918366.7 2331.2)", + "Point Z (515388.6 4918366.6 2331.3)", + "Point Z (515388.6 4918366.7 2331.4)", + "Point Z (515388.2 4918366.6 2332.4)", + "Point Z (515388.2 4918366.7 2332.2)", + "Point Z (515388.2 4918366.7 2332.3)", + "Point Z (515388.2 4918366.7 2332.7)", + "Point Z (515388.2 4918366.7 2332.7)", + "Point Z (515388.2 4918366.7 2332.7)", + "Point Z (515388.2 4918366.7 2332.6)", + "Point Z (515388.2 4918366.6 2332.5)", + "Point Z (515388.2 4918366.6 2332.5)", + "Point Z (515388.3 4918366.6 2334.7)", + "Point Z (515388.3 4918366.7 2334.7)", + "Point Z (515388.2 4918366.7 2335.1)", + "Point Z (515388.6 4918366.6 2331.2)", + "Point Z (515388.6 4918366.6 2331.1)", + "Point Z (515388.6 4918366.7 2331.1)", + "Point Z (515388.6 4918366.7 2331.1)", + "Point Z (515388.6 4918366.6 2331.3)", + "Point Z (515388.6 4918366.7 2331.3)", + "Point Z (515388.6 4918366.6 2331.1)", + "Point Z (515388.6 4918366.7 2331.3)", + "Point Z (515388.6 4918366.7 2331.2)", + "Point Z (515388.6 4918366.7 2331.4)", + "Point Z (515388.6 4918366.7 2331.4)", + "Point Z (515388.2 4918366.6 2332.3)", + "Point Z (515388.2 4918366.7 2332.4)", + "Point Z (515388.2 4918366.7 2332.4)", + "Point Z (515388.2 4918366.7 2332.7)", + "Point Z (515388.2 4918366.6 2332.6)", + "Point Z (515388.2 4918366.7 2332.6)", + "Point Z (515388.2 4918366.6 2332.5)", + "Point Z (515388.2 4918366.6 2332.5)", + "Point Z (515388.2 4918366.7 2332.4)", + "Point Z (515388.2 4918366.7 2332.6)", + "Point Z (515388.3 4918366.7 2334.7)", + ], + ) self.assertAlmostEqual(results.zRange().lower(), 2325.1325, 2) self.assertAlmostEqual(results.zRange().upper(), 2335.0755, 2) features = results.asFeatures(Qgis.ProfileExportType.Features3D) self.assertEqual(len(features), 182) self.assertEqual(features[0].layerIdentifier, pcl.id()) - self.assertEqual(features[0].geometry.asWkt(1), - 'Point Z (515389.1 4918366.7 2326.1)') + self.assertEqual( + features[0].geometry.asWkt(1), "Point Z (515389.1 4918366.7 2326.1)" + ) self.assertEqual(features[-1].layerIdentifier, pcl.id()) - self.assertEqual(features[-1].geometry.asWkt(1), - 'Point Z (515388.3 4918366.7 2334.7)') + self.assertEqual( + features[-1].geometry.asWkt(1), "Point Z (515388.3 4918366.7 2334.7)" + ) features = results.asFeatures(Qgis.ProfileExportType.Profile2D) self.assertEqual(len(features), 182) self.assertEqual(features[0].layerIdentifier, pcl.id()) - self.assertEqual(features[0].geometry.asWkt(1), - 'Point (1.1 2326.1)') + self.assertEqual(features[0].geometry.asWkt(1), "Point (1.1 2326.1)") self.assertEqual(features[-1].layerIdentifier, pcl.id()) - self.assertEqual(features[-1].geometry.asWkt(1), - 'Point (0.3 2334.7)') + self.assertEqual(features[-1].geometry.asWkt(1), "Point (0.3 2334.7)") features = results.asFeatures(Qgis.ProfileExportType.DistanceVsElevationTable) self.assertEqual(len(features), 182) self.assertEqual(features[0].layerIdentifier, pcl.id()) - self.assertAlmostEqual(features[0].attributes['distance'], 1.129138, 2) - self.assertAlmostEqual(features[0].attributes['elevation'], 2326.052, 2) - self.assertEqual(features[0].geometry.asWkt(1), 'Point Z (515389.1 4918366.7 2326.1)') - self.assertEqual(features[-1].geometry.asWkt(1), 'Point Z (515388.3 4918366.7 2334.7)') - self.assertAlmostEqual(features[-1].attributes['distance'], 0.319292, 2) - self.assertAlmostEqual(features[-1].attributes['elevation'], 2334.69125, 2) + self.assertAlmostEqual(features[0].attributes["distance"], 1.129138, 2) + self.assertAlmostEqual(features[0].attributes["elevation"], 2326.052, 2) + self.assertEqual( + features[0].geometry.asWkt(1), "Point Z (515389.1 4918366.7 2326.1)" + ) + self.assertEqual( + features[-1].geometry.asWkt(1), "Point Z (515388.3 4918366.7 2334.7)" + ) + self.assertAlmostEqual(features[-1].attributes["distance"], 0.319292, 2) + self.assertAlmostEqual(features[-1].attributes["elevation"], 2334.69125, 2) # ensure maximum error is considered context.setMapUnitsPerDistancePixel(0.0001) self.assertTrue(generator.generateProfile(context)) results = generator.takeResults() - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 2), - {0.0: 2325.17, 0.01: 2325.14, 0.02: 2325.18, 0.03: 2325.14, 0.08: 2325.16, 0.11: 2325.16, - 0.12: 2325.14, 0.14: 2325.16, 0.15: 2325.14, 0.18: 2325.15, 0.19: 2325.15, 0.21: 2332.45, - 0.22: 2332.68, 0.23: 2332.44, 0.24: 2332.38, 0.25: 2332.37, 0.26: 2325.16, 0.27: 2332.27, - 0.28: 2335.05, 0.29: 2335.08, 0.3: 2334.71, 0.31: 2325.13, 0.32: 2325.14, 0.33: 2325.14, - 0.34: 2325.13, 0.36: 2325.14, 0.39: 2325.14, 0.41: 2325.13, 0.42: 2325.14, 0.44: 2325.14, - 0.46: 2325.14, 0.49: 2325.14, 0.53: 2325.14, 0.56: 2325.16, 0.57: 2325.16, 0.61: 2325.17, - 0.62: 2331.38, 0.63: 2330.44, 0.64: 2331.31, 0.65: 2331.41, 0.66: 2331.33, 0.67: 2331.13, - 0.68: 2331.14, 0.69: 2331.01, 0.7: 2331.0, 0.71: 2330.52, 0.72: 2330.61, 0.92: 2332.72, - 1.0: 2325.29, 1.01: 2325.25, 1.02: 2325.27, 1.03: 2325.39, 1.04: 2325.36, 1.05: 2325.24, - 1.07: 2325.41, 1.08: 2325.38, 1.09: 2325.23, 1.1: 2325.21, 1.11: 2325.3, 1.12: 2325.28, - 1.13: 2325.24, 1.15: 2326.11, 1.16: 2325.22, 1.17: 2325.82, 1.18: 2325.49, 1.19: 2325.55, - 1.2: 2325.58, 1.21: 2325.62}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 2), + { + 0.0: 2325.17, + 0.01: 2325.14, + 0.02: 2325.18, + 0.03: 2325.14, + 0.08: 2325.16, + 0.11: 2325.16, + 0.12: 2325.14, + 0.14: 2325.16, + 0.15: 2325.14, + 0.18: 2325.15, + 0.19: 2325.15, + 0.21: 2332.45, + 0.22: 2332.68, + 0.23: 2332.44, + 0.24: 2332.38, + 0.25: 2332.37, + 0.26: 2325.16, + 0.27: 2332.27, + 0.28: 2335.05, + 0.29: 2335.08, + 0.3: 2334.71, + 0.31: 2325.13, + 0.32: 2325.14, + 0.33: 2325.14, + 0.34: 2325.13, + 0.36: 2325.14, + 0.39: 2325.14, + 0.41: 2325.13, + 0.42: 2325.14, + 0.44: 2325.14, + 0.46: 2325.14, + 0.49: 2325.14, + 0.53: 2325.14, + 0.56: 2325.16, + 0.57: 2325.16, + 0.61: 2325.17, + 0.62: 2331.38, + 0.63: 2330.44, + 0.64: 2331.31, + 0.65: 2331.41, + 0.66: 2331.33, + 0.67: 2331.13, + 0.68: 2331.14, + 0.69: 2331.01, + 0.7: 2331.0, + 0.71: 2330.52, + 0.72: 2330.61, + 0.92: 2332.72, + 1.0: 2325.29, + 1.01: 2325.25, + 1.02: 2325.27, + 1.03: 2325.39, + 1.04: 2325.36, + 1.05: 2325.24, + 1.07: 2325.41, + 1.08: 2325.38, + 1.09: 2325.23, + 1.1: 2325.21, + 1.11: 2325.3, + 1.12: 2325.28, + 1.13: 2325.24, + 1.15: 2326.11, + 1.16: 2325.22, + 1.17: 2325.82, + 1.18: 2325.49, + 1.19: 2325.55, + 1.2: 2325.58, + 1.21: 2325.62, + }, + ) # ensure distance/elevation ranges are respected context.setDistanceRange(QgsDoubleRange(0.3, 0.7)) self.assertTrue(generator.generateProfile(context)) results = generator.takeResults() - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 2), - {0.3: 2334.71, 0.31: 2325.13, 0.32: 2325.14, 0.33: 2325.14, 0.34: 2325.13, 0.36: 2325.14, - 0.39: 2325.14, 0.41: 2325.13, 0.42: 2325.14, 0.44: 2325.14, 0.46: 2325.14, 0.49: 2325.14, - 0.53: 2325.14, 0.56: 2325.16, 0.57: 2325.16, 0.61: 2325.17, 0.62: 2331.38, 0.63: 2330.44, - 0.64: 2331.31, 0.65: 2331.41, 0.66: 2331.33, 0.67: 2331.13, 0.68: 2331.14, 0.69: 2331.01, - 0.7: 2330.97}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 2), + { + 0.3: 2334.71, + 0.31: 2325.13, + 0.32: 2325.14, + 0.33: 2325.14, + 0.34: 2325.13, + 0.36: 2325.14, + 0.39: 2325.14, + 0.41: 2325.13, + 0.42: 2325.14, + 0.44: 2325.14, + 0.46: 2325.14, + 0.49: 2325.14, + 0.53: 2325.14, + 0.56: 2325.16, + 0.57: 2325.16, + 0.61: 2325.17, + 0.62: 2331.38, + 0.63: 2330.44, + 0.64: 2331.31, + 0.65: 2331.41, + 0.66: 2331.33, + 0.67: 2331.13, + 0.68: 2331.14, + 0.69: 2331.01, + 0.7: 2330.97, + }, + ) context.setElevationRange(QgsDoubleRange(2325, 2326)) self.assertTrue(generator.generateProfile(context)) results = generator.takeResults() - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 2), - {0.31: 2325.13, 0.32: 2325.14, 0.33: 2325.14, 0.34: 2325.13, 0.36: 2325.14, 0.39: 2325.14, - 0.41: 2325.13, 0.42: 2325.14, 0.44: 2325.14, 0.46: 2325.14, 0.49: 2325.14, 0.53: 2325.14, - 0.56: 2325.16, 0.57: 2325.16, 0.61: 2325.17, 0.64: 2325.18, 0.68: 2325.19}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 2), + { + 0.31: 2325.13, + 0.32: 2325.14, + 0.33: 2325.14, + 0.34: 2325.13, + 0.36: 2325.14, + 0.39: 2325.14, + 0.41: 2325.13, + 0.42: 2325.14, + 0.44: 2325.14, + 0.46: 2325.14, + 0.49: 2325.14, + 0.53: 2325.14, + 0.56: 2325.16, + 0.57: 2325.16, + 0.61: 2325.17, + 0.64: 2325.18, + 0.68: 2325.19, + }, + ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testSnapping(self): pcl = QgsPointCloudLayer( - os.path.join(unitTestDataPath(), 'point_clouds', 'ept', 'lone-star-laszip', 'ept.json'), 'test', 'ept') + os.path.join( + unitTestDataPath(), + "point_clouds", + "ept", + "lone-star-laszip", + "ept.json", + ), + "test", + "ept", + ) self.assertTrue(pcl.isValid()) pcl.elevationProperties().setMaximumScreenError(30) - pcl.elevationProperties().setMaximumScreenErrorUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) + pcl.elevationProperties().setMaximumScreenErrorUnit( + QgsUnitTypes.RenderUnit.RenderMillimeters + ) curve = QgsLineString() curve.fromWkt( - 'LineString (515387.94696552358800545 4918366.65919817332178354, 515389.15378401038469747 4918366.63842081092298031)') + "LineString (515387.94696552358800545 4918366.65919817332178354, 515389.15378401038469747 4918366.63842081092298031)" + ) req = QgsProfileRequest(curve) req.setCrs(pcl.crs()) req.setTolerance(0.05) @@ -280,17 +526,32 @@ def testSnapping(self): self.assertAlmostEqual(res.snappedPoint.distance(), 0.2783, 2) self.assertAlmostEqual(res.snappedPoint.elevation(), 2335.04575, 2) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testIdentify(self): pcl = QgsPointCloudLayer( - os.path.join(unitTestDataPath(), 'point_clouds', 'ept', 'lone-star-laszip', 'ept.json'), 'test', 'ept') + os.path.join( + unitTestDataPath(), + "point_clouds", + "ept", + "lone-star-laszip", + "ept.json", + ), + "test", + "ept", + ) self.assertTrue(pcl.isValid()) pcl.elevationProperties().setMaximumScreenError(30) - pcl.elevationProperties().setMaximumScreenErrorUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) + pcl.elevationProperties().setMaximumScreenErrorUnit( + QgsUnitTypes.RenderUnit.RenderMillimeters + ) curve = QgsLineString() curve.fromWkt( - 'LineString (515387.94696552358800545 4918366.65919817332178354, 515389.15378401038469747 4918366.63842081092298031)') + "LineString (515387.94696552358800545 4918366.65919817332178354, 515389.15378401038469747 4918366.63842081092298031)" + ) req = QgsProfileRequest(curve) req.setCrs(pcl.crs()) req.setTolerance(0.05) @@ -315,28 +576,123 @@ def testIdentify(self): res = r.identify(QgsProfilePoint(0.27, 2335), context) self.assertEqual(len(res), 1) self.assertEqual(res[0].layer(), pcl) - self.assertCountEqual(res[0].results(), [ - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1612, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.2245, 'Y': 4918366.61, 'Z': 2335.04575}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 199, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.60825, 'Y': 4918366.628, 'Z': 2334.60175}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1678, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.27575, 'Y': 4918366.6325, 'Z': 2334.728}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1605, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.25025, 'Y': 4918366.62825, 'Z': 2334.7095}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1633, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.28575, 'Y': 4918366.66725, 'Z': 2334.7065}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1547, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.238, 'Y': 4918366.6555, 'Z': 2335.0755}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1603, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.26675, 'Y': 4918366.685, 'Z': 2334.69125}]) + self.assertCountEqual( + res[0].results(), + [ + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1612, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.2245, + "Y": 4918366.61, + "Z": 2335.04575, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 199, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.60825, + "Y": 4918366.628, + "Z": 2334.60175, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1678, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.27575, + "Y": 4918366.6325, + "Z": 2334.728, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1605, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.25025, + "Y": 4918366.62825, + "Z": 2334.7095, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1633, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.28575, + "Y": 4918366.66725, + "Z": 2334.7065, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1547, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.238, + "Y": 4918366.6555, + "Z": 2335.0755, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1603, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.26675, + "Y": 4918366.685, + "Z": 2334.69125, + }, + ], + ) context.maximumPointDistanceDelta = 0 context.maximumPointElevationDelta = 0 @@ -344,93 +700,413 @@ def testIdentify(self): res = r.identify(QgsDoubleRange(0.2, 0.3), QgsDoubleRange(2330, 2360), context) self.assertEqual(len(res), 1) self.assertEqual(res[0].layer(), pcl) - self.assertCountEqual(res[0].results(), [ - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 565, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.21275, 'Y': 4918366.65675, 'Z': 2332.19075}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1357, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.17375, 'Y': 4918366.679, 'Z': 2332.56025}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1612, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.2245, 'Y': 4918366.61, 'Z': 2335.04575}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1452, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.1985, 'Y': 4918366.61025, 'Z': 2332.38325}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 501, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.2145, 'Y': 4918366.66275, 'Z': 2332.16675}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1197, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.22125, 'Y': 4918366.68675, 'Z': 2332.2715}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 202, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.16825, 'Y': 4918366.6625, 'Z': 2332.73325}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 922, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.165, 'Y': 4918366.65025, 'Z': 2332.6565}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 955, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.1715, 'Y': 4918366.673, 'Z': 2332.6835}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1195, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.1785, 'Y': 4918366.6955, 'Z': 2332.6125}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1432, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.15825, 'Y': 4918366.62575, 'Z': 2332.501}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1413, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.1615, 'Y': 4918366.63675, 'Z': 2332.453}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1547, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.238, 'Y': 4918366.6555, 'Z': 2335.0755}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1259, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.20925, 'Y': 4918366.646, 'Z': 2332.29025}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1369, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.1895, 'Y': 4918366.662, 'Z': 2332.38325}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1394, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.2015, 'Y': 4918366.703, 'Z': 2332.36625}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 688, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.166, 'Y': 4918366.654, 'Z': 2332.7065}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1399, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.17225, 'Y': 4918366.60575, 'Z': 2332.57475}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1024, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.17475, 'Y': 4918366.683, 'Z': 2332.636}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1274, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.1585, 'Y': 4918366.62625, 'Z': 2332.5265}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1443, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.15875, 'Y': 4918366.62725, 'Z': 2332.4765}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1332, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.18, 'Y': 4918366.69875, 'Z': 2332.43775}, - {'Classification': 0, 'EdgeOfFlightLine': 0, 'GpsTime': 0.0, 'Intensity': 1295, 'NumberOfReturns': 1, - 'OriginId': 3, 'PointSourceId': 0, 'ReturnNumber': 1, 'ScanAngleRank': 0.0, 'ScanDirectionFlag': 1, - 'UserData': 0, 'X': 515388.1725, 'Y': 4918366.67475, 'Z': 2332.5855}]) - - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + self.assertCountEqual( + res[0].results(), + [ + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 565, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.21275, + "Y": 4918366.65675, + "Z": 2332.19075, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1357, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.17375, + "Y": 4918366.679, + "Z": 2332.56025, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1612, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.2245, + "Y": 4918366.61, + "Z": 2335.04575, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1452, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.1985, + "Y": 4918366.61025, + "Z": 2332.38325, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 501, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.2145, + "Y": 4918366.66275, + "Z": 2332.16675, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1197, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.22125, + "Y": 4918366.68675, + "Z": 2332.2715, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 202, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.16825, + "Y": 4918366.6625, + "Z": 2332.73325, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 922, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.165, + "Y": 4918366.65025, + "Z": 2332.6565, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 955, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.1715, + "Y": 4918366.673, + "Z": 2332.6835, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1195, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.1785, + "Y": 4918366.6955, + "Z": 2332.6125, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1432, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.15825, + "Y": 4918366.62575, + "Z": 2332.501, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1413, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.1615, + "Y": 4918366.63675, + "Z": 2332.453, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1547, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.238, + "Y": 4918366.6555, + "Z": 2335.0755, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1259, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.20925, + "Y": 4918366.646, + "Z": 2332.29025, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1369, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.1895, + "Y": 4918366.662, + "Z": 2332.38325, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1394, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.2015, + "Y": 4918366.703, + "Z": 2332.36625, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 688, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.166, + "Y": 4918366.654, + "Z": 2332.7065, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1399, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.17225, + "Y": 4918366.60575, + "Z": 2332.57475, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1024, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.17475, + "Y": 4918366.683, + "Z": 2332.636, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1274, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.1585, + "Y": 4918366.62625, + "Z": 2332.5265, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1443, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.15875, + "Y": 4918366.62725, + "Z": 2332.4765, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1332, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.18, + "Y": 4918366.69875, + "Z": 2332.43775, + }, + { + "Classification": 0, + "EdgeOfFlightLine": 0, + "GpsTime": 0.0, + "Intensity": 1295, + "NumberOfReturns": 1, + "OriginId": 3, + "PointSourceId": 0, + "ReturnNumber": 1, + "ScanAngleRank": 0.0, + "ScanDirectionFlag": 1, + "UserData": 0, + "X": 515388.1725, + "Y": 4918366.67475, + "Z": 2332.5855, + }, + ], + ) + + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testProfileRenderFixedColor(self): pcl = QgsPointCloudLayer( - os.path.join(unitTestDataPath(), 'point_clouds', 'ept', 'lone-star-laszip', 'ept.json'), 'test', 'ept') + os.path.join( + unitTestDataPath(), + "point_clouds", + "ept", + "lone-star-laszip", + "ept.json", + ), + "test", + "ept", + ) self.assertTrue(pcl.isValid()) pcl.elevationProperties().setMaximumScreenError(30) - pcl.elevationProperties().setMaximumScreenErrorUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) + pcl.elevationProperties().setMaximumScreenErrorUnit( + QgsUnitTypes.RenderUnit.RenderMillimeters + ) pcl.elevationProperties().setPointSymbol(Qgis.PointCloudSymbol.Square) pcl.elevationProperties().setPointColor(QColor(255, 0, 255)) pcl.elevationProperties().setPointSize(3) - pcl.elevationProperties().setPointSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) + pcl.elevationProperties().setPointSizeUnit( + QgsUnitTypes.RenderUnit.RenderMillimeters + ) pcl.elevationProperties().setRespectLayerColors(False) curve = QgsLineString() curve.fromWkt( - 'LineString (515387.94696552358800545 4918366.65919817332178354, 515389.15378401038469747 4918366.63842081092298031)') + "LineString (515387.94696552358800545 4918366.65919817332178354, 515389.15378401038469747 4918366.63842081092298031)" + ) req = QgsProfileRequest(curve) req.setCrs(pcl.crs()) req.setTolerance(0.05) @@ -440,28 +1116,41 @@ def testProfileRenderFixedColor(self): res = plot_renderer.renderToImage(400, 400, 0, curve.length(), 2320, 2330) self.assertTrue( - self.image_check('point_cloud_layer_fixed_color', 'point_cloud_layer_fixed_color', res, - color_tolerance=2, - allowed_mismatch=20) + self.image_check( + "point_cloud_layer_fixed_color", + "point_cloud_layer_fixed_color", + res, + color_tolerance=2, + allowed_mismatch=20, + ) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def test_vertical_transformation_4979_to_4985(self): pcl = QgsPointCloudLayer( - self.get_test_data_path('point_clouds/ept/rgb16/ept.json').as_posix(), 'test', 'ept') + self.get_test_data_path("point_clouds/ept/rgb16/ept.json").as_posix(), + "test", + "ept", + ) self.assertTrue(pcl.isValid()) - pcl.setCrs(QgsCoordinateReferenceSystem('EPSG:4979')) - self.assertEqual(pcl.crs3D().authid(), 'EPSG:4979') + pcl.setCrs(QgsCoordinateReferenceSystem("EPSG:4979")) + self.assertEqual(pcl.crs3D().authid(), "EPSG:4979") pcl.elevationProperties().setMaximumScreenError(30) - pcl.elevationProperties().setMaximumScreenErrorUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) + pcl.elevationProperties().setMaximumScreenErrorUnit( + QgsUnitTypes.RenderUnit.RenderMillimeters + ) curve = QgsLineString() curve.fromWkt( - 'LineString (7.37810825606327025 2.69442638932088574, 7.44718273878368908 2.71100426469523947)') + "LineString (7.37810825606327025 2.69442638932088574, 7.44718273878368908 2.71100426469523947)" + ) req = QgsProfileRequest(curve) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:4985')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:4985")) req.setTolerance(0.005) generator = pcl.createProfileGenerator(req) @@ -471,42 +1160,42 @@ def test_vertical_transformation_4979_to_4985(self): self.assertTrue(generator.generateProfile(context)) results = generator.takeResults() - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 3), - {0.013: -5.409, 0.064: -5.41}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 3), + {0.013: -5.409, 0.064: -5.41}, + ) - self.assertCountEqual([g.asWkt(3) for g in results.asGeometries()], - ['Point Z (7.39 2.7 -5.409)', 'Point Z (7.44 2.71 -5.41)']) + self.assertCountEqual( + [g.asWkt(3) for g in results.asGeometries()], + ["Point Z (7.39 2.7 -5.409)", "Point Z (7.44 2.71 -5.41)"], + ) self.assertAlmostEqual(results.zRange().lower(), -5.40999, 4) self.assertAlmostEqual(results.zRange().upper(), -5.40920, 4) features = results.asFeatures(Qgis.ProfileExportType.Features3D) self.assertEqual(len(features), 2) self.assertEqual(features[0].layerIdentifier, pcl.id()) - self.assertEqual(features[0].geometry.asWkt(3), - 'Point Z (7.39 2.7 -5.409)') + self.assertEqual(features[0].geometry.asWkt(3), "Point Z (7.39 2.7 -5.409)") self.assertEqual(features[-1].layerIdentifier, pcl.id()) - self.assertEqual(features[-1].geometry.asWkt(3), - 'Point Z (7.44 2.71 -5.41)') + self.assertEqual(features[-1].geometry.asWkt(3), "Point Z (7.44 2.71 -5.41)") features = results.asFeatures(Qgis.ProfileExportType.Profile2D) self.assertEqual(len(features), 2) self.assertEqual(features[0].layerIdentifier, pcl.id()) - self.assertEqual(features[0].geometry.asWkt(3), - 'Point (0.013 -5.409)') + self.assertEqual(features[0].geometry.asWkt(3), "Point (0.013 -5.409)") self.assertEqual(features[-1].layerIdentifier, pcl.id()) - self.assertEqual(features[-1].geometry.asWkt(3), - 'Point (0.064 -5.41)') + self.assertEqual(features[-1].geometry.asWkt(3), "Point (0.064 -5.41)") features = results.asFeatures(Qgis.ProfileExportType.DistanceVsElevationTable) self.assertEqual(len(features), 2) self.assertEqual(features[0].layerIdentifier, pcl.id()) - self.assertAlmostEqual(features[0].attributes['distance'], 0.012704944, 4) - self.assertAlmostEqual(features[0].attributes['elevation'], -5.409209, 4) - self.assertEqual(features[0].geometry.asWkt(3), 'Point Z (7.39 2.7 -5.409)') - self.assertEqual(features[-1].geometry.asWkt(3), 'Point Z (7.44 2.71 -5.41)') - self.assertAlmostEqual(features[-1].attributes['distance'], 0.063658039178, 4) - self.assertAlmostEqual(features[-1].attributes['elevation'], -5.409997397, 4) + self.assertAlmostEqual(features[0].attributes["distance"], 0.012704944, 4) + self.assertAlmostEqual(features[0].attributes["elevation"], -5.409209, 4) + self.assertEqual(features[0].geometry.asWkt(3), "Point Z (7.39 2.7 -5.409)") + self.assertEqual(features[-1].geometry.asWkt(3), "Point Z (7.44 2.71 -5.41)") + self.assertAlmostEqual(features[-1].attributes["distance"], 0.063658039178, 4) + self.assertAlmostEqual(features[-1].attributes["elevation"], -5.409997397, 4) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspointcloudprovider.py b/tests/src/python/test_qgspointcloudprovider.py index 88fc30a1bb3b..9a1ab3ad0411 100644 --- a/tests/src/python/test_qgspointcloudprovider.py +++ b/tests/src/python/test_qgspointcloudprovider.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '09/11/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "09/11/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.core import ( QgsPointCloudLayer, @@ -24,80 +25,225 @@ class TestQgsPointCloudDataProvider(QgisTestCase): - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testStatistics(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) - self.assertEqual(layer.dataProvider().metadataStatistic('X', QgsStatisticalSummary.Statistic.Count), 253) - self.assertEqual(layer.dataProvider().metadataStatistic('X', QgsStatisticalSummary.Statistic.Min), 498062.0) - self.assertEqual(layer.dataProvider().metadataStatistic('X', QgsStatisticalSummary.Statistic.Max), 498067.39) - self.assertAlmostEqual(layer.dataProvider().metadataStatistic('X', QgsStatisticalSummary.Statistic.Range), 5.39000000001397, 5) - self.assertAlmostEqual(layer.dataProvider().metadataStatistic('X', QgsStatisticalSummary.Statistic.Mean), 498064.7342292491, 5) - self.assertAlmostEqual(layer.dataProvider().metadataStatistic('X', QgsStatisticalSummary.Statistic.StDev), - 1.5636647117681046, 5) + self.assertEqual( + layer.dataProvider().metadataStatistic( + "X", QgsStatisticalSummary.Statistic.Count + ), + 253, + ) + self.assertEqual( + layer.dataProvider().metadataStatistic( + "X", QgsStatisticalSummary.Statistic.Min + ), + 498062.0, + ) + self.assertEqual( + layer.dataProvider().metadataStatistic( + "X", QgsStatisticalSummary.Statistic.Max + ), + 498067.39, + ) + self.assertAlmostEqual( + layer.dataProvider().metadataStatistic( + "X", QgsStatisticalSummary.Statistic.Range + ), + 5.39000000001397, + 5, + ) + self.assertAlmostEqual( + layer.dataProvider().metadataStatistic( + "X", QgsStatisticalSummary.Statistic.Mean + ), + 498064.7342292491, + 5, + ) + self.assertAlmostEqual( + layer.dataProvider().metadataStatistic( + "X", QgsStatisticalSummary.Statistic.StDev + ), + 1.5636647117681046, + 5, + ) with self.assertRaises(ValueError): - layer.dataProvider().metadataStatistic('X', QgsStatisticalSummary.Statistic.Majority) + layer.dataProvider().metadataStatistic( + "X", QgsStatisticalSummary.Statistic.Majority + ) with self.assertRaises(ValueError): - layer.dataProvider().metadataStatistic('Xxxxx', QgsStatisticalSummary.Statistic.Count) - - self.assertEqual(layer.dataProvider().metadataStatistic('Intensity', QgsStatisticalSummary.Statistic.Count), 253) - self.assertEqual(layer.dataProvider().metadataStatistic('Intensity', QgsStatisticalSummary.Statistic.Min), 199) - self.assertEqual(layer.dataProvider().metadataStatistic('Intensity', QgsStatisticalSummary.Statistic.Max), 2086.0) - self.assertAlmostEqual(layer.dataProvider().metadataStatistic('Intensity', QgsStatisticalSummary.Statistic.Range), 1887.0, 5) - self.assertAlmostEqual(layer.dataProvider().metadataStatistic('Intensity', QgsStatisticalSummary.Statistic.Mean), 728.521739130435, 5) - self.assertAlmostEqual(layer.dataProvider().metadataStatistic('Intensity', QgsStatisticalSummary.Statistic.StDev), - 440.9652417017358, 5) - - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + layer.dataProvider().metadataStatistic( + "Xxxxx", QgsStatisticalSummary.Statistic.Count + ) + + self.assertEqual( + layer.dataProvider().metadataStatistic( + "Intensity", QgsStatisticalSummary.Statistic.Count + ), + 253, + ) + self.assertEqual( + layer.dataProvider().metadataStatistic( + "Intensity", QgsStatisticalSummary.Statistic.Min + ), + 199, + ) + self.assertEqual( + layer.dataProvider().metadataStatistic( + "Intensity", QgsStatisticalSummary.Statistic.Max + ), + 2086.0, + ) + self.assertAlmostEqual( + layer.dataProvider().metadataStatistic( + "Intensity", QgsStatisticalSummary.Statistic.Range + ), + 1887.0, + 5, + ) + self.assertAlmostEqual( + layer.dataProvider().metadataStatistic( + "Intensity", QgsStatisticalSummary.Statistic.Mean + ), + 728.521739130435, + 5, + ) + self.assertAlmostEqual( + layer.dataProvider().metadataStatistic( + "Intensity", QgsStatisticalSummary.Statistic.StDev + ), + 440.9652417017358, + 5, + ) + + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testMetadataClasses(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) - self.assertEqual(layer.dataProvider().metadataClasses('X'), []) - self.assertCountEqual(layer.dataProvider().metadataClasses('Classification'), [1, 2, 3, 5]) + self.assertEqual(layer.dataProvider().metadataClasses("X"), []) + self.assertCountEqual( + layer.dataProvider().metadataClasses("Classification"), [1, 2, 3, 5] + ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testMetadataClassStatistics(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) self.assertTrue(layer.isValid()) with self.assertRaises(ValueError): - self.assertEqual(layer.dataProvider().metadataClassStatistic('X', 0, QgsStatisticalSummary.Statistic.Count), []) + self.assertEqual( + layer.dataProvider().metadataClassStatistic( + "X", 0, QgsStatisticalSummary.Statistic.Count + ), + [], + ) with self.assertRaises(ValueError): - self.assertEqual(layer.dataProvider().metadataClassStatistic('Classification', 0, QgsStatisticalSummary.Statistic.Count), []) + self.assertEqual( + layer.dataProvider().metadataClassStatistic( + "Classification", 0, QgsStatisticalSummary.Statistic.Count + ), + [], + ) with self.assertRaises(ValueError): - self.assertEqual(layer.dataProvider().metadataClassStatistic('Classification', 1, QgsStatisticalSummary.Statistic.Sum), []) - - self.assertEqual(layer.dataProvider().metadataClassStatistic('Classification', 1, QgsStatisticalSummary.Statistic.Count), 1) - self.assertEqual(layer.dataProvider().metadataClassStatistic('Classification', 2, QgsStatisticalSummary.Statistic.Count), - 160) - self.assertEqual(layer.dataProvider().metadataClassStatistic('Classification', 3, QgsStatisticalSummary.Statistic.Count), - 89) - self.assertEqual(layer.dataProvider().metadataClassStatistic('Classification', 5, QgsStatisticalSummary.Statistic.Count), - 3) - - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + self.assertEqual( + layer.dataProvider().metadataClassStatistic( + "Classification", 1, QgsStatisticalSummary.Statistic.Sum + ), + [], + ) + + self.assertEqual( + layer.dataProvider().metadataClassStatistic( + "Classification", 1, QgsStatisticalSummary.Statistic.Count + ), + 1, + ) + self.assertEqual( + layer.dataProvider().metadataClassStatistic( + "Classification", 2, QgsStatisticalSummary.Statistic.Count + ), + 160, + ) + self.assertEqual( + layer.dataProvider().metadataClassStatistic( + "Classification", 3, QgsStatisticalSummary.Statistic.Count + ), + 89, + ) + self.assertEqual( + layer.dataProvider().metadataClassStatistic( + "Classification", 5, QgsStatisticalSummary.Statistic.Count + ), + 3, + ) + + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testOriginalMetadataEpt(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', 'test', 'ept') - self.assertEqual(layer.dataProvider().originalMetadata()['major_version'], 1.0) - self.assertEqual(layer.dataProvider().originalMetadata()['minor_version'], 2.0) - self.assertEqual(layer.dataProvider().originalMetadata()['software_id'], 'PDAL 2.1.0 (Releas)') # spellok - self.assertEqual(layer.dataProvider().originalMetadata()['creation_year'], 2020.0) - self.assertEqual(layer.dataProvider().originalMetadata()['creation_doy'], 309.0) - - @unittest.skipIf('pdal' not in QgsProviderRegistry.instance().providerList(), 'PDAL provider not available') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/sunshine-coast/ept.json", + "test", + "ept", + ) + self.assertEqual(layer.dataProvider().originalMetadata()["major_version"], 1.0) + self.assertEqual(layer.dataProvider().originalMetadata()["minor_version"], 2.0) + self.assertEqual( + layer.dataProvider().originalMetadata()["software_id"], + "PDAL 2.1.0 (Releas)", + ) # spellok + self.assertEqual( + layer.dataProvider().originalMetadata()["creation_year"], 2020.0 + ) + self.assertEqual(layer.dataProvider().originalMetadata()["creation_doy"], 309.0) + + @unittest.skipIf( + "pdal" not in QgsProviderRegistry.instance().providerList(), + "PDAL provider not available", + ) def testOriginalMetadataPdal(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/las/cloud.las', 'test', 'pdal') - self.assertEqual(layer.dataProvider().originalMetadata()['major_version'], 1.0) - self.assertEqual(layer.dataProvider().originalMetadata()['minor_version'], 2.0) - self.assertEqual(layer.dataProvider().originalMetadata()['software_id'], 'PDAL 2.1.0 (Releas)') # spellok - self.assertEqual(layer.dataProvider().originalMetadata()['creation_year'], 2020.0) - self.assertEqual(layer.dataProvider().originalMetadata()['creation_doy'], 309.0) - - -if __name__ == '__main__': + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/las/cloud.las", "test", "pdal" + ) + self.assertEqual(layer.dataProvider().originalMetadata()["major_version"], 1.0) + self.assertEqual(layer.dataProvider().originalMetadata()["minor_version"], 2.0) + self.assertEqual( + layer.dataProvider().originalMetadata()["software_id"], + "PDAL 2.1.0 (Releas)", + ) # spellok + self.assertEqual( + layer.dataProvider().originalMetadata()["creation_year"], 2020.0 + ) + self.assertEqual(layer.dataProvider().originalMetadata()["creation_doy"], 309.0) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspointcloudrgbrenderer.py b/tests/src/python/test_qgspointcloudrgbrenderer.py index 0ef759dc2650..1ba84e9b01d7 100644 --- a/tests/src/python/test_qgspointcloudrgbrenderer.py +++ b/tests/src/python/test_qgspointcloudrgbrenderer.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '09/11/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "09/11/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QDir, QSize from qgis.PyQt.QtGui import QPainter @@ -44,11 +45,16 @@ class TestQgsPointCloudRgbRenderer(QgisTestCase): @classmethod def control_path_prefix(cls): - return 'pointcloudrenderer' + return "pointcloudrenderer" - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testSetLayer(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/rgb/ept.json", "test", "ept" + ) self.assertTrue(layer.isValid()) # test that a point cloud with RGB attributes is automatically assigned the RGB renderer by default @@ -59,9 +65,14 @@ def testSetLayer(self): self.assertIsNone(layer.renderer().greenContrastEnhancement()) self.assertIsNone(layer.renderer().blueContrastEnhancement()) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testSetLayer16(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb16/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/rgb16/ept.json", "test", "ept" + ) self.assertTrue(layer.isValid()) # test that a point cloud with RGB attributes is automatically assigned the RGB renderer by default @@ -69,43 +80,61 @@ def testSetLayer16(self): # for this point cloud, we should default to 0-65024 ranges with contrast enhancement self.assertEqual(layer.renderer().redContrastEnhancement().minimumValue(), 0) - self.assertEqual(layer.renderer().redContrastEnhancement().maximumValue(), 65535.0) - self.assertEqual(layer.renderer().redContrastEnhancement().contrastEnhancementAlgorithm(), - QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum) + self.assertEqual( + layer.renderer().redContrastEnhancement().maximumValue(), 65535.0 + ) + self.assertEqual( + layer.renderer().redContrastEnhancement().contrastEnhancementAlgorithm(), + QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum, + ) self.assertEqual(layer.renderer().greenContrastEnhancement().minimumValue(), 0) - self.assertEqual(layer.renderer().greenContrastEnhancement().maximumValue(), 65535.0) - self.assertEqual(layer.renderer().greenContrastEnhancement().contrastEnhancementAlgorithm(), - QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum) + self.assertEqual( + layer.renderer().greenContrastEnhancement().maximumValue(), 65535.0 + ) + self.assertEqual( + layer.renderer().greenContrastEnhancement().contrastEnhancementAlgorithm(), + QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum, + ) self.assertEqual(layer.renderer().blueContrastEnhancement().minimumValue(), 0) - self.assertEqual(layer.renderer().blueContrastEnhancement().maximumValue(), 65535.0) - self.assertEqual(layer.renderer().blueContrastEnhancement().contrastEnhancementAlgorithm(), - QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum) + self.assertEqual( + layer.renderer().blueContrastEnhancement().maximumValue(), 65535.0 + ) + self.assertEqual( + layer.renderer().blueContrastEnhancement().contrastEnhancementAlgorithm(), + QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum, + ) def testBasic(self): renderer = QgsPointCloudRgbRenderer() - renderer.setBlueAttribute('b') - self.assertEqual(renderer.blueAttribute(), 'b') - renderer.setGreenAttribute('g') - self.assertEqual(renderer.greenAttribute(), 'g') - renderer.setRedAttribute('r') - self.assertEqual(renderer.redAttribute(), 'r') + renderer.setBlueAttribute("b") + self.assertEqual(renderer.blueAttribute(), "b") + renderer.setGreenAttribute("g") + self.assertEqual(renderer.greenAttribute(), "g") + renderer.setRedAttribute("r") + self.assertEqual(renderer.redAttribute(), "r") redce = QgsContrastEnhancement() redce.setMinimumValue(100) redce.setMaximumValue(120) - redce.setContrastEnhancementAlgorithm(QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchAndClipToMinimumMaximum) + redce.setContrastEnhancementAlgorithm( + QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchAndClipToMinimumMaximum + ) renderer.setRedContrastEnhancement(redce) greence = QgsContrastEnhancement() greence.setMinimumValue(130) greence.setMaximumValue(150) - greence.setContrastEnhancementAlgorithm(QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum) + greence.setContrastEnhancementAlgorithm( + QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum + ) renderer.setGreenContrastEnhancement(greence) bluece = QgsContrastEnhancement() bluece.setMinimumValue(170) bluece.setMaximumValue(190) - bluece.setContrastEnhancementAlgorithm(QgsContrastEnhancement.ContrastEnhancementAlgorithm.ClipToMinimumMaximum) + bluece.setContrastEnhancementAlgorithm( + QgsContrastEnhancement.ContrastEnhancementAlgorithm.ClipToMinimumMaximum + ) renderer.setBlueContrastEnhancement(bluece) renderer.setMaximumScreenError(18) @@ -116,69 +145,90 @@ def testBasic(self): rr = renderer.clone() self.assertEqual(rr.maximumScreenError(), 18) - self.assertEqual(rr.maximumScreenErrorUnit(), QgsUnitTypes.RenderUnit.RenderInches) + self.assertEqual( + rr.maximumScreenErrorUnit(), QgsUnitTypes.RenderUnit.RenderInches + ) self.assertEqual(rr.pointSize(), 13) self.assertEqual(rr.pointSizeUnit(), QgsUnitTypes.RenderUnit.RenderPoints) self.assertEqual(rr.pointSizeMapUnitScale().minScale, 1000) self.assertEqual(rr.pointSizeMapUnitScale().maxScale, 2000) - self.assertEqual(rr.blueAttribute(), 'b') - self.assertEqual(rr.greenAttribute(), 'g') - self.assertEqual(rr.redAttribute(), 'r') + self.assertEqual(rr.blueAttribute(), "b") + self.assertEqual(rr.greenAttribute(), "g") + self.assertEqual(rr.redAttribute(), "r") self.assertEqual(rr.redContrastEnhancement().minimumValue(), 100) self.assertEqual(rr.redContrastEnhancement().maximumValue(), 120) - self.assertEqual(rr.redContrastEnhancement().contrastEnhancementAlgorithm(), - QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchAndClipToMinimumMaximum) + self.assertEqual( + rr.redContrastEnhancement().contrastEnhancementAlgorithm(), + QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchAndClipToMinimumMaximum, + ) self.assertEqual(rr.greenContrastEnhancement().minimumValue(), 130) self.assertEqual(rr.greenContrastEnhancement().maximumValue(), 150) - self.assertEqual(rr.greenContrastEnhancement().contrastEnhancementAlgorithm(), - QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum) + self.assertEqual( + rr.greenContrastEnhancement().contrastEnhancementAlgorithm(), + QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum, + ) self.assertEqual(rr.blueContrastEnhancement().minimumValue(), 170) self.assertEqual(rr.blueContrastEnhancement().maximumValue(), 190) - self.assertEqual(rr.blueContrastEnhancement().contrastEnhancementAlgorithm(), - QgsContrastEnhancement.ContrastEnhancementAlgorithm.ClipToMinimumMaximum) + self.assertEqual( + rr.blueContrastEnhancement().contrastEnhancementAlgorithm(), + QgsContrastEnhancement.ContrastEnhancementAlgorithm.ClipToMinimumMaximum, + ) doc = QDomDocument("testdoc") elem = renderer.save(doc, QgsReadWriteContext()) r2 = QgsPointCloudRgbRenderer.create(elem, QgsReadWriteContext()) self.assertEqual(r2.maximumScreenError(), 18) - self.assertEqual(r2.maximumScreenErrorUnit(), QgsUnitTypes.RenderUnit.RenderInches) + self.assertEqual( + r2.maximumScreenErrorUnit(), QgsUnitTypes.RenderUnit.RenderInches + ) self.assertEqual(r2.pointSize(), 13) self.assertEqual(r2.pointSizeUnit(), QgsUnitTypes.RenderUnit.RenderPoints) self.assertEqual(r2.pointSizeMapUnitScale().minScale, 1000) self.assertEqual(r2.pointSizeMapUnitScale().maxScale, 2000) - self.assertEqual(r2.blueAttribute(), 'b') - self.assertEqual(r2.greenAttribute(), 'g') - self.assertEqual(r2.redAttribute(), 'r') + self.assertEqual(r2.blueAttribute(), "b") + self.assertEqual(r2.greenAttribute(), "g") + self.assertEqual(r2.redAttribute(), "r") self.assertEqual(r2.redContrastEnhancement().minimumValue(), 100) self.assertEqual(r2.redContrastEnhancement().maximumValue(), 120) - self.assertEqual(r2.redContrastEnhancement().contrastEnhancementAlgorithm(), - QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchAndClipToMinimumMaximum) + self.assertEqual( + r2.redContrastEnhancement().contrastEnhancementAlgorithm(), + QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchAndClipToMinimumMaximum, + ) self.assertEqual(r2.greenContrastEnhancement().minimumValue(), 130) self.assertEqual(r2.greenContrastEnhancement().maximumValue(), 150) - self.assertEqual(r2.greenContrastEnhancement().contrastEnhancementAlgorithm(), - QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum) + self.assertEqual( + r2.greenContrastEnhancement().contrastEnhancementAlgorithm(), + QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum, + ) self.assertEqual(r2.blueContrastEnhancement().minimumValue(), 170) self.assertEqual(r2.blueContrastEnhancement().maximumValue(), 190) - self.assertEqual(r2.blueContrastEnhancement().contrastEnhancementAlgorithm(), - QgsContrastEnhancement.ContrastEnhancementAlgorithm.ClipToMinimumMaximum) + self.assertEqual( + r2.blueContrastEnhancement().contrastEnhancementAlgorithm(), + QgsContrastEnhancement.ContrastEnhancementAlgorithm.ClipToMinimumMaximum, + ) def testUsedAttributes(self): renderer = QgsPointCloudRgbRenderer() - renderer.setBlueAttribute('b') - renderer.setGreenAttribute('g') - renderer.setRedAttribute('r') + renderer.setBlueAttribute("b") + renderer.setGreenAttribute("g") + renderer.setRedAttribute("r") rc = QgsRenderContext() prc = QgsPointCloudRenderContext(rc, QgsVector3D(), QgsVector3D(), 1, 0) - self.assertEqual(renderer.usedAttributes(prc), {'r', 'g', 'b'}) + self.assertEqual(renderer.usedAttributes(prc), {"r", "g", "b"}) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRender(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/rgb/ept.json", "test", "ept" + ) self.assertTrue(layer.isValid()) layer.renderer().setPointSize(2) @@ -192,12 +242,17 @@ def testRender(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('rgb_render', 'rgb_render', mapsettings) + self.render_map_settings_check("rgb_render", "rgb_render", mapsettings) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderCircles(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/rgb/ept.json", "test", "ept" + ) self.assertTrue(layer.isValid()) layer.renderer().setPointSize(3) @@ -212,12 +267,19 @@ def testRenderCircles(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('rgb_circle_render', 'rgb_circle_render', mapsettings) + self.render_map_settings_check( + "rgb_circle_render", "rgb_circle_render", mapsettings + ) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderCrsTransform(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/rgb/ept.json", "test", "ept" + ) self.assertTrue(layer.isValid()) layer.renderer().setPointSize(2) @@ -226,17 +288,26 @@ def testRenderCrsTransform(self): mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) - mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) - mapsettings.setExtent(QgsRectangle(152.977434544, -26.663017454, 152.977424882, -26.663009624)) + mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) + mapsettings.setExtent( + QgsRectangle(152.977434544, -26.663017454, 152.977424882, -26.663009624) + ) mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('rgb_render_crs_transform', 'rgb_render_crs_transform', mapsettings) + self.render_map_settings_check( + "rgb_render_crs_transform", "rgb_render_crs_transform", mapsettings + ) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderWithContrast(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/rgb/ept.json", "test", "ept" + ) self.assertTrue(layer.isValid()) layer.renderer().setPointSize(2) @@ -245,19 +316,25 @@ def testRenderWithContrast(self): redce = QgsContrastEnhancement() redce.setMinimumValue(100) redce.setMaximumValue(120) - redce.setContrastEnhancementAlgorithm(QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum) + redce.setContrastEnhancementAlgorithm( + QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum + ) layer.renderer().setRedContrastEnhancement(redce) greence = QgsContrastEnhancement() greence.setMinimumValue(130) greence.setMaximumValue(150) - greence.setContrastEnhancementAlgorithm(QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum) + greence.setContrastEnhancementAlgorithm( + QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum + ) layer.renderer().setGreenContrastEnhancement(greence) bluece = QgsContrastEnhancement() bluece.setMinimumValue(170) bluece.setMaximumValue(190) - bluece.setContrastEnhancementAlgorithm(QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum) + bluece.setContrastEnhancementAlgorithm( + QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum + ) layer.renderer().setBlueContrastEnhancement(bluece) mapsettings = QgsMapSettings() @@ -268,12 +345,17 @@ def testRenderWithContrast(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('rgb_contrast', 'rgb_contrast', mapsettings) + self.render_map_settings_check("rgb_contrast", "rgb_contrast", mapsettings) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderOpacity(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/rgb/ept.json", "test", "ept" + ) self.assertTrue(layer.isValid()) layer.renderer().setPointSize(2) @@ -289,12 +371,17 @@ def testRenderOpacity(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('opacity', 'opacity', mapsettings) + self.render_map_settings_check("opacity", "opacity", mapsettings) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderBlendMode(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/rgb/ept.json", "test", "ept" + ) self.assertTrue(layer.isValid()) layer.renderer().setPointSize(2) @@ -310,12 +397,17 @@ def testRenderBlendMode(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('blendmode', 'blendmode', mapsettings) + self.render_map_settings_check("blendmode", "blendmode", mapsettings) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderPointSize(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/rgb/ept.json", "test", "ept" + ) self.assertTrue(layer.isValid()) layer.renderer().setPointSize(0.05) @@ -329,12 +421,17 @@ def testRenderPointSize(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('pointsize', 'pointsize', mapsettings) + self.render_map_settings_check("pointsize", "pointsize", mapsettings) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderZRange(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/rgb/ept.json", "test", "ept" + ) self.assertTrue(layer.isValid()) layer.renderer().setPointSize(2) @@ -349,12 +446,17 @@ def testRenderZRange(self): mapsettings.setZRange(QgsDoubleRange(1.1, 1.2)) self.assertTrue( - self.render_map_settings_check('zfilter', 'zfilter', mapsettings) + self.render_map_settings_check("zfilter", "zfilter", mapsettings) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderClipRegion(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/rgb/ept.json", "test", "ept" + ) self.assertTrue(layer.isValid()) layer.renderer().setPointSize(2) @@ -363,26 +465,41 @@ def testRenderClipRegion(self): mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) - mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) - mapsettings.setExtent(QgsRectangle(152.977434544, -26.663017454, 152.977424882, -26.663009624)) + mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) + mapsettings.setExtent( + QgsRectangle(152.977434544, -26.663017454, 152.977424882, -26.663009624) + ) mapsettings.setLayers([layer]) - region = QgsMapClippingRegion(QgsGeometry.fromWkt( - 'Polygon ((152.97742833685992991 -26.66301088198133584, 152.97742694456141521 -26.66301085776744983, 152.97742676295726483 -26.66301358182974468, 152.97742895431403554 -26.66301349708113833, 152.97742833685992991 -26.66301088198133584))')) + region = QgsMapClippingRegion( + QgsGeometry.fromWkt( + "Polygon ((152.97742833685992991 -26.66301088198133584, 152.97742694456141521 -26.66301085776744983, 152.97742676295726483 -26.66301358182974468, 152.97742895431403554 -26.66301349708113833, 152.97742833685992991 -26.66301088198133584))" + ) + ) region.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipPainterOnly) - region2 = QgsMapClippingRegion(QgsGeometry.fromWkt( - 'Polygon ((152.97743215054714483 -26.66301111201326535, 152.97742715037946937 -26.66301116044103736, 152.97742754990858316 -26.66301436878107367, 152.97743264693181686 -26.66301491359353193, 152.97743215054714483 -26.66301111201326535))')) - region2.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipToIntersection) + region2 = QgsMapClippingRegion( + QgsGeometry.fromWkt( + "Polygon ((152.97743215054714483 -26.66301111201326535, 152.97742715037946937 -26.66301116044103736, 152.97742754990858316 -26.66301436878107367, 152.97743264693181686 -26.66301491359353193, 152.97743215054714483 -26.66301111201326535))" + ) + ) + region2.setFeatureClip( + QgsMapClippingRegion.FeatureClippingType.ClipToIntersection + ) mapsettings.addClippingRegion(region) mapsettings.addClippingRegion(region2) self.assertTrue( - self.render_map_settings_check('clip_region', 'clip_region', mapsettings) + self.render_map_settings_check("clip_region", "clip_region", mapsettings) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderOrderedTopToBottom(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/rgb/ept.json", "test", "ept" + ) self.assertTrue(layer.isValid()) layer.renderer().setPointSize(6) @@ -397,12 +514,19 @@ def testRenderOrderedTopToBottom(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('rgb_top_to_bottom', 'rgb_top_to_bottom', mapsettings) + self.render_map_settings_check( + "rgb_top_to_bottom", "rgb_top_to_bottom", mapsettings + ) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderOrderedBottomToTop(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/rgb/ept.json", "test", "ept" + ) self.assertTrue(layer.isValid()) layer.renderer().setPointSize(6) @@ -417,12 +541,19 @@ def testRenderOrderedBottomToTop(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('rgb_bottom_to_top', 'rgb_bottom_to_top', mapsettings) + self.render_map_settings_check( + "rgb_bottom_to_top", "rgb_bottom_to_top", mapsettings + ) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderTriangles(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/rgb/ept.json", "test", "ept" + ) self.assertTrue(layer.isValid()) layer.renderer().setPointSize(6) @@ -437,12 +568,19 @@ def testRenderTriangles(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('rgb_triangles', 'rgb_triangles', mapsettings) + self.render_map_settings_check( + "rgb_triangles", "rgb_triangles", mapsettings + ) ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testRenderTrianglesHorizontalFilter(self): - layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') + layer = QgsPointCloudLayer( + unitTestDataPath() + "/point_clouds/ept/rgb/ept.json", "test", "ept" + ) self.assertTrue(layer.isValid()) layer.renderer().setPointSize(6) @@ -460,9 +598,11 @@ def testRenderTrianglesHorizontalFilter(self): mapsettings.setLayers([layer]) self.assertTrue( - self.render_map_settings_check('rgb_triangles_filter', 'rgb_triangles_filter', mapsettings) + self.render_map_settings_check( + "rgb_triangles_filter", "rgb_triangles_filter", mapsettings + ) ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspointclusterrenderer.py b/tests/src/python/test_qgspointclusterrenderer.py index 728e617e4022..4970e8598d85 100644 --- a/tests/src/python/test_qgspointclusterrenderer.py +++ b/tests/src/python/test_qgspointclusterrenderer.py @@ -18,9 +18,9 @@ """ -__author__ = 'Nyall Dawson' -__date__ = 'September 2016' -__copyright__ = '(C) 2016, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "September 2016" +__copyright__ = "(C) 2016, Nyall Dawson" import os @@ -45,7 +45,7 @@ QgsUnitTypes, QgsVectorLayer, QgsCategorizedSymbolRenderer, - QgsRendererCategory + QgsRendererCategory, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -62,18 +62,24 @@ class TestQgsPointClusterRenderer(QgisTestCase): @classmethod def control_path_prefix(cls): - return 'cluster_renderer' + return "cluster_renderer" def setUp(self): - myShpFile = os.path.join(TEST_DATA_DIR, 'points.shp') - self.layer = QgsVectorLayer(myShpFile, 'Points', 'ogr') + myShpFile = os.path.join(TEST_DATA_DIR, "points.shp") + self.layer = QgsVectorLayer(myShpFile, "Points", "ogr") QgsProject.instance().addMapLayer(self.layer) self.renderer = QgsPointClusterRenderer() - sym1 = QgsMarkerSymbol.createSimple({'color': '#ff00ff', 'size': '3', 'outline_style': 'no'}) + sym1 = QgsMarkerSymbol.createSimple( + {"color": "#ff00ff", "size": "3", "outline_style": "no"} + ) renderer = QgsSingleSymbolRenderer(sym1) self.renderer.setEmbeddedRenderer(renderer) - self.renderer.setClusterSymbol(QgsMarkerSymbol.createSimple({'color': '#ffff00', 'size': '3', 'outline_style': 'no'})) + self.renderer.setClusterSymbol( + QgsMarkerSymbol.createSimple( + {"color": "#ffff00", "size": "3", "outline_style": "no"} + ) + ) self.layer.setRenderer(self.renderer) rendered_layers = [self.layer] @@ -87,40 +93,40 @@ def tearDown(self): QgsProject.instance().removeAllMapLayers() def _setProperties(self, r): - """ set properties for a renderer for testing with _checkProperties""" + """set properties for a renderer for testing with _checkProperties""" r.setTolerance(5) r.setToleranceUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) r.setToleranceMapUnitScale(QgsMapUnitScale(5, 15)) m = QgsMarkerSymbol() m.setColor(QColor(0, 255, 0)) r.setClusterSymbol(m) - sym1 = QgsMarkerSymbol.createSimple({'color': '#fdbf6f'}) + sym1 = QgsMarkerSymbol.createSimple({"color": "#fdbf6f"}) renderer = QgsSingleSymbolRenderer(sym1) r.setEmbeddedRenderer(renderer) def _checkProperties(self, r): - """ test properties of renderer against expected""" + """test properties of renderer against expected""" self.assertEqual(r.tolerance(), 5) self.assertEqual(r.toleranceUnit(), QgsUnitTypes.RenderUnit.RenderMapUnits) self.assertEqual(r.toleranceMapUnitScale(), QgsMapUnitScale(5, 15)) self.assertEqual(r.clusterSymbol().color(), QColor(0, 255, 0)) - self.assertEqual(r.embeddedRenderer().symbol().color().name(), '#fdbf6f') + self.assertEqual(r.embeddedRenderer().symbol().color().name(), "#fdbf6f") def testGettersSetters(self): - """ test getters and setters """ + """test getters and setters""" r = QgsPointClusterRenderer() self._setProperties(r) self._checkProperties(r) def testClone(self): - """ test cloning renderer """ + """test cloning renderer""" r = QgsPointClusterRenderer() self._setProperties(r) c = r.clone() self._checkProperties(c) def testSaveCreate(self): - """ test saving and recreating from XML """ + """test saving and recreating from XML""" r = QgsPointClusterRenderer() self._setProperties(r) doc = QDomDocument("testdoc") @@ -131,17 +137,21 @@ def testSaveCreate(self): def test_legend_keys(self): symbol1 = QgsMarkerSymbol() symbol2 = QgsMarkerSymbol() - sub_renderer = QgsCategorizedSymbolRenderer('cat', [QgsRendererCategory('cat1', symbol1, 'cat1', True, '0'), - QgsRendererCategory('cat2', symbol2, 'cat2', True, '1') - ]) + sub_renderer = QgsCategorizedSymbolRenderer( + "cat", + [ + QgsRendererCategory("cat1", symbol1, "cat1", True, "0"), + QgsRendererCategory("cat2", symbol2, "cat2", True, "1"), + ], + ) renderer = QgsPointClusterRenderer() renderer.setEmbeddedRenderer(sub_renderer) - self.assertEqual(renderer.legendKeys(), {'0', '1'}) + self.assertEqual(renderer.legendKeys(), {"0", "1"}) def testConvert(self): - """ test renderer conversion """ + """test renderer conversion""" # same type, should clone r = QgsPointClusterRenderer() @@ -157,7 +167,7 @@ def testConvert(self): m = QgsMarkerSymbol() m.setColor(QColor(0, 255, 0)) r.setCenterSymbol(m) - sym1 = QgsMarkerSymbol.createSimple({'color': '#fdbf6f'}) + sym1 = QgsMarkerSymbol.createSimple({"color": "#fdbf6f"}) renderer = QgsSingleSymbolRenderer(sym1) r.setEmbeddedRenderer(renderer) @@ -166,40 +176,45 @@ def testConvert(self): self.assertEqual(d.tolerance(), 5) self.assertEqual(d.toleranceUnit(), QgsUnitTypes.RenderUnit.RenderMapUnits) self.assertEqual(d.toleranceMapUnitScale(), QgsMapUnitScale(5, 15)) - self.assertEqual(d.embeddedRenderer().symbol().color().name(), '#fdbf6f') + self.assertEqual(d.embeddedRenderer().symbol().color().name(), "#fdbf6f") def testRenderNoCluster(self): self.layer.renderer().setTolerance(1) self.assertTrue( self.render_map_settings_check( - 'cluster_no_cluster', - 'cluster_no_cluster', - self.mapsettings) + "cluster_no_cluster", "cluster_no_cluster", self.mapsettings + ) ) def testRenderWithin(self): self.layer.renderer().setTolerance(10) self.assertTrue( self.render_map_settings_check( - 'cluster_cluster', - 'cluster_cluster', - self.mapsettings) + "cluster_cluster", "cluster_cluster", self.mapsettings + ) ) def testRenderVariables(self): - """ test rendering with expression variables in marker """ + """test rendering with expression variables in marker""" self.layer.renderer().setTolerance(10) old_marker = self.layer.renderer().clusterSymbol().clone() - new_marker = QgsMarkerSymbol.createSimple({'color': '#ffff00', 'size': '3', 'outline_style': 'no'}) - new_marker.symbolLayer(0).setDataDefinedProperty(QgsSymbolLayer.Property.PropertyFillColor, QgsProperty.fromExpression('@cluster_color')) - new_marker.symbolLayer(0).setDataDefinedProperty(QgsSymbolLayer.Property.PropertySize, QgsProperty.fromExpression('@cluster_size*2')) + new_marker = QgsMarkerSymbol.createSimple( + {"color": "#ffff00", "size": "3", "outline_style": "no"} + ) + new_marker.symbolLayer(0).setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyFillColor, + QgsProperty.fromExpression("@cluster_color"), + ) + new_marker.symbolLayer(0).setDataDefinedProperty( + QgsSymbolLayer.Property.PropertySize, + QgsProperty.fromExpression("@cluster_size*2"), + ) self.layer.renderer().setClusterSymbol(new_marker) result = self.render_map_settings_check( - 'cluster_variables', - 'cluster_variables', - self.mapsettings) + "cluster_variables", "cluster_variables", self.mapsettings + ) self.layer.renderer().setClusterSymbol(old_marker) self.assertTrue(result) @@ -207,25 +222,31 @@ def testMultiPoint(self): """ Test multipoint handling """ - layer = QgsVectorLayer('Multipoint?field=cat:string', '', 'memory') + layer = QgsVectorLayer("Multipoint?field=cat:string", "", "memory") self.assertTrue(layer.isValid()) f = QgsFeature(layer.fields()) - f.setAttributes(['a']) - f.setGeometry(QgsGeometry.fromWkt('MultiPoint(5 5, 5 6, 9 9)')) + f.setAttributes(["a"]) + f.setGeometry(QgsGeometry.fromWkt("MultiPoint(5 5, 5 6, 9 9)")) layer.dataProvider().addFeature(f) - f.setAttributes(['b']) - f.setGeometry(QgsGeometry.fromWkt('MultiPoint(2 1, 2 2, 5 5)')) + f.setAttributes(["b"]) + f.setGeometry(QgsGeometry.fromWkt("MultiPoint(2 1, 2 2, 5 5)")) layer.dataProvider().addFeature(f) - f.setAttributes(['c']) - f.setGeometry(QgsGeometry.fromWkt('MultiPoint(9 1)')) + f.setAttributes(["c"]) + f.setGeometry(QgsGeometry.fromWkt("MultiPoint(9 1)")) layer.dataProvider().addFeature(f) renderer = QgsPointClusterRenderer() - sym1 = QgsMarkerSymbol.createSimple({'color': '#ff00ff', 'size': '3', 'outline_style': 'no'}) + sym1 = QgsMarkerSymbol.createSimple( + {"color": "#ff00ff", "size": "3", "outline_style": "no"} + ) sub_renderer = QgsSingleSymbolRenderer(sym1) renderer.setEmbeddedRenderer(sub_renderer) - renderer.setClusterSymbol(QgsMarkerSymbol.createSimple({'color': '#ffff00', 'size': '3', 'outline_style': 'no'})) + renderer.setClusterSymbol( + QgsMarkerSymbol.createSimple( + {"color": "#ffff00", "size": "3", "outline_style": "no"} + ) + ) renderer.setToleranceUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) renderer.setTolerance(2) layer.setRenderer(renderer) @@ -239,9 +260,8 @@ def testMultiPoint(self): self.assertTrue( self.render_map_settings_check( - 'cluster_multipoint', - 'cluster_multipoint', - mapsettings) + "cluster_multipoint", "cluster_multipoint", mapsettings + ) ) def testUsedAttributes(self): @@ -250,5 +270,5 @@ def testUsedAttributes(self): self.assertCountEqual(self.renderer.usedAttributes(ctx), {}) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspointdisplacementrenderer.py b/tests/src/python/test_qgspointdisplacementrenderer.py index eef18c120356..57a168aa5f82 100644 --- a/tests/src/python/test_qgspointdisplacementrenderer.py +++ b/tests/src/python/test_qgspointdisplacementrenderer.py @@ -18,9 +18,9 @@ """ -__author__ = 'Nyall Dawson' -__date__ = 'September 2016' -__copyright__ = '(C) 2016, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "September 2016" +__copyright__ = "(C) 2016, Nyall Dawson" import os @@ -49,7 +49,7 @@ QgsSymbol, QgsSymbolLayer, QgsUnitTypes, - QgsVectorLayer + QgsVectorLayer, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -66,21 +66,27 @@ class TestQgsPointDisplacementRenderer(QgisTestCase): @classmethod def control_path_prefix(cls): - return 'displacement_renderer' + return "displacement_renderer" def _setUp(self): - myShpFile = os.path.join(TEST_DATA_DIR, 'points.shp') - layer = QgsVectorLayer(myShpFile, 'Points', 'ogr') + myShpFile = os.path.join(TEST_DATA_DIR, "points.shp") + layer = QgsVectorLayer(myShpFile, "Points", "ogr") QgsProject.instance().addMapLayer(layer) renderer = QgsPointDisplacementRenderer() - sym1 = QgsMarkerSymbol.createSimple({'color': '#ff00ff', 'size': '3', 'outline_style': 'no'}) + sym1 = QgsMarkerSymbol.createSimple( + {"color": "#ff00ff", "size": "3", "outline_style": "no"} + ) sym_renderer = QgsSingleSymbolRenderer(sym1) renderer.setEmbeddedRenderer(sym_renderer) renderer.setCircleRadiusAddition(2) renderer.setCircleWidth(1) renderer.setCircleColor(QColor(0, 0, 0)) - renderer.setCenterSymbol(QgsMarkerSymbol.createSimple({'color': '#ffff00', 'size': '3', 'outline_style': 'no'})) + renderer.setCenterSymbol( + QgsMarkerSymbol.createSimple( + {"color": "#ffff00", "size": "3", "outline_style": "no"} + ) + ) layer.setRenderer(renderer) rendered_layers = [layer] @@ -96,9 +102,9 @@ def _tearDown(self, layer): QgsProject.instance().removeMapLayer(layer) def _setProperties(self, r): - """ set properties for a renderer for testing with _checkProperties""" - r.setLabelAttributeName('name') - f = QgsFontUtils.getStandardTestFont('Bold Oblique', 14) + """set properties for a renderer for testing with _checkProperties""" + r.setLabelAttributeName("name") + f = QgsFontUtils.getStandardTestFont("Bold Oblique", 14) r.setLabelFont(f) r.setMinimumLabelScale(50000) r.setLabelColor(QColor(255, 0, 0)) @@ -113,14 +119,14 @@ def _setProperties(self, r): m = QgsMarkerSymbol() m.setColor(QColor(0, 255, 0)) r.setCenterSymbol(m) - sym1 = QgsMarkerSymbol.createSimple({'color': '#fdbf6f'}) + sym1 = QgsMarkerSymbol.createSimple({"color": "#fdbf6f"}) renderer = QgsSingleSymbolRenderer(sym1) r.setEmbeddedRenderer(renderer) def _checkProperties(self, r): - """ test properties of renderer against expected""" - self.assertEqual(r.labelAttributeName(), 'name') - f = QgsFontUtils.getStandardTestFont('Bold Oblique', 14) + """test properties of renderer against expected""" + self.assertEqual(r.labelAttributeName(), "name") + f = QgsFontUtils.getStandardTestFont("Bold Oblique", 14) self.assertEqual(r.labelFont().styleName(), f.styleName()) self.assertEqual(r.minimumLabelScale(), 50000) self.assertEqual(r.labelColor(), QColor(255, 0, 0)) @@ -130,36 +136,42 @@ def _checkProperties(self, r): self.assertEqual(r.circleWidth(), 15) self.assertEqual(r.circleColor(), QColor(0, 255, 0)) self.assertEqual(r.circleRadiusAddition(), 2.5) - self.assertEqual(r.placement(), QgsPointDisplacementRenderer.Placement.ConcentricRings) + self.assertEqual( + r.placement(), QgsPointDisplacementRenderer.Placement.ConcentricRings + ) self.assertEqual(r.centerSymbol().color(), QColor(0, 255, 0)) - self.assertEqual(r.embeddedRenderer().symbol().color().name(), '#fdbf6f') + self.assertEqual(r.embeddedRenderer().symbol().color().name(), "#fdbf6f") self.assertEqual(r.labelDistanceFactor(), 0.25) def _create_categorized_renderer(self): - cat_renderer = QgsCategorizedSymbolRenderer(attrName='Class') - sym1 = QgsMarkerSymbol.createSimple({'color': '#ff00ff', 'size': '6', 'outline_style': 'no'}) - cat1 = QgsRendererCategory('Biplane', sym1, 'Big') + cat_renderer = QgsCategorizedSymbolRenderer(attrName="Class") + sym1 = QgsMarkerSymbol.createSimple( + {"color": "#ff00ff", "size": "6", "outline_style": "no"} + ) + cat1 = QgsRendererCategory("Biplane", sym1, "Big") cat_renderer.addCategory(cat1) - sym2 = QgsMarkerSymbol.createSimple({'color': '#ff00ff', 'size': '3', 'outline_style': 'no'}) - cat2 = QgsRendererCategory(['B52', 'Jet'], sym2, 'Smaller') + sym2 = QgsMarkerSymbol.createSimple( + {"color": "#ff00ff", "size": "3", "outline_style": "no"} + ) + cat2 = QgsRendererCategory(["B52", "Jet"], sym2, "Smaller") cat_renderer.addCategory(cat2) return cat_renderer def testGettersSetters(self): - """ test getters and setters """ + """test getters and setters""" r = QgsPointDisplacementRenderer() self._setProperties(r) self._checkProperties(r) def testClone(self): - """ test cloning renderer """ + """test cloning renderer""" r = QgsPointDisplacementRenderer() self._setProperties(r) c = r.clone() self._checkProperties(c) def testSaveCreate(self): - """ test saving and recreating from XML """ + """test saving and recreating from XML""" r = QgsPointDisplacementRenderer() self._setProperties(r) doc = QDomDocument("testdoc") @@ -168,7 +180,7 @@ def testSaveCreate(self): self._checkProperties(c) def testConvert(self): - """ test renderer conversion """ + """test renderer conversion""" # same type, should clone r = QgsPointDisplacementRenderer() @@ -184,7 +196,7 @@ def testConvert(self): m = QgsMarkerSymbol() m.setColor(QColor(0, 255, 0)) r.setClusterSymbol(m) - sym1 = QgsMarkerSymbol.createSimple({'color': '#fdbf6f'}) + sym1 = QgsMarkerSymbol.createSimple({"color": "#fdbf6f"}) renderer = QgsSingleSymbolRenderer(sym1) r.setEmbeddedRenderer(renderer) @@ -193,15 +205,14 @@ def testConvert(self): self.assertEqual(d.tolerance(), 5) self.assertEqual(d.toleranceUnit(), QgsUnitTypes.RenderUnit.RenderMapUnits) self.assertEqual(d.toleranceMapUnitScale(), QgsMapUnitScale(5, 15)) - self.assertEqual(d.embeddedRenderer().symbol().color().name(), '#fdbf6f') + self.assertEqual(d.embeddedRenderer().symbol().color().name(), "#fdbf6f") def testRenderNoCluster(self): layer, renderer, mapsettings = self._setUp() layer.renderer().setTolerance(1) res = self.render_map_settings_check( - 'displacement_no_cluster', - 'displacement_no_cluster', - mapsettings) + "displacement_no_cluster", "displacement_no_cluster", mapsettings + ) self.assertTrue(res) self._tearDown(layer) @@ -210,9 +221,8 @@ def testRenderWithin(self): layer, renderer, mapsettings = self._setUp() layer.renderer().setTolerance(10) res = self.render_map_settings_check( - 'displacement_cluster', - 'displacement_cluster', - mapsettings) + "displacement_cluster", "displacement_cluster", mapsettings + ) self.assertTrue(res) self._tearDown(layer) @@ -220,36 +230,42 @@ def testMultiPoint(self): """ Test multipoint handling """ - layer = QgsVectorLayer('Multipoint?field=cat:string', '', 'memory') + layer = QgsVectorLayer("Multipoint?field=cat:string", "", "memory") self.assertTrue(layer.isValid()) f = QgsFeature(layer.fields()) - f.setAttributes(['a']) - f.setGeometry(QgsGeometry.fromWkt('MultiPoint(5 5, 5 6, 9 9)')) + f.setAttributes(["a"]) + f.setGeometry(QgsGeometry.fromWkt("MultiPoint(5 5, 5 6, 9 9)")) layer.dataProvider().addFeature(f) - f.setAttributes(['b']) - f.setGeometry(QgsGeometry.fromWkt('MultiPoint(2 1, 2 2, 5 5)')) + f.setAttributes(["b"]) + f.setGeometry(QgsGeometry.fromWkt("MultiPoint(2 1, 2 2, 5 5)")) layer.dataProvider().addFeature(f) - f.setAttributes(['c']) - f.setGeometry(QgsGeometry.fromWkt('MultiPoint(9 1)')) + f.setAttributes(["c"]) + f.setGeometry(QgsGeometry.fromWkt("MultiPoint(9 1)")) layer.dataProvider().addFeature(f) renderer = QgsPointDisplacementRenderer() - sym1 = QgsMarkerSymbol.createSimple({'color': '#ff00ff', 'size': '3', 'outline_style': 'no'}) + sym1 = QgsMarkerSymbol.createSimple( + {"color": "#ff00ff", "size": "3", "outline_style": "no"} + ) sym_renderer = QgsCategorizedSymbolRenderer() - sym_renderer.setClassAttribute('cat') + sym_renderer.setClassAttribute("cat") sym1.setColor(QColor(255, 0, 0)) - sym_renderer.addCategory(QgsRendererCategory('a', sym1.clone(), 'a')) + sym_renderer.addCategory(QgsRendererCategory("a", sym1.clone(), "a")) sym1.setColor(QColor(0, 255, 0)) - sym_renderer.addCategory(QgsRendererCategory('b', sym1.clone(), 'b')) + sym_renderer.addCategory(QgsRendererCategory("b", sym1.clone(), "b")) sym1.setColor(QColor(0, 0, 255)) - sym_renderer.addCategory(QgsRendererCategory('c', sym1.clone(), 'c')) + sym_renderer.addCategory(QgsRendererCategory("c", sym1.clone(), "c")) renderer.setEmbeddedRenderer(sym_renderer) renderer.setCircleRadiusAddition(2) renderer.setCircleWidth(1) renderer.setCircleColor(QColor(0, 0, 0)) - renderer.setCenterSymbol(QgsMarkerSymbol.createSimple({'color': '#ffff00', 'size': '3', 'outline_style': 'no'})) + renderer.setCenterSymbol( + QgsMarkerSymbol.createSimple( + {"color": "#ffff00", "size": "3", "outline_style": "no"} + ) + ) renderer.setToleranceUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) renderer.setTolerance(2) layer.setRenderer(renderer) @@ -262,28 +278,32 @@ def testMultiPoint(self): mapsettings.setLayers(rendered_layers) result = self.render_map_settings_check( - 'displacement_multipoint', - 'displacement_multipoint', - mapsettings) + "displacement_multipoint", "displacement_multipoint", mapsettings + ) self.assertTrue(result) def testRenderVariables(self): - """ test rendering with expression variables in marker """ + """test rendering with expression variables in marker""" layer, renderer, mapsettings = self._setUp() layer.renderer().setTolerance(10) old_marker = layer.renderer().centerSymbol().clone() - new_marker = QgsMarkerSymbol.createSimple({'color': '#ffff00', 'size': '3', 'outline_style': 'no'}) - new_marker.symbolLayer(0).setDataDefinedProperty(QgsSymbolLayer.Property.PropertyFillColor, - QgsProperty.fromExpression('@cluster_color')) - new_marker.symbolLayer(0).setDataDefinedProperty(QgsSymbolLayer.Property.PropertySize, - QgsProperty.fromExpression('@cluster_size*2')) + new_marker = QgsMarkerSymbol.createSimple( + {"color": "#ffff00", "size": "3", "outline_style": "no"} + ) + new_marker.symbolLayer(0).setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyFillColor, + QgsProperty.fromExpression("@cluster_color"), + ) + new_marker.symbolLayer(0).setDataDefinedProperty( + QgsSymbolLayer.Property.PropertySize, + QgsProperty.fromExpression("@cluster_size*2"), + ) layer.renderer().setCenterSymbol(new_marker) result = self.render_map_settings_check( - 'displacement_variables', - 'displacement_variables', - mapsettings) + "displacement_variables", "displacement_variables", mapsettings + ) layer.renderer().setCenterSymbol(old_marker) self.assertTrue(result) self._tearDown(layer) @@ -293,9 +313,8 @@ def testRenderGrid(self): layer.renderer().setTolerance(10) layer.renderer().setPlacement(QgsPointDisplacementRenderer.Placement.Grid) res = self.render_map_settings_check( - 'displacement_grid', - 'displacement_grid', - mapsettings) + "displacement_grid", "displacement_grid", mapsettings + ) self.assertTrue(res) self._tearDown(layer) @@ -306,53 +325,57 @@ def testRenderGridAdjust(self): layer.renderer().setPlacement(QgsPointDisplacementRenderer.Placement.Grid) layer.renderer().setCircleColor(QColor()) res = self.render_map_settings_check( - 'displacement_adjust_grid', - 'displacement_adjust_grid', - mapsettings) + "displacement_adjust_grid", "displacement_adjust_grid", mapsettings + ) self.assertTrue(res) self._tearDown(layer) def testClusterRingLabels(self): layer, renderer, mapsettings = self._setUp() layer.renderer().setTolerance(10) - layer.renderer().setLabelAttributeName('Class') + layer.renderer().setLabelAttributeName("Class") layer.renderer().setLabelDistanceFactor(0.35) - f = QgsFontUtils.getStandardTestFont('Bold', 14) + f = QgsFontUtils.getStandardTestFont("Bold", 14) layer.renderer().setLabelFont(f) res = self.render_map_settings_check( - 'displacement_cluster_ring_labels', - 'displacement_cluster_ring_labels', - mapsettings) + "displacement_cluster_ring_labels", + "displacement_cluster_ring_labels", + mapsettings, + ) self.assertTrue(res) self._tearDown(layer) def testClusterGridLabels(self): layer, renderer, mapsettings = self._setUp() layer.renderer().setTolerance(10) - layer.renderer().setLabelAttributeName('Class') + layer.renderer().setLabelAttributeName("Class") layer.renderer().setLabelDistanceFactor(0.35) - f = QgsFontUtils.getStandardTestFont('Bold', 14) + f = QgsFontUtils.getStandardTestFont("Bold", 14) layer.renderer().setLabelFont(f) layer.renderer().setPlacement(QgsPointDisplacementRenderer.Placement.Grid) res = self.render_map_settings_check( - 'displacement_cluster_grid_labels', - 'displacement_cluster_grid_labels', - mapsettings) + "displacement_cluster_grid_labels", + "displacement_cluster_grid_labels", + mapsettings, + ) self.assertTrue(res) self._tearDown(layer) def testClusterConcentricLabels(self): layer, renderer, mapsettings = self._setUp() layer.renderer().setTolerance(10) - layer.renderer().setLabelAttributeName('Class') + layer.renderer().setLabelAttributeName("Class") layer.renderer().setLabelDistanceFactor(0.35) - f = QgsFontUtils.getStandardTestFont('Bold', 14) + f = QgsFontUtils.getStandardTestFont("Bold", 14) layer.renderer().setLabelFont(f) - layer.renderer().setPlacement(QgsPointDisplacementRenderer.Placement.ConcentricRings) + layer.renderer().setPlacement( + QgsPointDisplacementRenderer.Placement.ConcentricRings + ) res = self.render_map_settings_check( - 'displacement_cluster_concentric_labels', - 'displacement_cluster_concentric_labels', - mapsettings) + "displacement_cluster_concentric_labels", + "displacement_cluster_concentric_labels", + mapsettings, + ) self.assertTrue(res) self._tearDown(layer) @@ -360,14 +383,15 @@ def testClusterRingLabelsDifferentSizes(self): layer, renderer, mapsettings = self._setUp() renderer.setEmbeddedRenderer(self._create_categorized_renderer()) layer.renderer().setTolerance(10) - layer.renderer().setLabelAttributeName('Class') + layer.renderer().setLabelAttributeName("Class") layer.renderer().setLabelDistanceFactor(0.35) - f = QgsFontUtils.getStandardTestFont('Bold', 14) + f = QgsFontUtils.getStandardTestFont("Bold", 14) layer.renderer().setLabelFont(f) res = self.render_map_settings_check( - 'displacement_cluster_ring_labels_diff_size', - 'displacement_cluster_ring_labels_diff_size', - mapsettings) + "displacement_cluster_ring_labels_diff_size", + "displacement_cluster_ring_labels_diff_size", + mapsettings, + ) self.assertTrue(res) self._tearDown(layer) @@ -375,15 +399,16 @@ def testClusterGridLabelsDifferentSizes(self): layer, renderer, mapsettings = self._setUp() renderer.setEmbeddedRenderer(self._create_categorized_renderer()) layer.renderer().setTolerance(10) - layer.renderer().setLabelAttributeName('Class') + layer.renderer().setLabelAttributeName("Class") layer.renderer().setLabelDistanceFactor(0.35) - f = QgsFontUtils.getStandardTestFont('Bold', 14) + f = QgsFontUtils.getStandardTestFont("Bold", 14) layer.renderer().setLabelFont(f) layer.renderer().setPlacement(QgsPointDisplacementRenderer.Placement.Grid) res = self.render_map_settings_check( - 'displacement_cluster_grid_labels_diff_size', - 'displacement_cluster_grid_labels_diff_size', - mapsettings) + "displacement_cluster_grid_labels_diff_size", + "displacement_cluster_grid_labels_diff_size", + mapsettings, + ) self.assertTrue(res) self._tearDown(layer) @@ -391,15 +416,18 @@ def testClusterConcentricLabelsDifferentSizes(self): layer, renderer, mapsettings = self._setUp() renderer.setEmbeddedRenderer(self._create_categorized_renderer()) layer.renderer().setTolerance(10) - layer.renderer().setLabelAttributeName('Class') + layer.renderer().setLabelAttributeName("Class") layer.renderer().setLabelDistanceFactor(0.35) - f = QgsFontUtils.getStandardTestFont('Bold', 14) + f = QgsFontUtils.getStandardTestFont("Bold", 14) layer.renderer().setLabelFont(f) - layer.renderer().setPlacement(QgsPointDisplacementRenderer.Placement.ConcentricRings) + layer.renderer().setPlacement( + QgsPointDisplacementRenderer.Placement.ConcentricRings + ) res = self.render_map_settings_check( - 'displacement_cluster_concentric_labels_diff_size', - 'displacement_cluster_concentric_labels_diff_size', - mapsettings) + "displacement_cluster_concentric_labels_diff_size", + "displacement_cluster_concentric_labels_diff_size", + mapsettings, + ) self.assertTrue(res) self._tearDown(layer) @@ -407,14 +435,15 @@ def testClusterRingLabelsDifferentSizesFarther(self): layer, renderer, mapsettings = self._setUp() renderer.setEmbeddedRenderer(self._create_categorized_renderer()) layer.renderer().setTolerance(10) - layer.renderer().setLabelAttributeName('Class') + layer.renderer().setLabelAttributeName("Class") layer.renderer().setLabelDistanceFactor(1) - f = QgsFontUtils.getStandardTestFont('Bold', 14) + f = QgsFontUtils.getStandardTestFont("Bold", 14) layer.renderer().setLabelFont(f) res = self.render_map_settings_check( - 'displacement_cluster_ring_labels_diff_size_farther', - 'displacement_cluster_ring_labels_diff_size_farther', - mapsettings) + "displacement_cluster_ring_labels_diff_size_farther", + "displacement_cluster_ring_labels_diff_size_farther", + mapsettings, + ) self.assertTrue(res) self._tearDown(layer) @@ -422,15 +451,16 @@ def testClusterGridLabelsDifferentSizesFarther(self): layer, renderer, mapsettings = self._setUp() renderer.setEmbeddedRenderer(self._create_categorized_renderer()) layer.renderer().setTolerance(10) - layer.renderer().setLabelAttributeName('Class') + layer.renderer().setLabelAttributeName("Class") layer.renderer().setLabelDistanceFactor(1) layer.renderer().setPlacement(QgsPointDisplacementRenderer.Placement.Grid) - f = QgsFontUtils.getStandardTestFont('Bold', 14) + f = QgsFontUtils.getStandardTestFont("Bold", 14) layer.renderer().setLabelFont(f) res = self.render_map_settings_check( - 'displacement_cluster_grid_labels_diff_size_farther', - 'displacement_cluster_grid_labels_diff_size_farther', - mapsettings) + "displacement_cluster_grid_labels_diff_size_farther", + "displacement_cluster_grid_labels_diff_size_farther", + mapsettings, + ) self.assertTrue(res) self._tearDown(layer) @@ -438,42 +468,51 @@ def testClusterConcentricLabelsDifferentSizesFarther(self): layer, renderer, mapsettings = self._setUp() renderer.setEmbeddedRenderer(self._create_categorized_renderer()) layer.renderer().setTolerance(10) - layer.renderer().setLabelAttributeName('Class') + layer.renderer().setLabelAttributeName("Class") layer.renderer().setLabelDistanceFactor(1) - f = QgsFontUtils.getStandardTestFont('Bold', 14) + f = QgsFontUtils.getStandardTestFont("Bold", 14) layer.renderer().setLabelFont(f) - layer.renderer().setPlacement(QgsPointDisplacementRenderer.Placement.ConcentricRings) + layer.renderer().setPlacement( + QgsPointDisplacementRenderer.Placement.ConcentricRings + ) res = self.render_map_settings_check( - 'displacement_cluster_concentric_labels_diff_size_farther', - 'displacement_cluster_concentric_labels_diff_size_farther', - mapsettings) + "displacement_cluster_concentric_labels_diff_size_farther", + "displacement_cluster_concentric_labels_diff_size_farther", + mapsettings, + ) self.assertTrue(res) self._tearDown(layer) def test_legend_keys(self): symbol1 = QgsMarkerSymbol() symbol2 = QgsMarkerSymbol() - sub_renderer = QgsCategorizedSymbolRenderer('cat', [QgsRendererCategory('cat1', symbol1, 'cat1', True, '0'), - QgsRendererCategory('cat2', symbol2, 'cat2', True, '1') - ]) + sub_renderer = QgsCategorizedSymbolRenderer( + "cat", + [ + QgsRendererCategory("cat1", symbol1, "cat1", True, "0"), + QgsRendererCategory("cat2", symbol2, "cat2", True, "1"), + ], + ) renderer = QgsPointDisplacementRenderer() renderer.setEmbeddedRenderer(sub_renderer) - self.assertEqual(renderer.legendKeys(), {'0', '1'}) + self.assertEqual(renderer.legendKeys(), {"0", "1"}) def test_legend_key_to_expression(self): - sym1 = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'outline_color': 'black'}) + sym1 = QgsMarkerSymbol.createSimple( + {"color": "#fdbf6f", "outline_color": "black"} + ) sub_renderer = QgsSingleSymbolRenderer(sym1) renderer = QgsPointDisplacementRenderer() renderer.setEmbeddedRenderer(sub_renderer) - exp, ok = renderer.legendKeyToExpression('0', None) + exp, ok = renderer.legendKeyToExpression("0", None) self.assertTrue(ok) - self.assertEqual(exp, 'TRUE') + self.assertEqual(exp, "TRUE") - exp, ok = renderer.legendKeyToExpression('xxxx', None) + exp, ok = renderer.legendKeyToExpression("xxxx", None) self.assertFalse(ok) def testUsedAttributes(self): @@ -493,7 +532,9 @@ def testGeometryGenerator(self): layer.renderer().setPlacement(QgsPointDisplacementRenderer.Placement.Ring) layer.renderer().setCircleRadiusAddition(0) - geomGeneratorSymbolLayer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': '$geometry'}) + geomGeneratorSymbolLayer = QgsGeometryGeneratorSymbolLayer.create( + {"geometryModifier": "$geometry"} + ) geomGeneratorSymbolLayer.setSymbolType(QgsSymbol.SymbolType.Marker) geomGeneratorSymbolLayer.subSymbol().setSize(2.5) @@ -509,5 +550,5 @@ def testGeometryGenerator(self): job.waitForFinished() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspolygon.py b/tests/src/python/test_qgspolygon.py index da755918178a..9302704b7816 100644 --- a/tests/src/python/test_qgspolygon.py +++ b/tests/src/python/test_qgspolygon.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Loïc Bartoletti' -__date__ = '19/12/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "Loïc Bartoletti" +__date__ = "19/12/2023" +__copyright__ = "Copyright 2023, The QGIS Project" import qgis # NOQA @@ -26,9 +27,27 @@ def testFuzzyComparisons(self): ###### epsilon = 0.001 geom1 = QgsPolygon() - geom1.setExteriorRing(QgsLineString([QgsPoint(0.0, 0.0), QgsPoint(0.001, 0.001), QgsPoint(0.003, 0.003), QgsPoint(0.0, 0.0)])) + geom1.setExteriorRing( + QgsLineString( + [ + QgsPoint(0.0, 0.0), + QgsPoint(0.001, 0.001), + QgsPoint(0.003, 0.003), + QgsPoint(0.0, 0.0), + ] + ) + ) geom2 = QgsPolygon() - geom2.setExteriorRing(QgsLineString([QgsPoint(0.0, 0.0), QgsPoint(0.002, 0.002), QgsPoint(0.003, 0.003), QgsPoint(0.0, 0.0)])) + geom2.setExteriorRing( + QgsLineString( + [ + QgsPoint(0.0, 0.0), + QgsPoint(0.002, 0.002), + QgsPoint(0.003, 0.003), + QgsPoint(0.0, 0.0), + ] + ) + ) self.assertNotEqual(geom1, geom2) # epsilon = 1e-8 here @@ -45,9 +64,27 @@ def testFuzzyComparisons(self): ####### epsilon = 0.001 geom1 = QgsPolygon() - geom1.setExteriorRing(QgsLineString([QgsPoint(0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001), QgsPoint(0.003, 0.003, 0.003), QgsPoint(0.0, 0.0, 0.0)])) + geom1.setExteriorRing( + QgsLineString( + [ + QgsPoint(0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.001), + QgsPoint(0.003, 0.003, 0.003), + QgsPoint(0.0, 0.0, 0.0), + ] + ) + ) geom2 = QgsPolygon() - geom2.setExteriorRing(QgsLineString([QgsPoint(0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.002), QgsPoint(0.003, 0.003, 0.003), QgsPoint(0.0, 0.0, 0.0)])) + geom2.setExteriorRing( + QgsLineString( + [ + QgsPoint(0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.002), + QgsPoint(0.003, 0.003, 0.003), + QgsPoint(0.0, 0.0, 0.0), + ] + ) + ) self.assertNotEqual(geom1, geom2) # epsilon = 1e-8 here @@ -64,9 +101,27 @@ def testFuzzyComparisons(self): ####### epsilon = 0.001 geom1 = QgsPolygon() - geom1.setExteriorRing(QgsLineString([QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.001), QgsPoint(0.003, 0.003, m=0.003), QgsPoint(0.0, 0.0, m=0.0)])) + geom1.setExteriorRing( + QgsLineString( + [ + QgsPoint(0.0, 0.0, m=0.0), + QgsPoint(0.001, 0.001, m=0.001), + QgsPoint(0.003, 0.003, m=0.003), + QgsPoint(0.0, 0.0, m=0.0), + ] + ) + ) geom2 = QgsPolygon() - geom2.setExteriorRing(QgsLineString([QgsPoint(0.0, 0.0, m=0.0), QgsPoint(0.001, 0.001, m=0.002), QgsPoint(0.003, 0.003, m=0.003), QgsPoint(0.0, 0.0, m=0.0)])) + geom2.setExteriorRing( + QgsLineString( + [ + QgsPoint(0.0, 0.0, m=0.0), + QgsPoint(0.001, 0.001, m=0.002), + QgsPoint(0.003, 0.003, m=0.003), + QgsPoint(0.0, 0.0, m=0.0), + ] + ) + ) self.assertNotEqual(geom1, geom2) # epsilon = 1e-8 here @@ -83,9 +138,27 @@ def testFuzzyComparisons(self): ###### epsilon = 0.001 geom1 = QgsPolygon() - geom1.setExteriorRing(QgsLineString([QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.001, 0.001), QgsPoint(0.003, 0.003, 0.003, 0.003), QgsPoint(0.0, 0.0, 0.0, 0.0)])) + geom1.setExteriorRing( + QgsLineString( + [ + QgsPoint(0.0, 0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.001, 0.001), + QgsPoint(0.003, 0.003, 0.003, 0.003), + QgsPoint(0.0, 0.0, 0.0, 0.0), + ] + ) + ) geom2 = QgsPolygon() - geom2.setExteriorRing(QgsLineString([QgsPoint(0.0, 0.0, 0.0, 0.0), QgsPoint(0.001, 0.001, 0.002, 0.002), QgsPoint(0.003, 0.003, 0.003, 0.003), QgsPoint(0.0, 0.0, 0.0, 0.0)])) + geom2.setExteriorRing( + QgsLineString( + [ + QgsPoint(0.0, 0.0, 0.0, 0.0), + QgsPoint(0.001, 0.001, 0.002, 0.002), + QgsPoint(0.003, 0.003, 0.003, 0.003), + QgsPoint(0.0, 0.0, 0.0, 0.0), + ] + ) + ) self.assertNotEqual(geom1, geom2) # epsilon = 1e-8 here @@ -102,22 +175,50 @@ def test_simplify_by_distance(self): test simplifyByDistance """ p = QgsPolygon() - p.fromWkt('Polygon ((4.33843532846714908 1.48149845255473167, 4.47478429197079919 8.6398190364963412, 5.8382739270072932 16.47988443795619418, 10.61048764963503288 22.88828572262772809, 17.63245927007298519 27.72867392700729283, 27.04053775182481445 30.11478078832115912, 34.81242867153284237 28.34224426277371478, 42.51614510948904524 23.97907743065692188, 44.83407748905109713 17.84337407299268818, 44.15233267153284658 9.52608729927005982, 42.44797062773722018 1.75419637956203189, 37.26671001459853727 -4.65420490510949492, 29.5629935766423344 -6.63126487591242153, 18.51872753284671091 -7.31300969343067209, 7.1335890802919657 -5.13142627737227031, 5.15652910948904619 -1.9272256350365069, 4.33843532846714908 1.48149845255473167),(20.31173353218648003 19.78274965689762155, 17.28447821560356346 9.99697084282726678, 21.22695025580456729 4.57607178755088739, 26.01423773319150001 3.23844734533983569, 28.33748018545281155 3.87205892322928236, 32.20955093922164991 5.6320910840332985, 34.60319467791511983 8.37774125488756738, 35.23680625580456649 12.24981200865641284, 34.6735959643472782 15.84027761669661771, 32.13914965278949154 19.43074322473681548, 26.92945445680959438 22.03559082272676761, 22.98698241660859054 21.04997281267651488, 20.31173353218648003 19.78274965689762155))') - self.assertEqual(p.simplifyByDistance(1).asWkt(3), 'Polygon ((4.338 1.481, 5.838 16.48, 10.61 22.888, 17.632 27.729, 27.041 30.115, 34.812 28.342, 42.516 23.979, 44.834 17.843, 44.152 9.526, 42.448 1.754, 37.267 -4.654, 18.519 -7.313, 7.134 -5.131, 4.338 1.481),(20.312 19.783, 17.284 9.997, 21.227 4.576, 26.014 3.238, 32.21 5.632, 34.603 8.378, 35.237 12.25, 32.139 19.431, 26.929 22.036, 20.312 19.783))') - self.assertEqual(p.simplifyByDistance(2).asWkt(3), 'Polygon ((4.338 1.481, 5.838 16.48, 17.632 27.729, 27.041 30.115, 42.516 23.979, 44.152 9.526, 37.267 -4.654, 18.519 -7.313, 7.134 -5.131, 4.338 1.481),(20.312 19.783, 17.284 9.997, 21.227 4.576, 32.21 5.632, 35.237 12.25, 32.139 19.431, 26.929 22.036, 20.312 19.783))') + p.fromWkt( + "Polygon ((4.33843532846714908 1.48149845255473167, 4.47478429197079919 8.6398190364963412, 5.8382739270072932 16.47988443795619418, 10.61048764963503288 22.88828572262772809, 17.63245927007298519 27.72867392700729283, 27.04053775182481445 30.11478078832115912, 34.81242867153284237 28.34224426277371478, 42.51614510948904524 23.97907743065692188, 44.83407748905109713 17.84337407299268818, 44.15233267153284658 9.52608729927005982, 42.44797062773722018 1.75419637956203189, 37.26671001459853727 -4.65420490510949492, 29.5629935766423344 -6.63126487591242153, 18.51872753284671091 -7.31300969343067209, 7.1335890802919657 -5.13142627737227031, 5.15652910948904619 -1.9272256350365069, 4.33843532846714908 1.48149845255473167),(20.31173353218648003 19.78274965689762155, 17.28447821560356346 9.99697084282726678, 21.22695025580456729 4.57607178755088739, 26.01423773319150001 3.23844734533983569, 28.33748018545281155 3.87205892322928236, 32.20955093922164991 5.6320910840332985, 34.60319467791511983 8.37774125488756738, 35.23680625580456649 12.24981200865641284, 34.6735959643472782 15.84027761669661771, 32.13914965278949154 19.43074322473681548, 26.92945445680959438 22.03559082272676761, 22.98698241660859054 21.04997281267651488, 20.31173353218648003 19.78274965689762155))" + ) + self.assertEqual( + p.simplifyByDistance(1).asWkt(3), + "Polygon ((4.338 1.481, 5.838 16.48, 10.61 22.888, 17.632 27.729, 27.041 30.115, 34.812 28.342, 42.516 23.979, 44.834 17.843, 44.152 9.526, 42.448 1.754, 37.267 -4.654, 18.519 -7.313, 7.134 -5.131, 4.338 1.481),(20.312 19.783, 17.284 9.997, 21.227 4.576, 26.014 3.238, 32.21 5.632, 34.603 8.378, 35.237 12.25, 32.139 19.431, 26.929 22.036, 20.312 19.783))", + ) + self.assertEqual( + p.simplifyByDistance(2).asWkt(3), + "Polygon ((4.338 1.481, 5.838 16.48, 17.632 27.729, 27.041 30.115, 42.516 23.979, 44.152 9.526, 37.267 -4.654, 18.519 -7.313, 7.134 -5.131, 4.338 1.481),(20.312 19.783, 17.284 9.997, 21.227 4.576, 32.21 5.632, 35.237 12.25, 32.139 19.431, 26.929 22.036, 20.312 19.783))", + ) # ported GEOS tests - p.fromWkt('POLYGON ((20 220, 40 220, 60 220, 80 220, 100 220, 120 220, 140 220, 140 180, 100 180, 60 180, 20 180, 20 220))') - self.assertEqual(p.simplifyByDistance(10).asWkt(), 'Polygon ((20 220, 140 220, 140 180, 20 180, 20 220))') - p.fromWkt('POLYGON ((120 120, 121 121, 122 122, 220 120, 180 199, 160 200, 140 199, 120 120))') - self.assertEqual(p.simplifyByDistance(10).asWkt(), 'Polygon ((120 120, 220 120, 180 199, 160 200, 140 199, 120 120))') - p.fromWkt('POLYGON ((80 200, 240 200, 240 60, 80 60, 80 200), (120 120, 220 120, 180 199, 160 200, 140 199, 120 120))') - self.assertEqual(p.simplifyByDistance(10).asWkt(), 'Polygon ((80 200, 240 200, 240 60, 80 60, 80 200),(120 120, 220 120, 180 199, 160 200, 140 199, 120 120))') - p.fromWkt('POLYGON ((1 0, 2 0, 2 2, 0 2, 0 0, 1 0))') - self.assertEqual(p.simplifyByDistance(0).asWkt(), 'Polygon ((2 0, 2 2, 0 2, 0 0, 2 0))') - p.fromWkt('POLYGON ((42 42, 0 42, 0 100, 42 100, 100 42, 42 42))') - self.assertEqual(p.simplifyByDistance(1).asWkt(), 'Polygon ((0 42, 0 100, 42 100, 100 42, 0 42))') - - -if __name__ == '__main__': + p.fromWkt( + "POLYGON ((20 220, 40 220, 60 220, 80 220, 100 220, 120 220, 140 220, 140 180, 100 180, 60 180, 20 180, 20 220))" + ) + self.assertEqual( + p.simplifyByDistance(10).asWkt(), + "Polygon ((20 220, 140 220, 140 180, 20 180, 20 220))", + ) + p.fromWkt( + "POLYGON ((120 120, 121 121, 122 122, 220 120, 180 199, 160 200, 140 199, 120 120))" + ) + self.assertEqual( + p.simplifyByDistance(10).asWkt(), + "Polygon ((120 120, 220 120, 180 199, 160 200, 140 199, 120 120))", + ) + p.fromWkt( + "POLYGON ((80 200, 240 200, 240 60, 80 60, 80 200), (120 120, 220 120, 180 199, 160 200, 140 199, 120 120))" + ) + self.assertEqual( + p.simplifyByDistance(10).asWkt(), + "Polygon ((80 200, 240 200, 240 60, 80 60, 80 200),(120 120, 220 120, 180 199, 160 200, 140 199, 120 120))", + ) + p.fromWkt("POLYGON ((1 0, 2 0, 2 2, 0 2, 0 0, 1 0))") + self.assertEqual( + p.simplifyByDistance(0).asWkt(), "Polygon ((2 0, 2 2, 0 2, 0 0, 2 0))" + ) + p.fromWkt("POLYGON ((42 42, 0 42, 0 100, 42 100, 100 42, 42 42))") + self.assertEqual( + p.simplifyByDistance(1).asWkt(), + "Polygon ((0 42, 0 100, 42 100, 100 42, 0 42))", + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspolyhedralsurface.py b/tests/src/python/test_qgspolyhedralsurface.py index dd54fa6d42da..acda576fddca 100644 --- a/tests/src/python/test_qgspolyhedralsurface.py +++ b/tests/src/python/test_qgspolyhedralsurface.py @@ -5,14 +5,20 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Jean Felder' -__date__ = '12/08/2024' -__copyright__ = 'Copyright 2024, The QGIS Project' + +__author__ = "Jean Felder" +__date__ = "12/08/2024" +__copyright__ = "Copyright 2024, The QGIS Project" import qgis # NOQA from qgis.core import ( - QgsLineString, QgsPoint, QgsPolygon, QgsPolyhedralSurface, QgsWkbTypes) + QgsLineString, + QgsPoint, + QgsPolygon, + QgsPolyhedralSurface, + QgsWkbTypes, +) import unittest from qgis.testing import start_app, QgisTestCase @@ -35,7 +41,7 @@ def test_constructor(self): def test_wkt(self): # 2D surface = QgsPolyhedralSurface() - surface.fromWkt('POLYHEDRALSURFACE (((0 0,0 1,1 1,1 0,0 0)))') + surface.fromWkt("POLYHEDRALSURFACE (((0 0,0 1,1 1,1 0,0 0)))") self.assertFalse(surface.isEmpty()) self.assertEqual(surface.numPatches(), 1) self.assertFalse(surface.is3D()) @@ -48,7 +54,7 @@ def test_wkt(self): # 3D surfaceZ = QgsPolyhedralSurface() - surfaceZ.fromWkt('POLYHEDRALSURFACE Z (((0 0 0,0 1 0,1 1 0,0 0 0)))') + surfaceZ.fromWkt("POLYHEDRALSURFACE Z (((0 0 0,0 1 0,1 1 0,0 0 0)))") self.assertFalse(surfaceZ.isEmpty()) self.assertEqual(surfaceZ.numPatches(), 1) self.assertTrue(surfaceZ.is3D()) @@ -61,7 +67,7 @@ def test_wkt(self): # Measure surfaceM = QgsPolyhedralSurface() - surfaceM.fromWkt('POLYHEDRALSURFACE M (((0 0 3,0 1 3,1 1 3,0 0 3)))') + surfaceM.fromWkt("POLYHEDRALSURFACE M (((0 0 3,0 1 3,1 1 3,0 0 3)))") self.assertFalse(surfaceM.isEmpty()) self.assertEqual(surfaceM.numPatches(), 1) self.assertFalse(surfaceM.is3D()) @@ -74,9 +80,11 @@ def test_wkt(self): # ZM surfaceZM = QgsPolyhedralSurface() - surfaceZM.fromWkt('POLYHEDRALSURFACE ZM ' - '(((0 0 1 2,0 1 1 2,1 1 1 2,0 0 1 2)),' - '((10 10 0 0,10 11 0 0,11 11 0 0,10 10 0 0)))') + surfaceZM.fromWkt( + "POLYHEDRALSURFACE ZM " + "(((0 0 1 2,0 1 1 2,1 1 1 2,0 0 1 2))," + "((10 10 0 0,10 11 0 0,11 11 0 0,10 10 0 0)))" + ) self.assertFalse(surfaceZM.isEmpty()) self.assertEqual(surfaceZM.numPatches(), 2) self.assertTrue(surfaceZM.is3D()) @@ -96,12 +104,24 @@ def test_patch(self): patch1 = QgsPolygon() patchExterior1 = QgsLineString( - [QgsPoint(0, 0), QgsPoint(0, 10), QgsPoint(10, 10), QgsPoint(10, 0), - QgsPoint(0, 0)]) + [ + QgsPoint(0, 0), + QgsPoint(0, 10), + QgsPoint(10, 10), + QgsPoint(10, 0), + QgsPoint(0, 0), + ] + ) patch1.setExteriorRing(patchExterior1) patchInteriorRing = QgsLineString( - [QgsPoint(1, 1), QgsPoint(1, 9), QgsPoint(9, 9), QgsPoint(9, 1), - QgsPoint(1, 1)]) + [ + QgsPoint(1, 1), + QgsPoint(1, 9), + QgsPoint(9, 9), + QgsPoint(9, 1), + QgsPoint(1, 1), + ] + ) patch1.addInteriorRing(patchInteriorRing) surface.addPatch(patch1) self.assertEqual(surface.numPatches(), 1) @@ -110,8 +130,14 @@ def test_patch(self): patch2 = QgsPolygon() patchExterior2 = QgsLineString( - [QgsPoint(10, 0), QgsPoint(10, 10), QgsPoint(20, 10), QgsPoint(20, 0), - QgsPoint(10, 0)]) + [ + QgsPoint(10, 0), + QgsPoint(10, 10), + QgsPoint(20, 10), + QgsPoint(20, 0), + QgsPoint(10, 0), + ] + ) patch2.setExteriorRing(patchExterior2) surface.addPatch(patch2) self.assertEqual(surface.numPatches(), 2) @@ -130,21 +156,35 @@ def test_len(self): patch1 = QgsPolygon() patchExterior1 = QgsLineString( - [QgsPoint(0, 0), QgsPoint(0, 10), QgsPoint(10, 10), QgsPoint(10, 0), - QgsPoint(0, 0)]) + [ + QgsPoint(0, 0), + QgsPoint(0, 10), + QgsPoint(10, 10), + QgsPoint(10, 0), + QgsPoint(0, 0), + ] + ) patch1.setExteriorRing(patchExterior1) patchInteriorRing = QgsLineString( - [QgsPoint(1, 1), QgsPoint(1, 9), QgsPoint(9, 9), QgsPoint(9, 1), - QgsPoint(1, 1)]) + [ + QgsPoint(1, 1), + QgsPoint(1, 9), + QgsPoint(9, 9), + QgsPoint(9, 1), + QgsPoint(1, 1), + ] + ) patch1.addInteriorRing(patchInteriorRing) surface1.addPatch(patch1) self.assertEqual(surface1.numPatches(), 1) self.assertEqual(len(surface1), 1) surface2 = QgsPolyhedralSurface() - surface2.fromWkt('POLYHEDRALSURFACE ZM ' - '(((0 0 1 2,0 1 1 2,1 1 1 2,0 0 1 2)),' - '((10 10 0 0,10 11 0 0,11 11 0 0,10 10 0 0)))') + surface2.fromWkt( + "POLYHEDRALSURFACE ZM " + "(((0 0 1 2,0 1 1 2,1 1 1 2,0 0 1 2))," + "((10 10 0 0,10 11 0 0,11 11 0 0,10 10 0 0)))" + ) self.assertTrue(surface2.numPatches(), 2) self.assertTrue(len(surface2), 2) @@ -157,12 +197,24 @@ def test_getitem(self): patch1 = QgsPolygon() patchExterior1 = QgsLineString( - [QgsPoint(0, 0), QgsPoint(0, 10), QgsPoint(10, 10), QgsPoint(10, 0), - QgsPoint(0, 0)]) + [ + QgsPoint(0, 0), + QgsPoint(0, 10), + QgsPoint(10, 10), + QgsPoint(10, 0), + QgsPoint(0, 0), + ] + ) patch1.setExteriorRing(patchExterior1) patchInteriorRing = QgsLineString( - [QgsPoint(1, 1), QgsPoint(1, 9), QgsPoint(9, 9), QgsPoint(9, 1), - QgsPoint(1, 1)]) + [ + QgsPoint(1, 1), + QgsPoint(1, 9), + QgsPoint(9, 9), + QgsPoint(9, 1), + QgsPoint(1, 1), + ] + ) patch1.addInteriorRing(patchInteriorRing) surface.addPatch(patch1) self.assertEqual(surface.numPatches(), 1) @@ -175,8 +227,14 @@ def test_getitem(self): patch2 = QgsPolygon() patchExterior2 = QgsLineString( - [QgsPoint(10, 0), QgsPoint(10, 10), QgsPoint(20, 10), QgsPoint(20, 0), - QgsPoint(10, 0)]) + [ + QgsPoint(10, 0), + QgsPoint(10, 10), + QgsPoint(20, 10), + QgsPoint(20, 0), + QgsPoint(10, 0), + ] + ) patch2.setExteriorRing(patchExterior2) surface.addPatch(patch2) self.assertEqual(surface.numPatches(), 2) @@ -190,5 +248,5 @@ def test_getitem(self): surface[-3] -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspolymorphicrelation.py b/tests/src/python/test_qgspolymorphicrelation.py index d3a60846d5c4..a7c3edd5c8af 100644 --- a/tests/src/python/test_qgspolymorphicrelation.py +++ b/tests/src/python/test_qgspolymorphicrelation.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Ivan Ivanov' -__date__ = '11/1/2021' -__copyright__ = 'Copyright 2021, QGIS Project' + +__author__ = "Ivan Ivanov" +__date__ = "11/1/2021" +__copyright__ = "Copyright 2021, QGIS Project" from qgis.core import ( @@ -25,8 +26,11 @@ def createReferencingLayer(): - layer = QgsVectorLayer("NoGeometry?field=fid:integer&field=referenced_layer:string&field=referenced_fid:string&field=url:string", - "referencinglayer", "memory") + layer = QgsVectorLayer( + "NoGeometry?field=fid:integer&field=referenced_layer:string&field=referenced_fid:string&field=url:string", + "referencinglayer", + "memory", + ) assert layer.isValid() f1 = QgsFeature() f1.setFields(layer.fields()) @@ -46,8 +50,8 @@ def createReferencingLayer(): def createReferencedLayer(layer_name): layer = QgsVectorLayer( - "Point?field=fid:string&field=value:integer", - layer_name, "memory") + "Point?field=fid:string&field=value:integer", layer_name, "memory" + ) assert layer.isValid() f1 = QgsFeature() f1.setFields(layer.fields()) @@ -72,10 +76,12 @@ def formatAttributes(attrs): class TestQgsRelation(QgisTestCase): def setUp(self): - self.referencedLayer1 = createReferencedLayer('referencedlayer1') - self.referencedLayer2 = createReferencedLayer('referencedlayer2') + self.referencedLayer1 = createReferencedLayer("referencedlayer1") + self.referencedLayer2 = createReferencedLayer("referencedlayer2") self.referencingLayer = createReferencingLayer() - QgsProject.instance().addMapLayers([self.referencedLayer1, self.referencedLayer2, self.referencingLayer]) + QgsProject.instance().addMapLayers( + [self.referencedLayer1, self.referencedLayer2, self.referencingLayer] + ) def tearDown(self): QgsProject.instance().removeAllMapLayers() @@ -84,92 +90,107 @@ def test_isValid(self): poly_rel = QgsPolymorphicRelation() self.assertFalse(poly_rel.isValid()) - poly_rel.setId('poly_rel1') + poly_rel.setId("poly_rel1") self.assertFalse(poly_rel.isValid()) - poly_rel.setName('Polymorphic Relation Number One') + poly_rel.setName("Polymorphic Relation Number One") self.assertFalse(poly_rel.isValid()) poly_rel.setReferencingLayer(self.referencingLayer.id()) self.assertFalse(poly_rel.isValid()) - poly_rel.setReferencedLayerIds([self.referencedLayer1.id(), self.referencedLayer2.id()]) + poly_rel.setReferencedLayerIds( + [self.referencedLayer1.id(), self.referencedLayer2.id()] + ) self.assertFalse(poly_rel.isValid()) - poly_rel.setReferencedLayerField('referenced_layer') + poly_rel.setReferencedLayerField("referenced_layer") self.assertFalse(poly_rel.isValid()) - poly_rel.setReferencedLayerExpression('@layer_name') + poly_rel.setReferencedLayerExpression("@layer_name") self.assertFalse(poly_rel.isValid()) - poly_rel.addFieldPair('referenced_fid', 'fid') + poly_rel.addFieldPair("referenced_fid", "fid") self.assertTrue(poly_rel.isValid()) def test_setId(self): poly_rel = QgsPolymorphicRelation() - self.assertEqual(poly_rel.id(), '') - poly_rel.setId('poly_rel_1') - self.assertEqual(poly_rel.id(), 'poly_rel_1') + self.assertEqual(poly_rel.id(), "") + poly_rel.setId("poly_rel_1") + self.assertEqual(poly_rel.id(), "poly_rel_1") def test_setName(self): poly_rel = QgsPolymorphicRelation() self.assertEqual(poly_rel.name(), 'Polymorphic relations for ""') poly_rel.setReferencingLayer(self.referencingLayer.id()) - self.assertEqual(poly_rel.name(), 'Polymorphic relations for "referencinglayer"') - poly_rel.setName('Polymorphic Relation 1') - self.assertEqual(poly_rel.name(), 'Polymorphic Relation 1') + self.assertEqual( + poly_rel.name(), 'Polymorphic relations for "referencinglayer"' + ) + poly_rel.setName("Polymorphic Relation 1") + self.assertEqual(poly_rel.name(), "Polymorphic Relation 1") def test_setReferencingLayer(self): poly_rel = QgsPolymorphicRelation() - self.assertEqual(poly_rel.referencingLayerId(), '') + self.assertEqual(poly_rel.referencingLayerId(), "") poly_rel.setReferencingLayer(self.referencingLayer.id()) self.assertEqual(poly_rel.referencingLayerId(), self.referencingLayer.id()) def test_setReferencedLayerIds(self): poly_rel = QgsPolymorphicRelation() self.assertListEqual(poly_rel.referencedLayerIds(), []) - poly_rel.setReferencedLayerIds([self.referencedLayer1.id(), self.referencedLayer2.id()]) - self.assertListEqual(poly_rel.referencedLayerIds(), [self.referencedLayer1.id(), self.referencedLayer2.id()]) + poly_rel.setReferencedLayerIds( + [self.referencedLayer1.id(), self.referencedLayer2.id()] + ) + self.assertListEqual( + poly_rel.referencedLayerIds(), + [self.referencedLayer1.id(), self.referencedLayer2.id()], + ) def test_setReferencedLayerField(self): poly_rel = QgsPolymorphicRelation() - self.assertEqual(poly_rel.referencedLayerField(), '') + self.assertEqual(poly_rel.referencedLayerField(), "") poly_rel.setReferencedLayerField(self.referencingLayer.id()) self.assertEqual(poly_rel.referencedLayerField(), self.referencingLayer.id()) def test_setReferencedLayerExpression(self): poly_rel = QgsPolymorphicRelation() - self.assertEqual(poly_rel.referencedLayerExpression(), '') - poly_rel.setReferencedLayerExpression('@layer_name') - self.assertEqual(poly_rel.referencedLayerExpression(), '@layer_name') + self.assertEqual(poly_rel.referencedLayerExpression(), "") + poly_rel.setReferencedLayerExpression("@layer_name") + self.assertEqual(poly_rel.referencedLayerExpression(), "@layer_name") def test_addFieldPair(self): poly_rel = QgsPolymorphicRelation() self.assertEqual(poly_rel.fieldPairs(), {}) - poly_rel.addFieldPair('referenced_fid', 'fid') - self.assertEqual(poly_rel.fieldPairs(), {'referenced_fid': 'fid'}) + poly_rel.addFieldPair("referenced_fid", "fid") + self.assertEqual(poly_rel.fieldPairs(), {"referenced_fid": "fid"}) def test_layerRepresentation(self): poly_rel = QgsPolymorphicRelation() - poly_rel.setId('poly_rel1') - poly_rel.setName('Polymorphic Relation Number One') + poly_rel.setId("poly_rel1") + poly_rel.setName("Polymorphic Relation Number One") poly_rel.setReferencingLayer(self.referencingLayer.id()) - poly_rel.setReferencedLayerIds([self.referencedLayer1.id(), self.referencedLayer2.id()]) - poly_rel.setReferencedLayerField('referenced_layer') - poly_rel.setReferencedLayerExpression('@layer_name') - poly_rel.addFieldPair('referenced_fid', 'fid') + poly_rel.setReferencedLayerIds( + [self.referencedLayer1.id(), self.referencedLayer2.id()] + ) + poly_rel.setReferencedLayerField("referenced_layer") + poly_rel.setReferencedLayerExpression("@layer_name") + poly_rel.addFieldPair("referenced_fid", "fid") - self.assertEqual(poly_rel.layerRepresentation(self.referencedLayer1), 'referencedlayer1') + self.assertEqual( + poly_rel.layerRepresentation(self.referencedLayer1), "referencedlayer1" + ) def test_generateRelations(self): poly_rel = QgsPolymorphicRelation() - poly_rel.setId('poly_rel1') - poly_rel.setName('Polymorphic Relation Number One') + poly_rel.setId("poly_rel1") + poly_rel.setName("Polymorphic Relation Number One") poly_rel.setReferencingLayer(self.referencingLayer.id()) - poly_rel.setReferencedLayerIds([self.referencedLayer1.id(), self.referencedLayer2.id()]) - poly_rel.setReferencedLayerField('referenced_layer') - poly_rel.setReferencedLayerExpression('@layer_name') - poly_rel.addFieldPair('referenced_fid', 'fid') + poly_rel.setReferencedLayerIds( + [self.referencedLayer1.id(), self.referencedLayer2.id()] + ) + poly_rel.setReferencedLayerField("referenced_layer") + poly_rel.setReferencedLayerExpression("@layer_name") + poly_rel.addFieldPair("referenced_fid", "fid") QgsProject.instance().relationManager().addPolymorphicRelation(poly_rel) @@ -185,24 +206,39 @@ def test_generateRelations(self): self.assertEqual(rel1.polymorphicRelationId(), poly_rel.id()) self.assertEqual(rel1.referencingLayer(), poly_rel.referencingLayer()) self.assertEqual(rel1.referencedLayer(), self.referencedLayer1) - self.assertEqual(rel1.fieldPairs(), {'referenced_fid': 'fid'}) + self.assertEqual(rel1.fieldPairs(), {"referenced_fid": "fid"}) features = list(self.referencedLayer1.getFeatures()) self.assertEqual(len(features), 3) - self.assertEqual(rel1.getRelatedFeaturesFilter(features[0]), '"referenced_layer" = \'referencedlayer1\' AND "referenced_fid" = \'foo\'') + self.assertEqual( + rel1.getRelatedFeaturesFilter(features[0]), + "\"referenced_layer\" = 'referencedlayer1' AND \"referenced_fid\" = 'foo'", + ) it = rel1.getRelatedFeatures(features[0]) - self.assertListEqual([f.attributes() for f in it], [ - [1, 'referencedlayer1', 'foo', './file1.jpg'], - [2, 'referencedlayer1', 'foo', './file2.jpg'], - ]) - - self.assertEqual(rel1.getRelatedFeaturesFilter(features[1]), '"referenced_layer" = \'referencedlayer1\' AND "referenced_fid" = \'bar\'') + self.assertListEqual( + [f.attributes() for f in it], + [ + [1, "referencedlayer1", "foo", "./file1.jpg"], + [2, "referencedlayer1", "foo", "./file2.jpg"], + ], + ) + + self.assertEqual( + rel1.getRelatedFeaturesFilter(features[1]), + "\"referenced_layer\" = 'referencedlayer1' AND \"referenced_fid\" = 'bar'", + ) it = rel1.getRelatedFeatures(features[1]) - self.assertListEqual([f.attributes() for f in it], [ - [3, 'referencedlayer1', 'bar', './file3.jpg'], - ]) - - self.assertEqual(rel1.getRelatedFeaturesFilter(features[2]), '"referenced_layer" = \'referencedlayer1\' AND "referenced_fid" = \'foobar\'\'bar\'') + self.assertListEqual( + [f.attributes() for f in it], + [ + [3, "referencedlayer1", "bar", "./file3.jpg"], + ], + ) + + self.assertEqual( + rel1.getRelatedFeaturesFilter(features[2]), + "\"referenced_layer\" = 'referencedlayer1' AND \"referenced_fid\" = 'foobar''bar'", + ) it = rel1.getRelatedFeatures(features[2]) self.assertListEqual([f.attributes() for f in it], []) @@ -211,24 +247,34 @@ def test_generateRelations(self): self.assertEqual(rel2.polymorphicRelationId(), poly_rel.id()) self.assertEqual(rel2.referencingLayer(), poly_rel.referencingLayer()) self.assertEqual(rel2.referencedLayer(), self.referencedLayer2) - self.assertEqual(rel2.fieldPairs(), {'referenced_fid': 'fid'}) + self.assertEqual(rel2.fieldPairs(), {"referenced_fid": "fid"}) features = list(self.referencedLayer2.getFeatures()) self.assertEqual(len(features), 3) - self.assertEqual(rel2.getRelatedFeaturesFilter(features[0]), '"referenced_layer" = \'referencedlayer2\' AND "referenced_fid" = \'foo\'') + self.assertEqual( + rel2.getRelatedFeaturesFilter(features[0]), + "\"referenced_layer\" = 'referencedlayer2' AND \"referenced_fid\" = 'foo'", + ) it = rel2.getRelatedFeatures(features[0]) self.assertListEqual([f.attributes() for f in it], []) - self.assertEqual(rel2.getRelatedFeaturesFilter(features[1]), '"referenced_layer" = \'referencedlayer2\' AND "referenced_fid" = \'bar\'') + self.assertEqual( + rel2.getRelatedFeaturesFilter(features[1]), + "\"referenced_layer\" = 'referencedlayer2' AND \"referenced_fid\" = 'bar'", + ) it = rel2.getRelatedFeatures(features[1]) self.assertListEqual([f.attributes() for f in it], []) - self.assertEqual(rel2.getRelatedFeaturesFilter(features[2]), '"referenced_layer" = \'referencedlayer2\' AND "referenced_fid" = \'foobar\'\'bar\'') + self.assertEqual( + rel2.getRelatedFeaturesFilter(features[2]), + "\"referenced_layer\" = 'referencedlayer2' AND \"referenced_fid\" = 'foobar''bar'", + ) it = rel2.getRelatedFeatures(features[2]) - self.assertListEqual([f.attributes() for f in it], [ - [4, 'referencedlayer2', "foobar'bar", './file4.jpg'] - ]) + self.assertListEqual( + [f.attributes() for f in it], + [[4, "referencedlayer2", "foobar'bar", "./file4.jpg"]], + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspostgresdomain.py b/tests/src/python/test_qgspostgresdomain.py index 8972d8bcd24e..2066ba2cd086 100644 --- a/tests/src/python/test_qgspostgresdomain.py +++ b/tests/src/python/test_qgspostgresdomain.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Denis Rouzaud' -__date__ = '10/02/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Denis Rouzaud" +__date__ = "10/02/2018" +__copyright__ = "Copyright 2018, The QGIS Project" import os @@ -27,19 +28,28 @@ def setUpClass(cls): :return: """ super().setUpClass() - cls.dbconn = 'service=\'qgis_test\'' - if 'QGIS_PGTEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_PGTEST_DB'] + cls.dbconn = "service='qgis_test'" + if "QGIS_PGTEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_PGTEST_DB"] # Create test layer - cls.vl = QgsVectorLayer(cls.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."colors" sql=', 'colors', 'postgres') + cls.vl = QgsVectorLayer( + cls.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."colors" sql=', + "colors", + "postgres", + ) QgsProject.instance().addMapLayer(cls.vl) def test_postgres_domain(self): - self.assertEqual(self.vl.dataProvider().enumValues(1), ['red', 'green', 'blue']) - self.assertEqual(self.vl.dataProvider().enumValues(2), ['yellow', 'cyan', 'magenta']) - self.assertEqual(self.vl.dataProvider().enumValues(3), ['Alchemilla', 'Alstroemeria', 'Alyssum']) + self.assertEqual(self.vl.dataProvider().enumValues(1), ["red", "green", "blue"]) + self.assertEqual( + self.vl.dataProvider().enumValues(2), ["yellow", "cyan", "magenta"] + ) + self.assertEqual( + self.vl.dataProvider().enumValues(3), + ["Alchemilla", "Alstroemeria", "Alyssum"], + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgspostgrestransaction.py b/tests/src/python/test_qgspostgrestransaction.py index d63a3c4c1980..dcdc30a2c999 100644 --- a/tests/src/python/test_qgspostgrestransaction.py +++ b/tests/src/python/test_qgspostgrestransaction.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '11/06/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "11/06/2018" +__copyright__ = "Copyright 2018, The QGIS Project" import os @@ -33,22 +34,28 @@ def setUpClass(cls): :return: """ super().setUpClass() - cls.dbconn = 'service=qgis_test' - if 'QGIS_PGTEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_PGTEST_DB'] + cls.dbconn = "service=qgis_test" + if "QGIS_PGTEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_PGTEST_DB"] # Create test layer - cls.vl_b = QgsVectorLayer(cls.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."books" sql=', 'books', - 'postgres') - cls.vl_a = QgsVectorLayer(cls.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."authors" sql=', - 'authors', 'postgres') + cls.vl_b = QgsVectorLayer( + cls.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."books" sql=', + "books", + "postgres", + ) + cls.vl_a = QgsVectorLayer( + cls.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."authors" sql=', + "authors", + "postgres", + ) QgsProject.instance().addMapLayer(cls.vl_b) QgsProject.instance().addMapLayer(cls.vl_a) cls.relMgr = QgsProject.instance().relationManager() - assert (cls.vl_a.isValid()) - assert (cls.vl_b.isValid()) + assert cls.vl_a.isValid() + assert cls.vl_b.isValid() def startTransaction(self): """ @@ -109,10 +116,17 @@ def test_transactionGroupEditingStatus(self): project = QgsProject() project.setTransactionMode(Qgis.TransactionMode.AutomaticGroups) - vl_b = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."books" sql=', 'books', - 'postgres') - vl_a = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."authors" sql=', - 'authors', 'postgres') + vl_b = QgsVectorLayer( + self.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."books" sql=', + "books", + "postgres", + ) + vl_a = QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'pk\' table="qgis_test"."authors" sql=', + "authors", + "postgres", + ) project.addMapLayers([vl_a, vl_b]) @@ -125,5 +139,5 @@ def test_transactionGroupEditingStatus(self): self.assertTrue(vl_b.isEditable()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprocessexecutable_pt1.py b/tests/src/python/test_qgsprocessexecutable_pt1.py index 4e97a9777399..364c10bd57a9 100644 --- a/tests/src/python/test_qgsprocessexecutable_pt1.py +++ b/tests/src/python/test_qgsprocessexecutable_pt1.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 by Nyall Dawson' -__date__ = '05/04/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 by Nyall Dawson" +__date__ = "05/04/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import glob import json @@ -22,14 +23,14 @@ from utilities import unitTestDataPath -print('CTEST_FULL_OUTPUT') +print("CTEST_FULL_OUTPUT") TEST_DATA_DIR = unitTestDataPath() class TestQgsProcessExecutablePt1(unittest.TestCase): - TMP_DIR = '' + TMP_DIR = "" @classmethod def setUpClass(cls): @@ -45,25 +46,33 @@ def tearDownClass(cls): @staticmethod def _strip_ignorable_errors(output: str): - return '\n'.join([e for e in output.splitlines() if e not in ( - 'Problem with GRASS installation: GRASS was not found or is not correctly installed', - 'QStandardPaths: wrong permissions on runtime directory /tmp, 0777 instead of 0700', - 'MESA: error: ZINK: failed to choose pdev', - 'MESA: error: ZINK: vkEnumeratePhysicalDevices failed (VK_ERROR_INITIALIZATION_FAILED)', - 'glx: failed to create drisw screen', - 'failed to load driver: zink', - 'QML debugging is enabled. Only use this in a safe environment.' + return "\n".join( + [ + e + for e in output.splitlines() + if e + not in ( + "Problem with GRASS installation: GRASS was not found or is not correctly installed", + "QStandardPaths: wrong permissions on runtime directory /tmp, 0777 instead of 0700", + "MESA: error: ZINK: failed to choose pdev", + "MESA: error: ZINK: vkEnumeratePhysicalDevices failed (VK_ERROR_INITIALIZATION_FAILED)", + "glx: failed to create drisw screen", + "failed to load driver: zink", + "QML debugging is enabled. Only use this in a safe environment.", + ) + ] ) - ]) def run_process(self, arguments): call = [QGIS_PROCESS_BIN] + arguments - print(' '.join(call)) + print(" ".join(call)) myenv = os.environ.copy() - myenv["QGIS_DEBUG"] = '0' + myenv["QGIS_DEBUG"] = "0" - p = subprocess.Popen(call, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=myenv) + p = subprocess.Popen( + call, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=myenv + ) output, err = p.communicate() rc = p.returncode @@ -71,12 +80,18 @@ def run_process(self, arguments): def run_process_stdin(self, arguments, stdin_string: str): call = [QGIS_PROCESS_BIN] + arguments - print(' '.join(call)) + print(" ".join(call)) myenv = os.environ.copy() - myenv["QGIS_DEBUG"] = '0' - - p = subprocess.Popen(call, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, env=myenv) + myenv["QGIS_DEBUG"] = "0" + + p = subprocess.Popen( + call, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + env=myenv, + ) output, err = p.communicate(input=stdin_string.encode()) rc = p.returncode @@ -84,343 +99,362 @@ def run_process_stdin(self, arguments, stdin_string: str): def testNoArgs(self): rc, output, err = self.run_process([]) - self.assertIn('Available commands', output) + self.assertIn("Available commands", output) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) def testPlugins(self): - rc, output, err = self.run_process(['plugins']) - self.assertIn('indicates loaded plugins', output.lower()) - self.assertIn('available plugins', output.lower()) - self.assertIn('processing', output.lower()) - self.assertNotIn('metasearch', output.lower()) + rc, output, err = self.run_process(["plugins"]) + self.assertIn("indicates loaded plugins", output.lower()) + self.assertIn("available plugins", output.lower()) + self.assertIn("processing", output.lower()) + self.assertNotIn("metasearch", output.lower()) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) def testPluginsSkipLoading(self): - rc, output, err = self.run_process(['plugins', '--skip-loading-plugins']) - self.assertIn('indicates enabled plugins', output.lower()) - self.assertIn('available plugins', output.lower()) - self.assertIn('processing', output.lower()) - self.assertNotIn('metasearch', output.lower()) + rc, output, err = self.run_process(["plugins", "--skip-loading-plugins"]) + self.assertIn("indicates enabled plugins", output.lower()) + self.assertIn("available plugins", output.lower()) + self.assertIn("processing", output.lower()) + self.assertNotIn("metasearch", output.lower()) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) def testPluginStatus(self): - rc, output, err = self.run_process(['plugins']) - self.assertIn('available plugins', output.lower()) - previously_enabled = '* grassprovider' in output.lower() + rc, output, err = self.run_process(["plugins"]) + self.assertIn("available plugins", output.lower()) + previously_enabled = "* grassprovider" in output.lower() # ensure plugin is enabled initially - self.run_process(['plugins', 'enable', 'grassprovider']) + self.run_process(["plugins", "enable", "grassprovider"]) # try to re-enable, should error out - rc, output, err = self.run_process(['plugins', 'enable', 'grassprovider']) + rc, output, err = self.run_process(["plugins", "enable", "grassprovider"]) - self.assertIn('plugin is already enabled', err.lower()) + self.assertIn("plugin is already enabled", err.lower()) self.assertEqual(rc, 1) - rc, output, err = self.run_process(['plugins']) - self.assertIn('available plugins', output.lower()) - self.assertIn('* grassprovider', output.lower()) + rc, output, err = self.run_process(["plugins"]) + self.assertIn("available plugins", output.lower()) + self.assertIn("* grassprovider", output.lower()) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) # disable - rc, output, err = self.run_process(['plugins', 'disable', 'grassprovider']) + rc, output, err = self.run_process(["plugins", "disable", "grassprovider"]) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) # try to re-disable - rc, output, err = self.run_process(['plugins', 'disable', 'grassprovider']) - self.assertIn('plugin is already disabled', err.lower()) + rc, output, err = self.run_process(["plugins", "disable", "grassprovider"]) + self.assertIn("plugin is already disabled", err.lower()) self.assertEqual(rc, 1) - rc, output, err = self.run_process(['plugins']) - self.assertIn('available plugins', output.lower()) - self.assertNotIn('* grassprovider', output.lower()) + rc, output, err = self.run_process(["plugins"]) + self.assertIn("available plugins", output.lower()) + self.assertNotIn("* grassprovider", output.lower()) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) - rc, output, err = self.run_process(['plugins', 'enable', 'grassprovider']) + rc, output, err = self.run_process(["plugins", "enable", "grassprovider"]) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) - rc, output, err = self.run_process(['plugins']) - self.assertIn('available plugins', output.lower()) - self.assertIn('* grassprovider', output.lower()) + rc, output, err = self.run_process(["plugins"]) + self.assertIn("available plugins", output.lower()) + self.assertIn("* grassprovider", output.lower()) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) if not previously_enabled: - self.run_process(['plugins', 'disable', 'grassprovider']) + self.run_process(["plugins", "disable", "grassprovider"]) # not a plugin - rc, output, err = self.run_process(['plugins', 'enable', 'reformatplugin']) - self.assertIn('no matching plugins found', err.lower()) + rc, output, err = self.run_process(["plugins", "enable", "reformatplugin"]) + self.assertIn("no matching plugins found", err.lower()) self.assertEqual(rc, 1) - rc, output, err = self.run_process(['plugins', 'disable', 'reformatplugin']) - self.assertIn('no matching plugins found', err.lower()) + rc, output, err = self.run_process(["plugins", "disable", "reformatplugin"]) + self.assertIn("no matching plugins found", err.lower()) self.assertEqual(rc, 1) def testPluginsJson(self): - rc, output, err = self.run_process(['plugins', '--json']) + rc, output, err = self.run_process(["plugins", "--json"]) res = json.loads(output) - self.assertIn('gdal_version', res) - self.assertIn('geos_version', res) - self.assertIn('proj_version', res) - self.assertIn('python_version', res) - self.assertIn('qt_version', res) - self.assertIn('qgis_version', res) - self.assertIn('plugins', res) - self.assertIn('processing', res['plugins']) - self.assertTrue(res['plugins']['processing']['loaded']) + self.assertIn("gdal_version", res) + self.assertIn("geos_version", res) + self.assertIn("proj_version", res) + self.assertIn("python_version", res) + self.assertIn("qt_version", res) + self.assertIn("qgis_version", res) + self.assertIn("plugins", res) + self.assertIn("processing", res["plugins"]) + self.assertTrue(res["plugins"]["processing"]["loaded"]) self.assertEqual(rc, 0) def testAlgorithmList(self): - rc, output, err = self.run_process(['list']) - self.assertIn('available algorithms', output.lower()) - self.assertIn('native:reprojectlayer', output.lower()) - self.assertIn('gdal:translate', output.lower()) + rc, output, err = self.run_process(["list"]) + self.assertIn("available algorithms", output.lower()) + self.assertIn("native:reprojectlayer", output.lower()) + self.assertIn("gdal:translate", output.lower()) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) def testAlgorithmListNoPython(self): - rc, output, err = self.run_process(['--no-python', 'list']) - self.assertIn('available algorithms', output.lower()) - self.assertIn('native:reprojectlayer', output.lower()) - self.assertNotIn('gdal:translate', output.lower()) + rc, output, err = self.run_process(["--no-python", "list"]) + self.assertIn("available algorithms", output.lower()) + self.assertIn("native:reprojectlayer", output.lower()) + self.assertNotIn("gdal:translate", output.lower()) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) def testAlgorithmsListJson(self): - rc, output, err = self.run_process(['list', '--json']) + rc, output, err = self.run_process(["list", "--json"]) res = json.loads(output) - self.assertIn('gdal_version', res) - self.assertIn('geos_version', res) - self.assertIn('proj_version', res) - self.assertIn('python_version', res) - self.assertIn('qt_version', res) - self.assertIn('qgis_version', res) - - self.assertIn('providers', res) - self.assertIn('native', res['providers']) - self.assertTrue(res['providers']['native']['is_active']) - self.assertIn('native:buffer', res['providers']['native']['algorithms']) - self.assertIn('gdal:translate', - res['providers']['gdal']['algorithms']) - self.assertFalse(res['providers']['native']['algorithms']['native:buffer']['deprecated']) + self.assertIn("gdal_version", res) + self.assertIn("geos_version", res) + self.assertIn("proj_version", res) + self.assertIn("python_version", res) + self.assertIn("qt_version", res) + self.assertIn("qgis_version", res) + + self.assertIn("providers", res) + self.assertIn("native", res["providers"]) + self.assertTrue(res["providers"]["native"]["is_active"]) + self.assertIn("native:buffer", res["providers"]["native"]["algorithms"]) + self.assertIn("gdal:translate", res["providers"]["gdal"]["algorithms"]) + self.assertFalse( + res["providers"]["native"]["algorithms"]["native:buffer"]["deprecated"] + ) self.assertEqual(rc, 0) def testAlgorithmHelpNoAlg(self): - rc, output, err = self.run_process(['help', '--no-python']) + rc, output, err = self.run_process(["help", "--no-python"]) self.assertEqual(rc, 1) - self.assertIn('algorithm id or model file not specified', err.lower()) + self.assertIn("algorithm id or model file not specified", err.lower()) self.assertFalse(output) def testAlgorithmHelp(self): - rc, output, err = self.run_process(['help', '--no-python', 'native:centroids']) - self.assertIn('representing the centroid', output.lower()) - self.assertIn('argument type', output.lower()) + rc, output, err = self.run_process(["help", "--no-python", "native:centroids"]) + self.assertIn("representing the centroid", output.lower()) + self.assertIn("argument type", output.lower()) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) def testAlgorithmHelpJson(self): - rc, output, err = self.run_process(['help', '--no-python', 'native:buffer', '--json']) + rc, output, err = self.run_process( + ["help", "--no-python", "native:buffer", "--json"] + ) res = json.loads(output) - self.assertIn('gdal_version', res) - self.assertIn('geos_version', res) - self.assertIn('proj_version', res) - self.assertIn('python_version', res) - self.assertIn('qt_version', res) - self.assertIn('qgis_version', res) + self.assertIn("gdal_version", res) + self.assertIn("geos_version", res) + self.assertIn("proj_version", res) + self.assertIn("python_version", res) + self.assertIn("qt_version", res) + self.assertIn("qgis_version", res) - self.assertFalse(res['algorithm_details']['deprecated']) - self.assertTrue(res['provider_details']['is_active']) + self.assertFalse(res["algorithm_details"]["deprecated"]) + self.assertTrue(res["provider_details"]["is_active"]) - self.assertIn('OUTPUT', res['outputs']) - self.assertEqual(res['outputs']['OUTPUT']['description'], 'Buffered') - self.assertEqual(res['parameters']['DISSOLVE']['description'], 'Dissolve result') - self.assertFalse(res['parameters']['DISTANCE']['is_advanced']) + self.assertIn("OUTPUT", res["outputs"]) + self.assertEqual(res["outputs"]["OUTPUT"]["description"], "Buffered") + self.assertEqual( + res["parameters"]["DISSOLVE"]["description"], "Dissolve result" + ) + self.assertFalse(res["parameters"]["DISTANCE"]["is_advanced"]) self.assertEqual(rc, 0) def testAlgorithmRunNoAlg(self): - rc, output, err = self.run_process(['run', '--no-python']) - self.assertIn('algorithm id or model file not specified', err.lower()) + rc, output, err = self.run_process(["run", "--no-python"]) + self.assertIn("algorithm id or model file not specified", err.lower()) self.assertFalse(output) self.assertEqual(rc, 1) def testAlgorithmRunNoArgs(self): - rc, output, err = self.run_process(['run', '--no-python', 'native:centroids']) - self.assertIn('the following mandatory parameters were not specified', err.lower()) - self.assertIn('inputs', output.lower()) + rc, output, err = self.run_process(["run", "--no-python", "native:centroids"]) + self.assertIn( + "the following mandatory parameters were not specified", err.lower() + ) + self.assertIn("inputs", output.lower()) self.assertEqual(rc, 1) def testAlgorithmRunLegacy(self): - output_file = self.TMP_DIR + '/polygon_centroid.shp' - rc, output, err = self.run_process(['run', '--no-python', 'native:centroids', f"--INPUT={TEST_DATA_DIR + '/polys.shp'}", f'--OUTPUT={output_file}']) + output_file = self.TMP_DIR + "/polygon_centroid.shp" + rc, output, err = self.run_process( + [ + "run", + "--no-python", + "native:centroids", + f"--INPUT={TEST_DATA_DIR + '/polys.shp'}", + f"--OUTPUT={output_file}", + ] + ) self.assertFalse(self._strip_ignorable_errors(err)) - self.assertIn('0...10...20...30...40...50...60...70...80...90', output.lower()) - self.assertIn('results', output.lower()) - self.assertIn('OUTPUT:\t' + output_file, output) + self.assertIn("0...10...20...30...40...50...60...70...80...90", output.lower()) + self.assertIn("results", output.lower()) + self.assertIn("OUTPUT:\t" + output_file, output) self.assertTrue(os.path.exists(output_file)) self.assertEqual(rc, 0) def testAlgorithmRun(self): - output_file = self.TMP_DIR + '/polygon_centroid.shp' - rc, output, err = self.run_process(['run', '--no-python', 'native:centroids', '--', f"INPUT={TEST_DATA_DIR + '/polys.shp'}", f'OUTPUT={output_file}']) + output_file = self.TMP_DIR + "/polygon_centroid.shp" + rc, output, err = self.run_process( + [ + "run", + "--no-python", + "native:centroids", + "--", + f"INPUT={TEST_DATA_DIR + '/polys.shp'}", + f"OUTPUT={output_file}", + ] + ) self.assertFalse(self._strip_ignorable_errors(err)) - self.assertIn('0...10...20...30...40...50...60...70...80...90', output.lower()) - self.assertIn('results', output.lower()) - self.assertIn('OUTPUT:\t' + output_file, output) + self.assertIn("0...10...20...30...40...50...60...70...80...90", output.lower()) + self.assertIn("results", output.lower()) + self.assertIn("OUTPUT:\t" + output_file, output) self.assertTrue(os.path.exists(output_file)) self.assertEqual(rc, 0) def testAlgorithmRunStdIn(self): - output_file = self.TMP_DIR + '/polygon_centroid_json.shp' + output_file = self.TMP_DIR + "/polygon_centroid_json.shp" params = { - 'inputs': { - 'INPUT': TEST_DATA_DIR + '/polys.shp', - 'OUTPUT': output_file - } + "inputs": {"INPUT": TEST_DATA_DIR + "/polys.shp", "OUTPUT": output_file} } - rc, output, err = self.run_process_stdin(['run', '--no-python', 'native:centroids', '-'], json.dumps(params)) + rc, output, err = self.run_process_stdin( + ["run", "--no-python", "native:centroids", "-"], json.dumps(params) + ) self.assertFalse(self._strip_ignorable_errors(err)) res = json.loads(output) - self.assertIn('gdal_version', res) - self.assertIn('geos_version', res) - self.assertIn('proj_version', res) - self.assertIn('python_version', res) - self.assertIn('qt_version', res) - self.assertIn('qgis_version', res) + self.assertIn("gdal_version", res) + self.assertIn("geos_version", res) + self.assertIn("proj_version", res) + self.assertIn("python_version", res) + self.assertIn("qt_version", res) + self.assertIn("qgis_version", res) - self.assertEqual(res['algorithm_details']['name'], 'Centroids') - self.assertEqual(res['inputs']['INPUT'], TEST_DATA_DIR + '/polys.shp') - self.assertEqual(res['inputs']['OUTPUT'], output_file) - self.assertEqual(res['results']['OUTPUT'], output_file) + self.assertEqual(res["algorithm_details"]["name"], "Centroids") + self.assertEqual(res["inputs"]["INPUT"], TEST_DATA_DIR + "/polys.shp") + self.assertEqual(res["inputs"]["OUTPUT"], output_file) + self.assertEqual(res["results"]["OUTPUT"], output_file) self.assertTrue(os.path.exists(output_file)) self.assertEqual(rc, 0) def testAlgorithmRunStdInExtraSettings(self): - output_file = self.TMP_DIR + '/polygon_centroid_json.shp' + output_file = self.TMP_DIR + "/polygon_centroid_json.shp" params = { - 'inputs': { - 'INPUT': TEST_DATA_DIR + '/polys.shp', - 'OUTPUT': output_file - }, - 'ellipsoid': 'EPSG:7019', - 'distance_units': 'feet', - 'area_units': 'ha', - 'project_path': TEST_DATA_DIR + '/joins.qgs' + "inputs": {"INPUT": TEST_DATA_DIR + "/polys.shp", "OUTPUT": output_file}, + "ellipsoid": "EPSG:7019", + "distance_units": "feet", + "area_units": "ha", + "project_path": TEST_DATA_DIR + "/joins.qgs", } - rc, output, err = self.run_process_stdin(['run', '--no-python', 'native:centroids', '-'], json.dumps(params)) + rc, output, err = self.run_process_stdin( + ["run", "--no-python", "native:centroids", "-"], json.dumps(params) + ) res = json.loads(output) - self.assertIn('gdal_version', res) - self.assertIn('geos_version', res) - self.assertIn('proj_version', res) - self.assertIn('python_version', res) - self.assertIn('qt_version', res) - self.assertIn('qgis_version', res) - - self.assertEqual(res['algorithm_details']['name'], 'Centroids') - self.assertEqual(res['ellipsoid'], 'EPSG:7019') - self.assertEqual(res['distance_unit'], 'feet') - self.assertEqual(res['area_unit'], 'hectares') - self.assertEqual(res['project_path'], TEST_DATA_DIR + '/joins.qgs') - self.assertEqual(res['inputs']['INPUT'], TEST_DATA_DIR + '/polys.shp') - self.assertEqual(res['inputs']['OUTPUT'], output_file) - self.assertEqual(res['results']['OUTPUT'], output_file) + self.assertIn("gdal_version", res) + self.assertIn("geos_version", res) + self.assertIn("proj_version", res) + self.assertIn("python_version", res) + self.assertIn("qt_version", res) + self.assertIn("qgis_version", res) + + self.assertEqual(res["algorithm_details"]["name"], "Centroids") + self.assertEqual(res["ellipsoid"], "EPSG:7019") + self.assertEqual(res["distance_unit"], "feet") + self.assertEqual(res["area_unit"], "hectares") + self.assertEqual(res["project_path"], TEST_DATA_DIR + "/joins.qgs") + self.assertEqual(res["inputs"]["INPUT"], TEST_DATA_DIR + "/polys.shp") + self.assertEqual(res["inputs"]["OUTPUT"], output_file) + self.assertEqual(res["results"]["OUTPUT"], output_file) self.assertTrue(os.path.exists(output_file)) self.assertEqual(rc, 0) def testAlgorithmRunStdInExtraSettingsBadDistanceUnit(self): - output_file = self.TMP_DIR + '/polygon_centroid_json.shp' + output_file = self.TMP_DIR + "/polygon_centroid_json.shp" params = { - 'inputs': { - 'INPUT': TEST_DATA_DIR + '/polys.shp', - 'OUTPUT': output_file - }, - 'distance_units': 'xxx', + "inputs": {"INPUT": TEST_DATA_DIR + "/polys.shp", "OUTPUT": output_file}, + "distance_units": "xxx", } - rc, output, err = self.run_process_stdin(['run', '--no-python', 'native:centroids', '-'], json.dumps(params)) + rc, output, err = self.run_process_stdin( + ["run", "--no-python", "native:centroids", "-"], json.dumps(params) + ) self.assertEqual(rc, 1) - self.assertIn('xxx is not a valid distance unit value', err) + self.assertIn("xxx is not a valid distance unit value", err) def testAlgorithmRunStdInExtraSettingsBadAreaUnit(self): - output_file = self.TMP_DIR + '/polygon_centroid_json.shp' + output_file = self.TMP_DIR + "/polygon_centroid_json.shp" params = { - 'inputs': { - 'INPUT': TEST_DATA_DIR + '/polys.shp', - 'OUTPUT': output_file - }, - 'area_units': 'xxx', + "inputs": {"INPUT": TEST_DATA_DIR + "/polys.shp", "OUTPUT": output_file}, + "area_units": "xxx", } - rc, output, err = self.run_process_stdin(['run', '--no-python', 'native:centroids', '-'], json.dumps(params)) + rc, output, err = self.run_process_stdin( + ["run", "--no-python", "native:centroids", "-"], json.dumps(params) + ) self.assertEqual(rc, 1) - self.assertIn('xxx is not a valid area unit value', err) + self.assertIn("xxx is not a valid area unit value", err) def testAlgorithmRunStdInExtraSettingsBadProjectPath(self): - output_file = self.TMP_DIR + '/polygon_centroid_json.shp' + output_file = self.TMP_DIR + "/polygon_centroid_json.shp" params = { - 'inputs': { - 'INPUT': TEST_DATA_DIR + '/polys.shp', - 'OUTPUT': output_file - }, - 'project_path': 'xxx', + "inputs": {"INPUT": TEST_DATA_DIR + "/polys.shp", "OUTPUT": output_file}, + "project_path": "xxx", } - rc, output, err = self.run_process_stdin(['run', '--no-python', 'native:centroids', '-'], json.dumps(params)) + rc, output, err = self.run_process_stdin( + ["run", "--no-python", "native:centroids", "-"], json.dumps(params) + ) self.assertEqual(rc, 1) self.assertIn('Could not load the QGIS project "xxx"', err) -if __name__ == '__main__': +if __name__ == "__main__": # look for qgis bin path - QGIS_PROCESS_BIN = '' - prefixPath = os.environ['QGIS_PREFIX_PATH'] + QGIS_PROCESS_BIN = "" + prefixPath = os.environ["QGIS_PREFIX_PATH"] # see qgsapplication.cpp:98 - for f in ['', '..', 'bin']: + for f in ["", "..", "bin"]: d = os.path.join(prefixPath, f) - b = os.path.abspath(os.path.join(d, 'qgis_process')) + b = os.path.abspath(os.path.join(d, "qgis_process")) if os.path.exists(b): QGIS_PROCESS_BIN = b break - b = os.path.abspath(os.path.join(d, 'qgis_process.exe')) + b = os.path.abspath(os.path.join(d, "qgis_process.exe")) if os.path.exists(b): QGIS_PROCESS_BIN = b break - if sys.platform[:3] == 'dar': # Mac + if sys.platform[:3] == "dar": # Mac # QGIS.app may be QGIS_x.x-dev.app for nightlies # internal binary will match, minus the '.app' found = False - for app_path in glob.glob(d + '/QGIS*.app'): - m = re.search(r'/(QGIS(_\d\.\d-dev)?)\.app', app_path) + for app_path in glob.glob(d + "/QGIS*.app"): + m = re.search(r"/(QGIS(_\d\.\d-dev)?)\.app", app_path) if m: - QGIS_PROCESS_BIN = app_path + '/Contents/MacOS/' + m.group(1) + QGIS_PROCESS_BIN = app_path + "/Contents/MacOS/" + m.group(1) found = True break if found: break - print(f'\nQGIS_PROCESS_BIN: {QGIS_PROCESS_BIN}') - assert QGIS_PROCESS_BIN, 'qgis_process binary not found, skipping test suite' + print(f"\nQGIS_PROCESS_BIN: {QGIS_PROCESS_BIN}") + assert QGIS_PROCESS_BIN, "qgis_process binary not found, skipping test suite" unittest.main() diff --git a/tests/src/python/test_qgsprocessexecutable_pt2.py b/tests/src/python/test_qgsprocessexecutable_pt2.py index abaecee4b01a..ab393bc9875f 100644 --- a/tests/src/python/test_qgsprocessexecutable_pt2.py +++ b/tests/src/python/test_qgsprocessexecutable_pt2.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 by Nyall Dawson' -__date__ = '05/04/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 by Nyall Dawson" +__date__ = "05/04/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import glob import json @@ -22,14 +23,14 @@ from utilities import unitTestDataPath -print('CTEST_FULL_OUTPUT') +print("CTEST_FULL_OUTPUT") TEST_DATA_DIR = unitTestDataPath() class TestQgsProcessExecutablePt2(unittest.TestCase): - TMP_DIR = '' + TMP_DIR = "" @classmethod def setUpClass(cls): @@ -45,25 +46,33 @@ def tearDownClass(cls): @staticmethod def _strip_ignorable_errors(output: str): - return '\n'.join([e for e in output.splitlines() if e not in ( - 'Problem with GRASS installation: GRASS was not found or is not correctly installed', - 'QStandardPaths: wrong permissions on runtime directory /tmp, 0777 instead of 0700', - 'MESA: error: ZINK: failed to choose pdev', - 'MESA: error: ZINK: vkEnumeratePhysicalDevices failed (VK_ERROR_INITIALIZATION_FAILED)', - 'glx: failed to create drisw screen', - 'failed to load driver: zink', - 'QML debugging is enabled. Only use this in a safe environment.' + return "\n".join( + [ + e + for e in output.splitlines() + if e + not in ( + "Problem with GRASS installation: GRASS was not found or is not correctly installed", + "QStandardPaths: wrong permissions on runtime directory /tmp, 0777 instead of 0700", + "MESA: error: ZINK: failed to choose pdev", + "MESA: error: ZINK: vkEnumeratePhysicalDevices failed (VK_ERROR_INITIALIZATION_FAILED)", + "glx: failed to create drisw screen", + "failed to load driver: zink", + "QML debugging is enabled. Only use this in a safe environment.", + ) + ] ) - ]) def run_process(self, arguments): call = [QGIS_PROCESS_BIN] + arguments - print(' '.join(call)) + print(" ".join(call)) myenv = os.environ.copy() - myenv["QGIS_DEBUG"] = '0' + myenv["QGIS_DEBUG"] = "0" - p = subprocess.Popen(call, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=myenv) + p = subprocess.Popen( + call, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=myenv + ) output, err = p.communicate() rc = p.returncode @@ -71,55 +80,74 @@ def run_process(self, arguments): def run_process_stdin(self, arguments, stdin_string: str): call = [QGIS_PROCESS_BIN] + arguments - print(' '.join(call)) + print(" ".join(call)) myenv = os.environ.copy() - myenv["QGIS_DEBUG"] = '0' - - p = subprocess.Popen(call, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, env=myenv) + myenv["QGIS_DEBUG"] = "0" + + p = subprocess.Popen( + call, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + env=myenv, + ) output, err = p.communicate(input=stdin_string.encode()) rc = p.returncode return rc, output.decode(), err.decode() def testAlgorithmRunStdInMissingInputKey(self): - output_file = self.TMP_DIR + '/polygon_centroid_json.shp' + output_file = self.TMP_DIR + "/polygon_centroid_json.shp" - params = { - 'INPUT': TEST_DATA_DIR + '/polys.shp', - 'OUTPUT': output_file - } + params = {"INPUT": TEST_DATA_DIR + "/polys.shp", "OUTPUT": output_file} - rc, output, err = self.run_process_stdin(['run', '--no-python', 'native:centroids', '-'], json.dumps(params)) + rc, output, err = self.run_process_stdin( + ["run", "--no-python", "native:centroids", "-"], json.dumps(params) + ) self.assertEqual(rc, 1) self.assertIn('JSON parameters object must contain an "inputs" key.', err) def testAlgorithmRunStdInNoInput(self): - rc, output, err = self.run_process_stdin(['run', '--no-python', 'native:centroids', '-'], '') + rc, output, err = self.run_process_stdin( + ["run", "--no-python", "native:centroids", "-"], "" + ) self.assertEqual(rc, 1) - self.assertIn('Could not parse JSON parameters', err) + self.assertIn("Could not parse JSON parameters", err) def testAlgorithmRunStdInBadInput(self): - rc, output, err = self.run_process_stdin(['run', '--no-python', 'native:centroids', '-'], '{"not valid json"}') + rc, output, err = self.run_process_stdin( + ["run", "--no-python", "native:centroids", "-"], '{"not valid json"}' + ) self.assertEqual(rc, 1) - self.assertIn('Could not parse JSON parameters', err) + self.assertIn("Could not parse JSON parameters", err) def testAlgorithmRunJson(self): - output_file = self.TMP_DIR + '/polygon_centroid2.shp' - rc, output, err = self.run_process(['run', '--no-python', '--json', 'native:centroids', '--', f"INPUT={TEST_DATA_DIR + '/polys.shp'}", f'OUTPUT={output_file}']) + output_file = self.TMP_DIR + "/polygon_centroid2.shp" + rc, output, err = self.run_process( + [ + "run", + "--no-python", + "--json", + "native:centroids", + "--", + f"INPUT={TEST_DATA_DIR + '/polys.shp'}", + f"OUTPUT={output_file}", + ] + ) res = json.loads(output) - self.assertIn('gdal_version', res) - self.assertIn('geos_version', res) - self.assertIn('proj_version', res) - self.assertIn('python_version', res) - self.assertIn('qt_version', res) - self.assertIn('qgis_version', res) + self.assertIn("gdal_version", res) + self.assertIn("geos_version", res) + self.assertIn("proj_version", res) + self.assertIn("python_version", res) + self.assertIn("qt_version", res) + self.assertIn("qgis_version", res) - self.assertEqual(res['algorithm_details']['name'], 'Centroids') - self.assertEqual(res['inputs']['INPUT'], TEST_DATA_DIR + '/polys.shp') - self.assertEqual(res['inputs']['OUTPUT'], output_file) - self.assertEqual(res['results']['OUTPUT'], output_file) + self.assertEqual(res["algorithm_details"]["name"], "Centroids") + self.assertEqual(res["inputs"]["INPUT"], TEST_DATA_DIR + "/polys.shp") + self.assertEqual(res["inputs"]["OUTPUT"], output_file) + self.assertEqual(res["results"]["OUTPUT"], output_file) self.assertTrue(os.path.exists(output_file)) self.assertEqual(rc, 0) @@ -128,262 +156,340 @@ def testAlgorithmRunListValue(self): """ Test an algorithm which requires a list of layers as a parameter value """ - output_file = self.TMP_DIR + '/package.gpkg' - rc, output, err = self.run_process(['run', '--no-python', '--json', 'native:package', '--', - f"LAYERS={TEST_DATA_DIR + '/polys.shp'}", - f"LAYERS={TEST_DATA_DIR + '/points.shp'}", - f"LAYERS={TEST_DATA_DIR + '/lines.shp'}", - f'OUTPUT={output_file}']) + output_file = self.TMP_DIR + "/package.gpkg" + rc, output, err = self.run_process( + [ + "run", + "--no-python", + "--json", + "native:package", + "--", + f"LAYERS={TEST_DATA_DIR + '/polys.shp'}", + f"LAYERS={TEST_DATA_DIR + '/points.shp'}", + f"LAYERS={TEST_DATA_DIR + '/lines.shp'}", + f"OUTPUT={output_file}", + ] + ) res = json.loads(output) - self.assertIn('gdal_version', res) - self.assertIn('geos_version', res) - self.assertIn('proj_version', res) - self.assertIn('python_version', res) - self.assertIn('qt_version', res) - self.assertIn('qgis_version', res) + self.assertIn("gdal_version", res) + self.assertIn("geos_version", res) + self.assertIn("proj_version", res) + self.assertIn("python_version", res) + self.assertIn("qt_version", res) + self.assertIn("qgis_version", res) - self.assertEqual(res['algorithm_details']['name'], 'Package layers') - self.assertEqual(len(res['inputs']['LAYERS']), 3) - self.assertEqual(res['inputs']['OUTPUT'], output_file) - self.assertEqual(res['results']['OUTPUT'], output_file) - self.assertEqual(len(res['results']['OUTPUT_LAYERS']), 3) + self.assertEqual(res["algorithm_details"]["name"], "Package layers") + self.assertEqual(len(res["inputs"]["LAYERS"]), 3) + self.assertEqual(res["inputs"]["OUTPUT"], output_file) + self.assertEqual(res["results"]["OUTPUT"], output_file) + self.assertEqual(len(res["results"]["OUTPUT_LAYERS"]), 3) self.assertTrue(os.path.exists(output_file)) self.assertEqual(rc, 0) def testModelHelp(self): - rc, output, err = self.run_process(['help', '--no-python', TEST_DATA_DIR + '/test_model.model3']) + rc, output, err = self.run_process( + ["help", "--no-python", TEST_DATA_DIR + "/test_model.model3"] + ) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) - self.assertIn('model description', output.lower()) - self.assertIn('author of model', output.lower()) - self.assertIn('version 2.1', output.lower()) - self.assertIn('examples', output.lower()) - self.assertIn('this is an example of running the model', output.lower()) + self.assertIn("model description", output.lower()) + self.assertIn("author of model", output.lower()) + self.assertIn("version 2.1", output.lower()) + self.assertIn("examples", output.lower()) + self.assertIn("this is an example of running the model", output.lower()) def testModelRun(self): - output_file = self.TMP_DIR + '/model_output.shp' - rc, output, err = self.run_process(['run', '--no-python', TEST_DATA_DIR + '/test_model.model3', '--', f"FEATS={TEST_DATA_DIR + '/polys.shp'}", f'native:centroids_1:CENTROIDS={output_file}']) + output_file = self.TMP_DIR + "/model_output.shp" + rc, output, err = self.run_process( + [ + "run", + "--no-python", + TEST_DATA_DIR + "/test_model.model3", + "--", + f"FEATS={TEST_DATA_DIR + '/polys.shp'}", + f"native:centroids_1:CENTROIDS={output_file}", + ] + ) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) - self.assertIn('0...10...20...30...40...50...60...70...80...90', output.lower()) - self.assertIn('results', output.lower()) + self.assertIn("0...10...20...30...40...50...60...70...80...90", output.lower()) + self.assertIn("results", output.lower()) self.assertTrue(os.path.exists(output_file)) def testModelRunStdIn(self): - output_file = self.TMP_DIR + '/model_output_stdin.shp' + output_file = self.TMP_DIR + "/model_output_stdin.shp" params = { - 'inputs': { - 'FEATS': TEST_DATA_DIR + '/polys.shp', - 'native:centroids_1:CENTROIDS': output_file + "inputs": { + "FEATS": TEST_DATA_DIR + "/polys.shp", + "native:centroids_1:CENTROIDS": output_file, } } - rc, output, err = self.run_process_stdin(['run', '--no-python', TEST_DATA_DIR + '/test_model.model3', '-'], json.dumps(params)) + rc, output, err = self.run_process_stdin( + ["run", "--no-python", TEST_DATA_DIR + "/test_model.model3", "-"], + json.dumps(params), + ) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) res = json.loads(output) - self.assertIn('gdal_version', res) - self.assertIn('geos_version', res) - self.assertIn('proj_version', res) - self.assertIn('python_version', res) - self.assertIn('qt_version', res) - self.assertIn('qgis_version', res) - self.assertEqual(res['algorithm_details']['id'], 'Test model') + self.assertIn("gdal_version", res) + self.assertIn("geos_version", res) + self.assertIn("proj_version", res) + self.assertIn("python_version", res) + self.assertIn("qt_version", res) + self.assertIn("qgis_version", res) + self.assertEqual(res["algorithm_details"]["id"], "Test model") self.assertTrue(os.path.exists(output_file)) def testModelRunJson(self): - output_file = self.TMP_DIR + '/model_output2.shp' - rc, output, err = self.run_process(['run', TEST_DATA_DIR + '/test_model.model3', '--no-python', '--json', '--', f"FEATS={TEST_DATA_DIR + '/polys.shp'}", f'native:centroids_1:CENTROIDS={output_file}']) + output_file = self.TMP_DIR + "/model_output2.shp" + rc, output, err = self.run_process( + [ + "run", + TEST_DATA_DIR + "/test_model.model3", + "--no-python", + "--json", + "--", + f"FEATS={TEST_DATA_DIR + '/polys.shp'}", + f"native:centroids_1:CENTROIDS={output_file}", + ] + ) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) res = json.loads(output) - self.assertIn('gdal_version', res) - self.assertIn('geos_version', res) - self.assertIn('proj_version', res) - self.assertIn('python_version', res) - self.assertIn('qt_version', res) - self.assertIn('qgis_version', res) - self.assertEqual(res['algorithm_details']['id'], 'Test model') + self.assertIn("gdal_version", res) + self.assertIn("geos_version", res) + self.assertIn("proj_version", res) + self.assertIn("python_version", res) + self.assertIn("qt_version", res) + self.assertIn("qgis_version", res) + self.assertEqual(res["algorithm_details"]["id"], "Test model") self.assertTrue(os.path.exists(output_file)) def testModelRunWithLog(self): - output_file = self.TMP_DIR + '/model_log.log' - rc, output, err = self.run_process(['run', '--no-python', TEST_DATA_DIR + '/test_logging_model.model3', '--', f'logfile={output_file}']) + output_file = self.TMP_DIR + "/model_log.log" + rc, output, err = self.run_process( + [ + "run", + "--no-python", + TEST_DATA_DIR + "/test_logging_model.model3", + "--", + f"logfile={output_file}", + ] + ) self.assertEqual(rc, 0) - self.assertIn('0...10...20...30...40...50...60...70...80...90', output.lower()) - self.assertIn('results', output.lower()) + self.assertIn("0...10...20...30...40...50...60...70...80...90", output.lower()) + self.assertIn("results", output.lower()) self.assertTrue(os.path.exists(output_file)) with open(output_file) as f: - lines = '\n'.join(f.readlines()) + lines = "\n".join(f.readlines()) - self.assertIn('Test logged message', lines) + self.assertIn("Test logged message", lines) def testPythonScriptHelp(self): - rc, output, err = self.run_process(['help', TEST_DATA_DIR + '/convert_to_upper.py']) + rc, output, err = self.run_process( + ["help", TEST_DATA_DIR + "/convert_to_upper.py"] + ) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) - self.assertIn('converts a string to upper case', output.lower()) + self.assertIn("converts a string to upper case", output.lower()) def testPythonScriptRun(self): - rc, output, err = self.run_process(['run', TEST_DATA_DIR + '/convert_to_upper.py', '--', 'INPUT=abc']) + rc, output, err = self.run_process( + ["run", TEST_DATA_DIR + "/convert_to_upper.py", "--", "INPUT=abc"] + ) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) - self.assertIn('Converted abc to ABC', output) - self.assertIn('OUTPUT:\tABC', output) + self.assertIn("Converted abc to ABC", output) + self.assertIn("OUTPUT:\tABC", output) def testPythonScriptRunJson(self): - rc, output, err = self.run_process(['run', TEST_DATA_DIR + '/convert_to_upper.py', '--json', '--', 'INPUT=abc']) + rc, output, err = self.run_process( + ["run", TEST_DATA_DIR + "/convert_to_upper.py", "--json", "--", "INPUT=abc"] + ) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) res = json.loads(output) - self.assertIn('gdal_version', res) - self.assertIn('geos_version', res) - self.assertIn('proj_version', res) - self.assertIn('python_version', res) - self.assertIn('qt_version', res) - self.assertIn('qgis_version', res) - self.assertEqual(res['algorithm_details']['id'], 'script:converttouppercase') - self.assertEqual(res['results']['OUTPUT'], 'ABC') + self.assertIn("gdal_version", res) + self.assertIn("geos_version", res) + self.assertIn("proj_version", res) + self.assertIn("python_version", res) + self.assertIn("qt_version", res) + self.assertIn("qgis_version", res) + self.assertEqual(res["algorithm_details"]["id"], "script:converttouppercase") + self.assertEqual(res["results"]["OUTPUT"], "ABC") def testScriptRunStdIn(self): - output_file = self.TMP_DIR + '/model_output_stdin.shp' + output_file = self.TMP_DIR + "/model_output_stdin.shp" - params = { - 'inputs': - { - 'INPUT': 'abc def' - } - } + params = {"inputs": {"INPUT": "abc def"}} - rc, output, err = self.run_process_stdin(['run', TEST_DATA_DIR + '/convert_to_upper.py', '-'], json.dumps(params)) + rc, output, err = self.run_process_stdin( + ["run", TEST_DATA_DIR + "/convert_to_upper.py", "-"], json.dumps(params) + ) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) res = json.loads(output) - self.assertIn('gdal_version', res) - self.assertIn('geos_version', res) - self.assertIn('proj_version', res) - self.assertIn('python_version', res) - self.assertIn('qt_version', res) - self.assertIn('qgis_version', res) - self.assertEqual(res['algorithm_details']['id'], 'script:converttouppercase') - self.assertEqual(res['results']['OUTPUT'], 'ABC DEF') + self.assertIn("gdal_version", res) + self.assertIn("geos_version", res) + self.assertIn("proj_version", res) + self.assertIn("python_version", res) + self.assertIn("qt_version", res) + self.assertIn("qgis_version", res) + self.assertEqual(res["algorithm_details"]["id"], "script:converttouppercase") + self.assertEqual(res["results"]["OUTPUT"], "ABC DEF") def testPythonScriptRunNotAlgorithm(self): - rc, output, err = self.run_process(['run', TEST_DATA_DIR + '/not_a_processing_script.py']) + rc, output, err = self.run_process( + ["run", TEST_DATA_DIR + "/not_a_processing_script.py"] + ) self.assertEqual(rc, 1) - self.assertIn('is not a valid Processing script', err) + self.assertIn("is not a valid Processing script", err) def testPythonScriptHelpNotAlgorithm(self): - rc, output, err = self.run_process(['help', TEST_DATA_DIR + '/not_a_processing_script.py']) + rc, output, err = self.run_process( + ["help", TEST_DATA_DIR + "/not_a_processing_script.py"] + ) self.assertEqual(rc, 1) - self.assertIn('is not a valid Processing script', err) + self.assertIn("is not a valid Processing script", err) def testPythonScriptRunError(self): - rc, output, err = self.run_process(['run', TEST_DATA_DIR + '/script_with_error.py']) + rc, output, err = self.run_process( + ["run", TEST_DATA_DIR + "/script_with_error.py"] + ) self.assertNotEqual(rc, 0) - self.assertIn('is not a valid Processing script', err) + self.assertIn("is not a valid Processing script", err) def testPythonScriptHelpError(self): - rc, output, err = self.run_process(['help', TEST_DATA_DIR + '/script_with_error.py']) + rc, output, err = self.run_process( + ["help", TEST_DATA_DIR + "/script_with_error.py"] + ) self.assertNotEqual(rc, 0) - self.assertIn('is not a valid Processing script', err) + self.assertIn("is not a valid Processing script", err) def testComplexParameterNames(self): - rc, output, err = self.run_process(['run', TEST_DATA_DIR + '/complex_names.py', '--INPUT with many complex chars.123 a=abc', '--another% complex# NaMe=def']) + rc, output, err = self.run_process( + [ + "run", + TEST_DATA_DIR + "/complex_names.py", + "--INPUT with many complex chars.123 a=abc", + "--another% complex# NaMe=def", + ] + ) self.assertFalse(self._strip_ignorable_errors(err)) - self.assertIn('OUTPUT: abc:def', output) + self.assertIn("OUTPUT: abc:def", output) self.assertEqual(rc, 0) def testLoadLayer(self): - rc, output, err = self.run_process(['run', '--no-python', 'native:raiseexception', '--MESSAGE=CONFIRMED', f"--CONDITION=layer_property(load_layer('{TEST_DATA_DIR + '/points.shp'}','ogr'),'feature_count')>10"]) - self.assertIn('CONFIRMED', self._strip_ignorable_errors(err)) + rc, output, err = self.run_process( + [ + "run", + "--no-python", + "native:raiseexception", + "--MESSAGE=CONFIRMED", + f"--CONDITION=layer_property(load_layer('{TEST_DATA_DIR + '/points.shp'}','ogr'),'feature_count')>10", + ] + ) + self.assertIn("CONFIRMED", self._strip_ignorable_errors(err)) self.assertEqual(rc, 1) def testDynamicParameters(self): - output_file = self.TMP_DIR + '/dynamic_out2.shp' + output_file = self.TMP_DIR + "/dynamic_out2.shp" rc, output, err = self.run_process( - ['run', 'native:buffer', '--INPUT=' + TEST_DATA_DIR + '/points.shp', '--OUTPUT=' + output_file, '--DISTANCE=field:fid', '--json']) + [ + "run", + "native:buffer", + "--INPUT=" + TEST_DATA_DIR + "/points.shp", + "--OUTPUT=" + output_file, + "--DISTANCE=field:fid", + "--json", + ] + ) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) res = json.loads(output) - self.assertEqual(res['algorithm_details']['id'], 'native:buffer') - self.assertEqual(res['inputs']['DISTANCE'], 'field:fid') + self.assertEqual(res["algorithm_details"]["id"], "native:buffer") + self.assertEqual(res["inputs"]["DISTANCE"], "field:fid") def testDynamicParametersJson(self): - output_file = self.TMP_DIR + '/dynamic_out.shp' + output_file = self.TMP_DIR + "/dynamic_out.shp" params = { - 'inputs': - { - 'INPUT': TEST_DATA_DIR + '/points.shp', - 'DISTANCE': {'type': 'data_defined', 'field': 'fid'}, - 'OUTPUT': output_file - } + "inputs": { + "INPUT": TEST_DATA_DIR + "/points.shp", + "DISTANCE": {"type": "data_defined", "field": "fid"}, + "OUTPUT": output_file, + } } rc, output, err = self.run_process_stdin( - ['run', 'native:buffer', '-'], json.dumps(params)) + ["run", "native:buffer", "-"], json.dumps(params) + ) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) res = json.loads(output) - self.assertEqual(res['algorithm_details']['id'], 'native:buffer') - self.assertEqual(res['inputs']['DISTANCE'], {'field': 'fid', 'type': 'data_defined'}) + self.assertEqual(res["algorithm_details"]["id"], "native:buffer") + self.assertEqual( + res["inputs"]["DISTANCE"], {"field": "fid", "type": "data_defined"} + ) def testStartupOptimisationsStyleLazyInitialized(self): """ Ensure that the costly QgsStyle.defaultStyle() initialization is NOT performed by default when running qgis_process commands """ - rc, output, err = self.run_process(['run', TEST_DATA_DIR + '/report_style_initialization_status.py']) + rc, output, err = self.run_process( + ["run", TEST_DATA_DIR + "/report_style_initialization_status.py"] + ) self.assertFalse(self._strip_ignorable_errors(err)) self.assertEqual(rc, 0) - self.assertIn('IS_INITIALIZED: false', output) + self.assertIn("IS_INITIALIZED: false", output) -if __name__ == '__main__': +if __name__ == "__main__": # look for qgis bin path - QGIS_PROCESS_BIN = '' - prefixPath = os.environ['QGIS_PREFIX_PATH'] + QGIS_PROCESS_BIN = "" + prefixPath = os.environ["QGIS_PREFIX_PATH"] # see qgsapplication.cpp:98 - for f in ['', '..', 'bin']: + for f in ["", "..", "bin"]: d = os.path.join(prefixPath, f) - b = os.path.abspath(os.path.join(d, 'qgis_process')) + b = os.path.abspath(os.path.join(d, "qgis_process")) if os.path.exists(b): QGIS_PROCESS_BIN = b break - b = os.path.abspath(os.path.join(d, 'qgis_process.exe')) + b = os.path.abspath(os.path.join(d, "qgis_process.exe")) if os.path.exists(b): QGIS_PROCESS_BIN = b break - if sys.platform[:3] == 'dar': # Mac + if sys.platform[:3] == "dar": # Mac # QGIS.app may be QGIS_x.x-dev.app for nightlies # internal binary will match, minus the '.app' found = False - for app_path in glob.glob(d + '/QGIS*.app'): - m = re.search(r'/(QGIS(_\d\.\d-dev)?)\.app', app_path) + for app_path in glob.glob(d + "/QGIS*.app"): + m = re.search(r"/(QGIS(_\d\.\d-dev)?)\.app", app_path) if m: - QGIS_PROCESS_BIN = app_path + '/Contents/MacOS/' + m.group(1) + QGIS_PROCESS_BIN = app_path + "/Contents/MacOS/" + m.group(1) found = True break if found: break - print(f'\nQGIS_PROCESS_BIN: {QGIS_PROCESS_BIN}') - assert QGIS_PROCESS_BIN, 'qgis_process binary not found, skipping test suite' + print(f"\nQGIS_PROCESS_BIN: {QGIS_PROCESS_BIN}") + assert QGIS_PROCESS_BIN, "qgis_process binary not found, skipping test suite" unittest.main() diff --git a/tests/src/python/test_qgsprocessingalgrunner.py b/tests/src/python/test_qgsprocessingalgrunner.py index 5fcd6004d0dd..48fcc832bceb 100644 --- a/tests/src/python/test_qgsprocessingalgrunner.py +++ b/tests/src/python/test_qgsprocessingalgrunner.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '2019-02' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "2019-02" +__copyright__ = "Copyright 2019, The QGIS Project" from processing.core.Processing import Processing from qgis.PyQt.QtCore import QCoreApplication @@ -22,7 +23,7 @@ QgsSettings, QgsTask, QgsProcessingException, - QgsVectorLayer + QgsVectorLayer, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -32,7 +33,7 @@ class ConsoleFeedBack(QgsProcessingFeedback): - _error = '' + _error = "" def reportError(self, error, fatalError=False): self._error = error @@ -44,27 +45,27 @@ class CrashingProcessingAlgorithm(QgsProcessingAlgorithm): Wrong class in factory createInstance() """ - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + OUTPUT = "OUTPUT" def tr(self, string): - return QCoreApplication.translate('Processing', string) + return QCoreApplication.translate("Processing", string) def createInstance(self): """Wrong!""" return ExampleProcessingAlgorithm() # noqa def name(self): - return 'mycrashingscript' + return "mycrashingscript" def displayName(self): - return self.tr('My Crashing Script') + return self.tr("My Crashing Script") def group(self): - return self.tr('Example scripts') + return self.tr("Example scripts") def groupId(self): - return 'examplescripts' + return "examplescripts" def shortHelpString(self): return self.tr("Example algorithm short description") @@ -73,69 +74,73 @@ def initAlgorithm(self, config=None): pass def processAlgorithm(self, parameters, context, feedback): - return {self.OUTPUT: 'an_id'} + return {self.OUTPUT: "an_id"} class TestAlgorithm(QgsProcessingAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + OUTPUT = "OUTPUT" def createInstance(self): return TestAlgorithm() def name(self): - return 'test' + return "test" def displayName(self): - return 'test' + return "test" def group(self): - return 'test' + return "test" def groupId(self): - return 'test' + return "test" def shortHelpString(self): - return 'test' + return "test" def initAlgorithm(self, config=None): pass def processAlgorithm(self, parameters, context, feedback): - context.temporaryLayerStore().addMapLayer(QgsVectorLayer("Point?crs=epsg:3111", "v1", "memory")) - return {self.OUTPUT: 'an_id'} + context.temporaryLayerStore().addMapLayer( + QgsVectorLayer("Point?crs=epsg:3111", "v1", "memory") + ) + return {self.OUTPUT: "an_id"} class ExceptionAlgorithm(QgsProcessingAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + OUTPUT = "OUTPUT" def createInstance(self): return ExceptionAlgorithm() def name(self): - return 'test' + return "test" def displayName(self): - return 'test' + return "test" def group(self): - return 'test' + return "test" def groupId(self): - return 'test' + return "test" def shortHelpString(self): - return 'test' + return "test" def initAlgorithm(self, config=None): pass def processAlgorithm(self, parameters, context, feedback): - context.temporaryLayerStore().addMapLayer(QgsVectorLayer("Point?crs=epsg:3111", "v1", "memory")) - raise QgsProcessingException('error') + context.temporaryLayerStore().addMapLayer( + QgsVectorLayer("Point?crs=epsg:3111", "v1", "memory") + ) + raise QgsProcessingException("error") class TestQgsProcessingAlgRunner(QgisTestCase): @@ -145,8 +150,7 @@ def setUpClass(cls): """Run before all tests""" super().setUpClass() QCoreApplication.setOrganizationName("QGIS_Test") - QCoreApplication.setOrganizationDomain( - "QGIS_TestPyQgsProcessingInPlace.com") + QCoreApplication.setOrganizationDomain("QGIS_TestPyQgsProcessingInPlace.com") QCoreApplication.setApplicationName("QGIS_TestPyQgsProcessingInPlace") QgsSettings().clear() Processing.initialize() @@ -157,41 +161,118 @@ def test_flags(self): """ Test task flags """ - thread_safe_alg = QgsApplication.processingRegistry().algorithmById('native:buffer') - nonthread_safe_alg = QgsApplication.processingRegistry().algorithmById('native:setprojectvariable') + thread_safe_alg = QgsApplication.processingRegistry().algorithmById( + "native:buffer" + ) + nonthread_safe_alg = QgsApplication.processingRegistry().algorithmById( + "native:setprojectvariable" + ) context = QgsProcessingContext() context.setProject(QgsProject.instance()) feedback = ConsoleFeedBack() - task = QgsProcessingAlgRunnerTask(thread_safe_alg, {}, context=context, feedback=feedback) + task = QgsProcessingAlgRunnerTask( + thread_safe_alg, {}, context=context, feedback=feedback + ) self.assertEqual(task.flags(), QgsTask.Flag.CanCancel) - task = QgsProcessingAlgRunnerTask(thread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.Flags()) + task = QgsProcessingAlgRunnerTask( + thread_safe_alg, + {}, + context=context, + feedback=feedback, + flags=QgsTask.Flags(), + ) self.assertEqual(task.flags(), QgsTask.Flags()) - task = QgsProcessingAlgRunnerTask(thread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.Flag.CanCancel) + task = QgsProcessingAlgRunnerTask( + thread_safe_alg, + {}, + context=context, + feedback=feedback, + flags=QgsTask.Flag.CanCancel, + ) self.assertEqual(task.flags(), QgsTask.Flag.CanCancel) - task = QgsProcessingAlgRunnerTask(thread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.Flag.CancelWithoutPrompt) + task = QgsProcessingAlgRunnerTask( + thread_safe_alg, + {}, + context=context, + feedback=feedback, + flags=QgsTask.Flag.CancelWithoutPrompt, + ) self.assertEqual(task.flags(), QgsTask.Flag.CancelWithoutPrompt) - task = QgsProcessingAlgRunnerTask(thread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.Flag.CancelWithoutPrompt | QgsTask.Flag.CanCancel) - self.assertEqual(task.flags(), QgsTask.Flag.CancelWithoutPrompt | QgsTask.Flag.CanCancel) + task = QgsProcessingAlgRunnerTask( + thread_safe_alg, + {}, + context=context, + feedback=feedback, + flags=QgsTask.Flag.CancelWithoutPrompt | QgsTask.Flag.CanCancel, + ) + self.assertEqual( + task.flags(), QgsTask.Flag.CancelWithoutPrompt | QgsTask.Flag.CanCancel + ) # alg which can't be canceled - task = QgsProcessingAlgRunnerTask(nonthread_safe_alg, {}, context=context, feedback=feedback) + task = QgsProcessingAlgRunnerTask( + nonthread_safe_alg, {}, context=context, feedback=feedback + ) self.assertEqual(task.flags(), QgsTask.Flags()) # we clear the CanCancel flag automatically, since the algorithm itself cannot be canceled - task = QgsProcessingAlgRunnerTask(nonthread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.Flag.CanCancel) + task = QgsProcessingAlgRunnerTask( + nonthread_safe_alg, + {}, + context=context, + feedback=feedback, + flags=QgsTask.Flag.CanCancel, + ) self.assertEqual(task.flags(), QgsTask.Flags()) # hidden task - task = QgsProcessingAlgRunnerTask(thread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.Flag.Hidden) + task = QgsProcessingAlgRunnerTask( + thread_safe_alg, + {}, + context=context, + feedback=feedback, + flags=QgsTask.Flag.Hidden, + ) self.assertEqual(task.flags(), QgsTask.Flag.Hidden) - task = QgsProcessingAlgRunnerTask(thread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.Flag.Hidden | QgsTask.Flag.CanCancel) + task = QgsProcessingAlgRunnerTask( + thread_safe_alg, + {}, + context=context, + feedback=feedback, + flags=QgsTask.Flag.Hidden | QgsTask.Flag.CanCancel, + ) self.assertEqual(task.flags(), QgsTask.Flag.Hidden | QgsTask.Flag.CanCancel) - task = QgsProcessingAlgRunnerTask(thread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.Flag.Hidden | QgsTask.Flag.CanCancel | QgsTask.Flag.CancelWithoutPrompt) - self.assertEqual(task.flags(), QgsTask.Flag.Hidden | QgsTask.Flag.CanCancel | QgsTask.Flag.CancelWithoutPrompt) - - task = QgsProcessingAlgRunnerTask(nonthread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.Flag.Hidden) + task = QgsProcessingAlgRunnerTask( + thread_safe_alg, + {}, + context=context, + feedback=feedback, + flags=QgsTask.Flag.Hidden + | QgsTask.Flag.CanCancel + | QgsTask.Flag.CancelWithoutPrompt, + ) + self.assertEqual( + task.flags(), + QgsTask.Flag.Hidden + | QgsTask.Flag.CanCancel + | QgsTask.Flag.CancelWithoutPrompt, + ) + + task = QgsProcessingAlgRunnerTask( + nonthread_safe_alg, + {}, + context=context, + feedback=feedback, + flags=QgsTask.Flag.Hidden, + ) self.assertEqual(task.flags(), QgsTask.Flag.Hidden) - task = QgsProcessingAlgRunnerTask(nonthread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.Flag.Hidden | QgsTask.Flag.CanCancel) + task = QgsProcessingAlgRunnerTask( + nonthread_safe_alg, + {}, + context=context, + feedback=feedback, + flags=QgsTask.Flag.Hidden | QgsTask.Flag.CanCancel, + ) self.assertEqual(task.flags(), QgsTask.Flag.Hidden) def test_bad_script_dont_crash(self): # spellok @@ -201,9 +282,13 @@ def test_bad_script_dont_crash(self): # spellok context.setProject(QgsProject.instance()) feedback = ConsoleFeedBack() - task = QgsProcessingAlgRunnerTask(CrashingProcessingAlgorithm(), {}, context=context, feedback=feedback) + task = QgsProcessingAlgRunnerTask( + CrashingProcessingAlgorithm(), {}, context=context, feedback=feedback + ) self.assertTrue(task.isCanceled()) - self.assertIn('name \'ExampleProcessingAlgorithm\' is not defined', feedback._error) + self.assertIn( + "name 'ExampleProcessingAlgorithm' is not defined", feedback._error + ) def test_good(self): """ @@ -214,7 +299,9 @@ def test_good(self): context.setProject(QgsProject.instance()) feedback = ConsoleFeedBack() - task = QgsProcessingAlgRunnerTask(TestAlgorithm(), {}, context=context, feedback=feedback) + task = QgsProcessingAlgRunnerTask( + TestAlgorithm(), {}, context=context, feedback=feedback + ) self.assertFalse(task.isCanceled()) TestQgsProcessingAlgRunner.finished = False TestQgsProcessingAlgRunner.success = None @@ -240,7 +327,9 @@ def test_raises_exception(self): context.setProject(QgsProject.instance()) feedback = ConsoleFeedBack() - task = QgsProcessingAlgRunnerTask(ExceptionAlgorithm(), {}, context=context, feedback=feedback) + task = QgsProcessingAlgRunnerTask( + ExceptionAlgorithm(), {}, context=context, feedback=feedback + ) self.assertFalse(task.isCanceled()) TestQgsProcessingAlgRunner.finished = False TestQgsProcessingAlgRunner.success = None @@ -260,5 +349,5 @@ def on_executed(success, results): self.assertEqual(context.temporaryLayerStore().count(), 1) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprocessingbatch.py b/tests/src/python/test_qgsprocessingbatch.py index 4690400c15e8..3034339fed5e 100644 --- a/tests/src/python/test_qgsprocessingbatch.py +++ b/tests/src/python/test_qgsprocessingbatch.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '09/11/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "09/11/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.core import QgsProcessingBatchFeedback, QgsProcessingFeedback @@ -28,11 +29,11 @@ def testFeedback(self): # test error collection self.assertFalse(feedback.popErrors()) - feedback.reportError('error 1') - feedback.reportError('error 2') - self.assertEqual(feedback.popErrors(), ['error 1', 'error 2']) + feedback.reportError("error 1") + feedback.reportError("error 2") + self.assertEqual(feedback.popErrors(), ["error 1", "error 2"]) self.assertFalse(feedback.popErrors()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprocessingfavoritealgorithmmanager.py b/tests/src/python/test_qgsprocessingfavoritealgorithmmanager.py index a09e9ecebd11..93618017c74b 100644 --- a/tests/src/python/test_qgsprocessingfavoritealgorithmmanager.py +++ b/tests/src/python/test_qgsprocessingfavoritealgorithmmanager.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Alexander Bruy' -__date__ = '2024-02' -__copyright__ = 'Copyright 2024, The QGIS Project' + +__author__ = "Alexander Bruy" +__date__ = "2024-02" +__copyright__ = "Copyright 2024, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication from qgis.PyQt.QtTest import QSignalSpy @@ -35,52 +36,68 @@ def test_log(self): self.assertFalse(log.favoriteAlgorithmIds()) spy = QSignalSpy(log.changed) - log.add('test') - self.assertEqual(log.favoriteAlgorithmIds(), ['test']) + log.add("test") + self.assertEqual(log.favoriteAlgorithmIds(), ["test"]) self.assertEqual(len(spy), 1) - log.add('test') - self.assertEqual(log.favoriteAlgorithmIds(), ['test']) + log.add("test") + self.assertEqual(log.favoriteAlgorithmIds(), ["test"]) self.assertEqual(len(spy), 1) - log.add('test2') - self.assertEqual(log.favoriteAlgorithmIds(), ['test', 'test2']) + log.add("test2") + self.assertEqual(log.favoriteAlgorithmIds(), ["test", "test2"]) self.assertEqual(len(spy), 2) - log.remove('test') - self.assertEqual(log.favoriteAlgorithmIds(), ['test2']) + log.remove("test") + self.assertEqual(log.favoriteAlgorithmIds(), ["test2"]) self.assertEqual(len(spy), 3) - log.add('test') - self.assertEqual(log.favoriteAlgorithmIds(), ['test2', 'test']) + log.add("test") + self.assertEqual(log.favoriteAlgorithmIds(), ["test2", "test"]) self.assertEqual(len(spy), 4) - log.add('test3') - self.assertEqual(log.favoriteAlgorithmIds(), ['test2', 'test', 'test3']) + log.add("test3") + self.assertEqual(log.favoriteAlgorithmIds(), ["test2", "test", "test3"]) self.assertEqual(len(spy), 5) - log.add('test4') - self.assertEqual(log.favoriteAlgorithmIds(), ['test2', 'test', 'test3', 'test4']) + log.add("test4") + self.assertEqual( + log.favoriteAlgorithmIds(), ["test2", "test", "test3", "test4"] + ) self.assertEqual(len(spy), 6) - log.add('test5') - self.assertEqual(log.favoriteAlgorithmIds(), ['test2', 'test', 'test3', 'test4', 'test5']) + log.add("test5") + self.assertEqual( + log.favoriteAlgorithmIds(), ["test2", "test", "test3", "test4", "test5"] + ) self.assertEqual(len(spy), 7) - log.add('test6') - self.assertEqual(log.favoriteAlgorithmIds(), ['test2', 'test', 'test3', 'test4', 'test5', 'test6']) + log.add("test6") + self.assertEqual( + log.favoriteAlgorithmIds(), + ["test2", "test", "test3", "test4", "test5", "test6"], + ) self.assertEqual(len(spy), 8) - log.add('test7') - self.assertEqual(log.favoriteAlgorithmIds(), ['test2', 'test', 'test3', 'test4', 'test5', 'test6', 'test7']) + log.add("test7") + self.assertEqual( + log.favoriteAlgorithmIds(), + ["test2", "test", "test3", "test4", "test5", "test6", "test7"], + ) self.assertEqual(len(spy), 9) - log.add('test3') - self.assertEqual(log.favoriteAlgorithmIds(), ['test2', 'test', 'test3', 'test4', 'test5', 'test6', 'test7']) + log.add("test3") + self.assertEqual( + log.favoriteAlgorithmIds(), + ["test2", "test", "test3", "test4", "test5", "test6", "test7"], + ) self.assertEqual(len(spy), 9) # test that log has been saved to QgsSettings log2 = QgsProcessingFavoriteAlgorithmManager() - self.assertEqual(log2.favoriteAlgorithmIds(), ['test2', 'test', 'test3', 'test4', 'test5', 'test6', 'test7']) + self.assertEqual( + log2.favoriteAlgorithmIds(), + ["test2", "test", "test3", "test4", "test5", "test6", "test7"], + ) log2.clear() self.assertEqual(log2.favoriteAlgorithmIds(), []) @@ -89,5 +106,5 @@ def test_gui_instance(self): self.assertIsNotNone(QgsGui.instance().processingFavoriteAlgorithmManager()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprocessinginplace.py b/tests/src/python/test_qgsprocessinginplace.py index 6f1a55d96b6a..366ac9d5552b 100644 --- a/tests/src/python/test_qgsprocessinginplace.py +++ b/tests/src/python/test_qgsprocessinginplace.py @@ -5,9 +5,10 @@ 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' + +__author__ = "Alessandro Pasotti" +__date__ = "2018-09" +__copyright__ = "Copyright 2018, The QGIS Project" import os import re @@ -37,7 +38,9 @@ QgsSettings, QgsVectorLayer, QgsVectorLayerUtils, - QgsWkbTypes, NULL) + QgsWkbTypes, + NULL, +) import unittest from qgis.testing import start_app, QgisTestCase @@ -52,19 +55,19 @@ def reportError(self, error, fatalError=False): print(error) -base_types = ['Point', 'LineString', 'Polygon'] +base_types = ["Point", "LineString", "Polygon"] def _add_multi(base): - return base + ['Multi' + _b for _b in base] + return base + ["Multi" + _b for _b in base] def _add_z(base): - return base + [_b + 'Z' for _b in base] + return base + [_b + "Z" for _b in base] def _add_m(base): - return base + [_b + 'M' for _b in base] + return base + [_b + "M" for _b in base] def _all_true(): @@ -72,7 +75,7 @@ def _all_true(): types = _add_multi(types) types = _add_z(types) types = _add_m(types) - types.append('NoGeometry') + types.append("NoGeometry") return {t: True for t in types} @@ -88,24 +91,27 @@ def setUpClass(cls): """Run before all tests""" QCoreApplication.setOrganizationName("QGIS_Test") - QCoreApplication.setOrganizationDomain( - "QGIS_TestPyQgsProcessingInPlace.com") + QCoreApplication.setOrganizationDomain("QGIS_TestPyQgsProcessingInPlace.com") QCoreApplication.setApplicationName("QGIS_TestPyQgsProcessingInPlace") QgsSettings().clear() Processing.initialize() QgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms()) cls.registry = QgsApplication.instance().processingRegistry() fields = QgsFields() - fields.append(QgsField('int_f', QVariant.Int)) + fields.append(QgsField("int_f", QVariant.Int)) cls.vl = QgsMemoryProviderUtils.createMemoryLayer( - 'mylayer', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:4326')) + "mylayer", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:4326"), + ) f1 = QgsFeature(cls.vl.fields()) - f1['int_f'] = 1 - f1.setGeometry(QgsGeometry.fromWkt('Point(9 45)')) + f1["int_f"] = 1 + f1.setGeometry(QgsGeometry.fromWkt("Point(9 45)")) f2 = QgsFeature(cls.vl.fields()) - f2['int_f'] = 2 - f2.setGeometry(QgsGeometry.fromWkt('Point(9.5 45.6)')) + f2["int_f"] = 2 + f2.setGeometry(QgsGeometry.fromWkt("Point(9.5 45.6)")) cls.vl.dataProvider().addFeatures([f1, f2]) assert cls.vl.isValid() @@ -114,14 +120,24 @@ def setUpClass(cls): # Multipolygon layer cls.multipoly_vl = QgsMemoryProviderUtils.createMemoryLayer( - 'mymultiplayer', fields, QgsWkbTypes.Type.MultiPolygon, QgsCoordinateReferenceSystem('EPSG:4326')) + "mymultiplayer", + fields, + QgsWkbTypes.Type.MultiPolygon, + QgsCoordinateReferenceSystem("EPSG:4326"), + ) f3 = QgsFeature(cls.multipoly_vl.fields()) - f3.setGeometry(QgsGeometry.fromWkt( - 'MultiPolygon (((2.81856297539240419 41.98170998812887689, 2.81874467773035464 41.98167537995160359, 2.81879535908157752 41.98154066615795443, 2.81866433873670452 41.98144056064155905, 2.81848263699778379 41.98147516865246587, 2.81843195500470811 41.98160988234612034, 2.81856297539240419 41.98170998812887689)),((2.81898589063455907 41.9815711567298635, 2.81892080450418803 41.9816030048432367, 2.81884192631866437 41.98143737613141724, 2.8190679469505846 41.98142270931093378, 2.81898589063455907 41.9815711567298635)))')) + f3.setGeometry( + QgsGeometry.fromWkt( + "MultiPolygon (((2.81856297539240419 41.98170998812887689, 2.81874467773035464 41.98167537995160359, 2.81879535908157752 41.98154066615795443, 2.81866433873670452 41.98144056064155905, 2.81848263699778379 41.98147516865246587, 2.81843195500470811 41.98160988234612034, 2.81856297539240419 41.98170998812887689)),((2.81898589063455907 41.9815711567298635, 2.81892080450418803 41.9816030048432367, 2.81884192631866437 41.98143737613141724, 2.8190679469505846 41.98142270931093378, 2.81898589063455907 41.9815711567298635)))" + ) + ) f4 = QgsFeature(cls.multipoly_vl.fields()) - f4.setGeometry(QgsGeometry.fromWkt( - 'MultiPolygon (((2.81823679385631332 41.98133290154246566, 2.81830770255185703 41.98123540208609228, 2.81825871989355159 41.98112524362621656, 2.81813882853970243 41.98111258462271422, 2.81806791984415872 41.98121008407908761, 2.81811690250246416 41.98132024253896333, 2.81823679385631332 41.98133290154246566)),((2.81835835162010895 41.98123286963267731, 2.8183127674586852 41.98108725356146209, 2.8184520523963692 41.98115436357689134, 2.81835835162010895 41.98123286963267731)))')) + f4.setGeometry( + QgsGeometry.fromWkt( + "MultiPolygon (((2.81823679385631332 41.98133290154246566, 2.81830770255185703 41.98123540208609228, 2.81825871989355159 41.98112524362621656, 2.81813882853970243 41.98111258462271422, 2.81806791984415872 41.98121008407908761, 2.81811690250246416 41.98132024253896333, 2.81823679385631332 41.98133290154246566)),((2.81835835162010895 41.98123286963267731, 2.8183127674586852 41.98108725356146209, 2.8184520523963692 41.98115436357689134, 2.81835835162010895 41.98123286963267731)))" + ) + ) cls.multipoly_vl.dataProvider().addFeatures([f3, f4]) assert cls.multipoly_vl.isValid() @@ -132,9 +148,13 @@ def setUpClass(cls): def _make_layer(self, layer_wkb_name): fields = QgsFields() wkb_type = getattr(QgsWkbTypes, layer_wkb_name) - fields.append(QgsField('int_f', QVariant.Int)) + fields.append(QgsField("int_f", QVariant.Int)) layer = QgsMemoryProviderUtils.createMemoryLayer( - f'{layer_wkb_name}_layer', fields, wkb_type, QgsCoordinateReferenceSystem('EPSG:4326')) + f"{layer_wkb_name}_layer", + fields, + wkb_type, + QgsCoordinateReferenceSystem("EPSG:4326"), + ) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), wkb_type) return layer @@ -145,67 +165,108 @@ def _support_inplace_edit_tester(self, alg_name, expected): for layer_wkb_name, supported in expected.items(): layer = self._make_layer(layer_wkb_name) # print("Checking %s ( %s ) : %s" % (alg_name, layer_wkb_name, supported)) - self.assertEqual(alg.supportInPlaceEdit(layer), supported, - f"Expected: {alg_name} - {layer_wkb_name} = supported: {supported}") + self.assertEqual( + alg.supportInPlaceEdit(layer), + supported, + f"Expected: {alg_name} - {layer_wkb_name} = supported: {supported}", + ) def test_support_in_place_edit(self): ALL = _all_true() - GEOMETRY_ONLY = {t: t != 'NoGeometry' for t in _all_true().keys()} + GEOMETRY_ONLY = {t: t != "NoGeometry" for t in _all_true().keys()} NONE = _all_false() - LINESTRING_ONLY = {t: t.find('LineString') >= 0 for t in _all_true().keys()} - Z_ONLY = {t: t.find('Z') > 0 for t in _all_true().keys()} - M_ONLY = {t: t.rfind('M') > 0 for t in _all_true().keys()} - NOT_M = {t: t.rfind('M') < 1 and t != 'NoGeometry' for t in _all_true().keys()} - POLYGON_ONLY = {t: t.find('Polygon') for t in _all_true().keys()} - POLYGON_ONLY_NOT_M_NOT_Z = {t: t in ('Polygon', 'MultiPolygon') for t in _all_true().keys()} - MULTI_ONLY = {t: t.find('Multi') == 0 for t in _all_true().keys()} - SINGLE_ONLY = {t: t.find('Multi') == -1 for t in _all_true().keys()} - LINESTRING_AND_POLYGON_ONLY = {t: (t.find('LineString') >= 0 or t.find('Polygon') >= 0) for t in - _all_true().keys()} + LINESTRING_ONLY = {t: t.find("LineString") >= 0 for t in _all_true().keys()} + Z_ONLY = {t: t.find("Z") > 0 for t in _all_true().keys()} + M_ONLY = {t: t.rfind("M") > 0 for t in _all_true().keys()} + NOT_M = {t: t.rfind("M") < 1 and t != "NoGeometry" for t in _all_true().keys()} + POLYGON_ONLY = {t: t.find("Polygon") for t in _all_true().keys()} + POLYGON_ONLY_NOT_M_NOT_Z = { + t: t in ("Polygon", "MultiPolygon") for t in _all_true().keys() + } + MULTI_ONLY = {t: t.find("Multi") == 0 for t in _all_true().keys()} + SINGLE_ONLY = {t: t.find("Multi") == -1 for t in _all_true().keys()} + LINESTRING_AND_POLYGON_ONLY = { + t: (t.find("LineString") >= 0 or t.find("Polygon") >= 0) + for t in _all_true().keys() + } LINESTRING_AND_POLYGON_ONLY_NOT_M = { - t: (t.rfind('M') < 1 and (t.find('LineString') >= 0 or t.find('Polygon') >= 0)) for t in _all_true().keys()} + t: ( + t.rfind("M") < 1 + and (t.find("LineString") >= 0 or t.find("Polygon") >= 0) + ) + for t in _all_true().keys() + } LINESTRING_AND_POLYGON_ONLY_NOT_M_NOT_Z = { - t: (t.rfind('M') < 1 and t.find('Z') == -1 and (t.find('LineString') >= 0 or t.find('Polygon') >= 0)) for t - in _all_true().keys()} - - self._support_inplace_edit_tester('native:smoothgeometry', LINESTRING_AND_POLYGON_ONLY) - self._support_inplace_edit_tester('native:arrayoffsetlines', LINESTRING_ONLY) - self._support_inplace_edit_tester('native:arraytranslatedfeatures', GEOMETRY_ONLY) - self._support_inplace_edit_tester('native:reprojectlayer', GEOMETRY_ONLY) - self._support_inplace_edit_tester('qgis:densifygeometries', LINESTRING_AND_POLYGON_ONLY) - self._support_inplace_edit_tester('qgis:densifygeometriesgivenaninterval', LINESTRING_AND_POLYGON_ONLY) - self._support_inplace_edit_tester('native:setzfromraster', Z_ONLY) - self._support_inplace_edit_tester('native:explodelines', LINESTRING_ONLY) - self._support_inplace_edit_tester('native:extendlines', LINESTRING_ONLY) - self._support_inplace_edit_tester('native:fixgeometries', NOT_M) - self._support_inplace_edit_tester('native:minimumenclosingcircle', POLYGON_ONLY_NOT_M_NOT_Z) - self._support_inplace_edit_tester('native:multiringconstantbuffer', POLYGON_ONLY_NOT_M_NOT_Z) - self._support_inplace_edit_tester('native:orientedminimumboundingbox', POLYGON_ONLY_NOT_M_NOT_Z) - self._support_inplace_edit_tester('qgis:orthogonalize', LINESTRING_AND_POLYGON_ONLY) - self._support_inplace_edit_tester('native:removeduplicatevertices', GEOMETRY_ONLY) - self._support_inplace_edit_tester('native:rotatefeatures', GEOMETRY_ONLY) - self._support_inplace_edit_tester('native:segmentizebymaxangle', NONE) - self._support_inplace_edit_tester('native:segmentizebymaxdistance', NONE) - self._support_inplace_edit_tester('native:setmfromraster', M_ONLY) - self._support_inplace_edit_tester('native:simplifygeometries', LINESTRING_AND_POLYGON_ONLY) - self._support_inplace_edit_tester('native:snappointstogrid', GEOMETRY_ONLY) - self._support_inplace_edit_tester('native:multiparttosingleparts', GEOMETRY_ONLY) - self._support_inplace_edit_tester('native:promotetomulti', MULTI_ONLY) - self._support_inplace_edit_tester('native:subdivide', GEOMETRY_ONLY) - self._support_inplace_edit_tester('native:translategeometry', GEOMETRY_ONLY) - self._support_inplace_edit_tester('native:swapxy', GEOMETRY_ONLY) - self._support_inplace_edit_tester('qgis:linestopolygons', NONE) - self._support_inplace_edit_tester('qgis:polygonstolines', NONE) - self._support_inplace_edit_tester('native:boundary', NONE) - self._support_inplace_edit_tester('native:clip', GEOMETRY_ONLY) - self._support_inplace_edit_tester('native:difference', GEOMETRY_ONLY) - self._support_inplace_edit_tester('native:dropgeometries', ALL) - self._support_inplace_edit_tester('native:splitwithlines', LINESTRING_AND_POLYGON_ONLY) - self._support_inplace_edit_tester('native:splitlinesbylength', LINESTRING_ONLY) - self._support_inplace_edit_tester('native:buffer', POLYGON_ONLY_NOT_M_NOT_Z) - self._support_inplace_edit_tester('native:antimeridiansplit', LINESTRING_ONLY) - self._support_inplace_edit_tester('native:affinetransform', GEOMETRY_ONLY) + t: ( + t.rfind("M") < 1 + and t.find("Z") == -1 + and (t.find("LineString") >= 0 or t.find("Polygon") >= 0) + ) + for t in _all_true().keys() + } + + self._support_inplace_edit_tester( + "native:smoothgeometry", LINESTRING_AND_POLYGON_ONLY + ) + self._support_inplace_edit_tester("native:arrayoffsetlines", LINESTRING_ONLY) + self._support_inplace_edit_tester( + "native:arraytranslatedfeatures", GEOMETRY_ONLY + ) + self._support_inplace_edit_tester("native:reprojectlayer", GEOMETRY_ONLY) + self._support_inplace_edit_tester( + "qgis:densifygeometries", LINESTRING_AND_POLYGON_ONLY + ) + self._support_inplace_edit_tester( + "qgis:densifygeometriesgivenaninterval", LINESTRING_AND_POLYGON_ONLY + ) + self._support_inplace_edit_tester("native:setzfromraster", Z_ONLY) + self._support_inplace_edit_tester("native:explodelines", LINESTRING_ONLY) + self._support_inplace_edit_tester("native:extendlines", LINESTRING_ONLY) + self._support_inplace_edit_tester("native:fixgeometries", NOT_M) + self._support_inplace_edit_tester( + "native:minimumenclosingcircle", POLYGON_ONLY_NOT_M_NOT_Z + ) + self._support_inplace_edit_tester( + "native:multiringconstantbuffer", POLYGON_ONLY_NOT_M_NOT_Z + ) + self._support_inplace_edit_tester( + "native:orientedminimumboundingbox", POLYGON_ONLY_NOT_M_NOT_Z + ) + self._support_inplace_edit_tester( + "qgis:orthogonalize", LINESTRING_AND_POLYGON_ONLY + ) + self._support_inplace_edit_tester( + "native:removeduplicatevertices", GEOMETRY_ONLY + ) + self._support_inplace_edit_tester("native:rotatefeatures", GEOMETRY_ONLY) + self._support_inplace_edit_tester("native:segmentizebymaxangle", NONE) + self._support_inplace_edit_tester("native:segmentizebymaxdistance", NONE) + self._support_inplace_edit_tester("native:setmfromraster", M_ONLY) + self._support_inplace_edit_tester( + "native:simplifygeometries", LINESTRING_AND_POLYGON_ONLY + ) + self._support_inplace_edit_tester("native:snappointstogrid", GEOMETRY_ONLY) + self._support_inplace_edit_tester( + "native:multiparttosingleparts", GEOMETRY_ONLY + ) + self._support_inplace_edit_tester("native:promotetomulti", MULTI_ONLY) + self._support_inplace_edit_tester("native:subdivide", GEOMETRY_ONLY) + self._support_inplace_edit_tester("native:translategeometry", GEOMETRY_ONLY) + self._support_inplace_edit_tester("native:swapxy", GEOMETRY_ONLY) + self._support_inplace_edit_tester("qgis:linestopolygons", NONE) + self._support_inplace_edit_tester("qgis:polygonstolines", NONE) + self._support_inplace_edit_tester("native:boundary", NONE) + self._support_inplace_edit_tester("native:clip", GEOMETRY_ONLY) + self._support_inplace_edit_tester("native:difference", GEOMETRY_ONLY) + self._support_inplace_edit_tester("native:dropgeometries", ALL) + self._support_inplace_edit_tester( + "native:splitwithlines", LINESTRING_AND_POLYGON_ONLY + ) + self._support_inplace_edit_tester("native:splitlinesbylength", LINESTRING_ONLY) + self._support_inplace_edit_tester("native:buffer", POLYGON_ONLY_NOT_M_NOT_Z) + self._support_inplace_edit_tester("native:antimeridiansplit", LINESTRING_ONLY) + self._support_inplace_edit_tester("native:affinetransform", GEOMETRY_ONLY) def _make_compatible_tester(self, feature_wkt, layer_wkb_name, attrs=[1]): layer = self._make_layer(layer_wkb_name) @@ -225,196 +286,286 @@ def _make_compatible_tester(self, feature_wkt, layer_wkb_name, attrs=[1]): for new_f in new_features: self.assertEqual(new_f.geometry().wkbType(), layer.wkbType()) - self.assertTrue(layer.addFeatures(new_features), f"Fail: {feature_wkt} - {attrs} - {layer_wkb_name}") + self.assertTrue( + layer.addFeatures(new_features), + f"Fail: {feature_wkt} - {attrs} - {layer_wkb_name}", + ) return layer, new_features def test_QgsVectorLayerUtilsmakeFeaturesCompatible(self): """Test fixer function""" # Test failure - self._make_compatible_tester('LineString (1 1, 2 2, 3 3)', 'Point') - self._make_compatible_tester('LineString (1 1, 2 2, 3 3)', 'Polygon') - self._make_compatible_tester('Polygon((1 1, 2 2, 1 2, 1 1))', 'Point') - self._make_compatible_tester('Polygon((1 1, 2 2, 1 2, 1 1))', 'LineString') + self._make_compatible_tester("LineString (1 1, 2 2, 3 3)", "Point") + self._make_compatible_tester("LineString (1 1, 2 2, 3 3)", "Polygon") + self._make_compatible_tester("Polygon((1 1, 2 2, 1 2, 1 1))", "Point") + self._make_compatible_tester("Polygon((1 1, 2 2, 1 2, 1 1))", "LineString") - self._make_compatible_tester('Point(1 1)', 'Point') - self._make_compatible_tester('Point(1 1)', 'Point', [1, 'nope']) - self._make_compatible_tester('Point z (1 1 3)', 'Point') - self._make_compatible_tester('Point z (1 1 3)', 'PointZ') + self._make_compatible_tester("Point(1 1)", "Point") + self._make_compatible_tester("Point(1 1)", "Point", [1, "nope"]) + self._make_compatible_tester("Point z (1 1 3)", "Point") + self._make_compatible_tester("Point z (1 1 3)", "PointZ") # Adding Z back - l, f = self._make_compatible_tester('Point (1 1)', 'PointZ') + l, f = self._make_compatible_tester("Point (1 1)", "PointZ") self.assertEqual(f[0].geometry().constGet().z(), 0) # Adding M back - l, f = self._make_compatible_tester('Point (1 1)', 'PointM') + l, f = self._make_compatible_tester("Point (1 1)", "PointM") self.assertEqual(f[0].geometry().constGet().m(), 0) - self._make_compatible_tester('Point m (1 1 3)', 'Point') - self._make_compatible_tester('Point(1 3)', 'MultiPoint') - self._make_compatible_tester('MultiPoint((1 3), (2 2))', 'MultiPoint') + self._make_compatible_tester("Point m (1 1 3)", "Point") + self._make_compatible_tester("Point(1 3)", "MultiPoint") + self._make_compatible_tester("MultiPoint((1 3), (2 2))", "MultiPoint") - self._make_compatible_tester('Polygon((1 1, 2 2, 3 3, 1 1))', 'Polygon') - self._make_compatible_tester('Polygon((1 1, 2 2, 3 3, 1 1))', 'Polygon', [1, 'nope']) - self._make_compatible_tester('Polygon z ((1 1 1, 2 2 2, 3 3 3, 1 1 1))', 'Polygon') - self._make_compatible_tester('Polygon z ((1 1 1, 2 2 2, 3 3 3, 1 1 1))', 'PolygonZ') + self._make_compatible_tester("Polygon((1 1, 2 2, 3 3, 1 1))", "Polygon") + self._make_compatible_tester( + "Polygon((1 1, 2 2, 3 3, 1 1))", "Polygon", [1, "nope"] + ) + self._make_compatible_tester( + "Polygon z ((1 1 1, 2 2 2, 3 3 3, 1 1 1))", "Polygon" + ) + self._make_compatible_tester( + "Polygon z ((1 1 1, 2 2 2, 3 3 3, 1 1 1))", "PolygonZ" + ) # Adding Z back - l, f = self._make_compatible_tester('Polygon ((1 1, 2 2, 3 3, 1 1))', 'PolygonZ') + l, f = self._make_compatible_tester( + "Polygon ((1 1, 2 2, 3 3, 1 1))", "PolygonZ" + ) g = f[0].geometry() g2 = g.constGet() for v in g2.vertices(): self.assertEqual(v.z(), 0) # Adding M back - l, f = self._make_compatible_tester('Polygon ((1 1, 2 2, 3 3, 1 1))', 'PolygonM') + l, f = self._make_compatible_tester( + "Polygon ((1 1, 2 2, 3 3, 1 1))", "PolygonM" + ) g = f[0].geometry() g2 = g.constGet() for v in g2.vertices(): self.assertEqual(v.m(), 0) - self._make_compatible_tester('Polygon m ((1 1 1, 2 2 2, 3 3 3, 1 1 1))', 'Polygon') - self._make_compatible_tester('Polygon m ((1 1 1, 2 2 2, 3 3 3, 1 1 1))', 'PolygonM') - self._make_compatible_tester('Polygon((1 1, 2 2, 3 3, 1 1))', 'MultiPolygon') - self._make_compatible_tester('MultiPolygon(((1 1, 2 2, 3 3, 1 1)), ((1 1, 2 2, 3 3, 1 1)))', 'MultiPolygon') + self._make_compatible_tester( + "Polygon m ((1 1 1, 2 2 2, 3 3 3, 1 1 1))", "Polygon" + ) + self._make_compatible_tester( + "Polygon m ((1 1 1, 2 2 2, 3 3 3, 1 1 1))", "PolygonM" + ) + self._make_compatible_tester("Polygon((1 1, 2 2, 3 3, 1 1))", "MultiPolygon") + self._make_compatible_tester( + "MultiPolygon(((1 1, 2 2, 3 3, 1 1)), ((1 1, 2 2, 3 3, 1 1)))", + "MultiPolygon", + ) - self._make_compatible_tester('LineString(1 1, 2 2, 3 3, 1 1)', 'LineString') - self._make_compatible_tester('LineString(1 1, 2 2, 3 3, 1 1)', 'LineString', [1, 'nope']) - self._make_compatible_tester('LineString z (1 1 1, 2 2 2, 3 3 3, 1 1 1)', 'LineString') - self._make_compatible_tester('LineString z (1 1 1, 2 2 2, 3 3 3, 1 1 1)', 'LineStringZ') - self._make_compatible_tester('LineString m (1 1 1, 2 2 2, 3 3 3, 1 1 1)', 'LineString') - self._make_compatible_tester('LineString m (1 1 1, 2 2 2, 3 3 3, 1 1 1)', 'LineStringM') + self._make_compatible_tester("LineString(1 1, 2 2, 3 3, 1 1)", "LineString") + self._make_compatible_tester( + "LineString(1 1, 2 2, 3 3, 1 1)", "LineString", [1, "nope"] + ) + self._make_compatible_tester( + "LineString z (1 1 1, 2 2 2, 3 3 3, 1 1 1)", "LineString" + ) + self._make_compatible_tester( + "LineString z (1 1 1, 2 2 2, 3 3 3, 1 1 1)", "LineStringZ" + ) + self._make_compatible_tester( + "LineString m (1 1 1, 2 2 2, 3 3 3, 1 1 1)", "LineString" + ) + self._make_compatible_tester( + "LineString m (1 1 1, 2 2 2, 3 3 3, 1 1 1)", "LineStringM" + ) # Adding Z back - l, f = self._make_compatible_tester('LineString (1 1, 2 2, 3 3, 1 1)', 'LineStringZ') + l, f = self._make_compatible_tester( + "LineString (1 1, 2 2, 3 3, 1 1)", "LineStringZ" + ) g = f[0].geometry() g2 = g.constGet() for v in g2.vertices(): self.assertEqual(v.z(), 0) # Adding M back - l, f = self._make_compatible_tester('LineString (1 1, 2 2, 3 3, 1 1)', 'LineStringM') + l, f = self._make_compatible_tester( + "LineString (1 1, 2 2, 3 3, 1 1)", "LineStringM" + ) g = f[0].geometry() g2 = g.constGet() for v in g2.vertices(): self.assertEqual(v.m(), 0) - self._make_compatible_tester('LineString(1 1, 2 2, 3 3, 1 1)', 'MultiLineString') - self._make_compatible_tester('MultiLineString((1 1, 2 2, 3 3, 1 1), (1 1, 2 2, 3 3, 1 1))', 'MultiLineString') + self._make_compatible_tester( + "LineString(1 1, 2 2, 3 3, 1 1)", "MultiLineString" + ) + self._make_compatible_tester( + "MultiLineString((1 1, 2 2, 3 3, 1 1), (1 1, 2 2, 3 3, 1 1))", + "MultiLineString", + ) # Test Multi -> Single - l, f = self._make_compatible_tester('MultiLineString((1 1, 2 2, 3 3, 1 1), (10 1, 20 2, 30 3, 10 1))', - 'LineString') + l, f = self._make_compatible_tester( + "MultiLineString((1 1, 2 2, 3 3, 1 1), (10 1, 20 2, 30 3, 10 1))", + "LineString", + ) self.assertEqual(len(f), 2) - self.assertEqual(f[0].geometry().asWkt(), 'LineString (1 1, 2 2, 3 3, 1 1)') - self.assertEqual(f[1].geometry().asWkt(), 'LineString (10 1, 20 2, 30 3, 10 1)') + self.assertEqual(f[0].geometry().asWkt(), "LineString (1 1, 2 2, 3 3, 1 1)") + self.assertEqual(f[1].geometry().asWkt(), "LineString (10 1, 20 2, 30 3, 10 1)") # line -> points - l, f = self._make_compatible_tester('LineString (1 1, 2 2, 3 3)', 'Point') + l, f = self._make_compatible_tester("LineString (1 1, 2 2, 3 3)", "Point") self.assertEqual(len(f), 3) - self.assertEqual(f[0].geometry().asWkt(), 'Point (1 1)') - self.assertEqual(f[1].geometry().asWkt(), 'Point (2 2)') - self.assertEqual(f[2].geometry().asWkt(), 'Point (3 3)') + self.assertEqual(f[0].geometry().asWkt(), "Point (1 1)") + self.assertEqual(f[1].geometry().asWkt(), "Point (2 2)") + self.assertEqual(f[2].geometry().asWkt(), "Point (3 3)") - l, f = self._make_compatible_tester('LineString (1 1, 2 2, 3 3)', 'MultiPoint') + l, f = self._make_compatible_tester("LineString (1 1, 2 2, 3 3)", "MultiPoint") self.assertEqual(len(f), 1) - self.assertEqual(f[0].geometry().asWkt(), 'MultiPoint ((1 1),(2 2),(3 3))') + self.assertEqual(f[0].geometry().asWkt(), "MultiPoint ((1 1),(2 2),(3 3))") - l, f = self._make_compatible_tester('MultiLineString ((1 1, 2 2),(4 4, 3 3))', 'Point') + l, f = self._make_compatible_tester( + "MultiLineString ((1 1, 2 2),(4 4, 3 3))", "Point" + ) self.assertEqual(len(f), 4) - self.assertEqual(f[0].geometry().asWkt(), 'Point (1 1)') - self.assertEqual(f[1].geometry().asWkt(), 'Point (2 2)') - self.assertEqual(f[2].geometry().asWkt(), 'Point (4 4)') - self.assertEqual(f[3].geometry().asWkt(), 'Point (3 3)') + self.assertEqual(f[0].geometry().asWkt(), "Point (1 1)") + self.assertEqual(f[1].geometry().asWkt(), "Point (2 2)") + self.assertEqual(f[2].geometry().asWkt(), "Point (4 4)") + self.assertEqual(f[3].geometry().asWkt(), "Point (3 3)") - l, f = self._make_compatible_tester('MultiLineString ((1 1, 2 2),(4 4, 3 3))', 'MultiPoint') + l, f = self._make_compatible_tester( + "MultiLineString ((1 1, 2 2),(4 4, 3 3))", "MultiPoint" + ) self.assertEqual(len(f), 1) - self.assertEqual(f[0].geometry().asWkt(), 'MultiPoint ((1 1),(2 2),(4 4),(3 3))') + self.assertEqual( + f[0].geometry().asWkt(), "MultiPoint ((1 1),(2 2),(4 4),(3 3))" + ) # line -> polygon - l, f = self._make_compatible_tester('LineString (1 1, 1 2, 2 2)', 'Polygon') + l, f = self._make_compatible_tester("LineString (1 1, 1 2, 2 2)", "Polygon") self.assertEqual(len(f), 1) - self.assertEqual(f[0].geometry().asWkt(), 'Polygon ((1 1, 1 2, 2 2, 1 1))') + self.assertEqual(f[0].geometry().asWkt(), "Polygon ((1 1, 1 2, 2 2, 1 1))") - l, f = self._make_compatible_tester('LineString (1 1, 1 2, 2 2)', 'MultiPolygon') + l, f = self._make_compatible_tester( + "LineString (1 1, 1 2, 2 2)", "MultiPolygon" + ) self.assertEqual(len(f), 1) - self.assertEqual(f[0].geometry().asWkt(), 'MultiPolygon (((1 1, 1 2, 2 2, 1 1)))') + self.assertEqual( + f[0].geometry().asWkt(), "MultiPolygon (((1 1, 1 2, 2 2, 1 1)))" + ) - l, f = self._make_compatible_tester('MultiLineString ((1 1, 1 2, 2 2, 1 1),(3 3, 4 3, 4 4))', 'Polygon') + l, f = self._make_compatible_tester( + "MultiLineString ((1 1, 1 2, 2 2, 1 1),(3 3, 4 3, 4 4))", "Polygon" + ) self.assertEqual(len(f), 2) - self.assertEqual(f[0].geometry().asWkt(), 'Polygon ((1 1, 1 2, 2 2, 1 1))') - self.assertEqual(f[1].geometry().asWkt(), 'Polygon ((3 3, 4 3, 4 4, 3 3))') + self.assertEqual(f[0].geometry().asWkt(), "Polygon ((1 1, 1 2, 2 2, 1 1))") + self.assertEqual(f[1].geometry().asWkt(), "Polygon ((3 3, 4 3, 4 4, 3 3))") - l, f = self._make_compatible_tester('MultiLineString ((1 1, 1 2, 2 2, 1 1),(3 3, 4 3, 4 4))', 'MultiPolygon') + l, f = self._make_compatible_tester( + "MultiLineString ((1 1, 1 2, 2 2, 1 1),(3 3, 4 3, 4 4))", "MultiPolygon" + ) self.assertEqual(len(f), 1) - self.assertEqual(f[0].geometry().asWkt(), 'MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))') + self.assertEqual( + f[0].geometry().asWkt(), + "MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))", + ) - l, f = self._make_compatible_tester('CircularString (1 1, 1 2, 2 2, 2 0, 1 1)', 'CurvePolygon') + l, f = self._make_compatible_tester( + "CircularString (1 1, 1 2, 2 2, 2 0, 1 1)", "CurvePolygon" + ) self.assertEqual(len(f), 1) - self.assertEqual(f[0].geometry().asWkt(), 'CurvePolygon (CircularString (1 1, 1 2, 2 2, 2 0, 1 1))') + self.assertEqual( + f[0].geometry().asWkt(), + "CurvePolygon (CircularString (1 1, 1 2, 2 2, 2 0, 1 1))", + ) - l, f = self._make_compatible_tester('CircularString (1 1, 1 2, 2 2, 2 0, 1 1)', 'Polygon') + l, f = self._make_compatible_tester( + "CircularString (1 1, 1 2, 2 2, 2 0, 1 1)", "Polygon" + ) self.assertEqual(len(f), 1) - self.assertTrue(f[0].geometry().asWkt(2).startswith('Polygon ((1 1, 0.99 1.01, 0.98 1.02')) + self.assertTrue( + f[0].geometry().asWkt(2).startswith("Polygon ((1 1, 0.99 1.01, 0.98 1.02") + ) # polygon -> points - l, f = self._make_compatible_tester('Polygon ((1 1, 1 2, 2 2, 1 1))', 'Point') + l, f = self._make_compatible_tester("Polygon ((1 1, 1 2, 2 2, 1 1))", "Point") self.assertEqual(len(f), 3) - self.assertEqual(f[0].geometry().asWkt(), 'Point (1 1)') - self.assertEqual(f[1].geometry().asWkt(), 'Point (1 2)') - self.assertEqual(f[2].geometry().asWkt(), 'Point (2 2)') + self.assertEqual(f[0].geometry().asWkt(), "Point (1 1)") + self.assertEqual(f[1].geometry().asWkt(), "Point (1 2)") + self.assertEqual(f[2].geometry().asWkt(), "Point (2 2)") - l, f = self._make_compatible_tester('Polygon ((1 1, 1 2, 2 2, 1 1))', 'MultiPoint') + l, f = self._make_compatible_tester( + "Polygon ((1 1, 1 2, 2 2, 1 1))", "MultiPoint" + ) self.assertEqual(len(f), 1) - self.assertEqual(f[0].geometry().asWkt(), 'MultiPoint ((1 1),(1 2),(2 2))') + self.assertEqual(f[0].geometry().asWkt(), "MultiPoint ((1 1),(1 2),(2 2))") - l, f = self._make_compatible_tester('MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))', 'Point') + l, f = self._make_compatible_tester( + "MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))", "Point" + ) self.assertEqual(len(f), 6) - self.assertEqual(f[0].geometry().asWkt(), 'Point (1 1)') - self.assertEqual(f[1].geometry().asWkt(), 'Point (1 2)') - self.assertEqual(f[2].geometry().asWkt(), 'Point (2 2)') - self.assertEqual(f[3].geometry().asWkt(), 'Point (3 3)') - self.assertEqual(f[4].geometry().asWkt(), 'Point (4 3)') - self.assertEqual(f[5].geometry().asWkt(), 'Point (4 4)') - - l, f = self._make_compatible_tester('MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))', - 'MultiPoint') + self.assertEqual(f[0].geometry().asWkt(), "Point (1 1)") + self.assertEqual(f[1].geometry().asWkt(), "Point (1 2)") + self.assertEqual(f[2].geometry().asWkt(), "Point (2 2)") + self.assertEqual(f[3].geometry().asWkt(), "Point (3 3)") + self.assertEqual(f[4].geometry().asWkt(), "Point (4 3)") + self.assertEqual(f[5].geometry().asWkt(), "Point (4 4)") + + l, f = self._make_compatible_tester( + "MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))", "MultiPoint" + ) self.assertEqual(len(f), 1) - self.assertEqual(f[0].geometry().asWkt(), 'MultiPoint ((1 1),(1 2),(2 2),(3 3),(4 3),(4 4))') + self.assertEqual( + f[0].geometry().asWkt(), "MultiPoint ((1 1),(1 2),(2 2),(3 3),(4 3),(4 4))" + ) # polygon -> lines - l, f = self._make_compatible_tester('Polygon ((1 1, 1 2, 2 2, 1 1))', 'LineString') + l, f = self._make_compatible_tester( + "Polygon ((1 1, 1 2, 2 2, 1 1))", "LineString" + ) self.assertEqual(len(f), 1) - self.assertEqual(f[0].geometry().asWkt(), 'LineString (1 1, 1 2, 2 2, 1 1)') + self.assertEqual(f[0].geometry().asWkt(), "LineString (1 1, 1 2, 2 2, 1 1)") - l, f = self._make_compatible_tester('Polygon ((1 1, 1 2, 2 2, 1 1))', 'MultiLineString') + l, f = self._make_compatible_tester( + "Polygon ((1 1, 1 2, 2 2, 1 1))", "MultiLineString" + ) self.assertEqual(len(f), 1) - self.assertEqual(f[0].geometry().asWkt(), 'MultiLineString ((1 1, 1 2, 2 2, 1 1))') + self.assertEqual( + f[0].geometry().asWkt(), "MultiLineString ((1 1, 1 2, 2 2, 1 1))" + ) - l, f = self._make_compatible_tester('MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))', - 'LineString') + l, f = self._make_compatible_tester( + "MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))", "LineString" + ) self.assertEqual(len(f), 2) - self.assertEqual(f[0].geometry().asWkt(), 'LineString (1 1, 1 2, 2 2, 1 1)') - self.assertEqual(f[1].geometry().asWkt(), 'LineString (3 3, 4 3, 4 4, 3 3)') + self.assertEqual(f[0].geometry().asWkt(), "LineString (1 1, 1 2, 2 2, 1 1)") + self.assertEqual(f[1].geometry().asWkt(), "LineString (3 3, 4 3, 4 4, 3 3)") - l, f = self._make_compatible_tester('MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))', - 'MultiLineString') + l, f = self._make_compatible_tester( + "MultiPolygon (((1 1, 1 2, 2 2, 1 1)),((3 3, 4 3, 4 4, 3 3)))", + "MultiLineString", + ) self.assertEqual(len(f), 1) - self.assertEqual(f[0].geometry().asWkt(), 'MultiLineString ((1 1, 1 2, 2 2, 1 1),(3 3, 4 3, 4 4, 3 3))') + self.assertEqual( + f[0].geometry().asWkt(), + "MultiLineString ((1 1, 1 2, 2 2, 1 1),(3 3, 4 3, 4 4, 3 3))", + ) def test_make_features_compatible_attributes(self): """Test corner cases for attributes""" # Test feature without attributes fields = QgsFields() - fields.append(QgsField('int_f', QVariant.Int)) - fields.append(QgsField('str_f', QVariant.String)) + fields.append(QgsField("int_f", QVariant.Int)) + fields.append(QgsField("str_f", QVariant.String)) layer = QgsMemoryProviderUtils.createMemoryLayer( - 'mkfca_layer', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:4326')) + "mkfca_layer", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:4326"), + ) self.assertTrue(layer.isValid()) f1 = QgsFeature(layer.fields()) - f1['int_f'] = 1 - f1['str_f'] = 'str' - f1.setGeometry(QgsGeometry.fromWkt('Point(9 45)')) + f1["int_f"] = 1 + f1["str_f"] = "str" + f1.setGeometry(QgsGeometry.fromWkt("Point(9 45)")) new_features = QgsVectorLayerUtils.makeFeaturesCompatible([f1], layer) self.assertEqual(new_features[0].attributes(), f1.attributes()) self.assertTrue(new_features[0].geometry().asWkt(), f1.geometry().asWkt()) @@ -428,7 +579,7 @@ def test_make_features_compatible_attributes(self): # Test pad with 0 without fields f1 = QgsFeature() - f1.setGeometry(QgsGeometry.fromWkt('Point(9 45)')) + f1.setGeometry(QgsGeometry.fromWkt("Point(9 45)")) new_features = QgsVectorLayerUtils.makeFeaturesCompatible([f1], layer) self.assertEqual(len(new_features[0].attributes()), 2) self.assertEqual(new_features[0].attributes()[0], NULL) @@ -436,30 +587,34 @@ def test_make_features_compatible_attributes(self): # Test drop extra attrs f1 = QgsFeature(layer.fields()) - f1.setAttributes([1, 'foo', 'extra']) - f1.setGeometry(QgsGeometry.fromWkt('Point(9 45)')) + f1.setAttributes([1, "foo", "extra"]) + f1.setGeometry(QgsGeometry.fromWkt("Point(9 45)")) new_features = QgsVectorLayerUtils.makeFeaturesCompatible([f1], layer) self.assertEqual(len(new_features[0].attributes()), 2) self.assertEqual(new_features[0].attributes()[0], 1) - self.assertEqual(new_features[0].attributes()[1], 'foo') + self.assertEqual(new_features[0].attributes()[1], "foo") def test_make_features_compatible_different_field_length(self): """Test regression #21497""" fields = QgsFields() - fields.append(QgsField('int_f1', QVariant.Int)) + fields.append(QgsField("int_f1", QVariant.Int)) f1 = QgsFeature(fields) f1.setAttributes([12345]) - f1.setGeometry(QgsGeometry.fromWkt('Point(9 45)')) + f1.setGeometry(QgsGeometry.fromWkt("Point(9 45)")) fields = QgsFields() - fields.append(QgsField('int_f2', QVariant.Int)) - fields.append(QgsField('int_f1', QVariant.Int)) + fields.append(QgsField("int_f2", QVariant.Int)) + fields.append(QgsField("int_f1", QVariant.Int)) vl2 = QgsMemoryProviderUtils.createMemoryLayer( - 'mymultiplayer', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:4326')) + "mymultiplayer", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:4326"), + ) new_features = QgsVectorLayerUtils.makeFeaturesCompatible([f1], vl2) self.assertEqual(new_features[0].attributes(), [None, 12345]) - f1.setGeometry(QgsGeometry.fromWkt('MultiPoint((9 45))')) + f1.setGeometry(QgsGeometry.fromWkt("MultiPoint((9 45))")) new_features = QgsVectorLayerUtils.makeFeaturesCompatible([f1], vl2) self.assertEqual(new_features[0].attributes(), [None, 12345]) @@ -467,7 +622,7 @@ def test_make_features_compatible_geometry(self): """Test corner cases for geometries""" # Make a feature with no geometry - layer = self._make_layer('Point') + layer = self._make_layer("Point") self.assertTrue(layer.isValid()) self.assertTrue(layer.startEditing()) f1 = QgsFeature(layer.fields()) @@ -476,39 +631,56 @@ def test_make_features_compatible_geometry(self): # Check that it is accepted on a Point layer new_features = QgsVectorLayerUtils.makeFeaturesCompatible([f1], layer) self.assertEqual(len(new_features), 1) - self.assertEqual(new_features[0].geometry().asWkt(), '') + self.assertEqual(new_features[0].geometry().asWkt(), "") # Make a geometry-less layer nogeom_layer = QgsMemoryProviderUtils.createMemoryLayer( - 'nogeom_layer', layer.fields(), QgsWkbTypes.Type.NoGeometry, QgsCoordinateReferenceSystem('EPSG:4326')) + "nogeom_layer", + layer.fields(), + QgsWkbTypes.Type.NoGeometry, + QgsCoordinateReferenceSystem("EPSG:4326"), + ) # Check that a geometry-less feature is accepted new_features = QgsVectorLayerUtils.makeFeaturesCompatible([f1], nogeom_layer) self.assertEqual(len(new_features), 1) - self.assertEqual(new_features[0].geometry().asWkt(), '') + self.assertEqual(new_features[0].geometry().asWkt(), "") # Make a geometry-less layer nogeom_layer = QgsMemoryProviderUtils.createMemoryLayer( - 'nogeom_layer', layer.fields(), QgsWkbTypes.Type.NoGeometry, QgsCoordinateReferenceSystem('EPSG:4326')) + "nogeom_layer", + layer.fields(), + QgsWkbTypes.Type.NoGeometry, + QgsCoordinateReferenceSystem("EPSG:4326"), + ) # Check that a Point feature is accepted but geometry was dropped - f1.setGeometry(QgsGeometry.fromWkt('Point(9 45)')) + f1.setGeometry(QgsGeometry.fromWkt("Point(9 45)")) new_features = QgsVectorLayerUtils.makeFeaturesCompatible([f1], nogeom_layer) self.assertEqual(len(new_features), 1) - self.assertEqual(new_features[0].geometry().asWkt(), '') + self.assertEqual(new_features[0].geometry().asWkt(), "") - def _alg_tester(self, alg_name, input_layer, parameters, invalid_geometry_policy=QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck, retain_selection=False): + def _alg_tester( + self, + alg_name, + input_layer, + parameters, + invalid_geometry_policy=QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck, + retain_selection=False, + ): alg = self.registry.createAlgorithmById(alg_name) self.assertIsNotNone(alg) - parameters['INPUT'] = input_layer - parameters['OUTPUT'] = 'memory:' + parameters["INPUT"] = input_layer + parameters["OUTPUT"] = "memory:" old_features = [f for f in input_layer.getFeatures()] if not retain_selection: input_layer.selectByIds([old_features[0].id()]) # Check selected - self.assertEqual(input_layer.selectedFeatureIds(), [old_features[0].id()], alg_name) + self.assertEqual( + input_layer.selectedFeatureIds(), [old_features[0].id()], alg_name + ) context = QgsProcessingContext() context.setInvalidGeometryCheck(invalid_geometry_policy) @@ -518,14 +690,17 @@ def _alg_tester(self, alg_name, input_layer, parameters, invalid_geometry_policy input_layer.rollBack() ok = False ok, _ = execute_in_place_run( - alg, parameters, context=context, feedback=feedback, raise_exceptions=True) + alg, parameters, context=context, feedback=feedback, raise_exceptions=True + ) new_features = [f for f in input_layer.getFeatures()] # Check ret values self.assertTrue(ok, alg_name) # Check geometry types (drop Z or M) - self.assertEqual(new_features[0].geometry().wkbType(), old_features[0].geometry().wkbType()) + self.assertEqual( + new_features[0].geometry().wkbType(), old_features[0].geometry().wkbType() + ) return old_features, new_features @@ -535,25 +710,37 @@ def test_execute_in_place_run(self): self.vl.rollBack() old_features, new_features = self._alg_tester( - 'native:translategeometry', + "native:translategeometry", self.vl, { - 'DELTA_X': 1.1, - 'DELTA_Y': 1.1, - } + "DELTA_X": 1.1, + "DELTA_Y": 1.1, + }, ) # First feature was selected and modified self.assertEqual(new_features[0].id(), old_features[0].id()) - self.assertAlmostEqual(new_features[0].geometry().asPoint().x(), old_features[0].geometry().asPoint().x() + 1.1, - delta=0.01) - self.assertAlmostEqual(new_features[0].geometry().asPoint().y(), old_features[0].geometry().asPoint().y() + 1.1, - delta=0.01) + self.assertAlmostEqual( + new_features[0].geometry().asPoint().x(), + old_features[0].geometry().asPoint().x() + 1.1, + delta=0.01, + ) + self.assertAlmostEqual( + new_features[0].geometry().asPoint().y(), + old_features[0].geometry().asPoint().y() + 1.1, + delta=0.01, + ) # Second feature was not selected and not modified self.assertEqual(new_features[1].id(), old_features[1].id()) - self.assertEqual(new_features[1].geometry().asPoint().x(), old_features[1].geometry().asPoint().x()) - self.assertEqual(new_features[1].geometry().asPoint().y(), old_features[1].geometry().asPoint().y()) + self.assertEqual( + new_features[1].geometry().asPoint().x(), + old_features[1].geometry().asPoint().x(), + ) + self.assertEqual( + new_features[1].geometry().asPoint().y(), + old_features[1].geometry().asPoint().y(), + ) # Check selected self.assertEqual(self.vl.selectedFeatureIds(), [old_features[0].id()]) @@ -561,32 +748,32 @@ def test_execute_in_place_run(self): # Check that if the only change is Z or M then we should fail with self.assertRaises(QgsProcessingException) as cm: self._alg_tester( - 'native:translategeometry', + "native:translategeometry", self.vl, { - 'DELTA_Z': 1.1, - } + "DELTA_Z": 1.1, + }, ) self.vl.rollBack() # Check that if the only change is Z or M then we should fail with self.assertRaises(QgsProcessingException) as cm: self._alg_tester( - 'native:translategeometry', + "native:translategeometry", self.vl, { - 'DELTA_M': 1.1, - } + "DELTA_M": 1.1, + }, ) self.vl.rollBack() old_features, new_features = self._alg_tester( - 'native:translategeometry', + "native:translategeometry", self.vl, { - 'DELTA_X': 1.1, - 'DELTA_Z': 1.1, - } + "DELTA_X": 1.1, + "DELTA_Z": 1.1, + }, ) def test_select_all_features(self): @@ -600,21 +787,22 @@ def test_select_all_features(self): context.setProject(QgsProject.instance()) feedback = ConsoleFeedBack() - alg = self.registry.createAlgorithmById('native:translategeometry') + alg = self.registry.createAlgorithmById("native:translategeometry") self.assertIsNotNone(alg) parameters = { - 'DELTA_X': 1.1, - 'DELTA_Y': 1.1, + "DELTA_X": 1.1, + "DELTA_Y": 1.1, } - parameters['INPUT'] = self.vl - parameters['OUTPUT'] = 'memory:' + parameters["INPUT"] = self.vl + parameters["OUTPUT"] = "memory:" old_features = [f for f in self.vl.getFeatures()] ok, _ = execute_in_place_run( - alg, parameters, context=context, feedback=feedback, raise_exceptions=True) + alg, parameters, context=context, feedback=feedback, raise_exceptions=True + ) new_features = [f for f in self.vl.getFeatures()] self.assertEqual(len(new_features), old_count) @@ -626,10 +814,7 @@ def test_multi_to_single(self): """Check that the geometry type is still multi after the alg is run""" old_features, new_features = self._alg_tester( - 'native:multiparttosingleparts', - self.multipoly_vl, - { - } + "native:multiparttosingleparts", self.multipoly_vl, {} ) self.assertEqual(len(new_features), 3) @@ -643,13 +828,13 @@ def test_arraytranslatedfeatures(self): old_count = self.vl.featureCount() old_features, new_features = self._alg_tester( - 'native:arraytranslatedfeatures', + "native:arraytranslatedfeatures", self.vl, { - 'COUNT': 2, - 'DELTA_X': 1.1, - 'DELTA_Z': 1.1, - } + "COUNT": 2, + "DELTA_X": 1.1, + "DELTA_Z": 1.1, + }, ) self.assertEqual(len(new_features), old_count + 2) @@ -663,11 +848,11 @@ def test_reprojectlayer(self): old_count = self.vl.featureCount() old_features, new_features = self._alg_tester( - 'native:reprojectlayer', + "native:reprojectlayer", self.vl, { - 'TARGET_CRS': 'EPSG:3857', - } + "TARGET_CRS": "EPSG:3857", + }, ) g = [f.geometry() for f in new_features][0] @@ -680,13 +865,21 @@ def test_reprojectlayer(self): def test_snappointstogrid(self): """Check that this runs correctly""" - polygon_layer = self._make_layer('Polygon') + polygon_layer = self._make_layer("Polygon") f1 = QgsFeature(polygon_layer.fields()) f1.setAttributes([1]) - f1.setGeometry(QgsGeometry.fromWkt('POLYGON((1.2 1.2, 1.2 2.2, 2.2 2.2, 2.2 1.2, 1.2 1.2))')) + f1.setGeometry( + QgsGeometry.fromWkt( + "POLYGON((1.2 1.2, 1.2 2.2, 2.2 2.2, 2.2 1.2, 1.2 1.2))" + ) + ) f2 = QgsFeature(polygon_layer.fields()) f2.setAttributes([2]) - 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))')) + 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.startEditing()) self.assertTrue(polygon_layer.addFeatures([f1, f2])) @@ -699,44 +892,56 @@ def test_snappointstogrid(self): self.assertEqual(polygon_layer.selectedFeatureCount(), 1) old_features, new_features = self._alg_tester( - 'native:snappointstogrid', + "native:snappointstogrid", polygon_layer, { - 'HSPACING': 0.5, - 'VSPACING': 0.5, - } + "HSPACING": 0.5, + "VSPACING": 0.5, + }, ) g = [f.geometry() for f in new_features][0] - self.assertEqual(g.asWkt(), 'Polygon ((1 1, 1 2, 2 2, 2 1, 1 1))') + self.assertEqual(g.asWkt(), "Polygon ((1 1, 1 2, 2 2, 2 1, 1 1))") # Check selected self.assertEqual(polygon_layer.selectedFeatureIds(), [1]) def test_clip(self): mask_layer = QgsMemoryProviderUtils.createMemoryLayer( - 'mask_layer', self.vl.fields(), QgsWkbTypes.Type.Polygon, QgsCoordinateReferenceSystem('EPSG:4326')) + "mask_layer", + self.vl.fields(), + QgsWkbTypes.Type.Polygon, + QgsCoordinateReferenceSystem("EPSG:4326"), + ) self.assertTrue(mask_layer.isValid()) self.assertTrue(mask_layer.startEditing()) f = QgsFeature(mask_layer.fields()) f.setAttributes([1]) - f.setGeometry(QgsGeometry.fromWkt('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')) + f.setGeometry(QgsGeometry.fromWkt("POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))")) self.assertTrue(f.isValid()) f2 = QgsFeature(mask_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))')) + 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(mask_layer.addFeatures([f, f2])) mask_layer.commitChanges() mask_layer.rollBack() clip_layer = QgsMemoryProviderUtils.createMemoryLayer( - 'clip_layer', self.vl.fields(), QgsWkbTypes.Type.LineString, QgsCoordinateReferenceSystem('EPSG:4326')) + "clip_layer", + self.vl.fields(), + QgsWkbTypes.Type.LineString, + QgsCoordinateReferenceSystem("EPSG:4326"), + ) self.assertTrue(clip_layer.isValid()) self.assertTrue(clip_layer.startEditing()) f = QgsFeature(clip_layer.fields()) f.setAttributes([1]) - f.setGeometry(QgsGeometry.fromWkt('LINESTRING(-1 -1, 3 3)')) + f.setGeometry(QgsGeometry.fromWkt("LINESTRING(-1 -1, 3 3)")) self.assertTrue(f.isValid()) self.assertTrue(clip_layer.addFeatures([f])) self.assertEqual(clip_layer.featureCount(), 1) @@ -747,29 +952,33 @@ def test_clip(self): QgsProject.instance().addMapLayers([clip_layer, mask_layer]) old_features, new_features = self._alg_tester( - 'native:clip', + "native:clip", clip_layer, { - 'OVERLAY': mask_layer.id(), - } + "OVERLAY": mask_layer.id(), + }, ) self.assertEqual(len(new_features), 2) - self.assertEqual(new_features[0].geometry().asWkt(), 'LineString (0 0, 1 1)') + self.assertEqual(new_features[0].geometry().asWkt(), "LineString (0 0, 1 1)") self.assertEqual(new_features[0].attributes(), [1]) def test_fix_geometries(self): - polygon_layer = self._make_layer('Polygon') + polygon_layer = self._make_layer("Polygon") self.assertTrue(polygon_layer.startEditing()) f1 = QgsFeature(polygon_layer.fields()) f1.setAttributes([1]) # Flake! - f1.setGeometry(QgsGeometry.fromWkt('POLYGON ((0 0, 2 2, 0 2, 2 0, 0 0))')) + f1.setGeometry(QgsGeometry.fromWkt("POLYGON ((0 0, 2 2, 0 2, 2 0, 0 0))")) self.assertTrue(f1.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))')) + 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([f1, f2])) polygon_layer.commitChanges() @@ -779,27 +988,31 @@ def test_fix_geometries(self): QgsProject.instance().addMapLayers([polygon_layer]) old_features, new_features = self._alg_tester( - 'native:fixgeometries', + "native:fixgeometries", polygon_layer, - { - }, - QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid + {}, + QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid, ) self.assertEqual(polygon_layer.featureCount(), 3) geoms = [f.geometry() for f in new_features] [g.normalize() for g in geoms] wkt1, wkt2, wkt3 = (g.asWkt() for g in geoms) - self.assertEqual(wkt1, 'Polygon ((0 0, 1 1, 2 0, 0 0))') - self.assertEqual(wkt2, 'Polygon ((0 2, 2 2, 1 1, 0 2))') - self.assertEqual(re.sub(r'0000\d+', '', wkt3), 'Polygon ((1.1 1.1, 1.1 2.1, 2.1 2.1, 2.1 1.1, 1.1 1.1))') + self.assertEqual(wkt1, "Polygon ((0 0, 1 1, 2 0, 0 0))") + self.assertEqual(wkt2, "Polygon ((0 2, 2 2, 1 1, 0 2))") + self.assertEqual( + re.sub(r"0000\d+", "", wkt3), + "Polygon ((1.1 1.1, 1.1 2.1, 2.1 2.1, 2.1 1.1, 1.1 1.1))", + ) # Test with Z (interpolated) - polygonz_layer = self._make_layer('PolygonZ') + polygonz_layer = self._make_layer("PolygonZ") self.assertTrue(polygonz_layer.startEditing()) f3 = QgsFeature(polygonz_layer.fields()) f3.setAttributes([1]) - f3.setGeometry(QgsGeometry.fromWkt('POLYGON Z((0 0 1, 2 2 1, 0 2 3, 2 0 4, 0 0 1))')) + f3.setGeometry( + QgsGeometry.fromWkt("POLYGON Z((0 0 1, 2 2 1, 0 2 3, 2 0 4, 0 0 1))") + ) self.assertTrue(f3.isValid()) self.assertTrue(polygonz_layer.addFeatures([f3])) polygonz_layer.commitChanges() @@ -809,36 +1022,33 @@ def test_fix_geometries(self): QgsProject.instance().addMapLayers([polygonz_layer]) old_features, new_features = self._alg_tester( - 'native:fixgeometries', - polygonz_layer, - { - } + "native:fixgeometries", polygonz_layer, {} ) self.assertEqual(polygonz_layer.featureCount(), 2) geoms = [f.geometry() for f in new_features] [g.normalize() for g in geoms] wkt1, wkt2 = (g.asWkt() for g in geoms) - self.assertEqual(wkt1, 'Polygon Z ((0 0 1, 1 1 2.25, 2 0 4, 0 0 1))') - self.assertEqual(wkt2, 'Polygon Z ((0 2 3, 2 2 1, 1 1 2.25, 0 2 3))') + self.assertEqual(wkt1, "Polygon Z ((0 0 1, 1 1 2.25, 2 0 4, 0 0 1))") + self.assertEqual(wkt2, "Polygon Z ((0 2 3, 2 2 1, 1 1 2.25, 0 2 3))") def _test_difference_on_invalid_geometries(self, geom_option): - polygon_layer = self._make_layer('Polygon') + 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))')) + f.setGeometry(QgsGeometry.fromWkt("Polygon ((0 0, 2 2, 0 2, 2 0, 0 0))")) self.assertTrue(f.isValid()) self.assertTrue(polygon_layer.addFeatures([f])) polygon_layer.commitChanges() polygon_layer.rollBack() self.assertEqual(polygon_layer.featureCount(), 1) - overlay_layer = self._make_layer('Polygon') + overlay_layer = self._make_layer("Polygon") self.assertTrue(overlay_layer.startEditing()) f = QgsFeature(overlay_layer.fields()) f.setAttributes([1]) - f.setGeometry(QgsGeometry.fromWkt('Polygon ((0 0, 2 0, 2 2, 0 2, 0 0))')) + f.setGeometry(QgsGeometry.fromWkt("Polygon ((0 0, 2 0, 2 2, 0 2, 0 0))")) self.assertTrue(f.isValid()) self.assertTrue(overlay_layer.addFeatures([f])) overlay_layer.commitChanges() @@ -850,19 +1060,21 @@ def _test_difference_on_invalid_geometries(self, geom_option): old_features = [f for f in polygon_layer.getFeatures()] # 'Ignore features with invalid geometries' = 1 - ProcessingConfig.setSettingValue(ProcessingConfig.FILTER_INVALID_GEOMETRIES, geom_option) + ProcessingConfig.setSettingValue( + ProcessingConfig.FILTER_INVALID_GEOMETRIES, geom_option + ) feedback = ConsoleFeedBack() context = dataobjects.createContext(feedback) context.setProject(QgsProject.instance()) - alg = self.registry.createAlgorithmById('native:difference') + alg = self.registry.createAlgorithmById("native:difference") self.assertIsNotNone(alg) parameters = { - 'OVERLAY': overlay_layer, - 'INPUT': polygon_layer, - 'OUTPUT': ':memory', + "OVERLAY": overlay_layer, + "INPUT": polygon_layer, + "OUTPUT": ":memory", } old_features = [f for f in polygon_layer.getFeatures()] @@ -870,7 +1082,8 @@ def _test_difference_on_invalid_geometries(self, geom_option): self.assertTrue(polygon_layer.startEditing()) polygon_layer.selectAll() ok, _ = execute_in_place_run( - alg, parameters, context=context, feedback=feedback, raise_exceptions=True) + alg, parameters, context=context, feedback=feedback, raise_exceptions=True + ) new_features = [f for f in polygon_layer.getFeatures()] @@ -890,11 +1103,13 @@ def test_unique_constraints(self): """Test issue #31634""" temp_dir = QTemporaryDir() temp_path = temp_dir.path() - gpkg_name = 'bug_31634_Multi_to_Singleparts_FID.gpkg' + gpkg_name = "bug_31634_Multi_to_Singleparts_FID.gpkg" gpkg_path = os.path.join(temp_path, gpkg_name) shutil.copyfile(os.path.join(unitTestDataPath(), gpkg_name), gpkg_path) - gpkg_layer = QgsVectorLayer(gpkg_path + '|layername=Multi_to_Singleparts_FID_bug', 'lyr', 'ogr') + gpkg_layer = QgsVectorLayer( + gpkg_path + "|layername=Multi_to_Singleparts_FID_bug", "lyr", "ogr" + ) self.assertTrue(gpkg_layer.isValid()) QgsProject.instance().addMapLayers([gpkg_layer]) @@ -905,16 +1120,17 @@ def test_unique_constraints(self): context = dataobjects.createContext(feedback) context.setProject(QgsProject.instance()) - alg = self.registry.createAlgorithmById('native:multiparttosingleparts') + alg = self.registry.createAlgorithmById("native:multiparttosingleparts") self.assertIsNotNone(alg) parameters = { - 'INPUT': gpkg_layer, - 'OUTPUT': ':memory', + "INPUT": gpkg_layer, + "OUTPUT": ":memory", } ok, _ = execute_in_place_run( - alg, parameters, context=context, feedback=feedback, raise_exceptions=True) + alg, parameters, context=context, feedback=feedback, raise_exceptions=True + ) pks = set() for f in gpkg_layer.getFeatures(): @@ -927,32 +1143,44 @@ def test_regenerate_fid(self): temp_dir = QTemporaryDir() temp_path = temp_dir.path() - gpkg_name = 'bug_31634_Multi_to_Singleparts_FID.gpkg' + gpkg_name = "bug_31634_Multi_to_Singleparts_FID.gpkg" gpkg_path = os.path.join(temp_path, gpkg_name) shutil.copyfile(os.path.join(unitTestDataPath(), gpkg_name), gpkg_path) - gpkg_layer = QgsVectorLayer(gpkg_path + '|layername=Multi_to_Singleparts_FID_bug', 'lyr', 'ogr') + gpkg_layer = QgsVectorLayer( + gpkg_path + "|layername=Multi_to_Singleparts_FID_bug", "lyr", "ogr" + ) self.assertTrue(gpkg_layer.isValid()) f = next(gpkg_layer.getFeatures()) - self.assertEqual(f['fid'], 1) + self.assertEqual(f["fid"], 1) res = QgsVectorLayerUtils.makeFeatureCompatible(f, gpkg_layer) - self.assertEqual([ff['fid'] for ff in res], [1]) + self.assertEqual([ff["fid"] for ff in res], [1]) # if RegeneratePrimaryKey set then we should discard fid field - res = QgsVectorLayerUtils.makeFeatureCompatible(f, gpkg_layer, QgsFeatureSink.SinkFlag.RegeneratePrimaryKey) - self.assertEqual([ff['fid'] for ff in res], [None]) + res = QgsVectorLayerUtils.makeFeatureCompatible( + f, gpkg_layer, QgsFeatureSink.SinkFlag.RegeneratePrimaryKey + ) + self.assertEqual([ff["fid"] for ff in res], [None]) def test_datadefinedvalue(self): """Check that data defined parameters work correctly""" - polygon_layer = self._make_layer('Polygon') + polygon_layer = self._make_layer("Polygon") f1 = QgsFeature(polygon_layer.fields()) f1.setAttributes([1]) - f1.setGeometry(QgsGeometry.fromWkt('POLYGON((1.2 1.2, 1.2 2.2, 2.2 2.2, 2.2 1.2, 1.2 1.2))')) + f1.setGeometry( + QgsGeometry.fromWkt( + "POLYGON((1.2 1.2, 1.2 2.2, 2.2 2.2, 2.2 1.2, 1.2 1.2))" + ) + ) f2 = QgsFeature(polygon_layer.fields()) f2.setAttributes([2]) - 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))')) + 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.startEditing()) self.assertTrue(polygon_layer.addFeatures([f1, f2])) @@ -965,19 +1193,26 @@ def test_datadefinedvalue(self): self.assertEqual(polygon_layer.selectedFeatureCount(), 2) old_features, new_features = self._alg_tester( - 'native:densifygeometries', + "native:densifygeometries", polygon_layer, { - 'VERTICES': QgsProperty.fromField('int_f'), - }, retain_selection=True + "VERTICES": QgsProperty.fromField("int_f"), + }, + retain_selection=True, ) geometries = [f.geometry() for f in new_features] - self.assertEqual(geometries[0].asWkt(2), 'Polygon ((1.2 1.2, 1.2 1.7, 1.2 2.2, 1.7 2.2, 2.2 2.2, 2.2 1.7, 2.2 1.2, 1.7 1.2, 1.2 1.2))') - self.assertEqual(geometries[1].asWkt(2), 'Polygon ((1.1 1.1, 1.1 1.43, 1.1 1.77, 1.1 2.1, 1.43 2.1, 1.77 2.1, 2.1 2.1, 2.1 1.77, 2.1 1.43, 2.1 1.1, 1.77 1.1, 1.43 1.1, 1.1 1.1))') + self.assertEqual( + geometries[0].asWkt(2), + "Polygon ((1.2 1.2, 1.2 1.7, 1.2 2.2, 1.7 2.2, 2.2 2.2, 2.2 1.7, 2.2 1.2, 1.7 1.2, 1.2 1.2))", + ) + self.assertEqual( + geometries[1].asWkt(2), + "Polygon ((1.1 1.1, 1.1 1.43, 1.1 1.77, 1.1 2.1, 1.43 2.1, 1.77 2.1, 2.1 2.1, 2.1 1.77, 2.1 1.43, 2.1 1.1, 1.77 1.1, 1.43 1.1, 1.1 1.1))", + ) # Check selected self.assertCountEqual(polygon_layer.selectedFeatureIds(), [1, 2]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprocessingparameters.py b/tests/src/python/test_qgsprocessingparameters.py index b3a1bb71a0df..157cc8febb59 100644 --- a/tests/src/python/test_qgsprocessingparameters.py +++ b/tests/src/python/test_qgsprocessingparameters.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'David Marteau' -__date__ = '2020-09' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "David Marteau" +__date__ = "2020-09" +__copyright__ = "Copyright 2020, The QGIS Project" from processing.core.Processing import Processing from qgis.PyQt.QtCore import QCoreApplication @@ -30,22 +31,24 @@ def setUpClass(cls): """Run before all tests""" super().setUpClass() QCoreApplication.setOrganizationName("QGIS_Test") - QCoreApplication.setOrganizationDomain( - "QGIS_TestPyQgsProcessingParameters.com") + QCoreApplication.setOrganizationDomain("QGIS_TestPyQgsProcessingParameters.com") QCoreApplication.setApplicationName("QGIS_TestPyQgsProcessingParameters") QgsSettings().clear() Processing.initialize() cls.registry = QgsApplication.instance().processingRegistry() def test_qgsprocessinggometry(self): # spellok - """ Test QgsProcessingParameterGeometry initialization """ - geomtypes = [QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.GeometryType.PolygonGeometry] - param = QgsProcessingParameterGeometry(name='test', geometryTypes=geomtypes) + """Test QgsProcessingParameterGeometry initialization""" + geomtypes = [ + QgsWkbTypes.GeometryType.PointGeometry, + QgsWkbTypes.GeometryType.PolygonGeometry, + ] + param = QgsProcessingParameterGeometry(name="test", geometryTypes=geomtypes) types = param.geometryTypes() self.assertEqual(param.geometryTypes(), geomtypes) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprocessingrecentalgorithmslog.py b/tests/src/python/test_qgsprocessingrecentalgorithmslog.py index 6510a8264ae3..155ecc949364 100644 --- a/tests/src/python/test_qgsprocessingrecentalgorithmslog.py +++ b/tests/src/python/test_qgsprocessingrecentalgorithmslog.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2018-07' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2018-07" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication from qgis.PyQt.QtTest import QSignalSpy @@ -26,7 +27,9 @@ def setUpClass(cls): """Run before all tests""" super().setUpClass() QCoreApplication.setOrganizationName("QGIS_Test") - QCoreApplication.setOrganizationDomain("QGIS_TestPyQgsNewGeoPackageLayerDialog.com") + QCoreApplication.setOrganizationDomain( + "QGIS_TestPyQgsNewGeoPackageLayerDialog.com" + ) QCoreApplication.setApplicationName("QGIS_TestPyQgsNewGeoPackageLayerDialog") QgsSettings().clear() @@ -35,52 +38,62 @@ def test_log(self): self.assertFalse(log.recentAlgorithmIds()) spy = QSignalSpy(log.changed) - log.push('test') - self.assertEqual(log.recentAlgorithmIds(), ['test']) + log.push("test") + self.assertEqual(log.recentAlgorithmIds(), ["test"]) self.assertEqual(len(spy), 1) - log.push('test') - self.assertEqual(log.recentAlgorithmIds(), ['test']) + log.push("test") + self.assertEqual(log.recentAlgorithmIds(), ["test"]) self.assertEqual(len(spy), 1) - log.push('test2') - self.assertEqual(log.recentAlgorithmIds(), ['test2', 'test']) + log.push("test2") + self.assertEqual(log.recentAlgorithmIds(), ["test2", "test"]) self.assertEqual(len(spy), 2) - log.push('test') - self.assertEqual(log.recentAlgorithmIds(), ['test', 'test2']) + log.push("test") + self.assertEqual(log.recentAlgorithmIds(), ["test", "test2"]) self.assertEqual(len(spy), 3) - log.push('test3') - self.assertEqual(log.recentAlgorithmIds(), ['test3', 'test', 'test2']) + log.push("test3") + self.assertEqual(log.recentAlgorithmIds(), ["test3", "test", "test2"]) self.assertEqual(len(spy), 4) - log.push('test4') - self.assertEqual(log.recentAlgorithmIds(), ['test4', 'test3', 'test', 'test2']) + log.push("test4") + self.assertEqual(log.recentAlgorithmIds(), ["test4", "test3", "test", "test2"]) self.assertEqual(len(spy), 5) - log.push('test5') - self.assertEqual(log.recentAlgorithmIds(), ['test5', 'test4', 'test3', 'test', 'test2']) + log.push("test5") + self.assertEqual( + log.recentAlgorithmIds(), ["test5", "test4", "test3", "test", "test2"] + ) self.assertEqual(len(spy), 6) - log.push('test6') - self.assertEqual(log.recentAlgorithmIds(), ['test6', 'test5', 'test4', 'test3', 'test']) + log.push("test6") + self.assertEqual( + log.recentAlgorithmIds(), ["test6", "test5", "test4", "test3", "test"] + ) self.assertEqual(len(spy), 7) - log.push('test3') - self.assertEqual(log.recentAlgorithmIds(), ['test3', 'test6', 'test5', 'test4', 'test']) + log.push("test3") + self.assertEqual( + log.recentAlgorithmIds(), ["test3", "test6", "test5", "test4", "test"] + ) self.assertEqual(len(spy), 8) - log.push('test3') - self.assertEqual(log.recentAlgorithmIds(), ['test3', 'test6', 'test5', 'test4', 'test']) + log.push("test3") + self.assertEqual( + log.recentAlgorithmIds(), ["test3", "test6", "test5", "test4", "test"] + ) self.assertEqual(len(spy), 8) # test that log has been saved to QgsSettings log2 = QgsProcessingRecentAlgorithmLog() - self.assertEqual(log2.recentAlgorithmIds(), ['test3', 'test6', 'test5', 'test4', 'test']) + self.assertEqual( + log2.recentAlgorithmIds(), ["test3", "test6", "test5", "test4", "test"] + ) def test_gui_instance(self): self.assertIsNotNone(QgsGui.instance().processingRecentAlgorithmLog()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprocessingutils.py b/tests/src/python/test_qgsprocessingutils.py index a037a5db34cd..74cc8043c564 100644 --- a/tests/src/python/test_qgsprocessingutils.py +++ b/tests/src/python/test_qgsprocessingutils.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Germán Carrillo' -__date__ = '7.3.2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Germán Carrillo" +__date__ = "7.3.2022" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.core import QgsField, QgsFields, QgsProcessingUtils import unittest @@ -24,15 +25,15 @@ def setUpClass(cls): start_app() def test_combineFields_no_name_conflict(self): - field1A = QgsField('ID') - field1B = QgsField('NAME') + field1A = QgsField("ID") + field1B = QgsField("NAME") fields1 = QgsFields() fields1.append(field1A) fields1.append(field1B) - field2A = QgsField('FID') - field2B = QgsField('AREA') - field2C = QgsField('COUNT') + field2A = QgsField("FID") + field2B = QgsField("AREA") + field2C = QgsField("COUNT") fields2 = QgsFields() fields2.append(field2A) fields2.append(field2B) @@ -41,22 +42,22 @@ def test_combineFields_no_name_conflict(self): combined = QgsProcessingUtils.combineFields(fields1, fields2) self.assertEqual(len(combined), 5) - expected_names = ['ID', 'NAME', 'FID', 'AREA', 'COUNT'] + expected_names = ["ID", "NAME", "FID", "AREA", "COUNT"] obtained_names = [field.name() for field in combined] self.assertEqual(expected_names, obtained_names) def test_combineFields_no_name_conflict_prefix(self): - prefix = 'joined_' + prefix = "joined_" - field1A = QgsField('ID') - field1B = QgsField('NAME') + field1A = QgsField("ID") + field1B = QgsField("NAME") fields1 = QgsFields() fields1.append(field1A) fields1.append(field1B) - field2A = QgsField('FID') - field2B = QgsField('AREA') - field2C = QgsField('COUNT') + field2A = QgsField("FID") + field2B = QgsField("AREA") + field2C = QgsField("COUNT") fields2 = QgsFields() fields2.append(field2A) fields2.append(field2B) @@ -65,20 +66,20 @@ def test_combineFields_no_name_conflict_prefix(self): combined = QgsProcessingUtils.combineFields(fields1, fields2, prefix) self.assertEqual(len(combined), 5) - expected_names = ['ID', 'NAME', 'joined_FID', 'joined_AREA', 'joined_COUNT'] + expected_names = ["ID", "NAME", "joined_FID", "joined_AREA", "joined_COUNT"] obtained_names = [field.name() for field in combined] self.assertEqual(expected_names, obtained_names) def test_combineFields_name_conflict(self): - field1A = QgsField('ID') - field1B = QgsField('NAME') + field1A = QgsField("ID") + field1B = QgsField("NAME") fields1 = QgsFields() fields1.append(field1A) fields1.append(field1B) - field2A = QgsField('FID') - field2B = QgsField('NAME') - field2C = QgsField('COUNT') + field2A = QgsField("FID") + field2B = QgsField("NAME") + field2C = QgsField("COUNT") fields2 = QgsFields() fields2.append(field2A) fields2.append(field2B) @@ -87,22 +88,22 @@ def test_combineFields_name_conflict(self): combined = QgsProcessingUtils.combineFields(fields1, fields2) self.assertEqual(len(combined), 5) - expected_names = ['ID', 'NAME', 'FID', 'NAME_2', 'COUNT'] + expected_names = ["ID", "NAME", "FID", "NAME_2", "COUNT"] obtained_names = [field.name() for field in combined] self.assertEqual(expected_names, obtained_names) def test_combineFields_name_conflict_prefix(self): - prefix = 'joined_' + prefix = "joined_" - field1A = QgsField('ID') - field1B = QgsField('NAME') + field1A = QgsField("ID") + field1B = QgsField("NAME") fields1 = QgsFields() fields1.append(field1A) fields1.append(field1B) - field2A = QgsField('FID') - field2B = QgsField('NAME') - field2C = QgsField('COUNT') + field2A = QgsField("FID") + field2B = QgsField("NAME") + field2C = QgsField("COUNT") fields2 = QgsFields() fields2.append(field2A) fields2.append(field2B) @@ -111,20 +112,20 @@ def test_combineFields_name_conflict_prefix(self): combined = QgsProcessingUtils.combineFields(fields1, fields2, prefix) self.assertEqual(len(combined), 5) - expected_names = ['ID', 'NAME', 'joined_FID', 'joined_NAME', 'joined_COUNT'] + expected_names = ["ID", "NAME", "joined_FID", "joined_NAME", "joined_COUNT"] obtained_names = [field.name() for field in combined] self.assertEqual(expected_names, obtained_names) def test_combineFields_issue_47651(self): - field1A = QgsField('ID') - field1B = QgsField('FK') + field1A = QgsField("ID") + field1B = QgsField("FK") fields1 = QgsFields() fields1.append(field1A) fields1.append(field1B) - field2A = QgsField('ID') - field2B = QgsField('ID_2') - field2C = QgsField('COUNT') + field2A = QgsField("ID") + field2B = QgsField("ID_2") + field2C = QgsField("COUNT") fields2 = QgsFields() fields2.append(field2A) fields2.append(field2B) @@ -133,21 +134,21 @@ def test_combineFields_issue_47651(self): combined = QgsProcessingUtils.combineFields(fields1, fields2) self.assertEqual(len(combined), 5) - expected_names = ['ID', 'FK', 'ID_3', 'ID_2', 'COUNT'] + expected_names = ["ID", "FK", "ID_3", "ID_2", "COUNT"] obtained_names = [field.name() for field in combined] self.assertEqual(expected_names, obtained_names) def test_combineFields_issue_47651_prefix(self): - prefix = 'joined_' - field1A = QgsField('ID') - field1B = QgsField('FK') + prefix = "joined_" + field1A = QgsField("ID") + field1B = QgsField("FK") fields1 = QgsFields() fields1.append(field1A) fields1.append(field1B) - field2A = QgsField('ID') - field2B = QgsField('ID_2') - field2C = QgsField('COUNT') + field2A = QgsField("ID") + field2B = QgsField("ID_2") + field2C = QgsField("COUNT") fields2 = QgsFields() fields2.append(field2A) fields2.append(field2B) @@ -156,7 +157,7 @@ def test_combineFields_issue_47651_prefix(self): combined = QgsProcessingUtils.combineFields(fields1, fields2, prefix) self.assertEqual(len(combined), 5) - expected_names = ['ID', 'FK', 'joined_ID', 'joined_ID_2', 'joined_COUNT'] + expected_names = ["ID", "FK", "joined_ID", "joined_ID_2", "joined_COUNT"] obtained_names = [field.name() for field in combined] self.assertEqual(expected_names, obtained_names) diff --git a/tests/src/python/test_qgsprofileexporter.py b/tests/src/python/test_qgsprofileexporter.py index 5ab044af9fb1..6cc446d7b5cf 100644 --- a/tests/src/python/test_qgsprofileexporter.py +++ b/tests/src/python/test_qgsprofileexporter.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '18/03/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "18/03/2022" +__copyright__ = "Copyright 2022, The QGIS Project" import os import tempfile @@ -29,7 +30,7 @@ QgsMemoryProviderUtils, QgsFields, QgsFeature, - QgsGeometry + QgsGeometry, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -42,18 +43,18 @@ class TestQgsProfileExporter(QgisTestCase): def testExport(self): - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) rl.elevationProperties().setEnabled(True) curve = QgsLineString() - curve.fromWkt('LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)') + curve.fromWkt( + "LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)" + ) req = QgsProfileRequest(curve) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) - exporter = QgsProfileExporter( - [rl], - req, Qgis.ProfileExportType.Features3D) + exporter = QgsProfileExporter([rl], req, Qgis.ProfileExportType.Features3D) exporter.run() @@ -68,44 +69,51 @@ def testExport(self): self.assertEqual(len(features), 1) self.assertEqual(features[0][0], rl.id()) self.assertEqual(features[0].geometry().constGet().numPoints(), 1394) - self.assertEqual(features[0].geometry().constGet().pointN(0).asWkt(-2), 'Point Z (-348100 6633700 200)') - self.assertEqual(features[0].geometry().constGet().pointN(1393).asWkt(-2), 'Point Z (-345800 6631600 100)') + self.assertEqual( + features[0].geometry().constGet().pointN(0).asWkt(-2), + "Point Z (-348100 6633700 200)", + ) + self.assertEqual( + features[0].geometry().constGet().pointN(1393).asWkt(-2), + "Point Z (-345800 6631600 100)", + ) def testExportTaskDxf(self): - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) rl.elevationProperties().setEnabled(True) curve = QgsLineString() - curve.fromWkt('LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)') + curve.fromWkt( + "LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)" + ) req = QgsProfileRequest(curve) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) with tempfile.TemporaryDirectory() as temp_dir: exporter = QgsProfileExporterTask( [rl], - req, Qgis.ProfileExportType.Features3D, - os.path.join(temp_dir, 'test.dxf'), - QgsProject.instance().transformContext() + req, + Qgis.ProfileExportType.Features3D, + os.path.join(temp_dir, "test.dxf"), + QgsProject.instance().transformContext(), ) QgsApplication.taskManager().addTask(exporter) exporter.waitForFinished() - self.assertEqual(exporter.result(), - QgsProfileExporterTask.ExportResult.Success - ) self.assertEqual( - exporter.createdFiles(), - [os.path.join(temp_dir, 'test.dxf')]) - - self.assertTrue( - os.path.exists(os.path.join(temp_dir, 'test.dxf')) + exporter.result(), QgsProfileExporterTask.ExportResult.Success + ) + self.assertEqual( + exporter.createdFiles(), [os.path.join(temp_dir, "test.dxf")] ) + self.assertTrue(os.path.exists(os.path.join(temp_dir, "test.dxf"))) + layers = exporter.takeLayers() self.assertEqual(len(layers), 1) - output_layer = QgsVectorLayer(exporter.createdFiles()[0], 'test') + output_layer = QgsVectorLayer(exporter.createdFiles()[0], "test") self.assertTrue(output_layer.isValid()) self.assertEqual(output_layer.wkbType(), Qgis.WkbType.LineStringZ) @@ -113,56 +121,73 @@ def testExportTaskDxf(self): self.assertEqual(len(features), 1) self.assertEqual(features[0].geometry().constGet().numPoints(), 1394) - self.assertEqual(features[0].geometry().constGet().pointN(0).asWkt(-2), 'Point Z (-348100 6633700 200)') - self.assertEqual(features[0].geometry().constGet().pointN(1393).asWkt(-2), 'Point Z (-345800 6631600 100)') + self.assertEqual( + features[0].geometry().constGet().pointN(0).asWkt(-2), + "Point Z (-348100 6633700 200)", + ) + self.assertEqual( + features[0].geometry().constGet().pointN(1393).asWkt(-2), + "Point Z (-345800 6631600 100)", + ) def testExportTaskDxfMultiLayer(self): - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) rl.elevationProperties().setEnabled(True) vl = QgsMemoryProviderUtils.createMemoryLayer( - 'test', QgsFields(), Qgis.WkbType.LineStringZ, - QgsCoordinateReferenceSystem('EPSG:3857') + "test", + QgsFields(), + Qgis.WkbType.LineStringZ, + QgsCoordinateReferenceSystem("EPSG:3857"), ) self.assertTrue(vl.isValid()) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) feature = QgsFeature(vl.fields()) - feature.setGeometry(QgsGeometry.fromWkt('LineStringZ (-347860.62472087447531521 6632536.37540269736200571 30, -347016.72474283445626497 6633588.82537531014531851 40)')) + feature.setGeometry( + QgsGeometry.fromWkt( + "LineStringZ (-347860.62472087447531521 6632536.37540269736200571 30, -347016.72474283445626497 6633588.82537531014531851 40)" + ) + ) self.assertTrue(vl.dataProvider().addFeature(feature)) curve = QgsLineString() - curve.fromWkt('LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)') + curve.fromWkt( + "LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)" + ) req = QgsProfileRequest(curve) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) with tempfile.TemporaryDirectory() as temp_dir: exporter = QgsProfileExporterTask( [rl, vl], - req, Qgis.ProfileExportType.Features3D, - os.path.join(temp_dir, 'test.dxf'), - QgsProject.instance().transformContext() + req, + Qgis.ProfileExportType.Features3D, + os.path.join(temp_dir, "test.dxf"), + QgsProject.instance().transformContext(), ) QgsApplication.taskManager().addTask(exporter) exporter.waitForFinished() - self.assertEqual(exporter.result(), - QgsProfileExporterTask.ExportResult.Success - ) self.assertEqual( - exporter.createdFiles(), - [os.path.join(temp_dir, 'test.dxf')]) - - self.assertTrue( - os.path.exists(os.path.join(temp_dir, 'test.dxf')) + exporter.result(), QgsProfileExporterTask.ExportResult.Success + ) + self.assertEqual( + exporter.createdFiles(), [os.path.join(temp_dir, "test.dxf")] ) + self.assertTrue(os.path.exists(os.path.join(temp_dir, "test.dxf"))) + layers = exporter.takeLayers() self.assertEqual(len(layers), 2) - point_output = QgsVectorLayer(exporter.createdFiles()[0] + '|geometrytype=Point25D', 'test') - line_output = QgsVectorLayer(exporter.createdFiles()[0] + '|geometrytype=LineString25D', 'test') + point_output = QgsVectorLayer( + exporter.createdFiles()[0] + "|geometrytype=Point25D", "test" + ) + line_output = QgsVectorLayer( + exporter.createdFiles()[0] + "|geometrytype=LineString25D", "test" + ) self.assertTrue(point_output.isValid()) self.assertTrue(line_output.isValid()) @@ -173,49 +198,58 @@ def testExportTaskDxfMultiLayer(self): self.assertEqual(len(features), 1) self.assertEqual(features[0].geometry().constGet().numPoints(), 1394) - self.assertEqual(features[0].geometry().constGet().pointN(0).asWkt(-2), 'Point Z (-348100 6633700 200)') - self.assertEqual(features[0].geometry().constGet().pointN(1393).asWkt(-2), 'Point Z (-345800 6631600 100)') + self.assertEqual( + features[0].geometry().constGet().pointN(0).asWkt(-2), + "Point Z (-348100 6633700 200)", + ) + self.assertEqual( + features[0].geometry().constGet().pointN(1393).asWkt(-2), + "Point Z (-345800 6631600 100)", + ) features = [f for f in point_output.getFeatures()] self.assertEqual(len(features), 1) - self.assertEqual(features[0].geometry().asWkt(-1), 'Point Z (-347360 6633160 40)') + self.assertEqual( + features[0].geometry().asWkt(-1), "Point Z (-347360 6633160 40)" + ) def testExportTaskShp(self): - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) rl.elevationProperties().setEnabled(True) curve = QgsLineString() - curve.fromWkt('LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)') + curve.fromWkt( + "LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)" + ) req = QgsProfileRequest(curve) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) with tempfile.TemporaryDirectory() as temp_dir: exporter = QgsProfileExporterTask( [rl], - req, Qgis.ProfileExportType.Features3D, - os.path.join(temp_dir, 'test.shp'), - QgsProject.instance().transformContext() + req, + Qgis.ProfileExportType.Features3D, + os.path.join(temp_dir, "test.shp"), + QgsProject.instance().transformContext(), ) QgsApplication.taskManager().addTask(exporter) exporter.waitForFinished() - self.assertEqual(exporter.result(), - QgsProfileExporterTask.ExportResult.Success - ) self.assertEqual( - exporter.createdFiles(), - [os.path.join(temp_dir, 'test.shp')]) - - self.assertTrue( - os.path.exists(os.path.join(temp_dir, 'test.shp')) + exporter.result(), QgsProfileExporterTask.ExportResult.Success ) + self.assertEqual( + exporter.createdFiles(), [os.path.join(temp_dir, "test.shp")] + ) + + self.assertTrue(os.path.exists(os.path.join(temp_dir, "test.shp"))) layers = exporter.takeLayers() self.assertEqual(len(layers), 1) - output_layer = QgsVectorLayer(exporter.createdFiles()[0], 'test') + output_layer = QgsVectorLayer(exporter.createdFiles()[0], "test") self.assertTrue(output_layer.isValid()) self.assertEqual(output_layer.wkbType(), Qgis.WkbType.MultiLineStringZ) @@ -223,65 +257,87 @@ def testExportTaskShp(self): self.assertEqual(len(features), 1) self.assertEqual(features[0].geometry().constGet()[0].numPoints(), 1394) - self.assertEqual(features[0].geometry().constGet()[0].pointN(0).asWkt(-2), 'Point Z (-348100 6633700 200)') - self.assertEqual(features[0].geometry().constGet()[0].pointN(1393).asWkt(-2), 'Point Z (-345800 6631600 100)') + self.assertEqual( + features[0].geometry().constGet()[0].pointN(0).asWkt(-2), + "Point Z (-348100 6633700 200)", + ) + self.assertEqual( + features[0].geometry().constGet()[0].pointN(1393).asWkt(-2), + "Point Z (-345800 6631600 100)", + ) def testExportTaskShpMultiLayer(self): - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) rl.elevationProperties().setEnabled(True) vl = QgsMemoryProviderUtils.createMemoryLayer( - 'test', QgsFields(), Qgis.WkbType.LineStringZ, - QgsCoordinateReferenceSystem('EPSG:3857') + "test", + QgsFields(), + Qgis.WkbType.LineStringZ, + QgsCoordinateReferenceSystem("EPSG:3857"), ) self.assertTrue(vl.isValid()) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) feature = QgsFeature(vl.fields()) - feature.setGeometry(QgsGeometry.fromWkt('LineString Z (-347860.62472087447531521 6632536.37540269736200571 30, -347016.72474283445626497 6633588.82537531014531851 40)')) + feature.setGeometry( + QgsGeometry.fromWkt( + "LineString Z (-347860.62472087447531521 6632536.37540269736200571 30, -347016.72474283445626497 6633588.82537531014531851 40)" + ) + ) self.assertTrue(vl.dataProvider().addFeature(feature)) curve = QgsLineString() - curve.fromWkt('LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)') + curve.fromWkt( + "LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)" + ) req = QgsProfileRequest(curve) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) with tempfile.TemporaryDirectory() as temp_dir: exporter = QgsProfileExporterTask( [rl, vl], - req, Qgis.ProfileExportType.Features3D, - os.path.join(temp_dir, 'test.shp'), - QgsProject.instance().transformContext() + req, + Qgis.ProfileExportType.Features3D, + os.path.join(temp_dir, "test.shp"), + QgsProject.instance().transformContext(), ) QgsApplication.taskManager().addTask(exporter) exporter.waitForFinished() - self.assertEqual(exporter.result(), - QgsProfileExporterTask.ExportResult.Success - ) + self.assertEqual( + exporter.result(), QgsProfileExporterTask.ExportResult.Success + ) self.assertCountEqual( exporter.createdFiles(), - [os.path.join(temp_dir, 'test_1.shp'), - os.path.join(temp_dir, 'test_2.shp')]) - - self.assertTrue( - os.path.exists(os.path.join(temp_dir, 'test_1.shp')) - ) - self.assertTrue( - os.path.exists(os.path.join(temp_dir, 'test_2.shp')) + [ + os.path.join(temp_dir, "test_1.shp"), + os.path.join(temp_dir, "test_2.shp"), + ], ) + self.assertTrue(os.path.exists(os.path.join(temp_dir, "test_1.shp"))) + self.assertTrue(os.path.exists(os.path.join(temp_dir, "test_2.shp"))) + layers = exporter.takeLayers() self.assertEqual(len(layers), 2) - output_1 = QgsVectorLayer(exporter.createdFiles()[0], 'test') - output_2 = QgsVectorLayer(exporter.createdFiles()[1], 'test') + output_1 = QgsVectorLayer(exporter.createdFiles()[0], "test") + output_2 = QgsVectorLayer(exporter.createdFiles()[1], "test") self.assertTrue(output_1.isValid()) self.assertTrue(output_2.isValid()) - line_output = output_1 if output_1.geometryType() == Qgis.GeometryType.Line else output_2 - point_output = output_1 if output_1.geometryType() == Qgis.GeometryType.Point else output_2 + line_output = ( + output_1 + if output_1.geometryType() == Qgis.GeometryType.Line + else output_2 + ) + point_output = ( + output_1 + if output_1.geometryType() == Qgis.GeometryType.Point + else output_2 + ) self.assertEqual(line_output.wkbType(), Qgis.WkbType.MultiLineStringZ) self.assertEqual(point_output.wkbType(), Qgis.WkbType.PointZ) @@ -290,49 +346,58 @@ def testExportTaskShpMultiLayer(self): self.assertEqual(len(features), 1) self.assertEqual(features[0].geometry().constGet()[0].numPoints(), 1394) - self.assertEqual(features[0].geometry().constGet()[0].pointN(0).asWkt(-2), 'Point Z (-348100 6633700 200)') - self.assertEqual(features[0].geometry().constGet()[0].pointN(1393).asWkt(-2), 'Point Z (-345800 6631600 100)') + self.assertEqual( + features[0].geometry().constGet()[0].pointN(0).asWkt(-2), + "Point Z (-348100 6633700 200)", + ) + self.assertEqual( + features[0].geometry().constGet()[0].pointN(1393).asWkt(-2), + "Point Z (-345800 6631600 100)", + ) features = [f for f in point_output.getFeatures()] self.assertEqual(len(features), 1) - self.assertEqual(features[0].geometry().asWkt(-1), 'Point Z (-347360 6633160 40)') + self.assertEqual( + features[0].geometry().asWkt(-1), "Point Z (-347360 6633160 40)" + ) def testExportTaskGpkg(self): - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) rl.elevationProperties().setEnabled(True) curve = QgsLineString() - curve.fromWkt('LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)') + curve.fromWkt( + "LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)" + ) req = QgsProfileRequest(curve) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) with tempfile.TemporaryDirectory() as temp_dir: exporter = QgsProfileExporterTask( [rl], - req, Qgis.ProfileExportType.Features3D, - os.path.join(temp_dir, 'test.gpkg'), - QgsProject.instance().transformContext() + req, + Qgis.ProfileExportType.Features3D, + os.path.join(temp_dir, "test.gpkg"), + QgsProject.instance().transformContext(), ) QgsApplication.taskManager().addTask(exporter) exporter.waitForFinished() - self.assertEqual(exporter.result(), - QgsProfileExporterTask.ExportResult.Success - ) self.assertEqual( - exporter.createdFiles(), - [os.path.join(temp_dir, 'test.gpkg')]) - - self.assertTrue( - os.path.exists(os.path.join(temp_dir, 'test.gpkg')) + exporter.result(), QgsProfileExporterTask.ExportResult.Success ) + self.assertEqual( + exporter.createdFiles(), [os.path.join(temp_dir, "test.gpkg")] + ) + + self.assertTrue(os.path.exists(os.path.join(temp_dir, "test.gpkg"))) layers = exporter.takeLayers() self.assertEqual(len(layers), 1) - output_layer = QgsVectorLayer(exporter.createdFiles()[0], 'test') + output_layer = QgsVectorLayer(exporter.createdFiles()[0], "test") self.assertTrue(output_layer.isValid()) self.assertEqual(output_layer.wkbType(), Qgis.WkbType.LineStringZ) @@ -340,61 +405,82 @@ def testExportTaskGpkg(self): self.assertEqual(len(features), 1) self.assertEqual(features[0].geometry().constGet().numPoints(), 1394) - self.assertEqual(features[0].geometry().constGet().pointN(0).asWkt(-2), 'Point Z (-348100 6633700 200)') - self.assertEqual(features[0].geometry().constGet().pointN(1393).asWkt(-2), 'Point Z (-345800 6631600 100)') + self.assertEqual( + features[0].geometry().constGet().pointN(0).asWkt(-2), + "Point Z (-348100 6633700 200)", + ) + self.assertEqual( + features[0].geometry().constGet().pointN(1393).asWkt(-2), + "Point Z (-345800 6631600 100)", + ) def testExportTaskGpkgMultiLayer(self): - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) rl.elevationProperties().setEnabled(True) vl = QgsMemoryProviderUtils.createMemoryLayer( - 'test', QgsFields(), Qgis.WkbType.LineStringZ, - QgsCoordinateReferenceSystem('EPSG:3857') + "test", + QgsFields(), + Qgis.WkbType.LineStringZ, + QgsCoordinateReferenceSystem("EPSG:3857"), ) self.assertTrue(vl.isValid()) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) feature = QgsFeature(vl.fields()) - feature.setGeometry(QgsGeometry.fromWkt('LineString Z (-347860.62472087447531521 6632536.37540269736200571 30, -347016.72474283445626497 6633588.82537531014531851 40)')) + feature.setGeometry( + QgsGeometry.fromWkt( + "LineString Z (-347860.62472087447531521 6632536.37540269736200571 30, -347016.72474283445626497 6633588.82537531014531851 40)" + ) + ) self.assertTrue(vl.dataProvider().addFeature(feature)) curve = QgsLineString() - curve.fromWkt('LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)') + curve.fromWkt( + "LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)" + ) req = QgsProfileRequest(curve) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) with tempfile.TemporaryDirectory() as temp_dir: exporter = QgsProfileExporterTask( [rl, vl], - req, Qgis.ProfileExportType.Features3D, - os.path.join(temp_dir, 'test.gpkg'), - QgsProject.instance().transformContext() + req, + Qgis.ProfileExportType.Features3D, + os.path.join(temp_dir, "test.gpkg"), + QgsProject.instance().transformContext(), ) QgsApplication.taskManager().addTask(exporter) exporter.waitForFinished() - self.assertEqual(exporter.result(), - QgsProfileExporterTask.ExportResult.Success - ) self.assertEqual( - exporter.createdFiles(), - [os.path.join(temp_dir, 'test.gpkg')]) - - self.assertTrue( - os.path.exists(os.path.join(temp_dir, 'test.gpkg')) + exporter.result(), QgsProfileExporterTask.ExportResult.Success + ) + self.assertEqual( + exporter.createdFiles(), [os.path.join(temp_dir, "test.gpkg")] ) + self.assertTrue(os.path.exists(os.path.join(temp_dir, "test.gpkg"))) + layers = exporter.takeLayers() self.assertEqual(len(layers), 2) - output_1 = QgsVectorLayer(exporter.createdFiles()[0] + '|layerId=0', 'test') - output_2 = QgsVectorLayer(exporter.createdFiles()[0] + '|layerId=1', 'test') + output_1 = QgsVectorLayer(exporter.createdFiles()[0] + "|layerId=0", "test") + output_2 = QgsVectorLayer(exporter.createdFiles()[0] + "|layerId=1", "test") self.assertTrue(output_1.isValid()) self.assertTrue(output_2.isValid()) - line_output = output_1 if output_1.geometryType() == Qgis.GeometryType.Line else output_2 - point_output = output_1 if output_1.geometryType() == Qgis.GeometryType.Point else output_2 + line_output = ( + output_1 + if output_1.geometryType() == Qgis.GeometryType.Line + else output_2 + ) + point_output = ( + output_1 + if output_1.geometryType() == Qgis.GeometryType.Point + else output_2 + ) self.assertEqual(line_output.wkbType(), Qgis.WkbType.LineStringZ) self.assertEqual(point_output.wkbType(), Qgis.WkbType.PointZ) @@ -403,14 +489,22 @@ def testExportTaskGpkgMultiLayer(self): self.assertEqual(len(features), 1) self.assertEqual(features[0].geometry().constGet().numPoints(), 1394) - self.assertEqual(features[0].geometry().constGet().pointN(0).asWkt(-2), 'Point Z (-348100 6633700 200)') - self.assertEqual(features[0].geometry().constGet().pointN(1393).asWkt(-2), 'Point Z (-345800 6631600 100)') + self.assertEqual( + features[0].geometry().constGet().pointN(0).asWkt(-2), + "Point Z (-348100 6633700 200)", + ) + self.assertEqual( + features[0].geometry().constGet().pointN(1393).asWkt(-2), + "Point Z (-345800 6631600 100)", + ) features = [f for f in point_output.getFeatures()] self.assertEqual(len(features), 1) - self.assertEqual(features[0].geometry().asWkt(-1), 'Point Z (-347360 6633160 40)') + self.assertEqual( + features[0].geometry().asWkt(-1), "Point Z (-347360 6633160 40)" + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprofilepoint.py b/tests/src/python/test_qgsprofilepoint.py index 9542b2a029f0..76543caad323 100644 --- a/tests/src/python/test_qgsprofilepoint.py +++ b/tests/src/python/test_qgsprofilepoint.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '18/03/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "18/03/2022" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.core import QgsProfilePoint @@ -22,7 +23,7 @@ class TestQgsProfilePoint(QgisTestCase): def testBasic(self): point = QgsProfilePoint() self.assertTrue(point.isEmpty()) - self.assertEqual(str(point), '') + self.assertEqual(str(point), "") point.setDistance(1) self.assertFalse(point.isEmpty()) @@ -36,7 +37,7 @@ def testBasic(self): point = QgsProfilePoint(1, 2) self.assertEqual(point.distance(), 1) self.assertEqual(point.elevation(), 2) - self.assertEqual(str(point), '') + self.assertEqual(str(point), "") self.assertEqual(point[0], 1) self.assertEqual(point[1], 2) self.assertEqual(len(point), 2) @@ -68,5 +69,5 @@ def test_equality(self): self.assertFalse(p1 != p2) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprofilerequest.py b/tests/src/python/test_qgsprofilerequest.py index 1b03099603c8..dee7c7d7c503 100644 --- a/tests/src/python/test_qgsprofilerequest.py +++ b/tests/src/python/test_qgsprofilerequest.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '18/03/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "18/03/2022" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.core import ( @@ -30,28 +31,38 @@ class TestQgsProfileRequest(QgisTestCase): def testBasic(self): req = QgsProfileRequest(QgsLineString([[1, 2], [3, 4]])) - self.assertEqual(req.profileCurve().asWkt(), 'LineString (1 2, 3 4)') + self.assertEqual(req.profileCurve().asWkt(), "LineString (1 2, 3 4)") - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')).setTolerance(5).setStepDistance(15) - self.assertEqual(req.crs().authid(), 'EPSG:3857') + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")).setTolerance( + 5 + ).setStepDistance(15) + self.assertEqual(req.crs().authid(), "EPSG:3857") self.assertEqual(req.tolerance(), 5) self.assertEqual(req.stepDistance(), 15) - proj_string = '+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1' + proj_string = "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1" transform_context = QgsCoordinateTransformContext() - transform_context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:4283'), proj_string) + transform_context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + proj_string, + ) req.setTransformContext(transform_context) - self.assertEqual(req.transformContext().calculateCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:4283')), proj_string) + self.assertEqual( + req.transformContext().calculateCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + ), + proj_string, + ) exp_context = QgsExpressionContext() context_scope = QgsExpressionContextScope() - context_scope.setVariable('test_var', 5, True) + context_scope.setVariable("test_var", 5, True) exp_context.appendScope(context_scope) req.setExpressionContext(exp_context) - self.assertEqual(req.expressionContext().variable('test_var'), 5) + self.assertEqual(req.expressionContext().variable("test_var"), 5) terrain = QgsFlatTerrainProvider() terrain.setOffset(5) @@ -59,15 +70,20 @@ def testBasic(self): self.assertEqual(req.terrainProvider().offset(), 5) copy = QgsProfileRequest(req) - self.assertEqual(copy.profileCurve().asWkt(), 'LineString (1 2, 3 4)') - self.assertEqual(copy.crs().authid(), 'EPSG:3857') + self.assertEqual(copy.profileCurve().asWkt(), "LineString (1 2, 3 4)") + self.assertEqual(copy.crs().authid(), "EPSG:3857") self.assertEqual(copy.tolerance(), 5) self.assertEqual(copy.stepDistance(), 15) - self.assertEqual(copy.transformContext().calculateCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:4283')), proj_string) + self.assertEqual( + copy.transformContext().calculateCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + ), + proj_string, + ) self.assertIsInstance(copy.terrainProvider(), QgsFlatTerrainProvider) self.assertEqual(copy.terrainProvider().offset(), 5) - self.assertEqual(copy.expressionContext().variable('test_var'), 5) + self.assertEqual(copy.expressionContext().variable("test_var"), 5) def testEquality(self): """ @@ -89,15 +105,18 @@ def testEquality(self): req.setProfileCurve(QgsLineString([[1, 2], [3, 5]])) self.assertEqual(req, req2) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) self.assertNotEqual(req, req2) - req2.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req2.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) self.assertEqual(req, req2) - proj_string = '+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1' + proj_string = "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1" transform_context = QgsCoordinateTransformContext() - transform_context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:3111'), - QgsCoordinateReferenceSystem('EPSG:4283'), proj_string) + transform_context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:4283"), + proj_string, + ) req.setTransformContext(transform_context) self.assertNotEqual(req, req2) @@ -132,5 +151,5 @@ def testEquality(self): self.assertEqual(req, req2) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprofilesourceregistry.py b/tests/src/python/test_qgsprofilesourceregistry.py index e0efc6d2ba02..16ee0e59e3f2 100644 --- a/tests/src/python/test_qgsprofilesourceregistry.py +++ b/tests/src/python/test_qgsprofilesourceregistry.py @@ -5,16 +5,13 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Germán Carrillo' -__date__ = '03/05/2024' -__copyright__ = 'Copyright 2024, The QGIS Project' +__author__ = "Germán Carrillo" +__date__ = "03/05/2024" +__copyright__ = "Copyright 2024, The QGIS Project" -from qgis.PyQt.QtCore import ( - QRectF, - Qt, - QPointF -) + +from qgis.PyQt.QtCore import QRectF, Qt, QPointF from qgis.PyQt.QtGui import QColor, QPainterPath, QPolygonF from qgis.PyQt.QtTest import QSignalSpy from qgis.core import ( @@ -39,7 +36,7 @@ QgsProfileGenerationContext, QgsProfileRequest, QgsProject, - QgsTextFormat + QgsTextFormat, ) from qgis.gui import QgsElevationProfileCanvas @@ -63,8 +60,8 @@ def __init__(self): self.max_z = -100 self.marker_symbol = QgsMarkerSymbol.createSimple( - {'name': 'square', 'size': 2, 'color': '#00ff00', - 'outline_style': 'no'}) + {"name": "square", "size": 2, "color": "#00ff00", "outline_style": "no"} + ) def asFeatures(self, type, feedback): result = [] @@ -116,7 +113,9 @@ def renderResults(self, context): minZ = context.elevationRange().lower() maxZ = context.elevationRange().upper() - visibleRegion = QRectF(minDistance, minZ, maxDistance - minDistance, maxZ - minZ) + visibleRegion = QRectF( + minDistance, minZ, maxDistance - minDistance, maxZ - minZ + ) clipPath = QPainterPath() clipPath.addPolygon(context.worldTransform().map(QPolygonF(visibleRegion))) painter.setClipPath(clipPath, Qt.ClipOperation.IntersectClip) @@ -130,7 +129,7 @@ def renderResults(self, context): self.marker_symbol.renderPoint( context.worldTransform().map(QPointF(k, v)), None, - context.renderContext() + context.renderContext(), ) self.marker_symbol.stopRender(context.renderContext()) @@ -140,7 +139,9 @@ class MyProfileGenerator(QgsAbstractProfileGenerator): def __init__(self, request): QgsAbstractProfileGenerator.__init__(self) self.__request = request - self.__profile_curve = request.profileCurve().clone() if request.profileCurve() else None + self.__profile_curve = ( + request.profileCurve().clone() if request.profileCurve() else None + ) self.__results = None self.__feedback = QgsFeedback() @@ -161,7 +162,8 @@ def generateProfile(self, context): # QgsProfileGenerationContext {"z": 429.3, "d": 2199.9, "x": 2582027.691, "y": 1217250.279}, {"z": 702.5, "d": 4399.9, "x": 2579969.567, "y": 1218027.326}, {"z": 857.9, "d": 6430.1, "x": 2578394.472, "y": 1219308.404}, - {"z": 1282.7, "d": 8460.4, "x": 2576819.377, "y": 1220589.481}] + {"z": 1282.7, "d": 8460.4, "x": 2576819.377, "y": 1220589.481}, + ] for point in result: if self.__feedback.isCanceled(): @@ -203,20 +205,23 @@ def test_register_unregister_source(self): QgsApplication.profileSourceRegistry().registerProfileSource(source) self.assertEqual( len(QgsApplication.profileSourceRegistry().profileSources()), - len(initial_sources) + 1 + len(initial_sources) + 1, + ) + self.assertEqual( + QgsApplication.profileSourceRegistry().profileSources()[-1], source ) - self.assertEqual(QgsApplication.profileSourceRegistry().profileSources()[-1], source) QgsApplication.profileSourceRegistry().unregisterProfileSource(source) self.assertEqual( - QgsApplication.profileSourceRegistry().profileSources(), - initial_sources + QgsApplication.profileSourceRegistry().profileSources(), initial_sources ) def test_generate_profile_from_custom_source(self): curve = QgsLineString() - curve.fromWkt("LINESTRING (2584085.816 1216473.232, 2579969.567 1218027.326, 2576819.377 1220589.481)") + curve.fromWkt( + "LINESTRING (2584085.816 1216473.232, 2579969.567 1218027.326, 2576819.377 1220589.481)" + ) req = QgsProfileRequest(curve) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:2056')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:2056")) source = MyProfileSource() generator = source.createProfileGenerator(req) @@ -226,30 +231,38 @@ def test_generate_profile_from_custom_source(self): self.assertEqual(results.zRange(), QgsDoubleRange(429.3, 1282.7)) self.assertTrue(len(results.asGeometries()), 5) - expected_geoms = [QgsGeometry(QgsPoint(2584085.816, 1216473.232, 454.8)), - QgsGeometry(QgsPoint(2582027.691, 1217250.279, 429.3)), - QgsGeometry(QgsPoint(2579969.567, 1218027.326, 702.5)), - QgsGeometry(QgsPoint(2578394.472, 1219308.404, 857.9)), - QgsGeometry(QgsPoint(2576819.377, 1220589.481, 1282.7))] + expected_geoms = [ + QgsGeometry(QgsPoint(2584085.816, 1216473.232, 454.8)), + QgsGeometry(QgsPoint(2582027.691, 1217250.279, 429.3)), + QgsGeometry(QgsPoint(2579969.567, 1218027.326, 702.5)), + QgsGeometry(QgsPoint(2578394.472, 1219308.404, 857.9)), + QgsGeometry(QgsPoint(2576819.377, 1220589.481, 1282.7)), + ] for i, geom in enumerate(results.asGeometries()): self.checkGeometriesEqual(geom, expected_geoms[i], 0, 0) - features = results.asFeatures(Qgis.ProfileExportType.DistanceVsElevationTable, QgsFeedback()) + features = results.asFeatures( + Qgis.ProfileExportType.DistanceVsElevationTable, QgsFeedback() + ) self.assertEqual(len(features), len(results.distance_to_height)) for feature in features: self.assertEqual(feature.geometry.wkbType(), Qgis.WkbType.PointZ) self.assertTrue(not feature.geometry.isEmpty()) d = feature.attributes["distance"] self.assertIn(d, results.distance_to_height) - self.assertEqual(feature.attributes["elevation"], results.distance_to_height[d]) + self.assertEqual( + feature.attributes["elevation"], results.distance_to_height[d] + ) def test_export_3d_from_custom_source(self): source = MyProfileSource() curve = QgsLineString() - curve.fromWkt("LINESTRING (2584085.816 1216473.232, 2579969.567 1218027.326, 2576819.377 1220589.481)") + curve.fromWkt( + "LINESTRING (2584085.816 1216473.232, 2579969.567 1218027.326, 2576819.377 1220589.481)" + ) req = QgsProfileRequest(curve) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:2056')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:2056")) exporter = QgsProfileExporter([source], req, Qgis.ProfileExportType.Features3D) exporter.run(QgsFeedback()) @@ -268,9 +281,11 @@ def test_export_3d_from_custom_source(self): def test_export_2d_from_custom_source(self): source = MyProfileSource() curve = QgsLineString() - curve.fromWkt("LINESTRING (2584085.816 1216473.232, 2579969.567 1218027.326, 2576819.377 1220589.481)") + curve.fromWkt( + "LINESTRING (2584085.816 1216473.232, 2579969.567 1218027.326, 2576819.377 1220589.481)" + ) req = QgsProfileRequest(curve) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:2056')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:2056")) exporter = QgsProfileExporter([source], req, Qgis.ProfileExportType.Profile2D) exporter.run(QgsFeedback()) @@ -285,7 +300,7 @@ def test_export_2d_from_custom_source(self): 2199.9: 429.3, 4399.9: 702.5, 6430.1: 857.9, - 8460.4: 1282.7 + 8460.4: 1282.7, } for i, feature in enumerate(layer.getFeatures()): geom = feature.geometry().constGet() @@ -296,11 +311,15 @@ def test_export_2d_from_custom_source(self): def test_export_distance_elevation_from_custom_source(self): source = MyProfileSource() curve = QgsLineString() - curve.fromWkt("LINESTRING (2584085.816 1216473.232, 2579969.567 1218027.326, 2576819.377 1220589.481)") + curve.fromWkt( + "LINESTRING (2584085.816 1216473.232, 2579969.567 1218027.326, 2576819.377 1220589.481)" + ) req = QgsProfileRequest(curve) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:2056')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:2056")) - exporter = QgsProfileExporter([source], req, Qgis.ProfileExportType.DistanceVsElevationTable) + exporter = QgsProfileExporter( + [source], req, Qgis.ProfileExportType.DistanceVsElevationTable + ) exporter.run(QgsFeedback()) layers = exporter.toLayers() self.assertEqual(len(layers), 1) @@ -314,7 +333,7 @@ def test_export_distance_elevation_from_custom_source(self): 2199.9: 429.3, 4399.9: 702.5, 6430.1: 857.9, - 8460.4: 1282.7 + 8460.4: 1282.7, } expected_z = list(expected_values.values()) for i, feature in enumerate(layer.getFeatures()): @@ -329,7 +348,9 @@ def test_profile_canvas_custom_source(self): canvas.setProject(QgsProject.instance()) canvas.setCrs(QgsCoordinateReferenceSystem("EPSG:2056")) curve = QgsLineString() - curve.fromWkt("LINESTRING (2584085.816 1216473.232, 2579969.567 1218027.326, 2576819.377 1220589.481)") + curve.fromWkt( + "LINESTRING (2584085.816 1216473.232, 2579969.567 1218027.326, 2576819.377 1220589.481)" + ) canvas.setProfileCurve(curve.clone()) spy = QSignalSpy(canvas.activeJobCountChanged) self.assertTrue(spy.isValid()) @@ -340,12 +361,24 @@ def test_profile_canvas_custom_source(self): spy.wait() distance_range = canvas.visibleDistanceRange() - self.assertTrue(distance_range.contains(0), f"Distance 0 (min) not included in range ({distance_range})") - self.assertTrue(distance_range.contains(8460.4), f"Distance 8460.4 (max) not included in range ({distance_range})") + self.assertTrue( + distance_range.contains(0), + f"Distance 0 (min) not included in range ({distance_range})", + ) + self.assertTrue( + distance_range.contains(8460.4), + f"Distance 8460.4 (max) not included in range ({distance_range})", + ) elevation_range = canvas.visibleElevationRange() - self.assertTrue(elevation_range.contains(429.3), f"Elevation 429.3 (min) not included in range ({elevation_range})") - self.assertTrue(elevation_range.contains(1282.7), f"Elevation 1282.7 (max) not included in range ({elevation_range})") + self.assertTrue( + elevation_range.contains(429.3), + f"Elevation 429.3 (min) not included in range ({elevation_range})", + ) + self.assertTrue( + elevation_range.contains(1282.7), + f"Elevation 1282.7 (max) not included in range ({elevation_range})", + ) QgsApplication.profileSourceRegistry().unregisterProfileSource(source) def test_layout_item_profile_custom_source(self): @@ -364,7 +397,8 @@ def test_layout_item_profile_custom_source(self): curve = QgsLineString() curve.fromWkt( - "LINESTRING (2584085.816 1216473.232, 2579969.567 1218027.326, 2576819.377 1220589.481)") + "LINESTRING (2584085.816 1216473.232, 2579969.567 1218027.326, 2576819.377 1220589.481)" + ) profile_item.setProfileCurve(curve) profile_item.setCrs(QgsCoordinateReferenceSystem("EPSG:2056")) @@ -375,9 +409,12 @@ def test_layout_item_profile_custom_source(self): profile_item.plot().xAxis().setGridIntervalMajor(1000) profile_item.plot().xAxis().setGridIntervalMinor(500) - profile_item.plot().xAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffaaff', 'width': 2})) + profile_item.plot().xAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffaaff", "width": 2}) + ) profile_item.plot().xAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) format = QgsTextFormat() format.setFont(QgsFontUtils.getStandardTestFont("Bold")) @@ -389,21 +426,25 @@ def test_layout_item_profile_custom_source(self): profile_item.plot().yAxis().setGridIntervalMajor(1000) profile_item.plot().yAxis().setGridIntervalMinor(500) - profile_item.plot().yAxis().setGridMajorSymbol(QgsLineSymbol.createSimple({'color': '#ffffaa', 'width': 2})) + profile_item.plot().yAxis().setGridMajorSymbol( + QgsLineSymbol.createSimple({"color": "#ffffaa", "width": 2}) + ) profile_item.plot().yAxis().setGridMinorSymbol( - QgsLineSymbol.createSimple({'color': '#aaffaa', 'width': 2})) + QgsLineSymbol.createSimple({"color": "#aaffaa", "width": 2}) + ) profile_item.plot().yAxis().setTextFormat(format) profile_item.plot().yAxis().setLabelInterval(500) profile_item.plot().setChartBorderSymbol( - QgsFillSymbol.createSimple({'style': 'no', 'color': '#aaffaa', 'width_border': 2})) - - self.assertTrue( - self.render_layout_check('custom_profile', layout) + QgsFillSymbol.createSimple( + {"style": "no", "color": "#aaffaa", "width_border": 2} + ) ) + + self.assertTrue(self.render_layout_check("custom_profile", layout)) QgsApplication.profileSourceRegistry().unregisterProfileSource(source) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsproject.py b/tests/src/python/test_qgsproject.py index 4b2debf226d8..4da8f3309416 100644 --- a/tests/src/python/test_qgsproject.py +++ b/tests/src/python/test_qgsproject.py @@ -6,9 +6,9 @@ (at your option) any later version. """ -__author__ = 'Sebastian Dietrich' -__date__ = '19/11/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' +__author__ = "Sebastian Dietrich" +__date__ = "19/11/2015" +__copyright__ = "Copyright 2015, The QGIS Project" import codecs import os @@ -79,8 +79,8 @@ def test_makeKeyTokens_(self): # generate the characters that are allowed at the start of a token (and at every other position) validStartChars = ":_" charRanges = [ - (ord('a'), ord('z')), - (ord('A'), ord('Z')), + (ord("a"), ord("z")), + (ord("A"), ord("Z")), (0x00F8, 0x02FF), (0x0370, 0x037D), (0x037F, 0x1FFF), @@ -99,7 +99,7 @@ def test_makeKeyTokens_(self): # generate the characters that are only allowed inside a token, not at the start validInlineChars = "-.\xB7" charRanges = [ - (ord('0'), ord('9')), + (ord("0"), ord("9")), (0x0300, 0x036F), (0x203F, 0x2040), ] @@ -146,7 +146,7 @@ def catchMessage(self): def testClear(self): prj = QgsProject.instance() - prj.setTitle('xxx') + prj.setTitle("xxx") spy = QSignalSpy(prj.cleared) prj.clear() self.assertEqual(len(spy), 1) @@ -157,8 +157,8 @@ def testCrs(self): prj.clear() self.assertFalse(prj.crs().isValid()) - prj.setCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:3111')) - self.assertEqual(prj.crs().authid(), 'EPSG:3111') + prj.setCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs("EPSG:3111")) + self.assertEqual(prj.crs().authid(), "EPSG:3111") def test_vertical_crs(self): project = QgsProject() @@ -166,41 +166,41 @@ def test_vertical_crs(self): spy = QSignalSpy(project.verticalCrsChanged) # not a vertical crs - ok, err = project.setVerticalCrs( - QgsCoordinateReferenceSystem('EPSG:3111')) + ok, err = project.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertFalse(ok) - self.assertEqual(err, 'Specified CRS is a Projected CRS, not a Vertical CRS') + self.assertEqual(err, "Specified CRS is a Projected CRS, not a Vertical CRS") self.assertFalse(project.verticalCrs().isValid()) - ok, err = project.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:5703')) + ok, err = project.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:5703")) self.assertTrue(ok) - self.assertEqual(project.verticalCrs().authid(), 'EPSG:5703') + self.assertEqual(project.verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy), 1) # try overwriting with same crs, should be no new signal - ok, err = project.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:5703')) + ok, err = project.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:5703")) self.assertTrue(ok) self.assertEqual(len(spy), 1) # check that project vertical crs variables are set in expression context project_scope = project.createExpressionContextScope() - self.assertEqual(project_scope.variable('project_vertical_crs'), 'EPSG:5703') - self.assertIn('vunits=m', - project_scope.variable('project_vertical_crs_definition'), '') + self.assertEqual(project_scope.variable("project_vertical_crs"), "EPSG:5703") + self.assertIn( + "vunits=m", project_scope.variable("project_vertical_crs_definition"), "" + ) self.assertEqual( - project_scope.variable('project_vertical_crs_description'), 'NAVD88 height') - self.assertIn('VERTCRS', - project_scope.variable('project_vertical_crs_wkt'), '') + project_scope.variable("project_vertical_crs_description"), "NAVD88 height" + ) + self.assertIn("VERTCRS", project_scope.variable("project_vertical_crs_wkt"), "") # check that vertical crs is saved/restored with TemporaryDirectory() as d: - self.assertTrue(project.write(os.path.join(d, 'test_vertcrs.qgs'))) + self.assertTrue(project.write(os.path.join(d, "test_vertcrs.qgs"))) project2 = QgsProject() spy2 = QSignalSpy(project2.verticalCrsChanged) - project2.read(os.path.join(d, 'test_vertcrs.qgs')) - self.assertEqual(project2.verticalCrs().authid(), 'EPSG:5703') + project2.read(os.path.join(d, "test_vertcrs.qgs")) + self.assertEqual(project2.verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy2), 1) - project2.read(os.path.join(d, 'test_vertcrs.qgs')) - self.assertEqual(project2.verticalCrs().authid(), 'EPSG:5703') + project2.read(os.path.join(d, "test_vertcrs.qgs")) + self.assertEqual(project2.verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy2), 1) project.clear() @@ -208,7 +208,7 @@ def test_vertical_crs(self): self.assertFalse(project.verticalCrs().isValid()) # test resetting vertical crs back to not set - ok, err = project.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:5703')) + ok, err = project.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:5703")) self.assertTrue(ok) self.assertEqual(len(spy), 3) @@ -226,13 +226,13 @@ def test_vertical_crs_with_compound_project_crs(self): self.assertFalse(project.verticalCrs().isValid()) spy = QSignalSpy(project.verticalCrsChanged) - project.setCrs(QgsCoordinateReferenceSystem('EPSG:5500')) - self.assertEqual(project.crs().authid(), 'EPSG:5500') + project.setCrs(QgsCoordinateReferenceSystem("EPSG:5500")) + self.assertEqual(project.crs().authid(), "EPSG:5500") # QgsProject.verticalCrs() should return the vertical part of the # compound CRS - self.assertEqual(project.verticalCrs().authid(), 'EPSG:5703') + self.assertEqual(project.verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy), 1) - other_vert_crs = QgsCoordinateReferenceSystem('ESRI:115700') + other_vert_crs = QgsCoordinateReferenceSystem("ESRI:115700") self.assertTrue(other_vert_crs.isValid()) self.assertEqual(other_vert_crs.type(), Qgis.CrsType.Vertical) @@ -241,34 +241,42 @@ def test_vertical_crs_with_compound_project_crs(self): # precedence ok, err = project.setVerticalCrs(other_vert_crs) self.assertFalse(ok) - self.assertEqual(err, 'Project CRS is a Compound CRS, specified Vertical CRS will be ignored') - self.assertEqual(project.verticalCrs().authid(), 'EPSG:5703') + self.assertEqual( + err, "Project CRS is a Compound CRS, specified Vertical CRS will be ignored" + ) + self.assertEqual(project.verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy), 1) # setting the vertical crs to the vertical component of the compound crs # IS permitted, even though it effectively has no impact... - ok, err = project.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:5703')) + ok, err = project.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:5703")) self.assertTrue(ok) - self.assertEqual(project.verticalCrs().authid(), 'EPSG:5703') + self.assertEqual(project.verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy), 1) # reset horizontal crs to a non-compound crs, now the manually # specified vertical crs should take precedence - project.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) - self.assertEqual(project.verticalCrs().authid(), 'EPSG:5703') + project.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) + self.assertEqual(project.verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy), 1) # invalid combinations - project.setCrs(QgsCoordinateReferenceSystem('EPSG:4979')) - ok, err = project.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:5711')) + project.setCrs(QgsCoordinateReferenceSystem("EPSG:4979")) + ok, err = project.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:5711")) self.assertFalse(ok) - self.assertEqual(err, 'Project CRS is a Geographic 3D CRS, specified Vertical CRS will be ignored') - self.assertEqual(project.crs3D().authid(), 'EPSG:4979') + self.assertEqual( + err, + "Project CRS is a Geographic 3D CRS, specified Vertical CRS will be ignored", + ) + self.assertEqual(project.crs3D().authid(), "EPSG:4979") - project.setCrs(QgsCoordinateReferenceSystem('EPSG:4978')) - ok, err = project.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:5711')) + project.setCrs(QgsCoordinateReferenceSystem("EPSG:4978")) + ok, err = project.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:5711")) self.assertFalse(ok) - self.assertEqual(err, 'Project CRS is a Geocentric CRS, specified Vertical CRS will be ignored') - self.assertEqual(project.crs3D().authid(), 'EPSG:4978') + self.assertEqual( + err, + "Project CRS is a Geocentric CRS, specified Vertical CRS will be ignored", + ) + self.assertEqual(project.crs3D().authid(), "EPSG:4978") def test_vertical_crs_with_projected3d_project_crs(self): """ @@ -280,45 +288,47 @@ def test_vertical_crs_with_projected3d_project_crs(self): spy = QSignalSpy(project.verticalCrsChanged) - projected3d_crs = QgsCoordinateReferenceSystem.fromWkt("PROJCRS[\"NAD83(HARN) / Oregon GIC Lambert (ft)\",\n" - " BASEGEOGCRS[\"NAD83(HARN)\",\n" - " DATUM[\"NAD83 (High Accuracy Reference Network)\",\n" - " ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n" - " LENGTHUNIT[\"metre\",1]]],\n" - " PRIMEM[\"Greenwich\",0,\n" - " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" - " ID[\"EPSG\",4957]],\n" - " CONVERSION[\"unnamed\",\n" - " METHOD[\"Lambert Conic Conformal (2SP)\",\n" - " ID[\"EPSG\",9802]],\n" - " PARAMETER[\"Latitude of false origin\",41.75,\n" - " ANGLEUNIT[\"degree\",0.0174532925199433],\n" - " ID[\"EPSG\",8821]],\n" - " PARAMETER[\"Longitude of false origin\",-120.5,\n" - " ANGLEUNIT[\"degree\",0.0174532925199433],\n" - " ID[\"EPSG\",8822]],\n" - " PARAMETER[\"Latitude of 1st standard parallel\",43,\n" - " ANGLEUNIT[\"degree\",0.0174532925199433],\n" - " ID[\"EPSG\",8823]],\n" - " PARAMETER[\"Latitude of 2nd standard parallel\",45.5,\n" - " ANGLEUNIT[\"degree\",0.0174532925199433],\n" - " ID[\"EPSG\",8824]],\n" - " PARAMETER[\"Easting at false origin\",1312335.958,\n" - " LENGTHUNIT[\"foot\",0.3048],\n" - " ID[\"EPSG\",8826]],\n" - " PARAMETER[\"Northing at false origin\",0,\n" - " LENGTHUNIT[\"foot\",0.3048],\n" - " ID[\"EPSG\",8827]]],\n" - " CS[Cartesian,3],\n" - " AXIS[\"easting\",east,\n" - " ORDER[1],\n" - " LENGTHUNIT[\"foot\",0.3048]],\n" - " AXIS[\"northing\",north,\n" - " ORDER[2],\n" - " LENGTHUNIT[\"foot\",0.3048]],\n" - " AXIS[\"ellipsoidal height (h)\",up,\n" - " ORDER[3],\n" - " LENGTHUNIT[\"foot\",0.3048]]]") + projected3d_crs = QgsCoordinateReferenceSystem.fromWkt( + 'PROJCRS["NAD83(HARN) / Oregon GIC Lambert (ft)",\n' + ' BASEGEOGCRS["NAD83(HARN)",\n' + ' DATUM["NAD83 (High Accuracy Reference Network)",\n' + ' ELLIPSOID["GRS 1980",6378137,298.257222101,\n' + ' LENGTHUNIT["metre",1]]],\n' + ' PRIMEM["Greenwich",0,\n' + ' ANGLEUNIT["degree",0.0174532925199433]],\n' + ' ID["EPSG",4957]],\n' + ' CONVERSION["unnamed",\n' + ' METHOD["Lambert Conic Conformal (2SP)",\n' + ' ID["EPSG",9802]],\n' + ' PARAMETER["Latitude of false origin",41.75,\n' + ' ANGLEUNIT["degree",0.0174532925199433],\n' + ' ID["EPSG",8821]],\n' + ' PARAMETER["Longitude of false origin",-120.5,\n' + ' ANGLEUNIT["degree",0.0174532925199433],\n' + ' ID["EPSG",8822]],\n' + ' PARAMETER["Latitude of 1st standard parallel",43,\n' + ' ANGLEUNIT["degree",0.0174532925199433],\n' + ' ID["EPSG",8823]],\n' + ' PARAMETER["Latitude of 2nd standard parallel",45.5,\n' + ' ANGLEUNIT["degree",0.0174532925199433],\n' + ' ID["EPSG",8824]],\n' + ' PARAMETER["Easting at false origin",1312335.958,\n' + ' LENGTHUNIT["foot",0.3048],\n' + ' ID["EPSG",8826]],\n' + ' PARAMETER["Northing at false origin",0,\n' + ' LENGTHUNIT["foot",0.3048],\n' + ' ID["EPSG",8827]]],\n' + " CS[Cartesian,3],\n" + ' AXIS["easting",east,\n' + " ORDER[1],\n" + ' LENGTHUNIT["foot",0.3048]],\n' + ' AXIS["northing",north,\n' + " ORDER[2],\n" + ' LENGTHUNIT["foot",0.3048]],\n' + ' AXIS["ellipsoidal height (h)",up,\n' + " ORDER[3],\n" + ' LENGTHUNIT["foot",0.3048]]]' + ) self.assertTrue(projected3d_crs.isValid()) project.setCrs(projected3d_crs) self.assertEqual(project.crs().toWkt(), projected3d_crs.toWkt()) @@ -327,7 +337,7 @@ def test_vertical_crs_with_projected3d_project_crs(self): # QgsProject.verticalCrs() should return invalid crs self.assertFalse(project.verticalCrs().isValid()) self.assertEqual(len(spy), 0) - other_vert_crs = QgsCoordinateReferenceSystem('ESRI:115700') + other_vert_crs = QgsCoordinateReferenceSystem("ESRI:115700") self.assertTrue(other_vert_crs.isValid()) self.assertEqual(other_vert_crs.type(), Qgis.CrsType.Vertical) @@ -336,7 +346,10 @@ def test_vertical_crs_with_projected3d_project_crs(self): # precedence ok, err = project.setVerticalCrs(other_vert_crs) self.assertFalse(ok) - self.assertEqual(err, 'Project CRS is a Projected 3D CRS, specified Vertical CRS will be ignored') + self.assertEqual( + err, + "Project CRS is a Projected 3D CRS, specified Vertical CRS will be ignored", + ) self.assertFalse(project.verticalCrs().isValid()) self.assertEqual(len(spy), 0) self.assertEqual(project.crs3D().toWkt(), projected3d_crs.toWkt()) @@ -348,81 +361,80 @@ def test_crs_3d(self): spy = QSignalSpy(project.crs3DChanged) # set project crs to a 2d crs - project.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) + project.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) - self.assertEqual(project.crs3D().authid(), 'EPSG:3111') + self.assertEqual(project.crs3D().authid(), "EPSG:3111") self.assertEqual(len(spy), 1) # don't change, no new signals - project.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) - self.assertEqual(project.crs3D().authid(), 'EPSG:3111') + project.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) + self.assertEqual(project.crs3D().authid(), "EPSG:3111") self.assertEqual(len(spy), 1) # change 2d crs, should be new signals - project.setCrs(QgsCoordinateReferenceSystem('EPSG:3113')) - self.assertEqual(project.crs3D().authid(), 'EPSG:3113') + project.setCrs(QgsCoordinateReferenceSystem("EPSG:3113")) + self.assertEqual(project.crs3D().authid(), "EPSG:3113") self.assertEqual(len(spy), 2) # change vertical crs: # not a vertical crs, no change - ok, err = project.setVerticalCrs( - QgsCoordinateReferenceSystem('EPSG:3111')) + ok, err = project.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertFalse(ok) - self.assertEqual(project.crs3D().authid(), 'EPSG:3113') + self.assertEqual(project.crs3D().authid(), "EPSG:3113") self.assertEqual(len(spy), 2) # valid vertical crs - ok, err = project.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:5703')) + ok, err = project.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:5703")) self.assertTrue(ok) self.assertEqual(project.crs3D().type(), Qgis.CrsType.Compound) # crs3D should be a compound crs - self.assertEqual(project.crs3D().horizontalCrs().authid(), 'EPSG:3113') - self.assertEqual(project.crs3D().verticalCrs().authid(), 'EPSG:5703') + self.assertEqual(project.crs3D().horizontalCrs().authid(), "EPSG:3113") + self.assertEqual(project.crs3D().verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy), 3) # try overwriting with same crs, should be no new signal - ok, err = project.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:5703')) + ok, err = project.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:5703")) self.assertTrue(ok) self.assertEqual(len(spy), 3) # set 2d crs to a compound crs - project.setCrs(QgsCoordinateReferenceSystem('EPSG:5500')) - self.assertEqual(project.crs().authid(), 'EPSG:5500') - self.assertEqual(project.crs3D().authid(), 'EPSG:5500') + project.setCrs(QgsCoordinateReferenceSystem("EPSG:5500")) + self.assertEqual(project.crs().authid(), "EPSG:5500") + self.assertEqual(project.crs3D().authid(), "EPSG:5500") self.assertEqual(len(spy), 4) - project.setCrs(QgsCoordinateReferenceSystem('EPSG:5500')) - self.assertEqual(project.crs().authid(), 'EPSG:5500') - self.assertEqual(project.crs3D().authid(), 'EPSG:5500') + project.setCrs(QgsCoordinateReferenceSystem("EPSG:5500")) + self.assertEqual(project.crs().authid(), "EPSG:5500") + self.assertEqual(project.crs3D().authid(), "EPSG:5500") self.assertEqual(len(spy), 4) # remove vertical crs, should be no change because compound crs is causing vertical crs to be ignored project.setVerticalCrs(QgsCoordinateReferenceSystem()) - self.assertEqual(project.crs3D().authid(), 'EPSG:5500') + self.assertEqual(project.crs3D().authid(), "EPSG:5500") self.assertEqual(len(spy), 4) - project.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:5703')) - self.assertEqual(project.crs3D().authid(), 'EPSG:5500') + project.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:5703")) + self.assertEqual(project.crs3D().authid(), "EPSG:5500") self.assertEqual(len(spy), 4) # set crs back to 2d crs, should be new signal - project.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) - self.assertEqual(project.crs3D().horizontalCrs().authid(), 'EPSG:3111') - self.assertEqual(project.crs3D().verticalCrs().authid(), 'EPSG:5703') + project.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) + self.assertEqual(project.crs3D().horizontalCrs().authid(), "EPSG:3111") + self.assertEqual(project.crs3D().verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy), 5) # check that crs3D is handled correctly during save/restore with TemporaryDirectory() as d: - self.assertTrue(project.write(os.path.join(d, 'test_crs3d.qgs'))) + self.assertTrue(project.write(os.path.join(d, "test_crs3d.qgs"))) project2 = QgsProject() spy2 = QSignalSpy(project2.crs3DChanged) - project2.read(os.path.join(d, 'test_crs3d.qgs')) - self.assertEqual(project2.crs3D().horizontalCrs().authid(), 'EPSG:3111') - self.assertEqual(project2.crs3D().verticalCrs().authid(), 'EPSG:5703') + project2.read(os.path.join(d, "test_crs3d.qgs")) + self.assertEqual(project2.crs3D().horizontalCrs().authid(), "EPSG:3111") + self.assertEqual(project2.crs3D().verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy2), 1) - project2.read(os.path.join(d, 'test_crs3d.qgs')) - self.assertEqual(project2.crs3D().horizontalCrs().authid(), 'EPSG:3111') - self.assertEqual(project2.crs3D().verticalCrs().authid(), 'EPSG:5703') + project2.read(os.path.join(d, "test_crs3d.qgs")) + self.assertEqual(project2.crs3D().horizontalCrs().authid(), "EPSG:3111") + self.assertEqual(project2.crs3D().verticalCrs().authid(), "EPSG:5703") self.assertEqual(len(spy2), 1) project.clear() @@ -433,13 +445,13 @@ def testEllipsoid(self): prj = QgsProject.instance() prj.clear() - prj.setCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:3111')) - prj.setEllipsoid('WGS84') - self.assertEqual(prj.ellipsoid(), 'WGS84') + prj.setCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs("EPSG:3111")) + prj.setEllipsoid("WGS84") + self.assertEqual(prj.ellipsoid(), "WGS84") # if project has NO crs, then ellipsoid should always be none prj.setCrs(QgsCoordinateReferenceSystem()) - self.assertEqual(prj.ellipsoid(), 'NONE') + self.assertEqual(prj.ellipsoid(), "NONE") def testDistanceUnits(self): prj = QgsProject.instance() @@ -457,27 +469,41 @@ def testAreaUnits(self): def testReadEntry(self): prj = QgsProject.instance() - prj.read(os.path.join(TEST_DATA_DIR, 'labeling/test-labeling.qgs')) + prj.read(os.path.join(TEST_DATA_DIR, "labeling/test-labeling.qgs")) # add a test entry list prj.writeEntry("TestScope", "/TestListProperty", ["Entry1", "Entry2"]) # valid key, valid value - self.assertEqual(prj.readNumEntry("SpatialRefSys", "/ProjectionsEnabled", -1), (0, True)) - self.assertEqual(prj.readEntry("SpatialRefSys", "/ProjectCrs"), ("EPSG:32613", True)) + self.assertEqual( + prj.readNumEntry("SpatialRefSys", "/ProjectionsEnabled", -1), (0, True) + ) + self.assertEqual( + prj.readEntry("SpatialRefSys", "/ProjectCrs"), ("EPSG:32613", True) + ) self.assertEqual(prj.readBoolEntry("PAL", "/ShowingCandidates"), (False, True)) - self.assertEqual(prj.readNumEntry("PAL", "/CandidatesPolygon"), (8., True)) - self.assertEqual(prj.readListEntry("TestScope", "/TestListProperty"), (["Entry1", "Entry2"], True)) + self.assertEqual(prj.readNumEntry("PAL", "/CandidatesPolygon"), (8.0, True)) + self.assertEqual( + prj.readListEntry("TestScope", "/TestListProperty"), + (["Entry1", "Entry2"], True), + ) # invalid key - self.assertEqual(prj.readNumEntry("SpatialRefSys", "/InvalidKey", -1), (-1, False)) - self.assertEqual(prj.readEntry("SpatialRefSys", "/InvalidKey", "wrong"), ("wrong", False)) + self.assertEqual( + prj.readNumEntry("SpatialRefSys", "/InvalidKey", -1), (-1, False) + ) + self.assertEqual( + prj.readEntry("SpatialRefSys", "/InvalidKey", "wrong"), ("wrong", False) + ) self.assertEqual(prj.readBoolEntry("PAL", "/InvalidKey", True), (True, False)) - self.assertEqual(prj.readDoubleEntry("PAL", "/InvalidKey", 42.), (42., False)) - self.assertEqual(prj.readListEntry("TestScope", "/InvalidKey", ["Default1", "Default2"]), (["Default1", "Default2"], False)) + self.assertEqual(prj.readDoubleEntry("PAL", "/InvalidKey", 42.0), (42.0, False)) + self.assertEqual( + prj.readListEntry("TestScope", "/InvalidKey", ["Default1", "Default2"]), + (["Default1", "Default2"], False), + ) def testEmbeddedGroup(self): - testdata_path = unitTestDataPath('embedded_groups') + '/' + testdata_path = unitTestDataPath("embedded_groups") + "/" prj_path = os.path.join(testdata_path, "project2.qgs") prj = QgsProject() @@ -487,64 +513,68 @@ def testEmbeddedGroup(self): self.assertEqual(len(layer_tree_group.findLayerIds()), 2) for layer_id in layer_tree_group.findLayerIds(): name = prj.mapLayer(layer_id).name() - self.assertIn(name, ['polys', 'lines']) - if name == 'polys': - self.assertTrue(layer_tree_group.findLayer(layer_id).itemVisibilityChecked()) - elif name == 'lines': - self.assertFalse(layer_tree_group.findLayer(layer_id).itemVisibilityChecked()) + self.assertIn(name, ["polys", "lines"]) + if name == "polys": + self.assertTrue( + layer_tree_group.findLayer(layer_id).itemVisibilityChecked() + ) + elif name == "lines": + self.assertFalse( + layer_tree_group.findLayer(layer_id).itemVisibilityChecked() + ) def testInstance(self): - """ test retrieving global instance """ + """test retrieving global instance""" self.assertTrue(QgsProject.instance()) # register a layer to the singleton - QgsProject.instance().addMapLayer(createLayer('test')) + QgsProject.instance().addMapLayer(createLayer("test")) # check that the same instance is returned - self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1) + self.assertEqual(len(QgsProject.instance().mapLayersByName("test")), 1) QgsProject.instance().removeAllMapLayers() def test_addMapLayer(self): - """ test adding individual map layers to registry """ + """test adding individual map layers to registry""" QgsProject.instance().removeAllMapLayers() - l1 = createLayer('test') + l1 = createLayer("test") self.assertEqual(QgsProject.instance().addMapLayer(l1), l1) - self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1) + self.assertEqual(len(QgsProject.instance().mapLayersByName("test")), 1) self.assertEqual(QgsProject.instance().count(), 1) # adding a second layer should leave existing layers intact - l2 = createLayer('test2') + l2 = createLayer("test2") self.assertEqual(QgsProject.instance().addMapLayer(l2), l2) - self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1) - self.assertEqual(len(QgsProject.instance().mapLayersByName('test2')), 1) + self.assertEqual(len(QgsProject.instance().mapLayersByName("test")), 1) + self.assertEqual(len(QgsProject.instance().mapLayersByName("test2")), 1) self.assertEqual(QgsProject.instance().count(), 2) QgsProject.instance().removeAllMapLayers() def test_addMapLayerAlreadyAdded(self): - """ test that already added layers can't be readded to registry """ + """test that already added layers can't be readded to registry""" QgsProject.instance().removeAllMapLayers() - l1 = createLayer('test') + l1 = createLayer("test") QgsProject.instance().addMapLayer(l1) - self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1) + self.assertEqual(len(QgsProject.instance().mapLayersByName("test")), 1) self.assertEqual(QgsProject.instance().count(), 1) self.assertEqual(QgsProject.instance().addMapLayer(l1), None) - self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1) + self.assertEqual(len(QgsProject.instance().mapLayersByName("test")), 1) self.assertEqual(QgsProject.instance().count(), 1) QgsProject.instance().removeAllMapLayers() def test_addMapLayerInvalid(self): - """ test that invalid map layers can be added to registry """ + """test that invalid map layers can be added to registry""" QgsProject.instance().removeAllMapLayers() - vl = QgsVectorLayer("Point?field=x:string", 'test', "xxx") + vl = QgsVectorLayer("Point?field=x:string", "test", "xxx") self.assertEqual(QgsProject.instance().addMapLayer(vl), vl) self.assertNotIn(vl, QgsProject.instance().mapLayers(True).values()) - self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1) + self.assertEqual(len(QgsProject.instance().mapLayersByName("test")), 1) self.assertEqual(QgsProject.instance().count(), 1) self.assertEqual(QgsProject.instance().validCount(), 0) @@ -553,7 +583,7 @@ def test_addMapLayerInvalid(self): QgsProject.instance().removeAllMapLayers() def test_addMapLayerSignals(self): - """ test that signals are correctly emitted when adding map layer""" + """test that signals are correctly emitted when adding map layer""" QgsProject.instance().removeAllMapLayers() @@ -561,7 +591,7 @@ def test_addMapLayerSignals(self): layers_added_spy = QSignalSpy(QgsProject.instance().layersAdded) legend_layers_added_spy = QSignalSpy(QgsProject.instance().legendLayersAdded) - l1 = createLayer('test') + l1 = createLayer("test") QgsProject.instance().addMapLayer(l1) # can't seem to actually test the data which was emitted, so best we can do is test @@ -571,7 +601,7 @@ def test_addMapLayerSignals(self): self.assertEqual(len(legend_layers_added_spy), 1) # layer not added to legend - QgsProject.instance().addMapLayer(createLayer('test2'), False) + QgsProject.instance().addMapLayer(createLayer("test2"), False) self.assertEqual(len(layer_was_added_spy), 2) self.assertEqual(len(layers_added_spy), 2) self.assertEqual(len(legend_layers_added_spy), 1) @@ -584,65 +614,65 @@ def test_addMapLayerSignals(self): self.assertEqual(len(legend_layers_added_spy), 1) def test_addMapLayers(self): - """ test adding multiple map layers to registry """ + """test adding multiple map layers to registry""" QgsProject.instance().removeAllMapLayers() - l1 = createLayer('test') - l2 = createLayer('test2') + l1 = createLayer("test") + l2 = createLayer("test2") self.assertEqual(set(QgsProject.instance().addMapLayers([l1, l2])), {l1, l2}) - self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1) - self.assertEqual(len(QgsProject.instance().mapLayersByName('test2')), 1) + self.assertEqual(len(QgsProject.instance().mapLayersByName("test")), 1) + self.assertEqual(len(QgsProject.instance().mapLayersByName("test2")), 1) self.assertEqual(QgsProject.instance().count(), 2) # adding more layers should leave existing layers intact - l3 = createLayer('test3') - l4 = createLayer('test4') + l3 = createLayer("test3") + l4 = createLayer("test4") self.assertEqual(set(QgsProject.instance().addMapLayers([l3, l4])), {l3, l4}) - self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1) - self.assertEqual(len(QgsProject.instance().mapLayersByName('test2')), 1) - self.assertEqual(len(QgsProject.instance().mapLayersByName('test3')), 1) - self.assertEqual(len(QgsProject.instance().mapLayersByName('test4')), 1) + self.assertEqual(len(QgsProject.instance().mapLayersByName("test")), 1) + self.assertEqual(len(QgsProject.instance().mapLayersByName("test2")), 1) + self.assertEqual(len(QgsProject.instance().mapLayersByName("test3")), 1) + self.assertEqual(len(QgsProject.instance().mapLayersByName("test4")), 1) self.assertEqual(QgsProject.instance().count(), 4) QgsProject.instance().removeAllMapLayers() def test_addMapLayersInvalid(self): - """ test that invalid map layers can be added to registry """ + """test that invalid map layers can be added to registry""" QgsProject.instance().removeAllMapLayers() - vl = QgsVectorLayer("Point?field=x:string", 'test', "xxx") + vl = QgsVectorLayer("Point?field=x:string", "test", "xxx") self.assertEqual(QgsProject.instance().addMapLayers([vl]), [vl]) self.assertNotIn(vl, QgsProject.instance().mapLayers(True).values()) - self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1) + self.assertEqual(len(QgsProject.instance().mapLayersByName("test")), 1) self.assertEqual(QgsProject.instance().count(), 1) self.assertEqual(QgsProject.instance().validCount(), 0) QgsProject.instance().removeAllMapLayers() def test_addMapLayersAlreadyAdded(self): - """ test that already added layers can't be readded to registry """ + """test that already added layers can't be readded to registry""" QgsProject.instance().removeAllMapLayers() - l1 = createLayer('test') + l1 = createLayer("test") self.assertEqual(QgsProject.instance().addMapLayers([l1]), [l1]) - self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1) + self.assertEqual(len(QgsProject.instance().mapLayersByName("test")), 1) self.assertEqual(QgsProject.instance().count(), 1) self.assertEqual(QgsProject.instance().addMapLayers([l1]), []) - self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1) + self.assertEqual(len(QgsProject.instance().mapLayersByName("test")), 1) self.assertEqual(QgsProject.instance().count(), 1) QgsProject.instance().removeAllMapLayers() def test_addMapLayersSignals(self): - """ test that signals are correctly emitted when adding map layers""" + """test that signals are correctly emitted when adding map layers""" QgsProject.instance().removeAllMapLayers() layer_was_added_spy = QSignalSpy(QgsProject.instance().layerWasAdded) layers_added_spy = QSignalSpy(QgsProject.instance().layersAdded) legend_layers_added_spy = QSignalSpy(QgsProject.instance().legendLayersAdded) - l1 = createLayer('test') - l2 = createLayer('test2') + l1 = createLayer("test") + l2 = createLayer("test2") QgsProject.instance().addMapLayers([l1, l2]) # can't seem to actually test the data which was emitted, so best we can do is test @@ -652,7 +682,9 @@ def test_addMapLayersSignals(self): self.assertEqual(len(legend_layers_added_spy), 1) # layer not added to legend - QgsProject.instance().addMapLayers([createLayer('test3'), createLayer('test4')], False) + QgsProject.instance().addMapLayers( + [createLayer("test3"), createLayer("test4")], False + ) self.assertEqual(len(layer_was_added_spy), 4) self.assertEqual(len(layers_added_spy), 2) self.assertEqual(len(legend_layers_added_spy), 1) @@ -665,77 +697,77 @@ def test_addMapLayersSignals(self): self.assertEqual(len(legend_layers_added_spy), 1) def test_mapLayerById(self): - """ test retrieving map layer by ID """ + """test retrieving map layer by ID""" QgsProject.instance().removeAllMapLayers() # test no crash with empty registry - self.assertEqual(QgsProject.instance().mapLayer('bad'), None) + self.assertEqual(QgsProject.instance().mapLayer("bad"), None) self.assertEqual(QgsProject.instance().mapLayer(None), None) - l1 = createLayer('test') - l2 = createLayer('test2') + l1 = createLayer("test") + l2 = createLayer("test2") QgsProject.instance().addMapLayers([l1, l2]) - self.assertEqual(QgsProject.instance().mapLayer('bad'), None) + self.assertEqual(QgsProject.instance().mapLayer("bad"), None) self.assertEqual(QgsProject.instance().mapLayer(None), None) self.assertEqual(QgsProject.instance().mapLayer(l1.id()), l1) self.assertEqual(QgsProject.instance().mapLayer(l2.id()), l2) def test_mapLayersByName(self): - """ test retrieving map layer by name """ + """test retrieving map layer by name""" p = QgsProject() # test no crash with empty registry - self.assertEqual(p.mapLayersByName('bad'), []) + self.assertEqual(p.mapLayersByName("bad"), []) self.assertEqual(p.mapLayersByName(None), []) - l1 = createLayer('test') - l2 = createLayer('test2') + l1 = createLayer("test") + l2 = createLayer("test2") p.addMapLayers([l1, l2]) - self.assertEqual(p.mapLayersByName('bad'), []) + self.assertEqual(p.mapLayersByName("bad"), []) self.assertEqual(p.mapLayersByName(None), []) - self.assertEqual(p.mapLayersByName('test'), [l1]) - self.assertEqual(p.mapLayersByName('test2'), [l2]) + self.assertEqual(p.mapLayersByName("test"), [l1]) + self.assertEqual(p.mapLayersByName("test2"), [l2]) # duplicate name - l3 = createLayer('test') + l3 = createLayer("test") p.addMapLayer(l3) - self.assertEqual(set(p.mapLayersByName('test')), {l1, l3}) + self.assertEqual(set(p.mapLayersByName("test")), {l1, l3}) def test_mapLayers(self): - """ test retrieving map layers list """ + """test retrieving map layers list""" QgsProject.instance().removeAllMapLayers() # test no crash with empty registry self.assertEqual(QgsProject.instance().mapLayers(), {}) - l1 = createLayer('test') - l2 = createLayer('test2') + l1 = createLayer("test") + l2 = createLayer("test2") QgsProject.instance().addMapLayers([l1, l2]) self.assertEqual(QgsProject.instance().mapLayers(), {l1.id(): l1, l2.id(): l2}) def test_removeMapLayersById(self): - """ test removing map layers by ID """ + """test removing map layers by ID""" QgsProject.instance().removeAllMapLayers() # test no crash with empty registry - QgsProject.instance().removeMapLayers(['bad']) + QgsProject.instance().removeMapLayers(["bad"]) QgsProject.instance().removeMapLayers([None]) - l1 = createLayer('test') - l2 = createLayer('test2') - l3 = createLayer('test3') + l1 = createLayer("test") + l2 = createLayer("test2") + l3 = createLayer("test3") QgsProject.instance().addMapLayers([l1, l2, l3]) self.assertEqual(QgsProject.instance().count(), 3) # remove bad layers - QgsProject.instance().removeMapLayers(['bad']) + QgsProject.instance().removeMapLayers(["bad"]) self.assertEqual(QgsProject.instance().count(), 3) QgsProject.instance().removeMapLayers([None]) self.assertEqual(QgsProject.instance().count(), 3) @@ -757,23 +789,23 @@ def test_removeMapLayersById(self): self.assertTrue(sip.isdeleted(l2)) # try removing a layer not in the registry - l4 = createLayer('test4') + l4 = createLayer("test4") QgsProject.instance().removeMapLayers([l4.id()]) self.assertFalse(sip.isdeleted(l4)) # fails on qt5 due to removeMapLayers list type conversion - needs a PyName alias # added to removeMapLayers for QGIS 3.0 - @QgisTestCase.expectedFailure(QT_VERSION_STR[0] == '5') + @QgisTestCase.expectedFailure(QT_VERSION_STR[0] == "5") def test_removeMapLayersByLayer(self): - """ test removing map layers by layer""" + """test removing map layers by layer""" QgsProject.instance().removeAllMapLayers() # test no crash with empty registry QgsProject.instance().removeMapLayers([None]) - l1 = createLayer('test') - l2 = createLayer('test2') - l3 = createLayer('test3') + l1 = createLayer("test") + l2 = createLayer("test2") + l3 = createLayer("test3") QgsProject.instance().addMapLayers([l1, l2, l3]) self.assertEqual(QgsProject.instance().count(), 3) @@ -796,21 +828,21 @@ def test_removeMapLayersByLayer(self): self.assertTrue(sip.isdeleted(l3)) def test_removeMapLayerById(self): - """ test removing a map layer by ID """ + """test removing a map layer by ID""" QgsProject.instance().removeAllMapLayers() # test no crash with empty registry - QgsProject.instance().removeMapLayer('bad') + QgsProject.instance().removeMapLayer("bad") QgsProject.instance().removeMapLayer(None) - l1 = createLayer('test') - l2 = createLayer('test2') + l1 = createLayer("test") + l2 = createLayer("test2") QgsProject.instance().addMapLayers([l1, l2]) self.assertEqual(QgsProject.instance().count(), 2) # remove bad layers - QgsProject.instance().removeMapLayer('bad') + QgsProject.instance().removeMapLayer("bad") self.assertEqual(QgsProject.instance().count(), 2) QgsProject.instance().removeMapLayer(None) self.assertEqual(QgsProject.instance().count(), 2) @@ -832,20 +864,20 @@ def test_removeMapLayerById(self): self.assertTrue(sip.isdeleted(l2)) # try removing a layer not in the registry - l3 = createLayer('test3') + l3 = createLayer("test3") QgsProject.instance().removeMapLayer(l3.id()) self.assertFalse(sip.isdeleted(l3)) def test_removeMapLayerByLayer(self): - """ test removing a map layer by layer """ + """test removing a map layer by layer""" QgsProject.instance().removeAllMapLayers() # test no crash with empty registry - QgsProject.instance().removeMapLayer('bad') + QgsProject.instance().removeMapLayer("bad") QgsProject.instance().removeMapLayer(None) - l1 = createLayer('test') - l2 = createLayer('test2') + l1 = createLayer("test") + l2 = createLayer("test2") QgsProject.instance().addMapLayers([l1, l2]) self.assertEqual(QgsProject.instance().count(), 2) @@ -853,7 +885,7 @@ def test_removeMapLayerByLayer(self): # remove bad layers QgsProject.instance().removeMapLayer(None) self.assertEqual(QgsProject.instance().count(), 2) - l3 = createLayer('test3') + l3 = createLayer("test3") QgsProject.instance().removeMapLayer(l3) self.assertEqual(QgsProject.instance().count(), 2) @@ -870,38 +902,44 @@ def test_removeMapLayerByLayer(self): self.assertTrue(sip.isdeleted(l2)) # try removing a layer not in the registry - l3 = createLayer('test3') + l3 = createLayer("test3") QgsProject.instance().removeMapLayer(l3) self.assertFalse(sip.isdeleted(l3)) def test_removeAllMapLayers(self): - """ test removing all map layers from registry """ + """test removing all map layers from registry""" QgsProject.instance().removeAllMapLayers() - l1 = createLayer('test') - l2 = createLayer('test2') + l1 = createLayer("test") + l2 = createLayer("test2") QgsProject.instance().addMapLayers([l1, l2]) self.assertEqual(QgsProject.instance().count(), 2) QgsProject.instance().removeAllMapLayers() self.assertEqual(QgsProject.instance().count(), 0) - self.assertEqual(QgsProject.instance().mapLayersByName('test'), []) - self.assertEqual(QgsProject.instance().mapLayersByName('test2'), []) + self.assertEqual(QgsProject.instance().mapLayersByName("test"), []) + self.assertEqual(QgsProject.instance().mapLayersByName("test2"), []) def test_addRemoveLayersSignals(self): - """ test that signals are correctly emitted when removing map layers""" + """test that signals are correctly emitted when removing map layers""" QgsProject.instance().removeAllMapLayers() - layers_will_be_removed_spy = QSignalSpy(QgsProject.instance().layersWillBeRemoved) - layer_will_be_removed_spy_str = QSignalSpy(QgsProject.instance().layerWillBeRemoved[str]) - layer_will_be_removed_spy_layer = QSignalSpy(QgsProject.instance().layerWillBeRemoved[QgsMapLayer]) + layers_will_be_removed_spy = QSignalSpy( + QgsProject.instance().layersWillBeRemoved + ) + layer_will_be_removed_spy_str = QSignalSpy( + QgsProject.instance().layerWillBeRemoved[str] + ) + layer_will_be_removed_spy_layer = QSignalSpy( + QgsProject.instance().layerWillBeRemoved[QgsMapLayer] + ) layers_removed_spy = QSignalSpy(QgsProject.instance().layersRemoved) layer_removed_spy = QSignalSpy(QgsProject.instance().layerRemoved) remove_all_spy = QSignalSpy(QgsProject.instance().removeAll) - l1 = createLayer('l1') - l2 = createLayer('l2') - l3 = createLayer('l3') - l4 = createLayer('l4') + l1 = createLayer("l1") + l2 = createLayer("l2") + l3 = createLayer("l3") + l4 = createLayer("l4") QgsProject.instance().addMapLayers([l1, l2, l3, l4]) # remove 1 layer @@ -936,7 +974,7 @@ def test_addRemoveLayersSignals(self): self.assertEqual(len(remove_all_spy), 1) # remove some layers which aren't in the registry - QgsProject.instance().removeMapLayers(['asdasd']) + QgsProject.instance().removeMapLayers(["asdasd"]) self.assertEqual(len(layers_will_be_removed_spy), 3) self.assertEqual(len(layer_will_be_removed_spy_str), 4) self.assertEqual(len(layer_will_be_removed_spy_layer), 4) @@ -944,7 +982,7 @@ def test_addRemoveLayersSignals(self): self.assertEqual(len(layer_removed_spy), 4) self.assertEqual(len(remove_all_spy), 1) - l5 = createLayer('test5') + l5 = createLayer("test5") QgsProject.instance().removeMapLayer(l5) self.assertEqual(len(layers_will_be_removed_spy), 3) self.assertEqual(len(layer_will_be_removed_spy_str), 4) @@ -958,17 +996,17 @@ def test_RemoveLayerShouldNotSegFault(self): reg = QgsProject.instance() # Should not segfault - reg.removeMapLayers(['not_exists']) - reg.removeMapLayer('not_exists2') + reg.removeMapLayers(["not_exists"]) + reg.removeMapLayer("not_exists2") # check also that the removal of an unexistent layer does not insert a null layer for k, layer in list(reg.mapLayers().items()): - assert (layer is not None) + assert layer is not None def testTakeLayer(self): # test taking ownership of a layer from the project - l1 = createLayer('l1') - l2 = createLayer('l2') + l1 = createLayer("l1") + l2 = createLayer("l2") p = QgsProject() # add one layer to project @@ -997,7 +1035,9 @@ def testTakeLayer(self): def test_transactionsGroup(self): # Undefined transaction group (wrong provider key). QgsProject.instance().setTransactionMode(Qgis.TransactionMode.AutomaticGroups) - noTg = QgsProject.instance().transactionGroup("provider-key", "database-connection-string") + noTg = QgsProject.instance().transactionGroup( + "provider-key", "database-connection-string" + ) self.assertIsNone(noTg) def test_zip_new_project(self): @@ -1005,7 +1045,7 @@ def test_zip_new_project(self): tmpFile = f"{tmpDir.path()}/project.qgz" # zip with existing file - open(tmpFile, 'a').close() + open(tmpFile, "a").close() project = QgsProject() self.assertTrue(project.write(tmpFile)) @@ -1072,9 +1112,9 @@ def testUpgradeOtfFrom2x(self): Test that upgrading a 2.x project correctly brings across project CRS and OTF transformation settings """ prj = QgsProject.instance() - prj.read(os.path.join(TEST_DATA_DIR, 'projects', 'test_memory_layer_proj.qgs')) + prj.read(os.path.join(TEST_DATA_DIR, "projects", "test_memory_layer_proj.qgs")) self.assertTrue(prj.crs().isValid()) - self.assertEqual(prj.crs().authid(), 'EPSG:2056') + self.assertEqual(prj.crs().authid(), "EPSG:2056") def testSnappingChangedSignal(self): """ @@ -1120,19 +1160,42 @@ def testRelativePaths(self): """ tmpDir = QTemporaryDir() tmpFile = f"{tmpDir.path()}/project.qgs" - copyfile(os.path.join(TEST_DATA_DIR, "points.shp"), os.path.join(tmpDir.path(), "points.shp")) - copyfile(os.path.join(TEST_DATA_DIR, "points.dbf"), os.path.join(tmpDir.path(), "points.dbf")) - copyfile(os.path.join(TEST_DATA_DIR, "points.shx"), os.path.join(tmpDir.path(), "points.shx")) - copyfile(os.path.join(TEST_DATA_DIR, "lines.shp"), os.path.join(tmpDir.path(), "lines.shp")) - copyfile(os.path.join(TEST_DATA_DIR, "lines.dbf"), os.path.join(tmpDir.path(), "lines.dbf")) - copyfile(os.path.join(TEST_DATA_DIR, "lines.shx"), os.path.join(tmpDir.path(), "lines.shx")) - copyfile(os.path.join(TEST_DATA_DIR, "landsat_4326.tif"), os.path.join(tmpDir.path(), "landsat_4326.tif")) + copyfile( + os.path.join(TEST_DATA_DIR, "points.shp"), + os.path.join(tmpDir.path(), "points.shp"), + ) + copyfile( + os.path.join(TEST_DATA_DIR, "points.dbf"), + os.path.join(tmpDir.path(), "points.dbf"), + ) + copyfile( + os.path.join(TEST_DATA_DIR, "points.shx"), + os.path.join(tmpDir.path(), "points.shx"), + ) + copyfile( + os.path.join(TEST_DATA_DIR, "lines.shp"), + os.path.join(tmpDir.path(), "lines.shp"), + ) + copyfile( + os.path.join(TEST_DATA_DIR, "lines.dbf"), + os.path.join(tmpDir.path(), "lines.dbf"), + ) + copyfile( + os.path.join(TEST_DATA_DIR, "lines.shx"), + os.path.join(tmpDir.path(), "lines.shx"), + ) + copyfile( + os.path.join(TEST_DATA_DIR, "landsat_4326.tif"), + os.path.join(tmpDir.path(), "landsat_4326.tif"), + ) project = QgsProject() l0 = QgsVectorLayer(os.path.join(tmpDir.path(), "points.shp"), "points", "ogr") l1 = QgsVectorLayer(os.path.join(tmpDir.path(), "lines.shp"), "lines", "ogr") - l2 = QgsRasterLayer(os.path.join(tmpDir.path(), "landsat_4326.tif"), "landsat", "gdal") + l2 = QgsRasterLayer( + os.path.join(tmpDir.path(), "landsat_4326.tif"), "landsat", "gdal" + ) self.assertTrue(l0.isValid()) self.assertTrue(l1.isValid()) self.assertTrue(l2.isValid()) @@ -1141,7 +1204,7 @@ def testRelativePaths(self): del project with open(tmpFile) as f: - content = ''.join(f.readlines()) + content = "".join(f.readlines()) self.assertIn('source="./lines.shp"', content) self.assertIn('source="./points.shp"', content) self.assertIn('source="./landsat_4326.tif"', content) @@ -1150,13 +1213,16 @@ def testRelativePaths(self): project = QgsProject() self.assertTrue(project.read(tmpFile)) store = project.layerStore() - self.assertEqual({l.name() for l in store.mapLayers().values()}, {'lines', 'landsat', 'points'}) - project.writeEntryBool('Paths', '/Absolute', True) + self.assertEqual( + {l.name() for l in store.mapLayers().values()}, + {"lines", "landsat", "points"}, + ) + project.writeEntryBool("Paths", "/Absolute", True) tmpFile2 = f"{tmpDir.path()}/project2.qgs" self.assertTrue(project.write(tmpFile2)) with open(tmpFile2) as f: - content = ''.join(f.readlines()) + content = "".join(f.readlines()) self.assertIn(f'source="{tmpDir.path()}/lines.shp"', content) self.assertIn(f'source="{tmpDir.path()}/points.shp"', content) self.assertIn(f'source="{tmpDir.path()}/landsat_4326.tif"', content) @@ -1171,33 +1237,38 @@ def testRelativePathsGpkg(self): def _check_datasource(_path): # Verify datasource path stored in the project - ds = ogr.GetDriverByName('GPKG').Open(_path) + ds = ogr.GetDriverByName("GPKG").Open(_path) l = ds.GetLayer(1) - self.assertEqual(l.GetName(), 'qgis_projects') + self.assertEqual(l.GetName(), "qgis_projects") self.assertEqual(l.GetFeatureCount(), 1) f = l.GetFeature(1) - zip_content = BytesIO(codecs.decode(f.GetFieldAsBinary(2), 'hex')) + zip_content = BytesIO(codecs.decode(f.GetFieldAsBinary(2), "hex")) z = ZipFile(zip_content) qgs = z.read(z.filelist[0]) - self.assertEqual(re.findall(b'(.*)?', qgs)[1], - b'./relative_paths_gh30387.gpkg|layername=some_data') + self.assertEqual( + re.findall(b"(.*)?", qgs)[1], + b"./relative_paths_gh30387.gpkg|layername=some_data", + ) with TemporaryDirectory() as d: - path = os.path.join(d, 'relative_paths_gh30387.gpkg') - copyfile(os.path.join(TEST_DATA_DIR, 'projects', 'relative_paths_gh30387.gpkg'), path) + path = os.path.join(d, "relative_paths_gh30387.gpkg") + copyfile( + os.path.join(TEST_DATA_DIR, "projects", "relative_paths_gh30387.gpkg"), + path, + ) project = QgsProject() - l = QgsVectorLayer(path + '|layername=some_data', 'mylayer', 'ogr') + l = QgsVectorLayer(path + "|layername=some_data", "mylayer", "ogr") self.assertTrue(l.isValid()) self.assertTrue(project.addMapLayers([l])) self.assertEqual(project.count(), 1) # Project URI - uri = f'geopackage://{path}?projectName=relative_project' + uri = f"geopackage://{path}?projectName=relative_project" project.setFileName(uri) self.assertTrue(project.write()) # Verify project = QgsProject() self.assertTrue(project.read(uri)) - self.assertEqual(project.writePath(path), './relative_paths_gh30387.gpkg') + self.assertEqual(project.writePath(path), "./relative_paths_gh30387.gpkg") _check_datasource(path) @@ -1206,13 +1277,13 @@ def _check_datasource(_path): with TemporaryDirectory() as d2: # Move it! - path2 = os.path.join(d2, 'relative_paths_gh30387.gpkg') + path2 = os.path.join(d2, "relative_paths_gh30387.gpkg") copyfile(path, path2) # Delete old temporary dir del d # Verify moved project = QgsProject() - uri2 = f'geopackage://{path2}?projectName=relative_project' + uri2 = f"geopackage://{path2}?projectName=relative_project" self.assertTrue(project.read(uri2)) _check_datasource(path2) @@ -1229,19 +1300,42 @@ def testSymbolicLinkInProjectPath(self): """ tmpDir = QTemporaryDir() tmpFile = f"{tmpDir.path()}/project.qgs" - copyfile(os.path.join(TEST_DATA_DIR, "points.shp"), os.path.join(tmpDir.path(), "points.shp")) - copyfile(os.path.join(TEST_DATA_DIR, "points.dbf"), os.path.join(tmpDir.path(), "points.dbf")) - copyfile(os.path.join(TEST_DATA_DIR, "points.shx"), os.path.join(tmpDir.path(), "points.shx")) - copyfile(os.path.join(TEST_DATA_DIR, "lines.shp"), os.path.join(tmpDir.path(), "lines.shp")) - copyfile(os.path.join(TEST_DATA_DIR, "lines.dbf"), os.path.join(tmpDir.path(), "lines.dbf")) - copyfile(os.path.join(TEST_DATA_DIR, "lines.shx"), os.path.join(tmpDir.path(), "lines.shx")) - copyfile(os.path.join(TEST_DATA_DIR, "landsat_4326.tif"), os.path.join(tmpDir.path(), "landsat_4326.tif")) + copyfile( + os.path.join(TEST_DATA_DIR, "points.shp"), + os.path.join(tmpDir.path(), "points.shp"), + ) + copyfile( + os.path.join(TEST_DATA_DIR, "points.dbf"), + os.path.join(tmpDir.path(), "points.dbf"), + ) + copyfile( + os.path.join(TEST_DATA_DIR, "points.shx"), + os.path.join(tmpDir.path(), "points.shx"), + ) + copyfile( + os.path.join(TEST_DATA_DIR, "lines.shp"), + os.path.join(tmpDir.path(), "lines.shp"), + ) + copyfile( + os.path.join(TEST_DATA_DIR, "lines.dbf"), + os.path.join(tmpDir.path(), "lines.dbf"), + ) + copyfile( + os.path.join(TEST_DATA_DIR, "lines.shx"), + os.path.join(tmpDir.path(), "lines.shx"), + ) + copyfile( + os.path.join(TEST_DATA_DIR, "landsat_4326.tif"), + os.path.join(tmpDir.path(), "landsat_4326.tif"), + ) project = QgsProject() l0 = QgsVectorLayer(os.path.join(tmpDir.path(), "points.shp"), "points", "ogr") l1 = QgsVectorLayer(os.path.join(tmpDir.path(), "lines.shp"), "lines", "ogr") - l2 = QgsRasterLayer(os.path.join(tmpDir.path(), "landsat_4326.tif"), "landsat", "gdal") + l2 = QgsRasterLayer( + os.path.join(tmpDir.path(), "landsat_4326.tif"), "landsat", "gdal" + ) self.assertTrue(l0.isValid()) self.assertTrue(l1.isValid()) self.assertTrue(l2.isValid()) @@ -1262,7 +1356,7 @@ def testSymbolicLinkInProjectPath(self): del project with open(tmpFile) as f: - content = ''.join(f.readlines()) + content = "".join(f.readlines()) self.assertIn('source="./lines.shp"', content) self.assertIn('source="./points.shp"', content) self.assertIn('source="./landsat_4326.tif"', content) @@ -1276,7 +1370,7 @@ def testHomePath(self): # simulate save file tmp_dir = QTemporaryDir() tmp_file = f"{tmp_dir.path()}/project.qgs" - with open(tmp_file, 'w') as f: + with open(tmp_file, "w") as f: pass p.setFileName(tmp_file) @@ -1286,73 +1380,76 @@ def testHomePath(self): self.assertEqual(len(path_changed_spy), 1) # manually override home path - p.setPresetHomePath('/tmp/my_path') - self.assertEqual(p.homePath(), '/tmp/my_path') - self.assertEqual(p.presetHomePath(), '/tmp/my_path') + p.setPresetHomePath("/tmp/my_path") + self.assertEqual(p.homePath(), "/tmp/my_path") + self.assertEqual(p.presetHomePath(), "/tmp/my_path") self.assertEqual(len(path_changed_spy), 2) # check project scope scope = QgsExpressionContextUtils.projectScope(p) - self.assertEqual(scope.variable('project_home'), '/tmp/my_path') + self.assertEqual(scope.variable("project_home"), "/tmp/my_path") # no extra signal if path is unchanged - p.setPresetHomePath('/tmp/my_path') - self.assertEqual(p.homePath(), '/tmp/my_path') - self.assertEqual(p.presetHomePath(), '/tmp/my_path') + p.setPresetHomePath("/tmp/my_path") + self.assertEqual(p.homePath(), "/tmp/my_path") + self.assertEqual(p.presetHomePath(), "/tmp/my_path") self.assertEqual(len(path_changed_spy), 2) # setting file name should not affect home path is manually set tmp_file_2 = f"{tmp_dir.path()}/project/project2.qgs" - os.mkdir(tmp_dir.path() + '/project') - with open(tmp_file_2, 'w') as f: + os.mkdir(tmp_dir.path() + "/project") + with open(tmp_file_2, "w") as f: pass p.setFileName(tmp_file_2) - self.assertEqual(p.homePath(), '/tmp/my_path') - self.assertEqual(p.presetHomePath(), '/tmp/my_path') + self.assertEqual(p.homePath(), "/tmp/my_path") + self.assertEqual(p.presetHomePath(), "/tmp/my_path") self.assertEqual(len(path_changed_spy), 2) scope = QgsExpressionContextUtils.projectScope(p) - self.assertEqual(scope.variable('project_home'), '/tmp/my_path') + self.assertEqual(scope.variable("project_home"), "/tmp/my_path") # clear manual path - p.setPresetHomePath('') - self.assertEqual(p.homePath(), tmp_dir.path() + '/project') + p.setPresetHomePath("") + self.assertEqual(p.homePath(), tmp_dir.path() + "/project") self.assertFalse(p.presetHomePath()) self.assertEqual(len(path_changed_spy), 3) scope = QgsExpressionContextUtils.projectScope(p) - self.assertEqual(scope.variable('project_home'), tmp_dir.path() + '/project') + self.assertEqual(scope.variable("project_home"), tmp_dir.path() + "/project") # relative path - p.setPresetHomePath('../home') - self.assertEqual(p.homePath(), tmp_dir.path() + '/home') - self.assertEqual(p.presetHomePath(), '../home') + p.setPresetHomePath("../home") + self.assertEqual(p.homePath(), tmp_dir.path() + "/home") + self.assertEqual(p.presetHomePath(), "../home") self.assertEqual(len(path_changed_spy), 4) scope = QgsExpressionContextUtils.projectScope(p) - self.assertEqual(scope.variable('project_home'), tmp_dir.path() + '/home') + self.assertEqual(scope.variable("project_home"), tmp_dir.path() + "/home") # relative path, no filename - p.setFileName('') - self.assertEqual(p.homePath(), '../home') - self.assertEqual(p.presetHomePath(), '../home') + p.setFileName("") + self.assertEqual(p.homePath(), "../home") + self.assertEqual(p.presetHomePath(), "../home") scope = QgsExpressionContextUtils.projectScope(p) - self.assertEqual(scope.variable('project_home'), '../home') + self.assertEqual(scope.variable("project_home"), "../home") p = QgsProject() path_changed_spy = QSignalSpy(p.homePathChanged) - p.setFileName('/tmp/not/existing/here/path.qgz') + p.setFileName("/tmp/not/existing/here/path.qgz") self.assertFalse(p.presetHomePath()) - self.assertEqual(p.homePath(), '/tmp/not/existing/here') + self.assertEqual(p.homePath(), "/tmp/not/existing/here") self.assertEqual(len(path_changed_spy), 1) # Tests whether the home paths of a GPKG stored project returns the GPKG folder. with TemporaryDirectory() as d: - path = os.path.join(d, 'relative_paths_gh30387.gpkg') - copyfile(os.path.join(TEST_DATA_DIR, 'projects', 'relative_paths_gh30387.gpkg'), path) + path = os.path.join(d, "relative_paths_gh30387.gpkg") + copyfile( + os.path.join(TEST_DATA_DIR, "projects", "relative_paths_gh30387.gpkg"), + path, + ) project = QgsProject() # Project URI - uri = f'geopackage://{path}?projectName=relative_project' + uri = f"geopackage://{path}?projectName=relative_project" project.setFileName(uri) self.assertTrue(project.write()) # Verify @@ -1434,10 +1531,10 @@ def testDirtyBlocker(self): def testCustomLayerOrderFrom2xProject(self): prj = QgsProject.instance() - prj.read(os.path.join(TEST_DATA_DIR, 'layer_rendering_order_issue_qgis3.qgs')) + prj.read(os.path.join(TEST_DATA_DIR, "layer_rendering_order_issue_qgis3.qgs")) - layer_x = prj.mapLayers()['x20180406151213536'] - layer_y = prj.mapLayers()['y20180406151217017'] + layer_x = prj.mapLayers()["x20180406151213536"] + layer_y = prj.mapLayers()["y20180406151217017"] # check layer order tree = prj.layerTreeRoot() @@ -1449,10 +1546,10 @@ def testCustomLayerOrderFrom2xProject(self): def testCustomLayerOrderFrom3xProject(self): prj = QgsProject.instance() - prj.read(os.path.join(TEST_DATA_DIR, 'layer_rendering_order_qgis3_project.qgs')) + prj.read(os.path.join(TEST_DATA_DIR, "layer_rendering_order_qgis3_project.qgs")) - layer_x = prj.mapLayers()['x20180406151213536'] - layer_y = prj.mapLayers()['y20180406151217017'] + layer_x = prj.mapLayers()["x20180406151213536"] + layer_y = prj.mapLayers()["y20180406151217017"] # check layer order tree = prj.layerTreeRoot() @@ -1490,15 +1587,15 @@ def testLayerChangeDirtiesProject(self): self.assertTrue(p.addMapLayers([l])) p.setDirty(False) - l.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) + l.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertTrue(p.isDirty()) p.setDirty(False) - l.setName('test') + l.setName("test") self.assertTrue(p.isDirty()) p.setDirty(False) - self.assertTrue(l.setSubsetString('class=\'a\'')) + self.assertTrue(l.setSubsetString("class='a'")) self.assertTrue(p.isDirty()) def testProjectTitleWithPeriod(self): @@ -1512,8 +1609,8 @@ def testProjectTitleWithPeriod(self): p1 = QgsProject() p1.setFileName(tmpFile2) - self.assertEqual(p0.baseName(), '2.18.21') - self.assertEqual(p1.baseName(), 'qgis-3.2.0') + self.assertEqual(p0.baseName(), "2.18.21") + self.assertEqual(p1.baseName(), "qgis-3.2.0") def testWriteEntry(self): @@ -1523,11 +1620,11 @@ def testWriteEntry(self): # zip with existing file project = QgsProject() query = 'select * from "sample DH" where "sample DH"."Elev" > 130 and "sample DH"."Elev" < 140' - self.assertTrue(project.writeEntry('myscope', 'myentry', query)) + self.assertTrue(project.writeEntry("myscope", "myentry", query)) self.assertTrue(project.write(tmpFile)) self.assertTrue(project.read(tmpFile)) - q, ok = project.readEntry('myscope', 'myentry') + q, ok = project.readEntry("myscope", "myentry") self.assertTrue(ok) self.assertEqual(q, query) @@ -1537,38 +1634,38 @@ def testDirtying(self): # writing a new entry should dirty the project project.setDirty(False) - self.assertTrue(project.writeEntry('myscope', 'myentry', True)) + self.assertTrue(project.writeEntry("myscope", "myentry", True)) self.assertTrue(project.isDirty()) # over-writing a pre-existing entry with the same value should _not_ dirty the project project.setDirty(False) - self.assertTrue(project.writeEntry('myscope', 'myentry', True)) + self.assertTrue(project.writeEntry("myscope", "myentry", True)) self.assertFalse(project.isDirty()) # over-writing a pre-existing entry with a different value should dirty the project project.setDirty(False) - self.assertTrue(project.writeEntry('myscope', 'myentry', False)) + self.assertTrue(project.writeEntry("myscope", "myentry", False)) self.assertTrue(project.isDirty()) # removing an existing entry should dirty the project project.setDirty(False) - self.assertTrue(project.removeEntry('myscope', 'myentry')) + self.assertTrue(project.removeEntry("myscope", "myentry")) self.assertTrue(project.isDirty()) # removing a non-existing entry should _not_ dirty the project project.setDirty(False) - self.assertTrue(project.removeEntry('myscope', 'myentry')) + self.assertTrue(project.removeEntry("myscope", "myentry")) self.assertFalse(project.isDirty()) # setting a project CRS with a new value should dirty the project - project.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + project.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) project.setDirty(False) - project.setCrs(QgsCoordinateReferenceSystem('EPSG:3148')) + project.setCrs(QgsCoordinateReferenceSystem("EPSG:3148")) self.assertTrue(project.isDirty()) # setting a project CRS with the same project CRS should not dirty the project project.setDirty(False) - project.setCrs(QgsCoordinateReferenceSystem('EPSG:3148')) + project.setCrs(QgsCoordinateReferenceSystem("EPSG:3148")) self.assertFalse(project.isDirty()) def testBackgroundColor(self): @@ -1611,11 +1708,27 @@ def testSelectionColor(self): def testColorScheme(self): p = QgsProject.instance() spy = QSignalSpy(p.projectColorsChanged) - p.setProjectColors([[QColor(255, 0, 0), 'red'], [QColor(0, 255, 0), 'green'], [QColor.fromCmykF(1, 0.9, 0.8, 0.7), 'TestCmyk']]) + p.setProjectColors( + [ + [QColor(255, 0, 0), "red"], + [QColor(0, 255, 0), "green"], + [QColor.fromCmykF(1, 0.9, 0.8, 0.7), "TestCmyk"], + ] + ) self.assertEqual(len(spy), 1) - scheme = [s for s in QgsApplication.colorSchemeRegistry().schemes() if isinstance(s, QgsProjectColorScheme)][0] - self.assertEqual([[c[0], c[1]] for c in scheme.fetchColors()], - [[QColor(255, 0, 0), 'red'], [QColor(0, 255, 0), 'green'], [QColor.fromCmykF(1, 0.9, 0.8, 0.7), 'TestCmyk']]) + scheme = [ + s + for s in QgsApplication.colorSchemeRegistry().schemes() + if isinstance(s, QgsProjectColorScheme) + ][0] + self.assertEqual( + [[c[0], c[1]] for c in scheme.fetchColors()], + [ + [QColor(255, 0, 0), "red"], + [QColor(0, 255, 0), "green"], + [QColor.fromCmykF(1, 0.9, 0.8, 0.7), "TestCmyk"], + ], + ) project_filepath = getTempfilePath("qgs") p.write(project_filepath) @@ -1635,9 +1748,19 @@ def testColorScheme(self): # Test that write/read doesn't convert color to RGB always p = QgsProject.instance() p.read(project_filepath) - scheme = [s for s in QgsApplication.colorSchemeRegistry().schemes() if isinstance(s, QgsProjectColorScheme)][0] - self.assertEqual([[c[0], c[1]] for c in scheme.fetchColors()], - [[QColor(255, 0, 0), 'red'], [QColor(0, 255, 0), 'green'], [QColor.fromCmykF(1, 0.9, 0.8, 0.7), 'TestCmyk']]) + scheme = [ + s + for s in QgsApplication.colorSchemeRegistry().schemes() + if isinstance(s, QgsProjectColorScheme) + ][0] + self.assertEqual( + [[c[0], c[1]] for c in scheme.fetchColors()], + [ + [QColor(255, 0, 0), "red"], + [QColor(0, 255, 0), "green"], + [QColor.fromCmykF(1, 0.9, 0.8, 0.7), "TestCmyk"], + ], + ) def testTransformContextSignalIsEmitted(self): """Test that when a project transform context changes a transformContextChanged signal is emitted""" @@ -1645,7 +1768,11 @@ def testTransformContextSignalIsEmitted(self): p = QgsProject() spy = QSignalSpy(p.transformContextChanged) ctx = QgsCoordinateTransformContext() - ctx.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'), 'x') + ctx.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + "x", + ) p.setTransformContext(ctx) self.assertEqual(len(spy), 1) @@ -1653,11 +1780,14 @@ def testGpkgDirtyingWhenRemovedFromStorage(self): """Test that when a GPKG stored project is removed from the storage it is marked dirty""" with TemporaryDirectory() as d: - path = os.path.join(d, 'relative_paths_gh30387.gpkg') - copyfile(os.path.join(TEST_DATA_DIR, 'projects', 'relative_paths_gh30387.gpkg'), path) + path = os.path.join(d, "relative_paths_gh30387.gpkg") + copyfile( + os.path.join(TEST_DATA_DIR, "projects", "relative_paths_gh30387.gpkg"), + path, + ) project = QgsProject.instance() # Project URI - uri = f'geopackage://{path}?projectName=relative_project' + uri = f"geopackage://{path}?projectName=relative_project" project.setFileName(uri) self.assertTrue(project.write()) # Verify @@ -1718,7 +1848,9 @@ def testTransactionMode(self): self.assertEqual(project.transactionMode(), Qgis.TransactionMode.Disabled) project.setTransactionMode(Qgis.TransactionMode.AutomaticGroups) - self.assertEqual(project.transactionMode(), Qgis.TransactionMode.AutomaticGroups) + self.assertEqual( + project.transactionMode(), Qgis.TransactionMode.AutomaticGroups + ) project.setTransactionMode(Qgis.TransactionMode.BufferedGroups) self.assertEqual(project.transactionMode(), Qgis.TransactionMode.BufferedGroups) @@ -1730,9 +1862,9 @@ def testEditBufferGroup(self): project = QgsProject() project.removeAllMapLayers() - l1 = createLayer('test') + l1 = createLayer("test") project.addMapLayer(l1) - l2 = createLayer('test2') + l2 = createLayer("test2") project.addMapLayer(l2) # TransactionMode disabled -> editBufferGroup is empty @@ -1749,8 +1881,12 @@ def testStartEditingCommitRollBack(self): project = QgsProject() project.removeAllMapLayers() - layer_a = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer&field=int2:integer', 'test', 'memory') - layer_b = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer&field=int2:integer', 'test', 'memory') + layer_a = QgsVectorLayer( + "Point?crs=epsg:4326&field=int:integer&field=int2:integer", "test", "memory" + ) + layer_b = QgsVectorLayer( + "Point?crs=epsg:4326&field=int:integer&field=int2:integer", "test", "memory" + ) project.addMapLayers([layer_a, layer_b]) project.setTransactionMode(Qgis.TransactionMode.BufferedGroups) @@ -1777,8 +1913,8 @@ def testStartEditingCommitRollBack(self): self.assertTrue(project.editBufferGroup().isEditing()) f = QgsFeature(layer_a.fields()) - f.setAttribute('int', 123) - f.setGeometry(QgsGeometry.fromWkt('point(7 45)')) + f.setAttribute("int", 123) + f.setGeometry(QgsGeometry.fromWkt("point(7 45)")) self.assertTrue(layer_a.addFeatures([f])) self.assertEqual(len(project.editBufferGroup().modifiedLayers()), 1) self.assertIn(layer_a, project.editBufferGroup().modifiedLayers()) @@ -1811,9 +1947,15 @@ def test_remember_editable_status(self): project = QgsProject() project.removeAllMapLayers() - layer_a = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer&field=int2:integer', 'test', 'memory') - layer_b = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer&field=int2:integer', 'test', 'memory') - layer_c = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer&field=int2:integer', 'test', 'memory') + layer_a = QgsVectorLayer( + "Point?crs=epsg:4326&field=int:integer&field=int2:integer", "test", "memory" + ) + layer_b = QgsVectorLayer( + "Point?crs=epsg:4326&field=int:integer&field=int2:integer", "test", "memory" + ) + layer_c = QgsVectorLayer( + "Point?crs=epsg:4326&field=int:integer&field=int2:integer", "test", "memory" + ) project.addMapLayers([layer_a, layer_b, layer_c]) @@ -1839,7 +1981,9 @@ def test_remember_editable_status(self): project3 = QgsProject() self.assertTrue(project3.read(tmp_project_file2)) - self.assertTrue(project3.flags() & Qgis.ProjectFlag.RememberLayerEditStatusBetweenSessions) + self.assertTrue( + project3.flags() & Qgis.ProjectFlag.RememberLayerEditStatusBetweenSessions + ) # the layers should be made immediately editable self.assertTrue(project3.mapLayer(layer_a.id()).isEditable()) self.assertFalse(project3.mapLayer(layer_b.id()).isEditable()) @@ -1852,7 +1996,9 @@ def test_remember_editable_status(self): project4 = QgsProject() self.assertTrue(project4.read(tmp_project_file3)) - self.assertFalse(project4.flags() & Qgis.ProjectFlag.RememberLayerEditStatusBetweenSessions) + self.assertFalse( + project4.flags() & Qgis.ProjectFlag.RememberLayerEditStatusBetweenSessions + ) self.assertFalse(project4.mapLayer(layer_a.id()).isEditable()) self.assertFalse(project4.mapLayer(layer_b.id()).isEditable()) self.assertFalse(project4.mapLayer(layer_c.id()).isEditable()) @@ -1864,18 +2010,41 @@ def test_remember_evaluate_default_values(self): project = QgsProject() - layer = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer&field=int2:integer', 'test', 'memory') - layer2 = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer&field=int2:integer', 'test', 'memory') + layer = QgsVectorLayer( + "Point?crs=epsg:4326&field=int:integer&field=int2:integer", "test", "memory" + ) + layer2 = QgsVectorLayer( + "Point?crs=epsg:4326&field=int:integer&field=int2:integer", "test", "memory" + ) project.addMapLayers([layer]) - self.assertEqual(layer.dataProvider().providerProperty(QgsDataProvider.ProviderProperty.EvaluateDefaultValues, None), False) - project.setFlags(project.flags() | Qgis.ProjectFlag.EvaluateDefaultValuesOnProviderSide) - self.assertTrue(project.flags() & Qgis.ProjectFlag.EvaluateDefaultValuesOnProviderSide) - self.assertEqual(layer.dataProvider().providerProperty(QgsDataProvider.ProviderProperty.EvaluateDefaultValues, None), True) + self.assertEqual( + layer.dataProvider().providerProperty( + QgsDataProvider.ProviderProperty.EvaluateDefaultValues, None + ), + False, + ) + project.setFlags( + project.flags() | Qgis.ProjectFlag.EvaluateDefaultValuesOnProviderSide + ) + self.assertTrue( + project.flags() & Qgis.ProjectFlag.EvaluateDefaultValuesOnProviderSide + ) + self.assertEqual( + layer.dataProvider().providerProperty( + QgsDataProvider.ProviderProperty.EvaluateDefaultValues, None + ), + True, + ) project.addMapLayers([layer2]) - self.assertEqual(layer2.dataProvider().providerProperty(QgsDataProvider.ProviderProperty.EvaluateDefaultValues, None), True) + self.assertEqual( + layer2.dataProvider().providerProperty( + QgsDataProvider.ProviderProperty.EvaluateDefaultValues, None + ), + True, + ) tmp_dir = QTemporaryDir() tmp_project_file = f"{tmp_dir.path()}/project.qgs" @@ -1887,9 +2056,25 @@ def test_remember_evaluate_default_values(self): layers = list(project2.mapLayers().values()) self.assertEqual(len(layers), 2) - self.assertTrue(project2.flags() & Qgis.ProjectFlag.EvaluateDefaultValuesOnProviderSide) - self.assertEqual(layers[0].dataProvider().providerProperty(QgsDataProvider.ProviderProperty.EvaluateDefaultValues, None), True) - self.assertEqual(layers[1].dataProvider().providerProperty(QgsDataProvider.ProviderProperty.EvaluateDefaultValues, None), True) + self.assertTrue( + project2.flags() & Qgis.ProjectFlag.EvaluateDefaultValuesOnProviderSide + ) + self.assertEqual( + layers[0] + .dataProvider() + .providerProperty( + QgsDataProvider.ProviderProperty.EvaluateDefaultValues, None + ), + True, + ) + self.assertEqual( + layers[1] + .dataProvider() + .providerProperty( + QgsDataProvider.ProviderProperty.EvaluateDefaultValues, None + ), + True, + ) def testRasterLayerFlagDontResolveLayers(self): """ @@ -1897,13 +2082,18 @@ def testRasterLayerFlagDontResolveLayers(self): """ tmpDir = QTemporaryDir() tmpFile = f"{tmpDir.path()}/project.qgs" - copyfile(os.path.join(TEST_DATA_DIR, "landsat_4326.tif"), os.path.join(tmpDir.path(), "landsat_4326.tif")) + copyfile( + os.path.join(TEST_DATA_DIR, "landsat_4326.tif"), + os.path.join(tmpDir.path(), "landsat_4326.tif"), + ) project = QgsProject() - l = QgsRasterLayer(os.path.join(tmpDir.path(), "landsat_4326.tif"), "landsat", "gdal") + l = QgsRasterLayer( + os.path.join(tmpDir.path(), "landsat_4326.tif"), "landsat", "gdal" + ) self.assertTrue(l.isValid()) - QgsLayerNotesUtils.setLayerNotes(l, 'my notes') + QgsLayerNotesUtils.setLayerNotes(l, "my notes") self.assertTrue(project.addMapLayers([l])) self.assertTrue(project.write(tmpFile)) del project @@ -1917,5 +2107,5 @@ def testRasterLayerFlagDontResolveLayers(self): del project -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprojectbadlayers.py b/tests/src/python/test_qgsprojectbadlayers.py index 624f36b079b9..a569ffa65627 100644 --- a/tests/src/python/test_qgsprojectbadlayers.py +++ b/tests/src/python/test_qgsprojectbadlayers.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '20/10/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "20/10/2018" +__copyright__ = "Copyright 2018, The QGIS Project" import filecmp import os @@ -47,7 +48,7 @@ def getBaseMapSettings(cls): :rtype: QgsMapSettings """ ms = QgsMapSettings() - crs = QgsCoordinateReferenceSystem('epsg:4326') + crs = QgsCoordinateReferenceSystem("epsg:4326") ms.setBackgroundColor(QColor(152, 219, 249)) ms.setOutputSize(QSize(420, 280)) ms.setOutputDpi(72) @@ -64,7 +65,7 @@ def _change_data_source(self, layer, datasource, provider_key): options = QgsDataProvider.ProviderOptions() - subset_string = '' + subset_string = "" if not layer.isValid(): try: subset_string = layer.dataProvider().subsetString() @@ -79,7 +80,7 @@ def _change_data_source(self, layer, datasource, provider_key): self.assertTrue(layer.originalXmlProperties(), layer.name()) context = QgsReadWriteContext() context.setPathResolver(QgsProject.instance().pathResolver()) - errorMsg = '' + errorMsg = "" doc = QDomDocument() self.assertTrue(doc.setContent(layer.originalXmlProperties())) layer_node = QDomNode(doc.firstChild()) @@ -90,49 +91,73 @@ def test_project_roundtrip(self): p = QgsProject.instance() temp_dir = QTemporaryDir() - for ext in ('shp', 'dbf', 'shx', 'prj'): - copyfile(os.path.join(TEST_DATA_DIR, f'lines.{ext}'), os.path.join(temp_dir.path(), f'lines.{ext}')) - copyfile(os.path.join(TEST_DATA_DIR, 'raster', 'band1_byte_ct_epsg4326.tif'), os.path.join(temp_dir.path(), 'band1_byte_ct_epsg4326.tif')) - copyfile(os.path.join(TEST_DATA_DIR, 'raster', 'band1_byte_ct_epsg4326.tif'), os.path.join(temp_dir.path(), 'band1_byte_ct_epsg4326_copy.tif')) - l = QgsVectorLayer(os.path.join(temp_dir.path(), 'lines.shp'), 'lines', 'ogr') + for ext in ("shp", "dbf", "shx", "prj"): + copyfile( + os.path.join(TEST_DATA_DIR, f"lines.{ext}"), + os.path.join(temp_dir.path(), f"lines.{ext}"), + ) + copyfile( + os.path.join(TEST_DATA_DIR, "raster", "band1_byte_ct_epsg4326.tif"), + os.path.join(temp_dir.path(), "band1_byte_ct_epsg4326.tif"), + ) + copyfile( + os.path.join(TEST_DATA_DIR, "raster", "band1_byte_ct_epsg4326.tif"), + os.path.join(temp_dir.path(), "band1_byte_ct_epsg4326_copy.tif"), + ) + l = QgsVectorLayer(os.path.join(temp_dir.path(), "lines.shp"), "lines", "ogr") self.assertTrue(l.isValid()) - rl = QgsRasterLayer(os.path.join(temp_dir.path(), 'band1_byte_ct_epsg4326.tif'), 'raster', 'gdal') + rl = QgsRasterLayer( + os.path.join(temp_dir.path(), "band1_byte_ct_epsg4326.tif"), + "raster", + "gdal", + ) self.assertTrue(rl.isValid()) - rl_copy = QgsRasterLayer(os.path.join(temp_dir.path(), 'band1_byte_ct_epsg4326_copy.tif'), 'raster_copy', 'gdal') + rl_copy = QgsRasterLayer( + os.path.join(temp_dir.path(), "band1_byte_ct_epsg4326_copy.tif"), + "raster_copy", + "gdal", + ) self.assertTrue(rl_copy.isValid()) self.assertTrue(p.addMapLayers([l, rl, rl_copy])) # Save project - project_path = os.path.join(temp_dir.path(), 'project.qgs') + project_path = os.path.join(temp_dir.path(), "project.qgs") self.assertTrue(p.write(project_path)) # Re-load the project, checking for the XML properties p.removeAllMapLayers() self.assertTrue(p.read(project_path)) - vector = list(p.mapLayersByName('lines'))[0] - raster = list(p.mapLayersByName('raster'))[0] - raster_copy = list(p.mapLayersByName('raster_copy'))[0] + vector = list(p.mapLayersByName("lines"))[0] + raster = list(p.mapLayersByName("raster"))[0] + raster_copy = list(p.mapLayersByName("raster_copy"))[0] self.assertTrue(vector.originalXmlProperties()) self.assertTrue(raster.originalXmlProperties()) self.assertTrue(raster_copy.originalXmlProperties()) # Test setter - raster.setOriginalXmlProperties('pippo') - self.assertEqual(raster.originalXmlProperties(), 'pippo') + raster.setOriginalXmlProperties("pippo") + self.assertEqual(raster.originalXmlProperties(), "pippo") # Now create an invalid project: - bad_project_path = os.path.join(temp_dir.path(), 'project_bad.qgs') + bad_project_path = os.path.join(temp_dir.path(), "project_bad.qgs") with open(project_path) as infile: - with open(bad_project_path, 'w+') as outfile: - outfile.write(infile.read().replace('./lines.shp', './lines-BAD_SOURCE.shp').replace('band1_byte_ct_epsg4326_copy.tif', 'band1_byte_ct_epsg4326_copy-BAD_SOURCE.tif')) + with open(bad_project_path, "w+") as outfile: + outfile.write( + infile.read() + .replace("./lines.shp", "./lines-BAD_SOURCE.shp") + .replace( + "band1_byte_ct_epsg4326_copy.tif", + "band1_byte_ct_epsg4326_copy-BAD_SOURCE.tif", + ) + ) # Load the bad project p.removeAllMapLayers() self.assertTrue(p.read(bad_project_path)) # Check layer is invalid - vector = list(p.mapLayersByName('lines'))[0] - raster = list(p.mapLayersByName('raster'))[0] - raster_copy = list(p.mapLayersByName('raster_copy'))[0] + vector = list(p.mapLayersByName("lines"))[0] + raster = list(p.mapLayersByName("raster"))[0] + raster_copy = list(p.mapLayersByName("raster_copy"))[0] self.assertIsNotNone(vector.dataProvider()) self.assertIsNotNone(raster.dataProvider()) self.assertIsNotNone(raster_copy.dataProvider()) @@ -141,24 +166,31 @@ def test_project_roundtrip(self): # Try a getFeatures self.assertEqual([f for f in vector.getFeatures()], []) self.assertTrue(raster.isValid()) - self.assertEqual(vector.providerType(), 'ogr') + self.assertEqual(vector.providerType(), "ogr") # Save the project - bad_project_path2 = os.path.join(temp_dir.path(), 'project_bad2.qgs') + bad_project_path2 = os.path.join(temp_dir.path(), "project_bad2.qgs") p.write(bad_project_path2) # Re-save the project, with fixed paths - good_project_path = os.path.join(temp_dir.path(), 'project_good.qgs') + good_project_path = os.path.join(temp_dir.path(), "project_good.qgs") with open(bad_project_path2) as infile: - with open(good_project_path, 'w+') as outfile: - outfile.write(infile.read().replace('./lines-BAD_SOURCE.shp', './lines.shp').replace('band1_byte_ct_epsg4326_copy-BAD_SOURCE.tif', 'band1_byte_ct_epsg4326_copy.tif')) + with open(good_project_path, "w+") as outfile: + outfile.write( + infile.read() + .replace("./lines-BAD_SOURCE.shp", "./lines.shp") + .replace( + "band1_byte_ct_epsg4326_copy-BAD_SOURCE.tif", + "band1_byte_ct_epsg4326_copy.tif", + ) + ) # Load the good project p.removeAllMapLayers() self.assertTrue(p.read(good_project_path)) # Check layer is valid - vector = list(p.mapLayersByName('lines'))[0] - raster = list(p.mapLayersByName('raster'))[0] - raster_copy = list(p.mapLayersByName('raster_copy'))[0] + vector = list(p.mapLayersByName("lines"))[0] + raster = list(p.mapLayersByName("raster"))[0] + raster_copy = list(p.mapLayersByName("raster_copy"))[0] self.assertTrue(vector.isValid()) self.assertTrue(raster.isValid()) self.assertTrue(raster_copy.isValid()) @@ -168,15 +200,20 @@ def test_project_relations(self): temp_dir = QTemporaryDir() p = QgsProject.instance() - for ext in ('qgs', 'gpkg'): - copyfile(os.path.join(TEST_DATA_DIR, 'projects', f'relation_reference_test.{ext}'), os.path.join(temp_dir.path(), f'relation_reference_test.{ext}')) + for ext in ("qgs", "gpkg"): + copyfile( + os.path.join( + TEST_DATA_DIR, "projects", f"relation_reference_test.{ext}" + ), + os.path.join(temp_dir.path(), f"relation_reference_test.{ext}"), + ) # Load the good project - project_path = os.path.join(temp_dir.path(), 'relation_reference_test.qgs') + project_path = os.path.join(temp_dir.path(), "relation_reference_test.qgs") p.removeAllMapLayers() self.assertTrue(p.read(project_path)) - point_a = list(p.mapLayersByName('point_a'))[0] - point_b = list(p.mapLayersByName('point_b'))[0] + point_a = list(p.mapLayersByName("point_a"))[0] + point_b = list(p.mapLayersByName("point_b"))[0] point_a_source = point_a.publicSource() point_b_source = point_b.publicSource() self.assertTrue(point_a.isValid()) @@ -192,16 +229,23 @@ def _check_relations(): _check_relations() # Now build a bad project - bad_project_path = os.path.join(temp_dir.path(), 'relation_reference_test_bad.qgs') + bad_project_path = os.path.join( + temp_dir.path(), "relation_reference_test_bad.qgs" + ) with open(project_path) as infile: - with open(bad_project_path, 'w+') as outfile: - outfile.write(infile.read().replace('./relation_reference_test.gpkg', './relation_reference_test-BAD_SOURCE.gpkg')) + with open(bad_project_path, "w+") as outfile: + outfile.write( + infile.read().replace( + "./relation_reference_test.gpkg", + "./relation_reference_test-BAD_SOURCE.gpkg", + ) + ) # Load the bad project p.removeAllMapLayers() self.assertTrue(p.read(bad_project_path)) - point_a = list(p.mapLayersByName('point_a'))[0] - point_b = list(p.mapLayersByName('point_b'))[0] + point_a = list(p.mapLayersByName("point_a"))[0] + point_b = list(p.mapLayersByName("point_b"))[0] self.assertFalse(point_a.isValid()) self.assertFalse(point_b.isValid()) @@ -211,8 +255,8 @@ def _check_relations(): # Changing data source, relations should be restored: options = QgsDataProvider.ProviderOptions() - point_a.setDataSource(point_a_source, 'point_a', 'ogr', options) - point_b.setDataSource(point_b_source, 'point_b', 'ogr', options) + point_a.setDataSource(point_a_source, "point_a", "ogr", options) + point_b.setDataSource(point_b_source, "point_b", "ogr", options) self.assertTrue(point_a.isValid()) self.assertTrue(point_b.isValid()) @@ -222,8 +266,8 @@ def _check_relations(): # Reload the bad project p.removeAllMapLayers() self.assertTrue(p.read(bad_project_path)) - point_a = list(p.mapLayersByName('point_a'))[0] - point_b = list(p.mapLayersByName('point_b'))[0] + point_a = list(p.mapLayersByName("point_a"))[0] + point_b = list(p.mapLayersByName("point_b"))[0] self.assertFalse(point_a.isValid()) self.assertFalse(point_b.isValid()) @@ -232,20 +276,29 @@ def _check_relations(): _check_relations() # Save the bad project - bad_project_path2 = os.path.join(temp_dir.path(), 'relation_reference_test_bad2.qgs') + bad_project_path2 = os.path.join( + temp_dir.path(), "relation_reference_test_bad2.qgs" + ) p.write(bad_project_path2) # Now fix the bad project - bad_project_path_fixed = os.path.join(temp_dir.path(), 'relation_reference_test_bad_fixed.qgs') + bad_project_path_fixed = os.path.join( + temp_dir.path(), "relation_reference_test_bad_fixed.qgs" + ) with open(bad_project_path2) as infile: - with open(bad_project_path_fixed, 'w+') as outfile: - outfile.write(infile.read().replace('./relation_reference_test-BAD_SOURCE.gpkg', './relation_reference_test.gpkg')) + with open(bad_project_path_fixed, "w+") as outfile: + outfile.write( + infile.read().replace( + "./relation_reference_test-BAD_SOURCE.gpkg", + "./relation_reference_test.gpkg", + ) + ) # Load the fixed project p.removeAllMapLayers() self.assertTrue(p.read(bad_project_path_fixed)) - point_a = list(p.mapLayersByName('point_a'))[0] - point_b = list(p.mapLayersByName('point_b'))[0] + point_a = list(p.mapLayersByName("point_a"))[0] + point_b = list(p.mapLayersByName("point_b"))[0] point_a_source = point_a.publicSource() point_b_source = point_b.publicSource() self.assertTrue(point_a.isValid()) @@ -258,24 +311,28 @@ def testStyles(self): temp_dir = QTemporaryDir() p = QgsProject.instance() for f in ( - 'bad_layer_raster_test.tfw', - 'bad_layer_raster_test.tiff', - 'bad_layer_raster_test.tiff.aux.xml', - 'bad_layers_test.gpkg', - 'good_layers_test.qgs'): - copyfile(os.path.join(TEST_DATA_DIR, 'projects', f), os.path.join(temp_dir.path(), f)) - - project_path = os.path.join(temp_dir.path(), 'good_layers_test.qgs') + "bad_layer_raster_test.tfw", + "bad_layer_raster_test.tiff", + "bad_layer_raster_test.tiff.aux.xml", + "bad_layers_test.gpkg", + "good_layers_test.qgs", + ): + copyfile( + os.path.join(TEST_DATA_DIR, "projects", f), + os.path.join(temp_dir.path(), f), + ) + + project_path = os.path.join(temp_dir.path(), "good_layers_test.qgs") p = QgsProject().instance() p.removeAllMapLayers() self.assertTrue(p.read(project_path)) self.assertEqual(p.count(), 4) ms = self.getBaseMapSettings() - point_a_copy = list(p.mapLayersByName('point_a copy'))[0] - point_a = list(p.mapLayersByName('point_a'))[0] - point_b = list(p.mapLayersByName('point_b'))[0] - raster = list(p.mapLayersByName('bad_layer_raster_test'))[0] + point_a_copy = list(p.mapLayersByName("point_a copy"))[0] + point_a = list(p.mapLayersByName("point_a"))[0] + point_b = list(p.mapLayersByName("point_b"))[0] + raster = list(p.mapLayersByName("bad_layer_raster_test"))[0] self.assertTrue(point_a_copy.isValid()) self.assertTrue(point_a.isValid()) self.assertTrue(point_b.isValid()) @@ -283,48 +340,69 @@ def testStyles(self): ms.setExtent(QgsRectangle(2.81861, 41.98138, 2.81952, 41.9816)) ms.setLayers([point_a_copy, point_a, point_b, raster]) image = renderMapToImage(ms) - self.assertTrue(image.save(os.path.join(temp_dir.path(), 'expected.png'), 'PNG')) + self.assertTrue( + image.save(os.path.join(temp_dir.path(), "expected.png"), "PNG") + ) point_a_source = point_a.publicSource() point_b_source = point_b.publicSource() raster_source = raster.publicSource() - self._change_data_source(point_a, point_a_source, 'ogr') + self._change_data_source(point_a, point_a_source, "ogr") # Attention: we are not passing the subset string here: - self._change_data_source(point_a_copy, point_a_source, 'ogr') - self._change_data_source(point_b, point_b_source, 'ogr') - self._change_data_source(raster, raster_source, 'gdal') - self.assertTrue(image.save(os.path.join(temp_dir.path(), 'actual.png'), 'PNG')) - - self.assertTrue(filecmp.cmp(os.path.join(temp_dir.path(), 'actual.png'), os.path.join(temp_dir.path(), 'expected.png')), False) + self._change_data_source(point_a_copy, point_a_source, "ogr") + self._change_data_source(point_b, point_b_source, "ogr") + self._change_data_source(raster, raster_source, "gdal") + self.assertTrue(image.save(os.path.join(temp_dir.path(), "actual.png"), "PNG")) + + self.assertTrue( + filecmp.cmp( + os.path.join(temp_dir.path(), "actual.png"), + os.path.join(temp_dir.path(), "expected.png"), + ), + False, + ) # Now build a bad project p.removeAllMapLayers() - bad_project_path = os.path.join(temp_dir.path(), 'bad_layers_test.qgs') + bad_project_path = os.path.join(temp_dir.path(), "bad_layers_test.qgs") with open(project_path) as infile: - with open(bad_project_path, 'w+') as outfile: - outfile.write(infile.read().replace('./bad_layers_test.', './bad_layers_test-BAD_SOURCE.').replace('bad_layer_raster_test.tiff', 'bad_layer_raster_test-BAD_SOURCE.tiff')) + with open(bad_project_path, "w+") as outfile: + outfile.write( + infile.read() + .replace("./bad_layers_test.", "./bad_layers_test-BAD_SOURCE.") + .replace( + "bad_layer_raster_test.tiff", + "bad_layer_raster_test-BAD_SOURCE.tiff", + ) + ) p.removeAllMapLayers() self.assertTrue(p.read(bad_project_path)) self.assertEqual(p.count(), 4) - point_a_copy = list(p.mapLayersByName('point_a copy'))[0] - point_a = list(p.mapLayersByName('point_a'))[0] - point_b = list(p.mapLayersByName('point_b'))[0] - raster = list(p.mapLayersByName('bad_layer_raster_test'))[0] + point_a_copy = list(p.mapLayersByName("point_a copy"))[0] + point_a = list(p.mapLayersByName("point_a"))[0] + point_b = list(p.mapLayersByName("point_b"))[0] + raster = list(p.mapLayersByName("bad_layer_raster_test"))[0] self.assertFalse(point_a.isValid()) self.assertFalse(point_a_copy.isValid()) self.assertFalse(point_b.isValid()) self.assertFalse(raster.isValid()) ms.setLayers([point_a_copy, point_a, point_b, raster]) image = renderMapToImage(ms) - self.assertTrue(image.save(os.path.join(temp_dir.path(), 'bad.png'), 'PNG')) - self.assertFalse(filecmp.cmp(os.path.join(temp_dir.path(), 'bad.png'), os.path.join(temp_dir.path(), 'expected.png')), False) - - self._change_data_source(point_a, point_a_source, 'ogr') + self.assertTrue(image.save(os.path.join(temp_dir.path(), "bad.png"), "PNG")) + self.assertFalse( + filecmp.cmp( + os.path.join(temp_dir.path(), "bad.png"), + os.path.join(temp_dir.path(), "expected.png"), + ), + False, + ) + + self._change_data_source(point_a, point_a_source, "ogr") # We are not passing the subset string!! - self._change_data_source(point_a_copy, point_a_source, 'ogr') - self._change_data_source(point_b, point_b_source, 'ogr') - self._change_data_source(raster, raster_source, 'gdal') + self._change_data_source(point_a_copy, point_a_source, "ogr") + self._change_data_source(point_b, point_b_source, "ogr") + self._change_data_source(raster, raster_source, "gdal") self.assertTrue(point_a.isValid()) self.assertTrue(point_a_copy.isValid()) self.assertTrue(point_b.isValid()) @@ -332,10 +410,18 @@ def testStyles(self): ms.setLayers([point_a_copy, point_a, point_b, raster]) image = renderMapToImage(ms) - self.assertTrue(image.save(os.path.join(temp_dir.path(), 'actual_fixed.png'), 'PNG')) + self.assertTrue( + image.save(os.path.join(temp_dir.path(), "actual_fixed.png"), "PNG") + ) - self.assertTrue(filecmp.cmp(os.path.join(temp_dir.path(), 'actual_fixed.png'), os.path.join(temp_dir.path(), 'expected.png')), False) + self.assertTrue( + filecmp.cmp( + os.path.join(temp_dir.path(), "actual_fixed.png"), + os.path.join(temp_dir.path(), "expected.png"), + ), + False, + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprojectdisplaysettings.py b/tests/src/python/test_qgsprojectdisplaysettings.py index 705bad6fcb41..0f5f16036926 100644 --- a/tests/src/python/test_qgsprojectdisplaysettings.py +++ b/tests/src/python/test_qgsprojectdisplaysettings.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '09/01/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "09/01/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication from qgis.PyQt.QtTest import QSignalSpy @@ -49,42 +50,62 @@ def testBearingFormat(self): format = QgsBearingNumericFormat() format.setNumberDecimalPlaces(9) - format.setDirectionFormat(QgsBearingNumericFormat.FormatDirectionOption.UseRange0To360) + format.setDirectionFormat( + QgsBearingNumericFormat.FormatDirectionOption.UseRange0To360 + ) spy = QSignalSpy(p.bearingFormatChanged) p.setBearingFormat(format) self.assertEqual(len(spy), 1) self.assertEqual(p.bearingFormat().numberDecimalPlaces(), 9) - self.assertEqual(p.bearingFormat().directionFormat(), QgsBearingNumericFormat.FormatDirectionOption.UseRange0To360) + self.assertEqual( + p.bearingFormat().directionFormat(), + QgsBearingNumericFormat.FormatDirectionOption.UseRange0To360, + ) format = QgsBearingNumericFormat() format.setNumberDecimalPlaces(3) - format.setDirectionFormat(QgsBearingNumericFormat.FormatDirectionOption.UseRangeNegative180ToPositive180) + format.setDirectionFormat( + QgsBearingNumericFormat.FormatDirectionOption.UseRangeNegative180ToPositive180 + ) p.setBearingFormat(format) self.assertEqual(len(spy), 2) self.assertEqual(p.bearingFormat().numberDecimalPlaces(), 3) - self.assertEqual(p.bearingFormat().directionFormat(), QgsBearingNumericFormat.FormatDirectionOption.UseRangeNegative180ToPositive180) + self.assertEqual( + p.bearingFormat().directionFormat(), + QgsBearingNumericFormat.FormatDirectionOption.UseRangeNegative180ToPositive180, + ) def testGeographicCoordinateFormat(self): p = QgsProjectDisplaySettings() format = QgsGeographicCoordinateNumericFormat() format.setNumberDecimalPlaces(9) - format.setAngleFormat(QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds) + format.setAngleFormat( + QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds + ) spy = QSignalSpy(p.geographicCoordinateFormatChanged) p.setGeographicCoordinateFormat(format) self.assertEqual(len(spy), 1) self.assertEqual(p.geographicCoordinateFormat().numberDecimalPlaces(), 9) - self.assertEqual(p.geographicCoordinateFormat().angleFormat(), QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds) + self.assertEqual( + p.geographicCoordinateFormat().angleFormat(), + QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds, + ) format = QgsGeographicCoordinateNumericFormat() format.setNumberDecimalPlaces(3) - format.setAngleFormat(QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutes) + format.setAngleFormat( + QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutes + ) p.setGeographicCoordinateFormat(format) self.assertEqual(len(spy), 2) self.assertEqual(p.geographicCoordinateFormat().numberDecimalPlaces(), 3) - self.assertEqual(p.geographicCoordinateFormat().angleFormat(), QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutes) + self.assertEqual( + p.geographicCoordinateFormat().angleFormat(), + QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutes, + ) def testCoordinateTypeGeographic(self): p = QgsProjectDisplaySettings() @@ -114,9 +135,9 @@ def testCoordinateTypeCustomCrs(self): self.assertEqual(len(spy), 1) self.assertEqual(p.coordinateType(), Qgis.CoordinateDisplayType.CustomCrs) spy = QSignalSpy(p.coordinateCustomCrsChanged) - p.setCoordinateCustomCrs(QgsCoordinateReferenceSystem('EPSG:3148')) + p.setCoordinateCustomCrs(QgsCoordinateReferenceSystem("EPSG:3148")) self.assertEqual(len(spy), 1) - self.assertEqual(p.coordinateCustomCrs().authid(), 'EPSG:3148') + self.assertEqual(p.coordinateCustomCrs().authid(), "EPSG:3148") def testReset(self): """ @@ -124,33 +145,47 @@ def testReset(self): """ format = QgsBearingNumericFormat() format.setNumberDecimalPlaces(3) - format.setDirectionFormat(QgsBearingNumericFormat.FormatDirectionOption.UseRangeNegative180ToPositive180) + format.setDirectionFormat( + QgsBearingNumericFormat.FormatDirectionOption.UseRangeNegative180ToPositive180 + ) p = QgsProjectDisplaySettings() p.setBearingFormat(format) self.assertEqual(p.bearingFormat().numberDecimalPlaces(), 3) - self.assertEqual(p.bearingFormat().directionFormat(), QgsBearingNumericFormat.FormatDirectionOption.UseRangeNegative180ToPositive180) + self.assertEqual( + p.bearingFormat().directionFormat(), + QgsBearingNumericFormat.FormatDirectionOption.UseRangeNegative180ToPositive180, + ) format = QgsGeographicCoordinateNumericFormat() format.setNumberDecimalPlaces(7) - format.setAngleFormat(QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds) + format.setAngleFormat( + QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds + ) p.setGeographicCoordinateFormat(format) self.assertEqual(p.geographicCoordinateFormat().numberDecimalPlaces(), 7) - self.assertEqual(p.geographicCoordinateFormat().angleFormat(), QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds) + self.assertEqual( + p.geographicCoordinateFormat().angleFormat(), + QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds, + ) # setup a local default bearing format s = QgsLocalDefaultSettings() format = QgsBearingNumericFormat() format.setNumberDecimalPlaces(9) - format.setDirectionFormat(QgsBearingNumericFormat.FormatDirectionOption.UseRange0To360) + format.setDirectionFormat( + QgsBearingNumericFormat.FormatDirectionOption.UseRange0To360 + ) s.setBearingFormat(format) format = QgsGeographicCoordinateNumericFormat() format.setNumberDecimalPlaces(5) - format.setAngleFormat(QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutes) + format.setAngleFormat( + QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutes + ) s.setGeographicCoordinateFormat(format) p.setCoordinateType(Qgis.CoordinateDisplayType.MapGeographic) - p.setCoordinateCustomCrs(QgsCoordinateReferenceSystem('EPSG:3148')) + p.setCoordinateCustomCrs(QgsCoordinateReferenceSystem("EPSG:3148")) spy = QSignalSpy(p.bearingFormatChanged) spy2 = QSignalSpy(p.geographicCoordinateFormatChanged) @@ -163,25 +198,35 @@ def testReset(self): self.assertEqual(len(spy4), 1) # project should default to local default format self.assertEqual(p.bearingFormat().numberDecimalPlaces(), 9) - self.assertEqual(p.bearingFormat().directionFormat(), QgsBearingNumericFormat.FormatDirectionOption.UseRange0To360) + self.assertEqual( + p.bearingFormat().directionFormat(), + QgsBearingNumericFormat.FormatDirectionOption.UseRange0To360, + ) self.assertEqual(p.geographicCoordinateFormat().numberDecimalPlaces(), 5) - self.assertEqual(p.geographicCoordinateFormat().angleFormat(), QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutes) + self.assertEqual( + p.geographicCoordinateFormat().angleFormat(), + QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutes, + ) self.assertEqual(p.coordinateType(), Qgis.CoordinateDisplayType.MapCrs) - self.assertEqual(p.coordinateCustomCrs().authid(), 'EPSG:4326') + self.assertEqual(p.coordinateCustomCrs().authid(), "EPSG:4326") def testReadWrite(self): p = QgsProjectDisplaySettings() format = QgsBearingNumericFormat() format.setNumberDecimalPlaces(9) - format.setDirectionFormat(QgsBearingNumericFormat.FormatDirectionOption.UseRange0To360) + format.setDirectionFormat( + QgsBearingNumericFormat.FormatDirectionOption.UseRange0To360 + ) p.setBearingFormat(format) format = QgsGeographicCoordinateNumericFormat() format.setNumberDecimalPlaces(7) - format.setAngleFormat(QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds) + format.setAngleFormat( + QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds + ) p.setGeographicCoordinateFormat(format) p.setCoordinateAxisOrder(Qgis.CoordinateOrder.YX) @@ -196,11 +241,17 @@ def testReadWrite(self): self.assertEqual(len(spy), 1) self.assertEqual(len(spy2), 1) self.assertEqual(p2.bearingFormat().numberDecimalPlaces(), 9) - self.assertEqual(p2.bearingFormat().directionFormat(), QgsBearingNumericFormat.FormatDirectionOption.UseRange0To360) + self.assertEqual( + p2.bearingFormat().directionFormat(), + QgsBearingNumericFormat.FormatDirectionOption.UseRange0To360, + ) self.assertEqual(p.geographicCoordinateFormat().numberDecimalPlaces(), 7) - self.assertEqual(p.geographicCoordinateFormat().angleFormat(), QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds) + self.assertEqual( + p.geographicCoordinateFormat().angleFormat(), + QgsGeographicCoordinateNumericFormat.AngleFormat.DegreesMinutesSeconds, + ) self.assertEqual(p.coordinateAxisOrder(), Qgis.CoordinateOrder.YX) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprojectelevationproperties.py b/tests/src/python/test_qgsprojectelevationproperties.py index 7cb9845fc855..067908ed46b1 100644 --- a/tests/src/python/test_qgsprojectelevationproperties.py +++ b/tests/src/python/test_qgsprojectelevationproperties.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '09/11/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "09/11/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import os @@ -97,7 +98,7 @@ def test_layer_resolving(self): # add raster layer to a project p = QgsProject() - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), 'float1-16.tif'), 'rl') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "float1-16.tif"), "rl") self.assertTrue(rl.isValid()) p.addMapLayer(rl) @@ -111,10 +112,15 @@ def test_layer_resolving(self): project2 = QgsProject() self.assertTrue(project2.read(tmp_project_file)) - self.assertIsInstance(project2.elevationProperties().terrainProvider(), QgsRasterDemTerrainProvider) + self.assertIsInstance( + project2.elevationProperties().terrainProvider(), + QgsRasterDemTerrainProvider, + ) # make sure layer is resolved - self.assertEqual(project2.elevationProperties().terrainProvider().layer().id(), rl.id()) + self.assertEqual( + project2.elevationProperties().terrainProvider().layer().id(), rl.id() + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprojectgpssettings.py b/tests/src/python/test_qgsprojectgpssettings.py index 7905faaddee4..8296ae1e887e 100644 --- a/tests/src/python/test_qgsprojectgpssettings.py +++ b/tests/src/python/test_qgsprojectgpssettings.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '03/11/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "03/11/2022" +__copyright__ = "Copyright 2022, The QGIS Project" import os @@ -52,7 +53,9 @@ def testSettings(self): spy_add_track = QSignalSpy(p.automaticallyAddTrackVerticesChanged) spy_auto_commit = QSignalSpy(p.automaticallyCommitFeaturesChanged) - spy_destination_follows_active = QSignalSpy(p.destinationFollowsActiveLayerChanged) + spy_destination_follows_active = QSignalSpy( + p.destinationFollowsActiveLayerChanged + ) p.setAutomaticallyAddTrackVertices(True) self.assertEqual(len(spy_add_track), 1) @@ -90,9 +93,11 @@ def testSettings(self): self.assertEqual(len(spy_destination_follows_active), 2) self.assertTrue(spy_destination_follows_active[-1][0]) - layer1 = QgsVectorLayer(os.path.join(unitTestDataPath(), 'lines.shp'), 'layer1') + layer1 = QgsVectorLayer(os.path.join(unitTestDataPath(), "lines.shp"), "layer1") self.assertTrue(layer1.isValid()) - layer2 = QgsVectorLayer(os.path.join(unitTestDataPath(), 'points.shp'), 'layer2') + layer2 = QgsVectorLayer( + os.path.join(unitTestDataPath(), "points.shp"), "layer2" + ) self.assertTrue(layer2.isValid()) self.assertFalse(p.destinationLayer()) @@ -110,36 +115,42 @@ def testSettings(self): self.assertEqual(spy[1][0], layer2) self.assertEqual(p.destinationLayer(), layer2) - p.setDestinationTimeStampField(layer1, 'test') - p.setDestinationTimeStampField(layer2, 'test2') - self.assertEqual(p.destinationTimeStampFields(), {layer1.id(): 'test', - layer2.id(): 'test2'}) + p.setDestinationTimeStampField(layer1, "test") + p.setDestinationTimeStampField(layer2, "test2") + self.assertEqual( + p.destinationTimeStampFields(), {layer1.id(): "test", layer2.id(): "test2"} + ) def test_time_stamp_field_changes(self): - layer1 = QgsVectorLayer(os.path.join(unitTestDataPath(), 'lines.shp'), 'layer1') + layer1 = QgsVectorLayer(os.path.join(unitTestDataPath(), "lines.shp"), "layer1") self.assertTrue(layer1.isValid()) - layer2 = QgsVectorLayer(os.path.join(unitTestDataPath(), 'points.shp'), 'layer2') + layer2 = QgsVectorLayer( + os.path.join(unitTestDataPath(), "points.shp"), "layer2" + ) self.assertTrue(layer2.isValid()) p = QgsProjectGpsSettings() - spy_destination_time_stamp_field_changed = QSignalSpy(p.destinationTimeStampFieldChanged) + spy_destination_time_stamp_field_changed = QSignalSpy( + p.destinationTimeStampFieldChanged + ) - p.setDestinationTimeStampField(layer1, 'test') + p.setDestinationTimeStampField(layer1, "test") # no signal emitted, layer1 is not destination layer self.assertEqual(len(spy_destination_time_stamp_field_changed), 0) p.setDestinationLayer(layer2) self.assertEqual(len(spy_destination_time_stamp_field_changed), 1) self.assertFalse(spy_destination_time_stamp_field_changed[-1][0]) - p.setDestinationTimeStampField(layer2, 'test2') + p.setDestinationTimeStampField(layer2, "test2") self.assertEqual(len(spy_destination_time_stamp_field_changed), 2) - self.assertEqual(spy_destination_time_stamp_field_changed[-1][0], 'test2') - self.assertEqual(p.destinationTimeStampFields(), {layer1.id(): 'test', - layer2.id(): 'test2'}) + self.assertEqual(spy_destination_time_stamp_field_changed[-1][0], "test2") + self.assertEqual( + p.destinationTimeStampFields(), {layer1.id(): "test", layer2.id(): "test2"} + ) # changing destination layer will emit signal p.setDestinationLayer(layer1) self.assertEqual(len(spy_destination_time_stamp_field_changed), 3) - self.assertEqual(spy_destination_time_stamp_field_changed[-1][0], 'test') + self.assertEqual(spy_destination_time_stamp_field_changed[-1][0], "test") def testReset(self): """ @@ -155,17 +166,21 @@ def testReset(self): p.setAutomaticallyAddTrackVertices(True) p.setDestinationFollowsActiveLayer(False) - layer1 = QgsVectorLayer(os.path.join(unitTestDataPath(), 'lines.shp'), 'layer1') + layer1 = QgsVectorLayer(os.path.join(unitTestDataPath(), "lines.shp"), "layer1") self.assertTrue(layer1.isValid()) p.setDestinationLayer(layer1) - p.setDestinationTimeStampField(layer1, 'test') + p.setDestinationTimeStampField(layer1, "test") spy_add_track = QSignalSpy(p.automaticallyAddTrackVerticesChanged) spy_auto_commit = QSignalSpy(p.automaticallyCommitFeaturesChanged) spy_dest_layer_changed = QSignalSpy(p.destinationLayerChanged) - spy_destination_follows_active = QSignalSpy(p.destinationFollowsActiveLayerChanged) - spy_destination_time_stamp_field_changed = QSignalSpy(p.destinationTimeStampFieldChanged) + spy_destination_follows_active = QSignalSpy( + p.destinationFollowsActiveLayerChanged + ) + spy_destination_time_stamp_field_changed = QSignalSpy( + p.destinationTimeStampFieldChanged + ) p.reset() self.assertFalse(p.automaticallyAddTrackVertices()) @@ -190,15 +205,17 @@ def testReadWrite(self): p.setAutomaticallyAddTrackVertices(True) p.setDestinationFollowsActiveLayer(False) - layer1 = QgsVectorLayer(os.path.join(unitTestDataPath(), 'lines.shp'), 'layer1') + layer1 = QgsVectorLayer(os.path.join(unitTestDataPath(), "lines.shp"), "layer1") self.assertTrue(layer1.isValid()) p.setDestinationLayer(layer1) - layer2 = QgsVectorLayer(os.path.join(unitTestDataPath(), 'points.shp'), 'layer2') + layer2 = QgsVectorLayer( + os.path.join(unitTestDataPath(), "points.shp"), "layer2" + ) self.assertTrue(layer2.isValid()) - p.setDestinationTimeStampField(layer1, 'test') - p.setDestinationTimeStampField(layer2, 'test2') + p.setDestinationTimeStampField(layer1, "test") + p.setDestinationTimeStampField(layer2, "test2") project = QgsProject() project.addMapLayer(layer1) @@ -211,8 +228,12 @@ def testReadWrite(self): spy = QSignalSpy(p2.automaticallyAddTrackVerticesChanged) spy2 = QSignalSpy(p2.automaticallyCommitFeaturesChanged) spy_dest_layer_changed = QSignalSpy(p2.destinationLayerChanged) - spy_destination_follows_active = QSignalSpy(p2.destinationFollowsActiveLayerChanged) - spy_destination_time_stamp_field_changed = QSignalSpy(p2.destinationTimeStampFieldChanged) + spy_destination_follows_active = QSignalSpy( + p2.destinationFollowsActiveLayerChanged + ) + spy_destination_time_stamp_field_changed = QSignalSpy( + p2.destinationTimeStampFieldChanged + ) self.assertTrue(p2.readXml(elem, QgsReadWriteContext())) self.assertEqual(len(spy), 1) @@ -224,8 +245,9 @@ def testReadWrite(self): self.assertTrue(p2.automaticallyCommitFeatures()) self.assertTrue(p2.automaticallyAddTrackVertices()) self.assertFalse(p2.destinationFollowsActiveLayer()) - self.assertEqual(p2.destinationTimeStampFields(), {layer1.id(): 'test', - layer2.id(): 'test2'}) + self.assertEqual( + p2.destinationTimeStampFields(), {layer1.id(): "test", layer2.id(): "test2"} + ) # needs to be resolved first self.assertFalse(p2.destinationLayer()) @@ -233,8 +255,8 @@ def testReadWrite(self): self.assertEqual(len(spy_dest_layer_changed), 2) self.assertEqual(p2.destinationLayer(), layer1) self.assertEqual(len(spy_destination_time_stamp_field_changed), 2) - self.assertEqual(spy_destination_time_stamp_field_changed[-1][0], 'test') + self.assertEqual(spy_destination_time_stamp_field_changed[-1][0], "test") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprojectionselectionwidgets.py b/tests/src/python/test_qgsprojectionselectionwidgets.py index a89b604988f1..2b6f18ecfb2f 100644 --- a/tests/src/python/test_qgsprojectionselectionwidgets.py +++ b/tests/src/python/test_qgsprojectionselectionwidgets.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '12/11/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "12/11/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication from qgis.PyQt.QtTest import QSignalSpy @@ -16,13 +17,13 @@ QgsApplication, QgsSettings, QgsCoordinateReferenceSystem, - QgsProject + QgsProject, ) from qgis.gui import ( QgsProjectionSelectionDialog, QgsProjectionSelectionTreeWidget, QgsProjectionSelectionWidget, - QgsCoordinateReferenceSystemProxyModel + QgsCoordinateReferenceSystemProxyModel, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -46,78 +47,120 @@ def setUpClass(cls): QgsSettings().setValue("/projections/defaultProjectCrs", "EPSG:4326") def testShowingHiding(self): - """ test showing and hiding options """ + """test showing and hiding options""" QgsProject.instance().setCrs(QgsCoordinateReferenceSystem()) w = QgsProjectionSelectionWidget() # layer crs w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.LayerCrs, False) - self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.LayerCrs)) + self.assertFalse( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.LayerCrs) + ) w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.LayerCrs, True) # should still be hidden, because layer crs not set - self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.LayerCrs)) - w.setLayerCrs(QgsCoordinateReferenceSystem('EPSG:3111')) - self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.LayerCrs)) + self.assertFalse( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.LayerCrs) + ) + w.setLayerCrs(QgsCoordinateReferenceSystem("EPSG:3111")) + self.assertTrue( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.LayerCrs) + ) w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.LayerCrs, False) - self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.LayerCrs)) + self.assertFalse( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.LayerCrs) + ) # project crs w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.ProjectCrs, False) - self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.ProjectCrs)) + self.assertFalse( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.ProjectCrs) + ) w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.ProjectCrs, True) # should still be hidden, because project crs was not set - self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.ProjectCrs)) - QgsProject.instance().setCrs(QgsCoordinateReferenceSystem('EPSG:3113')) + self.assertFalse( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.ProjectCrs) + ) + QgsProject.instance().setCrs(QgsCoordinateReferenceSystem("EPSG:3113")) w = QgsProjectionSelectionWidget() w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.ProjectCrs, True) - self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.ProjectCrs)) + self.assertTrue( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.ProjectCrs) + ) w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.ProjectCrs, False) - self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.ProjectCrs)) + self.assertFalse( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.ProjectCrs) + ) # default crs w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.DefaultCrs, False) - self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.DefaultCrs)) + self.assertFalse( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.DefaultCrs) + ) w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.DefaultCrs, True) - self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.DefaultCrs)) + self.assertTrue( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.DefaultCrs) + ) # current crs w = QgsProjectionSelectionWidget() w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs, False) - self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs)) + self.assertFalse( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs) + ) w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs, True) - self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs)) + self.assertTrue( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs) + ) w = QgsProjectionSelectionWidget() - w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) + w.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs, False) - self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs)) + self.assertFalse( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs) + ) w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs, True) - self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs)) + self.assertTrue( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs) + ) # not set w = QgsProjectionSelectionWidget() w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet, False) - self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet)) + self.assertFalse( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet) + ) w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet, True) - self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet)) + self.assertTrue( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet) + ) w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet, False) - self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet)) + self.assertFalse( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet) + ) def testShowingNotSetOption(self): - """ test showing the not set option """ + """test showing the not set option""" w = QgsProjectionSelectionWidget() # start with an invalid CRS w.setCrs(QgsCoordinateReferenceSystem()) # add the not-set option w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet, True) - self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet)) + self.assertTrue( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet) + ) # current crs (which would show "invalid") should be hidden - self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs)) + self.assertFalse( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs) + ) # hide not-set option w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet, False) - self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet)) + self.assertFalse( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet) + ) # and now current crs option ('invalid') should be reshown - self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs)) + self.assertTrue( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs) + ) # repeat with a slightly different workflow w = QgsProjectionSelectionWidget() @@ -125,104 +168,111 @@ def testShowingNotSetOption(self): w.setCrs(QgsCoordinateReferenceSystem()) # add the not-set option w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet, True) - self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet)) + self.assertTrue( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet) + ) # current crs (which would show "invalid") should be hidden - self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs)) + self.assertFalse( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs) + ) # now set a current crs - w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) + w.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) # both current and not set options should be shown - self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs)) - self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet)) + self.assertTrue( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs) + ) + self.assertTrue( + w.optionVisible(QgsProjectionSelectionWidget.CrsOption.CrsNotSet) + ) def testRecent(self): registry = QgsApplication.coordinateReferenceSystemRegistry() registry.clearRecent() - QgsProject.instance().setCrs(QgsCoordinateReferenceSystem('EPSG:3113')) + QgsProject.instance().setCrs(QgsCoordinateReferenceSystem("EPSG:3113")) w = QgsProjectionSelectionWidget() w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.LayerCrs, True) - w.setLayerCrs(QgsCoordinateReferenceSystem('EPSG:3111')) - w.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + w.setLayerCrs(QgsCoordinateReferenceSystem("EPSG:3111")) + w.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs, True) w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.ProjectCrs, True) self.assertIsInstance(w.children()[0], QComboBox) cb = w.children()[0] self.assertEqual(cb.count(), 4) - self.assertEqual(cb.itemText(0), 'EPSG:4326 - WGS 84') - self.assertEqual(cb.itemText(1), 'Project CRS: EPSG:3113 - GDA94 / BCSG02') - self.assertEqual(cb.itemText(2), 'Default CRS: EPSG:4326 - WGS 84') - self.assertEqual(cb.itemText(3), 'Layer CRS: EPSG:3111 - GDA94 / Vicgrid') + self.assertEqual(cb.itemText(0), "EPSG:4326 - WGS 84") + self.assertEqual(cb.itemText(1), "Project CRS: EPSG:3113 - GDA94 / BCSG02") + self.assertEqual(cb.itemText(2), "Default CRS: EPSG:4326 - WGS 84") + self.assertEqual(cb.itemText(3), "Layer CRS: EPSG:3111 - GDA94 / Vicgrid") # push some recent crs - registry.pushRecent(QgsCoordinateReferenceSystem('EPSG:3857')) + registry.pushRecent(QgsCoordinateReferenceSystem("EPSG:3857")) self.assertEqual(cb.count(), 5) - self.assertEqual(cb.itemText(0), 'EPSG:4326 - WGS 84') - self.assertEqual(cb.itemText(1), 'Project CRS: EPSG:3113 - GDA94 / BCSG02') - self.assertEqual(cb.itemText(2), 'Default CRS: EPSG:4326 - WGS 84') - self.assertEqual(cb.itemText(3), 'Layer CRS: EPSG:3111 - GDA94 / Vicgrid') - self.assertEqual(cb.itemText(4), 'EPSG:3857 - WGS 84 / Pseudo-Mercator') + self.assertEqual(cb.itemText(0), "EPSG:4326 - WGS 84") + self.assertEqual(cb.itemText(1), "Project CRS: EPSG:3113 - GDA94 / BCSG02") + self.assertEqual(cb.itemText(2), "Default CRS: EPSG:4326 - WGS 84") + self.assertEqual(cb.itemText(3), "Layer CRS: EPSG:3111 - GDA94 / Vicgrid") + self.assertEqual(cb.itemText(4), "EPSG:3857 - WGS 84 / Pseudo-Mercator") - registry.pushRecent(QgsCoordinateReferenceSystem('EPSG:28356')) + registry.pushRecent(QgsCoordinateReferenceSystem("EPSG:28356")) self.assertEqual(cb.count(), 6) - self.assertEqual(cb.itemText(0), 'EPSG:4326 - WGS 84') - self.assertEqual(cb.itemText(1), 'Project CRS: EPSG:3113 - GDA94 / BCSG02') - self.assertEqual(cb.itemText(2), 'Default CRS: EPSG:4326 - WGS 84') - self.assertEqual(cb.itemText(3), 'Layer CRS: EPSG:3111 - GDA94 / Vicgrid') - self.assertEqual(cb.itemText(4), 'EPSG:28356 - GDA94 / MGA zone 56') - self.assertEqual(cb.itemText(5), 'EPSG:3857 - WGS 84 / Pseudo-Mercator') + self.assertEqual(cb.itemText(0), "EPSG:4326 - WGS 84") + self.assertEqual(cb.itemText(1), "Project CRS: EPSG:3113 - GDA94 / BCSG02") + self.assertEqual(cb.itemText(2), "Default CRS: EPSG:4326 - WGS 84") + self.assertEqual(cb.itemText(3), "Layer CRS: EPSG:3111 - GDA94 / Vicgrid") + self.assertEqual(cb.itemText(4), "EPSG:28356 - GDA94 / MGA zone 56") + self.assertEqual(cb.itemText(5), "EPSG:3857 - WGS 84 / Pseudo-Mercator") # push a recent CRS which is already in the list (same as project crs) # this should not be shown twice - registry.pushRecent(QgsCoordinateReferenceSystem('EPSG:3111')) + registry.pushRecent(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertEqual(cb.count(), 6) - self.assertEqual(cb.itemText(0), 'EPSG:4326 - WGS 84') - self.assertEqual(cb.itemText(1), 'Project CRS: EPSG:3113 - GDA94 / BCSG02') - self.assertEqual(cb.itemText(2), 'Default CRS: EPSG:4326 - WGS 84') - self.assertEqual(cb.itemText(3), 'Layer CRS: EPSG:3111 - GDA94 / Vicgrid') - self.assertEqual(cb.itemText(4), 'EPSG:28356 - GDA94 / MGA zone 56') - self.assertEqual(cb.itemText(5), 'EPSG:3857 - WGS 84 / Pseudo-Mercator') - - registry.removeRecent(QgsCoordinateReferenceSystem('EPSG:3857')) + self.assertEqual(cb.itemText(0), "EPSG:4326 - WGS 84") + self.assertEqual(cb.itemText(1), "Project CRS: EPSG:3113 - GDA94 / BCSG02") + self.assertEqual(cb.itemText(2), "Default CRS: EPSG:4326 - WGS 84") + self.assertEqual(cb.itemText(3), "Layer CRS: EPSG:3111 - GDA94 / Vicgrid") + self.assertEqual(cb.itemText(4), "EPSG:28356 - GDA94 / MGA zone 56") + self.assertEqual(cb.itemText(5), "EPSG:3857 - WGS 84 / Pseudo-Mercator") + + registry.removeRecent(QgsCoordinateReferenceSystem("EPSG:3857")) self.assertEqual(cb.count(), 5) - self.assertEqual(cb.itemText(0), 'EPSG:4326 - WGS 84') - self.assertEqual(cb.itemText(1), 'Project CRS: EPSG:3113 - GDA94 / BCSG02') - self.assertEqual(cb.itemText(2), 'Default CRS: EPSG:4326 - WGS 84') - self.assertEqual(cb.itemText(3), 'Layer CRS: EPSG:3111 - GDA94 / Vicgrid') - self.assertEqual(cb.itemText(4), 'EPSG:28356 - GDA94 / MGA zone 56') + self.assertEqual(cb.itemText(0), "EPSG:4326 - WGS 84") + self.assertEqual(cb.itemText(1), "Project CRS: EPSG:3113 - GDA94 / BCSG02") + self.assertEqual(cb.itemText(2), "Default CRS: EPSG:4326 - WGS 84") + self.assertEqual(cb.itemText(3), "Layer CRS: EPSG:3111 - GDA94 / Vicgrid") + self.assertEqual(cb.itemText(4), "EPSG:28356 - GDA94 / MGA zone 56") spy = QSignalSpy(w.crsChanged) cb.setCurrentIndex(1) self.assertEqual(len(spy), 1) - self.assertEqual(spy[-1][0], QgsCoordinateReferenceSystem('EPSG:3113')) + self.assertEqual(spy[-1][0], QgsCoordinateReferenceSystem("EPSG:3113")) cb.setCurrentIndex(0) self.assertEqual(len(spy), 2) - self.assertEqual(spy[-1][0], QgsCoordinateReferenceSystem('EPSG:4326')) + self.assertEqual(spy[-1][0], QgsCoordinateReferenceSystem("EPSG:4326")) cb.setCurrentIndex(2) self.assertEqual(len(spy), 3) - self.assertEqual(spy[-1][0], QgsCoordinateReferenceSystem('EPSG:4326')) + self.assertEqual(spy[-1][0], QgsCoordinateReferenceSystem("EPSG:4326")) cb.setCurrentIndex(3) self.assertEqual(len(spy), 4) - self.assertEqual(spy[-1][0], QgsCoordinateReferenceSystem('EPSG:3111')) + self.assertEqual(spy[-1][0], QgsCoordinateReferenceSystem("EPSG:3111")) cb.setCurrentIndex(4) self.assertEqual(len(spy), 5) - self.assertEqual(spy[-1][0], QgsCoordinateReferenceSystem('EPSG:28356')) + self.assertEqual(spy[-1][0], QgsCoordinateReferenceSystem("EPSG:28356")) def testFilters(self): registry = QgsApplication.coordinateReferenceSystemRegistry() registry.clearRecent() # a horizontal crs - registry.pushRecent(QgsCoordinateReferenceSystem('EPSG:28356')) + registry.pushRecent(QgsCoordinateReferenceSystem("EPSG:28356")) # a vertical crs - registry.pushRecent(QgsCoordinateReferenceSystem('ESRI:115866')) + registry.pushRecent(QgsCoordinateReferenceSystem("ESRI:115866")) - QgsProject.instance().setCrs( - QgsCoordinateReferenceSystem('EPSG:3113')) + QgsProject.instance().setCrs(QgsCoordinateReferenceSystem("EPSG:3113")) w = QgsProjectionSelectionWidget() w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.LayerCrs, True) # some vertical crses - w.setLayerCrs(QgsCoordinateReferenceSystem('ESRI:115851')) - w.setCrs(QgsCoordinateReferenceSystem('ESRI:115852')) + w.setLayerCrs(QgsCoordinateReferenceSystem("ESRI:115851")) + w.setCrs(QgsCoordinateReferenceSystem("ESRI:115852")) w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs, True) w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.ProjectCrs, True) @@ -230,73 +280,74 @@ def testFilters(self): self.assertIsInstance(w.children()[0], QComboBox) cb = w.children()[0] self.assertEqual(cb.count(), 3) - self.assertEqual(cb.itemText(0), - 'Project CRS: EPSG:3113 - GDA94 / BCSG02') - self.assertEqual(cb.itemText(1), 'Default CRS: EPSG:4326 - WGS 84') - self.assertEqual(cb.itemText(2), - 'EPSG:28356 - GDA94 / MGA zone 56') + self.assertEqual(cb.itemText(0), "Project CRS: EPSG:3113 - GDA94 / BCSG02") + self.assertEqual(cb.itemText(1), "Default CRS: EPSG:4326 - WGS 84") + self.assertEqual(cb.itemText(2), "EPSG:28356 - GDA94 / MGA zone 56") # filter the combo to show horizontal and vertical - w.setFilters(QgsCoordinateReferenceSystemProxyModel.Filters( - QgsCoordinateReferenceSystemProxyModel.Filter.FilterHorizontal | - QgsCoordinateReferenceSystemProxyModel.Filter.FilterVertical - )) + w.setFilters( + QgsCoordinateReferenceSystemProxyModel.Filters( + QgsCoordinateReferenceSystemProxyModel.Filter.FilterHorizontal + | QgsCoordinateReferenceSystemProxyModel.Filter.FilterVertical + ) + ) self.assertEqual(cb.count(), 6) - self.assertEqual(cb.itemText(0), 'ESRI:115852 - SIRGAS-CON_DGF01P01') - self.assertEqual(cb.itemText(1), - 'Project CRS: EPSG:3113 - GDA94 / BCSG02') - self.assertEqual(cb.itemText(2), 'Default CRS: EPSG:4326 - WGS 84') - self.assertEqual(cb.itemText(3), - 'Layer CRS: ESRI:115851 - SIRGAS-CON_DGF00P01') - self.assertEqual(cb.itemText(4), - 'ESRI:115866 - SIRGAS-CON_SIR17P01') - self.assertEqual(cb.itemText(5), - 'EPSG:28356 - GDA94 / MGA zone 56') + self.assertEqual(cb.itemText(0), "ESRI:115852 - SIRGAS-CON_DGF01P01") + self.assertEqual(cb.itemText(1), "Project CRS: EPSG:3113 - GDA94 / BCSG02") + self.assertEqual(cb.itemText(2), "Default CRS: EPSG:4326 - WGS 84") + self.assertEqual(cb.itemText(3), "Layer CRS: ESRI:115851 - SIRGAS-CON_DGF00P01") + self.assertEqual(cb.itemText(4), "ESRI:115866 - SIRGAS-CON_SIR17P01") + self.assertEqual(cb.itemText(5), "EPSG:28356 - GDA94 / MGA zone 56") # only vertical - w.setFilters(QgsCoordinateReferenceSystemProxyModel.Filters( - QgsCoordinateReferenceSystemProxyModel.Filter.FilterVertical - )) + w.setFilters( + QgsCoordinateReferenceSystemProxyModel.Filters( + QgsCoordinateReferenceSystemProxyModel.Filter.FilterVertical + ) + ) self.assertEqual(cb.count(), 3) - self.assertEqual(cb.itemText(0), 'ESRI:115852 - SIRGAS-CON_DGF01P01') - self.assertEqual(cb.itemText(1), - 'Layer CRS: ESRI:115851 - SIRGAS-CON_DGF00P01') - self.assertEqual(cb.itemText(2), - 'ESRI:115866 - SIRGAS-CON_SIR17P01') + self.assertEqual(cb.itemText(0), "ESRI:115852 - SIRGAS-CON_DGF01P01") + self.assertEqual(cb.itemText(1), "Layer CRS: ESRI:115851 - SIRGAS-CON_DGF00P01") + self.assertEqual(cb.itemText(2), "ESRI:115866 - SIRGAS-CON_SIR17P01") def testFilteredCrs(self): registry = QgsApplication.coordinateReferenceSystemRegistry() registry.clearRecent() - QgsProject.instance().setCrs(QgsCoordinateReferenceSystem('EPSG:3113')) + QgsProject.instance().setCrs(QgsCoordinateReferenceSystem("EPSG:3113")) w = QgsProjectionSelectionWidget() w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.LayerCrs, True) - w.setLayerCrs(QgsCoordinateReferenceSystem('EPSG:3111')) - w.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + w.setLayerCrs(QgsCoordinateReferenceSystem("EPSG:3111")) + w.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.CurrentCrs, True) w.setOptionVisible(QgsProjectionSelectionWidget.CrsOption.ProjectCrs, True) self.assertIsInstance(w.children()[0], QComboBox) cb = w.children()[0] self.assertEqual(cb.count(), 4) - self.assertEqual(cb.itemText(0), 'EPSG:4326 - WGS 84') - self.assertEqual(cb.itemText(1), 'Project CRS: EPSG:3113 - GDA94 / BCSG02') - self.assertEqual(cb.itemText(2), 'Default CRS: EPSG:4326 - WGS 84') - self.assertEqual(cb.itemText(3), 'Layer CRS: EPSG:3111 - GDA94 / Vicgrid') - - w.setFilter([QgsCoordinateReferenceSystem('EPSG:3111'), QgsCoordinateReferenceSystem('EPSG:3113')]) + self.assertEqual(cb.itemText(0), "EPSG:4326 - WGS 84") + self.assertEqual(cb.itemText(1), "Project CRS: EPSG:3113 - GDA94 / BCSG02") + self.assertEqual(cb.itemText(2), "Default CRS: EPSG:4326 - WGS 84") + self.assertEqual(cb.itemText(3), "Layer CRS: EPSG:3111 - GDA94 / Vicgrid") + + w.setFilter( + [ + QgsCoordinateReferenceSystem("EPSG:3111"), + QgsCoordinateReferenceSystem("EPSG:3113"), + ] + ) self.assertEqual(cb.count(), 2) - self.assertEqual(cb.itemText(0), 'Project CRS: EPSG:3113 - GDA94 / BCSG02') - self.assertEqual(cb.itemText(1), 'Layer CRS: EPSG:3111 - GDA94 / Vicgrid') + self.assertEqual(cb.itemText(0), "Project CRS: EPSG:3113 - GDA94 / BCSG02") + self.assertEqual(cb.itemText(1), "Layer CRS: EPSG:3111 - GDA94 / Vicgrid") w.setFilter([]) self.assertEqual(cb.count(), 4) - self.assertEqual(cb.itemText(0), 'EPSG:4326 - WGS 84') - self.assertEqual(cb.itemText(1), 'Project CRS: EPSG:3113 - GDA94 / BCSG02') - self.assertEqual(cb.itemText(2), 'Default CRS: EPSG:4326 - WGS 84') - self.assertEqual(cb.itemText(3), 'Layer CRS: EPSG:3111 - GDA94 / Vicgrid') + self.assertEqual(cb.itemText(0), "EPSG:4326 - WGS 84") + self.assertEqual(cb.itemText(1), "Project CRS: EPSG:3113 - GDA94 / BCSG02") + self.assertEqual(cb.itemText(2), "Default CRS: EPSG:4326 - WGS 84") + self.assertEqual(cb.itemText(3), "Layer CRS: EPSG:3111 - GDA94 / Vicgrid") QgsProject.instance().setCrs(QgsCoordinateReferenceSystem()) @@ -304,34 +355,39 @@ def testSignal(self): w = QgsProjectionSelectionWidget() w.show() spy = QSignalSpy(w.crsChanged) - w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) - self.assertEqual(w.crs().authid(), 'EPSG:3111') + w.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) + self.assertEqual(w.crs().authid(), "EPSG:3111") self.assertEqual(len(spy), 1) # setting the same crs doesn't emit the signal - w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) + w.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertEqual(len(spy), 1) def testTreeWidgetGettersSetters(self): - """ basic tests for QgsProjectionSelectionTreeWidget """ + """basic tests for QgsProjectionSelectionTreeWidget""" w = QgsProjectionSelectionTreeWidget() self.assertFalse(w.hasValidSelection()) - w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) - self.assertEqual(w.crs().authid(), 'EPSG:3111') + w.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) + self.assertEqual(w.crs().authid(), "EPSG:3111") self.assertTrue(w.hasValidSelection()) def testTreeWidgetUnknownCrs(self): w = QgsProjectionSelectionTreeWidget() self.assertFalse(w.hasValidSelection()) - crs = QgsCoordinateReferenceSystem.fromWkt('GEOGCS["unknown",DATUM["unknown",SPHEROID["unknown",6378237,298.257223563]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433]]') + crs = QgsCoordinateReferenceSystem.fromWkt( + 'GEOGCS["unknown",DATUM["unknown",SPHEROID["unknown",6378237,298.257223563]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433]]' + ) self.assertTrue(crs.isValid()) w.setCrs(crs) self.assertTrue(w.crs().isValid()) self.assertFalse(w.crs().authid()) self.assertTrue(w.hasValidSelection()) - self.assertEqual(w.crs().toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT2_2018), 'GEOGCRS["unknown",DATUM["unknown",ELLIPSOID["unknown",6378237,298.257223563,LENGTHUNIT["metre",1,ID["EPSG",9001]]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["longitude",east,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["latitude",north,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]]]') + self.assertEqual( + w.crs().toWkt(QgsCoordinateReferenceSystem.WktVariant.WKT2_2018), + 'GEOGCRS["unknown",DATUM["unknown",ELLIPSOID["unknown",6378237,298.257223563,LENGTHUNIT["metre",1,ID["EPSG",9001]]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["longitude",east,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["latitude",north,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]]]', + ) def testTreeWidgetNotSetOption(self): - """ test allowing no projection option for QgsProjectionSelectionTreeWidget """ + """test allowing no projection option for QgsProjectionSelectionTreeWidget""" w = QgsProjectionSelectionTreeWidget() w.setShowNoProjection(True) self.assertTrue(w.showNoProjection()) @@ -345,13 +401,13 @@ def testTreeWidgetNotSetOption(self): self.assertFalse(w.crs().isValid()) def testDialogGettersSetters(self): - """ basic tests for QgsProjectionSelectionTreeWidget """ + """basic tests for QgsProjectionSelectionTreeWidget""" w = QgsProjectionSelectionDialog() - w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) - self.assertEqual(w.crs().authid(), 'EPSG:3111') + w.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) + self.assertEqual(w.crs().authid(), "EPSG:3111") def testDialogNotSetOption(self): - """ test allowing no projection option for QgsProjectionSelectionTreeWidget """ + """test allowing no projection option for QgsProjectionSelectionTreeWidget""" w = QgsProjectionSelectionDialog() w.setShowNoProjection(True) self.assertTrue(w.showNoProjection()) @@ -369,10 +425,10 @@ def testTreeWidgetDeferredLoad(self): w = QgsProjectionSelectionTreeWidget() spy = QSignalSpy(w.crsSelected) self.assertFalse(w.hasValidSelection()) - w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) + w.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertEqual(len(spy), 1) self.assertTrue(w.hasValidSelection()) - self.assertEqual(w.crs().authid(), 'EPSG:3111') + self.assertEqual(w.crs().authid(), "EPSG:3111") self.assertEqual(len(spy), 1) w = QgsProjectionSelectionTreeWidget() @@ -383,17 +439,17 @@ def testTreeWidgetDeferredLoad(self): self.assertTrue(w.hasValidSelection()) self.assertFalse(w.crs().isValid()) self.assertEqual(len(spy), 1) - w.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + w.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) self.assertEqual(len(spy), 2) # expect same behavior if we show w = QgsProjectionSelectionTreeWidget() spy = QSignalSpy(w.crsSelected) self.assertFalse(w.hasValidSelection()) - w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) + w.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertEqual(len(spy), 1) self.assertTrue(w.hasValidSelection()) - self.assertEqual(w.crs().authid(), 'EPSG:3111') + self.assertEqual(w.crs().authid(), "EPSG:3111") self.assertEqual(len(spy), 1) w = QgsProjectionSelectionTreeWidget() @@ -409,21 +465,21 @@ def testTreeWidgetDeferredLoad(self): w = QgsProjectionSelectionTreeWidget() spy = QSignalSpy(w.crsSelected) self.assertFalse(w.hasValidSelection()) - w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) - w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) + w.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) + w.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertEqual(len(spy), 1) # no double signals if same crs set w = QgsProjectionSelectionTreeWidget() spy = QSignalSpy(w.crsSelected) self.assertFalse(w.hasValidSelection()) - w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) - w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) - w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) + w.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) + w.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) + w.setCrs(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertEqual(len(spy), 1) - w.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + w.setCrs(QgsCoordinateReferenceSystem("EPSG:4326")) self.assertEqual(len(spy), 2) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprojectmetadata.py b/tests/src/python/test_qgsprojectmetadata.py index 54446251102e..6fae74e15835 100644 --- a/tests/src/python/test_qgsprojectmetadata.py +++ b/tests/src/python/test_qgsprojectmetadata.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '19/03/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "19/03/2018" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, QTime from qgis.PyQt.QtTest import QSignalSpy @@ -31,99 +32,106 @@ class TestQgsProjectMetadata(QgisTestCase): def testGettersSetters(self): m = QgsProjectMetadata() - m.setIdentifier('identifier') - self.assertEqual(m.identifier(), 'identifier') + m.setIdentifier("identifier") + self.assertEqual(m.identifier(), "identifier") - m.setParentIdentifier('parent identifier') - self.assertEqual(m.parentIdentifier(), 'parent identifier') + m.setParentIdentifier("parent identifier") + self.assertEqual(m.parentIdentifier(), "parent identifier") - m.setLanguage('en-us') - self.assertEqual(m.language(), 'en-us') + m.setLanguage("en-us") + self.assertEqual(m.language(), "en-us") - m.setType('type') - self.assertEqual(m.type(), 'type') + m.setType("type") + self.assertEqual(m.type(), "type") - m.setTitle('title') - self.assertEqual(m.title(), 'title') + m.setTitle("title") + self.assertEqual(m.title(), "title") - m.setCategories(['category']) - self.assertEqual(m.categories(), ['category']) + m.setCategories(["category"]) + self.assertEqual(m.categories(), ["category"]) - m.setAbstract('abstract') - self.assertEqual(m.abstract(), 'abstract') + m.setAbstract("abstract") + self.assertEqual(m.abstract(), "abstract") - m.setHistory(['loaded into QGIS']) - self.assertEqual(m.history(), ['loaded into QGIS']) - m.setHistory(['accidentally deleted some features']) - self.assertEqual(m.history(), ['accidentally deleted some features']) - m.addHistoryItem('panicked and deleted more') - self.assertEqual(m.history(), ['accidentally deleted some features', 'panicked and deleted more']) + m.setHistory(["loaded into QGIS"]) + self.assertEqual(m.history(), ["loaded into QGIS"]) + m.setHistory(["accidentally deleted some features"]) + self.assertEqual(m.history(), ["accidentally deleted some features"]) + m.addHistoryItem("panicked and deleted more") + self.assertEqual( + m.history(), + ["accidentally deleted some features", "panicked and deleted more"], + ) - m.setAuthor('my author') - self.assertEqual(m.author(), 'my author') + m.setAuthor("my author") + self.assertEqual(m.author(), "my author") m.setCreationDateTime(QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))) - self.assertEqual(m.creationDateTime(), QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))) + self.assertEqual( + m.creationDateTime(), QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)) + ) def createTestMetadata(self): """ Returns a standard metadata which can be tested with checkExpectedMetadata """ m = QgsProjectMetadata() - m.setIdentifier('1234') - m.setParentIdentifier('xyz') - m.setLanguage('en-CA') - m.setType('project') - m.setTitle('roads') - m.setAbstract('my roads') - m.setHistory(['history a', 'history b']) - m.setKeywords({ - 'GEMET': ['kw1', 'kw2'], - 'gmd:topicCategory': ['natural'], - }) + m.setIdentifier("1234") + m.setParentIdentifier("xyz") + m.setLanguage("en-CA") + m.setType("project") + m.setTitle("roads") + m.setAbstract("my roads") + m.setHistory(["history a", "history b"]) + m.setKeywords( + { + "GEMET": ["kw1", "kw2"], + "gmd:topicCategory": ["natural"], + } + ) c = QgsAbstractMetadataBase.Contact() - c.name = 'John Smith' - c.organization = 'ACME' - c.position = 'staff' - c.voice = '1500 515 555' - c.fax = 'xx.xxx.xxx.xxxx' - c.email = 'foo@example.org' - c.role = 'pointOfContact' + c.name = "John Smith" + c.organization = "ACME" + c.position = "staff" + c.voice = "1500 515 555" + c.fax = "xx.xxx.xxx.xxxx" + c.email = "foo@example.org" + c.role = "pointOfContact" address = QgsAbstractMetadataBase.Address() - address.type = 'postal' - address.address = '123 Main Street' - address.city = 'anycity' - address.administrativeArea = 'anyprovince' - address.postalCode = '90210' - address.country = 'Canada' + address.type = "postal" + address.address = "123 Main Street" + address.city = "anycity" + address.administrativeArea = "anyprovince" + address.postalCode = "90210" + address.country = "Canada" c.addresses = [address] m.setContacts([c]) l = QgsAbstractMetadataBase.Link() - l.name = 'geonode:roads' - l.type = 'OGC:WMS' - l.description = 'my GeoNode road layer' - l.url = 'http://example.org/wms' + l.name = "geonode:roads" + l.type = "OGC:WMS" + l.description = "my GeoNode road layer" + l.url = "http://example.org/wms" l2 = QgsAbstractMetadataBase.Link() - l2.name = 'geonode:roads' - l2.type = 'OGC:WFS' - l2.description = 'my GeoNode road layer' - l2.url = 'http://example.org/wfs' + l2.name = "geonode:roads" + l2.type = "OGC:WFS" + l2.description = "my GeoNode road layer" + l2.url = "http://example.org/wfs" l3 = QgsAbstractMetadataBase.Link() - l3.name = 'roads' - l3.type = 'WWW:LINK' - l3.description = 'full dataset download' - l3.url = 'http://example.org/roads.tgz' - l3.format = 'ESRI Shapefile' - l3.mimeType = 'application/gzip' - l3.size = '283676' + l3.name = "roads" + l3.type = "WWW:LINK" + l3.description = "full dataset download" + l3.url = "http://example.org/roads.tgz" + l3.format = "ESRI Shapefile" + l3.mimeType = "application/gzip" + l3.size = "283676" m.setLinks([l, l2, l3]) - m.setAuthor('my author') + m.setAuthor("my author") m.setCreationDateTime(QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))) return m @@ -133,7 +141,7 @@ def testEquality(self): md2 = self.createTestMetadata() self.assertEqual(md, md2) - md2.setAuthor('xx') + md2.setAuthor("xx") self.assertNotEqual(md, md2) md2 = self.createTestMetadata() @@ -144,48 +152,50 @@ def checkExpectedMetadata(self, m): """ Checks that a metadata object matches that returned by createTestMetadata """ - self.assertEqual(m.identifier(), '1234') - self.assertEqual(m.parentIdentifier(), 'xyz') - self.assertEqual(m.language(), 'en-CA') - self.assertEqual(m.type(), 'project') - self.assertEqual(m.title(), 'roads') - self.assertEqual(m.abstract(), 'my roads') - self.assertEqual(m.history(), ['history a', 'history b']) + self.assertEqual(m.identifier(), "1234") + self.assertEqual(m.parentIdentifier(), "xyz") + self.assertEqual(m.language(), "en-CA") + self.assertEqual(m.type(), "project") + self.assertEqual(m.title(), "roads") + self.assertEqual(m.abstract(), "my roads") + self.assertEqual(m.history(), ["history a", "history b"]) + self.assertEqual( + m.keywords(), {"GEMET": ["kw1", "kw2"], "gmd:topicCategory": ["natural"]} + ) + + self.assertEqual(m.contacts()[0].name, "John Smith") + self.assertEqual(m.contacts()[0].organization, "ACME") + self.assertEqual(m.contacts()[0].position, "staff") + self.assertEqual(m.contacts()[0].voice, "1500 515 555") + self.assertEqual(m.contacts()[0].fax, "xx.xxx.xxx.xxxx") + self.assertEqual(m.contacts()[0].email, "foo@example.org") + self.assertEqual(m.contacts()[0].role, "pointOfContact") + self.assertEqual(m.contacts()[0].addresses[0].type, "postal") + self.assertEqual(m.contacts()[0].addresses[0].address, "123 Main Street") + self.assertEqual(m.contacts()[0].addresses[0].city, "anycity") + self.assertEqual(m.contacts()[0].addresses[0].administrativeArea, "anyprovince") + self.assertEqual(m.contacts()[0].addresses[0].postalCode, "90210") + self.assertEqual(m.contacts()[0].addresses[0].country, "Canada") + self.assertEqual(m.links()[0].name, "geonode:roads") + self.assertEqual(m.links()[0].type, "OGC:WMS") + self.assertEqual(m.links()[0].description, "my GeoNode road layer") + self.assertEqual(m.links()[0].url, "http://example.org/wms") + self.assertEqual(m.links()[1].name, "geonode:roads") + self.assertEqual(m.links()[1].type, "OGC:WFS") + self.assertEqual(m.links()[1].description, "my GeoNode road layer") + self.assertEqual(m.links()[1].url, "http://example.org/wfs") + self.assertEqual(m.links()[2].name, "roads") + self.assertEqual(m.links()[2].type, "WWW:LINK") + self.assertEqual(m.links()[2].description, "full dataset download") + self.assertEqual(m.links()[2].url, "http://example.org/roads.tgz") + self.assertEqual(m.links()[2].format, "ESRI Shapefile") + self.assertEqual(m.links()[2].mimeType, "application/gzip") + self.assertEqual(m.links()[2].size, "283676") + + self.assertEqual(m.author(), "my author") self.assertEqual( - m.keywords(), - {'GEMET': ['kw1', 'kw2'], 'gmd:topicCategory': ['natural']}) - - self.assertEqual(m.contacts()[0].name, 'John Smith') - self.assertEqual(m.contacts()[0].organization, 'ACME') - self.assertEqual(m.contacts()[0].position, 'staff') - self.assertEqual(m.contacts()[0].voice, '1500 515 555') - self.assertEqual(m.contacts()[0].fax, 'xx.xxx.xxx.xxxx') - self.assertEqual(m.contacts()[0].email, 'foo@example.org') - self.assertEqual(m.contacts()[0].role, 'pointOfContact') - self.assertEqual(m.contacts()[0].addresses[0].type, 'postal') - self.assertEqual(m.contacts()[0].addresses[0].address, '123 Main Street') - self.assertEqual(m.contacts()[0].addresses[0].city, 'anycity') - self.assertEqual(m.contacts()[0].addresses[0].administrativeArea, 'anyprovince') - self.assertEqual(m.contacts()[0].addresses[0].postalCode, '90210') - self.assertEqual(m.contacts()[0].addresses[0].country, 'Canada') - self.assertEqual(m.links()[0].name, 'geonode:roads') - self.assertEqual(m.links()[0].type, 'OGC:WMS') - self.assertEqual(m.links()[0].description, 'my GeoNode road layer') - self.assertEqual(m.links()[0].url, 'http://example.org/wms') - self.assertEqual(m.links()[1].name, 'geonode:roads') - self.assertEqual(m.links()[1].type, 'OGC:WFS') - self.assertEqual(m.links()[1].description, 'my GeoNode road layer') - self.assertEqual(m.links()[1].url, 'http://example.org/wfs') - self.assertEqual(m.links()[2].name, 'roads') - self.assertEqual(m.links()[2].type, 'WWW:LINK') - self.assertEqual(m.links()[2].description, 'full dataset download') - self.assertEqual(m.links()[2].url, 'http://example.org/roads.tgz') - self.assertEqual(m.links()[2].format, 'ESRI Shapefile') - self.assertEqual(m.links()[2].mimeType, 'application/gzip') - self.assertEqual(m.links()[2].size, '283676') - - self.assertEqual(m.author(), 'my author') - self.assertEqual(m.creationDateTime(), QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))) + m.creationDateTime(), QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)) + ) def testStandard(self): m = self.createTestMetadata() @@ -221,108 +231,108 @@ def testValidateNative(self): # spellok # corrupt metadata piece by piece... m = self.createTestMetadata() - m.setIdentifier('') + m.setIdentifier("") res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'identifier') + self.assertEqual(list[0].section, "identifier") m = self.createTestMetadata() - m.setLanguage('') + m.setLanguage("") res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'language') + self.assertEqual(list[0].section, "language") m = self.createTestMetadata() - m.setType('') + m.setType("") res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'type') + self.assertEqual(list[0].section, "type") m = self.createTestMetadata() - m.setTitle('') + m.setTitle("") res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'title') + self.assertEqual(list[0].section, "title") m = self.createTestMetadata() - m.setAbstract('') + m.setAbstract("") res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'abstract') + self.assertEqual(list[0].section, "abstract") m = self.createTestMetadata() m.setContacts([]) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'contacts') + self.assertEqual(list[0].section, "contacts") m = self.createTestMetadata() m.setLinks([]) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'links') + self.assertEqual(list[0].section, "links") m = self.createTestMetadata() - m.setKeywords({'': ['kw1', 'kw2']}) + m.setKeywords({"": ["kw1", "kw2"]}) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'keywords') + self.assertEqual(list[0].section, "keywords") self.assertEqual(list[0].identifier, 0) m = self.createTestMetadata() - m.setKeywords({'AA': []}) + m.setKeywords({"AA": []}) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'keywords') + self.assertEqual(list[0].section, "keywords") self.assertEqual(list[0].identifier, 0) m = self.createTestMetadata() c = m.contacts()[0] - c.name = '' + c.name = "" m.setContacts([c]) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'contacts') + self.assertEqual(list[0].section, "contacts") self.assertEqual(list[0].identifier, 0) m = self.createTestMetadata() l = m.links()[0] - l.name = '' + l.name = "" m.setLinks([l]) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'links') + self.assertEqual(list[0].section, "links") self.assertEqual(list[0].identifier, 0) m = self.createTestMetadata() l = m.links()[0] - l.type = '' + l.type = "" m.setLinks([l]) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'links') + self.assertEqual(list[0].section, "links") self.assertEqual(list[0].identifier, 0) m = self.createTestMetadata() l = m.links()[0] - l.url = '' + l.url = "" m.setLinks([l]) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'links') + self.assertEqual(list[0].section, "links") self.assertEqual(list[0].identifier, 0) m = self.createTestMetadata() - m.setAuthor('') + m.setAuthor("") res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'author') + self.assertEqual(list[0].section, "author") m = self.createTestMetadata() m.setCreationDateTime(QDateTime()) res, list = v.validate(m) self.assertFalse(res) - self.assertEqual(list[0].section, 'creation') + self.assertEqual(list[0].section, "creation") def testProject(self): p = QgsProject() @@ -335,135 +345,149 @@ def testProject(self): p.clear() self.assertEqual(len(metadata_changed_spy), 2) - self.assertEqual(p.metadata().title(), '') + self.assertEqual(p.metadata().title(), "") # test that the project title is just a shortcut to the metadata title field - p.setTitle('my title') - self.assertEqual(p.metadata().title(), 'my title') - m.setTitle('my title 2') + p.setTitle("my title") + self.assertEqual(p.metadata().title(), "my title") + m.setTitle("my title 2") p.setMetadata(m) - self.assertEqual(p.title(), 'my title 2') + self.assertEqual(p.title(), "my title 2") def testCombine(self): m1 = QgsProjectMetadata() m2 = QgsProjectMetadata() # should be retained - m1.setIdentifier('i1') + m1.setIdentifier("i1") m1.combine(m2) - self.assertEqual(m1.identifier(), 'i1') + self.assertEqual(m1.identifier(), "i1") # should be overwritten m1.setIdentifier(None) - m2.setIdentifier('i2') + m2.setIdentifier("i2") m1.combine(m2) - self.assertEqual(m1.identifier(), 'i2') + self.assertEqual(m1.identifier(), "i2") # should be overwritten - m1.setIdentifier('i1') - m2.setIdentifier('i2') + m1.setIdentifier("i1") + m2.setIdentifier("i2") m1.combine(m2) - self.assertEqual(m1.identifier(), 'i2') + self.assertEqual(m1.identifier(), "i2") - m1.setParentIdentifier('pi1') + m1.setParentIdentifier("pi1") m2.setParentIdentifier(None) m1.combine(m2) - self.assertEqual(m1.parentIdentifier(), 'pi1') + self.assertEqual(m1.parentIdentifier(), "pi1") m1.setParentIdentifier(None) - m2.setParentIdentifier('pi2') + m2.setParentIdentifier("pi2") m1.combine(m2) - self.assertEqual(m1.parentIdentifier(), 'pi2') + self.assertEqual(m1.parentIdentifier(), "pi2") - m1.setLanguage('l1') + m1.setLanguage("l1") m2.setLanguage(None) m1.combine(m2) - self.assertEqual(m1.language(), 'l1') + self.assertEqual(m1.language(), "l1") m1.setLanguage(None) - m2.setLanguage('l2') + m2.setLanguage("l2") m1.combine(m2) - self.assertEqual(m1.language(), 'l2') + self.assertEqual(m1.language(), "l2") - m1.setType('ty1') + m1.setType("ty1") m2.setType(None) m1.combine(m2) - self.assertEqual(m1.type(), 'ty1') + self.assertEqual(m1.type(), "ty1") m1.setType(None) - m2.setType('ty2') + m2.setType("ty2") m1.combine(m2) - self.assertEqual(m1.type(), 'ty2') + self.assertEqual(m1.type(), "ty2") - m1.setTitle('t1') + m1.setTitle("t1") m2.setTitle(None) m1.combine(m2) - self.assertEqual(m1.title(), 't1') + self.assertEqual(m1.title(), "t1") m1.setTitle(None) - m2.setTitle('t2') + m2.setTitle("t2") m1.combine(m2) - self.assertEqual(m1.title(), 't2') + self.assertEqual(m1.title(), "t2") - m1.setAbstract('a1') + m1.setAbstract("a1") m2.setAbstract(None) m1.combine(m2) - self.assertEqual(m1.abstract(), 'a1') + self.assertEqual(m1.abstract(), "a1") m1.setAbstract(None) - m2.setAbstract('a2') + m2.setAbstract("a2") m1.combine(m2) - self.assertEqual(m1.abstract(), 'a2') + self.assertEqual(m1.abstract(), "a2") - m1.setHistory(['h1', 'hh1']) + m1.setHistory(["h1", "hh1"]) m2.setHistory([]) m1.combine(m2) - self.assertEqual(m1.history(), ['h1', 'hh1']) + self.assertEqual(m1.history(), ["h1", "hh1"]) m1.setHistory([]) - m2.setHistory(['h2', 'hh2']) + m2.setHistory(["h2", "hh2"]) m1.combine(m2) - self.assertEqual(m1.history(), ['h2', 'hh2']) + self.assertEqual(m1.history(), ["h2", "hh2"]) - m1.setKeywords({'words': ['k1', 'kk1']}) + m1.setKeywords({"words": ["k1", "kk1"]}) m2.setKeywords({}) m1.combine(m2) - self.assertEqual(m1.keywords(), {'words': ['k1', 'kk1']}) + self.assertEqual(m1.keywords(), {"words": ["k1", "kk1"]}) m1.setKeywords({}) - m2.setKeywords({'words': ['k2', 'kk2']}) + m2.setKeywords({"words": ["k2", "kk2"]}) m1.combine(m2) - self.assertEqual(m1.keywords(), {'words': ['k2', 'kk2']}) + self.assertEqual(m1.keywords(), {"words": ["k2", "kk2"]}) - m1.setContacts([QgsProjectMetadata.Contact('c1'), QgsProjectMetadata.Contact('cc1')]) + m1.setContacts( + [QgsProjectMetadata.Contact("c1"), QgsProjectMetadata.Contact("cc1")] + ) m2.setContacts([]) m1.combine(m2) - self.assertEqual(m1.contacts(), [QgsProjectMetadata.Contact('c1'), QgsProjectMetadata.Contact('cc1')]) + self.assertEqual( + m1.contacts(), + [QgsProjectMetadata.Contact("c1"), QgsProjectMetadata.Contact("cc1")], + ) m1.setContacts([]) - m2.setContacts([QgsProjectMetadata.Contact('c2'), QgsProjectMetadata.Contact('cc2')]) + m2.setContacts( + [QgsProjectMetadata.Contact("c2"), QgsProjectMetadata.Contact("cc2")] + ) m1.combine(m2) - self.assertEqual(m1.contacts(), [QgsProjectMetadata.Contact('c2'), QgsProjectMetadata.Contact('cc2')]) + self.assertEqual( + m1.contacts(), + [QgsProjectMetadata.Contact("c2"), QgsProjectMetadata.Contact("cc2")], + ) - m1.setLinks([QgsProjectMetadata.Link('l1'), QgsProjectMetadata.Link('ll1')]) + m1.setLinks([QgsProjectMetadata.Link("l1"), QgsProjectMetadata.Link("ll1")]) m2.setLinks([]) m1.combine(m2) - self.assertEqual(m1.links(), [QgsProjectMetadata.Link('l1'), QgsProjectMetadata.Link('ll1')]) + self.assertEqual( + m1.links(), [QgsProjectMetadata.Link("l1"), QgsProjectMetadata.Link("ll1")] + ) m1.setLinks([]) - m2.setLinks([QgsProjectMetadata.Link('l2'), QgsProjectMetadata.Link('ll2')]) + m2.setLinks([QgsProjectMetadata.Link("l2"), QgsProjectMetadata.Link("ll2")]) m1.combine(m2) - self.assertEqual(m1.links(), [QgsProjectMetadata.Link('l2'), QgsProjectMetadata.Link('ll2')]) + self.assertEqual( + m1.links(), [QgsProjectMetadata.Link("l2"), QgsProjectMetadata.Link("ll2")] + ) - m1.setAuthor('au1') + m1.setAuthor("au1") m2.setAuthor(None) m1.combine(m2) - self.assertEqual(m1.author(), 'au1') + self.assertEqual(m1.author(), "au1") m1.setAuthor(None) - m2.setAuthor('au2') + m2.setAuthor("au2") m1.combine(m2) - self.assertEqual(m1.author(), 'au2') + self.assertEqual(m1.author(), "au2") m1.setCreationDateTime(QDateTime(2020, 1, 1, 0, 0, 0)) m2.setCreationDateTime(QDateTime()) @@ -476,5 +500,5 @@ def testCombine(self): self.assertEqual(m1.creationDateTime(), QDateTime(2021, 1, 1, 0, 0, 0)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprojectrelationmanager.py b/tests/src/python/test_qgsprojectrelationmanager.py index 6dc33de126c1..26003580f3d1 100644 --- a/tests/src/python/test_qgsprojectrelationmanager.py +++ b/tests/src/python/test_qgsprojectrelationmanager.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'David Marteau' -__date__ = '19/12/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "David Marteau" +__date__ = "19/12/2019" +__copyright__ = "Copyright 2019, The QGIS Project" import os @@ -33,15 +34,20 @@ def createReferencingLayer(): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=foreignkey:integer", - "referencinglayer", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=foreignkey:integer", + "referencinglayer", + "memory", + ) return layer def createReferencedLayer(): layer = QgsVectorLayer( "Point?field=x:string&field=y:integer&field=z:integer", - "referencedlayer", "memory") + "referencedlayer", + "memory", + ) return layer @@ -55,8 +61,7 @@ def setUp(self): self.project.addMapLayers([self.referencedLayer, self.referencingLayer]) def test_addRelation(self): - """ test adding relations to a manager - """ + """test adding relations to a manager""" manager = self.project.relationManager() relations = manager.relations() self.assertEqual(len(relations), 0) @@ -64,27 +69,31 @@ def test_addRelation(self): rel = QgsRelation(manager.context()) rel.setReferencingLayer(self.referencingLayer.id()) rel.setReferencedLayer(self.referencedLayer.id()) - rel.addFieldPair('foreignkey', 'y') + rel.addFieldPair("foreignkey", "y") - rel.setId('rel1') - rel.setName('Relation Number One') + rel.setId("rel1") + rel.setName("Relation Number One") assert rel.isValid() manager.addRelation(rel) relations = manager.relations() self.assertEqual(len(relations), 1) - self.assertEqual(relations['rel1'].id(), 'rel1') + self.assertEqual(relations["rel1"].id(), "rel1") def test_loadRelation(self): - """ Test loading relation with project """ + """Test loading relation with project""" project = QgsProject() - project.read(os.path.join(unitTestDataPath(), 'projects', 'test-project-with-relations.qgs')) + project.read( + os.path.join( + unitTestDataPath(), "projects", "test-project-with-relations.qgs" + ) + ) manager = project.relationManager() relations = manager.relations() assert len(relations) > 0 -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprojectservervalidator.py b/tests/src/python/test_qgsprojectservervalidator.py index 30f88920ba72..88ff6b8d525b 100644 --- a/tests/src/python/test_qgsprojectservervalidator.py +++ b/tests/src/python/test_qgsprojectservervalidator.py @@ -8,9 +8,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Etienne Trimaille' -__date__ = '27/03/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Etienne Trimaille" +__date__ = "27/03/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.core import QgsProject, QgsProjectServerValidator, QgsVectorLayer import unittest @@ -24,7 +25,7 @@ class TestQgsprojectServerValidator(QgisTestCase): def test_project_server_validator(self): """Test project server validator.""" project = QgsProject() - layer = QgsVectorLayer('Point?field=fldtxt:string', 'layer_1', 'memory') + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer_1", "memory") project.addMapLayers([layer]) # Valid @@ -32,82 +33,97 @@ def test_project_server_validator(self): self.assertTrue(valid) self.assertFalse(results) - layer_1 = QgsVectorLayer('Point?field=fldtxt:string', 'layer_1', 'memory') + layer_1 = QgsVectorLayer("Point?field=fldtxt:string", "layer_1", "memory") project.addMapLayers([layer_1]) # Not valid, same layer name valid, results = QgsProjectServerValidator.validate(project) self.assertFalse(valid) self.assertEqual(1, len(results)) - self.assertEqual(QgsProjectServerValidator.ValidationError.DuplicatedNames, results[0].error) + self.assertEqual( + QgsProjectServerValidator.ValidationError.DuplicatedNames, results[0].error + ) # Not valid, short name is invalid - layer_1.setShortName('layer_1_invalid_#') + layer_1.setShortName("layer_1_invalid_#") valid, results = QgsProjectServerValidator.validate(project) self.assertFalse(valid) self.assertEqual(1, len(results)) - self.assertEqual(QgsProjectServerValidator.ValidationError.LayerShortName, results[0].error) + self.assertEqual( + QgsProjectServerValidator.ValidationError.LayerShortName, results[0].error + ) # Not valid, same short name as the first layer name - layer_1.setShortName('layer_1') + layer_1.setShortName("layer_1") valid, results = QgsProjectServerValidator.validate(project) self.assertFalse(valid) self.assertEqual(1, len(results)) - self.assertEqual(QgsProjectServerValidator.ValidationError.DuplicatedNames, results[0].error) + self.assertEqual( + QgsProjectServerValidator.ValidationError.DuplicatedNames, results[0].error + ) # Valid - layer_1.setShortName('layer_1_bis') + layer_1.setShortName("layer_1_bis") valid, results = QgsProjectServerValidator.validate(project) self.assertTrue(valid) self.assertEqual(0, len(results)) # Not valid, a group with same name as the first layer - group = project.layerTreeRoot().addGroup('layer_1') + group = project.layerTreeRoot().addGroup("layer_1") valid, results = QgsProjectServerValidator.validate(project) self.assertFalse(valid) self.assertEqual(1, len(results)) - self.assertEqual(QgsProjectServerValidator.ValidationError.DuplicatedNames, results[0].error) + self.assertEqual( + QgsProjectServerValidator.ValidationError.DuplicatedNames, results[0].error + ) # Valid - group.setCustomProperty('wmsShortName', 'my_group1') + group.setCustomProperty("wmsShortName", "my_group1") valid, results = QgsProjectServerValidator.validate(project) self.assertTrue(valid) self.assertEqual(0, len(results)) # Not valid, the project title is invalid - project.setTitle('@ layer 1') + project.setTitle("@ layer 1") valid, results = QgsProjectServerValidator.validate(project) self.assertFalse(valid) self.assertEqual(1, len(results)) - self.assertEqual(QgsProjectServerValidator.ValidationError.ProjectShortName, results[0].error) + self.assertEqual( + QgsProjectServerValidator.ValidationError.ProjectShortName, results[0].error + ) # Valid project title - project.setTitle('project_title') + project.setTitle("project_title") valid, results = QgsProjectServerValidator.validate(project) self.assertTrue(valid) self.assertEqual(0, len(results)) # Valid despite the bad project title, use project short name - project.setTitle('@ layer 1') - project.writeEntry('WMSRootName', '/', 'project_short_name') + project.setTitle("@ layer 1") + project.writeEntry("WMSRootName", "/", "project_short_name") valid, results = QgsProjectServerValidator.validate(project) self.assertTrue(valid) self.assertEqual(0, len(results)) # Not valid project short name - project.setTitle('project_title') - project.writeEntry('WMSRootName', '/', 'project with space') + project.setTitle("project_title") + project.writeEntry("WMSRootName", "/", "project with space") valid, results = QgsProjectServerValidator.validate(project) self.assertFalse(valid) self.assertEqual(1, len(results)) - self.assertEqual(QgsProjectServerValidator.ValidationError.ProjectShortName, results[0].error) + self.assertEqual( + QgsProjectServerValidator.ValidationError.ProjectShortName, results[0].error + ) # Not valid, duplicated project short name - project.writeEntry('WMSRootName', '/', 'layer_1') + project.writeEntry("WMSRootName", "/", "layer_1") valid, results = QgsProjectServerValidator.validate(project) self.assertEqual(1, len(results)) - self.assertEqual(QgsProjectServerValidator.ValidationError.ProjectRootNameConflict, results[0].error) + self.assertEqual( + QgsProjectServerValidator.ValidationError.ProjectRootNameConflict, + results[0].error, + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprojectstylesettings.py b/tests/src/python/test_qgsprojectstylesettings.py index fe7306f2acde..b423c4c0242b 100644 --- a/tests/src/python/test_qgsprojectstylesettings.py +++ b/tests/src/python/test_qgsprojectstylesettings.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Mathieu Pellerin' -__date__ = '09/05/2022' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Mathieu Pellerin" +__date__ = "09/05/2022" +__copyright__ = "Copyright 2019, The QGIS Project" from qgis.PyQt.QtCore import ( QCoreApplication, @@ -16,7 +17,7 @@ QModelIndex, Qt, QTemporaryDir, - QTemporaryFile + QTemporaryFile, ) from qgis.PyQt.QtGui import QColor, QColorSpace, QFont from qgis.PyQt.QtTest import QSignalSpy @@ -122,12 +123,18 @@ def testProjectStyle(self): project = QgsProject() settings = project.styleSettings() self.assertIsInstance(settings.projectStyle(), QgsStyle) - self.assertEqual(settings.projectStyle().name(), 'Project Styles') + self.assertEqual(settings.projectStyle().name(), "Project Styles") text_format = QgsTextFormat() text_format.setColor(QColor(255, 0, 0)) - self.assertTrue(settings.projectStyle().addTextFormat('my text format', text_format)) - self.assertTrue(settings.projectStyle().saveTextFormat('my text format', text_format, True, [])) + self.assertTrue( + settings.projectStyle().addTextFormat("my text format", text_format) + ) + self.assertTrue( + settings.projectStyle().saveTextFormat( + "my text format", text_format, True, [] + ) + ) self.assertEqual(settings.projectStyle().textFormatCount(), 1) tmp_dir = QTemporaryDir() @@ -141,12 +148,21 @@ def testProjectStyle(self): project2 = QgsProject() self.assertTrue(project2.read(tmp_project_file)) self.assertEqual(project2.styleSettings().projectStyle().textFormatCount(), 1) - self.assertEqual(project2.styleSettings().projectStyle().textFormat('my text format').color().name(), '#ff0000') + self.assertEqual( + project2.styleSettings() + .projectStyle() + .textFormat("my text format") + .color() + .name(), + "#ff0000", + ) project2.clear() self.assertEqual(project2.styleSettings().projectStyle().textFormatCount(), 0) - @unittest.skipIf(QgsCombinedStyleModel is None, "QgsCombinedStyleModel not available") + @unittest.skipIf( + QgsCombinedStyleModel is None, "QgsCombinedStyleModel not available" + ) def testStylePaths(self): p = QgsProjectStyleSettings() spy = QSignalSpy(p.styleDatabasesChanged) @@ -155,10 +171,12 @@ def testStylePaths(self): model_with_default = QgsProjectStyleDatabaseModel(p) model_with_default.setShowDefaultStyle(True) proxy_model = QgsProjectStyleDatabaseProxyModel(model_with_default) - proxy_model.setFilters(QgsProjectStyleDatabaseProxyModel.Filter.FilterHideReadOnly) + proxy_model.setFilters( + QgsProjectStyleDatabaseProxyModel.Filter.FilterHideReadOnly + ) project_style = QgsStyle() - project_style.setName('project') + project_style.setName("project") model_with_project_style = QgsProjectStyleDatabaseModel(p) model_with_project_style.setShowDefaultStyle(True) model_with_project_style.setProjectStyle(project_style) @@ -167,227 +185,569 @@ def testStylePaths(self): self.assertFalse(p.styles()) self.assertEqual(p.combinedStyleModel().rowCount(), 0) self.assertEqual(model.rowCount(QModelIndex()), 0) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) self.assertEqual(model_with_default.rowCount(QModelIndex()), 1) - self.assertEqual(model_with_default.data(model_with_default.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'Default') - self.assertEqual(model_with_default.data(model_with_default.index(0, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), QgsStyle.defaultStyle()) + self.assertEqual( + model_with_default.data( + model_with_default.index(0, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "Default", + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + QgsStyle.defaultStyle(), + ) self.assertEqual(model_with_project_style.rowCount(QModelIndex()), 2) self.assertEqual( - model_with_project_style.data(model_with_project_style.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'project') - self.assertEqual(model_with_project_style.data(model_with_project_style.index(0, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), project_style) + model_with_project_style.data( + model_with_project_style.index(0, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "project", + ) + self.assertEqual( + model_with_project_style.data( + model_with_project_style.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + project_style, + ) + self.assertEqual( + model_with_project_style.data( + model_with_project_style.index(1, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "Default", + ) self.assertEqual( - model_with_project_style.data(model_with_project_style.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'Default') - self.assertEqual(model_with_project_style.data(model_with_project_style.index(1, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), QgsStyle.defaultStyle()) + model_with_project_style.data( + model_with_project_style.index(1, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + QgsStyle.defaultStyle(), + ) self.assertEqual(proxy_model.rowCount(QModelIndex()), 1) - self.assertEqual(proxy_model.data(proxy_model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'Default') self.assertEqual( - proxy_model.data(proxy_model.index(0, 0, QModelIndex()), QgsProjectStyleDatabaseModel.Role.StyleRole), - QgsStyle.defaultStyle()) - - p.addStyleDatabasePath(unitTestDataPath() + '/style1.db') + proxy_model.data( + proxy_model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole + ), + "Default", + ) + self.assertEqual( + proxy_model.data( + proxy_model.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + QgsStyle.defaultStyle(), + ) + + p.addStyleDatabasePath(unitTestDataPath() + "/style1.db") self.assertEqual(len(spy), 1) - self.assertEqual(p.styleDatabasePaths(), [unitTestDataPath() + '/style1.db']) + self.assertEqual(p.styleDatabasePaths(), [unitTestDataPath() + "/style1.db"]) self.assertEqual(p.combinedStyleModel().rowCount(), 1) - self.assertEqual(p.combinedStyleModel().data(p.combinedStyleModel().index(0, 0)), 'style1') + self.assertEqual( + p.combinedStyleModel().data(p.combinedStyleModel().index(0, 0)), "style1" + ) self.assertEqual(len(p.styles()), 1) - self.assertEqual(p.styles()[0].fileName(), unitTestDataPath() + '/style1.db') - self.assertEqual(p.styles()[0].name(), 'style1') + self.assertEqual(p.styles()[0].fileName(), unitTestDataPath() + "/style1.db") + self.assertEqual(p.styles()[0].name(), "style1") self.assertEqual(model.rowCount(QModelIndex()), 1) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'style1') - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsProjectStyleDatabaseModel.Role.StyleRole), - p.styles()[0]) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsProjectStyleDatabaseModel.Role.PathRole), - unitTestDataPath() + '/style1.db') + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "style1", + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + p.styles()[0], + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.PathRole, + ), + unitTestDataPath() + "/style1.db", + ) self.assertEqual(model_with_default.rowCount(QModelIndex()), 2) - self.assertEqual(model_with_default.data(model_with_default.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'Default') - self.assertEqual(model_with_default.data(model_with_default.index(0, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), QgsStyle.defaultStyle()) - self.assertEqual(model_with_default.data(model_with_default.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'style1') - self.assertEqual(model_with_default.data(model_with_default.index(1, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), p.styles()[0]) - self.assertEqual(model_with_default.data(model_with_default.index(1, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.PathRole), - unitTestDataPath() + '/style1.db') + self.assertEqual( + model_with_default.data( + model_with_default.index(0, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "Default", + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + QgsStyle.defaultStyle(), + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(1, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "style1", + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(1, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + p.styles()[0], + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(1, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.PathRole, + ), + unitTestDataPath() + "/style1.db", + ) self.assertEqual(model_with_project_style.rowCount(QModelIndex()), 3) self.assertEqual( - model_with_project_style.data(model_with_project_style.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'project') - self.assertEqual(model_with_project_style.data(model_with_project_style.index(0, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), project_style) + model_with_project_style.data( + model_with_project_style.index(0, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "project", + ) + self.assertEqual( + model_with_project_style.data( + model_with_project_style.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + project_style, + ) + self.assertEqual( + model_with_project_style.data( + model_with_project_style.index(1, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "Default", + ) + self.assertEqual( + model_with_project_style.data( + model_with_project_style.index(1, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + QgsStyle.defaultStyle(), + ) + self.assertEqual( + model_with_project_style.data( + model_with_project_style.index(2, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "style1", + ) self.assertEqual( - model_with_project_style.data(model_with_project_style.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'Default') - self.assertEqual(model_with_project_style.data(model_with_project_style.index(1, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), QgsStyle.defaultStyle()) + model_with_project_style.data( + model_with_project_style.index(2, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + p.styles()[0], + ) self.assertEqual( - model_with_project_style.data(model_with_project_style.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'style1') - self.assertEqual(model_with_project_style.data(model_with_project_style.index(2, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), p.styles()[0]) - self.assertEqual(model_with_project_style.data(model_with_project_style.index(2, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.PathRole), - unitTestDataPath() + '/style1.db') + model_with_project_style.data( + model_with_project_style.index(2, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.PathRole, + ), + unitTestDataPath() + "/style1.db", + ) self.assertEqual(proxy_model.rowCount(QModelIndex()), 2) - self.assertEqual(proxy_model.data(proxy_model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'Default') self.assertEqual( - proxy_model.data(proxy_model.index(0, 0, QModelIndex()), QgsProjectStyleDatabaseModel.Role.StyleRole), - QgsStyle.defaultStyle()) - self.assertEqual(proxy_model.data(proxy_model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'style1') + proxy_model.data( + proxy_model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole + ), + "Default", + ) self.assertEqual( - proxy_model.data(proxy_model.index(1, 0, QModelIndex()), QgsProjectStyleDatabaseModel.Role.StyleRole), - p.styles()[0]) - self.assertEqual(proxy_model.data(proxy_model.index(1, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.PathRole), unitTestDataPath() + '/style1.db') + proxy_model.data( + proxy_model.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + QgsStyle.defaultStyle(), + ) + self.assertEqual( + proxy_model.data( + proxy_model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole + ), + "style1", + ) + self.assertEqual( + proxy_model.data( + proxy_model.index(1, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + p.styles()[0], + ) + self.assertEqual( + proxy_model.data( + proxy_model.index(1, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.PathRole, + ), + unitTestDataPath() + "/style1.db", + ) # try re-adding path which is already present - p.addStyleDatabasePath(unitTestDataPath() + '/style1.db') + p.addStyleDatabasePath(unitTestDataPath() + "/style1.db") self.assertEqual(len(spy), 1) - self.assertEqual(p.styleDatabasePaths(), [unitTestDataPath() + '/style1.db']) + self.assertEqual(p.styleDatabasePaths(), [unitTestDataPath() + "/style1.db"]) self.assertEqual(p.combinedStyleModel().rowCount(), 1) - self.assertEqual(p.combinedStyleModel().data(p.combinedStyleModel().index(0, 0)), 'style1') + self.assertEqual( + p.combinedStyleModel().data(p.combinedStyleModel().index(0, 0)), "style1" + ) self.assertEqual(model.rowCount(QModelIndex()), 1) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'style1') - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsProjectStyleDatabaseModel.Role.StyleRole), - p.styles()[0]) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "style1", + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + p.styles()[0], + ) self.assertEqual(model_with_default.rowCount(QModelIndex()), 2) - self.assertEqual(model_with_default.data(model_with_default.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'Default') - self.assertEqual(model_with_default.data(model_with_default.index(0, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), QgsStyle.defaultStyle()) - self.assertEqual(model_with_default.data(model_with_default.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'style1') - self.assertEqual(model_with_default.data(model_with_default.index(1, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), p.styles()[0]) - - p.addStyleDatabasePath(unitTestDataPath() + '/style2.db') + self.assertEqual( + model_with_default.data( + model_with_default.index(0, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "Default", + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + QgsStyle.defaultStyle(), + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(1, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "style1", + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(1, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + p.styles()[0], + ) + + p.addStyleDatabasePath(unitTestDataPath() + "/style2.db") self.assertEqual(len(spy), 2) - self.assertEqual(p.styleDatabasePaths(), [unitTestDataPath() + '/style1.db', unitTestDataPath() + '/style2.db']) - self.assertEqual(p.styles()[0].fileName(), unitTestDataPath() + '/style1.db') - self.assertEqual(p.styles()[0].name(), 'style1') - self.assertEqual(p.styles()[1].fileName(), unitTestDataPath() + '/style2.db') - self.assertEqual(p.styles()[1].name(), 'style2') + self.assertEqual( + p.styleDatabasePaths(), + [unitTestDataPath() + "/style1.db", unitTestDataPath() + "/style2.db"], + ) + self.assertEqual(p.styles()[0].fileName(), unitTestDataPath() + "/style1.db") + self.assertEqual(p.styles()[0].name(), "style1") + self.assertEqual(p.styles()[1].fileName(), unitTestDataPath() + "/style2.db") + self.assertEqual(p.styles()[1].name(), "style2") self.assertEqual(p.combinedStyleModel().rowCount(), 2) - self.assertEqual(p.combinedStyleModel().data(p.combinedStyleModel().index(0, 0)), 'style1') - self.assertEqual(p.combinedStyleModel().data(p.combinedStyleModel().index(1, 0)), 'style2') + self.assertEqual( + p.combinedStyleModel().data(p.combinedStyleModel().index(0, 0)), "style1" + ) + self.assertEqual( + p.combinedStyleModel().data(p.combinedStyleModel().index(1, 0)), "style2" + ) self.assertEqual(model.rowCount(QModelIndex()), 2) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'style1') - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsProjectStyleDatabaseModel.Role.StyleRole), - p.styles()[0]) - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'style2') - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), QgsProjectStyleDatabaseModel.Role.StyleRole), - p.styles()[1]) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "style1", + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + p.styles()[0], + ) + self.assertEqual( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "style2", + ) + self.assertEqual( + model.data( + model.index(1, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + p.styles()[1], + ) self.assertEqual(model_with_default.rowCount(QModelIndex()), 3) - self.assertEqual(model_with_default.data(model_with_default.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'Default') - self.assertEqual(model_with_default.data(model_with_default.index(0, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), QgsStyle.defaultStyle()) - self.assertEqual(model_with_default.data(model_with_default.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'style1') - self.assertEqual(model_with_default.data(model_with_default.index(1, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), p.styles()[0]) - self.assertEqual(model_with_default.data(model_with_default.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'style2') - self.assertEqual(model_with_default.data(model_with_default.index(2, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), p.styles()[1]) + self.assertEqual( + model_with_default.data( + model_with_default.index(0, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "Default", + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + QgsStyle.defaultStyle(), + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(1, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "style1", + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(1, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + p.styles()[0], + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(2, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "style2", + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(2, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + p.styles()[1], + ) self.assertEqual(model_with_project_style.rowCount(QModelIndex()), 4) self.assertEqual( - model_with_project_style.data(model_with_project_style.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'project') - self.assertEqual(model_with_project_style.data(model_with_project_style.index(0, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), project_style) + model_with_project_style.data( + model_with_project_style.index(0, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "project", + ) + self.assertEqual( + model_with_project_style.data( + model_with_project_style.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + project_style, + ) + self.assertEqual( + model_with_project_style.data( + model_with_project_style.index(1, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "Default", + ) + self.assertEqual( + model_with_project_style.data( + model_with_project_style.index(1, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + QgsStyle.defaultStyle(), + ) self.assertEqual( - model_with_project_style.data(model_with_project_style.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'Default') - self.assertEqual(model_with_project_style.data(model_with_project_style.index(1, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), QgsStyle.defaultStyle()) + model_with_project_style.data( + model_with_project_style.index(2, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "style1", + ) self.assertEqual( - model_with_project_style.data(model_with_project_style.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'style1') - self.assertEqual(model_with_project_style.data(model_with_project_style.index(2, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), p.styles()[0]) + model_with_project_style.data( + model_with_project_style.index(2, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + p.styles()[0], + ) self.assertEqual( - model_with_project_style.data(model_with_project_style.index(3, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'style2') - self.assertEqual(model_with_project_style.data(model_with_project_style.index(3, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), p.styles()[1]) + model_with_project_style.data( + model_with_project_style.index(3, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "style2", + ) + self.assertEqual( + model_with_project_style.data( + model_with_project_style.index(3, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + p.styles()[1], + ) - self.assertEqual(p.styleAtPath(unitTestDataPath() + '/style1.db'), p.styles()[0]) - self.assertEqual(p.styleAtPath(unitTestDataPath() + '/style2.db'), p.styles()[1]) - self.assertFalse(p.styleAtPath('.xxx')) + self.assertEqual( + p.styleAtPath(unitTestDataPath() + "/style1.db"), p.styles()[0] + ) + self.assertEqual( + p.styleAtPath(unitTestDataPath() + "/style2.db"), p.styles()[1] + ) + self.assertFalse(p.styleAtPath(".xxx")) - p.setStyleDatabasePaths([unitTestDataPath() + '/style3.db']) + p.setStyleDatabasePaths([unitTestDataPath() + "/style3.db"]) self.assertEqual(len(spy), 3) - self.assertEqual(p.styleDatabasePaths(), [unitTestDataPath() + '/style3.db']) + self.assertEqual(p.styleDatabasePaths(), [unitTestDataPath() + "/style3.db"]) self.assertEqual(p.combinedStyleModel().rowCount(), 1) - self.assertEqual(p.combinedStyleModel().data(p.combinedStyleModel().index(0, 0)), 'style3') + self.assertEqual( + p.combinedStyleModel().data(p.combinedStyleModel().index(0, 0)), "style3" + ) self.assertEqual(model.rowCount(QModelIndex()), 1) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'style3') - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsProjectStyleDatabaseModel.Role.StyleRole), - p.styles()[0]) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "style3", + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + p.styles()[0], + ) self.assertEqual(model_with_default.rowCount(QModelIndex()), 2) - self.assertEqual(model_with_default.data(model_with_default.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'Default') - self.assertEqual(model_with_default.data(model_with_default.index(0, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), QgsStyle.defaultStyle()) - self.assertEqual(model_with_default.data(model_with_default.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'style3') - self.assertEqual(model_with_default.data(model_with_default.index(1, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), p.styles()[0]) + self.assertEqual( + model_with_default.data( + model_with_default.index(0, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "Default", + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + QgsStyle.defaultStyle(), + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(1, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "style3", + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(1, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + p.styles()[0], + ) self.assertEqual(model_with_project_style.rowCount(QModelIndex()), 3) self.assertEqual( - model_with_project_style.data(model_with_project_style.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'project') - self.assertEqual(model_with_project_style.data(model_with_project_style.index(0, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), project_style) + model_with_project_style.data( + model_with_project_style.index(0, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "project", + ) self.assertEqual( - model_with_project_style.data(model_with_project_style.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'Default') - self.assertEqual(model_with_project_style.data(model_with_project_style.index(1, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), QgsStyle.defaultStyle()) + model_with_project_style.data( + model_with_project_style.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + project_style, + ) self.assertEqual( - model_with_project_style.data(model_with_project_style.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'style3') - self.assertEqual(model_with_project_style.data(model_with_project_style.index(2, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), p.styles()[0]) + model_with_project_style.data( + model_with_project_style.index(1, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "Default", + ) + self.assertEqual( + model_with_project_style.data( + model_with_project_style.index(1, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + QgsStyle.defaultStyle(), + ) + self.assertEqual( + model_with_project_style.data( + model_with_project_style.index(2, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "style3", + ) + self.assertEqual( + model_with_project_style.data( + model_with_project_style.index(2, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + p.styles()[0], + ) - self.assertEqual(p.styles()[0].fileName(), unitTestDataPath() + '/style3.db') - self.assertEqual(p.styles()[0].name(), 'style3') + self.assertEqual(p.styles()[0].fileName(), unitTestDataPath() + "/style3.db") + self.assertEqual(p.styles()[0].name(), "style3") - p.setStyleDatabasePaths([unitTestDataPath() + '/style3.db']) + p.setStyleDatabasePaths([unitTestDataPath() + "/style3.db"]) self.assertEqual(len(spy), 3) self.assertEqual(p.combinedStyleModel().rowCount(), 1) - self.assertEqual(p.combinedStyleModel().data(p.combinedStyleModel().index(0, 0)), 'style3') + self.assertEqual( + p.combinedStyleModel().data(p.combinedStyleModel().index(0, 0)), "style3" + ) self.assertEqual(model.rowCount(QModelIndex()), 1) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'style3') - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsProjectStyleDatabaseModel.Role.StyleRole), - p.styles()[0]) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "style3", + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + p.styles()[0], + ) self.assertEqual(model_with_default.rowCount(QModelIndex()), 2) - self.assertEqual(model_with_default.data(model_with_default.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'Default') - self.assertEqual(model_with_default.data(model_with_default.index(0, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), QgsStyle.defaultStyle()) - self.assertEqual(model_with_default.data(model_with_default.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'style3') - self.assertEqual(model_with_default.data(model_with_default.index(1, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), p.styles()[0]) + self.assertEqual( + model_with_default.data( + model_with_default.index(0, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "Default", + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + QgsStyle.defaultStyle(), + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(1, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "style3", + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(1, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + p.styles()[0], + ) p.setStyleDatabasePaths([]) self.assertEqual(len(spy), 4) @@ -397,39 +757,97 @@ def testStylePaths(self): self.assertEqual(model.rowCount(QModelIndex()), 0) self.assertEqual(model_with_default.rowCount(QModelIndex()), 1) - self.assertEqual(model_with_default.data(model_with_default.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'Default') - self.assertEqual(model_with_default.data(model_with_default.index(0, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), QgsStyle.defaultStyle()) + self.assertEqual( + model_with_default.data( + model_with_default.index(0, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "Default", + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + QgsStyle.defaultStyle(), + ) # test using a .xml path - p.addStyleDatabasePath(unitTestDataPath() + '/categorized.xml') - self.assertEqual(p.styles()[0].fileName(), unitTestDataPath() + '/categorized.xml') + p.addStyleDatabasePath(unitTestDataPath() + "/categorized.xml") + self.assertEqual( + p.styles()[0].fileName(), unitTestDataPath() + "/categorized.xml" + ) self.assertEqual(p.combinedStyleModel().rowCount(), 4) - self.assertEqual(p.combinedStyleModel().data(p.combinedStyleModel().index(0, 0)), 'categorized') - self.assertEqual(p.combinedStyleModel().data(p.combinedStyleModel().index(1, 0)), ' ----c/- ') - self.assertEqual(p.combinedStyleModel().data(p.combinedStyleModel().index(2, 0)), 'B ') - self.assertEqual(p.combinedStyleModel().data(p.combinedStyleModel().index(3, 0)), 'a') + self.assertEqual( + p.combinedStyleModel().data(p.combinedStyleModel().index(0, 0)), + "categorized", + ) + self.assertEqual( + p.combinedStyleModel().data(p.combinedStyleModel().index(1, 0)), " ----c/- " + ) + self.assertEqual( + p.combinedStyleModel().data(p.combinedStyleModel().index(2, 0)), "B " + ) + self.assertEqual( + p.combinedStyleModel().data(p.combinedStyleModel().index(3, 0)), "a" + ) self.assertEqual(model.rowCount(QModelIndex()), 1) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'categorized') - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsProjectStyleDatabaseModel.Role.StyleRole), - p.styles()[0]) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "categorized", + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + p.styles()[0], + ) self.assertEqual(model_with_default.rowCount(QModelIndex()), 2) - self.assertEqual(model_with_default.data(model_with_default.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'Default') - self.assertEqual(model_with_default.data(model_with_default.index(0, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), QgsStyle.defaultStyle()) - self.assertEqual(model_with_default.data(model_with_default.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'categorized') - self.assertEqual(model_with_default.data(model_with_default.index(1, 0, QModelIndex()), - QgsProjectStyleDatabaseModel.Role.StyleRole), p.styles()[0]) + self.assertEqual( + model_with_default.data( + model_with_default.index(0, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "Default", + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + QgsStyle.defaultStyle(), + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(1, 0, QModelIndex()), + Qt.ItemDataRole.DisplayRole, + ), + "categorized", + ) + self.assertEqual( + model_with_default.data( + model_with_default.index(1, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + p.styles()[0], + ) # read only style should not be included self.assertEqual(proxy_model.rowCount(QModelIndex()), 1) - self.assertEqual(proxy_model.data(proxy_model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'Default') self.assertEqual( - proxy_model.data(proxy_model.index(0, 0, QModelIndex()), QgsProjectStyleDatabaseModel.Role.StyleRole), - QgsStyle.defaultStyle()) + proxy_model.data( + proxy_model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole + ), + "Default", + ) + self.assertEqual( + proxy_model.data( + proxy_model.index(0, 0, QModelIndex()), + QgsProjectStyleDatabaseModel.Role.StyleRole, + ), + QgsStyle.defaultStyle(), + ) def testReadWrite(self): project = QgsProject() @@ -448,7 +866,9 @@ def testReadWrite(self): p.setRandomizeDefaultSymbolColor(False) p.setDefaultSymbolOpacity(0.25) - p.setStyleDatabasePaths([unitTestDataPath() + '/style1.db', unitTestDataPath() + '/style2.db']) + p.setStyleDatabasePaths( + [unitTestDataPath() + "/style1.db", unitTestDataPath() + "/style2.db"] + ) doc = QDomDocument("testdoc") elem = p.writeXml(doc, QgsReadWriteContext()) @@ -464,8 +884,10 @@ def testReadWrite(self): self.assertFalse(p2.randomizeDefaultSymbolColor()) self.assertEqual(p2.defaultSymbolOpacity(), 0.25) - self.assertEqual(p2.styleDatabasePaths(), - [unitTestDataPath() + '/style1.db', unitTestDataPath() + '/style2.db']) + self.assertEqual( + p2.styleDatabasePaths(), + [unitTestDataPath() + "/style1.db", unitTestDataPath() + "/style2.db"], + ) def testColorSettings(self): """ @@ -485,7 +907,7 @@ def testColorSettings(self): project.setDirty(False) self.assertEqual(settings.colorModel(), Qgis.ColorModel.Cmyk) - with open(os.path.join(TEST_DATA_DIR, "sRGB2014.icc"), mode='rb') as f: + with open(os.path.join(TEST_DATA_DIR, "sRGB2014.icc"), mode="rb") as f: colorSpace = QColorSpace.fromIccProfile(f.read()) self.assertTrue(colorSpace.isValid()) @@ -497,7 +919,9 @@ def testColorSettings(self): self.assertEqual(len(project.attachedFiles()), 2) # save and restore - projectFile = QTemporaryFile(QDir.temp().absoluteFilePath("testCmykSettings.qgz")) + projectFile = QTemporaryFile( + QDir.temp().absoluteFilePath("testCmykSettings.qgz") + ) projectFile.open() self.assertTrue(project.write(projectFile.fileName())) @@ -515,7 +939,9 @@ def testColorSettings(self): self.assertEqual(len(project.attachedFiles()), 1) # save and restore cleared - projectFile = QTemporaryFile(QDir.temp().absoluteFilePath("testCmykSettingsCleared.qgz")) + projectFile = QTemporaryFile( + QDir.temp().absoluteFilePath("testCmykSettingsCleared.qgz") + ) projectFile.open() self.assertTrue(project.write(projectFile.fileName())) @@ -526,5 +952,5 @@ def testColorSettings(self): self.assertEqual(len(project.attachedFiles()), 1) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprojecttimesettings.py b/tests/src/python/test_qgsprojecttimesettings.py index f63d4d788c29..d4f5873ef669 100644 --- a/tests/src/python/test_qgsprojecttimesettings.py +++ b/tests/src/python/test_qgsprojecttimesettings.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Samweli Mwakisambwe' -__date__ = '6/3/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Samweli Mwakisambwe" +__date__ = "6/3/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, QTime from qgis.PyQt.QtTest import QSignalSpy @@ -36,12 +37,12 @@ def testTemporalRange(self): r = QgsDateTimeRange( QDateTime(QDate(2020, 1, 1), QTime(8, 0, 0)), - QDateTime(QDate(2020, 12, 1), QTime(8, 0, 0)) + QDateTime(QDate(2020, 12, 1), QTime(8, 0, 0)), ) rc = QgsDateTimeRange( QDateTime(QDate(2020, 1, 1), QTime(8, 0, 0)), - QDateTime(QDate(2020, 12, 1), QTime(8, 0, 0)) + QDateTime(QDate(2020, 12, 1), QTime(8, 0, 0)), ) p.setTemporalRange(r) @@ -80,7 +81,7 @@ def testReadWrite(self): r = QgsDateTimeRange( QDateTime(QDate(2020, 1, 1), QTime(8, 0, 0)), - QDateTime(QDate(2020, 12, 1), QTime(8, 0, 0)) + QDateTime(QDate(2020, 12, 1), QTime(8, 0, 0)), ) p.setTemporalRange(r) p.setTimeStep(4.8) @@ -100,5 +101,5 @@ def testReadWrite(self): self.assertTrue(p.isTemporalRangeCumulative()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprojectutils.py b/tests/src/python/test_qgsprojectutils.py index 8dd823233ace..cb9c4b404df7 100644 --- a/tests/src/python/test_qgsprojectutils.py +++ b/tests/src/python/test_qgsprojectutils.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2021-07' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2021-07" +__copyright__ = "Copyright 2021, The QGIS Project" from qgis.core import ( @@ -34,113 +35,159 @@ def test_layersMatchingPath(self): """ Test QgsProjectUtils.layersMatchingPath() """ - self.assertFalse(QgsProjectUtils.layersMatchingPath(None, '')) - self.assertFalse(QgsProjectUtils.layersMatchingPath(None, 'aaaaa')) + self.assertFalse(QgsProjectUtils.layersMatchingPath(None, "")) + self.assertFalse(QgsProjectUtils.layersMatchingPath(None, "aaaaa")) # add some layers to a project # shapefile - layer1 = QgsVectorLayer(unitTestDataPath() + '/points.shp', 'l1') + layer1 = QgsVectorLayer(unitTestDataPath() + "/points.shp", "l1") self.assertTrue(layer1.isValid()) p = QgsProject() p.addMapLayer(layer1) - gpkg1 = QgsVectorLayer(unitTestDataPath() + '/mixed_layers.gpkg|layername=lines', 'l1') + gpkg1 = QgsVectorLayer( + unitTestDataPath() + "/mixed_layers.gpkg|layername=lines", "l1" + ) self.assertTrue(gpkg1.isValid()) p.addMapLayer(gpkg1) - gpkg2 = QgsVectorLayer(unitTestDataPath() + '/mixed_layers.gpkg|layername=points', 'l1') + gpkg2 = QgsVectorLayer( + unitTestDataPath() + "/mixed_layers.gpkg|layername=points", "l1" + ) self.assertTrue(gpkg2.isValid()) p.addMapLayer(gpkg2) # raster layer from gpkg - rl = QgsRasterLayer(f'GPKG:{unitTestDataPath()}/mixed_layers.gpkg:band1') + rl = QgsRasterLayer(f"GPKG:{unitTestDataPath()}/mixed_layers.gpkg:band1") self.assertTrue(rl.isValid()) p.addMapLayer(rl) - self.assertFalse(QgsProjectUtils.layersMatchingPath(p, '')) - self.assertFalse(QgsProjectUtils.layersMatchingPath(p, 'aaa')) - self.assertCountEqual(QgsProjectUtils.layersMatchingPath(p, unitTestDataPath() + '/points.shp'), [layer1]) - self.assertCountEqual(QgsProjectUtils.layersMatchingPath(p, unitTestDataPath() + '/mixed_layers.gpkg'), [gpkg1, gpkg2, rl]) + self.assertFalse(QgsProjectUtils.layersMatchingPath(p, "")) + self.assertFalse(QgsProjectUtils.layersMatchingPath(p, "aaa")) + self.assertCountEqual( + QgsProjectUtils.layersMatchingPath(p, unitTestDataPath() + "/points.shp"), + [layer1], + ) + self.assertCountEqual( + QgsProjectUtils.layersMatchingPath( + p, unitTestDataPath() + "/mixed_layers.gpkg" + ), + [gpkg1, gpkg2, rl], + ) def test_updateLayerPath(self): """ Test QgsProjectUtils.updateLayerPath """ - self.assertFalse(QgsProjectUtils.updateLayerPath(None, '', '')) - self.assertFalse(QgsProjectUtils.updateLayerPath(None, 'aaaaa', 'bbbb')) + self.assertFalse(QgsProjectUtils.updateLayerPath(None, "", "")) + self.assertFalse(QgsProjectUtils.updateLayerPath(None, "aaaaa", "bbbb")) p = QgsProject() - self.assertFalse(QgsProjectUtils.updateLayerPath(p, 'aaaaa', 'bbbb')) + self.assertFalse(QgsProjectUtils.updateLayerPath(p, "aaaaa", "bbbb")) # add some layers to a project # shapefile - layer1 = QgsVectorLayer(unitTestDataPath() + '/points.shp', 'l1') + layer1 = QgsVectorLayer(unitTestDataPath() + "/points.shp", "l1") self.assertTrue(layer1.isValid()) p.addMapLayer(layer1) - gpkg1 = QgsVectorLayer(unitTestDataPath() + '/mixed_layers.gpkg|layername=lines', 'l1') + gpkg1 = QgsVectorLayer( + unitTestDataPath() + "/mixed_layers.gpkg|layername=lines", "l1" + ) self.assertTrue(gpkg1.isValid()) p.addMapLayer(gpkg1) - gpkg2 = QgsVectorLayer(unitTestDataPath() + '/mixed_layers.gpkg|layername=points', 'l1') + gpkg2 = QgsVectorLayer( + unitTestDataPath() + "/mixed_layers.gpkg|layername=points", "l1" + ) self.assertTrue(gpkg2.isValid()) p.addMapLayer(gpkg2) # raster layer from gpkg - rl = QgsRasterLayer(f'GPKG:{unitTestDataPath()}/mixed_layers.gpkg:band1') + rl = QgsRasterLayer(f"GPKG:{unitTestDataPath()}/mixed_layers.gpkg:band1") self.assertTrue(rl.isValid()) p.addMapLayer(rl) - memory_layer = QgsVectorLayer("Point?field=x:string", 'my layer', "memory") + memory_layer = QgsVectorLayer("Point?field=x:string", "my layer", "memory") old_memory_source = memory_layer.source() p.addMapLayer(memory_layer) - self.assertFalse(QgsProjectUtils.updateLayerPath(p, '', '')) - self.assertFalse(QgsProjectUtils.updateLayerPath(p, 'aaa', 'bbb')) + self.assertFalse(QgsProjectUtils.updateLayerPath(p, "", "")) + self.assertFalse(QgsProjectUtils.updateLayerPath(p, "aaa", "bbb")) # replace shapefile path - self.assertTrue(QgsProjectUtils.updateLayerPath(p, unitTestDataPath() + '/points.shp', unitTestDataPath() + '/points22.shp')) - self.assertEqual(layer1.source(), unitTestDataPath() + '/points22.shp') - self.assertEqual(gpkg1.source(), unitTestDataPath() + '/mixed_layers.gpkg|layername=lines') - self.assertEqual(gpkg2.source(), unitTestDataPath() + '/mixed_layers.gpkg|layername=points') - self.assertEqual(rl.source(), f'GPKG:{unitTestDataPath()}/mixed_layers.gpkg:band1') + self.assertTrue( + QgsProjectUtils.updateLayerPath( + p, + unitTestDataPath() + "/points.shp", + unitTestDataPath() + "/points22.shp", + ) + ) + self.assertEqual(layer1.source(), unitTestDataPath() + "/points22.shp") + self.assertEqual( + gpkg1.source(), unitTestDataPath() + "/mixed_layers.gpkg|layername=lines" + ) + self.assertEqual( + gpkg2.source(), unitTestDataPath() + "/mixed_layers.gpkg|layername=points" + ) + self.assertEqual( + rl.source(), f"GPKG:{unitTestDataPath()}/mixed_layers.gpkg:band1" + ) self.assertEqual(memory_layer.source(), old_memory_source) # should return false if we call again, no more matching paths - self.assertFalse(QgsProjectUtils.updateLayerPath(p, unitTestDataPath() + '/points.shp', - unitTestDataPath() + '/points22.shp')) + self.assertFalse( + QgsProjectUtils.updateLayerPath( + p, + unitTestDataPath() + "/points.shp", + unitTestDataPath() + "/points22.shp", + ) + ) # replace geopackage path - self.assertTrue(QgsProjectUtils.updateLayerPath(p, unitTestDataPath() + '/mixed_layers.gpkg', unitTestDataPath() + '/mixed_layers22.gpkg')) - self.assertEqual(layer1.source(), unitTestDataPath() + '/points22.shp') - self.assertEqual(gpkg1.source(), unitTestDataPath() + '/mixed_layers22.gpkg|layername=lines') - self.assertEqual(gpkg2.source(), unitTestDataPath() + '/mixed_layers22.gpkg|layername=points') - self.assertEqual(rl.source(), f'GPKG:{unitTestDataPath()}/mixed_layers22.gpkg:band1') + self.assertTrue( + QgsProjectUtils.updateLayerPath( + p, + unitTestDataPath() + "/mixed_layers.gpkg", + unitTestDataPath() + "/mixed_layers22.gpkg", + ) + ) + self.assertEqual(layer1.source(), unitTestDataPath() + "/points22.shp") + self.assertEqual( + gpkg1.source(), unitTestDataPath() + "/mixed_layers22.gpkg|layername=lines" + ) + self.assertEqual( + gpkg2.source(), unitTestDataPath() + "/mixed_layers22.gpkg|layername=points" + ) + self.assertEqual( + rl.source(), f"GPKG:{unitTestDataPath()}/mixed_layers22.gpkg:band1" + ) self.assertEqual(memory_layer.source(), old_memory_source) # should return false if we call again, no more matching paths - self.assertFalse(QgsProjectUtils.updateLayerPath(p, unitTestDataPath() + '/mixed_layers.gpkg', - unitTestDataPath() + '/mixed_layers22.gpkg')) + self.assertFalse( + QgsProjectUtils.updateLayerPath( + p, + unitTestDataPath() + "/mixed_layers.gpkg", + unitTestDataPath() + "/mixed_layers22.gpkg", + ) + ) def test_layer_is_contained_in_group_layer(self): p = QgsProject() - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") p.addMapLayer(layer) - layer2 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") p.addMapLayer(layer2) - layer3 = QgsVectorLayer("Point?field=fldtxt:string", - "layer3", "memory") + layer3 = QgsVectorLayer("Point?field=fldtxt:string", "layer3", "memory") p.addMapLayer(layer3) - layer4 = QgsVectorLayer("Point?field=fldtxt:string", - "layer4", "memory") + layer4 = QgsVectorLayer("Point?field=fldtxt:string", "layer4", "memory") p.addMapLayer(layer4) options = QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) - group_layer = QgsGroupLayer('group', options) + group_layer = QgsGroupLayer("group", options) group_layer.setChildLayers([layer, layer4]) p.addMapLayer(group_layer) options = QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) - group_layer2 = QgsGroupLayer('group2', options) + group_layer2 = QgsGroupLayer("group2", options) group_layer2.setChildLayers([group_layer, layer3]) p.addMapLayer(group_layer2) @@ -152,25 +199,22 @@ def test_layer_is_contained_in_group_layer(self): # catch alternative situation -- group layer nodes which are unchecked layer_tree_root = p.layerTreeRoot() - tree_group1 = layer_tree_root.addGroup('group 1') + tree_group1 = layer_tree_root.addGroup("group 1") - tree_group2 = layer_tree_root.addGroup('group 2') + tree_group2 = layer_tree_root.addGroup("group 2") - layer5 = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer5 = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") p.addMapLayer(layer5) node1 = tree_group1.addLayer(layer5) node1.setItemVisibilityChecked(False) - layer6 = QgsVectorLayer("Point?field=fldtxt:string", - "layer2", "memory") + layer6 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") p.addMapLayer(layer6) - tree_group1a = tree_group1.addGroup('group 1a') + tree_group1a = tree_group1.addGroup("group 1a") node2 = tree_group1a.addLayer(layer6) node2.setItemVisibilityChecked(False) - layer7 = QgsVectorLayer("Point?field=fldtxt:string", - "layer3", "memory") + layer7 = QgsVectorLayer("Point?field=fldtxt:string", "layer3", "memory") p.addMapLayer(layer7) node3 = tree_group2.addLayer(layer7) node3.setItemVisibilityChecked(False) @@ -179,12 +223,14 @@ def test_layer_is_contained_in_group_layer(self): self.assertFalse(QgsProjectUtils.layerIsContainedInGroupLayer(p, layer6)) self.assertFalse(QgsProjectUtils.layerIsContainedInGroupLayer(p, layer7)) - group_layer_from_tree = tree_group1.convertToGroupLayer(QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext())) + group_layer_from_tree = tree_group1.convertToGroupLayer( + QgsGroupLayer.LayerOptions(QgsCoordinateTransformContext()) + ) self.assertTrue(QgsProjectUtils.layerIsContainedInGroupLayer(p, layer5)) self.assertTrue(QgsProjectUtils.layerIsContainedInGroupLayer(p, layer6)) self.assertFalse(QgsProjectUtils.layerIsContainedInGroupLayer(p, layer7)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprojectviewsettings.py b/tests/src/python/test_qgsprojectviewsettings.py index 53b29cb43622..11ef712dc053 100644 --- a/tests/src/python/test_qgsprojectviewsettings.py +++ b/tests/src/python/test_qgsprojectviewsettings.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '30/10/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "30/10/2019" +__copyright__ = "Copyright 2019, The QGIS Project" import os @@ -82,22 +83,35 @@ def testDefaultViewExtent(self): p = QgsProjectViewSettings() self.assertTrue(p.defaultViewExtent().isNull()) - p.setDefaultViewExtent(QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857"))) - self.assertEqual(p.defaultViewExtent(), QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857"))) + p.setDefaultViewExtent( + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857") + ) + ) + self.assertEqual( + p.defaultViewExtent(), + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857") + ), + ) p.setDefaultViewExtent(QgsReferencedRectangle()) self.assertTrue(p.defaultViewExtent().isNull()) - p.setDefaultViewExtent(QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857"))) + p.setDefaultViewExtent( + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857") + ) + ) p.reset() self.assertTrue(p.defaultViewExtent().isNull()) def testDefaultViewExtentWithCanvas(self): p = QgsProject() - p.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + p.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) canvas = QgsMapCanvas() - canvas.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) + canvas.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) canvas.setFrameStyle(0) canvas.resize(600, 400) self.assertEqual(canvas.width(), 600) @@ -116,9 +130,14 @@ def testDefaultViewExtentWithCanvas(self): self.assertAlmostEqual(canvas.extent().yMinimum(), 29.16666, 3) self.assertAlmostEqual(canvas.extent().xMaximum(), 20, 3) self.assertAlmostEqual(canvas.extent().yMaximum(), 35.833333333, 3) - self.assertEqual(canvas.mapSettings().destinationCrs().authid(), 'EPSG:4326') + self.assertEqual(canvas.mapSettings().destinationCrs().authid(), "EPSG:4326") - p.viewSettings().setDefaultViewExtent(QgsReferencedRectangle(QgsRectangle(1000, 2000, 1500, 2500), QgsCoordinateReferenceSystem('EPSG:3857'))) + p.viewSettings().setDefaultViewExtent( + QgsReferencedRectangle( + QgsRectangle(1000, 2000, 1500, 2500), + QgsCoordinateReferenceSystem("EPSG:3857"), + ) + ) self.assertTrue(p.write(tmpFile)) QgsProject.instance().read(tmpFile) @@ -127,7 +146,7 @@ def testDefaultViewExtentWithCanvas(self): self.assertAlmostEqual(canvas.extent().yMinimum(), 0.017966, 3) self.assertAlmostEqual(canvas.extent().xMaximum(), 0.01459762, 3) self.assertAlmostEqual(canvas.extent().yMaximum(), 0.02245788, 3) - self.assertEqual(canvas.mapSettings().destinationCrs().authid(), 'EPSG:4326') + self.assertEqual(canvas.mapSettings().destinationCrs().authid(), "EPSG:4326") def testDefaultRotation(self): p = QgsProjectViewSettings() @@ -159,13 +178,26 @@ def testPresetFullExtent(self): p = QgsProjectViewSettings() self.assertTrue(p.presetFullExtent().isNull()) - p.setPresetFullExtent(QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857"))) - self.assertEqual(p.presetFullExtent(), QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857"))) + p.setPresetFullExtent( + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857") + ) + ) + self.assertEqual( + p.presetFullExtent(), + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857") + ), + ) p.setPresetFullExtent(QgsReferencedRectangle()) self.assertTrue(p.presetFullExtent().isNull()) - p.setPresetFullExtent(QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857"))) + p.setPresetFullExtent( + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857") + ) + ) p.reset() self.assertTrue(p.presetFullExtent().isNull()) @@ -173,13 +205,25 @@ def testPresetFullExtentChangedSignal(self): p = QgsProjectViewSettings() spy = QSignalSpy(p.presetFullExtentChanged) - p.setPresetFullExtent(QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857"))) + p.setPresetFullExtent( + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857") + ) + ) self.assertEqual(len(spy), 1) - p.setPresetFullExtent(QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857"))) + p.setPresetFullExtent( + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857") + ) + ) self.assertEqual(len(spy), 1) - p.setPresetFullExtent(QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:4326"))) + p.setPresetFullExtent( + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) self.assertEqual(len(spy), 2) p.reset() @@ -190,26 +234,30 @@ def testPresetFullExtentChangedSignal(self): def testFullExtent(self): p = QgsProject() - p.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + p.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) self.assertTrue(p.viewSettings().fullExtent().isNull()) - p.viewSettings().setPresetFullExtent(QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:4326"))) + p.viewSettings().setPresetFullExtent( + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:4326") + ) + ) self.assertAlmostEqual(p.viewSettings().fullExtent().xMinimum(), 111319, -1) self.assertAlmostEqual(p.viewSettings().fullExtent().xMaximum(), 333958, -1) self.assertAlmostEqual(p.viewSettings().fullExtent().yMinimum(), 222684, -1) self.assertAlmostEqual(p.viewSettings().fullExtent().yMaximum(), 445640, -1) - self.assertEqual(p.viewSettings().fullExtent().crs().authid(), 'EPSG:3857') + self.assertEqual(p.viewSettings().fullExtent().crs().authid(), "EPSG:3857") # add layers - shapefile = os.path.join(TEST_DATA_DIR, 'polys.shp') - layer = QgsVectorLayer(shapefile, 'Polys', 'ogr') + shapefile = os.path.join(TEST_DATA_DIR, "polys.shp") + layer = QgsVectorLayer(shapefile, "Polys", "ogr") p.addMapLayer(layer) # no change, because preset extent is set self.assertAlmostEqual(p.viewSettings().fullExtent().xMinimum(), 111319, -1) self.assertAlmostEqual(p.viewSettings().fullExtent().xMaximum(), 333958, -1) self.assertAlmostEqual(p.viewSettings().fullExtent().yMinimum(), 222684, -1) self.assertAlmostEqual(p.viewSettings().fullExtent().yMaximum(), 445640, -1) - self.assertEqual(p.viewSettings().fullExtent().crs().authid(), 'EPSG:3857') + self.assertEqual(p.viewSettings().fullExtent().crs().authid(), "EPSG:3857") # remove preset extent p.viewSettings().setPresetFullExtent(QgsReferencedRectangle()) # extent should come from layers @@ -217,21 +265,24 @@ def testFullExtent(self): self.assertAlmostEqual(p.viewSettings().fullExtent().xMaximum(), -9327461, -2) self.assertAlmostEqual(p.viewSettings().fullExtent().yMinimum(), 2815417, -2) self.assertAlmostEqual(p.viewSettings().fullExtent().yMaximum(), 5897492, -2) - self.assertEqual(p.viewSettings().fullExtent().crs().authid(), 'EPSG:3857') + self.assertEqual(p.viewSettings().fullExtent().crs().authid(), "EPSG:3857") # add another layer - shapefile = os.path.join(TEST_DATA_DIR, 'lines.shp') - layer = QgsVectorLayer(shapefile, 'Lines', 'ogr') + shapefile = os.path.join(TEST_DATA_DIR, "lines.shp") + layer = QgsVectorLayer(shapefile, "Lines", "ogr") p.addMapLayer(layer) self.assertAlmostEqual(p.viewSettings().fullExtent().xMinimum(), -13238432, -2) self.assertAlmostEqual(p.viewSettings().fullExtent().xMaximum(), -9164115, -2) self.assertAlmostEqual(p.viewSettings().fullExtent().yMinimum(), 2657217, -2) self.assertAlmostEqual(p.viewSettings().fullExtent().yMaximum(), 5897492, -2) - self.assertEqual(p.viewSettings().fullExtent().crs().authid(), 'EPSG:3857') + self.assertEqual(p.viewSettings().fullExtent().crs().authid(), "EPSG:3857") # add a layer with a different crs - layer = QgsVectorLayer("Point?crs=EPSG:3857&field=fldtxt:string&field=fldint:integer", - "x", "memory") + layer = QgsVectorLayer( + "Point?crs=EPSG:3857&field=fldtxt:string&field=fldint:integer", + "x", + "memory", + ) p.addMapLayer(layer) f = QgsFeature() f.setAttributes(["test", 123]) @@ -244,7 +295,7 @@ def testFullExtent(self): self.assertAlmostEqual(p.viewSettings().fullExtent().xMaximum(), -8164115, -2) self.assertAlmostEqual(p.viewSettings().fullExtent().yMinimum(), 2657217, -2) self.assertAlmostEqual(p.viewSettings().fullExtent().yMaximum(), 5997492, -2) - self.assertEqual(p.viewSettings().fullExtent().crs().authid(), 'EPSG:3857') + self.assertEqual(p.viewSettings().fullExtent().crs().authid(), "EPSG:3857") def testFullExtentWithBasemap(self): """ @@ -252,12 +303,16 @@ def testFullExtentWithBasemap(self): a project, UNLESS only basemap layers are present """ p = QgsProject() - p.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + p.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) self.assertTrue(p.viewSettings().fullExtent().isNull()) # add only a basemap layer - xyz_layer = QgsRasterLayer("type=xyz&url=file://tile.openstreetmap.org/%7Bz%7D/%7Bx%7D/%7By%7D.png&zmax=19&zmin=0", '', "wms") + xyz_layer = QgsRasterLayer( + "type=xyz&url=file://tile.openstreetmap.org/%7Bz%7D/%7Bx%7D/%7By%7D.png&zmax=19&zmin=0", + "", + "wms", + ) self.assertEqual(xyz_layer.properties(), Qgis.MapLayerProperty.IsBasemapLayer) p.addMapLayer(xyz_layer) @@ -268,15 +323,15 @@ def testFullExtentWithBasemap(self): self.assertAlmostEqual(p.viewSettings().fullExtent().yMaximum(), 20037508, -2) # add a non-basemap layer - shapefile = os.path.join(TEST_DATA_DIR, 'lines.shp') - layer = QgsVectorLayer(shapefile, 'Lines', 'ogr') + shapefile = os.path.join(TEST_DATA_DIR, "lines.shp") + layer = QgsVectorLayer(shapefile, "Lines", "ogr") p.addMapLayer(layer) # now project extent should ignore basemap layer extents self.assertAlmostEqual(p.viewSettings().fullExtent().xMinimum(), -13093754, -2) self.assertAlmostEqual(p.viewSettings().fullExtent().xMaximum(), -9164115, -2) self.assertAlmostEqual(p.viewSettings().fullExtent().yMinimum(), 2657217, -2) self.assertAlmostEqual(p.viewSettings().fullExtent().yMaximum(), 5809709, -2) - self.assertEqual(p.viewSettings().fullExtent().crs().authid(), 'EPSG:3857') + self.assertEqual(p.viewSettings().fullExtent().crs().authid(), "EPSG:3857") def testReadWrite(self): p = QgsProjectViewSettings() @@ -295,9 +350,16 @@ def testReadWrite(self): p.setUseProjectScales(True) p.setMapScales([56, 78, 99]) - p.setDefaultViewExtent(QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857"))) + p.setDefaultViewExtent( + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857") + ) + ) p.setPresetFullExtent( - QgsReferencedRectangle(QgsRectangle(11, 12, 13, 14), QgsCoordinateReferenceSystem("EPSG:3111"))) + QgsReferencedRectangle( + QgsRectangle(11, 12, 13, 14), QgsCoordinateReferenceSystem("EPSG:3111") + ) + ) elem = p.writeXml(doc, QgsReadWriteContext()) p2 = QgsProjectViewSettings() @@ -306,10 +368,19 @@ def testReadWrite(self): self.assertEqual(p2.mapScales(), [99.0, 78.0, 56.0]) self.assertTrue(p2.useProjectScales()) self.assertEqual(len(spy), 1) - self.assertEqual(p2.defaultViewExtent(), QgsReferencedRectangle(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857"))) - self.assertEqual(p2.presetFullExtent(), - QgsReferencedRectangle(QgsRectangle(11, 12, 13, 14), QgsCoordinateReferenceSystem("EPSG:3111"))) - - -if __name__ == '__main__': + self.assertEqual( + p2.defaultViewExtent(), + QgsReferencedRectangle( + QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem("EPSG:3857") + ), + ) + self.assertEqual( + p2.presetFullExtent(), + QgsReferencedRectangle( + QgsRectangle(11, 12, 13, 14), QgsCoordinateReferenceSystem("EPSG:3111") + ), + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsproperty.py b/tests/src/python/test_qgsproperty.py index 67e43bd46615..d72d4d7bff6c 100644 --- a/tests/src/python/test_qgsproperty.py +++ b/tests/src/python/test_qgsproperty.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '11.04.2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "11.04.2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtCore import QDate from qgis.core import QgsProperty @@ -21,9 +22,9 @@ def test_bool_operator(self): self.assertFalse(property) property = QgsProperty.fromValue(5) self.assertTrue(property) - property = QgsProperty.fromField('field') + property = QgsProperty.fromField("field") self.assertTrue(property) - property = QgsProperty.fromExpression('1+2') + property = QgsProperty.fromExpression("1+2") self.assertTrue(property) diff --git a/tests/src/python/test_qgspropertyoverridebutton.py b/tests/src/python/test_qgspropertyoverridebutton.py index 29ce4ae8a8c4..da34484cf3a1 100644 --- a/tests/src/python/test_qgspropertyoverridebutton.py +++ b/tests/src/python/test_qgspropertyoverridebutton.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '11/01/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "11/01/2019" +__copyright__ = "Copyright 2019, The QGIS Project" from qgis.PyQt.QtGui import QColor from qgis.core import ( @@ -26,96 +27,137 @@ class TestQgsPropertyOverrideButton(QgisTestCase): def testProjectColor(self): - scheme = [s for s in QgsApplication.colorSchemeRegistry().schemes() if isinstance(s, QgsProjectColorScheme)][0] + scheme = [ + s + for s in QgsApplication.colorSchemeRegistry().schemes() + if isinstance(s, QgsProjectColorScheme) + ][0] scheme.setColors([]) - definition = QgsPropertyDefinition('test', 'test', QgsPropertyDefinition.StandardPropertyTemplate.ColorWithAlpha) + definition = QgsPropertyDefinition( + "test", + "test", + QgsPropertyDefinition.StandardPropertyTemplate.ColorWithAlpha, + ) button = QgsPropertyOverrideButton() button.init(0, QgsProperty(), definition) button.aboutToShowMenu() - self.assertIn('Project Color', [a.text() for a in button.menu().actions()]) - self.assertIn('Color', [a.text() for a in button.menu().actions()]) - color_action = [a for a in button.menu().actions() if a.text() == 'Color'][0] - self.assertEqual([a.text() for a in color_action.menu().actions()][0], 'No colors set') + self.assertIn("Project Color", [a.text() for a in button.menu().actions()]) + self.assertIn("Color", [a.text() for a in button.menu().actions()]) + color_action = [a for a in button.menu().actions() if a.text() == "Color"][0] + self.assertEqual( + [a.text() for a in color_action.menu().actions()][0], "No colors set" + ) # add some project colors - scheme.setColors([[QColor(255, 0, 0), 'color 1'], [QColor(255, 255, 0), 'burnt marigold']]) + scheme.setColors( + [[QColor(255, 0, 0), "color 1"], [QColor(255, 255, 0), "burnt marigold"]] + ) button.aboutToShowMenu() - self.assertIn('Project Color', [a.text() for a in button.menu().actions()]) - self.assertIn('Color', [a.text() for a in button.menu().actions()]) - color_action = [a for a in button.menu().actions() if a.text() == 'Color'][0] - self.assertEqual([a.text() for a in color_action.menu().actions()], ['color 1', 'burnt marigold']) + self.assertIn("Project Color", [a.text() for a in button.menu().actions()]) + self.assertIn("Color", [a.text() for a in button.menu().actions()]) + color_action = [a for a in button.menu().actions() if a.text() == "Color"][0] + self.assertEqual( + [a.text() for a in color_action.menu().actions()], + ["color 1", "burnt marigold"], + ) button.menuActionTriggered(color_action.menu().actions()[1]) self.assertTrue(button.toProperty().isActive()) - self.assertEqual(button.toProperty().asExpression(), 'project_color_object(\'burnt marigold\')') + self.assertEqual( + button.toProperty().asExpression(), "project_color_object('burnt marigold')" + ) button.menuActionTriggered(color_action.menu().actions()[0]) self.assertTrue(button.toProperty().isActive()) - self.assertEqual(button.toProperty().asExpression(), 'project_color_object(\'color 1\')') + self.assertEqual( + button.toProperty().asExpression(), "project_color_object('color 1')" + ) - button.setToProperty(QgsProperty.fromExpression('project_color_object(\'burnt marigold\')')) + button.setToProperty( + QgsProperty.fromExpression("project_color_object('burnt marigold')") + ) button.aboutToShowMenu() - color_action = [a for a in button.menu().actions() if a.text() == 'Color'][0] + color_action = [a for a in button.menu().actions() if a.text() == "Color"][0] self.assertTrue(color_action.isChecked()) - self.assertEqual([a.isChecked() for a in color_action.menu().actions()], [False, True]) + self.assertEqual( + [a.isChecked() for a in color_action.menu().actions()], [False, True] + ) - button.setToProperty(QgsProperty.fromExpression('project_color(\'color 1\')')) + button.setToProperty(QgsProperty.fromExpression("project_color('color 1')")) button.aboutToShowMenu() - color_action = [a for a in button.menu().actions() if a.text() == 'Color'][0] + color_action = [a for a in button.menu().actions() if a.text() == "Color"][0] self.assertTrue(color_action.isChecked()) - self.assertEqual([a.isChecked() for a in color_action.menu().actions()], [True, False]) + self.assertEqual( + [a.isChecked() for a in color_action.menu().actions()], [True, False] + ) # should also see color menu for ColorNoAlpha properties - definition = QgsPropertyDefinition('test', 'test', QgsPropertyDefinition.StandardPropertyTemplate.ColorNoAlpha) + definition = QgsPropertyDefinition( + "test", "test", QgsPropertyDefinition.StandardPropertyTemplate.ColorNoAlpha + ) button = QgsPropertyOverrideButton() button.init(0, QgsProperty(), definition) button.aboutToShowMenu() - self.assertIn('Project Color', [a.text() for a in button.menu().actions()]) - self.assertIn('Color', [a.text() for a in button.menu().actions()]) + self.assertIn("Project Color", [a.text() for a in button.menu().actions()]) + self.assertIn("Color", [a.text() for a in button.menu().actions()]) # but no color menu for other types - definition = QgsPropertyDefinition('test', 'test', QgsPropertyDefinition.StandardPropertyTemplate.Double) + definition = QgsPropertyDefinition( + "test", "test", QgsPropertyDefinition.StandardPropertyTemplate.Double + ) button = QgsPropertyOverrideButton() button.init(0, QgsProperty(), definition) button.aboutToShowMenu() - self.assertNotIn('Project Color', [a.text() for a in button.menu().actions()]) - self.assertNotIn('Color', [a.text() for a in button.menu().actions()]) + self.assertNotIn("Project Color", [a.text() for a in button.menu().actions()]) + self.assertNotIn("Color", [a.text() for a in button.menu().actions()]) def testLinkedColorButton(self): - definition = QgsPropertyDefinition('test', 'test', QgsPropertyDefinition.StandardPropertyTemplate.ColorWithAlpha) + definition = QgsPropertyDefinition( + "test", + "test", + QgsPropertyDefinition.StandardPropertyTemplate.ColorWithAlpha, + ) button = QgsPropertyOverrideButton() button.init(0, QgsProperty(), definition) cb = QgsColorButton() button.registerLinkedWidget(cb) - project_scheme = [s for s in QgsApplication.colorSchemeRegistry().schemes() if isinstance(s, QgsProjectColorScheme)][0] - project_scheme.setColors([[QColor(255, 0, 0), 'col1'], [QColor(0, 255, 0), 'col2']]) + project_scheme = [ + s + for s in QgsApplication.colorSchemeRegistry().schemes() + if isinstance(s, QgsProjectColorScheme) + ][0] + project_scheme.setColors( + [[QColor(255, 0, 0), "col1"], [QColor(0, 255, 0), "col2"]] + ) - button.setToProperty(QgsProperty.fromValue('#ff0000')) + button.setToProperty(QgsProperty.fromValue("#ff0000")) self.assertTrue(cb.isEnabled()) self.assertFalse(cb.linkedProjectColorName()) button.setActive(False) self.assertTrue(cb.isEnabled()) self.assertFalse(cb.linkedProjectColorName()) - button.setToProperty(QgsProperty.fromExpression('project_color(\'Cthulhu\'s delight\')')) + button.setToProperty( + QgsProperty.fromExpression("project_color('Cthulhu's delight')") + ) self.assertTrue(cb.isEnabled()) self.assertFalse(cb.linkedProjectColorName()) - button.setToProperty(QgsProperty.fromExpression('project_color(\'col1\')')) + button.setToProperty(QgsProperty.fromExpression("project_color('col1')")) self.assertTrue(cb.isEnabled()) - self.assertEqual(cb.linkedProjectColorName(), 'col1') + self.assertEqual(cb.linkedProjectColorName(), "col1") button.setActive(False) self.assertTrue(cb.isEnabled()) self.assertFalse(cb.linkedProjectColorName()) button.setActive(True) self.assertTrue(cb.isEnabled()) - self.assertEqual(cb.linkedProjectColorName(), 'col1') + self.assertEqual(cb.linkedProjectColorName(), "col1") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsproviderconnection_base.py b/tests/src/python/test_qgsproviderconnection_base.py index b21a2f7fa118..f1d38563af77 100644 --- a/tests/src/python/test_qgsproviderconnection_base.py +++ b/tests/src/python/test_qgsproviderconnection_base.py @@ -10,9 +10,10 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '05/08/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "05/08/2019" +__copyright__ = "Copyright 2019, The QGIS Project" import os import time @@ -41,25 +42,25 @@ from qgis.testing import start_app -class TestPyQgsProviderConnectionBase(): +class TestPyQgsProviderConnectionBase: # Provider test cases must define the string URI for the test - uri = '' + uri = "" # Provider test cases must define the provider name (e.g. "postgres" or "ogr") - providerKey = '' + providerKey = "" configuration = {} - defaultSchema = 'public' + defaultSchema = "public" - myNewTable = 'myNewTable' - myVeryNewTable = 'myVeryNewTable' - myUtf8Table = 'myUtf8\U0001f604Table' - geometryColumnName = 'geom' + myNewTable = "myNewTable" + myVeryNewTable = "myVeryNewTable" + myUtf8Table = "myUtf8\U0001f604Table" + geometryColumnName = "geom" # Provider test cases can define a schema and table name for SQL query layers test sqlVectorLayerSchema = None # string, empty string for schema-less DBs (SQLite) - sqlVectorLayerTable = None # string - sqlVectorLayerCrs = None # string + sqlVectorLayerTable = None # string + sqlVectorLayerCrs = None # string @classmethod def setUpClass(cls): @@ -74,7 +75,7 @@ def setUp(self): def tearDown(self): report_file_path = f"{QDir.tempPath()}/qgistest.html" - with open(report_file_path, 'a') as report_file: + with open(report_file_path, "a") as report_file: report_file.write(self.report) def treat_date_as_string(self): @@ -84,7 +85,8 @@ def treat_date_as_string(self): def getUniqueSchemaName(self, name): """This function must return a schema name with unique prefix/postfix, - if the tests are run simultaneously on the same machine by different CI instances""" + if the tests are run simultaneously on the same machine by different CI instances + """ return name def _test_save_load(self, md, uri, configuration): @@ -92,12 +94,12 @@ def _test_save_load(self, md, uri, configuration): conn = md.createConnection(uri, configuration) - md.saveConnection(conn, 'qgis_test1') + md.saveConnection(conn, "qgis_test1") # Check that we retrieve the new connection - self.assertIn('qgis_test1', md.connections().keys()) - self.assertIn('qgis_test1', md.dbConnections().keys()) + self.assertIn("qgis_test1", md.connections().keys()) + self.assertIn("qgis_test1", md.dbConnections().keys()) - return md.connections()['qgis_test1'] + return md.connections()["qgis_test1"] def _table_names(self, table_properties): """Return table default names from table property list""" @@ -116,11 +118,14 @@ def _test_operations(self, md, conn): capabilities = conn.capabilities() # Schema operations - if (capabilities & QgsAbstractDatabaseProviderConnection.Capability.CreateSchema + if ( + capabilities & QgsAbstractDatabaseProviderConnection.Capability.CreateSchema and capabilities & QgsAbstractDatabaseProviderConnection.Capability.Schemas - and capabilities & QgsAbstractDatabaseProviderConnection.Capability.DropSchema): + and capabilities + & QgsAbstractDatabaseProviderConnection.Capability.DropSchema + ): - myNewSchema = self.getUniqueSchemaName('myNewSchema') + myNewSchema = self.getUniqueSchemaName("myNewSchema") # Start clean if myNewSchema in conn.schemas(): conn.dropSchema(myNewSchema, True) @@ -135,9 +140,12 @@ def _test_operations(self, md, conn): conn.createSchema(myNewSchema) # Test rename - if capabilities & QgsAbstractDatabaseProviderConnection.Capability.RenameSchema: + if ( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.RenameSchema + ): # Rename - myVeryNewSchema = self.getUniqueSchemaName('myVeryNewSchema') + myVeryNewSchema = self.getUniqueSchemaName("myVeryNewSchema") conn.renameSchema(myNewSchema, myVeryNewSchema) schemas = conn.schemas() self.assertIn(myVeryNewSchema, schemas) @@ -153,7 +161,7 @@ def _test_operations(self, md, conn): self.assertNotIn(myNewSchema, schemas) # UTF8 schema - myUtf8NewSchema = self.getUniqueSchemaName('myUtf8\U0001f604NewSchema') + myUtf8NewSchema = self.getUniqueSchemaName("myUtf8\U0001f604NewSchema") conn.createSchema(myUtf8NewSchema) schemas = conn.schemas() conn.dropSchema(myUtf8NewSchema) @@ -162,15 +170,24 @@ def _test_operations(self, md, conn): # Table operations schema = None - if (capabilities & QgsAbstractDatabaseProviderConnection.Capability.CreateVectorTable + if ( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.CreateVectorTable and capabilities & QgsAbstractDatabaseProviderConnection.Capability.Tables - and capabilities & QgsAbstractDatabaseProviderConnection.Capability.DropVectorTable): - - if capabilities & QgsAbstractDatabaseProviderConnection.Capability.CreateSchema: - schema = self.getUniqueSchemaName('myNewSchema') + and capabilities + & QgsAbstractDatabaseProviderConnection.Capability.DropVectorTable + ): + + if ( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.CreateSchema + ): + schema = self.getUniqueSchemaName("myNewSchema") conn.createSchema(schema) - elif capabilities & QgsAbstractDatabaseProviderConnection.Capability.Schemas: + elif ( + capabilities & QgsAbstractDatabaseProviderConnection.Capability.Schemas + ): schema = self.getUniqueSchemaName(self.defaultSchema) # Start clean @@ -190,12 +207,16 @@ def _test_operations(self, md, conn): typ = QgsWkbTypes.Type.LineString # Create - conn.createVectorTable(schema, self.myNewTable, fields, typ, crs, True, options) + conn.createVectorTable( + schema, self.myNewTable, fields, typ, crs, True, options + ) table_names = self._table_names(conn.tables(schema)) self.assertIn(self.myNewTable, table_names) # Create UTF8 table - conn.createVectorTable(schema, self.myUtf8Table, fields, typ, crs, True, options) + conn.createVectorTable( + schema, self.myUtf8Table, fields, typ, crs, True, options + ) table_names = self._table_names(conn.tables(schema)) self.assertIn(self.myNewTable, table_names) self.assertIn(self.myUtf8Table, table_names) @@ -205,10 +226,14 @@ def _test_operations(self, md, conn): self.assertIn(self.myNewTable, table_names) # insert something, because otherwise some databases cannot guess - if self.providerKey in ['hana', 'mssql', 'oracle']: + if self.providerKey in ["hana", "mssql", "oracle"]: f = QgsFeature(fields) - f.setGeometry(QgsGeometry.fromWkt('LineString (-72.345 71.987, -80 80)')) - vl = QgsVectorLayer(conn.tableUri(schema, self.myNewTable), 'vl', self.providerKey) + f.setGeometry( + QgsGeometry.fromWkt("LineString (-72.345 71.987, -80 80)") + ) + vl = QgsVectorLayer( + conn.tableUri(schema, self.myNewTable), "vl", self.providerKey + ) vl.dataProvider().addFeatures([f]) # Check table information @@ -220,61 +245,106 @@ def _test_operations(self, md, conn): self.assertEqual(table_property.geometryColumnCount(), 1) # with oracle line and curve have the same type, so it defaults to curve https://docs.oracle.com/database/121/SPATL/sdo_geometry-object-type.htm#SPATL494 - line_wkb_type = QgsWkbTypes.Type.LineString if self.providerKey != 'oracle' else QgsWkbTypes.Type.CompoundCurve - - self.assertEqual(table_property.geometryColumnTypes()[0].wkbType, line_wkb_type) + line_wkb_type = ( + QgsWkbTypes.Type.LineString + if self.providerKey != "oracle" + else QgsWkbTypes.Type.CompoundCurve + ) + + self.assertEqual( + table_property.geometryColumnTypes()[0].wkbType, line_wkb_type + ) cols = table_property.geometryColumnTypes() self.assertEqual(cols[0].crs, QgsCoordinateReferenceSystem.fromEpsgId(3857)) self.assertEqual(table_property.defaultName(), self.myNewTable) # Check aspatial tables - conn.createVectorTable(schema, 'myNewAspatialTable', fields, QgsWkbTypes.Type.NoGeometry, crs, True, options) - table_properties = conn.tables(schema, QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial) - table_property = self._table_by_name(table_properties, 'myNewAspatialTable') + conn.createVectorTable( + schema, + "myNewAspatialTable", + fields, + QgsWkbTypes.Type.NoGeometry, + crs, + True, + options, + ) + table_properties = conn.tables( + schema, QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial + ) + table_property = self._table_by_name(table_properties, "myNewAspatialTable") self.assertIsNotNone(table_property) self.assertEqual(table_property.maxCoordinateDimensions(), 0) - self.assertEqual(table_property.tableName(), 'myNewAspatialTable') + self.assertEqual(table_property.tableName(), "myNewAspatialTable") self.assertEqual(table_property.geometryColumnCount(), 0) - self.assertEqual(table_property.geometryColumn(), '') - self.assertEqual(table_property.defaultName(), 'myNewAspatialTable') + self.assertEqual(table_property.geometryColumn(), "") + self.assertEqual(table_property.defaultName(), "myNewAspatialTable") cols = table_property.geometryColumnTypes() # We always return geom col types, even when there is no geometry self.assertEqual(cols[0].wkbType, QgsWkbTypes.Type.NoGeometry) self.assertFalse(cols[0].crs.isValid()) - self.assertFalse(table_property.flags() & QgsAbstractDatabaseProviderConnection.TableFlag.Raster) - self.assertFalse(table_property.flags() & QgsAbstractDatabaseProviderConnection.TableFlag.Vector) - self.assertTrue(table_property.flags() & QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial) + self.assertFalse( + table_property.flags() + & QgsAbstractDatabaseProviderConnection.TableFlag.Raster + ) + self.assertFalse( + table_property.flags() + & QgsAbstractDatabaseProviderConnection.TableFlag.Vector + ) + self.assertTrue( + table_property.flags() + & QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial + ) # Check executeSql - if capabilities & QgsAbstractDatabaseProviderConnection.Capability.ExecuteSql: + if ( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.ExecuteSql + ): if schema: - table = f"\"{schema}\".\"myNewAspatialTable\"" + table = f'"{schema}"."myNewAspatialTable"' else: - table = 'myNewAspatialTable' + table = "myNewAspatialTable" # MSSQL literal syntax for UTF8 requires 'N' prefix # Oracle date time definition needs some prefix - sql = "INSERT INTO {} (\"string_t\", \"long_t\", \"double_t\", \"integer_t\", \"date_t\", \"datetime_t\", \"time_t\") VALUES ({}'QGIS Rocks - \U0001f604', 666, 1.234, 1234, {} '2019-07-08', {}, '12:00:13.00')".format( - table, 'N' if self.providerKey == 'mssql' else '', - "DATE" if self.providerKey == 'oracle' else '', - "TIMESTAMP '2019-07-08 12:00:12'" if self.providerKey == 'oracle' else "'2019-07-08T12:00:12'" + sql = 'INSERT INTO {} ("string_t", "long_t", "double_t", "integer_t", "date_t", "datetime_t", "time_t") VALUES ({}\'QGIS Rocks - \U0001f604\', 666, 1.234, 1234, {} \'2019-07-08\', {}, \'12:00:13.00\')'.format( + table, + "N" if self.providerKey == "mssql" else "", + "DATE" if self.providerKey == "oracle" else "", + ( + "TIMESTAMP '2019-07-08 12:00:12'" + if self.providerKey == "oracle" + else "'2019-07-08T12:00:12'" + ), ) res = conn.executeSql(sql) self.assertEqual(res, []) - sql = f"SELECT \"string_t\", \"long_t\", \"double_t\", \"integer_t\", \"date_t\", \"datetime_t\" FROM {table}" + sql = f'SELECT "string_t", "long_t", "double_t", "integer_t", "date_t", "datetime_t" FROM {table}' res = conn.executeSql(sql) expected_date = QtCore.QDate(2019, 7, 8) # GPKG and spatialite have no type for time if self.treat_date_as_string(): - expected_date = '2019-07-08' + expected_date = "2019-07-08" # Oracle DATE type contains date and time and so returns a QDateTime object - elif self.providerKey == 'oracle': + elif self.providerKey == "oracle": expected_date = QtCore.QDateTime(QtCore.QDate(2019, 7, 8)) - self.assertEqual(res, [['QGIS Rocks - \U0001f604', 666, 1.234, 1234, expected_date, QtCore.QDateTime(2019, 7, 8, 12, 0, 12)]]) + self.assertEqual( + res, + [ + [ + "QGIS Rocks - \U0001f604", + 666, + 1.234, + 1234, + expected_date, + QtCore.QDateTime(2019, 7, 8, 12, 0, 12), + ] + ], + ) # Test column names res = conn.execSql(sql) @@ -285,8 +355,30 @@ def _test_operations(self, md, conn): self.assertEqual(row_count, 1) rows = res.rows() - self.assertEqual(rows, [['QGIS Rocks - \U0001f604', 666, 1.234, 1234, expected_date, QtCore.QDateTime(2019, 7, 8, 12, 0, 12)]]) - self.assertEqual(res.columns(), ['string_t', 'long_t', 'double_t', 'integer_t', 'date_t', 'datetime_t']) + self.assertEqual( + rows, + [ + [ + "QGIS Rocks - \U0001f604", + 666, + 1.234, + 1234, + expected_date, + QtCore.QDateTime(2019, 7, 8, 12, 0, 12), + ] + ], + ) + self.assertEqual( + res.columns(), + [ + "string_t", + "long_t", + "double_t", + "integer_t", + "date_t", + "datetime_t", + ], + ) self.assertEqual(res.fetchedRowCount(), 1) @@ -311,38 +403,57 @@ def _test_operations(self, md, conn): self.assertFalse(res.hasNextRow()) # Test time_t - sql = f"SELECT \"time_t\" FROM {table}" + sql = f'SELECT "time_t" FROM {table}' res = conn.executeSql(sql) # This does not work in MSSQL and returns a QByteArray, we have no way to know that it is a time # value and there is no way we can convert it. - if self.providerKey != 'mssql': - self.assertIn(res, ([[QtCore.QTime(12, 0, 13)]], [['12:00:13.00']])) + if self.providerKey != "mssql": + self.assertIn(res, ([[QtCore.QTime(12, 0, 13)]], [["12:00:13.00"]])) sql = "DELETE FROM {} WHERE \"string_t\" = {}'QGIS Rocks - \U0001f604'".format( - table, 'N' if self.providerKey == 'mssql' else '') + table, "N" if self.providerKey == "mssql" else "" + ) res = conn.executeSql(sql) self.assertEqual(res, []) - sql = f"SELECT \"string_t\", \"integer_t\" FROM {table}" + sql = f'SELECT "string_t", "integer_t" FROM {table}' res = conn.executeSql(sql) self.assertEqual(res, []) # Check that we do NOT get the aspatial table when querying for vectors - table_names = self._table_names(conn.tables(schema, QgsAbstractDatabaseProviderConnection.TableFlag.Vector)) + table_names = self._table_names( + conn.tables( + schema, QgsAbstractDatabaseProviderConnection.TableFlag.Vector + ) + ) self.assertIn(self.myNewTable, table_names) - self.assertNotIn('myNewAspatialTable', table_names) + self.assertNotIn("myNewAspatialTable", table_names) # Query for rasters (in qgis_test schema or no schema for GPKG, spatialite has no support) - if self.providerKey not in ('spatialite', 'mssql', 'hana', 'oracle'): - table_properties = conn.tables('qgis_test', QgsAbstractDatabaseProviderConnection.TableFlag.Raster) + if self.providerKey not in ("spatialite", "mssql", "hana", "oracle"): + table_properties = conn.tables( + "qgis_test", QgsAbstractDatabaseProviderConnection.TableFlag.Raster + ) # At least one raster should be there (except for spatialite) self.assertGreaterEqual(len(table_properties), 1) table_property = table_properties[0] - self.assertTrue(table_property.flags() & QgsAbstractDatabaseProviderConnection.TableFlag.Raster) - self.assertFalse(table_property.flags() & QgsAbstractDatabaseProviderConnection.TableFlag.Vector) - self.assertFalse(table_property.flags() & QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial) + self.assertTrue( + table_property.flags() + & QgsAbstractDatabaseProviderConnection.TableFlag.Raster + ) + self.assertFalse( + table_property.flags() + & QgsAbstractDatabaseProviderConnection.TableFlag.Vector + ) + self.assertFalse( + table_property.flags() + & QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial + ) - if capabilities & QgsAbstractDatabaseProviderConnection.Capability.RenameVectorTable: + if ( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.RenameVectorTable + ): # Rename conn.renameVectorTable(schema, self.myNewTable, self.myVeryNewTable) tables = self._table_names(conn.tables(schema)) @@ -361,30 +472,71 @@ def _test_operations(self, md, conn): # Spatial index spatial_index_exists = False # we don't initially know if a spatial index exists -- some formats may create them by default, others don't - if capabilities & QgsAbstractDatabaseProviderConnection.Capability.SpatialIndexExists: - spatial_index_exists = conn.spatialIndexExists(schema, self.myNewTable, self.geometryColumnName) - if capabilities & QgsAbstractDatabaseProviderConnection.Capability.DeleteSpatialIndex: + if ( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.SpatialIndexExists + ): + spatial_index_exists = conn.spatialIndexExists( + schema, self.myNewTable, self.geometryColumnName + ) + if ( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.DeleteSpatialIndex + ): if spatial_index_exists: - conn.deleteSpatialIndex(schema, self.myNewTable, self.geometryColumnName) - if capabilities & QgsAbstractDatabaseProviderConnection.Capability.SpatialIndexExists: - self.assertFalse(conn.spatialIndexExists(schema, self.myNewTable, self.geometryColumnName)) - - if capabilities & (QgsAbstractDatabaseProviderConnection.Capability.CreateSpatialIndex | QgsAbstractDatabaseProviderConnection.Capability.SpatialIndexExists): + conn.deleteSpatialIndex( + schema, self.myNewTable, self.geometryColumnName + ) + if ( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.SpatialIndexExists + ): + self.assertFalse( + conn.spatialIndexExists( + schema, self.myNewTable, self.geometryColumnName + ) + ) + + if capabilities & ( + QgsAbstractDatabaseProviderConnection.Capability.CreateSpatialIndex + | QgsAbstractDatabaseProviderConnection.Capability.SpatialIndexExists + ): options = QgsAbstractDatabaseProviderConnection.SpatialIndexOptions() options.geometryColumnName = self.geometryColumnName - if not conn.spatialIndexExists(schema, self.myNewTable, options.geometryColumnName): + if not conn.spatialIndexExists( + schema, self.myNewTable, options.geometryColumnName + ): conn.createSpatialIndex(schema, self.myNewTable, options) - self.assertTrue(conn.spatialIndexExists(schema, self.myNewTable, self.geometryColumnName)) + self.assertTrue( + conn.spatialIndexExists( + schema, self.myNewTable, self.geometryColumnName + ) + ) # now we know for certain a spatial index exists, let's retry dropping it - if capabilities & QgsAbstractDatabaseProviderConnection.Capability.DeleteSpatialIndex: - conn.deleteSpatialIndex(schema, self.myNewTable, self.geometryColumnName) - if capabilities & QgsAbstractDatabaseProviderConnection.Capability.SpatialIndexExists: - self.assertFalse(conn.spatialIndexExists(schema, self.myNewTable, self.geometryColumnName)) - - if capabilities & QgsAbstractDatabaseProviderConnection.Capability.DropSchema: + if ( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.DeleteSpatialIndex + ): + conn.deleteSpatialIndex( + schema, self.myNewTable, self.geometryColumnName + ) + if ( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.SpatialIndexExists + ): + self.assertFalse( + conn.spatialIndexExists( + schema, self.myNewTable, self.geometryColumnName + ) + ) + + if ( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.DropSchema + ): # Drop schema (should fail) with self.assertRaises(QgsProviderConnectionException) as ex: conn.dropSchema(schema) @@ -396,13 +548,17 @@ def _test_operations(self, md, conn): self.assertEqual(ct.crs, QgsCoordinateReferenceSystem.fromEpsgId(3857)) self.assertEqual(ct.wkbType, line_wkb_type) # Add a new (existing type) - table.addGeometryColumnType(line_wkb_type, QgsCoordinateReferenceSystem.fromEpsgId(3857)) + table.addGeometryColumnType( + line_wkb_type, QgsCoordinateReferenceSystem.fromEpsgId(3857) + ) self.assertEqual(len(table.geometryColumnTypes()), 1) ct = table.geometryColumnTypes()[0] self.assertEqual(ct.crs, QgsCoordinateReferenceSystem.fromEpsgId(3857)) self.assertEqual(ct.wkbType, line_wkb_type) # Add a new one - table.addGeometryColumnType(line_wkb_type, QgsCoordinateReferenceSystem.fromEpsgId(4326)) + table.addGeometryColumnType( + line_wkb_type, QgsCoordinateReferenceSystem.fromEpsgId(4326) + ) self.assertEqual(len(table.geometryColumnTypes()), 2) ct = table.geometryColumnTypes()[0] self.assertEqual(ct.crs, QgsCoordinateReferenceSystem.fromEpsgId(3857)) @@ -413,39 +569,57 @@ def _test_operations(self, md, conn): # Check fields fields = conn.fields(schema, self.myNewTable) - for f in ['string_t', 'long_t', 'double_t', 'integer_t', 'date_t', 'datetime_t', 'time_t']: + for f in [ + "string_t", + "long_t", + "double_t", + "integer_t", + "date_t", + "datetime_t", + "time_t", + ]: self.assertIn(f, fields.names()) if capabilities & QgsAbstractDatabaseProviderConnection.Capability.AddField: - field = QgsField('short_lived_field', QVariant.Int, 'integer') + field = QgsField("short_lived_field", QVariant.Int, "integer") conn.addField(field, schema, self.myNewTable) fields = conn.fields(schema, self.myNewTable) - self.assertIn('short_lived_field', fields.names()) + self.assertIn("short_lived_field", fields.names()) - if capabilities & QgsAbstractDatabaseProviderConnection.Capability.DeleteField: - conn.deleteField('short_lived_field', schema, self.myNewTable) + if ( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.DeleteField + ): + conn.deleteField("short_lived_field", schema, self.myNewTable) # This fails on Travis for spatialite, for no particular reason - if self.providerKey == 'spatialite' and not os.environ.get('TRAVIS', False): + if self.providerKey == "spatialite" and not os.environ.get( + "TRAVIS", False + ): fields = conn.fields(schema, self.myNewTable) - self.assertNotIn('short_lived_field', fields.names()) + self.assertNotIn("short_lived_field", fields.names()) # Drop table conn.dropVectorTable(schema, self.myNewTable) - conn.dropVectorTable(schema, 'myNewAspatialTable') + conn.dropVectorTable(schema, "myNewAspatialTable") table_names = self._table_names(conn.tables(schema)) self.assertNotIn(self.myNewTable, table_names) - if capabilities & QgsAbstractDatabaseProviderConnection.Capability.DropSchema: + if ( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.DropSchema + ): # Drop schema conn.dropSchema(schema) self.assertNotIn(schema, conn.schemas()) conns = md.connections() - self.assertTrue(isinstance(list(conns.values())[0], QgsAbstractDatabaseProviderConnection)) + self.assertTrue( + isinstance(list(conns.values())[0], QgsAbstractDatabaseProviderConnection) + ) # Remove connection spy_deleted = QSignalSpy(md.connectionDeleted) - md.deleteConnection('qgis_test1') + md.deleteConnection("qgis_test1") self.assertEqual(list(md.connections().values()), []) self.assertEqual(len(spy_deleted), 1) @@ -455,17 +629,30 @@ def test_errors(self): md = QgsProviderRegistry.instance().providerMetadata(self.providerKey) conn = self._test_save_load(md, self.uri, self.configuration) - if conn.capabilities() & QgsAbstractDatabaseProviderConnection.Capability.Schemas: + if ( + conn.capabilities() + & QgsAbstractDatabaseProviderConnection.Capability.Schemas + ): with self.assertRaises(QgsProviderConnectionException) as ex: - conn.createVectorTable('notExists', 'notReally', QgsFields(), QgsWkbTypes.Type.Point, - QgsCoordinateReferenceSystem(), False, {}) + conn.createVectorTable( + "notExists", + "notReally", + QgsFields(), + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem(), + False, + {}, + ) - if conn.capabilities() & QgsAbstractDatabaseProviderConnection.Capability.DropVectorTable: + if ( + conn.capabilities() + & QgsAbstractDatabaseProviderConnection.Capability.DropVectorTable + ): with self.assertRaises(QgsProviderConnectionException) as ex: conn.executeSql('DROP TABLE "notExists"') # Remove connection - md.deleteConnection('qgis_test1') + md.deleteConnection("qgis_test1") self.assertEqual(list(md.connections().values()), []) def test_connections(self): @@ -483,7 +670,7 @@ def test_connections(self): self.assertEqual(len(changed_spy), 0) # if we try to save again, the connectionChanged signal should be emitted instead of connectionCreated - md.saveConnection(conn, 'qgis_test1') + md.saveConnection(conn, "qgis_test1") self.assertEqual(len(created_spy), 1) self.assertEqual(len(changed_spy), 1) @@ -496,13 +683,21 @@ def test_native_types(self): conn = md.createConnection(self.uri, {}) native_types = conn.nativeTypes() names = [nt.mTypeName.lower() for nt in native_types] - self.assertTrue('integer' in names or 'decimal' in names or 'number' in names, names) - self.assertTrue('string' in names or 'text' in names or 'nvarchar' in names or 'varchar2' in names, names) + self.assertTrue( + "integer" in names or "decimal" in names or "number" in names, names + ) + self.assertTrue( + "string" in names + or "text" in names + or "nvarchar" in names + or "varchar2" in names, + names, + ) def testExecuteSqlCancel(self): """Test that feedback can cancel an executeSql query""" - if hasattr(self, 'slowQuery'): + if hasattr(self, "slowQuery"): md = QgsProviderRegistry.instance().providerMetadata(self.providerKey) conn = md.createConnection(self.uri, {}) @@ -516,9 +711,12 @@ def _cancel(): start = time.time() QtCore.QTimer.singleShot(500, _cancel) - task = QgsTask.fromFunction('test long running query', _run) + task = QgsTask.fromFunction("test long running query", _run) QgsApplication.taskManager().addTask(task) - while task.status() not in [QgsTask.TaskStatus.Complete, QgsTask.TaskStatus.Terminated]: + while task.status() not in [ + QgsTask.TaskStatus.Complete, + QgsTask.TaskStatus.Terminated, + ]: QgsApplication.processEvents() end = time.time() self.assertLess(end - start, 1) @@ -529,23 +727,34 @@ def testCreateSqlVectorLayer(self): md = QgsProviderRegistry.instance().providerMetadata(self.providerKey) conn = md.createConnection(self.uri, {}) - if not conn.capabilities() & QgsAbstractDatabaseProviderConnection.Capability.SqlLayers: - print(f"FIXME: {self.providerKey} data provider does not support query layers!") + if ( + not conn.capabilities() + & QgsAbstractDatabaseProviderConnection.Capability.SqlLayers + ): + print( + f"FIXME: {self.providerKey} data provider does not support query layers!" + ) return - schema = getattr(self, 'sqlVectorLayerSchema', None) + schema = getattr(self, "sqlVectorLayerSchema", None) if schema is None: - print(f"FIXME: {self.providerKey} data provider test case does not define self.sqlVectorLayerSchema for query layers test!") + print( + f"FIXME: {self.providerKey} data provider test case does not define self.sqlVectorLayerSchema for query layers test!" + ) return - table = getattr(self, 'sqlVectorLayerTable', None) + table = getattr(self, "sqlVectorLayerTable", None) if table is None: - print(f"FIXME: {self.providerKey} data provider test case does not define self.sqlVectorLayerTable for query layers test!") + print( + f"FIXME: {self.providerKey} data provider test case does not define self.sqlVectorLayerTable for query layers test!" + ) return - crs = getattr(self, 'sqlVectorLayerCrs', None) + crs = getattr(self, "sqlVectorLayerCrs", None) if crs is None: - print(f"FIXME: {self.providerKey} data provider test case does not define self.sqlVectorLayerCrs for query layers test!") + print( + f"FIXME: {self.providerKey} data provider test case does not define self.sqlVectorLayerCrs for query layers test!" + ) return sql_layer_capabilities = conn.sqlLayerDefinitionCapabilities() @@ -554,11 +763,13 @@ def testCreateSqlVectorLayer(self): table_info = conn.table(schema, table) options = QgsAbstractDatabaseProviderConnection.SqlVectorLayerOptions() - options.layerName = 'My SQL Layer' + options.layerName = "My SQL Layer" # Some providers do not support schema - if schema != '': - options.sql = f'SELECT * FROM "{table_info.schema()}"."{table_info.tableName()}"' + if schema != "": + options.sql = ( + f'SELECT * FROM "{table_info.schema()}"."{table_info.tableName()}"' + ) else: options.sql = f'SELECT * FROM "{table_info.tableName()}"' @@ -588,16 +799,19 @@ def testCreateSqlVectorLayer(self): # Some providers can also create SQL layer without an explicit geometry column if sql_layer_capabilities & Qgis.SqlLayerDefinitionCapability.GeometryColumn: options.primaryKeyColumns = table_info.primaryKeyColumns() - options.geometryColumn = '' + options.geometryColumn = "" vl = conn.createSqlVectorLayer(options) self.assertTrue(vl.isValid()) self.assertTrue(vl.isSqlQuery()) # This may fail for OGR where the provider is smart enough to guess the geometry column - if self.providerKey != 'ogr': + if self.providerKey != "ogr": self.assertFalse(vl.isSpatial()) # Some providers can also create SQL layer with filters - if sql_layer_capabilities & Qgis.SqlLayerDefinitionCapability.SubsetStringFilter: + if ( + sql_layer_capabilities + & Qgis.SqlLayerDefinitionCapability.SubsetStringFilter + ): options.primaryKeyColumns = table_info.primaryKeyColumns() options.geometryColumn = table_info.geometryColumn() options.filter = f'"{options.primaryKeyColumns[0]}" > 0' diff --git a/tests/src/python/test_qgsproviderconnection_hana.py b/tests/src/python/test_qgsproviderconnection_hana.py index 183a0ca9f53f..2559ae2a75e9 100644 --- a/tests/src/python/test_qgsproviderconnection_hana.py +++ b/tests/src/python/test_qgsproviderconnection_hana.py @@ -6,9 +6,10 @@ (at your option) any later version. """ -__author__ = 'Maxim Rylov' -__date__ = '02/04/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Maxim Rylov" +__date__ = "02/04/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import os @@ -22,34 +23,43 @@ from test_qgsproviderconnection_base import TestPyQgsProviderConnectionBase -class TestPyQgsProviderConnectionHana(unittest.TestCase, TestPyQgsProviderConnectionBase): +class TestPyQgsProviderConnectionHana( + unittest.TestCase, TestPyQgsProviderConnectionBase +): # Provider test cases must define the provider name (e.g. "hana" or "ogr") - providerKey = 'hana' + providerKey = "hana" # Provider test cases must define the string URI for the test - uri = '' + uri = "" # HANA connection object conn = None # Name of the schema - schemaName = '' + schemaName = "" @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsProviderConnectionHana, cls).setUpClass() + super().setUpClass() TestPyQgsProviderConnectionBase.setUpClass() - cls.uri = 'driver=\'/usr/sap/hdbclient/libodbcHDB.so\' host=localhost port=30015 ' \ - 'user=SYSTEM password=mypassword sslEnabled=true sslValidateCertificate=False' - if 'QGIS_HANA_TEST_DB' in os.environ: - cls.uri = os.environ['QGIS_HANA_TEST_DB'] + cls.uri = ( + "driver='/usr/sap/hdbclient/libodbcHDB.so' host=localhost port=30015 " + "user=SYSTEM password=mypassword sslEnabled=true sslValidateCertificate=False" + ) + if "QGIS_HANA_TEST_DB" in os.environ: + cls.uri = os.environ["QGIS_HANA_TEST_DB"] cls.conn = QgsHanaProviderUtils.createConnection(cls.uri) - cls.schemaName = QgsHanaProviderUtils.generateSchemaName(cls.conn, 'qgis_test_provider_conn') + cls.schemaName = QgsHanaProviderUtils.generateSchemaName( + cls.conn, "qgis_test_provider_conn" + ) QgsHanaProviderUtils.createAndFillDefaultTables(cls.conn, cls.schemaName) # Create test layers cls.vl = QgsHanaProviderUtils.createVectorLayer( - cls.uri + f' key=\'pk\' srid=4326 type=POINT table="{cls.schemaName}"."some_data" (geom) sql=', 'test') + cls.uri + + f' key=\'pk\' srid=4326 type=POINT table="{cls.schemaName}"."some_data" (geom) sql=', + "test", + ) @classmethod def tearDownClass(cls): @@ -57,23 +67,28 @@ def tearDownClass(cls): QgsHanaProviderUtils.cleanUp(cls.conn, cls.schemaName) cls.conn.close() - super(TestPyQgsProviderConnectionHana, cls).tearDownClass() + super().tearDownClass() def getUniqueSchemaName(self, name): - return 'qgis_test_' + QgsHanaProviderUtils.generateSchemaName(self.conn, name) + return "qgis_test_" + QgsHanaProviderUtils.generateSchemaName(self.conn, name) def createProviderMetadata(self): return QgsProviderRegistry.instance().providerMetadata(self.providerKey) def createVectorLayer(self, conn_parameters, layer_name): - return QgsHanaProviderUtils.createVectorLayer(self.uri + ' ' + conn_parameters, layer_name) + return QgsHanaProviderUtils.createVectorLayer( + self.uri + " " + conn_parameters, layer_name + ) def testConnectionsFromUri(self): """Create a connection from a layer uri and retrieve it""" md = self.createProviderMetadata() - vl = self.createVectorLayer(f'key=\'key1\' srid=4326 type=POINT table="{self.schemaName}"."some_data" (' - 'geom) sql=', 'test') + vl = self.createVectorLayer( + f'key=\'key1\' srid=4326 type=POINT table="{self.schemaName}"."some_data" (' + "geom) sql=", + "test", + ) uri = vl.dataProvider().uri().uri() conn = md.createConnection(uri, {}) self.assertEqual(conn.uri(), uri) @@ -83,7 +98,9 @@ def testTableUri(self): md = self.createProviderMetadata() conn = md.createConnection(self.uri, {}) - vl = QgsHanaProviderUtils.createVectorLayer(conn.tableUri(self.schemaName, 'some_data'), 'test') + vl = QgsHanaProviderUtils.createVectorLayer( + conn.tableUri(self.schemaName, "some_data"), "test" + ) def testConnections(self): """Create some connections and retrieve them""" @@ -92,35 +109,76 @@ def testConnections(self): conn = md.createConnection(self.uri, {}) # Retrieve capabilities capabilities = conn.capabilities() - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.CreateSchema)) - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.DropSchema)) - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.CreateVectorTable)) - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.DropVectorTable)) - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.RenameVectorTable)) - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.Tables)) - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.Schemas)) - - table_names = self._table_names(conn.tables(self.schemaName, QgsAbstractDatabaseProviderConnection.TableFlag.Vector)) - self.assertEqual(table_names.sort(), ['some_data', 'some_poly_data'].sort()) - - view_names = self._table_names(conn.tables(self.schemaName, QgsAbstractDatabaseProviderConnection.TableFlag.View)) - self.assertEqual(view_names, ['some_data_view']) + self.assertTrue( + bool( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.CreateSchema + ) + ) + self.assertTrue( + bool( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.DropSchema + ) + ) + self.assertTrue( + bool( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.CreateVectorTable + ) + ) + self.assertTrue( + bool( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.DropVectorTable + ) + ) + self.assertTrue( + bool( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.RenameVectorTable + ) + ) + self.assertTrue( + bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.Tables) + ) + self.assertTrue( + bool( + capabilities & QgsAbstractDatabaseProviderConnection.Capability.Schemas + ) + ) + + table_names = self._table_names( + conn.tables( + self.schemaName, QgsAbstractDatabaseProviderConnection.TableFlag.Vector + ) + ) + self.assertEqual(table_names.sort(), ["some_data", "some_poly_data"].sort()) + + view_names = self._table_names( + conn.tables( + self.schemaName, QgsAbstractDatabaseProviderConnection.TableFlag.View + ) + ) + self.assertEqual(view_names, ["some_data_view"]) def testTrueFalse(self): """Test returned values from BOOL queries""" md = self.createProviderMetadata() conn = md.createConnection(self.uri, {}) - self.assertEqual(conn.executeSql('SELECT FALSE FROM DUMMY'), [[False]]) - self.assertEqual(conn.executeSql('SELECT TRUE FROM DUMMY'), [[True]]) + self.assertEqual(conn.executeSql("SELECT FALSE FROM DUMMY"), [[False]]) + self.assertEqual(conn.executeSql("SELECT TRUE FROM DUMMY"), [[True]]) def testPrimaryKeys(self): """Test returned primary keys""" md = self.createProviderMetadata() conn = md.createConnection(self.uri, {}) - self.assertEqual(conn.table(self.schemaName, 'some_data').primaryKeyColumns(), ['pk']) + self.assertEqual( + conn.table(self.schemaName, "some_data").primaryKeyColumns(), ["pk"] + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsproviderconnection_mssql.py b/tests/src/python/test_qgsproviderconnection_mssql.py index a552e9b88be4..3a893cd6150b 100644 --- a/tests/src/python/test_qgsproviderconnection_mssql.py +++ b/tests/src/python/test_qgsproviderconnection_mssql.py @@ -6,9 +6,10 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '12/03/2020' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "12/03/2020" +__copyright__ = "Copyright 2019, The QGIS Project" import os @@ -25,119 +26,124 @@ from test_qgsproviderconnection_base import TestPyQgsProviderConnectionBase -class TestPyQgsProviderConnectionMssql(unittest.TestCase, TestPyQgsProviderConnectionBase): +class TestPyQgsProviderConnectionMssql( + unittest.TestCase, TestPyQgsProviderConnectionBase +): # Provider test cases must define the string URI for the test - uri = '' + uri = "" # Provider test cases must define the provider name (e.g. "postgres" or "ogr") - providerKey = 'mssql' + providerKey = "mssql" @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsProviderConnectionMssql, cls).setUpClass() + super().setUpClass() TestPyQgsProviderConnectionBase.setUpClass() # These are the connection details for the SQL Server instance running on Travis cls.dbconn = "service='testsqlserver' user=sa password='' " - if 'QGIS_MSSQLTEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_MSSQLTEST_DB'] + if "QGIS_MSSQLTEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_MSSQLTEST_DB"] cls.uri = cls.dbconn try: - md = QgsProviderRegistry.instance().providerMetadata('mssql') + md = QgsProviderRegistry.instance().providerMetadata("mssql") conn = md.createConnection(cls.uri, {}) - conn.executeSql('drop schema [myNewSchema]') + conn.executeSql("drop schema [myNewSchema]") except: pass def test_configuration(self): """Test storage and retrieval for configuration parameters""" - uri = 'dbname=\'qgis_test\' service=\'driver={SQL Server};server=localhost;port=1433;database=qgis_test\' user=\'sa\' password=\'\' srid=4326 type=Point estimatedMetadata=\'true\' disableInvalidGeometryHandling=\'1\' table="qgis_test"."someData" (geom)' - md = QgsProviderRegistry.instance().providerMetadata('mssql') + uri = "dbname='qgis_test' service='driver={SQL Server};server=localhost;port=1433;database=qgis_test' user='sa' password='' srid=4326 type=Point estimatedMetadata='true' disableInvalidGeometryHandling='1' table=\"qgis_test\".\"someData\" (geom)" + md = QgsProviderRegistry.instance().providerMetadata("mssql") conn = md.createConnection(uri, {}) ds_uri = QgsDataSourceUri(conn.uri()) - self.assertEqual(ds_uri.username(), 'sa') - self.assertEqual(ds_uri.database(), 'qgis_test') - self.assertEqual(ds_uri.table(), '') - self.assertEqual(ds_uri.schema(), '') - self.assertEqual(ds_uri.geometryColumn(), '') + self.assertEqual(ds_uri.username(), "sa") + self.assertEqual(ds_uri.database(), "qgis_test") + self.assertEqual(ds_uri.table(), "") + self.assertEqual(ds_uri.schema(), "") + self.assertEqual(ds_uri.geometryColumn(), "") self.assertTrue(ds_uri.useEstimatedMetadata()) - self.assertEqual(ds_uri.srid(), '') - self.assertEqual(ds_uri.password(), '') - self.assertEqual(ds_uri.param('disableInvalidGeometryHandling'), '1') + self.assertEqual(ds_uri.srid(), "") + self.assertEqual(ds_uri.password(), "") + self.assertEqual(ds_uri.param("disableInvalidGeometryHandling"), "1") - conn.store('coronavirus') - conn = md.findConnection('coronavirus', False) + conn.store("coronavirus") + conn = md.findConnection("coronavirus", False) ds_uri = QgsDataSourceUri(conn.uri()) - self.assertEqual(ds_uri.username(), 'sa') - self.assertEqual(ds_uri.database(), 'qgis_test') - self.assertEqual(ds_uri.table(), '') - self.assertEqual(ds_uri.schema(), '') + self.assertEqual(ds_uri.username(), "sa") + self.assertEqual(ds_uri.database(), "qgis_test") + self.assertEqual(ds_uri.table(), "") + self.assertEqual(ds_uri.schema(), "") self.assertTrue(ds_uri.useEstimatedMetadata()) - self.assertEqual(ds_uri.geometryColumn(), '') - self.assertEqual(ds_uri.srid(), '') - self.assertEqual(ds_uri.password(), '') - self.assertEqual(ds_uri.param('disableInvalidGeometryHandling'), 'true') - conn.remove('coronavirus') + self.assertEqual(ds_uri.geometryColumn(), "") + self.assertEqual(ds_uri.srid(), "") + self.assertEqual(ds_uri.password(), "") + self.assertEqual(ds_uri.param("disableInvalidGeometryHandling"), "true") + conn.remove("coronavirus") def test_mssql_connections_from_uri(self): """Create a connection from a layer uri and retrieve it""" - md = QgsProviderRegistry.instance().providerMetadata('mssql') + md = QgsProviderRegistry.instance().providerMetadata("mssql") def test_table_uri(self): """Create a connection from a layer uri and create a table URI""" - md = QgsProviderRegistry.instance().providerMetadata('mssql') + md = QgsProviderRegistry.instance().providerMetadata("mssql") conn = md.createConnection(self.uri, {}) - vl = QgsVectorLayer(conn.tableUri('qgis_test', 'someData'), 'my', 'mssql') + vl = QgsVectorLayer(conn.tableUri("qgis_test", "someData"), "my", "mssql") self.assertTrue(vl.isValid()) def test_mssql_fields(self): """Test fields""" - md = QgsProviderRegistry.instance().providerMetadata('mssql') + md = QgsProviderRegistry.instance().providerMetadata("mssql") conn = md.createConnection(self.uri, {}) - fields = conn.fields('qgis_test', 'someData') - self.assertEqual(fields.names(), ['pk', 'cnt', 'name', 'name2', 'num_char', 'dt', 'date', 'time']) + fields = conn.fields("qgis_test", "someData") + self.assertEqual( + fields.names(), + ["pk", "cnt", "name", "name2", "num_char", "dt", "date", "time"], + ) def test_schemas_filtering(self): """Test schemas filtering""" - md = QgsProviderRegistry.instance().providerMetadata('mssql') + md = QgsProviderRegistry.instance().providerMetadata("mssql") conn = md.createConnection(self.uri, {}) schemas = conn.schemas() - self.assertIn('dbo', schemas) - self.assertIn('qgis_test', schemas) + self.assertIn("dbo", schemas) + self.assertIn("qgis_test", schemas) filterUri = QgsDataSourceUri(self.uri) - filterUri.setParam('excludedSchemas', 'dbo') + filterUri.setParam("excludedSchemas", "dbo") conn = md.createConnection(filterUri.uri(), {}) schemas = conn.schemas() - self.assertNotIn('dbo', schemas) - self.assertIn('qgis_test', schemas) + self.assertNotIn("dbo", schemas) + self.assertIn("qgis_test", schemas) # Store the connection - conn.store('filteredConnection') + conn.store("filteredConnection") - otherConn = md.createConnection('filteredConnection') + otherConn = md.createConnection("filteredConnection") schemas = otherConn.schemas() - self.assertNotIn('dbo', schemas) - self.assertIn('qgis_test', schemas) + self.assertNotIn("dbo", schemas) + self.assertIn("qgis_test", schemas) def test_exec_sql(self): - md = QgsProviderRegistry.instance().providerMetadata('mssql') + md = QgsProviderRegistry.instance().providerMetadata("mssql") conn = md.createConnection(self.uri, {}) - results = conn.executeSql('select * from qgis_test.some_poly_data') + results = conn.executeSql("select * from qgis_test.some_poly_data") rows = [] - results2 = conn.execSql('select * from qgis_test.some_poly_data') + results2 = conn.execSql("select * from qgis_test.some_poly_data") while results2.hasNextRow(): rows.append(results2.nextRow()) @@ -148,38 +154,58 @@ def test_exec_sql(self): def test_geometry_z(self): """Test for issue GH #52660: Z values are not correctly stored when using MSSQL""" - md = QgsProviderRegistry.instance().providerMetadata('mssql') + md = QgsProviderRegistry.instance().providerMetadata("mssql") conn = md.createConnection(self.uri, {}) - conn.dropVectorTable('qgis_test', 'test_z') - - conn.createVectorTable('qgis_test', 'test_z', QgsFields(), Qgis.WkbType.PolygonZ, QgsCoordinateReferenceSystem(), True, {}) - conn.executeSql("""INSERT INTO qgis_test.test_z (geom) values (geometry::STGeomFromText ('POLYGON ((523699.41 6231152.17 80.53, 523698.64 6231154.35 79.96, 523694.92 6231152.82 80.21, 523695.8 6231150.68 80.54, 523699.41 6231152.17 80.53))' , 25832))""") - - tb = conn.table('qgis_test', 'test_z') + conn.dropVectorTable("qgis_test", "test_z") + + conn.createVectorTable( + "qgis_test", + "test_z", + QgsFields(), + Qgis.WkbType.PolygonZ, + QgsCoordinateReferenceSystem(), + True, + {}, + ) + conn.executeSql( + """INSERT INTO qgis_test.test_z (geom) values (geometry::STGeomFromText ('POLYGON ((523699.41 6231152.17 80.53, 523698.64 6231154.35 79.96, 523694.92 6231152.82 80.21, 523695.8 6231150.68 80.54, 523699.41 6231152.17 80.53))' , 25832))""" + ) + + tb = conn.table("qgis_test", "test_z") gct = tb.geometryColumnTypes()[0] self.assertEqual(gct.wkbType, Qgis.WkbType.PolygonZ) self.assertEqual(tb.maxCoordinateDimensions(), 3) - vl = QgsVectorLayer(conn.tableUri('qgis_test', 'test_z'), 'test_z', 'mssql') + vl = QgsVectorLayer(conn.tableUri("qgis_test", "test_z"), "test_z", "mssql") self.assertEqual(vl.wkbType(), Qgis.WkbType.PolygonZ) - conn.dropVectorTable('qgis_test', 'test_z') + conn.dropVectorTable("qgis_test", "test_z") # Also test ZM - conn.dropVectorTable('qgis_test', 'test_zm') - conn.createVectorTable('qgis_test', 'test_zm', QgsFields(), Qgis.WkbType.PolygonZM, QgsCoordinateReferenceSystem(), True, {}) - conn.executeSql("""INSERT INTO qgis_test.test_zm (geom) values (geometry::STGeomFromText ('POLYGON ((523699.41 6231152.17 80.53 123, 523698.64 6231154.35 79.96 456, 523694.92 6231152.82 80.21 789, 523695.8 6231150.68 80.54, 523699.41 6231152.17 80.53 123))' , 25832))""") - - tb = conn.table('qgis_test', 'test_zm') + conn.dropVectorTable("qgis_test", "test_zm") + conn.createVectorTable( + "qgis_test", + "test_zm", + QgsFields(), + Qgis.WkbType.PolygonZM, + QgsCoordinateReferenceSystem(), + True, + {}, + ) + conn.executeSql( + """INSERT INTO qgis_test.test_zm (geom) values (geometry::STGeomFromText ('POLYGON ((523699.41 6231152.17 80.53 123, 523698.64 6231154.35 79.96 456, 523694.92 6231152.82 80.21 789, 523695.8 6231150.68 80.54, 523699.41 6231152.17 80.53 123))' , 25832))""" + ) + + tb = conn.table("qgis_test", "test_zm") gct = tb.geometryColumnTypes()[0] self.assertEqual(gct.wkbType, Qgis.WkbType.PolygonZM) self.assertEqual(tb.maxCoordinateDimensions(), 4) - vl = QgsVectorLayer(conn.tableUri('qgis_test', 'test_zm'), 'test_zm', 'mssql') + vl = QgsVectorLayer(conn.tableUri("qgis_test", "test_zm"), "test_zm", "mssql") self.assertEqual(vl.wkbType(), Qgis.WkbType.PolygonZM) - conn.dropVectorTable('qgis_test', 'test_zm') + conn.dropVectorTable("qgis_test", "test_zm") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsproviderconnection_ogr_gpkg.py b/tests/src/python/test_qgsproviderconnection_ogr_gpkg.py index 0f5d4ed277fc..e34c52bf483a 100644 --- a/tests/src/python/test_qgsproviderconnection_ogr_gpkg.py +++ b/tests/src/python/test_qgsproviderconnection_ogr_gpkg.py @@ -6,9 +6,10 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '10/08/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "10/08/2019" +__copyright__ = "Copyright 2019, The QGIS Project" import shutil @@ -39,15 +40,17 @@ def GDAL_COMPUTE_VERSION(maj, min, rev): - return ((maj) * 1000000 + (min) * 10000 + (rev) * 100) + return (maj) * 1000000 + (min) * 10000 + (rev) * 100 -class TestPyQgsProviderConnectionGpkg(unittest.TestCase, TestPyQgsProviderConnectionBase): +class TestPyQgsProviderConnectionGpkg( + unittest.TestCase, TestPyQgsProviderConnectionBase +): # Provider test cases must define the string URI for the test - uri = '' + uri = "" # Provider test cases must define the provider name (e.g. "postgres" or "ogr") - providerKey = 'ogr' + providerKey = "ogr" # Provider test cases can define a slowQuery for executeSql cancellation test # Note: GDAL does not support GDALDatasetExecuteSQL interruption, so @@ -62,332 +65,432 @@ class TestPyQgsProviderConnectionGpkg(unittest.TestCase, TestPyQgsProviderConnec SELECT i FROM r WHERE i = 1; """ # Provider test cases can define a schema and table name for SQL query layers test - sqlVectorLayerSchema = '' - sqlVectorLayerTable = 'cdb_lines' - sqlVectorLayerCrs = 'EPSG:25832' + sqlVectorLayerSchema = "" + sqlVectorLayerTable = "cdb_lines" + sqlVectorLayerCrs = "EPSG:25832" @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsProviderConnectionGpkg, cls).setUpClass() + super().setUpClass() TestPyQgsProviderConnectionBase.setUpClass() - gpkg_original_path = f'{TEST_DATA_DIR}/qgis_server/test_project_wms_grouped_layers.gpkg' + gpkg_original_path = ( + f"{TEST_DATA_DIR}/qgis_server/test_project_wms_grouped_layers.gpkg" + ) cls.temp_dir = QTemporaryDir() - cls.gpkg_path = f'{cls.temp_dir.path()}/test_project_wms_grouped_layers.gpkg' + cls.gpkg_path = f"{cls.temp_dir.path()}/test_project_wms_grouped_layers.gpkg" shutil.copy(gpkg_original_path, cls.gpkg_path) - gpkg_domains_original_path = f'{TEST_DATA_DIR}/domains.gpkg' - cls.gpkg_domains_path = f'{cls.temp_dir.path()}/domains.gpkg' + gpkg_domains_original_path = f"{TEST_DATA_DIR}/domains.gpkg" + cls.gpkg_domains_path = f"{cls.temp_dir.path()}/domains.gpkg" shutil.copy(gpkg_domains_original_path, cls.gpkg_domains_path) - vl = QgsVectorLayer(f'{cls.gpkg_path}|layername=cdb_lines', 'test', 'ogr') + vl = QgsVectorLayer(f"{cls.gpkg_path}|layername=cdb_lines", "test", "ogr") assert vl.isValid() cls.uri = cls.gpkg_path def test_gpkg_connections_from_uri(self): """Create a connection from a layer uri and retrieve it""" - md = QgsProviderRegistry.instance().providerMetadata('ogr') - vl = QgsVectorLayer(f'{self.gpkg_path}|layername=cdb_lines', 'test', 'ogr') + md = QgsProviderRegistry.instance().providerMetadata("ogr") + vl = QgsVectorLayer(f"{self.gpkg_path}|layername=cdb_lines", "test", "ogr") conn = md.createConnection(vl.dataProvider().dataSourceUri(), {}) self.assertEqual(conn.uri(), self.gpkg_path) def test_gpkg_table_uri(self): """Create a connection from a layer uri and create a table URI""" - md = QgsProviderRegistry.instance().providerMetadata('ogr') + md = QgsProviderRegistry.instance().providerMetadata("ogr") conn = md.createConnection(self.uri, {}) - self.assertEqual(conn.tableUri('', 'cdb_lines'), f'{self.gpkg_path}|layername=cdb_lines') - vl = QgsVectorLayer(conn.tableUri('', 'cdb_lines'), 'lines', 'ogr') + self.assertEqual( + conn.tableUri("", "cdb_lines"), f"{self.gpkg_path}|layername=cdb_lines" + ) + vl = QgsVectorLayer(conn.tableUri("", "cdb_lines"), "lines", "ogr") self.assertTrue(vl.isValid()) # Test table(), throws if not found - conn.table('', 'osm') - conn.table('', 'cdb_lines') + conn.table("", "osm") + conn.table("", "cdb_lines") - self.assertEqual(conn.tableUri('', 'osm'), f"GPKG:{self.uri}:osm") - rl = QgsRasterLayer(conn.tableUri('', 'osm'), 'r', 'gdal') + self.assertEqual(conn.tableUri("", "osm"), f"GPKG:{self.uri}:osm") + rl = QgsRasterLayer(conn.tableUri("", "osm"), "r", "gdal") self.assertTrue(rl.isValid()) def test_gpkg_connections(self): """Create some connections and retrieve them""" - md = QgsProviderRegistry.instance().providerMetadata('ogr') + md = QgsProviderRegistry.instance().providerMetadata("ogr") conn = md.createConnection(self.uri, {}) - md.saveConnection(conn, 'qgis_test1') + md.saveConnection(conn, "qgis_test1") # Retrieve capabilities capabilities = conn.capabilities() - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.Tables)) - self.assertFalse(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.Schemas)) - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.CreateVectorTable)) - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.DropVectorTable)) - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.RenameVectorTable)) - if int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 10, 0): - self.assertFalse(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.RenameRasterTable)) + self.assertTrue( + bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.Tables) + ) + self.assertFalse( + bool( + capabilities & QgsAbstractDatabaseProviderConnection.Capability.Schemas + ) + ) + self.assertTrue( + bool( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.CreateVectorTable + ) + ) + self.assertTrue( + bool( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.DropVectorTable + ) + ) + self.assertTrue( + bool( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.RenameVectorTable + ) + ) + if int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 10, 0): + self.assertFalse( + bool( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.RenameRasterTable + ) + ) else: - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.RenameRasterTable)) + self.assertTrue( + bool( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.RenameRasterTable + ) + ) crs = QgsCoordinateReferenceSystem.fromEpsgId(3857) typ = QgsWkbTypes.Type.LineString - conn.createVectorTable('', 'myNewAspatialTable', QgsFields(), QgsWkbTypes.Type.NoGeometry, crs, True, {}) - conn.createVectorTable('', 'myNewTable', QgsFields(), typ, crs, True, {}) + conn.createVectorTable( + "", + "myNewAspatialTable", + QgsFields(), + QgsWkbTypes.Type.NoGeometry, + crs, + True, + {}, + ) + conn.createVectorTable("", "myNewTable", QgsFields(), typ, crs, True, {}) # Check filters and special cases - table_names = self._table_names(conn.tables('', QgsAbstractDatabaseProviderConnection.TableFlag.Raster)) - self.assertIn('osm', table_names) - self.assertNotIn('myNewTable', table_names) - self.assertNotIn('myNewAspatialTable', table_names) + table_names = self._table_names( + conn.tables("", QgsAbstractDatabaseProviderConnection.TableFlag.Raster) + ) + self.assertIn("osm", table_names) + self.assertNotIn("myNewTable", table_names) + self.assertNotIn("myNewAspatialTable", table_names) - table_names = self._table_names(conn.tables('', QgsAbstractDatabaseProviderConnection.TableFlag.View)) - self.assertNotIn('osm', table_names) - self.assertNotIn('myNewTable', table_names) - self.assertNotIn('myNewAspatialTable', table_names) + table_names = self._table_names( + conn.tables("", QgsAbstractDatabaseProviderConnection.TableFlag.View) + ) + self.assertNotIn("osm", table_names) + self.assertNotIn("myNewTable", table_names) + self.assertNotIn("myNewAspatialTable", table_names) - table_names = self._table_names(conn.tables('', QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial)) - self.assertNotIn('osm', table_names) - self.assertNotIn('myNewTable', table_names) - self.assertIn('myNewAspatialTable', table_names) + table_names = self._table_names( + conn.tables("", QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial) + ) + self.assertNotIn("osm", table_names) + self.assertNotIn("myNewTable", table_names) + self.assertIn("myNewAspatialTable", table_names) def test_gpkg_fields(self): """Test fields""" - md = QgsProviderRegistry.instance().providerMetadata('ogr') + md = QgsProviderRegistry.instance().providerMetadata("ogr") conn = md.createConnection(self.uri, {}) - fields = conn.fields('', 'cdb_lines') - table_info = conn.table('', 'cdb_lines') + fields = conn.fields("", "cdb_lines") + table_info = conn.table("", "cdb_lines") self.assertIn(table_info.geometryColumn(), fields.names()) self.assertIn(table_info.primaryKeyColumns()[0], fields.names()) - self.assertEqual(fields.names(), ['fid', 'id', 'typ', 'name', 'ortsrat', 'id_long', 'geom']) + self.assertEqual( + fields.names(), ["fid", "id", "typ", "name", "ortsrat", "id_long", "geom"] + ) # aspatial table - fields = conn.fields('', 'myNewAspatialTable') - table_info = conn.table('', 'myNewAspatialTable') + fields = conn.fields("", "myNewAspatialTable") + table_info = conn.table("", "myNewAspatialTable") self.assertFalse(table_info.geometryColumn()) self.assertIn(table_info.primaryKeyColumns()[0], fields.names()) - self.assertEqual(fields.names(), ['fid']) + self.assertEqual(fields.names(), ["fid"]) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 5, 0), "GDAL 3.5 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 5, 0), + "GDAL 3.5 required", + ) def test_gpkg_field_domain_names(self): """ Test retrieving field domain names """ - md = QgsProviderRegistry.instance().providerMetadata('ogr') + md = QgsProviderRegistry.instance().providerMetadata("ogr") conn = md.createConnection(self.gpkg_domains_path, {}) domain_names = conn.fieldDomainNames() - self.assertCountEqual(domain_names, ['enum_domain', - 'glob_domain', - 'range_domain_int', - 'range_domain_int64', - 'range_domain_real', - 'range_domain_real_inf']) - - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 3, 0), "GDAL 3.3 required") + self.assertCountEqual( + domain_names, + [ + "enum_domain", + "glob_domain", + "range_domain_int", + "range_domain_int64", + "range_domain_real", + "range_domain_real_inf", + ], + ) + + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 3, 0), + "GDAL 3.3 required", + ) def test_gpkg_field_domain(self): """ Test retrieving field domain """ - md = QgsProviderRegistry.instance().providerMetadata('ogr') + md = QgsProviderRegistry.instance().providerMetadata("ogr") conn = md.createConnection(self.gpkg_domains_path, {}) - domain = conn.fieldDomain('enum_domain') + domain = conn.fieldDomain("enum_domain") self.assertEqual(domain.type(), Qgis.FieldDomainType.Coded) - self.assertEqual(domain.name(), 'enum_domain') + self.assertEqual(domain.name(), "enum_domain") - domain = conn.fieldDomain('range_domain_int') + domain = conn.fieldDomain("range_domain_int") self.assertEqual(domain.type(), Qgis.FieldDomainType.Range) - self.assertEqual(domain.name(), 'range_domain_int') + self.assertEqual(domain.name(), "range_domain_int") self.assertEqual(domain.minimum(), 1) self.assertEqual(domain.maximum(), 2) - domain = conn.fieldDomain('glob_domain') + domain = conn.fieldDomain("glob_domain") self.assertEqual(domain.type(), Qgis.FieldDomainType.Glob) - self.assertEqual(domain.name(), 'glob_domain') - self.assertEqual(domain.glob(), '*') + self.assertEqual(domain.name(), "glob_domain") + self.assertEqual(domain.glob(), "*") - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 3, 0), "GDAL 3.3 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 3, 0), + "GDAL 3.3 required", + ) def test_gpkg_field_domain_create(self): """ Test creating field domains """ - gpkg_domains_original_path = f'{TEST_DATA_DIR}/domains.gpkg' - temp_domains_path = f'{self.temp_dir.path()}/domains_create.gpkg' + gpkg_domains_original_path = f"{TEST_DATA_DIR}/domains.gpkg" + temp_domains_path = f"{self.temp_dir.path()}/domains_create.gpkg" shutil.copy(gpkg_domains_original_path, temp_domains_path) - md = QgsProviderRegistry.instance().providerMetadata('ogr') + md = QgsProviderRegistry.instance().providerMetadata("ogr") conn = md.createConnection(temp_domains_path, {}) - domain = QgsRangeFieldDomain('my new domain', 'my new domain desc', QVariant.Int, 5, True, 15, True) - conn.addFieldDomain(domain, '') + domain = QgsRangeFieldDomain( + "my new domain", "my new domain desc", QVariant.Int, 5, True, 15, True + ) + conn.addFieldDomain(domain, "") # try retrieving result del conn conn = md.createConnection(temp_domains_path, {}) - res = conn.fieldDomain('my new domain') + res = conn.fieldDomain("my new domain") self.assertEqual(res.type(), Qgis.FieldDomainType.Range) - self.assertEqual(res.name(), 'my new domain') + self.assertEqual(res.name(), "my new domain") self.assertEqual(res.minimum(), 5) self.assertEqual(res.maximum(), 15) # try adding another with a duplicate name, should fail with self.assertRaises(QgsProviderConnectionException) as e: - conn.addFieldDomain(domain, '') - self.assertEqual(str(e.exception), 'Could not create field domain: A domain of identical name already exists') + conn.addFieldDomain(domain, "") + self.assertEqual( + str(e.exception), + "Could not create field domain: A domain of identical name already exists", + ) - domain = QgsGlobFieldDomain('my new glob domain', 'my new glob desc', QVariant.String, '*aaabc*') - conn.addFieldDomain(domain, '') + domain = QgsGlobFieldDomain( + "my new glob domain", "my new glob desc", QVariant.String, "*aaabc*" + ) + conn.addFieldDomain(domain, "") # try retrieving result del conn conn = md.createConnection(temp_domains_path, {}) - res = conn.fieldDomain('my new glob domain') + res = conn.fieldDomain("my new glob domain") self.assertEqual(res.type(), Qgis.FieldDomainType.Glob) - self.assertEqual(res.name(), 'my new glob domain') - self.assertEqual(res.description(), 'my new glob desc') - self.assertEqual(res.glob(), '*aaabc*') + self.assertEqual(res.name(), "my new glob domain") + self.assertEqual(res.description(), "my new glob desc") + self.assertEqual(res.glob(), "*aaabc*") # coded value - domain = QgsCodedFieldDomain('my new coded domain', 'my new coded desc', QVariant.String, [QgsCodedValue('a', 'aa'), QgsCodedValue('b', 'bb')]) - conn.addFieldDomain(domain, '') + domain = QgsCodedFieldDomain( + "my new coded domain", + "my new coded desc", + QVariant.String, + [QgsCodedValue("a", "aa"), QgsCodedValue("b", "bb")], + ) + conn.addFieldDomain(domain, "") # try retrieving result del conn conn = md.createConnection(temp_domains_path, {}) - res = conn.fieldDomain('my new coded domain') + res = conn.fieldDomain("my new coded domain") self.assertEqual(res.type(), Qgis.FieldDomainType.Coded) - self.assertEqual(res.name(), 'my new coded domain') - self.assertEqual(res.description(), 'my new coded desc') - self.assertCountEqual(res.values(), [QgsCodedValue('a', 'aa'), QgsCodedValue('b', 'bb')]) + self.assertEqual(res.name(), "my new coded domain") + self.assertEqual(res.description(), "my new coded desc") + self.assertCountEqual( + res.values(), [QgsCodedValue("a", "aa"), QgsCodedValue("b", "bb")] + ) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 3, 0), "GDAL 3.3 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 3, 0), + "GDAL 3.3 required", + ) def test_gpkg_field_domain_set(self): """ Test setting field domains """ - gpkg_domains_original_path = f'{TEST_DATA_DIR}/bug_17878.gpkg' - temp_domains_path = f'{self.temp_dir.path()}/domain_set.gpkg' + gpkg_domains_original_path = f"{TEST_DATA_DIR}/bug_17878.gpkg" + temp_domains_path = f"{self.temp_dir.path()}/domain_set.gpkg" shutil.copy(gpkg_domains_original_path, temp_domains_path) - md = QgsProviderRegistry.instance().providerMetadata('ogr') + md = QgsProviderRegistry.instance().providerMetadata("ogr") conn = md.createConnection(temp_domains_path, {}) - domain = QgsRangeFieldDomain('my new domain', 'my new domain desc', QVariant.Int, 5, True, 15, True) - conn.addFieldDomain(domain, '') + domain = QgsRangeFieldDomain( + "my new domain", "my new domain desc", QVariant.Int, 5, True, 15, True + ) + conn.addFieldDomain(domain, "") # field doesn't exist with self.assertRaises(QgsProviderConnectionException): - conn.setFieldDomainName('xxx', '', 'bug_17878', 'my new domain') + conn.setFieldDomainName("xxx", "", "bug_17878", "my new domain") - conn.setFieldDomainName('int_field', '', 'bug_17878', 'my new domain') + conn.setFieldDomainName("int_field", "", "bug_17878", "my new domain") # try retrieving result del conn conn = md.createConnection(temp_domains_path, {}) - fields = conn.fields('', 'bug_17878') - field = fields.field('int_field') - self.assertEqual(field.constraints().domainName(), 'my new domain') + fields = conn.fields("", "bug_17878") + field = fields.field("int_field") + self.assertEqual(field.constraints().domainName(), "my new domain") def test_create_vector_layer(self): """Test query layers""" - md = QgsProviderRegistry.instance().providerMetadata('ogr') + md = QgsProviderRegistry.instance().providerMetadata("ogr") conn = md.createConnection(self.uri, {}) options = QgsAbstractDatabaseProviderConnection.SqlVectorLayerOptions() - options.sql = 'SELECT fid, name, geom FROM cdb_lines WHERE name LIKE \'S%\' LIMIT 2' + options.sql = ( + "SELECT fid, name, geom FROM cdb_lines WHERE name LIKE 'S%' LIMIT 2" + ) vl = conn.createSqlVectorLayer(options) self.assertTrue(vl.isValid()) self.assertEqual(vl.geometryType(), QgsWkbTypes.GeometryType.PolygonGeometry) features = [f for f in vl.getFeatures()] self.assertEqual(len(features), 2) - self.assertEqual(features[0].attributes(), [8, 'Sülfeld']) + self.assertEqual(features[0].attributes(), [8, "Sülfeld"]) def test_execute_sql_pk_geoms(self): """OGR hides fid and geom from attributes, check if we can still get them""" - md = QgsProviderRegistry.instance().providerMetadata('ogr') + md = QgsProviderRegistry.instance().providerMetadata("ogr") conn = md.createConnection(self.uri, {}) # Check errors with self.assertRaises(QgsProviderConnectionException): - sql = 'SELECT not_exists, name, geom FROM cdb_lines WHERE name LIKE \'S%\' LIMIT 2' + sql = "SELECT not_exists, name, geom FROM cdb_lines WHERE name LIKE 'S%' LIMIT 2" results = conn.executeSql(sql) - sql = 'SELECT fid, name, geom FROM cdb_lines WHERE name LIKE \'S%\' LIMIT 2' + sql = "SELECT fid, name, geom FROM cdb_lines WHERE name LIKE 'S%' LIMIT 2" results = conn.executeSql(sql) - self.assertEqual(results[0][:2], [8, 'Sülfeld']) - self.assertEqual(results[1][:2], [16, 'Steimker Berg']) - self.assertEqual(results[0][2][:20], 'Polygon ((612694.674') - self.assertEqual(results[1][2][:20], 'Polygon ((622042.427') + self.assertEqual(results[0][:2], [8, "Sülfeld"]) + self.assertEqual(results[1][:2], [16, "Steimker Berg"]) + self.assertEqual(results[0][2][:20], "Polygon ((612694.674") + self.assertEqual(results[1][2][:20], "Polygon ((622042.427") - sql = 'SELECT name, st_astext(geom) FROM cdb_lines WHERE name LIKE \'S%\' LIMIT 2' + sql = "SELECT name, st_astext(geom) FROM cdb_lines WHERE name LIKE 'S%' LIMIT 2" results = conn.executeSql(sql) - self.assertEqual(results[0], ['Sülfeld', - 'POLYGON((612694.674 5807839.658, 612668.715 5808176.815, 612547.354 5808414.452, 612509.527 5808425.73, 612522.932 5808473.02, 612407.901 5808519.082, 612505.836 5808632.763, 612463.449 5808781.115, 612433.57 5808819.061, 612422.685 5808980.281999, 612473.423 5808995.424999, 612333.856 5809647.731, 612307.316 5809781.446, 612267.099 5809852.803, 612308.221 5810040.995, 613920.397 5811079.478, 613947.16 5811129.3, 614022.726 5811154.456, 614058.436 5811260.36, 614194.037 5811331.972, 614307.176 5811360.06, 614343.842 5811323.238, 614443.449 5811363.03, 614526.199 5811059.031, 614417.83 5811057.603, 614787.296 5809648.422, 614772.062 5809583.246, 614981.93 5809245.35, 614811.885 5809138.271, 615063.452 5809100.954, 615215.476 5809029.413, 615469.441 5808883.282, 615569.846 5808829.522, 615577.239 5808806.242, 615392.964 5808736.873, 615306.34 5808662.171, 615335.445 5808290.588, 615312.192 5808290.397, 614890.582 5808077.956, 615018.854 5807799.895, 614837.326 5807688.363, 614435.698 5807646.847, 614126.351 5807661.841, 613555.813 5807814.801, 612826.66 5807964.828, 612830.113 5807856.315, 612694.674 5807839.658))']) + self.assertEqual( + results[0], + [ + "Sülfeld", + "POLYGON((612694.674 5807839.658, 612668.715 5808176.815, 612547.354 5808414.452, 612509.527 5808425.73, 612522.932 5808473.02, 612407.901 5808519.082, 612505.836 5808632.763, 612463.449 5808781.115, 612433.57 5808819.061, 612422.685 5808980.281999, 612473.423 5808995.424999, 612333.856 5809647.731, 612307.316 5809781.446, 612267.099 5809852.803, 612308.221 5810040.995, 613920.397 5811079.478, 613947.16 5811129.3, 614022.726 5811154.456, 614058.436 5811260.36, 614194.037 5811331.972, 614307.176 5811360.06, 614343.842 5811323.238, 614443.449 5811363.03, 614526.199 5811059.031, 614417.83 5811057.603, 614787.296 5809648.422, 614772.062 5809583.246, 614981.93 5809245.35, 614811.885 5809138.271, 615063.452 5809100.954, 615215.476 5809029.413, 615469.441 5808883.282, 615569.846 5808829.522, 615577.239 5808806.242, 615392.964 5808736.873, 615306.34 5808662.171, 615335.445 5808290.588, 615312.192 5808290.397, 614890.582 5808077.956, 615018.854 5807799.895, 614837.326 5807688.363, 614435.698 5807646.847, 614126.351 5807661.841, 613555.813 5807814.801, 612826.66 5807964.828, 612830.113 5807856.315, 612694.674 5807839.658))", + ], + ) def test_rename_field(self): - gpkg_domains_original_path = f'{TEST_DATA_DIR}/bug_17878.gpkg' - temp_domains_path = f'{self.temp_dir.path()}/rename_field.gpkg' + gpkg_domains_original_path = f"{TEST_DATA_DIR}/bug_17878.gpkg" + temp_domains_path = f"{self.temp_dir.path()}/rename_field.gpkg" shutil.copy(gpkg_domains_original_path, temp_domains_path) - md = QgsProviderRegistry.instance().providerMetadata('ogr') + md = QgsProviderRegistry.instance().providerMetadata("ogr") conn = md.createConnection(self.uri, {}) - fields = conn.fields('', 'cdb_lines') - self.assertEqual(fields.names(), ['fid', 'id', 'typ', 'name', 'ortsrat', 'id_long', 'geom']) + fields = conn.fields("", "cdb_lines") + self.assertEqual( + fields.names(), ["fid", "id", "typ", "name", "ortsrat", "id_long", "geom"] + ) # invalid table name with self.assertRaises(QgsProviderConnectionException): - conn.renameField('schema', 'asdasd', 'asd', 'xyz') + conn.renameField("schema", "asdasd", "asd", "xyz") # invalid existing field name with self.assertRaises(QgsProviderConnectionException): - conn.renameField('schema', 'cdb_lines', 'asd', 'xyz') + conn.renameField("schema", "cdb_lines", "asd", "xyz") # try to rename over existing field with self.assertRaises(QgsProviderConnectionException): - conn.renameField('schema', 'cdb_lines', 'name', 'ortsrat') + conn.renameField("schema", "cdb_lines", "name", "ortsrat") # try to rename geometry field with self.assertRaises(QgsProviderConnectionException): - conn.renameField('schema', 'cdb_lines', 'geom', 'the_geom') + conn.renameField("schema", "cdb_lines", "geom", "the_geom") # good rename - conn.renameField('schema', 'cdb_lines', 'name', 'name2') - fields = conn.fields('', 'cdb_lines') - self.assertEqual(fields.names(), ['fid', 'id', 'typ', 'name2', 'ortsrat', 'id_long', 'geom']) + conn.renameField("schema", "cdb_lines", "name", "name2") + fields = conn.fields("", "cdb_lines") + self.assertEqual( + fields.names(), ["fid", "id", "typ", "name2", "ortsrat", "id_long", "geom"] + ) # make sure schema is ignored - conn.renameField('', 'cdb_lines', 'name2', 'name3') - fields = conn.fields('', 'cdb_lines') - self.assertEqual(fields.names(), ['fid', 'id', 'typ', 'name3', 'ortsrat', 'id_long', 'geom']) + conn.renameField("", "cdb_lines", "name2", "name3") + fields = conn.fields("", "cdb_lines") + self.assertEqual( + fields.names(), ["fid", "id", "typ", "name3", "ortsrat", "id_long", "geom"] + ) def test_searchLayerMetadata_buggy_extent(self): - """ Test fix for https://github.com/qgis/QGIS/issues/56203 """ + """Test fix for https://github.com/qgis/QGIS/issues/56203""" - md = QgsProviderRegistry.instance().providerMetadata('ogr') - conn = md.createConnection(f'{TEST_DATA_DIR}/provider/bug_56203.gpkg', {}) + md = QgsProviderRegistry.instance().providerMetadata("ogr") + conn = md.createConnection(f"{TEST_DATA_DIR}/provider/bug_56203.gpkg", {}) res = conn.searchLayerMetadata(QgsMetadataSearchContext()) self.assertTrue(res[0].geographicExtent().isEmpty()) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 10, 0), "GDAL 3.10 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 10, 0), + "GDAL 3.10 required", + ) def test_rename_raster_layer(self): """Test renaming a raster layer""" md = QgsProviderRegistry.instance().providerMetadata(self.providerKey) conn = md.createConnection(self.uri, {}) - tables = conn.tables('', QgsAbstractDatabaseProviderConnection.TableFlag.Raster) + tables = conn.tables("", QgsAbstractDatabaseProviderConnection.TableFlag.Raster) osm = tables[0] - self.assertEqual(osm.tableName(), 'osm') - conn.renameRasterTable('', 'osm', 'osm_new') - tables = conn.tables('', QgsAbstractDatabaseProviderConnection.TableFlag.Raster) + self.assertEqual(osm.tableName(), "osm") + conn.renameRasterTable("", "osm", "osm_new") + tables = conn.tables("", QgsAbstractDatabaseProviderConnection.TableFlag.Raster) osm = tables[0] - self.assertEqual(osm.tableName(), 'osm_new') + self.assertEqual(osm.tableName(), "osm_new") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsproviderconnection_oracle.py b/tests/src/python/test_qgsproviderconnection_oracle.py index d018e4a6d51e..ab3f7aef9ec8 100644 --- a/tests/src/python/test_qgsproviderconnection_oracle.py +++ b/tests/src/python/test_qgsproviderconnection_oracle.py @@ -6,9 +6,10 @@ (at your option) any later version. """ -__author__ = 'Julien Cabieces' -__date__ = '28/12/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Julien Cabieces" +__date__ = "28/12/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import os @@ -24,72 +25,80 @@ from test_qgsproviderconnection_base import TestPyQgsProviderConnectionBase -class TestPyQgsProviderConnectionOracle(unittest.TestCase, TestPyQgsProviderConnectionBase): +class TestPyQgsProviderConnectionOracle( + unittest.TestCase, TestPyQgsProviderConnectionBase +): # Provider test cases must define the string URI for the test - uri = '' + uri = "" # Provider test cases must define the provider name (e.g. "postgres" or "ogr") - providerKey = 'oracle' + providerKey = "oracle" # there is no service for oracle provider test so we need to save user and password # to keep them when storing/loading connections in parent class _test_save_load method - configuration = {"saveUsername": True, "savePassword": True, "onlyExistingTypes": True} + configuration = { + "saveUsername": True, + "savePassword": True, + "onlyExistingTypes": True, + } - defaultSchema = 'QGIS' + defaultSchema = "QGIS" # need to override this because tables with geometries need to be uppercase - myNewTable = 'MYNEWTABLE' - myVeryNewTable = 'MYVERYNEWTABLE' - myUtf8Table = 'MYUTF8\U0001F604TABLE' - geometryColumnName = 'GEOM' + myNewTable = "MYNEWTABLE" + myVeryNewTable = "MYVERYNEWTABLE" + myUtf8Table = "MYUTF8\U0001F604TABLE" + geometryColumnName = "GEOM" # Provider test cases can define a schema and table name for SQL query layers test - sqlVectorLayerSchema = 'QGIS' - sqlVectorLayerTable = 'SOME_DATA' - sqlVectorLayerCrs = 'EPSG:4326' + sqlVectorLayerSchema = "QGIS" + sqlVectorLayerTable = "SOME_DATA" + sqlVectorLayerCrs = "EPSG:4326" def execSQLCommand(self, sql, ignore_errors=False): self.assertTrue(self.conn) query = QSqlQuery(self.conn) res = query.exec(sql) if not ignore_errors: - self.assertTrue(res, sql + ': ' + query.lastError().text()) + self.assertTrue(res, sql + ": " + query.lastError().text()) query.finish() @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsProviderConnectionOracle, cls).setUpClass() + super().setUpClass() TestPyQgsProviderConnectionBase.setUpClass() # These are the connection details for the Docker Oracle instance running on Travis cls.dbconn = "host=localhost/XEPDB1 port=1521 user='QGIS' password='qgis'" - if 'QGIS_ORACLETEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_ORACLETEST_DB'] + if "QGIS_ORACLETEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_ORACLETEST_DB"] cls.uri = cls.dbconn - cls.conn = QSqlDatabase.addDatabase('QOCISPATIAL', "oracletest") - cls.conn.setDatabaseName('localhost/XEPDB1') - if 'QGIS_ORACLETEST_DBNAME' in os.environ: - cls.conn.setDatabaseName(os.environ['QGIS_ORACLETEST_DBNAME']) - cls.conn.setUserName('QGIS') - cls.conn.setPassword('qgis') + cls.conn = QSqlDatabase.addDatabase("QOCISPATIAL", "oracletest") + cls.conn.setDatabaseName("localhost/XEPDB1") + if "QGIS_ORACLETEST_DBNAME" in os.environ: + cls.conn.setDatabaseName(os.environ["QGIS_ORACLETEST_DBNAME"]) + cls.conn.setUserName("QGIS") + cls.conn.setPassword("qgis") # Start clean - md = QgsProviderRegistry.instance().providerMetadata('oracle') + md = QgsProviderRegistry.instance().providerMetadata("oracle") conn = md.createConnection(cls.dbconn, {}) for table_name in (cls.myNewTable, cls.myVeryNewTable): try: - conn.dropVectorTable('QGIS', table_name) + conn.dropVectorTable("QGIS", table_name) except QgsProviderConnectionException: pass try: - conn.executeSql(f"DELETE FROM user_sdo_geom_metadata WHERE TABLE_NAME = '{table_name}'") + conn.executeSql( + f"DELETE FROM user_sdo_geom_metadata WHERE TABLE_NAME = '{table_name}'" + ) except QgsProviderConnectionException: pass @@ -97,107 +106,197 @@ def setUpClass(cls): def test_tables_with_options(self): - md = QgsProviderRegistry.instance().providerMetadata('oracle') + md = QgsProviderRegistry.instance().providerMetadata("oracle") - def get_tables(schema, configuration, flags=QgsAbstractDatabaseProviderConnection.TableFlags()): + def get_tables( + schema, + configuration, + flags=QgsAbstractDatabaseProviderConnection.TableFlags(), + ): conn = md.createConnection(self.uri, configuration) tables = conn.tables(schema, flags) - return sorted([table.tableName() for table in tables if table.tableName() in [ - 'DATE_TIMES', 'GENERATED_COLUMNS', 'LINE_DATA', 'OTHER_TABLE', 'POINT_DATA', 'POINT_DATA_IDENTITY', 'POLY_DATA', 'SOME_DATA', 'SOME_POLY_DATA']]) + return sorted( + [ + table.tableName() + for table in tables + if table.tableName() + in [ + "DATE_TIMES", + "GENERATED_COLUMNS", + "LINE_DATA", + "OTHER_TABLE", + "POINT_DATA", + "POINT_DATA_IDENTITY", + "POLY_DATA", + "SOME_DATA", + "SOME_POLY_DATA", + ] + ] + ) # all tables - self.assertEqual(get_tables('QGIS', {}), - ['DATE_TIMES', 'GENERATED_COLUMNS', 'LINE_DATA', 'POINT_DATA', 'POINT_DATA_IDENTITY', 'POLY_DATA', 'SOME_DATA', 'SOME_POLY_DATA']) + self.assertEqual( + get_tables("QGIS", {}), + [ + "DATE_TIMES", + "GENERATED_COLUMNS", + "LINE_DATA", + "POINT_DATA", + "POINT_DATA_IDENTITY", + "POLY_DATA", + "SOME_DATA", + "SOME_POLY_DATA", + ], + ) # only non-spatial tables - self.assertEqual(get_tables('QGIS', {}, QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial), - ['DATE_TIMES', 'GENERATED_COLUMNS']) + self.assertEqual( + get_tables( + "QGIS", {}, QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial + ), + ["DATE_TIMES", "GENERATED_COLUMNS"], + ) # only vector tables - self.assertEqual(get_tables('QGIS', {}, QgsAbstractDatabaseProviderConnection.TableFlag.Vector), - ['LINE_DATA', 'POINT_DATA', 'POINT_DATA_IDENTITY', 'POLY_DATA', 'SOME_DATA', 'SOME_POLY_DATA']) + self.assertEqual( + get_tables( + "QGIS", {}, QgsAbstractDatabaseProviderConnection.TableFlag.Vector + ), + [ + "LINE_DATA", + "POINT_DATA", + "POINT_DATA_IDENTITY", + "POLY_DATA", + "SOME_DATA", + "SOME_POLY_DATA", + ], + ) # only table existing in sdo_geom_metadata table - self.assertEqual(get_tables('QGIS', {"geometryColumnsOnly": True}, QgsAbstractDatabaseProviderConnection.TableFlag.Vector), - ['SOME_DATA', 'SOME_POLY_DATA']) - - self.execSQLCommand('DROP TABLE OTHER_USER.OTHER_TABLE', ignore_errors=True) - self.execSQLCommand('DROP USER OTHER_USER CASCADE', ignore_errors=True) - self.execSQLCommand('CREATE USER OTHER_USER') - self.execSQLCommand('GRANT ALL PRIVILEGES TO OTHER_USER') - self.execSQLCommand('CREATE TABLE OTHER_USER.OTHER_TABLE ( "pk" INTEGER PRIMARY KEY, GEOM SDO_GEOMETRY)') + self.assertEqual( + get_tables( + "QGIS", + {"geometryColumnsOnly": True}, + QgsAbstractDatabaseProviderConnection.TableFlag.Vector, + ), + ["SOME_DATA", "SOME_POLY_DATA"], + ) + + self.execSQLCommand("DROP TABLE OTHER_USER.OTHER_TABLE", ignore_errors=True) + self.execSQLCommand("DROP USER OTHER_USER CASCADE", ignore_errors=True) + self.execSQLCommand("CREATE USER OTHER_USER") + self.execSQLCommand("GRANT ALL PRIVILEGES TO OTHER_USER") + self.execSQLCommand( + 'CREATE TABLE OTHER_USER.OTHER_TABLE ( "pk" INTEGER PRIMARY KEY, GEOM SDO_GEOMETRY)' + ) # if a schema is specified, schema (i.e. user) tables are returned, whatever userTablesOnly value - self.assertEqual(get_tables('OTHER_USER', {"userTablesOnly": True}), - ['OTHER_TABLE']) + self.assertEqual( + get_tables("OTHER_USER", {"userTablesOnly": True}), ["OTHER_TABLE"] + ) - self.assertEqual(get_tables('OTHER_USER', {"userTablesOnly": False}), - ['OTHER_TABLE']) + self.assertEqual( + get_tables("OTHER_USER", {"userTablesOnly": False}), ["OTHER_TABLE"] + ) # no schema is specified, all user tables (vector ones in this case) are returned - self.assertEqual(get_tables('', {"userTablesOnly": True}, QgsAbstractDatabaseProviderConnection.TableFlag.Vector), - ['LINE_DATA', 'POINT_DATA', 'POINT_DATA_IDENTITY', 'POLY_DATA', 'SOME_DATA', 'SOME_POLY_DATA']) + self.assertEqual( + get_tables( + "", + {"userTablesOnly": True}, + QgsAbstractDatabaseProviderConnection.TableFlag.Vector, + ), + [ + "LINE_DATA", + "POINT_DATA", + "POINT_DATA_IDENTITY", + "POLY_DATA", + "SOME_DATA", + "SOME_POLY_DATA", + ], + ) # no schema is specified, all tables (vector ones in this case) tables are returned - self.assertEqual(get_tables('', {"userTablesOnly": False}, QgsAbstractDatabaseProviderConnection.TableFlag.Vector), - ['LINE_DATA', 'OTHER_TABLE', 'POINT_DATA', 'POINT_DATA_IDENTITY', 'POLY_DATA', 'SOME_DATA', 'SOME_POLY_DATA']) + self.assertEqual( + get_tables( + "", + {"userTablesOnly": False}, + QgsAbstractDatabaseProviderConnection.TableFlag.Vector, + ), + [ + "LINE_DATA", + "OTHER_TABLE", + "POINT_DATA", + "POINT_DATA_IDENTITY", + "POLY_DATA", + "SOME_DATA", + "SOME_POLY_DATA", + ], + ) def test_configuration(self): """Test storage and retrieval for configuration parameters""" - uri = ("authcfg='test_cfg' dbname='qgis_test' username='QGIS' password='qgis' dbworkspace='workspace' " - "estimatedMetadata='true' host='localhost' port='1521' dboptions='test_opts' ") + uri = ( + "authcfg='test_cfg' dbname='qgis_test' username='QGIS' password='qgis' dbworkspace='workspace' " + "estimatedMetadata='true' host='localhost' port='1521' dboptions='test_opts' " + ) - md = QgsProviderRegistry.instance().providerMetadata('oracle') + md = QgsProviderRegistry.instance().providerMetadata("oracle") conn = md.createConnection(uri, {"saveUsername": True, "savePassword": True}) ds_uri = QgsDataSourceUri(conn.uri()) - self.assertEqual(ds_uri.username(), 'QGIS') - self.assertEqual(ds_uri.host(), 'localhost') - self.assertEqual(ds_uri.port(), '1521') - self.assertEqual(ds_uri.database(), 'qgis_test') + self.assertEqual(ds_uri.username(), "QGIS") + self.assertEqual(ds_uri.host(), "localhost") + self.assertEqual(ds_uri.port(), "1521") + self.assertEqual(ds_uri.database(), "qgis_test") self.assertTrue(ds_uri.useEstimatedMetadata()) - self.assertEqual(ds_uri.password(), 'qgis') - self.assertEqual(ds_uri.param('dboptions'), 'test_opts') - self.assertEqual(ds_uri.param('dbworkspace'), 'workspace') + self.assertEqual(ds_uri.password(), "qgis") + self.assertEqual(ds_uri.param("dboptions"), "test_opts") + self.assertEqual(ds_uri.param("dbworkspace"), "workspace") - conn.store('myconf') - conn = md.findConnection('myconf', False) + conn.store("myconf") + conn = md.findConnection("myconf", False) ds_uri = QgsDataSourceUri(conn.uri()) - self.assertEqual(ds_uri.username(), 'QGIS') - self.assertEqual(ds_uri.host(), 'localhost') - self.assertEqual(ds_uri.port(), '1521') - self.assertEqual(ds_uri.database(), 'qgis_test') + self.assertEqual(ds_uri.username(), "QGIS") + self.assertEqual(ds_uri.host(), "localhost") + self.assertEqual(ds_uri.port(), "1521") + self.assertEqual(ds_uri.database(), "qgis_test") self.assertTrue(ds_uri.useEstimatedMetadata()) - self.assertEqual(ds_uri.password(), 'qgis') - self.assertEqual(ds_uri.param('dboptions'), 'test_opts') - self.assertEqual(ds_uri.param('dbworkspace'), 'workspace') - conn.remove('myconf') + self.assertEqual(ds_uri.password(), "qgis") + self.assertEqual(ds_uri.param("dboptions"), "test_opts") + self.assertEqual(ds_uri.param("dbworkspace"), "workspace") + conn.remove("myconf") def test_pkcols(self): """Test retrieval of primary columns""" - self.execSQLCommand("""CREATE OR REPLACE VIEW "QGIS"."SOME_DATA_VIEW" AS SELECT * FROM "QGIS"."SOME_DATA" """) + self.execSQLCommand( + """CREATE OR REPLACE VIEW "QGIS"."SOME_DATA_VIEW" AS SELECT * FROM "QGIS"."SOME_DATA" """ + ) - md = QgsProviderRegistry.instance().providerMetadata('oracle') + md = QgsProviderRegistry.instance().providerMetadata("oracle") conn = md.createConnection(self.uri, {}) - tables = conn.tables('QGIS') + tables = conn.tables("QGIS") tables_dict = {table.tableName(): table.primaryKeyColumns() for table in tables} - self.assertEqual(sorted(tables_dict['SOME_DATA_VIEW']), ['GEOM', 'cnt', 'date', 'dt', 'name', 'name2', 'num_char', 'pk', 'time']) - self.assertEqual(sorted(tables_dict['SOME_DATA']), ['pk']) - self.assertEqual(sorted(tables_dict['POINT_DATA_IDENTITY']), ['pk']) + self.assertEqual( + sorted(tables_dict["SOME_DATA_VIEW"]), + ["GEOM", "cnt", "date", "dt", "name", "name2", "num_char", "pk", "time"], + ) + self.assertEqual(sorted(tables_dict["SOME_DATA"]), ["pk"]) + self.assertEqual(sorted(tables_dict["POINT_DATA_IDENTITY"]), ["pk"]) def test_schemas(self): """Test schemas retrieval""" # may be added by previous test - self.execSQLCommand('DROP USER OTHER_USER CASCADE', ignore_errors=True) + self.execSQLCommand("DROP USER OTHER_USER CASCADE", ignore_errors=True) - md = QgsProviderRegistry.instance().providerMetadata('oracle') + md = QgsProviderRegistry.instance().providerMetadata("oracle") conn = md.createConnection(self.uri, {}) - self.assertEqual(conn.schemas(), ['QGIS']) + self.assertEqual(conn.schemas(), ["QGIS"]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsproviderconnection_postgres.py b/tests/src/python/test_qgsproviderconnection_postgres.py index 47a999bbf8a5..0ddb6b2ef2a5 100644 --- a/tests/src/python/test_qgsproviderconnection_postgres.py +++ b/tests/src/python/test_qgsproviderconnection_postgres.py @@ -6,9 +6,10 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '10/08/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "10/08/2019" +__copyright__ = "Copyright 2019, The QGIS Project" import os @@ -29,67 +30,94 @@ from test_qgsproviderconnection_base import TestPyQgsProviderConnectionBase -class TestPyQgsProviderConnectionPostgres(unittest.TestCase, TestPyQgsProviderConnectionBase): +class TestPyQgsProviderConnectionPostgres( + unittest.TestCase, TestPyQgsProviderConnectionBase +): # Provider test cases must define the string URI for the test - uri = '' + uri = "" # Provider test cases must define the provider name (e.g. "postgres" or "ogr") - providerKey = 'postgres' + providerKey = "postgres" # Provider test cases can define a slowQuery for executeSql cancellation test slowQuery = "select pg_sleep(30)" # Provider test cases can define a schema and table name for SQL query layers test - sqlVectorLayerSchema = 'qgis_test' - sqlVectorLayerTable = 'someData' - sqlVectorLayerCrs = 'EPSG:4326' + sqlVectorLayerSchema = "qgis_test" + sqlVectorLayerTable = "someData" + sqlVectorLayerCrs = "EPSG:4326" @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsProviderConnectionPostgres, cls).setUpClass() + super().setUpClass() TestPyQgsProviderConnectionBase.setUpClass() cls.postgres_conn = "service='qgis_test'" - if 'QGIS_PGTEST_DB' in os.environ: - cls.postgres_conn = os.environ['QGIS_PGTEST_DB'] + if "QGIS_PGTEST_DB" in os.environ: + cls.postgres_conn = os.environ["QGIS_PGTEST_DB"] # Create test layers - vl = QgsVectorLayer(cls.postgres_conn + ' sslmode=disable key=\'"key1","key2"\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=', 'test', 'postgres') + vl = QgsVectorLayer( + cls.postgres_conn + + ' sslmode=disable key=\'"key1","key2"\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=', + "test", + "postgres", + ) assert vl.isValid() - cls.uri = cls.postgres_conn + ' sslmode=disable' + cls.uri = cls.postgres_conn + " sslmode=disable" def test_postgis_connections_from_uri(self): """Create a connection from a layer uri and retrieve it""" - md = QgsProviderRegistry.instance().providerMetadata('postgres') - vl = QgsVectorLayer(self.postgres_conn + ' sslmode=disable key=\'"key1","key2"\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=', 'test', 'postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") + vl = QgsVectorLayer( + self.postgres_conn + + ' sslmode=disable key=\'"key1","key2"\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=', + "test", + "postgres", + ) conn = md.createConnection(vl.dataProvider().uri().uri(), {}) self.assertEqual(conn.uri(), self.uri) # Test table(), throws if not found - table_info = conn.table('qgis_test', 'someData') - table_info = conn.table('qgis_test', 'Raster1') + table_info = conn.table("qgis_test", "someData") + table_info = conn.table("qgis_test", "Raster1") # Test raster - self.assertEqual(conn.tableUri('qgis_test', 'Raster1'), - f'{self.uri} table="qgis_test"."Raster1"') + self.assertEqual( + conn.tableUri("qgis_test", "Raster1"), + f'{self.uri} table="qgis_test"."Raster1"', + ) - rl = QgsRasterLayer(conn.tableUri('qgis_test', 'Raster1'), 'r1', 'postgresraster') + rl = QgsRasterLayer( + conn.tableUri("qgis_test", "Raster1"), "r1", "postgresraster" + ) self.assertTrue(rl.isValid()) def test_sslmode_store(self): """Test that sslmode is stored as a string in the settings""" - md = QgsProviderRegistry.instance().providerMetadata('postgres') - conn = md.createConnection('database=\'mydb\' username=\'myuser\' password=\'mypasswd\' sslmode=verify-ca', {}) - conn.store('my_sslmode_test') + md = QgsProviderRegistry.instance().providerMetadata("postgres") + conn = md.createConnection( + "database='mydb' username='myuser' password='mypasswd' sslmode=verify-ca", + {}, + ) + conn.store("my_sslmode_test") settings = QgsSettings() - settings.beginGroup('/PostgreSQL/connections/my_sslmode_test') - self.assertEqual(settings.value("sslmode"), 'SslVerifyCa') - self.assertEqual(settings.enumValue("sslmode", QgsDataSourceUri.SslMode.SslPrefer), QgsDataSourceUri.SslMode.SslVerifyCa) + settings.beginGroup("/PostgreSQL/connections/my_sslmode_test") + self.assertEqual(settings.value("sslmode"), "SslVerifyCa") + self.assertEqual( + settings.enumValue("sslmode", QgsDataSourceUri.SslMode.SslPrefer), + QgsDataSourceUri.SslMode.SslVerifyCa, + ) def test_postgis_geometry_filter(self): """Make sure the postgres provider only returns one matching geometry record and no polygons etc.""" - vl = QgsVectorLayer(self.postgres_conn + ' srid=4326 type=POINT table="qgis_test"."geometries_table" (geom) sql=', 'test', 'postgres') + vl = QgsVectorLayer( + self.postgres_conn + + ' srid=4326 type=POINT table="qgis_test"."geometries_table" (geom) sql=', + "test", + "postgres", + ) ids = [f.id() for f in vl.getFeatures()] self.assertEqual(ids, [2]) @@ -97,94 +125,148 @@ def test_postgis_geometry_filter(self): def test_postgis_table_uri(self): """Create a connection from a layer uri and create a table URI""" - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.uri, {}) - vl = QgsVectorLayer(conn.tableUri('qgis_test', 'geometries_table'), 'my', 'postgres') + vl = QgsVectorLayer( + conn.tableUri("qgis_test", "geometries_table"), "my", "postgres" + ) self.assertTrue(vl.isValid()) def test_postgis_connections(self): """Create some connections and retrieve them""" - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.uri, {}) - md.saveConnection(conn, 'qgis_test1') + md.saveConnection(conn, "qgis_test1") # Retrieve capabilities capabilities = conn.capabilities() - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.Tables)) - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.Schemas)) - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.CreateVectorTable)) - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.DropVectorTable)) - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.RenameVectorTable)) - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.RenameRasterTable)) + self.assertTrue( + bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.Tables) + ) + self.assertTrue( + bool( + capabilities & QgsAbstractDatabaseProviderConnection.Capability.Schemas + ) + ) + self.assertTrue( + bool( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.CreateVectorTable + ) + ) + self.assertTrue( + bool( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.DropVectorTable + ) + ) + self.assertTrue( + bool( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.RenameVectorTable + ) + ) + self.assertTrue( + bool( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.RenameRasterTable + ) + ) # Check filters and special cases - table_names = self._table_names(conn.tables('qgis_test', QgsAbstractDatabaseProviderConnection.TableFlag.Raster)) - self.assertIn('Raster1', table_names) - self.assertNotIn('geometryless_table', table_names) - self.assertNotIn('geometries_table', table_names) - self.assertNotIn('geometries_view', table_names) - - table_names = self._table_names(conn.tables('qgis_test', QgsAbstractDatabaseProviderConnection.TableFlag.View)) - self.assertNotIn('Raster1', table_names) - self.assertNotIn('geometryless_table', table_names) - self.assertNotIn('geometries_table', table_names) - self.assertIn('geometries_view', table_names) - - table_names = self._table_names(conn.tables('qgis_test', QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial)) - self.assertNotIn('Raster1', table_names) - self.assertIn('geometryless_table', table_names) - self.assertNotIn('geometries_table', table_names) - self.assertNotIn('geometries_view', table_names) - - tables = conn.tables('qgis_test', QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial | QgsAbstractDatabaseProviderConnection.TableFlag.View) + table_names = self._table_names( + conn.tables( + "qgis_test", QgsAbstractDatabaseProviderConnection.TableFlag.Raster + ) + ) + self.assertIn("Raster1", table_names) + self.assertNotIn("geometryless_table", table_names) + self.assertNotIn("geometries_table", table_names) + self.assertNotIn("geometries_view", table_names) + + table_names = self._table_names( + conn.tables( + "qgis_test", QgsAbstractDatabaseProviderConnection.TableFlag.View + ) + ) + self.assertNotIn("Raster1", table_names) + self.assertNotIn("geometryless_table", table_names) + self.assertNotIn("geometries_table", table_names) + self.assertIn("geometries_view", table_names) + + table_names = self._table_names( + conn.tables( + "qgis_test", QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial + ) + ) + self.assertNotIn("Raster1", table_names) + self.assertIn("geometryless_table", table_names) + self.assertNotIn("geometries_table", table_names) + self.assertNotIn("geometries_view", table_names) + + tables = conn.tables( + "qgis_test", + QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial + | QgsAbstractDatabaseProviderConnection.TableFlag.View, + ) table_names = self._table_names(tables) - b32523_view = self._table_by_name(tables, 'b32523') + b32523_view = self._table_by_name(tables, "b32523") self.assertTrue(b32523_view) pks = b32523_view.primaryKeyColumns() - self.assertIn('pk', pks) - self.assertIn('random', pks) + self.assertIn("pk", pks) + self.assertIn("random", pks) - geometries_table = self._table_by_name(conn.tables('qgis_test'), 'geometries_table') - srids_and_types = [[t.crs.postgisSrid(), t.wkbType] - for t in geometries_table.geometryColumnTypes()] + geometries_table = self._table_by_name( + conn.tables("qgis_test"), "geometries_table" + ) + srids_and_types = [ + [t.crs.postgisSrid(), t.wkbType] + for t in geometries_table.geometryColumnTypes() + ] srids_and_types.sort() - self.assertEqual(srids_and_types, - [[0, 1], [0, 2], [0, 3], [0, 7], [3857, 1], [4326, 1]]) + self.assertEqual( + srids_and_types, [[0, 1], [0, 2], [0, 3], [0, 7], [3857, 1], [4326, 1]] + ) # Check TopoGeometry and Pointcloud layers are found in vector table names - tables = conn.tables('qgis_test', QgsAbstractDatabaseProviderConnection.TableFlag.Vector) + tables = conn.tables( + "qgis_test", QgsAbstractDatabaseProviderConnection.TableFlag.Vector + ) table_names = self._table_names(tables) - self.assertIn('TopoLayer1', table_names) - self.assertIn('PointCloudPointLayer', table_names) - self.assertIn('PointCloudPatchLayer', table_names) + self.assertIn("TopoLayer1", table_names) + self.assertIn("PointCloudPointLayer", table_names) + self.assertIn("PointCloudPatchLayer", table_names) - self.assertIn('geometries_table', table_names) + self.assertIn("geometries_table", table_names) # Revoke select permissions on topology.topology from qgis_test_user - conn.executeSql('REVOKE SELECT ON topology.topology FROM qgis_test_user') + conn.executeSql("REVOKE SELECT ON topology.topology FROM qgis_test_user") # Revoke select permissions on pointcloud_format from qgis_test_user - conn.executeSql('REVOKE SELECT ON pointcloud_formats FROM qgis_test_user') + conn.executeSql("REVOKE SELECT ON pointcloud_formats FROM qgis_test_user") # Revoke select permissions on pointcloud_format from qgis_test_user - conn.executeSql('REVOKE SELECT ON raster_columns FROM public') - conn.executeSql('REVOKE SELECT ON raster_columns FROM qgis_test_user') + conn.executeSql("REVOKE SELECT ON raster_columns FROM public") + conn.executeSql("REVOKE SELECT ON raster_columns FROM qgis_test_user") # Re-connect as the qgis_test_role role - newuri = self.uri + ' user=qgis_test_user password=qgis_test_user_password' + newuri = self.uri + " user=qgis_test_user password=qgis_test_user_password" newconn = md.createConnection(newuri, {}) # Check TopoGeometry and Pointcloud layers are not found in vector table names - tableTypes = QgsAbstractDatabaseProviderConnection.TableFlag.Vector | QgsAbstractDatabaseProviderConnection.TableFlag.Raster - tables = newconn.tables('qgis_test', tableTypes) + tableTypes = ( + QgsAbstractDatabaseProviderConnection.TableFlag.Vector + | QgsAbstractDatabaseProviderConnection.TableFlag.Raster + ) + tables = newconn.tables("qgis_test", tableTypes) table_names = self._table_names(tables) - self.assertNotIn('TopoLayer1', table_names) - self.assertNotIn('PointCloudPointLayer', table_names) - self.assertNotIn('PointCloudPatchLayer', table_names) - self.assertNotIn('Raster1', table_names) - self.assertIn('geometries_table', table_names) + self.assertNotIn("TopoLayer1", table_names) + self.assertNotIn("PointCloudPointLayer", table_names) + self.assertNotIn("PointCloudPatchLayer", table_names) + self.assertNotIn("Raster1", table_names) + self.assertIn("geometries_table", table_names) # TODO: only revoke select permission on topology.layer, grant # on topology.topology @@ -199,69 +281,109 @@ def test_postgis_connections(self): # table # Grant select permissions back on topology.topology to qgis_test_user - conn.executeSql('GRANT SELECT ON topology.topology TO qgis_test_user') + conn.executeSql("GRANT SELECT ON topology.topology TO qgis_test_user") # Grant select permissions back on pointcloud_formats to qgis_test_user - conn.executeSql('GRANT SELECT ON pointcloud_formats TO qgis_test_user') + conn.executeSql("GRANT SELECT ON pointcloud_formats TO qgis_test_user") # Grant select permissions back on raster_columns to qgis_test_user - conn.executeSql('GRANT SELECT ON raster_columns TO public') - conn.executeSql('GRANT SELECT ON raster_columns TO qgis_test_user') + conn.executeSql("GRANT SELECT ON raster_columns TO public") + conn.executeSql("GRANT SELECT ON raster_columns TO qgis_test_user") # error: ERROR: relation "qgis_test.raster1" does not exist def test_postgis_raster_rename(self): """Test raster rename""" - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.uri, {}) - md.saveConnection(conn, 'qgis_test1') - - table = self._table_by_name(conn.tables('qgis_test', QgsAbstractDatabaseProviderConnection.TableFlag.Raster), 'Raster1') - self.assertTrue(QgsRasterLayer(f"PG: {conn.uri()} dbname='qgis_test' schema='qgis_test' column='{table.geometryColumn()}' table='{table.tableName()}'", 'r1', 'gdal').isValid()) - conn.renameRasterTable('qgis_test', table.tableName(), 'Raster2') - table = self._table_by_name(conn.tables('qgis_test', QgsAbstractDatabaseProviderConnection.TableFlag.Raster), 'Raster2') - self.assertTrue(QgsRasterLayer(f"PG: {conn.uri()} dbname='qgis_test' schema='qgis_test' column='{table.geometryColumn()}' table='{table.tableName()}'", 'r1', 'gdal').isValid()) - table_names = self._table_names(conn.tables('qgis_test', QgsAbstractDatabaseProviderConnection.TableFlag.Raster)) - self.assertNotIn('Raster1', table_names) - self.assertIn('Raster2', table_names) - conn.renameRasterTable('qgis_test', table.tableName(), 'Raster1') - table_names = self._table_names(conn.tables('qgis_test', QgsAbstractDatabaseProviderConnection.TableFlag.Raster)) - self.assertNotIn('Raster2', table_names) - self.assertIn('Raster1', table_names) + md.saveConnection(conn, "qgis_test1") + + table = self._table_by_name( + conn.tables( + "qgis_test", QgsAbstractDatabaseProviderConnection.TableFlag.Raster + ), + "Raster1", + ) + self.assertTrue( + QgsRasterLayer( + f"PG: {conn.uri()} dbname='qgis_test' schema='qgis_test' column='{table.geometryColumn()}' table='{table.tableName()}'", + "r1", + "gdal", + ).isValid() + ) + conn.renameRasterTable("qgis_test", table.tableName(), "Raster2") + table = self._table_by_name( + conn.tables( + "qgis_test", QgsAbstractDatabaseProviderConnection.TableFlag.Raster + ), + "Raster2", + ) + self.assertTrue( + QgsRasterLayer( + f"PG: {conn.uri()} dbname='qgis_test' schema='qgis_test' column='{table.geometryColumn()}' table='{table.tableName()}'", + "r1", + "gdal", + ).isValid() + ) + table_names = self._table_names( + conn.tables( + "qgis_test", QgsAbstractDatabaseProviderConnection.TableFlag.Raster + ) + ) + self.assertNotIn("Raster1", table_names) + self.assertIn("Raster2", table_names) + conn.renameRasterTable("qgis_test", table.tableName(), "Raster1") + table_names = self._table_names( + conn.tables( + "qgis_test", QgsAbstractDatabaseProviderConnection.TableFlag.Raster + ) + ) + self.assertNotIn("Raster2", table_names) + self.assertIn("Raster1", table_names) def test_true_false(self): """Test returned values from BOOL queries""" md = QgsProviderRegistry.instance().providerMetadata(self.providerKey) conn = md.createConnection(self.uri, {}) - self.assertEqual(conn.executeSql('SELECT FALSE'), [[False]]) - self.assertEqual(conn.executeSql('SELECT TRUE'), [[True]]) + self.assertEqual(conn.executeSql("SELECT FALSE"), [[False]]) + self.assertEqual(conn.executeSql("SELECT TRUE"), [[True]]) def test_nulls(self): """Test returned values from typed NULL queries""" md = QgsProviderRegistry.instance().providerMetadata(self.providerKey) conn = md.createConnection(self.uri, {}) - self.assertEqual(conn.executeSql('SELECT NULL::bool'), [[None]]) - self.assertEqual(conn.executeSql('SELECT NULL::text'), [[None]]) - self.assertEqual(conn.executeSql('SELECT NULL::bytea'), [[None]]) - self.assertEqual(conn.executeSql('SELECT NULL::char'), [[None]]) + self.assertEqual(conn.executeSql("SELECT NULL::bool"), [[None]]) + self.assertEqual(conn.executeSql("SELECT NULL::text"), [[None]]) + self.assertEqual(conn.executeSql("SELECT NULL::bytea"), [[None]]) + self.assertEqual(conn.executeSql("SELECT NULL::char"), [[None]]) def test_pk_cols_order(self): """Test that PKs are returned in consistent order: see GH #34167""" md = QgsProviderRegistry.instance().providerMetadata(self.providerKey) conn = md.createConnection(self.uri, {}) - self.assertEqual(conn.table('qgis_test', 'bikes_view').primaryKeyColumns(), ['pk', 'name']) - self.assertEqual(conn.table('qgis_test', 'some_poly_data_view').primaryKeyColumns(), ['pk', 'geom']) + self.assertEqual( + conn.table("qgis_test", "bikes_view").primaryKeyColumns(), ["pk", "name"] + ) + self.assertEqual( + conn.table("qgis_test", "some_poly_data_view").primaryKeyColumns(), + ["pk", "geom"], + ) def test_char_type_conversion(self): """Test char types: see GH #34806""" md = QgsProviderRegistry.instance().providerMetadata(self.providerKey) conn = md.createConnection(self.uri, {}) - self.assertEqual(conn.executeSql("SELECT relname, relkind FROM pg_class c, pg_namespace n WHERE n.oid = c.relnamespace AND relname = 'bikes_view' AND c.relkind IN ('t', 'v', 'm')"), [['bikes_view', 'v']]) + self.assertEqual( + conn.executeSql( + "SELECT relname, relkind FROM pg_class c, pg_namespace n WHERE n.oid = c.relnamespace AND relname = 'bikes_view' AND c.relkind IN ('t', 'v', 'm')" + ), + [["bikes_view", "v"]], + ) def test_foreign_table_csv(self): """Test foreign table""" @@ -269,19 +391,20 @@ def test_foreign_table_csv(self): md = QgsProviderRegistry.instance().providerMetadata(self.providerKey) conn = md.createConnection(self.uri, {}) temp_dir = QTemporaryDir() - csv_path = os.path.join(temp_dir.path(), 'test.csv') + csv_path = os.path.join(temp_dir.path(), "test.csv") csv = """id,description,geom_x,geom_y 1,Basic point,10.5,20.82 2,Integer point,11,22 3,Final point,13.0,23.0 """ - with open(csv_path, 'w') as f: + with open(csv_path, "w") as f: f.write(csv) os.chmod(temp_dir.path(), 0o777) os.chmod(csv_path, 0o777) - foreign_table_definition = """ + foreign_table_definition = ( + """ CREATE EXTENSION IF NOT EXISTS file_fdw; CREATE SERVER IF NOT EXISTS file_fdw_test_server FOREIGN DATA WRAPPER file_fdw; CREATE FOREIGN TABLE IF NOT EXISTS points_csv ( @@ -289,13 +412,24 @@ def test_foreign_table_csv(self): name text, x numeric, y numeric ) SERVER file_fdw_test_server OPTIONS ( filename '%s', format 'csv', header 'true' ); -""" % csv_path +""" + % csv_path + ) conn.executeSql(foreign_table_definition) - self.assertNotEqual(conn.tables('public', QgsAbstractDatabaseProviderConnection.TableFlag.Foreign | QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial), []) + self.assertNotEqual( + conn.tables( + "public", + QgsAbstractDatabaseProviderConnection.TableFlag.Foreign + | QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial, + ), + [], + ) - @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'), 'Disabled on Travis') + @unittest.skipIf( + os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), "Disabled on Travis" + ) def test_foreign_table_server(self): """Test foreign table with server""" @@ -319,17 +453,33 @@ def test_foreign_table_server(self): IMPORT FOREIGN SCHEMA qgis_test LIMIT TO ( "someData" ) FROM SERVER postgres_fdw_test_server INTO foreign_schema; - """.format(host=host, user=user, port=port, dbname=dbname, password=password, service=service) + """.format( + host=host, + user=user, + port=port, + dbname=dbname, + password=password, + service=service, + ) conn.executeSql(foreign_table_definition) - self.assertEqual(conn.tables('foreign_schema', QgsAbstractDatabaseProviderConnection.TableFlag.Foreign)[0].tableName(), 'someData') + self.assertEqual( + conn.tables( + "foreign_schema", + QgsAbstractDatabaseProviderConnection.TableFlag.Foreign, + )[0].tableName(), + "someData", + ) def test_fields(self): """Test fields""" - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.uri, {}) - fields = conn.fields('qgis_test', 'someData') - self.assertEqual(fields.names(), ['pk', 'cnt', 'name', 'name2', 'num_char', 'dt', 'date', 'time', 'geom']) + fields = conn.fields("qgis_test", "someData") + self.assertEqual( + fields.names(), + ["pk", "cnt", "name", "name2", "num_char", "dt", "date", "time", "geom"], + ) sql = """ DROP TABLE IF EXISTS qgis_test.gh_37666; @@ -341,49 +491,56 @@ def test_fields(self): """ conn.executeSql(sql) - fields = conn.fields('qgis_test', 'gh_37666') - self.assertEqual(fields.names(), ['id', 'geom', 'geog']) - self.assertEqual([f.typeName() for f in fields], ['int4', 'geometry', 'geography']) - table = conn.table('qgis_test', 'gh_37666') - self.assertEqual(table.primaryKeyColumns(), ['id']) + fields = conn.fields("qgis_test", "gh_37666") + self.assertEqual(fields.names(), ["id", "geom", "geog"]) + self.assertEqual( + [f.typeName() for f in fields], ["int4", "geometry", "geography"] + ) + table = conn.table("qgis_test", "gh_37666") + self.assertEqual(table.primaryKeyColumns(), ["id"]) def test_fields_no_pk(self): """Test issue: no fields are exposed for raster_columns""" - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.uri, {}) - self.assertTrue(conn.tableExists('public', 'raster_columns')) + self.assertTrue(conn.tableExists("public", "raster_columns")) fields = conn.fields("public", "raster_columns") - self.assertTrue(set(fields.names()).issuperset({ - 'r_table_catalog', - 'r_table_schema', - 'r_table_name', - 'r_raster_column', - 'srid', - 'scale_x', - 'scale_y', - 'blocksize_x', - 'blocksize_y', - 'same_alignment', - 'regular_blocking', - 'num_bands', - 'pixel_types', - 'nodata_values', - 'out_db', - 'spatial_index'})) + self.assertTrue( + set(fields.names()).issuperset( + { + "r_table_catalog", + "r_table_schema", + "r_table_name", + "r_raster_column", + "srid", + "scale_x", + "scale_y", + "blocksize_x", + "blocksize_y", + "same_alignment", + "regular_blocking", + "num_bands", + "pixel_types", + "nodata_values", + "out_db", + "spatial_index", + } + ) + ) def test_exceptions(self): """Test that exception are converted to Python QgsProviderConnectionException""" - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.uri, {}) with self.assertRaises(QgsProviderConnectionException): - conn.table('my_not_existent_schema', 'my_not_existent_table') + conn.table("my_not_existent_schema", "my_not_existent_table") def test_zm(self): """Test regression GH #43268""" - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.uri, {}) sql = """ DROP TABLE IF EXISTS qgis_test.gh_43268_test_zm; @@ -395,13 +552,21 @@ def test_zm(self): """ conn.executeSql(sql) - table_info = conn.table('qgis_test', 'gh_43268_test_zm') - self.assertEqual(sorted([QgsWkbTypes.displayString(col.wkbType) for col in table_info.geometryColumnTypes()]), ['LineStringZ', 'PointZ', 'PolygonZ']) + table_info = conn.table("qgis_test", "gh_43268_test_zm") + self.assertEqual( + sorted( + [ + QgsWkbTypes.displayString(col.wkbType) + for col in table_info.geometryColumnTypes() + ] + ), + ["LineStringZ", "PointZ", "PolygonZ"], + ) def test_m(self): """Test regression GH #55223""" - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.uri, {}) sql = """ DROP TABLE IF EXISTS qgis_test.gh_55223_test_m; @@ -415,16 +580,23 @@ def test_m(self): FROM test_measure; """ conn.executeSql(sql) - geom_types = [t.geometryColumnTypes()[0] for t in conn.tables() if t.tableName() == 'gh_55223_test_m'] - self.assertEqual(sorted([QgsWkbTypes.displayString(col.wkbType) for col in geom_types]), ['LineString', 'LineStringM']) + geom_types = [ + t.geometryColumnTypes()[0] + for t in conn.tables() + if t.tableName() == "gh_55223_test_m" + ] + self.assertEqual( + sorted([QgsWkbTypes.displayString(col.wkbType) for col in geom_types]), + ["LineString", "LineStringM"], + ) def test_table_scan(self): """Test that with use estimated metadata disabled all geometry column - types can be identified, test for GH #43186 """ + types can be identified, test for GH #43186""" - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") uri = QgsDataSourceUri(self.uri) - conn = md.createConnection(uri.uri(), {'estimatedMetadata': True}) + conn = md.createConnection(uri.uri(), {"estimatedMetadata": True}) sql = """ DROP TABLE IF EXISTS qgis_test.geometry_table_with_multiple_types; @@ -444,38 +616,38 @@ def test_table_scan(self): sql = "INSERT INTO qgis_test.geometry_table_with_multiple_types (geom) VALUES (ST_GeomFromText('linestring(9 45, 10 46)', 4326));" conn.executeSql(sql) - table = conn.table('qgis_test', 'geometry_table_with_multiple_types') + table = conn.table("qgis_test", "geometry_table_with_multiple_types") self.assertEqual(len(table.geometryColumnTypes()), 1) uri = QgsDataSourceUri(self.uri) uri.setUseEstimatedMetadata(False) - conn = md.createConnection(uri.uri(), {'estimatedMetadata': False}) + conn = md.createConnection(uri.uri(), {"estimatedMetadata": False}) - table = conn.table('qgis_test', 'geometry_table_with_multiple_types') + table = conn.table("qgis_test", "geometry_table_with_multiple_types") self.assertEqual(len(table.geometryColumnTypes()), 2) # Tesf for #43199 - uri.setSchema('qgis_test') - uri.setTable('geometry_table_with_multiple_types') - uri.setGeometryColumn('geom') + uri.setSchema("qgis_test") + uri.setTable("geometry_table_with_multiple_types") + uri.setGeometryColumn("geom") uri.setWkbType(QgsWkbTypes.Type.Point) - vl = QgsVectorLayer(uri.uri(), 'points', 'postgres') + vl = QgsVectorLayer(uri.uri(), "points", "postgres") self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 110) - uri.setGeometryColumn('geom') + uri.setGeometryColumn("geom") uri.setWkbType(QgsWkbTypes.Type.LineString) - vl = QgsVectorLayer(uri.uri(), 'lines', 'postgres') + vl = QgsVectorLayer(uri.uri(), "lines", "postgres") self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 10) def test_create_vector_layer(self): """Test query layers""" - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.uri, {}) sql = """ @@ -491,9 +663,11 @@ def test_create_vector_layer(self): conn.executeSql(sql) options = QgsAbstractDatabaseProviderConnection.SqlVectorLayerOptions() - options.sql = 'SELECT id, geom FROM qgis_test.query_layer1 WHERE id < 200 LIMIT 2' - options.primaryKeyColumns = ['id'] - options.geometryColumn = 'geom' + options.sql = ( + "SELECT id, geom FROM qgis_test.query_layer1 WHERE id < 200 LIMIT 2" + ) + options.primaryKeyColumns = ["id"] + options.geometryColumn = "geom" vl = conn.createSqlVectorLayer(options) self.assertTrue(vl.isValid()) self.assertTrue(vl.isSqlQuery()) @@ -503,7 +677,9 @@ def test_create_vector_layer(self): features = [f for f in vl.getFeatures()] self.assertEqual(len(features), 0) - options.sql = 'SELECT id, geom FROM qgis_test.query_layer1 WHERE id > 200 LIMIT 2' + options.sql = ( + "SELECT id, geom FROM qgis_test.query_layer1 WHERE id > 200 LIMIT 2" + ) vl = conn.createSqlVectorLayer(options) self.assertTrue(vl.isValid()) self.assertTrue(vl.isSqlQuery()) @@ -511,7 +687,9 @@ def test_create_vector_layer(self): features = [f for f in vl.getFeatures()] self.assertEqual(len(features), 2) - options.sql = 'SELECT id, geom FROM qgis_test.query_layer1 WHERE id > 210 LIMIT 2' + options.sql = ( + "SELECT id, geom FROM qgis_test.query_layer1 WHERE id > 210 LIMIT 2" + ) vl = conn.createSqlVectorLayer(options) self.assertTrue(vl.isValid()) self.assertTrue(vl.isSqlQuery()) @@ -519,8 +697,8 @@ def test_create_vector_layer(self): features = [f for f in vl.getFeatures()] self.assertEqual(len(features), 1) - options.sql = 'SELECT id, geom FROM qgis_test.query_layer1 LIMIT 2' - options.filter = 'id > 210' + options.sql = "SELECT id, geom FROM qgis_test.query_layer1 LIMIT 2" + options.filter = "id > 210" vl = conn.createSqlVectorLayer(options) self.assertTrue(vl.isValid()) self.assertTrue(vl.isSqlQuery()) @@ -529,21 +707,23 @@ def test_create_vector_layer(self): self.assertEqual(len(features), 1) # Wrong calls - options.primaryKeyColumns = ['DOES_NOT_EXIST'] + options.primaryKeyColumns = ["DOES_NOT_EXIST"] vl = conn.createSqlVectorLayer(options) self.assertFalse(vl.isValid()) self.assertFalse(vl.vectorLayerTypeFlags() & Qgis.VectorLayerTypeFlag.SqlQuery) self.assertFalse(vl.isSqlQuery()) - options.primaryKeyColumns = ['id'] - options.geometryColumn = 'DOES_NOT_EXIST' + options.primaryKeyColumns = ["id"] + options.geometryColumn = "DOES_NOT_EXIST" vl = conn.createSqlVectorLayer(options) self.assertFalse(vl.isValid()) self.assertFalse(vl.isSqlQuery()) - options.sql = 'SELECT id, geom FROM qgis_test.query_layer1 WHERE id > 210 LIMIT 2' + options.sql = ( + "SELECT id, geom FROM qgis_test.query_layer1 WHERE id > 210 LIMIT 2" + ) options.primaryKeyColumns = [] - options.geometryColumn = '' + options.geometryColumn = "" vl = conn.createSqlVectorLayer(options) self.assertTrue(vl.isValid()) self.assertTrue(vl.isSqlQuery()) @@ -551,9 +731,11 @@ def test_create_vector_layer(self): self.assertEqual(len(features), 1) # No geometry and no PK, aspatial layer - options.sql = 'SELECT id, geom FROM qgis_test.query_layer1 WHERE id > 210 LIMIT 2' + options.sql = ( + "SELECT id, geom FROM qgis_test.query_layer1 WHERE id > 210 LIMIT 2" + ) options.primaryKeyColumns = [] - options.geometryColumn = '' + options.geometryColumn = "" vl = conn.createSqlVectorLayer(options) self.assertTrue(vl.isValid()) self.assertTrue(vl.isSqlQuery()) @@ -577,9 +759,11 @@ def test_create_vector_layer(self): conn.executeSql(sql) options = QgsAbstractDatabaseProviderConnection.SqlVectorLayerOptions() - options.sql = 'SELECT id, id2, geom FROM qgis_test.query_layer2 ORDER BY id ASC LIMIT 1' - options.primaryKeyColumns = ['id', 'id2'] - options.geometryColumn = 'geom' + options.sql = ( + "SELECT id, id2, geom FROM qgis_test.query_layer2 ORDER BY id ASC LIMIT 1" + ) + options.primaryKeyColumns = ["id", "id2"] + options.geometryColumn = "geom" vl = conn.createSqlVectorLayer(options) self.assertTrue(vl.isValid()) self.assertTrue(vl.isSqlQuery()) @@ -592,7 +776,7 @@ def test_create_vector_layer(self): # No PKs options.primaryKeyColumns = [] - options.geometryColumn = 'geom' + options.geometryColumn = "geom" vl = conn.createSqlVectorLayer(options) self.assertTrue(vl.isSqlQuery()) self.assertTrue(vl.isValid()) @@ -601,5 +785,5 @@ def test_create_vector_layer(self): self.assertEqual(len(features), 1) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsproviderconnection_spatialite.py b/tests/src/python/test_qgsproviderconnection_spatialite.py index 8096ceea6e95..52bb4e453c50 100644 --- a/tests/src/python/test_qgsproviderconnection_spatialite.py +++ b/tests/src/python/test_qgsproviderconnection_spatialite.py @@ -6,9 +6,10 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '28/10/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "28/10/2019" +__copyright__ = "Copyright 2019, The QGIS Project" import os import shutil @@ -32,12 +33,14 @@ TEST_DATA_DIR = unitTestDataPath() -class TestPyQgsProviderConnectionSpatialite(unittest.TestCase, TestPyQgsProviderConnectionBase): +class TestPyQgsProviderConnectionSpatialite( + unittest.TestCase, TestPyQgsProviderConnectionBase +): # Provider test cases must define the string URI for the test - uri = '' + uri = "" # Provider test cases must define the provider name (e.g. "postgres" or "ogr") - providerKey = 'spatialite' + providerKey = "spatialite" # Provider test cases can define a slowQuery for executeSql cancellation test # Note: GDAL does not support GDALDatasetExecuteSQL interruption, so @@ -52,34 +55,36 @@ class TestPyQgsProviderConnectionSpatialite(unittest.TestCase, TestPyQgsProvider SELECT i FROM r WHERE i = 1; """ # Provider test cases can define a schema and table name for SQL query layers test - sqlVectorLayerSchema = '' - sqlVectorLayerTable = 'cdb_lines' - sqlVectorLayerCrs = 'EPSG:25832' + sqlVectorLayerSchema = "" + sqlVectorLayerTable = "cdb_lines" + sqlVectorLayerCrs = "EPSG:25832" @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsProviderConnectionSpatialite, cls).setUpClass() + super().setUpClass() TestPyQgsProviderConnectionBase.setUpClass() cls.basetestpath = tempfile.mkdtemp() - spatialite_original_path = f'{TEST_DATA_DIR}/qgis_server/test_project_wms_grouped_layers.sqlite' - cls.spatialite_path = os.path.join(cls.basetestpath, 'test.sqlite') + spatialite_original_path = ( + f"{TEST_DATA_DIR}/qgis_server/test_project_wms_grouped_layers.sqlite" + ) + cls.spatialite_path = os.path.join(cls.basetestpath, "test.sqlite") shutil.copy(spatialite_original_path, cls.spatialite_path) cls.uri = f"dbname='{cls.spatialite_path}'" - vl = QgsVectorLayer(f'{cls.uri} table=\'cdb_lines\'', 'test', 'spatialite') + vl = QgsVectorLayer(f"{cls.uri} table='cdb_lines'", "test", "spatialite") assert vl.isValid() @classmethod def tearDownClass(cls): """Run after all tests""" os.unlink(cls.spatialite_path) - super(TestPyQgsProviderConnectionSpatialite, cls).tearDownClass() + super().tearDownClass() def test_spatialite_connections_from_uri(self): """Create a connection from a layer uri and retrieve it""" - md = QgsProviderRegistry.instance().providerMetadata('spatialite') - vl = QgsVectorLayer(f'{self.uri} table=\'cdb_lines\'', 'test', 'spatialite') + md = QgsProviderRegistry.instance().providerMetadata("spatialite") + vl = QgsVectorLayer(f"{self.uri} table='cdb_lines'", "test", "spatialite") self.assertTrue(vl.isValid()) conn = md.createConnection(vl.dataProvider().uri().uri(), {}) self.assertEqual(conn.uri(), self.uri) @@ -88,75 +93,120 @@ def test_spatialite_connections_from_uri(self): def test_spatialite_table_uri(self): """Create a connection from a layer uri and create a table URI""" - md = QgsProviderRegistry.instance().providerMetadata('spatialite') + md = QgsProviderRegistry.instance().providerMetadata("spatialite") conn = md.createConnection(self.uri, {}) - self.assertEqual(conn.tableUri('', 'cdb_lines'), f'{self.uri} table="cdb_lines"') - vl = QgsVectorLayer(conn.tableUri('', 'cdb_lines'), 'lines', 'spatialite') + self.assertEqual( + conn.tableUri("", "cdb_lines"), f'{self.uri} table="cdb_lines"' + ) + vl = QgsVectorLayer(conn.tableUri("", "cdb_lines"), "lines", "spatialite") self.assertTrue(vl.isValid()) # Test table(), throws if not found - table_info = conn.table('', 'cdb_lines') + table_info = conn.table("", "cdb_lines") def test_spatialite_connections(self): """Create some connections and retrieve them""" - md = QgsProviderRegistry.instance().providerMetadata('spatialite') + md = QgsProviderRegistry.instance().providerMetadata("spatialite") conn = md.createConnection(self.uri, {}) - md.saveConnection(conn, 'qgis_test1') + md.saveConnection(conn, "qgis_test1") # Retrieve capabilities capabilities = conn.capabilities() - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.Tables)) - self.assertFalse(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.Schemas)) - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.CreateVectorTable)) - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.DropVectorTable)) - self.assertTrue(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.RenameVectorTable)) - self.assertFalse(bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.RenameRasterTable)) + self.assertTrue( + bool(capabilities & QgsAbstractDatabaseProviderConnection.Capability.Tables) + ) + self.assertFalse( + bool( + capabilities & QgsAbstractDatabaseProviderConnection.Capability.Schemas + ) + ) + self.assertTrue( + bool( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.CreateVectorTable + ) + ) + self.assertTrue( + bool( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.DropVectorTable + ) + ) + self.assertTrue( + bool( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.RenameVectorTable + ) + ) + self.assertFalse( + bool( + capabilities + & QgsAbstractDatabaseProviderConnection.Capability.RenameRasterTable + ) + ) crs = QgsCoordinateReferenceSystem.fromEpsgId(3857) typ = QgsWkbTypes.Type.LineString - conn.createVectorTable('', 'myNewAspatialTable', QgsFields(), QgsWkbTypes.Type.NoGeometry, crs, True, {}) - conn.createVectorTable('', 'myNewTable', QgsFields(), typ, crs, True, {}) + conn.createVectorTable( + "", + "myNewAspatialTable", + QgsFields(), + QgsWkbTypes.Type.NoGeometry, + crs, + True, + {}, + ) + conn.createVectorTable("", "myNewTable", QgsFields(), typ, crs, True, {}) - table_names = self._table_names(conn.tables('', QgsAbstractDatabaseProviderConnection.TableFlag.View)) - self.assertIn('my_view', table_names) - self.assertNotIn('myNewTable', table_names) - self.assertNotIn('myNewAspatialTable', table_names) + table_names = self._table_names( + conn.tables("", QgsAbstractDatabaseProviderConnection.TableFlag.View) + ) + self.assertIn("my_view", table_names) + self.assertNotIn("myNewTable", table_names) + self.assertNotIn("myNewAspatialTable", table_names) - table_names = self._table_names(conn.tables('', QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial)) - self.assertNotIn('myNewTable', table_names) - self.assertIn('myNewAspatialTable', table_names) + table_names = self._table_names( + conn.tables("", QgsAbstractDatabaseProviderConnection.TableFlag.Aspatial) + ) + self.assertNotIn("myNewTable", table_names) + self.assertIn("myNewAspatialTable", table_names) def test_spatialite_fields(self): """Test fields""" - md = QgsProviderRegistry.instance().providerMetadata('spatialite') + md = QgsProviderRegistry.instance().providerMetadata("spatialite") conn = md.createConnection(self.uri, {}) - fields = conn.fields('', 'cdb_lines') - table_info = conn.table('', 'cdb_lines') + fields = conn.fields("", "cdb_lines") + table_info = conn.table("", "cdb_lines") self.assertIn(table_info.geometryColumn(), fields.names()) self.assertIn(table_info.primaryKeyColumns()[0], fields.names()) - self.assertEqual(fields.names(), ['pk', 'geom', 'fid', 'id', 'typ', 'name', 'ortsrat', 'id_long']) + self.assertEqual( + fields.names(), + ["pk", "geom", "fid", "id", "typ", "name", "ortsrat", "id_long"], + ) def test_create_vector_layer(self): """Test query layers""" - md = QgsProviderRegistry.instance().providerMetadata('spatialite') + md = QgsProviderRegistry.instance().providerMetadata("spatialite") conn = md.createConnection(self.uri, {}) options = QgsAbstractDatabaseProviderConnection.SqlVectorLayerOptions() - options.sql = 'SELECT fid, name, geom FROM cdb_lines WHERE name LIKE \'S%\' LIMIT 2' - options.geometryColumn = 'geom' + options.sql = ( + "SELECT fid, name, geom FROM cdb_lines WHERE name LIKE 'S%' LIMIT 2" + ) + options.geometryColumn = "geom" vl = conn.createSqlVectorLayer(options) self.assertTrue(vl.isValid()) self.assertTrue(vl.isSqlQuery()) self.assertEqual(vl.geometryType(), QgsWkbTypes.GeometryType.PolygonGeometry) features = [f for f in vl.getFeatures()] self.assertEqual(len(features), 2) - self.assertEqual(features[0].attributes(), [8, 'Sülfeld']) + self.assertEqual(features[0].attributes(), [8, "Sülfeld"]) - options.filter = 'name == \'Sülfeld\'' + options.filter = "name == 'Sülfeld'" vl = conn.createSqlVectorLayer(options) self.assertTrue(vl.isValid()) self.assertTrue(vl.isSqlQuery()) @@ -165,31 +215,36 @@ def test_create_vector_layer(self): self.assertEqual(vl.geometryType(), QgsWkbTypes.GeometryType.PolygonGeometry) features = [f for f in vl.getFeatures()] self.assertEqual(len(features), 1) - self.assertEqual(features[0].attributes(), [8, 'Sülfeld']) + self.assertEqual(features[0].attributes(), [8, "Sülfeld"]) def test_execute_sql_pk_geoms(self): """OGR hides fid and geom from attributes, check if we can still get them""" - md = QgsProviderRegistry.instance().providerMetadata('spatialite') + md = QgsProviderRegistry.instance().providerMetadata("spatialite") conn = md.createConnection(self.uri, {}) # Check errors with self.assertRaises(QgsProviderConnectionException): - sql = 'SELECT not_exists, name, geom FROM cdb_lines WHERE name LIKE \'S%\' LIMIT 2' + sql = "SELECT not_exists, name, geom FROM cdb_lines WHERE name LIKE 'S%' LIMIT 2" results = conn.executeSql(sql) - sql = 'SELECT fid, name, geom FROM cdb_lines WHERE name LIKE \'S%\' LIMIT 2' + sql = "SELECT fid, name, geom FROM cdb_lines WHERE name LIKE 'S%' LIMIT 2" results = conn.executeSql(sql) - self.assertEqual(results[0][:2], [8, 'Sülfeld']) - self.assertEqual(results[1][:2], [16, 'Steimker Berg']) - self.assertEqual(results[0][2][:20], 'Polygon ((612694.674') - self.assertEqual(results[1][2][:20], 'Polygon ((622042.427') + self.assertEqual(results[0][:2], [8, "Sülfeld"]) + self.assertEqual(results[1][:2], [16, "Steimker Berg"]) + self.assertEqual(results[0][2][:20], "Polygon ((612694.674") + self.assertEqual(results[1][2][:20], "Polygon ((622042.427") - sql = 'SELECT name, st_astext(geom) FROM cdb_lines WHERE name LIKE \'S%\' LIMIT 2' + sql = "SELECT name, st_astext(geom) FROM cdb_lines WHERE name LIKE 'S%' LIMIT 2" results = conn.executeSql(sql) - self.assertEqual(results[0], ['Sülfeld', - 'POLYGON((612694.674 5807839.658, 612668.715 5808176.815, 612547.354 5808414.452, 612509.527 5808425.73, 612522.932 5808473.02, 612407.901 5808519.082, 612505.836 5808632.763, 612463.449 5808781.115, 612433.57 5808819.061, 612422.685 5808980.281999, 612473.423 5808995.424999, 612333.856 5809647.731, 612307.316 5809781.446, 612267.099 5809852.803, 612308.221 5810040.995, 613920.397 5811079.478, 613947.16 5811129.3, 614022.726 5811154.456, 614058.436 5811260.36, 614194.037 5811331.972, 614307.176 5811360.06, 614343.842 5811323.238, 614443.449 5811363.03, 614526.199 5811059.031, 614417.83 5811057.603, 614787.296 5809648.422, 614772.062 5809583.246, 614981.93 5809245.35, 614811.885 5809138.271, 615063.452 5809100.954, 615215.476 5809029.413, 615469.441 5808883.282, 615569.846 5808829.522, 615577.239 5808806.242, 615392.964 5808736.873, 615306.34 5808662.171, 615335.445 5808290.588, 615312.192 5808290.397, 614890.582 5808077.956, 615018.854 5807799.895, 614837.326 5807688.363, 614435.698 5807646.847, 614126.351 5807661.841, 613555.813 5807814.801, 612826.66 5807964.828, 612830.113 5807856.315, 612694.674 5807839.658))']) + self.assertEqual( + results[0], + [ + "Sülfeld", + "POLYGON((612694.674 5807839.658, 612668.715 5808176.815, 612547.354 5808414.452, 612509.527 5808425.73, 612522.932 5808473.02, 612407.901 5808519.082, 612505.836 5808632.763, 612463.449 5808781.115, 612433.57 5808819.061, 612422.685 5808980.281999, 612473.423 5808995.424999, 612333.856 5809647.731, 612307.316 5809781.446, 612267.099 5809852.803, 612308.221 5810040.995, 613920.397 5811079.478, 613947.16 5811129.3, 614022.726 5811154.456, 614058.436 5811260.36, 614194.037 5811331.972, 614307.176 5811360.06, 614343.842 5811323.238, 614443.449 5811363.03, 614526.199 5811059.031, 614417.83 5811057.603, 614787.296 5809648.422, 614772.062 5809583.246, 614981.93 5809245.35, 614811.885 5809138.271, 615063.452 5809100.954, 615215.476 5809029.413, 615469.441 5808883.282, 615569.846 5808829.522, 615577.239 5808806.242, 615392.964 5808736.873, 615306.34 5808662.171, 615335.445 5808290.588, 615312.192 5808290.397, 614890.582 5808077.956, 615018.854 5807799.895, 614837.326 5807688.363, 614435.698 5807646.847, 614126.351 5807661.841, 613555.813 5807814.801, 612826.66 5807964.828, 612830.113 5807856.315, 612694.674 5807839.658))", + ], + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsproviderconnectioncombobox.py b/tests/src/python/test_qgsproviderconnectioncombobox.py index df0eeef157fd..e74b8c04116a 100644 --- a/tests/src/python/test_qgsproviderconnectioncombobox.py +++ b/tests/src/python/test_qgsproviderconnectioncombobox.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '8/03/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "8/03/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import os import shutil @@ -37,17 +38,19 @@ def setUpClass(cls): QCoreApplication.setApplicationName(cls.__name__) start_app() - gpkg_original_path = f'{TEST_DATA_DIR}/qgis_server/test_project_wms_grouped_layers.gpkg' + gpkg_original_path = ( + f"{TEST_DATA_DIR}/qgis_server/test_project_wms_grouped_layers.gpkg" + ) cls.basetestpath = tempfile.mkdtemp() - cls.gpkg_path = f'{cls.basetestpath}/test_gpkg.gpkg' + cls.gpkg_path = f"{cls.basetestpath}/test_gpkg.gpkg" shutil.copy(gpkg_original_path, cls.gpkg_path) - vl = QgsVectorLayer(f'{cls.gpkg_path}|layername=cdb_lines', 'test', 'ogr') + vl = QgsVectorLayer(f"{cls.gpkg_path}|layername=cdb_lines", "test", "ogr") assert vl.isValid() - gpkg2_original_path = f'{TEST_DATA_DIR}/points_gpkg.gpkg' - cls.gpkg_path2 = f'{cls.basetestpath}/test_gpkg2.gpkg' + gpkg2_original_path = f"{TEST_DATA_DIR}/points_gpkg.gpkg" + cls.gpkg_path2 = f"{cls.basetestpath}/test_gpkg2.gpkg" shutil.copy(gpkg2_original_path, cls.gpkg_path2) - vl = QgsVectorLayer(f'{cls.gpkg_path2}', 'test', 'ogr') + vl = QgsVectorLayer(f"{cls.gpkg_path2}", "test", "ogr") assert vl.isValid() @classmethod @@ -58,132 +61,132 @@ def tearDownClass(cls): super().tearDownClass() def testCombo(self): - """ test combobox functionality """ - m = QgsProviderConnectionComboBox('ogr') + """test combobox functionality""" + m = QgsProviderConnectionComboBox("ogr") spy = QSignalSpy(m.connectionChanged) self.assertEqual(m.count(), 0) self.assertFalse(m.currentConnection()) self.assertFalse(m.currentConnectionUri()) - md = QgsProviderRegistry.instance().providerMetadata('ogr') + md = QgsProviderRegistry.instance().providerMetadata("ogr") conn = md.createConnection(self.gpkg_path, {}) - md.saveConnection(conn, 'qgis_test1') + md.saveConnection(conn, "qgis_test1") self.assertEqual(m.count(), 1) - self.assertEqual(m.itemText(0), 'qgis_test1') - self.assertEqual(m.currentConnection(), 'qgis_test1') + self.assertEqual(m.itemText(0), "qgis_test1") + self.assertEqual(m.currentConnection(), "qgis_test1") self.assertEqual(m.currentConnectionUri(), self.gpkg_path) self.assertEqual(len(spy), 1) - self.assertEqual(spy[0][0], 'qgis_test1') + self.assertEqual(spy[0][0], "qgis_test1") - m.setConnection('qgis_test1') + m.setConnection("qgis_test1") self.assertEqual(len(spy), 1) - m.setConnection('') + m.setConnection("") self.assertFalse(m.currentConnection()) self.assertFalse(m.currentConnectionUri()) self.assertEqual(len(spy), 2) self.assertFalse(spy[-1][0]) - m.setConnection('') + m.setConnection("") self.assertEqual(len(spy), 2) self.assertFalse(m.currentConnection()) self.assertFalse(m.currentConnectionUri()) - m.setConnection('qgis_test1') + m.setConnection("qgis_test1") self.assertEqual(len(spy), 3) - self.assertEqual(m.currentConnection(), 'qgis_test1') + self.assertEqual(m.currentConnection(), "qgis_test1") self.assertEqual(m.currentConnectionUri(), self.gpkg_path) - self.assertEqual(spy[-1][0], 'qgis_test1') + self.assertEqual(spy[-1][0], "qgis_test1") conn2 = md.createConnection(self.gpkg_path2, {}) - md.saveConnection(conn2, 'aaa_qgis_test2') + md.saveConnection(conn2, "aaa_qgis_test2") self.assertEqual(m.count(), 2) - self.assertEqual(m.itemText(0), 'aaa_qgis_test2') - self.assertEqual(m.itemText(1), 'qgis_test1') + self.assertEqual(m.itemText(0), "aaa_qgis_test2") + self.assertEqual(m.itemText(1), "qgis_test1") - self.assertEqual(m.currentConnection(), 'qgis_test1') + self.assertEqual(m.currentConnection(), "qgis_test1") self.assertEqual(m.currentConnectionUri(), self.gpkg_path) self.assertEqual(len(spy), 3) - md.deleteConnection('qgis_test1') - self.assertEqual(m.currentConnection(), 'aaa_qgis_test2') + md.deleteConnection("qgis_test1") + self.assertEqual(m.currentConnection(), "aaa_qgis_test2") self.assertEqual(m.currentConnectionUri(), self.gpkg_path2) self.assertEqual(len(spy), 4) - self.assertEqual(spy[-1][0], 'aaa_qgis_test2') + self.assertEqual(spy[-1][0], "aaa_qgis_test2") - md.deleteConnection('aaa_qgis_test2') + md.deleteConnection("aaa_qgis_test2") def testComboSetProvider(self): - """ test combobox functionality with empty entry """ - m = QgsProviderConnectionComboBox('ogr') + """test combobox functionality with empty entry""" + m = QgsProviderConnectionComboBox("ogr") - md = QgsProviderRegistry.instance().providerMetadata('ogr') + md = QgsProviderRegistry.instance().providerMetadata("ogr") conn = md.createConnection(self.gpkg_path, {}) - md.saveConnection(conn, 'qgis_test_zzz') + md.saveConnection(conn, "qgis_test_zzz") self.assertEqual(m.count(), 1) - m.setProvider('ogr') + m.setProvider("ogr") self.assertEqual(m.count(), 1) - md.deleteConnection('qgis_test_zzz') + md.deleteConnection("qgis_test_zzz") def testComboWithEmpty(self): - """ test combobox functionality with empty entry """ - m = QgsProviderConnectionComboBox('ogr') + """test combobox functionality with empty entry""" + m = QgsProviderConnectionComboBox("ogr") m.setAllowEmptyConnection(True) spy = QSignalSpy(m.connectionChanged) self.assertEqual(m.count(), 1) self.assertFalse(m.currentConnection()) self.assertFalse(m.currentConnectionUri()) - md = QgsProviderRegistry.instance().providerMetadata('ogr') + md = QgsProviderRegistry.instance().providerMetadata("ogr") conn = md.createConnection(self.gpkg_path, {}) - md.saveConnection(conn, 'qgis_test1') + md.saveConnection(conn, "qgis_test1") self.assertEqual(m.count(), 2) self.assertFalse(m.itemText(0)) - self.assertEqual(m.itemText(1), 'qgis_test1') + self.assertEqual(m.itemText(1), "qgis_test1") self.assertFalse(m.currentConnection()) self.assertFalse(m.currentConnectionUri()) self.assertEqual(len(spy), 0) - m.setConnection('qgis_test1') + m.setConnection("qgis_test1") self.assertEqual(len(spy), 1) - m.setConnection('') + m.setConnection("") self.assertFalse(m.currentConnection()) self.assertFalse(m.currentConnectionUri()) self.assertEqual(len(spy), 2) self.assertFalse(spy[-1][0]) - m.setConnection('') + m.setConnection("") self.assertEqual(m.currentIndex(), 0) self.assertEqual(len(spy), 2) self.assertFalse(m.currentConnection()) self.assertFalse(m.currentConnectionUri()) - m.setConnection('qgis_test1') + m.setConnection("qgis_test1") self.assertEqual(len(spy), 3) - self.assertEqual(m.currentConnection(), 'qgis_test1') + self.assertEqual(m.currentConnection(), "qgis_test1") self.assertEqual(m.currentConnectionUri(), self.gpkg_path) - self.assertEqual(spy[-1][0], 'qgis_test1') + self.assertEqual(spy[-1][0], "qgis_test1") conn2 = md.createConnection(self.gpkg_path2, {}) - md.saveConnection(conn2, 'aaa_qgis_test2') + md.saveConnection(conn2, "aaa_qgis_test2") self.assertEqual(m.count(), 3) self.assertFalse(m.itemText(0)) - self.assertEqual(m.itemText(1), 'aaa_qgis_test2') - self.assertEqual(m.itemText(2), 'qgis_test1') + self.assertEqual(m.itemText(1), "aaa_qgis_test2") + self.assertEqual(m.itemText(2), "qgis_test1") - self.assertEqual(m.currentConnection(), 'qgis_test1') + self.assertEqual(m.currentConnection(), "qgis_test1") self.assertEqual(m.currentConnectionUri(), self.gpkg_path) self.assertEqual(len(spy), 3) # deleting the selected connection when we are allowing empty # connections should fallback to the empty item - md.deleteConnection('qgis_test1') + md.deleteConnection("qgis_test1") self.assertFalse(m.currentConnection()) self.assertFalse(m.currentConnectionUri()) self.assertEqual(len(spy), 4) self.assertFalse(spy[-1][0]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsproviderconnectionmodel.py b/tests/src/python/test_qgsproviderconnectionmodel.py index 26b8c5020e6c..fd3083e5c97e 100644 --- a/tests/src/python/test_qgsproviderconnectionmodel.py +++ b/tests/src/python/test_qgsproviderconnectionmodel.py @@ -6,9 +6,10 @@ (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '07/08/2020' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "07/08/2020" +__copyright__ = "Copyright 2019, The QGIS Project" import os import shutil @@ -38,17 +39,19 @@ def setUpClass(cls): QCoreApplication.setApplicationName(cls.__name__) start_app() - gpkg_original_path = f'{TEST_DATA_DIR}/qgis_server/test_project_wms_grouped_layers.gpkg' + gpkg_original_path = ( + f"{TEST_DATA_DIR}/qgis_server/test_project_wms_grouped_layers.gpkg" + ) cls.basetestpath = tempfile.mkdtemp() - cls.gpkg_path = f'{cls.basetestpath}/test_gpkg.gpkg' + cls.gpkg_path = f"{cls.basetestpath}/test_gpkg.gpkg" shutil.copy(gpkg_original_path, cls.gpkg_path) - vl = QgsVectorLayer(f'{cls.gpkg_path}|layername=cdb_lines', 'test', 'ogr') + vl = QgsVectorLayer(f"{cls.gpkg_path}|layername=cdb_lines", "test", "ogr") assert vl.isValid() - gpkg2_original_path = f'{TEST_DATA_DIR}/points_gpkg.gpkg' - cls.gpkg_path2 = f'{cls.basetestpath}/test_gpkg2.gpkg' + gpkg2_original_path = f"{TEST_DATA_DIR}/points_gpkg.gpkg" + cls.gpkg_path2 = f"{cls.basetestpath}/test_gpkg2.gpkg" shutil.copy(gpkg2_original_path, cls.gpkg_path2) - vl = QgsVectorLayer(f'{cls.gpkg_path2}', 'test', 'ogr') + vl = QgsVectorLayer(f"{cls.gpkg_path2}", "test", "ogr") assert vl.isValid() @classmethod @@ -61,125 +64,370 @@ def tearDownClass(cls): def test_model(self): """Test model functionality""" - md = QgsProviderRegistry.instance().providerMetadata('ogr') + md = QgsProviderRegistry.instance().providerMetadata("ogr") conn = md.createConnection(self.gpkg_path, {}) - md.saveConnection(conn, 'qgis_test1') + md.saveConnection(conn, "qgis_test1") - model = QgsProviderConnectionModel('ogr') + model = QgsProviderConnectionModel("ogr") self.assertEqual(model.rowCount(), 1) self.assertEqual(model.columnCount(), 1) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'qgis_test1') - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.ToolTipRole), self.gpkg_path) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleConnectionName), 'qgis_test1') - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleUri), self.gpkg_path) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleConfiguration), {}) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "qgis_test1", + ) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.ToolTipRole), + self.gpkg_path, + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleConnectionName, + ), + "qgis_test1", + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleUri, + ), + self.gpkg_path, + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleConfiguration, + ), + {}, + ) - md.saveConnection(conn, 'qgis_test1') + md.saveConnection(conn, "qgis_test1") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'qgis_test1') + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "qgis_test1", + ) conn2 = md.createConnection(self.gpkg_path2, {}) - md.saveConnection(conn2, 'qgis_test2') + md.saveConnection(conn2, "qgis_test2") self.assertEqual(model.rowCount(), 2) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'qgis_test1') - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.ToolTipRole), self.gpkg_path) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleConnectionName), 'qgis_test1') - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleUri), self.gpkg_path) - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'qgis_test2') - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.ToolTipRole), self.gpkg_path2) - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleConnectionName), 'qgis_test2') - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleUri), self.gpkg_path2) - - md.deleteConnection('qgis_test1') + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "qgis_test1", + ) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.ToolTipRole), + self.gpkg_path, + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleConnectionName, + ), + "qgis_test1", + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleUri, + ), + self.gpkg_path, + ) + self.assertEqual( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "qgis_test2", + ) + self.assertEqual( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.ToolTipRole), + self.gpkg_path2, + ) + self.assertEqual( + model.data( + model.index(1, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleConnectionName, + ), + "qgis_test2", + ) + self.assertEqual( + model.data( + model.index(1, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleUri, + ), + self.gpkg_path2, + ) + + md.deleteConnection("qgis_test1") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'qgis_test2') + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "qgis_test2", + ) - md.deleteConnection('qgis_test2') + md.deleteConnection("qgis_test2") def test_model_allow_empty(self): """Test model with empty entry""" - model = QgsProviderConnectionModel('ogr') + model = QgsProviderConnectionModel("ogr") self.assertEqual(model.rowCount(), 0) model.setAllowEmptyConnection(True) self.assertEqual(model.rowCount(), 1) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleEmpty)) - md = QgsProviderRegistry.instance().providerMetadata('ogr') + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertTrue( + model.data( + model.index(0, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleEmpty, + ) + ) + md = QgsProviderRegistry.instance().providerMetadata("ogr") conn = md.createConnection(self.gpkg_path, {}) - md.saveConnection(conn, 'qgis_test1') + md.saveConnection(conn, "qgis_test1") model.setAllowEmptyConnection(False) model.setAllowEmptyConnection(False) self.assertEqual(model.rowCount(), 1) self.assertEqual(model.columnCount(), 1) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'qgis_test1') - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.ToolTipRole), self.gpkg_path) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleConnectionName), 'qgis_test1') - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleUri), self.gpkg_path) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleConfiguration), {}) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleEmpty)) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "qgis_test1", + ) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.ToolTipRole), + self.gpkg_path, + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleConnectionName, + ), + "qgis_test1", + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleUri, + ), + self.gpkg_path, + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleConfiguration, + ), + {}, + ) + self.assertFalse( + model.data( + model.index(0, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleEmpty, + ) + ) model.setAllowEmptyConnection(True) model.setAllowEmptyConnection(True) self.assertEqual(model.rowCount(), 2) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.ToolTipRole)) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleConnectionName)) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleUri)) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleConfiguration)) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleEmpty)) - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'qgis_test1') - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.ToolTipRole), self.gpkg_path) - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleConnectionName), 'qgis_test1') - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleUri), self.gpkg_path) - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleConfiguration), {}) - self.assertFalse(model.data(model.index(1, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleEmpty)) - - md.saveConnection(conn, 'qgis_test1') + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.ToolTipRole) + ) + self.assertFalse( + model.data( + model.index(0, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleConnectionName, + ) + ) + self.assertFalse( + model.data( + model.index(0, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleUri, + ) + ) + self.assertFalse( + model.data( + model.index(0, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleConfiguration, + ) + ) + self.assertTrue( + model.data( + model.index(0, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleEmpty, + ) + ) + self.assertEqual( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "qgis_test1", + ) + self.assertEqual( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.ToolTipRole), + self.gpkg_path, + ) + self.assertEqual( + model.data( + model.index(1, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleConnectionName, + ), + "qgis_test1", + ) + self.assertEqual( + model.data( + model.index(1, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleUri, + ), + self.gpkg_path, + ) + self.assertEqual( + model.data( + model.index(1, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleConfiguration, + ), + {}, + ) + self.assertFalse( + model.data( + model.index(1, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleEmpty, + ) + ) + + md.saveConnection(conn, "qgis_test1") self.assertEqual(model.rowCount(), 2) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleEmpty)) - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'qgis_test1') - self.assertFalse(model.data(model.index(1, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleEmpty)) + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertTrue( + model.data( + model.index(0, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleEmpty, + ) + ) + self.assertEqual( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "qgis_test1", + ) + self.assertFalse( + model.data( + model.index(1, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleEmpty, + ) + ) model.setAllowEmptyConnection(False) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'qgis_test1') - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleEmpty)) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "qgis_test1", + ) + self.assertFalse( + model.data( + model.index(0, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleEmpty, + ) + ) model.setAllowEmptyConnection(True) conn2 = md.createConnection(self.gpkg_path2, {}) - md.saveConnection(conn2, 'qgis_test2') + md.saveConnection(conn2, "qgis_test2") self.assertEqual(model.rowCount(), 3) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertTrue(model.data(model.index(0, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleEmpty)) - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'qgis_test1') - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.ToolTipRole), self.gpkg_path) - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleConnectionName), 'qgis_test1') - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleUri), self.gpkg_path) - self.assertFalse(model.data(model.index(1, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleEmpty)) - self.assertEqual(model.data(model.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'qgis_test2') - self.assertEqual(model.data(model.index(2, 0, QModelIndex()), Qt.ItemDataRole.ToolTipRole), self.gpkg_path2) - self.assertEqual(model.data(model.index(2, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleConnectionName), 'qgis_test2') - self.assertEqual(model.data(model.index(2, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleUri), self.gpkg_path2) - self.assertFalse(model.data(model.index(2, 0, QModelIndex()), QgsProviderConnectionModel.Role.RoleEmpty)) + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertTrue( + model.data( + model.index(0, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleEmpty, + ) + ) + self.assertEqual( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "qgis_test1", + ) + self.assertEqual( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.ToolTipRole), + self.gpkg_path, + ) + self.assertEqual( + model.data( + model.index(1, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleConnectionName, + ), + "qgis_test1", + ) + self.assertEqual( + model.data( + model.index(1, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleUri, + ), + self.gpkg_path, + ) + self.assertFalse( + model.data( + model.index(1, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleEmpty, + ) + ) + self.assertEqual( + model.data(model.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "qgis_test2", + ) + self.assertEqual( + model.data(model.index(2, 0, QModelIndex()), Qt.ItemDataRole.ToolTipRole), + self.gpkg_path2, + ) + self.assertEqual( + model.data( + model.index(2, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleConnectionName, + ), + "qgis_test2", + ) + self.assertEqual( + model.data( + model.index(2, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleUri, + ), + self.gpkg_path2, + ) + self.assertFalse( + model.data( + model.index(2, 0, QModelIndex()), + QgsProviderConnectionModel.Role.RoleEmpty, + ) + ) model.setAllowEmptyConnection(False) self.assertEqual(model.rowCount(), 2) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'qgis_test1') - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'qgis_test2') + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "qgis_test1", + ) + self.assertEqual( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "qgis_test2", + ) model.setAllowEmptyConnection(True) - md.deleteConnection('qgis_test1') + md.deleteConnection("qgis_test1") self.assertEqual(model.rowCount(), 2) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'qgis_test2') + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertEqual( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "qgis_test2", + ) model.setAllowEmptyConnection(False) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'qgis_test2') + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "qgis_test2", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsproviderguiregistry.py b/tests/src/python/test_qgsproviderguiregistry.py index 82fdbd518395..e4c27b60ccfe 100644 --- a/tests/src/python/test_qgsproviderguiregistry.py +++ b/tests/src/python/test_qgsproviderguiregistry.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Mathieu Pellerin' -__date__ = '23/11/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Mathieu Pellerin" +__date__ = "23/11/2021" +__copyright__ = "Copyright 2021, The QGIS Project" import sys @@ -27,18 +28,18 @@ def testProviderList(self): Test provider list """ providers = QgsGui.providerGuiRegistry().providerList() - self.assertIn('ogr', providers) - self.assertIn('gdal', providers) - self.assertIn('wms', providers) - self.assertIn('wms', providers) - self.assertIn('wcs', providers) - self.assertIn('delimitedtext', providers) - self.assertIn('arcgisfeatureserver', providers) - if 'WITH_SPATIALITE=TRUE' in sys.argv: - self.assertIn('spatialite', providers) - self.assertIn('WFS', providers) - self.assertIn('virtual', providers) - - -if __name__ == '__main__': - unittest.main(argv=['WITH_SPATIALITE'], exit=False) + self.assertIn("ogr", providers) + self.assertIn("gdal", providers) + self.assertIn("wms", providers) + self.assertIn("wms", providers) + self.assertIn("wcs", providers) + self.assertIn("delimitedtext", providers) + self.assertIn("arcgisfeatureserver", providers) + if "WITH_SPATIALITE=TRUE" in sys.argv: + self.assertIn("spatialite", providers) + self.assertIn("WFS", providers) + self.assertIn("virtual", providers) + + +if __name__ == "__main__": + unittest.main(argv=["WITH_SPATIALITE"], exit=False) diff --git a/tests/src/python/test_qgsproviderregistry.py b/tests/src/python/test_qgsproviderregistry.py index efd95b981446..28b209f87561 100644 --- a/tests/src/python/test_qgsproviderregistry.py +++ b/tests/src/python/test_qgsproviderregistry.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '16/03/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "16/03/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.core import ( Qgis, @@ -61,8 +62,8 @@ def testProviderList(self): """ providers = QgsProviderRegistry.instance().providerList() - self.assertIn('ogr', providers) - self.assertIn('gdal', providers) + self.assertIn("ogr", providers) + self.assertIn("gdal", providers) def testProviderMetadata(self): """ @@ -76,23 +77,31 @@ def testProviderMetadata(self): self.assertTrue(QgsProviderRegistry.instance().providerMetadata(p.lower())) self.assertTrue(QgsProviderRegistry.instance().providerMetadata(p.upper())) - self.assertIsNone(QgsProviderRegistry.instance().providerMetadata('asdasdasdasdasd')) + self.assertIsNone( + QgsProviderRegistry.instance().providerMetadata("asdasdasdasdasd") + ) def testProvidersForLayerType(self): """ Test retrieving providers for a layer type """ - providers = QgsProviderRegistry.instance().providersForLayerType(QgsMapLayerType.VectorLayer) - self.assertIn('ogr', providers) - self.assertIn('memory', providers) - self.assertNotIn('gdal', providers) + providers = QgsProviderRegistry.instance().providersForLayerType( + QgsMapLayerType.VectorLayer + ) + self.assertIn("ogr", providers) + self.assertIn("memory", providers) + self.assertNotIn("gdal", providers) - providers = QgsProviderRegistry.instance().providersForLayerType(QgsMapLayerType.RasterLayer) - self.assertNotIn('ogr', providers) - self.assertNotIn('memory', providers) - self.assertIn('gdal', providers) + providers = QgsProviderRegistry.instance().providersForLayerType( + QgsMapLayerType.RasterLayer + ) + self.assertNotIn("ogr", providers) + self.assertNotIn("memory", providers) + self.assertIn("gdal", providers) - providers = QgsProviderRegistry.instance().providersForLayerType(QgsMapLayerType.AnnotationLayer) + providers = QgsProviderRegistry.instance().providersForLayerType( + QgsMapLayerType.AnnotationLayer + ) self.assertFalse(providers) def testCreateProvider(self): @@ -101,68 +110,127 @@ def testCreateProvider(self): """ providers = QgsProviderRegistry.instance().providerList() for p in providers: - if p in ('vectortile', 'arcgisvectortileservice', 'tiledscene'): + if p in ("vectortile", "arcgisvectortileservice", "tiledscene"): continue - self.assertTrue(QgsProviderRegistry.instance().createProvider(p, '')) + self.assertTrue(QgsProviderRegistry.instance().createProvider(p, "")) # should be case-insensitive - self.assertTrue(QgsProviderRegistry.instance().createProvider(p.lower(), '')) - self.assertTrue(QgsProviderRegistry.instance().createProvider(p.upper(), '')) - - self.assertIsNone(QgsProviderRegistry.instance().createProvider('asdasdasdasdasd', '')) + self.assertTrue( + QgsProviderRegistry.instance().createProvider(p.lower(), "") + ) + self.assertTrue( + QgsProviderRegistry.instance().createProvider(p.upper(), "") + ) + + self.assertIsNone( + QgsProviderRegistry.instance().createProvider("asdasdasdasdasd", "") + ) - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testShouldDeferUriForOtherProvidersEpt(self): - self.assertTrue(QgsProviderRegistry.instance().shouldDeferUriForOtherProviders('/home/nyall/ept.json', 'ogr')) - self.assertFalse(QgsProviderRegistry.instance().shouldDeferUriForOtherProviders('/home/nyall/ept.json', 'ept')) - self.assertFalse(QgsProviderRegistry.instance().shouldDeferUriForOtherProviders('/home/nyall/my.json', 'ogr')) + self.assertTrue( + QgsProviderRegistry.instance().shouldDeferUriForOtherProviders( + "/home/nyall/ept.json", "ogr" + ) + ) + self.assertFalse( + QgsProviderRegistry.instance().shouldDeferUriForOtherProviders( + "/home/nyall/ept.json", "ept" + ) + ) + self.assertFalse( + QgsProviderRegistry.instance().shouldDeferUriForOtherProviders( + "/home/nyall/my.json", "ogr" + ) + ) def testUriIsBlocklisted(self): - self.assertFalse(QgsProviderRegistry.instance().uriIsBlocklisted('/home/nyall/me.tif')) - self.assertFalse(QgsProviderRegistry.instance().uriIsBlocklisted('/home/nyall/me.shp')) + self.assertFalse( + QgsProviderRegistry.instance().uriIsBlocklisted("/home/nyall/me.tif") + ) + self.assertFalse( + QgsProviderRegistry.instance().uriIsBlocklisted("/home/nyall/me.shp") + ) # internal details only -- we should be hiding these uris! - self.assertTrue(QgsProviderRegistry.instance().uriIsBlocklisted('/home/nyall/me.shp.xml')) - self.assertTrue(QgsProviderRegistry.instance().uriIsBlocklisted('/home/nyall/me.aux.xml')) - self.assertTrue(QgsProviderRegistry.instance().uriIsBlocklisted('/home/nyall/me.AUX.XML')) - self.assertTrue(QgsProviderRegistry.instance().uriIsBlocklisted('/home/nyall/me.tif.aux.xml')) - self.assertTrue(QgsProviderRegistry.instance().uriIsBlocklisted('/home/nyall/me.tif.AUX.XML')) - self.assertTrue(QgsProviderRegistry.instance().uriIsBlocklisted('/home/nyall/me.png.aux.xml')) - self.assertTrue(QgsProviderRegistry.instance().uriIsBlocklisted('/home/nyall/me.tif.xml')) - - @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + self.assertTrue( + QgsProviderRegistry.instance().uriIsBlocklisted("/home/nyall/me.shp.xml") + ) + self.assertTrue( + QgsProviderRegistry.instance().uriIsBlocklisted("/home/nyall/me.aux.xml") + ) + self.assertTrue( + QgsProviderRegistry.instance().uriIsBlocklisted("/home/nyall/me.AUX.XML") + ) + self.assertTrue( + QgsProviderRegistry.instance().uriIsBlocklisted( + "/home/nyall/me.tif.aux.xml" + ) + ) + self.assertTrue( + QgsProviderRegistry.instance().uriIsBlocklisted( + "/home/nyall/me.tif.AUX.XML" + ) + ) + self.assertTrue( + QgsProviderRegistry.instance().uriIsBlocklisted( + "/home/nyall/me.png.aux.xml" + ) + ) + self.assertTrue( + QgsProviderRegistry.instance().uriIsBlocklisted("/home/nyall/me.tif.xml") + ) + + @unittest.skipIf( + "ept" not in QgsProviderRegistry.instance().providerList(), + "EPT provider not available", + ) def testFilePointCloudFilters(self): - parts = QgsProviderRegistry.instance().filePointCloudFilters().split(';;') - self.assertTrue(parts[0].startswith('All Supported Files (')) + parts = QgsProviderRegistry.instance().filePointCloudFilters().split(";;") + self.assertTrue(parts[0].startswith("All Supported Files (")) all_filter = parts[0][21:-1] - self.assertIn('ept.json', all_filter.split(' ')) - self.assertIn('EPT.JSON', all_filter.split(' ')) + self.assertIn("ept.json", all_filter.split(" ")) + self.assertIn("EPT.JSON", all_filter.split(" ")) - self.assertEqual(parts[1], 'All Files (*.*)') - self.assertIn('Entwine Point Clouds (ept.json EPT.JSON)', parts) + self.assertEqual(parts[1], "All Files (*.*)") + self.assertIn("Entwine Point Clouds (ept.json EPT.JSON)", parts) def testUnusableUriDetails(self): """ Test retrieving user-friendly details about an unusable URI """ - res, details = QgsProviderRegistry.instance().handleUnusableUri('') + res, details = QgsProviderRegistry.instance().handleUnusableUri("") self.assertFalse(res) - res, details = QgsProviderRegistry.instance().handleUnusableUri('/home/me/test.png') + res, details = QgsProviderRegistry.instance().handleUnusableUri( + "/home/me/test.png" + ) self.assertFalse(res) - res, details = QgsProviderRegistry.instance().handleUnusableUri('/home/me/test.las') + res, details = QgsProviderRegistry.instance().handleUnusableUri( + "/home/me/test.las" + ) self.assertTrue(res) - self.assertIn('LAS', details.warning) - res, details = QgsProviderRegistry.instance().handleUnusableUri('/home/me/test.laz') + self.assertIn("LAS", details.warning) + res, details = QgsProviderRegistry.instance().handleUnusableUri( + "/home/me/test.laz" + ) self.assertTrue(res) - self.assertIn('LAZ', details.warning) + self.assertIn("LAZ", details.warning) def testSublayerDetails(self): - ept_provider_metadata = QgsProviderRegistry.instance().providerMetadata('ept') - ogr_provider_metadata = QgsProviderRegistry.instance().providerMetadata('ogr') + ept_provider_metadata = QgsProviderRegistry.instance().providerMetadata("ept") + ogr_provider_metadata = QgsProviderRegistry.instance().providerMetadata("ogr") if ept_provider_metadata is not None: # test querying a uri which should be blocklisted - self.assertFalse(QgsProviderRegistry.instance().querySublayers(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept-build.json')) + self.assertFalse( + QgsProviderRegistry.instance().querySublayers( + unitTestDataPath() + + "/point_clouds/ept/sunshine-coast/ept-build.json" + ) + ) if ept_provider_metadata is not None and ogr_provider_metadata is not None: # test querying a uri which is technically capable of being opened by two providers, but which one provider is preferred @@ -170,46 +238,81 @@ def testSublayerDetails(self): # the OGR provider CAN technically open json files # when we directly query ogr provider metadata it should report sublayers for the json file... - self.assertEqual([l.providerKey() for l in ogr_provider_metadata.querySublayers( - unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', Qgis.SublayerQueryFlags(Qgis.SublayerQueryFlag.FastScan))], ['ogr']) + self.assertEqual( + [ + l.providerKey() + for l in ogr_provider_metadata.querySublayers( + unitTestDataPath() + + "/point_clouds/ept/sunshine-coast/ept.json", + Qgis.SublayerQueryFlags(Qgis.SublayerQueryFlag.FastScan), + ) + ], + ["ogr"], + ) # ...and when we query ept provider metadata directly it should also report sublayers for ept.json files... - self.assertEqual([l.providerKey() for l in ept_provider_metadata.querySublayers( - unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', Qgis.SublayerQueryFlags(Qgis.SublayerQueryFlag.FastScan))], ['ept']) + self.assertEqual( + [ + l.providerKey() + for l in ept_provider_metadata.querySublayers( + unitTestDataPath() + + "/point_clouds/ept/sunshine-coast/ept.json", + Qgis.SublayerQueryFlags(Qgis.SublayerQueryFlag.FastScan), + ) + ], + ["ept"], + ) # ... but when we query the provider registry itself, it should ONLY report the ept provider sublayers - self.assertEqual([l.providerKey() for l in QgsProviderRegistry.instance().querySublayers(unitTestDataPath() + '/point_clouds/ept/sunshine-coast/ept.json', Qgis.SublayerQueryFlags(Qgis.SublayerQueryFlag.FastScan))], ['ept']) - - provider1 = TestProviderMetadata('p1') - provider2 = TestProviderMetadata('p2') - - self.assertFalse(QgsProviderRegistry.instance().querySublayers('test_uri')) + self.assertEqual( + [ + l.providerKey() + for l in QgsProviderRegistry.instance().querySublayers( + unitTestDataPath() + + "/point_clouds/ept/sunshine-coast/ept.json", + Qgis.SublayerQueryFlags(Qgis.SublayerQueryFlag.FastScan), + ) + ], + ["ept"], + ) + + provider1 = TestProviderMetadata("p1") + provider2 = TestProviderMetadata("p2") + + self.assertFalse(QgsProviderRegistry.instance().querySublayers("test_uri")) self.assertTrue(QgsProviderRegistry.instance().registerProvider(provider1)) self.assertTrue(QgsProviderRegistry.instance().registerProvider(provider2)) - self.assertCountEqual([p.providerKey() for p in QgsProviderRegistry.instance().querySublayers('test_uri')], - ['p1', 'p2']) + self.assertCountEqual( + [ + p.providerKey() + for p in QgsProviderRegistry.instance().querySublayers("test_uri") + ], + ["p1", "p2"], + ) def test_tiled_scene_file_filters(self): """ Test fileTiledSceneFilters() """ registry = QgsProviderRegistry.instance() - self.assertEqual(registry.fileTiledSceneFilters(), - 'All Supported Files (tileset.json TILESET.JSON);;' - 'All Files (*.*);;' - 'Cesium 3D Tiles (tileset.json TILESET.JSON)') + self.assertEqual( + registry.fileTiledSceneFilters(), + "All Supported Files (tileset.json TILESET.JSON);;" + "All Files (*.*);;" + "Cesium 3D Tiles (tileset.json TILESET.JSON)", + ) - registry.registerProvider(TestProviderTiledSceneMetadata('slpk')) + registry.registerProvider(TestProviderTiledSceneMetadata("slpk")) self.assertEqual( registry.fileTiledSceneFilters(), - 'All Supported Files (tileset.json TILESET.JSON *.slpk *.SLPK);;' - 'All Files (*.*);;' - 'Cesium 3D Tiles (tileset.json TILESET.JSON);;' - 'Scene Layer Packages (*.slpk *.SLPK)' + "All Supported Files (tileset.json TILESET.JSON *.slpk *.SLPK);;" + "All Files (*.*);;" + "Cesium 3D Tiles (tileset.json TILESET.JSON);;" + "Scene Layer Packages (*.slpk *.SLPK)", ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprovidersqlquerybuilder.py b/tests/src/python/test_qgsprovidersqlquerybuilder.py index 3f9debe479fd..d44f87fe11d5 100644 --- a/tests/src/python/test_qgsprovidersqlquerybuilder.py +++ b/tests/src/python/test_qgsprovidersqlquerybuilder.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '25/08/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "25/08/2022" +__copyright__ = "Copyright 2022, The QGIS Project" import os import shutil @@ -26,16 +27,22 @@ class TestQgsProviderSqlQueryBuilder(QgisTestCase): def test_quoted_identifier(self): builder = QgsProviderSqlQueryBuilder() - self.assertEqual(builder.quoteIdentifier('a'), '"a"') - self.assertEqual(builder.quoteIdentifier('a table'), '"a table"') - self.assertEqual(builder.quoteIdentifier('a TABLE'), '"a TABLE"') + self.assertEqual(builder.quoteIdentifier("a"), '"a"') + self.assertEqual(builder.quoteIdentifier("a table"), '"a table"') + self.assertEqual(builder.quoteIdentifier("a TABLE"), '"a TABLE"') self.assertEqual(builder.quoteIdentifier('a "TABLE"'), '"a ""TABLE"""') def test_limit_query(self): builder = QgsProviderSqlQueryBuilder() - self.assertEqual(builder.createLimitQueryForTable('my_schema', 'my_table', 99), 'SELECT * FROM "my_schema"."my_table" LIMIT 99') - self.assertEqual(builder.createLimitQueryForTable(None, 'my_table', 99), 'SELECT * FROM "my_table" LIMIT 99') + self.assertEqual( + builder.createLimitQueryForTable("my_schema", "my_table", 99), + 'SELECT * FROM "my_schema"."my_table" LIMIT 99', + ) + self.assertEqual( + builder.createLimitQueryForTable(None, "my_table", 99), + 'SELECT * FROM "my_table" LIMIT 99', + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprovidersublayerdetails.py b/tests/src/python/test_qgsprovidersublayerdetails.py index 18eedeff3a31..0812b281a37f 100644 --- a/tests/src/python/test_qgsprovidersublayerdetails.py +++ b/tests/src/python/test_qgsprovidersublayerdetails.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '16/03/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "16/03/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import os @@ -36,23 +37,23 @@ def testGettersSetters(self): Test provider list """ d = QgsProviderSublayerDetails() - d.setProviderKey('key') - self.assertEqual(d.providerKey(), 'key') + d.setProviderKey("key") + self.assertEqual(d.providerKey(), "key") d.setType(QgsMapLayerType.MeshLayer) self.assertEqual(d.type(), QgsMapLayerType.MeshLayer) - d.setUri('some uri') - self.assertEqual(d.uri(), 'some uri') + d.setUri("some uri") + self.assertEqual(d.uri(), "some uri") - d.setName('name') - self.assertEqual(d.name(), 'name') + d.setName("name") + self.assertEqual(d.name(), "name") - d.setDescription('desc') - self.assertEqual(d.description(), 'desc') + d.setDescription("desc") + self.assertEqual(d.description(), "desc") - d.setPath(['a', 'b', 'c']) - self.assertEqual(d.path(), ['a', 'b', 'c']) + d.setPath(["a", "b", "c"]) + self.assertEqual(d.path(), ["a", "b", "c"]) self.assertEqual(d.featureCount(), Qgis.FeatureCountState.UnknownCount) d.setFeatureCount(1000) @@ -62,14 +63,14 @@ def testGettersSetters(self): d.setWkbType(QgsWkbTypes.Type.Point) self.assertEqual(d.wkbType(), QgsWkbTypes.Type.Point) - d.setGeometryColumnName('geom_col') - self.assertEqual(d.geometryColumnName(), 'geom_col') + d.setGeometryColumnName("geom_col") + self.assertEqual(d.geometryColumnName(), "geom_col") d.setLayerNumber(13) self.assertEqual(d.layerNumber(), 13) - d.setDriverName('drv') - self.assertEqual(d.driverName(), 'drv') + d.setDriverName("drv") + self.assertEqual(d.driverName(), "drv") d.setSkippedContainerScan(True) self.assertTrue(d.skippedContainerScan()) @@ -87,9 +88,9 @@ def test_equality(self): """ d = QgsProviderSublayerDetails() d2 = QgsProviderSublayerDetails() - d.setProviderKey('key') + d.setProviderKey("key") self.assertNotEqual(d, d2) - d2.setProviderKey('key') + d2.setProviderKey("key") self.assertEqual(d, d2) d.setType(QgsMapLayerType.MeshLayer) @@ -97,24 +98,24 @@ def test_equality(self): d2.setType(QgsMapLayerType.MeshLayer) self.assertEqual(d, d2) - d.setUri('some uri') + d.setUri("some uri") self.assertNotEqual(d, d2) - d2.setUri('some uri') + d2.setUri("some uri") self.assertEqual(d, d2) - d.setName('name') + d.setName("name") self.assertNotEqual(d, d2) - d2.setName('name') + d2.setName("name") self.assertEqual(d, d2) - d.setDescription('desc') + d.setDescription("desc") self.assertNotEqual(d, d2) - d2.setDescription('desc') + d2.setDescription("desc") self.assertEqual(d, d2) - d.setPath(['a', 'b', 'c']) + d.setPath(["a", "b", "c"]) self.assertNotEqual(d, d2) - d2.setPath(['a', 'b', 'c']) + d2.setPath(["a", "b", "c"]) self.assertEqual(d, d2) d.setFeatureCount(1000) @@ -127,9 +128,9 @@ def test_equality(self): d2.setWkbType(QgsWkbTypes.Type.Point) self.assertEqual(d, d2) - d.setGeometryColumnName('geom_col') + d.setGeometryColumnName("geom_col") self.assertNotEqual(d, d2) - d2.setGeometryColumnName('geom_col') + d2.setGeometryColumnName("geom_col") self.assertEqual(d, d2) d.setLayerNumber(13) @@ -137,9 +138,9 @@ def test_equality(self): d2.setLayerNumber(13) self.assertEqual(d, d2) - d.setDriverName('drv') + d.setDriverName("drv") self.assertNotEqual(d, d2) - d2.setDriverName('drv') + d2.setDriverName("drv") self.assertEqual(d, d2) d.setSkippedContainerScan(True) @@ -157,61 +158,63 @@ def test_to_layer(self): Test converting sub layer details to a layer """ details = QgsProviderSublayerDetails() - details.setUri(os.path.join(unitTestDataPath(), 'lines.shp')) - details.setName('my sub layer') + details.setUri(os.path.join(unitTestDataPath(), "lines.shp")) + details.setName("my sub layer") details.setType(QgsMapLayerType.VectorLayer) - details.setProviderKey('ogr') + details.setProviderKey("ogr") - options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext()) + options = QgsProviderSublayerDetails.LayerOptions( + QgsCoordinateTransformContext() + ) ml = details.toLayer(options) self.assertTrue(ml.isValid()) self.assertIsInstance(ml, QgsVectorLayer) - self.assertEqual(ml.name(), 'my sub layer') + self.assertEqual(ml.name(), "my sub layer") def test_to_mime(self): """ Test converting sub layer details to mime URIs """ details = QgsProviderSublayerDetails() - details.setUri(os.path.join(unitTestDataPath(), 'lines.shp')) - details.setName('my sub layer') + details.setUri(os.path.join(unitTestDataPath(), "lines.shp")) + details.setName("my sub layer") details.setType(QgsMapLayerType.VectorLayer) - details.setProviderKey('ogr') + details.setProviderKey("ogr") uri = details.toMimeUri() - self.assertEqual(uri.layerType, 'vector') - self.assertEqual(uri.providerKey, 'ogr') - self.assertEqual(uri.name, 'my sub layer') - self.assertEqual(uri.uri, os.path.join(unitTestDataPath(), 'lines.shp')) + self.assertEqual(uri.layerType, "vector") + self.assertEqual(uri.providerKey, "ogr") + self.assertEqual(uri.name, "my sub layer") + self.assertEqual(uri.uri, os.path.join(unitTestDataPath(), "lines.shp")) details.setType(QgsMapLayerType.RasterLayer) uri = details.toMimeUri() - self.assertEqual(uri.layerType, 'raster') + self.assertEqual(uri.layerType, "raster") details.setType(QgsMapLayerType.MeshLayer) uri = details.toMimeUri() - self.assertEqual(uri.layerType, 'mesh') + self.assertEqual(uri.layerType, "mesh") details.setType(QgsMapLayerType.VectorTileLayer) uri = details.toMimeUri() - self.assertEqual(uri.layerType, 'vector-tile') + self.assertEqual(uri.layerType, "vector-tile") details.setType(QgsMapLayerType.PointCloudLayer) uri = details.toMimeUri() - self.assertEqual(uri.layerType, 'pointcloud') + self.assertEqual(uri.layerType, "pointcloud") details.setType(QgsMapLayerType.PluginLayer) uri = details.toMimeUri() - self.assertEqual(uri.layerType, 'plugin') + self.assertEqual(uri.layerType, "plugin") details.setType(QgsMapLayerType.GroupLayer) uri = details.toMimeUri() - self.assertEqual(uri.layerType, 'group') + self.assertEqual(uri.layerType, "group") details.setType(QgsMapLayerType.AnnotationLayer) uri = details.toMimeUri() - self.assertEqual(uri.layerType, 'annotation') + self.assertEqual(uri.layerType, "annotation") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprovidersublayermodel.py b/tests/src/python/test_qgsprovidersublayermodel.py index bed1bd3c3335..1a692b9ffc8d 100644 --- a/tests/src/python/test_qgsprovidersublayermodel.py +++ b/tests/src/python/test_qgsprovidersublayermodel.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '05/07/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "05/07/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QModelIndex, Qt from qgis.core import ( @@ -32,169 +33,365 @@ def test_model(self): model = QgsProviderSublayerModel() self.assertEqual(model.rowCount(QModelIndex()), 0) self.assertEqual(model.columnCount(QModelIndex()), 2) - self.assertEqual(model.headerData(0, Qt.Orientation.Horizontal, Qt.ItemDataRole.DisplayRole), 'Item') - self.assertEqual(model.headerData(0, Qt.Orientation.Horizontal, Qt.ItemDataRole.ToolTipRole), 'Item') - self.assertEqual(model.headerData(1, Qt.Orientation.Horizontal, Qt.ItemDataRole.DisplayRole), 'Description') - self.assertEqual(model.headerData(1, Qt.Orientation.Horizontal, Qt.ItemDataRole.ToolTipRole), 'Description') + self.assertEqual( + model.headerData(0, Qt.Orientation.Horizontal, Qt.ItemDataRole.DisplayRole), + "Item", + ) + self.assertEqual( + model.headerData(0, Qt.Orientation.Horizontal, Qt.ItemDataRole.ToolTipRole), + "Item", + ) + self.assertEqual( + model.headerData(1, Qt.Orientation.Horizontal, Qt.ItemDataRole.DisplayRole), + "Description", + ) + self.assertEqual( + model.headerData(1, Qt.Orientation.Horizontal, Qt.ItemDataRole.ToolTipRole), + "Description", + ) # no crash, should return invalid results self.assertFalse(model.indexToSublayer(model.index(0, 0, QModelIndex())).name()) - self.assertFalse(model.indexToNonLayerItem(model.index(0, 0, QModelIndex())).name()) + self.assertFalse( + model.indexToNonLayerItem(model.index(0, 0, QModelIndex())).name() + ) layer1 = QgsProviderSublayerDetails() layer1.setType(QgsMapLayerType.RasterLayer) - layer1.setName('layer 1') - layer1.setDescription('description 1') - layer1.setProviderKey('gdal') - layer1.setUri('uri 1') + layer1.setName("layer 1") + layer1.setDescription("description 1") + layer1.setProviderKey("gdal") + layer1.setUri("uri 1") model.setSublayerDetails([layer1]) self.assertEqual(model.rowCount(QModelIndex()), 1) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'layer 1') - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 'description 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.ProviderKey), 'gdal') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.RasterLayer) - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Uri), 'uri 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Name), 'layer 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Description), 'description 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Flags), 0) - - self.assertEqual(model.indexToSublayer(model.index(0, 0, QModelIndex())), layer1) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "layer 1" + ) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "description 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.ProviderKey), + "gdal", + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.RasterLayer, + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Uri), "uri 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Name), "layer 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Description), + "description 1", + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Flags), 0 + ) + + self.assertEqual( + model.indexToSublayer(model.index(0, 0, QModelIndex())), layer1 + ) self.assertFalse(model.indexToSublayer(model.index(1, 0, QModelIndex())).name()) - self.assertFalse(model.indexToNonLayerItem(model.index(0, 0, QModelIndex())).name()) + self.assertFalse( + model.indexToNonLayerItem(model.index(0, 0, QModelIndex())).name() + ) layer2 = QgsProviderSublayerDetails() layer2.setType(QgsMapLayerType.VectorLayer) - layer2.setName('layer 2') - layer2.setDescription('description 2') - layer2.setProviderKey('ogr') - layer2.setUri('uri 2') + layer2.setName("layer 2") + layer2.setDescription("description 2") + layer2.setProviderKey("ogr") + layer2.setUri("uri 2") layer2.setFeatureCount(-1) layer2.setWkbType(QgsWkbTypes.Type.LineString) layer2.setFlags(Qgis.SublayerFlags(Qgis.SublayerFlag.SystemTable)) model.setSublayerDetails([layer1, layer2]) self.assertEqual(model.rowCount(QModelIndex()), 2) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'layer 1') - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 'description 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.ProviderKey), 'gdal') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.RasterLayer) - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Uri), 'uri 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Name), 'layer 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Description), 'description 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Flags), 0) - - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'layer 2') - self.assertEqual(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), 'description 2 - LineString (Uncounted)') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.ProviderKey), 'ogr') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.VectorLayer) - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Uri), 'uri 2') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Name), 'layer 2') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Description), 'description 2') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Flags), 1) - - self.assertEqual(model.indexToSublayer(model.index(0, 0, QModelIndex())), layer1) - self.assertEqual(model.indexToSublayer(model.index(1, 0, QModelIndex())), layer2) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "layer 1" + ) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "description 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.ProviderKey), + "gdal", + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.RasterLayer, + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Uri), "uri 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Name), "layer 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Description), + "description 1", + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Flags), 0 + ) + + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "layer 2" + ) + self.assertEqual( + model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), + "description 2 - LineString (Uncounted)", + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.ProviderKey), + "ogr", + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.VectorLayer, + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Uri), "uri 2" + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Name), "layer 2" + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Description), + "description 2", + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Flags), 1 + ) + + self.assertEqual( + model.indexToSublayer(model.index(0, 0, QModelIndex())), layer1 + ) + self.assertEqual( + model.indexToSublayer(model.index(1, 0, QModelIndex())), layer2 + ) self.assertFalse(model.indexToSublayer(model.index(2, 0, QModelIndex())).name()) - self.assertFalse(model.indexToNonLayerItem(model.index(0, 0, QModelIndex())).name()) + self.assertFalse( + model.indexToNonLayerItem(model.index(0, 0, QModelIndex())).name() + ) layer3 = QgsProviderSublayerDetails() layer3.setType(QgsMapLayerType.VectorLayer) - layer3.setName('layer 3') - layer3.setProviderKey('ogr') - layer3.setUri('uri 3') + layer3.setName("layer 3") + layer3.setProviderKey("ogr") + layer3.setUri("uri 3") layer3.setFeatureCount(1001) layer3.setWkbType(QgsWkbTypes.Type.Polygon) model.setSublayerDetails([layer1, layer2, layer3]) self.assertEqual(model.rowCount(QModelIndex()), 3) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'layer 1') - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 'description 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.ProviderKey), 'gdal') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.RasterLayer) - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Uri), 'uri 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Name), 'layer 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Description), 'description 1') - - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'layer 2') - self.assertEqual(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), 'description 2 - LineString (Uncounted)') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.ProviderKey), 'ogr') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.VectorLayer) - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Uri), 'uri 2') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Name), 'layer 2') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Description), 'description 2') - - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'layer 3') - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 'Polygon (1,001)') - self.assertEqual(model.data(model.index(2, 0), QgsProviderSublayerModel.Role.ProviderKey), 'ogr') - self.assertEqual(model.data(model.index(2, 0), QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.VectorLayer) - self.assertEqual(model.data(model.index(2, 0), QgsProviderSublayerModel.Role.Uri), 'uri 3') - self.assertEqual(model.data(model.index(2, 0), QgsProviderSublayerModel.Role.Name), 'layer 3') - self.assertEqual(model.data(model.index(2, 0), QgsProviderSublayerModel.Role.Description), None) - - self.assertEqual(model.indexToSublayer(model.index(0, 0, QModelIndex())), layer1) - self.assertEqual(model.indexToSublayer(model.index(1, 0, QModelIndex())), layer2) - self.assertEqual(model.indexToSublayer(model.index(2, 0, QModelIndex())), layer3) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "layer 1" + ) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "description 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.ProviderKey), + "gdal", + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.RasterLayer, + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Uri), "uri 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Name), "layer 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Description), + "description 1", + ) + + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "layer 2" + ) + self.assertEqual( + model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), + "description 2 - LineString (Uncounted)", + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.ProviderKey), + "ogr", + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.VectorLayer, + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Uri), "uri 2" + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Name), "layer 2" + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Description), + "description 2", + ) + + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "layer 3" + ) + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), + "Polygon (1,001)", + ) + self.assertEqual( + model.data(model.index(2, 0), QgsProviderSublayerModel.Role.ProviderKey), + "ogr", + ) + self.assertEqual( + model.data(model.index(2, 0), QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.VectorLayer, + ) + self.assertEqual( + model.data(model.index(2, 0), QgsProviderSublayerModel.Role.Uri), "uri 3" + ) + self.assertEqual( + model.data(model.index(2, 0), QgsProviderSublayerModel.Role.Name), "layer 3" + ) + self.assertEqual( + model.data(model.index(2, 0), QgsProviderSublayerModel.Role.Description), + None, + ) + + self.assertEqual( + model.indexToSublayer(model.index(0, 0, QModelIndex())), layer1 + ) + self.assertEqual( + model.indexToSublayer(model.index(1, 0, QModelIndex())), layer2 + ) + self.assertEqual( + model.indexToSublayer(model.index(2, 0, QModelIndex())), layer3 + ) self.assertFalse(model.indexToSublayer(model.index(3, 0, QModelIndex())).name()) - self.assertFalse(model.indexToNonLayerItem(model.index(0, 0, QModelIndex())).name()) + self.assertFalse( + model.indexToNonLayerItem(model.index(0, 0, QModelIndex())).name() + ) # remove a layer model.setSublayerDetails([layer3, layer1]) self.assertEqual(model.rowCount(QModelIndex()), 2) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'layer 1') - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 'description 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.ProviderKey), 'gdal') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.RasterLayer) - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Uri), 'uri 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Name), 'layer 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Description), 'description 1') - - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'layer 3') - self.assertEqual(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), 'Polygon (1,001)') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.ProviderKey), 'ogr') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.VectorLayer) - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Uri), 'uri 3') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Name), 'layer 3') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Description), None) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "layer 1" + ) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "description 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.ProviderKey), + "gdal", + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.RasterLayer, + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Uri), "uri 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Name), "layer 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Description), + "description 1", + ) + + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "layer 3" + ) + self.assertEqual( + model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), + "Polygon (1,001)", + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.ProviderKey), + "ogr", + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.VectorLayer, + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Uri), "uri 3" + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Name), "layer 3" + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Description), + None, + ) # remove another layer model.setSublayerDetails([layer3]) self.assertEqual(model.rowCount(QModelIndex()), 1) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'layer 3') - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 'Polygon (1,001)') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.ProviderKey), 'ogr') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.VectorLayer) - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Uri), 'uri 3') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Name), 'layer 3') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Description), None) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "layer 3" + ) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), + "Polygon (1,001)", + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.ProviderKey), + "ogr", + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.VectorLayer, + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Uri), "uri 3" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Name), "layer 3" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Description), + None, + ) def test_non_layer_item(self): item1 = QgsProviderSublayerModel.NonLayerItem() - item1.setUri('item uri 1') - item1.setName('item name 1') - item1.setType('item type 1') - item1.setDescription('item desc 1') + item1.setUri("item uri 1") + item1.setName("item name 1") + item1.setType("item type 1") + item1.setDescription("item desc 1") item2 = QgsProviderSublayerModel.NonLayerItem(item1) self.assertEqual(item1, item2) self.assertFalse(item1 != item2) - item2.setUri('uu') + item2.setUri("uu") self.assertNotEqual(item1, item2) self.assertTrue(item1 != item2) item2 = QgsProviderSublayerModel.NonLayerItem(item1) - item2.setName('item name 2') + item2.setName("item name 2") self.assertNotEqual(item1, item2) self.assertTrue(item1 != item2) item2 = QgsProviderSublayerModel.NonLayerItem(item1) - item2.setType('item type 2') + item2.setType("item type 2") self.assertNotEqual(item1, item2) self.assertTrue(item1 != item2) item2 = QgsProviderSublayerModel.NonLayerItem(item1) - item2.setDescription('item description 2') + item2.setDescription("item description 2") self.assertNotEqual(item1, item2) self.assertTrue(item1 != item2) @@ -202,179 +399,449 @@ def test_model_with_non_layer_items(self): model = QgsProviderSublayerModel() self.assertEqual(model.rowCount(QModelIndex()), 0) self.assertEqual(model.columnCount(QModelIndex()), 2) - self.assertEqual(model.headerData(0, Qt.Orientation.Horizontal, Qt.ItemDataRole.DisplayRole), 'Item') - self.assertEqual(model.headerData(0, Qt.Orientation.Horizontal, Qt.ItemDataRole.ToolTipRole), 'Item') - self.assertEqual(model.headerData(1, Qt.Orientation.Horizontal, Qt.ItemDataRole.DisplayRole), 'Description') - self.assertEqual(model.headerData(1, Qt.Orientation.Horizontal, Qt.ItemDataRole.ToolTipRole), 'Description') + self.assertEqual( + model.headerData(0, Qt.Orientation.Horizontal, Qt.ItemDataRole.DisplayRole), + "Item", + ) + self.assertEqual( + model.headerData(0, Qt.Orientation.Horizontal, Qt.ItemDataRole.ToolTipRole), + "Item", + ) + self.assertEqual( + model.headerData(1, Qt.Orientation.Horizontal, Qt.ItemDataRole.DisplayRole), + "Description", + ) + self.assertEqual( + model.headerData(1, Qt.Orientation.Horizontal, Qt.ItemDataRole.ToolTipRole), + "Description", + ) layer1 = QgsProviderSublayerDetails() layer1.setType(QgsMapLayerType.RasterLayer) - layer1.setName('layer 1') - layer1.setDescription('description 1') - layer1.setProviderKey('gdal') - layer1.setUri('uri 1') + layer1.setName("layer 1") + layer1.setDescription("description 1") + layer1.setProviderKey("gdal") + layer1.setUri("uri 1") model.setSublayerDetails([layer1]) self.assertEqual(model.rowCount(QModelIndex()), 1) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'layer 1') - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 'description 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.ProviderKey), 'gdal') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.RasterLayer) - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Uri), 'uri 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Name), 'layer 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Description), 'description 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), False) - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Flags), 0) - - self.assertEqual(model.indexToSublayer(model.index(0, 0, QModelIndex())), layer1) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "layer 1" + ) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "description 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.ProviderKey), + "gdal", + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.RasterLayer, + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Uri), "uri 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Name), "layer 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Description), + "description 1", + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), + False, + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Flags), 0 + ) + + self.assertEqual( + model.indexToSublayer(model.index(0, 0, QModelIndex())), layer1 + ) self.assertFalse(model.indexToSublayer(model.index(1, 0, QModelIndex())).name()) - self.assertFalse(model.indexToNonLayerItem(model.index(0, 0, QModelIndex())).name()) + self.assertFalse( + model.indexToNonLayerItem(model.index(0, 0, QModelIndex())).name() + ) item1 = QgsProviderSublayerModel.NonLayerItem() - item1.setUri('item uri 1') - item1.setName('item name 1') - item1.setType('item type 1') - item1.setDescription('item desc 1') + item1.setUri("item uri 1") + item1.setName("item name 1") + item1.setType("item type 1") + item1.setDescription("item desc 1") model.addNonLayerItem(item1) self.assertEqual(model.rowCount(QModelIndex()), 2) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'layer 1') - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 'description 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.ProviderKey), 'gdal') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.RasterLayer) - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Uri), 'uri 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Name), 'layer 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Description), 'description 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), False) - - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'item name 1') - self.assertEqual(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), 'item desc 1') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Uri), 'item uri 1') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Name), 'item name 1') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Description), 'item desc 1') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), True) - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.NonLayerItemType), 'item type 1') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Flags), None) - - self.assertEqual(model.indexToSublayer(model.index(0, 0, QModelIndex())), layer1) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "layer 1" + ) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "description 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.ProviderKey), + "gdal", + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.RasterLayer, + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Uri), "uri 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Name), "layer 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Description), + "description 1", + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), + False, + ) + + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "item name 1" + ) + self.assertEqual( + model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), "item desc 1" + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Uri), + "item uri 1", + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Name), + "item name 1", + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Description), + "item desc 1", + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), + True, + ) + self.assertEqual( + model.data( + model.index(1, 0), QgsProviderSublayerModel.Role.NonLayerItemType + ), + "item type 1", + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Flags), None + ) + + self.assertEqual( + model.indexToSublayer(model.index(0, 0, QModelIndex())), layer1 + ) self.assertFalse(model.indexToSublayer(model.index(1, 0, QModelIndex())).name()) - self.assertFalse(model.indexToNonLayerItem(model.index(0, 0, QModelIndex())).name()) - self.assertEqual(model.indexToNonLayerItem(model.index(1, 0, QModelIndex())), item1) - self.assertFalse(model.indexToNonLayerItem(model.index(2, 0, QModelIndex())).name()) + self.assertFalse( + model.indexToNonLayerItem(model.index(0, 0, QModelIndex())).name() + ) + self.assertEqual( + model.indexToNonLayerItem(model.index(1, 0, QModelIndex())), item1 + ) + self.assertFalse( + model.indexToNonLayerItem(model.index(2, 0, QModelIndex())).name() + ) item2 = QgsProviderSublayerModel.NonLayerItem() - item2.setUri('item uri 2') - item2.setName('item name 2') - item2.setType('item type 2') - item2.setDescription('item desc 2') + item2.setUri("item uri 2") + item2.setName("item name 2") + item2.setType("item type 2") + item2.setDescription("item desc 2") model.addNonLayerItem(item2) self.assertEqual(model.rowCount(QModelIndex()), 3) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'layer 1') - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 'description 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.ProviderKey), 'gdal') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.RasterLayer) - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Uri), 'uri 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Name), 'layer 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Description), 'description 1') - self.assertEqual(model.data(model.index(0, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), False) - - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'item name 1') - self.assertEqual(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), 'item desc 1') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Uri), 'item uri 1') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Name), 'item name 1') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Description), 'item desc 1') - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), True) - self.assertEqual(model.data(model.index(1, 0), QgsProviderSublayerModel.Role.NonLayerItemType), 'item type 1') - - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'item name 2') - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 'item desc 2') - self.assertEqual(model.data(model.index(2, 0), QgsProviderSublayerModel.Role.Uri), 'item uri 2') - self.assertEqual(model.data(model.index(2, 0), QgsProviderSublayerModel.Role.Name), 'item name 2') - self.assertEqual(model.data(model.index(2, 0), QgsProviderSublayerModel.Role.Description), 'item desc 2') - self.assertEqual(model.data(model.index(2, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), True) - self.assertEqual(model.data(model.index(2, 0), QgsProviderSublayerModel.Role.NonLayerItemType), 'item type 2') - - self.assertEqual(model.indexToSublayer(model.index(0, 0, QModelIndex())), layer1) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "layer 1" + ) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "description 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.ProviderKey), + "gdal", + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.RasterLayer, + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Uri), "uri 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Name), "layer 1" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.Description), + "description 1", + ) + self.assertEqual( + model.data(model.index(0, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), + False, + ) + + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "item name 1" + ) + self.assertEqual( + model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), "item desc 1" + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Uri), + "item uri 1", + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Name), + "item name 1", + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.Description), + "item desc 1", + ) + self.assertEqual( + model.data(model.index(1, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), + True, + ) + self.assertEqual( + model.data( + model.index(1, 0), QgsProviderSublayerModel.Role.NonLayerItemType + ), + "item type 1", + ) + + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "item name 2" + ) + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "item desc 2" + ) + self.assertEqual( + model.data(model.index(2, 0), QgsProviderSublayerModel.Role.Uri), + "item uri 2", + ) + self.assertEqual( + model.data(model.index(2, 0), QgsProviderSublayerModel.Role.Name), + "item name 2", + ) + self.assertEqual( + model.data(model.index(2, 0), QgsProviderSublayerModel.Role.Description), + "item desc 2", + ) + self.assertEqual( + model.data(model.index(2, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), + True, + ) + self.assertEqual( + model.data( + model.index(2, 0), QgsProviderSublayerModel.Role.NonLayerItemType + ), + "item type 2", + ) + + self.assertEqual( + model.indexToSublayer(model.index(0, 0, QModelIndex())), layer1 + ) self.assertFalse(model.indexToSublayer(model.index(1, 0, QModelIndex())).name()) - self.assertFalse(model.indexToNonLayerItem(model.index(0, 0, QModelIndex())).name()) - self.assertEqual(model.indexToNonLayerItem(model.index(1, 0, QModelIndex())), item1) - self.assertEqual(model.indexToNonLayerItem(model.index(2, 0, QModelIndex())), item2) - self.assertFalse(model.indexToNonLayerItem(model.index(3, 0, QModelIndex())).name()) + self.assertFalse( + model.indexToNonLayerItem(model.index(0, 0, QModelIndex())).name() + ) + self.assertEqual( + model.indexToNonLayerItem(model.index(1, 0, QModelIndex())), item1 + ) + self.assertEqual( + model.indexToNonLayerItem(model.index(2, 0, QModelIndex())), item2 + ) + self.assertFalse( + model.indexToNonLayerItem(model.index(3, 0, QModelIndex())).name() + ) def test_model_with_paths(self): model = QgsProviderSublayerModel() layer1 = QgsProviderSublayerDetails() layer1.setType(QgsMapLayerType.RasterLayer) - layer1.setName('layer 1') - layer1.setDescription('description 1') - layer1.setProviderKey('gdal') - layer1.setUri('uri 1') - layer1.setPath(['my', 'path']) + layer1.setName("layer 1") + layer1.setDescription("description 1") + layer1.setProviderKey("gdal") + layer1.setUri("uri 1") + layer1.setPath(["my", "path"]) model.setSublayerDetails([layer1]) self.assertEqual(model.rowCount(QModelIndex()), 1) my_group_index = model.index(0, 0) - self.assertEqual(model.data(my_group_index, Qt.ItemDataRole.DisplayRole), 'my') + self.assertEqual(model.data(my_group_index, Qt.ItemDataRole.DisplayRole), "my") self.assertEqual(model.rowCount(my_group_index), 1) path_group_index = model.index(0, 0, my_group_index) - self.assertEqual(model.data(path_group_index, Qt.ItemDataRole.DisplayRole), 'path') + self.assertEqual( + model.data(path_group_index, Qt.ItemDataRole.DisplayRole), "path" + ) self.assertEqual(model.rowCount(path_group_index), 1) - self.assertEqual(model.data(model.index(0, 0, path_group_index), Qt.ItemDataRole.DisplayRole), 'layer 1') - self.assertEqual(model.data(model.index(0, 1, path_group_index), Qt.ItemDataRole.DisplayRole), 'description 1') - self.assertEqual(model.data(model.index(0, 0, path_group_index), QgsProviderSublayerModel.Role.ProviderKey), 'gdal') - self.assertEqual(model.data(model.index(0, 0, path_group_index), QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.RasterLayer) - self.assertEqual(model.data(model.index(0, 0, path_group_index), QgsProviderSublayerModel.Role.Uri), 'uri 1') - self.assertEqual(model.data(model.index(0, 0, path_group_index), QgsProviderSublayerModel.Role.Name), 'layer 1') - self.assertEqual(model.data(model.index(0, 0, path_group_index), QgsProviderSublayerModel.Role.Description), 'description 1') - self.assertEqual(model.data(model.index(0, 0, path_group_index), QgsProviderSublayerModel.Role.Flags), 0) + self.assertEqual( + model.data( + model.index(0, 0, path_group_index), Qt.ItemDataRole.DisplayRole + ), + "layer 1", + ) + self.assertEqual( + model.data( + model.index(0, 1, path_group_index), Qt.ItemDataRole.DisplayRole + ), + "description 1", + ) + self.assertEqual( + model.data( + model.index(0, 0, path_group_index), + QgsProviderSublayerModel.Role.ProviderKey, + ), + "gdal", + ) + self.assertEqual( + model.data( + model.index(0, 0, path_group_index), + QgsProviderSublayerModel.Role.LayerType, + ), + QgsMapLayerType.RasterLayer, + ) + self.assertEqual( + model.data( + model.index(0, 0, path_group_index), QgsProviderSublayerModel.Role.Uri + ), + "uri 1", + ) + self.assertEqual( + model.data( + model.index(0, 0, path_group_index), QgsProviderSublayerModel.Role.Name + ), + "layer 1", + ) + self.assertEqual( + model.data( + model.index(0, 0, path_group_index), + QgsProviderSublayerModel.Role.Description, + ), + "description 1", + ) + self.assertEqual( + model.data( + model.index(0, 0, path_group_index), QgsProviderSublayerModel.Role.Flags + ), + 0, + ) # different path layer2 = QgsProviderSublayerDetails() layer2.setType(QgsMapLayerType.VectorLayer) - layer2.setName('layer 2') - layer2.setDescription('description 2') - layer2.setProviderKey('ogr') - layer2.setUri('uri 2') + layer2.setName("layer 2") + layer2.setDescription("description 2") + layer2.setProviderKey("ogr") + layer2.setUri("uri 2") layer2.setFeatureCount(-1) layer2.setWkbType(QgsWkbTypes.Type.LineString) layer2.setFlags(Qgis.SublayerFlags(Qgis.SublayerFlag.SystemTable)) - layer2.setPath(['my']) + layer2.setPath(["my"]) model.setSublayerDetails([layer1, layer2]) self.assertEqual(model.rowCount(QModelIndex()), 1) my_group_index = model.index(0, 0) - self.assertEqual(model.data(my_group_index, Qt.ItemDataRole.DisplayRole), 'my') + self.assertEqual(model.data(my_group_index, Qt.ItemDataRole.DisplayRole), "my") self.assertEqual(model.rowCount(my_group_index), 2) path_group_index = model.index(0, 0, my_group_index) - self.assertEqual(model.data(path_group_index, Qt.ItemDataRole.DisplayRole), 'path') + self.assertEqual( + model.data(path_group_index, Qt.ItemDataRole.DisplayRole), "path" + ) self.assertEqual(model.rowCount(path_group_index), 1) - self.assertEqual(model.data(model.index(0, 0, path_group_index), Qt.ItemDataRole.DisplayRole), 'layer 1') - self.assertEqual(model.data(model.index(0, 1, path_group_index), Qt.ItemDataRole.DisplayRole), 'description 1') - self.assertEqual(model.data(model.index(0, 0, path_group_index), QgsProviderSublayerModel.Role.ProviderKey), 'gdal') - self.assertEqual(model.data(model.index(0, 0, path_group_index), QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.RasterLayer) - self.assertEqual(model.data(model.index(0, 0, path_group_index), QgsProviderSublayerModel.Role.Uri), 'uri 1') - self.assertEqual(model.data(model.index(0, 0, path_group_index), QgsProviderSublayerModel.Role.Name), 'layer 1') - self.assertEqual(model.data(model.index(0, 0, path_group_index), QgsProviderSublayerModel.Role.Description), 'description 1') - self.assertEqual(model.data(model.index(0, 0, path_group_index), QgsProviderSublayerModel.Role.Flags), 0) + self.assertEqual( + model.data( + model.index(0, 0, path_group_index), Qt.ItemDataRole.DisplayRole + ), + "layer 1", + ) + self.assertEqual( + model.data( + model.index(0, 1, path_group_index), Qt.ItemDataRole.DisplayRole + ), + "description 1", + ) + self.assertEqual( + model.data( + model.index(0, 0, path_group_index), + QgsProviderSublayerModel.Role.ProviderKey, + ), + "gdal", + ) + self.assertEqual( + model.data( + model.index(0, 0, path_group_index), + QgsProviderSublayerModel.Role.LayerType, + ), + QgsMapLayerType.RasterLayer, + ) + self.assertEqual( + model.data( + model.index(0, 0, path_group_index), QgsProviderSublayerModel.Role.Uri + ), + "uri 1", + ) + self.assertEqual( + model.data( + model.index(0, 0, path_group_index), QgsProviderSublayerModel.Role.Name + ), + "layer 1", + ) + self.assertEqual( + model.data( + model.index(0, 0, path_group_index), + QgsProviderSublayerModel.Role.Description, + ), + "description 1", + ) + self.assertEqual( + model.data( + model.index(0, 0, path_group_index), QgsProviderSublayerModel.Role.Flags + ), + 0, + ) layer2_index = model.index(1, 0, my_group_index) - self.assertEqual(model.data(layer2_index, Qt.ItemDataRole.DisplayRole), 'layer 2') - self.assertEqual(model.data(model.index(1, 1, my_group_index), Qt.ItemDataRole.DisplayRole), 'description 2 - LineString (Uncounted)') - self.assertEqual(model.data(layer2_index, QgsProviderSublayerModel.Role.ProviderKey), 'ogr') - self.assertEqual(model.data(layer2_index, QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.VectorLayer) - self.assertEqual(model.data(layer2_index, QgsProviderSublayerModel.Role.Uri), 'uri 2') - self.assertEqual(model.data(layer2_index, QgsProviderSublayerModel.Role.Name), 'layer 2') - self.assertEqual(model.data(layer2_index, QgsProviderSublayerModel.Role.Description), 'description 2') - self.assertEqual(model.data(layer2_index, QgsProviderSublayerModel.Role.Flags), 1) + self.assertEqual( + model.data(layer2_index, Qt.ItemDataRole.DisplayRole), "layer 2" + ) + self.assertEqual( + model.data(model.index(1, 1, my_group_index), Qt.ItemDataRole.DisplayRole), + "description 2 - LineString (Uncounted)", + ) + self.assertEqual( + model.data(layer2_index, QgsProviderSublayerModel.Role.ProviderKey), "ogr" + ) + self.assertEqual( + model.data(layer2_index, QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.VectorLayer, + ) + self.assertEqual( + model.data(layer2_index, QgsProviderSublayerModel.Role.Uri), "uri 2" + ) + self.assertEqual( + model.data(layer2_index, QgsProviderSublayerModel.Role.Name), "layer 2" + ) + self.assertEqual( + model.data(layer2_index, QgsProviderSublayerModel.Role.Description), + "description 2", + ) + self.assertEqual( + model.data(layer2_index, QgsProviderSublayerModel.Role.Flags), 1 + ) # no path layer3 = QgsProviderSublayerDetails() layer3.setType(QgsMapLayerType.VectorLayer) - layer3.setName('layer 3') - layer3.setProviderKey('ogr') - layer3.setUri('uri 3') + layer3.setName("layer 3") + layer3.setProviderKey("ogr") + layer3.setUri("uri 3") layer3.setFeatureCount(1001) layer3.setWkbType(QgsWkbTypes.Type.Polygon) @@ -382,90 +849,207 @@ def test_model_with_paths(self): self.assertEqual(model.rowCount(QModelIndex()), 2) my_group_index = model.index(0, 0) - self.assertEqual(model.data(my_group_index, Qt.ItemDataRole.DisplayRole), 'my') + self.assertEqual(model.data(my_group_index, Qt.ItemDataRole.DisplayRole), "my") self.assertEqual(model.rowCount(my_group_index), 2) path_group_index = model.index(0, 0, my_group_index) - self.assertEqual(model.data(path_group_index, Qt.ItemDataRole.DisplayRole), 'path') + self.assertEqual( + model.data(path_group_index, Qt.ItemDataRole.DisplayRole), "path" + ) self.assertEqual(model.rowCount(path_group_index), 1) layer1_index = model.index(0, 0, path_group_index) - self.assertEqual(model.data(layer1_index, Qt.ItemDataRole.DisplayRole), 'layer 1') - self.assertEqual(model.data(model.index(0, 1, path_group_index), Qt.ItemDataRole.DisplayRole), 'description 1') - self.assertEqual(model.data(layer1_index, QgsProviderSublayerModel.Role.ProviderKey), 'gdal') - self.assertEqual(model.data(layer1_index, QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.RasterLayer) - self.assertEqual(model.data(layer1_index, QgsProviderSublayerModel.Role.Uri), 'uri 1') - self.assertEqual(model.data(layer1_index, QgsProviderSublayerModel.Role.Name), 'layer 1') - self.assertEqual(model.data(layer1_index, QgsProviderSublayerModel.Role.Description), 'description 1') - self.assertEqual(model.data(layer1_index, QgsProviderSublayerModel.Role.Flags), 0) + self.assertEqual( + model.data(layer1_index, Qt.ItemDataRole.DisplayRole), "layer 1" + ) + self.assertEqual( + model.data( + model.index(0, 1, path_group_index), Qt.ItemDataRole.DisplayRole + ), + "description 1", + ) + self.assertEqual( + model.data(layer1_index, QgsProviderSublayerModel.Role.ProviderKey), "gdal" + ) + self.assertEqual( + model.data(layer1_index, QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.RasterLayer, + ) + self.assertEqual( + model.data(layer1_index, QgsProviderSublayerModel.Role.Uri), "uri 1" + ) + self.assertEqual( + model.data(layer1_index, QgsProviderSublayerModel.Role.Name), "layer 1" + ) + self.assertEqual( + model.data(layer1_index, QgsProviderSublayerModel.Role.Description), + "description 1", + ) + self.assertEqual( + model.data(layer1_index, QgsProviderSublayerModel.Role.Flags), 0 + ) layer2_index = model.index(1, 0, my_group_index) - self.assertEqual(model.data(layer2_index, Qt.ItemDataRole.DisplayRole), 'layer 2') - self.assertEqual(model.data(model.index(1, 1, my_group_index), Qt.ItemDataRole.DisplayRole), 'description 2 - LineString (Uncounted)') - self.assertEqual(model.data(layer2_index, QgsProviderSublayerModel.Role.ProviderKey), 'ogr') - self.assertEqual(model.data(layer2_index, QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.VectorLayer) - self.assertEqual(model.data(layer2_index, QgsProviderSublayerModel.Role.Uri), 'uri 2') - self.assertEqual(model.data(layer2_index, QgsProviderSublayerModel.Role.Name), 'layer 2') - self.assertEqual(model.data(layer2_index, QgsProviderSublayerModel.Role.Description), 'description 2') - self.assertEqual(model.data(layer2_index, QgsProviderSublayerModel.Role.Flags), 1) + self.assertEqual( + model.data(layer2_index, Qt.ItemDataRole.DisplayRole), "layer 2" + ) + self.assertEqual( + model.data(model.index(1, 1, my_group_index), Qt.ItemDataRole.DisplayRole), + "description 2 - LineString (Uncounted)", + ) + self.assertEqual( + model.data(layer2_index, QgsProviderSublayerModel.Role.ProviderKey), "ogr" + ) + self.assertEqual( + model.data(layer2_index, QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.VectorLayer, + ) + self.assertEqual( + model.data(layer2_index, QgsProviderSublayerModel.Role.Uri), "uri 2" + ) + self.assertEqual( + model.data(layer2_index, QgsProviderSublayerModel.Role.Name), "layer 2" + ) + self.assertEqual( + model.data(layer2_index, QgsProviderSublayerModel.Role.Description), + "description 2", + ) + self.assertEqual( + model.data(layer2_index, QgsProviderSublayerModel.Role.Flags), 1 + ) layer3_index = model.index(1, 0) - self.assertEqual(model.data(layer3_index, Qt.ItemDataRole.DisplayRole), 'layer 3') - self.assertEqual(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), 'Polygon (1,001)') - self.assertEqual(model.data(layer3_index, QgsProviderSublayerModel.Role.ProviderKey), 'ogr') - self.assertEqual(model.data(layer3_index, QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.VectorLayer) - self.assertEqual(model.data(layer3_index, QgsProviderSublayerModel.Role.Uri), 'uri 3') - self.assertEqual(model.data(layer3_index, QgsProviderSublayerModel.Role.Name), 'layer 3') - self.assertEqual(model.data(layer3_index, QgsProviderSublayerModel.Role.Description), None) + self.assertEqual( + model.data(layer3_index, Qt.ItemDataRole.DisplayRole), "layer 3" + ) + self.assertEqual( + model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), + "Polygon (1,001)", + ) + self.assertEqual( + model.data(layer3_index, QgsProviderSublayerModel.Role.ProviderKey), "ogr" + ) + self.assertEqual( + model.data(layer3_index, QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.VectorLayer, + ) + self.assertEqual( + model.data(layer3_index, QgsProviderSublayerModel.Role.Uri), "uri 3" + ) + self.assertEqual( + model.data(layer3_index, QgsProviderSublayerModel.Role.Name), "layer 3" + ) + self.assertEqual( + model.data(layer3_index, QgsProviderSublayerModel.Role.Description), None + ) self.assertEqual(model.indexToSublayer(layer1_index), layer1) self.assertEqual(model.indexToSublayer(layer2_index), layer2) self.assertEqual(model.indexToSublayer(layer3_index), layer3) self.assertFalse(model.indexToSublayer(model.index(3, 0, QModelIndex())).name()) - self.assertFalse(model.indexToNonLayerItem(model.index(0, 0, QModelIndex())).name()) + self.assertFalse( + model.indexToNonLayerItem(model.index(0, 0, QModelIndex())).name() + ) # remove a layer model.setSublayerDetails([layer3, layer1]) self.assertEqual(model.rowCount(QModelIndex()), 2) my_group_index = model.index(0, 0) - self.assertEqual(model.data(my_group_index, Qt.ItemDataRole.DisplayRole), 'my') + self.assertEqual(model.data(my_group_index, Qt.ItemDataRole.DisplayRole), "my") self.assertEqual(model.rowCount(my_group_index), 1) path_group_index = model.index(0, 0, my_group_index) - self.assertEqual(model.data(path_group_index, Qt.ItemDataRole.DisplayRole), 'path') + self.assertEqual( + model.data(path_group_index, Qt.ItemDataRole.DisplayRole), "path" + ) self.assertEqual(model.rowCount(path_group_index), 1) layer1_index = model.index(0, 0, path_group_index) - self.assertEqual(model.data(layer1_index, Qt.ItemDataRole.DisplayRole), 'layer 1') - self.assertEqual(model.data(model.index(0, 1, path_group_index), Qt.ItemDataRole.DisplayRole), 'description 1') - self.assertEqual(model.data(layer1_index, QgsProviderSublayerModel.Role.ProviderKey), 'gdal') - self.assertEqual(model.data(layer1_index, QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.RasterLayer) - self.assertEqual(model.data(layer1_index, QgsProviderSublayerModel.Role.Uri), 'uri 1') - self.assertEqual(model.data(layer1_index, QgsProviderSublayerModel.Role.Name), 'layer 1') - self.assertEqual(model.data(layer1_index, QgsProviderSublayerModel.Role.Description), 'description 1') - self.assertEqual(model.data(layer1_index, QgsProviderSublayerModel.Role.Flags), 0) + self.assertEqual( + model.data(layer1_index, Qt.ItemDataRole.DisplayRole), "layer 1" + ) + self.assertEqual( + model.data( + model.index(0, 1, path_group_index), Qt.ItemDataRole.DisplayRole + ), + "description 1", + ) + self.assertEqual( + model.data(layer1_index, QgsProviderSublayerModel.Role.ProviderKey), "gdal" + ) + self.assertEqual( + model.data(layer1_index, QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.RasterLayer, + ) + self.assertEqual( + model.data(layer1_index, QgsProviderSublayerModel.Role.Uri), "uri 1" + ) + self.assertEqual( + model.data(layer1_index, QgsProviderSublayerModel.Role.Name), "layer 1" + ) + self.assertEqual( + model.data(layer1_index, QgsProviderSublayerModel.Role.Description), + "description 1", + ) + self.assertEqual( + model.data(layer1_index, QgsProviderSublayerModel.Role.Flags), 0 + ) layer3_index = model.index(1, 0) - self.assertEqual(model.data(layer3_index, Qt.ItemDataRole.DisplayRole), 'layer 3') - self.assertEqual(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), 'Polygon (1,001)') - self.assertEqual(model.data(layer3_index, QgsProviderSublayerModel.Role.ProviderKey), 'ogr') - self.assertEqual(model.data(layer3_index, QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.VectorLayer) - self.assertEqual(model.data(layer3_index, QgsProviderSublayerModel.Role.Uri), 'uri 3') - self.assertEqual(model.data(layer3_index, QgsProviderSublayerModel.Role.Name), 'layer 3') - self.assertEqual(model.data(layer3_index, QgsProviderSublayerModel.Role.Description), None) + self.assertEqual( + model.data(layer3_index, Qt.ItemDataRole.DisplayRole), "layer 3" + ) + self.assertEqual( + model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), + "Polygon (1,001)", + ) + self.assertEqual( + model.data(layer3_index, QgsProviderSublayerModel.Role.ProviderKey), "ogr" + ) + self.assertEqual( + model.data(layer3_index, QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.VectorLayer, + ) + self.assertEqual( + model.data(layer3_index, QgsProviderSublayerModel.Role.Uri), "uri 3" + ) + self.assertEqual( + model.data(layer3_index, QgsProviderSublayerModel.Role.Name), "layer 3" + ) + self.assertEqual( + model.data(layer3_index, QgsProviderSublayerModel.Role.Description), None + ) # remove another layer model.setSublayerDetails([layer3]) self.assertEqual(model.rowCount(QModelIndex()), 2) my_group_index = model.index(0, 0) - self.assertEqual(model.data(my_group_index, Qt.ItemDataRole.DisplayRole), 'my') + self.assertEqual(model.data(my_group_index, Qt.ItemDataRole.DisplayRole), "my") self.assertEqual(model.rowCount(my_group_index), 1) path_group_index = model.index(0, 0, my_group_index) - self.assertEqual(model.data(path_group_index, Qt.ItemDataRole.DisplayRole), 'path') + self.assertEqual( + model.data(path_group_index, Qt.ItemDataRole.DisplayRole), "path" + ) self.assertEqual(model.rowCount(path_group_index), 0) layer3_index = model.index(1, 0) - self.assertEqual(model.data(layer3_index, Qt.ItemDataRole.DisplayRole), 'layer 3') - self.assertEqual(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), 'Polygon (1,001)') - self.assertEqual(model.data(layer3_index, QgsProviderSublayerModel.Role.ProviderKey), 'ogr') - self.assertEqual(model.data(layer3_index, QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.VectorLayer) - self.assertEqual(model.data(layer3_index, QgsProviderSublayerModel.Role.Uri), 'uri 3') - self.assertEqual(model.data(layer3_index, QgsProviderSublayerModel.Role.Name), 'layer 3') - self.assertEqual(model.data(layer3_index, QgsProviderSublayerModel.Role.Description), None) + self.assertEqual( + model.data(layer3_index, Qt.ItemDataRole.DisplayRole), "layer 3" + ) + self.assertEqual( + model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), + "Polygon (1,001)", + ) + self.assertEqual( + model.data(layer3_index, QgsProviderSublayerModel.Role.ProviderKey), "ogr" + ) + self.assertEqual( + model.data(layer3_index, QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.VectorLayer, + ) + self.assertEqual( + model.data(layer3_index, QgsProviderSublayerModel.Role.Uri), "uri 3" + ) + self.assertEqual( + model.data(layer3_index, QgsProviderSublayerModel.Role.Name), "layer 3" + ) + self.assertEqual( + model.data(layer3_index, QgsProviderSublayerModel.Role.Description), None + ) def test_proxy(self): """ @@ -476,142 +1060,292 @@ def test_proxy(self): proxy.setSourceModel(model) self.assertEqual(model.rowCount(QModelIndex()), 0) self.assertEqual(proxy.columnCount(QModelIndex()), 2) - self.assertEqual(proxy.headerData(0, Qt.Orientation.Horizontal, Qt.ItemDataRole.DisplayRole), 'Item') - self.assertEqual(proxy.headerData(0, Qt.Orientation.Horizontal, Qt.ItemDataRole.ToolTipRole), 'Item') - self.assertEqual(proxy.headerData(1, Qt.Orientation.Horizontal, Qt.ItemDataRole.DisplayRole), 'Description') - self.assertEqual(proxy.headerData(1, Qt.Orientation.Horizontal, Qt.ItemDataRole.ToolTipRole), 'Description') + self.assertEqual( + proxy.headerData(0, Qt.Orientation.Horizontal, Qt.ItemDataRole.DisplayRole), + "Item", + ) + self.assertEqual( + proxy.headerData(0, Qt.Orientation.Horizontal, Qt.ItemDataRole.ToolTipRole), + "Item", + ) + self.assertEqual( + proxy.headerData(1, Qt.Orientation.Horizontal, Qt.ItemDataRole.DisplayRole), + "Description", + ) + self.assertEqual( + proxy.headerData(1, Qt.Orientation.Horizontal, Qt.ItemDataRole.ToolTipRole), + "Description", + ) layer1 = QgsProviderSublayerDetails() layer1.setType(QgsMapLayerType.RasterLayer) - layer1.setName('layer 1') - layer1.setDescription('description 1') - layer1.setProviderKey('gdal') - layer1.setUri('uri 1') + layer1.setName("layer 1") + layer1.setDescription("description 1") + layer1.setProviderKey("gdal") + layer1.setUri("uri 1") layer2 = QgsProviderSublayerDetails() layer2.setType(QgsMapLayerType.VectorLayer) - layer2.setName('another layer 2') - layer2.setDescription('description 2') - layer2.setProviderKey('ogr') - layer2.setUri('uri 2') + layer2.setName("another layer 2") + layer2.setDescription("description 2") + layer2.setProviderKey("ogr") + layer2.setUri("uri 2") layer2.setFeatureCount(-1) layer2.setWkbType(QgsWkbTypes.Type.LineString) layer3 = QgsProviderSublayerDetails() layer3.setType(QgsMapLayerType.VectorLayer) - layer3.setName('yet another layer 3') - layer3.setDescription('an empty layer') - layer3.setProviderKey('ogr') - layer3.setUri('uri 3') + layer3.setName("yet another layer 3") + layer3.setDescription("an empty layer") + layer3.setProviderKey("ogr") + layer3.setUri("uri 3") layer3.setFeatureCount(0) layer3.setWkbType(QgsWkbTypes.Type.Polygon) model.setSublayerDetails([layer1, layer2, layer3]) item1 = QgsProviderSublayerModel.NonLayerItem() - item1.setUri('item uri 1') - item1.setName('item name 1') - item1.setType('item type 1') - item1.setDescription('item desc 1') + item1.setUri("item uri 1") + item1.setName("item name 1") + item1.setType("item type 1") + item1.setDescription("item desc 1") model.addNonLayerItem(item1) self.assertEqual(proxy.rowCount(QModelIndex()), 4) - self.assertEqual(proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), 'item name 1') - self.assertEqual(proxy.data(proxy.index(0, 1), Qt.ItemDataRole.DisplayRole), 'item desc 1') - self.assertEqual(proxy.data(proxy.index(0, 0), QgsProviderSublayerModel.Role.Uri), 'item uri 1') - self.assertEqual(proxy.data(proxy.index(0, 0), QgsProviderSublayerModel.Role.Name), 'item name 1') - self.assertEqual(proxy.data(proxy.index(0, 0), QgsProviderSublayerModel.Role.Description), 'item desc 1') - self.assertEqual(proxy.data(proxy.index(0, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), True) - - self.assertEqual(proxy.data(proxy.index(1, 0), Qt.ItemDataRole.DisplayRole), 'another layer 2') - self.assertEqual(proxy.data(proxy.index(1, 1), Qt.ItemDataRole.DisplayRole), 'description 2 - LineString (Uncounted)') - self.assertEqual(proxy.data(proxy.index(1, 0), QgsProviderSublayerModel.Role.ProviderKey), 'ogr') - self.assertEqual(proxy.data(proxy.index(1, 0), QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.VectorLayer) - self.assertEqual(proxy.data(proxy.index(1, 0), QgsProviderSublayerModel.Role.Uri), 'uri 2') - self.assertEqual(proxy.data(proxy.index(1, 0), QgsProviderSublayerModel.Role.Name), 'another layer 2') - self.assertEqual(proxy.data(proxy.index(1, 0), QgsProviderSublayerModel.Role.Description), 'description 2') - self.assertEqual(proxy.data(proxy.index(1, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), False) - - self.assertEqual(proxy.data(proxy.index(2, 0), Qt.ItemDataRole.DisplayRole), 'layer 1') - self.assertEqual(proxy.data(proxy.index(2, 1), Qt.ItemDataRole.DisplayRole), 'description 1') - self.assertEqual(proxy.data(proxy.index(2, 0), QgsProviderSublayerModel.Role.ProviderKey), 'gdal') - self.assertEqual(proxy.data(proxy.index(2, 0), QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.RasterLayer) - self.assertEqual(proxy.data(proxy.index(2, 0), QgsProviderSublayerModel.Role.Uri), 'uri 1') - self.assertEqual(proxy.data(proxy.index(2, 0), QgsProviderSublayerModel.Role.Name), 'layer 1') - self.assertEqual(proxy.data(proxy.index(2, 0), QgsProviderSublayerModel.Role.Description), 'description 1') - self.assertEqual(proxy.data(proxy.index(2, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), False) - - self.assertEqual(proxy.data(proxy.index(3, 0), Qt.ItemDataRole.DisplayRole), 'yet another layer 3') - self.assertEqual(proxy.data(proxy.index(3, 1), Qt.ItemDataRole.DisplayRole), 'an empty layer - Polygon (0)') - self.assertEqual(proxy.data(proxy.index(3, 0), QgsProviderSublayerModel.Role.ProviderKey), 'ogr') - self.assertEqual(proxy.data(proxy.index(3, 0), QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.VectorLayer) - self.assertEqual(proxy.data(proxy.index(3, 0), QgsProviderSublayerModel.Role.Uri), 'uri 3') - self.assertEqual(proxy.data(proxy.index(3, 0), QgsProviderSublayerModel.Role.Name), 'yet another layer 3') - self.assertEqual(proxy.data(proxy.index(3, 0), QgsProviderSublayerModel.Role.Description), 'an empty layer') - self.assertEqual(proxy.data(proxy.index(3, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), False) - - proxy.setFilterString(' 1') + self.assertEqual( + proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), "item name 1" + ) + self.assertEqual( + proxy.data(proxy.index(0, 1), Qt.ItemDataRole.DisplayRole), "item desc 1" + ) + self.assertEqual( + proxy.data(proxy.index(0, 0), QgsProviderSublayerModel.Role.Uri), + "item uri 1", + ) + self.assertEqual( + proxy.data(proxy.index(0, 0), QgsProviderSublayerModel.Role.Name), + "item name 1", + ) + self.assertEqual( + proxy.data(proxy.index(0, 0), QgsProviderSublayerModel.Role.Description), + "item desc 1", + ) + self.assertEqual( + proxy.data(proxy.index(0, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), + True, + ) + + self.assertEqual( + proxy.data(proxy.index(1, 0), Qt.ItemDataRole.DisplayRole), + "another layer 2", + ) + self.assertEqual( + proxy.data(proxy.index(1, 1), Qt.ItemDataRole.DisplayRole), + "description 2 - LineString (Uncounted)", + ) + self.assertEqual( + proxy.data(proxy.index(1, 0), QgsProviderSublayerModel.Role.ProviderKey), + "ogr", + ) + self.assertEqual( + proxy.data(proxy.index(1, 0), QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.VectorLayer, + ) + self.assertEqual( + proxy.data(proxy.index(1, 0), QgsProviderSublayerModel.Role.Uri), "uri 2" + ) + self.assertEqual( + proxy.data(proxy.index(1, 0), QgsProviderSublayerModel.Role.Name), + "another layer 2", + ) + self.assertEqual( + proxy.data(proxy.index(1, 0), QgsProviderSublayerModel.Role.Description), + "description 2", + ) + self.assertEqual( + proxy.data(proxy.index(1, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), + False, + ) + + self.assertEqual( + proxy.data(proxy.index(2, 0), Qt.ItemDataRole.DisplayRole), "layer 1" + ) + self.assertEqual( + proxy.data(proxy.index(2, 1), Qt.ItemDataRole.DisplayRole), "description 1" + ) + self.assertEqual( + proxy.data(proxy.index(2, 0), QgsProviderSublayerModel.Role.ProviderKey), + "gdal", + ) + self.assertEqual( + proxy.data(proxy.index(2, 0), QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.RasterLayer, + ) + self.assertEqual( + proxy.data(proxy.index(2, 0), QgsProviderSublayerModel.Role.Uri), "uri 1" + ) + self.assertEqual( + proxy.data(proxy.index(2, 0), QgsProviderSublayerModel.Role.Name), "layer 1" + ) + self.assertEqual( + proxy.data(proxy.index(2, 0), QgsProviderSublayerModel.Role.Description), + "description 1", + ) + self.assertEqual( + proxy.data(proxy.index(2, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), + False, + ) + + self.assertEqual( + proxy.data(proxy.index(3, 0), Qt.ItemDataRole.DisplayRole), + "yet another layer 3", + ) + self.assertEqual( + proxy.data(proxy.index(3, 1), Qt.ItemDataRole.DisplayRole), + "an empty layer - Polygon (0)", + ) + self.assertEqual( + proxy.data(proxy.index(3, 0), QgsProviderSublayerModel.Role.ProviderKey), + "ogr", + ) + self.assertEqual( + proxy.data(proxy.index(3, 0), QgsProviderSublayerModel.Role.LayerType), + QgsMapLayerType.VectorLayer, + ) + self.assertEqual( + proxy.data(proxy.index(3, 0), QgsProviderSublayerModel.Role.Uri), "uri 3" + ) + self.assertEqual( + proxy.data(proxy.index(3, 0), QgsProviderSublayerModel.Role.Name), + "yet another layer 3", + ) + self.assertEqual( + proxy.data(proxy.index(3, 0), QgsProviderSublayerModel.Role.Description), + "an empty layer", + ) + self.assertEqual( + proxy.data(proxy.index(3, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), + False, + ) + + proxy.setFilterString(" 1") self.assertEqual(proxy.rowCount(QModelIndex()), 2) - self.assertEqual(proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), 'item name 1') - self.assertEqual(proxy.data(proxy.index(1, 0), Qt.ItemDataRole.DisplayRole), 'layer 1') - - proxy.setFilterString(' 2') + self.assertEqual( + proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), "item name 1" + ) + self.assertEqual( + proxy.data(proxy.index(1, 0), Qt.ItemDataRole.DisplayRole), "layer 1" + ) + + proxy.setFilterString(" 2") self.assertEqual(proxy.rowCount(QModelIndex()), 1) - self.assertEqual(proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), 'another layer 2') + self.assertEqual( + proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), + "another layer 2", + ) - proxy.setFilterString('ITEM') + proxy.setFilterString("ITEM") self.assertEqual(proxy.rowCount(QModelIndex()), 1) - self.assertEqual(proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), 'item name 1') + self.assertEqual( + proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), "item name 1" + ) # should also allow filtering by vector layer wkb type strings - proxy.setFilterString('LineSTRING') + proxy.setFilterString("LineSTRING") self.assertEqual(proxy.rowCount(QModelIndex()), 1) - self.assertEqual(proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), 'another layer 2') + self.assertEqual( + proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), + "another layer 2", + ) # should also allow filtering by the feature count as it appears in the description too but it's not in the description role - proxy.setFilterString('0') + proxy.setFilterString("0") self.assertEqual(proxy.rowCount(QModelIndex()), 1) - self.assertEqual(proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), 'yet another layer 3') + self.assertEqual( + proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), + "yet another layer 3", + ) - proxy.setFilterString('') + proxy.setFilterString("") self.assertEqual(proxy.rowCount(QModelIndex()), 4) - self.assertEqual(proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), 'item name 1') - self.assertEqual(proxy.data(proxy.index(1, 0), Qt.ItemDataRole.DisplayRole), 'another layer 2') - self.assertEqual(proxy.data(proxy.index(2, 0), Qt.ItemDataRole.DisplayRole), 'layer 1') - self.assertEqual(proxy.data(proxy.index(3, 0), Qt.ItemDataRole.DisplayRole), 'yet another layer 3') + self.assertEqual( + proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), "item name 1" + ) + self.assertEqual( + proxy.data(proxy.index(1, 0), Qt.ItemDataRole.DisplayRole), + "another layer 2", + ) + self.assertEqual( + proxy.data(proxy.index(2, 0), Qt.ItemDataRole.DisplayRole), "layer 1" + ) + self.assertEqual( + proxy.data(proxy.index(3, 0), Qt.ItemDataRole.DisplayRole), + "yet another layer 3", + ) # add a system table layer_system = QgsProviderSublayerDetails() layer_system.setType(QgsMapLayerType.VectorLayer) - layer_system.setName('system table') + layer_system.setName("system table") layer_system.setFlags(Qgis.SublayerFlags(Qgis.SublayerFlag.SystemTable)) model.setSublayerDetails([layer1, layer2, layer3, layer_system]) # system tables should be hidden by default self.assertEqual(proxy.rowCount(QModelIndex()), 4) - self.assertEqual(proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), 'item name 1') - self.assertEqual(proxy.data(proxy.index(1, 0), Qt.ItemDataRole.DisplayRole), 'another layer 2') - self.assertEqual(proxy.data(proxy.index(2, 0), Qt.ItemDataRole.DisplayRole), 'layer 1') - self.assertEqual(proxy.data(proxy.index(3, 0), Qt.ItemDataRole.DisplayRole), 'yet another layer 3') + self.assertEqual( + proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), "item name 1" + ) + self.assertEqual( + proxy.data(proxy.index(1, 0), Qt.ItemDataRole.DisplayRole), + "another layer 2", + ) + self.assertEqual( + proxy.data(proxy.index(2, 0), Qt.ItemDataRole.DisplayRole), "layer 1" + ) + self.assertEqual( + proxy.data(proxy.index(3, 0), Qt.ItemDataRole.DisplayRole), + "yet another layer 3", + ) proxy.setIncludeSystemTables(True) self.assertEqual(proxy.rowCount(QModelIndex()), 5) - self.assertEqual(proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), 'item name 1') - self.assertEqual(proxy.data(proxy.index(1, 0), Qt.ItemDataRole.DisplayRole), 'another layer 2') - self.assertEqual(proxy.data(proxy.index(2, 0), Qt.ItemDataRole.DisplayRole), 'layer 1') - self.assertEqual(proxy.data(proxy.index(3, 0), Qt.ItemDataRole.DisplayRole), 'system table') - self.assertEqual(proxy.data(proxy.index(4, 0), Qt.ItemDataRole.DisplayRole), 'yet another layer 3') + self.assertEqual( + proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), "item name 1" + ) + self.assertEqual( + proxy.data(proxy.index(1, 0), Qt.ItemDataRole.DisplayRole), + "another layer 2", + ) + self.assertEqual( + proxy.data(proxy.index(2, 0), Qt.ItemDataRole.DisplayRole), "layer 1" + ) + self.assertEqual( + proxy.data(proxy.index(3, 0), Qt.ItemDataRole.DisplayRole), "system table" + ) + self.assertEqual( + proxy.data(proxy.index(4, 0), Qt.ItemDataRole.DisplayRole), + "yet another layer 3", + ) # hide empty vector layers proxy.setIncludeEmptyLayers(False) self.assertEqual(proxy.rowCount(QModelIndex()), 4) - self.assertEqual(proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), 'item name 1') - self.assertEqual(proxy.data(proxy.index(1, 0), Qt.ItemDataRole.DisplayRole), 'another layer 2') - self.assertEqual(proxy.data(proxy.index(2, 0), Qt.ItemDataRole.DisplayRole), 'layer 1') - self.assertEqual(proxy.data(proxy.index(3, 0), Qt.ItemDataRole.DisplayRole), 'system table') - - -if __name__ == '__main__': + self.assertEqual( + proxy.data(proxy.index(0, 0), Qt.ItemDataRole.DisplayRole), "item name 1" + ) + self.assertEqual( + proxy.data(proxy.index(1, 0), Qt.ItemDataRole.DisplayRole), + "another layer 2", + ) + self.assertEqual( + proxy.data(proxy.index(2, 0), Qt.ItemDataRole.DisplayRole), "layer 1" + ) + self.assertEqual( + proxy.data(proxy.index(3, 0), Qt.ItemDataRole.DisplayRole), "system table" + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsprovidersublayertask.py b/tests/src/python/test_qgsprovidersublayertask.py index 13c06adadbde..36c0c9e03128 100644 --- a/tests/src/python/test_qgsprovidersublayertask.py +++ b/tests/src/python/test_qgsprovidersublayertask.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '30/06/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "30/06/2021" +__copyright__ = "Copyright 2021, The QGIS Project" from qgis.PyQt.QtTest import QSignalSpy from qgis.core import ( @@ -30,10 +31,11 @@ def test_query(self): """ Test querying sublayers using the task """ - task = QgsProviderSublayerTask(uri=unitTestDataPath() + '/mixed_types.TAB') + task = QgsProviderSublayerTask(uri=unitTestDataPath() + "/mixed_types.TAB") def completed(): completed.results = task.results() + completed.results = None task.taskCompleted.connect(completed) @@ -46,33 +48,42 @@ def completed(): self.assertEqual(completed.results[0].layerNumber(), 0) self.assertEqual(completed.results[0].name(), "mixed_types") self.assertEqual(completed.results[0].description(), "") - self.assertEqual(completed.results[0].uri(), f"{unitTestDataPath()}/mixed_types.TAB|geometrytype=Point") + self.assertEqual( + completed.results[0].uri(), + f"{unitTestDataPath()}/mixed_types.TAB|geometrytype=Point", + ) self.assertEqual(completed.results[0].providerKey(), "ogr") self.assertEqual(completed.results[0].type(), QgsMapLayerType.VectorLayer) self.assertEqual(completed.results[0].featureCount(), 4) self.assertEqual(completed.results[0].wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(completed.results[0].geometryColumnName(), '') + self.assertEqual(completed.results[0].geometryColumnName(), "") self.assertEqual(completed.results[1].layerNumber(), 0) self.assertEqual(completed.results[1].name(), "mixed_types") self.assertEqual(completed.results[1].description(), "") - self.assertEqual(completed.results[1].uri(), f"{unitTestDataPath()}/mixed_types.TAB|geometrytype=LineString") + self.assertEqual( + completed.results[1].uri(), + f"{unitTestDataPath()}/mixed_types.TAB|geometrytype=LineString", + ) self.assertEqual(completed.results[1].providerKey(), "ogr") self.assertEqual(completed.results[1].type(), QgsMapLayerType.VectorLayer) self.assertEqual(completed.results[1].featureCount(), 4) self.assertEqual(completed.results[1].wkbType(), QgsWkbTypes.Type.LineString) - self.assertEqual(completed.results[1].geometryColumnName(), '') + self.assertEqual(completed.results[1].geometryColumnName(), "") self.assertEqual(completed.results[2].layerNumber(), 0) self.assertEqual(completed.results[2].name(), "mixed_types") self.assertEqual(completed.results[2].description(), "") - self.assertEqual(completed.results[2].uri(), f"{unitTestDataPath()}/mixed_types.TAB|geometrytype=Polygon") + self.assertEqual( + completed.results[2].uri(), + f"{unitTestDataPath()}/mixed_types.TAB|geometrytype=Polygon", + ) self.assertEqual(completed.results[2].providerKey(), "ogr") self.assertEqual(completed.results[2].type(), QgsMapLayerType.VectorLayer) self.assertEqual(completed.results[2].featureCount(), 3) self.assertEqual(completed.results[2].wkbType(), QgsWkbTypes.Type.Polygon) - self.assertEqual(completed.results[2].geometryColumnName(), '') + self.assertEqual(completed.results[2].geometryColumnName(), "") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsproviderutils.py b/tests/src/python/test_qgsproviderutils.py index 324032271e5c..b9c8a1590222 100644 --- a/tests/src/python/test_qgsproviderutils.py +++ b/tests/src/python/test_qgsproviderutils.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '30/06/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "30/06/2021" +__copyright__ = "Copyright 2021, The QGIS Project" from qgis.core import ( Qgis, @@ -31,7 +32,7 @@ def test_sublayerDetailsAreIncomplete(self): """ Test sublayerDetailsAreIncomplete """ - uri = unitTestDataPath() + '/mixed_types.TAB' + uri = unitTestDataPath() + "/mixed_types.TAB" # surface scan only sublayers = QgsProviderRegistry.instance().querySublayers(uri) @@ -40,113 +41,196 @@ def test_sublayerDetailsAreIncomplete(self): # need to resolve geometry types for complete details about this uri! self.assertTrue(QgsProviderUtils.sublayerDetailsAreIncomplete(sublayers)) - self.assertTrue(QgsProviderUtils.sublayerDetailsAreIncomplete(sublayers, - QgsProviderUtils.SublayerCompletenessFlags( - QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownFeatureCount))) - self.assertTrue(QgsProviderUtils.sublayerDetailsAreIncomplete(sublayers, - QgsProviderUtils.SublayerCompletenessFlags( - QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownGeometryType))) + self.assertTrue( + QgsProviderUtils.sublayerDetailsAreIncomplete( + sublayers, + QgsProviderUtils.SublayerCompletenessFlags( + QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownFeatureCount + ), + ) + ) + self.assertTrue( + QgsProviderUtils.sublayerDetailsAreIncomplete( + sublayers, + QgsProviderUtils.SublayerCompletenessFlags( + QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownGeometryType + ), + ) + ) # ...unless we are ignoring both unknown feature count and unknown geometry types - self.assertFalse(QgsProviderUtils.sublayerDetailsAreIncomplete(sublayers, - QgsProviderUtils.SublayerCompletenessFlags( - QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownFeatureCount | - QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownGeometryType))) + self.assertFalse( + QgsProviderUtils.sublayerDetailsAreIncomplete( + sublayers, + QgsProviderUtils.SublayerCompletenessFlags( + QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownFeatureCount + | QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownGeometryType + ), + ) + ) # fake feature count, now we have complete details if we ignore unknown geometry type sublayers[0].setFeatureCount(5) - self.assertFalse(QgsProviderUtils.sublayerDetailsAreIncomplete(sublayers, - QgsProviderUtils.SublayerCompletenessFlags( - QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownGeometryType))) + self.assertFalse( + QgsProviderUtils.sublayerDetailsAreIncomplete( + sublayers, + QgsProviderUtils.SublayerCompletenessFlags( + QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownGeometryType + ), + ) + ) # retry with retrieving geometry types - sublayers = QgsProviderRegistry.instance().querySublayers(uri, Qgis.SublayerQueryFlag.ResolveGeometryType) + sublayers = QgsProviderRegistry.instance().querySublayers( + uri, Qgis.SublayerQueryFlag.ResolveGeometryType + ) # now we have all the details self.assertEqual(len(sublayers), 3) self.assertFalse(QgsProviderUtils.sublayerDetailsAreIncomplete(sublayers)) - self.assertFalse(QgsProviderUtils.sublayerDetailsAreIncomplete(sublayers, - QgsProviderUtils.SublayerCompletenessFlags( - QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownFeatureCount))) - self.assertFalse(QgsProviderUtils.sublayerDetailsAreIncomplete(sublayers, - QgsProviderUtils.SublayerCompletenessFlags( - QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownGeometryType))) + self.assertFalse( + QgsProviderUtils.sublayerDetailsAreIncomplete( + sublayers, + QgsProviderUtils.SublayerCompletenessFlags( + QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownFeatureCount + ), + ) + ) + self.assertFalse( + QgsProviderUtils.sublayerDetailsAreIncomplete( + sublayers, + QgsProviderUtils.SublayerCompletenessFlags( + QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownGeometryType + ), + ) + ) # this geopackage file requires manually requesting feature counts - uri = unitTestDataPath() + '/mixed_layers.gpkg' + uri = unitTestDataPath() + "/mixed_layers.gpkg" # surface scan only sublayers = QgsProviderRegistry.instance().querySublayers(uri) self.assertEqual(len(sublayers), 4) - self.assertEqual(sublayers[0].name(), 'band1') - self.assertEqual(sublayers[1].name(), 'band2') - self.assertEqual(sublayers[2].name(), 'points') + self.assertEqual(sublayers[0].name(), "band1") + self.assertEqual(sublayers[1].name(), "band2") + self.assertEqual(sublayers[2].name(), "points") self.assertEqual(sublayers[2].featureCount(), Qgis.FeatureCountState.Uncounted) - self.assertEqual(sublayers[3].name(), 'lines') + self.assertEqual(sublayers[3].name(), "lines") self.assertEqual(sublayers[3].featureCount(), Qgis.FeatureCountState.Uncounted) # need to count features for complete details about this uri! self.assertTrue(QgsProviderUtils.sublayerDetailsAreIncomplete(sublayers)) - self.assertTrue(QgsProviderUtils.sublayerDetailsAreIncomplete(sublayers, - QgsProviderUtils.SublayerCompletenessFlags( - QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownGeometryType))) + self.assertTrue( + QgsProviderUtils.sublayerDetailsAreIncomplete( + sublayers, + QgsProviderUtils.SublayerCompletenessFlags( + QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownGeometryType + ), + ) + ) # ...unless we are ignoring unknown feature counts, that is... - self.assertFalse(QgsProviderUtils.sublayerDetailsAreIncomplete(sublayers, - QgsProviderUtils.SublayerCompletenessFlags( - QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownFeatureCount))) + self.assertFalse( + QgsProviderUtils.sublayerDetailsAreIncomplete( + sublayers, + QgsProviderUtils.SublayerCompletenessFlags( + QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownFeatureCount + ), + ) + ) # retry with retrieving feature count - sublayers = QgsProviderRegistry.instance().querySublayers(uri, Qgis.SublayerQueryFlag.CountFeatures) + sublayers = QgsProviderRegistry.instance().querySublayers( + uri, Qgis.SublayerQueryFlag.CountFeatures + ) # now we have all the details self.assertEqual(len(sublayers), 4) - self.assertFalse(QgsProviderUtils.sublayerDetailsAreIncomplete(sublayers, - QgsProviderUtils.SublayerCompletenessFlags( - QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownFeatureCount))) - self.assertFalse(QgsProviderUtils.sublayerDetailsAreIncomplete(sublayers, - QgsProviderUtils.SublayerCompletenessFlags( - QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownGeometryType))) + self.assertFalse( + QgsProviderUtils.sublayerDetailsAreIncomplete( + sublayers, + QgsProviderUtils.SublayerCompletenessFlags( + QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownFeatureCount + ), + ) + ) + self.assertFalse( + QgsProviderUtils.sublayerDetailsAreIncomplete( + sublayers, + QgsProviderUtils.SublayerCompletenessFlags( + QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownGeometryType + ), + ) + ) self.assertFalse(QgsProviderUtils.sublayerDetailsAreIncomplete(sublayers)) - self.assertEqual(sublayers[0].name(), 'band1') - self.assertEqual(sublayers[1].name(), 'band2') - self.assertEqual(sublayers[2].name(), 'points') + self.assertEqual(sublayers[0].name(), "band1") + self.assertEqual(sublayers[1].name(), "band2") + self.assertEqual(sublayers[2].name(), "points") self.assertEqual(sublayers[2].featureCount(), 0) - self.assertEqual(sublayers[3].name(), 'lines') + self.assertEqual(sublayers[3].name(), "lines") self.assertEqual(sublayers[3].featureCount(), 6) # test with sublayer with skippedContainerScan flag sl1 = QgsProviderSublayerDetails() - sl1.setProviderKey('ogr') + sl1.setProviderKey("ogr") sl1.setType(QgsMapLayerType.VectorLayer) sl1.setWkbType(QgsWkbTypes.Type.Point) sl1.setFeatureCount(1) sl1.setSkippedContainerScan(False) self.assertFalse( - QgsProviderUtils.sublayerDetailsAreIncomplete([sl1], QgsProviderUtils.SublayerCompletenessFlags( - QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownFeatureCount))) + QgsProviderUtils.sublayerDetailsAreIncomplete( + [sl1], + QgsProviderUtils.SublayerCompletenessFlags( + QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownFeatureCount + ), + ) + ) self.assertFalse(QgsProviderUtils.sublayerDetailsAreIncomplete([sl1])) sl2 = QgsProviderSublayerDetails() - sl2.setProviderKey('ogr') + sl2.setProviderKey("ogr") sl2.setType(QgsMapLayerType.VectorLayer) sl2.setWkbType(QgsWkbTypes.Type.Point) sl2.setFeatureCount(1) sl2.setSkippedContainerScan(True) - self.assertTrue(QgsProviderUtils.sublayerDetailsAreIncomplete([sl2], QgsProviderUtils.SublayerCompletenessFlags( - QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownFeatureCount))) + self.assertTrue( + QgsProviderUtils.sublayerDetailsAreIncomplete( + [sl2], + QgsProviderUtils.SublayerCompletenessFlags( + QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownFeatureCount + ), + ) + ) self.assertTrue(QgsProviderUtils.sublayerDetailsAreIncomplete([sl2])) self.assertTrue( - QgsProviderUtils.sublayerDetailsAreIncomplete([sl1, sl2], QgsProviderUtils.SublayerCompletenessFlags( - QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownFeatureCount))) + QgsProviderUtils.sublayerDetailsAreIncomplete( + [sl1, sl2], + QgsProviderUtils.SublayerCompletenessFlags( + QgsProviderUtils.SublayerCompletenessFlag.IgnoreUnknownFeatureCount + ), + ) + ) self.assertTrue(QgsProviderUtils.sublayerDetailsAreIncomplete([sl1, sl2])) def test_suggestLayerNameFromFilePath(self): """ test suggestLayerNameFromFilePath """ - self.assertEqual(QgsProviderUtils.suggestLayerNameFromFilePath(''), '') - self.assertEqual(QgsProviderUtils.suggestLayerNameFromFilePath('/home/me/data/rivers.shp'), 'rivers') + self.assertEqual(QgsProviderUtils.suggestLayerNameFromFilePath(""), "") + self.assertEqual( + QgsProviderUtils.suggestLayerNameFromFilePath("/home/me/data/rivers.shp"), + "rivers", + ) # adf files should return parent dir name - self.assertEqual(QgsProviderUtils.suggestLayerNameFromFilePath('/home/me/data/rivers/hdr.adf'), 'rivers') + self.assertEqual( + QgsProviderUtils.suggestLayerNameFromFilePath( + "/home/me/data/rivers/hdr.adf" + ), + "rivers", + ) # ept.json files should return parent dir name - self.assertEqual(QgsProviderUtils.suggestLayerNameFromFilePath('/home/me/data/rivers/ept.json'), 'rivers') + self.assertEqual( + QgsProviderUtils.suggestLayerNameFromFilePath( + "/home/me/data/rivers/ept.json" + ), + "rivers", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsqueryresultmodel.py b/tests/src/python/test_qgsqueryresultmodel.py index 5db9940dcf13..7b8f9dda0ecb 100644 --- a/tests/src/python/test_qgsqueryresultmodel.py +++ b/tests/src/python/test_qgsqueryresultmodel.py @@ -6,9 +6,10 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '24/12/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "24/12/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import os @@ -21,9 +22,7 @@ ) from qgis.PyQt.QtTest import QAbstractItemModelTester from qgis.PyQt.QtWidgets import QDialog, QLabel, QListView, QVBoxLayout -from qgis.core import ( - QgsProviderRegistry, - QgsQueryResultModel, NULL) +from qgis.core import QgsProviderRegistry, QgsQueryResultModel, NULL import unittest from qgis.testing import start_app, QgisTestCase @@ -42,17 +41,19 @@ def setUpClass(cls): QCoreApplication.setApplicationName(cls.__name__) start_app() cls.postgres_conn = "service='qgis_test'" - if 'QGIS_PGTEST_DB' in os.environ: - cls.postgres_conn = os.environ['QGIS_PGTEST_DB'] - cls.uri = cls.postgres_conn + ' sslmode=disable' + if "QGIS_PGTEST_DB" in os.environ: + cls.postgres_conn = os.environ["QGIS_PGTEST_DB"] + cls.uri = cls.postgres_conn + " sslmode=disable" # Prepare data for threaded test cls._deleteBigData() - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(cls.uri, {}) - conn.executeSql('DROP TABLE IF EXISTS qgis_test.random_big_data CASCADE;') - conn.executeSql(f'SELECT * INTO qgis_test.random_big_data FROM ( SELECT x AS id, md5(random()::text) AS descr FROM generate_series(1,{cls.NUM_RECORDS}) x ) AS foo_row;') + conn.executeSql("DROP TABLE IF EXISTS qgis_test.random_big_data CASCADE;") + conn.executeSql( + f"SELECT * INTO qgis_test.random_big_data FROM ( SELECT x AS id, md5(random()::text) AS descr FROM generate_series(1,{cls.NUM_RECORDS}) x ) AS foo_row;" + ) @classmethod def tearDownClass(cls): @@ -64,20 +65,22 @@ def tearDownClass(cls): def _deleteBigData(cls): try: - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(cls.uri, {}) - conn.dropVectorTable('qgis_test', 'random_big_data') + conn.dropVectorTable("qgis_test", "random_big_data") except: pass def test_model(self): """Test the model""" - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.uri, {}) - res = conn.execSql('SELECT generate_series(1, 1000)') + res = conn.execSql("SELECT generate_series(1, 1000)") model = QgsQueryResultModel(res) - tester = QAbstractItemModelTester(model, QAbstractItemModelTester.FailureReportingMode.Warning) + tester = QAbstractItemModelTester( + model, QAbstractItemModelTester.FailureReportingMode.Warning + ) self.assertEqual(model.rowCount(model.index(-1, -1)), 0) while model.rowCount(model.index(-1, -1)) < 1000: @@ -85,14 +88,22 @@ def test_model(self): self.assertEqual(model.columnCount(model.index(-1, -1)), 1) self.assertEqual(model.rowCount(model.index(-1, -1)), 1000) - self.assertEqual(model.data(model.index(999, 0), Qt.ItemDataRole.DisplayRole), 1000) + self.assertEqual( + model.data(model.index(999, 0), Qt.ItemDataRole.DisplayRole), 1000 + ) # Test data for i in range(1000): - self.assertEqual(model.data(model.index(i, 0), Qt.ItemDataRole.DisplayRole), i + 1) + self.assertEqual( + model.data(model.index(i, 0), Qt.ItemDataRole.DisplayRole), i + 1 + ) - self.assertEqual(model.data(model.index(1000, 0), Qt.ItemDataRole.DisplayRole), NULL) - self.assertEqual(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), NULL) + self.assertEqual( + model.data(model.index(1000, 0), Qt.ItemDataRole.DisplayRole), NULL + ) + self.assertEqual( + model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), NULL + ) def test_model_stop(self): """Test that when a model is deleted fetching query rows is also interrupted""" @@ -103,9 +114,9 @@ def model_deleter(): def loop_exiter(): self.running = False - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.uri, {}) - res = conn.execSql('SELECT * FROM qgis_test.random_big_data') + res = conn.execSql("SELECT * FROM qgis_test.random_big_data") self.model = QgsQueryResultModel(res) @@ -125,27 +136,34 @@ def loop_exiter(): self.assertGreater(row_count, 0) self.assertLess(row_count, self.NUM_RECORDS) - @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'), 'Local manual test: not for CI') + @unittest.skipIf( + os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), + "Local manual test: not for CI", + ) def test_widget(self): """Manual local GUI test for the model""" d = QDialog() l = QVBoxLayout(d) d.setLayout(l) - lbl = QLabel('fetching...', d) + lbl = QLabel("fetching...", d) l.addWidget(lbl) v = QListView() l.addWidget(v) d.show() - md = QgsProviderRegistry.instance().providerMetadata('postgres') + md = QgsProviderRegistry.instance().providerMetadata("postgres") conn = md.createConnection(self.uri, {}) - res = conn.execSql('SELECT * FROM qgis_test.random_big_data') + res = conn.execSql("SELECT * FROM qgis_test.random_big_data") model = QgsQueryResultModel(res) - tester = QAbstractItemModelTester(model, QAbstractItemModelTester.FailureReportingMode.Warning) + tester = QAbstractItemModelTester( + model, QAbstractItemModelTester.FailureReportingMode.Warning + ) v.setModel(model) def _set_row_count(idx, first, last): - lbl.setText(f'Rows {model.rowCount(model.index(-1, -1))} fetched') # noqa: F821 + lbl.setText( + f"Rows {model.rowCount(model.index(-1, -1))} fetched" + ) # noqa: F821 model.rowsInserted.connect(_set_row_count) @@ -156,5 +174,5 @@ def _set_row_count(idx, first, last): del model -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrandommarkersymbollayer.py b/tests/src/python/test_qgsrandommarkersymbollayer.py index 3c7ab7000813..cf38766777e6 100644 --- a/tests/src/python/test_qgsrandommarkersymbollayer.py +++ b/tests/src/python/test_qgsrandommarkersymbollayer.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'October 2019' -__copyright__ = '(C) 2019, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "October 2019" +__copyright__ = "(C) 2019, Nyall Dawson" import os @@ -56,14 +56,16 @@ class TestQgsRandomMarkerSymbolLayer(QgisTestCase): @classmethod def control_path_prefix(cls): - return 'symbol_randommarkerfill' + return "symbol_randommarkerfill" def testSimple(self): s = QgsFillSymbol() s.deleteSymbolLayer(0) random_fill = QgsRandomMarkerFillSymbolLayer(10, seed=481523) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -84,7 +86,7 @@ def testSimple(self): doc = QDomDocument() context = QgsReadWriteContext() - element = QgsSymbolLayerUtils.saveSymbol('test', s, doc, context) + element = QgsSymbolLayerUtils.saveSymbol("test", s, doc, context) s2 = QgsSymbolLayerUtils.loadSymbol(element, context) self.assertEqual(s2.symbolLayer(0).pointCount(), 5) @@ -96,39 +98,66 @@ def testSimple(self): s3.appendSymbolLayer(random_fill.clone()) g = QgsGeometry.fromWkt( - 'Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))') + "Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))" + ) rendered_image = self.renderGeometry(s3, g) - self.assertTrue(self.image_check('randommarkerfill', 'randommarkerfill', rendered_image)) + self.assertTrue( + self.image_check("randommarkerfill", "randommarkerfill", rendered_image) + ) s3.symbolLayer(0).setPointCount(3) g = QgsGeometry.fromWkt( - 'Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))') + "Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))" + ) rendered_image = self.renderGeometry(s3, g) - self.assertTrue(self.image_check('randommarkerfill_3', 'randommarkerfill_3', rendered_image)) + self.assertTrue( + self.image_check("randommarkerfill_3", "randommarkerfill_3", rendered_image) + ) s3.symbolLayer(0).setSeed(12783) g = QgsGeometry.fromWkt( - 'Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))') + "Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))" + ) rendered_image = self.renderGeometry(s3, g) - self.assertTrue(self.image_check('randommarkerfill_seed', 'randommarkerfill_seed', rendered_image)) + self.assertTrue( + self.image_check( + "randommarkerfill_seed", "randommarkerfill_seed", rendered_image + ) + ) # random seed s3.symbolLayer(0).setSeed(0) g = QgsGeometry.fromWkt( - 'Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))') + "Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))" + ) rendered_image = self.renderGeometry(s3, g) - self.assertFalse(self.image_check('randommarkerfill_seed_different', 'randommarkerfill_seed', rendered_image, expect_fail=True)) + self.assertFalse( + self.image_check( + "randommarkerfill_seed_different", + "randommarkerfill_seed", + rendered_image, + expect_fail=True, + ) + ) # density-based count s3.symbolLayer(0).setSeed(1) - s3.symbolLayer(0).setCountMethod(QgsRandomMarkerFillSymbolLayer.CountMethod.DensityBasedCount) + s3.symbolLayer(0).setCountMethod( + QgsRandomMarkerFillSymbolLayer.CountMethod.DensityBasedCount + ) s3.symbolLayer(0).setPointCount(5) s3.symbolLayer(0).setDensityArea(250) # 250 square millimeter g = QgsGeometry.fromWkt( - 'Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))') + "Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))" + ) rendered_image = self.renderGeometry(s3, g) self.assertTrue( - self.image_check('randommarkerfill_densitybasedcount', 'randommarkerfill_densitybasedcount', rendered_image)) + self.image_check( + "randommarkerfill_densitybasedcount", + "randommarkerfill_densitybasedcount", + rendered_image, + ) + ) def testCreate(self): random_fill = QgsRandomMarkerFillSymbolLayer(10, seed=5) @@ -156,7 +185,9 @@ def testMultipart(self): s.appendSymbolLayer(simple_fill.clone()) random_fill = QgsRandomMarkerFillSymbolLayer(12, seed=481523) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -166,9 +197,16 @@ def testMultipart(self): s.appendSymbolLayer(random_fill.clone()) g = QgsGeometry.fromWkt( - 'MultiPolygon(((0 0, 5 0, 5 10, 0 10, 0 0),(1 1, 1 9, 4 9, 4 1, 1 1)), ((6 0, 10 0, 10 5, 6 5, 6 0)), ((8 6, 10 6, 10 10, 8 10, 8 6)))') + "MultiPolygon(((0 0, 5 0, 5 10, 0 10, 0 0),(1 1, 1 9, 4 9, 4 1, 1 1)), ((6 0, 10 0, 10 5, 6 5, 6 0)), ((8 6, 10 6, 10 10, 8 10, 8 6)))" + ) rendered_image = self.renderGeometry(s, g) - self.assertTrue(self.image_check('randommarkerfill_multipoly', 'randommarkerfill_multipoly', rendered_image)) + self.assertTrue( + self.image_check( + "randommarkerfill_multipoly", + "randommarkerfill_multipoly", + rendered_image, + ) + ) def testMultiLayer(self): """ @@ -181,7 +219,9 @@ def testMultiLayer(self): s.appendSymbolLayer(simple_fill.clone()) random_fill = QgsRandomMarkerFillSymbolLayer(12, seed=481523) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -194,13 +234,20 @@ def testMultiLayer(self): s.appendSymbolLayer(simple_fill.clone()) g = QgsGeometry.fromWkt( - 'MultiPolygon(((0 0, 5 0, 5 10, 0 10, 0 0),(1 1, 1 9, 4 9, 4 1, 1 1)), ((6 0, 10 0, 10 5, 6 5, 6 0)), ((8 6, 10 6, 10 10, 8 10, 8 6)))') + "MultiPolygon(((0 0, 5 0, 5 10, 0 10, 0 0),(1 1, 1 9, 4 9, 4 1, 1 1)), ((6 0, 10 0, 10 5, 6 5, 6 0)), ((8 6, 10 6, 10 10, 8 10, 8 6)))" + ) rendered_image = self.renderGeometry(s, g) - self.assertTrue(self.image_check('randommarkerfill_multilayer', 'randommarkerfill_multilayer', rendered_image)) + self.assertTrue( + self.image_check( + "randommarkerfill_multilayer", + "randommarkerfill_multilayer", + rendered_image, + ) + ) def testOpacityWithDataDefinedColor(self): - poly_shp = os.path.join(TEST_DATA_DIR, 'polys.shp') - poly_layer = QgsVectorLayer(poly_shp, 'Polys', 'ogr') + poly_shp = os.path.join(TEST_DATA_DIR, "polys.shp") + poly_layer = QgsVectorLayer(poly_shp, "Polys", "ogr") self.assertTrue(poly_layer.isValid()) s = QgsFillSymbol() s.deleteSymbolLayer(0) @@ -209,10 +256,14 @@ def testOpacityWithDataDefinedColor(self): marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Circle, 6) marker.setColor(QColor(255, 0, 0)) marker.setStrokeWidth(1) - marker.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyFillColor, QgsProperty.fromExpression( - "if(Name='Dam', 'red', 'green')")) - marker.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyStrokeColor, QgsProperty.fromExpression( - "if(Name='Dam', 'magenta', 'blue')")) + marker.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyFillColor, + QgsProperty.fromExpression("if(Name='Dam', 'red', 'green')"), + ) + marker.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyStrokeColor, + QgsProperty.fromExpression("if(Name='Dam', 'magenta', 'blue')"), + ) marker_symbol = QgsMarkerSymbol() marker_symbol.changeSymbolLayer(0, marker) marker_symbol.setOpacity(0.5) @@ -232,12 +283,14 @@ def testOpacityWithDataDefinedColor(self): # Test rendering self.assertTrue( - self.render_map_settings_check('randommarker_opacityddcolor', 'randommarker_opacityddcolor', ms) + self.render_map_settings_check( + "randommarker_opacityddcolor", "randommarker_opacityddcolor", ms + ) ) def testDataDefinedOpacity(self): - poly_shp = os.path.join(TEST_DATA_DIR, 'polys.shp') - poly_layer = QgsVectorLayer(poly_shp, 'Polys', 'ogr') + poly_shp = os.path.join(TEST_DATA_DIR, "polys.shp") + poly_layer = QgsVectorLayer(poly_shp, "Polys", "ogr") self.assertTrue(poly_layer.isValid()) s = QgsFillSymbol() s.deleteSymbolLayer(0) @@ -246,10 +299,14 @@ def testDataDefinedOpacity(self): marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Circle, 6) marker.setColor(QColor(255, 0, 0)) marker.setStrokeWidth(1) - marker.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyFillColor, QgsProperty.fromExpression( - "if(Name='Dam', 'red', 'green')")) - marker.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyStrokeColor, QgsProperty.fromExpression( - "if(Name='Dam', 'magenta', 'blue')")) + marker.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyFillColor, + QgsProperty.fromExpression("if(Name='Dam', 'red', 'green')"), + ) + marker.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyStrokeColor, + QgsProperty.fromExpression("if(Name='Dam', 'magenta', 'blue')"), + ) marker_symbol = QgsMarkerSymbol() marker_symbol.changeSymbolLayer(0, marker) marker_symbol.setOpacity(0.5) @@ -257,7 +314,10 @@ def testDataDefinedOpacity(self): s.appendSymbolLayer(random_fill.clone()) - s.setDataDefinedProperty(QgsSymbol.Property.PropertyOpacity, QgsProperty.fromExpression("if(\"Value\" >10, 25, 50)")) + s.setDataDefinedProperty( + QgsSymbol.Property.PropertyOpacity, + QgsProperty.fromExpression('if("Value" >10, 25, 50)'), + ) poly_layer.setRenderer(QgsSingleSymbolRenderer(s)) @@ -269,7 +329,9 @@ def testDataDefinedOpacity(self): # Test rendering self.assertTrue( - self.render_map_settings_check('randommarker_ddopacity', 'randommarker_ddopacity', ms) + self.render_map_settings_check( + "randommarker_ddopacity", "randommarker_ddopacity", ms + ) ) def renderGeometry(self, symbol, geom, buffer=20): @@ -306,5 +368,5 @@ def renderGeometry(self, symbol, geom, buffer=20): return image -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrange.py b/tests/src/python/test_qgsrange.py index f1cef0877539..c69bf6b1e03b 100644 --- a/tests/src/python/test_qgsrange.py +++ b/tests/src/python/test_qgsrange.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '11.04.2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "11.04.2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtCore import QDate from qgis.core import QgsDateRange, QgsDoubleRange, QgsIntRange, Qgis @@ -333,34 +334,70 @@ def testIsEmpty(self): def testContains(self): # includes both ends range = QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2)) - self.assertTrue(range.contains(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 4, 5)))) - self.assertTrue(range.contains(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 6, 2)))) - self.assertTrue(range.contains(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 4, 5)))) - self.assertTrue(range.contains(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2)))) - self.assertFalse(range.contains(QgsDateRange(QDate(2009, 4, 1), QDate(2010, 4, 5)))) - self.assertFalse(range.contains(QgsDateRange(QDate(2010, 4, 1), QDate(2017, 4, 5)))) + self.assertTrue( + range.contains(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 4, 5))) + ) + self.assertTrue( + range.contains(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 6, 2))) + ) + self.assertTrue( + range.contains(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 4, 5))) + ) + self.assertTrue( + range.contains(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2))) + ) + self.assertFalse( + range.contains(QgsDateRange(QDate(2009, 4, 1), QDate(2010, 4, 5))) + ) + self.assertFalse( + range.contains(QgsDateRange(QDate(2010, 4, 1), QDate(2017, 4, 5))) + ) self.assertFalse(range.contains(QgsDateRange(QDate(2010, 4, 1), QDate()))) self.assertFalse(range.contains(QgsDateRange(QDate(), QDate(2010, 4, 1)))) # infinite left end range = QgsDateRange(QDate(), QDate(2010, 6, 2)) - self.assertTrue(range.contains(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 4, 5)))) - self.assertTrue(range.contains(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 6, 2)))) - self.assertTrue(range.contains(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 4, 5)))) - self.assertTrue(range.contains(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2)))) - self.assertTrue(range.contains(QgsDateRange(QDate(2009, 4, 1), QDate(2010, 4, 5)))) - self.assertFalse(range.contains(QgsDateRange(QDate(2010, 4, 1), QDate(2017, 4, 5)))) + self.assertTrue( + range.contains(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 4, 5))) + ) + self.assertTrue( + range.contains(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 6, 2))) + ) + self.assertTrue( + range.contains(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 4, 5))) + ) + self.assertTrue( + range.contains(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2))) + ) + self.assertTrue( + range.contains(QgsDateRange(QDate(2009, 4, 1), QDate(2010, 4, 5))) + ) + self.assertFalse( + range.contains(QgsDateRange(QDate(2010, 4, 1), QDate(2017, 4, 5))) + ) self.assertFalse(range.contains(QgsDateRange(QDate(2010, 4, 1), QDate()))) self.assertTrue(range.contains(QgsDateRange(QDate(), QDate(2010, 4, 1)))) # infinite right end range = QgsDateRange(QDate(2010, 3, 1), QDate()) - self.assertTrue(range.contains(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 4, 5)))) - self.assertTrue(range.contains(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 6, 2)))) - self.assertTrue(range.contains(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 4, 5)))) - self.assertTrue(range.contains(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2)))) - self.assertFalse(range.contains(QgsDateRange(QDate(2009, 4, 1), QDate(2010, 4, 5)))) - self.assertTrue(range.contains(QgsDateRange(QDate(2010, 4, 1), QDate(2017, 4, 5)))) + self.assertTrue( + range.contains(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 4, 5))) + ) + self.assertTrue( + range.contains(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 6, 2))) + ) + self.assertTrue( + range.contains(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 4, 5))) + ) + self.assertTrue( + range.contains(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2))) + ) + self.assertFalse( + range.contains(QgsDateRange(QDate(2009, 4, 1), QDate(2010, 4, 5))) + ) + self.assertTrue( + range.contains(QgsDateRange(QDate(2010, 4, 1), QDate(2017, 4, 5))) + ) self.assertTrue(range.contains(QgsDateRange(QDate(2010, 4, 1), QDate()))) self.assertFalse(range.contains(QgsDateRange(QDate(), QDate(2010, 4, 1)))) @@ -395,60 +432,128 @@ def testContainsElement(self): def testOverlaps(self): # includes both ends range = QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2)) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 4, 5)))) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 6, 2)))) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 4, 5)))) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2)))) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2009, 4, 1), QDate(2010, 4, 5)))) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate(2017, 4, 5)))) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 4, 5))) + ) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 6, 2))) + ) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 4, 5))) + ) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2))) + ) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2009, 4, 1), QDate(2010, 4, 5))) + ) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate(2017, 4, 5))) + ) self.assertTrue(range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate()))) self.assertTrue(range.overlaps(QgsDateRange(QDate(), QDate(2010, 4, 1)))) - self.assertFalse(range.overlaps(QgsDateRange(QDate(2009, 4, 1), QDate(2009, 8, 5)))) - self.assertFalse(range.overlaps(QgsDateRange(QDate(2019, 4, 1), QDate(2019, 8, 5)))) + self.assertFalse( + range.overlaps(QgsDateRange(QDate(2009, 4, 1), QDate(2009, 8, 5))) + ) + self.assertFalse( + range.overlaps(QgsDateRange(QDate(2019, 4, 1), QDate(2019, 8, 5))) + ) range = QgsDateRange(QDate(), QDate(2010, 6, 2)) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 4, 5)))) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 6, 2)))) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 4, 5)))) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2)))) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2009, 4, 1), QDate(2010, 4, 5)))) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate(2017, 4, 5)))) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 4, 5))) + ) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 6, 2))) + ) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 4, 5))) + ) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2))) + ) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2009, 4, 1), QDate(2010, 4, 5))) + ) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate(2017, 4, 5))) + ) self.assertTrue(range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate()))) self.assertTrue(range.overlaps(QgsDateRange(QDate(), QDate(2010, 4, 1)))) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2009, 4, 1), QDate(2009, 8, 5)))) - self.assertFalse(range.overlaps(QgsDateRange(QDate(2019, 4, 1), QDate(2019, 8, 5)))) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2009, 4, 1), QDate(2009, 8, 5))) + ) + self.assertFalse( + range.overlaps(QgsDateRange(QDate(2019, 4, 1), QDate(2019, 8, 5))) + ) range = QgsDateRange(QDate(2010, 3, 1), QDate()) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 4, 5)))) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 6, 2)))) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 4, 5)))) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2)))) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2009, 4, 1), QDate(2010, 4, 5)))) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate(2017, 4, 5)))) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 4, 5))) + ) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate(2010, 6, 2))) + ) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 4, 5))) + ) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2))) + ) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2009, 4, 1), QDate(2010, 4, 5))) + ) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate(2017, 4, 5))) + ) self.assertTrue(range.overlaps(QgsDateRange(QDate(2010, 4, 1), QDate()))) self.assertTrue(range.overlaps(QgsDateRange(QDate(), QDate(2010, 4, 1)))) - self.assertFalse(range.overlaps(QgsDateRange(QDate(2009, 4, 1), QDate(2009, 8, 5)))) - self.assertTrue(range.overlaps(QgsDateRange(QDate(2019, 4, 1), QDate(2019, 8, 5)))) + self.assertFalse( + range.overlaps(QgsDateRange(QDate(2009, 4, 1), QDate(2009, 8, 5))) + ) + self.assertTrue( + range.overlaps(QgsDateRange(QDate(2019, 4, 1), QDate(2019, 8, 5))) + ) def testIsInstant(self): self.assertFalse(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2)).isInstant()) self.assertTrue(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 3, 1)).isInstant()) - self.assertFalse(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 3, 1), False, False).isInstant()) + self.assertFalse( + QgsDateRange(QDate(2010, 3, 1), QDate(2010, 3, 1), False, False).isInstant() + ) self.assertFalse(QgsDateRange(QDate(), QDate()).isInstant()) def testIsInfinite(self): - self.assertFalse(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2)).isInfinite()) - self.assertFalse(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 3, 1)).isInfinite()) - self.assertFalse(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 3, 1), False, False).isInfinite()) + self.assertFalse( + QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2)).isInfinite() + ) + self.assertFalse( + QgsDateRange(QDate(2010, 3, 1), QDate(2010, 3, 1)).isInfinite() + ) + self.assertFalse( + QgsDateRange( + QDate(2010, 3, 1), QDate(2010, 3, 1), False, False + ).isInfinite() + ) self.assertTrue(QgsDateRange(QDate(), QDate()).isInfinite()) def testEquality(self): range = QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, False) - self.assertEqual(range, QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, False)) - self.assertNotEqual(range, QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, True)) - self.assertNotEqual(range, QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), True, False)) - self.assertNotEqual(range, QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 3), False, False)) - self.assertNotEqual(range, QgsDateRange(QDate(2010, 3, 2), QDate(2010, 6, 2), False, False)) + self.assertEqual( + range, QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, False) + ) + self.assertNotEqual( + range, QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, True) + ) + self.assertNotEqual( + range, QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), True, False) + ) + self.assertNotEqual( + range, QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 3), False, False) + ) + self.assertNotEqual( + range, QgsDateRange(QDate(2010, 3, 2), QDate(2010, 6, 2), False, False) + ) def testExtend(self): range_empty = QgsDateRange(QDate(2010, 6, 2), QDate(2010, 3, 1)) @@ -458,48 +563,106 @@ def testExtend(self): range = QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, False) self.assertFalse(range.extend(range_empty)) range = QgsDateRange(QDate(2010, 6, 2), QDate(2010, 3, 1)) - self.assertTrue(range.extend(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, False))) - self.assertEqual(range, QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, False)) + self.assertTrue( + range.extend( + QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, False) + ) + ) + self.assertEqual( + range, QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, False) + ) # Extend low range = QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, False) - self.assertTrue(range.extend(QgsDateRange(QDate(2010, 2, 1), QDate(2010, 6, 2), False, False))) - self.assertEqual(range, QgsDateRange(QDate(2010, 2, 1), QDate(2010, 6, 2), False, False)) + self.assertTrue( + range.extend( + QgsDateRange(QDate(2010, 2, 1), QDate(2010, 6, 2), False, False) + ) + ) + self.assertEqual( + range, QgsDateRange(QDate(2010, 2, 1), QDate(2010, 6, 2), False, False) + ) range = QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, False) - self.assertTrue(range.extend(QgsDateRange(QDate(2010, 2, 1), QDate(2010, 5, 2), True, False))) - self.assertEqual(range, QgsDateRange(QDate(2010, 2, 1), QDate(2010, 6, 2), True, False)) + self.assertTrue( + range.extend( + QgsDateRange(QDate(2010, 2, 1), QDate(2010, 5, 2), True, False) + ) + ) + self.assertEqual( + range, QgsDateRange(QDate(2010, 2, 1), QDate(2010, 6, 2), True, False) + ) # Extend high range = QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, False) - self.assertTrue(range.extend(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 7, 2), False, False))) - self.assertEqual(range, QgsDateRange(QDate(2010, 3, 1), QDate(2010, 7, 2), False, False)) + self.assertTrue( + range.extend( + QgsDateRange(QDate(2010, 3, 1), QDate(2010, 7, 2), False, False) + ) + ) + self.assertEqual( + range, QgsDateRange(QDate(2010, 3, 1), QDate(2010, 7, 2), False, False) + ) range = QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, False) - self.assertTrue(range.extend(QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, True))) - self.assertEqual(range, QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, True)) + self.assertTrue( + range.extend( + QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, True) + ) + ) + self.assertEqual( + range, QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, True) + ) # Extend both range = QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, False) - self.assertTrue(range.extend(QgsDateRange(QDate(2010, 2, 1), QDate(2010, 7, 2), False, False))) - self.assertEqual(range, QgsDateRange(QDate(2010, 2, 1), QDate(2010, 7, 2), False, False)) + self.assertTrue( + range.extend( + QgsDateRange(QDate(2010, 2, 1), QDate(2010, 7, 2), False, False) + ) + ) + self.assertEqual( + range, QgsDateRange(QDate(2010, 2, 1), QDate(2010, 7, 2), False, False) + ) # Extend none range = QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, False) - self.assertFalse(range.extend(QgsDateRange(QDate(2010, 4, 6), QDate(2010, 5, 2), False, False))) + self.assertFalse( + range.extend( + QgsDateRange(QDate(2010, 4, 6), QDate(2010, 5, 2), False, False) + ) + ) # Test infinity range = QgsDateRange(QDate(), QDate()) - self.assertFalse(range.extend(QgsDateRange(QDate(2010, 4, 6), QDate(2010, 5, 2), False, False))) + self.assertFalse( + range.extend( + QgsDateRange(QDate(2010, 4, 6), QDate(2010, 5, 2), False, False) + ) + ) range = QgsDateRange(QDate(), QDate(2010, 5, 2)) - self.assertFalse(range.extend(QgsDateRange(QDate(2010, 4, 6), QDate(2010, 5, 2), False, False))) + self.assertFalse( + range.extend( + QgsDateRange(QDate(2010, 4, 6), QDate(2010, 5, 2), False, False) + ) + ) self.assertEqual(range, QgsDateRange(QDate(), QDate(2010, 5, 2), True, True)) range = QgsDateRange(QDate(2010, 4, 6), QDate()) - self.assertTrue(range.extend(QgsDateRange(QDate(2010, 3, 6), QDate(2010, 5, 2), False, False))) + self.assertTrue( + range.extend( + QgsDateRange(QDate(2010, 3, 6), QDate(2010, 5, 2), False, False) + ) + ) self.assertEqual(range, QgsDateRange(QDate(2010, 3, 6), QDate(), False, True)) range = QgsDateRange(QDate(), QDate(2010, 5, 2)) - self.assertTrue(range.extend(QgsDateRange(QDate(2010, 3, 6), QDate(2010, 6, 2), False, False))) + self.assertTrue( + range.extend( + QgsDateRange(QDate(2010, 3, 6), QDate(2010, 6, 2), False, False) + ) + ) self.assertEqual(range, QgsDateRange(QDate(), QDate(2010, 6, 2), True, False)) range = QgsDateRange(QDate(2010, 4, 6), QDate()) - self.assertTrue(range.extend(QgsDateRange(QDate(), QDate(2010, 5, 2), True, False))) + self.assertTrue( + range.extend(QgsDateRange(QDate(), QDate(2010, 5, 2), True, False)) + ) self.assertEqual(range, QgsDateRange(QDate(), QDate(), True, True)) range = QgsDateRange(QDate(), QDate(2010, 4, 6)) self.assertTrue(range.extend(QgsDateRange(QDate(), QDate(), True, True))) diff --git a/tests/src/python/test_qgsrangeslider.py b/tests/src/python/test_qgsrangeslider.py index 105147e74697..17370a021e53 100644 --- a/tests/src/python/test_qgsrangeslider.py +++ b/tests/src/python/test_qgsrangeslider.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2020-11-25' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2020-11-25" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import Qt from qgis.PyQt.QtTest import QSignalSpy @@ -323,5 +324,5 @@ def test_fixed_range_width(self): self.assertEqual(w.lowerValue(), 0) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrangewidgets.py b/tests/src/python/test_qgsrangewidgets.py index ab536c7c4297..54462297c619 100644 --- a/tests/src/python/test_qgsrangewidgets.py +++ b/tests/src/python/test_qgsrangewidgets.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Tobias Reber' -__date__ = '20/05/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Tobias Reber" +__date__ = "20/05/2015" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.core import NULL, QgsFeature, QgsGeometry, QgsPointXY, QgsVectorLayer @@ -29,8 +30,11 @@ def setUp(self): """ create a layer with one feature """ - self.layer = QgsVectorLayer("Point?crs=EPSG:21781&field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + self.layer = QgsVectorLayer( + "Point?crs=EPSG:21781&field=fldtxt:string&field=fldint:integer", + "addfeat", + "memory", + ) pr = self.layer.dataProvider() # NOQA f = QgsFeature() f.setAttributes(["Hello World", 123]) @@ -41,7 +45,7 @@ def __createRangeWidget(self, allownull=False): create a range widget """ reg = QgsGui.editorWidgetRegistry() - configWdg = reg.createConfigWidget('Range', self.layer, 1, None) + configWdg = reg.createConfigWidget("Range", self.layer, 1, None) config = configWdg.config() config["Min"] = 0 @@ -49,7 +53,7 @@ def __createRangeWidget(self, allownull=False): if allownull: config["AllowNull"] = allownull - rangewidget = reg.create('Range', self.layer, 1, config, None, None) + rangewidget = reg.create("Range", self.layer, 1, config, None, None) return rangewidget def test_range_widget_numbers(self): @@ -92,5 +96,5 @@ def test_range_widget_null_allowed(self): self.assertEqual(rangewidget.value(), 0) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterattributetable.py b/tests/src/python/test_qgsrasterattributetable.py index 44d074f08e48..09540b59830d 100644 --- a/tests/src/python/test_qgsrasterattributetable.py +++ b/tests/src/python/test_qgsrasterattributetable.py @@ -9,9 +9,9 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '20/08/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "20/08/2022" +__copyright__ = "Copyright 2022, The QGIS Project" import os import shutil @@ -88,33 +88,35 @@ def createTestRasters(cls, path): geotransform = (xmin, xres, 0, ymax, 0, -yres) # create the 2-band raster file - cls.uri_2x2_2_BANDS_INT16 = os.path.join(cls.temp_path, '2x2_2_BANDS_INT16.tif') - dst_ds = gdal.GetDriverByName('GTiff').Create( - cls.uri_2x2_2_BANDS_INT16, ny, nx, 2, gdal.GDT_Int16) - - dst_ds.SetGeoTransform(geotransform) # specify coords - srs = osr.SpatialReference() # establish encoding - srs.ImportFromEPSG(3857) # WGS84 lat/long + cls.uri_2x2_2_BANDS_INT16 = os.path.join(cls.temp_path, "2x2_2_BANDS_INT16.tif") + dst_ds = gdal.GetDriverByName("GTiff").Create( + cls.uri_2x2_2_BANDS_INT16, ny, nx, 2, gdal.GDT_Int16 + ) + + dst_ds.SetGeoTransform(geotransform) # specify coords + srs = osr.SpatialReference() # establish encoding + srs.ImportFromEPSG(3857) # WGS84 lat/long dst_ds.SetProjection(srs.ExportToWkt()) # export coords to file - dst_ds.GetRasterBand(1).WriteArray(r_pixels) # write r-band to the raster + dst_ds.GetRasterBand(1).WriteArray(r_pixels) # write r-band to the raster dst_ds.GetRasterBand(2).WriteArray(g_pixels) # write g-band to the raster - dst_ds.FlushCache() # write to disk + dst_ds.FlushCache() # write to disk dst_ds = None # Create the single band version of the 16 bit raster # 2x2_1_BAND_INT16 - cls.uri_2x2_1_BAND_INT16 = os.path.join(cls.temp_path, '2x2_1_BAND_INT16.tif') - dst_ds = gdal.GetDriverByName('GTiff').Create( - cls.uri_2x2_1_BAND_INT16, ny, nx, 1, gdal.GDT_Int16) - - dst_ds.SetGeoTransform(geotransform) # specify coords - srs = osr.SpatialReference() # establish encoding - srs.ImportFromEPSG(3857) # WGS84 lat/long + cls.uri_2x2_1_BAND_INT16 = os.path.join(cls.temp_path, "2x2_1_BAND_INT16.tif") + dst_ds = gdal.GetDriverByName("GTiff").Create( + cls.uri_2x2_1_BAND_INT16, ny, nx, 1, gdal.GDT_Int16 + ) + + dst_ds.SetGeoTransform(geotransform) # specify coords + srs = osr.SpatialReference() # establish encoding + srs.ImportFromEPSG(3857) # WGS84 lat/long dst_ds.SetProjection(srs.ExportToWkt()) # export coords to file - dst_ds.GetRasterBand(1).WriteArray(r_pixels) # write r-band to the raster + dst_ds.GetRasterBand(1).WriteArray(r_pixels) # write r-band to the raster - dst_ds.FlushCache() # write to disk + dst_ds.FlushCache() # write to disk dst_ds = None # Create a 2x2 single band float raster @@ -124,22 +126,23 @@ def createTestRasters(cls, path): # Create Each Channel r_pixels = np.zeros((image_size), dtype=np.float64) - r_pixels[0, 0] = -1E23 + r_pixels[0, 0] = -1e23 r_pixels[0, 1] = 2.345 - r_pixels[1, 0] = 3.456E12 - r_pixels[1, 1] = 4.567E23 + r_pixels[1, 0] = 3.456e12 + r_pixels[1, 1] = 4.567e23 - cls.uri_2x2_1_BAND_FLOAT = os.path.join(cls.temp_path, '2x2_1_BAND_FLOAT.tif') - dst_ds = gdal.GetDriverByName('GTiff').Create( - cls.uri_2x2_1_BAND_FLOAT, ny, nx, 1, gdal.GDT_Float32) + cls.uri_2x2_1_BAND_FLOAT = os.path.join(cls.temp_path, "2x2_1_BAND_FLOAT.tif") + dst_ds = gdal.GetDriverByName("GTiff").Create( + cls.uri_2x2_1_BAND_FLOAT, ny, nx, 1, gdal.GDT_Float32 + ) - dst_ds.SetGeoTransform(geotransform) # specify coords - srs = osr.SpatialReference() # establish encoding - srs.ImportFromEPSG(3857) # WGS84 lat/long + dst_ds.SetGeoTransform(geotransform) # specify coords + srs = osr.SpatialReference() # establish encoding + srs.ImportFromEPSG(3857) # WGS84 lat/long dst_ds.SetProjection(srs.ExportToWkt()) # export coords to file - dst_ds.GetRasterBand(1).WriteArray(r_pixels) # write r-band to the raster + dst_ds.GetRasterBand(1).WriteArray(r_pixels) # write r-band to the raster - dst_ds.FlushCache() # write to disk + dst_ds.FlushCache() # write to disk dst_ds = None @@ -157,20 +160,56 @@ def testRat(self): # Create RAT rat = QgsRasterAttributeTable() - rat.appendField(QgsRasterAttributeTable.Field('Value', Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Count', Qgis.RasterAttributeTableFieldUsage.PixelCount, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Class', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Class2', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Class3', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Red', Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Green', Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Blue', Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Double', Qgis.RasterAttributeTableFieldUsage.Generic, QVariant.Double)) + rat.appendField( + QgsRasterAttributeTable.Field( + "Value", Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Count", Qgis.RasterAttributeTableFieldUsage.PixelCount, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class2", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class3", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Red", Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Green", Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Blue", Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Double", Qgis.RasterAttributeTableFieldUsage.Generic, QVariant.Double + ) + ) data_rows = [ - [0, 1, 'zero', 'zero2', 'zero3', 0, 10, 100, 1.234], - [2, 1, 'one', 'one2', 'one3', 100, 20, 0, 0.998], - [4, 2, 'two', 'two2', 'two3', 200, 30, 50, 123456], + [0, 1, "zero", "zero2", "zero3", 0, 10, 100, 1.234], + [2, 1, "one", "one2", "one3", 100, 20, 0, 0.998], + [4, 2, "two", "two2", "two3", 200, 30, 50, 123456], ] for row in data_rows: @@ -196,29 +235,91 @@ def testRat(self): rat = d.attributeTable(1) self.assertEqual(rat.type(), Qgis.RasterAttributeTableType.Thematic) self.assertTrue(rat.isValid()[0]) - self.assertEqual([f.name for f in rat.fields()], ['Value', 'Count', 'Class', 'Class2', 'Class3', 'Red', 'Green', 'Blue', 'Double']) - self.assertEqual([f.type for f in rat.fields()], [QVariant.Int, QVariant.Int, QVariant.String, QVariant.String, QVariant.String, QVariant.Int, QVariant.Int, QVariant.Int, QVariant.Double]) - self.assertEqual(rat.data(), [ - [0, 1, 'zero', 'zero2', 'zero3', 0, 10, 100, 1.234], - [2, 1, 'one', 'one2', 'one3', 100, 20, 0, 0.998], - [4, 2, 'two', 'two2', 'two3', 200, 30, 50, 123456]]) + self.assertEqual( + [f.name for f in rat.fields()], + [ + "Value", + "Count", + "Class", + "Class2", + "Class3", + "Red", + "Green", + "Blue", + "Double", + ], + ) + self.assertEqual( + [f.type for f in rat.fields()], + [ + QVariant.Int, + QVariant.Int, + QVariant.String, + QVariant.String, + QVariant.String, + QVariant.Int, + QVariant.Int, + QVariant.Int, + QVariant.Double, + ], + ) + self.assertEqual( + rat.data(), + [ + [0, 1, "zero", "zero2", "zero3", 0, 10, 100, 1.234], + [2, 1, "one", "one2", "one3", 100, 20, 0, 0.998], + [4, 2, "two", "two2", "two3", 200, 30, 50, 123456], + ], + ) # Band 2 data_rows = [ - [1, 1, 'one', 'one2', 'one3', 100, 20, 10], - [3, 1, 'three', 'three2', 'tree3', 200, 10, 20], - [5, 2, 'five', 'five2', 'five3', 50, 40, 250], + [1, 1, "one", "one2", "one3", 100, 20, 10], + [3, 1, "three", "three2", "tree3", 200, 10, 20], + [5, 2, "five", "five2", "five3", 50, 40, 250], ] rat = QgsRasterAttributeTable() - rat.appendField(QgsRasterAttributeTable.Field('Value', Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Count', Qgis.RasterAttributeTableFieldUsage.PixelCount, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Class', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Class2', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Class3', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Red', Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Green', Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Blue', Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int)) + rat.appendField( + QgsRasterAttributeTable.Field( + "Value", Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Count", Qgis.RasterAttributeTableFieldUsage.PixelCount, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class2", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class3", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Red", Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Green", Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Blue", Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int + ) + ) for row in data_rows: rat.appendRow(row) @@ -236,55 +337,131 @@ def testRat(self): rat = d.attributeTable(1) self.assertTrue(rat.isValid()[0]) rat.fields() - self.assertEqual([f.name for f in rat.fields()], ['Value', 'Count', 'Class', 'Class2', 'Class3', 'Red', 'Green', 'Blue', 'Double']) - self.assertEqual([f.type for f in rat.fields()], [QVariant.Int, QVariant.Int, QVariant.String, QVariant.String, QVariant.String, QVariant.Int, QVariant.Int, QVariant.Int, QVariant.Double]) - self.assertEqual(rat.data(), [ - [0, 1, 'zero', 'zero2', 'zero3', 0, 10, 100, 1.234], - [2, 1, 'one', 'one2', 'one3', 100, 20, 0, 0.998], - [4, 2, 'two', 'two2', 'two3', 200, 30, 50, 123456]]) + self.assertEqual( + [f.name for f in rat.fields()], + [ + "Value", + "Count", + "Class", + "Class2", + "Class3", + "Red", + "Green", + "Blue", + "Double", + ], + ) + self.assertEqual( + [f.type for f in rat.fields()], + [ + QVariant.Int, + QVariant.Int, + QVariant.String, + QVariant.String, + QVariant.String, + QVariant.Int, + QVariant.Int, + QVariant.Int, + QVariant.Double, + ], + ) + self.assertEqual( + rat.data(), + [ + [0, 1, "zero", "zero2", "zero3", 0, 10, 100, 1.234], + [2, 1, "one", "one2", "one3", 100, 20, 0, 0.998], + [4, 2, "two", "two2", "two3", 200, 30, 50, 123456], + ], + ) rat = d.attributeTable(2) self.assertTrue(rat.isValid()[0]) self.assertTrue(rat.hasColor()) rat.fields() - self.assertEqual([f.name for f in rat.fields()], ['Value', 'Count', 'Class', 'Class2', 'Class3', 'Red', 'Green', 'Blue']) - self.assertEqual(rat.data(), [ - [1, 1, 'one', 'one2', 'one3', 100, 20, 10], - [3, 1, 'three', 'three2', 'tree3', 200, 10, 20], - [5, 2, 'five', 'five2', 'five3', 50, 40, 250], - ]) + self.assertEqual( + [f.name for f in rat.fields()], + ["Value", "Count", "Class", "Class2", "Class3", "Red", "Green", "Blue"], + ) + self.assertEqual( + rat.data(), + [ + [1, 1, "one", "one2", "one3", 100, 20, 10], + [3, 1, "three", "three2", "tree3", 200, 10, 20], + [5, 2, "five", "five2", "five3", 50, 40, 250], + ], + ) # Test DBF RATs self.assertTrue(d.writeFileBasedAttributeTable(1, self.uri_2x2_2_BANDS_INT16)) del raster - os.unlink(self.uri_2x2_2_BANDS_INT16 + '.aux.xml') + os.unlink(self.uri_2x2_2_BANDS_INT16 + ".aux.xml") raster = QgsRasterLayer(self.uri_2x2_2_BANDS_INT16) self.assertTrue(raster.isValid()) d = raster.dataProvider() self.assertFalse(d.readNativeAttributeTable()[0]) - self.assertTrue(d.readFileBasedAttributeTable(1, self.uri_2x2_2_BANDS_INT16 + '.vat.dbf')[0]) + self.assertTrue( + d.readFileBasedAttributeTable(1, self.uri_2x2_2_BANDS_INT16 + ".vat.dbf")[0] + ) rat = d.attributeTable(1) self.assertTrue(rat.isValid()[0]) - self.assertEqual([f.name for f in rat.fields()], ['Value', 'Count', 'Class', 'Class2', 'Class3', 'Red', 'Green', 'Blue', 'Double']) + self.assertEqual( + [f.name for f in rat.fields()], + [ + "Value", + "Count", + "Class", + "Class2", + "Class3", + "Red", + "Green", + "Blue", + "Double", + ], + ) # Note: when reading from DBF, count and value are always long - self.assertEqual([f.type for f in rat.fields()], [QVariant.LongLong, QVariant.LongLong, QVariant.String, QVariant.String, QVariant.String, QVariant.Int, QVariant.Int, QVariant.Int, QVariant.Double]) - self.assertEqual(rat.data(), [ - [0, 1, 'zero', 'zero2', 'zero3', 0, 10, 100, 1.234], - [2, 1, 'one', 'one2', 'one3', 100, 20, 0, 0.998], - [4, 2, 'two', 'two2', 'two3', 200, 30, 50, 123456]]) + self.assertEqual( + [f.type for f in rat.fields()], + [ + QVariant.LongLong, + QVariant.LongLong, + QVariant.String, + QVariant.String, + QVariant.String, + QVariant.Int, + QVariant.Int, + QVariant.Int, + QVariant.Double, + ], + ) + self.assertEqual( + rat.data(), + [ + [0, 1, "zero", "zero2", "zero3", 0, 10, 100, 1.234], + [2, 1, "one", "one2", "one3", 100, 20, 0, 0.998], + [4, 2, "two", "two2", "two3", 200, 30, 50, 123456], + ], + ) # Test color self.assertTrue(rat.hasColor()) self.assertFalse(rat.hasRamp()) - self.assertEqual(rat.color(0).name(), '#000a64') + self.assertEqual(rat.color(0).name(), "#000a64") self.assertEqual(rat.color(0).alpha(), 255) - self.assertEqual(rat.color(1).name(), '#641400') - - self.assertEqual(len(rat.fieldsByUsage(Qgis.RasterAttributeTableFieldUsage.Blue)), 1) - self.assertEqual(len(rat.fieldsByUsage(Qgis.RasterAttributeTableFieldUsage.Alpha)), 0) - - self.assertTrue(rat.fieldsByUsage(Qgis.RasterAttributeTableFieldUsage.Red)[0].isColor()) - self.assertFalse(rat.fieldsByUsage(Qgis.RasterAttributeTableFieldUsage.Red)[0].isRamp()) + self.assertEqual(rat.color(1).name(), "#641400") + + self.assertEqual( + len(rat.fieldsByUsage(Qgis.RasterAttributeTableFieldUsage.Blue)), 1 + ) + self.assertEqual( + len(rat.fieldsByUsage(Qgis.RasterAttributeTableFieldUsage.Alpha)), 0 + ) + + self.assertTrue( + rat.fieldsByUsage(Qgis.RasterAttributeTableFieldUsage.Red)[0].isColor() + ) + self.assertFalse( + rat.fieldsByUsage(Qgis.RasterAttributeTableFieldUsage.Red)[0].isRamp() + ) self.assertTrue(rat.fieldByName("Blue")[1]) self.assertTrue(rat.fieldByName("Red")[1]) @@ -298,16 +475,24 @@ def testTableOperationsAndValidation(self): self.assertNotEqual(len(error), 0) valid, error = rat.isValid() - rat.appendField(QgsRasterAttributeTable.Field('Class', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) self.assertFalse(valid) self.assertNotEqual(len(error), 0) - rat.appendField(QgsRasterAttributeTable.Field('Value', Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Int)) + rat.appendField( + QgsRasterAttributeTable.Field( + "Value", Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Int + ) + ) self.assertFalse(valid) self.assertNotEqual(len(error), 0) data_rows = [ - ['zero', 0], - ['two', 2], - ['four', 4], + ["zero", 0], + ["two", 2], + ["four", 4], ] for row in data_rows: rat.appendRow(row) @@ -321,121 +506,237 @@ def testTableOperationsAndValidation(self): self.assertFalse(rat.hasRamp()) # Add color - rat.appendField(QgsRasterAttributeTable.Field('Red', Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Green', Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Blue', Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int)) + rat.appendField( + QgsRasterAttributeTable.Field( + "Red", Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Green", Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Blue", Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int + ) + ) self.assertTrue(rat.hasColor()) self.assertFalse(rat.hasRamp()) - self.assertEqual([f.name for f in rat.fields()], ['Class', 'Value', 'Red', 'Green', 'Blue']) + self.assertEqual( + [f.name for f in rat.fields()], ["Class", "Value", "Red", "Green", "Blue"] + ) for row in rat.data(): self.assertEqual(len(row), 5) # Remove fields - self.assertFalse(rat.removeField('xxx')[0]) - self.assertTrue(rat.removeField('Red')[0]) - self.assertEqual([f.name for f in rat.fields()], ['Class', 'Value', 'Green', 'Blue']) + self.assertFalse(rat.removeField("xxx")[0]) + self.assertTrue(rat.removeField("Red")[0]) + self.assertEqual( + [f.name for f in rat.fields()], ["Class", "Value", "Green", "Blue"] + ) for row in rat.data(): self.assertEqual(len(row), 4) self.assertFalse(rat.isValid()[0]) # Test insert and append # unique field already exists - self.assertFalse(rat.appendField(QgsRasterAttributeTable.Field('Blue', Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int))[0]) - self.assertTrue(rat.appendField(QgsRasterAttributeTable.Field('Red', Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int))[0]) - - self.assertEqual([f.name for f in rat.fields()], ['Class', 'Value', 'Green', 'Blue', 'Red']) + self.assertFalse( + rat.appendField( + QgsRasterAttributeTable.Field( + "Blue", Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int + ) + )[0] + ) + self.assertTrue( + rat.appendField( + QgsRasterAttributeTable.Field( + "Red", Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int + ) + )[0] + ) + + self.assertEqual( + [f.name for f in rat.fields()], ["Class", "Value", "Green", "Blue", "Red"] + ) for row in rat.data(): self.assertEqual(len(row), 5) self.assertTrue(rat.isValid()[0]) - self.assertTrue(rat.removeField('Red')[0]) - self.assertTrue(rat.insertField(-1, QgsRasterAttributeTable.Field('Red', Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int))[0]) - self.assertEqual([f.name for f in rat.fields()], ['Red', 'Class', 'Value', 'Green', 'Blue']) - self.assertTrue(rat.removeField('Red')[0]) + self.assertTrue(rat.removeField("Red")[0]) + self.assertTrue( + rat.insertField( + -1, + QgsRasterAttributeTable.Field( + "Red", Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int + ), + )[0] + ) + self.assertEqual( + [f.name for f in rat.fields()], ["Red", "Class", "Value", "Green", "Blue"] + ) + self.assertTrue(rat.removeField("Red")[0]) # 100 is not valid but field is appended - self.assertTrue(rat.insertField(100, QgsRasterAttributeTable.Field('Red', Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int))[0]) - self.assertEqual([f.name for f in rat.fields()], ['Class', 'Value', 'Green', 'Blue', 'Red']) + self.assertTrue( + rat.insertField( + 100, + QgsRasterAttributeTable.Field( + "Red", Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int + ), + )[0] + ) + self.assertEqual( + [f.name for f in rat.fields()], ["Class", "Value", "Green", "Blue", "Red"] + ) # Test row operations self.assertFalse(rat.appendRow([])[0]) - self.assertFalse(rat.appendRow(['class', '3', '10', 20, 100.1, 'xxx'])[0]) - self.assertTrue(rat.appendRow(['class', '3', '10', 20, 100.1])[0]) - self.assertEqual(rat.data()[3], ['class', 3, 10, 20, 100]) + self.assertFalse(rat.appendRow(["class", "3", "10", 20, 100.1, "xxx"])[0]) + self.assertTrue(rat.appendRow(["class", "3", "10", 20, 100.1])[0]) + self.assertEqual(rat.data()[3], ["class", 3, 10, 20, 100]) # Get/set color color = rat.color(3) - self.assertEqual(color.name(), '#640a14') - self.assertTrue(rat.setColor(3, QColor('#010203'))) + self.assertEqual(color.name(), "#640a14") + self.assertTrue(rat.setColor(3, QColor("#010203"))) color = rat.color(3) - self.assertEqual(color.name(), '#010203') + self.assertEqual(color.name(), "#010203") # Set value - self.assertFalse(rat.setValue(-1, 0, 'class_new')) - self.assertFalse(rat.setValue(100, 0, 'class_new')) - self.assertFalse(rat.setValue(0, 100, 'class_new')) - self.assertTrue(rat.setValue(3, 0, 'class_new')) - self.assertTrue(rat.value(3, 0), 'class_new') + self.assertFalse(rat.setValue(-1, 0, "class_new")) + self.assertFalse(rat.setValue(100, 0, "class_new")) + self.assertFalse(rat.setValue(0, 100, "class_new")) + self.assertTrue(rat.setValue(3, 0, "class_new")) + self.assertTrue(rat.value(3, 0), "class_new") # Remove row self.assertEqual(len(rat.data()), 4) self.assertFalse(rat.removeRow(-1)[0]) self.assertTrue(rat.removeRow(0)[0]) self.assertEqual(len(rat.data()), 3) - self.assertEqual(rat.data()[0][0], 'two') + self.assertEqual(rat.data()[0][0], "two") # Insert row - self.assertTrue(rat.insertRow(-1, ['zero', 0, 0, 0, 0])[0]) - self.assertEqual(rat.data()[0][0], 'zero') + self.assertTrue(rat.insertRow(-1, ["zero", 0, 0, 0, 0])[0]) + self.assertEqual(rat.data()[0][0], "zero") self.assertEqual(len(rat.data()), 4) - self.assertTrue(rat.insertRow(1000, ['five', 1, 2, 3, 4])[0]) - self.assertEqual(rat.data()[4], ['five', 1, 2, 3, 4]) + self.assertTrue(rat.insertRow(1000, ["five", 1, 2, 3, 4])[0]) + self.assertEqual(rat.data()[4], ["five", 1, 2, 3, 4]) self.assertEqual(len(rat.data()), 5) - self.assertTrue(rat.insertRow(1, ['after 0', 1, 2, 3, 4])[0]) - self.assertEqual(rat.data()[1], ['after 0', 1, 2, 3, 4]) + self.assertTrue(rat.insertRow(1, ["after 0", 1, 2, 3, 4])[0]) + self.assertEqual(rat.data()[1], ["after 0", 1, 2, 3, 4]) self.assertEqual(len(rat.data()), 6) # Remove color and add ramp - self.assertTrue(rat.removeField('Red')[0]) - self.assertTrue(rat.removeField('Green')[0]) - self.assertTrue(rat.removeField('Blue')[0]) - self.assertTrue(rat.removeField('Value')[0]) - rat.appendField(QgsRasterAttributeTable.Field('RedMin', Qgis.RasterAttributeTableFieldUsage.RedMin, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('GreenMin', Qgis.RasterAttributeTableFieldUsage.GreenMin, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('BlueMin', Qgis.RasterAttributeTableFieldUsage.BlueMin, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('RedMax', Qgis.RasterAttributeTableFieldUsage.RedMax, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('GreenMax', Qgis.RasterAttributeTableFieldUsage.GreenMax, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('BlueMax', Qgis.RasterAttributeTableFieldUsage.BlueMax, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('ValueMin', Qgis.RasterAttributeTableFieldUsage.Min, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('ValueMax', Qgis.RasterAttributeTableFieldUsage.Max, QVariant.Int)) + self.assertTrue(rat.removeField("Red")[0]) + self.assertTrue(rat.removeField("Green")[0]) + self.assertTrue(rat.removeField("Blue")[0]) + self.assertTrue(rat.removeField("Value")[0]) + rat.appendField( + QgsRasterAttributeTable.Field( + "RedMin", Qgis.RasterAttributeTableFieldUsage.RedMin, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "GreenMin", Qgis.RasterAttributeTableFieldUsage.GreenMin, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "BlueMin", Qgis.RasterAttributeTableFieldUsage.BlueMin, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "RedMax", Qgis.RasterAttributeTableFieldUsage.RedMax, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "GreenMax", Qgis.RasterAttributeTableFieldUsage.GreenMax, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "BlueMax", Qgis.RasterAttributeTableFieldUsage.BlueMax, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "ValueMin", Qgis.RasterAttributeTableFieldUsage.Min, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "ValueMax", Qgis.RasterAttributeTableFieldUsage.Max, QVariant.Int + ) + ) valid, error = rat.isValid() self.assertTrue(valid) self.assertFalse(rat.hasColor()) self.assertTrue(rat.hasRamp()) - self.assertTrue(rat.setRamp(1, QColor('#010203'), QColor('#020304'))) - self.assertEqual(rat.ramp(1).color1().name(), '#010203') - self.assertEqual(rat.ramp(1).color2().name(), '#020304') + self.assertTrue(rat.setRamp(1, QColor("#010203"), QColor("#020304"))) + self.assertEqual(rat.ramp(1).color1().name(), "#010203") + self.assertEqual(rat.ramp(1).color2().name(), "#020304") def testWriteReadDbfRat(self): # Create RAT rat = QgsRasterAttributeTable() - rat.appendField(QgsRasterAttributeTable.Field('Value', Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Count', Qgis.RasterAttributeTableFieldUsage.PixelCount, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Class', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Class2', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Class3', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Red', Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Green', Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Blue', Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Double', Qgis.RasterAttributeTableFieldUsage.Generic, QVariant.Double)) + rat.appendField( + QgsRasterAttributeTable.Field( + "Value", Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Count", Qgis.RasterAttributeTableFieldUsage.PixelCount, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class2", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class3", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Red", Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Green", Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Blue", Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Double", Qgis.RasterAttributeTableFieldUsage.Generic, QVariant.Double + ) + ) data_rows = [ - [0, 1, 'zero', 'zero2', 'zero3', 0, 10, 100, 1.234], - [2, 1, 'one', 'one2', 'one3', 100, 20, 0, 0.998], - [4, 2, 'two', 'two2', 'two3', 200, 30, 50, 123456], + [0, 1, "zero", "zero2", "zero3", 0, 10, 100, 1.234], + [2, 1, "one", "one2", "one3", 100, 20, 0, 0.998], + [4, 2, "two", "two2", "two3", 200, 30, 50, 123456], ] usages = [f.usage for f in rat.fields()] @@ -444,7 +745,7 @@ def testWriteReadDbfRat(self): for row in data_rows: rat.appendRow(row) - rat_path = os.path.join(self.temp_path, 'test_rat1.vat.dbf') + rat_path = os.path.join(self.temp_path, "test_rat1.vat.dbf") self.assertTrue(rat.isDirty()) self.assertTrue(rat.writeToFile(rat_path)[0]) self.assertTrue(os.path.exists(rat_path)) @@ -454,30 +755,88 @@ def testWriteReadDbfRat(self): self.assertTrue(rat.readFromFile(rat_path)[0]) self.assertTrue(rat.isValid()[0]) self.assertTrue(rat.hasColor()) - self.assertEqual([f.name for f in rat.fields()], ['Value', 'Count', 'Class', 'Class2', 'Class3', 'Red', 'Green', 'Blue', 'Double']) + self.assertEqual( + [f.name for f in rat.fields()], + [ + "Value", + "Count", + "Class", + "Class2", + "Class3", + "Red", + "Green", + "Blue", + "Double", + ], + ) self.assertEqual([f.usage for f in rat.fields()], usages) - self.assertEqual([f.type for f in rat.fields()], [QVariant.LongLong, QVariant.LongLong, QVariant.String, QVariant.String, QVariant.String, QVariant.Int, QVariant.Int, QVariant.Int, QVariant.Double]) - self.assertEqual(rat.data(), [ - [0, 1, 'zero', 'zero2', 'zero3', 0, 10, 100, 1.234], - [2, 1, 'one', 'one2', 'one3', 100, 20, 0, 0.998], - [4, 2, 'two', 'two2', 'two3', 200, 30, 50, 123456]]) + self.assertEqual( + [f.type for f in rat.fields()], + [ + QVariant.LongLong, + QVariant.LongLong, + QVariant.String, + QVariant.String, + QVariant.String, + QVariant.Int, + QVariant.Int, + QVariant.Int, + QVariant.Double, + ], + ) + self.assertEqual( + rat.data(), + [ + [0, 1, "zero", "zero2", "zero3", 0, 10, 100, 1.234], + [2, 1, "one", "one2", "one3", 100, 20, 0, 0.998], + [4, 2, "two", "two2", "two3", 200, 30, 50, 123456], + ], + ) def testClassification(self): # Create RAT for 16 bit raster rat = QgsRasterAttributeTable() - rat.appendField(QgsRasterAttributeTable.Field('Value', Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Class', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Class2', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Class3', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Red', Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Green', Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Blue', Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int)) + rat.appendField( + QgsRasterAttributeTable.Field( + "Value", Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class2", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class3", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Red", Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Green", Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Blue", Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int + ) + ) data_rows = [ - [0, 'zero', 'zero', 'even', 0, 0, 0], - [1, 'one', 'not0', 'odd', 1, 1, 1], - [2, 'two', 'not0', 'even', 2, 2, 2], + [0, "zero", "zero", "even", 0, 0, 0], + [1, "one", "not0", "odd", 1, 1, 1], + [2, "two", "not0", "even", 2, 2, 2], ] for row in data_rows: @@ -498,22 +857,34 @@ def testClassification(self): # Test classes rat = raster.attributeTable(1) classes = rat.minMaxClasses() - self.assertEqual({c.name: c.minMaxValues for c in classes}, {'zero': [0.0], 'one': [1.0], 'two': [2.0]}) - self.assertEqual(classes[0].color.name(), '#000000') - self.assertEqual(classes[1].color.name(), '#010101') - self.assertEqual(classes[2].color.name(), '#020202') + self.assertEqual( + {c.name: c.minMaxValues for c in classes}, + {"zero": [0.0], "one": [1.0], "two": [2.0]}, + ) + self.assertEqual(classes[0].color.name(), "#000000") + self.assertEqual(classes[1].color.name(), "#010101") + self.assertEqual(classes[2].color.name(), "#020202") classes = rat.minMaxClasses(1) - self.assertEqual({c.name: c.minMaxValues for c in classes}, {'zero': [0.0], 'one': [1.0], 'two': [2.0]}) + self.assertEqual( + {c.name: c.minMaxValues for c in classes}, + {"zero": [0.0], "one": [1.0], "two": [2.0]}, + ) classes = rat.minMaxClasses(2) - self.assertEqual({c.name: c.minMaxValues for c in classes}, {'zero': [0.0], 'not0': [1.0, 2.0]}) - self.assertEqual(classes[0].color.name(), '#000000') - self.assertEqual(classes[1].color.name(), '#010101') + self.assertEqual( + {c.name: c.minMaxValues for c in classes}, + {"zero": [0.0], "not0": [1.0, 2.0]}, + ) + self.assertEqual(classes[0].color.name(), "#000000") + self.assertEqual(classes[1].color.name(), "#010101") classes = rat.minMaxClasses(3) - self.assertEqual({c.name: c.minMaxValues for c in classes}, {'even': [0.0, 2.0], 'odd': [1.0]}) - self.assertEqual(classes[0].color.name(), '#000000') - self.assertEqual(classes[1].color.name(), '#010101') + self.assertEqual( + {c.name: c.minMaxValues for c in classes}, + {"even": [0.0, 2.0], "odd": [1.0]}, + ) + self.assertEqual(classes[0].color.name(), "#000000") + self.assertEqual(classes[1].color.name(), "#010101") # Class out of range errors classes = rat.minMaxClasses(100) @@ -524,26 +895,54 @@ def testClassification(self): self.assertEqual(len(classes), 0) # Test row function - self.assertEqual(rat.row(0), [0, 'zero', 'zero', 'even', 0, 0, 0]) - self.assertEqual(rat.row(2.0), [2, 'two', 'not0', 'even', 2, 2, 2]) + self.assertEqual(rat.row(0), [0, "zero", "zero", "even", 0, 0, 0]) + self.assertEqual(rat.row(2.0), [2, "two", "not0", "even", 2, 2, 2]) self.assertEqual(rat.row(100.0), []) def testPalettedRenderer(self): # Create RAT for 16 bit raster rat = QgsRasterAttributeTable() - rat.appendField(QgsRasterAttributeTable.Field('Value', Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Class', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Class2', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Class3', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Red', Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Green', Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Blue', Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int)) + rat.appendField( + QgsRasterAttributeTable.Field( + "Value", Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class2", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class3", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Red", Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Green", Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Blue", Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int + ) + ) data_rows = [ - [0, 'zero', 'zero', 'even', 0, 0, 0], - [1, 'one', 'not0', 'odd', 1, 1, 1], - [2, 'two', 'not0', 'even', 2, 2, 2], + [0, "zero", "zero", "even", 0, 0, 0], + [1, "one", "not0", "odd", 1, 1, 1], + [2, "two", "not0", "even", 2, 2, 2], ] for row in data_rows: @@ -565,56 +964,131 @@ def testPalettedRenderer(self): classes = [] for c in rat.minMaxClasses(): - mc = QgsPalettedRasterRenderer.MultiValueClass(c.minMaxValues, c.color, c.name) + mc = QgsPalettedRasterRenderer.MultiValueClass( + c.minMaxValues, c.color, c.name + ) classes.append(mc) renderer.setMultiValueClasses(classes) - self.assertEqual([f"{c.values}:{c.label}:{c.color.name()}" for c in renderer.multiValueClasses()], ['[0.0]:zero:#000000', '[1.0]:one:#010101', '[2.0]:two:#020202']) - self.assertEqual([f"{c.values}:{c.label}:{c.color.name()}" for c in QgsPalettedRasterRenderer.rasterAttributeTableToClassData(rat)], ['[0.0]:zero:#000000', '[1.0]:one:#010101', '[2.0]:two:#020202']) - self.assertEqual([f"{c.values}:{c.label}:{c.color.name()}" for c in raster.renderer().multiValueClasses()], ['[0.0]:zero:#000000', '[1.0]:one:#010101', '[2.0]:two:#020202']) + self.assertEqual( + [ + f"{c.values}:{c.label}:{c.color.name()}" + for c in renderer.multiValueClasses() + ], + ["[0.0]:zero:#000000", "[1.0]:one:#010101", "[2.0]:two:#020202"], + ) + self.assertEqual( + [ + f"{c.values}:{c.label}:{c.color.name()}" + for c in QgsPalettedRasterRenderer.rasterAttributeTableToClassData(rat) + ], + ["[0.0]:zero:#000000", "[1.0]:one:#010101", "[2.0]:two:#020202"], + ) + self.assertEqual( + [ + f"{c.values}:{c.label}:{c.color.name()}" + for c in raster.renderer().multiValueClasses() + ], + ["[0.0]:zero:#000000", "[1.0]:one:#010101", "[2.0]:two:#020202"], + ) def testCreateFromPalettedRaster(self): raster = QgsRasterLayer(self.uri_2x2_1_BAND_INT16) - classes = QgsPalettedRasterRenderer.classDataFromRaster(raster.dataProvider(), 1, None) + classes = QgsPalettedRasterRenderer.classDataFromRaster( + raster.dataProvider(), 1, None + ) for i in range(len(classes)): - classes[i].color = QColor(f'#0{i}0{i}0{i}') + classes[i].color = QColor(f"#0{i}0{i}0{i}") renderer = QgsPalettedRasterRenderer(raster.dataProvider(), 1, classes) raster.setRenderer(renderer) rat, band = QgsRasterAttributeTable.createFromRaster(raster) - self.assertEqual(rat.data(), [ - [0.0, '0', 0, 0, 0, 255], - [2.0, '2', 1, 1, 1, 255], - [4.0, '4', 2, 2, 2, 255] - ]) + self.assertEqual( + rat.data(), + [ + [0.0, "0", 0, 0, 0, 255], + [2.0, "2", 1, 1, 1, 255], + [4.0, "4", 2, 2, 2, 255], + ], + ) usages = rat.usages() - self.assertEqual(usages, [Qgis.RasterAttributeTableFieldUsage.MinMax, Qgis.RasterAttributeTableFieldUsage.Name, Qgis.RasterAttributeTableFieldUsage.Red, Qgis.RasterAttributeTableFieldUsage.Green, Qgis.RasterAttributeTableFieldUsage.Blue, Qgis.RasterAttributeTableFieldUsage.Alpha]) + self.assertEqual( + usages, + [ + Qgis.RasterAttributeTableFieldUsage.MinMax, + Qgis.RasterAttributeTableFieldUsage.Name, + Qgis.RasterAttributeTableFieldUsage.Red, + Qgis.RasterAttributeTableFieldUsage.Green, + Qgis.RasterAttributeTableFieldUsage.Blue, + Qgis.RasterAttributeTableFieldUsage.Alpha, + ], + ) def testCreateFromPseudoColorRaster(self): raster = QgsRasterLayer(self.uri_2x2_1_BAND_INT16) renderer = QgsSingleBandPseudoColorRenderer(raster.dataProvider(), 1) - ramp = QgsPresetSchemeColorRamp([QColor('#00000'), QColor('#0F0F0F'), QColor('#CFCFCF'), QColor('#FFFFFF')]) + ramp = QgsPresetSchemeColorRamp( + [QColor("#00000"), QColor("#0F0F0F"), QColor("#CFCFCF"), QColor("#FFFFFF")] + ) renderer.setClassificationMin(0) renderer.setClassificationMax(4) renderer.createShader(ramp) raster.setRenderer(renderer) - self.assertEqual([(i.color.name(), i.value) for i in raster.renderer().shader().rasterShaderFunction().colorRampItemList()], - [('#000000', 0.0), - ('#0f0f0f', 1.3333333333333333), - ('#cfcfcf', 2.6666666666666665), - ('#ffffff', 4.0)]) + self.assertEqual( + [ + (i.color.name(), i.value) + for i in raster.renderer() + .shader() + .rasterShaderFunction() + .colorRampItemList() + ], + [ + ("#000000", 0.0), + ("#0f0f0f", 1.3333333333333333), + ("#cfcfcf", 2.6666666666666665), + ("#ffffff", 4.0), + ], + ) rat, band = QgsRasterAttributeTable.createFromRaster(raster) - self.assertEqual(rat.data(), [ - [0.0, 1.3333333333333333, '0 - 1.33', 0, 0, 0, 255, 15, 15, 15, 255], - [1.3333333333333333, 2.6666666666666665, '1.33 - 2.67', 15, 15, 15, 255, 207, 207, 207, 255], - [2.6666666666666665, 4.0, '2.67 - 4', 207, 207, 207, 255, 255, 255, 255, 255]]) + self.assertEqual( + rat.data(), + [ + [0.0, 1.3333333333333333, "0 - 1.33", 0, 0, 0, 255, 15, 15, 15, 255], + [ + 1.3333333333333333, + 2.6666666666666665, + "1.33 - 2.67", + 15, + 15, + 15, + 255, + 207, + 207, + 207, + 255, + ], + [ + 2.6666666666666665, + 4.0, + "2.67 - 4", + 207, + 207, + 207, + 255, + 255, + 255, + 255, + 255, + ], + ], + ) def testUsageInformation(self): @@ -624,12 +1098,24 @@ def testUsageInformation(self): def testFloatRatNoColorTable(self): - path = os.path.join(unitTestDataPath('raster'), 'band1_float32_noct_epsg4326.tif') - shutil.copyfile(os.path.join(unitTestDataPath('raster'), 'band1_float32_noct_epsg4326.tif'), os.path.join(self.temp_path, 'band1_float32_noct_epsg4326.tif')) + path = os.path.join( + unitTestDataPath("raster"), "band1_float32_noct_epsg4326.tif" + ) + shutil.copyfile( + os.path.join(unitTestDataPath("raster"), "band1_float32_noct_epsg4326.tif"), + os.path.join(self.temp_path, "band1_float32_noct_epsg4326.tif"), + ) # Note this rename from "rat" to "aux.xml" because of an ancient git ignore. - shutil.copyfile(os.path.join(unitTestDataPath('raster'), 'band1_float32_noct_epsg4326.rat.xml'), os.path.join(self.temp_path, 'band1_float32_noct_epsg4326.tif.aux.xml')) - - raster = QgsRasterLayer(os.path.join(self.temp_path, 'band1_float32_noct_epsg4326.tif')) + shutil.copyfile( + os.path.join( + unitTestDataPath("raster"), "band1_float32_noct_epsg4326.rat.xml" + ), + os.path.join(self.temp_path, "band1_float32_noct_epsg4326.tif.aux.xml"), + ) + + raster = QgsRasterLayer( + os.path.join(self.temp_path, "band1_float32_noct_epsg4326.tif") + ) self.assertEqual(raster.attributeTableCount(), 1) rat = raster.attributeTable(1) @@ -642,17 +1128,41 @@ def testRamp(self): """Test ramps with various RAT types""" rat = QgsRasterAttributeTable() - rat.appendField(QgsRasterAttributeTable.Field('ValueMin', Qgis.RasterAttributeTableFieldUsage.Min, QVariant.Double)) - rat.appendField(QgsRasterAttributeTable.Field('ValueMax', Qgis.RasterAttributeTableFieldUsage.Max, QVariant.Double)) - rat.appendField(QgsRasterAttributeTable.Field('Class', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Red', Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Green', Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Blue', Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int)) + rat.appendField( + QgsRasterAttributeTable.Field( + "ValueMin", Qgis.RasterAttributeTableFieldUsage.Min, QVariant.Double + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "ValueMax", Qgis.RasterAttributeTableFieldUsage.Max, QVariant.Double + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Red", Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Green", Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Blue", Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int + ) + ) data_rows = [ - [2, 2.99999, 'two', 20, 20, 20], - [0, 0.999999, 'zero', 0, 0, 0], - [1, 1.999999, 'one', 10, 10, 10], + [2, 2.99999, "two", 20, 20, 20], + [0, 0.999999, "zero", 0, 0, 0], + [1, 1.999999, "one", 10, 10, 10], ] for row in data_rows: @@ -662,8 +1172,8 @@ def testRamp(self): ramp, labels = rat.colorRamp() - self.assertEqual(ramp.color1().name(), '#000000') - self.assertEqual(ramp.color2().name(), '#141414') + self.assertEqual(ramp.color1().name(), "#000000") + self.assertEqual(ramp.color2().name(), "#141414") self.assertEqual(len(ramp.stops()), 2) self.assertEqual([int(s.offset * 100) for s in ramp.stops()], [33, 66]) self.assertGreater(len(labels), 0) @@ -672,9 +1182,9 @@ def testRamp(self): rat.removeRow(0) data_rows = [ - [2.599999, 2.99999, 'two.5-three', 0, 255, 0], - [0, 1.99999, 'zero-two', 0, 0, 255], - [2, 2.5, 'two-two.5', 255, 0, 0], + [2.599999, 2.99999, "two.5-three", 0, 255, 0], + [0, 1.99999, "zero-two", 0, 0, 255], + [2, 2.5, "two-two.5", 255, 0, 0], ] for row in data_rows: @@ -683,15 +1193,15 @@ def testRamp(self): self.assertTrue(rat.isValid()[0]) ramp, labels = rat.colorRamp() - self.assertEqual(labels, ['0 - 1.99999', '2 - 2.5', '2.6 - 2.99999']) + self.assertEqual(labels, ["0 - 1.99999", "2 - 2.5", "2.6 - 2.99999"]) - self.assertEqual(ramp.color1().name(), '#0000ff') - self.assertEqual(ramp.color2().name(), '#00ff00') + self.assertEqual(ramp.color1().name(), "#0000ff") + self.assertEqual(ramp.color2().name(), "#00ff00") self.assertEqual(len(ramp.stops()), 2) self.assertEqual([int(s.offset * 100) for s in ramp.stops()], [66, 86]) ramp, labels = rat.colorRamp(2) - self.assertEqual(labels, ['zero-two', 'two-two.5', 'two.5-three']) + self.assertEqual(labels, ["zero-two", "two-two.5", "two.5-three"]) raster = QgsRasterLayer(self.uri_2x2_1_BAND_INT16) self.assertTrue(raster.isValid()) @@ -712,24 +1222,66 @@ def testRamp(self): self.assertEqual(func.minimumValue(), 0.0) self.assertEqual(func.maximumValue(), 2.99999) - self.assertEqual([(int(100 * st.offset), st.color.name()) for st in func.sourceColorRamp().stops()], [(66, '#0000ff'), (86, '#ff0000')]) + self.assertEqual( + [ + (int(100 * st.offset), st.color.name()) + for st in func.sourceColorRamp().stops() + ], + [(66, "#0000ff"), (86, "#ff0000")], + ) # Test range classes and colors rat = QgsRasterAttributeTable() - rat.appendField(QgsRasterAttributeTable.Field('ValueMin', Qgis.RasterAttributeTableFieldUsage.Min, QVariant.Double)) - rat.appendField(QgsRasterAttributeTable.Field('ValueMax', Qgis.RasterAttributeTableFieldUsage.Max, QVariant.Double)) - rat.appendField(QgsRasterAttributeTable.Field('Class', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('RedMin', Qgis.RasterAttributeTableFieldUsage.RedMin, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('GreenMin', Qgis.RasterAttributeTableFieldUsage.GreenMin, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('BlueMin', Qgis.RasterAttributeTableFieldUsage.BlueMin, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('RedMax', Qgis.RasterAttributeTableFieldUsage.RedMax, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('GreenMax', Qgis.RasterAttributeTableFieldUsage.GreenMax, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('BlueMax', Qgis.RasterAttributeTableFieldUsage.BlueMax, QVariant.Int)) + rat.appendField( + QgsRasterAttributeTable.Field( + "ValueMin", Qgis.RasterAttributeTableFieldUsage.Min, QVariant.Double + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "ValueMax", Qgis.RasterAttributeTableFieldUsage.Max, QVariant.Double + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "RedMin", Qgis.RasterAttributeTableFieldUsage.RedMin, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "GreenMin", Qgis.RasterAttributeTableFieldUsage.GreenMin, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "BlueMin", Qgis.RasterAttributeTableFieldUsage.BlueMin, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "RedMax", Qgis.RasterAttributeTableFieldUsage.RedMax, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "GreenMax", Qgis.RasterAttributeTableFieldUsage.GreenMax, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "BlueMax", Qgis.RasterAttributeTableFieldUsage.BlueMax, QVariant.Int + ) + ) data_rows = [ - [2.50000000001, 3, 'two.5-three', 0, 255, 0, 255, 0, 0], - [0, 2, 'zero-two', 255, 0, 0, 0, 255, 0], - [2.00000000001, 2.5, 'two-two.5', 0, 255, 0, 0, 0, 255], + [2.50000000001, 3, "two.5-three", 0, 255, 0, 255, 0, 0], + [0, 2, "zero-two", 255, 0, 0, 0, 255, 0], + [2.00000000001, 2.5, "two-two.5", 0, 255, 0, 0, 0, 255], ] for row in data_rows: @@ -749,25 +1301,58 @@ def testRamp(self): shader = renderer.shader() func = shader.rasterShaderFunction() - self.assertEqual([(int(100 * st.offset), st.color.name()) for st in func.sourceColorRamp().stops()], [(66, '#00ff00'), (83, '#0000ff')] - ) + self.assertEqual( + [ + (int(100 * st.offset), st.color.name()) + for st in func.sourceColorRamp().stops() + ], + [(66, "#00ff00"), (83, "#0000ff")], + ) # Test range classes and discrete colors on float raster = QgsRasterLayer(self.uri_2x2_1_BAND_FLOAT) rat = QgsRasterAttributeTable() - rat.appendField(QgsRasterAttributeTable.Field('ValueMin', Qgis.RasterAttributeTableFieldUsage.Min, QVariant.Double)) - rat.appendField(QgsRasterAttributeTable.Field('ValueMax', Qgis.RasterAttributeTableFieldUsage.Max, QVariant.Double)) - rat.appendField(QgsRasterAttributeTable.Field('Class', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Class2', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Red', Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Green', Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Blue', Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int)) + rat.appendField( + QgsRasterAttributeTable.Field( + "ValueMin", Qgis.RasterAttributeTableFieldUsage.Min, QVariant.Double + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "ValueMax", Qgis.RasterAttributeTableFieldUsage.Max, QVariant.Double + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class2", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Red", Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Green", Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Blue", Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int + ) + ) # Unordered! data_rows = [ - [1e+20, 5e+25, 'green class', 'class 2', 0, 255, 0], - [-1e+25, 3000000000000, 'red class', 'class 0', 255, 0, 0], - [3000000000000, 1e+20, 'blue class', 'class 1', 0, 0, 255], + [1e20, 5e25, "green class", "class 2", 0, 255, 0], + [-1e25, 3000000000000, "red class", "class 0", 255, 0, 0], + [3000000000000, 1e20, "blue class", "class 1", 0, 0, 255], ] for row in data_rows: @@ -777,11 +1362,14 @@ def testRamp(self): # Test ordered ordered = rat.orderedRows() - self.assertEqual(ordered, [ - [-1e+25, 3000000000000, 'red class', 'class 0', 255, 0, 0], - [3000000000000, 1e+20, 'blue class', 'class 1', 0, 0, 255], - [1e+20, 5e+25, 'green class', 'class 2', 0, 255, 0], - ]) + self.assertEqual( + ordered, + [ + [-1e25, 3000000000000, "red class", "class 0", 255, 0, 0], + [3000000000000, 1e20, "blue class", "class 1", 0, 0, 255], + [1e20, 5e25, "green class", "class 2", 0, 255, 0], + ], + ) raster.dataProvider().setAttributeTable(1, rat) ok, errors = raster.dataProvider().writeNativeAttributeTable() # spellok @@ -792,65 +1380,103 @@ def testRamp(self): shader = renderer.shader() func = shader.rasterShaderFunction() - self.assertEqual([i[0] for i in renderer.legendSymbologyItems()], ['red class', 'blue class', 'green class']) + self.assertEqual( + [i[0] for i in renderer.legendSymbologyItems()], + ["red class", "blue class", "green class"], + ) # Test color less athematic RAT rat = raster.attributeTable(1) - self.assertTrue(rat.removeField('Red')[0]) - self.assertTrue(rat.removeField('Green')[0]) - self.assertTrue(rat.removeField('Blue')[0]) + self.assertTrue(rat.removeField("Red")[0]) + self.assertTrue(rat.removeField("Green")[0]) + self.assertTrue(rat.removeField("Blue")[0]) self.assertFalse(rat.hasColor()) self.assertFalse(rat.hasRamp()) ramp = rat.colorRamp() ramp, labels = rat.colorRamp() self.assertEqual(len(ramp.stops()) + 1, len(labels)) - self.assertEqual(labels, ['-1e+25 - 3e+12', '3e+12 - 1e+20', '1e+20 - 5e+25']) + self.assertEqual(labels, ["-1e+25 - 3e+12", "3e+12 - 1e+20", "1e+20 - 5e+25"]) ramp, labels = rat.colorRamp(2) self.assertEqual(len(ramp.stops()) + 1, len(labels)) - self.assertEqual(labels, ['red class', 'blue class', 'green class']) + self.assertEqual(labels, ["red class", "blue class", "green class"]) def testFileStorage(self): """Test tht RAT information for external file-based RATs is stored in the project""" rat = QgsRasterAttributeTable() - rat.appendField(QgsRasterAttributeTable.Field('Value', Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Double)) - rat.appendField(QgsRasterAttributeTable.Field('Class', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Red', Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Green', Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Blue', Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Alpha', Qgis.RasterAttributeTableFieldUsage.Alpha, QVariant.Int)) - - data_rows = [[0.0, '0', 0, 0, 0, 255], - [2.0, '2', 1, 1, 1, 255], - [4.0, '4', 2, 2, 2, 255] - ] + rat.appendField( + QgsRasterAttributeTable.Field( + "Value", Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Double + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Red", Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Green", Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Blue", Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Alpha", Qgis.RasterAttributeTableFieldUsage.Alpha, QVariant.Int + ) + ) + + data_rows = [ + [0.0, "0", 0, 0, 0, 255], + [2.0, "2", 1, 1, 1, 255], + [4.0, "4", 2, 2, 2, 255], + ] for row in data_rows: rat.appendRow(row) self.assertTrue(rat.isValid()[0]) - self.assertTrue(rat.writeToFile(os.path.join(self.temp_path, 'my_rat'))) + self.assertTrue(rat.writeToFile(os.path.join(self.temp_path, "my_rat"))) raster = QgsRasterLayer(self.uri_2x2_2_BANDS_INT16) project = QgsProject.instance() project.addMapLayers([raster]) raster.dataProvider().setAttributeTable(2, rat) self.assertEqual(raster.attributeTableCount(), 1) - self.assertTrue(project.write(os.path.join(self.temp_path, 'my_project.qgs'))) + self.assertTrue(project.write(os.path.join(self.temp_path, "my_project.qgs"))) - project.read(os.path.join(self.temp_path, 'my_project.qgs')) + project.read(os.path.join(self.temp_path, "my_project.qgs")) raster = list(project.mapLayers().values())[0] self.assertEqual(raster.attributeTableCount(), 1) rat = raster.attributeTable(2) self.assertTrue(rat.isValid()[0]) - self.assertEqual(rat.filePath(), os.path.join(self.temp_path, 'my_rat.vat.dbf')) - self.assertEqual(rat.usages(), [Qgis.RasterAttributeTableFieldUsage.MinMax, Qgis.RasterAttributeTableFieldUsage.Name, Qgis.RasterAttributeTableFieldUsage.Red, Qgis.RasterAttributeTableFieldUsage.Green, Qgis.RasterAttributeTableFieldUsage.Blue, Qgis.RasterAttributeTableFieldUsage.Alpha]) + self.assertEqual(rat.filePath(), os.path.join(self.temp_path, "my_rat.vat.dbf")) + self.assertEqual( + rat.usages(), + [ + Qgis.RasterAttributeTableFieldUsage.MinMax, + Qgis.RasterAttributeTableFieldUsage.Name, + Qgis.RasterAttributeTableFieldUsage.Red, + Qgis.RasterAttributeTableFieldUsage.Green, + Qgis.RasterAttributeTableFieldUsage.Blue, + Qgis.RasterAttributeTableFieldUsage.Alpha, + ], + ) self.assertEqual(rat.data(), data_rows) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterattributetablemodel.py b/tests/src/python/test_qgsrasterattributetablemodel.py index befbfe40f2dd..750610939486 100644 --- a/tests/src/python/test_qgsrasterattributetablemodel.py +++ b/tests/src/python/test_qgsrasterattributetablemodel.py @@ -9,9 +9,9 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '04/09/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "04/09/2022" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.PyQt.QtCore import QModelIndex, QVariant, Qt from qgis.PyQt.QtGui import QColor @@ -35,20 +35,56 @@ def setUp(self): # Create RAT rat = QgsRasterAttributeTable() - rat.appendField(QgsRasterAttributeTable.Field('Value', Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Count', Qgis.RasterAttributeTableFieldUsage.PixelCount, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Class', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Class2', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Class3', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Red', Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Green', Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Blue', Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Double', Qgis.RasterAttributeTableFieldUsage.Generic, QVariant.Double)) + rat.appendField( + QgsRasterAttributeTable.Field( + "Value", Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Count", Qgis.RasterAttributeTableFieldUsage.PixelCount, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class2", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class3", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Red", Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Green", Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Blue", Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Double", Qgis.RasterAttributeTableFieldUsage.Generic, QVariant.Double + ) + ) data_rows = [ - [0, 1, 'zero', 'zero2', 'zero3', 0, 10, 100, 1.234], - [2, 1, 'one', 'one2', 'one3', 100, 20, 0, 0.998], - [4, 2, 'two', 'two2', 'two3', 200, 30, 50, 123456], + [0, 1, "zero", "zero2", "zero3", 0, 10, 100, 1.234], + [2, 1, "one", "one2", "one3", 100, 20, 0, 0.998], + [4, 2, "two", "two2", "two3", 200, 30, 50, 123456], ] for row in data_rows: @@ -59,14 +95,30 @@ def setUp(self): self.rat = rat self.model = QgsRasterAttributeTableModel(self.rat) - self.tester = QAbstractItemModelTester(self.model, QAbstractItemModelTester.FailureReportingMode.Fatal) + self.tester = QAbstractItemModelTester( + self.model, QAbstractItemModelTester.FailureReportingMode.Fatal + ) def testRatModel(self): # Test information methods self.assertTrue(self.model.hasColor()) self.assertFalse(self.model.hasRamp()) - self.assertEqual(self.model.headerNames(), ['Value', 'Count', 'Class', 'Class2', 'Class3', 'Red', 'Green', 'Blue', 'Double', 'Color']) + self.assertEqual( + self.model.headerNames(), + [ + "Value", + "Count", + "Class", + "Class2", + "Class3", + "Red", + "Green", + "Blue", + "Double", + "Color", + ], + ) self.assertFalse(self.model.editable()) self.model.setEditable(True) self.assertTrue(self.model.editable()) @@ -82,42 +134,88 @@ def testRatModel(self): self.assertFalse(self.model.hasColor()) self.assertTrue(self.model.isValid()[0]) self.assertTrue(self.model.isDirty()) - self.assertEqual(self.model.headerNames(), ['Value', 'Count', 'Class', 'Class2', 'Class3', 'Double']) + self.assertEqual( + self.model.headerNames(), + ["Value", "Count", "Class", "Class2", "Class3", "Double"], + ) self.assertFalse(self.model.removeField(-1)[0]) self.assertFalse(self.model.removeField(100)[0]) self.assertTrue(self.model.removeField(1)[0]) - self.assertEqual(self.model.headerNames(), ['Value', 'Class', 'Class2', 'Class3', 'Double']) + self.assertEqual( + self.model.headerNames(), ["Value", "Class", "Class2", "Class3", "Double"] + ) # Test invalid field operations # MinMax is unique - self.assertFalse(self.model.insertField(0, 'MyField', Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.String)[0]) - self.assertTrue(self.model.insertField(5, 'MyField', Qgis.RasterAttributeTableFieldUsage.Generic, QVariant.Double)[0]) - self.assertEqual(self.model.headerNames(), ['Value', 'Class', 'Class2', 'Class3', 'Double', 'MyField']) + self.assertFalse( + self.model.insertField( + 0, + "MyField", + Qgis.RasterAttributeTableFieldUsage.MinMax, + QVariant.String, + )[0] + ) + self.assertTrue( + self.model.insertField( + 5, + "MyField", + Qgis.RasterAttributeTableFieldUsage.Generic, + QVariant.Double, + )[0] + ) + self.assertEqual( + self.model.headerNames(), + ["Value", "Class", "Class2", "Class3", "Double", "MyField"], + ) self.assertTrue(self.model.isValid()[0]) # Remove MinMax self.assertTrue(self.model.removeField(0)) self.assertFalse(self.model.isValid()[0]) # Add it back - self.assertTrue(self.model.insertField(0, 'Value', Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Int)[0]) + self.assertTrue( + self.model.insertField( + 0, "Value", Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Int + )[0] + ) self.assertTrue(self.model.isValid()[0]) # Set Values for now zero value column for i in range(self.model.rowCount(QModelIndex())): - self.assertTrue(self.model.setData(self.model.index(i, 0), i, Qt.ItemDataRole.EditRole)) + self.assertTrue( + self.model.setData(self.model.index(i, 0), i, Qt.ItemDataRole.EditRole) + ) # Insert rows - self.assertFalse(self.model.insertRow(-1, [4, 'four', 'four2', 'four3', 123456, 1.2345])[0]) - self.assertFalse(self.model.insertRow(1000, [4, 'four', 'four2', 'four3', 123456, 1.2345])[0]) - self.assertFalse(self.model.insertRow(2, [4, 'four', 'four2', 'four3', 'xxx', 1.2345])[0]) - self.assertFalse(self.model.insertRow(2, [4, 'four', 'four2', 'four3', 999, 1.2345, 'xxx'])[0]) - self.assertFalse(self.model.insertRow(2, [4, 'four', 'four2', 'four3', 999])[0]) - self.assertTrue(self.model.insertRow(2, [4, 'four', 'four2', 'four3', 4444, 1.4444])[0]) + self.assertFalse( + self.model.insertRow(-1, [4, "four", "four2", "four3", 123456, 1.2345])[0] + ) + self.assertFalse( + self.model.insertRow(1000, [4, "four", "four2", "four3", 123456, 1.2345])[0] + ) + self.assertFalse( + self.model.insertRow(2, [4, "four", "four2", "four3", "xxx", 1.2345])[0] + ) + self.assertFalse( + self.model.insertRow(2, [4, "four", "four2", "four3", 999, 1.2345, "xxx"])[ + 0 + ] + ) + self.assertFalse(self.model.insertRow(2, [4, "four", "four2", "four3", 999])[0]) + self.assertTrue( + self.model.insertRow(2, [4, "four", "four2", "four3", 4444, 1.4444])[0] + ) self.assertEqual(self.model.rowCount(QModelIndex()), 4) - self.assertEqual(self.model.data(self.model.index(2, 0), Qt.ItemDataRole.DisplayRole), 4) - self.assertTrue(self.model.insertRow(4, [5, 'five', 'five', 'five', 5555, 1.5555])[0]) + self.assertEqual( + self.model.data(self.model.index(2, 0), Qt.ItemDataRole.DisplayRole), 4 + ) + self.assertTrue( + self.model.insertRow(4, [5, "five", "five", "five", 5555, 1.5555])[0] + ) self.assertEqual(self.model.rowCount(QModelIndex()), 5) - self.assertEqual(self.model.data(self.model.index(4, 0), Qt.ItemDataRole.DisplayRole), 5) + self.assertEqual( + self.model.data(self.model.index(4, 0), Qt.ItemDataRole.DisplayRole), 5 + ) # Remove rows self.assertFalse(self.model.removeRow(-1)[0]) @@ -129,25 +227,66 @@ def testRatModel(self): # Test data for color role # Add colors back - self.model.insertField(self.model.columnCount(QModelIndex()), 'Red', Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int) - self.model.insertField(self.model.columnCount(QModelIndex()), 'Green', Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int) - self.model.insertField(self.model.columnCount(QModelIndex()), 'Blue', Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int) + self.model.insertField( + self.model.columnCount(QModelIndex()), + "Red", + Qgis.RasterAttributeTableFieldUsage.Red, + QVariant.Int, + ) + self.model.insertField( + self.model.columnCount(QModelIndex()), + "Green", + Qgis.RasterAttributeTableFieldUsage.Green, + QVariant.Int, + ) + self.model.insertField( + self.model.columnCount(QModelIndex()), + "Blue", + Qgis.RasterAttributeTableFieldUsage.Blue, + QVariant.Int, + ) for i in range(self.model.rowCount(QModelIndex())): - self.assertTrue(self.model.setData(self.model.index(i, 6), i, Qt.ItemDataRole.EditRole)) - self.assertTrue(self.model.setData(self.model.index(i, 7), i, Qt.ItemDataRole.EditRole)) - self.assertTrue(self.model.setData(self.model.index(i, 8), i, Qt.ItemDataRole.EditRole)) + self.assertTrue( + self.model.setData(self.model.index(i, 6), i, Qt.ItemDataRole.EditRole) + ) + self.assertTrue( + self.model.setData(self.model.index(i, 7), i, Qt.ItemDataRole.EditRole) + ) + self.assertTrue( + self.model.setData(self.model.index(i, 8), i, Qt.ItemDataRole.EditRole) + ) # Check data from color - self.assertEqual(self.model.data(self.model.index(1, 9), Qt.ItemDataRole.DisplayRole), '#010101') - self.assertEqual(self.model.data(self.model.index(1, 9), Qt.ItemDataRole.BackgroundRole).name(), '#010101') + self.assertEqual( + self.model.data(self.model.index(1, 9), Qt.ItemDataRole.DisplayRole), + "#010101", + ) + self.assertEqual( + self.model.data( + self.model.index(1, 9), Qt.ItemDataRole.BackgroundRole + ).name(), + "#010101", + ) for i in range(self.model.rowCount(QModelIndex())): - self.assertTrue(self.model.setData(self.model.index(i, 9), QColor(f'#0{i}0{i}0{i}'), Qt.ItemDataRole.EditRole)) + self.assertTrue( + self.model.setData( + self.model.index(i, 9), + QColor(f"#0{i}0{i}0{i}"), + Qt.ItemDataRole.EditRole, + ) + ) - self.assertEqual(self.model.data(self.model.index(0, 9), Qt.ItemDataRole.DisplayRole), '#000000') - self.assertEqual(self.model.data(self.model.index(2, 9), Qt.ItemDataRole.DisplayRole), '#020202') + self.assertEqual( + self.model.data(self.model.index(0, 9), Qt.ItemDataRole.DisplayRole), + "#000000", + ) + self.assertEqual( + self.model.data(self.model.index(2, 9), Qt.ItemDataRole.DisplayRole), + "#020202", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterattributetablewidget.py b/tests/src/python/test_qgsrasterattributetablewidget.py index 1955d2948717..98ca954975dc 100644 --- a/tests/src/python/test_qgsrasterattributetablewidget.py +++ b/tests/src/python/test_qgsrasterattributetablewidget.py @@ -9,9 +9,9 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '20/08/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "20/08/2022" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.PyQt.QtCore import QTemporaryDir, QVariant from qgis.PyQt.QtWidgets import QDialog, QVBoxLayout @@ -46,20 +46,56 @@ def testWidget(self): # Create RAT rat = QgsRasterAttributeTable() - rat.appendField(QgsRasterAttributeTable.Field('Value', Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Count', Qgis.RasterAttributeTableFieldUsage.PixelCount, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Class', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Class2', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Class3', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Red', Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Green', Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Blue', Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Double', Qgis.RasterAttributeTableFieldUsage.Generic, QVariant.Double)) + rat.appendField( + QgsRasterAttributeTable.Field( + "Value", Qgis.RasterAttributeTableFieldUsage.MinMax, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Count", Qgis.RasterAttributeTableFieldUsage.PixelCount, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class2", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class3", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Red", Qgis.RasterAttributeTableFieldUsage.Red, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Green", Qgis.RasterAttributeTableFieldUsage.Green, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Blue", Qgis.RasterAttributeTableFieldUsage.Blue, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Double", Qgis.RasterAttributeTableFieldUsage.Generic, QVariant.Double + ) + ) data_rows = [ - [0, 1, 'zero', 'zero2', 'zero3', 0, 10, 100, 1.234], - [2, 1, 'one', 'one2', 'one3', 100, 20, 0, 0.998], - [4, 2, 'two', 'two2', 'two3', 200, 30, 50, 123456], + [0, 1, "zero", "zero2", "zero3", 0, 10, 100, 1.234], + [2, 1, "one", "one2", "one3", 100, 20, 0, 0.998], + [4, 2, "two", "two2", "two3", 200, 30, 50, 123456], ] for row in data_rows: @@ -78,22 +114,66 @@ def testWidget(self): self.assertTrue(ok) rat = QgsRasterAttributeTable() - rat.appendField(QgsRasterAttributeTable.Field('ValueMin', Qgis.RasterAttributeTableFieldUsage.Min, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('ValueMax', Qgis.RasterAttributeTableFieldUsage.Max, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Count', Qgis.RasterAttributeTableFieldUsage.PixelCount, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('Class', Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String)) - rat.appendField(QgsRasterAttributeTable.Field('Double', Qgis.RasterAttributeTableFieldUsage.Generic, QVariant.Double)) - rat.appendField(QgsRasterAttributeTable.Field('RedMin', Qgis.RasterAttributeTableFieldUsage.RedMin, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('GreenMin', Qgis.RasterAttributeTableFieldUsage.GreenMin, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('BlueMin', Qgis.RasterAttributeTableFieldUsage.BlueMin, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('RedMax', Qgis.RasterAttributeTableFieldUsage.RedMax, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('GreenMax', Qgis.RasterAttributeTableFieldUsage.GreenMax, QVariant.Int)) - rat.appendField(QgsRasterAttributeTable.Field('BlueMax', Qgis.RasterAttributeTableFieldUsage.BlueMax, QVariant.Int)) + rat.appendField( + QgsRasterAttributeTable.Field( + "ValueMin", Qgis.RasterAttributeTableFieldUsage.Min, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "ValueMax", Qgis.RasterAttributeTableFieldUsage.Max, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Count", Qgis.RasterAttributeTableFieldUsage.PixelCount, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Class", Qgis.RasterAttributeTableFieldUsage.Name, QVariant.String + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "Double", Qgis.RasterAttributeTableFieldUsage.Generic, QVariant.Double + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "RedMin", Qgis.RasterAttributeTableFieldUsage.RedMin, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "GreenMin", Qgis.RasterAttributeTableFieldUsage.GreenMin, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "BlueMin", Qgis.RasterAttributeTableFieldUsage.BlueMin, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "RedMax", Qgis.RasterAttributeTableFieldUsage.RedMax, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "GreenMax", Qgis.RasterAttributeTableFieldUsage.GreenMax, QVariant.Int + ) + ) + rat.appendField( + QgsRasterAttributeTable.Field( + "BlueMax", Qgis.RasterAttributeTableFieldUsage.BlueMax, QVariant.Int + ) + ) data_rows = [ - [0, 1, 1, 'zero', 1.234, 0, 0, 0, 0, 100, 100], - [1, 2, 1, 'one', 0.998, 0, 100, 100, 0, 150, 150], - [2, 4, 2, 'two', 123456, 0, 150, 150, 255, 0, 255], + [0, 1, 1, "zero", 1.234, 0, 0, 0, 0, 100, 100], + [1, 2, 1, "one", 0.998, 0, 100, 100, 0, 150, 150], + [2, 4, 2, "two", 123456, 0, 150, 150, 255, 0, 255], ] for row in data_rows: @@ -115,5 +195,5 @@ def testWidget(self): # dialog.exec_() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterbandcombobox.py b/tests/src/python/test_qgsrasterbandcombobox.py index 396b5bd9a739..eadb37ab3132 100644 --- a/tests/src/python/test_qgsrasterbandcombobox.py +++ b/tests/src/python/test_qgsrasterbandcombobox.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '09/05/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "09/05/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os @@ -45,7 +46,7 @@ def testNoLayer(self): self.assertEqual(combo.currentBand(), -1) def testInvalidLayer(self): - layer = QgsRasterLayer('blah', 'blah') + layer = QgsRasterLayer("blah", "blah") self.assertTrue(layer) self.assertFalse(layer.isValid()) combo = QgsRasterBandComboBox() @@ -64,8 +65,9 @@ def testInvalidLayer(self): self.assertEqual(signal_spy[-1][0], -1) # replace with valid layer - path = os.path.join(unitTestDataPath('raster'), - 'band3_float32_noct_epsg4326.tif') + path = os.path.join( + unitTestDataPath("raster"), "band3_float32_noct_epsg4326.tif" + ) info = QFileInfo(path) base_name = info.baseName() layer2 = QgsRasterLayer(path, base_name) @@ -108,30 +110,31 @@ def testInvalidLayer(self): self.assertEqual(len(signal_spy), 6) combo.setLayer(layer) - combo.setCurrentText('bad') + combo.setCurrentText("bad") self.assertEqual(combo.currentBand(), -1) self.assertEqual(len(signal_spy), 6) self.assertEqual(signal_spy[-1][0], -1) - combo.setCurrentText('5') + combo.setCurrentText("5") self.assertEqual(combo.currentBand(), 5) self.assertEqual(len(signal_spy), 7) self.assertEqual(signal_spy[-1][0], 5) - combo.setCurrentText('6.5') + combo.setCurrentText("6.5") self.assertEqual(combo.currentBand(), -1) self.assertEqual(len(signal_spy), 8) self.assertEqual(signal_spy[-1][0], -1) - combo.setCurrentText('5') + combo.setCurrentText("5") self.assertEqual(combo.currentBand(), 5) self.assertEqual(len(signal_spy), 9) self.assertEqual(signal_spy[-1][0], 5) - combo.setCurrentText('Not set') + combo.setCurrentText("Not set") self.assertEqual(combo.currentBand(), -1) self.assertEqual(len(signal_spy), 10) self.assertEqual(signal_spy[-1][0], -1) def testOneBandRaster(self): - path = os.path.join(unitTestDataPath('raster'), - 'band1_float32_noct_epsg4326.tif') + path = os.path.join( + unitTestDataPath("raster"), "band1_float32_noct_epsg4326.tif" + ) info = QFileInfo(path) base_name = info.baseName() layer = QgsRasterLayer(path, base_name) @@ -156,8 +159,9 @@ def testOneBandRaster(self): self.assertEqual(combo.count(), 1) def testMultiBandRaster(self): - path = os.path.join(unitTestDataPath('raster'), - 'band3_float32_noct_epsg4326.tif') + path = os.path.join( + unitTestDataPath("raster"), "band3_float32_noct_epsg4326.tif" + ) info = QFileInfo(path) base_name = info.baseName() layer = QgsRasterLayer(path, base_name) @@ -180,8 +184,9 @@ def testMultiBandRaster(self): self.assertEqual(combo.count(), 3) def testSignals(self): - path = os.path.join(unitTestDataPath('raster'), - 'band3_float32_noct_epsg4326.tif') + path = os.path.join( + unitTestDataPath("raster"), "band3_float32_noct_epsg4326.tif" + ) info = QFileInfo(path) base_name = info.baseName() layer = QgsRasterLayer(path, base_name) @@ -199,5 +204,5 @@ def testSignals(self): self.assertEqual(signal_spy[1][0], 3) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterblock.py b/tests/src/python/test_qgsrasterblock.py index d76e6f1dca85..f8b62ebe5b84 100644 --- a/tests/src/python/test_qgsrasterblock.py +++ b/tests/src/python/test_qgsrasterblock.py @@ -9,9 +9,9 @@ (at your option) any later version. """ -__author__ = 'Till Frankenbach' -__date__ = '24/07/2024' -__copyright__ = 'Copyright 2024, The QGIS Project' +__author__ = "Till Frankenbach" +__date__ = "24/07/2024" +__copyright__ = "Copyright 2024, The QGIS Project" import numpy @@ -56,5 +56,5 @@ def testQgsRasterBlock(self): self.assertTrue((block.as_numpy(use_masking=False) == expected_array).all()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrastercolorrampshader.py b/tests/src/python/test_qgsrastercolorrampshader.py index e80e77c489ca..121c3b967087 100644 --- a/tests/src/python/test_qgsrastercolorrampshader.py +++ b/tests/src/python/test_qgsrastercolorrampshader.py @@ -6,9 +6,9 @@ (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '17/08/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' +__author__ = "Nyall Dawson" +__date__ = "17/08/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtGui import QColor from qgis.core import QgsColorRampShader, QgsGradientColorRamp, QgsGradientStop @@ -23,7 +23,7 @@ def testNan(self): item1 = QgsColorRampShader.ColorRampItem(1, QColor(0, 0, 0)) item2 = QgsColorRampShader.ColorRampItem(2, QColor(255, 255, 255)) shader.setColorRampItemList([item1, item2]) - self.assertFalse(shader.shade(float('NaN'))[0]) + self.assertFalse(shader.shade(float("NaN"))[0]) self.assertFalse(shader.shade(float("inf"))[0]) def testCreateColorRamp(self): @@ -35,7 +35,12 @@ def testCreateColorRamp(self): shader.setColorRampItemList([item1, item2, item3]) shaderRamp = shader.createColorRamp() - gradientRamp = QgsGradientColorRamp(QColor(255, 0, 0), QColor(255, 255, 255), False, [QgsGradientStop(0.5, QColor(255, 255, 0))]) + gradientRamp = QgsGradientColorRamp( + QColor(255, 0, 0), + QColor(255, 255, 255), + False, + [QgsGradientStop(0.5, QColor(255, 255, 0))], + ) self.assertEqual(shaderRamp.color1(), gradientRamp.color1()) self.assertEqual(shaderRamp.color2(), gradientRamp.color2()) @@ -56,5 +61,5 @@ def testTwoClassesDiscrete(self): self.assertEqual(color2[1:4], (255, 255, 255)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrastercontourrenderer.py b/tests/src/python/test_qgsrastercontourrenderer.py index a5e7f0441fcf..9509a873ae2a 100644 --- a/tests/src/python/test_qgsrastercontourrenderer.py +++ b/tests/src/python/test_qgsrastercontourrenderer.py @@ -29,12 +29,11 @@ class TestQgsRasterContourRenderer(QgisTestCase): def test_renderer(self): - path = os.path.join(unitTestDataPath(), - 'landsat.tif') + path = os.path.join(unitTestDataPath(), "landsat.tif") info = QFileInfo(path) base_name = info.baseName() layer = QgsRasterLayer(path, base_name) - self.assertTrue(layer.isValid(), f'Raster not loaded: {path}') + self.assertTrue(layer.isValid(), f"Raster not loaded: {path}") renderer = QgsRasterContourRenderer(layer.dataProvider()) @@ -60,5 +59,5 @@ def test_contour_invalid_layer(self): self.assertEqual(renderer.inputBand(), 10) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterfilewriter.py b/tests/src/python/test_qgsrasterfilewriter.py index 4016d37178fc..e3e2f18b1293 100644 --- a/tests/src/python/test_qgsrasterfilewriter.py +++ b/tests/src/python/test_qgsrasterfilewriter.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Radim Blazek' -__date__ = '20/08/2012' -__copyright__ = 'Copyright 2012, The QGIS Project' + +__author__ = "Radim Blazek" +__date__ = "20/08/2012" +__copyright__ = "Copyright 2012, The QGIS Project" import glob import os @@ -34,7 +35,7 @@ def GDAL_COMPUTE_VERSION(maj, min, rev): - return ((maj) * 1000000 + (min) * 10000 + (rev) * 100) + return (maj) * 1000000 + (min) * 10000 + (rev) * 100 class TestQgsRasterFileWriter(QgisTestCase): @@ -74,11 +75,8 @@ def write(self, theRasterName): return False fileWriter.writeRaster( - pipe, - provider.xSize(), - provider.ySize(), - provider.extent(), - provider.crs()) + pipe, provider.xSize(), provider.ySize(), provider.extent(), provider.crs() + ) checker = QgsRasterChecker() ok = checker.runTest("gdal", tmpName, "gdal", path) @@ -98,71 +96,92 @@ def testWrite(self): allOk = False reportFilePath = f"{QDir.tempPath()}/qgistest.html" - reportFile = open(reportFilePath, 'a') + reportFile = open(reportFilePath, "a") reportFile.write(self.report) reportFile.close() assert allOk, "Raster file writer test failed" def testDriverForExtension(self): - self.assertEqual(QgsRasterFileWriter.driverForExtension('tif'), 'GTiff') - self.assertEqual(QgsRasterFileWriter.driverForExtension('TIF'), 'GTiff') - self.assertEqual(QgsRasterFileWriter.driverForExtension('tIf'), 'GTiff') - self.assertEqual(QgsRasterFileWriter.driverForExtension('.tif'), 'GTiff') - self.assertEqual(QgsRasterFileWriter.driverForExtension('img'), 'HFA') - self.assertEqual(QgsRasterFileWriter.driverForExtension('.vrt'), 'VRT') - self.assertEqual(QgsRasterFileWriter.driverForExtension('.jpg'), 'JPEG') - self.assertEqual(QgsRasterFileWriter.driverForExtension('asc'), 'AAIGrid') - self.assertEqual(QgsRasterFileWriter.driverForExtension('not a format'), '') - self.assertEqual(QgsRasterFileWriter.driverForExtension(''), '') + self.assertEqual(QgsRasterFileWriter.driverForExtension("tif"), "GTiff") + self.assertEqual(QgsRasterFileWriter.driverForExtension("TIF"), "GTiff") + self.assertEqual(QgsRasterFileWriter.driverForExtension("tIf"), "GTiff") + self.assertEqual(QgsRasterFileWriter.driverForExtension(".tif"), "GTiff") + self.assertEqual(QgsRasterFileWriter.driverForExtension("img"), "HFA") + self.assertEqual(QgsRasterFileWriter.driverForExtension(".vrt"), "VRT") + self.assertEqual(QgsRasterFileWriter.driverForExtension(".jpg"), "JPEG") + self.assertEqual(QgsRasterFileWriter.driverForExtension("asc"), "AAIGrid") + self.assertEqual(QgsRasterFileWriter.driverForExtension("not a format"), "") + self.assertEqual(QgsRasterFileWriter.driverForExtension(""), "") def testExtensionsForFormat(self): - self.assertCountEqual(QgsRasterFileWriter.extensionsForFormat('not format'), []) - self.assertCountEqual(QgsRasterFileWriter.extensionsForFormat('GTiff'), ['tiff', 'tif']) - if int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0): - self.assertCountEqual(QgsRasterFileWriter.extensionsForFormat('GPKG'), ['gpkg']) + self.assertCountEqual(QgsRasterFileWriter.extensionsForFormat("not format"), []) + self.assertCountEqual( + QgsRasterFileWriter.extensionsForFormat("GTiff"), ["tiff", "tif"] + ) + if int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0): + self.assertCountEqual( + QgsRasterFileWriter.extensionsForFormat("GPKG"), ["gpkg"] + ) else: self.assertCountEqual( - QgsRasterFileWriter.extensionsForFormat('GPKG'), ['gpkg', 'gpkg.zip']) - self.assertCountEqual(QgsRasterFileWriter.extensionsForFormat('JPEG'), ['jpg', 'jpeg']) - self.assertCountEqual(QgsRasterFileWriter.extensionsForFormat('AAIGrid'), ['asc']) + QgsRasterFileWriter.extensionsForFormat("GPKG"), ["gpkg", "gpkg.zip"] + ) + self.assertCountEqual( + QgsRasterFileWriter.extensionsForFormat("JPEG"), ["jpg", "jpeg"] + ) + self.assertCountEqual( + QgsRasterFileWriter.extensionsForFormat("AAIGrid"), ["asc"] + ) def testSupportedFiltersAndFormat(self): # test with formats in recommended order - formats = QgsRasterFileWriter.supportedFiltersAndFormats(QgsRasterFileWriter.RasterFormatOption.SortRecommended) - self.assertEqual(formats[0].filterString, 'GeoTIFF (*.tif *.TIF *.tiff *.TIFF)') - self.assertEqual(formats[0].driverName, 'GTiff') - self.assertIn('netCDF', [f.driverName for f in formats]) + formats = QgsRasterFileWriter.supportedFiltersAndFormats( + QgsRasterFileWriter.RasterFormatOption.SortRecommended + ) + self.assertEqual(formats[0].filterString, "GeoTIFF (*.tif *.TIF *.tiff *.TIFF)") + self.assertEqual(formats[0].driverName, "GTiff") + self.assertIn("netCDF", [f.driverName for f in formats]) # alphabetical sorting - formats2 = QgsRasterFileWriter.supportedFiltersAndFormats(QgsRasterFileWriter.RasterFormatOptions()) + formats2 = QgsRasterFileWriter.supportedFiltersAndFormats( + QgsRasterFileWriter.RasterFormatOptions() + ) self.assertLess(formats2[0].driverName, formats2[1].driverName) - self.assertCountEqual([f.driverName for f in formats], [f.driverName for f in formats2]) - self.assertNotEqual(formats2[0].driverName, 'GTiff') + self.assertCountEqual( + [f.driverName for f in formats], [f.driverName for f in formats2] + ) + self.assertNotEqual(formats2[0].driverName, "GTiff") def testSupportedFormatExtensions(self): formats = QgsRasterFileWriter.supportedFormatExtensions() - self.assertIn('tif', formats) - self.assertNotIn('exe', formats) - self.assertEqual(formats[0], 'tif') - self.assertIn('nc', formats) + self.assertIn("tif", formats) + self.assertNotIn("exe", formats) + self.assertEqual(formats[0], "tif") + self.assertIn("nc", formats) # alphabetical sorting - formats2 = QgsRasterFileWriter.supportedFormatExtensions(QgsRasterFileWriter.RasterFormatOptions()) + formats2 = QgsRasterFileWriter.supportedFormatExtensions( + QgsRasterFileWriter.RasterFormatOptions() + ) self.assertLess(formats2[1], formats2[2]) self.assertCountEqual(formats, formats2) - self.assertNotEqual(formats2[0], 'tif') + self.assertNotEqual(formats2[0], "tif") def testImportIntoGpkg(self): # init target file - test_gpkg = tempfile.mktemp(suffix='.gpkg', dir=self.testDataDir) - gdal.GetDriverByName('GPKG').Create(test_gpkg, 1, 1, 1) - source = QgsRasterLayer(os.path.join(self.testDataDir, 'raster', 'band3_byte_noct_epsg4326.tif'), 'my', 'gdal') + test_gpkg = tempfile.mktemp(suffix=".gpkg", dir=self.testDataDir) + gdal.GetDriverByName("GPKG").Create(test_gpkg, 1, 1, 1) + source = QgsRasterLayer( + os.path.join(self.testDataDir, "raster", "band3_byte_noct_epsg4326.tif"), + "my", + "gdal", + ) self.assertTrue(source.isValid()) provider = source.dataProvider() fw = QgsRasterFileWriter(test_gpkg) - fw.setOutputFormat('gpkg') - fw.setCreateOptions(['RASTER_TABLE=imported_table', 'APPEND_SUBDATASET=YES']) + fw.setOutputFormat("gpkg") + fw.setCreateOptions(["RASTER_TABLE=imported_table", "APPEND_SUBDATASET=YES"]) pipe = QgsRasterPipe() self.assertTrue(pipe.set(provider.clone())) @@ -171,40 +190,58 @@ def testImportIntoGpkg(self): projector.setCrs(provider.crs(), provider.crs()) self.assertTrue(pipe.set(projector)) - self.assertEqual(fw.writeRaster(pipe, - provider.xSize(), - provider.ySize(), - provider.extent(), - provider.crs()), 0) + self.assertEqual( + fw.writeRaster( + pipe, + provider.xSize(), + provider.ySize(), + provider.extent(), + provider.crs(), + ), + 0, + ) # Check that the test geopackage contains the raster layer and compare - rlayer = QgsRasterLayer(f'GPKG:{test_gpkg}:imported_table') + rlayer = QgsRasterLayer(f"GPKG:{test_gpkg}:imported_table") self.assertTrue(rlayer.isValid()) out_provider = rlayer.dataProvider() for i in range(3): - src_data = provider.block(i + 1, provider.extent(), source.width(), source.height()) - out_data = out_provider.block(i + 1, out_provider.extent(), rlayer.width(), rlayer.height()) + src_data = provider.block( + i + 1, provider.extent(), source.width(), source.height() + ) + out_data = out_provider.block( + i + 1, out_provider.extent(), rlayer.width(), rlayer.height() + ) self.assertEqual(src_data.data(), out_data.data()) # remove result file os.unlink(test_gpkg) def testExportToGpkgWithExtraExtent(self): - tmpName = tempfile.mktemp(suffix='.gpkg') - source = QgsRasterLayer(os.path.join(self.testDataDir, 'raster', 'band3_byte_noct_epsg4326.tif'), 'my', 'gdal') + tmpName = tempfile.mktemp(suffix=".gpkg") + source = QgsRasterLayer( + os.path.join(self.testDataDir, "raster", "band3_byte_noct_epsg4326.tif"), + "my", + "gdal", + ) self.assertTrue(source.isValid()) provider = source.dataProvider() fw = QgsRasterFileWriter(tmpName) - fw.setOutputFormat('gpkg') + fw.setOutputFormat("gpkg") pipe = QgsRasterPipe() self.assertTrue(pipe.set(provider.clone())) - self.assertEqual(fw.writeRaster(pipe, - provider.xSize() + 4, - provider.ySize() + 4, - QgsRectangle(-3 - 2, -4 - 2, 7 + 2, 6 + 2), - provider.crs()), 0) + self.assertEqual( + fw.writeRaster( + pipe, + provider.xSize() + 4, + provider.ySize() + 4, + QgsRectangle(-3 - 2, -4 - 2, 7 + 2, 6 + 2), + provider.crs(), + ), + 0, + ) del fw # Check that the test geopackage contains the raster layer and compare @@ -212,12 +249,16 @@ def testExportToGpkgWithExtraExtent(self): self.assertTrue(rlayer.isValid()) out_provider = rlayer.dataProvider() for i in range(3): - src_data = provider.block(i + 1, provider.extent(), source.width(), source.height()) - out_data = out_provider.block(i + 1, provider.extent(), source.width(), source.height()) + src_data = provider.block( + i + 1, provider.extent(), source.width(), source.height() + ) + out_data = out_provider.block( + i + 1, provider.extent(), source.width(), source.height() + ) self.assertEqual(src_data.data(), out_data.data()) out_data = out_provider.block(1, QgsRectangle(7, -4, 7 + 2, 6), 2, 8) # band3_byte_noct_epsg4326 nodata is 255 - self.assertEqual(out_data.data().data(), b'\xff' * 2 * 8) + self.assertEqual(out_data.data().data(), b"\xff" * 2 * 8) del out_provider del rlayer @@ -225,23 +266,32 @@ def testExportToGpkgWithExtraExtent(self): os.unlink(tmpName) def testExportToGpkgWithExtraExtentNoNoData(self): - tmpName = tempfile.mktemp(suffix='.gpkg') + tmpName = tempfile.mktemp(suffix=".gpkg") # Remove nodata - gdal.Translate('/vsimem/src.tif', os.path.join(self.testDataDir, 'raster', 'band3_byte_noct_epsg4326.tif'), options='-a_nodata none') - source = QgsRasterLayer('/vsimem/src.tif', 'my', 'gdal') + gdal.Translate( + "/vsimem/src.tif", + os.path.join(self.testDataDir, "raster", "band3_byte_noct_epsg4326.tif"), + options="-a_nodata none", + ) + source = QgsRasterLayer("/vsimem/src.tif", "my", "gdal") self.assertTrue(source.isValid()) provider = source.dataProvider() fw = QgsRasterFileWriter(tmpName) - fw.setOutputFormat('gpkg') + fw.setOutputFormat("gpkg") pipe = QgsRasterPipe() self.assertTrue(pipe.set(provider.clone())) - self.assertEqual(fw.writeRaster(pipe, - provider.xSize() + 4, - provider.ySize() + 4, - QgsRectangle(-3 - 2, -4 - 2, 7 + 2, 6 + 2), - provider.crs()), 0) + self.assertEqual( + fw.writeRaster( + pipe, + provider.xSize() + 4, + provider.ySize() + 4, + QgsRectangle(-3 - 2, -4 - 2, 7 + 2, 6 + 2), + provider.crs(), + ), + 0, + ) del fw # Check that the test geopackage contains the raster layer and compare @@ -249,22 +299,28 @@ def testExportToGpkgWithExtraExtentNoNoData(self): self.assertTrue(rlayer.isValid()) out_provider = rlayer.dataProvider() for i in range(3): - src_data = provider.block(i + 1, provider.extent(), source.width(), source.height()) - out_data = out_provider.block(i + 1, provider.extent(), source.width(), source.height()) + src_data = provider.block( + i + 1, provider.extent(), source.width(), source.height() + ) + out_data = out_provider.block( + i + 1, provider.extent(), source.width(), source.height() + ) self.assertEqual(src_data.data(), out_data.data()) out_data = out_provider.block(1, QgsRectangle(7, -4, 7 + 2, 6), 2, 8) # No nodata: defaults to zero - self.assertEqual(out_data.data().data(), b'\x00' * 2 * 8) + self.assertEqual(out_data.data().data(), b"\x00" * 2 * 8) del out_provider del rlayer # remove result file - gdal.Unlink('/vsimem/src.tif') + gdal.Unlink("/vsimem/src.tif") os.unlink(tmpName) def _testGeneratePyramids(self, pyramidFormat): - tmpName = tempfile.mktemp(suffix='.tif') - source = QgsRasterLayer(os.path.join(self.testDataDir, 'raster', 'byte.tif'), 'my', 'gdal') + tmpName = tempfile.mktemp(suffix=".tif") + source = QgsRasterLayer( + os.path.join(self.testDataDir, "raster", "byte.tif"), "my", "gdal" + ) self.assertTrue(source.isValid()) provider = source.dataProvider() fw = QgsRasterFileWriter(tmpName) @@ -280,11 +336,16 @@ def _testGeneratePyramids(self, pyramidFormat): projector.setCrs(provider.crs(), provider.crs()) self.assertTrue(pipe.set(projector)) - self.assertEqual(fw.writeRaster(pipe, - provider.xSize(), - provider.ySize(), - provider.extent(), - provider.crs()), 0) + self.assertEqual( + fw.writeRaster( + pipe, + provider.xSize(), + provider.ySize(), + provider.extent(), + provider.crs(), + ), + 0, + ) del fw ds = gdal.Open(tmpName) self.assertEqual(ds.RasterCount, 1) @@ -293,26 +354,30 @@ def _testGeneratePyramids(self, pyramidFormat): fl = ds.GetFileList() if pyramidFormat == QgsRaster.RasterPyramidsFormat.PyramidsGTiff: self.assertEqual(len(fl), 2, fl) - self.assertIn('.ovr', fl[1]) + self.assertIn(".ovr", fl[1]) elif pyramidFormat == QgsRaster.RasterPyramidsFormat.PyramidsInternal: self.assertEqual(len(fl), 1, fl) elif pyramidFormat == QgsRaster.RasterPyramidsFormat.PyramidsErdas: self.assertEqual(len(fl), 2, fl) - self.assertIn('.aux', fl[1]) + self.assertIn(".aux", fl[1]) os.unlink(tmpName) def testGeneratePyramidsExternal(self): return self._testGeneratePyramids(QgsRaster.RasterPyramidsFormat.PyramidsGTiff) def testGeneratePyramidsInternal(self): - return self._testGeneratePyramids(QgsRaster.RasterPyramidsFormat.PyramidsInternal) + return self._testGeneratePyramids( + QgsRaster.RasterPyramidsFormat.PyramidsInternal + ) def testGeneratePyramidsErdas(self): return self._testGeneratePyramids(QgsRaster.RasterPyramidsFormat.PyramidsErdas) def testWriteAsRawInvalidOutputFile(self): tmpName = "/this/is/invalid/file.tif" - source = QgsRasterLayer(os.path.join(self.testDataDir, 'raster', 'byte.tif'), 'my', 'gdal') + source = QgsRasterLayer( + os.path.join(self.testDataDir, "raster", "byte.tif"), "my", "gdal" + ) self.assertTrue(source.isValid()) provider = source.dataProvider() fw = QgsRasterFileWriter(tmpName) @@ -320,26 +385,40 @@ def testWriteAsRawInvalidOutputFile(self): pipe = QgsRasterPipe() self.assertTrue(pipe.set(provider.clone())) - self.assertEqual(fw.writeRaster(pipe, - provider.xSize(), - provider.ySize(), - provider.extent(), - provider.crs()), QgsRasterFileWriter.WriterError.CreateDatasourceError) + self.assertEqual( + fw.writeRaster( + pipe, + provider.xSize(), + provider.ySize(), + provider.extent(), + provider.crs(), + ), + QgsRasterFileWriter.WriterError.CreateDatasourceError, + ) del fw def testWriteAsImage(self): - tmpName = tempfile.mktemp(suffix='.tif') - source = QgsRasterLayer(os.path.join(self.testDataDir, 'raster', 'byte.tif'), 'my', 'gdal') - source.setContrastEnhancement(algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.NoEnhancement) + tmpName = tempfile.mktemp(suffix=".tif") + source = QgsRasterLayer( + os.path.join(self.testDataDir, "raster", "byte.tif"), "my", "gdal" + ) + source.setContrastEnhancement( + algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.NoEnhancement + ) self.assertTrue(source.isValid()) provider = source.dataProvider() fw = QgsRasterFileWriter(tmpName) - self.assertEqual(fw.writeRaster(source.pipe(), - provider.xSize(), - provider.ySize(), - provider.extent(), - provider.crs()), QgsRasterFileWriter.WriterError.NoError) + self.assertEqual( + fw.writeRaster( + source.pipe(), + provider.xSize(), + provider.ySize(), + provider.extent(), + provider.crs(), + ), + QgsRasterFileWriter.WriterError.NoError, + ) ds = gdal.Open(tmpName) self.assertEqual(ds.RasterCount, 4) self.assertEqual(ds.GetRasterBand(1).Checksum(), 4672) @@ -353,36 +432,52 @@ def testWriteAsImage(self): def testWriteAsImageInvalidOutputPath(self): tmpName = "/this/is/invalid/file.tif" - source = QgsRasterLayer(os.path.join(self.testDataDir, 'raster', 'byte.tif'), 'my', 'gdal') - source.setContrastEnhancement(algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.NoEnhancement) + source = QgsRasterLayer( + os.path.join(self.testDataDir, "raster", "byte.tif"), "my", "gdal" + ) + source.setContrastEnhancement( + algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.NoEnhancement + ) self.assertTrue(source.isValid()) provider = source.dataProvider() fw = QgsRasterFileWriter(tmpName) - self.assertEqual(fw.writeRaster(source.pipe(), - provider.xSize(), - provider.ySize(), - provider.extent(), - provider.crs()), QgsRasterFileWriter.WriterError.CreateDatasourceError) + self.assertEqual( + fw.writeRaster( + source.pipe(), + provider.xSize(), + provider.ySize(), + provider.extent(), + provider.crs(), + ), + QgsRasterFileWriter.WriterError.CreateDatasourceError, + ) del fw def testWriteAsRawGS7BG(self): - ''' Test that despite writing a Byte raster, we correctly handle GS7BG creating a Float64 ''' - tmpName = tempfile.mktemp(suffix='.grd') - source = QgsRasterLayer(os.path.join(self.testDataDir, 'raster', 'byte.tif'), 'my', 'gdal') + """Test that despite writing a Byte raster, we correctly handle GS7BG creating a Float64""" + tmpName = tempfile.mktemp(suffix=".grd") + source = QgsRasterLayer( + os.path.join(self.testDataDir, "raster", "byte.tif"), "my", "gdal" + ) self.assertTrue(source.isValid()) provider = source.dataProvider() fw = QgsRasterFileWriter(tmpName) - fw.setOutputFormat('GS7BG') + fw.setOutputFormat("GS7BG") pipe = QgsRasterPipe() self.assertTrue(pipe.set(provider.clone())) - self.assertEqual(fw.writeRaster(pipe, - provider.xSize(), - provider.ySize(), - provider.extent(), - provider.crs()), QgsRasterFileWriter.WriterError.NoError) + self.assertEqual( + fw.writeRaster( + pipe, + provider.xSize(), + provider.ySize(), + provider.extent(), + provider.crs(), + ), + QgsRasterFileWriter.WriterError.NoError, + ) del fw ds = gdal.Open(tmpName) @@ -392,5 +487,5 @@ def testWriteAsRawGS7BG(self): os.unlink(tmpName) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterfilewritertask.py b/tests/src/python/test_qgsrasterfilewritertask.py index c01a0e9bc5c5..803d3d76ddf4 100644 --- a/tests/src/python/test_qgsrasterfilewritertask.py +++ b/tests/src/python/test_qgsrasterfilewritertask.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '12/02/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "12/02/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os @@ -46,17 +47,25 @@ def onFail(self): def testSuccess(self): """test successfully writing a layer""" - path = os.path.join(unitTestDataPath(), 'raster', 'with_color_table.tif') + path = os.path.join(unitTestDataPath(), "raster", "with_color_table.tif") raster_layer = QgsRasterLayer(path, "test") self.assertTrue(raster_layer.isValid()) pipe = QgsRasterPipe() self.assertTrue(pipe.set(raster_layer.dataProvider().clone())) - tmp = create_temp_filename('success.tif') + tmp = create_temp_filename("success.tif") writer = QgsRasterFileWriter(tmp) - task = QgsRasterFileWriterTask(writer, pipe, 100, 100, raster_layer.extent(), raster_layer.crs(), QgsCoordinateTransformContext()) + task = QgsRasterFileWriterTask( + writer, + pipe, + 100, + 100, + raster_layer.extent(), + raster_layer.crs(), + QgsCoordinateTransformContext(), + ) task.writeComplete.connect(self.onSuccess) task.errorOccurred.connect(self.onFail) @@ -71,17 +80,25 @@ def testSuccess(self): def testLayerRemovalBeforeRun(self): """test behavior when layer is removed before task begins""" - path = os.path.join(unitTestDataPath(), 'raster', 'with_color_table.tif') + path = os.path.join(unitTestDataPath(), "raster", "with_color_table.tif") raster_layer = QgsRasterLayer(path, "test") self.assertTrue(raster_layer.isValid()) pipe = QgsRasterPipe() self.assertTrue(pipe.set(raster_layer.dataProvider().clone())) - tmp = create_temp_filename('remove_layer.tif') + tmp = create_temp_filename("remove_layer.tif") writer = QgsRasterFileWriter(tmp) - task = QgsRasterFileWriterTask(writer, pipe, 100, 100, raster_layer.extent(), raster_layer.crs(), QgsCoordinateTransformContext()) + task = QgsRasterFileWriterTask( + writer, + pipe, + 100, + 100, + raster_layer.extent(), + raster_layer.crs(), + QgsCoordinateTransformContext(), + ) task.writeComplete.connect(self.onSuccess) task.errorOccurred.connect(self.onFail) @@ -101,7 +118,7 @@ def testLayerRemovalBeforeRun(self): def testFail(self): """test error writing a layer""" - path = os.path.join(unitTestDataPath(), 'raster', 'with_color_table.tif') + path = os.path.join(unitTestDataPath(), "raster", "with_color_table.tif") raster_layer = QgsRasterLayer(path, "test") self.assertTrue(raster_layer.isValid()) @@ -111,7 +128,15 @@ def testFail(self): tmp = create_temp_filename("/this/is/invalid/file.tif") writer = QgsRasterFileWriter(tmp) - task = QgsRasterFileWriterTask(writer, pipe, 100, 100, raster_layer.extent(), raster_layer.crs(), QgsCoordinateTransformContext()) + task = QgsRasterFileWriterTask( + writer, + pipe, + 100, + 100, + raster_layer.extent(), + raster_layer.crs(), + QgsCoordinateTransformContext(), + ) task.writeComplete.connect(self.onSuccess) task.errorOccurred.connect(self.onFail) @@ -124,5 +149,5 @@ def testFail(self): self.assertTrue(self.fail) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterlayer.py b/tests/src/python/test_qgsrasterlayer.py index 51cdcaf7fbb9..78b7a5fa81a3 100644 --- a/tests/src/python/test_qgsrasterlayer.py +++ b/tests/src/python/test_qgsrasterlayer.py @@ -9,9 +9,9 @@ (at your option) any later version. """ -__author__ = 'Tim Sutton' -__date__ = '20/08/2012' -__copyright__ = 'Copyright 2012, The QGIS Project' +__author__ = "Tim Sutton" +__date__ = "20/08/2012" +__copyright__ = "Copyright 2012, The QGIS Project" import filecmp import os @@ -74,10 +74,12 @@ def setUp(self): self.iface.mapCanvas().viewport().resize(400, 400) # For some reason the resizeEvent is not delivered, fake it - self.iface.mapCanvas().resizeEvent(QResizeEvent(QSize(400, 400), self.iface.mapCanvas().size())) + self.iface.mapCanvas().resizeEvent( + QResizeEvent(QSize(400, 400), self.iface.mapCanvas().size()) + ) def testIdentify(self): - myPath = os.path.join(unitTestDataPath(), 'landsat.tif') + myPath = os.path.join(unitTestDataPath(), "landsat.tif") myFileInfo = QFileInfo(myPath) myBaseName = myFileInfo.baseName() myRasterLayer = QgsRasterLayer(myPath, myBaseName) @@ -86,7 +88,11 @@ def testIdentify(self): # print 'Extents: %s' % myRasterLayer.extent().toString() # myResult, myRasterValues = myRasterLayer.identify(myPoint) # assert myResult - myRasterValues = myRasterLayer.dataProvider().identify(myPoint, QgsRaster.IdentifyFormat.IdentifyFormatValue).results() + myRasterValues = ( + myRasterLayer.dataProvider() + .identify(myPoint, QgsRaster.IdentifyFormat.IdentifyFormatValue) + .results() + ) self.assertGreater(len(myRasterValues), 0) @@ -102,18 +108,18 @@ def testIdentify(self): for myValue in myValues: myIntValues.append(int(myValue)) myValues = str(myIntValues) - myExpectedValues = '[127, 141, 112, 72, 86, 126, 156, 211, 170]' - myMessage = f'Expected: {myValues}\nGot: {myExpectedValues}' + myExpectedValues = "[127, 141, 112, 72, 86, 126, 156, 211, 170]" + myMessage = f"Expected: {myValues}\nGot: {myExpectedValues}" self.assertEqual(myValues, myExpectedValues, myMessage) def testSampleIdentify(self): """Test that sample() and identify() return the same values, GH #44902""" tempdir = QTemporaryDir() - temppath = os.path.join(tempdir.path(), 'test_sample.tif') + temppath = os.path.join(tempdir.path(), "test_sample.tif") def _test(qgis_data_type): - rlayer = QgsRasterLayer(temppath, 'test_sample') + rlayer = QgsRasterLayer(temppath, "test_sample") self.assertTrue(rlayer.isValid()) self.assertEqual(rlayer.dataProvider().dataType(1), qgis_data_type) @@ -121,7 +127,11 @@ def _test(qgis_data_type): for y in [5022000.5, 5022001.5]: pos = QgsPointXY(x, y) value_sample = rlayer.dataProvider().sample(pos, 1)[0] - value_identify = rlayer.dataProvider().identify(pos, QgsRaster.IdentifyFormat.IdentifyFormatValue).results()[1] + value_identify = ( + rlayer.dataProvider() + .identify(pos, QgsRaster.IdentifyFormat.IdentifyFormatValue) + .results()[1] + ) # Check values for UInt32 if qgis_data_type == Qgis.DataType.UInt32: if y == 5022000.5: @@ -132,12 +142,11 @@ def _test(qgis_data_type): # print(value_sample, value_identify) # Test GDT_UInt32 - driver = gdal.GetDriverByName('GTiff') + driver = gdal.GetDriverByName("GTiff") outRaster = driver.Create(temppath, 3, 3, 1, gdal.GDT_UInt32) outRaster.SetGeoTransform((252290.0, 1.0, 0.0, 5022002.0, 0.0, -1.0)) outband = outRaster.GetRasterBand(1) - npdata = np.array([[4294967293, 1000, 5], - [4294967000, 50, 4]], dtype=np.uint32) + npdata = np.array([[4294967293, 1000, 5], [4294967000, 50, 4]], dtype=np.uint32) outband.WriteArray(npdata) outband.FlushCache() outRaster.FlushCache() @@ -146,12 +155,11 @@ def _test(qgis_data_type): _test(Qgis.DataType.UInt32) # Test GDT_Int32 - driver = gdal.GetDriverByName('GTiff') + driver = gdal.GetDriverByName("GTiff") outRaster = driver.Create(temppath, 3, 3, 1, gdal.GDT_Int32) outRaster.SetGeoTransform((252290.0, 1.0, 0.0, 5022002.0, 0.0, -1.0)) outband = outRaster.GetRasterBand(1) - npdata = np.array([[1294967293, 1000, 5], - [1294967000, 50, 4]], dtype=np.int32) + npdata = np.array([[1294967293, 1000, 5], [1294967000, 50, 4]], dtype=np.int32) outband.WriteArray(npdata) outband.FlushCache() outRaster.FlushCache() @@ -160,12 +168,13 @@ def _test(qgis_data_type): _test(Qgis.DataType.Int32) # Test GDT_Float32 - driver = gdal.GetDriverByName('GTiff') + driver = gdal.GetDriverByName("GTiff") outRaster = driver.Create(temppath, 3, 3, 1, gdal.GDT_Float32) outRaster.SetGeoTransform((252290.0, 1.0, 0.0, 5022002.0, 0.0, -1.0)) outband = outRaster.GetRasterBand(1) - npdata = np.array([[1294967293, 1000, 5], - [1294967000, 50, 4]], dtype=np.float32) + npdata = np.array( + [[1294967293, 1000, 5], [1294967000, 50, 4]], dtype=np.float32 + ) outband.WriteArray(npdata) outband.FlushCache() outRaster.FlushCache() @@ -174,12 +183,13 @@ def _test(qgis_data_type): _test(Qgis.DataType.Float32) # Test GDT_Float64 - driver = gdal.GetDriverByName('GTiff') + driver = gdal.GetDriverByName("GTiff") outRaster = driver.Create(temppath, 3, 3, 1, gdal.GDT_Float64) outRaster.SetGeoTransform((252290.0, 1.0, 0.0, 5022002.0, 0.0, -1.0)) outband = outRaster.GetRasterBand(1) - npdata = np.array([[1294967293, 1000, 5], - [1294967000, 50, 4]], dtype=np.float64) + npdata = np.array( + [[1294967293, 1000, 5], [1294967000, 50, 4]], dtype=np.float64 + ) outband.WriteArray(npdata) outband.FlushCache() outRaster.FlushCache() @@ -188,12 +198,11 @@ def _test(qgis_data_type): _test(Qgis.DataType.Float64) # Test GDT_Uint16 - driver = gdal.GetDriverByName('GTiff') + driver = gdal.GetDriverByName("GTiff") outRaster = driver.Create(temppath, 3, 3, 1, gdal.GDT_UInt16) outRaster.SetGeoTransform((252290.0, 1.0, 0.0, 5022002.0, 0.0, -1.0)) outband = outRaster.GetRasterBand(1) - npdata = np.array([[1294967293, 1000, 5], - [1294967000, 50, 4]], dtype=np.uint16) + npdata = np.array([[1294967293, 1000, 5], [1294967000, 50, 4]], dtype=np.uint16) outband.WriteArray(npdata) outband.FlushCache() outRaster.FlushCache() @@ -202,12 +211,11 @@ def _test(qgis_data_type): _test(Qgis.DataType.UInt16) # Test GDT_Int16 - driver = gdal.GetDriverByName('GTiff') + driver = gdal.GetDriverByName("GTiff") outRaster = driver.Create(temppath, 3, 3, 1, gdal.GDT_Int16) outRaster.SetGeoTransform((252290.0, 1.0, 0.0, 5022002.0, 0.0, -1.0)) outband = outRaster.GetRasterBand(1) - npdata = np.array([[31768, 1000, 5], - [12345, 50, 4]], dtype=np.int16) + npdata = np.array([[31768, 1000, 5], [12345, 50, 4]], dtype=np.int16) outband.WriteArray(npdata) outband.FlushCache() outRaster.FlushCache() @@ -216,12 +224,11 @@ def _test(qgis_data_type): _test(Qgis.DataType.Int16) # Test GDT_Int32 - driver = gdal.GetDriverByName('GTiff') + driver = gdal.GetDriverByName("GTiff") outRaster = driver.Create(temppath, 3, 3, 1, gdal.GDT_Int32) outRaster.SetGeoTransform((252290.0, 1.0, 0.0, 5022002.0, 0.0, -1.0)) outband = outRaster.GetRasterBand(1) - npdata = np.array([[31768, 1000, 5], - [12345, 50, 4]], dtype=np.int32) + npdata = np.array([[31768, 1000, 5], [12345, 50, 4]], dtype=np.int32) outband.WriteArray(npdata) outband.FlushCache() outRaster.FlushCache() @@ -230,12 +237,11 @@ def _test(qgis_data_type): _test(Qgis.DataType.Int32) # Test GDT_Byte - driver = gdal.GetDriverByName('GTiff') + driver = gdal.GetDriverByName("GTiff") outRaster = driver.Create(temppath, 3, 3, 1, gdal.GDT_Byte) outRaster.SetGeoTransform((252290.0, 1.0, 0.0, 5022002.0, 0.0, -1.0)) outband = outRaster.GetRasterBand(1) - npdata = np.array([[123, 255, 5], - [1, 50, 4]], dtype=np.byte) + npdata = np.array([[123, 255, 5], [1, 50, 4]], dtype=np.byte) outband.WriteArray(npdata) outband.FlushCache() outRaster.FlushCache() @@ -244,8 +250,9 @@ def _test(qgis_data_type): _test(Qgis.DataType.Byte) def testTransparency(self): - myPath = os.path.join(unitTestDataPath('raster'), - 'band1_float32_noct_epsg4326.tif') + myPath = os.path.join( + unitTestDataPath("raster"), "band1_float32_noct_epsg4326.tif" + ) myFileInfo = QFileInfo(myPath) myBaseName = myFileInfo.baseName() myRasterLayer = QgsRasterLayer(myPath, myBaseName) @@ -255,7 +262,8 @@ def testTransparency(self): myRasterLayer.setRenderer(renderer) myRasterLayer.setContrastEnhancement( QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum, - QgsRasterMinMaxOrigin.Limits.MinMax) + QgsRasterMinMaxOrigin.Limits.MinMax, + ) myContrastEnhancement = myRasterLayer.renderer().contrastEnhancement() # print ("myContrastEnhancement.minimumValue = %.17g" % @@ -268,37 +276,40 @@ def testTransparency(self): # 3.3999999521444001e+38) # It is not clear where the precision is lost. # We set the same values as C++. - myContrastEnhancement.setMinimumValue(-3.3319999287625854e+38) - myContrastEnhancement.setMaximumValue(3.3999999521443642e+38) + myContrastEnhancement.setMinimumValue(-3.3319999287625854e38) + myContrastEnhancement.setMaximumValue(3.3999999521443642e38) # myType = myRasterLayer.dataProvider().dataType(1); # myEnhancement = QgsContrastEnhancement(myType); myTransparentSingleValuePixelList = [] rasterTransparency = QgsRasterTransparency() - myTransparentPixel1 = \ - QgsRasterTransparency.TransparentSingleValuePixel() - myTransparentPixel1.min = -2.5840000772112106e+38 - myTransparentPixel1.max = -1.0879999684602689e+38 + myTransparentPixel1 = QgsRasterTransparency.TransparentSingleValuePixel() + myTransparentPixel1.min = -2.5840000772112106e38 + myTransparentPixel1.max = -1.0879999684602689e38 myTransparentPixel1.percentTransparent = 50 myTransparentSingleValuePixelList.append(myTransparentPixel1) - myTransparentPixel2 = \ - QgsRasterTransparency.TransparentSingleValuePixel() - myTransparentPixel2.min = 1.359999960575336e+37 - myTransparentPixel2.max = 9.520000231087593e+37 + myTransparentPixel2 = QgsRasterTransparency.TransparentSingleValuePixel() + myTransparentPixel2.min = 1.359999960575336e37 + myTransparentPixel2.max = 9.520000231087593e37 myTransparentPixel2.percentTransparent = 70 myTransparentSingleValuePixelList.append(myTransparentPixel2) rasterTransparency.setTransparentSingleValuePixelList( - myTransparentSingleValuePixelList) + myTransparentSingleValuePixelList + ) rasterRenderer = myRasterLayer.renderer() self.assertTrue(rasterRenderer) rasterRenderer.setRasterTransparency(rasterTransparency) - QgsProject.instance().addMapLayers([myRasterLayer, ]) + QgsProject.instance().addMapLayers( + [ + myRasterLayer, + ] + ) myMapSettings = QgsMapSettings() myMapSettings.setLayers([myRasterLayer]) @@ -306,15 +317,13 @@ def testTransparency(self): self.assertTrue( self.render_map_settings_check( - 'raster_transparency', - 'raster_transparency', - myMapSettings) + "raster_transparency", "raster_transparency", myMapSettings + ) ) def testIssue7023(self): """Check if converting a raster from 1.8 to 2 works.""" - myPath = os.path.join(unitTestDataPath('raster'), - 'raster-palette-crash2.tif') + myPath = os.path.join(unitTestDataPath("raster"), "raster-palette-crash2.tif") myFileInfo = QFileInfo(myPath) myBaseName = myFileInfo.baseName() myRasterLayer = QgsRasterLayer(myPath, myBaseName) @@ -324,8 +333,9 @@ def testIssue7023(self): def testShaderCrash(self): """Check if we assign a shader and then reassign it no crash occurs.""" - myPath = os.path.join(unitTestDataPath('raster'), - 'band1_float32_noct_epsg4326.tif') + myPath = os.path.join( + unitTestDataPath("raster"), "band1_float32_noct_epsg4326.tif" + ) myFileInfo = QFileInfo(myPath) myBaseName = myFileInfo.baseName() myRasterLayer = QgsRasterLayer(myPath, myBaseName) @@ -335,19 +345,17 @@ def testShaderCrash(self): myColorRampShader = QgsColorRampShader() myColorRampShader.setColorRampType(QgsColorRampShader.Type.Interpolated) myItems = [] - myItem = QgsColorRampShader.ColorRampItem( - 10, QColor('#ffff00'), 'foo') + myItem = QgsColorRampShader.ColorRampItem(10, QColor("#ffff00"), "foo") myItems.append(myItem) - myItem = QgsColorRampShader.ColorRampItem( - 100, QColor('#ff00ff'), 'bar') + myItem = QgsColorRampShader.ColorRampItem(100, QColor("#ff00ff"), "bar") myItems.append(myItem) - myItem = QgsColorRampShader.ColorRampItem( - 1000, QColor('#00ff00'), 'kazam') + myItem = QgsColorRampShader.ColorRampItem(1000, QColor("#00ff00"), "kazam") myItems.append(myItem) myColorRampShader.setColorRampItemList(myItems) myRasterShader.setRasterShaderFunction(myColorRampShader) myPseudoRenderer = QgsSingleBandPseudoColorRenderer( - myRasterLayer.dataProvider(), 1, myRasterShader) + myRasterLayer.dataProvider(), 1, myRasterShader + ) myRasterLayer.setRenderer(myPseudoRenderer) return @@ -357,28 +365,27 @@ def testShaderCrash(self): myColorRampShader = QgsColorRampShader() myColorRampShader.setColorRampType(QgsColorRampShader.Type.Interpolated) myItems = [] - myItem = QgsColorRampShader.ColorRampItem(10, - QColor('#ffff00'), 'foo') + myItem = QgsColorRampShader.ColorRampItem(10, QColor("#ffff00"), "foo") myItems.append(myItem) - myItem = QgsColorRampShader.ColorRampItem(100, - QColor('#ff00ff'), 'bar') + myItem = QgsColorRampShader.ColorRampItem(100, QColor("#ff00ff"), "bar") myItems.append(myItem) - myItem = QgsColorRampShader.ColorRampItem(1000, - QColor('#00ff00'), 'kazam') + myItem = QgsColorRampShader.ColorRampItem(1000, QColor("#00ff00"), "kazam") myItems.append(myItem) myColorRampShader.setColorRampItemList(myItems) myRasterShader.setRasterShaderFunction(myColorRampShader) # ####### crash on next line (fixed now)################## myPseudoRenderer = QgsSingleBandPseudoColorRenderer( - myRasterLayer.dataProvider(), 1, myRasterShader) + myRasterLayer.dataProvider(), 1, myRasterShader + ) myRasterLayer.setRenderer(myPseudoRenderer) def onRendererChanged(self): self.rendererChanged = True def test_setRenderer(self): - myPath = os.path.join(unitTestDataPath('raster'), - 'band1_float32_noct_epsg4326.tif') + myPath = os.path.join( + unitTestDataPath("raster"), "band1_float32_noct_epsg4326.tif" + ) myFileInfo = QFileInfo(myPath) myBaseName = myFileInfo.baseName() layer = QgsRasterLayer(myPath, myBaseName) @@ -394,11 +401,11 @@ def test_setRenderer(self): self.assertEqual(layer.renderer(), r) def test_server_properties(self): - """ Test server properties. """ + """Test server properties.""" raster_path = os.path.join( - unitTestDataPath('raster'), - 'band1_float32_noct_epsg4326.tif') - layer = QgsRasterLayer(raster_path, 'test_raster') + unitTestDataPath("raster"), "band1_float32_noct_epsg4326.tif" + ) + layer = QgsRasterLayer(raster_path, "test_raster") self.assertIsInstance(layer.serverProperties(), QgsMapLayerServerProperties) def testQgsRasterMinMaxOrigin(self): @@ -420,7 +427,9 @@ def testQgsRasterMinMaxOrigin(self): self.assertNotEqual(mmo, mmo_default) mmo = QgsRasterMinMaxOrigin() - self.assertEqual(mmo.statAccuracy(), QgsRasterMinMaxOrigin.StatAccuracy.Estimated) + self.assertEqual( + mmo.statAccuracy(), QgsRasterMinMaxOrigin.StatAccuracy.Estimated + ) mmo.setStatAccuracy(QgsRasterMinMaxOrigin.StatAccuracy.Exact) self.assertEqual(mmo.statAccuracy(), QgsRasterMinMaxOrigin.StatAccuracy.Exact) self.assertNotEqual(mmo, mmo_default) @@ -458,13 +467,12 @@ def testQgsRasterMinMaxOrigin(self): self.assertEqual(mmo, mmoUnserialized) def testBrightnessContrastGamma(self): - """ test raster brightness/contrast/gamma filter""" - path = os.path.join(unitTestDataPath(), - 'landsat_4326.tif') + """test raster brightness/contrast/gamma filter""" + path = os.path.join(unitTestDataPath(), "landsat_4326.tif") info = QFileInfo(path) base_name = info.baseName() layer = QgsRasterLayer(path, base_name) - self.assertTrue(layer.isValid(), f'Raster not loaded: {path}') + self.assertTrue(layer.isValid(), f"Raster not loaded: {path}") layer.brightnessFilter().setContrast(100) @@ -474,9 +482,8 @@ def testBrightnessContrastGamma(self): self.assertTrue( self.render_map_settings_check( - 'raster_contrast100', - 'raster_contrast100', - ms) + "raster_contrast100", "raster_contrast100", ms + ) ) layer.brightnessFilter().setContrast(-30) @@ -486,10 +493,7 @@ def testBrightnessContrastGamma(self): ms.setExtent(layer.extent()) self.assertTrue( - self.render_map_settings_check( - 'raster_contrast30', - 'raster_contrast30', - ms) + self.render_map_settings_check("raster_contrast30", "raster_contrast30", ms) ) layer.brightnessFilter().setContrast(0) @@ -501,9 +505,8 @@ def testBrightnessContrastGamma(self): self.assertTrue( self.render_map_settings_check( - 'raster_brightness50', - 'raster_brightness50', - ms) + "raster_brightness50", "raster_brightness50", ms + ) ) layer.brightnessFilter().setBrightness(-20) @@ -514,17 +517,15 @@ def testBrightnessContrastGamma(self): self.assertTrue( self.render_map_settings_check( - 'raster_brightness20', - 'raster_brightness20', - ms) + "raster_brightness20", "raster_brightness20", ms + ) ) - path = os.path.join(unitTestDataPath(), - 'landsat-int16-b1.tif') + path = os.path.join(unitTestDataPath(), "landsat-int16-b1.tif") info = QFileInfo(path) base_name = info.baseName() layer = QgsRasterLayer(path, base_name) - self.assertTrue(layer.isValid(), f'Raster not loaded: {path}') + self.assertTrue(layer.isValid(), f"Raster not loaded: {path}") layer.brightnessFilter().setGamma(0.22) @@ -533,10 +534,7 @@ def testBrightnessContrastGamma(self): ms.setExtent(layer.extent()) self.assertTrue( - self.render_map_settings_check( - 'raster_gamma022', - 'raster_gamma022', - ms) + self.render_map_settings_check("raster_gamma022", "raster_gamma022", ms) ) layer.brightnessFilter().setGamma(2.22) @@ -546,20 +544,16 @@ def testBrightnessContrastGamma(self): ms.setExtent(layer.extent()) self.assertTrue( - self.render_map_settings_check( - 'raster_gamma222', - 'raster_gamma222', - ms) + self.render_map_settings_check("raster_gamma222", "raster_gamma222", ms) ) def testInvertColors(self): - """ test raster invert colors filter""" - path = os.path.join(unitTestDataPath(), - 'landsat_4326.tif') + """test raster invert colors filter""" + path = os.path.join(unitTestDataPath(), "landsat_4326.tif") info = QFileInfo(path) base_name = info.baseName() layer = QgsRasterLayer(path, base_name) - self.assertTrue(layer.isValid(), f'Raster not loaded: {path}') + self.assertTrue(layer.isValid(), f"Raster not loaded: {path}") layer.hueSaturationFilter().setInvertColors(True) @@ -569,19 +563,17 @@ def testInvertColors(self): self.assertTrue( self.render_map_settings_check( - 'raster_invertcolors', - 'raster_invertcolors', - ms) + "raster_invertcolors", "raster_invertcolors", ms + ) ) def testInvertSemiOpaqueColors(self): - """ test raster invert colors filter""" - path = os.path.join(unitTestDataPath(), - 'landsat_4326.tif') + """test raster invert colors filter""" + path = os.path.join(unitTestDataPath(), "landsat_4326.tif") info = QFileInfo(path) base_name = info.baseName() layer = QgsRasterLayer(path, base_name) - self.assertTrue(layer.isValid(), f'Raster not loaded: {path}') + self.assertTrue(layer.isValid(), f"Raster not loaded: {path}") layer.setOpacity(0.33) layer.hueSaturationFilter().setInvertColors(True) @@ -592,14 +584,14 @@ def testInvertSemiOpaqueColors(self): self.assertTrue( self.render_map_settings_check( - 'raster_invertsemiopaquecolors', - 'raster_invertsemiopaquecolors', - ms) + "raster_invertsemiopaquecolors", "raster_invertsemiopaquecolors", ms + ) ) def testClone(self): - myPath = os.path.join(unitTestDataPath('raster'), - 'band1_float32_noct_epsg4326.tif') + myPath = os.path.join( + unitTestDataPath("raster"), "band1_float32_noct_epsg4326.tif" + ) myFileInfo = QFileInfo(myPath) myBaseName = myFileInfo.baseName() layer = QgsRasterLayer(myPath, myBaseName) @@ -640,13 +632,14 @@ def test_clone_resampling(self): Test that cloning copies resampling settings """ layer = QgsRasterLayer( - self.get_test_data_path('raster/band1_float32_noct_epsg4326.tif').as_posix(), - 'test') + self.get_test_data_path( + "raster/band1_float32_noct_epsg4326.tif" + ).as_posix(), + "test", + ) self.assertTrue(layer.isValid()) - layer.setResamplingStage( - Qgis.RasterResamplingStage.Provider - ) + layer.setResamplingStage(Qgis.RasterResamplingStage.Provider) layer.dataProvider().setZoomedInResamplingMethod( QgsRasterDataProvider.ResamplingMethod.CubicSpline ) @@ -656,17 +649,14 @@ def test_clone_resampling(self): # clone layer clone = layer.clone() - self.assertEqual( - clone.resamplingStage(), - Qgis.RasterResamplingStage.Provider - ) + self.assertEqual(clone.resamplingStage(), Qgis.RasterResamplingStage.Provider) self.assertEqual( clone.dataProvider().zoomedInResamplingMethod(), - QgsRasterDataProvider.ResamplingMethod.CubicSpline + QgsRasterDataProvider.ResamplingMethod.CubicSpline, ) self.assertEqual( clone.dataProvider().zoomedOutResamplingMethod(), - QgsRasterDataProvider.ResamplingMethod.Average + QgsRasterDataProvider.ResamplingMethod.Average, ) def testSetDataSource(self): @@ -674,8 +664,9 @@ def testSetDataSource(self): temp_dir = QTemporaryDir() options = QgsDataProvider.ProviderOptions() - myPath = os.path.join(unitTestDataPath('raster'), - 'band1_float32_noct_epsg4326.tif') + myPath = os.path.join( + unitTestDataPath("raster"), "band1_float32_noct_epsg4326.tif" + ) myFileInfo = QFileInfo(myPath) myBaseName = myFileInfo.baseName() layer = QgsRasterLayer(myPath, myBaseName) @@ -683,27 +674,43 @@ def testSetDataSource(self): image = layer.previewAsImage(QSize(400, 400)) self.assertFalse(image.isNull()) - self.assertTrue(image.save(os.path.join(temp_dir.path(), 'expected.png'), "PNG")) + self.assertTrue( + image.save(os.path.join(temp_dir.path(), "expected.png"), "PNG") + ) - layer.setDataSource(myPath.replace('4326.tif', '4326-BAD_SOURCE.tif'), 'bad_layer', 'gdal', options) + layer.setDataSource( + myPath.replace("4326.tif", "4326-BAD_SOURCE.tif"), + "bad_layer", + "gdal", + options, + ) self.assertFalse(layer.isValid()) image = layer.previewAsImage(QSize(400, 400)) self.assertTrue(image.isNull()) - layer.setDataSource(myPath.replace('4326-BAD_SOURCE.tif', '4326.tif'), 'bad_layer', 'gdal', options) + layer.setDataSource( + myPath.replace("4326-BAD_SOURCE.tif", "4326.tif"), + "bad_layer", + "gdal", + options, + ) self.assertTrue(layer.isValid()) image = layer.previewAsImage(QSize(400, 400)) self.assertFalse(image.isNull()) - self.assertTrue(image.save(os.path.join(temp_dir.path(), 'actual.png'), "PNG")) + self.assertTrue(image.save(os.path.join(temp_dir.path(), "actual.png"), "PNG")) self.assertTrue( - filecmp.cmp(os.path.join(temp_dir.path(), 'actual.png'), os.path.join(temp_dir.path(), 'expected.png')), - False) + filecmp.cmp( + os.path.join(temp_dir.path(), "actual.png"), + os.path.join(temp_dir.path(), "expected.png"), + ), + False, + ) def testWriteSld(self): """Test SLD generation for the XMLS fields geneerated at RasterLayer level and not to the deeper renderer level.""" - myPath = os.path.join(unitTestDataPath(), 'landsat.tif') + myPath = os.path.join(unitTestDataPath(), "landsat.tif") myFileInfo = QFileInfo(myPath) myBaseName = myFileInfo.baseName() myRasterLayer = QgsRasterLayer(myPath, myBaseName) @@ -711,235 +718,235 @@ def testWriteSld(self): # do generic export with default layer values dom, root, errorMessage = self.layerToSld(myRasterLayer) - elements = root.elementsByTagName('sld:LayerFeatureConstraints') + elements = root.elementsByTagName("sld:LayerFeatureConstraints") self.assertEqual(len(elements), 1) element = elements.at(0).toElement() - elements = element.elementsByTagName('sld:FeatureTypeConstraint') + elements = element.elementsByTagName("sld:FeatureTypeConstraint") self.assertEqual(len(elements), 1) element = elements.at(0).toElement() - elements = root.elementsByTagName('sld:UserStyle') + elements = root.elementsByTagName("sld:UserStyle") self.assertEqual(len(elements), 1) element = elements.at(0).toElement() - name = element.firstChildElement('sld:Name') + name = element.firstChildElement("sld:Name") self.assertFalse(name.isNull()) - self.assertEqual(name.text(), 'landsat') + self.assertEqual(name.text(), "landsat") - abstract = element.firstChildElement('sld:Abstract') + abstract = element.firstChildElement("sld:Abstract") self.assertTrue(abstract.isNull()) - title = element.firstChildElement('sld:Title') + title = element.firstChildElement("sld:Title") self.assertTrue(title.isNull()) - featureTypeStyle = element.firstChildElement('sld:FeatureTypeStyle') + featureTypeStyle = element.firstChildElement("sld:FeatureTypeStyle") self.assertFalse(featureTypeStyle.isNull()) - rule = featureTypeStyle.firstChildElement('sld:Rule') + rule = featureTypeStyle.firstChildElement("sld:Rule") self.assertFalse(rule.isNull()) - temp = rule.firstChildElement('sld:MinScaleDenominator') + temp = rule.firstChildElement("sld:MinScaleDenominator") self.assertTrue(temp.isNull()) - temp = rule.firstChildElement('sld:MaxScaleDenominator') + temp = rule.firstChildElement("sld:MaxScaleDenominator") self.assertTrue(temp.isNull()) - rasterSymbolizer = rule.firstChildElement('sld:RasterSymbolizer') + rasterSymbolizer = rule.firstChildElement("sld:RasterSymbolizer") self.assertFalse(rule.isNull()) - vendorOptions = rasterSymbolizer.elementsByTagName('sld:VendorOption') + vendorOptions = rasterSymbolizer.elementsByTagName("sld:VendorOption") self.assertEqual(vendorOptions.size(), 0) # set no default values and check exported sld - myRasterLayer.setName('') - myRasterLayer.setAbstract('fake') - myRasterLayer.setTitle('fake') + myRasterLayer.setName("") + myRasterLayer.setAbstract("fake") + myRasterLayer.setTitle("fake") dom, root, errorMessage = self.layerToSld(myRasterLayer) - elements = root.elementsByTagName('sld:LayerFeatureConstraints') + elements = root.elementsByTagName("sld:LayerFeatureConstraints") self.assertEqual(len(elements), 1) element = elements.at(0).toElement() - elements = element.elementsByTagName('sld:FeatureTypeConstraint') + elements = element.elementsByTagName("sld:FeatureTypeConstraint") self.assertEqual(len(elements), 1) element = elements.at(0).toElement() - elements = root.elementsByTagName('sld:UserStyle') + elements = root.elementsByTagName("sld:UserStyle") self.assertEqual(len(elements), 1) element = elements.at(0).toElement() # no generated if empty - name = element.firstChildElement('sld:Name') + name = element.firstChildElement("sld:Name") self.assertTrue(name.isNull()) # generated if not empty - abstract = element.firstChildElement('sld:Abstract') + abstract = element.firstChildElement("sld:Abstract") self.assertFalse(abstract.isNull()) - self.assertEqual(abstract.text(), 'fake') + self.assertEqual(abstract.text(), "fake") - title = element.firstChildElement('sld:Title') + title = element.firstChildElement("sld:Title") self.assertFalse(title.isNull()) - self.assertEqual(title.text(), 'fake') + self.assertEqual(title.text(), "fake") # if setScaleBasedVisibility is true print scales myRasterLayer.setScaleBasedVisibility(True) myRasterLayer.setMaximumScale(0.0001) myRasterLayer.setMinimumScale(0.01) dom, root, errorMessage = self.layerToSld(myRasterLayer) - elements = dom.elementsByTagName('sld:Rule') + elements = dom.elementsByTagName("sld:Rule") self.assertEqual(len(elements), 1) rule = elements.at(0).toElement() self.assertFalse(rule.isNull()) - temp = rule.firstChildElement('sld:MinScaleDenominator') + temp = rule.firstChildElement("sld:MinScaleDenominator") self.assertFalse(temp.isNull()) - self.assertEqual(temp.text(), '0.0001') + self.assertEqual(temp.text(), "0.0001") - temp = rule.firstChildElement('sld:MaxScaleDenominator') + temp = rule.firstChildElement("sld:MaxScaleDenominator") self.assertFalse(temp.isNull()) - self.assertEqual(temp.text(), '0.01') + self.assertEqual(temp.text(), "0.01") # check non default hueSaturationFilter values hue = myRasterLayer.hueSaturationFilter() hue.setInvertColors(True) dom, root, errorMessage = self.layerToSld(myRasterLayer) - elements = dom.elementsByTagName('sld:RasterSymbolizer') + elements = dom.elementsByTagName("sld:RasterSymbolizer") self.assertEqual(len(elements), 1) element = elements.at(0).toElement() self.assertFalse(element.isNull()) - self.assertVendorOption(element, 'invertColors', '1') + self.assertVendorOption(element, "invertColors", "1") # check non default hueSaturationFilter values hue = myRasterLayer.hueSaturationFilter() hue.setGrayscaleMode(QgsHueSaturationFilter.GrayscaleMode.GrayscaleLightness) dom, root, errorMessage = self.layerToSld(myRasterLayer) - elements = dom.elementsByTagName('sld:RasterSymbolizer') + elements = dom.elementsByTagName("sld:RasterSymbolizer") self.assertEqual(len(elements), 1) element = elements.at(0).toElement() self.assertFalse(element.isNull()) - self.assertVendorOption(element, 'grayScale', 'lightness') + self.assertVendorOption(element, "grayScale", "lightness") hue = myRasterLayer.hueSaturationFilter() hue.setGrayscaleMode(QgsHueSaturationFilter.GrayscaleMode.GrayscaleLuminosity) dom, root, errorMessage = self.layerToSld(myRasterLayer) - elements = dom.elementsByTagName('sld:RasterSymbolizer') + elements = dom.elementsByTagName("sld:RasterSymbolizer") self.assertEqual(len(elements), 1) element = elements.at(0).toElement() self.assertFalse(element.isNull()) - self.assertVendorOption(element, 'grayScale', 'luminosity') + self.assertVendorOption(element, "grayScale", "luminosity") hue = myRasterLayer.hueSaturationFilter() hue.setGrayscaleMode(QgsHueSaturationFilter.GrayscaleMode.GrayscaleAverage) dom, root, errorMessage = self.layerToSld(myRasterLayer) - elements = dom.elementsByTagName('sld:RasterSymbolizer') + elements = dom.elementsByTagName("sld:RasterSymbolizer") self.assertEqual(len(elements), 1) element = elements.at(0).toElement() self.assertFalse(element.isNull()) - self.assertVendorOption(element, 'grayScale', 'average') + self.assertVendorOption(element, "grayScale", "average") hue = myRasterLayer.hueSaturationFilter() hue.setGrayscaleMode(QgsHueSaturationFilter.GrayscaleMode.GrayscaleOff) dom, root, errorMessage = self.layerToSld(myRasterLayer) - elements = dom.elementsByTagName('sld:RasterSymbolizer') + elements = dom.elementsByTagName("sld:RasterSymbolizer") self.assertEqual(len(elements), 1) element = elements.at(0).toElement() self.assertFalse(element.isNull()) - self.assertVendorOption(element, 'grayScale', None) + self.assertVendorOption(element, "grayScale", None) # manage colorize vendorOption tags hue = myRasterLayer.hueSaturationFilter() hue.setColorizeOn(True) hue.setColorizeStrength(50) dom, root, errorMessage = self.layerToSld(myRasterLayer) - elements = dom.elementsByTagName('sld:RasterSymbolizer') + elements = dom.elementsByTagName("sld:RasterSymbolizer") self.assertEqual(len(elements), 1) element = elements.at(0).toElement() self.assertFalse(element.isNull()) - self.assertVendorOption(element, 'colorizeOn', '1') - self.assertVendorOption(element, 'colorizeRed', '255') - self.assertVendorOption(element, 'colorizeGreen', '128') - self.assertVendorOption(element, 'colorizeBlue', '128') - self.assertVendorOption(element, 'colorizeStrength', '0.5') - self.assertVendorOption(element, 'saturation', '0.498039') + self.assertVendorOption(element, "colorizeOn", "1") + self.assertVendorOption(element, "colorizeRed", "255") + self.assertVendorOption(element, "colorizeGreen", "128") + self.assertVendorOption(element, "colorizeBlue", "128") + self.assertVendorOption(element, "colorizeStrength", "0.5") + self.assertVendorOption(element, "saturation", "0.498039") # other hue non default values, no colorize and saturation = 0 hue = myRasterLayer.hueSaturationFilter() hue.setColorizeOn(False) hue.setSaturation(0) dom, root, errorMessage = self.layerToSld(myRasterLayer) - elements = dom.elementsByTagName('sld:RasterSymbolizer') + elements = dom.elementsByTagName("sld:RasterSymbolizer") self.assertEqual(len(elements), 1) element = elements.at(0).toElement() self.assertFalse(element.isNull()) - self.assertVendorOption(element, 'colorizeOn', None) - self.assertVendorOption(element, 'colorizeRed', None) - self.assertVendorOption(element, 'colorizeGreen', None) - self.assertVendorOption(element, 'colorizeBlue', None) - self.assertVendorOption(element, 'colorizeStrength', None) - self.assertVendorOption(element, 'saturation', None) - self.assertVendorOption(element, 'brightness', None) - self.assertVendorOption(element, 'contrast', None) + self.assertVendorOption(element, "colorizeOn", None) + self.assertVendorOption(element, "colorizeRed", None) + self.assertVendorOption(element, "colorizeGreen", None) + self.assertVendorOption(element, "colorizeBlue", None) + self.assertVendorOption(element, "colorizeStrength", None) + self.assertVendorOption(element, "saturation", None) + self.assertVendorOption(element, "brightness", None) + self.assertVendorOption(element, "contrast", None) # other hue non default values, no colorize and saturation = 100 hue = myRasterLayer.hueSaturationFilter() hue.setColorizeOn(False) hue.setSaturation(100) dom, root, errorMessage = self.layerToSld(myRasterLayer) - elements = dom.elementsByTagName('sld:RasterSymbolizer') + elements = dom.elementsByTagName("sld:RasterSymbolizer") self.assertEqual(len(elements), 1) element = elements.at(0).toElement() self.assertFalse(element.isNull()) - self.assertVendorOption(element, 'colorizeOn', None) - self.assertVendorOption(element, 'colorizeRed', None) - self.assertVendorOption(element, 'colorizeGreen', None) - self.assertVendorOption(element, 'colorizeBlue', None) - self.assertVendorOption(element, 'colorizeStrength', None) - self.assertVendorOption(element, 'saturation', '1') + self.assertVendorOption(element, "colorizeOn", None) + self.assertVendorOption(element, "colorizeRed", None) + self.assertVendorOption(element, "colorizeGreen", None) + self.assertVendorOption(element, "colorizeBlue", None) + self.assertVendorOption(element, "colorizeStrength", None) + self.assertVendorOption(element, "saturation", "1") hue.setSaturation(-100) dom, root, errorMessage = self.layerToSld(myRasterLayer) - self.assertVendorOption(root, 'saturation', '0') + self.assertVendorOption(root, "saturation", "0") # brightness filter default values dom, root, errorMessage = self.layerToSld(myRasterLayer) - elements = dom.elementsByTagName('sld:RasterSymbolizer') + elements = dom.elementsByTagName("sld:RasterSymbolizer") self.assertEqual(len(elements), 1) element = elements.at(0).toElement() self.assertFalse(element.isNull()) self.assertEqual(myRasterLayer.brightnessFilter().brightness(), 0) self.assertEqual(myRasterLayer.brightnessFilter().contrast(), 0) - self.assertVendorOption(element, 'brightness', None) - self.assertVendorOption(element, 'contrast', None) + self.assertVendorOption(element, "brightness", None) + self.assertVendorOption(element, "contrast", None) # brightness filter no default values bf = myRasterLayer.brightnessFilter() bf.setBrightness(-255) bf.setContrast(-100) dom, root, errorMessage = self.layerToSld(myRasterLayer) - elements = dom.elementsByTagName('sld:RasterSymbolizer') + elements = dom.elementsByTagName("sld:RasterSymbolizer") self.assertEqual(len(elements), 1) element = elements.at(0).toElement() self.assertFalse(element.isNull()) - self.assertVendorOption(element, 'brightness', '0') - self.assertVendorOption(element, 'contrast', '0') + self.assertVendorOption(element, "brightness", "0") + self.assertVendorOption(element, "contrast", "0") bf.setBrightness(255) bf.setContrast(100) dom, root, errorMessage = self.layerToSld(myRasterLayer) - elements = dom.elementsByTagName('sld:RasterSymbolizer') + elements = dom.elementsByTagName("sld:RasterSymbolizer") self.assertEqual(len(elements), 1) element = elements.at(0).toElement() self.assertFalse(element.isNull()) - self.assertVendorOption(element, 'brightness', '1') - self.assertVendorOption(element, 'contrast', '1') + self.assertVendorOption(element, "brightness", "1") + self.assertVendorOption(element, "contrast", "1") def assertVendorOption(self, root, name, expectedValue): """Set expectedValue=None to check that the vendor option is not present.""" - vendorOptions = root.elementsByTagName('sld:VendorOption') + vendorOptions = root.elementsByTagName("sld:VendorOption") found = False for vendorOptionIndex in range(vendorOptions.count()): vendorOption = vendorOptions.at(vendorOptionIndex) - self.assertEqual('sld:VendorOption', vendorOption.nodeName()) - if (vendorOption.attributes().namedItem('name').nodeValue() == name): + self.assertEqual("sld:VendorOption", vendorOption.nodeName()) + if vendorOption.attributes().namedItem("name").nodeValue() == name: found = True self.assertEqual(vendorOption.firstChild().nodeValue(), expectedValue) if (expectedValue is None) and found: @@ -951,14 +958,14 @@ def layerToSld(self, layer, properties={}): dom = QDomDocument() root = dom.createElement("FakeRoot") dom.appendChild(root) - errorMessage = '' + errorMessage = "" layer.writeSld(root, dom, errorMessage, properties) return dom, root, errorMessage def testHistogram(self): """Test histogram bindings regression GH #29700""" - l = QgsRasterLayer(unitTestDataPath('raster/landcover.img'), 'landcover') + l = QgsRasterLayer(unitTestDataPath("raster/landcover.img"), "landcover") self.assertTrue(l.isValid()) p = l.dataProvider() # Note that this is not a correct use of the API: there is no @@ -974,14 +981,15 @@ def testInvalidLayerStyleRestoration(self): """ Test that styles are correctly restored from invalid layers """ - source_path = os.path.join(unitTestDataPath('raster'), - 'band1_float32_noct_epsg4326.tif') + source_path = os.path.join( + unitTestDataPath("raster"), "band1_float32_noct_epsg4326.tif" + ) # copy to temp path tmp_dir = QTemporaryDir() - tmp_path = os.path.join(tmp_dir.path(), 'test_raster.tif') + tmp_path = os.path.join(tmp_dir.path(), "test_raster.tif") copyfile(source_path, tmp_path) - rl = QgsRasterLayer(tmp_path, 'test_raster', 'gdal') + rl = QgsRasterLayer(tmp_path, "test_raster", "gdal") self.assertTrue(rl.isValid()) renderer = QgsSingleBandPseudoColorRenderer(rl.dataProvider(), 1) color_ramp = QgsGradientColorRamp(QColor(255, 255, 0), QColor(0, 0, 255)) @@ -995,7 +1003,7 @@ def testInvalidLayerStyleRestoration(self): p = QgsProject() p.addMapLayer(rl) - project_path = os.path.join(tmp_dir.path(), 'test_project.qgs') + project_path = os.path.join(tmp_dir.path(), "test_project.qgs") self.assertTrue(p.write(project_path)) # simple case, layer still exists in same path @@ -1005,15 +1013,35 @@ def testInvalidLayerStyleRestoration(self): self.assertEqual(len(p2.mapLayers()), 1) rl2 = list(p2.mapLayers().values())[0] self.assertTrue(rl2.isValid()) - self.assertEqual(rl2.name(), 'test_raster') + self.assertEqual(rl2.name(), "test_raster") self.assertIsInstance(rl2.renderer(), QgsSingleBandPseudoColorRenderer) self.assertEqual(rl2.renderer().classificationMin(), 101) self.assertEqual(rl2.renderer().classificationMax(), 131) - self.assertEqual(rl2.renderer().shader().rasterShaderFunction().sourceColorRamp().color1().name(), '#ffff00') - self.assertEqual(rl2.renderer().shader().rasterShaderFunction().sourceColorRamp().color2().name(), '#0000ff') - self.assertIsInstance(rl2.resampleFilter().zoomedInResampler(), QgsCubicRasterResampler) - self.assertIsInstance(rl2.resampleFilter().zoomedOutResampler(), QgsBilinearRasterResampler) + self.assertEqual( + rl2.renderer() + .shader() + .rasterShaderFunction() + .sourceColorRamp() + .color1() + .name(), + "#ffff00", + ) + self.assertEqual( + rl2.renderer() + .shader() + .rasterShaderFunction() + .sourceColorRamp() + .color2() + .name(), + "#0000ff", + ) + self.assertIsInstance( + rl2.resampleFilter().zoomedInResampler(), QgsCubicRasterResampler + ) + self.assertIsInstance( + rl2.resampleFilter().zoomedOutResampler(), QgsBilinearRasterResampler + ) self.assertEqual(rl2.renderer().opacity(), 0.6) # now, remove raster @@ -1025,80 +1053,174 @@ def testInvalidLayerStyleRestoration(self): self.assertEqual(len(p2.mapLayers()), 1) rl2 = list(p2.mapLayers().values())[0] self.assertFalse(rl2.isValid()) - self.assertEqual(rl2.name(), 'test_raster') + self.assertEqual(rl2.name(), "test_raster") # invalid layers should still have renderer available self.assertIsInstance(rl2.renderer(), QgsSingleBandPseudoColorRenderer) self.assertEqual(rl2.renderer().classificationMin(), 101) self.assertEqual(rl2.renderer().classificationMax(), 131) - self.assertEqual(rl2.renderer().shader().rasterShaderFunction().sourceColorRamp().color1().name(), '#ffff00') - self.assertEqual(rl2.renderer().shader().rasterShaderFunction().sourceColorRamp().color2().name(), '#0000ff') - self.assertIsInstance(rl2.resampleFilter().zoomedInResampler(), QgsCubicRasterResampler) - self.assertIsInstance(rl2.resampleFilter().zoomedOutResampler(), QgsBilinearRasterResampler) + self.assertEqual( + rl2.renderer() + .shader() + .rasterShaderFunction() + .sourceColorRamp() + .color1() + .name(), + "#ffff00", + ) + self.assertEqual( + rl2.renderer() + .shader() + .rasterShaderFunction() + .sourceColorRamp() + .color2() + .name(), + "#0000ff", + ) + self.assertIsInstance( + rl2.resampleFilter().zoomedInResampler(), QgsCubicRasterResampler + ) + self.assertIsInstance( + rl2.resampleFilter().zoomedOutResampler(), QgsBilinearRasterResampler + ) self.assertEqual(rl2.renderer().opacity(), 0.6) # make a little change rl2.renderer().setOpacity(0.8) # now, fix path - rl2.setDataSource(source_path, 'test_raster', 'gdal', QgsDataProvider.ProviderOptions()) + rl2.setDataSource( + source_path, "test_raster", "gdal", QgsDataProvider.ProviderOptions() + ) self.assertTrue(rl2.isValid()) - self.assertEqual(rl2.name(), 'test_raster') + self.assertEqual(rl2.name(), "test_raster") # at this stage, the original style should be retained... self.assertIsInstance(rl2.renderer(), QgsSingleBandPseudoColorRenderer) self.assertEqual(rl2.renderer().classificationMin(), 101) self.assertEqual(rl2.renderer().classificationMax(), 131) - self.assertEqual(rl2.renderer().shader().rasterShaderFunction().sourceColorRamp().color1().name(), '#ffff00') - self.assertEqual(rl2.renderer().shader().rasterShaderFunction().sourceColorRamp().color2().name(), '#0000ff') - self.assertIsInstance(rl2.resampleFilter().zoomedInResampler(), QgsCubicRasterResampler) - self.assertIsInstance(rl2.resampleFilter().zoomedOutResampler(), QgsBilinearRasterResampler) + self.assertEqual( + rl2.renderer() + .shader() + .rasterShaderFunction() + .sourceColorRamp() + .color1() + .name(), + "#ffff00", + ) + self.assertEqual( + rl2.renderer() + .shader() + .rasterShaderFunction() + .sourceColorRamp() + .color2() + .name(), + "#0000ff", + ) + self.assertIsInstance( + rl2.resampleFilter().zoomedInResampler(), QgsCubicRasterResampler + ) + self.assertIsInstance( + rl2.resampleFilter().zoomedOutResampler(), QgsBilinearRasterResampler + ) # the opacity change (and other renderer changes made while the layer was invalid) should be retained self.assertEqual(rl2.renderer().opacity(), 0.8) # break path - rl2.setDataSource(tmp_path, 'test_raster', 'gdal', QgsDataProvider.ProviderOptions()) + rl2.setDataSource( + tmp_path, "test_raster", "gdal", QgsDataProvider.ProviderOptions() + ) # and restore - rl2.setDataSource(source_path, 'test_raster', 'gdal', QgsDataProvider.ProviderOptions()) + rl2.setDataSource( + source_path, "test_raster", "gdal", QgsDataProvider.ProviderOptions() + ) self.assertTrue(rl2.isValid()) - self.assertEqual(rl2.name(), 'test_raster') + self.assertEqual(rl2.name(), "test_raster") # at this stage, the original style should be recreated... self.assertIsInstance(rl2.renderer(), QgsSingleBandPseudoColorRenderer) self.assertEqual(rl2.renderer().classificationMin(), 101) self.assertEqual(rl2.renderer().classificationMax(), 131) - self.assertEqual(rl2.renderer().shader().rasterShaderFunction().sourceColorRamp().color1().name(), '#ffff00') - self.assertEqual(rl2.renderer().shader().rasterShaderFunction().sourceColorRamp().color2().name(), '#0000ff') - self.assertIsInstance(rl2.resampleFilter().zoomedInResampler(), QgsCubicRasterResampler) - self.assertIsInstance(rl2.resampleFilter().zoomedOutResampler(), QgsBilinearRasterResampler) + self.assertEqual( + rl2.renderer() + .shader() + .rasterShaderFunction() + .sourceColorRamp() + .color1() + .name(), + "#ffff00", + ) + self.assertEqual( + rl2.renderer() + .shader() + .rasterShaderFunction() + .sourceColorRamp() + .color2() + .name(), + "#0000ff", + ) + self.assertIsInstance( + rl2.resampleFilter().zoomedInResampler(), QgsCubicRasterResampler + ) + self.assertIsInstance( + rl2.resampleFilter().zoomedOutResampler(), QgsBilinearRasterResampler + ) self.assertEqual(rl2.renderer().opacity(), 0.8) # break again - rl2.setDataSource(tmp_path, 'test_raster', 'gdal', QgsDataProvider.ProviderOptions()) + rl2.setDataSource( + tmp_path, "test_raster", "gdal", QgsDataProvider.ProviderOptions() + ) # export via qlr, with broken path (but hopefully correct style) - doc = QgsLayerDefinition.exportLayerDefinitionLayers([rl2], QgsReadWriteContext()) - layers = QgsLayerDefinition.loadLayerDefinitionLayers(doc, QgsReadWriteContext()) + doc = QgsLayerDefinition.exportLayerDefinitionLayers( + [rl2], QgsReadWriteContext() + ) + layers = QgsLayerDefinition.loadLayerDefinitionLayers( + doc, QgsReadWriteContext() + ) self.assertEqual(len(layers), 1) rl2 = layers[0] self.assertFalse(rl2.isValid()) # fix path - rl2.setDataSource(source_path, 'test_raster', 'gdal', QgsDataProvider.ProviderOptions()) + rl2.setDataSource( + source_path, "test_raster", "gdal", QgsDataProvider.ProviderOptions() + ) self.assertTrue(rl2.isValid()) - self.assertEqual(rl2.name(), 'test_raster') + self.assertEqual(rl2.name(), "test_raster") # at this stage, the original style should be recreated... self.assertIsInstance(rl2.renderer(), QgsSingleBandPseudoColorRenderer) self.assertEqual(rl2.renderer().classificationMin(), 101) self.assertEqual(rl2.renderer().classificationMax(), 131) - self.assertEqual(rl2.renderer().shader().rasterShaderFunction().sourceColorRamp().color1().name(), '#ffff00') - self.assertEqual(rl2.renderer().shader().rasterShaderFunction().sourceColorRamp().color2().name(), '#0000ff') - self.assertIsInstance(rl2.resampleFilter().zoomedInResampler(), QgsCubicRasterResampler) - self.assertIsInstance(rl2.resampleFilter().zoomedOutResampler(), QgsBilinearRasterResampler) + self.assertEqual( + rl2.renderer() + .shader() + .rasterShaderFunction() + .sourceColorRamp() + .color1() + .name(), + "#ffff00", + ) + self.assertEqual( + rl2.renderer() + .shader() + .rasterShaderFunction() + .sourceColorRamp() + .color2() + .name(), + "#0000ff", + ) + self.assertIsInstance( + rl2.resampleFilter().zoomedInResampler(), QgsCubicRasterResampler + ) + self.assertIsInstance( + rl2.resampleFilter().zoomedOutResampler(), QgsBilinearRasterResampler + ) self.assertEqual(rl2.renderer().opacity(), 0.8) # another test - rl = QgsRasterLayer(source_path, 'test_raster', 'gdal') + rl = QgsRasterLayer(source_path, "test_raster", "gdal") self.assertTrue(rl.isValid()) renderer = QgsSingleBandPseudoColorRenderer(rl.dataProvider(), 1) color_ramp = QgsGradientColorRamp(QColor(255, 255, 0), QColor(0, 0, 255)) @@ -1111,17 +1233,41 @@ def testInvalidLayerStyleRestoration(self): rl.resampleFilter().setZoomedOutResampler(QgsBilinearRasterResampler()) # break path - rl.setDataSource(tmp_path, 'test_raster', 'gdal', QgsDataProvider.ProviderOptions()) + rl.setDataSource( + tmp_path, "test_raster", "gdal", QgsDataProvider.ProviderOptions() + ) # fix path - rl.setDataSource(source_path, 'test_raster', 'gdal', QgsDataProvider.ProviderOptions()) + rl.setDataSource( + source_path, "test_raster", "gdal", QgsDataProvider.ProviderOptions() + ) self.assertIsInstance(rl.renderer(), QgsSingleBandPseudoColorRenderer) self.assertEqual(rl.renderer().classificationMin(), 101) self.assertEqual(rl.renderer().classificationMax(), 131) - self.assertEqual(rl.renderer().shader().rasterShaderFunction().sourceColorRamp().color1().name(), '#ffff00') - self.assertEqual(rl.renderer().shader().rasterShaderFunction().sourceColorRamp().color2().name(), '#0000ff') - self.assertIsInstance(rl.resampleFilter().zoomedInResampler(), QgsCubicRasterResampler) - self.assertIsInstance(rl.resampleFilter().zoomedOutResampler(), QgsBilinearRasterResampler) + self.assertEqual( + rl.renderer() + .shader() + .rasterShaderFunction() + .sourceColorRamp() + .color1() + .name(), + "#ffff00", + ) + self.assertEqual( + rl.renderer() + .shader() + .rasterShaderFunction() + .sourceColorRamp() + .color2() + .name(), + "#0000ff", + ) + self.assertIsInstance( + rl.resampleFilter().zoomedInResampler(), QgsCubicRasterResampler + ) + self.assertIsInstance( + rl.resampleFilter().zoomedOutResampler(), QgsBilinearRasterResampler + ) self.assertEqual(rl.renderer().opacity(), 0.6) @@ -1131,106 +1277,181 @@ def setUp(self): """Prepare tc""" super().setUp() self.ctx = QgsCoordinateTransformContext() - self.ctx.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'), 'test') - self.rpath = os.path.join(unitTestDataPath(), 'landsat.tif') + self.ctx.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + "test", + ) + self.rpath = os.path.join(unitTestDataPath(), "landsat.tif") def testTransformContextIsSetInCtor(self): """Test transform context can be set from ctor""" - rl = QgsRasterLayer(self.rpath, 'raster') + rl = QgsRasterLayer(self.rpath, "raster") self.assertFalse( - rl.transformContext().hasTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'))) + rl.transformContext().hasTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + ) + ) options = QgsRasterLayer.LayerOptions(transformContext=self.ctx) - rl = QgsRasterLayer(self.rpath, 'raster', 'gdal', options) + rl = QgsRasterLayer(self.rpath, "raster", "gdal", options) self.assertTrue( - rl.transformContext().hasTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'))) + rl.transformContext().hasTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + ) + ) def testTransformContextInheritsFromProject(self): """Test that when a layer is added to a project it inherits its context""" - rl = QgsRasterLayer(self.rpath, 'raster') + rl = QgsRasterLayer(self.rpath, "raster") self.assertFalse( - rl.transformContext().hasTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'))) + rl.transformContext().hasTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + ) + ) p = QgsProject() self.assertFalse( - p.transformContext().hasTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'))) + p.transformContext().hasTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + ) + ) p.setTransformContext(self.ctx) self.assertTrue( - p.transformContext().hasTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'))) + p.transformContext().hasTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + ) + ) p.addMapLayers([rl]) self.assertTrue( - rl.transformContext().hasTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'))) + rl.transformContext().hasTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + ) + ) def testTransformContextIsSyncedFromProject(self): """Test that when a layer is synced when project context changes""" - rl = QgsRasterLayer(self.rpath, 'raster') + rl = QgsRasterLayer(self.rpath, "raster") self.assertFalse( - rl.transformContext().hasTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'))) + rl.transformContext().hasTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + ) + ) p = QgsProject() self.assertFalse( - p.transformContext().hasTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'))) + p.transformContext().hasTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + ) + ) p.setTransformContext(self.ctx) self.assertTrue( - p.transformContext().hasTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'))) + p.transformContext().hasTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + ) + ) p.addMapLayers([rl]) self.assertTrue( - rl.transformContext().hasTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'))) + rl.transformContext().hasTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + ) + ) # Now change the project context tc2 = QgsCoordinateTransformContext() p.setTransformContext(tc2) self.assertFalse( - p.transformContext().hasTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'))) + p.transformContext().hasTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + ) + ) self.assertFalse( - rl.transformContext().hasTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'))) + rl.transformContext().hasTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + ) + ) p.setTransformContext(self.ctx) self.assertTrue( - p.transformContext().hasTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'))) + p.transformContext().hasTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + ) + ) self.assertTrue( - rl.transformContext().hasTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'))) + rl.transformContext().hasTransform( + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsCoordinateReferenceSystem("EPSG:3857"), + ) + ) def test_save_restore_pipe_data_defined_settings(self): """ Test that raster pipe data defined settings are correctly saved/restored along with the layer """ - rl = QgsRasterLayer(self.rpath, 'raster') - rl.pipe().dataDefinedProperties().setProperty(QgsRasterPipe.Property.RendererOpacity, QgsProperty.fromExpression('100/2')) + rl = QgsRasterLayer(self.rpath, "raster") + rl.pipe().dataDefinedProperties().setProperty( + QgsRasterPipe.Property.RendererOpacity, QgsProperty.fromExpression("100/2") + ) doc = QDomDocument() layer_elem = doc.createElement("maplayer") self.assertTrue(rl.writeLayerXml(layer_elem, doc, QgsReadWriteContext())) - rl2 = QgsRasterLayer(self.rpath, 'raster') - self.assertEqual(rl2.pipe().dataDefinedProperties().property(QgsRasterPipe.Property.RendererOpacity), - QgsProperty()) + rl2 = QgsRasterLayer(self.rpath, "raster") + self.assertEqual( + rl2.pipe() + .dataDefinedProperties() + .property(QgsRasterPipe.Property.RendererOpacity), + QgsProperty(), + ) self.assertTrue(rl2.readXml(layer_elem, QgsReadWriteContext())) - self.assertEqual(rl2.pipe().dataDefinedProperties().property(QgsRasterPipe.Property.RendererOpacity), - QgsProperty.fromExpression('100/2')) + self.assertEqual( + rl2.pipe() + .dataDefinedProperties() + .property(QgsRasterPipe.Property.RendererOpacity), + QgsProperty.fromExpression("100/2"), + ) def test_render_data_defined_opacity(self): - path = os.path.join(unitTestDataPath('raster'), - 'band1_float32_noct_epsg4326.tif') - raster_layer = QgsRasterLayer(path, 'test') + path = os.path.join( + unitTestDataPath("raster"), "band1_float32_noct_epsg4326.tif" + ) + raster_layer = QgsRasterLayer(path, "test") self.assertTrue(raster_layer.isValid()) renderer = QgsSingleBandGrayRenderer(raster_layer.dataProvider(), 1) raster_layer.setRenderer(renderer) raster_layer.setContrastEnhancement( QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum, - QgsRasterMinMaxOrigin.Limits.MinMax) + QgsRasterMinMaxOrigin.Limits.MinMax, + ) - raster_layer.pipe().dataDefinedProperties().setProperty(QgsRasterPipe.Property.RendererOpacity, QgsProperty.fromExpression('@layer_opacity')) + raster_layer.pipe().dataDefinedProperties().setProperty( + QgsRasterPipe.Property.RendererOpacity, + QgsProperty.fromExpression("@layer_opacity"), + ) ce = raster_layer.renderer().contrastEnhancement() - ce.setMinimumValue(-3.3319999287625854e+38) - ce.setMaximumValue(3.3999999521443642e+38) + ce.setMinimumValue(-3.3319999287625854e38) + ce.setMaximumValue(3.3999999521443642e38) map_settings = QgsMapSettings() map_settings.setLayers([raster_layer]) @@ -1238,21 +1459,21 @@ def test_render_data_defined_opacity(self): context = QgsExpressionContext() scope = QgsExpressionContextScope() - scope.setVariable('layer_opacity', 50) + scope.setVariable("layer_opacity", 50) context.appendScope(scope) map_settings.setExpressionContext(context) self.assertTrue( self.render_map_settings_check( - 'raster_data_defined_opacity', - 'raster_data_defined_opacity', - map_settings) + "raster_data_defined_opacity", + "raster_data_defined_opacity", + map_settings, + ) ) def test_read_xml_crash(self): """Check if converting a raster from 1.8 to 2 works.""" - path = os.path.join(unitTestDataPath('raster'), - 'raster-palette-crash2.tif') + path = os.path.join(unitTestDataPath("raster"), "raster-palette-crash2.tif") layer = QgsRasterLayer(path, QFileInfo(path).baseName()) context = QgsReadWriteContext() document = QDomDocument("style") @@ -1265,7 +1486,7 @@ def test_read_xml_crash(self): layer.readLayerXml(map_layer_element, context) def test_as_numpy(self): - layer = QgsRasterLayer(self.rpath, 'raster') + layer = QgsRasterLayer(self.rpath, "raster") arrays = layer.as_numpy() self.assertEqual(type(arrays[5]), np.ndarray) self.assertEqual(arrays.shape, (9, 200, 200)) @@ -1277,24 +1498,27 @@ def test_as_numpy(self): self.assertEqual(arrays.shape, (2, 200, 200)) self.assertEqual(arrays[0].dtype, np.int8) - path = os.path.join(unitTestDataPath('raster'), - 'rgb_with_mask.tif') + path = os.path.join(unitTestDataPath("raster"), "rgb_with_mask.tif") layer = QgsRasterLayer(path, QFileInfo(path).baseName()) arrays = layer.as_numpy() self.assertEqual(type(arrays[0]), np.ndarray) self.assertEqual(arrays.shape, (4, 150, 162)) self.assertEqual(arrays[0].dtype, np.int8) - path = os.path.join(unitTestDataPath('raster'), - 'rnd_percentile_raster5_float64.tif') + path = os.path.join( + unitTestDataPath("raster"), "rnd_percentile_raster5_float64.tif" + ) layer = QgsRasterLayer(path, QFileInfo(path).baseName()) arrays = layer.as_numpy() - self.assertEqual(type(arrays[0]), np.ndarray) # All maskedArrays are converted to numpy.array + self.assertEqual( + type(arrays[0]), np.ndarray + ) # All maskedArrays are converted to numpy.array self.assertEqual(arrays.shape, (1, 4, 4)) self.assertEqual(arrays[0].dtype, np.float64) - path = os.path.join(unitTestDataPath('raster'), - 'rnd_percentile_raster5_float64.tif') + path = os.path.join( + unitTestDataPath("raster"), "rnd_percentile_raster5_float64.tif" + ) layer = QgsRasterLayer(path, QFileInfo(path).baseName()) arrays = layer.as_numpy(use_masking=False) self.assertEqual(type(arrays[0]), np.ndarray) @@ -1302,5 +1526,5 @@ def test_as_numpy(self): self.assertEqual(arrays[0].dtype, np.float64) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterlayerelevationproperties.py b/tests/src/python/test_qgsrasterlayerelevationproperties.py index fd384760fad6..43ff3ccd945e 100644 --- a/tests/src/python/test_qgsrasterlayerelevationproperties.py +++ b/tests/src/python/test_qgsrasterlayerelevationproperties.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '09/11/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "09/11/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import math import os @@ -22,7 +23,7 @@ QgsReadWriteContext, QgsRasterLayer, QgsDoubleRange, - QgsProperty + QgsProperty, ) from qgis.testing import start_app, QgisTestCase @@ -38,8 +39,9 @@ def test_basic_elevation_surface(self): Basic tests for the class using the RepresentsElevationSurface mode """ props = QgsRasterLayerElevationProperties(None) - self.assertEqual(props.mode(), - Qgis.RasterElevationMode.RepresentsElevationSurface) + self.assertEqual( + props.mode(), Qgis.RasterElevationMode.RepresentsElevationSurface + ) self.assertEqual(props.zScale(), 1) self.assertEqual(props.zOffset(), 0) self.assertFalse(props.isEnabled()) @@ -48,8 +50,7 @@ def test_basic_elevation_surface(self): self.assertTrue(props.fixedRange().isInfinite()) self.assertIsInstance(props.profileLineSymbol(), QgsLineSymbol) self.assertIsInstance(props.profileFillSymbol(), QgsFillSymbol) - self.assertEqual(props.profileSymbology(), - Qgis.ProfileSurfaceSymbology.Line) + self.assertEqual(props.profileSymbology(), Qgis.ProfileSurfaceSymbology.Line) props.setZOffset(0.5) props.setZScale(2) @@ -62,48 +63,54 @@ def test_basic_elevation_surface(self): self.assertTrue(props.isEnabled()) self.assertEqual(props.bandNumber(), 2) self.assertTrue(props.hasElevation()) - self.assertEqual(props.profileSymbology(), - Qgis.ProfileSurfaceSymbology.FillBelow) + self.assertEqual( + props.profileSymbology(), Qgis.ProfileSurfaceSymbology.FillBelow + ) self.assertEqual(props.elevationLimit(), 909) sym = QgsLineSymbol.createSimple( - {'outline_color': '#ff4433', 'outline_width': 0.5}) + {"outline_color": "#ff4433", "outline_width": 0.5} + ) props.setProfileLineSymbol(sym) - self.assertEqual(props.profileLineSymbol().color().name(), '#ff4433') + self.assertEqual(props.profileLineSymbol().color().name(), "#ff4433") - sym = QgsFillSymbol.createSimple({'color': '#ff44ff'}) + sym = QgsFillSymbol.createSimple({"color": "#ff44ff"}) props.setProfileFillSymbol(sym) - self.assertEqual(props.profileFillSymbol().color().name(), '#ff44ff') + self.assertEqual(props.profileFillSymbol().color().name(), "#ff44ff") doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsRasterLayerElevationProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.mode(), - Qgis.RasterElevationMode.RepresentsElevationSurface) + self.assertEqual( + props2.mode(), Qgis.RasterElevationMode.RepresentsElevationSurface + ) self.assertEqual(props2.zScale(), 2) self.assertEqual(props2.zOffset(), 0.5) self.assertTrue(props2.isEnabled()) self.assertEqual(props2.bandNumber(), 2) - self.assertEqual(props2.profileLineSymbol().color().name(), '#ff4433') - self.assertEqual(props2.profileFillSymbol().color().name(), '#ff44ff') - self.assertEqual(props2.profileSymbology(), - Qgis.ProfileSurfaceSymbology.FillBelow) + self.assertEqual(props2.profileLineSymbol().color().name(), "#ff4433") + self.assertEqual(props2.profileFillSymbol().color().name(), "#ff44ff") + self.assertEqual( + props2.profileSymbology(), Qgis.ProfileSurfaceSymbology.FillBelow + ) self.assertEqual(props2.elevationLimit(), 909) props2 = props.clone() - self.assertEqual(props2.mode(), - Qgis.RasterElevationMode.RepresentsElevationSurface) + self.assertEqual( + props2.mode(), Qgis.RasterElevationMode.RepresentsElevationSurface + ) self.assertEqual(props2.zScale(), 2) self.assertEqual(props2.zOffset(), 0.5) self.assertTrue(props2.isEnabled()) self.assertEqual(props2.bandNumber(), 2) - self.assertEqual(props2.profileLineSymbol().color().name(), '#ff4433') - self.assertEqual(props2.profileFillSymbol().color().name(), '#ff44ff') - self.assertEqual(props2.profileSymbology(), - Qgis.ProfileSurfaceSymbology.FillBelow) + self.assertEqual(props2.profileLineSymbol().color().name(), "#ff4433") + self.assertEqual(props2.profileFillSymbol().color().name(), "#ff44ff") + self.assertEqual( + props2.profileSymbology(), Qgis.ProfileSurfaceSymbology.FillBelow + ) self.assertEqual(props2.elevationLimit(), 909) def test_basic_fixed_range(self): @@ -119,55 +126,53 @@ def test_basic_fixed_range(self): props.setZOffset(0.5) props.setZScale(2) self.assertEqual(props.fixedRange(), QgsDoubleRange(103.1, 106.8)) - self.assertEqual(props.calculateZRange(None), - QgsDoubleRange(103.1, 106.8)) - self.assertEqual(props.significantZValues(None), - [103.1, 106.8]) + self.assertEqual(props.calculateZRange(None), QgsDoubleRange(103.1, 106.8)) + self.assertEqual(props.significantZValues(None), [103.1, 106.8]) self.assertFalse(props.isVisibleInZRange(QgsDoubleRange(3.1, 6.8))) self.assertTrue(props.isVisibleInZRange(QgsDoubleRange(3.1, 104.8))) self.assertTrue(props.isVisibleInZRange(QgsDoubleRange(104.8, 114.8))) self.assertFalse(props.isVisibleInZRange(QgsDoubleRange(114.8, 124.8))) doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsRasterLayerElevationProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.mode(), - Qgis.RasterElevationMode.FixedElevationRange) + self.assertEqual(props2.mode(), Qgis.RasterElevationMode.FixedElevationRange) self.assertEqual(props2.fixedRange(), QgsDoubleRange(103.1, 106.8)) props2 = props.clone() - self.assertEqual(props2.mode(), - Qgis.RasterElevationMode.FixedElevationRange) + self.assertEqual(props2.mode(), Qgis.RasterElevationMode.FixedElevationRange) self.assertEqual(props2.fixedRange(), QgsDoubleRange(103.1, 106.8)) # include lower, exclude upper - props.setFixedRange(QgsDoubleRange(103.1, 106.8, - includeLower=True, - includeUpper=False)) - elem = doc.createElement('test') + props.setFixedRange( + QgsDoubleRange(103.1, 106.8, includeLower=True, includeUpper=False) + ) + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsRasterLayerElevationProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.fixedRange(), QgsDoubleRange(103.1, 106.8, - includeLower=True, - includeUpper=False)) + self.assertEqual( + props2.fixedRange(), + QgsDoubleRange(103.1, 106.8, includeLower=True, includeUpper=False), + ) # exclude lower, include upper - props.setFixedRange(QgsDoubleRange(103.1, 106.8, - includeLower=False, - includeUpper=True)) - elem = doc.createElement('test') + props.setFixedRange( + QgsDoubleRange(103.1, 106.8, includeLower=False, includeUpper=True) + ) + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsRasterLayerElevationProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.fixedRange(), QgsDoubleRange(103.1, 106.8, - includeLower=False, - includeUpper=True)) + self.assertEqual( + props2.fixedRange(), + QgsDoubleRange(103.1, 106.8, includeLower=False, includeUpper=True), + ) def test_basic_fixed_range_per_band(self): """ @@ -177,89 +182,103 @@ def test_basic_fixed_range_per_band(self): self.assertFalse(props.fixedRangePerBand()) props.setMode(Qgis.RasterElevationMode.FixedRangePerBand) - props.setFixedRangePerBand({1: QgsDoubleRange(103.1, 106.8), - 2: QgsDoubleRange(106.8, 116.8), - 3: QgsDoubleRange(116.8, 126.8)}) + props.setFixedRangePerBand( + { + 1: QgsDoubleRange(103.1, 106.8), + 2: QgsDoubleRange(106.8, 116.8), + 3: QgsDoubleRange(116.8, 126.8), + } + ) # fixed ranges should not be affected by scale/offset props.setZOffset(0.5) props.setZScale(2) - self.assertEqual(props.fixedRangePerBand(), {1: QgsDoubleRange(103.1, 106.8), - 2: QgsDoubleRange(106.8, 116.8), - 3: QgsDoubleRange(116.8, 126.8)}) - self.assertEqual(props.calculateZRange(None), - QgsDoubleRange(103.1, 126.8)) - self.assertEqual(props.significantZValues(None), - [103.1, 106.8, 116.8, 126.8]) + self.assertEqual( + props.fixedRangePerBand(), + { + 1: QgsDoubleRange(103.1, 106.8), + 2: QgsDoubleRange(106.8, 116.8), + 3: QgsDoubleRange(116.8, 126.8), + }, + ) + self.assertEqual(props.calculateZRange(None), QgsDoubleRange(103.1, 126.8)) + self.assertEqual(props.significantZValues(None), [103.1, 106.8, 116.8, 126.8]) self.assertFalse(props.isVisibleInZRange(QgsDoubleRange(3.1, 6.8))) self.assertTrue(props.isVisibleInZRange(QgsDoubleRange(3.1, 104.8))) self.assertTrue(props.isVisibleInZRange(QgsDoubleRange(104.8, 114.8))) self.assertTrue(props.isVisibleInZRange(QgsDoubleRange(114.8, 124.8))) self.assertFalse(props.isVisibleInZRange(QgsDoubleRange(128.8, 134.8))) + self.assertEqual(props.bandForElevationRange(None, QgsDoubleRange(1, 2)), -1) + self.assertEqual(props.bandForElevationRange(None, QgsDoubleRange(103, 104)), 1) + self.assertEqual(props.bandForElevationRange(None, QgsDoubleRange(104, 108)), 2) + self.assertEqual(props.bandForElevationRange(None, QgsDoubleRange(112, 112)), 2) + self.assertEqual(props.bandForElevationRange(None, QgsDoubleRange(112, 118)), 3) + self.assertEqual(props.bandForElevationRange(None, QgsDoubleRange(118, 218)), 3) self.assertEqual( - props.bandForElevationRange(None, QgsDoubleRange(1, 2)), -1) - self.assertEqual( - props.bandForElevationRange(None, QgsDoubleRange(103, 104)), 1) - self.assertEqual( - props.bandForElevationRange(None, QgsDoubleRange(104, 108)), 2) - self.assertEqual( - props.bandForElevationRange(None, QgsDoubleRange(112, 112)), 2) - self.assertEqual( - props.bandForElevationRange(None, QgsDoubleRange(112, 118)), 3) - self.assertEqual( - props.bandForElevationRange(None, QgsDoubleRange(118, 218)), 3) - self.assertEqual( - props.bandForElevationRange(None, QgsDoubleRange(212, 218)), -1) + props.bandForElevationRange(None, QgsDoubleRange(212, 218)), -1 + ) doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsRasterLayerElevationProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.mode(), - Qgis.RasterElevationMode.FixedRangePerBand) - self.assertEqual(props2.fixedRangePerBand(), {1: QgsDoubleRange(103.1, 106.8), - 2: QgsDoubleRange(106.8, 116.8), - 3: QgsDoubleRange(116.8, 126.8)}) + self.assertEqual(props2.mode(), Qgis.RasterElevationMode.FixedRangePerBand) + self.assertEqual( + props2.fixedRangePerBand(), + { + 1: QgsDoubleRange(103.1, 106.8), + 2: QgsDoubleRange(106.8, 116.8), + 3: QgsDoubleRange(116.8, 126.8), + }, + ) props2 = props.clone() - self.assertEqual(props2.mode(), - Qgis.RasterElevationMode.FixedRangePerBand) - self.assertEqual(props2.fixedRangePerBand(), {1: QgsDoubleRange(103.1, 106.8), - 2: QgsDoubleRange(106.8, 116.8), - 3: QgsDoubleRange(116.8, 126.8)}) + self.assertEqual(props2.mode(), Qgis.RasterElevationMode.FixedRangePerBand) + self.assertEqual( + props2.fixedRangePerBand(), + { + 1: QgsDoubleRange(103.1, 106.8), + 2: QgsDoubleRange(106.8, 116.8), + 3: QgsDoubleRange(116.8, 126.8), + }, + ) # include lower, exclude upper - props.setFixedRangePerBand({1: QgsDoubleRange(103.1, 106.8, - includeLower=True, - includeUpper=False)}) - elem = doc.createElement('test') + props.setFixedRangePerBand( + {1: QgsDoubleRange(103.1, 106.8, includeLower=True, includeUpper=False)} + ) + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsRasterLayerElevationProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.fixedRangePerBand(), {1: QgsDoubleRange(103.1, 106.8, - includeLower=True, - includeUpper=False)}) + self.assertEqual( + props2.fixedRangePerBand(), + {1: QgsDoubleRange(103.1, 106.8, includeLower=True, includeUpper=False)}, + ) # exclude lower, include upper - props.setFixedRangePerBand({1: QgsDoubleRange(103.1, 106.8, - includeLower=False, - includeUpper=True)}) - elem = doc.createElement('test') + props.setFixedRangePerBand( + {1: QgsDoubleRange(103.1, 106.8, includeLower=False, includeUpper=True)} + ) + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsRasterLayerElevationProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.fixedRangePerBand(), {1: QgsDoubleRange(103.1, 106.8, - includeLower=False, - includeUpper=True)}) + self.assertEqual( + props2.fixedRangePerBand(), + {1: QgsDoubleRange(103.1, 106.8, includeLower=False, includeUpper=True)}, + ) def test_basic_dynamic_range_per_band(self): """ Basic tests for the class using the DynamicRangePerBand mode """ - raster_layer = QgsRasterLayer(os.path.join(unitTestDataPath(), 'landsat_4326.tif')) + raster_layer = QgsRasterLayer( + os.path.join(unitTestDataPath(), "landsat_4326.tif") + ) self.assertTrue(raster_layer.isValid()) props = QgsRasterLayerElevationProperties(None) @@ -267,188 +286,259 @@ def test_basic_dynamic_range_per_band(self): props.setMode(Qgis.RasterElevationMode.DynamicRangePerBand) props.dataDefinedProperties().setProperty( QgsRasterLayerElevationProperties.Property.RasterPerBandLowerElevation, - QgsProperty.fromExpression("@band*2")) + QgsProperty.fromExpression("@band*2"), + ) props.dataDefinedProperties().setProperty( QgsRasterLayerElevationProperties.Property.RasterPerBandUpperElevation, - QgsProperty.fromExpression("@band*2 + 1")) + QgsProperty.fromExpression("@band*2 + 1"), + ) # fixed ranges should not be affected by scale/offset props.setZOffset(0.5) props.setZScale(2) - self.assertEqual(props.dataDefinedProperties().property( - QgsRasterLayerElevationProperties.Property.RasterPerBandLowerElevation).asExpression(), - '@band*2') - self.assertEqual(props.dataDefinedProperties().property( - QgsRasterLayerElevationProperties.Property.RasterPerBandUpperElevation).asExpression(), - '@band*2 + 1') + self.assertEqual( + props.dataDefinedProperties() + .property( + QgsRasterLayerElevationProperties.Property.RasterPerBandLowerElevation + ) + .asExpression(), + "@band*2", + ) + self.assertEqual( + props.dataDefinedProperties() + .property( + QgsRasterLayerElevationProperties.Property.RasterPerBandUpperElevation + ) + .asExpression(), + "@band*2 + 1", + ) # layer is required to calculated z range self.assertEqual(props.calculateZRange(None), QgsDoubleRange()) self.assertEqual(props.calculateZRange(raster_layer), QgsDoubleRange(2, 19)) - self.assertEqual(props.significantZValues(None), - []) - self.assertEqual(props.significantZValues(raster_layer), - [2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0]) + self.assertEqual(props.significantZValues(None), []) + self.assertEqual( + props.significantZValues(raster_layer), + [ + 2.0, + 3.0, + 4.0, + 5.0, + 6.0, + 7.0, + 8.0, + 9.0, + 10.0, + 11.0, + 12.0, + 13.0, + 14.0, + 15.0, + 16.0, + 17.0, + 18.0, + 19.0, + ], + ) self.assertFalse(props.isVisibleInZRange(QgsDoubleRange(3.1, 6.8))) self.assertTrue(props.isVisibleInZRange(QgsDoubleRange(3.1, 6.8), raster_layer)) self.assertFalse( - props.isVisibleInZRange(QgsDoubleRange(1.1, 1.9), raster_layer)) + props.isVisibleInZRange(QgsDoubleRange(1.1, 1.9), raster_layer) + ) self.assertFalse(props.isVisibleInZRange(QgsDoubleRange(104.8, 114.8))) + self.assertEqual(props.bandForElevationRange(None, QgsDoubleRange(1, 2)), -1) self.assertEqual( - props.bandForElevationRange(None, QgsDoubleRange(1, 2)), -1) - self.assertEqual( - props.bandForElevationRange(None, QgsDoubleRange(3.1, 6.8)), -1) + props.bandForElevationRange(None, QgsDoubleRange(3.1, 6.8)), -1 + ) self.assertEqual( - props.bandForElevationRange(raster_layer, QgsDoubleRange(3.1, 6.8)), 3) + props.bandForElevationRange(raster_layer, QgsDoubleRange(3.1, 6.8)), 3 + ) self.assertEqual( - props.bandForElevationRange(raster_layer, QgsDoubleRange(13.1, 16.8)), 8) + props.bandForElevationRange(raster_layer, QgsDoubleRange(13.1, 16.8)), 8 + ) self.assertEqual( - props.bandForElevationRange(raster_layer, QgsDoubleRange(113.1, 116.8)), -1) + props.bandForElevationRange(raster_layer, QgsDoubleRange(113.1, 116.8)), -1 + ) doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsRasterLayerElevationProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.mode(), - Qgis.RasterElevationMode.DynamicRangePerBand) - self.assertEqual(props2.dataDefinedProperties().property( - QgsRasterLayerElevationProperties.Property.RasterPerBandLowerElevation).asExpression(), - '@band*2') - self.assertEqual(props2.dataDefinedProperties().property( - QgsRasterLayerElevationProperties.Property.RasterPerBandUpperElevation).asExpression(), - '@band*2 + 1') + self.assertEqual(props2.mode(), Qgis.RasterElevationMode.DynamicRangePerBand) + self.assertEqual( + props2.dataDefinedProperties() + .property( + QgsRasterLayerElevationProperties.Property.RasterPerBandLowerElevation + ) + .asExpression(), + "@band*2", + ) + self.assertEqual( + props2.dataDefinedProperties() + .property( + QgsRasterLayerElevationProperties.Property.RasterPerBandUpperElevation + ) + .asExpression(), + "@band*2 + 1", + ) props2 = props.clone() - self.assertEqual(props2.mode(), - Qgis.RasterElevationMode.DynamicRangePerBand) + self.assertEqual(props2.mode(), Qgis.RasterElevationMode.DynamicRangePerBand) self.assertEqual( - props2.dataDefinedProperties().property( - QgsRasterLayerElevationProperties.Property.RasterPerBandLowerElevation).asExpression(), - '@band*2') + props2.dataDefinedProperties() + .property( + QgsRasterLayerElevationProperties.Property.RasterPerBandLowerElevation + ) + .asExpression(), + "@band*2", + ) - self.assertEqual(props2.dataDefinedProperties().property( - QgsRasterLayerElevationProperties.Property.RasterPerBandUpperElevation).asExpression(), - '@band*2 + 1') + self.assertEqual( + props2.dataDefinedProperties() + .property( + QgsRasterLayerElevationProperties.Property.RasterPerBandUpperElevation + ) + .asExpression(), + "@band*2 + 1", + ) def test_looks_like_dem(self): layer = QgsRasterLayer( - os.path.join(unitTestDataPath(), 'landsat.tif'), 'i am not a dem') + os.path.join(unitTestDataPath(), "landsat.tif"), "i am not a dem" + ) self.assertTrue(layer.isValid()) # not like a dem, the layer has multiple bands - self.assertFalse( - QgsRasterLayerElevationProperties.layerLooksLikeDem(layer)) + self.assertFalse(QgsRasterLayerElevationProperties.layerLooksLikeDem(layer)) # layer data type doesn't look like a dem layer = QgsRasterLayer( - os.path.join(unitTestDataPath(), - 'raster/band1_byte_ct_epsg4326.tif'), - 'i am not a dem') + os.path.join(unitTestDataPath(), "raster/band1_byte_ct_epsg4326.tif"), + "i am not a dem", + ) self.assertTrue(layer.isValid()) - self.assertFalse( - QgsRasterLayerElevationProperties.layerLooksLikeDem(layer)) + self.assertFalse(QgsRasterLayerElevationProperties.layerLooksLikeDem(layer)) layer = QgsRasterLayer( - os.path.join(unitTestDataPath(), 'landsat-f32-b1.tif'), 'my layer') + os.path.join(unitTestDataPath(), "landsat-f32-b1.tif"), "my layer" + ) self.assertTrue(layer.isValid()) # not like a dem, the layer name doesn't hint this to - self.assertFalse( - QgsRasterLayerElevationProperties.layerLooksLikeDem(layer)) - layer.setName('i am a DEM') - self.assertTrue( - QgsRasterLayerElevationProperties.layerLooksLikeDem(layer)) - layer.setName('i am a raster') - self.assertFalse( - QgsRasterLayerElevationProperties.layerLooksLikeDem(layer)) + self.assertFalse(QgsRasterLayerElevationProperties.layerLooksLikeDem(layer)) + layer.setName("i am a DEM") + self.assertTrue(QgsRasterLayerElevationProperties.layerLooksLikeDem(layer)) + layer.setName("i am a raster") + self.assertFalse(QgsRasterLayerElevationProperties.layerLooksLikeDem(layer)) - layer.setName('i am a aster satellite layer') - self.assertTrue( - QgsRasterLayerElevationProperties.layerLooksLikeDem(layer)) + layer.setName("i am a aster satellite layer") + self.assertTrue(QgsRasterLayerElevationProperties.layerLooksLikeDem(layer)) def test_elevation_range_for_pixel_value(self): """ Test transforming pixel values to elevation ranges """ - raster_layer = QgsRasterLayer(os.path.join(unitTestDataPath(), 'landsat_4326.tif')) + raster_layer = QgsRasterLayer( + os.path.join(unitTestDataPath(), "landsat_4326.tif") + ) self.assertTrue(raster_layer.isValid()) props = QgsRasterLayerElevationProperties(raster_layer) self.assertEqual( props.elevationRangeForPixelValue(layer=None, band=1, pixelValue=3), - QgsDoubleRange()) + QgsDoubleRange(), + ) props.setEnabled(True) self.assertEqual( props.elevationRangeForPixelValue(layer=None, band=1, pixelValue=3), - QgsDoubleRange(3, 3)) + QgsDoubleRange(3, 3), + ) self.assertEqual( props.elevationRangeForPixelValue(layer=None, band=1, pixelValue=math.nan), - QgsDoubleRange()) + QgsDoubleRange(), + ) # check that band number is respected props.setBandNumber(2) self.assertEqual( props.elevationRangeForPixelValue(layer=None, band=1, pixelValue=3), - QgsDoubleRange()) + QgsDoubleRange(), + ) self.assertEqual( props.elevationRangeForPixelValue(layer=None, band=2, pixelValue=3), - QgsDoubleRange(3, 3)) + QgsDoubleRange(3, 3), + ) # check that offset/scale is respected props.setZOffset(0.5) props.setZScale(2) self.assertEqual( props.elevationRangeForPixelValue(layer=None, band=2, pixelValue=3), - QgsDoubleRange(6.5, 6.5)) + QgsDoubleRange(6.5, 6.5), + ) # with fixed range mode props.setMode(Qgis.RasterElevationMode.FixedElevationRange) props.setFixedRange(QgsDoubleRange(11, 15)) self.assertEqual( props.elevationRangeForPixelValue(layer=None, band=1, pixelValue=math.nan), - QgsDoubleRange()) + QgsDoubleRange(), + ) self.assertEqual( props.elevationRangeForPixelValue(layer=None, band=1, pixelValue=3), - QgsDoubleRange(11, 15)) + QgsDoubleRange(11, 15), + ) # with fixed range per band mode props.setMode(Qgis.RasterElevationMode.FixedRangePerBand) - props.setFixedRangePerBand({1: QgsDoubleRange(11, 15), - 2: QgsDoubleRange(16, 25)}) + props.setFixedRangePerBand( + {1: QgsDoubleRange(11, 15), 2: QgsDoubleRange(16, 25)} + ) self.assertEqual( props.elevationRangeForPixelValue(layer=None, band=1, pixelValue=math.nan), - QgsDoubleRange()) + QgsDoubleRange(), + ) self.assertEqual( props.elevationRangeForPixelValue(layer=None, band=1, pixelValue=3), - QgsDoubleRange(11, 15)) + QgsDoubleRange(11, 15), + ) self.assertEqual( props.elevationRangeForPixelValue(layer=None, band=2, pixelValue=3), - QgsDoubleRange(16, 25)) + QgsDoubleRange(16, 25), + ) # with dynamic range per band mode props.setMode(Qgis.RasterElevationMode.DynamicRangePerBand) props.dataDefinedProperties().setProperty( QgsRasterLayerElevationProperties.Property.RasterPerBandLowerElevation, - QgsProperty.fromExpression("@band*2")) + QgsProperty.fromExpression("@band*2"), + ) props.dataDefinedProperties().setProperty( QgsRasterLayerElevationProperties.Property.RasterPerBandUpperElevation, - QgsProperty.fromExpression("@band*2 + 1")) + QgsProperty.fromExpression("@band*2 + 1"), + ) self.assertEqual( props.elevationRangeForPixelValue(layer=None, band=1, pixelValue=math.nan), - QgsDoubleRange()) + QgsDoubleRange(), + ) self.assertEqual( props.elevationRangeForPixelValue(layer=raster_layer, band=1, pixelValue=3), - QgsDoubleRange(2, 3)) + QgsDoubleRange(2, 3), + ) self.assertEqual( props.elevationRangeForPixelValue(layer=raster_layer, band=2, pixelValue=3), - QgsDoubleRange(4, 5)) + QgsDoubleRange(4, 5), + ) self.assertEqual( - props.elevationRangeForPixelValue(layer=raster_layer, band=100, pixelValue=3), - QgsDoubleRange()) + props.elevationRangeForPixelValue( + layer=raster_layer, band=100, pixelValue=3 + ), + QgsDoubleRange(), + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterlayerprofilegenerator.py b/tests/src/python/test_qgsrasterlayerprofilegenerator.py index adeab0d0bdc3..46a031b1fdf8 100644 --- a/tests/src/python/test_qgsrasterlayerprofilegenerator.py +++ b/tests/src/python/test_qgsrasterlayerprofilegenerator.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '18/03/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "18/03/2022" +__copyright__ = "Copyright 2022, The QGIS Project" import os @@ -32,11 +33,13 @@ class TestQgsRasterLayerProfileGenerator(QgisTestCase): def testGeneration(self): - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) curve = QgsLineString() - curve.fromWkt('LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)') + curve.fromWkt( + "LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)" + ) req = QgsProfileRequest(curve) generator = rl.createProfileGenerator(req) @@ -51,7 +54,7 @@ def testGeneration(self): self.assertFalse(generator.generateProfile()) # set correct crs for linestring and re-try - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = rl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) @@ -70,32 +73,48 @@ def testGeneration(self): self.assertEqual(len(features), 1) self.assertEqual(features[0].layerIdentifier, rl.id()) self.assertEqual(features[0].geometry.constGet().numPoints(), 1394) - self.assertEqual(features[0].geometry.constGet().pointN(0).asWkt(-2), 'Point Z (-348100 6633700 200)') - self.assertEqual(features[0].geometry.constGet().pointN(1393).asWkt(-2), 'Point Z (-345800 6631600 100)') + self.assertEqual( + features[0].geometry.constGet().pointN(0).asWkt(-2), + "Point Z (-348100 6633700 200)", + ) + self.assertEqual( + features[0].geometry.constGet().pointN(1393).asWkt(-2), + "Point Z (-345800 6631600 100)", + ) features = r.asFeatures(Qgis.ProfileExportType.Profile2D) self.assertEqual(len(features), 1) self.assertEqual(features[0].layerIdentifier, rl.id()) self.assertEqual(features[0].geometry.constGet().numPoints(), 1394) - self.assertEqual(features[0].geometry.constGet().pointN(0).asWkt(-2), 'Point (0 200)') - self.assertEqual(features[0].geometry.constGet().pointN(1393).asWkt(-2), 'Point (3400 100)') + self.assertEqual( + features[0].geometry.constGet().pointN(0).asWkt(-2), "Point (0 200)" + ) + self.assertEqual( + features[0].geometry.constGet().pointN(1393).asWkt(-2), "Point (3400 100)" + ) features = r.asFeatures(Qgis.ProfileExportType.DistanceVsElevationTable) self.assertEqual(len(features), 1394) self.assertEqual(features[0].layerIdentifier, rl.id()) - self.assertAlmostEqual(features[0].attributes['distance'], 0, 0) - self.assertAlmostEqual(features[0].attributes['elevation'], 154.0, 0) - self.assertEqual(features[0].geometry.asWkt(-2), 'Point Z (-348100 6633700 200)') - self.assertEqual(features[-1].geometry.asWkt(-2), 'Point Z (-345800 6631600 100)') - self.assertAlmostEqual(features[-1].attributes['distance'], 3392.69, -1) - self.assertAlmostEqual(features[-1].attributes['elevation'], 99.0, 0) + self.assertAlmostEqual(features[0].attributes["distance"], 0, 0) + self.assertAlmostEqual(features[0].attributes["elevation"], 154.0, 0) + self.assertEqual( + features[0].geometry.asWkt(-2), "Point Z (-348100 6633700 200)" + ) + self.assertEqual( + features[-1].geometry.asWkt(-2), "Point Z (-345800 6631600 100)" + ) + self.assertAlmostEqual(features[-1].attributes["distance"], 3392.69, -1) + self.assertAlmostEqual(features[-1].attributes["elevation"], 99.0, 0) def testGenerationWithStepSize(self): - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) curve = QgsLineString() - curve.fromWkt('LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)') + curve.fromWkt( + "LineString (-348095.18706532847136259 6633687.0235139261931181, -347271.57799367723055184 6633093.13086318597197533, -346140.60267287614988163 6632697.89590711053460836, -345777.013075890194159 6631575.50219972990453243)" + ) req = QgsProfileRequest(curve) req.setStepDistance(10) @@ -111,7 +130,7 @@ def testGenerationWithStepSize(self): self.assertFalse(generator.generateProfile()) # set correct crs for linestring and re-try - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = rl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) @@ -130,38 +149,54 @@ def testGenerationWithStepSize(self): self.assertEqual(len(features), 1) self.assertEqual(features[0].layerIdentifier, rl.id()) self.assertEqual(features[0].geometry.constGet().numPoints(), 341) - self.assertEqual(features[0].geometry.constGet().pointN(0).asWkt(-2), 'Point Z (-348100 6633700 200)') - self.assertEqual(features[0].geometry.constGet().pointN(340).asWkt(-2), 'Point Z (-345800 6631600 100)') + self.assertEqual( + features[0].geometry.constGet().pointN(0).asWkt(-2), + "Point Z (-348100 6633700 200)", + ) + self.assertEqual( + features[0].geometry.constGet().pointN(340).asWkt(-2), + "Point Z (-345800 6631600 100)", + ) features = r.asFeatures(Qgis.ProfileExportType.Profile2D) self.assertEqual(len(features), 1) self.assertEqual(features[0].layerIdentifier, rl.id()) self.assertEqual(features[0].geometry.constGet().numPoints(), 341) - self.assertEqual(features[0].geometry.constGet().pointN(0).asWkt(-2), 'Point (0 200)') - self.assertEqual(features[0].geometry.constGet().pointN(340).asWkt(-2), 'Point (3400 100)') + self.assertEqual( + features[0].geometry.constGet().pointN(0).asWkt(-2), "Point (0 200)" + ) + self.assertEqual( + features[0].geometry.constGet().pointN(340).asWkt(-2), "Point (3400 100)" + ) features = r.asFeatures(Qgis.ProfileExportType.DistanceVsElevationTable) self.assertEqual(len(features), 341) self.assertEqual(features[0].layerIdentifier, rl.id()) - self.assertAlmostEqual(features[0].attributes['distance'], 0.0, 2) - self.assertAlmostEqual(features[0].attributes['elevation'], 154.0, 2) - self.assertEqual(features[0].geometry.asWkt(-2), 'Point Z (-348100 6633700 200)') - self.assertEqual(features[-1].geometry.asWkt(-2), 'Point Z (-345800 6631600 100)') - self.assertAlmostEqual(features[-1].attributes['distance'], 3393.2639, 2) - self.assertAlmostEqual(features[-1].attributes['elevation'], 99.0, 2) + self.assertAlmostEqual(features[0].attributes["distance"], 0.0, 2) + self.assertAlmostEqual(features[0].attributes["elevation"], 154.0, 2) + self.assertEqual( + features[0].geometry.asWkt(-2), "Point Z (-348100 6633700 200)" + ) + self.assertEqual( + features[-1].geometry.asWkt(-2), "Point Z (-345800 6631600 100)" + ) + self.assertAlmostEqual(features[-1].attributes["distance"], 3393.2639, 2) + self.assertAlmostEqual(features[-1].attributes["elevation"], 99.0, 2) def testGenerationWithVerticalLine(self): - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) curve = QgsLineString() - curve.fromWkt('LineString (321878.13400000002002344 130592.75222520538954996, 321878.13400000002002344 129982.02943174661777448)') + curve.fromWkt( + "LineString (321878.13400000002002344 130592.75222520538954996, 321878.13400000002002344 129982.02943174661777448)" + ) req = QgsProfileRequest(curve) req.setStepDistance(10) rl.elevationProperties().setEnabled(True) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:27700')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:27700")) generator = rl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) @@ -177,17 +212,19 @@ def testGenerationWithVerticalLine(self): self.assertEqual(r.zRange().upper(), 120) def testGenerationWithHorizontalLine(self): - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) curve = QgsLineString() - curve.fromWkt('LineString (321471.82703730149660259 130317.67500000000291038, 322294.53625493601430207 130317.67500000000291038)') + curve.fromWkt( + "LineString (321471.82703730149660259 130317.67500000000291038, 322294.53625493601430207 130317.67500000000291038)" + ) req = QgsProfileRequest(curve) req.setStepDistance(10) rl.elevationProperties().setEnabled(True) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:27700')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:27700")) generator = rl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) @@ -203,12 +240,14 @@ def testGenerationWithHorizontalLine(self): self.assertEqual(r.zRange().upper(), 130) def testSnapping(self): - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) rl.elevationProperties().setEnabled(True) curve = QgsLineString() - curve.fromWkt('LineString (321621.3770066662109457 129734.87810317709227093, 321894.21278918092139065 129858.49142702402605209)') + curve.fromWkt( + "LineString (321621.3770066662109457 129734.87810317709227093, 321894.21278918092139065 129858.49142702402605209)" + ) req = QgsProfileRequest(curve) generator = rl.createProfileGenerator(req) @@ -241,12 +280,14 @@ def testSnapping(self): self.assertFalse(res.isValid()) def testIdentify(self): - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) rl.elevationProperties().setEnabled(True) curve = QgsLineString() - curve.fromWkt('LineString (321621.3770066662109457 129734.87810317709227093, 321894.21278918092139065 129858.49142702402605209)') + curve.fromWkt( + "LineString (321621.3770066662109457 129734.87810317709227093, 321894.21278918092139065 129858.49142702402605209)" + ) req = QgsProfileRequest(curve) generator = rl.createProfileGenerator(req) @@ -266,18 +307,18 @@ def testIdentify(self): res = r.identify(QgsProfilePoint(0, 70), context) self.assertEqual(len(res), 1) self.assertEqual(res[0].layer(), rl) - self.assertEqual(res[0].results(), [{'distance': 0.0, 'elevation': 72.0}]) + self.assertEqual(res[0].results(), [{"distance": 0.0, "elevation": 72.0}]) context.maximumSurfaceDistanceDelta = 0 context.maximumSurfaceElevationDelta = 5 res = r.identify(QgsProfilePoint(200, 79), context) self.assertEqual(len(res), 1) self.assertEqual(res[0].layer(), rl) - self.assertEqual(res[0].results(), [{'distance': 200.0, 'elevation': 75.0}]) + self.assertEqual(res[0].results(), [{"distance": 200.0, "elevation": 75.0}]) res = r.identify(QgsProfilePoint(200, 85), context) self.assertFalse(res) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterlayerproperties.py b/tests/src/python/test_qgsrasterlayerproperties.py index afddf97bca9f..07b0efab0d7f 100644 --- a/tests/src/python/test_qgsrasterlayerproperties.py +++ b/tests/src/python/test_qgsrasterlayerproperties.py @@ -6,9 +6,9 @@ (at your option) any later version. """ -__author__ = 'Benjamin Jakimow' -__date__ = '14/01/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' +__author__ = "Benjamin Jakimow" +__date__ = "14/01/2022" +__copyright__ = "Copyright 2022, The QGIS Project" import pathlib import typing @@ -50,7 +50,9 @@ class MyWidget(QgsMapLayerConfigWidget): COUNT = 0 - def __init__(self, layer: QgsMapLayer, canvas: QgsMapCanvas, parent: QWidget = None): + def __init__( + self, layer: QgsMapLayer, canvas: QgsMapCanvas, parent: QWidget = None + ): super().__init__(layer, canvas, parent=parent) def apply(self) -> None: @@ -72,21 +74,25 @@ def supportsLayer(self, layer): def supportLayerPropertiesDialog(self): return True - def createWidget(self, - layer: QgsMapLayer, - canvas: QgsMapCanvas, - dockWidget: bool = ..., parent: - typing.Optional[QWidget] = ...) -> QgsMapLayerConfigWidget: + def createWidget( + self, + layer: QgsMapLayer, + canvas: QgsMapCanvas, + dockWidget: bool = ..., + parent: typing.Optional[QWidget] = ..., + ) -> QgsMapLayerConfigWidget: MyFactory.COUNT += 1 w = MyWidget(layer, canvas, parent=parent) return w - myFactory = MyFactory('Dummy Factory', QIcon()) + myFactory = MyFactory("Dummy Factory", QIcon()) myCanvas = QgsMapCanvas() - myPath = pathlib.Path(unitTestDataPath('raster')) / 'band1_float32_noct_epsg4326.tif' + myPath = ( + pathlib.Path(unitTestDataPath("raster")) / "band1_float32_noct_epsg4326.tif" + ) myRasterLayer = QgsRasterLayer(myPath.as_posix(), myPath.name) - assert myRasterLayer.isValid(), f'Raster not loaded {myPath}' + assert myRasterLayer.isValid(), f"Raster not loaded {myPath}" dialog = QgsRasterLayerProperties(myRasterLayer, myCanvas) @@ -95,21 +101,29 @@ def createWidget(self, # this should trigger dialog.accept() - self.assertEqual(MyFactory.COUNT, 1, msg='Custom QgsMapLayerConfigWidget::createWidget(...) not called') - self.assertEqual(MyWidget.COUNT, 1, msg='Custom QgsMapLayerConfigWidget::apply() not called') + self.assertEqual( + MyFactory.COUNT, + 1, + msg="Custom QgsMapLayerConfigWidget::createWidget(...) not called", + ) + self.assertEqual( + MyWidget.COUNT, 1, msg="Custom QgsMapLayerConfigWidget::apply() not called" + ) def test_transparency_load(self): """Test issue GH #54496""" myCanvas = QgsMapCanvas() - myPath = pathlib.Path(unitTestDataPath('raster')) / 'band1_float32_noct_epsg4326.tif' + myPath = ( + pathlib.Path(unitTestDataPath("raster")) / "band1_float32_noct_epsg4326.tif" + ) myRasterLayer = QgsRasterLayer(myPath.as_posix(), myPath.name) - assert myRasterLayer.isValid(), f'Raster not loaded {myPath}' + assert myRasterLayer.isValid(), f"Raster not loaded {myPath}" dialog = QgsRasterLayerProperties(myRasterLayer, myCanvas) - with tempfile.NamedTemporaryFile(suffix='.qml') as qml_file_object: + with tempfile.NamedTemporaryFile(suffix=".qml") as qml_file_object: renderer = myRasterLayer.renderer() renderer.setOpacity(0.5) self.assertTrue(myRasterLayer.saveNamedStyle(qml_file_object.name)[1]) @@ -122,5 +136,5 @@ def test_transparency_load(self): self.assertEqual(renderer.opacity(), 0.5) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterlayerrenderer.py b/tests/src/python/test_qgsrasterlayerrenderer.py index 08d3842678ea..8c5406c6ad22 100644 --- a/tests/src/python/test_qgsrasterlayerrenderer.py +++ b/tests/src/python/test_qgsrasterlayerrenderer.py @@ -5,18 +5,14 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2020-06' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2020-06" +__copyright__ = "Copyright 2020, The QGIS Project" import os -from qgis.PyQt.QtCore import ( - QSize, - QDate, - QTime, - QDateTime -) +from qgis.PyQt.QtCore import QSize, QDate, QTime, QDateTime from qgis.core import ( Qgis, QgsCoordinateReferenceSystem, @@ -33,7 +29,7 @@ QgsRasterLayerElevationProperties, QgsProperty, QgsDateTimeRange, - QgsLineSymbol + QgsLineSymbol, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -50,36 +46,47 @@ class TestQgsRasterLayerRenderer(QgisTestCase): @classmethod def control_path_prefix(cls): - return 'rasterlayerrenderer' + return "rasterlayerrenderer" def testRenderWithPainterClipRegions(self): - raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, 'rgb256x256.png')) + raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, "rgb256x256.png")) self.assertTrue(raster_layer.isValid()) - raster_layer.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + raster_layer.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) - mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) - mapsettings.setExtent(QgsRectangle(0.0001451, -0.0001291, 0.0021493, -0.0021306)) + mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326")) + mapsettings.setExtent( + QgsRectangle(0.0001451, -0.0001291, 0.0021493, -0.0021306) + ) mapsettings.setLayers([raster_layer]) - region = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon ((0.00131242078273144 -0.00059281669806561, 0.00066744230712249 -0.00110186995774045, 0.00065145110524788 -0.00152830200772984, 0.00141369839460392 -0.00189076925022083, 0.00210931567614912 -0.00094195793899443, 0.00169354442740946 -0.00067810310806349, 0.00131242078273144 -0.00059281669806561))')) + region = QgsMapClippingRegion( + QgsGeometry.fromWkt( + "Polygon ((0.00131242078273144 -0.00059281669806561, 0.00066744230712249 -0.00110186995774045, 0.00065145110524788 -0.00152830200772984, 0.00141369839460392 -0.00189076925022083, 0.00210931567614912 -0.00094195793899443, 0.00169354442740946 -0.00067810310806349, 0.00131242078273144 -0.00059281669806561))" + ) + ) region.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipPainterOnly) - region2 = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon ((0.00067010750743492 -0.0007740503193111, 0.00064612070462302 -0.00151764120648011, 0.00153629760897587 -0.00158693641460339, 0.0014909892036645 -0.00063812510337699, 0.00106722235398754 -0.00055816909400397, 0.00067010750743492 -0.0007740503193111))')) - region2.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipToIntersection) + region2 = QgsMapClippingRegion( + QgsGeometry.fromWkt( + "Polygon ((0.00067010750743492 -0.0007740503193111, 0.00064612070462302 -0.00151764120648011, 0.00153629760897587 -0.00158693641460339, 0.0014909892036645 -0.00063812510337699, 0.00106722235398754 -0.00055816909400397, 0.00067010750743492 -0.0007740503193111))" + ) + ) + region2.setFeatureClip( + QgsMapClippingRegion.FeatureClippingType.ClipToIntersection + ) mapsettings.addClippingRegion(region) mapsettings.addClippingRegion(region2) self.assertTrue( self.render_map_settings_check( - 'painterclip_region', - 'painterclip_region', - mapsettings) + "painterclip_region", "painterclip_region", mapsettings + ) ) def test_render_dem_with_z_range_filter(self): - raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, '3d', 'dtm.tif')) + raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, "3d", "dtm.tif")) self.assertTrue(raster_layer.isValid()) # start with no elevation settings on layer self.assertFalse(raster_layer.elevationProperties().hasElevation()) @@ -94,9 +101,10 @@ def test_render_dem_with_z_range_filter(self): self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings, not elevation enabled layer', - 'dem_no_filter', - map_settings) + "Z range filter on map settings, not elevation enabled layer", + "dem_no_filter", + map_settings, + ) ) # set layer as elevation enabled @@ -105,18 +113,20 @@ def test_render_dem_with_z_range_filter(self): map_settings.setZRange(QgsDoubleRange()) self.assertTrue( self.render_map_settings_check( - 'No Z range filter on map settings, elevation enabled layer', - 'dem_no_filter', - map_settings) + "No Z range filter on map settings, elevation enabled layer", + "dem_no_filter", + map_settings, + ) ) # filter on map settings, elevation enabled layer => should be filtered map_settings.setZRange(QgsDoubleRange(100, 130)) self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings, elevation enabled layer', - 'dem_filter', - map_settings) + "Z range filter on map settings, elevation enabled layer", + "dem_filter", + map_settings, + ) ) # with offset and scaling @@ -124,18 +134,17 @@ def test_render_dem_with_z_range_filter(self): raster_layer.elevationProperties().setZScale(0.75) self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings, elevation enabled layer with offset and scale', - 'dem_filter_offset_and_scale', - map_settings) + "Z range filter on map settings, elevation enabled layer with offset and scale", + "dem_filter_offset_and_scale", + map_settings, + ) ) def test_contour_render_dem_with_z_range_filter(self): - raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, '3d', 'dtm.tif')) + raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, "3d", "dtm.tif")) renderer = QgsRasterContourRenderer(raster_layer.dataProvider()) renderer.setContourInterval(10) - renderer.setContourSymbol( - QgsLineSymbol.createSimple({'width': 1}) - ) + renderer.setContourSymbol(QgsLineSymbol.createSimple({"width": 1})) renderer.setContourIndexInterval(0) raster_layer.setRenderer(renderer) @@ -154,9 +163,10 @@ def test_contour_render_dem_with_z_range_filter(self): raster_layer.elevationProperties().setEnabled(True) self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings, contour renderer', - 'dem_filter_contour', - map_settings) + "Z range filter on map settings, contour renderer", + "dem_filter_contour", + map_settings, + ) ) # with offset and scaling @@ -164,9 +174,10 @@ def test_contour_render_dem_with_z_range_filter(self): raster_layer.elevationProperties().setZScale(0.75) self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings, contour renderer, elevation enabled layer with offset and scale', - 'dem_filter_contour_offset_and_scale', - map_settings) + "Z range filter on map settings, contour renderer, elevation enabled layer with offset and scale", + "dem_filter_contour_offset_and_scale", + map_settings, + ) ) def test_render_fixed_elevation_range_with_z_range_filter(self): @@ -174,7 +185,7 @@ def test_render_fixed_elevation_range_with_z_range_filter(self): Test rendering a raster with a fixed elevation range when map settings has a z range filter """ - raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, '3d', 'dtm.tif')) + raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, "3d", "dtm.tif")) self.assertTrue(raster_layer.isValid()) # set layer as elevation enabled @@ -182,9 +193,7 @@ def test_render_fixed_elevation_range_with_z_range_filter(self): raster_layer.elevationProperties().setMode( Qgis.RasterElevationMode.FixedElevationRange ) - raster_layer.elevationProperties().setFixedRange( - QgsDoubleRange(33, 38) - ) + raster_layer.elevationProperties().setFixedRange(QgsDoubleRange(33, 38)) map_settings = QgsMapSettings() map_settings.setOutputSize(QSize(400, 400)) @@ -197,27 +206,30 @@ def test_render_fixed_elevation_range_with_z_range_filter(self): map_settings.setZRange(QgsDoubleRange()) self.assertTrue( self.render_map_settings_check( - 'No Z range filter on map settings, fixed elevation range layer', - 'dem_no_filter', - map_settings) + "No Z range filter on map settings, fixed elevation range layer", + "dem_no_filter", + map_settings, + ) ) # map settings range includes layer's range map_settings.setZRange(QgsDoubleRange(30, 35)) self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings includes layers fixed range', - 'fixed_elevation_range_included', - map_settings) + "Z range filter on map settings includes layers fixed range", + "fixed_elevation_range_included", + map_settings, + ) ) # map settings range excludes layer's range map_settings.setZRange(QgsDoubleRange(130, 135)) self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings outside of layers fixed range', - 'fixed_elevation_range_excluded', - map_settings) + "Z range filter on map settings outside of layers fixed range", + "fixed_elevation_range_excluded", + map_settings, + ) ) def test_render_fixed_range_per_band_with_z_range_filter(self): @@ -225,7 +237,7 @@ def test_render_fixed_range_per_band_with_z_range_filter(self): Test rendering a raster with a fixed range per band when map settings has a z range filter """ - raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, 'landsat_4326.tif')) + raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, "landsat_4326.tif")) self.assertTrue(raster_layer.isValid()) renderer = QgsSingleBandGrayRenderer(raster_layer.dataProvider(), 3) @@ -241,9 +253,11 @@ def test_render_fixed_range_per_band_with_z_range_filter(self): Qgis.RasterElevationMode.FixedRangePerBand ) raster_layer.elevationProperties().setFixedRangePerBand( - {3: QgsDoubleRange(33, 38), - 4: QgsDoubleRange(35, 40), - 5: QgsDoubleRange(40, 48)} + { + 3: QgsDoubleRange(33, 38), + 4: QgsDoubleRange(35, 40), + 5: QgsDoubleRange(40, 48), + } ) map_settings = QgsMapSettings() @@ -257,45 +271,50 @@ def test_render_fixed_range_per_band_with_z_range_filter(self): map_settings.setZRange(QgsDoubleRange()) self.assertTrue( self.render_map_settings_check( - 'No Z range filter on map settings, elevation range per band', - 'elevation_range_per_band_no_filter', - map_settings) + "No Z range filter on map settings, elevation range per band", + "elevation_range_per_band_no_filter", + map_settings, + ) ) # map settings range matches band 3 only map_settings.setZRange(QgsDoubleRange(30, 34)) self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings matches band 3 only', - 'elevation_range_per_band_match_3', - map_settings) + "Z range filter on map settings matches band 3 only", + "elevation_range_per_band_match_3", + map_settings, + ) ) # map settings range matches band 3 and 4, should pick the highest (4) map_settings.setZRange(QgsDoubleRange(36, 38.5)) self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings matches band 3 and 4', - 'elevation_range_per_band_match_4', - map_settings) + "Z range filter on map settings matches band 3 and 4", + "elevation_range_per_band_match_4", + map_settings, + ) ) # map settings range matches band 5 map_settings.setZRange(QgsDoubleRange(46, 58.5)) self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings matches band 5', - 'elevation_range_per_band_match_5', - map_settings) + "Z range filter on map settings matches band 5", + "elevation_range_per_band_match_5", + map_settings, + ) ) # map settings range excludes layer's range map_settings.setZRange(QgsDoubleRange(130, 135)) self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings outside of layer band ranges', - 'fixed_elevation_range_excluded', - map_settings) + "Z range filter on map settings outside of layer band ranges", + "fixed_elevation_range_excluded", + map_settings, + ) ) def test_render_dynamic_range_per_band_with_z_range_filter(self): @@ -303,7 +322,7 @@ def test_render_dynamic_range_per_band_with_z_range_filter(self): Test rendering a raster with a dynamic range per band when map settings has a z range filter """ - raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, 'landsat_4326.tif')) + raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, "landsat_4326.tif")) self.assertTrue(raster_layer.isValid()) renderer = QgsSingleBandGrayRenderer(raster_layer.dataProvider(), 3) @@ -321,11 +340,15 @@ def test_render_dynamic_range_per_band_with_z_range_filter(self): raster_layer.elevationProperties().dataDefinedProperties().setProperty( QgsRasterLayerElevationProperties.Property.RasterPerBandLowerElevation, - QgsProperty.fromExpression('case when @band=3 then 33 when @band=4 then 35 when @band=5 then 40 else null end') + QgsProperty.fromExpression( + "case when @band=3 then 33 when @band=4 then 35 when @band=5 then 40 else null end" + ), ) raster_layer.elevationProperties().dataDefinedProperties().setProperty( QgsRasterLayerElevationProperties.Property.RasterPerBandUpperElevation, - QgsProperty.fromExpression('case when @band=3 then 38 when @band=4 then 40 when @band=5 then 48 else null end') + QgsProperty.fromExpression( + "case when @band=3 then 38 when @band=4 then 40 when @band=5 then 48 else null end" + ), ) map_settings = QgsMapSettings() @@ -339,45 +362,50 @@ def test_render_dynamic_range_per_band_with_z_range_filter(self): map_settings.setZRange(QgsDoubleRange()) self.assertTrue( self.render_map_settings_check( - 'No Z range filter on map settings, elevation range per band', - 'elevation_range_per_band_no_filter', - map_settings) + "No Z range filter on map settings, elevation range per band", + "elevation_range_per_band_no_filter", + map_settings, + ) ) # map settings range matches band 3 only map_settings.setZRange(QgsDoubleRange(30, 34)) self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings matches band 3 only', - 'elevation_range_per_band_match_3', - map_settings) + "Z range filter on map settings matches band 3 only", + "elevation_range_per_band_match_3", + map_settings, + ) ) # map settings range matches band 3 and 4, should pick the highest (4) map_settings.setZRange(QgsDoubleRange(36, 38.5)) self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings matches band 3 and 4', - 'elevation_range_per_band_match_4', - map_settings) + "Z range filter on map settings matches band 3 and 4", + "elevation_range_per_band_match_4", + map_settings, + ) ) # map settings range matches band 5 map_settings.setZRange(QgsDoubleRange(46, 58.5)) self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings matches band 5', - 'elevation_range_per_band_match_5', - map_settings) + "Z range filter on map settings matches band 5", + "elevation_range_per_band_match_5", + map_settings, + ) ) # map settings range excludes layer's range map_settings.setZRange(QgsDoubleRange(130, 135)) self.assertTrue( self.render_map_settings_check( - 'Z range filter on map settings outside of layer band ranges', - 'fixed_elevation_range_excluded', - map_settings) + "Z range filter on map settings outside of layer band ranges", + "fixed_elevation_range_excluded", + map_settings, + ) ) def test_render_fixed_temporal_range_with_temporal_range_filter(self): @@ -385,7 +413,7 @@ def test_render_fixed_temporal_range_with_temporal_range_filter(self): Test rendering a raster with a fixed temporal range when map settings has a temporal range filter """ - raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, '3d', 'dtm.tif')) + raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, "3d", "dtm.tif")) self.assertTrue(raster_layer.isValid()) # set layer as elevation enabled @@ -395,10 +423,8 @@ def test_render_fixed_temporal_range_with_temporal_range_filter(self): ) raster_layer.temporalProperties().setFixedTemporalRange( QgsDateTimeRange( - QDateTime(QDate(2023, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2023, 12, 31), - QTime(23, 59, 59)) + QDateTime(QDate(2023, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2023, 12, 31), QTime(23, 59, 59)), ) ) @@ -413,38 +439,41 @@ def test_render_fixed_temporal_range_with_temporal_range_filter(self): map_settings.setIsTemporal(False) self.assertTrue( self.render_map_settings_check( - 'No temporal filter on map settings, fixed temporal range layer', - 'dem_no_filter', - map_settings) + "No temporal filter on map settings, fixed temporal range layer", + "dem_no_filter", + map_settings, + ) ) # map settings range includes layer's range map_settings.setIsTemporal(True) - map_settings.setTemporalRange(QgsDateTimeRange( - QDateTime(QDate(2022, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2023, 6, 30), - QTime(23, 59, 59)) - )) + map_settings.setTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2022, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2023, 6, 30), QTime(23, 59, 59)), + ) + ) self.assertTrue( self.render_map_settings_check( - 'Temporal range filter on map settings includes layers fixed range', - 'fixed_elevation_range_included', - map_settings) + "Temporal range filter on map settings includes layers fixed range", + "fixed_elevation_range_included", + map_settings, + ) ) # map settings range excludes layer's range - map_settings.setTemporalRange(QgsDateTimeRange( - QDateTime(QDate(2024, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2024, 6, 30), - QTime(23, 59, 59)) - )) + map_settings.setTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2024, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2024, 6, 30), QTime(23, 59, 59)), + ) + ) self.assertTrue( self.render_map_settings_check( - 'Temporal range filter on map settings outside of layers fixed range', - 'fixed_elevation_range_excluded', - map_settings) + "Temporal range filter on map settings outside of layers fixed range", + "fixed_elevation_range_excluded", + map_settings, + ) ) def test_render_fixed_range_per_band_with_temporal_range_filter(self): @@ -452,7 +481,7 @@ def test_render_fixed_range_per_band_with_temporal_range_filter(self): Test rendering a raster with a fixed temporal range per band when map settings has a temporal range filter """ - raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, 'landsat_4326.tif')) + raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, "landsat_4326.tif")) self.assertTrue(raster_layer.isValid()) renderer = QgsSingleBandGrayRenderer(raster_layer.dataProvider(), 3) @@ -471,20 +500,17 @@ def test_render_fixed_range_per_band_with_temporal_range_filter(self): { 3: QgsDateTimeRange( QDateTime(QDate(2023, 5, 6), QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 8), QTime(12, 13, 14)) + QDateTime(QDate(2023, 5, 8), QTime(12, 13, 14)), ), 4: QgsDateTimeRange( - QDateTime(QDate(2023, 5, 7), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 9), - QTime(12, 13, 14)) + QDateTime(QDate(2023, 5, 7), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 9), QTime(12, 13, 14)), ), 5: QgsDateTimeRange( - QDateTime(QDate(2023, 5, 9), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 11), - QTime(12, 13, 14)) - )} + QDateTime(QDate(2023, 5, 9), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 11), QTime(12, 13, 14)), + ), + } ) map_settings = QgsMapSettings() @@ -498,66 +524,71 @@ def test_render_fixed_range_per_band_with_temporal_range_filter(self): map_settings.setIsTemporal(False) self.assertTrue( self.render_map_settings_check( - 'No temporal range filter on map settings, temporal range per band', - 'elevation_range_per_band_no_filter', - map_settings) + "No temporal range filter on map settings, temporal range per band", + "elevation_range_per_band_no_filter", + map_settings, + ) ) # map settings range matches band 3 only map_settings.setIsTemporal(True) - map_settings.setTemporalRange(QgsDateTimeRange( - QDateTime(QDate(2023, 5, 3), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 6), - QTime(13, 13, 14)) - )) + map_settings.setTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 3), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 6), QTime(13, 13, 14)), + ) + ) self.assertTrue( self.render_map_settings_check( - 'Temporal range filter on map settings matches band 3 only', - 'elevation_range_per_band_match_3', - map_settings) + "Temporal range filter on map settings matches band 3 only", + "elevation_range_per_band_match_3", + map_settings, + ) ) # map settings range matches band 3 and 4, should pick the latest (4) - map_settings.setTemporalRange(QgsDateTimeRange( - QDateTime(QDate(2023, 5, 5), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 8), - QTime(13, 13, 14)) - )) + map_settings.setTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 5), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 8), QTime(13, 13, 14)), + ) + ) self.assertTrue( self.render_map_settings_check( - 'Temporal range filter on map settings matches band 3 and 4', - 'elevation_range_per_band_match_4', - map_settings) + "Temporal range filter on map settings matches band 3 and 4", + "elevation_range_per_band_match_4", + map_settings, + ) ) # map settings range matches band 5 - map_settings.setTemporalRange(QgsDateTimeRange( - QDateTime(QDate(2023, 5, 10), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 15), - QTime(13, 13, 14)) - )) + map_settings.setTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 10), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 15), QTime(13, 13, 14)), + ) + ) self.assertTrue( self.render_map_settings_check( - 'Temporal range filter on map settings matches band 5', - 'elevation_range_per_band_match_5', - map_settings) + "Temporal range filter on map settings matches band 5", + "elevation_range_per_band_match_5", + map_settings, + ) ) # map settings range excludes layer's range - map_settings.setTemporalRange(QgsDateTimeRange( - QDateTime(QDate(2024, 5, 10), - QTime(12, 13, 14)), - QDateTime(QDate(2024, 5, 15), - QTime(13, 13, 14)) - )) + map_settings.setTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2024, 5, 10), QTime(12, 13, 14)), + QDateTime(QDate(2024, 5, 15), QTime(13, 13, 14)), + ) + ) self.assertTrue( self.render_map_settings_check( - 'Temporal range filter on map settings outside of layer band ranges', - 'fixed_elevation_range_excluded', - map_settings) + "Temporal range filter on map settings outside of layer band ranges", + "fixed_elevation_range_excluded", + map_settings, + ) ) def test_render_represents_temporal_values(self): @@ -565,7 +596,7 @@ def test_render_represents_temporal_values(self): Test rendering a raster with its temporal properties' mode set to represents temporal values """ - raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, 'scaleoffset.tif')) + raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, "scaleoffset.tif")) self.assertTrue(raster_layer.isValid()) renderer = QgsSingleBandGrayRenderer(raster_layer.dataProvider(), 1) @@ -577,8 +608,12 @@ def test_render_represents_temporal_values(self): Qgis.RasterTemporalMode.RepresentsTemporalValues ) raster_layer.temporalProperties().setBandNumber(1) - raster_layer.temporalProperties().setTemporalRepresentationOffset(QDateTime(QDate(2024, 1, 1), QTime(0, 0, 0))) - raster_layer.temporalProperties().setTemporalRepresentationScale(QgsInterval(1, Qgis.TemporalUnit.Days)) + raster_layer.temporalProperties().setTemporalRepresentationOffset( + QDateTime(QDate(2024, 1, 1), QTime(0, 0, 0)) + ) + raster_layer.temporalProperties().setTemporalRepresentationScale( + QgsInterval(1, Qgis.TemporalUnit.Days) + ) map_settings = QgsMapSettings() map_settings.setOutputSize(QSize(400, 400)) @@ -591,26 +626,28 @@ def test_render_represents_temporal_values(self): map_settings.setIsTemporal(False) self.assertTrue( self.render_map_settings_check( - 'No temporal range filter on map settings on represents temporal values mode', - 'represents_temporal_values_no_filter', - map_settings) + "No temporal range filter on map settings on represents temporal values mode", + "represents_temporal_values_no_filter", + map_settings, + ) ) # map settings matches part of the overall range map_settings.setIsTemporal(True) - map_settings.setTemporalRange(QgsDateTimeRange( - QDateTime(QDate(2024, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2024, 1, 5), - QTime(23, 59, 59)) - )) + map_settings.setTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2024, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2024, 1, 5), QTime(23, 59, 59)), + ) + ) self.assertTrue( self.render_map_settings_check( - 'Temporal range filter on map settings on represents temporal values mode', - 'represents_temporal_values_filter', - map_settings) + "Temporal range filter on map settings on represents temporal values mode", + "represents_temporal_values_filter", + map_settings, + ) ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterlayertemporalproperties.py b/tests/src/python/test_qgsrasterlayertemporalproperties.py index ac5588cd903c..d362ece86cf8 100644 --- a/tests/src/python/test_qgsrasterlayertemporalproperties.py +++ b/tests/src/python/test_qgsrasterlayertemporalproperties.py @@ -8,18 +8,14 @@ import unittest -from qgis.PyQt.QtCore import ( - QDate, - QTime, - QDateTime -) +from qgis.PyQt.QtCore import QDate, QTime, QDateTime from qgis.PyQt.QtXml import QDomDocument from qgis.core import ( Qgis, QgsInterval, QgsRasterLayerTemporalProperties, QgsReadWriteContext, - QgsDateTimeRange + QgsDateTimeRange, ) from qgis.testing import start_app, QgisTestCase @@ -37,42 +33,75 @@ def test_basic_fixed_range(self): props.setIsActive(True) props.setMode(Qgis.RasterTemporalMode.FixedTemporalRange) - props.setFixedTemporalRange(QgsDateTimeRange( - QDateTime(QDate(2023, 5, 6), QTime(12, 13, 14)), - QDateTime(QDate(2023, 7, 3), QTime(1, 3, 4)))) - self.assertEqual(props.fixedTemporalRange(), - QgsDateTimeRange( - QDateTime(QDate(2023, 5, 6), QTime(12, 13, 14)), - QDateTime(QDate(2023, 7, 3), QTime(1, 3, 4)))) - self.assertFalse(props.isVisibleInTemporalRange(QgsDateTimeRange( - QDateTime(QDate(2022, 5, 6), QTime(12, 13, 14)), - QDateTime(QDate(2022, 7, 3), QTime(1, 3, 4))))) - self.assertTrue(props.isVisibleInTemporalRange(QgsDateTimeRange( - QDateTime(QDate(2023, 1, 6), QTime(12, 13, 14)), - QDateTime(QDate(2023, 6, 3), QTime(1, 3, 4))))) - self.assertTrue(props.isVisibleInTemporalRange(QgsDateTimeRange( - QDateTime(QDate(2023, 6, 6), QTime(12, 13, 14)), - QDateTime(QDate(2023, 9, 3), QTime(1, 3, 4))))) - self.assertFalse(props.isVisibleInTemporalRange(QgsDateTimeRange( - QDateTime(QDate(2024, 5, 6), QTime(12, 13, 14)), - QDateTime(QDate(2024, 7, 3), QTime(1, 3, 4))))) - self.assertEqual(props.allTemporalRanges(None), - [QgsDateTimeRange( - QDateTime(QDate(2023, 5, 6), QTime(12, 13, 14)), - QDateTime(QDate(2023, 7, 3), QTime(1, 3, 4)))]) + props.setFixedTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 6), QTime(12, 13, 14)), + QDateTime(QDate(2023, 7, 3), QTime(1, 3, 4)), + ) + ) + self.assertEqual( + props.fixedTemporalRange(), + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 6), QTime(12, 13, 14)), + QDateTime(QDate(2023, 7, 3), QTime(1, 3, 4)), + ), + ) + self.assertFalse( + props.isVisibleInTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2022, 5, 6), QTime(12, 13, 14)), + QDateTime(QDate(2022, 7, 3), QTime(1, 3, 4)), + ) + ) + ) + self.assertTrue( + props.isVisibleInTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2023, 1, 6), QTime(12, 13, 14)), + QDateTime(QDate(2023, 6, 3), QTime(1, 3, 4)), + ) + ) + ) + self.assertTrue( + props.isVisibleInTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2023, 6, 6), QTime(12, 13, 14)), + QDateTime(QDate(2023, 9, 3), QTime(1, 3, 4)), + ) + ) + ) + self.assertFalse( + props.isVisibleInTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2024, 5, 6), QTime(12, 13, 14)), + QDateTime(QDate(2024, 7, 3), QTime(1, 3, 4)), + ) + ) + ) + self.assertEqual( + props.allTemporalRanges(None), + [ + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 6), QTime(12, 13, 14)), + QDateTime(QDate(2023, 7, 3), QTime(1, 3, 4)), + ) + ], + ) doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsRasterLayerTemporalProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.mode(), - Qgis.RasterElevationMode.FixedElevationRange) - self.assertEqual(props2.fixedTemporalRange(), - QgsDateTimeRange( - QDateTime(QDate(2023, 5, 6), QTime(12, 13, 14)), - QDateTime(QDate(2023, 7, 3), QTime(1, 3, 4)))) + self.assertEqual(props2.mode(), Qgis.RasterElevationMode.FixedElevationRange) + self.assertEqual( + props2.fixedTemporalRange(), + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 6), QTime(12, 13, 14)), + QDateTime(QDate(2023, 7, 3), QTime(1, 3, 4)), + ), + ) def test_basic_fixed_range_per_band(self): """ @@ -83,196 +112,228 @@ def test_basic_fixed_range_per_band(self): self.assertFalse(props.fixedRangePerBand()) props.setMode(Qgis.RasterTemporalMode.FixedRangePerBand) - props.setFixedRangePerBand({ - 1: QgsDateTimeRange( - QDateTime(QDate(2023, 5, 6), QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 8), QTime(12, 13, 14)) + props.setFixedRangePerBand( + { + 1: QgsDateTimeRange( + QDateTime(QDate(2023, 5, 6), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 8), QTime(12, 13, 14)), + ), + 2: QgsDateTimeRange( + QDateTime(QDate(2023, 5, 7), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 9), QTime(12, 13, 14)), + ), + 3: QgsDateTimeRange( + QDateTime(QDate(2023, 5, 9), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 11), QTime(12, 13, 14)), + ), + } + ) + self.assertEqual( + props.fixedRangePerBand(), + { + 1: QgsDateTimeRange( + QDateTime(QDate(2023, 5, 6), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 8), QTime(12, 13, 14)), + ), + 2: QgsDateTimeRange( + QDateTime(QDate(2023, 5, 7), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 9), QTime(12, 13, 14)), + ), + 3: QgsDateTimeRange( + QDateTime(QDate(2023, 5, 9), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 11), QTime(12, 13, 14)), + ), + }, + ) + self.assertFalse( + props.isVisibleInTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 1), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 3), QTime(12, 13, 14)), + ) + ) + ) + self.assertTrue( + props.isVisibleInTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 5), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 7), QTime(12, 13, 14)), + ) + ) + ) + self.assertTrue( + props.isVisibleInTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 8), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 11), QTime(12, 13, 14)), + ) + ) + ) + self.assertTrue( + props.isVisibleInTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 10), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 13), QTime(12, 13, 14)), + ) + ) + ) + self.assertFalse( + props.isVisibleInTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 12), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 14), QTime(12, 13, 14)), + ) + ) + ) + self.assertEqual( + props.allTemporalRanges(None), + [ + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 6), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 8), QTime(12, 13, 14)), + ), + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 7), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 9), QTime(12, 13, 14)), + ), + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 9), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 11), QTime(12, 13, 14)), + ), + ], + ) + + self.assertEqual( + props.bandForTemporalRange( + None, + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 3), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 4), QTime(12, 13, 14)), + ), ), - 2: QgsDateTimeRange( - QDateTime(QDate(2023, 5, 7), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 9), - QTime(12, 13, 14)) + -1, + ) + self.assertEqual( + props.bandForTemporalRange( + None, + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 3), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 6), QTime(12, 14, 14)), + ), ), - 3: QgsDateTimeRange( - QDateTime(QDate(2023, 5, 9), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 11), - QTime(12, 13, 14)) - )}) - self.assertEqual(props.fixedRangePerBand(), - { - 1: QgsDateTimeRange( - QDateTime(QDate(2023, 5, 6), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 8), - QTime(12, 13, 14)) - ), - 2: QgsDateTimeRange( - QDateTime(QDate(2023, 5, 7), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 9), - QTime(12, 13, 14)) - ), - 3: QgsDateTimeRange( - QDateTime(QDate(2023, 5, 9), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 11), - QTime(12, 13, 14)) - )}) - self.assertFalse(props.isVisibleInTemporalRange(QgsDateTimeRange( - QDateTime(QDate(2023, 5, 1), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 3), - QTime(12, 13, 14)) - ))) - self.assertTrue(props.isVisibleInTemporalRange(QgsDateTimeRange( - QDateTime(QDate(2023, 5, 5), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 7), - QTime(12, 13, 14)) - ))) - self.assertTrue(props.isVisibleInTemporalRange(QgsDateTimeRange( - QDateTime(QDate(2023, 5, 8), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 11), - QTime(12, 13, 14)) - ))) - self.assertTrue(props.isVisibleInTemporalRange(QgsDateTimeRange( - QDateTime(QDate(2023, 5, 10), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 13), - QTime(12, 13, 14)) - ))) - self.assertFalse(props.isVisibleInTemporalRange(QgsDateTimeRange( - QDateTime(QDate(2023, 5, 12), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 14), - QTime(12, 13, 14)) - ))) - self.assertEqual(props.allTemporalRanges(None), - [QgsDateTimeRange( - QDateTime(QDate(2023, 5, 6), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 8), - QTime(12, 13, 14)) - ), - QgsDateTimeRange( - QDateTime(QDate(2023, 5, 7), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 9), - QTime(12, 13, 14)) - ), - QgsDateTimeRange( - QDateTime(QDate(2023, 5, 9), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 11), - QTime(12, 13, 14)) - )]) - - self.assertEqual(props.bandForTemporalRange(None, QgsDateTimeRange( - QDateTime(QDate(2023, 5, 3), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 4), - QTime(12, 13, 14)) - )), -1) - self.assertEqual(props.bandForTemporalRange(None, QgsDateTimeRange( - QDateTime(QDate(2023, 5, 3), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 6), - QTime(12, 14, 14)) - )), 1) - self.assertEqual(props.bandForTemporalRange(None, QgsDateTimeRange( - QDateTime(QDate(2023, 5, 3), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 8), - QTime(12, 14, 14)) - )), 2) - self.assertEqual(props.bandForTemporalRange(None, QgsDateTimeRange( - QDateTime(QDate(2023, 5, 10), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 12), - QTime(12, 14, 14)) - )), 3) - self.assertEqual(props.bandForTemporalRange(None, QgsDateTimeRange( - QDateTime(QDate(2023, 5, 13), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 16), - QTime(12, 14, 14)) - )), -1) + 1, + ) + self.assertEqual( + props.bandForTemporalRange( + None, + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 3), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 8), QTime(12, 14, 14)), + ), + ), + 2, + ) + self.assertEqual( + props.bandForTemporalRange( + None, + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 10), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 12), QTime(12, 14, 14)), + ), + ), + 3, + ) + self.assertEqual( + props.bandForTemporalRange( + None, + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 13), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 16), QTime(12, 14, 14)), + ), + ), + -1, + ) doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsRasterLayerTemporalProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.mode(), - Qgis.RasterTemporalMode.FixedRangePerBand) - self.assertEqual(props2.fixedRangePerBand(), - { - 1: QgsDateTimeRange( - QDateTime(QDate(2023, 5, 6), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 8), - QTime(12, 13, 14)) - ), - 2: QgsDateTimeRange( - QDateTime(QDate(2023, 5, 7), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 9), - QTime(12, 13, 14)) - ), - 3: QgsDateTimeRange( - QDateTime(QDate(2023, 5, 9), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 11), - QTime(12, 13, 14)) - )}) + self.assertEqual(props2.mode(), Qgis.RasterTemporalMode.FixedRangePerBand) + self.assertEqual( + props2.fixedRangePerBand(), + { + 1: QgsDateTimeRange( + QDateTime(QDate(2023, 5, 6), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 8), QTime(12, 13, 14)), + ), + 2: QgsDateTimeRange( + QDateTime(QDate(2023, 5, 7), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 9), QTime(12, 13, 14)), + ), + 3: QgsDateTimeRange( + QDateTime(QDate(2023, 5, 9), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 11), QTime(12, 13, 14)), + ), + }, + ) # include lower, exclude upper - props.setFixedRangePerBand({1: QgsDateTimeRange( - QDateTime(QDate(2023, 5, 9), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 11), - QTime(12, 13, 14)), - includeBeginning=True, - includeEnd=False)}) - elem = doc.createElement('test') + props.setFixedRangePerBand( + { + 1: QgsDateTimeRange( + QDateTime(QDate(2023, 5, 9), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 11), QTime(12, 13, 14)), + includeBeginning=True, + includeEnd=False, + ) + } + ) + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsRasterLayerTemporalProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.fixedRangePerBand(), - {1: QgsDateTimeRange( - QDateTime(QDate(2023, 5, 9), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 11), - QTime(12, 13, 14)), - includeBeginning=True, - includeEnd=False)}) + self.assertEqual( + props2.fixedRangePerBand(), + { + 1: QgsDateTimeRange( + QDateTime(QDate(2023, 5, 9), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 11), QTime(12, 13, 14)), + includeBeginning=True, + includeEnd=False, + ) + }, + ) # exclude lower, include upper - props.setFixedRangePerBand({1: QgsDateTimeRange( - QDateTime(QDate(2023, 5, 9), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 11), - QTime(12, 13, 14)), - includeBeginning=False, - includeEnd=True)}) - elem = doc.createElement('test') + props.setFixedRangePerBand( + { + 1: QgsDateTimeRange( + QDateTime(QDate(2023, 5, 9), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 11), QTime(12, 13, 14)), + includeBeginning=False, + includeEnd=True, + ) + } + ) + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsRasterLayerTemporalProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.fixedRangePerBand(), - {1: QgsDateTimeRange( - QDateTime(QDate(2023, 5, 9), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 11), - QTime(12, 13, 14)), - includeBeginning=False, - includeEnd=True)}) + self.assertEqual( + props2.fixedRangePerBand(), + { + 1: QgsDateTimeRange( + QDateTime(QDate(2023, 5, 9), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 11), QTime(12, 13, 14)), + includeBeginning=False, + includeEnd=True, + ) + }, + ) def test_basic_represents_temporal_value(self): """ @@ -280,48 +341,72 @@ def test_basic_represents_temporal_value(self): """ props = QgsRasterLayerTemporalProperties(None) props.setMode(Qgis.RasterTemporalMode.RepresentsTemporalValues) - self.assertEqual(props.mode(), - Qgis.RasterTemporalMode.RepresentsTemporalValues) + self.assertEqual(props.mode(), Qgis.RasterTemporalMode.RepresentsTemporalValues) self.assertEqual(props.bandNumber(), 1) - self.assertEqual(props.temporalRepresentationScale(), QgsInterval(1, Qgis.TemporalUnit.Days)) + self.assertEqual( + props.temporalRepresentationScale(), QgsInterval(1, Qgis.TemporalUnit.Days) + ) self.assertEqual(props.temporalRepresentationOffset(), QDateTime()) self.assertFalse(props.isActive()) props.setBandNumber(2) props.setTemporalRepresentationScale(QgsInterval(2.5, Qgis.TemporalUnit.Weeks)) - props.setTemporalRepresentationOffset(QDateTime(QDate(2024, 1, 1), QTime(0, 0, 0))) + props.setTemporalRepresentationOffset( + QDateTime(QDate(2024, 1, 1), QTime(0, 0, 0)) + ) props.setIsActive(True) self.assertEqual(props.bandNumber(), 2) - self.assertEqual(props.temporalRepresentationScale(), QgsInterval(2.5, Qgis.TemporalUnit.Weeks)) - self.assertEqual(props.temporalRepresentationOffset(), QDateTime(QDate(2024, 1, 1), QTime(0, 0, 0))) + self.assertEqual( + props.temporalRepresentationScale(), + QgsInterval(2.5, Qgis.TemporalUnit.Weeks), + ) + self.assertEqual( + props.temporalRepresentationOffset(), + QDateTime(QDate(2024, 1, 1), QTime(0, 0, 0)), + ) self.assertTrue(props.isActive()) - self.assertEqual(props.bandForTemporalRange(None, QgsDateTimeRange( - QDateTime(QDate(2023, 5, 3), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 4), - QTime(12, 13, 14)) - )), 2) - self.assertEqual(props.filteredBandsForTemporalRange(None, QgsDateTimeRange( - QDateTime(QDate(2023, 5, 3), - QTime(12, 13, 14)), - QDateTime(QDate(2023, 5, 4), - QTime(12, 13, 14)) - )), [2]) + self.assertEqual( + props.bandForTemporalRange( + None, + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 3), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 4), QTime(12, 13, 14)), + ), + ), + 2, + ) + self.assertEqual( + props.filteredBandsForTemporalRange( + None, + QgsDateTimeRange( + QDateTime(QDate(2023, 5, 3), QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 4), QTime(12, 13, 14)), + ), + ), + [2], + ) doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsRasterLayerTemporalProperties(None) props2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(props2.mode(), - Qgis.RasterTemporalMode.RepresentsTemporalValues) + self.assertEqual( + props2.mode(), Qgis.RasterTemporalMode.RepresentsTemporalValues + ) self.assertEqual(props.bandNumber(), 2) - self.assertEqual(props2.temporalRepresentationScale(), QgsInterval(2.5, Qgis.TemporalUnit.Weeks)) - self.assertEqual(props2.temporalRepresentationOffset(), QDateTime(QDate(2024, 1, 1), QTime(0, 0, 0))) + self.assertEqual( + props2.temporalRepresentationScale(), + QgsInterval(2.5, Qgis.TemporalUnit.Weeks), + ) + self.assertEqual( + props2.temporalRepresentationOffset(), + QDateTime(QDate(2024, 1, 1), QTime(0, 0, 0)), + ) self.assertTrue(props2.isActive()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterlayerutils.py b/tests/src/python/test_qgsrasterlayerutils.py index 4b4b47fc061c..6b262983b8bd 100644 --- a/tests/src/python/test_qgsrasterlayerutils.py +++ b/tests/src/python/test_qgsrasterlayerutils.py @@ -8,17 +8,13 @@ import os -from qgis.PyQt.QtCore import ( - QDate, - QTime, - QDateTime -) +from qgis.PyQt.QtCore import QDate, QTime, QDateTime from qgis.core import ( Qgis, QgsRasterLayerUtils, QgsRasterLayer, QgsDoubleRange, - QgsDateTimeRange + QgsDateTimeRange, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -34,19 +30,17 @@ class TestQgsRasterLayerUtils(QgisTestCase): def test_rendered_band_for_elevation_and_temporal_ranges(self): - raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, 'landsat_4326.tif')) + raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, "landsat_4326.tif")) self.assertTrue(raster_layer.isValid()) # no temporal or elevation properties band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2023, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2023, 12, 31), - QTime(23, 59, 59)) + QDateTime(QDate(2023, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2023, 12, 31), QTime(23, 59, 59)), ), - QgsDoubleRange(30, 50) + QgsDoubleRange(30, 50), ) self.assertEqual(band, -1) self.assertTrue(matched) @@ -57,27 +51,26 @@ def test_rendered_band_for_elevation_and_temporal_ranges(self): Qgis.RasterElevationMode.FixedRangePerBand ) raster_layer.elevationProperties().setFixedRangePerBand( - {1: QgsDoubleRange(1, 5), - 2: QgsDoubleRange(4, 10), - 3: QgsDoubleRange(11, 15), - 4: QgsDoubleRange(1, 5), - 5: QgsDoubleRange(4, 10), - 6: QgsDoubleRange(11, 16), - 7: QgsDoubleRange(1, 5), - 8: QgsDoubleRange(4, 10), - 9: QgsDoubleRange(11, 15), - } + { + 1: QgsDoubleRange(1, 5), + 2: QgsDoubleRange(4, 10), + 3: QgsDoubleRange(11, 15), + 4: QgsDoubleRange(1, 5), + 5: QgsDoubleRange(4, 10), + 6: QgsDoubleRange(11, 16), + 7: QgsDoubleRange(1, 5), + 8: QgsDoubleRange(4, 10), + 9: QgsDoubleRange(11, 15), + } ) # no matching elevation band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2023, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2023, 12, 31), - QTime(23, 59, 59)) + QDateTime(QDate(2023, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2023, 12, 31), QTime(23, 59, 59)), ), - QgsDoubleRange(30, 50) + QgsDoubleRange(30, 50), ) self.assertEqual(band, -1) self.assertFalse(matched) @@ -85,24 +78,20 @@ def test_rendered_band_for_elevation_and_temporal_ranges(self): band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2023, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2023, 12, 31), - QTime(23, 59, 59)) + QDateTime(QDate(2023, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2023, 12, 31), QTime(23, 59, 59)), ), - QgsDoubleRange(1, 3) + QgsDoubleRange(1, 3), ) self.assertEqual(band, 7) self.assertTrue(matched) band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2023, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2023, 12, 31), - QTime(23, 59, 59)) + QDateTime(QDate(2023, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2023, 12, 31), QTime(23, 59, 59)), ), - QgsDoubleRange(5, 8) + QgsDoubleRange(5, 8), ) self.assertEqual(band, 8) self.assertTrue(matched) @@ -111,12 +100,10 @@ def test_rendered_band_for_elevation_and_temporal_ranges(self): band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2023, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2023, 12, 31), - QTime(23, 59, 59)) + QDateTime(QDate(2023, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2023, 12, 31), QTime(23, 59, 59)), ), - QgsDoubleRange() + QgsDoubleRange(), ) self.assertEqual(band, -1) self.assertTrue(matched) @@ -130,59 +117,41 @@ def test_rendered_band_for_elevation_and_temporal_ranges(self): raster_layer.temporalProperties().setFixedRangePerBand( { 1: QgsDateTimeRange( - QDateTime(QDate(2020, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2020, 12, 31), - QTime(23, 59, 59)) + QDateTime(QDate(2020, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2020, 12, 31), QTime(23, 59, 59)), ), 2: QgsDateTimeRange( - QDateTime(QDate(2020, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2020, 12, 31), - QTime(23, 59, 59)) + QDateTime(QDate(2020, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2020, 12, 31), QTime(23, 59, 59)), ), 3: QgsDateTimeRange( - QDateTime(QDate(2020, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2020, 12, 31), - QTime(23, 59, 59)) + QDateTime(QDate(2020, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2020, 12, 31), QTime(23, 59, 59)), ), 4: QgsDateTimeRange( - QDateTime(QDate(2021, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2021, 12, 31), - QTime(23, 59, 59)) + QDateTime(QDate(2021, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2021, 12, 31), QTime(23, 59, 59)), ), 5: QgsDateTimeRange( - QDateTime(QDate(2021, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2021, 12, 31), - QTime(23, 59, 59)) + QDateTime(QDate(2021, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2021, 12, 31), QTime(23, 59, 59)), ), 6: QgsDateTimeRange( - QDateTime(QDate(2021, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2021, 12, 31), - QTime(23, 59, 59)) + QDateTime(QDate(2021, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2021, 12, 31), QTime(23, 59, 59)), ), 7: QgsDateTimeRange( - QDateTime(QDate(2022, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2022, 12, 31), - QTime(23, 59, 59)) + QDateTime(QDate(2022, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2022, 12, 31), QTime(23, 59, 59)), ), 8: QgsDateTimeRange( - QDateTime(QDate(2022, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2022, 12, 31), - QTime(23, 59, 59)) + QDateTime(QDate(2022, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2022, 12, 31), QTime(23, 59, 59)), ), 9: QgsDateTimeRange( - QDateTime(QDate(2022, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2022, 12, 31), - QTime(23, 59, 59)) - ) + QDateTime(QDate(2022, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2022, 12, 31), QTime(23, 59, 59)), + ), } ) @@ -190,12 +159,10 @@ def test_rendered_band_for_elevation_and_temporal_ranges(self): band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2023, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2023, 12, 31), - QTime(23, 59, 59)) + QDateTime(QDate(2023, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2023, 12, 31), QTime(23, 59, 59)), ), - QgsDoubleRange(30, 50) + QgsDoubleRange(30, 50), ) self.assertEqual(band, -1) self.assertFalse(matched) @@ -203,24 +170,20 @@ def test_rendered_band_for_elevation_and_temporal_ranges(self): band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2020, 1, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2020, 6, 30), - QTime(23, 59, 59)) + QDateTime(QDate(2020, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2020, 6, 30), QTime(23, 59, 59)), ), - QgsDoubleRange(1, 3) + QgsDoubleRange(1, 3), ) self.assertEqual(band, 3) self.assertTrue(matched) band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2020, 6, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2021, 6, 30), - QTime(23, 59, 59)) + QDateTime(QDate(2020, 6, 1), QTime(0, 0, 0)), + QDateTime(QDate(2021, 6, 30), QTime(23, 59, 59)), ), - QgsDoubleRange(5, 8) + QgsDoubleRange(5, 8), ) self.assertEqual(band, 6) self.assertTrue(matched) @@ -229,7 +192,7 @@ def test_rendered_band_for_elevation_and_temporal_ranges(self): band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange(QDateTime(), QDateTime()), - QgsDoubleRange(5, 8) + QgsDoubleRange(5, 8), ) self.assertEqual(band, -1) self.assertTrue(matched) @@ -241,7 +204,7 @@ def test_rendered_band_for_elevation_and_temporal_ranges(self): band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange(QDateTime(), QDateTime()), - QgsDoubleRange(5, 8) + QgsDoubleRange(5, 8), ) self.assertEqual(band, 8) self.assertTrue(matched) @@ -250,11 +213,10 @@ def test_rendered_band_for_elevation_and_temporal_ranges(self): band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2020, 6, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2021, 6, 30), - QTime(23, 59, 59))), - QgsDoubleRange() + QDateTime(QDate(2020, 6, 1), QTime(0, 0, 0)), + QDateTime(QDate(2021, 6, 30), QTime(23, 59, 59)), + ), + QgsDoubleRange(), ) self.assertEqual(band, 6) self.assertTrue(matched) @@ -262,34 +224,30 @@ def test_rendered_band_for_elevation_and_temporal_ranges(self): band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2020, 6, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2020, 6, 30), - QTime(23, 59, 59))), - QgsDoubleRange(2, 3) + QDateTime(QDate(2020, 6, 1), QTime(0, 0, 0)), + QDateTime(QDate(2020, 6, 30), QTime(23, 59, 59)), + ), + QgsDoubleRange(2, 3), ) self.assertEqual(band, 1) self.assertTrue(matched) band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2020, 6, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2020, 6, 30), - QTime(23, 59, 59))), - QgsDoubleRange(3, 7) + QDateTime(QDate(2020, 6, 1), QTime(0, 0, 0)), + QDateTime(QDate(2020, 6, 30), QTime(23, 59, 59)), + ), + QgsDoubleRange(3, 7), ) self.assertEqual(band, 2) self.assertTrue(matched) band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2020, 6, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2020, 6, 30), - QTime(23, 59, 59))), - QgsDoubleRange(11, - 13) + QDateTime(QDate(2020, 6, 1), QTime(0, 0, 0)), + QDateTime(QDate(2020, 6, 30), QTime(23, 59, 59)), + ), + QgsDoubleRange(11, 13), ) self.assertEqual(band, 3) self.assertTrue(matched) @@ -297,34 +255,30 @@ def test_rendered_band_for_elevation_and_temporal_ranges(self): band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2021, 6, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2021, 6, 30), - QTime(23, 59, 59))), - QgsDoubleRange(2, 3) + QDateTime(QDate(2021, 6, 1), QTime(0, 0, 0)), + QDateTime(QDate(2021, 6, 30), QTime(23, 59, 59)), + ), + QgsDoubleRange(2, 3), ) self.assertEqual(band, 4) self.assertTrue(matched) band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2021, 6, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2021, 6, 30), - QTime(23, 59, 59))), - QgsDoubleRange(3, 7) + QDateTime(QDate(2021, 6, 1), QTime(0, 0, 0)), + QDateTime(QDate(2021, 6, 30), QTime(23, 59, 59)), + ), + QgsDoubleRange(3, 7), ) self.assertEqual(band, 5) self.assertTrue(matched) band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2021, 6, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2021, 6, 30), - QTime(23, 59, 59))), - QgsDoubleRange(11, - 13) + QDateTime(QDate(2021, 6, 1), QTime(0, 0, 0)), + QDateTime(QDate(2021, 6, 30), QTime(23, 59, 59)), + ), + QgsDoubleRange(11, 13), ) self.assertEqual(band, 6) self.assertTrue(matched) @@ -332,34 +286,30 @@ def test_rendered_band_for_elevation_and_temporal_ranges(self): band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2022, 6, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2022, 6, 30), - QTime(23, 59, 59))), - QgsDoubleRange(2, 3) + QDateTime(QDate(2022, 6, 1), QTime(0, 0, 0)), + QDateTime(QDate(2022, 6, 30), QTime(23, 59, 59)), + ), + QgsDoubleRange(2, 3), ) self.assertEqual(band, 7) self.assertTrue(matched) band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2022, 6, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2022, 6, 30), - QTime(23, 59, 59))), - QgsDoubleRange(3, 7) + QDateTime(QDate(2022, 6, 1), QTime(0, 0, 0)), + QDateTime(QDate(2022, 6, 30), QTime(23, 59, 59)), + ), + QgsDoubleRange(3, 7), ) self.assertEqual(band, 8) self.assertTrue(matched) band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2022, 6, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2022, 6, 30), - QTime(23, 59, 59))), - QgsDoubleRange(11, - 13) + QDateTime(QDate(2022, 6, 1), QTime(0, 0, 0)), + QDateTime(QDate(2022, 6, 30), QTime(23, 59, 59)), + ), + QgsDoubleRange(11, 13), ) self.assertEqual(band, 9) self.assertTrue(matched) @@ -368,12 +318,10 @@ def test_rendered_band_for_elevation_and_temporal_ranges(self): band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2023, 6, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2023, 6, 30), - QTime(23, 59, 59))), - QgsDoubleRange(11, - 13) + QDateTime(QDate(2023, 6, 1), QTime(0, 0, 0)), + QDateTime(QDate(2023, 6, 30), QTime(23, 59, 59)), + ), + QgsDoubleRange(11, 13), ) self.assertEqual(band, -1) self.assertFalse(matched) @@ -382,16 +330,14 @@ def test_rendered_band_for_elevation_and_temporal_ranges(self): band, matched = QgsRasterLayerUtils.renderedBandForElevationAndTemporalRange( raster_layer, QgsDateTimeRange( - QDateTime(QDate(2022, 6, 1), - QTime(0, 0, 0)), - QDateTime(QDate(2022, 6, 30), - QTime(23, 59, 59))), - QgsDoubleRange(111, - 113) + QDateTime(QDate(2022, 6, 1), QTime(0, 0, 0)), + QDateTime(QDate(2022, 6, 30), QTime(23, 59, 59)), + ), + QgsDoubleRange(111, 113), ) self.assertEqual(band, -1) self.assertFalse(matched) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterlinesymbollayer.py b/tests/src/python/test_qgsrasterlinesymbollayer.py index 948970527f93..71d469ace4c8 100644 --- a/tests/src/python/test_qgsrasterlinesymbollayer.py +++ b/tests/src/python/test_qgsrasterlinesymbollayer.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'March 2019' -__copyright__ = '(C) 2019, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "March 2019" +__copyright__ = "(C) 2019, Nyall Dawson" from qgis.PyQt.QtCore import Qt @@ -50,132 +50,158 @@ def testRender(self): s.deleteSymbolLayer(0) raster_line = QgsRasterLineSymbolLayer() - raster_line.setPath(TEST_DATA_DIR + '/raster_brush.png') + raster_line.setPath(TEST_DATA_DIR + "/raster_brush.png") raster_line.setWidth(8) s.appendSymbolLayer(raster_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) - self.assertTrue(self.image_check('rasterline_render', 'rasterline_render', rendered_image)) + self.assertTrue( + self.image_check("rasterline_render", "rasterline_render", rendered_image) + ) def testRenderHairline(self): s = QgsLineSymbol() s.deleteSymbolLayer(0) raster_line = QgsRasterLineSymbolLayer() - raster_line.setPath(TEST_DATA_DIR + '/raster_brush.png') + raster_line.setPath(TEST_DATA_DIR + "/raster_brush.png") raster_line.setWidth(0) s.appendSymbolLayer(raster_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) - self.assertTrue(self.image_check('rasterline_hairline', 'rasterline_hairline', rendered_image)) + self.assertTrue( + self.image_check( + "rasterline_hairline", "rasterline_hairline", rendered_image + ) + ) def testRenderClosedRing(self): s = QgsLineSymbol() s.deleteSymbolLayer(0) raster_line = QgsRasterLineSymbolLayer() - raster_line.setPath(TEST_DATA_DIR + '/raster_brush.png') + raster_line.setPath(TEST_DATA_DIR + "/raster_brush.png") raster_line.setWidth(8) s.appendSymbolLayer(raster_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10, 0 10, 0 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 0, 10 10, 0 10, 0 0)") rendered_image = self.renderGeometry(s, g) - self.assertTrue(self.image_check('rasterline_closed', 'rasterline_closed', rendered_image)) + self.assertTrue( + self.image_check("rasterline_closed", "rasterline_closed", rendered_image) + ) def testRenderOpacity(self): s = QgsLineSymbol() s.deleteSymbolLayer(0) raster_line = QgsRasterLineSymbolLayer() - raster_line.setPath(TEST_DATA_DIR + '/raster_brush.png') + raster_line.setPath(TEST_DATA_DIR + "/raster_brush.png") raster_line.setWidth(8) raster_line.setOpacity(0.5) s.appendSymbolLayer(raster_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) - self.assertTrue(self.image_check('rasterline_opacity', 'rasterline_opacity', rendered_image)) + self.assertTrue( + self.image_check("rasterline_opacity", "rasterline_opacity", rendered_image) + ) def testRenderFlatCap(self): s = QgsLineSymbol() s.deleteSymbolLayer(0) raster_line = QgsRasterLineSymbolLayer() - raster_line.setPath(TEST_DATA_DIR + '/raster_brush.png') + raster_line.setPath(TEST_DATA_DIR + "/raster_brush.png") raster_line.setWidth(15) raster_line.setPenCapStyle(Qt.PenCapStyle.FlatCap) s.appendSymbolLayer(raster_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) - self.assertTrue(self.image_check('rasterline_flatcap', 'rasterline_flatcap', rendered_image)) + self.assertTrue( + self.image_check("rasterline_flatcap", "rasterline_flatcap", rendered_image) + ) def testRenderSquareCap(self): s = QgsLineSymbol() s.deleteSymbolLayer(0) raster_line = QgsRasterLineSymbolLayer() - raster_line.setPath(TEST_DATA_DIR + '/raster_brush.png') + raster_line.setPath(TEST_DATA_DIR + "/raster_brush.png") raster_line.setWidth(15) raster_line.setPenCapStyle(Qt.PenCapStyle.SquareCap) s.appendSymbolLayer(raster_line.clone()) - g = QgsGeometry.fromWkt('LineString(2 2, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(2 2, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) - self.assertTrue(self.image_check('rasterline_squarecap', 'rasterline_squarecap', rendered_image)) + self.assertTrue( + self.image_check( + "rasterline_squarecap", "rasterline_squarecap", rendered_image + ) + ) def testRenderMiterJoin(self): s = QgsLineSymbol() s.deleteSymbolLayer(0) raster_line = QgsRasterLineSymbolLayer() - raster_line.setPath(TEST_DATA_DIR + '/raster_brush.png') + raster_line.setPath(TEST_DATA_DIR + "/raster_brush.png") raster_line.setWidth(15) raster_line.setPenJoinStyle(Qt.PenJoinStyle.MiterJoin) s.appendSymbolLayer(raster_line.clone()) - g = QgsGeometry.fromWkt('LineString(0 15, 0 0, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(0 15, 0 0, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) - self.assertTrue(self.image_check('rasterline_miterjoin', 'rasterline_miterjoin', rendered_image)) + self.assertTrue( + self.image_check( + "rasterline_miterjoin", "rasterline_miterjoin", rendered_image + ) + ) def testRenderBevelJoin(self): s = QgsLineSymbol() s.deleteSymbolLayer(0) raster_line = QgsRasterLineSymbolLayer() - raster_line.setPath(TEST_DATA_DIR + '/raster_brush.png') + raster_line.setPath(TEST_DATA_DIR + "/raster_brush.png") raster_line.setWidth(15) raster_line.setPenJoinStyle(Qt.PenJoinStyle.BevelJoin) s.appendSymbolLayer(raster_line.clone()) - g = QgsGeometry.fromWkt('LineString(2 2, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(2 2, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) - self.assertTrue(self.image_check('rasterline_beveljoin', 'rasterline_beveljoin', rendered_image)) + self.assertTrue( + self.image_check( + "rasterline_beveljoin", "rasterline_beveljoin", rendered_image + ) + ) def testLineOffset(self): s = QgsLineSymbol() s.deleteSymbolLayer(0) raster_line = QgsRasterLineSymbolLayer() - raster_line.setPath(TEST_DATA_DIR + '/raster_brush.png') + raster_line.setPath(TEST_DATA_DIR + "/raster_brush.png") raster_line.setWidth(5) raster_line.setOffset(5) s.appendSymbolLayer(raster_line.clone()) - g = QgsGeometry.fromWkt('LineString(2 2, 10 10, 10 0)') + g = QgsGeometry.fromWkt("LineString(2 2, 10 10, 10 0)") rendered_image = self.renderGeometry(s, g) - self.assertTrue(self.image_check('rasterline_offset', 'rasterline_offset', rendered_image)) + self.assertTrue( + self.image_check("rasterline_offset", "rasterline_offset", rendered_image) + ) def renderGeometry(self, symbol, geom, buffer=20): f = QgsFeature() @@ -211,5 +237,5 @@ def renderGeometry(self, symbol, geom, buffer=20): return image -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterpipe.py b/tests/src/python/test_qgsrasterpipe.py index c877e87340f9..e7ecd1e716c6 100644 --- a/tests/src/python/test_qgsrasterpipe.py +++ b/tests/src/python/test_qgsrasterpipe.py @@ -18,9 +18,9 @@ """ -__author__ = 'Nyall Dawson' -__date__ = 'June 2021' -__copyright__ = '(C) 2021, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "June 2021" +__copyright__ = "(C) 2021, Nyall Dawson" from qgis.core import ( QgsExpressionContext, @@ -44,9 +44,15 @@ class TestQgsRasterPipe(QgisTestCase): def test_data_defined_properties(self): pipe = QgsRasterPipe() - pipe.dataDefinedProperties().setProperty(QgsRasterPipe.Property.RendererOpacity, QgsProperty.fromExpression('100/2')) - self.assertEqual(pipe.dataDefinedProperties().property(QgsRasterPipe.Property.RendererOpacity), - QgsProperty.fromExpression('100/2')) + pipe.dataDefinedProperties().setProperty( + QgsRasterPipe.Property.RendererOpacity, QgsProperty.fromExpression("100/2") + ) + self.assertEqual( + pipe.dataDefinedProperties().property( + QgsRasterPipe.Property.RendererOpacity + ), + QgsProperty.fromExpression("100/2"), + ) pipe.set(QgsSingleBandPseudoColorRenderer(None)) self.assertTrue(pipe.renderer()) @@ -57,5 +63,5 @@ def test_data_defined_properties(self): self.assertEqual(pipe.renderer().opacity(), 0.5) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterrange.py b/tests/src/python/test_qgsrasterrange.py index 52c88c68c0a7..b3091f79235c 100644 --- a/tests/src/python/test_qgsrasterrange.py +++ b/tests/src/python/test_qgsrasterrange.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '07/06/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "07/06/2018" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.core import QgsRasterRange @@ -131,25 +132,39 @@ def testOverlaps(self): self.assertTrue(range.overlaps(QgsRasterRange(-1, 0))) self.assertFalse(range.overlaps(QgsRasterRange(-10, -1))) self.assertFalse(range.overlaps(QgsRasterRange(11, 12))) - self.assertTrue(range.overlaps(QgsRasterRange(-1, float('NaN')))) - self.assertTrue(range.overlaps(QgsRasterRange(0, float('NaN')))) - self.assertTrue(range.overlaps(QgsRasterRange(1, float('NaN')))) - self.assertTrue(range.overlaps(QgsRasterRange(10, float('NaN')))) - self.assertFalse(range.overlaps(QgsRasterRange(11, float('NaN')))) - self.assertFalse(range.overlaps(QgsRasterRange(float('NaN'), -1))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 0))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 1))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 10))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 11))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), float('NaN')))) - self.assertFalse(range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.Exclusive))) - self.assertFalse(range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMin))) - self.assertTrue(range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMax))) - self.assertFalse(range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.Exclusive))) - self.assertTrue(range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMin))) - self.assertFalse(range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMax))) + self.assertTrue(range.overlaps(QgsRasterRange(-1, float("NaN")))) + self.assertTrue(range.overlaps(QgsRasterRange(0, float("NaN")))) + self.assertTrue(range.overlaps(QgsRasterRange(1, float("NaN")))) + self.assertTrue(range.overlaps(QgsRasterRange(10, float("NaN")))) + self.assertFalse(range.overlaps(QgsRasterRange(11, float("NaN")))) + self.assertFalse(range.overlaps(QgsRasterRange(float("NaN"), -1))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 0))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 1))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 10))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 11))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), float("NaN")))) + self.assertFalse( + range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.Exclusive)) + ) + self.assertFalse( + range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMin)) + ) + self.assertTrue( + range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMax)) + ) + self.assertFalse( + range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.Exclusive)) + ) + self.assertTrue( + range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMin)) + ) + self.assertFalse( + range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMax)) + ) - range = QgsRasterRange(float('NaN'), 10, QgsRasterRange.BoundsType.IncludeMinAndMax) + range = QgsRasterRange( + float("NaN"), 10, QgsRasterRange.BoundsType.IncludeMinAndMax + ) self.assertTrue(range.overlaps(QgsRasterRange(1, 9))) self.assertTrue(range.overlaps(QgsRasterRange(1, 10))) self.assertTrue(range.overlaps(QgsRasterRange(1, 11))) @@ -164,25 +179,39 @@ def testOverlaps(self): self.assertTrue(range.overlaps(QgsRasterRange(-1, 0))) self.assertTrue(range.overlaps(QgsRasterRange(-10, -1))) self.assertFalse(range.overlaps(QgsRasterRange(11, 12))) - self.assertTrue(range.overlaps(QgsRasterRange(-1, float('NaN')))) - self.assertTrue(range.overlaps(QgsRasterRange(0, float('NaN')))) - self.assertTrue(range.overlaps(QgsRasterRange(1, float('NaN')))) - self.assertTrue(range.overlaps(QgsRasterRange(10, float('NaN')))) - self.assertFalse(range.overlaps(QgsRasterRange(11, float('NaN')))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), -1))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 0))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 1))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 10))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 11))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), float('NaN')))) - self.assertTrue(range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.Exclusive))) - self.assertTrue(range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMin))) - self.assertTrue(range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMax))) - self.assertFalse(range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.Exclusive))) - self.assertTrue(range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMin))) - self.assertFalse(range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMax))) + self.assertTrue(range.overlaps(QgsRasterRange(-1, float("NaN")))) + self.assertTrue(range.overlaps(QgsRasterRange(0, float("NaN")))) + self.assertTrue(range.overlaps(QgsRasterRange(1, float("NaN")))) + self.assertTrue(range.overlaps(QgsRasterRange(10, float("NaN")))) + self.assertFalse(range.overlaps(QgsRasterRange(11, float("NaN")))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), -1))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 0))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 1))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 10))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 11))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), float("NaN")))) + self.assertTrue( + range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.Exclusive)) + ) + self.assertTrue( + range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMin)) + ) + self.assertTrue( + range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMax)) + ) + self.assertFalse( + range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.Exclusive)) + ) + self.assertTrue( + range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMin)) + ) + self.assertFalse( + range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMax)) + ) - range = QgsRasterRange(0, float('NaN'), QgsRasterRange.BoundsType.IncludeMinAndMax) + range = QgsRasterRange( + 0, float("NaN"), QgsRasterRange.BoundsType.IncludeMinAndMax + ) self.assertTrue(range.overlaps(QgsRasterRange(1, 9))) self.assertTrue(range.overlaps(QgsRasterRange(1, 10))) self.assertTrue(range.overlaps(QgsRasterRange(1, 11))) @@ -197,23 +226,35 @@ def testOverlaps(self): self.assertTrue(range.overlaps(QgsRasterRange(-1, 0))) self.assertFalse(range.overlaps(QgsRasterRange(-10, -1))) self.assertTrue(range.overlaps(QgsRasterRange(11, 12))) - self.assertTrue(range.overlaps(QgsRasterRange(-1, float('NaN')))) - self.assertTrue(range.overlaps(QgsRasterRange(0, float('NaN')))) - self.assertTrue(range.overlaps(QgsRasterRange(1, float('NaN')))) - self.assertTrue(range.overlaps(QgsRasterRange(10, float('NaN')))) - self.assertTrue(range.overlaps(QgsRasterRange(11, float('NaN')))) - self.assertFalse(range.overlaps(QgsRasterRange(float('NaN'), -1))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 0))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 1))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 10))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 11))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), float('NaN')))) - self.assertFalse(range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.Exclusive))) - self.assertFalse(range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMin))) - self.assertTrue(range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMax))) - self.assertTrue(range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.Exclusive))) - self.assertTrue(range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMin))) - self.assertTrue(range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMax))) + self.assertTrue(range.overlaps(QgsRasterRange(-1, float("NaN")))) + self.assertTrue(range.overlaps(QgsRasterRange(0, float("NaN")))) + self.assertTrue(range.overlaps(QgsRasterRange(1, float("NaN")))) + self.assertTrue(range.overlaps(QgsRasterRange(10, float("NaN")))) + self.assertTrue(range.overlaps(QgsRasterRange(11, float("NaN")))) + self.assertFalse(range.overlaps(QgsRasterRange(float("NaN"), -1))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 0))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 1))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 10))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 11))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), float("NaN")))) + self.assertFalse( + range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.Exclusive)) + ) + self.assertFalse( + range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMin)) + ) + self.assertTrue( + range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMax)) + ) + self.assertTrue( + range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.Exclusive)) + ) + self.assertTrue( + range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMin)) + ) + self.assertTrue( + range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMax)) + ) # includes left end range = QgsRasterRange(0, 10, QgsRasterRange.BoundsType.IncludeMin) @@ -231,23 +272,35 @@ def testOverlaps(self): self.assertTrue(range.overlaps(QgsRasterRange(-1, 0))) self.assertFalse(range.overlaps(QgsRasterRange(-10, -1))) self.assertFalse(range.overlaps(QgsRasterRange(11, 12))) - self.assertTrue(range.overlaps(QgsRasterRange(-1, float('NaN')))) - self.assertTrue(range.overlaps(QgsRasterRange(0, float('NaN')))) - self.assertTrue(range.overlaps(QgsRasterRange(1, float('NaN')))) - self.assertFalse(range.overlaps(QgsRasterRange(10, float('NaN')))) - self.assertFalse(range.overlaps(QgsRasterRange(11, float('NaN')))) - self.assertFalse(range.overlaps(QgsRasterRange(float('NaN'), -1))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 0))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 1))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 10))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 11))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), float('NaN')))) - self.assertFalse(range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.Exclusive))) - self.assertFalse(range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMin))) - self.assertTrue(range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMax))) - self.assertFalse(range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.Exclusive))) - self.assertFalse(range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMin))) - self.assertFalse(range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMax))) + self.assertTrue(range.overlaps(QgsRasterRange(-1, float("NaN")))) + self.assertTrue(range.overlaps(QgsRasterRange(0, float("NaN")))) + self.assertTrue(range.overlaps(QgsRasterRange(1, float("NaN")))) + self.assertFalse(range.overlaps(QgsRasterRange(10, float("NaN")))) + self.assertFalse(range.overlaps(QgsRasterRange(11, float("NaN")))) + self.assertFalse(range.overlaps(QgsRasterRange(float("NaN"), -1))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 0))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 1))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 10))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 11))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), float("NaN")))) + self.assertFalse( + range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.Exclusive)) + ) + self.assertFalse( + range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMin)) + ) + self.assertTrue( + range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMax)) + ) + self.assertFalse( + range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.Exclusive)) + ) + self.assertFalse( + range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMin)) + ) + self.assertFalse( + range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMax)) + ) # includes right end range = QgsRasterRange(0, 10, QgsRasterRange.BoundsType.IncludeMax) @@ -265,23 +318,35 @@ def testOverlaps(self): self.assertFalse(range.overlaps(QgsRasterRange(-1, 0))) self.assertFalse(range.overlaps(QgsRasterRange(-10, -1))) self.assertFalse(range.overlaps(QgsRasterRange(11, 12))) - self.assertTrue(range.overlaps(QgsRasterRange(-1, float('NaN')))) + self.assertTrue(range.overlaps(QgsRasterRange(-1, float("NaN")))) self.assertTrue(range.overlaps(QgsRasterRange(0, 50))) - self.assertTrue(range.overlaps(QgsRasterRange(1, float('NaN')))) - self.assertTrue(range.overlaps(QgsRasterRange(10, float('NaN')))) - self.assertFalse(range.overlaps(QgsRasterRange(11, float('NaN')))) - self.assertFalse(range.overlaps(QgsRasterRange(float('NaN'), -1))) - self.assertFalse(range.overlaps(QgsRasterRange(float('NaN'), 0))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 1))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 10))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 11))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), float('NaN')))) - self.assertFalse(range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.Exclusive))) - self.assertFalse(range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMin))) - self.assertFalse(range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMax))) - self.assertFalse(range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.Exclusive))) - self.assertTrue(range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMin))) - self.assertFalse(range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMax))) + self.assertTrue(range.overlaps(QgsRasterRange(1, float("NaN")))) + self.assertTrue(range.overlaps(QgsRasterRange(10, float("NaN")))) + self.assertFalse(range.overlaps(QgsRasterRange(11, float("NaN")))) + self.assertFalse(range.overlaps(QgsRasterRange(float("NaN"), -1))) + self.assertFalse(range.overlaps(QgsRasterRange(float("NaN"), 0))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 1))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 10))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 11))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), float("NaN")))) + self.assertFalse( + range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.Exclusive)) + ) + self.assertFalse( + range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMin)) + ) + self.assertFalse( + range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMax)) + ) + self.assertFalse( + range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.Exclusive)) + ) + self.assertTrue( + range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMin)) + ) + self.assertFalse( + range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMax)) + ) # includes neither end range = QgsRasterRange(0, 10, QgsRasterRange.BoundsType.Exclusive) @@ -298,41 +363,112 @@ def testOverlaps(self): self.assertFalse(range.overlaps(QgsRasterRange(-1, 0))) self.assertFalse(range.overlaps(QgsRasterRange(-10, -1))) self.assertFalse(range.overlaps(QgsRasterRange(11, 12))) - self.assertTrue(range.overlaps(QgsRasterRange(-1, float('NaN')))) - self.assertTrue(range.overlaps(QgsRasterRange(1, float('NaN')))) - self.assertFalse(range.overlaps(QgsRasterRange(10, float('NaN')))) - self.assertFalse(range.overlaps(QgsRasterRange(11, float('NaN')))) - self.assertFalse(range.overlaps(QgsRasterRange(float('NaN'), -1))) - self.assertFalse(range.overlaps(QgsRasterRange(float('NaN'), 0))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 1))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 10))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), 11))) - self.assertTrue(range.overlaps(QgsRasterRange(float('NaN'), float('NaN')))) - self.assertFalse(range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.Exclusive))) - self.assertFalse(range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMin))) - self.assertFalse(range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMax))) - self.assertFalse(range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.Exclusive))) - self.assertFalse(range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMin))) - self.assertFalse(range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMax))) + self.assertTrue(range.overlaps(QgsRasterRange(-1, float("NaN")))) + self.assertTrue(range.overlaps(QgsRasterRange(1, float("NaN")))) + self.assertFalse(range.overlaps(QgsRasterRange(10, float("NaN")))) + self.assertFalse(range.overlaps(QgsRasterRange(11, float("NaN")))) + self.assertFalse(range.overlaps(QgsRasterRange(float("NaN"), -1))) + self.assertFalse(range.overlaps(QgsRasterRange(float("NaN"), 0))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 1))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 10))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), 11))) + self.assertTrue(range.overlaps(QgsRasterRange(float("NaN"), float("NaN")))) + self.assertFalse( + range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.Exclusive)) + ) + self.assertFalse( + range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMin)) + ) + self.assertFalse( + range.overlaps(QgsRasterRange(-1, 0, QgsRasterRange.BoundsType.IncludeMax)) + ) + self.assertFalse( + range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.Exclusive)) + ) + self.assertFalse( + range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMin)) + ) + self.assertFalse( + range.overlaps(QgsRasterRange(10, 11, QgsRasterRange.BoundsType.IncludeMax)) + ) def testAsText(self): - self.assertEqual(QgsRasterRange(0, 10, QgsRasterRange.BoundsType.IncludeMinAndMax).asText(), '0 ≤ x ≤ 10') - self.assertEqual(QgsRasterRange(-1, float('NaN')).asText(), '-1 ≤ x ≤ ∞') - self.assertEqual(QgsRasterRange(float('NaN'), 5).asText(), '-∞ ≤ x ≤ 5') - self.assertEqual(QgsRasterRange(float('NaN'), float('NaN')).asText(), '-∞ ≤ x ≤ ∞') - self.assertEqual(QgsRasterRange(0, 10, QgsRasterRange.BoundsType.IncludeMin).asText(), '0 ≤ x < 10') - self.assertEqual(QgsRasterRange(-1, float('NaN'), QgsRasterRange.BoundsType.IncludeMin).asText(), '-1 ≤ x < ∞') - self.assertEqual(QgsRasterRange(float('NaN'), 5, QgsRasterRange.BoundsType.IncludeMin).asText(), '-∞ ≤ x < 5') - self.assertEqual(QgsRasterRange(float('NaN'), float('NaN'), QgsRasterRange.BoundsType.IncludeMin).asText(), '-∞ ≤ x < ∞') - self.assertEqual(QgsRasterRange(0, 10, QgsRasterRange.BoundsType.IncludeMax).asText(), '0 < x ≤ 10') - self.assertEqual(QgsRasterRange(-1, float('NaN'), QgsRasterRange.BoundsType.IncludeMax).asText(), '-1 < x ≤ ∞') - self.assertEqual(QgsRasterRange(float('NaN'), 5, QgsRasterRange.BoundsType.IncludeMax).asText(), '-∞ < x ≤ 5') - self.assertEqual(QgsRasterRange(float('NaN'), float('NaN'), QgsRasterRange.BoundsType.IncludeMax).asText(), '-∞ < x ≤ ∞') - self.assertEqual(QgsRasterRange(0, 10, QgsRasterRange.BoundsType.Exclusive).asText(), '0 < x < 10') - self.assertEqual(QgsRasterRange(-1, float('NaN'), QgsRasterRange.BoundsType.Exclusive).asText(), '-1 < x < ∞') - self.assertEqual(QgsRasterRange(float('NaN'), 5, QgsRasterRange.BoundsType.Exclusive).asText(), '-∞ < x < 5') - self.assertEqual(QgsRasterRange(float('NaN'), float('NaN'), QgsRasterRange.BoundsType.Exclusive).asText(), '-∞ < x < ∞') + self.assertEqual( + QgsRasterRange(0, 10, QgsRasterRange.BoundsType.IncludeMinAndMax).asText(), + "0 ≤ x ≤ 10", + ) + self.assertEqual(QgsRasterRange(-1, float("NaN")).asText(), "-1 ≤ x ≤ ∞") + self.assertEqual(QgsRasterRange(float("NaN"), 5).asText(), "-∞ ≤ x ≤ 5") + self.assertEqual( + QgsRasterRange(float("NaN"), float("NaN")).asText(), "-∞ ≤ x ≤ ∞" + ) + self.assertEqual( + QgsRasterRange(0, 10, QgsRasterRange.BoundsType.IncludeMin).asText(), + "0 ≤ x < 10", + ) + self.assertEqual( + QgsRasterRange( + -1, float("NaN"), QgsRasterRange.BoundsType.IncludeMin + ).asText(), + "-1 ≤ x < ∞", + ) + self.assertEqual( + QgsRasterRange( + float("NaN"), 5, QgsRasterRange.BoundsType.IncludeMin + ).asText(), + "-∞ ≤ x < 5", + ) + self.assertEqual( + QgsRasterRange( + float("NaN"), float("NaN"), QgsRasterRange.BoundsType.IncludeMin + ).asText(), + "-∞ ≤ x < ∞", + ) + self.assertEqual( + QgsRasterRange(0, 10, QgsRasterRange.BoundsType.IncludeMax).asText(), + "0 < x ≤ 10", + ) + self.assertEqual( + QgsRasterRange( + -1, float("NaN"), QgsRasterRange.BoundsType.IncludeMax + ).asText(), + "-1 < x ≤ ∞", + ) + self.assertEqual( + QgsRasterRange( + float("NaN"), 5, QgsRasterRange.BoundsType.IncludeMax + ).asText(), + "-∞ < x ≤ 5", + ) + self.assertEqual( + QgsRasterRange( + float("NaN"), float("NaN"), QgsRasterRange.BoundsType.IncludeMax + ).asText(), + "-∞ < x ≤ ∞", + ) + self.assertEqual( + QgsRasterRange(0, 10, QgsRasterRange.BoundsType.Exclusive).asText(), + "0 < x < 10", + ) + self.assertEqual( + QgsRasterRange( + -1, float("NaN"), QgsRasterRange.BoundsType.Exclusive + ).asText(), + "-1 < x < ∞", + ) + self.assertEqual( + QgsRasterRange( + float("NaN"), 5, QgsRasterRange.BoundsType.Exclusive + ).asText(), + "-∞ < x < 5", + ) + self.assertEqual( + QgsRasterRange( + float("NaN"), float("NaN"), QgsRasterRange.BoundsType.Exclusive + ).asText(), + "-∞ < x < ∞", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterrendererregistry.py b/tests/src/python/test_qgsrasterrendererregistry.py index b57ba82d8352..c787b40cffae 100644 --- a/tests/src/python/test_qgsrasterrendererregistry.py +++ b/tests/src/python/test_qgsrasterrendererregistry.py @@ -5,10 +5,8 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -from qgis.core import ( - Qgis, - QgsRasterRendererRegistry -) + +from qgis.core import Qgis, QgsRasterRendererRegistry import unittest from qgis.testing import start_app, QgisTestCase @@ -27,25 +25,29 @@ def test_registered(self): Test that standard renderers are registered """ registry = QgsRasterRendererRegistry() - self.assertIn('multibandcolor', registry.renderersList()) - self.assertIn('singlebandgray', registry.renderersList()) - self.assertIn('singlebandpseudocolor', registry.renderersList()) - self.assertIn('singlebandcolordata', registry.renderersList()) - self.assertIn('hillshade', registry.renderersList()) - self.assertIn('paletted', registry.renderersList()) - self.assertIn('contour', registry.renderersList()) + self.assertIn("multibandcolor", registry.renderersList()) + self.assertIn("singlebandgray", registry.renderersList()) + self.assertIn("singlebandpseudocolor", registry.renderersList()) + self.assertIn("singlebandcolordata", registry.renderersList()) + self.assertIn("hillshade", registry.renderersList()) + self.assertIn("paletted", registry.renderersList()) + self.assertIn("contour", registry.renderersList()) def test_capabilities(self): """ Test retrieving renderer capabilities """ registry = QgsRasterRendererRegistry() - self.assertFalse(registry.rendererCapabilities('not a renderer')) - self.assertEqual(registry.rendererCapabilities('multibandcolor'), - Qgis.RasterRendererCapability.UsesMultipleBands) - self.assertEqual(registry.rendererCapabilities('singlebandgray'), - Qgis.RasterRendererCapabilities()) - - -if __name__ == '__main__': + self.assertFalse(registry.rendererCapabilities("not a renderer")) + self.assertEqual( + registry.rendererCapabilities("multibandcolor"), + Qgis.RasterRendererCapability.UsesMultipleBands, + ) + self.assertEqual( + registry.rendererCapabilities("singlebandgray"), + Qgis.RasterRendererCapabilities(), + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterrendererutils.py b/tests/src/python/test_qgsrasterrendererutils.py index 2c623cc54a0c..db2025c16918 100644 --- a/tests/src/python/test_qgsrasterrendererutils.py +++ b/tests/src/python/test_qgsrasterrendererutils.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 by Nyall Dawson' -__date__ = '15/09/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 by Nyall Dawson" +__date__ = "15/09/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QTemporaryDir from qgis.PyQt.QtGui import QColor @@ -24,38 +25,67 @@ class TestQgsRasterRendererUtils(QgisTestCase): def testSaveRestoreColorMap(self): - items = [QgsColorRampShader.ColorRampItem(5.5, QColor(255, 100, 120, 60), 'my item'), - QgsColorRampShader.ColorRampItem(15.7, QColor(150, 90, 220)), - QgsColorRampShader.ColorRampItem(22, QColor(255, 0, 0, 100), 'my, & ^ "\' item'), - QgsColorRampShader.ColorRampItem(25.5, QColor(255, 200, 220, 10), 'my item 3')] + items = [ + QgsColorRampShader.ColorRampItem(5.5, QColor(255, 100, 120, 60), "my item"), + QgsColorRampShader.ColorRampItem(15.7, QColor(150, 90, 220)), + QgsColorRampShader.ColorRampItem( + 22, QColor(255, 0, 0, 100), "my, & ^ \"' item" + ), + QgsColorRampShader.ColorRampItem( + 25.5, QColor(255, 200, 220, 10), "my item 3" + ), + ] tmp_dir = QTemporaryDir() tmp_file = f"{tmp_dir.path()}/ramp.txt" - self.assertTrue(QgsRasterRendererUtils.saveColorMapFile(tmp_file, items, QgsColorRampShader.Type.Interpolated)) - res, read_items, type, errors = QgsRasterRendererUtils.parseColorMapFile('') + self.assertTrue( + QgsRasterRendererUtils.saveColorMapFile( + tmp_file, items, QgsColorRampShader.Type.Interpolated + ) + ) + res, read_items, type, errors = QgsRasterRendererUtils.parseColorMapFile("") self.assertFalse(res) - res, read_items, type, errors = QgsRasterRendererUtils.parseColorMapFile(tmp_file) + res, read_items, type, errors = QgsRasterRendererUtils.parseColorMapFile( + tmp_file + ) self.assertTrue(res) self.assertEqual(type, QgsColorRampShader.Type.Interpolated) self.assertFalse(errors) self.assertEqual([i.value for i in read_items], [i.value for i in items]) - self.assertEqual([i.color.name() for i in read_items], [i.color.name() for i in items]) - self.assertEqual([i.label for i in read_items], ['my item', 'Color entry 2', 'my, & ^ "\' item', 'my item 3']) + self.assertEqual( + [i.color.name() for i in read_items], [i.color.name() for i in items] + ) + self.assertEqual( + [i.label for i in read_items], + ["my item", "Color entry 2", "my, & ^ \"' item", "my item 3"], + ) - self.assertTrue(QgsRasterRendererUtils.saveColorMapFile(tmp_file, items, QgsColorRampShader.Type.Discrete)) - res, read_items, type, errors = QgsRasterRendererUtils.parseColorMapFile(tmp_file) + self.assertTrue( + QgsRasterRendererUtils.saveColorMapFile( + tmp_file, items, QgsColorRampShader.Type.Discrete + ) + ) + res, read_items, type, errors = QgsRasterRendererUtils.parseColorMapFile( + tmp_file + ) self.assertTrue(res) self.assertEqual(type, QgsColorRampShader.Type.Discrete) self.assertFalse(errors) - self.assertTrue(QgsRasterRendererUtils.saveColorMapFile(tmp_file, items, QgsColorRampShader.Type.Exact)) - res, read_items, type, errors = QgsRasterRendererUtils.parseColorMapFile(tmp_file) + self.assertTrue( + QgsRasterRendererUtils.saveColorMapFile( + tmp_file, items, QgsColorRampShader.Type.Exact + ) + ) + res, read_items, type, errors = QgsRasterRendererUtils.parseColorMapFile( + tmp_file + ) self.assertTrue(res) self.assertEqual(type, QgsColorRampShader.Type.Exact) self.assertFalse(errors) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterrerderer_createsld.py b/tests/src/python/test_qgsrasterrerderer_createsld.py index 9c07733fb298..380e7148861a 100644 --- a/tests/src/python/test_qgsrasterrerderer_createsld.py +++ b/tests/src/python/test_qgsrasterrerderer_createsld.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Luigi Pirelli' -__date__ = 'December 2018' -__copyright__ = '(C) 2018, Luigi Pirelli' +__author__ = "Luigi Pirelli" +__date__ = "December 2018" +__copyright__ = "(C) 2018, Luigi Pirelli" import os import random @@ -53,7 +53,7 @@ class TestQgsRasterRendererCreateSld(QgisTestCase): """ - This class tests the creation of SLD from QGis raster layers + This class tests the creation of SLD from QGis raster layers """ def setUp(self): @@ -65,147 +65,188 @@ def tearDown(self): def __init__(self, methodName): """Run once on class initialization.""" QgisTestCase.__init__(self, methodName) - myPath = os.path.join(TEST_DATA_DIR, 'landsat.tif') + myPath = os.path.join(TEST_DATA_DIR, "landsat.tif") rasterFileInfo = QFileInfo(myPath) - self.raster_layer = QgsRasterLayer(rasterFileInfo.filePath(), - rasterFileInfo.completeBaseName()) + self.raster_layer = QgsRasterLayer( + rasterFileInfo.filePath(), rasterFileInfo.completeBaseName() + ) def testSingleBandPseudoColorRenderer_Interpolated(self): # get min and max of the band to renderer bandNo = 3 - stats = self.raster_layer.dataProvider().bandStatistics(bandNo, QgsRasterBandStats.Stats.Min | QgsRasterBandStats.Stats.Max) + stats = self.raster_layer.dataProvider().bandStatistics( + bandNo, QgsRasterBandStats.Stats.Min | QgsRasterBandStats.Stats.Max + ) minValue = stats.minimumValue maxValue = stats.maximumValue # create shader for the renderer shader = QgsRasterShader(minValue, maxValue) colorRampShaderFcn = QgsColorRampShader(minValue, maxValue) colorRampShaderFcn.setColorRampType(QgsColorRampShader.Type.Interpolated) - colorRampShaderFcn.setClassificationMode(QgsColorRampShader.ClassificationMode.Continuous) + colorRampShaderFcn.setClassificationMode( + QgsColorRampShader.ClassificationMode.Continuous + ) colorRampShaderFcn.setClip(True) items = [] for index in range(10): - items.append(QgsColorRampShader.ColorRampItem(index, QColor('#{0:02d}{0:02d}{0:02d}'.format(index)), - f"{index}")) + items.append( + QgsColorRampShader.ColorRampItem( + index, QColor("#{0:02d}{0:02d}{0:02d}".format(index)), f"{index}" + ) + ) colorRampShaderFcn.setColorRampItemList(items) shader.setRasterShaderFunction(colorRampShaderFcn) # create instance to test - rasterRenderer = QgsSingleBandPseudoColorRenderer(self.raster_layer.dataProvider(), bandNo, shader) + rasterRenderer = QgsSingleBandPseudoColorRenderer( + self.raster_layer.dataProvider(), bandNo, shader + ) self.raster_layer.setRenderer(rasterRenderer) # do test dom, root = self.rendererToSld(self.raster_layer.renderer()) self.assertNoOpacity(root) - self.assertChannelBand(root, 'sld:GrayChannel', f'{bandNo}') + self.assertChannelBand(root, "sld:GrayChannel", f"{bandNo}") # check ColorMapEntry classes - colorMap = root.elementsByTagName('sld:ColorMap') + colorMap = root.elementsByTagName("sld:ColorMap") colorMap = colorMap.item(0).toElement() self.assertFalse(colorMap.isNull()) - self.assertEqual(colorMap.attribute('type'), 'ramp') - colorMapEntries = colorMap.elementsByTagName('sld:ColorMapEntry') + self.assertEqual(colorMap.attribute("type"), "ramp") + colorMapEntries = colorMap.elementsByTagName("sld:ColorMapEntry") self.assertEqual(colorMapEntries.count(), 10) for index in range(colorMapEntries.count()): colorMapEntry = colorMapEntries.at(index).toElement() - self.assertEqual(colorMapEntry.attribute('quantity'), f'{index}') - self.assertEqual(colorMapEntry.attribute('label'), f'{index}') - self.assertEqual(colorMapEntry.attribute('opacity'), '') - self.assertEqual(colorMapEntry.attribute('color'), '#{0:02d}{0:02d}{0:02d}'.format(index)) + self.assertEqual(colorMapEntry.attribute("quantity"), f"{index}") + self.assertEqual(colorMapEntry.attribute("label"), f"{index}") + self.assertEqual(colorMapEntry.attribute("opacity"), "") + self.assertEqual( + colorMapEntry.attribute("color"), "#{0:02d}{0:02d}{0:02d}".format(index) + ) def testSingleBandPseudoColorRenderer_Discrete(self): # get min and max of the band to renderer bandNo = 3 - stats = self.raster_layer.dataProvider().bandStatistics(bandNo, QgsRasterBandStats.Stats.Min | QgsRasterBandStats.Stats.Max) + stats = self.raster_layer.dataProvider().bandStatistics( + bandNo, QgsRasterBandStats.Stats.Min | QgsRasterBandStats.Stats.Max + ) minValue = stats.minimumValue maxValue = stats.maximumValue # create shader for the renderer shader = QgsRasterShader(minValue, maxValue) colorRampShaderFcn = QgsColorRampShader(minValue, maxValue) colorRampShaderFcn.setColorRampType(QgsColorRampShader.Type.Discrete) - colorRampShaderFcn.setClassificationMode(QgsColorRampShader.ClassificationMode.Continuous) + colorRampShaderFcn.setClassificationMode( + QgsColorRampShader.ClassificationMode.Continuous + ) colorRampShaderFcn.setClip(True) items = [] for index in range(10): - items.append(QgsColorRampShader.ColorRampItem(index, QColor('#{0:02d}{0:02d}{0:02d}'.format(index)), - f"{index}")) + items.append( + QgsColorRampShader.ColorRampItem( + index, QColor("#{0:02d}{0:02d}{0:02d}".format(index)), f"{index}" + ) + ) colorRampShaderFcn.setColorRampItemList(items) shader.setRasterShaderFunction(colorRampShaderFcn) # create instance to test - rasterRenderer = QgsSingleBandPseudoColorRenderer(self.raster_layer.dataProvider(), bandNo, shader) + rasterRenderer = QgsSingleBandPseudoColorRenderer( + self.raster_layer.dataProvider(), bandNo, shader + ) self.raster_layer.setRenderer(rasterRenderer) # do test dom, root = self.rendererToSld(self.raster_layer.renderer()) self.assertNoOpacity(root) - self.assertChannelBand(root, 'sld:GrayChannel', f'{bandNo}') + self.assertChannelBand(root, "sld:GrayChannel", f"{bandNo}") # check ColorMapEntry classes - colorMap = root.elementsByTagName('sld:ColorMap') + colorMap = root.elementsByTagName("sld:ColorMap") colorMap = colorMap.item(0).toElement() self.assertFalse(colorMap.isNull()) - self.assertEqual(colorMap.attribute('type'), 'intervals') - colorMapEntries = colorMap.elementsByTagName('sld:ColorMapEntry') + self.assertEqual(colorMap.attribute("type"), "intervals") + colorMapEntries = colorMap.elementsByTagName("sld:ColorMapEntry") self.assertEqual(colorMapEntries.count(), 10) for index in range(colorMapEntries.count()): colorMapEntry = colorMapEntries.at(index).toElement() - self.assertEqual(colorMapEntry.attribute('quantity'), f'{index}') - self.assertEqual(colorMapEntry.attribute('label'), f'{index}') - self.assertEqual(colorMapEntry.attribute('opacity'), '') - self.assertEqual(colorMapEntry.attribute('color'), '#{0:02d}{0:02d}{0:02d}'.format(index)) + self.assertEqual(colorMapEntry.attribute("quantity"), f"{index}") + self.assertEqual(colorMapEntry.attribute("label"), f"{index}") + self.assertEqual(colorMapEntry.attribute("opacity"), "") + self.assertEqual( + colorMapEntry.attribute("color"), "#{0:02d}{0:02d}{0:02d}".format(index) + ) def testSingleBandPseudoColorRenderer_Exact(self): # get min and max of the band to renderer bandNo = 3 - stats = self.raster_layer.dataProvider().bandStatistics(bandNo, QgsRasterBandStats.Stats.Min | QgsRasterBandStats.Stats.Max) + stats = self.raster_layer.dataProvider().bandStatistics( + bandNo, QgsRasterBandStats.Stats.Min | QgsRasterBandStats.Stats.Max + ) minValue = stats.minimumValue maxValue = stats.maximumValue # create shader for the renderer shader = QgsRasterShader(minValue, maxValue) colorRampShaderFcn = QgsColorRampShader(minValue, maxValue) colorRampShaderFcn.setColorRampType(QgsColorRampShader.Type.Exact) - colorRampShaderFcn.setClassificationMode(QgsColorRampShader.ClassificationMode.Continuous) + colorRampShaderFcn.setClassificationMode( + QgsColorRampShader.ClassificationMode.Continuous + ) colorRampShaderFcn.setClip(True) items = [] for index in range(10): - items.append(QgsColorRampShader.ColorRampItem(index, QColor('#{0:02d}{0:02d}{0:02d}'.format(index)), - f"{index}")) + items.append( + QgsColorRampShader.ColorRampItem( + index, QColor("#{0:02d}{0:02d}{0:02d}".format(index)), f"{index}" + ) + ) colorRampShaderFcn.setColorRampItemList(items) shader.setRasterShaderFunction(colorRampShaderFcn) # create instance to test - rasterRenderer = QgsSingleBandPseudoColorRenderer(self.raster_layer.dataProvider(), bandNo, shader) + rasterRenderer = QgsSingleBandPseudoColorRenderer( + self.raster_layer.dataProvider(), bandNo, shader + ) self.raster_layer.setRenderer(rasterRenderer) # do test dom, root = self.rendererToSld(self.raster_layer.renderer()) self.assertNoOpacity(root) - self.assertChannelBand(root, 'sld:GrayChannel', f'{bandNo}') + self.assertChannelBand(root, "sld:GrayChannel", f"{bandNo}") # check ColorMapEntry classes - colorMap = root.elementsByTagName('sld:ColorMap') + colorMap = root.elementsByTagName("sld:ColorMap") colorMap = colorMap.item(0).toElement() self.assertFalse(colorMap.isNull()) - self.assertEqual(colorMap.attribute('type'), 'values') - self.assertFalse(colorMap.hasAttribute('extendend')) - colorMapEntries = colorMap.elementsByTagName('sld:ColorMapEntry') + self.assertEqual(colorMap.attribute("type"), "values") + self.assertFalse(colorMap.hasAttribute("extendend")) + colorMapEntries = colorMap.elementsByTagName("sld:ColorMapEntry") self.assertEqual(colorMapEntries.count(), 10) for index in range(colorMapEntries.count()): colorMapEntry = colorMapEntries.at(index).toElement() - self.assertEqual(colorMapEntry.attribute('quantity'), f'{index}') - self.assertEqual(colorMapEntry.attribute('label'), f'{index}') - self.assertEqual(colorMapEntry.attribute('opacity'), '') - self.assertEqual(colorMapEntry.attribute('color'), '#{0:02d}{0:02d}{0:02d}'.format(index)) + self.assertEqual(colorMapEntry.attribute("quantity"), f"{index}") + self.assertEqual(colorMapEntry.attribute("label"), f"{index}") + self.assertEqual(colorMapEntry.attribute("opacity"), "") + self.assertEqual( + colorMapEntry.attribute("color"), "#{0:02d}{0:02d}{0:02d}".format(index) + ) # add check that is set ColoMap extended="true" if colormap is bigger that 255 entries # !NOTE! can't reuse previous shader => segmentation fault shader = QgsRasterShader(minValue, maxValue) colorRampShaderFcn = QgsColorRampShader(minValue, maxValue) colorRampShaderFcn.setColorRampType(QgsColorRampShader.Type.Exact) - colorRampShaderFcn.setClassificationMode(QgsColorRampShader.ClassificationMode.Continuous) + colorRampShaderFcn.setClassificationMode( + QgsColorRampShader.ClassificationMode.Continuous + ) colorRampShaderFcn.setClip(True) items = [] for index in range(255): items.append( - QgsColorRampShader.ColorRampItem(index, QColor.fromHsv(index, 255, 255, 255), f"{index}")) + QgsColorRampShader.ColorRampItem( + index, QColor.fromHsv(index, 255, 255, 255), f"{index}" + ) + ) colorRampShaderFcn.setColorRampItemList(items) shader.setRasterShaderFunction(colorRampShaderFcn) # create instance to test - rasterRenderer = QgsSingleBandPseudoColorRenderer(self.raster_layer.dataProvider(), bandNo, shader) + rasterRenderer = QgsSingleBandPseudoColorRenderer( + self.raster_layer.dataProvider(), bandNo, shader + ) # self.raster_layer.setRenderer(rasterRenderer) # dom, root = self.rendererToSld(self.raster_layer.renderer()) # self.assertTrue( colorMap.hasAttribute( 'extendend' ) ) @@ -214,67 +255,78 @@ def testSingleBandPseudoColorRenderer_Exact(self): def testPalettedRasterRenderer(self): # create 10 color classes # classesString = '122 0 0 0 255 122\n123 1 1 1 255 123\n124 2 2 2 255 124\n125 3 3 3 255 125\n126 4 4 4 255 126\n127 5 5 5 255 127\n128 6 6 6 255 128\n129 7 7 7 255 129\n130 8 8 8 255 130' - classesString = '' + classesString = "" for index in range(10): - classesString += '{0} {0} {0} {0} 255 {0}\n'.format(index) + classesString += "{0} {0} {0} {0} 255 {0}\n".format(index) classes = QgsPalettedRasterRenderer.classDataFromString(classesString) rasterRenderer = QgsPalettedRasterRenderer( - self.raster_layer.dataProvider(), 3, classes) + self.raster_layer.dataProvider(), 3, classes + ) self.raster_layer.setRenderer(rasterRenderer) dom, root = self.rendererToSld(self.raster_layer.renderer()) self.assertNoOpacity(root) - self.assertChannelBand(root, 'sld:GrayChannel', '3') + self.assertChannelBand(root, "sld:GrayChannel", "3") # check ColorMapEntry classes - colorMap = root.elementsByTagName('sld:ColorMap') + colorMap = root.elementsByTagName("sld:ColorMap") colorMap = colorMap.item(0).toElement() self.assertFalse(colorMap.isNull()) - self.assertEqual(colorMap.attribute('type'), 'values') - self.assertFalse(colorMap.hasAttribute('extendend')) - colorMapEntries = colorMap.elementsByTagName('sld:ColorMapEntry') + self.assertEqual(colorMap.attribute("type"), "values") + self.assertFalse(colorMap.hasAttribute("extendend")) + colorMapEntries = colorMap.elementsByTagName("sld:ColorMapEntry") self.assertEqual(colorMapEntries.count(), 10) for index in range(colorMapEntries.count()): colorMapEntry = colorMapEntries.at(index).toElement() - self.assertEqual(colorMapEntry.attribute('quantity'), f'{index}') - self.assertEqual(colorMapEntry.attribute('label'), f'{index}') - self.assertEqual(colorMapEntry.attribute('opacity'), '') - self.assertEqual(colorMapEntry.attribute('color'), '#{0:02d}{0:02d}{0:02d}'.format(index)) + self.assertEqual(colorMapEntry.attribute("quantity"), f"{index}") + self.assertEqual(colorMapEntry.attribute("label"), f"{index}") + self.assertEqual(colorMapEntry.attribute("opacity"), "") + self.assertEqual( + colorMapEntry.attribute("color"), "#{0:02d}{0:02d}{0:02d}".format(index) + ) # add check that is set ColoMap extended="true" if colormap is bigger that 255 entries - classesString = '' + classesString = "" values = range(255) for index in range(255): - classesString += '{0} {1} {1} {1} 255 {0}\n'.format(index, random.choice(values)) + classesString += "{0} {1} {1} {1} 255 {0}\n".format( + index, random.choice(values) + ) classes = QgsPalettedRasterRenderer.classDataFromString(classesString) rasterRenderer = QgsPalettedRasterRenderer( - self.raster_layer.dataProvider(), 3, classes) + self.raster_layer.dataProvider(), 3, classes + ) self.raster_layer.setRenderer(rasterRenderer) dom, root = self.rendererToSld(self.raster_layer.renderer()) - colorMap = root.elementsByTagName('sld:ColorMap') + colorMap = root.elementsByTagName("sld:ColorMap") colorMap = colorMap.item(0).toElement() - self.assertTrue(colorMap.hasAttribute('extended')) - self.assertEqual(colorMap.attribute('extended'), 'true') + self.assertTrue(colorMap.hasAttribute("extended")) + self.assertEqual(colorMap.attribute("extended"), "true") def testMultiBandColorRenderer(self): rasterRenderer = QgsMultiBandColorRenderer( - self.raster_layer.dataProvider(), 3, 1, 2) + self.raster_layer.dataProvider(), 3, 1, 2 + ) self.raster_layer.setRenderer(rasterRenderer) - self.raster_layer.setContrastEnhancement(algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum, - limits=QgsRasterMinMaxOrigin.Limits.MinMax) + self.raster_layer.setContrastEnhancement( + algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum, + limits=QgsRasterMinMaxOrigin.Limits.MinMax, + ) dom, root = self.rendererToSld(self.raster_layer.renderer()) self.assertNoOpacity(root) - self.assertChannelBand(root, 'sld:RedChannel', '3') - self.assertChannelBand(root, 'sld:GreenChannel', '1') - self.assertChannelBand(root, 'sld:BlueChannel', '2') + self.assertChannelBand(root, "sld:RedChannel", "3") + self.assertChannelBand(root, "sld:GreenChannel", "1") + self.assertChannelBand(root, "sld:BlueChannel", "2") def testSingleBandGrayRenderer(self): # check with StretchToMinimumMaximum rasterRenderer = QgsSingleBandGrayRenderer(self.raster_layer.dataProvider(), 3) self.raster_layer.setRenderer(rasterRenderer) - self.raster_layer.setContrastEnhancement(algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum, - limits=QgsRasterMinMaxOrigin.Limits.MinMax) + self.raster_layer.setContrastEnhancement( + algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum, + limits=QgsRasterMinMaxOrigin.Limits.MinMax, + ) maximum = self.raster_layer.renderer().contrastEnhancement().maximumValue() minmum = self.raster_layer.renderer().contrastEnhancement().minimumValue() self.assertEqual(minmum, 51) @@ -283,38 +335,44 @@ def testSingleBandGrayRenderer(self): # check default values dom, root = self.rendererToSld(self.raster_layer.renderer()) self.assertNoOpacity(root) - self.assertChannelBand(root, 'sld:GrayChannel', '3') + self.assertChannelBand(root, "sld:GrayChannel", "3") - elements = root.elementsByTagName('sld:ContrastEnhancement') + elements = root.elementsByTagName("sld:ContrastEnhancement") self.assertEqual(len(elements), 1) enhancement = elements.at(0).toElement() self.assertFalse(enhancement.isNull()) - normalize = enhancement.firstChildElement('sld:Normalize') + normalize = enhancement.firstChildElement("sld:Normalize") self.assertFalse(normalize.isNull()) - self.assertVendorOption(normalize, 'algorithm', 'StretchToMinimumMaximum') - self.assertVendorOption(normalize, 'minValue', '51') - self.assertVendorOption(normalize, 'maxValue', '172') + self.assertVendorOption(normalize, "algorithm", "StretchToMinimumMaximum") + self.assertVendorOption(normalize, "minValue", "51") + self.assertVendorOption(normalize, "maxValue", "172") - elements = root.elementsByTagName('sld:ColorMap') + elements = root.elementsByTagName("sld:ColorMap") self.assertEqual(len(elements), 1) colorMap = elements.at(0).toElement() self.assertFalse(colorMap.isNull()) - colorMapEntries = colorMap.elementsByTagName('sld:ColorMapEntry') + colorMapEntries = colorMap.elementsByTagName("sld:ColorMapEntry") self.assertEqual(len(colorMapEntries), 2) clorMap1 = colorMapEntries.at(0) - self.assertEqual(clorMap1.attributes().namedItem('color').nodeValue(), '#000000') - self.assertEqual(clorMap1.attributes().namedItem('quantity').nodeValue(), '0') + self.assertEqual( + clorMap1.attributes().namedItem("color").nodeValue(), "#000000" + ) + self.assertEqual(clorMap1.attributes().namedItem("quantity").nodeValue(), "0") clorMap2 = colorMapEntries.at(1) - self.assertEqual(clorMap2.attributes().namedItem('color').nodeValue(), '#ffffff') - self.assertEqual(clorMap2.attributes().namedItem('quantity').nodeValue(), '255') + self.assertEqual( + clorMap2.attributes().namedItem("color").nodeValue(), "#ffffff" + ) + self.assertEqual(clorMap2.attributes().namedItem("quantity").nodeValue(), "255") # check when StretchAndClipToMinimumMaximum # then min/max have always to be the real one and not that set in the contrastEnhancement - self.raster_layer.setContrastEnhancement(algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchAndClipToMinimumMaximum, - limits=QgsRasterMinMaxOrigin.Limits.MinMax) + self.raster_layer.setContrastEnhancement( + algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchAndClipToMinimumMaximum, + limits=QgsRasterMinMaxOrigin.Limits.MinMax, + ) minmum = self.raster_layer.renderer().contrastEnhancement().setMinimumValue(100) maximum = self.raster_layer.renderer().contrastEnhancement().maximumValue() minmum = self.raster_layer.renderer().contrastEnhancement().minimumValue() @@ -323,47 +381,57 @@ def testSingleBandGrayRenderer(self): dom, root = self.rendererToSld(self.raster_layer.renderer()) self.assertNoOpacity(root) - self.assertChannelBand(root, 'sld:GrayChannel', '3') + self.assertChannelBand(root, "sld:GrayChannel", "3") - elements = root.elementsByTagName('sld:ContrastEnhancement') + elements = root.elementsByTagName("sld:ContrastEnhancement") self.assertEqual(len(elements), 1) enhancement = elements.at(0).toElement() self.assertFalse(enhancement.isNull()) - normalize = enhancement.firstChildElement('sld:Normalize') + normalize = enhancement.firstChildElement("sld:Normalize") self.assertFalse(normalize.isNull()) - self.assertVendorOption(normalize, 'minValue', '51') - self.assertVendorOption(normalize, 'maxValue', '172') + self.assertVendorOption(normalize, "minValue", "51") + self.assertVendorOption(normalize, "maxValue", "172") - elements = root.elementsByTagName('sld:ColorMap') + elements = root.elementsByTagName("sld:ColorMap") self.assertEqual(len(elements), 1) colorMap = elements.at(0).toElement() self.assertFalse(colorMap.isNull()) - colorMapEntries = colorMap.elementsByTagName('sld:ColorMapEntry') + colorMapEntries = colorMap.elementsByTagName("sld:ColorMapEntry") self.assertEqual(len(colorMapEntries), 4) clorMap1 = colorMapEntries.at(0) - self.assertEqual(clorMap1.attributes().namedItem('color').nodeValue(), '#000000') - self.assertEqual(clorMap1.attributes().namedItem('quantity').nodeValue(), '100') - self.assertEqual(clorMap1.attributes().namedItem('opacity').nodeValue(), '0') + self.assertEqual( + clorMap1.attributes().namedItem("color").nodeValue(), "#000000" + ) + self.assertEqual(clorMap1.attributes().namedItem("quantity").nodeValue(), "100") + self.assertEqual(clorMap1.attributes().namedItem("opacity").nodeValue(), "0") clorMap2 = colorMapEntries.at(1) - self.assertEqual(clorMap2.attributes().namedItem('color').nodeValue(), '#000000') - self.assertEqual(clorMap2.attributes().namedItem('quantity').nodeValue(), '100') + self.assertEqual( + clorMap2.attributes().namedItem("color").nodeValue(), "#000000" + ) + self.assertEqual(clorMap2.attributes().namedItem("quantity").nodeValue(), "100") clorMap3 = colorMapEntries.at(2) - self.assertEqual(clorMap3.attributes().namedItem('color').nodeValue(), '#ffffff') - self.assertEqual(clorMap3.attributes().namedItem('quantity').nodeValue(), '172') + self.assertEqual( + clorMap3.attributes().namedItem("color").nodeValue(), "#ffffff" + ) + self.assertEqual(clorMap3.attributes().namedItem("quantity").nodeValue(), "172") clorMap4 = colorMapEntries.at(3) - self.assertEqual(clorMap4.attributes().namedItem('color').nodeValue(), '#ffffff') - self.assertEqual(clorMap4.attributes().namedItem('quantity').nodeValue(), '172') - self.assertEqual(clorMap4.attributes().namedItem('opacity').nodeValue(), '0') + self.assertEqual( + clorMap4.attributes().namedItem("color").nodeValue(), "#ffffff" + ) + self.assertEqual(clorMap4.attributes().namedItem("quantity").nodeValue(), "172") + self.assertEqual(clorMap4.attributes().namedItem("opacity").nodeValue(), "0") # check when ClipToMinimumMaximum # then min/max have always to be the real one and not that set in the contrastEnhancement - self.raster_layer.setContrastEnhancement(algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.ClipToMinimumMaximum, - limits=QgsRasterMinMaxOrigin.Limits.MinMax) + self.raster_layer.setContrastEnhancement( + algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.ClipToMinimumMaximum, + limits=QgsRasterMinMaxOrigin.Limits.MinMax, + ) minmum = self.raster_layer.renderer().contrastEnhancement().setMinimumValue(100) maximum = self.raster_layer.renderer().contrastEnhancement().maximumValue() minmum = self.raster_layer.renderer().contrastEnhancement().minimumValue() @@ -372,48 +440,56 @@ def testSingleBandGrayRenderer(self): dom, root = self.rendererToSld(self.raster_layer.renderer()) self.assertNoOpacity(root) - self.assertChannelBand(root, 'sld:GrayChannel', '3') + self.assertChannelBand(root, "sld:GrayChannel", "3") - elements = root.elementsByTagName('sld:ContrastEnhancement') + elements = root.elementsByTagName("sld:ContrastEnhancement") self.assertEqual(len(elements), 1) enhancement = elements.at(0).toElement() self.assertFalse(enhancement.isNull()) - normalize = enhancement.firstChildElement('sld:Normalize') + normalize = enhancement.firstChildElement("sld:Normalize") self.assertFalse(normalize.isNull()) - self.assertVendorOption(normalize, 'minValue', '51') - self.assertVendorOption(normalize, 'maxValue', '172') + self.assertVendorOption(normalize, "minValue", "51") + self.assertVendorOption(normalize, "maxValue", "172") - elements = root.elementsByTagName('sld:ColorMap') + elements = root.elementsByTagName("sld:ColorMap") self.assertEqual(len(elements), 1) colorMap = elements.at(0).toElement() self.assertFalse(colorMap.isNull()) - colorMapEntries = colorMap.elementsByTagName('sld:ColorMapEntry') + colorMapEntries = colorMap.elementsByTagName("sld:ColorMapEntry") self.assertEqual(len(colorMapEntries), 4) clorMap1 = colorMapEntries.at(0) - self.assertEqual(clorMap1.attributes().namedItem('color').nodeValue(), '#000000') - self.assertEqual(clorMap1.attributes().namedItem('quantity').nodeValue(), '100') - self.assertEqual(clorMap1.attributes().namedItem('opacity').nodeValue(), '0') + self.assertEqual( + clorMap1.attributes().namedItem("color").nodeValue(), "#000000" + ) + self.assertEqual(clorMap1.attributes().namedItem("quantity").nodeValue(), "100") + self.assertEqual(clorMap1.attributes().namedItem("opacity").nodeValue(), "0") clorMap2 = colorMapEntries.at(1) - self.assertEqual(clorMap2.attributes().namedItem('color').nodeValue(), '#000000') - self.assertEqual(clorMap2.attributes().namedItem('quantity').nodeValue(), '100') + self.assertEqual( + clorMap2.attributes().namedItem("color").nodeValue(), "#000000" + ) + self.assertEqual(clorMap2.attributes().namedItem("quantity").nodeValue(), "100") clorMap3 = colorMapEntries.at(2) - self.assertEqual(clorMap3.attributes().namedItem('color').nodeValue(), '#ffffff') - self.assertEqual(clorMap3.attributes().namedItem('quantity').nodeValue(), '172') + self.assertEqual( + clorMap3.attributes().namedItem("color").nodeValue(), "#ffffff" + ) + self.assertEqual(clorMap3.attributes().namedItem("quantity").nodeValue(), "172") clorMap4 = colorMapEntries.at(3) - self.assertEqual(clorMap4.attributes().namedItem('color').nodeValue(), '#ffffff') - self.assertEqual(clorMap4.attributes().namedItem('quantity').nodeValue(), '172') - self.assertEqual(clorMap4.attributes().namedItem('opacity').nodeValue(), '0') + self.assertEqual( + clorMap4.attributes().namedItem("color").nodeValue(), "#ffffff" + ) + self.assertEqual(clorMap4.attributes().namedItem("quantity").nodeValue(), "172") + self.assertEqual(clorMap4.attributes().namedItem("opacity").nodeValue(), "0") def testRasterRenderer(self): class fakerenderer(QgsRasterRenderer): def __init__(self, interface): - QgsRasterRenderer.__init__(self, interface, '') + QgsRasterRenderer.__init__(self, interface, "") rasterRenderer = fakerenderer(self.raster_layer.dataProvider()) self.raster_layer.setRenderer(rasterRenderer) @@ -424,7 +500,7 @@ def __init__(self, interface): # check if opacity is not the default value rasterRenderer.setOpacity(1.1) dom, root = self.rendererToSld(self.raster_layer.renderer()) - self.assertOpacity(root, '1.1') + self.assertOpacity(root, "1.1") # check gamma properties from [-100:0] stretched to [0:1] # and (0:100] stretche dto (1:100] @@ -450,48 +526,75 @@ def __init__(self, interface): def testStretchingAlgorithm(self): rasterRenderer = QgsMultiBandColorRenderer( - self.raster_layer.dataProvider(), 3, 1, 2) + self.raster_layer.dataProvider(), 3, 1, 2 + ) self.raster_layer.setRenderer(rasterRenderer) # check StretchToMinimumMaximum stretching alg - self.raster_layer.setContrastEnhancement(algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum, - limits=QgsRasterMinMaxOrigin.Limits.MinMax) + self.raster_layer.setContrastEnhancement( + algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchToMinimumMaximum, + limits=QgsRasterMinMaxOrigin.Limits.MinMax, + ) dom, root = self.rendererToSld(self.raster_layer.renderer()) - self.assertContrastEnhancement(root, 'sld:RedChannel', 'StretchToMinimumMaximum', '51', '172') - self.assertContrastEnhancement(root, 'sld:GreenChannel', 'StretchToMinimumMaximum', '122', '130') - self.assertContrastEnhancement(root, 'sld:BlueChannel', 'StretchToMinimumMaximum', '133', '148') + self.assertContrastEnhancement( + root, "sld:RedChannel", "StretchToMinimumMaximum", "51", "172" + ) + self.assertContrastEnhancement( + root, "sld:GreenChannel", "StretchToMinimumMaximum", "122", "130" + ) + self.assertContrastEnhancement( + root, "sld:BlueChannel", "StretchToMinimumMaximum", "133", "148" + ) # check StretchAndClipToMinimumMaximum stretching alg - self.raster_layer.setContrastEnhancement(algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchAndClipToMinimumMaximum, - limits=QgsRasterMinMaxOrigin.Limits.MinMax) + self.raster_layer.setContrastEnhancement( + algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.StretchAndClipToMinimumMaximum, + limits=QgsRasterMinMaxOrigin.Limits.MinMax, + ) dom, root = self.rendererToSld(self.raster_layer.renderer()) - self.assertContrastEnhancement(root, 'sld:RedChannel', 'ClipToZero', '51', '172') - self.assertContrastEnhancement(root, 'sld:GreenChannel', 'ClipToZero', '122', '130') - self.assertContrastEnhancement(root, 'sld:BlueChannel', 'ClipToZero', '133', '148') + self.assertContrastEnhancement( + root, "sld:RedChannel", "ClipToZero", "51", "172" + ) + self.assertContrastEnhancement( + root, "sld:GreenChannel", "ClipToZero", "122", "130" + ) + self.assertContrastEnhancement( + root, "sld:BlueChannel", "ClipToZero", "133", "148" + ) # check ClipToMinimumMaximum stretching alg - self.raster_layer.setContrastEnhancement(algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.ClipToMinimumMaximum, - limits=QgsRasterMinMaxOrigin.Limits.MinMax) + self.raster_layer.setContrastEnhancement( + algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.ClipToMinimumMaximum, + limits=QgsRasterMinMaxOrigin.Limits.MinMax, + ) dom, root = self.rendererToSld(self.raster_layer.renderer()) - self.assertContrastEnhancement(root, 'sld:RedChannel', 'ClipToMinimumMaximum', '51', '172') - self.assertContrastEnhancement(root, 'sld:GreenChannel', 'ClipToMinimumMaximum', '122', '130') - self.assertContrastEnhancement(root, 'sld:BlueChannel', 'ClipToMinimumMaximum', '133', '148') + self.assertContrastEnhancement( + root, "sld:RedChannel", "ClipToMinimumMaximum", "51", "172" + ) + self.assertContrastEnhancement( + root, "sld:GreenChannel", "ClipToMinimumMaximum", "122", "130" + ) + self.assertContrastEnhancement( + root, "sld:BlueChannel", "ClipToMinimumMaximum", "133", "148" + ) # check NoEnhancement stretching alg - self.raster_layer.setContrastEnhancement(algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.NoEnhancement) + self.raster_layer.setContrastEnhancement( + algorithm=QgsContrastEnhancement.ContrastEnhancementAlgorithm.NoEnhancement + ) dom, root = self.rendererToSld(self.raster_layer.renderer()) - self.assertContrastEnhancement(root, 'sld:RedChannel') - self.assertContrastEnhancement(root, 'sld:GreenChannel') - self.assertContrastEnhancement(root, 'sld:BlueChannel') + self.assertContrastEnhancement(root, "sld:RedChannel") + self.assertContrastEnhancement(root, "sld:GreenChannel") + self.assertContrastEnhancement(root, "sld:BlueChannel") def assertVendorOption(self, root, name, expectedValue): """Set expectedValue=None to check that the vendor option is not present.""" - vendorOptions = root.elementsByTagName('sld:VendorOption') + vendorOptions = root.elementsByTagName("sld:VendorOption") found = False for vendorOptionIndex in range(vendorOptions.count()): vendorOption = vendorOptions.at(vendorOptionIndex) - self.assertEqual('sld:VendorOption', vendorOption.nodeName()) - if (vendorOption.attributes().namedItem('name').nodeValue() == name): + self.assertEqual("sld:VendorOption", vendorOption.nodeName()) + if vendorOption.attributes().namedItem("name").nodeValue() == name: found = True self.assertEqual(vendorOption.firstChild().nodeValue(), expectedValue) if (expectedValue is None) and found: @@ -500,50 +603,61 @@ def assertVendorOption(self, root, name, expectedValue): self.fail(f"Not found VendorOption: {name}") def assertGamma(self, root, expectedValue, index=0): - enhancement = root.elementsByTagName('sld:ContrastEnhancement').item(index) - gamma = enhancement.firstChildElement('sld:GammaValue') + enhancement = root.elementsByTagName("sld:ContrastEnhancement").item(index) + gamma = enhancement.firstChildElement("sld:GammaValue") self.assertEqual(expectedValue, gamma.firstChild().nodeValue()) def assertOpacity(self, root, expectedValue, index=0): - opacity = root.elementsByTagName('sld:Opacity').item(index) + opacity = root.elementsByTagName("sld:Opacity").item(index) self.assertEqual(expectedValue, opacity.firstChild().nodeValue()) def assertNoOpacity(self, root): - opacities = root.elementsByTagName('sld:Opacity') + opacities = root.elementsByTagName("sld:Opacity") self.assertEqual(opacities.size(), 0) - def assertContrastEnhancement(self, root, bandTag, expectedAlg=None, expectedMin=None, expectedMax=None, index=0): - channelSelection = root.elementsByTagName('sld:ChannelSelection').item(index) + def assertContrastEnhancement( + self, + root, + bandTag, + expectedAlg=None, + expectedMin=None, + expectedMax=None, + index=0, + ): + channelSelection = root.elementsByTagName("sld:ChannelSelection").item(index) self.assertIsNotNone(channelSelection) band = channelSelection.firstChildElement(bandTag) # check if no enhancement alg is iset - if (not expectedAlg): - contrastEnhancementName = band.firstChildElement('sld:ContrastEnhancement') - self.assertEqual('', contrastEnhancementName.firstChild().nodeName()) + if not expectedAlg: + contrastEnhancementName = band.firstChildElement("sld:ContrastEnhancement") + self.assertEqual("", contrastEnhancementName.firstChild().nodeName()) return # check if enhancement alg is set - contrastEnhancementName = band.firstChildElement('sld:ContrastEnhancement') - self.assertEqual('sld:Normalize', contrastEnhancementName.firstChild().nodeName()) - normalize = contrastEnhancementName.firstChildElement('sld:Normalize') - vendorOptions = normalize.elementsByTagName('VendorOption') + contrastEnhancementName = band.firstChildElement("sld:ContrastEnhancement") + self.assertEqual( + "sld:Normalize", contrastEnhancementName.firstChild().nodeName() + ) + normalize = contrastEnhancementName.firstChildElement("sld:Normalize") + vendorOptions = normalize.elementsByTagName("VendorOption") for vendorOptionIndex in range(vendorOptions.count()): vendorOption = vendorOptions.at(vendorOptionIndex) - self.assertEqual('VendorOption', vendorOption.nodeName()) - if (vendorOption.attributes().namedItem('name').nodeValue() == 'algorithm'): + self.assertEqual("VendorOption", vendorOption.nodeName()) + if vendorOption.attributes().namedItem("name").nodeValue() == "algorithm": self.assertEqual(expectedAlg, vendorOption.firstChild().nodeValue()) - elif (vendorOption.attributes().namedItem('name').nodeValue() == 'minValue'): + elif vendorOption.attributes().namedItem("name").nodeValue() == "minValue": self.assertEqual(expectedMin, vendorOption.firstChild().nodeValue()) - elif (vendorOption.attributes().namedItem('name').nodeValue() == 'maxValue'): + elif vendorOption.attributes().namedItem("name").nodeValue() == "maxValue": self.assertEqual(expectedMax, vendorOption.firstChild().nodeValue()) else: self.fail( - f"Unrecognised vendorOption name {vendorOption.attributes().namedItem('name').nodeValue()}") + f"Unrecognised vendorOption name {vendorOption.attributes().namedItem('name').nodeValue()}" + ) def assertChannelBand(self, root, bandTag, expectedValue, index=0): - channelSelection = root.elementsByTagName('sld:ChannelSelection').item(index) + channelSelection = root.elementsByTagName("sld:ChannelSelection").item(index) self.assertIsNotNone(channelSelection) band = channelSelection.firstChildElement(bandTag) - sourceChannelName = band.firstChildElement('sld:SourceChannelName') + sourceChannelName = band.firstChildElement("sld:SourceChannelName") self.assertEqual(expectedValue, sourceChannelName.firstChild().nodeValue()) def rendererToSld(self, renderer, properties={}): @@ -554,5 +668,5 @@ def rendererToSld(self, renderer, properties={}): return dom, root -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrasterresampler.py b/tests/src/python/test_qgsrasterresampler.py index 2eaea3cea3f2..cbd863bf7552 100644 --- a/tests/src/python/test_qgsrasterresampler.py +++ b/tests/src/python/test_qgsrasterresampler.py @@ -6,9 +6,9 @@ (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '14/11/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' +__author__ = "Nyall Dawson" +__date__ = "14/11/2019" +__copyright__ = "Copyright 2019, The QGIS Project" import os import shutil @@ -47,17 +47,19 @@ def checkBlockContents(self, block, expected): def testBilinearResample(self): with tempfile.TemporaryDirectory() as dest_dir: - path = os.path.join(unitTestDataPath(), 'landsat.tif') - dest_path = shutil.copy(path, os.path.join(dest_dir, 'landsat.tif')) + path = os.path.join(unitTestDataPath(), "landsat.tif") + dest_path = shutil.copy(path, os.path.join(dest_dir, "landsat.tif")) - raster_layer = QgsRasterLayer(dest_path, 'test') + raster_layer = QgsRasterLayer(dest_path, "test") raster_layer.dataProvider().setNoDataValue(1, -9999) self.assertTrue(raster_layer.isValid()) - extent = QgsRectangle(785994.37761193525511771, - 3346249.2209800467826426, - 786108.49096253968309611, - 3346362.94137834152206779) + extent = QgsRectangle( + 785994.37761193525511771, + 3346249.2209800467826426, + 786108.49096253968309611, + 3346362.94137834152206779, + ) renderer = QgsSingleBandGrayRenderer(raster_layer.dataProvider(), 1) filter = QgsRasterResampleFilter(renderer) @@ -67,21 +69,30 @@ def testBilinearResample(self): self.checkBlockContents(block, [[124, 127], [125, 126]]) block = filter.block(1, extent, 4, 4) - self.checkBlockContents(block, [[124, 124, 127, 127], - [124, 124, 127, 127], - [125, 125, 126, 126], - [125, 125, 126, 126]] - ) + self.checkBlockContents( + block, + [ + [124, 124, 127, 127], + [124, 124, 127, 127], + [125, 125, 126, 126], + [125, 125, 126, 126], + ], + ) block = filter.block(1, extent, 8, 8) - self.checkBlockContents(block, [[124, 124, 124, 124, 127, 127, 127, 127], - [124, 124, 124, 124, 127, 127, 127, 127], - [124, 124, 124, 124, 127, 127, 127, 127], - [124, 124, 124, 124, 127, 127, 127, 127], - [125, 125, 125, 125, 126, 126, 126, 126], - [125, 125, 125, 125, 126, 126, 126, 126], - [125, 125, 125, 125, 126, 126, 126, 126], - [125, 125, 125, 125, 126, 126, 126, 126]]) + self.checkBlockContents( + block, + [ + [124, 124, 124, 124, 127, 127, 127, 127], + [124, 124, 124, 124, 127, 127, 127, 127], + [124, 124, 124, 124, 127, 127, 127, 127], + [124, 124, 124, 124, 127, 127, 127, 127], + [125, 125, 125, 125, 126, 126, 126, 126], + [125, 125, 125, 125, 126, 126, 126, 126], + [125, 125, 125, 125, 126, 126, 126, 126], + [125, 125, 125, 125, 126, 126, 126, 126], + ], + ) # with resampling filter.setZoomedInResampler(QgsBilinearRasterResampler()) @@ -89,111 +100,142 @@ def testBilinearResample(self): self.checkBlockContents(block, [[124, 127], [125, 126]]) block = filter.block(1, extent, 4, 4) - self.checkBlockContents(block, - [[124, 124, 126, 126], - [124, 124, 125, 126], - [124, 124, 125, 126], - [125, 125, 125, 126]] - ) + self.checkBlockContents( + block, + [ + [124, 124, 126, 126], + [124, 124, 125, 126], + [124, 124, 125, 126], + [125, 125, 125, 126], + ], + ) block = filter.block(1, extent, 8, 8) - self.checkBlockContents(block, - [[124, 124, 124, 125, 125, 126, 126, 126], - [124, 124, 124, 125, 125, 126, 126, 126], - [124, 124, 124, 124, 125, 125, 126, 126], - [124, 124, 124, 124, 125, 125, 126, 126], - [124, 124, 124, 124, 125, 125, 126, 126], - [124, 124, 124, 124, 125, 125, 126, 126], - [125, 125, 125, 125, 125, 125, 126, 126], - [125, 125, 125, 125, 125, 125, 126, 126]] - ) + self.checkBlockContents( + block, + [ + [124, 124, 124, 125, 125, 126, 126, 126], + [124, 124, 124, 125, 125, 126, 126, 126], + [124, 124, 124, 124, 125, 125, 126, 126], + [124, 124, 124, 124, 125, 125, 126, 126], + [124, 124, 124, 124, 125, 125, 126, 126], + [124, 124, 124, 124, 125, 125, 126, 126], + [125, 125, 125, 125, 125, 125, 126, 126], + [125, 125, 125, 125, 125, 125, 126, 126], + ], + ) # with oversampling - extent = QgsRectangle(785878.92593475803732872, 3346136.27493690419942141, 786223.56509550288319588, 3346477.7564090033993125) + extent = QgsRectangle( + 785878.92593475803732872, + 3346136.27493690419942141, + 786223.56509550288319588, + 3346477.7564090033993125, + ) block = filter.block(1, extent, 2, 2) self.checkBlockContents(block, [[127, 126], [125, 126]]) block = filter.block(1, extent, 4, 4) - self.checkBlockContents(block, - [[125, 127, 127, 127], - [126, 127, 127, 126], - [125, 126, 126, 126], - [127, 125, 125, 125]] - ) + self.checkBlockContents( + block, + [ + [125, 127, 127, 127], + [126, 127, 127, 126], + [125, 126, 126, 126], + [127, 125, 125, 125], + ], + ) block = filter.block(1, extent, 8, 8) - self.checkBlockContents(block, - [[126, 126, 126, 126, 125, 125, 125, 126], - [126, 126, 125, 125, 125, 126, 126, 126], - [126, 125, 124, 124, 125, 126, 126, 126], - [126, 125, 124, 124, 125, 126, 126, 126], - [125, 125, 124, 124, 124, 126, 126, 126], - [125, 125, 125, 125, 125, 126, 126, 126], - [125, 125, 125, 125, 125, 126, 126, 126], - [125, 125, 126, 126, 125, 125, 125, 125]] - ) + self.checkBlockContents( + block, + [ + [126, 126, 126, 126, 125, 125, 125, 126], + [126, 126, 125, 125, 125, 126, 126, 126], + [126, 125, 124, 124, 125, 126, 126, 126], + [126, 125, 124, 124, 125, 126, 126, 126], + [125, 125, 124, 124, 124, 126, 126, 126], + [125, 125, 125, 125, 125, 126, 126, 126], + [125, 125, 125, 125, 125, 126, 126, 126], + [125, 125, 126, 126, 125, 125, 125, 125], + ], + ) filter.setMaxOversampling(2) block = filter.block(1, extent, 2, 2) self.checkBlockContents(block, [[127, 126], [125, 126]]) block = filter.block(1, extent, 4, 4) - self.checkBlockContents(block, - [[125, 127, 127, 127], - [126, 127, 127, 126], - [125, 126, 126, 126], - [127, 125, 125, 125]] - ) + self.checkBlockContents( + block, + [ + [125, 127, 127, 127], + [126, 127, 127, 126], + [125, 126, 126, 126], + [127, 125, 125, 125], + ], + ) block = filter.block(1, extent, 8, 8) - self.checkBlockContents(block, - [[126, 126, 126, 126, 125, 125, 125, 126], - [126, 126, 125, 125, 125, 126, 126, 126], - [126, 125, 124, 124, 125, 126, 126, 126], - [126, 125, 124, 124, 125, 126, 126, 126], - [125, 125, 124, 124, 124, 126, 126, 126], - [125, 125, 125, 125, 125, 126, 126, 126], - [125, 125, 125, 125, 125, 126, 126, 126], - [125, 125, 126, 126, 125, 125, 125, 125]] - ) + self.checkBlockContents( + block, + [ + [126, 126, 126, 126, 125, 125, 125, 126], + [126, 126, 125, 125, 125, 126, 126, 126], + [126, 125, 124, 124, 125, 126, 126, 126], + [126, 125, 124, 124, 125, 126, 126, 126], + [125, 125, 124, 124, 124, 126, 126, 126], + [125, 125, 125, 125, 125, 126, 126, 126], + [125, 125, 125, 125, 125, 126, 126, 126], + [125, 125, 126, 126, 125, 125, 125, 125], + ], + ) filter.setMaxOversampling(4) block = filter.block(1, extent, 2, 2) self.checkBlockContents(block, [[127, 126], [125, 126]]) block = filter.block(1, extent, 4, 4) - self.checkBlockContents(block, - [[125, 127, 127, 127], - [126, 127, 127, 126], - [125, 126, 126, 126], - [127, 125, 125, 125]] - ) + self.checkBlockContents( + block, + [ + [125, 127, 127, 127], + [126, 127, 127, 126], + [125, 126, 126, 126], + [127, 125, 125, 125], + ], + ) block = filter.block(1, extent, 8, 8) - self.checkBlockContents(block, - [[126, 126, 126, 126, 125, 125, 125, 126], - [126, 126, 125, 125, 125, 126, 126, 126], - [126, 125, 124, 124, 125, 126, 126, 126], - [126, 125, 124, 124, 125, 126, 126, 126], - [125, 125, 124, 124, 124, 126, 126, 126], - [125, 125, 125, 125, 125, 126, 126, 126], - [125, 125, 125, 125, 125, 126, 126, 126], - [125, 125, 126, 126, 125, 125, 125, 125]] - ) + self.checkBlockContents( + block, + [ + [126, 126, 126, 126, 125, 125, 125, 126], + [126, 126, 125, 125, 125, 126, 126, 126], + [126, 125, 124, 124, 125, 126, 126, 126], + [126, 125, 124, 124, 125, 126, 126, 126], + [125, 125, 124, 124, 124, 126, 126, 126], + [125, 125, 125, 125, 125, 126, 126, 126], + [125, 125, 125, 125, 125, 126, 126, 126], + [125, 125, 126, 126, 125, 125, 125, 125], + ], + ) def testCubicResample(self): with tempfile.TemporaryDirectory() as dest_dir: - path = os.path.join(unitTestDataPath(), 'landsat.tif') - dest_path = shutil.copy(path, os.path.join(dest_dir, 'landsat.tif')) + path = os.path.join(unitTestDataPath(), "landsat.tif") + dest_path = shutil.copy(path, os.path.join(dest_dir, "landsat.tif")) - raster_layer = QgsRasterLayer(dest_path, 'test') + raster_layer = QgsRasterLayer(dest_path, "test") raster_layer.dataProvider().setNoDataValue(1, -9999) self.assertTrue(raster_layer.isValid()) - extent = QgsRectangle(785994.37761193525511771, - 3346249.2209800467826426, - 786108.49096253968309611, - 3346362.94137834152206779) + extent = QgsRectangle( + 785994.37761193525511771, + 3346249.2209800467826426, + 786108.49096253968309611, + 3346362.94137834152206779, + ) renderer = QgsSingleBandGrayRenderer(raster_layer.dataProvider(), 1) filter = QgsRasterResampleFilter(renderer) @@ -203,21 +245,30 @@ def testCubicResample(self): self.checkBlockContents(block, [[124, 127], [125, 126]]) block = filter.block(1, extent, 4, 4) - self.checkBlockContents(block, [[124, 124, 127, 127], - [124, 124, 127, 127], - [125, 125, 126, 126], - [125, 125, 126, 126]] - ) + self.checkBlockContents( + block, + [ + [124, 124, 127, 127], + [124, 124, 127, 127], + [125, 125, 126, 126], + [125, 125, 126, 126], + ], + ) block = filter.block(1, extent, 8, 8) - self.checkBlockContents(block, [[124, 124, 124, 124, 127, 127, 127, 127], - [124, 124, 124, 124, 127, 127, 127, 127], - [124, 124, 124, 124, 127, 127, 127, 127], - [124, 124, 124, 124, 127, 127, 127, 127], - [125, 125, 125, 125, 126, 126, 126, 126], - [125, 125, 125, 125, 126, 126, 126, 126], - [125, 125, 125, 125, 126, 126, 126, 126], - [125, 125, 125, 125, 126, 126, 126, 126]]) + self.checkBlockContents( + block, + [ + [124, 124, 124, 124, 127, 127, 127, 127], + [124, 124, 124, 124, 127, 127, 127, 127], + [124, 124, 124, 124, 127, 127, 127, 127], + [124, 124, 124, 124, 127, 127, 127, 127], + [125, 125, 125, 125, 126, 126, 126, 126], + [125, 125, 125, 125, 126, 126, 126, 126], + [125, 125, 125, 125, 126, 126, 126, 126], + [125, 125, 125, 125, 126, 126, 126, 126], + ], + ) # with resampling filter.setZoomedInResampler(QgsCubicRasterResampler()) @@ -225,120 +276,176 @@ def testCubicResample(self): self.checkBlockContents(block, [[124, 127], [125, 126]]) block = filter.block(1, extent, 4, 4) - self.checkBlockContents(block, - [[124, 125, 127, 127], - [124, 125, 126, 127], - [125, 125, 126, 126], - [125, 125, 126, 126]] - ) + self.checkBlockContents( + block, + [ + [124, 125, 127, 127], + [124, 125, 126, 127], + [125, 125, 126, 126], + [125, 125, 126, 126], + ], + ) block = filter.block(1, extent, 8, 8) - self.checkBlockContents(block, - [[125, 124, 124, 125, 126, 127, 127, 127], - [125, 124, 124, 125, 126, 127, 127, 127], - [125, 124, 124, 125, 126, 127, 127, 127], - [125, 124, 124, 125, 126, 126, 127, 127], - [125, 125, 125, 125, 126, 126, 126, 126], - [125, 125, 125, 125, 126, 126, 126, 126], - [125, 125, 125, 125, 126, 126, 126, 126], - [125, 125, 125, 125, 126, 126, 126, 126]] - ) + self.checkBlockContents( + block, + [ + [125, 124, 124, 125, 126, 127, 127, 127], + [125, 124, 124, 125, 126, 127, 127, 127], + [125, 124, 124, 125, 126, 127, 127, 127], + [125, 124, 124, 125, 126, 126, 127, 127], + [125, 125, 125, 125, 126, 126, 126, 126], + [125, 125, 125, 125, 126, 126, 126, 126], + [125, 125, 125, 125, 126, 126, 126, 126], + [125, 125, 125, 125, 126, 126, 126, 126], + ], + ) # with oversampling - extent = QgsRectangle(785878.92593475803732872, 3346136.27493690419942141, 786223.56509550288319588, 3346477.7564090033993125) + extent = QgsRectangle( + 785878.92593475803732872, + 3346136.27493690419942141, + 786223.56509550288319588, + 3346477.7564090033993125, + ) block = filter.block(1, extent, 2, 2) self.checkBlockContents(block, [[127, 126], [125, 126]]) block = filter.block(1, extent, 4, 4) - self.checkBlockContents(block, - [[125, 127, 127, 127], - [126, 127, 127, 126], - [125, 126, 126, 126], - [127, 125, 125, 125]] - ) + self.checkBlockContents( + block, + [ + [125, 127, 127, 127], + [126, 127, 127, 126], + [125, 126, 126, 126], + [127, 125, 125, 125], + ], + ) block = filter.block(1, extent, 8, 8) - self.checkBlockContents(block, - [[127, 126, 127, 126, 126, 125, 126, 126], - [127, 127, 127, 126, 126, 126, 126, 126], - [126, 127, 125, 125, 126, 127, 127, 127], - [126, 126, 126, 124, 126, 127, 126, 127], - [126, 126, 125, 124, 125, 126, 126, 127], - [126, 126, 125, 125, 125, 126, 127, 127], - [126, 125, 127, 125, 125, 127, 128, 126], - [126, 125, 127, 127, 126, 125, 125, 126]] - ) + self.checkBlockContents( + block, + [ + [127, 126, 127, 126, 126, 125, 126, 126], + [127, 127, 127, 126, 126, 126, 126, 126], + [126, 127, 125, 125, 126, 127, 127, 127], + [126, 126, 126, 124, 126, 127, 126, 127], + [126, 126, 125, 124, 125, 126, 126, 127], + [126, 126, 125, 125, 125, 126, 127, 127], + [126, 125, 127, 125, 125, 127, 128, 126], + [126, 125, 127, 127, 126, 125, 125, 126], + ], + ) filter.setMaxOversampling(2) block = filter.block(1, extent, 2, 2) self.checkBlockContents(block, [[127, 126], [125, 126]]) block = filter.block(1, extent, 4, 4) - self.checkBlockContents(block, - [[125, 127, 127, 127], - [126, 127, 127, 126], - [125, 126, 126, 126], - [127, 125, 125, 125]] - ) + self.checkBlockContents( + block, + [ + [125, 127, 127, 127], + [126, 127, 127, 126], + [125, 126, 126, 126], + [127, 125, 125, 125], + ], + ) block = filter.block(1, extent, 8, 8) - self.checkBlockContents(block, - [[127, 126, 127, 126, 126, 125, 126, 126], - [127, 127, 127, 126, 126, 126, 126, 126], - [126, 127, 125, 125, 126, 127, 127, 127], - [126, 126, 126, 124, 126, 127, 126, 127], - [126, 126, 125, 124, 125, 126, 126, 127], - [126, 126, 125, 125, 125, 126, 127, 127], - [126, 125, 127, 125, 125, 127, 128, 126], - [126, 125, 127, 127, 126, 125, 125, 126]] - ) + self.checkBlockContents( + block, + [ + [127, 126, 127, 126, 126, 125, 126, 126], + [127, 127, 127, 126, 126, 126, 126, 126], + [126, 127, 125, 125, 126, 127, 127, 127], + [126, 126, 126, 124, 126, 127, 126, 127], + [126, 126, 125, 124, 125, 126, 126, 127], + [126, 126, 125, 125, 125, 126, 127, 127], + [126, 125, 127, 125, 125, 127, 128, 126], + [126, 125, 127, 127, 126, 125, 125, 126], + ], + ) filter.setMaxOversampling(4) block = filter.block(1, extent, 2, 2) self.checkBlockContents(block, [[127, 126], [125, 126]]) block = filter.block(1, extent, 4, 4) - self.checkBlockContents(block, - [[125, 127, 127, 127], - [126, 127, 127, 126], - [125, 126, 126, 126], - [127, 125, 125, 125]] - ) + self.checkBlockContents( + block, + [ + [125, 127, 127, 127], + [126, 127, 127, 126], + [125, 126, 126, 126], + [127, 125, 125, 125], + ], + ) block = filter.block(1, extent, 8, 8) - self.checkBlockContents(block, - [[127, 126, 127, 126, 126, 125, 126, 126], - [127, 127, 127, 126, 126, 126, 126, 126], - [126, 127, 125, 125, 126, 127, 127, 127], - [126, 126, 126, 124, 126, 127, 126, 127], - [126, 126, 125, 124, 125, 126, 126, 127], - [126, 126, 125, 125, 125, 126, 127, 127], - [126, 125, 127, 125, 125, 127, 128, 126], - [126, 125, 127, 127, 126, 125, 125, 126]] - ) + self.checkBlockContents( + block, + [ + [127, 126, 127, 126, 126, 125, 126, 126], + [127, 127, 127, 126, 126, 126, 126, 126], + [126, 127, 125, 125, 126, 127, 127, 127], + [126, 126, 126, 124, 126, 127, 126, 127], + [126, 126, 125, 124, 125, 126, 126, 127], + [126, 126, 125, 125, 125, 126, 127, 127], + [126, 125, 127, 125, 125, 127, 128, 126], + [126, 125, 127, 127, 126, 125, 125, 126], + ], + ) @contextmanager def setupGDALResampling(self): temp_folder = tempfile.mkdtemp() - tmpfilename = os.path.join(temp_folder, 'test.tif') + tmpfilename = os.path.join(temp_folder, "test.tif") - ds = gdal.GetDriverByName('GTiff').Create(tmpfilename, 5, 5) + ds = gdal.GetDriverByName("GTiff").Create(tmpfilename, 5, 5) xmin = 100 ymax = 1000 xres = 5 yres = 5 ds.SetGeoTransform([xmin, xres, 0, ymax, 0, -yres]) - ds.WriteRaster(0, 0, 5, 5, - struct.pack('B' * 5 * 5, - 10, 20, 30, 40, 150, - 20, 30, 40, 50, 160, - 30, 40, 50, 60, 170, - 40, 50, 60, 70, 180, - 50, 60, 70, 80, 190)) + ds.WriteRaster( + 0, + 0, + 5, + 5, + struct.pack( + "B" * 5 * 5, + 10, + 20, + 30, + 40, + 150, + 20, + 30, + 40, + 50, + 160, + 30, + 40, + 50, + 60, + 170, + 40, + 50, + 60, + 70, + 180, + 50, + 60, + 70, + 80, + 190, + ), + ) ds = None - raster_layer = QgsRasterLayer(tmpfilename, 'test') + raster_layer = QgsRasterLayer(tmpfilename, "test") self.assertTrue(raster_layer.isValid()) raster_layer.dataProvider().enableProviderResampling(True) @@ -356,16 +463,23 @@ def _getExtentRequestInside(self): xres = 5 yres = 5 - extent = QgsRectangle(xmin + 2.25 * xres, - ymax - 4.25 * yres, - xmin + 4.25 * xres, - ymax - 2.25 * yres) + extent = QgsRectangle( + xmin + 2.25 * xres, + ymax - 4.25 * yres, + xmin + 4.25 * xres, + ymax - 2.25 * yres, + ) return extent def checkRawBlockContents(self, block, expected): res = [] for r in range(block.height()): - res.append([(0 if block.isNoData(r, c) else block.value(r, c)) for c in range(block.width())]) + res.append( + [ + (0 if block.isNoData(r, c) else block.value(r, c)) + for c in range(block.width()) + ] + ) self.assertEqual(res, expected) def testGDALResampling_nearest(self): @@ -378,60 +492,100 @@ def testGDALResampling_nearest(self): def testGDALResampling_nominal_resolution_zoomed_in_bilinear(self): with self.setupGDALResampling() as provider: - provider.setZoomedInResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Bilinear) + provider.setZoomedInResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Bilinear + ) block = provider.block(1, self._getExtentRequestInside(), 2, 2) self.checkRawBlockContents(block, [[55, 90], [65, 100]]) def testGDALResampling_nominal_resolution_zoomed_in_cubic(self): with self.setupGDALResampling() as provider: - provider.setZoomedInResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Cubic) + provider.setZoomedInResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Cubic + ) block = provider.block(1, self._getExtentRequestInside(), 2, 2) self.checkRawBlockContents(block, [[53, 88], [63, 98]]) def testGDALResampling_nominal_resolution_zoomed_out_bilinear(self): with self.setupGDALResampling() as provider: - provider.setZoomedOutResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Bilinear) + provider.setZoomedOutResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Bilinear + ) block = provider.block(1, self._getExtentRequestInside(), 2, 2) self.checkRawBlockContents(block, [[55, 90], [65, 100]]) def testGDALResampling_nominal_resolution_zoomed_out_cubic(self): with self.setupGDALResampling() as provider: - provider.setZoomedOutResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Cubic) + provider.setZoomedOutResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Cubic + ) block = provider.block(1, self._getExtentRequestInside(), 2, 2) self.checkRawBlockContents(block, [[53, 88], [63, 98]]) def testGDALResampling_oversampling_bilinear(self): with self.setupGDALResampling() as provider: - provider.setZoomedInResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Bilinear) - provider.setZoomedOutResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Cubic) # ignored + provider.setZoomedInResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Bilinear + ) + provider.setZoomedOutResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Cubic + ) # ignored block = provider.block(1, self._getExtentRequestInside(), 4, 4) - self.checkRawBlockContents(block, [[50, 55, 60, 115], [55, 60, 65, 120], [60, 65, 70, 125], [65, 70, 75, 130]]) + self.checkRawBlockContents( + block, + [ + [50, 55, 60, 115], + [55, 60, 65, 120], + [60, 65, 70, 125], + [65, 70, 75, 130], + ], + ) def testGDALResampling_oversampling_cubic(self): with self.setupGDALResampling() as provider: - provider.setZoomedInResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Cubic) - provider.setZoomedOutResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Bilinear) # ignored + provider.setZoomedInResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Cubic + ) + provider.setZoomedOutResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Bilinear + ) # ignored block = provider.block(1, self._getExtentRequestInside(), 4, 4) - self.checkRawBlockContents(block, [[50, 49, 60, 119], [55, 54, 65, 124], [60, 59, 70, 129], [66, 65, 76, 135]]) + self.checkRawBlockContents( + block, + [ + [50, 49, 60, 119], + [55, 54, 65, 124], + [60, 59, 70, 129], + [66, 65, 76, 135], + ], + ) def testGDALResampling_downsampling_bilinear(self): with self.setupGDALResampling() as provider: - provider.setZoomedOutResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Bilinear) - provider.setZoomedInResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Cubic) # ignored + provider.setZoomedOutResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Bilinear + ) + provider.setZoomedInResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Cubic + ) # ignored block = provider.block(1, self._getExtentRequestInside(), 1, 1) self.checkRawBlockContents(block, [[84]]) def testGDALResampling_downsampling_cubic(self): with self.setupGDALResampling() as provider: - provider.setZoomedOutResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Cubic) - provider.setZoomedInResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Bilinear) # ignored + provider.setZoomedOutResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Cubic + ) + provider.setZoomedInResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Bilinear + ) # ignored block = provider.block(1, self._getExtentRequestInside(), 1, 1) self.checkRawBlockContents(block, [[86]]) @@ -439,28 +593,38 @@ def testGDALResampling_downsampling_bilinear_beyond_max_oversampling_factor(self with self.setupGDALResampling() as provider: provider.setMaxOversampling(1.5) - provider.setZoomedOutResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Bilinear) - provider.setZoomedInResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Cubic) # ignored + provider.setZoomedOutResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Bilinear + ) + provider.setZoomedInResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Cubic + ) # ignored block = provider.block(1, self._getExtentRequestInside(), 1, 1) # as we request at a x2 oversampling factor and the limit is 1.5 # fallback to an alternate method using first nearest resampling # and then bilinear self.checkRawBlockContents(block, [[120]]) - def testGDALResampling_downsampling_bilinear_beyond_max_oversampling_factor_containing_raster_extent(self): + def testGDALResampling_downsampling_bilinear_beyond_max_oversampling_factor_containing_raster_extent( + self, + ): xmin = 100 ymax = 1000 xres = 5 yres = 5 - extent = QgsRectangle(xmin - 10 * xres, - ymax - (5 + 10) * yres, - xmin + (5 + 10) * xres, - ymax + 10 * yres) + extent = QgsRectangle( + xmin - 10 * xres, + ymax - (5 + 10) * yres, + xmin + (5 + 10) * xres, + ymax + 10 * yres, + ) with self.setupGDALResampling() as provider: - provider.setZoomedInResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Bilinear) + provider.setZoomedInResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Bilinear + ) provider.setMaxOversampling(1) block = provider.block(1, extent, 3, 3) self.checkRawBlockContents(block, [[0, 0, 0], [0, 50.0, 0], [0, 0, 0]]) @@ -472,24 +636,33 @@ def testGDALResampling_nominal_resolution_containing_raster_extent(self): xres = 5 yres = 5 - extent = QgsRectangle(xmin - 2.25 * xres, - ymax - (5 + 2.75) * yres, - xmin + (5 + 2.75) * xres, - ymax + 2.25 * yres) + extent = QgsRectangle( + xmin - 2.25 * xres, + ymax - (5 + 2.75) * yres, + xmin + (5 + 2.75) * xres, + ymax + 2.25 * yres, + ) with self.setupGDALResampling() as provider: - provider.setZoomedInResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Bilinear) + provider.setZoomedInResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Bilinear + ) block = provider.block(1, extent, 10, 10) - self.checkRawBlockContents(block, [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 25, 35, 45, 130, 0, 0, 0], - [0, 0, 0, 35, 45, 55, 140, 0, 0, 0], - [0, 0, 0, 45, 55, 65, 150, 0, 0, 0], - [0, 0, 0, 55, 65, 75, 160, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) + self.checkRawBlockContents( + block, + [ + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 25, 35, 45, 130, 0, 0, 0], + [0, 0, 0, 35, 45, 55, 140, 0, 0, 0], + [0, 0, 0, 45, 55, 65, 150, 0, 0, 0], + [0, 0, 0, 55, 65, 75, 160, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + ], + ) def testGDALResampling_nominal_resolution_aligned_containing_raster_extent(self): @@ -498,24 +671,33 @@ def testGDALResampling_nominal_resolution_aligned_containing_raster_extent(self) xres = 5 yres = 5 - extent = QgsRectangle(xmin - 2 * xres, - ymax - (5 + 3) * yres, - xmin + (5 + 3) * xres, - ymax + 2 * yres) + extent = QgsRectangle( + xmin - 2 * xres, + ymax - (5 + 3) * yres, + xmin + (5 + 3) * xres, + ymax + 2 * yres, + ) with self.setupGDALResampling() as provider: - provider.setZoomedInResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Bilinear) + provider.setZoomedInResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Bilinear + ) block = provider.block(1, extent, 10, 10) - self.checkRawBlockContents(block, [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 10, 20, 30, 40, 150, 0, 0, 0], - [0, 0, 20, 30, 40, 50, 160, 0, 0, 0], - [0, 0, 30, 40, 50, 60, 170, 0, 0, 0], - [0, 0, 40, 50, 60, 70, 180, 0, 0, 0], - [0, 0, 50, 60, 70, 80, 190, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) + self.checkRawBlockContents( + block, + [ + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 10, 20, 30, 40, 150, 0, 0, 0], + [0, 0, 20, 30, 40, 50, 160, 0, 0, 0], + [0, 0, 30, 40, 50, 60, 170, 0, 0, 0], + [0, 0, 40, 50, 60, 70, 180, 0, 0, 0], + [0, 0, 50, 60, 70, 80, 190, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + ], + ) def testGDALResampling_nominal_resolution_slightly_overlapping_left_edge(self): @@ -524,13 +706,14 @@ def testGDALResampling_nominal_resolution_slightly_overlapping_left_edge(self): xres = 5 yres = 5 - extent = QgsRectangle(xmin - 0.2 * xres, - ymax - 4.25 * yres, - xmin + 1.8 * xres, - ymax - 2.25 * yres) + extent = QgsRectangle( + xmin - 0.2 * xres, ymax - 4.25 * yres, xmin + 1.8 * xres, ymax - 2.25 * yres + ) with self.setupGDALResampling() as provider: - provider.setZoomedInResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Bilinear) + provider.setZoomedInResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Bilinear + ) block = provider.block(1, extent, 2, 2) # The values in the left column are not subject to resampling currently self.checkRawBlockContents(block, [[30, 41], [50, 51]]) @@ -542,13 +725,14 @@ def testGDALResampling_nominal_resolution_slightly_overlapping_top_edge(self): xres = 5 yres = 5 - extent = QgsRectangle(xmin + 2.25 * xres, - ymax - 1.8 * yres, - xmin + 4.25 * xres, - ymax + 0.2 * yres) + extent = QgsRectangle( + xmin + 2.25 * xres, ymax - 1.8 * yres, xmin + 4.25 * xres, ymax + 0.2 * yres + ) with self.setupGDALResampling() as provider: - provider.setZoomedInResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Bilinear) + provider.setZoomedInResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Bilinear + ) block = provider.block(1, extent, 2, 2) # The values in the top line are not subject to resampling currently self.checkRawBlockContents(block, [[30, 150], [41, 76]]) @@ -560,13 +744,17 @@ def testGDALResampling_nominal_resolution_slightly_overlapping_right_edge(self): xres = 5 yres = 5 - extent = QgsRectangle(xmin + (5 - 2 + 0.2) * xres, - ymax - 4.25 * yres, - xmin + (5 + 0.2) * xres, - ymax - 2.25 * yres) + extent = QgsRectangle( + xmin + (5 - 2 + 0.2) * xres, + ymax - 4.25 * yres, + xmin + (5 + 0.2) * xres, + ymax - 2.25 * yres, + ) with self.setupGDALResampling() as provider: - provider.setZoomedInResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Bilinear) + provider.setZoomedInResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Bilinear + ) block = provider.block(1, extent, 2, 2) # The values in the right column are not subject to resampling currently self.checkRawBlockContents(block, [[85, 170], [95, 190]]) @@ -578,13 +766,17 @@ def testGDALResampling_nominal_resolution_slightly_overlapping_bottom_edge(self) xres = 5 yres = 5 - extent = QgsRectangle(xmin + 2.25 * xres, - ymax - (5 + 0.2) * yres, - xmin + 4.25 * xres, - ymax - (5 - 2 + 0.2) * yres) + extent = QgsRectangle( + xmin + 2.25 * xres, + ymax - (5 + 0.2) * yres, + xmin + 4.25 * xres, + ymax - (5 - 2 + 0.2) * yres, + ) with self.setupGDALResampling() as provider: - provider.setZoomedInResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Bilinear) + provider.setZoomedInResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Bilinear + ) block = provider.block(1, extent, 2, 2) # The values in the bottom line are not subject to resampling currently self.checkRawBlockContents(block, [[65, 100], [70, 190]]) @@ -597,16 +789,17 @@ def testGDALResampling_less_than_one_pixel(self): yres = 5 # Extent is less than one pixel. Simulates pixel identification - extent = QgsRectangle(xmin + 2.25 * xres, - ymax - 4.25 * yres, - xmin + 2.5 * xres, - ymax - 4.5 * yres) + extent = QgsRectangle( + xmin + 2.25 * xres, ymax - 4.25 * yres, xmin + 2.5 * xres, ymax - 4.5 * yres + ) with self.setupGDALResampling() as provider: - provider.setZoomedInResamplingMethod(QgsRasterDataProvider.ResamplingMethod.Bilinear) + provider.setZoomedInResamplingMethod( + QgsRasterDataProvider.ResamplingMethod.Bilinear + ) block = provider.block(1, extent, 1, 1) self.checkRawBlockContents(block, [[68]]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrastersinglecolorrenderer.py b/tests/src/python/test_qgsrastersinglecolorrenderer.py index 6ef5a3a420d1..5b70a5da780b 100644 --- a/tests/src/python/test_qgsrastersinglecolorrenderer.py +++ b/tests/src/python/test_qgsrastersinglecolorrenderer.py @@ -28,16 +28,15 @@ class TestQgsRasterSingleBandGrayRenderer(QgisTestCase): def testRenderer(self): - path = os.path.join(unitTestDataPath(), - 'landsat-int16-b1.tif') + path = os.path.join(unitTestDataPath(), "landsat-int16-b1.tif") info = QFileInfo(path) base_name = info.baseName() layer = QgsRasterLayer(path, base_name) - self.assertTrue(layer.isValid(), f'Raster not loaded: {path}') + self.assertTrue(layer.isValid(), f"Raster not loaded: {path}") - renderer = QgsRasterSingleColorRenderer(layer.dataProvider(), - 1, - QColor(255, 0, 0)) + renderer = QgsRasterSingleColorRenderer( + layer.dataProvider(), 1, QColor(255, 0, 0) + ) self.assertEqual(renderer.inputBand(), 1) self.assertEqual(renderer.usesBands(), [1]) @@ -52,11 +51,10 @@ def testRenderer(self): self.assertTrue( self.render_map_settings_check( - 'raster_single_color_renderer', - 'raster_single_color_renderer', - ms) + "raster_single_color_renderer", "raster_single_color_renderer", ms + ) ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrastertransparency.py b/tests/src/python/test_qgsrastertransparency.py index 0a27a945aafc..4d5d35721333 100644 --- a/tests/src/python/test_qgsrastertransparency.py +++ b/tests/src/python/test_qgsrastertransparency.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '29/02/2024' -__copyright__ = 'Copyright 2024, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "29/02/2024" +__copyright__ = "Copyright 2024, The QGIS Project" from qgis.PyQt.QtXml import QDomDocument @@ -18,34 +19,54 @@ class TestQgsRasterTransparency(TestCase): def test_transparency_single_repr(self): - self.assertEqual(repr(QgsRasterTransparency.TransparentSingleValuePixel(1, 10, 0.3)), - '') + self.assertEqual( + repr(QgsRasterTransparency.TransparentSingleValuePixel(1, 10, 0.3)), + "", + ) def test_transparency_single_equality(self): - self.assertEqual(QgsRasterTransparency.TransparentSingleValuePixel(1, 10, 0.3), - QgsRasterTransparency.TransparentSingleValuePixel(1, 10, 0.3)) - self.assertNotEqual(QgsRasterTransparency.TransparentSingleValuePixel(1, 10, 0.3), - QgsRasterTransparency.TransparentSingleValuePixel(2, 10, 0.3)) - self.assertNotEqual(QgsRasterTransparency.TransparentSingleValuePixel(1, 10, 0.3), - QgsRasterTransparency.TransparentSingleValuePixel(1, 11, 0.3)) - self.assertNotEqual(QgsRasterTransparency.TransparentSingleValuePixel(1, 10, 0.3), - QgsRasterTransparency.TransparentSingleValuePixel(1, 10, 0.4)) + self.assertEqual( + QgsRasterTransparency.TransparentSingleValuePixel(1, 10, 0.3), + QgsRasterTransparency.TransparentSingleValuePixel(1, 10, 0.3), + ) + self.assertNotEqual( + QgsRasterTransparency.TransparentSingleValuePixel(1, 10, 0.3), + QgsRasterTransparency.TransparentSingleValuePixel(2, 10, 0.3), + ) + self.assertNotEqual( + QgsRasterTransparency.TransparentSingleValuePixel(1, 10, 0.3), + QgsRasterTransparency.TransparentSingleValuePixel(1, 11, 0.3), + ) + self.assertNotEqual( + QgsRasterTransparency.TransparentSingleValuePixel(1, 10, 0.3), + QgsRasterTransparency.TransparentSingleValuePixel(1, 10, 0.4), + ) def test_transparency_single_value(self): transparency = QgsRasterTransparency() self.assertFalse(transparency.transparentSingleValuePixelList()) - transparency.setTransparentSingleValuePixelList([ - QgsRasterTransparency.TransparentSingleValuePixel(10, 20, 0.3), - QgsRasterTransparency.TransparentSingleValuePixel(30, 40, 0.6, includeMaximum=False), - QgsRasterTransparency.TransparentSingleValuePixel(50, 60, 0.9, includeMinimum=False) - ]) + transparency.setTransparentSingleValuePixelList( + [ + QgsRasterTransparency.TransparentSingleValuePixel(10, 20, 0.3), + QgsRasterTransparency.TransparentSingleValuePixel( + 30, 40, 0.6, includeMaximum=False + ), + QgsRasterTransparency.TransparentSingleValuePixel( + 50, 60, 0.9, includeMinimum=False + ), + ] + ) self.assertEqual( transparency.transparentSingleValuePixelList(), [ QgsRasterTransparency.TransparentSingleValuePixel(10, 20, 0.3), - QgsRasterTransparency.TransparentSingleValuePixel(30, 40, 0.6, includeMaximum=False), - QgsRasterTransparency.TransparentSingleValuePixel(50, 60, 0.9, includeMinimum=False) - ] + QgsRasterTransparency.TransparentSingleValuePixel( + 30, 40, 0.6, includeMaximum=False + ), + QgsRasterTransparency.TransparentSingleValuePixel( + 50, 60, 0.9, includeMinimum=False + ), + ], ) self.assertEqual(transparency.alphaValue(0), 255) self.assertEqual(transparency.alphaValue(10), 76) @@ -76,52 +97,90 @@ def test_transparency_single_value(self): self.assertEqual(transparency.opacityForValue(61), 1.0) def test_transparency_three_repr(self): - self.assertEqual(repr(QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3)), - '') - self.assertEqual(repr(QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 3, 4, 5)), - '') + self.assertEqual( + repr(QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3)), + "", + ) + self.assertEqual( + repr( + QgsRasterTransparency.TransparentThreeValuePixel( + 1, 10, 20, 0.3, 3, 4, 5 + ) + ), + "", + ) def test_transparency_three_equality(self): - self.assertEqual(QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3), - QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3)) - self.assertEqual(QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5, 6, 7), - QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5, 6, 7)) - self.assertNotEqual(QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3), - QgsRasterTransparency.TransparentThreeValuePixel(2, 10, 20, 0.3)) - self.assertNotEqual(QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3), - QgsRasterTransparency.TransparentThreeValuePixel(1, 11, 20, 0.3)) - self.assertNotEqual(QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3), - QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 25, 0.3)) - self.assertNotEqual(QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3), - QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.4)) - self.assertNotEqual(QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5), - QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3)) - self.assertNotEqual(QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3), - QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5)) - self.assertNotEqual(QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5, 6), - QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5)) - self.assertNotEqual(QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5, 6), - QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 6, 5)) - self.assertNotEqual(QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5, 6, 7), - QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5, 6)) - self.assertNotEqual(QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5, 6), - QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5, 6, 7)) + self.assertEqual( + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3), + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3), + ) + self.assertEqual( + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5, 6, 7), + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5, 6, 7), + ) + self.assertNotEqual( + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3), + QgsRasterTransparency.TransparentThreeValuePixel(2, 10, 20, 0.3), + ) + self.assertNotEqual( + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3), + QgsRasterTransparency.TransparentThreeValuePixel(1, 11, 20, 0.3), + ) + self.assertNotEqual( + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3), + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 25, 0.3), + ) + self.assertNotEqual( + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3), + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.4), + ) + self.assertNotEqual( + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5), + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3), + ) + self.assertNotEqual( + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3), + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5), + ) + self.assertNotEqual( + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5, 6), + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5), + ) + self.assertNotEqual( + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5, 6), + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 6, 5), + ) + self.assertNotEqual( + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5, 6, 7), + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5, 6), + ) + self.assertNotEqual( + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5, 6), + QgsRasterTransparency.TransparentThreeValuePixel(1, 10, 20, 0.3, 5, 6, 7), + ) def test_transparency_three_value(self): transparency = QgsRasterTransparency() self.assertFalse(transparency.transparentThreeValuePixelList()) - transparency.setTransparentThreeValuePixelList([ - QgsRasterTransparency.TransparentThreeValuePixel(10, 20, 30, 0.3), - QgsRasterTransparency.TransparentThreeValuePixel(30, 40, 50, 0.6), - QgsRasterTransparency.TransparentThreeValuePixel(90, 140, 150, 0.6, 8, 9, 10) - ]) + transparency.setTransparentThreeValuePixelList( + [ + QgsRasterTransparency.TransparentThreeValuePixel(10, 20, 30, 0.3), + QgsRasterTransparency.TransparentThreeValuePixel(30, 40, 50, 0.6), + QgsRasterTransparency.TransparentThreeValuePixel( + 90, 140, 150, 0.6, 8, 9, 10 + ), + ] + ) self.assertEqual( transparency.transparentThreeValuePixelList(), [ QgsRasterTransparency.TransparentThreeValuePixel(10, 20, 30, 0.3), QgsRasterTransparency.TransparentThreeValuePixel(30, 40, 50, 0.6), - QgsRasterTransparency.TransparentThreeValuePixel(90, 140, 150, 0.6, 8, 9, 10) - ] + QgsRasterTransparency.TransparentThreeValuePixel( + 90, 140, 150, 0.6, 8, 9, 10 + ), + ], ) self.assertEqual(transparency.alphaValue(0, 0, 0), 255) self.assertEqual(transparency.alphaValue(10, 0, 0), 255) @@ -157,19 +216,25 @@ def test_transparency_three_value(self): def test_read_write_xml(self): transparency = QgsRasterTransparency() - transparency.setTransparentThreeValuePixelList([ - QgsRasterTransparency.TransparentThreeValuePixel(10, 20, 30, 0.3), - QgsRasterTransparency.TransparentThreeValuePixel(30, 40, 50, 0.6), - QgsRasterTransparency.TransparentThreeValuePixel(30, 40, 50, 0.6, 5, 6, 7), - ]) - transparency.setTransparentSingleValuePixelList([ - QgsRasterTransparency.TransparentSingleValuePixel(10, 20, 0.3), - QgsRasterTransparency.TransparentSingleValuePixel(30, 40, 0.6), - QgsRasterTransparency.TransparentSingleValuePixel(50, 60, 0.9) - ]) + transparency.setTransparentThreeValuePixelList( + [ + QgsRasterTransparency.TransparentThreeValuePixel(10, 20, 30, 0.3), + QgsRasterTransparency.TransparentThreeValuePixel(30, 40, 50, 0.6), + QgsRasterTransparency.TransparentThreeValuePixel( + 30, 40, 50, 0.6, 5, 6, 7 + ), + ] + ) + transparency.setTransparentSingleValuePixelList( + [ + QgsRasterTransparency.TransparentSingleValuePixel(10, 20, 0.3), + QgsRasterTransparency.TransparentSingleValuePixel(30, 40, 0.6), + QgsRasterTransparency.TransparentSingleValuePixel(50, 60, 0.9), + ] + ) doc = QDomDocument("testdoc") - parent = doc.createElement('test') + parent = doc.createElement("test") transparency.writeXml(doc, parent) transparency2 = QgsRasterTransparency() @@ -180,18 +245,20 @@ def test_read_write_xml(self): [ QgsRasterTransparency.TransparentSingleValuePixel(10, 20, 0.3), QgsRasterTransparency.TransparentSingleValuePixel(30, 40, 0.6), - QgsRasterTransparency.TransparentSingleValuePixel(50, 60, 0.9) - ] + QgsRasterTransparency.TransparentSingleValuePixel(50, 60, 0.9), + ], ) self.assertEqual( transparency2.transparentThreeValuePixelList(), [ QgsRasterTransparency.TransparentThreeValuePixel(10, 20, 30, 0.3), QgsRasterTransparency.TransparentThreeValuePixel(30, 40, 50, 0.6), - QgsRasterTransparency.TransparentThreeValuePixel(30, 40, 50, 0.6, 5, 6, 7), - ] + QgsRasterTransparency.TransparentThreeValuePixel( + 30, 40, 50, 0.6, 5, 6, 7 + ), + ], ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrastertransparencywidget.py b/tests/src/python/test_qgsrastertransparencywidget.py index 9e90ae50c6d8..e052cfeb7583 100644 --- a/tests/src/python/test_qgsrastertransparencywidget.py +++ b/tests/src/python/test_qgsrastertransparencywidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '07/06/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "07/06/2018" +__copyright__ = "Copyright 2018, The QGIS Project" import pathlib @@ -30,7 +31,7 @@ def no_data_values(layer: QgsRasterLayer): return [n.min() for n in layer.dataProvider().userNoDataValues(1)] def test_transparency_widget(self): - path = pathlib.Path(unitTestDataPath()) / 'landsat_4326.tif' + path = pathlib.Path(unitTestDataPath()) / "landsat_4326.tif" self.assertTrue(path.is_file()) layer = QgsRasterLayer(path.as_posix()) self.assertTrue(layer.isValid()) @@ -39,14 +40,20 @@ def test_transparency_widget(self): no_data_value = -99 nd_ref = [no_data_value] - layer.dataProvider().setUserNoDataValue(1, [QgsRasterRange(no_data_value, no_data_value)]) + layer.dataProvider().setUserNoDataValue( + 1, [QgsRasterRange(no_data_value, no_data_value)] + ) nd0 = self.no_data_values(layer) self.assertListEqual(nd0, nd_ref) w = QgsRasterTransparencyWidget(layer, canvas) self.assertIsInstance(w, QgsRasterTransparencyWidget) nd1 = self.no_data_values(layer) - self.assertListEqual(nd1, nd_ref, msg='Widget initialization should not change the "no data value"') + self.assertListEqual( + nd1, + nd_ref, + msg='Widget initialization should not change the "no data value"', + ) w.syncToLayer() nd2 = self.no_data_values(layer) @@ -54,16 +61,22 @@ def test_transparency_widget(self): w.syncToLayer() nd3 = self.no_data_values(layer) - self.assertListEqual(nd3, nd_ref, msg='repeated syncToLayer changed the "no data value"') + self.assertListEqual( + nd3, nd_ref, msg='repeated syncToLayer changed the "no data value"' + ) w.apply() nd4 = self.no_data_values(layer) - self.assertListEqual(nd4, nd_ref, msg='apply changed the "no data value" but should not') + self.assertListEqual( + nd4, nd_ref, msg='apply changed the "no data value" but should not' + ) w.apply() nd5 = self.no_data_values(layer) - self.assertListEqual(nd5, nd_ref, msg='repeated apply changed the "no data value" but should not') + self.assertListEqual( + nd5, nd_ref, msg='repeated apply changed the "no data value" but should not' + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsratiolockbutton.py b/tests/src/python/test_qgsratiolockbutton.py index 37866904c6e8..267e02d814e3 100644 --- a/tests/src/python/test_qgsratiolockbutton.py +++ b/tests/src/python/test_qgsratiolockbutton.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '18/07/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "18/07/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import unittest @@ -22,7 +23,7 @@ class TestQgsRatioLockButton(QgisTestCase): def testLinkedWidgets(self): - """ test linking spin boxes to combobox""" + """test linking spin boxes to combobox""" w = QgsRatioLockButton() spin_width = QDoubleSpinBox() @@ -117,7 +118,9 @@ def testResetRatio(self): spin_width.blockSignals(False) spin_height.setValue(2000) - self.assertEqual(spin_width.value(), 4000) # signals were blocked, so ratio wasn't updated + self.assertEqual( + spin_width.value(), 4000 + ) # signals were blocked, so ratio wasn't updated spin_width.blockSignals(True) spin_width.setValue(2000) @@ -127,5 +130,5 @@ def testResetRatio(self): self.assertEqual(spin_width.value(), 1000) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsreadwritecontext.py b/tests/src/python/test_qgsreadwritecontext.py index e7bcef726a71..07383ee51032 100644 --- a/tests/src/python/test_qgsreadwritecontext.py +++ b/tests/src/python/test_qgsreadwritecontext.py @@ -6,9 +6,9 @@ (at your option) any later version. """ -__author__ = 'Denis Rouzaud' -__date__ = '28.02.2018' -__copyright__ = 'Copyright 2017, The QGIS Project' +__author__ = "Denis Rouzaud" +__date__ = "28.02.2018" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.core import Qgis, QgsReadWriteContext @@ -19,43 +19,65 @@ class TestQgsReadWriteContext(unittest.TestCase): def testEnterCategory(self): context = QgsReadWriteContext() - context.pushMessage('msg0', Qgis.MessageLevel.Critical) - with QgsReadWriteContext.enterCategory(context, 'cat1'): - context.pushMessage('msg1', Qgis.MessageLevel.Warning) - with QgsReadWriteContext.enterCategory(context, 'cat2', "detail2"): - context.pushMessage('msg2') - context.pushMessage('msg3') - context.pushMessage('msg4') + context.pushMessage("msg0", Qgis.MessageLevel.Critical) + with QgsReadWriteContext.enterCategory(context, "cat1"): + context.pushMessage("msg1", Qgis.MessageLevel.Warning) + with QgsReadWriteContext.enterCategory(context, "cat2", "detail2"): + context.pushMessage("msg2") + context.pushMessage("msg3") + context.pushMessage("msg4") messages = context.takeMessages() - self.assertEqual(messages[0].message(), 'msg0') + self.assertEqual(messages[0].message(), "msg0") self.assertEqual(messages[0].level(), Qgis.MessageLevel.Critical) self.assertEqual(messages[0].categories(), []) - self.assertEqual(messages[1].message(), 'msg1') + self.assertEqual(messages[1].message(), "msg1") self.assertEqual(messages[1].level(), Qgis.MessageLevel.Warning) - self.assertEqual(messages[1].categories(), ['cat1']) + self.assertEqual(messages[1].categories(), ["cat1"]) - self.assertEqual(messages[2].message(), 'msg2') - self.assertEqual(messages[2].categories(), ['cat1', 'cat2 :: detail2']) + self.assertEqual(messages[2].message(), "msg2") + self.assertEqual(messages[2].categories(), ["cat1", "cat2 :: detail2"]) - self.assertEqual(messages[3].message(), 'msg3') - self.assertEqual(messages[3].categories(), ['cat1']) + self.assertEqual(messages[3].message(), "msg3") + self.assertEqual(messages[3].categories(), ["cat1"]) - self.assertEqual(messages[4].message(), 'msg4') + self.assertEqual(messages[4].message(), "msg4") self.assertEqual(messages[4].categories(), []) def test_message_equality(self): """ Test QgsReadWriteContext.ReadWriteMessage equality operator """ - m1 = QgsReadWriteContext.ReadWriteMessage('m1', Qgis.MessageLevel.Info, ['cat1', 'cat2']) - self.assertEqual(m1, QgsReadWriteContext.ReadWriteMessage('m1', Qgis.MessageLevel.Info, ['cat1', 'cat2'])) - self.assertNotEqual(m1, QgsReadWriteContext.ReadWriteMessage('m2', Qgis.MessageLevel.Info, ['cat1', 'cat2'])) - self.assertNotEqual(m1, QgsReadWriteContext.ReadWriteMessage('m1', Qgis.MessageLevel.Warning, ['cat1', 'cat2'])) - self.assertNotEqual(m1, QgsReadWriteContext.ReadWriteMessage('m1', Qgis.MessageLevel.Info, ['cat3', 'cat2'])) - - -if __name__ == '__main__': + m1 = QgsReadWriteContext.ReadWriteMessage( + "m1", Qgis.MessageLevel.Info, ["cat1", "cat2"] + ) + self.assertEqual( + m1, + QgsReadWriteContext.ReadWriteMessage( + "m1", Qgis.MessageLevel.Info, ["cat1", "cat2"] + ), + ) + self.assertNotEqual( + m1, + QgsReadWriteContext.ReadWriteMessage( + "m2", Qgis.MessageLevel.Info, ["cat1", "cat2"] + ), + ) + self.assertNotEqual( + m1, + QgsReadWriteContext.ReadWriteMessage( + "m1", Qgis.MessageLevel.Warning, ["cat1", "cat2"] + ), + ) + self.assertNotEqual( + m1, + QgsReadWriteContext.ReadWriteMessage( + "m1", Qgis.MessageLevel.Info, ["cat3", "cat2"] + ), + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrecentcoordinatereferencesystemsmodel.py b/tests/src/python/test_qgsrecentcoordinatereferencesystemsmodel.py index cbe50896aca5..576219537c25 100644 --- a/tests/src/python/test_qgsrecentcoordinatereferencesystemsmodel.py +++ b/tests/src/python/test_qgsrecentcoordinatereferencesystemsmodel.py @@ -5,16 +5,13 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2022 by Nyall Dawson' -__date__ = '12/07/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' +__author__ = "(C) 2022 by Nyall Dawson" +__date__ = "12/07/2023" +__copyright__ = "Copyright 2023, The QGIS Project" -from qgis.PyQt.QtCore import ( - Qt, - QModelIndex, - QCoreApplication -) + +from qgis.PyQt.QtCore import Qt, QModelIndex, QCoreApplication from qgis.core import ( Qgis, QgsApplication, @@ -24,7 +21,7 @@ from qgis.gui import ( QgsRecentCoordinateReferenceSystemsModel, QgsRecentCoordinateReferenceSystemsProxyModel, - QgsCoordinateReferenceSystemProxyModel + QgsCoordinateReferenceSystemProxyModel, ) import unittest @@ -53,83 +50,128 @@ def test_model(self): self.assertFalse(model.index(-1, 0, QModelIndex()).isValid()) self.assertFalse(model.index(0, 0, QModelIndex()).isValid()) self.assertFalse(model.index(1, 0, QModelIndex()).isValid()) - self.assertIsNone(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) + self.assertIsNone( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) self.assertFalse(model.crs(model.index(0, 0, QModelIndex())).isValid()) self.assertFalse(model.crs(model.index(-1, 0, QModelIndex())).isValid()) self.assertFalse(model.crs(model.index(1, 0, QModelIndex())).isValid()) # push a crs registry = QgsApplication.coordinateReferenceSystemRegistry() - registry.pushRecent(QgsCoordinateReferenceSystem('EPSG:3111')) + registry.pushRecent(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertEqual(model.rowCount(), 1) self.assertTrue(model.index(0, 0, QModelIndex()).isValid()) self.assertFalse(model.index(1, 0, QModelIndex()).isValid()) self.assertEqual( - model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'EPSG:3111 - GDA94 / Vicgrid') - self.assertIsNone(model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "EPSG:3111 - GDA94 / Vicgrid", + ) self.assertIsNone( - model.data(model.index(-1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.crs(model.index(0, 0, QModelIndex())), - QgsCoordinateReferenceSystem('EPSG:3111')) + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertIsNone( + model.data(model.index(-1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertEqual( + model.crs(model.index(0, 0, QModelIndex())), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) # push another crs - registry.pushRecent(QgsCoordinateReferenceSystem('EPSG:4326')) + registry.pushRecent(QgsCoordinateReferenceSystem("EPSG:4326")) self.assertEqual(model.rowCount(), 2) self.assertTrue(model.index(0, 0, QModelIndex()).isValid()) self.assertTrue(model.index(1, 0, QModelIndex()).isValid()) self.assertFalse(model.index(2, 0, QModelIndex()).isValid()) self.assertEqual( - model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'EPSG:4326 - WGS 84') + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "EPSG:4326 - WGS 84", + ) + self.assertEqual( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "EPSG:3111 - GDA94 / Vicgrid", + ) + self.assertIsNone( + model.data(model.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) self.assertEqual( - model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'EPSG:3111 - GDA94 / Vicgrid') - self.assertIsNone(model.data(model.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.crs(model.index(0, 0, QModelIndex())), - QgsCoordinateReferenceSystem('EPSG:4326')) - self.assertEqual(model.crs(model.index(1, 0, QModelIndex())), - QgsCoordinateReferenceSystem('EPSG:3111')) + model.crs(model.index(0, 0, QModelIndex())), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + self.assertEqual( + model.crs(model.index(1, 0, QModelIndex())), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) # push first crs back to top - registry.pushRecent(QgsCoordinateReferenceSystem('EPSG:3111')) + registry.pushRecent(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertEqual(model.rowCount(), 2) self.assertTrue(model.index(0, 0, QModelIndex()).isValid()) self.assertTrue(model.index(1, 0, QModelIndex()).isValid()) self.assertFalse(model.index(2, 0, QModelIndex()).isValid()) self.assertEqual( - model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'EPSG:3111 - GDA94 / Vicgrid') + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "EPSG:3111 - GDA94 / Vicgrid", + ) + self.assertEqual( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "EPSG:4326 - WGS 84", + ) + self.assertIsNone( + model.data(model.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertEqual( + model.crs(model.index(0, 0, QModelIndex())), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) self.assertEqual( - model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'EPSG:4326 - WGS 84') - self.assertIsNone(model.data(model.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.crs(model.index(0, 0, QModelIndex())), - QgsCoordinateReferenceSystem('EPSG:3111')) - self.assertEqual(model.crs(model.index(1, 0, QModelIndex())), - QgsCoordinateReferenceSystem('EPSG:4326')) + model.crs(model.index(1, 0, QModelIndex())), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) # remove crs (not in recent list!) - registry.removeRecent(QgsCoordinateReferenceSystem('EPSG:3857')) + registry.removeRecent(QgsCoordinateReferenceSystem("EPSG:3857")) self.assertEqual(model.rowCount(), 2) self.assertTrue(model.index(0, 0, QModelIndex()).isValid()) self.assertTrue(model.index(1, 0, QModelIndex()).isValid()) self.assertFalse(model.index(2, 0, QModelIndex()).isValid()) self.assertEqual( - model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'EPSG:3111 - GDA94 / Vicgrid') + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "EPSG:3111 - GDA94 / Vicgrid", + ) + self.assertEqual( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "EPSG:4326 - WGS 84", + ) + self.assertIsNone( + model.data(model.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) self.assertEqual( - model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'EPSG:4326 - WGS 84') - self.assertIsNone(model.data(model.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.crs(model.index(0, 0, QModelIndex())), - QgsCoordinateReferenceSystem('EPSG:3111')) - self.assertEqual(model.crs(model.index(1, 0, QModelIndex())), - QgsCoordinateReferenceSystem('EPSG:4326')) + model.crs(model.index(0, 0, QModelIndex())), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) + self.assertEqual( + model.crs(model.index(1, 0, QModelIndex())), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) # remove crs (in recent list!) - registry.removeRecent(QgsCoordinateReferenceSystem('EPSG:3111')) + registry.removeRecent(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertEqual(model.rowCount(), 1) self.assertTrue(model.index(0, 0, QModelIndex()).isValid()) self.assertFalse(model.index(1, 0, QModelIndex()).isValid()) self.assertEqual( - model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'EPSG:4326 - WGS 84') - self.assertIsNone(model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.crs(model.index(0, 0, QModelIndex())), - QgsCoordinateReferenceSystem('EPSG:4326')) + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "EPSG:4326 - WGS 84", + ) + self.assertIsNone( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertEqual( + model.crs(model.index(0, 0, QModelIndex())), + QgsCoordinateReferenceSystem("EPSG:4326"), + ) # clear list registry.clearRecent() @@ -137,23 +179,19 @@ def test_model(self): # model limit of 30 items should consider crs types for _id in range(32510, 32550): - registry.pushRecent( - QgsCoordinateReferenceSystem(f"EPSG:{_id}") - ) + registry.pushRecent(QgsCoordinateReferenceSystem(f"EPSG:{_id}")) self.assertEqual(model.rowCount(), 30) for row in range(30): self.assertEqual( model.crs(model.index(row, 0, QModelIndex())).authid(), - f"EPSG:{32549 - row}" + f"EPSG:{32549 - row}", ) # these are vertical CRS, so their addition should NOT cause # the existing items to drop for _id in range(115851, 115867): - registry.pushRecent( - QgsCoordinateReferenceSystem(f"ESRI:{_id}") - ) + registry.pushRecent(QgsCoordinateReferenceSystem(f"ESRI:{_id}")) self.assertEqual(model.rowCount(), 46) def test_proxy(self): @@ -167,45 +205,57 @@ def test_proxy(self): self.assertFalse(model.index(0, 0, QModelIndex()).isValid()) self.assertFalse(model.index(1, 0, QModelIndex()).isValid()) self.assertIsNone( - model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) self.assertFalse(model.crs(model.index(0, 0, QModelIndex())).isValid()) - self.assertFalse( - model.crs(model.index(-1, 0, QModelIndex())).isValid()) + self.assertFalse(model.crs(model.index(-1, 0, QModelIndex())).isValid()) self.assertFalse(model.crs(model.index(1, 0, QModelIndex())).isValid()) # push a crs - registry.pushRecent(QgsCoordinateReferenceSystem('EPSG:3111')) + registry.pushRecent(QgsCoordinateReferenceSystem("EPSG:3111")) self.assertEqual(model.rowCount(), 1) self.assertTrue(model.index(0, 0, QModelIndex()).isValid()) self.assertFalse(model.index(1, 0, QModelIndex()).isValid()) self.assertEqual( model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'EPSG:3111 - GDA94 / Vicgrid') + "EPSG:3111 - GDA94 / Vicgrid", + ) self.assertIsNone( - model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) self.assertIsNone( - model.data(model.index(-1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.crs(model.index(0, 0, QModelIndex())), - QgsCoordinateReferenceSystem('EPSG:3111')) + model.data(model.index(-1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertEqual( + model.crs(model.index(0, 0, QModelIndex())), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) # push a vertical crs - registry.pushRecent(QgsCoordinateReferenceSystem('ESRI:115851')) + registry.pushRecent(QgsCoordinateReferenceSystem("ESRI:115851")) self.assertEqual(model.rowCount(), 2) self.assertTrue(model.index(0, 0, QModelIndex()).isValid()) self.assertTrue(model.index(1, 0, QModelIndex()).isValid()) self.assertFalse(model.index(2, 0, QModelIndex()).isValid()) self.assertEqual( model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'ESRI:115851 - SIRGAS-CON_DGF00P01') + "ESRI:115851 - SIRGAS-CON_DGF00P01", + ) self.assertEqual( model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'EPSG:3111 - GDA94 / Vicgrid') + "EPSG:3111 - GDA94 / Vicgrid", + ) self.assertIsNone( - model.data(model.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.crs(model.index(0, 0, QModelIndex())), - QgsCoordinateReferenceSystem('ESRI:115851')) - self.assertEqual(model.crs(model.index(1, 0, QModelIndex())), - QgsCoordinateReferenceSystem('EPSG:3111')) + model.data(model.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertEqual( + model.crs(model.index(0, 0, QModelIndex())), + QgsCoordinateReferenceSystem("ESRI:115851"), + ) + self.assertEqual( + model.crs(model.index(1, 0, QModelIndex())), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) # add filter model.setFilters(QgsCoordinateReferenceSystemProxyModel.Filter.FilterHorizontal) @@ -214,11 +264,15 @@ def test_proxy(self): self.assertFalse(model.index(1, 0, QModelIndex()).isValid()) self.assertEqual( model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'EPSG:3111 - GDA94 / Vicgrid') + "EPSG:3111 - GDA94 / Vicgrid", + ) self.assertIsNone( - model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.crs(model.index(0, 0, QModelIndex())), - QgsCoordinateReferenceSystem('EPSG:3111')) + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertEqual( + model.crs(model.index(0, 0, QModelIndex())), + QgsCoordinateReferenceSystem("EPSG:3111"), + ) model.setFilters(QgsCoordinateReferenceSystemProxyModel.Filter.FilterVertical) self.assertEqual(model.rowCount(), 1) @@ -226,12 +280,16 @@ def test_proxy(self): self.assertFalse(model.index(1, 0, QModelIndex()).isValid()) self.assertEqual( model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), - 'ESRI:115851 - SIRGAS-CON_DGF00P01') + "ESRI:115851 - SIRGAS-CON_DGF00P01", + ) self.assertIsNone( - model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.crs(model.index(0, 0, QModelIndex())), - QgsCoordinateReferenceSystem('ESRI:115851')) + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertEqual( + model.crs(model.index(0, 0, QModelIndex())), + QgsCoordinateReferenceSystem("ESRI:115851"), + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrectangle.py b/tests/src/python/test_qgsrectangle.py index 0023001024ea..3aa599e63f81 100644 --- a/tests/src/python/test_qgsrectangle.py +++ b/tests/src/python/test_qgsrectangle.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Tim Sutton' -__date__ = '20/08/2012' -__copyright__ = 'Copyright 2012, The QGIS Project' + +__author__ = "Tim Sutton" +__date__ = "20/08/2012" +__copyright__ = "Copyright 2012, The QGIS Project" from qgis.core import QgsPointXY, QgsRectangle, QgsVector import unittest @@ -112,46 +113,47 @@ def testUnion(self): def testAsWktCoordinates(self): """Test that we can get a proper wkt representation fo the rect""" rect1 = QgsRectangle(0.0, 0.0, 5.0, 5.0) - myExpectedWkt = ('0 0, ' - '5 5') + myExpectedWkt = "0 0, " "5 5" myWkt = rect1.asWktCoordinates() - myMessage = f'Expected: {myExpectedWkt}\nGot: {myWkt}\n' + myMessage = f"Expected: {myExpectedWkt}\nGot: {myWkt}\n" self.assertTrue(compareWkt(myWkt, myExpectedWkt), myMessage) def testAsWktPolygon(self): """Test that we can get a proper rect wkt polygon representation for rect""" rect1 = QgsRectangle(0.0, 0.0, 5.0, 5.0) - myExpectedWkt = ('Polygon ((0 0, ' - '5 0, ' - '5 5, ' - '0 5, ' - '0 0))') + myExpectedWkt = "Polygon ((0 0, " "5 0, " "5 5, " "0 5, " "0 0))" myWkt = rect1.asWktPolygon() - myMessage = f'Expected: {myExpectedWkt}\nGot: {myWkt}\n' + myMessage = f"Expected: {myExpectedWkt}\nGot: {myWkt}\n" self.assertTrue(compareWkt(myWkt, myExpectedWkt), myMessage) def testToString(self): """Test the different string representations""" - self.assertEqual(QgsRectangle().toString(), 'Null') + self.assertEqual(QgsRectangle().toString(), "Null") rect = QgsRectangle(0, 0.1, 0.2, 0.3) - self.assertEqual(rect.toString(), '0.0000000000000000,0.1000000000000000 : 0.2000000000000000,0.3000000000000000') + self.assertEqual( + rect.toString(), + "0.0000000000000000,0.1000000000000000 : 0.2000000000000000,0.3000000000000000", + ) # can't test the actual result here, because floating point inaccuracies mean the result is unpredictable # at this precision self.assertEqual(len(rect.toString(20)), 93) - self.assertEqual(rect.toString(0), '0,0 : 0,0') - self.assertEqual(rect.toString(2), '0.00,0.10 : 0.20,0.30') - self.assertEqual(rect.toString(1), '0.0,0.1 : 0.2,0.3') - self.assertEqual(rect.toString(-1), '0.00,0.10 : 0.20,0.30') + self.assertEqual(rect.toString(0), "0,0 : 0,0") + self.assertEqual(rect.toString(2), "0.00,0.10 : 0.20,0.30") + self.assertEqual(rect.toString(1), "0.0,0.1 : 0.2,0.3") + self.assertEqual(rect.toString(-1), "0.00,0.10 : 0.20,0.30") rect = QgsRectangle(5000000.01111, -0.3, 5000000.44111, 99.8) - self.assertEqual(rect.toString(-1), '5000000.01,-0.30 : 5000000.44,99.80') + self.assertEqual(rect.toString(-1), "5000000.01,-0.30 : 5000000.44,99.80") def testAsPolygon(self): """Test string representation as polygon""" - self.assertEqual(QgsRectangle().asPolygon(), 'EMPTY') - self.assertEqual(QgsRectangle(0, 0.1, 0.2, 0.3).asPolygon(), '0.00000000 0.10000000, 0.00000000 0.30000000, 0.20000000 0.30000000, 0.20000000 0.10000000, 0.00000000 0.10000000') + self.assertEqual(QgsRectangle().asPolygon(), "EMPTY") + self.assertEqual( + QgsRectangle(0, 0.1, 0.2, 0.3).asPolygon(), + "0.00000000 0.10000000, 0.00000000 0.30000000, 0.20000000 0.30000000, 0.20000000 0.10000000, 0.00000000 0.10000000", + ) def testToBox3d(self): rect = QgsRectangle(0, 0.1, 0.2, 0.3) @@ -181,5 +183,5 @@ def testInvert(self): self.assertEqual(rect.yMaximum(), 0.2) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsreferencedgeometry.py b/tests/src/python/test_qgsreferencedgeometry.py index e4a15d67b415..85c8df0fce9c 100644 --- a/tests/src/python/test_qgsreferencedgeometry.py +++ b/tests/src/python/test_qgsreferencedgeometry.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '31/08/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "31/08/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtCore import QVariant from qgis.core import ( @@ -17,7 +18,7 @@ QgsReferencedPointXY, QgsReferencedRectangle, QgsReferencedGeometry, - QgsGeometry + QgsGeometry, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -28,23 +29,31 @@ class TestQgsReferencedGeometry(QgisTestCase): def testRectangle(self): - rect = QgsReferencedRectangle(QgsRectangle(0.0, 1.0, 20.0, 10.0), QgsCoordinateReferenceSystem('epsg:3111')) + rect = QgsReferencedRectangle( + QgsRectangle(0.0, 1.0, 20.0, 10.0), + QgsCoordinateReferenceSystem("epsg:3111"), + ) self.assertEqual(rect.xMinimum(), 0.0) self.assertEqual(rect.yMinimum(), 1.0) self.assertEqual(rect.xMaximum(), 20.0) self.assertEqual(rect.yMaximum(), 10.0) - self.assertEqual(rect.crs().authid(), 'EPSG:3111') + self.assertEqual(rect.crs().authid(), "EPSG:3111") - rect.setCrs(QgsCoordinateReferenceSystem('epsg:28356')) - self.assertEqual(rect.crs().authid(), 'EPSG:28356') + rect.setCrs(QgsCoordinateReferenceSystem("epsg:28356")) + self.assertEqual(rect.crs().authid(), "EPSG:28356") # in variant - v = QVariant(QgsReferencedRectangle(QgsRectangle(1.0, 2.0, 3.0, 4.0), QgsCoordinateReferenceSystem('epsg:3111'))) + v = QVariant( + QgsReferencedRectangle( + QgsRectangle(1.0, 2.0, 3.0, 4.0), + QgsCoordinateReferenceSystem("epsg:3111"), + ) + ) self.assertEqual(v.value().xMinimum(), 1.0) self.assertEqual(v.value().yMinimum(), 2.0) self.assertEqual(v.value().xMaximum(), 3.0) self.assertEqual(v.value().yMaximum(), 4.0) - self.assertEqual(v.value().crs().authid(), 'EPSG:3111') + self.assertEqual(v.value().crs().authid(), "EPSG:3111") # to rectangle r = QgsRectangle(rect) @@ -62,28 +71,46 @@ def testRectangle(self): self.assertEqual(r2.yMaximum(), 40.0) # equality - rect = QgsReferencedRectangle(QgsRectangle(0.0, 1.0, 20.0, 10.0), QgsCoordinateReferenceSystem('epsg:3111')) - rect2 = QgsReferencedRectangle(QgsRectangle(0.0, 1.0, 20.0, 10.0), QgsCoordinateReferenceSystem('epsg:3111')) + rect = QgsReferencedRectangle( + QgsRectangle(0.0, 1.0, 20.0, 10.0), + QgsCoordinateReferenceSystem("epsg:3111"), + ) + rect2 = QgsReferencedRectangle( + QgsRectangle(0.0, 1.0, 20.0, 10.0), + QgsCoordinateReferenceSystem("epsg:3111"), + ) self.assertEqual(rect, rect2) - rect2 = QgsReferencedRectangle(QgsRectangle(0.0, 1.0, 20.0, 10.0), QgsCoordinateReferenceSystem('epsg:4326')) + rect2 = QgsReferencedRectangle( + QgsRectangle(0.0, 1.0, 20.0, 10.0), + QgsCoordinateReferenceSystem("epsg:4326"), + ) self.assertNotEqual(rect, rect2) - rect2 = QgsReferencedRectangle(QgsRectangle(0.0, 1.5, 20.0, 10.0), QgsCoordinateReferenceSystem('epsg:3111')) + rect2 = QgsReferencedRectangle( + QgsRectangle(0.0, 1.5, 20.0, 10.0), + QgsCoordinateReferenceSystem("epsg:3111"), + ) self.assertNotEqual(rect, rect2) def testPoint(self): - point = QgsReferencedPointXY(QgsPointXY(1.0, 2.0), QgsCoordinateReferenceSystem('epsg:3111')) + point = QgsReferencedPointXY( + QgsPointXY(1.0, 2.0), QgsCoordinateReferenceSystem("epsg:3111") + ) self.assertEqual(point.x(), 1.0) self.assertEqual(point.y(), 2.0) - self.assertEqual(point.crs().authid(), 'EPSG:3111') + self.assertEqual(point.crs().authid(), "EPSG:3111") - point.setCrs(QgsCoordinateReferenceSystem('epsg:28356')) - self.assertEqual(point.crs().authid(), 'EPSG:28356') + point.setCrs(QgsCoordinateReferenceSystem("epsg:28356")) + self.assertEqual(point.crs().authid(), "EPSG:28356") # in variant - v = QVariant(QgsReferencedPointXY(QgsPointXY(3.0, 4.0), QgsCoordinateReferenceSystem('epsg:3111'))) + v = QVariant( + QgsReferencedPointXY( + QgsPointXY(3.0, 4.0), QgsCoordinateReferenceSystem("epsg:3111") + ) + ) self.assertEqual(v.value().x(), 3.0) self.assertEqual(v.value().y(), 4.0) - self.assertEqual(v.value().crs().authid(), 'EPSG:3111') + self.assertEqual(v.value().crs().authid(), "EPSG:3111") # to QgsPointXY p = QgsPointXY(point) @@ -91,35 +118,75 @@ def testPoint(self): self.assertEqual(p.y(), 2.0) # equality - point = QgsReferencedPointXY(QgsPointXY(1.0, 2.0), QgsCoordinateReferenceSystem('epsg:3111')) - point2 = QgsReferencedPointXY(QgsPointXY(1.0, 2.0), QgsCoordinateReferenceSystem('epsg:3111')) + point = QgsReferencedPointXY( + QgsPointXY(1.0, 2.0), QgsCoordinateReferenceSystem("epsg:3111") + ) + point2 = QgsReferencedPointXY( + QgsPointXY(1.0, 2.0), QgsCoordinateReferenceSystem("epsg:3111") + ) self.assertEqual(point, point2) - point2 = QgsReferencedPointXY(QgsPointXY(1.0, 2.0), QgsCoordinateReferenceSystem('epsg:4326')) + point2 = QgsReferencedPointXY( + QgsPointXY(1.0, 2.0), QgsCoordinateReferenceSystem("epsg:4326") + ) self.assertNotEqual(point, point2) - point2 = QgsReferencedPointXY(QgsPointXY(1.1, 2.0), QgsCoordinateReferenceSystem('epsg:3111')) + point2 = QgsReferencedPointXY( + QgsPointXY(1.1, 2.0), QgsCoordinateReferenceSystem("epsg:3111") + ) self.assertNotEqual(point, point2) def test_equality(self): self.assertEqual(QgsReferencedGeometry(), QgsReferencedGeometry()) - self.assertEqual(QgsReferencedGeometry(QgsGeometry.fromPointXY(QgsPointXY(1, 2)), QgsCoordinateReferenceSystem('EPSG:3111')), - QgsReferencedGeometry(QgsGeometry.fromPointXY(QgsPointXY(1, 2)), - QgsCoordinateReferenceSystem('EPSG:3111'))) - self.assertEqual(QgsReferencedGeometry(QgsGeometry.fromPointXY(QgsPointXY(1, 2)), - QgsCoordinateReferenceSystem()), - QgsReferencedGeometry(QgsGeometry.fromPointXY(QgsPointXY(1, 2)), - QgsCoordinateReferenceSystem())) - self.assertNotEqual(QgsReferencedGeometry(QgsGeometry.fromPointXY(QgsPointXY(1, 2)), - QgsCoordinateReferenceSystem('EPSG:3111')), - QgsReferencedGeometry(QgsGeometry.fromPointXY(QgsPointXY(1, 22)), - QgsCoordinateReferenceSystem('EPSG:3111'))) - self.assertNotEqual(QgsReferencedGeometry(QgsGeometry.fromPointXY(QgsPointXY(1, 2)), QgsCoordinateReferenceSystem('EPSG:3111')), - QgsReferencedGeometry(QgsGeometry.fromPointXY(QgsPointXY(1, 2)), - QgsCoordinateReferenceSystem('EPSG:4326'))) - self.assertNotEqual(QgsReferencedGeometry(QgsGeometry.fromPointXY(QgsPointXY(1, 2)), - QgsCoordinateReferenceSystem()), - QgsReferencedGeometry(QgsGeometry.fromPointXY(QgsPointXY(1, 22)), - QgsCoordinateReferenceSystem())) - - -if __name__ == '__main__': + self.assertEqual( + QgsReferencedGeometry( + QgsGeometry.fromPointXY(QgsPointXY(1, 2)), + QgsCoordinateReferenceSystem("EPSG:3111"), + ), + QgsReferencedGeometry( + QgsGeometry.fromPointXY(QgsPointXY(1, 2)), + QgsCoordinateReferenceSystem("EPSG:3111"), + ), + ) + self.assertEqual( + QgsReferencedGeometry( + QgsGeometry.fromPointXY(QgsPointXY(1, 2)), + QgsCoordinateReferenceSystem(), + ), + QgsReferencedGeometry( + QgsGeometry.fromPointXY(QgsPointXY(1, 2)), + QgsCoordinateReferenceSystem(), + ), + ) + self.assertNotEqual( + QgsReferencedGeometry( + QgsGeometry.fromPointXY(QgsPointXY(1, 2)), + QgsCoordinateReferenceSystem("EPSG:3111"), + ), + QgsReferencedGeometry( + QgsGeometry.fromPointXY(QgsPointXY(1, 22)), + QgsCoordinateReferenceSystem("EPSG:3111"), + ), + ) + self.assertNotEqual( + QgsReferencedGeometry( + QgsGeometry.fromPointXY(QgsPointXY(1, 2)), + QgsCoordinateReferenceSystem("EPSG:3111"), + ), + QgsReferencedGeometry( + QgsGeometry.fromPointXY(QgsPointXY(1, 2)), + QgsCoordinateReferenceSystem("EPSG:4326"), + ), + ) + self.assertNotEqual( + QgsReferencedGeometry( + QgsGeometry.fromPointXY(QgsPointXY(1, 2)), + QgsCoordinateReferenceSystem(), + ), + QgsReferencedGeometry( + QgsGeometry.fromPointXY(QgsPointXY(1, 22)), + QgsCoordinateReferenceSystem(), + ), + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrelation.py b/tests/src/python/test_qgsrelation.py index af5ca52f3657..c83f3191c7b0 100644 --- a/tests/src/python/test_qgsrelation.py +++ b/tests/src/python/test_qgsrelation.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Matthias Kuhn' -__date__ = '07/10/2013' -__copyright__ = 'Copyright 2013, The QGIS Project' + +__author__ = "Matthias Kuhn" +__date__ = "07/10/2013" +__copyright__ = "Copyright 2013, The QGIS Project" import os @@ -30,8 +31,11 @@ def createReferencingLayer(): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=foreignkey:integer", - "referencinglayer", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=foreignkey:integer", + "referencinglayer", + "memory", + ) pr = layer.dataProvider() f1 = QgsFeature() f1.setFields(layer.fields()) @@ -52,7 +56,9 @@ def createReferencingLayer(): def createReferencedLayer(): layer = QgsVectorLayer( "Point?field=x:string&field=y:integer&field=z:integer", - "referencedlayer", "memory") + "referencedlayer", + "memory", + ) pr = layer.dataProvider() f1 = QgsFeature() f1.setFields(layer.fields()) @@ -79,7 +85,9 @@ class TestQgsRelation(QgisTestCase): def setUp(self): self.referencedLayer = createReferencedLayer() self.referencingLayer = createReferencingLayer() - QgsProject.instance().addMapLayers([self.referencedLayer, self.referencingLayer]) + QgsProject.instance().addMapLayers( + [self.referencedLayer, self.referencingLayer] + ) def tearDown(self): QgsProject.instance().removeAllMapLayers() @@ -87,60 +95,60 @@ def tearDown(self): def test_isValid(self): rel = QgsRelation() self.assertFalse(rel.isValid()) - self.assertEqual(rel.validationError(), 'Referencing layer not set') + self.assertEqual(rel.validationError(), "Referencing layer not set") - rel.setId('rel1') + rel.setId("rel1") self.assertFalse(rel.isValid()) - self.assertEqual(rel.validationError(), 'Referencing layer not set') + self.assertEqual(rel.validationError(), "Referencing layer not set") - rel.setName('Relation Number One') + rel.setName("Relation Number One") self.assertFalse(rel.isValid()) - self.assertEqual(rel.validationError(), 'Referencing layer not set') + self.assertEqual(rel.validationError(), "Referencing layer not set") - rel.setReferencingLayer('xxx') + rel.setReferencingLayer("xxx") self.assertFalse(rel.isValid()) - self.assertEqual(rel.validationError(), 'Referencing layer xxx does not exist') + self.assertEqual(rel.validationError(), "Referencing layer xxx does not exist") rel.setReferencingLayer(self.referencingLayer.id()) self.assertFalse(rel.isValid()) - self.assertEqual(rel.validationError(), 'Referenced layer not set') + self.assertEqual(rel.validationError(), "Referenced layer not set") - rel.setReferencedLayer('yyy') + rel.setReferencedLayer("yyy") self.assertFalse(rel.isValid()) - self.assertEqual(rel.validationError(), 'Referenced layer yyy does not exist') + self.assertEqual(rel.validationError(), "Referenced layer yyy does not exist") rel.setReferencedLayer(self.referencedLayer.id()) self.assertFalse(rel.isValid()) - self.assertEqual(rel.validationError(), 'No fields specified for relationship') + self.assertEqual(rel.validationError(), "No fields specified for relationship") - rel.addFieldPair('foreignkey', 'y') + rel.addFieldPair("foreignkey", "y") self.assertTrue(rel.isValid()) - self.assertEqual(rel.validationError(), '') + self.assertEqual(rel.validationError(), "") def test_getRelatedFeatures(self): rel = QgsRelation() - rel.setId('rel1') - rel.setName('Relation Number One') + rel.setId("rel1") + rel.setName("Relation Number One") rel.setReferencingLayer(self.referencingLayer.id()) rel.setReferencedLayer(self.referencedLayer.id()) - rel.addFieldPair('foreignkey', 'y') + rel.addFieldPair("foreignkey", "y") feat = next(self.referencedLayer.getFeatures()) self.assertEqual(rel.getRelatedFeaturesFilter(feat), '"foreignkey" = 123') it = rel.getRelatedFeatures(feat) - self.assertEqual([a.attributes() for a in it], [['test1', 123], ['test2', 123]]) + self.assertEqual([a.attributes() for a in it], [["test1", 123], ["test2", 123]]) def test_getRelatedFeaturesWithQuote(self): rel = QgsRelation() - rel.setId('rel1') - rel.setName('Relation Number One') + rel.setId("rel1") + rel.setName("Relation Number One") rel.setReferencingLayer(self.referencingLayer.id()) rel.setReferencedLayer(self.referencedLayer.id()) - rel.addFieldPair('fldtxt', 'x') + rel.addFieldPair("fldtxt", "x") feat = self.referencedLayer.getFeature(3) @@ -149,48 +157,48 @@ def test_getRelatedFeaturesWithQuote(self): def test_getReferencedFeature(self): rel = QgsRelation() - rel.setId('rel1') - rel.setName('Relation Number One') + rel.setId("rel1") + rel.setName("Relation Number One") rel.setReferencingLayer(self.referencingLayer.id()) rel.setReferencedLayer(self.referencedLayer.id()) - rel.addFieldPair('foreignkey', 'y') + rel.addFieldPair("foreignkey", "y") feat = next(self.referencingLayer.getFeatures()) f = rel.getReferencedFeature(feat) self.assertTrue(f.isValid()) - self.assertEqual(f[0], 'foo') + self.assertEqual(f[0], "foo") # try mixing up the field pair field name cases -- we should be tolerant to this rel2 = QgsRelation() - rel2.setId('rel1') - rel2.setName('Relation Number One') + rel2.setId("rel1") + rel2.setName("Relation Number One") rel2.setReferencingLayer(self.referencingLayer.id()) rel2.setReferencedLayer(self.referencedLayer.id()) - rel2.addFieldPair('ForeignKey', 'Y') + rel2.addFieldPair("ForeignKey", "Y") feat = next(self.referencingLayer.getFeatures()) f = rel2.getReferencedFeature(feat) self.assertTrue(f.isValid()) - self.assertEqual(f[0], 'foo') + self.assertEqual(f[0], "foo") def test_fieldPairs(self): rel = QgsRelation() - rel.setId('rel1') - rel.setName('Relation Number One') + rel.setId("rel1") + rel.setName("Relation Number One") rel.setReferencingLayer(self.referencingLayer.id()) rel.setReferencedLayer(self.referencedLayer.id()) - rel.addFieldPair('foreignkey', 'y') + rel.addFieldPair("foreignkey", "y") - self.assertEqual(rel.fieldPairs(), {'foreignkey': 'y'}) + self.assertEqual(rel.fieldPairs(), {"foreignkey": "y"}) def testValidRelationAfterChangingStyle(self): # load project - myPath = os.path.join(unitTestDataPath(), 'relations.qgs') + myPath = os.path.join(unitTestDataPath(), "relations.qgs") p = QgsProject.instance() self.assertTrue(p.read(myPath)) for l in p.mapLayers().values(): @@ -206,7 +214,10 @@ def testValidRelationAfterChangingStyle(self): self.assertEqual(len(referencedLayer.editFormConfig().tabs()[0].children()), 7) for tab in referencedLayer.editFormConfig().tabs(): for t in tab.children(): - if (t.type() == QgsAttributeEditorElement.AttributeEditorType.AeTypeRelation): + if ( + t.type() + == QgsAttributeEditorElement.AttributeEditorType.AeTypeRelation + ): valid = t.relation().isValid() self.assertTrue(valid) @@ -233,18 +244,21 @@ def testValidRelationAfterChangingStyle(self): valid = False for tab in referencedLayer.editFormConfig().tabs(): for t in tab.children(): - if (t.type() == QgsAttributeEditorElement.AttributeEditorType.AeTypeRelation): + if ( + t.type() + == QgsAttributeEditorElement.AttributeEditorType.AeTypeRelation + ): valid = t.relation().isValid() self.assertTrue(valid) def test_polymorphicRelationId(self): rel = QgsRelation() - self.assertEqual(rel.polymorphicRelationId(), '') + self.assertEqual(rel.polymorphicRelationId(), "") - rel.setPolymorphicRelationId('poly_rel_id') + rel.setPolymorphicRelationId("poly_rel_id") - self.assertEqual(rel.polymorphicRelationId(), 'poly_rel_id') + self.assertEqual(rel.polymorphicRelationId(), "poly_rel_id") def test_generateId_empty_relation(self): rel = QgsRelation() @@ -254,21 +268,24 @@ def test_generateId_empty_relation(self): def test_referencingFieldsAllowNull(self): rel = QgsRelation() - rel.setId('rel1') - rel.setName('Relation Number One') + rel.setId("rel1") + rel.setName("Relation Number One") rel.setReferencingLayer(self.referencingLayer.id()) rel.setReferencedLayer(self.referencedLayer.id()) - rel.addFieldPair('foreignkey', 'y') + rel.addFieldPair("foreignkey", "y") self.assertTrue(rel.referencingFieldsAllowNull()) referencingLayer = rel.referencingLayer() # Set Not Null constraint on the field - referencingLayer.setFieldConstraint(referencingLayer.fields().indexFromName('foreignkey'), QgsFieldConstraints.Constraint.ConstraintNotNull) + referencingLayer.setFieldConstraint( + referencingLayer.fields().indexFromName("foreignkey"), + QgsFieldConstraints.Constraint.ConstraintNotNull, + ) self.assertFalse(rel.referencingFieldsAllowNull()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrelationeditorwidgetregistry.py b/tests/src/python/test_qgsrelationeditorwidgetregistry.py index ab19d759c51a..b2d2f5f8436b 100644 --- a/tests/src/python/test_qgsrelationeditorwidgetregistry.py +++ b/tests/src/python/test_qgsrelationeditorwidgetregistry.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Matthias Kuhn' -__date__ = '28/11/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Matthias Kuhn" +__date__ = "28/11/2015" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.PyQt.QtWidgets import ( QCheckBox, @@ -42,16 +43,23 @@ def setUpClass(cls): def test_cannot_delete_relation_editor(self): count_before = len(self.registry.relationWidgetNames()) - self.registry.removeRelationWidget('relation_editor') + self.registry.removeRelationWidget("relation_editor") count_after = len(self.registry.relationWidgetNames()) self.assertEqual(count_before, count_after) - self.assertIsInstance(self.registry.create('relation_editor', {}), QgsRelationEditorWidget) - self.assertIsInstance(self.registry.createConfigWidget('relation_editor', QgsRelation()), QgsRelationEditorConfigWidget) + self.assertIsInstance( + self.registry.create("relation_editor", {}), QgsRelationEditorWidget + ) + self.assertIsInstance( + self.registry.createConfigWidget("relation_editor", QgsRelation()), + QgsRelationEditorConfigWidget, + ) def test_returns_none_when_unknown_widget_id(self): - self.assertIsNone(self.registry.create('babinatatitrunkina', {})) - self.assertIsNone(self.registry.createConfigWidget('babinatatitrunkina', QgsRelation())) + self.assertIsNone(self.registry.create("babinatatitrunkina", {})) + self.assertIsNone( + self.registry.createConfigWidget("babinatatitrunkina", QgsRelation()) + ) def test_creates_new_widget(self): # define the widget @@ -62,37 +70,41 @@ def __init__(self, config, parent): self.setLayout(QGridLayout()) self.label = QLabel() - self.label.setText(f'According to the configuration, the checkboxin state was {str(config.get("checkboxin", "Unknown"))}') + self.label.setText( + f'According to the configuration, the checkboxin state was {str(config.get("checkboxin", "Unknown"))}' + ) self.layout().addWidget(self.label) def config(self): - return { - - } + return {} def setConfig(self, config): - self.label.setText(f'According to the configuration, the checkboxin state was {str(config.get("checkboxin", "Unknown"))}') + self.label.setText( + f'According to the configuration, the checkboxin state was {str(config.get("checkboxin", "Unknown"))}' + ) # define the config widget - class QgsExampleRelationEditorConfigWidget(QgsAbstractRelationEditorConfigWidget): + class QgsExampleRelationEditorConfigWidget( + QgsAbstractRelationEditorConfigWidget + ): def __init__(self, relation, parent): super().__init__(relation, parent) self.setLayout(QGridLayout()) - self.checkbox = QCheckBox('Is this checkbox checkboxin?') + self.checkbox = QCheckBox("Is this checkbox checkboxin?") self.layout().addWidget(self.checkbox) def config(self): - return { - "checkboxin": self.checkbox.isChecked() - } + return {"checkboxin": self.checkbox.isChecked()} def setConfig(self, config): - self.checkbox.setChecked(config.get('checkboxin', False)) + self.checkbox.setChecked(config.get("checkboxin", False)) # define the widget factory - class QgsExampleRelationEditorWidgetFactory(QgsAbstractRelationEditorWidgetFactory): + class QgsExampleRelationEditorWidgetFactory( + QgsAbstractRelationEditorWidgetFactory + ): def type(self): return "example" @@ -105,14 +117,19 @@ def create(self, config, parent): def configWidget(self, relation, parent): return QgsExampleRelationEditorConfigWidget(relation, parent) - self.assertIsNone(self.registry.create('example', {})) - self.assertIsNone(self.registry.createConfigWidget('example', QgsRelation())) + self.assertIsNone(self.registry.create("example", {})) + self.assertIsNone(self.registry.createConfigWidget("example", QgsRelation())) self.registry.addRelationWidget(QgsExampleRelationEditorWidgetFactory()) - self.assertIsInstance(self.registry.create('example', {}), QgsExampleRelationEditorWidget) - self.assertIsInstance(self.registry.createConfigWidget('example', QgsRelation()), QgsExampleRelationEditorConfigWidget) + self.assertIsInstance( + self.registry.create("example", {}), QgsExampleRelationEditorWidget + ) + self.assertIsInstance( + self.registry.createConfigWidget("example", QgsRelation()), + QgsExampleRelationEditorConfigWidget, + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrelationeditwidget.py b/tests/src/python/test_qgsrelationeditwidget.py index ece758559334..5a87c961df50 100644 --- a/tests/src/python/test_qgsrelationeditwidget.py +++ b/tests/src/python/test_qgsrelationeditwidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Matthias Kuhn' -__date__ = '28/11/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Matthias Kuhn" +__date__ = "28/11/2015" +__copyright__ = "Copyright 2015, The QGIS Project" import os @@ -53,14 +54,32 @@ def setUpClass(cls): super().setUpClass() cls.mapCanvas = QgsMapCanvas() QgsGui.editorWidgetRegistry().initEditors(cls.mapCanvas) - cls.dbconn = 'service=\'qgis_test\'' - if 'QGIS_PGTEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_PGTEST_DB'] + cls.dbconn = "service='qgis_test'" + if "QGIS_PGTEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_PGTEST_DB"] # Create test layer - cls.vl_books = QgsVectorLayer(cls.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."books" sql=', 'books', 'postgres') - cls.vl_authors = QgsVectorLayer(cls.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."authors" sql=', 'authors', 'postgres') - cls.vl_editors = QgsVectorLayer(cls.dbconn + ' sslmode=disable key=\'fk_book,fk_author\' table="qgis_test"."editors" sql=', 'editors', 'postgres') - cls.vl_link_books_authors = QgsVectorLayer(cls.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."books_authors" sql=', 'books_authors', 'postgres') + cls.vl_books = QgsVectorLayer( + cls.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."books" sql=', + "books", + "postgres", + ) + cls.vl_authors = QgsVectorLayer( + cls.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."authors" sql=', + "authors", + "postgres", + ) + cls.vl_editors = QgsVectorLayer( + cls.dbconn + + ' sslmode=disable key=\'fk_book,fk_author\' table="qgis_test"."editors" sql=', + "editors", + "postgres", + ) + cls.vl_link_books_authors = QgsVectorLayer( + cls.dbconn + + ' sslmode=disable key=\'pk\' table="qgis_test"."books_authors" sql=', + "books_authors", + "postgres", + ) QgsProject.instance().addMapLayer(cls.vl_books) QgsProject.instance().addMapLayer(cls.vl_authors) @@ -96,16 +115,16 @@ def setUp(self): self.rel_a = QgsRelation() self.rel_a.setReferencingLayer(self.vl_link_books_authors.id()) self.rel_a.setReferencedLayer(self.vl_authors.id()) - self.rel_a.addFieldPair('fk_author', 'pk') - self.rel_a.setId('rel_a') + self.rel_a.addFieldPair("fk_author", "pk") + self.rel_a.setId("rel_a") assert self.rel_a.isValid() self.relMgr.addRelation(self.rel_a) self.rel_b = QgsRelation() self.rel_b.setReferencingLayer(self.vl_link_books_authors.id()) self.rel_b.setReferencedLayer(self.vl_books.id()) - self.rel_b.addFieldPair('fk_book', 'pk') - self.rel_b.setId('rel_b') + self.rel_b.addFieldPair("fk_book", "pk") + self.rel_b.setId("rel_b") assert self.rel_b.isValid() self.relMgr.addRelation(self.rel_b) @@ -143,24 +162,34 @@ def test_delete_feature(self): """ Check if a feature can be deleted properly """ - self.createWrapper(self.vl_authors, '"name"=\'Erich Gamma\'') + self.createWrapper(self.vl_authors, "\"name\"='Erich Gamma'") self.assertEqual(self.table_view.model().rowCount(), 1) self.assertEqual(1, len([f for f in self.vl_books.getFeatures()])) - fid = next(self.vl_books.getFeatures(QgsFeatureRequest().setFilterExpression('"name"=\'Design Patterns. Elements of Reusable Object-Oriented Software\''))).id() + fid = next( + self.vl_books.getFeatures( + QgsFeatureRequest().setFilterExpression( + "\"name\"='Design Patterns. Elements of Reusable Object-Oriented Software'" + ) + ) + ).id() self.widget.featureSelectionManager().select([fid]) - btn = self.widget.findChild(QToolButton, 'mDeleteFeatureButton') + btn = self.widget.findChild(QToolButton, "mDeleteFeatureButton") def clickOk(): # Click the "Delete features" button on the confirmation message # box widget = self.widget.findChild(QMessageBox) buttonBox = widget.findChild(QDialogButtonBox) - deleteButton = next(b for b in buttonBox.buttons() if buttonBox.buttonRole(b) == QDialogButtonBox.ButtonRole.AcceptRole) + deleteButton = next( + b + for b in buttonBox.buttons() + if buttonBox.buttonRole(b) == QDialogButtonBox.ButtonRole.AcceptRole + ) deleteButton.click() QTimer.singleShot(1, clickOk) @@ -186,12 +215,14 @@ def test_add_feature(self): """ Check if a new related feature is added """ - self.createWrapper(self.vl_authors, '"name"=\'Douglas Adams\'') + self.createWrapper(self.vl_authors, "\"name\"='Douglas Adams'") self.assertEqual(self.table_view.model().rowCount(), 0) - self.vltools.setValues([None, 'The Hitchhiker\'s Guide to the Galaxy', 'Sputnik Editions', 1961]) - btn = self.widget.findChild(QToolButton, 'mAddFeatureButton') + self.vltools.setValues( + [None, "The Hitchhiker's Guide to the Galaxy", "Sputnik Editions", 1961] + ) + btn = self.widget.findChild(QToolButton, "mAddFeatureButton") btn.click() # Book entry has been created @@ -206,13 +237,22 @@ def test_link_feature(self): """ Check if an existing feature can be linked """ - wrapper = self.createWrapper(self.vl_authors, '"name"=\'Douglas Adams\'') # NOQA + wrapper = self.createWrapper( + self.vl_authors, "\"name\"='Douglas Adams'" + ) # NOQA f = QgsFeature(self.vl_books.fields()) - f.setAttributes([self.vl_books.dataProvider().defaultValueClause(0), 'The Hitchhiker\'s Guide to the Galaxy', 'Sputnik Editions', 1961]) + f.setAttributes( + [ + self.vl_books.dataProvider().defaultValueClause(0), + "The Hitchhiker's Guide to the Galaxy", + "Sputnik Editions", + 1961, + ] + ) self.vl_books.addFeature(f) - btn = self.widget.findChild(QToolButton, 'mLinkFeatureButton') + btn = self.widget.findChild(QToolButton, "mLinkFeatureButton") btn.click() dlg = self.widget.findChild(QDialog) @@ -220,7 +260,11 @@ def test_link_feature(self): dlg.accept() # magically the above code selects the feature here... - link_feature = next(self.vl_link_books_authors.getFeatures(QgsFeatureRequest().setFilterExpression(f'"fk_book"={f[0]}'))) + link_feature = next( + self.vl_link_books_authors.getFeatures( + QgsFeatureRequest().setFilterExpression(f'"fk_book"={f[0]}') + ) + ) self.assertIsNotNone(link_feature[0]) self.assertEqual(self.table_view.model().rowCount(), 1) @@ -229,19 +273,24 @@ def test_unlink_feature(self): """ Check if a linked feature can be unlinked """ - wrapper = self.createWrapper(self.vl_books) # NOQA + wrapper = self.createWrapper(self.vl_books) # NOQA # All authors are listed self.assertEqual(self.table_view.model().rowCount(), 4) it = self.vl_authors.getFeatures( - QgsFeatureRequest().setFilterExpression('"name" IN (\'Richard Helm\', \'Ralph Johnson\')')) + QgsFeatureRequest().setFilterExpression( + "\"name\" IN ('Richard Helm', 'Ralph Johnson')" + ) + ) self.widget.featureSelectionManager().select([f.id() for f in it]) - self.assertEqual(2, self.widget.featureSelectionManager().selectedFeatureCount()) + self.assertEqual( + 2, self.widget.featureSelectionManager().selectedFeatureCount() + ) - btn = self.widget.findChild(QToolButton, 'mUnlinkFeatureButton') + btn = self.widget.findChild(QToolButton, "mUnlinkFeatureButton") btn.click() # This is actually more checking that the database on delete action is properly set on the relation @@ -253,49 +302,74 @@ def test_discover_relations(self): """ Test the automatic discovery of relations """ - relations = self.relMgr.discoverRelations([], [self.vl_authors, self.vl_books, self.vl_link_books_authors]) + relations = self.relMgr.discoverRelations( + [], [self.vl_authors, self.vl_books, self.vl_link_books_authors] + ) relations = {r.name(): r for r in relations} - self.assertEqual({'books_authors_fk_book_fkey', 'books_authors_fk_author_fkey'}, set(relations.keys())) + self.assertEqual( + {"books_authors_fk_book_fkey", "books_authors_fk_author_fkey"}, + set(relations.keys()), + ) - ba2b = relations['books_authors_fk_book_fkey'] + ba2b = relations["books_authors_fk_book_fkey"] self.assertTrue(ba2b.isValid()) - self.assertEqual('books_authors', ba2b.referencingLayer().name()) - self.assertEqual('books', ba2b.referencedLayer().name()) + self.assertEqual("books_authors", ba2b.referencingLayer().name()) + self.assertEqual("books", ba2b.referencedLayer().name()) self.assertEqual([0], ba2b.referencingFields()) self.assertEqual([0], ba2b.referencedFields()) - ba2a = relations['books_authors_fk_author_fkey'] + ba2a = relations["books_authors_fk_author_fkey"] self.assertTrue(ba2a.isValid()) - self.assertEqual('books_authors', ba2a.referencingLayer().name()) - self.assertEqual('authors', ba2a.referencedLayer().name()) + self.assertEqual("books_authors", ba2a.referencingLayer().name()) + self.assertEqual("authors", ba2a.referencedLayer().name()) self.assertEqual([1], ba2a.referencingFields()) self.assertEqual([0], ba2a.referencedFields()) - self.assertEqual([], self.relMgr.discoverRelations([self.rel_a, self.rel_b], [self.vl_authors, self.vl_books, self.vl_link_books_authors])) - self.assertEqual(1, len(self.relMgr.discoverRelations([], [self.vl_authors, self.vl_link_books_authors]))) + self.assertEqual( + [], + self.relMgr.discoverRelations( + [self.rel_a, self.rel_b], + [self.vl_authors, self.vl_books, self.vl_link_books_authors], + ), + ) + self.assertEqual( + 1, + len( + self.relMgr.discoverRelations( + [], [self.vl_authors, self.vl_link_books_authors] + ) + ), + ) # composite keys relation relations = self.relMgr.discoverRelations([], [self.vl_books, self.vl_editors]) self.assertEqual(len(relations), 1) relation = relations[0] - self.assertEqual('books_fk_editor_fkey', relation.name()) + self.assertEqual("books_fk_editor_fkey", relation.name()) self.assertTrue(relation.isValid()) - self.assertEqual('books', relation.referencingLayer().name()) - self.assertEqual('editors', relation.referencedLayer().name()) + self.assertEqual("books", relation.referencingLayer().name()) + self.assertEqual("editors", relation.referencedLayer().name()) self.assertEqual([2, 3], relation.referencingFields()) self.assertEqual([0, 1], relation.referencedFields()) def test_selection(self): fbook = QgsFeature(self.vl_books.fields()) - fbook.setAttributes([self.vl_books.dataProvider().defaultValueClause(0), 'The Hitchhiker\'s Guide to the Galaxy', 'Sputnik Editions', 1961]) + fbook.setAttributes( + [ + self.vl_books.dataProvider().defaultValueClause(0), + "The Hitchhiker's Guide to the Galaxy", + "Sputnik Editions", + 1961, + ] + ) self.vl_books.addFeature(fbook) flink = QgsFeature(self.vl_link_books_authors.fields()) flink.setAttributes([fbook.id(), 5]) self.vl_link_books_authors.addFeature(flink) - self.createWrapper(self.vl_authors, '"name"=\'Douglas Adams\'') + self.createWrapper(self.vl_authors, "\"name\"='Douglas Adams'") self.zoomToButton = self.widget.findChild(QToolButton, "mDeleteFeatureButton") self.assertTrue(self.zoomToButton) @@ -320,8 +394,18 @@ def test_add_feature_geometry(self): """ Test to add a feature with a geometry """ - vl_pipes = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."pipes" (geom) sql=', 'pipes', 'postgres') - vl_leaks = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."leaks" (geom) sql=', 'leaks', 'postgres') + vl_pipes = QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'pk\' table="qgis_test"."pipes" (geom) sql=', + "pipes", + "postgres", + ) + vl_leaks = QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'pk\' table="qgis_test"."leaks" (geom) sql=', + "leaks", + "postgres", + ) vl_leaks.startEditing() QgsProject.instance().addMapLayer(vl_pipes) @@ -333,15 +417,23 @@ def test_add_feature_geometry(self): rel = QgsRelation() rel.setReferencingLayer(vl_leaks.id()) rel.setReferencedLayer(vl_pipes.id()) - rel.addFieldPair('pipe', 'id') - rel.setId('rel_pipe_leak') + rel.addFieldPair("pipe", "id") + rel.setId("rel_pipe_leak") self.assertTrue(rel.isValid()) self.relMgr.addRelation(rel) # Mock vector layer tool to just set default value on created feature class DummyVlTools(QgsVectorLayerTools): - def addFeature(self, layer, defaultValues, defaultGeometry, parentWidget=None, showModal=True, hideParent=False): + def addFeature( + self, + layer, + defaultValues, + defaultGeometry, + parentWidget=None, + showModal=True, + hideParent=False, + ): f = QgsFeature(layer.fields()) for idx, value in defaultValues.items(): f.setAttribute(idx, value) @@ -366,13 +458,13 @@ def addFeature(self, layer, defaultValues, defaultGeometry, parentWidget=None, s table_view = widget.findChild(QTableView) self.assertEqual(table_view.model().rowCount(), 1) - btn = widget.findChild(QToolButton, 'mAddFeatureGeometryButton') + btn = widget.findChild(QToolButton, "mAddFeatureGeometryButton") self.assertTrue(btn.isVisible()) self.assertTrue(btn.isEnabled()) btn.click() self.assertTrue(self.mapCanvas.mapTool()) feature = QgsFeature(vl_leaks.fields()) - feature.setGeometry(QgsGeometry.fromWkt('POINT(0 0.8)')) + feature.setGeometry(QgsGeometry.fromWkt("POINT(0 0.8)")) self.mapCanvas.mapTool().digitizingCompleted.emit(feature) self.assertEqual(table_view.model().rowCount(), 2) self.assertEqual(vl_leaks.featureCount(), 4) @@ -382,7 +474,7 @@ def addFeature(self, layer, defaultValues, defaultGeometry, parentWidget=None, s # get new created feature feat = next(vl_leaks.getFeatures('"id" is NULL')) self.assertTrue(feat.isValid()) - self.assertTrue(feat.geometry().equals(QgsGeometry.fromWkt('POINT(0 0.8)'))) + self.assertTrue(feat.geometry().equals(QgsGeometry.fromWkt("POINT(0 0.8)"))) vl_leaks.rollBack() @@ -406,7 +498,7 @@ def createWrapper(self, layer, filter=None): nmrel = self.rel_b self.wrapper = QgsRelationWidgetWrapper(layer, relation) - self.wrapper.setConfig({'nm-rel': nmrel.id()}) + self.wrapper.setConfig({"nm-rel": nmrel.id()}) context = QgsAttributeEditorContext() context.setMapCanvas(self.mapCanvas) context.setVectorLayerTools(self.vltools) @@ -426,7 +518,6 @@ def createWrapper(self, layer, filter=None): class VlTools(QgsVectorLayerTools): - """ Mock the QgsVectorLayerTools Since we don't have a user on the test server to input this data for us, we can just use this. @@ -440,7 +531,15 @@ def setValues(self, values): """ self.values = values - def addFeature(self, layer, defaultValues, defaultGeometry, parentWidget=None, showModal=True, hideParent=False): + def addFeature( + self, + layer, + defaultValues, + defaultGeometry, + parentWidget=None, + showModal=True, + hideParent=False, + ): """ Overrides the addFeature method :param layer: vector layer @@ -471,5 +570,5 @@ def saveEdits(self, layer): pass -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrelationmanager.py b/tests/src/python/test_qgsrelationmanager.py index 27842c99b324..36c849217228 100644 --- a/tests/src/python/test_qgsrelationmanager.py +++ b/tests/src/python/test_qgsrelationmanager.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '17/05/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "17/05/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.core import ( @@ -24,15 +25,20 @@ def createReferencingLayer(): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=foreignkey:integer&field=referenced_layer:string&field=referenced_fid:string", - "referencinglayer", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=foreignkey:integer&field=referenced_layer:string&field=referenced_fid:string", + "referencinglayer", + "memory", + ) return layer def createReferencedLayer(): layer = QgsVectorLayer( "Point?field=x:string&field=y:integer&field=z:integer", - "referencedlayer", "memory") + "referencedlayer", + "memory", + ) return layer @@ -41,7 +47,9 @@ class TestQgsRelationManager(QgisTestCase): def setUp(self): self.referencedLayer = createReferencedLayer() self.referencingLayer = createReferencingLayer() - QgsProject.instance().addMapLayers([self.referencedLayer, self.referencingLayer]) + QgsProject.instance().addMapLayers( + [self.referencedLayer, self.referencingLayer] + ) def tearDown(self): QgsProject.instance().removeAllMapLayers() @@ -50,39 +58,39 @@ def createRelation(self): rel = QgsRelation() rel.setReferencingLayer(self.referencingLayer.id()) rel.setReferencedLayer(self.referencedLayer.id()) - rel.addFieldPair('foreignkey', 'y') + rel.addFieldPair("foreignkey", "y") return rel def createPolymorphicRelation(self): polyRel = QgsPolymorphicRelation() polyRel.setReferencingLayer(self.referencingLayer.id()) polyRel.setReferencedLayerIds([self.referencedLayer.id()]) - polyRel.setReferencedLayerField('referenced_layer') - polyRel.setReferencedLayerExpression('@layer_name') - polyRel.addFieldPair('referenced_fid', 'x') + polyRel.setReferencedLayerField("referenced_layer") + polyRel.setReferencedLayerExpression("@layer_name") + polyRel.addFieldPair("referenced_fid", "x") return polyRel def test_addRelation(self): - """ test adding relations to a manager """ + """test adding relations to a manager""" manager = QgsRelationManager() relations = manager.relations() self.assertEqual(len(relations), 0) rel = self.createRelation() - rel.setId('rel1') - rel.setName('Relation Number One') + rel.setId("rel1") + rel.setName("Relation Number One") assert rel.isValid() manager.addRelation(rel) relations = manager.relations() self.assertEqual(len(relations), 1) - self.assertEqual(relations['rel1'].id(), 'rel1') + self.assertEqual(relations["rel1"].id(), "rel1") rel = self.createRelation() - rel.setId('rel2') - rel.setName('Relation Number Two') + rel.setId("rel2") + rel.setName("Relation Number Two") assert rel.isValid() manager.addRelation(rel) @@ -90,76 +98,76 @@ def test_addRelation(self): relations = manager.relations() self.assertEqual(len(relations), 2) ids = [r.id() for r in list(relations.values())] - self.assertEqual(set(ids), {'rel1', 'rel2'}) + self.assertEqual(set(ids), {"rel1", "rel2"}) def test_relationById(self): - """ test retrieving relation by id""" + """test retrieving relation by id""" manager = QgsRelationManager() - rel = manager.relation('does not exist') + rel = manager.relation("does not exist") self.assertFalse(rel.isValid()) # add two relations rel = self.createRelation() - rel.setId('rel1') - rel.setName('Relation Number One') + rel.setId("rel1") + rel.setName("Relation Number One") assert rel.isValid() manager.addRelation(rel) rel = self.createRelation() - rel.setId('rel2') - rel.setName('Relation Number Two') + rel.setId("rel2") + rel.setName("Relation Number Two") assert rel.isValid() manager.addRelation(rel) - rel = manager.relation('does not exist') + rel = manager.relation("does not exist") self.assertFalse(rel.isValid()) - rel = manager.relation('rel1') - self.assertEqual(rel.id(), 'rel1') + rel = manager.relation("rel1") + self.assertEqual(rel.id(), "rel1") - rel = manager.relation('rel2') - self.assertEqual(rel.id(), 'rel2') + rel = manager.relation("rel2") + self.assertEqual(rel.id(), "rel2") def test_relationByName(self): - """ test retrieving relations by name""" + """test retrieving relations by name""" manager = QgsRelationManager() - rels = manager.relationsByName('does not exist') + rels = manager.relationsByName("does not exist") self.assertEqual(rels, []) # add some relations rel = self.createRelation() - rel.setId('rel1') - rel.setName('my relation') + rel.setId("rel1") + rel.setName("my relation") assert rel.isValid() manager.addRelation(rel) rel = self.createRelation() - rel.setId('rel2') - rel.setName('dupe name') + rel.setId("rel2") + rel.setName("dupe name") assert rel.isValid() manager.addRelation(rel) rel = self.createRelation() - rel.setId('rel3') - rel.setName('dupe name') + rel.setId("rel3") + rel.setName("dupe name") assert rel.isValid() manager.addRelation(rel) - rels = manager.relationsByName('does not exist') + rels = manager.relationsByName("does not exist") self.assertEqual(rels, []) - rels = manager.relationsByName('my relation') + rels = manager.relationsByName("my relation") ids = [r.id() for r in rels] - self.assertEqual(set(ids), {'rel1'}) + self.assertEqual(set(ids), {"rel1"}) # case insensitive - rels = manager.relationsByName('My RelAtion') + rels = manager.relationsByName("My RelAtion") ids = [r.id() for r in rels] - self.assertEqual(set(ids), {'rel1'}) + self.assertEqual(set(ids), {"rel1"}) # multiple results - rels = manager.relationsByName('dupe name') + rels = manager.relationsByName("dupe name") ids = [r.id() for r in rels] - self.assertEqual(set(ids), {'rel2', 'rel3'}) + self.assertEqual(set(ids), {"rel2", "rel3"}) def test_setPolymorphicRelations(self): # tests polymorphicRelations/setPolymorphicRelations @@ -170,14 +178,14 @@ def test_setPolymorphicRelations(self): self.assertListEqual(list(manager.polymorphicRelations()), []) poly_rel1 = self.createPolymorphicRelation() - poly_rel1.setId('poly_rel1') - poly_rel1.setName('Poly Rel 1') + poly_rel1.setId("poly_rel1") + poly_rel1.setName("Poly Rel 1") poly_rel2 = self.createPolymorphicRelation() - poly_rel2.setId('poly_rel2') - poly_rel2.setName('Poly Rel 2') + poly_rel2.setId("poly_rel2") + poly_rel2.setName("Poly Rel 2") poly_rel3 = self.createPolymorphicRelation() - poly_rel3.setId('poly_rel3') - poly_rel3.setName('Poly Rel 3') + poly_rel3.setId("poly_rel3") + poly_rel3.setName("Poly Rel 3") # the relation should be valid now self.assertTrue(poly_rel1.isValid()) @@ -187,16 +195,25 @@ def test_setPolymorphicRelations(self): manager.setPolymorphicRelations([poly_rel1, poly_rel2, poly_rel3]) # the relations should match - self.assertListEqual(list(manager.polymorphicRelations()), ['poly_rel1', 'poly_rel2', 'poly_rel3']) - self.assertTrue(manager.polymorphicRelations()['poly_rel1']) - self.assertTrue(manager.polymorphicRelations()['poly_rel2']) - self.assertTrue(manager.polymorphicRelations()['poly_rel3']) - self.assertTrue(manager.polymorphicRelations()['poly_rel1'].hasEqualDefinition(poly_rel1)) - self.assertTrue(manager.polymorphicRelations()['poly_rel2'].hasEqualDefinition(poly_rel2)) - self.assertTrue(manager.polymorphicRelations()['poly_rel3'].hasEqualDefinition(poly_rel3)) + self.assertListEqual( + list(manager.polymorphicRelations()), + ["poly_rel1", "poly_rel2", "poly_rel3"], + ) + self.assertTrue(manager.polymorphicRelations()["poly_rel1"]) + self.assertTrue(manager.polymorphicRelations()["poly_rel2"]) + self.assertTrue(manager.polymorphicRelations()["poly_rel3"]) + self.assertTrue( + manager.polymorphicRelations()["poly_rel1"].hasEqualDefinition(poly_rel1) + ) + self.assertTrue( + manager.polymorphicRelations()["poly_rel2"].hasEqualDefinition(poly_rel2) + ) + self.assertTrue( + manager.polymorphicRelations()["poly_rel3"].hasEqualDefinition(poly_rel3) + ) manager.setPolymorphicRelations([poly_rel1]) - self.assertListEqual(list(manager.polymorphicRelations()), ['poly_rel1']) + self.assertListEqual(list(manager.polymorphicRelations()), ["poly_rel1"]) manager.setPolymorphicRelations([]) self.assertListEqual(list(manager.polymorphicRelations()), []) @@ -209,11 +226,11 @@ def test_polymorphicRelation(self): self.assertFalse(manager.polymorphicRelations()) poly_rel1 = self.createPolymorphicRelation() - poly_rel1.setId('poly_rel1') - poly_rel1.setName('Poly Rel 1') + poly_rel1.setId("poly_rel1") + poly_rel1.setName("Poly Rel 1") poly_rel2 = self.createPolymorphicRelation() - poly_rel2.setId('poly_rel2') - poly_rel2.setName('Poly Rel 2') + poly_rel2.setId("poly_rel2") + poly_rel2.setName("Poly Rel 2") # the relation should be valid now self.assertTrue(poly_rel1.isValid()) @@ -222,11 +239,15 @@ def test_polymorphicRelation(self): manager.addPolymorphicRelation(poly_rel1) manager.addPolymorphicRelation(poly_rel2) - self.assertFalse(manager.polymorphicRelation('poly_invalid_id').isValid()) - self.assertTrue(manager.polymorphicRelation('poly_rel1').isValid()) - self.assertTrue(manager.polymorphicRelation('poly_rel2').isValid()) - self.assertTrue(manager.polymorphicRelation('poly_rel1').hasEqualDefinition(poly_rel1)) - self.assertTrue(manager.polymorphicRelation('poly_rel2').hasEqualDefinition(poly_rel2)) + self.assertFalse(manager.polymorphicRelation("poly_invalid_id").isValid()) + self.assertTrue(manager.polymorphicRelation("poly_rel1").isValid()) + self.assertTrue(manager.polymorphicRelation("poly_rel2").isValid()) + self.assertTrue( + manager.polymorphicRelation("poly_rel1").hasEqualDefinition(poly_rel1) + ) + self.assertTrue( + manager.polymorphicRelation("poly_rel2").hasEqualDefinition(poly_rel2) + ) def test_removePolymorphicRelation(self): # tests addPolymorphicRelation/removePolymorphicRelation @@ -238,37 +259,54 @@ def test_removePolymorphicRelation(self): self.assertFalse(manager.relations()) poly_rel1 = self.createPolymorphicRelation() - poly_rel1.setId('poly_rel1') - poly_rel1.setName('Poly Rel 1') + poly_rel1.setId("poly_rel1") + poly_rel1.setName("Poly Rel 1") poly_rel2 = self.createPolymorphicRelation() - poly_rel2.setId('poly_rel2') - poly_rel2.setName('Poly Rel 2') + poly_rel2.setId("poly_rel2") + poly_rel2.setName("Poly Rel 2") # the relation should be valid now self.assertTrue(poly_rel1.isValid()) self.assertTrue(poly_rel2.isValid()) - self.assertFalse(manager.polymorphicRelation('poly_invalid_id').isValid()) - self.assertListEqual([r.polymorphicRelationId() for r in manager.relations().values()], []) + self.assertFalse(manager.polymorphicRelation("poly_invalid_id").isValid()) + self.assertListEqual( + [r.polymorphicRelationId() for r in manager.relations().values()], [] + ) manager.addPolymorphicRelation(poly_rel1) - self.assertTrue(manager.polymorphicRelation('poly_rel1').isValid()) - self.assertTrue(manager.polymorphicRelation('poly_rel1').hasEqualDefinition(poly_rel1)) - self.assertListEqual([r.polymorphicRelationId() for r in manager.relations().values()], [poly_rel1.id()]) + self.assertTrue(manager.polymorphicRelation("poly_rel1").isValid()) + self.assertTrue( + manager.polymorphicRelation("poly_rel1").hasEqualDefinition(poly_rel1) + ) + self.assertListEqual( + [r.polymorphicRelationId() for r in manager.relations().values()], + [poly_rel1.id()], + ) manager.addPolymorphicRelation(poly_rel2) - self.assertTrue(manager.polymorphicRelation('poly_rel2').isValid()) - self.assertTrue(manager.polymorphicRelation('poly_rel2').hasEqualDefinition(poly_rel2)) - self.assertListEqual([r.polymorphicRelationId() for r in manager.relations().values()], [poly_rel1.id(), poly_rel2.id()]) + self.assertTrue(manager.polymorphicRelation("poly_rel2").isValid()) + self.assertTrue( + manager.polymorphicRelation("poly_rel2").hasEqualDefinition(poly_rel2) + ) + self.assertListEqual( + [r.polymorphicRelationId() for r in manager.relations().values()], + [poly_rel1.id(), poly_rel2.id()], + ) manager.removePolymorphicRelation(poly_rel1.id()) - self.assertFalse(manager.polymorphicRelation('poly_rel1').isValid()) - self.assertTrue(manager.polymorphicRelation('poly_rel2').isValid()) - self.assertListEqual([r.polymorphicRelationId() for r in manager.relations().values()], [poly_rel2.id()]) + self.assertFalse(manager.polymorphicRelation("poly_rel1").isValid()) + self.assertTrue(manager.polymorphicRelation("poly_rel2").isValid()) + self.assertListEqual( + [r.polymorphicRelationId() for r in manager.relations().values()], + [poly_rel2.id()], + ) manager.removePolymorphicRelation(poly_rel2.id()) - self.assertFalse(manager.polymorphicRelation('poly_rel1').isValid()) - self.assertFalse(manager.polymorphicRelation('poly_rel2').isValid()) - self.assertListEqual([r.polymorphicRelationId() for r in manager.relations().values()], []) + self.assertFalse(manager.polymorphicRelation("poly_rel1").isValid()) + self.assertFalse(manager.polymorphicRelation("poly_rel2").isValid()) + self.assertListEqual( + [r.polymorphicRelationId() for r in manager.relations().values()], [] + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrelationpostgres.py b/tests/src/python/test_qgsrelationpostgres.py index 11983ab7402d..028f8ac9059c 100644 --- a/tests/src/python/test_qgsrelationpostgres.py +++ b/tests/src/python/test_qgsrelationpostgres.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Loïc Bartoletti' -__date__ = '27/07/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Loïc Bartoletti" +__date__ = "27/07/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import os @@ -24,9 +25,9 @@ class TestQgsRelationPostgresql(QgisTestCase): def setUpClass(cls): super().setUpClass() - cls.dbconn = 'service=\'qgis_test\'' - if 'QGIS_PGTEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_PGTEST_DB'] + cls.dbconn = "service='qgis_test'" + if "QGIS_PGTEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_PGTEST_DB"] cls.relMgr = QgsProject.instance().relationManager() @@ -44,11 +45,44 @@ def test_discover_relations(self): """ # Create test layer - tables = ['c_amgmt_amgmt_lot', 'c_batiment_bat_lot', 'c_ens_immo_amgmt', 'c_ens_immo_bat', 'c_terrain_ens_immo', 't_actes', 't_adresse', 't_amgmt', 't_amgmt_lot', 't_bat', 't_bat_lot', 't_ens_immo', 't_terrain'] # spellok - vl_tables = ['vl_c_amgmt_amgmt_lot', 'vl_c_batiment_bat_lot', 'vl_c_ens_immo_amgmt', 'vl_c_ens_immo_bat', 'vl_c_terrain_ens_immo', 'vl_t_actes', 'vl_t_adresse', 'vl_t_amgmt', 'vl_t_amgmt_lot', 'vl_t_bat', 'vl_t_bat_lot', 'vl_t_ens_immo', 'vl_t_terrain'] # spellok + tables = [ + "c_amgmt_amgmt_lot", + "c_batiment_bat_lot", + "c_ens_immo_amgmt", + "c_ens_immo_bat", + "c_terrain_ens_immo", + "t_actes", + "t_adresse", + "t_amgmt", + "t_amgmt_lot", + "t_bat", + "t_bat_lot", + "t_ens_immo", + "t_terrain", + ] # spellok + vl_tables = [ + "vl_c_amgmt_amgmt_lot", + "vl_c_batiment_bat_lot", + "vl_c_ens_immo_amgmt", + "vl_c_ens_immo_bat", + "vl_c_terrain_ens_immo", + "vl_t_actes", + "vl_t_adresse", + "vl_t_amgmt", + "vl_t_amgmt_lot", + "vl_t_bat", + "vl_t_bat_lot", + "vl_t_ens_immo", + "vl_t_terrain", + ] # spellok for i in range(len(tables)): - vl_tables[i] = QgsVectorLayer(self.dbconn + f' sslmode=disable key=\'pk\' table="relations"."{tables[i]}" sql=', tables[i], 'postgres') + vl_tables[i] = QgsVectorLayer( + self.dbconn + + f' sslmode=disable key=\'pk\' table="relations"."{tables[i]}" sql=', + tables[i], + "postgres", + ) assert vl_tables[i].isValid() QgsProject.instance().addMapLayer(vl_tables[i]) @@ -62,9 +96,19 @@ def test_discover_relations(self): def test_discover_relations_spaced(self): """Test regression https://github.com/qgis/QGIS/issues/39025 and https://github.com/qgis/QGIS/issues/39036""" - vl_parent = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'pk\' table="spaced schema"."spaced parent" sql=', 'parent', 'postgres') + vl_parent = QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'pk\' table="spaced schema"."spaced parent" sql=', + "parent", + "postgres", + ) self.assertTrue(vl_parent.isValid()) - vl_child = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'pk\' table="spaced schema"."spaced child" sql=', 'child', 'postgres') + vl_child = QgsVectorLayer( + self.dbconn + + ' sslmode=disable key=\'pk\' table="spaced schema"."spaced child" sql=', + "child", + "postgres", + ) self.assertTrue(vl_child.isValid()) QgsProject.instance().clear() @@ -74,5 +118,5 @@ def test_discover_relations_spaced(self): self.assertEqual(len(relations), 1) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrendercontext.py b/tests/src/python/test_qgsrendercontext.py index 61981b4bd181..c5db636a0c57 100644 --- a/tests/src/python/test_qgsrendercontext.py +++ b/tests/src/python/test_qgsrendercontext.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '16/01/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "16/01/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtCore import QDateTime, QSize from qgis.PyQt.QtGui import QImage, QPainter, QPainterPath @@ -28,7 +29,7 @@ QgsRenderedFeatureHandlerInterface, QgsUnitTypes, QgsVectorSimplifyMethod, - QgsVectorLayer + QgsVectorLayer, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -53,9 +54,16 @@ def testGettersSetters(self): c = QgsRenderContext() c.setTextRenderFormat(QgsRenderContext.TextRenderFormat.TextFormatAlwaysText) - self.assertEqual(c.textRenderFormat(), QgsRenderContext.TextRenderFormat.TextFormatAlwaysText) - c.setTextRenderFormat(QgsRenderContext.TextRenderFormat.TextFormatAlwaysOutlines) - self.assertEqual(c.textRenderFormat(), QgsRenderContext.TextRenderFormat.TextFormatAlwaysOutlines) + self.assertEqual( + c.textRenderFormat(), QgsRenderContext.TextRenderFormat.TextFormatAlwaysText + ) + c.setTextRenderFormat( + QgsRenderContext.TextRenderFormat.TextFormatAlwaysOutlines + ) + self.assertEqual( + c.textRenderFormat(), + QgsRenderContext.TextRenderFormat.TextFormatAlwaysOutlines, + ) c.setMapExtent(QgsRectangle(1, 2, 3, 4)) self.assertEqual(c.mapExtent(), QgsRectangle(1, 2, 3, 4)) @@ -108,7 +116,10 @@ def testCopyConstructor(self): c1.setCurrentFrame(6) c2 = QgsRenderContext(c1) - self.assertEqual(c2.textRenderFormat(), QgsRenderContext.TextRenderFormat.TextFormatAlwaysText) + self.assertEqual( + c2.textRenderFormat(), + QgsRenderContext.TextRenderFormat.TextFormatAlwaysText, + ) self.assertEqual(c2.mapExtent(), QgsRectangle(1, 2, 3, 4)) self.assertEqual(c2.zRange(), QgsDoubleRange(1, 10)) self.assertEqual(c2.symbologyReferenceScale(), 1000) @@ -119,20 +130,33 @@ def testCopyConstructor(self): self.assertEqual(c2.frameRate(), 30) self.assertEqual(c2.currentFrame(), 6) - c1.setTextRenderFormat(QgsRenderContext.TextRenderFormat.TextFormatAlwaysOutlines) + c1.setTextRenderFormat( + QgsRenderContext.TextRenderFormat.TextFormatAlwaysOutlines + ) c2 = QgsRenderContext(c1) - self.assertEqual(c2.textRenderFormat(), QgsRenderContext.TextRenderFormat.TextFormatAlwaysOutlines) + self.assertEqual( + c2.textRenderFormat(), + QgsRenderContext.TextRenderFormat.TextFormatAlwaysOutlines, + ) c1.setIsTemporal(True) - c1.setTemporalRange(QgsDateTimeRange(QDateTime(2020, 1, 1, 0, 0), QDateTime(2010, 12, 31, 23, 59))) + c1.setTemporalRange( + QgsDateTimeRange( + QDateTime(2020, 1, 1, 0, 0), QDateTime(2010, 12, 31, 23, 59) + ) + ) c2 = QgsRenderContext(c1) self.assertEqual(c2.isTemporal(), True) - self.assertEqual(c2.temporalRange(), - QgsDateTimeRange(QDateTime(2020, 1, 1, 0, 0), QDateTime(2010, 12, 31, 23, 59))) + self.assertEqual( + c2.temporalRange(), + QgsDateTimeRange( + QDateTime(2020, 1, 1, 0, 0), QDateTime(2010, 12, 31, 23, 59) + ), + ) def testFromQPainter(self): - """ test QgsRenderContext.fromQPainter """ + """test QgsRenderContext.fromQPainter""" # no painter c = QgsRenderContext.fromQPainter(None) @@ -145,7 +169,9 @@ def testFromQPainter(self): c = QgsRenderContext.fromQPainter(p) self.assertEqual(c.painter(), p) self.assertEqual(c.testFlag(QgsRenderContext.Flag.Antialiasing), False) - self.assertEqual(c.testFlag(QgsRenderContext.Flag.LosslessImageRendering), False) + self.assertEqual( + c.testFlag(QgsRenderContext.Flag.LosslessImageRendering), False + ) self.assertAlmostEqual(c.scaleFactor(), 88 / 25.4, 3) # should have an invalid mapToPixel by default @@ -166,8 +192,12 @@ def testFromQPainter(self): c = QgsRenderContext.fromQPainter(p) self.assertEqual(c.painter(), p) self.assertEqual(c.testFlag(QgsRenderContext.Flag.Antialiasing), True) - self.assertEqual(c.testFlag(QgsRenderContext.Flag.LosslessImageRendering), supports_lossless) - self.assertAlmostEqual(c.scaleFactor(), dots_per_m / 1000, 3) # scaleFactor should be pixels/mm + self.assertEqual( + c.testFlag(QgsRenderContext.Flag.LosslessImageRendering), supports_lossless + ) + self.assertAlmostEqual( + c.scaleFactor(), dots_per_m / 1000, 3 + ) # scaleFactor should be pixels/mm def testFromMapSettings(self): """ @@ -175,7 +205,7 @@ def testFromMapSettings(self): """ ms = QgsMapSettings() ms.setOutputSize(QSize(1000, 1000)) - ms.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3111')) + ms.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3111")) ms.setExtent(QgsRectangle(10000, 20000, 30000, 40000)) ms.setFlag(QgsMapSettings.Flag.Antialiasing, True) ms.setFlag(QgsMapSettings.Flag.LosslessImageRendering, True) @@ -187,14 +217,17 @@ def testFromMapSettings(self): ms.setFrameRate(30) ms.setCurrentFrame(6) - layer1 = QgsVectorLayer('Point?crs=EPSG:3857', '', 'memory') - layer2 = QgsVectorLayer('Point?crs=EPSG:3857', '', 'memory') - layer3 = QgsVectorLayer('Point?crs=EPSG:3857', '', 'memory') + layer1 = QgsVectorLayer("Point?crs=EPSG:3857", "", "memory") + layer2 = QgsVectorLayer("Point?crs=EPSG:3857", "", "memory") + layer3 = QgsVectorLayer("Point?crs=EPSG:3857", "", "memory") ms.setLayers([layer1, layer2, layer3]) ms.setTextRenderFormat(QgsRenderContext.TextRenderFormat.TextFormatAlwaysText) rc = QgsRenderContext.fromMapSettings(ms) - self.assertEqual(rc.textRenderFormat(), QgsRenderContext.TextRenderFormat.TextFormatAlwaysText) + self.assertEqual( + rc.textRenderFormat(), + QgsRenderContext.TextRenderFormat.TextFormatAlwaysText, + ) self.assertTrue(rc.testFlag(QgsRenderContext.Flag.Antialiasing)) self.assertTrue(rc.testFlag(QgsRenderContext.Flag.LosslessImageRendering)) self.assertTrue(rc.testFlag(QgsRenderContext.Flag.Render3DMap)) @@ -206,15 +239,23 @@ def testFromMapSettings(self): self.assertEqual(rc.imageFormat(), QImage.Format.Format_Alpha8) self.assertEqual(rc.frameRate(), 30) self.assertEqual(rc.currentFrame(), 6) - self.assertEqual(rc.customProperties()['visible_layer_ids'], [layer1.id(), layer2.id(), layer3.id()]) + self.assertEqual( + rc.customProperties()["visible_layer_ids"], + [layer1.id(), layer2.id(), layer3.id()], + ) # should have an valid mapToPixel self.assertTrue(rc.mapToPixel().isValid()) - ms.setTextRenderFormat(QgsRenderContext.TextRenderFormat.TextFormatAlwaysOutlines) + ms.setTextRenderFormat( + QgsRenderContext.TextRenderFormat.TextFormatAlwaysOutlines + ) ms.setZRange(QgsDoubleRange()) rc = QgsRenderContext.fromMapSettings(ms) - self.assertEqual(rc.textRenderFormat(), QgsRenderContext.TextRenderFormat.TextFormatAlwaysOutlines) + self.assertEqual( + rc.textRenderFormat(), + QgsRenderContext.TextRenderFormat.TextFormatAlwaysOutlines, + ) self.assertTrue(ms.zRange().isInfinite()) self.assertEqual(rc.mapExtent(), QgsRectangle(10000, 20000, 30000, 40000)) @@ -223,10 +264,18 @@ def testFromMapSettings(self): rc = QgsRenderContext.fromMapSettings(ms) self.assertEqual(rc.isTemporal(), True) - ms.setTemporalRange(QgsDateTimeRange(QDateTime(2020, 1, 1, 0, 0), QDateTime(2010, 12, 31, 23, 59))) + ms.setTemporalRange( + QgsDateTimeRange( + QDateTime(2020, 1, 1, 0, 0), QDateTime(2010, 12, 31, 23, 59) + ) + ) rc = QgsRenderContext.fromMapSettings(ms) - self.assertEqual(rc.temporalRange(), - QgsDateTimeRange(QDateTime(2020, 1, 1, 0, 0), QDateTime(2010, 12, 31, 23, 59))) + self.assertEqual( + rc.temporalRange(), + QgsDateTimeRange( + QDateTime(2020, 1, 1, 0, 0), QDateTime(2010, 12, 31, 23, 59) + ), + ) ms.setDpiTarget(111.1) rc = QgsRenderContext.fromMapSettings(ms) @@ -237,24 +286,41 @@ def testVectorSimplification(self): Test vector simplification hints, ensure they are copied correctly from map settings """ rc = QgsRenderContext() - self.assertEqual(rc.vectorSimplifyMethod().simplifyHints(), QgsVectorSimplifyMethod.SimplifyHint.NoSimplification) + self.assertEqual( + rc.vectorSimplifyMethod().simplifyHints(), + QgsVectorSimplifyMethod.SimplifyHint.NoSimplification, + ) ms = QgsMapSettings() rc = QgsRenderContext.fromMapSettings(ms) - self.assertEqual(rc.vectorSimplifyMethod().simplifyHints(), QgsVectorSimplifyMethod.SimplifyHint.NoSimplification) + self.assertEqual( + rc.vectorSimplifyMethod().simplifyHints(), + QgsVectorSimplifyMethod.SimplifyHint.NoSimplification, + ) rc2 = QgsRenderContext(rc) - self.assertEqual(rc2.vectorSimplifyMethod().simplifyHints(), QgsVectorSimplifyMethod.SimplifyHint.NoSimplification) + self.assertEqual( + rc2.vectorSimplifyMethod().simplifyHints(), + QgsVectorSimplifyMethod.SimplifyHint.NoSimplification, + ) method = QgsVectorSimplifyMethod() - method.setSimplifyHints(QgsVectorSimplifyMethod.SimplifyHint.GeometrySimplification) + method.setSimplifyHints( + QgsVectorSimplifyMethod.SimplifyHint.GeometrySimplification + ) ms.setSimplifyMethod(method) rc = QgsRenderContext.fromMapSettings(ms) - self.assertEqual(rc.vectorSimplifyMethod().simplifyHints(), QgsVectorSimplifyMethod.SimplifyHint.GeometrySimplification) + self.assertEqual( + rc.vectorSimplifyMethod().simplifyHints(), + QgsVectorSimplifyMethod.SimplifyHint.GeometrySimplification, + ) rc2 = QgsRenderContext(rc) - self.assertEqual(rc2.vectorSimplifyMethod().simplifyHints(), QgsVectorSimplifyMethod.SimplifyHint.GeometrySimplification) + self.assertEqual( + rc2.vectorSimplifyMethod().simplifyHints(), + QgsVectorSimplifyMethod.SimplifyHint.GeometrySimplification, + ) def test_mask_settings(self): """ @@ -296,14 +362,16 @@ def testRenderedFeatureHandlers(self): self.assertTrue(rc2.hasRenderedFeatureHandlers()) def testRenderMetersInMapUnits(self): - crs_wsg84 = QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:4326') - rt_extent = QgsRectangle(13.37768985634235, 52.51625705830762, 13.37771931686235, 52.51628651882762) + crs_wsg84 = QgsCoordinateReferenceSystem.fromOgcWmsCrs("EPSG:4326") + rt_extent = QgsRectangle( + 13.37768985634235, 52.51625705830762, 13.37771931686235, 52.51628651882762 + ) point_berlin_wsg84 = QgsPointXY(13.37770458660236, 52.51627178856762) length_wsg84_mapunits = 0.00001473026350140572 meters_test = 2.40 da_wsg84 = QgsDistanceArea() da_wsg84.setSourceCrs(crs_wsg84, QgsProject.instance().transformContext()) - if (da_wsg84.sourceCrs().isGeographic()): + if da_wsg84.sourceCrs().isGeographic(): da_wsg84.setEllipsoid(da_wsg84.sourceCrs().ellipsoidAcronym()) meters_test_mapunits = meters_test * length_wsg84_mapunits ms = QgsMapSettings() @@ -312,27 +380,66 @@ def testRenderMetersInMapUnits(self): ms.setOutputSize(QSize(50, 50)) r = QgsRenderContext.fromMapSettings(ms) r.setExtent(rt_extent) - self.assertEqual(r.extent().center().toString(7), point_berlin_wsg84.toString(7)) + self.assertEqual( + r.extent().center().toString(7), point_berlin_wsg84.toString(7) + ) c = QgsMapUnitScale() r.setDistanceArea(da_wsg84) - result_test_painterunits = r.convertToPainterUnits(meters_test, QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, c) + result_test_painterunits = r.convertToPainterUnits( + meters_test, QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, c + ) self.assertAlmostEqual(result_test_painterunits, 60.0203759, 1) - result_test_painterunits = r.convertToPainterUnits(-meters_test, QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, c) + result_test_painterunits = r.convertToPainterUnits( + -meters_test, QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, c + ) self.assertAlmostEqual(result_test_painterunits, -60.0203759, 1) - result_test_mapunits = r.convertToMapUnits(meters_test, QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, c) - self.assertEqual(QgsDistanceArea.formatDistance(result_test_mapunits, 7, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - QgsDistanceArea.formatDistance(meters_test_mapunits, 7, QgsUnitTypes.DistanceUnit.DistanceDegrees, True)) - result_test_mapunits = r.convertToMapUnits(-meters_test, QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, c) - self.assertEqual(QgsDistanceArea.formatDistance(result_test_mapunits, 7, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), - QgsDistanceArea.formatDistance(-meters_test_mapunits, 7, QgsUnitTypes.DistanceUnit.DistanceDegrees, True)) - result_test_meters = r.convertFromMapUnits(meters_test_mapunits, QgsUnitTypes.RenderUnit.RenderMetersInMapUnits) - self.assertEqual(QgsDistanceArea.formatDistance(result_test_meters, 1, QgsUnitTypes.DistanceUnit.DistanceMeters, True), - QgsDistanceArea.formatDistance(meters_test, 1, QgsUnitTypes.DistanceUnit.DistanceMeters, True)) + result_test_mapunits = r.convertToMapUnits( + meters_test, QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, c + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + result_test_mapunits, 7, QgsUnitTypes.DistanceUnit.DistanceDegrees, True + ), + QgsDistanceArea.formatDistance( + meters_test_mapunits, 7, QgsUnitTypes.DistanceUnit.DistanceDegrees, True + ), + ) + result_test_mapunits = r.convertToMapUnits( + -meters_test, QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, c + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + result_test_mapunits, 7, QgsUnitTypes.DistanceUnit.DistanceDegrees, True + ), + QgsDistanceArea.formatDistance( + -meters_test_mapunits, + 7, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + True, + ), + ) + result_test_meters = r.convertFromMapUnits( + meters_test_mapunits, QgsUnitTypes.RenderUnit.RenderMetersInMapUnits + ) + self.assertEqual( + QgsDistanceArea.formatDistance( + result_test_meters, 1, QgsUnitTypes.DistanceUnit.DistanceMeters, True + ), + QgsDistanceArea.formatDistance( + meters_test, 1, QgsUnitTypes.DistanceUnit.DistanceMeters, True + ), + ) # attempting to convert to meters in map units when no extent is available should fallback to a very # approximate degrees -> meters conversion r.setExtent(QgsRectangle()) - self.assertAlmostEqual(r.convertToPainterUnits(5555, QgsUnitTypes.RenderUnit.RenderMetersInMapUnits), 84692, -10) + self.assertAlmostEqual( + r.convertToPainterUnits( + 5555, QgsUnitTypes.RenderUnit.RenderMetersInMapUnits + ), + 84692, + -10, + ) def testConvertSingleUnit(self): ms = QgsMapSettings() @@ -494,17 +601,25 @@ def testConvertToPainterUnitsNoMapToPixel(self): # what else can we do? size = r.convertToPainterUnits(10, QgsUnitTypes.RenderUnit.RenderMapUnits, c) self.assertAlmostEqual(size, 41.66666, places=3) - size = r.convertToPainterUnits(10, QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, c) + size = r.convertToPainterUnits( + 10, QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, c + ) self.assertAlmostEqual(size, 41.66666, places=3) # sizes should be clamped to reasonable range -- we don't want to treat 2000m map unit sizes as 10 million pixels! size = r.convertToPainterUnits(2000, QgsUnitTypes.RenderUnit.RenderMapUnits, c) self.assertEqual(size, 100.0) - size = r.convertToPainterUnits(2000, QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, c) + size = r.convertToPainterUnits( + 2000, QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, c + ) self.assertEqual(size, 100.0) - size = r.convertToPainterUnits(0.0002, QgsUnitTypes.RenderUnit.RenderMapUnits, c) + size = r.convertToPainterUnits( + 0.0002, QgsUnitTypes.RenderUnit.RenderMapUnits, c + ) self.assertEqual(size, 10.0) - size = r.convertToPainterUnits(0.0002, QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, c) + size = r.convertToPainterUnits( + 0.0002, QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, c + ) self.assertEqual(size, 10.0) # normal units, should not be affected @@ -543,20 +658,50 @@ def testConvertToPainterUnitsSpecialCases(self): self.assertAlmostEqual(size, 118.11023622047244, places=5) r.setFlag(Qgis.RenderContextFlag.RenderSymbolPreview, False) - size = r.convertToPainterUnits(10, QgsUnitTypes.RenderUnit.RenderMillimeters, c, Qgis.RenderSubcomponentProperty.BlurSize) + size = r.convertToPainterUnits( + 10, + QgsUnitTypes.RenderUnit.RenderMillimeters, + c, + Qgis.RenderSubcomponentProperty.BlurSize, + ) self.assertAlmostEqual(size, 118.11023622047244, places=5) - size = r.convertToPainterUnits(10, QgsUnitTypes.RenderUnit.RenderMillimeters, c, Qgis.RenderSubcomponentProperty.ShadowOffset) + size = r.convertToPainterUnits( + 10, + QgsUnitTypes.RenderUnit.RenderMillimeters, + c, + Qgis.RenderSubcomponentProperty.ShadowOffset, + ) self.assertAlmostEqual(size, 118.11023622047244, places=5) - size = r.convertToPainterUnits(10, QgsUnitTypes.RenderUnit.RenderMillimeters, c, Qgis.RenderSubcomponentProperty.GlowSpread) + size = r.convertToPainterUnits( + 10, + QgsUnitTypes.RenderUnit.RenderMillimeters, + c, + Qgis.RenderSubcomponentProperty.GlowSpread, + ) self.assertAlmostEqual(size, 118.11023622047244, places=5) # subcomponents which should be size limited in symbol previews r.setFlag(Qgis.RenderContextFlag.RenderSymbolPreview, True) - size = r.convertToPainterUnits(10, QgsUnitTypes.RenderUnit.RenderMillimeters, c, Qgis.RenderSubcomponentProperty.BlurSize) + size = r.convertToPainterUnits( + 10, + QgsUnitTypes.RenderUnit.RenderMillimeters, + c, + Qgis.RenderSubcomponentProperty.BlurSize, + ) self.assertAlmostEqual(size, 30.0, places=5) - size = r.convertToPainterUnits(10, QgsUnitTypes.RenderUnit.RenderMillimeters, c, Qgis.RenderSubcomponentProperty.ShadowOffset) + size = r.convertToPainterUnits( + 10, + QgsUnitTypes.RenderUnit.RenderMillimeters, + c, + Qgis.RenderSubcomponentProperty.ShadowOffset, + ) self.assertAlmostEqual(size, 100.0, places=5) - size = r.convertToPainterUnits(10, QgsUnitTypes.RenderUnit.RenderMillimeters, c, Qgis.RenderSubcomponentProperty.GlowSpread) + size = r.convertToPainterUnits( + 10, + QgsUnitTypes.RenderUnit.RenderMillimeters, + c, + Qgis.RenderSubcomponentProperty.GlowSpread, + ) self.assertAlmostEqual(size, 50.0, places=5) def testConvertToMapUnits(self): @@ -573,19 +718,33 @@ def testConvertToMapUnits(self): size = r.convertToMapUnits(2, QgsUnitTypes.RenderUnit.RenderMapUnits, c) self.assertEqual(size, 2.0) - self.assertEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderMapUnits), 2) + self.assertEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderMapUnits), 2 + ) size = r.convertToMapUnits(2, QgsUnitTypes.RenderUnit.RenderMillimeters, c) self.assertAlmostEqual(size, 47.244094, places=5) - self.assertEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderMillimeters), 2) + self.assertEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderMillimeters), 2 + ) size = r.convertToMapUnits(5.66929, QgsUnitTypes.RenderUnit.RenderPoints, c) self.assertAlmostEqual(size, 47.2440833, places=5) - self.assertAlmostEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderPoints), 5.66929, 4) + self.assertAlmostEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderPoints), + 5.66929, + 4, + ) size = r.convertToMapUnits(5.66929, QgsUnitTypes.RenderUnit.RenderInches, c) self.assertAlmostEqual(size, 3401.574, places=5) - self.assertAlmostEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderInches), 5.66929, 4) + self.assertAlmostEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderInches), + 5.66929, + 4, + ) size = r.convertToMapUnits(2, QgsUnitTypes.RenderUnit.RenderPixels, c) self.assertAlmostEqual(size, 4.0, places=5) - self.assertAlmostEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderPixels), 2, 4) + self.assertAlmostEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderPixels), 2, 4 + ) # minimum size greater than the calculated size, so size should be limited to minSizeMM c.minSizeMM = 5 @@ -656,53 +815,95 @@ def testConvertToMapUnits(self): size = r.convertToMapUnits(2, QgsUnitTypes.RenderUnit.RenderMapUnits, c) self.assertEqual(size, 2.0) - self.assertEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderMapUnits), 2) + self.assertEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderMapUnits), 2 + ) size = r.convertToMapUnits(2, QgsUnitTypes.RenderUnit.RenderMillimeters, c) self.assertAlmostEqual(size, 47.244094, places=5) - self.assertEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderMillimeters), 2) + self.assertEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderMillimeters), 2 + ) size = r.convertToMapUnits(5.66929, QgsUnitTypes.RenderUnit.RenderPoints, c) self.assertAlmostEqual(size, 47.2440833, places=5) - self.assertAlmostEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderPoints), 5.66929, 4) + self.assertAlmostEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderPoints), + 5.66929, + 4, + ) size = r.convertToMapUnits(5.66929, QgsUnitTypes.RenderUnit.RenderInches, c) self.assertAlmostEqual(size, 3401.574, places=5) - self.assertAlmostEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderInches), 5.66929, 4) + self.assertAlmostEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderInches), + 5.66929, + 4, + ) size = r.convertToMapUnits(2, QgsUnitTypes.RenderUnit.RenderPixels, c) self.assertAlmostEqual(size, 4.0, places=5) - self.assertAlmostEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderPixels), 2, 4) + self.assertAlmostEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderPixels), 2, 4 + ) r.setRendererScale(2000) size = r.convertToMapUnits(2, QgsUnitTypes.RenderUnit.RenderMapUnits, c) self.assertEqual(size, 2.0) - self.assertEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderMapUnits), 2) + self.assertEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderMapUnits), 2 + ) size = r.convertToMapUnits(2, QgsUnitTypes.RenderUnit.RenderMillimeters, c) self.assertAlmostEqual(size, 47.244094 * 2, places=5) - self.assertEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderMillimeters), 2) + self.assertEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderMillimeters), 2 + ) size = r.convertToMapUnits(5.66929, QgsUnitTypes.RenderUnit.RenderPoints, c) self.assertAlmostEqual(size, 47.2440833 * 2, places=5) - self.assertAlmostEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderPoints), 5.66929, 4) + self.assertAlmostEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderPoints), + 5.66929, + 4, + ) size = r.convertToMapUnits(5.66929, QgsUnitTypes.RenderUnit.RenderInches, c) self.assertAlmostEqual(size, 3401.574 * 2, places=5) - self.assertAlmostEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderInches), 5.66929, 4) + self.assertAlmostEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderInches), + 5.66929, + 4, + ) size = r.convertToMapUnits(2, QgsUnitTypes.RenderUnit.RenderPixels, c) self.assertAlmostEqual(size, 4.0 * 2, places=5) - self.assertAlmostEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderPixels), 2, 4) + self.assertAlmostEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderPixels), 2, 4 + ) r.setRendererScale(500) size = r.convertToMapUnits(2, QgsUnitTypes.RenderUnit.RenderMapUnits, c) self.assertEqual(size, 2.0) - self.assertEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderMapUnits), 2) + self.assertEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderMapUnits), 2 + ) size = r.convertToMapUnits(2, QgsUnitTypes.RenderUnit.RenderMillimeters, c) self.assertAlmostEqual(size, 47.244094 / 2, places=5) - self.assertEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderMillimeters), 2) + self.assertEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderMillimeters), 2 + ) size = r.convertToMapUnits(5.66929, QgsUnitTypes.RenderUnit.RenderPoints, c) self.assertAlmostEqual(size, 47.2440833 / 2, places=5) - self.assertAlmostEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderPoints), 5.66929, 4) + self.assertAlmostEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderPoints), + 5.66929, + 4, + ) size = r.convertToMapUnits(5.66929, QgsUnitTypes.RenderUnit.RenderInches, c) self.assertAlmostEqual(size, 3401.574 / 2, places=5) - self.assertAlmostEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderInches), 5.66929, 4) + self.assertAlmostEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderInches), + 5.66929, + 4, + ) size = r.convertToMapUnits(2, QgsUnitTypes.RenderUnit.RenderPixels, c) self.assertAlmostEqual(size, 4.0 / 2, places=5) - self.assertAlmostEqual(r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderPixels), 2, 4) + self.assertAlmostEqual( + r.convertFromMapUnits(size, QgsUnitTypes.RenderUnit.RenderPixels), 2, 4 + ) def testConvertFromPainterUnits(self): ms = QgsMapSettings() @@ -817,18 +1018,18 @@ def testMapUnitScaleFactor(self): def testCustomRenderingFlags(self): rc = QgsRenderContext() - rc.setCustomRenderingFlag('myexport', True) - rc.setCustomRenderingFlag('omitgeometries', 'points') - self.assertTrue(rc.customRenderingFlags()['myexport']) - self.assertEqual(rc.customRenderingFlags()['omitgeometries'], 'points') + rc.setCustomRenderingFlag("myexport", True) + rc.setCustomRenderingFlag("omitgeometries", "points") + self.assertTrue(rc.customRenderingFlags()["myexport"]) + self.assertEqual(rc.customRenderingFlags()["omitgeometries"], "points") # test that custom flags are correctly copied from settings settings = QgsMapSettings() - settings.setCustomRenderingFlag('myexport', True) - settings.setCustomRenderingFlag('omitgeometries', 'points') + settings.setCustomRenderingFlag("myexport", True) + settings.setCustomRenderingFlag("omitgeometries", "points") rc = QgsRenderContext.fromMapSettings(settings) - self.assertTrue(rc.customRenderingFlags()['myexport']) - self.assertEqual(rc.customRenderingFlags()['omitgeometries'], 'points') + self.assertTrue(rc.customRenderingFlags()["myexport"]) + self.assertEqual(rc.customRenderingFlags()["omitgeometries"], "points") def testTemporalState(self): rc = QgsRenderContext() @@ -839,35 +1040,56 @@ def testClippingRegion(self): ms = QgsMapSettings() rc = QgsRenderContext.fromMapSettings(ms) self.assertFalse(rc.clippingRegions()) - ms.addClippingRegion(QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon(( 0 0, 1 0 , 1 1 , 0 1, 0 0 ))'))) - ms.addClippingRegion(QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon(( 10 0, 11 0 , 11 1 , 10 1, 10 0 ))'))) + ms.addClippingRegion( + QgsMapClippingRegion( + QgsGeometry.fromWkt("Polygon(( 0 0, 1 0 , 1 1 , 0 1, 0 0 ))") + ) + ) + ms.addClippingRegion( + QgsMapClippingRegion( + QgsGeometry.fromWkt("Polygon(( 10 0, 11 0 , 11 1 , 10 1, 10 0 ))") + ) + ) rc = QgsRenderContext.fromMapSettings(ms) self.assertEqual(len(rc.clippingRegions()), 2) - self.assertEqual(rc.clippingRegions()[0].geometry().asWkt(), 'Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))') - self.assertEqual(rc.clippingRegions()[1].geometry().asWkt(), 'Polygon ((10 0, 11 0, 11 1, 10 1, 10 0))') + self.assertEqual( + rc.clippingRegions()[0].geometry().asWkt(), + "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))", + ) + self.assertEqual( + rc.clippingRegions()[1].geometry().asWkt(), + "Polygon ((10 0, 11 0, 11 1, 10 1, 10 0))", + ) def testFeatureClipGeometry(self): rc = QgsRenderContext() self.assertTrue(rc.featureClipGeometry().isNull()) - rc.setFeatureClipGeometry(QgsGeometry.fromWkt('Polygon(( 0 0, 1 0 , 1 1 , 0 1, 0 0 ))')) - self.assertEqual(rc.featureClipGeometry().asWkt(), 'Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))') + rc.setFeatureClipGeometry( + QgsGeometry.fromWkt("Polygon(( 0 0, 1 0 , 1 1 , 0 1, 0 0 ))") + ) + self.assertEqual( + rc.featureClipGeometry().asWkt(), "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))" + ) rc2 = QgsRenderContext(rc) - self.assertEqual(rc2.featureClipGeometry().asWkt(), 'Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))') + self.assertEqual( + rc2.featureClipGeometry().asWkt(), "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))" + ) def test_deprecated_mask_methods(self): rc = QgsRenderContext() - self.assertFalse(rc.symbolLayerClipPaths('x')) + self.assertFalse(rc.symbolLayerClipPaths("x")) path = QPainterPath() path.moveTo(1, 1) path.lineTo(1, 10) path.lineTo(10, 10) path.lineTo(10, 1) path.lineTo(1, 1) - rc.addSymbolLayerClipPath('x', path) - self.assertEqual([g.asWkt() for g in rc.symbolLayerClipGeometries('x')], - ['Polygon ((1 1, 1 10, 10 10, 10 1, 1 1))']) - self.assertEqual([p.elementCount() for p in rc.symbolLayerClipPaths('x')], - [5]) + rc.addSymbolLayerClipPath("x", path) + self.assertEqual( + [g.asWkt() for g in rc.symbolLayerClipGeometries("x")], + ["Polygon ((1 1, 1 10, 10 10, 10 1, 1 1))"], + ) + self.assertEqual([p.elementCount() for p in rc.symbolLayerClipPaths("x")], [5]) def testSetPainterFlags(self): rc = QgsRenderContext() @@ -877,7 +1099,9 @@ def testSetPainterFlags(self): rc.setPainterFlagsUsingContext(p) self.assertFalse(p.testRenderHint(QPainter.RenderHint.Antialiasing)) try: - self.assertFalse(p.testRenderHint(QPainter.RenderHint.LosslessImageRendering)) + self.assertFalse( + p.testRenderHint(QPainter.RenderHint.LosslessImageRendering) + ) except AttributeError: pass @@ -887,7 +1111,9 @@ def testSetPainterFlags(self): rc.setPainterFlagsUsingContext(p) self.assertTrue(p.testRenderHint(QPainter.RenderHint.Antialiasing)) try: - self.assertTrue(p.testRenderHint(QPainter.RenderHint.LosslessImageRendering)) + self.assertTrue( + p.testRenderHint(QPainter.RenderHint.LosslessImageRendering) + ) except AttributeError: pass @@ -898,56 +1124,90 @@ def test_symbol_layer_clip_geometries(self): Test logic relating to symbol layer clip geometries. """ rc = QgsRenderContext() - self.assertFalse(rc.symbolLayerHasClipGeometries('x')) - - rc.addSymbolLayerClipGeometry('x', QgsGeometry.fromWkt('Polygon(( 0 0, 1 0 , 1 1 , 0 1, 0 0 ))')) - self.assertTrue(rc.symbolLayerHasClipGeometries('x')) - self.assertFalse(rc.symbolLayerHasClipGeometries('y')) - - self.assertEqual([g.asWkt() for g in rc.symbolLayerClipGeometries('x')], - ['Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))']) - self.assertFalse(rc.symbolLayerClipGeometries('y')) - rc.addSymbolLayerClipGeometry('x', QgsGeometry.fromWkt( - 'Polygon(( 20 0, 21 0 , 21 1 , 20 1, 20 0 ))')) - self.assertEqual([g.asWkt() for g in rc.symbolLayerClipGeometries('x')], - ['Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))', - 'Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))']) - self.assertFalse(rc.symbolLayerClipGeometries('y')) - rc.addSymbolLayerClipGeometry('y', QgsGeometry.fromWkt( - 'Polygon(( 30 0, 31 0 , 31 1 , 30 1, 30 0 ))')) - self.assertEqual([g.asWkt() for g in rc.symbolLayerClipGeometries('x')], - ['Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))', - 'Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))']) - self.assertEqual([g.asWkt() for g in rc.symbolLayerClipGeometries('y')], - ['Polygon ((30 0, 31 0, 31 1, 30 1, 30 0))']) + self.assertFalse(rc.symbolLayerHasClipGeometries("x")) + + rc.addSymbolLayerClipGeometry( + "x", QgsGeometry.fromWkt("Polygon(( 0 0, 1 0 , 1 1 , 0 1, 0 0 ))") + ) + self.assertTrue(rc.symbolLayerHasClipGeometries("x")) + self.assertFalse(rc.symbolLayerHasClipGeometries("y")) + + self.assertEqual( + [g.asWkt() for g in rc.symbolLayerClipGeometries("x")], + ["Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))"], + ) + self.assertFalse(rc.symbolLayerClipGeometries("y")) + rc.addSymbolLayerClipGeometry( + "x", QgsGeometry.fromWkt("Polygon(( 20 0, 21 0 , 21 1 , 20 1, 20 0 ))") + ) + self.assertEqual( + [g.asWkt() for g in rc.symbolLayerClipGeometries("x")], + [ + "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))", + "Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))", + ], + ) + self.assertFalse(rc.symbolLayerClipGeometries("y")) + rc.addSymbolLayerClipGeometry( + "y", QgsGeometry.fromWkt("Polygon(( 30 0, 31 0 , 31 1 , 30 1, 30 0 ))") + ) + self.assertEqual( + [g.asWkt() for g in rc.symbolLayerClipGeometries("x")], + [ + "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))", + "Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))", + ], + ) + self.assertEqual( + [g.asWkt() for g in rc.symbolLayerClipGeometries("y")], + ["Polygon ((30 0, 31 0, 31 1, 30 1, 30 0))"], + ) rc2 = QgsRenderContext(rc) - self.assertTrue(rc2.symbolLayerHasClipGeometries('x')) - self.assertTrue(rc2.symbolLayerHasClipGeometries('y')) - self.assertFalse(rc2.symbolLayerHasClipGeometries('z')) - self.assertEqual([g.asWkt() for g in rc2.symbolLayerClipGeometries('x')], - ['Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))', - 'Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))']) + self.assertTrue(rc2.symbolLayerHasClipGeometries("x")) + self.assertTrue(rc2.symbolLayerHasClipGeometries("y")) + self.assertFalse(rc2.symbolLayerHasClipGeometries("z")) self.assertEqual( - [g.asWkt() for g in rc2.symbolLayerClipGeometries('y')], - ['Polygon ((30 0, 31 0, 31 1, 30 1, 30 0))']) - self.assertFalse(rc2.symbolLayerClipGeometries('z')) + [g.asWkt() for g in rc2.symbolLayerClipGeometries("x")], + [ + "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))", + "Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))", + ], + ) + self.assertEqual( + [g.asWkt() for g in rc2.symbolLayerClipGeometries("y")], + ["Polygon ((30 0, 31 0, 31 1, 30 1, 30 0))"], + ) + self.assertFalse(rc2.symbolLayerClipGeometries("z")) # adding multipart geometries to the render context should # split these to multiple separate geometries rc = QgsRenderContext() - rc.addSymbolLayerClipGeometry('x', QgsGeometry.fromWkt( - 'MultiPolygon((( 0 0, 1 0 , 1 1 , 0 1, 0 0 )),((20 0, 21 0, 21 1, 20 1, 20 0)))')) - self.assertEqual([g.asWkt() for g in rc.symbolLayerClipGeometries('x')], - ['Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))', - 'Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))']) - rc.addSymbolLayerClipGeometry('x', QgsGeometry.fromWkt( - 'Polygon(( 30 0, 31 0 , 31 1 , 30 1, 30 0 ))')) - self.assertEqual([g.asWkt() for g in rc.symbolLayerClipGeometries('x')], - ['Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))', - 'Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))', - 'Polygon ((30 0, 31 0, 31 1, 30 1, 30 0))']) - - -if __name__ == '__main__': + rc.addSymbolLayerClipGeometry( + "x", + QgsGeometry.fromWkt( + "MultiPolygon((( 0 0, 1 0 , 1 1 , 0 1, 0 0 )),((20 0, 21 0, 21 1, 20 1, 20 0)))" + ), + ) + self.assertEqual( + [g.asWkt() for g in rc.symbolLayerClipGeometries("x")], + [ + "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))", + "Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))", + ], + ) + rc.addSymbolLayerClipGeometry( + "x", QgsGeometry.fromWkt("Polygon(( 30 0, 31 0 , 31 1 , 30 1, 30 0 ))") + ) + self.assertEqual( + [g.asWkt() for g in rc.symbolLayerClipGeometries("x")], + [ + "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))", + "Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))", + "Polygon ((30 0, 31 0, 31 1, 30 1, 30 0))", + ], + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrendereditemresults.py b/tests/src/python/test_qgsrendereditemresults.py index 450d7bbd6fca..848b70c3e6b5 100644 --- a/tests/src/python/test_qgsrendereditemresults.py +++ b/tests/src/python/test_qgsrendereditemresults.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2021 by Nyall Dawson' -__date__ = '03/09/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "(C) 2021 by Nyall Dawson" +__date__ = "03/09/2021" +__copyright__ = "Copyright 2021, The QGIS Project" import math @@ -33,20 +34,22 @@ class TestQgsRenderedItemResults(QgisTestCase): def test_basic(self): - details = QgsRenderedItemDetails('layer_id') - self.assertEqual(details.layerId(), 'layer_id') + details = QgsRenderedItemDetails("layer_id") + self.assertEqual(details.layerId(), "layer_id") details.setBoundingBox(QgsRectangle(1, 2, 3, 4)) self.assertEqual(details.boundingBox(), QgsRectangle(1, 2, 3, 4)) def test_rendered_annotation_item_details(self): - details = QgsRenderedAnnotationItemDetails('layer_id', 'item_id') - self.assertEqual(details.layerId(), 'layer_id') - self.assertEqual(details.itemId(), 'item_id') - self.assertEqual(str(details), '') + details = QgsRenderedAnnotationItemDetails("layer_id", "item_id") + self.assertEqual(details.layerId(), "layer_id") + self.assertEqual(details.itemId(), "item_id") + self.assertEqual( + str(details), "" + ) def test_rendered_calculated_results(self): - results = QgsRenderedLayerStatistics('layer_id') - self.assertEqual(results.layerId(), 'layer_id') + results = QgsRenderedLayerStatistics("layer_id") + self.assertEqual(results.layerId(), "layer_id") self.assertEqual(len(results.minimum()), 1) self.assertTrue(math.isnan(results.minimum(0))) self.assertEqual(len(results.maximum()), 1) @@ -69,62 +72,107 @@ def test_rendered_calculated_results(self): self.assertEqual(len(results.maximum()), 2) self.assertEqual(results.maximum(), [10.0, 5.2]) - results2 = QgsRenderedLayerStatistics('layer_id', [-5.2, 3.0], [5.0, 9.3]) - self.assertEqual(results2.layerId(), 'layer_id') + results2 = QgsRenderedLayerStatistics("layer_id", [-5.2, 3.0], [5.0, 9.3]) + self.assertEqual(results2.layerId(), "layer_id") self.assertEqual(len(results.minimum()), 2) self.assertEqual(results2.minimum(), [-5.2, 3.0]) self.assertEqual(results2.minimum(1), 3.0) self.assertEqual(len(results.maximum()), 2) self.assertEqual(results2.maximum(1), 9.3) - self.assertEqual(str(results2), '') + self.assertEqual( + str(results2), + "", + ) def test_results(self): results = QgsRenderedItemResults() - self.assertFalse(results.renderedAnnotationItemsInBounds(QgsRectangle(-100000000, -100000000, 100000000, 100000000))) + self.assertFalse( + results.renderedAnnotationItemsInBounds( + QgsRectangle(-100000000, -100000000, 100000000, 100000000) + ) + ) rc = QgsRenderContext() - details1 = QgsRenderedAnnotationItemDetails('layer_id', 'item_id_1') + details1 = QgsRenderedAnnotationItemDetails("layer_id", "item_id_1") details1.setBoundingBox(QgsRectangle(1, 1, 10, 10)) - details2 = QgsRenderedAnnotationItemDetails('layer_id', 'item_id_2') + details2 = QgsRenderedAnnotationItemDetails("layer_id", "item_id_2") details2.setBoundingBox(QgsRectangle(1, 1, 5, 5)) results.appendResults([details1, details2], rc) # query annotation items - self.assertCountEqual([(i.layerId(), i.itemId()) for i in results.renderedAnnotationItemsInBounds(QgsRectangle(-100000000, -100000000, 100000000, 100000000))], - [('layer_id', 'item_id_1'), - ('layer_id', 'item_id_2')]) - self.assertCountEqual([(i.layerId(), i.itemId()) for i in results.renderedAnnotationItemsInBounds(QgsRectangle(0, 0, 10, 10))], - [('layer_id', 'item_id_1'), - ('layer_id', 'item_id_2')]) - self.assertCountEqual([(i.layerId(), i.itemId()) for i in results.renderedAnnotationItemsInBounds(QgsRectangle(6, 6, 10, 10))], - [('layer_id', 'item_id_1')]) + self.assertCountEqual( + [ + (i.layerId(), i.itemId()) + for i in results.renderedAnnotationItemsInBounds( + QgsRectangle(-100000000, -100000000, 100000000, 100000000) + ) + ], + [("layer_id", "item_id_1"), ("layer_id", "item_id_2")], + ) + self.assertCountEqual( + [ + (i.layerId(), i.itemId()) + for i in results.renderedAnnotationItemsInBounds( + QgsRectangle(0, 0, 10, 10) + ) + ], + [("layer_id", "item_id_1"), ("layer_id", "item_id_2")], + ) + self.assertCountEqual( + [ + (i.layerId(), i.itemId()) + for i in results.renderedAnnotationItemsInBounds( + QgsRectangle(6, 6, 10, 10) + ) + ], + [("layer_id", "item_id_1")], + ) # add another item - details3 = QgsRenderedAnnotationItemDetails('layer_id2', 'item_id_3') + details3 = QgsRenderedAnnotationItemDetails("layer_id2", "item_id_3") details3.setBoundingBox(QgsRectangle(4, 4, 7, 7)) results.appendResults([details3], rc) - self.assertCountEqual([(i.layerId(), i.itemId()) for i in results.renderedAnnotationItemsInBounds(QgsRectangle(0, 0, 10, 10))], - [('layer_id', 'item_id_1'), - ('layer_id', 'item_id_2'), - ('layer_id2', 'item_id_3')]) - self.assertCountEqual([(i.layerId(), i.itemId()) for i in results.renderedAnnotationItemsInBounds(QgsRectangle(6, 6, 10, 10))], - [('layer_id', 'item_id_1'), - ('layer_id2', 'item_id_3')]) + self.assertCountEqual( + [ + (i.layerId(), i.itemId()) + for i in results.renderedAnnotationItemsInBounds( + QgsRectangle(0, 0, 10, 10) + ) + ], + [ + ("layer_id", "item_id_1"), + ("layer_id", "item_id_2"), + ("layer_id2", "item_id_3"), + ], + ) + self.assertCountEqual( + [ + (i.layerId(), i.itemId()) + for i in results.renderedAnnotationItemsInBounds( + QgsRectangle(6, 6, 10, 10) + ) + ], + [("layer_id", "item_id_1"), ("layer_id2", "item_id_3")], + ) def test_transfer_results(self): results = QgsRenderedItemResults() - self.assertFalse(results.renderedAnnotationItemsInBounds(QgsRectangle(-100000000, -100000000, 100000000, 100000000))) + self.assertFalse( + results.renderedAnnotationItemsInBounds( + QgsRectangle(-100000000, -100000000, 100000000, 100000000) + ) + ) rc = QgsRenderContext() - details1 = QgsRenderedAnnotationItemDetails('layer_id', 'item_id_1') + details1 = QgsRenderedAnnotationItemDetails("layer_id", "item_id_1") details1.setBoundingBox(QgsRectangle(1, 1, 10, 10)) - details2 = QgsRenderedAnnotationItemDetails('layer_id2', 'item_id_2') + details2 = QgsRenderedAnnotationItemDetails("layer_id2", "item_id_2") details2.setBoundingBox(QgsRectangle(1, 1, 5, 5)) - details3 = QgsRenderedAnnotationItemDetails('layer_id3', 'item_id_3') + details3 = QgsRenderedAnnotationItemDetails("layer_id3", "item_id_3") details3.setBoundingBox(QgsRectangle(4, 4, 7, 7)) results.appendResults([details1, details2, details3], rc) @@ -133,83 +181,149 @@ def test_transfer_results(self): # transfer some results to results2 # first no layers specified => nothing should be transferred results2.transferResults(results, []) - self.assertCountEqual([(i.layerId(), i.itemId()) for i in results.renderedAnnotationItemsInBounds(QgsRectangle(0, 0, 10, 10))], - [('layer_id', 'item_id_1'), - ('layer_id2', 'item_id_2'), - ('layer_id3', 'item_id_3')]) - self.assertFalse(results2.renderedAnnotationItemsInBounds(QgsRectangle(0, 0, 10, 10))) - - results2.transferResults(results, ['layer_id2', 'layer_id3']) - self.assertEqual([(i.layerId(), i.itemId()) for i in results.renderedItems()], - [('layer_id', 'item_id_1')]) - self.assertCountEqual([(i.layerId(), i.itemId()) for i in results2.renderedAnnotationItemsInBounds(QgsRectangle(0, 0, 10, 10))], - [('layer_id2', 'item_id_2'), - ('layer_id3', 'item_id_3')]) + self.assertCountEqual( + [ + (i.layerId(), i.itemId()) + for i in results.renderedAnnotationItemsInBounds( + QgsRectangle(0, 0, 10, 10) + ) + ], + [ + ("layer_id", "item_id_1"), + ("layer_id2", "item_id_2"), + ("layer_id3", "item_id_3"), + ], + ) + self.assertFalse( + results2.renderedAnnotationItemsInBounds(QgsRectangle(0, 0, 10, 10)) + ) + + results2.transferResults(results, ["layer_id2", "layer_id3"]) + self.assertEqual( + [(i.layerId(), i.itemId()) for i in results.renderedItems()], + [("layer_id", "item_id_1")], + ) + self.assertCountEqual( + [ + (i.layerId(), i.itemId()) + for i in results2.renderedAnnotationItemsInBounds( + QgsRectangle(0, 0, 10, 10) + ) + ], + [("layer_id2", "item_id_2"), ("layer_id3", "item_id_3")], + ) # same layers, nothing should happen - results2.transferResults(results, ['layer_id2', 'layer_id3']) - self.assertEqual([(i.layerId(), i.itemId()) for i in results.renderedItems()], - [('layer_id', 'item_id_1')]) - self.assertCountEqual([(i.layerId(), i.itemId()) for i in results2.renderedAnnotationItemsInBounds(QgsRectangle(0, 0, 10, 10))], - [('layer_id2', 'item_id_2'), - ('layer_id3', 'item_id_3')]) + results2.transferResults(results, ["layer_id2", "layer_id3"]) + self.assertEqual( + [(i.layerId(), i.itemId()) for i in results.renderedItems()], + [("layer_id", "item_id_1")], + ) + self.assertCountEqual( + [ + (i.layerId(), i.itemId()) + for i in results2.renderedAnnotationItemsInBounds( + QgsRectangle(0, 0, 10, 10) + ) + ], + [("layer_id2", "item_id_2"), ("layer_id3", "item_id_3")], + ) # remaining layer - results2.transferResults(results, ['layer_id']) + results2.transferResults(results, ["layer_id"]) self.assertFalse([(i.layerId(), i.itemId()) for i in results.renderedItems()]) - self.assertCountEqual([(i.layerId(), i.itemId()) for i in results2.renderedAnnotationItemsInBounds(QgsRectangle(0, 0, 10, 10))], - [('layer_id', 'item_id_1'), - ('layer_id2', 'item_id_2'), - ('layer_id3', 'item_id_3')]) + self.assertCountEqual( + [ + (i.layerId(), i.itemId()) + for i in results2.renderedAnnotationItemsInBounds( + QgsRectangle(0, 0, 10, 10) + ) + ], + [ + ("layer_id", "item_id_1"), + ("layer_id2", "item_id_2"), + ("layer_id3", "item_id_3"), + ], + ) # transfer all results results3 = QgsRenderedItemResults() # nothing should happen -- no results in results3 to transfer results2.transferResults(results3) - self.assertFalse(results3.renderedAnnotationItemsInBounds(QgsRectangle(0, 0, 10, 10))) - self.assertCountEqual([(i.layerId(), i.itemId()) for i in results2.renderedAnnotationItemsInBounds(QgsRectangle(0, 0, 10, 10))], - [('layer_id', 'item_id_1'), - ('layer_id2', 'item_id_2'), - ('layer_id3', 'item_id_3')]) + self.assertFalse( + results3.renderedAnnotationItemsInBounds(QgsRectangle(0, 0, 10, 10)) + ) + self.assertCountEqual( + [ + (i.layerId(), i.itemId()) + for i in results2.renderedAnnotationItemsInBounds( + QgsRectangle(0, 0, 10, 10) + ) + ], + [ + ("layer_id", "item_id_1"), + ("layer_id2", "item_id_2"), + ("layer_id3", "item_id_3"), + ], + ) # transfer all results from results2 to results3 results3.transferResults(results2) self.assertFalse(results2.renderedItems()) - self.assertCountEqual([(i.layerId(), i.itemId()) for i in results3.renderedAnnotationItemsInBounds(QgsRectangle(0, 0, 10, 10))], - [('layer_id', 'item_id_1'), - ('layer_id2', 'item_id_2'), - ('layer_id3', 'item_id_3')]) + self.assertCountEqual( + [ + (i.layerId(), i.itemId()) + for i in results3.renderedAnnotationItemsInBounds( + QgsRectangle(0, 0, 10, 10) + ) + ], + [ + ("layer_id", "item_id_1"), + ("layer_id2", "item_id_2"), + ("layer_id3", "item_id_3"), + ], + ) def test_erase_results(self): results = QgsRenderedItemResults() rc = QgsRenderContext() - details1 = QgsRenderedAnnotationItemDetails('layer_id', 'item_id_1') + details1 = QgsRenderedAnnotationItemDetails("layer_id", "item_id_1") details1.setBoundingBox(QgsRectangle(1, 1, 10, 10)) - details2 = QgsRenderedAnnotationItemDetails('layer_id2', 'item_id_2') + details2 = QgsRenderedAnnotationItemDetails("layer_id2", "item_id_2") details2.setBoundingBox(QgsRectangle(1, 1, 5, 5)) - details3 = QgsRenderedAnnotationItemDetails('layer_id3', 'item_id_3') + details3 = QgsRenderedAnnotationItemDetails("layer_id3", "item_id_3") details3.setBoundingBox(QgsRectangle(4, 4, 7, 7)) results.appendResults([details1, details2, details3], rc) - self.assertCountEqual([(i.layerId(), i.itemId()) for i in results.renderedItems()], - [('layer_id', 'item_id_1'), - ('layer_id2', 'item_id_2'), - ('layer_id3', 'item_id_3')]) + self.assertCountEqual( + [(i.layerId(), i.itemId()) for i in results.renderedItems()], + [ + ("layer_id", "item_id_1"), + ("layer_id2", "item_id_2"), + ("layer_id3", "item_id_3"), + ], + ) results.eraseResultsFromLayers([]) - self.assertCountEqual([(i.layerId(), i.itemId()) for i in results.renderedItems()], - [('layer_id', 'item_id_1'), - ('layer_id2', 'item_id_2'), - ('layer_id3', 'item_id_3')]) - - results.eraseResultsFromLayers(['layer_id2', 'layer_id3']) - self.assertCountEqual([(i.layerId(), i.itemId()) for i in results.renderedItems()], - [('layer_id', 'item_id_1')]) - results.eraseResultsFromLayers(['layer_id2', 'layer_id']) + self.assertCountEqual( + [(i.layerId(), i.itemId()) for i in results.renderedItems()], + [ + ("layer_id", "item_id_1"), + ("layer_id2", "item_id_2"), + ("layer_id3", "item_id_3"), + ], + ) + + results.eraseResultsFromLayers(["layer_id2", "layer_id3"]) + self.assertCountEqual( + [(i.layerId(), i.itemId()) for i in results.renderedItems()], + [("layer_id", "item_id_1")], + ) + results.eraseResultsFromLayers(["layer_id2", "layer_id"]) self.assertFalse(results.renderedItems()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrenderer.py b/tests/src/python/test_qgsrenderer.py index c9cd40595ffd..fd3620efca9e 100644 --- a/tests/src/python/test_qgsrenderer.py +++ b/tests/src/python/test_qgsrenderer.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '07/06/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "07/06/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.core import ( @@ -25,8 +26,11 @@ def createReferencingLayer(): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=foreignkey:integer", - "referencinglayer", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=foreignkey:integer", + "referencinglayer", + "memory", + ) pr = layer.dataProvider() f1 = QgsFeature() f1.setFields(layer.fields()) @@ -56,7 +60,7 @@ def createRenderer(self, elem): def clearRegistry(): # clear registry to start with for r in QgsApplication.rendererRegistry().renderersList(): - if r == 'singleSymbol': + if r == "singleSymbol": continue QgsApplication.rendererRegistry().removeRenderer(r) @@ -64,114 +68,168 @@ def clearRegistry(): class TestQgsRendererV2Registry(QgisTestCase): def testInstance(self): - """ test retrieving global instance """ + """test retrieving global instance""" self.assertTrue(QgsApplication.rendererRegistry()) # instance should be initially populated with some default renderers - self.assertIn('singleSymbol', QgsApplication.rendererRegistry().renderersList()) + self.assertIn("singleSymbol", QgsApplication.rendererRegistry().renderersList()) # register a renderer to the singleton, to test that the same instance is always returned - self.assertNotIn('test', QgsApplication.rendererRegistry().renderersList()) - self.assertTrue(QgsApplication.rendererRegistry().addRenderer(TestRenderer('test'))) - self.assertIn('test', QgsApplication.rendererRegistry().renderersList()) + self.assertNotIn("test", QgsApplication.rendererRegistry().renderersList()) + self.assertTrue( + QgsApplication.rendererRegistry().addRenderer(TestRenderer("test")) + ) + self.assertIn("test", QgsApplication.rendererRegistry().renderersList()) def testAddRenderer(self): - """ test adding renderers to registry """ + """test adding renderers to registry""" clearRegistry() # add a renderer - self.assertTrue(QgsApplication.rendererRegistry().addRenderer(TestRenderer('test2'))) - self.assertIn('test2', QgsApplication.rendererRegistry().renderersList()) + self.assertTrue( + QgsApplication.rendererRegistry().addRenderer(TestRenderer("test2")) + ) + self.assertIn("test2", QgsApplication.rendererRegistry().renderersList()) # try adding it again - should be rejected due to duplicate name - self.assertFalse(QgsApplication.rendererRegistry().addRenderer(TestRenderer('test2'))) - self.assertIn('test2', QgsApplication.rendererRegistry().renderersList()) + self.assertFalse( + QgsApplication.rendererRegistry().addRenderer(TestRenderer("test2")) + ) + self.assertIn("test2", QgsApplication.rendererRegistry().renderersList()) def testRemoveRenderer(self): - """ test removing renderers from registry """ + """test removing renderers from registry""" clearRegistry() # try removing non-existent renderer - self.assertFalse(QgsApplication.rendererRegistry().removeRenderer('test3')) + self.assertFalse(QgsApplication.rendererRegistry().removeRenderer("test3")) # now add it - self.assertTrue(QgsApplication.rendererRegistry().addRenderer(TestRenderer('test3'))) - self.assertIn('test3', QgsApplication.rendererRegistry().renderersList()) + self.assertTrue( + QgsApplication.rendererRegistry().addRenderer(TestRenderer("test3")) + ) + self.assertIn("test3", QgsApplication.rendererRegistry().renderersList()) # try removing it again - should be OK this time - self.assertTrue(QgsApplication.rendererRegistry().removeRenderer('test3')) - self.assertNotIn('test3', QgsApplication.rendererRegistry().renderersList()) + self.assertTrue(QgsApplication.rendererRegistry().removeRenderer("test3")) + self.assertNotIn("test3", QgsApplication.rendererRegistry().renderersList()) # try removing it again - should be false since already removed - self.assertFalse(QgsApplication.rendererRegistry().removeRenderer('test3')) + self.assertFalse(QgsApplication.rendererRegistry().removeRenderer("test3")) def testRetrieveRenderer(self): - """ test retrieving renderer by name """ + """test retrieving renderer by name""" clearRegistry() # try non-existent renderer - self.assertFalse(QgsApplication.rendererRegistry().rendererMetadata('test4')) + self.assertFalse(QgsApplication.rendererRegistry().rendererMetadata("test4")) # now add it - r = TestRenderer('test4') + r = TestRenderer("test4") self.assertTrue(QgsApplication.rendererRegistry().addRenderer(r)) # try retrieving it - result = QgsApplication.rendererRegistry().rendererMetadata('test4') + result = QgsApplication.rendererRegistry().rendererMetadata("test4") self.assertTrue(result) - self.assertEqual(result.name(), 'test4') + self.assertEqual(result.name(), "test4") def testRenderersList(self): - """ test getting list of renderers from registry """ + """test getting list of renderers from registry""" clearRegistry() - self.assertEqual(QgsApplication.rendererRegistry().renderersList(), ['singleSymbol']) + self.assertEqual( + QgsApplication.rendererRegistry().renderersList(), ["singleSymbol"] + ) # add some renderers - r1 = TestRenderer('test1', QgsRendererAbstractMetadata.LayerType.PointLayer) + r1 = TestRenderer("test1", QgsRendererAbstractMetadata.LayerType.PointLayer) self.assertTrue(QgsApplication.rendererRegistry().addRenderer(r1)) - r2 = TestRenderer('test2', QgsRendererAbstractMetadata.LayerType.LineLayer) + r2 = TestRenderer("test2", QgsRendererAbstractMetadata.LayerType.LineLayer) self.assertTrue(QgsApplication.rendererRegistry().addRenderer(r2)) - r3 = TestRenderer('test3', QgsRendererAbstractMetadata.LayerType.PolygonLayer) + r3 = TestRenderer("test3", QgsRendererAbstractMetadata.LayerType.PolygonLayer) self.assertTrue(QgsApplication.rendererRegistry().addRenderer(r3)) - r4 = TestRenderer('test4', QgsRendererAbstractMetadata.LayerType.PointLayer | QgsRendererAbstractMetadata.LayerType.LineLayer) + r4 = TestRenderer( + "test4", + QgsRendererAbstractMetadata.LayerType.PointLayer + | QgsRendererAbstractMetadata.LayerType.LineLayer, + ) self.assertTrue(QgsApplication.rendererRegistry().addRenderer(r4)) - self.assertEqual(QgsApplication.rendererRegistry().renderersList(), ['singleSymbol', 'test1', 'test2', 'test3', 'test4']) + self.assertEqual( + QgsApplication.rendererRegistry().renderersList(), + ["singleSymbol", "test1", "test2", "test3", "test4"], + ) # test subsets - self.assertEqual(QgsApplication.rendererRegistry().renderersList(QgsRendererAbstractMetadata.LayerType.PointLayer), ['singleSymbol', 'test1', 'test4']) - self.assertEqual(QgsApplication.rendererRegistry().renderersList(QgsRendererAbstractMetadata.LayerType.LineLayer), ['singleSymbol', 'test2', 'test4']) - self.assertEqual(QgsApplication.rendererRegistry().renderersList(QgsRendererAbstractMetadata.LayerType.PolygonLayer), ['singleSymbol', 'test3']) - self.assertEqual(QgsApplication.rendererRegistry().renderersList(QgsRendererAbstractMetadata.LayerType.LineLayer | QgsRendererAbstractMetadata.LayerType.PolygonLayer), ['singleSymbol', 'test2', 'test3', 'test4']) + self.assertEqual( + QgsApplication.rendererRegistry().renderersList( + QgsRendererAbstractMetadata.LayerType.PointLayer + ), + ["singleSymbol", "test1", "test4"], + ) + self.assertEqual( + QgsApplication.rendererRegistry().renderersList( + QgsRendererAbstractMetadata.LayerType.LineLayer + ), + ["singleSymbol", "test2", "test4"], + ) + self.assertEqual( + QgsApplication.rendererRegistry().renderersList( + QgsRendererAbstractMetadata.LayerType.PolygonLayer + ), + ["singleSymbol", "test3"], + ) + self.assertEqual( + QgsApplication.rendererRegistry().renderersList( + QgsRendererAbstractMetadata.LayerType.LineLayer + | QgsRendererAbstractMetadata.LayerType.PolygonLayer + ), + ["singleSymbol", "test2", "test3", "test4"], + ) def testRenderersByLayerType(self): - """ test retrieving compatible renderers by layer type """ + """test retrieving compatible renderers by layer type""" clearRegistry() # add some renderers - r1 = TestRenderer('test1', QgsRendererAbstractMetadata.LayerType.PointLayer) + r1 = TestRenderer("test1", QgsRendererAbstractMetadata.LayerType.PointLayer) self.assertTrue(QgsApplication.rendererRegistry().addRenderer(r1)) - r2 = TestRenderer('test2', QgsRendererAbstractMetadata.LayerType.LineLayer) + r2 = TestRenderer("test2", QgsRendererAbstractMetadata.LayerType.LineLayer) self.assertTrue(QgsApplication.rendererRegistry().addRenderer(r2)) - r3 = TestRenderer('test3', QgsRendererAbstractMetadata.LayerType.PolygonLayer) + r3 = TestRenderer("test3", QgsRendererAbstractMetadata.LayerType.PolygonLayer) self.assertTrue(QgsApplication.rendererRegistry().addRenderer(r3)) - r4 = TestRenderer('test4', QgsRendererAbstractMetadata.LayerType.PointLayer | QgsRendererAbstractMetadata.LayerType.LineLayer) + r4 = TestRenderer( + "test4", + QgsRendererAbstractMetadata.LayerType.PointLayer + | QgsRendererAbstractMetadata.LayerType.LineLayer, + ) self.assertTrue(QgsApplication.rendererRegistry().addRenderer(r4)) # make some layers - point_layer = QgsVectorLayer("Point?field=fldtxt:string", - "pointlayer", "memory") - line_layer = QgsVectorLayer("LineString?field=fldtxt:string", - "linelayer", "memory") - polygon_layer = QgsVectorLayer("Polygon?field=fldtxt:string", - "polylayer", "memory") + point_layer = QgsVectorLayer( + "Point?field=fldtxt:string", "pointlayer", "memory" + ) + line_layer = QgsVectorLayer( + "LineString?field=fldtxt:string", "linelayer", "memory" + ) + polygon_layer = QgsVectorLayer( + "Polygon?field=fldtxt:string", "polylayer", "memory" + ) # test subsets - self.assertEqual(QgsApplication.rendererRegistry().renderersList(point_layer), ['singleSymbol', 'test1', 'test4']) - self.assertEqual(QgsApplication.rendererRegistry().renderersList(line_layer), ['singleSymbol', 'test2', 'test4']) - self.assertEqual(QgsApplication.rendererRegistry().renderersList(polygon_layer), ['singleSymbol', 'test3']) - - -if __name__ == '__main__': + self.assertEqual( + QgsApplication.rendererRegistry().renderersList(point_layer), + ["singleSymbol", "test1", "test4"], + ) + self.assertEqual( + QgsApplication.rendererRegistry().renderersList(line_layer), + ["singleSymbol", "test2", "test4"], + ) + self.assertEqual( + QgsApplication.rendererRegistry().renderersList(polygon_layer), + ["singleSymbol", "test3"], + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrendererrasterpropertieswidget.py b/tests/src/python/test_qgsrendererrasterpropertieswidget.py index c3ca0b0bc66b..cae3ebe68a84 100644 --- a/tests/src/python/test_qgsrendererrasterpropertieswidget.py +++ b/tests/src/python/test_qgsrendererrasterpropertieswidget.py @@ -22,9 +22,10 @@ def multibandRasterLayer(self) -> QgsRasterLayer: try: from utilities import unitTestDataPath - path = pathlib.Path(unitTestDataPath()) / 'landsat_4326.tif' + + path = pathlib.Path(unitTestDataPath()) / "landsat_4326.tif" except ModuleNotFoundError: - path = pathlib.Path(__file__).parent / 'landsat_4326.tif' + path = pathlib.Path(__file__).parent / "landsat_4326.tif" assert isinstance(path, pathlib.Path) and path.is_file() lyr = QgsRasterLayer(path.as_posix()) @@ -73,5 +74,5 @@ def test_syncToLayer_MultiBand(self): assert r.usesBands() == [3, 1, 2] -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsreport.py b/tests/src/python/test_qgsreport.py index 475547392677..c41aef035e37 100644 --- a/tests/src/python/test_qgsreport.py +++ b/tests/src/python/test_qgsreport.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '29/12/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "29/12/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtXml import QDomDocument from qgis.core import ( @@ -253,48 +254,52 @@ def testIteration(self): self.assertTrue(r.beginRender()) self.assertTrue(r.next()) self.assertEqual(r.layout(), report_header) - self.assertEqual(r.filePath('/tmp/myreport', 'png'), '/tmp/myreport_0001.png') + self.assertEqual(r.filePath("/tmp/myreport", "png"), "/tmp/myreport_0001.png") self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_header) - self.assertEqual(r.filePath('/tmp/myreport', 'png'), '/tmp/myreport_0002.png') + self.assertEqual(r.filePath("/tmp/myreport", "png"), "/tmp/myreport_0002.png") self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_body) - self.assertEqual(r.filePath('/tmp/myreport', '.png'), '/tmp/myreport_0003.png') + self.assertEqual(r.filePath("/tmp/myreport", ".png"), "/tmp/myreport_0003.png") self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_footer) - self.assertEqual(r.filePath('/tmp/myreport', 'jpg'), '/tmp/myreport_0004.jpg') + self.assertEqual(r.filePath("/tmp/myreport", "jpg"), "/tmp/myreport_0004.jpg") self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_header) - self.assertEqual(r.filePath('/tmp/myreport', 'png'), '/tmp/myreport_0005.png') + self.assertEqual(r.filePath("/tmp/myreport", "png"), "/tmp/myreport_0005.png") self.assertTrue(r.next()) self.assertEqual(r.layout(), child2a_header) - self.assertEqual(r.filePath('/tmp/myreport', 'png'), '/tmp/myreport_0006.png') + self.assertEqual(r.filePath("/tmp/myreport", "png"), "/tmp/myreport_0006.png") self.assertTrue(r.next()) self.assertEqual(r.layout(), child2a_footer) - self.assertEqual(r.filePath('/tmp/myreport', 'png'), '/tmp/myreport_0007.png') + self.assertEqual(r.filePath("/tmp/myreport", "png"), "/tmp/myreport_0007.png") self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_footer) - self.assertEqual(r.filePath('/tmp/myreport', 'png'), '/tmp/myreport_0008.png') + self.assertEqual(r.filePath("/tmp/myreport", "png"), "/tmp/myreport_0008.png") self.assertTrue(r.next()) self.assertEqual(r.layout(), report_footer) - self.assertEqual(r.filePath('/tmp/myreport', 'png'), '/tmp/myreport_0009.png') + self.assertEqual(r.filePath("/tmp/myreport", "png"), "/tmp/myreport_0009.png") self.assertFalse(r.next()) def testFieldGroup(self): # create a layer - ptLayer = QgsVectorLayer("Point?crs=epsg:4326&field=country:string(20)&field=state:string(20)&field=town:string(20)", "points", "memory") + ptLayer = QgsVectorLayer( + "Point?crs=epsg:4326&field=country:string(20)&field=state:string(20)&field=town:string(20)", + "points", + "memory", + ) attributes = [ - ['Australia', 'QLD', 'Brisbane'], - ['Australia', 'QLD', 'Emerald'], - ['NZ', 'state1', 'town1'], - ['Australia', 'VIC', 'Melbourne'], - ['NZ', 'state1', 'town2'], - ['Australia', 'QLD', 'Beerburrum'], - ['Australia', 'VIC', 'Geelong'], - ['NZ', 'state2', 'town2'], - ['PNG', 'state1', 'town1'], - ['Australia', 'NSW', 'Sydney'] + ["Australia", "QLD", "Brisbane"], + ["Australia", "QLD", "Emerald"], + ["NZ", "state1", "town1"], + ["Australia", "VIC", "Melbourne"], + ["NZ", "state1", "town2"], + ["Australia", "QLD", "Beerburrum"], + ["Australia", "VIC", "Geelong"], + ["NZ", "state2", "town2"], + ["PNG", "state1", "town1"], + ["Australia", "NSW", "Sydney"], ] pr = ptLayer.dataProvider() @@ -315,39 +320,66 @@ def testFieldGroup(self): child1.setLayer(ptLayer) child1.setBody(child1_body) child1.setBodyEnabled(True) - child1.setField('country') + child1.setField("country") r.appendChild(child1) self.assertTrue(r.beginRender()) self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Brisbane']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Brisbane"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Emerald']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Emerald"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC', 'Melbourne']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "VIC", "Melbourne"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Beerburrum']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Beerburrum"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC', 'Geelong']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "VIC", "Geelong"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'NSW', 'Sydney']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "NSW", "Sydney"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1", "town1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state2', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state2", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['PNG', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["PNG", "state1", "town1"], + ) self.assertFalse(r.next()) # another group @@ -359,39 +391,66 @@ def testFieldGroup(self): child2.setLayer(ptLayer) child2.setBody(child2_body) child2.setBodyEnabled(True) - child2.setField('state') + child2.setField("state") child1.appendChild(child2) self.assertTrue(r.beginRender()) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'NSW', 'Sydney']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "NSW", "Sydney"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Brisbane']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Brisbane"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Emerald']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Emerald"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Beerburrum']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Beerburrum"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC', 'Melbourne']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "VIC", "Melbourne"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC', 'Geelong']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "VIC", "Geelong"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1", "town1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state2', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state2", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['PNG', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["PNG", "state1", "town1"], + ) self.assertFalse(r.next()) # another group @@ -403,40 +462,67 @@ def testFieldGroup(self): child3.setLayer(ptLayer) child3.setBody(child3_body) child3.setBodyEnabled(True) - child3.setField('town') + child3.setField("town") child3.setSortAscending(False) child2.appendChild(child3) self.assertTrue(r.beginRender()) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'NSW', 'Sydney']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "NSW", "Sydney"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Emerald']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Emerald"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Brisbane']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Brisbane"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Beerburrum']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Beerburrum"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC', 'Melbourne']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "VIC", "Melbourne"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC', 'Geelong']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "VIC", "Geelong"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1", "town1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state2', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state2", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['PNG', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["PNG", "state1", "town1"], + ) self.assertFalse(r.next()) # add headers/footers @@ -450,70 +536,129 @@ def testFieldGroup(self): self.assertTrue(r.beginRender()) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'NSW', 'Sydney']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "NSW", "Sydney"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'NSW', 'Sydney']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "NSW", "Sydney"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'NSW', 'Sydney']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "NSW", "Sydney"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Emerald']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Emerald"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Emerald']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Emerald"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Brisbane']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Brisbane"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Beerburrum']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Beerburrum"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Beerburrum']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Beerburrum"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC', 'Melbourne']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "VIC", "Melbourne"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC', 'Melbourne']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "VIC", "Melbourne"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC', 'Geelong']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "VIC", "Geelong"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC', 'Geelong']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "VIC", "Geelong"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1", "town1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1", "town1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state2', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state2", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state2', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state2", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state2', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state2", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['PNG', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["PNG", "state1", "town1"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['PNG', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["PNG", "state1", "town1"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['PNG', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["PNG", "state1", "town1"], + ) self.assertFalse(r.next()) # header/footer for section2 @@ -527,88 +672,158 @@ def testFieldGroup(self): self.assertTrue(r.beginRender()) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_header) - self.assertEqual(r.layout().reportContext().feature().attributes()[:2], ['Australia', 'NSW']) + self.assertEqual( + r.layout().reportContext().feature().attributes()[:2], ["Australia", "NSW"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'NSW', 'Sydney']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "NSW", "Sydney"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'NSW', 'Sydney']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "NSW", "Sydney"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'NSW', 'Sydney']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "NSW", "Sydney"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Emerald']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Emerald"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Emerald']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Emerald"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Brisbane']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Brisbane"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Beerburrum']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Beerburrum"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Beerburrum']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Beerburrum"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC', 'Melbourne']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "VIC", "Melbourne"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC', 'Melbourne']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "VIC", "Melbourne"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC', 'Geelong']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "VIC", "Geelong"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes()[:2], ['Australia', 'VIC']) + self.assertEqual( + r.layout().reportContext().feature().attributes()[:2], ["Australia", "VIC"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_footer) - self.assertEqual(r.layout().reportContext().feature().attributes()[:2], ['Australia', 'VIC']) + self.assertEqual( + r.layout().reportContext().feature().attributes()[:2], ["Australia", "VIC"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_header) - self.assertEqual(r.layout().reportContext().feature().attributes()[:2], ['NZ', 'state1']) + self.assertEqual( + r.layout().reportContext().feature().attributes()[:2], ["NZ", "state1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1", "town1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1", "town1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state2', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state2", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state2', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state2", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state2', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state2", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_footer) - self.assertEqual(r.layout().reportContext().feature().attributes()[:2], ['NZ', 'state2']) + self.assertEqual( + r.layout().reportContext().feature().attributes()[:2], ["NZ", "state2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_header) - self.assertEqual(r.layout().reportContext().feature().attributes()[:2], ['PNG', 'state1']) + self.assertEqual( + r.layout().reportContext().feature().attributes()[:2], ["PNG", "state1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['PNG', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["PNG", "state1", "town1"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['PNG', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["PNG", "state1", "town1"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['PNG', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["PNG", "state1", "town1"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_footer) - self.assertEqual(r.layout().reportContext().feature().attributes()[:2], ['PNG', 'state1']) + self.assertEqual( + r.layout().reportContext().feature().attributes()[:2], ["PNG", "state1"] + ) self.assertFalse(r.next()) # child 1 and report header/footer @@ -630,100 +845,177 @@ def testFieldGroup(self): self.assertEqual(r.layout(), report_header) self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_header) - self.assertEqual(r.layout().reportContext().feature().attributes()[:1], ['Australia']) + self.assertEqual( + r.layout().reportContext().feature().attributes()[:1], ["Australia"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_header) - self.assertEqual(r.layout().reportContext().feature().attributes()[:2], ['Australia', 'NSW']) + self.assertEqual( + r.layout().reportContext().feature().attributes()[:2], ["Australia", "NSW"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'NSW', 'Sydney']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "NSW", "Sydney"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'NSW', 'Sydney']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "NSW", "Sydney"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'NSW', 'Sydney']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "NSW", "Sydney"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Emerald']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Emerald"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Emerald']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Emerald"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Brisbane']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Brisbane"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Beerburrum']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Beerburrum"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD', 'Beerburrum']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "QLD", "Beerburrum"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC', 'Melbourne']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "VIC", "Melbourne"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC', 'Melbourne']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "VIC", "Melbourne"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC', 'Geelong']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "VIC", "Geelong"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC', 'Geelong']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["Australia", "VIC", "Geelong"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_footer) - self.assertEqual(r.layout().reportContext().feature().attributes()[:2], ['Australia', 'VIC']) + self.assertEqual( + r.layout().reportContext().feature().attributes()[:2], ["Australia", "VIC"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_header) - self.assertEqual(r.layout().reportContext().feature().attributes()[:2], ['NZ', 'state1']) + self.assertEqual( + r.layout().reportContext().feature().attributes()[:2], ["NZ", "state1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1", "town1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1", "town1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state2', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state2", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state2', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state2", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state2', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state2", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_footer) - self.assertEqual(r.layout().reportContext().feature().attributes()[:2], ['NZ', 'state2']) + self.assertEqual( + r.layout().reportContext().feature().attributes()[:2], ["NZ", "state2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_header) - self.assertEqual(r.layout().reportContext().feature().attributes()[:2], ['PNG', 'state1']) + self.assertEqual( + r.layout().reportContext().feature().attributes()[:2], ["PNG", "state1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['PNG', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["PNG", "state1", "town1"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['PNG', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["PNG", "state1", "town1"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['PNG', 'state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), + ["PNG", "state1", "town1"], + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_footer) - self.assertEqual(r.layout().reportContext().feature().attributes()[:2], ['PNG', 'state1']) + self.assertEqual( + r.layout().reportContext().feature().attributes()[:2], ["PNG", "state1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_footer) - self.assertEqual(r.layout().reportContext().feature().attributes()[:1], ['PNG']) + self.assertEqual(r.layout().reportContext().feature().attributes()[:1], ["PNG"]) self.assertTrue(r.next()) self.assertEqual(r.layout(), report_footer) self.assertFalse(r.next()) def testFieldGroupSectionVisibility(self): - states = QgsVectorLayer("Point?crs=epsg:4326&field=country:string(20)&field=state:string(20)", "points", "memory") + states = QgsVectorLayer( + "Point?crs=epsg:4326&field=country:string(20)&field=state:string(20)", + "points", + "memory", + ) p = QgsProject() r = QgsReport(p) @@ -731,7 +1023,7 @@ def testFieldGroupSectionVisibility(self): # add a child child1 = QgsReportSectionFieldGroup() child1.setLayer(states) - child1.setField('country') + child1.setField("country") child1_header = QgsLayout(p) child1.setHeader(child1_header) child1.setHeaderEnabled(True) @@ -744,8 +1036,12 @@ def testFieldGroupSectionVisibility(self): self.assertTrue(r.beginRender()) self.assertFalse(r.next()) - child1.setHeaderVisibility(QgsReportSectionFieldGroup.SectionVisibility.AlwaysInclude) - child1.setFooterVisibility(QgsReportSectionFieldGroup.SectionVisibility.AlwaysInclude) + child1.setHeaderVisibility( + QgsReportSectionFieldGroup.SectionVisibility.AlwaysInclude + ) + child1.setFooterVisibility( + QgsReportSectionFieldGroup.SectionVisibility.AlwaysInclude + ) # check that the header is included when no features are found self.assertTrue(r.beginRender()) @@ -756,15 +1052,19 @@ def testFieldGroupSectionVisibility(self): def testFieldGroupMultiLayer(self): # create a layer - states = QgsVectorLayer("Point?crs=epsg:4326&field=country:string(20)&field=state:string(20)", "points", "memory") + states = QgsVectorLayer( + "Point?crs=epsg:4326&field=country:string(20)&field=state:string(20)", + "points", + "memory", + ) attributes = [ - ['Australia', 'QLD'], - ['NZ', 'state1'], - ['Australia', 'VIC'], - ['NZ', 'state2'], - ['PNG', 'state3'], - ['Australia', 'NSW'] + ["Australia", "QLD"], + ["NZ", "state1"], + ["Australia", "VIC"], + ["NZ", "state2"], + ["PNG", "state3"], + ["Australia", "NSW"], ] pr = states.dataProvider() @@ -775,17 +1075,21 @@ def testFieldGroupMultiLayer(self): f.setAttribute(1, a[1]) self.assertTrue(pr.addFeature(f)) - places = QgsVectorLayer("Point?crs=epsg:4326&field=state:string(20)&field=town:string(20)", "points", "memory") + places = QgsVectorLayer( + "Point?crs=epsg:4326&field=state:string(20)&field=town:string(20)", + "points", + "memory", + ) attributes = [ - ['QLD', 'Brisbane'], - ['QLD', 'Emerald'], - ['state1', 'town1'], - ['VIC', 'Melbourne'], - ['state1', 'town2'], - ['QLD', 'Beerburrum'], - ['VIC', 'Geelong'], - ['state3', 'town1'] + ["QLD", "Brisbane"], + ["QLD", "Emerald"], + ["state1", "town1"], + ["VIC", "Melbourne"], + ["state1", "town2"], + ["QLD", "Beerburrum"], + ["VIC", "Geelong"], + ["state3", "town1"], ] pr = places.dataProvider() @@ -805,27 +1109,39 @@ def testFieldGroupMultiLayer(self): child1.setLayer(states) child1.setBody(child1_body) child1.setBodyEnabled(True) - child1.setField('country') + child1.setField("country") r.appendChild(child1) self.assertTrue(r.beginRender()) self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["Australia", "QLD"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["Australia", "VIC"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'NSW']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["Australia", "NSW"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child1_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['PNG', 'state3']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["PNG", "state3"] + ) self.assertFalse(r.next()) # another group @@ -837,27 +1153,39 @@ def testFieldGroupMultiLayer(self): child2.setLayer(states) child2.setBody(child2_body) child2.setBodyEnabled(True) - child2.setField('state') + child2.setField("state") child1.appendChild(child2) self.assertTrue(r.beginRender()) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'NSW']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["Australia", "NSW"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["Australia", "QLD"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["Australia", "VIC"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['PNG', 'state3']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["PNG", "state3"] + ) self.assertFalse(r.next()) # another group @@ -867,52 +1195,80 @@ def testFieldGroupMultiLayer(self): child3.setLayer(places) child3.setBody(child3_body) child3.setBodyEnabled(True) - child3.setField('town') + child3.setField("town") child3.setSortAscending(False) child2.appendChild(child3) self.assertTrue(r.beginRender()) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'NSW']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["Australia", "NSW"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["Australia", "QLD"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['QLD', 'Emerald']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["QLD", "Emerald"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['QLD', 'Brisbane']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["QLD", "Brisbane"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['QLD', 'Beerburrum']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["QLD", "Beerburrum"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["Australia", "VIC"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['VIC', 'Melbourne']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["VIC", "Melbourne"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['VIC', 'Geelong']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["VIC", "Geelong"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['state1', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["state1", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["state1", "town1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['PNG', 'state3']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["PNG", "state3"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['state3', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["state3", "town1"] + ) self.assertFalse(r.next()) # add headers/footers @@ -926,79 +1282,127 @@ def testFieldGroupMultiLayer(self): self.assertTrue(r.beginRender()) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'NSW']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["Australia", "NSW"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'QLD']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["Australia", "QLD"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['QLD', 'Emerald']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["QLD", "Emerald"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['QLD', 'Emerald']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["QLD", "Emerald"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['QLD', 'Brisbane']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["QLD", "Brisbane"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['QLD', 'Beerburrum']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["QLD", "Beerburrum"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['QLD', 'Beerburrum']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["QLD", "Beerburrum"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['Australia', 'VIC']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["Australia", "VIC"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['VIC', 'Melbourne']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["VIC", "Melbourne"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['VIC', 'Melbourne']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["VIC", "Melbourne"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['VIC', 'Geelong']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["VIC", "Geelong"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['VIC', 'Geelong']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["VIC", "Geelong"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['state1', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["state1", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['state1', 'town2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["state1", "town2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["state1", "town1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['state1', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["state1", "town1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['NZ', 'state2']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["NZ", "state2"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child2_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['PNG', 'state3']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["PNG", "state3"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_header) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['state3', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["state3", "town1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_body) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['state3', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["state3", "town1"] + ) self.assertTrue(r.next()) self.assertEqual(r.layout(), child3_footer) - self.assertEqual(r.layout().reportContext().feature().attributes(), ['state3', 'town1']) + self.assertEqual( + r.layout().reportContext().feature().attributes(), ["state3", "town1"] + ) self.assertFalse(r.next()) def testReadWriteXml(self): p = QgsProject() - ptLayer = QgsVectorLayer("Point?crs=epsg:4326&field=country:string(20)&field=state:string(20)&field=town:string(20)", "points", "memory") + ptLayer = QgsVectorLayer( + "Point?crs=epsg:4326&field=country:string(20)&field=state:string(20)&field=town:string(20)", + "points", + "memory", + ) p.addMapLayer(ptLayer) r = QgsReport(p) - r.setName('my report') + r.setName("my report") # add a header r.setHeaderEnabled(True) report_header = QgsLayout(p) @@ -1026,7 +1430,7 @@ def testReadWriteXml(self): child2a_body = QgsLayout(p) child2a_body.setUnits(QgsUnitTypes.LayoutUnit.LayoutInches) child2a.setBody(child2a_body) - child2a.setField('my field') + child2a.setField("my field") child2a.setLayer(ptLayer) child1.appendChild(child2a) @@ -1037,20 +1441,28 @@ def testReadWriteXml(self): r2 = QgsReport(p) self.assertTrue(r2.readLayoutXml(elem, doc, QgsReadWriteContext())) - self.assertEqual(r2.name(), 'my report') + self.assertEqual(r2.name(), "my report") self.assertTrue(r2.headerEnabled()) self.assertEqual(r2.header().units(), QgsUnitTypes.LayoutUnit.LayoutInches) self.assertTrue(r2.footerEnabled()) self.assertEqual(r2.footer().units(), QgsUnitTypes.LayoutUnit.LayoutMeters) self.assertEqual(r2.childCount(), 1) - self.assertEqual(r2.childSection(0).body().units(), QgsUnitTypes.LayoutUnit.LayoutPoints) + self.assertEqual( + r2.childSection(0).body().units(), QgsUnitTypes.LayoutUnit.LayoutPoints + ) self.assertEqual(r2.childSection(0).childCount(), 2) - self.assertEqual(r2.childSection(0).childSection(0).body().units(), QgsUnitTypes.LayoutUnit.LayoutPixels) - self.assertEqual(r2.childSection(0).childSection(1).body().units(), QgsUnitTypes.LayoutUnit.LayoutInches) - self.assertEqual(r2.childSection(0).childSection(1).field(), 'my field') + self.assertEqual( + r2.childSection(0).childSection(0).body().units(), + QgsUnitTypes.LayoutUnit.LayoutPixels, + ) + self.assertEqual( + r2.childSection(0).childSection(1).body().units(), + QgsUnitTypes.LayoutUnit.LayoutInches, + ) + self.assertEqual(r2.childSection(0).childSection(1).field(), "my field") self.assertEqual(r2.childSection(0).childSection(1).layer(), ptLayer) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrubberband.py b/tests/src/python/test_qgsrubberband.py index a2a9ed6cb61f..863f19d3f4ed 100644 --- a/tests/src/python/test_qgsrubberband.py +++ b/tests/src/python/test_qgsrubberband.py @@ -6,7 +6,6 @@ (at your option) any later version. """ - from qgis.gui import QgsRubberBand import unittest from qgis.testing import start_app, QgisTestCase @@ -21,7 +20,7 @@ def setUp(self): self.iface = get_iface() def testBugfix48471(self): - """ Test scenario of https://github.com/qgis/QGIS/issues/48471 """ + """Test scenario of https://github.com/qgis/QGIS/issues/48471""" countBefore = 0 for item in self.iface.mapCanvas().scene().items(): @@ -41,5 +40,5 @@ def testBugfix48471(self): self.iface.mapCanvas().scene().removeItem(rubberband) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsrulebasedrenderer.py b/tests/src/python/test_qgsrulebasedrenderer.py index d1ad7a7fa27b..c6ccf1458bf9 100644 --- a/tests/src/python/test_qgsrulebasedrenderer.py +++ b/tests/src/python/test_qgsrulebasedrenderer.py @@ -8,11 +8,7 @@ from qgis.PyQt.QtCore import Qt from qgis.PyQt.QtXml import QDomDocument -from qgis.core import ( - QgsMarkerSymbol, - QgsFillSymbol, - QgsRuleBasedRenderer -) +from qgis.core import QgsMarkerSymbol, QgsFillSymbol, QgsRuleBasedRenderer import unittest from qgis.testing import start_app, QgisTestCase @@ -24,18 +20,14 @@ def createMarkerSymbol(): - symbol = QgsMarkerSymbol.createSimple({ - "color": "100,150,50", - "name": "square", - "size": "3.0" - }) + symbol = QgsMarkerSymbol.createSimple( + {"color": "100,150,50", "name": "square", "size": "3.0"} + ) return symbol def createFillSymbol(): - symbol = QgsFillSymbol.createSimple({ - "color": "100,150,50" - }) + symbol = QgsFillSymbol.createSimple({"color": "100,150,50"}) return symbol @@ -45,11 +37,21 @@ def test_to_sld(self): root_rule = QgsRuleBasedRenderer.Rule(None) symbol_a = createMarkerSymbol() root_rule.appendChild( - QgsRuleBasedRenderer.Rule(symbol_a, filterExp='"something"=1', label="label a", description="rule a") + QgsRuleBasedRenderer.Rule( + symbol_a, + filterExp='"something"=1', + label="label a", + description="rule a", + ) ) symbol_b = createMarkerSymbol() root_rule.appendChild( - QgsRuleBasedRenderer.Rule(symbol_b, filterExp='"something"=2', label="label b", description="rule b") + QgsRuleBasedRenderer.Rule( + symbol_b, + filterExp='"something"=2', + label="label b", + description="rule b", + ) ) # this rule should NOT be included in the SLD, as it would otherwise result @@ -58,7 +60,13 @@ def test_to_sld(self): symbol_which_is_empty_in_sld[0].setBrushStyle(Qt.BrushStyle.NoBrush) symbol_which_is_empty_in_sld[0].setStrokeStyle(Qt.PenStyle.NoPen) root_rule.appendChild( - QgsRuleBasedRenderer.Rule(symbol_which_is_empty_in_sld, filterExp='"something"=3', label="label c", description="rule c")) + QgsRuleBasedRenderer.Rule( + symbol_which_is_empty_in_sld, + filterExp='"something"=3', + label="label c", + description="rule c", + ) + ) renderer = QgsRuleBasedRenderer(root_rule) diff --git a/tests/src/python/test_qgsscalebarrendererregistry.py b/tests/src/python/test_qgsscalebarrendererregistry.py index 6af4094666cc..1d7c362bee79 100644 --- a/tests/src/python/test_qgsscalebarrendererregistry.py +++ b/tests/src/python/test_qgsscalebarrendererregistry.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '20/03/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "20/03/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.core import QgsScaleBarRenderer, QgsScaleBarRendererRegistry @@ -20,13 +21,13 @@ class TestRenderer(QgsScaleBarRenderer): def id(self): - return 'test' + return "test" def sortKey(self): return 45 def visibleName(self): - return 'TesT' + return "TesT" def clone(self): return TestRenderer() @@ -39,29 +40,31 @@ def testRegistry(self): self.assertTrue(registry.renderers()) for f in registry.renderers(): self.assertEqual(registry.renderer(f).id(), f) - self.assertEqual(registry.visibleName(f), registry.renderer(f).visibleName()) + self.assertEqual( + registry.visibleName(f), registry.renderer(f).visibleName() + ) self.assertEqual(registry.sortKey(f), registry.renderer(f).sortKey()) - self.assertIsNone(registry.renderer('bad')) - self.assertFalse(registry.visibleName('bad')) - self.assertFalse(registry.sortKey('bad')) + self.assertIsNone(registry.renderer("bad")) + self.assertFalse(registry.visibleName("bad")) + self.assertFalse(registry.sortKey("bad")) - self.assertIn('Double Box', registry.renderers()) + self.assertIn("Double Box", registry.renderers()) registry.addRenderer(TestRenderer()) - self.assertIn('test', registry.renderers()) - self.assertTrue(isinstance(registry.renderer('test'), TestRenderer)) - self.assertEqual(registry.visibleName('test'), 'TesT') - self.assertEqual(registry.sortKey('test'), 45) + self.assertIn("test", registry.renderers()) + self.assertTrue(isinstance(registry.renderer("test"), TestRenderer)) + self.assertEqual(registry.visibleName("test"), "TesT") + self.assertEqual(registry.sortKey("test"), 45) - registry.removeRenderer('test') + registry.removeRenderer("test") - self.assertNotIn('test', registry.renderers()) - self.assertIsNone(registry.renderer('test')) - self.assertFalse(registry.visibleName('test')) + self.assertNotIn("test", registry.renderers()) + self.assertIsNone(registry.renderer("test")) + self.assertFalse(registry.visibleName("test")) - registry.removeRenderer('test') + registry.removeRenderer("test") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsscalebarrenderers.py b/tests/src/python/test_qgsscalebarrenderers.py index c659acf4dd69..ecdf62a4e592 100644 --- a/tests/src/python/test_qgsscalebarrenderers.py +++ b/tests/src/python/test_qgsscalebarrenderers.py @@ -25,5 +25,5 @@ def test_context(self): self.assertFalse(context.isValid()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsscalecalculator.py b/tests/src/python/test_qgsscalecalculator.py index fb9293595fb2..f065867376d4 100644 --- a/tests/src/python/test_qgsscalecalculator.py +++ b/tests/src/python/test_qgsscalecalculator.py @@ -5,16 +5,13 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Mathieu Pellerin' -__date__ = '30/12/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' +__author__ = "Mathieu Pellerin" +__date__ = "30/12/2021" +__copyright__ = "Copyright 2021, The QGIS Project" -from qgis.core import ( - Qgis, - QgsRectangle, - QgsScaleCalculator -) + +from qgis.core import Qgis, QgsRectangle, QgsScaleCalculator import unittest from qgis.testing import start_app, QgisTestCase @@ -73,5 +70,5 @@ def testCalculateImageSize(self): self.assertAlmostEqual(image_size.height(), 339.983, 3) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsscalewidget.py b/tests/src/python/test_qgsscalewidget.py index e1462e6179ac..2503199909c1 100644 --- a/tests/src/python/test_qgsscalewidget.py +++ b/tests/src/python/test_qgsscalewidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '13/03/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "13/03/2019" +__copyright__ = "Copyright 2019, The QGIS Project" import math @@ -26,20 +27,20 @@ class TestQgsScaleWidget(QgisTestCase): def testBasic(self): w = QgsScaleWidget() spy = QSignalSpy(w.scaleChanged) - w.setScaleString('1:2345') - self.assertEqual(w.scaleString(), '1:2,345') + w.setScaleString("1:2345") + self.assertEqual(w.scaleString(), "1:2,345") self.assertEqual(w.scale(), 2345) self.assertEqual(len(spy), 1) self.assertEqual(spy[-1][0], 2345) - w.setScaleString('0.02') - self.assertEqual(w.scaleString(), '1:50') + w.setScaleString("0.02") + self.assertEqual(w.scaleString(), "1:50") self.assertEqual(w.scale(), 50) self.assertEqual(len(spy), 2) self.assertEqual(spy[-1][0], 50) - w.setScaleString('1:4,000') - self.assertEqual(w.scaleString(), '1:4,000') + w.setScaleString("1:4,000") + self.assertEqual(w.scaleString(), "1:4,000") self.assertEqual(w.scale(), 4000) self.assertEqual(len(spy), 3) self.assertEqual(spy[-1][0], 4000) @@ -48,27 +49,27 @@ def test_predefined_scales(self): w = QgsScaleWidget() combo = w.findChild(QComboBox) - w.updateScales(['1:500', '1:100']) + w.updateScales(["1:500", "1:100"]) self.assertEqual(combo.count(), 2) - self.assertEqual(combo.itemText(0), '1:500') - self.assertEqual(combo.itemText(1), '1:100') + self.assertEqual(combo.itemText(0), "1:500") + self.assertEqual(combo.itemText(1), "1:100") w.setScale(100) self.assertEqual(w.scale(), 100) - self.assertEqual(combo.currentText(), '1:100') + self.assertEqual(combo.currentText(), "1:100") w.setScale(500) self.assertEqual(w.scale(), 500) - self.assertEqual(combo.currentText(), '1:500') + self.assertEqual(combo.currentText(), "1:500") w.setPredefinedScales([10.0, 20.0, 30.0, 500.0]) self.assertEqual(combo.count(), 4) - self.assertEqual(combo.itemText(0), '1:10') - self.assertEqual(combo.itemText(1), '1:20') - self.assertEqual(combo.itemText(2), '1:30') - self.assertEqual(combo.itemText(3), '1:500') + self.assertEqual(combo.itemText(0), "1:10") + self.assertEqual(combo.itemText(1), "1:20") + self.assertEqual(combo.itemText(2), "1:30") + self.assertEqual(combo.itemText(3), "1:500") self.assertEqual(w.scale(), 500) - self.assertEqual(combo.currentText(), '1:500') + self.assertEqual(combo.currentText(), "1:500") def testNull(self): w = QgsScaleWidget() @@ -83,7 +84,7 @@ def testNull(self): w.setAllowNull(True) self.assertTrue(w.allowNull()) - w.setScaleString('') + w.setScaleString("") self.assertEqual(len(spy), 1) self.assertTrue(math.isnan(w.scale())) self.assertTrue(math.isnan(spy[-1][0])) @@ -92,19 +93,19 @@ def testNull(self): self.assertTrue(math.isnan(w.scale())) self.assertTrue(w.isNull()) - w.setScaleString('0.02') + w.setScaleString("0.02") self.assertEqual(w.scale(), 50.0) self.assertEqual(len(spy), 2) self.assertEqual(spy[-1][0], 50.0) self.assertFalse(w.isNull()) - w.setScaleString('') + w.setScaleString("") self.assertTrue(math.isnan(w.scale())) self.assertEqual(len(spy), 3) self.assertTrue(math.isnan(spy[-1][0])) self.assertTrue(w.isNull()) - w.setScaleString('0.02') + w.setScaleString("0.02") self.assertEqual(w.scale(), 50.0) self.assertEqual(len(spy), 4) self.assertEqual(spy[-1][0], 50.0) @@ -120,28 +121,28 @@ def testNull(self): def test_combo(self): w = QgsScaleComboBox() - w.updateScales(['1:500', '1:100']) + w.updateScales(["1:500", "1:100"]) self.assertEqual(w.count(), 2) - self.assertEqual(w.itemText(0), '1:500') - self.assertEqual(w.itemText(1), '1:100') + self.assertEqual(w.itemText(0), "1:500") + self.assertEqual(w.itemText(1), "1:100") w.setScale(100) self.assertEqual(w.scale(), 100) - self.assertEqual(w.currentText(), '1:100') + self.assertEqual(w.currentText(), "1:100") w.setScale(500) self.assertEqual(w.scale(), 500) - self.assertEqual(w.currentText(), '1:500') + self.assertEqual(w.currentText(), "1:500") w.setPredefinedScales([10.0, 20.0, 30.0, 500.0]) self.assertEqual(w.count(), 4) - self.assertEqual(w.itemText(0), '1:10') - self.assertEqual(w.itemText(1), '1:20') - self.assertEqual(w.itemText(2), '1:30') - self.assertEqual(w.itemText(3), '1:500') + self.assertEqual(w.itemText(0), "1:10") + self.assertEqual(w.itemText(1), "1:20") + self.assertEqual(w.itemText(2), "1:30") + self.assertEqual(w.itemText(3), "1:500") self.assertEqual(w.scale(), 500) - self.assertEqual(w.currentText(), '1:500') + self.assertEqual(w.currentText(), "1:500") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsscreenproperties.py b/tests/src/python/test_qgsscreenproperties.py index 9ef738ce1633..b8d9f750c9a2 100644 --- a/tests/src/python/test_qgsscreenproperties.py +++ b/tests/src/python/test_qgsscreenproperties.py @@ -5,15 +5,13 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '22/06/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "22/06/2023" +__copyright__ = "Copyright 2023, The QGIS Project" from qgis.PyQt.QtGui import QGuiApplication -from qgis.core import ( - QgsScreenProperties, - QgsRenderContext -) +from qgis.core import QgsScreenProperties, QgsRenderContext from qgis.testing import unittest, start_app qgis_app = start_app() @@ -58,14 +56,10 @@ def test_from_screen(self): if not screen: return - properties = QgsScreenProperties( - screen - ) + properties = QgsScreenProperties(screen) self.assertTrue(properties.isValid()) - self.assertEqual(properties.devicePixelRatio(), - screen.devicePixelRatio()) - self.assertEqual(properties.physicalDpi(), - screen.physicalDotsPerInch()) + self.assertEqual(properties.devicePixelRatio(), screen.devicePixelRatio()) + self.assertEqual(properties.physicalDpi(), screen.physicalDotsPerInch()) def test_update_render_context(self): context = QgsRenderContext() @@ -90,5 +84,5 @@ def test_update_render_context(self): self.assertAlmostEqual(context.scaleFactor(), 7.87401, 3) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssearchwidgettoolbutton.py b/tests/src/python/test_qgssearchwidgettoolbutton.py index 25128f8063bf..d8e80affd8c0 100644 --- a/tests/src/python/test_qgssearchwidgettoolbutton.py +++ b/tests/src/python/test_qgssearchwidgettoolbutton.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '18/05/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "18/05/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.gui import QgsSearchWidgetToolButton, QgsSearchWidgetWrapper @@ -24,9 +25,11 @@ def testAvailableFlags(self): Test setting available flags """ w = QgsSearchWidgetToolButton() - w.setAvailableFlags(QgsSearchWidgetWrapper.FilterFlag.EqualTo | - QgsSearchWidgetWrapper.FilterFlag.NotEqualTo | - QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive) + w.setAvailableFlags( + QgsSearchWidgetWrapper.FilterFlag.EqualTo + | QgsSearchWidgetWrapper.FilterFlag.NotEqualTo + | QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive + ) flags = w.availableFlags() self.assertTrue(flags & QgsSearchWidgetWrapper.FilterFlag.EqualTo) @@ -35,9 +38,14 @@ def testAvailableFlags(self): self.assertFalse(flags & QgsSearchWidgetWrapper.FilterFlag.Between) # setting available flags should update active flags - w.setActiveFlags(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo | QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive) - w.setAvailableFlags(QgsSearchWidgetWrapper.FilterFlag.EqualTo | - QgsSearchWidgetWrapper.FilterFlag.NotEqualTo) + w.setActiveFlags( + QgsSearchWidgetWrapper.FilterFlag.NotEqualTo + | QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive + ) + w.setAvailableFlags( + QgsSearchWidgetWrapper.FilterFlag.EqualTo + | QgsSearchWidgetWrapper.FilterFlag.NotEqualTo + ) flags = w.activeFlags() self.assertFalse(flags & QgsSearchWidgetWrapper.FilterFlag.EqualTo) self.assertTrue(flags & QgsSearchWidgetWrapper.FilterFlag.NotEqualTo) @@ -48,40 +56,55 @@ def testActiveFlags(self): Test setting/retrieving active flag logic """ w = QgsSearchWidgetToolButton() - w.setAvailableFlags(QgsSearchWidgetWrapper.FilterFlag.EqualTo | - QgsSearchWidgetWrapper.FilterFlag.NotEqualTo | - QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive) + w.setAvailableFlags( + QgsSearchWidgetWrapper.FilterFlag.EqualTo + | QgsSearchWidgetWrapper.FilterFlag.NotEqualTo + | QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive + ) w.setActiveFlags(QgsSearchWidgetWrapper.FilterFlag.EqualTo) flags = w.activeFlags() self.assertTrue(flags & QgsSearchWidgetWrapper.FilterFlag.EqualTo) self.assertFalse(flags & QgsSearchWidgetWrapper.FilterFlag.NotEqualTo) - w.setActiveFlags(QgsSearchWidgetWrapper.FilterFlag.EqualTo | QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive) + w.setActiveFlags( + QgsSearchWidgetWrapper.FilterFlag.EqualTo + | QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive + ) flags = w.activeFlags() self.assertTrue(flags & QgsSearchWidgetWrapper.FilterFlag.EqualTo) self.assertTrue(flags & QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive) # setting a non-available flag as active - w.setAvailableFlags(QgsSearchWidgetWrapper.FilterFlag.EqualTo | - QgsSearchWidgetWrapper.FilterFlag.NotEqualTo) - w.setActiveFlags(QgsSearchWidgetWrapper.FilterFlag.EqualTo | QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive) + w.setAvailableFlags( + QgsSearchWidgetWrapper.FilterFlag.EqualTo + | QgsSearchWidgetWrapper.FilterFlag.NotEqualTo + ) + w.setActiveFlags( + QgsSearchWidgetWrapper.FilterFlag.EqualTo + | QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive + ) flags = w.activeFlags() self.assertTrue(flags & QgsSearchWidgetWrapper.FilterFlag.EqualTo) self.assertFalse(flags & QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive) # setting conflicting flags - w.setActiveFlags(QgsSearchWidgetWrapper.FilterFlag.EqualTo | QgsSearchWidgetWrapper.FilterFlag.NotEqualTo) + w.setActiveFlags( + QgsSearchWidgetWrapper.FilterFlag.EqualTo + | QgsSearchWidgetWrapper.FilterFlag.NotEqualTo + ) flags = w.activeFlags() self.assertTrue(flags & QgsSearchWidgetWrapper.FilterFlag.EqualTo) self.assertFalse(flags & QgsSearchWidgetWrapper.FilterFlag.NotEqualTo) def testToggleFlag(self): - """ Test toggling flags """ + """Test toggling flags""" w = QgsSearchWidgetToolButton() - w.setAvailableFlags(QgsSearchWidgetWrapper.FilterFlag.EqualTo | - QgsSearchWidgetWrapper.FilterFlag.NotEqualTo | - QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive) + w.setAvailableFlags( + QgsSearchWidgetWrapper.FilterFlag.EqualTo + | QgsSearchWidgetWrapper.FilterFlag.NotEqualTo + | QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive + ) w.setActiveFlags(QgsSearchWidgetWrapper.FilterFlag.EqualTo) # should set flag w.toggleFlag(QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive) @@ -97,8 +120,10 @@ def testToggleFlag(self): self.assertFalse(flags & QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive) # toggling non-available flag should be ignored - w.setAvailableFlags(QgsSearchWidgetWrapper.FilterFlag.Between | - QgsSearchWidgetWrapper.FilterFlag.NotEqualTo) + w.setAvailableFlags( + QgsSearchWidgetWrapper.FilterFlag.Between + | QgsSearchWidgetWrapper.FilterFlag.NotEqualTo + ) w.setActiveFlags(QgsSearchWidgetWrapper.FilterFlag.Between) # should be ignored w.toggleFlag(QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive) @@ -109,10 +134,15 @@ def testToggleFlag(self): self.assertTrue(flags & QgsSearchWidgetWrapper.FilterFlag.Between) # toggling exclusive flag should result in other exclusive flags being cleared - w.setAvailableFlags(QgsSearchWidgetWrapper.FilterFlag.Between | - QgsSearchWidgetWrapper.FilterFlag.NotEqualTo | - QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive) - w.setActiveFlags(QgsSearchWidgetWrapper.FilterFlag.Between | QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive) + w.setAvailableFlags( + QgsSearchWidgetWrapper.FilterFlag.Between + | QgsSearchWidgetWrapper.FilterFlag.NotEqualTo + | QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive + ) + w.setActiveFlags( + QgsSearchWidgetWrapper.FilterFlag.Between + | QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive + ) w.toggleFlag(QgsSearchWidgetWrapper.FilterFlag.Between) flags = w.activeFlags() self.assertTrue(flags & QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive) @@ -125,13 +155,17 @@ def testToggleFlag(self): self.assertFalse(flags & QgsSearchWidgetWrapper.FilterFlag.Between) def testSetInactive(self): - """ Test setting the search as inactive """ + """Test setting the search as inactive""" w = QgsSearchWidgetToolButton() - w.setAvailableFlags(QgsSearchWidgetWrapper.FilterFlag.EqualTo | - QgsSearchWidgetWrapper.FilterFlag.NotEqualTo | - QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive) - w.setActiveFlags(QgsSearchWidgetWrapper.FilterFlag.EqualTo | - QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive) + w.setAvailableFlags( + QgsSearchWidgetWrapper.FilterFlag.EqualTo + | QgsSearchWidgetWrapper.FilterFlag.NotEqualTo + | QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive + ) + w.setActiveFlags( + QgsSearchWidgetWrapper.FilterFlag.EqualTo + | QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive + ) self.assertTrue(w.isActive()) w.setInactive() flags = w.activeFlags() @@ -140,11 +174,13 @@ def testSetInactive(self): self.assertFalse(w.isActive()) def testSetActive(self): - """ Test setting the search as active should adopt default flags""" + """Test setting the search as active should adopt default flags""" w = QgsSearchWidgetToolButton() - w.setAvailableFlags(QgsSearchWidgetWrapper.FilterFlag.Between | - QgsSearchWidgetWrapper.FilterFlag.NotEqualTo | - QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive) + w.setAvailableFlags( + QgsSearchWidgetWrapper.FilterFlag.Between + | QgsSearchWidgetWrapper.FilterFlag.NotEqualTo + | QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive + ) w.setActiveFlags(QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive) w.setDefaultFlags(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo) self.assertFalse(w.isActive()) @@ -155,5 +191,5 @@ def testSetActive(self): self.assertTrue(w.isActive()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssearchwidgetwrapper.py b/tests/src/python/test_qgssearchwidgetwrapper.py index b5c55c8040b3..4cc9f00bcb7a 100644 --- a/tests/src/python/test_qgssearchwidgetwrapper.py +++ b/tests/src/python/test_qgssearchwidgetwrapper.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2016-05' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2016-05" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, QTime from qgis.PyQt.QtWidgets import QWidget @@ -31,20 +32,21 @@ class PyQgsSearchWidgetWrapper(QgisTestCase): def testFlagToString(self): # test converting QgsSearchWidgetWrapper.FilterFlag to string - tests = [QgsSearchWidgetWrapper.FilterFlag.EqualTo, - QgsSearchWidgetWrapper.FilterFlag.NotEqualTo, - QgsSearchWidgetWrapper.FilterFlag.GreaterThan, - QgsSearchWidgetWrapper.FilterFlag.LessThan, - QgsSearchWidgetWrapper.FilterFlag.GreaterThanOrEqualTo, - QgsSearchWidgetWrapper.FilterFlag.LessThanOrEqualTo, - QgsSearchWidgetWrapper.FilterFlag.Between, - QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive, - QgsSearchWidgetWrapper.FilterFlag.Contains, - QgsSearchWidgetWrapper.FilterFlag.DoesNotContain, - QgsSearchWidgetWrapper.FilterFlag.IsNull, - QgsSearchWidgetWrapper.FilterFlag.IsNotNull, - QgsSearchWidgetWrapper.FilterFlag.IsNotBetween - ] + tests = [ + QgsSearchWidgetWrapper.FilterFlag.EqualTo, + QgsSearchWidgetWrapper.FilterFlag.NotEqualTo, + QgsSearchWidgetWrapper.FilterFlag.GreaterThan, + QgsSearchWidgetWrapper.FilterFlag.LessThan, + QgsSearchWidgetWrapper.FilterFlag.GreaterThanOrEqualTo, + QgsSearchWidgetWrapper.FilterFlag.LessThanOrEqualTo, + QgsSearchWidgetWrapper.FilterFlag.Between, + QgsSearchWidgetWrapper.FilterFlag.CaseInsensitive, + QgsSearchWidgetWrapper.FilterFlag.Contains, + QgsSearchWidgetWrapper.FilterFlag.DoesNotContain, + QgsSearchWidgetWrapper.FilterFlag.IsNull, + QgsSearchWidgetWrapper.FilterFlag.IsNotNull, + QgsSearchWidgetWrapper.FilterFlag.IsNotBetween, + ] for t in tests: self.assertGreater(len(QgsSearchWidgetWrapper.toString(t)), 0) @@ -59,36 +61,81 @@ def testExclusiveFlags(self): class PyQgsDefaultSearchWidgetWrapper(QgisTestCase): def testCreateExpression(self): - """ Test creating an expression using the widget""" - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=flddate:datetime", - "test", "memory") + """Test creating an expression using the widget""" + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer&field=flddate:datetime", + "test", + "memory", + ) parent = QWidget() w = QgsDefaultSearchWidgetWrapper(layer, 0) w.initWidget(parent) line_edit = w.lineEdit() - line_edit.setText('test') + line_edit.setText("test") case_sensitive = w.caseSensitiveCheckBox() case_sensitive.setChecked(False) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"fldtxt" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"fldtxt" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), 'lower("fldtxt")=lower(\'test\')') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), 'lower("fldtxt")<>lower(\'test\')') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"fldtxt" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"fldtxt" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), + "lower(\"fldtxt\")=lower('test')", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), + "lower(\"fldtxt\")<>lower('test')", + ) case_sensitive.setChecked(True) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldtxt"=\'test\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '"fldtxt"<>\'test\'') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), + "\"fldtxt\"='test'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), + "\"fldtxt\"<>'test'", + ) case_sensitive.setChecked(False) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.Contains), '"fldtxt" ILIKE \'%test%\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.DoesNotContain), 'NOT ("fldtxt" ILIKE \'%test%\')') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.StartsWith), '"fldtxt" ILIKE \'test%\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EndsWith), '"fldtxt" ILIKE \'%test\'') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.Contains), + "\"fldtxt\" ILIKE '%test%'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.DoesNotContain), + "NOT (\"fldtxt\" ILIKE '%test%')", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.StartsWith), + "\"fldtxt\" ILIKE 'test%'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EndsWith), + "\"fldtxt\" ILIKE '%test'", + ) case_sensitive.setChecked(True) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.Contains), '"fldtxt" LIKE \'%test%\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.DoesNotContain), 'NOT ("fldtxt" LIKE \'%test%\')') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.StartsWith), '"fldtxt" LIKE \'test%\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EndsWith), '"fldtxt" LIKE \'%test\'') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.Contains), + "\"fldtxt\" LIKE '%test%'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.DoesNotContain), + "NOT (\"fldtxt\" LIKE '%test%')", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.StartsWith), + "\"fldtxt\" LIKE 'test%'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EndsWith), + "\"fldtxt\" LIKE '%test'", + ) case_sensitive.setChecked(False) # numeric field @@ -98,13 +145,31 @@ def testCreateExpression(self): # may need updating if widget layout changes: line_edit = w.lineEdit() - line_edit.setText('5.5') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldint"=5.5') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '"fldint"<>5.5') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThan), '"fldint">5.5') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThan), '"fldint"<5.5') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThanOrEqualTo), '"fldint">=5.5') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThanOrEqualTo), '"fldint"<=5.5') + line_edit.setText("5.5") + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), + '"fldint"=5.5', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), + '"fldint"<>5.5', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThan), + '"fldint">5.5', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThan), + '"fldint"<5.5', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThanOrEqualTo), + '"fldint">=5.5', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThanOrEqualTo), + '"fldint"<=5.5', + ) # date/time/datetime parent = QWidget() @@ -113,76 +178,144 @@ def testCreateExpression(self): # may need updating if widget layout changes: line_edit = w.lineEdit() - line_edit.setText('2015-06-03') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"flddate"=\'2015-06-03\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '"flddate"<>\'2015-06-03\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThan), '"flddate">\'2015-06-03\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThan), '"flddate"<\'2015-06-03\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThanOrEqualTo), '"flddate">=\'2015-06-03\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThanOrEqualTo), '"flddate"<=\'2015-06-03\'') + line_edit.setText("2015-06-03") + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), + "\"flddate\"='2015-06-03'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), + "\"flddate\"<>'2015-06-03'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThan), + "\"flddate\">'2015-06-03'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThan), + "\"flddate\"<'2015-06-03'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThanOrEqualTo), + "\"flddate\">='2015-06-03'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThanOrEqualTo), + "\"flddate\"<='2015-06-03'", + ) class PyQgsValueMapSearchWidgetWrapper(QgisTestCase): def testCreateExpression(self): - """ Test creating an expression using the widget""" - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", "test", "memory") + """Test creating an expression using the widget""" + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "test", "memory" + ) w = QgsValueMapSearchWidgetWrapper(layer, 0) - config = {"map": [{"val1": 1}, - {"val2": 200}]} + config = {"map": [{"val1": 1}, {"val2": 200}]} w.setConfig(config) c = w.widget() # first, set it to the "select value" item c.setCurrentIndex(0) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"fldtxt" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"fldtxt" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"fldtxt" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"fldtxt" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), "" + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), "" + ) c.setCurrentIndex(1) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"fldtxt" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"fldtxt" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldtxt"=\'1\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '"fldtxt"<>\'1\'') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"fldtxt" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"fldtxt" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), + "\"fldtxt\"='1'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), + "\"fldtxt\"<>'1'", + ) c.setCurrentIndex(2) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"fldtxt" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"fldtxt" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldtxt"=\'200\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '"fldtxt"<>\'200\'') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"fldtxt" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"fldtxt" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), + "\"fldtxt\"='200'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), + "\"fldtxt\"<>'200'", + ) # try with numeric field w = QgsValueMapSearchWidgetWrapper(layer, 1) w.setConfig(config) c = w.widget() c.setCurrentIndex(1) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"fldint" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"fldint" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldint"=1') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '"fldint"<>1') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"fldint" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"fldint" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldint"=1' + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), + '"fldint"<>1', + ) class PyQgsValueRelationSearchWidgetWrapper(QgisTestCase): def testCreateExpression(self): - """ Test creating an expression using the widget""" - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", "test", "memory") + """Test creating an expression using the widget""" + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "test", "memory" + ) # setup value relation - parent_layer = QgsVectorLayer("Point?field=stringkey:string&field=intkey:integer&field=display:string", "parent", "memory") + parent_layer = QgsVectorLayer( + "Point?field=stringkey:string&field=intkey:integer&field=display:string", + "parent", + "memory", + ) f1 = QgsFeature(parent_layer.fields(), 1) - f1.setAttributes(['a', 1, 'value a']) + f1.setAttributes(["a", 1, "value a"]) f2 = QgsFeature(parent_layer.fields(), 2) - f2.setAttributes(['b', 2, 'value b']) + f2.setAttributes(["b", 2, "value b"]) f3 = QgsFeature(parent_layer.fields(), 3) - f3.setAttributes(['c', 3, 'value c']) + f3.setAttributes(["c", 3, "value c"]) parent_layer.dataProvider().addFeatures([f1, f2, f3]) QgsProject.instance().addMapLayers([layer, parent_layer]) - config = {"Layer": parent_layer.id(), - "Key": 'stringkey', - "Value": 'display'} + config = {"Layer": parent_layer.id(), "Key": "stringkey", "Value": "display"} w = QgsValueRelationSearchWidgetWrapper(layer, 0) w.setConfig(config) @@ -191,91 +324,195 @@ def testCreateExpression(self): # first, set it to the "select value" item c.setCurrentIndex(0) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"fldtxt" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"fldtxt" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"fldtxt" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"fldtxt" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), "" + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), "" + ) c.setCurrentIndex(1) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"fldtxt" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"fldtxt" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldtxt"=\'a\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '"fldtxt"<>\'a\'') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"fldtxt" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"fldtxt" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), + "\"fldtxt\"='a'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), + "\"fldtxt\"<>'a'", + ) c.setCurrentIndex(2) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"fldtxt" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"fldtxt" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldtxt"=\'b\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '"fldtxt"<>\'b\'') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"fldtxt" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"fldtxt" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), + "\"fldtxt\"='b'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), + "\"fldtxt\"<>'b'", + ) # try with numeric field w = QgsValueRelationSearchWidgetWrapper(layer, 1) - config['Key'] = 'intkey' + config["Key"] = "intkey" w.setConfig(config) c = w.widget() - c.setCurrentIndex(c.findText('value c')) + c.setCurrentIndex(c.findText("value c")) self.assertEqual(c.currentIndex(), 3) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"fldint" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"fldint" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldint"=3') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '"fldint"<>3') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"fldint" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"fldint" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldint"=3' + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), + '"fldint"<>3', + ) # try with allow null set w = QgsValueRelationSearchWidgetWrapper(layer, 1) - config['AllowNull'] = True + config["AllowNull"] = True w.setConfig(config) c = w.widget() - c.setCurrentIndex(c.findText('value c')) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"fldint" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"fldint" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldint"=3') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '"fldint"<>3') + c.setCurrentIndex(c.findText("value c")) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"fldint" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"fldint" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldint"=3' + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), + '"fldint"<>3', + ) # try with line edit w = QgsValueRelationSearchWidgetWrapper(layer, 1) - config['UseCompleter'] = True + config["UseCompleter"] = True w.setConfig(config) l = w.widget() - l.setText('value b') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"fldint" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"fldint" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldint"=2') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '"fldint"<>2') + l.setText("value b") + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"fldint" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"fldint" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldint"=2' + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), + '"fldint"<>2', + ) class PyQgsCheckboxSearchWidgetWrapper(QgisTestCase): def testCreateExpression(self): - """ Test creating an expression using the widget""" - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=fieldbool:bool", "test", "memory") + """Test creating an expression using the widget""" + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer&field=fieldbool:bool", + "test", + "memory", + ) w = QgsCheckboxSearchWidgetWrapper(layer, 0) - config = {"CheckedState": 5, - "UncheckedState": 9} + config = {"CheckedState": 5, "UncheckedState": 9} w.setConfig(config) c = w.widget() # first check with string field type c.setChecked(True) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"fldtxt" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"fldtxt" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldtxt"=\'5\'') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"fldtxt" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"fldtxt" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), + "\"fldtxt\"='5'", + ) c.setChecked(False) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"fldtxt" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"fldtxt" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldtxt"=\'9\'') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"fldtxt" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"fldtxt" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), + "\"fldtxt\"='9'", + ) # try with numeric field w = QgsCheckboxSearchWidgetWrapper(layer, 1) w.setConfig(config) c = w.widget() c.setChecked(True) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"fldint" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"fldint" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldint"=5') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"fldint" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"fldint" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldint"=5' + ) c.setChecked(False) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"fldint" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"fldint" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldint"=9') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"fldint" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"fldint" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldint"=9' + ) # Check boolean expression parent = QWidget() @@ -283,125 +520,261 @@ def testCreateExpression(self): w.initWidget(parent) c = w.widget() c.setChecked(True) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fieldbool"=true') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), + '"fieldbool"=true', + ) c.setChecked(False) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fieldbool"=false') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), + '"fieldbool"=false', + ) class PyQgsDateTimeSearchWidgetWrapper(QgisTestCase): def testCreateExpression(self): - """ Test creating an expression using the widget""" - layer = QgsVectorLayer("Point?field=date:date&field=time:time&field=datetime:datetime", "test", "memory") + """Test creating an expression using the widget""" + layer = QgsVectorLayer( + "Point?field=date:date&field=time:time&field=datetime:datetime", + "test", + "memory", + ) w = QgsDateTimeSearchWidgetWrapper(layer, 0) - config = {"field_format": 'yyyy-MM-dd', - "display_format": 'yyyy-MM-dd'} + config = {"field_format": "yyyy-MM-dd", "display_format": "yyyy-MM-dd"} w.setConfig(config) c = w.widget() # first check with date field type c.setDateTime(QDateTime(QDate(2013, 4, 5), QTime())) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"date" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"date" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"date"=\'2013-04-05\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '"date"<>\'2013-04-05\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThan), '"date">\'2013-04-05\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThan), '"date"<\'2013-04-05\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThanOrEqualTo), '"date">=\'2013-04-05\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThanOrEqualTo), '"date"<=\'2013-04-05\'') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"date" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"date" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), + "\"date\"='2013-04-05'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), + "\"date\"<>'2013-04-05'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThan), + "\"date\">'2013-04-05'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThan), + "\"date\"<'2013-04-05'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThanOrEqualTo), + "\"date\">='2013-04-05'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThanOrEqualTo), + "\"date\"<='2013-04-05'", + ) # time field type w = QgsDateTimeSearchWidgetWrapper(layer, 1) - config = {"field_format": 'HH:mm:ss', - "display_format": 'HH:mm:ss'} + config = {"field_format": "HH:mm:ss", "display_format": "HH:mm:ss"} w.setConfig(config) c = w.widget() c.setDateTime(QDateTime(QDate(2013, 4, 5), QTime(13, 14, 15))) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"time" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"time" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"time"=\'13:14:15\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '"time"<>\'13:14:15\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThan), '"time">\'13:14:15\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThan), '"time"<\'13:14:15\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThanOrEqualTo), '"time">=\'13:14:15\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThanOrEqualTo), '"time"<=\'13:14:15\'') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"time" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"time" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), + "\"time\"='13:14:15'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), + "\"time\"<>'13:14:15'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThan), + "\"time\">'13:14:15'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThan), + "\"time\"<'13:14:15'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThanOrEqualTo), + "\"time\">='13:14:15'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThanOrEqualTo), + "\"time\"<='13:14:15'", + ) # datetime field type w = QgsDateTimeSearchWidgetWrapper(layer, 2) - config = {"field_format": 'yyyy-MM-dd HH:mm:ss', - "display_format": 'yyyy-MM-dd HH:mm:ss'} + config = { + "field_format": "yyyy-MM-dd HH:mm:ss", + "display_format": "yyyy-MM-dd HH:mm:ss", + } w.setConfig(config) c = w.widget() c.setDateTime(QDateTime(QDate(2013, 4, 5), QTime(13, 14, 15))) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"datetime" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"datetime" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"datetime"=\'2013-04-05 13:14:15\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '"datetime"<>\'2013-04-05 13:14:15\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThan), '"datetime">\'2013-04-05 13:14:15\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThan), '"datetime"<\'2013-04-05 13:14:15\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThanOrEqualTo), '"datetime">=\'2013-04-05 13:14:15\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThanOrEqualTo), '"datetime"<=\'2013-04-05 13:14:15\'') + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"datetime" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"datetime" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), + "\"datetime\"='2013-04-05 13:14:15'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), + "\"datetime\"<>'2013-04-05 13:14:15'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThan), + "\"datetime\">'2013-04-05 13:14:15'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThan), + "\"datetime\"<'2013-04-05 13:14:15'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.GreaterThanOrEqualTo), + "\"datetime\">='2013-04-05 13:14:15'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.LessThanOrEqualTo), + "\"datetime\"<='2013-04-05 13:14:15'", + ) class PyQgsRelationReferenceSearchWidgetWrapper(QgisTestCase): def testCreateExpression(self): - """ Test creating an expression using the widget""" - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", "test", "memory") + """Test creating an expression using the widget""" + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "test", "memory" + ) # setup value relation - parent_layer = QgsVectorLayer("Point?field=stringkey:string&field=intkey:integer&field=display:string", "parent", "memory") + parent_layer = QgsVectorLayer( + "Point?field=stringkey:string&field=intkey:integer&field=display:string", + "parent", + "memory", + ) f1 = QgsFeature(parent_layer.fields(), 1) - f1.setAttributes(['a', 1, 'value a']) + f1.setAttributes(["a", 1, "value a"]) f2 = QgsFeature(parent_layer.fields(), 2) - f2.setAttributes(['b', 2, 'value b']) + f2.setAttributes(["b", 2, "value b"]) f3 = QgsFeature(parent_layer.fields(), 3) - f3.setAttributes(['c', 3, 'value c']) + f3.setAttributes(["c", 3, "value c"]) parent_layer.dataProvider().addFeatures([f1, f2, f3]) QgsProject.instance().addMapLayers([layer, parent_layer]) relationManager = QgsProject.instance().relationManager() relation = QgsRelation() - relation.setId('relation') + relation.setId("relation") relation.setReferencingLayer(layer.id()) relation.setReferencedLayer(parent_layer.id()) - relation.addFieldPair('fldtxt', 'stringkey') + relation.addFieldPair("fldtxt", "stringkey") self.assertTrue(relation.isValid()) relationManager.addRelation(relation) # Everything valid - config = {'Relation': relation.id(), 'AllowNULL': True} + config = {"Relation": relation.id(), "AllowNULL": True} w = QgsRelationReferenceSearchWidgetWrapper(layer, 0, None) w.setConfig(config) - w.widget().setForeignKey('a') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"fldtxt" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"fldtxt" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldtxt"=\'a\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '"fldtxt"<>\'a\'') - - w.widget().setForeignKey('b') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"fldtxt" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"fldtxt" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldtxt"=\'b\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '"fldtxt"<>\'b\'') - - w.widget().setForeignKey('c') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"fldtxt" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"fldtxt" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldtxt"=\'c\'') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '"fldtxt"<>\'c\'') + w.widget().setForeignKey("a") + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"fldtxt" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"fldtxt" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), + "\"fldtxt\"='a'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), + "\"fldtxt\"<>'a'", + ) + + w.widget().setForeignKey("b") + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"fldtxt" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"fldtxt" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), + "\"fldtxt\"='b'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), + "\"fldtxt\"<>'b'", + ) + + w.widget().setForeignKey("c") + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"fldtxt" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"fldtxt" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), + "\"fldtxt\"='c'", + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), + "\"fldtxt\"<>'c'", + ) w.widget().setForeignKey(None) - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), '"fldtxt" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), '"fldtxt" IS NOT NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), '"fldtxt" IS NULL') - self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), '"fldtxt" IS NOT NULL') - - -if __name__ == '__main__': + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNull), + '"fldtxt" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.IsNotNull), + '"fldtxt" IS NOT NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.EqualTo), + '"fldtxt" IS NULL', + ) + self.assertEqual( + w.createExpression(QgsSearchWidgetWrapper.FilterFlag.NotEqualTo), + '"fldtxt" IS NOT NULL', + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsselectioncontext.py b/tests/src/python/test_qgsselectioncontext.py index 061fdb0346e4..372c89fbe0ca 100644 --- a/tests/src/python/test_qgsselectioncontext.py +++ b/tests/src/python/test_qgsselectioncontext.py @@ -6,7 +6,6 @@ (at your option) any later version. """ - from qgis.core import QgsSelectionContext from qgis.testing import unittest @@ -19,5 +18,5 @@ def testBasic(self): self.assertEqual(context.scale(), 1000) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssensormanager.py b/tests/src/python/test_qgssensormanager.py index a997e7c89afb..1d2f21ad937e 100644 --- a/tests/src/python/test_qgssensormanager.py +++ b/tests/src/python/test_qgssensormanager.py @@ -5,13 +5,21 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2023 by Mathieu Pellerin' -__date__ = '19/03/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "(C) 2023 by Mathieu Pellerin" +__date__ = "19/03/2023" +__copyright__ = "Copyright 2023, The QGIS Project" import os -from qgis.PyQt.QtCore import QCoreApplication, QEvent, QLocale, QTemporaryDir, QIODevice, QBuffer +from qgis.PyQt.QtCore import ( + QCoreApplication, + QEvent, + QLocale, + QTemporaryDir, + QIODevice, + QBuffer, +) from qgis.PyQt.QtTest import QSignalSpy from qgis.PyQt.QtXml import QDomDocument from qgis.core import ( @@ -23,7 +31,7 @@ QgsExpressionContextUtils, QgsIODeviceSensor, QgsProject, - QgsSensorManager + QgsSensorManager, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -53,7 +61,7 @@ def handleDisconnect(self): def pushData(self, data): self.buffer.buffer().clear() self.buffer.seek(0) - self.buffer.write(data.encode('ascii')) + self.buffer.write(data.encode("ascii")) self.buffer.seek(0) @@ -83,7 +91,7 @@ def setUp(self): def tearDown(self): """Run after each test.""" self.sensor.disconnectSensor() - self.sensor.setName('') + self.sensor.setName("") pass def testManagerAddRemove(self): @@ -104,49 +112,53 @@ def testManagerAddRemove(self): self.assertEqual(len(manager_removed_spy), 1) def testNameAndStatus(self): - self.assertEqual(self.sensor.name(), '') - self.sensor.setName('test sensor') - self.assertEqual(self.sensor.name(), 'test sensor') + self.assertEqual(self.sensor.name(), "") + self.sensor.setName("test sensor") + self.assertEqual(self.sensor.name(), "test sensor") self.assertEqual(self.sensor.status(), Qgis.DeviceConnectionStatus.Disconnected) self.sensor.connectSensor() self.assertEqual(self.sensor.status(), Qgis.DeviceConnectionStatus.Connected) def testProcessData(self): - self.sensor.setName('test sensor') + self.sensor.setName("test sensor") self.sensor.connectSensor() self.assertEqual(self.sensor.status(), Qgis.DeviceConnectionStatus.Connected) sensor_spy = QSignalSpy(self.sensor.dataChanged) manager_spy = QSignalSpy(self.manager.sensorDataCaptured) - self.sensor.pushData('test string') + self.sensor.pushData("test string") manager_spy.wait() self.assertEqual(len(sensor_spy), 1) self.assertEqual(len(manager_spy), 1) - self.assertEqual(self.sensor.data().lastValue, 'test string') - self.assertEqual(self.manager.sensorData('test sensor').lastValue, 'test string') + self.assertEqual(self.sensor.data().lastValue, "test string") + self.assertEqual( + self.manager.sensorData("test sensor").lastValue, "test string" + ) def testSensorDataExpression(self): - self.sensor.setName('test sensor') + self.sensor.setName("test sensor") self.sensor.connectSensor() self.assertEqual(self.sensor.status(), Qgis.DeviceConnectionStatus.Connected) data_spy = QSignalSpy(self.sensor.dataChanged) - self.sensor.pushData('test string 2') + self.sensor.pushData("test string 2") data_spy.wait() self.assertEqual(len(data_spy), 1) - self.assertEqual(self.sensor.data().lastValue, 'test string 2') + self.assertEqual(self.sensor.data().lastValue, "test string 2") - expression = QgsExpression('sensor_data(\'test sensor\')') + expression = QgsExpression("sensor_data('test sensor')") context = QgsExpressionContext() - context.appendScope(QgsExpressionContextUtils.projectScope(QgsProject.instance())) + context.appendScope( + QgsExpressionContextUtils.projectScope(QgsProject.instance()) + ) result = expression.evaluate(context) - self.assertEqual(result, 'test string 2') + self.assertEqual(result, "test string 2") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssensormodel.py b/tests/src/python/test_qgssensormodel.py index 51653985e372..dc1fba90dc41 100644 --- a/tests/src/python/test_qgssensormodel.py +++ b/tests/src/python/test_qgssensormodel.py @@ -5,13 +5,22 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2023 by Mathieu Pellerin' -__date__ = '19/03/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "(C) 2023 by Mathieu Pellerin" +__date__ = "19/03/2023" +__copyright__ = "Copyright 2023, The QGIS Project" import os -from qgis.PyQt.QtCore import QCoreApplication, QEvent, QLocale, QTemporaryDir, QIODevice, QBuffer, QDateTime +from qgis.PyQt.QtCore import ( + QCoreApplication, + QEvent, + QLocale, + QTemporaryDir, + QIODevice, + QBuffer, + QDateTime, +) from qgis.PyQt.QtTest import QSignalSpy from qgis.PyQt.QtXml import QDomDocument from qgis.core import ( @@ -58,7 +67,7 @@ def handleDisconnect(self): def pushData(self, data): self.buffer.buffer().clear() self.buffer.seek(0) - self.buffer.write(data.encode('ascii')) + self.buffer.write(data.encode("ascii")) self.buffer.seek(0) @@ -90,9 +99,9 @@ def tearDown(self): def testModel(self): sensor1 = QgsTcpSocketSensor() - sensor1.setName('name1') + sensor1.setName("name1") sensor2 = TestSensor() - sensor2.setName('name2') + sensor2.setName("name2") model_row_inserted_spy = QSignalSpy(self.model.rowsInserted) @@ -108,23 +117,56 @@ def testModel(self): self.assertEqual(len(model_row_removed_spy), 1) self.assertEqual(self.model.rowCount(), 1) - self.assertEqual(self.model.data(self.model.index(0, 0), QgsSensorModel.Role.SensorId), sensor2.id()) - self.assertEqual(self.model.data(self.model.index(0, 0), QgsSensorModel.Role.SensorName), sensor2.name()) - self.assertEqual(self.model.data(self.model.index(0, 0), QgsSensorModel.Role.SensorLastValue), None) - self.assertEqual(self.model.data(self.model.index(0, 0), QgsSensorModel.Role.SensorLastTimestamp), None) - self.assertEqual(self.model.data(self.model.index(0, 0), QgsSensorModel.Role.Sensor), sensor2) + self.assertEqual( + self.model.data(self.model.index(0, 0), QgsSensorModel.Role.SensorId), + sensor2.id(), + ) + self.assertEqual( + self.model.data(self.model.index(0, 0), QgsSensorModel.Role.SensorName), + sensor2.name(), + ) + self.assertEqual( + self.model.data( + self.model.index(0, 0), QgsSensorModel.Role.SensorLastValue + ), + None, + ) + self.assertEqual( + self.model.data( + self.model.index(0, 0), QgsSensorModel.Role.SensorLastTimestamp + ), + None, + ) + self.assertEqual( + self.model.data(self.model.index(0, 0), QgsSensorModel.Role.Sensor), sensor2 + ) model_data_changed_spy = QSignalSpy(self.model.dataChanged) - sensor2.setName('new name2') + sensor2.setName("new name2") sensor2.connectSensor() - sensor2.pushData('test string') + sensor2.pushData("test string") model_data_changed_spy.wait() - self.assertEqual(len(model_data_changed_spy), 4) # new name, connecting + connected state, and data change signals - self.assertEqual(self.model.data(self.model.index(0, 0), QgsSensorModel.Role.SensorName), sensor2.name()) - self.assertEqual(self.model.data(self.model.index(0, 0), QgsSensorModel.Role.SensorLastValue), sensor2.data().lastValue) - self.assertEqual(self.model.data(self.model.index(0, 0), QgsSensorModel.Role.SensorLastTimestamp), sensor2.data().lastTimestamp) - - -if __name__ == '__main__': + self.assertEqual( + len(model_data_changed_spy), 4 + ) # new name, connecting + connected state, and data change signals + self.assertEqual( + self.model.data(self.model.index(0, 0), QgsSensorModel.Role.SensorName), + sensor2.name(), + ) + self.assertEqual( + self.model.data( + self.model.index(0, 0), QgsSensorModel.Role.SensorLastValue + ), + sensor2.data().lastValue, + ) + self.assertEqual( + self.model.data( + self.model.index(0, 0), QgsSensorModel.Role.SensorLastTimestamp + ), + sensor2.data().lastTimestamp, + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssensorregistry.py b/tests/src/python/test_qgssensorregistry.py index 29ef06cd229e..e5ad5dbc6cb5 100644 --- a/tests/src/python/test_qgssensorregistry.py +++ b/tests/src/python/test_qgssensorregistry.py @@ -5,12 +5,18 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Mathieu Pellerin' -__date__ = '19/03/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' +__author__ = "Mathieu Pellerin" +__date__ = "19/03/2023" +__copyright__ = "Copyright 2023, The QGIS Project" -from qgis.core import QgsSensorRegistry, QgsSensorAbstractMetadata, QgsTcpSocketSensor, QgsUdpSocketSensor + +from qgis.core import ( + QgsSensorRegistry, + QgsSensorAbstractMetadata, + QgsTcpSocketSensor, + QgsUdpSocketSensor, +) import unittest from qgis.testing import start_app, QgisTestCase @@ -42,22 +48,28 @@ def testRegistry(self): registry.addSensorType(TestTcpSensorMetadata()) registry.addSensorType(TestUdpSensorMetadata()) - self.assertEqual(registry.sensorTypes(), {'test_tcp_sensor': 'test tcp sensor', 'test_udp_sensor': 'test udp sensor'}) - - sensor = registry.createSensor('test_tcp_sensor') + self.assertEqual( + registry.sensorTypes(), + { + "test_tcp_sensor": "test tcp sensor", + "test_udp_sensor": "test udp sensor", + }, + ) + + sensor = registry.createSensor("test_tcp_sensor") self.assertTrue(sensor) - self.assertEqual(sensor.type(), 'tcp_socket') + self.assertEqual(sensor.type(), "tcp_socket") - sensor = registry.createSensor('test_udp_sensor') + sensor = registry.createSensor("test_udp_sensor") self.assertTrue(sensor) - self.assertEqual(sensor.type(), 'udp_socket') + self.assertEqual(sensor.type(), "udp_socket") - sensor = registry.createSensor('invalid_sensor_type') + sensor = registry.createSensor("invalid_sensor_type") self.assertFalse(sensor) - registry.removeSensorType('test_tcp_sensor') - self.assertEqual(registry.sensorTypes(), {'test_udp_sensor': 'test udp sensor'}) + registry.removeSensorType("test_tcp_sensor") + self.assertEqual(registry.sensorTypes(), {"test_udp_sensor": "test udp sensor"}) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserialportsensor.py b/tests/src/python/test_qgsserialportsensor.py index 91e4e10f4cb9..698261190972 100644 --- a/tests/src/python/test_qgsserialportsensor.py +++ b/tests/src/python/test_qgsserialportsensor.py @@ -5,14 +5,23 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2023 by Mathieu Pellerin' -__date__ = '19/03/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "(C) 2023 by Mathieu Pellerin" +__date__ = "19/03/2023" +__copyright__ = "Copyright 2023, The QGIS Project" import os import posix -from qgis.PyQt.QtCore import QCoreApplication, QEvent, QLocale, QTemporaryDir, QIODevice, QBuffer, QByteArray +from qgis.PyQt.QtCore import ( + QCoreApplication, + QEvent, + QLocale, + QTemporaryDir, + QIODevice, + QBuffer, + QByteArray, +) from qgis.PyQt.QtTest import QSignalSpy from qgis.PyQt.QtXml import QDomDocument from qgis.core import ( @@ -20,7 +29,7 @@ QgsApplication, QgsProject, QgsSerialPortSensor, - QgsSensorManager + QgsSensorManager, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -60,9 +69,9 @@ def testSerialPortSensor(self): fd_file = os.fdopen(fd1, "wb") serial_port_sensor = QgsSerialPortSensor() - serial_port_sensor.setName('serial port sensor') + serial_port_sensor.setName("serial port sensor") serial_port_sensor.setPortName(os.ttyname(fd2)) - serial_port_sensor.setDelimiter(b'\n') + serial_port_sensor.setDelimiter(b"\n") serial_port_sensor_id = serial_port_sensor.id() @@ -72,10 +81,12 @@ def testSerialPortSensor(self): manager_spy = QSignalSpy(self.manager.sensorDataCaptured) serial_port_sensor.connectSensor() - self.assertEqual(serial_port_sensor.status(), Qgis.DeviceConnectionStatus.Connected) + self.assertEqual( + serial_port_sensor.status(), Qgis.DeviceConnectionStatus.Connected + ) QCoreApplication.processEvents() - fd_file.write(b'test 1\nfull ') + fd_file.write(b"test 1\nfull ") fd_file.flush() QCoreApplication.processEvents() @@ -84,17 +95,21 @@ def testSerialPortSensor(self): self.assertEqual(len(manager_spy), 0) QCoreApplication.processEvents() - fd_file.write(b'test 2\n') + fd_file.write(b"test 2\n") fd_file.flush() QCoreApplication.processEvents() self.assertEqual(len(sensor_spy), 1) self.assertEqual(len(manager_spy), 1) - self.assertEqual(serial_port_sensor.data().lastValue, QByteArray(b'full test 2')) - self.assertEqual(self.manager.sensorData('serial port sensor').lastValue, b'full test 2') + self.assertEqual( + serial_port_sensor.data().lastValue, QByteArray(b"full test 2") + ) + self.assertEqual( + self.manager.sensorData("serial port sensor").lastValue, b"full test 2" + ) self.manager.removeSensor(serial_port_sensor_id) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver.py b/tests/src/python/test_qgsserver.py index 4b6dcc9995a5..c9427078000f 100644 --- a/tests/src/python/test_qgsserver.py +++ b/tests/src/python/test_qgsserver.py @@ -19,14 +19,15 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '25/05/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "25/05/2015" +__copyright__ = "Copyright 2015, The QGIS Project" import os # Deterministic XML -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" import base64 import difflib @@ -62,62 +63,111 @@ start_app() # Strip path and content length because path may vary -RE_STRIP_UNCHECKABLE = br'MAP=[^"]+|Content-Length: \d+' -RE_ELEMENT = br'\[\s]+)[ >]' -RE_ELEMENT_CONTENT = br'<[^>\[]+>(.+)\[\s]+>' +RE_STRIP_UNCHECKABLE = rb'MAP=[^"]+|Content-Length: \d+' +RE_ELEMENT = rb"\[\s]+)[ >]" +RE_ELEMENT_CONTENT = rb"<[^>\[]+>(.+)\[\s]+>" RE_ATTRIBUTES = rb'((?:(?!\s|=).)*)\s*?=\s*?["\']?((?:(?<=")(?:(?<=\\)"|[^"])*|(?<=\')(?:(?<=\\)\'|[^\'])*)|(?:(?!"|\')(?:(?!\/>|>|\s).)+))' class QgsServerTestBase(QgisTestCase): - """Base class for QGIS server tests""" # Set to True in child classes to re-generate reference files for this class regenerate_reference = False - def assertXMLEqual(self, response, expected, msg='', raw=False): + def assertXMLEqual(self, response, expected, msg="", raw=False): """Compare XML line by line and sorted attributes""" response_lines = response.splitlines() expected_lines = expected.splitlines() line_no = 1 diffs = [] - for diff in difflib.unified_diff([l.decode('utf8') for l in expected_lines], [l.decode('utf8') for l in response_lines]): + for diff in difflib.unified_diff( + [l.decode("utf8") for l in expected_lines], + [l.decode("utf8") for l in response_lines], + ): diffs.append(diff) self.assertEqual( len(expected_lines), len(response_lines), - "Expected and response have different number of lines!\n{}\n{}\nWe got :\n{}".format(msg, '\n'.join(diffs), '\n'.join([i.decode("utf-8") for i in response_lines]))) + "Expected and response have different number of lines!\n{}\n{}\nWe got :\n{}".format( + msg, + "\n".join(diffs), + "\n".join([i.decode("utf-8") for i in response_lines]), + ), + ) for expected_line in expected_lines: expected_line = expected_line.strip() response_line = response_lines[line_no - 1].strip() - response_line = response_line.replace(b'e+6', br'e+06') + response_line = response_line.replace(b"e+6", rb"e+06") # Compare tag if re.match(RE_ELEMENT, expected_line) and not raw: expected_elements = re.findall(RE_ELEMENT, expected_line) response_elements = re.findall(RE_ELEMENT, response_line) - self.assertEqual(expected_elements[0], - response_elements[0], msg=msg + f"\nTag mismatch on line {line_no}: {expected_line} != {response_line}") + self.assertEqual( + expected_elements[0], + response_elements[0], + msg=msg + + f"\nTag mismatch on line {line_no}: {expected_line} != {response_line}", + ) # Compare content - if len(expected_elements) == 2 and expected_elements[0] == expected_elements[1]: - expected_element_content = re.findall(RE_ELEMENT_CONTENT, expected_line) - response_element_content = re.findall(RE_ELEMENT_CONTENT, response_line) - self.assertEqual(len(expected_element_content), len(response_element_content), - msg=msg + f"\nContent mismatch on line {line_no}: {expected_line} != {response_line}") + if ( + len(expected_elements) == 2 + and expected_elements[0] == expected_elements[1] + ): + expected_element_content = re.findall( + RE_ELEMENT_CONTENT, expected_line + ) + response_element_content = re.findall( + RE_ELEMENT_CONTENT, response_line + ) + self.assertEqual( + len(expected_element_content), + len(response_element_content), + msg=msg + + f"\nContent mismatch on line {line_no}: {expected_line} != {response_line}", + ) if len(expected_element_content): - self.assertEqual(expected_element_content[0], - response_element_content[0], msg=msg + f"\nContent mismatch on line {line_no}: {expected_line} != {response_line}") + self.assertEqual( + expected_element_content[0], + response_element_content[0], + msg=msg + + f"\nContent mismatch on line {line_no}: {expected_line} != {response_line}", + ) else: - self.assertEqual(expected_line, response_line, msg=msg + f"\nTag line mismatch {line_no}: {expected_line} != {response_line}\n{msg}") + self.assertEqual( + expected_line, + response_line, + msg=msg + + f"\nTag line mismatch {line_no}: {expected_line} != {response_line}\n{msg}", + ) # print("---->%s\t%s == %s" % (line_no, expected_line, response_line)) # Compare attributes if re.findall(RE_ATTRIBUTES, expected_line): # has attrs - expected_attrs, expected_values = zip(*sorted(re.findall(RE_ATTRIBUTES, expected_line))) - self.assertTrue(re.findall(RE_ATTRIBUTES, response_line), msg=msg + f"\nXML attributes differ at line {line_no}: {expected_line} != {response_line}") - response_attrs, response_values = zip(*sorted(re.findall(RE_ATTRIBUTES, response_line))) - self.assertEqual(expected_attrs, response_attrs, msg=msg + f"\nXML attributes differ at line {line_no}: {expected_attrs} != {response_attrs}") - self.assertEqual(expected_values, response_values, msg=msg + f"\nXML attribute values differ at line {line_no}: {expected_values} != {response_values}") + expected_attrs, expected_values = zip( + *sorted(re.findall(RE_ATTRIBUTES, expected_line)) + ) + self.assertTrue( + re.findall(RE_ATTRIBUTES, response_line), + msg=msg + + f"\nXML attributes differ at line {line_no}: {expected_line} != {response_line}", + ) + response_attrs, response_values = zip( + *sorted(re.findall(RE_ATTRIBUTES, response_line)) + ) + self.assertEqual( + expected_attrs, + response_attrs, + msg=msg + + f"\nXML attributes differ at line {line_no}: {expected_attrs} != {response_attrs}", + ) + self.assertEqual( + expected_values, + response_values, + msg=msg + + f"\nXML attribute values differ at line {line_no}: {expected_values} != {response_values}", + ) line_no += 1 @classmethod @@ -125,42 +175,45 @@ def setUpClass(self): """Create the server instance""" super().setUpClass() self.fontFamily = QgsFontUtils.standardTestFontFamily() - QgsFontUtils.loadStandardTestFonts(['All']) + QgsFontUtils.loadStandardTestFonts(["All"]) self.temporary_dir = tempfile.TemporaryDirectory() self.temporary_path = self.temporary_dir.name # Copy all testdata to the temporary directory - copytree(unitTestDataPath('qgis_server'), os.path.join(self.temporary_path, 'qgis_server')) - copytree(unitTestDataPath('qgis_server_accesscontrol'), os.path.join(self.temporary_path, 'qgis_server_accesscontrol')) + copytree( + unitTestDataPath("qgis_server"), + os.path.join(self.temporary_path, "qgis_server"), + ) + copytree( + unitTestDataPath("qgis_server_accesscontrol"), + os.path.join(self.temporary_path, "qgis_server_accesscontrol"), + ) for f in [ - 'empty_spatial_layer.dbf', - 'empty_spatial_layer.prj', - 'empty_spatial_layer.qpj', - 'empty_spatial_layer.shp', - 'empty_spatial_layer.shx', - 'france_parts.dbf', - 'france_parts.prj', - 'france_parts.qpj', - 'france_parts.shp', - 'france_parts.shp.xml', - 'france_parts.shx', - 'landsat.tif', - 'points.dbf', - 'points.prj', - 'points.shp', - 'points.shx', - 'requires_warped_vrt.tif', + "empty_spatial_layer.dbf", + "empty_spatial_layer.prj", + "empty_spatial_layer.qpj", + "empty_spatial_layer.shp", + "empty_spatial_layer.shx", + "france_parts.dbf", + "france_parts.prj", + "france_parts.qpj", + "france_parts.shp", + "france_parts.shp.xml", + "france_parts.shx", + "landsat.tif", + "points.dbf", + "points.prj", + "points.shp", + "points.shx", + "requires_warped_vrt.tif", ]: - os.symlink( - unitTestDataPath(f), - os.path.join(self.temporary_path, f) - ) + os.symlink(unitTestDataPath(f), os.path.join(self.temporary_path, f)) - self.testdata_path = os.path.join(self.temporary_path, 'qgis_server') + '/' + self.testdata_path = os.path.join(self.temporary_path, "qgis_server") + "/" - d = os.path.join(self.temporary_path, 'qgis_server_accesscontrol') + d = os.path.join(self.temporary_path, "qgis_server_accesscontrol") self.projectPath = os.path.join(d, "project.qgs") self.projectAnnotationPath = os.path.join(d, "project_with_annotations.qgs") @@ -169,7 +222,7 @@ def setUpClass(self): self.projectGroupsPath = os.path.join(d, "project_groups.qgs") # Clean env just to be sure - env_vars = ['QUERY_STRING', 'QGIS_PROJECT_FILE'] + env_vars = ["QUERY_STRING", "QGIS_PROJECT_FILE"] for ev in env_vars: try: del os.environ[ev] @@ -194,17 +247,24 @@ def tearDownClass(self): def strip_version_xmlns(self, text): """Order of attributes is random, strip version and xmlns""" - return text.replace(b'version="1.3.0"', b'').replace(b'xmlns="http://www.opengis.net/ogc"', b'') + return text.replace(b'version="1.3.0"', b"").replace( + b'xmlns="http://www.opengis.net/ogc"', b"" + ) def assert_headers(self, header, body): stream = StringIO() - header_string = header.decode('utf-8') + header_string = header.decode("utf-8") stream.write(header_string) headers = email.message_from_string(header_string) - if 'content-length' in headers: - content_length = int(headers['content-length']) + if "content-length" in headers: + content_length = int(headers["content-length"]) body_length = len(body) - self.assertEqual(content_length, body_length, msg="Header reported content-length: %d Actual body length was: %d" % (content_length, body_length)) + self.assertEqual( + content_length, + body_length, + msg="Header reported content-length: %d Actual body length was: %d" + % (content_length, body_length), + ) @classmethod def store_reference(self, reference_path, response): @@ -215,13 +275,13 @@ def store_reference(self, reference_path, response): return # Store the output for debug or to regenerate the reference documents: - f = open(reference_path, 'wb+') + f = open(reference_path, "wb+") f.write(response) f.close() def _result(self, data): headers = {} - for line in data[0].decode('UTF-8').split("\n"): + for line in data[0].decode("UTF-8").split("\n"): if line != "": header = line.split(":") self.assertEqual(len(header), 2, line) @@ -229,30 +289,41 @@ def _result(self, data): return data[1], headers - def _img_diff(self, image: str, control_image, max_diff, max_size_diff=QSize(), outputFormat='PNG') -> bool: - - if outputFormat == 'PNG': - extFile = 'png' - elif outputFormat == 'JPG': - extFile = 'jpg' - elif outputFormat == 'WEBP': - extFile = 'webp' + def _img_diff( + self, + image: str, + control_image, + max_diff, + max_size_diff=QSize(), + outputFormat="PNG", + ) -> bool: + + if outputFormat == "PNG": + extFile = "png" + elif outputFormat == "JPG": + extFile = "jpg" + elif outputFormat == "WEBP": + extFile = "webp" else: - raise RuntimeError('Yeah, new format implemented') + raise RuntimeError("Yeah, new format implemented") - temp_image = os.path.join(tempfile.gettempdir(), f"{control_image}_result.{extFile}") + temp_image = os.path.join( + tempfile.gettempdir(), f"{control_image}_result.{extFile}" + ) with open(temp_image, "wb") as f: f.write(image) - if outputFormat != 'PNG': + if outputFormat != "PNG": # TODO fix this, it's not actually testing anything..! return True rendered_image = QImage(temp_image) - if rendered_image.format() not in (QImage.Format.Format_RGB32, - QImage.Format.Format_ARGB32, - QImage.Format.Format_ARGB32_Premultiplied): + if rendered_image.format() not in ( + QImage.Format.Format_RGB32, + QImage.Format.Format_ARGB32, + QImage.Format.Format_ARGB32_Premultiplied, + ): rendered_image = rendered_image.convertToFormat(QImage.Format.Format_ARGB32) return self.image_check( @@ -262,40 +333,63 @@ def _img_diff(self, image: str, control_image, max_diff, max_size_diff=QSize(), control_image, allowed_mismatch=max_diff, control_path_prefix="qgis_server", - size_tolerance=max_size_diff + size_tolerance=max_size_diff, ) - def _img_diff_error(self, response, headers, test_name: str, max_diff=100, max_size_diff=QSize(), outputFormat='PNG'): + def _img_diff_error( + self, + response, + headers, + test_name: str, + max_diff=100, + max_size_diff=QSize(), + outputFormat="PNG", + ): """ :param outputFormat: PNG, JPG or WEBP """ - if outputFormat == 'PNG': - extFile = 'png' - contentType = 'image/png' - elif outputFormat == 'JPG': - extFile = 'jpg' - contentType = 'image/jpeg' - elif outputFormat == 'WEBP': - extFile = 'webp' - contentType = 'image/webp' + if outputFormat == "PNG": + extFile = "png" + contentType = "image/png" + elif outputFormat == "JPG": + extFile = "jpg" + contentType = "image/jpeg" + elif outputFormat == "WEBP": + extFile = "webp" + contentType = "image/webp" else: - raise RuntimeError('Yeah, new format implemented') + raise RuntimeError("Yeah, new format implemented") if self.regenerate_reference: - reference_path = unitTestDataPath( - 'control_images') + '/qgis_server/' + test_name + '/' + test_name + '.' + extFile + reference_path = ( + unitTestDataPath("control_images") + + "/qgis_server/" + + test_name + + "/" + + test_name + + "." + + extFile + ) self.store_reference(reference_path, response) self.assertEqual( - headers.get("Content-Type"), contentType, - f"Content type is wrong: {headers.get('Content-Type')} instead of {contentType}\n{response}") + headers.get("Content-Type"), + contentType, + f"Content type is wrong: {headers.get('Content-Type')} instead of {contentType}\n{response}", + ) self.assertTrue( self._img_diff(response, test_name, max_diff, max_size_diff, outputFormat) ) - def _execute_request(self, qs, requestMethod=QgsServerRequest.GetMethod, data=None, request_headers=None): + def _execute_request( + self, + qs, + requestMethod=QgsServerRequest.GetMethod, + data=None, + request_headers=None, + ): request = QgsBufferServerRequest(qs, requestMethod, request_headers or {}, data) response = QgsBufferServerResponse() self.server.handleRequest(request, response) @@ -306,7 +400,9 @@ def _execute_request(self, qs, requestMethod=QgsServerRequest.GetMethod, data=No headers.append((f"{k}: {rh[k]}").encode()) return b"\n".join(headers) + b"\n\n", bytes(response.body()) - def _execute_request_project(self, qs, project, requestMethod=QgsServerRequest.GetMethod, data=None): + def _execute_request_project( + self, qs, project, requestMethod=QgsServerRequest.GetMethod, data=None + ): request = QgsBufferServerRequest(qs, requestMethod, {}, data) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) @@ -317,11 +413,20 @@ def _execute_request_project(self, qs, project, requestMethod=QgsServerRequest.G headers.append((f"{k}: {rh[k]}").encode()) return b"\n".join(headers) + b"\n\n", bytes(response.body()) - def _assert_status_code(self, status_code, qs, requestMethod=QgsServerRequest.GetMethod, data=None, project=None): + def _assert_status_code( + self, + status_code, + qs, + requestMethod=QgsServerRequest.GetMethod, + data=None, + project=None, + ): request = QgsBufferServerRequest(qs, requestMethod, {}, data) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) - assert response.statusCode() == status_code, f"{response.statusCode()} != {status_code}" + assert ( + response.statusCode() == status_code + ), f"{response.statusCode()} != {status_code}" def _assertRed(self, color: QColor): self.assertEqual(color.red(), 255) @@ -356,11 +461,11 @@ def test_assert_xml_equal(self): # test bad assertion expected = b'\n\n' - response = b'\n' + response = b"\n" self.assertRaises(AssertionError, engine.assertXMLEqual, response, expected) expected = b'\n\n' - response = b'\n\n' + response = b"\n\n" self.assertRaises(AssertionError, engine.assertXMLEqual, response, expected) expected = b'\n\n' @@ -390,7 +495,6 @@ def test_assert_xml_equal(self): class TestQgsServer(QgsServerTestBase): - """Tests container""" # Set to True to re-generate reference files for this class @@ -411,22 +515,38 @@ def test_multiple_servers(self): def test_requestHandler(self): """Test request handler""" - headers = {'header-key-1': 'header-value-1', 'header-key-2': 'header-value-2'} - request = QgsBufferServerRequest('http://somesite.com/somepath', QgsServerRequest.GetMethod, headers) + headers = {"header-key-1": "header-value-1", "header-key-2": "header-value-2"} + request = QgsBufferServerRequest( + "http://somesite.com/somepath", QgsServerRequest.GetMethod, headers + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response) - self.assertEqual(bytes(response.body()), b'\nProject file error. For OWS services: please provide a SERVICE and a MAP parameter pointing to a valid QGIS project file\n') - self.assertEqual(response.headers(), {'Content-Length': '195', 'Content-Type': 'text/xml; charset=utf-8'}) + self.assertEqual( + bytes(response.body()), + b'\nProject file error. For OWS services: please provide a SERVICE and a MAP parameter pointing to a valid QGIS project file\n', + ) + self.assertEqual( + response.headers(), + {"Content-Length": "195", "Content-Type": "text/xml; charset=utf-8"}, + ) self.assertEqual(response.statusCode(), 500) def test_requestHandlerProject(self): """Test request handler with none project""" - headers = {'header-key-1': 'header-value-1', 'header-key-2': 'header-value-2'} - request = QgsBufferServerRequest('http://somesite.com/somepath', QgsServerRequest.GetMethod, headers) + headers = {"header-key-1": "header-value-1", "header-key-2": "header-value-2"} + request = QgsBufferServerRequest( + "http://somesite.com/somepath", QgsServerRequest.GetMethod, headers + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, None) - self.assertEqual(bytes(response.body()), b'\nProject file error. For OWS services: please provide a SERVICE and a MAP parameter pointing to a valid QGIS project file\n') - self.assertEqual(response.headers(), {'Content-Length': '195', 'Content-Type': 'text/xml; charset=utf-8'}) + self.assertEqual( + bytes(response.body()), + b'\nProject file error. For OWS services: please provide a SERVICE and a MAP parameter pointing to a valid QGIS project file\n', + ) + self.assertEqual( + response.headers(), + {"Content-Length": "195", "Content-Type": "text/xml; charset=utf-8"}, + ) self.assertEqual(response.statusCode(), 500) def test_api(self): @@ -435,23 +555,29 @@ def test_api(self): # Test as a whole header, body = self._execute_request("") response = self.strip_version_xmlns(header + body) - expected = self.strip_version_xmlns(b'Content-Length: 195\nContent-Type: text/xml; charset=utf-8\n\n\nProject file error. For OWS services: please provide a SERVICE and a MAP parameter pointing to a valid QGIS project file\n') + expected = self.strip_version_xmlns( + b'Content-Length: 195\nContent-Type: text/xml; charset=utf-8\n\n\nProject file error. For OWS services: please provide a SERVICE and a MAP parameter pointing to a valid QGIS project file\n' + ) self.assertEqual(response, expected) - expected = b'Content-Length: 195\nContent-Type: text/xml; charset=utf-8\n\n' + expected = b"Content-Length: 195\nContent-Type: text/xml; charset=utf-8\n\n" self.assertEqual(header, expected) # Test response when project is specified but without service project = self.testdata_path + "test_project_wfs.qgs" - qs = f'?MAP={urllib.parse.quote(project)}' + qs = f"?MAP={urllib.parse.quote(project)}" header, body = self._execute_request(qs) response = self.strip_version_xmlns(header + body) - expected = self.strip_version_xmlns(b'Content-Length: 365\nContent-Type: text/xml; charset=utf-8\n\n\n\n Service unknown or unsupported. Current supported services (case-sensitive): WMS WFS WCS WMTS SampleService, or use a WFS3 (OGC API Features) endpoint\n\n') + expected = self.strip_version_xmlns( + b'Content-Length: 365\nContent-Type: text/xml; charset=utf-8\n\n\n\n Service unknown or unsupported. Current supported services (case-sensitive): WMS WFS WCS WMTS SampleService, or use a WFS3 (OGC API Features) endpoint\n\n' + ) self.assertEqual(response, expected) - expected = b'Content-Length: 365\nContent-Type: text/xml; charset=utf-8\n\n' + expected = b"Content-Length: 365\nContent-Type: text/xml; charset=utf-8\n\n" self.assertEqual(header, expected) # Test body - expected = self.strip_version_xmlns(b'\n\n Service unknown or unsupported. Current supported services (case-sensitive): WMS WFS WCS WMTS SampleService, or use a WFS3 (OGC API Features) endpoint\n\n') + expected = self.strip_version_xmlns( + b'\n\n Service unknown or unsupported. Current supported services (case-sensitive): WMS WFS WCS WMTS SampleService, or use a WFS3 (OGC API Features) endpoint\n\n' + ) self.assertEqual(self.strip_version_xmlns(body), expected) # WCS tests @@ -459,77 +585,107 @@ def wcs_request_compare(self, request): project = self.projectPath assert os.path.exists(project), "Project file not found: " + project - query_string = f'?MAP={urllib.parse.quote(project)}&SERVICE=WCS&VERSION=1.0.0&REQUEST={request}' + query_string = f"?MAP={urllib.parse.quote(project)}&SERVICE=WCS&VERSION=1.0.0&REQUEST={request}" header, body = self._execute_request(query_string) self.assert_headers(header, body) response = header + body - reference_path = self.testdata_path + 'wcs_' + request.lower() + '.txt' - f = open(reference_path, 'rb') + reference_path = self.testdata_path + "wcs_" + request.lower() + ".txt" + f = open(reference_path, "rb") self.store_reference(reference_path, response) expected = f.read() f.close() - response = re.sub(RE_STRIP_UNCHECKABLE, b'', response) - expected = re.sub(RE_STRIP_UNCHECKABLE, b'', expected) + response = re.sub(RE_STRIP_UNCHECKABLE, b"", response) + expected = re.sub(RE_STRIP_UNCHECKABLE, b"", expected) - self.assertXMLEqual(response, expected, msg=f"request {query_string} failed.\n Query: {request}\n Expected:\n{expected.decode('utf-8')}\n\n Response:\n{response.decode('utf-8')}") + self.assertXMLEqual( + response, + expected, + msg=f"request {query_string} failed.\n Query: {request}\n Expected:\n{expected.decode('utf-8')}\n\n Response:\n{response.decode('utf-8')}", + ) def test_project_wcs(self): """Test some WCS request""" - for request in ('GetCapabilities', 'DescribeCoverage'): + for request in ("GetCapabilities", "DescribeCoverage"): self.wcs_request_compare(request) def test_wcs_getcapabilities_url(self): # empty url in project project = os.path.join(self.testdata_path, "test_project_without_urls.qgs") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WCS", - "VERSION": "1.0.0", - "REQUEST": "GetCapabilities", - "STYLES": "" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WCS", + "VERSION": "1.0.0", + "REQUEST": "GetCapabilities", + "STYLES": "", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) item_found = False for item in str(r).split("\\n"): if "OnlineResource" in item: - self.assertEqual("=\"?" in item, True) + self.assertEqual('="?' in item, True) item_found = True self.assertTrue(item_found) # url well defined in project project = os.path.join(self.testdata_path, "test_project_with_urls.qgs") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WCS", - "VERSION": "1.0.0", - "REQUEST": "GetCapabilities", - "STYLES": "" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WCS", + "VERSION": "1.0.0", + "REQUEST": "GetCapabilities", + "STYLES": "", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) item_found = False for item in str(r).split("\\n"): if "OnlineResource" in item: - self.assertEqual("\"my_wcs_advertised_url" in item, True) + self.assertEqual('"my_wcs_advertised_url' in item, True) item_found = True self.assertTrue(item_found) # Service URL in header - for header_name, header_value in (("X-Qgis-Service-Url", "http://test1"), ("X-Qgis-Wcs-Service-Url", "http://test2")): + for header_name, header_value in ( + ("X-Qgis-Service-Url", "http://test1"), + ("X-Qgis-Wcs-Service-Url", "http://test2"), + ): # empty url in project project = os.path.join(self.testdata_path, "test_project_without_urls.qgs") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WCS", - "VERSION": "1.0.0", - "REQUEST": "GetCapabilities", - "STYLES": "" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WCS", + "VERSION": "1.0.0", + "REQUEST": "GetCapabilities", + "STYLES": "", + }.items() + ) + ] + ) - r, h = self._result(self._execute_request(qs, request_headers={header_name: header_value})) + r, h = self._result( + self._execute_request(qs, request_headers={header_name: header_value}) + ) item_found = False for item in str(r).split("\\n"): @@ -541,19 +697,32 @@ def test_wcs_getcapabilities_url(self): # Other headers combinaison for headers, online_resource in ( ({"Forwarded": "host=test3;proto=https"}, "https://test3"), - ({"Forwarded": "host=test4;proto=https, host=test5;proto=https"}, "https://test4"), - ({"X-Forwarded-Host": "test6", "X-Forwarded-Proto": "https"}, "https://test6"), + ( + {"Forwarded": "host=test4;proto=https, host=test5;proto=https"}, + "https://test4", + ), + ( + {"X-Forwarded-Host": "test6", "X-Forwarded-Proto": "https"}, + "https://test6", + ), ({"Host": "test7"}, "test7"), ): # empty url in project project = os.path.join(self.testdata_path, "test_project_without_urls.qgs") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WCS", - "VERSION": "1.0.0", - "REQUEST": "GetCapabilities", - "STYLES": "" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WCS", + "VERSION": "1.0.0", + "REQUEST": "GetCapabilities", + "STYLES": "", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs, request_headers=headers)) @@ -588,7 +757,7 @@ def test_filter(self): # multiple qgis expressions filter0 = "to_datetime('2017-09-29 12:00:00')" - filter1 = "Contours:\"elev\" <= 1200" + filter1 = 'Contours:"elev" <= 1200' filter2 = "\"name\"='three'" param = QgsServerParameterDefinition() @@ -677,5 +846,5 @@ def test_filter(self): self.assertEqual(param.toOgcFilterList()[7], "") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_accesscontrol.py b/tests/src/python/test_qgsserver_accesscontrol.py index 35569b101186..ec3d23b1ebf8 100644 --- a/tests/src/python/test_qgsserver_accesscontrol.py +++ b/tests/src/python/test_qgsserver_accesscontrol.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Stephane Brunner' -__date__ = '28/08/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Stephane Brunner" +__date__ = "28/08/2015" +__copyright__ = "Copyright 2015, The QGIS Project" import os import shutil @@ -28,21 +29,21 @@ from test_qgsserver import QgsServerTestBase from utilities import unitTestDataPath -XML_NS = \ - 'service="WFS" version="1.0.0" ' \ - 'xmlns:wfs="http://www.opengis.net/wfs" ' \ - 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' \ - 'xmlns:ogc="http://www.opengis.net/ogc" ' \ - 'xmlns="http://www.opengis.net/wfs" updateSequence="0" ' \ - 'xmlns:xlink="http://www.w3.org/1999/xlink" ' \ - 'xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/WFS-capabilities.xsd" ' \ - 'xmlns:gml="http://www.opengis.net/gml" ' \ +XML_NS = ( + 'service="WFS" version="1.0.0" ' + 'xmlns:wfs="http://www.opengis.net/wfs" ' + 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' + 'xmlns:ogc="http://www.opengis.net/ogc" ' + 'xmlns="http://www.opengis.net/wfs" updateSequence="0" ' + 'xmlns:xlink="http://www.w3.org/1999/xlink" ' + 'xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/WFS-capabilities.xsd" ' + 'xmlns:gml="http://www.opengis.net/gml" ' 'xmlns:ows="http://www.opengis.net/ows" ' +) class RestrictedAccessControl(QgsAccessControlFilter): - - """ Used to have restriction access """ + """Used to have restriction access""" # Be able to deactivate the access control to have a reference point _active = False @@ -51,7 +52,7 @@ def __init__(self, server_iface): super(QgsAccessControlFilter, self).__init__(server_iface) def layerFilterExpression(self, layer): - """ Return an additional expression filter """ + """Return an additional expression filter""" if not self._active: return super().layerFilterExpression(layer) @@ -64,7 +65,7 @@ def layerFilterExpression(self, layer): return None def layerFilterSubsetString(self, layer): - """ Return an additional subset string (typically SQL) filter """ + """Return an additional subset string (typically SQL) filter""" if not self._active: return super().layerFilterSubsetString(layer) @@ -79,7 +80,7 @@ def layerFilterSubsetString(self, layer): return None def layerPermissions(self, layer): - """ Return the layer rights """ + """Return the layer rights""" if not self._active: return super().layerPermissions(layer) @@ -95,12 +96,14 @@ def layerPermissions(self, layer): else: rights.canRead = layer.name() not in ("Country", "Hello_OnOff") if layer.name() == "db_point": - rights.canRead = rights.canInsert = rights.canUpdate = rights.canDelete = True + rights.canRead = rights.canInsert = rights.canUpdate = rights.canDelete = ( + True + ) return rights def authorizedLayerAttributes(self, layer, attributes): - """ Return the authorised layer attributes """ + """Return the authorised layer attributes""" if not self._active: return super().authorizedLayerAttributes(layer, attributes) @@ -110,7 +113,7 @@ def authorizedLayerAttributes(self, layer, attributes): return attributes def allowToEdit(self, layer, feature): - """ Are we authorise to modify the following geometry """ + """Are we authorise to modify the following geometry""" if not self._active: return super().allowToEdit(layer, feature) @@ -126,7 +129,7 @@ class TestQgsServerAccessControl(QgsServerTestBase): @classmethod def _execute_request(cls, qs, requestMethod=QgsServerRequest.GetMethod, data=None): if data is not None: - data = data.encode('utf-8') + data = data.encode("utf-8") request = QgsBufferServerRequest(qs, requestMethod, {}, data) response = QgsBufferServerResponse() cls._server.handleRequest(request, response) @@ -150,7 +153,7 @@ def setUpClass(cls): @classmethod def project_file(cls): - return 'project_grp.qgs' + return "project_grp.qgs" def setUp(self): super().setUp() @@ -164,20 +167,23 @@ def setUp(self): del os.environ[k] self.projectPath = os.path.join(self.tmp_path, self.project_file()) - self.assertTrue(os.path.isfile(self.projectPath), f'Could not find project file "{self.projectPath}"') + self.assertTrue( + os.path.isfile(self.projectPath), + f'Could not find project file "{self.projectPath}"', + ) def tearDown(self): shutil.rmtree(self.tmp_path, True) def _handle_request(self, restricted, query_string, **kwargs): self._accesscontrol._active = restricted - qs = "?" + query_string if query_string is not None else '' + qs = "?" + query_string if query_string is not None else "" result = self._result(self._execute_request(qs, **kwargs)) return result def _result(self, data): headers = {} - for line in data[0].decode('UTF-8').split("\n"): + for line in data[0].decode("UTF-8").split("\n"): if line != "": header = line.split(":") self.assertEqual(len(header), 2, line) @@ -195,28 +201,36 @@ def _get_restricted(self, query_string): def _post_fullaccess(self, data, query_string=None): self._server.putenv("QGIS_PROJECT_FILE", self.projectPath) - result = self._handle_request(False, query_string, requestMethod=QgsServerRequest.PostMethod, data=data) - self._server.putenv("QGIS_PROJECT_FILE", '') + result = self._handle_request( + False, query_string, requestMethod=QgsServerRequest.PostMethod, data=data + ) + self._server.putenv("QGIS_PROJECT_FILE", "") return result def _post_restricted(self, data, query_string=None): self._server.putenv("QGIS_PROJECT_FILE", self.projectPath) - result = self._handle_request(True, query_string, requestMethod=QgsServerRequest.PostMethod, data=data) - self._server.putenv("QGIS_PROJECT_FILE", '') + result = self._handle_request( + True, query_string, requestMethod=QgsServerRequest.PostMethod, data=data + ) + self._server.putenv("QGIS_PROJECT_FILE", "") return result - def _img_diff(self, image, control_image, max_diff, max_size_diff=QSize(), outputFormat='PNG'): + def _img_diff( + self, image, control_image, max_diff, max_size_diff=QSize(), outputFormat="PNG" + ): - if outputFormat == 'PNG': - extFile = 'png' - elif outputFormat == 'JPG': - extFile = 'jpg' - elif outputFormat == 'WEBP': - extFile = 'webp' + if outputFormat == "PNG": + extFile = "png" + elif outputFormat == "JPG": + extFile = "jpg" + elif outputFormat == "WEBP": + extFile = "webp" else: - raise RuntimeError('Yeah, new format implemented') + raise RuntimeError("Yeah, new format implemented") - temp_image = os.path.join(tempfile.gettempdir(), f"{control_image}_result.{extFile}") + temp_image = os.path.join( + tempfile.gettempdir(), f"{control_image}_result.{extFile}" + ) with open(temp_image, "wb") as f: f.write(image) @@ -229,12 +243,15 @@ def _img_diff(self, image, control_image, max_diff, max_size_diff=QSize(), outpu control.setSizeTolerance(max_size_diff.width(), max_size_diff.height()) return control.compareImages(control_image), control.report() - def _img_diff_error(self, response, headers, image, max_diff=10, max_size_diff=QSize()): - super()._img_diff_error(response, headers, image, max_diff=max_diff, - max_size_diff=max_size_diff) + def _img_diff_error( + self, response, headers, image, max_diff=10, max_size_diff=QSize() + ): + super()._img_diff_error( + response, headers, image, max_diff=max_diff, max_size_diff=max_size_diff + ) def _geo_img_diff(self, image_1, image_2): - if os.name == 'nt': + if os.name == "nt": # Not supported on Windows due to #13061 return 0 @@ -243,10 +260,15 @@ def _geo_img_diff(self, image_1, image_2): image_1 = gdal.Open(os.path.join(tempfile.gettempdir(), image_2), GA_ReadOnly) assert image_1, "No output image written: " + image_2 - image_2 = gdal.Open(os.path.join(self.testdata_path, "results", image_2), GA_ReadOnly) + image_2 = gdal.Open( + os.path.join(self.testdata_path, "results", image_2), GA_ReadOnly + ) assert image_1, "No expected image found:" + image_2 - if image_1.RasterXSize != image_2.RasterXSize or image_1.RasterYSize != image_2.RasterYSize: + if ( + image_1.RasterXSize != image_2.RasterXSize + or image_1.RasterYSize != image_2.RasterYSize + ): image_1 = None image_2 = None return 1000 # wrong size @@ -254,7 +276,9 @@ def _geo_img_diff(self, image_1, image_2): square_sum = 0 for x in range(image_1.RasterXSize): for y in range(image_1.RasterYSize): - square_sum += (image_1.ReadAsArray()[x][y] - image_2.ReadAsArray()[x][y]) ** 2 + square_sum += ( + image_1.ReadAsArray()[x][y] - image_2.ReadAsArray()[x][y] + ) ** 2 # Explicitly close GDAL datasets image_1 = None @@ -270,8 +294,11 @@ def _test_colors(self, colors): gid {id} - """.format(id=id, xml_ns=XML_NS) + """.format( + id=id, xml_ns=XML_NS + ) ) self.assertTrue( str(response).find(f"{color}") != -1, - f"Wrong color in result\n{response}") + f"Wrong color in result\n{response}", + ) diff --git a/tests/src/python/test_qgsserver_accesscontrol_fix_filters.py b/tests/src/python/test_qgsserver_accesscontrol_fix_filters.py index 6c66c56ace20..b85e6fe5abd9 100644 --- a/tests/src/python/test_qgsserver_accesscontrol_fix_filters.py +++ b/tests/src/python/test_qgsserver_accesscontrol_fix_filters.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'David Marteau' -__date__ = '10/09/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "David Marteau" +__date__ = "10/09/2022" +__copyright__ = "Copyright 2022, The QGIS Project" import urllib.error import urllib.parse @@ -23,33 +24,48 @@ class TestQgsServerAccessControlFixFilters(TestQgsServerAccessControl): def test_wfs_getfeature_fix_feature_filters(self): - wfs_query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WFS", - "VERSION": "1.0.0", - "REQUEST": "GetFeature", - "TYPENAME": "Hello_Filter", - "EXP_FILTER": "pkuid = 1" - }.items())]) + wfs_query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WFS", + "VERSION": "1.0.0", + "REQUEST": "GetFeature", + "TYPENAME": "Hello_Filter", + "EXP_FILTER": "pkuid = 1", + }.items() + ) + ] + ) - wms_query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "FORMAT": "image/png", - "LAYERS": "Hello_Filter", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857" - }.items())]) + wms_query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "FORMAT": "image/png", + "LAYERS": "Hello_Filter", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + }.items() + ) + ] + ) # Execute an unrestricted wfs request response, headers = self._get_fullaccess(wfs_query_string) self.assertTrue( str(response).find("1") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # Execute a restricted WMS request # That will store the filter expression in cache @@ -64,7 +80,8 @@ def test_wfs_getfeature_fix_feature_filters(self): response, headers = self._get_fullaccess(wfs_query_string) self.assertTrue( str(response).find("1") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) if __name__ == "__main__": diff --git a/tests/src/python/test_qgsserver_accesscontrol_wcs.py b/tests/src/python/test_qgsserver_accesscontrol_wcs.py index 3c731c2bbce9..44a026df7440 100644 --- a/tests/src/python/test_qgsserver_accesscontrol_wcs.py +++ b/tests/src/python/test_qgsserver_accesscontrol_wcs.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Stephane Brunner' -__date__ = '28/08/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Stephane Brunner" +__date__ = "28/08/2015" +__copyright__ = "Copyright 2015, The QGIS Project" import urllib.error import urllib.parse @@ -23,120 +24,177 @@ class TestQgsServerAccessControlWCS(TestQgsServerAccessControl): def test_wcs_getcapabilities(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WCS", - "VERSION": "1.0.0", - "REQUEST": "GetCapabilities", - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WCS", + "VERSION": "1.0.0", + "REQUEST": "GetCapabilities", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( str(response).find("dem") != -1, - f"No dem layer in WCS/GetCapabilities\n{response}") + f"No dem layer in WCS/GetCapabilities\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertTrue( str(response).find("dem") != -1, - f"No dem layer in WCS/GetCapabilities\n{response}") - - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WCS", - "VERSION": "1.0.0", - "REQUEST": "GetCapabilities", - "TEST": "dem", - }.items())]) + f"No dem layer in WCS/GetCapabilities\n{response}", + ) + + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WCS", + "VERSION": "1.0.0", + "REQUEST": "GetCapabilities", + "TEST": "dem", + }.items() + ) + ] + ) response, headers = self._get_restricted(query_string) self.assertFalse( str(response).find("dem") != -1, - f"Unexpected dem layer in WCS/GetCapabilities\n{response}") + f"Unexpected dem layer in WCS/GetCapabilities\n{response}", + ) def test_wcs_describecoverage(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WCS", - "VERSION": "1.0.0", - "REQUEST": "DescribeCoverage", - "COVERAGE": "dem", - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WCS", + "VERSION": "1.0.0", + "REQUEST": "DescribeCoverage", + "COVERAGE": "dem", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( str(response).find("dem") != -1, - f"No dem layer in DescribeCoverage\n{response}") + f"No dem layer in DescribeCoverage\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertTrue( str(response).find("dem") != -1, - f"No dem layer in DescribeCoverage\n{response}") - - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WCS", - "VERSION": "1.0.0", - "REQUEST": "DescribeCoverage", - "COVERAGE": "dem", - "TEST": "dem", - }.items())]) + f"No dem layer in DescribeCoverage\n{response}", + ) + + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WCS", + "VERSION": "1.0.0", + "REQUEST": "DescribeCoverage", + "COVERAGE": "dem", + "TEST": "dem", + }.items() + ) + ] + ) response, headers = self._get_restricted(query_string) self.assertFalse( str(response).find("dem") != -1, - f"Unexpected dem layer in DescribeCoverage\n{response}") + f"Unexpected dem layer in DescribeCoverage\n{response}", + ) def test_wcs_getcoverage(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WCS", - "VERSION": "1.0.0", - "REQUEST": "GetCoverage", - "COVERAGE": "dem", - "CRS": "EPSG:3857", - "BBOX": "-1387454,4252256,431091,5458375", - "HEIGHT": "100", - "WIDTH": "100", - "FORMAT": "GTiff", - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WCS", + "VERSION": "1.0.0", + "REQUEST": "GetCoverage", + "COVERAGE": "dem", + "CRS": "EPSG:3857", + "BBOX": "-1387454,4252256,431091,5458375", + "HEIGHT": "100", + "WIDTH": "100", + "FORMAT": "GTiff", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertEqual( - headers.get("Content-Type"), "image/tiff", - f"Content type for GetMap is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "image/tiff", + f"Content type for GetMap is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( self._geo_img_diff(response, "WCS_GetCoverage.geotiff") == 0, - "Image for GetCoverage is wrong") + "Image for GetCoverage is wrong", + ) response, headers = self._get_restricted(query_string) self.assertEqual( - headers.get("Content-Type"), "image/tiff", - f"Content type for GetMap is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "image/tiff", + f"Content type for GetMap is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( self._geo_img_diff(response, "WCS_GetCoverage.geotiff") == 0, - "Image for GetCoverage is wrong") - - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WCS", - "VERSION": "1.0.0", - "REQUEST": "GetCoverage", - "COVERAGE": "dem", - "CRS": "EPSG:3857", - "BBOX": "-1387454,4252256,431091,5458375", - "HEIGHT": "100", - "WIDTH": "100", - "FORMAT": "GTiff", - "TEST": "dem", - }.items())]) + "Image for GetCoverage is wrong", + ) + + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WCS", + "VERSION": "1.0.0", + "REQUEST": "GetCoverage", + "COVERAGE": "dem", + "CRS": "EPSG:3857", + "BBOX": "-1387454,4252256,431091,5458375", + "HEIGHT": "100", + "WIDTH": "100", + "FORMAT": "GTiff", + "TEST": "dem", + }.items() + ) + ] + ) response, headers = self._get_restricted(query_string) self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for GetMap is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for GetMap is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find('') != -1, - "The layer for the COVERAGE 'dem' is not found") + "The layer for the COVERAGE 'dem' is not found", + ) if __name__ == "__main__": diff --git a/tests/src/python/test_qgsserver_accesscontrol_wfs.py b/tests/src/python/test_qgsserver_accesscontrol_wfs.py index 0fdb97c1f227..a802b6f65256 100644 --- a/tests/src/python/test_qgsserver_accesscontrol_wfs.py +++ b/tests/src/python/test_qgsserver_accesscontrol_wfs.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Stephane Brunner' -__date__ = '28/08/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Stephane Brunner" +__date__ = "28/08/2015" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.testing import unittest import os @@ -23,123 +24,163 @@ class TestQgsServerAccessControlWFS(TestQgsServerAccessControl): def test_wfs_getcapabilities(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WFS", - "VERSION": "1.0.0", - "REQUEST": "GetCapabilities" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WFS", + "VERSION": "1.0.0", + "REQUEST": "GetCapabilities", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( str(response).find("Hello") != -1, - f"No Hello layer in WFS/GetCapabilities\n{response}") + f"No Hello layer in WFS/GetCapabilities\n{response}", + ) self.assertTrue( str(response).find("Hello_OnOff") != -1, - f"No Hello layer in WFS/GetCapabilities\n{response}") + f"No Hello layer in WFS/GetCapabilities\n{response}", + ) self.assertTrue( str(response).find("Country") != -1, - f"No Country layer in WFS/GetCapabilities\n{response}") + f"No Country layer in WFS/GetCapabilities\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertTrue( str(response).find("Hello") != -1, - f"No Hello layer in WFS/GetCapabilities\n{response}") + f"No Hello layer in WFS/GetCapabilities\n{response}", + ) self.assertFalse( str(response).find("Hello_OnOff") != -1, - f"No Hello layer in WFS/GetCapabilities\n{response}") + f"No Hello layer in WFS/GetCapabilities\n{response}", + ) self.assertFalse( str(response).find("Country") != -1, - f"Unexpected Country layer in WFS/GetCapabilities\n{response}") + f"Unexpected Country layer in WFS/GetCapabilities\n{response}", + ) def test_wfs_describefeaturetype_hello(self): """Tests WFS DescribeFeatureType Request on 'Hello' with access control - The restricted access to 'Hello' is the expression `$id = 1` - The field 'color' has restricted access + The restricted access to 'Hello' is the expression `$id = 1` + The field 'color' has restricted access """ - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WFS", - "VERSION": "1.0.0", - "REQUEST": "DescribeFeatureType", - "TYPENAME": "Hello" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WFS", + "VERSION": "1.0.0", + "REQUEST": "DescribeFeatureType", + "TYPENAME": "Hello", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( str(response).find('name="Hello"') != -1, - f"No Hello layer in DescribeFeatureType\n{response}") + f"No Hello layer in DescribeFeatureType\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertTrue( str(response).find('name="Hello"') != -1, - f"No Hello layer in DescribeFeatureType\n{response}") + f"No Hello layer in DescribeFeatureType\n{response}", + ) def test_wfs_describefeaturetype_country(self): """Tests WFS DescribeFeatureType Request on 'Country' with access control - The layer 'Country'has restricted access + The layer 'Country'has restricted access """ - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WFS", - "VERSION": "1.0.0", - "REQUEST": "DescribeFeatureType", - "TYPENAME": "Country" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WFS", + "VERSION": "1.0.0", + "REQUEST": "DescribeFeatureType", + "TYPENAME": "Country", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( str(response).find('name="Country"') != -1, - f"No Country layer in DescribeFeatureType\n{response}") + f"No Country layer in DescribeFeatureType\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertFalse( str(response).find('name="Country"') != -1, - f"Unexpected Country layer in DescribeFeatureType\n{response}") + f"Unexpected Country layer in DescribeFeatureType\n{response}", + ) def test_wfs_getfeature_hello(self): """Tests WFS GetFeature Request on 'Hello' with access control - The restricted access to 'Hello' is the expression `$id = 1` - The field 'color' has restricted access + The restricted access to 'Hello' is the expression `$id = 1` + The field 'color' has restricted access """ data = """ - """.format(xml_ns=XML_NS) + """.format( + xml_ns=XML_NS + ) response, headers = self._post_fullaccess(data) # The feature with `pk = 1` is in the response with the field 'color' self.assertTrue( str(response).find("1") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) self.assertTrue( str(response).find("red") != -1, # spellok - f"No color in result of GetFeature\n{response}") + f"No color in result of GetFeature\n{response}", + ) # The feature with `pk = 2` is in the response (no filter, no access control) self.assertTrue( str(response).find("2") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) response, headers = self._post_restricted(data) # The feature with `pk = 1` is in the response without the field 'color' self.assertTrue( str(response).find("1") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) self.assertFalse( str(response).find("red") != -1, # spellok - f"Unexpected color in result of GetFeature\n{response}") + f"Unexpected color in result of GetFeature\n{response}", + ) self.assertFalse( str(response).find("NULL") != -1, # spellok - f"Unexpected color NULL in result of GetFeature\n{response}") + f"Unexpected color NULL in result of GetFeature\n{response}", + ) # The feature with `pk = 2` is not in the response: access control self.assertFalse( str(response).find("2") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) def test_wfs_getfeature_ogc_filter_hello(self): """Tests WFS GetFeature Request on 'Hello' with OGC Filter `pkuid = 1` and access control - The restricted access to 'Hello' is the expression `$id = 1` - The field 'color' has restricted access + The restricted access to 'Hello' is the expression `$id = 1` + The field 'color' has restricted access """ data = """ @@ -147,40 +188,49 @@ def test_wfs_getfeature_ogc_filter_hello(self): pkuid 1 - """.format(xml_ns=XML_NS) + """.format( + xml_ns=XML_NS + ) response, headers = self._post_fullaccess(data) # The feature with `pk = 1` is in the response with the field 'color' self.assertTrue( str(response).find("1") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) self.assertTrue( str(response).find("red") != -1, # spellok - f"No color in result of GetFeature\n{response}") + f"No color in result of GetFeature\n{response}", + ) # The feature with `pk = 2` is not in the response self.assertFalse( str(response).find("2") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) response, headers = self._post_restricted(data) # The feature with `pk = 1` is in the response without the field 'color' self.assertTrue( str(response).find("1") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) self.assertFalse( str(response).find("red") != -1, # spellok - f"Unexpected color in result of GetFeature\n{response}") + f"Unexpected color in result of GetFeature\n{response}", + ) self.assertFalse( str(response).find("NULL") != -1, # spellok - f"Unexpected color NULL in result of GetFeature\n{response}") + f"Unexpected color NULL in result of GetFeature\n{response}", + ) # The feature with `pk = 2` is still not in the response self.assertFalse( str(response).find("2") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) def test_wfs_getfeature_ogc_filter_hello2(self): """Tests WFS GetFeature Request on 'Hello' with OGC Filter `pkuid = 2` and access control - The restricted access to 'Hello' is the expression `$id = 1` + The restricted access to 'Hello' is the expression `$id = 1` """ data = """ @@ -188,68 +238,82 @@ def test_wfs_getfeature_ogc_filter_hello2(self): pkuid 2 - """.format(xml_ns=XML_NS) + """.format( + xml_ns=XML_NS + ) response, headers = self._post_fullaccess(data) # The feature with `pk = 2` is in the response self.assertTrue( str(response).find("2") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # The feature with `pk = 1` is not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) response, headers = self._post_restricted(data) # The feature with `pk = 2` is not in the response self.assertFalse( str(response).find("2") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 1` is still not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) def test_wfs_getfeature_hello_filter(self): """Tests WFS GetFeature Request on 'Hello_Filter' with access control - The restricted access to 'Hello_Filter is the expression `pkuid = 6 or pkuid = 7` + The restricted access to 'Hello_Filter is the expression `pkuid = 6 or pkuid = 7` """ data = """ - """.format(xml_ns=XML_NS) + """.format( + xml_ns=XML_NS + ) response, headers = self._post_fullaccess(data) # The feature with `pk = 1` is in the response (no filter, no access control) self.assertTrue( str(response).find("1") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # The feature with `pk = 6` is in the response (no filter, no access control) self.assertTrue( str(response).find("6") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 7` is in the response (no filter, no access control) self.assertTrue( str(response).find("7") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) response, headers = self._post_restricted(data) # The feature with `pk = 1` is not in the response: access control self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 6` is in the response: access control self.assertTrue( str(response).find("6") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 7` is in the response: access control self.assertTrue( str(response).find("7") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) def test_wfs_getfeature_ogc_filter_hello_filter(self): """Tests WFS GetFeature Request on 'Hello_Filter' with OGC Filter `pkuid = 1` and access control - The restricted access to 'Hello_Filter is the expression `pkuid = 6 or pkuid = 7` + The restricted access to 'Hello_Filter is the expression `pkuid = 6 or pkuid = 7` """ data = """ @@ -257,31 +321,37 @@ def test_wfs_getfeature_ogc_filter_hello_filter(self): pkuid 1 - """.format(xml_ns=XML_NS) + """.format( + xml_ns=XML_NS + ) response, headers = self._post_fullaccess(data) # The feature with `pk = 1` is in the response self.assertTrue( str(response).find("1") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # The feature with `pk = 6` is not in the response self.assertFalse( str(response).find("6") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) response, headers = self._post_restricted(data) # The feature with `pk = 1` is not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 6` is still not in the response self.assertFalse( str(response).find("6") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) def test_wfs_getfeature_ogc_filter_hello_filter2(self): """Tests WFS GetFeature Request on 'Hello_Filter' with OGC Filter `pkuid = 6` and access control - The restricted access to 'Hello_Filter is the expression `pkuid = 6 or pkuid = 7` + The restricted access to 'Hello_Filter is the expression `pkuid = 6 or pkuid = 7` """ data = """ @@ -289,68 +359,82 @@ def test_wfs_getfeature_ogc_filter_hello_filter2(self): pkuid 6 - """.format(xml_ns=XML_NS) + """.format( + xml_ns=XML_NS + ) response, headers = self._post_fullaccess(data) # The feature with `pk = 6` is in the response self.assertTrue( str(response).find("6") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # The feature with `pk = 7` is not in the response self.assertFalse( str(response).find("7") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) response, headers = self._post_restricted(data) # The feature with `pk = 6` is still in the response self.assertTrue( str(response).find("6") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # The feature with `pk = 7` is still not in the response self.assertFalse( str(response).find("7") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) def test_wfs_getfeature_hello_onoff(self): """Tests WFS GetFeature Request on 'Hello_OnOff' with access control - The restricted access to 'Hello_OnOff is cannot be read + The restricted access to 'Hello_OnOff is cannot be read """ data = """ - """.format(xml_ns=XML_NS) + """.format( + xml_ns=XML_NS + ) response, headers = self._post_fullaccess(data) # Some qgs feature Hello_OnOff element self.assertTrue( str(response).find("1") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # The feature with `pk = 6` is in the response self.assertTrue( str(response).find("6") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) response, headers = self._post_restricted(data) # The feature with `pk = 1` is not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 6` is not in the response self.assertFalse( str(response).find("6") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # No qgs feature Hello_OnOff element self.assertFalse( str(response).find(" @@ -358,35 +442,43 @@ def test_wfs_getfeature_ogc_filter_hello_onoff(self): pkuid 1 - """.format(xml_ns=XML_NS) + """.format( + xml_ns=XML_NS + ) response, headers = self._post_fullaccess(data) # Some qgs feature Hello_OnOff element self.assertTrue( str(response).find("1") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # The feature with `pk = 6` is not in the response self.assertFalse( str(response).find("6") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) response, headers = self._post_restricted(data) # The feature with `pk = 1` is not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 6` is still not in the response self.assertFalse( str(response).find("6") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # No qgs feature Hello_OnOff element self.assertFalse( str(response).find(" pkuid 1 - """.format(xml_ns=XML_NS) + """.format( + xml_ns=XML_NS + ) response, headers = self._post_fullaccess(data) self.assertTrue( - str(response).find("") != -1, - f"No result in GetFeature\n{response}") + str(response).find("") != -1, f"No result in GetFeature\n{response}" + ) self.assertTrue( str(response).find("1") != -1, - f"No good result in GetFeature\n{response}") + f"No good result in GetFeature\n{response}", + ) response, headers = self._post_restricted(data) self.assertTrue( - str(response).find("") != -1, - f"No result in GetFeature\n{response}") + str(response).find("") != -1, f"No result in GetFeature\n{response}" + ) self.assertTrue( str(response).find("1") != -1, - f"No good result in GetFeature\n{response}") + f"No good result in GetFeature\n{response}", + ) def test_wfs_getfeature_subsetstring2(self): data = """ @@ -422,25 +518,29 @@ def test_wfs_getfeature_subsetstring2(self): pkuid 2 - """.format(xml_ns=XML_NS) + """.format( + xml_ns=XML_NS + ) response, headers = self._post_fullaccess(data) self.assertTrue( - str(response).find("") != -1, - f"No result in GetFeature\n{response}") + str(response).find("") != -1, f"No result in GetFeature\n{response}" + ) self.assertTrue( str(response).find("2") != -1, - f"No good result in GetFeature\n{response}") + f"No good result in GetFeature\n{response}", + ) response, headers = self._post_restricted(data) self.assertFalse( str(response).find("") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) def test_wfs_getfeature_project_subsetstring(self): """Tests access control with a subset string already applied to a layer in a project - 'Hello_Project_SubsetString' layer has a subsetString of "pkuid in (7,8)" - This test checks for retrieving a feature which should be available in with/without access control + 'Hello_Project_SubsetString' layer has a subsetString of "pkuid in (7,8)" + This test checks for retrieving a feature which should be available in with/without access control """ data = """ @@ -448,29 +548,33 @@ def test_wfs_getfeature_project_subsetstring(self): pkuid 7 - """.format(xml_ns=XML_NS) + """.format( + xml_ns=XML_NS + ) # should be one result response, headers = self._post_fullaccess(data) self.assertTrue( - str(response).find("") != -1, - f"No result in GetFeature\n{response}") + str(response).find("") != -1, f"No result in GetFeature\n{response}" + ) self.assertTrue( str(response).find("7") != -1, - f"Feature with pkuid=7 not found in GetFeature\n{response}") + f"Feature with pkuid=7 not found in GetFeature\n{response}", + ) response, headers = self._post_restricted(data) self.assertTrue( - str(response).find("") != -1, - f"No result in GetFeature\n{response}") + str(response).find("") != -1, f"No result in GetFeature\n{response}" + ) self.assertTrue( str(response).find("7") != -1, - f"Feature with pkuid=7 not found in GetFeature, has been incorrectly filtered out by access controls\n{response}") + f"Feature with pkuid=7 not found in GetFeature, has been incorrectly filtered out by access controls\n{response}", + ) def test_wfs_getfeature_project_subsetstring2(self): """Tests access control with a subset string already applied to a layer in a project - 'Hello_Project_SubsetString' layer has a subsetString of "pkuid in (7,8)" - This test checks for a feature which should be filtered out by access controls + 'Hello_Project_SubsetString' layer has a subsetString of "pkuid in (7,8)" + This test checks for a feature which should be filtered out by access controls """ data = """ @@ -478,27 +582,31 @@ def test_wfs_getfeature_project_subsetstring2(self): pkuid 8 - """.format(xml_ns=XML_NS) + """.format( + xml_ns=XML_NS + ) # should be one result response, headers = self._post_fullaccess(data) self.assertTrue( - str(response).find("") != -1, - f"No result in GetFeature\n{response}") + str(response).find("") != -1, f"No result in GetFeature\n{response}" + ) self.assertTrue( str(response).find("8") != -1, - f"Feature with pkuid=8 not found in GetFeature\n{response}") + f"Feature with pkuid=8 not found in GetFeature\n{response}", + ) response, headers = self._post_restricted(data) self.assertFalse( str(response).find("") != -1, - f"Feature with pkuid=8 was found in GetFeature, but should have been filtered out by access controls\n{response}") + f"Feature with pkuid=8 was found in GetFeature, but should have been filtered out by access controls\n{response}", + ) def test_wfs_getfeature_project_subsetstring3(self): """Tests access control with a subset string already applied to a layer in a project - 'Hello_Project_SubsetString' layer has a subsetString of "pkuid in (7,8)" - This test checks for a features which should be filtered out by project subsetStrings. - For example, pkuid 6 passes the access control checks, but should not be shown because of project layer subsetString + 'Hello_Project_SubsetString' layer has a subsetString of "pkuid in (7,8)" + This test checks for a features which should be filtered out by project subsetStrings. + For example, pkuid 6 passes the access control checks, but should not be shown because of project layer subsetString """ data = """ @@ -506,525 +614,696 @@ def test_wfs_getfeature_project_subsetstring3(self): pkuid 6 - """.format(xml_ns=XML_NS) + """.format( + xml_ns=XML_NS + ) # should be no results, since pkuid 1 should be filtered out by project subsetString response, headers = self._post_fullaccess(data) self.assertTrue( str(response).find("") == -1, - f"Project based layer subsetString not respected in GetFeature\n{response}") + f"Project based layer subsetString not respected in GetFeature\n{response}", + ) response, headers = self._post_restricted(data) self.assertFalse( str(response).find("") != -1, - f"Project based layer subsetString not respected in GetFeature with restricted access\n{response}") + f"Project based layer subsetString not respected in GetFeature with restricted access\n{response}", + ) # # KVP request instead of XML request # # def test_wfs_getfeature_exp_filter_hello(self): """Tests WFS GetFeature Request on 'Hello' with Expression Filter `pkuid = 1` and access control - The restricted access to 'Hello' is the expression `$id = 1` - The field 'color' has restricted access + The restricted access to 'Hello' is the expression `$id = 1` + The field 'color' has restricted access """ - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WFS", - "VERSION": "1.0.0", - "REQUEST": "GetFeature", - "TYPENAME": "Hello", - "EXP_FILTER": "pkuid = 1" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WFS", + "VERSION": "1.0.0", + "REQUEST": "GetFeature", + "TYPENAME": "Hello", + "EXP_FILTER": "pkuid = 1", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) # The feature with `pk = 1` is in the response with the field 'color' self.assertTrue( str(response).find("1") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) self.assertTrue( str(response).find("red") != -1, # spellok - f"No color in result of GetFeature\n{response}") + f"No color in result of GetFeature\n{response}", + ) # The feature with `pk = 2` is not in the response self.assertFalse( str(response).find("2") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) response, headers = self._get_restricted(query_string) # The feature with `pk = 1` is in the response without the field 'color' self.assertTrue( str(response).find("1") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) self.assertFalse( str(response).find("red") != -1, # spellok - f"Unexpected color in result of GetFeature\n{response}") + f"Unexpected color in result of GetFeature\n{response}", + ) self.assertFalse( str(response).find("NULL") != -1, # spellok - f"Unexpected color NULL in result of GetFeature\n{response}") + f"Unexpected color NULL in result of GetFeature\n{response}", + ) # The feature with `pk = 2` is still not in the response self.assertFalse( str(response).find("2") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) def test_wfs_getfeature_exp_filter_hello2(self): """Tests WFS GetFeature Request on 'Hello' with Expression Filter `pkuid = 2` and access control - The restricted access to 'Hello' is the expression `$id = 1` + The restricted access to 'Hello' is the expression `$id = 1` """ - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WFS", - "VERSION": "1.0.0", - "REQUEST": "GetFeature", - "TYPENAME": "Hello", - "EXP_FILTER": "pkuid = 2" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WFS", + "VERSION": "1.0.0", + "REQUEST": "GetFeature", + "TYPENAME": "Hello", + "EXP_FILTER": "pkuid = 2", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) # The feature with `pk = 2` is in the response self.assertTrue( str(response).find("2") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # The feature with `pk = 1` is not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) response, headers = self._get_restricted(query_string) # The feature with `pk = 2` is not in the response self.assertFalse( str(response).find("2") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 1` is still not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # No qgs feature Hello element self.assertFalse( str(response).find("1") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # The feature with `pk = 6` is not in the response self.assertFalse( str(response).find("6") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 7` is not in the response self.assertFalse( str(response).find("7") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) response, headers = self._get_restricted(query_string) # The feature with `pk = 1` is not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 6` is still not in the response self.assertFalse( str(response).find("6") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 7` is still not in the response self.assertFalse( str(response).find("7") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # No qgs feature Hello_Filter element self.assertFalse( str(response).find("6") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # The feature with `pk = 1` is not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 7` is not in the response self.assertFalse( str(response).find("7") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertTrue( str(response).find("6") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # The feature with `pk = 1` is still not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 7` is not in the response self.assertFalse( str(response).find("7") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) def test_wfs_getfeature_featureid_hello(self): """Tests WFS GetFeature Request on 'Hello' with FeatureId `Hello.1` and access control - The restricted access to 'Hello' is the expression `$id = 1` - The field 'color' has restricted access + The restricted access to 'Hello' is the expression `$id = 1` + The field 'color' has restricted access """ - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WFS", - "VERSION": "1.0.0", - "REQUEST": "GetFeature", - "TYPENAME": "Hello", - "FEATUREID": "Hello.1" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WFS", + "VERSION": "1.0.0", + "REQUEST": "GetFeature", + "TYPENAME": "Hello", + "FEATUREID": "Hello.1", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) # The feature with `pk = 1` is in the response with the field 'color' self.assertTrue( str(response).find("1") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) self.assertTrue( str(response).find("red") != -1, # spellok - f"No color in result of GetFeature\n{response}") + f"No color in result of GetFeature\n{response}", + ) # The feature with `pk = 2` is not in the response self.assertFalse( str(response).find("2") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) response, headers = self._get_restricted(query_string) # The feature with `pk = 1` is in the response without the field 'color' self.assertTrue( str(response).find("1") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) self.assertFalse( str(response).find("red") != -1, # spellok - f"Unexpected color in result of GetFeature\n{response}") + f"Unexpected color in result of GetFeature\n{response}", + ) self.assertFalse( str(response).find("NULL") != -1, # spellok - f"Unexpected color NULL in result of GetFeature\n{response}") + f"Unexpected color NULL in result of GetFeature\n{response}", + ) # The feature with `pk = 2` is still not in the response self.assertFalse( str(response).find("2") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) def test_wfs_getfeature_featureid_hello2(self): """Tests WFS GetFeature Request on 'Hello' with FeatureId `Hello.2` and access control - The restricted access to 'Hello' is the expression `$id = 1` - The field 'color' has restricted access + The restricted access to 'Hello' is the expression `$id = 1` + The field 'color' has restricted access """ - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WFS", - "VERSION": "1.0.0", - "REQUEST": "GetFeature", - "TYPENAME": "Hello", - "FEATUREID": "Hello.2" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WFS", + "VERSION": "1.0.0", + "REQUEST": "GetFeature", + "TYPENAME": "Hello", + "FEATUREID": "Hello.2", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) # The feature with `pk = 2` is in the response self.assertTrue( str(response).find("2") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # The feature with `pk = 1` is not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) response, headers = self._get_restricted(query_string) # The feature with `pk = 2` is not in the response self.assertFalse( str(response).find("2") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 1` is still not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # No qgs feature Hello element self.assertFalse( str(response).find("1") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # The feature with `pk = 6` is not in the response self.assertFalse( str(response).find("6") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 7` is not in the response self.assertFalse( str(response).find("7") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) response, headers = self._get_restricted(query_string) # The feature with `pk = 1` is not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 6` is still not in the response self.assertFalse( str(response).find("6") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 7` is still not in the response self.assertFalse( str(response).find("7") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # No qgs feature Hello_Filter element self.assertFalse( str(response).find("6") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # The feature with `pk = 1` is not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 7` is not in the response self.assertFalse( str(response).find("7") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) response, headers = self._get_restricted(query_string) # The feature with `pk = 6` is in the response self.assertTrue( str(response).find("6") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # The feature with `pk = 1` is not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 7` is not in the response self.assertFalse( str(response).find("7") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # # ESRI Shapefile datasource # # def test_wfs_getfeature_shp_featureid_hello(self): """Tests WFS GetFeature Request on 'Hello' with FeatureId `Hello.1` and access control - The datasource is an ESRI Shapefile - The restricted access to 'Hello' is the expression `$id = 1` - The field 'color' has restricted access + The datasource is an ESRI Shapefile + The restricted access to 'Hello' is the expression `$id = 1` + The field 'color' has restricted access """ - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(os.path.join(self.tmp_path, 'project_shp.qgs')), - "SERVICE": "WFS", - "VERSION": "1.0.0", - "REQUEST": "GetFeature", - "TYPENAME": "Hello", - "FEATUREID": "Hello.1" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote( + os.path.join(self.tmp_path, "project_shp.qgs") + ), + "SERVICE": "WFS", + "VERSION": "1.0.0", + "REQUEST": "GetFeature", + "TYPENAME": "Hello", + "FEATUREID": "Hello.1", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) # The feature with `pk = 2` is in the response with the field 'color' self.assertTrue( str(response).find("2") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) self.assertTrue( str(response).find("blue") != -1, # spellok - f"No color in result of GetFeature\n{response}") + f"No color in result of GetFeature\n{response}", + ) # The feature with `pk = 1` is not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) response, headers = self._get_restricted(query_string) # The feature with `pk = 2` is in the response without the field 'color' self.assertTrue( str(response).find("2") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) self.assertFalse( str(response).find("blue") != -1, # spellok - f"Unexpected color in result of GetFeature\n{response}") + f"Unexpected color in result of GetFeature\n{response}", + ) self.assertFalse( str(response).find("NULL") != -1, # spellok - f"Unexpected color NULL in result of GetFeature\n{response}") + f"Unexpected color NULL in result of GetFeature\n{response}", + ) # The feature with `pk = 1` is still not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) def test_wfs_getfeature_shp_featureid_hello2(self): """Tests WFS GetFeature Request on 'Hello' with FeatureId `Hello.0` and access control - The datasource is an ESRI Shapefile - The restricted access to 'Hello' is the expression `$id = 1` - The field 'color' has restricted access + The datasource is an ESRI Shapefile + The restricted access to 'Hello' is the expression `$id = 1` + The field 'color' has restricted access """ - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(os.path.join(self.tmp_path, 'project_shp.qgs')), - "SERVICE": "WFS", - "VERSION": "1.0.0", - "REQUEST": "GetFeature", - "TYPENAME": "Hello", - "FEATUREID": "Hello.0" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote( + os.path.join(self.tmp_path, "project_shp.qgs") + ), + "SERVICE": "WFS", + "VERSION": "1.0.0", + "REQUEST": "GetFeature", + "TYPENAME": "Hello", + "FEATUREID": "Hello.0", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) # The feature with `pk = 1` is in the response self.assertTrue( str(response).find("1") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # The feature with `pk = 2` is not in the response self.assertFalse( str(response).find("2") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) response, headers = self._get_restricted(query_string) # The feature with `pk = 1` is not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 2` is still not in the response self.assertFalse( str(response).find("2") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # No qgs feature Hello_Filter element self.assertFalse( str(response).find("1") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # The feature with `pk = 6` is not in the response self.assertFalse( str(response).find("6") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 7` is not in the response self.assertFalse( str(response).find("7") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) response, headers = self._get_restricted(query_string) # The feature with `pk = 1` is not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 6` is still not in the response self.assertFalse( str(response).find("6") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 7` is still not in the response self.assertFalse( str(response).find("7") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # No qgs feature Hello_Filter element self.assertFalse( str(response).find("6") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # The feature with `pk = 1` is not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 7` is not in the response self.assertFalse( str(response).find("7") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) response, headers = self._get_restricted(query_string) # The feature with `pk = 6` is in the response self.assertTrue( str(response).find("6") != -1, - f"No result in GetFeature\n{response}") + f"No result in GetFeature\n{response}", + ) # The feature with `pk = 1` is not in the response self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) # The feature with `pk = 7` is not in the response self.assertFalse( str(response).find("7") != -1, - f"Unexpected result in GetFeature\n{response}") + f"Unexpected result in GetFeature\n{response}", + ) if __name__ == "__main__": diff --git a/tests/src/python/test_qgsserver_accesscontrol_wfs_transactional.py b/tests/src/python/test_qgsserver_accesscontrol_wfs_transactional.py index 6174ff589b2c..a01a1cca9bf6 100644 --- a/tests/src/python/test_qgsserver_accesscontrol_wfs_transactional.py +++ b/tests/src/python/test_qgsserver_accesscontrol_wfs_transactional.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Stephane Brunner' -__date__ = '28/08/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Stephane Brunner" +__date__ = "28/08/2015" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.testing import unittest @@ -58,46 +59,66 @@ class TestQgsServerAccessControlWFSTransactional(TestQgsServerAccessControl): @classmethod def project_file(cls): - return 'project_shp.qgs' + return "project_shp.qgs" def test_wfstransaction_insert(self): - data = WFS_TRANSACTION_INSERT.format(x=1, y=2, name="test", color="{color}", gid="{gid}", xml_ns=XML_NS) + data = WFS_TRANSACTION_INSERT.format( + x=1, y=2, name="test", color="{color}", gid="{gid}", xml_ns=XML_NS + ) self._test_colors({1: "blue"}) response, headers = self._post_fullaccess(data.format(color="red", gid=2)) self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for Insert is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for Insert is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find("") != -1, - f"WFS/Transactions Insert don't succeed\n{response}") + f"WFS/Transactions Insert don't succeed\n{response}", + ) self._test_colors({2: "red"}) response, headers = self._post_restricted(data.format(color="blue", gid=3)) self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for Insert is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for Insert is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find("") == -1, - f"WFS/Transactions Insert succeed\n{response}") + f"WFS/Transactions Insert succeed\n{response}", + ) - response, headers = self._post_restricted(data.format(color="red", gid=4), "LAYER_PERM=no") + response, headers = self._post_restricted( + data.format(color="red", gid=4), "LAYER_PERM=no" + ) self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for Insert is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for Insert is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find( - 'No permissions to do WFS changes on layer \\\'db_point\\\'') != -1, - f"WFS/Transactions Insert succeed\n{response}") + "No permissions to do WFS changes on layer \\'db_point\\'" + ) + != -1, + f"WFS/Transactions Insert succeed\n{response}", + ) - response, headers = self._post_restricted(data.format(color="yellow", gid=5), "LAYER_PERM=yes") + response, headers = self._post_restricted( + data.format(color="yellow", gid=5), "LAYER_PERM=yes" + ) self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for Insert is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for Insert is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find("") != -1, - f"WFS/Transactions Insert don't succeed\n{response}") + f"WFS/Transactions Insert don't succeed\n{response}", + ) self._test_colors({5: "yellow"}) def test_wfstransaction_update(self): @@ -106,48 +127,69 @@ def test_wfstransaction_update(self): response, headers = self._post_restricted(data.format(color="yellow")) self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for GetMap is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for GetMap is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find("") == -1, - f"WFS/Transactions Update succeed\n{response}") + f"WFS/Transactions Update succeed\n{response}", + ) self._test_colors({1: "blue"}) response, headers = self._post_fullaccess(data.format(color="red")) self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for Update is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for Update is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find("") != -1, - f"WFS/Transactions Update don't succeed\n{response}") + f"WFS/Transactions Update don't succeed\n{response}", + ) self._test_colors({1: "red"}) response, headers = self._post_restricted(data.format(color="blue")) self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for Update is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for Update is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find("") == -1, - f"WFS/Transactions Update succeed\n{response}") + f"WFS/Transactions Update succeed\n{response}", + ) self._test_colors({1: "red"}) - response, headers = self._post_restricted(data.format(color="yellow"), "LAYER_PERM=no") + response, headers = self._post_restricted( + data.format(color="yellow"), "LAYER_PERM=no" + ) self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for Update is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for Update is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find( - 'No permissions to do WFS changes on layer \\\'db_point\\\'') != -1, - f"WFS/Transactions Update succeed\n{response}") + "No permissions to do WFS changes on layer \\'db_point\\'" + ) + != -1, + f"WFS/Transactions Update succeed\n{response}", + ) self._test_colors({1: "red"}) - response, headers = self._post_restricted(data.format(color="yellow"), "LAYER_PERM=yes") + response, headers = self._post_restricted( + data.format(color="yellow"), "LAYER_PERM=yes" + ) self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for Update is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for Update is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find("") != -1, - f"WFS/Transactions Update don't succeed\n{response}") + f"WFS/Transactions Update don't succeed\n{response}", + ) self._test_colors({1: "yellow"}) def test_wfstransaction_delete_fullaccess(self): @@ -156,11 +198,14 @@ def test_wfstransaction_delete_fullaccess(self): response, headers = self._post_fullaccess(data) self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for GetMap is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for GetMap is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find("") != -1, - f"WFS/Transactions Delete didn't succeed\n{response}") + f"WFS/Transactions Delete didn't succeed\n{response}", + ) def test_wfstransaction_delete_restricted(self): data = WFS_TRANSACTION_DELETE.format(id="0", xml_ns=XML_NS) @@ -168,11 +213,14 @@ def test_wfstransaction_delete_restricted(self): response, headers = self._post_restricted(data) self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for GetMap is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for GetMap is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find("") == -1, - f"WFS/Transactions Delete succeed\n{response}") + f"WFS/Transactions Delete succeed\n{response}", + ) data_update = WFS_TRANSACTION_UPDATE.format(id="0", color="red", xml_ns=XML_NS) response, headers = self._post_fullaccess(data_update) @@ -180,20 +228,28 @@ def test_wfstransaction_delete_restricted(self): response, headers = self._post_restricted(data, "LAYER_PERM=no") self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for GetMap is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for GetMap is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find( - 'No permissions to do WFS changes on layer \\\'db_point\\\'') != -1, - f"WFS/Transactions Delete succeed\n{response}") + "No permissions to do WFS changes on layer \\'db_point\\'" + ) + != -1, + f"WFS/Transactions Delete succeed\n{response}", + ) response, headers = self._post_restricted(data, "LAYER_PERM=yes") self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for GetMap is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for GetMap is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find("") != -1, - f"WFS/Transactions Delete don't succeed\n{response}") + f"WFS/Transactions Delete don't succeed\n{response}", + ) if __name__ == "__main__": diff --git a/tests/src/python/test_qgsserver_accesscontrol_wms.py b/tests/src/python/test_qgsserver_accesscontrol_wms.py index 55c45896be8c..321e488fbe69 100644 --- a/tests/src/python/test_qgsserver_accesscontrol_wms.py +++ b/tests/src/python/test_qgsserver_accesscontrol_wms.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Stephane Brunner' -__date__ = '28/08/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Stephane Brunner" +__date__ = "28/08/2015" +__copyright__ = "Copyright 2015, The QGIS Project" import json import os @@ -33,909 +34,1225 @@ class TestQgsServerAccessControlWMS(TestQgsServerAccessControl): """QGIS Server Access Control WMS Tests""" def test_wms_getcapabilities(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetCapabilities" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetCapabilities", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( str(response).find("Hello") != -1, - f"No Hello layer in GetCapabilities\n{response}") + f"No Hello layer in GetCapabilities\n{response}", + ) self.assertTrue( str(response).find("Country_grp") != -1, - f"Unexpected Country_grp layer in GetCapabilities\n{response}") + f"Unexpected Country_grp layer in GetCapabilities\n{response}", + ) self.assertTrue( str(response).find("Country") != -1, - f"No Country layer in GetCapabilities\n{response}") + f"No Country layer in GetCapabilities\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertTrue( str(response).find("Hello") != -1, - f"No Hello layer in GetCapabilities\n{response}") + f"No Hello layer in GetCapabilities\n{response}", + ) self.assertFalse( str(response).find("Country_grp") != -1, - f"Unexpected Country_grp layer in GetCapabilities\n{response}") + f"Unexpected Country_grp layer in GetCapabilities\n{response}", + ) self.assertFalse( str(response).find("Country") != -1, - f"Unexpected Country layer in GetCapabilities\n{response}") + f"Unexpected Country layer in GetCapabilities\n{response}", + ) def test_wms_getprojectsettings(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetProjectSettings" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetProjectSettings", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( str(response).find("Hello") != -1, - f"No Hello layer in GetProjectSettings\n{response}") + f"No Hello layer in GetProjectSettings\n{response}", + ) self.assertTrue( str(response).find("Country") != -1, - f"No Country layer in GetProjectSettings\n{response}") + f"No Country layer in GetProjectSettings\n{response}", + ) self.assertTrue( str(response).find("Country_grp") != -1, - f"No Country_grp layer in GetProjectSettings\n{response}") + f"No Country_grp layer in GetProjectSettings\n{response}", + ) self.assertTrue( str(response).find( - "Country_Diagrams,Country_Labels,Country,dem,Hello_Filter_SubsetString,Hello_Project_SubsetString,Hello_SubsetString,Hello_Filter,Hello_OnOff,Hello,db_point") != -1, - f"LayerDrawingOrder in GetProjectSettings\n{response}") + "Country_Diagrams,Country_Labels,Country,dem,Hello_Filter_SubsetString,Hello_Project_SubsetString,Hello_SubsetString,Hello_Filter,Hello_OnOff,Hello,db_point" + ) + != -1, + f"LayerDrawingOrder in GetProjectSettings\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertTrue( str(response).find("Hello") != -1, - f"No Hello layer in GetProjectSettings\n{response}") + f"No Hello layer in GetProjectSettings\n{response}", + ) self.assertFalse( str(response).find("Country") != -1, - f"Unexpected Country layer in GetProjectSettings\n{response}") + f"Unexpected Country layer in GetProjectSettings\n{response}", + ) self.assertFalse( str(response).find("Country_grp") != -1, - f"Unexpected Country_grp layer in GetProjectSettings\n{response}") + f"Unexpected Country_grp layer in GetProjectSettings\n{response}", + ) self.assertTrue( str(response).find( - "Country_Diagrams,Country_Labels,dem,Hello_Filter_SubsetString,Hello_Project_SubsetString,Hello_SubsetString,Hello_Filter,Hello,db_point") != -1, - f"Wrong LayerDrawingOrder in GetProjectSettings\n{response}") + "Country_Diagrams,Country_Labels,dem,Hello_Filter_SubsetString,Hello_Project_SubsetString,Hello_SubsetString,Hello_Filter,Hello,db_point" + ) + != -1, + f"Wrong LayerDrawingOrder in GetProjectSettings\n{response}", + ) def test_wms_getcontext(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetContext" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetContext", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( - str(response).find("name=\"Hello\"") != -1, - f"No Hello layer in GetContext\n{response}") + str(response).find('name="Hello"') != -1, + f"No Hello layer in GetContext\n{response}", + ) self.assertTrue( - str(response).find("name=\"Country\"") != -1, - f"No Country layer in GetProjectSettings\n{response}") + str(response).find('name="Country"') != -1, + f"No Country layer in GetProjectSettings\n{response}", + ) self.assertTrue( - str(response).find("name=\"Country\"") - < str(response).find("name=\"Hello\""), - f"Hello layer not after Country layer\n{response}") + str(response).find('name="Country"') < str(response).find('name="Hello"'), + f"Hello layer not after Country layer\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertTrue( - str(response).find("name=\"Hello\"") != -1, - f"No Hello layer in GetContext\n{response}") + str(response).find('name="Hello"') != -1, + f"No Hello layer in GetContext\n{response}", + ) self.assertFalse( - str(response).find("name=\"Country\"") != -1, - f"Unexpected Country layer in GetProjectSettings\n{response}") + str(response).find('name="Country"') != -1, + f"Unexpected Country layer in GetProjectSettings\n{response}", + ) def test_wms_describelayer_hello(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "DescribeLayer", - "LAYERS": "Hello", - "SLD_VERSION": "1.1.0" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "DescribeLayer", + "LAYERS": "Hello", + "SLD_VERSION": "1.1.0", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( str(response).find("Hello") != -1, - f"No Hello layer in DescribeLayer\n{response}") + f"No Hello layer in DescribeLayer\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertTrue( str(response).find("Hello") != -1, - f"No Hello layer in DescribeLayer\n{response}") + f"No Hello layer in DescribeLayer\n{response}", + ) def test_wms_describelayer_country(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "DescribeLayer", - "LAYERS": "Country", - "SLD_VERSION": "1.1.0" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "DescribeLayer", + "LAYERS": "Country", + "SLD_VERSION": "1.1.0", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( - str(response).find("Country") != -1, - f"No Country layer in DescribeLayer\n{response}") + str(response).find("Country") + != -1, + f"No Country layer in DescribeLayer\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertFalse( - str(response).find("Country") != -1, - f"Unexpected Country layer in DescribeLayer\n{response}") + str(response).find("Country") + != -1, + f"Unexpected Country layer in DescribeLayer\n{response}", + ) def test_wms_getmap(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self._img_diff_error(response, headers, "WMS_GetMap") - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + }.items() + ) + ] + ) response, headers = self._get_restricted(query_string) self._img_diff_error(response, headers, "Restricted_WMS_GetMap") - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + }.items() + ) + ] + ) response, headers = self._get_restricted(query_string) self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for GetMap is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for GetMap is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find('') != -1, - "Not allowed do a GetMap on Country" + "Not allowed do a GetMap on Country", ) def test_wms_getmap_grp(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country_grp,Hello_grp", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country_grp,Hello_grp", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self._img_diff_error(response, headers, "WMS_GetMap") - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Hello_grp", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Hello_grp", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + }.items() + ) + ] + ) response, headers = self._get_restricted(query_string) self._img_diff_error(response, headers, "Restricted_WMS_GetMap") - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country_grp", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country_grp", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + }.items() + ) + ] + ) response, headers = self._get_restricted(query_string) self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for GetMap is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for GetMap is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find('') != -1, - "Not allowed do a GetMap on Country_grp" + "Not allowed do a GetMap on Country_grp", ) # Check group ACL. # The whole group should not fail since it contains # allowed layers. - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "project_grp", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "project_grp", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + }.items() + ) + ] + ) response, headers = self._get_restricted(query_string) self.assertEqual( - headers.get("Content-Type"), "image/png", - f"Content type for GetMap is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "image/png", + f"Content type for GetMap is wrong: {headers.get('Content-Type')}", + ) def test_wms_getfeatureinfo_hello(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetFeatureInfo", - "LAYERS": "Country,Hello", - "QUERY_LAYERS": "Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "FEATURE_COUNT": "10", - "INFO_FORMAT": "application/vnd.ogc.gml", - "X": "56", - "Y": "144" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetFeatureInfo", + "LAYERS": "Country,Hello", + "QUERY_LAYERS": "Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "FEATURE_COUNT": "10", + "INFO_FORMAT": "application/vnd.ogc.gml", + "X": "56", + "Y": "144", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( str(response).find("1") != -1, - f"No result in GetFeatureInfo\n{response}") + f"No result in GetFeatureInfo\n{response}", + ) self.assertTrue( str(response).find("red") != -1, # spellok - f"No color in result of GetFeatureInfo\n{response}") + f"No color in result of GetFeatureInfo\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for GetFeatureInfo is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for GetFeatureInfo is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find('') != -1, - "Not allowed do a GetFeatureInfo on Country" - ) - - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetFeatureInfo", - "LAYERS": "Hello", - "QUERY_LAYERS": "Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "FEATURE_COUNT": "10", - "INFO_FORMAT": "application/vnd.ogc.gml", - "X": "56", - "Y": "144" - }.items())]) + "Not allowed do a GetFeatureInfo on Country", + ) + + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetFeatureInfo", + "LAYERS": "Hello", + "QUERY_LAYERS": "Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "FEATURE_COUNT": "10", + "INFO_FORMAT": "application/vnd.ogc.gml", + "X": "56", + "Y": "144", + }.items() + ) + ] + ) response, headers = self._get_restricted(query_string) self.assertTrue( str(response).find("1") != -1, - f"No result in GetFeatureInfo\n{response}") + f"No result in GetFeatureInfo\n{response}", + ) self.assertFalse( str(response).find("red") != -1, # spellok - f"Unexpected color in result of GetFeatureInfo\n{response}") + f"Unexpected color in result of GetFeatureInfo\n{response}", + ) self.assertFalse( str(response).find("NULL") != -1, # spellok - f"Unexpected color NULL in result of GetFeatureInfo\n{response}") + f"Unexpected color NULL in result of GetFeatureInfo\n{response}", + ) def test_wms_getfeatureinfo_hello_grp(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetFeatureInfo", - "LAYERS": "Country_grp,Hello_grp", - "QUERY_LAYERS": "Hello_grp", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "FEATURE_COUNT": "10", - "INFO_FORMAT": "application/vnd.ogc.gml", - "X": "56", - "Y": "144" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetFeatureInfo", + "LAYERS": "Country_grp,Hello_grp", + "QUERY_LAYERS": "Hello_grp", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "FEATURE_COUNT": "10", + "INFO_FORMAT": "application/vnd.ogc.gml", + "X": "56", + "Y": "144", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertFalse( - str(response).find("Layer \'Hello_grp\' is not queryable") != -1, - f"The WMS layer group are queryable GetFeatureInfo\n{response}") + str(response).find("Layer 'Hello_grp' is not queryable") != -1, + f"The WMS layer group are queryable GetFeatureInfo\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertFalse( - str(response).find("Layer \'Hello_grp\' is not queryable") != -1, - f"The WMS layer group are queryable GetFeatureInfo\n{response}") + str(response).find("Layer 'Hello_grp' is not queryable") != -1, + f"The WMS layer group are queryable GetFeatureInfo\n{response}", + ) def test_wms_getfeatureinfo_hello2(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetFeatureInfo", - "LAYERS": "Country,Hello", - "QUERY_LAYERS": "Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "FEATURE_COUNT": "10", - "INFO_FORMAT": "application/vnd.ogc.gml", - "X": "146", - "Y": "160" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetFeatureInfo", + "LAYERS": "Country,Hello", + "QUERY_LAYERS": "Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "FEATURE_COUNT": "10", + "INFO_FORMAT": "application/vnd.ogc.gml", + "X": "146", + "Y": "160", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( str(response).find("2") != -1, - f"No result in GetFeatureInfo\n{response}") + f"No result in GetFeatureInfo\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertFalse( str(response).find("2") != -1, - f"Unexpected result in GetFeatureInfo\n{response}") + f"Unexpected result in GetFeatureInfo\n{response}", + ) def test_wms_getfeatureinfo_country(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetFeatureInfo", - "LAYERS": "Country,Hello", - "QUERY_LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "FEATURE_COUNT": "10", - "INFO_FORMAT": "application/vnd.ogc.gml", - "X": "56", - "Y": "144" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetFeatureInfo", + "LAYERS": "Country,Hello", + "QUERY_LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "FEATURE_COUNT": "10", + "INFO_FORMAT": "application/vnd.ogc.gml", + "X": "56", + "Y": "144", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( str(response).find("1") != -1, - f"No result in GetFeatureInfo\n{response}") + f"No result in GetFeatureInfo\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeatureInfo\n{response}") + f"Unexpected result in GetFeatureInfo\n{response}", + ) def test_wms_getfeatureinfo_country_grp(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetFeatureInfo", - "LAYERS": "Country_grp,Hello", - "QUERY_LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "FEATURE_COUNT": "10", - "INFO_FORMAT": "application/vnd.ogc.gml", - "X": "56", - "Y": "144" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetFeatureInfo", + "LAYERS": "Country_grp,Hello", + "QUERY_LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "FEATURE_COUNT": "10", + "INFO_FORMAT": "application/vnd.ogc.gml", + "X": "56", + "Y": "144", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( str(response).find("1") != -1, - f"No result in GetFeatureInfo\n{response}") + f"No result in GetFeatureInfo\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertFalse( str(response).find("1") != -1, - f"Unexpected result in GetFeatureInfo\n{response}") + f"Unexpected result in GetFeatureInfo\n{response}", + ) # # Subset String # # def test_wms_getmap_subsetstring(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello_SubsetString", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello_SubsetString", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self._img_diff_error(response, headers, "WMS_GetMap") - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Hello_SubsetString", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Hello_SubsetString", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + }.items() + ) + ] + ) response, headers = self._get_restricted(query_string) self._img_diff_error(response, headers, "Restricted_WMS_GetMap") def test_wms_getmap_subsetstring_with_filter(self): - """ test that request filter and access control subsetStrings are correctly combined. Note that for this + """test that request filter and access control subsetStrings are correctly combined. Note that for this test we reuse the projectsubsetstring reference images as we are using filter requests to set the same filter " pkuid in (7,8) " as the project subsetstring uses for its test. """ - query_string = "&".join(["%s=%s" % i for i in { - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Hello_Filter_SubsetString", - "FILTER": "Hello_Filter_SubsetString:\"pkuid\" IN ( 7 , 8 )", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857" - }.items()]) + query_string = "&".join( + [ + "%s=%s" % i + for i in { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Hello_Filter_SubsetString", + "FILTER": 'Hello_Filter_SubsetString:"pkuid" IN ( 7 , 8 )', + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + }.items() + ] + ) response, headers = self._get_fullaccess(query_string) self._img_diff_error(response, headers, "WMS_GetMap_projectsubstring") - query_string = "&".join(["%s=%s" % i for i in { - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Hello_Filter_SubsetString", - "FILTER": "Hello_Filter_SubsetString:\"pkuid\" IN ( 7 , 8 )", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857" - }.items()]) + query_string = "&".join( + [ + "%s=%s" % i + for i in { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Hello_Filter_SubsetString", + "FILTER": 'Hello_Filter_SubsetString:"pkuid" IN ( 7 , 8 )', + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + }.items() + ] + ) response, headers = self._get_restricted(query_string) - self._img_diff_error(response, headers, "Restricted_WMS_GetMap_projectsubstring") - - filter = "pkuid7" \ - "pkuid8" \ - "" - query_string = "&".join(["%s=%s" % i for i in { - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Hello_Filter_SubsetString", - "FILTER": filter, - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857" - }.items()]) + self._img_diff_error( + response, headers, "Restricted_WMS_GetMap_projectsubstring" + ) + + filter = ( + "pkuid7" + "pkuid8" + "" + ) + query_string = "&".join( + [ + "%s=%s" % i + for i in { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Hello_Filter_SubsetString", + "FILTER": filter, + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + }.items() + ] + ) response, headers = self._get_restricted(query_string) - self._img_diff_error(response, headers, "Restricted_WMS_GetMap_projectsubstring_OGC") + self._img_diff_error( + response, headers, "Restricted_WMS_GetMap_projectsubstring_OGC" + ) def test_wms_getmap_projectsubsetstring(self): - """ test that project set layer subsetStrings are honored""" - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Hello_Project_SubsetString", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857" - }.items())]) + """test that project set layer subsetStrings are honored""" + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Hello_Project_SubsetString", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self._img_diff_error(response, headers, "WMS_GetMap_projectsubstring") - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Hello_Project_SubsetString", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Hello_Project_SubsetString", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + }.items() + ) + ] + ) response, headers = self._get_restricted(query_string) - self._img_diff_error(response, headers, "Restricted_WMS_GetMap_projectsubstring") + self._img_diff_error( + response, headers, "Restricted_WMS_GetMap_projectsubstring" + ) def test_wms_getfeatureinfo_subsetstring(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetFeatureInfo", - "LAYERS": "Country,Hello_SubsetString", - "QUERY_LAYERS": "Hello_SubsetString", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "FEATURE_COUNT": "10", - "INFO_FORMAT": "application/vnd.ogc.gml", - "X": "56", - "Y": "144", - "MAP": urllib.parse.quote(self.projectPath) - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetFeatureInfo", + "LAYERS": "Country,Hello_SubsetString", + "QUERY_LAYERS": "Hello_SubsetString", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "FEATURE_COUNT": "10", + "INFO_FORMAT": "application/vnd.ogc.gml", + "X": "56", + "Y": "144", + "MAP": urllib.parse.quote(self.projectPath), + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( str(response).find("") != -1, - f"No result in GetFeatureInfo Hello/1\n{response}") + f"No result in GetFeatureInfo Hello/1\n{response}", + ) self.assertTrue( str(response).find("1") != -1, - f"No good result in GetFeatureInfo Hello/1\n{response}") + f"No good result in GetFeatureInfo Hello/1\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for GetFeatureInfo is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for GetFeatureInfo is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find('') != -1, - "Not allowed do a GetFeatureInfo on Country" - ) - - query_string = "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetFeatureInfo", - "LAYERS": "Hello_SubsetString", - "QUERY_LAYERS": "Hello_SubsetString", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "FEATURE_COUNT": "10", - "INFO_FORMAT": "application/vnd.ogc.gml", - "X": "56", - "Y": "144", - "MAP": urllib.parse.quote(self.projectPath) - }.items())]) + "Not allowed do a GetFeatureInfo on Country", + ) + + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetFeatureInfo", + "LAYERS": "Hello_SubsetString", + "QUERY_LAYERS": "Hello_SubsetString", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "FEATURE_COUNT": "10", + "INFO_FORMAT": "application/vnd.ogc.gml", + "X": "56", + "Y": "144", + "MAP": urllib.parse.quote(self.projectPath), + }.items() + ) + ] + ) response, headers = self._get_restricted(query_string) self.assertTrue( str(response).find("") != -1, - f"No result in GetFeatureInfo Hello/1\n{response}") + f"No result in GetFeatureInfo Hello/1\n{response}", + ) self.assertTrue( str(response).find("1") != -1, - f"No good result in GetFeatureInfo Hello/1\n{response}") + f"No good result in GetFeatureInfo Hello/1\n{response}", + ) def test_wms_getfeatureinfo_subsetstring2(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetFeatureInfo", - "LAYERS": "Country,Hello_SubsetString", - "QUERY_LAYERS": "Hello_SubsetString", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "FEATURE_COUNT": "10", - "INFO_FORMAT": "application/vnd.ogc.gml", - "X": "146", - "Y": "160", - "MAP": urllib.parse.quote(self.projectPath) - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetFeatureInfo", + "LAYERS": "Country,Hello_SubsetString", + "QUERY_LAYERS": "Hello_SubsetString", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "FEATURE_COUNT": "10", + "INFO_FORMAT": "application/vnd.ogc.gml", + "X": "146", + "Y": "160", + "MAP": urllib.parse.quote(self.projectPath), + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( str(response).find("") != -1, - f"No result result in GetFeatureInfo Hello/2\n{response}") + f"No result result in GetFeatureInfo Hello/2\n{response}", + ) self.assertTrue( str(response).find("2") != -1, - f"No good result result in GetFeatureInfo Hello/2\n{response}") + f"No good result result in GetFeatureInfo Hello/2\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertFalse( str(response).find("") != -1, - f"Unexpected result result in GetFeatureInfo Hello/2\n{response}") + f"Unexpected result result in GetFeatureInfo Hello/2\n{response}", + ) def test_wms_getfeatureinfo_projectsubsetstring(self): """test that layer subsetStrings set in projects are honored. This test checks for a feature which should be filtered out by the project set layer subsetString """ - query_string = "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetFeatureInfo", - "LAYERS": "Hello_Project_SubsetString", - "QUERY_LAYERS": "Hello_Project_SubsetString", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "FEATURE_COUNT": "10", - "INFO_FORMAT": "application/vnd.ogc.gml", - "X": "56", - "Y": "144", - "MAP": urllib.parse.quote(self.projectPath) - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetFeatureInfo", + "LAYERS": "Hello_Project_SubsetString", + "QUERY_LAYERS": "Hello_Project_SubsetString", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "FEATURE_COUNT": "10", + "INFO_FORMAT": "application/vnd.ogc.gml", + "X": "56", + "Y": "144", + "MAP": urllib.parse.quote(self.projectPath), + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertFalse( str(response).find("") != -1, - f"Project set layer subsetString not honored in WMS GetFeatureInfo/1\n{response}") + f"Project set layer subsetString not honored in WMS GetFeatureInfo/1\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertFalse( str(response).find("") != -1, - f"Project set layer subsetString not honored in WMS GetFeatureInfo when access control applied/1\n{response}") + f"Project set layer subsetString not honored in WMS GetFeatureInfo when access control applied/1\n{response}", + ) def test_wms_getfeatureinfo_projectsubsetstring5(self): """test that layer subsetStrings set in projects are honored. This test checks for a feature which should pass both project set layer subsetString and access control filters """ - query_string = "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetFeatureInfo", - "LAYERS": "Hello_Project_SubsetString", - "QUERY_LAYERS": "Hello_Project_SubsetString", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-1623412,3146330,-1603412,3166330", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "FEATURE_COUNT": "10", - "INFO_FORMAT": "application/vnd.ogc.gml", - "X": "146", - "Y": "160", - "MAP": urllib.parse.quote(self.projectPath) - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetFeatureInfo", + "LAYERS": "Hello_Project_SubsetString", + "QUERY_LAYERS": "Hello_Project_SubsetString", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-1623412,3146330,-1603412,3166330", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "FEATURE_COUNT": "10", + "INFO_FORMAT": "application/vnd.ogc.gml", + "X": "146", + "Y": "160", + "MAP": urllib.parse.quote(self.projectPath), + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( str(response).find("") != -1, - f"No result result in GetFeatureInfo Hello/2\n{response}") + f"No result result in GetFeatureInfo Hello/2\n{response}", + ) self.assertTrue( str(response).find("7") != -1, - f"No good result result in GetFeatureInfo Hello/2\n{response}") + f"No good result result in GetFeatureInfo Hello/2\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertTrue( str(response).find("") != -1, - f"No result result in GetFeatureInfo Hello/2\n{response}") + f"No result result in GetFeatureInfo Hello/2\n{response}", + ) self.assertTrue( str(response).find("7") != -1, - f"No good result result in GetFeatureInfo Hello/2\n{response}") + f"No good result result in GetFeatureInfo Hello/2\n{response}", + ) def test_wms_getfeatureinfo_projectsubsetstring3(self): """test that layer subsetStrings set in projects are honored. This test checks for a feature which should pass the project set layer subsetString but fail the access control checks """ - query_string = "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetFeatureInfo", - "LAYERS": "Hello_Project_SubsetString", - "QUERY_LAYERS": "Hello_Project_SubsetString", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "3415650,2018968,3415750,2019968", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "FEATURE_COUNT": "10", - "INFO_FORMAT": "application/vnd.ogc.gml", - "X": "146", - "Y": "160", - "MAP": urllib.parse.quote(self.projectPath) - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetFeatureInfo", + "LAYERS": "Hello_Project_SubsetString", + "QUERY_LAYERS": "Hello_Project_SubsetString", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "3415650,2018968,3415750,2019968", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "FEATURE_COUNT": "10", + "INFO_FORMAT": "application/vnd.ogc.gml", + "X": "146", + "Y": "160", + "MAP": urllib.parse.quote(self.projectPath), + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( str(response).find("") != -1, - f"No result result in GetFeatureInfo Hello/2\n{response}") + f"No result result in GetFeatureInfo Hello/2\n{response}", + ) self.assertTrue( str(response).find("8") != -1, - f"No good result result in GetFeatureInfo Hello/2\n{response}") + f"No good result result in GetFeatureInfo Hello/2\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertFalse( str(response).find("") != -1, - f"Unexpected result from GetFeatureInfo Hello/2\n{response}") + f"Unexpected result from GetFeatureInfo Hello/2\n{response}", + ) def test_wms_getfeatureinfo_subsetstring_with_filter(self): """test that request filters are honored. This test checks for a feature which should be filtered out by the request filter """ - query_string = "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetFeatureInfo", - "LAYERS": "Hello_Filter_SubsetString", - "QUERY_LAYERS": "Hello_Filter_SubsetString", - "FILTER": "Hello_Filter_SubsetString:\"pkuid\" IN ( 7 , 8 )", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "FEATURE_COUNT": "10", - "INFO_FORMAT": "application/vnd.ogc.gml", - "X": "56", - "Y": "144", - "MAP": urllib.parse.quote(self.projectPath) - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetFeatureInfo", + "LAYERS": "Hello_Filter_SubsetString", + "QUERY_LAYERS": "Hello_Filter_SubsetString", + "FILTER": 'Hello_Filter_SubsetString:"pkuid" IN ( 7 , 8 )', + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "FEATURE_COUNT": "10", + "INFO_FORMAT": "application/vnd.ogc.gml", + "X": "56", + "Y": "144", + "MAP": urllib.parse.quote(self.projectPath), + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertFalse( str(response).find("") != -1, - f"Request filter not honored in WMS GetFeatureInfo/1\n{response}") + f"Request filter not honored in WMS GetFeatureInfo/1\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertFalse( str(response).find("") != -1, - f"Request filter not honored in WMS GetFeatureInfo when access control applied/1\n{response}") + f"Request filter not honored in WMS GetFeatureInfo when access control applied/1\n{response}", + ) def test_wms_getfeatureinfo_projectsubsetstring4(self): """test that request filters are honored. This test checks for a feature which should pass both request filter and access control filters """ - query_string = "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetFeatureInfo", - "LAYERS": "Hello_Filter_SubsetString", - "QUERY_LAYERS": "Hello_Filter_SubsetString", - "FILTER": "Hello_Filter_SubsetString:\"pkuid\" IN ( 7 , 8 )", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-1623412,3146330,-1603412,3166330", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "FEATURE_COUNT": "10", - "INFO_FORMAT": "application/vnd.ogc.gml", - "X": "146", - "Y": "160", - "MAP": urllib.parse.quote(self.projectPath) - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetFeatureInfo", + "LAYERS": "Hello_Filter_SubsetString", + "QUERY_LAYERS": "Hello_Filter_SubsetString", + "FILTER": 'Hello_Filter_SubsetString:"pkuid" IN ( 7 , 8 )', + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-1623412,3146330,-1603412,3166330", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "FEATURE_COUNT": "10", + "INFO_FORMAT": "application/vnd.ogc.gml", + "X": "146", + "Y": "160", + "MAP": urllib.parse.quote(self.projectPath), + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( str(response).find("") != -1, - f"No result result in GetFeatureInfo Hello/2\n{response}") + f"No result result in GetFeatureInfo Hello/2\n{response}", + ) self.assertTrue( str(response).find("7") != -1, - f"No good result result in GetFeatureInfo Hello/2\n{response}") + f"No good result result in GetFeatureInfo Hello/2\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertTrue( str(response).find("") != -1, - f"No result result in GetFeatureInfo Hello/2\n{response}") + f"No result result in GetFeatureInfo Hello/2\n{response}", + ) self.assertTrue( str(response).find("7") != -1, - f"No good result result in GetFeatureInfo Hello/2\n{response}") + f"No good result result in GetFeatureInfo Hello/2\n{response}", + ) def test_wms_getfeatureinfo_projectsubsetstring2(self): """test that request filters are honored. This test checks for a feature which should pass the request filter but fail the access control checks """ - query_string = "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetFeatureInfo", - "LAYERS": "Hello_Filter_SubsetString", - "QUERY_LAYERS": "Hello_Filter_SubsetString", - "FILTER": "Hello_Filter_SubsetString:\"pkuid\" IN ( 7 , 8 )", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "3415650,2018968,3415750,2019968", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "FEATURE_COUNT": "10", - "INFO_FORMAT": "application/vnd.ogc.gml", - "X": "146", - "Y": "160", - "MAP": urllib.parse.quote(self.projectPath) - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetFeatureInfo", + "LAYERS": "Hello_Filter_SubsetString", + "QUERY_LAYERS": "Hello_Filter_SubsetString", + "FILTER": 'Hello_Filter_SubsetString:"pkuid" IN ( 7 , 8 )', + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "3415650,2018968,3415750,2019968", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "FEATURE_COUNT": "10", + "INFO_FORMAT": "application/vnd.ogc.gml", + "X": "146", + "Y": "160", + "MAP": urllib.parse.quote(self.projectPath), + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self.assertTrue( str(response).find("") != -1, - f"No result result in GetFeatureInfo Hello/2\n{response}") + f"No result result in GetFeatureInfo Hello/2\n{response}", + ) self.assertTrue( str(response).find("8") != -1, - f"No good result result in GetFeatureInfo Hello/2\n{response}") + f"No good result result in GetFeatureInfo Hello/2\n{response}", + ) response, headers = self._get_restricted(query_string) self.assertFalse( str(response).find("") != -1, - f"Unexpected result from GetFeatureInfo Hello/2\n{response}") + f"Unexpected result from GetFeatureInfo Hello/2\n{response}", + ) def test_security_issue_gh32475(self): """Test access control security issue GH 32475""" @@ -945,34 +1262,44 @@ class Filter(QgsAccessControlFilter): def layerFilterSubsetString(self, layer): handler = iface.requestHandler() if handler.parameter("LAYER_PERM") == "yes": - if layer.name() == "as_symbols" or layer.shortName() == "as_symbols": - return "\"gid\" != 1" + if ( + layer.name() == "as_symbols" + or layer.shortName() == "as_symbols" + ): + return '"gid" != 1' return None def _gfi(restrict, layers): - qs = ("?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetFeatureInfo&" + - "BBOX=612616,5810132,619259,5813237" + - "&CRS=EPSG:25832&WIDTH=2759&HEIGHT=1290&&STYLES=" + - "&FORMAT=application/json&QUERY_LAYERS=%s" + - "&INFO_FORMAT=application/json&I=508&J=560&FEATURE_COUNT=10") % layers + qs = ( + "?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetFeatureInfo&" + + "BBOX=612616,5810132,619259,5813237" + + "&CRS=EPSG:25832&WIDTH=2759&HEIGHT=1290&&STYLES=" + + "&FORMAT=application/json&QUERY_LAYERS=%s" + + "&INFO_FORMAT=application/json&I=508&J=560&FEATURE_COUNT=10" + ) % layers if restrict: qs = qs + "&LAYER_PERM=yes" request = QgsBufferServerRequest(qs) response = QgsBufferServerResponse() server.handleRequest(request, response, project) - return json.loads(bytes(response.body()).decode('utf8'))['features'] + return json.loads(bytes(response.body()).decode("utf8"))["features"] server = self._server project = QgsProject() - project.read(os.path.join(unitTestDataPath('qgis_server'), 'test_project_wms_grouped_nested_layers.qgs')) + project.read( + os.path.join( + unitTestDataPath("qgis_server"), + "test_project_wms_grouped_nested_layers.qgs", + ) + ) iface = server.serverInterface() filter = Filter(iface) iface.registerAccessControl(filter, 100) - self.assertEqual(len(_gfi(False, 'areas and symbols')), 1) - self.assertEqual(len(_gfi(True, 'areas and symbols')), 0) - self.assertEqual(len(_gfi(False, 'as_symbols')), 1) - self.assertEqual(len(_gfi(True, 'as_symbols')), 0) + self.assertEqual(len(_gfi(False, "areas and symbols")), 1) + self.assertEqual(len(_gfi(True, "areas and symbols")), 0) + self.assertEqual(len(_gfi(False, "as_symbols")), 1) + self.assertEqual(len(_gfi(True, "as_symbols")), 0) if __name__ == "__main__": diff --git a/tests/src/python/test_qgsserver_accesscontrol_wms_getlegendgraphic.py b/tests/src/python/test_qgsserver_accesscontrol_wms_getlegendgraphic.py index 36a54040723f..01b05c3b3418 100644 --- a/tests/src/python/test_qgsserver_accesscontrol_wms_getlegendgraphic.py +++ b/tests/src/python/test_qgsserver_accesscontrol_wms_getlegendgraphic.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Stephane Brunner' -__date__ = '28/08/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Stephane Brunner" +__date__ = "28/08/2015" +__copyright__ = "Copyright 2015, The QGIS Project" import urllib.parse @@ -25,81 +26,114 @@ class TestQgsServerAccessControlWMSGetlegendgraphic(TestQgsServerAccessControl): # regenerate_reference = True def test_wms_getlegendgraphic_hello(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYERS": "Hello", - "FORMAT": "image/png", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "30", - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "20", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTFAMILY": self.fontFamily, - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYERS": "Hello", + "FORMAT": "image/png", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "30", + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "20", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) - self._img_diff_error(response, headers, "WMS_GetLegendGraphic_Hello", 250, QSize(10, 10)) + self._img_diff_error( + response, headers, "WMS_GetLegendGraphic_Hello", 250, QSize(10, 10) + ) response, headers = self._get_restricted(query_string) - self._img_diff_error(response, headers, "WMS_GetLegendGraphic_Hello", 250, QSize(10, 10)) + self._img_diff_error( + response, headers, "WMS_GetLegendGraphic_Hello", 250, QSize(10, 10) + ) def test_wms_getlegendgraphic_country(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYERS": "Country", - "FORMAT": "image/png", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "30", - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "20", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTFAMILY": self.fontFamily, - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYERS": "Country", + "FORMAT": "image/png", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "30", + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "20", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) - self._img_diff_error(response, headers, "WMS_GetLegendGraphic_Country", 250, QSize(10, 10)) + self._img_diff_error( + response, headers, "WMS_GetLegendGraphic_Country", 250, QSize(10, 10) + ) response, headers = self._get_restricted(query_string) self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for GetMap is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for GetMap is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find('') != -1, - "Not allowed GetLegendGraphic" + "Not allowed GetLegendGraphic", ) def test_wms_getlegendgraphic_country_grp(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYERS": "Country_grp", - "FORMAT": "image/png", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "30", - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "20", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTFAMILY": self.fontFamily, - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYERS": "Country_grp", + "FORMAT": "image/png", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "30", + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "20", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) - self._img_diff_error(response, headers, "WMS_GetLegendGraphic_Country", 250, QSize(10, 10)) + self._img_diff_error( + response, headers, "WMS_GetLegendGraphic_Country", 250, QSize(10, 10) + ) response, headers = self._get_restricted(query_string) self.assertEqual( - headers.get("Content-Type"), "text/xml; charset=utf-8", - f"Content type for GetMap is wrong: {headers.get('Content-Type')}") + headers.get("Content-Type"), + "text/xml; charset=utf-8", + f"Content type for GetMap is wrong: {headers.get('Content-Type')}", + ) self.assertTrue( str(response).find('') != -1, - "Not allowed GetLegendGraphic" + "Not allowed GetLegendGraphic", ) diff --git a/tests/src/python/test_qgsserver_accesscontrol_wms_getmap_postgres.py b/tests/src/python/test_qgsserver_accesscontrol_wms_getmap_postgres.py index 700429b66c8a..c8a9ca21e0cd 100644 --- a/tests/src/python/test_qgsserver_accesscontrol_wms_getmap_postgres.py +++ b/tests/src/python/test_qgsserver_accesscontrol_wms_getmap_postgres.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Stephane Brunner' -__date__ = '28/08/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Stephane Brunner" +__date__ = "28/08/2015" +__copyright__ = "Copyright 2015, The QGIS Project" import os import urllib.error @@ -24,8 +25,7 @@ class RestrictedAccessControlPG(QgsAccessControlFilter): - - """ Used to have restriction access """ + """Used to have restriction access""" # Be able to deactivate the access control to have a reference point _active = False @@ -34,7 +34,7 @@ def __init__(self, server_iface): super(QgsAccessControlFilter, self).__init__(server_iface) def layerFilterExpression(self, layer): - """ Return an additional expression filter """ + """Return an additional expression filter""" if not self._active: return super().layerFilterExpression(layer) @@ -45,7 +45,7 @@ def layerFilterExpression(self, layer): return None def layerFilterSubsetString(self, layer): - """ Return an additional subset string (typically SQL) filter """ + """Return an additional subset string (typically SQL) filter""" if not self._active: return super().layerFilterSubsetString(layer) @@ -56,17 +56,17 @@ def layerFilterSubsetString(self, layer): return None def layerPermissions(self, layer): - """ Return the layer rights """ + """Return the layer rights""" return super().layerPermissions(layer) def authorizedLayerAttributes(self, layer, attributes): - """ Return the authorised layer attributes """ + """Return the authorised layer attributes""" return super().authorizedLayerAttributes(layer, attributes) def allowToEdit(self, layer, feature): - """ Are we authorise to modify the following geometry """ + """Are we authorise to modify the following geometry""" return super().allowToEdit(layer, feature) @@ -82,22 +82,33 @@ def setUpClass(cls): super().setUpClass() - if 'QGIS_PGTEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_PGTEST_DB'] + if "QGIS_PGTEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_PGTEST_DB"] else: - cls.dbconn = 'service=qgis_test dbname=qgis_test sslmode=disable ' + cls.dbconn = "service=qgis_test dbname=qgis_test sslmode=disable " # Test layer - md = QgsProviderRegistry.instance().providerMetadata('postgres') - uri = cls.dbconn + ' dbname=qgis_test sslmode=disable ' + md = QgsProviderRegistry.instance().providerMetadata("postgres") + uri = cls.dbconn + " dbname=qgis_test sslmode=disable " conn = md.createConnection(uri, {}) conn.executeSql('DROP TABLE IF EXISTS "qgis_test"."someDataLong" CASCADE') - conn.executeSql('SELECT * INTO "qgis_test"."someDataLong" FROM "qgis_test"."someData"') - conn.executeSql('ALTER TABLE "qgis_test"."someDataLong" ALTER COLUMN "pk" TYPE bigint') - conn.executeSql('ALTER TABLE "qgis_test"."someDataLong" ALTER COLUMN "pk" SET NOT NULL') - conn.executeSql('CREATE UNIQUE INDEX someDataLongIdx ON "qgis_test"."someDataLong" ("pk")') - - cls.vlconn = cls.dbconn + ' sslmode=disable key=\'pk\' checkPrimaryKeyUnicity=0 srid=4326 type=POINT table="qgis_test"."someDataLong" (geom) sql=' + conn.executeSql( + 'SELECT * INTO "qgis_test"."someDataLong" FROM "qgis_test"."someData"' + ) + conn.executeSql( + 'ALTER TABLE "qgis_test"."someDataLong" ALTER COLUMN "pk" TYPE bigint' + ) + conn.executeSql( + 'ALTER TABLE "qgis_test"."someDataLong" ALTER COLUMN "pk" SET NOT NULL' + ) + conn.executeSql( + 'CREATE UNIQUE INDEX someDataLongIdx ON "qgis_test"."someDataLong" ("pk")' + ) + + cls.vlconn = ( + cls.dbconn + + ' sslmode=disable key=\'pk\' checkPrimaryKeyUnicity=0 srid=4326 type=POINT table="qgis_test"."someDataLong" (geom) sql=' + ) cls._accesscontrolpg = RestrictedAccessControlPG(cls._server_iface) cls._server_iface.registerAccessControl(cls._accesscontrolpg, 100) @@ -106,147 +117,206 @@ def setUp(self): super().setUp() self.projectPath = os.path.join(self.testdata_path, "project_postgres.qgs") - self.assertTrue(os.path.isfile(self.projectPath), f'Could not find project file "{self.projectPath}"') + self.assertTrue( + os.path.isfile(self.projectPath), + f'Could not find project file "{self.projectPath}"', + ) def _handle_request(self, restricted, query_string, **kwargs): self._accesscontrolpg._active = restricted return super()._handle_request(restricted, query_string, **kwargs) def test_wms_getmap(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello,someData", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello,someData", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self._img_diff_error(response, headers, "WMS_PG_GetMap") - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Hello,someData", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Hello,someData", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + }.items() + ) + ] + ) response, headers = self._get_restricted(query_string) self._img_diff_error(response, headers, "Restricted_WMS_PG_GetMap") - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello,someData", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "SELECTION": "someData: 4" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello,someData", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "SELECTION": "someData: 4", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self._img_diff_error(response, headers, "WMS_PG_GetMap_Selection") - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Hello,someData", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "SELECTION": "someData: 4" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Hello,someData", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "SELECTION": "someData: 4", + }.items() + ) + ] + ) response, headers = self._get_restricted(query_string) self._img_diff_error(response, headers, "Restricted_WMS_PG_GetMap_Selection") def test_wms_getmap_long(self): - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello,someDataLong", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello,someDataLong", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self._img_diff_error(response, headers, "WMS_PG_GetMap") - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Hello,someDataLong", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Hello,someDataLong", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + }.items() + ) + ] + ) response, headers = self._get_restricted(query_string) self._img_diff_error(response, headers, "Restricted_WMS_PG_GetMap") - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello,someDataLong", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "SELECTION": "someDataLong: 4" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello,someDataLong", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "SELECTION": "someDataLong: 4", + }.items() + ) + ] + ) response, headers = self._get_fullaccess(query_string) self._img_diff_error(response, headers, "WMS_PG_GetMap_Selection") - query_string = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Hello,someDataLong", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-6318936.5,5696513,16195283.5", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "SELECTION": "someDataLong: 4" - }.items())]) + query_string = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Hello,someDataLong", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-6318936.5,5696513,16195283.5", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "SELECTION": "someDataLong: 4", + }.items() + ) + ] + ) response, headers = self._get_restricted(query_string) self._img_diff_error(response, headers, "Restricted_WMS_PG_GetMap_Selection") diff --git a/tests/src/python/test_qgsserver_accesscontrol_wms_getprint_postgres.py b/tests/src/python/test_qgsserver_accesscontrol_wms_getprint_postgres.py index 8cdd70f18763..dce081d0b96f 100644 --- a/tests/src/python/test_qgsserver_accesscontrol_wms_getprint_postgres.py +++ b/tests/src/python/test_qgsserver_accesscontrol_wms_getprint_postgres.py @@ -9,15 +9,16 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '25/02/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "25/02/2021" +__copyright__ = "Copyright 2021, The QGIS Project" import os import re # Needed on Qt 5 so that the serialization of XML is consistent among all executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" from qgis.core import QgsProject, QgsProviderRegistry, QgsVectorLayer from qgis.PyQt.QtCore import QTemporaryDir @@ -38,16 +39,16 @@ class RestrictedAccessControl(QgsAccessControlFilter): # Be able to deactivate the access control to have a reference point active = { - 'layerFilterExpression': False, - 'layerFilterSubsetString': False, - 'authorizedLayerAttributes': False, - 'layerPermissions': False, + "layerFilterExpression": False, + "layerFilterSubsetString": False, + "authorizedLayerAttributes": False, + "layerPermissions": False, } def layerFilterExpression(self, layer): - """ Return an additional expression filter """ + """Return an additional expression filter""" - if not self.active['layerFilterExpression']: + if not self.active["layerFilterExpression"]: return super().layerFilterExpression(layer) if layer.name() == "multiple_pks": @@ -56,9 +57,9 @@ def layerFilterExpression(self, layer): return None def layerFilterSubsetString(self, layer): - """ Return an additional subset string (typically SQL) filter """ + """Return an additional subset string (typically SQL) filter""" - if not self.active['layerFilterSubsetString']: + if not self.active["layerFilterSubsetString"]: return super().layerFilterSubsetString(layer) if layer.name() == "multiple_pks": @@ -67,9 +68,9 @@ def layerFilterSubsetString(self, layer): return None def authorizedLayerAttributes(self, layer, attributes): - """ Return the authorised layer attributes """ + """Return the authorised layer attributes""" - if not self.active['authorizedLayerAttributes']: + if not self.active["authorizedLayerAttributes"]: return super().authorizedLayerAttributes(layer, attributes) allowed = [] @@ -81,10 +82,10 @@ def authorizedLayerAttributes(self, layer, attributes): return allowed def layerPermissions(self, layer): - """ Return the layer rights """ + """Return the layer rights""" rights = QgsAccessControlFilter.LayerPermissions() - rights.canRead = not self.active['layerPermissions'] + rights.canRead = not self.active["layerPermissions"] return rights @@ -100,39 +101,52 @@ def setUpClass(cls): super().setUpClass() - if 'QGIS_PGTEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_PGTEST_DB'] + if "QGIS_PGTEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_PGTEST_DB"] else: - cls.dbconn = 'service=qgis_test dbname=qgis_test sslmode=disable ' + cls.dbconn = "service=qgis_test dbname=qgis_test sslmode=disable " # Test layer - md = QgsProviderRegistry.instance().providerMetadata('postgres') - uri = cls.dbconn + ' dbname=qgis_test sslmode=disable ' + md = QgsProviderRegistry.instance().providerMetadata("postgres") + uri = cls.dbconn + " dbname=qgis_test sslmode=disable " conn = md.createConnection(uri, {}) - project_path = os.path.join(unitTestDataPath('qgis_server_accesscontrol'), 'pg_multiple_pks.qgs') + project_path = os.path.join( + unitTestDataPath("qgis_server_accesscontrol"), "pg_multiple_pks.qgs" + ) cls.temp_dir = QTemporaryDir() - cls.temp_project_path = os.path.join(cls.temp_dir.path(), 'pg_multiple_pks.qgs') + cls.temp_project_path = os.path.join(cls.temp_dir.path(), "pg_multiple_pks.qgs") # Create test layer conn.executeSql("DROP TABLE IF EXISTS qgis_test.multiple_pks") conn.executeSql( - "CREATE TABLE qgis_test.multiple_pks ( pk1 bigint not null, pk2 bigint not null, name text not null, geom geometry(POINT,4326), PRIMARY KEY ( pk1, pk2 ) )") + "CREATE TABLE qgis_test.multiple_pks ( pk1 bigint not null, pk2 bigint not null, name text not null, geom geometry(POINT,4326), PRIMARY KEY ( pk1, pk2 ) )" + ) conn.executeSql( - "INSERT INTO qgis_test.multiple_pks VALUES ( 1, 1, '1-1', ST_GeomFromText('point(7 45)', 4326))") + "INSERT INTO qgis_test.multiple_pks VALUES ( 1, 1, '1-1', ST_GeomFromText('point(7 45)', 4326))" + ) conn.executeSql( - "INSERT INTO qgis_test.multiple_pks VALUES ( 1, 2, '1-2', ST_GeomFromText('point(8 46)', 4326))") + "INSERT INTO qgis_test.multiple_pks VALUES ( 1, 2, '1-2', ST_GeomFromText('point(8 46)', 4326))" + ) - cls.layer_uri = uri + \ - " sslmode=disable key='pk1,pk2' estimatedmetadata=true srid=4326 type=Point checkPrimaryKeyUnicity='0' table=\"qgis_test\".\"multiple_pks\" (geom)" - layer = QgsVectorLayer(cls.layer_uri, 'multiple_pks', 'postgres') + cls.layer_uri = ( + uri + + " sslmode=disable key='pk1,pk2' estimatedmetadata=true srid=4326 type=Point checkPrimaryKeyUnicity='0' table=\"qgis_test\".\"multiple_pks\" (geom)" + ) + layer = QgsVectorLayer(cls.layer_uri, "multiple_pks", "postgres") assert layer.isValid() project = open(project_path).read() - with open(cls.temp_project_path, 'w+') as f: - f.write(re.sub(r'.*', f'{cls.layer_uri}', project)) + with open(cls.temp_project_path, "w+") as f: + f.write( + re.sub( + r".*", + f"{cls.layer_uri}", + project, + ) + ) cls.test_project = QgsProject() cls.test_project.read(cls.temp_project_path) @@ -144,10 +158,10 @@ def setUpClass(cls): cls._server_iface.registerAccessControl(cls._accesscontrol, 100) def _clear_constraints(self): - self._accesscontrol.active['authorizedLayerAttributes'] = False - self._accesscontrol.active['layerFilterExpression'] = False - self._accesscontrol.active['layerFilterSubsetString'] = False - self._accesscontrol.active['layerPermissions'] = False + self._accesscontrol.active["authorizedLayerAttributes"] = False + self._accesscontrol.active["layerFilterExpression"] = False + self._accesscontrol.active["layerFilterSubsetString"] = False + self._accesscontrol.active["layerPermissions"] = False def setUp(self): super().setUp() @@ -156,22 +170,22 @@ def setUp(self): def _check_exception(self, qs, exception_text): """Check that server throws""" - req = QgsBufferServerRequest('http://my_server/' + qs) + req = QgsBufferServerRequest("http://my_server/" + qs) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 400) - self.assertIn(exception_text, bytes(res.body()).decode('utf8')) + self.assertIn(exception_text, bytes(res.body()).decode("utf8")) def _check_white(self, qs): """Check that output is a white image""" - req = QgsBufferServerRequest('http://my_server/' + qs) + req = QgsBufferServerRequest("http://my_server/" + qs) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) - result_path = os.path.join(self.temp_dir.path(), 'white.png') - with open(result_path, 'wb+') as f: + result_path = os.path.join(self.temp_dir.path(), "white.png") + with open(result_path, "wb+") as f: f.write(res.body()) # A full white image is expected @@ -183,30 +197,37 @@ def _check_white(self, qs): self.assertEqual(color.blue(), 255) def test_wms_getprint_postgres(self): - """Test issue GH #41800 """ + """Test issue GH #41800""" # Extent for feature where pk1 = 1, pk2 = 2 - qs = "?" + "&".join(["%s=%s" % i for i in list({ - 'SERVICE': "WMS", - 'VERSION': "1.3.0", - 'REQUEST': "GetPrint", - 'CRS': 'EPSG:4326', - 'FORMAT': 'png', - 'LAYERS': 'multiple_pks', - 'DPI': 72, - 'TEMPLATE': "print1", - 'map0:EXTENT': '45.70487804878048621,7.67926829268292099,46.22987804878049189,8.42479674796748235', - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetPrint", + "CRS": "EPSG:4326", + "FORMAT": "png", + "LAYERS": "multiple_pks", + "DPI": 72, + "TEMPLATE": "print1", + "map0:EXTENT": "45.70487804878048621,7.67926829268292099,46.22987804878049189,8.42479674796748235", + }.items() + ) + ] + ) def _check_red(): - req = QgsBufferServerRequest('http://my_server/' + qs) + req = QgsBufferServerRequest("http://my_server/" + qs) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) - result_path = os.path.join(self.temp_dir.path(), 'red.png') - with open(result_path, 'wb+') as f: + result_path = os.path.join(self.temp_dir.path(), "red.png") + with open(result_path, "wb+") as f: f.write(res.body()) # A full red image is expected @@ -222,29 +243,31 @@ def _check_red(): # Now activate the rule to exclude the feature where pk1 = 1, pk2 = 2 # A white image is expected - self._accesscontrol.active['layerFilterExpression'] = True + self._accesscontrol.active["layerFilterExpression"] = True self._check_white(qs) # Activate the other rule for subset string - self._accesscontrol.active['layerFilterExpression'] = False - self._accesscontrol.active['layerFilterSubsetString'] = True + self._accesscontrol.active["layerFilterExpression"] = False + self._accesscontrol.active["layerFilterSubsetString"] = True self._check_white(qs) # Activate the other rule for layer permission - self._accesscontrol.active['layerFilterSubsetString'] = False - self._accesscontrol.active['layerPermissions'] = True + self._accesscontrol.active["layerFilterSubsetString"] = False + self._accesscontrol.active["layerPermissions"] = True - req = QgsBufferServerRequest('http://my_server/' + qs) + req = QgsBufferServerRequest("http://my_server/" + qs) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 403) # Test attribute table (template print2) with no rule - self._accesscontrol.active['layerPermissions'] = False + self._accesscontrol.active["layerPermissions"] = False - req = QgsBufferServerRequest('http://my_server/' + qs.replace('print1', 'print2')) + req = QgsBufferServerRequest( + "http://my_server/" + qs.replace("print1", "print2") + ) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) @@ -252,19 +275,25 @@ def _check_red(): self._img_diff_error(res.body(), res.headers(), "WMS_GetPrint_postgres_print2") # Test attribute table with rule - self._accesscontrol.active['authorizedLayerAttributes'] = True + self._accesscontrol.active["authorizedLayerAttributes"] = True - req = QgsBufferServerRequest('http://my_server/' + qs.replace('print1', 'print2')) + req = QgsBufferServerRequest( + "http://my_server/" + qs.replace("print1", "print2") + ) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) - self._img_diff_error(res.body(), res.headers(), "WMS_GetPrint_postgres_print2_filtered") + self._img_diff_error( + res.body(), res.headers(), "WMS_GetPrint_postgres_print2_filtered" + ) # Re-Test attribute table (template print2) with no rule - self._accesscontrol.active['authorizedLayerAttributes'] = False + self._accesscontrol.active["authorizedLayerAttributes"] = False - req = QgsBufferServerRequest('http://my_server/' + qs.replace('print1', 'print2')) + req = QgsBufferServerRequest( + "http://my_server/" + qs.replace("print1", "print2") + ) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) @@ -272,48 +301,64 @@ def _check_red(): self._img_diff_error(res.body(), res.headers(), "WMS_GetPrint_postgres_print2") # Test with layer permissions - self._accesscontrol.active['layerPermissions'] = True - req = QgsBufferServerRequest('http://my_server/' + qs.replace('print1', 'print2')) + self._accesscontrol.active["layerPermissions"] = True + req = QgsBufferServerRequest( + "http://my_server/" + qs.replace("print1", "print2") + ) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 403) # Test with subset string - self._accesscontrol.active['layerPermissions'] = False - self._accesscontrol.active['layerFilterSubsetString'] = True - req = QgsBufferServerRequest('http://my_server/' + qs.replace('print1', 'print2')) + self._accesscontrol.active["layerPermissions"] = False + self._accesscontrol.active["layerFilterSubsetString"] = True + req = QgsBufferServerRequest( + "http://my_server/" + qs.replace("print1", "print2") + ) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) - self._img_diff_error(res.body(), res.headers(), "WMS_GetPrint_postgres_print2_subset") + self._img_diff_error( + res.body(), res.headers(), "WMS_GetPrint_postgres_print2_subset" + ) # Test with filter expression - self._accesscontrol.active['layerFilterExpression'] = True - self._accesscontrol.active['layerFilterSubsetString'] = False - req = QgsBufferServerRequest('http://my_server/' + qs.replace('print1', 'print2')) + self._accesscontrol.active["layerFilterExpression"] = True + self._accesscontrol.active["layerFilterSubsetString"] = False + req = QgsBufferServerRequest( + "http://my_server/" + qs.replace("print1", "print2") + ) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) - self._img_diff_error(res.body(), res.headers(), "WMS_GetPrint_postgres_print2_subset") + self._img_diff_error( + res.body(), res.headers(), "WMS_GetPrint_postgres_print2_subset" + ) # Test attribute table with attribute filter - self._accesscontrol.active['layerFilterExpression'] = False - self._accesscontrol.active['authorizedLayerAttributes'] = True + self._accesscontrol.active["layerFilterExpression"] = False + self._accesscontrol.active["authorizedLayerAttributes"] = True - req = QgsBufferServerRequest('http://my_server/' + qs.replace('print1', 'print2')) + req = QgsBufferServerRequest( + "http://my_server/" + qs.replace("print1", "print2") + ) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) - self._img_diff_error(res.body(), res.headers(), "WMS_GetPrint_postgres_print2_filtered") + self._img_diff_error( + res.body(), res.headers(), "WMS_GetPrint_postgres_print2_filtered" + ) # Clear constraints self._clear_constraints() _check_red() - req = QgsBufferServerRequest('http://my_server/' + qs.replace('print1', 'print2')) + req = QgsBufferServerRequest( + "http://my_server/" + qs.replace("print1", "print2") + ) res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) @@ -323,25 +368,32 @@ def _check_red(): def test_atlas(self): """Test atlas""" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - 'SERVICE': "WMS", - 'VERSION': "1.3.0", - 'REQUEST': "GetPrint", - 'CRS': 'EPSG:4326', - 'FORMAT': 'png', - 'LAYERS': 'multiple_pks', - 'DPI': 72, - 'TEMPLATE': "print1", - }.items())]) - - req = QgsBufferServerRequest('http://my_server/' + qs + '&ATLAS_PK=1,2') + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetPrint", + "CRS": "EPSG:4326", + "FORMAT": "png", + "LAYERS": "multiple_pks", + "DPI": 72, + "TEMPLATE": "print1", + }.items() + ) + ] + ) + + req = QgsBufferServerRequest("http://my_server/" + qs + "&ATLAS_PK=1,2") res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) - result_path = os.path.join(self.temp_dir.path(), 'atlas_1_2.png') - with open(result_path, 'wb+') as f: + result_path = os.path.join(self.temp_dir.path(), "atlas_1_2.png") + with open(result_path, "wb+") as f: f.write(res.body()) # A full red image is expected @@ -353,23 +405,23 @@ def test_atlas(self): self.assertEqual(color.blue(), 0) # Forbid 1-1 - self._accesscontrol.active['layerFilterSubsetString'] = True - self._check_exception(qs + '&ATLAS_PK=1,2', "Atlas error: empty atlas.") + self._accesscontrol.active["layerFilterSubsetString"] = True + self._check_exception(qs + "&ATLAS_PK=1,2", "Atlas error: empty atlas.") - self._accesscontrol.active['layerFilterSubsetString'] = False - self._accesscontrol.active['layerFilterExpression'] = True - self._check_exception(qs + '&ATLAS_PK=1,2', "Atlas error: empty atlas.") + self._accesscontrol.active["layerFilterSubsetString"] = False + self._accesscontrol.active["layerFilterExpression"] = True + self._check_exception(qs + "&ATLAS_PK=1,2", "Atlas error: empty atlas.") # Remove all constraints self._clear_constraints() - req = QgsBufferServerRequest('http://my_server/' + qs + '&ATLAS_PK=1,2') + req = QgsBufferServerRequest("http://my_server/" + qs + "&ATLAS_PK=1,2") res = QgsBufferServerResponse() self._server.handleRequest(req, res, self.test_project) self.assertEqual(res.statusCode(), 200) - result_path = os.path.join(self.temp_dir.path(), 'atlas_1_2.png') - with open(result_path, 'wb+') as f: + result_path = os.path.join(self.temp_dir.path(), "atlas_1_2.png") + with open(result_path, "wb+") as f: f.write(res.body()) # A full red image is expected @@ -381,5 +433,5 @@ def test_atlas(self): self.assertEqual(color.blue(), 0) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_api.py b/tests/src/python/test_qgsserver_api.py index df98ca9883cc..7aeca8c1be19 100644 --- a/tests/src/python/test_qgsserver_api.py +++ b/tests/src/python/test_qgsserver_api.py @@ -8,9 +8,10 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '17/04/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "17/04/2019" +__copyright__ = "Copyright 2019, The QGIS Project" import json import os @@ -18,7 +19,7 @@ import shutil # Deterministic XML -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" from urllib import parse @@ -51,121 +52,152 @@ class QgsServerAPIUtilsTest(QgsServerTestBase): - """ QGIS API server utils tests""" + """QGIS API server utils tests""" def test_parse_bbox(self): - bbox = QgsServerApiUtils.parseBbox( - '8.203495,44.901482,8.203497,44.901484') + bbox = QgsServerApiUtils.parseBbox("8.203495,44.901482,8.203497,44.901484") self.assertEqual(bbox.xMinimum(), 8.203495) self.assertEqual(bbox.yMinimum(), 44.901482) self.assertEqual(bbox.xMaximum(), 8.203497) self.assertEqual(bbox.yMaximum(), 44.901484) bbox = QgsServerApiUtils.parseBbox( - '8.203495,44.901482,100,8.203497,44.901484,120') + "8.203495,44.901482,100,8.203497,44.901484,120" + ) self.assertEqual(bbox.xMinimum(), 8.203495) self.assertEqual(bbox.yMinimum(), 44.901482) self.assertEqual(bbox.xMaximum(), 8.203497) self.assertEqual(bbox.yMaximum(), 44.901484) - bbox = QgsServerApiUtils.parseBbox('something_wrong_here') + bbox = QgsServerApiUtils.parseBbox("something_wrong_here") self.assertTrue(bbox.isEmpty()) bbox = QgsServerApiUtils.parseBbox( - '8.203495,44.901482,8.203497,something_wrong_here') + "8.203495,44.901482,8.203497,something_wrong_here" + ) self.assertTrue(bbox.isEmpty()) def test_published_crs(self): """Test published WMS CRSs""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) crss = QgsServerApiUtils.publishedCrsList(project) - self.assertIn('http://www.opengis.net/def/crs/OGC/1.3/CRS84', crss) - self.assertIn( - 'http://www.opengis.net/def/crs/EPSG/0/3857', crss) - self.assertIn( - 'http://www.opengis.net/def/crs/EPSG/0/4326', crss) + self.assertIn("http://www.opengis.net/def/crs/OGC/1.3/CRS84", crss) + self.assertIn("http://www.opengis.net/def/crs/EPSG/0/3857", crss) + self.assertIn("http://www.opengis.net/def/crs/EPSG/0/4326", crss) def test_parse_crs(self): - crs = QgsServerApiUtils.parseCrs( - 'http://www.opengis.net/def/crs/OGC/1.3/CRS84') + crs = QgsServerApiUtils.parseCrs("http://www.opengis.net/def/crs/OGC/1.3/CRS84") self.assertTrue(crs.isValid()) - crs = QgsServerApiUtils.parseCrs( - 'http://www.opengis.net/def/crs/EPSG/0/4326') + crs = QgsServerApiUtils.parseCrs("http://www.opengis.net/def/crs/EPSG/0/4326") self.assertEqual(crs.postgisSrid(), 4326) - crs = QgsServerApiUtils.parseCrs( - 'http://www.opengis.net/def/crs/EPSG/0/3857') + crs = QgsServerApiUtils.parseCrs("http://www.opengis.net/def/crs/EPSG/0/3857") self.assertTrue(crs.isValid()) self.assertEqual(crs.postgisSrid(), 3857) - crs = QgsServerApiUtils.parseCrs( - 'http://www.opengis.net/something_wrong_here') + crs = QgsServerApiUtils.parseCrs("http://www.opengis.net/something_wrong_here") self.assertFalse(crs.isValid()) def test_append_path(self): path = QgsServerApiUtils.appendMapParameter( - '/wfs3', QtCore.QUrl('https://www.qgis.org/wfs3?MAP=/some/path')) - self.assertEqual(path, '/wfs3?MAP=/some/path') + "/wfs3", QtCore.QUrl("https://www.qgis.org/wfs3?MAP=/some/path") + ) + self.assertEqual(path, "/wfs3?MAP=/some/path") def test_temporal_extent(self): project = QgsProject() tempDir = QtCore.QTemporaryDir() - source_project_path = unitTestDataPath( - 'qgis_server') + '/test_project_api_timefilters.qgs' - source_data_path = unitTestDataPath( - 'qgis_server') + '/test_project_api_timefilters.gpkg' + source_project_path = ( + unitTestDataPath("qgis_server") + "/test_project_api_timefilters.qgs" + ) + source_data_path = ( + unitTestDataPath("qgis_server") + "/test_project_api_timefilters.gpkg" + ) dest_project_path = os.path.join( - tempDir.path(), 'test_project_api_timefilters.qgs') + tempDir.path(), "test_project_api_timefilters.qgs" + ) dest_data_path = os.path.join( - tempDir.path(), 'test_project_api_timefilters.gpkg') + tempDir.path(), "test_project_api_timefilters.gpkg" + ) shutil.copy(source_data_path, dest_data_path) shutil.copy(source_project_path, dest_project_path) project.read(dest_project_path) layer = list(project.mapLayers().values())[0] - layer.serverProperties().removeWmsDimension('date') - layer.serverProperties().removeWmsDimension('time') - self.assertTrue(layer.serverProperties().addWmsDimension( - QgsVectorLayerServerProperties.WmsDimensionInfo('time', 'updated_string'))) - self.assertEqual(QgsServerApiUtils.temporalExtent(layer), [ - ['2010-01-01T01:01:01', '2020-01-01T01:01:01']]) - - layer.serverProperties().removeWmsDimension('date') - layer.serverProperties().removeWmsDimension('time') - self.assertTrue(layer.serverProperties().addWmsDimension( - QgsVectorLayerServerProperties.WmsDimensionInfo('date', 'created'))) - self.assertEqual(QgsServerApiUtils.temporalExtent(layer), [ - ['2010-01-01T00:00:00', '2019-01-01T00:00:00']]) - - layer.serverProperties().removeWmsDimension('date') - layer.serverProperties().removeWmsDimension('time') - self.assertTrue(layer.serverProperties().addWmsDimension( - QgsVectorLayerServerProperties.WmsDimensionInfo('date', 'created_string'))) - self.assertEqual(QgsServerApiUtils.temporalExtent(layer), [ - ['2010-01-01T00:00:00', '2019-01-01T00:00:00']]) - - layer.serverProperties().removeWmsDimension('date') - layer.serverProperties().removeWmsDimension('time') - self.assertTrue(layer.serverProperties().addWmsDimension( - QgsVectorLayerServerProperties.WmsDimensionInfo('time', 'updated'))) - self.assertEqual(QgsServerApiUtils.temporalExtent(layer), [ - ['2010-01-01T01:01:01', '2022-01-01T01:01:01']]) - - layer.serverProperties().removeWmsDimension('date') - layer.serverProperties().removeWmsDimension('time') - self.assertTrue(layer.serverProperties().addWmsDimension( - QgsVectorLayerServerProperties.WmsDimensionInfo('date', 'begin', 'end'))) - self.assertEqual(QgsServerApiUtils.temporalExtent(layer), [ - ['2010-01-01T00:00:00', '2022-01-01T00:00:00']]) + layer.serverProperties().removeWmsDimension("date") + layer.serverProperties().removeWmsDimension("time") + self.assertTrue( + layer.serverProperties().addWmsDimension( + QgsVectorLayerServerProperties.WmsDimensionInfo( + "time", "updated_string" + ) + ) + ) + self.assertEqual( + QgsServerApiUtils.temporalExtent(layer), + [["2010-01-01T01:01:01", "2020-01-01T01:01:01"]], + ) + + layer.serverProperties().removeWmsDimension("date") + layer.serverProperties().removeWmsDimension("time") + self.assertTrue( + layer.serverProperties().addWmsDimension( + QgsVectorLayerServerProperties.WmsDimensionInfo("date", "created") + ) + ) + self.assertEqual( + QgsServerApiUtils.temporalExtent(layer), + [["2010-01-01T00:00:00", "2019-01-01T00:00:00"]], + ) + + layer.serverProperties().removeWmsDimension("date") + layer.serverProperties().removeWmsDimension("time") + self.assertTrue( + layer.serverProperties().addWmsDimension( + QgsVectorLayerServerProperties.WmsDimensionInfo( + "date", "created_string" + ) + ) + ) + self.assertEqual( + QgsServerApiUtils.temporalExtent(layer), + [["2010-01-01T00:00:00", "2019-01-01T00:00:00"]], + ) + + layer.serverProperties().removeWmsDimension("date") + layer.serverProperties().removeWmsDimension("time") + self.assertTrue( + layer.serverProperties().addWmsDimension( + QgsVectorLayerServerProperties.WmsDimensionInfo("time", "updated") + ) + ) + self.assertEqual( + QgsServerApiUtils.temporalExtent(layer), + [["2010-01-01T01:01:01", "2022-01-01T01:01:01"]], + ) + + layer.serverProperties().removeWmsDimension("date") + layer.serverProperties().removeWmsDimension("time") + self.assertTrue( + layer.serverProperties().addWmsDimension( + QgsVectorLayerServerProperties.WmsDimensionInfo("date", "begin", "end") + ) + ) + self.assertEqual( + QgsServerApiUtils.temporalExtent(layer), + [["2010-01-01T00:00:00", "2022-01-01T00:00:00"]], + ) class API(QgsServerApi): - def __init__(self, iface, version='1.0'): + def __init__(self, iface, version="1.0"): super().__init__(iface) self._version = version @@ -179,11 +211,11 @@ def rootPath(self): return "/testapi" def executeRequest(self, request_context): - request_context.response().write(b"\"Test API\"") + request_context.response().write(b'"Test API"') class QgsServerAPITestBase(QgsServerTestBase): - """ QGIS API server tests""" + """QGIS API server tests""" # Set to True in child classes to re-generate reference files for this class regeregenerate_api_reference = False @@ -191,7 +223,7 @@ class QgsServerAPITestBase(QgsServerTestBase): def assertEqualBrackets(self, actual, expected): """Also counts parenthesis""" - self.assertEqual(actual.count('('), actual.count(')')) + self.assertEqual(actual.count("("), actual.count(")")) self.assertEqual(actual, expected) def dump(self, response): @@ -199,81 +231,96 @@ def dump(self, response): result = [] for n, v in response.headers().items(): - if n == 'Content-Length': + if n == "Content-Length": continue result.append(f"{n}: {v}") - result.append('') - result.append(bytes(response.body()).decode('utf8')) - return '\n'.join(result) + result.append("") + result.append(bytes(response.body()).decode("utf8")) + return "\n".join(result) def assertLinesEqual(self, actual, expected, reference_file): """Break on first different line""" - actual_lines = actual.split('\n') - expected_lines = expected.split('\n') + actual_lines = actual.split("\n") + expected_lines = expected.split("\n") for i in range(len(actual_lines)): - self.assertEqual(actual_lines[i], expected_lines[i], "File: {}\nLine: {}\nActual : {}\nExpected: {}".format( - reference_file, i, actual_lines[i], expected_lines[i])) + self.assertEqual( + actual_lines[i], + expected_lines[i], + "File: {}\nLine: {}\nActual : {}\nExpected: {}".format( + reference_file, i, actual_lines[i], expected_lines[i] + ), + ) def normalize_json(self, content): """Normalize a json string""" - reference_content = content.split('\n') - j = ''.join(reference_content[reference_content.index('') + 1:]) + reference_content = content.split("\n") + j = "".join(reference_content[reference_content.index("") + 1 :]) # Do not test timeStamp j = json.loads(j) try: - j['timeStamp'] = '2019-07-05T12:27:07Z' + j["timeStamp"] = "2019-07-05T12:27:07Z" except: pass # Fix coordinate precision differences in Travis try: - bbox = j['extent']['spatial']['bbox'][0] + bbox = j["extent"]["spatial"]["bbox"][0] bbox = [round(c, 4) for c in bbox] - j['extent']['spatial']['bbox'][0] = bbox + j["extent"]["spatial"]["bbox"][0] = bbox except: pass json_content = json.dumps(j, indent=4) # Rounding errors - json_content = re.sub(r'(\d{5})\d+\.\d+', r'\1', json_content) - json_content = re.sub(r'(\d+\.\d{4})\d+', r'\1', json_content) + json_content = re.sub(r"(\d{5})\d+\.\d+", r"\1", json_content) + json_content = re.sub(r"(\d+\.\d{4})\d+", r"\1", json_content) # Poject hash json_content = re.sub( - r'[a-f0-9]{32}', r'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', json_content) - headers_content = '\n'.join( - reference_content[:reference_content.index('') + 1]) - return headers_content + '\n' + json_content + r"[a-f0-9]{32}", r"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", json_content + ) + headers_content = "\n".join( + reference_content[: reference_content.index("") + 1] + ) + return headers_content + "\n" + json_content - def compareApi(self, request, project, reference_file, subdir='api'): + def compareApi(self, request, project, reference_file, subdir="api"): response = QgsBufferServerResponse() # Add json to accept it reference_file is JSON - if reference_file.endswith('.json'): - request.setHeader('Accept', 'application/json') + if reference_file.endswith(".json"): + request.setHeader("Accept", "application/json") self.server.handleRequest(request, response, project) - result = bytes(response.body()).decode( - 'utf8') if reference_file.endswith('html') else self.dump(response) - path = os.path.join(self.temporary_path, - 'qgis_server', subdir, reference_file) + result = ( + bytes(response.body()).decode("utf8") + if reference_file.endswith("html") + else self.dump(response) + ) + path = os.path.join(self.temporary_path, "qgis_server", subdir, reference_file) if self.regeregenerate_api_reference: # Try to change timestamp try: - content = result.split('\n') - j = ''.join(content[content.index('') + 1:]) + content = result.split("\n") + j = "".join(content[content.index("") + 1 :]) j = json.loads(j) - j['timeStamp'] = '2019-07-05T12:27:07Z' - result = '\n'.join(content[:2]) + '\n' + \ - json.dumps(j, ensure_ascii=False, indent=2) + j["timeStamp"] = "2019-07-05T12:27:07Z" + result = ( + "\n".join(content[:2]) + + "\n" + + json.dumps(j, ensure_ascii=False, indent=2) + ) except: pass - f = open(path.encode('utf8'), 'w+', encoding='utf8') + f = open(path.encode("utf8"), "w+", encoding="utf8") f.write(result) f.close() print(f"Reference file {path.encode('utf8')} regenerated!") - with open(path.encode('utf8'), encoding='utf8') as f: - if reference_file.endswith('json'): - self.assertLinesEqual(self.normalize_json( - result), self.normalize_json(f.read()), path.encode('utf8')) + with open(path.encode("utf8"), encoding="utf8") as f: + if reference_file.endswith("json"): + self.assertLinesEqual( + self.normalize_json(result), + self.normalize_json(f.read()), + path.encode("utf8"), + ) else: self.assertEqual(f.read(), result) @@ -283,7 +330,7 @@ def compareContentType(self, url, headers, content_type, project=QgsProject()): request = QgsBufferServerRequest(url, headers=headers) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) - self.assertEqual(response.headers()['Content-Type'], content_type) + self.assertEqual(response.headers()["Content-Type"], content_type) @classmethod def setUpClass(cls): @@ -294,7 +341,14 @@ def setUpClass(cls): class RestrictedLayerAccessControl(QgsAccessControlFilter): """Access control filter to exclude a list of layers by ID, used by WFS3 test""" - def __init__(self, server_iface, ecxluded_layers=[], can_delete=False, can_edit=False, can_insert=False): + def __init__( + self, + server_iface, + ecxluded_layers=[], + can_delete=False, + can_edit=False, + can_insert=False, + ): self.excluded_layers = ecxluded_layers self.can_delete = can_delete self.can_edit = can_edit @@ -302,10 +356,15 @@ def __init__(self, server_iface, ecxluded_layers=[], can_delete=False, can_edit= super(QgsAccessControlFilter, self).__init__(server_iface) def layerPermissions(self, layer): - """ Return the layer rights """ + """Return the layer rights""" rights = QgsAccessControlFilter.LayerPermissions() - rights.canRead = layer.id() not in self.excluded_layers or self.can_edit or self.can_delete or self.can_insert + rights.canRead = ( + layer.id() not in self.excluded_layers + or self.can_edit + or self.can_delete + or self.can_insert + ) rights.canUpdate = layer.id() not in self.excluded_layers or self.can_edit rights.canInsert = layer.id() not in self.excluded_layers or self.can_insert rights.canDelete = layer.id() not in self.excluded_layers or self.can_delete @@ -313,22 +372,22 @@ def layerPermissions(self, layer): class QgsServerAPITest(QgsServerAPITestBase): - """ QGIS API server tests""" + """QGIS API server tests""" def test_api(self): """Test API registering""" api = API(self.server.serverInterface()) self.server.serverInterface().serviceRegistry().registerApi(api) - request = QgsBufferServerRequest('http://server.qgis.org/testapi') - self.compareApi(request, None, 'test_api.json') + request = QgsBufferServerRequest("http://server.qgis.org/testapi") + self.compareApi(request, None, "test_api.json") self.server.serverInterface().serviceRegistry().unregisterApi(api.name()) def test_0_version_registration(self): reg = QgsServiceRegistry() api = API(self.server.serverInterface()) - api1 = API(self.server.serverInterface(), '1.1') + api1 = API(self.server.serverInterface(), "1.1") # 1.1 comes first reg.registerApi(api1) @@ -349,9 +408,9 @@ def test_0_version_registration(self): def test_1_unregister_services(self): reg = QgsServiceRegistry() - api = API(self.server.serverInterface(), '1.0a') - api1 = API(self.server.serverInterface(), '1.0b') - api2 = API(self.server.serverInterface(), '1.0c') + api = API(self.server.serverInterface(), "1.0a") + api1 = API(self.server.serverInterface(), "1.0b") + api2 = API(self.server.serverInterface(), "1.0c") reg.registerApi(api) reg.registerApi(api1) @@ -380,515 +439,670 @@ def test_1_unregister_services(self): def test_wfs3_landing_page(self): """Test WFS3 API landing page in HTML format""" - request = QgsBufferServerRequest('http://server.qgis.org/wfs3.html') - self.compareApi(request, None, 'test_wfs3_landing_page.html') + request = QgsBufferServerRequest("http://server.qgis.org/wfs3.html") + self.compareApi(request, None, "test_wfs3_landing_page.html") def test_content_type_negotiation(self): """Test content-type negotiation and conflicts""" # Default: json - self.compareContentType( - 'http://server.qgis.org/wfs3', {}, 'application/json') + self.compareContentType("http://server.qgis.org/wfs3", {}, "application/json") # Explicit request - self.compareContentType('http://server.qgis.org/wfs3', - {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'}, - 'text/html') - self.compareContentType('http://server.qgis.org/wfs3', - {'Accept': 'application/json'}, 'application/json') - # File suffix self.compareContentType( - 'http://server.qgis.org/wfs3.json', {}, 'application/json') + "http://server.qgis.org/wfs3", + { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + }, + "text/html", + ) + self.compareContentType( + "http://server.qgis.org/wfs3", + {"Accept": "application/json"}, + "application/json", + ) + # File suffix self.compareContentType( - 'http://server.qgis.org/wfs3.html', {}, 'text/html') + "http://server.qgis.org/wfs3.json", {}, "application/json" + ) + self.compareContentType("http://server.qgis.org/wfs3.html", {}, "text/html") # File extension must take precedence over Accept header self.compareContentType( - 'http://server.qgis.org/wfs3.html', {'Accept': 'application/json'}, 'text/html') + "http://server.qgis.org/wfs3.html", + {"Accept": "application/json"}, + "text/html", + ) self.compareContentType( - 'http://server.qgis.org/wfs3.json', {'Accept': 'text/html'}, 'application/json') + "http://server.qgis.org/wfs3.json", + {"Accept": "text/html"}, + "application/json", + ) # Alias request (we ask for json but we get geojson) project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) self.compareContentType( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?bbox=8.203495,44.901482,8.203497,44.901484', - {'Accept': 'application/json'}, 'application/geo+json', - project=project + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?bbox=8.203495,44.901482,8.203497,44.901484", + {"Accept": "application/json"}, + "application/geo+json", + project=project, ) self.compareContentType( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?bbox=8.203495,44.901482,8.203497,44.901484', - {'Accept': 'application/vnd.geo+json'}, 'application/geo+json', - project=project + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?bbox=8.203495,44.901482,8.203497,44.901484", + {"Accept": "application/vnd.geo+json"}, + "application/geo+json", + project=project, ) self.compareContentType( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?bbox=8.203495,44.901482,8.203497,44.901484', - {'Accept': 'application/geojson'}, 'application/geo+json', - project=project + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?bbox=8.203495,44.901482,8.203497,44.901484", + {"Accept": "application/geojson"}, + "application/geo+json", + project=project, ) def test_wfs3_landing_page_json(self): """Test WFS3 API landing page in JSON format""" - request = QgsBufferServerRequest('http://server.qgis.org/wfs3.json') - self.compareApi(request, None, 'test_wfs3_landing_page.json') - request = QgsBufferServerRequest('http://server.qgis.org/wfs3') - request.setHeader('Accept', 'application/json') - self.compareApi(request, None, 'test_wfs3_landing_page.json') + request = QgsBufferServerRequest("http://server.qgis.org/wfs3.json") + self.compareApi(request, None, "test_wfs3_landing_page.json") + request = QgsBufferServerRequest("http://server.qgis.org/wfs3") + request.setHeader("Accept", "application/json") + self.compareApi(request, None, "test_wfs3_landing_page.json") def test_wfs3_api(self): """Test WFS3 API""" # No project: error - request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/api.openapi3') - self.compareApi(request, None, 'test_wfs3_api.json') + request = QgsBufferServerRequest("http://server.qgis.org/wfs3/api.openapi3") + self.compareApi(request, None, "test_wfs3_api.json") - request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/api.openapi3') + request = QgsBufferServerRequest("http://server.qgis.org/wfs3/api.openapi3") project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) - self.compareApi(request, project, 'test_wfs3_api_project.json') + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) + self.compareApi(request, project, "test_wfs3_api_project.json") def test_wfs3_api_permissions(self): """Test the API with different permissions on a layer""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) server = QgsServer() - request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/api.openapi3') + request = QgsBufferServerRequest("http://server.qgis.org/wfs3/api.openapi3") response = QgsBufferServerResponse() server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 200) - result = bytes(response.body()).decode('utf8') + result = bytes(response.body()).decode("utf8") jresult = json.loads(result) - paths = jresult['paths']['/wfs3/collections/testlayer èé/items/{featureId}'] + paths = jresult["paths"]["/wfs3/collections/testlayer èé/items/{featureId}"] - self.assertIn('get', paths) - self.assertIn('put', paths) - self.assertIn('delete', paths) - self.assertIn('patch', paths) + self.assertIn("get", paths) + self.assertIn("put", paths) + self.assertIn("delete", paths) + self.assertIn("patch", paths) - self.assertIn('post', jresult['paths']['/wfs3/collections/testlayer èé/items']) + self.assertIn("post", jresult["paths"]["/wfs3/collections/testlayer èé/items"]) # Access control filter to exclude a layer - acfilter = RestrictedLayerAccessControl(server.serverInterface(), ['testlayer20150528120452665'], can_edit=True, can_delete=False, can_insert=False) + acfilter = RestrictedLayerAccessControl( + server.serverInterface(), + ["testlayer20150528120452665"], + can_edit=True, + can_delete=False, + can_insert=False, + ) server.serverInterface().registerAccessControl(acfilter, 100) response = QgsBufferServerResponse() server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 200) - result = bytes(response.body()).decode('utf8') + result = bytes(response.body()).decode("utf8") jresult = json.loads(result) - paths = jresult['paths']['/wfs3/collections/testlayer èé/items/{featureId}'] + paths = jresult["paths"]["/wfs3/collections/testlayer èé/items/{featureId}"] - self.assertIn('put', paths) - self.assertIn('patch', paths) - self.assertNotIn('delete', paths) + self.assertIn("put", paths) + self.assertIn("patch", paths) + self.assertNotIn("delete", paths) - self.assertNotIn('post', jresult['paths']['/wfs3/collections/testlayer èé/items']) + self.assertNotIn( + "post", jresult["paths"]["/wfs3/collections/testlayer èé/items"] + ) def test_wfs3_conformance(self): """Test WFS3 API""" - request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/conformance') - self.compareApi(request, None, 'test_wfs3_conformance.json') + request = QgsBufferServerRequest("http://server.qgis.org/wfs3/conformance") + self.compareApi(request, None, "test_wfs3_conformance.json") def test_wfs3_collections_empty(self): """Test WFS3 collections API""" - request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections') - self.compareApi(request, None, 'test_wfs3_collections_empty.json') - request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections.json') - self.compareApi(request, None, 'test_wfs3_collections_empty.json') - request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections.html') - self.compareApi(request, None, 'test_wfs3_collections_empty.html') + request = QgsBufferServerRequest("http://server.qgis.org/wfs3/collections") + self.compareApi(request, None, "test_wfs3_collections_empty.json") + request = QgsBufferServerRequest("http://server.qgis.org/wfs3/collections.json") + self.compareApi(request, None, "test_wfs3_collections_empty.json") + request = QgsBufferServerRequest("http://server.qgis.org/wfs3/collections.html") + self.compareApi(request, None, "test_wfs3_collections_empty.html") def test_wfs3_collections_json(self): """Test WFS3 API collections in json format""" - request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections.json') + request = QgsBufferServerRequest("http://server.qgis.org/wfs3/collections.json") project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) - self.compareApi(request, project, 'test_wfs3_collections_project.json') + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) + self.compareApi(request, project, "test_wfs3_collections_project.json") def test_wfs3_collections_json_excluded_layer(self): """Test WFS3 API collections in json format with an excluded layer""" - request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections.json') + request = QgsBufferServerRequest("http://server.qgis.org/wfs3/collections.json") project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) server = QgsServer() response = QgsBufferServerResponse() server.handleRequest(request, response, project) - self.assertEqual(response.headers()['Content-Type'], 'application/json') + self.assertEqual(response.headers()["Content-Type"], "application/json") self.assertEqual(response.statusCode(), 200) - result = bytes(response.body()).decode('utf8') + result = bytes(response.body()).decode("utf8") jresult = json.loads(result) - ids = [l['id'] for l in jresult['collections']] - self.assertIn('layer1_with_short_name', ids) + ids = [l["id"] for l in jresult["collections"]] + self.assertIn("layer1_with_short_name", ids) # Access control filter to exclude a layer - acfilter = RestrictedLayerAccessControl(server.serverInterface(), ['testlayer_c0988fd7_97ca_451d_adbc_37ad6d10583a']) + acfilter = RestrictedLayerAccessControl( + server.serverInterface(), ["testlayer_c0988fd7_97ca_451d_adbc_37ad6d10583a"] + ) server.serverInterface().registerAccessControl(acfilter, 100) response = QgsBufferServerResponse() server.handleRequest(request, response, project) - self.assertEqual(response.headers()['Content-Type'], 'application/json') + self.assertEqual(response.headers()["Content-Type"], "application/json") self.assertEqual(response.statusCode(), 200) - result = bytes(response.body()).decode('utf8') + result = bytes(response.body()).decode("utf8") jresult = json.loads(result) - ids = [l['id'] for l in jresult['collections']] - self.assertNotIn('layer1_with_short_name', ids) + ids = [l["id"] for l in jresult["collections"]] + self.assertNotIn("layer1_with_short_name", ids) def test_wfs3_collections_html(self): """Test WFS3 API collections in html format""" - request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections.html') + request = QgsBufferServerRequest("http://server.qgis.org/wfs3/collections.html") project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) - self.compareApi(request, project, 'test_wfs3_collections_project.html') + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) + self.compareApi(request, project, "test_wfs3_collections_project.html") def test_wfs3_collections_content_type(self): """Test WFS3 API collections in html format with Accept header""" - request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections') - request.setHeader('Accept', 'text/html') + request = QgsBufferServerRequest("http://server.qgis.org/wfs3/collections") + request.setHeader("Accept", "text/html") project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) - self.assertEqual(response.headers()['Content-Type'], 'text/html') - request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections') - request.setHeader('Accept', 'text/html') + self.assertEqual(response.headers()["Content-Type"], "text/html") + request = QgsBufferServerRequest("http://server.qgis.org/wfs3/collections") + request.setHeader("Accept", "text/html") response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) - self.assertEqual(response.headers()['Content-Type'], 'text/html') + self.assertEqual(response.headers()["Content-Type"], "text/html") def test_wfs3_collection_json(self): """Test WFS3 API collection""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé') - self.compareApi(request, project, - 'test_wfs3_collection_testlayer_èé.json') + "http://server.qgis.org/wfs3/collections/testlayer%20èé" + ) + self.compareApi(request, project, "test_wfs3_collection_testlayer_èé.json") def test_wfs3_collection_shortname_json(self): """Test WFS3 API collection with short name""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/layer1_with_short_name') - self.compareApi(request, project, - 'test_wfs3_collection_layer1_with_short_name.json') + "http://server.qgis.org/wfs3/collections/layer1_with_short_name" + ) + self.compareApi( + request, project, "test_wfs3_collection_layer1_with_short_name.json" + ) def test_wfs3_collection_temporal_extent_json(self): """Test collection with timefilter""" project = QgsProject() tempDir = QtCore.QTemporaryDir() - source_project_path = unitTestDataPath( - 'qgis_server') + '/test_project_api_timefilters.qgs' - source_data_path = unitTestDataPath( - 'qgis_server') + '/test_project_api_timefilters.gpkg' + source_project_path = ( + unitTestDataPath("qgis_server") + "/test_project_api_timefilters.qgs" + ) + source_data_path = ( + unitTestDataPath("qgis_server") + "/test_project_api_timefilters.gpkg" + ) dest_project_path = os.path.join( - tempDir.path(), 'test_project_api_timefilters.qgs') + tempDir.path(), "test_project_api_timefilters.qgs" + ) dest_data_path = os.path.join( - tempDir.path(), 'test_project_api_timefilters.gpkg') + tempDir.path(), "test_project_api_timefilters.gpkg" + ) shutil.copy(source_data_path, dest_data_path) shutil.copy(source_project_path, dest_project_path) project.read(dest_project_path) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/points') - self.compareApi(request, project, - 'test_wfs3_collection_points_timefilters.json') + "http://server.qgis.org/wfs3/collections/points" + ) + self.compareApi( + request, project, "test_wfs3_collection_points_timefilters.json" + ) def test_wfs3_collection_html(self): """Test WFS3 API collection""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé.html') - self.compareApi(request, project, - 'test_wfs3_collection_testlayer_èé.html') + "http://server.qgis.org/wfs3/collections/testlayer%20èé.html" + ) + self.compareApi(request, project, "test_wfs3_collection_testlayer_èé.html") request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/') - request.setHeader('Accept', 'text/html') - self.compareApi(request, project, - 'test_wfs3_collection_testlayer_èé.html') + "http://server.qgis.org/wfs3/collections/testlayer%20èé/" + ) + request.setHeader("Accept", "text/html") + self.compareApi(request, project, "test_wfs3_collection_testlayer_èé.html") def test_wfs3_collection_items(self): """Test WFS3 API items""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items') - self.compareApi(request, project, - 'test_wfs3_collections_items_testlayer_èé.json') + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items" + ) + self.compareApi( + request, project, "test_wfs3_collections_items_testlayer_èé.json" + ) def test_wfs3_collection_items_html(self): """Test WFS3 API items""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items.html') - self.compareApi(request, project, - 'test_wfs3_collections_items_testlayer_èé.html') + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items.html" + ) + self.compareApi( + request, project, "test_wfs3_collections_items_testlayer_èé.html" + ) def test_wfs3_collection_items_html_limit_0(self): """Test WFS3 API items limit=0""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items.html?limit=0') - self.compareApi(request, project, - 'test_wfs3_collections_items_testlayer_èé_1.html') + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items.html?limit=0" + ) + self.compareApi( + request, project, "test_wfs3_collections_items_testlayer_èé_1.html" + ) def test_wfs3_collection_items_html_pagination(self): """Test WFS3 API items pagination""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_wms_grouped_nested_layers.qgs')) + project.read( + os.path.join( + self.temporary_path, + "qgis_server", + "test_project_wms_grouped_nested_layers.qgs", + ) + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/as-areas-short-name/items.html?offset=0&limit=6') - self.compareApi(request, project, - 'test_wfs3_collections_items_as_areas_short_name_1.html') + "http://server.qgis.org/wfs3/collections/as-areas-short-name/items.html?offset=0&limit=6" + ) + self.compareApi( + request, project, "test_wfs3_collections_items_as_areas_short_name_1.html" + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/as-areas-short-name/items.html?offset=6&limit=6') - self.compareApi(request, project, - 'test_wfs3_collections_items_as_areas_short_name_2.html') + "http://server.qgis.org/wfs3/collections/as-areas-short-name/items.html?offset=6&limit=6" + ) + self.compareApi( + request, project, "test_wfs3_collections_items_as_areas_short_name_2.html" + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/as-areas-short-name/items.html?offset=12&limit=6') - self.compareApi(request, project, - 'test_wfs3_collections_items_as_areas_short_name_3.html') + "http://server.qgis.org/wfs3/collections/as-areas-short-name/items.html?offset=12&limit=6" + ) + self.compareApi( + request, project, "test_wfs3_collections_items_as_areas_short_name_3.html" + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/as-areas-short-name/items.html?offset=18&limit=6') - self.compareApi(request, project, - 'test_wfs3_collections_items_as_areas_short_name_4.html') + "http://server.qgis.org/wfs3/collections/as-areas-short-name/items.html?offset=18&limit=6" + ) + self.compareApi( + request, project, "test_wfs3_collections_items_as_areas_short_name_4.html" + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/as-areas-short-name/items.html?offset=24&limit=6') - self.compareApi(request, project, - 'test_wfs3_collections_items_as_areas_short_name_5.html') + "http://server.qgis.org/wfs3/collections/as-areas-short-name/items.html?offset=24&limit=6" + ) + self.compareApi( + request, project, "test_wfs3_collections_items_as_areas_short_name_5.html" + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/as-areas-short-name/items.html?offset=30&limit=6') - self.compareApi(request, project, - 'test_wfs3_collections_items_as_areas_short_name_6.html') + "http://server.qgis.org/wfs3/collections/as-areas-short-name/items.html?offset=30&limit=6" + ) + self.compareApi( + request, project, "test_wfs3_collections_items_as_areas_short_name_6.html" + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/as-areas-short-name/items.html?offset=36&limit=6') - self.compareApi(request, project, - 'test_wfs3_collections_items_as_areas_short_name_7.html') + "http://server.qgis.org/wfs3/collections/as-areas-short-name/items.html?offset=36&limit=6" + ) + self.compareApi( + request, project, "test_wfs3_collections_items_as_areas_short_name_7.html" + ) def test_wfs3_collection_items_crs(self): """Test WFS3 API items with CRS""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) - encoded_crs = parse.quote( - 'http://www.opengis.net/def/crs/EPSG/0/3857', safe='') + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) + encoded_crs = parse.quote("http://www.opengis.net/def/crs/EPSG/0/3857", safe="") request = QgsBufferServerRequest( - f'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?crs={encoded_crs}') + f"http://server.qgis.org/wfs3/collections/testlayer%20èé/items?crs={encoded_crs}" + ) self.compareApi( - request, project, 'test_wfs3_collections_items_testlayer_èé_crs_3857.json') + request, project, "test_wfs3_collections_items_testlayer_èé_crs_3857.json" + ) def test_wfs3_collection_items_as_areas_crs_4326(self): """Test WFS3 API items with CRS""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', - 'test_project_wms_grouped_nested_layers.qgs')) - encoded_crs = parse.quote( - 'http://www.opengis.net/def/crs/EPSG/0/4326', safe='') + project.read( + os.path.join( + self.temporary_path, + "qgis_server", + "test_project_wms_grouped_nested_layers.qgs", + ) + ) + encoded_crs = parse.quote("http://www.opengis.net/def/crs/EPSG/0/4326", safe="") request = QgsBufferServerRequest( - f'http://server.qgis.org/wfs3/collections/as-areas-short-name/items?crs={encoded_crs}') + f"http://server.qgis.org/wfs3/collections/as-areas-short-name/items?crs={encoded_crs}" + ) self.compareApi( - request, project, 'test_wfs3_collections_items_as-areas-short-name_4326.json') + request, + project, + "test_wfs3_collections_items_as-areas-short-name_4326.json", + ) def test_wfs3_collection_items_as_areas_crs_3857(self): """Test WFS3 API items with CRS""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', - 'test_project_wms_grouped_nested_layers.qgs')) - encoded_crs = parse.quote( - 'http://www.opengis.net/def/crs/EPSG/0/3857', safe='') + project.read( + os.path.join( + self.temporary_path, + "qgis_server", + "test_project_wms_grouped_nested_layers.qgs", + ) + ) + encoded_crs = parse.quote("http://www.opengis.net/def/crs/EPSG/0/3857", safe="") request = QgsBufferServerRequest( - f'http://server.qgis.org/wfs3/collections/as-areas-short-name/items?crs={encoded_crs}') + f"http://server.qgis.org/wfs3/collections/as-areas-short-name/items?crs={encoded_crs}" + ) self.compareApi( - request, project, 'test_wfs3_collections_items_as-areas-short-name_3857.json') + request, + project, + "test_wfs3_collections_items_as-areas-short-name_3857.json", + ) def test_invalid_args(self): """Test wrong args""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=-1') + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=-1" + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 400) # Bad request - self.assertEqual(response.body(), - b'[{"code":"Bad request error","description":"Argument \'limit\' is not valid. Number of features to retrieve [0-10000]"}]') # Bad request + self.assertEqual( + response.body(), + b'[{"code":"Bad request error","description":"Argument \'limit\' is not valid. Number of features to retrieve [0-10000]"}]', + ) # Bad request request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=10001') + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=10001" + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 400) # Bad request - self.assertEqual(response.body(), - b'[{"code":"Bad request error","description":"Argument \'limit\' is not valid. Number of features to retrieve [0-10000]"}]') # Bad request + self.assertEqual( + response.body(), + b'[{"code":"Bad request error","description":"Argument \'limit\' is not valid. Number of features to retrieve [0-10000]"}]', + ) # Bad request # Test overflowing int32 request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=' + str((1 << 32))) + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=" + + str(1 << 32) + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 400) # Bad request - self.assertEqual(response.body(), - b'[{"code":"Bad request error","description":"Argument \'limit\' is not valid. Number of features to retrieve [0-10000]"}]') # Bad request + self.assertEqual( + response.body(), + b'[{"code":"Bad request error","description":"Argument \'limit\' is not valid. Number of features to retrieve [0-10000]"}]', + ) # Bad request def test_wfs3_collection_items_limit(self): """Test WFS3 API item limits""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=1') + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=1" + ) self.compareApi( - request, project, 'test_wfs3_collections_items_testlayer_èé_limit_1.json') + request, project, "test_wfs3_collections_items_testlayer_èé_limit_1.json" + ) def test_wfs3_collection_items_limit_offset(self): """Test WFS3 API offset""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=1&offset=1') + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=1&offset=1" + ) self.compareApi( - request, project, 'test_wfs3_collections_items_testlayer_èé_limit_1_offset_1.json') + request, + project, + "test_wfs3_collections_items_testlayer_èé_limit_1_offset_1.json", + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=1&offset=-1') + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=1&offset=-1" + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 400) # Bad request - self.assertEqual(response.body(), - b'[{"code":"Bad request error","description":"Argument \'offset\' is not valid. Offset for features to retrieve [0-3]"}]') # Bad request + self.assertEqual( + response.body(), + b'[{"code":"Bad request error","description":"Argument \'offset\' is not valid. Offset for features to retrieve [0-3]"}]', + ) # Bad request request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=-1&offset=1') + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=-1&offset=1" + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 400) # Bad request - self.assertEqual(response.body(), - b'[{"code":"Bad request error","description":"Argument \'limit\' is not valid. Number of features to retrieve [0-10000]"}]') # Bad request + self.assertEqual( + response.body(), + b'[{"code":"Bad request error","description":"Argument \'limit\' is not valid. Number of features to retrieve [0-10000]"}]', + ) # Bad request def test_wfs3_collection_items_limit_offset_2(self): """Test WFS3 API offset 2""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=1&offset=2') + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=1&offset=2" + ) self.compareApi( - request, project, 'test_wfs3_collections_items_testlayer_èé_limit_1_offset_2.json') + request, + project, + "test_wfs3_collections_items_testlayer_èé_limit_1_offset_2.json", + ) def test_wfs3_collection_items_limit_2(self): """Test WFS3 API limit 2""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=2') + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=2" + ) self.compareApi( - request, project, 'test_wfs3_collections_items_testlayer_èé_limit_2.json') + request, project, "test_wfs3_collections_items_testlayer_èé_limit_2.json" + ) def test_wfs3_collection_items_bbox(self): """Test WFS3 API bbox""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?bbox=8.203495,44.901482,8.203497,44.901484') - self.compareApi(request, project, - 'test_wfs3_collections_items_testlayer_èé_bbox.json') + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?bbox=8.203495,44.901482,8.203497,44.901484" + ) + self.compareApi( + request, project, "test_wfs3_collections_items_testlayer_èé_bbox.json" + ) # Test with a different CRS - encoded_crs = parse.quote( - 'http://www.opengis.net/def/crs/EPSG/0/3857', safe='') + encoded_crs = parse.quote("http://www.opengis.net/def/crs/EPSG/0/3857", safe="") request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?bbox=913191,5606014,913234,5606029&bbox-crs={}'.format( - encoded_crs)) + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?bbox=913191,5606014,913234,5606029&bbox-crs={}".format( + encoded_crs + ) + ) self.compareApi( - request, project, 'test_wfs3_collections_items_testlayer_èé_bbox_3857.json') + request, project, "test_wfs3_collections_items_testlayer_èé_bbox_3857.json" + ) def test_wfs3_collection_items_bbox_25832(self): """Test WFS3 API bbox with reprojection""" project = QgsProject() - vl = QgsVectorLayer("Point?crs=EPSG:25832&field=fldint:integer", - "testlayer25832", "memory") + vl = QgsVectorLayer( + "Point?crs=EPSG:25832&field=fldint:integer", "testlayer25832", "memory" + ) f = QgsFeature(vl.fields()) f.setAttribute(0, 1) - f.setGeometry(QgsGeometry.fromWkt('point(361774 4963545)')) + f.setGeometry(QgsGeometry.fromWkt("point(361774 4963545)")) vl.dataProvider().addFeatures((f,)) project.addMapLayers([vl]) project.writeEntry("WFSLayers", "/", (vl.id(),)) - project.writeEntry("WMSCrsList", "/", ("EPSG:25832", "EPSG:4326",)) + project.writeEntry( + "WMSCrsList", + "/", + ( + "EPSG:25832", + "EPSG:4326", + ), + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer25832/items?bbox=7.16305252070271603,44.75906320523620963,7.3418755610416051,44.87555723151492515') + "http://server.qgis.org/wfs3/collections/testlayer25832/items?bbox=7.16305252070271603,44.75906320523620963,7.3418755610416051,44.87555723151492515" + ) - self.compareApi(request, project, - 'test_wfs3_collections_items_testlayer25832_bbox.json') + self.compareApi( + request, project, "test_wfs3_collections_items_testlayer25832_bbox.json" + ) def test_wfs3_static_handler(self): """Test static handler""" - request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/static/style.css') + request = QgsBufferServerRequest("http://server.qgis.org/wfs3/static/style.css") response = QgsBufferServerResponse() self.server.handleRequest(request, response, None) - body = bytes(response.body()).decode('utf8') - self.assertIn('Content-Length', response.headers()) - self.assertEqual(response.headers()['Content-Type'], 'text/css') + body = bytes(response.body()).decode("utf8") + self.assertIn("Content-Length", response.headers()) + self.assertEqual(response.headers()["Content-Type"], "text/css") self.assertGreater(len(body), 0) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/static/does_not_exists.css') + "http://server.qgis.org/wfs3/static/does_not_exists.css" + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, None) - body = bytes(response.body()).decode('utf8') - self.assertEqual(body, - '[{"code":"API not found error","description":"Static file does_not_exists.css was not found"}]') + body = bytes(response.body()).decode("utf8") + self.assertEqual( + body, + '[{"code":"API not found error","description":"Static file does_not_exists.css was not found"}]', + ) def test_wfs3_collection_items_post(self): """Test WFS3 API items POST""" tmpDir = QtCore.QTemporaryDir() - shutil.copy(unitTestDataPath('qgis_server') + '/test_project_api_editing.qgs', - tmpDir.path() + '/test_project_api_editing.qgs') - shutil.copy(unitTestDataPath('qgis_server') + '/test_project_api_editing.gpkg', - tmpDir.path() + '/test_project_api_editing.gpkg') + shutil.copy( + unitTestDataPath("qgis_server") + "/test_project_api_editing.qgs", + tmpDir.path() + "/test_project_api_editing.qgs", + ) + shutil.copy( + unitTestDataPath("qgis_server") + "/test_project_api_editing.gpkg", + tmpDir.path() + "/test_project_api_editing.gpkg", + ) project = QgsProject() - project.read(tmpDir.path() + '/test_project_api_editing.qgs') + project.read(tmpDir.path() + "/test_project_api_editing.qgs") # Project layers with different permissions - insert_layer = r'test%20layer%20èé%203857%20published%20insert' - update_layer = r'test%20layer%20èé%203857%20published%20update' - delete_layer = r'test%20layer%20èé%203857%20published%20delete' - unpublished_layer = r'test%20layer%203857%20èé%20unpublished' - hidden_text_2_layer = r'test%20layer%20èé%203857%20published%20hidden%20text_2' + insert_layer = r"test%20layer%20èé%203857%20published%20insert" + update_layer = r"test%20layer%20èé%203857%20published%20update" + delete_layer = r"test%20layer%20èé%203857%20published%20delete" + unpublished_layer = r"test%20layer%203857%20èé%20unpublished" + hidden_text_2_layer = r"test%20layer%20èé%203857%20published%20hidden%20text_2" # Invalid request - data = b'not json!' - request = QgsBufferServerRequest(f'http://server.qgis.org/wfs3/collections/{insert_layer}/items', - QgsBufferServerRequest.PostMethod, - {'Content-Type': 'application/geo+json'}, - data - ) + data = b"not json!" + request = QgsBufferServerRequest( + f"http://server.qgis.org/wfs3/collections/{insert_layer}/items", + QgsBufferServerRequest.PostMethod, + {"Content-Type": "application/geo+json"}, + data, + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 400) self.assertTrue( - '[{"code":"Bad request error","description":"JSON parse error' in bytes(response.body()).decode('utf8')) + '[{"code":"Bad request error","description":"JSON parse error' + in bytes(response.body()).decode("utf8") + ) # Valid request data = b"""{ @@ -911,63 +1125,78 @@ def test_wfs3_collection_items_post(self): }, "type": "Feature" }""" - request = QgsBufferServerRequest(f'http://server.qgis.org/wfs3/collections/{insert_layer}/items', - QgsBufferServerRequest.PostMethod, - {'Content-Type': 'application/geo+json'}, - data - ) + request = QgsBufferServerRequest( + f"http://server.qgis.org/wfs3/collections/{insert_layer}/items", + QgsBufferServerRequest.PostMethod, + {"Content-Type": "application/geo+json"}, + data, + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 201) self.assertEqual(response.body(), '"string"') # Get last feature req = QgsFeatureRequest() - order_by_clause = QgsFeatureRequest.OrderByClause('$id', False) + order_by_clause = QgsFeatureRequest.OrderByClause("$id", False) req.setOrderBy(QgsFeatureRequest.OrderBy([order_by_clause])) - feature = next(project.mapLayersByName( - 'test layer èé 3857 published insert')[0].getFeatures(req)) - self.assertEqual(response.headers()['Location'], - f'http://server.qgis.org/wfs3/collections/{insert_layer}/items/{feature.id()}') - self.assertEqual(feature.attribute('text_1'), 'Text 1') - self.assertEqual(feature.attribute('text_2'), 'Text 2') - self.assertEqual(feature.attribute('int_1'), 123) - self.assertEqual(feature.attribute('float_1'), 12345.678) - self.assertEqual(feature.attribute('bool_1'), True) - self.assertEqual(bytes(feature.attribute('blob_1')), b"test") - self.assertEqual(re.sub( - r'\.\d+', '', feature.geometry().asWkt().upper()), 'MULTIPOINT ((806732 5592286))') + feature = next( + project.mapLayersByName("test layer èé 3857 published insert")[ + 0 + ].getFeatures(req) + ) + self.assertEqual( + response.headers()["Location"], + f"http://server.qgis.org/wfs3/collections/{insert_layer}/items/{feature.id()}", + ) + self.assertEqual(feature.attribute("text_1"), "Text 1") + self.assertEqual(feature.attribute("text_2"), "Text 2") + self.assertEqual(feature.attribute("int_1"), 123) + self.assertEqual(feature.attribute("float_1"), 12345.678) + self.assertEqual(feature.attribute("bool_1"), True) + self.assertEqual(bytes(feature.attribute("blob_1")), b"test") + self.assertEqual( + re.sub(r"\.\d+", "", feature.geometry().asWkt().upper()), + "MULTIPOINT ((806732 5592286))", + ) def test_wfs3_collection_items_put(self): """Test WFS3 API items PUT""" tmpDir = QtCore.QTemporaryDir() - shutil.copy(unitTestDataPath('qgis_server') + '/test_project_api_editing.qgs', - tmpDir.path() + '/test_project_api_editing.qgs') - shutil.copy(unitTestDataPath('qgis_server') + '/test_project_api_editing.gpkg', - tmpDir.path() + '/test_project_api_editing.gpkg') + shutil.copy( + unitTestDataPath("qgis_server") + "/test_project_api_editing.qgs", + tmpDir.path() + "/test_project_api_editing.qgs", + ) + shutil.copy( + unitTestDataPath("qgis_server") + "/test_project_api_editing.gpkg", + tmpDir.path() + "/test_project_api_editing.gpkg", + ) project = QgsProject() - project.read(tmpDir.path() + '/test_project_api_editing.qgs') + project.read(tmpDir.path() + "/test_project_api_editing.qgs") # Project layers with different permissions - insert_layer = r'test%20layer%20èé%203857%20published%20insert' - update_layer = r'test%20layer%20èé%203857%20published%20update' - delete_layer = r'test%20layer%20èé%203857%20published%20delete' - unpublished_layer = r'test%20layer%203857%20èé%20unpublished' - hidden_text_2_layer = r'test%20layer%20èé%203857%20published%20hidden%20text_2' + insert_layer = r"test%20layer%20èé%203857%20published%20insert" + update_layer = r"test%20layer%20èé%203857%20published%20update" + delete_layer = r"test%20layer%20èé%203857%20published%20delete" + unpublished_layer = r"test%20layer%203857%20èé%20unpublished" + hidden_text_2_layer = r"test%20layer%20èé%203857%20published%20hidden%20text_2" # Invalid request - data = b'not json!' - request = QgsBufferServerRequest(f'http://server.qgis.org/wfs3/collections/{update_layer}/items/1', - QgsBufferServerRequest.PutMethod, - {'Content-Type': 'application/geo+json'}, - data - ) + data = b"not json!" + request = QgsBufferServerRequest( + f"http://server.qgis.org/wfs3/collections/{update_layer}/items/1", + QgsBufferServerRequest.PutMethod, + {"Content-Type": "application/geo+json"}, + data, + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 400) self.assertTrue( - '[{"code":"Bad request error","description":"JSON parse error' in bytes(response.body()).decode('utf8')) + '[{"code":"Bad request error","description":"JSON parse error' + in bytes(response.body()).decode("utf8") + ) # Valid request: change feature with ID 1 data = b"""{ @@ -992,43 +1221,48 @@ def test_wfs3_collection_items_put(self): }""" # Unauthorized layer - request = QgsBufferServerRequest(f'http://server.qgis.org/wfs3/collections/{insert_layer}/items/1', - QgsBufferServerRequest.PutMethod, - {'Content-Type': 'application/geo+json'}, - data - ) + request = QgsBufferServerRequest( + f"http://server.qgis.org/wfs3/collections/{insert_layer}/items/1", + QgsBufferServerRequest.PutMethod, + {"Content-Type": "application/geo+json"}, + data, + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 403) # Authorized layer - request = QgsBufferServerRequest(f'http://server.qgis.org/wfs3/collections/{update_layer}/items/1', - QgsBufferServerRequest.PutMethod, - {'Content-Type': 'application/geo+json'}, - data - ) + request = QgsBufferServerRequest( + f"http://server.qgis.org/wfs3/collections/{update_layer}/items/1", + QgsBufferServerRequest.PutMethod, + {"Content-Type": "application/geo+json"}, + data, + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 200) - j = json.loads(bytes(response.body()).decode('utf8')) - self.assertEqual(j['properties']['text_1'], 'Text 1') - self.assertEqual(j['properties']['text_2'], 'Text 2') - self.assertEqual(j['properties']['int_1'], 123) - self.assertEqual(j['properties']['float_1'], 12345.678) - self.assertEqual(j['properties']['bool_1'], True) - self.assertEqual(j['properties']['blob_1'], "dGVzdA==") - self.assertEqual(j['geometry']['coordinates'], [[7.247, 44.814]]) - - feature = project.mapLayersByName('test layer èé 3857 published update')[ - 0].getFeature(1) - self.assertEqual(feature.attribute('text_1'), 'Text 1') - self.assertEqual(feature.attribute('text_2'), 'Text 2') - self.assertEqual(feature.attribute('int_1'), 123) - self.assertEqual(feature.attribute('float_1'), 12345.678) - self.assertEqual(feature.attribute('bool_1'), True) - self.assertEqual(bytes(feature.attribute('blob_1')), b"test") - self.assertEqual(re.sub( - r'\.\d+', '', feature.geometry().asWkt().upper()), 'MULTIPOINT ((806732 5592286))') + j = json.loads(bytes(response.body()).decode("utf8")) + self.assertEqual(j["properties"]["text_1"], "Text 1") + self.assertEqual(j["properties"]["text_2"], "Text 2") + self.assertEqual(j["properties"]["int_1"], 123) + self.assertEqual(j["properties"]["float_1"], 12345.678) + self.assertEqual(j["properties"]["bool_1"], True) + self.assertEqual(j["properties"]["blob_1"], "dGVzdA==") + self.assertEqual(j["geometry"]["coordinates"], [[7.247, 44.814]]) + + feature = project.mapLayersByName("test layer èé 3857 published update")[ + 0 + ].getFeature(1) + self.assertEqual(feature.attribute("text_1"), "Text 1") + self.assertEqual(feature.attribute("text_2"), "Text 2") + self.assertEqual(feature.attribute("int_1"), 123) + self.assertEqual(feature.attribute("float_1"), 12345.678) + self.assertEqual(feature.attribute("bool_1"), True) + self.assertEqual(bytes(feature.attribute("blob_1")), b"test") + self.assertEqual( + re.sub(r"\.\d+", "", feature.geometry().asWkt().upper()), + "MULTIPOINT ((806732 5592286))", + ) # Test with partial and unordered properties data = b"""{ @@ -1047,33 +1281,37 @@ def test_wfs3_collection_items_put(self): }, "type": "Feature" }""" - request = QgsBufferServerRequest(f'http://server.qgis.org/wfs3/collections/{update_layer}/items/1', - QgsBufferServerRequest.PutMethod, - {'Content-Type': 'application/geo+json'}, - data - ) + request = QgsBufferServerRequest( + f"http://server.qgis.org/wfs3/collections/{update_layer}/items/1", + QgsBufferServerRequest.PutMethod, + {"Content-Type": "application/geo+json"}, + data, + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 200) - j = json.loads(bytes(response.body()).decode('utf8')) - self.assertEqual(j['properties']['text_1'], 'Text 1-bis') - self.assertEqual(j['properties']['text_2'], 'Text 2-bis') - self.assertEqual(j['properties']['int_1'], 1234) - self.assertEqual(j['properties']['float_1'], 12345.678) - self.assertEqual(j['properties']['bool_1'], False) - self.assertEqual(j['properties']['blob_1'], "dGVzdA==") - self.assertEqual(j['geometry']['coordinates'], [[8.247, 45.814]]) - - feature = project.mapLayersByName('test layer èé 3857 published update')[ - 0].getFeature(1) - self.assertEqual(feature.attribute('text_1'), 'Text 1-bis') - self.assertEqual(feature.attribute('text_2'), 'Text 2-bis') - self.assertEqual(feature.attribute('int_1'), 1234) - self.assertEqual(feature.attribute('float_1'), 12345.678) - self.assertEqual(feature.attribute('bool_1'), False) - self.assertEqual(bytes(feature.attribute('blob_1')), b"test") - self.assertEqual(re.sub( - r'\.\d+', '', feature.geometry().asWkt().upper()), 'MULTIPOINT ((918051 5750592))') + j = json.loads(bytes(response.body()).decode("utf8")) + self.assertEqual(j["properties"]["text_1"], "Text 1-bis") + self.assertEqual(j["properties"]["text_2"], "Text 2-bis") + self.assertEqual(j["properties"]["int_1"], 1234) + self.assertEqual(j["properties"]["float_1"], 12345.678) + self.assertEqual(j["properties"]["bool_1"], False) + self.assertEqual(j["properties"]["blob_1"], "dGVzdA==") + self.assertEqual(j["geometry"]["coordinates"], [[8.247, 45.814]]) + + feature = project.mapLayersByName("test layer èé 3857 published update")[ + 0 + ].getFeature(1) + self.assertEqual(feature.attribute("text_1"), "Text 1-bis") + self.assertEqual(feature.attribute("text_2"), "Text 2-bis") + self.assertEqual(feature.attribute("int_1"), 1234) + self.assertEqual(feature.attribute("float_1"), 12345.678) + self.assertEqual(feature.attribute("bool_1"), False) + self.assertEqual(bytes(feature.attribute("blob_1")), b"test") + self.assertEqual( + re.sub(r"\.\d+", "", feature.geometry().asWkt().upper()), + "MULTIPOINT ((918051 5750592))", + ) # Try to update a forbidden (unpublished) field data = b"""{ @@ -1089,11 +1327,12 @@ def test_wfs3_collection_items_put(self): }, "type": "Feature" }""" - request = QgsBufferServerRequest(f'http://server.qgis.org/wfs3/collections/{hidden_text_2_layer}/items/1', - QgsBufferServerRequest.PutMethod, - {'Content-Type': 'application/geo+json'}, - data - ) + request = QgsBufferServerRequest( + f"http://server.qgis.org/wfs3/collections/{hidden_text_2_layer}/items/1", + QgsBufferServerRequest.PutMethod, + {"Content-Type": "application/geo+json"}, + data, + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 403) @@ -1102,73 +1341,87 @@ def test_wfs3_collection_items_delete(self): """Test WFS3 API items DELETE""" tmpDir = QtCore.QTemporaryDir() - shutil.copy(unitTestDataPath('qgis_server') + '/test_project_api_editing.qgs', - tmpDir.path() + '/test_project_api_editing.qgs') - shutil.copy(unitTestDataPath('qgis_server') + '/test_project_api_editing.gpkg', - tmpDir.path() + '/test_project_api_editing.gpkg') + shutil.copy( + unitTestDataPath("qgis_server") + "/test_project_api_editing.qgs", + tmpDir.path() + "/test_project_api_editing.qgs", + ) + shutil.copy( + unitTestDataPath("qgis_server") + "/test_project_api_editing.gpkg", + tmpDir.path() + "/test_project_api_editing.gpkg", + ) project = QgsProject() - project.read(tmpDir.path() + '/test_project_api_editing.qgs') + project.read(tmpDir.path() + "/test_project_api_editing.qgs") # Project layers with different permissions - insert_layer = r'test%20layer%20èé%203857%20published%20insert' - update_layer = r'test%20layer%20èé%203857%20published%20update' - delete_layer = r'test%20layer%20èé%203857%20published%20delete' - unpublished_layer = r'test%20layer%203857%20èé%20unpublished' - hidden_text_2_layer = r'test%20layer%20èé%203857%20published%20hidden%20text_2' + insert_layer = r"test%20layer%20èé%203857%20published%20insert" + update_layer = r"test%20layer%20èé%203857%20published%20update" + delete_layer = r"test%20layer%20èé%203857%20published%20delete" + unpublished_layer = r"test%20layer%203857%20èé%20unpublished" + hidden_text_2_layer = r"test%20layer%20èé%203857%20published%20hidden%20text_2" # Valid request on unauthorized layer - data = b'' - request = QgsBufferServerRequest(f'http://server.qgis.org/wfs3/collections/{update_layer}/items/1', - QgsBufferServerRequest.DeleteMethod) + data = b"" + request = QgsBufferServerRequest( + f"http://server.qgis.org/wfs3/collections/{update_layer}/items/1", + QgsBufferServerRequest.DeleteMethod, + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 403) # Valid request on authorized layer - data = b'' - request = QgsBufferServerRequest(f'http://server.qgis.org/wfs3/collections/{delete_layer}/items/1', - QgsBufferServerRequest.DeleteMethod) + data = b"" + request = QgsBufferServerRequest( + f"http://server.qgis.org/wfs3/collections/{delete_layer}/items/1", + QgsBufferServerRequest.DeleteMethod, + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 200) # Check that it was really deleted - layer = project.mapLayersByName( - 'test layer èé 3857 published delete')[0] + layer = project.mapLayersByName("test layer èé 3857 published delete")[0] self.assertNotIn(1, layer.allFeatureIds()) def test_wfs3_collection_items_patch(self): """Test WFS3 API items PATCH""" tmpDir = QtCore.QTemporaryDir() - shutil.copy(unitTestDataPath('qgis_server') + '/test_project_api_editing.qgs', - tmpDir.path() + '/test_project_api_editing.qgs') - shutil.copy(unitTestDataPath('qgis_server') + '/test_project_api_editing.gpkg', - tmpDir.path() + '/test_project_api_editing.gpkg') + shutil.copy( + unitTestDataPath("qgis_server") + "/test_project_api_editing.qgs", + tmpDir.path() + "/test_project_api_editing.qgs", + ) + shutil.copy( + unitTestDataPath("qgis_server") + "/test_project_api_editing.gpkg", + tmpDir.path() + "/test_project_api_editing.gpkg", + ) project = QgsProject() - project.read(tmpDir.path() + '/test_project_api_editing.qgs') + project.read(tmpDir.path() + "/test_project_api_editing.qgs") # Project layers with different permissions - insert_layer = r'test%20layer%20èé%203857%20published%20insert' - update_layer = r'test%20layer%20èé%203857%20published%20update' - delete_layer = r'test%20layer%20èé%203857%20published%20delete' - unpublished_layer = r'test%20layer%203857%20èé%20unpublished' - hidden_text_2_layer = r'test%20layer%20èé%203857%20published%20hidden%20text_2' + insert_layer = r"test%20layer%20èé%203857%20published%20insert" + update_layer = r"test%20layer%20èé%203857%20published%20update" + delete_layer = r"test%20layer%20èé%203857%20published%20delete" + unpublished_layer = r"test%20layer%203857%20èé%20unpublished" + hidden_text_2_layer = r"test%20layer%20èé%203857%20published%20hidden%20text_2" # Invalid request - data = b'not json!' - request = QgsBufferServerRequest(f'http://server.qgis.org/wfs3/collections/{update_layer}/items/1', - QgsBufferServerRequest.PutMethod, - {'Content-Type': 'application/json'}, - data - ) + data = b"not json!" + request = QgsBufferServerRequest( + f"http://server.qgis.org/wfs3/collections/{update_layer}/items/1", + QgsBufferServerRequest.PutMethod, + {"Content-Type": "application/json"}, + data, + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 400) self.assertTrue( - '[{"code":"Bad request error","description":"JSON parse error' in bytes(response.body()).decode('utf8')) + '[{"code":"Bad request error","description":"JSON parse error' + in bytes(response.body()).decode("utf8") + ) # Invalid request: contains "add" data = b""" @@ -1181,16 +1434,19 @@ def test_wfs3_collection_items_patch(self): } } """ - request = QgsBufferServerRequest(f'http://server.qgis.org/wfs3/collections/{update_layer}/items/1', - QgsBufferServerRequest.PatchMethod, - {'Content-Type': 'application/json'}, - data - ) + request = QgsBufferServerRequest( + f"http://server.qgis.org/wfs3/collections/{update_layer}/items/1", + QgsBufferServerRequest.PatchMethod, + {"Content-Type": "application/json"}, + data, + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 400) - self.assertEqual(bytes(response.body()).decode('utf8'), - r'[{"code":"Not implemented error","description":"\"add\" instruction in PATCH method is not implemented"}]') + self.assertEqual( + bytes(response.body()).decode("utf8"), + r'[{"code":"Not implemented error","description":"\"add\" instruction in PATCH method is not implemented"}]', + ) # Valid request: change feature with ID 1 data = b"""{ @@ -1201,50 +1457,56 @@ def test_wfs3_collection_items_patch(self): }""" # Unauthorized layer - request = QgsBufferServerRequest(f'http://server.qgis.org/wfs3/collections/{insert_layer}/items/1', - QgsBufferServerRequest.PatchMethod, - {'Content-Type': 'application/json'}, - data - ) + request = QgsBufferServerRequest( + f"http://server.qgis.org/wfs3/collections/{insert_layer}/items/1", + QgsBufferServerRequest.PatchMethod, + {"Content-Type": "application/json"}, + data, + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 403) # Authorized layer - request = QgsBufferServerRequest(f'http://server.qgis.org/wfs3/collections/{update_layer}/items/1', - QgsBufferServerRequest.PatchMethod, - {'Content-Type': 'application/json'}, - data - ) + request = QgsBufferServerRequest( + f"http://server.qgis.org/wfs3/collections/{update_layer}/items/1", + QgsBufferServerRequest.PatchMethod, + {"Content-Type": "application/json"}, + data, + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 200, msg=response.body()) - j = json.loads(bytes(response.body()).decode('utf8')) - self.assertEqual(j['properties']['text_1'], 'Torre Pellice 1') - self.assertEqual(j['properties']['text_2'], 'A new text 2') - self.assertEqual(j['properties']['int_1'], 7) - self.assertEqual(j['properties']['float_1'], 1234.567) - self.assertEqual(j['properties']['bool_1'], True) - self.assertEqual(j['properties']['blob_1'], "dGVzdA==") - self.assertEqual(j['geometry']['coordinates'], [[7.227328, 44.820762]]) - - feature = project.mapLayersByName('test layer èé 3857 published update')[ - 0].getFeature(1) - self.assertEqual(feature.attribute('text_1'), 'Torre Pellice 1') - self.assertEqual(feature.attribute('text_2'), 'A new text 2') - self.assertEqual(feature.attribute('int_1'), 7) - self.assertEqual(feature.attribute('float_1'), 1234.567) - self.assertEqual(feature.attribute('bool_1'), True) - self.assertEqual(bytes(feature.attribute('blob_1')), b"test") - self.assertEqual(re.sub( - r'\.\d+', '', feature.geometry().asWkt().upper()), 'MULTIPOINT ((804542 5593348))') + j = json.loads(bytes(response.body()).decode("utf8")) + self.assertEqual(j["properties"]["text_1"], "Torre Pellice 1") + self.assertEqual(j["properties"]["text_2"], "A new text 2") + self.assertEqual(j["properties"]["int_1"], 7) + self.assertEqual(j["properties"]["float_1"], 1234.567) + self.assertEqual(j["properties"]["bool_1"], True) + self.assertEqual(j["properties"]["blob_1"], "dGVzdA==") + self.assertEqual(j["geometry"]["coordinates"], [[7.227328, 44.820762]]) + + feature = project.mapLayersByName("test layer èé 3857 published update")[ + 0 + ].getFeature(1) + self.assertEqual(feature.attribute("text_1"), "Torre Pellice 1") + self.assertEqual(feature.attribute("text_2"), "A new text 2") + self.assertEqual(feature.attribute("int_1"), 7) + self.assertEqual(feature.attribute("float_1"), 1234.567) + self.assertEqual(feature.attribute("bool_1"), True) + self.assertEqual(bytes(feature.attribute("blob_1")), b"test") + self.assertEqual( + re.sub(r"\.\d+", "", feature.geometry().asWkt().upper()), + "MULTIPOINT ((804542 5593348))", + ) # Try to update a forbidden (unpublished) field - request = QgsBufferServerRequest(f'http://server.qgis.org/wfs3/collections/{hidden_text_2_layer}/items/1', - QgsBufferServerRequest.PatchMethod, - {'Content-Type': 'application/json'}, - data - ) + request = QgsBufferServerRequest( + f"http://server.qgis.org/wfs3/collections/{hidden_text_2_layer}/items/1", + QgsBufferServerRequest.PatchMethod, + {"Content-Type": "application/json"}, + data, + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 403) @@ -1252,180 +1514,248 @@ def test_wfs3_collection_items_patch(self): def test_wfs3_field_filters(self): """Test field filters""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) # Check not published response = QgsBufferServerResponse() request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer3/items?name=two') + "http://server.qgis.org/wfs3/collections/testlayer3/items?name=two" + ) self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 404) # Not found request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/layer1_with_short_name/items?name=two') + "http://server.qgis.org/wfs3/collections/layer1_with_short_name/items?name=two" + ) self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 200) self.compareApi( - request, project, 'test_wfs3_collections_items_layer1_with_short_name_eq_two.json') + request, + project, + "test_wfs3_collections_items_layer1_with_short_name_eq_two.json", + ) def test_wfs3_sorting(self): """Test sorting""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) # Check not published response = QgsBufferServerResponse() request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/layer1_with_short_name/items?sortby=does_not_exist') + "http://server.qgis.org/wfs3/collections/layer1_with_short_name/items?sortby=does_not_exist" + ) self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 400) # Bad request request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/layer1_with_short_name/items?sortby=name') + "http://server.qgis.org/wfs3/collections/layer1_with_short_name/items?sortby=name" + ) self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 200) self.compareApi( - request, project, 'test_wfs3_collections_items_layer1_with_short_name_sort_by_name.json') + request, + project, + "test_wfs3_collections_items_layer1_with_short_name_sort_by_name.json", + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/layer1_with_short_name/items?sortby=name&sortdesc=1') + "http://server.qgis.org/wfs3/collections/layer1_with_short_name/items?sortby=name&sortdesc=1" + ) self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 200) self.compareApi( - request, project, 'test_wfs3_collections_items_layer1_with_short_name_sort_by_name_desc.json') + request, + project, + "test_wfs3_collections_items_layer1_with_short_name_sort_by_name_desc.json", + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/layer1_with_short_name/items?sortby=name&sortdesc=0') + "http://server.qgis.org/wfs3/collections/layer1_with_short_name/items?sortby=name&sortdesc=0" + ) self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 200) self.compareApi( - request, project, 'test_wfs3_collections_items_layer1_with_short_name_sort_by_name_asc.json') + request, + project, + "test_wfs3_collections_items_layer1_with_short_name_sort_by_name_asc.json", + ) def test_wfs3_collection_items_properties(self): """Test WFS3 API items""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) # Invalid request request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?properties') + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?properties" + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) - self.assertIn(bytes(response.body()).decode('utf8'), ( - '[{"code":"Bad request error","description":"Argument \'properties\' is not valid. Comma separated list of feature property names to be added to the result. Valid values: \'id\', \'utf8nameè\', \'name\'"}]', - '[{"code":"Bad request error","description":"Argument \'properties\' is not valid. Comma separated list of feature property names to be added to the result. Valid values: \'id\', \'name\', \'utf8nameè\'"}]')) + self.assertIn( + bytes(response.body()).decode("utf8"), + ( + "[{\"code\":\"Bad request error\",\"description\":\"Argument 'properties' is not valid. Comma separated list of feature property names to be added to the result. Valid values: 'id', 'utf8nameè', 'name'\"}]", + "[{\"code\":\"Bad request error\",\"description\":\"Argument 'properties' is not valid. Comma separated list of feature property names to be added to the result. Valid values: 'id', 'name', 'utf8nameè'\"}]", + ), + ) # Valid request response = QgsBufferServerResponse() request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?properties=name') + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?properties=name" + ) self.server.handleRequest(request, response, project) - j = json.loads(bytes(response.body()).decode('utf8')) - self.assertIn('name', j['features'][0]['properties']) - self.assertNotIn('id', j['features'][0]['properties']) + j = json.loads(bytes(response.body()).decode("utf8")) + self.assertIn("name", j["features"][0]["properties"]) + self.assertNotIn("id", j["features"][0]["properties"]) response = QgsBufferServerResponse() request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?properties=name,id') + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?properties=name,id" + ) self.server.handleRequest(request, response, project) - j = json.loads(bytes(response.body()).decode('utf8')) - self.assertIn('name', j['features'][0]['properties']) - self.assertIn('id', j['features'][0]['properties']) + j = json.loads(bytes(response.body()).decode("utf8")) + self.assertIn("name", j["features"][0]["properties"]) + self.assertIn("id", j["features"][0]["properties"]) response = QgsBufferServerResponse() request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?properties=id') + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?properties=id" + ) self.server.handleRequest(request, response, project) - j = json.loads(bytes(response.body()).decode('utf8')) - self.assertNotIn('name', j['features'][0]['properties']) - self.assertIn('id', j['features'][0]['properties']) + j = json.loads(bytes(response.body()).decode("utf8")) + self.assertNotIn("name", j["features"][0]["properties"]) + self.assertIn("id", j["features"][0]["properties"]) def test_wfs3_field_filters_star(self): """Test field filters""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/layer1_with_short_name/items?name=tw*') - response = self.compareApi(request, project, - 'test_wfs3_collections_items_layer1_with_short_name_eq_tw_star.json') + "http://server.qgis.org/wfs3/collections/layer1_with_short_name/items?name=tw*" + ) + response = self.compareApi( + request, + project, + "test_wfs3_collections_items_layer1_with_short_name_eq_tw_star.json", + ) self.assertEqual(response.statusCode(), 200) def test_wfs3_excluded_attributes(self): """Test excluded attributes""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/exclude_attribute/items/0.geojson') + "http://server.qgis.org/wfs3/collections/exclude_attribute/items/0.geojson" + ) response = self.compareApi( - request, project, 'test_wfs3_collections_items_exclude_attribute_0.json') + request, project, "test_wfs3_collections_items_exclude_attribute_0.json" + ) self.assertEqual(response.statusCode(), 200) def test_wfs3_invalid_fids(self): """Test exceptions for invalid fids""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/exclude_attribute/items/123456.geojson') + "http://server.qgis.org/wfs3/collections/exclude_attribute/items/123456.geojson" + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) - self.assertEqual(bytes(response.body()).decode('utf-8'), '[{"code":"Internal server error","description":"Invalid feature [123456]"}]') + self.assertEqual( + bytes(response.body()).decode("utf-8"), + '[{"code":"Internal server error","description":"Invalid feature [123456]"}]', + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/exclude_attribute/items/xYz@#.geojson') + "http://server.qgis.org/wfs3/collections/exclude_attribute/items/xYz@#.geojson" + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) - self.assertEqual(bytes(response.body()).decode('utf-8'), '[{"code":"Internal server error","description":"Invalid feature ID [xYz@]"}]') + self.assertEqual( + bytes(response.body()).decode("utf-8"), + '[{"code":"Internal server error","description":"Invalid feature ID [xYz@]"}]', + ) def test_wfs3_field_alias(self): project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/fields_alias/items.geojson') + "http://server.qgis.org/wfs3/collections/fields_alias/items.geojson" + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) - j_response = json.loads(bytes(response.body()).decode('utf8')) - self.assertEqual(list(j_response['features'][0]['properties'].keys()), ['alias_id', 'alias_name', 'utf8nameè']) + j_response = json.loads(bytes(response.body()).decode("utf8")) + self.assertEqual( + list(j_response["features"][0]["properties"].keys()), + ["alias_id", "alias_name", "utf8nameè"], + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/fields_alias/items.geojson?properties=alias_name') + "http://server.qgis.org/wfs3/collections/fields_alias/items.geojson?properties=alias_name" + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) - j_response = json.loads(bytes(response.body()).decode('utf8')) - self.assertEqual(list(j_response['features'][0]['properties'].keys()), ['alias_name']) + j_response = json.loads(bytes(response.body()).decode("utf8")) + self.assertEqual( + list(j_response["features"][0]["properties"].keys()), ["alias_name"] + ) # Also accepts real name request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/fields_alias/items.geojson?properties=name') + "http://server.qgis.org/wfs3/collections/fields_alias/items.geojson?properties=name" + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) - j_response = json.loads(bytes(response.body()).decode('utf8')) - self.assertEqual(list(j_response['features'][0]['properties'].keys()), ['alias_name']) + j_response = json.loads(bytes(response.body()).decode("utf8")) + self.assertEqual( + list(j_response["features"][0]["properties"].keys()), ["alias_name"] + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/fields_alias/items.geojson?sortby=alias_name&sortdesc=1') + "http://server.qgis.org/wfs3/collections/fields_alias/items.geojson?sortby=alias_name&sortdesc=1" + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) - j_response = json.loads(bytes(response.body()).decode('utf8')) - self.assertEqual([f['id'] for f in j_response['features']], ['1', '2', '0']) + j_response = json.loads(bytes(response.body()).decode("utf8")) + self.assertEqual([f["id"] for f in j_response["features"]], ["1", "2", "0"]) # Also accepts real name request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/fields_alias/items.geojson?sortby=name&sortdesc=1') + "http://server.qgis.org/wfs3/collections/fields_alias/items.geojson?sortby=name&sortdesc=1" + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) - j_response = json.loads(bytes(response.body()).decode('utf8')) - self.assertEqual([f['id'] for f in j_response['features']], ['1', '2', '0']) + j_response = json.loads(bytes(response.body()).decode("utf8")) + self.assertEqual([f["id"] for f in j_response["features"]], ["1", "2", "0"]) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/fields_alias/items.geojson?alias_name=th*') + "http://server.qgis.org/wfs3/collections/fields_alias/items.geojson?alias_name=th*" + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) - j_response = json.loads(bytes(response.body()).decode('utf8')) - self.assertEqual([f['id'] for f in j_response['features']], ['2']) + j_response = json.loads(bytes(response.body()).decode("utf8")) + self.assertEqual([f["id"] for f in j_response["features"]], ["2"]) # Also accepts real name request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/fields_alias/items.geojson?name=th*') + "http://server.qgis.org/wfs3/collections/fields_alias/items.geojson?name=th*" + ) response = QgsBufferServerResponse() self.server.handleRequest(request, response, project) - j_response = json.loads(bytes(response.body()).decode('utf8')) - self.assertEqual([f['id'] for f in j_response['features']], ['2']) + j_response = json.loads(bytes(response.body()).decode("utf8")) + self.assertEqual([f["id"] for f in j_response["features"]], ["2"]) def test_wfs3_time_filters_ranges(self): """Test datetime filters""" @@ -1433,14 +1763,18 @@ def test_wfs3_time_filters_ranges(self): project = QgsProject() tempDir = QtCore.QTemporaryDir() - source_project_path = unitTestDataPath( - 'qgis_server') + '/test_project_api_timefilters.qgs' - source_data_path = unitTestDataPath( - 'qgis_server') + '/test_project_api_timefilters.gpkg' + source_project_path = ( + unitTestDataPath("qgis_server") + "/test_project_api_timefilters.qgs" + ) + source_data_path = ( + unitTestDataPath("qgis_server") + "/test_project_api_timefilters.gpkg" + ) dest_project_path = os.path.join( - tempDir.path(), 'test_project_api_timefilters.qgs') + tempDir.path(), "test_project_api_timefilters.qgs" + ) dest_data_path = os.path.join( - tempDir.path(), 'test_project_api_timefilters.gpkg') + tempDir.path(), "test_project_api_timefilters.gpkg" + ) shutil.copy(source_data_path, dest_data_path) shutil.copy(source_project_path, dest_project_path) project.read(dest_project_path) @@ -1448,94 +1782,162 @@ def test_wfs3_time_filters_ranges(self): # Prepare projects with all options layer = list(project.mapLayers().values())[0] - layer.serverProperties().removeWmsDimension('date') - layer.serverProperties().removeWmsDimension('time') + layer.serverProperties().removeWmsDimension("date") + layer.serverProperties().removeWmsDimension("time") self.assertEqual(len(layer.serverProperties().wmsDimensions()), 0) - self.assertEqual(len(project.mapLayersByName('points')[ - 0].serverProperties().wmsDimensions()), 0) + self.assertEqual( + len( + project.mapLayersByName("points")[0].serverProperties().wmsDimensions() + ), + 0, + ) none_path = os.path.join( - tempDir.path(), 'test_project_api_timefilters_none.qgs') + tempDir.path(), "test_project_api_timefilters_none.qgs" + ) project.write(none_path) layer = list(project.mapLayers().values())[0] - layer.serverProperties().removeWmsDimension('date') - layer.serverProperties().removeWmsDimension('time') - self.assertTrue(layer.serverProperties().addWmsDimension( - QgsVectorLayerServerProperties.WmsDimensionInfo('date', 'created'))) + layer.serverProperties().removeWmsDimension("date") + layer.serverProperties().removeWmsDimension("time") + self.assertTrue( + layer.serverProperties().addWmsDimension( + QgsVectorLayerServerProperties.WmsDimensionInfo("date", "created") + ) + ) created_path = os.path.join( - tempDir.path(), 'test_project_api_timefilters_created.qgs') + tempDir.path(), "test_project_api_timefilters_created.qgs" + ) project.write(created_path) project.read(created_path) - self.assertEqual(len(project.mapLayersByName('points')[ - 0].serverProperties().wmsDimensions()), 1) + self.assertEqual( + len( + project.mapLayersByName("points")[0].serverProperties().wmsDimensions() + ), + 1, + ) layer = list(project.mapLayers().values())[0] - layer.serverProperties().removeWmsDimension('date') - layer.serverProperties().removeWmsDimension('time') - self.assertTrue(layer.serverProperties().addWmsDimension( - QgsVectorLayerServerProperties.WmsDimensionInfo('date', 'created_string'))) + layer.serverProperties().removeWmsDimension("date") + layer.serverProperties().removeWmsDimension("time") + self.assertTrue( + layer.serverProperties().addWmsDimension( + QgsVectorLayerServerProperties.WmsDimensionInfo( + "date", "created_string" + ) + ) + ) created_string_path = os.path.join( - tempDir.path(), 'test_project_api_timefilters_created_string.qgs') + tempDir.path(), "test_project_api_timefilters_created_string.qgs" + ) project.write(created_string_path) project.read(created_string_path) - self.assertEqual(len(project.mapLayersByName('points')[ - 0].serverProperties().wmsDimensions()), 1) + self.assertEqual( + len( + project.mapLayersByName("points")[0].serverProperties().wmsDimensions() + ), + 1, + ) layer = list(project.mapLayers().values())[0] - layer.serverProperties().removeWmsDimension('date') - layer.serverProperties().removeWmsDimension('time') - self.assertTrue(layer.serverProperties().addWmsDimension( - QgsVectorLayerServerProperties.WmsDimensionInfo('time', 'updated_string'))) + layer.serverProperties().removeWmsDimension("date") + layer.serverProperties().removeWmsDimension("time") + self.assertTrue( + layer.serverProperties().addWmsDimension( + QgsVectorLayerServerProperties.WmsDimensionInfo( + "time", "updated_string" + ) + ) + ) updated_string_path = os.path.join( - tempDir.path(), 'test_project_api_timefilters_updated_string.qgs') + tempDir.path(), "test_project_api_timefilters_updated_string.qgs" + ) project.write(updated_string_path) project.read(updated_string_path) - self.assertEqual(len(project.mapLayersByName('points')[ - 0].serverProperties().wmsDimensions()), 1) + self.assertEqual( + len( + project.mapLayersByName("points")[0].serverProperties().wmsDimensions() + ), + 1, + ) layer = list(project.mapLayers().values())[0] - layer.serverProperties().removeWmsDimension('date') - layer.serverProperties().removeWmsDimension('time') - self.assertEqual(len(project.mapLayersByName('points')[ - 0].serverProperties().wmsDimensions()), 0) - self.assertTrue(layer.serverProperties().addWmsDimension( - QgsVectorLayerServerProperties.WmsDimensionInfo('time', 'updated'))) + layer.serverProperties().removeWmsDimension("date") + layer.serverProperties().removeWmsDimension("time") + self.assertEqual( + len( + project.mapLayersByName("points")[0].serverProperties().wmsDimensions() + ), + 0, + ) + self.assertTrue( + layer.serverProperties().addWmsDimension( + QgsVectorLayerServerProperties.WmsDimensionInfo("time", "updated") + ) + ) updated_path = os.path.join( - tempDir.path(), 'test_project_api_timefilters_updated.qgs') + tempDir.path(), "test_project_api_timefilters_updated.qgs" + ) project.write(updated_path) project.read(updated_path) - self.assertEqual(len(project.mapLayersByName('points')[ - 0].serverProperties().wmsDimensions()), 1) + self.assertEqual( + len( + project.mapLayersByName("points")[0].serverProperties().wmsDimensions() + ), + 1, + ) layer = list(project.mapLayers().values())[0] - layer.serverProperties().removeWmsDimension('date') - layer.serverProperties().removeWmsDimension('time') - self.assertEqual(len(project.mapLayersByName('points')[ - 0].serverProperties().wmsDimensions()), 0) - self.assertTrue(layer.serverProperties().addWmsDimension( - QgsVectorLayerServerProperties.WmsDimensionInfo('time', 'updated'))) - self.assertTrue(layer.serverProperties().addWmsDimension( - QgsVectorLayerServerProperties.WmsDimensionInfo('date', 'created'))) + layer.serverProperties().removeWmsDimension("date") + layer.serverProperties().removeWmsDimension("time") + self.assertEqual( + len( + project.mapLayersByName("points")[0].serverProperties().wmsDimensions() + ), + 0, + ) + self.assertTrue( + layer.serverProperties().addWmsDimension( + QgsVectorLayerServerProperties.WmsDimensionInfo("time", "updated") + ) + ) + self.assertTrue( + layer.serverProperties().addWmsDimension( + QgsVectorLayerServerProperties.WmsDimensionInfo("date", "created") + ) + ) both_path = os.path.join( - tempDir.path(), 'test_project_api_timefilters_both.qgs') + tempDir.path(), "test_project_api_timefilters_both.qgs" + ) project.write(both_path) project.read(both_path) - self.assertEqual(len(project.mapLayersByName('points')[ - 0].serverProperties().wmsDimensions()), 2) + self.assertEqual( + len( + project.mapLayersByName("points")[0].serverProperties().wmsDimensions() + ), + 2, + ) layer = list(project.mapLayers().values())[0] - layer.serverProperties().removeWmsDimension('date') - layer.serverProperties().removeWmsDimension('time') - self.assertTrue(layer.serverProperties().addWmsDimension( - QgsVectorLayerServerProperties.WmsDimensionInfo('date', 'begin', 'end'))) + layer.serverProperties().removeWmsDimension("date") + layer.serverProperties().removeWmsDimension("time") + self.assertTrue( + layer.serverProperties().addWmsDimension( + QgsVectorLayerServerProperties.WmsDimensionInfo("date", "begin", "end") + ) + ) date_range_path = os.path.join( - tempDir.path(), 'test_project_api_timefilters_date_range.qgs') + tempDir.path(), "test_project_api_timefilters_date_range.qgs" + ) project.write(date_range_path) project.read(date_range_path) - self.assertEqual(len(project.mapLayersByName('points')[ - 0].serverProperties().wmsDimensions()), 1) + self.assertEqual( + len( + project.mapLayersByName("points")[0].serverProperties().wmsDimensions() + ), + 1, + ) - ''' + """ Test data wkt_geom fid name created updated begin end Point (7.28848021144956881 44.79768920192042714) 3 bibiana @@ -1543,7 +1945,7 @@ def test_wfs3_time_filters_ranges(self): Point (7.22555186948937145 44.82015087638781381) 4 torre 2018-01-01 2021-01-01T01:01:01.000 2018-01-01 2021-01-01 Point (7.2500747591236081 44.81342128741047048) 1 luserna 2019-01-01 2022-01-01T01:01:01.000 2020-01-01 2022-01-01 Point (7.2500747591236081 44.81342128741047048) 5 villar 2010-01-01 2010-01-01T01:01:01.000 2010-01-01 2010-01-01 - ''' + """ # What to test: # interval-closed = date-time "/" date-time @@ -1555,11 +1957,12 @@ def test_wfs3_time_filters_ranges(self): def _date_tester(project_path, datetime, expected, unexpected): # Test "created" date field exact request = QgsBufferServerRequest( - f'http://server.qgis.org/wfs3/collections/points/items?datetime={datetime}') + f"http://server.qgis.org/wfs3/collections/points/items?datetime={datetime}" + ) response = QgsBufferServerResponse() project.read(project_path) self.server.handleRequest(request, response, project) - body = bytes(response.body()).decode('utf8') + body = bytes(response.body()).decode("utf8") # print(body) for exp in expected: self.assertIn(exp, body) @@ -1569,326 +1972,639 @@ def _date_tester(project_path, datetime, expected, unexpected): def _interval(project_path, interval): project.read(project_path) layer = list(project.mapLayers().values())[0] - return QgsServerApiUtils.temporalFilterExpression(layer, interval).expression() + return QgsServerApiUtils.temporalFilterExpression( + layer, interval + ).expression() # Bad request request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/points/items?datetime=bad timing!') + "http://server.qgis.org/wfs3/collections/points/items?datetime=bad timing!" + ) response = QgsBufferServerResponse() project.read(created_path) self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 400) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/points/items?datetime=2020-01-01/2010-01-01') + "http://server.qgis.org/wfs3/collections/points/items?datetime=2020-01-01/2010-01-01" + ) self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 400) # empty request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/points/items?datetime=2020-01-01/2010-01-01') + "http://server.qgis.org/wfs3/collections/points/items?datetime=2020-01-01/2010-01-01" + ) self.server.handleRequest(request, response, project) self.assertEqual(response.statusCode(), 400) # Created (date type) - self.assertEqualBrackets(_interval(created_path, '2017-01-01'), - '( "created" IS NULL OR "created" = to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_path, '../2017-01-01'), - '( "created" IS NULL OR "created" <= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_path, '/2017-01-01'), - '( "created" IS NULL OR "created" <= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_path, '2017-01-01/'), - '( "created" IS NULL OR "created" >= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_path, '2017-01-01/..'), - '( "created" IS NULL OR "created" >= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_path, '2017-01-01/2018-01-01'), - '( "created" IS NULL OR ( to_date( \'2017-01-01\' ) <= "created" AND "created" <= to_date( \'2018-01-01\' ) ) )') - - self.assertEqualBrackets(_interval(created_path, '2017-01-01T01:01:01'), - '( "created" IS NULL OR "created" = to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_path, '../2017-01-01T01:01:01'), - '( "created" IS NULL OR "created" <= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_path, '/2017-01-01T01:01:01'), - '( "created" IS NULL OR "created" <= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_path, '2017-01-01T01:01:01/'), - '( "created" IS NULL OR "created" >= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_path, '2017-01-01T01:01:01/..'), - '( "created" IS NULL OR "created" >= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_path, '2017-01-01T01:01:01/2018-01-01T01:01:01'), - '( "created" IS NULL OR ( to_date( \'2017-01-01\' ) <= "created" AND "created" <= to_date( \'2018-01-01\' ) ) )') + self.assertEqualBrackets( + _interval(created_path, "2017-01-01"), + '( "created" IS NULL OR "created" = to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_path, "../2017-01-01"), + '( "created" IS NULL OR "created" <= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_path, "/2017-01-01"), + '( "created" IS NULL OR "created" <= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_path, "2017-01-01/"), + '( "created" IS NULL OR "created" >= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_path, "2017-01-01/.."), + '( "created" IS NULL OR "created" >= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_path, "2017-01-01/2018-01-01"), + '( "created" IS NULL OR ( to_date( \'2017-01-01\' ) <= "created" AND "created" <= to_date( \'2018-01-01\' ) ) )', + ) + + self.assertEqualBrackets( + _interval(created_path, "2017-01-01T01:01:01"), + '( "created" IS NULL OR "created" = to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_path, "../2017-01-01T01:01:01"), + '( "created" IS NULL OR "created" <= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_path, "/2017-01-01T01:01:01"), + '( "created" IS NULL OR "created" <= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_path, "2017-01-01T01:01:01/"), + '( "created" IS NULL OR "created" >= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_path, "2017-01-01T01:01:01/.."), + '( "created" IS NULL OR "created" >= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_path, "2017-01-01T01:01:01/2018-01-01T01:01:01"), + '( "created" IS NULL OR ( to_date( \'2017-01-01\' ) <= "created" AND "created" <= to_date( \'2018-01-01\' ) ) )', + ) # Updated (datetime type) - self.assertEqualBrackets(_interval(updated_path, '2017-01-01'), - '( "updated" IS NULL OR to_date( "updated" ) = to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(updated_path, '/2017-01-01'), - '( "updated" IS NULL OR to_date( "updated" ) <= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(updated_path, '../2017-01-01'), - '( "updated" IS NULL OR to_date( "updated" ) <= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(updated_path, '2017-01-01/'), - '( "updated" IS NULL OR to_date( "updated" ) >= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(updated_path, '2017-01-01/..'), - '( "updated" IS NULL OR to_date( "updated" ) >= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(updated_path, '2017-01-01/2018-01-01'), - '( "updated" IS NULL OR ( to_date( \'2017-01-01\' ) <= to_date( "updated" ) AND to_date( "updated" ) <= to_date( \'2018-01-01\' ) ) )') - - self.assertEqualBrackets(_interval(updated_path, '2017-01-01T01:01:01'), - '( "updated" IS NULL OR "updated" = to_datetime( \'2017-01-01T01:01:01\' ) )') - self.assertEqualBrackets(_interval(updated_path, '../2017-01-01T01:01:01'), - '( "updated" IS NULL OR "updated" <= to_datetime( \'2017-01-01T01:01:01\' ) )') - self.assertEqualBrackets(_interval(updated_path, '/2017-01-01T01:01:01'), - '( "updated" IS NULL OR "updated" <= to_datetime( \'2017-01-01T01:01:01\' ) )') - self.assertEqualBrackets(_interval(updated_path, '2017-01-01T01:01:01/'), - '( "updated" IS NULL OR "updated" >= to_datetime( \'2017-01-01T01:01:01\' ) )') - self.assertEqualBrackets(_interval(updated_path, '2017-01-01T01:01:01/..'), - '( "updated" IS NULL OR "updated" >= to_datetime( \'2017-01-01T01:01:01\' ) )') - self.assertEqualBrackets(_interval(updated_path, '2017-01-01T01:01:01/2018-01-01T01:01:01'), - '( "updated" IS NULL OR ( to_datetime( \'2017-01-01T01:01:01\' ) <= "updated" AND "updated" <= to_datetime( \'2018-01-01T01:01:01\' ) ) )') + self.assertEqualBrackets( + _interval(updated_path, "2017-01-01"), + '( "updated" IS NULL OR to_date( "updated" ) = to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_path, "/2017-01-01"), + '( "updated" IS NULL OR to_date( "updated" ) <= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_path, "../2017-01-01"), + '( "updated" IS NULL OR to_date( "updated" ) <= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_path, "2017-01-01/"), + '( "updated" IS NULL OR to_date( "updated" ) >= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_path, "2017-01-01/.."), + '( "updated" IS NULL OR to_date( "updated" ) >= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_path, "2017-01-01/2018-01-01"), + '( "updated" IS NULL OR ( to_date( \'2017-01-01\' ) <= to_date( "updated" ) AND to_date( "updated" ) <= to_date( \'2018-01-01\' ) ) )', + ) + + self.assertEqualBrackets( + _interval(updated_path, "2017-01-01T01:01:01"), + '( "updated" IS NULL OR "updated" = to_datetime( \'2017-01-01T01:01:01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_path, "../2017-01-01T01:01:01"), + '( "updated" IS NULL OR "updated" <= to_datetime( \'2017-01-01T01:01:01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_path, "/2017-01-01T01:01:01"), + '( "updated" IS NULL OR "updated" <= to_datetime( \'2017-01-01T01:01:01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_path, "2017-01-01T01:01:01/"), + '( "updated" IS NULL OR "updated" >= to_datetime( \'2017-01-01T01:01:01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_path, "2017-01-01T01:01:01/.."), + '( "updated" IS NULL OR "updated" >= to_datetime( \'2017-01-01T01:01:01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_path, "2017-01-01T01:01:01/2018-01-01T01:01:01"), + '( "updated" IS NULL OR ( to_datetime( \'2017-01-01T01:01:01\' ) <= "updated" AND "updated" <= to_datetime( \'2018-01-01T01:01:01\' ) ) )', + ) # Created string (date type) - self.assertEqualBrackets(_interval(created_string_path, '2017-01-01'), - '( "created_string" IS NULL OR to_date( "created_string" ) = to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_string_path, '../2017-01-01'), - '( "created_string" IS NULL OR to_date( "created_string" ) <= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_string_path, '/2017-01-01'), - '( "created_string" IS NULL OR to_date( "created_string" ) <= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_string_path, '2017-01-01/'), - '( "created_string" IS NULL OR to_date( "created_string" ) >= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_string_path, '2017-01-01/..'), - '( "created_string" IS NULL OR to_date( "created_string" ) >= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_string_path, '2017-01-01/2018-01-01'), - '( "created_string" IS NULL OR ( to_date( \'2017-01-01\' ) <= to_date( "created_string" ) AND to_date( "created_string" ) <= to_date( \'2018-01-01\' ) ) )') - - self.assertEqualBrackets(_interval(created_string_path, '2017-01-01T01:01:01'), - '( "created_string" IS NULL OR to_date( "created_string" ) = to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_string_path, '../2017-01-01T01:01:01'), - '( "created_string" IS NULL OR to_date( "created_string" ) <= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_string_path, '/2017-01-01T01:01:01'), - '( "created_string" IS NULL OR to_date( "created_string" ) <= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_string_path, '2017-01-01T01:01:01/'), - '( "created_string" IS NULL OR to_date( "created_string" ) >= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_string_path, '2017-01-01T01:01:01/..'), - '( "created_string" IS NULL OR to_date( "created_string" ) >= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(created_string_path, '2017-01-01T01:01:01/2018-01-01T01:01:01'), - '( "created_string" IS NULL OR ( to_date( \'2017-01-01\' ) <= to_date( "created_string" ) AND to_date( "created_string" ) <= to_date( \'2018-01-01\' ) ) )') + self.assertEqualBrackets( + _interval(created_string_path, "2017-01-01"), + '( "created_string" IS NULL OR to_date( "created_string" ) = to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_string_path, "../2017-01-01"), + '( "created_string" IS NULL OR to_date( "created_string" ) <= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_string_path, "/2017-01-01"), + '( "created_string" IS NULL OR to_date( "created_string" ) <= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_string_path, "2017-01-01/"), + '( "created_string" IS NULL OR to_date( "created_string" ) >= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_string_path, "2017-01-01/.."), + '( "created_string" IS NULL OR to_date( "created_string" ) >= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_string_path, "2017-01-01/2018-01-01"), + '( "created_string" IS NULL OR ( to_date( \'2017-01-01\' ) <= to_date( "created_string" ) AND to_date( "created_string" ) <= to_date( \'2018-01-01\' ) ) )', + ) + + self.assertEqualBrackets( + _interval(created_string_path, "2017-01-01T01:01:01"), + '( "created_string" IS NULL OR to_date( "created_string" ) = to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_string_path, "../2017-01-01T01:01:01"), + '( "created_string" IS NULL OR to_date( "created_string" ) <= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_string_path, "/2017-01-01T01:01:01"), + '( "created_string" IS NULL OR to_date( "created_string" ) <= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_string_path, "2017-01-01T01:01:01/"), + '( "created_string" IS NULL OR to_date( "created_string" ) >= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_string_path, "2017-01-01T01:01:01/.."), + '( "created_string" IS NULL OR to_date( "created_string" ) >= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(created_string_path, "2017-01-01T01:01:01/2018-01-01T01:01:01"), + '( "created_string" IS NULL OR ( to_date( \'2017-01-01\' ) <= to_date( "created_string" ) AND to_date( "created_string" ) <= to_date( \'2018-01-01\' ) ) )', + ) # Updated string (datetime type) - self.assertEqualBrackets(_interval(updated_string_path, '2017-01-01'), - '( "updated_string" IS NULL OR to_date( "updated_string" ) = to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(updated_string_path, '/2017-01-01'), - '( "updated_string" IS NULL OR to_date( "updated_string" ) <= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(updated_string_path, '../2017-01-01'), - '( "updated_string" IS NULL OR to_date( "updated_string" ) <= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(updated_string_path, '2017-01-01/'), - '( "updated_string" IS NULL OR to_date( "updated_string" ) >= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(updated_string_path, '2017-01-01/..'), - '( "updated_string" IS NULL OR to_date( "updated_string" ) >= to_date( \'2017-01-01\' ) )') - self.assertEqualBrackets(_interval(updated_string_path, '2017-01-01/2018-01-01'), - '( "updated_string" IS NULL OR ( to_date( \'2017-01-01\' ) <= to_date( "updated_string" ) AND to_date( "updated_string" ) <= to_date( \'2018-01-01\' ) ) )') - - self.assertEqualBrackets(_interval(updated_string_path, '2017-01-01T01:01:01'), - '( "updated_string" IS NULL OR to_datetime( "updated_string" ) = to_datetime( \'2017-01-01T01:01:01\' ) )') - self.assertEqualBrackets(_interval(updated_string_path, '../2017-01-01T01:01:01'), - '( "updated_string" IS NULL OR to_datetime( "updated_string" ) <= to_datetime( \'2017-01-01T01:01:01\' ) )') - self.assertEqualBrackets(_interval(updated_string_path, '/2017-01-01T01:01:01'), - '( "updated_string" IS NULL OR to_datetime( "updated_string" ) <= to_datetime( \'2017-01-01T01:01:01\' ) )') - self.assertEqualBrackets(_interval(updated_string_path, '2017-01-01T01:01:01/'), - '( "updated_string" IS NULL OR to_datetime( "updated_string" ) >= to_datetime( \'2017-01-01T01:01:01\' ) )') - self.assertEqualBrackets(_interval(updated_string_path, '2017-01-01T01:01:01/..'), - '( "updated_string" IS NULL OR to_datetime( "updated_string" ) >= to_datetime( \'2017-01-01T01:01:01\' ) )') - self.assertEqualBrackets(_interval(updated_string_path, '2017-01-01T01:01:01/2018-01-01T01:01:01'), - '( "updated_string" IS NULL OR ( to_datetime( \'2017-01-01T01:01:01\' ) <= to_datetime( "updated_string" ) AND to_datetime( "updated_string" ) <= to_datetime( \'2018-01-01T01:01:01\' ) ) )') + self.assertEqualBrackets( + _interval(updated_string_path, "2017-01-01"), + '( "updated_string" IS NULL OR to_date( "updated_string" ) = to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_string_path, "/2017-01-01"), + '( "updated_string" IS NULL OR to_date( "updated_string" ) <= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_string_path, "../2017-01-01"), + '( "updated_string" IS NULL OR to_date( "updated_string" ) <= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_string_path, "2017-01-01/"), + '( "updated_string" IS NULL OR to_date( "updated_string" ) >= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_string_path, "2017-01-01/.."), + '( "updated_string" IS NULL OR to_date( "updated_string" ) >= to_date( \'2017-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_string_path, "2017-01-01/2018-01-01"), + '( "updated_string" IS NULL OR ( to_date( \'2017-01-01\' ) <= to_date( "updated_string" ) AND to_date( "updated_string" ) <= to_date( \'2018-01-01\' ) ) )', + ) + + self.assertEqualBrackets( + _interval(updated_string_path, "2017-01-01T01:01:01"), + '( "updated_string" IS NULL OR to_datetime( "updated_string" ) = to_datetime( \'2017-01-01T01:01:01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_string_path, "../2017-01-01T01:01:01"), + '( "updated_string" IS NULL OR to_datetime( "updated_string" ) <= to_datetime( \'2017-01-01T01:01:01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_string_path, "/2017-01-01T01:01:01"), + '( "updated_string" IS NULL OR to_datetime( "updated_string" ) <= to_datetime( \'2017-01-01T01:01:01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_string_path, "2017-01-01T01:01:01/"), + '( "updated_string" IS NULL OR to_datetime( "updated_string" ) >= to_datetime( \'2017-01-01T01:01:01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_string_path, "2017-01-01T01:01:01/.."), + '( "updated_string" IS NULL OR to_datetime( "updated_string" ) >= to_datetime( \'2017-01-01T01:01:01\' ) )', + ) + self.assertEqualBrackets( + _interval(updated_string_path, "2017-01-01T01:01:01/2018-01-01T01:01:01"), + '( "updated_string" IS NULL OR ( to_datetime( \'2017-01-01T01:01:01\' ) <= to_datetime( "updated_string" ) AND to_datetime( "updated_string" ) <= to_datetime( \'2018-01-01T01:01:01\' ) ) )', + ) # Ranges - self.assertEqualBrackets(_interval(date_range_path, '2010-01-01'), - '( "begin" IS NULL OR "begin" <= to_date( \'2010-01-01\' ) ) AND ( "end" IS NULL OR to_date( \'2010-01-01\' ) <= "end" )') - self.assertEqualBrackets(_interval(date_range_path, '../2010-01-01'), - '( "begin" IS NULL OR "begin" <= to_date( \'2010-01-01\' ) )') - self.assertEqualBrackets(_interval(date_range_path, '2010-01-01/..'), - '( "end" IS NULL OR "end" >= to_date( \'2010-01-01\' ) )') + self.assertEqualBrackets( + _interval(date_range_path, "2010-01-01"), + '( "begin" IS NULL OR "begin" <= to_date( \'2010-01-01\' ) ) AND ( "end" IS NULL OR to_date( \'2010-01-01\' ) <= "end" )', + ) + self.assertEqualBrackets( + _interval(date_range_path, "../2010-01-01"), + '( "begin" IS NULL OR "begin" <= to_date( \'2010-01-01\' ) )', + ) + self.assertEqualBrackets( + _interval(date_range_path, "2010-01-01/.."), + '( "end" IS NULL OR "end" >= to_date( \'2010-01-01\' ) )', + ) # Overlap of ranges - self.assertEqualBrackets(_interval(date_range_path, '2010-01-01/2020-09-12'), - '( "begin" IS NULL OR "begin" <= to_date( \'2020-09-12\' ) ) AND ( "end" IS NULL OR "end" >= to_date( \'2010-01-01\' ) )') + self.assertEqualBrackets( + _interval(date_range_path, "2010-01-01/2020-09-12"), + '( "begin" IS NULL OR "begin" <= to_date( \'2020-09-12\' ) ) AND ( "end" IS NULL OR "end" >= to_date( \'2010-01-01\' ) )', + ) ################################################################################## # Test "created" date field # Test exact - _date_tester(created_path, '2017-01-01', - ['bricherasio'], ['luserna', 'torre']) + _date_tester(created_path, "2017-01-01", ["bricherasio"], ["luserna", "torre"]) # Test datetime field exact (test that we can use a time on a date type field) - _date_tester(created_path, '2017-01-01T01:01:01', - ['bricherasio'], ['luserna', 'torre']) + _date_tester( + created_path, "2017-01-01T01:01:01", ["bricherasio"], ["luserna", "torre"] + ) # Test exact no match - _date_tester(created_path, '2000-05-06', [], - ['luserna', 'bricherasio', 'torre']) + _date_tester( + created_path, "2000-05-06", [], ["luserna", "bricherasio", "torre"] + ) ################################################################################## # Test "updated" datetime field # Test exact - _date_tester(updated_path, '2019-01-01T01:01:01', - ['bricherasio'], ['luserna', 'torre']) + _date_tester( + updated_path, "2019-01-01T01:01:01", ["bricherasio"], ["luserna", "torre"] + ) # Test date field exact (test that we can also use a date on a datetime type field) - _date_tester(updated_path, '2019-01-01', - ['bricherasio'], ['luserna', 'torre']) + _date_tester(updated_path, "2019-01-01", ["bricherasio"], ["luserna", "torre"]) # Test exact no match - _date_tester(updated_path, '2017-01-01T05:05:05', - [], ['luserna', 'bricherasio', 'torre']) + _date_tester( + updated_path, "2017-01-01T05:05:05", [], ["luserna", "bricherasio", "torre"] + ) ################################################################################## # Test both # Test exact - _date_tester(both_path, '2010-01-01T01:01:01', - ['villar'], ['torre', 'bricherasio', 'luserna']) + _date_tester( + both_path, + "2010-01-01T01:01:01", + ["villar"], + ["torre", "bricherasio", "luserna"], + ) # Test date field exact (test that we can use a date on a datetime type field) - _date_tester(both_path, '2010-01-01', - ['villar'], ['luserna', 'bricherasio', 'torre']) + _date_tester( + both_path, "2010-01-01", ["villar"], ["luserna", "bricherasio", "torre"] + ) # Test exact no match - _date_tester(both_path, '2020-05-06T05:05:05', [], - ['luserna', 'bricherasio', 'torre', 'villar']) + _date_tester( + both_path, + "2020-05-06T05:05:05", + [], + ["luserna", "bricherasio", "torre", "villar"], + ) # Test intervals ################################################################################## # Test "created" date field - _date_tester(created_path, '2016-05-04/2018-05-06', - ['bricherasio', 'torre'], ['luserna', 'villar']) - _date_tester(created_path, '2016-05-04/..', - ['bricherasio', 'torre', 'luserna'], ['villar']) - _date_tester(created_path, '2016-05-04/', - ['bricherasio', 'torre', 'luserna'], ['villar']) - _date_tester(created_path, '2100-05-04/', [], - ['luserna', 'bricherasio', 'torre', 'villar']) - _date_tester(created_path, '2100-05-04/..', [], - ['luserna', 'bricherasio', 'torre', 'villar']) - _date_tester(created_path, '/2018-05-06', - ['bricherasio', 'torre', 'villar'], ['luserna']) - _date_tester(created_path, '../2018-05-06', - ['bricherasio', 'torre', 'villar'], ['luserna']) + _date_tester( + created_path, + "2016-05-04/2018-05-06", + ["bricherasio", "torre"], + ["luserna", "villar"], + ) + _date_tester( + created_path, + "2016-05-04/..", + ["bricherasio", "torre", "luserna"], + ["villar"], + ) + _date_tester( + created_path, "2016-05-04/", ["bricherasio", "torre", "luserna"], ["villar"] + ) + _date_tester( + created_path, + "2100-05-04/", + [], + ["luserna", "bricherasio", "torre", "villar"], + ) + _date_tester( + created_path, + "2100-05-04/..", + [], + ["luserna", "bricherasio", "torre", "villar"], + ) + _date_tester( + created_path, "/2018-05-06", ["bricherasio", "torre", "villar"], ["luserna"] + ) + _date_tester( + created_path, + "../2018-05-06", + ["bricherasio", "torre", "villar"], + ["luserna"], + ) # Test datetimes on "created" date field - _date_tester(created_path, '2016-05-04T01:01:01/2018-05-06T01:01:01', ['bricherasio', 'torre'], - ['luserna', 'villar']) - _date_tester(created_path, '2016-05-04T01:01:01/..', - ['bricherasio', 'torre', 'luserna'], ['villar']) - _date_tester(created_path, '2016-05-04T01:01:01/', - ['bricherasio', 'torre', 'luserna'], ['villar']) - _date_tester(created_path, '2100-05-04T01:01:01/', [], - ['luserna', 'bricherasio', 'torre', 'villar']) - _date_tester(created_path, '2100-05-04T01:01:01/..', [], - ['luserna', 'bricherasio', 'torre', 'villar']) - _date_tester(created_path, '/2018-05-06T01:01:01', - ['bricherasio', 'torre', 'villar'], ['luserna']) - _date_tester(created_path, '../2018-05-06T01:01:01', - ['bricherasio', 'torre', 'villar'], ['luserna']) + _date_tester( + created_path, + "2016-05-04T01:01:01/2018-05-06T01:01:01", + ["bricherasio", "torre"], + ["luserna", "villar"], + ) + _date_tester( + created_path, + "2016-05-04T01:01:01/..", + ["bricherasio", "torre", "luserna"], + ["villar"], + ) + _date_tester( + created_path, + "2016-05-04T01:01:01/", + ["bricherasio", "torre", "luserna"], + ["villar"], + ) + _date_tester( + created_path, + "2100-05-04T01:01:01/", + [], + ["luserna", "bricherasio", "torre", "villar"], + ) + _date_tester( + created_path, + "2100-05-04T01:01:01/..", + [], + ["luserna", "bricherasio", "torre", "villar"], + ) + _date_tester( + created_path, + "/2018-05-06T01:01:01", + ["bricherasio", "torre", "villar"], + ["luserna"], + ) + _date_tester( + created_path, + "../2018-05-06T01:01:01", + ["bricherasio", "torre", "villar"], + ["luserna"], + ) ################################################################################## # Test "updated" date field - _date_tester(updated_path, '2020-05-04/2022-12-31', - ['torre', 'luserna'], ['bricherasio', 'villar']) - _date_tester(updated_path, '2020-05-04/..', - ['torre', 'luserna'], ['bricherasio', 'villar']) - _date_tester(updated_path, '2020-05-04/', - ['torre', 'luserna'], ['bricherasio', 'villar']) - _date_tester(updated_path, '2019-01-01/', - ['torre', 'luserna', 'bricherasio'], ['villar']) - _date_tester(updated_path, '2019-01-01/..', - ['torre', 'luserna', 'bricherasio'], ['villar']) - _date_tester(updated_path, '/2020-02-02', - ['villar', 'bricherasio'], ['torre', 'luserna']) - _date_tester(updated_path, '../2020-02-02', - ['villar', 'bricherasio'], ['torre', 'luserna']) + _date_tester( + updated_path, + "2020-05-04/2022-12-31", + ["torre", "luserna"], + ["bricherasio", "villar"], + ) + _date_tester( + updated_path, + "2020-05-04/..", + ["torre", "luserna"], + ["bricherasio", "villar"], + ) + _date_tester( + updated_path, "2020-05-04/", ["torre", "luserna"], ["bricherasio", "villar"] + ) + _date_tester( + updated_path, "2019-01-01/", ["torre", "luserna", "bricherasio"], ["villar"] + ) + _date_tester( + updated_path, + "2019-01-01/..", + ["torre", "luserna", "bricherasio"], + ["villar"], + ) + _date_tester( + updated_path, "/2020-02-02", ["villar", "bricherasio"], ["torre", "luserna"] + ) + _date_tester( + updated_path, + "../2020-02-02", + ["villar", "bricherasio"], + ["torre", "luserna"], + ) # Test datetimes on "updated" datetime field - _date_tester(updated_path, '2020-05-04T01:01:01/2022-12-31T01:01:01', ['torre', 'luserna'], - ['bricherasio', 'villar']) - _date_tester(updated_path, '2020-05-04T01:01:01/..', - ['torre', 'luserna'], ['bricherasio', 'villar']) - _date_tester(updated_path, '2020-05-04T01:01:01/', - ['torre', 'luserna'], ['bricherasio', 'villar']) - _date_tester(updated_path, '2019-01-01T01:01:01/', - ['torre', 'luserna', 'bricherasio'], ['villar']) - _date_tester(updated_path, '2019-01-01T01:01:01/..', - ['torre', 'luserna', 'bricherasio'], ['villar']) - _date_tester(updated_path, '/2020-02-02T01:01:01', - ['villar', 'bricherasio'], ['torre', 'luserna']) - _date_tester(updated_path, '../2020-02-02T01:01:01', - ['villar', 'bricherasio'], ['torre', 'luserna']) + _date_tester( + updated_path, + "2020-05-04T01:01:01/2022-12-31T01:01:01", + ["torre", "luserna"], + ["bricherasio", "villar"], + ) + _date_tester( + updated_path, + "2020-05-04T01:01:01/..", + ["torre", "luserna"], + ["bricherasio", "villar"], + ) + _date_tester( + updated_path, + "2020-05-04T01:01:01/", + ["torre", "luserna"], + ["bricherasio", "villar"], + ) + _date_tester( + updated_path, + "2019-01-01T01:01:01/", + ["torre", "luserna", "bricherasio"], + ["villar"], + ) + _date_tester( + updated_path, + "2019-01-01T01:01:01/..", + ["torre", "luserna", "bricherasio"], + ["villar"], + ) + _date_tester( + updated_path, + "/2020-02-02T01:01:01", + ["villar", "bricherasio"], + ["torre", "luserna"], + ) + _date_tester( + updated_path, + "../2020-02-02T01:01:01", + ["villar", "bricherasio"], + ["torre", "luserna"], + ) ################################################################################## # Test both - _date_tester(both_path, '2010-01-01', - ['villar'], ['luserna', 'bricherasio']) - _date_tester(both_path, '2010-01-01/2010-01-01', - ['villar'], ['luserna', 'bricherasio']) - _date_tester(both_path, '2017-01-01/2021-01-01', - ['torre', 'bricherasio'], ['luserna', 'villar']) - _date_tester(both_path, '../2021-01-01', - ['torre', 'bricherasio', 'villar'], ['luserna']) - _date_tester(both_path, '2019-01-01/..', - ['luserna'], ['torre', 'bricherasio', 'villar']) + _date_tester(both_path, "2010-01-01", ["villar"], ["luserna", "bricherasio"]) + _date_tester( + both_path, "2010-01-01/2010-01-01", ["villar"], ["luserna", "bricherasio"] + ) + _date_tester( + both_path, + "2017-01-01/2021-01-01", + ["torre", "bricherasio"], + ["luserna", "villar"], + ) + _date_tester( + both_path, "../2021-01-01", ["torre", "bricherasio", "villar"], ["luserna"] + ) + _date_tester( + both_path, "2019-01-01/..", ["luserna"], ["torre", "bricherasio", "villar"] + ) ################################################################################## # Test none path (should take the first date/datetime field, that is "created") - _date_tester(none_path, '2016-05-04/2018-05-06', - ['bricherasio', 'torre'], ['luserna', 'villar']) - _date_tester(none_path, '2016-05-04/..', - ['bricherasio', 'torre', 'luserna'], ['villar']) - _date_tester(none_path, '2016-05-04/', - ['bricherasio', 'torre', 'luserna'], ['villar']) - _date_tester(none_path, '2100-05-04/', [], - ['luserna', 'bricherasio', 'torre', 'villar']) - _date_tester(none_path, '2100-05-04/..', [], - ['luserna', 'bricherasio', 'torre', 'villar']) - _date_tester(none_path, '/2018-05-06', - ['bricherasio', 'torre', 'villar'], ['luserna']) - _date_tester(none_path, '../2018-05-06', - ['bricherasio', 'torre', 'villar'], ['luserna']) + _date_tester( + none_path, + "2016-05-04/2018-05-06", + ["bricherasio", "torre"], + ["luserna", "villar"], + ) + _date_tester( + none_path, "2016-05-04/..", ["bricherasio", "torre", "luserna"], ["villar"] + ) + _date_tester( + none_path, "2016-05-04/", ["bricherasio", "torre", "luserna"], ["villar"] + ) + _date_tester( + none_path, "2100-05-04/", [], ["luserna", "bricherasio", "torre", "villar"] + ) + _date_tester( + none_path, + "2100-05-04/..", + [], + ["luserna", "bricherasio", "torre", "villar"], + ) + _date_tester( + none_path, "/2018-05-06", ["bricherasio", "torre", "villar"], ["luserna"] + ) + _date_tester( + none_path, "../2018-05-06", ["bricherasio", "torre", "villar"], ["luserna"] + ) # Test datetimes on "created" date field - _date_tester(none_path, '2016-05-04T01:01:01/2018-05-06T01:01:01', ['bricherasio', 'torre'], - ['luserna', 'villar']) - _date_tester(none_path, '2016-05-04T01:01:01/..', - ['bricherasio', 'torre', 'luserna'], ['villar']) - _date_tester(none_path, '2016-05-04T01:01:01/', - ['bricherasio', 'torre', 'luserna'], ['villar']) - _date_tester(none_path, '2100-05-04T01:01:01/', [], - ['luserna', 'bricherasio', 'torre', 'villar']) - _date_tester(none_path, '2100-05-04T01:01:01/..', [], - ['luserna', 'bricherasio', 'torre', 'villar']) - _date_tester(none_path, '/2018-05-06T01:01:01', - ['bricherasio', 'torre', 'villar'], ['luserna']) - _date_tester(none_path, '../2018-05-06T01:01:01', - ['bricherasio', 'torre', 'villar'], ['luserna']) + _date_tester( + none_path, + "2016-05-04T01:01:01/2018-05-06T01:01:01", + ["bricherasio", "torre"], + ["luserna", "villar"], + ) + _date_tester( + none_path, + "2016-05-04T01:01:01/..", + ["bricherasio", "torre", "luserna"], + ["villar"], + ) + _date_tester( + none_path, + "2016-05-04T01:01:01/", + ["bricherasio", "torre", "luserna"], + ["villar"], + ) + _date_tester( + none_path, + "2100-05-04T01:01:01/", + [], + ["luserna", "bricherasio", "torre", "villar"], + ) + _date_tester( + none_path, + "2100-05-04T01:01:01/..", + [], + ["luserna", "bricherasio", "torre", "villar"], + ) + _date_tester( + none_path, + "/2018-05-06T01:01:01", + ["bricherasio", "torre", "villar"], + ["luserna"], + ) + _date_tester( + none_path, + "../2018-05-06T01:01:01", + ["bricherasio", "torre", "villar"], + ["luserna"], + ) ##################################################################################################### # Test ranges - _date_tester(date_range_path, '2000-05-05T01:01:01', [], - ['bricherasio', 'villar', 'luserna', 'torre']) - _date_tester(date_range_path, '2020-05-05T01:01:01', - ['luserna', 'torre'], ['bricherasio', 'villar']) - _date_tester(date_range_path, '../2000-05-05T01:01:01', [], - ['luserna', 'torre', 'bricherasio', 'villar']) - _date_tester(date_range_path, '../2017-05-05T01:01:01', - ['bricherasio', 'villar'], ['luserna', 'torre']) - _date_tester(date_range_path, '../2050-05-05T01:01:01', - ['bricherasio', 'villar', 'luserna', 'torre'], []) - _date_tester(date_range_path, '2020-05-05T01:01:01/', - ['luserna', 'torre'], ['bricherasio', 'villar']) - - _date_tester(date_range_path, '2000-05-05', [], - ['bricherasio', 'villar', 'luserna', 'torre']) - _date_tester(date_range_path, '2020-05-05', - ['luserna', 'torre'], ['bricherasio', 'villar']) - _date_tester(date_range_path, '../2000-05-05', [], - ['luserna', 'torre', 'bricherasio', 'villar']) - _date_tester(date_range_path, '../2017-05-05', - ['bricherasio', 'villar'], ['luserna', 'torre']) - _date_tester(date_range_path, '../2050-05-05', - ['bricherasio', 'villar', 'luserna', 'torre'], []) - _date_tester(date_range_path, '2020-05-05/', - ['luserna', 'torre'], ['bricherasio', 'villar']) + _date_tester( + date_range_path, + "2000-05-05T01:01:01", + [], + ["bricherasio", "villar", "luserna", "torre"], + ) + _date_tester( + date_range_path, + "2020-05-05T01:01:01", + ["luserna", "torre"], + ["bricherasio", "villar"], + ) + _date_tester( + date_range_path, + "../2000-05-05T01:01:01", + [], + ["luserna", "torre", "bricherasio", "villar"], + ) + _date_tester( + date_range_path, + "../2017-05-05T01:01:01", + ["bricherasio", "villar"], + ["luserna", "torre"], + ) + _date_tester( + date_range_path, + "../2050-05-05T01:01:01", + ["bricherasio", "villar", "luserna", "torre"], + [], + ) + _date_tester( + date_range_path, + "2020-05-05T01:01:01/", + ["luserna", "torre"], + ["bricherasio", "villar"], + ) + + _date_tester( + date_range_path, + "2000-05-05", + [], + ["bricherasio", "villar", "luserna", "torre"], + ) + _date_tester( + date_range_path, + "2020-05-05", + ["luserna", "torre"], + ["bricherasio", "villar"], + ) + _date_tester( + date_range_path, + "../2000-05-05", + [], + ["luserna", "torre", "bricherasio", "villar"], + ) + _date_tester( + date_range_path, + "../2017-05-05", + ["bricherasio", "villar"], + ["luserna", "torre"], + ) + _date_tester( + date_range_path, + "../2050-05-05", + ["bricherasio", "villar", "luserna", "torre"], + [], + ) + _date_tester( + date_range_path, + "2020-05-05/", + ["luserna", "torre"], + ["bricherasio", "villar"], + ) # Test bad requests request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/points/items?datetime=bad timing!') + "http://server.qgis.org/wfs3/collections/points/items?datetime=bad timing!" + ) response = QgsBufferServerResponse() project.read(created_path) self.server.handleRequest(request, response, project) @@ -1923,7 +2639,13 @@ def handleRequest(self, context): def parameters(self, context): return [ - QgsServerQueryStringParameter('value1', True, QgsServerQueryStringParameter.Type.Double, 'a double value')] + QgsServerQueryStringParameter( + "value1", + True, + QgsServerQueryStringParameter.Type.Double, + "a double value", + ) + ] class Handler2(QgsServerOgcApiHandler): @@ -1955,9 +2677,18 @@ def handleRequest(self, context): def parameters(self, context): return [ QgsServerQueryStringParameter( - 'value1', True, QgsServerQueryStringParameter.Type.Double, 'a double value'), - QgsServerQueryStringParameter('value2', False, QgsServerQueryStringParameter.Type.String, - 'a string value'), ] + "value1", + True, + QgsServerQueryStringParameter.Type.Double, + "a double value", + ), + QgsServerQueryStringParameter( + "value2", + False, + QgsServerQueryStringParameter.Type.String, + "a string value", + ), + ] class Handler3(QgsServerOgcApiHandler): @@ -1995,7 +2726,13 @@ def handleRequest(self, context): def parameters(self, context): return [ - QgsServerQueryStringParameter('value1', True, QgsServerQueryStringParameter.Type.Double, 'a double value')] + QgsServerQueryStringParameter( + "value1", + True, + QgsServerQueryStringParameter.Type.Double, + "a double value", + ) + ] def templatePath(self, context): if self.templatePathOverride is None: @@ -2067,138 +2804,170 @@ def handleRequest(self, context): def parameters(self, context): return [ - QgsServerQueryStringParameter('value1', True, QgsServerQueryStringParameter.Type.Double, 'a double value')] + QgsServerQueryStringParameter( + "value1", + True, + QgsServerQueryStringParameter.Type.Double, + "a double value", + ) + ] class QgsServerOgcAPITest(QgsServerAPITestBase): - """ QGIS OGC API server tests""" + """QGIS OGC API server tests""" def testOgcApi(self): """Test OGC API""" - api = QgsServerOgcApi(self.server.serverInterface(), - '/api1', 'apione', 'an api', '1.1') - self.assertEqual(api.name(), 'apione') - self.assertEqual(api.description(), 'an api') - self.assertEqual(api.version(), '1.1') - self.assertEqual(api.rootPath(), '/api1') - url = 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=-1' - self.assertEqual(api.sanitizeUrl(QtCore.QUrl(url)).toString(), - 'http://server.qgis.org/wfs3/collections/testlayer \xe8\xe9/items?limit=-1') - self.assertEqual(api.sanitizeUrl(QtCore.QUrl('/path//double//slashes//#fr')).toString(), - '/path/double/slashes#fr') - self.assertEqual(api.relToString(QgsServerOgcApi.data), 'data') - self.assertEqual(api.relToString( - QgsServerOgcApi.alternate), 'alternate') - self.assertEqual(api.contentTypeToString(QgsServerOgcApi.JSON), 'JSON') - self.assertEqual(api.contentTypeToStdString( - QgsServerOgcApi.JSON), 'JSON') - self.assertEqual(api.contentTypeToExtension( - QgsServerOgcApi.JSON), 'json') - self.assertEqual(api.contentTypeToExtension( - QgsServerOgcApi.GEOJSON), 'geojson') + api = QgsServerOgcApi( + self.server.serverInterface(), "/api1", "apione", "an api", "1.1" + ) + self.assertEqual(api.name(), "apione") + self.assertEqual(api.description(), "an api") + self.assertEqual(api.version(), "1.1") + self.assertEqual(api.rootPath(), "/api1") + url = "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=-1" + self.assertEqual( + api.sanitizeUrl(QtCore.QUrl(url)).toString(), + "http://server.qgis.org/wfs3/collections/testlayer \xe8\xe9/items?limit=-1", + ) + self.assertEqual( + api.sanitizeUrl(QtCore.QUrl("/path//double//slashes//#fr")).toString(), + "/path/double/slashes#fr", + ) + self.assertEqual(api.relToString(QgsServerOgcApi.data), "data") + self.assertEqual(api.relToString(QgsServerOgcApi.alternate), "alternate") + self.assertEqual(api.contentTypeToString(QgsServerOgcApi.JSON), "JSON") + self.assertEqual(api.contentTypeToStdString(QgsServerOgcApi.JSON), "JSON") + self.assertEqual(api.contentTypeToExtension(QgsServerOgcApi.JSON), "json") + self.assertEqual(api.contentTypeToExtension(QgsServerOgcApi.GEOJSON), "geojson") def testOgcApiHandler(self): """Test OGC API Handler""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=-1') + "http://server.qgis.org/wfs3/collections/testlayer%20èé/items?limit=-1" + ) response = QgsBufferServerResponse() ctx = QgsServerApiContext( - '/services/api1', request, response, project, self.server.serverInterface()) + "/services/api1", request, response, project, self.server.serverInterface() + ) h = Handler1() - self.assertTrue(h.staticPath(ctx).endswith( - '/resources/server/api/ogc/static')) + self.assertTrue(h.staticPath(ctx).endswith("/resources/server/api/ogc/static")) self.assertEqual(h.path(), QtCore.QRegularExpression("/handlerone")) - self.assertEqual(h.description(), 'The first handler ever') - self.assertEqual(h.operationId(), 'handlerOne') - self.assertEqual(h.summary(), 'First of its name') - self.assertEqual(h.linkTitle(), 'Handler One Link Title') + self.assertEqual(h.description(), "The first handler ever") + self.assertEqual(h.operationId(), "handlerOne") + self.assertEqual(h.summary(), "First of its name") + self.assertEqual(h.linkTitle(), "Handler One Link Title") self.assertEqual(h.linkType(), QgsServerOgcApi.data) with self.assertRaises(QgsServerApiBadRequestException) as ex: h.handleRequest(ctx) - self.assertEqual(str(ex.exception), - 'Missing required argument: \'value1\'') + self.assertEqual(str(ex.exception), "Missing required argument: 'value1'") r = ctx.response() - self.assertEqual(r.data(), '') + self.assertEqual(r.data(), "") with self.assertRaises(QgsServerApiBadRequestException) as ex: h.values(ctx) - self.assertEqual(str(ex.exception), - 'Missing required argument: \'value1\'') + self.assertEqual(str(ex.exception), "Missing required argument: 'value1'") # Add handler to API and test for /api2 ctx = QgsServerApiContext( - '/services/api2', request, response, project, self.server.serverInterface()) - api = QgsServerOgcApi(self.server.serverInterface(), - '/api2', 'apitwo', 'a second api', '1.2') + "/services/api2", request, response, project, self.server.serverInterface() + ) + api = QgsServerOgcApi( + self.server.serverInterface(), "/api2", "apitwo", "a second api", "1.2" + ) api.registerHandler(h) # Add a second handler (will be tested later) h2 = Handler2() api.registerHandler(h2) - ctx.request().setUrl(QtCore.QUrl('http://www.qgis.org/services/api1')) + ctx.request().setUrl(QtCore.QUrl("http://www.qgis.org/services/api1")) with self.assertRaises(QgsServerApiBadRequestException) as ex: api.executeRequest(ctx) self.assertEqual( - str(ex.exception), 'Requested URI does not match any registered API handler') + str(ex.exception), "Requested URI does not match any registered API handler" + ) - ctx.request().setUrl(QtCore.QUrl('http://www.qgis.org/services/api2')) + ctx.request().setUrl(QtCore.QUrl("http://www.qgis.org/services/api2")) with self.assertRaises(QgsServerApiBadRequestException) as ex: api.executeRequest(ctx) self.assertEqual( - str(ex.exception), 'Requested URI does not match any registered API handler') + str(ex.exception), "Requested URI does not match any registered API handler" + ) - ctx.request().setUrl(QtCore.QUrl('http://www.qgis.org/services/api2/handlerone')) + ctx.request().setUrl( + QtCore.QUrl("http://www.qgis.org/services/api2/handlerone") + ) with self.assertRaises(QgsServerApiBadRequestException) as ex: api.executeRequest(ctx) - self.assertEqual(str(ex.exception), - 'Missing required argument: \'value1\'') + self.assertEqual(str(ex.exception), "Missing required argument: 'value1'") - ctx.request().setUrl(QtCore.QUrl( - 'http://www.qgis.org/services/api2/handlerone?value1=not+a+double')) + ctx.request().setUrl( + QtCore.QUrl( + "http://www.qgis.org/services/api2/handlerone?value1=not+a+double" + ) + ) with self.assertRaises(QgsServerApiBadRequestException) as ex: api.executeRequest(ctx) self.assertEqual( - str(ex.exception), 'Argument \'value1\' could not be converted to Double') + str(ex.exception), "Argument 'value1' could not be converted to Double" + ) - ctx.request().setUrl(QtCore.QUrl( - 'http://www.qgis.org/services/api2/handlerone?value1=1.2345')) + ctx.request().setUrl( + QtCore.QUrl("http://www.qgis.org/services/api2/handlerone?value1=1.2345") + ) params = h.values(ctx) - self.assertEqual(params, {'value1': 1.2345}) + self.assertEqual(params, {"value1": 1.2345}) api.executeRequest(ctx) - self.assertEqual(json.loads(bytes(ctx.response().data()))[ - 'value1'], 1.2345) + self.assertEqual(json.loads(bytes(ctx.response().data()))["value1"], 1.2345) # Test path fragments extraction - ctx.request().setUrl(QtCore.QUrl( - 'http://www.qgis.org/services/api2/handlertwo/00/555?value1=1.2345')) + ctx.request().setUrl( + QtCore.QUrl( + "http://www.qgis.org/services/api2/handlertwo/00/555?value1=1.2345" + ) + ) params = h2.values(ctx) - self.assertEqual( - params, {'code1': '00', 'value1': 1.2345, 'value2': None}) + self.assertEqual(params, {"code1": "00", "value1": 1.2345, "value2": None}) # Test string encoding ctx.request().setUrl( - QtCore.QUrl('http://www.qgis.org/services/api2/handlertwo/00/555?value1=1.2345&value2=a%2Fstring%20some')) + QtCore.QUrl( + "http://www.qgis.org/services/api2/handlertwo/00/555?value1=1.2345&value2=a%2Fstring%20some" + ) + ) params = h2.values(ctx) self.assertEqual( - params, {'code1': '00', 'value1': 1.2345, 'value2': 'a/string some'}) + params, {"code1": "00", "value1": 1.2345, "value2": "a/string some"} + ) # Test links - self.assertEqual(h2.href(ctx), - 'http://www.qgis.org/services/api2/handlertwo/00/555?value1=1.2345&value2=a%2Fstring%20some') - self.assertEqual(h2.href(ctx, '/extra'), - 'http://www.qgis.org/services/api2/handlertwo/00/555/extra?value1=1.2345&value2=a%2Fstring%20some') - self.assertEqual(h2.href(ctx, '/extra', 'json'), - 'http://www.qgis.org/services/api2/handlertwo/00/555/extra.json?value1=1.2345&value2=a%2Fstring%20some') + self.assertEqual( + h2.href(ctx), + "http://www.qgis.org/services/api2/handlertwo/00/555?value1=1.2345&value2=a%2Fstring%20some", + ) + self.assertEqual( + h2.href(ctx, "/extra"), + "http://www.qgis.org/services/api2/handlertwo/00/555/extra?value1=1.2345&value2=a%2Fstring%20some", + ) + self.assertEqual( + h2.href(ctx, "/extra", "json"), + "http://www.qgis.org/services/api2/handlertwo/00/555/extra.json?value1=1.2345&value2=a%2Fstring%20some", + ) # Test template path self.assertTrue( - h2.templatePath(ctx).endswith('/resources/server/api/ogc/templates/services/api2/handlerTwo.html')) + h2.templatePath(ctx).endswith( + "/resources/server/api/ogc/templates/services/api2/handlerTwo.html" + ) + ) del project @@ -2206,49 +2975,55 @@ def testOgcApiHandlerContentType(self): """Test OGC API Handler content types""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) request = QgsBufferServerRequest( - 'http://server.qgis.org/api3/handlerthree?value1=9.5') + "http://server.qgis.org/api3/handlerthree?value1=9.5" + ) response = QgsBufferServerResponse() # Add handler to API and test for /api3 ctx = QgsServerApiContext( - '/services/api3', request, response, project, self.server.serverInterface()) - api = QgsServerOgcApi(self.server.serverInterface(), - '/api3', 'apithree', 'a third api', '1.2') + "/services/api3", request, response, project, self.server.serverInterface() + ) + api = QgsServerOgcApi( + self.server.serverInterface(), "/api3", "apithree", "a third api", "1.2" + ) h3 = Handler3() api.registerHandler(h3) ctx = QgsServerApiContext( - '/services/api3/', request, response, project, self.server.serverInterface()) + "/services/api3/", request, response, project, self.server.serverInterface() + ) api.executeRequest(ctx) - self.assertEqual(json.loads( - bytes(ctx.response().data()))['value1'], 9.5) + self.assertEqual(json.loads(bytes(ctx.response().data()))["value1"], 9.5) # Call HTML - ctx.request().setUrl(QtCore.QUrl( - 'http://server.qgis.org/api3/handlerthree.html?value1=9.5')) + ctx.request().setUrl( + QtCore.QUrl("http://server.qgis.org/api3/handlerthree.html?value1=9.5") + ) with self.assertRaises(QgsServerApiBadRequestException) as ex: api.executeRequest(ctx) - self.assertEqual(str(ex.exception), 'Unsupported Content-Type: HTML') + self.assertEqual(str(ex.exception), "Unsupported Content-Type: HTML") h3.setContentTypes([QgsServerOgcApi.HTML]) with self.assertRaises(QgsServerApiBadRequestException) as ex: api.executeRequest(ctx) - self.assertEqual(str(ex.exception), - 'Template not found: handlerThree.html') + self.assertEqual(str(ex.exception), "Template not found: handlerThree.html") # Define a template path tmpDir = QtCore.QTemporaryDir() - with open(tmpDir.path() + '/handlerThree.html', 'w+') as f: + with open(tmpDir.path() + "/handlerThree.html", "w+") as f: f.write("Hello world") - h3.templatePathOverride = tmpDir.path() + '/handlerThree.html' + h3.templatePathOverride = tmpDir.path() + "/handlerThree.html" ctx.response().clear() api.executeRequest(ctx) self.assertEqual(bytes(ctx.response().data()), b"Hello world") req = QgsBufferServerRequest( - 'http://localhost:8000/project/7ecb/wfs3/collections/zg.grundnutzung.html') + "http://localhost:8000/project/7ecb/wfs3/collections/zg.grundnutzung.html" + ) self.assertEqual(h3.contentTypeFromRequest(req), QgsServerOgcApi.HTML) del project @@ -2257,45 +3032,57 @@ def testOgcApiHandlerException(self): """Test OGC API Handler exception""" project = QgsProject() - project.read(os.path.join(self.temporary_path, 'qgis_server', 'test_project_api.qgs')) - request = QgsBufferServerRequest('') + project.read( + os.path.join(self.temporary_path, "qgis_server", "test_project_api.qgs") + ) + request = QgsBufferServerRequest("") response = QgsBufferServerResponse() ctx = QgsServerApiContext( - '/services/apiexception', request, response, project, self.server.serverInterface()) + "/services/apiexception", + request, + response, + project, + self.server.serverInterface(), + ) h = HandlerException() - api = QgsServerOgcApi(self.server.serverInterface(), - '/apiexception', 'apiexception', 'an api with exception', '1.2') + api = QgsServerOgcApi( + self.server.serverInterface(), + "/apiexception", + "apiexception", + "an api with exception", + "1.2", + ) api.registerHandler(h) h.setException(Exception("UTF-8 Exception 1 $ù~à^£")) - ctx.request().setUrl(QtCore.QUrl('http://www.qgis.org/handlerexception')) + ctx.request().setUrl(QtCore.QUrl("http://www.qgis.org/handlerexception")) with self.assertRaises(QgsServerApiBadRequestException) as ex: api.executeRequest(ctx) - self.assertEqual( - str(ex.exception), "UTF-8 Exception 1 $ù~à^£") + self.assertEqual(str(ex.exception), "UTF-8 Exception 1 $ù~à^£") h.setException(QgsServerApiBadRequestException("UTF-8 Exception 2 $ù~à^£")) - ctx.request().setUrl(QtCore.QUrl('http://www.qgis.org/handlerexception')) + ctx.request().setUrl(QtCore.QUrl("http://www.qgis.org/handlerexception")) with self.assertRaises(QgsServerApiBadRequestException) as ex: api.executeRequest(ctx) - self.assertEqual( - str(ex.exception), "UTF-8 Exception 2 $ù~à^£") + self.assertEqual(str(ex.exception), "UTF-8 Exception 2 $ù~à^£") del project def test_path_capture(self): """Test issue GH #45439""" - api = QgsServerOgcApi(self.server.serverInterface(), - '/api4', 'apifour', 'a fourth api', '1.2') + api = QgsServerOgcApi( + self.server.serverInterface(), "/api4", "apifour", "a fourth api", "1.2" + ) h4 = Handler4() api.registerHandler(h4) request = QgsBufferServerRequest( - 'http://localhost:19876/api4/france_parts.json?MAP=france_parts') + "http://localhost:19876/api4/france_parts.json?MAP=france_parts" + ) response = QgsBufferServerResponse() server = QgsServer() @@ -2304,11 +3091,13 @@ def test_path_capture(self): server.handleRequest(request, response) - self.assertEqual(h4.params, {'tilemapid': 'france_parts.json'}) + self.assertEqual(h4.params, {"tilemapid": "france_parts.json"}) ctx = QgsServerApiContext(api.rootPath(), request, response, None, iface) - self.assertEqual(h4.href(ctx), 'http://localhost:19876/api4/france_parts?MAP=france_parts') + self.assertEqual( + h4.href(ctx), "http://localhost:19876/api4/france_parts?MAP=france_parts" + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_apicontext.py b/tests/src/python/test_qgsserver_apicontext.py index 798fd2643044..b5f857bbb749 100644 --- a/tests/src/python/test_qgsserver_apicontext.py +++ b/tests/src/python/test_qgsserver_apicontext.py @@ -8,14 +8,15 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '11/07/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "11/07/2019" +__copyright__ = "Copyright 2019, The QGIS Project" import os # Deterministic XML -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" from qgis.server import ( QgsBufferServerRequest, @@ -27,7 +28,7 @@ class QgsServerApiContextsTest(QgsServerTestBase): - """ QGIS Server API context tests""" + """QGIS Server API context tests""" def testMatchedPath(self): """Test path extraction""" @@ -37,14 +38,18 @@ def testMatchedPath(self): context = QgsServerApiContext("/wfs3", request, response, None, None) self.assertEqual(context.matchedPath(), "/services/wfs3") - request = QgsBufferServerRequest("http://www.qgis.org/services/wfs3/collections.hml") + request = QgsBufferServerRequest( + "http://www.qgis.org/services/wfs3/collections.hml" + ) context = QgsServerApiContext("/wfs3", request, response, None, None) self.assertEqual(context.matchedPath(), "/services/wfs3") - request = QgsBufferServerRequest("http://www.qgis.org/services/wfs3/collections.hml") + request = QgsBufferServerRequest( + "http://www.qgis.org/services/wfs3/collections.hml" + ) context = QgsServerApiContext("/wfs4", request, response, None, None) self.assertEqual(context.matchedPath(), "") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_cachemanager.py b/tests/src/python/test_qgsserver_cachemanager.py index 51559e28e439..e905a15f7c26 100644 --- a/tests/src/python/test_qgsserver_cachemanager.py +++ b/tests/src/python/test_qgsserver_cachemanager.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'René-Luc DHONT' -__date__ = '19/07/2018' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "René-Luc DHONT" +__date__ = "19/07/2018" +__copyright__ = "Copyright 2015, The QGIS Project" import hashlib import os @@ -34,7 +35,7 @@ class PyServerCache(QgsServerCacheFilter): - """ Used to have restriction access """ + """Used to have restriction access""" # Be able to deactivate the access control to have a reference point _active = False @@ -46,7 +47,7 @@ def __init__(self, server_iface): if not os.path.exists(self._cache_dir): os.mkdir(self._cache_dir) - self._tile_cache_dir = os.path.join(self._cache_dir, 'tiles') + self._tile_cache_dir = os.path.join(self._cache_dir, "tiles") if not os.path.exists(self._tile_cache_dir): os.mkdir(self._tile_cache_dir) @@ -54,7 +55,7 @@ def getCachedDocument(self, project, request, key): m = hashlib.md5() paramMap = request.parameters() urlParam = "&".join([f"{k}={paramMap[k]}" for k in paramMap.keys()]) - m.update(urlParam.encode('utf8')) + m.update(urlParam.encode("utf8")) if not os.path.exists(os.path.join(self._cache_dir, m.hexdigest() + ".xml")): return QByteArray() @@ -63,8 +64,10 @@ def getCachedDocument(self, project, request, key): with open(os.path.join(self._cache_dir, m.hexdigest() + ".xml")) as f: statusOK, errorStr, errorLine, errorColumn = doc.setContent(f.read(), True) if not statusOK: - print("Could not read or find the contents document. Error at line %d, column %d:\n%s" % ( - errorLine, errorColumn, errorStr)) + print( + "Could not read or find the contents document. Error at line %d, column %d:\n%s" + % (errorLine, errorColumn, errorStr) + ) return QByteArray() return doc.toByteArray() @@ -76,7 +79,7 @@ def setCachedDocument(self, doc, project, request, key): m = hashlib.md5() paramMap = request.parameters() urlParam = "&".join([f"{k}={paramMap[k]}" for k in paramMap.keys()]) - m.update(urlParam.encode('utf8')) + m.update(urlParam.encode("utf8")) with open(os.path.join(self._cache_dir, m.hexdigest() + ".xml"), "w") as f: f.write(doc.toString()) return os.path.exists(os.path.join(self._cache_dir, m.hexdigest() + ".xml")) @@ -85,7 +88,7 @@ def deleteCachedDocument(self, project, request, key): m = hashlib.md5() paramMap = request.parameters() urlParam = "&".join([f"{k}={paramMap[k]}" for k in paramMap.keys()]) - m.update(urlParam.encode('utf8')) + m.update(urlParam.encode("utf8")) if os.path.exists(os.path.join(self._cache_dir, m.hexdigest() + ".xml")): os.remove(os.path.join(self._cache_dir, m.hexdigest() + ".xml")) return not os.path.exists(os.path.join(self._cache_dir, m.hexdigest() + ".xml")) @@ -101,13 +104,17 @@ def getCachedImage(self, project, request, key): m = hashlib.md5() paramMap = request.parameters() urlParam = "&".join([f"{k}={paramMap[k]}" for k in paramMap.keys()]) - m.update(urlParam.encode('utf8')) + m.update(urlParam.encode("utf8")) - if not os.path.exists(os.path.join(self._tile_cache_dir, m.hexdigest() + ".png")): + if not os.path.exists( + os.path.join(self._tile_cache_dir, m.hexdigest() + ".png") + ): return QByteArray() img = QImage(m.hexdigest() + ".png") - with open(os.path.join(self._tile_cache_dir, m.hexdigest() + ".png"), "rb") as f: + with open( + os.path.join(self._tile_cache_dir, m.hexdigest() + ".png"), "rb" + ) as f: statusOK = img.loadFromData(f.read()) if not statusOK: print("Could not read or find the contents document.") @@ -116,26 +123,32 @@ def getCachedImage(self, project, request, key): ba = QByteArray() buff = QBuffer(ba) buff.open(QIODevice.OpenModeFlag.WriteOnly) - img.save(buff, 'PNG') + img.save(buff, "PNG") return ba def setCachedImage(self, img, project, request, key): m = hashlib.md5() paramMap = request.parameters() urlParam = "&".join([f"{k}={paramMap[k]}" for k in paramMap.keys()]) - m.update(urlParam.encode('utf8')) - with open(os.path.join(self._tile_cache_dir, m.hexdigest() + ".png"), "wb") as f: + m.update(urlParam.encode("utf8")) + with open( + os.path.join(self._tile_cache_dir, m.hexdigest() + ".png"), "wb" + ) as f: f.write(img) - return os.path.exists(os.path.join(self._tile_cache_dir, m.hexdigest() + ".png")) + return os.path.exists( + os.path.join(self._tile_cache_dir, m.hexdigest() + ".png") + ) def deleteCachedImage(self, project, request, key): m = hashlib.md5() paramMap = request.parameters() urlParam = "&".join([f"{k}={paramMap[k]}" for k in paramMap.keys()]) - m.update(urlParam.encode('utf8')) + m.update(urlParam.encode("utf8")) if os.path.exists(os.path.join(self._tile_cache_dir, m.hexdigest() + ".png")): os.remove(os.path.join(self._tile_cache_dir, m.hexdigest() + ".png")) - return not os.path.exists(os.path.join(self._tile_cache_dir, m.hexdigest() + ".png")) + return not os.path.exists( + os.path.join(self._tile_cache_dir, m.hexdigest() + ".png") + ) def deleteCachedImages(self, project): filelist = [f for f in os.listdir(self._tile_cache_dir) if f.endswith(".png")] @@ -150,7 +163,7 @@ class TestQgsServerCacheManager(QgsServerTestBase): @classmethod def _handle_request(cls, qs, requestMethod=QgsServerRequest.GetMethod, data=None): if data is not None: - data = data.encode('utf-8') + data = data.encode("utf-8") request = QgsBufferServerRequest(qs, requestMethod, {}, data) response = QgsBufferServerResponse() cls.server.handleRequest(request, response) @@ -173,7 +186,7 @@ def setUpClass(cls): def _result(self, data): headers = {} - for line in data[0].decode('UTF-8').split("\n"): + for line in data[0].decode("UTF-8").split("\n"): if line != "": header = line.split(":") self.assertEqual(len(header), 2, line) @@ -229,41 +242,65 @@ def test_getcapabilities(self): header, body = self._execute_request(query_string) # without cache - query_string = '?MAP={}&SERVICE=WMTS&VERSION=1.0.0&REQUEST={}'.format( - urllib.parse.quote(project), 'GetCapabilities') + query_string = "?MAP={}&SERVICE=WMTS&VERSION=1.0.0&REQUEST={}".format( + urllib.parse.quote(project), "GetCapabilities" + ) header, body = self._execute_request(query_string) # with cache header, body = self._execute_request(query_string) - filelist = [f for f in os.listdir(self._servercache._cache_dir) if f.endswith(".xml")] - self.assertEqual(len(filelist), 6, 'Not enough file in cache') + filelist = [ + f for f in os.listdir(self._servercache._cache_dir) if f.endswith(".xml") + ] + self.assertEqual(len(filelist), 6, "Not enough file in cache") cacheManager = self._server_iface.cacheManager() - self.assertTrue(cacheManager.deleteCachedDocuments(None), 'deleteCachedDocuments does not return True') + self.assertTrue( + cacheManager.deleteCachedDocuments(None), + "deleteCachedDocuments does not return True", + ) - filelist = [f for f in os.listdir(self._servercache._cache_dir) if f.endswith(".xml")] - self.assertEqual(len(filelist), 0, 'All files in cache are not deleted ') + filelist = [ + f for f in os.listdir(self._servercache._cache_dir) if f.endswith(".xml") + ] + self.assertEqual(len(filelist), 0, "All files in cache are not deleted ") prj = QgsProject() prj.read(project) query_string = f"?MAP={urllib.parse.quote(project)}&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetCapabilities" - request = QgsBufferServerRequest(query_string, QgsServerRequest.GetMethod, {}, None) + request = QgsBufferServerRequest( + query_string, QgsServerRequest.GetMethod, {}, None + ) accessControls = self._server_iface.accessControls() cDoc = QDomDocument("wms_getcapabilities_130.xml") - self.assertFalse(cacheManager.getCachedDocument(cDoc, prj, request, accessControls), - 'getCachedDocument is not None') - - self.assertTrue(cacheManager.setCachedDocument(doc, prj, request, accessControls), 'setCachedDocument false') - - self.assertTrue(cacheManager.getCachedDocument(cDoc, prj, request, accessControls), 'getCachedDocument is None') - self.assertEqual(doc.documentElement().tagName(), cDoc.documentElement().tagName(), - 'cachedDocument not equal to provide document') + self.assertFalse( + cacheManager.getCachedDocument(cDoc, prj, request, accessControls), + "getCachedDocument is not None", + ) + + self.assertTrue( + cacheManager.setCachedDocument(doc, prj, request, accessControls), + "setCachedDocument false", + ) + + self.assertTrue( + cacheManager.getCachedDocument(cDoc, prj, request, accessControls), + "getCachedDocument is None", + ) + self.assertEqual( + doc.documentElement().tagName(), + cDoc.documentElement().tagName(), + "cachedDocument not equal to provide document", + ) - self.assertTrue(cacheManager.deleteCachedDocuments(None), 'deleteCachedDocuments does not return True') + self.assertTrue( + cacheManager.deleteCachedDocuments(None), + "deleteCachedDocuments does not return True", + ) def test_getcontext(self): project = self.projectPath @@ -275,225 +312,338 @@ def test_getcontext(self): # with cache header, body = self._execute_request(query_string) - filelist = [f for f in os.listdir(self._servercache._cache_dir) if f.endswith(".xml")] - self.assertEqual(len(filelist), 1, 'Not enough file in cache') + filelist = [ + f for f in os.listdir(self._servercache._cache_dir) if f.endswith(".xml") + ] + self.assertEqual(len(filelist), 1, "Not enough file in cache") cacheManager = self._server_iface.cacheManager() - self.assertTrue(cacheManager.deleteCachedDocuments(None), 'deleteCachedImages does not return True') + self.assertTrue( + cacheManager.deleteCachedDocuments(None), + "deleteCachedImages does not return True", + ) - filelist = [f for f in os.listdir(self._servercache._cache_dir) if f.endswith(".xml")] - self.assertEqual(len(filelist), 0, 'All files in cache are not deleted ') + filelist = [ + f for f in os.listdir(self._servercache._cache_dir) if f.endswith(".xml") + ] + self.assertEqual(len(filelist), 0, "All files in cache are not deleted ") def test_describefeaturetype(self): project = self.projectPath assert os.path.exists(project), "Project file not found: " + project - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WFS", - "VERSION": "1.1.0", - "REQUEST": "DescribeFeatureType", - "FEATURETYPE": "Country" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WFS", + "VERSION": "1.1.0", + "REQUEST": "DescribeFeatureType", + "FEATURETYPE": "Country", + }.items() + ) + ] + ) header, body = self._execute_request(qs) # with cache header, body = self._execute_request(qs) - filelist = [f for f in os.listdir(self._servercache._cache_dir) if f.endswith(".xml")] - self.assertEqual(len(filelist), 1, 'Not enough file in cache') + filelist = [ + f for f in os.listdir(self._servercache._cache_dir) if f.endswith(".xml") + ] + self.assertEqual(len(filelist), 1, "Not enough file in cache") cacheManager = self._server_iface.cacheManager() - self.assertTrue(cacheManager.deleteCachedDocuments(None), 'deleteCachedImages does not return True') + self.assertTrue( + cacheManager.deleteCachedDocuments(None), + "deleteCachedImages does not return True", + ) - filelist = [f for f in os.listdir(self._servercache._cache_dir) if f.endswith(".xml")] - self.assertEqual(len(filelist), 0, 'All files in cache are not deleted ') + filelist = [ + f for f in os.listdir(self._servercache._cache_dir) if f.endswith(".xml") + ] + self.assertEqual(len(filelist), 0, "All files in cache are not deleted ") def test_getlegendgraphic(self): project = self.projectPath assert os.path.exists(project), "Project file not found: " + project - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello", - "LAYERTITLE": "FALSE", - "RULELABEL": "FALSE", - "FORMAT": "image/png", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "LAYERTITLE": "FALSE", + "RULELABEL": "FALSE", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) # without cache r, h = self._result(self._execute_request(qs)) self.assertEqual( - h.get("Content-Type"), "image/png", - f"Content type is wrong: {h.get('Content-Type')}\n{r}") - self._img_diff_error(r, h, "WMS_GetLegendGraphic_Basic", max_size_diff=QSize(1, 1)) + h.get("Content-Type"), + "image/png", + f"Content type is wrong: {h.get('Content-Type')}\n{r}", + ) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_Basic", max_size_diff=QSize(1, 1) + ) # with cache r, h = self._result(self._execute_request(qs)) self.assertEqual( - h.get("Content-Type"), "image/png", - f"Content type is wrong: {h.get('Content-Type')}\n{r}") - self._img_diff_error(r, h, "WMS_GetLegendGraphic_Basic", max_size_diff=QSize(1, 1)) - - filelist = [f for f in os.listdir(self._servercache._tile_cache_dir) if f.endswith(".png")] - self.assertEqual(len(filelist), 1, 'Not enough image in cache') + h.get("Content-Type"), + "image/png", + f"Content type is wrong: {h.get('Content-Type')}\n{r}", + ) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_Basic", max_size_diff=QSize(1, 1) + ) + + filelist = [ + f + for f in os.listdir(self._servercache._tile_cache_dir) + if f.endswith(".png") + ] + self.assertEqual(len(filelist), 1, "Not enough image in cache") cacheManager = self._server_iface.cacheManager() - self.assertTrue(cacheManager.deleteCachedImages(None), 'deleteCachedImages does not return True') + self.assertTrue( + cacheManager.deleteCachedImages(None), + "deleteCachedImages does not return True", + ) - filelist = [f for f in os.listdir(self._servercache._tile_cache_dir) if f.endswith(".png")] - self.assertEqual(len(filelist), 0, 'All images in cache are not deleted ') + filelist = [ + f + for f in os.listdir(self._servercache._tile_cache_dir) + if f.endswith(".png") + ] + self.assertEqual(len(filelist), 0, "All images in cache are not deleted ") def test_gettile(self): project = self.projectPath assert os.path.exists(project), "Project file not found: " + project - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WMTS", - "VERSION": "1.0.0", - "REQUEST": "GetTile", - "LAYER": "Country", - "STYLE": "", - "TILEMATRIXSET": "EPSG:3857", - "TILEMATRIX": "0", - "TILEROW": "0", - "TILECOL": "0", - "FORMAT": "image/png" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WMTS", + "VERSION": "1.0.0", + "REQUEST": "GetTile", + "LAYER": "Country", + "STYLE": "", + "TILEMATRIXSET": "EPSG:3857", + "TILEMATRIX": "0", + "TILEROW": "0", + "TILECOL": "0", + "FORMAT": "image/png", + }.items() + ) + ] + ) # without cache r, h = self._result(self._execute_request(qs)) self.assertEqual( - h.get("Content-Type"), "image/png", - f"Content type is wrong: {h.get('Content-Type')}\n{r}") + h.get("Content-Type"), + "image/png", + f"Content type is wrong: {h.get('Content-Type')}\n{r}", + ) # with cache r, h = self._result(self._execute_request(qs)) self.assertEqual( - h.get("Content-Type"), "image/png", - f"Content type is wrong: {h.get('Content-Type')}\n{r}") - - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WMTS", - "VERSION": "1.0.0", - "REQUEST": "GetTile", - "LAYER": "Country", - "STYLE": "", - "TILEMATRIXSET": "EPSG:4326", - "TILEMATRIX": "0", - "TILEROW": "0", - "TILECOL": "0", - "FORMAT": "image/png" - }.items())]) + h.get("Content-Type"), + "image/png", + f"Content type is wrong: {h.get('Content-Type')}\n{r}", + ) + + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WMTS", + "VERSION": "1.0.0", + "REQUEST": "GetTile", + "LAYER": "Country", + "STYLE": "", + "TILEMATRIXSET": "EPSG:4326", + "TILEMATRIX": "0", + "TILEROW": "0", + "TILECOL": "0", + "FORMAT": "image/png", + }.items() + ) + ] + ) # without cache r, h = self._result(self._execute_request(qs)) self.assertEqual( - h.get("Content-Type"), "image/png", - f"Content type is wrong: {h.get('Content-Type')}\n{r}") + h.get("Content-Type"), + "image/png", + f"Content type is wrong: {h.get('Content-Type')}\n{r}", + ) # with cache r, h = self._result(self._execute_request(qs)) self.assertEqual( - h.get("Content-Type"), "image/png", - f"Content type is wrong: {h.get('Content-Type')}\n{r}") - - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WMTS", - "VERSION": "1.0.0", - "REQUEST": "GetTile", - "LAYER": "QGIS Server Hello World", - "STYLE": "", - "TILEMATRIXSET": "EPSG:3857", - "TILEMATRIX": "0", - "TILEROW": "0", - "TILECOL": "0", - "FORMAT": "image/png" - }.items())]) + h.get("Content-Type"), + "image/png", + f"Content type is wrong: {h.get('Content-Type')}\n{r}", + ) + + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WMTS", + "VERSION": "1.0.0", + "REQUEST": "GetTile", + "LAYER": "QGIS Server Hello World", + "STYLE": "", + "TILEMATRIXSET": "EPSG:3857", + "TILEMATRIX": "0", + "TILEROW": "0", + "TILECOL": "0", + "FORMAT": "image/png", + }.items() + ) + ] + ) # without cache r, h = self._result(self._execute_request(qs)) self.assertEqual( - h.get("Content-Type"), "image/png", - f"Content type is wrong: {h.get('Content-Type')}\n{r}") + h.get("Content-Type"), + "image/png", + f"Content type is wrong: {h.get('Content-Type')}\n{r}", + ) self._img_diff_error(r, h, "WMTS_GetTile_Project_3857_0", 20000) # with cache r, h = self._result(self._execute_request(qs)) self.assertEqual( - h.get("Content-Type"), "image/png", - f"Content type is wrong: {h.get('Content-Type')}\n{r}") + h.get("Content-Type"), + "image/png", + f"Content type is wrong: {h.get('Content-Type')}\n{r}", + ) self._img_diff_error(r, h, "WMTS_GetTile_Project_3857_0", 20000) - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WMTS", - "VERSION": "1.0.0", - "REQUEST": "GetTile", - "LAYER": "QGIS Server Hello World", - "STYLE": "", - "TILEMATRIXSET": "EPSG:4326", - "TILEMATRIX": "0", - "TILEROW": "0", - "TILECOL": "0", - "FORMAT": "image/png" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WMTS", + "VERSION": "1.0.0", + "REQUEST": "GetTile", + "LAYER": "QGIS Server Hello World", + "STYLE": "", + "TILEMATRIXSET": "EPSG:4326", + "TILEMATRIX": "0", + "TILEROW": "0", + "TILECOL": "0", + "FORMAT": "image/png", + }.items() + ) + ] + ) # without cache r, h = self._result(self._execute_request(qs)) self.assertEqual( - h.get("Content-Type"), "image/png", - f"Content type is wrong: {h.get('Content-Type')}\n{r}") + h.get("Content-Type"), + "image/png", + f"Content type is wrong: {h.get('Content-Type')}\n{r}", + ) self._img_diff_error(r, h, "WMTS_GetTile_Project_4326_0", 20000) # with cache r, h = self._result(self._execute_request(qs)) self.assertEqual( - h.get("Content-Type"), "image/png", - f"Content type is wrong: {h.get('Content-Type')}\n{r}") + h.get("Content-Type"), + "image/png", + f"Content type is wrong: {h.get('Content-Type')}\n{r}", + ) self._img_diff_error(r, h, "WMTS_GetTile_Project_4326_0", 20000) - filelist = [f for f in os.listdir(self._servercache._tile_cache_dir) if f.endswith(".png")] - self.assertEqual(len(filelist), 4, 'Not enough image in cache') + filelist = [ + f + for f in os.listdir(self._servercache._tile_cache_dir) + if f.endswith(".png") + ] + self.assertEqual(len(filelist), 4, "Not enough image in cache") cacheManager = self._server_iface.cacheManager() - self.assertTrue(cacheManager.deleteCachedImages(None), 'deleteCachedImages does not return True') + self.assertTrue( + cacheManager.deleteCachedImages(None), + "deleteCachedImages does not return True", + ) - filelist = [f for f in os.listdir(self._servercache._tile_cache_dir) if f.endswith(".png")] - self.assertEqual(len(filelist), 0, 'All images in cache are not deleted ') + filelist = [ + f + for f in os.listdir(self._servercache._tile_cache_dir) + if f.endswith(".png") + ] + self.assertEqual(len(filelist), 0, "All images in cache are not deleted ") def test_gettile_invalid_parameters(self): project = self.projectPath assert os.path.exists(project), "Project file not found: " + project - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WMTS", - "VERSION": "1.0.0", - "REQUEST": "GetTile", - "LAYER": "Country", - "STYLE": "", - "TILEMATRIXSET": "EPSG:3857", - "TILEMATRIX": "0", - "TILEROW": "0", - "TILECOL": "FOO", - "FORMAT": "image/png" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WMTS", + "VERSION": "1.0.0", + "REQUEST": "GetTile", + "LAYER": "Country", + "STYLE": "", + "TILEMATRIXSET": "EPSG:3857", + "TILEMATRIX": "0", + "TILEROW": "0", + "TILECOL": "FOO", + "FORMAT": "image/png", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - err = b"TILECOL (\'FOO\') cannot be converted into int" in r + err = b"TILECOL ('FOO') cannot be converted into int" in r self.assertTrue(err) - filelist = [f for f in os.listdir(self._servercache._tile_cache_dir) if f.endswith(".png")] - self.assertEqual(len(filelist), 0, 'Exception has been cached ') + filelist = [ + f + for f in os.listdir(self._servercache._tile_cache_dir) + if f.endswith(".png") + ] + self.assertEqual(len(filelist), 0, "Exception has been cached ") if __name__ == "__main__": diff --git a/tests/src/python/test_qgsserver_configcache.py b/tests/src/python/test_qgsserver_configcache.py index 206818985aab..6c73f0e0f4f7 100644 --- a/tests/src/python/test_qgsserver_configcache.py +++ b/tests/src/python/test_qgsserver_configcache.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'David Marteau' -__date__ = '28/01/2022' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "David Marteau" +__date__ = "28/01/2022" +__copyright__ = "Copyright 2015, The QGIS Project" import os from pathlib import Path @@ -38,15 +39,15 @@ def tearDownClass(self): def test_periodic_cache_strategy(self): - path = Path(unitTestDataPath('qgis_server_project')) / 'project.qgs' + path = Path(unitTestDataPath("qgis_server_project")) / "project.qgs" self.assertTrue(path.exists()) - os.environ['QGIS_SERVER_PROJECT_CACHE_STRATEGY'] = 'periodic' - os.environ['QGIS_SERVER_PROJECT_CACHE_CHECK_INTERVAL'] = '3000' + os.environ["QGIS_SERVER_PROJECT_CACHE_STRATEGY"] = "periodic" + os.environ["QGIS_SERVER_PROJECT_CACHE_CHECK_INTERVAL"] = "3000" settings = QgsServerSettings() settings.load() - self.assertEqual(settings.projectCacheStrategy(), 'periodic') + self.assertEqual(settings.projectCacheStrategy(), "periodic") self.assertEqual(settings.projectCacheCheckInterval(), 3000) cache = QgsConfigCache(settings) @@ -64,7 +65,7 @@ def test_periodic_cache_strategy(self): prj2 = cache.project(str(path)) self.assertIsNotNone(prj2) # Ensure project is not reloaded - self.assertEqual(prj2.readEntry("TestConfigCache", "/"), ('foobar', True)) + self.assertEqual(prj2.readEntry("TestConfigCache", "/"), ("foobar", True)) # Change project modified time path.touch() @@ -79,7 +80,7 @@ def test_periodic_cache_strategy(self): prj3 = cache.project(str(path)) self.assertIsNotNone(prj3) # Ensure project is not reloaded - self.assertEqual(prj3.readEntry("TestConfigCache", "/"), ('foobar', True)) + self.assertEqual(prj3.readEntry("TestConfigCache", "/"), ("foobar", True)) # Some delay st = time() @@ -94,14 +95,14 @@ def test_periodic_cache_strategy(self): def test_file_watcher_invalidation(self): - path = Path(unitTestDataPath('qgis_server_project')) / 'project.qgs' + path = Path(unitTestDataPath("qgis_server_project")) / "project.qgs" self.assertTrue(path.exists()) - os.environ['QGIS_SERVER_PROJECT_CACHE_STRATEGY'] = 'filesystem' + os.environ["QGIS_SERVER_PROJECT_CACHE_STRATEGY"] = "filesystem" settings = QgsServerSettings() settings.load() - self.assertEqual(settings.projectCacheStrategy(), 'filesystem') + self.assertEqual(settings.projectCacheStrategy(), "filesystem") cache = QgsConfigCache(settings) @@ -118,7 +119,7 @@ def test_file_watcher_invalidation(self): prj2 = cache.project(str(path)) self.assertIsNotNone(prj2) # Ensure project is not reloaded - self.assertEqual(prj2.readEntry("TestConfigCache", "/"), ('foobaz', True)) + self.assertEqual(prj2.readEntry("TestConfigCache", "/"), ("foobaz", True)) # Change project modified time path.touch() @@ -137,14 +138,14 @@ def test_file_watcher_invalidation(self): def test_null_invalidation(self): - path = Path(unitTestDataPath('qgis_server_project')) / 'project.qgs' + path = Path(unitTestDataPath("qgis_server_project")) / "project.qgs" self.assertTrue(path.exists()) - os.environ['QGIS_SERVER_PROJECT_CACHE_STRATEGY'] = 'off' + os.environ["QGIS_SERVER_PROJECT_CACHE_STRATEGY"] = "off" settings = QgsServerSettings() settings.load() - self.assertEqual(settings.projectCacheStrategy(), 'off') + self.assertEqual(settings.projectCacheStrategy(), "off") cache = QgsConfigCache(settings) @@ -161,7 +162,7 @@ def test_null_invalidation(self): prj2 = cache.project(str(path)) self.assertIsNotNone(prj2) # Ensure project is not reloaded - self.assertEqual(prj2.readEntry("TestConfigCache", "/"), ('barbaz', True)) + self.assertEqual(prj2.readEntry("TestConfigCache", "/"), ("barbaz", True)) # Change project modified time path.touch() @@ -180,28 +181,28 @@ def test_null_invalidation(self): def test_default_strategy_setting(self): - os.environ['QGIS_SERVER_PROJECT_CACHE_STRATEGY'] = '' + os.environ["QGIS_SERVER_PROJECT_CACHE_STRATEGY"] = "" settings = QgsServerSettings() settings.load() - self.assertEqual(settings.projectCacheStrategy(), 'filesystem') + self.assertEqual(settings.projectCacheStrategy(), "filesystem") def test_initialized_instance(self): - os.environ['QGIS_SERVER_PROJECT_CACHE_STRATEGY'] = 'off' + os.environ["QGIS_SERVER_PROJECT_CACHE_STRATEGY"] = "off" settings = QgsServerSettings() settings.load() QgsConfigCache.initialize(settings) - self.assertEqual(QgsConfigCache.instance().strategyName(), 'off') + self.assertEqual(QgsConfigCache.instance().strategyName(), "off") def test_list_projects(self): settings = QgsServerSettings() settings.load() cache = QgsConfigCache(settings) - path = Path(unitTestDataPath('qgis_server_project')) / 'project.qgs' + path = Path(unitTestDataPath("qgis_server_project")) / "project.qgs" prj1 = cache.project(str(path)) projects = cache.projects() diff --git a/tests/src/python/test_qgsserver_landingpage.py b/tests/src/python/test_qgsserver_landingpage.py index 3082c49a30a0..de26f7a5dcf1 100644 --- a/tests/src/python/test_qgsserver_landingpage.py +++ b/tests/src/python/test_qgsserver_landingpage.py @@ -8,16 +8,17 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '03/08/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "03/08/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import json import os import shutil # Deterministic XML -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" from qgis.PyQt import QtCore from qgis.server import ( @@ -30,7 +31,7 @@ class QgsServerLandingPageTest(QgsServerAPITestBase): - """ QGIS Server Landing Page tests""" + """QGIS Server Landing Page tests""" # Set to True in child classes to re-generate reference files for this class # regeregenerate_api_reference = True @@ -42,96 +43,124 @@ def setUpClass(cls): cls.temp_dir = QtCore.QTemporaryDir() temp_dir = cls.temp_dir.path() - cls.directories = [os.path.join(temp_dir, 'landingpage', 'projects'), os.path.join(temp_dir, 'landingpage', 'projects2')] - shutil.copytree(os.path.join(unitTestDataPath('qgis_server'), 'landingpage'), os.path.join(temp_dir, 'landingpage')) + cls.directories = [ + os.path.join(temp_dir, "landingpage", "projects"), + os.path.join(temp_dir, "landingpage", "projects2"), + ] + shutil.copytree( + os.path.join(unitTestDataPath("qgis_server"), "landingpage"), + os.path.join(temp_dir, "landingpage"), + ) def setUp(self): """Setup env""" super().setUp() try: - del (os.environ["QGIS_SERVER_DISABLED_APIS"]) + del os.environ["QGIS_SERVER_DISABLED_APIS"] except: pass try: - del (os.environ['QGIS_SERVER_LANDING_PAGE_PREFIX']) + del os.environ["QGIS_SERVER_LANDING_PAGE_PREFIX"] except: pass - os.environ['QGIS_SERVER_LANDING_PAGE_PROJECTS_DIRECTORIES'] = '||'.join(self.directories) + os.environ["QGIS_SERVER_LANDING_PAGE_PROJECTS_DIRECTORIES"] = "||".join( + self.directories + ) - if not os.environ.get('TRAVIS', False): - os.environ['QGIS_SERVER_LANDING_PAGE_PROJECTS_PG_CONNECTIONS'] = "postgresql://localhost:5432?sslmode=disable&dbname=landing_page_test&schema=public" + if not os.environ.get("TRAVIS", False): + os.environ["QGIS_SERVER_LANDING_PAGE_PROJECTS_PG_CONNECTIONS"] = ( + "postgresql://localhost:5432?sslmode=disable&dbname=landing_page_test&schema=public" + ) def test_landing_page_redirects(self): """Test landing page redirects""" - request = QgsBufferServerRequest('http://server.qgis.org/') - request.setHeader('Accept', 'application/json') + request = QgsBufferServerRequest("http://server.qgis.org/") + request.setHeader("Accept", "application/json") response = QgsBufferServerResponse() self.server.handleRequest(request, response) - self.assertEqual(response.headers()[ - 'Location'], 'http://server.qgis.org/index.json') + self.assertEqual( + response.headers()["Location"], "http://server.qgis.org/index.json" + ) - request = QgsBufferServerRequest('http://server.qgis.org') - request.setHeader('Accept', 'application/json') + request = QgsBufferServerRequest("http://server.qgis.org") + request.setHeader("Accept", "application/json") response = QgsBufferServerResponse() self.server.handleRequest(request, response) - self.assertEqual(response.headers()[ - 'Location'], 'http://server.qgis.org/index.json') + self.assertEqual( + response.headers()["Location"], "http://server.qgis.org/index.json" + ) response = QgsBufferServerResponse() - request.setHeader('Accept', 'text/html') + request.setHeader("Accept", "text/html") self.server.handleRequest(request, response) - self.assertEqual(response.headers()[ - 'Location'], 'http://server.qgis.org/index.html') + self.assertEqual( + response.headers()["Location"], "http://server.qgis.org/index.html" + ) def compareProjects(self, actual, expected, expected_path): """Order-agnostic project comparison""" - actual_raw = self.normalize_json(actual).split('\n') - expected_raw = self.normalize_json(expected).split('\n') - actual_raw = '\n'.join(actual_raw[actual_raw.index('') + 1:]) - expected_raw = '\n'.join(expected_raw[expected_raw.index('') + 1:]) + actual_raw = self.normalize_json(actual).split("\n") + expected_raw = self.normalize_json(expected).split("\n") + actual_raw = "\n".join(actual_raw[actual_raw.index("") + 1 :]) + expected_raw = "\n".join(expected_raw[expected_raw.index("") + 1 :]) actual_j = json.loads(actual_raw) expected_j = json.loads(expected_raw) - actual_projects = {p['title']: p for p in actual_j['projects']} - expected_projects = {p['title']: p for p in expected_j['projects']} + actual_projects = {p["title"]: p for p in actual_j["projects"]} + expected_projects = {p["title"]: p for p in expected_j["projects"]} if self.regeregenerate_api_reference: # Try to change timestamp try: - content = actual.split('\n') - j = ''.join(content[content.index('') + 1:]) + content = actual.split("\n") + j = "".join(content[content.index("") + 1 :]) j = json.loads(j) - j['timeStamp'] = '2019-07-05T12:27:07Z' - actual = '\n'.join(content[:2]) + '\n' + \ - json.dumps(j, ensure_ascii=False, indent=2) + j["timeStamp"] = "2019-07-05T12:27:07Z" + actual = ( + "\n".join(content[:2]) + + "\n" + + json.dumps(j, ensure_ascii=False, indent=2) + ) except: pass - f = open(expected_path.encode('utf8'), 'w+', encoding='utf8') + f = open(expected_path.encode("utf8"), "w+", encoding="utf8") f.write(actual) f.close() print(f"Reference file {expected_path.encode('utf8')} regenerated!") for title in expected_projects.keys(): - self.assertLinesEqual(json.dumps(actual_projects[title], indent=4), json.dumps(expected_projects[title], indent=4), expected_path.encode('utf8')) + self.assertLinesEqual( + json.dumps(actual_projects[title], indent=4), + json.dumps(expected_projects[title], indent=4), + expected_path.encode("utf8"), + ) def test_landing_page_json(self): """Test landing page in JSON format""" - request = QgsBufferServerRequest('http://server.qgis.org/index.json') - request.setBaseUrl(QtCore.QUrl('http://server.qgis.org/')) + request = QgsBufferServerRequest("http://server.qgis.org/index.json") + request.setBaseUrl(QtCore.QUrl("http://server.qgis.org/")) response = QgsBufferServerResponse() self.server.handleRequest(request, response) - j_actual = 'Content-Type: application/json\n\n' - j_actual += bytes(response.body()).decode('utf8)') - - if not os.environ.get('TRAVIS', False): - expected_path = os.path.join(unitTestDataPath('qgis_server'), 'landingpage', 'test_landing_page_with_pg_index.json') + j_actual = "Content-Type: application/json\n\n" + j_actual += bytes(response.body()).decode("utf8)") + + if not os.environ.get("TRAVIS", False): + expected_path = os.path.join( + unitTestDataPath("qgis_server"), + "landingpage", + "test_landing_page_with_pg_index.json", + ) else: - expected_path = os.path.join(unitTestDataPath('qgis_server'), 'landingpage', 'test_landing_page_index.json') + expected_path = os.path.join( + unitTestDataPath("qgis_server"), + "landingpage", + "test_landing_page_index.json", + ) j_expected = open(expected_path).read() self.compareProjects(j_actual, j_expected, expected_path) @@ -140,78 +169,91 @@ def test_project_json(self): """Test landing page project call in JSON format""" # Get hashes for test projects - request = QgsBufferServerRequest('http://server.qgis.org/index.json') - request.setHeader('Accept', 'application/json') + request = QgsBufferServerRequest("http://server.qgis.org/index.json") + request.setHeader("Accept", "application/json") response = QgsBufferServerResponse() self.server.handleRequest(request, response) j = json.loads(bytes(response.body())) - test_projects = {p['id']: p['title'].replace(' ', '_') for p in j['projects']} + test_projects = {p["id"]: p["title"].replace(" ", "_") for p in j["projects"]} for identifier, name in test_projects.items(): - request = QgsBufferServerRequest( - 'http://server.qgis.org/map/' + identifier) - request.setHeader('Accept', 'application/json') + request = QgsBufferServerRequest("http://server.qgis.org/map/" + identifier) + request.setHeader("Accept", "application/json") self.compareApi( - request, None, f"test_project_{name.replace('.', '_')}.json", subdir='landingpage') + request, + None, + f"test_project_{name.replace('.', '_')}.json", + subdir="landingpage", + ) def test_landing_page_json_empty(self): """Test landing page in JSON format with no projects""" - os.environ['QGIS_SERVER_LANDING_PAGE_PROJECTS_DIRECTORIES'] = '' - os.environ['QGIS_SERVER_LANDING_PAGE_PROJECTS_PG_CONNECTIONS'] = '' - request = QgsBufferServerRequest('http://server.qgis.org/index.json') + os.environ["QGIS_SERVER_LANDING_PAGE_PROJECTS_DIRECTORIES"] = "" + os.environ["QGIS_SERVER_LANDING_PAGE_PROJECTS_PG_CONNECTIONS"] = "" + request = QgsBufferServerRequest("http://server.qgis.org/index.json") self.compareApi( - request, None, 'test_landing_page_empty_index.json', subdir='landingpage') + request, None, "test_landing_page_empty_index.json", subdir="landingpage" + ) def test_landing_page_prefix(self): - os.environ['QGIS_SERVER_LANDING_PAGE_PREFIX'] = '/mylanding' + os.environ["QGIS_SERVER_LANDING_PAGE_PREFIX"] = "/mylanding" def _test_error(uri): request = QgsBufferServerRequest(uri) - request.setHeader('Accept', 'application/json') + request.setHeader("Accept", "application/json") response = QgsBufferServerResponse() self.server.handleRequest(request, response) - self.assertEqual(bytes(response.body()), b'\nProject file error. For OWS services: please provide a SERVICE and a MAP parameter pointing to a valid QGIS project file\n') + self.assertEqual( + bytes(response.body()), + b'\nProject file error. For OWS services: please provide a SERVICE and a MAP parameter pointing to a valid QGIS project file\n', + ) - _test_error('http://server.qgis.org/index.json') - _test_error('http://server.qgis.org/index.html') - _test_error('http://server.qgis.org/') - _test_error('http://server.qgis.org') + _test_error("http://server.qgis.org/index.json") + _test_error("http://server.qgis.org/index.html") + _test_error("http://server.qgis.org/") + _test_error("http://server.qgis.org") def _test_valid(uri): request = QgsBufferServerRequest(uri) - request.setHeader('Accept', 'application/json') + request.setHeader("Accept", "application/json") response = QgsBufferServerResponse() self.server.handleRequest(request, response) - if 'index' not in uri: - self.assertEqual(response.headers()[ - 'Location'], 'http://server.qgis.org/mylanding/index.json') + if "index" not in uri: + self.assertEqual( + response.headers()["Location"], + "http://server.qgis.org/mylanding/index.json", + ) else: # Just check that it's valid json j = json.loads(bytes(response.body())) - _test_valid('http://server.qgis.org/mylanding') - _test_valid('http://server.qgis.org/mylanding/') - _test_valid('http://server.qgis.org/mylanding/index.json') + _test_valid("http://server.qgis.org/mylanding") + _test_valid("http://server.qgis.org/mylanding/") + _test_valid("http://server.qgis.org/mylanding/index.json") # Test redirects with prefix - os.environ['QGIS_SERVER_LANDING_PAGE_PREFIX'] = '/ows/catalog' - request = QgsBufferServerRequest('http://server.qgis.org/ows/catalog') + os.environ["QGIS_SERVER_LANDING_PAGE_PREFIX"] = "/ows/catalog" + request = QgsBufferServerRequest("http://server.qgis.org/ows/catalog") response = QgsBufferServerResponse() - request.setHeader('Accept', 'text/html') + request.setHeader("Accept", "text/html") self.server.handleRequest(request, response) - self.assertEqual(response.headers()[ - 'Location'], 'http://server.qgis.org/ows/catalog/index.html') + self.assertEqual( + response.headers()["Location"], + "http://server.qgis.org/ows/catalog/index.html", + ) - request = QgsBufferServerRequest('http://server.qgis.org/ows/catalog/') + request = QgsBufferServerRequest("http://server.qgis.org/ows/catalog/") response = QgsBufferServerResponse() - request.setHeader('Accept', 'text/html') + request.setHeader("Accept", "text/html") self.server.handleRequest(request, response) - self.assertEqual(response.headers()[ - 'Location'], 'http://server.qgis.org/ows/catalog/index.html') + self.assertEqual( + response.headers()["Location"], + "http://server.qgis.org/ows/catalog/index.html", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_locale_override.py b/tests/src/python/test_qgsserver_locale_override.py index 348727e42013..46b146b95283 100644 --- a/tests/src/python/test_qgsserver_locale_override.py +++ b/tests/src/python/test_qgsserver_locale_override.py @@ -13,15 +13,16 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '01/04/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "01/04/2019" +__copyright__ = "Copyright 2019, The QGIS Project" import os # Needed on Qt 5 so that the serialization of XML is consistent among all # executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" from qgis.testing import unittest from test_qgsserver_wms import TestQgsServerWMSTestBase @@ -36,8 +37,8 @@ class TestQgsServerWMSLocaleOverride(TestQgsServerWMSTestBase): @classmethod def setUpClass(self): - os.environ['QGIS_SERVER_OVERRIDE_SYSTEM_LOCALE'] = 'EN_us' - os.environ['QGIS_SERVER_SHOW_GROUP_SEPARATOR'] = '0' + os.environ["QGIS_SERVER_OVERRIDE_SYSTEM_LOCALE"] = "EN_us" + os.environ["QGIS_SERVER_SHOW_GROUP_SEPARATOR"] = "0" super().setUpClass() @@ -46,15 +47,17 @@ def setUpClass(self): def testGetFeatureInfoThousandSeparator(self): - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer_thousands&styles=&' + - 'info_format=text%2Fxml&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer_thousands&X=190&Y=320', - 'wms_getfeatureinfo-thousands-text-xml', - project='test_project_gfi_thousands.qgs',) + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer_thousands&styles=&" + + "info_format=text%2Fxml&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer_thousands&X=190&Y=320", + "wms_getfeatureinfo-thousands-text-xml", + project="test_project_gfi_thousands.qgs", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_modules.py b/tests/src/python/test_qgsserver_modules.py index b3904af88778..4302c7e61341 100644 --- a/tests/src/python/test_qgsserver_modules.py +++ b/tests/src/python/test_qgsserver_modules.py @@ -18,9 +18,9 @@ *************************************************************************** """ -__author__ = 'David Marteau' -__date__ = 'December 2016' -__copyright__ = '(C) 2016, David Marteau' +__author__ = "David Marteau" +__date__ = "December 2016" +__copyright__ = "(C) 2016, David Marteau" """ QGIS test for server services """ @@ -74,8 +74,7 @@ def executeRequest(self, request, response): class TestModules(unittest.TestCase): - """ - """ + """ """ @classmethod def setUpClass(cls): @@ -89,13 +88,13 @@ def tearDownClass(cls): def setUp(self): """Create the server instance""" - self.testdata_path = unitTestDataPath('qgis_server') + '/' + self.testdata_path = unitTestDataPath("qgis_server") + "/" - d = unitTestDataPath('qgis_server_accesscontrol') + '/' + d = unitTestDataPath("qgis_server_accesscontrol") + "/" self.projectPath = os.path.join(d, "project.qgs") # Clean env just to be sure - env_vars = ['QUERY_STRING', 'QGIS_PROJECT_FILE'] + env_vars = ["QUERY_STRING", "QGIS_PROJECT_FILE"] for ev in env_vars: try: del os.environ[ev] @@ -111,5 +110,5 @@ def test_dummy(self): pass -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_plugins.py b/tests/src/python/test_qgsserver_plugins.py index f2ee1ba36086..56b0574da0a9 100644 --- a/tests/src/python/test_qgsserver_plugins.py +++ b/tests/src/python/test_qgsserver_plugins.py @@ -9,9 +9,10 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '22/04/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "22/04/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os @@ -24,21 +25,21 @@ from utilities import unitTestDataPath # Strip path and content length because path may vary -RE_STRIP_UNCHECKABLE = br'MAP=[^"]+|Content-Length: \d+' -RE_ATTRIBUTES = br'[^>\s]+=[^>\s]+' +RE_STRIP_UNCHECKABLE = rb'MAP=[^"]+|Content-Length: \d+' +RE_ATTRIBUTES = rb"[^>\s]+=[^>\s]+" class TestQgsServerPlugins(QgsServerTestBase): def setUp(self): """Create the server instance""" - self.testdata_path = unitTestDataPath('qgis_server') + '/' + self.testdata_path = unitTestDataPath("qgis_server") + "/" - d = unitTestDataPath('qgis_server_accesscontrol') + '/' + d = unitTestDataPath("qgis_server_accesscontrol") + "/" self.projectPath = os.path.join(d, "project.qgs") # Clean env just to be sure - env_vars = ['QUERY_STRING', 'QGIS_PROJECT_FILE'] + env_vars = ["QUERY_STRING", "QGIS_PROJECT_FILE"] for ev in env_vars: try: del os.environ[ev] @@ -69,10 +70,10 @@ def responseComplete(self): request = self.serverInterface().requestHandler() params = request.parameterMap() QgsMessageLog.logMessage("SimpleHelloFilter.responseComplete") - if params.get('SERVICE', '').upper() == 'SIMPLE': + if params.get("SERVICE", "").upper() == "SIMPLE": request.clear() - request.setResponseHeader('Content-type', 'text/plain') - request.appendBody(b'Hello from SimpleServer!') + request.setResponseHeader("Content-type", "text/plain") + request.appendBody(b"Hello from SimpleServer!") serverIface = self.server.serverInterface() filter = SimpleHelloFilter(serverIface) @@ -81,11 +82,11 @@ def responseComplete(self): self.assertEqual(filter, serverIface.filters()[100][0]) # global to be modified inside plugin filters - globals()['status_code'] = 0 + globals()["status_code"] = 0 # body to be checked inside plugin filters - globals()['body2'] = None + globals()["body2"] = None # headers to be checked inside plugin filters - globals()['headers2'] = None + globals()["headers2"] = None # Register some more filters class Filter1(QgsServerFilter): @@ -93,16 +94,16 @@ class Filter1(QgsServerFilter): def responseComplete(self): request = self.serverInterface().requestHandler() params = request.parameterMap() - if params.get('SERVICE', '').upper() == 'SIMPLE': - request.appendBody(b'Hello from Filter1!') + if params.get("SERVICE", "").upper() == "SIMPLE": + request.appendBody(b"Hello from Filter1!") class Filter2(QgsServerFilter): def responseComplete(self): request = self.serverInterface().requestHandler() params = request.parameterMap() - if params.get('SERVICE', '').upper() == 'SIMPLE': - request.appendBody(b'Hello from Filter2!') + if params.get("SERVICE", "").upper() == "SIMPLE": + request.appendBody(b"Hello from Filter2!") class Filter3(QgsServerFilter): """Test get and set status code""" @@ -129,7 +130,7 @@ def responseComplete(self): request = self.serverInterface().requestHandler() request.clearBody() headers2 = request.responseHeaders() - request.appendBody(b'new body, new life!') + request.appendBody(b"new body, new life!") filter1 = Filter1(serverIface) filter2 = Filter2(serverIface) @@ -143,16 +144,18 @@ def responseComplete(self): self.assertIn(filter2, serverIface.filters()[100]) self.assertEqual(filter1, serverIface.filters()[101][0]) self.assertEqual(filter2, serverIface.filters()[200][0]) - header, body = (_v for _v in self._execute_request('?service=simple')) + header, body = (_v for _v in self._execute_request("?service=simple")) response = header + body - expected = b'Content-Length: 62\nContent-type: text/plain\n\nHello from SimpleServer!Hello from Filter1!Hello from Filter2!' + expected = b"Content-Length: 62\nContent-type: text/plain\n\nHello from SimpleServer!Hello from Filter1!Hello from Filter2!" self.assertEqual(response, expected) # Check status code self.assertEqual(status_code, 999) # Check body getter from filter - self.assertEqual(body2, b'Hello from SimpleServer!Hello from Filter1!Hello from Filter2!') + self.assertEqual( + body2, b"Hello from SimpleServer!Hello from Filter1!Hello from Filter2!" + ) # Check that the bindings for complex type QgsServerFiltersMap are working filters = {100: [filter, filter2], 101: [filter1], 200: [filter2]} @@ -161,23 +164,24 @@ def responseComplete(self): self.assertIn(filter2, serverIface.filters()[100]) self.assertEqual(filter1, serverIface.filters()[101][0]) self.assertEqual(filter2, serverIface.filters()[200][0]) - header, body = self._execute_request('?service=simple') + header, body = self._execute_request("?service=simple") response = header + body - expected = b'Content-Length: 62\nContent-type: text/plain\n\nHello from SimpleServer!Hello from Filter1!Hello from Filter2!' + expected = b"Content-Length: 62\nContent-type: text/plain\n\nHello from SimpleServer!Hello from Filter1!Hello from Filter2!" self.assertEqual(response, expected) # Now, re-run with body setter filter5 = Filter5(serverIface) serverIface.registerFilter(filter5, 500) - header, body = self._execute_request('?service=simple') + header, body = self._execute_request("?service=simple") response = header + body - expected = b'Content-Length: 19\nContent-type: text/plain\n\nnew body, new life!' + expected = ( + b"Content-Length: 19\nContent-type: text/plain\n\nnew body, new life!" + ) self.assertEqual(response, expected) - self.assertEqual(headers2, {'Content-type': 'text/plain'}) + self.assertEqual(headers2, {"Content-type": "text/plain"}) def test_configpath(self): - """ Test plugin can read confif path - """ + """Test plugin can read confif path""" try: from qgis.core import QgsProject from qgis.server import QgsServerFilter @@ -185,12 +189,12 @@ def test_configpath(self): print("QGIS Server plugins are not compiled. Skipping test") return - d = unitTestDataPath('qgis_server_accesscontrol') + '/' + d = unitTestDataPath("qgis_server_accesscontrol") + "/" self.projectPath = os.path.join(d, "project.qgs") self.server = QgsServer() # global to be modified inside plugin filters - globals()['configFilePath2'] = None + globals()["configFilePath2"] = None class Filter0(QgsServerFilter): """Body setter, clear body, keep headers""" @@ -203,19 +207,19 @@ def requestReady(self): serverIface.registerFilter(Filter0(serverIface), 100) # Test using MAP - self._execute_request(f'?service=simple&MAP={self.projectPath}') + self._execute_request(f"?service=simple&MAP={self.projectPath}") # Check config file path self.assertEqual(configFilePath2, self.projectPath) # Reset result - globals()['configFilePath2'] = None + globals()["configFilePath2"] = None # Test with prqject as argument project = QgsProject() project.read(self.projectPath) - self._execute_request_project('?service=simple', project=project) + self._execute_request_project("?service=simple", project=project) # Check config file path self.assertEqual(configFilePath2, project.fileName()) @@ -238,8 +242,8 @@ def responseComplete(self): filter1 = FilterBroken(serverIface) filters = {100: [filter1]} serverIface.setFilters(filters) - header, body = self._execute_request('') - self.assertEqual(body, b'Internal Server Error') + header, body = self._execute_request("") + self.assertEqual(body, b"Internal Server Error") serverIface.setFilters({}) def test_get_path(self): @@ -262,15 +266,14 @@ def responseComplete(self): filter1 = Filter1(serverIface) filters = {100: [filter1]} serverIface.setFilters(filters) - header, body = self._execute_request('http://myserver/mypath/?myparam=1') - self.assertEqual(filter1.url, 'http://myserver/mypath/?myparam=1') - self.assertEqual(filter1.path, '/mypath/') + header, body = self._execute_request("http://myserver/mypath/?myparam=1") + self.assertEqual(filter1.url, "http://myserver/mypath/?myparam=1") + self.assertEqual(filter1.path, "/mypath/") serverIface.setFilters({}) def test_streaming_pipeline(self): - """ Test streaming pipeline propagation - """ + """Test streaming pipeline propagation""" try: from qgis.core import QgsProject from qgis.server import QgsServerFilter @@ -311,16 +314,16 @@ def onProjectReady(self): def onSendResponse(self): request = self.serverInterface().requestHandler() request.clearBody() - request.appendBody(b'A') + request.appendBody(b"A") request.sendResponse() - request.appendBody(b'B') + request.appendBody(b"B") request.sendResponse() # Stop propagating return self.propagate def onResponseComplete(self): request = self.serverInterface().requestHandler() - request.appendBody(b'C') + request.appendBody(b"C") return self.propagate # Methods should be called only if filter1 propagate @@ -342,12 +345,12 @@ def onProjectReady(self): def onSendResponse(self): request = self.serverInterface().requestHandler() - request.appendBody(b'D') + request.appendBody(b"D") return True def onResponseComplete(self): request = self.serverInterface().requestHandler() - request.appendBody(b'E') + request.appendBody(b"E") return True # Methods to manage propagate filter @@ -359,25 +362,25 @@ def __init__(self, iface, propagate_filter): def onRequestReady(self): request = self.serverInterface().requestHandler() - if self.step_to_stop_propagate == 'onRequestReady': + if self.step_to_stop_propagate == "onRequestReady": self.propagate_filter.propagate = False return True def onProjectReady(self): request = self.serverInterface().requestHandler() - if self.step_to_stop_propagate == 'onProjectReady': + if self.step_to_stop_propagate == "onProjectReady": self.propagate_filter.propagate = False return True def onSendResponse(self): request = self.serverInterface().requestHandler() - if self.step_to_stop_propagate == 'onSendResponse': + if self.step_to_stop_propagate == "onSendResponse": self.propagate_filter.propagate = False return True def onResponseComplete(self): request = self.serverInterface().requestHandler() - if self.step_to_stop_propagate == 'onResponseComplete': + if self.step_to_stop_propagate == "onResponseComplete": self.propagate_filter.propagate = False return True @@ -398,17 +401,21 @@ def onResponseComplete(self): # Test no propagation filter1.propagate = False - _, body = self._execute_request_project(f'?service={service0.name()}', project=project) + _, body = self._execute_request_project( + f"?service={service0.name()}", project=project + ) self.assertFalse(filter2.request_ready) self.assertFalse(filter2.project_ready) - self.assertEqual(body, b'ABC') + self.assertEqual(body, b"ABC") # Test with propagation filter1.propagate = True - _, body = self._execute_request_project(f'?service={service0.name()}', project=project) + _, body = self._execute_request_project( + f"?service={service0.name()}", project=project + ) self.assertTrue(filter2.request_ready) self.assertTrue(filter2.project_ready) - self.assertEqual(body, b'ABDCE') + self.assertEqual(body, b"ABDCE") # Manage propagation filter3 = Filter3(serverIface, filter1) @@ -418,45 +425,53 @@ def onResponseComplete(self): filter1.propagate = True filter2.request_ready = False filter2.project_ready = False - filter3.step_to_stop_propagate = 'onResponseComplete' - _, body = self._execute_request_project(f'?service={service0.name()}', project=project) + filter3.step_to_stop_propagate = "onResponseComplete" + _, body = self._execute_request_project( + f"?service={service0.name()}", project=project + ) self.assertTrue(filter2.request_ready) self.assertTrue(filter2.project_ready) - self.assertEqual(body, b'ABDC') + self.assertEqual(body, b"ABDC") # Stop at onSendResponse filter1.propagate = True filter2.request_ready = False filter2.project_ready = False - filter3.step_to_stop_propagate = 'onSendResponse' - _, body = self._execute_request_project(f'?service={service0.name()}', project=project) + filter3.step_to_stop_propagate = "onSendResponse" + _, body = self._execute_request_project( + f"?service={service0.name()}", project=project + ) self.assertTrue(filter2.request_ready) self.assertTrue(filter2.project_ready) - self.assertEqual(body, b'ABC') + self.assertEqual(body, b"ABC") # Stop at onProjectReady filter1.propagate = True filter2.request_ready = False filter2.project_ready = False - filter3.step_to_stop_propagate = 'onProjectReady' - _, body = self._execute_request_project(f'?service={service0.name()}', project=project) + filter3.step_to_stop_propagate = "onProjectReady" + _, body = self._execute_request_project( + f"?service={service0.name()}", project=project + ) self.assertTrue(filter2.request_ready) self.assertFalse(filter2.project_ready) - self.assertEqual(body, b'ABC') + self.assertEqual(body, b"ABC") # Stop at onRequestReady filter1.propagate = True filter2.request_ready = False filter2.project_ready = False - filter3.step_to_stop_propagate = 'onRequestReady' - _, body = self._execute_request_project(f'?service={service0.name()}', project=project) + filter3.step_to_stop_propagate = "onRequestReady" + _, body = self._execute_request_project( + f"?service={service0.name()}", project=project + ) self.assertFalse(filter2.request_ready) self.assertFalse(filter2.project_ready) - self.assertEqual(body, b'ABC') + self.assertEqual(body, b"ABC") serverIface.setFilters({}) reg.unregisterService(service0.name(), service0.version()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_projectutils.py b/tests/src/python/test_qgsserver_projectutils.py index 7159bbf34ce5..3cc6e07dd080 100644 --- a/tests/src/python/test_qgsserver_projectutils.py +++ b/tests/src/python/test_qgsserver_projectutils.py @@ -8,9 +8,10 @@ (at your option) any later version. """ -__author__ = 'Paul Blottiere' -__date__ = '26/12/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Paul Blottiere" +__date__ = "26/12/2016" +__copyright__ = "Copyright 2016, The QGIS Project" import os @@ -26,7 +27,7 @@ class TestQgsServerProjectUtils(unittest.TestCase): def setUp(self): - self.testdata_path = unitTestDataPath('qgis_server_project') + '/' + self.testdata_path = unitTestDataPath("qgis_server_project") + "/" self.prj = QgsProject() self.prjPath = os.path.join(self.testdata_path, "project.qgs") @@ -44,9 +45,15 @@ def test_size(self): self.assertEqual(QgsServerProjectUtils.wmsMaxHeight(self.prj), 500) def test_url(self): - self.assertEqual(QgsServerProjectUtils.wmsServiceUrl(self.prj), "my_wms_advertised_url") - self.assertEqual(QgsServerProjectUtils.wcsServiceUrl(self.prj), "my_wcs_advertised_url") - self.assertEqual(QgsServerProjectUtils.wfsServiceUrl(self.prj), "my_wfs_advertised_url") + self.assertEqual( + QgsServerProjectUtils.wmsServiceUrl(self.prj), "my_wms_advertised_url" + ) + self.assertEqual( + QgsServerProjectUtils.wcsServiceUrl(self.prj), "my_wcs_advertised_url" + ) + self.assertEqual( + QgsServerProjectUtils.wfsServiceUrl(self.prj), "my_wfs_advertised_url" + ) def test_wmsuselayerids(self): self.assertEqual(QgsServerProjectUtils.wmsUseLayerIds(self.prj), False) @@ -56,9 +63,9 @@ def test_wmsrestrictedlayers(self): # retrieve entry from project result = QgsServerProjectUtils.wmsRestrictedLayers(self.prj) expected = [] - expected.append('points') # layer - expected.append('group1') # local group - expected.append('groupEmbedded') # embedded group + expected.append("points") # layer + expected.append("group1") # local group + expected.append("groupEmbedded") # embedded group self.assertListEqual(sorted(expected), sorted(result)) @@ -67,9 +74,9 @@ def test_wfslayersids(self): result = QgsServerProjectUtils.wfsLayerIds(self.prj) expected = [] - expected.append('multipoint20170309173637804') # from embedded group - expected.append('points20170309173738552') # local layer - expected.append('polys20170309173913723') # from local group + expected.append("multipoint20170309173637804") # from embedded group + expected.append("points20170309173738552") # local layer + expected.append("polys20170309173913723") # from local group self.assertEqual(expected, result) @@ -78,20 +85,24 @@ def test_wcslayersids(self): result = QgsServerProjectUtils.wcsLayerIds(self.prj) expected = [] - expected.append('landsat20170313142548073') + expected.append("landsat20170313142548073") self.assertEqual(expected, result) - @mock.patch.dict(os.environ, {"QGIS_SERVER_WFS_SERVICE_URL": "http://localhost:8080"}) + @mock.patch.dict( + os.environ, {"QGIS_SERVER_WFS_SERVICE_URL": "http://localhost:8080"} + ) def test_map_uppercase_replace(self): """Test issue GH #54533 MAP replacementin URL arg""" settings = QgsServerSettings() - self.assertIsNotNone(settings.serviceUrl('WFS')) - request = QgsBufferServerRequest('http://localhost:8080/?MaP=/mAp.qgs&SERVICE=WMS&REQUEST=GetMap') - service_url = QgsServerProjectUtils.serviceUrl('WFS', request, settings) - self.assertEqual(service_url, 'http://localhost:8080/?MAP=/mAp.qgs') + self.assertIsNotNone(settings.serviceUrl("WFS")) + request = QgsBufferServerRequest( + "http://localhost:8080/?MaP=/mAp.qgs&SERVICE=WMS&REQUEST=GetMap" + ) + service_url = QgsServerProjectUtils.serviceUrl("WFS", request, settings) + self.assertEqual(service_url, "http://localhost:8080/?MAP=/mAp.qgs") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_request.py b/tests/src/python/test_qgsserver_request.py index a5ffe7876919..f36e3e7ca241 100644 --- a/tests/src/python/test_qgsserver_request.py +++ b/tests/src/python/test_qgsserver_request.py @@ -9,9 +9,9 @@ """ -__author__ = 'Alessandro Pasotti' -__date__ = '29/04/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "29/04/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os @@ -33,7 +33,16 @@ class QgsServerRequestTest(QgsServerTestBase): @staticmethod def _set_env(env={}): - for k in ('QUERY_STRING', 'REQUEST_URI', 'SERVER_NAME', 'CONTENT_LENGTH', 'SERVER_PORT', 'SCRIPT_NAME', 'REQUEST_BODY', 'REQUEST_METHOD'): + for k in ( + "QUERY_STRING", + "REQUEST_URI", + "SERVER_NAME", + "CONTENT_LENGTH", + "SERVER_PORT", + "SCRIPT_NAME", + "REQUEST_BODY", + "REQUEST_METHOD", + ): try: del os.environ[k] except KeyError: @@ -45,50 +54,54 @@ def _set_env(env={}): def test_requestHeaders(self): """Test request headers""" - headers = {'header-key-1': 'header-value-1', - 'header-key-2': 'header-value-2'} + headers = {"header-key-1": "header-value-1", "header-key-2": "header-value-2"} request = QgsServerRequest( - 'http://somesite.com/somepath', QgsServerRequest.GetMethod, headers) + "http://somesite.com/somepath", QgsServerRequest.GetMethod, headers + ) for k, v in request.headers().items(): self.assertEqual(headers[k], v) - request.removeHeader('header-key-1') - self.assertEqual(request.headers(), {'header-key-2': 'header-value-2'}) - request.setHeader('header-key-1', 'header-value-1') + request.removeHeader("header-key-1") + self.assertEqual(request.headers(), {"header-key-2": "header-value-2"}) + request.setHeader("header-key-1", "header-value-1") for k, v in request.headers().items(): self.assertEqual(headers[k], v) def test_requestParameters(self): """Test request parameters""" request = QgsServerRequest( - 'http://somesite.com/somepath?parm1=val1&parm2=val2', QgsServerRequest.GetMethod) - parameters = {'PARM1': 'val1', 'PARM2': 'val2'} + "http://somesite.com/somepath?parm1=val1&parm2=val2", + QgsServerRequest.GetMethod, + ) + parameters = {"PARM1": "val1", "PARM2": "val2"} for k, v in request.parameters().items(): self.assertEqual(parameters[k], v) - request.removeParameter('PARM1') - self.assertEqual(request.parameters(), {'PARM2': 'val2'}) - request.setHeader('PARM1', 'val1') + request.removeParameter("PARM1") + self.assertEqual(request.parameters(), {"PARM2": "val2"}) + request.setHeader("PARM1", "val1") for k, v in request.headers().items(): self.assertEqual(parameters[k], v) def test_requestParametersDecoding(self): """Test request parameters decoding""" request = QgsServerRequest( - 'http://somesite.com/somepath?parm1=val1%20%2B+val2', QgsServerRequest.GetMethod) - self.assertEqual(request.parameters()['PARM1'], 'val1 + val2') + "http://somesite.com/somepath?parm1=val1%20%2B+val2", + QgsServerRequest.GetMethod, + ) + self.assertEqual(request.parameters()["PARM1"], "val1 + val2") def test_requestUrl(self): """Test url""" request = QgsServerRequest( - 'http://somesite.com/somepath', QgsServerRequest.GetMethod) - self.assertEqual(request.url().toString(), - 'http://somesite.com/somepath') - request.setUrl(QUrl('http://someother.com/someotherpath')) - self.assertEqual(request.url().toString(), - 'http://someother.com/someotherpath') + "http://somesite.com/somepath", QgsServerRequest.GetMethod + ) + self.assertEqual(request.url().toString(), "http://somesite.com/somepath") + request.setUrl(QUrl("http://someother.com/someotherpath")) + self.assertEqual(request.url().toString(), "http://someother.com/someotherpath") def test_requestMethod(self): request = QgsServerRequest( - 'http://somesite.com/somepath', QgsServerRequest.GetMethod) + "http://somesite.com/somepath", QgsServerRequest.GetMethod + ) self.assertEqual(request.method(), QgsServerRequest.GetMethod) request.setMethod(QgsServerRequest.PostMethod) self.assertEqual(request.method(), QgsServerRequest.PostMethod) @@ -102,181 +115,251 @@ def _test_url(original_url, rewritten_url, env={}): self.assertEqual(request.originalUrl().toString(), original_url) self.assertEqual(request.url().toString(), rewritten_url) # Check MAP - if 'QUERY_STRING' in env: - map = {k.upper(): v[0] for k, v in parse_qs( - env['QUERY_STRING']).items()}['MAP'] + if "QUERY_STRING" in env: + map = { + k.upper(): v[0] for k, v in parse_qs(env["QUERY_STRING"]).items() + }["MAP"] else: - map = {k.upper(): v[0] for k, v in parse_qs( - urlparse(env['REQUEST_URI']).query).items()}['MAP'] - self.assertEqual(request.parameter('MAP'), map) - - _test_url('http://somesite.com/somepath/project1/', - 'http://somesite.com/somepath/project1/?map=/my/project1.qgs', { - 'REQUEST_URI': '/somepath/project1/', - 'SERVER_NAME': 'somesite.com', - 'QUERY_STRING': 'map=/my/project1.qgs' - }) - - _test_url('http://somesite.com/somepath/path/?token=QGIS2019', - 'http://somesite.com/somepath/path/?map=/my/path.qgs', { - 'REQUEST_URI': '/somepath/path/?token=QGIS2019', - 'SERVER_NAME': 'somesite.com', - 'QUERY_STRING': 'map=/my/path.qgs', - }) - - _test_url('http://somesite.com/somepath/index.html?map=/my/path.qgs', - 'http://somesite.com/somepath/index.html?map=/my/path.qgs', - { - 'REQUEST_URI': '/somepath/index.html?map=/my/path.qgs', - 'SERVER_NAME': 'somesite.com', - }) - - _test_url('http://somesite.com/somepath?map=/my/path.qgs', - 'http://somesite.com/somepath?map=/my/path.qgs', - { - 'REQUEST_URI': '/somepath?map=/my/path.qgs', - 'SERVER_NAME': 'somesite.com', - }) + map = { + k.upper(): v[0] + for k, v in parse_qs(urlparse(env["REQUEST_URI"]).query).items() + }["MAP"] + self.assertEqual(request.parameter("MAP"), map) + + _test_url( + "http://somesite.com/somepath/project1/", + "http://somesite.com/somepath/project1/?map=/my/project1.qgs", + { + "REQUEST_URI": "/somepath/project1/", + "SERVER_NAME": "somesite.com", + "QUERY_STRING": "map=/my/project1.qgs", + }, + ) + + _test_url( + "http://somesite.com/somepath/path/?token=QGIS2019", + "http://somesite.com/somepath/path/?map=/my/path.qgs", + { + "REQUEST_URI": "/somepath/path/?token=QGIS2019", + "SERVER_NAME": "somesite.com", + "QUERY_STRING": "map=/my/path.qgs", + }, + ) + + _test_url( + "http://somesite.com/somepath/index.html?map=/my/path.qgs", + "http://somesite.com/somepath/index.html?map=/my/path.qgs", + { + "REQUEST_URI": "/somepath/index.html?map=/my/path.qgs", + "SERVER_NAME": "somesite.com", + }, + ) + + _test_url( + "http://somesite.com/somepath?map=/my/path.qgs", + "http://somesite.com/somepath?map=/my/path.qgs", + { + "REQUEST_URI": "/somepath?map=/my/path.qgs", + "SERVER_NAME": "somesite.com", + }, + ) def test_fcgiRequestPOST(self): """Test various combinations of FCGI POST parameters with rewritten urls""" - def _check_links(params, method='GET'): + def _check_links(params, method="GET"): data = urlencode(params) - if method == 'GET': + if method == "GET": env = { - 'SERVER_NAME': 'www.myserver.com', - 'REQUEST_URI': '/aproject/', - 'QUERY_STRING': data, - 'REQUEST_METHOD': 'GET', + "SERVER_NAME": "www.myserver.com", + "REQUEST_URI": "/aproject/", + "QUERY_STRING": data, + "REQUEST_METHOD": "GET", } else: env = { - 'SERVER_NAME': 'www.myserver.com', - 'REQUEST_URI': '/aproject/', - 'REQUEST_BODY': data, - 'CONTENT_LENGTH': str(len(data)), - 'REQUEST_METHOD': 'POST', + "SERVER_NAME": "www.myserver.com", + "REQUEST_URI": "/aproject/", + "REQUEST_BODY": data, + "CONTENT_LENGTH": str(len(data)), + "REQUEST_METHOD": "POST", } self._set_env(env) request = QgsFcgiServerRequest() response = QgsBufferServerResponse() self.server.handleRequest(request, response) - self.assertNotIn(b'ServiceExceptionReport', response.body()) + self.assertNotIn(b"ServiceExceptionReport", response.body()) - if method == 'POST': - self.assertEqual(request.data(), data.encode('utf8')) + if method == "POST": + self.assertEqual(request.data(), data.encode("utf8")) else: original_url = request.originalUrl().toString() - self.assertTrue(original_url.startswith('http://www.myserver.com/aproject/')) - self.assertEqual(original_url.find(urlencode({'MAP': params['map']})), -1) + self.assertTrue( + original_url.startswith("http://www.myserver.com/aproject/") + ) + self.assertEqual( + original_url.find(urlencode({"MAP": params["map"]})), -1 + ) exp = re.compile(r'href="([^"]+)"', re.DOTALL | re.MULTILINE) - elems = exp.findall(bytes(response.body()).decode('utf8')) + elems = exp.findall(bytes(response.body()).decode("utf8")) self.assertGreater(len(elems), 0) for href in elems: - self.assertTrue(href.startswith('http://www.myserver.com/aproject/')) - self.assertEqual(href.find(urlencode({'MAP': params['map']})), -1) + self.assertTrue(href.startswith("http://www.myserver.com/aproject/")) + self.assertEqual(href.find(urlencode({"MAP": params["map"]})), -1) # Test post request handler params = { - 'map': os.path.join(self.testdata_path, 'test_project_wfs.qgs'), - 'REQUEST': 'GetCapabilities', - 'SERVICE': 'WFS', + "map": os.path.join(self.testdata_path, "test_project_wfs.qgs"), + "REQUEST": "GetCapabilities", + "SERVICE": "WFS", } _check_links(params) - _check_links(params, 'POST') - params['SERVICE'] = 'WMS' + _check_links(params, "POST") + params["SERVICE"] = "WMS" _check_links(params) - _check_links(params, 'POST') - params['SERVICE'] = 'WCS' + _check_links(params, "POST") + params["SERVICE"] = "WCS" _check_links(params) - _check_links(params, 'POST') - params['SERVICE'] = 'WMTS' + _check_links(params, "POST") + params["SERVICE"] = "WMTS" _check_links(params) - _check_links(params, 'POST') + _check_links(params, "POST") def test_fcgiRequestPOST_invalid_length_not_an_integer(self): """Test post request handler with wrong CONTENT_LENGTH""" - data = '+1' - self._set_env({ - 'SERVER_NAME': 'www.myserver.com', - 'SERVICE': 'WFS', - 'REQUEST_BODY': data, - 'CONTENT_LENGTH': "not an integer", - 'REQUEST_METHOD': 'POST', - }) + data = "+1" + self._set_env( + { + "SERVER_NAME": "www.myserver.com", + "SERVICE": "WFS", + "REQUEST_BODY": data, + "CONTENT_LENGTH": "not an integer", + "REQUEST_METHOD": "POST", + } + ) request = QgsFcgiServerRequest() self.assertTrue(request.hasError()) def test_fcgiRequestPOST_invalid_length_negative(self): """Test post request handler with wrong CONTENT_LENGTH""" - data = '+1' - self._set_env({ - 'SERVER_NAME': 'www.myserver.com', - 'SERVICE': 'WFS', - 'REQUEST_BODY': data, - 'CONTENT_LENGTH': "-1", - 'REQUEST_METHOD': 'POST', - }) + data = "+1" + self._set_env( + { + "SERVER_NAME": "www.myserver.com", + "SERVICE": "WFS", + "REQUEST_BODY": data, + "CONTENT_LENGTH": "-1", + "REQUEST_METHOD": "POST", + } + ) request = QgsFcgiServerRequest() self.assertTrue(request.hasError()) def test_fcgiRequestPOST_too_short_length(self): """Test post request handler with wrong CONTENT_LENGTH""" - data = '+1' - self._set_env({ - 'SERVER_NAME': 'www.myserver.com', - 'SERVICE': 'WFS', - 'REQUEST_BODY': data, - 'CONTENT_LENGTH': str(len(data) - 1), - 'REQUEST_METHOD': 'POST', - }) + data = "+1" + self._set_env( + { + "SERVER_NAME": "www.myserver.com", + "SERVICE": "WFS", + "REQUEST_BODY": data, + "CONTENT_LENGTH": str(len(data) - 1), + "REQUEST_METHOD": "POST", + } + ) request = QgsFcgiServerRequest() self.assertTrue(request.hasError()) def test_fcgiRequestBody(self): """Test request body""" - data = '+1' - self._set_env({ - 'SERVER_NAME': 'www.myserver.com', - 'SERVICE': 'WFS', - 'REQUEST_BODY': data, - 'CONTENT_LENGTH': str(len(data)), - 'REQUEST_METHOD': 'POST', - }) + data = "+1" + self._set_env( + { + "SERVER_NAME": "www.myserver.com", + "SERVICE": "WFS", + "REQUEST_BODY": data, + "CONTENT_LENGTH": str(len(data)), + "REQUEST_METHOD": "POST", + } + ) request = QgsFcgiServerRequest() self.assertFalse(request.hasError()) response = QgsBufferServerResponse() self.server.handleRequest(request, response) - self.assertEqual(request.parameter('REQUEST_BODY'), '+1') + self.assertEqual(request.parameter("REQUEST_BODY"), "+1") def test_add_parameters(self): request = QgsServerRequest() - request.setParameter('FOOBAR', 'foobar') - self.assertEqual(request.parameter('FOOBAR'), 'foobar') - self.assertEqual(request.parameter('UNKNOWN'), '') + request.setParameter("FOOBAR", "foobar") + self.assertEqual(request.parameter("FOOBAR"), "foobar") + self.assertEqual(request.parameter("UNKNOWN"), "") def test_headers(self): """Tests that the headers are working in Fcgi mode""" for header, env, enum, value in ( ("Host", "HTTP_HOST", QgsServerRequest.HOST, "example.com"), ("Forwarded", "HTTP_FORWARDED", QgsServerRequest.FORWARDED, "aaa"), - ("X-Forwarded-For", "HTTP_X_FORWARDED_FOR", QgsServerRequest.X_FORWARDED_FOR, "bbb"), - ("X-Forwarded-Host", "HTTP_X_FORWARDED_HOST", QgsServerRequest.X_FORWARDED_HOST, "ccc"), - ("X-Forwarded-Proto", "HTTP_X_FORWARDED_PROTO", QgsServerRequest.X_FORWARDED_PROTO, "ddd"), - ("X-Qgis-Service-Url", "HTTP_X_QGIS_SERVICE_URL", QgsServerRequest.X_QGIS_SERVICE_URL, "eee"), - ("X-Qgis-Wms-Service-Url", "HTTP_X_QGIS_WMS_SERVICE_URL", QgsServerRequest.X_QGIS_WMS_SERVICE_URL, "fff"), - ("X-Qgis-Wfs-Service-Url", "HTTP_X_QGIS_WFS_SERVICE_URL", QgsServerRequest.X_QGIS_WFS_SERVICE_URL, "ggg"), - ("X-Qgis-Wcs-Service-Url", "HTTP_X_QGIS_WCS_SERVICE_URL", QgsServerRequest.X_QGIS_WCS_SERVICE_URL, "hhh"), - ("X-Qgis-Wmts-Service-Url", "HTTP_X_QGIS_WMTS_SERVICE_URL", QgsServerRequest.X_QGIS_WMTS_SERVICE_URL, "iii"), + ( + "X-Forwarded-For", + "HTTP_X_FORWARDED_FOR", + QgsServerRequest.X_FORWARDED_FOR, + "bbb", + ), + ( + "X-Forwarded-Host", + "HTTP_X_FORWARDED_HOST", + QgsServerRequest.X_FORWARDED_HOST, + "ccc", + ), + ( + "X-Forwarded-Proto", + "HTTP_X_FORWARDED_PROTO", + QgsServerRequest.X_FORWARDED_PROTO, + "ddd", + ), + ( + "X-Qgis-Service-Url", + "HTTP_X_QGIS_SERVICE_URL", + QgsServerRequest.X_QGIS_SERVICE_URL, + "eee", + ), + ( + "X-Qgis-Wms-Service-Url", + "HTTP_X_QGIS_WMS_SERVICE_URL", + QgsServerRequest.X_QGIS_WMS_SERVICE_URL, + "fff", + ), + ( + "X-Qgis-Wfs-Service-Url", + "HTTP_X_QGIS_WFS_SERVICE_URL", + QgsServerRequest.X_QGIS_WFS_SERVICE_URL, + "ggg", + ), + ( + "X-Qgis-Wcs-Service-Url", + "HTTP_X_QGIS_WCS_SERVICE_URL", + QgsServerRequest.X_QGIS_WCS_SERVICE_URL, + "hhh", + ), + ( + "X-Qgis-Wmts-Service-Url", + "HTTP_X_QGIS_WMTS_SERVICE_URL", + QgsServerRequest.X_QGIS_WMTS_SERVICE_URL, + "iii", + ), ("Accept", "HTTP_ACCEPT", QgsServerRequest.ACCEPT, "jjj"), ("User-Agent", "HTTP_USER_AGENT", QgsServerRequest.USER_AGENT, "kkk"), - ("Authorization", "HTTP_AUTHORIZATION", QgsServerRequest.AUTHORIZATION, "lll"), + ( + "Authorization", + "HTTP_AUTHORIZATION", + QgsServerRequest.AUTHORIZATION, + "lll", + ), ): try: os.environ[env] = value @@ -289,5 +372,5 @@ def test_headers(self): del os.environ[env] -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_response.py b/tests/src/python/test_qgsserver_response.py index fd218b4aec17..f2fbf944186f 100644 --- a/tests/src/python/test_qgsserver_response.py +++ b/tests/src/python/test_qgsserver_response.py @@ -8,11 +8,12 @@ (at your option) any later version. """ + import unittest -__author__ = 'Alessandro Pasotti' -__date__ = '29/04/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "29/04/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.server import QgsBufferServerResponse @@ -22,15 +23,15 @@ class QgsServerResponseTest(unittest.TestCase): def test_responseHeaders(self): """Test response headers""" - headers = {'header-key-1': 'header-value-1', 'header-key-2': 'header-value-2'} + headers = {"header-key-1": "header-value-1", "header-key-2": "header-value-2"} response = QgsBufferServerResponse() for k, v in headers.items(): response.setHeader(k, v) for k, v in response.headers().items(): self.assertEqual(headers[k], v) - response.removeHeader('header-key-1') - self.assertEqual(response.headers(), {'header-key-2': 'header-value-2'}) - response.setHeader('header-key-1', 'header-value-1') + response.removeHeader("header-key-1") + self.assertEqual(response.headers(), {"header-key-2": "header-value-2"}) + response.setHeader("header-key-1", "header-value-1") for k, v in response.headers().items(): self.assertEqual(headers[k], v) @@ -44,19 +45,23 @@ def test_write(self): """Test that writing on the buffer sets the body""" # Set as str response = QgsBufferServerResponse() - response.write('Greetings from Essen Linux Hotel 2017 Hack Fest!') - self.assertEqual(bytes(response.body()), b'') + response.write("Greetings from Essen Linux Hotel 2017 Hack Fest!") + self.assertEqual(bytes(response.body()), b"") response.finish() - self.assertEqual(bytes(response.body()), b'Greetings from Essen Linux Hotel 2017 Hack Fest!') - self.assertEqual(response.headers(), {'Content-Length': '48'}) + self.assertEqual( + bytes(response.body()), b"Greetings from Essen Linux Hotel 2017 Hack Fest!" + ) + self.assertEqual(response.headers(), {"Content-Length": "48"}) # Set as a byte array response = QgsBufferServerResponse() - response.write(b'Greetings from Essen Linux Hotel 2017 Hack Fest!') - self.assertEqual(bytes(response.body()), b'') + response.write(b"Greetings from Essen Linux Hotel 2017 Hack Fest!") + self.assertEqual(bytes(response.body()), b"") response.finish() - self.assertEqual(bytes(response.body()), b'Greetings from Essen Linux Hotel 2017 Hack Fest!') + self.assertEqual( + bytes(response.body()), b"Greetings from Essen Linux Hotel 2017 Hack Fest!" + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_security.py b/tests/src/python/test_qgsserver_security.py index 2de5a5d883b3..221d50a5fdc6 100644 --- a/tests/src/python/test_qgsserver_security.py +++ b/tests/src/python/test_qgsserver_security.py @@ -8,16 +8,17 @@ (at your option) any later version. """ -__author__ = 'Paul Blottiere' -__date__ = '31/01/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Paul Blottiere" +__date__ = "31/01/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os from qgis.utils import spatialite_connect # Needed on Qt 5 so that the serialization of XML is consistent among all executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" import time import urllib.parse @@ -37,11 +38,11 @@ class TestQgsServerSecurity(QgsServerTestBase): @classmethod def setUpClass(cls): super().setUpClass() - cls.testdatapath = unitTestDataPath('qgis_server_security') + '/' - cls.db = os.path.join(cls.testdatapath, 'db.sqlite') - cls.db_clone = os.path.join(tempfile.gettempdir(), 'db_clone.sqlite') - cls.project = os.path.join(cls.testdatapath, 'project.qgs') - cls.project_clone = os.path.join(tempfile.gettempdir(), 'project.qgs') + cls.testdatapath = unitTestDataPath("qgis_server_security") + "/" + cls.db = os.path.join(cls.testdatapath, "db.sqlite") + cls.db_clone = os.path.join(tempfile.gettempdir(), "db_clone.sqlite") + cls.project = os.path.join(cls.testdatapath, "project.qgs") + cls.project_clone = os.path.join(tempfile.gettempdir(), "project.qgs") cls.app = QgsApplication([], False) @classmethod @@ -92,7 +93,7 @@ def test_wms_getfeatureinfo_filter_time_based_blind(self): conn = spatialite_connect(self.db_clone) cur = conn.cursor() sql = "select sqlite_version()" - sqlite_version = '' + sqlite_version = "" for row in cur.execute(sql): sqlite_version = row[0] conn.close() @@ -109,7 +110,8 @@ def test_wms_getfeatureinfo_filter_time_based_blind(self): # third step, check the time of response for a valid version # maximum: several seconds injection_sql = ") and (select case sqlite_version() when '{}' then substr(upper(hex(randomblob(99999999))),0,1) end)--".format( - sqlite_version) + sqlite_version + ) query = f"{filter_sql} {injection_sql}" start = time.time() @@ -119,7 +121,9 @@ def test_wms_getfeatureinfo_filter_time_based_blind(self): # compare duration. On my computer when safety check is deactivated: # duration_invalid_version: 0.012360334396362305 # duration_valid_version: 2.8810460567474365 - self.assertAlmostEqual(duration_valid_version, duration_invalid_version, delta=0.5) + self.assertAlmostEqual( + duration_valid_version, duration_invalid_version, delta=0.5 + ) def test_wms_getfeatureinfo_filter_stacked(self): """ @@ -149,12 +153,12 @@ def test_wms_getfeatureinfo_filter_union_0(self): """ filter_sql = "point:\"name\" = 'fake'" - injection_sql = ") union select 1,1,name,1,1 from sqlite_master where type = \"table\" order by name--" + injection_sql = ') union select 1,1,name,1,1 from sqlite_master where type = "table" order by name--' query = f"{filter_sql} {injection_sql}" d, h = self.handle_request_wms_getfeatureinfo(query) - self.assertNotIn(b'SpatialIndex', d) + self.assertNotIn(b"SpatialIndex", d) def test_wms_getfeatureinfo_filter_union_1(self): """ @@ -171,7 +175,7 @@ def test_wms_getfeatureinfo_filter_union_1(self): query = f"{filter_sql} {injection_sql}" d, h = self.handle_request_wms_getfeatureinfo(query) - self.assertNotIn(b'private_value', d) + self.assertNotIn(b"private_value", d) def test_wms_getfeatureinfo_filter_unicode(self): """ @@ -276,22 +280,25 @@ def test_wfs_getfeature_filter_stacked(self): # ogc:Literal / ogc:PropertyIsEqualTo literal = "4')); drop table point --" - filter_xml = "pkuid{}".format( - literal) + filter_xml = 'pkuid{}'.format( + literal + ) self.handle_request_wfs_getfeature_filter(filter_xml) self.assertTrue(self.is_point_table_still_exist()) # ogc:Literal / ogc:PropertyIsLike literal = "4')); drop table point --" - filter_xml = "pkuid{}".format( - literal) + filter_xml = 'pkuid{}'.format( + literal + ) self.handle_request_wfs_getfeature_filter(filter_xml) self.assertTrue(self.is_point_table_still_exist()) # ogc:PropertyName / ogc:PropertyIsLike propname = "name = 'a')); drop table point --" - filter_xml = "{}4".format( - propname) + filter_xml = '{}4'.format( + propname + ) self.handle_request_wfs_getfeature_filter(filter_xml) self.assertTrue(self.is_point_table_still_exist()) @@ -310,22 +317,25 @@ def test_wms_getmap_filter_stacked(self): # ogc:Literal / ogc:PropertyIsEqualTo literal = "4')); drop table point --" - filter_xml = "pkuid{}".format( - literal) + filter_xml = 'pkuid{}'.format( + literal + ) self.handle_request_wms_getmap(filter=filter_xml) self.assertTrue(self.is_point_table_still_exist()) # ogc:Literal / ogc:PropertyIsLike literal = "4')); drop table point --" - filter_xml = "pkuid{}".format( - literal) + filter_xml = 'pkuid{}'.format( + literal + ) self.handle_request_wms_getmap(filter=filter_xml) self.assertTrue(self.is_point_table_still_exist()) # ogc:PropertyName / ogc:PropertyIsLike propname = "name = 'a')); drop table point --" - filter_xml = "{}4".format( - propname) + filter_xml = '{}4'.format( + propname + ) self.handle_request_wms_getmap(filter=filter_xml) self.assertTrue(self.is_point_table_still_exist()) @@ -342,8 +352,9 @@ def test_wms_getmap_sld_stacked(self): """ literal = "4')); drop table point --" - sld = " point point Single symbol pkuid {} circle 5e86a10000007".format( - literal) + sld = ' point point Single symbol pkuid {} circle 5e86a10000007'.format( + literal + ) self.handle_request_wms_getmap(sld=sld) self.assertTrue(self.is_point_table_still_exist()) @@ -352,39 +363,51 @@ def check_service_exception_report(self, d): Return True if a ServiceExceptionReport is raised, False otherwise """ - if b'\s]+=[^>\s]+' +RE_STRIP_UNCHECKABLE = rb'MAP=[^"]+|Content-Length: \d+|timeStamp="[^"]+"' +RE_ATTRIBUTES = rb"[^>\s]+=[^>\s]+" class TestQgsServerWFS(QgsServerTestBase): @@ -53,105 +54,132 @@ class TestQgsServerWFS(QgsServerTestBase): # Set to True in child classes to re-generate reference files for this class regenerate_reference = False - def wfs_request_compare(self, - request, version='', - extra_query_string='', - reference_base_name=None, - project_file="test_project_wfs.qgs", - requestMethod=QgsServerRequest.GetMethod, - data=None): + def wfs_request_compare( + self, + request, + version="", + extra_query_string="", + reference_base_name=None, + project_file="test_project_wfs.qgs", + requestMethod=QgsServerRequest.GetMethod, + data=None, + ): project = self.testdata_path + project_file assert os.path.exists(project), "Project file not found: " + project - query_string = '?MAP={}&SERVICE=WFS&REQUEST={}'.format( - urllib.parse.quote(project), request) + query_string = "?MAP={}&SERVICE=WFS&REQUEST={}".format( + urllib.parse.quote(project), request + ) if version: - query_string += f'&VERSION={version}' + query_string += f"&VERSION={version}" if extra_query_string: - query_string += f'&{extra_query_string}' + query_string += f"&{extra_query_string}" header, body = self._execute_request( - query_string, requestMethod=requestMethod, data=data) + query_string, requestMethod=requestMethod, data=data + ) self.assert_headers(header, body) response = header + body if reference_base_name is not None: reference_name = reference_base_name else: - reference_name = 'wfs_' + request.lower() + reference_name = "wfs_" + request.lower() - if version == '1.0.0': - reference_name += '_1_0_0' - reference_name += '.txt' + if version == "1.0.0": + reference_name += "_1_0_0" + reference_name += ".txt" reference_path = self.testdata_path + reference_name self.store_reference(reference_path, response) - f = open(reference_path, 'rb') + f = open(reference_path, "rb") expected = f.read() f.close() - response = re.sub(RE_STRIP_UNCHECKABLE, b'', response) - expected = re.sub(RE_STRIP_UNCHECKABLE, b'', expected) + response = re.sub(RE_STRIP_UNCHECKABLE, b"", response) + expected = re.sub(RE_STRIP_UNCHECKABLE, b"", expected) # depending on flex/bison versions, these strings will be interchangeable - response = response.replace(b'end of file', b'$end') + response = response.replace(b"end of file", b"$end") - self.assertXMLEqual(response, expected, msg="request {} failed.\n Query: {}".format( - query_string, request)) + self.assertXMLEqual( + response, + expected, + msg=f"request {query_string} failed.\n Query: {request}", + ) return header, body def test_operation_not_supported(self): - qs = f'?MAP={urllib.parse.quote(self.projectPath)}&SERVICE=WFS&VERSION=1.1.0&REQUEST=NotAValidRequest' + qs = f"?MAP={urllib.parse.quote(self.projectPath)}&SERVICE=WFS&VERSION=1.1.0&REQUEST=NotAValidRequest" self._assert_status_code(501, qs) def test_project_wfs(self): """Test some WFS request""" - for request in ('GetCapabilities', 'DescribeFeatureType'): + for request in ("GetCapabilities", "DescribeFeatureType"): self.wfs_request_compare(request) - self.wfs_request_compare(request, '1.0.0') + self.wfs_request_compare(request, "1.0.0") def wfs_getfeature_compare(self, requestid, request): project = self.testdata_path + "test_project_wfs.qgs" assert os.path.exists(project), "Project file not found: " + project - query_string = '?MAP={}&SERVICE=WFS&VERSION=1.0.0&REQUEST={}'.format( - urllib.parse.quote(project), request) + query_string = "?MAP={}&SERVICE=WFS&VERSION=1.0.0&REQUEST={}".format( + urllib.parse.quote(project), request + ) header, body = self._execute_request(query_string) - if requestid == 'hits': - body = re.sub(br'timeStamp="\d+-\d+-\d+T\d+:\d+:\d+"', - b'timeStamp="****-**-**T**:**:**"', body) + if requestid == "hits": + body = re.sub( + rb'timeStamp="\d+-\d+-\d+T\d+:\d+:\d+"', + b'timeStamp="****-**-**T**:**:**"', + body, + ) self.result_compare( - 'wfs_getfeature_' + requestid + '.txt', + "wfs_getfeature_" + requestid + ".txt", f"request {query_string} failed.\n Query: {request}", - header, body + header, + body, ) def test_getfeature_invalid_typename(self): project = self.testdata_path + "test_project_wfs.qgs" # a single invalid typename - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WFS", - "REQUEST": "GetFeature", - "TYPENAME": "invalid" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WFS", + "REQUEST": "GetFeature", + "TYPENAME": "invalid", + }.items() + ) + ] + ) header, body = self._execute_request(qs) self.assertIn(b"TypeName 'invalid' could not be found", body) # an invalid typename preceded by a valid one - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WFS", - "REQUEST": "GetFeature", - "TYPENAME": "testlayer,invalid" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WFS", + "REQUEST": "GetFeature", + "TYPENAME": "testlayer,invalid", + }.items() + ) + ] + ) header, body = self._execute_request(qs) self.assertIn(b"TypeName 'invalid' could not be found", body) @@ -159,16 +187,18 @@ def test_getfeature_invalid_typename(self): def test_getfeature(self): tests = [] - tests.append(('nobbox', 'GetFeature&TYPENAME=testlayer')) + tests.append(("nobbox", "GetFeature&TYPENAME=testlayer")) + tests.append(("startindex2", "GetFeature&TYPENAME=testlayer&STARTINDEX=2")) + tests.append(("limit2", "GetFeature&TYPENAME=testlayer&MAXFEATURES=2")) tests.append( - ('startindex2', 'GetFeature&TYPENAME=testlayer&STARTINDEX=2')) - tests.append(('limit2', 'GetFeature&TYPENAME=testlayer&MAXFEATURES=2')) - tests.append( - ('start1_limit1', 'GetFeature&TYPENAME=testlayer&MAXFEATURES=1&STARTINDEX=1')) - tests.append( - ('srsname', 'GetFeature&TYPENAME=testlayer&SRSNAME=EPSG:3857')) - tests.append(('sortby', 'GetFeature&TYPENAME=testlayer&SORTBY=id D')) - tests.append(('hits', 'GetFeature&TYPENAME=testlayer&RESULTTYPE=hits')) + ( + "start1_limit1", + "GetFeature&TYPENAME=testlayer&MAXFEATURES=1&STARTINDEX=1", + ) + ) + tests.append(("srsname", "GetFeature&TYPENAME=testlayer&SRSNAME=EPSG:3857")) + tests.append(("sortby", "GetFeature&TYPENAME=testlayer&SORTBY=id D")) + tests.append(("hits", "GetFeature&TYPENAME=testlayer&RESULTTYPE=hits")) for id, req in tests: self.wfs_getfeature_compare(id, req) @@ -178,60 +208,79 @@ def test_getfeature_exp_filter(self): exp_filter = "EXP_FILTER=\"name\"='one';\"name\"='two'" req = f"SRSNAME=EPSG:4326&TYPENAME=testlayer,testlayer&{exp_filter}" self.wfs_request_compare( - "GetFeature", '1.0.0', req, 'wfs_getFeature_exp_filter_2') + "GetFeature", "1.0.0", req, "wfs_getFeature_exp_filter_2" + ) def test_wfs_getcapabilities_100_url(self): """Check that URL in GetCapabilities response is complete""" # empty url in project - project = os.path.join( - self.testdata_path, "test_project_without_urls.qgs") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WFS", - "VERSION": "1.0.0", - "REQUEST": "GetCapabilities" - }.items())]) + project = os.path.join(self.testdata_path, "test_project_without_urls.qgs") + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WFS", + "VERSION": "1.0.0", + "REQUEST": "GetCapabilities", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) for item in str(r).split("\\n"): if "onlineResource" in item: - self.assertEqual("onlineResource=\"?" in item, True) + self.assertEqual('onlineResource="?' in item, True) # url well defined in query string - project = os.path.join( - self.testdata_path, "test_project_without_urls.qgs") - qs = "https://www.qgis-server.org?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WFS", - "VERSION": "1.0.0", - "REQUEST": "GetCapabilities" - }.items())]) + project = os.path.join(self.testdata_path, "test_project_without_urls.qgs") + qs = "https://www.qgis-server.org?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WFS", + "VERSION": "1.0.0", + "REQUEST": "GetCapabilities", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) for item in str(r).split("\\n"): if "onlineResource" in item: self.assertTrue( - "onlineResource=\"https://www.qgis-server.org?" in item, True) + 'onlineResource="https://www.qgis-server.org?' in item, True + ) # url well defined in project - project = os.path.join( - self.testdata_path, "test_project_with_urls.qgs") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WFS", - "VERSION": "1.0.0", - "REQUEST": "GetCapabilities" - }.items())]) + project = os.path.join(self.testdata_path, "test_project_with_urls.qgs") + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WFS", + "VERSION": "1.0.0", + "REQUEST": "GetCapabilities", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) for item in str(r).split("\\n"): if "onlineResource" in item: - self.assertEqual( - "onlineResource=\"my_wfs_advertised_url\"" in item, True) + self.assertEqual('onlineResource="my_wfs_advertised_url"' in item, True) def test_wfs_getcapabilities_110_no_data(self): """Check that GetCapabilities response is correct if a layer @@ -240,19 +289,27 @@ def test_wfs_getcapabilities_110_no_data(self): project = self.testdata_path + "test_wfs_no_data.qgs" self.assertTrue(os.path.exists(project), "Project file not found: " + project) - query_string = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WFS", - "VERSION": "1.1.0", - "REQUEST": "GetCapabilities" - }.items())]) + query_string = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WFS", + "VERSION": "1.1.0", + "REQUEST": "GetCapabilities", + }.items() + ) + ] + ) header, body = self._execute_request(query_string) self.result_compare( "wfs_getCapabilities_1_1_0_no_data.txt", f"request {query_string} failed.\n Query: GetCapabilities", - header, body + header, + body, ) def result_compare(self, file_name, error_msg_header, header, body): @@ -261,11 +318,11 @@ def result_compare(self, file_name, error_msg_header, header, body): response = header + body reference_path = self.testdata_path + file_name self.store_reference(reference_path, response) - f = open(reference_path, 'rb') + f = open(reference_path, "rb") expected = f.read() f.close() - response = re.sub(RE_STRIP_UNCHECKABLE, b'', response) - expected = re.sub(RE_STRIP_UNCHECKABLE, b'', expected) + response = re.sub(RE_STRIP_UNCHECKABLE, b"", response) + expected = re.sub(RE_STRIP_UNCHECKABLE, b"", expected) self.assertXMLEqual(response, expected, msg=f"{error_msg_header}\n") def wfs_getfeature_post_compare(self, requestid, request): @@ -273,14 +330,18 @@ def wfs_getfeature_post_compare(self, requestid, request): project = self.testdata_path + "test_project_wfs.qgs" assert os.path.exists(project), "Project file not found: " + project - query_string = f'?MAP={urllib.parse.quote(project)}' + query_string = f"?MAP={urllib.parse.quote(project)}" header, body = self._execute_request( - query_string, requestMethod=QgsServerRequest.PostMethod, data=request.encode('utf-8')) + query_string, + requestMethod=QgsServerRequest.PostMethod, + data=request.encode("utf-8"), + ) self.result_compare( - f'wfs_getfeature_{requestid}.txt', + f"wfs_getfeature_{requestid}.txt", f"GetFeature in POST for '{requestid}' failed.", - header, body, + header, + body, ) def test_getfeature_post(self): @@ -301,16 +362,29 @@ def test_getfeature_post(self): """ - for version in ['1.0.0', '1.1.0']: - version_underscore = '_' + version.replace(".", "_") - tests.append((f'nobbox_post{version_underscore}', template.format( - version, ""))) - tests.append((f'startindex2_post{version_underscore}', template.format( - version, 'startIndex="2"'))) - tests.append((f'limit2_post{version_underscore}', template.format( - version, 'maxFeatures="2"'))) - tests.append((f'start1_limit1_post{version_underscore}', template.format( - version, 'startIndex="1" maxFeatures="1"'))) + for version in ["1.0.0", "1.1.0"]: + version_underscore = "_" + version.replace(".", "_") + tests.append( + (f"nobbox_post{version_underscore}", template.format(version, "")) + ) + tests.append( + ( + f"startindex2_post{version_underscore}", + template.format(version, 'startIndex="2"'), + ) + ) + tests.append( + ( + f"limit2_post{version_underscore}", + template.format(version, 'maxFeatures="2"'), + ) + ) + tests.append( + ( + f"start1_limit1_post{version_underscore}", + template.format(version, 'startIndex="1" maxFeatures="1"'), + ) + ) srsTemplate = """ @@ -327,12 +401,24 @@ def test_getfeature_post(self): """ - tests.append(('srsname_post_1_0_0', srsTemplate.format( - '1.0.0', '', 'srsName="EPSG:3857"'))) - tests.append(('srsname_post_1_1_0', srsTemplate.format( - '1.1.0', '', 'srsName="EPSG:3857"'))) - tests.append(('srsname_post_1_1_0_urn', srsTemplate.format( - '1.1.0', '', 'srsName="urn:ogc:def:crs:EPSG::3857"'))) + tests.append( + ( + "srsname_post_1_0_0", + srsTemplate.format("1.0.0", "", 'srsName="EPSG:3857"'), + ) + ) + tests.append( + ( + "srsname_post_1_1_0", + srsTemplate.format("1.1.0", "", 'srsName="EPSG:3857"'), + ) + ) + tests.append( + ( + "srsname_post_1_1_0_urn", + srsTemplate.format("1.1.0", "", 'srsName="urn:ogc:def:crs:EPSG::3857"'), + ) + ) # Issue https://github.com/qgis/QGIS/issues/36398 # Check get feature within polygon having srsName=EPSG:4326 (same as the project/layer) @@ -360,7 +446,9 @@ def test_getfeature_post(self): """ - tests.append(('within4326FilterTemplate_post', within4326FilterTemplate.format(""))) + tests.append( + ("within4326FilterTemplate_post", within4326FilterTemplate.format("")) + ) # Check get feature within polygon having srsName=EPSG:3857 (different from the project/layer) # The coordinates are converted from the one in 4326 @@ -388,7 +476,9 @@ def test_getfeature_post(self): """ - tests.append(('within3857FilterTemplate_post', within3857FilterTemplate.format(""))) + tests.append( + ("within3857FilterTemplate_post", within3857FilterTemplate.format("")) + ) srsTwoLayersTemplate = """ @@ -416,7 +506,7 @@ def test_getfeature_post(self): """ - tests.append(('srs_two_layers_post', srsTwoLayersTemplate.format(""))) + tests.append(("srs_two_layers_post", srsTwoLayersTemplate.format(""))) sortTemplate = """ @@ -439,7 +529,7 @@ def test_getfeature_post(self): """ - tests.append(('sortby_post', sortTemplate.format(""))) + tests.append(("sortby_post", sortTemplate.format(""))) andTemplate = """ @@ -459,7 +549,7 @@ def test_getfeature_post(self): """ - tests.append(('and_post', andTemplate.format(""))) + tests.append(("and_post", andTemplate.format(""))) andBboxTemplate = """ @@ -486,7 +576,7 @@ def test_getfeature_post(self): """ - tests.append(('bbox_inside_and_post', andBboxTemplate.format(""))) + tests.append(("bbox_inside_and_post", andBboxTemplate.format(""))) # With namespace template = """ @@ -504,7 +594,7 @@ def test_getfeature_post(self): """ - tests.append(('nobbox_post_1_0_0', template.format(""))) + tests.append(("nobbox_post_1_0_0", template.format(""))) template = """ @@ -521,7 +611,7 @@ def test_getfeature_post(self): """ - tests.append(('nobbox_post_1_0_0', template.format(""))) + tests.append(("nobbox_post_1_0_0", template.format(""))) for id, req in tests: self.wfs_getfeature_post_compare(id, req) @@ -531,152 +621,333 @@ def test_getFeatureBBOX(self): # Tests without CRS self.wfs_request_compare( - "GetFeature", '1.0.0', "TYPENAME=testlayer&RESULTTYPE=hits&BBOX=8.20347,44.901471,8.2035354,44.901493", 'wfs_getFeature_1_0_0_bbox_1_feature') + "GetFeature", + "1.0.0", + "TYPENAME=testlayer&RESULTTYPE=hits&BBOX=8.20347,44.901471,8.2035354,44.901493", + "wfs_getFeature_1_0_0_bbox_1_feature", + ) self.wfs_request_compare( - "GetFeature", '1.0.0', "TYPENAME=testlayer&RESULTTYPE=hits&BBOX=8.203127,44.9012765,8.204138,44.901632", 'wfs_getFeature_1_0_0_bbox_3_feature') + "GetFeature", + "1.0.0", + "TYPENAME=testlayer&RESULTTYPE=hits&BBOX=8.203127,44.9012765,8.204138,44.901632", + "wfs_getFeature_1_0_0_bbox_3_feature", + ) # Tests with CRS self.wfs_request_compare( - "GetFeature", '1.0.0', "SRSNAME=EPSG:4326&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=8.20347,44.901471,8.2035354,44.901493,EPSG:4326", 'wfs_getFeature_1_0_0_epsgbbox_1_feature') + "GetFeature", + "1.0.0", + "SRSNAME=EPSG:4326&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=8.20347,44.901471,8.2035354,44.901493,EPSG:4326", + "wfs_getFeature_1_0_0_epsgbbox_1_feature", + ) + self.wfs_request_compare( + "GetFeature", + "1.0.0", + "SRSNAME=EPSG:4326&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=8.203127,44.9012765,8.204138,44.901632,EPSG:4326", + "wfs_getFeature_1_0_0_epsgbbox_3_feature", + ) + self.wfs_request_compare( + "GetFeature", + "1.1.0", + "SRSNAME=EPSG:4326&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=8.20347,44.901471,8.2035354,44.901493,EPSG:4326", + "wfs_getFeature_1_1_0_epsgbbox_1_feature", + ) + self.wfs_request_compare( + "GetFeature", + "1.1.0", + "SRSNAME=EPSG:4326&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=8.203127,44.9012765,8.204138,44.901632,EPSG:4326", + "wfs_getFeature_1_1_0_epsgbbox_3_feature", + ) + + self.wfs_request_compare( + "GetFeature", + "1.0.0", + "SRSNAME=EPSG:4326&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=913144,5605992,913303,5606048,EPSG:3857", + "wfs_getFeature_1_0_0_epsgbbox_3_feature_3857", + ) + self.wfs_request_compare( + "GetFeature", + "1.0.0", + "SRSNAME=EPSG:4326&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=913206,5606024,913213,5606026,EPSG:3857", + "wfs_getFeature_1_0_0_epsgbbox_1_feature_3857", + ) self.wfs_request_compare( - "GetFeature", '1.0.0', "SRSNAME=EPSG:4326&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=8.203127,44.9012765,8.204138,44.901632,EPSG:4326", 'wfs_getFeature_1_0_0_epsgbbox_3_feature') + "GetFeature", + "1.1.0", + "SRSNAME=EPSG:4326&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=913144,5605992,913303,5606048,EPSG:3857", + "wfs_getFeature_1_1_0_epsgbbox_3_feature_3857", + ) self.wfs_request_compare( - "GetFeature", '1.1.0', "SRSNAME=EPSG:4326&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=8.20347,44.901471,8.2035354,44.901493,EPSG:4326", 'wfs_getFeature_1_1_0_epsgbbox_1_feature') + "GetFeature", + "1.1.0", + "SRSNAME=EPSG:4326&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=913206,5606024,913213,5606026,EPSG:3857", + "wfs_getFeature_1_1_0_epsgbbox_1_feature_3857", + ) + + self.wfs_request_compare( + "GetFeature", + "1.0.0", + "SRSNAME=EPSG:3857&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=913144,5605992,913303,5606048,EPSG:3857", + "wfs_getFeature_1_0_0_epsgbbox_3_feature_3857", + ) self.wfs_request_compare( - "GetFeature", '1.1.0', "SRSNAME=EPSG:4326&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=8.203127,44.9012765,8.204138,44.901632,EPSG:4326", 'wfs_getFeature_1_1_0_epsgbbox_3_feature') - - self.wfs_request_compare("GetFeature", '1.0.0', "SRSNAME=EPSG:4326&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=913144,5605992,913303,5606048,EPSG:3857", - 'wfs_getFeature_1_0_0_epsgbbox_3_feature_3857') - self.wfs_request_compare("GetFeature", '1.0.0', "SRSNAME=EPSG:4326&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=913206,5606024,913213,5606026,EPSG:3857", - 'wfs_getFeature_1_0_0_epsgbbox_1_feature_3857') - self.wfs_request_compare("GetFeature", '1.1.0', "SRSNAME=EPSG:4326&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=913144,5605992,913303,5606048,EPSG:3857", - 'wfs_getFeature_1_1_0_epsgbbox_3_feature_3857') - self.wfs_request_compare("GetFeature", '1.1.0', "SRSNAME=EPSG:4326&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=913206,5606024,913213,5606026,EPSG:3857", - 'wfs_getFeature_1_1_0_epsgbbox_1_feature_3857') - - self.wfs_request_compare("GetFeature", '1.0.0', "SRSNAME=EPSG:3857&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=913144,5605992,913303,5606048,EPSG:3857", - 'wfs_getFeature_1_0_0_epsgbbox_3_feature_3857') - self.wfs_request_compare("GetFeature", '1.0.0', "SRSNAME=EPSG:3857&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=913206,5606024,913213,5606026,EPSG:3857", - 'wfs_getFeature_1_0_0_epsgbbox_1_feature_3857') - self.wfs_request_compare("GetFeature", '1.1.0', "SRSNAME=EPSG:3857&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=913144,5605992,913303,5606048,EPSG:3857", - 'wfs_getFeature_1_1_0_epsgbbox_3_feature_3857') - self.wfs_request_compare("GetFeature", '1.1.0', "SRSNAME=EPSG:3857&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=913206,5606024,913213,5606026,EPSG:3857", - 'wfs_getFeature_1_1_0_epsgbbox_1_feature_3857') + "GetFeature", + "1.0.0", + "SRSNAME=EPSG:3857&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=913206,5606024,913213,5606026,EPSG:3857", + "wfs_getFeature_1_0_0_epsgbbox_1_feature_3857", + ) + self.wfs_request_compare( + "GetFeature", + "1.1.0", + "SRSNAME=EPSG:3857&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=913144,5605992,913303,5606048,EPSG:3857", + "wfs_getFeature_1_1_0_epsgbbox_3_feature_3857", + ) + self.wfs_request_compare( + "GetFeature", + "1.1.0", + "SRSNAME=EPSG:3857&TYPENAME=testlayer&RESULTTYPE=hits&BBOX=913206,5606024,913213,5606026,EPSG:3857", + "wfs_getFeature_1_1_0_epsgbbox_1_feature_3857", + ) def test_getFeatureFeatureId(self): """Test GetFeature with featureid""" self.wfs_request_compare( - "GetFeature", '1.0.0', "SRSNAME=EPSG:4326&TYPENAME=testlayer&FEATUREID=testlayer.0", 'wfs_getFeature_1_0_0_featureid_0') + "GetFeature", + "1.0.0", + "SRSNAME=EPSG:4326&TYPENAME=testlayer&FEATUREID=testlayer.0", + "wfs_getFeature_1_0_0_featureid_0", + ) # with multiple feature ids self.wfs_request_compare( - "GetFeature", '1.0.0', "SRSNAME=EPSG:4326&TYPENAME=testlayer&FEATUREID=testlayer.0,testlayer.2", 'wfs_getFeature_1_0_0_featureid_02') + "GetFeature", + "1.0.0", + "SRSNAME=EPSG:4326&TYPENAME=testlayer&FEATUREID=testlayer.0,testlayer.2", + "wfs_getFeature_1_0_0_featureid_02", + ) # with layer name Testing Layer (copy) self.wfs_request_compare( - "GetFeature", '1.0.0', "SRSNAME=EPSG:4326&TYPENAME=Testing_Layer_(copy)&FEATUREID=Testing_Layer_(copy).0", 'wfs_getFeature_1_0_0_featureid_0_testing') + "GetFeature", + "1.0.0", + "SRSNAME=EPSG:4326&TYPENAME=Testing_Layer_(copy)&FEATUREID=Testing_Layer_(copy).0", + "wfs_getFeature_1_0_0_featureid_0_testing", + ) # with propertynanme * self.wfs_request_compare( - "GetFeature", '1.0.0', "SRSNAME=EPSG:4326&TYPENAME=testlayer&FEATUREID=testlayer.0&PROPERTYNAME=*", 'wfs_getFeature_1_0_0_featureid_0') + "GetFeature", + "1.0.0", + "SRSNAME=EPSG:4326&TYPENAME=testlayer&FEATUREID=testlayer.0&PROPERTYNAME=*", + "wfs_getFeature_1_0_0_featureid_0", + ) def test_getFeatureFeature11urn(self): """Test GetFeature with SRSNAME as urn:ogc:def:crs:EPSG::X""" # urn:ogc:def:crs:EPSG::4326 self.wfs_request_compare( - "GetFeature", '1.1.0', "SRSNAME=urn:ogc:def:crs:EPSG::4326&TYPENAME=testlayer&FEATUREID=testlayer.0", 'wfs_getFeature_1_1_0_featureid_0_1_1_0') + "GetFeature", + "1.1.0", + "SRSNAME=urn:ogc:def:crs:EPSG::4326&TYPENAME=testlayer&FEATUREID=testlayer.0", + "wfs_getFeature_1_1_0_featureid_0_1_1_0", + ) # urn:ogc:def:crs:EPSG::3857 self.wfs_request_compare( - "GetFeature", '1.1.0', "SRSNAME=urn:ogc:def:crs:EPSG::3857&TYPENAME=testlayer&FEATUREID=testlayer.0", 'wfs_getFeature_1_1_0_featureid_0_1_1_0_epsg3857') + "GetFeature", + "1.1.0", + "SRSNAME=urn:ogc:def:crs:EPSG::3857&TYPENAME=testlayer&FEATUREID=testlayer.0", + "wfs_getFeature_1_1_0_featureid_0_1_1_0_epsg3857", + ) def test_get_feature_srsname_empty(self): """Test GetFeature with an empty SRSNAME.""" self.wfs_request_compare( - "GetFeature", '1.1.0', "TYPENAME=testlayer&FEATUREID=testlayer.0", 'wfs_getFeature_1_1_0_featureid_0_1_1_0_srsname') + "GetFeature", + "1.1.0", + "TYPENAME=testlayer&FEATUREID=testlayer.0", + "wfs_getFeature_1_1_0_featureid_0_1_1_0_srsname", + ) def test_get_feature_wrong_version_nomber(self): """Test GetFeature with a wrong version number. - This should fall back to the default version: 1.1.0 + This should fall back to the default version: 1.1.0 """ self.wfs_request_compare( - "GetFeature", '2.0.0', "SRSNAME=urn:ogc:def:crs:EPSG::4326&TYPENAME=testlayer&FEATUREID=testlayer.0", 'wfs_getFeature_1_1_0_featureid_0_1_1_0') + "GetFeature", + "2.0.0", + "SRSNAME=urn:ogc:def:crs:EPSG::4326&TYPENAME=testlayer&FEATUREID=testlayer.0", + "wfs_getFeature_1_1_0_featureid_0_1_1_0", + ) self.wfs_request_compare( - "GetFeature", '2.0.0', "TYPENAME=testlayer&FEATUREID=testlayer.0", 'wfs_getFeature_1_1_0_featureid_0_1_1_0_srsname') + "GetFeature", + "2.0.0", + "TYPENAME=testlayer&FEATUREID=testlayer.0", + "wfs_getFeature_1_1_0_featureid_0_1_1_0_srsname", + ) def test_getFeature_EXP_FILTER_regression_20927(self): """Test expressions with EXP_FILTER""" self.wfs_request_compare( - "GetFeature", '1.0.0', "SRSNAME=EPSG:4326&TYPENAME=testlayer&FEATUREID=testlayer.0&EXP_FILTER=\"name\"='one'", 'wfs_getFeature_1_0_0_EXP_FILTER_FID_one') + "GetFeature", + "1.0.0", + "SRSNAME=EPSG:4326&TYPENAME=testlayer&FEATUREID=testlayer.0&EXP_FILTER=\"name\"='one'", + "wfs_getFeature_1_0_0_EXP_FILTER_FID_one", + ) # Note that FEATUREID takes precedence over EXP_FILTER and the filter is completely ignored when FEATUREID is set self.wfs_request_compare( - "GetFeature", '1.0.0', "SRSNAME=EPSG:4326&TYPENAME=testlayer&FEATUREID=testlayer.0&EXP_FILTER=\"name\"='two'", 'wfs_getFeature_1_0_0_EXP_FILTER_FID_one') + "GetFeature", + "1.0.0", + "SRSNAME=EPSG:4326&TYPENAME=testlayer&FEATUREID=testlayer.0&EXP_FILTER=\"name\"='two'", + "wfs_getFeature_1_0_0_EXP_FILTER_FID_one", + ) self.wfs_request_compare( - "GetFeature", '1.0.0', "SRSNAME=EPSG:4326&TYPENAME=testlayer&EXP_FILTER=\"name\"='two'", 'wfs_getFeature_1_0_0_EXP_FILTER_two') + "GetFeature", + "1.0.0", + "SRSNAME=EPSG:4326&TYPENAME=testlayer&EXP_FILTER=\"name\"='two'", + "wfs_getFeature_1_0_0_EXP_FILTER_two", + ) self.wfs_request_compare( - "GetFeature", '1.0.0', "SRSNAME=EPSG:4326&TYPENAME=testlayer&EXP_FILTER=\"name\"=concat('tw', 'o')", 'wfs_getFeature_1_0_0_EXP_FILTER_two') + "GetFeature", + "1.0.0", + "SRSNAME=EPSG:4326&TYPENAME=testlayer&EXP_FILTER=\"name\"=concat('tw', 'o')", + "wfs_getFeature_1_0_0_EXP_FILTER_two", + ) # Syntax ok but function does not exist - self.wfs_request_compare("GetFeature", '1.0.0', "SRSNAME=EPSG:4326&TYPENAME=testlayer&EXP_FILTER=\"name\"=invalid_expression('tw', 'o')", - 'wfs_getFeature_1_0_0_EXP_FILTER_invalid_expression') + self.wfs_request_compare( + "GetFeature", + "1.0.0", + "SRSNAME=EPSG:4326&TYPENAME=testlayer&EXP_FILTER=\"name\"=invalid_expression('tw', 'o')", + "wfs_getFeature_1_0_0_EXP_FILTER_invalid_expression", + ) # Syntax error in exp - self.wfs_request_compare("GetFeature", '1.0.0', "SRSNAME=EPSG:4326&TYPENAME=testlayer&EXP_FILTER=\"name\"=concat('tw, 'o')", - 'wfs_getFeature_1_0_0_EXP_FILTER_syntax_error') + self.wfs_request_compare( + "GetFeature", + "1.0.0", + "SRSNAME=EPSG:4326&TYPENAME=testlayer&EXP_FILTER=\"name\"=concat('tw, 'o')", + "wfs_getFeature_1_0_0_EXP_FILTER_syntax_error", + ) # BBOX gml expressions - self.wfs_request_compare("GetFeature", '1.0.0', "SRSNAME=EPSG:4326&TYPENAME=testlayer&EXP_FILTER=intersects($geometry, geom_from_gml(' 8.20344750430995617,44.9013881888184514 8.20347909100379269,44.90140004005827024'))", 'wfs_getFeature_1_0_0_EXP_FILTER_gml_bbox_three') - self.wfs_request_compare("GetFeature", '1.0.0', "SRSNAME=EPSG:4326&TYPENAME=testlayer&EXP_FILTER=intersects($geometry, geom_from_gml(' 8.20348458304175665,44.90147459621791626 8.20351616973559317,44.9014864474577351'))", 'wfs_getFeature_1_0_0_EXP_FILTER_gml_bbox_one') + self.wfs_request_compare( + "GetFeature", + "1.0.0", + 'SRSNAME=EPSG:4326&TYPENAME=testlayer&EXP_FILTER=intersects($geometry, geom_from_gml(\' 8.20344750430995617,44.9013881888184514 8.20347909100379269,44.90140004005827024\'))', + "wfs_getFeature_1_0_0_EXP_FILTER_gml_bbox_three", + ) + self.wfs_request_compare( + "GetFeature", + "1.0.0", + 'SRSNAME=EPSG:4326&TYPENAME=testlayer&EXP_FILTER=intersects($geometry, geom_from_gml(\' 8.20348458304175665,44.90147459621791626 8.20351616973559317,44.9014864474577351\'))', + "wfs_getFeature_1_0_0_EXP_FILTER_gml_bbox_one", + ) def test_describeFeatureType(self): """Test DescribeFeatureType with TYPENAME filters""" project_file = "test_project_wms_grouped_layers.qgs" - self.wfs_request_compare("DescribeFeatureType", '1.0.0', "TYPENAME=as_areas&", - 'wfs_describeFeatureType_1_0_0_typename_as_areas', project_file=project_file) - self.wfs_request_compare("DescribeFeatureType", '1.0.0', "TYPENAME=as_areas&OUTPUTFORMAT=XMLSCHEMA&", - 'wfs_describeFeatureType_1_0_0_typename_as_areas', project_file=project_file) - - self.wfs_request_compare("DescribeFeatureType", '1.1.0', "TYPENAME=as_areas&", - 'wfs_describeFeatureType_1_1_0_typename_as_areas', project_file=project_file) - self.wfs_request_compare("DescribeFeatureType", '1.1.0', "TYPENAME=as_areas&OUTPUTFORMAT=XMLSCHEMA&", - 'wfs_describeFeatureType_1_1_0_typename_as_areas', project_file=project_file) - self.wfs_request_compare("DescribeFeatureType", '1.1.0', "TYPENAME=as_areas&OUTPUTFORMAT=text/xml; subtype=gml/3.1.1&", - 'wfs_describeFeatureType_1_1_0_typename_as_areas', project_file=project_file) - - self.wfs_request_compare("DescribeFeatureType", '1.0.0', "", - 'wfs_describeFeatureType_1_0_0_typename_empty', project_file=project_file) - self.wfs_request_compare("DescribeFeatureType", '1.1.0', "", - 'wfs_describeFeatureType_1_1_0_typename_empty', project_file=project_file) - - self.wfs_request_compare("DescribeFeatureType", '1.0.0', "TYPENAME=does_not_exist&", - 'wfs_describeFeatureType_1_0_0_typename_wrong', project_file=project_file) - self.wfs_request_compare("DescribeFeatureType", '1.1.0', "TYPENAME=does_not_exist&", - 'wfs_describeFeatureType_1_1_0_typename_wrong', project_file=project_file) + self.wfs_request_compare( + "DescribeFeatureType", + "1.0.0", + "TYPENAME=as_areas&", + "wfs_describeFeatureType_1_0_0_typename_as_areas", + project_file=project_file, + ) + self.wfs_request_compare( + "DescribeFeatureType", + "1.0.0", + "TYPENAME=as_areas&OUTPUTFORMAT=XMLSCHEMA&", + "wfs_describeFeatureType_1_0_0_typename_as_areas", + project_file=project_file, + ) + + self.wfs_request_compare( + "DescribeFeatureType", + "1.1.0", + "TYPENAME=as_areas&", + "wfs_describeFeatureType_1_1_0_typename_as_areas", + project_file=project_file, + ) + self.wfs_request_compare( + "DescribeFeatureType", + "1.1.0", + "TYPENAME=as_areas&OUTPUTFORMAT=XMLSCHEMA&", + "wfs_describeFeatureType_1_1_0_typename_as_areas", + project_file=project_file, + ) + self.wfs_request_compare( + "DescribeFeatureType", + "1.1.0", + "TYPENAME=as_areas&OUTPUTFORMAT=text/xml; subtype=gml/3.1.1&", + "wfs_describeFeatureType_1_1_0_typename_as_areas", + project_file=project_file, + ) + + self.wfs_request_compare( + "DescribeFeatureType", + "1.0.0", + "", + "wfs_describeFeatureType_1_0_0_typename_empty", + project_file=project_file, + ) + self.wfs_request_compare( + "DescribeFeatureType", + "1.1.0", + "", + "wfs_describeFeatureType_1_1_0_typename_empty", + project_file=project_file, + ) + + self.wfs_request_compare( + "DescribeFeatureType", + "1.0.0", + "TYPENAME=does_not_exist&", + "wfs_describeFeatureType_1_0_0_typename_wrong", + project_file=project_file, + ) + self.wfs_request_compare( + "DescribeFeatureType", + "1.1.0", + "TYPENAME=does_not_exist&", + "wfs_describeFeatureType_1_1_0_typename_wrong", + project_file=project_file, + ) def test_describeFeatureTypeGeoJson(self): - """Test DescribeFeatureType with GeoJSON format with TYPENAME filters - """ + """Test DescribeFeatureType with GeoJSON format with TYPENAME filters""" project_file = "test_project_wms_grouped_layers.qgs" - self.wfs_request_compare("DescribeFeatureType", '1.1.0', "TYPENAME=as_areas&OUTPUTFORMAT=GEOJSON", - 'wfs_describeFeatureType_1_1_0_typename_as_areas_geojson', project_file=project_file) + self.wfs_request_compare( + "DescribeFeatureType", + "1.1.0", + "TYPENAME=as_areas&OUTPUTFORMAT=GEOJSON", + "wfs_describeFeatureType_1_1_0_typename_as_areas_geojson", + project_file=project_file, + ) def test_GetFeature_with_cdata(self): - """ Test GetFeature with CDATA.""" + """Test GetFeature with CDATA.""" self.wfs_request_compare( "GetFeature", "1.0.0", "TYPENAME=test_layer_wfs_cdata_lines&", - 'wfs_getfeature_cdata', - project_file="test_layer_wfs_cdata.qgs") + "wfs_getfeature_cdata", + project_file="test_layer_wfs_cdata.qgs", + ) def test_describeFeatureTypeVirtualFields(self): """Test DescribeFeatureType with virtual fields: bug GH-29767""" project_file = "bug_gh29767_double_vfield.qgs" - self.wfs_request_compare("DescribeFeatureType", '1.1.0', "", - 'wfs_describeFeatureType_1_1_0_virtual_fields', project_file=project_file) + self.wfs_request_compare( + "DescribeFeatureType", + "1.1.0", + "", + "wfs_describeFeatureType_1_1_0_virtual_fields", + project_file=project_file, + ) def test_getFeatureFeature_0_nulls(self): """Test that 0 and null in integer columns are reported correctly""" @@ -700,176 +971,262 @@ def test_getFeatureFeature_0_nulls(self): """ - def _round_trip(value, field, version='1.1.0'): + def _round_trip(value, field, version="1.1.0"): """Set a value on fid 22 and field and check it back""" - encoded_data = post_data.format(field=field, value=value, version=version).encode('utf8') + encoded_data = post_data.format( + field=field, value=value, version=version + ).encode("utf8") # Strip the field if NULL if value is None: - encoded_data = encoded_data.replace(b'None', b'') + encoded_data = encoded_data.replace(b"None", b"") - header, body = self._execute_request("?MAP={}&SERVICE=WFS&VERSION={}".format( - self.testdata_path + 'test_project_wms_grouped_layers.qgs', version), QgsServerRequest.PostMethod, encoded_data) - if version == '1.0.0': - self.assertIn(b'', body) + header, body = self._execute_request( + "?MAP={}&SERVICE=WFS&VERSION={}".format( + self.testdata_path + "test_project_wms_grouped_layers.qgs", version + ), + QgsServerRequest.PostMethod, + encoded_data, + ) + if version == "1.0.0": + self.assertIn(b"", body) else: - self.assertIn(b'1', body) - header, body = self._execute_request("?MAP=%s&SERVICE=WFS&REQUEST=GetFeature&TYPENAME=cdb_lines&FEATUREID=cdb_lines.22" % ( - self.testdata_path + 'test_project_wms_grouped_layers.qgs')) + self.assertIn(b"1", body) + header, body = self._execute_request( + "?MAP=%s&SERVICE=WFS&REQUEST=GetFeature&TYPENAME=cdb_lines&FEATUREID=cdb_lines.22" + % (self.testdata_path + "test_project_wms_grouped_layers.qgs") + ) if value is not None: - xml_value = '{1}'.format(field, value).encode('utf8') + xml_value = "{1}".format(field, value).encode("utf8") self.assertTrue(xml_value in body, f"{xml_value} not found in body") else: - xml_value = f''.encode() + xml_value = f"".encode() self.assertNotIn(xml_value, body) # Check the backend vl = QgsVectorLayer( - self.testdata_path + 'test_project_wms_grouped_layers.gpkg|layername=cdb_lines', 'vl', 'ogr') + self.testdata_path + + "test_project_wms_grouped_layers.gpkg|layername=cdb_lines", + "vl", + "ogr", + ) self.assertTrue(vl.isValid()) self.assertEqual( - str(vl.getFeature(22)[field]), value if value is not None else 'NULL') + str(vl.getFeature(22)[field]), value if value is not None else "NULL" + ) - for version in ('1.0.0', '1.1.0'): - _round_trip('0', 'id_long', version) - _round_trip('12345', 'id_long', version) - _round_trip('0', 'id', version) - _round_trip('12345', 'id', version) - _round_trip(None, 'id', version) - _round_trip(None, 'id_long', version) + for version in ("1.0.0", "1.1.0"): + _round_trip("0", "id_long", version) + _round_trip("12345", "id_long", version) + _round_trip("0", "id", version) + _round_trip("12345", "id", version) + _round_trip(None, "id", version) + _round_trip(None, "id_long", version) # "name" is NOT NULL: try to set it to empty string - _round_trip('', 'name', version) + _round_trip("", "name", version) # Then NULL - data = post_data.format(field='name', value='', version=version).encode('utf8') - encoded_data = data.replace(b'', b'') - header, body = self._execute_request("?MAP=%s&SERVICE=WFS" % ( - self.testdata_path + 'test_project_wms_grouped_layers.qgs'), QgsServerRequest.PostMethod, encoded_data) - if version == '1.0.0': - self.assertIn(b'', body) + data = post_data.format(field="name", value="", version=version).encode( + "utf8" + ) + encoded_data = data.replace(b"", b"") + header, body = self._execute_request( + "?MAP=%s&SERVICE=WFS" + % (self.testdata_path + "test_project_wms_grouped_layers.qgs"), + QgsServerRequest.PostMethod, + encoded_data, + ) + if version == "1.0.0": + self.assertIn(b"", body) else: - self.assertTrue(b'0' in body) - self.assertIn(b'NOT NULL constraint error on layer \'cdb_lines\', field \'name\'', body) + self.assertTrue(b"0" in body) + self.assertIn( + b"NOT NULL constraint error on layer 'cdb_lines', field 'name'", + body, + ) def test_describeFeatureTypeGeometryless(self): """Test DescribeFeatureType with geometryless tables - bug GH-30381""" project_file = "test_project_geometryless_gh30381.qgs" - self.wfs_request_compare("DescribeFeatureType", '1.1.0', - reference_base_name='wfs_describeFeatureType_1_1_0_geometryless', - project_file=project_file) + self.wfs_request_compare( + "DescribeFeatureType", + "1.1.0", + reference_base_name="wfs_describeFeatureType_1_1_0_geometryless", + project_file=project_file, + ) def test_getFeatureFeatureIdJson(self): """Test GetFeature with featureid JSON format and various content types""" - for ct in ('GeoJSON', 'application/vnd.geo+json', 'application/json', 'application/geo+json'): + for ct in ( + "GeoJSON", + "application/vnd.geo+json", + "application/json", + "application/geo+json", + ): self.wfs_request_compare( "GetFeature", - '1.0.0', + "1.0.0", f"OUTPUTFORMAT={ct}" + "&SRSNAME=EPSG:4326&TYPENAME=testlayer&FEATUREID=testlayer.0", - 'wfs_getFeature_1_0_0_featureid_0_json') + "wfs_getFeature_1_0_0_featureid_0_json", + ) def test_getFeatureFeatureJsonCrs(self): """Test issue GH #25171, geojson srsName""" project = QgsProject() - layer = QgsVectorLayer("Point?crs=epsg:3857&field=fldint:integer", - "layer", "memory") + layer = QgsVectorLayer( + "Point?crs=epsg:3857&field=fldint:integer", "layer", "memory" + ) project.addMapLayers([layer]) project.writeEntry("WFSLayers", "/", [layer.id()]) f = QgsFeature(layer.fields()) - f.setGeometry(QgsGeometry.fromWkt('point(807305 5592878)')) + f.setGeometry(QgsGeometry.fromWkt("point(807305 5592878)")) f.setAttributes([123]) layer.dataProvider().addFeatures([f]) f = QgsFeature(layer.fields()) - f.setGeometry(QgsGeometry.fromWkt('point(812191 5589555)')) + f.setGeometry(QgsGeometry.fromWkt("point(812191 5589555)")) f.setAttributes([123]) layer.dataProvider().addFeatures([f]) - query_string = "?" + "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WFS", - "REQUEST": "GetFeature", - "VERSION": "1.1.0", - "TYPENAME": "layer", - "SRSNAME": "EPSG:3857", - "outputFormat": "GeoJSON" - }.items())]) + query_string = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WFS", + "REQUEST": "GetFeature", + "VERSION": "1.1.0", + "TYPENAME": "layer", + "SRSNAME": "EPSG:3857", + "outputFormat": "GeoJSON", + }.items() + ) + ] + ) header, body = self._execute_request_project(query_string, project) json.loads(body) jdata = json.loads(body) - jdata['features'][0]['geometry'] - jdata['features'][0]['geometry']['coordinates'] - self.assertEqual(jdata['features'][0]['geometry']['coordinates'], [807305, 5592878]) - self.assertEqual(jdata['crs']['properties']['name'], "urn:ogc:def:crs:EPSG::3857") - - query_string = "?" + "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WFS", - "REQUEST": "GetFeature", - "VERSION": "1.1.0", - "TYPENAME": "layer", - "SRSNAME": "EPSG:4326", - "outputFormat": "GeoJSON" - }.items())]) + jdata["features"][0]["geometry"] + jdata["features"][0]["geometry"]["coordinates"] + self.assertEqual( + jdata["features"][0]["geometry"]["coordinates"], [807305, 5592878] + ) + self.assertEqual( + jdata["crs"]["properties"]["name"], "urn:ogc:def:crs:EPSG::3857" + ) + + query_string = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WFS", + "REQUEST": "GetFeature", + "VERSION": "1.1.0", + "TYPENAME": "layer", + "SRSNAME": "EPSG:4326", + "outputFormat": "GeoJSON", + }.items() + ) + ] + ) header, body = self._execute_request_project(query_string, project) json.loads(body) jdata = json.loads(body) - jdata['features'][0]['geometry'] - jdata['features'][0]['geometry']['coordinates'] - self.assertEqual([int(i) for i in jdata['features'][0]['geometry']['coordinates']], [7, 44]) - self.assertFalse('crs' in jdata) - - query_string = "?" + "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WFS", - "REQUEST": "GetFeature", - "VERSION": "1.1.0", - "TYPENAME": "layer", - "outputFormat": "GeoJSON" - }.items())]) + jdata["features"][0]["geometry"] + jdata["features"][0]["geometry"]["coordinates"] + self.assertEqual( + [int(i) for i in jdata["features"][0]["geometry"]["coordinates"]], [7, 44] + ) + self.assertFalse("crs" in jdata) + + query_string = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WFS", + "REQUEST": "GetFeature", + "VERSION": "1.1.0", + "TYPENAME": "layer", + "outputFormat": "GeoJSON", + }.items() + ) + ] + ) header, body = self._execute_request_project(query_string, project) json.loads(body) jdata = json.loads(body) - jdata['features'][0]['geometry'] - jdata['features'][0]['geometry']['coordinates'] - self.assertEqual([int(i) for i in jdata['features'][0]['geometry']['coordinates']], [7, 44]) - - query_string = "?" + "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WFS", - "REQUEST": "GetFeature", - "VERSION": "1.1.0", - "TYPENAME": "layer", - "SRSNAME": "EPSG:32632", - "outputFormat": "GeoJSON" - }.items())]) + jdata["features"][0]["geometry"] + jdata["features"][0]["geometry"]["coordinates"] + self.assertEqual( + [int(i) for i in jdata["features"][0]["geometry"]["coordinates"]], [7, 44] + ) + + query_string = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WFS", + "REQUEST": "GetFeature", + "VERSION": "1.1.0", + "TYPENAME": "layer", + "SRSNAME": "EPSG:32632", + "outputFormat": "GeoJSON", + }.items() + ) + ] + ) header, body = self._execute_request_project(query_string, project) json.loads(body) jdata = json.loads(body) - jdata['features'][0]['geometry'] - jdata['features'][0]['geometry']['coordinates'] - self.assertEqual([int(i) for i in jdata['features'][0]['geometry']['coordinates']], [361806, 4964192]) - self.assertEqual(jdata['crs']['properties']['name'], "urn:ogc:def:crs:EPSG::32632") - - query_string = "?" + "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WFS", - "REQUEST": "GetFeature", - "VERSION": "1.1.0", - "TYPENAME": "layer", - "SRSNAME": "EPSG:3857", - "outputFormat": "GeoJSON", - "FEATUREID": "layer.2" - }.items())]) + jdata["features"][0]["geometry"] + jdata["features"][0]["geometry"]["coordinates"] + self.assertEqual( + [int(i) for i in jdata["features"][0]["geometry"]["coordinates"]], + [361806, 4964192], + ) + self.assertEqual( + jdata["crs"]["properties"]["name"], "urn:ogc:def:crs:EPSG::32632" + ) + + query_string = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WFS", + "REQUEST": "GetFeature", + "VERSION": "1.1.0", + "TYPENAME": "layer", + "SRSNAME": "EPSG:3857", + "outputFormat": "GeoJSON", + "FEATUREID": "layer.2", + }.items() + ) + ] + ) header, body = self._execute_request_project(query_string, project) json.loads(body) jdata = json.loads(body) - jdata['features'][0]['geometry'] - jdata['features'][0]['geometry']['coordinates'] - self.assertEqual([int(i) for i in jdata['features'][0]['geometry']['coordinates']], [812191, 5589555]) - self.assertEqual(jdata['crs']['properties']['name'], "urn:ogc:def:crs:EPSG::3857") + jdata["features"][0]["geometry"] + jdata["features"][0]["geometry"]["coordinates"] + self.assertEqual( + [int(i) for i in jdata["features"][0]["geometry"]["coordinates"]], + [812191, 5589555], + ) + self.assertEqual( + jdata["crs"]["properties"]["name"], "urn:ogc:def:crs:EPSG::3857" + ) def test_insert_srsName(self): """Test srsName is respected when insering""" @@ -889,50 +1246,67 @@ def test_insert_srsName(self):
    """ - project = self.testdata_path + \ - "test_project_wms_grouped_layers.qgs" + project = self.testdata_path + "test_project_wms_grouped_layers.qgs" assert os.path.exists(project), "Project file not found: " + project - query_string = f'?SERVICE=WFS&MAP={urllib.parse.quote(project)}' + query_string = f"?SERVICE=WFS&MAP={urllib.parse.quote(project)}" request = post_data.format( - name='4326-test1', - version='1.1.0', - srsName='EPSG:4326', - coordinates='10.67,52.48' + name="4326-test1", + version="1.1.0", + srsName="EPSG:4326", + coordinates="10.67,52.48", ) header, body = self._execute_request( - query_string, requestMethod=QgsServerRequest.PostMethod, data=request.encode('utf-8')) + query_string, + requestMethod=QgsServerRequest.PostMethod, + data=request.encode("utf-8"), + ) # Verify - vl = QgsVectorLayer(self.testdata_path + 'test_project_wms_grouped_layers.gpkg|layername=as_symbols', 'as_symbols') + vl = QgsVectorLayer( + self.testdata_path + + "test_project_wms_grouped_layers.gpkg|layername=as_symbols", + "as_symbols", + ) self.assertTrue(vl.isValid()) - feature = next(vl.getFeatures(QgsFeatureRequest(QgsExpression('"name" = \'4326-test1\'')))) + feature = next( + vl.getFeatures(QgsFeatureRequest(QgsExpression("\"name\" = '4326-test1'"))) + ) geom = feature.geometry() - tr = QgsCoordinateTransform(QgsCoordinateReferenceSystem.fromEpsgId(4326), vl.crs(), QgsCoordinateTransformContext()) + tr = QgsCoordinateTransform( + QgsCoordinateReferenceSystem.fromEpsgId(4326), + vl.crs(), + QgsCoordinateTransformContext(), + ) - geom_4326 = QgsGeometry.fromWkt('point( 10.67 52.48)') + geom_4326 = QgsGeometry.fromWkt("point( 10.67 52.48)") geom_4326.transform(tr) self.assertEqual(geom.asWkt(0), geom_4326.asWkt(0)) # Now: insert a feature in layer's CRS request = post_data.format( - name='25832-test1', - version='1.1.0', - srsName='EPSG:25832', - coordinates='613412,5815738' + name="25832-test1", + version="1.1.0", + srsName="EPSG:25832", + coordinates="613412,5815738", ) header, body = self._execute_request( - query_string, requestMethod=QgsServerRequest.PostMethod, data=request.encode('utf-8')) + query_string, + requestMethod=QgsServerRequest.PostMethod, + data=request.encode("utf-8"), + ) - feature = next(vl.getFeatures(QgsFeatureRequest(QgsExpression('"name" = \'25832-test1\'')))) + feature = next( + vl.getFeatures(QgsFeatureRequest(QgsExpression("\"name\" = '25832-test1'"))) + ) geom = feature.geometry() self.assertEqual(geom.asWkt(0), geom_4326.asWkt(0)) # Tests for inverted axis issue GH #36584 # Cleanup self.assertTrue(vl.startEditing()) - vl.selectByExpression('"name" LIKE \'4326-test%\'') + vl.selectByExpression("\"name\" LIKE '4326-test%'") vl.deleteSelectedFeatures() self.assertTrue(vl.commitChanges()) @@ -940,47 +1314,73 @@ def test_insert_srsName(self): def _test(version, srsName, lat_lon=False): self.i += 1 - name = f'4326-test_{self.i}' + name = f"4326-test_{self.i}" request = post_data.format( name=name, version=version, srsName=srsName, - coordinates='52.48,10.67' if lat_lon else '10.67,52.48' + coordinates="52.48,10.67" if lat_lon else "10.67,52.48", ) header, body = self._execute_request( - query_string, requestMethod=QgsServerRequest.PostMethod, data=request.encode('utf-8')) - feature = next(vl.getFeatures(QgsFeatureRequest(QgsExpression(f'"name" = \'{name}\'')))) + query_string, + requestMethod=QgsServerRequest.PostMethod, + data=request.encode("utf-8"), + ) + feature = next( + vl.getFeatures(QgsFeatureRequest(QgsExpression(f"\"name\" = '{name}'"))) + ) geom = feature.geometry() - self.assertEqual(geom.asWkt(0), geom_4326.asWkt(0), f"Transaction Failed: {version} , {srsName}, lat_lon={lat_lon}") + self.assertEqual( + geom.asWkt(0), + geom_4326.asWkt(0), + f"Transaction Failed: {version} , {srsName}, lat_lon={lat_lon}", + ) - _test('1.1.0', 'urn:ogc:def:crs:EPSG::4326', lat_lon=True) - _test('1.1.0', 'http://www.opengis.net/def/crs/EPSG/0/4326', lat_lon=True) - _test('1.1.0', 'http://www.opengis.net/gml/srs/epsg.xml#4326', lat_lon=False) - _test('1.1.0', 'EPSG:4326', lat_lon=False) + _test("1.1.0", "urn:ogc:def:crs:EPSG::4326", lat_lon=True) + _test("1.1.0", "http://www.opengis.net/def/crs/EPSG/0/4326", lat_lon=True) + _test("1.1.0", "http://www.opengis.net/gml/srs/epsg.xml#4326", lat_lon=False) + _test("1.1.0", "EPSG:4326", lat_lon=False) - _test('1.0.0', 'urn:ogc:def:crs:EPSG::4326', lat_lon=True) - _test('1.0.0', 'http://www.opengis.net/def/crs/EPSG/0/4326', lat_lon=True) - _test('1.0.0', 'http://www.opengis.net/gml/srs/epsg.xml#4326', lat_lon=False) - _test('1.0.0', 'EPSG:4326', lat_lon=False) + _test("1.0.0", "urn:ogc:def:crs:EPSG::4326", lat_lon=True) + _test("1.0.0", "http://www.opengis.net/def/crs/EPSG/0/4326", lat_lon=True) + _test("1.0.0", "http://www.opengis.net/gml/srs/epsg.xml#4326", lat_lon=False) + _test("1.0.0", "EPSG:4326", lat_lon=False) def _test_getFeature(version, srsName, lat_lon=False): # Now get the feature through WFS using BBOX filter - bbox = QgsGeometry.fromWkt('point( 10.7006 52.4317)').boundingBox() + bbox = QgsGeometry.fromWkt("point( 10.7006 52.4317)").boundingBox() bbox.grow(0.0001) - bbox_text = "%s,%s,%s,%s" % ((bbox.yMinimum(), bbox.xMinimum(), bbox.yMaximum(), bbox.xMaximum()) if lat_lon else (bbox.xMinimum(), bbox.yMinimum(), bbox.xMaximum(), bbox.yMaximum())) - req = query_string + '&REQUEST=GetFeature&VERSION={version}&TYPENAME=as_symbols&SRSNAME={srsName}&BBOX={bbox},{srsName}'.format(version=version, srsName=srsName, bbox=bbox_text) + bbox_text = "%s,%s,%s,%s" % ( + (bbox.yMinimum(), bbox.xMinimum(), bbox.yMaximum(), bbox.xMaximum()) + if lat_lon + else ( + bbox.xMinimum(), + bbox.yMinimum(), + bbox.xMaximum(), + bbox.yMaximum(), + ) + ) + req = ( + query_string + + "&REQUEST=GetFeature&VERSION={version}&TYPENAME=as_symbols&SRSNAME={srsName}&BBOX={bbox},{srsName}".format( + version=version, srsName=srsName, bbox=bbox_text + ) + ) header, body = self._execute_request(req) - self.assertTrue(b'gid>7' in body, f"GetFeature Failed: {version} , {srsName}, lat_lon={lat_lon}") + self.assertTrue( + b"gid>7" in body, + f"GetFeature Failed: {version} , {srsName}, lat_lon={lat_lon}", + ) - _test_getFeature('1.1.0', 'urn:ogc:def:crs:EPSG::4326', lat_lon=True) - _test_getFeature('1.1.0', 'EPSG:4326', lat_lon=False) + _test_getFeature("1.1.0", "urn:ogc:def:crs:EPSG::4326", lat_lon=True) + _test_getFeature("1.1.0", "EPSG:4326", lat_lon=False) - _test_getFeature('1.0.0', 'urn:ogc:def:crs:EPSG::4326', lat_lon=True) - _test_getFeature('1.0.0', 'EPSG:4326', lat_lon=False) + _test_getFeature("1.0.0", "urn:ogc:def:crs:EPSG::4326", lat_lon=True) + _test_getFeature("1.0.0", "EPSG:4326", lat_lon=False) # Cleanup self.assertTrue(vl.startEditing()) - vl.selectByExpression('"name" LIKE \'4326-test%\'') + vl.selectByExpression("\"name\" LIKE '4326-test%'") vl.deleteSelectedFeatures() self.assertTrue(vl.commitChanges()) @@ -988,97 +1388,148 @@ def test_getFeatureFeatureEnvelopeCrs(self): """Test issue GH #48642""" project = QgsProject() - layer = QgsVectorLayer("Point?crs=epsg:3857&field=fldint:integer", - "layer", "memory") + layer = QgsVectorLayer( + "Point?crs=epsg:3857&field=fldint:integer", "layer", "memory" + ) project.addMapLayers([layer]) project.writeEntry("WFSLayers", "/", [layer.id()]) f = QgsFeature(layer.fields()) - f.setGeometry(QgsGeometry.fromWkt('point(807305 5592878)')) + f.setGeometry(QgsGeometry.fromWkt("point(807305 5592878)")) f.setAttributes([123]) layer.dataProvider().addFeatures([f]) f = QgsFeature(layer.fields()) - f.setGeometry(QgsGeometry.fromWkt('point(812191 5589555)')) + f.setGeometry(QgsGeometry.fromWkt("point(812191 5589555)")) f.setAttributes([123]) layer.dataProvider().addFeatures([f]) - query_string = "?" + "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WFS", - "REQUEST": "GetFeature", - "VERSION": "1.1.0", - "TYPENAME": "layer", - "SRSNAME": "EPSG:4326" - }.items())]) + query_string = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WFS", + "REQUEST": "GetFeature", + "VERSION": "1.1.0", + "TYPENAME": "layer", + "SRSNAME": "EPSG:4326", + }.items() + ) + ] + ) header, body = self._execute_request_project(query_string, project) root = et.fromstring(body) - e = root.findall('.//gml:Envelope', root.nsmap)[0] - self.assertEqual(e.attrib, {'srsName': 'EPSG:4326'}) + e = root.findall(".//gml:Envelope", root.nsmap)[0] + self.assertEqual(e.attrib, {"srsName": "EPSG:4326"}) - self.assertEqual([c[:4] for c in e.findall('.//')[0].text.split(' ')], ['7.25', '44.7']) - self.assertEqual([c[:4] for c in e.findall('.//')[1].text.split(' ')], ['7.29', '44.8']) + self.assertEqual( + [c[:4] for c in e.findall(".//")[0].text.split(" ")], ["7.25", "44.7"] + ) + self.assertEqual( + [c[:4] for c in e.findall(".//")[1].text.split(" ")], ["7.29", "44.8"] + ) - query_string = "?" + "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WFS", - "REQUEST": "GetFeature", - "VERSION": "1.1.0", - "TYPENAME": "layer", - "SRSNAME": "EPSG:4326", - "BBOX": "7.2,44.5,8.2,45.1,EPSG:4326" - }.items())]) + query_string = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WFS", + "REQUEST": "GetFeature", + "VERSION": "1.1.0", + "TYPENAME": "layer", + "SRSNAME": "EPSG:4326", + "BBOX": "7.2,44.5,8.2,45.1,EPSG:4326", + }.items() + ) + ] + ) header, body = self._execute_request_project(query_string, project) root = et.fromstring(body) - e = root.findall('.//gml:Envelope', root.nsmap)[0] - self.assertEqual(e.attrib, {'srsName': 'EPSG:4326'}) - self.assertEqual([c[:4] for c in e.findall('.//')[0].text.split(' ')], ['7.2', '44.5']) - self.assertEqual([c[:4] for c in e.findall('.//')[1].text.split(' ')], ['8.2', '45.1']) - - query_string = "?" + "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WFS", - "REQUEST": "GetFeature", - "VERSION": "1.1.0", - "TYPENAME": "layer", - "SRSNAME": "EPSG:4326", - "BBOX": "807305,5589555,812191,5592878,EPSG:3857" - }.items())]) + e = root.findall(".//gml:Envelope", root.nsmap)[0] + self.assertEqual(e.attrib, {"srsName": "EPSG:4326"}) + self.assertEqual( + [c[:4] for c in e.findall(".//")[0].text.split(" ")], ["7.2", "44.5"] + ) + self.assertEqual( + [c[:4] for c in e.findall(".//")[1].text.split(" ")], ["8.2", "45.1"] + ) + + query_string = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WFS", + "REQUEST": "GetFeature", + "VERSION": "1.1.0", + "TYPENAME": "layer", + "SRSNAME": "EPSG:4326", + "BBOX": "807305,5589555,812191,5592878,EPSG:3857", + }.items() + ) + ] + ) header, body = self._execute_request_project(query_string, project) root = et.fromstring(body) - e = root.findall('.//gml:Envelope', root.nsmap)[0] - self.assertEqual(e.attrib, {'srsName': 'EPSG:4326'}) - self.assertEqual([c[:4] for c in e.findall('.//')[0].text.split(' ')], ['7.25', '44.7']) - self.assertEqual([c[:4] for c in e.findall('.//')[1].text.split(' ')], ['7.29', '44.8']) + e = root.findall(".//gml:Envelope", root.nsmap)[0] + self.assertEqual(e.attrib, {"srsName": "EPSG:4326"}) + self.assertEqual( + [c[:4] for c in e.findall(".//")[0].text.split(" ")], ["7.25", "44.7"] + ) + self.assertEqual( + [c[:4] for c in e.findall(".//")[1].text.split(" ")], ["7.29", "44.8"] + ) def test_describeFeatureTypeDateTime(self): """Test DescribeFeatureType with dateTime fields""" project_file = "../qgis_server_accesscontrol/project_with_dimensions.qgs" - self.wfs_request_compare("DescribeFeatureType", '1.0.0', "TYPENAME=Datetime_dim&", - 'wfs_describeFeatureType_1_0_0_typename_datetime_dim', project_file=project_file) - self.wfs_request_compare("DescribeFeatureType", '1.1.0', "TYPENAME=Datetime_dim&", - 'wfs_describeFeatureType_1_1_0_typename_datetime_dim', project_file=project_file) + self.wfs_request_compare( + "DescribeFeatureType", + "1.0.0", + "TYPENAME=Datetime_dim&", + "wfs_describeFeatureType_1_0_0_typename_datetime_dim", + project_file=project_file, + ) + self.wfs_request_compare( + "DescribeFeatureType", + "1.1.0", + "TYPENAME=Datetime_dim&", + "wfs_describeFeatureType_1_1_0_typename_datetime_dim", + project_file=project_file, + ) - self.wfs_request_compare("DescribeFeatureType", '1.1.0', "TYPENAME=datetime_str&", - 'wfs_describeFeatureType_1_1_0_typename_datetime_str', project_file=project_file) + self.wfs_request_compare( + "DescribeFeatureType", + "1.1.0", + "TYPENAME=datetime_str&", + "wfs_describeFeatureType_1_1_0_typename_datetime_str", + project_file=project_file, + ) def test_GetFeature_with_datetime(self): - """ Test GetFeature with date-time data""" + """Test GetFeature with date-time data""" project_file = "../qgis_server_accesscontrol/project_with_dimensions.qgs" self.wfs_request_compare( "GetFeature", "1.0.0", "TYPENAME=datetime_str&", - 'wfs_getfeature_datetime_str', - project_file=project_file) + "wfs_getfeature_datetime_str", + project_file=project_file, + ) self.wfs_request_compare( "GetFeature", "1.0.0", "TYPENAME=Datetime_dim&", - 'wfs_getfeature_datetime', - project_file=project_file) + "wfs_getfeature_datetime", + project_file=project_file, + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_wfst.py b/tests/src/python/test_qgsserver_wfst.py index 24a99491acbf..980cc5b0cf26 100644 --- a/tests/src/python/test_qgsserver_wfst.py +++ b/tests/src/python/test_qgsserver_wfst.py @@ -26,9 +26,9 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '05/15/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "05/15/2016" +__copyright__ = "Copyright 2016, The QGIS Project" import os import re @@ -52,14 +52,14 @@ from utilities import unitTestDataPath, waitServer # 0 = auto -QGIS_SERVER_PORT = os.environ.get('QGIS_SERVER_PORT', '0') +QGIS_SERVER_PORT = os.environ.get("QGIS_SERVER_PORT", "0") qgis_app = start_app() class TestWFST(QgisTestCase): - VERSION = '1.0.0' + VERSION = "1.0.0" @classmethod def setUpClass(cls): @@ -69,33 +69,39 @@ def setUpClass(cls): cls.port = QGIS_SERVER_PORT # Create tmp folder cls.temp_path = tempfile.mkdtemp() - cls.testdata_path = cls.temp_path + '/' + 'wfs_transactional' + '/' - copytree(unitTestDataPath('wfs_transactional') + '/', - cls.temp_path + '/' + 'wfs_transactional') - cls.project_path = cls.temp_path + '/' + 'wfs_transactional' + '/' + \ - 'wfs_transactional.qgs' - assert os.path.exists(cls.project_path), "Project not found: %s" % \ - cls.project_path + cls.testdata_path = cls.temp_path + "/" + "wfs_transactional" + "/" + copytree( + unitTestDataPath("wfs_transactional") + "/", + cls.temp_path + "/" + "wfs_transactional", + ) + cls.project_path = ( + cls.temp_path + "/" + "wfs_transactional" + "/" + "wfs_transactional.qgs" + ) + assert os.path.exists(cls.project_path), ( + "Project not found: %s" % cls.project_path + ) # Clean env just to be sure - env_vars = ['QUERY_STRING', 'QGIS_PROJECT_FILE'] + env_vars = ["QUERY_STRING", "QGIS_PROJECT_FILE"] for ev in env_vars: try: del os.environ[ev] except KeyError: pass # Clear all test layers - for ln in ['test_point', 'test_polygon', 'test_linestring']: + for ln in ["test_point", "test_polygon", "test_linestring"]: cls._clearLayer(ln) - os.environ['QGIS_SERVER_PORT'] = str(cls.port) - server_path = os.path.dirname(os.path.realpath(__file__)) + \ - '/qgis_wrapped_server.py' - cls.server = subprocess.Popen([sys.executable, server_path], - env=os.environ, stdout=subprocess.PIPE) + os.environ["QGIS_SERVER_PORT"] = str(cls.port) + server_path = ( + os.path.dirname(os.path.realpath(__file__)) + "/qgis_wrapped_server.py" + ) + cls.server = subprocess.Popen( + [sys.executable, server_path], env=os.environ, stdout=subprocess.PIPE + ) line = cls.server.stdout.readline() - cls.port = int(re.findall(br':(\d+)', line)[0]) + cls.port = int(re.findall(rb":(\d+)", line)[0]) assert cls.port != 0 # Wait for the server process to start - assert waitServer(f'http://127.0.0.1:{cls.port}'), "Server is not responding!" + assert waitServer(f"http://127.0.0.1:{cls.port}"), "Server is not responding!" @classmethod def tearDownClass(cls): @@ -105,7 +111,7 @@ def tearDownClass(cls): cls.server.wait() del cls.server # Clear all test layers - for ln in ['test_point', 'test_polygon', 'test_linestring']: + for ln in ["test_point", "test_polygon", "test_linestring"]: cls._clearLayer(ln) rmtree(cls.temp_path) @@ -139,7 +145,7 @@ def _getLayer(cls, layer_name): OGR Layer factory """ - path = cls.testdata_path + layer_name + '.shp' + path = cls.testdata_path + layer_name + ".shp" layer = QgsVectorLayer(path, layer_name, "ogr") assert layer.isValid() return layer @@ -151,17 +157,17 @@ def _getWFSLayer(cls, type_name, layer_name=None): """ if layer_name is None: - layer_name = 'wfs_' + type_name + layer_name = "wfs_" + type_name parms = { - 'srsname': 'EPSG:4326', - 'typename': type_name, - 'url': f'http://127.0.0.1:{cls.port}/?map={cls.project_path}', - 'version': cls.VERSION, - 'table': '', + "srsname": "EPSG:4326", + "typename": type_name, + "url": f"http://127.0.0.1:{cls.port}/?map={cls.project_path}", + "version": cls.VERSION, + "table": "", # 'sql': '', } - uri = ' '.join([(f"{k}='{v}'") for k, v in list(parms.items())]) - wfs_layer = QgsVectorLayer(uri, layer_name, 'WFS') + uri = " ".join([(f"{k}='{v}'") for k, v in list(parms.items())]) + wfs_layer = QgsVectorLayer(uri, layer_name, "WFS") assert wfs_layer.isValid() return wfs_layer @@ -186,15 +192,17 @@ def _checkAddFeatures(self, wfs_layer, layer, features): layer = self._getLayer(layer.name()) self.assertTrue(layer.isValid()) self.assertEqual(layer.featureCount(), len(features)) - self.assertEqual( - wfs_layer.dataProvider().featureCount(), len(features)) + self.assertEqual(wfs_layer.dataProvider().featureCount(), len(features)) ogr_features = [f for f in layer.dataProvider().getFeatures()] # Verify features from the layers for f in ogr_features: - geom = next(wfs_layer.dataProvider().getFeatures(QgsFeatureRequest( - QgsExpression(f"\"id\" = {f.attribute('id')}")))).geometry() + geom = next( + wfs_layer.dataProvider().getFeatures( + QgsFeatureRequest(QgsExpression(f"\"id\" = {f.attribute('id')}")) + ) + ).geometry() self.assertEqual(geom.boundingBox(), f.geometry().boundingBox()) def _checkUpdateFeatures(self, wfs_layer, old_features, new_features): @@ -203,24 +211,31 @@ def _checkUpdateFeatures(self, wfs_layer, old_features, new_features): """ for i in range(len(old_features)): - f = self._getFeatureByAttribute( - wfs_layer, 'id', old_features[i]['id']) - self.assertTrue(wfs_layer.dataProvider().changeGeometryValues( - {f.id(): new_features[i].geometry()})) - self.assertTrue(wfs_layer.dataProvider().changeAttributeValues( - {f.id(): {0: new_features[i]['id']}})) - self.assertTrue(wfs_layer.dataProvider().changeAttributeValues( - {f.id(): {1: new_features[i]['name']}})) + f = self._getFeatureByAttribute(wfs_layer, "id", old_features[i]["id"]) + self.assertTrue( + wfs_layer.dataProvider().changeGeometryValues( + {f.id(): new_features[i].geometry()} + ) + ) + self.assertTrue( + wfs_layer.dataProvider().changeAttributeValues( + {f.id(): {0: new_features[i]["id"]}} + ) + ) + self.assertTrue( + wfs_layer.dataProvider().changeAttributeValues( + {f.id(): {1: new_features[i]["name"]}} + ) + ) def _checkMatchFeatures(self, wfs_layer, features): """ Check feature attributes and geometry match """ for f in features: - wf = self._getFeatureByAttribute(wfs_layer, 'id', f['id']) - self.assertEqual(wf.geometry().asWkt(), - f.geometry().asWkt()) - self.assertEqual(f['name'], wf['name']) + wf = self._getFeatureByAttribute(wfs_layer, "id", f["id"]) + self.assertEqual(wf.geometry().asWkt(), f.geometry().asWkt()) + self.assertEqual(f["name"], wf["name"]) def _checkDeleteFeatures(self, layer, features): """ @@ -229,7 +244,7 @@ def _checkDeleteFeatures(self, layer, features): ids = [] for f in features: - wf = self._getFeatureByAttribute(layer, 'id', f['id']) + wf = self._getFeatureByAttribute(layer, "id", f["id"]) ids.append(wf.id()) self.assertTrue(layer.dataProvider().deleteFeatures(ids)) @@ -241,8 +256,7 @@ def _testLayer(self, wfs_layer, layer, old_features, new_features): self.assertEqual(wfs_layer.featureCount(), 0) self._checkAddFeatures(wfs_layer, layer, old_features) self._checkMatchFeatures(wfs_layer, old_features) - self.assertEqual(wfs_layer.dataProvider().featureCount(), - len(old_features)) + self.assertEqual(wfs_layer.dataProvider().featureCount(), len(old_features)) self._checkUpdateFeatures(wfs_layer, old_features, new_features) self._checkMatchFeatures(wfs_layer, new_features) self._checkDeleteFeatures(wfs_layer, new_features) @@ -253,19 +267,19 @@ def testWFSPoints(self): Adds some points, then check and clear all """ - layer_name = 'test_point' + layer_name = "test_point" layer = self._getLayer(layer_name) wfs_layer = self._getWFSLayer(layer_name) feat1 = QgsFeature(wfs_layer.fields()) - feat1['id'] = 11 + feat1["id"] = 11 feat1.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(9, 45))) feat2 = QgsFeature(wfs_layer.fields()) feat2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(9.5, 45.5))) - feat2['id'] = 12 + feat2["id"] = 12 old_features = [feat1, feat2] # Change feat1 new_feat1 = QgsFeature(wfs_layer.fields()) - new_feat1['id'] = 121 + new_feat1["id"] = 121 new_feat1.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 46))) new_features = [new_feat1, feat2] self._testLayer(wfs_layer, layer, old_features, new_features) @@ -276,26 +290,26 @@ def testWFSPointsMultipleEdits(self): Modify 2 points, then checks and clear all """ - layer_name = 'test_point' + layer_name = "test_point" layer = self._getLayer(layer_name) wfs_layer = self._getWFSLayer(layer_name) feat1 = QgsFeature(wfs_layer.fields()) - feat1['id'] = 11 - feat1['name'] = 'name 11' + feat1["id"] = 11 + feat1["name"] = "name 11" feat1.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(9, 45))) feat2 = QgsFeature(wfs_layer.fields()) feat2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(9.5, 45.5))) - feat2['id'] = 12 - feat2['name'] = 'name 12' + feat2["id"] = 12 + feat2["name"] = "name 12" old_features = [feat1, feat2] # Change feat1 and feat2 new_feat1 = QgsFeature(wfs_layer.fields()) - new_feat1['id'] = 121 - new_feat1['name'] = 'name 121' + new_feat1["id"] = 121 + new_feat1["name"] = "name 121" new_feat1.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 46))) new_feat2 = QgsFeature(wfs_layer.fields()) - new_feat2['id'] = 122 - new_feat2['name'] = 'name 122' + new_feat2["id"] = 122 + new_feat2["name"] = "name 122" new_feat2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10.5, 47))) new_features = [new_feat1, new_feat2] self._testLayer(wfs_layer, layer, old_features, new_features) @@ -305,26 +319,33 @@ def testWFSPolygons(self): Adds some polygons, then check and clear all """ - layer_name = 'test_polygon' + layer_name = "test_polygon" layer = self._getLayer(layer_name) wfs_layer = self._getWFSLayer(layer_name) feat1 = QgsFeature(wfs_layer.fields()) - feat1['id'] = 11 - feat1['name'] = 'name 11' - feat1.setGeometry(QgsGeometry.fromRect( - QgsRectangle(QgsPointXY(9, 45), QgsPointXY(10, 46)))) + feat1["id"] = 11 + feat1["name"] = "name 11" + feat1.setGeometry( + QgsGeometry.fromRect(QgsRectangle(QgsPointXY(9, 45), QgsPointXY(10, 46))) + ) feat2 = QgsFeature(wfs_layer.fields()) - feat2.setGeometry(QgsGeometry.fromRect(QgsRectangle( - QgsPointXY(9.5, 45.5), QgsPointXY(10.5, 46.5)))) - feat2['id'] = 12 - feat2['name'] = 'name 12' + feat2.setGeometry( + QgsGeometry.fromRect( + QgsRectangle(QgsPointXY(9.5, 45.5), QgsPointXY(10.5, 46.5)) + ) + ) + feat2["id"] = 12 + feat2["name"] = "name 12" old_features = [feat1, feat2] # Change feat1 new_feat1 = QgsFeature(wfs_layer.fields()) - new_feat1['id'] = 121 - new_feat1['name'] = 'name 121' - new_feat1.setGeometry(QgsGeometry.fromRect( - QgsRectangle(QgsPointXY(10, 46), QgsPointXY(11.5, 47.5)))) + new_feat1["id"] = 121 + new_feat1["name"] = "name 121" + new_feat1.setGeometry( + QgsGeometry.fromRect( + QgsRectangle(QgsPointXY(10, 46), QgsPointXY(11.5, 47.5)) + ) + ) new_features = [new_feat1, feat2] self._testLayer(wfs_layer, layer, old_features, new_features) @@ -333,26 +354,29 @@ def testWFSLineStrings(self): Adds some lines, then check and clear all """ - layer_name = 'test_linestring' + layer_name = "test_linestring" layer = self._getLayer(layer_name) wfs_layer = self._getWFSLayer(layer_name) feat1 = QgsFeature(wfs_layer.fields()) - feat1['id'] = 11 - feat1['name'] = 'name 11' - feat1.setGeometry(QgsGeometry.fromPolylineXY( - [QgsPointXY(9, 45), QgsPointXY(10, 46)])) + feat1["id"] = 11 + feat1["name"] = "name 11" + feat1.setGeometry( + QgsGeometry.fromPolylineXY([QgsPointXY(9, 45), QgsPointXY(10, 46)]) + ) feat2 = QgsFeature(wfs_layer.fields()) - feat2.setGeometry(QgsGeometry.fromPolylineXY( - [QgsPointXY(9.5, 45.5), QgsPointXY(10.5, 46.5)])) - feat2['id'] = 12 - feat2['name'] = 'name 12' + feat2.setGeometry( + QgsGeometry.fromPolylineXY([QgsPointXY(9.5, 45.5), QgsPointXY(10.5, 46.5)]) + ) + feat2["id"] = 12 + feat2["name"] = "name 12" old_features = [feat1, feat2] # Change feat1 new_feat1 = QgsFeature(wfs_layer.fields()) - new_feat1['id'] = 121 - new_feat1['name'] = 'name 121' - new_feat1.setGeometry(QgsGeometry.fromPolylineXY( - [QgsPointXY(9.8, 45.8), QgsPointXY(10.8, 46.8)])) + new_feat1["id"] = 121 + new_feat1["name"] = "name 121" + new_feat1.setGeometry( + QgsGeometry.fromPolylineXY([QgsPointXY(9.8, 45.8), QgsPointXY(10.8, 46.8)]) + ) new_features = [new_feat1, feat2] self._testLayer(wfs_layer, layer, old_features, new_features) @@ -360,8 +384,8 @@ def testWFSLineStrings(self): class TestWFST11(TestWFST): """Same tests for WFS 1.1""" - VERSION = '1.1.0' + VERSION = "1.1.0" -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_wms.py b/tests/src/python/test_qgsserver_wms.py index 4c4d42f066bf..350aad722cb9 100644 --- a/tests/src/python/test_qgsserver_wms.py +++ b/tests/src/python/test_qgsserver_wms.py @@ -9,15 +9,16 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '25/05/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "25/05/2015" +__copyright__ = "Copyright 2015, The QGIS Project" import json import os # Needed on Qt 5 so that the serialization of XML is consistent among all executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" import re import urllib.error @@ -48,29 +49,42 @@ # Strip path and content length because path may vary RE_STRIP_UNCHECKABLE = b'MAP=[^"]+|SERVICE=[^"]+|Content-Length: \\d+' -RE_STRIP_EXTENTS = b'<(north|east|south|west)Bound(Lat|Long)itude>.*|' -RE_ATTRIBUTES = b'[^>\\s]+=[^>\\s]+' +RE_STRIP_EXTENTS = b"<(north|east|south|west)Bound(Lat|Long)itude>.*|" +RE_ATTRIBUTES = b"[^>\\s]+=[^>\\s]+" class TestQgsServerWMSTestBase(QgsServerTestBase): - """QGIS Server WMS Tests""" # Set to True to re-generate reference files for this class regenerate_reference = False - def wms_request(self, request, extra=None, project='test_project.qgs', version='1.3.0'): + def wms_request( + self, request, extra=None, project="test_project.qgs", version="1.3.0" + ): if not os.path.exists(project): project = os.path.join(self.testdata_path, project) assert os.path.exists(project), "Project file not found: " + project - query_string = f'https://www.qgis.org/?MAP={urllib.parse.quote(project)}&SERVICE=WMS&VERSION={version}&REQUEST={request}' + query_string = f"https://www.qgis.org/?MAP={urllib.parse.quote(project)}&SERVICE=WMS&VERSION={version}&REQUEST={request}" if extra is not None: query_string += extra header, body = self._execute_request(query_string) return (header, body, query_string) - def wms_request_compare(self, request, extra=None, reference_file=None, project='test_project.qgs', version='1.3.0', ignoreExtent=False, normalizeJson=False, raw=False): - response_header, response_body, query_string = self.wms_request(request, extra, project, version) + def wms_request_compare( + self, + request, + extra=None, + reference_file=None, + project="test_project.qgs", + version="1.3.0", + ignoreExtent=False, + normalizeJson=False, + raw=False, + ): + response_header, response_body, query_string = self.wms_request( + request, extra, project, version + ) response = response_header + response_body if not isinstance(reference_file, (list, tuple)): @@ -81,17 +95,22 @@ def wms_request_compare(self, request, extra=None, reference_file=None, project= last_exception = None found_match = False for reference_file in reference_files: - reference_path = os.path.join(self.testdata_path, (request.lower() if not reference_file else reference_file) + '.txt') + reference_path = os.path.join( + self.testdata_path, + (request.lower() if not reference_file else reference_file) + ".txt", + ) self.store_reference(reference_path, response) - f = open(reference_path, 'rb') + f = open(reference_path, "rb") expected = f.read() def _n(r): - lines = r.split(b'\n') + lines = r.split(b"\n") b = lines[2:] h = lines[:2] try: - return b'\n'.join(h) + json.dumps(json.loads(b'\n'.join(b))).encode('utf8') + return b"\n".join(h) + json.dumps(json.loads(b"\n".join(b))).encode( + "utf8" + ) except: return r @@ -99,11 +118,11 @@ def _n(r): expected = _n(expected) f.close() - response = re.sub(RE_STRIP_UNCHECKABLE, b'*****', response) - expected = re.sub(RE_STRIP_UNCHECKABLE, b'*****', expected) + response = re.sub(RE_STRIP_UNCHECKABLE, b"*****", response) + expected = re.sub(RE_STRIP_UNCHECKABLE, b"*****", expected) if ignoreExtent: - response = re.sub(RE_STRIP_EXTENTS, b'*****', response) - expected = re.sub(RE_STRIP_EXTENTS, b'*****', expected) + response = re.sub(RE_STRIP_EXTENTS, b"*****", response) + expected = re.sub(RE_STRIP_EXTENTS, b"*****", expected) msg = f"request {query_string} failed.\nQuery: {request}\nExpected file: {reference_path}\nResponse:\n{response.decode('utf-8')}" @@ -118,22 +137,33 @@ def _n(r): class TestQgsServerWMS(TestQgsServerWMSTestBase): - """QGIS Server WMS Tests""" def test_getcapabilities(self): - self.wms_request_compare('GetCapabilities', reference_file="getcapabilities-map") + self.wms_request_compare( + "GetCapabilities", reference_file="getcapabilities-map" + ) def test_getcapabilities_case_insensitive(self): - self.wms_request_compare('getcapabilities', reference_file="getcapabilities-map") - self.wms_request_compare('GETCAPABILITIES', reference_file="getcapabilities-map") + self.wms_request_compare( + "getcapabilities", reference_file="getcapabilities-map" + ) + self.wms_request_compare( + "GETCAPABILITIES", reference_file="getcapabilities-map" + ) def test_getcapabilities_advertised_url(self): server = QgsServer() request = QgsServerRequest() - projectPath = os.path.join(self.testdata_path, 'test_project.qgs') - request.setUrl(QUrl('http://localhost/qgis_mapserv.fcgi?MAP=' + projectPath + '&SERVICE=WMS&REQUEST=GetCapabilities')) - request.setOriginalUrl(QUrl('http://localhost/wms/test_project')) + projectPath = os.path.join(self.testdata_path, "test_project.qgs") + request.setUrl( + QUrl( + "http://localhost/qgis_mapserv.fcgi?MAP=" + + projectPath + + "&SERVICE=WMS&REQUEST=GetCapabilities" + ) + ) + request.setOriginalUrl(QUrl("http://localhost/wms/test_project")) response = QgsBufferServerResponse() server.handleRequest(request, response) response.flush() @@ -144,293 +174,433 @@ def test_getcapabilities_advertised_url(self): for k in rk: headers.append((f"{k}: {rh[k]}").encode()) - reference_path = os.path.join(self.testdata_path, 'wms_getcapabilities_rewriting.txt') - f = open(reference_path, 'rb') + reference_path = os.path.join( + self.testdata_path, "wms_getcapabilities_rewriting.txt" + ) + f = open(reference_path, "rb") expected = f.read() - self.assertXMLEqual(b"\n".join(headers) + b"\n\n" + bytes(response.body()), expected) + self.assertXMLEqual( + b"\n".join(headers) + b"\n\n" + bytes(response.body()), expected + ) def test_getprojectsettings(self): - self.wms_request_compare('GetProjectSettings') + self.wms_request_compare("GetProjectSettings") def test_getprojectsettings_opacity(self): - self.wms_request_compare('GetProjectSettings', None, 'getprojectsettings_opacity', 'test_opacity_project.qgs') + self.wms_request_compare( + "GetProjectSettings", + None, + "getprojectsettings_opacity", + "test_opacity_project.qgs", + ) def test_getcontext(self): - self.wms_request_compare('GetContext') + self.wms_request_compare("GetContext") def test_operation_not_supported(self): - qs = f'?MAP={urllib.parse.quote(self.projectPath)}&SERVICE=WMS&VERSION=1.3.0&REQUEST=NotAValidRequest' + qs = f"?MAP={urllib.parse.quote(self.projectPath)}&SERVICE=WMS&VERSION=1.3.0&REQUEST=NotAValidRequest" self._assert_status_code(501, qs) def test_describelayer(self): # Test DescribeLayer - self.wms_request_compare('DescribeLayer', - '&layers=testlayer%20%C3%A8%C3%A9&' + - 'SLD_VERSION=1.1.0', - 'describelayer') + self.wms_request_compare( + "DescribeLayer", + "&layers=testlayer%20%C3%A8%C3%A9&" + "SLD_VERSION=1.1.0", + "describelayer", + ) def test_getstyles(self): # Test GetStyles - self.wms_request_compare('GetStyles', - '&layers=testlayer%20%C3%A8%C3%A9&', - 'getstyles') + self.wms_request_compare( + "GetStyles", "&layers=testlayer%20%C3%A8%C3%A9&", "getstyles" + ) # Test GetStyles with labeling - self.wms_request_compare('GetStyles', - '&layers=pointlabel', - 'getstyles_pointlabel', - project=self.projectPath) + self.wms_request_compare( + "GetStyles", + "&layers=pointlabel", + "getstyles_pointlabel", + project=self.projectPath, + ) # Test GetStyle with labeling - self.wms_request_compare('GetStyle', - '&layers=pointlabel', - 'getstyles_pointlabel', - project=self.projectPath) + self.wms_request_compare( + "GetStyle", + "&layers=pointlabel", + "getstyles_pointlabel", + project=self.projectPath, + ) # Test SLD unchange after GetMap SLD_BODY - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "REQUEST": "GetStyles", - "VERSION": "1.1.1", - "SERVICE": "WMS", - "LAYERS": "db_point" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "REQUEST": "GetStyles", + "VERSION": "1.1.1", + "SERVICE": "WMS", + "LAYERS": "db_point", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) assert "StyledLayerDescriptor" in str(r), f"StyledLayerDescriptor not in {r}" assert "__sld_style" not in str(r), f"__sld_style in {r}" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "REQUEST": "GetMap", - "VERSION": "1.1.1", - "SERVICE": "WMS", - "SLD_BODY": " db_point db_point_style Single symbol gid 1 square 5e86a1 000000 0.007 ", - "BBOX": "-16817707,-4710778,5696513,14587125", - "WIDTH": "500", - "HEIGHT": "500", - "LAYERS": "db_point", - "STYLES": "", - "FORMAT": "image/png", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "REQUEST": "GetMap", + "VERSION": "1.1.1", + "SERVICE": "WMS", + "SLD_BODY": ' db_point db_point_style Single symbol gid 1 square 5e86a1 000000 0.007 ', + "BBOX": "-16817707,-4710778,5696513,14587125", + "WIDTH": "500", + "HEIGHT": "500", + "LAYERS": "db_point", + "STYLES": "", + "FORMAT": "image/png", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) self._assert_status_code(200, qs) - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "REQUEST": "GetStyles", - "VERSION": "1.1.1", - "SERVICE": "WMS", - "LAYERS": "db_point" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "REQUEST": "GetStyles", + "VERSION": "1.1.1", + "SERVICE": "WMS", + "LAYERS": "db_point", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) assert "StyledLayerDescriptor" in str(r), f"StyledLayerDescriptor not in {r}" assert "__sld_style" not in str(r), f"__sld_style in {r}" def test_wms_getschemaextension(self): - self.wms_request_compare('GetSchemaExtension', - '', - 'getschemaextension') + self.wms_request_compare("GetSchemaExtension", "", "getschemaextension") - def wms_request_compare_project(self, request, extra=None, reference_file=None, project_name="test_project.qgs"): + def wms_request_compare_project( + self, request, extra=None, reference_file=None, project_name="test_project.qgs" + ): projectPath = self.testdata_path + project_name assert os.path.exists(projectPath), "Project file not found: " + projectPath project = QgsProject() project.read(projectPath) - query_string = f'https://www.qgis.org/?SERVICE=WMS&VERSION=1.3.0&REQUEST={request}' + query_string = ( + f"https://www.qgis.org/?SERVICE=WMS&VERSION=1.3.0&REQUEST={request}" + ) if extra is not None: query_string += extra header, body = self._execute_request_project(query_string, project) response = header + body - reference_path = self.testdata_path + (request.lower() if not reference_file else reference_file) + '.txt' + reference_path = ( + self.testdata_path + + (request.lower() if not reference_file else reference_file) + + ".txt" + ) self.store_reference(reference_path, response) - f = open(reference_path, 'rb') + f = open(reference_path, "rb") expected = f.read() f.close() - response = re.sub(RE_STRIP_UNCHECKABLE, b'*****', response) - expected = re.sub(RE_STRIP_UNCHECKABLE, b'*****', expected) + response = re.sub(RE_STRIP_UNCHECKABLE, b"*****", response) + expected = re.sub(RE_STRIP_UNCHECKABLE, b"*****", expected) - self.assertXMLEqual(response, expected, msg=f"request {query_string} failed.\nQuery: {request}\nExpected file: {reference_path}\nResponse:\n{response.decode('utf-8')}") + self.assertXMLEqual( + response, + expected, + msg=f"request {query_string} failed.\nQuery: {request}\nExpected file: {reference_path}\nResponse:\n{response.decode('utf-8')}", + ) def test_wms_getcapabilities_project(self): """WMS GetCapabilities without map parameter""" - self.wms_request_compare_project('GetCapabilities') + self.wms_request_compare_project("GetCapabilities") # reference_file='getcapabilities_without_map_param' could be the right response def test_wms_getcapabilities_project_empty_layer(self): """WMS GetCapabilities with empty layer different CRS: wrong bbox - Regression GH 30264""" - self.wms_request_compare_project('GetCapabilities', reference_file='wms_getcapabilities_empty_layer', project_name='bug_gh30264_empty_layer_wrong_bbox.qgs') + self.wms_request_compare_project( + "GetCapabilities", + reference_file="wms_getcapabilities_empty_layer", + project_name="bug_gh30264_empty_layer_wrong_bbox.qgs", + ) def wms_inspire_request_compare(self, request): """WMS INSPIRE tests""" project = self.testdata_path + "test_project_inspire.qgs" assert os.path.exists(project), "Project file not found: " + project - query_string = f'?MAP={urllib.parse.quote(project)}&SERVICE=WMS&VERSION=1.3.0&REQUEST={request}' + query_string = f"?MAP={urllib.parse.quote(project)}&SERVICE=WMS&VERSION=1.3.0&REQUEST={request}" header, body = self._execute_request(query_string) response = header + body - reference_path = self.testdata_path + request.lower() + '_inspire.txt' + reference_path = self.testdata_path + request.lower() + "_inspire.txt" self.store_reference(reference_path, response) - f = open(reference_path, 'rb') + f = open(reference_path, "rb") expected = f.read() f.close() - response = re.sub(RE_STRIP_UNCHECKABLE, b'', response) - expected = re.sub(RE_STRIP_UNCHECKABLE, b'', expected) - self.assertXMLEqual(response, expected, msg=f"request {query_string} failed.\nQuery: {request}\nExpected file: {reference_path}\nResponse:\n{response.decode('utf-8')}") + response = re.sub(RE_STRIP_UNCHECKABLE, b"", response) + expected = re.sub(RE_STRIP_UNCHECKABLE, b"", expected) + self.assertXMLEqual( + response, + expected, + msg=f"request {query_string} failed.\nQuery: {request}\nExpected file: {reference_path}\nResponse:\n{response.decode('utf-8')}", + ) def test_project_wms_inspire(self): """Test some WMS request""" - for request in ('GetCapabilities',): + for request in ("GetCapabilities",): self.wms_inspire_request_compare(request) def test_wms_getcapabilities_without_title(self): # Empty title in project leads to a Layer element without Name, Title # and Abstract tags. However, it should still have a CRS and a BBOX # according to OGC specifications tests. - self.wms_request_compare('GetCapabilities', reference_file='wms_getcapabilities_without_title', project='test_project_without_title.qgs') + self.wms_request_compare( + "GetCapabilities", + reference_file="wms_getcapabilities_without_title", + project="test_project_without_title.qgs", + ) def test_wms_getcapabilities_empty_spatial_layer(self): # The project contains a spatial layer without feature and the WMS # extent is not configured in the project. - self.wms_request_compare('GetCapabilities', - reference_file='wms_getcapabilities_empty_spatial_layer', - project='test_project_empty_spatial_layer.qgz', - ignoreExtent=True) + self.wms_request_compare( + "GetCapabilities", + reference_file="wms_getcapabilities_empty_spatial_layer", + project="test_project_empty_spatial_layer.qgz", + ignoreExtent=True, + ) def test_wms_getcapabilities_versions(self): # default version 1.3.0 when empty VERSION parameter project = os.path.join(self.testdata_path, "test_project.qgs") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WMS", - "REQUEST": "GetCapabilities", - }.items())]) - - self.wms_request_compare(qs, reference_file='wms_getcapabilities_1_3_0', version='') + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WMS", + "REQUEST": "GetCapabilities", + }.items() + ) + ] + ) + + self.wms_request_compare( + qs, reference_file="wms_getcapabilities_1_3_0", version="" + ) # default version 1.3.0 when VERSION = 1.3.0 parameter project = os.path.join(self.testdata_path, "test_project.qgs") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WMS", - "REQUEST": "GetCapabilities", - }.items())]) - - self.wms_request_compare(qs, reference_file='wms_getcapabilities_1_3_0', version='1.3.0') + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WMS", + "REQUEST": "GetCapabilities", + }.items() + ) + ] + ) + + self.wms_request_compare( + qs, reference_file="wms_getcapabilities_1_3_0", version="1.3.0" + ) # version 1.1.1 project = os.path.join(self.testdata_path, "test_project.qgs") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WMS", - "REQUEST": "GetCapabilities", - }.items())]) - - self.wms_request_compare(qs, reference_file='wms_getcapabilities_1_1_1', version='1.1.1') + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WMS", + "REQUEST": "GetCapabilities", + }.items() + ) + ] + ) + + self.wms_request_compare( + qs, reference_file="wms_getcapabilities_1_1_1", version="1.1.1" + ) # default version 1.3.0 when invalid VERSION parameter project = os.path.join(self.testdata_path, "test_project.qgs") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WMS", - "REQUEST": "GetCapabilities", - }.items())]) - - self.wms_request_compare(qs, reference_file='wms_getcapabilities_1_3_0', version='33.33.33') + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WMS", + "REQUEST": "GetCapabilities", + }.items() + ) + ] + ) + + self.wms_request_compare( + qs, reference_file="wms_getcapabilities_1_3_0", version="33.33.33" + ) def test_wms_getcapabilities_url(self): # empty url in project project = os.path.join(self.testdata_path, "test_project_without_urls.qgs") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetCapabilities", - "STYLES": "" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetCapabilities", + "STYLES": "", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) item_found = False for item in str(r).split("\\n"): if "OnlineResource" in item: - self.assertEqual("xlink:href=\"?" in item, True) + self.assertEqual('xlink:href="?' in item, True) item_found = True self.assertTrue(item_found) # url passed in query string # verify that GetCapabilities isn't put into the url for non-uppercase parameter names project = os.path.join(self.testdata_path, "test_project_without_urls.qgs") - qs = "https://www.qgis-server.org?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SeRvIcE": "WMS", - "VeRsIoN": "1.3.0", - "ReQuEsT": "GetCapabilities", - "STYLES": "" - }.items())]) + qs = "https://www.qgis-server.org?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SeRvIcE": "WMS", + "VeRsIoN": "1.3.0", + "ReQuEsT": "GetCapabilities", + "STYLES": "", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) item_found = False for item in str(r).split("\\n"): if "OnlineResource" in item: - self.assertEqual("xlink:href=\"https://www.qgis-server.org?" in item, True) + self.assertEqual( + 'xlink:href="https://www.qgis-server.org?' in item, True + ) self.assertEqual("GetCapabilities" in item, False) item_found = True self.assertTrue(item_found) # url well defined in project project = os.path.join(self.testdata_path, "test_project_with_urls.qgs") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetCapabilities", - "STYLES": "" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetCapabilities", + "STYLES": "", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) item_found = False for item in str(r).split("\\n"): - if "OnlineResource" in item and "xlink:href=\"my_wms_advertised_url?" in item: + if ( + "OnlineResource" in item + and 'xlink:href="my_wms_advertised_url?' in item + ): item_found = True self.assertTrue(item_found) - @unittest.skip('Timeout issues') + @unittest.skip("Timeout issues") def test_wms_GetProjectSettings_wms_print_layers(self): projectPath = self.testdata_path + "test_project_wms_printlayers.qgs" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": projectPath, - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetProjectSettings" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": projectPath, + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetProjectSettings", + }.items() + ) + ] + ) header, body = self._execute_request(qs) - xmlResult = body.decode('utf-8') - self.assertNotEqual(xmlResult.find("1"), -1) - self.assertNotEqual(xmlResult.find("contextualWMSLegend=0&crs=EPSG:21781&dpiMode=7&featureCount=10&format=image/png&layers=public_geo_gemeinden&styles=&url=https://qgiscloud.com/mhugent/qgis_unittest_wms/wms?"), -1) - self.assertNotEqual(xmlResult.find("contextualWMSLegend=0&amp;crs=EPSG:21781&amp;dpiMode=7&amp;featureCount=10&amp;format=image/png&amp;layers=public_geo_gemeinden&amp;styles=&amp;url=https://qgiscloud.com/mhugent/qgis_unittest_wms_print/wms?"), -1) + xmlResult = body.decode("utf-8") + self.assertNotEqual( + xmlResult.find("1"), -1 + ) + self.assertNotEqual( + xmlResult.find( + "contextualWMSLegend=0&crs=EPSG:21781&dpiMode=7&featureCount=10&format=image/png&layers=public_geo_gemeinden&styles=&url=https://qgiscloud.com/mhugent/qgis_unittest_wms/wms?" + ), + -1, + ) + self.assertNotEqual( + xmlResult.find( + "contextualWMSLegend=0&amp;crs=EPSG:21781&amp;dpiMode=7&amp;featureCount=10&amp;format=image/png&amp;layers=public_geo_gemeinden&amp;styles=&amp;url=https://qgiscloud.com/mhugent/qgis_unittest_wms_print/wms?" + ), + -1, + ) def test_getcapabilities_owslib(self): # read getcapabilities document - docPath = self.testdata_path + 'getcapabilities.txt' + docPath = self.testdata_path + "getcapabilities.txt" f = open(docPath) doc = f.read() f.close() # clean header in doc - doc = doc.replace('Content-Length: 15066\n', '') - doc = doc.replace('Content-Type: text/xml; charset=utf-8\n\n', '') - doc = doc.replace('\n', '') + doc = doc.replace("Content-Length: 15066\n", "") + doc = doc.replace("Content-Type: text/xml; charset=utf-8\n\n", "") + doc = doc.replace('\n', "") # read capabilities document with owslib - w = WebMapService(None, xml=doc, version='1.3.0') + w = WebMapService(None, xml=doc, version="1.3.0") # check content - rootLayerName = 'QGIS Test Project' + rootLayerName = "QGIS Test Project" self.assertIn(rootLayerName, w.contents.keys()) def test_get_styles_sld_label_negative_offset(self): @@ -439,13 +609,18 @@ def test_get_styles_sld_label_negative_offset(self): # Create a point layer with a negative offset for the label project = QgsProject() fields = QgsFields() - fields.append(QgsField('int', QVariant.Int)) - layer = QgsMemoryProviderUtils.createMemoryLayer('pointlabel', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem(4326)) + fields.append(QgsField("int", QVariant.Int)) + layer = QgsMemoryProviderUtils.createMemoryLayer( + "pointlabel", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem(4326), + ) layer.setLabelsEnabled(True) settings = QgsPalLayerSettings() settings.xOffset = -10 settings.yOffset = -5 - settings.fieldName = 'int' + settings.fieldName = "int" settings.enabled = True settings.placement = QgsPalLayerSettings.Placement.OverPoint @@ -457,13 +632,13 @@ def test_get_styles_sld_label_negative_offset(self): # Test GetStyles with labeling server = QgsServer() request = QgsServerRequest() - request.setUrl(QUrl('?SERVICE=WMS&REQUEST=GetStyles&LAYERS=pointlabel')) + request.setUrl(QUrl("?SERVICE=WMS&REQUEST=GetStyles&LAYERS=pointlabel")) response = QgsBufferServerResponse() server.handleRequest(request, response, project) - body = response.body().data().decode('utf8').replace('\n', '') - self.assertIn('-36', body) - self.assertIn('-18', body) + body = response.body().data().decode("utf8").replace("\n", "") + self.assertIn("-36", body) + self.assertIn("-18", body) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_wms_dimension.py b/tests/src/python/test_qgsserver_wms_dimension.py index 6267742a3318..b6286f27e45e 100644 --- a/tests/src/python/test_qgsserver_wms_dimension.py +++ b/tests/src/python/test_qgsserver_wms_dimension.py @@ -8,9 +8,9 @@ (at your option) any later version. """ -__author__ = 'René-Luc Dhont' -__date__ = '29/08/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' +__author__ = "René-Luc Dhont" +__date__ = "29/08/2019" +__copyright__ = "Copyright 2019, The QGIS Project" import os import urllib.error @@ -30,325 +30,468 @@ class TestQgsServerWMSDimension(TestQgsServerWMSTestBase): def setUp(self): super().setUp() - self.testdata_path = os.path.join(self.temporary_path, "qgis_server_accesscontrol") + self.testdata_path = os.path.join( + self.temporary_path, "qgis_server_accesscontrol" + ) - self.projectPath = os.path.join(self.testdata_path, 'project_with_dimensions.qgs') - self.assertTrue(os.path.isfile(self.projectPath), f'Could not find project file "{self.projectPath}"') + self.projectPath = os.path.join( + self.testdata_path, "project_with_dimensions.qgs" + ) + self.assertTrue( + os.path.isfile(self.projectPath), + f'Could not find project file "{self.projectPath}"', + ) - def wms_request(self, request, extra=None, project='project_with_dimensions.qgs', version='1.3.0'): + def wms_request( + self, + request, + extra=None, + project="project_with_dimensions.qgs", + version="1.3.0", + ): return super().wms_request(request, extra, project, version) - def wms_request_compare(self, request, extra=None, reference_file=None, project='project_with_dimensions.qgs', version='1.3.0', ignoreExtent=False, normalizeJson=False): + def wms_request_compare( + self, + request, + extra=None, + reference_file=None, + project="project_with_dimensions.qgs", + version="1.3.0", + ignoreExtent=False, + normalizeJson=False, + ): args = dict( extra=extra, - reference_file=os.path.join('results', (request.lower() + '_wms_dimension' if not reference_file else reference_file)), + reference_file=os.path.join( + "results", + ( + request.lower() + "_wms_dimension" + if not reference_file + else reference_file + ), + ), project=project, version=version, ignoreExtent=ignoreExtent, - normalizeJson=normalizeJson + normalizeJson=normalizeJson, ) return super().wms_request_compare(request, **args) def test_wms_getcapabilities(self): - self.wms_request_compare('GetCapabilities') + self.wms_request_compare("GetCapabilities") def test_wms_getmap_default(self): # default rendering - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "dem,Slopes,Contours,Datetime_dim", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-1219081,4281848,172260,5673189", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "dem,Slopes,Contours,Datetime_dim", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-1219081,4281848,172260,5673189", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Dimension_All_NoValue") def test_wms_getmap_simple_value(self): # dimension with value - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "dem,Slopes,Contours", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-1219081,4281848,172260,5673189", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "ELEVATION": "1000" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "dem,Slopes,Contours", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-1219081,4281848,172260,5673189", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "ELEVATION": "1000", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Dimension_Elevation_Value") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "dem,Slopes,Contours", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-1219081,4281848,172260,5673189", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "DIM_RANGE_ELEVATION": "1000" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "dem,Slopes,Contours", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-1219081,4281848,172260,5673189", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "DIM_RANGE_ELEVATION": "1000", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Dimension_RangeElevation_Value") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "dem,Datetime_dim", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-1219081,4281848,172260,5673189", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "TIME": "2021-05-31T17:00:00" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "dem,Datetime_dim", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-1219081,4281848,172260,5673189", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "TIME": "2021-05-31T17:00:00", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Dimension_Time_Value") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "dem,Datetime_dim", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-1219081,4281848,172260,5673189", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "DIM_DATE": "2021-05-31" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "dem,Datetime_dim", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-1219081,4281848,172260,5673189", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "DIM_DATE": "2021-05-31", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Dimension_Date_Value") # multi dimension with value - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "dem,Slopes,Contours", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-1219081,4281848,172260,5673189", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "ELEVATION": "1000", - "DIM_RANGE_ELEVATION": "1000" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "dem,Slopes,Contours", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-1219081,4281848,172260,5673189", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "ELEVATION": "1000", + "DIM_RANGE_ELEVATION": "1000", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetMap_Dimension_Elevation_RangeElevation_Value") + self._img_diff_error( + r, h, "WMS_GetMap_Dimension_Elevation_RangeElevation_Value" + ) def test_wms_getmap_range_value(self): # dimension with range value - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "dem,Slopes,Contours", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-1219081,4281848,172260,5673189", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "ELEVATION": "1000/2000" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "dem,Slopes,Contours", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-1219081,4281848,172260,5673189", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "ELEVATION": "1000/2000", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Dimension_Elevation_RangeValue") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "dem,Slopes,Contours", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-1219081,4281848,172260,5673189", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "DIM_RANGE_ELEVATION": "1000/2000" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "dem,Slopes,Contours", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-1219081,4281848,172260,5673189", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "DIM_RANGE_ELEVATION": "1000/2000", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Dimension_RangeElevation_RangeValue") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "dem,Datetime_dim", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-1219081,4281848,172260,5673189", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "TIME": "2021-05-31T09:00:00/2021-06-30T09:00:00" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "dem,Datetime_dim", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-1219081,4281848,172260,5673189", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "TIME": "2021-05-31T09:00:00/2021-06-30T09:00:00", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Dimension_Time_RangeValue") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "dem,Datetime_dim", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-1219081,4281848,172260,5673189", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "DIM_DATE": "2021-05-31/2021-06-30" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "dem,Datetime_dim", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-1219081,4281848,172260,5673189", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "DIM_DATE": "2021-05-31/2021-06-30", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Dimension_Date_RangeValue") def test_wms_getmap_multi_values(self): # dimension with multi values - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "dem,Slopes,Contours", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-1219081,4281848,172260,5673189", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "ELEVATION": "1000,2000" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "dem,Slopes,Contours", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-1219081,4281848,172260,5673189", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "ELEVATION": "1000,2000", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Dimension_Elevation_MultiValues") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "dem,Slopes,Contours", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-1219081,4281848,172260,5673189", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "DIM_RANGE_ELEVATION": "1000,2000" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "dem,Slopes,Contours", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-1219081,4281848,172260,5673189", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "DIM_RANGE_ELEVATION": "1000,2000", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Dimension_RangeElevation_MultiValues") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "dem,Datetime_dim", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-1219081,4281848,172260,5673189", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "TIME": "2021-05-31T10:00:00,2021-05-31T17:00:00" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "dem,Datetime_dim", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-1219081,4281848,172260,5673189", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "TIME": "2021-05-31T10:00:00,2021-05-31T17:00:00", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Dimension_Time_MultiValues") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "dem,Datetime_dim", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-1219081,4281848,172260,5673189", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "DIM_DATE": "2021-05-31,2021-06-30" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "dem,Datetime_dim", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-1219081,4281848,172260,5673189", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "DIM_DATE": "2021-05-31,2021-06-30", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Dimension_Date_MultiValues") def test_wms_getmap_mix_values(self): # dimension with mix values - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "dem,Slopes,Contours", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-1219081,4281848,172260,5673189", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "ELEVATION": "1000/1500,2000" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "dem,Slopes,Contours", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-1219081,4281848,172260,5673189", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "ELEVATION": "1000/1500,2000", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Dimension_Elevation_MixValues") # same as ELEVATION=1000/2000 self._img_diff_error(r, h, "WMS_GetMap_Dimension_Elevation_RangeValue") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "dem,Slopes,Contours", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-1219081,4281848,172260,5673189", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "DIM_RANGE_ELEVATION": "1000/1500,2000" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "dem,Slopes,Contours", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-1219081,4281848,172260,5673189", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "DIM_RANGE_ELEVATION": "1000/1500,2000", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Dimension_RangeElevation_MixValues") @@ -357,21 +500,28 @@ def test_wms_getmap_mix_values(self): def test_wms_getmap_with_filter(self): # dimension with filter - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "dem,Slopes,Contours", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-1219081,4281848,172260,5673189", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "ELEVATION": "800/2200", - "FILTER": "Contours:\"elev\" <= 1200" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "dem,Slopes,Contours", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-1219081,4281848,172260,5673189", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "ELEVATION": "800/2200", + "FILTER": 'Contours:"elev" <= 1200', + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Dimension_Elevation_RangeValue_Filter") @@ -379,20 +529,27 @@ def test_wms_getmap_with_filter(self): self._img_diff_error(r, h, "WMS_GetMap_Dimension_Elevation_Value") def test_wms_getprint_dimension(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-1219081,4281848,172260,5673189", - "map0:LAYERS": "dem,Datetime_dim", - "map0:SCALE": "10013037", - "CRS": "EPSG:3857", - "HEIGHT": "500", - "DIM_DATE": "2021-05-31,2021-06-30" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-1219081,4281848,172260,5673189", + "map0:LAYERS": "dem,Datetime_dim", + "map0:SCALE": "10013037", + "CRS": "EPSG:3857", + "HEIGHT": "500", + "DIM_DATE": "2021-05-31,2021-06-30", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_Dimension", max_size_diff=QSize(1, 1)) diff --git a/tests/src/python/test_qgsserver_wms_dxf.py b/tests/src/python/test_qgsserver_wms_dxf.py index 07a23e291236..eadd87aadf71 100644 --- a/tests/src/python/test_qgsserver_wms_dxf.py +++ b/tests/src/python/test_qgsserver_wms_dxf.py @@ -9,9 +9,10 @@ (at your option) any later version. """ -__author__ = 'Tudor Bărăscu' -__date__ = '27/01/2021' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Tudor Bărăscu" +__date__ = "27/01/2021" +__copyright__ = "Copyright 2020, The QGIS Project" import os import urllib.parse @@ -23,46 +24,56 @@ from test_qgsserver import QgsServerTestBase # Needed on Qt 5 so that the serialization of XML is consistent among all executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" class PyQgsServerWMSGetMapDxf(QgsServerTestBase): def test_dxf_export_works_with_reverse_axis_epsg(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(os.path.join(self.testdata_path, - 'test_dxf_export.qgs')), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "BBOX": "399980,449980,400050,450100", - "CRS": "EPSG:3844", - "LAYERS": "test_dxf_export", - "STYLES": ",", - "FORMAT": "application/dxf", - "SCALE": "500", - "FILE_NAME": "test_dxf_export.dxf" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote( + os.path.join(self.testdata_path, "test_dxf_export.qgs") + ), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "BBOX": "399980,449980,400050,450100", + "CRS": "EPSG:3844", + "LAYERS": "test_dxf_export", + "STYLES": ",", + "FORMAT": "application/dxf", + "SCALE": "500", + "FILE_NAME": "test_dxf_export.dxf", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) tempDir = QtCore.QTemporaryDir() - dxf = os.path.join(tempDir.path(), 'test_dxf_export.dxf') - f = open(dxf, 'wb') + dxf = os.path.join(tempDir.path(), "test_dxf_export.dxf") + f = open(dxf, "wb") f.write(r) f.close() vl = QgsVectorLayer(dxf, "lyr", "ogr") - myMessage = ('Expected downloaded dxf contains: %s line\nGot: %s\n' % - (1, vl.featureCount())) + myMessage = "Expected downloaded dxf contains: {} line\nGot: {}\n".format( + 1, + vl.featureCount(), + ) self.assertEqual(vl.featureCount(), 1, myMessage) line_from_dxf = next(vl.getFeatures()).geometry().asWkt() - line = 'LineString (450000 400000, 450100 400000)' + line = "LineString (450000 400000, 450100 400000)" self.assertEqual(line_from_dxf, line) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_wms_getcapabilities_group_name.py b/tests/src/python/test_qgsserver_wms_getcapabilities_group_name.py index 9b35e620a75c..f741b7831b68 100644 --- a/tests/src/python/test_qgsserver_wms_getcapabilities_group_name.py +++ b/tests/src/python/test_qgsserver_wms_getcapabilities_group_name.py @@ -8,9 +8,10 @@ (at your option) any later version. """ -__author__ = 'Tomas Straupis' -__date__ = '2023-10-13' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "Tomas Straupis" +__date__ = "2023-10-13" +__copyright__ = "Copyright 2023, The QGIS Project" import os import urllib.parse @@ -30,50 +31,82 @@ def setUp(self): # First project has "skipping name tag for groups" setting set to false (default) self.project_with_name = os.path.join(self.testdata_path, "wms_group_test1.qgs") # Second project has "skipping name tag for groups" setting set to true - self.project_without_name = os.path.join(self.testdata_path, "wms_group_test2.qgs") + self.project_without_name = os.path.join( + self.testdata_path, "wms_group_test2.qgs" + ) def test_wms_getcapabilities_with(self): r = make_capabilities_request(self, self.project_with_name) - self.assertIn(b'layer_group', r, 'attribute should be specified for a layer group') + self.assertIn( + b"layer_group", + r, + "attribute should be specified for a layer group", + ) def test_wms_getmap_with(self): r = make_map_request(self, self.project_with_name) - self.assertNotIn(b'', r, 'there should be no server exception for a layer group in LAYERS=') + self.assertNotIn( + b'', + r, + "there should be no server exception for a layer group in LAYERS=", + ) def test_wms_getcapabilities_without(self): r = make_capabilities_request(self, self.project_without_name) - self.assertNotIn(b'layer_group', r, 'attribute should NOT be specified for a layer group') + self.assertNotIn( + b"layer_group", + r, + "attribute should NOT be specified for a layer group", + ) def test_wms_getmap_without(self): r = make_map_request(self, self.project_without_name) - self.assertIn(b'', r, 'there should a server exception for a layer group in LAYERS=') + self.assertIn( + b'', + r, + "there should a server exception for a layer group in LAYERS=", + ) def make_capabilities_request(instance, project): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WMS", - "REQUEST": "GetCapabilities" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WMS", + "REQUEST": "GetCapabilities", + }.items() + ) + ] + ) r, h = instance._result(instance._execute_request(qs)) return instance.strip_version_xmlns(r) def make_map_request(instance, project): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WMS", - "REQUEST": "GetMap", - "BBOX": "6053181%2C594460%2C6053469%2C595183", - "CRS": "EPSG%3A3346", - "WIDTH": "1500", - "HEIGHT": "600", - "LAYERS": "layer_group", - "VERSION": "1.3.0" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WMS", + "REQUEST": "GetMap", + "BBOX": "6053181%2C594460%2C6053469%2C595183", + "CRS": "EPSG%3A3346", + "WIDTH": "1500", + "HEIGHT": "600", + "LAYERS": "layer_group", + "VERSION": "1.3.0", + }.items() + ) + ] + ) r, h = instance._result(instance._execute_request(qs)) return instance.strip_version_xmlns(r) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_wms_getfeatureinfo.py b/tests/src/python/test_qgsserver_wms_getfeatureinfo.py index d9dbe42e1327..080d85eda131 100644 --- a/tests/src/python/test_qgsserver_wms_getfeatureinfo.py +++ b/tests/src/python/test_qgsserver_wms_getfeatureinfo.py @@ -9,15 +9,16 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '11/03/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "11/03/2018" +__copyright__ = "Copyright 2018, The QGIS Project" import os # Needed on Qt 5 so that the serialization of XML is consistent among all # executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" import json import urllib.error @@ -50,276 +51,328 @@ class TestQgsServerWMSGetFeatureInfo(TestQgsServerWMSTestBase): def tearDown(self): super().tearDown() - os.putenv('QGIS_SERVER_ALLOWED_EXTRA_SQL_TOKENS', '') + os.putenv("QGIS_SERVER_ALLOWED_EXTRA_SQL_TOKENS", "") def testGetFeatureInfo(self): # Test getfeatureinfo response xml - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&styles=&' + - 'info_format=text%2Fxml&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320', - 'wms_getfeatureinfo-text-xml') - - self.wms_request_compare('GetFeatureInfo', - '&layers=&styles=&' + - 'info_format=text%2Fxml&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320', - 'wms_getfeatureinfo-text-xml') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&styles=&" + + "info_format=text%2Fxml&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320", + "wms_getfeatureinfo-text-xml", + ) + + self.wms_request_compare( + "GetFeatureInfo", + "&layers=&styles=&" + + "info_format=text%2Fxml&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320", + "wms_getfeatureinfo-text-xml", + ) # Test getfeatureinfo on non queryable layer - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer3&styles=&' + - 'info_format=text%2Fxml&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer3&X=190&Y=320', - 'wms_getfeatureinfo-testlayer3-notqueryable') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer3&styles=&" + + "info_format=text%2Fxml&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer3&X=190&Y=320", + "wms_getfeatureinfo-testlayer3-notqueryable", + ) # Test getfeatureinfo on group without shortname (no queryable...) - self.wms_request_compare('GetFeatureInfo', - '&layers=groupwithoutshortname&styles=&' + - 'info_format=text%2Fxml&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=groupwithoutshortname&X=190&Y=320', - 'wms_getfeatureinfo-groupwithoutshortname-notqueryable') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=groupwithoutshortname&styles=&" + + "info_format=text%2Fxml&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=groupwithoutshortname&X=190&Y=320", + "wms_getfeatureinfo-groupwithoutshortname-notqueryable", + ) # Test getfeatureinfo on group with shortname (no queryable...) - self.wms_request_compare('GetFeatureInfo', - '&layers=group_name&styles=&' + - 'info_format=text%2Fxml&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=group_name&X=190&Y=320', - 'wms_getfeatureinfo-group_name-notqueryable') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=group_name&styles=&" + + "info_format=text%2Fxml&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=group_name&X=190&Y=320", + "wms_getfeatureinfo-group_name-notqueryable", + ) # Test getfeatureinfo response html - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&styles=&' + - 'info_format=text%2Fhtml&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320', - 'wms_getfeatureinfo-text-html') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&styles=&" + + "info_format=text%2Fhtml&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320", + "wms_getfeatureinfo-text-html", + ) # Test getfeatureinfo response html tag chars name - self.wms_request_compare('GetFeatureInfo', - '&layers=%3Ctest%20layer%20name%3E&styles=&' + - 'info_format=text%2Fhtml&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=%3Ctest%20layer%20name%3E&X=190&Y=320', - 'wms_getfeatureinfo-text-html-tag-chars') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=%3Ctest%20layer%20name%3E&styles=&" + + "info_format=text%2Fhtml&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=%3Ctest%20layer%20name%3E&X=190&Y=320", + "wms_getfeatureinfo-text-html-tag-chars", + ) # Test getfeatureinfo response html tag chars title - self.wms_request_compare('GetFeatureInfo', - '&layers=%3Ctest%20layer%20title%3E&styles=&' + - 'info_format=text%2Fhtml&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=%3Ctest%20layer%20title%3E&X=190&Y=320', - 'wms_getfeatureinfo-text-html-tag-chars-title') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=%3Ctest%20layer%20title%3E&styles=&" + + "info_format=text%2Fhtml&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=%3Ctest%20layer%20title%3E&X=190&Y=320", + "wms_getfeatureinfo-text-html-tag-chars-title", + ) # Test getfeatureinfo response html with geometry - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&styles=&' + - 'info_format=text%2Fhtml&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320&' + - 'with_geometry=true', - 'wms_getfeatureinfo-text-html-geometry') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&styles=&" + + "info_format=text%2Fhtml&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320&" + + "with_geometry=true", + "wms_getfeatureinfo-text-html-geometry", + ) # Test getfeatureinfo response html with maptip and display name for vector layer - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&styles=&' + - 'info_format=text%2Fhtml&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320&' + - 'with_display_name=true&' + - 'with_maptip=true', - 'wms_getfeatureinfo-text-html-maptip') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&styles=&" + + "info_format=text%2Fhtml&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320&" + + "with_display_name=true&" + + "with_maptip=true", + "wms_getfeatureinfo-text-html-maptip", + ) # Test getfeatureinfo response html only with maptip for vector layer - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&styles=&' + - 'info_format=text%2Fhtml&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320&' + - 'with_maptip=html_fi_only_maptip', - 'wms_getfeatureinfo-html-only-with-maptip-vector') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&styles=&" + + "info_format=text%2Fhtml&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320&" + + "with_maptip=html_fi_only_maptip", + "wms_getfeatureinfo-html-only-with-maptip-vector", + ) # Test getfeatureinfo response html with maptip and display name in text mode for vector layer - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&styles=&' + - 'info_format=text%2Fplain&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320&' + - 'with_display_name=true&' + - 'with_maptip=true', - 'wms_getfeatureinfo-text-html-maptip-plain') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&styles=&" + + "info_format=text%2Fplain&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320&" + + "with_display_name=true&" + + "with_maptip=true", + "wms_getfeatureinfo-text-html-maptip-plain", + ) # Test getfeatureinfo response text - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&styles=&' + - 'transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320&' + - 'info_format=text/plain', - 'wms_getfeatureinfo-text-plain') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&styles=&" + + "transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320&" + + "info_format=text/plain", + "wms_getfeatureinfo-text-plain", + ) # Test getfeatureinfo default info_format - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&styles=&' + - 'transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320', - 'wms_getfeatureinfo-text-plain') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&styles=&" + + "transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320", + "wms_getfeatureinfo-text-plain", + ) # Test getfeatureinfo invalid info_format - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&styles=&' + - 'transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320&' + - 'info_format=InvalidFormat', - 'wms_getfeatureinfo-invalid-format') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&styles=&" + + "transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320&" + + "info_format=InvalidFormat", + "wms_getfeatureinfo-invalid-format", + ) # Test feature info request with filter geometry - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&' + - 'INFO_FORMAT=text%2Fxml&' + - 'width=600&height=400&srs=EPSG%3A4326&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&' + - 'FEATURE_COUNT=10&FILTER_GEOM=POLYGON((8.2035381 44.901459,8.2035562 44.901459,8.2035562 44.901418,8.2035381 44.901418,8.2035381 44.901459))', - 'wms_getfeatureinfo_geometry_filter') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&" + + "INFO_FORMAT=text%2Fxml&" + + "width=600&height=400&srs=EPSG%3A4326&" + + "query_layers=testlayer%20%C3%A8%C3%A9&" + + "FEATURE_COUNT=10&FILTER_GEOM=POLYGON((8.2035381 44.901459,8.2035562 44.901459,8.2035562 44.901418,8.2035381 44.901418,8.2035381 44.901459))", + "wms_getfeatureinfo_geometry_filter", + ) # Test feature info request with filter geometry and feature filter # FILTER_GEOM includes feature "two" and "three" and FILTER includes # feature "one" and "two". We expect to get only feature "two" # See issue GH #58998 - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&' + - 'INFO_FORMAT=text%2Fxml&' + - 'width=600&height=400&srs=EPSG%3A4326&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&' + - 'FEATURE_COUNT=10&' + - 'FILTER_GEOM=POLYGON((8.20343877754122275 44.90137289898639494, 8.20356495882830572 44.90137289898639494, 8.20356495882830572 44.90146497029139994, 8.20343877754122275 44.90146497029139994, 8.20343877754122275 44.90137289898639494))&' + - 'FILTER=testlayer%20%C3%A8%C3%A9:"name" = \'two\' or "name" = \'one\'', - 'wms_getfeatureinfo_geometry_and_exp_filter_exclude') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&" + + "INFO_FORMAT=text%2Fxml&" + + "width=600&height=400&srs=EPSG%3A4326&" + + "query_layers=testlayer%20%C3%A8%C3%A9&" + + "FEATURE_COUNT=10&" + + "FILTER_GEOM=POLYGON((8.20343877754122275 44.90137289898639494, 8.20356495882830572 44.90137289898639494, 8.20356495882830572 44.90146497029139994, 8.20343877754122275 44.90146497029139994, 8.20343877754122275 44.90137289898639494))&" + + "FILTER=testlayer%20%C3%A8%C3%A9:\"name\" = 'two' or \"name\" = 'one'", + "wms_getfeatureinfo_geometry_and_exp_filter_exclude", + ) # Test feature info request with filter geometry in non-layer CRS - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&' + - 'INFO_FORMAT=text%2Fxml&' + - 'width=600&height=400&srs=EPSG%3A3857&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&' + - 'FEATURE_COUNT=10&FILTER_GEOM=POLYGON ((913213.6839952 5606021.5399693, 913215.6988780 5606021.5399693, 913215.6988780 5606015.09643322, 913213.6839952 5606015.0964332, 913213.6839952 5606021.5399693))', - 'wms_getfeatureinfo_geometry_filter_3857') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&" + + "INFO_FORMAT=text%2Fxml&" + + "width=600&height=400&srs=EPSG%3A3857&" + + "query_layers=testlayer%20%C3%A8%C3%A9&" + + "FEATURE_COUNT=10&FILTER_GEOM=POLYGON ((913213.6839952 5606021.5399693, 913215.6988780 5606021.5399693, 913215.6988780 5606015.09643322, 913213.6839952 5606015.0964332, 913213.6839952 5606021.5399693))", + "wms_getfeatureinfo_geometry_filter_3857", + ) # Test feature info request with invalid query_layer - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&' + - 'INFO_FORMAT=text%2Fxml&' + - 'width=600&height=400&srs=EPSG%3A3857&' + - 'query_layers=InvalidLayer&' + - 'FEATURE_COUNT=10&FILTER_GEOM=POLYGON((8.2035381 44.901459,8.2035562 44.901459,8.2035562 44.901418,8.2035381 44.901418,8.2035381 44.901459))', - 'wms_getfeatureinfo_invalid_query_layers') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&" + + "INFO_FORMAT=text%2Fxml&" + + "width=600&height=400&srs=EPSG%3A3857&" + + "query_layers=InvalidLayer&" + + "FEATURE_COUNT=10&FILTER_GEOM=POLYGON((8.2035381 44.901459,8.2035562 44.901459,8.2035562 44.901418,8.2035381 44.901418,8.2035381 44.901459))", + "wms_getfeatureinfo_invalid_query_layers", + ) # Test feature info request with '+' instead of ' ' in layers and # query_layers parameters - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer+%C3%A8%C3%A9&styles=&' + - 'info_format=text%2Fxml&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer+%C3%A8%C3%A9&X=190&Y=320', - 'wms_getfeatureinfo-text-xml') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer+%C3%A8%C3%A9&styles=&" + + "info_format=text%2Fxml&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer+%C3%A8%C3%A9&X=190&Y=320", + "wms_getfeatureinfo-text-xml", + ) # layer1 is a clone of layer0 but with a scale visibility. Thus, # GetFeatureInfo response contains only a feature for layer0 and layer1 # is ignored for the required bbox. Without the scale visibility option, # the feature for layer1 would have been in the response too. mypath = self.testdata_path + "test_project_scalevisibility.qgs" - self.wms_request_compare('GetFeatureInfo', - '&layers=layer0,layer1&styles=&' + - 'VERSION=1.1.0&' + - 'info_format=text%2Fxml&' + - 'width=500&height=500&srs=EPSG%3A4326' + - '&bbox=8.1976,44.8998,8.2100,44.9027&' + - 'query_layers=layer0,layer1&X=235&Y=243', - 'wms_getfeatureinfo_notvisible', - 'test_project_scalevisibility.qgs') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=layer0,layer1&styles=&" + + "VERSION=1.1.0&" + + "info_format=text%2Fxml&" + + "width=500&height=500&srs=EPSG%3A4326" + + "&bbox=8.1976,44.8998,8.2100,44.9027&" + + "query_layers=layer0,layer1&X=235&Y=243", + "wms_getfeatureinfo_notvisible", + "test_project_scalevisibility.qgs", + ) # Test GetFeatureInfo resolves "value map" widget values but also # Server usage of qgs and gpkg file mypath = self.testdata_path + "test_project_values.qgz" - self.wms_request_compare('GetFeatureInfo', - '&layers=layer0&styles=&' + - 'VERSION=1.3.0&' + - 'info_format=text%2Fxml&' + - 'width=926&height=787&srs=EPSG%3A4326' + - '&bbox=912217,5605059,914099,5606652' + - '&CRS=EPSG:3857' + - '&FEATURE_COUNT=10' + - '&QUERY_LAYERS=layer0&I=487&J=308', - 'wms_getfeatureinfo-values0-text-xml', - 'test_project_values.qgz') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=layer0&styles=&" + + "VERSION=1.3.0&" + + "info_format=text%2Fxml&" + + "width=926&height=787&srs=EPSG%3A4326" + + "&bbox=912217,5605059,914099,5606652" + + "&CRS=EPSG:3857" + + "&FEATURE_COUNT=10" + + "&QUERY_LAYERS=layer0&I=487&J=308", + "wms_getfeatureinfo-values0-text-xml", + "test_project_values.qgz", + ) # Test GetFeatureInfo on raster layer - self.wms_request_compare('GetFeatureInfo', - '&layers=landsat&styles=&' + - 'info_format=text%2Fxml&transparent=true&' + - 'width=500&height=500&srs=EPSG%3A3857&' + - 'bbox=1989139.6,3522745.0,2015014.9,3537004.5&' + - 'query_layers=landsat&X=250&Y=250', - 'wms_getfeatureinfo-raster-text-xml') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=landsat&styles=&" + + "info_format=text%2Fxml&transparent=true&" + + "width=500&height=500&srs=EPSG%3A3857&" + + "bbox=1989139.6,3522745.0,2015014.9,3537004.5&" + + "query_layers=landsat&X=250&Y=250", + "wms_getfeatureinfo-raster-text-xml", + ) # Test GetFeatureInfo on raster layer with maptip - self.wms_request_compare('GetFeatureInfo', - '&layers=landsat&styles=&' + - 'info_format=text%2Fxml&transparent=true&' + - 'width=500&height=500&srs=EPSG%3A3857&' + - 'bbox=1989139.6,3522745.0,2015014.9,3537004.5&' + - 'query_layers=landsat&X=250&Y=250&' + - 'with_maptip=true', - 'wms_getfeatureinfo-raster-text-xml-maptip') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=landsat&styles=&" + + "info_format=text%2Fxml&transparent=true&" + + "width=500&height=500&srs=EPSG%3A3857&" + + "bbox=1989139.6,3522745.0,2015014.9,3537004.5&" + + "query_layers=landsat&X=250&Y=250&" + + "with_maptip=true", + "wms_getfeatureinfo-raster-text-xml-maptip", + ) # Test GetFeatureInfo on raster layer HTML only with maptip - self.wms_request_compare('GetFeatureInfo', - '&layers=landsat&styles=&' + - 'info_format=text%2Fhtml&transparent=true&' + - 'width=500&height=500&srs=EPSG%3A3857&' + - 'bbox=1989139.6,3522745.0,2015014.9,3537004.5&' + - 'query_layers=landsat&X=250&Y=250&' + - 'with_maptip=html_fi_only_maptip', - 'wms_getfeatureinfo-html-only-with-maptip-raster') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=landsat&styles=&" + + "info_format=text%2Fhtml&transparent=true&" + + "width=500&height=500&srs=EPSG%3A3857&" + + "bbox=1989139.6,3522745.0,2015014.9,3537004.5&" + + "query_layers=landsat&X=250&Y=250&" + + "with_maptip=html_fi_only_maptip", + "wms_getfeatureinfo-html-only-with-maptip-raster", + ) def testGetFeatureInfoValueRelation(self): """Test GetFeatureInfo resolves "value relation" widget values. regression 18518""" mypath = self.testdata_path + "test_project_values.qgz" - self.wms_request_compare('GetFeatureInfo', - '&layers=layer1&styles=&' + - 'VERSION=1.3.0&' + - 'info_format=text%2Fxml&' + - 'width=926&height=787&srs=EPSG%3A4326' + - '&bbox=912217,5605059,914099,5606652' + - '&CRS=EPSG:3857' + - '&FEATURE_COUNT=10' + - '&WITH_GEOMETRY=True' + - '&QUERY_LAYERS=layer1&I=487&J=308', - 'wms_getfeatureinfo-values1-text-xml', - 'test_project_values.qgz') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=layer1&styles=&" + + "VERSION=1.3.0&" + + "info_format=text%2Fxml&" + + "width=926&height=787&srs=EPSG%3A4326" + + "&bbox=912217,5605059,914099,5606652" + + "&CRS=EPSG:3857" + + "&FEATURE_COUNT=10" + + "&WITH_GEOMETRY=True" + + "&QUERY_LAYERS=layer1&I=487&J=308", + "wms_getfeatureinfo-values1-text-xml", + "test_project_values.qgz", + ) # TODO make GetFeatureInfo show what's in the display expression and # enable test @@ -327,451 +380,529 @@ def testGetFeatureInfoValueRelation(self): def testGetFeatureInfoRelationReference(self): """Test GetFeatureInfo solves "relation reference" widget "display expression" values""" mypath = self.testdata_path + "test_project_values.qgz" - self.wms_request_compare('GetFeatureInfo', - '&layers=layer2&styles=&' + - 'VERSION=1.3.0&' + - 'info_format=text%2Fxml&' + - 'width=926&height=787&srs=EPSG%3A4326' + - '&bbox=912217,5605059,914099,5606652' + - '&CRS=EPSG:3857' + - '&FEATURE_COUNT=10' + - '&WITH_GEOMETRY=True' + - '&QUERY_LAYERS=layer2&I=487&J=308', - 'wms_getfeatureinfo-values2-text-xml', - 'test_project_values.qgz') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=layer2&styles=&" + + "VERSION=1.3.0&" + + "info_format=text%2Fxml&" + + "width=926&height=787&srs=EPSG%3A4326" + + "&bbox=912217,5605059,914099,5606652" + + "&CRS=EPSG:3857" + + "&FEATURE_COUNT=10" + + "&WITH_GEOMETRY=True" + + "&QUERY_LAYERS=layer2&I=487&J=308", + "wms_getfeatureinfo-values2-text-xml", + "test_project_values.qgz", + ) def testGetFeatureInfoSortedByDesigner(self): """Test GetFeatureInfo resolves DRAG&DROP Designer order when use attribute form settings for GetFeatureInfo is checked, see https://github.com/qgis/QGIS/pull/41031 """ mypath = self.testdata_path + "test_project_values.qgz" - self.wms_request_compare('GetFeatureInfo', - '&layers=layer2&styles=&' + - 'VERSION=1.3.0&' + - 'info_format=text%2Fxml&' + - 'width=926&height=787&srs=EPSG%3A4326' + - '&bbox=912217,5605059,914099,5606652' + - '&CRS=EPSG:3857' + - '&FEATURE_COUNT=10' + - '&WITH_GEOMETRY=True' + - '&QUERY_LAYERS=layer3&I=487&J=308', - 'wms_getfeatureinfo-values5-text-xml', - 'test_project_values.qgz') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=layer2&styles=&" + + "VERSION=1.3.0&" + + "info_format=text%2Fxml&" + + "width=926&height=787&srs=EPSG%3A4326" + + "&bbox=912217,5605059,914099,5606652" + + "&CRS=EPSG:3857" + + "&FEATURE_COUNT=10" + + "&WITH_GEOMETRY=True" + + "&QUERY_LAYERS=layer3&I=487&J=308", + "wms_getfeatureinfo-values5-text-xml", + "test_project_values.qgz", + ) def testGetFeatureInfoFilterGPKG(self): # 'test_project.qgz' ='test_project.qgs' but with a gpkg source + different fid # Regression for #8656 Test getfeatureinfo response xml with gpkg datasource # Mind the gap! (the space in the FILTER expression) - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&' + - 'INFO_FORMAT=text%2Fxml&' + - 'width=600&height=400&srs=EPSG%3A3857&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&' + - 'FEATURE_COUNT=10&FILTER=testlayer%20%C3%A8%C3%A9' + - urllib.parse.quote(':"NAME" = \'two\''), - 'wms_getfeatureinfo_filter_gpkg', - 'test_project.qgz') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&" + + "INFO_FORMAT=text%2Fxml&" + + "width=600&height=400&srs=EPSG%3A3857&" + + "query_layers=testlayer%20%C3%A8%C3%A9&" + + "FEATURE_COUNT=10&FILTER=testlayer%20%C3%A8%C3%A9" + + urllib.parse.quote(":\"NAME\" = 'two'"), + "wms_getfeatureinfo_filter_gpkg", + "test_project.qgz", + ) def testGetFeatureInfoFilter(self): # Test getfeatureinfo response xml # Regression for #8656 # Mind the gap! (the space in the FILTER expression) - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&' + - 'INFO_FORMAT=text%2Fxml&' + - 'width=600&height=400&srs=EPSG%3A3857&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&' + - 'FEATURE_COUNT=10&FILTER=testlayer%20%C3%A8%C3%A9' + - urllib.parse.quote(':"NAME" = \'two\''), - 'wms_getfeatureinfo_filter') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&" + + "INFO_FORMAT=text%2Fxml&" + + "width=600&height=400&srs=EPSG%3A3857&" + + "query_layers=testlayer%20%C3%A8%C3%A9&" + + "FEATURE_COUNT=10&FILTER=testlayer%20%C3%A8%C3%A9" + + urllib.parse.quote(":\"NAME\" = 'two'"), + "wms_getfeatureinfo_filter", + ) # Test a filter with NO condition results - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&' + - 'INFO_FORMAT=text%2Fxml&' + - 'width=600&height=400&srs=EPSG%3A3857&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&' + - 'FEATURE_COUNT=10&FILTER=testlayer%20%C3%A8%C3%A9' + - urllib.parse.quote( - ':"NAME" = \'two\' AND "utf8nameè" = \'no-results\''), - 'wms_getfeatureinfo_filter_no_results') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&" + + "INFO_FORMAT=text%2Fxml&" + + "width=600&height=400&srs=EPSG%3A3857&" + + "query_layers=testlayer%20%C3%A8%C3%A9&" + + "FEATURE_COUNT=10&FILTER=testlayer%20%C3%A8%C3%A9" + + urllib.parse.quote(":\"NAME\" = 'two' AND \"utf8nameè\" = 'no-results'"), + "wms_getfeatureinfo_filter_no_results", + ) # Test a filter with OR condition results - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&' + - 'INFO_FORMAT=text%2Fxml&' + - 'width=600&height=400&srs=EPSG%3A3857&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&' + - 'FEATURE_COUNT=10&FILTER=testlayer%20%C3%A8%C3%A9' + - urllib.parse.quote( - ':"NAME" = \'two\' OR "NAME" = \'three\''), - 'wms_getfeatureinfo_filter_or') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&" + + "INFO_FORMAT=text%2Fxml&" + + "width=600&height=400&srs=EPSG%3A3857&" + + "query_layers=testlayer%20%C3%A8%C3%A9&" + + "FEATURE_COUNT=10&FILTER=testlayer%20%C3%A8%C3%A9" + + urllib.parse.quote(":\"NAME\" = 'two' OR \"NAME\" = 'three'"), + "wms_getfeatureinfo_filter_or", + ) # Test a filter with OR condition and UTF results # Note that the layer name that contains utf-8 chars cannot be # to upper case. - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&' + - 'INFO_FORMAT=text%2Fxml&' + - 'width=600&height=400&srs=EPSG%3A3857&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&' + - 'FEATURE_COUNT=10&FILTER=testlayer%20%C3%A8%C3%A9' + - urllib.parse.quote( - ':"NAME" = \'two\' OR "utf8nameè" = \'three èé↓\''), - 'wms_getfeatureinfo_filter_or_utf8') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&" + + "INFO_FORMAT=text%2Fxml&" + + "width=600&height=400&srs=EPSG%3A3857&" + + "query_layers=testlayer%20%C3%A8%C3%A9&" + + "FEATURE_COUNT=10&FILTER=testlayer%20%C3%A8%C3%A9" + + urllib.parse.quote(":\"NAME\" = 'two' OR \"utf8nameè\" = 'three èé↓'"), + "wms_getfeatureinfo_filter_or_utf8", + ) # Regression #18292 Server GetFeatureInfo FILTER search fails when # WIDTH, HEIGHT are not specified - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&' + - 'INFO_FORMAT=text%2Fxml&' + - 'srs=EPSG%3A3857&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&' + - 'FEATURE_COUNT=10&FILTER=testlayer%20%C3%A8%C3%A9' + - urllib.parse.quote(':"NAME" = \'two\''), - 'wms_getfeatureinfo_filter_no_width') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&" + + "INFO_FORMAT=text%2Fxml&" + + "srs=EPSG%3A3857&" + + "query_layers=testlayer%20%C3%A8%C3%A9&" + + "FEATURE_COUNT=10&FILTER=testlayer%20%C3%A8%C3%A9" + + urllib.parse.quote(":\"NAME\" = 'two'"), + "wms_getfeatureinfo_filter_no_width", + ) # Test a filter without CRS parameter - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&' + - 'INFO_FORMAT=text%2Fxml&' + - 'width=600&height=400&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&' + - 'FEATURE_COUNT=10&FILTER=testlayer%20%C3%A8%C3%A9' + - urllib.parse.quote(':"NAME" = \'two\''), - 'wms_getfeatureinfo_filter_no_crs') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&" + + "INFO_FORMAT=text%2Fxml&" + + "width=600&height=400&" + + "query_layers=testlayer%20%C3%A8%C3%A9&" + + "FEATURE_COUNT=10&FILTER=testlayer%20%C3%A8%C3%A9" + + urllib.parse.quote(":\"NAME\" = 'two'"), + "wms_getfeatureinfo_filter_no_crs", + ) def testGetFeatureInfoOGCfilterJSON(self): # OGC Filter test with info_format=application/json # Test OGC filter with I/J and BBOX - self.wms_request_compare('GetFeatureInfo', - '&LAYERS=testlayer%20%C3%A8%C3%A9&' + - 'INFO_FORMAT=application%2Fjson&' + - 'WIDTH=1266&HEIGHT=531&' + - 'QUERY_LAYERS=testlayer%20%C3%A8%C3%A9&' + - 'FEATURE_COUNT=10&' + - 'CRS=EPSG:4326&' + - 'BBOX=44.90139177500000045,8.20339159915254967,44.90148522499999473,8.20361440084745297&' + - 'I=882&J=282&' - 'FILTER=id2', 'wms_getfeatureinfo_filter_ogc') + self.wms_request_compare( + "GetFeatureInfo", + "&LAYERS=testlayer%20%C3%A8%C3%A9&" + + "INFO_FORMAT=application%2Fjson&" + + "WIDTH=1266&HEIGHT=531&" + + "QUERY_LAYERS=testlayer%20%C3%A8%C3%A9&" + + "FEATURE_COUNT=10&" + + "CRS=EPSG:4326&" + + "BBOX=44.90139177500000045,8.20339159915254967,44.90148522499999473,8.20361440084745297&" + + "I=882&J=282&" + "FILTER=id2", + "wms_getfeatureinfo_filter_ogc", + ) # Test OGC filter with I/J and BBOX, filter id 3: empty result - self.wms_request_compare('GetFeatureInfo', - '&LAYERS=testlayer%20%C3%A8%C3%A9&' + - 'INFO_FORMAT=application%2Fjson&' + - 'WIDTH=1266&HEIGHT=531&' + - 'QUERY_LAYERS=testlayer%20%C3%A8%C3%A9&' + - 'FEATURE_COUNT=10&' + - 'CRS=EPSG:4326&' + - 'BBOX=44.90139177500000045,8.20339159915254967,44.90148522499999473,8.20361440084745297&' + - 'I=882&J=282&' - 'FILTER=id3', 'wms_getfeatureinfo_filter_ogc_empty') + self.wms_request_compare( + "GetFeatureInfo", + "&LAYERS=testlayer%20%C3%A8%C3%A9&" + + "INFO_FORMAT=application%2Fjson&" + + "WIDTH=1266&HEIGHT=531&" + + "QUERY_LAYERS=testlayer%20%C3%A8%C3%A9&" + + "FEATURE_COUNT=10&" + + "CRS=EPSG:4326&" + + "BBOX=44.90139177500000045,8.20339159915254967,44.90148522499999473,8.20361440084745297&" + + "I=882&J=282&" + "FILTER=id3", + "wms_getfeatureinfo_filter_ogc_empty", + ) # Test OGC filter with no I/J and BBOX - self.wms_request_compare('GetFeatureInfo', - '&LAYERS=testlayer%20%C3%A8%C3%A9&' + - 'INFO_FORMAT=application%2Fjson&' + - 'WIDTH=1266&HEIGHT=531&' + - 'QUERY_LAYERS=testlayer%20%C3%A8%C3%A9&' + - 'FEATURE_COUNT=10&' + - 'CRS=EPSG:4326&' + - 'FILTER=id2', 'wms_getfeatureinfo_filter_ogc') + self.wms_request_compare( + "GetFeatureInfo", + "&LAYERS=testlayer%20%C3%A8%C3%A9&" + + "INFO_FORMAT=application%2Fjson&" + + "WIDTH=1266&HEIGHT=531&" + + "QUERY_LAYERS=testlayer%20%C3%A8%C3%A9&" + + "FEATURE_COUNT=10&" + + "CRS=EPSG:4326&" + + "FILTER=id2", + "wms_getfeatureinfo_filter_ogc", + ) # Test OGC filter with no I/J and wrong BBOX - self.wms_request_compare('GetFeatureInfo', - '&LAYERS=testlayer%20%C3%A8%C3%A9&' + - 'INFO_FORMAT=application%2Fjson&' + - 'WIDTH=1266&HEIGHT=531&' + - 'QUERY_LAYERS=testlayer%20%C3%A8%C3%A9&' + - 'FEATURE_COUNT=10&' + - 'CRS=EPSG:4326&' + - 'BBOX=46,9,47,10&' + - 'FILTER=id2', 'wms_getfeatureinfo_filter_ogc_empty') + self.wms_request_compare( + "GetFeatureInfo", + "&LAYERS=testlayer%20%C3%A8%C3%A9&" + + "INFO_FORMAT=application%2Fjson&" + + "WIDTH=1266&HEIGHT=531&" + + "QUERY_LAYERS=testlayer%20%C3%A8%C3%A9&" + + "FEATURE_COUNT=10&" + + "CRS=EPSG:4326&" + + "BBOX=46,9,47,10&" + + "FILTER=id2", + "wms_getfeatureinfo_filter_ogc_empty", + ) # Test OGC filter with no I/J and BBOX plus complex OR filter - self.wms_request_compare('GetFeatureInfo', - '&LAYERS=testlayer%20%C3%A8%C3%A9&' + - 'INFO_FORMAT=application%2Fjson&' + - 'WIDTH=1266&HEIGHT=531&' + - 'QUERY_LAYERS=testlayer%20%C3%A8%C3%A9&' + - 'FEATURE_COUNT=10&' + - 'CRS=EPSG:4326&' + - 'FILTER=id2' + - 'id3', 'wms_getfeatureinfo_filter_ogc_complex') + self.wms_request_compare( + "GetFeatureInfo", + "&LAYERS=testlayer%20%C3%A8%C3%A9&" + + "INFO_FORMAT=application%2Fjson&" + + "WIDTH=1266&HEIGHT=531&" + + "QUERY_LAYERS=testlayer%20%C3%A8%C3%A9&" + + "FEATURE_COUNT=10&" + + "CRS=EPSG:4326&" + + "FILTER=id2" + + "id3", + "wms_getfeatureinfo_filter_ogc_complex", + ) # Test OGC filter with no I/J and BBOX plus complex AND filter - self.wms_request_compare('GetFeatureInfo', - '&LAYERS=testlayer%20%C3%A8%C3%A9&' + - 'INFO_FORMAT=application%2Fjson&' + - 'WIDTH=1266&HEIGHT=531&' + - 'QUERY_LAYERS=testlayer%20%C3%A8%C3%A9&' + - 'FEATURE_COUNT=10&' + - 'CRS=EPSG:4326&' + - 'FILTER=id2' + - 'id3', 'wms_getfeatureinfo_filter_ogc_empty') + self.wms_request_compare( + "GetFeatureInfo", + "&LAYERS=testlayer%20%C3%A8%C3%A9&" + + "INFO_FORMAT=application%2Fjson&" + + "WIDTH=1266&HEIGHT=531&" + + "QUERY_LAYERS=testlayer%20%C3%A8%C3%A9&" + + "FEATURE_COUNT=10&" + + "CRS=EPSG:4326&" + + "FILTER=id2" + + "id3", + "wms_getfeatureinfo_filter_ogc_empty", + ) # Test OGC filter with no I/J and BBOX plus complex AND filter - self.wms_request_compare('GetFeatureInfo', - '&LAYERS=testlayer%20%C3%A8%C3%A9&' + - 'INFO_FORMAT=application%2Fjson&' + - 'WIDTH=1266&HEIGHT=531&' + - 'QUERY_LAYERS=testlayer%20%C3%A8%C3%A9&' + - 'FEATURE_COUNT=10&' + - 'CRS=EPSG:4326&' + - 'FILTER=id2' + - 'nametwo', 'wms_getfeatureinfo_filter_ogc') + self.wms_request_compare( + "GetFeatureInfo", + "&LAYERS=testlayer%20%C3%A8%C3%A9&" + + "INFO_FORMAT=application%2Fjson&" + + "WIDTH=1266&HEIGHT=531&" + + "QUERY_LAYERS=testlayer%20%C3%A8%C3%A9&" + + "FEATURE_COUNT=10&" + + "CRS=EPSG:4326&" + + "FILTER=id2" + + "nametwo", + "wms_getfeatureinfo_filter_ogc", + ) def testGetFeatureInfoGML(self): # Test getfeatureinfo response gml - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&styles=&' + - 'info_format=application%2Fvnd.ogc.gml&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320', - 'wms_getfeatureinfo-text-gml') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&styles=&" + + "info_format=application%2Fvnd.ogc.gml&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320", + "wms_getfeatureinfo-text-gml", + ) # Test getfeatureinfo response gml with gml - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&styles=&' + - 'info_format=application%2Fvnd.ogc.gml&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320&' + - 'with_geometry=true', - 'wms_getfeatureinfo-text-gml-geometry') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&styles=&" + + "info_format=application%2Fvnd.ogc.gml&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320&" + + "with_geometry=true", + "wms_getfeatureinfo-text-gml-geometry", + ) def testGetFeatureInfoJSON(self): # simple test without geometry and info_format=application/json - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&styles=&' + - 'info_format=application%2Fjson&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320', - 'wms_getfeatureinfo_json', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&styles=&" + + "info_format=application%2Fjson&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320", + "wms_getfeatureinfo_json", + normalizeJson=True, + ) # simple test without geometry and info_format=application/geo+json - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&styles=&' + - 'info_format=application%2Fgeo%2Bjson&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320', - 'wms_getfeatureinfo_geojson', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&styles=&" + + "info_format=application%2Fgeo%2Bjson&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320", + "wms_getfeatureinfo_geojson", + normalizeJson=True, + ) # test with several features and several layers - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9,fields_alias,exclude_attribute&styles=&' + - 'info_format=application%2Fjson&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer%20%C3%A8%C3%A9,fields_alias,exclude_attribute&' + - 'X=190&Y=320&FEATURE_COUNT=2&FI_POINT_TOLERANCE=200', - 'wms_getfeatureinfo_multiple_json', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9,fields_alias,exclude_attribute&styles=&" + + "info_format=application%2Fjson&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer%20%C3%A8%C3%A9,fields_alias,exclude_attribute&" + + "X=190&Y=320&FEATURE_COUNT=2&FI_POINT_TOLERANCE=200", + "wms_getfeatureinfo_multiple_json", + normalizeJson=True, + ) # simple test with geometry with underlying layer in 3857 - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&styles=&' + - 'info_format=application%2Fjson&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320&' + - 'with_geometry=true', - 'wms_getfeatureinfo_geometry_json', - 'test_project_epsg3857.qgs', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&styles=&" + + "info_format=application%2Fjson&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320&" + + "with_geometry=true", + "wms_getfeatureinfo_geometry_json", + "test_project_epsg3857.qgs", + normalizeJson=True, + ) # simple test with geometry with underlying layer in 4326 - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&styles=&' + - 'info_format=application%2Fjson&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320&' + - 'with_geometry=true', - 'wms_getfeatureinfo_geometry_json', - 'test_project.qgs', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&styles=&" + + "info_format=application%2Fjson&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320&" + + "with_geometry=true", + "wms_getfeatureinfo_geometry_json", + "test_project.qgs", + normalizeJson=True, + ) # test with alias - self.wms_request_compare('GetFeatureInfo', - '&layers=fields_alias&styles=&' + - 'info_format=application%2Fjson&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=fields_alias&X=190&Y=320', - 'wms_getfeatureinfo_alias_json', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&layers=fields_alias&styles=&" + + "info_format=application%2Fjson&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=fields_alias&X=190&Y=320", + "wms_getfeatureinfo_alias_json", + normalizeJson=True, + ) # test with excluded attributes - self.wms_request_compare('GetFeatureInfo', - '&layers=exclude_attribute&styles=&' + - 'info_format=application%2Fjson&transparent=true&' + - 'width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C' + - '5606005.488876367%2C913235.426296057%2C5606035.347090538&' + - 'query_layers=exclude_attribute&X=190&Y=320', - 'wms_getfeatureinfo_exclude_attribute_json', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&layers=exclude_attribute&styles=&" + + "info_format=application%2Fjson&transparent=true&" + + "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C" + + "5606005.488876367%2C913235.426296057%2C5606035.347090538&" + + "query_layers=exclude_attribute&X=190&Y=320", + "wms_getfeatureinfo_exclude_attribute_json", + normalizeJson=True, + ) # test with raster layer - self.wms_request_compare('GetFeatureInfo', - '&layers=landsat&styles=&' + - 'info_format=application%2Fjson&transparent=true&' + - 'width=500&height=500&srs=EPSG%3A3857&' + - 'bbox=1989139.6,3522745.0,2015014.9,3537004.5&' + - 'query_layers=landsat&X=250&Y=250', - 'wms_getfeatureinfo_raster_json', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&layers=landsat&styles=&" + + "info_format=application%2Fjson&transparent=true&" + + "width=500&height=500&srs=EPSG%3A3857&" + + "bbox=1989139.6,3522745.0,2015014.9,3537004.5&" + + "query_layers=landsat&X=250&Y=250", + "wms_getfeatureinfo_raster_json", + normalizeJson=True, + ) # simple test with geometry with underlying layer in 4326 and CRS is EPSG:4326 - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&styles=&' + - 'info_format=application%2Fjson&transparent=true&' + - 'width=600&height=400&srs=EPSG:4326&' + - 'bbox=44.9014173,8.2034387,44.9015094,8.2036094&' + - 'query_layers=testlayer2&X=203&Y=116&' + - 'with_geometry=true', - 'wms_getfeatureinfo_geometry_CRS84_json', - 'test_project.qgs', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&styles=&" + + "info_format=application%2Fjson&transparent=true&" + + "width=600&height=400&srs=EPSG:4326&" + + "bbox=44.9014173,8.2034387,44.9015094,8.2036094&" + + "query_layers=testlayer2&X=203&Y=116&" + + "with_geometry=true", + "wms_getfeatureinfo_geometry_CRS84_json", + "test_project.qgs", + normalizeJson=True, + ) # simple test with geometry with underlying layer in 4326 and CRS is CRS84 - self.wms_request_compare('GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&styles=&' + - 'info_format=application%2Fjson&transparent=true&' + - 'width=600&height=400&srs=OGC:CRS84&' + - 'bbox=8.2034387,44.9014173,8.2036094,44.9015094&' + - 'query_layers=testlayer2&X=203&Y=116&' + - 'with_geometry=true', - 'wms_getfeatureinfo_geometry_CRS84_json', - 'test_project.qgs', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&styles=&" + + "info_format=application%2Fjson&transparent=true&" + + "width=600&height=400&srs=OGC:CRS84&" + + "bbox=8.2034387,44.9014173,8.2036094,44.9015094&" + + "query_layers=testlayer2&X=203&Y=116&" + + "with_geometry=true", + "wms_getfeatureinfo_geometry_CRS84_json", + "test_project.qgs", + normalizeJson=True, + ) def testGetFeatureInfoGroupedLayers(self): """Test that we can get feature info from the top and group layers""" # areas+and+symbols (not nested) - self.wms_request_compare('GetFeatureInfo', - '&BBOX=52.44095517977704901,10.71171069440170776,52.440955186258563,10.71171070552261817' + - '&CRS=EPSG:4326' + - '&WIDTH=2&HEIGHT=2' + - '&QUERY_LAYERS=areas+and+symbols' + - '&INFO_FORMAT=application/json' + - '&I=0&J=1' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_group_name_areas', - 'test_project_wms_grouped_layers.qgs', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=52.44095517977704901,10.71171069440170776,52.440955186258563,10.71171070552261817" + + "&CRS=EPSG:4326" + + "&WIDTH=2&HEIGHT=2" + + "&QUERY_LAYERS=areas+and+symbols" + + "&INFO_FORMAT=application/json" + + "&I=0&J=1" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_group_name_areas", + "test_project_wms_grouped_layers.qgs", + normalizeJson=True, + ) # areas+and+symbols (nested) - self.wms_request_compare('GetFeatureInfo', - '&BBOX=52.44095517977704901,10.71171069440170776,52.440955186258563,10.71171070552261817' + - '&CRS=EPSG:4326' + - '&WIDTH=2&HEIGHT=2' + - '&QUERY_LAYERS=areas+and+symbols' + - '&INFO_FORMAT=application/json' + - '&I=0&J=1' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_group_name_areas_nested', - 'test_project_wms_grouped_nested_layers.qgs', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=52.44095517977704901,10.71171069440170776,52.440955186258563,10.71171070552261817" + + "&CRS=EPSG:4326" + + "&WIDTH=2&HEIGHT=2" + + "&QUERY_LAYERS=areas+and+symbols" + + "&INFO_FORMAT=application/json" + + "&I=0&J=1" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_group_name_areas_nested", + "test_project_wms_grouped_nested_layers.qgs", + normalizeJson=True, + ) # as-areas-short-name - self.wms_request_compare('GetFeatureInfo', - '&BBOX=52.44095517977704901,10.71171069440170776,52.440955186258563,10.71171070552261817' + - '&CRS=EPSG:4326' + - '&WIDTH=2&HEIGHT=2' + - '&QUERY_LAYERS=as-areas-short-name' + - '&INFO_FORMAT=application/json' + - '&I=0&J=1' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_group_name_areas_nested', - 'test_project_wms_grouped_nested_layers.qgs', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=52.44095517977704901,10.71171069440170776,52.440955186258563,10.71171070552261817" + + "&CRS=EPSG:4326" + + "&WIDTH=2&HEIGHT=2" + + "&QUERY_LAYERS=as-areas-short-name" + + "&INFO_FORMAT=application/json" + + "&I=0&J=1" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_group_name_areas_nested", + "test_project_wms_grouped_nested_layers.qgs", + normalizeJson=True, + ) # Top level: QGIS Server - Grouped Layer - self.wms_request_compare('GetFeatureInfo', - '&BBOX=52.44095517977704901,10.71171069440170776,52.440955186258563,10.71171070552261817' + - '&CRS=EPSG:4326' + - '&WIDTH=2&HEIGHT=2' + - '&QUERY_LAYERS=QGIS+Server+-+Grouped Nested Layer' + - '&INFO_FORMAT=application/json' + - '&I=0&J=1' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_group_name_top', - 'test_project_wms_grouped_nested_layers.qgs', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=52.44095517977704901,10.71171069440170776,52.440955186258563,10.71171070552261817" + + "&CRS=EPSG:4326" + + "&WIDTH=2&HEIGHT=2" + + "&QUERY_LAYERS=QGIS+Server+-+Grouped Nested Layer" + + "&INFO_FORMAT=application/json" + + "&I=0&J=1" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_group_name_top", + "test_project_wms_grouped_nested_layers.qgs", + normalizeJson=True, + ) # Multiple matches from 2 layer groups - self.wms_request_compare('GetFeatureInfo', - '&BBOX=52.44095517977704901,10.71171069440170776,52.440955186258563,10.71171070552261817' + - '&CRS=EPSG:4326' + - '&WIDTH=2&HEIGHT=2' + - '&QUERY_LAYERS=areas+and+symbols,city+and+district+boundaries' + - '&INFO_FORMAT=application/json' + - '&I=0&J=1' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_group_name_areas_cities', - 'test_project_wms_grouped_nested_layers.qgs', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=52.44095517977704901,10.71171069440170776,52.440955186258563,10.71171070552261817" + + "&CRS=EPSG:4326" + + "&WIDTH=2&HEIGHT=2" + + "&QUERY_LAYERS=areas+and+symbols,city+and+district+boundaries" + + "&INFO_FORMAT=application/json" + + "&I=0&J=1" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_group_name_areas_cities", + "test_project_wms_grouped_nested_layers.qgs", + normalizeJson=True, + ) # no_query group (nested) - self.wms_request_compare('GetFeatureInfo', - '&BBOX=52.44095517977704901,10.71171069440170776,52.440955186258563,10.71171070552261817' + - '&CRS=EPSG:4326' + - '&WIDTH=2&HEIGHT=2' + - '&QUERY_LAYERS=no_query' + - '&INFO_FORMAT=application/json' + - '&I=0&J=1' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_group_no_query', - 'test_project_wms_grouped_nested_layers.qgs', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=52.44095517977704901,10.71171069440170776,52.440955186258563,10.71171070552261817" + + "&CRS=EPSG:4326" + + "&WIDTH=2&HEIGHT=2" + + "&QUERY_LAYERS=no_query" + + "&INFO_FORMAT=application/json" + + "&I=0&J=1" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_group_no_query", + "test_project_wms_grouped_nested_layers.qgs", + normalizeJson=True, + ) # query_child group (nested) - self.wms_request_compare('GetFeatureInfo', - '&BBOX=52.44095517977704901,10.71171069440170776,52.440955186258563,10.71171070552261817' + - '&CRS=EPSG:4326' + - '&WIDTH=2&HEIGHT=2' + - '&QUERY_LAYERS=query_child' + - '&INFO_FORMAT=application/json' + - '&I=0&J=1' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_group_query_child', - 'test_project_wms_grouped_nested_layers.qgs', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=52.44095517977704901,10.71171069440170776,52.440955186258563,10.71171070552261817" + + "&CRS=EPSG:4326" + + "&WIDTH=2&HEIGHT=2" + + "&QUERY_LAYERS=query_child" + + "&INFO_FORMAT=application/json" + + "&I=0&J=1" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_group_query_child", + "test_project_wms_grouped_nested_layers.qgs", + normalizeJson=True, + ) # child_ok group (nested) - self.wms_request_compare('GetFeatureInfo', - '&BBOX=52.44095517977704901,10.71171069440170776,52.440955186258563,10.71171070552261817' + - '&CRS=EPSG:4326' + - '&WIDTH=2&HEIGHT=2' + - '&QUERY_LAYERS=child_ok' + - '&INFO_FORMAT=application/json' + - '&I=0&J=1' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_group_query_child', - 'test_project_wms_grouped_nested_layers.qgs', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=52.44095517977704901,10.71171069440170776,52.440955186258563,10.71171070552261817" + + "&CRS=EPSG:4326" + + "&WIDTH=2&HEIGHT=2" + + "&QUERY_LAYERS=child_ok" + + "&INFO_FORMAT=application/json" + + "&I=0&J=1" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_group_query_child", + "test_project_wms_grouped_nested_layers.qgs", + normalizeJson=True, + ) # as_areas_query_copy == as-areas-short-name-query-copy (nested) - self.wms_request_compare('GetFeatureInfo', - '&BBOX=52.44095517977704901,10.71171069440170776,52.440955186258563,10.71171070552261817' + - '&CRS=EPSG:4326' + - '&WIDTH=2&HEIGHT=2' + - '&QUERY_LAYERS=as-areas-short-name-query-copy' + - '&INFO_FORMAT=application/json' + - '&I=0&J=1' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_group_query_child', - 'test_project_wms_grouped_nested_layers.qgs', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=52.44095517977704901,10.71171069440170776,52.440955186258563,10.71171070552261817" + + "&CRS=EPSG:4326" + + "&WIDTH=2&HEIGHT=2" + + "&QUERY_LAYERS=as-areas-short-name-query-copy" + + "&INFO_FORMAT=application/json" + + "&I=0&J=1" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_group_query_child", + "test_project_wms_grouped_nested_layers.qgs", + normalizeJson=True, + ) def testGetFeatureInfoNoQueriable(self): """Test GetFeatureInfo for all layers when there is a single not queryable, @@ -779,281 +910,329 @@ def testGetFeatureInfoNoQueriable(self): """ project = QgsProject() - project.setTitle('wmsproject') + project.setTitle("wmsproject") fields = QgsFields() - fields.append(QgsField('fid', QVariant.Int)) + fields.append(QgsField("fid", QVariant.Int)) vl1 = QgsMemoryProviderUtils.createMemoryLayer( - 'vl1', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:4326')) + "vl1", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:4326"), + ) f1 = QgsFeature(vl1.fields()) - f1['fid'] = 1 - f1.setGeometry(QgsGeometry.fromWkt('Point(9 45)')) + f1["fid"] = 1 + f1.setGeometry(QgsGeometry.fromWkt("Point(9 45)")) f2 = QgsFeature(vl1.fields()) - f2['fid'] = 1 - f2.setGeometry(QgsGeometry.fromWkt('Point(10 46)')) + f2["fid"] = 1 + f2.setGeometry(QgsGeometry.fromWkt("Point(10 46)")) vl1.dataProvider().addFeatures([f1, f2]) vl2 = QgsMemoryProviderUtils.createMemoryLayer( - 'vl2', fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem('EPSG:4326')) + "vl2", + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem("EPSG:4326"), + ) vl2.dataProvider().addFeatures([f1, f2]) project.addMapLayers([vl1, vl2]) req_params = { - 'SERVICE': 'WMS', - 'REQUEST': 'GetFeatureInfo', - 'VERSION': '1.3.0', - 'LAYERS': '', - 'STYLES': '', - 'INFO_FORMAT': r'application%2Fjson', - 'WIDTH': '10', - 'HEIGHT': '10', - 'SRS': r'EPSG%3A4326', - 'BBOX': '45,9,46,10', - 'CRS': 'EPSG:4326', - 'FEATURE_COUNT': '2', - 'QUERY_LAYERS': 'wmsproject', - 'I': '0', - 'J': '10', - 'FILTER': '', - 'FI_POINT_TOLERANCE': '2' + "SERVICE": "WMS", + "REQUEST": "GetFeatureInfo", + "VERSION": "1.3.0", + "LAYERS": "", + "STYLES": "", + "INFO_FORMAT": r"application%2Fjson", + "WIDTH": "10", + "HEIGHT": "10", + "SRS": r"EPSG%3A4326", + "BBOX": "45,9,46,10", + "CRS": "EPSG:4326", + "FEATURE_COUNT": "2", + "QUERY_LAYERS": "wmsproject", + "I": "0", + "J": "10", + "FILTER": "", + "FI_POINT_TOLERANCE": "2", } - req = QgsBufferServerRequest('?' + '&'.join([f"{k}={v}" for k, v in req_params.items()])) + req = QgsBufferServerRequest( + "?" + "&".join([f"{k}={v}" for k, v in req_params.items()]) + ) res = QgsBufferServerResponse() self.server.handleRequest(req, res, project) j_body = json.loads(bytes(res.body()).decode()) - self.assertEqual(len(j_body['features']), 2) + self.assertEqual(len(j_body["features"]), 2) - vl1.setFlags(vl1.flags() & ~ QgsMapLayer.LayerFlag.Identifiable) + vl1.setFlags(vl1.flags() & ~QgsMapLayer.LayerFlag.Identifiable) - req = QgsBufferServerRequest('?' + '&'.join([f"{k}={v}" for k, v in req_params.items()])) + req = QgsBufferServerRequest( + "?" + "&".join([f"{k}={v}" for k, v in req_params.items()]) + ) res = QgsBufferServerResponse() self.server.handleRequest(req, res, project) j_body = json.loads(bytes(res.body()).decode()) - self.assertEqual(len(j_body['features']), 1) + self.assertEqual(len(j_body["features"]), 1) - req_params['LAYERS'] = 'vl1,vl2' - req = QgsBufferServerRequest('?' + '&'.join([f"{k}={v}" for k, v in req_params.items()])) + req_params["LAYERS"] = "vl1,vl2" + req = QgsBufferServerRequest( + "?" + "&".join([f"{k}={v}" for k, v in req_params.items()]) + ) res = QgsBufferServerResponse() self.server.handleRequest(req, res, project) j_body = json.loads(bytes(res.body()).decode()) - self.assertEqual(len(j_body['features']), 1) + self.assertEqual(len(j_body["features"]), 1) - req_params['LAYERS'] = 'wmsproject' - req_params['QUERY_LAYERS'] = 'vl2' - req = QgsBufferServerRequest('?' + '&'.join([f"{k}={v}" for k, v in req_params.items()])) + req_params["LAYERS"] = "wmsproject" + req_params["QUERY_LAYERS"] = "vl2" + req = QgsBufferServerRequest( + "?" + "&".join([f"{k}={v}" for k, v in req_params.items()]) + ) res = QgsBufferServerResponse() self.server.handleRequest(req, res, project) j_body = json.loads(bytes(res.body()).decode()) - self.assertEqual(len(j_body['features']), 1) + self.assertEqual(len(j_body["features"]), 1) - req_params['LAYERS'] = 'vl2' - req_params['QUERY_LAYERS'] = 'wmsproject' - req = QgsBufferServerRequest('?' + '&'.join([f"{k}={v}" for k, v in req_params.items()])) + req_params["LAYERS"] = "vl2" + req_params["QUERY_LAYERS"] = "wmsproject" + req = QgsBufferServerRequest( + "?" + "&".join([f"{k}={v}" for k, v in req_params.items()]) + ) res = QgsBufferServerResponse() self.server.handleRequest(req, res, project) j_body = json.loads(bytes(res.body()).decode()) - self.assertEqual(len(j_body['features']), 1) + self.assertEqual(len(j_body["features"]), 1) def testGetFeatureInfoJsonUseIdAsLayerName(self): """Test GH #36262 where json response + use layer id""" - self.wms_request_compare('GetFeatureInfo', - '&BBOX=44.90139177500000045,8.20335906129666981,44.90148522499999473,8.20364693870333284' + - '&CRS=EPSG:4326' + - '&WIDTH=1568&HEIGHT=509' + - '&LAYERS=testlayer_%C3%A8%C3%A9_cf86cf11_222f_4b62_929c_12cfc82b9774' + - '&STYLES=' + - '&FORMAT=image/jpeg' + - '&QUERY_LAYERS=testlayer_%C3%A8%C3%A9_cf86cf11_222f_4b62_929c_12cfc82b9774' + - '&INFO_FORMAT=application/json' + - '&I=1022&J=269' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_json_layer_ids', - 'test_project_use_layer_ids.qgs', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=44.90139177500000045,8.20335906129666981,44.90148522499999473,8.20364693870333284" + + "&CRS=EPSG:4326" + + "&WIDTH=1568&HEIGHT=509" + + "&LAYERS=testlayer_%C3%A8%C3%A9_cf86cf11_222f_4b62_929c_12cfc82b9774" + + "&STYLES=" + + "&FORMAT=image/jpeg" + + "&QUERY_LAYERS=testlayer_%C3%A8%C3%A9_cf86cf11_222f_4b62_929c_12cfc82b9774" + + "&INFO_FORMAT=application/json" + + "&I=1022&J=269" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_json_layer_ids", + "test_project_use_layer_ids.qgs", + normalizeJson=True, + ) # Raster - self.wms_request_compare('GetFeatureInfo', - '&BBOX=30.1492201749999964,17.81444988978388722,30.2599248249999988,18.15548111021611533' + - '&CRS=EPSG:4326' + - '&WIDTH=1568&HEIGHT=509' + - '&LAYERS=landsat_a7d15b35_ca83_4b23_a9fb_af3fbdd60d15' + - '&STYLES=' + - '&FORMAT=image/jpeg' + - '&QUERY_LAYERS=landsat_a7d15b35_ca83_4b23_a9fb_af3fbdd60d15' + - '&INFO_FORMAT=application/json' + - '&I=769&J=275&FEATURE_COUNT=10', - 'wms_getfeatureinfo_json_layer_ids_raster', - 'test_project_use_layer_ids.qgs', - normalizeJson=True) - - @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'), - "This test cannot run in TRAVIS because it relies on cascading external services") + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=30.1492201749999964,17.81444988978388722,30.2599248249999988,18.15548111021611533" + + "&CRS=EPSG:4326" + + "&WIDTH=1568&HEIGHT=509" + + "&LAYERS=landsat_a7d15b35_ca83_4b23_a9fb_af3fbdd60d15" + + "&STYLES=" + + "&FORMAT=image/jpeg" + + "&QUERY_LAYERS=landsat_a7d15b35_ca83_4b23_a9fb_af3fbdd60d15" + + "&INFO_FORMAT=application/json" + + "&I=769&J=275&FEATURE_COUNT=10", + "wms_getfeatureinfo_json_layer_ids_raster", + "test_project_use_layer_ids.qgs", + normalizeJson=True, + ) + + @unittest.skipIf( + os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), + "This test cannot run in TRAVIS because it relies on cascading external services", + ) def testGetFeatureInfoCascadingLayers(self): """Test that we can get feature info on cascading WMS layers""" - project_name = 'bug_gh31177_gfi_cascading_wms.qgs' - self.wms_request_compare('GetFeatureInfo', - '&BBOX=852729.31,5631138.51,853012.18,5631346.17' + - '&CRS=EPSG:3857' + - '&WIDTH=850&HEIGHT=624' + - '&QUERY_LAYERS=Alberate' + - '&INFO_FORMAT=application/vnd.ogc.gml' + - '&I=509&J=289' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_cascading_issue31177', - project_name) + project_name = "bug_gh31177_gfi_cascading_wms.qgs" + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=852729.31,5631138.51,853012.18,5631346.17" + + "&CRS=EPSG:3857" + + "&WIDTH=850&HEIGHT=624" + + "&QUERY_LAYERS=Alberate" + + "&INFO_FORMAT=application/vnd.ogc.gml" + + "&I=509&J=289" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_cascading_issue31177", + project_name, + ) def testGetFeatureInfoRasterNoData(self): # outside the image in text - self.wms_request_compare('GetFeatureInfo', - '&BBOX=-39.43236293126383885,135.95002698514588246,-30.54405018572365194,156.29582900705395332' + - '&CRS=EPSG:4326' + - '&VERSION=1.3.0' + - '&WIDTH=800&HEIGHT=400' + - '&LAYERS=requires_warped_vrt' + - '&QUERY_LAYERS=requires_warped_vrt' + - '&I=1&J=1' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_raster_nodata_out_txt', - 'test_raster_nodata.qgz', - raw=True) + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=-39.43236293126383885,135.95002698514588246,-30.54405018572365194,156.29582900705395332" + + "&CRS=EPSG:4326" + + "&VERSION=1.3.0" + + "&WIDTH=800&HEIGHT=400" + + "&LAYERS=requires_warped_vrt" + + "&QUERY_LAYERS=requires_warped_vrt" + + "&I=1&J=1" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_raster_nodata_out_txt", + "test_raster_nodata.qgz", + raw=True, + ) # 0 text - self.wms_request_compare('GetFeatureInfo', - '&BBOX=-39.43236293126383885,135.95002698514588246,-30.54405018572365194,156.29582900705395332' + - '&CRS=EPSG:4326' + - '&VERSION=1.3.0' + - '&WIDTH=800&HEIGHT=400' + - '&LAYERS=requires_warped_vrt' + - '&QUERY_LAYERS=requires_warped_vrt' + - '&I=576&J=163' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_raster_nodata_zero_txt', - 'test_raster_nodata.qgz', - raw=True) + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=-39.43236293126383885,135.95002698514588246,-30.54405018572365194,156.29582900705395332" + + "&CRS=EPSG:4326" + + "&VERSION=1.3.0" + + "&WIDTH=800&HEIGHT=400" + + "&LAYERS=requires_warped_vrt" + + "&QUERY_LAYERS=requires_warped_vrt" + + "&I=576&J=163" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_raster_nodata_zero_txt", + "test_raster_nodata.qgz", + raw=True, + ) # nodata text - self.wms_request_compare('GetFeatureInfo', - '&BBOX=-39.43236293126383885,135.95002698514588246,-30.54405018572365194,156.29582900705395332' + - '&CRS=EPSG:4326' + - '&VERSION=1.3.0' + - '&WIDTH=800&HEIGHT=400' + - '&LAYERS=requires_warped_vrt' + - '&QUERY_LAYERS=requires_warped_vrt' + - '&I=560&J=78' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_raster_nodata_txt', - 'test_raster_nodata.qgz', - raw=True) + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=-39.43236293126383885,135.95002698514588246,-30.54405018572365194,156.29582900705395332" + + "&CRS=EPSG:4326" + + "&VERSION=1.3.0" + + "&WIDTH=800&HEIGHT=400" + + "&LAYERS=requires_warped_vrt" + + "&QUERY_LAYERS=requires_warped_vrt" + + "&I=560&J=78" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_raster_nodata_txt", + "test_raster_nodata.qgz", + raw=True, + ) # outside the image in html - self.wms_request_compare('GetFeatureInfo', - '&BBOX=-39.43236293126383885,135.95002698514588246,-30.54405018572365194,156.29582900705395332' + - '&CRS=EPSG:4326' + - '&VERSION=1.3.0' + - '&INFO_FORMAT=text/html' + - '&WIDTH=800&HEIGHT=400' + - '&LAYERS=requires_warped_vrt' + - '&QUERY_LAYERS=requires_warped_vrt' + - '&I=1&J=1' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_raster_nodata_out_html', - 'test_raster_nodata.qgz', - raw=True) + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=-39.43236293126383885,135.95002698514588246,-30.54405018572365194,156.29582900705395332" + + "&CRS=EPSG:4326" + + "&VERSION=1.3.0" + + "&INFO_FORMAT=text/html" + + "&WIDTH=800&HEIGHT=400" + + "&LAYERS=requires_warped_vrt" + + "&QUERY_LAYERS=requires_warped_vrt" + + "&I=1&J=1" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_raster_nodata_out_html", + "test_raster_nodata.qgz", + raw=True, + ) # 0 html - self.wms_request_compare('GetFeatureInfo', - '&BBOX=-39.43236293126383885,135.95002698514588246,-30.54405018572365194,156.29582900705395332' + - '&CRS=EPSG:4326' + - '&VERSION=1.3.0' + - '&INFO_FORMAT=text/html' + - '&WIDTH=800&HEIGHT=400' + - '&LAYERS=requires_warped_vrt' + - '&QUERY_LAYERS=requires_warped_vrt' + - '&I=576&J=163' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_raster_nodata_zero_html', - 'test_raster_nodata.qgz', - raw=True) + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=-39.43236293126383885,135.95002698514588246,-30.54405018572365194,156.29582900705395332" + + "&CRS=EPSG:4326" + + "&VERSION=1.3.0" + + "&INFO_FORMAT=text/html" + + "&WIDTH=800&HEIGHT=400" + + "&LAYERS=requires_warped_vrt" + + "&QUERY_LAYERS=requires_warped_vrt" + + "&I=576&J=163" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_raster_nodata_zero_html", + "test_raster_nodata.qgz", + raw=True, + ) # nodata html - self.wms_request_compare('GetFeatureInfo', - '&BBOX=-39.43236293126383885,135.95002698514588246,-30.54405018572365194,156.29582900705395332' + - '&CRS=EPSG:4326' + - '&VERSION=1.3.0' + - '&INFO_FORMAT=text/html' + - '&WIDTH=800&HEIGHT=400' + - '&LAYERS=requires_warped_vrt' + - '&QUERY_LAYERS=requires_warped_vrt' + - '&I=560&J=78' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_raster_nodata_html', - 'test_raster_nodata.qgz', - raw=True) + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=-39.43236293126383885,135.95002698514588246,-30.54405018572365194,156.29582900705395332" + + "&CRS=EPSG:4326" + + "&VERSION=1.3.0" + + "&INFO_FORMAT=text/html" + + "&WIDTH=800&HEIGHT=400" + + "&LAYERS=requires_warped_vrt" + + "&QUERY_LAYERS=requires_warped_vrt" + + "&I=560&J=78" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_raster_nodata_html", + "test_raster_nodata.qgz", + raw=True, + ) # outside the image in json - self.wms_request_compare('GetFeatureInfo', - '&BBOX=-39.43236293126383885,135.95002698514588246,-30.54405018572365194,156.29582900705395332' + - '&CRS=EPSG:4326' + - '&VERSION=1.3.0' + - '&INFO_FORMAT=application/json' + - '&WIDTH=800&HEIGHT=400' + - '&LAYERS=requires_warped_vrt' + - '&QUERY_LAYERS=requires_warped_vrt' + - '&I=1&J=1' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_raster_nodata_out_json', - 'test_raster_nodata.qgz', - raw=True) + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=-39.43236293126383885,135.95002698514588246,-30.54405018572365194,156.29582900705395332" + + "&CRS=EPSG:4326" + + "&VERSION=1.3.0" + + "&INFO_FORMAT=application/json" + + "&WIDTH=800&HEIGHT=400" + + "&LAYERS=requires_warped_vrt" + + "&QUERY_LAYERS=requires_warped_vrt" + + "&I=1&J=1" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_raster_nodata_out_json", + "test_raster_nodata.qgz", + raw=True, + ) # 0 json - self.wms_request_compare('GetFeatureInfo', - '&BBOX=-39.43236293126383885,135.95002698514588246,-30.54405018572365194,156.29582900705395332' + - '&CRS=EPSG:4326' + - '&VERSION=1.3.0' + - '&INFO_FORMAT=application/json' + - '&WIDTH=800&HEIGHT=400' + - '&LAYERS=requires_warped_vrt' + - '&QUERY_LAYERS=requires_warped_vrt' + - '&I=576&J=163' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_raster_nodata_zero_json', - 'test_raster_nodata.qgz', - raw=True) + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=-39.43236293126383885,135.95002698514588246,-30.54405018572365194,156.29582900705395332" + + "&CRS=EPSG:4326" + + "&VERSION=1.3.0" + + "&INFO_FORMAT=application/json" + + "&WIDTH=800&HEIGHT=400" + + "&LAYERS=requires_warped_vrt" + + "&QUERY_LAYERS=requires_warped_vrt" + + "&I=576&J=163" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_raster_nodata_zero_json", + "test_raster_nodata.qgz", + raw=True, + ) # nodata json - self.wms_request_compare('GetFeatureInfo', - '&BBOX=-39.43236293126383885,135.95002698514588246,-30.54405018572365194,156.29582900705395332' + - '&CRS=EPSG:4326' + - '&VERSION=1.3.0' + - '&INFO_FORMAT=application/json' + - '&WIDTH=800&HEIGHT=400' + - '&LAYERS=requires_warped_vrt' + - '&QUERY_LAYERS=requires_warped_vrt' + - '&I=560&J=78' + - '&FEATURE_COUNT=10', - 'wms_getfeatureinfo_raster_nodata_json', - 'test_raster_nodata.qgz', - raw=True) + self.wms_request_compare( + "GetFeatureInfo", + "&BBOX=-39.43236293126383885,135.95002698514588246,-30.54405018572365194,156.29582900705395332" + + "&CRS=EPSG:4326" + + "&VERSION=1.3.0" + + "&INFO_FORMAT=application/json" + + "&WIDTH=800&HEIGHT=400" + + "&LAYERS=requires_warped_vrt" + + "&QUERY_LAYERS=requires_warped_vrt" + + "&I=560&J=78" + + "&FEATURE_COUNT=10", + "wms_getfeatureinfo_raster_nodata_json", + "test_raster_nodata.qgz", + raw=True, + ) def test_wrong_filter_throws(self): """Test that a wrong FILTER expression throws an InvalidParameterValue exception""" _, response_body, _ = self.wms_request( - 'GetFeatureInfo', - '&layers=testlayer%20%C3%A8%C3%A9&' + - 'INFO_FORMAT=text%2Fxml&' + - 'width=600&height=400&srs=EPSG%3A3857&' + - 'query_layers=testlayer%20%C3%A8%C3%A9&' + - 'FEATURE_COUNT=10&FILTER=testlayer%20%C3%A8%C3%A9' + - urllib.parse.quote(':"XXXXXXXXXNAMEXXXXXXX" = \'two\'')) - - self.assertEqual(response_body.decode('utf8'), '\n\n Filter not valid for layer testlayer èé: check the filter syntax and the field names.\n\n') + "GetFeatureInfo", + "&layers=testlayer%20%C3%A8%C3%A9&" + + "INFO_FORMAT=text%2Fxml&" + + "width=600&height=400&srs=EPSG%3A3857&" + + "query_layers=testlayer%20%C3%A8%C3%A9&" + + "FEATURE_COUNT=10&FILTER=testlayer%20%C3%A8%C3%A9" + + urllib.parse.quote(":\"XXXXXXXXXNAMEXXXXXXX\" = 'two'"), + ) + + self.assertEqual( + response_body.decode("utf8"), + '\n\n Filter not valid for layer testlayer èé: check the filter syntax and the field names.\n\n', + ) def testGetFeatureInfoFilterAllowedExtraTokens(self): """Test GetFeatureInfo with forbidden and extra tokens @@ -1064,98 +1243,120 @@ def testGetFeatureInfoFilterAllowedExtraTokens(self): self.assertTrue(project.read(project_path)) req_params = { - 'SERVICE': 'WMS', - 'REQUEST': 'GetFeatureInfo', - 'VERSION': '1.3.0', - 'LAYERS': 'layer4', - 'STYLES': '', - 'INFO_FORMAT': r'application%2Fjson', - 'WIDTH': '926', - 'HEIGHT': '787', - 'SRS': r'EPSG%3A4326', - 'BBOX': '912217,5605059,914099,5606652', - 'CRS': 'EPSG:3857', - 'FEATURE_COUNT': '10', - 'QUERY_LAYERS': 'layer4', - 'FILTER': 'layer4:"utf8nameè" != \'\'', + "SERVICE": "WMS", + "REQUEST": "GetFeatureInfo", + "VERSION": "1.3.0", + "LAYERS": "layer4", + "STYLES": "", + "INFO_FORMAT": r"application%2Fjson", + "WIDTH": "926", + "HEIGHT": "787", + "SRS": r"EPSG%3A4326", + "BBOX": "912217,5605059,914099,5606652", + "CRS": "EPSG:3857", + "FEATURE_COUNT": "10", + "QUERY_LAYERS": "layer4", + "FILTER": "layer4:\"utf8nameè\" != ''", } - req = QgsBufferServerRequest('?' + '&'.join([f"{k}={v}" for k, v in req_params.items()])) + req = QgsBufferServerRequest( + "?" + "&".join([f"{k}={v}" for k, v in req_params.items()]) + ) res = QgsBufferServerResponse() self.server.handleRequest(req, res, project) j_body = json.loads(bytes(res.body()).decode()) - self.assertEqual(len(j_body['features']), 3) + self.assertEqual(len(j_body["features"]), 3) - req_params['FILTER'] = 'layer4:"utf8nameè" = \'three èé↓\'' - req = QgsBufferServerRequest('?' + '&'.join([f"{k}={v}" for k, v in req_params.items()])) + req_params["FILTER"] = "layer4:\"utf8nameè\" = 'three èé↓'" + req = QgsBufferServerRequest( + "?" + "&".join([f"{k}={v}" for k, v in req_params.items()]) + ) res = QgsBufferServerResponse() self.server.handleRequest(req, res, project) j_body = json.loads(bytes(res.body()).decode()) - self.assertEqual(len(j_body['features']), 1) + self.assertEqual(len(j_body["features"]), 1) - req_params['FILTER'] = 'layer4:"utf8nameè" != \'three èé↓\'' - req = QgsBufferServerRequest('?' + '&'.join([f"{k}={v}" for k, v in req_params.items()])) + req_params["FILTER"] = "layer4:\"utf8nameè\" != 'three èé↓'" + req = QgsBufferServerRequest( + "?" + "&".join([f"{k}={v}" for k, v in req_params.items()]) + ) res = QgsBufferServerResponse() self.server.handleRequest(req, res, project) j_body = json.loads(bytes(res.body()).decode()) - self.assertEqual(len(j_body['features']), 2) + self.assertEqual(len(j_body["features"]), 2) # REPLACE filter - req_params['FILTER'] = 'layer4:REPLACE ( "utf8nameè" , \'three\' , \'____\' ) != \'____ èé↓\'' - req = QgsBufferServerRequest('?' + '&'.join([f"{k}={v}" for k, v in req_params.items()])) + req_params["FILTER"] = ( + "layer4:REPLACE ( \"utf8nameè\" , 'three' , '____' ) != '____ èé↓'" + ) + req = QgsBufferServerRequest( + "?" + "&".join([f"{k}={v}" for k, v in req_params.items()]) + ) res = QgsBufferServerResponse() self.server.handleRequest(req, res, project) self.assertEqual(res.statusCode(), 403) - os.putenv('QGIS_SERVER_ALLOWED_EXTRA_SQL_TOKENS', 'RePlAcE') + os.putenv("QGIS_SERVER_ALLOWED_EXTRA_SQL_TOKENS", "RePlAcE") self.server.serverInterface().reloadSettings() - req = QgsBufferServerRequest('?' + '&'.join([f"{k}={v}" for k, v in req_params.items()])) + req = QgsBufferServerRequest( + "?" + "&".join([f"{k}={v}" for k, v in req_params.items()]) + ) res = QgsBufferServerResponse() self.server.handleRequest(req, res, project) j_body = json.loads(bytes(res.body()).decode()) - self.assertEqual(len(j_body['features']), 2) + self.assertEqual(len(j_body["features"]), 2) - os.putenv('QGIS_SERVER_ALLOWED_EXTRA_SQL_TOKENS', '') + os.putenv("QGIS_SERVER_ALLOWED_EXTRA_SQL_TOKENS", "") self.server.serverInterface().reloadSettings() - req_params['FILTER'] = 'layer4:REPLACE ( "utf8nameè" , \'three\' , \'____\' ) != \'____ èé↓\'' - req = QgsBufferServerRequest('?' + '&'.join([f"{k}={v}" for k, v in req_params.items()])) + req_params["FILTER"] = ( + "layer4:REPLACE ( \"utf8nameè\" , 'three' , '____' ) != '____ èé↓'" + ) + req = QgsBufferServerRequest( + "?" + "&".join([f"{k}={v}" for k, v in req_params.items()]) + ) res = QgsBufferServerResponse() self.server.handleRequest(req, res, project) self.assertEqual(res.statusCode(), 403) # Multiple filters - os.putenv('QGIS_SERVER_ALLOWED_EXTRA_SQL_TOKENS', 'RePlAcE,LowEr') + os.putenv("QGIS_SERVER_ALLOWED_EXTRA_SQL_TOKENS", "RePlAcE,LowEr") self.server.serverInterface().reloadSettings() - req_params['FILTER'] = 'layer4:LOWER ( REPLACE ( "utf8nameè" , \'three\' , \'THREE\' ) ) = \'three èé↓\'' + req_params["FILTER"] = ( + "layer4:LOWER ( REPLACE ( \"utf8nameè\" , 'three' , 'THREE' ) ) = 'three èé↓'" + ) - req = QgsBufferServerRequest('?' + '&'.join([f"{k}={v}" for k, v in req_params.items()])) + req = QgsBufferServerRequest( + "?" + "&".join([f"{k}={v}" for k, v in req_params.items()]) + ) res = QgsBufferServerResponse() self.server.handleRequest(req, res, project) j_body = json.loads(bytes(res.body()).decode()) - self.assertEqual(len(j_body['features']), 1) + self.assertEqual(len(j_body["features"]), 1) def testGetFeatureInfoSortedByDesignerWithJoinLayer(self): """Test GetFeatureInfo resolves DRAG&DROP Designer order when use attribute form settings for GetFeatureInfo with a column from a Joined Layer when the option is checked, see https://github.com/qgis/QGIS/pull/41031 """ mypath = self.testdata_path + "test_project_values.qgz" - self.wms_request_compare('GetFeatureInfo', - '&layers=layer2&styles=&' + - 'VERSION=1.3.0&' + - 'info_format=text%2Fxml&' + - 'width=926&height=787&srs=EPSG%3A4326' + - '&bbox=912217,5605059,914099,5606652' + - '&CRS=EPSG:3857' + - '&FEATURE_COUNT=10' + - '&WITH_GEOMETRY=True' + - '&QUERY_LAYERS=layer4&I=487&J=308', - 'wms_getfeatureinfo-values4-text-xml', - 'test_project_values.qgz') - - -if __name__ == '__main__': + self.wms_request_compare( + "GetFeatureInfo", + "&layers=layer2&styles=&" + + "VERSION=1.3.0&" + + "info_format=text%2Fxml&" + + "width=926&height=787&srs=EPSG%3A4326" + + "&bbox=912217,5605059,914099,5606652" + + "&CRS=EPSG:3857" + + "&FEATURE_COUNT=10" + + "&WITH_GEOMETRY=True" + + "&QUERY_LAYERS=layer4&I=487&J=308", + "wms_getfeatureinfo-values4-text-xml", + "test_project_values.qgz", + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_wms_getfeatureinfo_postgres.py b/tests/src/python/test_qgsserver_wms_getfeatureinfo_postgres.py index ce4099ac8992..264e3262d538 100644 --- a/tests/src/python/test_qgsserver_wms_getfeatureinfo_postgres.py +++ b/tests/src/python/test_qgsserver_wms_getfeatureinfo_postgres.py @@ -9,15 +9,16 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '22/01/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "22/01/2021" +__copyright__ = "Copyright 2021, The QGIS Project" import os # Needed on Qt 5 so that the serialization of XML is consistent among all # executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" import json import urllib.parse @@ -43,52 +44,70 @@ def setUpClass(cls): super().setUpClass() - if 'QGIS_PGTEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_PGTEST_DB'] + if "QGIS_PGTEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_PGTEST_DB"] else: - cls.dbconn = 'service=qgis_test dbname=qgis_test sslmode=disable ' + cls.dbconn = "service=qgis_test dbname=qgis_test sslmode=disable " # Test layer - md = QgsProviderRegistry.instance().providerMetadata('postgres') - uri = cls.dbconn + ' dbname=qgis_test sslmode=disable ' + md = QgsProviderRegistry.instance().providerMetadata("postgres") + uri = cls.dbconn + " dbname=qgis_test sslmode=disable " conn = md.createConnection(uri, {}) conn.executeSql('DROP TABLE IF EXISTS "qgis_test"."someDataLong" CASCADE') - conn.executeSql('SELECT * INTO "qgis_test"."someDataLong" FROM "qgis_test"."someData"') - conn.executeSql('ALTER TABLE "qgis_test"."someDataLong" ALTER COLUMN "pk" TYPE bigint') - conn.executeSql('ALTER TABLE "qgis_test"."someDataLong" ALTER COLUMN "pk" SET NOT NULL') - conn.executeSql('CREATE UNIQUE INDEX someDataLongIdx ON "qgis_test"."someDataLong" ("pk")') + conn.executeSql( + 'SELECT * INTO "qgis_test"."someDataLong" FROM "qgis_test"."someData"' + ) + conn.executeSql( + 'ALTER TABLE "qgis_test"."someDataLong" ALTER COLUMN "pk" TYPE bigint' + ) + conn.executeSql( + 'ALTER TABLE "qgis_test"."someDataLong" ALTER COLUMN "pk" SET NOT NULL' + ) + conn.executeSql( + 'CREATE UNIQUE INDEX someDataLongIdx ON "qgis_test"."someDataLong" ("pk")' + ) - cls.vlconn = cls.dbconn + ' sslmode=disable key=\'pk\' checkPrimaryKeyUnicity=0 srid=4326 type=POINT table="qgis_test"."someDataLong" (geom) sql=' + cls.vlconn = ( + cls.dbconn + + ' sslmode=disable key=\'pk\' checkPrimaryKeyUnicity=0 srid=4326 type=POINT table="qgis_test"."someDataLong" (geom) sql=' + ) # Create another layer with multiple PKs conn.executeSql('DROP TABLE IF EXISTS "qgis_test"."multiple_pks"') conn.executeSql( - 'CREATE TABLE "qgis_test"."multiple_pks" ( pk1 bigint not null, pk2 bigint not null, name text not null, geom geometry(POINT,4326), PRIMARY KEY ( pk1, pk2 ) )') + 'CREATE TABLE "qgis_test"."multiple_pks" ( pk1 bigint not null, pk2 bigint not null, name text not null, geom geometry(POINT,4326), PRIMARY KEY ( pk1, pk2 ) )' + ) conn.executeSql( - 'INSERT INTO "qgis_test"."multiple_pks" VALUES ( 1, 1, \'1-1\', ST_GeomFromText(\'point(7 45)\', 4326))') + "INSERT INTO \"qgis_test\".\"multiple_pks\" VALUES ( 1, 1, '1-1', ST_GeomFromText('point(7 45)', 4326))" + ) conn.executeSql( - 'INSERT INTO "qgis_test"."multiple_pks" VALUES ( 1, 2, \'1-2\', ST_GeomFromText(\'point(8 46)\', 4326))') + "INSERT INTO \"qgis_test\".\"multiple_pks\" VALUES ( 1, 2, '1-2', ST_GeomFromText('point(8 46)', 4326))" + ) - cls.vlconn_multiplepks = cls.dbconn + \ - " sslmode=disable key='pk1,pk2' estimatedmetadata=true srid=4326 type=Point checkPrimaryKeyUnicity='0' table=\"qgis_test\".\"multiple_pks\" (geom)" + cls.vlconn_multiplepks = ( + cls.dbconn + + " sslmode=disable key='pk1,pk2' estimatedmetadata=true srid=4326 type=Point checkPrimaryKeyUnicity='0' table=\"qgis_test\".\"multiple_pks\" (geom)" + ) def _baseFilterTest(self, info_format): - vl = QgsVectorLayer(self.vlconn, 'someData', 'postgres') + vl = QgsVectorLayer(self.vlconn, "someData", "postgres") self.assertTrue(vl.isValid()) # Pre-filtered - vl2 = QgsVectorLayer(self.vlconn, 'someData', 'postgres') + vl2 = QgsVectorLayer(self.vlconn, "someData", "postgres") self.assertTrue(vl2.isValid()) - [f for f in vl2.getFeatures(QgsFeatureRequest(QgsExpression('pk > 2')))] - - base_features_url = ('http://qgis/?SERVICE=WMS&REQUEST=GetFeatureInfo&' + - 'LAYERS=someData&STYLES=&' + - r'INFO_FORMAT={}&' + - 'SRS=EPSG%3A4326&' + - 'QUERY_LAYERS=someData&X=-1&Y=-1&' + - 'FEATURE_COUNT=100&' - 'FILTER=someData') + [f for f in vl2.getFeatures(QgsFeatureRequest(QgsExpression("pk > 2")))] + + base_features_url = ( + "http://qgis/?SERVICE=WMS&REQUEST=GetFeatureInfo&" + + "LAYERS=someData&STYLES=&" + + r"INFO_FORMAT={}&" + + "SRS=EPSG%3A4326&" + + "QUERY_LAYERS=someData&X=-1&Y=-1&" + + "FEATURE_COUNT=100&" + "FILTER=someData" + ) two_feature_url = base_features_url + urllib.parse.quote(':"pk" = 2') @@ -100,7 +119,7 @@ def _baseFilterTest(self, info_format): req = QgsBufferServerRequest(url) res = QgsBufferServerResponse() self.server.handleRequest(req, res, p) - reference_body = bytes(res.body()).decode('utf8') + reference_body = bytes(res.body()).decode("utf8") # Pre-filter p = QgsProject() @@ -109,234 +128,253 @@ def _baseFilterTest(self, info_format): req = QgsBufferServerRequest(url) res = QgsBufferServerResponse() self.server.handleRequest(req, res, p) - two_feature_body = bytes(res.body()).decode('utf8') + two_feature_body = bytes(res.body()).decode("utf8") self.assertEqual(reference_body, two_feature_body, info_format) def testGetFeatureInfoFilterPg(self): """Test issue GH #41124""" - self._baseFilterTest('text/plain') - self._baseFilterTest('text/html') - self._baseFilterTest('text/xml') - self._baseFilterTest('application/json') - self._baseFilterTest('application/vnd.ogc.gml') + self._baseFilterTest("text/plain") + self._baseFilterTest("text/html") + self._baseFilterTest("text/xml") + self._baseFilterTest("application/json") + self._baseFilterTest("application/vnd.ogc.gml") def testMultiplePks(self): """Test issue GH #41786""" - vl = QgsVectorLayer(self.vlconn_multiplepks, 'someData', 'postgres') + vl = QgsVectorLayer(self.vlconn_multiplepks, "someData", "postgres") self.assertTrue(vl.isValid()) p = QgsProject() p.addMapLayers([vl]) - json_features_url = ('http://qgis/?SERVICE=WMS&REQUEST=GetFeatureInfo&' + - 'LAYERS=someData&STYLES=&' + - 'INFO_FORMAT=application/json&' + - 'SRS=EPSG%3A4326&' + - 'QUERY_LAYERS=someData&X=-1&Y=-1&' + - 'FEATURE_COUNT=100&') + json_features_url = ( + "http://qgis/?SERVICE=WMS&REQUEST=GetFeatureInfo&" + + "LAYERS=someData&STYLES=&" + + "INFO_FORMAT=application/json&" + + "SRS=EPSG%3A4326&" + + "QUERY_LAYERS=someData&X=-1&Y=-1&" + + "FEATURE_COUNT=100&" + ) req = QgsBufferServerRequest(json_features_url) res = QgsBufferServerResponse() self.server.handleRequest(req, res, p) - j = json.loads(bytes(res.body()).decode('utf8')) - self.assertEqual(j, {'features': [{'geometry': None, - 'id': 'someData.1@@1', - 'properties': {'name': '1-1', 'pk1': 1, 'pk2': 1}, - 'type': 'Feature'}, - {'geometry': None, - 'id': 'someData.1@@2', - 'properties': {'name': '1-2', 'pk1': 1, 'pk2': 2}, - 'type': 'Feature'}], - 'type': 'FeatureCollection'}) + j = json.loads(bytes(res.body()).decode("utf8")) + self.assertEqual( + j, + { + "features": [ + { + "geometry": None, + "id": "someData.1@@1", + "properties": {"name": "1-1", "pk1": 1, "pk2": 1}, + "type": "Feature", + }, + { + "geometry": None, + "id": "someData.1@@2", + "properties": {"name": "1-2", "pk1": 1, "pk2": 2}, + "type": "Feature", + }, + ], + "type": "FeatureCollection", + }, + ) def testGetFeatureInfoPostgresTypes(self): # compare json list output with file - self.wms_request_compare('GetFeatureInfo', - '&layers=json' + - '&info_format=text%2Fxml' + - '&srs=EPSG%3A3857' + - '&QUERY_LAYERS=json' + - '&FILTER=json' + - urllib.parse.quote(':"pk" = 1'), - 'get_postgres_types_json_list', - 'test_project_postgres_types.qgs', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&layers=json" + + "&info_format=text%2Fxml" + + "&srs=EPSG%3A3857" + + "&QUERY_LAYERS=json" + + "&FILTER=json" + + urllib.parse.quote(':"pk" = 1'), + "get_postgres_types_json_list", + "test_project_postgres_types.qgs", + normalizeJson=True, + ) # compare dict output with file - self.wms_request_compare('GetFeatureInfo', - '&layers=json' + - '&info_format=text%2Fxml' + - '&srs=EPSG%3A3857' + - '&QUERY_LAYERS=json' + - '&FILTER=json' + - urllib.parse.quote(':"pk" = 2'), - 'get_postgres_types_json_dict', - 'test_project_postgres_types.qgs', - normalizeJson=True) + self.wms_request_compare( + "GetFeatureInfo", + "&layers=json" + + "&info_format=text%2Fxml" + + "&srs=EPSG%3A3857" + + "&QUERY_LAYERS=json" + + "&FILTER=json" + + urllib.parse.quote(':"pk" = 2'), + "get_postgres_types_json_dict", + "test_project_postgres_types.qgs", + normalizeJson=True, + ) # compare decoded json field list - response_header, response_body, query_string = self.wms_request('GetFeatureInfo', - '&layers=json' + - '&info_format=text%2Fxml' + - '&srs=EPSG%3A3857' + - '&QUERY_LAYERS=json' + - '&FILTER=json' + - urllib.parse.quote( - ':"pk" = 1'), - 'test_project_postgres_types.qgs') + response_header, response_body, query_string = self.wms_request( + "GetFeatureInfo", + "&layers=json" + + "&info_format=text%2Fxml" + + "&srs=EPSG%3A3857" + + "&QUERY_LAYERS=json" + + "&FILTER=json" + + urllib.parse.quote(':"pk" = 1'), + "test_project_postgres_types.qgs", + ) root = ET.fromstring(response_body) - for attribute in root.iter('Attribute'): - if attribute.get('name') == 'jvalue': - self.assertIsInstance(json.loads(attribute.get('value')), list) - self.assertEqual(json.loads(attribute.get('value')), [1, 2, 3]) - self.assertEqual( - json.loads( - attribute.get('value')), [ - 1.0, 2.0, 3.0]) - if attribute.get('name') == 'jbvalue': - self.assertIsInstance(json.loads(attribute.get('value')), list) - self.assertEqual(json.loads(attribute.get('value')), [4, 5, 6]) - self.assertEqual( - json.loads( - attribute.get('value')), [ - 4.0, 5.0, 6.0]) + for attribute in root.iter("Attribute"): + if attribute.get("name") == "jvalue": + self.assertIsInstance(json.loads(attribute.get("value")), list) + self.assertEqual(json.loads(attribute.get("value")), [1, 2, 3]) + self.assertEqual(json.loads(attribute.get("value")), [1.0, 2.0, 3.0]) + if attribute.get("name") == "jbvalue": + self.assertIsInstance(json.loads(attribute.get("value")), list) + self.assertEqual(json.loads(attribute.get("value")), [4, 5, 6]) + self.assertEqual(json.loads(attribute.get("value")), [4.0, 5.0, 6.0]) # compare decoded json field dict - response_header, response_body, query_string = self.wms_request('GetFeatureInfo', - '&layers=json' + - '&info_format=text%2Fxml' + - '&srs=EPSG%3A3857' + - '&QUERY_LAYERS=json' + - '&FILTER=json' + - urllib.parse.quote( - ':"pk" = 2'), - 'test_project_postgres_types.qgs') + response_header, response_body, query_string = self.wms_request( + "GetFeatureInfo", + "&layers=json" + + "&info_format=text%2Fxml" + + "&srs=EPSG%3A3857" + + "&QUERY_LAYERS=json" + + "&FILTER=json" + + urllib.parse.quote(':"pk" = 2'), + "test_project_postgres_types.qgs", + ) root = ET.fromstring(response_body) - for attribute in root.iter('Attribute'): - if attribute.get('name') == 'jvalue': - self.assertIsInstance(json.loads(attribute.get('value')), dict) - self.assertEqual( - json.loads( - attribute.get('value')), { - 'a': 1, 'b': 2}) - self.assertEqual( - json.loads( - attribute.get('value')), { - 'a': 1.0, 'b': 2.0}) - if attribute.get('name') == 'jbvalue': - self.assertIsInstance(json.loads(attribute.get('value')), dict) + for attribute in root.iter("Attribute"): + if attribute.get("name") == "jvalue": + self.assertIsInstance(json.loads(attribute.get("value")), dict) + self.assertEqual(json.loads(attribute.get("value")), {"a": 1, "b": 2}) self.assertEqual( - json.loads( - attribute.get('value')), { - 'c': 4, 'd': 5}) + json.loads(attribute.get("value")), {"a": 1.0, "b": 2.0} + ) + if attribute.get("name") == "jbvalue": + self.assertIsInstance(json.loads(attribute.get("value")), dict) + self.assertEqual(json.loads(attribute.get("value")), {"c": 4, "d": 5}) self.assertEqual( - json.loads( - attribute.get('value')), { - 'c': 4.0, 'd': 5.0}) + json.loads(attribute.get("value")), {"c": 4.0, "d": 5.0} + ) def testGetFeatureInfoTolerance(self): - self.wms_request_compare('GetFeatureInfo', - '&layers=layer3&styles=&' + - 'VERSION=1.3.0&' + - 'info_format=text%2Fxml&' + - 'width=400&height=200' + - '&bbox=913119.2,5605988.9,913316.0,5606047.4' + - '&CRS=EPSG:3857' + - '&FEATURE_COUNT=10' + - '&WITH_GEOMETRY=False' + - '&QUERY_LAYERS=layer3&I=193&J=100' + - '&FI_POINT_TOLERANCE=0', - 'wms_getfeatureinfo_point_tolerance_0_text_xml', - 'test_project_values_postgres.qgz') - - self.wms_request_compare('GetFeatureInfo', - '&layers=layer3&styles=&' + - 'VERSION=1.3.0&' + - 'info_format=text%2Fxml&' + - 'width=400&height=200' + - '&bbox=913119.2,5605988.9,913316.0,5606047.4' + - '&CRS=EPSG:3857' + - '&FEATURE_COUNT=10' + - '&WITH_GEOMETRY=False' + - '&QUERY_LAYERS=layer3&I=193&J=100' + - '&FI_POINT_TOLERANCE=20', - 'wms_getfeatureinfo_point_tolerance_20_text_xml', - 'test_project_values_postgres.qgz') - - self.wms_request_compare('GetFeatureInfo', - '&layers=ls2d&styles=&' + - 'VERSION=1.3.0&' + - 'info_format=text%2Fxml&' + - 'width=400&height=200' + - '&bbox=-50396.4,-2783.0,161715.8,114108.6' + - '&CRS=EPSG:3857' + - '&FEATURE_COUNT=10' + - '&WITH_GEOMETRY=False' + - '&QUERY_LAYERS=ls2d&I=153&J=147' + - '&FI_LINE_TOLERANCE=0', - 'wms_getfeatureinfo_line_tolerance_0_text_xml', - 'test_project_values_postgres.qgz') - - self.wms_request_compare('GetFeatureInfo', - '&layers=ls2d&styles=&' + - 'VERSION=1.3.0&' + - 'info_format=text%2Fxml&' + - 'width=400&height=200' + - '&bbox=-50396.4,-2783.0,161715.8,114108.6' + - '&CRS=EPSG:3857' + - '&FEATURE_COUNT=10' + - '&WITH_GEOMETRY=False' + - '&QUERY_LAYERS=ls2d&I=153&J=147' + - '&FI_LINE_TOLERANCE=20', - 'wms_getfeatureinfo_line_tolerance_20_text_xml', - 'test_project_values_postgres.qgz') - - self.wms_request_compare('GetFeatureInfo', - '&layers=p2d&styles=&' + - 'VERSION=1.3.0&' + - 'info_format=text%2Fxml&' + - 'width=400&height=200' + - '&bbox=-135832.0,-66482.4,240321.9,167300.4' + - '&CRS=EPSG:3857' + - '&FEATURE_COUNT=10' + - '&WITH_GEOMETRY=False' + - '&QUERY_LAYERS=p2d&I=206&J=144' + - '&FI_POLYGON_TOLERANCE=0', - 'wms_getfeatureinfo_polygon_tolerance_0_text_xml', - 'test_project_values_postgres.qgz') - - self.wms_request_compare('GetFeatureInfo', - '&layers=p2d&styles=&' + - 'VERSION=1.3.0&' + - 'info_format=text%2Fxml&' + - 'width=400&height=200' + - '&bbox=-135832.0,-66482.4,240321.9,167300.4' + - '&CRS=EPSG:3857' + - '&FEATURE_COUNT=10' + - '&WITH_GEOMETRY=False' + - '&QUERY_LAYERS=p2d&I=206&J=144' + - '&FI_POLYGON_TOLERANCE=20', - 'wms_getfeatureinfo_polygon_tolerance_20_text_xml', - 'test_project_values_postgres.qgz') + self.wms_request_compare( + "GetFeatureInfo", + "&layers=layer3&styles=&" + + "VERSION=1.3.0&" + + "info_format=text%2Fxml&" + + "width=400&height=200" + + "&bbox=913119.2,5605988.9,913316.0,5606047.4" + + "&CRS=EPSG:3857" + + "&FEATURE_COUNT=10" + + "&WITH_GEOMETRY=False" + + "&QUERY_LAYERS=layer3&I=193&J=100" + + "&FI_POINT_TOLERANCE=0", + "wms_getfeatureinfo_point_tolerance_0_text_xml", + "test_project_values_postgres.qgz", + ) + + self.wms_request_compare( + "GetFeatureInfo", + "&layers=layer3&styles=&" + + "VERSION=1.3.0&" + + "info_format=text%2Fxml&" + + "width=400&height=200" + + "&bbox=913119.2,5605988.9,913316.0,5606047.4" + + "&CRS=EPSG:3857" + + "&FEATURE_COUNT=10" + + "&WITH_GEOMETRY=False" + + "&QUERY_LAYERS=layer3&I=193&J=100" + + "&FI_POINT_TOLERANCE=20", + "wms_getfeatureinfo_point_tolerance_20_text_xml", + "test_project_values_postgres.qgz", + ) + + self.wms_request_compare( + "GetFeatureInfo", + "&layers=ls2d&styles=&" + + "VERSION=1.3.0&" + + "info_format=text%2Fxml&" + + "width=400&height=200" + + "&bbox=-50396.4,-2783.0,161715.8,114108.6" + + "&CRS=EPSG:3857" + + "&FEATURE_COUNT=10" + + "&WITH_GEOMETRY=False" + + "&QUERY_LAYERS=ls2d&I=153&J=147" + + "&FI_LINE_TOLERANCE=0", + "wms_getfeatureinfo_line_tolerance_0_text_xml", + "test_project_values_postgres.qgz", + ) + + self.wms_request_compare( + "GetFeatureInfo", + "&layers=ls2d&styles=&" + + "VERSION=1.3.0&" + + "info_format=text%2Fxml&" + + "width=400&height=200" + + "&bbox=-50396.4,-2783.0,161715.8,114108.6" + + "&CRS=EPSG:3857" + + "&FEATURE_COUNT=10" + + "&WITH_GEOMETRY=False" + + "&QUERY_LAYERS=ls2d&I=153&J=147" + + "&FI_LINE_TOLERANCE=20", + "wms_getfeatureinfo_line_tolerance_20_text_xml", + "test_project_values_postgres.qgz", + ) + + self.wms_request_compare( + "GetFeatureInfo", + "&layers=p2d&styles=&" + + "VERSION=1.3.0&" + + "info_format=text%2Fxml&" + + "width=400&height=200" + + "&bbox=-135832.0,-66482.4,240321.9,167300.4" + + "&CRS=EPSG:3857" + + "&FEATURE_COUNT=10" + + "&WITH_GEOMETRY=False" + + "&QUERY_LAYERS=p2d&I=206&J=144" + + "&FI_POLYGON_TOLERANCE=0", + "wms_getfeatureinfo_polygon_tolerance_0_text_xml", + "test_project_values_postgres.qgz", + ) + + self.wms_request_compare( + "GetFeatureInfo", + "&layers=p2d&styles=&" + + "VERSION=1.3.0&" + + "info_format=text%2Fxml&" + + "width=400&height=200" + + "&bbox=-135832.0,-66482.4,240321.9,167300.4" + + "&CRS=EPSG:3857" + + "&FEATURE_COUNT=10" + + "&WITH_GEOMETRY=False" + + "&QUERY_LAYERS=p2d&I=206&J=144" + + "&FI_POLYGON_TOLERANCE=20", + "wms_getfeatureinfo_polygon_tolerance_20_text_xml", + "test_project_values_postgres.qgz", + ) def testGetFeatureInfoValueRelationArray(self): """Test GetFeatureInfo on "value relation" widget with array field (multiple selections)""" mypath = self.testdata_path + "test_project_values_postgres.qgz" - self.wms_request_compare('GetFeatureInfo', - '&layers=layer3&styles=&' + - 'VERSION=1.3.0&' + - 'info_format=text%2Fxml&' + - 'width=926&height=787&srs=EPSG%3A4326' + - '&bbox=912217,5605059,914099,5606652' + - '&CRS=EPSG:3857' + - '&FEATURE_COUNT=10' + - '&WITH_GEOMETRY=True' + - '&QUERY_LAYERS=layer3&I=487&J=308', - 'wms_getfeatureinfo-values3-text-xml', - 'test_project_values_postgres.qgz') - - -if __name__ == '__main__': + self.wms_request_compare( + "GetFeatureInfo", + "&layers=layer3&styles=&" + + "VERSION=1.3.0&" + + "info_format=text%2Fxml&" + + "width=926&height=787&srs=EPSG%3A4326" + + "&bbox=912217,5605059,914099,5606652" + + "&CRS=EPSG:3857" + + "&FEATURE_COUNT=10" + + "&WITH_GEOMETRY=True" + + "&QUERY_LAYERS=layer3&I=487&J=308", + "wms_getfeatureinfo-values3-text-xml", + "test_project_values_postgres.qgz", + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_wms_getlegendgraphic.py b/tests/src/python/test_qgsserver_wms_getlegendgraphic.py index 06feb6cd0bb0..dc29d376ef94 100644 --- a/tests/src/python/test_qgsserver_wms_getlegendgraphic.py +++ b/tests/src/python/test_qgsserver_wms_getlegendgraphic.py @@ -9,14 +9,15 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '25/05/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "25/05/2015" +__copyright__ = "Copyright 2015, The QGIS Project" import os # Needed on Qt 5 so that the serialization of XML is consistent among all executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" import re import json @@ -51,8 +52,8 @@ ) # Strip path and content length because path may vary -RE_STRIP_UNCHECKABLE = br'MAP=[^"]+|Content-Length: \d+' -RE_ATTRIBUTES = br'[^>\s]+=[^>\s]+' +RE_STRIP_UNCHECKABLE = rb'MAP=[^"]+|Content-Length: \d+' +RE_ATTRIBUTES = rb"[^>\s]+=[^>\s]+" class TestQgsServerWMSGetLegendGraphic(TestQgsServerWMSTestBase): @@ -64,114 +65,153 @@ class TestQgsServerWMSGetLegendGraphic(TestQgsServerWMSTestBase): def test_getLegendGraphics(self): """Test that does not return an exception but an image""" parms = { - 'MAP': self.testdata_path + "test_project.qgs", - 'SERVICE': 'WMS', - 'VERSION': '1.3.0', - 'REQUEST': 'GetLegendGraphic', - 'FORMAT': 'image/png', + "MAP": self.testdata_path + "test_project.qgs", + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetLegendGraphic", + "FORMAT": "image/png", # 'WIDTH': '20', # optional # 'HEIGHT': '20', # optional - 'LAYER': 'testlayer%20èé', + "LAYER": "testlayer%20èé", } - qs = '?' + '&'.join([f"{k}={v}" for k, v in parms.items()]) + qs = "?" + "&".join([f"{k}={v}" for k, v in parms.items()]) h, r = self._execute_request(qs) - self.assertEqual(-1, h.find(b'Content-Type: text/xml; charset=utf-8'), f"Header: {h}\nResponse:\n{r}") - self.assertNotEqual(-1, h.find(b'Content-Type: image/png'), f"Header: {h}\nResponse:\n{r}") + self.assertEqual( + -1, + h.find(b"Content-Type: text/xml; charset=utf-8"), + f"Header: {h}\nResponse:\n{r}", + ) + self.assertNotEqual( + -1, h.find(b"Content-Type: image/png"), f"Header: {h}\nResponse:\n{r}" + ) def test_wms_GetLegendGraphic_LayerSpace(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello", - "FORMAT": "image/png", - # "HEIGHT": "500", - # "WIDTH": "500", - "LAYERSPACE": "50.0", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "30", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "20", - "ITEMFONTFAMILY": self.fontFamily, - "LAYERTITLE": "TRUE", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "FORMAT": "image/png", + # "HEIGHT": "500", + # "WIDTH": "500", + "LAYERSPACE": "50.0", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "30", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "20", + "ITEMFONTFAMILY": self.fontFamily, + "LAYERTITLE": "TRUE", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_LayerSpace", max_size_diff=QSize(1, 1)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_LayerSpace", max_size_diff=QSize(1, 1) + ) def test_wms_getLegendGraphics_invalid_parameters(self): """Test that does return an exception""" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello,db_point", - "LAYERTITLE": "FALSE", - "RULELABEL": "FALSE", - "FORMAT": "image/png", - "HEIGHT": "500", - "WIDTH": "500", - "RULE": "1", - "BBOX": "-151.7,-38.9,51.0,78.0", - "CRS": "EPSG:4326" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello,db_point", + "LAYERTITLE": "FALSE", + "RULELABEL": "FALSE", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "RULE": "1", + "BBOX": "-151.7,-38.9,51.0,78.0", + "CRS": "EPSG:4326", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) err = b"BBOX parameter cannot be combined with RULE" in r self.assertTrue(err) def test_wms_GetLegendGraphic_LayerTitleSpace(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello", - "FORMAT": "image/png", - # "HEIGHT": "500", - # "WIDTH": "500", - "LAYERTITLESPACE": "20.0", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "30", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "20", - "ITEMFONTFAMILY": self.fontFamily, - "LAYERTITLE": "TRUE", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "FORMAT": "image/png", + # "HEIGHT": "500", + # "WIDTH": "500", + "LAYERTITLESPACE": "20.0", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "30", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "20", + "ITEMFONTFAMILY": self.fontFamily, + "LAYERTITLE": "TRUE", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_LayerTitleSpace", - max_size_diff=QSize(1, 5)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_LayerTitleSpace", max_size_diff=QSize(1, 5) + ) def test_wms_GetLegendGraphic_ShowFeatureCount(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello", - "FORMAT": "image/png", - # "HEIGHT": "500", - # "WIDTH": "500", - "LAYERTITLE": "TRUE", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "30", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "20", - "ITEMFONTFAMILY": self.fontFamily, - "SHOWFEATURECOUNT": "TRUE", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "FORMAT": "image/png", + # "HEIGHT": "500", + # "WIDTH": "500", + "LAYERTITLE": "TRUE", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "30", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "20", + "ITEMFONTFAMILY": self.fontFamily, + "SHOWFEATURECOUNT": "TRUE", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_ShowFeatureCount", max_size_diff=QSize(1, 1)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_ShowFeatureCount", max_size_diff=QSize(1, 1) + ) def test_wms_getLegendGraphics_layertitle(self): """Test that does not return an exception but an image""" @@ -179,947 +219,1351 @@ def test_wms_getLegendGraphics_layertitle(self): print("TEST FONT FAMILY: ", self.fontFamily) parms = { - 'MAP': self.testdata_path + "test_project.qgs", - 'SERVICE': 'WMS', - 'VERSION': '1.3.0', - 'REQUEST': 'GetLegendGraphic', - 'FORMAT': 'image/png', + "MAP": self.testdata_path + "test_project.qgs", + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetLegendGraphic", + "FORMAT": "image/png", # 'WIDTH': '20', # optional # 'HEIGHT': '20', # optional - 'LAYER': 'testlayer%20èé', - 'LAYERFONTBOLD': 'TRUE', - 'LAYERFONTSIZE': '30', - 'LAYERFONTFAMILY': self.fontFamily, - 'ITEMFONTBOLD': 'TRUE', - 'ITEMFONTSIZE': '20', - 'ITEMFONTFAMILY': self.fontFamily, - 'LAYERTITLE': 'TRUE', - 'RULELABEL': 'TRUE' + "LAYER": "testlayer%20èé", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "30", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "20", + "ITEMFONTFAMILY": self.fontFamily, + "LAYERTITLE": "TRUE", + "RULELABEL": "TRUE", } - qs = '?' + '&'.join([f"{k}={v}" for k, v in parms.items()]) + qs = "?" + "&".join([f"{k}={v}" for k, v in parms.items()]) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetLegendGraphic_test", 250, QSize(15, 15)) # no set of LAYERTITLE and RULELABEL means they are true parms = { - 'MAP': self.testdata_path + "test_project.qgs", - 'SERVICE': 'WMS', - 'VERSION': '1.3.0', - 'REQUEST': 'GetLegendGraphic', - 'FORMAT': 'image/png', + "MAP": self.testdata_path + "test_project.qgs", + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetLegendGraphic", + "FORMAT": "image/png", # 'WIDTH': '20', # optional # 'HEIGHT': '20', # optional - 'LAYER': 'testlayer%20èé', - 'LAYERFONTBOLD': 'TRUE', - 'LAYERFONTSIZE': '30', - 'LAYERFONTFAMILY': self.fontFamily, - 'ITEMFONTBOLD': 'TRUE', - 'ITEMFONTSIZE': '20', - 'ITEMFONTFAMILY': self.fontFamily + "LAYER": "testlayer%20èé", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "30", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "20", + "ITEMFONTFAMILY": self.fontFamily, } - qs = '?' + '&'.join([f"{k}={v}" for k, v in parms.items()]) + qs = "?" + "&".join([f"{k}={v}" for k, v in parms.items()]) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetLegendGraphic_test", 250, QSize(15, 15)) parms = { - 'MAP': self.testdata_path + "test_project.qgs", - 'SERVICE': 'WMS', - 'VERSION': '1.3.0', - 'REQUEST': 'GetLegendGraphic', - 'FORMAT': 'image/png', + "MAP": self.testdata_path + "test_project.qgs", + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetLegendGraphic", + "FORMAT": "image/png", # 'WIDTH': '20', # optional # 'HEIGHT': '20', # optional - 'LAYER': 'testlayer%20èé', - 'LAYERTITLE': 'FALSE', - 'RULELABEL': 'FALSE' + "LAYER": "testlayer%20èé", + "LAYERTITLE": "FALSE", + "RULELABEL": "FALSE", } - qs = '?' + '&'.join([f"{k}={v}" for k, v in parms.items()]) + qs = "?" + "&".join([f"{k}={v}" for k, v in parms.items()]) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_test_layertitle_false", 250, QSize(15, 15)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_test_layertitle_false", 250, QSize(15, 15) + ) def test_wms_getLegendGraphics_rulelabel(self): """Test that does not return an exception but an image""" parms = { - 'MAP': self.testdata_path + "test_project.qgs", - 'SERVICE': 'WMS', - 'VERSION': '1.3.0', - 'REQUEST': 'GetLegendGraphic', - 'FORMAT': 'image/png', - 'LAYER': 'testlayer%20èé', - 'LAYERFONTBOLD': 'TRUE', - 'LAYERFONTSIZE': '30', - 'LAYERFONTFAMILY': self.fontFamily, - 'ITEMFONTBOLD': 'TRUE', - 'ITEMFONTSIZE': '20', - 'ITEMFONTFAMILY': self.fontFamily, - 'RULELABEL': 'FALSE' + "MAP": self.testdata_path + "test_project.qgs", + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetLegendGraphic", + "FORMAT": "image/png", + "LAYER": "testlayer%20èé", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "30", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "20", + "ITEMFONTFAMILY": self.fontFamily, + "RULELABEL": "FALSE", } - qs = '?' + '&'.join([f"{k}={v}" for k, v in parms.items()]) + qs = "?" + "&".join([f"{k}={v}" for k, v in parms.items()]) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_rulelabel_false", 250, QSize(15, 15)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_rulelabel_false", 250, QSize(15, 15) + ) parms = { - 'MAP': self.testdata_path + "test_project.qgs", - 'SERVICE': 'WMS', - 'VERSION': '1.3.0', - 'REQUEST': 'GetLegendGraphic', - 'FORMAT': 'image/png', - 'LAYER': 'testlayer%20èé', - 'LAYERFONTBOLD': 'TRUE', - 'LAYERFONTSIZE': '30', - 'LAYERFONTFAMILY': self.fontFamily, - 'ITEMFONTBOLD': 'TRUE', - 'ITEMFONTSIZE': '20', - 'ITEMFONTFAMILY': self.fontFamily, - 'LAYERTITLE': 'FALSE', - 'RULELABEL': 'TRUE' + "MAP": self.testdata_path + "test_project.qgs", + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetLegendGraphic", + "FORMAT": "image/png", + "LAYER": "testlayer%20èé", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "30", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "20", + "ITEMFONTFAMILY": self.fontFamily, + "LAYERTITLE": "FALSE", + "RULELABEL": "TRUE", } - qs = '?' + '&'.join([f"{k}={v}" for k, v in parms.items()]) + qs = "?" + "&".join([f"{k}={v}" for k, v in parms.items()]) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_rulelabel_true", 250, QSize(15, 15)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_rulelabel_true", 250, QSize(15, 15) + ) # no set of RULELABEL means it is true parms = { - 'MAP': self.testdata_path + "test_project.qgs", - 'SERVICE': 'WMS', - 'VERSION': '1.3.0', - 'REQUEST': 'GetLegendGraphic', - 'FORMAT': 'image/png', - 'LAYER': 'testlayer%20èé', - 'LAYERFONTBOLD': 'TRUE', - 'LAYERFONTSIZE': '30', - 'LAYERFONTFAMILY': self.fontFamily, - 'ITEMFONTBOLD': 'TRUE', - 'ITEMFONTSIZE': '20', - 'ITEMFONTFAMILY': self.fontFamily, - 'LAYERTITLE': 'FALSE' + "MAP": self.testdata_path + "test_project.qgs", + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetLegendGraphic", + "FORMAT": "image/png", + "LAYER": "testlayer%20èé", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "30", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "20", + "ITEMFONTFAMILY": self.fontFamily, + "LAYERTITLE": "FALSE", } - qs = '?' + '&'.join([f"{k}={v}" for k, v in parms.items()]) + qs = "?" + "&".join([f"{k}={v}" for k, v in parms.items()]) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_rulelabel_notset", 250, QSize(15, 15)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_rulelabel_notset", 250, QSize(15, 15) + ) # RULELABEL AUTO for single symbol means it is removed parms = { - 'MAP': self.testdata_path + "test_project.qgs", - 'SERVICE': 'WMS', - 'VERSION': '1.3.0', - 'REQUEST': 'GetLegendGraphic', - 'FORMAT': 'image/png', - 'LAYER': 'testlayer%20èé', - 'LAYERTITLE': 'FALSE', - 'RULELABEL': 'AUTO' + "MAP": self.testdata_path + "test_project.qgs", + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetLegendGraphic", + "FORMAT": "image/png", + "LAYER": "testlayer%20èé", + "LAYERTITLE": "FALSE", + "RULELABEL": "AUTO", } - qs = '?' + '&'.join([f"{k}={v}" for k, v in parms.items()]) + qs = "?" + "&".join([f"{k}={v}" for k, v in parms.items()]) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_rulelabel_auto", 250, QSize(15, 15)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_rulelabel_auto", 250, QSize(15, 15) + ) def test_wms_getLegendGraphics_rule(self): """Test that does not return an exception but an image""" parms = { - 'MAP': self.testdata_path + "test_project_legend_rule.qgs", - 'SERVICE': 'WMS', - 'VERSION': '1.3.0', - 'REQUEST': 'GetLegendGraphic', - 'FORMAT': 'image/png', - 'LAYER': 'testlayer%20èé', - 'WIDTH': '20', - 'HEIGHT': '20', - 'RULE': 'rule0', + "MAP": self.testdata_path + "test_project_legend_rule.qgs", + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetLegendGraphic", + "FORMAT": "image/png", + "LAYER": "testlayer%20èé", + "WIDTH": "20", + "HEIGHT": "20", + "RULE": "rule0", } - qs = '?' + '&'.join([f"{k}={v}" for k, v in parms.items()]) + qs = "?" + "&".join([f"{k}={v}" for k, v in parms.items()]) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetLegendGraphic_rule0", 250, QSize(15, 15)) parms = { - 'MAP': self.testdata_path + "test_project_legend_rule.qgs", - 'SERVICE': 'WMS', - 'VERSION': '1.3.0', - 'REQUEST': 'GetLegendGraphic', - 'FORMAT': 'image/png', - 'LAYER': 'testlayer%20èé', - 'WIDTH': '20', - 'HEIGHT': '20', - 'RULE': 'rule1', + "MAP": self.testdata_path + "test_project_legend_rule.qgs", + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetLegendGraphic", + "FORMAT": "image/png", + "LAYER": "testlayer%20èé", + "WIDTH": "20", + "HEIGHT": "20", + "RULE": "rule1", } - qs = '?' + '&'.join([f"{k}={v}" for k, v in parms.items()]) + qs = "?" + "&".join([f"{k}={v}" for k, v in parms.items()]) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetLegendGraphic_rule1", 250, QSize(15, 15)) def test_wms_GetLegendGraphic_Basic(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello", - "LAYERTITLE": "FALSE", - "RULELABEL": "FALSE", - "FORMAT": "image/png", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "LAYERTITLE": "FALSE", + "RULELABEL": "FALSE", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_Basic", max_size_diff=QSize(1, 1)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_Basic", max_size_diff=QSize(1, 1) + ) def test_wms_GetLegendGraphic_Transparent(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello", - "LAYERTITLE": "FALSE", - "RULELABEL": "FALSE", - "FORMAT": "image/png", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "TRANSPARENT": "TRUE" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "LAYERTITLE": "FALSE", + "RULELABEL": "FALSE", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "TRANSPARENT": "TRUE", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_Transparent", max_size_diff=QSize(1, 1)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_Transparent", max_size_diff=QSize(1, 1) + ) def test_wms_GetLegendGraphic_Background(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello", - "LAYERTITLE": "FALSE", - "RULELABEL": "FALSE", - "FORMAT": "image/png", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "BGCOLOR": "green" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "LAYERTITLE": "FALSE", + "RULELABEL": "FALSE", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "BGCOLOR": "green", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_Background", max_size_diff=QSize(1, 1)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_Background", max_size_diff=QSize(1, 1) + ) - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello", - "LAYERTITLE": "FALSE", - "RULELABEL": "FALSE", - "FORMAT": "image/png", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "BGCOLOR": "0x008000" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "LAYERTITLE": "FALSE", + "RULELABEL": "FALSE", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "BGCOLOR": "0x008000", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_Background_Hex", max_size_diff=QSize(1, 1)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_Background_Hex", max_size_diff=QSize(1, 1) + ) def test_wms_GetLegendGraphic_BoxSpace(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello", - "LAYERTITLE": "FALSE", - "RULELABEL": "FALSE", - "BOXSPACE": "100", - "FORMAT": "image/png", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "LAYERTITLE": "FALSE", + "RULELABEL": "FALSE", + "BOXSPACE": "100", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_BoxSpace", max_size_diff=QSize(5, 5)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_BoxSpace", max_size_diff=QSize(5, 5) + ) def test_wms_GetLegendGraphic_SymbolSpace(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello", - "LAYERTITLE": "FALSE", - "RULELABEL": "FALSE", - "SYMBOLSPACE": "100", - "FORMAT": "image/png", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "LAYERTITLE": "FALSE", + "RULELABEL": "FALSE", + "SYMBOLSPACE": "100", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_SymbolSpace", max_size_diff=QSize(1, 1)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_SymbolSpace", max_size_diff=QSize(1, 1) + ) def test_wms_GetLegendGraphic_IconLabelSpace(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello", - "LAYERTITLE": "FALSE", - "RULELABEL": "FALSE", - "ICONLABELSPACE": "100", - "FORMAT": "image/png", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "LAYERTITLE": "FALSE", + "RULELABEL": "FALSE", + "ICONLABELSPACE": "100", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_IconLabelSpace", max_size_diff=QSize(1, 1)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_IconLabelSpace", max_size_diff=QSize(1, 1) + ) def test_wms_GetLegendGraphic_SymbolSize(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello", - "LAYERTITLE": "FALSE", - "RULELABEL": "FALSE", - "SYMBOLWIDTH": "50", - "SYMBOLHEIGHT": "30", - "FORMAT": "image/png", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "LAYERTITLE": "FALSE", + "RULELABEL": "FALSE", + "SYMBOLWIDTH": "50", + "SYMBOLHEIGHT": "30", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_SymbolSize", - max_size_diff=QSize(1, 1)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_SymbolSize", max_size_diff=QSize(1, 1) + ) def test_wms_GetLegendGraphic_LayerFont(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello", - "LAYERTITLE": "TRUE", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTITALIC": "TRUE", - "LAYERFONTSIZE": "30", - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "20", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTFAMILY": self.fontFamily, - "FORMAT": "image/png", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "LAYERTITLE": "TRUE", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTITALIC": "TRUE", + "LAYERFONTSIZE": "30", + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "20", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTFAMILY": self.fontFamily, + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_LayerFont", max_size_diff=QSize(1, 1)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_LayerFont", max_size_diff=QSize(1, 1) + ) def test_wms_GetLegendGraphic_ItemFont(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello", - "LAYERTITLE": "TRUE", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "30", - "ITEMFONTBOLD": "TRUE", - "ITEMFONTITALIC": "TRUE", - "ITEMFONTSIZE": "20", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTFAMILY": self.fontFamily, - "FORMAT": "image/png", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "LAYERTITLE": "TRUE", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "30", + "ITEMFONTBOLD": "TRUE", + "ITEMFONTITALIC": "TRUE", + "ITEMFONTSIZE": "20", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTFAMILY": self.fontFamily, + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_ItemFont", max_size_diff=QSize(1, 1)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_ItemFont", max_size_diff=QSize(1, 1) + ) def test_wms_GetLegendGraphic_BBox(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello,db_point", - "LAYERTITLE": "FALSE", - "RULELABEL": "FALSE", - "FORMAT": "image/png", - "SRCHEIGHT": "500", - "SRCWIDTH": "500", - "BBOX": "-151.7,-38.9,51.0,78.0", - "CRS": "EPSG:4326" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello,db_point", + "LAYERTITLE": "FALSE", + "RULELABEL": "FALSE", + "FORMAT": "image/png", + "SRCHEIGHT": "500", + "SRCWIDTH": "500", + "BBOX": "-151.7,-38.9,51.0,78.0", + "CRS": "EPSG:4326", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_BBox", max_size_diff=QSize(1, 1)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_BBox", max_size_diff=QSize(1, 1) + ) def test_wms_GetLegendGraphic_BBox2(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello,db_point", - "LAYERTITLE": "FALSE", - "RULELABEL": "FALSE", - "FORMAT": "image/png", - "SRCHEIGHT": "500", - "SRCWIDTH": "500", - "BBOX": "-76.08,-6.4,-19.38,38.04", - "SRS": "EPSG:4326" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello,db_point", + "LAYERTITLE": "FALSE", + "RULELABEL": "FALSE", + "FORMAT": "image/png", + "SRCHEIGHT": "500", + "SRCWIDTH": "500", + "BBOX": "-76.08,-6.4,-19.38,38.04", + "SRS": "EPSG:4326", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_BBox2", max_size_diff=QSize(1, 1)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_BBox2", max_size_diff=QSize(1, 1) + ) def test_wms_GetLegendGraphic_BBox_Fallback(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello,db_point", - "LAYERTITLE": "FALSE", - "RULELABEL": "FALSE", - "FORMAT": "image/png", - "HEIGHT": "500", - "WIDTH": "500", - "BBOX": "-151.7,-38.9,51.0,78.0", - "CRS": "EPSG:4326" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello,db_point", + "LAYERTITLE": "FALSE", + "RULELABEL": "FALSE", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "BBOX": "-151.7,-38.9,51.0,78.0", + "CRS": "EPSG:4326", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_BBox", max_size_diff=QSize(1, 1)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_BBox", max_size_diff=QSize(1, 1) + ) def test_wms_GetLegendGraphic_BBox2_Fallback(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello,db_point", - "LAYERTITLE": "FALSE", - "RULELABEL": "FALSE", - "FORMAT": "image/png", - "HEIGHT": "500", - "WIDTH": "500", - "BBOX": "-76.08,-6.4,-19.38,38.04", - "SRS": "EPSG:4326" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello,db_point", + "LAYERTITLE": "FALSE", + "RULELABEL": "FALSE", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "BBOX": "-76.08,-6.4,-19.38,38.04", + "SRS": "EPSG:4326", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_BBox2", max_size_diff=QSize(1, 1)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_BBox2", max_size_diff=QSize(1, 1) + ) def test_wms_GetLegendGraphic_EmptyLegend(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_contextual_legend.qgs', - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "QGIS%20Server%20Hello%20World", - "FORMAT": "image/png", - "SRCHEIGHT": "840", - "SRCWIDTH": "1226", - "BBOX": "10.38450,-49.6370,73.8183,42.9461", - "SRS": "EPSG:4326", - "SCALE": "15466642" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + + "test_project_contextual_legend.qgs", + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "QGIS%20Server%20Hello%20World", + "FORMAT": "image/png", + "SRCHEIGHT": "840", + "SRCWIDTH": "1226", + "BBOX": "10.38450,-49.6370,73.8183,42.9461", + "SRS": "EPSG:4326", + "SCALE": "15466642", + }.items() + ) + ] + ) h, r = self._execute_request(qs) - self.assertEqual(-1, h.find(b'Content-Type: text/xml; charset=utf-8'), f"Header: {h}\nResponse:\n{r}") - self.assertNotEqual(-1, h.find(b'Content-Type: image/png'), f"Header: {h}\nResponse:\n{r}") + self.assertEqual( + -1, + h.find(b"Content-Type: text/xml; charset=utf-8"), + f"Header: {h}\nResponse:\n{r}", + ) + self.assertNotEqual( + -1, h.find(b"Content-Type: image/png"), f"Header: {h}\nResponse:\n{r}" + ) def test_wms_GetLegendGraphic_wmsRootName(self): """Test an unreported issue when a wmsRootName short name is set in the service capabilities""" # First test with the project title itself: - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_wms_grouped_layers.qgs', - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "QGIS%20Server%20-%20Grouped%20Layer", - "FORMAT": "image/png", - "SRCHEIGHT": "840", - "SRCWIDTH": "1226", - "BBOX": "609152,5808188,625492,5814318", - "SRS": "EPSG:25832", - "SCALE": "38976" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + + "test_project_wms_grouped_layers.qgs", + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "QGIS%20Server%20-%20Grouped%20Layer", + "FORMAT": "image/png", + "SRCHEIGHT": "840", + "SRCWIDTH": "1226", + "BBOX": "609152,5808188,625492,5814318", + "SRS": "EPSG:25832", + "SCALE": "38976", + }.items() + ) + ] + ) h, r = self._execute_request(qs) - self.assertEqual(-1, h.find(b'Content-Type: text/xml; charset=utf-8'), f"Header: {h}\nResponse:\n{r}") - self.assertNotEqual(-1, h.find(b'Content-Type: image/png'), f"Header: {h}\nResponse:\n{r}") + self.assertEqual( + -1, + h.find(b"Content-Type: text/xml; charset=utf-8"), + f"Header: {h}\nResponse:\n{r}", + ) + self.assertNotEqual( + -1, h.find(b"Content-Type: image/png"), f"Header: {h}\nResponse:\n{r}" + ) # Then test with the wmsRootName short name: - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_wms_grouped_layers_wmsroot.qgs', - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "All_grouped_layers", - "FORMAT": "image/png", - "SRCHEIGHT": "840", - "SRCWIDTH": "1226", - "BBOX": "609152,5808188,625492,5814318", - "SRS": "EPSG:25832", - "SCALE": "38976" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + + "test_project_wms_grouped_layers_wmsroot.qgs", + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "All_grouped_layers", + "FORMAT": "image/png", + "SRCHEIGHT": "840", + "SRCWIDTH": "1226", + "BBOX": "609152,5808188,625492,5814318", + "SRS": "EPSG:25832", + "SCALE": "38976", + }.items() + ) + ] + ) h, r = self._execute_request(qs) - self.assertEqual(-1, h.find(b'Content-Type: text/xml; charset=utf-8'), f"Header: {h}\nResponse:\n{r}") - self.assertNotEqual(-1, h.find(b'Content-Type: image/png'), f"Header: {h}\nResponse:\n{r}") + self.assertEqual( + -1, + h.find(b"Content-Type: text/xml; charset=utf-8"), + f"Header: {h}\nResponse:\n{r}", + ) + self.assertNotEqual( + -1, h.find(b"Content-Type: image/png"), f"Header: {h}\nResponse:\n{r}" + ) def test_wms_GetLegendGraphic_ScaleSymbol_Min(self): # 1:500000000 min - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_scaledsymbols.qgs', - "SERVICE": "WMS", - "REQUEST": "GetLegendGraphic", - "LAYER": "testlayer", - "FORMAT": "image/png", - "SRCHEIGHT": "550", - "SRCWIDTH": "850", - "BBOX": "-608.4,-1002.6,698.2,1019.0", - "CRS": "EPSG:4326", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + "test_project_scaledsymbols.qgs", + "SERVICE": "WMS", + "REQUEST": "GetLegendGraphic", + "LAYER": "testlayer", + "FORMAT": "image/png", + "SRCHEIGHT": "550", + "SRCWIDTH": "850", + "BBOX": "-608.4,-1002.6,698.2,1019.0", + "CRS": "EPSG:4326", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_Min", max_size_diff=QSize(1, 1)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_ScaleSymbol_Min", max_size_diff=QSize(1, 1) + ) # 1:1000000000 min - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_scaledsymbols.qgs', - "SERVICE": "WMS", - "REQUEST": "GetLegendGraphic", - "LAYER": "testlayer", - "FORMAT": "image/png", - "SRCHEIGHT": "550", - "SRCWIDTH": "850", - "BBOX": "-1261.7,-2013.5,1351.5,2029.9", - "CRS": "EPSG:4326", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + "test_project_scaledsymbols.qgs", + "SERVICE": "WMS", + "REQUEST": "GetLegendGraphic", + "LAYER": "testlayer", + "FORMAT": "image/png", + "SRCHEIGHT": "550", + "SRCWIDTH": "850", + "BBOX": "-1261.7,-2013.5,1351.5,2029.9", + "CRS": "EPSG:4326", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_Min", max_size_diff=QSize(15, 15)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_ScaleSymbol_Min", max_size_diff=QSize(15, 15) + ) def test_wms_GetLegendGraphic_ScaleSymbol_Scaled_01(self): # 1:10000000 scaled - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_scaledsymbols.qgs', - "SERVICE": "WMS", - "REQUEST": "GetLegendGraphic", - "LAYER": "testlayer", - "FORMAT": "image/png", - "SRCHEIGHT": "550", - "SRCWIDTH": "850", - "BBOX": "31.8,-12.0,58.0,28.4", - "CRS": "EPSG:4326", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + "test_project_scaledsymbols.qgs", + "SERVICE": "WMS", + "REQUEST": "GetLegendGraphic", + "LAYER": "testlayer", + "FORMAT": "image/png", + "SRCHEIGHT": "550", + "SRCWIDTH": "850", + "BBOX": "31.8,-12.0,58.0,28.4", + "CRS": "EPSG:4326", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_Scaled_01", max_size_diff=QSize(15, 15)) + self._img_diff_error( + r, + h, + "WMS_GetLegendGraphic_ScaleSymbol_Scaled_01", + max_size_diff=QSize(15, 15), + ) def test_wms_GetLegendGraphic_ScaleSymbol_Scaled_02(self): # 1:15000000 scaled - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_scaledsymbols.qgs', - "SERVICE": "WMS", - "REQUEST": "GetLegendGraphic", - "LAYER": "testlayer", - "FORMAT": "image/png", - "SRCHEIGHT": "550", - "SRCWIDTH": "850", - "BBOX": "25.3,-22.1,64.5,38.5", - "CRS": "EPSG:4326", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + "test_project_scaledsymbols.qgs", + "SERVICE": "WMS", + "REQUEST": "GetLegendGraphic", + "LAYER": "testlayer", + "FORMAT": "image/png", + "SRCHEIGHT": "550", + "SRCWIDTH": "850", + "BBOX": "25.3,-22.1,64.5,38.5", + "CRS": "EPSG:4326", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_Scaled_02", max_size_diff=QSize(15, 15)) + self._img_diff_error( + r, + h, + "WMS_GetLegendGraphic_ScaleSymbol_Scaled_02", + max_size_diff=QSize(15, 15), + ) def test_wms_GetLegendGraphic_ScaleSymbol_Max(self): # 1:100000 max - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_scaledsymbols.qgs', - "SERVICE": "WMS", - "REQUEST": "GetLegendGraphic", - "LAYER": "testlayer", - "FORMAT": "image/png", - "SRCHEIGHT": "550", - "SRCWIDTH": "850", - "BBOX": "44.8,8.0,45.0,8.4", - "CRS": "EPSG:4326", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + "test_project_scaledsymbols.qgs", + "SERVICE": "WMS", + "REQUEST": "GetLegendGraphic", + "LAYER": "testlayer", + "FORMAT": "image/png", + "SRCHEIGHT": "550", + "SRCWIDTH": "850", + "BBOX": "44.8,8.0,45.0,8.4", + "CRS": "EPSG:4326", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_Max", max_size_diff=QSize(15, 15)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_ScaleSymbol_Max", max_size_diff=QSize(15, 15) + ) # 1:1000000 max - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_scaledsymbols.qgs', - "SERVICE": "WMS", - "REQUEST": "GetLegendGraphic", - "LAYER": "testlayer", - "FORMAT": "image/png", - "SRCHEIGHT": "550", - "SRCWIDTH": "850", - "BBOX": "43.6,6.2,46.2,10.2", - "CRS": "EPSG:4326", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + "test_project_scaledsymbols.qgs", + "SERVICE": "WMS", + "REQUEST": "GetLegendGraphic", + "LAYER": "testlayer", + "FORMAT": "image/png", + "SRCHEIGHT": "550", + "SRCWIDTH": "850", + "BBOX": "43.6,6.2,46.2,10.2", + "CRS": "EPSG:4326", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_Max", max_size_diff=QSize(15, 15)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_ScaleSymbol_Max", max_size_diff=QSize(15, 15) + ) def test_wms_GetLegendGraphic_ScaleSymbol_DefaultMapUnitsPerMillimeter(self): # map units per mm on 1:20000000 with SRCHEIGHT=598&SRCWIDTH=1640&BBOX=16.5,-69.7,73.3,86.1 would be around what is set as default: 0.359 map units per mm - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_scaledsymbols.qgs', - "SERVICE": "WMS", - "REQUEST": "GetLegendGraphic", - "LAYER": "testlayer", - "FORMAT": "image/png", - "CRS": "EPSG:4326", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + "test_project_scaledsymbols.qgs", + "SERVICE": "WMS", + "REQUEST": "GetLegendGraphic", + "LAYER": "testlayer", + "FORMAT": "image/png", + "CRS": "EPSG:4326", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_DefaultMapUnitsPerMillimeter", - max_size_diff=QSize(15, 15)) + self._img_diff_error( + r, + h, + "WMS_GetLegendGraphic_ScaleSymbol_DefaultMapUnitsPerMillimeter", + max_size_diff=QSize(15, 15), + ) def test_wms_GetLegendGraphic_ScaleSymbol_Scaled_2056(self): # 1:1000 scale on an EPSG:2056 calculating DPI that is around 96 - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_scaledsymbols_2056.qgs', - "SERVICE": "WMS", - "REQUEST": "GetLegendGraphic", - "LAYER": "testlayer_2056", - "FORMAT": "image/png", - "SRCHEIGHT": "600", - "SRCWIDTH": "1500", - "BBOX": "2662610.7,1268841.8,2663010.5,1269000.05", - "CRS": "EPSG:2056", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + + "test_project_scaledsymbols_2056.qgs", + "SERVICE": "WMS", + "REQUEST": "GetLegendGraphic", + "LAYER": "testlayer_2056", + "FORMAT": "image/png", + "SRCHEIGHT": "600", + "SRCWIDTH": "1500", + "BBOX": "2662610.7,1268841.8,2663010.5,1269000.05", + "CRS": "EPSG:2056", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_Scaled_2056", max_size_diff=QSize(15, 15)) + self._img_diff_error( + r, + h, + "WMS_GetLegendGraphic_ScaleSymbol_Scaled_2056", + max_size_diff=QSize(15, 15), + ) def test_wms_GetLegendGraphic_ScaleSymbol_DefaultScale_2056(self): # 1:1000 as default value - it's not exactly the same result than passing the bbox and size because of exact DPI 96 (default) - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_scaledsymbols_2056.qgs', - "SERVICE": "WMS", - "REQUEST": "GetLegendGraphic", - "LAYER": "testlayer_2056", - "FORMAT": "image/png", - "CRS": "EPSG:2056", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + + "test_project_scaledsymbols_2056.qgs", + "SERVICE": "WMS", + "REQUEST": "GetLegendGraphic", + "LAYER": "testlayer_2056", + "FORMAT": "image/png", + "CRS": "EPSG:2056", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_DefaultScale_2056", max_size_diff=QSize(15, 15)) + self._img_diff_error( + r, + h, + "WMS_GetLegendGraphic_ScaleSymbol_DefaultScale_2056", + max_size_diff=QSize(15, 15), + ) def test_wms_GetLegendGraphic_MetersAtScaleSymbol_Scaled(self): # meters at scale symbols on EPSG:4326 calculated with BBOX - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_meters_at_scaledsymbols.qgs', - "SERVICE": "WMS", - "REQUEST": "GetLegendGraphic", - "LAYER": "testlayer", - "FORMAT": "image/png", - "SRCHEIGHT": "2550", - "SRCWIDTH": "3850", - "BBOX": "44.89945254864102964,8.20044117721021948,44.90400902275693085,8.20936038559772285", - "CRS": "EPSG:4326", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + + "test_project_meters_at_scaledsymbols.qgs", + "SERVICE": "WMS", + "REQUEST": "GetLegendGraphic", + "LAYER": "testlayer", + "FORMAT": "image/png", + "SRCHEIGHT": "2550", + "SRCWIDTH": "3850", + "BBOX": "44.89945254864102964,8.20044117721021948,44.90400902275693085,8.20936038559772285", + "CRS": "EPSG:4326", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_MetersAtScaleSymbol_Scaled", max_size_diff=QSize(15, 15)) + self._img_diff_error( + r, + h, + "WMS_GetLegendGraphic_MetersAtScaleSymbol_Scaled", + max_size_diff=QSize(15, 15), + ) def test_wms_GetLegendGraphic_MetersAtScaleSymbol_DefaultScale(self): # meters at scale symbols on EPSG:4326 calculated with Default Scale set in the projects configuration - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_meters_at_scaledsymbols.qgs', - "SERVICE": "WMS", - "REQUEST": "GetLegendGraphic", - "LAYER": "testlayer", - "FORMAT": "image/png", - "CRS": "EPSG:4326", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + + "test_project_meters_at_scaledsymbols.qgs", + "SERVICE": "WMS", + "REQUEST": "GetLegendGraphic", + "LAYER": "testlayer", + "FORMAT": "image/png", + "CRS": "EPSG:4326", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_MetersAtScaleSymbol_DefaultScale", max_size_diff=QSize(15, 15)) + self._img_diff_error( + r, + h, + "WMS_GetLegendGraphic_MetersAtScaleSymbol_DefaultScale", + max_size_diff=QSize(15, 15), + ) def test_wms_GetLegendGraphic_MetersAtScaleSymbol_Rule(self): # meters at scale symbols on EPSG:4326 calculated with Default Scale set in the projects configuration and having a rule - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_meters_at_scaledsymbols.qgs', - "SERVICE": "WMS", - "REQUEST": "GetLegendGraphic", - "LAYER": "testlayer", - "FORMAT": "image/png", - "CRS": "EPSG:4326", - "WIDTH": "50", - "HEIGHT": "50", - "RULE": "two" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + + "test_project_meters_at_scaledsymbols.qgs", + "SERVICE": "WMS", + "REQUEST": "GetLegendGraphic", + "LAYER": "testlayer", + "FORMAT": "image/png", + "CRS": "EPSG:4326", + "WIDTH": "50", + "HEIGHT": "50", + "RULE": "two", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_MetersAtScaleSymbol_Rule", max_size_diff=QSize(15, 15)) + self._img_diff_error( + r, + h, + "WMS_GetLegendGraphic_MetersAtScaleSymbol_Rule", + max_size_diff=QSize(15, 15), + ) def test_wms_GetLegendGraphic_MetersAtScaleSymbol_Scaled_2056(self): # meters at scale symbols on EPSG:2056 calculated with BBOX - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_meters_at_scaledsymbols_2056.qgs', - "SERVICE": "WMS", - "REQUEST": "GetLegendGraphic", - "LAYER": "testlayer_2056", - "FORMAT": "image/png", - "SRCHEIGHT": "1100", - "SRCWIDTH": "1700", - "BBOX": "2662610.7,1268841.8,2663010.5,1269000.05", - "CRS": "EPSG:2056", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + + "test_project_meters_at_scaledsymbols_2056.qgs", + "SERVICE": "WMS", + "REQUEST": "GetLegendGraphic", + "LAYER": "testlayer_2056", + "FORMAT": "image/png", + "SRCHEIGHT": "1100", + "SRCWIDTH": "1700", + "BBOX": "2662610.7,1268841.8,2663010.5,1269000.05", + "CRS": "EPSG:2056", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_MetersAtScaleSymbol_Scaled_2056", max_size_diff=QSize(15, 15)) + self._img_diff_error( + r, + h, + "WMS_GetLegendGraphic_MetersAtScaleSymbol_Scaled_2056", + max_size_diff=QSize(15, 15), + ) def test_wms_GetLegendGraphic_MetersAtScaleSymbol_DefaultScale_2056(self): # meters at scale symbols on EPSG:2056 calculated with Default Scale set in the projects configuration - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_meters_at_scaledsymbols_2056.qgs', - "SERVICE": "WMS", - "REQUEST": "GetLegendGraphic", - "LAYER": "testlayer_2056", - "FORMAT": "image/png", - "CRS": "EPSG:2056", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + + "test_project_meters_at_scaledsymbols_2056.qgs", + "SERVICE": "WMS", + "REQUEST": "GetLegendGraphic", + "LAYER": "testlayer_2056", + "FORMAT": "image/png", + "CRS": "EPSG:2056", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_MetersAtScaleSymbol_DefaultScale_2056", max_size_diff=QSize(15, 15)) + self._img_diff_error( + r, + h, + "WMS_GetLegendGraphic_MetersAtScaleSymbol_DefaultScale_2056", + max_size_diff=QSize(15, 15), + ) def test_wms_GetLegendGraphic_MetersAtScaleSymbol_Rule_2056(self): # meters at scale symbols on EPSG:2056 calculated with Default Scale set in the projects configuration and having a rule - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_meters_at_scaledsymbols_2056.qgs', - "SERVICE": "WMS", - "REQUEST": "GetLegendGraphic", - "LAYER": "testlayer_2056", - "FORMAT": "image/png", - "CRS": "EPSG:2056", - "WIDTH": "50", - "HEIGHT": "50", - "RULE": "test" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + + "test_project_meters_at_scaledsymbols_2056.qgs", + "SERVICE": "WMS", + "REQUEST": "GetLegendGraphic", + "LAYER": "testlayer_2056", + "FORMAT": "image/png", + "CRS": "EPSG:2056", + "WIDTH": "50", + "HEIGHT": "50", + "RULE": "test", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_MetersAtScaleSymbol_Rule_2056", max_size_diff=QSize(15, 15)) + self._img_diff_error( + r, + h, + "WMS_GetLegendGraphic_MetersAtScaleSymbol_Rule_2056", + max_size_diff=QSize(15, 15), + ) def test_wms_GetLegendGraphic_LAYERFONTCOLOR(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello", - "FORMAT": "image/png", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily, - "LAYERFONTCOLOR": "red" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + "LAYERFONTCOLOR": "red", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_LAYERFONTCOLOR", max_size_diff=QSize(10, 10)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_LAYERFONTCOLOR", max_size_diff=QSize(10, 10) + ) def test_wms_GetLegendGraphic_ITEMFONTCOLOR(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello", - "FORMAT": "image/png", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily, - "ITEMFONTCOLOR": "red" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + "ITEMFONTCOLOR": "red", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_ITEMFONTCOLOR", max_size_diff=QSize(10, 10)) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_ITEMFONTCOLOR", max_size_diff=QSize(10, 10) + ) def test_wms_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello", - "FORMAT": "image/png", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily, - "ITEMFONTCOLOR": "red", - "LAYERFONTCOLOR": "blue" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + "ITEMFONTCOLOR": "red", + "LAYERFONTCOLOR": "blue", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR", max_size_diff=QSize(10, 10)) + self._img_diff_error( + r, + h, + "WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR", + max_size_diff=QSize(10, 10), + ) def test_wms_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR_hex(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello", - "FORMAT": "image/png", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily, - "ITEMFONTCOLOR": r"%23FF0000", - "LAYERFONTCOLOR": r"%230000FF" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + "ITEMFONTCOLOR": r"%23FF0000", + "LAYERFONTCOLOR": r"%230000FF", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR", max_size_diff=QSize(10, 10)) + self._img_diff_error( + r, + h, + "WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR", + max_size_diff=QSize(10, 10), + ) def test_BBoxNoWidthNoHeight(self): """Test with BBOX and no width/height (like QGIS client does)""" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_wms_grouped_nested_layers.qgs', - "SERVICE": "WMS", - "VERSION": "1.3", - "REQUEST": "GetLegendGraphic", - "LAYER": "areas%20and%20symbols", - "FORMAT": "image/png", - "CRS": "EPSG:4326", - "BBOX": "52.44462990911360123,10.6723591605239374,52.44631832182876963,10.6795952150175264", - "SLD_VERSION": "1.1", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + + "test_project_wms_grouped_nested_layers.qgs", + "SERVICE": "WMS", + "VERSION": "1.3", + "REQUEST": "GetLegendGraphic", + "LAYER": "areas%20and%20symbols", + "FORMAT": "image/png", + "CRS": "EPSG:4326", + "BBOX": "52.44462990911360123,10.6723591605239374,52.44631832182876963,10.6795952150175264", + "SLD_VERSION": "1.1", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self.assertNotIn(b'Exception', r) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_NoWidthNoHeight", max_size_diff=QSize(10, 2)) + self.assertNotIn(b"Exception", r) + self._img_diff_error( + r, h, "WMS_GetLegendGraphic_NoWidthNoHeight", max_size_diff=QSize(10, 2) + ) def testGetLegendGraphicRegression32020(self): """When two classes have the same symbol they both are shown in the contextual @@ -1129,153 +1573,221 @@ def testGetLegendGraphicRegression32020(self): """ # Visible is "Type 1" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'bug_gh32020.qgs', - "SERVICE": "WMS", - "VERSION": "1.3", - "REQUEST": "GetLegendGraphic", - "LAYER": "test_layer", - "FORMAT": "image/png", - "CRS": "EPSG:4326", - "BBOX": "0.05148830809982496426,-2.237691019614711507,0.8090701330998248952,-0.2050896957968479928", - "SLD_VERSION": "1.1", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + "bug_gh32020.qgs", + "SERVICE": "WMS", + "VERSION": "1.3", + "REQUEST": "GetLegendGraphic", + "LAYER": "test_layer", + "FORMAT": "image/png", + "CRS": "EPSG:4326", + "BBOX": "0.05148830809982496426,-2.237691019614711507,0.8090701330998248952,-0.2050896957968479928", + "SLD_VERSION": "1.1", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self.assertNotIn(b'Exception', r) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_Regression32020_type1", max_size_diff=QSize(10, 5)) + self.assertNotIn(b"Exception", r) + self._img_diff_error( + r, + h, + "WMS_GetLegendGraphic_Regression32020_type1", + max_size_diff=QSize(10, 5), + ) # Visible is "Type 2" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'bug_gh32020.qgs', - "SERVICE": "WMS", - "VERSION": "1.3", - "REQUEST": "GetLegendGraphic", - "LAYER": "test_layer", - "FORMAT": "image/png", - "CRS": "EPSG:4326", - "BBOX": "0.02893333257443075901,-0.2568334631786342026,1.544096982574430621,3.808369184457092604", - "SLD_VERSION": "1.1", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + "bug_gh32020.qgs", + "SERVICE": "WMS", + "VERSION": "1.3", + "REQUEST": "GetLegendGraphic", + "LAYER": "test_layer", + "FORMAT": "image/png", + "CRS": "EPSG:4326", + "BBOX": "0.02893333257443075901,-0.2568334631786342026,1.544096982574430621,3.808369184457092604", + "SLD_VERSION": "1.1", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self.assertNotIn(b'Exception', r) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_Regression32020_type2", max_size_diff=QSize(10, 5)) + self.assertNotIn(b"Exception", r) + self._img_diff_error( + r, + h, + "WMS_GetLegendGraphic_Regression32020_type2", + max_size_diff=QSize(10, 5), + ) # Visible is "Type 2" and 3 - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'bug_gh32020.qgs', - "SERVICE": "WMS", - "VERSION": "1.3", - "REQUEST": "GetLegendGraphic", - "LAYER": "test_layer", - "FORMAT": "image/png", - "CRS": "EPSG:4326", - "BBOX": "-0.6636370923817864753,-0.2886757815674259042,0.8515265576182133866,3.776526866068300681", - "SLD_VERSION": "1.1", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + "bug_gh32020.qgs", + "SERVICE": "WMS", + "VERSION": "1.3", + "REQUEST": "GetLegendGraphic", + "LAYER": "test_layer", + "FORMAT": "image/png", + "CRS": "EPSG:4326", + "BBOX": "-0.6636370923817864753,-0.2886757815674259042,0.8515265576182133866,3.776526866068300681", + "SLD_VERSION": "1.1", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self.assertNotIn(b'Exception', r) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_Regression32020_type2_and_3", max_size_diff=QSize(10, 5)) + self.assertNotIn(b"Exception", r) + self._img_diff_error( + r, + h, + "WMS_GetLegendGraphic_Regression32020_type2_and_3", + max_size_diff=QSize(10, 5), + ) # Visible is "Type 1" and 3 - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'bug_gh32020.qgs', - "SERVICE": "WMS", - "VERSION": "1.3", - "REQUEST": "GetLegendGraphic", - "LAYER": "test_layer", - "FORMAT": "image/png", - "CRS": "EPSG:4326", - "BBOX": "-0.5787242433450088264,-4.316729057749563836,0.9364394066549910356,-0.2515264101138368069", - "SLD_VERSION": "1.1", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + "bug_gh32020.qgs", + "SERVICE": "WMS", + "VERSION": "1.3", + "REQUEST": "GetLegendGraphic", + "LAYER": "test_layer", + "FORMAT": "image/png", + "CRS": "EPSG:4326", + "BBOX": "-0.5787242433450088264,-4.316729057749563836,0.9364394066549910356,-0.2515264101138368069", + "SLD_VERSION": "1.1", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self.assertNotIn(b'Exception', r) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_Regression32020_type1_and_3", max_size_diff=QSize(10, 5)) + self.assertNotIn(b"Exception", r) + self._img_diff_error( + r, + h, + "WMS_GetLegendGraphic_Regression32020_type1_and_3", + max_size_diff=QSize(10, 5), + ) # Change CRS: 3857 # Visible is "Type 2" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'bug_gh32020.qgs', - "SERVICE": "WMS", - "VERSION": "1.3", - "REQUEST": "GetLegendGraphic", - "LAYER": "test_layer", - "FORMAT": "image/png", - "CRS": "EPSG:3857", - "BBOX": "-28147.15420315234223,3960.286488616475253,424402.4530122592696,172632.4964886165108", - "SLD_VERSION": "1.1", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + "bug_gh32020.qgs", + "SERVICE": "WMS", + "VERSION": "1.3", + "REQUEST": "GetLegendGraphic", + "LAYER": "test_layer", + "FORMAT": "image/png", + "CRS": "EPSG:3857", + "BBOX": "-28147.15420315234223,3960.286488616475253,424402.4530122592696,172632.4964886165108", + "SLD_VERSION": "1.1", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self.assertNotIn(b'Exception', r) - self._img_diff_error(r, h, "WMS_GetLegendGraphic_Regression32020_type2_3857", max_size_diff=QSize(10, 5)) + self.assertNotIn(b"Exception", r) + self._img_diff_error( + r, + h, + "WMS_GetLegendGraphic_Regression32020_type2_3857", + max_size_diff=QSize(10, 5), + ) def test_wms_GetLegendGraphic_JSON(self): - self.wms_request_compare("GetLegendGraphic", - "&LAYERS=testlayer%20%C3%A8%C3%A9" - "&FORMAT=application/json", - ["wms_getlegendgraphic_json", "wms_getlegendgraphic_json2"]) + self.wms_request_compare( + "GetLegendGraphic", + "&LAYERS=testlayer%20%C3%A8%C3%A9" "&FORMAT=application/json", + ["wms_getlegendgraphic_json", "wms_getlegendgraphic_json2"], + ) def test_wms_GetLegendGraphic_JSON_multiple_layers(self): - self.wms_request_compare("GetLegendGraphic", - "&LAYERS=testlayer%20%C3%A8%C3%A9,testlayer3" - "&FORMAT=application/json", - ["wms_getlegendgraphic_json_multiple_layers", "wms_getlegendgraphic_json_multiple_layers2", "wms_getlegendgraphic_json_multiple_layers3"]) + self.wms_request_compare( + "GetLegendGraphic", + "&LAYERS=testlayer%20%C3%A8%C3%A9,testlayer3" "&FORMAT=application/json", + [ + "wms_getlegendgraphic_json_multiple_layers", + "wms_getlegendgraphic_json_multiple_layers2", + "wms_getlegendgraphic_json_multiple_layers3", + ], + ) def test_wms_GetLegendGraphic_JSON_multiple_symbol(self): - self.wms_request_compare("GetLegendGraphic", - "&LAYERS=cdb_lines" - "&FORMAT=application/json", - ["wms_getlegendgraphic_json_multiple_symbol", "wms_getlegendgraphic_json_multiple_symbol2"], - 'test_project_wms_grouped_layers.qgs') + self.wms_request_compare( + "GetLegendGraphic", + "&LAYERS=cdb_lines" "&FORMAT=application/json", + [ + "wms_getlegendgraphic_json_multiple_symbol", + "wms_getlegendgraphic_json_multiple_symbol2", + ], + "test_project_wms_grouped_layers.qgs", + ) def testJsonSymbolMaxMinScale(self): """Test min/max scale in symbol json export""" project = QgsProject() - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") - symbol = QgsMarkerSymbol.createSimple( - {'name': 'square', 'color': 'red'}) + symbol = QgsMarkerSymbol.createSimple({"name": "square", "color": "red"}) scale_min = 10000 scale_max = 1000 - rule = QgsRuleBasedRenderer.Rule(symbol, scale_min, scale_max, '') + rule = QgsRuleBasedRenderer.Rule(symbol, scale_min, scale_max, "") rootrule = QgsRuleBasedRenderer.Rule(None) rootrule.appendChild(rule) layer.setRenderer(QgsRuleBasedRenderer(rootrule)) @@ -1283,32 +1795,41 @@ def testJsonSymbolMaxMinScale(self): project.addMapLayers([layer]) server = QgsServer() - request = QgsBufferServerRequest("/?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetLegendGraphic" + - "&LAYERS=layer1" + - "&FORMAT=application/json") + request = QgsBufferServerRequest( + "/?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetLegendGraphic" + + "&LAYERS=layer1" + + "&FORMAT=application/json" + ) response = QgsBufferServerResponse() server.handleRequest(request, response, project) j = json.loads(bytes(response.body())) - node = j['nodes'][0] - self.assertEqual(node['scaleMaxDenom'], 1000) - self.assertEqual(node['scaleMinDenom'], 10000) + node = j["nodes"][0] + self.assertEqual(node["scaleMaxDenom"], 1000) + self.assertEqual(node["scaleMinDenom"], 10000) def test_json_rule_based_max_min_scale_without_symbol(self): - """ Test min/max scale in rule based json export when a rule doesn't have a symbol. """ + """Test min/max scale in rule based json export when a rule doesn't have a symbol.""" root_rule = QgsRuleBasedRenderer.Rule(None) # Rule with symbol high_scale_rule = QgsRuleBasedRenderer.Rule( QgsSymbol.defaultSymbol(QgsWkbTypes.GeometryType.PointGeometry), - minimumScale=25000, maximumScale=1000, label='high-scale') + minimumScale=25000, + maximumScale=1000, + label="high-scale", + ) root_rule.appendChild(high_scale_rule) # Rule without symbol - low_scale_rule = QgsRuleBasedRenderer.Rule(None, minimumScale=100000, maximumScale=25000, label='low-scale') + low_scale_rule = QgsRuleBasedRenderer.Rule( + None, minimumScale=100000, maximumScale=25000, label="low-scale" + ) # Sub-rule with a symbol sub_rule = QgsRuleBasedRenderer.Rule( - QgsSymbol.defaultSymbol(QgsWkbTypes.GeometryType.PointGeometry), label='low-scale-sub') + QgsSymbol.defaultSymbol(QgsWkbTypes.GeometryType.PointGeometry), + label="low-scale-sub", + ) low_scale_rule.appendChild(sub_rule) root_rule.appendChild(low_scale_rule) @@ -1332,37 +1853,45 @@ def test_json_rule_based_max_min_scale_without_symbol(self): server.handleRequest(request, response, project) result = json.loads(bytes(response.body())) - node = result['nodes'][0]['symbols'] + node = result["nodes"][0]["symbols"] # With icon first_rule = node[0] - self.assertEqual(first_rule['scaleMaxDenom'], 25000) - self.assertEqual(first_rule['scaleMinDenom'], 1000) - self.assertEqual(first_rule['title'], 'high-scale') - self.assertIn('icon', first_rule) + self.assertEqual(first_rule["scaleMaxDenom"], 25000) + self.assertEqual(first_rule["scaleMinDenom"], 1000) + self.assertEqual(first_rule["title"], "high-scale") + self.assertIn("icon", first_rule) # Without icon second_rule = node[1] - self.assertEqual(second_rule['scaleMaxDenom'], 100000) - self.assertEqual(second_rule['scaleMinDenom'], 25000) - self.assertEqual(second_rule['title'], 'low-scale') - self.assertNotIn('icon', second_rule) + self.assertEqual(second_rule["scaleMaxDenom"], 100000) + self.assertEqual(second_rule["scaleMinDenom"], 25000) + self.assertEqual(second_rule["title"], "low-scale") + self.assertNotIn("icon", second_rule) def testLegendPlaceholderIcon(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": self.testdata_path + 'test_project_legend_placeholder_image.qgs', - "SERVICE": "WMS", - "VERSION": "1.3", - "REQUEST": "GetLegendGraphic", - "LAYER": "landsat", - "FORMAT": "image/png", - "LAYERFONTBOLD": "TRUE", - "LAYERFONTSIZE": "12", - "LAYERFONTFAMILY": self.fontFamily, - "ITEMFONTBOLD": "TRUE", - "ITEMFONTSIZE": "12", - "ITEMFONTFAMILY": self.fontFamily - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": self.testdata_path + + "test_project_legend_placeholder_image.qgs", + "SERVICE": "WMS", + "VERSION": "1.3", + "REQUEST": "GetLegendGraphic", + "LAYER": "landsat", + "FORMAT": "image/png", + "LAYERFONTBOLD": "TRUE", + "LAYERFONTSIZE": "12", + "LAYERFONTFAMILY": self.fontFamily, + "ITEMFONTBOLD": "TRUE", + "ITEMFONTSIZE": "12", + "ITEMFONTFAMILY": self.fontFamily, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetLegendGraphic_Legend_Placeholder_Icon") @@ -1370,15 +1899,15 @@ def testLegendPlaceholderIcon(self): def test_wms_GetLegendGraphic_JSON_rule_details(self): project = QgsProject() - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") - symbol = QgsMarkerSymbol.createSimple( - {'name': 'square', 'color': 'red'}) + symbol = QgsMarkerSymbol.createSimple({"name": "square", "color": "red"}) scale_min = 10000 scale_max = 1000 - rule = QgsRuleBasedRenderer.Rule(symbol, scale_min, scale_max, "fldtxt = 'one'", 'label1', 'description1') + rule = QgsRuleBasedRenderer.Rule( + symbol, scale_min, scale_max, "fldtxt = 'one'", "label1", "description1" + ) rootrule = QgsRuleBasedRenderer.Rule(None) rootrule.appendChild(rule) layer.setRenderer(QgsRuleBasedRenderer(rootrule)) @@ -1386,35 +1915,41 @@ def test_wms_GetLegendGraphic_JSON_rule_details(self): project.addMapLayers([layer]) server = QgsServer() - request = QgsBufferServerRequest("/?SERVICE=WMS&VERSION=1.30&REQUEST=GetLegendGraphic" + - "&LAYERS=layer1" + - "&FORMAT=application/json" + - "&SHOWRULEDETAILS=1") + request = QgsBufferServerRequest( + "/?SERVICE=WMS&VERSION=1.30&REQUEST=GetLegendGraphic" + + "&LAYERS=layer1" + + "&FORMAT=application/json" + + "&SHOWRULEDETAILS=1" + ) response = QgsBufferServerResponse() server.handleRequest(request, response, project) j = json.loads(bytes(response.body())) - node = j['nodes'][0] - self.assertEqual(node['scaleMaxDenom'], 1000) - self.assertEqual(node['scaleMinDenom'], 10000) - self.assertEqual(node['rule'], "(fldtxt = 'one') AND (@map_scale <= 1000) AND (@map_scale >= 10000)") + node = j["nodes"][0] + self.assertEqual(node["scaleMaxDenom"], 1000) + self.assertEqual(node["scaleMinDenom"], 10000) + self.assertEqual( + node["rule"], + "(fldtxt = 'one') AND (@map_scale <= 1000) AND (@map_scale >= 10000)", + ) # Add a second rule project = QgsProject() - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") - symbol1 = QgsMarkerSymbol.createSimple( - {'name': 'square', 'color': 'red'}) - symbol2 = QgsMarkerSymbol.createSimple( - {'name': 'square', 'color': 'green'}) + symbol1 = QgsMarkerSymbol.createSimple({"name": "square", "color": "red"}) + symbol2 = QgsMarkerSymbol.createSimple({"name": "square", "color": "green"}) scale_min = 10000 scale_max = 1000 rootrule = QgsRuleBasedRenderer.Rule(None) - rule1 = QgsRuleBasedRenderer.Rule(symbol1, scale_min, scale_max, "fldtxt = 'one'", 'label1', 'description1') + rule1 = QgsRuleBasedRenderer.Rule( + symbol1, scale_min, scale_max, "fldtxt = 'one'", "label1", "description1" + ) rootrule.appendChild(rule1) - rule2 = QgsRuleBasedRenderer.Rule(symbol2, scale_min, scale_max, "fldtxt = 'two'", 'label2', 'description2') + rule2 = QgsRuleBasedRenderer.Rule( + symbol2, scale_min, scale_max, "fldtxt = 'two'", "label2", "description2" + ) rootrule.appendChild(rule2) layer.setRenderer(QgsRuleBasedRenderer(rootrule)) @@ -1422,90 +1957,107 @@ def test_wms_GetLegendGraphic_JSON_rule_details(self): server = QgsServer() - request = QgsBufferServerRequest("/?SERVICE=WMS&VERSION=1.30&REQUEST=GetLegendGraphic" + - "&LAYERS=layer1" + - "&FORMAT=application/json" + - "&SHOWRULEDETAILS=1") + request = QgsBufferServerRequest( + "/?SERVICE=WMS&VERSION=1.30&REQUEST=GetLegendGraphic" + + "&LAYERS=layer1" + + "&FORMAT=application/json" + + "&SHOWRULEDETAILS=1" + ) response = QgsBufferServerResponse() server.handleRequest(request, response, project) j = json.loads(bytes(response.body())) node = j - self.assertEqual(node['nodes'][0]['symbols'][0]['rule'], "(fldtxt = 'one') AND (@map_scale <= 1000) AND (@map_scale >= 10000)") - self.assertEqual(node['nodes'][0]['symbols'][1]['rule'], "(fldtxt = 'two') AND (@map_scale <= 1000) AND (@map_scale >= 10000)") + self.assertEqual( + node["nodes"][0]["symbols"][0]["rule"], + "(fldtxt = 'one') AND (@map_scale <= 1000) AND (@map_scale >= 10000)", + ) + self.assertEqual( + node["nodes"][0]["symbols"][1]["rule"], + "(fldtxt = 'two') AND (@map_scale <= 1000) AND (@map_scale >= 10000)", + ) def test_wms_GetLegendGraphic_JSON_rule_filter(self): project = QgsProject() - layer = QgsVectorLayer("Point?field=fldtxt:string", - "layer1", "memory") + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") - symbol1 = QgsMarkerSymbol.createSimple( - {'name': 'square', 'color': 'red'}) - symbol2 = QgsMarkerSymbol.createSimple( - {'name': 'square', 'color': 'green'}) + symbol1 = QgsMarkerSymbol.createSimple({"name": "square", "color": "red"}) + symbol2 = QgsMarkerSymbol.createSimple({"name": "square", "color": "green"}) scale_min = 10000 scale_max = 1000 rootrule = QgsRuleBasedRenderer.Rule(None) - rule1 = QgsRuleBasedRenderer.Rule(symbol1, scale_min, scale_max, "fldtxt = 'one'", 'label1', 'description1') + rule1 = QgsRuleBasedRenderer.Rule( + symbol1, scale_min, scale_max, "fldtxt = 'one'", "label1", "description1" + ) rootrule.appendChild(rule1) - rule2 = QgsRuleBasedRenderer.Rule(symbol2, scale_min, scale_max, "fldtxt = 'two'", 'label2', 'description2') + rule2 = QgsRuleBasedRenderer.Rule( + symbol2, scale_min, scale_max, "fldtxt = 'two'", "label2", "description2" + ) rootrule.appendChild(rule2) layer.setRenderer(QgsRuleBasedRenderer(rootrule)) project.addMapLayers([layer]) server = QgsServer() - request = QgsBufferServerRequest("/?SERVICE=WMS&VERSION=1.30&REQUEST=GetLegendGraphic" + - "&LAYERS=layer1" + - "&FORMAT=application/json" + - "&RULE=label2" + - "&SHOWRULEDETAILS=1") + request = QgsBufferServerRequest( + "/?SERVICE=WMS&VERSION=1.30&REQUEST=GetLegendGraphic" + + "&LAYERS=layer1" + + "&FORMAT=application/json" + + "&RULE=label2" + + "&SHOWRULEDETAILS=1" + ) response = QgsBufferServerResponse() server.handleRequest(request, response, project) j = json.loads(bytes(response.body())) node = j - self.assertEqual(node['scaleMaxDenom'], 1000) - self.assertEqual(node['scaleMinDenom'], 10000) - self.assertEqual(node['rule'], "(fldtxt = 'two') AND (@map_scale <= 1000) AND (@map_scale >= 10000)") - - icon = node['icon'] - request = QgsBufferServerRequest("/?SERVICE=WMS&VERSION=1.30&REQUEST=GetLegendGraphic" + - "&LAYERS=layer1" + - "&FORMAT=application/json" + - "&RULE=label2") + self.assertEqual(node["scaleMaxDenom"], 1000) + self.assertEqual(node["scaleMinDenom"], 10000) + self.assertEqual( + node["rule"], + "(fldtxt = 'two') AND (@map_scale <= 1000) AND (@map_scale >= 10000)", + ) + + icon = node["icon"] + request = QgsBufferServerRequest( + "/?SERVICE=WMS&VERSION=1.30&REQUEST=GetLegendGraphic" + + "&LAYERS=layer1" + + "&FORMAT=application/json" + + "&RULE=label2" + ) response = QgsBufferServerResponse() server.handleRequest(request, response, project) j = json.loads(bytes(response.body())) node = j - self.assertEqual(node['icon'], icon) + self.assertEqual(node["icon"], icon) def test_wms_GetLegendGraphic_JSON_raster_color_ramp(self): """Test raster color ramp legend in JSON format""" project = QgsProject() - path = os.path.join(unitTestDataPath('raster'), - 'byte.tif') + path = os.path.join(unitTestDataPath("raster"), "byte.tif") layer = QgsRasterLayer(path, "layer1") self.assertTrue(layer.isValid()) project.addMapLayers([layer]) server = QgsServer() - request = QgsBufferServerRequest("/?SERVICE=WMS&VERSION=1.30&REQUEST=GetLegendGraphic" + - "&LAYERS=layer1" + - "&FORMAT=application/json") + request = QgsBufferServerRequest( + "/?SERVICE=WMS&VERSION=1.30&REQUEST=GetLegendGraphic" + + "&LAYERS=layer1" + + "&FORMAT=application/json" + ) response = QgsBufferServerResponse() server.handleRequest(request, response, project) j = json.loads(bytes(response.body())) node = j - self.assertEqual(node['nodes'][0]['symbols'][0]['title'], 'Band 1 (Gray)') - self.assertEqual(node['nodes'][0]['symbols'][1]['max'], 255) - self.assertEqual(node['nodes'][0]['symbols'][1]['min'], 74) - self.assertNotEqual(node['nodes'][0]['symbols'][1]['icon'], '') + self.assertEqual(node["nodes"][0]["symbols"][0]["title"], "Band 1 (Gray)") + self.assertEqual(node["nodes"][0]["symbols"][1]["max"], 255) + self.assertEqual(node["nodes"][0]["symbols"][1]["min"], 74) + self.assertNotEqual(node["nodes"][0]["symbols"][1]["icon"], "") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_wms_getmap.py b/tests/src/python/test_qgsserver_wms_getmap.py index 5763c7f98d9f..6210a55d0788 100644 --- a/tests/src/python/test_qgsserver_wms_getmap.py +++ b/tests/src/python/test_qgsserver_wms_getmap.py @@ -9,14 +9,15 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '25/05/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "25/05/2015" +__copyright__ = "Copyright 2015, The QGIS Project" import os # Needed on Qt 5 so that the serialization of XML is consistent among all executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" import urllib.error import urllib.parse @@ -49,8 +50,8 @@ from utilities import unitTestDataPath # Strip path and content length because path may vary -RE_STRIP_UNCHECKABLE = br'MAP=[^"]+|Content-Length: \d+' -RE_ATTRIBUTES = br'[^>\s]+=[^>\s]+' +RE_STRIP_UNCHECKABLE = rb'MAP=[^"]+|Content-Length: \d+' +RE_ATTRIBUTES = rb"[^>\s]+=[^>\s]+" class TestQgsServerWMSGetMap(QgsServerTestBase): @@ -60,215 +61,299 @@ class TestQgsServerWMSGetMap(QgsServerTestBase): def test_wms_getmap_basic_mode(self): # 1 bits - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png; mode=1bit", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png; mode=1bit", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Mode_1bit", 20000) # 8 bits - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png; mode=8bit", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png; mode=8bit", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Mode_8bit", 20000) # 16 bits - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png; mode=16bit", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png; mode=16bit", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Mode_16bit", 20000) # webp - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/webp", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) - - r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetMap_Mode_16bit", 20000, outputFormat='WEBP') + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/webp", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) + + r, h = self._result(self._execute_request(qs)) + self._img_diff_error(r, h, "WMS_GetMap_Mode_16bit", 20000, outputFormat="WEBP") def test_wms_getmap_basic(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Basic") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,dem", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,dem", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Basic2") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectUseLayerIdsPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "country20131022151106556", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectUseLayerIdsPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "country20131022151106556", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Basic3") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,db_point", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,db_point", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Basic4") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "sERVICE": "WMS", - "VeRSION": "1.1.1", - "REqUEST": "GetMap", - "LAYeRS": "Country,db_point", - "STYLeS": "", - "FORMAt": "image/png", - "bBOX": "-16817707,-4710778,5696513,14587125", - "HeIGHT": "500", - "WIDTH": "500", - "CRs": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "sERVICE": "WMS", + "VeRSION": "1.1.1", + "REqUEST": "GetMap", + "LAYeRS": "Country,db_point", + "STYLeS": "", + "FORMAt": "image/png", + "bBOX": "-16817707,-4710778,5696513,14587125", + "HeIGHT": "500", + "WIDTH": "500", + "CRs": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Basic4") def test_wms_getmap_complex_labeling(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "pointlabel", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "pointlabel", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Labeling_Complex") def test_wms_getmap_context_rendering(self): project = os.path.join(self.testdata_path, "test_project_render_context.qgs") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "points", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-119.8,20.4,-82.4,49.2", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:4326" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "points", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-119.8,20.4,-82.4,49.2", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:4326", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_ContextRendering") def test_wms_getmap_dpi(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "DPI": "112.5" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "DPI": "112.5", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Basic5") @@ -277,20 +362,27 @@ def test_wms_getmap_dpi(self): self.assertEqual(round(img.dotsPerMeterY() / 39.37, 1), 112.5) def test_wms_getmap_dpi_png_8bit(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png; mode=8bit", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "DPI": "112.5" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png; mode=8bit", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "DPI": "112.5", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) img = QImage.fromData(r, "PNG") @@ -299,350 +391,497 @@ def test_wms_getmap_dpi_png_8bit(self): def test_wms_getmap_invalid_parameters(self): # invalid format - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "pdf", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) - - r, h = self._result(self._execute_request(qs)) - err = b"The format \'pdf\' from FORMAT is not supported." in r + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "pdf", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) + + r, h = self._result(self._execute_request(qs)) + err = b"The format 'pdf' from FORMAT is not supported." in r self.assertTrue(err) # height should be an int - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "FOO", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) - - r, h = self._result(self._execute_request(qs)) - err = b"HEIGHT (\'FOO\') cannot be converted into int" in r + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "FOO", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) + + r, h = self._result(self._execute_request(qs)) + err = b"HEIGHT ('FOO') cannot be converted into int" in r self.assertTrue(err) # height should be > 0 - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "-1", - "WIDTH": "1", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "-1", + "WIDTH": "1", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) err = b"The requested map size is too large" in r self.assertTrue(err) # width should be an int - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "FOO", - "CRS": "EPSG:3857" - }.items())]) - - r, h = self._result(self._execute_request(qs)) - err = b"WIDTH (\'FOO\') cannot be converted into int" in r + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "FOO", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) + + r, h = self._result(self._execute_request(qs)) + err = b"WIDTH ('FOO') cannot be converted into int" in r self.assertTrue(err) # width should be > 0 - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "1", - "WIDTH": "-1", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "1", + "WIDTH": "-1", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) err = b"The requested map size is too large" in r self.assertTrue(err) # bbox should be formatted like "double,double,double,double" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) - - r, h = self._result(self._execute_request(qs)) - err = b"BBOX (\'-16817707,-4710778,5696513\') cannot be converted into a rectangle" in r + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) + + r, h = self._result(self._execute_request(qs)) + err = ( + b"BBOX ('-16817707,-4710778,5696513') cannot be converted into a rectangle" + in r + ) self.assertTrue(err) - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,FOO", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) - - r, h = self._result(self._execute_request(qs)) - err = b"BBOX (\'-16817707,-4710778,5696513,FOO\') cannot be converted into a rectangle" in r + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,FOO", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) + + r, h = self._result(self._execute_request(qs)) + err = ( + b"BBOX ('-16817707,-4710778,5696513,FOO') cannot be converted into a rectangle" + in r + ) self.assertTrue(err) # test invalid bbox : xmin > xmax - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "1,0,0,1", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "1,0,0,1", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) err = b"cannot be converted into a rectangle" in r self.assertTrue(err) # test invalid bbox : ymin > ymax - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "0,1,0,0", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "0,1,0,0", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) err = b"cannot be converted into a rectangle" in r self.assertTrue(err) # opacities should be a list of int - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "OPACITIES": "253,FOO", - "CRS": "EPSG:3857" - }.items())]) - - r, h = self._result(self._execute_request(qs)) - err = b"OPACITIES (\'253,FOO\') cannot be converted into a list of int" in r + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "OPACITIES": "253,FOO", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) + + r, h = self._result(self._execute_request(qs)) + err = b"OPACITIES ('253,FOO') cannot be converted into a list of int" in r self.assertTrue(err) # filters should be formatted like "layer0:filter0;layer1:filter1" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "FILTER": "Country \"name\" = 'eurasia'" - }.items())]) - - r, h = self._result(self._execute_request(qs)) - err = b"FILTER (\'Country \"name\" = \'eurasia\'\') is not properly formatted" in r + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "FILTER": "Country \"name\" = 'eurasia'", + }.items() + ) + ] + ) + + r, h = self._result(self._execute_request(qs)) + err = b"FILTER ('Country \"name\" = 'eurasia'') is not properly formatted" in r self.assertTrue(err) # selections should be formatted like "layer0:id0,id1;layer1:id0" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "SELECTION": "Country=4" - }.items())]) - - r, h = self._result(self._execute_request(qs)) - err = b"SELECTION (\'Country=4\') is not properly formatted" in r + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "SELECTION": "Country=4", + }.items() + ) + ] + ) + + r, h = self._result(self._execute_request(qs)) + err = b"SELECTION ('Country=4') is not properly formatted" in r self.assertTrue(err) # invalid highlight geometries - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country_Labels", - "HIGHLIGHT_GEOM": "POLYGONN((-15000000 10000000, -15000000 6110620, 2500000 6110620, 2500000 10000000, -15000000 10000000))", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) - - r, h = self._result(self._execute_request(qs)) - err = b"HIGHLIGHT_GEOM (\'POLYGONN((-15000000 10000000, -15000000 6110620, 2500000 6110620, 2500000 10000000, -15000000 10000000))\') cannot be converted into a list of geometries" in r + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country_Labels", + "HIGHLIGHT_GEOM": "POLYGONN((-15000000 10000000, -15000000 6110620, 2500000 6110620, 2500000 10000000, -15000000 10000000))", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) + + r, h = self._result(self._execute_request(qs)) + err = ( + b"HIGHLIGHT_GEOM ('POLYGONN((-15000000 10000000, -15000000 6110620, 2500000 6110620, 2500000 10000000, -15000000 10000000))') cannot be converted into a list of geometries" + in r + ) self.assertTrue(err) # invalid highlight label colors - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country_Labels", - "HIGHLIGHT_LABELCOLOR": "%2300230000;%230023000", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) - - r, h = self._result(self._execute_request(qs)) - err = b"HIGHLIGHT_LABELCOLOR (\'#00230000;#0023000\') cannot be converted into a list of colors" in r + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country_Labels", + "HIGHLIGHT_LABELCOLOR": "%2300230000;%230023000", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) + + r, h = self._result(self._execute_request(qs)) + err = ( + b"HIGHLIGHT_LABELCOLOR ('#00230000;#0023000') cannot be converted into a list of colors" + in r + ) self.assertTrue(err) # invalid list of label sizes - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country_Labels", - "HIGHLIGHT_LABELSIZE": "16;17;FOO", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) - - r, h = self._result(self._execute_request(qs)) - err = b"HIGHLIGHT_LABELSIZE (\'16;17;FOO\') cannot be converted into a list of int" in r + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country_Labels", + "HIGHLIGHT_LABELSIZE": "16;17;FOO", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) + + r, h = self._result(self._execute_request(qs)) + err = ( + b"HIGHLIGHT_LABELSIZE ('16;17;FOO') cannot be converted into a list of int" + in r + ) self.assertTrue(err) # invalid list of label buffer size - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country_Labels", - "HIGHLIGHT_LABELBUFFERSIZE": "1.5;2;FF", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) - - r, h = self._result(self._execute_request(qs)) - err = b"HIGHLIGHT_LABELBUFFERSIZE (\'1.5;2;FF\') cannot be converted into a list of float" in r + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country_Labels", + "HIGHLIGHT_LABELBUFFERSIZE": "1.5;2;FF", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) + + r, h = self._result(self._execute_request(qs)) + err = ( + b"HIGHLIGHT_LABELBUFFERSIZE ('1.5;2;FF') cannot be converted into a list of float" + in r + ) self.assertTrue(err) # invalid buffer color - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country_Labels", - "HIGHLIGHT_LABELBUFFERCOLOR": "%232300FF00;%232300FF0", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) - - r, h = self._result(self._execute_request(qs)) - err = b"HIGHLIGHT_LABELBUFFERCOLOR (\'#2300FF00;#2300FF0\') cannot be converted into a list of colors" in r + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country_Labels", + "HIGHLIGHT_LABELBUFFERCOLOR": "%232300FF00;%232300FF0", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) + + r, h = self._result(self._execute_request(qs)) + err = ( + b"HIGHLIGHT_LABELBUFFERCOLOR ('#2300FF00;#2300FF0') cannot be converted into a list of colors" + in r + ) self.assertTrue(err) def test_wms_getmap_transparent(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "TRANSPARENT": "TRUE" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "TRANSPARENT": "TRUE", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Transparent") @@ -651,690 +890,938 @@ def test_wms_getmap_labeling_settings(self): # Test the `DrawRectOnly` option # May fail if the labeling position engine is tweaked. - d = unitTestDataPath('qgis_server_accesscontrol') + '/' + d = unitTestDataPath("qgis_server_accesscontrol") + "/" project = os.path.join(d, "project_labeling_settings.qgs") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(project), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country_Labels", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "TRANSPARENT": "TRUE" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(project), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country_Labels", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "TRANSPARENT": "TRUE", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_LabelingSettings") def test_wms_getmap_background(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "BGCOLOR": "green" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "BGCOLOR": "green", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Background") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "BGCOLOR": "0x008000" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "BGCOLOR": "0x008000", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Background_Hex") def test_wms_getmap_order(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Hello,Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Hello,Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_LayerOrder") def test_wms_getmap_srs(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-151.7,-38.9,51.0,78.0", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:4326" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-151.7,-38.9,51.0,78.0", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:4326", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_SRS") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-151.7,-38.9,51.0,78.0", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:4326" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-151.7,-38.9,51.0,78.0", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:4326", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_SRS") def test_wms_getmap_style(self): # default style - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country_Labels", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country_Labels", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_StyleDefault") # custom style with STYLES parameter - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country_Labels", - "STYLES": "custom", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country_Labels", + "STYLES": "custom", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_StyleCustom") # custom style with STYLE parameter - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country_Labels", - "STYLE": "custom", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country_Labels", + "STYLE": "custom", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_StyleCustom") # mixed custom and default style with STYLES parameter - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country_Labels,Hello", - "STYLES": "custom,", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country_Labels,Hello", + "STYLES": "custom,", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_StyleMixed") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Hello,Country_Labels", - "STYLES": "default,custom", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Hello,Country_Labels", + "STYLES": "default,custom", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_StyleMixed_LayerOrder") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Hello,Country_Labels", - "STYLES": ",custom", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Hello,Country_Labels", + "STYLES": ",custom", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_StyleMixed_LayerOrder") def test_wms_getmap_filter(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "FILTER": "Country:\"name\" = 'eurasia'" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "FILTER": "Country:\"name\" = 'eurasia'", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Filter") # try to display a feature yet filtered by the project - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectStatePath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "FILTER": "Country:\"name\" = 'africa'" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectStatePath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "FILTER": "Country:\"name\" = 'africa'", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Filter2") # display all features to check that initial filter is restored - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectStatePath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectStatePath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Filter3") # display multiple features filtered from multiple layers - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectStatePath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello,Hello_Filter_SubsetString", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "FILTER": "Country: \"name\" IN ( 'arctic' , 'eurasia' );Hello: \"color\" = 'red';Hello_Filter_SubsetString: \"color\" = 'slate'" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectStatePath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello,Hello_Filter_SubsetString", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "FILTER": "Country: \"name\" IN ( 'arctic' , 'eurasia' );Hello: \"color\" = 'red';Hello_Filter_SubsetString: \"color\" = 'slate'", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Filter4") # display multiple features filtered from multiple layers with same filter for some - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Country_Diagrams,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "1017529,-4226661,11271098,17063190", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "FILTER": "Country,Country_Diagrams: \"name\" IN ( 'africa' , 'eurasia' );Hello: \"color\" IN ( 'magenta' , 'cerese' )" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Country_Diagrams,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "1017529,-4226661,11271098,17063190", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "FILTER": "Country,Country_Diagrams: \"name\" IN ( 'africa' , 'eurasia' );Hello: \"color\" IN ( 'magenta' , 'cerese' )", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Filter5") # test that filters with colons in values work as expected projectPath = os.path.join(self.testdata_path, "test_project_wms_filter.qgs") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "points", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-80000,25000,-15000,50000.0", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "FILTER": "points:\"name\" = 'foo:bar'" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "points", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-80000,25000,-15000,50000.0", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "FILTER": "points:\"name\" = 'foo:bar'", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Filter6") # Error in filter (missing quote after africa) with multiple layer filter - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Country_Diagrams,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "1017529,-4226661,11271098,17063190", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "FILTER": "Country,Country_Diagrams: \"name\" IN ( 'africa , 'eurasia' );Hello: \"color\" IN ( 'magenta' , 'cerese' )" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Country_Diagrams,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "1017529,-4226661,11271098,17063190", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "FILTER": "Country,Country_Diagrams: \"name\" IN ( 'africa , 'eurasia' );Hello: \"color\" IN ( 'magenta' , 'cerese' )", + }.items() + ) + ] + ) expected = self.strip_version_xmlns( - b'\n\n The filter string "name" IN ( \'africa , \'eurasia\' ) has been rejected because of security reasons. Note: Text strings have to be enclosed in single or double quotes. A space between each word / special character is mandatory. Allowed Keywords and special characters are IS,NOT,NULL,AND,OR,IN,=,<,>=,>,>=,!=,\',\',(,),DMETAPHONE,SOUNDEX. Not allowed are semicolons in the filter expression.\n\n') + b'\n\n The filter string "name" IN ( \'africa , \'eurasia\' ) has been rejected because of security reasons. Note: Text strings have to be enclosed in single or double quotes. A space between each word / special character is mandatory. Allowed Keywords and special characters are IS,NOT,NULL,AND,OR,IN,=,<,>=,>,>=,!=,\',\',(,),DMETAPHONE,SOUNDEX. Not allowed are semicolons in the filter expression.\n\n' + ) r, h = self._result(self._execute_request(qs)) self.assertEqual(self.strip_version_xmlns(r), expected) # Test IS NOT NULL, so display all features - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectStatePath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "FILTER": "Country:\"name\" IS NOT NULL" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectStatePath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "FILTER": 'Country:"name" IS NOT NULL', + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Filter3") def test_wms_getmap_filter_ogc(self): - filter = "name" + \ - "eurasia" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "FILTER": filter - }.items())]) + filter = ( + "name" + + "eurasia" + ) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "FILTER": filter, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Filter_OGC") def test_wms_getmap_filter_ogc_with_empty(self): - filter = "(name" + \ - "eurasia)()" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "FILTER": filter - }.items())]) + filter = ( + "(name" + + "eurasia)()" + ) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "FILTER": filter, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Filter_OGC") # empty filter - filter = ("(" - ")") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "FILTER": filter - }.items())]) + filter = '(' ")" + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "FILTER": filter, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Filter_OGC2") # filter on the second layer - filter_hello = ("()") - filter_country = ("(name" - "eurasia" - ")") + filter_hello = "()" + filter_country = ( + "(name" + "eurasia" + ")" + ) filter = f"{filter_hello}{filter_country}" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Hello,Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "FILTER": filter - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Hello,Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "FILTER": filter, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Filter_OGC3") def test_wms_getmap_filter_ogc_v2(self): # with namespace - filter = ('' - '' - 'name' - 'eurasia' - '' - '') - - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "FILTER": filter - }.items())]) + filter = ( + '' + "" + "name" + "eurasia" + "" + "" + ) + + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "FILTER": filter, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Filter_OGC_V2") # without namespace (only with prefix) - filter = ('' - '' - 'name' - 'eurasia' - '' - '') - - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "FILTER": filter - }.items())]) + filter = ( + "" + "" + "name" + "eurasia" + "" + "" + ) + + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "FILTER": filter, + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Filter_OGC_V2") def test_wms_getmap_selection(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "SRS": "EPSG:3857", - "SELECTION": "Country: 4,1;Hello: 2,5" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "SRS": "EPSG:3857", + "SELECTION": "Country: 4,1;Hello: 2,5", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Selection") def test_wms_getmap_diagrams(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country_Diagrams,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country_Diagrams,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Diagrams") def test_wms_getmap_opacities(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "OPACITIES": "125, 50" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "OPACITIES": "125, 50", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Opacities") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello,dem", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "OPACITIES": "125,50,150" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello,dem", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "OPACITIES": "125,50,150", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Opacities2") # Test OPACITIES with specific STYLES - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello,dem", - "STYLES": "origin,default,default", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "OPACITIES": "125,50,150" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello,dem", + "STYLES": "origin,default,default", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "OPACITIES": "125,50,150", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Opacities3") def test_wms_getmap_highlight(self): # highlight layer with color separated from sld - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country_Labels", - "HIGHLIGHT_GEOM": "POLYGON((-15000000 10000000, -15000000 6110620, 2500000 6110620, 2500000 10000000, -15000000 10000000))", - "HIGHLIGHT_SYMBOL": "HighlightSymbol%23ea117311.6", - "HIGHLIGHT_LABELSTRING": "Highlight Layer!", - "HIGHLIGHT_LABELFONT": "QGIS Vera Sans", - "HIGHLIGHT_LABELSIZE": "20", - "HIGHLIGHT_LABELCOLOR": "%2300FF0000", - "HIGHLIGHT_LABELBUFFERCOLOR": "%232300FF00", - "HIGHLIGHT_LABELBUFFERSIZE": "1.5", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country_Labels", + "HIGHLIGHT_GEOM": "POLYGON((-15000000 10000000, -15000000 6110620, 2500000 6110620, 2500000 10000000, -15000000 10000000))", + "HIGHLIGHT_SYMBOL": 'HighlightSymbol%23ea117311.6', + "HIGHLIGHT_LABELSTRING": "Highlight Layer!", + "HIGHLIGHT_LABELFONT": "QGIS Vera Sans", + "HIGHLIGHT_LABELSIZE": "20", + "HIGHLIGHT_LABELCOLOR": "%2300FF0000", + "HIGHLIGHT_LABELBUFFERCOLOR": "%232300FF00", + "HIGHLIGHT_LABELBUFFERSIZE": "1.5", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Highlight") def test_wms_getmap_highlight_point(self): # checks SLD stroke-width works for Points See issue 19795 comments - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country_Labels", - "HIGHLIGHT_GEOM": "POINT(-6250000 8055310)", - "HIGHLIGHT_SYMBOL": "circle%23ff000017.5%237bdcb5128.4", - "HIGHLIGHT_LABELSTRING": "Highlight Point :)", - "HIGHLIGHT_LABELFONT": "QGIS Vera Sans", - "HIGHLIGHT_LABELSIZE": "20", - "HIGHLIGHT_LABELCOLOR": "%2300FF0000", - "HIGHLIGHT_LABELBUFFERCOLOR": "%232300FF00", - "HIGHLIGHT_LABELBUFFERSIZE": "1.2", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country_Labels", + "HIGHLIGHT_GEOM": "POINT(-6250000 8055310)", + "HIGHLIGHT_SYMBOL": 'circle%23ff000017.5%237bdcb5128.4', + "HIGHLIGHT_LABELSTRING": "Highlight Point :)", + "HIGHLIGHT_LABELFONT": "QGIS Vera Sans", + "HIGHLIGHT_LABELSIZE": "20", + "HIGHLIGHT_LABELCOLOR": "%2300FF0000", + "HIGHLIGHT_LABELBUFFERCOLOR": "%232300FF00", + "HIGHLIGHT_LABELBUFFERSIZE": "1.2", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Highlight_Point") def test_wms_getmap_highlight_point_label_options(self): # checks HIGHLIGHT_LABEL_ROTATION, HIGHLIGHT_LABEL_HORIZONTAL_ALIGNMENT, HIGHLIGHT_LABEL_VERTICAL_ALIGNMENT - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country_Labels", - "HIGHLIGHT_GEOM": "POINT(-6250000 8055310)", - "HIGHLIGHT_SYMBOL": "circle%23ff000017.5%237bdcb5128.4", - "HIGHLIGHT_LABELSTRING": "Highlight Point :)", - "HIGHLIGHT_LABELFONT": "QGIS Vera Sans", - "HIGHLIGHT_LABELSIZE": "20", - "HIGHLIGHT_LABELCOLOR": "%2300FF0000", - "HIGHLIGHT_LABELBUFFERCOLOR": "%232300FF00", - "HIGHLIGHT_LABELBUFFERSIZE": "1.2", - "HIGHLIGHT_LABEL_ROTATION": "45", - "HIGHLIGHT_LABEL_HORIZONTAL_ALIGNMENT": "center", - "HIGHLIGHT_LABEL_VERTICAL_ALIGNMENT": "half", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country_Labels", + "HIGHLIGHT_GEOM": "POINT(-6250000 8055310)", + "HIGHLIGHT_SYMBOL": 'circle%23ff000017.5%237bdcb5128.4', + "HIGHLIGHT_LABELSTRING": "Highlight Point :)", + "HIGHLIGHT_LABELFONT": "QGIS Vera Sans", + "HIGHLIGHT_LABELSIZE": "20", + "HIGHLIGHT_LABELCOLOR": "%2300FF0000", + "HIGHLIGHT_LABELBUFFERCOLOR": "%232300FF00", + "HIGHLIGHT_LABELBUFFERSIZE": "1.2", + "HIGHLIGHT_LABEL_ROTATION": "45", + "HIGHLIGHT_LABEL_HORIZONTAL_ALIGNMENT": "center", + "HIGHLIGHT_LABEL_VERTICAL_ALIGNMENT": "half", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Highlight_Point_Label_Options") @@ -1342,68 +1829,89 @@ def test_wms_getmap_highlight_point_label_options(self): def test_wms_getmap_highlight_line(self): # checks SLD stroke-width works for Lines See issue 19795 comments - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country_Labels", - "HIGHLIGHT_GEOM": "LINESTRING(-15000000 8055310, 2500000 8055310)", - "HIGHLIGHT_SYMBOL": "%23ff0000117.3round", - "HIGHLIGHT_LABELSTRING": "", - "HIGHLIGHT_LABELSIZE": "10", - "HIGHLIGHT_LABELCOLOR": "black", - "HIGHLIGHT_LABELBUFFERCOLOR": "white", - "HIGHLIGHT_LABELBUFFERSIZE": "1", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country_Labels", + "HIGHLIGHT_GEOM": "LINESTRING(-15000000 8055310, 2500000 8055310)", + "HIGHLIGHT_SYMBOL": '%23ff0000117.3round', + "HIGHLIGHT_LABELSTRING": "", + "HIGHLIGHT_LABELSIZE": "10", + "HIGHLIGHT_LABELCOLOR": "black", + "HIGHLIGHT_LABELBUFFERCOLOR": "white", + "HIGHLIGHT_LABELBUFFERSIZE": "1", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Highlight_Line") def test_wms_getmap_highlight_empty_labels(self): # Checks if the empty label for Eurasia is correctly handled. Otherwise the highlight point for Eurasia would be labeled as Africa - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country_Labels", - "HIGHLIGHT_GEOM": "POINT(-4000000 12215266);POINT(3271207 6832268);POINT(2360238 1035192)", - "HIGHLIGHT_LABELSTRING": "Arctic;;Africa", - "HIGHLIGHT_SYMBOL": "circle%23ff000017.5%237bdcb5128.4;circle%23ff000017.5%237bdcb5128.4;circle%23ff000017.5%237bdcb5128.4", - "HIGHLIGHT_LABELSIZE": "16;16;16", - "HIGHLIGHT_LABELCOLOR": "red;red;red", - "HIGHLIGHT_LABELBUFFERCOLOR": "white;white;white", - "HIGHLIGHT_LABELBUFFERSIZE": "1;1;1", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country_Labels", + "HIGHLIGHT_GEOM": "POINT(-4000000 12215266);POINT(3271207 6832268);POINT(2360238 1035192)", + "HIGHLIGHT_LABELSTRING": "Arctic;;Africa", + "HIGHLIGHT_SYMBOL": 'circle%23ff000017.5%237bdcb5128.4;circle%23ff000017.5%237bdcb5128.4;circle%23ff000017.5%237bdcb5128.4', + "HIGHLIGHT_LABELSIZE": "16;16;16", + "HIGHLIGHT_LABELCOLOR": "red;red;red", + "HIGHLIGHT_LABELBUFFERCOLOR": "white;white;white", + "HIGHLIGHT_LABELBUFFERSIZE": "1;1;1", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Highlight_Empty_Labels") def test_wms_getmap_annotations(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectAnnotationPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,Hello", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectAnnotationPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,Hello", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Annotations") @@ -1414,85 +1922,115 @@ def test_wms_getmap_sld(self): import threading # Bring up a simple HTTP server - os.chdir(unitTestDataPath() + '') + os.chdir(unitTestDataPath() + "") handler = http.server.SimpleHTTPRequestHandler - httpd = socketserver.TCPServer(('localhost', 0), handler) + httpd = socketserver.TCPServer(("localhost", 0), handler) port = httpd.server_address[1] httpd_thread = threading.Thread(target=httpd.serve_forever) httpd_thread.daemon = True httpd_thread.start() - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,db_point", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,db_point", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_SLDRestored") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "REQUEST": "GetMap", - "VERSION": "1.1.1", - "SERVICE": "WMS", - "SLD": "http://localhost:" + str( - port) + "/qgis_local_server/db_point.sld", - "BBOX": "-16817707,-4710778,5696513,14587125", - "WIDTH": "500", - "HEIGHT": "500", - "LAYERS": "db_point", - "STYLES": "", - "FORMAT": "image/png", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "REQUEST": "GetMap", + "VERSION": "1.1.1", + "SERVICE": "WMS", + "SLD": "http://localhost:" + + str(port) + + "/qgis_local_server/db_point.sld", + "BBOX": "-16817707,-4710778,5696513,14587125", + "WIDTH": "500", + "HEIGHT": "500", + "LAYERS": "db_point", + "STYLES": "", + "FORMAT": "image/png", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_SLD") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,db_point", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,db_point", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_SLDRestored") # Test SVG - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "REQUEST": "GetMap", - "VERSION": "1.1.1", - "SERVICE": "WMS", - "SLD": "http://localhost:" + str( - port) + "/qgis_local_server/db_point_svg.sld", - "BBOX": "-16817707,-4710778,5696513,14587125", - "WIDTH": "500", - "HEIGHT": "500", - "LAYERS": "db_point", - "STYLES": "", - "FORMAT": "image/png", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "REQUEST": "GetMap", + "VERSION": "1.1.1", + "SERVICE": "WMS", + "SLD": "http://localhost:" + + str(port) + + "/qgis_local_server/db_point_svg.sld", + "BBOX": "-16817707,-4710778,5696513,14587125", + "WIDTH": "500", + "HEIGHT": "500", + "LAYERS": "db_point", + "STYLES": "", + "FORMAT": "image/png", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_SLD_SVG") @@ -1500,54 +2038,75 @@ def test_wms_getmap_sld(self): httpd.server_close() def test_wms_getmap_sld_body(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,db_point", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,db_point", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_SLDRestored") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "REQUEST": "GetMap", - "VERSION": "1.1.1", - "SERVICE": "WMS", - "SLD_BODY": " db_point db_point_style Single symbol gid 1 square 5e86a1 000000 1000000 ", - "BBOX": "-16817707,-4710778,5696513,14587125", - "WIDTH": "500", - "HEIGHT": "500", - "LAYERS": "db_point", - "STYLES": "", - "FORMAT": "image/png", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "REQUEST": "GetMap", + "VERSION": "1.1.1", + "SERVICE": "WMS", + "SLD_BODY": ' db_point db_point_style Single symbol gid 1 square 5e86a1 000000 1000000 ', + "BBOX": "-16817707,-4710778,5696513,14587125", + "WIDTH": "500", + "HEIGHT": "500", + "LAYERS": "db_point", + "STYLES": "", + "FORMAT": "image/png", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_SLD") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,db_point", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,db_point", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_SLDRestored") @@ -1556,35 +2115,49 @@ def test_wms_getmap_sld_restore_labeling(self): """QGIS Server has to restore all the style. This test is not done to evaluate the SLD application but the style restoration and specifically the labeling.""" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "pointlabel", - "STYLES": "", - "SLD_BODY": " pointlabel pointlabel_style Single symbol square 5e86a1 000000 0.007 ", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) - r, h = self._result(self._execute_request(qs)) - - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "pointlabel", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "pointlabel", + "STYLES": "", + "SLD_BODY": ' pointlabel pointlabel_style Single symbol square 5e86a1 000000 0.007 ', + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) + r, h = self._result(self._execute_request(qs)) + + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "pointlabel", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Labeling_Complex") @@ -1593,35 +2166,49 @@ def test_wms_getmap_group(self): """A WMS shall render the requested layers by drawing the leftmost in the list bottommost, the next one over that, and so on.""" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectGroupsPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country_Diagrams,Country_Labels,Country", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectGroupsPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country_Diagrams,Country_Labels,Country", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r_individual, _ = self._result(self._execute_request(qs)) - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectGroupsPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "CountryGroup", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectGroupsPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "CountryGroup", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r_group, _ = self._result(self._execute_request(qs)) @@ -1634,140 +2221,206 @@ def test_wms_getmap_group(self): f.close() #""" - self.assertEqual(r_individual, r_group, - 'Individual layers query and group layers query results should be identical') - - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectGroupsPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "group_short_name", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + self.assertEqual( + r_individual, + r_group, + "Individual layers query and group layers query results should be identical", + ) + + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectGroupsPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "group_short_name", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r_group, _ = self._result(self._execute_request(qs)) - self.assertEqual(r_individual, r_group, - 'Individual layers query and group layers query with short name results should be identical') - - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectGroupsPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "SLD_BODY": " CountryGroup ", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + self.assertEqual( + r_individual, + r_group, + "Individual layers query and group layers query with short name results should be identical", + ) + + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectGroupsPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "SLD_BODY": ' CountryGroup ', + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r_group_sld, _ = self._result(self._execute_request(qs)) - self.assertEqual(r_individual, r_group_sld, - 'Individual layers query and SLD group layers query results should be identical') + self.assertEqual( + r_individual, + r_group_sld, + "Individual layers query and SLD group layers query results should be identical", + ) def test_wms_getmap_group_regression_20810(self): """A WMS shall render the requested layers by drawing the leftmost in the list - bottommost, the next one over that, and so on. Even if the layers are inside groups.""" - - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(os.path.join(self.testdata_path, - 'test_project_wms_grouped_layers.qgs')), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "BBOX": "613402.5658687877003,5809005.018114360981,619594.408781287726,5813869.006602735259", - "CRS": "EPSG:25832", - "WIDTH": "429", - "HEIGHT": "337", - "LAYERS": "osm,areas and symbols", - "STYLES": ",", - "FORMAT": "image/png", - "DPI": "200", - "MAP_RESOLUTION": "200", - "FORMAT_OPTIONS": "dpi:200" - }.items())]) + bottommost, the next one over that, and so on. Even if the layers are inside groups. + """ + + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote( + os.path.join( + self.testdata_path, + "test_project_wms_grouped_layers.qgs", + ) + ), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "BBOX": "613402.5658687877003,5809005.018114360981,619594.408781287726,5813869.006602735259", + "CRS": "EPSG:25832", + "WIDTH": "429", + "HEIGHT": "337", + "LAYERS": "osm,areas and symbols", + "STYLES": ",", + "FORMAT": "image/png", + "DPI": "200", + "MAP_RESOLUTION": "200", + "FORMAT_OPTIONS": "dpi:200", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_GroupedLayersUp") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(os.path.join(self.testdata_path, - 'test_project_wms_grouped_layers.qgs')), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "BBOX": "613402.5658687877003,5809005.018114360981,619594.408781287726,5813869.006602735259", - "CRS": "EPSG:25832", - "WIDTH": "429", - "HEIGHT": "337", - "LAYERS": "areas and symbols,osm", - "STYLES": ",", - "FORMAT": "image/png", - "DPI": "200", - "MAP_RESOLUTION": "200", - "FORMAT_OPTIONS": "dpi:200" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote( + os.path.join( + self.testdata_path, + "test_project_wms_grouped_layers.qgs", + ) + ), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "BBOX": "613402.5658687877003,5809005.018114360981,619594.408781287726,5813869.006602735259", + "CRS": "EPSG:25832", + "WIDTH": "429", + "HEIGHT": "337", + "LAYERS": "areas and symbols,osm", + "STYLES": ",", + "FORMAT": "image/png", + "DPI": "200", + "MAP_RESOLUTION": "200", + "FORMAT_OPTIONS": "dpi:200", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_GroupedLayersDown") def test_wms_getmap_datasource_error(self): """Must throw a server exception if datasource if not available""" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(os.path.join(self.testdata_path, - 'test_project_wms_invalid_layers.qgs')), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "BBOX": "613402.5658687877003,5809005.018114360981,619594.408781287726,5813869.006602735259", - "CRS": "EPSG:25832", - "WIDTH": "429", - "HEIGHT": "337", - "LAYERS": "areas and symbols,osm", - "STYLES": ",", - "FORMAT": "image/png", - "DPI": "200", - "MAP_RESOLUTION": "200", - "FORMAT_OPTIONS": "dpi:200" - }.items())]) - - r, h = self._result(self._execute_request(qs)) - - self.assertIn('ServerException', str(r)) - - @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'), - 'Can\'t rely on external resources for continuous integration') + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote( + os.path.join( + self.testdata_path, + "test_project_wms_invalid_layers.qgs", + ) + ), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "BBOX": "613402.5658687877003,5809005.018114360981,619594.408781287726,5813869.006602735259", + "CRS": "EPSG:25832", + "WIDTH": "429", + "HEIGHT": "337", + "LAYERS": "areas and symbols,osm", + "STYLES": ",", + "FORMAT": "image/png", + "DPI": "200", + "MAP_RESOLUTION": "200", + "FORMAT_OPTIONS": "dpi:200", + }.items() + ) + ] + ) + + r, h = self._result(self._execute_request(qs)) + + self.assertIn("ServerException", str(r)) + + @unittest.skipIf( + os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), + "Can't rely on external resources for continuous integration", + ) def test_wms_getmap_external(self): # 1 bits - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "REQUEST": "GetMap", - "LAYERS": "EXTERNAL_WMS:landsat,Country", - "OPACITIES": "255,150", - "landsat:layers": "GEBCO_LATEST", - "landsat:dpiMode": "7", - "landsat:url": "https://www.gebco.net/data_and_products/gebco_web_services/web_map_service/mapserv", - "landsat:crs": "EPSG:4326", - "landsat:styles": "default", - "landsat:format": "image/jpeg", - "landsat:bbox": "-90,-180,90,180", - "landsat:version": "1.3.0", - "STYLES": "", - "BBOX": "-90,-180,90,180", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:4326" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "REQUEST": "GetMap", + "LAYERS": "EXTERNAL_WMS:landsat,Country", + "OPACITIES": "255,150", + "landsat:layers": "GEBCO_LATEST", + "landsat:dpiMode": "7", + "landsat:url": "https://www.gebco.net/data_and_products/gebco_web_services/web_map_service/mapserv", + "landsat:crs": "EPSG:4326", + "landsat:styles": "default", + "landsat:format": "image/jpeg", + "landsat:bbox": "-90,-180,90,180", + "landsat:version": "1.3.0", + "STYLES": "", + "BBOX": "-90,-180,90,180", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:4326", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_External", 20000) @@ -1775,45 +2428,65 @@ def test_wms_getmap_external(self): def test_wms_getmap_root_custom_layer_order_regression_21917(self): """When drawing root layer, custom layer order order should be respected.""" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(os.path.join(self.testdata_path, - 'bug_21917_root_layer_order.qgs')), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "BBOX": "44.9014,8.20346,44.9015,8.20355", - "CRS": "EPSG:4326", - "WIDTH": "400", - "HEIGHT": "400", - "LAYERS": "group", - "STYLES": ",", - "FORMAT": "image/png", - "DPI": "200", - "MAP_RESOLUTION": "200", - "FORMAT_OPTIONS": "dpi:200" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote( + os.path.join( + self.testdata_path, "bug_21917_root_layer_order.qgs" + ) + ), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "BBOX": "44.9014,8.20346,44.9015,8.20355", + "CRS": "EPSG:4326", + "WIDTH": "400", + "HEIGHT": "400", + "LAYERS": "group", + "STYLES": ",", + "FORMAT": "image/png", + "DPI": "200", + "MAP_RESOLUTION": "200", + "FORMAT_OPTIONS": "dpi:200", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Group_Layer_Order") # Check with root_layer - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(os.path.join(self.testdata_path, - 'bug_21917_root_layer_order.qgs')), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "BBOX": "44.9014,8.20346,44.9015,8.20355", - "CRS": "EPSG:4326", - "WIDTH": "400", - "HEIGHT": "400", - "LAYERS": "root_layer", - "STYLES": ",", - "FORMAT": "image/png", - "DPI": "200", - "MAP_RESOLUTION": "200", - "FORMAT_OPTIONS": "dpi:200" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote( + os.path.join( + self.testdata_path, "bug_21917_root_layer_order.qgs" + ) + ), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "BBOX": "44.9014,8.20346,44.9015,8.20355", + "CRS": "EPSG:4326", + "WIDTH": "400", + "HEIGHT": "400", + "LAYERS": "root_layer", + "STYLES": ",", + "FORMAT": "image/png", + "DPI": "200", + "MAP_RESOLUTION": "200", + "FORMAT_OPTIONS": "dpi:200", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Group_Layer_Order") @@ -1822,158 +2495,230 @@ def test_wms_getmap_tile_buffer(self): """Test the implementation of tile_map_edge_buffer from mapserver.""" # Check without tiled parameters (default is false) - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote( - os.path.join(self.testdata_path, 'wms_tile_buffer.qgs')), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "BBOX": "310187,6163153,324347,6177313", - "CRS": "EPSG:3857", - "WIDTH": "512", - "HEIGHT": "512", - "LAYERS": "wms_tile_buffer_data", - "FORMAT": "image/png" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote( + os.path.join(self.testdata_path, "wms_tile_buffer.qgs") + ), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "BBOX": "310187,6163153,324347,6177313", + "CRS": "EPSG:3857", + "WIDTH": "512", + "HEIGHT": "512", + "LAYERS": "wms_tile_buffer_data", + "FORMAT": "image/png", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Tiled_False") # Check with tiled=false - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote( - os.path.join(self.testdata_path, 'wms_tile_buffer.qgs')), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "BBOX": "310187,6163153,324347,6177313", - "CRS": "EPSG:3857", - "WIDTH": "512", - "HEIGHT": "512", - "LAYERS": "wms_tile_buffer_data", - "FORMAT": "image/png", - "TILED": "false" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote( + os.path.join(self.testdata_path, "wms_tile_buffer.qgs") + ), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "BBOX": "310187,6163153,324347,6177313", + "CRS": "EPSG:3857", + "WIDTH": "512", + "HEIGHT": "512", + "LAYERS": "wms_tile_buffer_data", + "FORMAT": "image/png", + "TILED": "false", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Tiled_False") # Check with tiled=true - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote( - os.path.join(self.testdata_path, 'wms_tile_buffer.qgs')), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "BBOX": "310187,6163153,324347,6177313", - "CRS": "EPSG:3857", - "WIDTH": "512", - "HEIGHT": "512", - "LAYERS": "wms_tile_buffer_data", - "FORMAT": "image/png", - "TILED": "true" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote( + os.path.join(self.testdata_path, "wms_tile_buffer.qgs") + ), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "BBOX": "310187,6163153,324347,6177313", + "CRS": "EPSG:3857", + "WIDTH": "512", + "HEIGHT": "512", + "LAYERS": "wms_tile_buffer_data", + "FORMAT": "image/png", + "TILED": "true", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Tiled_True") # Check with labels and tiled=false - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote( - os.path.join(self.testdata_path, 'wms_tile_buffer.qgs')), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "BBOX": "310187,6163153,324347,6177313", - "CRS": "EPSG:3857", - "WIDTH": "512", - "HEIGHT": "512", - "LAYERS": "wms_tile_buffer_labels", - "FORMAT": "image/png", - "TILED": "false" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote( + os.path.join(self.testdata_path, "wms_tile_buffer.qgs") + ), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "BBOX": "310187,6163153,324347,6177313", + "CRS": "EPSG:3857", + "WIDTH": "512", + "HEIGHT": "512", + "LAYERS": "wms_tile_buffer_labels", + "FORMAT": "image/png", + "TILED": "false", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Tiled_Labels_False") # Check with labels and tiled=true - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote( - os.path.join(self.testdata_path, 'wms_tile_buffer.qgs')), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "BBOX": "310187,6163153,324347,6177313", - "CRS": "EPSG:3857", - "WIDTH": "512", - "HEIGHT": "512", - "LAYERS": "wms_tile_buffer_labels", - "FORMAT": "image/png", - "TILED": "true" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote( + os.path.join(self.testdata_path, "wms_tile_buffer.qgs") + ), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "BBOX": "310187,6163153,324347,6177313", + "CRS": "EPSG:3857", + "WIDTH": "512", + "HEIGHT": "512", + "LAYERS": "wms_tile_buffer_labels", + "FORMAT": "image/png", + "TILED": "true", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Tiled_Labels_True") # Check with rotated labels and tiled=true - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote( - os.path.join(self.testdata_path, 'wms_tile_buffer.qgs')), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "BBOX": "317914,6163276,327923,6173244", - "CRS": "EPSG:3857", - "WIDTH": "512", - "HEIGHT": "512", - "LAYERS": "wms_tile_buffer_labels_rotated", - "FORMAT": "image/png", - "TILED": "true" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote( + os.path.join(self.testdata_path, "wms_tile_buffer.qgs") + ), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "BBOX": "317914,6163276,327923,6173244", + "CRS": "EPSG:3857", + "WIDTH": "512", + "HEIGHT": "512", + "LAYERS": "wms_tile_buffer_labels_rotated", + "FORMAT": "image/png", + "TILED": "true", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_Tiled_Rotated_Labels_True") - @unittest.skipIf(os.getenv('QGIS_CONTINUOUS_INTEGRATION_RUN'), "This tests fails on GH workflow") + @unittest.skipIf( + os.getenv("QGIS_CONTINUOUS_INTEGRATION_RUN"), "This tests fails on GH workflow" + ) def test_mode8bit_with_transparency(self): # 8 bits - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote( - self.testdata_path + 'test_project_wms_8bit_with_transparency.qgs'), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "test_layer", - "STYLES": "", - "FORMAT": "image/png; mode=8bit", - "BBOX": "913204.62,5606011.36,913217.45,5606025.58", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857", - "TRANSPARENT": "TRUE" - }.items())]) - - r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetMap_Mode_8bit_with_transparency", max_diff=1500) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote( + self.testdata_path + + "test_project_wms_8bit_with_transparency.qgs" + ), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "test_layer", + "STYLES": "", + "FORMAT": "image/png; mode=8bit", + "BBOX": "913204.62,5606011.36,913217.45,5606025.58", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "TRANSPARENT": "TRUE", + }.items() + ) + ] + ) + + r, h = self._result(self._execute_request(qs)) + self._img_diff_error( + r, h, "WMS_GetMap_Mode_8bit_with_transparency", max_diff=1500 + ) def test_multiple_layers_with_equal_name(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(os.path.join(self.testdata_path, - 'test_project_wms_duplicate_names.qgz')), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "BBOX": "613402.5658687877003,5809005.018114360981,619594.408781287726,5813869.006602735259", - "CRS": "EPSG:25832", - "WIDTH": "429", - "HEIGHT": "337", - "LAYERS": "layer", - "STYLES": ",", - "FORMAT": "image/png", - "DPI": "200", - "MAP_RESOLUTION": "200", - "FORMAT_OPTIONS": "dpi:200" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote( + os.path.join( + self.testdata_path, + "test_project_wms_duplicate_names.qgz", + ) + ), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "BBOX": "613402.5658687877003,5809005.018114360981,619594.408781287726,5813869.006602735259", + "CRS": "EPSG:25832", + "WIDTH": "429", + "HEIGHT": "337", + "LAYERS": "layer", + "STYLES": ",", + "FORMAT": "image/png", + "DPI": "200", + "MAP_RESOLUTION": "200", + "FORMAT_OPTIONS": "dpi:200", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_DuplicateNames") @@ -1981,62 +2726,88 @@ def test_multiple_layers_with_equal_name(self): def test_wms_getmap_plus_sign(self): """Test issue GH #41116""" - vl = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer', 'test+plus', 'memory') + vl = QgsVectorLayer( + "Point?crs=epsg:4326&field=int:integer", "test+plus", "memory" + ) p = QgsProject() p.addMapLayers([vl]) - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": urllib.parse.quote('test+plus'), - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-170,-80,170,80", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:4326" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": urllib.parse.quote("test+plus"), + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-170,-80,170,80", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:4326", + }.items() + ) + ] + ) r, h = self._result(self._execute_request_project(qs, p)) # No exceptions - self.assertEqual(h['Content-Type'], 'image/png') + self.assertEqual(h["Content-Type"], "image/png") self.assertNotIn(b"The layer 'test plus' does not exist", r) # + literal: we get an exception - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": 'test+plus', - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "-170,-80,170,80", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:4326" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "test+plus", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "-170,-80,170,80", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:4326", + }.items() + ) + ] + ) r, h = self._result(self._execute_request_project(qs, p)) self.assertIn(b"The layer 'test plus' does not exist", r) def test_wms_annotation_item(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(os.path.join(self.testdata_path, - 'test_project_annotation_item.qgz')), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "BBOX": "44.9014,8.20346,44.9015,8.20364", - "CRS": "EPSG:4326", - "WIDTH": "800", - "HEIGHT": "400", - "LAYERS": "points", - "STYLES": ",", - "FORMAT": "image/png", - "DPI": "96", - "MAP_RESOLUTION": "96", - "FORMAT_OPTIONS": "dpi:96" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote( + os.path.join( + self.testdata_path, "test_project_annotation_item.qgz" + ) + ), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "BBOX": "44.9014,8.20346,44.9015,8.20364", + "CRS": "EPSG:4326", + "WIDTH": "800", + "HEIGHT": "400", + "LAYERS": "points", + "STYLES": ",", + "FORMAT": "image/png", + "DPI": "96", + "MAP_RESOLUTION": "96", + "FORMAT_OPTIONS": "dpi:96", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetMap_AnnotationItem") @@ -2045,15 +2816,19 @@ def test_temporal_properties(self): """Test temporal properties""" # sample table with likely single field - layer_date = QgsVectorLayer("Point?srid=EPSG:4326&field=event_id:integer&field=event_date:date", "test_date", "memory") + layer_date = QgsVectorLayer( + "Point?srid=EPSG:4326&field=event_id:integer&field=event_date:date", + "test_date", + "memory", + ) self.assertTrue(layer_date.isValid()) f = QgsFeature() f.setAttributes([1, QDate(2001, 1, 1)]) - f.setGeometry(QgsGeometry.fromWkt('Point (1 1)')) + f.setGeometry(QgsGeometry.fromWkt("Point (1 1)")) self.assertTrue(layer_date.dataProvider().addFeature(f)) f.setAttributes([2, QDate(2002, 2, 2)]) - f.setGeometry(QgsGeometry.fromWkt('Point (2 2)')) + f.setGeometry(QgsGeometry.fromWkt("Point (2 2)")) self.assertTrue(layer_date.dataProvider().addFeature(f)) single_symbol_renderer = layer_date.renderer() @@ -2064,20 +2839,39 @@ def test_temporal_properties(self): props_date.setIsActive(False) props_date = layer_date.temporalProperties() self.assertFalse(props_date.isActive()) - self.assertEqual(props_date.startField(), 'event_date') + self.assertEqual(props_date.startField(), "event_date") self.assertFalse(props_date.endField()) - self.assertEqual(props_date.mode(), QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeInstantFromField) + self.assertEqual( + props_date.mode(), + QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeInstantFromField, + ) # sample table with likely dual fields - layer_range = QgsVectorLayer("Point?srid=EPSG:4326&field=event_id:integer&field=start_date:datetime&field=end_date:datetime", "test_range", "memory") + layer_range = QgsVectorLayer( + "Point?srid=EPSG:4326&field=event_id:integer&field=start_date:datetime&field=end_date:datetime", + "test_range", + "memory", + ) self.assertTrue(layer_range.isValid()) f = QgsFeature() - f.setAttributes([3, QDateTime(QDate(2003, 3, 3), QTime(3, 3, 2)), QDateTime(QDate(2003, 3, 3), QTime(3, 3, 4))]) - f.setGeometry(QgsGeometry.fromWkt('Point (3 3)')) + f.setAttributes( + [ + 3, + QDateTime(QDate(2003, 3, 3), QTime(3, 3, 2)), + QDateTime(QDate(2003, 3, 3), QTime(3, 3, 4)), + ] + ) + f.setGeometry(QgsGeometry.fromWkt("Point (3 3)")) self.assertTrue(layer_range.dataProvider().addFeature(f)) - f.setAttributes([4, QDateTime(QDate(2004, 4, 4), QTime(4, 4, 3)), QDateTime(QDate(2004, 4, 4), QTime(4, 4, 5))]) - f.setGeometry(QgsGeometry.fromWkt('Point (4 4)')) + f.setAttributes( + [ + 4, + QDateTime(QDate(2004, 4, 4), QTime(4, 4, 3)), + QDateTime(QDate(2004, 4, 4), QTime(4, 4, 5)), + ] + ) + f.setGeometry(QgsGeometry.fromWkt("Point (4 4)")) self.assertTrue(layer_range.dataProvider().addFeature(f)) single_symbol_renderer = layer_range.renderer() @@ -2088,45 +2882,62 @@ def test_temporal_properties(self): props_range.setIsActive(False) props_range = layer_range.temporalProperties() self.assertFalse(props_range.isActive()) - self.assertEqual(props_range.startField(), 'start_date') - self.assertEqual(props_range.endField(), 'end_date') - self.assertEqual(props_range.mode(), QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeStartAndEndFromFields) + self.assertEqual(props_range.startField(), "start_date") + self.assertEqual(props_range.endField(), "end_date") + self.assertEqual( + props_range.mode(), + QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeStartAndEndFromFields, + ) project = QgsProject() project.addMapLayers([layer_date, layer_range]) - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "test_date,test_range", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "0,0,5,5", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:4326", - "TRANSPARENT": "TRUE" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "test_date,test_range", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "0,0,5,5", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:4326", + "TRANSPARENT": "TRUE", + }.items() + ) + ] + ) r, h = self._result(self._execute_request_project(qs, project)) self._img_diff_error(r, h, "WMS_GetMap_TemporalProperties_no_filter") # Time filter but no exposed properties - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "test_date,test_range", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "0,0,5,5", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:4326", - "TRANSPARENT": "TRUE", - "TIME": "2001-01-01" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "test_date,test_range", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "0,0,5,5", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:4326", + "TRANSPARENT": "TRUE", + "TIME": "2001-01-01", + }.items() + ) + ] + ) r, h = self._result(self._execute_request_project(qs, project)) self._img_diff_error(r, h, "WMS_GetMap_TemporalProperties_no_filter") @@ -2139,68 +2950,92 @@ def test_temporal_properties(self): self._img_diff_error(r, h, "WMS_GetMap_TemporalProperties_date_filter") # Filtr both layers - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "test_date,test_range", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "0,0,5,5", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:4326", - "TRANSPARENT": "TRUE", - "TIME": "2002-02-02/2003-03-04" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "test_date,test_range", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "0,0,5,5", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:4326", + "TRANSPARENT": "TRUE", + "TIME": "2002-02-02/2003-03-04", + }.items() + ) + ] + ) r, h = self._result(self._execute_request_project(qs, project)) self._img_diff_error(r, h, "WMS_GetMap_TemporalProperties_datetime_filter") # Test get capabilities - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetCapabilities", - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetCapabilities", + }.items() + ) + ] + ) r, h = self._result(self._execute_request_project(qs, project)) t = et.fromstring(r) ns = t.nsmap del ns[None] - ns['wms'] = 'http://www.opengis.net/wms' - - date_dimension = t.xpath("//wms:Layer/wms:Name[text()='test_date']/../wms:Dimension", namespaces=ns)[0] - self.assertEqual(date_dimension.attrib, {'units': 'ISO8601', 'name': 'TIME'}) - - date_extent = t.xpath("//wms:Layer/wms:Name[text()='test_date']/../wms:Extent", namespaces=ns)[0] - self.assertEqual(date_extent.attrib, {'name': 'TIME'}) - self.assertEqual(date_extent.text, '2001-01-01/2002-02-02') - - range_dimension = t.xpath("//wms:Layer/wms:Name[text()='test_range']/../wms:Dimension", namespaces=ns)[0] - self.assertEqual(range_dimension.attrib, {'units': 'ISO8601', 'name': 'TIME'}) - - range_extent = t.xpath("//wms:Layer/wms:Name[text()='test_range']/../wms:Extent", namespaces=ns)[0] - self.assertEqual(range_extent.attrib, {'name': 'TIME'}) - self.assertEqual(range_extent.text, '2003-03-03/2004-04-04') + ns["wms"] = "http://www.opengis.net/wms" + + date_dimension = t.xpath( + "//wms:Layer/wms:Name[text()='test_date']/../wms:Dimension", namespaces=ns + )[0] + self.assertEqual(date_dimension.attrib, {"units": "ISO8601", "name": "TIME"}) + + date_extent = t.xpath( + "//wms:Layer/wms:Name[text()='test_date']/../wms:Extent", namespaces=ns + )[0] + self.assertEqual(date_extent.attrib, {"name": "TIME"}) + self.assertEqual(date_extent.text, "2001-01-01/2002-02-02") + + range_dimension = t.xpath( + "//wms:Layer/wms:Name[text()='test_range']/../wms:Dimension", namespaces=ns + )[0] + self.assertEqual(range_dimension.attrib, {"units": "ISO8601", "name": "TIME"}) + + range_extent = t.xpath( + "//wms:Layer/wms:Name[text()='test_range']/../wms:Extent", namespaces=ns + )[0] + self.assertEqual(range_extent.attrib, {"name": "TIME"}) + self.assertEqual(range_extent.text, "2003-03-03/2004-04-04") def test_get_map_labeling_opacities(self): """Test if OPACITIES is also applied to labels""" layer = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=name:string&key=pk', - 'test', 'memory') + "Point?crs=epsg:4326&field=pk:integer&field=name:string&key=pk", + "test", + "memory", + ) provider = layer.dataProvider() f1 = QgsFeature() - f1.setAttributes([1, 'Label1']) - f1.setGeometry(QgsGeometry.fromWkt('Point (2 2)')) + f1.setAttributes([1, "Label1"]) + f1.setGeometry(QgsGeometry.fromWkt("Point (2 2)")) self.assertTrue(f1.isValid()) f2 = QgsFeature() - f2.setAttributes([1, 'Label2']) - f2.setGeometry(QgsGeometry.fromWkt('Point (1 1)')) + f2.setAttributes([1, "Label2"]) + f2.setGeometry(QgsGeometry.fromWkt("Point (1 1)")) self.assertTrue(f2.isValid()) self.assertTrue(provider.addFeatures([f1, f2])) @@ -2232,65 +3067,90 @@ def test_get_map_labeling_opacities(self): layer.setLabeling(QgsVectorLayerSimpleLabeling(settings)) layer.setLabelsEnabled(True) - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "test", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "0,0,2,2", - "HEIGHT": "200", - "WIDTH": "200", - "CRS": "EPSG:4326", - "DPI": 96, - "OPACITIES": "128" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "test", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "0,0,2,2", + "HEIGHT": "200", + "WIDTH": "200", + "CRS": "EPSG:4326", + "DPI": 96, + "OPACITIES": "128", + }.items() + ) + ] + ) request = QgsBufferServerRequest(qs) response = QgsBufferServerResponse() server = QgsServer() server.handleRequest(request, response, project) - self._img_diff_error(response.body(), response.headers(), "WMS_GetMap_LabelingOpacities128") + self._img_diff_error( + response.body(), response.headers(), "WMS_GetMap_LabelingOpacities128" + ) # Test restorer - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "test", - "STYLES": "", - "FORMAT": "image/png", - "BBOX": "0,0,2,2", - "HEIGHT": "200", - "WIDTH": "200", - "CRS": "EPSG:4326", - "DPI": 96, - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "test", + "STYLES": "", + "FORMAT": "image/png", + "BBOX": "0,0,2,2", + "HEIGHT": "200", + "WIDTH": "200", + "CRS": "EPSG:4326", + "DPI": 96, + }.items() + ) + ] + ) request = QgsBufferServerRequest(qs) response = QgsBufferServerResponse() server = QgsServer() server.handleRequest(request, response, project) - self._img_diff_error(response.body(), response.headers(), "WMS_GetMap_LabelingOpacities") + self._img_diff_error( + response.body(), response.headers(), "WMS_GetMap_LabelingOpacities" + ) def test_get_map_pdf(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetMap", - "LAYERS": "Country,dem", - "STYLES": "", - "FORMAT": "application/pdf", - "BBOX": "-16817707,-4710778,5696513,14587125", - "HEIGHT": "500", - "WIDTH": "500", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetMap", + "LAYERS": "Country,dem", + "STYLES": "", + "FORMAT": "application/pdf", + "BBOX": "-16817707,-4710778,5696513,14587125", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) self._assert_status_code(200, qs) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_wms_getmap_ignore_bad_layers.py b/tests/src/python/test_qgsserver_wms_getmap_ignore_bad_layers.py index ea867266abac..c24bfedd84d8 100644 --- a/tests/src/python/test_qgsserver_wms_getmap_ignore_bad_layers.py +++ b/tests/src/python/test_qgsserver_wms_getmap_ignore_bad_layers.py @@ -9,14 +9,15 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '13/04/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "13/04/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import os # Needed on Qt 5 so that the serialization of XML is consistent among all executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" import urllib.error import urllib.parse @@ -28,8 +29,8 @@ from test_qgsserver import QgsServerTestBase # Strip path and content length because path may vary -RE_STRIP_UNCHECKABLE = br'MAP=[^"]+|Content-Length: \d+' -RE_ATTRIBUTES = br'[^>\s]+=[^>\s]+' +RE_STRIP_UNCHECKABLE = rb'MAP=[^"]+|Content-Length: \d+' +RE_ATTRIBUTES = rb"[^>\s]+=[^>\s]+" class TestQgsServerWMSGetMapIgnoreBadLayers(QgsServerTestBase): @@ -39,34 +40,47 @@ class TestQgsServerWMSGetMapIgnoreBadLayers(QgsServerTestBase): @classmethod def setUpClass(cls): - os.environ['QGIS_SERVER_IGNORE_BAD_LAYERS'] = 'true' + os.environ["QGIS_SERVER_IGNORE_BAD_LAYERS"] = "true" super().setUpClass() def test_wms_getmap_datasource_error_ignore(self): """Must NOT throw a server exception if datasource if not available and QGIS_SERVER_IGNORE_BAD_LAYERS is set""" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(os.path.join(self.testdata_path, - 'test_project_wms_invalid_layers.qgs')), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "BBOX": "613402.5658687877003,5809005.018114360981,619594.408781287726,5813869.006602735259", - "CRS": "EPSG:25832", - "WIDTH": "429", - "HEIGHT": "337", - "LAYERS": "areas and symbols,osm", - "STYLES": ",", - "FORMAT": "image/png", - "DPI": "200", - "MAP_RESOLUTION": "200", - "FORMAT_OPTIONS": "dpi:200" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote( + os.path.join( + self.testdata_path, + "test_project_wms_invalid_layers.qgs", + ) + ), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "BBOX": "613402.5658687877003,5809005.018114360981,619594.408781287726,5813869.006602735259", + "CRS": "EPSG:25832", + "WIDTH": "429", + "HEIGHT": "337", + "LAYERS": "areas and symbols,osm", + "STYLES": ",", + "FORMAT": "image/png", + "DPI": "200", + "MAP_RESOLUTION": "200", + "FORMAT_OPTIONS": "dpi:200", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self.assertFalse('ServerException' in str(r), 'Unexpected ServerException ' + str(r)) + self.assertFalse( + "ServerException" in str(r), "Unexpected ServerException " + str(r) + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_wms_getmap_size_project.py b/tests/src/python/test_qgsserver_wms_getmap_size_project.py index 25d8c2575931..80efcebb2334 100644 --- a/tests/src/python/test_qgsserver_wms_getmap_size_project.py +++ b/tests/src/python/test_qgsserver_wms_getmap_size_project.py @@ -13,15 +13,16 @@ (at your option) any later version. """ -__author__ = 'Marco Bernasocchi' -__date__ = '01/04/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Marco Bernasocchi" +__date__ = "01/04/2019" +__copyright__ = "Copyright 2019, The QGIS Project" import os # Needed on Qt 5 so that the serialization of XML is consistent among all # executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" import urllib.parse @@ -37,11 +38,13 @@ class TestQgsServerWMSGetMapSizeProject(QgsServerTestBase): regenerate_reference = False def setUp(self): - os.environ['QGIS_SERVER_WMS_MAX_WIDTH'] = '6000' - os.environ['QGIS_SERVER_WMS_MAX_HEIGHT'] = '6000' + os.environ["QGIS_SERVER_WMS_MAX_WIDTH"] = "6000" + os.environ["QGIS_SERVER_WMS_MAX_HEIGHT"] = "6000" super().setUp() self.project = os.path.join(self.testdata_path, "test_project_with_size.qgs") - self.expected_too_big = self.strip_version_xmlns(b'\n\n The requested map size is too large\n\n') + self.expected_too_big = self.strip_version_xmlns( + b'\n\n The requested map size is too large\n\n' + ) def test_wms_getmap_invalid_size_project(self): # test the 6000 limit from server is overridden by the more conservative 5000 in the project @@ -50,20 +53,27 @@ def test_wms_getmap_invalid_size_project(self): def make_request(instance, height, width): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(instance.project), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetMap", - "LAYERS": "", - "STYLES": "", - "FORMAT": "image/png", - "HEIGHT": str(height), - "WIDTH": str(width) - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(instance.project), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetMap", + "LAYERS": "", + "STYLES": "", + "FORMAT": "image/png", + "HEIGHT": str(height), + "WIDTH": str(width), + }.items() + ) + ] + ) r, h = instance._result(instance._execute_request(qs)) return instance.strip_version_xmlns(r) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_wms_getmap_size_server.py b/tests/src/python/test_qgsserver_wms_getmap_size_server.py index 31f631d04034..4898fbd675d0 100644 --- a/tests/src/python/test_qgsserver_wms_getmap_size_server.py +++ b/tests/src/python/test_qgsserver_wms_getmap_size_server.py @@ -13,15 +13,16 @@ (at your option) any later version. """ -__author__ = 'Marco Bernasocchi' -__date__ = '01/04/2019' -__copyright__ = 'Copyright 2019, The QGIS Project' + +__author__ = "Marco Bernasocchi" +__date__ = "01/04/2019" +__copyright__ = "Copyright 2019, The QGIS Project" import os # Needed on Qt 5 so that the serialization of XML is consistent among all # executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" from qgis.testing import unittest from test_qgsserver import QgsServerTestBase @@ -36,13 +37,15 @@ class TestQgsServerWMSGetMapSizeServer(QgsServerTestBase): @classmethod def setUpClass(self): - os.environ['QGIS_SERVER_WMS_MAX_WIDTH'] = '3000' - os.environ['QGIS_SERVER_WMS_MAX_HEIGHT'] = '3000' + os.environ["QGIS_SERVER_WMS_MAX_WIDTH"] = "3000" + os.environ["QGIS_SERVER_WMS_MAX_HEIGHT"] = "3000" super().setUpClass() def setUp(self): self.project = os.path.join(self.testdata_path, "test_project_with_size.qgs") - self.expected_too_big = self.strip_version_xmlns(b'\n\n The requested map size is too large\n\n') + self.expected_too_big = self.strip_version_xmlns( + b'\n\n The requested map size is too large\n\n' + ) def test_wms_getmap_invalid_size_server(self): # test the 3000 limit from server is overriding the less conservative 5000 in the project @@ -50,5 +53,5 @@ def test_wms_getmap_invalid_size_server(self): self.assertEqual(self.strip_version_xmlns(r), self.expected_too_big) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_wms_getprint.py b/tests/src/python/test_qgsserver_wms_getprint.py index 11150471ac65..e2555b0e0d17 100644 --- a/tests/src/python/test_qgsserver_wms_getprint.py +++ b/tests/src/python/test_qgsserver_wms_getprint.py @@ -9,14 +9,15 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '25/05/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "25/05/2015" +__copyright__ = "Copyright 2015, The QGIS Project" import os # Needed on Qt 5 so that the serialization of XML is consistent among all executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" import urllib.parse @@ -29,183 +30,260 @@ class TestQgsServerWMSGetPrint(QgsServerTestBase): """QGIS Server WMS Tests for GetPrint request""" def test_wms_getprint_basic(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country,Hello", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country,Hello", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_Basic") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "LAYERS": "Country,Hello", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "LAYERS": "Country,Hello", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_Basic") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country,Hello", - "LAYERS": "Country,Hello", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country,Hello", + "LAYERS": "Country,Hello", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_Basic") def test_wms_getprint_style(self): # default style - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country_Labels", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country_Labels", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - assert h.get("Content-Type").startswith('image'), r + assert h.get("Content-Type").startswith("image"), r self._img_diff_error(r, h, "WMS_GetPrint_StyleDefault") # custom style - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country_Labels", - "map0:STYLES": "custom", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country_Labels", + "map0:STYLES": "custom", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_StyleCustom") # default style - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "LAYERS": "Country_Labels", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "LAYERS": "Country_Labels", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_StyleDefault") # custom style - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "LAYERS": "Country_Labels", - "STYLES": "custom", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "LAYERS": "Country_Labels", + "STYLES": "custom", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_StyleCustom") # default style - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country_Labels", - "LAYERS": "Country_Labels", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country_Labels", + "LAYERS": "Country_Labels", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_StyleDefault") # custom style - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country_Labels", - "map0:STYLES": "custom", - "LAYERS": "Country_Labels", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country_Labels", + "map0:STYLES": "custom", + "LAYERS": "Country_Labels", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_StyleCustom") def test_wms_getprint_group(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectGroupsPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country_Diagrams,Country_Labels,Country", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectGroupsPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country_Diagrams,Country_Labels,Country", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r_individual, h = self._result(self._execute_request(qs)) # test reference image self._img_diff_error(r_individual, h, "WMS_GetPrint_Group") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectGroupsPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "CountryGroup", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectGroupsPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "CountryGroup", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r_group, h = self._result(self._execute_request(qs)) @@ -225,164 +303,229 @@ def test_wms_getprint_group(self): # self.assertEqual(r_individual, r_group, 'Individual layers query and group layers query results should be identical') def test_wms_getprint_legend(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4copy", - "FORMAT": "png", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country,Hello", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4copy", + "FORMAT": "png", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country,Hello", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_Legend") def test_wms_getprint_srs(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-309.015,-133.011,312.179,133.949", - "map0:LAYERS": "Country,Hello", - "CRS": "EPSG:4326" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-309.015,-133.011,312.179,133.949", + "map0:LAYERS": "Country,Hello", + "CRS": "EPSG:4326", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_SRS") def test_wms_getprint_scale(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country,Hello", - "map0:SCALE": "36293562", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country,Hello", + "map0:SCALE": "36293562", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_Scale") def test_wms_getprint_size(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country,Hello", - "map0:SCALE": "36293562", - "CRS": "EPSG:3857", - "HEIGHT": "100" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country,Hello", + "map0:SCALE": "36293562", + "CRS": "EPSG:3857", + "HEIGHT": "100", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_Size", max_size_diff=QSize(1, 1)) def test_wms_getprint_grid(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country,Hello", - "map0:GRID_INTERVAL_X": "1000000", - "map0:GRID_INTERVAL_Y": "2000000", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country,Hello", + "map0:GRID_INTERVAL_X": "1000000", + "map0:GRID_INTERVAL_Y": "2000000", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_Grid") def test_wms_getprint_rotation(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country,Hello", - "map0:ROTATION": "45", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country,Hello", + "map0:ROTATION": "45", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_Rotation") def test_wms_getprint_two_maps(self): """Test map0 and map1 apply to the correct maps""" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4twoMaps", - "FORMAT": "png", - "map0:EXTENT": "11863620.20301065221428871,-5848927.97872077487409115,19375243.89574331790208817,138857.97204941", - "map0:LAYERS": "Country", - "map1:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map1:LAYERS": "Country,Hello", - "CRS": "EPSG:3857", - "IDTEXTBOX": "", - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4twoMaps", + "FORMAT": "png", + "map0:EXTENT": "11863620.20301065221428871,-5848927.97872077487409115,19375243.89574331790208817,138857.97204941", + "map0:LAYERS": "Country", + "map1:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map1:LAYERS": "Country,Hello", + "CRS": "EPSG:3857", + "IDTEXTBOX": "", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_TwoMaps") def test_wms_getprint_excluded_layout(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "REQUEST": "GetPrint", - "TEMPLATE": "excluded", - "CRS": "EPSG:4326" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "REQUEST": "GetPrint", + "TEMPLATE": "excluded", + "CRS": "EPSG:4326", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self.assertIn(b"The TEMPLATE parameter is invalid", r) - @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'), - 'Can\'t rely on external resources for continuous integration') + @unittest.skipIf( + os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), + "Can't rely on external resources for continuous integration", + ) def test_wms_getprint_external(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "map0:EXTENT": "-90,-180,90,180", - "map0:LAYERS": "EXTERNAL_WMS:landsat,Country", - "landsat:layers": "GEBCO_LATEST", - "landsat:dpiMode": "7", - "landsat:url": "https://www.gebco.net/data_and_products/gebco_web_services/web_map_service/mapserv", - "landsat:crs": "EPSG:4326", - "landsat:styles": "default", - "landsat:format": "image/jpeg", - "landsat:bbox": "-90,-180,90,180", - "landsat:version": "1.3.0", - "CRS": "EPSG:4326" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "map0:EXTENT": "-90,-180,90,180", + "map0:LAYERS": "EXTERNAL_WMS:landsat,Country", + "landsat:layers": "GEBCO_LATEST", + "landsat:dpiMode": "7", + "landsat:url": "https://www.gebco.net/data_and_products/gebco_web_services/web_map_service/mapserv", + "landsat:crs": "EPSG:4326", + "landsat:styles": "default", + "landsat:format": "image/jpeg", + "landsat:bbox": "-90,-180,90,180", + "landsat:version": "1.3.0", + "CRS": "EPSG:4326", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_External") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_wms_getprint_atlas.py b/tests/src/python/test_qgsserver_wms_getprint_atlas.py index cde28160dd4f..62efa7912891 100644 --- a/tests/src/python/test_qgsserver_wms_getprint_atlas.py +++ b/tests/src/python/test_qgsserver_wms_getprint_atlas.py @@ -9,14 +9,15 @@ (at your option) any later version. """ -__author__ = 'René-Luc DHONT' -__date__ = '24/06/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "René-Luc DHONT" +__date__ = "24/06/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import os # Needed on Qt 5 so that the serialization of XML is consistent among all executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" import urllib.parse @@ -30,36 +31,56 @@ class TestQgsServerWMSGetPrintAtlas(QgsServerTestBase): """QGIS Server WMS Tests for GetPrint atlas request""" def __test_wms_getprint_atlas(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "CRS": "EPSG:3857", - "ATLAS_PK": "3", - "map0:LAYERS": "Country,Hello", - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "CRS": "EPSG:3857", + "ATLAS_PK": "3", + "map0:LAYERS": "Country,Hello", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_Atlas") def __test_wms_getprint_atlas_getProjectSettings(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.3.0", - "REQUEST": "GetProjectSettings", - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetProjectSettings", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self.assertIn('atlasEnabled="1"', str(r)) - self.assertIn('', str(r)) + self.assertIn("", str(r)) def test_wms_getprint_atlas_no_pk(self): """Test issue GH #30817""" project = QgsProject() - self.assertTrue(project.read(os.path.join(unitTestDataPath(), 'qgis_server', 'bug_gh30817_atlas_pk.qgs'))) + self.assertTrue( + project.read( + os.path.join( + unitTestDataPath(), "qgis_server", "bug_gh30817_atlas_pk.qgs" + ) + ) + ) params = { "SERVICE": "WMS", "VERSION": "1.3.0", @@ -76,12 +97,12 @@ def test_wms_getprint_atlas_no_pk(self): self._img_diff_error(r, h, "WMS_GetPrint_Atlas_No_Pk") # Test issue GH #49900: when using map scales scale - params['TEMPLATE'] = 'layout_fixed_scale' - params['ATLAS_PK'] = '4' + params["TEMPLATE"] = "layout_fixed_scale" + params["ATLAS_PK"] = "4" qs = "?" + "&".join(["%s=%s" % i for i in list(params.items())]) r, h = self._result(self._execute_request_project(qs, project)) self._img_diff_error(r, h, "WMS_GetPrint_Atlas_Fixed_Scale") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_wms_getprint_extra.py b/tests/src/python/test_qgsserver_wms_getprint_extra.py index f93b37b00ba5..8915602f56b9 100644 --- a/tests/src/python/test_qgsserver_wms_getprint_extra.py +++ b/tests/src/python/test_qgsserver_wms_getprint_extra.py @@ -9,14 +9,15 @@ (at your option) any later version. """ -__author__ = 'René-Luc DHONT' -__date__ = '25/06/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "René-Luc DHONT" +__date__ = "25/06/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import os # Needed on Qt 5 so that the serialization of XML is consistent among all executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" import urllib.parse @@ -29,147 +30,200 @@ class TestQgsServerWMSGetPrintExtra(QgsServerTestBase): """QGIS Server WMS Tests for GetPrint group request""" def test_wms_getprint_selection(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "LAYERS": "Country,Hello", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country,Hello", - "CRS": "EPSG:3857", - "SELECTION": "Country: 4" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "LAYERS": "Country,Hello", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country,Hello", + "CRS": "EPSG:3857", + "SELECTION": "Country: 4", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_Selection") def test_wms_getprint_opacity(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0%3AEXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country,Hello", - "CRS": "EPSG:3857", - "SELECTION": "Country: 4", - "LAYERS": "Country,Hello", - "OPACITIES": "125,125" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0%3AEXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country,Hello", + "CRS": "EPSG:3857", + "SELECTION": "Country: 4", + "LAYERS": "Country,Hello", + "OPACITIES": "125,125", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_Opacity") def test_wms_getprint_opacity_post(self): - qs = "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0%3AEXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country,Hello", - "CRS": "EPSG:3857", - "SELECTION": "Country: 4", - "LAYERS": "Country,Hello", - "OPACITIES": "125%2C125" - }.items())]) - - r, h = self._result(self._execute_request('', QgsServerRequest.PostMethod, data=qs.encode('utf-8'))) + qs = "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0%3AEXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country,Hello", + "CRS": "EPSG:3857", + "SELECTION": "Country: 4", + "LAYERS": "Country,Hello", + "OPACITIES": "125%2C125", + }.items() + ) + ] + ) + + r, h = self._result( + self._execute_request( + "", QgsServerRequest.PostMethod, data=qs.encode("utf-8") + ) + ) self._img_diff_error(r, h, "WMS_GetPrint_Opacity") def test_wms_getprint_highlight(self): # default style - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country_Labels", - "map0:HIGHLIGHT_GEOM": "POLYGON((-15000000 10000000, -15000000 6110620, 2500000 6110620, 2500000 10000000, -15000000 10000000))", - "map0:HIGHLIGHT_SYMBOL": "HighlightSymbol%23ea117311.6", - "map0:HIGHLIGHT_LABELSTRING": "Highlight Layer!", - "map0:HIGHLIGHT_LABELFONT": "QGIS Vera Sans", - "map0:HIGHLIGHT_LABELSIZE": "20", - "map0:HIGHLIGHT_LABELCOLOR": "%2300FF0000", - "map0:HIGHLIGHT_LABELBUFFERCOLOR": "%232300FF00", - "map0:HIGHLIGHT_LABELBUFFERSIZE": "1.5", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country_Labels", + "map0:HIGHLIGHT_GEOM": "POLYGON((-15000000 10000000, -15000000 6110620, 2500000 6110620, 2500000 10000000, -15000000 10000000))", + "map0:HIGHLIGHT_SYMBOL": 'HighlightSymbol%23ea117311.6', + "map0:HIGHLIGHT_LABELSTRING": "Highlight Layer!", + "map0:HIGHLIGHT_LABELFONT": "QGIS Vera Sans", + "map0:HIGHLIGHT_LABELSIZE": "20", + "map0:HIGHLIGHT_LABELCOLOR": "%2300FF0000", + "map0:HIGHLIGHT_LABELBUFFERCOLOR": "%232300FF00", + "map0:HIGHLIGHT_LABELBUFFERSIZE": "1.5", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - assert h.get("Content-Type").startswith('image'), r + assert h.get("Content-Type").startswith("image"), r self._img_diff_error(r, h, "WMS_GetPrint_Highlight") def test_wms_getprint_highlight_labeldistance(self): # default style - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country_Labels", - "map0:HIGHLIGHT_GEOM": "LINESTRING(-15000000 6110620, 2500000 6110620)", - "map0:HIGHLIGHT_SYMBOL": "HighlightSymbol%23ea117311.6", - "map0:HIGHLIGHT_LABELSTRING": "Highlight Layer!", - "map0:HIGHLIGHT_LABELFONT": "QGIS Vera Sans", - "map0:HIGHLIGHT_LABELSIZE": "16", - "map0:HIGHLIGHT_LABELCOLOR": "%2300FF0000", - "map0:HIGHLIGHT_LABELBUFFERCOLOR": "%232300FF00", - "map0:HIGHLIGHT_LABELBUFFERSIZE": "1.5", - "map0:HIGHLIGHT_LABEL_DISTANCE": "5", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country_Labels", + "map0:HIGHLIGHT_GEOM": "LINESTRING(-15000000 6110620, 2500000 6110620)", + "map0:HIGHLIGHT_SYMBOL": 'HighlightSymbol%23ea117311.6', + "map0:HIGHLIGHT_LABELSTRING": "Highlight Layer!", + "map0:HIGHLIGHT_LABELFONT": "QGIS Vera Sans", + "map0:HIGHLIGHT_LABELSIZE": "16", + "map0:HIGHLIGHT_LABELCOLOR": "%2300FF0000", + "map0:HIGHLIGHT_LABELBUFFERCOLOR": "%232300FF00", + "map0:HIGHLIGHT_LABELBUFFERSIZE": "1.5", + "map0:HIGHLIGHT_LABEL_DISTANCE": "5", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - assert h.get("Content-Type").startswith('image'), r + assert h.get("Content-Type").startswith("image"), r self._img_diff_error(r, h, "WMS_GetPrint_Highlight_Labeldistance") def test_wms_getprint_label(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country,Hello", - "CRS": "EPSG:3857", - "IDTEXTBOX": "Updated QGIS composer label" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country,Hello", + "CRS": "EPSG:3857", + "IDTEXTBOX": "Updated QGIS composer label", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_LabelUpdated") - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "png", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country,Hello", - "CRS": "EPSG:3857", - "IDTEXTBOX": "" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "png", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country,Hello", + "CRS": "EPSG:3857", + "IDTEXTBOX": "", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetPrint_LabelRemoved") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_wms_getprint_legend.py b/tests/src/python/test_qgsserver_wms_getprint_legend.py index 1c8ac6006a1d..089e1a642289 100644 --- a/tests/src/python/test_qgsserver_wms_getprint_legend.py +++ b/tests/src/python/test_qgsserver_wms_getprint_legend.py @@ -9,15 +9,16 @@ (at your option) any later version. """ -__author__ = 'Sebastien Peillet' -__date__ = '30/06/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Sebastien Peillet" +__date__ = "30/06/2021" +__copyright__ = "Copyright 2021, The QGIS Project" import os import shutil # Needed on Qt 5 so that the serialization of XML is consistent among all executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" from qgis.core import QgsProject from qgis.PyQt.QtCore import QTemporaryDir @@ -34,19 +35,27 @@ class PyQgsServerWMSGetPrintLegend(QgsServerTestBase): def test_wms_getprint_legend(self): """Test project has 2 layer: red and green and five templates: - red: follow map theme red - green: follow map theme green - blank: no map theme - full: follow map theme full with both layer - falsegreen : follow map theme falsegreen (visible layer : green but with blue style) + red: follow map theme red + green: follow map theme green + blank: no map theme + full: follow map theme full with both layer + falsegreen : follow map theme falsegreen (visible layer : green but with blue style) """ tmp_dir = QTemporaryDir() - shutil.copyfile(os.path.join(unitTestDataPath('qgis_server'), 'test_project_legend.qgs'), os.path.join(tmp_dir.path(), 'test_project_legend.qgs')) - shutil.copyfile(os.path.join(unitTestDataPath('qgis_server'), 'test_project_legend.gpkg'), os.path.join(tmp_dir.path(), 'test_project_legend.gpkg')) + shutil.copyfile( + os.path.join(unitTestDataPath("qgis_server"), "test_project_legend.qgs"), + os.path.join(tmp_dir.path(), "test_project_legend.qgs"), + ) + shutil.copyfile( + os.path.join(unitTestDataPath("qgis_server"), "test_project_legend.gpkg"), + os.path.join(tmp_dir.path(), "test_project_legend.gpkg"), + ) project = QgsProject() - self.assertTrue(project.read(os.path.join(tmp_dir.path(), 'test_project_legend.qgs'))) + self.assertTrue( + project.read(os.path.join(tmp_dir.path(), "test_project_legend.qgs")) + ) params = { "SERVICE": "WMS", @@ -59,7 +68,7 @@ def test_wms_getprint_legend(self): "map0:SCALE": "281285", "map0:LAYERS": "red", "CRS": "EPSG:3857", - "DPI": '72' + "DPI": "72", } ###################################################### @@ -70,7 +79,9 @@ def test_wms_getprint_legend(self): # blank template, no theme, no LAYERS, specified map0:LAYERS is red response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -81,7 +92,9 @@ def test_wms_getprint_legend(self): # blank template, no LAYERS, specified map0:LAYERS is green params["map0:LAYERS"] = "green" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -92,7 +105,9 @@ def test_wms_getprint_legend(self): # blank template params["map0:LAYERS"] = "" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -104,7 +119,9 @@ def test_wms_getprint_legend(self): params["TEMPLATE"] = "red" params["map0:LAYERS"] = "red" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -115,7 +132,9 @@ def test_wms_getprint_legend(self): # red template, red theme, specified map0:LAYERS is green params["map0:LAYERS"] = "green" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -126,7 +145,9 @@ def test_wms_getprint_legend(self): # red template, red theme, no map0:LAYERS params["map0:LAYERS"] = "" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -138,7 +159,9 @@ def test_wms_getprint_legend(self): params["TEMPLATE"] = "green" params["map0:LAYERS"] = "red" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -149,7 +172,9 @@ def test_wms_getprint_legend(self): # green template, green theme, specified map0:LAYERS is green params["map0:LAYERS"] = "green" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -160,7 +185,9 @@ def test_wms_getprint_legend(self): # green template, green theme, no map0:LAYERS params["map0:LAYERS"] = "" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -172,7 +199,9 @@ def test_wms_getprint_legend(self): params["TEMPLATE"] = "full" params["map0:LAYERS"] = "red" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -183,7 +212,9 @@ def test_wms_getprint_legend(self): # full template, full theme, specified map0:LAYERS is green params["map0:LAYERS"] = "green" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -194,7 +225,9 @@ def test_wms_getprint_legend(self): # full template, full theme, no map0:LAYERS params["map0:LAYERS"] = "" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -206,7 +239,9 @@ def test_wms_getprint_legend(self): params["TEMPLATE"] = "falsegreen" params["map0:LAYERS"] = "red" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -217,7 +252,9 @@ def test_wms_getprint_legend(self): # full template, full theme, specified map0:LAYERS is green params["map0:LAYERS"] = "green" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -228,7 +265,9 @@ def test_wms_getprint_legend(self): # full template, full theme, no map0:LAYERS params["map0:LAYERS"] = "" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -237,5 +276,5 @@ def test_wms_getprint_legend(self): self._assertWhite(image.pixelColor(600, 60)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_wms_getprint_maptheme.py b/tests/src/python/test_qgsserver_wms_getprint_maptheme.py index a220cef2f4c7..32f559466a7f 100644 --- a/tests/src/python/test_qgsserver_wms_getprint_maptheme.py +++ b/tests/src/python/test_qgsserver_wms_getprint_maptheme.py @@ -9,14 +9,15 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '24/05/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "24/05/2021" +__copyright__ = "Copyright 2021, The QGIS Project" import os # Needed on Qt 5 so that the serialization of XML is consistent among all executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" from qgis.core import QgsProject from qgis.PyQt.QtGui import QImage @@ -34,16 +35,20 @@ def setUpClass(cls): super().setUpClass() project = QgsProject() - assert (project.read(os.path.join(cls.temporary_path, 'qgis_server', 'test_project_mapthemes.qgs'))) + assert project.read( + os.path.join( + cls.temporary_path, "qgis_server", "test_project_mapthemes.qgs" + ) + ) cls.project = project - cls.polygon = 'POLYGON((7.09769689415099325 44.92867722467413216, 7.37818833364500737 44.92867722467413216, 7.37818833364500737 45.0714498943264914, 7.09769689415099325 45.0714498943264914, 7.09769689415099325 44.92867722467413216))' + cls.polygon = "POLYGON((7.09769689415099325 44.92867722467413216, 7.37818833364500737 44.92867722467413216, 7.37818833364500737 45.0714498943264914, 7.09769689415099325 45.0714498943264914, 7.09769689415099325 44.92867722467413216))" def test_wms_getprint_maptheme(self): """Test templates green and red have 2 layers: red and green - template red: follow map theme red - template green: follow map theme green - template blank: no map theme + template red: follow map theme red + template green: follow map theme green + template blank: no map theme """ project = self.project @@ -58,7 +63,7 @@ def test_wms_getprint_maptheme(self): "map0:EXTENT": "44.92867722467413216,7.097696894150993252,45.0714498943264914,7.378188333645007368", "map0:LAYERS": "red", "CRS": "EPSG:4326", - "DPI": '72' + "DPI": "72", } ###################################################### @@ -66,7 +71,9 @@ def test_wms_getprint_maptheme(self): # blank template, specified layer is red response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -75,7 +82,9 @@ def test_wms_getprint_maptheme(self): # blank template, specified layer is green params["map0:LAYERS"] = "green" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -85,7 +94,9 @@ def test_wms_getprint_maptheme(self): params["map0:LAYERS"] = "" params["TEMPLATE"] = "red" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -95,7 +106,9 @@ def test_wms_getprint_maptheme(self): params["map0:LAYERS"] = "" params["TEMPLATE"] = "green" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -107,7 +120,9 @@ def test_wms_getprint_maptheme(self): params["map0:LAYERS"] = "red" params["TEMPLATE"] = "green" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -117,7 +132,9 @@ def test_wms_getprint_maptheme(self): params["LAYERS"] = "red" params["TEMPLATE"] = "green" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -129,7 +146,9 @@ def test_wms_getprint_maptheme(self): params["map0:LAYERS"] = "green" params["TEMPLATE"] = "red" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -137,27 +156,29 @@ def test_wms_getprint_maptheme(self): def test_wms_getprint_maptheme_multiple_maps(self): """Test template points has 4 layers: points_black, points_red, points_green, points_blue - the template has two maps (from top to bottom) map1 and map0 using - respectively the 4points-red and 4points-green map themes + the template has two maps (from top to bottom) map1 and map0 using + respectively the 4points-red and 4points-green map themes """ project = self.project # No LAYERS specified params = { - 'SERVICE': 'WMS', - 'VERSION': '1.3.0', - 'REQUEST': 'GetPrint', - 'TEMPLATE': 'points', - 'FORMAT': 'png', - 'map0:EXTENT': '44.66151222233335716,6.71202136069002187,45.25042454764368927,7.83398711866607833', - 'CRS': 'EPSG:4326', - 'DPI': '72', - 'map1:EXTENT': '44.66151222233335716,6.71202136069002187,45.25042454764368927,7.83398711866607833' + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetPrint", + "TEMPLATE": "points", + "FORMAT": "png", + "map0:EXTENT": "44.66151222233335716,6.71202136069002187,45.25042454764368927,7.83398711866607833", + "CRS": "EPSG:4326", + "DPI": "72", + "map1:EXTENT": "44.66151222233335716,6.71202136069002187,45.25042454764368927,7.83398711866607833", } response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -176,7 +197,9 @@ def test_wms_getprint_maptheme_multiple_maps(self): # Black LAYERS params["LAYERS"] = "points_black" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -196,7 +219,9 @@ def test_wms_getprint_maptheme_multiple_maps(self): del params["LAYERS"] params["map0:LAYERS"] = "points_black" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -217,7 +242,9 @@ def test_wms_getprint_maptheme_multiple_maps(self): params["map0:LAYERS"] = "points_blue" params["LAYERS"] = "points_black" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -235,30 +262,32 @@ def test_wms_getprint_maptheme_multiple_maps(self): def test_wms_getprint_maptheme_highlight(self): """Test templates green and red have 2 layers: red and green - template red: follow map theme red - template green: follow map theme green - template blank: no map theme + template red: follow map theme red + template green: follow map theme green + template blank: no map theme """ project = self.project params = { - 'SERVICE': 'WMS', - 'VERSION': '1.3.0', - 'REQUEST': 'GetPrint', - 'TEMPLATE': 'blank', - 'FORMAT': 'png', - 'LAYERS': '', - 'map0:EXTENT': '44.92867722467413216,7.097696894150993252,45.0714498943264914,7.378188333645007368', - 'map0:LAYERS': 'red', - 'CRS': 'EPSG:4326', - 'DPI': '72', - 'map0:HIGHLIGHT_GEOM': self.polygon, - 'map0:HIGHLIGHT_SYMBOL': r'%230000FF' + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetPrint", + "TEMPLATE": "blank", + "FORMAT": "png", + "LAYERS": "", + "map0:EXTENT": "44.92867722467413216,7.097696894150993252,45.0714498943264914,7.378188333645007368", + "map0:LAYERS": "red", + "CRS": "EPSG:4326", + "DPI": "72", + "map0:HIGHLIGHT_GEOM": self.polygon, + "map0:HIGHLIGHT_SYMBOL": r'%230000FF', } response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -269,7 +298,9 @@ def test_wms_getprint_maptheme_highlight(self): params["map0:LAYERS"] = "" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -279,7 +310,9 @@ def test_wms_getprint_maptheme_highlight(self): params["TEMPLATE"] = "red" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -289,7 +322,9 @@ def test_wms_getprint_maptheme_highlight(self): params["TEMPLATE"] = "green" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -300,7 +335,9 @@ def test_wms_getprint_maptheme_highlight(self): params["LAYERS"] = "red" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -313,20 +350,22 @@ def test_wms_getprint_atlas_dd_theme_(self): # No LAYERS specified params = { - 'SERVICE': 'WMS', - 'VERSION': '1.3.0', - 'REQUEST': 'GetPrint', - 'TEMPLATE': 'data_defined_theme', - 'FORMAT': 'png', - 'CRS': 'EPSG:4326', - 'DPI': '72', + "SERVICE": "WMS", + "VERSION": "1.3.0", + "REQUEST": "GetPrint", + "TEMPLATE": "data_defined_theme", + "FORMAT": "png", + "CRS": "EPSG:4326", + "DPI": "72", } def _test_red(): - params['ATLAS_PK'] = '2' + params["ATLAS_PK"] = "2" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -335,10 +374,12 @@ def _test_red(): self._assertWhite(image.pixelColor(685, 150)) def _test_green(): - params['ATLAS_PK'] = '4' + params["ATLAS_PK"] = "4" response = QgsBufferServerResponse() - request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()])) + request = QgsBufferServerRequest( + "?" + "&".join(["%s=%s" % i for i in params.items()]) + ) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") @@ -353,5 +394,5 @@ def _test_green(): _test_green() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_wms_getprint_outputs.py b/tests/src/python/test_qgsserver_wms_getprint_outputs.py index 4cbf479dad1e..45821f21b13f 100644 --- a/tests/src/python/test_qgsserver_wms_getprint_outputs.py +++ b/tests/src/python/test_qgsserver_wms_getprint_outputs.py @@ -9,14 +9,15 @@ (at your option) any later version. """ -__author__ = 'René-Luc DHONT' -__date__ = '24/06/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "René-Luc DHONT" +__date__ = "24/06/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import os # Needed on Qt 5 so that the serialization of XML is consistent among all executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" import subprocess import tempfile @@ -43,7 +44,7 @@ def _pdf_to_png(self, pdf_file_path, rendered_file_path, page, dpi=96): # * Poppler w/o Cairo does not always correctly render vectors in PDF to image # * muPDF renders correctly, but slightly shifts colors for util in [ - 'pdftocairo', + "pdftocairo", # 'mudraw', ]: PDFUTIL = getExecutablePath(util) @@ -52,37 +53,62 @@ def _pdf_to_png(self, pdf_file_path, rendered_file_path, page, dpi=96): # noinspection PyUnboundLocalVariable if not PDFUTIL: - assert False, ('PDF-to-image utility not found on PATH: ' - 'install Poppler (with Cairo)') + assert False, ( + "PDF-to-image utility not found on PATH: " + "install Poppler (with Cairo)" + ) - if PDFUTIL.strip().endswith('pdftocairo'): + if PDFUTIL.strip().endswith("pdftocairo"): filebase = os.path.join( os.path.dirname(rendered_file_path), - os.path.splitext(os.path.basename(rendered_file_path))[0] + os.path.splitext(os.path.basename(rendered_file_path))[0], ) call = [ - PDFUTIL, '-png', '-singlefile', '-r', str(dpi), - '-x', '0', '-y', '0', '-f', str(page), '-l', str(page), - pdf_file_path, filebase + PDFUTIL, + "-png", + "-singlefile", + "-r", + str(dpi), + "-x", + "0", + "-y", + "0", + "-f", + str(page), + "-l", + str(page), + pdf_file_path, + filebase, ] - elif PDFUTIL.strip().endswith('mudraw'): + elif PDFUTIL.strip().endswith("mudraw"): call = [ - PDFUTIL, '-c', 'rgba', - '-r', str(dpi), '-f', str(page), '-l', str(page), + PDFUTIL, + "-c", + "rgba", + "-r", + str(dpi), + "-f", + str(page), + "-l", + str(page), # '-b', '8', - '-o', rendered_file_path, pdf_file_path + "-o", + rendered_file_path, + pdf_file_path, ] else: - return False, '' + return False, "" print(f"exportToPdf call: {' '.join(call)}") try: subprocess.check_call(call) except subprocess.CalledProcessError as e: - assert False, ("exportToPdf failed!\n" - "cmd: {}\n" - "returncode: {}\n" - "message: {}".format(e.cmd, e.returncode, e.message)) + assert False, ( + "exportToPdf failed!\n" + "cmd: {}\n" + "returncode: {}\n" + "message: {}".format(e.cmd, e.returncode, e.message) + ) def _pdf_diff(self, pdf, control_image, max_diff, max_size_diff=QSize(), dpi=96): @@ -103,23 +129,38 @@ def _pdf_diff(self, pdf, control_image, max_diff, max_size_diff=QSize(), dpi=96) color_tolerance=0, allowed_mismatch=max_diff, size_tolerance=max_size_diff, - control_path_prefix="qgis_server" + control_path_prefix="qgis_server", ) - def _pdf_diff_error(self, response, headers, image, max_diff=100, max_size_diff=QSize(), - unittest_data_path='control_images', dpi=96): - - reference_path = unitTestDataPath(unittest_data_path) + '/qgis_server/' + image + '/' + image + '.pdf' + def _pdf_diff_error( + self, + response, + headers, + image, + max_diff=100, + max_size_diff=QSize(), + unittest_data_path="control_images", + dpi=96, + ): + + reference_path = ( + unitTestDataPath(unittest_data_path) + + "/qgis_server/" + + image + + "/" + + image + + ".pdf" + ) self.store_reference(reference_path, response) self.assertEqual( - headers.get("Content-Type"), 'application/pdf', - f"Content type is wrong: {headers.get('Content-Type')} instead of application/pdf\n{response}") - - self.assertTrue( - self._pdf_diff(response, image, max_diff, max_size_diff, dpi) + headers.get("Content-Type"), + "application/pdf", + f"Content type is wrong: {headers.get('Content-Type')} instead of application/pdf\n{response}", ) + self.assertTrue(self._pdf_diff(response, image, max_diff, max_size_diff, dpi)) + def _svg_to_png(svg_file_path, rendered_file_path, width): svgr = QSvgRenderer(svg_file_path) @@ -133,7 +174,7 @@ def _svg_to_png(svg_file_path, rendered_file_path, width): svgr.render(p) p.end() - res = image.save(rendered_file_path, 'png') + res = image.save(rendered_file_path, "png") if not res: os.unlink(rendered_file_path) @@ -142,33 +183,47 @@ def _svg_to_png(svg_file_path, rendered_file_path, width): def test_wms_getprint_basic(self): # Output JPEG - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "jpeg", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "LAYERS": "Country,Hello", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "jpeg", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "LAYERS": "Country,Hello", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self._img_diff_error(r, h, "WMS_GetPrint_Basic", outputFormat='JPG') + self._img_diff_error(r, h, "WMS_GetPrint_Basic", outputFormat="JPG") # Output PDF - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "pdf", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "LAYERS": "Country,Hello", - "CRS": "EPSG:3857" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "pdf", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "LAYERS": "Country,Hello", + "CRS": "EPSG:3857", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._pdf_diff_error(r, h, "WMS_GetPrint_Basic_Pdf", dpi=300) @@ -176,23 +231,30 @@ def test_wms_getprint_basic(self): def test_wms_getprint_selection(self): # Output PDF - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetPrint", - "TEMPLATE": "layoutA4", - "FORMAT": "pdf", - "LAYERS": "Country,Hello", - "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", - "map0:LAYERS": "Country,Hello", - "CRS": "EPSG:3857", - "SELECTION": "Country: 4" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetPrint", + "TEMPLATE": "layoutA4", + "FORMAT": "pdf", + "LAYERS": "Country,Hello", + "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031", + "map0:LAYERS": "Country,Hello", + "CRS": "EPSG:3857", + "SELECTION": "Country: 4", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._pdf_diff_error(r, h, "WMS_GetPrint_Selection_Pdf", dpi=300) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserver_wmts.py b/tests/src/python/test_qgsserver_wmts.py index 9dbf218205a3..e47993ecf291 100644 --- a/tests/src/python/test_qgsserver_wmts.py +++ b/tests/src/python/test_qgsserver_wmts.py @@ -9,14 +9,15 @@ (at your option) any later version. """ -__author__ = 'René-Luc Dhont' -__date__ = '19/09/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "René-Luc Dhont" +__date__ = "19/09/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os # Needed on Qt 5 so that the serialization of XML is consistent among all executions -os.environ['QT_HASH_SEED'] = '1' +os.environ["QT_HASH_SEED"] = "1" import re import urllib.error @@ -30,8 +31,8 @@ from test_qgsserver import QgsServerTestBase # Strip path and content length because path may vary -RE_STRIP_UNCHECKABLE = br'MAP=[^"]+|Content-Length: \d+|timeStamp="[^"]+"' -RE_ATTRIBUTES = br'[^>\s]+=[^>\s]+' +RE_STRIP_UNCHECKABLE = rb'MAP=[^"]+|Content-Length: \d+|timeStamp="[^"]+"' +RE_ATTRIBUTES = rb"[^>\s]+=[^>\s]+" class TestQgsServerWMTS(QgsServerTestBase): @@ -40,18 +41,27 @@ class TestQgsServerWMTS(QgsServerTestBase): # Set to True to re-generate reference files for this class regenerate_reference = False - def wmts_request_compare(self, request, version='', extra_query_string='', reference_base_name=None, project=None): + def wmts_request_compare( + self, + request, + version="", + extra_query_string="", + reference_base_name=None, + project=None, + ): # project = self.testdata_path + "test_project_wfs.qgs" if not project: project = self.projectGroupsPath assert os.path.exists(project), "Project file not found: " + project - query_string = f'?MAP={urllib.parse.quote(project)}&SERVICE=WMTS&REQUEST={request}' + query_string = ( + f"?MAP={urllib.parse.quote(project)}&SERVICE=WMTS&REQUEST={request}" + ) if version: - query_string += f'&VERSION={version}' + query_string += f"&VERSION={version}" if extra_query_string: - query_string += f'&{extra_query_string}' + query_string += f"&{extra_query_string}" header, body = self._execute_request(query_string) self.assert_headers(header, body) @@ -60,28 +70,36 @@ def wmts_request_compare(self, request, version='', extra_query_string='', refer if reference_base_name is not None: reference_name = reference_base_name else: - reference_name = 'wmts_' + request.lower() + reference_name = "wmts_" + request.lower() - reference_name += '.txt' + reference_name += ".txt" reference_path = os.path.join(self.testdata_path, reference_name) self.store_reference(reference_path, response) - f = open(reference_path, 'rb') + f = open(reference_path, "rb") expected = f.read() f.close() - response = re.sub(RE_STRIP_UNCHECKABLE, b'', response) - expected = re.sub(RE_STRIP_UNCHECKABLE, b'', expected) - - self.assertXMLEqual(response, expected, msg=f"request {query_string} failed.\n Query: {request}") - - def wmts_request_compare_project(self, project, request, version='', extra_query_string='', - reference_base_name=None): - query_string = f'https://www.qgis.org/?SERVICE=WMTS&REQUEST={request}' + response = re.sub(RE_STRIP_UNCHECKABLE, b"", response) + expected = re.sub(RE_STRIP_UNCHECKABLE, b"", expected) + + self.assertXMLEqual( + response, expected, msg=f"request {query_string} failed.\n Query: {request}" + ) + + def wmts_request_compare_project( + self, + project, + request, + version="", + extra_query_string="", + reference_base_name=None, + ): + query_string = f"https://www.qgis.org/?SERVICE=WMTS&REQUEST={request}" if version: - query_string += f'&VERSION={version}' + query_string += f"&VERSION={version}" if extra_query_string: - query_string += f'&{extra_query_string}' + query_string += f"&{extra_query_string}" header, body = self._execute_request_project(query_string, project) self.assert_headers(header, body) @@ -90,226 +108,311 @@ def wmts_request_compare_project(self, project, request, version='', extra_query if reference_base_name is not None: reference_name = reference_base_name else: - reference_name = 'wmts_' + request.lower() + reference_name = "wmts_" + request.lower() - reference_name += '.txt' + reference_name += ".txt" reference_path = os.path.join(self.testdata_path, reference_name) self.store_reference(reference_path, response) - f = open(reference_path, 'rb') + f = open(reference_path, "rb") expected = f.read() f.close() - response = re.sub(RE_STRIP_UNCHECKABLE, b'', response) - expected = re.sub(RE_STRIP_UNCHECKABLE, b'', expected) + response = re.sub(RE_STRIP_UNCHECKABLE, b"", response) + expected = re.sub(RE_STRIP_UNCHECKABLE, b"", expected) - self.assertXMLEqual(response, expected, msg=f"request {query_string} failed.\n Query: {request}") + self.assertXMLEqual( + response, expected, msg=f"request {query_string} failed.\n Query: {request}" + ) def test_operation_not_supported(self): - qs = f'?MAP={urllib.parse.quote(self.projectPath)}&SERVICE=WFS&VERSION=1.0.0&REQUEST=NotAValidRequest' + qs = f"?MAP={urllib.parse.quote(self.projectPath)}&SERVICE=WFS&VERSION=1.0.0&REQUEST=NotAValidRequest" self._assert_status_code(501, qs) def test_project_wmts(self): """Test some WMTS request""" - for request in ('GetCapabilities',): + for request in ("GetCapabilities",): self.wmts_request_compare(request) # self.wmts_request_compare(request, '1.0.0') def test_getcapabilities_epsg_axis_inverted(self): - project = os.path.join(self.testdata_path, "test_project_wmts_epsg_axis_inverted.qgz") - self.wmts_request_compare('GetCapabilities', project=project, reference_base_name="wmts_getcapabilities_axis_inverted") + project = os.path.join( + self.testdata_path, "test_project_wmts_epsg_axis_inverted.qgz" + ) + self.wmts_request_compare( + "GetCapabilities", + project=project, + reference_base_name="wmts_getcapabilities_axis_inverted", + ) def test_wmts_gettile(self): # Testing project WMTS layer - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectGroupsPath), - "SERVICE": "WMTS", - "VERSION": "1.0.0", - "REQUEST": "GetTile", - "LAYER": "QGIS Server Hello World", - "STYLE": "", - "TILEMATRIXSET": "EPSG:3857", - "TILEMATRIX": "0", - "TILEROW": "0", - "TILECOL": "0", - "FORMAT": "image/png" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectGroupsPath), + "SERVICE": "WMTS", + "VERSION": "1.0.0", + "REQUEST": "GetTile", + "LAYER": "QGIS Server Hello World", + "STYLE": "", + "TILEMATRIXSET": "EPSG:3857", + "TILEMATRIX": "0", + "TILEROW": "0", + "TILECOL": "0", + "FORMAT": "image/png", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMTS_GetTile_Project_3857_0", 20000) - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectGroupsPath), - "SERVICE": "WMTS", - "VERSION": "1.0.0", - "REQUEST": "GetTile", - "LAYER": "QGIS Server Hello World", - "STYLE": "", - "TILEMATRIXSET": "EPSG:4326", - "TILEMATRIX": "0", - "TILEROW": "0", - "TILECOL": "0", - "FORMAT": "image/png" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectGroupsPath), + "SERVICE": "WMTS", + "VERSION": "1.0.0", + "REQUEST": "GetTile", + "LAYER": "QGIS Server Hello World", + "STYLE": "", + "TILEMATRIXSET": "EPSG:4326", + "TILEMATRIX": "0", + "TILEROW": "0", + "TILECOL": "0", + "FORMAT": "image/png", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMTS_GetTile_Project_4326_0", 20000) # Testing group WMTS layer - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectGroupsPath), - "SERVICE": "WMTS", - "VERSION": "1.0.0", - "REQUEST": "GetTile", - "LAYER": "CountryGroup", - "STYLE": "", - "TILEMATRIXSET": "EPSG:3857", - "TILEMATRIX": "0", - "TILEROW": "0", - "TILECOL": "0", - "FORMAT": "image/png" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectGroupsPath), + "SERVICE": "WMTS", + "VERSION": "1.0.0", + "REQUEST": "GetTile", + "LAYER": "CountryGroup", + "STYLE": "", + "TILEMATRIXSET": "EPSG:3857", + "TILEMATRIX": "0", + "TILEROW": "0", + "TILECOL": "0", + "FORMAT": "image/png", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMTS_GetTile_CountryGroup_3857_0", 20000) - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectGroupsPath), - "SERVICE": "WMTS", - "VERSION": "1.0.0", - "REQUEST": "GetTile", - "LAYER": "CountryGroup", - "STYLE": "", - "TILEMATRIXSET": "EPSG:4326", - "TILEMATRIX": "0", - "TILEROW": "0", - "TILECOL": "0", - "FORMAT": "image/png" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectGroupsPath), + "SERVICE": "WMTS", + "VERSION": "1.0.0", + "REQUEST": "GetTile", + "LAYER": "CountryGroup", + "STYLE": "", + "TILEMATRIXSET": "EPSG:4326", + "TILEMATRIX": "0", + "TILEROW": "0", + "TILECOL": "0", + "FORMAT": "image/png", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMTS_GetTile_CountryGroup_4326_0", 20000) # Testing QgsMapLayer WMTS layer - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectGroupsPath), - "SERVICE": "WMTS", - "VERSION": "1.0.0", - "REQUEST": "GetTile", - "LAYER": "Hello", - "STYLE": "", - "TILEMATRIXSET": "EPSG:3857", - "TILEMATRIX": "0", - "TILEROW": "0", - "TILECOL": "0", - "FORMAT": "image/png" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectGroupsPath), + "SERVICE": "WMTS", + "VERSION": "1.0.0", + "REQUEST": "GetTile", + "LAYER": "Hello", + "STYLE": "", + "TILEMATRIXSET": "EPSG:3857", + "TILEMATRIX": "0", + "TILEROW": "0", + "TILECOL": "0", + "FORMAT": "image/png", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMTS_GetTile_Hello_3857_0", 20000) - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectGroupsPath), - "SERVICE": "WMTS", - "VERSION": "1.0.0", - "REQUEST": "GetTile", - "LAYER": "Hello", - "STYLE": "", - "TILEMATRIXSET": "EPSG:4326", - "TILEMATRIX": "0", - "TILEROW": "0", - "TILECOL": "0", - "FORMAT": "image/png" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectGroupsPath), + "SERVICE": "WMTS", + "VERSION": "1.0.0", + "REQUEST": "GetTile", + "LAYER": "Hello", + "STYLE": "", + "TILEMATRIXSET": "EPSG:4326", + "TILEMATRIX": "0", + "TILEROW": "0", + "TILECOL": "0", + "FORMAT": "image/png", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMTS_GetTile_Hello_4326_0", 20000) def test_wmts_gettile_invalid_parameters(self): - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectGroupsPath), - "SERVICE": "WMTS", - "VERSION": "1.0.0", - "REQUEST": "GetTile", - "LAYER": "Hello", - "STYLE": "", - "TILEMATRIXSET": "EPSG:3857", - "TILEMATRIX": "0", - "TILEROW": "0", - "TILECOL": "FOO", - "FORMAT": "image/png" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectGroupsPath), + "SERVICE": "WMTS", + "VERSION": "1.0.0", + "REQUEST": "GetTile", + "LAYER": "Hello", + "STYLE": "", + "TILEMATRIXSET": "EPSG:3857", + "TILEMATRIX": "0", + "TILEROW": "0", + "TILECOL": "FOO", + "FORMAT": "image/png", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - err = b"TILECOL (\'FOO\') cannot be converted into int" in r + err = b"TILECOL ('FOO') cannot be converted into int" in r self.assertTrue(err) - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectGroupsPath), - "SERVICE": "WMTS", - "VERSION": "1.0.0", - "REQUEST": "GetTile", - "LAYER": "Hello", - "STYLE": "", - "TILEMATRIXSET": "EPSG:3857", - "TILEMATRIX": "0", - "TILEROW": "0", - "TILECOL": "1", - "FORMAT": "image/png" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectGroupsPath), + "SERVICE": "WMTS", + "VERSION": "1.0.0", + "REQUEST": "GetTile", + "LAYER": "Hello", + "STYLE": "", + "TILEMATRIXSET": "EPSG:3857", + "TILEMATRIX": "0", + "TILEROW": "0", + "TILECOL": "1", + "FORMAT": "image/png", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) err = b"TileCol is unknown" in r self.assertTrue(err) - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectGroupsPath), - "SERVICE": "WMTS", - "VERSION": "1.0.0", - "REQUEST": "GetTile", - "LAYER": "Hello", - "STYLE": "", - "TILEMATRIXSET": "EPSG:3857", - "TILEMATRIX": "0", - "TILEROW": "0", - "TILECOL": "-1", - "FORMAT": "image/png" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectGroupsPath), + "SERVICE": "WMTS", + "VERSION": "1.0.0", + "REQUEST": "GetTile", + "LAYER": "Hello", + "STYLE": "", + "TILEMATRIXSET": "EPSG:3857", + "TILEMATRIX": "0", + "TILEROW": "0", + "TILECOL": "-1", + "FORMAT": "image/png", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) err = b"TileCol is unknown" in r self.assertTrue(err) - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectGroupsPath), - "SERVICE": "WMTS", - "VERSION": "1.0.0", - "REQUEST": "GetTile", - "LAYER": "dem", - "STYLE": "", - "TILEMATRIXSET": "EPSG:3857", - "TILEMATRIX": "0", - "TILEROW": "0", - "TILECOL": "0", - "FORMAT": "image/png" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectGroupsPath), + "SERVICE": "WMTS", + "VERSION": "1.0.0", + "REQUEST": "GetTile", + "LAYER": "dem", + "STYLE": "", + "TILEMATRIXSET": "EPSG:3857", + "TILEMATRIX": "0", + "TILEROW": "0", + "TILECOL": "0", + "FORMAT": "image/png", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - err = b"Layer \'dem\' not found" in r + err = b"Layer 'dem' not found" in r self.assertTrue(err) - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectGroupsPath), - "SERVICE": "WMTS", - "VERSION": "1.0.0", - "REQUEST": "GetTile", - "LAYER": "Hello", - "STYLE": "", - "TILEMATRIXSET": "EPSG:2154", - "TILEMATRIX": "0", - "TILEROW": "0", - "TILECOL": "0", - "FORMAT": "image/png" - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectGroupsPath), + "SERVICE": "WMTS", + "VERSION": "1.0.0", + "REQUEST": "GetTile", + "LAYER": "Hello", + "STYLE": "", + "TILEMATRIXSET": "EPSG:2154", + "TILEMATRIX": "0", + "TILEROW": "0", + "TILECOL": "0", + "FORMAT": "image/png", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) err = b"TileMatrixSet is unknown" in r @@ -321,52 +424,77 @@ def test_wmts_config(self): project = QgsProject() project.read(projectPath) - self.wmts_request_compare_project(project, 'GetCapabilities', reference_base_name='wmts_getcapabilities_config') - - self.assertTrue(project.removeEntry('WMTSGrids', 'Config')) - self.assertTrue(project.removeEntry('WMTSGrids', 'CRS')) - self.wmts_request_compare_project(project, 'GetCapabilities', reference_base_name='wmts_getcapabilities_config') - - self.assertTrue(project.writeEntry('WMTSGrids', 'Config', - ('EPSG:3857,20037508.342789248,-20037508.342789248,559082264.0287179,20',))) - self.assertTrue(project.writeEntry('WMTSGrids', 'CRS', ('EPSG:3857',))) - self.wmts_request_compare_project(project, 'GetCapabilities', - reference_base_name='wmts_getcapabilities_config_3857') + self.wmts_request_compare_project( + project, + "GetCapabilities", + reference_base_name="wmts_getcapabilities_config", + ) + + self.assertTrue(project.removeEntry("WMTSGrids", "Config")) + self.assertTrue(project.removeEntry("WMTSGrids", "CRS")) + self.wmts_request_compare_project( + project, + "GetCapabilities", + reference_base_name="wmts_getcapabilities_config", + ) + + self.assertTrue( + project.writeEntry( + "WMTSGrids", + "Config", + ( + "EPSG:3857,20037508.342789248,-20037508.342789248,559082264.0287179,20", + ), + ) + ) + self.assertTrue(project.writeEntry("WMTSGrids", "CRS", ("EPSG:3857",))) + self.wmts_request_compare_project( + project, + "GetCapabilities", + reference_base_name="wmts_getcapabilities_config_3857", + ) def test_wmts_getfeatureinfo(self): """Test regression issue GH #57441""" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectGroupsPath), - "SERVICE": "WMTS", - "VERSION": "1.0.0", - "REQUEST": "GetFeatureInfo", - "LAYER": "QGIS Server Hello World", - "STYLE": "", - "TILEMATRIXSET": "EPSG:3857", - "TILEMATRIX": "0", - "TILEROW": "0", - "TILECOL": "0", - "I": "0", - "J": "0", - }.items())]) + qs = "?" + "&".join( + [ + "%s=%s" % i + for i in list( + { + "MAP": urllib.parse.quote(self.projectGroupsPath), + "SERVICE": "WMTS", + "VERSION": "1.0.0", + "REQUEST": "GetFeatureInfo", + "LAYER": "QGIS Server Hello World", + "STYLE": "", + "TILEMATRIXSET": "EPSG:3857", + "TILEMATRIX": "0", + "TILEROW": "0", + "TILECOL": "0", + "I": "0", + "J": "0", + }.items() + ) + ] + ) r, h = self._result(self._execute_request(qs)) - self.assertIn(b"RequestNotWellFormed\">InfoFormat is mandatory", r) + self.assertIn(b'RequestNotWellFormed">InfoFormat is mandatory', r) # Add INFOFORMAT qs2 = qs + "&INFOFORMAT=text/plain" r, h = self._result(self._execute_request(qs2)) self.assertNotIn(b"ormat is mandatory", r) - self.assertEqual(h['Content-Type'], "text/plain; charset=utf-8") + self.assertEqual(h["Content-Type"], "text/plain; charset=utf-8") # Try json format qs2 = qs + "&INFOFORMAT=application/json" r, h = self._result(self._execute_request(qs2)) self.assertNotIn(b"ormat is mandatory", r) - self.assertEqual(h['Content-Type'], "application/json; charset=utf-8") + self.assertEqual(h["Content-Type"], "application/json; charset=utf-8") # For back-compatibility with previous versions let's be good and accept FORMAT as well @@ -375,8 +503,8 @@ def test_wmts_getfeatureinfo(self): r, h = self._result(self._execute_request(qs2)) self.assertNotIn(b"ormat is mandatory", r) - self.assertEqual(h['Content-Type'], "application/json; charset=utf-8") + self.assertEqual(h["Content-Type"], "application/json; charset=utf-8") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsserverlogger.py b/tests/src/python/test_qgsserverlogger.py index aa4b92f014d0..bdacc75568fb 100644 --- a/tests/src/python/test_qgsserverlogger.py +++ b/tests/src/python/test_qgsserverlogger.py @@ -3,9 +3,10 @@ From build dir, run: ctest -R PyQgsServerLogger -V """ -__author__ = 'Eric Lemoine' -__date__ = '11/09/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Eric Lemoine" +__date__ = "11/09/2018" +__copyright__ = "Copyright 2018, The QGIS Project" import os @@ -17,7 +18,7 @@ class TestQgsServerLogger(unittest.TestCase): - log_file = os.path.join(unitTestDataPath('qgis_server'), 'qgis_server_test.log') + log_file = os.path.join(unitTestDataPath("qgis_server"), "qgis_server_test.log") @staticmethod def remove_file(filename): @@ -38,7 +39,7 @@ def tearDown(self): self.remove_file(self.log_file) def test_logging_no_log_file(self): - self.logger.setLogFile('') + self.logger.setLogFile("") exists = os.access(self.log_file, os.R_OK) self.assertFalse(exists) @@ -48,7 +49,7 @@ def test_logging_log_file(self): self.assertTrue(exists) def test_logging_log_file_stderr(self): - self.logger.setLogFile('stderr') + self.logger.setLogFile("stderr") exists = os.access(self.log_file, os.R_OK) self.assertFalse(exists) diff --git a/tests/src/python/test_qgssettings.py b/tests/src/python/test_qgssettings.py index c67460c1e834..77264153cb00 100644 --- a/tests/src/python/test_qgssettings.py +++ b/tests/src/python/test_qgssettings.py @@ -18,9 +18,9 @@ import unittest from qgis.testing import start_app, QgisTestCase -__author__ = 'Alessandro Pasotti' -__date__ = '02/02/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "02/02/2017" +__copyright__ = "Copyright 2017, The QGIS Project" start_app() @@ -32,11 +32,13 @@ class TestQgsSettings(QgisTestCase): def setUp(self): self.cnt += 1 - h, path = tempfile.mkstemp('.ini') + h, path = tempfile.mkstemp(".ini") Path(path).touch() assert QgsSettings.setGlobalSettingsPath(path) - self.settings = QgsSettings('testqgissettings', f'testqgissettings{self.cnt}') - self.globalsettings = QSettings(self.settings.globalSettingsPath(), QSettings.Format.IniFormat) + self.settings = QgsSettings("testqgissettings", f"testqgissettings{self.cnt}") + self.globalsettings = QSettings( + self.settings.globalSettingsPath(), QSettings.Format.IniFormat + ) self.globalsettings.sync() assert os.path.exists(self.globalsettings.fileName()) @@ -58,7 +60,9 @@ def addToDefaults(self, key, value): self.globalsettings.sync() def addArrayToDefaults(self, prefix, key, values): - defaults = QSettings(self.settings.globalSettingsPath(), QSettings.Format.IniFormat) # NOQA + defaults = QSettings( + self.settings.globalSettingsPath(), QSettings.Format.IniFormat + ) # NOQA self.globalsettings.beginWriteArray(prefix) i = 0 for v in values: @@ -69,7 +73,9 @@ def addArrayToDefaults(self, prefix, key, values): self.globalsettings.sync() def addGroupToDefaults(self, prefix, kvp): - defaults = QSettings(self.settings.globalSettingsPath(), QSettings.Format.IniFormat) # NOQA + defaults = QSettings( + self.settings.globalSettingsPath(), QSettings.Format.IniFormat + ) # NOQA self.globalsettings.beginGroup(prefix) for k, v in kvp.items(): self.globalsettings.setValue(k, v) @@ -77,160 +83,207 @@ def addGroupToDefaults(self, prefix, kvp): self.globalsettings.sync() def test_basic_functionality(self): - self.assertEqual(self.settings.value('testqgissettings/doesnotexists', 'notexist'), 'notexist') - self.settings.setValue('testqgissettings/name', 'qgisrocks') + self.assertEqual( + self.settings.value("testqgissettings/doesnotexists", "notexist"), + "notexist", + ) + self.settings.setValue("testqgissettings/name", "qgisrocks") self.settings.sync() - self.assertEqual(self.settings.value('testqgissettings/name'), 'qgisrocks') + self.assertEqual(self.settings.value("testqgissettings/name"), "qgisrocks") def test_defaults(self): - self.assertIsNone(self.settings.value('testqgissettings/name')) - self.addToDefaults('testqgissettings/name', 'qgisrocks') - self.assertEqual(self.settings.value('testqgissettings/name'), 'qgisrocks') + self.assertIsNone(self.settings.value("testqgissettings/name")) + self.addToDefaults("testqgissettings/name", "qgisrocks") + self.assertEqual(self.settings.value("testqgissettings/name"), "qgisrocks") def test_allkeys(self): self.assertEqual(self.settings.allKeys(), []) - self.addToDefaults('testqgissettings/name', 'qgisrocks') - self.addToDefaults('testqgissettings/name2', 'qgisrocks2') - self.settings.setValue('nepoti/eman', 'osaple') + self.addToDefaults("testqgissettings/name", "qgisrocks") + self.addToDefaults("testqgissettings/name2", "qgisrocks2") + self.settings.setValue("nepoti/eman", "osaple") self.assertEqual(3, len(self.settings.allKeys())) - self.assertIn('testqgissettings/name', self.settings.allKeys()) - self.assertIn('nepoti/eman', self.settings.allKeys()) - self.assertEqual('qgisrocks', self.settings.value('testqgissettings/name')) - self.assertEqual('qgisrocks2', self.settings.value('testqgissettings/name2')) - self.assertEqual('qgisrocks', self.globalsettings.value('testqgissettings/name')) - self.assertEqual('osaple', self.settings.value('nepoti/eman')) + self.assertIn("testqgissettings/name", self.settings.allKeys()) + self.assertIn("nepoti/eman", self.settings.allKeys()) + self.assertEqual("qgisrocks", self.settings.value("testqgissettings/name")) + self.assertEqual("qgisrocks2", self.settings.value("testqgissettings/name2")) + self.assertEqual( + "qgisrocks", self.globalsettings.value("testqgissettings/name") + ) + self.assertEqual("osaple", self.settings.value("nepoti/eman")) self.assertEqual(3, len(self.settings.allKeys())) self.assertEqual(2, len(self.globalsettings.allKeys())) def test_precedence_simple(self): self.assertEqual(self.settings.allKeys(), []) - self.addToDefaults('testqgissettings/names/name1', 'qgisrocks1') - self.settings.setValue('testqgissettings/names/name1', 'qgisrocks-1') + self.addToDefaults("testqgissettings/names/name1", "qgisrocks1") + self.settings.setValue("testqgissettings/names/name1", "qgisrocks-1") - self.assertEqual(self.settings.value('testqgissettings/names/name1'), 'qgisrocks-1') + self.assertEqual( + self.settings.value("testqgissettings/names/name1"), "qgisrocks-1" + ) def test_precedence_group(self): """Test if user can override a group value""" self.assertEqual(self.settings.allKeys(), []) - self.addGroupToDefaults('connections-xyz', { - 'OSM': 'http://a.tile.openstreetmap.org/{z}/{x}/{y}.png', - 'OSM-b': 'http://b.tile.openstreetmap.org/{z}/{x}/{y}.png', - }) - self.settings.beginGroup('connections-xyz') - self.assertEqual(self.settings.value('OSM'), 'http://a.tile.openstreetmap.org/{z}/{x}/{y}.png') - self.assertEqual(self.settings.value('OSM-b'), 'http://b.tile.openstreetmap.org/{z}/{x}/{y}.png') + self.addGroupToDefaults( + "connections-xyz", + { + "OSM": "http://a.tile.openstreetmap.org/{z}/{x}/{y}.png", + "OSM-b": "http://b.tile.openstreetmap.org/{z}/{x}/{y}.png", + }, + ) + self.settings.beginGroup("connections-xyz") + self.assertEqual( + self.settings.value("OSM"), + "http://a.tile.openstreetmap.org/{z}/{x}/{y}.png", + ) + self.assertEqual( + self.settings.value("OSM-b"), + "http://b.tile.openstreetmap.org/{z}/{x}/{y}.png", + ) self.settings.endGroup() # Override edit - self.settings.beginGroup('connections-xyz') - self.settings.setValue('OSM', 'http://c.tile.openstreetmap.org/{z}/{x}/{y}.png') + self.settings.beginGroup("connections-xyz") + self.settings.setValue("OSM", "http://c.tile.openstreetmap.org/{z}/{x}/{y}.png") self.settings.endGroup() # Check it again! - self.settings.beginGroup('connections-xyz') - self.assertEqual(self.settings.value('OSM'), 'http://c.tile.openstreetmap.org/{z}/{x}/{y}.png') - self.assertEqual(self.settings.value('OSM-b'), 'http://b.tile.openstreetmap.org/{z}/{x}/{y}.png') + self.settings.beginGroup("connections-xyz") + self.assertEqual( + self.settings.value("OSM"), + "http://c.tile.openstreetmap.org/{z}/{x}/{y}.png", + ) + self.assertEqual( + self.settings.value("OSM-b"), + "http://b.tile.openstreetmap.org/{z}/{x}/{y}.png", + ) self.settings.endGroup() # Override remove: the global value will be resumed!!! - self.settings.beginGroup('connections-xyz') - self.settings.remove('OSM') + self.settings.beginGroup("connections-xyz") + self.settings.remove("OSM") self.settings.endGroup() # Check it again! - self.settings.beginGroup('connections-xyz') - self.assertEqual(self.settings.value('OSM'), 'http://a.tile.openstreetmap.org/{z}/{x}/{y}.png') - self.assertEqual(self.settings.value('OSM-b'), 'http://b.tile.openstreetmap.org/{z}/{x}/{y}.png') + self.settings.beginGroup("connections-xyz") + self.assertEqual( + self.settings.value("OSM"), + "http://a.tile.openstreetmap.org/{z}/{x}/{y}.png", + ) + self.assertEqual( + self.settings.value("OSM-b"), + "http://b.tile.openstreetmap.org/{z}/{x}/{y}.png", + ) self.settings.endGroup() # Override remove: store a blank! - self.settings.beginGroup('connections-xyz') - self.settings.setValue('OSM', '') + self.settings.beginGroup("connections-xyz") + self.settings.setValue("OSM", "") self.settings.endGroup() # Check it again! - self.settings.beginGroup('connections-xyz') - self.assertEqual(self.settings.value('OSM'), '') - self.assertEqual(self.settings.value('OSM-b'), 'http://b.tile.openstreetmap.org/{z}/{x}/{y}.png') + self.settings.beginGroup("connections-xyz") + self.assertEqual(self.settings.value("OSM"), "") + self.assertEqual( + self.settings.value("OSM-b"), + "http://b.tile.openstreetmap.org/{z}/{x}/{y}.png", + ) self.settings.endGroup() # Override remove: store a None: will resume the global setting! - self.settings.beginGroup('connections-xyz') - self.settings.setValue('OSM', None) + self.settings.beginGroup("connections-xyz") + self.settings.setValue("OSM", None) self.settings.endGroup() # Check it again! - self.settings.beginGroup('connections-xyz') - self.assertEqual(self.settings.value('OSM'), 'http://a.tile.openstreetmap.org/{z}/{x}/{y}.png') - self.assertEqual(self.settings.value('OSM-b'), 'http://b.tile.openstreetmap.org/{z}/{x}/{y}.png') + self.settings.beginGroup("connections-xyz") + self.assertEqual( + self.settings.value("OSM"), + "http://a.tile.openstreetmap.org/{z}/{x}/{y}.png", + ) + self.assertEqual( + self.settings.value("OSM-b"), + "http://b.tile.openstreetmap.org/{z}/{x}/{y}.png", + ) self.settings.endGroup() def test_uft8(self): self.assertEqual(self.settings.allKeys(), []) - self.addToDefaults('testqgissettings/names/namèé↓1', 'qgisrocks↓1') - self.assertEqual(self.settings.value('testqgissettings/names/namèé↓1'), 'qgisrocks↓1') - - self.settings.setValue('testqgissettings/names/namèé↓2', 'qgisrocks↓2') - self.assertEqual(self.settings.value('testqgissettings/names/namèé↓2'), 'qgisrocks↓2') - self.settings.setValue('testqgissettings/names/namèé↓1', 'qgisrocks↓-1') - self.assertEqual(self.settings.value('testqgissettings/names/namèé↓1'), 'qgisrocks↓-1') + self.addToDefaults("testqgissettings/names/namèé↓1", "qgisrocks↓1") + self.assertEqual( + self.settings.value("testqgissettings/names/namèé↓1"), "qgisrocks↓1" + ) + + self.settings.setValue("testqgissettings/names/namèé↓2", "qgisrocks↓2") + self.assertEqual( + self.settings.value("testqgissettings/names/namèé↓2"), "qgisrocks↓2" + ) + self.settings.setValue("testqgissettings/names/namèé↓1", "qgisrocks↓-1") + self.assertEqual( + self.settings.value("testqgissettings/names/namèé↓1"), "qgisrocks↓-1" + ) def test_groups(self): self.assertEqual(self.settings.allKeys(), []) - self.addToDefaults('testqgissettings/names/name1', 'qgisrocks1') - self.addToDefaults('testqgissettings/names/name2', 'qgisrocks2') - self.addToDefaults('testqgissettings/names/name3', 'qgisrocks3') - self.addToDefaults('testqgissettings/name', 'qgisrocks') + self.addToDefaults("testqgissettings/names/name1", "qgisrocks1") + self.addToDefaults("testqgissettings/names/name2", "qgisrocks2") + self.addToDefaults("testqgissettings/names/name3", "qgisrocks3") + self.addToDefaults("testqgissettings/name", "qgisrocks") - self.settings.beginGroup('testqgissettings') - self.assertEqual(self.settings.group(), 'testqgissettings') - self.assertEqual(['names'], self.settings.childGroups()) + self.settings.beginGroup("testqgissettings") + self.assertEqual(self.settings.group(), "testqgissettings") + self.assertEqual(["names"], self.settings.childGroups()) - self.settings.setValue('surnames/name1', 'qgisrocks-1') - self.assertEqual(['surnames', 'names'], self.settings.childGroups()) + self.settings.setValue("surnames/name1", "qgisrocks-1") + self.assertEqual(["surnames", "names"], self.settings.childGroups()) - self.settings.setValue('names/name1', 'qgisrocks-1') - self.assertEqual('qgisrocks-1', self.settings.value('names/name1')) + self.settings.setValue("names/name1", "qgisrocks-1") + self.assertEqual("qgisrocks-1", self.settings.value("names/name1")) self.settings.endGroup() - self.assertEqual(self.settings.group(), '') - self.settings.beginGroup('testqgissettings/names') - self.assertEqual(self.settings.group(), 'testqgissettings/names') - self.settings.setValue('name4', 'qgisrocks-4') + self.assertEqual(self.settings.group(), "") + self.settings.beginGroup("testqgissettings/names") + self.assertEqual(self.settings.group(), "testqgissettings/names") + self.settings.setValue("name4", "qgisrocks-4") keys = sorted(self.settings.childKeys()) - self.assertEqual(keys, ['name1', 'name2', 'name3', 'name4']) + self.assertEqual(keys, ["name1", "name2", "name3", "name4"]) self.settings.endGroup() - self.assertEqual(self.settings.group(), '') - self.assertEqual('qgisrocks-1', self.settings.value('testqgissettings/names/name1')) - self.assertEqual('qgisrocks-4', self.settings.value('testqgissettings/names/name4')) + self.assertEqual(self.settings.group(), "") + self.assertEqual( + "qgisrocks-1", self.settings.value("testqgissettings/names/name1") + ) + self.assertEqual( + "qgisrocks-4", self.settings.value("testqgissettings/names/name4") + ) def test_global_groups(self): self.assertEqual(self.settings.allKeys(), []) self.assertEqual(self.globalsettings.allKeys(), []) - self.addToDefaults('testqgissettings/foo/first', 'qgis') - self.addToDefaults('testqgissettings/foo/last', 'rocks') + self.addToDefaults("testqgissettings/foo/first", "qgis") + self.addToDefaults("testqgissettings/foo/last", "rocks") - self.settings.beginGroup('testqgissettings') - self.assertEqual(self.settings.group(), 'testqgissettings') - self.assertEqual(['foo'], self.settings.childGroups()) - self.assertEqual(['foo'], self.settings.globalChildGroups()) + self.settings.beginGroup("testqgissettings") + self.assertEqual(self.settings.group(), "testqgissettings") + self.assertEqual(["foo"], self.settings.childGroups()) + self.assertEqual(["foo"], self.settings.globalChildGroups()) self.settings.endGroup() - self.assertEqual(self.settings.group(), '') + self.assertEqual(self.settings.group(), "") - self.settings.setValue('testqgissettings/bar/first', 'qgis') - self.settings.setValue('testqgissettings/bar/last', 'rocks') + self.settings.setValue("testqgissettings/bar/first", "qgis") + self.settings.setValue("testqgissettings/bar/last", "rocks") - self.settings.beginGroup('testqgissettings') - self.assertEqual(sorted(['bar', 'foo']), sorted(self.settings.childGroups())) - self.assertEqual(['foo'], self.settings.childGroups(Qgis.SettingsOrigin.Global)) - self.assertEqual(['bar'], self.settings.childGroups(Qgis.SettingsOrigin.Local)) + self.settings.beginGroup("testqgissettings") + self.assertEqual(sorted(["bar", "foo"]), sorted(self.settings.childGroups())) + self.assertEqual(["foo"], self.settings.childGroups(Qgis.SettingsOrigin.Global)) + self.assertEqual(["bar"], self.settings.childGroups(Qgis.SettingsOrigin.Local)) self.settings.endGroup() - self.globalsettings.remove('testqgissettings/foo') + self.globalsettings.remove("testqgissettings/foo") - self.settings.beginGroup('testqgissettings') - self.assertEqual(['bar'], self.settings.childGroups()) + self.settings.beginGroup("testqgissettings") + self.assertEqual(["bar"], self.settings.childGroups()) self.assertEqual([], self.settings.globalChildGroups()) self.settings.endGroup() @@ -238,249 +291,397 @@ def test_origin(self): self.assertEqual(self.settings.allKeys(), []) self.assertEqual(self.globalsettings.allKeys(), []) - self.addToDefaults('testqgissettings/global/setting', 'qgis') - self.settings.setValue('testqgissettings/local/setting', 'rocks') - - self.assertEqual(self.settings.origin('testqgissettings/global/setting'), Qgis.SettingsOrigin.Global) - self.assertEqual(self.settings.origin('testqgissettings/local/setting'), Qgis.SettingsOrigin.Local) - self.assertEqual(self.settings.origin('undefined-key'), Qgis.SettingsOrigin.Any) - - self.settings.setValue('testqgissettings/global/setting', 'rocks') - self.assertEqual(self.settings.origin('testqgissettings/global/setting'), Qgis.SettingsOrigin.Global) + self.addToDefaults("testqgissettings/global/setting", "qgis") + self.settings.setValue("testqgissettings/local/setting", "rocks") + + self.assertEqual( + self.settings.origin("testqgissettings/global/setting"), + Qgis.SettingsOrigin.Global, + ) + self.assertEqual( + self.settings.origin("testqgissettings/local/setting"), + Qgis.SettingsOrigin.Local, + ) + self.assertEqual(self.settings.origin("undefined-key"), Qgis.SettingsOrigin.Any) + + self.settings.setValue("testqgissettings/global/setting", "rocks") + self.assertEqual( + self.settings.origin("testqgissettings/global/setting"), + Qgis.SettingsOrigin.Global, + ) def test_group_section(self): # Test group by using Section - self.settings.beginGroup('firstgroup', section=QgsSettings.Section.Core) - self.assertEqual(self.settings.group(), 'core/firstgroup') + self.settings.beginGroup("firstgroup", section=QgsSettings.Section.Core) + self.assertEqual(self.settings.group(), "core/firstgroup") self.assertEqual([], self.settings.childGroups()) - self.settings.setValue('key', 'value') - self.settings.setValue('key2/subkey1', 'subvalue1') - self.settings.setValue('key2/subkey2', 'subvalue2') - self.settings.setValue('key3', 'value3') - - self.assertEqual(['key', 'key2/subkey1', 'key2/subkey2', 'key3'], self.settings.allKeys()) - self.assertEqual(['key', 'key3'], self.settings.childKeys()) - self.assertEqual(['key2'], self.settings.childGroups()) + self.settings.setValue("key", "value") + self.settings.setValue("key2/subkey1", "subvalue1") + self.settings.setValue("key2/subkey2", "subvalue2") + self.settings.setValue("key3", "value3") + + self.assertEqual( + ["key", "key2/subkey1", "key2/subkey2", "key3"], self.settings.allKeys() + ) + self.assertEqual(["key", "key3"], self.settings.childKeys()) + self.assertEqual(["key2"], self.settings.childGroups()) self.settings.endGroup() - self.assertEqual(self.settings.group(), '') + self.assertEqual(self.settings.group(), "") # Set value by writing the group manually - self.settings.setValue('firstgroup/key4', 'value4', section=QgsSettings.Section.Core) + self.settings.setValue( + "firstgroup/key4", "value4", section=QgsSettings.Section.Core + ) # Checking the value that have been set - self.assertEqual(self.settings.value('firstgroup/key', section=QgsSettings.Section.Core), 'value') - self.assertEqual(self.settings.value('firstgroup/key2/subkey1', section=QgsSettings.Section.Core), 'subvalue1') - self.assertEqual(self.settings.value('firstgroup/key2/subkey2', section=QgsSettings.Section.Core), 'subvalue2') - self.assertEqual(self.settings.value('firstgroup/key3', section=QgsSettings.Section.Core), 'value3') - self.assertEqual(self.settings.value('firstgroup/key4', section=QgsSettings.Section.Core), 'value4') + self.assertEqual( + self.settings.value("firstgroup/key", section=QgsSettings.Section.Core), + "value", + ) + self.assertEqual( + self.settings.value( + "firstgroup/key2/subkey1", section=QgsSettings.Section.Core + ), + "subvalue1", + ) + self.assertEqual( + self.settings.value( + "firstgroup/key2/subkey2", section=QgsSettings.Section.Core + ), + "subvalue2", + ) + self.assertEqual( + self.settings.value("firstgroup/key3", section=QgsSettings.Section.Core), + "value3", + ) + self.assertEqual( + self.settings.value("firstgroup/key4", section=QgsSettings.Section.Core), + "value4", + ) # Clean up firstgroup - self.settings.remove('firstgroup', section=QgsSettings.Section.Core) + self.settings.remove("firstgroup", section=QgsSettings.Section.Core) def test_array(self): self.assertEqual(self.settings.allKeys(), []) - self.addArrayToDefaults('testqgissettings', 'key', ['qgisrocks1', 'qgisrocks2', 'qgisrocks3']) - self.assertEqual(self.settings.allKeys(), ['testqgissettings/1/key', 'testqgissettings/2/key', 'testqgissettings/3/key', 'testqgissettings/size']) - self.assertEqual(self.globalsettings.allKeys(), ['testqgissettings/1/key', 'testqgissettings/2/key', 'testqgissettings/3/key', 'testqgissettings/size']) - - self.assertEqual(3, self.globalsettings.beginReadArray('testqgissettings')) + self.addArrayToDefaults( + "testqgissettings", "key", ["qgisrocks1", "qgisrocks2", "qgisrocks3"] + ) + self.assertEqual( + self.settings.allKeys(), + [ + "testqgissettings/1/key", + "testqgissettings/2/key", + "testqgissettings/3/key", + "testqgissettings/size", + ], + ) + self.assertEqual( + self.globalsettings.allKeys(), + [ + "testqgissettings/1/key", + "testqgissettings/2/key", + "testqgissettings/3/key", + "testqgissettings/size", + ], + ) + + self.assertEqual(3, self.globalsettings.beginReadArray("testqgissettings")) self.globalsettings.endArray() - self.assertEqual(3, self.settings.beginReadArray('testqgissettings')) + self.assertEqual(3, self.settings.beginReadArray("testqgissettings")) values = [] for i in range(3): self.settings.setArrayIndex(i) values.append(self.settings.value("key")) - self.assertEqual(values, ['qgisrocks1', 'qgisrocks2', 'qgisrocks3']) + self.assertEqual(values, ["qgisrocks1", "qgisrocks2", "qgisrocks3"]) def test_array_overrides(self): """Test if an array completely shadows the global one""" self.assertEqual(self.settings.allKeys(), []) - self.addArrayToDefaults('testqgissettings', 'key', ['qgisrocks1', 'qgisrocks2', 'qgisrocks3']) - self.assertEqual(self.settings.allKeys(), ['testqgissettings/1/key', 'testqgissettings/2/key', 'testqgissettings/3/key', 'testqgissettings/size']) - self.assertEqual(self.globalsettings.allKeys(), ['testqgissettings/1/key', 'testqgissettings/2/key', 'testqgissettings/3/key', 'testqgissettings/size']) - - self.assertEqual(3, self.globalsettings.beginReadArray('testqgissettings')) + self.addArrayToDefaults( + "testqgissettings", "key", ["qgisrocks1", "qgisrocks2", "qgisrocks3"] + ) + self.assertEqual( + self.settings.allKeys(), + [ + "testqgissettings/1/key", + "testqgissettings/2/key", + "testqgissettings/3/key", + "testqgissettings/size", + ], + ) + self.assertEqual( + self.globalsettings.allKeys(), + [ + "testqgissettings/1/key", + "testqgissettings/2/key", + "testqgissettings/3/key", + "testqgissettings/size", + ], + ) + + self.assertEqual(3, self.globalsettings.beginReadArray("testqgissettings")) self.globalsettings.endArray() - self.assertEqual(3, self.settings.beginReadArray('testqgissettings')) + self.assertEqual(3, self.settings.beginReadArray("testqgissettings")) # Now override! - self.settings.beginWriteArray('testqgissettings') + self.settings.beginWriteArray("testqgissettings") self.settings.setArrayIndex(0) - self.settings.setValue('key', 'myqgisrocksmore1') + self.settings.setValue("key", "myqgisrocksmore1") self.settings.setArrayIndex(1) - self.settings.setValue('key', 'myqgisrocksmore2') + self.settings.setValue("key", "myqgisrocksmore2") self.settings.endArray() # Check it! - self.assertEqual(2, self.settings.beginReadArray('testqgissettings')) + self.assertEqual(2, self.settings.beginReadArray("testqgissettings")) values = [] for i in range(2): self.settings.setArrayIndex(i) values.append(self.settings.value("key")) - self.assertEqual(values, ['myqgisrocksmore1', 'myqgisrocksmore2']) + self.assertEqual(values, ["myqgisrocksmore1", "myqgisrocksmore2"]) def test_section_getters_setters(self): self.assertEqual(self.settings.allKeys(), []) - self.settings.setValue('key1', 'core1', section=QgsSettings.Section.Core) - self.settings.setValue('key2', 'core2', section=QgsSettings.Section.Core) + self.settings.setValue("key1", "core1", section=QgsSettings.Section.Core) + self.settings.setValue("key2", "core2", section=QgsSettings.Section.Core) - self.settings.setValue('key1', 'server1', section=QgsSettings.Section.Server) - self.settings.setValue('key2', 'server2', section=QgsSettings.Section.Server) + self.settings.setValue("key1", "server1", section=QgsSettings.Section.Server) + self.settings.setValue("key2", "server2", section=QgsSettings.Section.Server) - self.settings.setValue('key1', 'gui1', section=QgsSettings.Section.Gui) - self.settings.setValue('key2', 'gui2', QgsSettings.Section.Gui) + self.settings.setValue("key1", "gui1", section=QgsSettings.Section.Gui) + self.settings.setValue("key2", "gui2", QgsSettings.Section.Gui) - self.settings.setValue('key1', 'plugins1', section=QgsSettings.Section.Plugins) - self.settings.setValue('key2', 'plugins2', section=QgsSettings.Section.Plugins) + self.settings.setValue("key1", "plugins1", section=QgsSettings.Section.Plugins) + self.settings.setValue("key2", "plugins2", section=QgsSettings.Section.Plugins) - self.settings.setValue('key1', 'misc1', section=QgsSettings.Section.Misc) - self.settings.setValue('key2', 'misc2', section=QgsSettings.Section.Misc) + self.settings.setValue("key1", "misc1", section=QgsSettings.Section.Misc) + self.settings.setValue("key2", "misc2", section=QgsSettings.Section.Misc) - self.settings.setValue('key1', 'auth1', section=QgsSettings.Section.Auth) - self.settings.setValue('key2', 'auth2', section=QgsSettings.Section.Auth) + self.settings.setValue("key1", "auth1", section=QgsSettings.Section.Auth) + self.settings.setValue("key2", "auth2", section=QgsSettings.Section.Auth) - self.settings.setValue('key1', 'app1', section=QgsSettings.Section.App) - self.settings.setValue('key2', 'app2', section=QgsSettings.Section.App) + self.settings.setValue("key1", "app1", section=QgsSettings.Section.App) + self.settings.setValue("key2", "app2", section=QgsSettings.Section.App) - self.settings.setValue('key1', 'provider1', section=QgsSettings.Section.Providers) - self.settings.setValue('key2', 'provider2', section=QgsSettings.Section.Providers) + self.settings.setValue( + "key1", "provider1", section=QgsSettings.Section.Providers + ) + self.settings.setValue( + "key2", "provider2", section=QgsSettings.Section.Providers + ) # This is an overwrite of previous setting and it is intentional - self.settings.setValue('key1', 'auth1', section=QgsSettings.Section.Auth) - self.settings.setValue('key2', 'auth2', section=QgsSettings.Section.Auth) + self.settings.setValue("key1", "auth1", section=QgsSettings.Section.Auth) + self.settings.setValue("key2", "auth2", section=QgsSettings.Section.Auth) # Test that the values are namespaced - self.assertEqual(self.settings.value('core/key1'), 'core1') - self.assertEqual(self.settings.value('core/key2'), 'core2') + self.assertEqual(self.settings.value("core/key1"), "core1") + self.assertEqual(self.settings.value("core/key2"), "core2") - self.assertEqual(self.settings.value('server/key1'), 'server1') - self.assertEqual(self.settings.value('server/key2'), 'server2') + self.assertEqual(self.settings.value("server/key1"), "server1") + self.assertEqual(self.settings.value("server/key2"), "server2") - self.assertEqual(self.settings.value('gui/key1'), 'gui1') - self.assertEqual(self.settings.value('gui/key2'), 'gui2') + self.assertEqual(self.settings.value("gui/key1"), "gui1") + self.assertEqual(self.settings.value("gui/key2"), "gui2") - self.assertEqual(self.settings.value('plugins/key1'), 'plugins1') - self.assertEqual(self.settings.value('plugins/key2'), 'plugins2') + self.assertEqual(self.settings.value("plugins/key1"), "plugins1") + self.assertEqual(self.settings.value("plugins/key2"), "plugins2") - self.assertEqual(self.settings.value('misc/key1'), 'misc1') - self.assertEqual(self.settings.value('misc/key2'), 'misc2') + self.assertEqual(self.settings.value("misc/key1"), "misc1") + self.assertEqual(self.settings.value("misc/key2"), "misc2") # Test getters - self.assertEqual(self.settings.value('key1', None, section=QgsSettings.Section.Core), 'core1') - self.assertEqual(self.settings.value('key2', None, section=QgsSettings.Section.Core), 'core2') - - self.assertEqual(self.settings.value('key1', None, section=QgsSettings.Section.Server), 'server1') - self.assertEqual(self.settings.value('key2', None, section=QgsSettings.Section.Server), 'server2') - - self.assertEqual(self.settings.value('key1', None, section=QgsSettings.Section.Gui), 'gui1') - self.assertEqual(self.settings.value('key2', None, section=QgsSettings.Section.Gui), 'gui2') - - self.assertEqual(self.settings.value('key1', None, section=QgsSettings.Section.Plugins), 'plugins1') - self.assertEqual(self.settings.value('key2', None, section=QgsSettings.Section.Plugins), 'plugins2') - - self.assertEqual(self.settings.value('key1', None, section=QgsSettings.Section.Misc), 'misc1') - self.assertEqual(self.settings.value('key2', None, section=QgsSettings.Section.Misc), 'misc2') - - self.assertEqual(self.settings.value('key1', None, section=QgsSettings.Section.Auth), 'auth1') - self.assertEqual(self.settings.value('key2', None, section=QgsSettings.Section.Auth), 'auth2') - - self.assertEqual(self.settings.value('key1', None, section=QgsSettings.Section.App), 'app1') - self.assertEqual(self.settings.value('key2', None, section=QgsSettings.Section.App), 'app2') - - self.assertEqual(self.settings.value('key1', None, section=QgsSettings.Section.Providers), 'provider1') - self.assertEqual(self.settings.value('key2', None, section=QgsSettings.Section.Providers), 'provider2') + self.assertEqual( + self.settings.value("key1", None, section=QgsSettings.Section.Core), "core1" + ) + self.assertEqual( + self.settings.value("key2", None, section=QgsSettings.Section.Core), "core2" + ) + + self.assertEqual( + self.settings.value("key1", None, section=QgsSettings.Section.Server), + "server1", + ) + self.assertEqual( + self.settings.value("key2", None, section=QgsSettings.Section.Server), + "server2", + ) + + self.assertEqual( + self.settings.value("key1", None, section=QgsSettings.Section.Gui), "gui1" + ) + self.assertEqual( + self.settings.value("key2", None, section=QgsSettings.Section.Gui), "gui2" + ) + + self.assertEqual( + self.settings.value("key1", None, section=QgsSettings.Section.Plugins), + "plugins1", + ) + self.assertEqual( + self.settings.value("key2", None, section=QgsSettings.Section.Plugins), + "plugins2", + ) + + self.assertEqual( + self.settings.value("key1", None, section=QgsSettings.Section.Misc), "misc1" + ) + self.assertEqual( + self.settings.value("key2", None, section=QgsSettings.Section.Misc), "misc2" + ) + + self.assertEqual( + self.settings.value("key1", None, section=QgsSettings.Section.Auth), "auth1" + ) + self.assertEqual( + self.settings.value("key2", None, section=QgsSettings.Section.Auth), "auth2" + ) + + self.assertEqual( + self.settings.value("key1", None, section=QgsSettings.Section.App), "app1" + ) + self.assertEqual( + self.settings.value("key2", None, section=QgsSettings.Section.App), "app2" + ) + + self.assertEqual( + self.settings.value("key1", None, section=QgsSettings.Section.Providers), + "provider1", + ) + self.assertEqual( + self.settings.value("key2", None, section=QgsSettings.Section.Providers), + "provider2", + ) # Test default values on Section getter - self.assertEqual(self.settings.value('key_not_exist', 'misc_not_exist', section=QgsSettings.Section.Misc), 'misc_not_exist') + self.assertEqual( + self.settings.value( + "key_not_exist", "misc_not_exist", section=QgsSettings.Section.Misc + ), + "misc_not_exist", + ) def test_contains(self): self.assertEqual(self.settings.allKeys(), []) - self.addToDefaults('testqgissettings/name', 'qgisrocks1') - self.addToDefaults('testqgissettings/name2', 'qgisrocks2') + self.addToDefaults("testqgissettings/name", "qgisrocks1") + self.addToDefaults("testqgissettings/name2", "qgisrocks2") - self.assertTrue(self.settings.contains('testqgissettings/name')) - self.assertTrue(self.settings.contains('testqgissettings/name2')) + self.assertTrue(self.settings.contains("testqgissettings/name")) + self.assertTrue(self.settings.contains("testqgissettings/name2")) - self.settings.setValue('testqgissettings/name3', 'qgisrocks3') - self.assertTrue(self.settings.contains('testqgissettings/name3')) + self.settings.setValue("testqgissettings/name3", "qgisrocks3") + self.assertTrue(self.settings.contains("testqgissettings/name3")) def test_remove(self): - self.settings.setValue('testQgisSettings/temp', True) - self.assertEqual(self.settings.value('testQgisSettings/temp'), True) - self.settings.remove('testQgisSettings/temp') - self.assertEqual(self.settings.value('testqQgisSettings/temp'), None) + self.settings.setValue("testQgisSettings/temp", True) + self.assertEqual(self.settings.value("testQgisSettings/temp"), True) + self.settings.remove("testQgisSettings/temp") + self.assertEqual(self.settings.value("testqQgisSettings/temp"), None) # Test remove by using Section - self.settings.setValue('testQgisSettings/tempSection', True, section=QgsSettings.Section.Core) - self.assertEqual(self.settings.value('testQgisSettings/tempSection', section=QgsSettings.Section.Core), True) - self.settings.remove('testQgisSettings/temp', section=QgsSettings.Section.Core) - self.assertEqual(self.settings.value('testqQgisSettings/temp', section=QgsSettings.Section.Core), None) + self.settings.setValue( + "testQgisSettings/tempSection", True, section=QgsSettings.Section.Core + ) + self.assertEqual( + self.settings.value( + "testQgisSettings/tempSection", section=QgsSettings.Section.Core + ), + True, + ) + self.settings.remove("testQgisSettings/temp", section=QgsSettings.Section.Core) + self.assertEqual( + self.settings.value( + "testqQgisSettings/temp", section=QgsSettings.Section.Core + ), + None, + ) def test_enumValue(self): - self.settings.setValue('enum', 'Layer') - self.assertEqual(self.settings.enumValue('enum', Qgis.MapToolUnit.Pixels), Qgis.MapToolUnit.Layer) - self.settings.setValue('enum', 'dummy_setting') - self.assertEqual(self.settings.enumValue('enum', Qgis.MapToolUnit.Pixels), Qgis.MapToolUnit.Pixels) - self.assertEqual(type(self.settings.enumValue('enum', Qgis.MapToolUnit.Pixels)), QgsTolerance.UnitType) + self.settings.setValue("enum", "Layer") + self.assertEqual( + self.settings.enumValue("enum", Qgis.MapToolUnit.Pixels), + Qgis.MapToolUnit.Layer, + ) + self.settings.setValue("enum", "dummy_setting") + self.assertEqual( + self.settings.enumValue("enum", Qgis.MapToolUnit.Pixels), + Qgis.MapToolUnit.Pixels, + ) + self.assertEqual( + type(self.settings.enumValue("enum", Qgis.MapToolUnit.Pixels)), + QgsTolerance.UnitType, + ) def test_setEnumValue(self): - self.settings.setValue('enum', 'Layer') - self.assertEqual(self.settings.enumValue('enum', Qgis.MapToolUnit.Pixels), Qgis.MapToolUnit.Layer) - self.settings.setEnumValue('enum', Qgis.MapToolUnit.Pixels) - self.assertEqual(self.settings.enumValue('enum', Qgis.MapToolUnit.Pixels), Qgis.MapToolUnit.Pixels) + self.settings.setValue("enum", "Layer") + self.assertEqual( + self.settings.enumValue("enum", Qgis.MapToolUnit.Pixels), + Qgis.MapToolUnit.Layer, + ) + self.settings.setEnumValue("enum", Qgis.MapToolUnit.Pixels) + self.assertEqual( + self.settings.enumValue("enum", Qgis.MapToolUnit.Pixels), + Qgis.MapToolUnit.Pixels, + ) def test_flagValue(self): - pointAndLine = Qgis.LayerFilters(Qgis.LayerFilter.PointLayer | Qgis.LayerFilter.LineLayer) - pointAndPolygon = Qgis.LayerFilters(Qgis.LayerFilter.PointLayer | Qgis.LayerFilter.PolygonLayer) - - self.settings.setValue('flag', 'PointLayer|PolygonLayer') - self.assertEqual(self.settings.flagValue('flag', pointAndLine), pointAndPolygon) - self.settings.setValue('flag', 'dummy_setting') - self.assertEqual(self.settings.flagValue('flag', pointAndLine), pointAndLine) - self.assertEqual(type(self.settings.flagValue('enum', pointAndLine)), Qgis.LayerFilters) + pointAndLine = Qgis.LayerFilters( + Qgis.LayerFilter.PointLayer | Qgis.LayerFilter.LineLayer + ) + pointAndPolygon = Qgis.LayerFilters( + Qgis.LayerFilter.PointLayer | Qgis.LayerFilter.PolygonLayer + ) + + self.settings.setValue("flag", "PointLayer|PolygonLayer") + self.assertEqual(self.settings.flagValue("flag", pointAndLine), pointAndPolygon) + self.settings.setValue("flag", "dummy_setting") + self.assertEqual(self.settings.flagValue("flag", pointAndLine), pointAndLine) + self.assertEqual( + type(self.settings.flagValue("enum", pointAndLine)), Qgis.LayerFilters + ) def test_overwriteDefaultValues(self): """Test that unchanged values are not stored""" - self.globalsettings.setValue('a_value_with_default', 'a value') - self.globalsettings.setValue('an_invalid_value', NULL) + self.globalsettings.setValue("a_value_with_default", "a value") + self.globalsettings.setValue("an_invalid_value", NULL) - self.assertEqual(self.settings.value('a_value_with_default'), 'a value') - self.assertEqual(self.settings.value('an_invalid_value'), NULL) + self.assertEqual(self.settings.value("a_value_with_default"), "a value") + self.assertEqual(self.settings.value("an_invalid_value"), NULL) # Now, set them with the same current value - self.settings.setValue('a_value_with_default', 'a value') - self.settings.setValue('an_invalid_value', NULL) + self.settings.setValue("a_value_with_default", "a value") + self.settings.setValue("an_invalid_value", NULL) # Check pure_settings = QSettings(self.settings.fileName(), QSettings.Format.IniFormat) - self.assertNotIn('a_value_with_default', pure_settings.allKeys()) - self.assertNotIn('an_invalid_value', pure_settings.allKeys()) + self.assertNotIn("a_value_with_default", pure_settings.allKeys()) + self.assertNotIn("an_invalid_value", pure_settings.allKeys()) # Set a changed value - self.settings.setValue('a_value_with_default', 'a new value') - self.settings.setValue('an_invalid_value', 'valid value') + self.settings.setValue("a_value_with_default", "a new value") + self.settings.setValue("an_invalid_value", "valid value") # Check - self.assertIn('a_value_with_default', pure_settings.allKeys()) - self.assertIn('an_invalid_value', pure_settings.allKeys()) + self.assertIn("a_value_with_default", pure_settings.allKeys()) + self.assertIn("an_invalid_value", pure_settings.allKeys()) - self.assertEqual(self.settings.value('a_value_with_default'), 'a new value') - self.assertEqual(self.settings.value('an_invalid_value'), 'valid value') + self.assertEqual(self.settings.value("a_value_with_default"), "a new value") + self.assertEqual(self.settings.value("an_invalid_value"), "valid value") # Re-set to original values - self.settings.setValue('a_value_with_default', 'a value') - self.settings.setValue('an_invalid_value', NULL) + self.settings.setValue("a_value_with_default", "a value") + self.settings.setValue("an_invalid_value", NULL) - self.assertEqual(self.settings.value('a_value_with_default'), 'a value') - self.assertEqual(self.settings.value('an_invalid_value'), NULL) + self.assertEqual(self.settings.value("a_value_with_default"), "a value") + self.assertEqual(self.settings.value("an_invalid_value"), NULL) # Check if they are gone pure_settings = QSettings(self.settings.fileName(), QSettings.Format.IniFormat) - self.assertIn('a_value_with_default', pure_settings.allKeys()) - self.assertIn('an_invalid_value', pure_settings.allKeys()) + self.assertIn("a_value_with_default", pure_settings.allKeys()) + self.assertIn("an_invalid_value", pure_settings.allKeys()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssettingseditorregistry.py b/tests/src/python/test_qgssettingseditorregistry.py index 390b878b7b8e..ec2b3b69f94a 100644 --- a/tests/src/python/test_qgssettingseditorregistry.py +++ b/tests/src/python/test_qgssettingseditorregistry.py @@ -17,7 +17,11 @@ QgsSettingsEntryEnumFlag, QgsSettingsEntryInteger, ) -from qgis.gui import QgsGui, QgsSettingsEditorWidgetWrapper, QgsSettingsEnumEditorWidgetWrapper +from qgis.gui import ( + QgsGui, + QgsSettingsEditorWidgetWrapper, + QgsSettingsEnumEditorWidgetWrapper, +) import unittest from qgis.testing import start_app, QgisTestCase @@ -30,7 +34,9 @@ class PyQgsSettingsRegistry(QgisTestCase): def setUp(self): - self.settings_node = QgsSettingsTree.createPluginTreeNode(pluginName=PLUGIN_NAME) + self.settings_node = QgsSettingsTree.createPluginTreeNode( + pluginName=PLUGIN_NAME + ) def tearDown(self): QgsSettingsTree.unregisterPluginTreeNode(PLUGIN_NAME) @@ -51,9 +57,13 @@ def test_settings_registry(self): self.assertEqual(int_setting.value(), 6) def test_settings_registry_custom_enumflag_py(self): - priority_setting = QgsSettingsEntryEnumFlag("priority", self.settings_node, QgsLocatorFilter.Priority.High) + priority_setting = QgsSettingsEntryEnumFlag( + "priority", self.settings_node, QgsLocatorFilter.Priority.High + ) registry = QgsGui.settingsEditorWidgetRegistry() - registry.addWrapperForSetting(QgsSettingsEnumEditorWidgetWrapper(), priority_setting) + registry.addWrapperForSetting( + QgsSettingsEnumEditorWidgetWrapper(), priority_setting + ) editor = registry.createEditor(priority_setting, []) self.assertIsInstance(editor, QComboBox) @@ -71,5 +81,5 @@ def test_settings_registry_custom_enumflag_py(self): self.assertEqual(QgsSettings().value(f"plugins/{PLUGIN_NAME}/priority"), "Low") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssettingsentry.py b/tests/src/python/test_qgssettingsentry.py index fd2392c7b5f9..2c322c357d54 100644 --- a/tests/src/python/test_qgssettingsentry.py +++ b/tests/src/python/test_qgssettingsentry.py @@ -32,9 +32,9 @@ import unittest from qgis.testing import start_app, QgisTestCase -__author__ = 'Damiano Lombardi' -__date__ = '02/04/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' +__author__ = "Damiano Lombardi" +__date__ = "02/04/2021" +__copyright__ = "Copyright 2021, The QGIS Project" start_app() @@ -59,7 +59,9 @@ def test_settings_entry_base(self): defaultValue = 42 description = "Variant value for basic functionality test" - settingsEntryVariant = QgsSettingsEntryVariant(settingsKey, self.pluginName, defaultValue, description) + settingsEntryVariant = QgsSettingsEntryVariant( + settingsKey, self.pluginName, defaultValue, description + ) # Check key self.assertEqual(settingsEntryVariant.key(), settingsKeyComplete) @@ -95,31 +97,39 @@ def test_settings_entry_base(self): def test_settings_plugin_key(self): # be sure that the constructor in PyQGIS only creates keys with plugins prefix - settings_types = [x for x in dir(qgis_core) if x.startswith('QgsSettingsEntry') and not x.endswith('Base') and x != 'QgsSettingsEntryGroup'] + settings_types = [ + x + for x in dir(qgis_core) + if x.startswith("QgsSettingsEntry") + and not x.endswith("Base") + and x != "QgsSettingsEntryGroup" + ] hardcoded_types = { - 'QgsSettingsEntryBool': True, - 'QgsSettingsEntryColor': QColor(), - 'QgsSettingsEntryDouble': 0.0, - 'QgsSettingsEntryEnumFlag': QgsUnitTypes.LayoutUnit.LayoutMeters, - 'QgsSettingsEntryInteger': 1, - 'QgsSettingsEntryString': 'Hello', - 'QgsSettingsEntryStringList': [], - 'QgsSettingsEntryVariant': 1, - 'QgsSettingsEntryVariantMap': {}, + "QgsSettingsEntryBool": True, + "QgsSettingsEntryColor": QColor(), + "QgsSettingsEntryDouble": 0.0, + "QgsSettingsEntryEnumFlag": QgsUnitTypes.LayoutUnit.LayoutMeters, + "QgsSettingsEntryInteger": 1, + "QgsSettingsEntryString": "Hello", + "QgsSettingsEntryStringList": [], + "QgsSettingsEntryVariant": 1, + "QgsSettingsEntryVariantMap": {}, } self.assertEqual(settings_types, list(hardcoded_types.keys())) for setting_type, default_value in hardcoded_types.items(): settings_key = f"settings/key_{setting_type}" settings_key_complete = f"/plugins/{self.pluginName}/{settings_key}" QgsSettings().remove(settings_key_complete) - settings_entry = eval(f'qgis_core.{setting_type}(settings_key, self.pluginName, default_value)') + settings_entry = eval( + f"qgis_core.{setting_type}(settings_key, self.pluginName, default_value)" + ) self.assertEqual(settings_entry.key(), settings_key_complete) def test_with_parent_element(self): root = QgsSettingsTree.createPluginTreeNode(self.pluginName) setting = QgsSettingsEntryInteger("my_setting", root) self.assertEqual(setting.key(), f"/plugins/{self.pluginName}/my_setting") - self.assertEqual(setting.name(), 'my_setting') + self.assertEqual(setting.name(), "my_setting") def test_settings_entry_base_default_value_override(self): settingsKey = "settingsEntryBase/defaultValueOverride/variantValue" @@ -131,7 +141,9 @@ def test_settings_entry_base_default_value_override(self): defaultValue = 42 defaultValueOverride = 123 description = "Variant value for default override functionality test" - settingsEntryVariant = QgsSettingsEntryVariant(settingsKey, self.pluginName, defaultValue, description) + settingsEntryVariant = QgsSettingsEntryVariant( + settingsKey, self.pluginName, defaultValue, description + ) # Normal default value self.assertEqual(settingsEntryVariant.value(), defaultValue) @@ -140,25 +152,45 @@ def test_settings_entry_base_default_value_override(self): self.assertEqual(settingsEntryVariant.value(), defaultValue) # Overridden default value - self.assertEqual(settingsEntryVariant.valueWithDefaultOverride(defaultValueOverride), defaultValueOverride) + self.assertEqual( + settingsEntryVariant.valueWithDefaultOverride(defaultValueOverride), + defaultValueOverride, + ) def test_settings_entry_base_dynamic_key(self): settingsKeyDynamic = "settingsEntryBase/%1/variantValue" dynamicKeyPart1 = "first" dynamicKeyPart2 = "second" - settingsKeyComplete1 = f"/plugins/{self.pluginName}/{settingsKeyDynamic}".replace("%1", dynamicKeyPart1) - settingsKeyComplete2 = f"/plugins/{self.pluginName}/{settingsKeyDynamic}".replace("%1", dynamicKeyPart2) + settingsKeyComplete1 = ( + f"/plugins/{self.pluginName}/{settingsKeyDynamic}".replace( + "%1", dynamicKeyPart1 + ) + ) + settingsKeyComplete2 = ( + f"/plugins/{self.pluginName}/{settingsKeyDynamic}".replace( + "%1", dynamicKeyPart2 + ) + ) # Make sure settings does not exists QgsSettings().remove(settingsKeyComplete1) QgsSettings().remove(settingsKeyComplete2) defaultValue = 42 - settingsEntryVariantDynamic = QgsSettingsEntryVariant(settingsKeyDynamic, self.pluginName, defaultValue, "Variant value for dynamic key functionality test") + settingsEntryVariantDynamic = QgsSettingsEntryVariant( + settingsKeyDynamic, + self.pluginName, + defaultValue, + "Variant value for dynamic key functionality test", + ) # Check key - self.assertEqual(settingsEntryVariantDynamic.key(dynamicKeyPart1), settingsKeyComplete1) - self.assertEqual(settingsEntryVariantDynamic.key(dynamicKeyPart2), settingsKeyComplete2) + self.assertEqual( + settingsEntryVariantDynamic.key(dynamicKeyPart1), settingsKeyComplete1 + ) + self.assertEqual( + settingsEntryVariantDynamic.key(dynamicKeyPart2), settingsKeyComplete2 + ) # Get set values settingsEntryVariantDynamic.setValue(43, dynamicKeyPart1) @@ -172,21 +204,35 @@ def test_settings_entry_base_dynamic_multiple_keys(self): settingsKeyDynamic = "settingsEntryBase/%1/anotherPart_%2/variantValue" dynamicKeyPart1 = "first" dynamicKeyPart2 = "second" - settingsKeyComplete = f"/plugins/{self.pluginName}/{settingsKeyDynamic}".replace("%1", dynamicKeyPart1).replace("%2", dynamicKeyPart2) + settingsKeyComplete = ( + f"/plugins/{self.pluginName}/{settingsKeyDynamic}".replace( + "%1", dynamicKeyPart1 + ).replace("%2", dynamicKeyPart2) + ) # Make sure settings does not exists QgsSettings().remove(settingsKeyComplete) defaultValue = 42 - settingsEntryVariantDynamic = QgsSettingsEntryVariant(settingsKeyDynamic, self.pluginName, defaultValue, "Variant value for dynamic multiple keys functionality test") + settingsEntryVariantDynamic = QgsSettingsEntryVariant( + settingsKeyDynamic, + self.pluginName, + defaultValue, + "Variant value for dynamic multiple keys functionality test", + ) # Check key - self.assertEqual(settingsEntryVariantDynamic.key([dynamicKeyPart1, dynamicKeyPart2]), settingsKeyComplete) + self.assertEqual( + settingsEntryVariantDynamic.key([dynamicKeyPart1, dynamicKeyPart2]), + settingsKeyComplete, + ) # Get set values settingsEntryVariantDynamic.setValue(43, [dynamicKeyPart1, dynamicKeyPart2]) self.assertEqual(QgsSettings().value(settingsKeyComplete, defaultValue), 43) - self.assertEqual(settingsEntryVariantDynamic.value([dynamicKeyPart1, dynamicKeyPart2]), 43) + self.assertEqual( + settingsEntryVariantDynamic.value([dynamicKeyPart1, dynamicKeyPart2]), 43 + ) def test_settings_entry_variant(self): settingsKey = "settingsEntryVariant/variantValue" @@ -197,7 +243,9 @@ def test_settings_entry_variant(self): defaultValue = 42 description = "Variant value functionality test" - settingsEntryVariant = QgsSettingsEntryVariant(settingsKey, self.pluginName, defaultValue, description) + settingsEntryVariant = QgsSettingsEntryVariant( + settingsKey, self.pluginName, defaultValue, description + ) # Set/Get value # as settings still does not exists return default value @@ -219,7 +267,9 @@ def test_settings_entry_string(self): defaultValue = "abc" description = "String value functionality test" - settingsEntryString = QgsSettingsEntryString(settingsKey, self.pluginName, defaultValue, description) + settingsEntryString = QgsSettingsEntryString( + settingsKey, self.pluginName, defaultValue, description + ) # Set/Get value # as settings still does not exists return default value @@ -241,18 +291,24 @@ def test_settings_entry_stringlist(self): defaultValue = ["abc", "def"] description = "String list value functionality test" - settingsEntryStringList = QgsSettingsEntryStringList(settingsKey, self.pluginName, defaultValue, description) + settingsEntryStringList = QgsSettingsEntryStringList( + settingsKey, self.pluginName, defaultValue, description + ) # Set/Get value # as settings still does not exists return default value self.assertEqual(settingsEntryStringList.valueAsVariant(), defaultValue) settingsEntryStringList.setValue(["uvw", "xyz"]) # Verify setValue using QgsSettings - self.assertEqual(QgsSettings().value(settingsKeyComplete, defaultValue), ["uvw", "xyz"]) + self.assertEqual( + QgsSettings().value(settingsKeyComplete, defaultValue), ["uvw", "xyz"] + ) self.assertEqual(settingsEntryStringList.valueAsVariant(), ["uvw", "xyz"]) # Settings type - self.assertEqual(settingsEntryStringList.settingsType(), Qgis.SettingsType.StringList) + self.assertEqual( + settingsEntryStringList.settingsType(), Qgis.SettingsType.StringList + ) def test_settings_entry_variantmap(self): settingsKey = "settingsEntryVariantMap/varriantMapValue" @@ -262,15 +318,23 @@ def test_settings_entry_variantmap(self): QgsSettings().remove(settingsKeyComplete) defaultValue = {"key0": "value0"} - settingsEntryVariantMap = QgsSettingsEntryVariantMap(settingsKey, self.pluginName, defaultValue) + settingsEntryVariantMap = QgsSettingsEntryVariantMap( + settingsKey, self.pluginName, defaultValue + ) self.assertEqual(settingsEntryVariantMap.value(), defaultValue) - newValue = {"number": 123, "text": "hi there", "color": QColor(Qt.GlobalColor.yellow)} + newValue = { + "number": 123, + "text": "hi there", + "color": QColor(Qt.GlobalColor.yellow), + } settingsEntryVariantMap.setValue(newValue) self.assertEqual(newValue, settingsEntryVariantMap.value()) # Settings type - self.assertEqual(settingsEntryVariantMap.settingsType(), Qgis.SettingsType.VariantMap) + self.assertEqual( + settingsEntryVariantMap.settingsType(), Qgis.SettingsType.VariantMap + ) def test_settings_entry_bool(self): settingsKey = "settingsEntryBool/boolValue" @@ -281,7 +345,9 @@ def test_settings_entry_bool(self): defaultValue = False description = "Bool value functionality test" - settingsEntryBool = QgsSettingsEntryBool(settingsKey, self.pluginName, defaultValue, description) + settingsEntryBool = QgsSettingsEntryBool( + settingsKey, self.pluginName, defaultValue, description + ) # Set/Get value # as settings still does not exists return default value @@ -303,7 +369,9 @@ def test_settings_entry_integer(self): defaultValue = 42 description = "Integer value functionality test" - settingsEntryInteger = QgsSettingsEntryInteger(settingsKey, self.pluginName, defaultValue, description) + settingsEntryInteger = QgsSettingsEntryInteger( + settingsKey, self.pluginName, defaultValue, description + ) # Set/Get value # as settings still does not exists return default value @@ -331,7 +399,9 @@ def test_settings_entry_double(self): defaultValue = 3.14 description = "Double value functionality test" - settingsEntryDouble = QgsSettingsEntryDouble(settingsKey, self.pluginName, defaultValue, description) + settingsEntryDouble = QgsSettingsEntryDouble( + settingsKey, self.pluginName, defaultValue, description + ) # Set/Get value # as settings still does not exists return default value @@ -344,7 +414,9 @@ def test_settings_entry_double(self): # Set/Get negative value settingsEntryDouble.setValue(-273.15) # Verify setValue using QgsSettings - self.assertEqual(QgsSettings().value(settingsKeyComplete, defaultValue), -273.15) + self.assertEqual( + QgsSettings().value(settingsKeyComplete, defaultValue), -273.15 + ) self.assertEqual(settingsEntryDouble.valueAsVariant(), -273.15) # Settings type @@ -358,7 +430,14 @@ def test_settings_entry_color(self): QgsSettings().remove(settingsKeyComplete) defaultValue = QColor(Qt.GlobalColor.darkGreen) - settingsEntry = QgsSettingsEntryColor(settingsKey, self.pluginName, defaultValue, None, Qgis.SettingsOptions(), False) + settingsEntry = QgsSettingsEntryColor( + settingsKey, + self.pluginName, + defaultValue, + None, + Qgis.SettingsOptions(), + False, + ) # Check default value self.assertEqual(settingsEntry.defaultValue(), defaultValue) @@ -376,19 +455,27 @@ def test_settings_entry_enum(self): defaultValue = QgsUnitTypes.LayoutUnit.LayoutMeters description = "Enum value functionality test" - settingsEntryEnum = QgsSettingsEntryEnumFlag(settingsKey, self.pluginName, defaultValue, description) + settingsEntryEnum = QgsSettingsEntryEnumFlag( + settingsKey, self.pluginName, defaultValue, description + ) # Check default value - self.assertEqual(settingsEntryEnum.defaultValue(), QgsUnitTypes.LayoutUnit.LayoutMeters) + self.assertEqual( + settingsEntryEnum.defaultValue(), QgsUnitTypes.LayoutUnit.LayoutMeters + ) # Check set value success = settingsEntryEnum.setValue(QgsUnitTypes.LayoutUnit.LayoutFeet) self.assertEqual(success, True) - qgsSettingsValue = QgsSettings().enumValue(settingsKeyComplete, QgsUnitTypes.LayoutUnit.LayoutMeters) + qgsSettingsValue = QgsSettings().enumValue( + settingsKeyComplete, QgsUnitTypes.LayoutUnit.LayoutMeters + ) self.assertEqual(qgsSettingsValue, QgsUnitTypes.LayoutUnit.LayoutFeet) # Check get value - QgsSettings().setEnumValue(settingsKeyComplete, QgsUnitTypes.LayoutUnit.LayoutPicas) + QgsSettings().setEnumValue( + settingsKeyComplete, QgsUnitTypes.LayoutUnit.LayoutPicas + ) self.assertEqual(settingsEntryEnum.value(), QgsUnitTypes.LayoutUnit.LayoutPicas) # Check settings type @@ -399,31 +486,50 @@ def test_settings_entry_enum(self): self.assertEqual(success, False) # Current value should not have changed - qgsSettingsValue = QgsSettings().enumValue(settingsKeyComplete, QgsUnitTypes.LayoutUnit.LayoutMeters) + qgsSettingsValue = QgsSettings().enumValue( + settingsKeyComplete, QgsUnitTypes.LayoutUnit.LayoutMeters + ) self.assertEqual(qgsSettingsValue, QgsUnitTypes.LayoutUnit.LayoutPicas) # With save as integer option - settingsEntryEnumAsInteger = QgsSettingsEntryEnumFlag("enum-value-2", self.pluginName, defaultValue, description, Qgis.SettingsOption.SaveEnumFlagAsInt) + settingsEntryEnumAsInteger = QgsSettingsEntryEnumFlag( + "enum-value-2", + self.pluginName, + defaultValue, + description, + Qgis.SettingsOption.SaveEnumFlagAsInt, + ) settingsEntryEnumAsInteger.remove() self.assertEqual(settingsEntryEnumAsInteger.value(), defaultValue) - success = settingsEntryEnumAsInteger.setValue(QgsUnitTypes.LayoutUnit.LayoutFeet) + success = settingsEntryEnumAsInteger.setValue( + QgsUnitTypes.LayoutUnit.LayoutFeet + ) self.assertEqual(success, True) - qgsSettingsValue = QgsSettings().value(f"plugins/{self.pluginName}/enum-value-2", int(QgsUnitTypes.LayoutUnit.LayoutMeters)) + qgsSettingsValue = QgsSettings().value( + f"plugins/{self.pluginName}/enum-value-2", + int(QgsUnitTypes.LayoutUnit.LayoutMeters), + ) self.assertEqual(qgsSettingsValue, int(QgsUnitTypes.LayoutUnit.LayoutFeet)) def test_settings_entry_flag(self): settingsKey = "settingsEntryFlag/flagValue" settingsKeyComplete = f"plugins/{self.pluginName}/{settingsKey}" - pointAndLine = Qgis.LayerFilters(Qgis.LayerFilter.PointLayer | Qgis.LayerFilter.LineLayer) - pointAndPolygon = Qgis.LayerFilters(Qgis.LayerFilter.PointLayer | Qgis.LayerFilter.PolygonLayer) + pointAndLine = Qgis.LayerFilters( + Qgis.LayerFilter.PointLayer | Qgis.LayerFilter.LineLayer + ) + pointAndPolygon = Qgis.LayerFilters( + Qgis.LayerFilter.PointLayer | Qgis.LayerFilter.PolygonLayer + ) hasGeometry = Qgis.LayerFilters(Qgis.LayerFilter.HasGeometry) # Make sure settings does not exists QgsSettings().remove(settingsKeyComplete) description = "Flag value functionality test" - settingsEntryFlag = QgsSettingsEntryEnumFlag(settingsKey, self.pluginName, pointAndLine, description) + settingsEntryFlag = QgsSettingsEntryEnumFlag( + settingsKey, self.pluginName, pointAndLine, description + ) # Check default value self.assertEqual(settingsEntryFlag.defaultValue(), pointAndLine) @@ -435,17 +541,25 @@ def test_settings_entry_flag(self): self.assertEqual(qgsSettingsValue, hasGeometry) # Check get value - QgsSettings().setValue(settingsKeyComplete, 'PointLayer|PolygonLayer') + QgsSettings().setValue(settingsKeyComplete, "PointLayer|PolygonLayer") self.assertEqual(settingsEntryFlag.value(), pointAndPolygon) # Check settings type self.assertEqual(settingsEntryFlag.settingsType(), Qgis.SettingsType.EnumFlag) def test_settings_entry_group(self): - settingsEntryString_1 = QgsSettingsEntryString('my/key/has/levels/my-setting-key-1', self.pluginName) - settingsEntryString_2 = QgsSettingsEntryString('my/key/has/levels/my-setting-key-2', self.pluginName) - settingsEntryString_3 = QgsSettingsEntryString('my-setting-key-3', self.pluginName) - settingsEntryString_4 = QgsSettingsEntryString('my-setting-key-4', self.pluginName) + settingsEntryString_1 = QgsSettingsEntryString( + "my/key/has/levels/my-setting-key-1", self.pluginName + ) + settingsEntryString_2 = QgsSettingsEntryString( + "my/key/has/levels/my-setting-key-2", self.pluginName + ) + settingsEntryString_3 = QgsSettingsEntryString( + "my-setting-key-3", self.pluginName + ) + settingsEntryString_4 = QgsSettingsEntryString( + "my-setting-key-4", self.pluginName + ) group_1 = QgsSettingsEntryGroup([settingsEntryString_1, settingsEntryString_2]) self.assertTrue(group_1.isValid()) @@ -454,16 +568,16 @@ def test_settings_entry_group(self): with self.assertRaises(ValueError): QgsSettingsEntryGroup([settingsEntryString_1, settingsEntryString_3]) - settingsEntryString_1.setValue('value-1') - settingsEntryString_2.setValue('value-2') + settingsEntryString_1.setValue("value-1") + settingsEntryString_2.setValue("value-2") self.assertTrue(settingsEntryString_1.exists()) self.assertTrue(settingsEntryString_2.exists()) group_1.removeAllSettingsAtBaseKey() self.assertFalse(settingsEntryString_1.exists()) self.assertFalse(settingsEntryString_2.exists()) - settingsEntryString_1.setValue('value-1') - settingsEntryString_2.setValue('value-2') + settingsEntryString_1.setValue("value-1") + settingsEntryString_2.setValue("value-2") self.assertTrue(settingsEntryString_1.exists()) self.assertTrue(settingsEntryString_2.exists()) group_1.removeAllChildrenSettings() @@ -478,20 +592,36 @@ def test_copy_value_from_key(self): settingsEntryOld = QgsSettingsEntryString(settingsOldKey, self.pluginName) settingsEntryOld.setValue("value from old key") self.assertFalse(settingsEntryNew.exists()) - self.assertFalse(settingsEntryNew.copyValueFromKey(f"plugins/{self.pluginName}/a-key-which-does-not-exist")) - self.assertTrue(settingsEntryNew.copyValueFromKey(f"plugins/{self.pluginName}/{settingsOldKey}", [], False)) + self.assertFalse( + settingsEntryNew.copyValueFromKey( + f"plugins/{self.pluginName}/a-key-which-does-not-exist" + ) + ) + self.assertTrue( + settingsEntryNew.copyValueFromKey( + f"plugins/{self.pluginName}/{settingsOldKey}", [], False + ) + ) self.assertTrue(settingsEntryNew.exists()) self.assertEqual(settingsEntryNew.value(), settingsEntryOld.value()) # with dynamic keys + delete settingsNewKeyDynamic = "settingsEntryMigrationNewKeyDynamic/%1/key" - settingsEntryNewDynamic = QgsSettingsEntryString(settingsNewKeyDynamic, self.pluginName) + settingsEntryNewDynamic = QgsSettingsEntryString( + settingsNewKeyDynamic, self.pluginName + ) settingsEntryNewDynamic.remove("key1") settingsOldKeyDynamic = "settingsEntryMigrationOldKey/%1/xxx" - settingsEntryOldDynamic = QgsSettingsEntryString(settingsOldKeyDynamic, self.pluginName) + settingsEntryOldDynamic = QgsSettingsEntryString( + settingsOldKeyDynamic, self.pluginName + ) settingsEntryOldDynamic.setValue("value from old key") self.assertFalse(settingsEntryNewDynamic.exists()) - self.assertTrue(settingsEntryNewDynamic.copyValueFromKey(f"plugins/{self.pluginName}/{settingsOldKey}", ["key1"], True)) + self.assertTrue( + settingsEntryNewDynamic.copyValueFromKey( + f"plugins/{self.pluginName}/{settingsOldKey}", ["key1"], True + ) + ) self.assertTrue(settingsEntryNewDynamic.exists("key1")) self.assertFalse(settingsEntryOldDynamic.exists("key1")) self.assertEqual(settingsEntryNewDynamic.value("key1"), "value from old key") @@ -509,5 +639,5 @@ def test_copy_to_value(self): self.assertEqual(settingsEntryDest.value(), settingsEntryDest.value()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssettingsregistry.py b/tests/src/python/test_qgssettingsregistry.py index c3202e576c9f..9175206f679f 100644 --- a/tests/src/python/test_qgssettingsregistry.py +++ b/tests/src/python/test_qgssettingsregistry.py @@ -17,9 +17,9 @@ import unittest from qgis.testing import start_app, QgisTestCase -__author__ = 'Damiano Lombardi' -__date__ = '18/04/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' +__author__ = "Damiano Lombardi" +__date__ = "18/04/2021" +__copyright__ = "Copyright 2021, The QGIS Project" start_app() @@ -39,13 +39,20 @@ def test_settings_registry(self): settingsRegistry.addSettingsEntry(settingsEntry) # check get settings entry - self.assertEqual(settingsRegistry.settingsEntry(settingsEntry.key(), False), settingsEntry) + self.assertEqual( + settingsRegistry.settingsEntry(settingsEntry.key(), False), settingsEntry + ) # add registry to core registry QgsApplication.settingsRegistryCore().addSubRegistry(settingsRegistry) - self.assertEqual(QgsApplication.settingsRegistryCore().settingsEntry(settingsEntry.key(), True), settingsEntry) + self.assertEqual( + QgsApplication.settingsRegistryCore().settingsEntry( + settingsEntry.key(), True + ), + settingsEntry, + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssettingstreenode.py b/tests/src/python/test_qgssettingstreenode.py index d2907892106d..3c5f8ba2e835 100644 --- a/tests/src/python/test_qgssettingstreenode.py +++ b/tests/src/python/test_qgssettingstreenode.py @@ -23,9 +23,9 @@ import unittest from qgis.testing import start_app, QgisTestCase -__author__ = 'Denis Rouzaud' -__date__ = '19/12/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' +__author__ = "Denis Rouzaud" +__date__ = "19/12/2022" +__copyright__ = "Copyright 2022, The QGIS Project" start_app() @@ -57,7 +57,9 @@ def test_parent(self): l1 = root.createChildNode("test-parent-level-1") self.assertEqual(l1.type(), Qgis.SettingsTreeNodeType.Standard) self.assertEqual(l1.key(), "test-parent-level-1") - self.assertEqual(l1.completeKey(), f"/plugins/{self.pluginName}/test-parent-level-1/") + self.assertEqual( + l1.completeKey(), f"/plugins/{self.pluginName}/test-parent-level-1/" + ) self.assertEqual(l1.parent(), root) self.assertEqual(root.childrenNodes(), [l1]) self.assertEqual(root.childrenSettings(), []) @@ -65,7 +67,10 @@ def test_parent(self): l1a = l1.createChildNode("level-a") self.assertEqual(l1a.type(), Qgis.SettingsTreeNodeType.Standard) self.assertEqual(l1a.key(), "level-a") - self.assertEqual(l1a.completeKey(), f"/plugins/{self.pluginName}/test-parent-level-1/level-a/") + self.assertEqual( + l1a.completeKey(), + f"/plugins/{self.pluginName}/test-parent-level-1/level-a/", + ) self.assertEqual(l1a.parent(), l1) self.assertEqual(l1.childrenNodes(), [l1a]) l1b = l1.createChildNode("level-b") @@ -87,19 +92,31 @@ def test_named_list(self): self.assertEqual(l1.namedNodesCount(), 0) nl = l1.createNamedListNode("my_list") self.assertEqual(nl.key(), "my_list") - self.assertEqual(nl.completeKey(), f"/plugins/{self.pluginName}/level-1/my_list/items/%1/") + self.assertEqual( + nl.completeKey(), f"/plugins/{self.pluginName}/level-1/my_list/items/%1/" + ) self.assertEqual(nl.namedNodesCount(), 1) self.assertEqual(nl.childrenNodes(), []) self.assertEqual(nl.childrenSettings(), []) # nesting lists - nl2 = nl.createNamedListNode("my_nested_list", Qgis.SettingsTreeNodeOption.NamedListSelectedItemSetting) + nl2 = nl.createNamedListNode( + "my_nested_list", Qgis.SettingsTreeNodeOption.NamedListSelectedItemSetting + ) self.assertEqual(nl2.key(), "my_nested_list") - self.assertEqual(nl2.completeKey(), f"/plugins/{self.pluginName}/level-1/my_list/items/%1/my_nested_list/items/%2/") + self.assertEqual( + nl2.completeKey(), + f"/plugins/{self.pluginName}/level-1/my_list/items/%1/my_nested_list/items/%2/", + ) self.assertEqual(nl2.namedNodesCount(), 2) self.assertEqual(nl2.childrenNodes(), []) - self.assertEqual(len(nl2.childrenSettings()), 0) # the setting for the current selection - self.assertEqual(nl2.selectedItemSetting().definitionKey(), f"/plugins/{self.pluginName}/level-1/my_list/items/%1/my_nested_list/selected") + self.assertEqual( + len(nl2.childrenSettings()), 0 + ) # the setting for the current selection + self.assertEqual( + nl2.selectedItemSetting().definitionKey(), + f"/plugins/{self.pluginName}/level-1/my_list/items/%1/my_nested_list/selected", + ) selected_key = f"/plugins/{self.pluginName}/level-1/my_list/items/item1/my_nested_list/selected" self.assertEqual(QgsSettings().value(selected_key), None) nl2.setSelectedItem("xxx", ["item1"]) @@ -107,17 +124,23 @@ def test_named_list(self): # list with settings setting = QgsSettingsEntryString("mysetting-inlist", nl2) - self.assertEqual(setting.definitionKey(), f"/plugins/{self.pluginName}/level-1/my_list/items/%1/my_nested_list/items/%2/mysetting-inlist") - self.assertEqual(setting.key(['item1', 'item2']), f"/plugins/{self.pluginName}/level-1/my_list/items/item1/my_nested_list/items/item2/mysetting-inlist") + self.assertEqual( + setting.definitionKey(), + f"/plugins/{self.pluginName}/level-1/my_list/items/%1/my_nested_list/items/%2/mysetting-inlist", + ) + self.assertEqual( + setting.key(["item1", "item2"]), + f"/plugins/{self.pluginName}/level-1/my_list/items/item1/my_nested_list/items/item2/mysetting-inlist", + ) self.assertEqual(nl2.childrenNodes(), []) self.assertEqual(len(nl2.childrenSettings()), 1) self.assertEqual(nl2.childrenSettings()[0], setting) setting.setValue("xxx", ["item1", "item2"]) - self.assertEqual(QgsSettings().value(setting.key(['item1', 'item2'])), "xxx") + self.assertEqual(QgsSettings().value(setting.key(["item1", "item2"])), "xxx") with self.assertRaises(QgsSettingsException): nl2.deleteItem("item2") nl2.deleteItem("item2", ["item1"]) - self.assertEqual(QgsSettings().value(setting.key(['item1', 'item2'])), None) + self.assertEqual(QgsSettings().value(setting.key(["item1", "item2"])), None) def test_delete_all_items(self): proot = QgsSettingsTree.createPluginTreeNode(self.pluginName) @@ -158,9 +181,14 @@ def test_duplicated_key(self): def test_python_implementation(self): proot = QgsSettingsTree.createPluginTreeNode(self.pluginName) - self.setting = QgsSettingsEntryEnumFlag("python-implemented-setting", proot, QgsUnitTypes.LayoutUnit.LayoutMeters) + self.setting = QgsSettingsEntryEnumFlag( + "python-implemented-setting", proot, QgsUnitTypes.LayoutUnit.LayoutMeters + ) self.assertEqual(type(self.setting), QgsSettingsEntryEnumFlag) - self.assertEqual(type(proot.childSetting("python-implemented-setting")), QgsSettingsEntryEnumFlag) + self.assertEqual( + type(proot.childSetting("python-implemented-setting")), + QgsSettingsEntryEnumFlag, + ) def test_get_node(self): node = QgsSettingsTree.node("gps") @@ -171,37 +199,49 @@ def test_get_node(self): self.assertEqual(len(QgsSettingsTree.node("gps").childrenNodes()), count + 1) def test_register_unregister_settings(self): - root = QgsSettingsTree.createPluginTreeNode(pluginName='crash_at_three') - s1 = QgsSettingsEntryString('root setting 1', root, 'value', 'desc') - s2 = QgsSettingsEntryString('root setting 2', root, 'value', 'desc') - s3 = QgsSettingsEntryString('setting 3', root, 'value', 'desc') - - n1 = root.createChildNode('node 1') - n1s1 = QgsSettingsEntryString('node 1 setting 1', n1, 'value', 'desc') - n1s2 = QgsSettingsEntryString('node 1 setting 2', n1, 'value', 'desc') - n1s3 = QgsSettingsEntryString('node 1 setting 3', n1, 'c', 'node 1 desc 3') - - n1c1 = n1.createChildNode('node 1 child 1') - n1c1s1 = QgsSettingsEntryString('node 1 child 1 setting 1', n1c1, 'value', 'desc') - n1c1s2 = QgsSettingsEntryString('node 1 child 1 setting 2', n1c1, 'value', 'desc') - n1c1s3 = QgsSettingsEntryString('node 1 child 1 setting 3', n1c1, 'value', 'desc') - - n1c2 = n1.createChildNode('node 1 child 2') - n1c2s1 = QgsSettingsEntryString('node 1 child 2 setting 1', n1c2, 'value', 'desc') - n1c2s2 = QgsSettingsEntryString('node 1 child 2 setting 2', n1c2, 'value', 'desc') - n1c2s3 = QgsSettingsEntryString('node 1 child 2 setting 3', n1c2, 'value', 'desc') - - n1c3 = n1.createChildNode('node 1 child 3') - - n2 = root.createChildNode('node 2') - n2s1 = QgsSettingsEntryString('node 2 setting 1', n2, 'value', 'desc') - n2s2 = QgsSettingsEntryString('node 2 setting 2', n2, 'value', 'desc') - n2s3 = QgsSettingsEntryString('node 2 setting 3', n2, 'value', 'desc') - - n3 = root.createChildNode('node 3') - - QgsSettingsTree.unregisterPluginTreeNode(pluginName='crash_at_three') - - -if __name__ == '__main__': + root = QgsSettingsTree.createPluginTreeNode(pluginName="crash_at_three") + s1 = QgsSettingsEntryString("root setting 1", root, "value", "desc") + s2 = QgsSettingsEntryString("root setting 2", root, "value", "desc") + s3 = QgsSettingsEntryString("setting 3", root, "value", "desc") + + n1 = root.createChildNode("node 1") + n1s1 = QgsSettingsEntryString("node 1 setting 1", n1, "value", "desc") + n1s2 = QgsSettingsEntryString("node 1 setting 2", n1, "value", "desc") + n1s3 = QgsSettingsEntryString("node 1 setting 3", n1, "c", "node 1 desc 3") + + n1c1 = n1.createChildNode("node 1 child 1") + n1c1s1 = QgsSettingsEntryString( + "node 1 child 1 setting 1", n1c1, "value", "desc" + ) + n1c1s2 = QgsSettingsEntryString( + "node 1 child 1 setting 2", n1c1, "value", "desc" + ) + n1c1s3 = QgsSettingsEntryString( + "node 1 child 1 setting 3", n1c1, "value", "desc" + ) + + n1c2 = n1.createChildNode("node 1 child 2") + n1c2s1 = QgsSettingsEntryString( + "node 1 child 2 setting 1", n1c2, "value", "desc" + ) + n1c2s2 = QgsSettingsEntryString( + "node 1 child 2 setting 2", n1c2, "value", "desc" + ) + n1c2s3 = QgsSettingsEntryString( + "node 1 child 2 setting 3", n1c2, "value", "desc" + ) + + n1c3 = n1.createChildNode("node 1 child 3") + + n2 = root.createChildNode("node 2") + n2s1 = QgsSettingsEntryString("node 2 setting 1", n2, "value", "desc") + n2s2 = QgsSettingsEntryString("node 2 setting 2", n2, "value", "desc") + n2s3 = QgsSettingsEntryString("node 2 setting 3", n2, "value", "desc") + + n3 = root.createChildNode("node 3") + + QgsSettingsTree.unregisterPluginTreeNode(pluginName="crash_at_three") + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsshortcutsmanager.py b/tests/src/python/test_qgsshortcutsmanager.py index 46ad684d9544..329b7ef88beb 100644 --- a/tests/src/python/test_qgsshortcutsmanager.py +++ b/tests/src/python/test_qgsshortcutsmanager.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '28/05/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "28/05/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication from qgis.PyQt.QtWidgets import QAction, QShortcut, QWidget @@ -30,11 +31,11 @@ def setUpClass(cls): start_app() def testInstance(self): - """ test retrieving global instance """ + """test retrieving global instance""" self.assertTrue(QgsGui.shortcutsManager()) # register an action to the singleton - action = QAction('test', None) + action = QAction("test", None) QgsGui.shortcutsManager().registerAction(action) # check that the same instance is returned self.assertEqual(QgsGui.shortcutsManager().listActions(), [action]) @@ -42,120 +43,120 @@ def testInstance(self): self.assertEqual(s2.listActions(), []) def testConstructor(self): - """ test constructing managers""" - s = QgsShortcutsManager(None, '/my_path/') - self.assertEqual(s.settingsPath(), '/my_path/') + """test constructing managers""" + s = QgsShortcutsManager(None, "/my_path/") + self.assertEqual(s.settingsPath(), "/my_path/") def testSettingsPath(self): - """ test that settings path is respected """ + """test that settings path is respected""" QgsSettings().clear() - s1 = QgsShortcutsManager(None, '/path1/') - s2 = QgsShortcutsManager(None, '/path2/') + s1 = QgsShortcutsManager(None, "/path1/") + s2 = QgsShortcutsManager(None, "/path2/") - action1 = QAction('action', None) + action1 = QAction("action", None) s1.registerAction(action1) - s1.setKeySequence(action1, 'B') + s1.setKeySequence(action1, "B") - action2 = QAction('action', None) + action2 = QAction("action", None) s2.registerAction(action2) - s2.setKeySequence(action2, 'C') + s2.setKeySequence(action2, "C") # test retrieving - r1 = QgsShortcutsManager(None, '/path1/') - r2 = QgsShortcutsManager(None, '/path2/') + r1 = QgsShortcutsManager(None, "/path1/") + r2 = QgsShortcutsManager(None, "/path2/") - raction1 = QAction('action', None) + raction1 = QAction("action", None) r1.registerAction(raction1) - raction2 = QAction('action', None) + raction2 = QAction("action", None) r2.registerAction(raction2) - self.assertEqual(raction1.shortcut().toString(), 'B') - self.assertEqual(raction2.shortcut().toString(), 'C') + self.assertEqual(raction1.shortcut().toString(), "B") + self.assertEqual(raction2.shortcut().toString(), "C") def testRegisterAction(self): - """ test registering actions """ + """test registering actions""" QgsSettings().clear() s = QgsShortcutsManager(None) - action1 = QAction('action1', None) - action1.setShortcut('x') - self.assertTrue(s.registerAction(action1, 'A')) - action2 = QAction('action2', None) - action2.setShortcut('y') - self.assertTrue(s.registerAction(action2, 'B')) + action1 = QAction("action1", None) + action1.setShortcut("x") + self.assertTrue(s.registerAction(action1, "A")) + action2 = QAction("action2", None) + action2.setShortcut("y") + self.assertTrue(s.registerAction(action2, "B")) self.assertCountEqual(s.listActions(), [action1, action2]) # try re-registering an existing action - should fail, but leave action registered - self.assertFalse(s.registerAction(action2, 'B')) + self.assertFalse(s.registerAction(action2, "B")) self.assertCountEqual(s.listActions(), [action1, action2]) # actions should have been set to default sequences - self.assertEqual(action1.shortcut().toString(), 'A') - self.assertEqual(action2.shortcut().toString(), 'B') + self.assertEqual(action1.shortcut().toString(), "A") + self.assertEqual(action2.shortcut().toString(), "B") # test that adding an action should set its shortcut automatically - s.setKeySequence('action1', 'C') - s.setKeySequence('action2', 'D') + s.setKeySequence("action1", "C") + s.setKeySequence("action2", "D") s = QgsShortcutsManager(None) - self.assertTrue(s.registerAction(action1, 'A')) - self.assertTrue(s.registerAction(action2, 'B')) + self.assertTrue(s.registerAction(action1, "A")) + self.assertTrue(s.registerAction(action2, "B")) # actions should have been set to previous shortcuts - self.assertEqual(action1.shortcut().toString(), 'C') - self.assertEqual(action2.shortcut().toString(), 'D') + self.assertEqual(action1.shortcut().toString(), "C") + self.assertEqual(action2.shortcut().toString(), "D") # test registering an action containing '&' in name s = QgsShortcutsManager(None) - action = QAction('&action1', None) + action = QAction("&action1", None) self.assertTrue(s.registerAction(action)) - self.assertEqual(action1.shortcut().toString(), 'C') + self.assertEqual(action1.shortcut().toString(), "C") def testRegisterShortcut(self): - """ test registering shortcuts """ + """test registering shortcuts""" QgsSettings().clear() s = QgsShortcutsManager(None) shortcut1 = QShortcut(None) - shortcut1.setKey('x') - shortcut1.setObjectName('shortcut1') - self.assertTrue(s.registerShortcut(shortcut1, 'A')) + shortcut1.setKey("x") + shortcut1.setObjectName("shortcut1") + self.assertTrue(s.registerShortcut(shortcut1, "A")) shortcut2 = QShortcut(None) - shortcut2.setKey('y') - shortcut2.setObjectName('shortcut2') - self.assertTrue(s.registerShortcut(shortcut2, 'B')) + shortcut2.setKey("y") + shortcut2.setObjectName("shortcut2") + self.assertTrue(s.registerShortcut(shortcut2, "B")) # shortcuts should have been set to default sequences - self.assertEqual(shortcut1.key().toString(), 'A') - self.assertEqual(shortcut2.key().toString(), 'B') + self.assertEqual(shortcut1.key().toString(), "A") + self.assertEqual(shortcut2.key().toString(), "B") # test that adding a shortcut should set its sequence automatically - s.setKeySequence(shortcut1, 'C') - s.setKeySequence(shortcut2, 'D') + s.setKeySequence(shortcut1, "C") + s.setKeySequence(shortcut2, "D") s = QgsShortcutsManager(None) - self.assertTrue(s.registerShortcut(shortcut1, 'A')) - self.assertTrue(s.registerShortcut(shortcut2, 'B')) + self.assertTrue(s.registerShortcut(shortcut1, "A")) + self.assertTrue(s.registerShortcut(shortcut2, "B")) # shortcuts should have been set to previous sequences - self.assertEqual(shortcut1.key().toString(), 'C') - self.assertEqual(shortcut2.key().toString(), 'D') + self.assertEqual(shortcut1.key().toString(), "C") + self.assertEqual(shortcut2.key().toString(), "D") def testRegisterAll(self): - """ test registering all children """ + """test registering all children""" w = QWidget() - action1 = QAction('action1', w) + action1 = QAction("action1", w) shortcut1 = QShortcut(w) - shortcut1.setObjectName('shortcut1') + shortcut1.setObjectName("shortcut1") w2 = QWidget(w) - action2 = QAction('action2', w2) + action2 = QAction("action2", w2) shortcut2 = QShortcut(w2) - shortcut2.setObjectName('shortcut2') + shortcut2.setObjectName("shortcut2") # recursive s = QgsShortcutsManager() @@ -184,23 +185,23 @@ def testRegisterAll(self): self.assertEqual(set(s.listShortcuts()), {shortcut1}) def testUnregister(self): - """ test unregistering from manager """ + """test unregistering from manager""" QgsSettings().clear() s = QgsShortcutsManager(None) shortcut1 = QShortcut(None) - shortcut1.setKey('x') - shortcut1.setObjectName('shortcut1') + shortcut1.setKey("x") + shortcut1.setObjectName("shortcut1") shortcut2 = QShortcut(None) - shortcut2.setKey('y') - shortcut2.setObjectName('shortcut2') + shortcut2.setKey("y") + shortcut2.setObjectName("shortcut2") - action1 = QAction('action1', None) - action1.setShortcut('x') - action2 = QAction('action2', None) - action2.setShortcut('y') + action1 = QAction("action1", None) + action1.setShortcut("x") + action2 = QAction("action2", None) + action2.setShortcut("y") # try unregistering objects not registered in manager self.assertFalse(s.unregisterShortcut(shortcut1)) @@ -225,7 +226,7 @@ def testUnregister(self): self.assertTrue(s.unregisterShortcut(shortcut2)) def testList(self): - """ test listing registered objects """ + """test listing registered objects""" QgsSettings().clear() @@ -237,8 +238,8 @@ def testList(self): shortcut1 = QShortcut(None) shortcut2 = QShortcut(None) - action1 = QAction('action1', None) - action2 = QAction('action2', None) + action1 = QAction("action1", None) + action2 = QAction("action2", None) s.registerShortcut(shortcut1) s.registerShortcut(shortcut2) s.registerAction(action1) @@ -249,7 +250,7 @@ def testList(self): self.assertEqual(set(s.listAll()), {action1, action2, shortcut1, shortcut2}) def testDefault(self): - """ test retrieving default sequences """ + """test retrieving default sequences""" QgsSettings().clear() @@ -257,212 +258,212 @@ def testDefault(self): shortcut1 = QShortcut(None) shortcut2 = QShortcut(None) - action1 = QAction('action1', None) - action2 = QAction('action2', None) + action1 = QAction("action1", None) + action2 = QAction("action2", None) # test while not yet registered - self.assertEqual(s.defaultKeySequence(shortcut1), '') - self.assertEqual(s.defaultKeySequence(action1), '') - self.assertEqual(s.objectDefaultKeySequence(shortcut1), '') - self.assertEqual(s.objectDefaultKeySequence(action1), '') + self.assertEqual(s.defaultKeySequence(shortcut1), "") + self.assertEqual(s.defaultKeySequence(action1), "") + self.assertEqual(s.objectDefaultKeySequence(shortcut1), "") + self.assertEqual(s.objectDefaultKeySequence(action1), "") # now register them - s.registerShortcut(shortcut1, 'A') - s.registerShortcut(shortcut2, 'B') - s.registerAction(action1, 'C') - s.registerAction(action2, 'D') - - self.assertEqual(s.defaultKeySequence(shortcut1), 'A') - self.assertEqual(s.defaultKeySequence(shortcut2), 'B') - self.assertEqual(s.defaultKeySequence(action1), 'C') - self.assertEqual(s.defaultKeySequence(action2), 'D') - self.assertEqual(s.objectDefaultKeySequence(shortcut1), 'A') - self.assertEqual(s.objectDefaultKeySequence(shortcut2), 'B') - self.assertEqual(s.objectDefaultKeySequence(action1), 'C') - self.assertEqual(s.objectDefaultKeySequence(action2), 'D') + s.registerShortcut(shortcut1, "A") + s.registerShortcut(shortcut2, "B") + s.registerAction(action1, "C") + s.registerAction(action2, "D") + + self.assertEqual(s.defaultKeySequence(shortcut1), "A") + self.assertEqual(s.defaultKeySequence(shortcut2), "B") + self.assertEqual(s.defaultKeySequence(action1), "C") + self.assertEqual(s.defaultKeySequence(action2), "D") + self.assertEqual(s.objectDefaultKeySequence(shortcut1), "A") + self.assertEqual(s.objectDefaultKeySequence(shortcut2), "B") + self.assertEqual(s.objectDefaultKeySequence(action1), "C") + self.assertEqual(s.objectDefaultKeySequence(action2), "D") def testSetSequence(self): - """ test setting key sequences """ + """test setting key sequences""" QgsSettings().clear() s = QgsShortcutsManager(None) shortcut1 = QShortcut(None) - shortcut1.setObjectName('shortcut1') + shortcut1.setObjectName("shortcut1") shortcut2 = QShortcut(None) - shortcut2.setObjectName('shortcut2') - action1 = QAction('action1', None) - action2 = QAction('action2', None) + shortcut2.setObjectName("shortcut2") + action1 = QAction("action1", None) + action2 = QAction("action2", None) - s.registerShortcut(shortcut1, 'A') - s.registerShortcut(shortcut2, 'B') - s.registerAction(action1, 'C') - s.registerAction(action2, 'D') + s.registerShortcut(shortcut1, "A") + s.registerShortcut(shortcut2, "B") + s.registerAction(action1, "C") + s.registerAction(action2, "D") # test setting by action/shortcut - self.assertTrue(s.setKeySequence(shortcut1, 'E')) - self.assertTrue(s.setKeySequence(shortcut2, 'F')) - self.assertTrue(s.setKeySequence(action1, 'G')) - self.assertTrue(s.setKeySequence(action2, 'H')) + self.assertTrue(s.setKeySequence(shortcut1, "E")) + self.assertTrue(s.setKeySequence(shortcut2, "F")) + self.assertTrue(s.setKeySequence(action1, "G")) + self.assertTrue(s.setKeySequence(action2, "H")) # test that action/shortcuts have been updated - self.assertEqual(shortcut1.key().toString(), 'E') - self.assertEqual(shortcut2.key().toString(), 'F') - self.assertEqual(action1.shortcut().toString(), 'G') - self.assertEqual(action2.shortcut().toString(), 'H') + self.assertEqual(shortcut1.key().toString(), "E") + self.assertEqual(shortcut2.key().toString(), "F") + self.assertEqual(action1.shortcut().toString(), "G") + self.assertEqual(action2.shortcut().toString(), "H") # new manager s = QgsShortcutsManager(None) # new shortcuts shortcut1 = QShortcut(None) - shortcut1.setObjectName('shortcut1') + shortcut1.setObjectName("shortcut1") shortcut2 = QShortcut(None) - shortcut2.setObjectName('shortcut2') - action1 = QAction('action1', None) - action2 = QAction('action2', None) + shortcut2.setObjectName("shortcut2") + action1 = QAction("action1", None) + action2 = QAction("action2", None) # register them - s.registerShortcut(shortcut1, 'A') - s.registerShortcut(shortcut2, 'B') - s.registerAction(action1, 'C') - s.registerAction(action2, 'D') + s.registerShortcut(shortcut1, "A") + s.registerShortcut(shortcut2, "B") + s.registerAction(action1, "C") + s.registerAction(action2, "D") # check that previously set sequence has been restored - self.assertEqual(shortcut1.key().toString(), 'E') - self.assertEqual(shortcut2.key().toString(), 'F') - self.assertEqual(action1.shortcut().toString(), 'G') - self.assertEqual(action2.shortcut().toString(), 'H') + self.assertEqual(shortcut1.key().toString(), "E") + self.assertEqual(shortcut2.key().toString(), "F") + self.assertEqual(action1.shortcut().toString(), "G") + self.assertEqual(action2.shortcut().toString(), "H") # same test, using setObjectKeySequence QgsSettings().clear() s = QgsShortcutsManager(None) shortcut1 = QShortcut(None) - shortcut1.setObjectName('shortcut1') - action1 = QAction('action1', None) - s.registerShortcut(shortcut1, 'A') - s.registerAction(action1, 'C') - self.assertTrue(s.setObjectKeySequence(shortcut1, 'E')) - self.assertTrue(s.setObjectKeySequence(action1, 'G')) - self.assertEqual(shortcut1.key().toString(), 'E') - self.assertEqual(action1.shortcut().toString(), 'G') + shortcut1.setObjectName("shortcut1") + action1 = QAction("action1", None) + s.registerShortcut(shortcut1, "A") + s.registerAction(action1, "C") + self.assertTrue(s.setObjectKeySequence(shortcut1, "E")) + self.assertTrue(s.setObjectKeySequence(action1, "G")) + self.assertEqual(shortcut1.key().toString(), "E") + self.assertEqual(action1.shortcut().toString(), "G") s = QgsShortcutsManager(None) shortcut1 = QShortcut(None) - shortcut1.setObjectName('shortcut1') - action1 = QAction('action1', None) - s.registerShortcut(shortcut1, 'A') - s.registerAction(action1, 'C') - self.assertEqual(shortcut1.key().toString(), 'E') - self.assertEqual(action1.shortcut().toString(), 'G') + shortcut1.setObjectName("shortcut1") + action1 = QAction("action1", None) + s.registerShortcut(shortcut1, "A") + s.registerAction(action1, "C") + self.assertEqual(shortcut1.key().toString(), "E") + self.assertEqual(action1.shortcut().toString(), "G") # same test, using setKeySequence by name QgsSettings().clear() s = QgsShortcutsManager(None) shortcut1 = QShortcut(None) - shortcut1.setObjectName('shortcut1') - action1 = QAction('action1', None) - s.registerShortcut(shortcut1, 'A') - s.registerAction(action1, 'C') - self.assertFalse(s.setKeySequence('invalid_name', 'E')) - self.assertTrue(s.setKeySequence('shortcut1', 'E')) - self.assertTrue(s.setKeySequence('action1', 'G')) - self.assertEqual(shortcut1.key().toString(), 'E') - self.assertEqual(action1.shortcut().toString(), 'G') + shortcut1.setObjectName("shortcut1") + action1 = QAction("action1", None) + s.registerShortcut(shortcut1, "A") + s.registerAction(action1, "C") + self.assertFalse(s.setKeySequence("invalid_name", "E")) + self.assertTrue(s.setKeySequence("shortcut1", "E")) + self.assertTrue(s.setKeySequence("action1", "G")) + self.assertEqual(shortcut1.key().toString(), "E") + self.assertEqual(action1.shortcut().toString(), "G") s = QgsShortcutsManager(None) shortcut1 = QShortcut(None) - shortcut1.setObjectName('shortcut1') - action1 = QAction('action1', None) - s.registerShortcut(shortcut1, 'A') - s.registerAction(action1, 'C') - self.assertEqual(shortcut1.key().toString(), 'E') - self.assertEqual(action1.shortcut().toString(), 'G') + shortcut1.setObjectName("shortcut1") + action1 = QAction("action1", None) + s.registerShortcut(shortcut1, "A") + s.registerAction(action1, "C") + self.assertEqual(shortcut1.key().toString(), "E") + self.assertEqual(action1.shortcut().toString(), "G") def testBySequence(self): - """ test retrieving by sequence """ + """test retrieving by sequence""" QgsSettings().clear() shortcut1 = QShortcut(None) - shortcut1.setObjectName('shortcut1') + shortcut1.setObjectName("shortcut1") shortcut2 = QShortcut(None) - shortcut2.setObjectName('shortcut2') - action1 = QAction('action1', None) - action2 = QAction('action2', None) + shortcut2.setObjectName("shortcut2") + action1 = QAction("action1", None) + action2 = QAction("action2", None) s = QgsShortcutsManager(None) - self.assertFalse(s.actionForSequence('E')) - self.assertFalse(s.objectForSequence('F')) + self.assertFalse(s.actionForSequence("E")) + self.assertFalse(s.objectForSequence("F")) - s.registerShortcut(shortcut1, 'E') - s.registerShortcut(shortcut2, 'A') - s.registerAction(action1, 'F') - s.registerAction(action2, 'B') + s.registerShortcut(shortcut1, "E") + s.registerShortcut(shortcut2, "A") + s.registerAction(action1, "F") + s.registerAction(action2, "B") # use another way of registering sequences - self.assertTrue(s.setKeySequence(shortcut2, 'G')) - self.assertTrue(s.setKeySequence(action2, 'H')) - - self.assertEqual(s.objectForSequence('E'), shortcut1) - self.assertEqual(s.objectForSequence('F'), action1) - self.assertEqual(s.objectForSequence('G'), shortcut2) - self.assertEqual(s.objectForSequence('H'), action2) - self.assertFalse(s.objectForSequence('A')) - self.assertFalse(s.objectForSequence('B')) - - self.assertEqual(s.shortcutForSequence('E'), shortcut1) - self.assertFalse(s.shortcutForSequence('F')) - self.assertEqual(s.shortcutForSequence('G'), shortcut2) - self.assertFalse(s.shortcutForSequence('H')) - self.assertFalse(s.actionForSequence('E')) - self.assertEqual(s.actionForSequence('F'), action1) - self.assertFalse(s.actionForSequence('G')) - self.assertEqual(s.actionForSequence('H'), action2) + self.assertTrue(s.setKeySequence(shortcut2, "G")) + self.assertTrue(s.setKeySequence(action2, "H")) + + self.assertEqual(s.objectForSequence("E"), shortcut1) + self.assertEqual(s.objectForSequence("F"), action1) + self.assertEqual(s.objectForSequence("G"), shortcut2) + self.assertEqual(s.objectForSequence("H"), action2) + self.assertFalse(s.objectForSequence("A")) + self.assertFalse(s.objectForSequence("B")) + + self.assertEqual(s.shortcutForSequence("E"), shortcut1) + self.assertFalse(s.shortcutForSequence("F")) + self.assertEqual(s.shortcutForSequence("G"), shortcut2) + self.assertFalse(s.shortcutForSequence("H")) + self.assertFalse(s.actionForSequence("E")) + self.assertEqual(s.actionForSequence("F"), action1) + self.assertFalse(s.actionForSequence("G")) + self.assertEqual(s.actionForSequence("H"), action2) def testByName(self): - """" test retrieving actions and shortcuts by name """ + """ " test retrieving actions and shortcuts by name""" QgsSettings().clear() shortcut1 = QShortcut(None) - shortcut1.setObjectName('shortcut1') + shortcut1.setObjectName("shortcut1") shortcut2 = QShortcut(None) - shortcut2.setObjectName('shortcut2') - action1 = QAction('action1', None) - action2 = QAction('action2', None) + shortcut2.setObjectName("shortcut2") + action1 = QAction("action1", None) + action2 = QAction("action2", None) s = QgsShortcutsManager(None) - self.assertFalse(s.actionByName('action1')) - self.assertFalse(s.shortcutByName('shortcut1')) + self.assertFalse(s.actionByName("action1")) + self.assertFalse(s.shortcutByName("shortcut1")) s.registerShortcut(shortcut1) s.registerShortcut(shortcut2) s.registerAction(action1) s.registerAction(action2) - self.assertEqual(s.shortcutByName('shortcut1'), shortcut1) - self.assertFalse(s.shortcutByName('action1')) - self.assertEqual(s.shortcutByName('shortcut2'), shortcut2) - self.assertFalse(s.shortcutByName('action2')) - self.assertFalse(s.actionByName('shortcut1')) - self.assertEqual(s.actionByName('action1'), action1) - self.assertFalse(s.actionByName('shortcut2')) - self.assertEqual(s.actionByName('action2'), action2) + self.assertEqual(s.shortcutByName("shortcut1"), shortcut1) + self.assertFalse(s.shortcutByName("action1")) + self.assertEqual(s.shortcutByName("shortcut2"), shortcut2) + self.assertFalse(s.shortcutByName("action2")) + self.assertFalse(s.actionByName("shortcut1")) + self.assertEqual(s.actionByName("action1"), action1) + self.assertFalse(s.actionByName("shortcut2")) + self.assertEqual(s.actionByName("action2"), action2) def testTooltip(self): - """" test action tooltips """ - action1 = QAction('action1', None) - action1.setToolTip('my tooltip') - action2 = QAction('action2', None) - action2.setToolTip('my multiline\ntooltip') - action3 = QAction('action3', None) - action3.setToolTip('my tooltip (Ctrl+S)') + """ " test action tooltips""" + action1 = QAction("action1", None) + action1.setToolTip("my tooltip") + action2 = QAction("action2", None) + action2.setToolTip("my multiline\ntooltip") + action3 = QAction("action3", None) + action3.setToolTip("my tooltip (Ctrl+S)") s = QgsShortcutsManager(None) s.registerAction(action1) s.registerAction(action2) - s.registerAction(action3, 'Ctrl+S') + s.registerAction(action3, "Ctrl+S") - self.assertEqual(action1.toolTip(), 'my tooltip') - self.assertEqual(action2.toolTip(), 'my multiline

    tooltip

    ') - self.assertEqual(action3.toolTip(), 'my tooltip (Ctrl+S)') + self.assertEqual(action1.toolTip(), "my tooltip") + self.assertEqual(action2.toolTip(), "my multiline

    tooltip

    ") + self.assertEqual(action3.toolTip(), "my tooltip (Ctrl+S)") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssimplefillsymbollayer.py b/tests/src/python/test_qgssimplefillsymbollayer.py index 8f5c6a25cff7..0390a84bb451 100644 --- a/tests/src/python/test_qgssimplefillsymbollayer.py +++ b/tests/src/python/test_qgssimplefillsymbollayer.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'September 2020' -__copyright__ = '(C) 2020, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "September 2020" +__copyright__ = "(C) 2020, Nyall Dawson" import os @@ -54,30 +54,34 @@ def control_path_prefix(cls): def testRender(self): # rendering test - s = QgsFillSymbol.createSimple({'outline_color': '#ff0000', 'outline_width': '2', 'color': '#ff5588'}) + s = QgsFillSymbol.createSimple( + {"outline_color": "#ff0000", "outline_width": "2", "color": "#ff5588"} + ) - g = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 0 0))') + g = QgsGeometry.fromWkt("Polygon((0 0, 10 0, 10 10, 0 0))") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('simplefill_render', 'simplefill_render', rendered_image) + self.image_check("simplefill_render", "simplefill_render", rendered_image) ) def testRenderWithOffset(self): # rendering test with offset - s = QgsFillSymbol.createSimple({'outline_color': '#ff0000', 'outline_width': '2', 'color': '#ff5588'}) + s = QgsFillSymbol.createSimple( + {"outline_color": "#ff0000", "outline_width": "2", "color": "#ff5588"} + ) s[0].setOffset(QPointF(5, 3)) - g = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 0 0))') + g = QgsGeometry.fromWkt("Polygon((0 0, 10 0, 10 10, 0 0))") rendered_image = self.renderGeometry(s, g) self.assertTrue( - self.image_check('simplefill_offset', 'simplefill_offset', rendered_image) + self.image_check("simplefill_offset", "simplefill_offset", rendered_image) ) def testDataDefinedOffset(self): - """ test that rendering a fill symbol with data defined offset works""" + """test that rendering a fill symbol with data defined offset works""" - polys_shp = os.path.join(TEST_DATA_DIR, 'polys.shp') - polys_layer = QgsVectorLayer(polys_shp, 'Polygons', 'ogr') + polys_shp = os.path.join(TEST_DATA_DIR, "polys.shp") + polys_layer = QgsVectorLayer(polys_shp, "Polygons", "ogr") # lets render two layers, to make comparison easier layer = QgsSimpleFillSymbolLayer() @@ -88,7 +92,12 @@ def testDataDefinedOffset(self): symbol.changeSymbolLayer(0, layer) layer = QgsSimpleFillSymbolLayer() - layer.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyOffset, QgsProperty.fromExpression("array(-(x_min($geometry)+100)/5, (y_min($geometry)-35)/5)")) + layer.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyOffset, + QgsProperty.fromExpression( + "array(-(x_min($geometry)+100)/5, (y_min($geometry)-35)/5)" + ), + ) layer.setStrokeStyle(Qt.PenStyle.NoPen) layer.setColor(QColor(100, 150, 150)) @@ -104,21 +113,27 @@ def testDataDefinedOffset(self): # Test rendering self.assertTrue( - self.render_map_settings_check('simplefill_ddoffset', 'simplefill_ddoffset', ms) + self.render_map_settings_check( + "simplefill_ddoffset", "simplefill_ddoffset", ms + ) ) def testOpacityWithDataDefinedColor(self): - poly_shp = os.path.join(TEST_DATA_DIR, 'polys.shp') - poly_layer = QgsVectorLayer(poly_shp, 'Polys', 'ogr') + poly_shp = os.path.join(TEST_DATA_DIR, "polys.shp") + poly_layer = QgsVectorLayer(poly_shp, "Polys", "ogr") self.assertTrue(poly_layer.isValid()) layer = QgsSimpleFillSymbolLayer() layer.setStrokeStyle(Qt.PenStyle.NoPen) layer.setColor(QColor(200, 250, 50)) - layer.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyFillColor, QgsProperty.fromExpression( - "if(Name='Dam', 'red', 'green')")) - layer.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyStrokeColor, QgsProperty.fromExpression( - "if(Name='Dam', 'magenta', 'blue')")) + layer.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyFillColor, + QgsProperty.fromExpression("if(Name='Dam', 'red', 'green')"), + ) + layer.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyStrokeColor, + QgsProperty.fromExpression("if(Name='Dam', 'magenta', 'blue')"), + ) symbol = QgsFillSymbol() symbol.changeSymbolLayer(0, layer) @@ -135,26 +150,35 @@ def testOpacityWithDataDefinedColor(self): # Test rendering self.assertTrue( - self.render_map_settings_check('simplefill_opacityddcolor', 'simplefill_opacityddcolor', ms) + self.render_map_settings_check( + "simplefill_opacityddcolor", "simplefill_opacityddcolor", ms + ) ) def testDataDefinedOpacity(self): - poly_shp = os.path.join(TEST_DATA_DIR, 'polys.shp') - poly_layer = QgsVectorLayer(poly_shp, 'Polys', 'ogr') + poly_shp = os.path.join(TEST_DATA_DIR, "polys.shp") + poly_layer = QgsVectorLayer(poly_shp, "Polys", "ogr") self.assertTrue(poly_layer.isValid()) layer = QgsSimpleFillSymbolLayer() layer.setStrokeStyle(Qt.PenStyle.NoPen) layer.setColor(QColor(200, 250, 50)) - layer.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyFillColor, QgsProperty.fromExpression( - "if(Name='Dam', 'red', 'green')")) - layer.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyStrokeColor, QgsProperty.fromExpression( - "if(Name='Dam', 'magenta', 'blue')")) + layer.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyFillColor, + QgsProperty.fromExpression("if(Name='Dam', 'red', 'green')"), + ) + layer.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyStrokeColor, + QgsProperty.fromExpression("if(Name='Dam', 'magenta', 'blue')"), + ) symbol = QgsFillSymbol() symbol.changeSymbolLayer(0, layer) - symbol.setDataDefinedProperty(QgsSymbol.Property.PropertyOpacity, QgsProperty.fromExpression("if(\"Value\" >10, 25, 50)")) + symbol.setDataDefinedProperty( + QgsSymbol.Property.PropertyOpacity, + QgsProperty.fromExpression('if("Value" >10, 25, 50)'), + ) poly_layer.setRenderer(QgsSingleSymbolRenderer(symbol)) @@ -166,7 +190,9 @@ def testDataDefinedOpacity(self): # Test rendering self.assertTrue( - self.render_map_settings_check('simplefill_ddopacity', 'simplefill_ddopacity', ms) + self.render_map_settings_check( + "simplefill_ddopacity", "simplefill_ddopacity", ms + ) ) def renderGeometry(self, symbol, geom): @@ -202,5 +228,5 @@ def renderGeometry(self, symbol, geom): return image -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssimplelinesymbollayer.py b/tests/src/python/test_qgssimplelinesymbollayer.py index 9ebf10f0cac6..17bcefb8aa94 100644 --- a/tests/src/python/test_qgssimplelinesymbollayer.py +++ b/tests/src/python/test_qgssimplelinesymbollayer.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'November 2018' -__copyright__ = '(C) 2018, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "November 2018" +__copyright__ = "(C) 2018, Nyall Dawson" import os @@ -57,61 +57,81 @@ class TestQgsSimpleLineSymbolLayer(QgisTestCase): @classmethod def control_path_prefix(cls): - return 'symbol_simpleline' + return "symbol_simpleline" def testDashPatternWithDataDefinedWidth(self): # rendering test - s = QgsLineSymbol.createSimple({'outline_color': '#ff0000', 'outline_width': '2'}) + s = QgsLineSymbol.createSimple( + {"outline_color": "#ff0000", "outline_width": "2"} + ) s[0].setUseCustomDashPattern(True) s[0].setPenCapStyle(Qt.PenCapStyle.FlatCap) s[0].setCustomDashVector([3, 4, 5, 6]) - s[0].dataDefinedProperties().setProperty(QgsSymbolLayer.Property.PropertyStrokeWidth, QgsProperty.fromExpression('3')) + s[0].dataDefinedProperties().setProperty( + QgsSymbolLayer.Property.PropertyStrokeWidth, QgsProperty.fromExpression("3") + ) - g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10, 0 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 0, 10 10, 0 10)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'simpleline_dashpattern_datadefined_width', - 'simpleline_dashpattern_datadefined_width', + "simpleline_dashpattern_datadefined_width", + "simpleline_dashpattern_datadefined_width", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def testTrimDistance(self): - s = QgsLineSymbol.createSimple({'outline_color': '#ff0000', 'outline_width': '0.6'}) + s = QgsLineSymbol.createSimple( + {"outline_color": "#ff0000", "outline_width": "0.6"} + ) s.symbolLayer(0).setTrimDistanceStart(1.2) s.symbolLayer(0).setTrimDistanceStartUnit(QgsUnitTypes.RenderUnit.RenderPoints) s.symbolLayer(0).setTrimDistanceStartMapUnitScale(QgsMapUnitScale(5, 10)) s.symbolLayer(0).setTrimDistanceEnd(3.2) - s.symbolLayer(0).setTrimDistanceEndUnit(QgsUnitTypes.RenderUnit.RenderPercentage) + s.symbolLayer(0).setTrimDistanceEndUnit( + QgsUnitTypes.RenderUnit.RenderPercentage + ) s.symbolLayer(0).setTrimDistanceEndMapUnitScale(QgsMapUnitScale(15, 20)) s2 = s.clone() self.assertEqual(s2.symbolLayer(0).trimDistanceStart(), 1.2) - self.assertEqual(s2.symbolLayer(0).trimDistanceStartUnit(), QgsUnitTypes.RenderUnit.RenderPoints) + self.assertEqual( + s2.symbolLayer(0).trimDistanceStartUnit(), + QgsUnitTypes.RenderUnit.RenderPoints, + ) self.assertEqual(s2.symbolLayer(0).trimDistanceStartMapUnitScale().minScale, 5) self.assertEqual(s2.symbolLayer(0).trimDistanceStartMapUnitScale().maxScale, 10) self.assertEqual(s2.symbolLayer(0).trimDistanceEnd(), 3.2) - self.assertEqual(s2.symbolLayer(0).trimDistanceEndUnit(), QgsUnitTypes.RenderUnit.RenderPercentage) + self.assertEqual( + s2.symbolLayer(0).trimDistanceEndUnit(), + QgsUnitTypes.RenderUnit.RenderPercentage, + ) self.assertEqual(s2.symbolLayer(0).trimDistanceEndMapUnitScale().minScale, 15) self.assertEqual(s2.symbolLayer(0).trimDistanceEndMapUnitScale().maxScale, 20) doc = QDomDocument() context = QgsReadWriteContext() - element = QgsSymbolLayerUtils.saveSymbol('test', s, doc, context) + element = QgsSymbolLayerUtils.saveSymbol("test", s, doc, context) s2 = QgsSymbolLayerUtils.loadSymbol(element, context) self.assertEqual(s2.symbolLayer(0).trimDistanceStart(), 1.2) - self.assertEqual(s2.symbolLayer(0).trimDistanceStartUnit(), QgsUnitTypes.RenderUnit.RenderPoints) + self.assertEqual( + s2.symbolLayer(0).trimDistanceStartUnit(), + QgsUnitTypes.RenderUnit.RenderPoints, + ) self.assertEqual(s2.symbolLayer(0).trimDistanceStartMapUnitScale().minScale, 5) self.assertEqual(s2.symbolLayer(0).trimDistanceStartMapUnitScale().maxScale, 10) self.assertEqual(s2.symbolLayer(0).trimDistanceEnd(), 3.2) - self.assertEqual(s2.symbolLayer(0).trimDistanceEndUnit(), QgsUnitTypes.RenderUnit.RenderPercentage) + self.assertEqual( + s2.symbolLayer(0).trimDistanceEndUnit(), + QgsUnitTypes.RenderUnit.RenderPercentage, + ) self.assertEqual(s2.symbolLayer(0).trimDistanceEndMapUnitScale().minScale, 15) self.assertEqual(s2.symbolLayer(0).trimDistanceEndMapUnitScale().maxScale, 20) @@ -119,22 +139,26 @@ def testTrimDistanceRender(self): """ Rendering test of trim distances """ - s = QgsLineSymbol.createSimple({'outline_color': '#ff0000', 'outline_width': '2'}) + s = QgsLineSymbol.createSimple( + {"outline_color": "#ff0000", "outline_width": "2"} + ) s.symbolLayer(0).setTrimDistanceStart(150) s.symbolLayer(0).setTrimDistanceStartUnit(QgsUnitTypes.RenderUnit.RenderPoints) s.symbolLayer(0).setTrimDistanceEnd(9) - s.symbolLayer(0).setTrimDistanceEndUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) + s.symbolLayer(0).setTrimDistanceEndUnit( + QgsUnitTypes.RenderUnit.RenderMillimeters + ) - g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10, 0 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 0, 10 10, 0 10)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'simpleline_trim_distance_units', - 'simpleline_trim_distance_units', + "simpleline_trim_distance_units", + "simpleline_trim_distance_units", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -142,22 +166,28 @@ def testTrimDistanceRenderPercentage(self): """ Rendering test of trim distances using percentage """ - s = QgsLineSymbol.createSimple({'outline_color': '#ff0000', 'outline_width': '2'}) + s = QgsLineSymbol.createSimple( + {"outline_color": "#ff0000", "outline_width": "2"} + ) s.symbolLayer(0).setTrimDistanceStart(10) - s.symbolLayer(0).setTrimDistanceStartUnit(QgsUnitTypes.RenderUnit.RenderPercentage) + s.symbolLayer(0).setTrimDistanceStartUnit( + QgsUnitTypes.RenderUnit.RenderPercentage + ) s.symbolLayer(0).setTrimDistanceEnd(50) - s.symbolLayer(0).setTrimDistanceEndUnit(QgsUnitTypes.RenderUnit.RenderPercentage) + s.symbolLayer(0).setTrimDistanceEndUnit( + QgsUnitTypes.RenderUnit.RenderPercentage + ) - g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10, 0 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 0, 10 10, 0 10)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'simpleline_trim_distance_percentage', - 'simpleline_trim_distance_percentage', + "simpleline_trim_distance_percentage", + "simpleline_trim_distance_percentage", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -165,30 +195,42 @@ def testTrimDistanceRenderDataDefined(self): """ Rendering test of trim distances using data defined lengths """ - s = QgsLineSymbol.createSimple({'outline_color': '#ff0000', 'outline_width': '2'}) + s = QgsLineSymbol.createSimple( + {"outline_color": "#ff0000", "outline_width": "2"} + ) s.symbolLayer(0).setTrimDistanceStart(1) - s.symbolLayer(0).setTrimDistanceStartUnit(QgsUnitTypes.RenderUnit.RenderPercentage) + s.symbolLayer(0).setTrimDistanceStartUnit( + QgsUnitTypes.RenderUnit.RenderPercentage + ) s.symbolLayer(0).setTrimDistanceEnd(5) - s.symbolLayer(0).setTrimDistanceEndUnit(QgsUnitTypes.RenderUnit.RenderPercentage) + s.symbolLayer(0).setTrimDistanceEndUnit( + QgsUnitTypes.RenderUnit.RenderPercentage + ) - s.symbolLayer(0).setDataDefinedProperty(QgsSymbolLayer.Property.PropertyTrimStart, QgsProperty.fromExpression('5*2')) - s.symbolLayer(0).setDataDefinedProperty(QgsSymbolLayer.Property.PropertyTrimEnd, QgsProperty.fromExpression('60-10')) + s.symbolLayer(0).setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyTrimStart, QgsProperty.fromExpression("5*2") + ) + s.symbolLayer(0).setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyTrimEnd, QgsProperty.fromExpression("60-10") + ) - g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10, 0 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 0, 10 10, 0 10)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'simpleline_trim_distance_percentage', - 'simpleline_trim_distance_percentage', + "simpleline_trim_distance_percentage", + "simpleline_trim_distance_percentage", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def testDashPatternOffset(self): - s = QgsLineSymbol.createSimple({'outline_color': '#ff0000', 'outline_width': '0.6'}) + s = QgsLineSymbol.createSimple( + {"outline_color": "#ff0000", "outline_width": "0.6"} + ) s.symbolLayer(0).setDashPatternOffset(1.2) s.symbolLayer(0).setDashPatternOffsetUnit(QgsUnitTypes.RenderUnit.RenderPoints) @@ -196,83 +238,97 @@ def testDashPatternOffset(self): s2 = s.clone() self.assertEqual(s2.symbolLayer(0).dashPatternOffset(), 1.2) - self.assertEqual(s2.symbolLayer(0).dashPatternOffsetUnit(), QgsUnitTypes.RenderUnit.RenderPoints) + self.assertEqual( + s2.symbolLayer(0).dashPatternOffsetUnit(), + QgsUnitTypes.RenderUnit.RenderPoints, + ) self.assertEqual(s2.symbolLayer(0).dashPatternOffsetMapUnitScale().minScale, 5) self.assertEqual(s2.symbolLayer(0).dashPatternOffsetMapUnitScale().maxScale, 10) doc = QDomDocument() context = QgsReadWriteContext() - element = QgsSymbolLayerUtils.saveSymbol('test', s, doc, context) + element = QgsSymbolLayerUtils.saveSymbol("test", s, doc, context) s2 = QgsSymbolLayerUtils.loadSymbol(element, context) self.assertEqual(s2.symbolLayer(0).dashPatternOffset(), 1.2) - self.assertEqual(s2.symbolLayer(0).dashPatternOffsetUnit(), QgsUnitTypes.RenderUnit.RenderPoints) + self.assertEqual( + s2.symbolLayer(0).dashPatternOffsetUnit(), + QgsUnitTypes.RenderUnit.RenderPoints, + ) self.assertEqual(s2.symbolLayer(0).dashPatternOffsetMapUnitScale().minScale, 5) self.assertEqual(s2.symbolLayer(0).dashPatternOffsetMapUnitScale().maxScale, 10) def testDashPatternOffsetRender(self): # rendering test - s = QgsLineSymbol.createSimple({'outline_color': '#ff0000', 'outline_width': '2'}) + s = QgsLineSymbol.createSimple( + {"outline_color": "#ff0000", "outline_width": "2"} + ) s.symbolLayer(0).setPenStyle(Qt.PenStyle.DashDotDotLine) s.symbolLayer(0).setDashPatternOffset(10) s.symbolLayer(0).setDashPatternOffsetUnit(QgsUnitTypes.RenderUnit.RenderPoints) - g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10, 0 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 0, 10 10, 0 10)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'simpleline_dashpattern_offset', - 'simpleline_dashpattern_offset', + "simpleline_dashpattern_offset", + "simpleline_dashpattern_offset", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def testDashPatternOffsetRenderNegative(self): # rendering test - s = QgsLineSymbol.createSimple({'outline_color': '#ff0000', 'outline_width': '2'}) + s = QgsLineSymbol.createSimple( + {"outline_color": "#ff0000", "outline_width": "2"} + ) s.symbolLayer(0).setPenStyle(Qt.PenStyle.DashDotDotLine) s.symbolLayer(0).setDashPatternOffset(-10) s.symbolLayer(0).setDashPatternOffsetUnit(QgsUnitTypes.RenderUnit.RenderPoints) - g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10, 0 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 0, 10 10, 0 10)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'simpleline_dashpattern_offset_negative', - 'simpleline_dashpattern_offset_negative', + "simpleline_dashpattern_offset_negative", + "simpleline_dashpattern_offset_negative", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def testDashPatternOffsetRenderCustomPattern(self): # rendering test - s = QgsLineSymbol.createSimple({'outline_color': '#ff0000', 'outline_width': '2'}) + s = QgsLineSymbol.createSimple( + {"outline_color": "#ff0000", "outline_width": "2"} + ) s.symbolLayer(0).setUseCustomDashPattern(True) s.symbolLayer(0).setPenCapStyle(Qt.PenCapStyle.FlatCap) s.symbolLayer(0).setCustomDashVector([3, 4, 5, 6]) s.symbolLayer(0).setDashPatternOffset(10) - g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10, 0 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 10 0, 10 10, 0 10)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'simpleline_dashpattern_offset_custom', - 'simpleline_dashpattern_offset_custom', + "simpleline_dashpattern_offset_custom", + "simpleline_dashpattern_offset_custom", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def testDashTweaks(self): - s = QgsLineSymbol.createSimple({'outline_color': '#ff0000', 'outline_width': '0.6'}) + s = QgsLineSymbol.createSimple( + {"outline_color": "#ff0000", "outline_width": "0.6"} + ) self.assertFalse(s.symbolLayer(0).alignDashPattern()) self.assertFalse(s.symbolLayer(0).tweakDashPatternOnCorners()) @@ -286,7 +342,7 @@ def testDashTweaks(self): doc = QDomDocument() context = QgsReadWriteContext() - element = QgsSymbolLayerUtils.saveSymbol('test', s, doc, context) + element = QgsSymbolLayerUtils.saveSymbol("test", s, doc, context) s2 = QgsSymbolLayerUtils.loadSymbol(element, context) self.assertTrue(s2.symbolLayer(0).alignDashPattern()) @@ -294,73 +350,90 @@ def testDashTweaks(self): def testAlignDashRender(self): # rendering test - s = QgsLineSymbol.createSimple({'outline_color': '#ff0000', 'outline_width': '2'}) + s = QgsLineSymbol.createSimple( + {"outline_color": "#ff0000", "outline_width": "2"} + ) s.symbolLayer(0).setPenStyle(Qt.PenStyle.DashDotDotLine) s.symbolLayer(0).setAlignDashPattern(True) - g = QgsGeometry.fromWkt('LineString(0 0, 9.2 0, 9.2 10, 1.3 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 9.2 0, 9.2 10, 1.3 10)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'simpleline_aligndashpattern', - 'simpleline_aligndashpattern', + "simpleline_aligndashpattern", + "simpleline_aligndashpattern", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def testDashCornerTweakDashRender(self): # rendering test - s = QgsLineSymbol.createSimple({'outline_color': '#ff0000', 'outline_width': '2'}) + s = QgsLineSymbol.createSimple( + {"outline_color": "#ff0000", "outline_width": "2"} + ) s.symbolLayer(0).setPenStyle(Qt.PenStyle.DashDotDotLine) s.symbolLayer(0).setAlignDashPattern(True) s.symbolLayer(0).setTweakDashPatternOnCorners(True) s.symbolLayer(0).setPenJoinStyle(Qt.PenJoinStyle.RoundJoin) - g = QgsGeometry.fromWkt('LineString(0 0, 2 1, 3 1, 10 0, 10 10, 5 5)') + g = QgsGeometry.fromWkt("LineString(0 0, 2 1, 3 1, 10 0, 10 10, 5 5)") rendered_image = self.renderGeometry(s, g) self.assertTrue( self.image_check( - 'simpleline_dashcornertweak', - 'simpleline_dashcornertweak', + "simpleline_dashcornertweak", + "simpleline_dashcornertweak", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def testAlignDashRenderSmallWidth(self): # rendering test - s = QgsLineSymbol.createSimple({'outline_color': '#ff0000', 'outline_width': '0.1'}) + s = QgsLineSymbol.createSimple( + {"outline_color": "#ff0000", "outline_width": "0.1"} + ) s.symbolLayer(0).setPenStyle(Qt.PenStyle.DashDotDotLine) s.symbolLayer(0).setAlignDashPattern(True) - g = QgsGeometry.fromWkt('LineString(0 0, 9.2 0, 9.2 10, 1.3 10)') + g = QgsGeometry.fromWkt("LineString(0 0, 9.2 0, 9.2 10, 1.3 10)") rendered_image = self.renderGeometry(s, g) - self.assertTrue(self.image_check('simpleline_aligndashpattern_small_width', 'simpleline_aligndashpattern_small_width', rendered_image)) + self.assertTrue( + self.image_check( + "simpleline_aligndashpattern_small_width", + "simpleline_aligndashpattern_small_width", + rendered_image, + ) + ) def testRingNumberVariable(self): # test test geometry_ring_num variable s3 = QgsFillSymbol() s3.deleteSymbolLayer(0) - s3.appendSymbolLayer( - QgsSimpleLineSymbolLayer(color=QColor(255, 0, 0), width=2)) - s3.symbolLayer(0).setDataDefinedProperty(QgsSymbolLayer.Property.PropertyStrokeColor, - QgsProperty.fromExpression('case when @geometry_ring_num=0 then \'green\' when @geometry_ring_num=1 then \'blue\' when @geometry_ring_num=2 then \'red\' end')) + s3.appendSymbolLayer(QgsSimpleLineSymbolLayer(color=QColor(255, 0, 0), width=2)) + s3.symbolLayer(0).setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyStrokeColor, + QgsProperty.fromExpression( + "case when @geometry_ring_num=0 then 'green' when @geometry_ring_num=1 then 'blue' when @geometry_ring_num=2 then 'red' end" + ), + ) - g = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))') + g = QgsGeometry.fromWkt( + "Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))" + ) rendered_image = self.renderGeometry(s3, g) self.assertTrue( self.image_check( - 'simpleline_ring_num', - 'simpleline_ring_num', + "simpleline_ring_num", + "simpleline_ring_num", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -369,62 +442,85 @@ def testRingFilter(self): s = QgsFillSymbol() s.deleteSymbolLayer(0) - s.appendSymbolLayer( - QgsSimpleLineSymbolLayer(color=QColor(255, 0, 0), width=2)) - self.assertEqual(s.symbolLayer(0).ringFilter(), QgsLineSymbolLayer.RenderRingFilter.AllRings) - s.symbolLayer(0).setRingFilter(QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly) - self.assertEqual(s.symbolLayer(0).ringFilter(), QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly) + s.appendSymbolLayer(QgsSimpleLineSymbolLayer(color=QColor(255, 0, 0), width=2)) + self.assertEqual( + s.symbolLayer(0).ringFilter(), QgsLineSymbolLayer.RenderRingFilter.AllRings + ) + s.symbolLayer(0).setRingFilter( + QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly + ) + self.assertEqual( + s.symbolLayer(0).ringFilter(), + QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly, + ) s2 = s.clone() - self.assertEqual(s2.symbolLayer(0).ringFilter(), QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly) + self.assertEqual( + s2.symbolLayer(0).ringFilter(), + QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly, + ) doc = QDomDocument() context = QgsReadWriteContext() - element = QgsSymbolLayerUtils.saveSymbol('test', s, doc, context) + element = QgsSymbolLayerUtils.saveSymbol("test", s, doc, context) s2 = QgsSymbolLayerUtils.loadSymbol(element, context) - self.assertEqual(s2.symbolLayer(0).ringFilter(), QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly) + self.assertEqual( + s2.symbolLayer(0).ringFilter(), + QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly, + ) # rendering test s3 = QgsFillSymbol() s3.deleteSymbolLayer(0) - s3.appendSymbolLayer( - QgsSimpleLineSymbolLayer(color=QColor(255, 0, 0), width=2)) - s3.symbolLayer(0).setRingFilter(QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly) + s3.appendSymbolLayer(QgsSimpleLineSymbolLayer(color=QColor(255, 0, 0), width=2)) + s3.symbolLayer(0).setRingFilter( + QgsLineSymbolLayer.RenderRingFilter.ExteriorRingOnly + ) - g = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))') + g = QgsGeometry.fromWkt( + "Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))" + ) rendered_image = self.renderGeometry(s3, g) self.assertTrue( self.image_check( - 'simpleline_exterioronly', - 'simpleline_exterioronly', + "simpleline_exterioronly", + "simpleline_exterioronly", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) - s3.symbolLayer(0).setRingFilter(QgsLineSymbolLayer.RenderRingFilter.InteriorRingsOnly) - g = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))') + s3.symbolLayer(0).setRingFilter( + QgsLineSymbolLayer.RenderRingFilter.InteriorRingsOnly + ) + g = QgsGeometry.fromWkt( + "Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))" + ) rendered_image = self.renderGeometry(s3, g) self.assertTrue( self.image_check( - 'simpleline_interioronly', - 'simpleline_interioronly', + "simpleline_interioronly", + "simpleline_interioronly", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def testOpacityWithDataDefinedColor(self): - line_shp = os.path.join(TEST_DATA_DIR, 'lines.shp') - line_layer = QgsVectorLayer(line_shp, 'Lines', 'ogr') + line_shp = os.path.join(TEST_DATA_DIR, "lines.shp") + line_layer = QgsVectorLayer(line_shp, "Lines", "ogr") self.assertTrue(line_layer.isValid()) - s = QgsLineSymbol.createSimple({'outline_color': '#ff0000', 'outline_width': '2'}) - s.symbolLayer(0).setDataDefinedProperty(QgsSymbolLayer.Property.PropertyStrokeColor, QgsProperty.fromExpression( - "if(Name='Arterial', 'red', 'green')")) + s = QgsLineSymbol.createSimple( + {"outline_color": "#ff0000", "outline_width": "2"} + ) + s.symbolLayer(0).setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyStrokeColor, + QgsProperty.fromExpression("if(Name='Arterial', 'red', 'green')"), + ) s.setOpacity(0.5) @@ -439,21 +535,27 @@ def testOpacityWithDataDefinedColor(self): # Test rendering self.assertTrue( self.render_map_settings_check( - 'simpleline_opacityddcolor', - 'simpleline_opacityddcolor', - ms) + "simpleline_opacityddcolor", "simpleline_opacityddcolor", ms + ) ) def testDataDefinedOpacity(self): - line_shp = os.path.join(TEST_DATA_DIR, 'lines.shp') - line_layer = QgsVectorLayer(line_shp, 'Lines', 'ogr') + line_shp = os.path.join(TEST_DATA_DIR, "lines.shp") + line_layer = QgsVectorLayer(line_shp, "Lines", "ogr") self.assertTrue(line_layer.isValid()) - s = QgsLineSymbol.createSimple({'outline_color': '#ff0000', 'outline_width': '2'}) - s.symbolLayer(0).setDataDefinedProperty(QgsSymbolLayer.Property.PropertyStrokeColor, QgsProperty.fromExpression( - "if(Name='Arterial', 'red', 'green')")) + s = QgsLineSymbol.createSimple( + {"outline_color": "#ff0000", "outline_width": "2"} + ) + s.symbolLayer(0).setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyStrokeColor, + QgsProperty.fromExpression("if(Name='Arterial', 'red', 'green')"), + ) - s.setDataDefinedProperty(QgsSymbol.Property.PropertyOpacity, QgsProperty.fromExpression("if(\"Value\" = 1, 25, 50)")) + s.setDataDefinedProperty( + QgsSymbol.Property.PropertyOpacity, + QgsProperty.fromExpression('if("Value" = 1, 25, 50)'), + ) line_layer.setRenderer(QgsSingleSymbolRenderer(s)) @@ -466,9 +568,8 @@ def testDataDefinedOpacity(self): # Test rendering self.assertTrue( self.render_map_settings_check( - 'simpleline_ddopacity', - 'simpleline_ddopacity', - ms) + "simpleline_ddopacity", "simpleline_ddopacity", ms + ) ) def renderGeometry(self, symbol, geom): @@ -504,5 +605,5 @@ def renderGeometry(self, symbol, geom): return image -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssinglebandcolordatarenderer.py b/tests/src/python/test_qgssinglebandcolordatarenderer.py index 42fd44063c00..c93130ec19c8 100644 --- a/tests/src/python/test_qgssinglebandcolordatarenderer.py +++ b/tests/src/python/test_qgssinglebandcolordatarenderer.py @@ -29,12 +29,11 @@ class TestQgsSingleBandColorDataRenderer(QgisTestCase): def test_renderer(self): - path = os.path.join(unitTestDataPath(), - 'landsat.tif') + path = os.path.join(unitTestDataPath(), "landsat.tif") info = QFileInfo(path) base_name = info.baseName() layer = QgsRasterLayer(path, base_name) - self.assertTrue(layer.isValid(), f'Raster not loaded: {path}') + self.assertTrue(layer.isValid(), f"Raster not loaded: {path}") renderer = QgsSingleBandColorDataRenderer(layer.dataProvider(), 1) @@ -60,5 +59,5 @@ def test_singleband_invalid_layer(self): self.assertEqual(renderer.inputBand(), 10) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssinglebandgrayrenderer.py b/tests/src/python/test_qgssinglebandgrayrenderer.py index e82e1335492e..fade3f4c2b6b 100644 --- a/tests/src/python/test_qgssinglebandgrayrenderer.py +++ b/tests/src/python/test_qgssinglebandgrayrenderer.py @@ -29,15 +29,13 @@ class TestQgsSingleBandGrayRenderer(QgisTestCase): def test_renderer(self): - path = os.path.join(unitTestDataPath(), - 'landsat.tif') + path = os.path.join(unitTestDataPath(), "landsat.tif") info = QFileInfo(path) base_name = info.baseName() layer = QgsRasterLayer(path, base_name) - self.assertTrue(layer.isValid(), f'Raster not loaded: {path}') + self.assertTrue(layer.isValid(), f"Raster not loaded: {path}") - renderer = QgsSingleBandGrayRenderer(layer.dataProvider(), - 1) + renderer = QgsSingleBandGrayRenderer(layer.dataProvider(), 1) self.assertEqual(renderer.inputBand(), 1) @@ -52,8 +50,7 @@ def test_invalid_layer(self): """ Test gray renderer band with a broken layer path """ - renderer = QgsSingleBandGrayRenderer(None, - 11) + renderer = QgsSingleBandGrayRenderer(None, 11) self.assertEqual(renderer.inputBand(), 11) @@ -62,5 +59,5 @@ def test_invalid_layer(self): self.assertEqual(renderer.inputBand(), 10) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssinglebandpseudocolorrenderer.py b/tests/src/python/test_qgssinglebandpseudocolorrenderer.py index 98c7a95bbc6e..3d435957a3f9 100644 --- a/tests/src/python/test_qgssinglebandpseudocolorrenderer.py +++ b/tests/src/python/test_qgssinglebandpseudocolorrenderer.py @@ -29,15 +29,13 @@ class TestQgsSingleBandPseudoColorRenderer(QgisTestCase): def test_renderer(self): - path = os.path.join(unitTestDataPath(), - 'landsat.tif') + path = os.path.join(unitTestDataPath(), "landsat.tif") info = QFileInfo(path) base_name = info.baseName() layer = QgsRasterLayer(path, base_name) - self.assertTrue(layer.isValid(), f'Raster not loaded: {path}') + self.assertTrue(layer.isValid(), f"Raster not loaded: {path}") - renderer = QgsSingleBandPseudoColorRenderer(layer.dataProvider(), - 1) + renderer = QgsSingleBandPseudoColorRenderer(layer.dataProvider(), 1) self.assertEqual(renderer.inputBand(), 1) @@ -52,8 +50,7 @@ def test_invalid_layer(self): """ Test renderer band with a broken layer path """ - renderer = QgsSingleBandPseudoColorRenderer(None, - 11) + renderer = QgsSingleBandPseudoColorRenderer(None, 11) self.assertEqual(renderer.inputBand(), 11) @@ -62,5 +59,5 @@ def test_invalid_layer(self): self.assertEqual(renderer.inputBand(), 10) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssingleitemmodel.py b/tests/src/python/test_qgssingleitemmodel.py index d9f29901f279..317f011296c4 100644 --- a/tests/src/python/test_qgssingleitemmodel.py +++ b/tests/src/python/test_qgssingleitemmodel.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '28/3/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "28/3/2022" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.PyQt.QtCore import Qt from qgis.PyQt.QtGui import QColor @@ -21,59 +22,89 @@ class TestQgsSingleItemModel(QgisTestCase): def testModel(self): - model = QgsSingleItemModel(None, 'my item', { - Qt.ItemDataRole.ForegroundRole: QColor(255, 0, 0), - Qt.ItemDataRole.BackgroundRole: QColor(0, 255, 0), - Qt.ItemDataRole.UserRole + 123: 'abc' - }, Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsDropEnabled) + model = QgsSingleItemModel( + None, + "my item", + { + Qt.ItemDataRole.ForegroundRole: QColor(255, 0, 0), + Qt.ItemDataRole.BackgroundRole: QColor(0, 255, 0), + Qt.ItemDataRole.UserRole + 123: "abc", + }, + Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsDropEnabled, + ) self.assertEqual(model.rowCount(), 1) self.assertEqual(model.columnCount(), 1) index = model.index(0, 0) - self.assertEqual(model.data(index, Qt.ItemDataRole.DisplayRole), 'my item') + self.assertEqual(model.data(index, Qt.ItemDataRole.DisplayRole), "my item") # by default tooltip should follow item text - self.assertEqual(model.data(index, Qt.ItemDataRole.ToolTipRole), 'my item') - self.assertEqual(model.data(index, Qt.ItemDataRole.ForegroundRole), QColor(255, 0, 0)) - self.assertEqual(model.data(index, Qt.ItemDataRole.BackgroundRole), QColor(0, 255, 0)) - self.assertEqual(model.data(index, Qt.ItemDataRole.BackgroundRole), QColor(0, 255, 0)) - self.assertEqual(model.data(index, Qt.ItemDataRole.UserRole + 123), 'abc') + self.assertEqual(model.data(index, Qt.ItemDataRole.ToolTipRole), "my item") + self.assertEqual( + model.data(index, Qt.ItemDataRole.ForegroundRole), QColor(255, 0, 0) + ) + self.assertEqual( + model.data(index, Qt.ItemDataRole.BackgroundRole), QColor(0, 255, 0) + ) + self.assertEqual( + model.data(index, Qt.ItemDataRole.BackgroundRole), QColor(0, 255, 0) + ) + self.assertEqual(model.data(index, Qt.ItemDataRole.UserRole + 123), "abc") self.assertIsNone(model.data(index, Qt.ItemDataRole.UserRole + 124)) - self.assertEqual(model.flags(index), Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsDropEnabled) + self.assertEqual( + model.flags(index), + Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsDropEnabled, + ) def testToolTip(self): - model = QgsSingleItemModel(None, 'my item', { - Qt.ItemDataRole.ToolTipRole: 'abc' - }, Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsDropEnabled) + model = QgsSingleItemModel( + None, + "my item", + {Qt.ItemDataRole.ToolTipRole: "abc"}, + Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsDropEnabled, + ) index = model.index(0, 0) - self.assertEqual(model.data(index, Qt.ItemDataRole.DisplayRole), 'my item') + self.assertEqual(model.data(index, Qt.ItemDataRole.DisplayRole), "my item") # manually specified tooltip should take precedence - self.assertEqual(model.data(index, Qt.ItemDataRole.ToolTipRole), 'abc') + self.assertEqual(model.data(index, Qt.ItemDataRole.ToolTipRole), "abc") def testModelWithColumns(self): - model = QgsSingleItemModel(None, [ - {Qt.ItemDataRole.DisplayRole: 'col 1', Qt.ItemDataRole.ToolTipRole: 'column 1'}, - {Qt.ItemDataRole.DisplayRole: 'col 2', Qt.ItemDataRole.ToolTipRole: 'column 2'}, - {Qt.ItemDataRole.DisplayRole: 'col 3'}, - ], Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsDropEnabled) + model = QgsSingleItemModel( + None, + [ + { + Qt.ItemDataRole.DisplayRole: "col 1", + Qt.ItemDataRole.ToolTipRole: "column 1", + }, + { + Qt.ItemDataRole.DisplayRole: "col 2", + Qt.ItemDataRole.ToolTipRole: "column 2", + }, + {Qt.ItemDataRole.DisplayRole: "col 3"}, + ], + Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsDropEnabled, + ) self.assertEqual(model.rowCount(), 1) self.assertEqual(model.columnCount(), 3) index = model.index(0, 0) - self.assertEqual(model.data(index, Qt.ItemDataRole.DisplayRole), 'col 1') - self.assertEqual(model.data(index, Qt.ItemDataRole.ToolTipRole), 'column 1') + self.assertEqual(model.data(index, Qt.ItemDataRole.DisplayRole), "col 1") + self.assertEqual(model.data(index, Qt.ItemDataRole.ToolTipRole), "column 1") index = model.index(0, 1) - self.assertEqual(model.data(index, Qt.ItemDataRole.DisplayRole), 'col 2') - self.assertEqual(model.data(index, Qt.ItemDataRole.ToolTipRole), 'column 2') + self.assertEqual(model.data(index, Qt.ItemDataRole.DisplayRole), "col 2") + self.assertEqual(model.data(index, Qt.ItemDataRole.ToolTipRole), "column 2") index = model.index(0, 2) - self.assertEqual(model.data(index, Qt.ItemDataRole.DisplayRole), 'col 3') + self.assertEqual(model.data(index, Qt.ItemDataRole.DisplayRole), "col 3") self.assertFalse(model.data(index, Qt.ItemDataRole.ToolTipRole)) - self.assertEqual(model.flags(index), Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsDropEnabled) + self.assertEqual( + model.flags(index), + Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsDropEnabled, + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssinglesymbolrenderer.py b/tests/src/python/test_qgssinglesymbolrenderer.py index e694f51ccf91..9eab10ecdc51 100644 --- a/tests/src/python/test_qgssinglesymbolrenderer.py +++ b/tests/src/python/test_qgssinglesymbolrenderer.py @@ -18,9 +18,9 @@ """ -__author__ = 'Matthias Kuhn' -__date__ = 'December 2015' -__copyright__ = '(C) 2015, Matthias Kuhn' +__author__ = "Matthias Kuhn" +__date__ = "December 2015" +__copyright__ = "(C) 2015, Matthias Kuhn" import os @@ -48,12 +48,14 @@ class TestQgsSingleSymbolRenderer(QgisTestCase): def setUp(self): self.iface = get_iface() - myShpFile = os.path.join(TEST_DATA_DIR, 'polys_overlapping.shp') - layer = QgsVectorLayer(myShpFile, 'Polys', 'ogr') + myShpFile = os.path.join(TEST_DATA_DIR, "polys_overlapping.shp") + layer = QgsVectorLayer(myShpFile, "Polys", "ogr") QgsProject.instance().addMapLayer(layer) # Create rulebased style - sym1 = QgsFillSymbol.createSimple({'color': '#fdbf6f', 'outline_color': 'black'}) + sym1 = QgsFillSymbol.createSimple( + {"color": "#fdbf6f", "outline_color": "black"} + ) self.renderer = QgsSingleSymbolRenderer(sym1) layer.setRenderer(self.renderer) @@ -66,24 +68,24 @@ def setUp(self): self.mapsettings.setLayers(rendered_layers) def testOrderBy(self): - self.renderer.setOrderBy(QgsFeatureRequest.OrderBy([QgsFeatureRequest.OrderByClause('Value', False)])) + self.renderer.setOrderBy( + QgsFeatureRequest.OrderBy([QgsFeatureRequest.OrderByClause("Value", False)]) + ) self.renderer.setOrderByEnabled(True) # Setup rendering check self.assertTrue( self.render_map_settings_check( - 'singlesymbol_orderby', - 'singlesymbol_orderby', - self.mapsettings) + "singlesymbol_orderby", "singlesymbol_orderby", self.mapsettings + ) ) # disable order by and retest self.renderer.setOrderByEnabled(False) self.assertTrue( self.render_map_settings_check( - 'singlesymbol_noorderby', - 'singlesymbol_noorderby', - self.mapsettings) + "singlesymbol_noorderby", "singlesymbol_noorderby", self.mapsettings + ) ) def testUsedAttributes(self): @@ -92,22 +94,26 @@ def testUsedAttributes(self): self.assertCountEqual(self.renderer.usedAttributes(ctx), {}) def test_legend_keys(self): - sym1 = QgsFillSymbol.createSimple({'color': '#fdbf6f', 'outline_color': 'black'}) + sym1 = QgsFillSymbol.createSimple( + {"color": "#fdbf6f", "outline_color": "black"} + ) renderer = QgsSingleSymbolRenderer(sym1) - self.assertEqual(renderer.legendKeys(), {'0'}) + self.assertEqual(renderer.legendKeys(), {"0"}) def test_legend_key_to_expression(self): - sym1 = QgsFillSymbol.createSimple({'color': '#fdbf6f', 'outline_color': 'black'}) + sym1 = QgsFillSymbol.createSimple( + {"color": "#fdbf6f", "outline_color": "black"} + ) renderer = QgsSingleSymbolRenderer(sym1) - exp, ok = renderer.legendKeyToExpression('0', None) + exp, ok = renderer.legendKeyToExpression("0", None) self.assertTrue(ok) - self.assertEqual(exp, 'TRUE') + self.assertEqual(exp, "TRUE") - exp, ok = renderer.legendKeyToExpression('xxxx', None) + exp, ok = renderer.legendKeyToExpression("xxxx", None) self.assertFalse(ok) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssourceselectprovider.py b/tests/src/python/test_qgssourceselectprovider.py index 276111cad5d7..0a3d26942ed1 100644 --- a/tests/src/python/test_qgssourceselectprovider.py +++ b/tests/src/python/test_qgssourceselectprovider.py @@ -25,9 +25,9 @@ from qgis.testing import start_app, QgisTestCase from utilities import unitTestDataPath -__author__ = 'Alessandro Pasotti' -__date__ = '01/09/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' +__author__ = "Alessandro Pasotti" +__date__ = "01/09/2017" +__copyright__ = "Copyright 2017, The QGIS Project" class ConcreteDataSourceWidget(QgsAbstractDataSourceWidget): @@ -110,45 +110,77 @@ def _testRegistry(self, registry): registry.addProvider(ConcreteSourceSelectProvider2()) # Check order - self.assertEqual(['MyTestProviderKey', 'MyName'], - [p.name() for p in registry.providers() if p.providerKey().startswith('MyTestProviderKey')]) + self.assertEqual( + ["MyTestProviderKey", "MyName"], + [ + p.name() + for p in registry.providers() + if p.providerKey().startswith("MyTestProviderKey") + ], + ) registry = QgsSourceSelectProviderRegistry() registry.addProvider(ConcreteSourceSelectProvider()) registry.addProvider(ConcreteSourceSelectProvider2()) # Check order - self.assertEqual(['MyTestProviderKey', 'MyName'], - [p.name() for p in registry.providers() if p.providerKey().startswith('MyTestProviderKey')]) + self.assertEqual( + ["MyTestProviderKey", "MyName"], + [ + p.name() + for p in registry.providers() + if p.providerKey().startswith("MyTestProviderKey") + ], + ) # Get provider by name - self.assertTrue(registry.providerByName('MyTestProviderKey')) - self.assertTrue(registry.providerByName('MyName')) + self.assertTrue(registry.providerByName("MyTestProviderKey")) + self.assertTrue(registry.providerByName("MyName")) # Get not existent by name - self.assertFalse(registry.providerByName('Oh This Is Missing!')) + self.assertFalse(registry.providerByName("Oh This Is Missing!")) # Get providers by data provider key - self.assertGreater(len(registry.providersByKey('MyTestProviderKey')), 0) - self.assertGreater(len(registry.providersByKey('MyTestProviderKey2')), 0) + self.assertGreater(len(registry.providersByKey("MyTestProviderKey")), 0) + self.assertGreater(len(registry.providersByKey("MyTestProviderKey2")), 0) # Get not existent by key - self.assertEqual(len(registry.providersByKey('Oh This Is Missing!')), 0) + self.assertEqual(len(registry.providersByKey("Oh This Is Missing!")), 0) def testRemoveProvider(self): registry = QgsSourceSelectProviderRegistry() registry.addProvider(ConcreteSourceSelectProvider()) registry.addProvider(ConcreteSourceSelectProvider2()) - self.assertEqual(['MyTestProviderKey', 'MyName'], - [p.name() for p in registry.providers() if p.providerKey().startswith('MyTestProviderKey')]) - - self.assertTrue(registry.removeProvider(registry.providerByName('MyName'))) - self.assertEqual(['MyTestProviderKey'], - [p.name() for p in registry.providers() if p.providerKey().startswith('MyTestProviderKey')]) - - self.assertTrue(registry.removeProvider(registry.providerByName('MyTestProviderKey'))) - self.assertEqual([], - [p.name() for p in registry.providers() if p.providerKey().startswith('MyTestProviderKey')]) + self.assertEqual( + ["MyTestProviderKey", "MyName"], + [ + p.name() + for p in registry.providers() + if p.providerKey().startswith("MyTestProviderKey") + ], + ) + + self.assertTrue(registry.removeProvider(registry.providerByName("MyName"))) + self.assertEqual( + ["MyTestProviderKey"], + [ + p.name() + for p in registry.providers() + if p.providerKey().startswith("MyTestProviderKey") + ], + ) + + self.assertTrue( + registry.removeProvider(registry.providerByName("MyTestProviderKey")) + ) + self.assertEqual( + [], + [ + p.name() + for p in registry.providers() + if p.providerKey().startswith("MyTestProviderKey") + ], + ) def testRegistry(self): registry = QgsSourceSelectProviderRegistry() @@ -158,23 +190,28 @@ def testRegistrySingleton(self): registry = QgsGui.sourceSelectProviderRegistry() self._testRegistry(registry) # Check that at least OGR and GDAL are here - self.assertTrue(registry.providersByKey('ogr')) - self.assertTrue(registry.providersByKey('gdal')) + self.assertTrue(registry.providersByKey("ogr")) + self.assertTrue(registry.providersByKey("gdal")) def testSourceSelectProvidersConfigureFromUri(self): """ Test configure from URI """ registry = QgsGui.sourceSelectProviderRegistry() - enabled_entries = {reg_entry.name(): reg_entry for reg_entry in registry.providers() if reg_entry.capabilities() & QgsSourceSelectProvider.Capability.ConfigureFromUri} - self.assertIn('ogr', enabled_entries.keys()) - self.assertIn('gdal', enabled_entries.keys()) - self.assertIn('GeoPackage', enabled_entries.keys()) - self.assertIn('spatialite', enabled_entries.keys()) + enabled_entries = { + reg_entry.name(): reg_entry + for reg_entry in registry.providers() + if reg_entry.capabilities() + & QgsSourceSelectProvider.Capability.ConfigureFromUri + } + self.assertIn("ogr", enabled_entries.keys()) + self.assertIn("gdal", enabled_entries.keys()) + self.assertIn("GeoPackage", enabled_entries.keys()) + self.assertIn("spatialite", enabled_entries.keys()) # Test ogr - test_path = os.path.join(unitTestDataPath(), 'points.shp') - source_select = enabled_entries['ogr'].createDataSourceWidget() + test_path = os.path.join(unitTestDataPath(), "points.shp") + source_select = enabled_entries["ogr"].createDataSourceWidget() self.assertTrue(source_select.configureFromUri(test_path)) spy = QSignalSpy(source_select.addVectorLayers) source_select.addButtonClicked() @@ -183,8 +220,8 @@ def testSourceSelectProvidersConfigureFromUri(self): self.assertEqual(arg_path[0], test_path) # Test GDAL - test_path = os.path.join(unitTestDataPath(), 'raster_layer.tiff') - source_select = enabled_entries['gdal'].createDataSourceWidget() + test_path = os.path.join(unitTestDataPath(), "raster_layer.tiff") + source_select = enabled_entries["gdal"].createDataSourceWidget() spy = QSignalSpy(source_select.addRasterLayers) self.assertTrue(source_select.configureFromUri(test_path)) source_select.addButtonClicked() @@ -193,25 +230,27 @@ def testSourceSelectProvidersConfigureFromUri(self): self.assertEqual(arg_path[0], test_path) # Test vector GPKG - test_path = os.path.join(unitTestDataPath(), 'mixed_layers.gpkg|layername=points') - source_select = enabled_entries['GeoPackage'].createDataSourceWidget() + test_path = os.path.join( + unitTestDataPath(), "mixed_layers.gpkg|layername=points" + ) + source_select = enabled_entries["GeoPackage"].createDataSourceWidget() self.assertTrue(source_select.configureFromUri(test_path)) spy = QSignalSpy(source_select.addLayer) source_select.addButtonClicked() self.assertEqual(len(spy), 1) _, arg_path, arg_name, arg_key = spy[0] self.assertEqual(arg_path, test_path) - self.assertEqual(arg_name, 'points') - self.assertEqual(arg_key, 'ogr') + self.assertEqual(arg_name, "points") + self.assertEqual(arg_key, "ogr") # Test vector spatialite - test_path = os.path.join(unitTestDataPath(), 'provider', 'spatialite.db') + test_path = os.path.join(unitTestDataPath(), "provider", "spatialite.db") uri = QgsDataSourceUri() uri.setDatabase(test_path) - uri.setTable('some data') - uri.setGeometryColumn('geom') - uri.setSql('pk > 0') - source_select = enabled_entries['spatialite'].createDataSourceWidget() + uri.setTable("some data") + uri.setGeometryColumn("geom") + uri.setSql("pk > 0") + source_select = enabled_entries["spatialite"].createDataSourceWidget() self.assertTrue(source_select.configureFromUri(uri.uri())) spy = QSignalSpy(source_select.addDatabaseLayers) source_select.addButtonClicked() @@ -220,5 +259,5 @@ def testSourceSelectProvidersConfigureFromUri(self): self.assertEqual(arg_tables[0], uri.uri()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssourcewidgetproviderregistry.py b/tests/src/python/test_qgssourcewidgetproviderregistry.py index a7ac6bf381d5..a4f9a80375a4 100644 --- a/tests/src/python/test_qgssourcewidgetproviderregistry.py +++ b/tests/src/python/test_qgssourcewidgetproviderregistry.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '23/12/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "23/12/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.core import QgsVectorLayer @@ -32,7 +33,7 @@ def setSourceUri(self, uri): pass def sourceUri(self): - return '' + return "" class TestProvider(QgsProviderSourceWidgetProvider): @@ -61,29 +62,29 @@ def testRegistry(self): registry = QgsGui.sourceWidgetProviderRegistry() initial_providers = registry.providers() self.assertTrue(initial_providers) # we expect a bunch of default providers - self.assertTrue([p.name() for p in initial_providers if p.name() == 'xyz']) + self.assertTrue([p.name() for p in initial_providers if p.name() == "xyz"]) # add a new provider - p1 = TestProvider('p1') + p1 = TestProvider("p1") registry.addProvider(p1) self.assertIn(p1, registry.providers()) - p2 = TestProvider('p2') + p2 = TestProvider("p2") registry.addProvider(p2) self.assertIn(p1, registry.providers()) self.assertIn(p2, registry.providers()) registry.removeProvider(None) - p3 = TestProvider('p3') + p3 = TestProvider("p3") # not in registry yet registry.removeProvider(p3) registry.removeProvider(p1) - self.assertNotIn('p1', [p.name() for p in registry.providers()]) + self.assertNotIn("p1", [p.name() for p in registry.providers()]) self.assertIn(p2, registry.providers()) registry.removeProvider(p2) - self.assertNotIn('p2', [p.name() for p in registry.providers()]) + self.assertNotIn("p2", [p.name() for p in registry.providers()]) self.assertEqual(registry.providers(), initial_providers) def testProviderKey(self): @@ -91,27 +92,29 @@ def testProviderKey(self): registry = QgsGui.sourceWidgetProviderRegistry() # self.assertIsNotNone(registry.providerByName('WFS')) - self.assertIsNone(registry.providerByName('i_do_not_exist')) - self.assertEqual(registry.providerByName('gdal').providerKey(), 'gdal') + self.assertIsNone(registry.providerByName("i_do_not_exist")) + self.assertEqual(registry.providerByName("gdal").providerKey(), "gdal") def testCreateDialogWithCustomImplementation(self): - """ Tests that createWidget() returns a custom implementation """ + """Tests that createWidget() returns a custom implementation""" registry = QgsGui.sourceWidgetProviderRegistry() - p1 = TestProvider('p1') + p1 = TestProvider("p1") try: registry.addProvider(p1) vl = QgsVectorLayer( - 'Polygon?crs=epsg:4326&field=id:int', - 'layer_for_this_provider', - 'memory') + "Polygon?crs=epsg:4326&field=id:int", + "layer_for_this_provider", + "memory", + ) self.assertIsNotNone(registry.createWidget(vl)) - self.assertEqual(registry.createWidget(vl).objectName(), - TestSourceWidget().objectName()) + self.assertEqual( + registry.createWidget(vl).objectName(), TestSourceWidget().objectName() + ) finally: registry.removeProvider(p1) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsspatialindex.py b/tests/src/python/test_qgsspatialindex.py index 4125743a2862..1fa3da8100c1 100644 --- a/tests/src/python/test_qgsspatialindex.py +++ b/tests/src/python/test_qgsspatialindex.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Alexander Bruy' -__date__ = '20/01/2011' -__copyright__ = 'Copyright 2012, The QGIS Project' + +__author__ = "Alexander Bruy" +__date__ = "20/01/2011" +__copyright__ = "Copyright 2012, The QGIS Project" from qgis.core import ( @@ -41,20 +42,20 @@ def testIndex(self): fids = idx.intersects(rect) myExpectedValue = 4 myValue = len(fids) - myMessage = f'Expected: {myExpectedValue} Got: {myValue}' + myMessage = f"Expected: {myExpectedValue} Got: {myValue}" self.assertEqual(myValue, myExpectedValue, myMessage) fids.sort() - myMessage = f'Expected: {[1, 2, 5, 6]}\nGot: {fids}\n' + myMessage = f"Expected: {[1, 2, 5, 6]}\nGot: {fids}\n" assert fids == [1, 2, 5, 6], myMessage # nearest neighbor test fids = idx.nearestNeighbor(QgsPointXY(8.75, 6.25), 3) myExpectedValue = 0 myValue = len(fids) - myMessage = f'Expected: {myExpectedValue} Got: {myValue}' + myMessage = f"Expected: {myExpectedValue} Got: {myValue}" fids.sort() - myMessage = f'Expected: {[0, 1, 5]}\nGot: {fids}\n' + myMessage = f"Expected: {[0, 1, 5]}\nGot: {fids}\n" assert fids == [0, 1, 5], myMessage def testGetGeometry(self): @@ -80,13 +81,13 @@ def testGetGeometry(self): with self.assertRaises(KeyError): idx.geometry(1000) - self.assertEqual(idx2.geometry(1).asWkt(1), 'Point (11 0)') - self.assertEqual(idx2.geometry(2).asWkt(1), 'Point (12 0)') + self.assertEqual(idx2.geometry(1).asWkt(1), "Point (11 0)") + self.assertEqual(idx2.geometry(2).asWkt(1), "Point (12 0)") with self.assertRaises(KeyError): idx2.geometry(-100) with self.assertRaises(KeyError): idx2.geometry(1000) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssphere.py b/tests/src/python/test_qgssphere.py index bc855d35acd6..5e49dedd2ecb 100644 --- a/tests/src/python/test_qgssphere.py +++ b/tests/src/python/test_qgssphere.py @@ -7,17 +7,13 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2023 by Nyall Dawson' -__date__ = '14/07/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "(C) 2023 by Nyall Dawson" +__date__ = "14/07/2023" +__copyright__ = "Copyright 2023, The QGIS Project" import math -from qgis.core import ( - QgsSphere, - QgsPoint, - QgsCircle, - QgsVector3D -) +from qgis.core import QgsSphere, QgsPoint, QgsCircle, QgsVector3D import unittest from qgis.testing import start_app, QgisTestCase @@ -32,7 +28,7 @@ class TestQgsSphere(QgisTestCase): def test_null(self): sphere = QgsSphere() self.assertTrue(sphere.isNull()) - self.assertEqual(str(sphere), '') + self.assertEqual(str(sphere), "") # a null sphere should also be considered empty self.assertTrue(sphere.isEmpty()) @@ -45,7 +41,7 @@ def test_sphere(self): self.assertEqual(sphere.center(), QgsPoint(1, 2, 3)) self.assertEqual(sphere.centerVector(), QgsVector3D(1, 2, 3)) self.assertEqual(sphere.radius(), 4) - self.assertEqual(str(sphere), '') + self.assertEqual(str(sphere), "") def test_setters(self): sphere = QgsSphere(1, 2, 3, 4) @@ -107,5 +103,5 @@ def test_bounding_box(self): self.assertEqual(box.zMaximum(), 7) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssqlstatement.py b/tests/src/python/test_qgssqlstatement.py index 26b37991144f..b897d003c62b 100644 --- a/tests/src/python/test_qgssqlstatement.py +++ b/tests/src/python/test_qgssqlstatement.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Even Rouault' -__date__ = '4/4/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Even Rouault" +__date__ = "4/4/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.core import QgsSQLStatement, QgsSQLStatementFragment from qgis.testing import unittest @@ -34,20 +35,20 @@ def testNominalSimple(self): self.assertEqual(len(tables), 1) table = tables[0] self.assertEqual(table.nodeType(), QgsSQLStatement.NodeType.ntTableDef) - self.assertEqual(table.name(), 't') - self.assertEqual(table.alias(), '') + self.assertEqual(table.name(), "t") + self.assertEqual(table.alias(), "") columns = statement_node.columns() self.assertEqual(len(columns), 1) column = columns[0] self.assertEqual(column.nodeType(), QgsSQLStatement.NodeType.ntSelectedColumn) column_ref = column.column() - self.assertEqual(column.alias(), '') + self.assertEqual(column.alias(), "") self.assertEqual(column_ref.nodeType(), QgsSQLStatement.NodeType.ntColumnRef) - self.assertEqual(column_ref.name(), 'a') - self.assertEqual(column_ref.tableName(), '') + self.assertEqual(column_ref.name(), "a") + self.assertEqual(column_ref.tableName(), "") def testNominalSimpleQuoted(self): - statement = "SELECT a FROM \"t\"" + statement = 'SELECT a FROM "t"' self.checkNominal(statement, "SELECT a FROM t") exp = QgsSQLStatement(statement) statement_node = exp.rootNode() @@ -56,17 +57,17 @@ def testNominalSimpleQuoted(self): self.assertEqual(len(tables), 1) table = tables[0] self.assertEqual(table.nodeType(), QgsSQLStatement.NodeType.ntTableDef) - self.assertEqual(table.name(), 't') - self.assertEqual(table.alias(), '') + self.assertEqual(table.name(), "t") + self.assertEqual(table.alias(), "") columns = statement_node.columns() self.assertEqual(len(columns), 1) column = columns[0] self.assertEqual(column.nodeType(), QgsSQLStatement.NodeType.ntSelectedColumn) column_ref = column.column() - self.assertEqual(column.alias(), '') + self.assertEqual(column.alias(), "") self.assertEqual(column_ref.nodeType(), QgsSQLStatement.NodeType.ntColumnRef) - self.assertEqual(column_ref.name(), 'a') - self.assertEqual(column_ref.tableName(), '') + self.assertEqual(column_ref.name(), "a") + self.assertEqual(column_ref.tableName(), "") def testNominalSimpleWithSchema(self): statement = "SELECT a FROM user.mySchema3.tableName" @@ -78,22 +79,22 @@ def testNominalSimpleWithSchema(self): self.assertEqual(len(tables), 1) table = tables[0] self.assertEqual(table.nodeType(), QgsSQLStatement.NodeType.ntTableDef) - self.assertEqual(table.name(), 'tableName') - self.assertEqual(table.schema(), 'user.mySchema3') - self.assertEqual(table.alias(), '') + self.assertEqual(table.name(), "tableName") + self.assertEqual(table.schema(), "user.mySchema3") + self.assertEqual(table.alias(), "") columns = statement_node.columns() self.assertEqual(len(columns), 1) column = columns[0] self.assertEqual(column.nodeType(), QgsSQLStatement.NodeType.ntSelectedColumn) column_ref = column.column() - self.assertEqual(column.alias(), '') + self.assertEqual(column.alias(), "") self.assertEqual(column_ref.nodeType(), QgsSQLStatement.NodeType.ntColumnRef) - self.assertEqual(column_ref.name(), 'a') - self.assertEqual(column_ref.tableName(), '') + self.assertEqual(column_ref.name(), "a") + self.assertEqual(column_ref.tableName(), "") def testNominalSimpleWithSchemaQuoted(self): - statement = "SELECT a FROM \"user\".\"mySchema3\".\"tableName\"" - self.checkNominal(statement, 'SELECT a FROM user.mySchema3.tableName') + statement = 'SELECT a FROM "user"."mySchema3"."tableName"' + self.checkNominal(statement, "SELECT a FROM user.mySchema3.tableName") exp = QgsSQLStatement(statement) statement_node = exp.rootNode() self.assertEqual(statement_node.nodeType(), QgsSQLStatement.NodeType.ntSelect) @@ -101,18 +102,18 @@ def testNominalSimpleWithSchemaQuoted(self): self.assertEqual(len(tables), 1) table = tables[0] self.assertEqual(table.nodeType(), QgsSQLStatement.NodeType.ntTableDef) - self.assertEqual(table.name(), 'tableName') - self.assertEqual(table.schema(), 'user.mySchema3') - self.assertEqual(table.alias(), '') + self.assertEqual(table.name(), "tableName") + self.assertEqual(table.schema(), "user.mySchema3") + self.assertEqual(table.alias(), "") columns = statement_node.columns() self.assertEqual(len(columns), 1) column = columns[0] self.assertEqual(column.nodeType(), QgsSQLStatement.NodeType.ntSelectedColumn) column_ref = column.column() - self.assertEqual(column.alias(), '') + self.assertEqual(column.alias(), "") self.assertEqual(column_ref.nodeType(), QgsSQLStatement.NodeType.ntColumnRef) - self.assertEqual(column_ref.name(), 'a') - self.assertEqual(column_ref.tableName(), '') + self.assertEqual(column_ref.name(), "a") + self.assertEqual(column_ref.tableName(), "") def testNominalSimpleWithAlias(self): statement = "SELECT a FROM tableName AS myTable" @@ -124,17 +125,17 @@ def testNominalSimpleWithAlias(self): self.assertEqual(len(tables), 1) table = tables[0] self.assertEqual(table.nodeType(), QgsSQLStatement.NodeType.ntTableDef) - self.assertEqual(table.name(), 'tableName') - self.assertEqual(table.alias(), 'myTable') + self.assertEqual(table.name(), "tableName") + self.assertEqual(table.alias(), "myTable") columns = statement_node.columns() self.assertEqual(len(columns), 1) column = columns[0] self.assertEqual(column.nodeType(), QgsSQLStatement.NodeType.ntSelectedColumn) column_ref = column.column() - self.assertEqual(column.alias(), '') + self.assertEqual(column.alias(), "") self.assertEqual(column_ref.nodeType(), QgsSQLStatement.NodeType.ntColumnRef) - self.assertEqual(column_ref.name(), 'a') - self.assertEqual(column_ref.tableName(), '') + self.assertEqual(column_ref.name(), "a") + self.assertEqual(column_ref.tableName(), "") def testNominalSimpleWithAliasAndSchema(self): statement = "SELECT a FROM dbo.mySchema.tableName AS myTable" @@ -146,22 +147,22 @@ def testNominalSimpleWithAliasAndSchema(self): self.assertEqual(len(tables), 1) table = tables[0] self.assertEqual(table.nodeType(), QgsSQLStatement.NodeType.ntTableDef) - self.assertEqual(table.name(), 'tableName') - self.assertEqual(table.schema(), 'dbo.mySchema') - self.assertEqual(table.alias(), 'myTable') + self.assertEqual(table.name(), "tableName") + self.assertEqual(table.schema(), "dbo.mySchema") + self.assertEqual(table.alias(), "myTable") columns = statement_node.columns() self.assertEqual(len(columns), 1) column = columns[0] self.assertEqual(column.nodeType(), QgsSQLStatement.NodeType.ntSelectedColumn) column_ref = column.column() - self.assertEqual(column.alias(), '') + self.assertEqual(column.alias(), "") self.assertEqual(column_ref.nodeType(), QgsSQLStatement.NodeType.ntColumnRef) - self.assertEqual(column_ref.name(), 'a') - self.assertEqual(column_ref.tableName(), '') + self.assertEqual(column_ref.name(), "a") + self.assertEqual(column_ref.tableName(), "") def testNominalSimpleWithAliasAndSchemaQuoted(self): - statement = "SELECT a FROM \"dbo\".\"mySchema\".\"tableName\" AS myTable" - self.checkNominal(statement, 'SELECT a FROM dbo.mySchema.tableName AS myTable') + statement = 'SELECT a FROM "dbo"."mySchema"."tableName" AS myTable' + self.checkNominal(statement, "SELECT a FROM dbo.mySchema.tableName AS myTable") exp = QgsSQLStatement(statement) statement_node = exp.rootNode() self.assertEqual(statement_node.nodeType(), QgsSQLStatement.NodeType.ntSelect) @@ -169,18 +170,18 @@ def testNominalSimpleWithAliasAndSchemaQuoted(self): self.assertEqual(len(tables), 1) table = tables[0] self.assertEqual(table.nodeType(), QgsSQLStatement.NodeType.ntTableDef) - self.assertEqual(table.name(), 'tableName') - self.assertEqual(table.schema(), 'dbo.mySchema') - self.assertEqual(table.alias(), 'myTable') + self.assertEqual(table.name(), "tableName") + self.assertEqual(table.schema(), "dbo.mySchema") + self.assertEqual(table.alias(), "myTable") columns = statement_node.columns() self.assertEqual(len(columns), 1) column = columns[0] self.assertEqual(column.nodeType(), QgsSQLStatement.NodeType.ntSelectedColumn) column_ref = column.column() - self.assertEqual(column.alias(), '') + self.assertEqual(column.alias(), "") self.assertEqual(column_ref.nodeType(), QgsSQLStatement.NodeType.ntColumnRef) - self.assertEqual(column_ref.name(), 'a') - self.assertEqual(column_ref.tableName(), '') + self.assertEqual(column_ref.name(), "a") + self.assertEqual(column_ref.tableName(), "") def testNominalSelectDistinct(self): statement = "SELECT DISTINCT a FROM t" @@ -188,22 +189,26 @@ def testNominalSelectDistinct(self): def testNominalColumns(self): statement = "SELECT null, 1234567890123456789, a, b b_alias, 'literal', CAST(1 AS varchar), " - statement += "\"1c\", *, \"*\", a.*, foo(), bar(baz, baw), t.c AS \"1quoted\", " - statement += "COUNT(*), COUNT(*) a, COUNT(DISTINCT x), COUNT(DISTINCT x) AS a, \"select\" FROM t" + statement += '"1c", *, "*", a.*, foo(), bar(baz, baw), t.c AS "1quoted", ' + statement += 'COUNT(*), COUNT(*) a, COUNT(DISTINCT x), COUNT(DISTINCT x) AS a, "select" FROM t' expected_dump = "SELECT NULL, 1234567890123456789, a, b AS b_alias, 'literal', CAST(1 AS varchar), " - expected_dump += "\"1c\", *, \"*\", a.*, foo(), bar(baz, baw), t.c AS \"1quoted\", " - expected_dump += "COUNT(*), COUNT(*) AS a, COUNT(DISTINCT x), COUNT(DISTINCT x) AS a, \"select\" FROM t" + expected_dump += '"1c", *, "*", a.*, foo(), bar(baz, baw), t.c AS "1quoted", ' + expected_dump += 'COUNT(*), COUNT(*) AS a, COUNT(DISTINCT x), COUNT(DISTINCT x) AS a, "select" FROM t' self.checkNominal(statement, expected_dump) def testNominalFrom(self): - statement = "SELECT a FROM t1, t2 at2, t3 AS at3, \"1quoted\", t4 AS \"2quoted\"" - expected_dump = "SELECT a FROM t1, t2 AS at2, t3 AS at3, \"1quoted\", t4 AS \"2quoted\"" + statement = 'SELECT a FROM t1, t2 at2, t3 AS at3, "1quoted", t4 AS "2quoted"' + expected_dump = ( + 'SELECT a FROM t1, t2 AS at2, t3 AS at3, "1quoted", t4 AS "2quoted"' + ) self.checkNominal(statement, expected_dump) def testNominalWhere(self): - statement = "SELECT a FROM t WHERE 1.5 <= 'a' OR TRUE OR FALSE OR a IS NULL AND b IS NOT NULL " + \ - "OR NOT d OR 1 + (2 - 3) * 4 / 5 ^ 6 <> 0 OR a IN (1, 2) OR b NOT IN (5) " + \ - "OR x BETWEEN 5 AND 6 OR x NOT BETWEEN 5 AND 6 OR c = d OR c > d OR c < d OR c >= d OR c <= d" + statement = ( + "SELECT a FROM t WHERE 1.5 <= 'a' OR TRUE OR FALSE OR a IS NULL AND b IS NOT NULL " + + "OR NOT d OR 1 + (2 - 3) * 4 / 5 ^ 6 <> 0 OR a IN (1, 2) OR b NOT IN (5) " + + "OR x BETWEEN 5 AND 6 OR x NOT BETWEEN 5 AND 6 OR c = d OR c > d OR c < d OR c >= d OR c <= d" + ) self.checkNominal(statement) def checkJoinType(self, joinType): @@ -211,17 +216,19 @@ def checkJoinType(self, joinType): self.checkNominal(statement) def testJoinTypes(self): - self.checkJoinType('JOIN') - self.checkJoinType('LEFT JOIN') - self.checkJoinType('LEFT OUTER JOIN') - self.checkJoinType('RIGHT JOIN') - self.checkJoinType('RIGHT OUTER JOIN') - self.checkJoinType('CROSS JOIN') - self.checkJoinType('FULL JOIN') - self.checkJoinType('INNER JOIN') + self.checkJoinType("JOIN") + self.checkJoinType("LEFT JOIN") + self.checkJoinType("LEFT OUTER JOIN") + self.checkJoinType("RIGHT JOIN") + self.checkJoinType("RIGHT OUTER JOIN") + self.checkJoinType("CROSS JOIN") + self.checkJoinType("FULL JOIN") + self.checkJoinType("INNER JOIN") def testJoin(self): - statement = "SELECT a FROM t JOIN j1 ON TRUE JOIN j2 USING (a) JOIN j3 USING (\"1a\", b)" + statement = ( + 'SELECT a FROM t JOIN j1 ON TRUE JOIN j2 USING (a) JOIN j3 USING ("1a", b)' + ) self.checkNominal(statement) def testNominalOrderBy(self): @@ -230,14 +237,15 @@ def testNominalOrderBy(self): self.checkNominal(statement, expected_dump) def testNominalFull(self): - statement = \ + statement = ( "SELECT a FROM t JOIN j1 ON cond1 JOIN j2 ON cond2 WHERE TRUE ORDER BY c" + ) self.checkNominal(statement) def checkError(self, statement): exp = QgsSQLStatement(statement) self.assertEqual(exp.hasParserError(), True) - self.assertNotEqual(exp.parserErrorString(), '') + self.assertNotEqual(exp.parserErrorString(), "") self.assertEqual(exp.dump(), "(no root)") self.assertEqual(exp.rootNode(), None) @@ -269,78 +277,88 @@ def testBasicValidationCheck(self): exp = QgsSQLStatement("error") (b, errorMsg) = exp.doBasicValidationChecks() self.assertFalse(b) - self.assertEqual(errorMsg, 'No root node') + self.assertEqual(errorMsg, "No root node") exp = QgsSQLStatement("SELECT c FROM t") (b, errorMsg) = exp.doBasicValidationChecks() self.assertTrue(b) - self.assertEqual(errorMsg, '') + self.assertEqual(errorMsg, "") exp = QgsSQLStatement("SELECT t.c FROM t ORDER BY t.c") (b, errorMsg) = exp.doBasicValidationChecks() self.assertTrue(b) - self.assertEqual(errorMsg, '') + self.assertEqual(errorMsg, "") exp = QgsSQLStatement("SELECT t.c FROM t t_alias") (b, errorMsg) = exp.doBasicValidationChecks() self.assertFalse(b) self.assertEqual( - errorMsg, 'Table t is referenced by column c, but not selected in FROM / JOIN.') + errorMsg, + "Table t is referenced by column c, but not selected in FROM / JOIN.", + ) - exp = QgsSQLStatement( - "SELECT CAST(1 + foo(t_unknown.a) AS varchar) FROM t") + exp = QgsSQLStatement("SELECT CAST(1 + foo(t_unknown.a) AS varchar) FROM t") (b, errorMsg) = exp.doBasicValidationChecks() self.assertFalse(b) self.assertEqual( - errorMsg, 'Table t_unknown is referenced by column a, but not selected in FROM / JOIN.') + errorMsg, + "Table t_unknown is referenced by column a, but not selected in FROM / JOIN.", + ) exp = QgsSQLStatement("SELECT c FROM t WHERE t_unknown.a = 1") (b, errorMsg) = exp.doBasicValidationChecks() self.assertFalse(b) self.assertEqual( - errorMsg, 'Table t_unknown is referenced by column a, but not selected in FROM / JOIN.') + errorMsg, + "Table t_unknown is referenced by column a, but not selected in FROM / JOIN.", + ) exp = QgsSQLStatement( - "SELECT c FROM t JOIN t2 ON t.c1 = t2.c2 AND t3.c3 IS NOT NULL") + "SELECT c FROM t JOIN t2 ON t.c1 = t2.c2 AND t3.c3 IS NOT NULL" + ) (b, errorMsg) = exp.doBasicValidationChecks() self.assertFalse(b) self.assertEqual( - errorMsg, 'Table t3 is referenced by column c3, but not selected in FROM / JOIN.') + errorMsg, + "Table t3 is referenced by column c3, but not selected in FROM / JOIN.", + ) exp = QgsSQLStatement("SELECT c FROM t ORDER BY t_unknown.c") (b, errorMsg) = exp.doBasicValidationChecks() self.assertFalse(b) self.assertEqual( - errorMsg, 'Table t_unknown is referenced by column c, but not selected in FROM / JOIN.') + errorMsg, + "Table t_unknown is referenced by column c, but not selected in FROM / JOIN.", + ) def testFragmentColumnRef(self): - exp = QgsSQLStatementFragment('col') + exp = QgsSQLStatementFragment("col") self.assertFalse(exp.hasParserError()) self.assertIsInstance(exp.rootNode(), QgsSQLStatement.NodeColumnRef) - self.assertEqual(exp.rootNode().name(), 'col') + self.assertEqual(exp.rootNode().name(), "col") exp = QgsSQLStatementFragment('"col"') self.assertFalse(exp.hasParserError()) self.assertIsInstance(exp.rootNode(), QgsSQLStatement.NodeColumnRef) - self.assertEqual(exp.rootNode().name(), 'col') + self.assertEqual(exp.rootNode().name(), "col") def testFragmentFunction(self): - exp = QgsSQLStatementFragment('upper(col)') + exp = QgsSQLStatementFragment("upper(col)") self.assertFalse(exp.hasParserError()) self.assertIsInstance(exp.rootNode(), QgsSQLStatement.NodeFunction) - self.assertEqual(exp.rootNode().name(), 'upper') + self.assertEqual(exp.rootNode().name(), "upper") def testFragmentCondition(self): - exp = QgsSQLStatementFragment('col = \'a\'') + exp = QgsSQLStatementFragment("col = 'a'") self.assertFalse(exp.hasParserError()) self.assertIsInstance(exp.rootNode(), QgsSQLStatement.NodeBinaryOperator) - self.assertEqual(exp.rootNode().opLeft().name(), 'col') - self.assertEqual(exp.rootNode().opRight().value(), 'a') + self.assertEqual(exp.rootNode().opLeft().name(), "col") + self.assertEqual(exp.rootNode().opRight().value(), "a") def checkFragmentError(self, statement): exp = QgsSQLStatementFragment(statement) self.assertEqual(exp.hasParserError(), True) - self.assertNotEqual(exp.parserErrorString(), '') + self.assertNotEqual(exp.parserErrorString(), "") self.assertEqual(exp.dump(), "(no root)") self.assertEqual(exp.rootNode(), None) @@ -355,36 +373,36 @@ def testFragmentError(self): def testMsFragment(self): # Microsoft style identifiers can have a bunch of weird characters in them! - exp = QgsSQLStatementFragment('[col$_# :]') + exp = QgsSQLStatementFragment("[col$_# :]") self.assertFalse(exp.hasParserError()) self.assertIsInstance(exp.rootNode(), QgsSQLStatement.NodeColumnRef) - self.assertEqual(exp.rootNode().name(), 'col$_# :') + self.assertEqual(exp.rootNode().name(), "col$_# :") - exp = QgsSQLStatementFragment('[table$_# :].[col$_# :]') + exp = QgsSQLStatementFragment("[table$_# :].[col$_# :]") self.assertFalse(exp.hasParserError()) self.assertIsInstance(exp.rootNode(), QgsSQLStatement.NodeColumnRef) - self.assertEqual(exp.rootNode().name(), 'col$_# :') - self.assertEqual(exp.rootNode().tableName(), 'table$_# :') + self.assertEqual(exp.rootNode().name(), "col$_# :") + self.assertEqual(exp.rootNode().tableName(), "table$_# :") def testMsDateLiteral(self): # Microsoft style date reference - exp = QgsSQLStatementFragment('#05-30-2020#') + exp = QgsSQLStatementFragment("#05-30-2020#") self.assertFalse(exp.hasParserError()) self.assertIsInstance(exp.rootNode(), QgsSQLStatement.NodeLiteral) - self.assertEqual(exp.rootNode().value(), '05-30-2020') - exp = QgsSQLStatementFragment('#05/30/2020#') + self.assertEqual(exp.rootNode().value(), "05-30-2020") + exp = QgsSQLStatementFragment("#05/30/2020#") self.assertFalse(exp.hasParserError()) self.assertIsInstance(exp.rootNode(), QgsSQLStatement.NodeLiteral) - self.assertEqual(exp.rootNode().value(), '05/30/2020') - exp = QgsSQLStatementFragment('#05/30/2020 13:45:55#') + self.assertEqual(exp.rootNode().value(), "05/30/2020") + exp = QgsSQLStatementFragment("#05/30/2020 13:45:55#") self.assertFalse(exp.hasParserError()) self.assertIsInstance(exp.rootNode(), QgsSQLStatement.NodeLiteral) - self.assertEqual(exp.rootNode().value(), '05/30/2020 13:45:55') - exp = QgsSQLStatementFragment('[date] = #05/30/2020 13:45:55#') + self.assertEqual(exp.rootNode().value(), "05/30/2020 13:45:55") + exp = QgsSQLStatementFragment("[date] = #05/30/2020 13:45:55#") self.assertFalse(exp.hasParserError()) self.assertIsInstance(exp.rootNode(), QgsSQLStatement.NodeBinaryOperator) - self.assertEqual(exp.rootNode().opLeft().name(), 'date') - self.assertEqual(exp.rootNode().opRight().value(), '05/30/2020 13:45:55') + self.assertEqual(exp.rootNode().opLeft().name(), "date") + self.assertEqual(exp.rootNode().opRight().value(), "05/30/2020 13:45:55") if __name__ == "__main__": diff --git a/tests/src/python/test_qgsstringstatisticalsummary.py b/tests/src/python/test_qgsstringstatisticalsummary.py index aa13cdc6a3a5..23682bbe561c 100644 --- a/tests/src/python/test_qgsstringstatisticalsummary.py +++ b/tests/src/python/test_qgsstringstatisticalsummary.py @@ -5,15 +5,13 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '07/05/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' +__author__ = "Nyall Dawson" +__date__ = "07/05/2016" +__copyright__ = "Copyright 2016, The QGIS Project" -from qgis.core import ( - NULL, - QgsStringStatisticalSummary -) + +from qgis.core import NULL, QgsStringStatisticalSummary from qgis.testing import unittest @@ -24,7 +22,18 @@ def testStats(self): # added one-at-a-time s = QgsStringStatisticalSummary() self.assertEqual(s.statistics(), QgsStringStatisticalSummary.Statistic.All) - strings = ['cc', 'aaaa', 'bbbbbbbb', 'aaaa', 'eeee', '', 'eeee', 'aaaa', None, 'dddd'] + strings = [ + "cc", + "aaaa", + "bbbbbbbb", + "aaaa", + "eeee", + "", + "eeee", + "aaaa", + None, + "dddd", + ] s.calculate(strings) s2 = QgsStringStatisticalSummary() for string in strings: @@ -34,89 +43,124 @@ def testStats(self): self.assertEqual(s2.count(), 10) self.assertEqual(s.countDistinct(), 6) self.assertEqual(s2.countDistinct(), 6) - self.assertEqual(set(s.distinctValues()), {'cc', 'aaaa', 'bbbbbbbb', 'eeee', 'dddd', ''}) + self.assertEqual( + set(s.distinctValues()), {"cc", "aaaa", "bbbbbbbb", "eeee", "dddd", ""} + ) self.assertEqual(s2.distinctValues(), s.distinctValues()) self.assertEqual(s.countMissing(), 2) self.assertEqual(s2.countMissing(), 2) - self.assertEqual(s.min(), 'aaaa') - self.assertEqual(s2.min(), 'aaaa') - self.assertEqual(s.max(), 'eeee') - self.assertEqual(s2.max(), 'eeee') + self.assertEqual(s.min(), "aaaa") + self.assertEqual(s2.min(), "aaaa") + self.assertEqual(s.max(), "eeee") + self.assertEqual(s2.max(), "eeee") self.assertEqual(s.minLength(), 0) self.assertEqual(s2.minLength(), 0) self.assertEqual(s.maxLength(), 8) self.assertEqual(s2.maxLength(), 8) self.assertEqual(s.meanLength(), 3.4) self.assertEqual(s2.meanLength(), 3.4) - self.assertEqual(s.minority(), 'bbbbbbbb') - self.assertEqual(s2.minority(), 'bbbbbbbb') - self.assertEqual(s.majority(), 'aaaa') - self.assertEqual(s2.majority(), 'aaaa') + self.assertEqual(s.minority(), "bbbbbbbb") + self.assertEqual(s2.minority(), "bbbbbbbb") + self.assertEqual(s.majority(), "aaaa") + self.assertEqual(s2.majority(), "aaaa") # extra check for minLength without empty strings - s.calculate(['1111111', '111', '11111']) + s.calculate(["1111111", "111", "11111"]) self.assertEqual(s.minLength(), 3) def testIndividualStats(self): # tests calculation of statistics one at a time, to make sure statistic calculations are not # dependent on each other - tests = [{'stat': QgsStringStatisticalSummary.Statistic.Count, 'expected': 10}, - {'stat': QgsStringStatisticalSummary.Statistic.CountDistinct, 'expected': 6}, - {'stat': QgsStringStatisticalSummary.Statistic.CountMissing, 'expected': 2}, - {'stat': QgsStringStatisticalSummary.Statistic.Min, 'expected': 'aaaa'}, - {'stat': QgsStringStatisticalSummary.Statistic.Max, 'expected': 'eeee'}, - {'stat': QgsStringStatisticalSummary.Statistic.MinimumLength, 'expected': 0}, - {'stat': QgsStringStatisticalSummary.Statistic.MaximumLength, 'expected': 8}, - {'stat': QgsStringStatisticalSummary.Statistic.MeanLength, 'expected': 3.4}, - {'stat': QgsStringStatisticalSummary.Statistic.Minority, 'expected': 'bbbbbbbb'}, - {'stat': QgsStringStatisticalSummary.Statistic.Majority, 'expected': 'aaaa'}, - ] + tests = [ + {"stat": QgsStringStatisticalSummary.Statistic.Count, "expected": 10}, + { + "stat": QgsStringStatisticalSummary.Statistic.CountDistinct, + "expected": 6, + }, + {"stat": QgsStringStatisticalSummary.Statistic.CountMissing, "expected": 2}, + {"stat": QgsStringStatisticalSummary.Statistic.Min, "expected": "aaaa"}, + {"stat": QgsStringStatisticalSummary.Statistic.Max, "expected": "eeee"}, + { + "stat": QgsStringStatisticalSummary.Statistic.MinimumLength, + "expected": 0, + }, + { + "stat": QgsStringStatisticalSummary.Statistic.MaximumLength, + "expected": 8, + }, + {"stat": QgsStringStatisticalSummary.Statistic.MeanLength, "expected": 3.4}, + { + "stat": QgsStringStatisticalSummary.Statistic.Minority, + "expected": "bbbbbbbb", + }, + { + "stat": QgsStringStatisticalSummary.Statistic.Majority, + "expected": "aaaa", + }, + ] s = QgsStringStatisticalSummary() s3 = QgsStringStatisticalSummary() for t in tests: # test constructor - s2 = QgsStringStatisticalSummary(t['stat']) - self.assertEqual(s2.statistics(), t['stat']) - - s.setStatistics(t['stat']) - s3.setStatistics(t['stat']) - self.assertEqual(s.statistics(), t['stat']) - - strings = ['cc', 'aaaa', 'bbbbbbbb', 'aaaa', 'eeee', '', 'eeee', 'aaaa', '', 'dddd'] + s2 = QgsStringStatisticalSummary(t["stat"]) + self.assertEqual(s2.statistics(), t["stat"]) + + s.setStatistics(t["stat"]) + s3.setStatistics(t["stat"]) + self.assertEqual(s.statistics(), t["stat"]) + + strings = [ + "cc", + "aaaa", + "bbbbbbbb", + "aaaa", + "eeee", + "", + "eeee", + "aaaa", + "", + "dddd", + ] s.calculate(strings) s3.reset() for string in strings: s3.addString(string) s3.finalize() - self.assertEqual(s.statistic(t['stat']), t['expected']) - self.assertEqual(s3.statistic(t['stat']), t['expected']) + self.assertEqual(s.statistic(t["stat"]), t["expected"]) + self.assertEqual(s3.statistic(t["stat"]), t["expected"]) # display name - self.assertGreater(len(QgsStringStatisticalSummary.displayName(t['stat'])), 0) + self.assertGreater( + len(QgsStringStatisticalSummary.displayName(t["stat"])), 0 + ) def testVariantStats(self): s = QgsStringStatisticalSummary() self.assertEqual(s.statistics(), QgsStringStatisticalSummary.Statistic.All) - s.calculateFromVariants(['cc', 5, 'bbbb', 'aaaa', 'eeee', 6, 9, '9', None]) + s.calculateFromVariants(["cc", 5, "bbbb", "aaaa", "eeee", 6, 9, "9", None]) self.assertEqual(s.count(), 6) - self.assertEqual(set(s.distinctValues()), {'cc', 'aaaa', 'bbbb', 'eeee', '', '9'}) + self.assertEqual( + set(s.distinctValues()), {"cc", "aaaa", "bbbb", "eeee", "", "9"} + ) self.assertEqual(s.countMissing(), 1) - self.assertEqual(s.min(), '9') - self.assertEqual(s.max(), 'eeee') + self.assertEqual(s.min(), "9") + self.assertEqual(s.max(), "eeee") def testAddVariantStats(self): s = QgsStringStatisticalSummary() self.assertEqual(s.statistics(), QgsStringStatisticalSummary.Statistic.All) - for v in ['cc', 5, 'bbbb', 'aaaa', 'eeee', 6, 9, '9', None]: + for v in ["cc", 5, "bbbb", "aaaa", "eeee", 6, 9, "9", None]: s.addValue(v) self.assertEqual(s.count(), 6) - self.assertEqual(set(s.distinctValues()), {'cc', 'aaaa', 'bbbb', 'eeee', '', '9'}) + self.assertEqual( + set(s.distinctValues()), {"cc", "aaaa", "bbbb", "eeee", "", "9"} + ) self.assertEqual(s.countMissing(), 1) - self.assertEqual(s.min(), '9') - self.assertEqual(s.max(), 'eeee') + self.assertEqual(s.min(), "9") + self.assertEqual(s.max(), "eeee") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsstringutils.py b/tests/src/python/test_qgsstringutils.py index 16254bdcb545..4fa4fbd176b6 100644 --- a/tests/src/python/test_qgsstringutils.py +++ b/tests/src/python/test_qgsstringutils.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '30/08/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "30/08/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtXml import QDomDocument from qgis.core import ( @@ -21,70 +22,81 @@ class PyQgsStringReplacement(unittest.TestCase): def testBasic(self): - """ basic tests for QgsStringReplacement""" - r = QgsStringReplacement('match', 'replace') - self.assertEqual(r.match(), 'match') - self.assertEqual(r.replacement(), 'replace') + """basic tests for QgsStringReplacement""" + r = QgsStringReplacement("match", "replace") + self.assertEqual(r.match(), "match") + self.assertEqual(r.replacement(), "replace") - r = QgsStringReplacement('match', 'replace', True, True) + r = QgsStringReplacement("match", "replace", True, True) self.assertTrue(r.wholeWordOnly()) self.assertTrue(r.caseSensitive()) def testReplace(self): - """ test applying replacements""" + """test applying replacements""" # case insensitive - r = QgsStringReplacement('match', 'replace', False, False) - self.assertEqual(r.process('one MaTch only'), 'one replace only') - self.assertEqual(r.process('more then one MaTch here match two'), 'more then one replace here replace two') - self.assertEqual(r.process('match start and end MaTch'), 'replace start and end replace') - self.assertEqual(r.process('no hits'), 'no hits') - self.assertEqual(r.process('some exmatches here'), 'some exreplacees here') - self.assertEqual(r.process(''), '') + r = QgsStringReplacement("match", "replace", False, False) + self.assertEqual(r.process("one MaTch only"), "one replace only") + self.assertEqual( + r.process("more then one MaTch here match two"), + "more then one replace here replace two", + ) + self.assertEqual( + r.process("match start and end MaTch"), "replace start and end replace" + ) + self.assertEqual(r.process("no hits"), "no hits") + self.assertEqual(r.process("some exmatches here"), "some exreplacees here") + self.assertEqual(r.process(""), "") # case sensitive - r = QgsStringReplacement('match', 'replace', True, False) - self.assertEqual(r.process('one MaTch only'), 'one MaTch only') - self.assertEqual(r.process('one match only'), 'one replace only') + r = QgsStringReplacement("match", "replace", True, False) + self.assertEqual(r.process("one MaTch only"), "one MaTch only") + self.assertEqual(r.process("one match only"), "one replace only") # whole word only, case insensitive - r = QgsStringReplacement('match', 'replace', False, True) - self.assertEqual(r.process('some exmatches here'), 'some exmatches here') - self.assertEqual(r.process('some match here'), 'some replace here') - self.assertEqual(r.process('some exmatches MaTch here'), 'some exmatches replace here') - self.assertEqual(r.process('some match maTCh here'), 'some replace replace here') - self.assertEqual(r.process('some -match. here'), 'some -replace. here') - self.assertEqual(r.process('match here'), 'replace here') - self.assertEqual(r.process('some match'), 'some replace') + r = QgsStringReplacement("match", "replace", False, True) + self.assertEqual(r.process("some exmatches here"), "some exmatches here") + self.assertEqual(r.process("some match here"), "some replace here") + self.assertEqual( + r.process("some exmatches MaTch here"), "some exmatches replace here" + ) + self.assertEqual( + r.process("some match maTCh here"), "some replace replace here" + ) + self.assertEqual(r.process("some -match. here"), "some -replace. here") + self.assertEqual(r.process("match here"), "replace here") + self.assertEqual(r.process("some match"), "some replace") # whole word only, case sensitive - r = QgsStringReplacement('match', 'replace', True, True) - self.assertEqual(r.process('some exmatches here'), 'some exmatches here') - self.assertEqual(r.process('some match here'), 'some replace here') - self.assertEqual(r.process('some exmatches MaTch here'), 'some exmatches MaTch here') - self.assertEqual(r.process('some match maTCh here'), 'some replace maTCh here') + r = QgsStringReplacement("match", "replace", True, True) + self.assertEqual(r.process("some exmatches here"), "some exmatches here") + self.assertEqual(r.process("some match here"), "some replace here") + self.assertEqual( + r.process("some exmatches MaTch here"), "some exmatches MaTch here" + ) + self.assertEqual(r.process("some match maTCh here"), "some replace maTCh here") def testEquality(self): - """ test equality operator""" - r1 = QgsStringReplacement('a', 'b', True, True) - r2 = QgsStringReplacement('a', 'b', True, True) + """test equality operator""" + r1 = QgsStringReplacement("a", "b", True, True) + r2 = QgsStringReplacement("a", "b", True, True) self.assertEqual(r1, r2) - r2 = QgsStringReplacement('c', 'b') + r2 = QgsStringReplacement("c", "b") self.assertNotEqual(r1, r2) - r2 = QgsStringReplacement('a', 'c') + r2 = QgsStringReplacement("a", "c") self.assertNotEqual(r1, r2) - r2 = QgsStringReplacement('a', 'b', False, True) + r2 = QgsStringReplacement("a", "b", False, True) self.assertNotEqual(r1, r2) - r2 = QgsStringReplacement('c', 'b', True, False) + r2 = QgsStringReplacement("c", "b", True, False) self.assertNotEqual(r1, r2) def testSaveRestore(self): - """ test saving/restoring replacement to map""" - r1 = QgsStringReplacement('a', 'b', True, True) + """test saving/restoring replacement to map""" + r1 = QgsStringReplacement("a", "b", True, True) props = r1.properties() r2 = QgsStringReplacement.fromProperties(props) self.assertEqual(r1, r2) - r1 = QgsStringReplacement('a', 'b', False, False) + r1 = QgsStringReplacement("a", "b", False, False) props = r1.properties() r2 = QgsStringReplacement.fromProperties(props) self.assertEqual(r1, r2) @@ -93,33 +105,40 @@ def testSaveRestore(self): class PyQgsStringReplacementCollection(unittest.TestCase): def testBasic(self): - """ basic QgsStringReplacementCollection tests""" - list = [QgsStringReplacement('aa', '11'), - QgsStringReplacement('bb', '22')] + """basic QgsStringReplacementCollection tests""" + list = [QgsStringReplacement("aa", "11"), QgsStringReplacement("bb", "22")] c = QgsStringReplacementCollection(list) self.assertEqual(c.replacements(), list) def testReplacements(self): - """ test replacing using collection of replacements """ + """test replacing using collection of replacements""" c = QgsStringReplacementCollection() - c.setReplacements([QgsStringReplacement('aa', '11'), - QgsStringReplacement('bb', '22')]) - self.assertEqual(c.process('here aa bb is aa string bb'), 'here 11 22 is 11 string 22') - self.assertEqual(c.process('no matches'), 'no matches') - self.assertEqual(c.process(''), '') + c.setReplacements( + [QgsStringReplacement("aa", "11"), QgsStringReplacement("bb", "22")] + ) + self.assertEqual( + c.process("here aa bb is aa string bb"), "here 11 22 is 11 string 22" + ) + self.assertEqual(c.process("no matches"), "no matches") + self.assertEqual(c.process(""), "") # test replacements are done in order - c.setReplacements([QgsStringReplacement('aa', '11'), - QgsStringReplacement('11', '22')]) - self.assertEqual(c.process('string aa'), 'string 22') + c.setReplacements( + [QgsStringReplacement("aa", "11"), QgsStringReplacement("11", "22")] + ) + self.assertEqual(c.process("string aa"), "string 22") # no replacements c.setReplacements([]) - self.assertEqual(c.process('string aa'), 'string aa') + self.assertEqual(c.process("string aa"), "string aa") def testSaveRestore(self): - """ test saving and restoring collections """ - c = QgsStringReplacementCollection([QgsStringReplacement('aa', '11', False, False), - QgsStringReplacement('bb', '22', True, True)]) + """test saving and restoring collections""" + c = QgsStringReplacementCollection( + [ + QgsStringReplacement("aa", "11", False, False), + QgsStringReplacement("bb", "22", True, True), + ] + ) doc = QDomDocument("testdoc") elem = doc.createElement("replacements") c.writeXml(elem, doc) @@ -131,109 +150,227 @@ def testSaveRestore(self): class PyQgsStringUtils(unittest.TestCase): def testMixed(self): - """ test mixed capitalization - ie, no change! """ - self.assertFalse(QgsStringUtils.capitalize(None, QgsStringUtils.Capitalization.MixedCase)) - self.assertEqual(QgsStringUtils.capitalize('', QgsStringUtils.Capitalization.MixedCase), '') - self.assertEqual(QgsStringUtils.capitalize('testing 123', QgsStringUtils.Capitalization.MixedCase), 'testing 123') - self.assertEqual(QgsStringUtils.capitalize(' tESTinG 123 ', QgsStringUtils.Capitalization.MixedCase), ' tESTinG 123 ') - self.assertEqual(QgsStringUtils.capitalize(' TESTING ABC', QgsStringUtils.Capitalization.MixedCase), ' TESTING ABC') + """test mixed capitalization - ie, no change!""" + self.assertFalse( + QgsStringUtils.capitalize(None, QgsStringUtils.Capitalization.MixedCase) + ) + self.assertEqual( + QgsStringUtils.capitalize("", QgsStringUtils.Capitalization.MixedCase), "" + ) + self.assertEqual( + QgsStringUtils.capitalize( + "testing 123", QgsStringUtils.Capitalization.MixedCase + ), + "testing 123", + ) + self.assertEqual( + QgsStringUtils.capitalize( + " tESTinG 123 ", QgsStringUtils.Capitalization.MixedCase + ), + " tESTinG 123 ", + ) + self.assertEqual( + QgsStringUtils.capitalize( + " TESTING ABC", QgsStringUtils.Capitalization.MixedCase + ), + " TESTING ABC", + ) def testUpperCase(self): - """ test uppercase """ - self.assertFalse(QgsStringUtils.capitalize(None, QgsStringUtils.Capitalization.AllUppercase)) - self.assertEqual(QgsStringUtils.capitalize('', QgsStringUtils.Capitalization.AllUppercase), '') - self.assertEqual(QgsStringUtils.capitalize('testing 123', QgsStringUtils.Capitalization.AllUppercase), 'TESTING 123') - self.assertEqual(QgsStringUtils.capitalize(' tESTinG abc ', QgsStringUtils.Capitalization.AllUppercase), ' TESTING ABC ') - self.assertEqual(QgsStringUtils.capitalize(' TESTING ABC', QgsStringUtils.Capitalization.AllUppercase), ' TESTING ABC') + """test uppercase""" + self.assertFalse( + QgsStringUtils.capitalize(None, QgsStringUtils.Capitalization.AllUppercase) + ) + self.assertEqual( + QgsStringUtils.capitalize("", QgsStringUtils.Capitalization.AllUppercase), + "", + ) + self.assertEqual( + QgsStringUtils.capitalize( + "testing 123", QgsStringUtils.Capitalization.AllUppercase + ), + "TESTING 123", + ) + self.assertEqual( + QgsStringUtils.capitalize( + " tESTinG abc ", QgsStringUtils.Capitalization.AllUppercase + ), + " TESTING ABC ", + ) + self.assertEqual( + QgsStringUtils.capitalize( + " TESTING ABC", QgsStringUtils.Capitalization.AllUppercase + ), + " TESTING ABC", + ) def testLowerCase(self): - """ test lowercase """ - self.assertFalse(QgsStringUtils.capitalize(None, QgsStringUtils.Capitalization.AllLowercase)) - self.assertEqual(QgsStringUtils.capitalize('', QgsStringUtils.Capitalization.AllLowercase), '') - self.assertEqual(QgsStringUtils.capitalize('testing 123', QgsStringUtils.Capitalization.AllLowercase), 'testing 123') - self.assertEqual(QgsStringUtils.capitalize(' tESTinG abc ', QgsStringUtils.Capitalization.AllLowercase), - ' testing abc ') - self.assertEqual(QgsStringUtils.capitalize(' TESTING ABC', QgsStringUtils.Capitalization.AllLowercase), ' testing abc') + """test lowercase""" + self.assertFalse( + QgsStringUtils.capitalize(None, QgsStringUtils.Capitalization.AllLowercase) + ) + self.assertEqual( + QgsStringUtils.capitalize("", QgsStringUtils.Capitalization.AllLowercase), + "", + ) + self.assertEqual( + QgsStringUtils.capitalize( + "testing 123", QgsStringUtils.Capitalization.AllLowercase + ), + "testing 123", + ) + self.assertEqual( + QgsStringUtils.capitalize( + " tESTinG abc ", QgsStringUtils.Capitalization.AllLowercase + ), + " testing abc ", + ) + self.assertEqual( + QgsStringUtils.capitalize( + " TESTING ABC", QgsStringUtils.Capitalization.AllLowercase + ), + " testing abc", + ) def testCapitalizeFirst(self): - """ test capitalize first """ - self.assertFalse(QgsStringUtils.capitalize(None, QgsStringUtils.Capitalization.ForceFirstLetterToCapital)) - self.assertEqual(QgsStringUtils.capitalize('', QgsStringUtils.Capitalization.ForceFirstLetterToCapital), '') - self.assertEqual(QgsStringUtils.capitalize('testing 123', QgsStringUtils.Capitalization.ForceFirstLetterToCapital), 'Testing 123') - self.assertEqual(QgsStringUtils.capitalize('testing', QgsStringUtils.Capitalization.ForceFirstLetterToCapital), - 'Testing') - self.assertEqual(QgsStringUtils.capitalize('Testing', QgsStringUtils.Capitalization.ForceFirstLetterToCapital), - 'Testing') - self.assertEqual(QgsStringUtils.capitalize('TESTING', QgsStringUtils.Capitalization.ForceFirstLetterToCapital), - 'TESTING') - self.assertEqual(QgsStringUtils.capitalize(' tESTinG abc ', QgsStringUtils.Capitalization.ForceFirstLetterToCapital), - ' TESTinG Abc ') - self.assertEqual(QgsStringUtils.capitalize(' TESTING ABC', QgsStringUtils.Capitalization.ForceFirstLetterToCapital), ' TESTING ABC') - self.assertEqual(QgsStringUtils.capitalize(' testing abc', QgsStringUtils.Capitalization.ForceFirstLetterToCapital), - ' Testing Abc') + """test capitalize first""" + self.assertFalse( + QgsStringUtils.capitalize( + None, QgsStringUtils.Capitalization.ForceFirstLetterToCapital + ) + ) + self.assertEqual( + QgsStringUtils.capitalize( + "", QgsStringUtils.Capitalization.ForceFirstLetterToCapital + ), + "", + ) + self.assertEqual( + QgsStringUtils.capitalize( + "testing 123", QgsStringUtils.Capitalization.ForceFirstLetterToCapital + ), + "Testing 123", + ) + self.assertEqual( + QgsStringUtils.capitalize( + "testing", QgsStringUtils.Capitalization.ForceFirstLetterToCapital + ), + "Testing", + ) + self.assertEqual( + QgsStringUtils.capitalize( + "Testing", QgsStringUtils.Capitalization.ForceFirstLetterToCapital + ), + "Testing", + ) + self.assertEqual( + QgsStringUtils.capitalize( + "TESTING", QgsStringUtils.Capitalization.ForceFirstLetterToCapital + ), + "TESTING", + ) + self.assertEqual( + QgsStringUtils.capitalize( + " tESTinG abc ", + QgsStringUtils.Capitalization.ForceFirstLetterToCapital, + ), + " TESTinG Abc ", + ) + self.assertEqual( + QgsStringUtils.capitalize( + " TESTING ABC", + QgsStringUtils.Capitalization.ForceFirstLetterToCapital, + ), + " TESTING ABC", + ) + self.assertEqual( + QgsStringUtils.capitalize( + " testing abc", + QgsStringUtils.Capitalization.ForceFirstLetterToCapital, + ), + " Testing Abc", + ) def testfuzzyScore(self): - self.assertEqual(QgsStringUtils.fuzzyScore('', ''), 0) - self.assertEqual(QgsStringUtils.fuzzyScore('foo', ''), 0) - self.assertEqual(QgsStringUtils.fuzzyScore('', 'foo'), 0) - self.assertEqual(QgsStringUtils.fuzzyScore('foo', 'foo'), 1) - self.assertEqual(QgsStringUtils.fuzzyScore('bar', 'foo'), 0) - self.assertEqual(QgsStringUtils.fuzzyScore('FOO', 'foo'), 1) - self.assertEqual(QgsStringUtils.fuzzyScore('foo', 'FOO'), 1) - self.assertEqual(QgsStringUtils.fuzzyScore(' foo ', 'foo'), 1) - self.assertEqual(QgsStringUtils.fuzzyScore('foo', ' foo '), 1) - self.assertEqual(QgsStringUtils.fuzzyScore('foo', ' foo '), 1) - self.assertEqual(QgsStringUtils.fuzzyScore('foo_bar', 'foo bar'), 1) - self.assertGreater(QgsStringUtils.fuzzyScore('foo bar', 'foo'), 0) - self.assertGreater(QgsStringUtils.fuzzyScore('foo bar', 'fooba'), 0) - self.assertGreater(QgsStringUtils.fuzzyScore('foo_bar', 'ob'), 0) - self.assertGreater(QgsStringUtils.fuzzyScore('foo bar', 'foobar'), 0) - self.assertGreater(QgsStringUtils.fuzzyScore('foo bar', 'foo_bar'), 0) - self.assertGreater(QgsStringUtils.fuzzyScore('foo_bar', 'foo bar'), 0) - self.assertEqual( - QgsStringUtils.fuzzyScore('foo bar', 'foobar'), - QgsStringUtils.fuzzyScore('foo_bar', 'foobar') - ) - self.assertEqual( - QgsStringUtils.fuzzyScore('foo bar', 'foo_bar'), - QgsStringUtils.fuzzyScore('foo_bar', 'foo_bar') - ) - self.assertEqual( - QgsStringUtils.fuzzyScore('foo bar', 'foo bar'), - QgsStringUtils.fuzzyScore('foo_bar', 'foo bar') + self.assertEqual(QgsStringUtils.fuzzyScore("", ""), 0) + self.assertEqual(QgsStringUtils.fuzzyScore("foo", ""), 0) + self.assertEqual(QgsStringUtils.fuzzyScore("", "foo"), 0) + self.assertEqual(QgsStringUtils.fuzzyScore("foo", "foo"), 1) + self.assertEqual(QgsStringUtils.fuzzyScore("bar", "foo"), 0) + self.assertEqual(QgsStringUtils.fuzzyScore("FOO", "foo"), 1) + self.assertEqual(QgsStringUtils.fuzzyScore("foo", "FOO"), 1) + self.assertEqual(QgsStringUtils.fuzzyScore(" foo ", "foo"), 1) + self.assertEqual(QgsStringUtils.fuzzyScore("foo", " foo "), 1) + self.assertEqual(QgsStringUtils.fuzzyScore("foo", " foo "), 1) + self.assertEqual(QgsStringUtils.fuzzyScore("foo_bar", "foo bar"), 1) + self.assertGreater(QgsStringUtils.fuzzyScore("foo bar", "foo"), 0) + self.assertGreater(QgsStringUtils.fuzzyScore("foo bar", "fooba"), 0) + self.assertGreater(QgsStringUtils.fuzzyScore("foo_bar", "ob"), 0) + self.assertGreater(QgsStringUtils.fuzzyScore("foo bar", "foobar"), 0) + self.assertGreater(QgsStringUtils.fuzzyScore("foo bar", "foo_bar"), 0) + self.assertGreater(QgsStringUtils.fuzzyScore("foo_bar", "foo bar"), 0) + self.assertEqual( + QgsStringUtils.fuzzyScore("foo bar", "foobar"), + QgsStringUtils.fuzzyScore("foo_bar", "foobar"), + ) + self.assertEqual( + QgsStringUtils.fuzzyScore("foo bar", "foo_bar"), + QgsStringUtils.fuzzyScore("foo_bar", "foo_bar"), + ) + self.assertEqual( + QgsStringUtils.fuzzyScore("foo bar", "foo bar"), + QgsStringUtils.fuzzyScore("foo_bar", "foo bar"), ) # note the accent self.assertEqual( - QgsStringUtils.fuzzyScore('foo_bér', 'foober'), - QgsStringUtils.fuzzyScore('foo_ber', 'foobér') + QgsStringUtils.fuzzyScore("foo_bér", "foober"), + QgsStringUtils.fuzzyScore("foo_ber", "foobér"), ) self.assertGreater( - QgsStringUtils.fuzzyScore('abcd efg hig', 'abcd hig'), - QgsStringUtils.fuzzyScore('abcd efg hig', 'abcd e h') + QgsStringUtils.fuzzyScore("abcd efg hig", "abcd hig"), + QgsStringUtils.fuzzyScore("abcd efg hig", "abcd e h"), ) # full words are preferred, even though the same number of characters used self.assertGreater( - QgsStringUtils.fuzzyScore('abcd efg hig', 'abcd hig'), - QgsStringUtils.fuzzyScore('abcd efg hig', 'abcd e hi') + QgsStringUtils.fuzzyScore("abcd efg hig", "abcd hig"), + QgsStringUtils.fuzzyScore("abcd efg hig", "abcd e hi"), ) def test_truncate_from_middle(self): """ Test QgsStringUtils.truncateMiddleOfString """ - self.assertEqual(QgsStringUtils.truncateMiddleOfString('', 0), '') - self.assertEqual(QgsStringUtils.truncateMiddleOfString('', 10), '') - self.assertEqual(QgsStringUtils.truncateMiddleOfString('abcdef', 10), 'abcdef') - self.assertEqual(QgsStringUtils.truncateMiddleOfString('abcdefghij', 10), 'abcdefghij') - self.assertEqual(QgsStringUtils.truncateMiddleOfString('abcdefghijk', 10), 'abcd…ghijk') - self.assertEqual(QgsStringUtils.truncateMiddleOfString('abcdefghijkl', 10), 'abcde…ijkl') - self.assertEqual(QgsStringUtils.truncateMiddleOfString('abcdefghijklmnop', 10), 'abcde…mnop') - self.assertEqual(QgsStringUtils.truncateMiddleOfString('this is a test', 11), 'this … test') - self.assertEqual(QgsStringUtils.truncateMiddleOfString('this is a test', 1), '…') - self.assertEqual(QgsStringUtils.truncateMiddleOfString('this is a test', 2), 't…') - self.assertEqual(QgsStringUtils.truncateMiddleOfString('this is a test', 3), 't…t') - self.assertEqual(QgsStringUtils.truncateMiddleOfString('this is a test', 0), '…') - - -if __name__ == '__main__': + self.assertEqual(QgsStringUtils.truncateMiddleOfString("", 0), "") + self.assertEqual(QgsStringUtils.truncateMiddleOfString("", 10), "") + self.assertEqual(QgsStringUtils.truncateMiddleOfString("abcdef", 10), "abcdef") + self.assertEqual( + QgsStringUtils.truncateMiddleOfString("abcdefghij", 10), "abcdefghij" + ) + self.assertEqual( + QgsStringUtils.truncateMiddleOfString("abcdefghijk", 10), "abcd…ghijk" + ) + self.assertEqual( + QgsStringUtils.truncateMiddleOfString("abcdefghijkl", 10), "abcde…ijkl" + ) + self.assertEqual( + QgsStringUtils.truncateMiddleOfString("abcdefghijklmnop", 10), "abcde…mnop" + ) + self.assertEqual( + QgsStringUtils.truncateMiddleOfString("this is a test", 11), "this … test" + ) + self.assertEqual( + QgsStringUtils.truncateMiddleOfString("this is a test", 1), "…" + ) + self.assertEqual( + QgsStringUtils.truncateMiddleOfString("this is a test", 2), "t…" + ) + self.assertEqual( + QgsStringUtils.truncateMiddleOfString("this is a test", 3), "t…t" + ) + self.assertEqual( + QgsStringUtils.truncateMiddleOfString("this is a test", 0), "…" + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsstylemodel.py b/tests/src/python/test_qgsstylemodel.py index 1b3a7476e1c9..8ffeaf837bfb 100644 --- a/tests/src/python/test_qgsstylemodel.py +++ b/tests/src/python/test_qgsstylemodel.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '10/09/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "10/09/2018" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.PyQt.QtCore import QModelIndex, QSize, Qt import unittest @@ -38,14 +39,17 @@ class Dummy3dSymbol(QgsAbstract3DSymbol): def __init__(self): super().__init__() - self.layer_types = [QgsWkbTypes.GeometryType.PointGeometry, QgsWkbTypes.GeometryType.LineGeometry] + self.layer_types = [ + QgsWkbTypes.GeometryType.PointGeometry, + QgsWkbTypes.GeometryType.LineGeometry, + ] @staticmethod def create(): return Dummy3dSymbol() def type(self): - return 'dummy' + return "dummy" def clone(self): return Dummy3dSymbol() @@ -61,25 +65,19 @@ def compatibleGeometryTypes(self): def createMarkerSymbol(): - symbol = QgsMarkerSymbol.createSimple({ - "color": "100,150,50", - "name": "square", - "size": "3.0" - }) + symbol = QgsMarkerSymbol.createSimple( + {"color": "100,150,50", "name": "square", "size": "3.0"} + ) return symbol def createLineSymbol(): - symbol = QgsLineSymbol.createSimple({ - "color": "100,150,50" - }) + symbol = QgsLineSymbol.createSimple({"color": "100,150,50"}) return symbol def createFillSymbol(): - symbol = QgsFillSymbol.createSimple({ - "color": "100,150,50" - }) + symbol = QgsFillSymbol.createSimple({"color": "100,150,50"}) return symbol @@ -89,36 +87,36 @@ def test_style_with_symbols(self): style = QgsStyle() style.createMemoryDatabase() - style.setName('style name') - style.setFileName('/home/me/my.db') + style.setName("style name") + style.setFileName("/home/me/my.db") # style with only symbols symbol_a = createMarkerSymbol() symbol_a.setColor(QColor(255, 10, 10)) - self.assertTrue(style.addSymbol('a', symbol_a, True)) - style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, 'a', ['tag 1', 'tag 2']) + self.assertTrue(style.addSymbol("a", symbol_a, True)) + style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, "a", ["tag 1", "tag 2"]) symbol_B = createMarkerSymbol() symbol_B.setColor(QColor(10, 255, 10)) - self.assertTrue(style.addSymbol('B ', symbol_B, True)) + self.assertTrue(style.addSymbol("B ", symbol_B, True)) symbol_b = createFillSymbol() symbol_b.setColor(QColor(10, 255, 10)) - self.assertTrue(style.addSymbol('b', symbol_b, True)) + self.assertTrue(style.addSymbol("b", symbol_b, True)) symbol_C = createLineSymbol() symbol_C.setColor(QColor(10, 255, 10)) - self.assertTrue(style.addSymbol('C', symbol_C, True)) - style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, 'C', ['tag 3']) - style.addFavorite(QgsStyle.StyleEntity.SymbolEntity, 'C') + self.assertTrue(style.addSymbol("C", symbol_C, True)) + style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, "C", ["tag 3"]) + style.addFavorite(QgsStyle.StyleEntity.SymbolEntity, "C") symbol_C = createMarkerSymbol() symbol_C.setColor(QColor(10, 255, 10)) - self.assertTrue(style.addSymbol(' ----c/- ', symbol_C, True)) + self.assertTrue(style.addSymbol(" ----c/- ", symbol_C, True)) model = QgsStyleModel(style) self.assertEqual(model.rowCount(), 5) self.assertEqual(model.columnCount(), 2) - self.assertEqual(model.headerData(0, Qt.Orientation.Horizontal), 'Name') - self.assertEqual(model.headerData(1, Qt.Orientation.Horizontal), 'Tags') + self.assertEqual(model.headerData(0, Qt.Orientation.Horizontal), "Name") + self.assertEqual(model.headerData(1, Qt.Orientation.Horizontal), "Tags") self.assertTrue(model.index(0, 0).isValid()) self.assertFalse(model.index(10, 0).isValid()) @@ -132,46 +130,80 @@ def test_style_with_symbols(self): self.assertFalse(model.flags(model.index(0, 1)) & Qt.ItemFlag.ItemIsEditable) self.assertTrue(model.flags(model.index(0, 0)) & Qt.ItemFlag.ItemIsEditable) - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.StyleName), 'style name') - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.StyleFileName), '/home/me/my.db') - - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.EntityName), ' ----c/- ') - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.EntityName), 'B ') - self.assertEqual(model.data(model.index(2, 0), QgsStyleModel.Role.EntityName), 'C') + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.StyleName), "style name" + ) + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.StyleFileName), + "/home/me/my.db", + ) + + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.EntityName), " ----c/- " + ) + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.EntityName), "B " + ) + self.assertEqual( + model.data(model.index(2, 0), QgsStyleModel.Role.EntityName), "C" + ) for role in (Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.EditRole): self.assertIsNone(model.data(model.index(-1, 0), role)) self.assertIsNone(model.data(model.index(-1, 1), role)) - self.assertEqual(model.data(model.index(0, 0), role), ' ----c/- ') + self.assertEqual(model.data(model.index(0, 0), role), " ----c/- ") self.assertFalse(model.data(model.index(0, 1), role)) self.assertIsNone(model.data(model.index(0, 2), role)) self.assertIsNone(model.data(model.index(0, -1), role)) - self.assertEqual(model.data(model.index(1, 0), role), 'B ') + self.assertEqual(model.data(model.index(1, 0), role), "B ") self.assertFalse(model.data(model.index(1, 1), role)) - self.assertEqual(model.data(model.index(2, 0), role), 'C') - self.assertEqual(model.data(model.index(2, 1), role), 'tag 3') - self.assertEqual(model.data(model.index(3, 0), role), 'a') - self.assertEqual(model.data(model.index(3, 1), role), 'tag 1, tag 2') - self.assertEqual(model.data(model.index(4, 0), role), 'b') + self.assertEqual(model.data(model.index(2, 0), role), "C") + self.assertEqual(model.data(model.index(2, 1), role), "tag 3") + self.assertEqual(model.data(model.index(3, 0), role), "a") + self.assertEqual(model.data(model.index(3, 1), role), "tag 1, tag 2") + self.assertEqual(model.data(model.index(4, 0), role), "b") self.assertFalse(model.data(model.index(4, 1), role)) self.assertIsNone(model.data(model.index(5, 0), role)) self.assertIsNone(model.data(model.index(5, 1), role)) # decorations - self.assertIsNone(model.data(model.index(-1, 0), Qt.ItemDataRole.DecorationRole)) + self.assertIsNone( + model.data(model.index(-1, 0), Qt.ItemDataRole.DecorationRole) + ) self.assertIsNone(model.data(model.index(0, 1), Qt.ItemDataRole.DecorationRole)) self.assertIsNone(model.data(model.index(5, 0), Qt.ItemDataRole.DecorationRole)) - self.assertFalse(model.data(model.index(0, 0), Qt.ItemDataRole.DecorationRole).isNull()) - - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.SymbolEntity) - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.SymbolEntity) - self.assertEqual(model.data(model.index(4, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.SymbolEntity) - - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.IsFavoriteRole), False) - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.IsFavoriteRole), False) - self.assertEqual(model.data(model.index(2, 0), QgsStyleModel.Role.IsFavoriteRole), True) - self.assertEqual(model.data(model.index(3, 0), QgsStyleModel.Role.IsFavoriteRole), False) - self.assertEqual(model.data(model.index(4, 0), QgsStyleModel.Role.IsFavoriteRole), False) + self.assertFalse( + model.data(model.index(0, 0), Qt.ItemDataRole.DecorationRole).isNull() + ) + + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.SymbolEntity, + ) + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.SymbolEntity, + ) + self.assertEqual( + model.data(model.index(4, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.SymbolEntity, + ) + + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + self.assertEqual( + model.data(model.index(2, 0), QgsStyleModel.Role.IsFavoriteRole), True + ) + self.assertEqual( + model.data(model.index(3, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + self.assertEqual( + model.data(model.index(4, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) def test_style_with_ramps(self): style = QgsStyle() @@ -180,18 +212,18 @@ def test_style_with_ramps(self): # style with only ramps ramp_a = QgsLimitedRandomColorRamp(5) - self.assertTrue(style.addColorRamp('a', ramp_a, True)) - style.tagSymbol(QgsStyle.StyleEntity.ColorrampEntity, 'a', ['tag 1', 'tag 2']) + self.assertTrue(style.addColorRamp("a", ramp_a, True)) + style.tagSymbol(QgsStyle.StyleEntity.ColorrampEntity, "a", ["tag 1", "tag 2"]) symbol_B = QgsLimitedRandomColorRamp() - self.assertTrue(style.addColorRamp('B ', symbol_B, True)) + self.assertTrue(style.addColorRamp("B ", symbol_B, True)) symbol_b = QgsLimitedRandomColorRamp() - self.assertTrue(style.addColorRamp('b', symbol_b, True)) + self.assertTrue(style.addColorRamp("b", symbol_b, True)) symbol_C = QgsLimitedRandomColorRamp() - self.assertTrue(style.addColorRamp('C', symbol_C, True)) - style.tagSymbol(QgsStyle.StyleEntity.ColorrampEntity, 'C', ['tag 3']) - style.addFavorite(QgsStyle.StyleEntity.ColorrampEntity, 'C') + self.assertTrue(style.addColorRamp("C", symbol_C, True)) + style.tagSymbol(QgsStyle.StyleEntity.ColorrampEntity, "C", ["tag 3"]) + style.addFavorite(QgsStyle.StyleEntity.ColorrampEntity, "C") symbol_C = QgsLimitedRandomColorRamp() - self.assertTrue(style.addColorRamp(' ----c/- ', symbol_C, True)) + self.assertTrue(style.addColorRamp(" ----c/- ", symbol_C, True)) model = QgsStyleModel(style) self.assertEqual(model.rowCount(), 5) @@ -206,36 +238,59 @@ def test_style_with_ramps(self): for role in (Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.EditRole): self.assertIsNone(model.data(model.index(-1, 0), role)) self.assertIsNone(model.data(model.index(-1, 1), role)) - self.assertEqual(model.data(model.index(0, 0), role), ' ----c/- ') + self.assertEqual(model.data(model.index(0, 0), role), " ----c/- ") self.assertFalse(model.data(model.index(0, 1), role)) self.assertIsNone(model.data(model.index(0, 2), role)) self.assertIsNone(model.data(model.index(0, -1), role)) - self.assertEqual(model.data(model.index(1, 0), role), 'B ') + self.assertEqual(model.data(model.index(1, 0), role), "B ") self.assertFalse(model.data(model.index(1, 1), role)) - self.assertEqual(model.data(model.index(2, 0), role), 'C') - self.assertEqual(model.data(model.index(2, 1), role), 'tag 3') - self.assertEqual(model.data(model.index(3, 0), role), 'a') - self.assertEqual(model.data(model.index(3, 1), role), 'tag 1, tag 2') - self.assertEqual(model.data(model.index(4, 0), role), 'b') + self.assertEqual(model.data(model.index(2, 0), role), "C") + self.assertEqual(model.data(model.index(2, 1), role), "tag 3") + self.assertEqual(model.data(model.index(3, 0), role), "a") + self.assertEqual(model.data(model.index(3, 1), role), "tag 1, tag 2") + self.assertEqual(model.data(model.index(4, 0), role), "b") self.assertFalse(model.data(model.index(4, 1), role)) self.assertIsNone(model.data(model.index(5, 0), role)) self.assertIsNone(model.data(model.index(5, 1), role)) # decorations - self.assertIsNone(model.data(model.index(-1, 0), Qt.ItemDataRole.DecorationRole)) + self.assertIsNone( + model.data(model.index(-1, 0), Qt.ItemDataRole.DecorationRole) + ) self.assertIsNone(model.data(model.index(0, 1), Qt.ItemDataRole.DecorationRole)) self.assertIsNone(model.data(model.index(5, 0), Qt.ItemDataRole.DecorationRole)) - self.assertFalse(model.data(model.index(0, 0), Qt.ItemDataRole.DecorationRole).isNull()) - - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.ColorrampEntity) - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.ColorrampEntity) - self.assertEqual(model.data(model.index(4, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.ColorrampEntity) - - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.IsFavoriteRole), False) - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.IsFavoriteRole), False) - self.assertEqual(model.data(model.index(2, 0), QgsStyleModel.Role.IsFavoriteRole), True) - self.assertEqual(model.data(model.index(3, 0), QgsStyleModel.Role.IsFavoriteRole), False) - self.assertEqual(model.data(model.index(4, 0), QgsStyleModel.Role.IsFavoriteRole), False) + self.assertFalse( + model.data(model.index(0, 0), Qt.ItemDataRole.DecorationRole).isNull() + ) + + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.ColorrampEntity, + ) + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.ColorrampEntity, + ) + self.assertEqual( + model.data(model.index(4, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.ColorrampEntity, + ) + + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + self.assertEqual( + model.data(model.index(2, 0), QgsStyleModel.Role.IsFavoriteRole), True + ) + self.assertEqual( + model.data(model.index(3, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + self.assertEqual( + model.data(model.index(4, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) def test_style_with_text_formats(self): style = QgsStyle() @@ -244,18 +299,18 @@ def test_style_with_text_formats(self): # style with text formats format_a = QgsTextFormat() - self.assertTrue(style.addTextFormat('a', format_a, True)) - style.tagSymbol(QgsStyle.StyleEntity.TextFormatEntity, 'a', ['tag 1', 'tag 2']) + self.assertTrue(style.addTextFormat("a", format_a, True)) + style.tagSymbol(QgsStyle.StyleEntity.TextFormatEntity, "a", ["tag 1", "tag 2"]) format_B = QgsTextFormat() - self.assertTrue(style.addTextFormat('B ', format_B, True)) + self.assertTrue(style.addTextFormat("B ", format_B, True)) format_b = QgsTextFormat() - self.assertTrue(style.addTextFormat('b', format_b, True)) + self.assertTrue(style.addTextFormat("b", format_b, True)) format_C = QgsTextFormat() - self.assertTrue(style.addTextFormat('C', format_C, True)) - style.tagSymbol(QgsStyle.StyleEntity.TextFormatEntity, 'C', ['tag 3']) - style.addFavorite(QgsStyle.StyleEntity.TextFormatEntity, 'C') + self.assertTrue(style.addTextFormat("C", format_C, True)) + style.tagSymbol(QgsStyle.StyleEntity.TextFormatEntity, "C", ["tag 3"]) + style.addFavorite(QgsStyle.StyleEntity.TextFormatEntity, "C") format_C = QgsTextFormat() - self.assertTrue(style.addTextFormat(' ----c/- ', format_C, True)) + self.assertTrue(style.addTextFormat(" ----c/- ", format_C, True)) model = QgsStyleModel(style) self.assertEqual(model.rowCount(), 5) @@ -270,36 +325,59 @@ def test_style_with_text_formats(self): for role in (Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.EditRole): self.assertIsNone(model.data(model.index(-1, 0), role)) self.assertIsNone(model.data(model.index(-1, 1), role)) - self.assertEqual(model.data(model.index(0, 0), role), ' ----c/- ') + self.assertEqual(model.data(model.index(0, 0), role), " ----c/- ") self.assertFalse(model.data(model.index(0, 1), role)) self.assertIsNone(model.data(model.index(0, 2), role)) self.assertIsNone(model.data(model.index(0, -1), role)) - self.assertEqual(model.data(model.index(1, 0), role), 'B ') + self.assertEqual(model.data(model.index(1, 0), role), "B ") self.assertFalse(model.data(model.index(1, 1), role)) - self.assertEqual(model.data(model.index(2, 0), role), 'C') - self.assertEqual(model.data(model.index(2, 1), role), 'tag 3') - self.assertEqual(model.data(model.index(3, 0), role), 'a') - self.assertEqual(model.data(model.index(3, 1), role), 'tag 1, tag 2') - self.assertEqual(model.data(model.index(4, 0), role), 'b') + self.assertEqual(model.data(model.index(2, 0), role), "C") + self.assertEqual(model.data(model.index(2, 1), role), "tag 3") + self.assertEqual(model.data(model.index(3, 0), role), "a") + self.assertEqual(model.data(model.index(3, 1), role), "tag 1, tag 2") + self.assertEqual(model.data(model.index(4, 0), role), "b") self.assertFalse(model.data(model.index(4, 1), role)) self.assertIsNone(model.data(model.index(5, 0), role)) self.assertIsNone(model.data(model.index(5, 1), role)) # decorations - self.assertIsNone(model.data(model.index(-1, 0), Qt.ItemDataRole.DecorationRole)) + self.assertIsNone( + model.data(model.index(-1, 0), Qt.ItemDataRole.DecorationRole) + ) self.assertIsNone(model.data(model.index(0, 1), Qt.ItemDataRole.DecorationRole)) self.assertIsNone(model.data(model.index(5, 0), Qt.ItemDataRole.DecorationRole)) - self.assertFalse(model.data(model.index(0, 0), Qt.ItemDataRole.DecorationRole).isNull()) - - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.TextFormatEntity) - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.TextFormatEntity) - self.assertEqual(model.data(model.index(4, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.TextFormatEntity) - - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.IsFavoriteRole), False) - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.IsFavoriteRole), False) - self.assertEqual(model.data(model.index(2, 0), QgsStyleModel.Role.IsFavoriteRole), True) - self.assertEqual(model.data(model.index(3, 0), QgsStyleModel.Role.IsFavoriteRole), False) - self.assertEqual(model.data(model.index(4, 0), QgsStyleModel.Role.IsFavoriteRole), False) + self.assertFalse( + model.data(model.index(0, 0), Qt.ItemDataRole.DecorationRole).isNull() + ) + + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.TextFormatEntity, + ) + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.TextFormatEntity, + ) + self.assertEqual( + model.data(model.index(4, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.TextFormatEntity, + ) + + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + self.assertEqual( + model.data(model.index(2, 0), QgsStyleModel.Role.IsFavoriteRole), True + ) + self.assertEqual( + model.data(model.index(3, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + self.assertEqual( + model.data(model.index(4, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) def test_style_with_label_settings(self): style = QgsStyle() @@ -309,22 +387,28 @@ def test_style_with_label_settings(self): format_a = QgsPalLayerSettings() format_a.layerType = QgsWkbTypes.GeometryType.PointGeometry - self.assertTrue(style.addLabelSettings('a', format_a, True)) - style.tagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, 'a', ['tag 1', 'tag 2']) + self.assertTrue(style.addLabelSettings("a", format_a, True)) + style.tagSymbol( + QgsStyle.StyleEntity.LabelSettingsEntity, "a", ["tag 1", "tag 2"] + ) format_B = QgsPalLayerSettings() format_B.layerType = QgsWkbTypes.GeometryType.LineGeometry - self.assertTrue(style.addLabelSettings('B ', format_B, True)) + self.assertTrue(style.addLabelSettings("B ", format_B, True)) format_b = QgsPalLayerSettings() - self.assertTrue(style.addLabelSettings('b', format_b, True)) + self.assertTrue(style.addLabelSettings("b", format_b, True)) format_C = QgsPalLayerSettings() - self.assertTrue(style.addLabelSettings('C', format_C, True)) - style.tagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, 'C', ['tag 3']) - style.addFavorite(QgsStyle.StyleEntity.LabelSettingsEntity, 'C') + self.assertTrue(style.addLabelSettings("C", format_C, True)) + style.tagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, "C", ["tag 3"]) + style.addFavorite(QgsStyle.StyleEntity.LabelSettingsEntity, "C") format_C = QgsPalLayerSettings() - self.assertTrue(style.addLabelSettings(' ----c/- ', format_C, True)) + self.assertTrue(style.addLabelSettings(" ----c/- ", format_C, True)) - self.assertEqual(style.labelSettingsLayerType('a'), QgsWkbTypes.GeometryType.PointGeometry) - self.assertEqual(style.labelSettingsLayerType('B '), QgsWkbTypes.GeometryType.LineGeometry) + self.assertEqual( + style.labelSettingsLayerType("a"), QgsWkbTypes.GeometryType.PointGeometry + ) + self.assertEqual( + style.labelSettingsLayerType("B "), QgsWkbTypes.GeometryType.LineGeometry + ) model = QgsStyleModel(style) self.assertEqual(model.rowCount(), 5) @@ -339,39 +423,68 @@ def test_style_with_label_settings(self): for role in (Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.EditRole): self.assertIsNone(model.data(model.index(-1, 0), role)) self.assertIsNone(model.data(model.index(-1, 1), role)) - self.assertEqual(model.data(model.index(0, 0), role), ' ----c/- ') + self.assertEqual(model.data(model.index(0, 0), role), " ----c/- ") self.assertFalse(model.data(model.index(0, 1), role)) self.assertIsNone(model.data(model.index(0, 2), role)) self.assertIsNone(model.data(model.index(0, -1), role)) - self.assertEqual(model.data(model.index(1, 0), role), 'B ') + self.assertEqual(model.data(model.index(1, 0), role), "B ") self.assertFalse(model.data(model.index(1, 1), role)) - self.assertEqual(model.data(model.index(2, 0), role), 'C') - self.assertEqual(model.data(model.index(2, 1), role), 'tag 3') - self.assertEqual(model.data(model.index(3, 0), role), 'a') - self.assertEqual(model.data(model.index(3, 1), role), 'tag 1, tag 2') - self.assertEqual(model.data(model.index(4, 0), role), 'b') + self.assertEqual(model.data(model.index(2, 0), role), "C") + self.assertEqual(model.data(model.index(2, 1), role), "tag 3") + self.assertEqual(model.data(model.index(3, 0), role), "a") + self.assertEqual(model.data(model.index(3, 1), role), "tag 1, tag 2") + self.assertEqual(model.data(model.index(4, 0), role), "b") self.assertFalse(model.data(model.index(4, 1), role)) self.assertIsNone(model.data(model.index(5, 0), role)) self.assertIsNone(model.data(model.index(5, 1), role)) # decorations - self.assertIsNone(model.data(model.index(-1, 0), Qt.ItemDataRole.DecorationRole)) + self.assertIsNone( + model.data(model.index(-1, 0), Qt.ItemDataRole.DecorationRole) + ) self.assertIsNone(model.data(model.index(0, 1), Qt.ItemDataRole.DecorationRole)) self.assertIsNone(model.data(model.index(5, 0), Qt.ItemDataRole.DecorationRole)) - self.assertFalse(model.data(model.index(0, 0), Qt.ItemDataRole.DecorationRole).isNull()) - - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.LabelSettingsEntity) - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.LabelSettingsEntity) - self.assertEqual(model.data(model.index(4, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.LabelSettingsEntity) - - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.IsFavoriteRole), False) - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.IsFavoriteRole), False) - self.assertEqual(model.data(model.index(2, 0), QgsStyleModel.Role.IsFavoriteRole), True) - self.assertEqual(model.data(model.index(3, 0), QgsStyleModel.Role.IsFavoriteRole), False) - self.assertEqual(model.data(model.index(4, 0), QgsStyleModel.Role.IsFavoriteRole), False) - - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.LayerTypeRole), QgsWkbTypes.GeometryType.LineGeometry) - self.assertEqual(model.data(model.index(3, 0), QgsStyleModel.Role.LayerTypeRole), QgsWkbTypes.GeometryType.PointGeometry) + self.assertFalse( + model.data(model.index(0, 0), Qt.ItemDataRole.DecorationRole).isNull() + ) + + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.LabelSettingsEntity, + ) + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.LabelSettingsEntity, + ) + self.assertEqual( + model.data(model.index(4, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.LabelSettingsEntity, + ) + + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + self.assertEqual( + model.data(model.index(2, 0), QgsStyleModel.Role.IsFavoriteRole), True + ) + self.assertEqual( + model.data(model.index(3, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + self.assertEqual( + model.data(model.index(4, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.LayerTypeRole), + QgsWkbTypes.GeometryType.LineGeometry, + ) + self.assertEqual( + model.data(model.index(3, 0), QgsStyleModel.Role.LayerTypeRole), + QgsWkbTypes.GeometryType.PointGeometry, + ) def test_style_with_legend_patch_shapes(self): style = QgsStyle() @@ -379,22 +492,40 @@ def test_style_with_legend_patch_shapes(self): # style with legend patch shapes - shape_a = QgsLegendPatchShape(QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt('Point( 4 5 )')) - self.assertTrue(style.addLegendPatchShape('a', shape_a, True)) - style.tagSymbol(QgsStyle.StyleEntity.LegendPatchShapeEntity, 'a', ['tag 1', 'tag 2']) - shape_B = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString( 4 5, 6 4 )')) - self.assertTrue(style.addLegendPatchShape('B ', shape_B, True)) - shape_b = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString( 14 5, 6 4 )')) - self.assertTrue(style.addLegendPatchShape('b', shape_b, True)) - shape_C = QgsLegendPatchShape(QgsSymbol.SymbolType.Fill, QgsGeometry.fromWkt('Polygon(( 4 5, 6 4, 7 3, 4 5) )')) - self.assertTrue(style.addLegendPatchShape('C', shape_C, True)) - style.tagSymbol(QgsStyle.StyleEntity.LegendPatchShapeEntity, 'C', ['tag 3']) - style.addFavorite(QgsStyle.StyleEntity.LegendPatchShapeEntity, 'C') - shape_C = QgsLegendPatchShape(QgsSymbol.SymbolType.Fill, QgsGeometry.fromWkt('Polygon(( 4 5, 16 4, 7 3, 4 5) )')) - self.assertTrue(style.addLegendPatchShape(' ----c/- ', shape_C, True)) - - self.assertEqual(style.legendPatchShapeSymbolType('a'), QgsSymbol.SymbolType.Marker) - self.assertEqual(style.legendPatchShapeSymbolType('B '), QgsSymbol.SymbolType.Line) + shape_a = QgsLegendPatchShape( + QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt("Point( 4 5 )") + ) + self.assertTrue(style.addLegendPatchShape("a", shape_a, True)) + style.tagSymbol( + QgsStyle.StyleEntity.LegendPatchShapeEntity, "a", ["tag 1", "tag 2"] + ) + shape_B = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt("LineString( 4 5, 6 4 )") + ) + self.assertTrue(style.addLegendPatchShape("B ", shape_B, True)) + shape_b = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt("LineString( 14 5, 6 4 )") + ) + self.assertTrue(style.addLegendPatchShape("b", shape_b, True)) + shape_C = QgsLegendPatchShape( + QgsSymbol.SymbolType.Fill, + QgsGeometry.fromWkt("Polygon(( 4 5, 6 4, 7 3, 4 5) )"), + ) + self.assertTrue(style.addLegendPatchShape("C", shape_C, True)) + style.tagSymbol(QgsStyle.StyleEntity.LegendPatchShapeEntity, "C", ["tag 3"]) + style.addFavorite(QgsStyle.StyleEntity.LegendPatchShapeEntity, "C") + shape_C = QgsLegendPatchShape( + QgsSymbol.SymbolType.Fill, + QgsGeometry.fromWkt("Polygon(( 4 5, 16 4, 7 3, 4 5) )"), + ) + self.assertTrue(style.addLegendPatchShape(" ----c/- ", shape_C, True)) + + self.assertEqual( + style.legendPatchShapeSymbolType("a"), QgsSymbol.SymbolType.Marker + ) + self.assertEqual( + style.legendPatchShapeSymbolType("B "), QgsSymbol.SymbolType.Line + ) model = QgsStyleModel(style) self.assertEqual(model.rowCount(), 5) @@ -409,42 +540,80 @@ def test_style_with_legend_patch_shapes(self): for role in (Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.EditRole): self.assertIsNone(model.data(model.index(-1, 0), role)) self.assertIsNone(model.data(model.index(-1, 1), role)) - self.assertEqual(model.data(model.index(0, 0), role), ' ----c/- ') + self.assertEqual(model.data(model.index(0, 0), role), " ----c/- ") self.assertFalse(model.data(model.index(0, 1), role)) self.assertIsNone(model.data(model.index(0, 2), role)) self.assertIsNone(model.data(model.index(0, -1), role)) - self.assertEqual(model.data(model.index(1, 0), role), 'B ') + self.assertEqual(model.data(model.index(1, 0), role), "B ") self.assertFalse(model.data(model.index(1, 1), role)) - self.assertEqual(model.data(model.index(2, 0), role), 'C') - self.assertEqual(model.data(model.index(2, 1), role), 'tag 3') - self.assertEqual(model.data(model.index(3, 0), role), 'a') - self.assertEqual(model.data(model.index(3, 1), role), 'tag 1, tag 2') - self.assertEqual(model.data(model.index(4, 0), role), 'b') + self.assertEqual(model.data(model.index(2, 0), role), "C") + self.assertEqual(model.data(model.index(2, 1), role), "tag 3") + self.assertEqual(model.data(model.index(3, 0), role), "a") + self.assertEqual(model.data(model.index(3, 1), role), "tag 1, tag 2") + self.assertEqual(model.data(model.index(4, 0), role), "b") self.assertFalse(model.data(model.index(4, 1), role)) self.assertIsNone(model.data(model.index(5, 0), role)) self.assertIsNone(model.data(model.index(5, 1), role)) # decorations - self.assertIsNone(model.data(model.index(-1, 0), Qt.ItemDataRole.DecorationRole)) + self.assertIsNone( + model.data(model.index(-1, 0), Qt.ItemDataRole.DecorationRole) + ) self.assertIsNone(model.data(model.index(0, 1), Qt.ItemDataRole.DecorationRole)) self.assertIsNone(model.data(model.index(5, 0), Qt.ItemDataRole.DecorationRole)) - self.assertFalse(model.data(model.index(0, 0), Qt.ItemDataRole.DecorationRole).isNull()) - - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.LegendPatchShapeEntity) - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.LegendPatchShapeEntity) - self.assertEqual(model.data(model.index(4, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.LegendPatchShapeEntity) - - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.IsFavoriteRole), False) - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.IsFavoriteRole), False) - self.assertEqual(model.data(model.index(2, 0), QgsStyleModel.Role.IsFavoriteRole), True) - self.assertEqual(model.data(model.index(3, 0), QgsStyleModel.Role.IsFavoriteRole), False) - self.assertEqual(model.data(model.index(4, 0), QgsStyleModel.Role.IsFavoriteRole), False) - - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.SymbolTypeRole), QgsSymbol.SymbolType.Fill) - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.SymbolTypeRole), QgsSymbol.SymbolType.Line) - self.assertEqual(model.data(model.index(2, 0), QgsStyleModel.Role.SymbolTypeRole), QgsSymbol.SymbolType.Fill) - self.assertEqual(model.data(model.index(3, 0), QgsStyleModel.Role.SymbolTypeRole), QgsSymbol.SymbolType.Marker) - self.assertEqual(model.data(model.index(4, 0), QgsStyleModel.Role.SymbolTypeRole), QgsSymbol.SymbolType.Line) + self.assertFalse( + model.data(model.index(0, 0), Qt.ItemDataRole.DecorationRole).isNull() + ) + + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.LegendPatchShapeEntity, + ) + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.LegendPatchShapeEntity, + ) + self.assertEqual( + model.data(model.index(4, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.LegendPatchShapeEntity, + ) + + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + self.assertEqual( + model.data(model.index(2, 0), QgsStyleModel.Role.IsFavoriteRole), True + ) + self.assertEqual( + model.data(model.index(3, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + self.assertEqual( + model.data(model.index(4, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.SymbolTypeRole), + QgsSymbol.SymbolType.Fill, + ) + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.SymbolTypeRole), + QgsSymbol.SymbolType.Line, + ) + self.assertEqual( + model.data(model.index(2, 0), QgsStyleModel.Role.SymbolTypeRole), + QgsSymbol.SymbolType.Fill, + ) + self.assertEqual( + model.data(model.index(3, 0), QgsStyleModel.Role.SymbolTypeRole), + QgsSymbol.SymbolType.Marker, + ) + self.assertEqual( + model.data(model.index(4, 0), QgsStyleModel.Role.SymbolTypeRole), + QgsSymbol.SymbolType.Line, + ) def test_style_with_3d_symbols(self): style = QgsStyle() @@ -453,18 +622,18 @@ def test_style_with_3d_symbols(self): # style with 3d symbols symbol_a = Dummy3dSymbol() - self.assertTrue(style.addSymbol3D('a', symbol_a, True)) - style.tagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, 'a', ['tag 1', 'tag 2']) + self.assertTrue(style.addSymbol3D("a", symbol_a, True)) + style.tagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, "a", ["tag 1", "tag 2"]) symbol_B = Dummy3dSymbol() - self.assertTrue(style.addSymbol3D('B ', symbol_B, True)) + self.assertTrue(style.addSymbol3D("B ", symbol_B, True)) symbol_b = Dummy3dSymbol() - self.assertTrue(style.addSymbol3D('b', symbol_b, True)) + self.assertTrue(style.addSymbol3D("b", symbol_b, True)) symbol_C = Dummy3dSymbol() - self.assertTrue(style.addSymbol3D('C', symbol_C, True)) - style.tagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, 'C', ['tag 3']) - style.addFavorite(QgsStyle.StyleEntity.Symbol3DEntity, 'C') + self.assertTrue(style.addSymbol3D("C", symbol_C, True)) + style.tagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, "C", ["tag 3"]) + style.addFavorite(QgsStyle.StyleEntity.Symbol3DEntity, "C") symbol_C = Dummy3dSymbol() - self.assertTrue(style.addSymbol3D(' ----c/- ', symbol_C, True)) + self.assertTrue(style.addSymbol3D(" ----c/- ", symbol_C, True)) model = QgsStyleModel(style) self.assertEqual(model.rowCount(), 5) @@ -479,43 +648,94 @@ def test_style_with_3d_symbols(self): for role in (Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.EditRole): self.assertIsNone(model.data(model.index(-1, 0), role)) self.assertIsNone(model.data(model.index(-1, 1), role)) - self.assertEqual(model.data(model.index(0, 0), role), ' ----c/- ') + self.assertEqual(model.data(model.index(0, 0), role), " ----c/- ") self.assertFalse(model.data(model.index(0, 1), role)) self.assertIsNone(model.data(model.index(0, 2), role)) self.assertIsNone(model.data(model.index(0, -1), role)) - self.assertEqual(model.data(model.index(1, 0), role), 'B ') + self.assertEqual(model.data(model.index(1, 0), role), "B ") self.assertFalse(model.data(model.index(1, 1), role)) - self.assertEqual(model.data(model.index(2, 0), role), 'C') - self.assertEqual(model.data(model.index(2, 1), role), 'tag 3') - self.assertEqual(model.data(model.index(3, 0), role), 'a') - self.assertEqual(model.data(model.index(3, 1), role), 'tag 1, tag 2') - self.assertEqual(model.data(model.index(4, 0), role), 'b') + self.assertEqual(model.data(model.index(2, 0), role), "C") + self.assertEqual(model.data(model.index(2, 1), role), "tag 3") + self.assertEqual(model.data(model.index(3, 0), role), "a") + self.assertEqual(model.data(model.index(3, 1), role), "tag 1, tag 2") + self.assertEqual(model.data(model.index(4, 0), role), "b") self.assertFalse(model.data(model.index(4, 1), role)) self.assertIsNone(model.data(model.index(5, 0), role)) self.assertIsNone(model.data(model.index(5, 1), role)) # decorations - self.assertIsNone(model.data(model.index(-1, 0), Qt.ItemDataRole.DecorationRole)) + self.assertIsNone( + model.data(model.index(-1, 0), Qt.ItemDataRole.DecorationRole) + ) self.assertIsNone(model.data(model.index(0, 1), Qt.ItemDataRole.DecorationRole)) self.assertIsNone(model.data(model.index(5, 0), Qt.ItemDataRole.DecorationRole)) # self.assertFalse(model.data(model.index(0, 0), Qt.DecorationRole).isNull()) - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.Symbol3DEntity) - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.Symbol3DEntity) - self.assertEqual(model.data(model.index(4, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.Symbol3DEntity) - - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.IsFavoriteRole), False) - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.IsFavoriteRole), False) - self.assertEqual(model.data(model.index(2, 0), QgsStyleModel.Role.IsFavoriteRole), True) - self.assertEqual(model.data(model.index(3, 0), QgsStyleModel.Role.IsFavoriteRole), False) - self.assertEqual(model.data(model.index(4, 0), QgsStyleModel.Role.IsFavoriteRole), False) - - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.CompatibleGeometryTypesRole), [0, 1]) - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.CompatibleGeometryTypesRole), [0, 1]) - self.assertEqual(model.data(model.index(2, 0), QgsStyleModel.Role.CompatibleGeometryTypesRole), [0, 1]) - self.assertEqual(model.data(model.index(3, 0), QgsStyleModel.Role.CompatibleGeometryTypesRole), [0, 1]) - self.assertEqual(model.data(model.index(4, 0), QgsStyleModel.Role.CompatibleGeometryTypesRole), [0, 1]) - self.assertEqual(model.data(model.index(5, 0), QgsStyleModel.Role.CompatibleGeometryTypesRole), None) + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.Symbol3DEntity, + ) + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.Symbol3DEntity, + ) + self.assertEqual( + model.data(model.index(4, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.Symbol3DEntity, + ) + + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + self.assertEqual( + model.data(model.index(2, 0), QgsStyleModel.Role.IsFavoriteRole), True + ) + self.assertEqual( + model.data(model.index(3, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + self.assertEqual( + model.data(model.index(4, 0), QgsStyleModel.Role.IsFavoriteRole), False + ) + + self.assertEqual( + model.data( + model.index(0, 0), QgsStyleModel.Role.CompatibleGeometryTypesRole + ), + [0, 1], + ) + self.assertEqual( + model.data( + model.index(1, 0), QgsStyleModel.Role.CompatibleGeometryTypesRole + ), + [0, 1], + ) + self.assertEqual( + model.data( + model.index(2, 0), QgsStyleModel.Role.CompatibleGeometryTypesRole + ), + [0, 1], + ) + self.assertEqual( + model.data( + model.index(3, 0), QgsStyleModel.Role.CompatibleGeometryTypesRole + ), + [0, 1], + ) + self.assertEqual( + model.data( + model.index(4, 0), QgsStyleModel.Role.CompatibleGeometryTypesRole + ), + [0, 1], + ) + self.assertEqual( + model.data( + model.index(5, 0), QgsStyleModel.Role.CompatibleGeometryTypesRole + ), + None, + ) def test_mixed_style(self): """ @@ -528,56 +748,72 @@ def test_mixed_style(self): symbol_a = createMarkerSymbol() symbol_a.setColor(QColor(255, 10, 10)) - self.assertTrue(style.addSymbol('a', symbol_a, True)) - style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, 'a', ['tag 1', 'tag 2']) + self.assertTrue(style.addSymbol("a", symbol_a, True)) + style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, "a", ["tag 1", "tag 2"]) symbol_B = createMarkerSymbol() symbol_B.setColor(QColor(10, 255, 10)) - self.assertTrue(style.addSymbol('B ', symbol_B, True)) + self.assertTrue(style.addSymbol("B ", symbol_B, True)) symbol_b = createFillSymbol() symbol_b.setColor(QColor(10, 255, 10)) - self.assertTrue(style.addSymbol('b', symbol_b, True)) + self.assertTrue(style.addSymbol("b", symbol_b, True)) symbol_C = createLineSymbol() symbol_C.setColor(QColor(10, 255, 10)) - self.assertTrue(style.addSymbol('C', symbol_C, True)) - style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, 'C', ['tag 3']) + self.assertTrue(style.addSymbol("C", symbol_C, True)) + style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, "C", ["tag 3"]) symbol_C = createMarkerSymbol() symbol_C.setColor(QColor(10, 255, 10)) - self.assertTrue(style.addSymbol(' ----c/- ', symbol_C, True)) + self.assertTrue(style.addSymbol(" ----c/- ", symbol_C, True)) ramp_a = QgsLimitedRandomColorRamp(5) - self.assertTrue(style.addColorRamp('ramp a', ramp_a, True)) - style.tagSymbol(QgsStyle.StyleEntity.ColorrampEntity, 'ramp a', ['tag 1', 'tag 2']) + self.assertTrue(style.addColorRamp("ramp a", ramp_a, True)) + style.tagSymbol( + QgsStyle.StyleEntity.ColorrampEntity, "ramp a", ["tag 1", "tag 2"] + ) symbol_B = QgsLimitedRandomColorRamp() - self.assertTrue(style.addColorRamp('ramp B ', symbol_B, True)) + self.assertTrue(style.addColorRamp("ramp B ", symbol_B, True)) symbol_b = QgsLimitedRandomColorRamp() - self.assertTrue(style.addColorRamp('ramp c', symbol_b, True)) + self.assertTrue(style.addColorRamp("ramp c", symbol_b, True)) format_a = QgsTextFormat() - self.assertTrue(style.addTextFormat('format a', format_a, True)) - style.tagSymbol(QgsStyle.StyleEntity.TextFormatEntity, 'format a', ['tag 1', 'tag 2']) + self.assertTrue(style.addTextFormat("format a", format_a, True)) + style.tagSymbol( + QgsStyle.StyleEntity.TextFormatEntity, "format a", ["tag 1", "tag 2"] + ) symbol_B = QgsTextFormat() - self.assertTrue(style.addTextFormat('format B ', symbol_B, True)) + self.assertTrue(style.addTextFormat("format B ", symbol_B, True)) symbol_b = QgsTextFormat() - self.assertTrue(style.addTextFormat('format c', symbol_b, True)) + self.assertTrue(style.addTextFormat("format c", symbol_b, True)) settings_a = QgsPalLayerSettings() - self.assertTrue(style.addLabelSettings('settings a', settings_a, True)) - style.tagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, 'settings a', ['tag 1', 'tag 2']) + self.assertTrue(style.addLabelSettings("settings a", settings_a, True)) + style.tagSymbol( + QgsStyle.StyleEntity.LabelSettingsEntity, "settings a", ["tag 1", "tag 2"] + ) symbol_B = QgsPalLayerSettings() - self.assertTrue(style.addLabelSettings('settings B ', symbol_B, True)) + self.assertTrue(style.addLabelSettings("settings B ", symbol_B, True)) symbol_b = QgsPalLayerSettings() - self.assertTrue(style.addLabelSettings('settings c', symbol_b, True)) - shape_a = QgsLegendPatchShape(QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt('Point (4 5)')) - self.assertTrue(style.addLegendPatchShape('shape a', shape_a, True)) - style.tagSymbol(QgsStyle.StyleEntity.LegendPatchShapeEntity, 'shape a', ['tag 1', 'tag 2']) - shape_B = QgsLegendPatchShape(QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt('Point (14 15)')) - self.assertTrue(style.addLegendPatchShape('shape B ', shape_B, True)) - shape_b = QgsLegendPatchShape(QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt('Point (14 25)')) - self.assertTrue(style.addLegendPatchShape('shape c', shape_b, True)) + self.assertTrue(style.addLabelSettings("settings c", symbol_b, True)) + shape_a = QgsLegendPatchShape( + QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt("Point (4 5)") + ) + self.assertTrue(style.addLegendPatchShape("shape a", shape_a, True)) + style.tagSymbol( + QgsStyle.StyleEntity.LegendPatchShapeEntity, "shape a", ["tag 1", "tag 2"] + ) + shape_B = QgsLegendPatchShape( + QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt("Point (14 15)") + ) + self.assertTrue(style.addLegendPatchShape("shape B ", shape_B, True)) + shape_b = QgsLegendPatchShape( + QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt("Point (14 25)") + ) + self.assertTrue(style.addLegendPatchShape("shape c", shape_b, True)) symbol3d_a = Dummy3dSymbol() - self.assertTrue(style.addSymbol3D('symbol3d a', symbol3d_a, True)) - style.tagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, 'symbol3d a', ['tag 1', 'tag 2']) + self.assertTrue(style.addSymbol3D("symbol3d a", symbol3d_a, True)) + style.tagSymbol( + QgsStyle.StyleEntity.Symbol3DEntity, "symbol3d a", ["tag 1", "tag 2"] + ) symbol3d_B = Dummy3dSymbol() - self.assertTrue(style.addSymbol3D('symbol3d B ', symbol3d_B, True)) + self.assertTrue(style.addSymbol3D("symbol3d B ", symbol3d_B, True)) symbol3d_b = Dummy3dSymbol() - self.assertTrue(style.addSymbol3D('symbol3d c', symbol3d_b, True)) + self.assertTrue(style.addSymbol3D("symbol3d c", symbol3d_b, True)) model = QgsStyleModel(style) self.assertEqual(model.rowCount(), 20) @@ -592,80 +828,148 @@ def test_mixed_style(self): for role in (Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.EditRole): self.assertIsNone(model.data(model.index(-1, 0), role)) self.assertIsNone(model.data(model.index(-1, 1), role)) - self.assertEqual(model.data(model.index(0, 0), role), ' ----c/- ') + self.assertEqual(model.data(model.index(0, 0), role), " ----c/- ") self.assertFalse(model.data(model.index(0, 1), role)) self.assertIsNone(model.data(model.index(0, 2), role)) self.assertIsNone(model.data(model.index(0, -1), role)) - self.assertEqual(model.data(model.index(1, 0), role), 'B ') + self.assertEqual(model.data(model.index(1, 0), role), "B ") self.assertFalse(model.data(model.index(1, 1), role)) - self.assertEqual(model.data(model.index(2, 0), role), 'C') - self.assertEqual(model.data(model.index(2, 1), role), 'tag 3') - self.assertEqual(model.data(model.index(3, 0), role), 'a') - self.assertEqual(model.data(model.index(3, 1), role), 'tag 1, tag 2') - self.assertEqual(model.data(model.index(4, 0), role), 'b') + self.assertEqual(model.data(model.index(2, 0), role), "C") + self.assertEqual(model.data(model.index(2, 1), role), "tag 3") + self.assertEqual(model.data(model.index(3, 0), role), "a") + self.assertEqual(model.data(model.index(3, 1), role), "tag 1, tag 2") + self.assertEqual(model.data(model.index(4, 0), role), "b") self.assertFalse(model.data(model.index(4, 1), role)) - self.assertEqual(model.data(model.index(5, 0), role), 'ramp B ') + self.assertEqual(model.data(model.index(5, 0), role), "ramp B ") self.assertFalse(model.data(model.index(5, 1), role)) - self.assertEqual(model.data(model.index(6, 0), role), 'ramp a') - self.assertEqual(model.data(model.index(6, 1), role), 'tag 1, tag 2') - self.assertEqual(model.data(model.index(7, 0), role), 'ramp c') + self.assertEqual(model.data(model.index(6, 0), role), "ramp a") + self.assertEqual(model.data(model.index(6, 1), role), "tag 1, tag 2") + self.assertEqual(model.data(model.index(7, 0), role), "ramp c") self.assertFalse(model.data(model.index(7, 1), role)) - self.assertEqual(model.data(model.index(8, 0), role), 'format B ') + self.assertEqual(model.data(model.index(8, 0), role), "format B ") self.assertFalse(model.data(model.index(8, 1), role)) - self.assertEqual(model.data(model.index(9, 0), role), 'format a') - self.assertEqual(model.data(model.index(9, 1), role), 'tag 1, tag 2') - self.assertEqual(model.data(model.index(10, 0), role), 'format c') + self.assertEqual(model.data(model.index(9, 0), role), "format a") + self.assertEqual(model.data(model.index(9, 1), role), "tag 1, tag 2") + self.assertEqual(model.data(model.index(10, 0), role), "format c") self.assertFalse(model.data(model.index(10, 1), role)) - self.assertEqual(model.data(model.index(11, 0), role), 'settings B ') + self.assertEqual(model.data(model.index(11, 0), role), "settings B ") self.assertFalse(model.data(model.index(11, 1), role)) - self.assertEqual(model.data(model.index(12, 0), role), 'settings a') - self.assertEqual(model.data(model.index(12, 1), role), 'tag 1, tag 2') - self.assertEqual(model.data(model.index(13, 0), role), 'settings c') + self.assertEqual(model.data(model.index(12, 0), role), "settings a") + self.assertEqual(model.data(model.index(12, 1), role), "tag 1, tag 2") + self.assertEqual(model.data(model.index(13, 0), role), "settings c") self.assertFalse(model.data(model.index(13, 1), role)) - self.assertEqual(model.data(model.index(14, 0), role), 'shape B ') + self.assertEqual(model.data(model.index(14, 0), role), "shape B ") self.assertFalse(model.data(model.index(14, 1), role)) - self.assertEqual(model.data(model.index(15, 0), role), 'shape a') - self.assertEqual(model.data(model.index(15, 1), role), 'tag 1, tag 2') - self.assertEqual(model.data(model.index(16, 0), role), 'shape c') + self.assertEqual(model.data(model.index(15, 0), role), "shape a") + self.assertEqual(model.data(model.index(15, 1), role), "tag 1, tag 2") + self.assertEqual(model.data(model.index(16, 0), role), "shape c") self.assertFalse(model.data(model.index(16, 1), role)) - self.assertEqual(model.data(model.index(17, 0), role), 'symbol3d B ') + self.assertEqual(model.data(model.index(17, 0), role), "symbol3d B ") self.assertFalse(model.data(model.index(17, 1), role)) - self.assertEqual(model.data(model.index(18, 0), role), 'symbol3d a') - self.assertEqual(model.data(model.index(18, 1), role), 'tag 1, tag 2') - self.assertEqual(model.data(model.index(19, 0), role), 'symbol3d c') + self.assertEqual(model.data(model.index(18, 0), role), "symbol3d a") + self.assertEqual(model.data(model.index(18, 1), role), "tag 1, tag 2") + self.assertEqual(model.data(model.index(19, 0), role), "symbol3d c") self.assertFalse(model.data(model.index(19, 1), role)) self.assertIsNone(model.data(model.index(20, 0), role)) self.assertIsNone(model.data(model.index(20, 1), role)) # decorations - self.assertIsNone(model.data(model.index(-1, 0), Qt.ItemDataRole.DecorationRole)) + self.assertIsNone( + model.data(model.index(-1, 0), Qt.ItemDataRole.DecorationRole) + ) self.assertIsNone(model.data(model.index(0, 1), Qt.ItemDataRole.DecorationRole)) - self.assertIsNone(model.data(model.index(20, 0), Qt.ItemDataRole.DecorationRole)) - self.assertFalse(model.data(model.index(0, 0), Qt.ItemDataRole.DecorationRole).isNull()) - self.assertFalse(model.data(model.index(5, 0), Qt.ItemDataRole.DecorationRole).isNull()) - self.assertFalse(model.data(model.index(8, 0), Qt.ItemDataRole.DecorationRole).isNull()) - self.assertFalse(model.data(model.index(11, 0), Qt.ItemDataRole.DecorationRole).isNull()) - self.assertFalse(model.data(model.index(14, 0), Qt.ItemDataRole.DecorationRole).isNull()) + self.assertIsNone( + model.data(model.index(20, 0), Qt.ItemDataRole.DecorationRole) + ) + self.assertFalse( + model.data(model.index(0, 0), Qt.ItemDataRole.DecorationRole).isNull() + ) + self.assertFalse( + model.data(model.index(5, 0), Qt.ItemDataRole.DecorationRole).isNull() + ) + self.assertFalse( + model.data(model.index(8, 0), Qt.ItemDataRole.DecorationRole).isNull() + ) + self.assertFalse( + model.data(model.index(11, 0), Qt.ItemDataRole.DecorationRole).isNull() + ) + self.assertFalse( + model.data(model.index(14, 0), Qt.ItemDataRole.DecorationRole).isNull() + ) # self.assertFalse(model.data(model.index(17, 0), Qt.DecorationRole).isNull()) - self.assertEqual(model.data(model.index(0, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.SymbolEntity) - self.assertEqual(model.data(model.index(1, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.SymbolEntity) - self.assertEqual(model.data(model.index(4, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.SymbolEntity) - self.assertEqual(model.data(model.index(5, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.ColorrampEntity) - self.assertEqual(model.data(model.index(6, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.ColorrampEntity) - self.assertEqual(model.data(model.index(7, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.ColorrampEntity) - self.assertEqual(model.data(model.index(8, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.TextFormatEntity) - self.assertEqual(model.data(model.index(9, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.TextFormatEntity) - self.assertEqual(model.data(model.index(10, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.TextFormatEntity) - self.assertEqual(model.data(model.index(11, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.LabelSettingsEntity) - self.assertEqual(model.data(model.index(12, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.LabelSettingsEntity) - self.assertEqual(model.data(model.index(13, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.LabelSettingsEntity) - self.assertEqual(model.data(model.index(14, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.LegendPatchShapeEntity) - self.assertEqual(model.data(model.index(15, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.LegendPatchShapeEntity) - self.assertEqual(model.data(model.index(16, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.LegendPatchShapeEntity) - self.assertEqual(model.data(model.index(17, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.Symbol3DEntity) - self.assertEqual(model.data(model.index(18, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.Symbol3DEntity) - self.assertEqual(model.data(model.index(19, 0), QgsStyleModel.Role.TypeRole), QgsStyle.StyleEntity.Symbol3DEntity) + self.assertEqual( + model.data(model.index(0, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.SymbolEntity, + ) + self.assertEqual( + model.data(model.index(1, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.SymbolEntity, + ) + self.assertEqual( + model.data(model.index(4, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.SymbolEntity, + ) + self.assertEqual( + model.data(model.index(5, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.ColorrampEntity, + ) + self.assertEqual( + model.data(model.index(6, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.ColorrampEntity, + ) + self.assertEqual( + model.data(model.index(7, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.ColorrampEntity, + ) + self.assertEqual( + model.data(model.index(8, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.TextFormatEntity, + ) + self.assertEqual( + model.data(model.index(9, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.TextFormatEntity, + ) + self.assertEqual( + model.data(model.index(10, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.TextFormatEntity, + ) + self.assertEqual( + model.data(model.index(11, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.LabelSettingsEntity, + ) + self.assertEqual( + model.data(model.index(12, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.LabelSettingsEntity, + ) + self.assertEqual( + model.data(model.index(13, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.LabelSettingsEntity, + ) + self.assertEqual( + model.data(model.index(14, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.LegendPatchShapeEntity, + ) + self.assertEqual( + model.data(model.index(15, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.LegendPatchShapeEntity, + ) + self.assertEqual( + model.data(model.index(16, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.LegendPatchShapeEntity, + ) + self.assertEqual( + model.data(model.index(17, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.Symbol3DEntity, + ) + self.assertEqual( + model.data(model.index(18, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.Symbol3DEntity, + ) + self.assertEqual( + model.data(model.index(19, 0), QgsStyleModel.Role.TypeRole), + QgsStyle.StyleEntity.Symbol3DEntity, + ) def test_add_delete_symbols(self): style = QgsStyle() @@ -675,50 +979,82 @@ def test_add_delete_symbols(self): self.assertEqual(model.rowCount(), 0) symbol = createMarkerSymbol() - self.assertTrue(style.addSymbol('a', symbol, True)) + self.assertTrue(style.addSymbol("a", symbol, True)) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) symbol = createMarkerSymbol() - self.assertTrue(style.addSymbol('c', symbol, True)) + self.assertTrue(style.addSymbol("c", symbol, True)) self.assertEqual(model.rowCount(), 2) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) symbol = createMarkerSymbol() - self.assertTrue(style.addSymbol('b', symbol, True)) + self.assertTrue(style.addSymbol("b", symbol, True)) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'b') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'c') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "b" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "c" + ) symbol = createMarkerSymbol() - self.assertTrue(style.addSymbol('1', symbol, True)) + self.assertTrue(style.addSymbol("1", symbol, True)) self.assertEqual(model.rowCount(), 4) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), '1') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'b') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'c') - - self.assertFalse(style.removeSymbol('xxxx')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "1" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "b" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + + self.assertFalse(style.removeSymbol("xxxx")) self.assertEqual(model.rowCount(), 4) - self.assertTrue(style.removeSymbol('b')) + self.assertTrue(style.removeSymbol("b")) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), '1') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'c') - - self.assertTrue(style.removeSymbol('1')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "1" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + + self.assertTrue(style.removeSymbol("1")) self.assertEqual(model.rowCount(), 2) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - - self.assertTrue(style.removeSymbol('c')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + + self.assertTrue(style.removeSymbol("c")) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) - self.assertTrue(style.removeSymbol('a')) + self.assertTrue(style.removeSymbol("a")) self.assertEqual(model.rowCount(), 0) def test_add_remove_ramps(self): @@ -727,41 +1063,73 @@ def test_add_remove_ramps(self): model = QgsStyleModel(style) symbol = createMarkerSymbol() - self.assertTrue(style.addSymbol('a', symbol, True)) + self.assertTrue(style.addSymbol("a", symbol, True)) symbol = createMarkerSymbol() - self.assertTrue(style.addSymbol('c', symbol, True)) + self.assertTrue(style.addSymbol("c", symbol, True)) self.assertEqual(model.rowCount(), 2) ramp_a = QgsLimitedRandomColorRamp(5) - self.assertTrue(style.addColorRamp('ramp a', ramp_a, True)) + self.assertTrue(style.addColorRamp("ramp a", ramp_a, True)) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) symbol_B = QgsLimitedRandomColorRamp() - self.assertTrue(style.addColorRamp('ramp c', symbol_B, True)) + self.assertTrue(style.addColorRamp("ramp c", symbol_B, True)) self.assertEqual(model.rowCount(), 4) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp c') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp c" + ) symbol_b = QgsLimitedRandomColorRamp() - self.assertTrue(style.addColorRamp('ramp b', symbol_b, True)) + self.assertTrue(style.addColorRamp("ramp b", symbol_b, True)) self.assertEqual(model.rowCount(), 5) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp b') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'ramp c') - - self.assertTrue(style.removeColorRamp('ramp a')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp b" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "ramp c" + ) + + self.assertTrue(style.removeColorRamp("ramp a")) self.assertEqual(model.rowCount(), 4) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp b') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp c') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp b" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp c" + ) def test_add_remove_text_formats(self): style = QgsStyle() @@ -769,65 +1137,125 @@ def test_add_remove_text_formats(self): model = QgsStyleModel(style) symbol = createMarkerSymbol() - self.assertTrue(style.addSymbol('a', symbol, True)) + self.assertTrue(style.addSymbol("a", symbol, True)) symbol = createMarkerSymbol() - self.assertTrue(style.addSymbol('c', symbol, True)) + self.assertTrue(style.addSymbol("c", symbol, True)) self.assertEqual(model.rowCount(), 2) ramp_a = QgsLimitedRandomColorRamp(5) - self.assertTrue(style.addColorRamp('ramp a', ramp_a, True)) + self.assertTrue(style.addColorRamp("ramp a", ramp_a, True)) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) format_a = QgsTextFormat() - self.assertTrue(style.addTextFormat('format a', format_a, True)) + self.assertTrue(style.addTextFormat("format a", format_a, True)) self.assertEqual(model.rowCount(), 4) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) format_B = QgsTextFormat() - self.assertTrue(style.addTextFormat('format c', format_B, True)) + self.assertTrue(style.addTextFormat("format c", format_B, True)) self.assertEqual(model.rowCount(), 5) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format c') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format c" + ) symbol_b = QgsTextFormat() - self.assertTrue(style.addTextFormat('format b', symbol_b, True)) + self.assertTrue(style.addTextFormat("format b", symbol_b, True)) self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format b') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format c') - - self.assertTrue(style.removeTextFormat('format a')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format b" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format c" + ) + + self.assertTrue(style.removeTextFormat("format a")) self.assertEqual(model.rowCount(), 5) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format b') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format c') - - self.assertTrue(style.removeColorRamp('ramp a')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format b" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format c" + ) + + self.assertTrue(style.removeColorRamp("ramp a")) self.assertEqual(model.rowCount(), 4) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'format b') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format c') - - self.assertTrue(style.removeSymbol('c')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "format b" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format c" + ) + + self.assertTrue(style.removeSymbol("c")) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'format b') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'format c') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "format b" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "format c" + ) def test_add_remove_label_settings(self): style = QgsStyle() @@ -835,85 +1263,171 @@ def test_add_remove_label_settings(self): model = QgsStyleModel(style) symbol = createMarkerSymbol() - self.assertTrue(style.addSymbol('a', symbol, True)) + self.assertTrue(style.addSymbol("a", symbol, True)) symbol = createMarkerSymbol() - self.assertTrue(style.addSymbol('c', symbol, True)) + self.assertTrue(style.addSymbol("c", symbol, True)) self.assertEqual(model.rowCount(), 2) ramp_a = QgsLimitedRandomColorRamp(5) - self.assertTrue(style.addColorRamp('ramp a', ramp_a, True)) + self.assertTrue(style.addColorRamp("ramp a", ramp_a, True)) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) format_a = QgsTextFormat() - self.assertTrue(style.addTextFormat('format a', format_a, True)) + self.assertTrue(style.addTextFormat("format a", format_a, True)) self.assertEqual(model.rowCount(), 4) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) settings_a = QgsPalLayerSettings() - self.assertTrue(style.addLabelSettings('settings a', settings_a, True)) + self.assertTrue(style.addLabelSettings("settings a", settings_a, True)) self.assertEqual(model.rowCount(), 5) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'settings a') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) settings_B = QgsPalLayerSettings() - self.assertTrue(style.addLabelSettings('settings c', settings_B, True)) + self.assertTrue(style.addLabelSettings("settings c", settings_B, True)) self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'settings c') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) settings_b = QgsPalLayerSettings() - self.assertTrue(style.addLabelSettings('settings b', settings_b, True)) + self.assertTrue(style.addLabelSettings("settings b", settings_b, True)) self.assertEqual(model.rowCount(), 7) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'settings b') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - - self.assertTrue(style.removeLabelSettings('settings a')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "settings b" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + + self.assertTrue(style.removeLabelSettings("settings a")) self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'settings b') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - - self.assertTrue(style.removeTextFormat('format a')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "settings b" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + + self.assertTrue(style.removeTextFormat("format a")) self.assertEqual(model.rowCount(), 5) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'settings b') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - - self.assertTrue(style.removeColorRamp('ramp a')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "settings b" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + + self.assertTrue(style.removeColorRamp("ramp a")) self.assertEqual(model.rowCount(), 4) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'settings b') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - - self.assertTrue(style.removeSymbol('c')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "settings b" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + + self.assertTrue(style.removeSymbol("c")) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'settings b') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'settings c') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "settings b" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) def test_add_remove_legend_patch_shape(self): style = QgsStyle() @@ -921,107 +1435,237 @@ def test_add_remove_legend_patch_shape(self): model = QgsStyleModel(style) symbol = createMarkerSymbol() - self.assertTrue(style.addSymbol('a', symbol, True)) + self.assertTrue(style.addSymbol("a", symbol, True)) symbol = createMarkerSymbol() - self.assertTrue(style.addSymbol('c', symbol, True)) + self.assertTrue(style.addSymbol("c", symbol, True)) self.assertEqual(model.rowCount(), 2) ramp_a = QgsLimitedRandomColorRamp(5) - self.assertTrue(style.addColorRamp('ramp a', ramp_a, True)) + self.assertTrue(style.addColorRamp("ramp a", ramp_a, True)) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) format_a = QgsTextFormat() - self.assertTrue(style.addTextFormat('format a', format_a, True)) + self.assertTrue(style.addTextFormat("format a", format_a, True)) self.assertEqual(model.rowCount(), 4) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) settings_a = QgsPalLayerSettings() - self.assertTrue(style.addLabelSettings('settings a', settings_a, True)) + self.assertTrue(style.addLabelSettings("settings a", settings_a, True)) self.assertEqual(model.rowCount(), 5) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'settings a') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) shape_a = QgsLegendPatchShape() - self.assertTrue(style.addLegendPatchShape('shape a', shape_a, True)) + self.assertTrue(style.addLegendPatchShape("shape a", shape_a, True)) self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'shape a') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) shape_B = QgsLegendPatchShape() - self.assertTrue(style.addLegendPatchShape('shape c', shape_B, True)) + self.assertTrue(style.addLegendPatchShape("shape c", shape_B, True)) self.assertEqual(model.rowCount(), 7) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'shape c') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) shape_b = QgsLegendPatchShape() - self.assertTrue(style.addLegendPatchShape('shape b', shape_b, True)) + self.assertTrue(style.addLegendPatchShape("shape b", shape_b, True)) self.assertEqual(model.rowCount(), 8) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'shape b') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - - self.assertTrue(style.removeEntityByName(QgsStyle.StyleEntity.LegendPatchShapeEntity, 'shape a')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "shape b" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + + self.assertTrue( + style.removeEntityByName( + QgsStyle.StyleEntity.LegendPatchShapeEntity, "shape a" + ) + ) self.assertEqual(model.rowCount(), 7) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'shape b') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - - self.assertTrue(style.removeEntityByName(QgsStyle.StyleEntity.LabelSettingsEntity, 'settings a')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "shape b" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + + self.assertTrue( + style.removeEntityByName( + QgsStyle.StyleEntity.LabelSettingsEntity, "settings a" + ) + ) self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'shape b') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - - self.assertTrue(style.removeEntityByName(QgsStyle.StyleEntity.TextFormatEntity, 'format a')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "shape b" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + + self.assertTrue( + style.removeEntityByName(QgsStyle.StyleEntity.TextFormatEntity, "format a") + ) self.assertEqual(model.rowCount(), 5) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'shape b') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - - self.assertTrue(style.removeEntityByName(QgsStyle.StyleEntity.ColorrampEntity, 'ramp a')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "shape b" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + + self.assertTrue( + style.removeEntityByName(QgsStyle.StyleEntity.ColorrampEntity, "ramp a") + ) self.assertEqual(model.rowCount(), 4) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'shape b') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - - self.assertTrue(style.removeEntityByName(QgsStyle.StyleEntity.SymbolEntity, 'c')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "shape b" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + + self.assertTrue( + style.removeEntityByName(QgsStyle.StyleEntity.SymbolEntity, "c") + ) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'shape b') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'shape c') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "shape b" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) def test_add_symbol3d(self): style = QgsStyle() @@ -1029,131 +1673,297 @@ def test_add_symbol3d(self): model = QgsStyleModel(style) symbol = createMarkerSymbol() - self.assertTrue(style.addSymbol('a', symbol, True)) + self.assertTrue(style.addSymbol("a", symbol, True)) symbol = createMarkerSymbol() - self.assertTrue(style.addSymbol('c', symbol, True)) + self.assertTrue(style.addSymbol("c", symbol, True)) self.assertEqual(model.rowCount(), 2) ramp_a = QgsLimitedRandomColorRamp(5) - self.assertTrue(style.addColorRamp('ramp a', ramp_a, True)) + self.assertTrue(style.addColorRamp("ramp a", ramp_a, True)) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) format_a = QgsTextFormat() - self.assertTrue(style.addTextFormat('format a', format_a, True)) + self.assertTrue(style.addTextFormat("format a", format_a, True)) self.assertEqual(model.rowCount(), 4) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) settings_a = QgsPalLayerSettings() - self.assertTrue(style.addLabelSettings('settings a', settings_a, True)) + self.assertTrue(style.addLabelSettings("settings a", settings_a, True)) self.assertEqual(model.rowCount(), 5) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'settings a') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) shape_a = QgsLegendPatchShape() - self.assertTrue(style.addLegendPatchShape('shape a', shape_a, True)) + self.assertTrue(style.addLegendPatchShape("shape a", shape_a, True)) self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'shape a') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) symbol3d_a = Dummy3dSymbol() - self.assertTrue(style.addSymbol3D('symbol3d a', symbol3d_a, True)) + self.assertTrue(style.addSymbol3D("symbol3d a", symbol3d_a, True)) self.assertEqual(model.rowCount(), 7) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) symbol3d_B = Dummy3dSymbol() - self.assertTrue(style.addSymbol3D('symbol3d c', symbol3d_B, True)) + self.assertTrue(style.addSymbol3D("symbol3d c", symbol3d_B, True)) self.assertEqual(model.rowCount(), 8) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) symbol3d_b = Dummy3dSymbol() - self.assertTrue(style.addSymbol3D('symbol3d b', symbol3d_b, True)) + self.assertTrue(style.addSymbol3D("symbol3d b", symbol3d_b, True)) self.assertEqual(model.rowCount(), 9) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d b') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.removeEntityByName(QgsStyle.StyleEntity.Symbol3DEntity, 'symbol3d a')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "symbol3d b" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue( + style.removeEntityByName(QgsStyle.StyleEntity.Symbol3DEntity, "symbol3d a") + ) self.assertEqual(model.rowCount(), 8) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d b') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.removeEntityByName(QgsStyle.StyleEntity.LegendPatchShapeEntity, 'shape a')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "symbol3d b" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue( + style.removeEntityByName( + QgsStyle.StyleEntity.LegendPatchShapeEntity, "shape a" + ) + ) self.assertEqual(model.rowCount(), 7) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d b') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.removeEntityByName(QgsStyle.StyleEntity.LabelSettingsEntity, 'settings a')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "symbol3d b" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue( + style.removeEntityByName( + QgsStyle.StyleEntity.LabelSettingsEntity, "settings a" + ) + ) self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d b') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.removeEntityByName(QgsStyle.StyleEntity.TextFormatEntity, 'format a')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "symbol3d b" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue( + style.removeEntityByName(QgsStyle.StyleEntity.TextFormatEntity, "format a") + ) self.assertEqual(model.rowCount(), 5) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d b') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.removeEntityByName(QgsStyle.StyleEntity.ColorrampEntity, 'ramp a')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "symbol3d b" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue( + style.removeEntityByName(QgsStyle.StyleEntity.ColorrampEntity, "ramp a") + ) self.assertEqual(model.rowCount(), 4) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d b') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.removeEntityByName(QgsStyle.StyleEntity.SymbolEntity, 'c')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "symbol3d b" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue( + style.removeEntityByName(QgsStyle.StyleEntity.SymbolEntity, "c") + ) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d b') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "symbol3d b" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) def test_renamed(self): style = QgsStyle() @@ -1161,388 +1971,988 @@ def test_renamed(self): model = QgsStyleModel(style) symbol = createMarkerSymbol() - self.assertTrue(style.addSymbol('a', symbol, True)) + self.assertTrue(style.addSymbol("a", symbol, True)) symbol = createMarkerSymbol() - self.assertTrue(style.addSymbol('c', symbol, True)) + self.assertTrue(style.addSymbol("c", symbol, True)) ramp_a = QgsLimitedRandomColorRamp(5) - self.assertTrue(style.addColorRamp('ramp a', ramp_a, True)) + self.assertTrue(style.addColorRamp("ramp a", ramp_a, True)) symbol_B = QgsLimitedRandomColorRamp() - self.assertTrue(style.addColorRamp('ramp c', symbol_B, True)) + self.assertTrue(style.addColorRamp("ramp c", symbol_B, True)) format_a = QgsTextFormat() - self.assertTrue(style.addTextFormat('format a', format_a, True)) + self.assertTrue(style.addTextFormat("format a", format_a, True)) format_B = QgsTextFormat() - self.assertTrue(style.addTextFormat('format c', format_B, True)) + self.assertTrue(style.addTextFormat("format c", format_B, True)) settings_a = QgsPalLayerSettings() - self.assertTrue(style.addLabelSettings('settings a', settings_a, True)) + self.assertTrue(style.addLabelSettings("settings a", settings_a, True)) settings_B = QgsPalLayerSettings() - self.assertTrue(style.addLabelSettings('settings c', settings_B, True)) + self.assertTrue(style.addLabelSettings("settings c", settings_B, True)) shape_a = QgsLegendPatchShape() - self.assertTrue(style.addLegendPatchShape('shape a', shape_a, True)) + self.assertTrue(style.addLegendPatchShape("shape a", shape_a, True)) shape_B = QgsLegendPatchShape() - self.assertTrue(style.addLegendPatchShape('shape c', shape_B, True)) + self.assertTrue(style.addLegendPatchShape("shape c", shape_B, True)) symbol3d_a = Dummy3dSymbol() - self.assertTrue(style.addSymbol3D('symbol3d a', symbol3d_a, True)) + self.assertTrue(style.addSymbol3D("symbol3d a", symbol3d_a, True)) symbol3d_B = Dummy3dSymbol() - self.assertTrue(style.addSymbol3D('symbol3d c', symbol3d_B, True)) + self.assertTrue(style.addSymbol3D("symbol3d c", symbol3d_B, True)) self.assertEqual(model.rowCount(), 12) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'a') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp c') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format c') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameSymbol('a', 'b')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "a" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp c" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format c" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameSymbol("a", "b")) self.assertEqual(model.rowCount(), 12) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'b') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp c') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format c') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameSymbol('b', 'd')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "b" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp c" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format c" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameSymbol("b", "d")) self.assertEqual(model.rowCount(), 12) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'd') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp c') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format c') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameSymbol('d', 'e')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "d" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp c" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format c" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameSymbol("d", "e")) self.assertEqual(model.rowCount(), 12) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'c') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp c') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format c') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameSymbol('c', 'f')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "c" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp c" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format c" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameSymbol("c", "f")) self.assertEqual(model.rowCount(), 12) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp a') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp c') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format c') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameColorRamp('ramp a', 'ramp b')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp a" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp c" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format c" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameColorRamp("ramp a", "ramp b")) self.assertEqual(model.rowCount(), 12) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp b') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp c') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format c') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameColorRamp('ramp b', 'ramp d')) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp c') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp d') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format c') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameColorRamp('ramp d', 'ramp e')) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp c') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp e') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format c') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameColorRamp('ramp c', 'ramp f')) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp e') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp f') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format a') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format c') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameTextFormat('format a', 'format b')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp b" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp c" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format c" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameColorRamp("ramp b", "ramp d")) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp c" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp d" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format c" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameColorRamp("ramp d", "ramp e")) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp c" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp e" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format c" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameColorRamp("ramp c", "ramp f")) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp e" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp f" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format a" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format c" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameTextFormat("format a", "format b")) self.assertEqual(model.rowCount(), 12) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp e') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp f') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format b') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format c') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameTextFormat('format b', 'format d')) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp e') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp f') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format c') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format d') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameTextFormat('format d', 'format e')) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp e') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp f') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format c') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format e') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameTextFormat('format c', 'format f')) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp e') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp f') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format e') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format f') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings a') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameLabelSettings('settings a', 'settings b')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp e" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp f" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format b" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format c" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameTextFormat("format b", "format d")) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp e" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp f" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format c" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format d" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameTextFormat("format d", "format e")) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp e" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp f" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format c" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format e" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameTextFormat("format c", "format f")) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp e" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp f" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format e" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format f" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings a" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameLabelSettings("settings a", "settings b")) self.assertEqual(model.rowCount(), 12) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp e') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp f') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format e') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format f') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings b') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameLabelSettings('settings b', 'settings d')) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp e') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp f') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format e') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format f') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings d') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameLabelSettings('settings d', 'settings e')) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp e') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp f') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format e') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format f') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings c') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings e') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameLabelSettings('settings c', 'settings f')) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp e') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp f') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format e') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format f') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings e') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings f') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape a') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameLegendPatchShape('shape a', 'shape b')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp e" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp f" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format e" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format f" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings b" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameLabelSettings("settings b", "settings d")) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp e" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp f" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format e" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format f" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings d" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameLabelSettings("settings d", "settings e")) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp e" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp f" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format e" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format f" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings c" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings e" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameLabelSettings("settings c", "settings f")) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp e" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp f" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format e" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format f" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings e" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings f" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape a" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameLegendPatchShape("shape a", "shape b")) self.assertEqual(model.rowCount(), 12) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp e') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp f') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format e') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format f') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings e') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings f') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape b') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameLegendPatchShape('shape b', 'shape d')) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp e') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp f') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format e') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format f') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings e') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings f') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape d') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameLegendPatchShape('shape d', 'shape e')) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp e') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp f') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format e') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format f') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings e') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings f') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape c') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape e') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameLegendPatchShape('shape c', 'shape f')) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp e') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp f') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format e') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format f') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings e') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings f') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape e') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape f') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d a') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameSymbol3D('symbol3d a', 'symbol3d b')) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp e" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp f" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format e" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format f" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings e" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings f" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape b" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameLegendPatchShape("shape b", "shape d")) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp e" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp f" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format e" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format f" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings e" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings f" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape d" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameLegendPatchShape("shape d", "shape e")) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp e" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp f" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format e" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format f" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings e" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings f" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape c" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape e" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameLegendPatchShape("shape c", "shape f")) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp e" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp f" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format e" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format f" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings e" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings f" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape e" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape f" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d a" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameSymbol3D("symbol3d a", "symbol3d b")) self.assertEqual(model.rowCount(), 12) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp e') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp f') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format e') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format f') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings e') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings f') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape e') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape f') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d b') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - - self.assertTrue(style.renameSymbol3D('symbol3d b', 'symbol3d d')) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp e') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp f') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format e') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format f') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings e') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings f') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape e') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape f') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d d') - - self.assertTrue(style.renameSymbol3D('symbol3d d', 'symbol3d e')) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp e') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp f') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format e') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format f') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings e') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings f') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape e') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape f') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d c') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d e') - - self.assertTrue(style.renameSymbol3D('symbol3d c', 'symbol3d f')) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'e') - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'f') - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'ramp e') - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'ramp f') - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'format e') - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'format f') - self.assertEqual(model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), 'settings e') - self.assertEqual(model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), 'settings f') - self.assertEqual(model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), 'shape e') - self.assertEqual(model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), 'shape f') - self.assertEqual(model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d e') - self.assertEqual(model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d f') + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp e" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp f" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format e" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format f" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings e" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings f" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape e" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape f" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d b" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + + self.assertTrue(style.renameSymbol3D("symbol3d b", "symbol3d d")) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp e" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp f" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format e" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format f" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings e" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings f" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape e" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape f" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d d" + ) + + self.assertTrue(style.renameSymbol3D("symbol3d d", "symbol3d e")) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp e" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp f" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format e" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format f" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings e" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings f" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape e" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape f" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d c" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d e" + ) + + self.assertTrue(style.renameSymbol3D("symbol3d c", "symbol3d f")) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), "e" + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "f" + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), "ramp e" + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), "ramp f" + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "format e" + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), "format f" + ) + self.assertEqual( + model.data(model.index(6, 0), Qt.ItemDataRole.DisplayRole), "settings e" + ) + self.assertEqual( + model.data(model.index(7, 0), Qt.ItemDataRole.DisplayRole), "settings f" + ) + self.assertEqual( + model.data(model.index(8, 0), Qt.ItemDataRole.DisplayRole), "shape e" + ) + self.assertEqual( + model.data(model.index(9, 0), Qt.ItemDataRole.DisplayRole), "shape f" + ) + self.assertEqual( + model.data(model.index(10, 0), Qt.ItemDataRole.DisplayRole), "symbol3d e" + ) + self.assertEqual( + model.data(model.index(11, 0), Qt.ItemDataRole.DisplayRole), "symbol3d f" + ) def test_tags_changed(self): style = QgsStyle() @@ -1550,29 +2960,29 @@ def test_tags_changed(self): model = QgsStyleModel(style) symbol = createMarkerSymbol() - self.assertTrue(style.addSymbol('a', symbol, True)) + self.assertTrue(style.addSymbol("a", symbol, True)) symbol = createMarkerSymbol() - self.assertTrue(style.addSymbol('c', symbol, True)) + self.assertTrue(style.addSymbol("c", symbol, True)) ramp_a = QgsLimitedRandomColorRamp(5) - self.assertTrue(style.addColorRamp('ramp a', ramp_a, True)) + self.assertTrue(style.addColorRamp("ramp a", ramp_a, True)) symbol_B = QgsLimitedRandomColorRamp() - self.assertTrue(style.addColorRamp('ramp c', symbol_B, True)) + self.assertTrue(style.addColorRamp("ramp c", symbol_B, True)) format_a = QgsTextFormat() - self.assertTrue(style.addTextFormat('format a', format_a, True)) + self.assertTrue(style.addTextFormat("format a", format_a, True)) format_B = QgsTextFormat() - self.assertTrue(style.addTextFormat('format c', format_B, True)) + self.assertTrue(style.addTextFormat("format c", format_B, True)) format_a = QgsPalLayerSettings() - self.assertTrue(style.addLabelSettings('settings a', format_a, True)) + self.assertTrue(style.addLabelSettings("settings a", format_a, True)) format_B = QgsPalLayerSettings() - self.assertTrue(style.addLabelSettings('settings c', format_B, True)) + self.assertTrue(style.addLabelSettings("settings c", format_B, True)) shape_a = QgsLegendPatchShape() - self.assertTrue(style.addLegendPatchShape('shape a', shape_a, True)) + self.assertTrue(style.addLegendPatchShape("shape a", shape_a, True)) shape_B = QgsLegendPatchShape() - self.assertTrue(style.addLegendPatchShape('shape c', shape_B, True)) + self.assertTrue(style.addLegendPatchShape("shape c", shape_B, True)) symbol3d_a = Dummy3dSymbol() - self.assertTrue(style.addSymbol3D('symbol3d a', symbol3d_a, True)) + self.assertTrue(style.addSymbol3D("symbol3d a", symbol3d_a, True)) symbol3d_B = Dummy3dSymbol() - self.assertTrue(style.addSymbol3D('symbol3d c', symbol3d_B, True)) + self.assertTrue(style.addSymbol3D("symbol3d c", symbol3d_B, True)) self.assertFalse(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) @@ -1587,8 +2997,10 @@ def test_tags_changed(self): self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, 'a', ['t1', 't2']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, "a", ["t1", "t2"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole)) @@ -1601,8 +3013,10 @@ def test_tags_changed(self): self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, 'a', ['t3']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, "a", ["t3"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole)) @@ -1615,10 +3029,14 @@ def test_tags_changed(self): self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.tagSymbol(QgsStyle.StyleEntity.ColorrampEntity, 'ramp a', ['t1', 't2']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.tagSymbol(QgsStyle.StyleEntity.ColorrampEntity, "ramp a", ["t1", "t2"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) @@ -1629,11 +3047,17 @@ def test_tags_changed(self): self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.tagSymbol(QgsStyle.StyleEntity.ColorrampEntity, 'ramp c', ['t3']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.tagSymbol(QgsStyle.StyleEntity.ColorrampEntity, "ramp c", ["t3"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) self.assertFalse(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole)) @@ -1643,11 +3067,19 @@ def test_tags_changed(self): self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, 'c', ['t4']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') - self.assertEqual(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), 't4') - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') + style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, "c", ["t4"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) + self.assertEqual( + model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole), "t4" + ) + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) self.assertFalse(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole)) @@ -1657,11 +3089,17 @@ def test_tags_changed(self): self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.detagSymbol(QgsStyle.StyleEntity.SymbolEntity, 'c', ['t4']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.detagSymbol(QgsStyle.StyleEntity.SymbolEntity, "c", ["t4"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) self.assertFalse(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole)) @@ -1671,11 +3109,17 @@ def test_tags_changed(self): self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.detagSymbol(QgsStyle.StyleEntity.ColorrampEntity, 'ramp a', ['t1']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.detagSymbol(QgsStyle.StyleEntity.ColorrampEntity, "ramp a", ["t1"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) self.assertFalse(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole)) @@ -1685,12 +3129,20 @@ def test_tags_changed(self): self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.tagSymbol(QgsStyle.StyleEntity.TextFormatEntity, 'format a', ['t1', 't2']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.tagSymbol(QgsStyle.StyleEntity.TextFormatEntity, "format a", ["t1", "t2"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole)) @@ -1699,13 +3151,23 @@ def test_tags_changed(self): self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.tagSymbol(QgsStyle.StyleEntity.TextFormatEntity, 'format c', ['t3']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.tagSymbol(QgsStyle.StyleEntity.TextFormatEntity, "format c", ["t3"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') - self.assertEqual(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole), 't3') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) + self.assertEqual( + model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) self.assertFalse(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole)) @@ -1713,13 +3175,23 @@ def test_tags_changed(self): self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.tagSymbol(QgsStyle.StyleEntity.TextFormatEntity, 'c', ['t6']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.tagSymbol(QgsStyle.StyleEntity.TextFormatEntity, "c", ["t6"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') - self.assertEqual(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole), 't3') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) + self.assertEqual( + model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) self.assertFalse(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole)) @@ -1727,12 +3199,20 @@ def test_tags_changed(self): self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.detagSymbol(QgsStyle.StyleEntity.TextFormatEntity, 'format c', ['t3']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.detagSymbol(QgsStyle.StyleEntity.TextFormatEntity, "format c", ["t3"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole)) @@ -1741,228 +3221,440 @@ def test_tags_changed(self): self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.tagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, 'settings a', ['t1', 't2']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.tagSymbol( + QgsStyle.StyleEntity.LabelSettingsEntity, "settings a", ["t1", "t2"] + ) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(9, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.tagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, 'settings c', ['t3']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.tagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, "settings c", ["t3"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') - self.assertEqual(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole), 't3') + self.assertEqual( + model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) + self.assertEqual( + model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) self.assertFalse(model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(9, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.tagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, 'c', ['t7']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.tagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, "c", ["t7"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') - self.assertEqual(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole), 't3') + self.assertEqual( + model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) + self.assertEqual( + model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) self.assertFalse(model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(9, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.detagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, 'settings c', ['t3']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.detagSymbol( + QgsStyle.StyleEntity.LabelSettingsEntity, "settings c", ["t3"] + ) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(9, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.tagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, 'settings a', ['t1', 't2']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.tagSymbol( + QgsStyle.StyleEntity.LabelSettingsEntity, "settings a", ["t1", "t2"] + ) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(9, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.tagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, 'settings c', ['t3']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.tagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, "settings c", ["t3"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') - self.assertEqual(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole), 't3') + self.assertEqual( + model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) + self.assertEqual( + model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) self.assertFalse(model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(9, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.tagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, 'c', ['t7']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.tagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, "c", ["t7"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') - self.assertEqual(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole), 't3') + self.assertEqual( + model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) + self.assertEqual( + model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) self.assertFalse(model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(9, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.detagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, 'settings c', ['t3']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.detagSymbol( + QgsStyle.StyleEntity.LabelSettingsEntity, "settings c", ["t3"] + ) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(9, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.tagSymbol(QgsStyle.StyleEntity.LegendPatchShapeEntity, 'shape a', ['t1', 't2']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.tagSymbol( + QgsStyle.StyleEntity.LegendPatchShapeEntity, "shape a", ["t1", "t2"] + ) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(9, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.tagSymbol(QgsStyle.StyleEntity.LegendPatchShapeEntity, 'shape c', ['t3']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.tagSymbol(QgsStyle.StyleEntity.LegendPatchShapeEntity, "shape c", ["t3"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') - self.assertEqual(model.data(model.index(9, 1), Qt.ItemDataRole.DisplayRole), 't3') + self.assertEqual( + model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) + self.assertEqual( + model.data(model.index(9, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.tagSymbol(QgsStyle.StyleEntity.LegendPatchShapeEntity, 'c', ['t7']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.tagSymbol(QgsStyle.StyleEntity.LegendPatchShapeEntity, "c", ["t7"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') - self.assertEqual(model.data(model.index(9, 1), Qt.ItemDataRole.DisplayRole), 't3') + self.assertEqual( + model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) + self.assertEqual( + model.data(model.index(9, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.detagSymbol(QgsStyle.StyleEntity.LegendPatchShapeEntity, 'shape c', ['t3']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.detagSymbol( + QgsStyle.StyleEntity.LegendPatchShapeEntity, "shape c", ["t3"] + ) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(9, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole)) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.tagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, 'symbol3d a', ['t1', 't2']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.tagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, "symbol3d a", ["t1", "t2"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(9, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) - style.tagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, 'symbol3d c', ['t3']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + style.tagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, "symbol3d c", ["t3"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(9, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') - self.assertEqual(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole), 't3') - - style.tagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, 'c', ['t7']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + self.assertEqual( + model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) + self.assertEqual( + model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + + style.tagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, "c", ["t7"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(9, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') - self.assertEqual(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole), 't3') - - style.detagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, 'symbol3d c', ['t3']) - self.assertEqual(model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), 't1, t2, t3') + self.assertEqual( + model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) + self.assertEqual( + model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + + style.detagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, "symbol3d c", ["t3"]) + self.assertEqual( + model.data(model.index(0, 1), Qt.ItemDataRole.DisplayRole), "t1, t2, t3" + ) self.assertFalse(model.data(model.index(1, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), 't2') - self.assertEqual(model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), 't3') - self.assertEqual(model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(2, 1), Qt.ItemDataRole.DisplayRole), "t2" + ) + self.assertEqual( + model.data(model.index(3, 1), Qt.ItemDataRole.DisplayRole), "t3" + ) + self.assertEqual( + model.data(model.index(4, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(5, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(6, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(7, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(8, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(9, 1), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole), 't1, t2') + self.assertEqual( + model.data(model.index(10, 1), Qt.ItemDataRole.DisplayRole), "t1, t2" + ) self.assertFalse(model.data(model.index(11, 1), Qt.ItemDataRole.DisplayRole)) def test_filter_proxy(self): @@ -1971,123 +3663,139 @@ def test_filter_proxy(self): symbol_a = createMarkerSymbol() symbol_a.setColor(QColor(255, 10, 10)) - self.assertTrue(style.addSymbol('a', symbol_a, True)) - style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, 'a', ['tag 1', 'tag 2']) + self.assertTrue(style.addSymbol("a", symbol_a, True)) + style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, "a", ["tag 1", "tag 2"]) symbol_B = createMarkerSymbol() symbol_B.setColor(QColor(10, 255, 10)) - self.assertTrue(style.addSymbol('BB', symbol_B, True)) + self.assertTrue(style.addSymbol("BB", symbol_B, True)) symbol_b = createFillSymbol() symbol_b.setColor(QColor(10, 255, 10)) - self.assertTrue(style.addSymbol('b', symbol_b, True)) + self.assertTrue(style.addSymbol("b", symbol_b, True)) symbol_C = createLineSymbol() symbol_C.setColor(QColor(10, 255, 10)) - self.assertTrue(style.addSymbol('C', symbol_C, True)) - style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, 'C', ['tag 3']) + self.assertTrue(style.addSymbol("C", symbol_C, True)) + style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, "C", ["tag 3"]) symbol_C = createMarkerSymbol() symbol_C.setColor(QColor(10, 255, 10)) - self.assertTrue(style.addSymbol('another', symbol_C, True)) + self.assertTrue(style.addSymbol("another", symbol_C, True)) ramp_a = QgsLimitedRandomColorRamp(5) - self.assertTrue(style.addColorRamp('ramp a', ramp_a, True)) - style.tagSymbol(QgsStyle.StyleEntity.ColorrampEntity, 'ramp a', ['tag 1', 'tag 2']) + self.assertTrue(style.addColorRamp("ramp a", ramp_a, True)) + style.tagSymbol( + QgsStyle.StyleEntity.ColorrampEntity, "ramp a", ["tag 1", "tag 2"] + ) symbol_B = QgsLimitedRandomColorRamp() - self.assertTrue(style.addColorRamp('ramp BB', symbol_B, True)) + self.assertTrue(style.addColorRamp("ramp BB", symbol_B, True)) symbol_b = QgsLimitedRandomColorRamp() - self.assertTrue(style.addColorRamp('ramp c', symbol_b, True)) + self.assertTrue(style.addColorRamp("ramp c", symbol_b, True)) format_a = QgsTextFormat() - self.assertTrue(style.addTextFormat('format a', format_a, True)) - style.tagSymbol(QgsStyle.StyleEntity.TextFormatEntity, 'format a', ['tag 1', 'tag 2']) + self.assertTrue(style.addTextFormat("format a", format_a, True)) + style.tagSymbol( + QgsStyle.StyleEntity.TextFormatEntity, "format a", ["tag 1", "tag 2"] + ) format_B = QgsTextFormat() - self.assertTrue(style.addTextFormat('format BB', format_B, True)) + self.assertTrue(style.addTextFormat("format BB", format_B, True)) format_b = QgsTextFormat() - self.assertTrue(style.addTextFormat('format c', format_b, True)) + self.assertTrue(style.addTextFormat("format c", format_b, True)) format_a = QgsPalLayerSettings() format_a.layerType = QgsWkbTypes.GeometryType.PointGeometry - self.assertTrue(style.addLabelSettings('settings a', format_a, True)) - style.tagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, 'settings a', ['tag 1', 'tag 2']) + self.assertTrue(style.addLabelSettings("settings a", format_a, True)) + style.tagSymbol( + QgsStyle.StyleEntity.LabelSettingsEntity, "settings a", ["tag 1", "tag 2"] + ) format_B = QgsPalLayerSettings() format_B.layerType = QgsWkbTypes.GeometryType.LineGeometry - self.assertTrue(style.addLabelSettings('settings BB', format_B, True)) + self.assertTrue(style.addLabelSettings("settings BB", format_B, True)) format_b = QgsPalLayerSettings() format_b.layerType = QgsWkbTypes.GeometryType.LineGeometry - self.assertTrue(style.addLabelSettings('settings c', format_b, True)) - - shape_a = QgsLegendPatchShape(QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt('Point( 4 5 )')) - self.assertTrue(style.addLegendPatchShape('shape a', shape_a, True)) - style.tagSymbol(QgsStyle.StyleEntity.LegendPatchShapeEntity, 'shape a', ['tag 1', 'tag 2']) - shape_B = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString( 4 5, 6 5 )')) - self.assertTrue(style.addLegendPatchShape('shape BB', shape_B, True)) - shape_b = QgsLegendPatchShape(QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt('LineString( 14 5, 6 5 )')) - self.assertTrue(style.addLegendPatchShape('shape c', shape_b, True)) + self.assertTrue(style.addLabelSettings("settings c", format_b, True)) + + shape_a = QgsLegendPatchShape( + QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt("Point( 4 5 )") + ) + self.assertTrue(style.addLegendPatchShape("shape a", shape_a, True)) + style.tagSymbol( + QgsStyle.StyleEntity.LegendPatchShapeEntity, "shape a", ["tag 1", "tag 2"] + ) + shape_B = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt("LineString( 4 5, 6 5 )") + ) + self.assertTrue(style.addLegendPatchShape("shape BB", shape_B, True)) + shape_b = QgsLegendPatchShape( + QgsSymbol.SymbolType.Line, QgsGeometry.fromWkt("LineString( 14 5, 6 5 )") + ) + self.assertTrue(style.addLegendPatchShape("shape c", shape_b, True)) symbol3d_a = Dummy3dSymbol() - self.assertTrue(style.addSymbol3D('sym3d a', symbol3d_a, True)) - style.tagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, 'sym3d a', ['tag 1', 'tag 2']) + self.assertTrue(style.addSymbol3D("sym3d a", symbol3d_a, True)) + style.tagSymbol( + QgsStyle.StyleEntity.Symbol3DEntity, "sym3d a", ["tag 1", "tag 2"] + ) symbol3d_B = Dummy3dSymbol() symbol3d_B.layer_types = [QgsWkbTypes.GeometryType.PolygonGeometry] - self.assertTrue(style.addSymbol3D('sym3d BB', symbol3d_B, True)) + self.assertTrue(style.addSymbol3D("sym3d BB", symbol3d_B, True)) symbol3d_B = Dummy3dSymbol() symbol3d_B.layer_types = [QgsWkbTypes.GeometryType.LineGeometry] - self.assertTrue(style.addSymbol3D('sym3d c', symbol3d_B, True)) + self.assertTrue(style.addSymbol3D("sym3d c", symbol3d_B, True)) model = QgsStyleProxyModel(style) self.assertEqual(model.rowCount(), 20) # filter string - model.setFilterString('xx') - self.assertEqual(model.filterString(), 'xx') + model.setFilterString("xx") + self.assertEqual(model.filterString(), "xx") self.assertEqual(model.rowCount(), 0) - model.setFilterString('b') + model.setFilterString("b") self.assertEqual(model.rowCount(), 7) - self.assertEqual(model.data(model.index(0, 0)), 'b') - self.assertEqual(model.data(model.index(1, 0)), 'BB') - self.assertEqual(model.data(model.index(2, 0)), 'format BB') - self.assertEqual(model.data(model.index(3, 0)), 'ramp BB') - self.assertEqual(model.data(model.index(4, 0)), 'settings BB') - self.assertEqual(model.data(model.index(5, 0)), 'shape BB') - self.assertEqual(model.data(model.index(6, 0)), 'sym3d BB') - model.setFilterString('bb') + self.assertEqual(model.data(model.index(0, 0)), "b") + self.assertEqual(model.data(model.index(1, 0)), "BB") + self.assertEqual(model.data(model.index(2, 0)), "format BB") + self.assertEqual(model.data(model.index(3, 0)), "ramp BB") + self.assertEqual(model.data(model.index(4, 0)), "settings BB") + self.assertEqual(model.data(model.index(5, 0)), "shape BB") + self.assertEqual(model.data(model.index(6, 0)), "sym3d BB") + model.setFilterString("bb") self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0)), 'BB') - self.assertEqual(model.data(model.index(1, 0)), 'format BB') - self.assertEqual(model.data(model.index(2, 0)), 'ramp BB') - self.assertEqual(model.data(model.index(3, 0)), 'settings BB') - self.assertEqual(model.data(model.index(4, 0)), 'shape BB') - self.assertEqual(model.data(model.index(5, 0)), 'sym3d BB') - model.setFilterString('tag 1') + self.assertEqual(model.data(model.index(0, 0)), "BB") + self.assertEqual(model.data(model.index(1, 0)), "format BB") + self.assertEqual(model.data(model.index(2, 0)), "ramp BB") + self.assertEqual(model.data(model.index(3, 0)), "settings BB") + self.assertEqual(model.data(model.index(4, 0)), "shape BB") + self.assertEqual(model.data(model.index(5, 0)), "sym3d BB") + model.setFilterString("tag 1") self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0)), 'a') - self.assertEqual(model.data(model.index(1, 0)), 'format a') - self.assertEqual(model.data(model.index(2, 0)), 'ramp a') - self.assertEqual(model.data(model.index(3, 0)), 'settings a') - self.assertEqual(model.data(model.index(4, 0)), 'shape a') - self.assertEqual(model.data(model.index(5, 0)), 'sym3d a') - model.setFilterString('TAG 1') + self.assertEqual(model.data(model.index(0, 0)), "a") + self.assertEqual(model.data(model.index(1, 0)), "format a") + self.assertEqual(model.data(model.index(2, 0)), "ramp a") + self.assertEqual(model.data(model.index(3, 0)), "settings a") + self.assertEqual(model.data(model.index(4, 0)), "shape a") + self.assertEqual(model.data(model.index(5, 0)), "sym3d a") + model.setFilterString("TAG 1") self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0)), 'a') - self.assertEqual(model.data(model.index(1, 0)), 'format a') - self.assertEqual(model.data(model.index(2, 0)), 'ramp a') - self.assertEqual(model.data(model.index(3, 0)), 'settings a') - self.assertEqual(model.data(model.index(4, 0)), 'shape a') - self.assertEqual(model.data(model.index(5, 0)), 'sym3d a') - model.setFilterString('ram b') + self.assertEqual(model.data(model.index(0, 0)), "a") + self.assertEqual(model.data(model.index(1, 0)), "format a") + self.assertEqual(model.data(model.index(2, 0)), "ramp a") + self.assertEqual(model.data(model.index(3, 0)), "settings a") + self.assertEqual(model.data(model.index(4, 0)), "shape a") + self.assertEqual(model.data(model.index(5, 0)), "sym3d a") + model.setFilterString("ram b") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'ramp BB') - model.setFilterString('mat b') + self.assertEqual(model.data(model.index(0, 0)), "ramp BB") + model.setFilterString("mat b") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'format BB') - model.setFilterString('ta ram') # match ta -> "tag 1", ram -> "ramp a" + self.assertEqual(model.data(model.index(0, 0)), "format BB") + model.setFilterString("ta ram") # match ta -> "tag 1", ram -> "ramp a" self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'ramp a') - model.setFilterString('ta ings') + self.assertEqual(model.data(model.index(0, 0)), "ramp a") + model.setFilterString("ta ings") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'settings a') - model.setFilterString('ta hap') + self.assertEqual(model.data(model.index(0, 0)), "settings a") + model.setFilterString("ta hap") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'shape a') - model.setFilterString('ta 3d') + self.assertEqual(model.data(model.index(0, 0)), "shape a") + model.setFilterString("ta 3d") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'sym3d a') - model.setFilterString('') + self.assertEqual(model.data(model.index(0, 0)), "sym3d a") + model.setFilterString("") self.assertEqual(model.rowCount(), 20) # entity type @@ -2099,65 +3807,65 @@ def test_filter_proxy(self): self.assertEqual(model.rowCount(), 20) model.setEntityFilterEnabled(True) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0)), 'ramp a') - self.assertEqual(model.data(model.index(1, 0)), 'ramp BB') - self.assertEqual(model.data(model.index(2, 0)), 'ramp c') - model.setFilterString('BB') + self.assertEqual(model.data(model.index(0, 0)), "ramp a") + self.assertEqual(model.data(model.index(1, 0)), "ramp BB") + self.assertEqual(model.data(model.index(2, 0)), "ramp c") + model.setFilterString("BB") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'ramp BB') - model.setFilterString('') + self.assertEqual(model.data(model.index(0, 0)), "ramp BB") + model.setFilterString("") model.setEntityFilter(QgsStyle.StyleEntity.SymbolEntity) self.assertEqual(model.rowCount(), 5) - self.assertEqual(model.data(model.index(0, 0)), 'a') - self.assertEqual(model.data(model.index(1, 0)), 'another') - self.assertEqual(model.data(model.index(2, 0)), 'b') - self.assertEqual(model.data(model.index(3, 0)), 'BB') - self.assertEqual(model.data(model.index(4, 0)), 'C') - model.setFilterString('ot') + self.assertEqual(model.data(model.index(0, 0)), "a") + self.assertEqual(model.data(model.index(1, 0)), "another") + self.assertEqual(model.data(model.index(2, 0)), "b") + self.assertEqual(model.data(model.index(3, 0)), "BB") + self.assertEqual(model.data(model.index(4, 0)), "C") + model.setFilterString("ot") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'another') - model.setFilterString('') + self.assertEqual(model.data(model.index(0, 0)), "another") + model.setFilterString("") model.setEntityFilter(QgsStyle.StyleEntity.TextFormatEntity) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0)), 'format a') - self.assertEqual(model.data(model.index(1, 0)), 'format BB') - self.assertEqual(model.data(model.index(2, 0)), 'format c') - model.setFilterString('BB') + self.assertEqual(model.data(model.index(0, 0)), "format a") + self.assertEqual(model.data(model.index(1, 0)), "format BB") + self.assertEqual(model.data(model.index(2, 0)), "format c") + model.setFilterString("BB") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'format BB') - model.setFilterString('') + self.assertEqual(model.data(model.index(0, 0)), "format BB") + model.setFilterString("") model.setEntityFilter(QgsStyle.StyleEntity.LabelSettingsEntity) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0)), 'settings a') - self.assertEqual(model.data(model.index(1, 0)), 'settings BB') - self.assertEqual(model.data(model.index(2, 0)), 'settings c') - model.setFilterString('BB') + self.assertEqual(model.data(model.index(0, 0)), "settings a") + self.assertEqual(model.data(model.index(1, 0)), "settings BB") + self.assertEqual(model.data(model.index(2, 0)), "settings c") + model.setFilterString("BB") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'settings BB') - model.setFilterString('') + self.assertEqual(model.data(model.index(0, 0)), "settings BB") + model.setFilterString("") model.setEntityFilter(QgsStyle.StyleEntity.LegendPatchShapeEntity) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0)), 'shape a') - self.assertEqual(model.data(model.index(1, 0)), 'shape BB') - self.assertEqual(model.data(model.index(2, 0)), 'shape c') - model.setFilterString('BB') + self.assertEqual(model.data(model.index(0, 0)), "shape a") + self.assertEqual(model.data(model.index(1, 0)), "shape BB") + self.assertEqual(model.data(model.index(2, 0)), "shape c") + model.setFilterString("BB") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'shape BB') - model.setFilterString('') + self.assertEqual(model.data(model.index(0, 0)), "shape BB") + model.setFilterString("") model.setEntityFilter(QgsStyle.StyleEntity.Symbol3DEntity) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0)), 'sym3d a') - self.assertEqual(model.data(model.index(1, 0)), 'sym3d BB') - self.assertEqual(model.data(model.index(2, 0)), 'sym3d c') - model.setFilterString('BB') + self.assertEqual(model.data(model.index(0, 0)), "sym3d a") + self.assertEqual(model.data(model.index(1, 0)), "sym3d BB") + self.assertEqual(model.data(model.index(2, 0)), "sym3d c") + model.setFilterString("BB") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'sym3d BB') - model.setFilterString('') + self.assertEqual(model.data(model.index(0, 0)), "sym3d BB") + model.setFilterString("") model.setEntityFilter(QgsStyle.StyleEntity.SymbolEntity) model.setEntityFilterEnabled(False) @@ -2170,431 +3878,439 @@ def test_filter_proxy(self): self.assertEqual(model.rowCount(), 20) model.setSymbolTypeFilterEnabled(True) self.assertEqual(model.rowCount(), 16) - self.assertEqual(model.data(model.index(0, 0)), 'a') - self.assertEqual(model.data(model.index(1, 0)), 'another') - self.assertEqual(model.data(model.index(2, 0)), 'BB') - self.assertEqual(model.data(model.index(3, 0)), 'format a') - self.assertEqual(model.data(model.index(4, 0)), 'format BB') - self.assertEqual(model.data(model.index(5, 0)), 'format c') - self.assertEqual(model.data(model.index(6, 0)), 'ramp a') - self.assertEqual(model.data(model.index(7, 0)), 'ramp BB') - self.assertEqual(model.data(model.index(8, 0)), 'ramp c') - self.assertEqual(model.data(model.index(9, 0)), 'settings a') - self.assertEqual(model.data(model.index(10, 0)), 'settings BB') - self.assertEqual(model.data(model.index(11, 0)), 'settings c') - self.assertEqual(model.data(model.index(12, 0)), 'shape a') - self.assertEqual(model.data(model.index(13, 0)), 'sym3d a') - self.assertEqual(model.data(model.index(14, 0)), 'sym3d BB') - self.assertEqual(model.data(model.index(15, 0)), 'sym3d c') + self.assertEqual(model.data(model.index(0, 0)), "a") + self.assertEqual(model.data(model.index(1, 0)), "another") + self.assertEqual(model.data(model.index(2, 0)), "BB") + self.assertEqual(model.data(model.index(3, 0)), "format a") + self.assertEqual(model.data(model.index(4, 0)), "format BB") + self.assertEqual(model.data(model.index(5, 0)), "format c") + self.assertEqual(model.data(model.index(6, 0)), "ramp a") + self.assertEqual(model.data(model.index(7, 0)), "ramp BB") + self.assertEqual(model.data(model.index(8, 0)), "ramp c") + self.assertEqual(model.data(model.index(9, 0)), "settings a") + self.assertEqual(model.data(model.index(10, 0)), "settings BB") + self.assertEqual(model.data(model.index(11, 0)), "settings c") + self.assertEqual(model.data(model.index(12, 0)), "shape a") + self.assertEqual(model.data(model.index(13, 0)), "sym3d a") + self.assertEqual(model.data(model.index(14, 0)), "sym3d BB") + self.assertEqual(model.data(model.index(15, 0)), "sym3d c") model.setEntityFilterEnabled(True) self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0)), 'a') - self.assertEqual(model.data(model.index(1, 0)), 'another') - self.assertEqual(model.data(model.index(2, 0)), 'BB') - model.setFilterString('oth') + self.assertEqual(model.data(model.index(0, 0)), "a") + self.assertEqual(model.data(model.index(1, 0)), "another") + self.assertEqual(model.data(model.index(2, 0)), "BB") + model.setFilterString("oth") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'another') + self.assertEqual(model.data(model.index(0, 0)), "another") model.setEntityFilterEnabled(False) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'another') + self.assertEqual(model.data(model.index(0, 0)), "another") model.setEntityFilterEnabled(True) - model.setFilterString('') + model.setFilterString("") model.setSymbolType(QgsSymbol.SymbolType.Line) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'C') + self.assertEqual(model.data(model.index(0, 0)), "C") model.setSymbolType(QgsSymbol.SymbolType.Fill) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'b') + self.assertEqual(model.data(model.index(0, 0)), "b") model.setEntityFilter(QgsStyle.StyleEntity.LegendPatchShapeEntity) model.setSymbolType(QgsSymbol.SymbolType.Marker) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'shape a') + self.assertEqual(model.data(model.index(0, 0)), "shape a") model.setSymbolType(QgsSymbol.SymbolType.Line) self.assertEqual(model.rowCount(), 2) - self.assertEqual(model.data(model.index(0, 0)), 'shape BB') - self.assertEqual(model.data(model.index(1, 0)), 'shape c') - model.setFilterString('BB') + self.assertEqual(model.data(model.index(0, 0)), "shape BB") + self.assertEqual(model.data(model.index(1, 0)), "shape c") + model.setFilterString("BB") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'shape BB') + self.assertEqual(model.data(model.index(0, 0)), "shape BB") - model.setFilterString('') + model.setFilterString("") model.setSymbolTypeFilterEnabled(False) model.setEntityFilterEnabled(False) self.assertEqual(model.rowCount(), 20) # tag id filter self.assertEqual(model.tagId(), -1) - tag_1_id = style.tagId('tag 1') - tag_3_id = style.tagId('tag 3') + tag_1_id = style.tagId("tag 1") + tag_3_id = style.tagId("tag 3") model.setTagId(tag_1_id) self.assertEqual(model.tagId(), tag_1_id) self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0)), 'a') - self.assertEqual(model.data(model.index(1, 0)), 'format a') - self.assertEqual(model.data(model.index(2, 0)), 'ramp a') - self.assertEqual(model.data(model.index(3, 0)), 'settings a') - self.assertEqual(model.data(model.index(4, 0)), 'shape a') - self.assertEqual(model.data(model.index(5, 0)), 'sym3d a') + self.assertEqual(model.data(model.index(0, 0)), "a") + self.assertEqual(model.data(model.index(1, 0)), "format a") + self.assertEqual(model.data(model.index(2, 0)), "ramp a") + self.assertEqual(model.data(model.index(3, 0)), "settings a") + self.assertEqual(model.data(model.index(4, 0)), "shape a") + self.assertEqual(model.data(model.index(5, 0)), "sym3d a") model.setEntityFilterEnabled(True) model.setEntityFilter(QgsStyle.StyleEntity.ColorrampEntity) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'ramp a') + self.assertEqual(model.data(model.index(0, 0)), "ramp a") model.setEntityFilter(QgsStyle.StyleEntity.TextFormatEntity) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'format a') + self.assertEqual(model.data(model.index(0, 0)), "format a") model.setEntityFilter(QgsStyle.StyleEntity.LabelSettingsEntity) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'settings a') + self.assertEqual(model.data(model.index(0, 0)), "settings a") model.setEntityFilter(QgsStyle.StyleEntity.LegendPatchShapeEntity) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'shape a') + self.assertEqual(model.data(model.index(0, 0)), "shape a") model.setEntityFilter(QgsStyle.StyleEntity.Symbol3DEntity) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'sym3d a') + self.assertEqual(model.data(model.index(0, 0)), "sym3d a") model.setEntityFilterEnabled(False) - model.setFilterString('ra') + model.setFilterString("ra") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'ramp a') - model.setFilterString('for') + self.assertEqual(model.data(model.index(0, 0)), "ramp a") + model.setFilterString("for") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'format a') - model.setFilterString('set') + self.assertEqual(model.data(model.index(0, 0)), "format a") + model.setFilterString("set") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'settings a') - model.setFilterString('hap') + self.assertEqual(model.data(model.index(0, 0)), "settings a") + model.setFilterString("hap") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'shape a') - model.setFilterString('3d') + self.assertEqual(model.data(model.index(0, 0)), "shape a") + model.setFilterString("3d") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'sym3d a') + self.assertEqual(model.data(model.index(0, 0)), "sym3d a") model.setEntityFilterEnabled(False) - model.setFilterString('') + model.setFilterString("") model.setTagId(-1) self.assertEqual(model.rowCount(), 20) model.setTagId(tag_3_id) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'C') - style.tagSymbol(QgsStyle.StyleEntity.ColorrampEntity, 'ramp c', ['tag 3']) + self.assertEqual(model.data(model.index(0, 0)), "C") + style.tagSymbol(QgsStyle.StyleEntity.ColorrampEntity, "ramp c", ["tag 3"]) self.assertEqual(model.rowCount(), 2) - self.assertEqual(model.data(model.index(0, 0)), 'C') - self.assertEqual(model.data(model.index(1, 0)), 'ramp c') - style.detagSymbol(QgsStyle.StyleEntity.ColorrampEntity, 'ramp c') + self.assertEqual(model.data(model.index(0, 0)), "C") + self.assertEqual(model.data(model.index(1, 0)), "ramp c") + style.detagSymbol(QgsStyle.StyleEntity.ColorrampEntity, "ramp c") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'C') - style.tagSymbol(QgsStyle.StyleEntity.TextFormatEntity, 'format c', ['tag 3']) + self.assertEqual(model.data(model.index(0, 0)), "C") + style.tagSymbol(QgsStyle.StyleEntity.TextFormatEntity, "format c", ["tag 3"]) self.assertEqual(model.rowCount(), 2) - self.assertEqual(model.data(model.index(0, 0)), 'C') - self.assertEqual(model.data(model.index(1, 0)), 'format c') - style.detagSymbol(QgsStyle.StyleEntity.TextFormatEntity, 'format c') + self.assertEqual(model.data(model.index(0, 0)), "C") + self.assertEqual(model.data(model.index(1, 0)), "format c") + style.detagSymbol(QgsStyle.StyleEntity.TextFormatEntity, "format c") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'C') - style.tagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, 'settings c', ['tag 3']) + self.assertEqual(model.data(model.index(0, 0)), "C") + style.tagSymbol( + QgsStyle.StyleEntity.LabelSettingsEntity, "settings c", ["tag 3"] + ) self.assertEqual(model.rowCount(), 2) - self.assertEqual(model.data(model.index(0, 0)), 'C') - self.assertEqual(model.data(model.index(1, 0)), 'settings c') - style.detagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, 'settings c') - style.tagSymbol(QgsStyle.StyleEntity.LegendPatchShapeEntity, 'shape c', ['tag 3']) + self.assertEqual(model.data(model.index(0, 0)), "C") + self.assertEqual(model.data(model.index(1, 0)), "settings c") + style.detagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, "settings c") + style.tagSymbol( + QgsStyle.StyleEntity.LegendPatchShapeEntity, "shape c", ["tag 3"] + ) self.assertEqual(model.rowCount(), 2) - self.assertEqual(model.data(model.index(0, 0)), 'C') - self.assertEqual(model.data(model.index(1, 0)), 'shape c') - style.detagSymbol(QgsStyle.StyleEntity.LegendPatchShapeEntity, 'shape c') - style.tagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, 'sym3d c', ['tag 3']) + self.assertEqual(model.data(model.index(0, 0)), "C") + self.assertEqual(model.data(model.index(1, 0)), "shape c") + style.detagSymbol(QgsStyle.StyleEntity.LegendPatchShapeEntity, "shape c") + style.tagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, "sym3d c", ["tag 3"]) self.assertEqual(model.rowCount(), 2) - self.assertEqual(model.data(model.index(0, 0)), 'C') - self.assertEqual(model.data(model.index(1, 0)), 'sym3d c') - style.detagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, 'sym3d c') + self.assertEqual(model.data(model.index(0, 0)), "C") + self.assertEqual(model.data(model.index(1, 0)), "sym3d c") + style.detagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, "sym3d c") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'C') + self.assertEqual(model.data(model.index(0, 0)), "C") model.setTagId(-1) self.assertEqual(model.rowCount(), 20) # tag string filter self.assertFalse(model.tagString()) - model.setTagString('tag 1') - self.assertEqual(model.tagString(), 'tag 1') + model.setTagString("tag 1") + self.assertEqual(model.tagString(), "tag 1") self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0)), 'a') - self.assertEqual(model.data(model.index(1, 0)), 'format a') - self.assertEqual(model.data(model.index(2, 0)), 'ramp a') - self.assertEqual(model.data(model.index(3, 0)), 'settings a') - self.assertEqual(model.data(model.index(4, 0)), 'shape a') - self.assertEqual(model.data(model.index(5, 0)), 'sym3d a') + self.assertEqual(model.data(model.index(0, 0)), "a") + self.assertEqual(model.data(model.index(1, 0)), "format a") + self.assertEqual(model.data(model.index(2, 0)), "ramp a") + self.assertEqual(model.data(model.index(3, 0)), "settings a") + self.assertEqual(model.data(model.index(4, 0)), "shape a") + self.assertEqual(model.data(model.index(5, 0)), "sym3d a") model.setEntityFilterEnabled(True) model.setEntityFilter(QgsStyle.StyleEntity.ColorrampEntity) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'ramp a') + self.assertEqual(model.data(model.index(0, 0)), "ramp a") model.setEntityFilter(QgsStyle.StyleEntity.TextFormatEntity) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'format a') + self.assertEqual(model.data(model.index(0, 0)), "format a") model.setEntityFilter(QgsStyle.StyleEntity.LabelSettingsEntity) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'settings a') + self.assertEqual(model.data(model.index(0, 0)), "settings a") model.setEntityFilter(QgsStyle.StyleEntity.LegendPatchShapeEntity) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'shape a') + self.assertEqual(model.data(model.index(0, 0)), "shape a") model.setEntityFilter(QgsStyle.StyleEntity.Symbol3DEntity) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'sym3d a') + self.assertEqual(model.data(model.index(0, 0)), "sym3d a") model.setEntityFilterEnabled(False) - model.setFilterString('ra') + model.setFilterString("ra") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'ramp a') - model.setFilterString('for') + self.assertEqual(model.data(model.index(0, 0)), "ramp a") + model.setFilterString("for") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'format a') - model.setFilterString('set') + self.assertEqual(model.data(model.index(0, 0)), "format a") + model.setFilterString("set") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'settings a') - model.setFilterString('hap') + self.assertEqual(model.data(model.index(0, 0)), "settings a") + model.setFilterString("hap") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'shape a') - model.setFilterString('3d') + self.assertEqual(model.data(model.index(0, 0)), "shape a") + model.setFilterString("3d") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'sym3d a') + self.assertEqual(model.data(model.index(0, 0)), "sym3d a") model.setEntityFilterEnabled(False) - model.setFilterString('') - model.setTagString('') + model.setFilterString("") + model.setTagString("") self.assertEqual(model.rowCount(), 20) - model.setTagString('tag 3') + model.setTagString("tag 3") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'C') - style.tagSymbol(QgsStyle.StyleEntity.ColorrampEntity, 'ramp c', ['tag 3']) + self.assertEqual(model.data(model.index(0, 0)), "C") + style.tagSymbol(QgsStyle.StyleEntity.ColorrampEntity, "ramp c", ["tag 3"]) self.assertEqual(model.rowCount(), 2) - self.assertEqual(model.data(model.index(0, 0)), 'C') - self.assertEqual(model.data(model.index(1, 0)), 'ramp c') - style.detagSymbol(QgsStyle.StyleEntity.ColorrampEntity, 'ramp c') + self.assertEqual(model.data(model.index(0, 0)), "C") + self.assertEqual(model.data(model.index(1, 0)), "ramp c") + style.detagSymbol(QgsStyle.StyleEntity.ColorrampEntity, "ramp c") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'C') - style.tagSymbol(QgsStyle.StyleEntity.TextFormatEntity, 'format c', ['tag 3']) + self.assertEqual(model.data(model.index(0, 0)), "C") + style.tagSymbol(QgsStyle.StyleEntity.TextFormatEntity, "format c", ["tag 3"]) self.assertEqual(model.rowCount(), 2) - self.assertEqual(model.data(model.index(0, 0)), 'C') - self.assertEqual(model.data(model.index(1, 0)), 'format c') - style.detagSymbol(QgsStyle.StyleEntity.TextFormatEntity, 'format c') + self.assertEqual(model.data(model.index(0, 0)), "C") + self.assertEqual(model.data(model.index(1, 0)), "format c") + style.detagSymbol(QgsStyle.StyleEntity.TextFormatEntity, "format c") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'C') - style.tagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, 'settings c', ['tag 3']) + self.assertEqual(model.data(model.index(0, 0)), "C") + style.tagSymbol( + QgsStyle.StyleEntity.LabelSettingsEntity, "settings c", ["tag 3"] + ) self.assertEqual(model.rowCount(), 2) - self.assertEqual(model.data(model.index(0, 0)), 'C') - self.assertEqual(model.data(model.index(1, 0)), 'settings c') - style.detagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, 'settings c') - style.tagSymbol(QgsStyle.StyleEntity.LegendPatchShapeEntity, 'shape c', ['tag 3']) + self.assertEqual(model.data(model.index(0, 0)), "C") + self.assertEqual(model.data(model.index(1, 0)), "settings c") + style.detagSymbol(QgsStyle.StyleEntity.LabelSettingsEntity, "settings c") + style.tagSymbol( + QgsStyle.StyleEntity.LegendPatchShapeEntity, "shape c", ["tag 3"] + ) self.assertEqual(model.rowCount(), 2) - self.assertEqual(model.data(model.index(0, 0)), 'C') - self.assertEqual(model.data(model.index(1, 0)), 'shape c') - style.detagSymbol(QgsStyle.StyleEntity.LegendPatchShapeEntity, 'shape c') - style.tagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, 'sym3d c', ['tag 3']) + self.assertEqual(model.data(model.index(0, 0)), "C") + self.assertEqual(model.data(model.index(1, 0)), "shape c") + style.detagSymbol(QgsStyle.StyleEntity.LegendPatchShapeEntity, "shape c") + style.tagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, "sym3d c", ["tag 3"]) self.assertEqual(model.rowCount(), 2) - self.assertEqual(model.data(model.index(0, 0)), 'C') - self.assertEqual(model.data(model.index(1, 0)), 'sym3d c') - style.detagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, 'sym3d c') + self.assertEqual(model.data(model.index(0, 0)), "C") + self.assertEqual(model.data(model.index(1, 0)), "sym3d c") + style.detagSymbol(QgsStyle.StyleEntity.Symbol3DEntity, "sym3d c") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'C') - model.setTagString('') + self.assertEqual(model.data(model.index(0, 0)), "C") + model.setTagString("") self.assertEqual(model.rowCount(), 20) # favorite filter - style.addFavorite(QgsStyle.StyleEntity.ColorrampEntity, 'ramp c') - style.addFavorite(QgsStyle.StyleEntity.SymbolEntity, 'another') - style.addFavorite(QgsStyle.StyleEntity.TextFormatEntity, 'format c') - style.addFavorite(QgsStyle.StyleEntity.LabelSettingsEntity, 'settings c') - style.addFavorite(QgsStyle.StyleEntity.LegendPatchShapeEntity, 'shape c') - style.addFavorite(QgsStyle.StyleEntity.Symbol3DEntity, 'sym3d c') + style.addFavorite(QgsStyle.StyleEntity.ColorrampEntity, "ramp c") + style.addFavorite(QgsStyle.StyleEntity.SymbolEntity, "another") + style.addFavorite(QgsStyle.StyleEntity.TextFormatEntity, "format c") + style.addFavorite(QgsStyle.StyleEntity.LabelSettingsEntity, "settings c") + style.addFavorite(QgsStyle.StyleEntity.LegendPatchShapeEntity, "shape c") + style.addFavorite(QgsStyle.StyleEntity.Symbol3DEntity, "sym3d c") self.assertEqual(model.favoritesOnly(), False) model.setFavoritesOnly(True) self.assertEqual(model.favoritesOnly(), True) self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0)), 'another') - self.assertEqual(model.data(model.index(1, 0)), 'format c') - self.assertEqual(model.data(model.index(2, 0)), 'ramp c') - self.assertEqual(model.data(model.index(3, 0)), 'settings c') - self.assertEqual(model.data(model.index(4, 0)), 'shape c') - self.assertEqual(model.data(model.index(5, 0)), 'sym3d c') + self.assertEqual(model.data(model.index(0, 0)), "another") + self.assertEqual(model.data(model.index(1, 0)), "format c") + self.assertEqual(model.data(model.index(2, 0)), "ramp c") + self.assertEqual(model.data(model.index(3, 0)), "settings c") + self.assertEqual(model.data(model.index(4, 0)), "shape c") + self.assertEqual(model.data(model.index(5, 0)), "sym3d c") model.setEntityFilterEnabled(True) model.setEntityFilter(QgsStyle.StyleEntity.ColorrampEntity) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'ramp c') + self.assertEqual(model.data(model.index(0, 0)), "ramp c") model.setEntityFilter(QgsStyle.StyleEntity.TextFormatEntity) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'format c') + self.assertEqual(model.data(model.index(0, 0)), "format c") model.setEntityFilter(QgsStyle.StyleEntity.LabelSettingsEntity) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'settings c') + self.assertEqual(model.data(model.index(0, 0)), "settings c") model.setEntityFilter(QgsStyle.StyleEntity.LegendPatchShapeEntity) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'shape c') + self.assertEqual(model.data(model.index(0, 0)), "shape c") model.setEntityFilter(QgsStyle.StyleEntity.Symbol3DEntity) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'sym3d c') + self.assertEqual(model.data(model.index(0, 0)), "sym3d c") model.setEntityFilterEnabled(False) - model.setFilterString('er') + model.setFilterString("er") self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'another') + self.assertEqual(model.data(model.index(0, 0)), "another") model.setEntityFilterEnabled(False) - model.setFilterString('') + model.setFilterString("") self.assertEqual(model.rowCount(), 6) - style.addFavorite(QgsStyle.StyleEntity.ColorrampEntity, 'ramp a') + style.addFavorite(QgsStyle.StyleEntity.ColorrampEntity, "ramp a") self.assertEqual(model.rowCount(), 7) - self.assertEqual(model.data(model.index(0, 0)), 'another') - self.assertEqual(model.data(model.index(1, 0)), 'format c') - self.assertEqual(model.data(model.index(2, 0)), 'ramp a') - self.assertEqual(model.data(model.index(3, 0)), 'ramp c') - self.assertEqual(model.data(model.index(4, 0)), 'settings c') - self.assertEqual(model.data(model.index(5, 0)), 'shape c') - self.assertEqual(model.data(model.index(6, 0)), 'sym3d c') - style.removeFavorite(QgsStyle.StyleEntity.ColorrampEntity, 'ramp a') + self.assertEqual(model.data(model.index(0, 0)), "another") + self.assertEqual(model.data(model.index(1, 0)), "format c") + self.assertEqual(model.data(model.index(2, 0)), "ramp a") + self.assertEqual(model.data(model.index(3, 0)), "ramp c") + self.assertEqual(model.data(model.index(4, 0)), "settings c") + self.assertEqual(model.data(model.index(5, 0)), "shape c") + self.assertEqual(model.data(model.index(6, 0)), "sym3d c") + style.removeFavorite(QgsStyle.StyleEntity.ColorrampEntity, "ramp a") self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0)), 'another') - self.assertEqual(model.data(model.index(1, 0)), 'format c') - self.assertEqual(model.data(model.index(2, 0)), 'ramp c') - self.assertEqual(model.data(model.index(3, 0)), 'settings c') - self.assertEqual(model.data(model.index(4, 0)), 'shape c') - self.assertEqual(model.data(model.index(5, 0)), 'sym3d c') - style.addFavorite(QgsStyle.StyleEntity.TextFormatEntity, 'format a') + self.assertEqual(model.data(model.index(0, 0)), "another") + self.assertEqual(model.data(model.index(1, 0)), "format c") + self.assertEqual(model.data(model.index(2, 0)), "ramp c") + self.assertEqual(model.data(model.index(3, 0)), "settings c") + self.assertEqual(model.data(model.index(4, 0)), "shape c") + self.assertEqual(model.data(model.index(5, 0)), "sym3d c") + style.addFavorite(QgsStyle.StyleEntity.TextFormatEntity, "format a") self.assertEqual(model.rowCount(), 7) - self.assertEqual(model.data(model.index(0, 0)), 'another') - self.assertEqual(model.data(model.index(1, 0)), 'format a') - self.assertEqual(model.data(model.index(2, 0)), 'format c') - self.assertEqual(model.data(model.index(3, 0)), 'ramp c') - self.assertEqual(model.data(model.index(4, 0)), 'settings c') - self.assertEqual(model.data(model.index(5, 0)), 'shape c') - self.assertEqual(model.data(model.index(6, 0)), 'sym3d c') - style.removeFavorite(QgsStyle.StyleEntity.TextFormatEntity, 'format a') + self.assertEqual(model.data(model.index(0, 0)), "another") + self.assertEqual(model.data(model.index(1, 0)), "format a") + self.assertEqual(model.data(model.index(2, 0)), "format c") + self.assertEqual(model.data(model.index(3, 0)), "ramp c") + self.assertEqual(model.data(model.index(4, 0)), "settings c") + self.assertEqual(model.data(model.index(5, 0)), "shape c") + self.assertEqual(model.data(model.index(6, 0)), "sym3d c") + style.removeFavorite(QgsStyle.StyleEntity.TextFormatEntity, "format a") self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0)), 'another') - self.assertEqual(model.data(model.index(1, 0)), 'format c') - self.assertEqual(model.data(model.index(2, 0)), 'ramp c') - self.assertEqual(model.data(model.index(3, 0)), 'settings c') - self.assertEqual(model.data(model.index(4, 0)), 'shape c') - self.assertEqual(model.data(model.index(5, 0)), 'sym3d c') - style.addFavorite(QgsStyle.StyleEntity.LabelSettingsEntity, 'settings a') + self.assertEqual(model.data(model.index(0, 0)), "another") + self.assertEqual(model.data(model.index(1, 0)), "format c") + self.assertEqual(model.data(model.index(2, 0)), "ramp c") + self.assertEqual(model.data(model.index(3, 0)), "settings c") + self.assertEqual(model.data(model.index(4, 0)), "shape c") + self.assertEqual(model.data(model.index(5, 0)), "sym3d c") + style.addFavorite(QgsStyle.StyleEntity.LabelSettingsEntity, "settings a") self.assertEqual(model.rowCount(), 7) - self.assertEqual(model.data(model.index(0, 0)), 'another') - self.assertEqual(model.data(model.index(1, 0)), 'format c') - self.assertEqual(model.data(model.index(2, 0)), 'ramp c') - self.assertEqual(model.data(model.index(3, 0)), 'settings a') - self.assertEqual(model.data(model.index(4, 0)), 'settings c') - self.assertEqual(model.data(model.index(5, 0)), 'shape c') - self.assertEqual(model.data(model.index(6, 0)), 'sym3d c') - style.removeFavorite(QgsStyle.StyleEntity.LabelSettingsEntity, 'settings a') + self.assertEqual(model.data(model.index(0, 0)), "another") + self.assertEqual(model.data(model.index(1, 0)), "format c") + self.assertEqual(model.data(model.index(2, 0)), "ramp c") + self.assertEqual(model.data(model.index(3, 0)), "settings a") + self.assertEqual(model.data(model.index(4, 0)), "settings c") + self.assertEqual(model.data(model.index(5, 0)), "shape c") + self.assertEqual(model.data(model.index(6, 0)), "sym3d c") + style.removeFavorite(QgsStyle.StyleEntity.LabelSettingsEntity, "settings a") self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0)), 'another') - self.assertEqual(model.data(model.index(1, 0)), 'format c') - self.assertEqual(model.data(model.index(2, 0)), 'ramp c') - self.assertEqual(model.data(model.index(3, 0)), 'settings c') - self.assertEqual(model.data(model.index(4, 0)), 'shape c') - self.assertEqual(model.data(model.index(5, 0)), 'sym3d c') - style.addFavorite(QgsStyle.StyleEntity.LegendPatchShapeEntity, 'shape a') + self.assertEqual(model.data(model.index(0, 0)), "another") + self.assertEqual(model.data(model.index(1, 0)), "format c") + self.assertEqual(model.data(model.index(2, 0)), "ramp c") + self.assertEqual(model.data(model.index(3, 0)), "settings c") + self.assertEqual(model.data(model.index(4, 0)), "shape c") + self.assertEqual(model.data(model.index(5, 0)), "sym3d c") + style.addFavorite(QgsStyle.StyleEntity.LegendPatchShapeEntity, "shape a") self.assertEqual(model.rowCount(), 7) - self.assertEqual(model.data(model.index(0, 0)), 'another') - self.assertEqual(model.data(model.index(1, 0)), 'format c') - self.assertEqual(model.data(model.index(2, 0)), 'ramp c') - self.assertEqual(model.data(model.index(3, 0)), 'settings c') - self.assertEqual(model.data(model.index(4, 0)), 'shape a') - self.assertEqual(model.data(model.index(5, 0)), 'shape c') - self.assertEqual(model.data(model.index(6, 0)), 'sym3d c') - style.removeFavorite(QgsStyle.StyleEntity.LegendPatchShapeEntity, 'shape a') + self.assertEqual(model.data(model.index(0, 0)), "another") + self.assertEqual(model.data(model.index(1, 0)), "format c") + self.assertEqual(model.data(model.index(2, 0)), "ramp c") + self.assertEqual(model.data(model.index(3, 0)), "settings c") + self.assertEqual(model.data(model.index(4, 0)), "shape a") + self.assertEqual(model.data(model.index(5, 0)), "shape c") + self.assertEqual(model.data(model.index(6, 0)), "sym3d c") + style.removeFavorite(QgsStyle.StyleEntity.LegendPatchShapeEntity, "shape a") self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0)), 'another') - self.assertEqual(model.data(model.index(1, 0)), 'format c') - self.assertEqual(model.data(model.index(2, 0)), 'ramp c') - self.assertEqual(model.data(model.index(3, 0)), 'settings c') - self.assertEqual(model.data(model.index(4, 0)), 'shape c') - self.assertEqual(model.data(model.index(5, 0)), 'sym3d c') - style.addFavorite(QgsStyle.StyleEntity.Symbol3DEntity, 'sym3d a') + self.assertEqual(model.data(model.index(0, 0)), "another") + self.assertEqual(model.data(model.index(1, 0)), "format c") + self.assertEqual(model.data(model.index(2, 0)), "ramp c") + self.assertEqual(model.data(model.index(3, 0)), "settings c") + self.assertEqual(model.data(model.index(4, 0)), "shape c") + self.assertEqual(model.data(model.index(5, 0)), "sym3d c") + style.addFavorite(QgsStyle.StyleEntity.Symbol3DEntity, "sym3d a") self.assertEqual(model.rowCount(), 7) - self.assertEqual(model.data(model.index(0, 0)), 'another') - self.assertEqual(model.data(model.index(1, 0)), 'format c') - self.assertEqual(model.data(model.index(2, 0)), 'ramp c') - self.assertEqual(model.data(model.index(3, 0)), 'settings c') - self.assertEqual(model.data(model.index(4, 0)), 'shape c') - self.assertEqual(model.data(model.index(5, 0)), 'sym3d a') - self.assertEqual(model.data(model.index(6, 0)), 'sym3d c') - style.removeFavorite(QgsStyle.StyleEntity.Symbol3DEntity, 'sym3d a') + self.assertEqual(model.data(model.index(0, 0)), "another") + self.assertEqual(model.data(model.index(1, 0)), "format c") + self.assertEqual(model.data(model.index(2, 0)), "ramp c") + self.assertEqual(model.data(model.index(3, 0)), "settings c") + self.assertEqual(model.data(model.index(4, 0)), "shape c") + self.assertEqual(model.data(model.index(5, 0)), "sym3d a") + self.assertEqual(model.data(model.index(6, 0)), "sym3d c") + style.removeFavorite(QgsStyle.StyleEntity.Symbol3DEntity, "sym3d a") self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0)), 'another') - self.assertEqual(model.data(model.index(1, 0)), 'format c') - self.assertEqual(model.data(model.index(2, 0)), 'ramp c') - self.assertEqual(model.data(model.index(3, 0)), 'settings c') - self.assertEqual(model.data(model.index(4, 0)), 'shape c') - self.assertEqual(model.data(model.index(5, 0)), 'sym3d c') - - style.addFavorite(QgsStyle.StyleEntity.SymbolEntity, 'BB') + self.assertEqual(model.data(model.index(0, 0)), "another") + self.assertEqual(model.data(model.index(1, 0)), "format c") + self.assertEqual(model.data(model.index(2, 0)), "ramp c") + self.assertEqual(model.data(model.index(3, 0)), "settings c") + self.assertEqual(model.data(model.index(4, 0)), "shape c") + self.assertEqual(model.data(model.index(5, 0)), "sym3d c") + + style.addFavorite(QgsStyle.StyleEntity.SymbolEntity, "BB") self.assertEqual(model.rowCount(), 7) - self.assertEqual(model.data(model.index(0, 0)), 'another') - self.assertEqual(model.data(model.index(1, 0)), 'BB') - self.assertEqual(model.data(model.index(2, 0)), 'format c') - self.assertEqual(model.data(model.index(3, 0)), 'ramp c') - self.assertEqual(model.data(model.index(4, 0)), 'settings c') - self.assertEqual(model.data(model.index(5, 0)), 'shape c') - self.assertEqual(model.data(model.index(6, 0)), 'sym3d c') - style.removeFavorite(QgsStyle.StyleEntity.SymbolEntity, 'another') + self.assertEqual(model.data(model.index(0, 0)), "another") + self.assertEqual(model.data(model.index(1, 0)), "BB") + self.assertEqual(model.data(model.index(2, 0)), "format c") + self.assertEqual(model.data(model.index(3, 0)), "ramp c") + self.assertEqual(model.data(model.index(4, 0)), "settings c") + self.assertEqual(model.data(model.index(5, 0)), "shape c") + self.assertEqual(model.data(model.index(6, 0)), "sym3d c") + style.removeFavorite(QgsStyle.StyleEntity.SymbolEntity, "another") self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0)), 'BB') - self.assertEqual(model.data(model.index(1, 0)), 'format c') - self.assertEqual(model.data(model.index(2, 0)), 'ramp c') - self.assertEqual(model.data(model.index(3, 0)), 'settings c') - self.assertEqual(model.data(model.index(4, 0)), 'shape c') - self.assertEqual(model.data(model.index(5, 0)), 'sym3d c') + self.assertEqual(model.data(model.index(0, 0)), "BB") + self.assertEqual(model.data(model.index(1, 0)), "format c") + self.assertEqual(model.data(model.index(2, 0)), "ramp c") + self.assertEqual(model.data(model.index(3, 0)), "settings c") + self.assertEqual(model.data(model.index(4, 0)), "shape c") + self.assertEqual(model.data(model.index(5, 0)), "sym3d c") model.setFavoritesOnly(False) self.assertEqual(model.rowCount(), 20) # smart group filter - style.addSmartgroup('smart', 'AND', ['tag 3'], [], ['c'], []) + style.addSmartgroup("smart", "AND", ["tag 3"], [], ["c"], []) self.assertEqual(model.smartGroupId(), -1) model.setSmartGroupId(1) self.assertEqual(model.smartGroupId(), 1) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'C') - style.addSmartgroup('smart', 'OR', ['tag 3'], [], ['c'], []) + self.assertEqual(model.data(model.index(0, 0)), "C") + style.addSmartgroup("smart", "OR", ["tag 3"], [], ["c"], []) model.setSmartGroupId(2) self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0)), 'C') - self.assertEqual(model.data(model.index(1, 0)), 'format c') - self.assertEqual(model.data(model.index(2, 0)), 'ramp c') - self.assertEqual(model.data(model.index(3, 0)), 'settings c') - self.assertEqual(model.data(model.index(4, 0)), 'shape c') - self.assertEqual(model.data(model.index(5, 0)), 'sym3d c') - style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, 'a', ['tag 3']) + self.assertEqual(model.data(model.index(0, 0)), "C") + self.assertEqual(model.data(model.index(1, 0)), "format c") + self.assertEqual(model.data(model.index(2, 0)), "ramp c") + self.assertEqual(model.data(model.index(3, 0)), "settings c") + self.assertEqual(model.data(model.index(4, 0)), "shape c") + self.assertEqual(model.data(model.index(5, 0)), "sym3d c") + style.tagSymbol(QgsStyle.StyleEntity.SymbolEntity, "a", ["tag 3"]) self.assertEqual(model.rowCount(), 7) - self.assertEqual(model.data(model.index(0, 0)), 'a') - self.assertEqual(model.data(model.index(1, 0)), 'C') - self.assertEqual(model.data(model.index(2, 0)), 'format c') - self.assertEqual(model.data(model.index(3, 0)), 'ramp c') - self.assertEqual(model.data(model.index(4, 0)), 'settings c') - self.assertEqual(model.data(model.index(5, 0)), 'shape c') - self.assertEqual(model.data(model.index(6, 0)), 'sym3d c') - style.renameColorRamp('ramp c', 'x') + self.assertEqual(model.data(model.index(0, 0)), "a") + self.assertEqual(model.data(model.index(1, 0)), "C") + self.assertEqual(model.data(model.index(2, 0)), "format c") + self.assertEqual(model.data(model.index(3, 0)), "ramp c") + self.assertEqual(model.data(model.index(4, 0)), "settings c") + self.assertEqual(model.data(model.index(5, 0)), "shape c") + self.assertEqual(model.data(model.index(6, 0)), "sym3d c") + style.renameColorRamp("ramp c", "x") self.assertEqual(model.rowCount(), 6) - self.assertEqual(model.data(model.index(0, 0)), 'a') - self.assertEqual(model.data(model.index(1, 0)), 'C') - self.assertEqual(model.data(model.index(2, 0)), 'format c') - self.assertEqual(model.data(model.index(3, 0)), 'settings c') - self.assertEqual(model.data(model.index(4, 0)), 'shape c') - self.assertEqual(model.data(model.index(5, 0)), 'sym3d c') - style.renameTextFormat('format c', 'x') + self.assertEqual(model.data(model.index(0, 0)), "a") + self.assertEqual(model.data(model.index(1, 0)), "C") + self.assertEqual(model.data(model.index(2, 0)), "format c") + self.assertEqual(model.data(model.index(3, 0)), "settings c") + self.assertEqual(model.data(model.index(4, 0)), "shape c") + self.assertEqual(model.data(model.index(5, 0)), "sym3d c") + style.renameTextFormat("format c", "x") self.assertEqual(model.rowCount(), 5) - self.assertEqual(model.data(model.index(0, 0)), 'a') - self.assertEqual(model.data(model.index(1, 0)), 'C') - self.assertEqual(model.data(model.index(2, 0)), 'settings c') - self.assertEqual(model.data(model.index(3, 0)), 'shape c') - self.assertEqual(model.data(model.index(4, 0)), 'sym3d c') - style.renameLabelSettings('settings c', 'x') + self.assertEqual(model.data(model.index(0, 0)), "a") + self.assertEqual(model.data(model.index(1, 0)), "C") + self.assertEqual(model.data(model.index(2, 0)), "settings c") + self.assertEqual(model.data(model.index(3, 0)), "shape c") + self.assertEqual(model.data(model.index(4, 0)), "sym3d c") + style.renameLabelSettings("settings c", "x") self.assertEqual(model.rowCount(), 4) - self.assertEqual(model.data(model.index(0, 0)), 'a') - self.assertEqual(model.data(model.index(1, 0)), 'C') - self.assertEqual(model.data(model.index(2, 0)), 'shape c') - self.assertEqual(model.data(model.index(3, 0)), 'sym3d c') - style.renameLegendPatchShape('shape c', 'x') + self.assertEqual(model.data(model.index(0, 0)), "a") + self.assertEqual(model.data(model.index(1, 0)), "C") + self.assertEqual(model.data(model.index(2, 0)), "shape c") + self.assertEqual(model.data(model.index(3, 0)), "sym3d c") + style.renameLegendPatchShape("shape c", "x") self.assertEqual(model.rowCount(), 3) - self.assertEqual(model.data(model.index(0, 0)), 'a') - self.assertEqual(model.data(model.index(1, 0)), 'C') - self.assertEqual(model.data(model.index(2, 0)), 'sym3d c') - style.renameSymbol3D('sym3d c', 'x') + self.assertEqual(model.data(model.index(0, 0)), "a") + self.assertEqual(model.data(model.index(1, 0)), "C") + self.assertEqual(model.data(model.index(2, 0)), "sym3d c") + style.renameSymbol3D("sym3d c", "x") self.assertEqual(model.rowCount(), 2) - self.assertEqual(model.data(model.index(0, 0)), 'a') - self.assertEqual(model.data(model.index(1, 0)), 'C') + self.assertEqual(model.data(model.index(0, 0)), "a") + self.assertEqual(model.data(model.index(1, 0)), "C") model.setSmartGroupId(-1) self.assertEqual(model.rowCount(), 20) @@ -2603,11 +4319,11 @@ def test_filter_proxy(self): self.assertEqual(model.rowCount(), 3) model.setLayerType(QgsWkbTypes.GeometryType.PointGeometry) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'settings a') + self.assertEqual(model.data(model.index(0, 0)), "settings a") model.setLayerType(QgsWkbTypes.GeometryType.LineGeometry) self.assertEqual(model.rowCount(), 2) - self.assertEqual(model.data(model.index(0, 0)), 'settings BB') - self.assertEqual(model.data(model.index(1, 0)), 'x') + self.assertEqual(model.data(model.index(0, 0)), "settings BB") + self.assertEqual(model.data(model.index(1, 0)), "x") model.setLayerType(QgsWkbTypes.GeometryType.PolygonGeometry) self.assertEqual(model.rowCount(), 0) model.setLayerType(QgsWkbTypes.GeometryType.UnknownGeometry) @@ -2618,14 +4334,14 @@ def test_filter_proxy(self): self.assertEqual(model.rowCount(), 3) model.setLayerType(QgsWkbTypes.GeometryType.PointGeometry) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'sym3d a') + self.assertEqual(model.data(model.index(0, 0)), "sym3d a") model.setLayerType(QgsWkbTypes.GeometryType.LineGeometry) self.assertEqual(model.rowCount(), 2) - self.assertEqual(model.data(model.index(0, 0)), 'sym3d a') - self.assertEqual(model.data(model.index(1, 0)), 'x') + self.assertEqual(model.data(model.index(0, 0)), "sym3d a") + self.assertEqual(model.data(model.index(1, 0)), "x") model.setLayerType(QgsWkbTypes.GeometryType.PolygonGeometry) self.assertEqual(model.rowCount(), 1) - self.assertEqual(model.data(model.index(0, 0)), 'sym3d BB') + self.assertEqual(model.data(model.index(0, 0)), "sym3d BB") model.setLayerType(QgsWkbTypes.GeometryType.UnknownGeometry) self.assertEqual(model.rowCount(), 3) @@ -2638,17 +4354,19 @@ def testIconSize(self): symbol_a = createMarkerSymbol() symbol_a.setColor(QColor(255, 10, 10)) - self.assertTrue(style.addSymbol('a', symbol_a, True)) + self.assertTrue(style.addSymbol("a", symbol_a, True)) ramp_a = QgsLimitedRandomColorRamp(5) - self.assertTrue(style.addColorRamp('ramp a', ramp_a, True)) + self.assertTrue(style.addColorRamp("ramp a", ramp_a, True)) format_a = QgsTextFormat() - self.assertTrue(style.addTextFormat('format a', format_a, True)) + self.assertTrue(style.addTextFormat("format a", format_a, True)) settings_a = QgsPalLayerSettings() - self.assertTrue(style.addLabelSettings('settings a', settings_a, True)) - shape_a = QgsLegendPatchShape(QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt('Point ( 4 5 )')) - self.assertTrue(style.addLegendPatchShape('shape a', shape_a, True)) + self.assertTrue(style.addLabelSettings("settings a", settings_a, True)) + shape_a = QgsLegendPatchShape( + QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt("Point ( 4 5 )") + ) + self.assertTrue(style.addLegendPatchShape("shape a", shape_a, True)) symbol3d_a = Dummy3dSymbol() - self.assertTrue(style.addSymbol3D('symbol3d a', symbol3d_a, True)) + self.assertTrue(style.addSymbol3D("symbol3d a", symbol3d_a, True)) # TODO - should be 6 when 3d symbols get an icon for i in range(5): @@ -2691,47 +4409,87 @@ def testSetData(self): symbol_a = createMarkerSymbol() symbol_a.setColor(QColor(255, 10, 10)) - self.assertTrue(style.addSymbol('a', symbol_a, True)) + self.assertTrue(style.addSymbol("a", symbol_a, True)) ramp_a = QgsLimitedRandomColorRamp(5) - self.assertTrue(style.addColorRamp('ramp a', ramp_a, True)) + self.assertTrue(style.addColorRamp("ramp a", ramp_a, True)) format_a = QgsTextFormat() - self.assertTrue(style.addTextFormat('format a', format_a, True)) + self.assertTrue(style.addTextFormat("format a", format_a, True)) settings_a = QgsPalLayerSettings() - self.assertTrue(style.addLabelSettings('settings a', settings_a, True)) - shape_a = QgsLegendPatchShape(QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt('Point ( 4 5 )')) - self.assertTrue(style.addLegendPatchShape('shape a', shape_a, True)) + self.assertTrue(style.addLabelSettings("settings a", settings_a, True)) + shape_a = QgsLegendPatchShape( + QgsSymbol.SymbolType.Marker, QgsGeometry.fromWkt("Point ( 4 5 )") + ) + self.assertTrue(style.addLegendPatchShape("shape a", shape_a, True)) symbol3d_a = Dummy3dSymbol() - self.assertTrue(style.addSymbol3D('symbol3d a', symbol3d_a, True)) + self.assertTrue(style.addSymbol3D("symbol3d a", symbol3d_a, True)) model = QgsStyleModel(style) self.assertEqual(model.rowCount(), 6) - self.assertEqual(style.symbolNames(), ['a']) - self.assertFalse(model.setData(QModelIndex(), 'b', Qt.ItemDataRole.EditRole)) - self.assertFalse(model.setData(model.index(0, 1), 'b', Qt.ItemDataRole.EditRole)) - self.assertTrue(model.setData(model.index(0, 0), 'new symbol name', Qt.ItemDataRole.EditRole)) - self.assertEqual(model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), 'new symbol name') - - self.assertEqual(style.symbolNames(), ['new symbol name']) - self.assertTrue(model.setData(model.index(1, 0), 'ramp new name', Qt.ItemDataRole.EditRole)) - self.assertEqual(model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), 'ramp new name') - self.assertEqual(style.colorRampNames(), ['ramp new name']) - - self.assertTrue(model.setData(model.index(2, 0), 'format new name', Qt.ItemDataRole.EditRole)) - self.assertEqual(model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), 'format new name') - self.assertEqual(style.textFormatNames(), ['format new name']) - - self.assertTrue(model.setData(model.index(3, 0), 'settings new name', Qt.ItemDataRole.EditRole)) - self.assertEqual(model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), 'settings new name') - self.assertEqual(style.labelSettingsNames(), ['settings new name']) - - self.assertTrue(model.setData(model.index(4, 0), 'shape new name', Qt.ItemDataRole.EditRole)) - self.assertEqual(model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), 'shape new name') - self.assertEqual(style.legendPatchShapeNames(), ['shape new name']) - - self.assertTrue(model.setData(model.index(5, 0), 'symbol3d new name', Qt.ItemDataRole.EditRole)) - self.assertEqual(model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), 'symbol3d new name') - self.assertEqual(style.symbol3DNames(), ['symbol3d new name']) + self.assertEqual(style.symbolNames(), ["a"]) + self.assertFalse(model.setData(QModelIndex(), "b", Qt.ItemDataRole.EditRole)) + self.assertFalse( + model.setData(model.index(0, 1), "b", Qt.ItemDataRole.EditRole) + ) + self.assertTrue( + model.setData( + model.index(0, 0), "new symbol name", Qt.ItemDataRole.EditRole + ) + ) + self.assertEqual( + model.data(model.index(0, 0), Qt.ItemDataRole.DisplayRole), + "new symbol name", + ) + + self.assertEqual(style.symbolNames(), ["new symbol name"]) + self.assertTrue( + model.setData(model.index(1, 0), "ramp new name", Qt.ItemDataRole.EditRole) + ) + self.assertEqual( + model.data(model.index(1, 0), Qt.ItemDataRole.DisplayRole), "ramp new name" + ) + self.assertEqual(style.colorRampNames(), ["ramp new name"]) + + self.assertTrue( + model.setData( + model.index(2, 0), "format new name", Qt.ItemDataRole.EditRole + ) + ) + self.assertEqual( + model.data(model.index(2, 0), Qt.ItemDataRole.DisplayRole), + "format new name", + ) + self.assertEqual(style.textFormatNames(), ["format new name"]) + + self.assertTrue( + model.setData( + model.index(3, 0), "settings new name", Qt.ItemDataRole.EditRole + ) + ) + self.assertEqual( + model.data(model.index(3, 0), Qt.ItemDataRole.DisplayRole), + "settings new name", + ) + self.assertEqual(style.labelSettingsNames(), ["settings new name"]) + + self.assertTrue( + model.setData(model.index(4, 0), "shape new name", Qt.ItemDataRole.EditRole) + ) + self.assertEqual( + model.data(model.index(4, 0), Qt.ItemDataRole.DisplayRole), "shape new name" + ) + self.assertEqual(style.legendPatchShapeNames(), ["shape new name"]) + + self.assertTrue( + model.setData( + model.index(5, 0), "symbol3d new name", Qt.ItemDataRole.EditRole + ) + ) + self.assertEqual( + model.data(model.index(5, 0), Qt.ItemDataRole.DisplayRole), + "symbol3d new name", + ) + self.assertEqual(style.symbol3DNames(), ["symbol3d new name"]) def test_reset_symbollayer_ids(self): """ @@ -2752,9 +4510,9 @@ def test_reset_symbollayer_ids(self): old_id = child_sl.id() self.assertTrue(child_sl.id()) - self.assertTrue(style.addSymbol('fillsymbol', fill_symbol, True)) + self.assertTrue(style.addSymbol("fillsymbol", fill_symbol, True)) - new_fill_symbol = style.symbol('fillsymbol') + new_fill_symbol = style.symbol("fillsymbol") self.assertEqual(len(new_fill_symbol.symbolLayers()), 1) subsymbol = new_fill_symbol.symbolLayers()[0].subSymbol() self.assertTrue(subsymbol) @@ -2765,5 +4523,5 @@ def test_reset_symbollayer_ids(self): self.assertTrue(child_sl.id() != old_id) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssubsetstringeditorproviderregistry.py b/tests/src/python/test_qgssubsetstringeditorproviderregistry.py index 9975ac27f05c..d46f99afff40 100644 --- a/tests/src/python/test_qgssubsetstringeditorproviderregistry.py +++ b/tests/src/python/test_qgssubsetstringeditorproviderregistry.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Even Rouault' -__date__ = '15/11/2020' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Even Rouault" +__date__ = "15/11/2020" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.PyQt.QtCore import Qt from qgis.core import QgsVectorLayer @@ -56,77 +57,78 @@ def testRegistry(self): registry = QgsGui.subsetStringEditorProviderRegistry() initial_providers = registry.providers() self.assertTrue(initial_providers) # we expect a bunch of default providers - self.assertTrue([p.name() for p in initial_providers if p.name() == 'WFS']) + self.assertTrue([p.name() for p in initial_providers if p.name() == "WFS"]) # add a new provider - p1 = TestProvider('p1') + p1 = TestProvider("p1") registry.addProvider(p1) self.assertIn(p1, registry.providers()) - p2 = TestProvider('p2') + p2 = TestProvider("p2") registry.addProvider(p2) self.assertIn(p1, registry.providers()) self.assertIn(p2, registry.providers()) registry.removeProvider(None) - p3 = TestProvider('p3') + p3 = TestProvider("p3") # not in registry yet registry.removeProvider(p3) registry.removeProvider(p1) - self.assertNotIn('p1', [p.name() for p in registry.providers()]) + self.assertNotIn("p1", [p.name() for p in registry.providers()]) self.assertIn(p2, registry.providers()) registry.removeProvider(p2) - self.assertNotIn('p2', [p.name() for p in registry.providers()]) + self.assertNotIn("p2", [p.name() for p in registry.providers()]) self.assertEqual(registry.providers(), initial_providers) def testProviderKey(self): """Tests finding provider by name and return providerKey""" registry = QgsGui.subsetStringEditorProviderRegistry() - self.assertIsNotNone(registry.providerByName('WFS')) - self.assertIsNone(registry.providerByName('i_do_not_exist')) - self.assertEqual(registry.providerByName('WFS').providerKey(), 'WFS') + self.assertIsNotNone(registry.providerByName("WFS")) + self.assertIsNone(registry.providerByName("i_do_not_exist")) + self.assertEqual(registry.providerByName("WFS").providerKey(), "WFS") # Test disabled since there's a memory corruption issue with QgsQueryBuilder() # creation in non-GUI mode. def DISABLED_testCreateDialogWithDefaultImplementation(self): - """ Tests that createDialog() returns the default implementation when no provider kicks in """ + """Tests that createDialog() returns the default implementation when no provider kicks in""" registry = QgsGui.subsetStringEditorProviderRegistry() - p1 = TestProvider('p1') + p1 = TestProvider("p1") try: registry.addProvider(p1) - vl = QgsVectorLayer( - 'Polygon?crs=epsg:4326&field=id:int', - 'test', - 'memory') + vl = QgsVectorLayer("Polygon?crs=epsg:4326&field=id:int", "test", "memory") self.assertIsNotNone(registry.createDialog(vl)) - self.assertEqual(registry.createDialog(vl).objectName(), - QgsQueryBuilder(vl).objectName()) + self.assertEqual( + registry.createDialog(vl).objectName(), QgsQueryBuilder(vl).objectName() + ) finally: registry.removeProvider(p1) def testCreateDialogWithCustomImplementation(self): - """ Tests that createDialog() returns a custom implementation """ + """Tests that createDialog() returns a custom implementation""" registry = QgsGui.subsetStringEditorProviderRegistry() - p1 = TestProvider('p1') + p1 = TestProvider("p1") try: registry.addProvider(p1) vl = QgsVectorLayer( - 'Polygon?crs=epsg:4326&field=id:int', - 'layer_for_this_provider', - 'memory') + "Polygon?crs=epsg:4326&field=id:int", + "layer_for_this_provider", + "memory", + ) self.assertIsNotNone(registry.createDialog(vl)) - self.assertEqual(registry.createDialog(vl).objectName(), - SubsetStringDialog().objectName()) + self.assertEqual( + registry.createDialog(vl).objectName(), + SubsetStringDialog().objectName(), + ) finally: registry.removeProvider(p1) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssvgcache.py b/tests/src/python/test_qgssvgcache.py index 7ed411c2f657..53f91fd8e05e 100644 --- a/tests/src/python/test_qgssvgcache.py +++ b/tests/src/python/test_qgssvgcache.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2018 by Nyall Dawson' -__date__ = '29/03/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "(C) 2018 by Nyall Dawson" +__date__ = "29/03/2018" +__copyright__ = "Copyright 2018, The QGIS Project" import http.server import os @@ -17,9 +18,7 @@ from qgis.PyQt.QtCore import QCoreApplication from qgis.PyQt.QtGui import QColor -from qgis.core import ( - QgsApplication -) +from qgis.core import QgsApplication import unittest from qgis.testing import start_app, QgisTestCase @@ -46,10 +45,10 @@ def control_path_prefix(cls): def setUpClass(cls): super().setUpClass() # Bring up a simple HTTP server, for remote SVG tests - os.chdir(unitTestDataPath() + '') + os.chdir(unitTestDataPath() + "") handler = SlowHTTPRequestHandler - cls.httpd = socketserver.TCPServer(('localhost', 0), handler) + cls.httpd = socketserver.TCPServer(("localhost", 0), handler) cls.port = cls.httpd.server_address[1] cls.httpd_thread = threading.Thread(target=cls.httpd.serve_forever) @@ -70,34 +69,46 @@ def waitForFetch(self): def testRemoteSVG(self): """Test fetching remote svg.""" - url = f'http://localhost:{str(TestQgsSvgCache.port)}/qgis_local_server/sample_svg.svg' - image, in_cache = QgsApplication.svgCache().svgAsImage(url, 100, fill=QColor(0, 0, 0), stroke=QColor(0, 0, 0), - strokeWidth=0.1, widthScaleFactor=1) + url = f"http://localhost:{str(TestQgsSvgCache.port)}/qgis_local_server/sample_svg.svg" + image, in_cache = QgsApplication.svgCache().svgAsImage( + url, + 100, + fill=QColor(0, 0, 0), + stroke=QColor(0, 0, 0), + strokeWidth=0.1, + widthScaleFactor=1, + ) # first should be waiting image self.assertTrue( self.image_check( - 'Remote SVG', - 'waiting_svg', + "Remote SVG", + "waiting_svg", image, color_tolerance=2, allowed_mismatch=20, - use_checkerboard_background=True + use_checkerboard_background=True, ) ) self.waitForFetch() # second should be correct image - image, in_cache = QgsApplication.svgCache().svgAsImage(url, 100, fill=QColor(0, 0, 0), stroke=QColor(0, 0, 0), - strokeWidth=0.1, widthScaleFactor=1) + image, in_cache = QgsApplication.svgCache().svgAsImage( + url, + 100, + fill=QColor(0, 0, 0), + stroke=QColor(0, 0, 0), + strokeWidth=0.1, + widthScaleFactor=1, + ) self.assertTrue( self.image_check( - 'Remote SVG', - 'remote_svg', + "Remote SVG", + "remote_svg", image, color_tolerance=2, allowed_mismatch=20, - use_checkerboard_background=True + use_checkerboard_background=True, ) ) @@ -106,35 +117,47 @@ def testRemoteSVG(self): def testRemoteSvgAsText(self): """Test fetching remote svg with text mime format - e.g. github raw svgs""" - url = f'http://localhost:{str(TestQgsSvgCache.port)}/qgis_local_server/svg_as_text.txt' - image, in_cache = QgsApplication.svgCache().svgAsImage(url, 100, fill=QColor(0, 0, 0), stroke=QColor(0, 0, 0), - strokeWidth=0.1, widthScaleFactor=1) + url = f"http://localhost:{str(TestQgsSvgCache.port)}/qgis_local_server/svg_as_text.txt" + image, in_cache = QgsApplication.svgCache().svgAsImage( + url, + 100, + fill=QColor(0, 0, 0), + stroke=QColor(0, 0, 0), + strokeWidth=0.1, + widthScaleFactor=1, + ) # first should be waiting image self.assertTrue( self.image_check( - 'Remote SVG as Text', - 'waiting_svg', + "Remote SVG as Text", + "waiting_svg", image, color_tolerance=2, allowed_mismatch=20, - use_checkerboard_background=True + use_checkerboard_background=True, ) ) self.waitForFetch() # second should be correct image - image, in_cache = QgsApplication.svgCache().svgAsImage(url, 100, fill=QColor(0, 0, 0), stroke=QColor(0, 0, 0), - strokeWidth=0.1, widthScaleFactor=1) + image, in_cache = QgsApplication.svgCache().svgAsImage( + url, + 100, + fill=QColor(0, 0, 0), + stroke=QColor(0, 0, 0), + strokeWidth=0.1, + widthScaleFactor=1, + ) # first should be waiting image self.assertTrue( self.image_check( - 'Remote SVG as Text', - 'remote_svg', + "Remote SVG as Text", + "remote_svg", image, color_tolerance=2, allowed_mismatch=20, - use_checkerboard_background=True + use_checkerboard_background=True, ) ) @@ -143,33 +166,45 @@ def testRemoteSvgAsText(self): def testRemoteSvgBadMime(self): """Test fetching remote svg with bad mime type""" - url = f'http://localhost:{str(TestQgsSvgCache.port)}/qgis_local_server/logo.png' - image, in_cache = QgsApplication.svgCache().svgAsImage(url, 100, fill=QColor(0, 0, 0), stroke=QColor(0, 0, 0), - strokeWidth=0.1, widthScaleFactor=1) + url = f"http://localhost:{str(TestQgsSvgCache.port)}/qgis_local_server/logo.png" + image, in_cache = QgsApplication.svgCache().svgAsImage( + url, + 100, + fill=QColor(0, 0, 0), + stroke=QColor(0, 0, 0), + strokeWidth=0.1, + widthScaleFactor=1, + ) # first should be waiting image self.assertTrue( self.image_check( - 'Remote SVG bad MIME type', - 'waiting_svg', + "Remote SVG bad MIME type", + "waiting_svg", image, color_tolerance=2, allowed_mismatch=20, - use_checkerboard_background=True + use_checkerboard_background=True, ) ) # second should be correct image self.waitForFetch() - image, in_cache = QgsApplication.svgCache().svgAsImage(url, 100, fill=QColor(0, 0, 0), stroke=QColor(0, 0, 0), - strokeWidth=0.1, widthScaleFactor=1) + image, in_cache = QgsApplication.svgCache().svgAsImage( + url, + 100, + fill=QColor(0, 0, 0), + stroke=QColor(0, 0, 0), + strokeWidth=0.1, + widthScaleFactor=1, + ) self.assertTrue( self.image_check( - 'Remote SVG bad MIME type', - 'bad_svg', + "Remote SVG bad MIME type", + "bad_svg", image, color_tolerance=2, allowed_mismatch=20, - use_checkerboard_background=True + use_checkerboard_background=True, ) ) @@ -178,18 +213,24 @@ def testRemoteSvgBadMime(self): def testRemoteSvgMissing(self): """Test fetching remote svg with bad url""" - url = f'http://localhost:{str(TestQgsSvgCache.port)}/qgis_local_server/xxx.svg' # oooo naughty - image, in_cache = QgsApplication.svgCache().svgAsImage(url, 100, fill=QColor(0, 0, 0), stroke=QColor(0, 0, 0), - strokeWidth=0.1, widthScaleFactor=1) + url = f"http://localhost:{str(TestQgsSvgCache.port)}/qgis_local_server/xxx.svg" # oooo naughty + image, in_cache = QgsApplication.svgCache().svgAsImage( + url, + 100, + fill=QColor(0, 0, 0), + stroke=QColor(0, 0, 0), + strokeWidth=0.1, + widthScaleFactor=1, + ) self.assertTrue( self.image_check( - 'Remote SVG missing', - 'waiting_svg', + "Remote SVG missing", + "waiting_svg", image, color_tolerance=2, allowed_mismatch=20, - use_checkerboard_background=True + use_checkerboard_background=True, ) ) @@ -199,50 +240,71 @@ def testRemoteSvgMissing(self): def testRemoteSVGBlocking(self): """Test fetching remote svg.""" # remote not yet requested so not in cache - url = f'http://localhost:{str(TestQgsSvgCache.port)}/qgis_local_server/QGIS_logo_2017.svg' - image, in_cache = QgsApplication.svgCache().svgAsImage(url, 100, fill=QColor(0, 0, 0), stroke=QColor(0, 0, 0), - strokeWidth=0.1, widthScaleFactor=1, blocking=1) + url = f"http://localhost:{str(TestQgsSvgCache.port)}/qgis_local_server/QGIS_logo_2017.svg" + image, in_cache = QgsApplication.svgCache().svgAsImage( + url, + 100, + fill=QColor(0, 0, 0), + stroke=QColor(0, 0, 0), + strokeWidth=0.1, + widthScaleFactor=1, + blocking=1, + ) # first should be correct image self.assertTrue( self.image_check( - 'Remote SVG sync', - 'remote_svg_blocking', + "Remote SVG sync", + "remote_svg_blocking", image, color_tolerance=2, allowed_mismatch=20, - use_checkerboard_background=True + use_checkerboard_background=True, ) ) # remote probably in cache - url = f'http://localhost:{str(TestQgsSvgCache.port)}/qgis_local_server/sample_svg.svg' - image, in_cache = QgsApplication.svgCache().svgAsImage(url, 100, fill=QColor(0, 0, 0), stroke=QColor(0, 0, 0), - strokeWidth=0.1, widthScaleFactor=1, blocking=1) + url = f"http://localhost:{str(TestQgsSvgCache.port)}/qgis_local_server/sample_svg.svg" + image, in_cache = QgsApplication.svgCache().svgAsImage( + url, + 100, + fill=QColor(0, 0, 0), + stroke=QColor(0, 0, 0), + strokeWidth=0.1, + widthScaleFactor=1, + blocking=1, + ) self.assertTrue( self.image_check( - 'Remote SVG', - 'remote_svg', + "Remote SVG", + "remote_svg", image, color_tolerance=2, allowed_mismatch=20, - use_checkerboard_background=True + use_checkerboard_background=True, ) ) # missing - url = f'http://localhost:{str(TestQgsSvgCache.port)}/qgis_local_server/xxx.svg' # oooo naughty - image, in_cache = QgsApplication.svgCache().svgAsImage(url, 100, fill=QColor(0, 0, 0), stroke=QColor(0, 0, 0), - strokeWidth=0.1, widthScaleFactor=1, blocking=1) + url = f"http://localhost:{str(TestQgsSvgCache.port)}/qgis_local_server/xxx.svg" # oooo naughty + image, in_cache = QgsApplication.svgCache().svgAsImage( + url, + 100, + fill=QColor(0, 0, 0), + stroke=QColor(0, 0, 0), + strokeWidth=0.1, + widthScaleFactor=1, + blocking=1, + ) self.assertTrue( self.image_check( - 'Remote SVG missing', - 'waiting_svg', + "Remote SVG missing", + "waiting_svg", image, color_tolerance=2, allowed_mismatch=20, - use_checkerboard_background=True + use_checkerboard_background=True, ) ) @@ -251,27 +313,26 @@ def testRemoteSVGBlocking(self): def test_inline_svg(self): inline_svg = """data:image/svg+xml;utf8,""" - image, in_cache = QgsApplication.svgCache().svgAsImage(inline_svg, 100, - fill=QColor(0, - 0, - 0), - stroke=QColor(0, - 0, - 0), - strokeWidth=0.1, - widthScaleFactor=1, - blocking=True) + image, in_cache = QgsApplication.svgCache().svgAsImage( + inline_svg, + 100, + fill=QColor(0, 0, 0), + stroke=QColor(0, 0, 0), + strokeWidth=0.1, + widthScaleFactor=1, + blocking=True, + ) self.assertTrue( self.image_check( - 'Inline svg', - 'inline_svg', + "Inline svg", + "inline_svg", image, color_tolerance=2, allowed_mismatch=20, - use_checkerboard_background=True + use_checkerboard_background=True, ) ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssvgsourcelineedit.py b/tests/src/python/test_qgssvgsourcelineedit.py index 71d1c9a6f781..51dca978f69f 100644 --- a/tests/src/python/test_qgssvgsourcelineedit.py +++ b/tests/src/python/test_qgssvgsourcelineedit.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '19/07/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "19/07/2018" +__copyright__ = "Copyright 2018, The QGIS Project" import os @@ -24,56 +25,56 @@ class TestQgsSvgSourceLineEdit(QgisTestCase): def testGettersSetters(self): - """ test widget getters/setters """ + """test widget getters/setters""" w = QgsSvgSourceLineEdit() spy = QSignalSpy(w.sourceChanged) - w.setSource('source') - self.assertEqual(w.source(), 'source') + w.setSource("source") + self.assertEqual(w.source(), "source") self.assertEqual(len(spy), 1) - self.assertEqual(spy[0][0], 'source') + self.assertEqual(spy[0][0], "source") # no signal for same value - w.setSource('source') - self.assertEqual(w.source(), 'source') + w.setSource("source") + self.assertEqual(w.source(), "source") self.assertEqual(len(spy), 1) - w.setSource('another') - self.assertEqual(w.source(), 'another') + w.setSource("another") + self.assertEqual(w.source(), "another") self.assertEqual(len(spy), 2) - self.assertEqual(spy[1][0], 'another') + self.assertEqual(spy[1][0], "another") def testEmbedding(self): - """Test embedding large SVGs """ + """Test embedding large SVGs""" w = QgsSvgSourceLineEdit() spy = QSignalSpy(w.sourceChanged) - w.setSource('source') - self.assertEqual(w.source(), 'source') + w.setSource("source") + self.assertEqual(w.source(), "source") self.assertEqual(len(spy), 1) - self.assertEqual(spy[0][0], 'source') + self.assertEqual(spy[0][0], "source") - b64 = 'base64:' + ''.join(['x'] * 1000000) + b64 = "base64:" + "".join(["x"] * 1000000) w.setSource(b64) self.assertEqual(w.source(), b64) self.assertEqual(len(spy), 2) self.assertEqual(spy[1][0], b64) - w.setSource(os.path.join(unitTestDataPath(), 'landsat.tif')) - self.assertEqual(w.source(), os.path.join(unitTestDataPath(), 'landsat.tif')) + w.setSource(os.path.join(unitTestDataPath(), "landsat.tif")) + self.assertEqual(w.source(), os.path.join(unitTestDataPath(), "landsat.tif")) self.assertEqual(len(spy), 3) - self.assertEqual(spy[2][0], os.path.join(unitTestDataPath(), 'landsat.tif')) + self.assertEqual(spy[2][0], os.path.join(unitTestDataPath(), "landsat.tif")) w.setSource(b64) self.assertEqual(w.source(), b64) self.assertEqual(len(spy), 4) self.assertEqual(spy[3][0], b64) - w.setSource('') - self.assertEqual(w.source(), '') + w.setSource("") + self.assertEqual(w.source(), "") self.assertEqual(len(spy), 5) - self.assertEqual(spy[4][0], '') + self.assertEqual(spy[4][0], "") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssymbol.py b/tests/src/python/test_qgssymbol.py index f5ad5094930c..39265c797e48 100644 --- a/tests/src/python/test_qgssymbol.py +++ b/tests/src/python/test_qgssymbol.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'January 2016' -__copyright__ = '(C) 2016, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "January 2016" +__copyright__ = "(C) 2016, Nyall Dawson" from qgis.PyQt.QtCore import QDir, QSize, Qt, QPointF @@ -75,9 +75,15 @@ def control_path_prefix(cls): def setUp(self): # Create some simple symbols - self.fill_symbol = QgsFillSymbol.createSimple({'color': '#ffffff', 'outline_color': 'black'}) - self.line_symbol = QgsLineSymbol.createSimple({'color': '#ffffff', 'line_width': '3'}) - self.marker_symbol = QgsMarkerSymbol.createSimple({'color': '#ffffff', 'size': '3', 'outline_color': 'black'}) + self.fill_symbol = QgsFillSymbol.createSimple( + {"color": "#ffffff", "outline_color": "black"} + ) + self.line_symbol = QgsLineSymbol.createSimple( + {"color": "#ffffff", "line_width": "3"} + ) + self.marker_symbol = QgsMarkerSymbol.createSimple( + {"color": "#ffffff", "size": "3", "outline_color": "black"} + ) def testPythonAdditions(self): """ @@ -87,9 +93,9 @@ def testPythonAdditions(self): markerSymbol.symbolLayer(0).setColor(QColor(255, 255, 0)) self.assertEqual(len(markerSymbol), 1) layers = [l.color().name() for l in markerSymbol] - self.assertEqual(layers, ['#ffff00']) - self.assertEqual(markerSymbol[0].color().name(), '#ffff00') - self.assertEqual(markerSymbol[-1].color().name(), '#ffff00') + self.assertEqual(layers, ["#ffff00"]) + self.assertEqual(markerSymbol[0].color().name(), "#ffff00") + self.assertEqual(markerSymbol[-1].color().name(), "#ffff00") with self.assertRaises(IndexError): _ = markerSymbol[1] with self.assertRaises(IndexError): @@ -119,19 +125,29 @@ def testPythonAdditions(self): del markerSymbol[-1] markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Star, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=10)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Star, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + ) + ) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Star, color=QColor(255, 255, 0), - strokeColor=QColor(0, 255, 255), size=10)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Star, + color=QColor(255, 255, 0), + strokeColor=QColor(0, 255, 255), + size=10, + ) + ) self.assertEqual(len(markerSymbol), 2) layers = [l.color().name() for l in markerSymbol] - self.assertEqual(layers, ['#ff0000', '#ffff00']) - self.assertEqual(markerSymbol[0].color().name(), '#ff0000') - self.assertEqual(markerSymbol[-1].color().name(), '#ffff00') - self.assertEqual(markerSymbol[1].color().name(), '#ffff00') - self.assertEqual(markerSymbol[-2].color().name(), '#ff0000') + self.assertEqual(layers, ["#ff0000", "#ffff00"]) + self.assertEqual(markerSymbol[0].color().name(), "#ff0000") + self.assertEqual(markerSymbol[-1].color().name(), "#ffff00") + self.assertEqual(markerSymbol[1].color().name(), "#ffff00") + self.assertEqual(markerSymbol[-2].color().name(), "#ff0000") with self.assertRaises(IndexError): _ = markerSymbol[2] with self.assertRaises(IndexError): @@ -148,49 +164,78 @@ def testPythonAdditions(self): del markerSymbol[1] layers = [l.color().name() for l in markerSymbol] - self.assertEqual(layers, ['#ff0000']) + self.assertEqual(layers, ["#ff0000"]) def testSymbolTypeToString(self): """ Test QgsSymbol.symbolTypeToString """ - self.assertEqual(QgsSymbol.symbolTypeToString(QgsSymbol.SymbolType.Marker), 'Marker') - self.assertEqual(QgsSymbol.symbolTypeToString(QgsSymbol.SymbolType.Line), 'Line') - self.assertEqual(QgsSymbol.symbolTypeToString(QgsSymbol.SymbolType.Fill), 'Fill') - self.assertEqual(QgsSymbol.symbolTypeToString(QgsSymbol.SymbolType.Hybrid), 'Hybrid') + self.assertEqual( + QgsSymbol.symbolTypeToString(QgsSymbol.SymbolType.Marker), "Marker" + ) + self.assertEqual( + QgsSymbol.symbolTypeToString(QgsSymbol.SymbolType.Line), "Line" + ) + self.assertEqual( + QgsSymbol.symbolTypeToString(QgsSymbol.SymbolType.Fill), "Fill" + ) + self.assertEqual( + QgsSymbol.symbolTypeToString(QgsSymbol.SymbolType.Hybrid), "Hybrid" + ) def testSymbolTypeForGeometryType(self): """ Test QgsSymbol.symbolTypeForGeometryType """ - self.assertEqual(QgsSymbol.symbolTypeForGeometryType(QgsWkbTypes.GeometryType.PointGeometry), QgsSymbol.SymbolType.Marker) - self.assertEqual(QgsSymbol.symbolTypeForGeometryType(QgsWkbTypes.GeometryType.LineGeometry), QgsSymbol.SymbolType.Line) - self.assertEqual(QgsSymbol.symbolTypeForGeometryType(QgsWkbTypes.GeometryType.PolygonGeometry), QgsSymbol.SymbolType.Fill) - self.assertEqual(QgsSymbol.symbolTypeForGeometryType(QgsWkbTypes.GeometryType.NullGeometry), QgsSymbol.SymbolType.Hybrid) - self.assertEqual(QgsSymbol.symbolTypeForGeometryType(QgsWkbTypes.GeometryType.UnknownGeometry), QgsSymbol.SymbolType.Hybrid) + self.assertEqual( + QgsSymbol.symbolTypeForGeometryType(QgsWkbTypes.GeometryType.PointGeometry), + QgsSymbol.SymbolType.Marker, + ) + self.assertEqual( + QgsSymbol.symbolTypeForGeometryType(QgsWkbTypes.GeometryType.LineGeometry), + QgsSymbol.SymbolType.Line, + ) + self.assertEqual( + QgsSymbol.symbolTypeForGeometryType( + QgsWkbTypes.GeometryType.PolygonGeometry + ), + QgsSymbol.SymbolType.Fill, + ) + self.assertEqual( + QgsSymbol.symbolTypeForGeometryType(QgsWkbTypes.GeometryType.NullGeometry), + QgsSymbol.SymbolType.Hybrid, + ) + self.assertEqual( + QgsSymbol.symbolTypeForGeometryType( + QgsWkbTypes.GeometryType.UnknownGeometry + ), + QgsSymbol.SymbolType.Hybrid, + ) def testColor(self): """ Test QgsSymbol.color() logic """ - symbol = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_color': '#ffffff'}) - self.assertEqual(symbol.color().name(), '#ff00ff') + symbol = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_color": "#ffffff"} + ) + self.assertEqual(symbol.color().name(), "#ff00ff") # insert a new first layer, symbol color should be taken from that layer second_fill = QgsSimpleFillSymbolLayer(QColor(0, 255, 0)) symbol.insertSymbolLayer(0, second_fill) - self.assertEqual(symbol.color().name(), '#00ff00') + self.assertEqual(symbol.color().name(), "#00ff00") # lock the first layer -- locked color layers are ignored, so symbol color should come from second layer second_fill.setLocked(True) - self.assertEqual(symbol.color().name(), '#ff00ff') + self.assertEqual(symbol.color().name(), "#ff00ff") # add a symbol layer which does not have colors (raster fill) raster_fill = QgsRasterFillSymbolLayer() symbol.insertSymbolLayer(0, raster_fill) self.assertFalse(raster_fill.color().isValid()) # raster fill does not have a valid color, so should be ignored and the 3rd symbol layer color will be returned - self.assertEqual(symbol.color().name(), '#ff00ff') + self.assertEqual(symbol.color().name(), "#ff00ff") def testFlags(self): """ @@ -208,7 +253,7 @@ def testFlags(self): # test that flags are saved/restored via XML doc = QDomDocument() context = QgsReadWriteContext() - element = QgsSymbolLayerUtils.saveSymbol('test', s, doc, context) + element = QgsSymbolLayerUtils.saveSymbol("test", s, doc, context) s2 = QgsSymbolLayerUtils.loadSymbol(element, context) self.assertEqual(s2.flags(), Qgis.SymbolFlag.RendererShouldUseSymbolLevels) @@ -228,84 +273,115 @@ def testCanCauseArtifactsBetweenAdjacentTiles(self): self.assertTrue(symbol.canCauseArtifactsBetweenAdjacentTiles()) def testGeometryRendering(self): - '''Tests rendering a bunch of different geometries, including bad/odd geometries.''' + """Tests rendering a bunch of different geometries, including bad/odd geometries.""" empty_multipolygon = QgsMultiPolygon() empty_multipolygon.addGeometry(QgsPolygon()) empty_polygon = QgsPolygon() empty_linestring = QgsLineString() - tests = [{'name': 'Point', - 'wkt': 'Point (1 2)', - 'reference_image': 'point'}, - {'name': 'MultiPoint', - 'wkt': 'MultiPoint ((10 30),(40 20),(30 10),(20 10))', - 'reference_image': 'multipoint'}, - {'name': 'LineString', - 'wkt': 'LineString (0 0,3 4,4 3)', - 'reference_image': 'linestring'}, - {'name': 'Empty LineString', - 'geom': QgsGeometry(empty_linestring), - 'reference_image': 'empty'}, - {'name': 'MultiLineString', - 'wkt': 'MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0), (3 1, 5 1, 5 0, 6 0))', - 'reference_image': 'multilinestring'}, - {'name': 'Polygon', - 'wkt': 'Polygon ((0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5))', - 'reference_image': 'polygon'}, - {'name': 'Empty Polygon', - 'geom': QgsGeometry(empty_polygon), - 'reference_image': 'empty'}, - {'name': 'MultiPolygon', - 'wkt': 'MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))', - 'reference_image': 'multipolygon'}, - {'name': 'Empty MultiPolygon', - 'geom': QgsGeometry(empty_multipolygon), - 'reference_image': 'empty'}, - {'name': 'CircularString', - 'wkt': 'CIRCULARSTRING(268 415,227 505,227 406)', - 'reference_image': 'circular_string', - 'clip_size': 30}, - {'name': 'CompoundCurve', - 'wkt': 'COMPOUNDCURVE((5 3, 5 13), CIRCULARSTRING(5 13, 7 15, 9 13), (9 13, 9 3), CIRCULARSTRING(9 3, 7 1, 5 3))', - 'reference_image': 'compound_curve', - 'clip_size': 30}, - {'name': 'CurvePolygon', - 'wkt': 'CURVEPOLYGON(CIRCULARSTRING(1 3, 3 5, 4 7, 7 3, 1 3))', - 'reference_image': 'curve_polygon'}, - {'name': 'MultiCurve', - 'wkt': 'MultiCurve((5 5,3 5,3 3,0 3),CIRCULARSTRING(0 0, 2 1,2 2))', - 'reference_image': 'multicurve'}, - {'name': 'CurvePolygon_no_arc', # refs #14028 - 'wkt': 'CURVEPOLYGON(LINESTRING(1 3, 3 5, 4 7, 7 3, 1 3))', - 'reference_image': 'curve_polygon_no_arc'}, - {'name': 'PolyhedralSurface', - 'wkt': 'POLYHEDRALSURFACE Z(((0.0 0.0 1.0,0.0 1.0 0.0,0.0 0.0 0.0,0.0 0.0 1.0)),((0.0 0.0 1.0,0.0 0.0 1.0,0.0 0.0 0.0,0.0 0.0 1.0)),((0.0 0.0 0.0,0.0 0.0 1.0,0.0 0.0 0.0,0.0 0.0 0.0)),((0.0 0.0 0.0,0.0 0.0 0.0,0.0 0.0 0.0,0.0 0.0 0.0)),((0.0 0.0 0.0,0.0 0.0 0.0,0.0 0.0 0.0,0.0 0.0 0.0)),((0.0 1.0 0.0,0.0 0.0 0.0,0.0 1.0 0.0,0.0 1.0 0.0)),((0.0 1.0 0.0,0.0 0.0 0.0,0.0 0.0 0.0,0.0 1.0 0.0)),((1.0 1.0 2.0,1.0 1.0 2.0,0.0 0.0 1.0,1.0 1.0 2.0)),((0.0 0.0 1.0,1.0 1.0 2.0,0.0 0.0 1.0,0.0 0.0 1.0)),((1.0 2.0 1.0,0.0 1.0 0.0,1.0 1.0 2.0,1.0 2.0 1.0)),((1.0 1.0 2.0,0.0 1.0 0.0,0.0 0.0 1.0,1.0 1.0 2.0)),((1.0 2.0 1.0,0.0 1.0 0.0,1.0 2.0 1.0,1.0 2.0 1.0)),((1.0 2.0 1.0,0.0 1.0 0.0,0.0 1.0 0.0,1.0 2.0 1.0)),((0.0 0.0 0.0,0.0 0.0 1.0,0.0 0.0 1.0,0.0 0.0 0.0)),((0.0 0.0 0.0,0.0 0.0 0.0,0.0 0.0 1.0,0.0 0.0 0.0)),((0.0 0.0 1.0,1.0 1.0 2.0,1.0 1.0 2.0,0.0 0.0 1.0)),((0.0 0.0 1.0,0.0 0.0 1.0,1.0 1.0 2.0,0.0 0.0 1.0)),((1.0 0.0 0.0,0.0 0.0 0.0,1.0 0.0 0.0,1.0 0.0 0.0)),((1.0 0.0 0.0,0.0 0.0 0.0,0.0 0.0 0.0,1.0 0.0 0.0)),((0.0 1.0 0.0,1.0 0.0 0.0,0.0 0.0 0.0,0.0 1.0 0.0)),((1.0 0.0 0.0,0.0 0.0 1.0,0.0 0.0 0.0,1.0 0.0 0.0)),((2.0 1.0 1.0,1.0 0.0 0.0,1.0 2.0 1.0,2.0 1.0 1.0)),((1.0 2.0 1.0,1.0 0.0 0.0,0.0 1.0 0.0,1.0 2.0 1.0)),((1.0 1.0 2.0,2.0 1.0 1.0,1.0 1.0 2.0,1.0 1.0 2.0)),((1.0 1.0 2.0,2.0 1.0 1.0,2.0 1.0 1.0,1.0 1.0 2.0)),((1.0 1.0 2.0,2.0 1.0 1.0,1.0 2.0 1.0,1.0 1.0 2.0)),((1.0 1.0 2.0,1.0 2.0 1.0,1.0 2.0 1.0,1.0 1.0 2.0)),((1.0 1.0 2.0,1.0 2.0 1.0,1.0 1.0 2.0,1.0 1.0 2.0)),((1.0 0.0 0.0,2.0 1.0 1.0,1.0 1.0 2.0,1.0 0.0 0.0)),((0.0 0.0 1.0,1.0 0.0 0.0,1.0 1.0 2.0,0.0 0.0 1.0)),((2.0 1.0 1.0,2.0 1.0 1.0,1.0 0.0 0.0,2.0 1.0 1.0)),((1.0 0.0 0.0,2.0 1.0 1.0,1.0 0.0 0.0,1.0 0.0 0.0)))', - 'reference_image': 'polyhedral_surface'}, - {'name': 'TIN', - 'wkt': - 'TIN Z ( ((0 0 0, 1 0 0, 0 1 0, 0 0 0)), ((0 1 0, 1 0 0, 1 1 0, 0 1 0)), ((0 1 0, 0.4 1 0, 0.4 1.5 0, 0 1 0)))', - 'reference_image': 'tin'}, ] + tests = [ + {"name": "Point", "wkt": "Point (1 2)", "reference_image": "point"}, + { + "name": "MultiPoint", + "wkt": "MultiPoint ((10 30),(40 20),(30 10),(20 10))", + "reference_image": "multipoint", + }, + { + "name": "LineString", + "wkt": "LineString (0 0,3 4,4 3)", + "reference_image": "linestring", + }, + { + "name": "Empty LineString", + "geom": QgsGeometry(empty_linestring), + "reference_image": "empty", + }, + { + "name": "MultiLineString", + "wkt": "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0), (3 1, 5 1, 5 0, 6 0))", + "reference_image": "multilinestring", + }, + { + "name": "Polygon", + "wkt": "Polygon ((0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5))", + "reference_image": "polygon", + }, + { + "name": "Empty Polygon", + "geom": QgsGeometry(empty_polygon), + "reference_image": "empty", + }, + { + "name": "MultiPolygon", + "wkt": "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))", + "reference_image": "multipolygon", + }, + { + "name": "Empty MultiPolygon", + "geom": QgsGeometry(empty_multipolygon), + "reference_image": "empty", + }, + { + "name": "CircularString", + "wkt": "CIRCULARSTRING(268 415,227 505,227 406)", + "reference_image": "circular_string", + "clip_size": 30, + }, + { + "name": "CompoundCurve", + "wkt": "COMPOUNDCURVE((5 3, 5 13), CIRCULARSTRING(5 13, 7 15, 9 13), (9 13, 9 3), CIRCULARSTRING(9 3, 7 1, 5 3))", + "reference_image": "compound_curve", + "clip_size": 30, + }, + { + "name": "CurvePolygon", + "wkt": "CURVEPOLYGON(CIRCULARSTRING(1 3, 3 5, 4 7, 7 3, 1 3))", + "reference_image": "curve_polygon", + }, + { + "name": "MultiCurve", + "wkt": "MultiCurve((5 5,3 5,3 3,0 3),CIRCULARSTRING(0 0, 2 1,2 2))", + "reference_image": "multicurve", + }, + { + "name": "CurvePolygon_no_arc", # refs #14028 + "wkt": "CURVEPOLYGON(LINESTRING(1 3, 3 5, 4 7, 7 3, 1 3))", + "reference_image": "curve_polygon_no_arc", + }, + { + "name": "PolyhedralSurface", + "wkt": "POLYHEDRALSURFACE Z(((0.0 0.0 1.0,0.0 1.0 0.0,0.0 0.0 0.0,0.0 0.0 1.0)),((0.0 0.0 1.0,0.0 0.0 1.0,0.0 0.0 0.0,0.0 0.0 1.0)),((0.0 0.0 0.0,0.0 0.0 1.0,0.0 0.0 0.0,0.0 0.0 0.0)),((0.0 0.0 0.0,0.0 0.0 0.0,0.0 0.0 0.0,0.0 0.0 0.0)),((0.0 0.0 0.0,0.0 0.0 0.0,0.0 0.0 0.0,0.0 0.0 0.0)),((0.0 1.0 0.0,0.0 0.0 0.0,0.0 1.0 0.0,0.0 1.0 0.0)),((0.0 1.0 0.0,0.0 0.0 0.0,0.0 0.0 0.0,0.0 1.0 0.0)),((1.0 1.0 2.0,1.0 1.0 2.0,0.0 0.0 1.0,1.0 1.0 2.0)),((0.0 0.0 1.0,1.0 1.0 2.0,0.0 0.0 1.0,0.0 0.0 1.0)),((1.0 2.0 1.0,0.0 1.0 0.0,1.0 1.0 2.0,1.0 2.0 1.0)),((1.0 1.0 2.0,0.0 1.0 0.0,0.0 0.0 1.0,1.0 1.0 2.0)),((1.0 2.0 1.0,0.0 1.0 0.0,1.0 2.0 1.0,1.0 2.0 1.0)),((1.0 2.0 1.0,0.0 1.0 0.0,0.0 1.0 0.0,1.0 2.0 1.0)),((0.0 0.0 0.0,0.0 0.0 1.0,0.0 0.0 1.0,0.0 0.0 0.0)),((0.0 0.0 0.0,0.0 0.0 0.0,0.0 0.0 1.0,0.0 0.0 0.0)),((0.0 0.0 1.0,1.0 1.0 2.0,1.0 1.0 2.0,0.0 0.0 1.0)),((0.0 0.0 1.0,0.0 0.0 1.0,1.0 1.0 2.0,0.0 0.0 1.0)),((1.0 0.0 0.0,0.0 0.0 0.0,1.0 0.0 0.0,1.0 0.0 0.0)),((1.0 0.0 0.0,0.0 0.0 0.0,0.0 0.0 0.0,1.0 0.0 0.0)),((0.0 1.0 0.0,1.0 0.0 0.0,0.0 0.0 0.0,0.0 1.0 0.0)),((1.0 0.0 0.0,0.0 0.0 1.0,0.0 0.0 0.0,1.0 0.0 0.0)),((2.0 1.0 1.0,1.0 0.0 0.0,1.0 2.0 1.0,2.0 1.0 1.0)),((1.0 2.0 1.0,1.0 0.0 0.0,0.0 1.0 0.0,1.0 2.0 1.0)),((1.0 1.0 2.0,2.0 1.0 1.0,1.0 1.0 2.0,1.0 1.0 2.0)),((1.0 1.0 2.0,2.0 1.0 1.0,2.0 1.0 1.0,1.0 1.0 2.0)),((1.0 1.0 2.0,2.0 1.0 1.0,1.0 2.0 1.0,1.0 1.0 2.0)),((1.0 1.0 2.0,1.0 2.0 1.0,1.0 2.0 1.0,1.0 1.0 2.0)),((1.0 1.0 2.0,1.0 2.0 1.0,1.0 1.0 2.0,1.0 1.0 2.0)),((1.0 0.0 0.0,2.0 1.0 1.0,1.0 1.0 2.0,1.0 0.0 0.0)),((0.0 0.0 1.0,1.0 0.0 0.0,1.0 1.0 2.0,0.0 0.0 1.0)),((2.0 1.0 1.0,2.0 1.0 1.0,1.0 0.0 0.0,2.0 1.0 1.0)),((1.0 0.0 0.0,2.0 1.0 1.0,1.0 0.0 0.0,1.0 0.0 0.0)))", + "reference_image": "polyhedral_surface", + }, + { + "name": "TIN", + "wkt": "TIN Z ( ((0 0 0, 1 0 0, 0 1 0, 0 0 0)), ((0 1 0, 1 0 0, 1 1 0, 0 1 0)), ((0 1 0, 0.4 1 0, 0.4 1.5 0, 0 1 0)))", + "reference_image": "tin", + }, + ] for test in tests: def get_geom(): - if 'geom' not in test: - geom = QgsGeometry.fromWkt(test['wkt']) - assert geom and not geom.isNull(), f"Could not create geometry {test['wkt']}" + if "geom" not in test: + geom = QgsGeometry.fromWkt(test["wkt"]) + assert ( + geom and not geom.isNull() + ), f"Could not create geometry {test['wkt']}" else: - geom = test['geom'] + geom = test["geom"] return geom geom = get_geom() rendered_image = self.renderGeometry(geom) self.assertTrue( self.image_check( - test['name'], - test['reference_image'], + test["name"], + test["reference_image"], rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -318,11 +394,11 @@ def get_geom(): rendered_image = self.renderGeometry(geom_z) self.assertTrue( self.image_check( - test['name'] + 'Z', - test['reference_image'], + test["name"] + "Z", + test["reference_image"], rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -331,11 +407,11 @@ def get_geom(): rendered_image = self.renderGeometry(geom_z) self.assertTrue( self.image_check( - test['name'] + 'ZM', - test['reference_image'], + test["name"] + "ZM", + test["reference_image"], rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -345,66 +421,74 @@ def get_geom(): rendered_image = self.renderGeometry(geom_m) self.assertTrue( self.image_check( - test['name'] + 'M', - test['reference_image'], + test["name"] + "M", + test["reference_image"], rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) # test with clipping geom = get_geom() - rendered_image = self.renderGeometry(geom, clipped_geometry=True, clip_size=test.get('clip_size', 10)) + rendered_image = self.renderGeometry( + geom, clipped_geometry=True, clip_size=test.get("clip_size", 10) + ) self.assertTrue( self.image_check( - test['name'], - test['reference_image'] + '_clipped', + test["name"], + test["reference_image"] + "_clipped", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) # test with Z geom_z = get_geom() geom_z.get().addZValue(5) - rendered_image = self.renderGeometry(geom_z, clipped_geometry=True, clip_size=test.get('clip_size', 10)) + rendered_image = self.renderGeometry( + geom_z, clipped_geometry=True, clip_size=test.get("clip_size", 10) + ) self.assertTrue( self.image_check( - test['name'] + 'Z', - test['reference_image'] + '_clipped', + test["name"] + "Z", + test["reference_image"] + "_clipped", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) # test with ZM geom_z.get().addMValue(15) - rendered_image = self.renderGeometry(geom_z, clipped_geometry=True, clip_size=test.get('clip_size', 10)) + rendered_image = self.renderGeometry( + geom_z, clipped_geometry=True, clip_size=test.get("clip_size", 10) + ) self.assertTrue( self.image_check( - test['name'] + 'ZM', - test['reference_image'] + '_clipped', + test["name"] + "ZM", + test["reference_image"] + "_clipped", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) # test with M geom_m = get_geom() geom_m.get().addMValue(15) - rendered_image = self.renderGeometry(geom_m, clipped_geometry=True, clip_size=test.get('clip_size', 10)) + rendered_image = self.renderGeometry( + geom_m, clipped_geometry=True, clip_size=test.get("clip_size", 10) + ) self.assertTrue( self.image_check( - test['name'] + 'M', - test['reference_image'] + '_clipped', + test["name"] + "M", + test["reference_image"] + "_clipped", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -420,7 +504,9 @@ def renderGeometry(self, geom, clipped_geometry=False, clip_size=10): # buffer extent by 10% if extent.width() > 0: if clipped_geometry: - extent = extent.buffered(-(extent.height() + extent.width()) / clip_size) + extent = extent.buffered( + -(extent.height() + extent.width()) / clip_size + ) else: extent = extent.buffered((extent.height() + extent.width()) / 20.0) else: @@ -460,224 +546,226 @@ def renderGeometry(self, geom, clipped_geometry=False, clip_size=10): def testReprojectionErrorsWhileRendering(self): # WKT of a polygon which causes reprojection errors while rendering # (apologies for the ridiculously complex wkt, but I can't find a way to reproduce with simplifiction) - wkt = 'MultiPolygon (((16.93392988400009358 42.77094147300012139, 16.88493899800005238 42.72939687700012712, ' \ - '16.80298912900011032 42.76349518400014915, 16.85816491000014139 42.78400299700011544, ' \ - '16.93392988400009358 42.77094147300012139)),((17.38200931100010393 42.79783763200002511, ' \ - '17.65894616000011297 42.74298737200008702, 17.74887129000009622 42.69456614800010641, ' \ - '17.32374108200008322 42.79083893400003547, 17.38200931100010393 42.79783763200002511)),' \ - '((16.768565300000148 42.97223541900014254, 17.03207441500009622 42.98261139500014849, ' \ - '17.13184655000009116 42.96954987200014386, 17.20020592500009116 42.92177969000012183, ' \ - '16.85141035200010151 42.90070221600008438, 16.65544681100004709 42.92625560099999404, ' \ - '16.70679772200014668 42.96954987200014386, 16.63168379000003938 42.98261139500014849, ' \ - '16.768565300000148 42.97223541900014254)),((17.05567467500011958 43.02895742400001211, ' \ - '17.24024498800011429 43.02277252800014651, 17.74146569100011561 42.83926015800001608, ' \ - '17.70736738400009358 42.88703034100014122, 17.65334906206413734 42.8909283361407887, ' \ - '17.70158573400010482 42.91950022500007833, 17.81175988700005064 42.909862570000044, ' \ - '17.85847538200005147 42.81697418200012351, 18.22413781700009849 42.62807098500009317, ' \ - '18.43735477700010961 42.55921213800017711, 18.4371480710000526 42.4934022020000981, ' \ - '18.49642988400009358 42.41632721600008438, 18.23894290500010129 42.55906810100005089, ' \ - '18.21753991000014139 42.6201032570001388, 18.07601972700010151 42.65131256700003348, ' \ - '18.0432235040000819 42.70205312700007028, 17.90162194100014403 42.75189850500014188, ' \ - '17.8928328790000819 42.79083893400003547, 17.72095787900005348 42.8262393250000315, ' \ - '17.7618921230000808 42.77871328300012976, 17.74870853000004445 42.77204010600017625, ' \ - '17.21387780000011958 42.98261139500014849, 17.04615319100011561 42.9950625670000619, ' \ - '17.00163821700004974 43.05149974200010377, 17.05567467500011958 43.02895742400001211)),' \ - '((16.19467207100007045 43.07440827000000638, 16.254893425000148 43.06854889500006323, ' \ - '16.08716881600014403 43.01146067900008063, 16.04883873800011429 43.06517161700004692, ' \ - '16.19467207100007045 43.07440827000000638)),((16.56275475400011032 43.22898997600010773, ' \ - '16.65951582100009887 43.21596914300012315, 16.72771243600001867 43.16461823100003414, ' \ - '17.19336998800014271 43.12726471600016964, 16.67017662900013875 43.12547435099999404, ' \ - '16.37159264400014536 43.19550202000006323, 16.49642988400006516 43.21808502800014651, ' \ - '16.58326256600014403 43.18866608300005794, 16.52051842500006273 43.22898997600010773, ' \ - '16.56275475400011032 43.22898997600010773)),((16.80681399800010922 43.34247467700005529, ' \ - '16.89234459700011826 43.31220123900006058, 16.84620201900008851 43.27338288000005662, ' \ - '16.62826582100012729 43.26373932500008834, 16.50074303500014139 43.28424713700003679, ' \ - '16.42188561300008587 43.31757233300011478, 16.40577233200011165 43.33270905200011214, ' \ - '16.45346113400009358 43.35317617400009738, 16.42628014400008851 43.39411041900011412, ' \ - '16.44703209700008983 43.39484284100014122, 16.80681399800010922 43.34247467700005529)),' \ - '((16.29818769600012729 43.40363190300011809, 16.30274498800008587 43.38727448100009099, ' \ - '16.39144941500012465 43.34638092700005529, 16.348643425000148 43.33869049700003018, ' \ - '16.20045006600014403 43.40704987200003018, 16.29818769600012729 43.40363190300011809)),' \ - '((16.33415774800010922 43.50153229400014254, 16.3752547540000819 43.49017975500008504, ' \ - '16.21143639400008851 43.49005768400009231, 16.26441491000014139 43.51288483300011478, ' \ - '16.33415774800010922 43.50153229400014254)),((15.67888431100004709 43.64801666900014254, ' \ - '15.74040774800010922 43.62750885600009099, 15.67204837300002396 43.63743724200010377, ' \ - '15.60377037900013875 43.67470937700007028, 15.67888431100004709 43.64801666900014254)),' \ - '((15.36736087300005238 43.79010651200015047, 15.39568118600007551 43.7724063170000619, ' \ - '15.22779381600014403 43.87445709800014981, 15.24073326900014536 43.88076406500009341, ' \ - '15.36736087300005238 43.79010651200015047)),((15.44271894600009887 43.89907461100013109, ' \ - '15.35865319100014403 43.91937897300014981, 15.26124108200011165 44.01105377800003282, ' \ - '15.38404381600008719 43.9701602230000077, 15.44271894600009887 43.89907461100013109)),' \ - '((15.22575931100010393 44.06622955900014915, 15.25440514400008851 44.01788971600014122, ' \ - '15.12183678500014139 44.09223053600005926, 15.06251061300008587 44.16193268400012073, ' \ - '15.22575931100010393 44.06622955900014915)),((14.83545983200014007 44.15102773600013109, ' \ - '14.85726972700010151 44.15204498900000374, 14.86915123800014271 44.14052969000006499, ' \ - '14.83521569100008719 44.14166901200009363, 14.81983483200014007 44.15302155199999845, ' \ - '14.82243899800005238 44.16868724200004692, 14.83545983200014007 44.15102773600013109)),' \ - '((14.98511803500011297 44.09096914300012315, 15.21680748800008587 43.91278717700008372, ' \ - '15.13331139400011693 43.92121002800003282, 15.19450931100004709 43.87262604400017096, ' \ - '15.10661868600007551 43.92544179900015422, 14.84961998800014271 44.17560455900014915, ' \ - '14.98511803500011297 44.09096914300012315)),((14.765961134000122 44.26504140800015819, ' \ - '14.74854576900014536 44.26166413000014188, 14.73959394600012729 44.28017812700015554, ' \ - '14.79167728000007287 44.27252838700003679, 14.765961134000122 44.26504140800015819)),' \ - '((14.66138756600011561 44.30866120000014519, 14.6407983730000808 44.31183502800003282, ' \ - '14.59506269600007045 44.34711334800006455, 14.643565300000148 44.32575104400011412, ' \ - '14.66138756600011561 44.30866120000014519)),((14.81120853000004445 44.35004303600000242, ' \ - '14.75619550900009358 44.36399974200004692, 14.76343834700008983 44.41535065300017493, ' \ - '14.80323326900008851 44.40550364800004957, 14.81120853000004445 44.35004303600000242)),' \ - '((14.27116946700002131 44.61253489800004957, 14.23259524800005238 44.62604401200012205, ' \ - '14.2657983730000808 44.67951080900003547, 14.28044681100007551 44.67755768400009231, ' \ - '14.27116946700002131 44.61253489800004957)),((14.84522545700008322 44.60053131700011875, ' \ - '14.93824303500014139 44.59414297100001079, 15.07553144600007045 44.48407623900006058, ' \ - '14.91114342500011958 44.54547760600014783, 15.04802493600004709 44.43943919500001982, ' \ - '15.09669030000009116 44.41518789300000947, 15.04151451900014536 44.47662995000008834, ' \ - '15.25440514400008851 44.34003327000000638, 15.165049675000148 44.36737702000006323, ' \ - '15.22022545700008322 44.3127302100001117, 15.13086998800008587 44.33258698100003414, ' \ - '15.17237389400014536 44.29913971600016964, 15.12875410200007309 44.31199778900018771, ' \ - '15.08920332100009887 44.37421295800000109, 15.11719811300014271 44.38719310099999404, ' \ - '15.04900149800010922 44.39468008000015686, 14.89747155000009116 44.49091217699999845, ' \ - '14.91863040500010129 44.50454336100013109, 14.87696373800011429 44.55975983300005794, ' \ - '14.73365319100008719 44.70319245000014519, 14.84522545700008322 44.60053131700011875)),' \ - '((14.41000410200010151 44.60097890800001608, 14.52662194100011561 44.50372955900012073, ' \ - '14.53435306100010393 44.48407623900006058, 14.42261803500008455 44.57387929900009738, ' \ - '14.36304772200014668 44.57343170800000109, 14.38257897200014668 44.60325755399999537, ' \ - '14.33578535200007309 44.71678294500010509, 14.39747155000009116 44.6856143250000315, ' \ - '14.41000410200010151 44.60097890800001608)),((14.75326582100007045 44.84585195500012844, ' \ - '14.74048912900011032 44.82050202000000638, 14.82243899800005238 44.77142975500005662, ' \ - '14.84961998800014271 44.70319245000014519, 14.65788821700004974 44.79877350500014188, ' \ - '14.7268172540000819 44.79877350500014188, 14.6858016290000819 44.8471540390000456, ' \ - '14.75326582100007045 44.84585195500012844)),((14.47103925900006516 44.95392487200003018, ' \ - '14.45191491000008455 44.79877350500014188, 14.47217858200011165 44.7079531920000619, ' \ - '14.53435306100010393 44.63426341400010244, 14.51335696700007816 44.618841864000089, ' \ - '14.42790774800005238 44.65656159100014122, 14.29420006600008719 44.9086367860001161, ' \ - '14.30152428500011297 44.94342682500014519, 14.38738040500004445 44.90900299700003018, ' \ - '14.39031009200004974 44.96039459800012139, 14.41138756600008719 44.95636627800014651, ' \ - '14.27849368600004709 45.1133487000000315, 14.29957116000014139 45.16233958499999801, ' \ - '14.35621178500014139 45.16925690300008966, 14.387705925000148 45.03904857000013351, ' \ - '14.47103925900006516 44.95392487200003018)),((14.56332441500012465 45.24974192900008063, ' \ - '14.62378991000011297 45.17548248900006058, 14.59742272200011826 45.16644928600005926, ' \ - '14.66529381600011561 45.16181061400011743, 14.66529381600011561 45.08734772300006455, ' \ - '14.74048912900011032 45.07306549700014386, 14.81495201900008851 44.97748444200009033, ' \ - '14.70639082100009887 44.9467227230000077, 14.62891686300014271 44.97817617400004053, ' \ - '14.62086022200008983 45.04559967700011214, 14.61695397200008983 45.02464427300007799, ' \ - '14.51050866000014139 45.03217194200011875, 14.43873131600014403 45.07050202000006323, ' \ - '14.4670516290000819 45.12409088700015047, 14.53012129000009622 45.13483307500014519, ' \ - '14.53435306100010393 45.23753489800002114, 14.56332441500012465 45.24974192900008063)),' \ - '((16.36947066200013978 46.54057118800012915, 16.63767134600004738 46.47447703100009164, ' \ - '16.75508020000012266 46.38187286400001597, 16.83765913900006694 46.38187286400001597, ' \ - '16.88923221800007468 46.29216257800014489, 17.05294315600005461 46.15346303300005104, ' \ - '17.20859257000006437 46.11656606000003933, 17.27587528500004055 46.01202463800002818, ' \ - '17.31680301900004793 45.99765859000002877, 17.29013798000011093 45.98463612900009423, ' \ - '17.40620324700006449 45.94365671800015605, 17.59110152100009827 45.93621531200012953, ' \ - '17.65652388500006964 45.84541982000014571, 17.80917606600013414 45.81441396100005647, ' \ - '17.85806197100004056 45.77172922800004073, 18.21121870900006456 45.78537180600012846, ' \ - '18.40438521300006869 45.74180857400001798, 18.57347049900010916 45.81668772400014689, ' \ - '18.6556360270001278 45.90758656800015558, 18.7755253500000947 45.88283355700004051, ' \ - '18.90130578600007993 45.93120269800006383, 18.87288374800004931 45.89523590100002082, ' \ - '18.90699019400011593 45.86795074500018643, 18.85531376100007606 45.85735707600009903, ' \ - '18.84497847500006174 45.8157058720000947, 18.96848514800012708 45.66873809800016204, ' \ - '18.90357954900008508 45.57308502200005762, 18.94171675700005153 45.53892689999999277, ' \ - '19.01809452300011571 45.56740061400002162, 19.10625451700005328 45.51164174500017623, ' \ - '19.00961958800010621 45.49867095900005154, 19.00300500400010151 45.45536611000007099, ' \ - '19.03742150900006891 45.42229319300010104, 18.97592655400006834 45.39495636000008005, ' \ - '19.09199182100007874 45.34999786400005917, 19.12475467900009107 45.29811472600006539, ' \ - '19.36308638500014467 45.24824696900010679, 19.40783817500010855 45.20313344400013023, ' \ - '19.39068160000005037 45.16933705700016333, 19.22593713300008744 45.16194732700016345, ' \ - '19.12186079900010327 45.195795390000157, 19.13767378700009658 45.14603098600004216, ' \ - '19.04486291500009543 45.13724599300006446, 19.08227665200013234 45.08494944300004192, ' \ - '19.0872375890000967 44.97710072800013847, 19.13167932100006396 44.95317454000003465, ' \ - '19.06667036900009293 44.90568389900012392, 18.99142948400006503 44.9149339800001286, ' \ - '19.01582076000008215 44.86563466400004074, 18.88962691200009658 44.86119049100013001, ' \ - '18.78338016700013213 44.91374542300012251, 18.79175174900009893 45.00154368100008639, ' \ - '18.73831831900008638 45.0159097290000858, 18.68405806500004473 45.08479441400000098, ' \ - '18.64871138500012648 45.06267689999999959, 18.61667199700013953 45.09766184500010411, ' \ - '18.54959598800010667 45.09476796500011631, 18.51703983500007666 45.05585561200003042, ' \ - '18.23788374800011525 45.15745147700012296, 18.15365116400005263 45.0975584930001645, ' \ - '18.00347945100011771 45.1493382780000303, 17.83573775200005684 45.0644338990000648, ' \ - '17.68473921700012852 45.1639627080000281, 17.48185754400009273 45.11440500900012296, ' \ - '17.49622359200009214 45.1416901650001563, 17.44775109900012922 45.13430043600014585, ' \ - '17.44330692500011537 45.16205068000009248, 17.38243208800008688 45.1396231090000839, ' \ - '17.26895064300006766 45.18954254200015441, 17.24548954300007608 45.15538442000017483, ' \ - '17.18709517400012032 45.14856313100001728, 17.0363033440001459 45.23047027600007652, ' \ - '17.00829471800011561 45.21615590500009318, 17.00829471800011561 45.24416453100009505, ' \ - '16.94731652900014751 45.23568959600000028, 16.9243721930001243 45.28452382500016427, ' \ - '16.81171757000004163 45.18122263700009, 16.52894413300009546 45.22225372400005483, ' \ - '16.38921106000003647 45.11683380099999852, 16.31624393700010955 45.00123362300008978, ' \ - '16.12152714000009723 45.09616322900008356, 16.02044803900011516 45.213933818000001, ' \ - '15.79234826700013627 45.18980092400012438, 15.76361617000014803 44.97555043600003444, ' \ - '15.7308533120001357 44.92723297200008403, 15.77343469200010873 44.84501576800015243, ' \ - '15.71607385200013596 44.80320953400008932, 15.72847619600008784 44.76910308800002269, ' \ - '15.80568078600006743 44.69665273000013883, 15.88877648900006534 44.72424794500012979, ' \ - '15.96897831200004703 44.63924021400013942, 16.02830285600006732 44.62471913700009907, ' \ - '16.04473596200011798 44.58937245700018082, 16.00608199000004106 44.54100331600012908, ' \ - '16.11646285000011858 44.52146962500013672, 16.15966434700004584 44.41610138000002905, ' \ - '16.13827030500004867 44.37760243800015303, 16.20286584400008678 44.35977406800010669, ' \ - '16.18756962000011868 44.28241444999999032, 16.21578495300011014 44.20815541600011045, ' \ - '16.32688928200008149 44.08237498000012522, 16.50103885900011846 43.99271637000008184, ' \ - '16.67859908100004418 43.8406843060001421, 16.71260217300007866 43.77151540100005889, ' \ - '17.03051558500007445 43.54847991900005866, 17.27050093600007585 43.46321380700000248, ' \ - '17.28993127500007176 43.3034302780000786, 17.44206669100009321 43.15243174300015028, ' \ - '17.6284119050001209 43.04657257100008394, 17.66272505700004558 42.96569895500012137, ' \ - '17.63450972400008254 42.950402731000068, 17.51563561300008587 42.95888906500012183, ' \ - '17.47087649800005238 43.01341380400010905, 17.50196373800014271 43.03099192900005221, ' \ - '17.43360436300014271 43.01740143400009231, 17.46021569100011561 43.03099192900005221, ' \ - '17.42611738400009358 43.06517161700004692, 17.4045516290000819 43.05149974200010377, ' \ - '17.31625410200012993 43.12726471600016964, 17.11394290500004445 43.21320221600008438, ' \ - '16.88062584700011826 43.40595123900006058, 16.62582441500009622 43.44904205900009231, ' \ - '16.52466881600011561 43.51080963700009363, 16.39144941500012465 43.51080963700009363, ' \ - '16.47339928500008455 43.5381533870001789, 16.43384850400013875 43.54975006700000506, ' \ - '16.11768639400008851 43.52448151200003679, 16.17237389400014536 43.4896914730000077, ' \ - '16.11312910200004467 43.47890859600009605, 15.95948326900011693 43.50397370000008834, ' \ - '15.987315300000148 43.54490794500010509, 15.92530358200011165 43.55857982000004824, ' \ - '15.91895592500009116 43.62872955900012073, 15.96631920700011165 43.64118073100003414, ' \ - '15.90479576900014536 43.64801666900014254, 15.95297285200010151 43.65086497599999404, ' \ - '15.95045006600008719 43.68854401200015047, 15.70630944100008719 43.76341380400005221, ' \ - '15.6174422540000819 43.82550690300017493, 15.66309655000009116 43.81297435099999404, ' \ - '15.67888431100004709 43.81928131700011875, 15.45508873800014271 43.92804596600014122, ' \ - '15.14454186300011429 44.19546133000015686, 15.15219160200012993 44.23529694200014717, ' \ - '15.11036217500011958 44.26434967700011214, 15.14063561300011429 44.28245677300013483, ' \ - '15.17660566500009622 44.24994538000005662, 15.20777428500008455 44.27277252800014651, ' \ - '15.19809004000012465 44.30166250200007028, 15.295258009000122 44.25067780199999845, ' \ - '15.30274498800008587 44.29913971600016964, 15.26124108200011165 44.33258698100003414, ' \ - '15.42448978000001603 44.26797109600006763, 15.52865644600009887 44.27179596600008438, ' \ - '15.30795332100009887 44.35439687700007028, 15.00733483200014007 44.56972890800012976, ' \ - '14.883799675000148 44.7236188820001388, 14.883799675000148 44.86147695500012844, 14.92164147200008983 ' \ - '44.95880768400009231, 14.85279381600011561 45.09365469000000815, 14.65788821700004974 ' \ - '45.19660065300017493, 14.57081139400008851 45.29364655200011214, 14.31153405000009116 ' \ - '45.34398021000005485, 14.23259524800005238 45.14935944200000506, 14.17937259200007816 ' \ - '45.13450755400005221, 14.19312584700008983 45.10561758000012844, 14.14389082100007045 ' \ - '45.05939362200003018, 14.151377800000148 44.97748444200009033, 14.06885826900014536 ' \ - '44.94953034100014122, 14.08383222700007309 44.9863955750000315, 14.04029381600014403 ' \ - '45.03896719000015025, 14.0756942070000548 44.98371002800003282, 14.02051842500011958 ' \ - '44.90110911700004692, 13.97266686300011429 44.90110911700004692, 13.99301191500009622 ' \ - '44.88129303600014453, 13.97266686300011429 44.82664622599999404, 14.00001061300008587 ' \ - '44.81305573100003414, 13.89014733200011165 44.83348216400010244, 13.91797936300014271 ' \ - '44.77826569200009033, 13.90316816500009622 44.77240631700014717, 13.89698326900011693 ' \ - '44.81305573100003414, 13.78711998800014271 44.87506745000008834, 13.84229576900008851 ' \ - '44.88812897300006455, 13.79460696700010658 44.89496491100008768, 13.77409915500007287 ' \ - '44.96381256700014717, 13.6232202480000808 45.07306549700014386, 13.61255944100014403 ' \ - '45.11786530199999845, 13.72624759200004974 45.13450755400005221, 13.5959578790000819 ' \ - '45.14541250200001343, 13.57545006600011561 45.26487864800007799, 13.60271243600001867 ' \ - '45.28534577000012007, 13.57545006600011561 45.30646393400006389, 13.60954837300005238 ' \ - '45.32013580900017757, 13.54127037900013875 45.34613678600005926, 13.50709069100014403 ' \ - '45.51190827000000638, 13.62901778100007277 45.45898346000016943, 13.75929406800014476 ' \ - '45.46316925100011019, 13.88900191200011136 45.42363678000005223, 13.98263960800005634 ' \ - '45.47531321200001742, 13.97189091000012695 45.5142255660000643, 14.09291711400010172 ' \ - '45.47391794800002174, 14.21869755100007637 45.49717234400004884, 14.37279667100006009 ' \ - '45.47784535800009564, 14.4689148350000778 45.52559438100014688, 14.49857710800012001 ' \ - '45.59618438800005435, 14.58094934100009255 45.66780792200010808, 14.66848921700008646 ' \ - '45.53396596300005683, 14.79716353300005949 45.46518463200006011, 14.88160282300009385 ' \ - '45.46978383400001178, 14.9226339110000481 45.51494903600017494, 15.13926151500010064 ' \ - '45.43004465799999991, 15.32519331800011742 45.45283396399999276, 15.36136682100004691 ' \ - '45.48203114900003641, 15.29666792800006192 45.52295888300012905, 15.2685559480001416 ' \ - '45.60166208900012919, 15.37376916500011248 45.64021270800010655, 15.25501672300006817 ' \ - '45.72346344000011698, 15.42906294700014769 45.77529490200011253, 15.45128381300008868 ' \ - '45.81513743100013869, 15.67607629400006886 45.84169911700014666, 15.65943648300003588 ' \ - '45.88882802400014782, 15.69798710100010908 46.0362092080000167, 15.58988000500005455 ' \ - '46.11351715100001059, 15.62284956800010605 46.19170359400006021, 16.01920780400010358 ' \ - '46.29882883700007312, 16.05961877400008575 46.33231516600015709, 16.0579651280001201 ' \ - '46.37753204400003426, 16.2756262620000598 46.37316538500006402, 16.23490523300009158 ' \ - '46.4933389280001137, 16.36947066200013978 46.54057118800012915))) ' + wkt = ( + "MultiPolygon (((16.93392988400009358 42.77094147300012139, 16.88493899800005238 42.72939687700012712, " + "16.80298912900011032 42.76349518400014915, 16.85816491000014139 42.78400299700011544, " + "16.93392988400009358 42.77094147300012139)),((17.38200931100010393 42.79783763200002511, " + "17.65894616000011297 42.74298737200008702, 17.74887129000009622 42.69456614800010641, " + "17.32374108200008322 42.79083893400003547, 17.38200931100010393 42.79783763200002511))," + "((16.768565300000148 42.97223541900014254, 17.03207441500009622 42.98261139500014849, " + "17.13184655000009116 42.96954987200014386, 17.20020592500009116 42.92177969000012183, " + "16.85141035200010151 42.90070221600008438, 16.65544681100004709 42.92625560099999404, " + "16.70679772200014668 42.96954987200014386, 16.63168379000003938 42.98261139500014849, " + "16.768565300000148 42.97223541900014254)),((17.05567467500011958 43.02895742400001211, " + "17.24024498800011429 43.02277252800014651, 17.74146569100011561 42.83926015800001608, " + "17.70736738400009358 42.88703034100014122, 17.65334906206413734 42.8909283361407887, " + "17.70158573400010482 42.91950022500007833, 17.81175988700005064 42.909862570000044, " + "17.85847538200005147 42.81697418200012351, 18.22413781700009849 42.62807098500009317, " + "18.43735477700010961 42.55921213800017711, 18.4371480710000526 42.4934022020000981, " + "18.49642988400009358 42.41632721600008438, 18.23894290500010129 42.55906810100005089, " + "18.21753991000014139 42.6201032570001388, 18.07601972700010151 42.65131256700003348, " + "18.0432235040000819 42.70205312700007028, 17.90162194100014403 42.75189850500014188, " + "17.8928328790000819 42.79083893400003547, 17.72095787900005348 42.8262393250000315, " + "17.7618921230000808 42.77871328300012976, 17.74870853000004445 42.77204010600017625, " + "17.21387780000011958 42.98261139500014849, 17.04615319100011561 42.9950625670000619, " + "17.00163821700004974 43.05149974200010377, 17.05567467500011958 43.02895742400001211))," + "((16.19467207100007045 43.07440827000000638, 16.254893425000148 43.06854889500006323, " + "16.08716881600014403 43.01146067900008063, 16.04883873800011429 43.06517161700004692, " + "16.19467207100007045 43.07440827000000638)),((16.56275475400011032 43.22898997600010773, " + "16.65951582100009887 43.21596914300012315, 16.72771243600001867 43.16461823100003414, " + "17.19336998800014271 43.12726471600016964, 16.67017662900013875 43.12547435099999404, " + "16.37159264400014536 43.19550202000006323, 16.49642988400006516 43.21808502800014651, " + "16.58326256600014403 43.18866608300005794, 16.52051842500006273 43.22898997600010773, " + "16.56275475400011032 43.22898997600010773)),((16.80681399800010922 43.34247467700005529, " + "16.89234459700011826 43.31220123900006058, 16.84620201900008851 43.27338288000005662, " + "16.62826582100012729 43.26373932500008834, 16.50074303500014139 43.28424713700003679, " + "16.42188561300008587 43.31757233300011478, 16.40577233200011165 43.33270905200011214, " + "16.45346113400009358 43.35317617400009738, 16.42628014400008851 43.39411041900011412, " + "16.44703209700008983 43.39484284100014122, 16.80681399800010922 43.34247467700005529))," + "((16.29818769600012729 43.40363190300011809, 16.30274498800008587 43.38727448100009099, " + "16.39144941500012465 43.34638092700005529, 16.348643425000148 43.33869049700003018, " + "16.20045006600014403 43.40704987200003018, 16.29818769600012729 43.40363190300011809))," + "((16.33415774800010922 43.50153229400014254, 16.3752547540000819 43.49017975500008504, " + "16.21143639400008851 43.49005768400009231, 16.26441491000014139 43.51288483300011478, " + "16.33415774800010922 43.50153229400014254)),((15.67888431100004709 43.64801666900014254, " + "15.74040774800010922 43.62750885600009099, 15.67204837300002396 43.63743724200010377, " + "15.60377037900013875 43.67470937700007028, 15.67888431100004709 43.64801666900014254))," + "((15.36736087300005238 43.79010651200015047, 15.39568118600007551 43.7724063170000619, " + "15.22779381600014403 43.87445709800014981, 15.24073326900014536 43.88076406500009341, " + "15.36736087300005238 43.79010651200015047)),((15.44271894600009887 43.89907461100013109, " + "15.35865319100014403 43.91937897300014981, 15.26124108200011165 44.01105377800003282, " + "15.38404381600008719 43.9701602230000077, 15.44271894600009887 43.89907461100013109))," + "((15.22575931100010393 44.06622955900014915, 15.25440514400008851 44.01788971600014122, " + "15.12183678500014139 44.09223053600005926, 15.06251061300008587 44.16193268400012073, " + "15.22575931100010393 44.06622955900014915)),((14.83545983200014007 44.15102773600013109, " + "14.85726972700010151 44.15204498900000374, 14.86915123800014271 44.14052969000006499, " + "14.83521569100008719 44.14166901200009363, 14.81983483200014007 44.15302155199999845, " + "14.82243899800005238 44.16868724200004692, 14.83545983200014007 44.15102773600013109))," + "((14.98511803500011297 44.09096914300012315, 15.21680748800008587 43.91278717700008372, " + "15.13331139400011693 43.92121002800003282, 15.19450931100004709 43.87262604400017096, " + "15.10661868600007551 43.92544179900015422, 14.84961998800014271 44.17560455900014915, " + "14.98511803500011297 44.09096914300012315)),((14.765961134000122 44.26504140800015819, " + "14.74854576900014536 44.26166413000014188, 14.73959394600012729 44.28017812700015554, " + "14.79167728000007287 44.27252838700003679, 14.765961134000122 44.26504140800015819))," + "((14.66138756600011561 44.30866120000014519, 14.6407983730000808 44.31183502800003282, " + "14.59506269600007045 44.34711334800006455, 14.643565300000148 44.32575104400011412, " + "14.66138756600011561 44.30866120000014519)),((14.81120853000004445 44.35004303600000242, " + "14.75619550900009358 44.36399974200004692, 14.76343834700008983 44.41535065300017493, " + "14.80323326900008851 44.40550364800004957, 14.81120853000004445 44.35004303600000242))," + "((14.27116946700002131 44.61253489800004957, 14.23259524800005238 44.62604401200012205, " + "14.2657983730000808 44.67951080900003547, 14.28044681100007551 44.67755768400009231, " + "14.27116946700002131 44.61253489800004957)),((14.84522545700008322 44.60053131700011875, " + "14.93824303500014139 44.59414297100001079, 15.07553144600007045 44.48407623900006058, " + "14.91114342500011958 44.54547760600014783, 15.04802493600004709 44.43943919500001982, " + "15.09669030000009116 44.41518789300000947, 15.04151451900014536 44.47662995000008834, " + "15.25440514400008851 44.34003327000000638, 15.165049675000148 44.36737702000006323, " + "15.22022545700008322 44.3127302100001117, 15.13086998800008587 44.33258698100003414, " + "15.17237389400014536 44.29913971600016964, 15.12875410200007309 44.31199778900018771, " + "15.08920332100009887 44.37421295800000109, 15.11719811300014271 44.38719310099999404, " + "15.04900149800010922 44.39468008000015686, 14.89747155000009116 44.49091217699999845, " + "14.91863040500010129 44.50454336100013109, 14.87696373800011429 44.55975983300005794, " + "14.73365319100008719 44.70319245000014519, 14.84522545700008322 44.60053131700011875))," + "((14.41000410200010151 44.60097890800001608, 14.52662194100011561 44.50372955900012073, " + "14.53435306100010393 44.48407623900006058, 14.42261803500008455 44.57387929900009738, " + "14.36304772200014668 44.57343170800000109, 14.38257897200014668 44.60325755399999537, " + "14.33578535200007309 44.71678294500010509, 14.39747155000009116 44.6856143250000315, " + "14.41000410200010151 44.60097890800001608)),((14.75326582100007045 44.84585195500012844, " + "14.74048912900011032 44.82050202000000638, 14.82243899800005238 44.77142975500005662, " + "14.84961998800014271 44.70319245000014519, 14.65788821700004974 44.79877350500014188, " + "14.7268172540000819 44.79877350500014188, 14.6858016290000819 44.8471540390000456, " + "14.75326582100007045 44.84585195500012844)),((14.47103925900006516 44.95392487200003018, " + "14.45191491000008455 44.79877350500014188, 14.47217858200011165 44.7079531920000619, " + "14.53435306100010393 44.63426341400010244, 14.51335696700007816 44.618841864000089, " + "14.42790774800005238 44.65656159100014122, 14.29420006600008719 44.9086367860001161, " + "14.30152428500011297 44.94342682500014519, 14.38738040500004445 44.90900299700003018, " + "14.39031009200004974 44.96039459800012139, 14.41138756600008719 44.95636627800014651, " + "14.27849368600004709 45.1133487000000315, 14.29957116000014139 45.16233958499999801, " + "14.35621178500014139 45.16925690300008966, 14.387705925000148 45.03904857000013351, " + "14.47103925900006516 44.95392487200003018)),((14.56332441500012465 45.24974192900008063, " + "14.62378991000011297 45.17548248900006058, 14.59742272200011826 45.16644928600005926, " + "14.66529381600011561 45.16181061400011743, 14.66529381600011561 45.08734772300006455, " + "14.74048912900011032 45.07306549700014386, 14.81495201900008851 44.97748444200009033, " + "14.70639082100009887 44.9467227230000077, 14.62891686300014271 44.97817617400004053, " + "14.62086022200008983 45.04559967700011214, 14.61695397200008983 45.02464427300007799, " + "14.51050866000014139 45.03217194200011875, 14.43873131600014403 45.07050202000006323, " + "14.4670516290000819 45.12409088700015047, 14.53012129000009622 45.13483307500014519, " + "14.53435306100010393 45.23753489800002114, 14.56332441500012465 45.24974192900008063))," + "((16.36947066200013978 46.54057118800012915, 16.63767134600004738 46.47447703100009164, " + "16.75508020000012266 46.38187286400001597, 16.83765913900006694 46.38187286400001597, " + "16.88923221800007468 46.29216257800014489, 17.05294315600005461 46.15346303300005104, " + "17.20859257000006437 46.11656606000003933, 17.27587528500004055 46.01202463800002818, " + "17.31680301900004793 45.99765859000002877, 17.29013798000011093 45.98463612900009423, " + "17.40620324700006449 45.94365671800015605, 17.59110152100009827 45.93621531200012953, " + "17.65652388500006964 45.84541982000014571, 17.80917606600013414 45.81441396100005647, " + "17.85806197100004056 45.77172922800004073, 18.21121870900006456 45.78537180600012846, " + "18.40438521300006869 45.74180857400001798, 18.57347049900010916 45.81668772400014689, " + "18.6556360270001278 45.90758656800015558, 18.7755253500000947 45.88283355700004051, " + "18.90130578600007993 45.93120269800006383, 18.87288374800004931 45.89523590100002082, " + "18.90699019400011593 45.86795074500018643, 18.85531376100007606 45.85735707600009903, " + "18.84497847500006174 45.8157058720000947, 18.96848514800012708 45.66873809800016204, " + "18.90357954900008508 45.57308502200005762, 18.94171675700005153 45.53892689999999277, " + "19.01809452300011571 45.56740061400002162, 19.10625451700005328 45.51164174500017623, " + "19.00961958800010621 45.49867095900005154, 19.00300500400010151 45.45536611000007099, " + "19.03742150900006891 45.42229319300010104, 18.97592655400006834 45.39495636000008005, " + "19.09199182100007874 45.34999786400005917, 19.12475467900009107 45.29811472600006539, " + "19.36308638500014467 45.24824696900010679, 19.40783817500010855 45.20313344400013023, " + "19.39068160000005037 45.16933705700016333, 19.22593713300008744 45.16194732700016345, " + "19.12186079900010327 45.195795390000157, 19.13767378700009658 45.14603098600004216, " + "19.04486291500009543 45.13724599300006446, 19.08227665200013234 45.08494944300004192, " + "19.0872375890000967 44.97710072800013847, 19.13167932100006396 44.95317454000003465, " + "19.06667036900009293 44.90568389900012392, 18.99142948400006503 44.9149339800001286, " + "19.01582076000008215 44.86563466400004074, 18.88962691200009658 44.86119049100013001, " + "18.78338016700013213 44.91374542300012251, 18.79175174900009893 45.00154368100008639, " + "18.73831831900008638 45.0159097290000858, 18.68405806500004473 45.08479441400000098, " + "18.64871138500012648 45.06267689999999959, 18.61667199700013953 45.09766184500010411, " + "18.54959598800010667 45.09476796500011631, 18.51703983500007666 45.05585561200003042, " + "18.23788374800011525 45.15745147700012296, 18.15365116400005263 45.0975584930001645, " + "18.00347945100011771 45.1493382780000303, 17.83573775200005684 45.0644338990000648, " + "17.68473921700012852 45.1639627080000281, 17.48185754400009273 45.11440500900012296, " + "17.49622359200009214 45.1416901650001563, 17.44775109900012922 45.13430043600014585, " + "17.44330692500011537 45.16205068000009248, 17.38243208800008688 45.1396231090000839, " + "17.26895064300006766 45.18954254200015441, 17.24548954300007608 45.15538442000017483, " + "17.18709517400012032 45.14856313100001728, 17.0363033440001459 45.23047027600007652, " + "17.00829471800011561 45.21615590500009318, 17.00829471800011561 45.24416453100009505, " + "16.94731652900014751 45.23568959600000028, 16.9243721930001243 45.28452382500016427, " + "16.81171757000004163 45.18122263700009, 16.52894413300009546 45.22225372400005483, " + "16.38921106000003647 45.11683380099999852, 16.31624393700010955 45.00123362300008978, " + "16.12152714000009723 45.09616322900008356, 16.02044803900011516 45.213933818000001, " + "15.79234826700013627 45.18980092400012438, 15.76361617000014803 44.97555043600003444, " + "15.7308533120001357 44.92723297200008403, 15.77343469200010873 44.84501576800015243, " + "15.71607385200013596 44.80320953400008932, 15.72847619600008784 44.76910308800002269, " + "15.80568078600006743 44.69665273000013883, 15.88877648900006534 44.72424794500012979, " + "15.96897831200004703 44.63924021400013942, 16.02830285600006732 44.62471913700009907, " + "16.04473596200011798 44.58937245700018082, 16.00608199000004106 44.54100331600012908, " + "16.11646285000011858 44.52146962500013672, 16.15966434700004584 44.41610138000002905, " + "16.13827030500004867 44.37760243800015303, 16.20286584400008678 44.35977406800010669, " + "16.18756962000011868 44.28241444999999032, 16.21578495300011014 44.20815541600011045, " + "16.32688928200008149 44.08237498000012522, 16.50103885900011846 43.99271637000008184, " + "16.67859908100004418 43.8406843060001421, 16.71260217300007866 43.77151540100005889, " + "17.03051558500007445 43.54847991900005866, 17.27050093600007585 43.46321380700000248, " + "17.28993127500007176 43.3034302780000786, 17.44206669100009321 43.15243174300015028, " + "17.6284119050001209 43.04657257100008394, 17.66272505700004558 42.96569895500012137, " + "17.63450972400008254 42.950402731000068, 17.51563561300008587 42.95888906500012183, " + "17.47087649800005238 43.01341380400010905, 17.50196373800014271 43.03099192900005221, " + "17.43360436300014271 43.01740143400009231, 17.46021569100011561 43.03099192900005221, " + "17.42611738400009358 43.06517161700004692, 17.4045516290000819 43.05149974200010377, " + "17.31625410200012993 43.12726471600016964, 17.11394290500004445 43.21320221600008438, " + "16.88062584700011826 43.40595123900006058, 16.62582441500009622 43.44904205900009231, " + "16.52466881600011561 43.51080963700009363, 16.39144941500012465 43.51080963700009363, " + "16.47339928500008455 43.5381533870001789, 16.43384850400013875 43.54975006700000506, " + "16.11768639400008851 43.52448151200003679, 16.17237389400014536 43.4896914730000077, " + "16.11312910200004467 43.47890859600009605, 15.95948326900011693 43.50397370000008834, " + "15.987315300000148 43.54490794500010509, 15.92530358200011165 43.55857982000004824, " + "15.91895592500009116 43.62872955900012073, 15.96631920700011165 43.64118073100003414, " + "15.90479576900014536 43.64801666900014254, 15.95297285200010151 43.65086497599999404, " + "15.95045006600008719 43.68854401200015047, 15.70630944100008719 43.76341380400005221, " + "15.6174422540000819 43.82550690300017493, 15.66309655000009116 43.81297435099999404, " + "15.67888431100004709 43.81928131700011875, 15.45508873800014271 43.92804596600014122, " + "15.14454186300011429 44.19546133000015686, 15.15219160200012993 44.23529694200014717, " + "15.11036217500011958 44.26434967700011214, 15.14063561300011429 44.28245677300013483, " + "15.17660566500009622 44.24994538000005662, 15.20777428500008455 44.27277252800014651, " + "15.19809004000012465 44.30166250200007028, 15.295258009000122 44.25067780199999845, " + "15.30274498800008587 44.29913971600016964, 15.26124108200011165 44.33258698100003414, " + "15.42448978000001603 44.26797109600006763, 15.52865644600009887 44.27179596600008438, " + "15.30795332100009887 44.35439687700007028, 15.00733483200014007 44.56972890800012976, " + "14.883799675000148 44.7236188820001388, 14.883799675000148 44.86147695500012844, 14.92164147200008983 " + "44.95880768400009231, 14.85279381600011561 45.09365469000000815, 14.65788821700004974 " + "45.19660065300017493, 14.57081139400008851 45.29364655200011214, 14.31153405000009116 " + "45.34398021000005485, 14.23259524800005238 45.14935944200000506, 14.17937259200007816 " + "45.13450755400005221, 14.19312584700008983 45.10561758000012844, 14.14389082100007045 " + "45.05939362200003018, 14.151377800000148 44.97748444200009033, 14.06885826900014536 " + "44.94953034100014122, 14.08383222700007309 44.9863955750000315, 14.04029381600014403 " + "45.03896719000015025, 14.0756942070000548 44.98371002800003282, 14.02051842500011958 " + "44.90110911700004692, 13.97266686300011429 44.90110911700004692, 13.99301191500009622 " + "44.88129303600014453, 13.97266686300011429 44.82664622599999404, 14.00001061300008587 " + "44.81305573100003414, 13.89014733200011165 44.83348216400010244, 13.91797936300014271 " + "44.77826569200009033, 13.90316816500009622 44.77240631700014717, 13.89698326900011693 " + "44.81305573100003414, 13.78711998800014271 44.87506745000008834, 13.84229576900008851 " + "44.88812897300006455, 13.79460696700010658 44.89496491100008768, 13.77409915500007287 " + "44.96381256700014717, 13.6232202480000808 45.07306549700014386, 13.61255944100014403 " + "45.11786530199999845, 13.72624759200004974 45.13450755400005221, 13.5959578790000819 " + "45.14541250200001343, 13.57545006600011561 45.26487864800007799, 13.60271243600001867 " + "45.28534577000012007, 13.57545006600011561 45.30646393400006389, 13.60954837300005238 " + "45.32013580900017757, 13.54127037900013875 45.34613678600005926, 13.50709069100014403 " + "45.51190827000000638, 13.62901778100007277 45.45898346000016943, 13.75929406800014476 " + "45.46316925100011019, 13.88900191200011136 45.42363678000005223, 13.98263960800005634 " + "45.47531321200001742, 13.97189091000012695 45.5142255660000643, 14.09291711400010172 " + "45.47391794800002174, 14.21869755100007637 45.49717234400004884, 14.37279667100006009 " + "45.47784535800009564, 14.4689148350000778 45.52559438100014688, 14.49857710800012001 " + "45.59618438800005435, 14.58094934100009255 45.66780792200010808, 14.66848921700008646 " + "45.53396596300005683, 14.79716353300005949 45.46518463200006011, 14.88160282300009385 " + "45.46978383400001178, 14.9226339110000481 45.51494903600017494, 15.13926151500010064 " + "45.43004465799999991, 15.32519331800011742 45.45283396399999276, 15.36136682100004691 " + "45.48203114900003641, 15.29666792800006192 45.52295888300012905, 15.2685559480001416 " + "45.60166208900012919, 15.37376916500011248 45.64021270800010655, 15.25501672300006817 " + "45.72346344000011698, 15.42906294700014769 45.77529490200011253, 15.45128381300008868 " + "45.81513743100013869, 15.67607629400006886 45.84169911700014666, 15.65943648300003588 " + "45.88882802400014782, 15.69798710100010908 46.0362092080000167, 15.58988000500005455 " + "46.11351715100001059, 15.62284956800010605 46.19170359400006021, 16.01920780400010358 " + "46.29882883700007312, 16.05961877400008575 46.33231516600015709, 16.0579651280001201 " + "46.37753204400003426, 16.2756262620000598 46.37316538500006402, 16.23490523300009158 " + "46.4933389280001137, 16.36947066200013978 46.54057118800012915))) " + ) geom = QgsGeometry.fromWkt(wkt) f = QgsFeature() f.setGeometry(geom) @@ -687,7 +775,8 @@ def testReprojectionErrorsWhileRendering(self): painter = QPainter() ms = QgsMapSettings() crs = QgsCoordinateReferenceSystem.fromProj( - '+proj=ortho +lat_0=36.5 +lon_0=-118.8 +x_0=0 +y_0=0 +a=6371000 +b=6371000 +units=m +no_defs') + "+proj=ortho +lat_0=36.5 +lon_0=-118.8 +x_0=0 +y_0=0 +a=6371000 +b=6371000 +units=m +no_defs" + ) self.assertTrue(crs.isValid()) ms.setDestinationCrs(crs) ms.setExtent(QgsRectangle(1374999.8, 3912610.7, 4724462.5, 6505499.6)) @@ -695,14 +784,20 @@ def testReprojectionErrorsWhileRendering(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - ct = QgsCoordinateTransform(QgsCoordinateReferenceSystem('epsg:4326'), - crs, QgsProject.instance()) + ct = QgsCoordinateTransform( + QgsCoordinateReferenceSystem("epsg:4326"), crs, QgsProject.instance() + ) self.assertTrue(ct.isValid()) context.setCoordinateTransform(ct) - context.setExtent(ct.transformBoundingBox(ms.extent(), QgsCoordinateTransform.TransformDirection.ReverseTransform)) + context.setExtent( + ct.transformBoundingBox( + ms.extent(), QgsCoordinateTransform.TransformDirection.ReverseTransform + ) + ) fill_symbol = QgsFillSymbol.createSimple( - {'color': '#ffffff', 'outline_color': '#ffffff', 'outline_width': '10'}) + {"color": "#ffffff", "outline_color": "#ffffff", "outline_width": "10"} + ) painter.begin(image) try: @@ -715,18 +810,20 @@ def testReprojectionErrorsWhileRendering(self): self.assertTrue( self.image_check( - 'Reprojection errors polygon', - 'reprojection_errors_polygon', + "Reprojection errors polygon", + "reprojection_errors_polygon", image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) # also test linestring linestring = QgsGeometry(geom.constGet().boundary()) f.setGeometry(linestring) - line_symbol = QgsLineSymbol.createSimple({'color': '#ffffff', 'outline_width': '10'}) + line_symbol = QgsLineSymbol.createSimple( + {"color": "#ffffff", "outline_width": "10"} + ) image = QImage(200, 200, QImage.Format.Format_RGB32) painter.begin(image) @@ -740,11 +837,11 @@ def testReprojectionErrorsWhileRendering(self): self.assertTrue( self.image_check( - 'Reprojection errors linestring', - 'reprojection_errors_linestring', + "Reprojection errors linestring", + "reprojection_errors_linestring", image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -770,12 +867,12 @@ def test_buffer_settings(self): self.assertEqual(s.bufferSettings().joinStyle(), Qt.PenJoinStyle.MiterJoin) s.bufferSettings().setFillSymbol( - QgsFillSymbol.createSimple({'color': '#00ff00', 'outline_color': 'red'}) + QgsFillSymbol.createSimple({"color": "#00ff00", "outline_color": "red"}) ) doc = QDomDocument() context = QgsReadWriteContext() - element = QgsSymbolLayerUtils.saveSymbol('test', s, doc, context) + element = QgsSymbolLayerUtils.saveSymbol("test", s, doc, context) s2 = QgsSymbolLayerUtils.loadSymbol(element, context) @@ -786,7 +883,9 @@ def test_buffer_settings(self): self.assertEqual(s2.bufferSettings().sizeMapUnitScale().maxScale, 10) self.assertEqual(s2.bufferSettings().joinStyle(), Qt.PenJoinStyle.MiterJoin) self.assertEqual(s2.bufferSettings().fillSymbol()[0].color(), QColor(0, 255, 0)) - self.assertEqual(s2.bufferSettings().fillSymbol()[0].strokeColor(), QColor(255, 0, 0)) + self.assertEqual( + s2.bufferSettings().fillSymbol()[0].strokeColor(), QColor(255, 0, 0) + ) s3 = s2.clone() self.assertTrue(s3.bufferSettings().enabled()) @@ -796,7 +895,9 @@ def test_buffer_settings(self): self.assertEqual(s3.bufferSettings().sizeMapUnitScale().maxScale, 10) self.assertEqual(s3.bufferSettings().joinStyle(), Qt.PenJoinStyle.MiterJoin) self.assertEqual(s3.bufferSettings().fillSymbol()[0].color(), QColor(0, 255, 0)) - self.assertEqual(s3.bufferSettings().fillSymbol()[0].strokeColor(), QColor(255, 0, 0)) + self.assertEqual( + s3.bufferSettings().fillSymbol()[0].strokeColor(), QColor(255, 0, 0) + ) def test_animation_settings(self): s = QgsFillSymbol() @@ -810,7 +911,7 @@ def test_animation_settings(self): s.setForceRHR(True) doc = QDomDocument() context = QgsReadWriteContext() - element = QgsSymbolLayerUtils.saveSymbol('test', s, doc, context) + element = QgsSymbolLayerUtils.saveSymbol("test", s, doc, context) s2 = QgsSymbolLayerUtils.loadSymbol(element, context) self.assertTrue(s2.animationSettings().isAnimated()) @@ -853,11 +954,13 @@ def renderCollection(self, geom, symbol): return image def test_render_line_nan_z(self): - geom = QgsGeometry.fromPolyline([ - QgsPoint(10, 10, 0), - QgsPoint(20, 20, 0), - QgsPoint(30, 10, float("nan")), - ]) + geom = QgsGeometry.fromPolyline( + [ + QgsPoint(10, 10, 0), + QgsPoint(20, 20, 0), + QgsPoint(30, 10, float("nan")), + ] + ) f = QgsFeature() f.setGeometry(geom) @@ -876,7 +979,7 @@ def test_render_line_nan_z(self): context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - symbol = QgsLineSymbol.createSimple({'color': '#ffffff', 'line_width': '3'}) + symbol = QgsLineSymbol.createSimple({"color": "#ffffff", "line_width": "3"}) painter.begin(image) try: @@ -889,21 +992,27 @@ def test_render_line_nan_z(self): self.assertTrue( self.image_check( - 'Linestring with nan z', - 'linestring_nan_z', + "Linestring with nan z", + "linestring_nan_z", image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def test_render_polygon_nan_z(self): - geom = QgsGeometry(QgsPolygon(QgsLineString([ - QgsPoint(10, 10, 0), - QgsPoint(20, 20, 0), - QgsPoint(30, 10, float("nan")), - QgsPoint(10, 10, 0), - ]))) + geom = QgsGeometry( + QgsPolygon( + QgsLineString( + [ + QgsPoint(10, 10, 0), + QgsPoint(20, 20, 0), + QgsPoint(30, 10, float("nan")), + QgsPoint(10, 10, 0), + ] + ) + ) + ) f = QgsFeature() f.setGeometry(geom) @@ -922,7 +1031,9 @@ def test_render_polygon_nan_z(self): context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - symbol = QgsFillSymbol.createSimple({'color': '#ffffff', 'outline_color': '#ffffff', 'outline_width': '3'}) + symbol = QgsFillSymbol.createSimple( + {"color": "#ffffff", "outline_color": "#ffffff", "outline_width": "3"} + ) painter.begin(image) try: @@ -935,79 +1046,106 @@ def test_render_polygon_nan_z(self): self.assertTrue( self.image_check( - 'Polygon with nan z', - 'polygon_nan_z', + "Polygon with nan z", + "polygon_nan_z", image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) def testGeometryCollectionRender(self): - tests = [{'name': 'Marker', - 'wkt': 'GeometryCollection (Point(1 2))', - 'symbol': self.marker_symbol, - 'reference_image': 'point'}, - {'name': 'MultiPoint', - 'wkt': 'GeometryCollection (Point(10 30),Point(40 20),Point(30 10),Point(20 10))', - 'symbol': self.marker_symbol, - 'reference_image': 'multipoint'}, - {'name': 'LineString', - 'wkt': 'GeometryCollection( LineString (0 0,3 4,4 3) )', - 'symbol': self.line_symbol, - 'reference_image': 'linestring'}, - {'name': 'MultiLineString', - 'wkt': 'GeometryCollection (LineString(0 0, 1 0, 1 1, 2 1, 2 0), LineString(3 1, 5 1, 5 0, 6 0))', - 'symbol': self.line_symbol, - 'reference_image': 'multilinestring'}, - {'name': 'Polygon', - 'wkt': 'GeometryCollection(Polygon ((0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5)))', - 'symbol': self.fill_symbol, - 'reference_image': 'polygon'}, - {'name': 'MultiPolygon', - 'wkt': 'GeometryCollection( Polygon((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),Polygon((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))', - 'symbol': self.fill_symbol, - 'reference_image': 'multipolygon'}, - {'name': 'CircularString', - 'wkt': 'GeometryCollection(CIRCULARSTRING(268 415,227 505,227 406))', - 'symbol': self.line_symbol, - 'reference_image': 'circular_string'}, - {'name': 'CompoundCurve', - 'wkt': 'GeometryCollection(COMPOUNDCURVE((5 3, 5 13), CIRCULARSTRING(5 13, 7 15, 9 13), (9 13, 9 3), CIRCULARSTRING(9 3, 7 1, 5 3)))', - 'symbol': self.line_symbol, - 'reference_image': 'compound_curve'}, - {'name': 'CurvePolygon', - 'wkt': 'GeometryCollection(CURVEPOLYGON(CIRCULARSTRING(1 3, 3 5, 4 7, 7 3, 1 3)))', - 'symbol': self.fill_symbol, - 'reference_image': 'curve_polygon'}, - {'name': 'CurvePolygon_no_arc', # refs #14028 - 'wkt': 'GeometryCollection(CURVEPOLYGON(LINESTRING(1 3, 3 5, 4 7, 7 3, 1 3)))', - 'symbol': self.fill_symbol, - 'reference_image': 'curve_polygon_no_arc'}, - {'name': 'Mixed line symbol', - 'wkt': 'GeometryCollection(Point(1 2), MultiPoint(3 3, 2 3), LineString (0 0,3 4,4 3), MultiLineString((3 1, 3 2, 4 2)), Polygon((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)), MultiPolygon(((4 0, 5 0, 5 1, 6 1, 6 2, 4 2, 4 0)),(( 1 4, 2 4, 1 5, 1 4))))', - 'symbol': self.line_symbol, - 'reference_image': 'collection_line_symbol'}, - {'name': 'Mixed fill symbol', - 'wkt': 'GeometryCollection(Point(1 2), MultiPoint(3 3, 2 3), LineString (0 0,3 4,4 3), MultiLineString((3 1, 3 2, 4 2)), Polygon((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)), MultiPolygon(((4 0, 5 0, 5 1, 6 1, 6 2, 4 2, 4 0)),(( 1 4, 2 4, 1 5, 1 4))))', - 'symbol': self.fill_symbol, - 'reference_image': 'collection_fill_symbol'}, - {'name': 'Mixed marker symbol', - 'wkt': 'GeometryCollection(Point(1 2), MultiPoint(3 3, 2 3), LineString (0 0,3 4,4 3), MultiLineString((3 1, 3 2, 4 2)), Polygon((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)), MultiPolygon(((4 0, 5 0, 5 1, 6 1, 6 2, 4 2, 4 0)),(( 1 4, 2 4, 1 5, 1 4))))', - 'symbol': self.marker_symbol, - 'reference_image': 'collection_marker_symbol'}, - ] + tests = [ + { + "name": "Marker", + "wkt": "GeometryCollection (Point(1 2))", + "symbol": self.marker_symbol, + "reference_image": "point", + }, + { + "name": "MultiPoint", + "wkt": "GeometryCollection (Point(10 30),Point(40 20),Point(30 10),Point(20 10))", + "symbol": self.marker_symbol, + "reference_image": "multipoint", + }, + { + "name": "LineString", + "wkt": "GeometryCollection( LineString (0 0,3 4,4 3) )", + "symbol": self.line_symbol, + "reference_image": "linestring", + }, + { + "name": "MultiLineString", + "wkt": "GeometryCollection (LineString(0 0, 1 0, 1 1, 2 1, 2 0), LineString(3 1, 5 1, 5 0, 6 0))", + "symbol": self.line_symbol, + "reference_image": "multilinestring", + }, + { + "name": "Polygon", + "wkt": "GeometryCollection(Polygon ((0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5)))", + "symbol": self.fill_symbol, + "reference_image": "polygon", + }, + { + "name": "MultiPolygon", + "wkt": "GeometryCollection( Polygon((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),Polygon((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))", + "symbol": self.fill_symbol, + "reference_image": "multipolygon", + }, + { + "name": "CircularString", + "wkt": "GeometryCollection(CIRCULARSTRING(268 415,227 505,227 406))", + "symbol": self.line_symbol, + "reference_image": "circular_string", + }, + { + "name": "CompoundCurve", + "wkt": "GeometryCollection(COMPOUNDCURVE((5 3, 5 13), CIRCULARSTRING(5 13, 7 15, 9 13), (9 13, 9 3), CIRCULARSTRING(9 3, 7 1, 5 3)))", + "symbol": self.line_symbol, + "reference_image": "compound_curve", + }, + { + "name": "CurvePolygon", + "wkt": "GeometryCollection(CURVEPOLYGON(CIRCULARSTRING(1 3, 3 5, 4 7, 7 3, 1 3)))", + "symbol": self.fill_symbol, + "reference_image": "curve_polygon", + }, + { + "name": "CurvePolygon_no_arc", # refs #14028 + "wkt": "GeometryCollection(CURVEPOLYGON(LINESTRING(1 3, 3 5, 4 7, 7 3, 1 3)))", + "symbol": self.fill_symbol, + "reference_image": "curve_polygon_no_arc", + }, + { + "name": "Mixed line symbol", + "wkt": "GeometryCollection(Point(1 2), MultiPoint(3 3, 2 3), LineString (0 0,3 4,4 3), MultiLineString((3 1, 3 2, 4 2)), Polygon((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)), MultiPolygon(((4 0, 5 0, 5 1, 6 1, 6 2, 4 2, 4 0)),(( 1 4, 2 4, 1 5, 1 4))))", + "symbol": self.line_symbol, + "reference_image": "collection_line_symbol", + }, + { + "name": "Mixed fill symbol", + "wkt": "GeometryCollection(Point(1 2), MultiPoint(3 3, 2 3), LineString (0 0,3 4,4 3), MultiLineString((3 1, 3 2, 4 2)), Polygon((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)), MultiPolygon(((4 0, 5 0, 5 1, 6 1, 6 2, 4 2, 4 0)),(( 1 4, 2 4, 1 5, 1 4))))", + "symbol": self.fill_symbol, + "reference_image": "collection_fill_symbol", + }, + { + "name": "Mixed marker symbol", + "wkt": "GeometryCollection(Point(1 2), MultiPoint(3 3, 2 3), LineString (0 0,3 4,4 3), MultiLineString((3 1, 3 2, 4 2)), Polygon((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)), MultiPolygon(((4 0, 5 0, 5 1, 6 1, 6 2, 4 2, 4 0)),(( 1 4, 2 4, 1 5, 1 4))))", + "symbol": self.marker_symbol, + "reference_image": "collection_marker_symbol", + }, + ] for test in tests: - geom = QgsGeometry.fromWkt(test['wkt']) - rendered_image = self.renderCollection(geom, test['symbol']) + geom = QgsGeometry.fromWkt(test["wkt"]) + rendered_image = self.renderCollection(geom, test["symbol"]) self.assertTrue( self.image_check( - test['name'], - test['reference_image'], + test["name"], + test["reference_image"], rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -1035,8 +1173,13 @@ def testSize(self): markerSymbol = QgsMarkerSymbol() markerSymbol.deleteSymbolLayer(0) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Star, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=10)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Star, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + ) + ) self.assertEqual(markerSymbol.size(), 10) self.assertAlmostEqual(markerSymbol.size(context), 37.795275590551185, 3) self.assertAlmostEqual(markerSymbol.size(context2), 118.11023622047244, 3) @@ -1048,11 +1191,21 @@ def testSize(self): # add additional layers markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Star, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=10)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Star, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + ) + ) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Star, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=30)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Star, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=30, + ) + ) self.assertEqual(markerSymbol.size(), 30) self.assertAlmostEqual(markerSymbol.size(context), 113.38582677165356, 3) self.assertAlmostEqual(markerSymbol.size(context2), 354.33070866141736, 3) @@ -1077,7 +1230,9 @@ def testSize(self): def testGeometryGeneratorSize(self): # test marker symbol size propagation to geometry generated sub marker symbols - geomGeneratorSymbolLayer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': '$geometry'}) + geomGeneratorSymbolLayer = QgsGeometryGeneratorSymbolLayer.create( + {"geometryModifier": "$geometry"} + ) geomGeneratorSymbolLayer.setSymbolType(QgsSymbol.SymbolType.Marker) geomGeneratorSymbolLayer.subSymbol().setSize(2.5) @@ -1091,7 +1246,9 @@ def testGeometryGeneratorSize(self): def testGeometryGeneratorWidth(self): # test line symbol width propagation to geometry generated sub line symbols - geomGeneratorSymbolLayer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': '$geometry'}) + geomGeneratorSymbolLayer = QgsGeometryGeneratorSymbolLayer.create( + {"geometryModifier": "$geometry"} + ) geomGeneratorSymbolLayer.setSymbolType(QgsSymbol.SymbolType.Line) geomGeneratorSymbolLayer.subSymbol().setWidth(2.5) @@ -1110,8 +1267,14 @@ def testAngle(self): markerSymbol = QgsMarkerSymbol() markerSymbol.deleteSymbolLayer(0) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Star, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=10, angle=90)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Star, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + angle=90, + ) + ) self.assertEqual(markerSymbol.angle(), 90) markerSymbol.setAngle(100) self.assertEqual(markerSymbol.angle(), 100) @@ -1119,11 +1282,23 @@ def testAngle(self): # add additional layers markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Star, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=10, angle=130)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Star, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + angle=130, + ) + ) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Star, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=10, angle=150)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Star, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + angle=150, + ) + ) # should take first layer's angle self.assertEqual(markerSymbol.angle(), 100) markerSymbol.setAngle(10) @@ -1140,28 +1315,58 @@ def testSizeUnit(self): markerSymbol = QgsMarkerSymbol() markerSymbol.deleteSymbolLayer(0) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Star, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=10)) - self.assertEqual(markerSymbol.sizeUnit(), QgsUnitTypes.RenderUnit.RenderMillimeters) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Star, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + ) + ) + self.assertEqual( + markerSymbol.sizeUnit(), QgsUnitTypes.RenderUnit.RenderMillimeters + ) markerSymbol.setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertEqual(markerSymbol.sizeUnit(), QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertEqual(markerSymbol.symbolLayer(0).sizeUnit(), QgsUnitTypes.RenderUnit.RenderMapUnits) + self.assertEqual( + markerSymbol.sizeUnit(), QgsUnitTypes.RenderUnit.RenderMapUnits + ) + self.assertEqual( + markerSymbol.symbolLayer(0).sizeUnit(), + QgsUnitTypes.RenderUnit.RenderMapUnits, + ) # add additional layers markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Star, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=10)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Star, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + ) + ) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Star, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=30)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Star, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=30, + ) + ) # should now be mixed size units - self.assertEqual(markerSymbol.sizeUnit(), QgsUnitTypes.RenderUnit.RenderUnknownUnit) + self.assertEqual( + markerSymbol.sizeUnit(), QgsUnitTypes.RenderUnit.RenderUnknownUnit + ) markerSymbol.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPixels) self.assertEqual(markerSymbol.sizeUnit(), QgsUnitTypes.RenderUnit.RenderPixels) # all layers should have size unit set - self.assertEqual(markerSymbol.symbolLayer(0).sizeUnit(), QgsUnitTypes.RenderUnit.RenderPixels) - self.assertEqual(markerSymbol.symbolLayer(1).sizeUnit(), QgsUnitTypes.RenderUnit.RenderPixels) - self.assertEqual(markerSymbol.symbolLayer(2).sizeUnit(), QgsUnitTypes.RenderUnit.RenderPixels) + self.assertEqual( + markerSymbol.symbolLayer(0).sizeUnit(), QgsUnitTypes.RenderUnit.RenderPixels + ) + self.assertEqual( + markerSymbol.symbolLayer(1).sizeUnit(), QgsUnitTypes.RenderUnit.RenderPixels + ) + self.assertEqual( + markerSymbol.symbolLayer(2).sizeUnit(), QgsUnitTypes.RenderUnit.RenderPixels + ) def testSizeMapUnitScale(self): # test sizeMapUnitScale and setSizeMapUnitScale @@ -1170,67 +1375,95 @@ def testSizeMapUnitScale(self): markerSymbol = QgsMarkerSymbol() markerSymbol.deleteSymbolLayer(0) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Star, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=10)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Star, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + ) + ) markerSymbol.symbolLayer(0).setSizeMapUnitScale(QgsMapUnitScale(10000, 20000)) self.assertEqual(markerSymbol.sizeMapUnitScale(), QgsMapUnitScale(10000, 20000)) markerSymbol.setSizeMapUnitScale(QgsMapUnitScale(1000, 2000)) self.assertEqual(markerSymbol.sizeMapUnitScale(), QgsMapUnitScale(1000, 2000)) - self.assertEqual(markerSymbol.symbolLayer(0).sizeMapUnitScale(), QgsMapUnitScale(1000, 2000)) + self.assertEqual( + markerSymbol.symbolLayer(0).sizeMapUnitScale(), QgsMapUnitScale(1000, 2000) + ) # add additional layers markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Star, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=10)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Star, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + ) + ) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Star, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=30)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Star, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=30, + ) + ) # should take first layer's map unit scale self.assertEqual(markerSymbol.sizeMapUnitScale(), QgsMapUnitScale(1000, 2000)) markerSymbol.setSizeMapUnitScale(QgsMapUnitScale(3000, 4000)) self.assertEqual(markerSymbol.sizeMapUnitScale(), QgsMapUnitScale(3000, 4000)) # all layers should have size unit set - self.assertEqual(markerSymbol.symbolLayer(0).sizeMapUnitScale(), QgsMapUnitScale(3000, 4000)) - self.assertEqual(markerSymbol.symbolLayer(1).sizeMapUnitScale(), QgsMapUnitScale(3000, 4000)) - self.assertEqual(markerSymbol.symbolLayer(2).sizeMapUnitScale(), QgsMapUnitScale(3000, 4000)) + self.assertEqual( + markerSymbol.symbolLayer(0).sizeMapUnitScale(), QgsMapUnitScale(3000, 4000) + ) + self.assertEqual( + markerSymbol.symbolLayer(1).sizeMapUnitScale(), QgsMapUnitScale(3000, 4000) + ) + self.assertEqual( + markerSymbol.symbolLayer(2).sizeMapUnitScale(), QgsMapUnitScale(3000, 4000) + ) def testBoundDisabledSymbolLayer(self): # test calculating symbol bounds with a disabled symbol layer s = QgsMarkerSymbol() s.deleteSymbolLayer(0) s.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(size=10, color=QColor(255, 255, 0))) + QgsSimpleMarkerSymbolLayer(size=10, color=QColor(255, 255, 0)) + ) s[0].setStrokeStyle(Qt.PenStyle.NoPen) # larger layer, but disabled. Should not be considered in the bounds s.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(size=20, color=QColor(255, 255, 0))) + QgsSimpleMarkerSymbolLayer(size=20, color=QColor(255, 255, 0)) + ) s[1].setStrokeStyle(Qt.PenStyle.NoPen) s[1].setEnabled(False) - g = QgsGeometry.fromWkt('Point(1 1)') + g = QgsGeometry.fromWkt("Point(1 1)") rendered_image = self.renderGeometry(s, g, QgsMapSettings.Flag.DrawSymbolBounds) self.assertTrue( self.image_check( - 'marker_bounds_layer_disabled', - 'marker_bounds_layer_disabled', + "marker_bounds_layer_disabled", + "marker_bounds_layer_disabled", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) # with data defined visibility s[1].setEnabled(True) - s[1].setDataDefinedProperty(QgsSymbolLayer.Property.PropertyLayerEnabled, QgsProperty.fromExpression('false')) + s[1].setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyLayerEnabled, + QgsProperty.fromExpression("false"), + ) rendered_image = self.renderGeometry(s, g, QgsMapSettings.Flag.DrawSymbolBounds) self.assertTrue( self.image_check( - 'marker_bounds_layer_disabled', - 'marker_bounds_layer_disabled', + "marker_bounds_layer_disabled", + "marker_bounds_layer_disabled", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -1238,33 +1471,42 @@ def test_animation(self): markerSymbol = QgsMarkerSymbol() markerSymbol.deleteSymbolLayer(0) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Triangle, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=10, angle=0)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Triangle, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + angle=0, + ) + ) markerSymbol[0].setStrokeStyle(Qt.PenStyle.NoPen) markerSymbol.animationSettings().setIsAnimated(True) - markerSymbol[0].setDataDefinedProperty(QgsSymbolLayer.Property.PropertyAngle, QgsProperty.fromExpression('@symbol_frame * 90')) - g = QgsGeometry.fromWkt('Point(1 1)') + markerSymbol[0].setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyAngle, + QgsProperty.fromExpression("@symbol_frame * 90"), + ) + g = QgsGeometry.fromWkt("Point(1 1)") rendered_image = self.renderGeometry(markerSymbol, g, frame=0) self.assertTrue( self.image_check( - 'animated_frame1', - 'animated_frame1', + "animated_frame1", + "animated_frame1", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) rendered_image = self.renderGeometry(markerSymbol, g, frame=1) self.assertTrue( self.image_check( - 'animated_frame2', - 'animated_frame2', + "animated_frame2", + "animated_frame2", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -1272,8 +1514,14 @@ def test_render_marker_buffer_single_layer_symbol(self): markerSymbol = QgsMarkerSymbol() markerSymbol.deleteSymbolLayer(0) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Triangle, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=10, angle=0)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Triangle, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + angle=0, + ) + ) markerSymbol[0].setStrokeStyle(Qt.PenStyle.NoPen) s = QgsSymbolBufferSettings() @@ -1285,20 +1533,20 @@ def test_render_marker_buffer_single_layer_symbol(self): s.setJoinStyle(Qt.PenJoinStyle.MiterJoin) s.setFillSymbol( - QgsFillSymbol.createSimple({'color': '#00ff00', 'outline_style': 'no'}) + QgsFillSymbol.createSimple({"color": "#00ff00", "outline_style": "no"}) ) markerSymbol.setBufferSettings(s) - g = QgsGeometry.fromWkt('Point(1 1)') + g = QgsGeometry.fromWkt("Point(1 1)") rendered_image = self.renderGeometry(markerSymbol, g) self.assertTrue( self.image_check( - 'marker_buffer1', - 'marker_buffer1', + "marker_buffer1", + "marker_buffer1", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -1306,13 +1554,25 @@ def test_render_marker_buffer_two_layer_symbol(self): markerSymbol = QgsMarkerSymbol() markerSymbol.deleteSymbolLayer(0) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Triangle, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=10, angle=0)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Triangle, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + angle=0, + ) + ) markerSymbol[0].setStrokeStyle(Qt.PenStyle.NoPen) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.SemiCircle, color=QColor(255, 255, 0), - strokeColor=QColor(0, 255, 0), size=7, angle=45)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.SemiCircle, + color=QColor(255, 255, 0), + strokeColor=QColor(0, 255, 0), + size=7, + angle=45, + ) + ) markerSymbol[1].setStrokeStyle(Qt.PenStyle.NoPen) s = QgsSymbolBufferSettings() @@ -1324,20 +1584,20 @@ def test_render_marker_buffer_two_layer_symbol(self): s.setJoinStyle(Qt.PenJoinStyle.MiterJoin) s.setFillSymbol( - QgsFillSymbol.createSimple({'color': '#00ff00', 'outline_style': 'no'}) + QgsFillSymbol.createSimple({"color": "#00ff00", "outline_style": "no"}) ) markerSymbol.setBufferSettings(s) - g = QgsGeometry.fromWkt('Point(1 1)') + g = QgsGeometry.fromWkt("Point(1 1)") rendered_image = self.renderGeometry(markerSymbol, g) self.assertTrue( self.image_check( - 'marker_buffer2', - 'marker_buffer2', + "marker_buffer2", + "marker_buffer2", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -1345,13 +1605,25 @@ def test_render_marker_buffer_two_layer_symbol_with_levels(self): markerSymbol = QgsMarkerSymbol() markerSymbol.deleteSymbolLayer(0) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Triangle, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=10, angle=0)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Triangle, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + angle=0, + ) + ) markerSymbol[0].setStrokeStyle(Qt.PenStyle.NoPen) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.SemiCircle, color=QColor(255, 255, 0), - strokeColor=QColor(0, 255, 0), size=7, angle=45)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.SemiCircle, + color=QColor(255, 255, 0), + strokeColor=QColor(0, 255, 0), + size=7, + angle=45, + ) + ) markerSymbol[1].setStrokeStyle(Qt.PenStyle.NoPen) s = QgsSymbolBufferSettings() @@ -1363,21 +1635,21 @@ def test_render_marker_buffer_two_layer_symbol_with_levels(self): s.setJoinStyle(Qt.PenJoinStyle.MiterJoin) s.setFillSymbol( - QgsFillSymbol.createSimple({'color': '#00ff00', 'outline_style': 'no'}) + QgsFillSymbol.createSimple({"color": "#00ff00", "outline_style": "no"}) ) markerSymbol.setBufferSettings(s) - g = QgsGeometry.fromWkt('Point(1 1)') + g = QgsGeometry.fromWkt("Point(1 1)") # first layer rendered_image = self.renderGeometry(markerSymbol, g, layer=0) self.assertTrue( self.image_check( - 'marker_buffer_layer1', - 'marker_buffer_layer1', + "marker_buffer_layer1", + "marker_buffer_layer1", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -1385,11 +1657,11 @@ def test_render_marker_buffer_two_layer_symbol_with_levels(self): rendered_image = self.renderGeometry(markerSymbol, g, layer=1) self.assertTrue( self.image_check( - 'marker_buffer_layer2', - 'marker_buffer_layer2', + "marker_buffer_layer2", + "marker_buffer_layer2", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -1397,8 +1669,14 @@ def test_render_marker_buffer_single_layer_symbol_render_point(self): markerSymbol = QgsMarkerSymbol() markerSymbol.deleteSymbolLayer(0) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Triangle, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=10, angle=0)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Triangle, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + angle=0, + ) + ) markerSymbol[0].setStrokeStyle(Qt.PenStyle.NoPen) s = QgsSymbolBufferSettings() @@ -1410,7 +1688,7 @@ def test_render_marker_buffer_single_layer_symbol_render_point(self): s.setJoinStyle(Qt.PenJoinStyle.MiterJoin) s.setFillSymbol( - QgsFillSymbol.createSimple({'color': '#00ff00', 'outline_style': 'no'}) + QgsFillSymbol.createSimple({"color": "#00ff00", "outline_style": "no"}) ) markerSymbol.setBufferSettings(s) @@ -1424,19 +1702,18 @@ def test_render_marker_buffer_single_layer_symbol_render_point(self): try: markerSymbol.startRender(context) - markerSymbol.renderPoint(QPointF(100, - 100), None, context) + markerSymbol.renderPoint(QPointF(100, 100), None, context) markerSymbol.stopRender(context) finally: painter.end() self.assertTrue( self.image_check( - 'marker_buffer1', - 'marker_buffer1', + "marker_buffer1", + "marker_buffer1", image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -1444,13 +1721,25 @@ def test_render_marker_buffer_two_layer_symbol_render_point(self): markerSymbol = QgsMarkerSymbol() markerSymbol.deleteSymbolLayer(0) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Triangle, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=10, angle=0)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Triangle, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + angle=0, + ) + ) markerSymbol[0].setStrokeStyle(Qt.PenStyle.NoPen) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.SemiCircle, color=QColor(255, 255, 0), - strokeColor=QColor(0, 255, 0), size=7, angle=45)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.SemiCircle, + color=QColor(255, 255, 0), + strokeColor=QColor(0, 255, 0), + size=7, + angle=45, + ) + ) markerSymbol[1].setStrokeStyle(Qt.PenStyle.NoPen) s = QgsSymbolBufferSettings() @@ -1462,7 +1751,7 @@ def test_render_marker_buffer_two_layer_symbol_render_point(self): s.setJoinStyle(Qt.PenJoinStyle.MiterJoin) s.setFillSymbol( - QgsFillSymbol.createSimple({'color': '#00ff00', 'outline_style': 'no'}) + QgsFillSymbol.createSimple({"color": "#00ff00", "outline_style": "no"}) ) markerSymbol.setBufferSettings(s) @@ -1476,19 +1765,18 @@ def test_render_marker_buffer_two_layer_symbol_render_point(self): try: markerSymbol.startRender(context) - markerSymbol.renderPoint(QPointF(100, - 100), None, context) + markerSymbol.renderPoint(QPointF(100, 100), None, context) markerSymbol.stopRender(context) finally: painter.end() self.assertTrue( self.image_check( - 'marker_buffer2', - 'marker_buffer2', + "marker_buffer2", + "marker_buffer2", image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -1496,8 +1784,14 @@ def test_render_marker_buffer_single_layer_symbol_render_preview_icon(self): markerSymbol = QgsMarkerSymbol() markerSymbol.deleteSymbolLayer(0) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Triangle, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=10, angle=0)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Triangle, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + angle=0, + ) + ) markerSymbol[0].setStrokeStyle(Qt.PenStyle.NoPen) s = QgsSymbolBufferSettings() @@ -1509,7 +1803,7 @@ def test_render_marker_buffer_single_layer_symbol_render_preview_icon(self): s.setJoinStyle(Qt.PenJoinStyle.MiterJoin) s.setFillSymbol( - QgsFillSymbol.createSimple({'color': '#00ff00', 'outline_style': 'no'}) + QgsFillSymbol.createSimple({"color": "#00ff00", "outline_style": "no"}) ) markerSymbol.setBufferSettings(s) @@ -1521,18 +1815,17 @@ def test_render_marker_buffer_single_layer_symbol_render_preview_icon(self): context = QgsRenderContext.fromQPainter(painter) context.setPainter(painter) - markerSymbol.drawPreviewIcon(painter, image.size(), - None) + markerSymbol.drawPreviewIcon(painter, image.size(), None) painter.end() self.assertTrue( self.image_check( - 'marker_buffer1', - 'marker_buffer1', + "marker_buffer1", + "marker_buffer1", image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -1540,13 +1833,25 @@ def test_render_marker_buffer_two_layer_symbol_render_preview_icon(self): markerSymbol = QgsMarkerSymbol() markerSymbol.deleteSymbolLayer(0) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.Triangle, color=QColor(255, 0, 0), - strokeColor=QColor(0, 255, 0), size=10, angle=0)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.Triangle, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + angle=0, + ) + ) markerSymbol[0].setStrokeStyle(Qt.PenStyle.NoPen) markerSymbol.appendSymbolLayer( - QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayerBase.Shape.SemiCircle, color=QColor(255, 255, 0), - strokeColor=QColor(0, 255, 0), size=7, angle=45)) + QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayerBase.Shape.SemiCircle, + color=QColor(255, 255, 0), + strokeColor=QColor(0, 255, 0), + size=7, + angle=45, + ) + ) markerSymbol[1].setStrokeStyle(Qt.PenStyle.NoPen) s = QgsSymbolBufferSettings() @@ -1558,7 +1863,7 @@ def test_render_marker_buffer_two_layer_symbol_render_preview_icon(self): s.setJoinStyle(Qt.PenJoinStyle.MiterJoin) s.setFillSymbol( - QgsFillSymbol.createSimple({'color': '#00ff00', 'outline_style': 'no'}) + QgsFillSymbol.createSimple({"color": "#00ff00", "outline_style": "no"}) ) markerSymbol.setBufferSettings(s) @@ -1570,22 +1875,23 @@ def test_render_marker_buffer_two_layer_symbol_render_preview_icon(self): context = QgsRenderContext.fromQPainter(painter) context.setPainter(painter) - markerSymbol.drawPreviewIcon(painter, image.size(), - None) + markerSymbol.drawPreviewIcon(painter, image.size(), None) painter.end() self.assertTrue( self.image_check( - 'marker_buffer2', - 'marker_buffer2', + "marker_buffer2", + "marker_buffer2", image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) - def renderGeometry(self, symbol, geom, flags=QgsMapSettings.Flags(), frame=None, layer=-1): + def renderGeometry( + self, symbol, geom, flags=QgsMapSettings.Flags(), frame=None, layer=-1 + ): f = QgsFeature() f.setGeometry(geom) @@ -1642,7 +1948,8 @@ def testWidth(self): line_symbol = QgsLineSymbol() line_symbol.deleteSymbolLayer(0) line_symbol.appendSymbolLayer( - QgsSimpleLineSymbolLayer(color=QColor(255, 0, 0), width=10)) + QgsSimpleLineSymbolLayer(color=QColor(255, 0, 0), width=10) + ) self.assertEqual(line_symbol.width(), 10) self.assertAlmostEqual(line_symbol.width(context), 37.795275590551185, 3) self.assertAlmostEqual(line_symbol.width(context2), 118.11023622047244, 3) @@ -1654,9 +1961,11 @@ def testWidth(self): # add additional layers line_symbol.appendSymbolLayer( - QgsSimpleLineSymbolLayer(color=QColor(255, 0, 0), width=10)) + QgsSimpleLineSymbolLayer(color=QColor(255, 0, 0), width=10) + ) line_symbol.appendSymbolLayer( - QgsSimpleLineSymbolLayer(color=QColor(255, 0, 0), width=30)) + QgsSimpleLineSymbolLayer(color=QColor(255, 0, 0), width=30) + ) self.assertEqual(line_symbol.width(), 30) self.assertAlmostEqual(line_symbol.width(context), 113.38582677165356, 3) self.assertAlmostEqual(line_symbol.width(context2), 354.33070866141736, 3) @@ -1692,7 +2001,10 @@ def testForceRHR(self): s = QgsFillSymbol() s.deleteSymbolLayer(0) s.appendSymbolLayer( - QgsSimpleFillSymbolLayer(color=QColor(255, 0, 0), strokeColor=QColor(0, 255, 0))) + QgsSimpleFillSymbolLayer( + color=QColor(255, 0, 0), strokeColor=QColor(0, 255, 0) + ) + ) self.assertFalse(s.forceRHR()) s.setForceRHR(True) self.assertTrue(s.forceRHR()) @@ -1702,7 +2014,7 @@ def testForceRHR(self): s.setForceRHR(True) doc = QDomDocument() context = QgsReadWriteContext() - element = QgsSymbolLayerUtils.saveSymbol('test', s, doc, context) + element = QgsSymbolLayerUtils.saveSymbol("test", s, doc, context) s2 = QgsSymbolLayerUtils.loadSymbol(element, context) self.assertTrue(s2.forceRHR()) @@ -1711,10 +2023,17 @@ def testForceRHR(self): s3 = QgsFillSymbol() s3.deleteSymbolLayer(0) s3.appendSymbolLayer( - QgsSimpleFillSymbolLayer(color=QColor(255, 200, 200), strokeColor=QColor(0, 255, 0), strokeWidth=2)) + QgsSimpleFillSymbolLayer( + color=QColor(255, 200, 200), + strokeColor=QColor(0, 255, 0), + strokeWidth=2, + ) + ) marker_line = QgsMarkerLineSymbolLayer(True) marker_line.setPlacement(QgsMarkerLineSymbolLayer.Placement.FirstVertex) - marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4) + marker = QgsSimpleMarkerSymbolLayer( + QgsSimpleMarkerSymbolLayer.Shape.Triangle, 4 + ) marker.setColor(QColor(255, 0, 0)) marker.setStrokeStyle(Qt.PenStyle.NoPen) marker_symbol = QgsMarkerSymbol() @@ -1723,15 +2042,16 @@ def testForceRHR(self): s3.appendSymbolLayer(marker_line) g = QgsGeometry.fromWkt( - 'Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))') + "Polygon((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1),(8 8, 9 8, 9 9, 8 9, 8 8))" + ) rendered_image = self.renderGeometry(s3, g) self.assertTrue( self.image_check( - 'polygon_forcerhr_off', - 'polygon_forcerhr_off', + "polygon_forcerhr_off", + "polygon_forcerhr_off", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -1739,11 +2059,11 @@ def testForceRHR(self): rendered_image = self.renderGeometry(s3, g) self.assertTrue( self.image_check( - 'polygon_forcerhr_on', - 'polygon_forcerhr_on', + "polygon_forcerhr_on", + "polygon_forcerhr_on", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -1789,5 +2109,5 @@ def testDefaultSymbolColor(self): self.assertEqual(s1.color().spec(), QColor.Spec.Cmyk) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssymbolbuffersettingswidget.py b/tests/src/python/test_qgssymbolbuffersettingswidget.py index 7e9c8d562abb..8ae739c55e31 100644 --- a/tests/src/python/test_qgssymbolbuffersettingswidget.py +++ b/tests/src/python/test_qgssymbolbuffersettingswidget.py @@ -5,15 +5,11 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + from qgis.PyQt.QtCore import Qt from qgis.PyQt.QtGui import QColor -from qgis.core import ( - Qgis, - QgsMapUnitScale, - QgsSymbolBufferSettings, - QgsFillSymbol -) +from qgis.core import Qgis, QgsMapUnitScale, QgsSymbolBufferSettings, QgsFillSymbol from qgis.gui import QgsSymbolBufferSettingsWidget import unittest from qgis.testing import start_app, QgisTestCase @@ -38,7 +34,7 @@ def testWidget(self): s.setJoinStyle(Qt.PenJoinStyle.MiterJoin) s.setFillSymbol( - QgsFillSymbol.createSimple({'color': '#00ff00', 'outline_color': 'red'}) + QgsFillSymbol.createSimple({"color": "#00ff00", "outline_color": "red"}) ) widget.setBufferSettings(s) @@ -55,5 +51,5 @@ def testWidget(self): self.assertEqual(new_settings.fillSymbol()[0].strokeColor(), QColor(255, 0, 0)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssymbolbutton.py b/tests/src/python/test_qgssymbolbutton.py index 112d101f6cec..0f18cae47e50 100644 --- a/tests/src/python/test_qgssymbolbutton.py +++ b/tests/src/python/test_qgssymbolbutton.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '23/07/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "23/07/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtGui import QColor from qgis.PyQt.QtTest import QSignalSpy @@ -25,8 +26,8 @@ def testGettersSetters(self): button = QgsSymbolButton() canvas = QgsMapCanvas() - button.setDialogTitle('test title') - self.assertEqual(button.dialogTitle(), 'test title') + button.setDialogTitle("test title") + self.assertEqual(button.dialogTitle(), "test title") button.setMapCanvas(canvas) self.assertEqual(button.mapCanvas(), canvas) @@ -112,5 +113,5 @@ def testSetColor(self): self.assertEqual(r.color(), QColor(0, 255, 0)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssymbolexpressionvariables.py b/tests/src/python/test_qgssymbolexpressionvariables.py index 4474966b3071..d837db5301e3 100644 --- a/tests/src/python/test_qgssymbolexpressionvariables.py +++ b/tests/src/python/test_qgssymbolexpressionvariables.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'January 2016' -__copyright__ = '(C) 2016, Matthiasd Kuhn' +__author__ = "Matthias Kuhn" +__date__ = "January 2016" +__copyright__ = "(C) 2016, Matthiasd Kuhn" import os @@ -45,8 +45,8 @@ class TestQgsSymbolExpressionVariables(QgisTestCase): def setUp(self): - myShpFile = os.path.join(TEST_DATA_DIR, 'polys.shp') - self.layer = QgsVectorLayer(myShpFile, 'Polys', 'ogr') + myShpFile = os.path.join(TEST_DATA_DIR, "polys.shp") + self.layer = QgsVectorLayer(myShpFile, "Polys", "ogr") QgsProject.instance().addMapLayer(self.layer) self.iface = get_iface() @@ -62,54 +62,77 @@ def tearDown(self): def testPartNum(self): # Create rulebased style - sym1 = QgsFillSymbol.createSimple({'color': '#fdbf6f', 'outline_color': 'black'}) + sym1 = QgsFillSymbol.createSimple( + {"color": "#fdbf6f", "outline_color": "black"} + ) renderer = QgsSingleSymbolRenderer(sym1) - renderer.symbols(QgsRenderContext())[0].symbolLayers()[0].setDataDefinedProperty(QgsSymbolLayer.Property.PropertyFillColor, QgsProperty.fromExpression('color_rgb( (@geometry_part_num - 1) * 200, 0, 0 )')) + renderer.symbols(QgsRenderContext())[0].symbolLayers()[ + 0 + ].setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyFillColor, + QgsProperty.fromExpression( + "color_rgb( (@geometry_part_num - 1) * 200, 0, 0 )" + ), + ) self.layer.setRenderer(renderer) # Setup rendering check self.assertTrue( self.render_map_settings_check( - 'part_geometry_part_num', - 'geometry_part_num', - self.mapsettings + "part_geometry_part_num", "geometry_part_num", self.mapsettings ) ) def testPartCount(self): # Create rulebased style - sym1 = QgsFillSymbol.createSimple({'color': '#fdbf6f', 'outline_color': 'black'}) + sym1 = QgsFillSymbol.createSimple( + {"color": "#fdbf6f", "outline_color": "black"} + ) renderer = QgsSingleSymbolRenderer(sym1) - renderer.symbols(QgsRenderContext())[0].symbolLayers()[0].setDataDefinedProperty(QgsSymbolLayer.Property.PropertyFillColor, QgsProperty.fromExpression('color_rgb( (@geometry_part_count - 1) * 200, 0, 0 )')) + renderer.symbols(QgsRenderContext())[0].symbolLayers()[ + 0 + ].setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyFillColor, + QgsProperty.fromExpression( + "color_rgb( (@geometry_part_count - 1) * 200, 0, 0 )" + ), + ) self.layer.setRenderer(renderer) self.assertTrue( self.render_map_settings_check( - 'part_geometry_part_count', - 'geometry_part_count', - self.mapsettings + "part_geometry_part_count", "geometry_part_count", self.mapsettings ) ) def testSymbolColor(self): # Create rulebased style - sym1 = QgsFillSymbol.createSimple({'color': '#ff0000', 'outline_color': 'black'}) + sym1 = QgsFillSymbol.createSimple( + {"color": "#ff0000", "outline_color": "black"} + ) renderer = QgsSingleSymbolRenderer(sym1) - renderer.symbols(QgsRenderContext())[0].symbolLayers()[0].setDataDefinedProperty(QgsSymbolLayer.Property.PropertyFillColor, QgsProperty.fromExpression('set_color_part( @symbol_color, \'value\', "Value" * 4)')) + renderer.symbols(QgsRenderContext())[0].symbolLayers()[ + 0 + ].setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyFillColor, + QgsProperty.fromExpression( + "set_color_part( @symbol_color, 'value', \"Value\" * 4)" + ), + ) self.layer.setRenderer(renderer) self.assertTrue( self.render_map_settings_check( - 'symbol_color_variable', - 'symbol_color_variable', + "symbol_color_variable", + "symbol_color_variable", self.mapsettings, - allowed_mismatch=50 + allowed_mismatch=50, ) ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssymbollayer.py b/tests/src/python/test_qgssymbollayer.py index d9c61dbaf733..c375fe43b298 100644 --- a/tests/src/python/test_qgssymbollayer.py +++ b/tests/src/python/test_qgssymbollayer.py @@ -18,9 +18,9 @@ """ -__author__ = 'Massimo Endrighi' -__date__ = 'October 2012' -__copyright__ = '(C) 2012, Massimo Endrighi' +__author__ = "Massimo Endrighi" +__date__ = "October 2012" +__copyright__ = "(C) 2012, Massimo Endrighi" import os @@ -80,7 +80,7 @@ QgsUnitTypes, QgsVectorFieldSymbolLayer, QgsVectorLayer, - QgsSymbolRenderContext + QgsSymbolRenderContext, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -97,22 +97,21 @@ class TestQgsSymbolLayer(QgisTestCase): - """ - This class test the sip binding for QgsSymbolLayer descendants - Every class is tested using the createFromSld implementation - An exception is done for: - - QgsLinePatternFillSymbolLayer where createFromSld implementation - returns NULL - - QgsPointPatternFillSymbolLayer where createFromSld implementation - returns NULL - - QgsVectorFieldSymbolLayer where createFromSld implementation - returns NULL - """ + This class test the sip binding for QgsSymbolLayer descendants + Every class is tested using the createFromSld implementation + An exception is done for: + - QgsLinePatternFillSymbolLayer where createFromSld implementation + returns NULL + - QgsPointPatternFillSymbolLayer where createFromSld implementation + returns NULL + - QgsVectorFieldSymbolLayer where createFromSld implementation + returns NULL + """ @classmethod def control_path_prefix(cls): - return 'symbol_layer' + return "symbol_layer" def testBinding(self): """Test python bindings existence.""" @@ -282,7 +281,7 @@ def testBinding(self): assert EXPECTED_TYPE == mType, mMessage def testGettersSetters(self): - """ test base class getters/setters """ + """test base class getters/setters""" layer = QgsSimpleFillSymbolLayer() layer.setEnabled(False) @@ -299,7 +298,7 @@ def testGettersSetters(self): self.assertEqual(layer.renderingPass(), 5) def testSaveRestore(self): - """ Test saving and restoring base symbol layer properties to xml""" + """Test saving and restoring base symbol layer properties to xml""" layer = QgsSimpleFillSymbolLayer() layer.setEnabled(False) @@ -311,18 +310,22 @@ def testSaveRestore(self): symbol.changeSymbolLayer(0, layer) doc = QDomDocument("testdoc") - elem = QgsSymbolLayerUtils.saveSymbol('test', symbol, doc, QgsReadWriteContext()) + elem = QgsSymbolLayerUtils.saveSymbol( + "test", symbol, doc, QgsReadWriteContext() + ) restored_symbol = QgsSymbolLayerUtils.loadSymbol(elem, QgsReadWriteContext()) restored_layer = restored_symbol.symbolLayer(0) self.assertFalse(restored_layer.enabled()) self.assertTrue(restored_layer.isLocked()) self.assertEqual(restored_layer.renderingPass(), 5) - self.assertEqual(restored_layer.userFlags(), - Qgis.SymbolLayerUserFlag.DisableSelectionRecoloring) + self.assertEqual( + restored_layer.userFlags(), + Qgis.SymbolLayerUserFlag.DisableSelectionRecoloring, + ) def testClone(self): - """ test that base symbol layer properties are cloned with layer """ + """test that base symbol layer properties are cloned with layer""" layer = QgsSimpleFillSymbolLayer() layer.setEnabled(False) @@ -338,11 +341,13 @@ def testClone(self): self.assertFalse(cloned_layer.enabled()) self.assertTrue(cloned_layer.isLocked()) self.assertEqual(cloned_layer.renderingPass(), 5) - self.assertEqual(cloned_layer.userFlags(), - Qgis.SymbolLayerUserFlag.DisableSelectionRecoloring) + self.assertEqual( + cloned_layer.userFlags(), + Qgis.SymbolLayerUserFlag.DisableSelectionRecoloring, + ) def testRenderFillLayerDisabled(self): - """ test that rendering a fill symbol with disabled layer works""" + """test that rendering a fill symbol with disabled layer works""" layer = QgsSimpleFillSymbolLayer() layer.setEnabled(False) @@ -353,7 +358,7 @@ def testRenderFillLayerDisabled(self): painter = QPainter() ms = QgsMapSettings() - geom = QgsGeometry.fromWkt('Polygon ((0 0, 10 0, 10 10, 0 10, 0 0))') + geom = QgsGeometry.fromWkt("Polygon ((0 0, 10 0, 10 10, 0 10, 0 0))") f = QgsFeature() f.setGeometry(geom) @@ -376,8 +381,7 @@ def testRenderFillLayerDisabled(self): painter.end() self.assertTrue( - self.image_check('symbollayer_disabled', - 'symbollayer_disabled', image) + self.image_check("symbollayer_disabled", "symbollayer_disabled", image) ) def testRenderFillLayerDataDefined(self): @@ -385,12 +389,15 @@ def testRenderFillLayerDataDefined(self): Test that rendering a fill symbol with data defined enabled layer works """ - polys_shp = os.path.join(TEST_DATA_DIR, 'polys.shp') - polys_layer = QgsVectorLayer(polys_shp, 'Polygons', 'ogr') + polys_shp = os.path.join(TEST_DATA_DIR, "polys.shp") + polys_layer = QgsVectorLayer(polys_shp, "Polygons", "ogr") QgsProject.instance().addMapLayer(polys_layer) layer = QgsSimpleFillSymbolLayer() - layer.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyLayerEnabled, QgsProperty.fromExpression("Name='Lake'")) + layer.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyLayerEnabled, + QgsProperty.fromExpression("Name='Lake'"), + ) layer.setStrokeStyle(Qt.PenStyle.NoPen) layer.setColor(QColor(100, 150, 150)) @@ -408,18 +415,16 @@ def testRenderFillLayerDataDefined(self): ctx = QgsRenderContext.fromMapSettings(ms) ctx.expressionContext().appendScope(polys_layer.createExpressionContextScope()) # for symbol layer - self.assertCountEqual(layer.usedAttributes(ctx), {'Name'}) + self.assertCountEqual(layer.usedAttributes(ctx), {"Name"}) # for symbol - self.assertCountEqual(symbol.usedAttributes(ctx), {'Name'}) + self.assertCountEqual(symbol.usedAttributes(ctx), {"Name"}) # for symbol renderer - self.assertCountEqual(polys_layer.renderer().usedAttributes(ctx), {'Name'}) + self.assertCountEqual(polys_layer.renderer().usedAttributes(ctx), {"Name"}) # Test rendering self.assertTrue( self.render_map_settings_check( - 'filllayer_ddenabled', - 'filllayer_ddenabled', - ms + "filllayer_ddenabled", "filllayer_ddenabled", ms ) ) @@ -439,7 +444,7 @@ def testRenderLineLayerDisabled(self): painter = QPainter() ms = QgsMapSettings() - geom = QgsGeometry.fromWkt('LineString (0 0,3 4,4 3)') + geom = QgsGeometry.fromWkt("LineString (0 0,3 4,4 3)") f = QgsFeature() f.setGeometry(geom) @@ -462,11 +467,7 @@ def testRenderLineLayerDisabled(self): painter.end() self.assertTrue( - self.image_check( - 'symbollayer_disabled', - 'symbollayer_disabled', - image - ) + self.image_check("symbollayer_disabled", "symbollayer_disabled", image) ) def testRenderLineLayerDataDefined(self): @@ -474,12 +475,15 @@ def testRenderLineLayerDataDefined(self): Test that rendering a line symbol with data defined enabled layer works """ - lines_shp = os.path.join(TEST_DATA_DIR, 'lines.shp') - lines_layer = QgsVectorLayer(lines_shp, 'Lines', 'ogr') + lines_shp = os.path.join(TEST_DATA_DIR, "lines.shp") + lines_layer = QgsVectorLayer(lines_shp, "Lines", "ogr") QgsProject.instance().addMapLayer(lines_layer) layer = QgsSimpleLineSymbolLayer() - layer.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyLayerEnabled, QgsProperty.fromExpression("Name='Highway'")) + layer.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyLayerEnabled, + QgsProperty.fromExpression("Name='Highway'"), + ) layer.setColor(QColor(100, 150, 150)) layer.setWidth(5) @@ -497,18 +501,16 @@ def testRenderLineLayerDataDefined(self): ctx = QgsRenderContext.fromMapSettings(ms) ctx.expressionContext().appendScope(lines_layer.createExpressionContextScope()) # for symbol layer - self.assertCountEqual(layer.usedAttributes(ctx), {'Name'}) + self.assertCountEqual(layer.usedAttributes(ctx), {"Name"}) # for symbol - self.assertCountEqual(symbol.usedAttributes(ctx), {'Name'}) + self.assertCountEqual(symbol.usedAttributes(ctx), {"Name"}) # for symbol renderer - self.assertCountEqual(lines_layer.renderer().usedAttributes(ctx), {'Name'}) + self.assertCountEqual(lines_layer.renderer().usedAttributes(ctx), {"Name"}) # Test rendering self.assertTrue( self.render_map_settings_check( - 'linelayer_ddenabled', - 'linelayer_ddenabled', - ms + "linelayer_ddenabled", "linelayer_ddenabled", ms ) ) @@ -528,7 +530,7 @@ def testRenderMarkerLayerDisabled(self): painter = QPainter() ms = QgsMapSettings() - geom = QgsGeometry.fromWkt('Point (1 2)') + geom = QgsGeometry.fromWkt("Point (1 2)") f = QgsFeature() f.setGeometry(geom) @@ -549,11 +551,7 @@ def testRenderMarkerLayerDisabled(self): painter.end() self.assertTrue( - self.image_check( - 'symbollayer_disabled', - 'symbollayer_disabled', - image - ) + self.image_check("symbollayer_disabled", "symbollayer_disabled", image) ) def testRenderMarkerLayerDataDefined(self): @@ -562,12 +560,15 @@ def testRenderMarkerLayerDataDefined(self): layer works """ - points_shp = os.path.join(TEST_DATA_DIR, 'points.shp') - points_layer = QgsVectorLayer(points_shp, 'Points', 'ogr') + points_shp = os.path.join(TEST_DATA_DIR, "points.shp") + points_layer = QgsVectorLayer(points_shp, "Points", "ogr") QgsProject.instance().addMapLayer(points_layer) layer = QgsSimpleMarkerSymbolLayer() - layer.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyLayerEnabled, QgsProperty.fromExpression("Class='Biplane'")) + layer.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyLayerEnabled, + QgsProperty.fromExpression("Class='Biplane'"), + ) layer.setColor(QColor(100, 150, 150)) layer.setSize(5) layer.setStrokeStyle(Qt.PenStyle.NoPen) @@ -586,18 +587,16 @@ def testRenderMarkerLayerDataDefined(self): ctx = QgsRenderContext.fromMapSettings(ms) ctx.expressionContext().appendScope(points_layer.createExpressionContextScope()) # for symbol layer - self.assertCountEqual(layer.usedAttributes(ctx), {'Class'}) + self.assertCountEqual(layer.usedAttributes(ctx), {"Class"}) # for symbol - self.assertCountEqual(symbol.usedAttributes(ctx), {'Class'}) + self.assertCountEqual(symbol.usedAttributes(ctx), {"Class"}) # for symbol renderer - self.assertCountEqual(points_layer.renderer().usedAttributes(ctx), {'Class'}) + self.assertCountEqual(points_layer.renderer().usedAttributes(ctx), {"Class"}) # Test rendering self.assertTrue( self.render_map_settings_check( - 'markerlayer_ddenabled', - 'markerlayer_ddenabled', - ms + "markerlayer_ddenabled", "markerlayer_ddenabled", ms ) ) QgsProject.instance().removeMapLayer(points_layer) @@ -606,8 +605,10 @@ def testQgsSimpleFillSymbolLayer(self): """ Create a new style from a .sld file and match test. """ - mTestName = 'QgsSimpleFillSymbolLayer' - mFilePath = QDir.toNativeSeparators(f'{unitTestDataPath()}/symbol_layer/{mTestName}.sld') + mTestName = "QgsSimpleFillSymbolLayer" + mFilePath = QDir.toNativeSeparators( + f"{unitTestDataPath()}/symbol_layer/{mTestName}.sld" + ) mDoc = QDomDocument(mTestName) mFile = QFile(mFilePath) @@ -615,7 +616,8 @@ def testQgsSimpleFillSymbolLayer(self): mDoc.setContent(mFile, True) mFile.close() mSymbolLayer = QgsSimpleFillSymbolLayer.createFromSld( - mDoc.elementsByTagName('PolygonSymbolizer').item(0).toElement()) + mDoc.elementsByTagName("PolygonSymbolizer").item(0).toElement() + ) mExpectedValue = type(QgsSimpleFillSymbolLayer()) mValue = type(mSymbolLayer) @@ -627,7 +629,7 @@ def testQgsSimpleFillSymbolLayer(self): mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage - mExpectedValue = '#ffaa7f' + mExpectedValue = "#ffaa7f" mValue = mSymbolLayer.strokeColor().name() mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage @@ -668,7 +670,7 @@ def testQgsGradientFillSymbolLayer(self): mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage - mExpectedValue = QColor('#55aaff') + mExpectedValue = QColor("#55aaff") mGradientLayer.setColor2(mExpectedValue) mValue = mGradientLayer.color2() mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' @@ -735,8 +737,10 @@ def testQgsCentroidFillSymbolLayer(self): """ Create a new style from a .sld file and match test """ - mTestName = 'QgsCentroidFillSymbolLayer' - mFilePath = QDir.toNativeSeparators(f'{unitTestDataPath()}/symbol_layer/{mTestName}.sld') + mTestName = "QgsCentroidFillSymbolLayer" + mFilePath = QDir.toNativeSeparators( + f"{unitTestDataPath()}/symbol_layer/{mTestName}.sld" + ) mDoc = QDomDocument(mTestName) mFile = QFile(mFilePath) @@ -744,7 +748,8 @@ def testQgsCentroidFillSymbolLayer(self): mDoc.setContent(mFile, True) mFile.close() mSymbolLayer = QgsCentroidFillSymbolLayer.createFromSld( - mDoc.elementsByTagName('PointSymbolizer').item(0).toElement()) + mDoc.elementsByTagName("PointSymbolizer").item(0).toElement() + ) mExpectedValue = type(QgsCentroidFillSymbolLayer()) mValue = type(mSymbolLayer) @@ -756,12 +761,12 @@ def testQgsCentroidFillSymbolLayer(self): mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage - mExpectedValue = '#55aaff' + mExpectedValue = "#55aaff" mValue = mSymbolLayer.subSymbol().symbolLayer(0).color().name() mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage - mExpectedValue = '#00ff00' + mExpectedValue = "#00ff00" mValue = mSymbolLayer.subSymbol().symbolLayer(0).strokeColor().name() mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage @@ -786,8 +791,10 @@ def testQgsLinePatternFillSymbolLayer(self): """ Create a new style from a .sld file and match test """ - mTestName = 'QgsLinePatternFillSymbolLayer' - mFilePath = QDir.toNativeSeparators(f'{unitTestDataPath()}/symbol_layer/{mTestName}.sld') + mTestName = "QgsLinePatternFillSymbolLayer" + mFilePath = QDir.toNativeSeparators( + f"{unitTestDataPath()}/symbol_layer/{mTestName}.sld" + ) mDoc = QDomDocument(mTestName) mFile = QFile(mFilePath) @@ -795,14 +802,15 @@ def testQgsLinePatternFillSymbolLayer(self): mDoc.setContent(mFile, True) mFile.close() mSymbolLayer = QgsLinePatternFillSymbolLayer.createFromSld( - mDoc.elementsByTagName('PolygonSymbolizer').item(0).toElement()) + mDoc.elementsByTagName("PolygonSymbolizer").item(0).toElement() + ) mExpectedValue = type(QgsLinePatternFillSymbolLayer()) mValue = type(mSymbolLayer) mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage - mExpectedValue = '#ff55ff' + mExpectedValue = "#ff55ff" mValue = mSymbolLayer.color().name() mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage @@ -839,8 +847,10 @@ def testQgsPointPatternFillSymbolLayerSld(self): """ # at the moment there is an empty createFromSld implementation # that return nulls - mTestName = 'QgsPointPatternFillSymbolLayer' - mFilePath = QDir.toNativeSeparators(f'{unitTestDataPath()}/symbol_layer/{mTestName}.sld') + mTestName = "QgsPointPatternFillSymbolLayer" + mFilePath = QDir.toNativeSeparators( + f"{unitTestDataPath()}/symbol_layer/{mTestName}.sld" + ) mDoc = QDomDocument(mTestName) mFile = QFile(mFilePath) @@ -848,7 +858,8 @@ def testQgsPointPatternFillSymbolLayerSld(self): mDoc.setContent(mFile, True) mFile.close() mSymbolLayer = QgsPointPatternFillSymbolLayer.createFromSld( - mDoc.elementsByTagName('PolygonSymbolizer').item(0).toElement()) + mDoc.elementsByTagName("PolygonSymbolizer").item(0).toElement() + ) mExpectedValue = type(QgsPointPatternFillSymbolLayer()) mValue = type(mSymbolLayer) @@ -860,12 +871,12 @@ def testQgsPointPatternFillSymbolLayerSld(self): mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage - mExpectedValue = '#ffaa00' + mExpectedValue = "#ffaa00" mValue = mSymbolLayer.subSymbol().symbolLayer(0).color().name() mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage - mExpectedValue = '#ff007f' + mExpectedValue = "#ff007f" mValue = mSymbolLayer.subSymbol().symbolLayer(0).strokeColor().name() mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage @@ -904,8 +915,10 @@ def testQgsSVGFillSymbolLayer(self): """ Create a new style from a .sld file and match test """ - mTestName = 'QgsSVGFillSymbolLayer' - mFilePath = QDir.toNativeSeparators(f'{unitTestDataPath()}/symbol_layer/{mTestName}.sld') + mTestName = "QgsSVGFillSymbolLayer" + mFilePath = QDir.toNativeSeparators( + f"{unitTestDataPath()}/symbol_layer/{mTestName}.sld" + ) mDoc = QDomDocument(mTestName) mFile = QFile(mFilePath) @@ -913,14 +926,15 @@ def testQgsSVGFillSymbolLayer(self): mDoc.setContent(mFile, True) mFile.close() mSymbolLayer = QgsSVGFillSymbolLayer.createFromSld( - mDoc.elementsByTagName('PolygonSymbolizer').item(0).toElement()) + mDoc.elementsByTagName("PolygonSymbolizer").item(0).toElement() + ) mExpectedValue = type(QgsSVGFillSymbolLayer("")) mValue = type(mSymbolLayer) mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage - mExpectedValue = 'accommodation_camping.svg' + mExpectedValue = "accommodation_camping.svg" mValue = os.path.basename(mSymbolLayer.svgFilePath()) mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage @@ -937,8 +951,10 @@ def testQgsMarkerLineSymbolLayer(self): """ Create a new style from a .sld file and match test """ - mTestName = 'QgsMarkerLineSymbolLayer' - mFilePath = QDir.toNativeSeparators(f'{unitTestDataPath()}/symbol_layer/{mTestName}.sld') + mTestName = "QgsMarkerLineSymbolLayer" + mFilePath = QDir.toNativeSeparators( + f"{unitTestDataPath()}/symbol_layer/{mTestName}.sld" + ) mDoc = QDomDocument(mTestName) mFile = QFile(mFilePath) @@ -946,7 +962,8 @@ def testQgsMarkerLineSymbolLayer(self): mDoc.setContent(mFile, True) mFile.close() mSymbolLayer = QgsMarkerLineSymbolLayer.createFromSld( - mDoc.elementsByTagName('LineSymbolizer').item(0).toElement()) + mDoc.elementsByTagName("LineSymbolizer").item(0).toElement() + ) mExpectedValue = type(QgsMarkerLineSymbolLayer()) mValue = type(mSymbolLayer) @@ -963,12 +980,12 @@ def testQgsMarkerLineSymbolLayer(self): mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage - mExpectedValue = '#000000' + mExpectedValue = "#000000" mValue = mSymbolLayer.subSymbol().symbolLayer(0).strokeColor().name() mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage - mExpectedValue = '#ff0000' + mExpectedValue = "#ff0000" mValue = mSymbolLayer.subSymbol().symbolLayer(0).color().name() mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage @@ -988,8 +1005,10 @@ def testQgsSimpleLineSymbolLayer(self): """ Create a new style from a .sld file and match test """ - mTestName = 'QgsSimpleLineSymbolLayer' - mFilePath = QDir.toNativeSeparators(f'{unitTestDataPath()}/symbol_layer/{mTestName}.sld') + mTestName = "QgsSimpleLineSymbolLayer" + mFilePath = QDir.toNativeSeparators( + f"{unitTestDataPath()}/symbol_layer/{mTestName}.sld" + ) mDoc = QDomDocument(mTestName) mFile = QFile(mFilePath) @@ -997,14 +1016,15 @@ def testQgsSimpleLineSymbolLayer(self): mDoc.setContent(mFile, True) mFile.close() mSymbolLayer = QgsSimpleLineSymbolLayer.createFromSld( - mDoc.elementsByTagName('LineSymbolizer').item(0).toElement()) + mDoc.elementsByTagName("LineSymbolizer").item(0).toElement() + ) mExpectedValue = type(QgsSimpleLineSymbolLayer()) mValue = type(mSymbolLayer) mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage - mExpectedValue = '#aa007f' + mExpectedValue = "#aa007f" mValue = mSymbolLayer.color().name() mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage @@ -1041,8 +1061,10 @@ def testQgsEllipseSymbolLayer(self): """ Create a new style from a .sld file and match test """ - mTestName = 'QgsEllipseSymbolLayer' - mFilePath = QDir.toNativeSeparators(f'{unitTestDataPath()}/symbol_layer/{mTestName}.sld') + mTestName = "QgsEllipseSymbolLayer" + mFilePath = QDir.toNativeSeparators( + f"{unitTestDataPath()}/symbol_layer/{mTestName}.sld" + ) mDoc = QDomDocument(mTestName) mFile = QFile(mFilePath) @@ -1050,24 +1072,25 @@ def testQgsEllipseSymbolLayer(self): mDoc.setContent(mFile, True) mFile.close() mSymbolLayer = QgsEllipseSymbolLayer.createFromSld( - mDoc.elementsByTagName('PointSymbolizer').item(0).toElement()) + mDoc.elementsByTagName("PointSymbolizer").item(0).toElement() + ) mExpectedValue = type(QgsEllipseSymbolLayer()) mValue = type(mSymbolLayer) mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage - mExpectedValue = 'circle' + mExpectedValue = "circle" mValue = mSymbolLayer.symbolName() mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage - mExpectedValue = '#ffff7f' + mExpectedValue = "#ffff7f" mValue = mSymbolLayer.fillColor().name() mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage - mExpectedValue = '#aaaaff' + mExpectedValue = "#aaaaff" mValue = mSymbolLayer.strokeColor().name() mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage @@ -1089,8 +1112,10 @@ def testQgsFontMarkerSymbolLayer(self): """ Create a new style from a .sld file and match test """ - mTestName = 'QgsFontMarkerSymbolLayer' - mFilePath = QDir.toNativeSeparators(f'{unitTestDataPath()}/symbol_layer/{mTestName}.sld') + mTestName = "QgsFontMarkerSymbolLayer" + mFilePath = QDir.toNativeSeparators( + f"{unitTestDataPath()}/symbol_layer/{mTestName}.sld" + ) mDoc = QDomDocument(mTestName) mFile = QFile(mFilePath) @@ -1098,14 +1123,15 @@ def testQgsFontMarkerSymbolLayer(self): mDoc.setContent(mFile, True) mFile.close() mSymbolLayer = QgsFontMarkerSymbolLayer.createFromSld( - mDoc.elementsByTagName('PointSymbolizer').item(0).toElement()) + mDoc.elementsByTagName("PointSymbolizer").item(0).toElement() + ) mExpectedValue = type(QgsFontMarkerSymbolLayer()) mValue = type(mSymbolLayer) mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage - mExpectedValue = 'Arial' + mExpectedValue = "Arial" mValue = mSymbolLayer.fontFamily() mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage @@ -1132,22 +1158,26 @@ def testQgsSvgMarkerSymbolLayer(self): """ Create a new style from a .sld file and match test """ - mTestName = 'QgsSvgMarkerSymbolLayer' - mFilePath = QDir.toNativeSeparators(f'{unitTestDataPath()}/symbol_layer/{mTestName}.sld') + mTestName = "QgsSvgMarkerSymbolLayer" + mFilePath = QDir.toNativeSeparators( + f"{unitTestDataPath()}/symbol_layer/{mTestName}.sld" + ) mDoc = QDomDocument(mTestName) mFile = QFile(mFilePath) mFile.open(QIODevice.OpenModeFlag.ReadOnly) mDoc.setContent(mFile, True) mFile.close() - mSymbolLayer = QgsSvgMarkerSymbolLayer.createFromSld(mDoc.elementsByTagName('PointSymbolizer').item(0).toElement()) + mSymbolLayer = QgsSvgMarkerSymbolLayer.createFromSld( + mDoc.elementsByTagName("PointSymbolizer").item(0).toElement() + ) mExpectedValue = type(QgsSvgMarkerSymbolLayer("")) mValue = type(mSymbolLayer) mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' assert mExpectedValue == mValue, mMessage - mExpectedValue = 'skull.svg' + mExpectedValue = "skull.svg" mValue = os.path.basename(mSymbolLayer.path()) print(("VALUE", mSymbolLayer.path())) mMessage = f'Expected "{mExpectedValue}" got "{mValue}"' @@ -1165,8 +1195,8 @@ def testQgsSvgMarkerSymbolLayer(self): # Check values set from the query string in OnlineResource self.assertEqual(mSymbolLayer.strokeWidth(), 2.0) - self.assertEqual(mSymbolLayer.strokeColor().name(), '#ff0000') - self.assertEqual(mSymbolLayer.fillColor().name(), '#00ff00') + self.assertEqual(mSymbolLayer.strokeColor().name(), "#ff0000") + self.assertEqual(mSymbolLayer.fillColor().name(), "#00ff00") ctx = QgsRenderContext() self.assertCountEqual(mSymbolLayer.usedAttributes(ctx), {}) @@ -1191,17 +1221,29 @@ def testQgsFilledMarkerSymbolLayer(self): def testSldOpacityFillExport(self): """Test issue GH #33376""" - vl = QgsVectorLayer('Point?crs=epsg:4326', 'test', 'memory') + vl = QgsVectorLayer("Point?crs=epsg:4326", "test", "memory") - foo_sym = QgsFillSymbol.createSimple({'color': '#00ff00', 'outline_color': '#0000ff'}) + foo_sym = QgsFillSymbol.createSimple( + {"color": "#00ff00", "outline_color": "#0000ff"} + ) foo_sym.setOpacity(0.66) vl.setRenderer(QgsSingleSymbolRenderer(foo_sym)) doc = QDomDocument() vl.exportSldStyle(doc, None) - self.assertIn('0.66', doc.toString()) - self.assertIn('#00ff00', doc.toString()) - self.assertIn('#0000ff', doc.toString()) - self.assertIn('0.66', doc.toString()) + self.assertIn( + '0.66', + doc.toString(), + ) + self.assertIn( + '#00ff00', doc.toString() + ) + self.assertIn( + '#0000ff', doc.toString() + ) + self.assertIn( + '0.66', + doc.toString(), + ) def testQgsVectorFieldSymbolLayer(self): """ @@ -1222,63 +1264,47 @@ def testQgsVectorFieldSymbolLayer(self): def test_should_render_selection_color(self): layer = QgsSimpleFillSymbolLayer.create( - {'color': '#00ff00', 'outline_color': '#0000ff'} + {"color": "#00ff00", "outline_color": "#0000ff"} ) render_context = QgsRenderContext() - context = QgsSymbolRenderContext(render_context, - Qgis.RenderUnit.Millimeters, - selected=False) - self.assertFalse( - layer.shouldRenderUsingSelectionColor(context) - ) - layer.setUserFlags( - Qgis.SymbolLayerUserFlag.DisableSelectionRecoloring - ) - self.assertFalse( - layer.shouldRenderUsingSelectionColor(context) + context = QgsSymbolRenderContext( + render_context, Qgis.RenderUnit.Millimeters, selected=False ) + self.assertFalse(layer.shouldRenderUsingSelectionColor(context)) + layer.setUserFlags(Qgis.SymbolLayerUserFlag.DisableSelectionRecoloring) + self.assertFalse(layer.shouldRenderUsingSelectionColor(context)) layer.setUserFlags(Qgis.SymbolLayerUserFlags()) - context = QgsSymbolRenderContext(render_context, - Qgis.RenderUnit.Millimeters, - selected=True) - self.assertTrue( - layer.shouldRenderUsingSelectionColor(context) - ) - layer.setUserFlags( - Qgis.SymbolLayerUserFlag.DisableSelectionRecoloring - ) - self.assertFalse( - layer.shouldRenderUsingSelectionColor(context) + context = QgsSymbolRenderContext( + render_context, Qgis.RenderUnit.Millimeters, selected=True ) + self.assertTrue(layer.shouldRenderUsingSelectionColor(context)) + layer.setUserFlags(Qgis.SymbolLayerUserFlag.DisableSelectionRecoloring) + self.assertFalse(layer.shouldRenderUsingSelectionColor(context)) def test_force_vector_rendering(self): render_context = QgsRenderContext() - context = QgsSymbolRenderContext(render_context, - Qgis.RenderUnit.Millimeters, - selected=False) - self.assertFalse( - context.forceVectorRendering() + context = QgsSymbolRenderContext( + render_context, Qgis.RenderUnit.Millimeters, selected=False ) + self.assertFalse(context.forceVectorRendering()) # render context flag should force vector rendering render_context.setFlag(Qgis.RenderContextFlag.ForceVectorOutput, True) - context = QgsSymbolRenderContext(render_context, - Qgis.RenderUnit.Millimeters, - selected=False) - self.assertTrue( - context.forceVectorRendering() + context = QgsSymbolRenderContext( + render_context, Qgis.RenderUnit.Millimeters, selected=False ) + self.assertTrue(context.forceVectorRendering()) # symbol render hint should also force vector rendering render_context.setFlag(Qgis.RenderContextFlag.ForceVectorOutput, False) - context = QgsSymbolRenderContext(render_context, - Qgis.RenderUnit.Millimeters, - renderHints=Qgis.SymbolRenderHint.ForceVectorRendering) - self.assertTrue( - context.forceVectorRendering() + context = QgsSymbolRenderContext( + render_context, + Qgis.RenderUnit.Millimeters, + renderHints=Qgis.SymbolRenderHint.ForceVectorRendering, ) + self.assertTrue(context.forceVectorRendering()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssymbollayer_createsld.py b/tests/src/python/test_qgssymbollayer_createsld.py index d31f6d1ce153..642a18dd6b0b 100644 --- a/tests/src/python/test_qgssymbollayer_createsld.py +++ b/tests/src/python/test_qgssymbollayer_createsld.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Andrea Aime' -__date__ = 'July 2016' -__copyright__ = '(C) 2012, Andrea Aime' +__author__ = "Andrea Aime" +__date__ = "July 2016" +__copyright__ = "(C) 2012, Andrea Aime" import os @@ -71,34 +71,42 @@ class TestQgsSymbolLayerCreateSld(QgisTestCase): """ - This class tests the creation of SLD from QGis layers - """ + This class tests the creation of SLD from QGis layers + """ def testSimpleMarkerRotation(self): symbol = QgsSimpleMarkerSymbolLayer( - QgsSimpleMarkerSymbolLayerBase.Shape.Star, color=QColor(255, 0, 0), strokeColor=QColor(0, 255, 0), size=10) + QgsSimpleMarkerSymbolLayerBase.Shape.Star, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + ) symbol.setAngle(50) dom, root = self.symbolToSld(symbol) # print( "Simple marker rotation: " + root.ownerDocument().toString()) - self.assertStaticRotation(root, '50') + self.assertStaticRotation(root, "50") symbol.setAngle(-50) dom, root = self.symbolToSld(symbol) # print( "Simple marker rotation: " + root.ownerDocument().toString()) - self.assertStaticRotation(root, '-50') + self.assertStaticRotation(root, "-50") def testSimpleMarkerUnitDefault(self): symbol = QgsSimpleMarkerSymbolLayer( - QgsSimpleMarkerSymbolLayerBase.Shape.Star, color=QColor(255, 0, 0), strokeColor=QColor(0, 255, 0), size=10) + QgsSimpleMarkerSymbolLayerBase.Shape.Star, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + ) symbol.setStrokeWidth(3) symbol.setOffset(QPointF(5, 10)) dom, root = self.symbolToSld(symbol) # print("Simple marker unit mm: " + root.ownerDocument().toString()) # Check the size has been rescaled to pixels - self.assertStaticSize(root, '36') + self.assertStaticSize(root, "36") # Check the same happened to the stroke width self.assertStrokeWidth(root, 2, 11) @@ -112,7 +120,11 @@ def testSimpleMarkerUnitDefault(self): def testSimpleMarkerUnitPixels(self): symbol = QgsSimpleMarkerSymbolLayer( - QgsSimpleMarkerSymbolLayerBase.Shape.Star, color=QColor(255, 0, 0), strokeColor=QColor(0, 255, 0), size=10) + QgsSimpleMarkerSymbolLayerBase.Shape.Star, + color=QColor(255, 0, 0), + strokeColor=QColor(0, 255, 0), + size=10, + ) symbol.setStrokeWidth(3) symbol.setOffset(QPointF(5, 10)) symbol.setOutputUnit(QgsUnitTypes.RenderUnit.RenderPixels) @@ -120,99 +132,104 @@ def testSimpleMarkerUnitPixels(self): # print("Marker unit mm: " + root.ownerDocument().toString()) # Check the size has not been rescaled - self.assertStaticSize(root, '10') + self.assertStaticSize(root, "10") # Check the same happened to the stroke width self.assertStrokeWidth(root, 2, 3) self.assertStaticDisplacement(root, 5, 10) def testSvgMarkerUnitDefault(self): - symbol = QgsSvgMarkerSymbolLayer('symbols/star.svg', 10, 90) + symbol = QgsSvgMarkerSymbolLayer("symbols/star.svg", 10, 90) symbol.setFillColor(QColor("blue")) symbol.setStrokeWidth(1) - symbol.setStrokeColor(QColor('red')) - symbol.setPath('symbols/star.svg') + symbol.setStrokeColor(QColor("red")) + symbol.setPath("symbols/star.svg") symbol.setOffset(QPointF(5, 10)) dom, root = self.symbolToSld(symbol) # print("Svg marker mm: " + dom.toString()) - self.assertExternalGraphic(root, 0, - 'symbols/star.svg?fill=%230000ff&fill-opacity=1&outline=%23ff0000&outline-opacity=1&outline-width=4', - 'image/svg+xml') - self.assertExternalGraphic(root, 1, - 'symbols/star.svg', 'image/svg+xml') - self.assertWellKnownMark(root, 0, 'square', '#0000ff', '#ff0000', 4) + self.assertExternalGraphic( + root, + 0, + "symbols/star.svg?fill=%230000ff&fill-opacity=1&outline=%23ff0000&outline-opacity=1&outline-width=4", + "image/svg+xml", + ) + self.assertExternalGraphic(root, 1, "symbols/star.svg", "image/svg+xml") + self.assertWellKnownMark(root, 0, "square", "#0000ff", "#ff0000", 4) # Check the size has been rescaled - self.assertStaticSize(root, '36') + self.assertStaticSize(root, "36") # Check rotation for good measure - self.assertStaticRotation(root, '90') + self.assertStaticRotation(root, "90") self.assertStaticDisplacement(root, 18, 36) symbol.setAngle(-45) dom, root = self.symbolToSld(symbol) - self.assertStaticRotation(root, '-45') + self.assertStaticRotation(root, "-45") def testSvgMarkerUnitPixels(self): - symbol = QgsSvgMarkerSymbolLayer('symbols/star.svg', 10, 0) + symbol = QgsSvgMarkerSymbolLayer("symbols/star.svg", 10, 0) symbol.setFillColor(QColor("blue")) symbol.setStrokeWidth(1) - symbol.setStrokeColor(QColor('red')) - symbol.setPath('symbols/star.svg') + symbol.setStrokeColor(QColor("red")) + symbol.setPath("symbols/star.svg") symbol.setOffset(QPointF(5, 10)) symbol.setOutputUnit(QgsUnitTypes.RenderUnit.RenderPixels) dom, root = self.symbolToSld(symbol) # print("Svg marker unit px: " + dom.toString()) - self.assertExternalGraphic(root, 0, - 'symbols/star.svg?fill=%230000ff&fill-opacity=1&outline=%23ff0000&outline-opacity=1&outline-width=1', - 'image/svg+xml') - self.assertExternalGraphic(root, 1, - 'symbols/star.svg', 'image/svg+xml') - self.assertWellKnownMark(root, 0, 'square', '#0000ff', '#ff0000', 1) + self.assertExternalGraphic( + root, + 0, + "symbols/star.svg?fill=%230000ff&fill-opacity=1&outline=%23ff0000&outline-opacity=1&outline-width=1", + "image/svg+xml", + ) + self.assertExternalGraphic(root, 1, "symbols/star.svg", "image/svg+xml") + self.assertWellKnownMark(root, 0, "square", "#0000ff", "#ff0000", 1) # Check the size has not been rescaled - self.assertStaticSize(root, '10') + self.assertStaticSize(root, "10") self.assertStaticDisplacement(root, 5, 10) def testFontMarkerUnitDefault(self): - symbol = QgsFontMarkerSymbolLayer('sans', ',', 10, QColor('black'), 45) + symbol = QgsFontMarkerSymbolLayer("sans", ",", 10, QColor("black"), 45) symbol.setOffset(QPointF(5, 10)) dom, root = self.symbolToSld(symbol) # print("Font marker unit mm: " + dom.toString()) # Check the size has been rescaled - self.assertStaticSize(root, '36') - self.assertStaticRotation(root, '45') + self.assertStaticSize(root, "36") + self.assertStaticRotation(root, "45") self.assertStaticDisplacement(root, 18, 36) symbol.setAngle(-45) dom, root = self.symbolToSld(symbol) - self.assertStaticRotation(root, '-45') + self.assertStaticRotation(root, "-45") def testFontMarkerUnitPixel(self): - symbol = QgsFontMarkerSymbolLayer('sans', ',', 10, QColor('black'), 45) + symbol = QgsFontMarkerSymbolLayer("sans", ",", 10, QColor("black"), 45) symbol.setOffset(QPointF(5, 10)) symbol.setOutputUnit(QgsUnitTypes.RenderUnit.RenderPixels) dom, root = self.symbolToSld(symbol) # print ("Font marker unit mm: " + dom.toString()) # Check the size has been rescaled - self.assertStaticSize(root, '10') - self.assertStaticRotation(root, '45') + self.assertStaticSize(root, "10") + self.assertStaticRotation(root, "45") self.assertStaticDisplacement(root, 5, 10) symbol.setAngle(-45) dom, root = self.symbolToSld(symbol) - self.assertStaticRotation(root, '-45') + self.assertStaticRotation(root, "-45") def createEllipseSymbolLayer(self): # No way to build it programmatically... - mTestName = 'QgsEllipseSymbolLayer' + mTestName = "QgsEllipseSymbolLayer" mFilePath = QDir.toNativeSeparators( - f'{unitTestDataPath()}/symbol_layer/{mTestName}.sld') + f"{unitTestDataPath()}/symbol_layer/{mTestName}.sld" + ) mDoc = QDomDocument(mTestName) mFile = QFile(mFilePath) @@ -220,7 +237,8 @@ def createEllipseSymbolLayer(self): mDoc.setContent(mFile, True) mFile.close() mSymbolLayer = QgsEllipseSymbolLayer.createFromSld( - mDoc.elementsByTagName('PointSymbolizer').item(0).toElement()) + mDoc.elementsByTagName("PointSymbolizer").item(0).toElement() + ) return mSymbolLayer def testEllipseMarkerUnitDefault(self): @@ -231,7 +249,7 @@ def testEllipseMarkerUnitDefault(self): # print ("Ellipse marker unit mm: " + dom.toString()) # Check the size has been rescaled - self.assertStaticSize(root, '25') + self.assertStaticSize(root, "25") # Check also the stroke width self.assertStrokeWidth(root, 2, 4) self.assertStaticDisplacement(root, 18, 36) @@ -244,7 +262,7 @@ def testEllipseMarkerUnitPixel(self): # print ("Ellipse marker unit mm: " + dom.toString()) # Check the size has been rescaled - self.assertStaticSize(root, '7') + self.assertStaticSize(root, "7") # Check also the stroke width self.assertStrokeWidth(root, 2, 1) self.assertStaticDisplacement(root, 5, 10) @@ -268,8 +286,8 @@ def testSimpleLineUnitDefault(self): # print ("Simple line px: \n" + dom.toString()) self.assertStrokeWidth(root, 1, 4) - self.assertDashPattern(root, 4, '36 36') - self.assertStaticPerpendicularOffset(root, '18') + self.assertDashPattern(root, 4, "36 36") + self.assertStaticPerpendicularOffset(root, "18") def testSimpleLineUnitPixel(self): symbol = QgsSimpleLineSymbolLayer(QColor("black"), 1) @@ -282,13 +300,14 @@ def testSimpleLineUnitPixel(self): # print ("Simple line px: \n" + dom.toString()) self.assertStrokeWidth(root, 1, 1) - self.assertDashPattern(root, 4, '10 10') - self.assertStaticPerpendicularOffset(root, '5') + self.assertDashPattern(root, 4, "10 10") + self.assertStaticPerpendicularOffset(root, "5") def testMarkLineUnitDefault(self): symbol = QgsMarkerLineSymbolLayer() symbol.setSubSymbol( - QgsMarkerSymbol.createSimple({'color': '#ffffff', 'size': '3'})) + QgsMarkerSymbol.createSimple({"color": "#ffffff", "size": "3"}) + ) symbol.setInterval(5) symbol.setOffset(5) dom, root = self.symbolToSld(symbol) @@ -296,15 +315,16 @@ def testMarkLineUnitDefault(self): # print ("Mark line mm: \n" + dom.toString()) # size of the mark - self.assertStaticSize(root, '11') + self.assertStaticSize(root, "11") # gap and offset - self.assertStaticGap(root, '18') - self.assertStaticPerpendicularOffset(root, '18') + self.assertStaticGap(root, "18") + self.assertStaticPerpendicularOffset(root, "18") def testMarkLineUnitPixels(self): symbol = QgsMarkerLineSymbolLayer() symbol.setSubSymbol( - QgsMarkerSymbol.createSimple({'color': '#ffffff', 'size': '3'})) + QgsMarkerSymbol.createSimple({"color": "#ffffff", "size": "3"}) + ) symbol.setInterval(5) symbol.setOffset(5) symbol.setOutputUnit(QgsUnitTypes.RenderUnit.RenderPixels) @@ -313,14 +333,19 @@ def testMarkLineUnitPixels(self): # print ("Mark line px: \n" + dom.toString()) # size of the mark - self.assertStaticSize(root, '3') + self.assertStaticSize(root, "3") # gap and offset - self.assertStaticGap(root, '5') - self.assertStaticPerpendicularOffset(root, '5') + self.assertStaticGap(root, "5") + self.assertStaticPerpendicularOffset(root, "5") def testSimpleFillDefault(self): symbol = QgsSimpleFillSymbolLayer( - QColor('red'), Qt.BrushStyle.SolidPattern, QColor('green'), Qt.PenStyle.SolidLine, 5) + QColor("red"), + Qt.BrushStyle.SolidPattern, + QColor("green"), + Qt.PenStyle.SolidLine, + 5, + ) symbol.setOffset(QPointF(5, 10)) dom, root = self.symbolToSld(symbol) @@ -332,7 +357,12 @@ def testSimpleFillDefault(self): def testSimpleFillPixels(self): symbol = QgsSimpleFillSymbolLayer( - QColor('red'), Qt.BrushStyle.SolidPattern, QColor('green'), Qt.PenStyle.SolidLine, 5) + QColor("red"), + Qt.BrushStyle.SolidPattern, + QColor("green"), + Qt.PenStyle.SolidLine, + 5, + ) symbol.setOffset(QPointF(5, 10)) symbol.setOutputUnit(QgsUnitTypes.RenderUnit.RenderPixels) @@ -343,61 +373,65 @@ def testSimpleFillPixels(self): self.assertStaticDisplacement(root, 5, 10) def testSvgFillDefault(self): - symbol = QgsSVGFillSymbolLayer('test/star.svg', 10, 45) - symbol.setSvgFillColor(QColor('blue')) + symbol = QgsSVGFillSymbolLayer("test/star.svg", 10, 45) + symbol.setSvgFillColor(QColor("blue")) symbol.setSvgStrokeWidth(3) - symbol.setSvgStrokeColor(QColor('yellow')) + symbol.setSvgStrokeColor(QColor("yellow")) symbol.setSubSymbol(QgsLineSymbol()) symbol.subSymbol().setWidth(10) dom, root = self.symbolToSld(symbol) # print ("Svg fill mm: \n" + dom.toString()) - self.assertExternalGraphic(root, 0, - 'test/star.svg?fill=%230000ff&fill-opacity=1&outline=%23ffff00&outline-opacity=1&outline-width=11', - 'image/svg+xml') - self.assertExternalGraphic(root, 1, - 'test/star.svg', 'image/svg+xml') - self.assertWellKnownMark(root, 0, 'square', '#0000ff', '#ffff00', 11) - - self.assertStaticRotation(root, '45') - self.assertStaticSize(root, '36') + self.assertExternalGraphic( + root, + 0, + "test/star.svg?fill=%230000ff&fill-opacity=1&outline=%23ffff00&outline-opacity=1&outline-width=11", + "image/svg+xml", + ) + self.assertExternalGraphic(root, 1, "test/star.svg", "image/svg+xml") + self.assertWellKnownMark(root, 0, "square", "#0000ff", "#ffff00", 11) + + self.assertStaticRotation(root, "45") + self.assertStaticSize(root, "36") # width of the polygon stroke - lineSymbolizer = root.elementsByTagName('se:LineSymbolizer').item(0).toElement() + lineSymbolizer = root.elementsByTagName("se:LineSymbolizer").item(0).toElement() self.assertStrokeWidth(lineSymbolizer, 1, 36) symbol.setAngle(-45) dom, root = self.symbolToSld(symbol) - self.assertStaticRotation(root, '-45') + self.assertStaticRotation(root, "-45") def testSvgFillPixel(self): - symbol = QgsSVGFillSymbolLayer('test/star.svg', 10, 45) + symbol = QgsSVGFillSymbolLayer("test/star.svg", 10, 45) symbol.setSubSymbol(QgsLineSymbol()) - symbol.setSvgFillColor(QColor('blue')) + symbol.setSvgFillColor(QColor("blue")) symbol.setSvgStrokeWidth(3) - symbol.setSvgStrokeColor(QColor('black')) + symbol.setSvgStrokeColor(QColor("black")) symbol.setOutputUnit(QgsUnitTypes.RenderUnit.RenderPixels) symbol.subSymbol().setWidth(10) dom, root = self.symbolToSld(symbol) # print ("Svg fill px: \n" + dom.toString()) - self.assertExternalGraphic(root, 0, - 'test/star.svg?fill=%230000ff&fill-opacity=1&outline=%23000000&outline-opacity=1&outline-width=3', - 'image/svg+xml') - self.assertExternalGraphic(root, 1, - 'test/star.svg', 'image/svg+xml') - self.assertWellKnownMark(root, 0, 'square', '#0000ff', '#000000', 3) - - self.assertStaticRotation(root, '45') - self.assertStaticSize(root, '10') + self.assertExternalGraphic( + root, + 0, + "test/star.svg?fill=%230000ff&fill-opacity=1&outline=%23000000&outline-opacity=1&outline-width=3", + "image/svg+xml", + ) + self.assertExternalGraphic(root, 1, "test/star.svg", "image/svg+xml") + self.assertWellKnownMark(root, 0, "square", "#0000ff", "#000000", 3) + + self.assertStaticRotation(root, "45") + self.assertStaticSize(root, "10") # width of the polygon stroke - lineSymbolizer = root.elementsByTagName('se:LineSymbolizer').item(0).toElement() + lineSymbolizer = root.elementsByTagName("se:LineSymbolizer").item(0).toElement() self.assertStrokeWidth(lineSymbolizer, 1, 10) symbol.setAngle(-45) dom, root = self.symbolToSld(symbol) - self.assertStaticRotation(root, '-45') + self.assertStaticRotation(root, "-45") def testLineFillDefault(self): symbol = QgsLinePatternFillSymbolLayer() @@ -408,14 +442,14 @@ def testLineFillDefault(self): dom, root = self.symbolToSld(symbol) # print ("Line fill mm: \n" + dom.toString()) - self.assertStaticRotation(root, '45') + self.assertStaticRotation(root, "45") self.assertStrokeWidth(root, 1, 4) - self.assertStaticSize(root, '18') + self.assertStaticSize(root, "18") self.assertStaticDisplacement(root, 15, 9) symbol.setLineAngle(-45) dom, root = self.symbolToSld(symbol) - self.assertStaticRotation(root, '-45') + self.assertStaticRotation(root, "-45") def testLineFillPixels(self): symbol = QgsLinePatternFillSymbolLayer() @@ -427,21 +461,21 @@ def testLineFillPixels(self): dom, root = self.symbolToSld(symbol) # print ("Line fill px: \n" + dom.toString()) - self.assertStaticRotation(root, '45') + self.assertStaticRotation(root, "45") self.assertStrokeWidth(root, 1, 1) - self.assertStaticSize(root, '5') + self.assertStaticSize(root, "5") self.assertStaticDisplacement(root, 4.25, 2.63) symbol.setLineAngle(-45) dom, root = self.symbolToSld(symbol) - self.assertStaticRotation(root, '-45') + self.assertStaticRotation(root, "-45") def testPointFillDefault(self): symbol = QgsPointPatternFillSymbolLayer() dom, root = self.symbolToSld(symbol) # print ("Point fill mm: \n" + dom.toString()) - self.assertStaticSize(root, '7') + self.assertStaticSize(root, "7") def testPointFillpixels(self): symbol = QgsPointPatternFillSymbolLayer() @@ -449,11 +483,13 @@ def testPointFillpixels(self): dom, root = self.symbolToSld(symbol) # print ("Point fill px: \n" + dom.toString()) - self.assertStaticSize(root, '2') + self.assertStaticSize(root, "2") def testSingleSymbolNoScaleDependencies(self): layer = QgsVectorLayer("Point", "addfeat", "memory") - mFilePath = QDir.toNativeSeparators(f"{unitTestDataPath()}/symbol_layer/singleSymbol.qml") + mFilePath = QDir.toNativeSeparators( + f"{unitTestDataPath()}/symbol_layer/singleSymbol.qml" + ) layer.loadNamedStyle(mFilePath) dom, root = self.layerToSld(layer) @@ -463,7 +499,9 @@ def testSingleSymbolNoScaleDependencies(self): def testSingleSymbolScaleDependencies(self): layer = QgsVectorLayer("Point", "addfeat", "memory") - mFilePath = QDir.toNativeSeparators(f"{unitTestDataPath()}/symbol_layer/singleSymbol.qml") + mFilePath = QDir.toNativeSeparators( + f"{unitTestDataPath()}/symbol_layer/singleSymbol.qml" + ) layer.loadNamedStyle(mFilePath) layer.setMaximumScale(1000) layer.setMinimumScale(500000) @@ -472,23 +510,27 @@ def testSingleSymbolScaleDependencies(self): dom, root = self.layerToSld(layer) # print("Scale dep on single symbol:" + dom.toString()) - self.assertScaleDenominator(root, '1000', '500000') + self.assertScaleDenominator(root, "1000", "500000") def testCategorizedNoScaleDependencies(self): layer = QgsVectorLayer("Polygon", "addfeat", "memory") - mFilePath = QDir.toNativeSeparators(f"{unitTestDataPath()}/symbol_layer/categorized.qml") + mFilePath = QDir.toNativeSeparators( + f"{unitTestDataPath()}/symbol_layer/categorized.qml" + ) layer.loadNamedStyle(mFilePath) dom, root = self.layerToSld(layer) # print("Categorized no scale deps:" + dom.toString()) - ruleCount = root.elementsByTagName('se:Rule').size() + ruleCount = root.elementsByTagName("se:Rule").size() for i in range(0, ruleCount): self.assertScaleDenominator(root, None, None, i) def testCategorizedWithScaleDependencies(self): layer = QgsVectorLayer("Polygon", "addfeat", "memory") - mFilePath = QDir.toNativeSeparators(f"{unitTestDataPath()}/symbol_layer/categorized.qml") + mFilePath = QDir.toNativeSeparators( + f"{unitTestDataPath()}/symbol_layer/categorized.qml" + ) layer.loadNamedStyle(mFilePath) layer.setMaximumScale(1000) layer.setMinimumScale(500000) @@ -497,20 +539,22 @@ def testCategorizedWithScaleDependencies(self): dom, root = self.layerToSld(layer) # print("Categorized with scale deps:" + dom.toString()) - ruleCount = root.elementsByTagName('se:Rule').size() + ruleCount = root.elementsByTagName("se:Rule").size() for i in range(0, ruleCount): - self.assertScaleDenominator(root, '1000', '500000', i) + self.assertScaleDenominator(root, "1000", "500000", i) def testGraduatedNoScaleDependencies(self): layer = QgsVectorLayer("Polygon", "addfeat", "memory") - mFilePath = QDir.toNativeSeparators(f"{unitTestDataPath()}/symbol_layer/graduated.qml") + mFilePath = QDir.toNativeSeparators( + f"{unitTestDataPath()}/symbol_layer/graduated.qml" + ) status = layer.loadNamedStyle(mFilePath) # NOQA dom, root = self.layerToSld(layer) # print("Graduated no scale deps:" + dom.toString()) - ruleCount = root.elementsByTagName('se:Rule').size() + ruleCount = root.elementsByTagName("se:Rule").size() for i in range(0, ruleCount): self.assertScaleDenominator(root, None, None, i) @@ -530,7 +574,9 @@ def testGraduatedNoScaleDependencies(self): def testRuleBasedNoRootScaleDependencies(self): layer = QgsVectorLayer("Polygon", "addfeat", "memory") - mFilePath = QDir.toNativeSeparators(f"{unitTestDataPath()}/symbol_layer/ruleBased.qml") + mFilePath = QDir.toNativeSeparators( + f"{unitTestDataPath()}/symbol_layer/ruleBased.qml" + ) status = layer.loadNamedStyle(mFilePath) # NOQA layer.setMaximumScale(5000) layer.setMinimumScale(50000000) @@ -539,37 +585,44 @@ def testRuleBasedNoRootScaleDependencies(self): dom, root = self.layerToSld(layer) # print("Rule based, with root scale deps:" + dom.toString()) - ruleCount = root.elementsByTagName('se:Rule').size() # NOQA - self.assertScaleDenominator(root, '5000', '40000000', 0) - self.assertScaleDenominator(root, '5000', '50000000', 1) + ruleCount = root.elementsByTagName("se:Rule").size() # NOQA + self.assertScaleDenominator(root, "5000", "40000000", 0) + self.assertScaleDenominator(root, "5000", "50000000", 1) def testCategorizedFunctionConflict(self): layer = QgsVectorLayer("Point", "addfeat", "memory") mFilePath = QDir.toNativeSeparators( - f"{unitTestDataPath()}/symbol_layer/categorizedFunctionConflict.qml") + f"{unitTestDataPath()}/symbol_layer/categorizedFunctionConflict.qml" + ) status = layer.loadNamedStyle(mFilePath) # NOQA dom, root = self.layerToSld(layer) # print("Rule based, with root scale deps:" + dom.toString()) - ruleCount = root.elementsByTagName('se:Rule').size() # NOQA + ruleCount = root.elementsByTagName("se:Rule").size() # NOQA self.assertEqual(7, ruleCount) - self.assertRuleRangeFilter(root, 0, 'Area', '0', True, '500', True) - self.assertRuleRangeFilter(root, 1, 'Area', '500', False, '1000', True) - self.assertRuleRangeFilter(root, 2, 'Area', '1000', False, '5000', True) - self.assertRuleRangeFilter(root, 3, 'Area', '5000', False, '10000', True) - self.assertRuleRangeFilter(root, 4, 'Area', '10000', False, '50000', True) - self.assertRuleRangeFilter(root, 5, 'Area', '50000', False, '100000', True) - self.assertRuleRangeFilter(root, 6, 'Area', '100000', False, '200000', True) - - def assertRuleRangeFilter(self, root, index, attributeName, min, includeMin, max, includeMax): - rule = root.elementsByTagName('se:Rule').item(index).toElement() + self.assertRuleRangeFilter(root, 0, "Area", "0", True, "500", True) + self.assertRuleRangeFilter(root, 1, "Area", "500", False, "1000", True) + self.assertRuleRangeFilter(root, 2, "Area", "1000", False, "5000", True) + self.assertRuleRangeFilter(root, 3, "Area", "5000", False, "10000", True) + self.assertRuleRangeFilter(root, 4, "Area", "10000", False, "50000", True) + self.assertRuleRangeFilter(root, 5, "Area", "50000", False, "100000", True) + self.assertRuleRangeFilter(root, 6, "Area", "100000", False, "200000", True) + + def assertRuleRangeFilter( + self, root, index, attributeName, min, includeMin, max, includeMax + ): + rule = root.elementsByTagName("se:Rule").item(index).toElement() filter = rule.elementsByTagName("Filter").item(0).firstChild() self.assertEqual("ogc:And", filter.nodeName()) gt = filter.firstChild() - expectedGtName = "ogc:PropertyIsGreaterThanOrEqualTo" if includeMin else "ogc:PropertyIsGreaterThan" + expectedGtName = ( + "ogc:PropertyIsGreaterThanOrEqualTo" + if includeMin + else "ogc:PropertyIsGreaterThan" + ) self.assertEqual(expectedGtName, gt.nodeName()) gtProperty = gt.firstChild() self.assertEqual("ogc:PropertyName", gtProperty.nodeName()) @@ -578,7 +631,11 @@ def assertRuleRangeFilter(self, root, index, attributeName, min, includeMin, max self.assertEqual(min, gtValue.toElement().text()) lt = filter.childNodes().item(1) - expectedLtName = "ogc:PropertyIsLessThanOrEqualTo" if includeMax else "ogc:PropertyIsLessThan" + expectedLtName = ( + "ogc:PropertyIsLessThanOrEqualTo" + if includeMax + else "ogc:PropertyIsLessThan" + ) self.assertEqual(expectedLtName, lt.nodeName()) ltProperty = lt.firstChild() self.assertEqual("ogc:PropertyName", ltProperty.nodeName()) @@ -605,13 +662,15 @@ def testSimpleLabeling(self): # print("Simple label text symbolizer" + dom.toString()) ts = self.getTextSymbolizer(root, 1, 0) - self.assertPropertyName(ts, 'se:Label', 'NAME') - font = self.assertElement(ts, 'se:Font', 0) - self.assertEqual(fontFamily, self.assertSvgParameter(font, 'font-family').text()) - self.assertEqual('11', self.assertSvgParameter(font, 'font-size').text()) + self.assertPropertyName(ts, "se:Label", "NAME") + font = self.assertElement(ts, "se:Font", 0) + self.assertEqual( + fontFamily, self.assertSvgParameter(font, "font-family").text() + ) + self.assertEqual("11", self.assertSvgParameter(font, "font-size").text()) - fill = self.assertElement(ts, 'se:Fill', 0) - self.assertEqual('#000000', self.assertSvgParameter(fill, "fill").text()) + fill = self.assertElement(ts, "se:Fill", 0) + self.assertEqual("#000000", self.assertSvgParameter(fill, "fill").text()) self.assertIsNone(self.assertSvgParameter(fill, "fill-opacity", True)) def testLabelingUomMillimeter(self): @@ -623,8 +682,8 @@ def testLabelingUomMillimeter(self): # print("Label sized in mm " + dom.toString()) ts = self.getTextSymbolizer(root, 1, 0) - font = self.assertElement(ts, 'se:Font', 0) - self.assertEqual('32', self.assertSvgParameter(font, 'font-size').text()) + font = self.assertElement(ts, "se:Font", 0) + self.assertEqual("32", self.assertSvgParameter(font, "font-size").text()) def testLabelingUomPixels(self): layer = QgsVectorLayer("Point", "addfeat", "memory") @@ -635,8 +694,8 @@ def testLabelingUomPixels(self): # print("Label sized in pixels " + dom.toString()) ts = self.getTextSymbolizer(root, 1, 0) - font = self.assertElement(ts, 'se:Font', 0) - self.assertEqual('9', self.assertSvgParameter(font, 'font-size').text()) + font = self.assertElement(ts, "se:Font", 0) + self.assertEqual("9", self.assertSvgParameter(font, "font-size").text()) def testLabelingUomInches(self): layer = QgsVectorLayer("Point", "addfeat", "memory") @@ -647,8 +706,8 @@ def testLabelingUomInches(self): # print("Label sized in inches " + dom.toString()) ts = self.getTextSymbolizer(root, 1, 0) - font = self.assertElement(ts, 'se:Font', 0) - self.assertEqual('816', self.assertSvgParameter(font, 'font-size').text()) + font = self.assertElement(ts, "se:Font", 0) + self.assertEqual("816", self.assertSvgParameter(font, "font-size").text()) def testTextStyle(self): layer = QgsVectorLayer("Point", "addfeat", "memory") @@ -659,57 +718,65 @@ def testTextStyle(self): dom, root = self.layerToSld(layer) # print("Simple label italic text" + dom.toString()) ts = self.getTextSymbolizer(root, 1, 0) - font = self.assertElement(ts, 'se:Font', 0) - self.assertIsNone(self.assertSvgParameter(font, 'font-weight', True)) - self.assertIsNone(self.assertSvgParameter(font, 'font-style', True)) + font = self.assertElement(ts, "se:Font", 0) + self.assertIsNone(self.assertSvgParameter(font, "font-weight", True)) + self.assertIsNone(self.assertSvgParameter(font, "font-style", True)) # testing bold self.updateLayerLabelingFontStyle(layer, True, False) dom, root = self.layerToSld(layer) # print("Simple label bold text" + dom.toString()) ts = self.getTextSymbolizer(root, 1, 0) - font = self.assertElement(ts, 'se:Font', 0) - self.assertEqual('bold', self.assertSvgParameter(font, 'font-weight').text()) - self.assertIsNone(self.assertSvgParameter(font, 'font-style', True)) + font = self.assertElement(ts, "se:Font", 0) + self.assertEqual("bold", self.assertSvgParameter(font, "font-weight").text()) + self.assertIsNone(self.assertSvgParameter(font, "font-style", True)) # testing italic self.updateLayerLabelingFontStyle(layer, False, True) dom, root = self.layerToSld(layer) # print("Simple label italic text" + dom.toString()) ts = self.getTextSymbolizer(root, 1, 0) - font = self.assertElement(ts, 'se:Font', 0) - self.assertEqual('italic', self.assertSvgParameter(font, 'font-style').text()) - self.assertIsNone(self.assertSvgParameter(font, 'font-weight', True)) + font = self.assertElement(ts, "se:Font", 0) + self.assertEqual("italic", self.assertSvgParameter(font, "font-style").text()) + self.assertIsNone(self.assertSvgParameter(font, "font-weight", True)) # testing bold italic self.updateLayerLabelingFontStyle(layer, True, True) dom, root = self.layerToSld(layer) # print("Simple label bold and italic text" + dom.toString()) ts = self.getTextSymbolizer(root, 1, 0) - font = self.assertElement(ts, 'se:Font', 0) - self.assertEqual('italic', self.assertSvgParameter(font, 'font-style').text()) - self.assertEqual('bold', self.assertSvgParameter(font, 'font-weight').text()) + font = self.assertElement(ts, "se:Font", 0) + self.assertEqual("italic", self.assertSvgParameter(font, "font-style").text()) + self.assertEqual("bold", self.assertSvgParameter(font, "font-weight").text()) # testing underline and strikethrough vendor options self.updateLayerLabelingFontStyle(layer, False, False, True, True) dom, root = self.layerToSld(layer) # print("Simple label underline and strikethrough text" + dom.toString()) ts = self.getTextSymbolizer(root, 1, 0) - font = self.assertElement(ts, 'se:Font', 0) - self.assertEqual('true', self.assertVendorOption(ts, 'underlineText').text()) - self.assertEqual('true', self.assertVendorOption(ts, 'strikethroughText').text()) + font = self.assertElement(ts, "se:Font", 0) + self.assertEqual("true", self.assertVendorOption(ts, "underlineText").text()) + self.assertEqual( + "true", self.assertVendorOption(ts, "strikethroughText").text() + ) def testTextMixedCase(self): self.assertCapitalizationFunction(QFont.Capitalization.MixedCase, None) def testTextUppercase(self): - self.assertCapitalizationFunction(QFont.Capitalization.AllUppercase, "strToUpperCase") + self.assertCapitalizationFunction( + QFont.Capitalization.AllUppercase, "strToUpperCase" + ) def testTextLowercase(self): - self.assertCapitalizationFunction(QFont.Capitalization.AllLowercase, "strToLowerCase") + self.assertCapitalizationFunction( + QFont.Capitalization.AllLowercase, "strToLowerCase" + ) def testTextCapitalcase(self): - self.assertCapitalizationFunction(QFont.Capitalization.Capitalize, "strCapitalize") + self.assertCapitalizationFunction( + QFont.Capitalization.Capitalize, "strCapitalize" + ) def assertCapitalizationFunction(self, capitalization, expectedFunction): layer = QgsVectorLayer("Point", "addfeat", "memory") @@ -749,9 +816,9 @@ def testLabelingTransparency(self): # print("Label with transparency " + dom.toString()) ts = self.getTextSymbolizer(root, 1, 0) - fill = self.assertElement(ts, 'se:Fill', 0) - self.assertEqual('#000000', self.assertSvgParameter(fill, "fill").text()) - self.assertEqual('0.5', self.assertSvgParameter(fill, "fill-opacity").text()) + fill = self.assertElement(ts, "se:Fill", 0) + self.assertEqual("#000000", self.assertSvgParameter(fill, "fill").text()) + self.assertEqual("0.5", self.assertSvgParameter(fill, "fill-opacity").text()) def testLabelingBuffer(self): layer = QgsVectorLayer("Point", "addfeat", "memory") @@ -767,11 +834,11 @@ def testLabelingBuffer(self): # print("Label with buffer 10 px " + dom.toString()) ts = self.getTextSymbolizer(root, 1, 0) - halo = self.assertElement(ts, 'se:Halo', 0) + halo = self.assertElement(ts, "se:Halo", 0) # not full width, just radius here - self.assertEqual('5', self.assertElement(ts, 'se:Radius', 0).text()) - haloFill = self.assertElement(halo, 'se:Fill', 0) - self.assertEqual('#000000', self.assertSvgParameter(haloFill, "fill").text()) + self.assertEqual("5", self.assertElement(ts, "se:Radius", 0).text()) + haloFill = self.assertElement(halo, "se:Fill", 0) + self.assertEqual("#000000", self.assertSvgParameter(haloFill, "fill").text()) def testLabelingBufferPointTranslucent(self): layer = QgsVectorLayer("Point", "addfeat", "memory") @@ -788,30 +855,32 @@ def testLabelingBufferPointTranslucent(self): # print("Label with buffer 10 points, red 50% transparent " + dom.toString()) ts = self.getTextSymbolizer(root, 1, 0) - halo = self.assertElement(ts, 'se:Halo', 0) + halo = self.assertElement(ts, "se:Halo", 0) # not full width, just radius here - self.assertEqual('6.5', self.assertElement(ts, 'se:Radius', 0).text()) - haloFill = self.assertElement(halo, 'se:Fill', 0) - self.assertEqual('#ff0000', self.assertSvgParameter(haloFill, "fill").text()) - self.assertEqual('0.5', self.assertSvgParameter(haloFill, "fill-opacity").text()) + self.assertEqual("6.5", self.assertElement(ts, "se:Radius", 0).text()) + haloFill = self.assertElement(halo, "se:Fill", 0) + self.assertEqual("#ff0000", self.assertSvgParameter(haloFill, "fill").text()) + self.assertEqual( + "0.5", self.assertSvgParameter(haloFill, "fill-opacity").text() + ) def testLabelingLowPriority(self): - self.assertLabelingPriority(0, 0, '0') + self.assertLabelingPriority(0, 0, "0") def testLabelingDefaultPriority(self): self.assertLabelingPriority(0, 5, None) def testLabelingHighPriority(self): - self.assertLabelingPriority(0, 10, '1000') + self.assertLabelingPriority(0, 10, "1000") def testLabelingZIndexLowPriority(self): - self.assertLabelingPriority(1, 0, '1001') + self.assertLabelingPriority(1, 0, "1001") def testLabelingZIndexDefaultPriority(self): self.assertLabelingPriority(1, 5, "1500") def testLabelingZIndexHighPriority(self): - self.assertLabelingPriority(1, 10, '2000') + self.assertLabelingPriority(1, 10, "2000") def assertLabelingPriority(self, zIndex, priority, expectedSldPriority): layer = QgsVectorLayer("Point", "addfeat", "memory") @@ -852,31 +921,49 @@ def testLabelingPlacementOverPointOffsetRotation(self): self.assertStaticAnchorPoint(pointPlacement, 0.5, 0.5) def testPointPlacementAboveLeft(self): - self.assertLabelQuadrant(QgsPalLayerSettings.QuadrantPosition.QuadrantAboveLeft, "AboveLeft", 1, 0) + self.assertLabelQuadrant( + QgsPalLayerSettings.QuadrantPosition.QuadrantAboveLeft, "AboveLeft", 1, 0 + ) def testPointPlacementAbove(self): - self.assertLabelQuadrant(QgsPalLayerSettings.QuadrantPosition.QuadrantAbove, "Above", 0.5, 0) + self.assertLabelQuadrant( + QgsPalLayerSettings.QuadrantPosition.QuadrantAbove, "Above", 0.5, 0 + ) def testPointPlacementAboveRight(self): - self.assertLabelQuadrant(QgsPalLayerSettings.QuadrantPosition.QuadrantAboveRight, "AboveRight", 0, 0) + self.assertLabelQuadrant( + QgsPalLayerSettings.QuadrantPosition.QuadrantAboveRight, "AboveRight", 0, 0 + ) def testPointPlacementLeft(self): - self.assertLabelQuadrant(QgsPalLayerSettings.QuadrantPosition.QuadrantLeft, "Left", 1, 0.5) + self.assertLabelQuadrant( + QgsPalLayerSettings.QuadrantPosition.QuadrantLeft, "Left", 1, 0.5 + ) def testPointPlacementRight(self): - self.assertLabelQuadrant(QgsPalLayerSettings.QuadrantPosition.QuadrantRight, "Right", 0, 0.5) + self.assertLabelQuadrant( + QgsPalLayerSettings.QuadrantPosition.QuadrantRight, "Right", 0, 0.5 + ) def testPointPlacementBelowLeft(self): - self.assertLabelQuadrant(QgsPalLayerSettings.QuadrantPosition.QuadrantBelowLeft, "BelowLeft", 1, 1) + self.assertLabelQuadrant( + QgsPalLayerSettings.QuadrantPosition.QuadrantBelowLeft, "BelowLeft", 1, 1 + ) def testPointPlacementBelow(self): - self.assertLabelQuadrant(QgsPalLayerSettings.QuadrantPosition.QuadrantBelow, "Below", 0.5, 1) + self.assertLabelQuadrant( + QgsPalLayerSettings.QuadrantPosition.QuadrantBelow, "Below", 0.5, 1 + ) def testPointPlacementBelowRight(self): - self.assertLabelQuadrant(QgsPalLayerSettings.QuadrantPosition.QuadrantBelowRight, "BelowRight", 0, 1) + self.assertLabelQuadrant( + QgsPalLayerSettings.QuadrantPosition.QuadrantBelowRight, "BelowRight", 0, 1 + ) def testPointPlacementCartoraphicOrderedPositionsAroundPoint(self): - self.assertPointPlacementDistance(QgsPalLayerSettings.Placement.OrderedPositionsAroundPoint) + self.assertPointPlacementDistance( + QgsPalLayerSettings.Placement.OrderedPositionsAroundPoint + ) def testPointPlacementCartoraphicAroundPoint(self): self.assertPointPlacementDistance(QgsPalLayerSettings.Placement.AroundPoint) @@ -888,45 +975,49 @@ def testLineParallelPlacement(self): dom, root = self.layerToSld(layer) # print("Label with parallel line placement " + dom.toString()) linePlacement = self.assertLinePlacement(root) - generalize = self.assertElement(linePlacement, 'se:GeneralizeLine', 0) + generalize = self.assertElement(linePlacement, "se:GeneralizeLine", 0) self.assertEqual("true", generalize.text()) def testLineParallelPlacementOffsetRepeat(self): layer = QgsVectorLayer("LineString", "addfeat", "memory") self.loadStyleWithCustomProperties(layer, "lineLabel") - self.updateLinePlacementProperties(layer, QgsPalLayerSettings.Placement.Line, 2, 50) + self.updateLinePlacementProperties( + layer, QgsPalLayerSettings.Placement.Line, 2, 50 + ) dom, root = self.layerToSld(layer) # print("Label with parallel line placement, perp. offset and repeat " + dom.toString()) ts = self.getTextSymbolizer(root, 1, 0) linePlacement = self.assertLinePlacement(ts) - generalize = self.assertElement(linePlacement, 'se:GeneralizeLine', 0) + generalize = self.assertElement(linePlacement, "se:GeneralizeLine", 0) self.assertEqual("true", generalize.text()) - offset = self.assertElement(linePlacement, 'se:PerpendicularOffset', 0) + offset = self.assertElement(linePlacement, "se:PerpendicularOffset", 0) self.assertEqual("7", offset.text()) - repeat = self.assertElement(linePlacement, 'se:Repeat', 0) + repeat = self.assertElement(linePlacement, "se:Repeat", 0) self.assertEqual("true", repeat.text()) - gap = self.assertElement(linePlacement, 'se:Gap', 0) + gap = self.assertElement(linePlacement, "se:Gap", 0) self.assertEqual("179", gap.text()) self.assertEqual("179", self.assertVendorOption(ts, "repeat").text()) def testLineCurvePlacementOffsetRepeat(self): layer = QgsVectorLayer("LineString", "addfeat", "memory") self.loadStyleWithCustomProperties(layer, "lineLabel") - self.updateLinePlacementProperties(layer, QgsPalLayerSettings.Placement.Curved, 2, 50, 30, 40) + self.updateLinePlacementProperties( + layer, QgsPalLayerSettings.Placement.Curved, 2, 50, 30, 40 + ) dom, root = self.layerToSld(layer) # print("Label with curved line placement " + dom.toString()) ts = self.getTextSymbolizer(root, 1, 0) linePlacement = self.assertLinePlacement(ts) - generalize = self.assertElement(linePlacement, 'se:GeneralizeLine', 0) + generalize = self.assertElement(linePlacement, "se:GeneralizeLine", 0) self.assertEqual("true", generalize.text()) - offset = self.assertElement(linePlacement, 'se:PerpendicularOffset', 0) + offset = self.assertElement(linePlacement, "se:PerpendicularOffset", 0) self.assertEqual("7", offset.text()) - repeat = self.assertElement(linePlacement, 'se:Repeat', 0) + repeat = self.assertElement(linePlacement, "se:Repeat", 0) self.assertEqual("true", repeat.text()) - gap = self.assertElement(linePlacement, 'se:Gap', 0) + gap = self.assertElement(linePlacement, "se:Gap", 0) self.assertEqual("179", gap.text()) self.assertEqual("179", self.assertVendorOption(ts, "repeat").text()) self.assertEqual("true", self.assertVendorOption(ts, "followLine").text()) @@ -966,20 +1057,22 @@ def testLabelingPolygonFree(self): def testLabelingPolygonPerimeterCurved(self): layer = QgsVectorLayer("Polygon", "addfeat", "memory") self.loadStyleWithCustomProperties(layer, "polygonLabel") - self.updateLinePlacementProperties(layer, QgsPalLayerSettings.Placement.PerimeterCurved, 2, 50, 30, -40) + self.updateLinePlacementProperties( + layer, QgsPalLayerSettings.Placement.PerimeterCurved, 2, 50, 30, -40 + ) dom, root = self.layerToSld(layer) # print("Polygon Label with curved perimeter line placement " + dom.toString()) ts = self.getTextSymbolizer(root, 1, 0) linePlacement = self.assertLinePlacement(ts) - generalize = self.assertElement(linePlacement, 'se:GeneralizeLine', 0) + generalize = self.assertElement(linePlacement, "se:GeneralizeLine", 0) self.assertEqual("true", generalize.text()) - offset = self.assertElement(linePlacement, 'se:PerpendicularOffset', 0) + offset = self.assertElement(linePlacement, "se:PerpendicularOffset", 0) self.assertEqual("7", offset.text()) - repeat = self.assertElement(linePlacement, 'se:Repeat', 0) + repeat = self.assertElement(linePlacement, "se:Repeat", 0) self.assertEqual("true", repeat.text()) - gap = self.assertElement(linePlacement, 'se:Gap', 0) + gap = self.assertElement(linePlacement, "se:Gap", 0) self.assertEqual("179", gap.text()) self.assertEqual("179", self.assertVendorOption(ts, "repeat").text()) self.assertEqual("true", self.assertVendorOption(ts, "followLine").text()) @@ -1026,46 +1119,80 @@ def testLabelUpsideDown(self): self.assertVendorOption(ts, "forceLeftToRight", "false") def testLabelBackgroundSquareResize(self): - self.assertLabelBackground(QgsTextBackgroundSettings.ShapeType.ShapeSquare, 'square', - QgsTextBackgroundSettings.SizeType.SizeBuffer, 'proportional') + self.assertLabelBackground( + QgsTextBackgroundSettings.ShapeType.ShapeSquare, + "square", + QgsTextBackgroundSettings.SizeType.SizeBuffer, + "proportional", + ) def testLabelBackgroundRectangleResize(self): - self.assertLabelBackground(QgsTextBackgroundSettings.ShapeType.ShapeRectangle, 'square', - QgsTextBackgroundSettings.SizeType.SizeBuffer, 'stretch') + self.assertLabelBackground( + QgsTextBackgroundSettings.ShapeType.ShapeRectangle, + "square", + QgsTextBackgroundSettings.SizeType.SizeBuffer, + "stretch", + ) def testLabelBackgroundCircleResize(self): - self.assertLabelBackground(QgsTextBackgroundSettings.ShapeType.ShapeCircle, 'circle', - QgsTextBackgroundSettings.SizeType.SizeBuffer, 'proportional') + self.assertLabelBackground( + QgsTextBackgroundSettings.ShapeType.ShapeCircle, + "circle", + QgsTextBackgroundSettings.SizeType.SizeBuffer, + "proportional", + ) def testLabelBackgroundEllipseResize(self): - self.assertLabelBackground(QgsTextBackgroundSettings.ShapeType.ShapeEllipse, 'circle', - QgsTextBackgroundSettings.SizeType.SizeBuffer, 'stretch') + self.assertLabelBackground( + QgsTextBackgroundSettings.ShapeType.ShapeEllipse, + "circle", + QgsTextBackgroundSettings.SizeType.SizeBuffer, + "stretch", + ) def testLabelBackgroundSquareAbsolute(self): - self.assertLabelBackground(QgsTextBackgroundSettings.ShapeType.ShapeSquare, 'square', - QgsTextBackgroundSettings.SizeType.SizeFixed, None) + self.assertLabelBackground( + QgsTextBackgroundSettings.ShapeType.ShapeSquare, + "square", + QgsTextBackgroundSettings.SizeType.SizeFixed, + None, + ) def testLabelBackgroundRectangleAbsolute(self): - self.assertLabelBackground(QgsTextBackgroundSettings.ShapeType.ShapeRectangle, 'square', - QgsTextBackgroundSettings.SizeType.SizeFixed, None) + self.assertLabelBackground( + QgsTextBackgroundSettings.ShapeType.ShapeRectangle, + "square", + QgsTextBackgroundSettings.SizeType.SizeFixed, + None, + ) def testLabelBackgroundCircleAbsolute(self): - self.assertLabelBackground(QgsTextBackgroundSettings.ShapeType.ShapeCircle, 'circle', - QgsTextBackgroundSettings.SizeType.SizeFixed, None) + self.assertLabelBackground( + QgsTextBackgroundSettings.ShapeType.ShapeCircle, + "circle", + QgsTextBackgroundSettings.SizeType.SizeFixed, + None, + ) def testLabelBackgroundEllipseAbsolute(self): - self.assertLabelBackground(QgsTextBackgroundSettings.ShapeType.ShapeEllipse, 'circle', - QgsTextBackgroundSettings.SizeType.SizeFixed, None) - - def assertLabelBackground(self, backgroundType, expectedMarkName, sizeType, expectedResize): + self.assertLabelBackground( + QgsTextBackgroundSettings.ShapeType.ShapeEllipse, + "circle", + QgsTextBackgroundSettings.SizeType.SizeFixed, + None, + ) + + def assertLabelBackground( + self, backgroundType, expectedMarkName, sizeType, expectedResize + ): layer = QgsVectorLayer("Polygon", "addfeat", "memory") self.loadStyleWithCustomProperties(layer, "polygonLabel") settings = layer.labeling().settings() background = QgsTextBackgroundSettings() background.setEnabled(True) background.setType(backgroundType) - background.setFillColor(QColor('yellow')) - background.setStrokeColor(QColor('black')) + background.setFillColor(QColor("yellow")) + background.setStrokeColor(QColor("black")) background.setStrokeWidth(2) background.setSize(QSizeF(10, 10)) background.setSizeType(sizeType) @@ -1079,20 +1206,28 @@ def assertLabelBackground(self, backgroundType, expectedMarkName, sizeType, expe ts = self.getTextSymbolizer(root, 1, 0) graphic = self.assertElement(ts, "se:Graphic", 0) - self.assertEqual("36", self.assertElement(graphic, 'se:Size', 0).text()) - self.assertWellKnownMark(graphic, 0, expectedMarkName, '#ffff00', '#000000', 7) + self.assertEqual("36", self.assertElement(graphic, "se:Size", 0).text()) + self.assertWellKnownMark(graphic, 0, expectedMarkName, "#ffff00", "#000000", 7) if expectedResize is None: - self.assertIsNone(expectedResize, self.assertVendorOption(ts, 'graphic-resize', True)) + self.assertIsNone( + expectedResize, self.assertVendorOption(ts, "graphic-resize", True) + ) else: - self.assertEqual(expectedResize, self.assertVendorOption(ts, 'graphic-resize').text()) + self.assertEqual( + expectedResize, self.assertVendorOption(ts, "graphic-resize").text() + ) if sizeType == 0: # check extra padding for proportional ellipse if backgroundType == QgsTextBackgroundSettings.ShapeType.ShapeEllipse: - self.assertEqual("42.5 49", self.assertVendorOption(ts, 'graphic-margin').text()) + self.assertEqual( + "42.5 49", self.assertVendorOption(ts, "graphic-margin").text() + ) else: - self.assertEqual("36 36", self.assertVendorOption(ts, 'graphic-margin').text()) + self.assertEqual( + "36 36", self.assertVendorOption(ts, "graphic-margin").text() + ) else: - self.assertIsNone(self.assertVendorOption(ts, 'graphic-margin', True)) + self.assertIsNone(self.assertVendorOption(ts, "graphic-margin", True)) def testLabelBackgroundSymbol(self): layer = QgsVectorLayer("Polygon", "addfeat", "memory") @@ -1101,7 +1236,9 @@ def testLabelBackgroundSymbol(self): background = QgsTextBackgroundSettings() background.setEnabled(True) background.setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) - fill_symbol = QgsFillSymbol.createSimple({'color': '#00ffff', 'outline_color': '#00ff00', 'outline_width': 2}) + fill_symbol = QgsFillSymbol.createSimple( + {"color": "#00ffff", "outline_color": "#00ff00", "outline_width": 2} + ) background.setFillSymbol(fill_symbol) format = settings.format() format.setBackground(background) @@ -1112,7 +1249,7 @@ def testLabelBackgroundSymbol(self): ts = self.getTextSymbolizer(root, 1, 0) graphic = self.assertElement(ts, "se:Graphic", 0) - self.assertWellKnownMark(graphic, 0, 'square', '#00ffff', '#00ff00', 7) + self.assertWellKnownMark(graphic, 0, "square", "#00ffff", "#00ff00", 7) def testRuleBasedLabels(self): layer = QgsVectorLayer("Point", "addfeat", "memory") @@ -1124,11 +1261,11 @@ def testRuleBasedLabels(self): # three rules, one with the point symbol, one with the first rule based label, # one with the second rule based label rule1 = self.getRule(root, 0) - self.assertElement(rule1, 'se:PointSymbolizer', 0) + self.assertElement(rule1, "se:PointSymbolizer", 0) rule2 = self.getRule(root, 1) - self.assertScaleDenominator(root, '100000', '10000000', 1) - tsRule2 = self.assertElement(rule2, 'se:TextSymbolizer', 0) + self.assertScaleDenominator(root, "100000", "10000000", 1) + tsRule2 = self.assertElement(rule2, "se:TextSymbolizer", 0) gt = rule2.elementsByTagName("Filter").item(0).firstChild() self.assertEqual("ogc:PropertyIsGreaterThan", gt.nodeName()) gtProperty = gt.toElement().firstChild() @@ -1138,7 +1275,7 @@ def testRuleBasedLabels(self): self.assertEqual("1000000", gtValue.toElement().text()) rule3 = self.getRule(root, 2) - tsRule3 = self.assertElement(rule3, 'se:TextSymbolizer', 0) + tsRule3 = self.assertElement(rule3, "se:TextSymbolizer", 0) lt = rule3.elementsByTagName("Filter").item(0).firstChild() self.assertEqual("ogc:PropertyIsLessThan", lt.nodeName()) ltProperty = lt.toElement().firstChild() @@ -1154,8 +1291,15 @@ def testRuleBasedLabels(self): xml2 = dom.toString() self.assertEqual(xml1, xml2) - def updateLinePlacementProperties(self, layer, linePlacement, distance, repeat, maxAngleInternal=25, - maxAngleExternal=-25): + def updateLinePlacementProperties( + self, + layer, + linePlacement, + distance, + repeat, + maxAngleInternal=25, + maxAngleExternal=-25, + ): settings = layer.labeling().settings() settings.placement = linePlacement settings.dist = distance @@ -1205,7 +1349,9 @@ def setLabelBufferSettings(self, layer, buffer): settings.setFormat(format) layer.setLabeling(QgsVectorLayerSimpleLabeling(settings)) - def updateLayerLabelingFontStyle(self, layer, bold, italic, underline=False, strikeout=False): + def updateLayerLabelingFontStyle( + self, layer, bold, italic, underline=False, strikeout=False + ): settings = layer.labeling().settings() format = settings.format() font = format.font() @@ -1226,7 +1372,9 @@ def updateLayerLabelingUnit(self, layer, unit): def loadStyleWithCustomProperties(self, layer, qmlFileName): # load the style, only vector symbology - path = QDir.toNativeSeparators(f'{unitTestDataPath()}/symbol_layer/{qmlFileName}.qml') + path = QDir.toNativeSeparators( + f"{unitTestDataPath()}/symbol_layer/{qmlFileName}.qml" + ) # labeling is in custom properties, they need to be loaded separately status = layer.loadNamedStyle(path) @@ -1238,15 +1386,19 @@ def loadStyleWithCustomProperties(self, layer, qmlFileName): flag = layer.readCustomProperties(doc.documentElement()) def assertPointPlacement(self, textSymbolizer): - labelPlacement = self.assertElement(textSymbolizer, 'se:LabelPlacement', 0) - self.assertIsNone(self.assertElement(labelPlacement, 'se:LinePlacement', 0, True)) - pointPlacement = self.assertElement(labelPlacement, 'se:PointPlacement', 0) + labelPlacement = self.assertElement(textSymbolizer, "se:LabelPlacement", 0) + self.assertIsNone( + self.assertElement(labelPlacement, "se:LinePlacement", 0, True) + ) + pointPlacement = self.assertElement(labelPlacement, "se:PointPlacement", 0) return pointPlacement def assertLinePlacement(self, textSymbolizer): - labelPlacement = self.assertElement(textSymbolizer, 'se:LabelPlacement', 0) - self.assertIsNone(self.assertElement(labelPlacement, 'se:PointPlacement', 0, True)) - linePlacement = self.assertElement(labelPlacement, 'se:LinePlacement', 0) + labelPlacement = self.assertElement(textSymbolizer, "se:LabelPlacement", 0) + self.assertIsNone( + self.assertElement(labelPlacement, "se:PointPlacement", 0, True) + ) + linePlacement = self.assertElement(labelPlacement, "se:LinePlacement", 0) return linePlacement def assertElement(self, container, elementName, index, allowMissing=False): @@ -1255,20 +1407,30 @@ def assertElement(self, container, elementName, index, allowMissing=False): if allowMissing: return None else: - self.fail('Expected to find at least ' + str( - index + 1) + ' ' + elementName + ' in ' + container.nodeName() + ' but found ' + str(list.size())) + self.fail( + "Expected to find at least " + + str(index + 1) + + " " + + elementName + + " in " + + container.nodeName() + + " but found " + + str(list.size()) + ) node = list.item(index) - self.assertTrue(node.isElement(), 'Found node but it''s not an element') + self.assertTrue(node.isElement(), "Found node but it" "s not an element") return node.toElement() def getRule(self, root, ruleIndex): - rule = self.assertElement(root, 'se:Rule', ruleIndex) + rule = self.assertElement(root, "se:Rule", ruleIndex) return rule def getTextSymbolizer(self, root, ruleIndex, textSymbolizerIndex): - rule = self.assertElement(root, 'se:Rule', ruleIndex) - textSymbolizer = self.assertElement(rule, 'se:TextSymbolizer', textSymbolizerIndex) + rule = self.assertElement(root, "se:Rule", ruleIndex) + textSymbolizer = self.assertElement( + rule, "se:TextSymbolizer", textSymbolizerIndex + ) return textSymbolizer def assertPropertyName(self, root, containerProperty, expectedAttributeName): @@ -1280,187 +1442,232 @@ def assertSvgParameter(self, container, expectedName, allowMissing=False): list = container.elementsByTagName("se:SvgParameter") for i in range(0, list.size()): item = list.item(i) - if item.isElement and item.isElement() and item.toElement().attribute('name') == expectedName: + if ( + item.isElement + and item.isElement() + and item.toElement().attribute("name") == expectedName + ): return item.toElement() if allowMissing: return None else: - self.fail('Could not find a se:SvgParameter named ' + expectedName + ' in ' + container.nodeName()) + self.fail( + "Could not find a se:SvgParameter named " + + expectedName + + " in " + + container.nodeName() + ) def assertVendorOption(self, container, expectedName, allowMissing=False): list = container.elementsByTagName("se:VendorOption") for i in range(0, list.size()): item = list.item(i) - if item.isElement and item.isElement() and item.toElement().attribute('name') == expectedName: + if ( + item.isElement + and item.isElement() + and item.toElement().attribute("name") == expectedName + ): return item.toElement() if allowMissing: return None else: - self.fail('Could not find a se:VendorOption named ' + expectedName + ' in ' + container.nodeName()) + self.fail( + "Could not find a se:VendorOption named " + + expectedName + + " in " + + container.nodeName() + ) def testRuleBaseEmptyFilter(self): layer = QgsVectorLayer("Point", "addfeat", "memory") - mFilePath = QDir.toNativeSeparators(f"{unitTestDataPath()}/symbol_layer/categorizedEmptyValue.qml") + mFilePath = QDir.toNativeSeparators( + f"{unitTestDataPath()}/symbol_layer/categorizedEmptyValue.qml" + ) status = layer.loadNamedStyle(mFilePath) # NOQA dom, root = self.layerToSld(layer) # print("Rule based, with last rule checking against empty value:" + dom.toString()) # get the third rule - rule = root.elementsByTagName('se:Rule').item(2).toElement() - filter = rule.elementsByTagName('ElseFilter').item(0).toElement() + rule = root.elementsByTagName("se:Rule").item(2).toElement() + filter = rule.elementsByTagName("ElseFilter").item(0).toElement() self.assertEqual("se:ElseFilter", filter.nodeName()) def testDataDefinedAngle(self): l = QgsSimpleMarkerSymbolLayer(Qgis.MarkerShape.Triangle) p = l.dataDefinedProperties() - p.setProperty(QgsSymbolLayer.Property.PropertyAngle, QgsProperty.fromExpression('"field_a"')) + p.setProperty( + QgsSymbolLayer.Property.PropertyAngle, + QgsProperty.fromExpression('"field_a"'), + ) dom = QDomDocument() root = dom.createElement("FakeRoot") dom.appendChild(root) l.toSld(dom, root, dict()) - rot = dom.elementsByTagName('se:Rotation').at(0).firstChild().toElement() - self.assertEqual(rot.tagName(), 'ogc:PropertyName') - self.assertEqual(rot.text(), 'field_a') + rot = dom.elementsByTagName("se:Rotation").at(0).firstChild().toElement() + self.assertEqual(rot.tagName(), "ogc:PropertyName") + self.assertEqual(rot.text(), "field_a") def testSaveSldStyleV2Png(self): """Test SLD export for polygons with PNG tiles""" # Point pattern layer = QgsVectorLayer("Polygon", "addfeat", "memory") - error, ok = layer.loadSldStyle(os.path.join(unitTestDataPath('symbol_layer'), 'QgsPointPatternFillSymbolLayer.sld')) + error, ok = layer.loadSldStyle( + os.path.join( + unitTestDataPath("symbol_layer"), "QgsPointPatternFillSymbolLayer.sld" + ) + ) self.assertTrue(ok) temp_dir = QTemporaryDir() temp_path = temp_dir.path() - sld_path = os.path.join(temp_path, 'export.sld') - context = QgsSldExportContext(Qgis.SldExportOption.Png, Qgis.SldExportVendorExtension.NoVendorExtension, sld_path) + sld_path = os.path.join(temp_path, "export.sld") + context = QgsSldExportContext( + Qgis.SldExportOption.Png, + Qgis.SldExportVendorExtension.NoVendorExtension, + sld_path, + ) message, ok = layer.saveSldStyleV2(context) self.assertTrue(ok) - self.assertTrue(os.path.exists(os.path.join(temp_path, 'export.png'))) + self.assertTrue(os.path.exists(os.path.join(temp_path, "export.png"))) with open(sld_path) as f: - self.assertIn('export.png', f.read()) + self.assertIn("export.png", f.read()) - image = QImage(os.path.join(temp_path, 'export.png')) + image = QImage(os.path.join(temp_path, "export.png")) self.assertTrue(image.hasAlphaChannel()) self.assertEqual(image.height(), 33) self.assertEqual(image.width(), 33) for x, y in ((16, 0), (0, 16), (16, 16), (32, 16), (16, 32)): - self.assertEqual(image.pixelColor(x, y).name(), '#000000') + self.assertEqual(image.pixelColor(x, y).name(), "#000000") self.assertEqual(image.pixelColor(x, y).alpha(), 0) for x, y in ((0, 0), (0, 32), (32, 0), (32, 32)): - self.assertNotEqual(image.pixelColor(x, y).name(), '#000000') + self.assertNotEqual(image.pixelColor(x, y).name(), "#000000") self.assertGreater(image.pixelColor(x, y).alpha(), 0) # Line pattern - error, ok = layer.loadSldStyle(os.path.join(unitTestDataPath('symbol_layer'), 'QgsLinePatternFillSymbolLayer.sld')) + error, ok = layer.loadSldStyle( + os.path.join( + unitTestDataPath("symbol_layer"), "QgsLinePatternFillSymbolLayer.sld" + ) + ) self.assertTrue(ok) temp_dir = QTemporaryDir() temp_path = temp_dir.path() - sld_path = os.path.join(temp_path, 'export.sld') - context = QgsSldExportContext(Qgis.SldExportOption.Png, Qgis.SldExportVendorExtension.NoVendorExtension, sld_path) + sld_path = os.path.join(temp_path, "export.sld") + context = QgsSldExportContext( + Qgis.SldExportOption.Png, + Qgis.SldExportVendorExtension.NoVendorExtension, + sld_path, + ) message, ok = layer.saveSldStyleV2(context) self.assertTrue(ok) - self.assertTrue(os.path.exists(os.path.join(temp_path, 'export.png'))) + self.assertTrue(os.path.exists(os.path.join(temp_path, "export.png"))) with open(sld_path) as f: - self.assertIn('export.png', f.read()) + self.assertIn("export.png", f.read()) - image = QImage(os.path.join(temp_path, 'export.png')) + image = QImage(os.path.join(temp_path, "export.png")) self.assertTrue(image.hasAlphaChannel()) self.assertEqual(image.height(), 7) self.assertEqual(image.width(), 4) for x, y in ((0, 0), (3, 3), (3, 3), (0, 6)): - self.assertEqual(image.pixelColor(x, y).name(), '#000000') + self.assertEqual(image.pixelColor(x, y).name(), "#000000") self.assertEqual(image.pixelColor(x, y).alpha(), 0) for x, y in ((2, 0), (0, 3), (3, 6)): - self.assertNotEqual(image.pixelColor(x, y).name(), '#000000') + self.assertNotEqual(image.pixelColor(x, y).name(), "#000000") self.assertGreater(image.pixelColor(x, y).alpha(), 0) def assertScaleDenominator(self, root, expectedMinScale, expectedMaxScale, index=0): - rule = root.elementsByTagName('se:Rule').item(index).toElement() + rule = root.elementsByTagName("se:Rule").item(index).toElement() if expectedMinScale: - minScale = rule.elementsByTagName('se:MinScaleDenominator').item(0) + minScale = rule.elementsByTagName("se:MinScaleDenominator").item(0) self.assertEqual(expectedMinScale, minScale.firstChild().nodeValue()) else: - self.assertEqual(0, root.elementsByTagName('se:MinScaleDenominator').size()) + self.assertEqual(0, root.elementsByTagName("se:MinScaleDenominator").size()) if expectedMaxScale: - maxScale = rule.elementsByTagName('se:MaxScaleDenominator').item(0) + maxScale = rule.elementsByTagName("se:MaxScaleDenominator").item(0) self.assertEqual(expectedMaxScale, maxScale.firstChild().nodeValue()) else: - self.assertEqual(0, root.elementsByTagName('se:MaxScaleDenominator').size()) + self.assertEqual(0, root.elementsByTagName("se:MaxScaleDenominator").size()) def assertDashPattern(self, root, svgParameterIdx, expectedPattern): - strokeWidth = root.elementsByTagName( - 'se:SvgParameter').item(svgParameterIdx) - svgParameterName = strokeWidth.attributes().namedItem('name') + strokeWidth = root.elementsByTagName("se:SvgParameter").item(svgParameterIdx) + svgParameterName = strokeWidth.attributes().namedItem("name") self.assertEqual("stroke-dasharray", svgParameterName.nodeValue()) - self.assertEqual( - expectedPattern, strokeWidth.firstChild().nodeValue()) + self.assertEqual(expectedPattern, strokeWidth.firstChild().nodeValue()) def assertStaticGap(self, root, expectedValue): # Check the rotation element is a literal, not a - rotation = root.elementsByTagName('se:Gap').item(0) + rotation = root.elementsByTagName("se:Gap").item(0) literal = rotation.firstChild() self.assertEqual("ogc:Literal", literal.nodeName()) self.assertEqual(expectedValue, literal.firstChild().nodeValue()) def assertStaticSize(self, root, expectedValue): - size = root.elementsByTagName('se:Size').item(0) + size = root.elementsByTagName("se:Size").item(0) self.assertEqual(expectedValue, size.firstChild().nodeValue()) def assertExternalGraphic(self, root, index, expectedLink, expectedFormat): - graphic = root.elementsByTagName('se:ExternalGraphic').item(index) - onlineResource = graphic.firstChildElement('se:OnlineResource') - self.assertEqual(expectedLink, onlineResource.attribute('xlink:href')) - format = graphic.firstChildElement('se:Format') + graphic = root.elementsByTagName("se:ExternalGraphic").item(index) + onlineResource = graphic.firstChildElement("se:OnlineResource") + self.assertEqual(expectedLink, onlineResource.attribute("xlink:href")) + format = graphic.firstChildElement("se:Format") self.assertEqual(expectedFormat, format.firstChild().nodeValue()) def assertStaticPerpendicularOffset(self, root, expectedValue): - offset = root.elementsByTagName('se:PerpendicularOffset').item(0) + offset = root.elementsByTagName("se:PerpendicularOffset").item(0) self.assertEqual(expectedValue, offset.firstChild().nodeValue()) - def assertWellKnownMark(self, root, index, expectedName, expectedFill, expectedStroke, expectedStrokeWidth): - mark = root.elementsByTagName('se:Mark').item(index) - wkn = mark.firstChildElement('se:WellKnownName') + def assertWellKnownMark( + self, + root, + index, + expectedName, + expectedFill, + expectedStroke, + expectedStrokeWidth, + ): + mark = root.elementsByTagName("se:Mark").item(index) + wkn = mark.firstChildElement("se:WellKnownName") self.assertEqual(expectedName, wkn.text()) - fill = mark.firstChildElement('se:Fill') + fill = mark.firstChildElement("se:Fill") if expectedFill is None: self.assertTrue(fill.isNull()) else: - parameter = fill.firstChildElement('se:SvgParameter') - self.assertEqual('fill', parameter.attribute('name')) + parameter = fill.firstChildElement("se:SvgParameter") + self.assertEqual("fill", parameter.attribute("name")) self.assertEqual(expectedFill, parameter.text()) - stroke = mark.firstChildElement('se:Stroke') + stroke = mark.firstChildElement("se:Stroke") if expectedStroke is None: self.assertTrue(stroke.isNull()) else: - parameter = stroke.firstChildElement('se:SvgParameter') - self.assertEqual('stroke', parameter.attribute('name')) + parameter = stroke.firstChildElement("se:SvgParameter") + self.assertEqual("stroke", parameter.attribute("name")) self.assertEqual(expectedStroke, parameter.text()) - parameter = parameter.nextSiblingElement('se:SvgParameter') - self.assertEqual('stroke-width', parameter.attribute('name')) + parameter = parameter.nextSiblingElement("se:SvgParameter") + self.assertEqual("stroke-width", parameter.attribute("name")) self.assertEqual(str(expectedStrokeWidth), parameter.text()) def assertStaticRotation(self, root, expectedValue, index=0): # Check the rotation element is a literal, not a - rotation = root.elementsByTagName('se:Rotation').item(index) + rotation = root.elementsByTagName("se:Rotation").item(index) literal = rotation.firstChild() self.assertEqual("ogc:Literal", literal.nodeName()) self.assertEqual(expectedValue, literal.firstChild().nodeValue()) def assertStaticDisplacement(self, root, expectedAnchorX, expectedAnchorY): - displacement = root.elementsByTagName('se:Displacement').item(0) + displacement = root.elementsByTagName("se:Displacement").item(0) self.assertIsNotNone(displacement) dx = displacement.firstChild() self.assertIsNotNone(dx) @@ -1472,7 +1679,7 @@ def assertStaticDisplacement(self, root, expectedAnchorX, expectedAnchorY): self.assertSldNumber(expectedAnchorY, dy.firstChild().nodeValue()) def assertStaticAnchorPoint(self, root, expectedDispX, expectedDispY): - anchor = root.elementsByTagName('se:AnchorPoint').item(0) + anchor = root.elementsByTagName("se:AnchorPoint").item(0) self.assertIsNotNone(anchor) ax = anchor.firstChild() self.assertIsNotNone(ax) @@ -1488,15 +1695,15 @@ def assertSldNumber(self, expected, stringValue): self.assertFloatEquals(expected, value, 0.01) def assertFloatEquals(self, expected, actual, tol): - self.assertLess(abs(expected - actual), tol, 'Expected %d but was %d' % (expected, actual)) + self.assertLess( + abs(expected - actual), tol, "Expected %d but was %d" % (expected, actual) + ) def assertStrokeWidth(self, root, svgParameterIdx, expectedWidth): - strokeWidth = root.elementsByTagName( - 'se:SvgParameter').item(svgParameterIdx) - svgParameterName = strokeWidth.attributes().namedItem('name') + strokeWidth = root.elementsByTagName("se:SvgParameter").item(svgParameterIdx) + svgParameterName = strokeWidth.attributes().namedItem("name") self.assertEqual("stroke-width", svgParameterName.nodeValue()) - self.assertSldNumber( - expectedWidth, strokeWidth.firstChild().nodeValue()) + self.assertSldNumber(expectedWidth, strokeWidth.firstChild().nodeValue()) def symbolToSld(self, symbolLayer): dom = QDomDocument() @@ -1514,5 +1721,5 @@ def layerToSld(self, mapLayer): return dom, root -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssymbollayer_readsld.py b/tests/src/python/test_qgssymbollayer_readsld.py index 34dfdfd3f37f..25920585512d 100644 --- a/tests/src/python/test_qgssymbollayer_readsld.py +++ b/tests/src/python/test_qgssymbollayer_readsld.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Jorge Gustavo Rocha' -__date__ = 'January 2017' -__copyright__ = '(C) 2017, Jorge Gustavo Rocha' +__author__ = "Jorge Gustavo Rocha" +__date__ = "January 2017" +__copyright__ = "(C) 2017, Jorge Gustavo Rocha" import os @@ -55,17 +55,24 @@ def createLayerWithOneLine(): # create a temporary layer # linelayer = iface.addVectorLayer("LineString?crs=epsg:4326&field=gid:int&field=name:string", "simple_line", "memory") - linelayer = QgsVectorLayer("LineString?crs=epsg:4326&field=gid:int&field=name:string", "simple_line", "memory") + linelayer = QgsVectorLayer( + "LineString?crs=epsg:4326&field=gid:int&field=name:string", + "simple_line", + "memory", + ) one = QgsFeature(linelayer.dataProvider().fields(), 0) - one.setAttributes([1, 'one']) - one.setGeometry(QgsGeometry.fromPolylineXY([QgsPointXY(-7, 38), QgsPointXY(-8, 42)])) + one.setAttributes([1, "one"]) + one.setGeometry( + QgsGeometry.fromPolylineXY([QgsPointXY(-7, 38), QgsPointXY(-8, 42)]) + ) linelayer.dataProvider().addFeatures([one]) return linelayer def createLayerWithOnePoint(): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) pr = layer.dataProvider() f = QgsFeature() f.setAttributes(["test", 123]) @@ -80,9 +87,19 @@ def createLayerWithOnePolygon(): assert layer.isValid() f1 = QgsFeature(layer.dataProvider().fields(), 1) f1.setAttribute("pk", 1) - f1.setGeometry(QgsGeometry.fromPolygonXY([[QgsPointXY(2484588, 2425722), QgsPointXY(2482767, 2398853), - QgsPointXY(2520109, 2397715), QgsPointXY(2520792, 2425494), - QgsPointXY(2484588, 2425722)]])) + f1.setGeometry( + QgsGeometry.fromPolygonXY( + [ + [ + QgsPointXY(2484588, 2425722), + QgsPointXY(2482767, 2398853), + QgsPointXY(2520109, 2397715), + QgsPointXY(2520792, 2425494), + QgsPointXY(2484588, 2425722), + ] + ] + ) + ) assert layer.dataProvider().addFeatures([f1]) return layer @@ -99,23 +116,30 @@ def setUp(self): # test VALUE def test_Literal_within_CSSParameter(self): layer = createLayerWithOneLine() - mFilePath = os.path.join(TEST_DATA_DIR, 'symbol_layer/external_sld/simple_streams.sld') + mFilePath = os.path.join( + TEST_DATA_DIR, "symbol_layer/external_sld/simple_streams.sld" + ) layer.loadSldStyle(mFilePath) props = layer.renderer().symbol().symbolLayers()[0].properties() def testLineColor(): # stroke CSSParameter within ogc:Literal # expected color is #003EBA, RGB 0,62,186 - self.assertEqual(layer.renderer().symbol().symbolLayers()[0].color().name(), '#003eba') + self.assertEqual( + layer.renderer().symbol().symbolLayers()[0].color().name(), "#003eba" + ) def testLineWidth(): # stroke-width CSSParameter within ogc:Literal - self.assertEqual(props['line_width'], '2') + self.assertEqual(props["line_width"], "2") def testLineOpacity(): # stroke-opacity CSSParameter NOT within ogc:Literal # stroke-opacity=0.1 - self.assertEqual(props['line_color'], '0,62,186,25,rgb:0,0.24313725490196078,0.72941176470588232,0.09803921568627451') + self.assertEqual( + props["line_color"], + "0,62,186,25,rgb:0,0.24313725490196078,0.72941176470588232,0.09803921568627451", + ) testLineColor() testLineWidth() @@ -134,26 +158,30 @@ def testSimpleMarkerRotation(self): # myShpFile = os.path.join(unitTestDataPath(), 'points.shp') # layer = QgsVectorLayer(myShpFile, 'points', 'ogr') layer = QgsVectorLayer("Point", "addfeat", "memory") - assert (layer.isValid()) + assert layer.isValid() # test if able to read 50.0 - mFilePath = os.path.join(unitTestDataPath(), - 'symbol_layer/external_sld/testSimpleMarkerRotation-directValue.sld') + mFilePath = os.path.join( + unitTestDataPath(), + "symbol_layer/external_sld/testSimpleMarkerRotation-directValue.sld", + ) layer.loadSldStyle(mFilePath) props = layer.renderer().symbol().symbolLayers()[0].properties() - self.assertEqual(props['angle'], '50') + self.assertEqual(props["angle"], "50") # test if able to read 50 - mFilePath = os.path.join(unitTestDataPath(), - 'symbol_layer/external_sld/testSimpleMarkerRotation-ogcLiteral.sld') + mFilePath = os.path.join( + unitTestDataPath(), + "symbol_layer/external_sld/testSimpleMarkerRotation-ogcLiteral.sld", + ) layer.loadSldStyle(mFilePath) props = layer.renderer().symbol().symbolLayers()[0].properties() - self.assertEqual(props['angle'], '50') + self.assertEqual(props["angle"], "50") def testSymbolSizeUom(self): # create a layer layer = createLayerWithOnePoint() # load a sld with marker size without uom attribute (pixels) - sld = 'symbol_layer/QgsSvgMarkerSymbolLayer.sld' + sld = "symbol_layer/QgsSvgMarkerSymbolLayer.sld" mFilePath = os.path.join(TEST_DATA_DIR, sld) layer.loadSldStyle(mFilePath) @@ -166,7 +194,7 @@ def testSymbolSizeUom(self): self.assertEqual(size, sld_size_px) # load a sld with marker size with uom attribute in pixel - sld = 'symbol_layer/QgsSvgMarkerSymbolLayerUomPixel.sld' + sld = "symbol_layer/QgsSvgMarkerSymbolLayerUomPixel.sld" mFilePath = os.path.join(TEST_DATA_DIR, sld) layer.loadSldStyle(mFilePath) @@ -179,7 +207,7 @@ def testSymbolSizeUom(self): self.assertEqual(size, sld_size_px) # load a sld with marker size with uom attribute in meter - sld = 'symbol_layer/QgsSvgMarkerSymbolLayerUomMetre.sld' + sld = "symbol_layer/QgsSvgMarkerSymbolLayerUomMetre.sld" mFilePath = os.path.join(TEST_DATA_DIR, sld) layer.loadSldStyle(mFilePath) @@ -192,7 +220,7 @@ def testSymbolSizeUom(self): self.assertEqual(size, sld_size_meters_at_scale) # load a sld with marker size with uom attribute in foot - sld = 'symbol_layer/QgsSvgMarkerSymbolLayerUomFoot.sld' + sld = "symbol_layer/QgsSvgMarkerSymbolLayerUomFoot.sld" mFilePath = os.path.join(TEST_DATA_DIR, sld) layer.loadSldStyle(mFilePath) @@ -210,7 +238,7 @@ def testSymbolSize(self): player = createLayerWithOnePolygon() # size test for QgsEllipseSymbolLayer - sld = 'symbol_layer/QgsEllipseSymbolLayer.sld' + sld = "symbol_layer/QgsEllipseSymbolLayer.sld" mFilePath = os.path.join(TEST_DATA_DIR, sld) layer.loadSldStyle(mFilePath) @@ -230,7 +258,7 @@ def testSymbolSize(self): # createFromSld not implemented # size test for QgsSimpleFillSymbolLayer - sld = 'symbol_layer/QgsSimpleFillSymbolLayer.sld' + sld = "symbol_layer/QgsSimpleFillSymbolLayer.sld" mFilePath = os.path.join(TEST_DATA_DIR, sld) player.loadSldStyle(mFilePath) @@ -244,7 +272,7 @@ def testSymbolSize(self): self.assertEqual(stroke_width, sld_stroke_width_px) # size test for QgsSVGFillSymbolLayer - sld = 'symbol_layer/QgsSVGFillSymbolLayer.sld' + sld = "symbol_layer/QgsSVGFillSymbolLayer.sld" mFilePath = os.path.join(TEST_DATA_DIR, sld) player.loadSldStyle(mFilePath) @@ -261,7 +289,7 @@ def testSymbolSize(self): self.assertEqual(stroke_width, sld_stroke_width_px) # size test for QgsSvgMarkerSymbolLayer - sld = 'symbol_layer/QgsSvgMarkerSymbolLayer.sld' + sld = "symbol_layer/QgsSvgMarkerSymbolLayer.sld" mFilePath = os.path.join(TEST_DATA_DIR, sld) layer.loadSldStyle(mFilePath) @@ -278,7 +306,7 @@ def testSymbolSize(self): # createFromSld not implemented # size test for QgsLinePatternFillSymbolLayer - sld = 'symbol_layer/QgsLinePatternFillSymbolLayer.sld' + sld = "symbol_layer/QgsLinePatternFillSymbolLayer.sld" mFilePath = os.path.join(TEST_DATA_DIR, sld) player.loadSldStyle(mFilePath) @@ -295,7 +323,7 @@ def testSymbolSize(self): self.assertEqual(stroke_width, sld_stroke_width_px) # test size for QgsSimpleLineSymbolLayer - sld = 'symbol_layer/QgsSimpleLineSymbolLayer.sld' + sld = "symbol_layer/QgsSimpleLineSymbolLayer.sld" mFilePath = os.path.join(TEST_DATA_DIR, sld) player.loadSldStyle(mFilePath) @@ -309,7 +337,7 @@ def testSymbolSize(self): self.assertEqual(stroke_width, sld_stroke_width_px) # test size for QgsMarkerLineSymbolLayer - sld = 'symbol_layer/QgsMarkerLineSymbolLayer.sld' + sld = "symbol_layer/QgsMarkerLineSymbolLayer.sld" mFilePath = os.path.join(TEST_DATA_DIR, sld) player.loadSldStyle(mFilePath) @@ -326,7 +354,7 @@ def testSymbolSize(self): self.assertEqual(offset, sld_offset_px) # test size for QgsSimpleMarkerSymbolLayer - sld = 'symbol_layer/QgsSimpleMarkerSymbolLayer.sld' + sld = "symbol_layer/QgsSimpleMarkerSymbolLayer.sld" mFilePath = os.path.join(TEST_DATA_DIR, sld) layer.loadSldStyle(mFilePath) @@ -345,7 +373,7 @@ def testSymbolSize(self): self.assertEqual(offset.y(), sld_displacement_y_px) # test size for QgsSVGMarkerSymbolLayer - sld = 'symbol_layer/QgsSvgMarkerSymbolLayer.sld' + sld = "symbol_layer/QgsSvgMarkerSymbolLayer.sld" mFilePath = os.path.join(TEST_DATA_DIR, sld) layer.loadSldStyle(mFilePath) @@ -358,7 +386,7 @@ def testSymbolSize(self): self.assertEqual(size, sld_size_px) # test size for QgsFontMarkerSymbolLayer - sld = 'symbol_layer/QgsFontMarkerSymbolLayer.sld' + sld = "symbol_layer/QgsFontMarkerSymbolLayer.sld" mFilePath = os.path.join(TEST_DATA_DIR, sld) layer.loadSldStyle(mFilePath) @@ -371,20 +399,20 @@ def testSymbolSize(self): self.assertEqual(size, sld_size_px) # test percent encoding for QgsFontMarkerSymbolLayer - sld = 'symbol_layer/QgsFontMarkerSymbolLayerPercentEncoding.sld' + sld = "symbol_layer/QgsFontMarkerSymbolLayerPercentEncoding.sld" mFilePath = os.path.join(TEST_DATA_DIR, sld) layer.loadSldStyle(mFilePath) sl = layer.renderer().symbol().symbolLayers()[0] self.assertTrue(isinstance(sl, QgsFontMarkerSymbolLayer)) - self.assertEqual(sl.fontFamily(), 'MapInfo Miscellaneous') + self.assertEqual(sl.fontFamily(), "MapInfo Miscellaneous") def testSymbolSizeAfterReload(self): # create a layer layer = createLayerWithOnePoint() # load a sld with marker size - sld = 'symbol_layer/QgsSvgMarkerSymbolLayer.sld' + sld = "symbol_layer/QgsSvgMarkerSymbolLayer.sld" mFilePath = os.path.join(TEST_DATA_DIR, sld) layer.loadSldStyle(mFilePath) @@ -417,23 +445,30 @@ def testSymbolSizeAfterReload(self): def test_Literal_within_CSSParameter_and_Text(self): layer = createLayerWithOneLine() - mFilePath = os.path.join(TEST_DATA_DIR, 'symbol_layer/external_sld/simple_line_with_text.sld') + mFilePath = os.path.join( + TEST_DATA_DIR, "symbol_layer/external_sld/simple_line_with_text.sld" + ) layer.loadSldStyle(mFilePath) props = layer.renderer().symbol().symbolLayers()[0].properties() def testLineColor(): # stroke SvgParameter within ogc:Literal # expected color is #003EBA, RGB 0,62,186 - self.assertEqual(layer.renderer().symbol().symbolLayers()[0].color().name(), '#003eba') + self.assertEqual( + layer.renderer().symbol().symbolLayers()[0].color().name(), "#003eba" + ) def testLineWidth(): # stroke-width SvgParameter within ogc:Literal - self.assertEqual(props['line_width'], '2') + self.assertEqual(props["line_width"], "2") def testLineOpacity(): # stroke-opacity SvgParameter NOT within ogc:Literal # stroke-opacity=0.1 - self.assertEqual(props['line_color'], '0,62,186,24,rgb:0,0.24313725490196078,0.72941176470588232,0.09411764705882353') + self.assertEqual( + props["line_color"], + "0,62,186,24,rgb:0,0.24313725490196078,0.72941176470588232,0.09411764705882353", + ) testLineColor() testLineWidth() @@ -442,16 +477,16 @@ def testLineOpacity(): from qgis.core import QgsPalLayerSettings self.assertTrue(layer.labelsEnabled()) - self.assertEqual(layer.labeling().type(), 'simple') + self.assertEqual(layer.labeling().type(), "simple") settings = layer.labeling().settings() - self.assertEqual(settings.fieldName, 'name') + self.assertEqual(settings.fieldName, "name") format = settings.format() - self.assertEqual(format.color().name(), '#ff0000') + self.assertEqual(format.color().name(), "#ff0000") font = format.font() - self.assertEqual(font.family(), 'QGIS Vera Sans') + self.assertEqual(font.family(), "QGIS Vera Sans") self.assertTrue(font.bold()) self.assertFalse(font.italic()) @@ -516,7 +551,7 @@ def test_read_circle(self): tmp_dir = QTemporaryDir() tmp_path = tmp_dir.path() - sld_path = os.path.join(tmp_path, 'circle_fill.sld') + sld_path = os.path.join(tmp_path, "circle_fill.sld") layer = createLayerWithOnePolygon() @@ -530,21 +565,35 @@ def _check_layer(layer, yMargin=10, xMargin=15): - QgsSimpleMarkerSymbolLayer (shape) """ layer.loadSldStyle(sld_path) - point_pattern_fill_symbol_layer = layer.renderer().symbol().symbolLayers()[0] + point_pattern_fill_symbol_layer = ( + layer.renderer().symbol().symbolLayers()[0] + ) marker = point_pattern_fill_symbol_layer.subSymbol() self.assertEqual(marker.type(), QgsSymbol.SymbolType.Marker) marker_symbol = marker.symbolLayers()[0] - self.assertEqual(marker_symbol.strokeColor().name(), '#801119') + self.assertEqual(marker_symbol.strokeColor().name(), "#801119") self.assertEqual(marker_symbol.strokeWidth(), 1.5) self.assertEqual(marker_symbol.shape(), Qgis.MarkerShape.Circle) self.assertEqual(marker_symbol.size(), 14) - self.assertEqual(point_pattern_fill_symbol_layer.distanceXUnit(), QgsUnitTypes.RenderUnit.RenderPixels) - self.assertEqual(point_pattern_fill_symbol_layer.distanceYUnit(), QgsUnitTypes.RenderUnit.RenderPixels) - self.assertEqual(point_pattern_fill_symbol_layer.distanceX(), xMargin * 2 + marker_symbol.size()) - self.assertEqual(point_pattern_fill_symbol_layer.distanceY(), yMargin * 2 + marker_symbol.size()) - - with open(sld_path, 'w+') as f: - f.write(sld.format('25')) + self.assertEqual( + point_pattern_fill_symbol_layer.distanceXUnit(), + QgsUnitTypes.RenderUnit.RenderPixels, + ) + self.assertEqual( + point_pattern_fill_symbol_layer.distanceYUnit(), + QgsUnitTypes.RenderUnit.RenderPixels, + ) + self.assertEqual( + point_pattern_fill_symbol_layer.distanceX(), + xMargin * 2 + marker_symbol.size(), + ) + self.assertEqual( + point_pattern_fill_symbol_layer.distanceY(), + yMargin * 2 + marker_symbol.size(), + ) + + with open(sld_path, "w+") as f: + f.write(sld.format("25")) _check_layer(layer, 25, 25) # From: https://docs.geoserver.org/stable/en/user/styling/sld/extensions/margins.html @@ -553,8 +602,8 @@ def _check_layer(layer, yMargin=10, xMargin=15): # top-bottom,right-left (two values, top and bottom sharing the same value) # top-right-bottom-left (single value for all four margins) - for margin in ('10 15', '10 15 10', '10 15 10 15'): - with open(sld_path, 'w+') as f: + for margin in ("10 15", "10 15 10", "10 15 10 15"): + with open(sld_path, "w+") as f: f.write(sld.format(margin)) _check_layer(layer) @@ -568,5 +617,5 @@ def _check_layer(layer, yMargin=10, xMargin=15): _check_layer(layer) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssymbollayerregistry.py b/tests/src/python/test_qgssymbollayerregistry.py index 2cc8fe9f1abb..99d07743c9ee 100644 --- a/tests/src/python/test_qgssymbollayerregistry.py +++ b/tests/src/python/test_qgssymbollayerregistry.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Denis Rouzaud' -__date__ = '26/11/2021' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Denis Rouzaud" +__date__ = "26/11/2021" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.PyQt import sip from qgis.core import ( @@ -25,7 +26,7 @@ class MySuperMarkerMetadata(QgsSymbolLayerAbstractMetadata): def __init__(self): - super().__init__('MySuperMarker', 'My Super Marker', Qgis.SymbolType.Marker) + super().__init__("MySuperMarker", "My Super Marker", Qgis.SymbolType.Marker) def createSymbolLayer(self, map: dict) -> QgsSymbolLayer: return QgsSimpleMarkerSymbolLayer() @@ -55,7 +56,9 @@ def testAddRemoveSymbolLayer(self): # layer already added self.assertFalse(self.registry.addSymbolLayerType(metadata)) # check there is one more layer - self.assertEqual(len(self.registry.symbolLayersForType(Qgis.SymbolType.Marker)), n + 1) + self.assertEqual( + len(self.registry.symbolLayersForType(Qgis.SymbolType.Marker)), n + 1 + ) # remove layer self.assertTrue(self.registry.removeSymbolLayerType(metadata)) # check layer has been deleted @@ -72,9 +75,12 @@ def testOwnership(self): metadata = MySuperMarkerMetadata() self.assertTrue(self.registry.addSymbolLayerType(metadata)) del metadata - self.assertIn(MySuperMarkerMetadata().name(), self.registry.symbolLayersForType(Qgis.SymbolType.Marker)) + self.assertIn( + MySuperMarkerMetadata().name(), + self.registry.symbolLayersForType(Qgis.SymbolType.Marker), + ) self.assertTrue(self.registry.removeSymbolLayerType(MySuperMarkerMetadata())) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgssymbollayerutils.py b/tests/src/python/test_qgssymbollayerutils.py index f969fa52e9a3..b4a1127e291a 100644 --- a/tests/src/python/test_qgssymbollayerutils.py +++ b/tests/src/python/test_qgssymbollayerutils.py @@ -5,21 +5,14 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2016-09' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2016-09" +__copyright__ = "Copyright 2016, The QGIS Project" import math -from qgis.PyQt.QtCore import ( - QDir, - QMimeData, - QPointF, - QSize, - QSizeF, - Qt, - QRectF -) +from qgis.PyQt.QtCore import QDir, QMimeData, QPointF, QSize, QSizeF, Qt, QRectF from qgis.PyQt.QtXml import QDomDocument, QDomElement from qgis.PyQt.QtGui import QColor, QImage, QPolygonF from qgis.core import ( @@ -43,7 +36,7 @@ QgsUnitTypes, QgsVectorLayer, QgsRenderContext, - QgsGeometry + QgsGeometry, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -68,7 +61,7 @@ def testEncodeDecodeSize(self): self.assertEqual(s2, s) # bad string - s2 = QgsSymbolLayerUtils.decodeSize('') + s2 = QgsSymbolLayerUtils.decodeSize("") self.assertEqual(s2, QSizeF(0, 0)) def testToSize(self): @@ -78,7 +71,7 @@ def testToSize(self): s2, ok = QgsSymbolLayerUtils.toSize(4) self.assertFalse(ok) - s2, ok = QgsSymbolLayerUtils.toSize('4') + s2, ok = QgsSymbolLayerUtils.toSize("4") self.assertFalse(ok) # arrays @@ -95,7 +88,7 @@ def testToSize(self): self.assertTrue(ok) self.assertEqual(s2, QSizeF(4, 5)) - s2, ok = QgsSymbolLayerUtils.toSize(['4', '5']) + s2, ok = QgsSymbolLayerUtils.toSize(["4", "5"]) self.assertTrue(ok) self.assertEqual(s2, QSizeF(4, 5)) @@ -112,7 +105,7 @@ def testToSize(self): self.assertEqual(s2, s) # bad string - s2, ok = QgsSymbolLayerUtils.toSize('') + s2, ok = QgsSymbolLayerUtils.toSize("") self.assertFalse(ok) self.assertEqual(s2, QSizeF()) @@ -127,11 +120,14 @@ def testEncodeDecodePoint(self): self.assertEqual(s2, s) # bad string - s2 = QgsSymbolLayerUtils.decodePoint('') + s2 = QgsSymbolLayerUtils.decodePoint("") self.assertEqual(s2, QPointF()) def testEncodeDecodeCoordinateReference(self): - items = {'feature': Qgis.SymbolCoordinateReference.Feature, 'viewport': Qgis.SymbolCoordinateReference.Viewport} + items = { + "feature": Qgis.SymbolCoordinateReference.Feature, + "viewport": Qgis.SymbolCoordinateReference.Viewport, + } for item in items.keys(): encoded = QgsSymbolLayerUtils.encodeCoordinateReference(items[item]) self.assertEqual(item, encoded) @@ -145,7 +141,7 @@ def testToPoint(self): s2, ok = QgsSymbolLayerUtils.toPoint(4) self.assertFalse(ok) - s2, ok = QgsSymbolLayerUtils.toPoint('4') + s2, ok = QgsSymbolLayerUtils.toPoint("4") self.assertFalse(ok) # arrays @@ -162,7 +158,7 @@ def testToPoint(self): self.assertTrue(ok) self.assertEqual(s2, QPointF(4, 5)) - s2, ok = QgsSymbolLayerUtils.toPoint(['4', '5']) + s2, ok = QgsSymbolLayerUtils.toPoint(["4", "5"]) self.assertTrue(ok) self.assertEqual(s2, QPointF(4, 5)) @@ -179,7 +175,7 @@ def testToPoint(self): self.assertEqual(s2, s) # bad string - s2, ok = QgsSymbolLayerUtils.toPoint('') + s2, ok = QgsSymbolLayerUtils.toPoint("") self.assertFalse(ok) self.assertEqual(s2, QPointF()) @@ -187,25 +183,25 @@ def testDecodeArrowHeadType(self): type, ok = QgsSymbolLayerUtils.decodeArrowHeadType(0) self.assertTrue(ok) self.assertEqual(type, QgsArrowSymbolLayer.HeadType.HeadSingle) - type, ok = QgsSymbolLayerUtils.decodeArrowHeadType('single') + type, ok = QgsSymbolLayerUtils.decodeArrowHeadType("single") self.assertTrue(ok) self.assertEqual(type, QgsArrowSymbolLayer.HeadType.HeadSingle) - type, ok = QgsSymbolLayerUtils.decodeArrowHeadType(' SINGLE ') + type, ok = QgsSymbolLayerUtils.decodeArrowHeadType(" SINGLE ") self.assertTrue(ok) self.assertEqual(type, QgsArrowSymbolLayer.HeadType.HeadSingle) type, ok = QgsSymbolLayerUtils.decodeArrowHeadType(1) self.assertTrue(ok) self.assertEqual(type, QgsArrowSymbolLayer.HeadType.HeadReversed) - type, ok = QgsSymbolLayerUtils.decodeArrowHeadType('reversed') + type, ok = QgsSymbolLayerUtils.decodeArrowHeadType("reversed") self.assertTrue(ok) self.assertEqual(type, QgsArrowSymbolLayer.HeadType.HeadReversed) type, ok = QgsSymbolLayerUtils.decodeArrowHeadType(2) self.assertTrue(ok) self.assertEqual(type, QgsArrowSymbolLayer.HeadType.HeadDouble) - type, ok = QgsSymbolLayerUtils.decodeArrowHeadType('double') + type, ok = QgsSymbolLayerUtils.decodeArrowHeadType("double") self.assertTrue(ok) self.assertEqual(type, QgsArrowSymbolLayer.HeadType.HeadDouble) - type, ok = QgsSymbolLayerUtils.decodeArrowHeadType('xxxxx') + type, ok = QgsSymbolLayerUtils.decodeArrowHeadType("xxxxx") self.assertFalse(ok) type, ok = QgsSymbolLayerUtils.decodeArrowHeadType(34) self.assertFalse(ok) @@ -214,25 +210,25 @@ def testDecodeArrowType(self): type, ok = QgsSymbolLayerUtils.decodeArrowType(0) self.assertTrue(ok) self.assertEqual(type, QgsArrowSymbolLayer.ArrowType.ArrowPlain) - type, ok = QgsSymbolLayerUtils.decodeArrowType('plain') + type, ok = QgsSymbolLayerUtils.decodeArrowType("plain") self.assertTrue(ok) self.assertEqual(type, QgsArrowSymbolLayer.ArrowType.ArrowPlain) - type, ok = QgsSymbolLayerUtils.decodeArrowType(' PLAIN ') + type, ok = QgsSymbolLayerUtils.decodeArrowType(" PLAIN ") self.assertTrue(ok) self.assertEqual(type, QgsArrowSymbolLayer.ArrowType.ArrowPlain) type, ok = QgsSymbolLayerUtils.decodeArrowType(1) self.assertTrue(ok) self.assertEqual(type, QgsArrowSymbolLayer.ArrowType.ArrowLeftHalf) - type, ok = QgsSymbolLayerUtils.decodeArrowType('lefthalf') + type, ok = QgsSymbolLayerUtils.decodeArrowType("lefthalf") self.assertTrue(ok) self.assertEqual(type, QgsArrowSymbolLayer.ArrowType.ArrowLeftHalf) type, ok = QgsSymbolLayerUtils.decodeArrowType(2) self.assertTrue(ok) self.assertEqual(type, QgsArrowSymbolLayer.ArrowType.ArrowRightHalf) - type, ok = QgsSymbolLayerUtils.decodeArrowType('righthalf') + type, ok = QgsSymbolLayerUtils.decodeArrowType("righthalf") self.assertTrue(ok) self.assertEqual(type, QgsArrowSymbolLayer.ArrowType.ArrowRightHalf) - type, ok = QgsSymbolLayerUtils.decodeArrowType('xxxxx') + type, ok = QgsSymbolLayerUtils.decodeArrowType("xxxxx") self.assertFalse(ok) type, ok = QgsSymbolLayerUtils.decodeArrowType(34) self.assertFalse(ok) @@ -241,50 +237,125 @@ def test_decode_marker_clip(self): """ Test decode marker clip """ - self.assertEqual(QgsSymbolLayerUtils.decodeMarkerClipMode(''), (Qgis.MarkerClipMode.Shape, False)) - self.assertEqual(QgsSymbolLayerUtils.decodeMarkerClipMode('xxx'), (Qgis.MarkerClipMode.Shape, False)) - self.assertEqual(QgsSymbolLayerUtils.decodeMarkerClipMode(' no '), (Qgis.MarkerClipMode.NoClipping, True)) - self.assertEqual(QgsSymbolLayerUtils.decodeMarkerClipMode(' NO '), (Qgis.MarkerClipMode.NoClipping, True)) - self.assertEqual(QgsSymbolLayerUtils.decodeMarkerClipMode(' shape '), (Qgis.MarkerClipMode.Shape, True)) - self.assertEqual(QgsSymbolLayerUtils.decodeMarkerClipMode(' Shape '), (Qgis.MarkerClipMode.Shape, True)) - self.assertEqual(QgsSymbolLayerUtils.decodeMarkerClipMode(' centroid_within '), (Qgis.MarkerClipMode.CentroidWithin, True)) - self.assertEqual(QgsSymbolLayerUtils.decodeMarkerClipMode(' Centroid_Within '), - (Qgis.MarkerClipMode.CentroidWithin, True)) - self.assertEqual(QgsSymbolLayerUtils.decodeMarkerClipMode(' completely_within '), - (Qgis.MarkerClipMode.CompletelyWithin, True)) - self.assertEqual(QgsSymbolLayerUtils.decodeMarkerClipMode(' Completely_Within '), - (Qgis.MarkerClipMode.CompletelyWithin, True)) + self.assertEqual( + QgsSymbolLayerUtils.decodeMarkerClipMode(""), + (Qgis.MarkerClipMode.Shape, False), + ) + self.assertEqual( + QgsSymbolLayerUtils.decodeMarkerClipMode("xxx"), + (Qgis.MarkerClipMode.Shape, False), + ) + self.assertEqual( + QgsSymbolLayerUtils.decodeMarkerClipMode(" no "), + (Qgis.MarkerClipMode.NoClipping, True), + ) + self.assertEqual( + QgsSymbolLayerUtils.decodeMarkerClipMode(" NO "), + (Qgis.MarkerClipMode.NoClipping, True), + ) + self.assertEqual( + QgsSymbolLayerUtils.decodeMarkerClipMode(" shape "), + (Qgis.MarkerClipMode.Shape, True), + ) + self.assertEqual( + QgsSymbolLayerUtils.decodeMarkerClipMode(" Shape "), + (Qgis.MarkerClipMode.Shape, True), + ) + self.assertEqual( + QgsSymbolLayerUtils.decodeMarkerClipMode(" centroid_within "), + (Qgis.MarkerClipMode.CentroidWithin, True), + ) + self.assertEqual( + QgsSymbolLayerUtils.decodeMarkerClipMode(" Centroid_Within "), + (Qgis.MarkerClipMode.CentroidWithin, True), + ) + self.assertEqual( + QgsSymbolLayerUtils.decodeMarkerClipMode(" completely_within "), + (Qgis.MarkerClipMode.CompletelyWithin, True), + ) + self.assertEqual( + QgsSymbolLayerUtils.decodeMarkerClipMode(" Completely_Within "), + (Qgis.MarkerClipMode.CompletelyWithin, True), + ) def test_encode_marker_clip(self): """ Test encode marker clip """ - self.assertEqual(QgsSymbolLayerUtils.encodeMarkerClipMode(Qgis.MarkerClipMode.Shape), 'shape') - self.assertEqual(QgsSymbolLayerUtils.encodeMarkerClipMode(Qgis.MarkerClipMode.NoClipping), 'no') - self.assertEqual(QgsSymbolLayerUtils.encodeMarkerClipMode(Qgis.MarkerClipMode.CentroidWithin), 'centroid_within') - self.assertEqual(QgsSymbolLayerUtils.encodeMarkerClipMode(Qgis.MarkerClipMode.CompletelyWithin), 'completely_within') + self.assertEqual( + QgsSymbolLayerUtils.encodeMarkerClipMode(Qgis.MarkerClipMode.Shape), "shape" + ) + self.assertEqual( + QgsSymbolLayerUtils.encodeMarkerClipMode(Qgis.MarkerClipMode.NoClipping), + "no", + ) + self.assertEqual( + QgsSymbolLayerUtils.encodeMarkerClipMode( + Qgis.MarkerClipMode.CentroidWithin + ), + "centroid_within", + ) + self.assertEqual( + QgsSymbolLayerUtils.encodeMarkerClipMode( + Qgis.MarkerClipMode.CompletelyWithin + ), + "completely_within", + ) def test_decode_line_clip(self): """ Test decode line clip """ - self.assertEqual(QgsSymbolLayerUtils.decodeLineClipMode(''), (Qgis.LineClipMode.ClipPainterOnly, False)) - self.assertEqual(QgsSymbolLayerUtils.decodeLineClipMode('xxx'), (Qgis.LineClipMode.ClipPainterOnly, False)) - self.assertEqual(QgsSymbolLayerUtils.decodeLineClipMode(' no '), (Qgis.LineClipMode.NoClipping, True)) - self.assertEqual(QgsSymbolLayerUtils.decodeLineClipMode(' NO '), (Qgis.LineClipMode.NoClipping, True)) - self.assertEqual(QgsSymbolLayerUtils.decodeLineClipMode(' during_render '), (Qgis.LineClipMode.ClipPainterOnly, True)) - self.assertEqual(QgsSymbolLayerUtils.decodeLineClipMode(' DURING_Render '), (Qgis.LineClipMode.ClipPainterOnly, True)) - self.assertEqual(QgsSymbolLayerUtils.decodeLineClipMode(' before_render '), (Qgis.LineClipMode.ClipToIntersection, True)) - self.assertEqual(QgsSymbolLayerUtils.decodeLineClipMode(' BEFORE_REnder '), - (Qgis.LineClipMode.ClipToIntersection, True)) + self.assertEqual( + QgsSymbolLayerUtils.decodeLineClipMode(""), + (Qgis.LineClipMode.ClipPainterOnly, False), + ) + self.assertEqual( + QgsSymbolLayerUtils.decodeLineClipMode("xxx"), + (Qgis.LineClipMode.ClipPainterOnly, False), + ) + self.assertEqual( + QgsSymbolLayerUtils.decodeLineClipMode(" no "), + (Qgis.LineClipMode.NoClipping, True), + ) + self.assertEqual( + QgsSymbolLayerUtils.decodeLineClipMode(" NO "), + (Qgis.LineClipMode.NoClipping, True), + ) + self.assertEqual( + QgsSymbolLayerUtils.decodeLineClipMode(" during_render "), + (Qgis.LineClipMode.ClipPainterOnly, True), + ) + self.assertEqual( + QgsSymbolLayerUtils.decodeLineClipMode(" DURING_Render "), + (Qgis.LineClipMode.ClipPainterOnly, True), + ) + self.assertEqual( + QgsSymbolLayerUtils.decodeLineClipMode(" before_render "), + (Qgis.LineClipMode.ClipToIntersection, True), + ) + self.assertEqual( + QgsSymbolLayerUtils.decodeLineClipMode(" BEFORE_REnder "), + (Qgis.LineClipMode.ClipToIntersection, True), + ) def test_encode_line_clip(self): """ Test encode line clip """ - self.assertEqual(QgsSymbolLayerUtils.encodeLineClipMode(Qgis.LineClipMode.ClipPainterOnly), 'during_render') - self.assertEqual(QgsSymbolLayerUtils.encodeLineClipMode(Qgis.LineClipMode.NoClipping), 'no') - self.assertEqual(QgsSymbolLayerUtils.encodeLineClipMode(Qgis.LineClipMode.ClipToIntersection), 'before_render') + self.assertEqual( + QgsSymbolLayerUtils.encodeLineClipMode(Qgis.LineClipMode.ClipPainterOnly), + "during_render", + ) + self.assertEqual( + QgsSymbolLayerUtils.encodeLineClipMode(Qgis.LineClipMode.NoClipping), "no" + ) + self.assertEqual( + QgsSymbolLayerUtils.encodeLineClipMode( + Qgis.LineClipMode.ClipToIntersection + ), + "before_render", + ) def testSymbolToFromMimeData(self): """ @@ -307,18 +378,28 @@ def testEncodeSldUom(self): # millimeter encode = None - encode = QgsSymbolLayerUtils.encodeSldUom(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTupleEqual(encode, ('', 3.571428571428571)) + encode = QgsSymbolLayerUtils.encodeSldUom( + QgsUnitTypes.RenderUnit.RenderMillimeters + ) + self.assertTupleEqual(encode, ("", 3.571428571428571)) # mapunits encode = None - encode = QgsSymbolLayerUtils.encodeSldUom(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTupleEqual(encode, ('http://www.opengeospatial.org/se/units/metre', 0.001)) + encode = QgsSymbolLayerUtils.encodeSldUom( + QgsUnitTypes.RenderUnit.RenderMapUnits + ) + self.assertTupleEqual( + encode, ("http://www.opengeospatial.org/se/units/metre", 0.001) + ) # meters at scale encode = None - encode = QgsSymbolLayerUtils.encodeSldUom(QgsUnitTypes.RenderUnit.RenderMetersInMapUnits) - self.assertTupleEqual(encode, ('http://www.opengeospatial.org/se/units/metre', 1.0)) + encode = QgsSymbolLayerUtils.encodeSldUom( + QgsUnitTypes.RenderUnit.RenderMetersInMapUnits + ) + self.assertTupleEqual( + encode, ("http://www.opengeospatial.org/se/units/metre", 1.0) + ) def testDecodeSldUom(self): """ @@ -327,17 +408,25 @@ def testDecodeSldUom(self): # meter decode = None - decode = QgsSymbolLayerUtils.decodeSldUom("http://www.opengeospatial.org/se/units/metre") + decode = QgsSymbolLayerUtils.decodeSldUom( + "http://www.opengeospatial.org/se/units/metre" + ) self.assertEqual(decode, (QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, 1.0)) # foot decode = None - decode = QgsSymbolLayerUtils.decodeSldUom("http://www.opengeospatial.org/se/units/foot") - self.assertEqual(decode, (QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, 0.3048)) + decode = QgsSymbolLayerUtils.decodeSldUom( + "http://www.opengeospatial.org/se/units/foot" + ) + self.assertEqual( + decode, (QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, 0.3048) + ) # pixel decode = None - decode = QgsSymbolLayerUtils.decodeSldUom("http://www.opengeospatial.org/se/units/pixel") + decode = QgsSymbolLayerUtils.decodeSldUom( + "http://www.opengeospatial.org/se/units/pixel" + ) self.assertEqual(decode, (QgsUnitTypes.RenderUnit.RenderPixels, 1.0)) def testPolylineLength(self): @@ -346,10 +435,23 @@ def testPolylineLength(self): """ self.assertEqual(QgsSymbolLayerUtils.polylineLength(QPolygonF()), 0.0) self.assertEqual( - QgsSymbolLayerUtils.polylineLength(QPolygonF([QPointF(11, 12), QPointF(11, 12)])), 0.0) + QgsSymbolLayerUtils.polylineLength( + QPolygonF([QPointF(11, 12), QPointF(11, 12)]) + ), + 0.0, + ) + self.assertEqual( + QgsSymbolLayerUtils.polylineLength( + QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(11, 12)]) + ), + 10.0, + ) self.assertEqual( - QgsSymbolLayerUtils.polylineLength(QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(11, 12)])), 10.0) - self.assertEqual(QgsSymbolLayerUtils.polylineLength(QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)])), 110.0) + QgsSymbolLayerUtils.polylineLength( + QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]) + ), + 110.0, + ) def testPolylineSubstring(self): res = QgsSymbolLayerUtils.polylineSubstring(QPolygonF(), 1, 2) # no crash @@ -364,72 +466,115 @@ def testPolylineSubstring(self): res = QgsSymbolLayerUtils.polylineSubstring(QPolygonF(), -1, -2) # no crash self.assertFalse(res) - res = QgsSymbolLayerUtils.polylineSubstring(QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), 0, - -110) + res = QgsSymbolLayerUtils.polylineSubstring( + QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), 0, -110 + ) self.assertEqual([p for p in res], []) - res = QgsSymbolLayerUtils.polylineSubstring(QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), 0, - 110) - self.assertEqual([p for p in res], [QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]) + res = QgsSymbolLayerUtils.polylineSubstring( + QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), 0, 110 + ) + self.assertEqual( + [p for p in res], [QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)] + ) - res = QgsSymbolLayerUtils.polylineSubstring(QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), -1, - -1000) + res = QgsSymbolLayerUtils.polylineSubstring( + QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), -1, -1000 + ) self.assertFalse([p for p in res]) - res = QgsSymbolLayerUtils.polylineSubstring(QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), 1, - -1000) + res = QgsSymbolLayerUtils.polylineSubstring( + QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), 1, -1000 + ) self.assertFalse([p for p in res]) - res = QgsSymbolLayerUtils.polylineSubstring(QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), -1, - 1000) + res = QgsSymbolLayerUtils.polylineSubstring( + QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), -1, 1000 + ) self.assertEqual([p for p in res], [QPointF(110.0, 12.0), QPointF(111.0, 12.0)]) - res = QgsSymbolLayerUtils.polylineSubstring(QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), - 100000, -10000) + res = QgsSymbolLayerUtils.polylineSubstring( + QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), + 100000, + -10000, + ) self.assertFalse([p for p in res]) - res = QgsSymbolLayerUtils.polylineSubstring(QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), 1, - -109) + res = QgsSymbolLayerUtils.polylineSubstring( + QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), 1, -109 + ) self.assertEqual([p for p in res], []) - res = QgsSymbolLayerUtils.polylineSubstring(QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), 1, - 109) - self.assertEqual([p for p in res], [QPointF(11.0, 3.0), QPointF(11.0, 12.0), QPointF(110.0, 12.0)]) + res = QgsSymbolLayerUtils.polylineSubstring( + QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), 1, 109 + ) + self.assertEqual( + [p for p in res], + [QPointF(11.0, 3.0), QPointF(11.0, 12.0), QPointF(110.0, 12.0)], + ) - res = QgsSymbolLayerUtils.polylineSubstring(QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), - -109, 109) - self.assertEqual([p for p in res], [QPointF(11.0, 3.0), QPointF(11.0, 12.0), QPointF(110.0, 12.0)]) + res = QgsSymbolLayerUtils.polylineSubstring( + QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), -109, 109 + ) + self.assertEqual( + [p for p in res], + [QPointF(11.0, 3.0), QPointF(11.0, 12.0), QPointF(110.0, 12.0)], + ) - res = QgsSymbolLayerUtils.polylineSubstring(QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), 1, - -1000) + res = QgsSymbolLayerUtils.polylineSubstring( + QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), 1, -1000 + ) self.assertEqual([p for p in res], []) - res = QgsSymbolLayerUtils.polylineSubstring(QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), 1, - 10) + res = QgsSymbolLayerUtils.polylineSubstring( + QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), 1, 10 + ) self.assertEqual([p for p in res], [QPointF(11, 3), QPointF(11, 12)]) - res = QgsSymbolLayerUtils.polylineSubstring(QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), 1, - 0) - self.assertEqual([p for p in res], [QPointF(11, 3), QPointF(11, 12), QPointF(111, 12)]) + res = QgsSymbolLayerUtils.polylineSubstring( + QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), 1, 0 + ) + self.assertEqual( + [p for p in res], [QPointF(11, 3), QPointF(11, 12), QPointF(111, 12)] + ) - res = QgsSymbolLayerUtils.polylineSubstring(QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), 1, - -90) - self.assertEqual([p for p in res], [QPointF(11, 3), QPointF(11, 12), QPointF(21, 12)]) + res = QgsSymbolLayerUtils.polylineSubstring( + QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]), 1, -90 + ) + self.assertEqual( + [p for p in res], [QPointF(11, 3), QPointF(11, 12), QPointF(21, 12)] + ) def testAppendPolyline(self): line = QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]) - line2 = QPolygonF([QPointF(111, 12), QPointF(111, 12), QPointF(111, 14), QPointF(111, 15)]) + line2 = QPolygonF( + [QPointF(111, 12), QPointF(111, 12), QPointF(111, 14), QPointF(111, 15)] + ) QgsSymbolLayerUtils.appendPolyline(line, line2) - self.assertEqual([p for p in line], - [QPointF(11.0, 2.0), QPointF(11.0, 12.0), QPointF(111.0, 12.0), QPointF(111.0, 14.0), - QPointF(111.0, 15.0)]) + self.assertEqual( + [p for p in line], + [ + QPointF(11.0, 2.0), + QPointF(11.0, 12.0), + QPointF(111.0, 12.0), + QPointF(111.0, 14.0), + QPointF(111.0, 15.0), + ], + ) line = QPolygonF([QPointF(11, 2), QPointF(11, 12), QPointF(111, 12)]) line2 = QPolygonF([QPointF(111, 14), QPointF(111, 15)]) QgsSymbolLayerUtils.appendPolyline(line, line2) - self.assertEqual([p for p in line], - [QPointF(11.0, 2.0), QPointF(11.0, 12.0), QPointF(111.0, 12.0), QPointF(111.0, 14.0), - QPointF(111.0, 15.0)]) + self.assertEqual( + [p for p in line], + [ + QPointF(11.0, 2.0), + QPointF(11.0, 12.0), + QPointF(111.0, 12.0), + QPointF(111.0, 14.0), + QPointF(111.0, 15.0), + ], + ) def testColorFromMimeData(self): data = QMimeData() @@ -440,7 +585,7 @@ def testColorFromMimeData(self): data.setColorData(QColor(255, 0, 255)) color, has_alpha = QgsSymbolLayerUtils.colorFromMimeData(data) self.assertTrue(color.isValid()) - self.assertEqual(color.name(), '#ff00ff') + self.assertEqual(color.name(), "#ff00ff") # should be true regardless of the actual color's opacity -- a QColor object has innate knowledge of the alpha, # so our input color HAS an alpha of 255 self.assertTrue(has_alpha) @@ -449,53 +594,53 @@ def testColorFromMimeData(self): data.setColorData(QColor(255, 0, 255, 100)) color, has_alpha = QgsSymbolLayerUtils.colorFromMimeData(data) self.assertTrue(color.isValid()) - self.assertEqual(color.name(), '#ff00ff') + self.assertEqual(color.name(), "#ff00ff") self.assertEqual(color.alpha(), 100) self.assertTrue(has_alpha) # text data data = QMimeData() - data.setText('#ff00ff') + data.setText("#ff00ff") color, has_alpha = QgsSymbolLayerUtils.colorFromMimeData(data) self.assertTrue(color.isValid()) - self.assertEqual(color.name(), '#ff00ff') + self.assertEqual(color.name(), "#ff00ff") # should be False -- no alpha was specified self.assertFalse(has_alpha) self.assertEqual(color.alpha(), 255) - data.setText('#ff00ff66') + data.setText("#ff00ff66") color, has_alpha = QgsSymbolLayerUtils.colorFromMimeData(data) self.assertTrue(color.isValid()) - self.assertEqual(color.name(), '#ff00ff') + self.assertEqual(color.name(), "#ff00ff") self.assertTrue(has_alpha) self.assertEqual(color.alpha(), 102) # "#" is optional - data.setText('ff00ff66') + data.setText("ff00ff66") color, has_alpha = QgsSymbolLayerUtils.colorFromMimeData(data) self.assertTrue(color.isValid()) - self.assertEqual(color.name(), '#ff00ff') + self.assertEqual(color.name(), "#ff00ff") self.assertTrue(has_alpha) self.assertEqual(color.alpha(), 102) - data.setText('255,0,255') + data.setText("255,0,255") color, has_alpha = QgsSymbolLayerUtils.colorFromMimeData(data) self.assertTrue(color.isValid()) - self.assertEqual(color.name(), '#ff00ff') + self.assertEqual(color.name(), "#ff00ff") self.assertFalse(has_alpha) self.assertEqual(color.alpha(), 255) - data.setText('255,0,255,0.5') + data.setText("255,0,255,0.5") color, has_alpha = QgsSymbolLayerUtils.colorFromMimeData(data) self.assertTrue(color.isValid()) - self.assertEqual(color.name(), '#ff00ff') + self.assertEqual(color.name(), "#ff00ff") self.assertTrue(has_alpha) self.assertEqual(color.alpha(), 128) - data.setText('rgba(255,0,255,0.5)') + data.setText("rgba(255,0,255,0.5)") color, has_alpha = QgsSymbolLayerUtils.colorFromMimeData(data) self.assertTrue(color.isValid()) - self.assertEqual(color.name(), '#ff00ff') + self.assertEqual(color.name(), "#ff00ff") self.assertTrue(has_alpha) self.assertEqual(color.alpha(), 128) @@ -510,35 +655,57 @@ def testPreviewColorRampHorizontal(self): pix = QgsSymbolLayerUtils.colorRampPreviewPixmap(r, QSize(200, 100)) img = QImage(pix) - self.assertTrue(self.image_check('color_ramp_horizontal', 'color_ramp_horizontal', img)) + self.assertTrue( + self.image_check("color_ramp_horizontal", "color_ramp_horizontal", img) + ) def testPreviewColorRampHorizontalNoCheckboard(self): r = QgsGradientColorRamp(QColor(200, 0, 0, 200), QColor(0, 200, 0, 255)) - pix = QgsSymbolLayerUtils.colorRampPreviewPixmap(r, QSize(200, 100), drawTransparentBackground=False) + pix = QgsSymbolLayerUtils.colorRampPreviewPixmap( + r, QSize(200, 100), drawTransparentBackground=False + ) img = QImage(pix) - self.assertTrue(self.image_check('color_ramp_no_check', 'color_ramp_no_check', img)) + self.assertTrue( + self.image_check("color_ramp_no_check", "color_ramp_no_check", img) + ) def testPreviewColorRampHorizontalFlipped(self): r = QgsGradientColorRamp(QColor(200, 0, 0, 200), QColor(0, 200, 0, 255)) - pix = QgsSymbolLayerUtils.colorRampPreviewPixmap(r, QSize(200, 100), flipDirection=True) + pix = QgsSymbolLayerUtils.colorRampPreviewPixmap( + r, QSize(200, 100), flipDirection=True + ) img = QImage(pix) - self.assertTrue(self.image_check('color_ramp_horizontal_flipped', 'color_ramp_horizontal_flipped', img)) + self.assertTrue( + self.image_check( + "color_ramp_horizontal_flipped", "color_ramp_horizontal_flipped", img + ) + ) def testPreviewColorRampVertical(self): r = QgsGradientColorRamp(QColor(200, 0, 0, 200), QColor(0, 200, 0, 255)) - pix = QgsSymbolLayerUtils.colorRampPreviewPixmap(r, QSize(100, 200), direction=Qt.Orientation.Vertical) + pix = QgsSymbolLayerUtils.colorRampPreviewPixmap( + r, QSize(100, 200), direction=Qt.Orientation.Vertical + ) img = QImage(pix) - self.assertTrue(self.image_check('color_ramp_vertical', 'color_ramp_vertical', img)) + self.assertTrue( + self.image_check("color_ramp_vertical", "color_ramp_vertical", img) + ) def testPreviewColorRampVerticalFlipped(self): r = QgsGradientColorRamp(QColor(200, 0, 0, 200), QColor(0, 200, 0, 255)) - pix = QgsSymbolLayerUtils.colorRampPreviewPixmap(r, QSize(100, 200), direction=Qt.Orientation.Vertical, flipDirection=True) + pix = QgsSymbolLayerUtils.colorRampPreviewPixmap( + r, QSize(100, 200), direction=Qt.Orientation.Vertical, flipDirection=True + ) img = QImage(pix) - self.assertTrue(self.image_check('color_ramp_vertical_flipped', 'color_ramp_vertical_flipped', img)) + self.assertTrue( + self.image_check( + "color_ramp_vertical_flipped", "color_ramp_vertical_flipped", img + ) + ) def testCondenseFillAndOutline(self): """ @@ -547,8 +714,16 @@ def testCondenseFillAndOutline(self): self.assertFalse(QgsSymbolLayerUtils.condenseFillAndOutline(None, None)) # not simple fill or line - self.assertFalse(QgsSymbolLayerUtils.condenseFillAndOutline(QgsShapeburstFillSymbolLayer(), QgsSimpleLineSymbolLayer())) - self.assertFalse(QgsSymbolLayerUtils.condenseFillAndOutline(QgsSimpleFillSymbolLayer(), QgsMarkerLineSymbolLayer())) + self.assertFalse( + QgsSymbolLayerUtils.condenseFillAndOutline( + QgsShapeburstFillSymbolLayer(), QgsSimpleLineSymbolLayer() + ) + ) + self.assertFalse( + QgsSymbolLayerUtils.condenseFillAndOutline( + QgsSimpleFillSymbolLayer(), QgsMarkerLineSymbolLayer() + ) + ) # simple fill/line fill = QgsSimpleFillSymbolLayer() @@ -591,7 +766,9 @@ def testCondenseFillAndOutline(self): self.assertFalse(QgsSymbolLayerUtils.condenseFillAndOutline(fill, line)) line = QgsSimpleLineSymbolLayer() - line.setDataDefinedProperty(QgsSymbolLayer.Property.PropertyTrimEnd, QgsProperty.fromValue(4)) + line.setDataDefinedProperty( + QgsSymbolLayer.Property.PropertyTrimEnd, QgsProperty.fromValue(4) + ) self.assertFalse(QgsSymbolLayerUtils.condenseFillAndOutline(fill, line)) # compatible! @@ -654,74 +831,319 @@ def testTileSize(self): [10, 20, math.pi / 2, 20, 10, math.pi / 2], [10, 20, math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi / 4], [10, 20, math.pi / 6, 36, 72, 0.5880031703261417], # Angle approx - # Second quadrant - [10, 20, math.pi / 2 + math.pi / 6, 72, 36, math.pi / 2 + 0.5880031703261417], # Angle approx - [10, 10, math.pi / 2 + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi / 2 + math.pi / 4], + [ + 10, + 20, + math.pi / 2 + math.pi / 6, + 72, + 36, + math.pi / 2 + 0.5880031703261417, + ], # Angle approx + [ + 10, + 10, + math.pi / 2 + math.pi / 4, + 10 * math.sqrt(2), + 10 * math.sqrt(2), + math.pi / 2 + math.pi / 4, + ], [10, 20, math.pi / 2 + math.pi / 2, 10, 20, math.pi / 2 + math.pi / 2], - [10, 20, math.pi / 2 + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi / 2 + math.pi / 4], - + [ + 10, + 20, + math.pi / 2 + math.pi / 4, + 20 * math.sqrt(2), + 20 * math.sqrt(2), + math.pi / 2 + math.pi / 4, + ], # Third quadrant - [10, 20, math.pi + math.pi / 6, 36, 72, math.pi + 0.5880031703261417], # Angle approx - [10, 10, math.pi + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi + math.pi / 4], + [ + 10, + 20, + math.pi + math.pi / 6, + 36, + 72, + math.pi + 0.5880031703261417, + ], # Angle approx + [ + 10, + 10, + math.pi + math.pi / 4, + 10 * math.sqrt(2), + 10 * math.sqrt(2), + math.pi + math.pi / 4, + ], [10, 20, math.pi + math.pi / 2, 20, 10, math.pi + math.pi / 2], - [10, 20, math.pi + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi + math.pi / 4], - + [ + 10, + 20, + math.pi + math.pi / 4, + 20 * math.sqrt(2), + 20 * math.sqrt(2), + math.pi + math.pi / 4, + ], # Fourth quadrant - [10, 20, math.pi + math.pi / 2 + math.pi / 6, 72, 36, math.pi + math.pi / 2 + 0.5880031703261417], # Angle approx - [10, 10, math.pi + math.pi / 2 + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi + math.pi / 2 + math.pi / 4], - [10, 20, math.pi + math.pi / 2 + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi + math.pi / 2 + math.pi / 4], - + [ + 10, + 20, + math.pi + math.pi / 2 + math.pi / 6, + 72, + 36, + math.pi + math.pi / 2 + 0.5880031703261417, + ], # Angle approx + [ + 10, + 10, + math.pi + math.pi / 2 + math.pi / 4, + 10 * math.sqrt(2), + 10 * math.sqrt(2), + math.pi + math.pi / 2 + math.pi / 4, + ], + [ + 10, + 20, + math.pi + math.pi / 2 + math.pi / 4, + 20 * math.sqrt(2), + 20 * math.sqrt(2), + math.pi + math.pi / 2 + math.pi / 4, + ], # Test out of range angles > 2 PI - # First quadrant - [10, 10, math.pi * 2 + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi / 4], + [ + 10, + 10, + math.pi * 2 + math.pi / 4, + 10 * math.sqrt(2), + 10 * math.sqrt(2), + math.pi / 4, + ], [10, 20, math.pi * 2 + math.pi / 2, 20, 10, math.pi / 2], - [10, 20, math.pi * 2 + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi / 4], - [10, 20, math.pi * 2 + math.pi / 6, 36, 72, 0.5880031703261417], # Angle approx - + [ + 10, + 20, + math.pi * 2 + math.pi / 4, + 20 * math.sqrt(2), + 20 * math.sqrt(2), + math.pi / 4, + ], + [ + 10, + 20, + math.pi * 2 + math.pi / 6, + 36, + 72, + 0.5880031703261417, + ], # Angle approx # Second quadrant - [10, 20, math.pi * 2 + math.pi / 2 + math.pi / 6, 72, 36, math.pi / 2 + 0.5880031703261417], # Angle approx - [10, 10, math.pi * 2 + math.pi / 2 + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi / 2 + math.pi / 4], - [10, 20, math.pi * 2 + math.pi / 2 + math.pi / 2, 10, 20, math.pi / 2 + math.pi / 2], - [10, 20, math.pi * 2 + math.pi / 2 + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi / 2 + math.pi / 4], - + [ + 10, + 20, + math.pi * 2 + math.pi / 2 + math.pi / 6, + 72, + 36, + math.pi / 2 + 0.5880031703261417, + ], # Angle approx + [ + 10, + 10, + math.pi * 2 + math.pi / 2 + math.pi / 4, + 10 * math.sqrt(2), + 10 * math.sqrt(2), + math.pi / 2 + math.pi / 4, + ], + [ + 10, + 20, + math.pi * 2 + math.pi / 2 + math.pi / 2, + 10, + 20, + math.pi / 2 + math.pi / 2, + ], + [ + 10, + 20, + math.pi * 2 + math.pi / 2 + math.pi / 4, + 20 * math.sqrt(2), + 20 * math.sqrt(2), + math.pi / 2 + math.pi / 4, + ], # Third quadrant - [10, 20, math.pi * 2 + math.pi + math.pi / 6, 36, 72, math.pi + 0.5880031703261417], # Angle approx - [10, 10, math.pi * 2 + math.pi + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi + math.pi / 4], - [10, 20, math.pi * 2 + math.pi + math.pi / 2, 20, 10, math.pi + math.pi / 2], - [10, 20, math.pi * 2 + math.pi + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi + math.pi / 4], - + [ + 10, + 20, + math.pi * 2 + math.pi + math.pi / 6, + 36, + 72, + math.pi + 0.5880031703261417, + ], # Angle approx + [ + 10, + 10, + math.pi * 2 + math.pi + math.pi / 4, + 10 * math.sqrt(2), + 10 * math.sqrt(2), + math.pi + math.pi / 4, + ], + [ + 10, + 20, + math.pi * 2 + math.pi + math.pi / 2, + 20, + 10, + math.pi + math.pi / 2, + ], + [ + 10, + 20, + math.pi * 2 + math.pi + math.pi / 4, + 20 * math.sqrt(2), + 20 * math.sqrt(2), + math.pi + math.pi / 4, + ], # Fourth quadrant - [10, 20, math.pi * 2 + math.pi + math.pi / 2 + math.pi / 6, 72, 36, math.pi + math.pi / 2 + 0.5880031703261417], # Angle approx - [10, 10, math.pi * 2 + math.pi + math.pi / 2 + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi + math.pi / 2 + math.pi / 4], - [10, 20, math.pi * 2 + math.pi + math.pi / 2 + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi + math.pi / 2 + math.pi / 4], - + [ + 10, + 20, + math.pi * 2 + math.pi + math.pi / 2 + math.pi / 6, + 72, + 36, + math.pi + math.pi / 2 + 0.5880031703261417, + ], # Angle approx + [ + 10, + 10, + math.pi * 2 + math.pi + math.pi / 2 + math.pi / 4, + 10 * math.sqrt(2), + 10 * math.sqrt(2), + math.pi + math.pi / 2 + math.pi / 4, + ], + [ + 10, + 20, + math.pi * 2 + math.pi + math.pi / 2 + math.pi / 4, + 20 * math.sqrt(2), + 20 * math.sqrt(2), + math.pi + math.pi / 2 + math.pi / 4, + ], # Test out of range angles < 0 - # First quadrant - [10, 10, - math.pi * 2 + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi / 4], - [10, 20, - math.pi * 2 + math.pi / 2, 20, 10, math.pi / 2], - [10, 20, - math.pi * 2 + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi / 4], - [10, 20, - math.pi * 2 + math.pi / 6, 36, 72, 0.5880031703261417], # Angle approx - + [ + 10, + 10, + -math.pi * 2 + math.pi / 4, + 10 * math.sqrt(2), + 10 * math.sqrt(2), + math.pi / 4, + ], + [10, 20, -math.pi * 2 + math.pi / 2, 20, 10, math.pi / 2], + [ + 10, + 20, + -math.pi * 2 + math.pi / 4, + 20 * math.sqrt(2), + 20 * math.sqrt(2), + math.pi / 4, + ], + [ + 10, + 20, + -math.pi * 2 + math.pi / 6, + 36, + 72, + 0.5880031703261417, + ], # Angle approx # Second quadrant - [10, 20, - math.pi * 2 + math.pi / 2 + math.pi / 6, 72, 36, math.pi / 2 + 0.5880031703261417], # Angle approx - [10, 10, - math.pi * 2 + math.pi / 2 + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi / 2 + math.pi / 4], - [10, 20, - math.pi * 2 + math.pi / 2 + math.pi / 2, 10, 20, math.pi / 2 + math.pi / 2], - [10, 20, - math.pi * 2 + math.pi / 2 + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi / 2 + math.pi / 4], - + [ + 10, + 20, + -math.pi * 2 + math.pi / 2 + math.pi / 6, + 72, + 36, + math.pi / 2 + 0.5880031703261417, + ], # Angle approx + [ + 10, + 10, + -math.pi * 2 + math.pi / 2 + math.pi / 4, + 10 * math.sqrt(2), + 10 * math.sqrt(2), + math.pi / 2 + math.pi / 4, + ], + [ + 10, + 20, + -math.pi * 2 + math.pi / 2 + math.pi / 2, + 10, + 20, + math.pi / 2 + math.pi / 2, + ], + [ + 10, + 20, + -math.pi * 2 + math.pi / 2 + math.pi / 4, + 20 * math.sqrt(2), + 20 * math.sqrt(2), + math.pi / 2 + math.pi / 4, + ], # Third quadrant - [10, 20, - math.pi * 2 + math.pi + math.pi / 6, 36, 72, math.pi + 0.5880031703261417], # Angle approx - [10, 10, - math.pi * 2 + math.pi + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi + math.pi / 4], - [10, 20, - math.pi * 2 + math.pi + math.pi / 2, 20, 10, math.pi + math.pi / 2], - [10, 20, - math.pi * 2 + math.pi + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi + math.pi / 4], - + [ + 10, + 20, + -math.pi * 2 + math.pi + math.pi / 6, + 36, + 72, + math.pi + 0.5880031703261417, + ], # Angle approx + [ + 10, + 10, + -math.pi * 2 + math.pi + math.pi / 4, + 10 * math.sqrt(2), + 10 * math.sqrt(2), + math.pi + math.pi / 4, + ], + [ + 10, + 20, + -math.pi * 2 + math.pi + math.pi / 2, + 20, + 10, + math.pi + math.pi / 2, + ], + [ + 10, + 20, + -math.pi * 2 + math.pi + math.pi / 4, + 20 * math.sqrt(2), + 20 * math.sqrt(2), + math.pi + math.pi / 4, + ], # Fourth quadrant - [10, 20, - math.pi * 2 + math.pi + math.pi / 2 + math.pi / 6, 72, 36, math.pi + math.pi / 2 + 0.5880031703261417], # Angle approx - [10, 10, - math.pi * 2 + math.pi + math.pi / 2 + math.pi / 4, 10 * math.sqrt(2), 10 * math.sqrt(2), math.pi + math.pi / 2 + math.pi / 4], - [10, 20, - math.pi * 2 + math.pi + math.pi / 2 + math.pi / 4, 20 * math.sqrt(2), 20 * math.sqrt(2), math.pi + math.pi / 2 + math.pi / 4], - + [ + 10, + 20, + -math.pi * 2 + math.pi + math.pi / 2 + math.pi / 6, + 72, + 36, + math.pi + math.pi / 2 + 0.5880031703261417, + ], # Angle approx + [ + 10, + 10, + -math.pi * 2 + math.pi + math.pi / 2 + math.pi / 4, + 10 * math.sqrt(2), + 10 * math.sqrt(2), + math.pi + math.pi / 2 + math.pi / 4, + ], + [ + 10, + 20, + -math.pi * 2 + math.pi + math.pi / 2 + math.pi / 4, + 20 * math.sqrt(2), + 20 * math.sqrt(2), + math.pi + math.pi / 2 + math.pi / 4, + ], ] for width, height, angle, exp_width, exp_height, exp_angle in test_data: @@ -735,7 +1157,7 @@ def test_clear_symbollayer_ids(self): Test we manage to clear all symbol layer ids on a symbol """ - source = QgsVectorLayer("Polygon?crs=EPSG:4326", 'layer', "memory") + source = QgsVectorLayer("Polygon?crs=EPSG:4326", "layer", "memory") self.assertTrue(source.isValid()) layer = QgsLinePatternFillSymbolLayer() @@ -836,70 +1258,130 @@ def test_collect_symbol_layer_clip_geometries(self): Test logic relating to symbol layer clip geometries. """ rc = QgsRenderContext() - self.assertFalse(QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( - rc, 'x', QRectF(0, 0, 10, 10) - )) - rc.addSymbolLayerClipGeometry('x', - QgsGeometry.fromWkt( - 'Polygon(( 0 0, 1 0 , 1 1 , 0 1, 0 0 ))')) - self.assertFalse(QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( - rc, 'y', QRectF(0, 0, 10, 10) - )) - self.assertCountEqual([g.asWkt() for g in - QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( - rc, 'x', QRectF(0, 0, 10, 10) - )], ['Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))']) - rc.addSymbolLayerClipGeometry('x', QgsGeometry.fromWkt( - 'Polygon(( 20 0, 21 0 , 21 1 , 20 1, 20 0 ))')) - self.assertCountEqual([g.asWkt() for g in - QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( - rc, 'x', QRectF(0, 0, 10, 10) - )], ['Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))']) - self.assertCountEqual([g.asWkt() for g in - QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( - rc, 'x', QRectF(15, 0, 10, 10) - )], - ['Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))']) - self.assertCountEqual([g.asWkt() for g in - QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( - rc, 'x', QRectF(0, 0, 25, 10) - )], ['Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))', - 'Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))']) + self.assertFalse( + QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( + rc, "x", QRectF(0, 0, 10, 10) + ) + ) + rc.addSymbolLayerClipGeometry( + "x", QgsGeometry.fromWkt("Polygon(( 0 0, 1 0 , 1 1 , 0 1, 0 0 ))") + ) + self.assertFalse( + QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( + rc, "y", QRectF(0, 0, 10, 10) + ) + ) + self.assertCountEqual( + [ + g.asWkt() + for g in QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( + rc, "x", QRectF(0, 0, 10, 10) + ) + ], + ["Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))"], + ) + rc.addSymbolLayerClipGeometry( + "x", QgsGeometry.fromWkt("Polygon(( 20 0, 21 0 , 21 1 , 20 1, 20 0 ))") + ) + self.assertCountEqual( + [ + g.asWkt() + for g in QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( + rc, "x", QRectF(0, 0, 10, 10) + ) + ], + ["Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))"], + ) + self.assertCountEqual( + [ + g.asWkt() + for g in QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( + rc, "x", QRectF(15, 0, 10, 10) + ) + ], + ["Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))"], + ) + self.assertCountEqual( + [ + g.asWkt() + for g in QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( + rc, "x", QRectF(0, 0, 25, 10) + ) + ], + [ + "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))", + "Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))", + ], + ) # null rect - self.assertCountEqual([g.asWkt() for g in - QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( - rc, 'x', QRectF() - )], ['Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))', - 'Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))']) - - rc.addSymbolLayerClipGeometry('y', - QgsGeometry.fromWkt( - 'Polygon(( 0 0, 2 0 , 2 1 , 0 1, 0 0 ))')) - self.assertCountEqual([g.asWkt() for g in - QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( - rc, 'x', QRectF(0, 0, 25, 10) - )], ['Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))', - 'Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))']) - self.assertCountEqual([g.asWkt() for g in - QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( - rc, 'y', QRectF(0, 0, 25, 10) - )], ['Polygon ((0 0, 2 0, 2 1, 0 1, 0 0))']) + self.assertCountEqual( + [ + g.asWkt() + for g in QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( + rc, "x", QRectF() + ) + ], + [ + "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))", + "Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))", + ], + ) + + rc.addSymbolLayerClipGeometry( + "y", QgsGeometry.fromWkt("Polygon(( 0 0, 2 0 , 2 1 , 0 1, 0 0 ))") + ) + self.assertCountEqual( + [ + g.asWkt() + for g in QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( + rc, "x", QRectF(0, 0, 25, 10) + ) + ], + [ + "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))", + "Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))", + ], + ) + self.assertCountEqual( + [ + g.asWkt() + for g in QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( + rc, "y", QRectF(0, 0, 25, 10) + ) + ], + ["Polygon ((0 0, 2 0, 2 1, 0 1, 0 0))"], + ) # null rect - self.assertCountEqual([g.asWkt() for g in - QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( - rc, 'x', QRectF() - )], ['Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))', - 'Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))']) - self.assertCountEqual([g.asWkt() for g in - QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( - rc, 'y', QRectF() - )], ['Polygon ((0 0, 2 0, 2 1, 0 1, 0 0))']) + self.assertCountEqual( + [ + g.asWkt() + for g in QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( + rc, "x", QRectF() + ) + ], + [ + "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))", + "Polygon ((20 0, 21 0, 21 1, 20 1, 20 0))", + ], + ) + self.assertCountEqual( + [ + g.asWkt() + for g in QgsSymbolLayerUtils.collectSymbolLayerClipGeometries( + rc, "y", QRectF() + ) + ], + ["Polygon ((0 0, 2 0, 2 1, 0 1, 0 0))"], + ) @staticmethod def polys_to_list(polys): - return [[[[round(p.x(), 3), round(p.y(), 3)] for p in ring] for ring in poly] for poly in polys] + return [ + [[[round(p.x(), 3), round(p.y(), 3)] for p in ring] for ring in poly] + for poly in polys + ] def test_to_qpolygonf(self): """ @@ -907,61 +1389,205 @@ def test_to_qpolygonf(self): """ # points - self.assertEqual(self.polys_to_list(QgsSymbolLayerUtils.toQPolygonF(QgsGeometry.fromWkt('Point( 5 5 )'), Qgis.SymbolType.Marker)), - [[[[0, 0]]]]) - self.assertEqual(self.polys_to_list(QgsSymbolLayerUtils.toQPolygonF(QgsGeometry.fromWkt('Point( 5 5 )'), Qgis.SymbolType.Line)), - []) - self.assertEqual(self.polys_to_list(QgsSymbolLayerUtils.toQPolygonF(QgsGeometry.fromWkt('Point( 5 5 )'), Qgis.SymbolType.Fill)), - []) + self.assertEqual( + self.polys_to_list( + QgsSymbolLayerUtils.toQPolygonF( + QgsGeometry.fromWkt("Point( 5 5 )"), Qgis.SymbolType.Marker + ) + ), + [[[[0, 0]]]], + ) + self.assertEqual( + self.polys_to_list( + QgsSymbolLayerUtils.toQPolygonF( + QgsGeometry.fromWkt("Point( 5 5 )"), Qgis.SymbolType.Line + ) + ), + [], + ) + self.assertEqual( + self.polys_to_list( + QgsSymbolLayerUtils.toQPolygonF( + QgsGeometry.fromWkt("Point( 5 5 )"), Qgis.SymbolType.Fill + ) + ), + [], + ) # multipoint - self.assertEqual(self.polys_to_list(QgsSymbolLayerUtils.toQPolygonF(QgsGeometry.fromWkt('MultiPoint((5 5), (1 2))'), Qgis.SymbolType.Marker)), - [[[[5.0, 5.0], [1.0, 2.0]]]]) - self.assertEqual(self.polys_to_list(QgsSymbolLayerUtils.toQPolygonF(QgsGeometry.fromWkt('MultiPoint((5 5), (1 2))'), Qgis.SymbolType.Line)), - []) - self.assertEqual(self.polys_to_list(QgsSymbolLayerUtils.toQPolygonF(QgsGeometry.fromWkt('MultiPoint((5 5), (1 2))'), Qgis.SymbolType.Fill)), - []) - self.assertEqual(self.polys_to_list(QgsSymbolLayerUtils.toQPolygonF(QgsGeometry.fromWkt('MultiPoint((5 5), (1 2), (4 3))'), Qgis.SymbolType.Marker)), - [[[[5.0, 5.0], [1.0, 2.0], [4.0, 3.0]]]]) + self.assertEqual( + self.polys_to_list( + QgsSymbolLayerUtils.toQPolygonF( + QgsGeometry.fromWkt("MultiPoint((5 5), (1 2))"), + Qgis.SymbolType.Marker, + ) + ), + [[[[5.0, 5.0], [1.0, 2.0]]]], + ) + self.assertEqual( + self.polys_to_list( + QgsSymbolLayerUtils.toQPolygonF( + QgsGeometry.fromWkt("MultiPoint((5 5), (1 2))"), + Qgis.SymbolType.Line, + ) + ), + [], + ) + self.assertEqual( + self.polys_to_list( + QgsSymbolLayerUtils.toQPolygonF( + QgsGeometry.fromWkt("MultiPoint((5 5), (1 2))"), + Qgis.SymbolType.Fill, + ) + ), + [], + ) + self.assertEqual( + self.polys_to_list( + QgsSymbolLayerUtils.toQPolygonF( + QgsGeometry.fromWkt("MultiPoint((5 5), (1 2), (4 3))"), + Qgis.SymbolType.Marker, + ) + ), + [[[[5.0, 5.0], [1.0, 2.0], [4.0, 3.0]]]], + ) # line - self.assertEqual(self.polys_to_list(QgsSymbolLayerUtils.toQPolygonF(QgsGeometry.fromWkt('LineString(1 5, 6 5)'), Qgis.SymbolType.Marker)), - [[[[0, 0]]]]) - self.assertEqual(self.polys_to_list(QgsSymbolLayerUtils.toQPolygonF(QgsGeometry.fromWkt('LineString(1 5, 6 5)'), Qgis.SymbolType.Line)), - [[[[1.0, 5.0], [6.0, 5.0]]]]) - self.assertEqual(self.polys_to_list(QgsSymbolLayerUtils.toQPolygonF(QgsGeometry.fromWkt('LineString(1 5, 6 5, 10 10)'), Qgis.SymbolType.Line)), - [[[[1.0, 5.0], [6.0, 5.0], [10, 10]]]]) - self.assertEqual(self.polys_to_list(QgsSymbolLayerUtils.toQPolygonF(QgsGeometry.fromWkt('LineString(1 5, 6 5)'), Qgis.SymbolType.Fill)), - []) + self.assertEqual( + self.polys_to_list( + QgsSymbolLayerUtils.toQPolygonF( + QgsGeometry.fromWkt("LineString(1 5, 6 5)"), Qgis.SymbolType.Marker + ) + ), + [[[[0, 0]]]], + ) + self.assertEqual( + self.polys_to_list( + QgsSymbolLayerUtils.toQPolygonF( + QgsGeometry.fromWkt("LineString(1 5, 6 5)"), Qgis.SymbolType.Line + ) + ), + [[[[1.0, 5.0], [6.0, 5.0]]]], + ) + self.assertEqual( + self.polys_to_list( + QgsSymbolLayerUtils.toQPolygonF( + QgsGeometry.fromWkt("LineString(1 5, 6 5, 10 10)"), + Qgis.SymbolType.Line, + ) + ), + [[[[1.0, 5.0], [6.0, 5.0], [10, 10]]]], + ) + self.assertEqual( + self.polys_to_list( + QgsSymbolLayerUtils.toQPolygonF( + QgsGeometry.fromWkt("LineString(1 5, 6 5)"), Qgis.SymbolType.Fill + ) + ), + [], + ) # circularstring - self.assertEqual(self.polys_to_list(QgsSymbolLayerUtils.toQPolygonF(QgsGeometry.fromWkt('CircularString(5 5, 1 2, 3 4)'), Qgis.SymbolType.Line))[0][0][:5], - [[5.0, 5.0], [5.131, 5.042], [5.263, 5.083], [5.396, 5.12], [5.529, 5.156]]) + self.assertEqual( + self.polys_to_list( + QgsSymbolLayerUtils.toQPolygonF( + QgsGeometry.fromWkt("CircularString(5 5, 1 2, 3 4)"), + Qgis.SymbolType.Line, + ) + )[0][0][:5], + [[5.0, 5.0], [5.131, 5.042], [5.263, 5.083], [5.396, 5.12], [5.529, 5.156]], + ) # multilinestring - self.assertEqual(self.polys_to_list(QgsSymbolLayerUtils.toQPolygonF(QgsGeometry.fromWkt('MultiLineString((5 5, 1 2),(3 6, 4 2))'), Qgis.SymbolType.Line)), - [[[[5.0, 5.0], [1.0, 2.0]]], [[[3.0, 6.0], [4.0, 2.0]]]]) + self.assertEqual( + self.polys_to_list( + QgsSymbolLayerUtils.toQPolygonF( + QgsGeometry.fromWkt("MultiLineString((5 5, 1 2),(3 6, 4 2))"), + Qgis.SymbolType.Line, + ) + ), + [[[[5.0, 5.0], [1.0, 2.0]]], [[[3.0, 6.0], [4.0, 2.0]]]], + ) # polygon - self.assertEqual(self.polys_to_list(QgsSymbolLayerUtils.toQPolygonF(QgsGeometry.fromWkt('Polygon((5 5, 1 2, 3 4, 5 5))'), Qgis.SymbolType.Marker)), - [[[[0.0, 0.0]]]]) - self.assertEqual(self.polys_to_list(QgsSymbolLayerUtils.toQPolygonF(QgsGeometry.fromWkt('Polygon((5 5, 1 2, 3 4, 5 5))'), Qgis.SymbolType.Line)), - []) - self.assertEqual(self.polys_to_list(QgsSymbolLayerUtils.toQPolygonF(QgsGeometry.fromWkt('Polygon((5 5, 1 2, 3 4, 5 5))'), Qgis.SymbolType.Fill)), - [[[[5.0, 5.0], [1.0, 2.0], [3.0, 4.0], [5.0, 5.0]]]]) + self.assertEqual( + self.polys_to_list( + QgsSymbolLayerUtils.toQPolygonF( + QgsGeometry.fromWkt("Polygon((5 5, 1 2, 3 4, 5 5))"), + Qgis.SymbolType.Marker, + ) + ), + [[[[0.0, 0.0]]]], + ) + self.assertEqual( + self.polys_to_list( + QgsSymbolLayerUtils.toQPolygonF( + QgsGeometry.fromWkt("Polygon((5 5, 1 2, 3 4, 5 5))"), + Qgis.SymbolType.Line, + ) + ), + [], + ) + self.assertEqual( + self.polys_to_list( + QgsSymbolLayerUtils.toQPolygonF( + QgsGeometry.fromWkt("Polygon((5 5, 1 2, 3 4, 5 5))"), + Qgis.SymbolType.Fill, + ) + ), + [[[[5.0, 5.0], [1.0, 2.0], [3.0, 4.0], [5.0, 5.0]]]], + ) # rings - self.assertEqual(self.polys_to_list(QgsSymbolLayerUtils.toQPolygonF(QgsGeometry.fromWkt('Polygon((5 5, 1 2, 3 4, 5 5), (4.5 4.5, 4.4 4.4, 4.5 4.4, 4.5 4.5))'), Qgis.SymbolType.Fill)), - [[[[5.0, 5.0], [1.0, 2.0], [3.0, 4.0], [5.0, 5.0]], [[4.5, 4.5], [4.4, 4.4], [4.5, 4.4], [4.5, 4.5]]]]) + self.assertEqual( + self.polys_to_list( + QgsSymbolLayerUtils.toQPolygonF( + QgsGeometry.fromWkt( + "Polygon((5 5, 1 2, 3 4, 5 5), (4.5 4.5, 4.4 4.4, 4.5 4.4, 4.5 4.5))" + ), + Qgis.SymbolType.Fill, + ) + ), + [ + [ + [[5.0, 5.0], [1.0, 2.0], [3.0, 4.0], [5.0, 5.0]], + [[4.5, 4.5], [4.4, 4.4], [4.5, 4.4], [4.5, 4.5]], + ] + ], + ) # circular - self.assertEqual(self.polys_to_list(QgsSymbolLayerUtils.toQPolygonF(QgsGeometry.fromWkt('CurvePolygon(CircularString(5 5, 3 4, 1 2, 3 0, 5 5))'), Qgis.SymbolType.Fill))[0][0][:5], - [[5.0, 5.0], [4.87, 4.955], [4.741, 4.909], [4.612, 4.859], [4.485, 4.808]]) + self.assertEqual( + self.polys_to_list( + QgsSymbolLayerUtils.toQPolygonF( + QgsGeometry.fromWkt( + "CurvePolygon(CircularString(5 5, 3 4, 1 2, 3 0, 5 5))" + ), + Qgis.SymbolType.Fill, + ) + )[0][0][:5], + [[5.0, 5.0], [4.87, 4.955], [4.741, 4.909], [4.612, 4.859], [4.485, 4.808]], + ) # multipolygon - self.assertEqual(self.polys_to_list(QgsSymbolLayerUtils.toQPolygonF(QgsGeometry.fromWkt('MultiPolygon(((5 5, 1 2, 3 4, 5 5), (4.5 4.5, 4.4 4.4, 4.5 4.4, 4.5 4.5)),((10 11, 11 11, 11 10, 10 11)))'), Qgis.SymbolType.Fill)), - [[[[5.0, 5.0], [1.0, 2.0], [3.0, 4.0], [5.0, 5.0]], [[4.5, 4.5], [4.4, 4.4], [4.5, 4.4], [4.5, 4.5]]], [[[10.0, 11.0], [11.0, 11.0], [11.0, 10.0], [10.0, 11.0]]]]) - - -if __name__ == '__main__': + self.assertEqual( + self.polys_to_list( + QgsSymbolLayerUtils.toQPolygonF( + QgsGeometry.fromWkt( + "MultiPolygon(((5 5, 1 2, 3 4, 5 5), (4.5 4.5, 4.4 4.4, 4.5 4.4, 4.5 4.5)),((10 11, 11 11, 11 10, 10 11)))" + ), + Qgis.SymbolType.Fill, + ) + ), + [ + [ + [[5.0, 5.0], [1.0, 2.0], [3.0, 4.0], [5.0, 5.0]], + [[4.5, 4.5], [4.4, 4.4], [4.5, 4.4], [4.5, 4.5]], + ], + [[[10.0, 11.0], [11.0, 11.0], [11.0, 10.0], [10.0, 11.0]]], + ], + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgstablecell.py b/tests/src/python/test_qgstablecell.py index edaa57771f3d..cd1ef74d490c 100644 --- a/tests/src/python/test_qgstablecell.py +++ b/tests/src/python/test_qgstablecell.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 by Nyall Dawson' -__date__ = '10/01/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 by Nyall Dawson" +__date__ = "10/01/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtGui import QColor from qgis.core import ( @@ -28,8 +29,8 @@ class TestQgsTableCell(QgisTestCase): def testCell(self): - c = QgsTableCell('test') - self.assertEqual(c.content(), 'test') + c = QgsTableCell("test") + self.assertEqual(c.content(), "test") c.setContent(5) self.assertEqual(c.content(), 5) @@ -41,8 +42,8 @@ def testCell(self): c.setBackgroundColor(QColor(255, 0, 0)) c.setForegroundColor(QColor(255, 0, 255)) c.setNumericFormat(QgsBearingNumericFormat()) - self.assertEqual(c.backgroundColor().name(), '#ff0000') - self.assertEqual(c.foregroundColor().name(), '#ff00ff') + self.assertEqual(c.backgroundColor().name(), "#ff0000") + self.assertEqual(c.foregroundColor().name(), "#ff00ff") self.assertIsInstance(c.numericFormat(), QgsBearingNumericFormat) format = QgsTextFormat() @@ -52,14 +53,14 @@ def testCell(self): self.assertTrue(c.textFormat().isValid()) def testProperties(self): - c = QgsTableCell('test') + c = QgsTableCell("test") props = c.properties(QgsReadWriteContext()) c2 = QgsTableCell() c2.setProperties(props, QgsReadWriteContext()) - self.assertEqual(c2.content(), 'test') + self.assertEqual(c2.content(), "test") self.assertFalse(c2.backgroundColor().isValid()) self.assertFalse(c2.foregroundColor().isValid()) self.assertFalse(c2.numericFormat()) @@ -78,14 +79,14 @@ def testProperties(self): c3 = QgsTableCell() c3.setProperties(props, QgsReadWriteContext()) - self.assertEqual(c3.content(), 'test') - self.assertEqual(c3.backgroundColor().name(), '#ff0000') - self.assertEqual(c3.foregroundColor().name(), '#ff00ff') + self.assertEqual(c3.content(), "test") + self.assertEqual(c3.backgroundColor().name(), "#ff0000") + self.assertEqual(c3.foregroundColor().name(), "#ff00ff") self.assertIsInstance(c3.numericFormat(), QgsBearingNumericFormat) self.assertTrue(c3.numericFormat().showPlusSign()) self.assertEqual(c3.textFormat().size(), 16.8) self.assertTrue(c3.textFormat().isValid()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgstabwidget.py b/tests/src/python/test_qgstabwidget.py index 6063f90fa528..ce5892f30fbb 100644 --- a/tests/src/python/test_qgstabwidget.py +++ b/tests/src/python/test_qgstabwidget.py @@ -1,4 +1,4 @@ -''' +""" test_qgstabwidget.py -------------------------------------- Date : September 2016 @@ -12,7 +12,7 @@ * (at your option) any later version. * * * ***************************************************************************/ -''' +""" from qgis.PyQt.QtWidgets import QWidget from qgis.gui import QgsTabWidget @@ -39,24 +39,24 @@ def testQgsTabWidget(self): wdg2 = QWidget() wdg3 = QWidget() - tabWidget.addTab(wdg1, '1') - tabWidget.addTab(wdg2, '2') - tabWidget.addTab(wdg3, '3') + tabWidget.addTab(wdg1, "1") + tabWidget.addTab(wdg2, "2") + tabWidget.addTab(wdg3, "3") tabWidget.hideTab(wdg2) self.assertEqual(tabWidget.count(), 2) tabWidget.showTab(wdg2) self.assertEqual(tabWidget.count(), 3) - self.assertEqual(tabWidget.tabText(0), '1') - self.assertEqual(tabWidget.tabText(1), '2') - self.assertEqual(tabWidget.tabText(2), '3') + self.assertEqual(tabWidget.tabText(0), "1") + self.assertEqual(tabWidget.tabText(1), "2") + self.assertEqual(tabWidget.tabText(2), "3") tabWidget.hideTab(wdg2) tabWidget.removeTab(1) - self.assertEqual(tabWidget.tabText(0), '1') + self.assertEqual(tabWidget.tabText(0), "1") tabWidget.showTab(wdg2) - self.assertEqual(tabWidget.tabText(1), '2') + self.assertEqual(tabWidget.tabText(1), "2") self.assertEqual(tabWidget.count(), 2) # Show an already visible tab @@ -82,5 +82,5 @@ def testQgsTabWidget(self): self.assertEqual(tabWidget.count(), 0) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgstaskmanager.py b/tests/src/python/test_qgstaskmanager.py index 088e341144ef..d72ad6bce8de 100644 --- a/tests/src/python/test_qgstaskmanager.py +++ b/tests/src/python/test_qgstaskmanager.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '26/04/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "26/04/2016" +__copyright__ = "Copyright 2016, The QGIS Project" import os from time import sleep @@ -23,14 +24,14 @@ def run(task, result): if not result: - raise Exception('canceled') + raise Exception("canceled") else: return result def run_with_kwargs(task, password, result): if not password == 1: - raise Exception('bad password value') + raise Exception("bad password value") else: return result @@ -39,7 +40,7 @@ def cancelable(task): while not task.isCanceled(): pass if task.isCanceled(): - raise Exception('canceled') + raise Exception("canceled") def progress_function(task): @@ -48,7 +49,7 @@ def progress_function(task): while not task.isCanceled(): pass if task.isCanceled(): - raise Exception('canceled') + raise Exception("canceled") def run_no_result(task): @@ -56,7 +57,7 @@ def run_no_result(task): def run_fail(task): - raise Exception('fail') + raise Exception("fail") def run_single_val_result(task): @@ -64,17 +65,20 @@ def run_single_val_result(task): def run_multiple_val_result(task): - return 5, 'whoo' + return 5, "whoo" class TestQgsTaskManager(QgisTestCase): def testTaskFromFunction(self): - """ test creating task from function """ + """test creating task from function""" - task = QgsTask.fromFunction('test task', run, 20) + task = QgsTask.fromFunction("test task", run, 20) QgsApplication.taskManager().addTask(task) - while task.status() not in [QgsTask.TaskStatus.Complete, QgsTask.TaskStatus.Terminated]: + while task.status() not in [ + QgsTask.TaskStatus.Complete, + QgsTask.TaskStatus.Terminated, + ]: QCoreApplication.processEvents() self.assertEqual(task.returned_values, 20) @@ -82,9 +86,12 @@ def testTaskFromFunction(self): self.assertEqual(task.status(), QgsTask.TaskStatus.Complete) # try a task which cancels itself - bad_task = QgsTask.fromFunction('test task2', run, None) + bad_task = QgsTask.fromFunction("test task2", run, None) QgsApplication.taskManager().addTask(bad_task) - while bad_task.status() not in [QgsTask.TaskStatus.Complete, QgsTask.TaskStatus.Terminated]: + while bad_task.status() not in [ + QgsTask.TaskStatus.Complete, + QgsTask.TaskStatus.Terminated, + ]: QCoreApplication.processEvents() self.assertFalse(bad_task.returned_values) @@ -92,19 +99,22 @@ def testTaskFromFunction(self): self.assertEqual(bad_task.status(), QgsTask.TaskStatus.Terminated) def testTaskFromFunctionWithFlags(self): - """ test creating task from function with flags""" + """test creating task from function with flags""" - task = QgsTask.fromFunction('test task', run, 20, flags=QgsTask.Flags()) + task = QgsTask.fromFunction("test task", run, 20, flags=QgsTask.Flags()) self.assertFalse(task.canCancel()) - task2 = QgsTask.fromFunction('test task', run, 20, flags=QgsTask.Flag.CanCancel) + task2 = QgsTask.fromFunction("test task", run, 20, flags=QgsTask.Flag.CanCancel) self.assertTrue(task2.canCancel()) def testTaskFromFunctionWithKwargs(self): - """ test creating task from function using kwargs """ + """test creating task from function using kwargs""" - task = QgsTask.fromFunction('test task3', run_with_kwargs, result=5, password=1) + task = QgsTask.fromFunction("test task3", run_with_kwargs, result=5, password=1) QgsApplication.taskManager().addTask(task) - while task.status() not in [QgsTask.TaskStatus.Complete, QgsTask.TaskStatus.Terminated]: + while task.status() not in [ + QgsTask.TaskStatus.Complete, + QgsTask.TaskStatus.Terminated, + ]: QCoreApplication.processEvents() self.assertEqual(task.returned_values, 5) @@ -112,8 +122,8 @@ def testTaskFromFunctionWithKwargs(self): self.assertEqual(task.status(), QgsTask.TaskStatus.Complete) def testTaskFromFunctionIsCancelable(self): - """ test that task from function can check canceled status """ - bad_task = QgsTask.fromFunction('test task4', cancelable) + """test that task from function can check canceled status""" + bad_task = QgsTask.fromFunction("test task4", cancelable) QgsApplication.taskManager().addTask(bad_task) while bad_task.status() != QgsTask.TaskStatus.Running: QCoreApplication.processEvents() @@ -128,8 +138,8 @@ def testTaskFromFunctionIsCancelable(self): self.assertTrue(bad_task.exception) def testTaskFromFunctionCanSetProgress(self): - """ test that task from function can set progress """ - task = QgsTask.fromFunction('test task5', progress_function) + """test that task from function can set progress""" + task = QgsTask.fromFunction("test task5", progress_function) QgsApplication.taskManager().addTask(task) while task.status() != QgsTask.TaskStatus.Running: QCoreApplication.processEvents() @@ -146,7 +156,7 @@ def testTaskFromFunctionCanSetProgress(self): QCoreApplication.processEvents() def testTaskFromFunctionFinished(self): - """ test that task from function can have callback finished function""" + """test that task from function can have callback finished function""" called = False def finished_no_val(e): @@ -155,9 +165,14 @@ def finished_no_val(e): called = True return - task = QgsTask.fromFunction('test task', run_no_result, on_finished=finished_no_val) + task = QgsTask.fromFunction( + "test task", run_no_result, on_finished=finished_no_val + ) QgsApplication.taskManager().addTask(task) - while task.status() not in [QgsTask.TaskStatus.Complete, QgsTask.TaskStatus.Terminated]: + while task.status() not in [ + QgsTask.TaskStatus.Complete, + QgsTask.TaskStatus.Terminated, + ]: QCoreApplication.processEvents() while QgsApplication.taskManager().countActiveTasks() > 0: QCoreApplication.processEvents() @@ -168,7 +183,7 @@ def finished_no_val(e): self.assertTrue(called) def testTaskFromFunctionFinishedFail(self): - """ test that task from function which fails calls finished with exception""" + """test that task from function which fails calls finished with exception""" finished_exception = None def finished_fail(e): @@ -176,9 +191,12 @@ def finished_fail(e): assert e finished_exception = e - task = QgsTask.fromFunction('test task', run_fail, on_finished=finished_fail) + task = QgsTask.fromFunction("test task", run_fail, on_finished=finished_fail) QgsApplication.taskManager().addTask(task) - while task.status() not in [QgsTask.TaskStatus.Complete, QgsTask.TaskStatus.Terminated]: + while task.status() not in [ + QgsTask.TaskStatus.Complete, + QgsTask.TaskStatus.Terminated, + ]: QCoreApplication.processEvents() while QgsApplication.taskManager().countActiveTasks() > 0: QCoreApplication.processEvents() @@ -189,7 +207,7 @@ def finished_fail(e): self.assertEqual(task.exception, finished_exception) def testTaskFromFunctionCanceledWhileQueued(self): - """ test that task from finished is called with exception when task is terminated while queued""" + """test that task from finished is called with exception when task is terminated while queued""" finished_exception = None def finished_fail(e): @@ -197,11 +215,16 @@ def finished_fail(e): assert e finished_exception = e - task = QgsTask.fromFunction('test task', run_no_result, on_finished=finished_fail) + task = QgsTask.fromFunction( + "test task", run_no_result, on_finished=finished_fail + ) task.hold() QgsApplication.taskManager().addTask(task) task.cancel() - while task.status() not in [QgsTask.TaskStatus.Complete, QgsTask.TaskStatus.Terminated]: + while task.status() not in [ + QgsTask.TaskStatus.Complete, + QgsTask.TaskStatus.Terminated, + ]: QCoreApplication.processEvents() while QgsApplication.taskManager().countActiveTasks() > 0: QCoreApplication.processEvents() @@ -212,7 +235,7 @@ def finished_fail(e): self.assertEqual(task.exception, finished_exception) def testTaskFromFunctionFinishedWithVal(self): - """ test that task from function can have callback finished function and is passed result values""" + """test that task from function can have callback finished function and is passed result values""" result_value = None def finished_single_value_result(e, value): @@ -221,9 +244,14 @@ def finished_single_value_result(e, value): result_value = value return - task = QgsTask.fromFunction('test task', run_single_val_result, on_finished=finished_single_value_result) + task = QgsTask.fromFunction( + "test task", run_single_val_result, on_finished=finished_single_value_result + ) QgsApplication.taskManager().addTask(task) - while task.status() not in [QgsTask.TaskStatus.Complete, QgsTask.TaskStatus.Terminated]: + while task.status() not in [ + QgsTask.TaskStatus.Complete, + QgsTask.TaskStatus.Terminated, + ]: QCoreApplication.processEvents() while QgsApplication.taskManager().countActiveTasks() > 0: QCoreApplication.processEvents() @@ -234,7 +262,7 @@ def finished_single_value_result(e, value): self.assertEqual(result_value, 5) def testTaskFromFunctionFinishedWithMultipleValues(self): - """ test that task from function can have callback finished function and is passed multiple result values""" + """test that task from function can have callback finished function and is passed multiple result values""" result_value = None result_statement = None @@ -245,22 +273,32 @@ def finished_multiple_value_result(e, results): result_value = results[0] result_statement = results[1] - task = QgsTask.fromFunction('test task', run_multiple_val_result, on_finished=finished_multiple_value_result) + task = QgsTask.fromFunction( + "test task", + run_multiple_val_result, + on_finished=finished_multiple_value_result, + ) QgsApplication.taskManager().addTask(task) - while task.status() not in [QgsTask.TaskStatus.Complete, QgsTask.TaskStatus.Terminated]: + while task.status() not in [ + QgsTask.TaskStatus.Complete, + QgsTask.TaskStatus.Terminated, + ]: QCoreApplication.processEvents() while QgsApplication.taskManager().countActiveTasks() > 0: QCoreApplication.processEvents() # check that the finished function was called - self.assertEqual(task.returned_values, (5, 'whoo')) + self.assertEqual(task.returned_values, (5, "whoo")) self.assertFalse(task.exception) self.assertEqual(result_value, 5) - self.assertEqual(result_statement, 'whoo') + self.assertEqual(result_statement, "whoo") - @unittest.skipIf(os.environ.get('QGIS_CONTINUOUS_INTEGRATION_RUN', 'true'), 'Test is unstable on Travis') + @unittest.skipIf( + os.environ.get("QGIS_CONTINUOUS_INTEGRATION_RUN", "true"), + "Test is unstable on Travis", + ) def testTaskFromFunctionWithSubTaskCompletedIsCalledOnce(self): # spellok - """ test that when a parent task has subtasks it does emit taskCompleted only once""" + """test that when a parent task has subtasks it does emit taskCompleted only once""" self.finished = 0 self.completed = 0 @@ -271,16 +309,29 @@ def _on_finished(e): def _on_completed(): self.completed += 1 - task = QgsTask.fromFunction('test task', run_no_result, on_finished=_on_finished) + task = QgsTask.fromFunction( + "test task", run_no_result, on_finished=_on_finished + ) task.taskCompleted.connect(_on_completed) spy = QSignalSpy(task.taskCompleted) - sub_task_1 = QgsTask.fromFunction('test subtask 1', run_no_result, on_finished=_on_finished) - sub_task_2 = QgsTask.fromFunction('test subtask 2', run_no_result, on_finished=_on_finished) - task.addSubTask(sub_task_1, [], QgsTask.SubTaskDependency.ParentDependsOnSubTask) - task.addSubTask(sub_task_2, [], QgsTask.SubTaskDependency.ParentDependsOnSubTask) + sub_task_1 = QgsTask.fromFunction( + "test subtask 1", run_no_result, on_finished=_on_finished + ) + sub_task_2 = QgsTask.fromFunction( + "test subtask 2", run_no_result, on_finished=_on_finished + ) + task.addSubTask( + sub_task_1, [], QgsTask.SubTaskDependency.ParentDependsOnSubTask + ) + task.addSubTask( + sub_task_2, [], QgsTask.SubTaskDependency.ParentDependsOnSubTask + ) QgsApplication.taskManager().addTask(task) - while task.status() not in [QgsTask.TaskStatus.Complete, QgsTask.TaskStatus.Terminated]: + while task.status() not in [ + QgsTask.TaskStatus.Complete, + QgsTask.TaskStatus.Terminated, + ]: QCoreApplication.processEvents() while QgsApplication.taskManager().countActiveTasks() > 0: QCoreApplication.processEvents() @@ -290,5 +341,5 @@ def _on_completed(): self.assertEqual(len(spy), 1) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgstemporalutils.py b/tests/src/python/test_qgstemporalutils.py index 4e8f78cc20e4..0c70bcbcc771 100644 --- a/tests/src/python/test_qgstemporalutils.py +++ b/tests/src/python/test_qgstemporalutils.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '13/3/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "13/3/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, Qt, QTime from qgis.core import ( @@ -32,266 +33,529 @@ class TestQgsTemporalUtils(QgisTestCase): def testTemporalRangeForProject(self): p = QgsProject() - r1 = QgsRasterLayer('', '', 'wms') - r2 = QgsRasterLayer('', '', 'wms') - r3 = QgsRasterLayer('', '', 'wms') + r1 = QgsRasterLayer("", "", "wms") + r2 = QgsRasterLayer("", "", "wms") + r3 = QgsRasterLayer("", "", "wms") r1.temporalProperties().setIsActive(True) - r1.temporalProperties().setFixedTemporalRange(QgsDateTimeRange(QDateTime(QDate(2020, 1, 1), QTime(), Qt.TimeSpec.UTC), - QDateTime(QDate(2020, 3, 31), QTime(), Qt.TimeSpec.UTC))) + r1.temporalProperties().setFixedTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2020, 1, 1), QTime(), Qt.TimeSpec.UTC), + QDateTime(QDate(2020, 3, 31), QTime(), Qt.TimeSpec.UTC), + ) + ) r2.temporalProperties().setIsActive(True) - r2.temporalProperties().setFixedTemporalRange(QgsDateTimeRange(QDateTime(QDate(2020, 4, 1), QTime(), Qt.TimeSpec.UTC), - QDateTime(QDate(2020, 7, 31), QTime(), Qt.TimeSpec.UTC))) + r2.temporalProperties().setFixedTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2020, 4, 1), QTime(), Qt.TimeSpec.UTC), + QDateTime(QDate(2020, 7, 31), QTime(), Qt.TimeSpec.UTC), + ) + ) r3.temporalProperties().setIsActive(True) - r3.temporalProperties().setFixedTemporalRange(QgsDateTimeRange(QDateTime(QDate(2019, 1, 1), QTime(), Qt.TimeSpec.UTC), - QDateTime(QDate(2020, 2, 28), QTime(), Qt.TimeSpec.UTC))) + r3.temporalProperties().setFixedTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2019, 1, 1), QTime(), Qt.TimeSpec.UTC), + QDateTime(QDate(2020, 2, 28), QTime(), Qt.TimeSpec.UTC), + ) + ) p.addMapLayers([r1, r2, r3]) range = QgsTemporalUtils.calculateTemporalRangeForProject(p) - self.assertEqual(range.begin(), QDateTime(QDate(2019, 1, 1), QTime(), Qt.TimeSpec.UTC)) - self.assertEqual(range.end(), QDateTime(QDate(2020, 7, 31), QTime(), Qt.TimeSpec.UTC)) + self.assertEqual( + range.begin(), QDateTime(QDate(2019, 1, 1), QTime(), Qt.TimeSpec.UTC) + ) + self.assertEqual( + range.end(), QDateTime(QDate(2020, 7, 31), QTime(), Qt.TimeSpec.UTC) + ) def testUsedTemporalRangesForProject(self): p = QgsProject() - r1 = QgsRasterLayer('', '', 'wms') - r2 = QgsRasterLayer('', '', 'wms') - r3 = QgsRasterLayer('', '', 'wms') - r4 = QgsRasterLayer('', '', 'wms') + r1 = QgsRasterLayer("", "", "wms") + r2 = QgsRasterLayer("", "", "wms") + r3 = QgsRasterLayer("", "", "wms") + r4 = QgsRasterLayer("", "", "wms") r1.temporalProperties().setIsActive(True) - r1.temporalProperties().setMode(QgsRasterLayerTemporalProperties.TemporalMode.ModeTemporalRangeFromDataProvider) - r1.dataProvider().temporalCapabilities().setAvailableTemporalRange(QgsDateTimeRange(QDateTime(QDate(2020, 1, 1), QTime(), Qt.TimeSpec.UTC), - QDateTime(QDate(2020, 3, 31), QTime(), Qt.TimeSpec.UTC))) + r1.temporalProperties().setMode( + QgsRasterLayerTemporalProperties.TemporalMode.ModeTemporalRangeFromDataProvider + ) + r1.dataProvider().temporalCapabilities().setAvailableTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2020, 1, 1), QTime(), Qt.TimeSpec.UTC), + QDateTime(QDate(2020, 3, 31), QTime(), Qt.TimeSpec.UTC), + ) + ) r2.temporalProperties().setIsActive(True) - r2.temporalProperties().setMode(QgsRasterLayerTemporalProperties.TemporalMode.ModeTemporalRangeFromDataProvider) - r2.dataProvider().temporalCapabilities().setAllAvailableTemporalRanges([QgsDateTimeRange(QDateTime(QDate(2020, 4, 1), QTime(), Qt.TimeSpec.UTC), - QDateTime(QDate(2020, 7, 31), QTime(), Qt.TimeSpec.UTC))]) + r2.temporalProperties().setMode( + QgsRasterLayerTemporalProperties.TemporalMode.ModeTemporalRangeFromDataProvider + ) + r2.dataProvider().temporalCapabilities().setAllAvailableTemporalRanges( + [ + QgsDateTimeRange( + QDateTime(QDate(2020, 4, 1), QTime(), Qt.TimeSpec.UTC), + QDateTime(QDate(2020, 7, 31), QTime(), Qt.TimeSpec.UTC), + ) + ] + ) r3.temporalProperties().setIsActive(True) - r3.temporalProperties().setMode(QgsRasterLayerTemporalProperties.TemporalMode.ModeTemporalRangeFromDataProvider) - r3.dataProvider().temporalCapabilities().setAllAvailableTemporalRanges([QgsDateTimeRange(QDateTime(QDate(2019, 1, 1), QTime(), Qt.TimeSpec.UTC), - QDateTime(QDate(2020, 2, 28), QTime(), Qt.TimeSpec.UTC))]) + r3.temporalProperties().setMode( + QgsRasterLayerTemporalProperties.TemporalMode.ModeTemporalRangeFromDataProvider + ) + r3.dataProvider().temporalCapabilities().setAllAvailableTemporalRanges( + [ + QgsDateTimeRange( + QDateTime(QDate(2019, 1, 1), QTime(), Qt.TimeSpec.UTC), + QDateTime(QDate(2020, 2, 28), QTime(), Qt.TimeSpec.UTC), + ) + ] + ) r4.temporalProperties().setIsActive(True) - r4.temporalProperties().setMode(QgsRasterLayerTemporalProperties.TemporalMode.ModeTemporalRangeFromDataProvider) - r4.dataProvider().temporalCapabilities().setAllAvailableTemporalRanges([QgsDateTimeRange(QDateTime(QDate(2021, 1, 1), QTime(), Qt.TimeSpec.UTC), - QDateTime(QDate(2021, 2, 28), QTime(), Qt.TimeSpec.UTC))]) + r4.temporalProperties().setMode( + QgsRasterLayerTemporalProperties.TemporalMode.ModeTemporalRangeFromDataProvider + ) + r4.dataProvider().temporalCapabilities().setAllAvailableTemporalRanges( + [ + QgsDateTimeRange( + QDateTime(QDate(2021, 1, 1), QTime(), Qt.TimeSpec.UTC), + QDateTime(QDate(2021, 2, 28), QTime(), Qt.TimeSpec.UTC), + ) + ] + ) p.addMapLayers([r1, r2, r3, r4]) ranges = QgsTemporalUtils.usedTemporalRangesForProject(p) - self.assertEqual(ranges, [QgsDateTimeRange(QDateTime(QDate(2019, 1, 1), QTime(), Qt.TimeSpec.UTC), - QDateTime(QDate(2020, 3, 31), QTime(), Qt.TimeSpec.UTC)), - QgsDateTimeRange(QDateTime(QDate(2020, 4, 1), QTime(), Qt.TimeSpec.UTC), - QDateTime(QDate(2020, 7, 31), QTime(), Qt.TimeSpec.UTC)), - QgsDateTimeRange(QDateTime(QDate(2021, 1, 1), QTime(), Qt.TimeSpec.UTC), - QDateTime(QDate(2021, 2, 28), QTime(), Qt.TimeSpec.UTC))]) + self.assertEqual( + ranges, + [ + QgsDateTimeRange( + QDateTime(QDate(2019, 1, 1), QTime(), Qt.TimeSpec.UTC), + QDateTime(QDate(2020, 3, 31), QTime(), Qt.TimeSpec.UTC), + ), + QgsDateTimeRange( + QDateTime(QDate(2020, 4, 1), QTime(), Qt.TimeSpec.UTC), + QDateTime(QDate(2020, 7, 31), QTime(), Qt.TimeSpec.UTC), + ), + QgsDateTimeRange( + QDateTime(QDate(2021, 1, 1), QTime(), Qt.TimeSpec.UTC), + QDateTime(QDate(2021, 2, 28), QTime(), Qt.TimeSpec.UTC), + ), + ], + ) def testFrameTimeCalculation(self): - expected = {QgsUnitTypes.TemporalUnit.TemporalMilliseconds: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 10), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalSeconds: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 10, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalMinutes: QDateTime(QDate(2021, 1, 1), QTime(12, 10, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalHours: QDateTime(QDate(2021, 1, 1), QTime(22, 0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalDays: QDateTime(QDate(2021, 1, 11), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalWeeks: QDateTime(QDate(2021, 3, 12), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalMonths: QDateTime(QDate(2021, 11, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalYears: QDateTime(QDate(2031, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalDecades: QDateTime(QDate(2121, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalCenturies: QDateTime(QDate(3021, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC) - } + expected = { + QgsUnitTypes.TemporalUnit.TemporalMilliseconds: QDateTime( + QDate(2021, 1, 1), QTime(12, 0, 0, 10), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalSeconds: QDateTime( + QDate(2021, 1, 1), QTime(12, 0, 10, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalMinutes: QDateTime( + QDate(2021, 1, 1), QTime(12, 10, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalHours: QDateTime( + QDate(2021, 1, 1), QTime(22, 0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalDays: QDateTime( + QDate(2021, 1, 11), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalWeeks: QDateTime( + QDate(2021, 3, 12), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalMonths: QDateTime( + QDate(2021, 11, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalYears: QDateTime( + QDate(2031, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalDecades: QDateTime( + QDate(2121, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalCenturies: QDateTime( + QDate(3021, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC + ), + } for unit in list(expected.keys()): - f = QgsTemporalUtils.calculateFrameTime(QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), - 1, - QgsInterval(10, unit)) + f = QgsTemporalUtils.calculateFrameTime( + QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), + 1, + QgsInterval(10, unit), + ) self.assertEqual(f, expected[unit]) - expected2 = {QgsUnitTypes.TemporalUnit.TemporalMilliseconds: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 10), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalSeconds: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 10, 500), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalMinutes: QDateTime(QDate(2021, 1, 1), QTime(12, 10, 30, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalHours: QDateTime(QDate(2021, 1, 1), QTime(22, 30, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalDays: QDateTime(QDate(2021, 1, 12), QTime(0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalWeeks: QDateTime(QDate(2021, 3, 16), QTime(0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalMonths: QDateTime(QDate(2021, 11, 12), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalYears: QDateTime(QDate(2031, 7, 3), QTime(15, 0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalDecades: QDateTime(QDate(2126, 1, 2), QTime(18, 0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalCenturies: QDateTime(QDate(3071, 1, 10), QTime(0, 0, 0, 0), Qt.TimeSpec.UTC) - } + expected2 = { + QgsUnitTypes.TemporalUnit.TemporalMilliseconds: QDateTime( + QDate(2021, 1, 1), QTime(12, 0, 0, 10), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalSeconds: QDateTime( + QDate(2021, 1, 1), QTime(12, 0, 10, 500), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalMinutes: QDateTime( + QDate(2021, 1, 1), QTime(12, 10, 30, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalHours: QDateTime( + QDate(2021, 1, 1), QTime(22, 30, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalDays: QDateTime( + QDate(2021, 1, 12), QTime(0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalWeeks: QDateTime( + QDate(2021, 3, 16), QTime(0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalMonths: QDateTime( + QDate(2021, 11, 12), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalYears: QDateTime( + QDate(2031, 7, 3), QTime(15, 0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalDecades: QDateTime( + QDate(2126, 1, 2), QTime(18, 0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalCenturies: QDateTime( + QDate(3071, 1, 10), QTime(0, 0, 0, 0), Qt.TimeSpec.UTC + ), + } for unit in list(expected2.keys()): - f = QgsTemporalUtils.calculateFrameTime(QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), - 1, - QgsInterval(10.5, unit)) + f = QgsTemporalUtils.calculateFrameTime( + QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), + 1, + QgsInterval(10.5, unit), + ) self.assertEqual(f, expected2[unit]) # frame number > 1 - expected2a = {QgsUnitTypes.TemporalUnit.TemporalMilliseconds: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 31), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalSeconds: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 31, 500), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalMinutes: QDateTime(QDate(2021, 1, 1), QTime(12, 31, 30, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalHours: QDateTime(QDate(2021, 1, 2), QTime(19, 30, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalDays: QDateTime(QDate(2021, 2, 2), QTime(0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalWeeks: QDateTime(QDate(2021, 8, 10), QTime(0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalMonths: QDateTime(QDate(2023, 8, 4), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalYears: QDateTime(QDate(2052, 7, 2), QTime(21, 0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalDecades: QDateTime(QDate(2336, 1, 5), QTime(6, 0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalCenturies: QDateTime(QDate(5171, 1, 26), QTime(0, 0, 0, 0), Qt.TimeSpec.UTC) - } + expected2a = { + QgsUnitTypes.TemporalUnit.TemporalMilliseconds: QDateTime( + QDate(2021, 1, 1), QTime(12, 0, 0, 31), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalSeconds: QDateTime( + QDate(2021, 1, 1), QTime(12, 0, 31, 500), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalMinutes: QDateTime( + QDate(2021, 1, 1), QTime(12, 31, 30, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalHours: QDateTime( + QDate(2021, 1, 2), QTime(19, 30, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalDays: QDateTime( + QDate(2021, 2, 2), QTime(0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalWeeks: QDateTime( + QDate(2021, 8, 10), QTime(0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalMonths: QDateTime( + QDate(2023, 8, 4), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalYears: QDateTime( + QDate(2052, 7, 2), QTime(21, 0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalDecades: QDateTime( + QDate(2336, 1, 5), QTime(6, 0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalCenturies: QDateTime( + QDate(5171, 1, 26), QTime(0, 0, 0, 0), Qt.TimeSpec.UTC + ), + } for unit in list(expected2.keys()): - f = QgsTemporalUtils.calculateFrameTime(QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), - 3, - QgsInterval(10.5, unit)) + f = QgsTemporalUtils.calculateFrameTime( + QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), + 3, + QgsInterval(10.5, unit), + ) self.assertEqual(f, expected2a[unit]) - expected3 = {QgsUnitTypes.TemporalUnit.TemporalMilliseconds: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalSeconds: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 200), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalMinutes: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 12, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalHours: QDateTime(QDate(2021, 1, 1), QTime(12, 12, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalDays: QDateTime(QDate(2021, 1, 1), QTime(16, 48, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalWeeks: QDateTime(QDate(2021, 1, 2), QTime(21, 36, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalMonths: QDateTime(QDate(2021, 1, 7), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalYears: QDateTime(QDate(2021, 3, 15), QTime(13, 12, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalDecades: QDateTime(QDate(2023, 1, 2), QTime(0, 0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalCenturies: QDateTime(QDate(2041, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC) - } + expected3 = { + QgsUnitTypes.TemporalUnit.TemporalMilliseconds: QDateTime( + QDate(2021, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalSeconds: QDateTime( + QDate(2021, 1, 1), QTime(12, 0, 0, 200), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalMinutes: QDateTime( + QDate(2021, 1, 1), QTime(12, 0, 12, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalHours: QDateTime( + QDate(2021, 1, 1), QTime(12, 12, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalDays: QDateTime( + QDate(2021, 1, 1), QTime(16, 48, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalWeeks: QDateTime( + QDate(2021, 1, 2), QTime(21, 36, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalMonths: QDateTime( + QDate(2021, 1, 7), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalYears: QDateTime( + QDate(2021, 3, 15), QTime(13, 12, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalDecades: QDateTime( + QDate(2023, 1, 2), QTime(0, 0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalCenturies: QDateTime( + QDate(2041, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC + ), + } for unit in list(expected3.keys()): - f = QgsTemporalUtils.calculateFrameTime(QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), - 1, - QgsInterval(0.2, unit)) + f = QgsTemporalUtils.calculateFrameTime( + QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), + 1, + QgsInterval(0.2, unit), + ) self.assertEqual(f, expected3[unit]) - expected3a = {QgsUnitTypes.TemporalUnit.TemporalMilliseconds: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalSeconds: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 600), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalMinutes: QDateTime(QDate(2021, 1, 1), QTime(12, 0, 36, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalHours: QDateTime(QDate(2021, 1, 1), QTime(12, 36, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalDays: QDateTime(QDate(2021, 1, 2), QTime(2, 24, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalWeeks: QDateTime(QDate(2021, 1, 5), QTime(16, 48, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalMonths: QDateTime(QDate(2021, 1, 19), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalYears: QDateTime(QDate(2021, 8, 8), QTime(15, 36, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalDecades: QDateTime(QDate(2027, 1, 2), QTime(0, 0, 0, 0), Qt.TimeSpec.UTC), - QgsUnitTypes.TemporalUnit.TemporalCenturies: QDateTime(QDate(2081, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC) - } + expected3a = { + QgsUnitTypes.TemporalUnit.TemporalMilliseconds: QDateTime( + QDate(2021, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalSeconds: QDateTime( + QDate(2021, 1, 1), QTime(12, 0, 0, 600), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalMinutes: QDateTime( + QDate(2021, 1, 1), QTime(12, 0, 36, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalHours: QDateTime( + QDate(2021, 1, 1), QTime(12, 36, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalDays: QDateTime( + QDate(2021, 1, 2), QTime(2, 24, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalWeeks: QDateTime( + QDate(2021, 1, 5), QTime(16, 48, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalMonths: QDateTime( + QDate(2021, 1, 19), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalYears: QDateTime( + QDate(2021, 8, 8), QTime(15, 36, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalDecades: QDateTime( + QDate(2027, 1, 2), QTime(0, 0, 0, 0), Qt.TimeSpec.UTC + ), + QgsUnitTypes.TemporalUnit.TemporalCenturies: QDateTime( + QDate(2081, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC + ), + } for unit in list(expected3.keys()): - f = QgsTemporalUtils.calculateFrameTime(QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), - 3, - QgsInterval(0.2, unit)) + f = QgsTemporalUtils.calculateFrameTime( + QDateTime(QDate(2021, 1, 1), QTime(12, 0, 0, 0), Qt.TimeSpec.UTC), + 3, + QgsInterval(0.2, unit), + ) self.assertEqual(f, expected3a[unit]) def testCalculateDateTimesUsingDuration(self): # invalid duration string vals, ok, exceeded = QgsTemporalUtils.calculateDateTimesUsingDuration( QDateTime(QDate(2021, 3, 23), QTime(0, 0, 0)), - QDateTime(QDate(2021, 3, 24), QTime(12, 0, 0)), 'xT12H') + QDateTime(QDate(2021, 3, 24), QTime(12, 0, 0)), + "xT12H", + ) self.assertFalse(ok) # null duration string vals, ok, exceeded = QgsTemporalUtils.calculateDateTimesUsingDuration( QDateTime(QDate(2021, 3, 23), QTime(0, 0, 0)), - QDateTime(QDate(2021, 3, 24), QTime(12, 0, 0)), '') + QDateTime(QDate(2021, 3, 24), QTime(12, 0, 0)), + "", + ) self.assertFalse(ok) vals, ok, exceeded = QgsTemporalUtils.calculateDateTimesUsingDuration( QDateTime(QDate(2021, 3, 23), QTime(0, 0, 0)), - QDateTime(QDate(2021, 3, 24), QTime(12, 0, 0)), 'P') + QDateTime(QDate(2021, 3, 24), QTime(12, 0, 0)), + "P", + ) self.assertFalse(ok) # valid durations vals, ok, exceeded = QgsTemporalUtils.calculateDateTimesUsingDuration( QDateTime(QDate(2021, 3, 23), QTime(0, 0, 0)), - QDateTime(QDate(2021, 3, 24), QTime(12, 0, 0)), 'PT12H') - self.assertEqual(vals, [QDateTime(2021, 3, 23, 0, 0), - QDateTime(2021, 3, 23, 12, 0), - QDateTime(2021, 3, 24, 0, 0), - QDateTime(2021, 3, 24, 12, 0)]) + QDateTime(QDate(2021, 3, 24), QTime(12, 0, 0)), + "PT12H", + ) + self.assertEqual( + vals, + [ + QDateTime(2021, 3, 23, 0, 0), + QDateTime(2021, 3, 23, 12, 0), + QDateTime(2021, 3, 24, 0, 0), + QDateTime(2021, 3, 24, 12, 0), + ], + ) self.assertTrue(ok) self.assertFalse(exceeded) vals, ok, exceeded = QgsTemporalUtils.calculateDateTimesUsingDuration( QDateTime(QDate(2021, 3, 23), QTime(0, 0, 0)), - QDateTime(QDate(2021, 3, 24), QTime(12, 0, 0)), 'PT12H', maxValues=2) - self.assertEqual(vals, [QDateTime(2021, 3, 23, 0, 0), - QDateTime(2021, 3, 23, 12, 0), - QDateTime(2021, 3, 24, 0, 0)]) + QDateTime(QDate(2021, 3, 24), QTime(12, 0, 0)), + "PT12H", + maxValues=2, + ) + self.assertEqual( + vals, + [ + QDateTime(2021, 3, 23, 0, 0), + QDateTime(2021, 3, 23, 12, 0), + QDateTime(2021, 3, 24, 0, 0), + ], + ) self.assertTrue(ok) self.assertTrue(exceeded) vals, ok, exceeded = QgsTemporalUtils.calculateDateTimesUsingDuration( QDateTime(QDate(2021, 3, 23), QTime(0, 0, 0)), - QDateTime(QDate(2021, 3, 24), QTime(12, 0, 0)), 'PT10H2M5S') - self.assertEqual(vals, [QDateTime(2021, 3, 23, 0, 0), QDateTime(2021, 3, 23, 10, 2, 5), - QDateTime(2021, 3, 23, 20, 4, 10), QDateTime(2021, 3, 24, 6, 6, 15)]) + QDateTime(QDate(2021, 3, 24), QTime(12, 0, 0)), + "PT10H2M5S", + ) + self.assertEqual( + vals, + [ + QDateTime(2021, 3, 23, 0, 0), + QDateTime(2021, 3, 23, 10, 2, 5), + QDateTime(2021, 3, 23, 20, 4, 10), + QDateTime(2021, 3, 24, 6, 6, 15), + ], + ) self.assertTrue(ok) self.assertFalse(exceeded) vals, ok, exceeded = QgsTemporalUtils.calculateDateTimesUsingDuration( QDateTime(QDate(2010, 3, 23), QTime(0, 0, 0)), - QDateTime(QDate(2021, 5, 24), QTime(12, 0, 0)), 'P2Y') - self.assertEqual(vals, - [QDateTime(2010, 3, 23, 0, 0), QDateTime(2012, 3, 23, 0, 0), QDateTime(2014, 3, 23, 0, 0), - QDateTime(2016, 3, 23, 0, 0), QDateTime(2018, 3, 23, 0, 0), QDateTime(2020, 3, 23, 0, 0)]) + QDateTime(QDate(2021, 5, 24), QTime(12, 0, 0)), + "P2Y", + ) + self.assertEqual( + vals, + [ + QDateTime(2010, 3, 23, 0, 0), + QDateTime(2012, 3, 23, 0, 0), + QDateTime(2014, 3, 23, 0, 0), + QDateTime(2016, 3, 23, 0, 0), + QDateTime(2018, 3, 23, 0, 0), + QDateTime(2020, 3, 23, 0, 0), + ], + ) self.assertTrue(ok) self.assertFalse(exceeded) vals, ok, exceeded = QgsTemporalUtils.calculateDateTimesUsingDuration( QDateTime(QDate(2020, 3, 23), QTime(0, 0, 0)), - QDateTime(QDate(2021, 5, 24), QTime(12, 0, 0)), 'P2M') - self.assertEqual(vals, - [QDateTime(2020, 3, 23, 0, 0), QDateTime(2020, 5, 23, 0, 0), QDateTime(2020, 7, 23, 0, 0), - QDateTime(2020, 9, 23, 0, 0), QDateTime(2020, 11, 23, 0, 0), QDateTime(2021, 1, 23, 0, 0), - QDateTime(2021, 3, 23, 0, 0), QDateTime(2021, 5, 23, 0, 0)]) + QDateTime(QDate(2021, 5, 24), QTime(12, 0, 0)), + "P2M", + ) + self.assertEqual( + vals, + [ + QDateTime(2020, 3, 23, 0, 0), + QDateTime(2020, 5, 23, 0, 0), + QDateTime(2020, 7, 23, 0, 0), + QDateTime(2020, 9, 23, 0, 0), + QDateTime(2020, 11, 23, 0, 0), + QDateTime(2021, 1, 23, 0, 0), + QDateTime(2021, 3, 23, 0, 0), + QDateTime(2021, 5, 23, 0, 0), + ], + ) self.assertTrue(ok) self.assertFalse(exceeded) vals, ok, exceeded = QgsTemporalUtils.calculateDateTimesUsingDuration( QDateTime(QDate(2021, 3, 23), QTime(0, 0, 0)), - QDateTime(QDate(2021, 5, 24), QTime(12, 0, 0)), 'P2W') - self.assertEqual(vals, [QDateTime(2021, 3, 23, 0, 0), QDateTime(2021, 4, 6, 0, 0), QDateTime(2021, 4, 20, 0, 0), - QDateTime(2021, 5, 4, 0, 0), QDateTime(2021, 5, 18, 0, 0)]) + QDateTime(QDate(2021, 5, 24), QTime(12, 0, 0)), + "P2W", + ) + self.assertEqual( + vals, + [ + QDateTime(2021, 3, 23, 0, 0), + QDateTime(2021, 4, 6, 0, 0), + QDateTime(2021, 4, 20, 0, 0), + QDateTime(2021, 5, 4, 0, 0), + QDateTime(2021, 5, 18, 0, 0), + ], + ) self.assertTrue(ok) self.assertFalse(exceeded) vals, ok, exceeded = QgsTemporalUtils.calculateDateTimesUsingDuration( QDateTime(QDate(2021, 3, 23), QTime(0, 0, 0)), - QDateTime(QDate(2021, 4, 7), QTime(12, 0, 0)), 'P2D') - self.assertEqual(vals, - [QDateTime(2021, 3, 23, 0, 0), QDateTime(2021, 3, 25, 0, 0), QDateTime(2021, 3, 27, 0, 0), - QDateTime(2021, 3, 29, 0, 0), QDateTime(2021, 3, 31, 0, 0), QDateTime(2021, 4, 2, 0, 0), - QDateTime(2021, 4, 4, 0, 0), QDateTime(2021, 4, 6, 0, 0)]) + QDateTime(QDate(2021, 4, 7), QTime(12, 0, 0)), + "P2D", + ) + self.assertEqual( + vals, + [ + QDateTime(2021, 3, 23, 0, 0), + QDateTime(2021, 3, 25, 0, 0), + QDateTime(2021, 3, 27, 0, 0), + QDateTime(2021, 3, 29, 0, 0), + QDateTime(2021, 3, 31, 0, 0), + QDateTime(2021, 4, 2, 0, 0), + QDateTime(2021, 4, 4, 0, 0), + QDateTime(2021, 4, 6, 0, 0), + ], + ) self.assertTrue(ok) self.assertFalse(exceeded) # complex mix vals, ok, exceeded = QgsTemporalUtils.calculateDateTimesUsingDuration( QDateTime(QDate(2010, 3, 23), QTime(0, 0, 0)), - QDateTime(QDate(2021, 5, 24), QTime(12, 0, 0)), 'P2Y1M3W4DT5H10M22S') - self.assertEqual(vals, [QDateTime(2010, 3, 23, 0, 0), QDateTime(2012, 5, 18, 5, 10, 22), - QDateTime(2014, 7, 13, 10, 20, 44), QDateTime(2016, 9, 7, 15, 31, 6), - QDateTime(2018, 11, 1, 20, 41, 28), QDateTime(2020, 12, 27, 1, 51, 50)]) + QDateTime(QDate(2021, 5, 24), QTime(12, 0, 0)), + "P2Y1M3W4DT5H10M22S", + ) + self.assertEqual( + vals, + [ + QDateTime(2010, 3, 23, 0, 0), + QDateTime(2012, 5, 18, 5, 10, 22), + QDateTime(2014, 7, 13, 10, 20, 44), + QDateTime(2016, 9, 7, 15, 31, 6), + QDateTime(2018, 11, 1, 20, 41, 28), + QDateTime(2020, 12, 27, 1, 51, 50), + ], + ) self.assertTrue(ok) self.assertFalse(exceeded) def testCalculateDateTimesFromISO8601(self): # invalid duration string - vals, ok, exceeded = QgsTemporalUtils.calculateDateTimesFromISO8601('x') + vals, ok, exceeded = QgsTemporalUtils.calculateDateTimesFromISO8601("x") self.assertFalse(ok) vals, ok, exceeded = QgsTemporalUtils.calculateDateTimesFromISO8601( - 'a-03-23T00:00:00Z/2021-03-24T12:00:00Z/PT12H') + "a-03-23T00:00:00Z/2021-03-24T12:00:00Z/PT12H" + ) self.assertFalse(ok) vals, ok, exceeded = QgsTemporalUtils.calculateDateTimesFromISO8601( - '2021-03-23T00:00:00Z/b-03-24T12:00:00Z/PT12H') + "2021-03-23T00:00:00Z/b-03-24T12:00:00Z/PT12H" + ) self.assertFalse(ok) vals, ok, exceeded = QgsTemporalUtils.calculateDateTimesFromISO8601( - '2021-03-23T00:00:00Z/2021-03-24T12:00:00Z/xc') + "2021-03-23T00:00:00Z/2021-03-24T12:00:00Z/xc" + ) self.assertFalse(ok) vals, ok, exceeded = QgsTemporalUtils.calculateDateTimesFromISO8601( - '2021-03-23T00:00:00Z/2021-03-24T12:00:00Z/PT12H') - self.assertEqual(vals, [QDateTime(QDate(2021, 3, 23), QTime(0, 0, 0, 0), Qt.TimeSpec(1)), - QDateTime(QDate(2021, 3, 23), QTime(12, 0, 0, 0), Qt.TimeSpec(1)), - QDateTime(QDate(2021, 3, 24), QTime(0, 0, 0, 0), Qt.TimeSpec(1)), - QDateTime(QDate(2021, 3, 24), QTime(12, 0, 0, 0), Qt.TimeSpec(1))]) + "2021-03-23T00:00:00Z/2021-03-24T12:00:00Z/PT12H" + ) + self.assertEqual( + vals, + [ + QDateTime(QDate(2021, 3, 23), QTime(0, 0, 0, 0), Qt.TimeSpec(1)), + QDateTime(QDate(2021, 3, 23), QTime(12, 0, 0, 0), Qt.TimeSpec(1)), + QDateTime(QDate(2021, 3, 24), QTime(0, 0, 0, 0), Qt.TimeSpec(1)), + QDateTime(QDate(2021, 3, 24), QTime(12, 0, 0, 0), Qt.TimeSpec(1)), + ], + ) self.assertTrue(ok) self.assertFalse(exceeded) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsterrainprovider.py b/tests/src/python/test_qgsterrainprovider.py index e9db11648ae5..12e657ee1228 100644 --- a/tests/src/python/test_qgsterrainprovider.py +++ b/tests/src/python/test_qgsterrainprovider.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '17/03/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "17/03/2022" +__copyright__ = "Copyright 2022, The QGIS Project" import math import os @@ -38,7 +39,7 @@ def testFlatProvider(self): Test QgsFlatTerrainProvider """ provider = QgsFlatTerrainProvider() - self.assertEqual(provider.type(), 'flat') + self.assertEqual(provider.type(), "flat") self.assertFalse(provider.crs().isValid()) self.assertEqual(provider.heightAt(1, 2), 0) @@ -54,7 +55,7 @@ def testFlatProvider(self): doc = QDomDocument("testdoc") context = QgsReadWriteContext() - parent_elem = doc.createElement('test') + parent_elem = doc.createElement("test") element = provider.writeXml(doc, context) parent_elem.appendChild(element) @@ -78,7 +79,7 @@ def testRasterDemProvider(self): Test QgsRasterDemTerrainProvider """ provider = QgsRasterDemTerrainProvider() - self.assertEqual(provider.type(), 'raster') + self.assertEqual(provider.type(), "raster") # without layer assigned self.assertFalse(provider.crs().isValid()) @@ -86,14 +87,14 @@ def testRasterDemProvider(self): # add raster layer to project p = QgsProject() - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), 'float1-16.tif'), 'rl') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "float1-16.tif"), "rl") self.assertTrue(rl.isValid()) p.addMapLayer(rl) provider.setLayer(rl) self.assertEqual(provider.layer(), rl) - self.assertEqual(provider.crs().authid(), 'EPSG:4326') + self.assertEqual(provider.crs().authid(), "EPSG:4326") self.assertEqual(provider.heightAt(106.4105, -6.6341), 11.0) # outside of raster extent self.assertTrue(math.isnan(provider.heightAt(1, 2))) @@ -114,7 +115,7 @@ def testRasterDemProvider(self): doc = QDomDocument("testdoc") context = QgsReadWriteContext() - parent_elem = doc.createElement('test') + parent_elem = doc.createElement("test") element = provider.writeXml(doc, context) parent_elem.appendChild(element) @@ -152,7 +153,7 @@ def testMeshProvider(self): Test QgsMeshTerrainProvider """ provider = QgsMeshTerrainProvider() - self.assertEqual(provider.type(), 'mesh') + self.assertEqual(provider.type(), "mesh") # without layer assigned self.assertFalse(provider.crs().isValid()) @@ -160,17 +161,21 @@ def testMeshProvider(self): # add mesh layer to project p = QgsProject() - mesh_layer = QgsMeshLayer(os.path.join(unitTestDataPath(), '3d', 'elev_mesh.2dm'), 'mdal', 'mdal') - mesh_layer.setCrs(QgsCoordinateReferenceSystem('EPSG:27700')) + mesh_layer = QgsMeshLayer( + os.path.join(unitTestDataPath(), "3d", "elev_mesh.2dm"), "mdal", "mdal" + ) + mesh_layer.setCrs(QgsCoordinateReferenceSystem("EPSG:27700")) self.assertTrue(mesh_layer.isValid()) p.addMapLayer(mesh_layer) provider.setLayer(mesh_layer) self.assertEqual(provider.layer(), mesh_layer) - self.assertEqual(provider.crs().authid(), 'EPSG:27700') + self.assertEqual(provider.crs().authid(), "EPSG:27700") self.assertTrue(math.isnan(provider.heightAt(1, 2))) - self.assertAlmostEqual(provider.heightAt(321695.2, 129990.5), 89.49743150684921, 5) + self.assertAlmostEqual( + provider.heightAt(321695.2, 129990.5), 89.49743150684921, 5 + ) provider.setOffset(5) self.assertEqual(provider.offset(), 5) @@ -187,7 +192,7 @@ def testMeshProvider(self): doc = QDomDocument("testdoc") context = QgsReadWriteContext() - parent_elem = doc.createElement('test') + parent_elem = doc.createElement("test") element = provider.writeXml(doc, context) parent_elem.appendChild(element) @@ -221,5 +226,5 @@ def testMeshProvider(self): self.assertTrue(provider1.equals(provider2)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgstextblock.py b/tests/src/python/test_qgstextblock.py index 4098054d5fa5..bb41acd836dd 100644 --- a/tests/src/python/test_qgstextblock.py +++ b/tests/src/python/test_qgstextblock.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '12/05/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "12/05/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtGui import QColor @@ -18,7 +19,7 @@ QgsTextBlock, QgsTextFragment, QgsTextBlockFormat, - QgsTextCharacterFormat + QgsTextCharacterFormat, ) import unittest @@ -35,11 +36,11 @@ def testConstructors(self): self.assertEqual(len(block), 0) # single fragment block - fragment = QgsTextFragment('ludicrous gibs!') + fragment = QgsTextFragment("ludicrous gibs!") block = QgsTextBlock(fragment) self.assertEqual(len(block), 1) self.assertEqual(block[0].text(), fragment.text()) - self.assertEqual(block.toPlainText(), 'ludicrous gibs!') + self.assertEqual(block.toPlainText(), "ludicrous gibs!") def test_format(self): block = QgsTextBlock() @@ -50,57 +51,57 @@ def test_format(self): self.assertTrue(block.blockFormat().hasHorizontalAlignmentSet()) def testFromPlainText(self): - block = QgsTextBlock.fromPlainText('abc def') + block = QgsTextBlock.fromPlainText("abc def") self.assertEqual(len(block), 1) - self.assertEqual(block[0].text(), 'abc def') + self.assertEqual(block[0].text(), "abc def") # with format char_format = QgsTextCharacterFormat() char_format.setTextColor(QColor(255, 0, 0)) - block = QgsTextBlock.fromPlainText('abc def', char_format) + block = QgsTextBlock.fromPlainText("abc def", char_format) self.assertEqual(len(block), 1) - self.assertEqual(block[0].text(), 'abc def') + self.assertEqual(block[0].text(), "abc def") self.assertTrue(block[0].characterFormat().textColor().isValid()) - self.assertEqual(block[0].characterFormat().textColor().name(), '#ff0000') + self.assertEqual(block[0].characterFormat().textColor().name(), "#ff0000") def testFromPlainTextWithTabs(self): - block = QgsTextBlock.fromPlainText('b c\td\t gah') - self.assertEqual(block[0].text(), 'b c') + block = QgsTextBlock.fromPlainText("b c\td\t gah") + self.assertEqual(block[0].text(), "b c") self.assertTrue(block[1].isTab()) - self.assertEqual(block[2].text(), 'd') + self.assertEqual(block[2].text(), "d") self.assertTrue(block[3].isTab()) - self.assertEqual(block[4].text(), ' gah') + self.assertEqual(block[4].text(), " gah") - block = QgsTextBlock.fromPlainText('b\t\tc\td') + block = QgsTextBlock.fromPlainText("b\t\tc\td") self.assertEqual(len(block), 6) - self.assertEqual(block[0].text(), 'b') + self.assertEqual(block[0].text(), "b") self.assertTrue(block[1].isTab()) self.assertTrue(block[2].isTab()) - self.assertEqual(block[3].text(), 'c') + self.assertEqual(block[3].text(), "c") self.assertTrue(block[4].isTab()) - self.assertEqual(block[5].text(), 'd') + self.assertEqual(block[5].text(), "d") def testAppend(self): block = QgsTextBlock() self.assertEqual(len(block), 0) - frag = QgsTextFragment('a') + frag = QgsTextFragment("a") block.append(frag) self.assertEqual(len(block), 1) - self.assertEqual(block[0].text(), 'a') - frag = QgsTextFragment('b') + self.assertEqual(block[0].text(), "a") + frag = QgsTextFragment("b") block.append(frag) self.assertEqual(len(block), 2) - self.assertEqual(block[0].text(), 'a') - self.assertEqual(block[1].text(), 'b') + self.assertEqual(block[0].text(), "a") + self.assertEqual(block[1].text(), "b") - self.assertEqual(block.toPlainText(), 'ab') + self.assertEqual(block.toPlainText(), "ab") def testInsert(self): block = QgsTextBlock() self.assertEqual(len(block), 0) - frag = QgsTextFragment('a') + frag = QgsTextFragment("a") with self.assertRaises(IndexError): block.insert(-1, frag) with self.assertRaises(IndexError): @@ -108,56 +109,56 @@ def testInsert(self): self.assertEqual(len(block), 0) block.insert(0, frag) self.assertEqual(len(block), 1) - self.assertEqual(block[0].text(), 'a') - frag = QgsTextFragment('b') + self.assertEqual(block[0].text(), "a") + frag = QgsTextFragment("b") block.insert(0, frag) self.assertEqual(len(block), 2) - self.assertEqual(block[0].text(), 'b') - self.assertEqual(block[1].text(), 'a') + self.assertEqual(block[0].text(), "b") + self.assertEqual(block[1].text(), "a") - frag = QgsTextFragment('c') + frag = QgsTextFragment("c") block.insert(1, frag) self.assertEqual(len(block), 3) - self.assertEqual(block[0].text(), 'b') - self.assertEqual(block[1].text(), 'c') - self.assertEqual(block[2].text(), 'a') + self.assertEqual(block[0].text(), "b") + self.assertEqual(block[1].text(), "c") + self.assertEqual(block[2].text(), "a") - frag = QgsTextFragment('d') + frag = QgsTextFragment("d") with self.assertRaises(IndexError): block.insert(4, frag) block.insert(3, frag) self.assertEqual(len(block), 4) - self.assertEqual(block[0].text(), 'b') - self.assertEqual(block[1].text(), 'c') - self.assertEqual(block[2].text(), 'a') - self.assertEqual(block[3].text(), 'd') + self.assertEqual(block[0].text(), "b") + self.assertEqual(block[1].text(), "c") + self.assertEqual(block[2].text(), "a") + self.assertEqual(block[3].text(), "d") def testAt(self): block = QgsTextBlock() - block.append(QgsTextFragment('a')) - block.append(QgsTextFragment('b')) + block.append(QgsTextFragment("a")) + block.append(QgsTextFragment("b")) self.assertEqual(len(block), 2) - self.assertEqual(block.at(0).text(), 'a') - self.assertEqual(block.at(1).text(), 'b') + self.assertEqual(block.at(0).text(), "a") + self.assertEqual(block.at(1).text(), "b") with self.assertRaises(KeyError): block.at(2) with self.assertRaises(KeyError): block.at(-1) - self.assertEqual(block[0].text(), 'a') - self.assertEqual(block[1].text(), 'b') + self.assertEqual(block[0].text(), "a") + self.assertEqual(block[1].text(), "b") with self.assertRaises(IndexError): _ = block[2] - self.assertEqual(block[-1].text(), 'b') - self.assertEqual(block[-2].text(), 'a') + self.assertEqual(block[-1].text(), "b") + self.assertEqual(block[-2].text(), "a") def testClear(self): block = QgsTextBlock() - block.append(QgsTextFragment('a')) - block.append(QgsTextFragment('b')) + block.append(QgsTextFragment("a")) + block.append(QgsTextFragment("b")) self.assertEqual(len(block), 2) self.assertFalse(block.empty()) @@ -166,12 +167,12 @@ def testClear(self): self.assertTrue(block.empty()) def testCapitalize(self): - fragment = QgsTextFragment('ludicrous gibs!') + fragment = QgsTextFragment("ludicrous gibs!") block = QgsTextBlock(fragment) - block.append(QgsTextFragment('another part')) + block.append(QgsTextFragment("another part")) block.applyCapitalization(QgsStringUtils.Capitalization.TitleCase) - self.assertEqual(block.toPlainText(), 'Ludicrous Gibs!Another Part') + self.assertEqual(block.toPlainText(), "Ludicrous Gibs!Another Part") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgstextblockformat.py b/tests/src/python/test_qgstextblockformat.py index d4e21acc885a..334f01eff6b6 100644 --- a/tests/src/python/test_qgstextblockformat.py +++ b/tests/src/python/test_qgstextblockformat.py @@ -7,6 +7,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + import math from qgis.PyQt.QtGui import QBrush, QColor @@ -15,7 +16,7 @@ QgsFontUtils, QgsRenderContext, QgsTextBlockFormat, - QgsMargins + QgsMargins, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -26,12 +27,14 @@ class TestQgsTextBlockFormat(QgisTestCase): def setUp(self): - QgsFontUtils.loadStandardTestFonts(['Bold', 'Oblique']) + QgsFontUtils.loadStandardTestFonts(["Bold", "Oblique"]) def testGettersSetters(self): format = QgsTextBlockFormat() self.assertFalse(format.hasHorizontalAlignmentSet()) - self.assertEqual(format.horizontalAlignment(), Qgis.TextHorizontalAlignment.Left) + self.assertEqual( + format.horizontalAlignment(), Qgis.TextHorizontalAlignment.Left + ) self.assertTrue(math.isnan(format.lineHeight())) self.assertTrue(math.isnan(format.lineHeightPercentage())) self.assertTrue(math.isnan(format.margins().top())) @@ -43,7 +46,9 @@ def testGettersSetters(self): format.setHasHorizontalAlignmentSet(True) self.assertTrue(format.hasHorizontalAlignmentSet()) format.setHorizontalAlignment(Qgis.TextHorizontalAlignment.Right) - self.assertEqual(format.horizontalAlignment(), Qgis.TextHorizontalAlignment.Right) + self.assertEqual( + format.horizontalAlignment(), Qgis.TextHorizontalAlignment.Right + ) format.setLineHeight(5) self.assertEqual(format.lineHeight(), 5) @@ -59,12 +64,12 @@ def testGettersSetters(self): format.setBackgroundBrush(QBrush(QColor(255, 255, 0))) self.assertTrue(format.hasBackground()) - self.assertEqual(format.backgroundBrush().color().name(), '#ffff00') + self.assertEqual(format.backgroundBrush().color().name(), "#ffff00") format = QgsTextBlockFormat() - format.setBackgroundImagePath('test') + format.setBackgroundImagePath("test") self.assertTrue(format.hasBackground()) - self.assertEqual(format.backgroundImagePath(), 'test') + self.assertEqual(format.backgroundImagePath(), "test") def testUpdateFont(self): context = QgsRenderContext() @@ -76,5 +81,5 @@ def testUpdateFont(self): # no effect for now... -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgstextcharacterformat.py b/tests/src/python/test_qgstextcharacterformat.py index 7d7ab4cffbae..471153fe6cf5 100644 --- a/tests/src/python/test_qgstextcharacterformat.py +++ b/tests/src/python/test_qgstextcharacterformat.py @@ -7,15 +7,13 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '12/05/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "12/05/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QSizeF -from qgis.PyQt.QtGui import ( - QColor, - QBrush -) +from qgis.PyQt.QtGui import QColor, QBrush from qgis.core import ( Qgis, QgsFontUtils, @@ -31,7 +29,7 @@ class TestQgsTextCharacterFormat(QgisTestCase): def setUp(self): - QgsFontUtils.loadStandardTestFonts(['Bold', 'Oblique']) + QgsFontUtils.loadStandardTestFonts(["Bold", "Oblique"]) def testGettersSetters(self): format = QgsTextCharacterFormat() @@ -42,18 +40,24 @@ def testGettersSetters(self): self.assertEqual(format.fontPointSize(), -1) self.assertFalse(format.family()) self.assertFalse(format.hasVerticalAlignmentSet()) - self.assertEqual(format.verticalAlignment(), Qgis.TextCharacterVerticalAlignment.Normal) + self.assertEqual( + format.verticalAlignment(), Qgis.TextCharacterVerticalAlignment.Normal + ) self.assertFalse(format.hasBackground()) format.setTextColor(QColor(255, 0, 0)) self.assertTrue(format.textColor().isValid()) - self.assertEqual(format.textColor().name(), '#ff0000') + self.assertEqual(format.textColor().name(), "#ff0000") format.setUnderline(QgsTextCharacterFormat.BooleanValue.SetTrue) - self.assertEqual(format.underline(), QgsTextCharacterFormat.BooleanValue.SetTrue) + self.assertEqual( + format.underline(), QgsTextCharacterFormat.BooleanValue.SetTrue + ) format.setStrikeOut(QgsTextCharacterFormat.BooleanValue.SetTrue) - self.assertEqual(format.strikeOut(), QgsTextCharacterFormat.BooleanValue.SetTrue) + self.assertEqual( + format.strikeOut(), QgsTextCharacterFormat.BooleanValue.SetTrue + ) format.setOverline(QgsTextCharacterFormat.BooleanValue.SetTrue) self.assertEqual(format.overline(), QgsTextCharacterFormat.BooleanValue.SetTrue) @@ -61,29 +65,31 @@ def testGettersSetters(self): format.setFontPointSize(12.5) self.assertEqual(format.fontPointSize(), 12.5) - format.setFamily('comic sans') - self.assertEqual(format.family(), 'comic sans') + format.setFamily("comic sans") + self.assertEqual(format.family(), "comic sans") format.setHasVerticalAlignmentSet(True) self.assertTrue(format.hasVerticalAlignmentSet()) format.setVerticalAlignment(Qgis.TextCharacterVerticalAlignment.SuperScript) - self.assertEqual(format.verticalAlignment(), Qgis.TextCharacterVerticalAlignment.SuperScript) + self.assertEqual( + format.verticalAlignment(), Qgis.TextCharacterVerticalAlignment.SuperScript + ) self.assertFalse(format.imagePath()) self.assertEqual(format.imageSize(), QSizeF()) - format.setImagePath('my.jpg') + format.setImagePath("my.jpg") format.setImageSize(QSizeF(40, 60)) - self.assertEqual(format.imagePath(), 'my.jpg') + self.assertEqual(format.imagePath(), "my.jpg") self.assertEqual(format.imageSize(), QSizeF(40, 60)) format.setBackgroundBrush(QBrush(QColor(255, 255, 0))) self.assertTrue(format.hasBackground()) - self.assertEqual(format.backgroundBrush().color().name(), '#ffff00') + self.assertEqual(format.backgroundBrush().color().name(), "#ffff00") format = QgsTextCharacterFormat() - format.setBackgroundImagePath('test') + format.setBackgroundImagePath("test") self.assertTrue(format.hasBackground()) - self.assertEqual(format.backgroundImagePath(), 'test') + self.assertEqual(format.backgroundImagePath(), "test") def testUpdateFont(self): context = QgsRenderContext() @@ -148,14 +154,14 @@ def testUpdateFont(self): self.assertEqual(font.pointSizeF(), old_size) self.assertEqual(font.family(), old_family) - format.setFamily('Serif') + format.setFamily("Serif") format.updateFontForFormat(font, context) - self.assertEqual(font.family(), 'Serif') - format.setFamily('') + self.assertEqual(font.family(), "Serif") + format.setFamily("") font.setFamily(old_family) format.updateFontForFormat(font, context) self.assertEqual(font.family(), old_family) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgstextdocument.py b/tests/src/python/test_qgstextdocument.py index d27a4b8ef0e4..78b735540410 100644 --- a/tests/src/python/test_qgstextdocument.py +++ b/tests/src/python/test_qgstextdocument.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '12/05/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "12/05/2020" +__copyright__ = "Copyright 2020, The QGIS Project" import math @@ -23,7 +24,7 @@ QgsTextDocument, QgsTextFragment, QgsTextFormat, - QgsMargins + QgsMargins, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -45,319 +46,320 @@ def testConstructors(self): self.assertEqual(len(doc[0]), 0) # single fragment document - fragment = QgsTextFragment('ludicrous gibs!') + fragment = QgsTextFragment("ludicrous gibs!") doc = QgsTextDocument(fragment) self.assertEqual(len(doc), 1) self.assertEqual(len(doc[0]), 1) self.assertEqual(doc[0][0].text(), fragment.text()) def testFromPlainText(self): - doc = QgsTextDocument.fromPlainText(['a', 'b c d', 'e']) + doc = QgsTextDocument.fromPlainText(["a", "b c d", "e"]) self.assertEqual(len(doc), 3) self.assertEqual(len(doc[0]), 1) - self.assertEqual(doc[0][0].text(), 'a') + self.assertEqual(doc[0][0].text(), "a") self.assertEqual(len(doc[1]), 1) - self.assertEqual(doc[1][0].text(), 'b c d') + self.assertEqual(doc[1][0].text(), "b c d") self.assertEqual(len(doc[2]), 1) - self.assertEqual(doc[2][0].text(), 'e') + self.assertEqual(doc[2][0].text(), "e") def testFromPlainTextWithTabs(self): - doc = QgsTextDocument.fromPlainText(['a', 'b c\td\t gah', 'e']) + doc = QgsTextDocument.fromPlainText(["a", "b c\td\t gah", "e"]) self.assertEqual(len(doc), 3) self.assertEqual(len(doc[0]), 1) - self.assertEqual(doc[0][0].text(), 'a') + self.assertEqual(doc[0][0].text(), "a") self.assertEqual(len(doc[1]), 5) - self.assertEqual(doc[1][0].text(), 'b c') + self.assertEqual(doc[1][0].text(), "b c") self.assertTrue(doc[1][1].isTab()) - self.assertEqual(doc[1][2].text(), 'd') + self.assertEqual(doc[1][2].text(), "d") self.assertTrue(doc[1][3].isTab()) - self.assertEqual(doc[1][4].text(), ' gah') + self.assertEqual(doc[1][4].text(), " gah") self.assertEqual(len(doc[2]), 1) - self.assertEqual(doc[2][0].text(), 'e') + self.assertEqual(doc[2][0].text(), "e") - doc = QgsTextDocument.fromPlainText(['b\t\tc\td']) + doc = QgsTextDocument.fromPlainText(["b\t\tc\td"]) self.assertEqual(len(doc), 1) self.assertEqual(len(doc[0]), 6) - self.assertEqual(doc[0][0].text(), 'b') + self.assertEqual(doc[0][0].text(), "b") self.assertTrue(doc[0][1].isTab()) self.assertTrue(doc[0][2].isTab()) - self.assertEqual(doc[0][3].text(), 'c') + self.assertEqual(doc[0][3].text(), "c") self.assertTrue(doc[0][4].isTab()) - self.assertEqual(doc[0][5].text(), 'd') + self.assertEqual(doc[0][5].text(), "d") def testFromHtml(self): - doc = QgsTextDocument.fromHtml(['abc
    def ghi
    jkl
    ', 'b c d', 'e']) + doc = QgsTextDocument.fromHtml( + [ + 'abc
    def ghi
    jkl
    ', + "b c d", + "e", + ] + ) self.assertEqual(len(doc), 5) self.assertEqual(len(doc[0]), 1) self.assertFalse(doc[0].blockFormat().hasHorizontalAlignmentSet()) - self.assertEqual(doc[0][0].text(), 'abc') - self.assertEqual(doc[0][0].characterFormat().underline(), QgsTextCharacterFormat.BooleanValue.NotSet) - self.assertEqual(doc[0][0].characterFormat().italic(), QgsTextCharacterFormat.BooleanValue.NotSet) + self.assertEqual(doc[0][0].text(), "abc") + self.assertEqual( + doc[0][0].characterFormat().underline(), + QgsTextCharacterFormat.BooleanValue.NotSet, + ) + self.assertEqual( + doc[0][0].characterFormat().italic(), + QgsTextCharacterFormat.BooleanValue.NotSet, + ) self.assertEqual(doc[0][0].characterFormat().fontWeight(), -1) self.assertFalse(doc[0][0].characterFormat().family()) self.assertEqual(doc[0][0].characterFormat().fontPointSize(), -1) self.assertFalse(doc[0][0].characterFormat().textColor().isValid()) self.assertFalse(doc[0][0].characterFormat().hasVerticalAlignmentSet()) self.assertEqual(len(doc[1]), 2) - self.assertEqual(doc[1][0].text(), 'def') - self.assertEqual(doc[1][0].characterFormat().underline(), QgsTextCharacterFormat.BooleanValue.SetTrue) - self.assertEqual(doc[1][0].characterFormat().italic(), QgsTextCharacterFormat.BooleanValue.SetTrue) + self.assertEqual(doc[1][0].text(), "def") + self.assertEqual( + doc[1][0].characterFormat().underline(), + QgsTextCharacterFormat.BooleanValue.SetTrue, + ) + self.assertEqual( + doc[1][0].characterFormat().italic(), + QgsTextCharacterFormat.BooleanValue.SetTrue, + ) self.assertTrue(doc[1].blockFormat().hasHorizontalAlignmentSet()) - self.assertEqual(doc[1].blockFormat().horizontalAlignment(), Qgis.TextHorizontalAlignment.Right) - if int(QT_VERSION_STR.split('.')[0]) >= 6: + self.assertEqual( + doc[1].blockFormat().horizontalAlignment(), + Qgis.TextHorizontalAlignment.Right, + ) + if int(QT_VERSION_STR.split(".")[0]) >= 6: self.assertEqual(doc[1][0].characterFormat().fontWeight(), 700) else: self.assertEqual(doc[1][0].characterFormat().fontWeight(), 75) - self.assertEqual(doc[1][0].characterFormat().family(), 'Serif') - self.assertEqual(doc[1][0].characterFormat().textColor().name(), '#ff0000') + self.assertEqual(doc[1][0].characterFormat().family(), "Serif") + self.assertEqual(doc[1][0].characterFormat().textColor().name(), "#ff0000") self.assertEqual(doc[1][0].characterFormat().fontPointSize(), 15) self.assertFalse(doc[1][0].characterFormat().hasVerticalAlignmentSet()) - self.assertEqual(doc[1][1].text(), ' ghi') - self.assertEqual(doc[1][1].characterFormat().underline(), QgsTextCharacterFormat.BooleanValue.NotSet) - self.assertEqual(doc[1][1].characterFormat().italic(), QgsTextCharacterFormat.BooleanValue.NotSet) + self.assertEqual(doc[1][1].text(), " ghi") + self.assertEqual( + doc[1][1].characterFormat().underline(), + QgsTextCharacterFormat.BooleanValue.NotSet, + ) + self.assertEqual( + doc[1][1].characterFormat().italic(), + QgsTextCharacterFormat.BooleanValue.NotSet, + ) self.assertEqual(doc[1][1].characterFormat().fontWeight(), -1) self.assertFalse(doc[1][1].characterFormat().family()) - self.assertEqual(doc[1][1].characterFormat().textColor().name(), '#ff0000') + self.assertEqual(doc[1][1].characterFormat().textColor().name(), "#ff0000") self.assertEqual(doc[1][1].characterFormat().fontPointSize(), -1) self.assertFalse(doc[1][1].characterFormat().hasVerticalAlignmentSet()) self.assertEqual(len(doc[2]), 1) - self.assertEqual(doc[2][0].text(), 'jkl') + self.assertEqual(doc[2][0].text(), "jkl") self.assertEqual(len(doc[3]), 1) - self.assertEqual(doc[3][0].text(), 'b c d') + self.assertEqual(doc[3][0].text(), "b c d") self.assertEqual(len(doc[4]), 1) - self.assertEqual(doc[4][0].text(), 'e') + self.assertEqual(doc[4][0].text(), "e") # with one line break - doc = QgsTextDocument.fromHtml(['a b
    c
    d']) + doc = QgsTextDocument.fromHtml( + ['a b
    c
    d'] + ) self.assertEqual(len(doc), 2) - self.assertEqual(doc[0][0].characterFormat().textColor().name(), '#ff0000') - self.assertEqual(doc[0][0].text(), 'a ') - self.assertEqual(doc[0][1].characterFormat().textColor().name(), '#0000ff') - self.assertEqual(doc[0][1].text(), 'b') + self.assertEqual(doc[0][0].characterFormat().textColor().name(), "#ff0000") + self.assertEqual(doc[0][0].text(), "a ") + self.assertEqual(doc[0][1].characterFormat().textColor().name(), "#0000ff") + self.assertEqual(doc[0][1].text(), "b") self.assertEqual(len(doc[1]), 2) - self.assertEqual(doc[1][0].characterFormat().textColor().name(), '#ff0000') - self.assertEqual(doc[1][0].text(), 'c') - self.assertEqual(doc[1][1].characterFormat().textColor().name(), '#000000') - self.assertEqual(doc[1][1].text(), 'd') + self.assertEqual(doc[1][0].characterFormat().textColor().name(), "#ff0000") + self.assertEqual(doc[1][0].text(), "c") + self.assertEqual(doc[1][1].characterFormat().textColor().name(), "#000000") + self.assertEqual(doc[1][1].text(), "d") # with two line breaks - doc = QgsTextDocument.fromHtml(['a
    b
    c
    d']) + doc = QgsTextDocument.fromHtml( + [ + 'a
    b
    c
    d' + ] + ) self.assertEqual(len(doc), 3) - self.assertEqual(doc[0][0].characterFormat().textColor().name(), '#ff0000') - self.assertEqual(doc[0][0].text(), 'a') - self.assertEqual(doc[1][0].characterFormat().textColor().name(), '#0000ff') - self.assertEqual(doc[1][0].text(), 'b') + self.assertEqual(doc[0][0].characterFormat().textColor().name(), "#ff0000") + self.assertEqual(doc[0][0].text(), "a") + self.assertEqual(doc[1][0].characterFormat().textColor().name(), "#0000ff") + self.assertEqual(doc[1][0].text(), "b") self.assertEqual(len(doc[2]), 2) - self.assertEqual(doc[2][0].characterFormat().textColor().name(), '#ff0000') - self.assertEqual(doc[2][0].text(), 'c') - self.assertEqual(doc[2][1].characterFormat().textColor().name(), '#000000') - self.assertEqual(doc[2][1].text(), 'd') + self.assertEqual(doc[2][0].characterFormat().textColor().name(), "#ff0000") + self.assertEqual(doc[2][0].text(), "c") + self.assertEqual(doc[2][1].characterFormat().textColor().name(), "#000000") + self.assertEqual(doc[2][1].text(), "d") # with tabs - doc = QgsTextDocument.fromHtml(['a\tb\tcd']) + doc = QgsTextDocument.fromHtml( + ['a\tb\tcd'] + ) self.assertEqual(len(doc), 1) self.assertEqual(len(doc[0]), 6) - self.assertEqual(doc[0][0].text(), 'a') - self.assertEqual(doc[0][0].characterFormat().textColor().name(), '#ff0000') + self.assertEqual(doc[0][0].text(), "a") + self.assertEqual(doc[0][0].characterFormat().textColor().name(), "#ff0000") self.assertTrue(doc[0][1].isTab()) - self.assertEqual(doc[0][2].text(), 'b') - self.assertEqual(doc[0][2].characterFormat().textColor().name(), '#0000ff') + self.assertEqual(doc[0][2].text(), "b") + self.assertEqual(doc[0][2].characterFormat().textColor().name(), "#0000ff") self.assertTrue(doc[0][3].isTab()) - self.assertEqual(doc[0][4].text(), 'c') - self.assertEqual(doc[0][4].characterFormat().textColor().name(), '#ff0000') + self.assertEqual(doc[0][4].text(), "c") + self.assertEqual(doc[0][4].characterFormat().textColor().name(), "#ff0000") # combination tabs and brs - doc = QgsTextDocument.fromHtml(['aaaa aaa\tb
    c
    d']) + doc = QgsTextDocument.fromHtml( + [ + 'aaaa aaa\tb
    c
    d' + ] + ) self.assertEqual(len(doc), 2) self.assertEqual(len(doc[0]), 3) - self.assertEqual(doc[0][0].text(), 'aaaa aaa') - self.assertEqual(doc[0][0].characterFormat().textColor().name(), '#ff0000') + self.assertEqual(doc[0][0].text(), "aaaa aaa") + self.assertEqual(doc[0][0].characterFormat().textColor().name(), "#ff0000") self.assertTrue(doc[0][1].isTab()) - self.assertEqual(doc[0][2].text(), 'b') - self.assertEqual(doc[0][2].characterFormat().textColor().name(), '#0000ff') + self.assertEqual(doc[0][2].text(), "b") + self.assertEqual(doc[0][2].characterFormat().textColor().name(), "#0000ff") self.assertEqual(len(doc[1]), 2) - self.assertEqual(doc[1][0].text(), 'c') - self.assertEqual(doc[1][0].characterFormat().textColor().name(), '#ff0000') - self.assertEqual(doc[1][1].text(), 'd') - self.assertEqual(doc[1][1].characterFormat().textColor().name(), '#000000') + self.assertEqual(doc[1][0].text(), "c") + self.assertEqual(doc[1][0].characterFormat().textColor().name(), "#ff0000") + self.assertEqual(doc[1][1].text(), "d") + self.assertEqual(doc[1][1].characterFormat().textColor().name(), "#000000") # Class || '\t' || 'a
    b\tcdcd' # combination tabs and newline, different string - doc = QgsTextDocument.fromHtml(['Class\ta
    b\tcdcd']) + doc = QgsTextDocument.fromHtml(["Class\ta
    b\tcdcd"]) self.assertEqual(len(doc), 2) self.assertEqual(len(doc[0]), 3) - self.assertEqual(doc[0][0].text(), 'Class') + self.assertEqual(doc[0][0].text(), "Class") self.assertTrue(doc[0][1].isTab()) - self.assertEqual(doc[0][2].text(), 'a') + self.assertEqual(doc[0][2].text(), "a") self.assertEqual(len(doc[1]), 3) - self.assertEqual(doc[1][0].text(), 'b') + self.assertEqual(doc[1][0].text(), "b") self.assertTrue(doc[1][1].isTab()) - self.assertEqual(doc[1][2].text(), 'cdcd') + self.assertEqual(doc[1][2].text(), "cdcd") # with line heights - doc = QgsTextDocument.fromHtml(['
    test
    test2
    test3
    ']) + doc = QgsTextDocument.fromHtml( + [ + '
    test
    test2
    test3
    ' + ] + ) self.assertEqual(len(doc), 3) self.assertEqual(len(doc[0]), 1) - self.assertEqual(doc[0][0].text(), 'test') - self.assertTrue(math.isnan( - doc[0].blockFormat().lineHeight() - )) - self.assertTrue(math.isnan( - doc[0].blockFormat().lineHeightPercentage() - )) + self.assertEqual(doc[0][0].text(), "test") + self.assertTrue(math.isnan(doc[0].blockFormat().lineHeight())) + self.assertTrue(math.isnan(doc[0].blockFormat().lineHeightPercentage())) self.assertEqual(len(doc[1]), 1) - self.assertEqual(doc[1][0].text(), 'test2') + self.assertEqual(doc[1][0].text(), "test2") self.assertEqual(doc[1].blockFormat().lineHeight(), 40) - self.assertTrue(math.isnan( - doc[1].blockFormat().lineHeightPercentage() - )) + self.assertTrue(math.isnan(doc[1].blockFormat().lineHeightPercentage())) self.assertEqual(len(doc[2]), 1) - self.assertEqual(doc[2][0].text(), 'test3') - self.assertTrue(math.isnan( - doc[2].blockFormat().lineHeight() - )) - self.assertEqual( - doc[2].blockFormat().lineHeightPercentage(), 0.2 - ) + self.assertEqual(doc[2][0].text(), "test3") + self.assertTrue(math.isnan(doc[2].blockFormat().lineHeight())) + self.assertEqual(doc[2].blockFormat().lineHeightPercentage(), 0.2) # with margins # note that there's a weird Qt limitation here, in that negative top margins are always completely ignored! # seems Qt's css parser excludes these... - doc = QgsTextDocument.fromHtml(['
    test
    test2
    test3
    test4
    ']) + doc = QgsTextDocument.fromHtml( + [ + '
    test
    test2
    test3
    test4
    ' + ] + ) self.assertEqual(len(doc), 4) self.assertEqual(len(doc[0]), 1) - self.assertEqual(doc[0][0].text(), 'test') - self.assertTrue(math.isnan( - doc[0].blockFormat().margins().left() - )) - self.assertTrue(math.isnan( - doc[0].blockFormat().margins().right() - )) - self.assertTrue(math.isnan( - doc[0].blockFormat().margins().top() - )) - self.assertTrue(math.isnan( - doc[0].blockFormat().margins().bottom() - )) + self.assertEqual(doc[0][0].text(), "test") + self.assertTrue(math.isnan(doc[0].blockFormat().margins().left())) + self.assertTrue(math.isnan(doc[0].blockFormat().margins().right())) + self.assertTrue(math.isnan(doc[0].blockFormat().margins().top())) + self.assertTrue(math.isnan(doc[0].blockFormat().margins().bottom())) self.assertEqual(len(doc[1]), 1) - self.assertEqual(doc[1][0].text(), 'test2') - self.assertEqual( - doc[1].blockFormat().margins(), QgsMargins(1, 3, -2, -4) - ) + self.assertEqual(doc[1][0].text(), "test2") + self.assertEqual(doc[1].blockFormat().margins(), QgsMargins(1, 3, -2, -4)) self.assertEqual(len(doc[2]), 1) - self.assertEqual(doc[2][0].text(), 'test3') - self.assertEqual( - doc[2].blockFormat().margins(), QgsMargins(-14, 11, -12, -13) - ) + self.assertEqual(doc[2][0].text(), "test3") + self.assertEqual(doc[2].blockFormat().margins(), QgsMargins(-14, 11, -12, -13)) self.assertEqual(len(doc[3]), 1) - self.assertEqual(doc[3][0].text(), 'test4') - self.assertEqual( - doc[3].blockFormat().margins().left(), 1 - ) - self.assertEqual( - doc[3].blockFormat().margins().right(), 2 - ) - self.assertTrue(math.isnan( - doc[3].blockFormat().margins().top() - )) - self.assertTrue(math.isnan( - doc[3].blockFormat().margins().bottom() - )) + self.assertEqual(doc[3][0].text(), "test4") + self.assertEqual(doc[3].blockFormat().margins().left(), 1) + self.assertEqual(doc[3].blockFormat().margins().right(), 2) + self.assertTrue(math.isnan(doc[3].blockFormat().margins().top())) + self.assertTrue(math.isnan(doc[3].blockFormat().margins().bottom())) # ensure that margins are NOT set for P / H1-6 elements # we didn't use to respect these and cannot change the rendering of existing projects now - doc = QgsTextDocument.fromHtml(['

    p

    h1

    h2

    h6
    ']) + doc = QgsTextDocument.fromHtml(["

    p

    h1

    h2

    h6
    "]) self.assertEqual(len(doc), 4) self.assertEqual(len(doc[0]), 1) - self.assertEqual(doc[0][0].text(), 'p') - self.assertTrue(math.isnan( - doc[0].blockFormat().margins().left() - )) - self.assertTrue(math.isnan( - doc[0].blockFormat().margins().right() - )) - self.assertTrue(math.isnan( - doc[0].blockFormat().margins().top() - )) - self.assertTrue(math.isnan( - doc[0].blockFormat().margins().bottom() - )) - self.assertTrue(math.isnan( - doc[1].blockFormat().margins().left() - )) - self.assertTrue(math.isnan( - doc[1].blockFormat().margins().right() - )) - self.assertTrue(math.isnan( - doc[1].blockFormat().margins().top() - )) - self.assertTrue(math.isnan( - doc[1].blockFormat().margins().bottom() - )) - self.assertTrue(math.isnan( - doc[2].blockFormat().margins().left() - )) - self.assertTrue(math.isnan( - doc[2].blockFormat().margins().right() - )) - self.assertTrue(math.isnan( - doc[2].blockFormat().margins().top() - )) - self.assertTrue(math.isnan( - doc[2].blockFormat().margins().bottom() - )) - self.assertTrue(math.isnan( - doc[3].blockFormat().margins().left() - )) - self.assertTrue(math.isnan( - doc[3].blockFormat().margins().right() - )) - self.assertTrue(math.isnan( - doc[3].blockFormat().margins().top() - )) - self.assertTrue(math.isnan( - doc[3].blockFormat().margins().bottom() - )) + self.assertEqual(doc[0][0].text(), "p") + self.assertTrue(math.isnan(doc[0].blockFormat().margins().left())) + self.assertTrue(math.isnan(doc[0].blockFormat().margins().right())) + self.assertTrue(math.isnan(doc[0].blockFormat().margins().top())) + self.assertTrue(math.isnan(doc[0].blockFormat().margins().bottom())) + self.assertTrue(math.isnan(doc[1].blockFormat().margins().left())) + self.assertTrue(math.isnan(doc[1].blockFormat().margins().right())) + self.assertTrue(math.isnan(doc[1].blockFormat().margins().top())) + self.assertTrue(math.isnan(doc[1].blockFormat().margins().bottom())) + self.assertTrue(math.isnan(doc[2].blockFormat().margins().left())) + self.assertTrue(math.isnan(doc[2].blockFormat().margins().right())) + self.assertTrue(math.isnan(doc[2].blockFormat().margins().top())) + self.assertTrue(math.isnan(doc[2].blockFormat().margins().bottom())) + self.assertTrue(math.isnan(doc[3].blockFormat().margins().left())) + self.assertTrue(math.isnan(doc[3].blockFormat().margins().right())) + self.assertTrue(math.isnan(doc[3].blockFormat().margins().top())) + self.assertTrue(math.isnan(doc[3].blockFormat().margins().bottom())) def test_from_html_with_background(self): - doc = QgsTextDocument.fromHtml(['
    redyellowoutside span
    ']) + doc = QgsTextDocument.fromHtml( + [ + '
    redyellowoutside span
    ' + ] + ) self.assertTrue(doc.hasBackgrounds()) self.assertEqual(len(doc), 1) self.assertTrue(doc[0].blockFormat().hasBackground()) - self.assertEqual(doc[0].blockFormat().backgroundBrush().color().name(), '#0000ff') + self.assertEqual( + doc[0].blockFormat().backgroundBrush().color().name(), "#0000ff" + ) self.assertEqual(len(doc[0]), 3) self.assertTrue(doc[0].hasBackgrounds()) self.assertTrue(doc[0][0].characterFormat().hasBackground()) - self.assertEqual(doc[0][0].characterFormat().backgroundBrush().color().name(), '#ff0000') + self.assertEqual( + doc[0][0].characterFormat().backgroundBrush().color().name(), "#ff0000" + ) self.assertTrue(doc[0][1].characterFormat().hasBackground()) - self.assertEqual(doc[0][1].characterFormat().backgroundBrush().color().name(), '#ffff00') + self.assertEqual( + doc[0][1].characterFormat().backgroundBrush().color().name(), "#ffff00" + ) self.assertFalse(doc[0][2].characterFormat().hasBackground()) # no backgound - doc = QgsTextDocument.fromHtml(['
    redyellowoutside span
    ']) + doc = QgsTextDocument.fromHtml( + ["
    redyellowoutside span
    "] + ) self.assertFalse(doc.hasBackgrounds()) self.assertFalse(doc[0].hasBackgrounds()) # background paths - doc = QgsTextDocument.fromHtml(['
    redyellowoutside span
    ']) + doc = QgsTextDocument.fromHtml( + [ + '
    redyellowoutside span
    ' + ] + ) self.assertTrue(doc.hasBackgrounds()) self.assertEqual(len(doc), 1) # there's a bug in Qt's css parsing here -- the background-image incorrectly gets attached to the spans, not the div! @@ -365,74 +367,94 @@ def test_from_html_with_background(self): self.assertTrue(doc[0].hasBackgrounds()) self.assertTrue(doc[0][0].characterFormat().hasBackground()) - self.assertEqual(doc[0][0].characterFormat().backgroundBrush().color().name(), '#ff0000') + self.assertEqual( + doc[0][0].characterFormat().backgroundBrush().color().name(), "#ff0000" + ) self.assertFalse(doc[0][0].characterFormat().backgroundImagePath()) self.assertTrue(doc[0][1].characterFormat().hasBackground()) - self.assertEqual(doc[0][1].characterFormat().backgroundImagePath(), 'something_else') + self.assertEqual( + doc[0][1].characterFormat().backgroundImagePath(), "something_else" + ) self.assertTrue(doc[0][2].characterFormat().hasBackground()) - self.assertEqual(doc[0][2].characterFormat().backgroundImagePath(), - 'something') + self.assertEqual(doc[0][2].characterFormat().backgroundImagePath(), "something") def testFromTextAndFormat(self): format = QgsTextFormat() format.setAllowHtmlFormatting(False) - doc = QgsTextDocument.fromTextAndFormat(['abc def'], format) + doc = QgsTextDocument.fromTextAndFormat(["abc def"], format) self.assertEqual(len(doc), 1) self.assertEqual(len(doc[0]), 1) - self.assertEqual(doc[0][0].text(), 'abc def') + self.assertEqual(doc[0][0].text(), "abc def") # as html format.setAllowHtmlFormatting(True) - doc = QgsTextDocument.fromTextAndFormat(['abc def'], format) + doc = QgsTextDocument.fromTextAndFormat(["abc def"], format) self.assertEqual(len(doc), 1) self.assertEqual(len(doc[0]), 2) - self.assertEqual(doc[0][0].text(), 'abc ') - self.assertEqual(doc[0][1].text(), 'def') + self.assertEqual(doc[0][0].text(), "abc ") + self.assertEqual(doc[0][1].text(), "def") # with capitalization option format.setCapitalization(Qgis.Capitalization.AllUppercase) format.setAllowHtmlFormatting(False) - doc = QgsTextDocument.fromTextAndFormat(['abc def'], format) + doc = QgsTextDocument.fromTextAndFormat(["abc def"], format) self.assertEqual(len(doc), 1) self.assertEqual(len(doc[0]), 1) - self.assertEqual(doc[0][0].text(), 'ABC DEF') + self.assertEqual(doc[0][0].text(), "ABC DEF") def testFromHtmlVerticalAlignment(self): - doc = QgsTextDocument.fromHtml(['abc
    defextra ghi
    supcss']) + doc = QgsTextDocument.fromHtml( + [ + 'abc
    defextra ghi
    supcss' + ] + ) self.assertEqual(len(doc), 3) self.assertEqual(len(doc[0]), 1) - self.assertEqual(doc[0][0].text(), 'abc') + self.assertEqual(doc[0][0].text(), "abc") self.assertFalse(doc[0][0].characterFormat().hasVerticalAlignmentSet()) self.assertEqual(len(doc[1]), 3) - self.assertEqual(doc[1][0].text(), 'def') + self.assertEqual(doc[1][0].text(), "def") self.assertTrue(doc[1][0].characterFormat().hasVerticalAlignmentSet()) - self.assertEqual(doc[1][0].characterFormat().verticalAlignment(), Qgis.TextCharacterVerticalAlignment.SubScript) - self.assertEqual(doc[1][1].text(), 'extra') + self.assertEqual( + doc[1][0].characterFormat().verticalAlignment(), + Qgis.TextCharacterVerticalAlignment.SubScript, + ) + self.assertEqual(doc[1][1].text(), "extra") self.assertTrue(doc[1][1].characterFormat().hasVerticalAlignmentSet()) - self.assertEqual(doc[1][1].characterFormat().verticalAlignment(), Qgis.TextCharacterVerticalAlignment.SubScript) - self.assertEqual(doc[1][2].text(), ' ghi') + self.assertEqual( + doc[1][1].characterFormat().verticalAlignment(), + Qgis.TextCharacterVerticalAlignment.SubScript, + ) + self.assertEqual(doc[1][2].text(), " ghi") self.assertFalse(doc[1][2].characterFormat().hasVerticalAlignmentSet()) self.assertEqual(len(doc[2]), 2) - self.assertEqual(doc[2][0].text(), 'sup') + self.assertEqual(doc[2][0].text(), "sup") self.assertTrue(doc[2][0].characterFormat().hasVerticalAlignmentSet()) - self.assertEqual(doc[2][0].characterFormat().verticalAlignment(), Qgis.TextCharacterVerticalAlignment.SuperScript) - self.assertEqual(doc[2][1].text(), 'css') + self.assertEqual( + doc[2][0].characterFormat().verticalAlignment(), + Qgis.TextCharacterVerticalAlignment.SuperScript, + ) + self.assertEqual(doc[2][1].text(), "css") self.assertTrue(doc[2][1].characterFormat().hasVerticalAlignmentSet()) - self.assertEqual(doc[2][1].characterFormat().verticalAlignment(), Qgis.TextCharacterVerticalAlignment.SubScript) + self.assertEqual( + doc[2][1].characterFormat().verticalAlignment(), + Qgis.TextCharacterVerticalAlignment.SubScript, + ) def testImage(self): - doc = QgsTextDocument.fromHtml([ - 'abcextra']) + doc = QgsTextDocument.fromHtml( + ['abcextra'] + ) self.assertEqual(len(doc), 1) self.assertEqual(len(doc[0]), 3) - self.assertEqual(doc[0][0].text(), 'abc') + self.assertEqual(doc[0][0].text(), "abc") self.assertFalse(doc[0][0].isImage()) self.assertFalse(doc[0][0].characterFormat().imagePath()) self.assertTrue(doc[0][1].isImage()) self.assertFalse(doc[0][1].text()) - self.assertEqual(doc[0][1].characterFormat().imagePath(), 'qgis.jpg') + self.assertEqual(doc[0][1].characterFormat().imagePath(), "qgis.jpg") self.assertEqual(doc[0][1].characterFormat().imageSize(), QSizeF(40, 60)) - self.assertEqual(doc[0][2].text(), 'extra') + self.assertEqual(doc[0][2].text(), "extra") self.assertFalse(doc[0][2].isImage()) self.assertTrue(doc[0][2].characterFormat().italic()) @@ -450,114 +472,131 @@ def testInsert(self): self.assertEqual(len(doc), 0) with self.assertRaises(IndexError): - doc.insert(-1, QgsTextBlock(QgsTextFragment('a'))) + doc.insert(-1, QgsTextBlock(QgsTextFragment("a"))) with self.assertRaises(IndexError): - doc.insert(1, QgsTextBlock(QgsTextFragment('a'))) + doc.insert(1, QgsTextBlock(QgsTextFragment("a"))) self.assertEqual(len(doc), 0) - doc.insert(0, QgsTextBlock(QgsTextFragment('a'))) + doc.insert(0, QgsTextBlock(QgsTextFragment("a"))) self.assertEqual(len(doc), 1) - self.assertEqual(doc[0][0].text(), 'a') + self.assertEqual(doc[0][0].text(), "a") - doc.insert(0, QgsTextBlock(QgsTextFragment('b'))) + doc.insert(0, QgsTextBlock(QgsTextFragment("b"))) self.assertEqual(len(doc), 2) - self.assertEqual(doc[0][0].text(), 'b') - self.assertEqual(doc[1][0].text(), 'a') + self.assertEqual(doc[0][0].text(), "b") + self.assertEqual(doc[1][0].text(), "a") - doc.insert(1, QgsTextBlock(QgsTextFragment('c'))) + doc.insert(1, QgsTextBlock(QgsTextFragment("c"))) self.assertEqual(len(doc), 3) - self.assertEqual(doc[0][0].text(), 'b') - self.assertEqual(doc[1][0].text(), 'c') - self.assertEqual(doc[2][0].text(), 'a') + self.assertEqual(doc[0][0].text(), "b") + self.assertEqual(doc[1][0].text(), "c") + self.assertEqual(doc[2][0].text(), "a") with self.assertRaises(IndexError): - doc.insert(4, QgsTextBlock(QgsTextFragment('d'))) - doc.insert(3, QgsTextBlock(QgsTextFragment('d'))) + doc.insert(4, QgsTextBlock(QgsTextFragment("d"))) + doc.insert(3, QgsTextBlock(QgsTextFragment("d"))) self.assertEqual(len(doc), 4) - self.assertEqual(doc[0][0].text(), 'b') - self.assertEqual(doc[1][0].text(), 'c') - self.assertEqual(doc[2][0].text(), 'a') - self.assertEqual(doc[3][0].text(), 'd') + self.assertEqual(doc[0][0].text(), "b") + self.assertEqual(doc[1][0].text(), "c") + self.assertEqual(doc[2][0].text(), "a") + self.assertEqual(doc[3][0].text(), "d") def testAt(self): doc = QgsTextDocument() self.assertEqual(len(doc), 0) block = QgsTextBlock() - block.append(QgsTextFragment('a')) + block.append(QgsTextFragment("a")) doc.append(block) block = QgsTextBlock() - block.append(QgsTextFragment('b')) + block.append(QgsTextFragment("b")) doc.append(block) self.assertEqual(len(doc), 2) - self.assertEqual(doc.at(0)[0].text(), 'a') - self.assertEqual(doc.at(1)[0].text(), 'b') + self.assertEqual(doc.at(0)[0].text(), "a") + self.assertEqual(doc.at(1)[0].text(), "b") with self.assertRaises(KeyError): doc.at(2) with self.assertRaises(KeyError): doc.at(-1) - self.assertEqual(doc[0][0].text(), 'a') - self.assertEqual(doc[1][0].text(), 'b') + self.assertEqual(doc[0][0].text(), "a") + self.assertEqual(doc[1][0].text(), "b") with self.assertRaises(IndexError): _ = doc[2] - self.assertEqual(doc[-1][0].text(), 'b') - self.assertEqual(doc[-2][0].text(), 'a') + self.assertEqual(doc[-1][0].text(), "b") + self.assertEqual(doc[-2][0].text(), "a") def testToPlainText(self): - self.assertEqual(QgsTextDocument.fromHtml(['']).toPlainText(), []) - self.assertEqual(QgsTextDocument.fromHtml(['abc']).toPlainText(), ['abc']) - self.assertEqual(QgsTextDocument.fromHtml(['abc\ndef']).toPlainText(), ['abc def']) - self.assertEqual(QgsTextDocument.fromHtml(['abcdef']).toPlainText(), ['abcdef']) - self.assertEqual(QgsTextDocument.fromHtml(['abc
    def
    ghi
    ']).toPlainText(), ['abc', 'def', 'ghi']) + self.assertEqual(QgsTextDocument.fromHtml([""]).toPlainText(), []) + self.assertEqual(QgsTextDocument.fromHtml(["abc"]).toPlainText(), ["abc"]) + self.assertEqual( + QgsTextDocument.fromHtml(["abc\ndef"]).toPlainText(), ["abc def"] + ) + self.assertEqual( + QgsTextDocument.fromHtml(["abcdef"]).toPlainText(), ["abcdef"] + ) + self.assertEqual( + QgsTextDocument.fromHtml( + ["abc
    def
    ghi
    "] + ).toPlainText(), + ["abc", "def", "ghi"], + ) def testSplitLines(self): - doc = QgsTextDocument.fromHtml(['abc def']) + doc = QgsTextDocument.fromHtml(["abc def"]) self.assertEqual(len(doc), 1) self.assertEqual(len(doc[0]), 1) - self.assertEqual(doc[0][0].text(), 'abc def') - doc.splitLines(' ') + self.assertEqual(doc[0][0].text(), "abc def") + doc.splitLines(" ") self.assertEqual(len(doc), 2) self.assertEqual(len(doc[0]), 1) - self.assertEqual(doc[0][0].text(), 'abc') + self.assertEqual(doc[0][0].text(), "abc") self.assertEqual(len(doc[1]), 1) - self.assertEqual(doc[1][0].text(), 'def') + self.assertEqual(doc[1][0].text(), "def") - doc = QgsTextDocument.fromHtml(['R_ED not
    red
    ']) + doc = QgsTextDocument.fromHtml( + ['R_ED not
    red
    '] + ) self.assertEqual(len(doc), 2) self.assertEqual(len(doc[0]), 2) - self.assertEqual(doc[0][0].text(), 'R_ED') - self.assertEqual(doc[0][1].text(), ' not ') + self.assertEqual(doc[0][0].text(), "R_ED") + self.assertEqual(doc[0][1].text(), " not ") self.assertEqual(len(doc[1]), 1) - self.assertEqual(doc[1][0].text(), 'red') - doc.splitLines(' ') + self.assertEqual(doc[1][0].text(), "red") + doc.splitLines(" ") self.assertEqual(len(doc), 4) self.assertEqual(len(doc[0]), 1) - self.assertEqual(doc[0][0].text(), 'R_ED') + self.assertEqual(doc[0][0].text(), "R_ED") self.assertEqual(len(doc[1]), 1) - self.assertEqual(doc[1][0].text(), 'not') + self.assertEqual(doc[1][0].text(), "not") self.assertEqual(len(doc[2]), 1) - self.assertEqual(doc[2][0].text(), '') + self.assertEqual(doc[2][0].text(), "") self.assertEqual(len(doc[3]), 1) - self.assertEqual(doc[3][0].text(), 'red') + self.assertEqual(doc[3][0].text(), "red") - doc = QgsTextDocument.fromHtml(['R_ED not
    red
    ']) - doc.splitLines('_') + doc = QgsTextDocument.fromHtml( + ['R_ED not
    red
    '] + ) + doc.splitLines("_") self.assertEqual(len(doc), 3) self.assertEqual(len(doc[0]), 1) - self.assertEqual(doc[0][0].text(), 'R') + self.assertEqual(doc[0][0].text(), "R") self.assertEqual(len(doc[1]), 2) - self.assertEqual(doc[1][0].text(), 'ED') - self.assertEqual(doc[1][1].text(), ' not ') + self.assertEqual(doc[1][0].text(), "ED") + self.assertEqual(doc[1][1].text(), " not ") self.assertEqual(len(doc[2]), 1) - self.assertEqual(doc[2][0].text(), 'red') + self.assertEqual(doc[2][0].text(), "red") def testCapitalize(self): - doc = QgsTextDocument.fromPlainText(['abc def ghi', 'more text', 'another block']) + doc = QgsTextDocument.fromPlainText( + ["abc def ghi", "more text", "another block"] + ) doc.applyCapitalization(QgsStringUtils.Capitalization.TitleCase) - self.assertEqual(doc.toPlainText(), ['Abc Def Ghi', 'More Text', 'Another Block']) + self.assertEqual( + doc.toPlainText(), ["Abc Def Ghi", "More Text", "Another Block"] + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgstextformat.py b/tests/src/python/test_qgstextformat.py index f8bc489025d3..c0a66643c5c9 100644 --- a/tests/src/python/test_qgstextformat.py +++ b/tests/src/python/test_qgstextformat.py @@ -5,21 +5,13 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Mathieu Pellerin' -__date__ = '2024-10-20' -__copyright__ = 'Copyright 2024, The QGIS Project' - -from qgis.PyQt.QtCore import ( - Qt, - QPointF, - QSizeF, - QT_VERSION_STR -) -from qgis.PyQt.QtGui import ( - QFont, - QColor, - QPainter -) + +__author__ = "Mathieu Pellerin" +__date__ = "2024-10-20" +__copyright__ = "Copyright 2024, The QGIS Project" + +from qgis.PyQt.QtCore import Qt, QPointF, QSizeF, QT_VERSION_STR +from qgis.PyQt.QtGui import QFont, QColor, QPainter from qgis.PyQt.QtXml import ( QDomDocument, ) @@ -58,7 +50,7 @@ class PyQgsTextFormat(QgisTestCase): @classmethod def setUpClass(cls): super().setUpClass() - QgsFontUtils.loadStandardTestFonts(['Bold', 'Oblique']) + QgsFontUtils.loadStandardTestFonts(["Bold", "Oblique"]) def testValid(self): t = QgsTextFormat() @@ -103,7 +95,7 @@ def testValid(self): self.assertTrue(t.isValid()) t = QgsTextFormat() - t.setNamedStyle('Bold') + t.setNamedStyle("Bold") self.assertTrue(t.isValid()) t = QgsTextFormat() @@ -171,7 +163,7 @@ def testValid(self): self.assertTrue(t.isValid()) t = QgsTextFormat() - t.setFamilies(['Arial', 'Comic Sans']) + t.setFamilies(["Arial", "Comic Sans"]) self.assertTrue(t.isValid()) t = QgsTextFormat() @@ -179,7 +171,9 @@ def testValid(self): self.assertTrue(t.isValid()) t = QgsTextFormat() - t.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.Bold, QgsProperty.fromValue(True)) + t.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Bold, QgsProperty.fromValue(True) + ) self.assertTrue(t.isValid()) t = QgsTextFormat() @@ -194,7 +188,7 @@ def test_tab(self): pos = QgsTextFormat.Tab(4) self.assertEqual(pos, QgsTextFormat.Tab(4)) self.assertNotEqual(pos, QgsTextFormat.Tab(14)) - self.assertEqual(str(pos), '') + self.assertEqual(str(pos), "") def createBufferSettings(self): s = QgsTextBufferSettings() @@ -250,7 +244,7 @@ def testBufferEquality(self): self.assertNotEqual(s, s2) def checkBufferSettings(self, s): - """ test QgsTextBufferSettings """ + """test QgsTextBufferSettings""" self.assertTrue(s.enabled()) self.assertEqual(s.size(), 5) self.assertEqual(s.sizeUnit(), Qgis.RenderUnit.Points) @@ -259,7 +253,9 @@ def checkBufferSettings(self, s): self.assertTrue(s.fillBufferInterior()) self.assertEqual(s.opacity(), 0.5) self.assertEqual(s.joinStyle(), Qt.PenJoinStyle.RoundJoin) - self.assertEqual(s.blendMode(), QPainter.CompositionMode.CompositionMode_DestinationAtop) + self.assertEqual( + s.blendMode(), QPainter.CompositionMode.CompositionMode_DestinationAtop + ) def testBufferGettersSetters(self): s = self.createBufferSettings() @@ -302,8 +298,12 @@ def createMaskSettings(self): s.setSizeMapUnitScale(QgsMapUnitScale(1, 2)) s.setOpacity(0.5) s.setJoinStyle(Qt.PenJoinStyle.RoundJoin) - s.setMaskedSymbolLayers([QgsSymbolLayerReference("layerid1", "symbol1"), - QgsSymbolLayerReference("layerid2", "symbol2")]) + s.setMaskedSymbolLayers( + [ + QgsSymbolLayerReference("layerid1", "symbol1"), + QgsSymbolLayerReference("layerid2", "symbol2"), + ] + ) return s def testMaskEquality(self): @@ -335,12 +335,16 @@ def testMaskEquality(self): self.assertNotEqual(s, s2) s = self.createMaskSettings() - s.setMaskedSymbolLayers([QgsSymbolLayerReference("layerid11", "symbol1"), - QgsSymbolLayerReference("layerid21", "symbol2")]) + s.setMaskedSymbolLayers( + [ + QgsSymbolLayerReference("layerid11", "symbol1"), + QgsSymbolLayerReference("layerid21", "symbol2"), + ] + ) self.assertNotEqual(s, s2) def checkMaskSettings(self, s): - """ test QgsTextMaskSettings """ + """test QgsTextMaskSettings""" self.assertTrue(s.enabled()) self.assertEqual(s.type(), QgsTextMaskSettings.MaskType.MaskBuffer) self.assertEqual(s.size(), 5) @@ -348,8 +352,13 @@ def checkMaskSettings(self, s): self.assertEqual(s.sizeMapUnitScale(), QgsMapUnitScale(1, 2)) self.assertEqual(s.opacity(), 0.5) self.assertEqual(s.joinStyle(), Qt.PenJoinStyle.RoundJoin) - self.assertEqual(s.maskedSymbolLayers(), [QgsSymbolLayerReference("layerid1", "symbol1"), - QgsSymbolLayerReference("layerid2", "symbol2")]) + self.assertEqual( + s.maskedSymbolLayers(), + [ + QgsSymbolLayerReference("layerid1", "symbol1"), + QgsSymbolLayerReference("layerid2", "symbol2"), + ], + ) def testMaskGettersSetters(self): s = self.createMaskSettings() @@ -381,7 +390,7 @@ def createBackgroundSettings(self): s = QgsTextBackgroundSettings() s.setEnabled(True) s.setType(QgsTextBackgroundSettings.ShapeType.ShapeEllipse) - s.setSvgFile('svg.svg') + s.setSvgFile("svg.svg") s.setSizeType(QgsTextBackgroundSettings.SizeType.SizePercent) s.setSize(QSizeF(1, 2)) s.setSizeUnit(Qgis.RenderUnit.Points) @@ -422,7 +431,7 @@ def testBackgroundEquality(self): self.assertNotEqual(s, s2) s = self.createBackgroundSettings() - s.setSvgFile('svg2.svg') + s.setSvgFile("svg2.svg") self.assertNotEqual(s, s2) s = self.createBackgroundSettings() @@ -506,15 +515,17 @@ def testBackgroundEquality(self): self.assertNotEqual(s, s2) def checkBackgroundSettings(self, s): - """ test QgsTextBackgroundSettings """ + """test QgsTextBackgroundSettings""" self.assertTrue(s.enabled()) self.assertEqual(s.type(), QgsTextBackgroundSettings.ShapeType.ShapeEllipse) - self.assertEqual(s.svgFile(), 'svg.svg') + self.assertEqual(s.svgFile(), "svg.svg") self.assertEqual(s.sizeType(), QgsTextBackgroundSettings.SizeType.SizePercent) self.assertEqual(s.size(), QSizeF(1, 2)) self.assertEqual(s.sizeUnit(), Qgis.RenderUnit.Points) self.assertEqual(s.sizeMapUnitScale(), QgsMapUnitScale(1, 2)) - self.assertEqual(s.rotationType(), QgsTextBackgroundSettings.RotationType.RotationFixed) + self.assertEqual( + s.rotationType(), QgsTextBackgroundSettings.RotationType.RotationFixed + ) self.assertEqual(s.rotation(), 45) self.assertEqual(s.offset(), QPointF(3, 4)) self.assertEqual(s.offsetUnit(), Qgis.RenderUnit.MapUnits) @@ -526,11 +537,13 @@ def checkBackgroundSettings(self, s): self.assertEqual(s.strokeColor(), QColor(0, 255, 0)) self.assertEqual(s.opacity(), 0.5) self.assertEqual(s.joinStyle(), Qt.PenJoinStyle.RoundJoin) - self.assertEqual(s.blendMode(), QPainter.CompositionMode.CompositionMode_DestinationAtop) + self.assertEqual( + s.blendMode(), QPainter.CompositionMode.CompositionMode_DestinationAtop + ) self.assertEqual(s.strokeWidth(), 7) self.assertEqual(s.strokeWidthUnit(), Qgis.RenderUnit.Points) self.assertEqual(s.strokeWidthMapUnitScale(), QgsMapUnitScale(25, 26)) - self.assertEqual(s.markerSymbol().color().name(), '#647086') + self.assertEqual(s.markerSymbol().color().name(), "#647086") def testBackgroundGettersSetters(self): s = self.createBackgroundSettings() @@ -644,9 +657,11 @@ def testShadowEquality(self): self.assertNotEqual(s, s2) def checkShadowSettings(self, s): - """ test QgsTextShadowSettings """ + """test QgsTextShadowSettings""" self.assertTrue(s.enabled()) - self.assertEqual(s.shadowPlacement(), QgsTextShadowSettings.ShadowPlacement.ShadowBuffer) + self.assertEqual( + s.shadowPlacement(), QgsTextShadowSettings.ShadowPlacement.ShadowBuffer + ) self.assertEqual(s.offsetAngle(), 45) self.assertEqual(s.offsetDistance(), 75) self.assertEqual(s.offsetUnit(), Qgis.RenderUnit.MapUnits) @@ -659,7 +674,9 @@ def checkShadowSettings(self, s): self.assertEqual(s.color(), QColor(255, 0, 0)) self.assertEqual(s.opacity(), 0.5) self.assertEqual(s.scale(), 123) - self.assertEqual(s.blendMode(), QPainter.CompositionMode.CompositionMode_DestinationAtop) + self.assertEqual( + s.blendMode(), QPainter.CompositionMode.CompositionMode_DestinationAtop + ) def testShadowGettersSetters(self): s = self.createShadowSettings() @@ -704,15 +721,15 @@ def createFormatSettings(self): s.mask().setEnabled(True) s.mask().setSize(32) s.background().setEnabled(True) - s.background().setSvgFile('test.svg') + s.background().setSvgFile("test.svg") s.shadow().setEnabled(True) s.shadow().setOffsetAngle(223) font = getTestFont() font.setKerning(False) s.setFont(font) s.setCapitalization(Qgis.Capitalization.TitleCase) - s.setNamedStyle('Italic') - s.setFamilies(['Arial', 'Comic Sans']) + s.setNamedStyle("Italic") + s.setFamilies(["Arial", "Comic Sans"]) s.setSize(5) s.setSizeUnit(Qgis.RenderUnit.Points) s.setSizeMapUnitScale(QgsMapUnitScale(1, 2)) @@ -734,7 +751,9 @@ def createFormatSettings(self): s.setStretchFactor(110) - s.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.Bold, QgsProperty.fromExpression('1>2')) + s.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Bold, QgsProperty.fromExpression("1>2") + ) return s def testFormatEquality(self): @@ -762,7 +781,7 @@ def testFormatEquality(self): self.assertNotEqual(s, s2) s = self.createFormatSettings() - s.background().setSvgFile('test2.svg') + s.background().setSvgFile("test2.svg") self.assertNotEqual(s, s2) s = self.createFormatSettings() @@ -780,7 +799,7 @@ def testFormatEquality(self): self.assertNotEqual(s, s2) s = self.createFormatSettings() - s.setNamedStyle('Bold') + s.setNamedStyle("Bold") self.assertNotEqual(s, s2) s = self.createFormatSettings() @@ -840,11 +859,13 @@ def testFormatEquality(self): self.assertNotEqual(s, s2) s = self.createFormatSettings() - s.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.Bold, QgsProperty.fromExpression('1>3')) + s.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Bold, QgsProperty.fromExpression("1>3") + ) self.assertNotEqual(s, s2) s = self.createFormatSettings() - s.setFamilies(['Times New Roman']) + s.setFamilies(["Times New Roman"]) self.assertNotEqual(s, s2) s = self.createFormatSettings() @@ -864,46 +885,58 @@ def testFormatEquality(self): self.assertNotEqual(s, s2) s = self.createFormatSettings() - s.setTabStopDistanceMapUnitScale( - QgsMapUnitScale(111, 122)) + s.setTabStopDistanceMapUnitScale(QgsMapUnitScale(111, 122)) self.assertNotEqual(s, s2) def checkTextFormat(self, s): - """ test QgsTextFormat """ + """test QgsTextFormat""" self.assertTrue(s.buffer().enabled()) self.assertEqual(s.buffer().size(), 25) self.assertTrue(s.mask().enabled()) self.assertEqual(s.mask().size(), 32) self.assertTrue(s.background().enabled()) - self.assertEqual(s.background().svgFile(), 'test.svg') + self.assertEqual(s.background().svgFile(), "test.svg") self.assertTrue(s.shadow().enabled()) self.assertEqual(s.shadow().offsetAngle(), 223) - self.assertEqual(s.font().family(), 'QGIS Vera Sans') - self.assertEqual(s.families(), ['Arial', 'Comic Sans']) + self.assertEqual(s.font().family(), "QGIS Vera Sans") + self.assertEqual(s.families(), ["Arial", "Comic Sans"]) self.assertFalse(s.font().kerning()) - self.assertEqual(s.namedStyle(), 'Italic') + self.assertEqual(s.namedStyle(), "Italic") self.assertEqual(s.size(), 5) self.assertEqual(s.sizeUnit(), Qgis.RenderUnit.Points) self.assertEqual(s.sizeMapUnitScale(), QgsMapUnitScale(1, 2)) self.assertEqual(s.color(), QColor(255, 0, 0)) self.assertEqual(s.opacity(), 0.5) - self.assertEqual(s.blendMode(), QPainter.CompositionMode.CompositionMode_DestinationAtop) + self.assertEqual( + s.blendMode(), QPainter.CompositionMode.CompositionMode_DestinationAtop + ) self.assertEqual(s.lineHeight(), 5) self.assertEqual(s.lineHeightUnit(), Qgis.RenderUnit.Inches) - self.assertEqual(s.previewBackgroundColor().name(), '#6496c8') - self.assertEqual(s.orientation(), QgsTextFormat.TextOrientation.VerticalOrientation) + self.assertEqual(s.previewBackgroundColor().name(), "#6496c8") + self.assertEqual( + s.orientation(), QgsTextFormat.TextOrientation.VerticalOrientation + ) self.assertEqual(s.capitalization(), Qgis.Capitalization.TitleCase) self.assertTrue(s.allowHtmlFormatting()) - self.assertEqual(s.dataDefinedProperties().property(QgsPalLayerSettings.Property.Bold).expressionString(), '1>2') + self.assertEqual( + s.dataDefinedProperties() + .property(QgsPalLayerSettings.Property.Bold) + .expressionString(), + "1>2", + ) self.assertTrue(s.forcedBold()) self.assertTrue(s.forcedItalic()) self.assertEqual(s.tabStopDistance(), 4.5) - self.assertEqual(s.tabPositions(), [QgsTextFormat.Tab(5), QgsTextFormat.Tab(17)]) + self.assertEqual( + s.tabPositions(), [QgsTextFormat.Tab(5), QgsTextFormat.Tab(17)] + ) self.assertEqual(s.tabStopDistanceUnit(), Qgis.RenderUnit.Inches) self.assertEqual(s.tabStopDistanceMapUnitScale(), QgsMapUnitScale(11, 12)) - if int(QT_VERSION_STR.split('.')[0]) > 6 or ( - int(QT_VERSION_STR.split('.')[0]) == 6 and int(QT_VERSION_STR.split('.')[1]) >= 3): + if int(QT_VERSION_STR.split(".")[0]) > 6 or ( + int(QT_VERSION_STR.split(".")[0]) == 6 + and int(QT_VERSION_STR.split(".")[1]) >= 3 + ): self.assertEqual(s.stretchFactor(), 110) def testFormatGettersSetters(self): @@ -949,17 +982,17 @@ def testRestoreUsingFamilyList(self): # swap out font name in xml to one which doesn't exist on system xml = doc.toString() - xml = xml.replace(QFont().family(), 'NOT A REAL FONT') + xml = xml.replace(QFont().family(), "NOT A REAL FONT") doc = QDomDocument("testdoc") doc.setContent(xml) - parent = doc.firstChildElement('settings') + parent = doc.firstChildElement("settings") t = QgsTextFormat() t.readXml(parent, QgsReadWriteContext()) # should be default font self.assertEqual(t.font().family(), QFont().family()) - format.setFamilies(['not real', 'still not real', getTestFont().family()]) + format.setFamilies(["not real", "still not real", getTestFont().family()]) doc = QDomDocument("testdoc") elem = format.writeXml(doc, QgsReadWriteContext()) @@ -969,14 +1002,16 @@ def testRestoreUsingFamilyList(self): # swap out font name in xml to one which doesn't exist on system xml = doc.toString() - xml = xml.replace(QFont().family(), 'NOT A REAL FONT') + xml = xml.replace(QFont().family(), "NOT A REAL FONT") doc = QDomDocument("testdoc") doc.setContent(xml) - parent = doc.firstChildElement('settings') + parent = doc.firstChildElement("settings") t = QgsTextFormat() t.readXml(parent, QgsReadWriteContext()) - self.assertEqual(t.families(), ['not real', 'still not real', getTestFont().family()]) + self.assertEqual( + t.families(), ["not real", "still not real", getTestFont().family()] + ) # should have skipped the missing fonts and fallen back to the test font family entry, NOT the default application font! self.assertEqual(t.font().family(), getTestFont().family()) @@ -1005,7 +1040,9 @@ def testContainsAdvancedEffects(self): self.assertTrue(t.containsAdvancedEffects()) t = QgsTextFormat() - t.buffer().setBlendMode(QPainter.CompositionMode.CompositionMode_DestinationAtop) + t.buffer().setBlendMode( + QPainter.CompositionMode.CompositionMode_DestinationAtop + ) self.assertFalse(t.containsAdvancedEffects()) t.buffer().setEnabled(True) self.assertTrue(t.containsAdvancedEffects()) @@ -1013,7 +1050,9 @@ def testContainsAdvancedEffects(self): self.assertFalse(t.containsAdvancedEffects()) t = QgsTextFormat() - t.background().setBlendMode(QPainter.CompositionMode.CompositionMode_DestinationAtop) + t.background().setBlendMode( + QPainter.CompositionMode.CompositionMode_DestinationAtop + ) self.assertFalse(t.containsAdvancedEffects()) t.background().setEnabled(True) self.assertTrue(t.containsAdvancedEffects()) @@ -1021,7 +1060,9 @@ def testContainsAdvancedEffects(self): self.assertFalse(t.containsAdvancedEffects()) t = QgsTextFormat() - t.shadow().setBlendMode(QPainter.CompositionMode.CompositionMode_DestinationAtop) + t.shadow().setBlendMode( + QPainter.CompositionMode.CompositionMode_DestinationAtop + ) self.assertFalse(t.containsAdvancedEffects()) t.shadow().setEnabled(True) self.assertTrue(t.containsAdvancedEffects()) @@ -1031,7 +1072,9 @@ def testContainsAdvancedEffects(self): def testRestoringAndSavingMissingFont(self): # test that a missing font on text format load will still save with the same missing font unless manually changed document = QDomDocument() - document.setContent('') + document.setContent( + '' + ) context = QgsReadWriteContext() text_format = QgsTextFormat() @@ -1056,71 +1099,107 @@ def testDataDefinedBufferSettings(self): context = QgsRenderContext() # buffer enabled - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.BufferDraw, QgsProperty.fromExpression('1')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.BufferDraw, QgsProperty.fromExpression("1") + ) f.updateDataDefinedProperties(context) self.assertTrue(f.buffer().enabled()) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.BufferDraw, QgsProperty.fromExpression('0')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.BufferDraw, QgsProperty.fromExpression("0") + ) context = QgsRenderContext() f.updateDataDefinedProperties(context) self.assertFalse(f.buffer().enabled()) # buffer size - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.BufferSize, QgsProperty.fromExpression('7.8')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.BufferSize, QgsProperty.fromExpression("7.8") + ) f.updateDataDefinedProperties(context) self.assertEqual(f.buffer().size(), 7.8) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.BufferUnit, QgsProperty.fromExpression("'pixel'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.BufferUnit, + QgsProperty.fromExpression("'pixel'"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.buffer().sizeUnit(), Qgis.RenderUnit.Pixels) # buffer opacity - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.BufferOpacity, QgsProperty.fromExpression('37')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.BufferOpacity, QgsProperty.fromExpression("37") + ) f.updateDataDefinedProperties(context) self.assertEqual(f.buffer().opacity(), 0.37) # blend mode - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.BufferBlendMode, QgsProperty.fromExpression("'burn'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.BufferBlendMode, + QgsProperty.fromExpression("'burn'"), + ) f.updateDataDefinedProperties(context) - self.assertEqual(f.buffer().blendMode(), QPainter.CompositionMode.CompositionMode_ColorBurn) + self.assertEqual( + f.buffer().blendMode(), QPainter.CompositionMode.CompositionMode_ColorBurn + ) # join style - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.BufferJoinStyle, - QgsProperty.fromExpression("'miter'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.BufferJoinStyle, + QgsProperty.fromExpression("'miter'"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.buffer().joinStyle(), Qt.PenJoinStyle.MiterJoin) # color - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.BufferColor, QgsProperty.fromExpression("'#ff0088'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.BufferColor, + QgsProperty.fromExpression("'#ff0088'"), + ) f.updateDataDefinedProperties(context) - self.assertEqual(f.buffer().color().name(), '#ff0088') + self.assertEqual(f.buffer().color().name(), "#ff0088") def testDataDefinedMaskSettings(self): f = QgsTextFormat() context = QgsRenderContext() # mask enabled - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.MaskEnabled, QgsProperty.fromExpression('1')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.MaskEnabled, QgsProperty.fromExpression("1") + ) f.updateDataDefinedProperties(context) self.assertTrue(f.mask().enabled()) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.MaskEnabled, QgsProperty.fromExpression('0')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.MaskEnabled, QgsProperty.fromExpression("0") + ) context = QgsRenderContext() f.updateDataDefinedProperties(context) self.assertFalse(f.mask().enabled()) # mask buffer size - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.MaskBufferSize, QgsProperty.fromExpression('7.8')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.MaskBufferSize, + QgsProperty.fromExpression("7.8"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.mask().size(), 7.8) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.MaskBufferUnit, QgsProperty.fromExpression("'pixel'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.MaskBufferUnit, + QgsProperty.fromExpression("'pixel'"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.mask().sizeUnit(), Qgis.RenderUnit.Pixels) # mask opacity - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.MaskOpacity, QgsProperty.fromExpression('37')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.MaskOpacity, QgsProperty.fromExpression("37") + ) f.updateDataDefinedProperties(context) self.assertEqual(f.mask().opacity(), 0.37) # join style - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.MaskJoinStyle, QgsProperty.fromExpression("'miter'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.MaskJoinStyle, + QgsProperty.fromExpression("'miter'"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.mask().joinStyle(), Qt.PenJoinStyle.MiterJoin) @@ -1129,128 +1208,227 @@ def testDataDefinedBackgroundSettings(self): context = QgsRenderContext() # background enabled - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeDraw, QgsProperty.fromExpression('1')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeDraw, QgsProperty.fromExpression("1") + ) f.updateDataDefinedProperties(context) self.assertTrue(f.background().enabled()) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeDraw, QgsProperty.fromExpression('0')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeDraw, QgsProperty.fromExpression("0") + ) context = QgsRenderContext() f.updateDataDefinedProperties(context) self.assertFalse(f.background().enabled()) # background size f.background().setSize(QSizeF(13, 14)) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeSizeX, QgsProperty.fromExpression('7.8')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeSizeX, QgsProperty.fromExpression("7.8") + ) f.updateDataDefinedProperties(context) self.assertEqual(f.background().size().width(), 7.8) self.assertEqual(f.background().size().height(), 14) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeSizeY, QgsProperty.fromExpression('17.8')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeSizeY, QgsProperty.fromExpression("17.8") + ) f.updateDataDefinedProperties(context) self.assertEqual(f.background().size().width(), 7.8) self.assertEqual(f.background().size().height(), 17.8) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeSizeUnits, QgsProperty.fromExpression("'pixel'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeSizeUnits, + QgsProperty.fromExpression("'pixel'"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.background().sizeUnit(), Qgis.RenderUnit.Pixels) # shape kind - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeKind, QgsProperty.fromExpression("'square'")) - f.updateDataDefinedProperties(context) - self.assertEqual(f.background().type(), QgsTextBackgroundSettings.ShapeType.ShapeSquare) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeKind, QgsProperty.fromExpression("'ellipse'")) - f.updateDataDefinedProperties(context) - self.assertEqual(f.background().type(), QgsTextBackgroundSettings.ShapeType.ShapeEllipse) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeKind, QgsProperty.fromExpression("'circle'")) - f.updateDataDefinedProperties(context) - self.assertEqual(f.background().type(), QgsTextBackgroundSettings.ShapeType.ShapeCircle) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeKind, QgsProperty.fromExpression("'svg'")) - f.updateDataDefinedProperties(context) - self.assertEqual(f.background().type(), QgsTextBackgroundSettings.ShapeType.ShapeSVG) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeKind, QgsProperty.fromExpression("'marker'")) - f.updateDataDefinedProperties(context) - self.assertEqual(f.background().type(), QgsTextBackgroundSettings.ShapeType.ShapeMarkerSymbol) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeKind, QgsProperty.fromExpression("'rect'")) - f.updateDataDefinedProperties(context) - self.assertEqual(f.background().type(), QgsTextBackgroundSettings.ShapeType.ShapeRectangle) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeKind, + QgsProperty.fromExpression("'square'"), + ) + f.updateDataDefinedProperties(context) + self.assertEqual( + f.background().type(), QgsTextBackgroundSettings.ShapeType.ShapeSquare + ) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeKind, + QgsProperty.fromExpression("'ellipse'"), + ) + f.updateDataDefinedProperties(context) + self.assertEqual( + f.background().type(), QgsTextBackgroundSettings.ShapeType.ShapeEllipse + ) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeKind, + QgsProperty.fromExpression("'circle'"), + ) + f.updateDataDefinedProperties(context) + self.assertEqual( + f.background().type(), QgsTextBackgroundSettings.ShapeType.ShapeCircle + ) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeKind, QgsProperty.fromExpression("'svg'") + ) + f.updateDataDefinedProperties(context) + self.assertEqual( + f.background().type(), QgsTextBackgroundSettings.ShapeType.ShapeSVG + ) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeKind, + QgsProperty.fromExpression("'marker'"), + ) + f.updateDataDefinedProperties(context) + self.assertEqual( + f.background().type(), QgsTextBackgroundSettings.ShapeType.ShapeMarkerSymbol + ) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeKind, QgsProperty.fromExpression("'rect'") + ) + f.updateDataDefinedProperties(context) + self.assertEqual( + f.background().type(), QgsTextBackgroundSettings.ShapeType.ShapeRectangle + ) # size type - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeSizeType, QgsProperty.fromExpression("'fixed'")) - f.updateDataDefinedProperties(context) - self.assertEqual(f.background().sizeType(), QgsTextBackgroundSettings.SizeType.SizeFixed) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeSizeType, QgsProperty.fromExpression("'buffer'")) - f.updateDataDefinedProperties(context) - self.assertEqual(f.background().sizeType(), QgsTextBackgroundSettings.SizeType.SizeBuffer) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeSizeType, + QgsProperty.fromExpression("'fixed'"), + ) + f.updateDataDefinedProperties(context) + self.assertEqual( + f.background().sizeType(), QgsTextBackgroundSettings.SizeType.SizeFixed + ) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeSizeType, + QgsProperty.fromExpression("'buffer'"), + ) + f.updateDataDefinedProperties(context) + self.assertEqual( + f.background().sizeType(), QgsTextBackgroundSettings.SizeType.SizeBuffer + ) # svg path - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeSVGFile, QgsProperty.fromExpression("'my.svg'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeSVGFile, + QgsProperty.fromExpression("'my.svg'"), + ) f.updateDataDefinedProperties(context) - self.assertEqual(f.background().svgFile(), 'my.svg') + self.assertEqual(f.background().svgFile(), "my.svg") # shape rotation - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeRotation, QgsProperty.fromExpression('67')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeRotation, QgsProperty.fromExpression("67") + ) f.updateDataDefinedProperties(context) self.assertEqual(f.background().rotation(), 67) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeRotationType, - QgsProperty.fromExpression("'offset'")) - f.updateDataDefinedProperties(context) - self.assertEqual(f.background().rotationType(), QgsTextBackgroundSettings.RotationType.RotationOffset) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeRotationType, - QgsProperty.fromExpression("'fixed'")) - f.updateDataDefinedProperties(context) - self.assertEqual(f.background().rotationType(), QgsTextBackgroundSettings.RotationType.RotationFixed) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeRotationType, - QgsProperty.fromExpression("'sync'")) - f.updateDataDefinedProperties(context) - self.assertEqual(f.background().rotationType(), QgsTextBackgroundSettings.RotationType.RotationSync) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeRotationType, + QgsProperty.fromExpression("'offset'"), + ) + f.updateDataDefinedProperties(context) + self.assertEqual( + f.background().rotationType(), + QgsTextBackgroundSettings.RotationType.RotationOffset, + ) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeRotationType, + QgsProperty.fromExpression("'fixed'"), + ) + f.updateDataDefinedProperties(context) + self.assertEqual( + f.background().rotationType(), + QgsTextBackgroundSettings.RotationType.RotationFixed, + ) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeRotationType, + QgsProperty.fromExpression("'sync'"), + ) + f.updateDataDefinedProperties(context) + self.assertEqual( + f.background().rotationType(), + QgsTextBackgroundSettings.RotationType.RotationSync, + ) # shape offset - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeOffset, QgsProperty.fromExpression("'7,9'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeOffset, + QgsProperty.fromExpression("'7,9'"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.background().offset(), QPointF(7, 9)) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeOffsetUnits, - QgsProperty.fromExpression("'pixel'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeOffsetUnits, + QgsProperty.fromExpression("'pixel'"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.background().offsetUnit(), Qgis.RenderUnit.Pixels) # shape radii - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeRadii, QgsProperty.fromExpression("'18,19'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeRadii, + QgsProperty.fromExpression("'18,19'"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.background().radii(), QSizeF(18, 19)) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeRadiiUnits, - QgsProperty.fromExpression("'pixel'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeRadiiUnits, + QgsProperty.fromExpression("'pixel'"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.background().radiiUnit(), Qgis.RenderUnit.Pixels) # shape opacity - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeOpacity, QgsProperty.fromExpression('37')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeOpacity, QgsProperty.fromExpression("37") + ) f.updateDataDefinedProperties(context) self.assertEqual(f.background().opacity(), 0.37) # color - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeFillColor, - QgsProperty.fromExpression("'#ff0088'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeFillColor, + QgsProperty.fromExpression("'#ff0088'"), + ) f.updateDataDefinedProperties(context) - self.assertEqual(f.background().fillColor().name(), '#ff0088') - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeStrokeColor, - QgsProperty.fromExpression("'#8800ff'")) + self.assertEqual(f.background().fillColor().name(), "#ff0088") + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeStrokeColor, + QgsProperty.fromExpression("'#8800ff'"), + ) f.updateDataDefinedProperties(context) - self.assertEqual(f.background().strokeColor().name(), '#8800ff') + self.assertEqual(f.background().strokeColor().name(), "#8800ff") # stroke width - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeStrokeWidth, QgsProperty.fromExpression('88')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeStrokeWidth, + QgsProperty.fromExpression("88"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.background().strokeWidth(), 88) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeStrokeWidthUnits, - QgsProperty.fromExpression("'pixel'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeStrokeWidthUnits, + QgsProperty.fromExpression("'pixel'"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.background().strokeWidthUnit(), Qgis.RenderUnit.Pixels) # blend mode - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeBlendMode, QgsProperty.fromExpression("'burn'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeBlendMode, + QgsProperty.fromExpression("'burn'"), + ) f.updateDataDefinedProperties(context) - self.assertEqual(f.background().blendMode(), QPainter.CompositionMode.CompositionMode_ColorBurn) + self.assertEqual( + f.background().blendMode(), + QPainter.CompositionMode.CompositionMode_ColorBurn, + ) # join style - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShapeJoinStyle, QgsProperty.fromExpression("'miter'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShapeJoinStyle, + QgsProperty.fromExpression("'miter'"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.background().joinStyle(), Qt.PenJoinStyle.MiterJoin) @@ -1259,67 +1437,119 @@ def testDataDefinedShadowSettings(self): context = QgsRenderContext() # shadow enabled - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShadowDraw, QgsProperty.fromExpression('1')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShadowDraw, QgsProperty.fromExpression("1") + ) f.updateDataDefinedProperties(context) self.assertTrue(f.shadow().enabled()) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShadowDraw, QgsProperty.fromExpression('0')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShadowDraw, QgsProperty.fromExpression("0") + ) context = QgsRenderContext() f.updateDataDefinedProperties(context) self.assertFalse(f.shadow().enabled()) # placement type - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShadowUnder, QgsProperty.fromExpression("'text'")) - f.updateDataDefinedProperties(context) - self.assertEqual(f.shadow().shadowPlacement(), QgsTextShadowSettings.ShadowPlacement.ShadowText) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShadowUnder, QgsProperty.fromExpression("'buffer'")) - f.updateDataDefinedProperties(context) - self.assertEqual(f.shadow().shadowPlacement(), QgsTextShadowSettings.ShadowPlacement.ShadowBuffer) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShadowUnder, - QgsProperty.fromExpression("'background'")) - f.updateDataDefinedProperties(context) - self.assertEqual(f.shadow().shadowPlacement(), QgsTextShadowSettings.ShadowPlacement.ShadowShape) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShadowUnder, QgsProperty.fromExpression("'svg'")) - f.updateDataDefinedProperties(context) - self.assertEqual(f.shadow().shadowPlacement(), QgsTextShadowSettings.ShadowPlacement.ShadowLowest) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShadowUnder, QgsProperty.fromExpression("'lowest'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShadowUnder, + QgsProperty.fromExpression("'text'"), + ) + f.updateDataDefinedProperties(context) + self.assertEqual( + f.shadow().shadowPlacement(), + QgsTextShadowSettings.ShadowPlacement.ShadowText, + ) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShadowUnder, + QgsProperty.fromExpression("'buffer'"), + ) + f.updateDataDefinedProperties(context) + self.assertEqual( + f.shadow().shadowPlacement(), + QgsTextShadowSettings.ShadowPlacement.ShadowBuffer, + ) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShadowUnder, + QgsProperty.fromExpression("'background'"), + ) + f.updateDataDefinedProperties(context) + self.assertEqual( + f.shadow().shadowPlacement(), + QgsTextShadowSettings.ShadowPlacement.ShadowShape, + ) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShadowUnder, + QgsProperty.fromExpression("'svg'"), + ) + f.updateDataDefinedProperties(context) + self.assertEqual( + f.shadow().shadowPlacement(), + QgsTextShadowSettings.ShadowPlacement.ShadowLowest, + ) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShadowUnder, + QgsProperty.fromExpression("'lowest'"), + ) # offset angle - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShadowOffsetAngle, QgsProperty.fromExpression('67')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShadowOffsetAngle, + QgsProperty.fromExpression("67"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.shadow().offsetAngle(), 67) # offset distance - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShadowOffsetDist, QgsProperty.fromExpression('38')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShadowOffsetDist, + QgsProperty.fromExpression("38"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.shadow().offsetDistance(), 38) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShadowOffsetUnits, - QgsProperty.fromExpression("'pixel'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShadowOffsetUnits, + QgsProperty.fromExpression("'pixel'"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.shadow().offsetUnit(), Qgis.RenderUnit.Pixels) # radius - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShadowRadius, QgsProperty.fromExpression('58')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShadowRadius, QgsProperty.fromExpression("58") + ) f.updateDataDefinedProperties(context) self.assertEqual(f.shadow().blurRadius(), 58) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShadowRadiusUnits, - QgsProperty.fromExpression("'pixel'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShadowRadiusUnits, + QgsProperty.fromExpression("'pixel'"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.shadow().blurRadiusUnit(), Qgis.RenderUnit.Pixels) # opacity - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShadowOpacity, QgsProperty.fromExpression('37')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShadowOpacity, QgsProperty.fromExpression("37") + ) f.updateDataDefinedProperties(context) self.assertEqual(f.shadow().opacity(), 0.37) # color - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShadowColor, QgsProperty.fromExpression("'#ff0088'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShadowColor, + QgsProperty.fromExpression("'#ff0088'"), + ) f.updateDataDefinedProperties(context) - self.assertEqual(f.shadow().color().name(), '#ff0088') + self.assertEqual(f.shadow().color().name(), "#ff0088") # blend mode - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.ShadowBlendMode, QgsProperty.fromExpression("'burn'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.ShadowBlendMode, + QgsProperty.fromExpression("'burn'"), + ) f.updateDataDefinedProperties(context) - self.assertEqual(f.shadow().blendMode(), QPainter.CompositionMode.CompositionMode_ColorBurn) + self.assertEqual( + f.shadow().blendMode(), QPainter.CompositionMode.CompositionMode_ColorBurn + ) def testDataDefinedFormatSettings(self): f = QgsTextFormat() @@ -1332,24 +1562,39 @@ def testDataDefinedFormatSettings(self): context = QgsRenderContext() # family - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.Family, QgsProperty.fromExpression( - f"'{QgsFontUtils.getStandardTestFont().family()}'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Family, + QgsProperty.fromExpression( + f"'{QgsFontUtils.getStandardTestFont().family()}'" + ), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.font().family(), QgsFontUtils.getStandardTestFont().family()) # style - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.FontStyle, QgsProperty.fromExpression("'Bold'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.FontStyle, QgsProperty.fromExpression("'Bold'") + ) f.updateDataDefinedProperties(context) - self.assertEqual(f.font().styleName(), 'Bold') - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.FontStyle, QgsProperty.fromExpression("'Roman'")) + self.assertEqual(f.font().styleName(), "Bold") + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.FontStyle, + QgsProperty.fromExpression("'Roman'"), + ) f.updateDataDefinedProperties(context) - self.assertEqual(f.font().styleName(), 'Roman') - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.Bold, QgsProperty.fromExpression("1")) + self.assertEqual(f.font().styleName(), "Roman") + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Bold, QgsProperty.fromExpression("1") + ) f.updateDataDefinedProperties(context) self.assertTrue(f.font().bold()) self.assertFalse(f.font().italic()) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.Bold, QgsProperty.fromExpression("0")) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.Italic, QgsProperty.fromExpression("1")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Bold, QgsProperty.fromExpression("0") + ) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Italic, QgsProperty.fromExpression("1") + ) f.updateDataDefinedProperties(context) self.assertFalse(f.font().bold()) self.assertTrue(f.font().italic()) @@ -1359,83 +1604,129 @@ def testDataDefinedFormatSettings(self): self.assertAlmostEqual(f.font().letterSpacing(), 3.3, 1) # underline - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.Underline, QgsProperty.fromExpression("0")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Underline, QgsProperty.fromExpression("0") + ) f.updateDataDefinedProperties(context) self.assertFalse(f.font().underline()) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.Underline, QgsProperty.fromExpression("1")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Underline, QgsProperty.fromExpression("1") + ) f.updateDataDefinedProperties(context) self.assertTrue(f.font().underline()) # strikeout - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.Strikeout, QgsProperty.fromExpression("0")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Strikeout, QgsProperty.fromExpression("0") + ) f.updateDataDefinedProperties(context) self.assertFalse(f.font().strikeOut()) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.Strikeout, QgsProperty.fromExpression("1")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Strikeout, QgsProperty.fromExpression("1") + ) f.updateDataDefinedProperties(context) self.assertTrue(f.font().strikeOut()) # color - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.Color, QgsProperty.fromExpression("'#ff0088'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Color, QgsProperty.fromExpression("'#ff0088'") + ) f.updateDataDefinedProperties(context) - self.assertEqual(f.color().name(), '#ff0088') + self.assertEqual(f.color().name(), "#ff0088") # size - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.Size, QgsProperty.fromExpression('38')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Size, QgsProperty.fromExpression("38") + ) f.updateDataDefinedProperties(context) self.assertEqual(f.size(), 38) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.FontSizeUnit, QgsProperty.fromExpression("'pixel'")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.FontSizeUnit, + QgsProperty.fromExpression("'pixel'"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.sizeUnit(), Qgis.RenderUnit.Pixels) # opacity - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.FontOpacity, QgsProperty.fromExpression('37')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.FontOpacity, QgsProperty.fromExpression("37") + ) f.updateDataDefinedProperties(context) self.assertEqual(f.opacity(), 0.37) # letter spacing - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.FontLetterSpacing, QgsProperty.fromExpression('58')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.FontLetterSpacing, + QgsProperty.fromExpression("58"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.font().letterSpacing(), 58) # word spacing - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.FontWordSpacing, QgsProperty.fromExpression('8')) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.FontWordSpacing, + QgsProperty.fromExpression("8"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.font().wordSpacing(), 8) # blend mode - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.FontBlendMode, QgsProperty.fromExpression("'burn'")) - f.updateDataDefinedProperties(context) - self.assertEqual(f.blendMode(), QPainter.CompositionMode.CompositionMode_ColorBurn) - - if int(QT_VERSION_STR.split('.')[0]) > 6 or ( - int(QT_VERSION_STR.split('.')[0]) == 6 and int(QT_VERSION_STR.split('.')[1]) >= 3): + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.FontBlendMode, + QgsProperty.fromExpression("'burn'"), + ) + f.updateDataDefinedProperties(context) + self.assertEqual( + f.blendMode(), QPainter.CompositionMode.CompositionMode_ColorBurn + ) + + if int(QT_VERSION_STR.split(".")[0]) > 6 or ( + int(QT_VERSION_STR.split(".")[0]) == 6 + and int(QT_VERSION_STR.split(".")[1]) >= 3 + ): # stretch - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.FontStretchFactor, QgsProperty.fromExpression("135")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.FontStretchFactor, + QgsProperty.fromExpression("135"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.stretchFactor(), 135) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.TabStopDistance, QgsProperty.fromExpression("15")) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.TabStopDistance, + QgsProperty.fromExpression("15"), + ) f.updateDataDefinedProperties(context) self.assertEqual(f.tabStopDistance(), 15) self.assertFalse(f.tabPositions()) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.TabStopDistance, QgsProperty.fromValue([11, 14])) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.TabStopDistance, + QgsProperty.fromValue([11, 14]), + ) f.updateDataDefinedProperties(context) - self.assertEqual(f.tabPositions(), [QgsTextFormat.Tab(11), QgsTextFormat.Tab(14)]) + self.assertEqual( + f.tabPositions(), [QgsTextFormat.Tab(11), QgsTextFormat.Tab(14)] + ) - f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.TabStopDistance, QgsProperty.fromValue(["13.5", "15.8"])) + f.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.TabStopDistance, + QgsProperty.fromValue(["13.5", "15.8"]), + ) f.updateDataDefinedProperties(context) - self.assertEqual(f.tabPositions(), [QgsTextFormat.Tab(13.5), QgsTextFormat.Tab(15.8)]) + self.assertEqual( + f.tabPositions(), [QgsTextFormat.Tab(13.5), QgsTextFormat.Tab(15.8)] + ) def testFontFoundFromLayer(self): layer = createEmptyLayer() - layer.setCustomProperty('labeling/fontFamily', 'asdasd') + layer.setCustomProperty("labeling/fontFamily", "asdasd") f = QgsTextFormat() f.readFromLayer(layer) self.assertFalse(f.fontFound()) font = getTestFont() - layer.setCustomProperty('labeling/fontFamily', font.family()) + layer.setCustomProperty("labeling/fontFamily", font.family()) f.readFromLayer(layer) self.assertTrue(f.fontFound()) @@ -1443,7 +1734,7 @@ def testFontFoundFromXml(self): doc = QDomDocument("testdoc") f = QgsTextFormat() elem = f.writeXml(doc, QgsReadWriteContext()) - elem.setAttribute('fontFamily', 'asdfasdfsadf') + elem.setAttribute("fontFamily", "asdfasdfsadf") parent = doc.createElement("parent") parent.appendChild(elem) @@ -1451,7 +1742,7 @@ def testFontFoundFromXml(self): self.assertFalse(f.fontFound()) font = getTestFont() - elem.setAttribute('fontFamily', font.family()) + elem.setAttribute("fontFamily", font.family()) f.readXml(parent, QgsReadWriteContext()) self.assertTrue(f.fontFound()) @@ -1476,7 +1767,7 @@ def testToQFont(self): f = getTestFont() f.setLetterSpacing(QFont.SpacingType.AbsoluteSpacing, 3) s.setFont(f) - s.setNamedStyle('Italic') + s.setNamedStyle("Italic") s.setSize(5.5) s.setSizeUnit(Qgis.RenderUnit.Points) @@ -1509,12 +1800,14 @@ def testToQFont(self): qfont = s.toQFont() self.assertTrue(qfont.italic()) - if int(QT_VERSION_STR.split('.')[0]) > 6 or ( - int(QT_VERSION_STR.split('.')[0]) == 6 and int(QT_VERSION_STR.split('.')[1]) >= 3): + if int(QT_VERSION_STR.split(".")[0]) > 6 or ( + int(QT_VERSION_STR.split(".")[0]) == 6 + and int(QT_VERSION_STR.split(".")[1]) >= 3 + ): s.setStretchFactor(115) qfont = s.toQFont() self.assertEqual(qfont.stretch(), 115) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgstextformatwidget.py b/tests/src/python/test_qgstextformatwidget.py index d20a65ed4bff..86b090f4f65f 100644 --- a/tests/src/python/test_qgstextformatwidget.py +++ b/tests/src/python/test_qgstextformatwidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2016-09' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2016-09" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtCore import QPointF, QSizeF, Qt from qgis.PyQt.QtGui import QColor, QPainter @@ -46,11 +47,21 @@ def createBufferSettings(self): s.setOpacity(0.5) s.setJoinStyle(Qt.PenJoinStyle.RoundJoin) s.setBlendMode(QPainter.CompositionMode.CompositionMode_Difference) - s.setPaintEffect(QgsBlurEffect.create({'blur_level': '2.0', 'blur_unit': QgsUnitTypes.encodeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters), 'enabled': '1'})) + s.setPaintEffect( + QgsBlurEffect.create( + { + "blur_level": "2.0", + "blur_unit": QgsUnitTypes.encodeUnit( + QgsUnitTypes.RenderUnit.RenderMillimeters + ), + "enabled": "1", + } + ) + ) return s def checkBufferSettings(self, s): - """ test QgsTextBufferSettings """ + """test QgsTextBufferSettings""" self.assertTrue(s.enabled()) self.assertEqual(s.size(), 5) self.assertEqual(s.sizeUnit(), QgsUnitTypes.RenderUnit.RenderPixels) @@ -59,7 +70,9 @@ def checkBufferSettings(self, s): self.assertTrue(s.fillBufferInterior()) self.assertEqual(s.opacity(), 0.5) self.assertEqual(s.joinStyle(), Qt.PenJoinStyle.RoundJoin) - self.assertEqual(s.blendMode(), QPainter.CompositionMode.CompositionMode_Difference) + self.assertEqual( + s.blendMode(), QPainter.CompositionMode.CompositionMode_Difference + ) self.assertTrue(s.paintEffect()) self.assertEqual(s.paintEffect().blurLevel(), 2.0) @@ -71,13 +84,27 @@ def createMaskSettings(self): s.setSizeMapUnitScale(QgsMapUnitScale(1, 2)) s.setOpacity(0.5) s.setJoinStyle(Qt.PenJoinStyle.BevelJoin) - s.setPaintEffect(QgsBlurEffect.create({'blur_level': '2.0', 'blur_unit': QgsUnitTypes.encodeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters), 'enabled': '1'})) - s.setMaskedSymbolLayers([QgsSymbolLayerReference("layerid1", QgsSymbolLayerId("symbol", 1)), - QgsSymbolLayerReference("layerid2", QgsSymbolLayerId("symbol2", 2))]) + s.setPaintEffect( + QgsBlurEffect.create( + { + "blur_level": "2.0", + "blur_unit": QgsUnitTypes.encodeUnit( + QgsUnitTypes.RenderUnit.RenderMillimeters + ), + "enabled": "1", + } + ) + ) + s.setMaskedSymbolLayers( + [ + QgsSymbolLayerReference("layerid1", QgsSymbolLayerId("symbol", 1)), + QgsSymbolLayerReference("layerid2", QgsSymbolLayerId("symbol2", 2)), + ] + ) return s def checkMaskSettings(self, s): - """ test QgsTextMaskSettings """ + """test QgsTextMaskSettings""" self.assertTrue(s.enabled()) self.assertEqual(s.size(), 5) self.assertEqual(s.sizeUnit(), QgsUnitTypes.RenderUnit.RenderPixels) @@ -86,14 +113,19 @@ def checkMaskSettings(self, s): self.assertEqual(s.joinStyle(), Qt.PenJoinStyle.BevelJoin) self.assertTrue(s.paintEffect()) self.assertEqual(s.paintEffect().blurLevel(), 2.0) - self.assertEqual(s.maskedSymbolLayers(), [QgsSymbolLayerReference("layerid1", QgsSymbolLayerId("symbol", 1)), - QgsSymbolLayerReference("layerid2", QgsSymbolLayerId("symbol2", 2))]) + self.assertEqual( + s.maskedSymbolLayers(), + [ + QgsSymbolLayerReference("layerid1", QgsSymbolLayerId("symbol", 1)), + QgsSymbolLayerReference("layerid2", QgsSymbolLayerId("symbol2", 2)), + ], + ) def createBackgroundSettings(self): s = QgsTextBackgroundSettings() s.setEnabled(True) s.setType(QgsTextBackgroundSettings.ShapeType.ShapeEllipse) - s.setSvgFile('svg.svg') + s.setSvgFile("svg.svg") s.setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) s.setSize(QSizeF(1, 2)) s.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPixels) @@ -114,7 +146,17 @@ def createBackgroundSettings(self): s.setStrokeWidth(7) s.setStrokeWidthUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) s.setStrokeWidthMapUnitScale(QgsMapUnitScale(QgsMapUnitScale(25, 26))) - s.setPaintEffect(QgsBlurEffect.create({'blur_level': '6.0', 'blur_unit': QgsUnitTypes.encodeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters), 'enabled': '1'})) + s.setPaintEffect( + QgsBlurEffect.create( + { + "blur_level": "6.0", + "blur_unit": QgsUnitTypes.encodeUnit( + QgsUnitTypes.RenderUnit.RenderMillimeters + ), + "enabled": "1", + } + ) + ) marker = QgsMarkerSymbol() marker.setColor(QColor(100, 112, 134)) @@ -123,15 +165,17 @@ def createBackgroundSettings(self): return s def checkBackgroundSettings(self, s): - """ test QgsTextBackgroundSettings """ + """test QgsTextBackgroundSettings""" self.assertTrue(s.enabled()) self.assertEqual(s.type(), QgsTextBackgroundSettings.ShapeType.ShapeEllipse) - self.assertEqual(s.svgFile(), 'svg.svg') + self.assertEqual(s.svgFile(), "svg.svg") self.assertEqual(s.sizeType(), QgsTextBackgroundSettings.SizeType.SizeFixed) self.assertEqual(s.size(), QSizeF(1, 2)) self.assertEqual(s.sizeUnit(), QgsUnitTypes.RenderUnit.RenderPixels) self.assertEqual(s.sizeMapUnitScale(), QgsMapUnitScale(1, 2)) - self.assertEqual(s.rotationType(), QgsTextBackgroundSettings.RotationType.RotationFixed) + self.assertEqual( + s.rotationType(), QgsTextBackgroundSettings.RotationType.RotationFixed + ) self.assertEqual(s.rotation(), 45) self.assertEqual(s.offset(), QPointF(3, 4)) self.assertEqual(s.offsetUnit(), QgsUnitTypes.RenderUnit.RenderMapUnits) @@ -142,7 +186,9 @@ def checkBackgroundSettings(self, s): self.assertEqual(s.fillColor(), QColor(255, 0, 0)) self.assertEqual(s.strokeColor(), QColor(0, 255, 0)) self.assertEqual(s.opacity(), 0.5) - self.assertEqual(s.blendMode(), QPainter.CompositionMode.CompositionMode_Difference) + self.assertEqual( + s.blendMode(), QPainter.CompositionMode.CompositionMode_Difference + ) self.assertEqual(s.strokeWidth(), 7) self.assertEqual(s.strokeWidthUnit(), QgsUnitTypes.RenderUnit.RenderMapUnits) self.assertEqual(s.strokeWidthMapUnitScale(), QgsMapUnitScale(25, 26)) @@ -169,9 +215,11 @@ def createShadowSettings(self): return s def checkShadowSettings(self, s): - """ test QgsTextShadowSettings """ + """test QgsTextShadowSettings""" self.assertTrue(s.enabled()) - self.assertEqual(s.shadowPlacement(), QgsTextShadowSettings.ShadowPlacement.ShadowBuffer) + self.assertEqual( + s.shadowPlacement(), QgsTextShadowSettings.ShadowPlacement.ShadowBuffer + ) self.assertEqual(s.offsetAngle(), 45) self.assertEqual(s.offsetDistance(), 75) self.assertEqual(s.offsetUnit(), QgsUnitTypes.RenderUnit.RenderMapUnits) @@ -184,7 +232,9 @@ def checkShadowSettings(self, s): self.assertEqual(s.color(), QColor(255, 0, 0)) self.assertEqual(s.opacity(), 0.5) self.assertEqual(s.scale(), 123) - self.assertEqual(s.blendMode(), QPainter.CompositionMode.CompositionMode_Difference) + self.assertEqual( + s.blendMode(), QPainter.CompositionMode.CompositionMode_Difference + ) def createFormatSettings(self): s = QgsTextFormat() @@ -195,7 +245,7 @@ def createFormatSettings(self): font = getTestFont() font.setKerning(False) s.setFont(font) - s.setNamedStyle('Roman') + s.setNamedStyle("Roman") s.setSize(5) s.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) s.setSizeMapUnitScale(QgsMapUnitScale(1, 2)) @@ -209,23 +259,27 @@ def createFormatSettings(self): return s def checkTextFormat(self, s): - """ test QgsTextFormat """ + """test QgsTextFormat""" self.checkBufferSettings(s.buffer()) self.checkMaskSettings(s.mask()) self.checkShadowSettings(s.shadow()) self.checkBackgroundSettings(s.background()) - self.assertEqual(s.font().family(), 'QGIS Vera Sans') + self.assertEqual(s.font().family(), "QGIS Vera Sans") self.assertFalse(s.font().kerning()) - self.assertEqual(s.namedStyle(), 'Roman') + self.assertEqual(s.namedStyle(), "Roman") self.assertEqual(s.size(), 5) self.assertEqual(s.sizeUnit(), QgsUnitTypes.RenderUnit.RenderPoints) self.assertEqual(s.sizeMapUnitScale(), QgsMapUnitScale(1, 2)) self.assertEqual(s.color(), QColor(255, 0, 0)) self.assertEqual(s.opacity(), 0.5) - self.assertEqual(s.blendMode(), QPainter.CompositionMode.CompositionMode_Difference) + self.assertEqual( + s.blendMode(), QPainter.CompositionMode.CompositionMode_Difference + ) self.assertEqual(s.lineHeight(), 5) - self.assertEqual(s.orientation(), QgsTextFormat.TextOrientation.VerticalOrientation) - self.assertEqual(s.previewBackgroundColor().name(), '#6496c8') + self.assertEqual( + s.orientation(), QgsTextFormat.TextOrientation.VerticalOrientation + ) + self.assertEqual(s.previewBackgroundColor().name(), "#6496c8") self.assertTrue(s.allowHtmlFormatting()) def testSettings(self): @@ -241,5 +295,5 @@ def testDialogSettings(self): self.checkTextFormat(d.format()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgstextfragment.py b/tests/src/python/test_qgstextfragment.py index 40dc6d3b63fa..ba04cd16504c 100644 --- a/tests/src/python/test_qgstextfragment.py +++ b/tests/src/python/test_qgstextfragment.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '12/05/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "12/05/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtGui import QColor from qgis.core import QgsStringUtils, QgsTextCharacterFormat, QgsTextFragment @@ -26,55 +27,55 @@ def testConstructors(self): frag = QgsTextFragment() self.assertFalse(frag.text()) - fragment = QgsTextFragment('ludicrous gibs!') - self.assertEqual(fragment.text(), 'ludicrous gibs!') + fragment = QgsTextFragment("ludicrous gibs!") + self.assertEqual(fragment.text(), "ludicrous gibs!") def testSetText(self): fragment = QgsTextFragment() - fragment.setText('ludicrous gibs!') - self.assertEqual(fragment.text(), 'ludicrous gibs!') + fragment.setText("ludicrous gibs!") + self.assertEqual(fragment.text(), "ludicrous gibs!") def test_is_tab(self): fragment = QgsTextFragment() self.assertFalse(fragment.isTab()) - fragment.setText('abc') + fragment.setText("abc") self.assertFalse(fragment.isTab()) - fragment.setText('abc\tdef') + fragment.setText("abc\tdef") self.assertFalse(fragment.isTab()) - fragment.setText('\t') + fragment.setText("\t") self.assertTrue(fragment.isTab()) def test_is_whitespace(self): fragment = QgsTextFragment() self.assertTrue(fragment.isWhitespace()) - fragment.setText('abc') + fragment.setText("abc") self.assertFalse(fragment.isWhitespace()) - fragment.setText(' a bc ') + fragment.setText(" a bc ") self.assertFalse(fragment.isWhitespace()) - fragment.setText('abc\tdef') + fragment.setText("abc\tdef") self.assertFalse(fragment.isWhitespace()) - fragment.setText('\t') + fragment.setText("\t") self.assertTrue(fragment.isWhitespace()) - fragment.setText(' ') + fragment.setText(" ") self.assertTrue(fragment.isWhitespace()) - fragment.setText('\t ') + fragment.setText("\t ") self.assertTrue(fragment.isWhitespace()) def testSetCharacterFormat(self): - fragment = QgsTextFragment('a') + fragment = QgsTextFragment("a") self.assertFalse(fragment.characterFormat().textColor().isValid()) format = QgsTextCharacterFormat() format.setTextColor(QColor(255, 0, 0)) fragment.setCharacterFormat(format) self.assertTrue(fragment.characterFormat().textColor().isValid()) - self.assertEqual(fragment.characterFormat().textColor().name(), '#ff0000') + self.assertEqual(fragment.characterFormat().textColor().name(), "#ff0000") def testCapitalize(self): - fragment = QgsTextFragment('ludicrous gibs!') + fragment = QgsTextFragment("ludicrous gibs!") fragment.applyCapitalization(QgsStringUtils.Capitalization.TitleCase) - self.assertEqual(fragment.text(), 'Ludicrous Gibs!') + self.assertEqual(fragment.text(), "Ludicrous Gibs!") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgstextrenderer.py b/tests/src/python/test_qgstextrenderer.py index 3e81f9a82ef5..fa667ee5d647 100644 --- a/tests/src/python/test_qgstextrenderer.py +++ b/tests/src/python/test_qgstextrenderer.py @@ -5,31 +5,17 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2016-09' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2016-09" +__copyright__ = "Copyright 2016, The QGIS Project" import os from typing import Optional from qgis.PyQt.QtSvg import QSvgGenerator -from qgis.PyQt.QtCore import ( - QT_VERSION_STR, - QDir, - QPointF, - QRectF, - QSize, - QSizeF, - Qt -) -from qgis.PyQt.QtGui import ( - QBrush, - QColor, - QImage, - QPainter, - QPen, - QPolygonF -) +from qgis.PyQt.QtCore import QT_VERSION_STR, QDir, QPointF, QRectF, QSize, QSizeF, Qt +from qgis.PyQt.QtGui import QBrush, QColor, QImage, QPainter, QPen, QPolygonF from qgis.core import ( Qgis, QgsBlurEffect, @@ -48,7 +34,7 @@ QgsTextFormat, QgsTextRenderer, QgsTextShadowSettings, - QgsUnitTypes + QgsUnitTypes, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -63,25 +49,52 @@ class PyQgsTextRenderer(QgisTestCase): @classmethod def setUpClass(cls): super().setUpClass() - QgsFontUtils.loadStandardTestFonts(['Bold', 'Oblique']) + QgsFontUtils.loadStandardTestFonts(["Bold", "Oblique"]) @classmethod def control_path_prefix(cls): - return 'text_renderer' + return "text_renderer" def testAlignmentConversion(self): - self.assertEqual(QgsTextRenderer.convertQtHAlignment(Qt.AlignmentFlag.AlignLeft), QgsTextRenderer.HAlignment.AlignLeft) - self.assertEqual(QgsTextRenderer.convertQtHAlignment(Qt.AlignmentFlag.AlignRight), QgsTextRenderer.HAlignment.AlignRight) - self.assertEqual(QgsTextRenderer.convertQtHAlignment(Qt.AlignmentFlag.AlignHCenter), QgsTextRenderer.HAlignment.AlignCenter) - self.assertEqual(QgsTextRenderer.convertQtHAlignment(Qt.AlignmentFlag.AlignJustify), QgsTextRenderer.HAlignment.AlignJustify) + self.assertEqual( + QgsTextRenderer.convertQtHAlignment(Qt.AlignmentFlag.AlignLeft), + QgsTextRenderer.HAlignment.AlignLeft, + ) + self.assertEqual( + QgsTextRenderer.convertQtHAlignment(Qt.AlignmentFlag.AlignRight), + QgsTextRenderer.HAlignment.AlignRight, + ) + self.assertEqual( + QgsTextRenderer.convertQtHAlignment(Qt.AlignmentFlag.AlignHCenter), + QgsTextRenderer.HAlignment.AlignCenter, + ) + self.assertEqual( + QgsTextRenderer.convertQtHAlignment(Qt.AlignmentFlag.AlignJustify), + QgsTextRenderer.HAlignment.AlignJustify, + ) # not supported, should fallback to left - self.assertEqual(QgsTextRenderer.convertQtHAlignment(Qt.AlignmentFlag.AlignAbsolute), QgsTextRenderer.HAlignment.AlignLeft) + self.assertEqual( + QgsTextRenderer.convertQtHAlignment(Qt.AlignmentFlag.AlignAbsolute), + QgsTextRenderer.HAlignment.AlignLeft, + ) - self.assertEqual(QgsTextRenderer.convertQtVAlignment(Qt.AlignmentFlag.AlignTop), QgsTextRenderer.VAlignment.AlignTop) - self.assertEqual(QgsTextRenderer.convertQtVAlignment(Qt.AlignmentFlag.AlignBottom), QgsTextRenderer.VAlignment.AlignBottom) - self.assertEqual(QgsTextRenderer.convertQtVAlignment(Qt.AlignmentFlag.AlignVCenter), QgsTextRenderer.VAlignment.AlignVCenter) + self.assertEqual( + QgsTextRenderer.convertQtVAlignment(Qt.AlignmentFlag.AlignTop), + QgsTextRenderer.VAlignment.AlignTop, + ) + self.assertEqual( + QgsTextRenderer.convertQtVAlignment(Qt.AlignmentFlag.AlignBottom), + QgsTextRenderer.VAlignment.AlignBottom, + ) + self.assertEqual( + QgsTextRenderer.convertQtVAlignment(Qt.AlignmentFlag.AlignVCenter), + QgsTextRenderer.VAlignment.AlignVCenter, + ) # note supported, should fallback to bottom - self.assertEqual(QgsTextRenderer.convertQtVAlignment(Qt.AlignmentFlag.AlignBaseline), QgsTextRenderer.VAlignment.AlignBottom) + self.assertEqual( + QgsTextRenderer.convertQtVAlignment(Qt.AlignmentFlag.AlignBaseline), + QgsTextRenderer.VAlignment.AlignBottom, + ) def testFontMetrics(self): """ @@ -93,7 +106,7 @@ def testFontMetrics(self): s.setSize(12) s.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - string = 'xxxxxxxxxxxxxxxxxxxxxx' + string = "xxxxxxxxxxxxxxxxxxxxxx" image = QImage(400, 400, QImage.Format.Format_RGB32) painter = QPainter(image) @@ -107,15 +120,22 @@ def testFontMetrics(self): self.assertAlmostEqual(metrics.horizontalAdvance(string), 51.9, 1) self.assertAlmostEqual(metrics2.horizontalAdvance(string), 104.15, 1) - def checkRender(self, format, name, part=None, angle=0, alignment=QgsTextRenderer.HAlignment.AlignLeft, - text=['test'], - rect=QRectF(100, 100, 50, 250), - vAlignment=QgsTextRenderer.VAlignment.AlignTop, - flags=Qgis.TextRendererFlags(), - image_size=400, - mode=Qgis.TextLayoutMode.Rectangle, - reference_scale: Optional[float] = None, - renderer_scale: Optional[float] = None): + def checkRender( + self, + format, + name, + part=None, + angle=0, + alignment=QgsTextRenderer.HAlignment.AlignLeft, + text=["test"], + rect=QRectF(100, 100, 50, 250), + vAlignment=QgsTextRenderer.VAlignment.AlignTop, + flags=Qgis.TextRendererFlags(), + image_size=400, + mode=Qgis.TextLayoutMode.Rectangle, + reference_scale: Optional[float] = None, + renderer_scale: Optional[float] = None, + ): image = QImage(image_size, image_size, QImage.Format.Format_RGB32) @@ -126,16 +146,19 @@ def checkRender(self, format, name, part=None, angle=0, alignment=QgsTextRendere context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) if renderer_scale: context.setRendererScale(renderer_scale) if reference_scale: context.setSymbologyReferenceScale(reference_scale) - for render_format in (Qgis.TextRenderFormat.AlwaysText, - Qgis.TextRenderFormat.AlwaysOutlines, - Qgis.TextRenderFormat.PreferText, - ): + for render_format in ( + Qgis.TextRenderFormat.AlwaysText, + Qgis.TextRenderFormat.AlwaysOutlines, + Qgis.TextRenderFormat.PreferText, + ): context.setTextRenderFormat(render_format) painter.begin(image) @@ -148,23 +171,21 @@ def checkRender(self, format, name, part=None, angle=0, alignment=QgsTextRendere # painter.drawRect(rect) if part is not None: - QgsTextRenderer.drawPart(rect, - angle, - alignment, - text, - context, - format, - part) + QgsTextRenderer.drawPart( + rect, angle, alignment, text, context, format, part + ) else: - QgsTextRenderer.drawText(rect, - angle, - alignment, - text, - context, - format, - vAlignment=vAlignment, - flags=flags, - mode=mode) + QgsTextRenderer.drawText( + rect, + angle, + alignment, + text, + context, + format, + vAlignment=vAlignment, + flags=flags, + mode=mode, + ) painter.setFont(format.scaledFont(context)) painter.setPen(QPen(QColor(255, 0, 255, 200))) @@ -182,12 +203,19 @@ def checkRender(self, format, name, part=None, angle=0, alignment=QgsTextRendere return False return True - def checkRenderPoint(self, format, name, part=None, angle=0, alignment=QgsTextRenderer.HAlignment.AlignLeft, - text=['test'], - point=QPointF(100, 200), - image_size=400, - enable_scale_workaround=False, - render_mask=False): + def checkRenderPoint( + self, + format, + name, + part=None, + angle=0, + alignment=QgsTextRenderer.HAlignment.AlignLeft, + text=["test"], + point=QPointF(100, 200), + image_size=400, + enable_scale_workaround=False, + render_mask=False, + ): image = QImage(image_size, image_size, QImage.Format.Format_RGB32) painter = QPainter() @@ -200,12 +228,16 @@ def checkRenderPoint(self, format, name, part=None, angle=0, alignment=QgsTextRe if render_mask: context.setIsGuiPreview(True) - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, enable_scale_workaround) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, + enable_scale_workaround, + ) - for render_format in (Qgis.TextRenderFormat.AlwaysText, - Qgis.TextRenderFormat.AlwaysOutlines, - Qgis.TextRenderFormat.PreferText, - ): + for render_format in ( + Qgis.TextRenderFormat.AlwaysText, + Qgis.TextRenderFormat.AlwaysOutlines, + Qgis.TextRenderFormat.PreferText, + ): context.setTextRenderFormat(render_format) painter.begin(image) painter.setRenderHint(QPainter.RenderHint.Antialiasing) @@ -217,20 +249,11 @@ def checkRenderPoint(self, format, name, part=None, angle=0, alignment=QgsTextRe # painter.drawRect(QRectF(point.x() - 5, point.y() - 5, 10, 10)) if part is not None: - QgsTextRenderer.drawPart(point, - angle, - alignment, - text, - context, - format, - part) + QgsTextRenderer.drawPart( + point, angle, alignment, text, context, format, part + ) else: - QgsTextRenderer.drawText(point, - angle, - alignment, - text, - context, - format) + QgsTextRenderer.drawText(point, angle, alignment, text, context, format) painter.setFont(format.scaledFont(context)) painter.setPen(QPen(QColor(255, 0, 255, 200))) @@ -250,26 +273,45 @@ def testDrawMassiveFont(self): the spacing between these characters is nill or close to a letter spacing """ format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(1100) - self.assertTrue(self.checkRender(format, 'massive_font', rect=QRectF(-800, -600, 1000, 1000), text=['a t'], image_size=800)) + self.assertTrue( + self.checkRender( + format, + "massive_font", + rect=QRectF(-800, -600, 1000, 1000), + text=["a t"], + image_size=800, + ) + ) def testDrawRectMixedHtml(self): """ Test drawing text in rect mode with mixed html fonts """ format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setAllowHtmlFormatting(True) format.setSize(30) - self.assertTrue(self.checkRender(format, 'rect_html', rect=QRectF(100, 100, 100, 100), text=['first line', 'second line', 'third line'])) + self.assertTrue( + self.checkRender( + format, + "rect_html", + rect=QRectF(100, 100, 100, 100), + text=[ + 'first line', + 'second line', + "third line", + ], + ) + ) def testDrawDocumentRect(self): """ Test drawing text document in rect mode """ format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setAllowHtmlFormatting(True) format.setSize(30) @@ -282,7 +324,9 @@ def testDrawDocumentRect(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) painter.begin(image) painter.setRenderHint(QPainter.RenderHint.Antialiasing) @@ -291,89 +335,161 @@ def testDrawDocumentRect(self): painter.setBrush(QBrush(QColor(182, 239, 255))) painter.setPen(Qt.PenStyle.NoPen) - doc = QgsTextDocument.fromHtml(['first line', 'second line', 'third line']) + doc = QgsTextDocument.fromHtml( + [ + 'first line', + 'second line', + "third line", + ] + ) - metrics = QgsTextDocumentMetrics.calculateMetrics(doc, format, context, - QgsTextRenderer.calculateScaleFactorForFormat(context, format)) + metrics = QgsTextDocumentMetrics.calculateMetrics( + doc, + format, + context, + QgsTextRenderer.calculateScaleFactorForFormat(context, format), + ) - QgsTextRenderer.drawDocument(QRectF(100, 100, 100, 100), - format, - doc, - metrics, - context, - mode=Qgis.TextLayoutMode.Rectangle) + QgsTextRenderer.drawDocument( + QRectF(100, 100, 100, 100), + format, + doc, + metrics, + context, + mode=Qgis.TextLayoutMode.Rectangle, + ) painter.end() - self.assertTrue(self.image_check('draw_document_rect', 'draw_document_rect', image, 'draw_document_rect')) + self.assertTrue( + self.image_check( + "draw_document_rect", "draw_document_rect", image, "draw_document_rect" + ) + ) def testDrawRectHtmlBackground(self): """ Test drawing html with backgrounds in rect mode """ format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setAllowHtmlFormatting(True) format.setSize(16) - self.assertTrue(self.checkRender(format, 'html_background_rect', rect=QRectF(10, 100, 300, 100), text=['
    red yellow outside span
    no span yel no bg
    '])) + self.assertTrue( + self.checkRender( + format, + "html_background_rect", + rect=QRectF(10, 100, 300, 100), + text=[ + '
    red yellow outside span
    no span yel no bg
    ' + ], + ) + ) def testDrawPointHtmlBackground(self): """ Test drawing html with backgrounds in point mode """ format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setAllowHtmlFormatting(True) format.setSize(16) - self.assertTrue(self.checkRenderPoint(format, 'html_background_point', point=QPointF(10, 100), text=['
    red yellow outside span
    no span yel no bg
    '])) + self.assertTrue( + self.checkRenderPoint( + format, + "html_background_point", + point=QPointF(10, 100), + text=[ + '
    red yellow outside span
    no span yel no bg
    ' + ], + ) + ) def testDrawRectHtmlBackgroundImage(self): """ Test drawing html with background image in rect mode """ format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setAllowHtmlFormatting(True) format.setSize(36) image_url = unitTestDataPath() + "/raster_brush.png" - self.assertTrue(self.checkRender(format, 'html_background_image_rect', rect=QRectF(10, 100, 300, 100), text=[f'
    test text
    '])) + self.assertTrue( + self.checkRender( + format, + "html_background_image_rect", + rect=QRectF(10, 100, 300, 100), + text=[ + f'
    test text
    ' + ], + ) + ) def testDrawPointHtmlBackgroundImage(self): """ Test drawing html with backgrounds in point mode """ format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setAllowHtmlFormatting(True) format.setSize(36) image_url = unitTestDataPath() + "/raster_brush.png" - self.assertTrue(self.checkRenderPoint(format, 'html_background_image_point', point=QPointF(10, 100), text=[f'
    test text
    '])) + self.assertTrue( + self.checkRenderPoint( + format, + "html_background_image_point", + point=QPointF(10, 100), + text=[ + f'
    test text
    ' + ], + ) + ) def testDrawRectCapHeightMode(self): """ Test drawing text in rect mode with cap height based line heights """ format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) - self.assertTrue(self.checkRender(format, 'rect_cap_height_mode', rect=QRectF(100, 100, 100, 100), text=['first line', 'second line', 'third line'], mode=Qgis.TextLayoutMode.RectangleCapHeightBased)) + self.assertTrue( + self.checkRender( + format, + "rect_cap_height_mode", + rect=QRectF(100, 100, 100, 100), + text=["first line", "second line", "third line"], + mode=Qgis.TextLayoutMode.RectangleCapHeightBased, + ) + ) def testDrawRectCapHeightModeMixedHtml(self): """ Test drawing text in rect mode with cap height based line heights """ format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setAllowHtmlFormatting(True) format.setSize(30) - self.assertTrue(self.checkRender(format, 'rect_cap_height_mode_html', rect=QRectF(100, 100, 100, 100), text=['first line', 'second line', 'third line'], mode=Qgis.TextLayoutMode.RectangleCapHeightBased)) + self.assertTrue( + self.checkRender( + format, + "rect_cap_height_mode_html", + rect=QRectF(100, 100, 100, 100), + text=[ + 'first line', + 'second line', + "third line", + ], + mode=Qgis.TextLayoutMode.RectangleCapHeightBased, + ) + ) def testDrawDocumentRectCapHeightMode(self): """ Test drawing text document in rect cap height mode """ format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setAllowHtmlFormatting(True) format.setSize(30) @@ -386,7 +502,9 @@ def testDrawDocumentRectCapHeightMode(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) painter.begin(image) painter.setRenderHint(QPainter.RenderHint.Antialiasing) @@ -395,47 +513,86 @@ def testDrawDocumentRectCapHeightMode(self): painter.setBrush(QBrush(QColor(182, 239, 255))) painter.setPen(Qt.PenStyle.NoPen) - doc = QgsTextDocument.fromHtml(['first line', 'second line', 'third line']) + doc = QgsTextDocument.fromHtml( + [ + 'first line', + 'second line', + "third line", + ] + ) - metrics = QgsTextDocumentMetrics.calculateMetrics(doc, format, context, - QgsTextRenderer.calculateScaleFactorForFormat(context, format)) + metrics = QgsTextDocumentMetrics.calculateMetrics( + doc, + format, + context, + QgsTextRenderer.calculateScaleFactorForFormat(context, format), + ) - QgsTextRenderer.drawDocument(QRectF(100, 100, 100, 100), - format, - doc, - metrics, - context, - mode=Qgis.TextLayoutMode.RectangleCapHeightBased) + QgsTextRenderer.drawDocument( + QRectF(100, 100, 100, 100), + format, + doc, + metrics, + context, + mode=Qgis.TextLayoutMode.RectangleCapHeightBased, + ) painter.end() - self.assertTrue(self.image_check('draw_document_rect_cap_height', 'draw_document_rect_cap_height', image, 'draw_document_rect_cap_height')) + self.assertTrue( + self.image_check( + "draw_document_rect_cap_height", + "draw_document_rect_cap_height", + image, + "draw_document_rect_cap_height", + ) + ) def testDrawRectAscentMode(self): """ Test drawing text in rect mode with cap height based line heights """ format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) - self.assertTrue(self.checkRender(format, 'rect_ascent_mode', rect=QRectF(100, 100, 100, 100), text=['first line', 'second line', 'third line'], mode=Qgis.TextLayoutMode.RectangleAscentBased)) + self.assertTrue( + self.checkRender( + format, + "rect_ascent_mode", + rect=QRectF(100, 100, 100, 100), + text=["first line", "second line", "third line"], + mode=Qgis.TextLayoutMode.RectangleAscentBased, + ) + ) def testDrawRectAscentModeMixedHtml(self): """ Test drawing text in rect mode with ascent based line heights """ format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setAllowHtmlFormatting(True) format.setSize(30) - self.assertTrue(self.checkRender(format, 'rect_ascent_mode_html', rect=QRectF(100, 100, 100, 100), text=['first line', 'second line', 'third line'], mode=Qgis.TextLayoutMode.RectangleAscentBased)) + self.assertTrue( + self.checkRender( + format, + "rect_ascent_mode_html", + rect=QRectF(100, 100, 100, 100), + text=[ + 'first line', + 'second line', + "third line", + ], + mode=Qgis.TextLayoutMode.RectangleAscentBased, + ) + ) def testDrawDocumentRectAscentMode(self): """ Test drawing text document in rect ascent mode """ format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setAllowHtmlFormatting(True) format.setSize(30) @@ -448,7 +605,9 @@ def testDrawDocumentRectAscentMode(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) painter.begin(image) painter.setRenderHint(QPainter.RenderHint.Antialiasing) @@ -457,34 +616,55 @@ def testDrawDocumentRectAscentMode(self): painter.setBrush(QBrush(QColor(182, 239, 255))) painter.setPen(Qt.PenStyle.NoPen) - doc = QgsTextDocument.fromHtml(['first line', 'second line', 'third line']) + doc = QgsTextDocument.fromHtml( + [ + 'first line', + 'second line', + "third line", + ] + ) - metrics = QgsTextDocumentMetrics.calculateMetrics(doc, format, context, - QgsTextRenderer.calculateScaleFactorForFormat(context, format)) + metrics = QgsTextDocumentMetrics.calculateMetrics( + doc, + format, + context, + QgsTextRenderer.calculateScaleFactorForFormat(context, format), + ) - QgsTextRenderer.drawDocument(QRectF(100, 100, 100, 100), - format, - doc, - metrics, - context, - mode=Qgis.TextLayoutMode.RectangleAscentBased) + QgsTextRenderer.drawDocument( + QRectF(100, 100, 100, 100), + format, + doc, + metrics, + context, + mode=Qgis.TextLayoutMode.RectangleAscentBased, + ) painter.end() - self.assertTrue(self.image_check('draw_document_rect_ascent', 'draw_document_rect_ascent', image, 'draw_document_rect_ascent')) + self.assertTrue( + self.image_check( + "draw_document_rect_ascent", + "draw_document_rect_ascent", + image, + "draw_document_rect_ascent", + ) + ) def testDrawDocumentShadowPlacement(self): """ Test drawing text document with shadow placement lowest """ format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setAllowHtmlFormatting(True) format.setSize(30) format.setColor(QColor(255, 255, 255)) format.shadow().setEnabled(True) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowLowest) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowLowest + ) format.shadow().setOpacity(1.0) format.shadow().setBlurRadius(0) format.shadow().setOffsetDistance(5) @@ -499,7 +679,9 @@ def testDrawDocumentShadowPlacement(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) painter.begin(image) painter.setRenderHint(QPainter.RenderHint.Antialiasing) @@ -508,21 +690,40 @@ def testDrawDocumentShadowPlacement(self): painter.setBrush(QBrush(QColor(182, 239, 255))) painter.setPen(Qt.PenStyle.NoPen) - doc = QgsTextDocument.fromHtml(['first line', 'second line', 'third line']) + doc = QgsTextDocument.fromHtml( + [ + 'first line', + 'second line', + "third line", + ] + ) - metrics = QgsTextDocumentMetrics.calculateMetrics(doc, format, context, - QgsTextRenderer.calculateScaleFactorForFormat(context, format)) + metrics = QgsTextDocumentMetrics.calculateMetrics( + doc, + format, + context, + QgsTextRenderer.calculateScaleFactorForFormat(context, format), + ) - QgsTextRenderer.drawDocument(QRectF(100, 100, 100, 100), - format, - doc, - metrics, - context, - mode=Qgis.TextLayoutMode.RectangleAscentBased) + QgsTextRenderer.drawDocument( + QRectF(100, 100, 100, 100), + format, + doc, + metrics, + context, + mode=Qgis.TextLayoutMode.RectangleAscentBased, + ) painter.end() - self.assertTrue(self.image_check('draw_document_shadow_lowest', 'draw_document_shadow_lowest', image, 'draw_document_shadow_lowest')) + self.assertTrue( + self.image_check( + "draw_document_shadow_lowest", + "draw_document_shadow_lowest", + image, + "draw_document_shadow_lowest", + ) + ) def testDrawForcedItalic(self): """ @@ -532,82 +733,106 @@ def testDrawForcedItalic(self): format.setFont(getTestFont()) format.setSize(30) format.setForcedItalic(True) - self.assertTrue(self.checkRender(format, 'forced_italic', text=['Forced italic'])) + self.assertTrue( + self.checkRender(format, "forced_italic", text=["Forced italic"]) + ) def testDrawRTL(self): """ Test drawing with simple rtl text """ format = QgsTextFormat() - format.setFont(getTestFont('Deja bold')) + format.setFont(getTestFont("Deja bold")) format.setSize(30) - self.assertTrue(self.checkRenderPoint(format, 'rtl', text=['مرحبا بالعالم'], - point=QPointF(5, 200))) + self.assertTrue( + self.checkRenderPoint( + format, "rtl", text=["مرحبا بالعالم"], point=QPointF(5, 200) + ) + ) def testDrawRTLHTML(self): """ Test drawing with rtl text with HTML formatting """ format = QgsTextFormat() - format.setFont(getTestFont('Deja bold')) + format.setFont(getTestFont("Deja bold")) format.setSize(30) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRenderPoint(format, 'rtl_html', text=['بالعالم مرحبا'], - point=QPointF(5, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "rtl_html", + text=['بالعالم مرحبا'], + point=QPointF(5, 200), + ) + ) def testDrawRTLRightAlign(self): """ Test drawing with rtl text with right align """ format = QgsTextFormat() - format.setFont(getTestFont('Deja bold')) + format.setFont(getTestFont("Deja bold")) format.setSize(30) - self.assertTrue(self.checkRender(format, 'rtl_right_align', text=['مرحبا بالعالم'], - rect=QRectF(5, 100, 350, 250), - alignment=QgsTextRenderer.HAlignment.AlignRight)) + self.assertTrue( + self.checkRender( + format, + "rtl_right_align", + text=["مرحبا بالعالم"], + rect=QRectF(5, 100, 350, 250), + alignment=QgsTextRenderer.HAlignment.AlignRight, + ) + ) def testDrawRTLBuffer(self): """ Test drawing with right to left text with buffer """ format = QgsTextFormat() - format.setFont(getTestFont('Deja bold')) + format.setFont(getTestFont("Deja bold")) format.setSize(30) format.buffer().setEnabled(True) format.buffer().setSize(2) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRenderPoint(format, 'rtl_buffer', text=['مرحبا بالعالم'], - point=QPointF(5, 200))) + self.assertTrue( + self.checkRenderPoint( + format, "rtl_buffer", text=["مرحبا بالعالم"], point=QPointF(5, 200) + ) + ) def testDrawRTLShadow(self): """ Test drawing with right to left text with shadow """ format = QgsTextFormat() - format.setFont(getTestFont('Deja bold')) + format.setFont(getTestFont("Deja bold")) format.setSize(30) - format.setColor( - QColor(255, 255, 0)) + format.setColor(QColor(255, 255, 0)) format.shadow().setEnabled(True) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowText) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowText + ) format.shadow().setOpacity(1.0) format.shadow().setBlurRadius(0) format.shadow().setOffsetDistance(5) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRenderPoint(format, 'rtl_shadow', text=['مرحبا بالعالم'], - point=QPointF(5, 200))) + self.assertTrue( + self.checkRenderPoint( + format, "rtl_shadow", text=["مرحبا بالعالم"], point=QPointF(5, 200) + ) + ) - @unittest.skip('broken') + @unittest.skip("broken") def testDrawTextOnLineRTL(self): """ Test drawing right to left text on line """ format = QgsTextFormat() - format.setFont(getTestFont('Deja bold')) + format.setFont(getTestFont("Deja bold")) format.setSize(25) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) @@ -620,7 +845,9 @@ def testDrawTextOnLineRTL(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) painter.begin(image) painter.setRenderHint(QPainter.RenderHint.Antialiasing) @@ -635,603 +862,957 @@ def testDrawTextOnLineRTL(self): painter.setBrush(QBrush(QColor(182, 239, 255))) painter.setPen(Qt.PenStyle.NoPen) - QgsTextRenderer.drawTextOnLine(line, 'مرحبا بالعالم', context, format, 0) + QgsTextRenderer.drawTextOnLine(line, "مرحبا بالعالم", context, format, 0) painter.end() - self.assertTrue(self.image_check('text_on_line_at_start', 'text_on_line_at_start', image, 'text_on_line_at_start')) + self.assertTrue( + self.image_check( + "text_on_line_at_start", + "text_on_line_at_start", + image, + "text_on_line_at_start", + ) + ) def testDrawRTLLTRMixed(self): """ Test drawing with mixed right to left and left to right text """ format = QgsTextFormat() - format.setFont(getTestFont('Deja bold')) + format.setFont(getTestFont("Deja bold")) format.setSize(30) - self.assertTrue(self.checkRenderPoint(format, 'rtl_mixed', text=['hello באמת abc'], - point=QPointF(5, 200))) + self.assertTrue( + self.checkRenderPoint( + format, "rtl_mixed", text=["hello באמת abc"], point=QPointF(5, 200) + ) + ) def testDrawRTLLTRMixedHtml(self): """ Test drawing with right to left marker, html mode """ format = QgsTextFormat() - format.setFont(getTestFont('Deja bold')) + format.setFont(getTestFont("Deja bold")) format.setSize(30) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRenderPoint(format, 'rtl_mixed_html', text=['hello באמת abc'], - point=QPointF(5, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "rtl_mixed_html", + text=["hello באמת abc"], + point=QPointF(5, 200), + ) + ) def testDrawRTLLTRMixedRect(self): """ Test drawing with right to left marker in rect mode, right aligned """ format = QgsTextFormat() - format.setFont(getTestFont('Deja bold')) + format.setFont(getTestFont("Deja bold")) format.setSize(30) - self.assertTrue(self.checkRender(format, 'rtl_mixed_right_align', text=['hello באמת abc'], - rect=QRectF(5, 100, 350, 250), - alignment=QgsTextRenderer.HAlignment.AlignRight)) + self.assertTrue( + self.checkRender( + format, + "rtl_mixed_right_align", + text=["hello באמת abc"], + rect=QRectF(5, 100, 350, 250), + alignment=QgsTextRenderer.HAlignment.AlignRight, + ) + ) def testDrawRTLLTRMixedBuffer(self): """ Test drawing with right to left marker with buffer """ format = QgsTextFormat() - format.setFont(getTestFont('Deja bold')) + format.setFont(getTestFont("Deja bold")) format.setSize(30) format.buffer().setEnabled(True) format.buffer().setSize(2) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRenderPoint(format, 'rtl_mixed_buffer', text=['hello באמת abc'], - point=QPointF(5, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "rtl_mixed_buffer", + text=["hello באמת abc"], + point=QPointF(5, 200), + ) + ) def testDrawRTLLTRMixedShadow(self): """ Test drawing with right to left marker with shadow """ format = QgsTextFormat() - format.setFont(getTestFont('Deja bold')) + format.setFont(getTestFont("Deja bold")) format.setSize(30) - format.setColor( - QColor(255, 255, 0)) + format.setColor(QColor(255, 255, 0)) format.shadow().setEnabled(True) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowText) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowText + ) format.shadow().setOpacity(1.0) format.shadow().setBlurRadius(0) format.shadow().setOffsetDistance(5) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRenderPoint(format, 'rtl_mixed_shadow', text=['hello באמת abc'], - point=QPointF(5, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "rtl_mixed_shadow", + text=["hello באמת abc"], + point=QPointF(5, 200), + ) + ) - @unittest.skipIf(int(QT_VERSION_STR.split('.')[0]) < 6 or (int(QT_VERSION_STR.split('.')[0]) == 6 and int(QT_VERSION_STR.split('.')[1]) < 3), 'Too old Qt') + @unittest.skipIf( + int(QT_VERSION_STR.split(".")[0]) < 6 + or ( + int(QT_VERSION_STR.split(".")[0]) == 6 + and int(QT_VERSION_STR.split(".")[1]) < 3 + ), + "Too old Qt", + ) def testDrawSmallCaps(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setCapitalization(Qgis.Capitalization.SmallCaps) format.setSize(30) - self.assertTrue(self.checkRender(format, 'mixed_small_caps', text=['Small Caps'])) + self.assertTrue( + self.checkRender(format, "mixed_small_caps", text=["Small Caps"]) + ) - @unittest.skipIf(int(QT_VERSION_STR.split('.')[0]) < 6 or (int(QT_VERSION_STR.split('.')[0]) == 6 and int(QT_VERSION_STR.split('.')[1]) < 3), 'Too old Qt') + @unittest.skipIf( + int(QT_VERSION_STR.split(".")[0]) < 6 + or ( + int(QT_VERSION_STR.split(".")[0]) == 6 + and int(QT_VERSION_STR.split(".")[1]) < 3 + ), + "Too old Qt", + ) def testDrawAllSmallCaps(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setCapitalization(Qgis.Capitalization.AllSmallCaps) - self.assertTrue(self.checkRender(format, 'all_small_caps', text=['Small Caps'])) - - @unittest.skipIf(int(QT_VERSION_STR.split('.')[0]) < 6 or (int(QT_VERSION_STR.split('.')[0]) == 6 and int(QT_VERSION_STR.split('.')[1]) < 3), 'Too old Qt') + self.assertTrue(self.checkRender(format, "all_small_caps", text=["Small Caps"])) + + @unittest.skipIf( + int(QT_VERSION_STR.split(".")[0]) < 6 + or ( + int(QT_VERSION_STR.split(".")[0]) == 6 + and int(QT_VERSION_STR.split(".")[1]) < 3 + ), + "Too old Qt", + ) def testDrawStretch(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setStretchFactor(150) - self.assertTrue(self.checkRender(format, 'stretch_expand')) - - @unittest.skipIf(int(QT_VERSION_STR.split('.')[0]) < 6 or (int(QT_VERSION_STR.split('.')[0]) == 6 and int(QT_VERSION_STR.split('.')[1]) < 3), 'Too old Qt') + self.assertTrue(self.checkRender(format, "stretch_expand")) + + @unittest.skipIf( + int(QT_VERSION_STR.split(".")[0]) < 6 + or ( + int(QT_VERSION_STR.split(".")[0]) == 6 + and int(QT_VERSION_STR.split(".")[1]) < 3 + ), + "Too old Qt", + ) def testDrawStretchCondense(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setStretchFactor(50) - self.assertTrue(self.checkRender(format, 'stretch_condense')) + self.assertTrue(self.checkRender(format, "stretch_condense")) def testDrawBackgroundDisabled(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(False) - self.assertTrue(self.checkRender(format, 'background_disabled', QgsTextRenderer.TextPart.Background)) + self.assertTrue( + self.checkRender( + format, "background_disabled", QgsTextRenderer.TextPart.Background + ) + ) def testDrawBackgroundRectangleFixedSizeMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(20, 10)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'background_rect_mapunits', QgsTextRenderer.TextPart.Background)) + self.assertTrue( + self.checkRender( + format, "background_rect_mapunits", QgsTextRenderer.TextPart.Background + ) + ) def testDrawBackgroundRectangleFixedSizeWithRotatedText(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(40) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(20, 20)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRenderPoint(format, 'background_rect_fixed_rotated_text', angle=3.141 / 4)) + self.assertTrue( + self.checkRenderPoint( + format, "background_rect_fixed_rotated_text", angle=3.141 / 4 + ) + ) def testDrawBackgroundRectangleBufferSizeWithRotatedText(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(40) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(2, 3)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeBuffer) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRenderPoint(format, 'background_rect_buffer_rotated_text', angle=3.141 / 4)) + self.assertTrue( + self.checkRenderPoint( + format, "background_rect_buffer_rotated_text", angle=3.141 / 4 + ) + ) def testDrawBackgroundRectangleMultilineFixedSizeMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(20, 10)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'background_rect_multiline_mapunits', QgsTextRenderer.TextPart.Background, - text=['test', 'multi', 'line'])) + self.assertTrue( + self.checkRender( + format, + "background_rect_multiline_mapunits", + QgsTextRenderer.TextPart.Background, + text=["test", "multi", "line"], + ) + ) def testDrawBackgroundPointMultilineFixedSizeMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(20, 10)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRenderPoint(format, 'background_point_multiline_mapunits', QgsTextRenderer.TextPart.Background, - text=['test', 'multi', 'line'])) + self.assertTrue( + self.checkRenderPoint( + format, + "background_point_multiline_mapunits", + QgsTextRenderer.TextPart.Background, + text=["test", "multi", "line"], + ) + ) def testDrawBackgroundRectangleMultilineBufferMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(4, 2)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeBuffer) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'background_rect_multiline_buffer_mapunits', QgsTextRenderer.TextPart.Background, - text=['test', 'multi', 'line'])) + self.assertTrue( + self.checkRender( + format, + "background_rect_multiline_buffer_mapunits", + QgsTextRenderer.TextPart.Background, + text=["test", "multi", "line"], + ) + ) def testDrawBackgroundPointMultilineBufferMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(4, 2)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeBuffer) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRenderPoint(format, 'background_point_multiline_buffer_mapunits', QgsTextRenderer.TextPart.Background, - text=['test', 'multi', 'line'])) + self.assertTrue( + self.checkRenderPoint( + format, + "background_point_multiline_buffer_mapunits", + QgsTextRenderer.TextPart.Background, + text=["test", "multi", "line"], + ) + ) def testDrawBackgroundPointFixedSizeMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(20, 10)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRenderPoint(format, 'background_point_mapunits', QgsTextRenderer.TextPart.Background, - text=['Testy'])) + self.assertTrue( + self.checkRenderPoint( + format, + "background_point_mapunits", + QgsTextRenderer.TextPart.Background, + text=["Testy"], + ) + ) def testDrawBackgroundRectangleCenterAlignFixedSizeMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(20, 10)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'background_rect_center_mapunits', QgsTextRenderer.TextPart.Background, - alignment=QgsTextRenderer.HAlignment.AlignCenter)) + self.assertTrue( + self.checkRender( + format, + "background_rect_center_mapunits", + QgsTextRenderer.TextPart.Background, + alignment=QgsTextRenderer.HAlignment.AlignCenter, + ) + ) def testDrawBackgroundPointCenterAlignFixedSizeMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(20, 10)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRenderPoint(format, 'background_point_center_mapunits', QgsTextRenderer.TextPart.Background, - alignment=QgsTextRenderer.HAlignment.AlignCenter)) + self.assertTrue( + self.checkRenderPoint( + format, + "background_point_center_mapunits", + QgsTextRenderer.TextPart.Background, + alignment=QgsTextRenderer.HAlignment.AlignCenter, + ) + ) def testDrawBackgroundRectangleRightAlignFixedSizeMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(20, 10)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'background_rect_right_mapunits', QgsTextRenderer.TextPart.Background, - alignment=QgsTextRenderer.HAlignment.AlignRight)) + self.assertTrue( + self.checkRender( + format, + "background_rect_right_mapunits", + QgsTextRenderer.TextPart.Background, + alignment=QgsTextRenderer.HAlignment.AlignRight, + ) + ) def testDrawBackgroundPointRightAlignFixedSizeMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(20, 10)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRenderPoint(format, 'background_point_right_mapunits', QgsTextRenderer.TextPart.Background, - alignment=QgsTextRenderer.HAlignment.AlignRight)) + self.assertTrue( + self.checkRenderPoint( + format, + "background_point_right_mapunits", + QgsTextRenderer.TextPart.Background, + alignment=QgsTextRenderer.HAlignment.AlignRight, + ) + ) def testDrawBackgroundRectangleFixedSizeMM(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(30, 20)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'background_rect_mm', QgsTextRenderer.TextPart.Background)) + self.assertTrue( + self.checkRender( + format, "background_rect_mm", QgsTextRenderer.TextPart.Background + ) + ) def testDrawBackgroundRectangleFixedSizePixels(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(60, 80)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderPixels) - self.assertTrue(self.checkRender(format, 'background_rect_pixels', QgsTextRenderer.TextPart.Background)) + self.assertTrue( + self.checkRender( + format, "background_rect_pixels", QgsTextRenderer.TextPart.Background + ) + ) def testDrawBackgroundRectBufferPixels(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - svg = os.path.join( - svgSymbolsPath(), 'backgrounds', 'background_square.svg') + svg = os.path.join(svgSymbolsPath(), "backgrounds", "background_square.svg") format.background().setSvgFile(svg) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(30, 50)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeBuffer) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderPixels) - self.assertTrue(self.checkRender(format, 'background_rect_buffer_pixels', QgsTextRenderer.TextPart.Background, - rect=QRectF(100, 100, 100, 100))) + self.assertTrue( + self.checkRender( + format, + "background_rect_buffer_pixels", + QgsTextRenderer.TextPart.Background, + rect=QRectF(100, 100, 100, 100), + ) + ) def testDrawBackgroundRectRightAlignBufferPixels(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - svg = os.path.join( - svgSymbolsPath(), 'backgrounds', 'background_square.svg') + svg = os.path.join(svgSymbolsPath(), "backgrounds", "background_square.svg") format.background().setSvgFile(svg) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(30, 50)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeBuffer) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderPixels) - self.assertTrue(self.checkRender(format, 'background_rect_right_buffer_pixels', QgsTextRenderer.TextPart.Background, - alignment=QgsTextRenderer.HAlignment.AlignRight, - rect=QRectF(100, 100, 100, 100))) + self.assertTrue( + self.checkRender( + format, + "background_rect_right_buffer_pixels", + QgsTextRenderer.TextPart.Background, + alignment=QgsTextRenderer.HAlignment.AlignRight, + rect=QRectF(100, 100, 100, 100), + ) + ) def testDrawBackgroundRectCenterAlignBufferPixels(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - svg = os.path.join( - svgSymbolsPath(), 'backgrounds', 'background_square.svg') + svg = os.path.join(svgSymbolsPath(), "backgrounds", "background_square.svg") format.background().setSvgFile(svg) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(30, 50)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeBuffer) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderPixels) - self.assertTrue(self.checkRender(format, 'background_rect_center_buffer_pixels', QgsTextRenderer.TextPart.Background, - alignment=QgsTextRenderer.HAlignment.AlignCenter, - rect=QRectF(100, 100, 100, 100))) + self.assertTrue( + self.checkRender( + format, + "background_rect_center_buffer_pixels", + QgsTextRenderer.TextPart.Background, + alignment=QgsTextRenderer.HAlignment.AlignCenter, + rect=QRectF(100, 100, 100, 100), + ) + ) def testDrawBackgroundPointBufferPixels(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - svg = os.path.join( - svgSymbolsPath(), 'backgrounds', 'background_square.svg') + svg = os.path.join(svgSymbolsPath(), "backgrounds", "background_square.svg") format.background().setSvgFile(svg) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(30, 50)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeBuffer) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderPixels) - self.assertTrue(self.checkRenderPoint(format, 'background_point_buffer_pixels', QgsTextRenderer.TextPart.Background, - point=QPointF(100, 100))) + self.assertTrue( + self.checkRenderPoint( + format, + "background_point_buffer_pixels", + QgsTextRenderer.TextPart.Background, + point=QPointF(100, 100), + ) + ) def testDrawBackgroundPointRightAlignBufferPixels(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - svg = os.path.join( - svgSymbolsPath(), 'backgrounds', 'background_square.svg') + svg = os.path.join(svgSymbolsPath(), "backgrounds", "background_square.svg") format.background().setSvgFile(svg) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(30, 50)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeBuffer) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderPixels) - self.assertTrue(self.checkRenderPoint(format, 'background_point_right_buffer_pixels', QgsTextRenderer.TextPart.Background, - alignment=QgsTextRenderer.HAlignment.AlignRight, - point=QPointF(100, 100))) + self.assertTrue( + self.checkRenderPoint( + format, + "background_point_right_buffer_pixels", + QgsTextRenderer.TextPart.Background, + alignment=QgsTextRenderer.HAlignment.AlignRight, + point=QPointF(100, 100), + ) + ) def testDrawBackgroundPointCenterAlignBufferPixels(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - svg = os.path.join( - svgSymbolsPath(), 'backgrounds', 'background_square.svg') + svg = os.path.join(svgSymbolsPath(), "backgrounds", "background_square.svg") format.background().setSvgFile(svg) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(30, 50)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeBuffer) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderPixels) - self.assertTrue(self.checkRenderPoint(format, 'background_point_center_buffer_pixels', QgsTextRenderer.TextPart.Background, - alignment=QgsTextRenderer.HAlignment.AlignCenter, - point=QPointF(100, 100))) + self.assertTrue( + self.checkRenderPoint( + format, + "background_point_center_buffer_pixels", + QgsTextRenderer.TextPart.Background, + alignment=QgsTextRenderer.HAlignment.AlignCenter, + point=QPointF(100, 100), + ) + ) def testDrawBackgroundRectBufferMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - svg = os.path.join( - svgSymbolsPath(), 'backgrounds', 'background_square.svg') + svg = os.path.join(svgSymbolsPath(), "backgrounds", "background_square.svg") format.background().setSvgFile(svg) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(4, 6)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeBuffer) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'background_rect_buffer_mapunits', QgsTextRenderer.TextPart.Background, - rect=QRectF(100, 100, 100, 100))) + self.assertTrue( + self.checkRender( + format, + "background_rect_buffer_mapunits", + QgsTextRenderer.TextPart.Background, + rect=QRectF(100, 100, 100, 100), + ) + ) def testDrawBackgroundRectBufferMM(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - svg = os.path.join( - svgSymbolsPath(), 'backgrounds', 'background_square.svg') + svg = os.path.join(svgSymbolsPath(), "backgrounds", "background_square.svg") format.background().setSvgFile(svg) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(10, 16)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeBuffer) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'background_rect_buffer_mm', QgsTextRenderer.TextPart.Background, - rect=QRectF(100, 100, 100, 100))) + self.assertTrue( + self.checkRender( + format, + "background_rect_buffer_mm", + QgsTextRenderer.TextPart.Background, + rect=QRectF(100, 100, 100, 100), + ) + ) def testDrawBackgroundEllipse(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeEllipse) format.background().setSize(QSizeF(60, 80)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderPixels) - self.assertTrue(self.checkRender(format, 'background_ellipse_pixels', QgsTextRenderer.TextPart.Background)) + self.assertTrue( + self.checkRender( + format, "background_ellipse_pixels", QgsTextRenderer.TextPart.Background + ) + ) def testDrawBackgroundSvgFixedPixels(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - svg = os.path.join( - svgSymbolsPath(), 'backgrounds', 'background_square.svg') + svg = os.path.join(svgSymbolsPath(), "backgrounds", "background_square.svg") format.background().setSvgFile(svg) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeSVG) format.background().setSize(QSizeF(60, 80)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderPixels) - self.assertTrue(self.checkRender(format, 'background_svg_fixed_pixels', QgsTextRenderer.TextPart.Background)) + self.assertTrue( + self.checkRender( + format, + "background_svg_fixed_pixels", + QgsTextRenderer.TextPart.Background, + ) + ) def testDrawBackgroundSvgFixedMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - svg = os.path.join( - svgSymbolsPath(), 'backgrounds', 'background_square.svg') + svg = os.path.join(svgSymbolsPath(), "backgrounds", "background_square.svg") format.background().setSvgFile(svg) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeSVG) format.background().setSize(QSizeF(20, 20)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'background_svg_fixed_mapunits', QgsTextRenderer.TextPart.Background)) + self.assertTrue( + self.checkRender( + format, + "background_svg_fixed_mapunits", + QgsTextRenderer.TextPart.Background, + ) + ) def testDrawBackgroundSvgFixedMM(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - svg = os.path.join( - svgSymbolsPath(), 'backgrounds', 'background_square.svg') + svg = os.path.join(svgSymbolsPath(), "backgrounds", "background_square.svg") format.background().setSvgFile(svg) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeSVG) format.background().setSize(QSizeF(30, 30)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'background_svg_fixed_mm', QgsTextRenderer.TextPart.Background)) + self.assertTrue( + self.checkRender( + format, "background_svg_fixed_mm", QgsTextRenderer.TextPart.Background + ) + ) def testDrawBackgroundRotationSynced(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(30, 20)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.background().setRotation(45) # should be ignored - format.background().setRotationType(QgsTextBackgroundSettings.RotationType.RotationSync) - self.assertTrue(self.checkRender(format, 'background_rotation_sync', QgsTextRenderer.TextPart.Background, angle=20)) + format.background().setRotationType( + QgsTextBackgroundSettings.RotationType.RotationSync + ) + self.assertTrue( + self.checkRender( + format, + "background_rotation_sync", + QgsTextRenderer.TextPart.Background, + angle=20, + ) + ) def testDrawBackgroundSvgBufferPixels(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - svg = os.path.join( - svgSymbolsPath(), 'backgrounds', 'background_square.svg') + svg = os.path.join(svgSymbolsPath(), "backgrounds", "background_square.svg") format.background().setSvgFile(svg) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeSVG) format.background().setSize(QSizeF(30, 30)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeBuffer) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderPixels) - self.assertTrue(self.checkRender(format, 'background_svg_buffer_pixels', QgsTextRenderer.TextPart.Background, - rect=QRectF(100, 100, 100, 100))) + self.assertTrue( + self.checkRender( + format, + "background_svg_buffer_pixels", + QgsTextRenderer.TextPart.Background, + rect=QRectF(100, 100, 100, 100), + ) + ) def testDrawBackgroundSvgBufferMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - svg = os.path.join( - svgSymbolsPath(), 'backgrounds', 'background_square.svg') + svg = os.path.join(svgSymbolsPath(), "backgrounds", "background_square.svg") format.background().setSvgFile(svg) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeSVG) format.background().setSize(QSizeF(4, 4)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeBuffer) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'background_svg_buffer_mapunits', QgsTextRenderer.TextPart.Background, - rect=QRectF(100, 100, 100, 100))) + self.assertTrue( + self.checkRender( + format, + "background_svg_buffer_mapunits", + QgsTextRenderer.TextPart.Background, + rect=QRectF(100, 100, 100, 100), + ) + ) def testDrawBackgroundSvgBufferMM(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - svg = os.path.join( - svgSymbolsPath(), 'backgrounds', 'background_square.svg') + svg = os.path.join(svgSymbolsPath(), "backgrounds", "background_square.svg") format.background().setSvgFile(svg) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeSVG) format.background().setSize(QSizeF(10, 10)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeBuffer) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'background_svg_buffer_mm', QgsTextRenderer.TextPart.Background, - rect=QRectF(100, 100, 100, 100))) + self.assertTrue( + self.checkRender( + format, + "background_svg_buffer_mm", + QgsTextRenderer.TextPart.Background, + rect=QRectF(100, 100, 100, 100), + ) + ) def testDrawBackgroundMarkerFixedPixels(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - format.background().setMarkerSymbol(QgsMarkerSymbol.createSimple( - {'color': '#ffffff', 'size': '3', 'outline_color': 'red', 'outline_width': '3'})) - format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeMarkerSymbol) + format.background().setMarkerSymbol( + QgsMarkerSymbol.createSimple( + { + "color": "#ffffff", + "size": "3", + "outline_color": "red", + "outline_width": "3", + } + ) + ) + format.background().setType( + QgsTextBackgroundSettings.ShapeType.ShapeMarkerSymbol + ) format.background().setSize(QSizeF(60, 80)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderPixels) - self.assertTrue(self.checkRender(format, 'background_marker_fixed_pixels', QgsTextRenderer.TextPart.Background)) + self.assertTrue( + self.checkRender( + format, + "background_marker_fixed_pixels", + QgsTextRenderer.TextPart.Background, + ) + ) def testDrawBackgroundMarkerFixedReferenceScale(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(16) format.background().setEnabled(True) - format.background().setMarkerSymbol(QgsMarkerSymbol.createSimple( - {'color': '#ffffff', 'size': '3', 'outline_color': 'red', 'outline_width': '3'})) - format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeMarkerSymbol) + format.background().setMarkerSymbol( + QgsMarkerSymbol.createSimple( + { + "color": "#ffffff", + "size": "3", + "outline_color": "red", + "outline_width": "3", + } + ) + ) + format.background().setType( + QgsTextBackgroundSettings.ShapeType.ShapeMarkerSymbol + ) format.background().setSize(QSizeF(6, 8)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'background_marker_fixed_reference_scale', - reference_scale=10000, renderer_scale=5000)) + self.assertTrue( + self.checkRender( + format, + "background_marker_fixed_reference_scale", + reference_scale=10000, + renderer_scale=5000, + ) + ) def testDrawBackgroundMarkerFixedMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - format.background().setMarkerSymbol(QgsMarkerSymbol.createSimple( - {'color': '#ffffff', 'size': '3', 'outline_color': 'red', 'outline_width': '3'})) - format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeMarkerSymbol) + format.background().setMarkerSymbol( + QgsMarkerSymbol.createSimple( + { + "color": "#ffffff", + "size": "3", + "outline_color": "red", + "outline_width": "3", + } + ) + ) + format.background().setType( + QgsTextBackgroundSettings.ShapeType.ShapeMarkerSymbol + ) format.background().setSize(QSizeF(20, 20)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'background_marker_fixed_mapunits', QgsTextRenderer.TextPart.Background)) + self.assertTrue( + self.checkRender( + format, + "background_marker_fixed_mapunits", + QgsTextRenderer.TextPart.Background, + ) + ) def testDrawBackgroundMarkerFixedMM(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - format.background().setMarkerSymbol(QgsMarkerSymbol.createSimple( - {'color': '#ffffff', 'size': '3', 'outline_color': 'red', 'outline_width': '3'})) - format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeMarkerSymbol) + format.background().setMarkerSymbol( + QgsMarkerSymbol.createSimple( + { + "color": "#ffffff", + "size": "3", + "outline_color": "red", + "outline_width": "3", + } + ) + ) + format.background().setType( + QgsTextBackgroundSettings.ShapeType.ShapeMarkerSymbol + ) format.background().setSize(QSizeF(30, 30)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'background_marker_fixed_mm', QgsTextRenderer.TextPart.Background)) + self.assertTrue( + self.checkRender( + format, + "background_marker_fixed_mm", + QgsTextRenderer.TextPart.Background, + ) + ) def testDrawBackgroundMarkerBufferPixels(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - format.background().setMarkerSymbol(QgsMarkerSymbol.createSimple( - {'color': '#ffffff', 'size': '3', 'outline_color': 'red', 'outline_width': '3'})) - format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeMarkerSymbol) + format.background().setMarkerSymbol( + QgsMarkerSymbol.createSimple( + { + "color": "#ffffff", + "size": "3", + "outline_color": "red", + "outline_width": "3", + } + ) + ) + format.background().setType( + QgsTextBackgroundSettings.ShapeType.ShapeMarkerSymbol + ) format.background().setSize(QSizeF(30, 30)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeBuffer) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderPixels) - self.assertTrue(self.checkRender(format, 'background_marker_buffer_pixels', QgsTextRenderer.TextPart.Background, - rect=QRectF(100, 100, 100, 100))) + self.assertTrue( + self.checkRender( + format, + "background_marker_buffer_pixels", + QgsTextRenderer.TextPart.Background, + rect=QRectF(100, 100, 100, 100), + ) + ) def testDrawBackgroundMarkerBufferMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - format.background().setMarkerSymbol(QgsMarkerSymbol.createSimple( - {'color': '#ffffff', 'size': '3', 'outline_color': 'red', 'outline_width': '3'})) - format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeMarkerSymbol) + format.background().setMarkerSymbol( + QgsMarkerSymbol.createSimple( + { + "color": "#ffffff", + "size": "3", + "outline_color": "red", + "outline_width": "3", + } + ) + ) + format.background().setType( + QgsTextBackgroundSettings.ShapeType.ShapeMarkerSymbol + ) format.background().setSize(QSizeF(4, 4)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeBuffer) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'background_marker_buffer_mapunits', QgsTextRenderer.TextPart.Background, - rect=QRectF(100, 100, 100, 100))) + self.assertTrue( + self.checkRender( + format, + "background_marker_buffer_mapunits", + QgsTextRenderer.TextPart.Background, + rect=QRectF(100, 100, 100, 100), + ) + ) def testDrawBackgroundMarkerBufferMM(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) - format.background().setMarkerSymbol(QgsMarkerSymbol.createSimple( - {'color': '#ffffff', 'size': '3', 'outline_color': 'red', 'outline_width': '3'})) - format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeMarkerSymbol) + format.background().setMarkerSymbol( + QgsMarkerSymbol.createSimple( + { + "color": "#ffffff", + "size": "3", + "outline_color": "red", + "outline_width": "3", + } + ) + ) + format.background().setType( + QgsTextBackgroundSettings.ShapeType.ShapeMarkerSymbol + ) format.background().setSize(QSizeF(10, 10)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeBuffer) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'background_marker_buffer_mm', QgsTextRenderer.TextPart.Background, - rect=QRectF(100, 100, 100, 100))) + self.assertTrue( + self.checkRender( + format, + "background_marker_buffer_mm", + QgsTextRenderer.TextPart.Background, + rect=QRectF(100, 100, 100, 100), + ) + ) def testDrawBackgroundRotationFixed(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(30, 20)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.background().setRotation(45) - format.background().setRotationType(QgsTextBackgroundSettings.RotationType.RotationFixed) - self.assertTrue(self.checkRender(format, 'background_rotation_fixed', QgsTextRenderer.TextPart.Background, angle=20)) + format.background().setRotationType( + QgsTextBackgroundSettings.RotationType.RotationFixed + ) + self.assertTrue( + self.checkRender( + format, + "background_rotation_fixed", + QgsTextRenderer.TextPart.Background, + angle=20, + ) + ) def testDrawRotationOffset(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(30, 20)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.background().setRotation(45) - format.background().setRotationType(QgsTextBackgroundSettings.RotationType.RotationOffset) - self.assertTrue(self.checkRender(format, 'background_rotation_offset', QgsTextRenderer.TextPart.Background, angle=20)) + format.background().setRotationType( + QgsTextBackgroundSettings.RotationType.RotationOffset + ) + self.assertTrue( + self.checkRender( + format, + "background_rotation_offset", + QgsTextRenderer.TextPart.Background, + angle=20, + ) + ) def testDrawBackgroundOffsetMM(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(30, 20)) @@ -1239,11 +1820,15 @@ def testDrawBackgroundOffsetMM(self): format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.background().setOffset(QPointF(30, 20)) format.background().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'background_offset_mm', QgsTextRenderer.TextPart.Background)) + self.assertTrue( + self.checkRender( + format, "background_offset_mm", QgsTextRenderer.TextPart.Background + ) + ) def testDrawBackgroundOffsetMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(30, 20)) @@ -1251,11 +1836,17 @@ def testDrawBackgroundOffsetMapUnits(self): format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.background().setOffset(QPointF(10, 5)) format.background().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'background_offset_mapunits', QgsTextRenderer.TextPart.Background)) + self.assertTrue( + self.checkRender( + format, + "background_offset_mapunits", + QgsTextRenderer.TextPart.Background, + ) + ) def testDrawBackgroundRadiiMM(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(30, 20)) @@ -1263,11 +1854,15 @@ def testDrawBackgroundRadiiMM(self): format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.background().setRadii(QSizeF(6, 4)) format.background().setRadiiUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'background_radii_mm', QgsTextRenderer.TextPart.Background)) + self.assertTrue( + self.checkRender( + format, "background_radii_mm", QgsTextRenderer.TextPart.Background + ) + ) def testDrawBackgroundRadiiMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(30, 20)) @@ -1275,31 +1870,43 @@ def testDrawBackgroundRadiiMapUnits(self): format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.background().setRadii(QSizeF(3, 2)) format.background().setRadiiUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'background_radii_mapunits', QgsTextRenderer.TextPart.Background)) + self.assertTrue( + self.checkRender( + format, "background_radii_mapunits", QgsTextRenderer.TextPart.Background + ) + ) def testDrawBackgroundOpacity(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(30, 20)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setOpacity(0.6) - self.assertTrue(self.checkRender(format, 'background_opacity', QgsTextRenderer.TextPart.Background)) + self.assertTrue( + self.checkRender( + format, "background_opacity", QgsTextRenderer.TextPart.Background + ) + ) def testDrawBackgroundFillColor(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(30, 20)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setFillColor(QColor(50, 100, 50)) - self.assertTrue(self.checkRender(format, 'background_fillcolor', QgsTextRenderer.TextPart.Background)) + self.assertTrue( + self.checkRender( + format, "background_fillcolor", QgsTextRenderer.TextPart.Background + ) + ) def testDrawBackgroundFillSymbol(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(30, 20)) @@ -1313,446 +1920,657 @@ def testDrawBackgroundFillSymbol(self): fill.setStrokeWidth(6) format.background().setFillSymbol(fill_symbol) - self.assertTrue(self.checkRender(format, 'background_fillsymbol', QgsTextRenderer.TextPart.Background)) + self.assertTrue( + self.checkRender( + format, "background_fillsymbol", QgsTextRenderer.TextPart.Background + ) + ) def testDrawBackgroundStroke(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(30, 20)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setStrokeColor(QColor(50, 100, 50)) format.background().setStrokeWidth(3) - format.background().setStrokeWidthUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'background_outline', QgsTextRenderer.TextPart.Background)) + format.background().setStrokeWidthUnit( + QgsUnitTypes.RenderUnit.RenderMillimeters + ) + self.assertTrue( + self.checkRender( + format, "background_outline", QgsTextRenderer.TextPart.Background + ) + ) def testDrawBackgroundEffect(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(30, 20)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) - format.background().setPaintEffect(QgsBlurEffect.create({'blur_level': '10', 'enabled': '1'})) - self.assertTrue(self.checkRender(format, 'background_effect', QgsTextRenderer.TextPart.Background, text=['test'])) + format.background().setPaintEffect( + QgsBlurEffect.create({"blur_level": "10", "enabled": "1"}) + ) + self.assertTrue( + self.checkRender( + format, + "background_effect", + QgsTextRenderer.TextPart.Background, + text=["test"], + ) + ) def testDrawText(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRender(format, 'text_bold', QgsTextRenderer.TextPart.Text, text=['test'])) + self.assertTrue( + self.checkRender( + format, "text_bold", QgsTextRenderer.TextPart.Text, text=["test"] + ) + ) def testDrawTextPoint(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRenderPoint(format, 'text_point_bold', QgsTextRenderer.TextPart.Text, text=['test'])) + self.assertTrue( + self.checkRenderPoint( + format, "text_point_bold", QgsTextRenderer.TextPart.Text, text=["test"] + ) + ) def testDrawTextNamedStyle(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) # need to call getTestFont to make sure font style is installed and ready to go - temp_font = getTestFont('Bold Oblique') # NOQA + temp_font = getTestFont("Bold Oblique") # NOQA format.setFont(getTestFont()) - format.setNamedStyle('Bold Oblique') + format.setNamedStyle("Bold Oblique") format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRender(format, 'text_named_style', QgsTextRenderer.TextPart.Text, text=['test'])) + self.assertTrue( + self.checkRender( + format, "text_named_style", QgsTextRenderer.TextPart.Text, text=["test"] + ) + ) def testDrawTextColor(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) - self.assertTrue(self.checkRender(format, 'text_color', QgsTextRenderer.TextPart.Text, text=['test'])) + self.assertTrue( + self.checkRender( + format, "text_color", QgsTextRenderer.TextPart.Text, text=["test"] + ) + ) def testDrawTextOpacity(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setOpacity(0.7) - self.assertTrue(self.checkRender(format, 'text_opacity', QgsTextRenderer.TextPart.Text, text=['test'])) + self.assertTrue( + self.checkRender( + format, "text_opacity", QgsTextRenderer.TextPart.Text, text=["test"] + ) + ) def testDrawTextBlendMode(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(100, 100, 100)) format.setBlendMode(QPainter.CompositionMode.CompositionMode_Difference) - self.assertTrue(self.checkRender(format, 'text_blend_mode', QgsTextRenderer.TextPart.Text, text=['test'])) + self.assertTrue( + self.checkRender( + format, "text_blend_mode", QgsTextRenderer.TextPart.Text, text=["test"] + ) + ) def testDrawTextAngle(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRender(format, 'text_angled', QgsTextRenderer.TextPart.Text, angle=90 / 180 * 3.141, text=['test'])) + self.assertTrue( + self.checkRender( + format, + "text_angled", + QgsTextRenderer.TextPart.Text, + angle=90 / 180 * 3.141, + text=["test"], + ) + ) def testDrawTextMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(5) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'text_mapunits', QgsTextRenderer.TextPart.Text, text=['test'])) + self.assertTrue( + self.checkRender( + format, "text_mapunits", QgsTextRenderer.TextPart.Text, text=["test"] + ) + ) def testDrawTextPixels(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(50) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPixels) - self.assertTrue(self.checkRender(format, 'text_pixels', QgsTextRenderer.TextPart.Text, text=['test'])) + self.assertTrue( + self.checkRender( + format, "text_pixels", QgsTextRenderer.TextPart.Text, text=["test"] + ) + ) def testDrawMultiLineText(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRender(format, 'text_multiline', QgsTextRenderer.TextPart.Text, text=['test', 'multi', 'line'])) + self.assertTrue( + self.checkRender( + format, + "text_multiline", + QgsTextRenderer.TextPart.Text, + text=["test", "multi", "line"], + ) + ) def testDrawMultiLineTextPoint(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRenderPoint(format, 'text_point_multiline', QgsTextRenderer.TextPart.Text, - text=['test', 'multi', 'line'])) + self.assertTrue( + self.checkRenderPoint( + format, + "text_point_multiline", + QgsTextRenderer.TextPart.Text, + text=["test", "multi", "line"], + ) + ) def testDrawLineHeightText(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setLineHeight(1.5) - self.assertTrue(self.checkRender(format, 'text_line_height', QgsTextRenderer.TextPart.Text, text=['test', 'multi', 'line'])) + self.assertTrue( + self.checkRender( + format, + "text_line_height", + QgsTextRenderer.TextPart.Text, + text=["test", "multi", "line"], + ) + ) def testDrawLineHeightAbsolutePoints(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setLineHeight(20) format.setLineHeightUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRender(format, 'text_line_absolute_height', QgsTextRenderer.TextPart.Text, text=['test', 'multi', 'line'])) + self.assertTrue( + self.checkRender( + format, + "text_line_absolute_height", + QgsTextRenderer.TextPart.Text, + text=["test", "multi", "line"], + ) + ) def testDrawLineHeightAbsoluteMillimeters(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setLineHeight(20) format.setLineHeightUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'text_line_absolute_mm_height', QgsTextRenderer.TextPart.Text, text=['test', 'multi', 'line'])) + self.assertTrue( + self.checkRender( + format, + "text_line_absolute_mm_height", + QgsTextRenderer.TextPart.Text, + text=["test", "multi", "line"], + ) + ) def testDrawBufferSizeMM(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.buffer().setEnabled(True) format.buffer().setSize(2) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'text_buffer_mm', QgsTextRenderer.TextPart.Buffer, text=['test'])) + self.assertTrue( + self.checkRender( + format, "text_buffer_mm", QgsTextRenderer.TextPart.Buffer, text=["test"] + ) + ) def testDrawBufferDisabled(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.buffer().setEnabled(False) - self.assertTrue(self.checkRender(format, 'text_disabled_buffer', QgsTextRenderer.TextPart.Buffer, text=['test'])) + self.assertTrue( + self.checkRender( + format, + "text_disabled_buffer", + QgsTextRenderer.TextPart.Buffer, + text=["test"], + ) + ) def testDrawBufferSizeMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.buffer().setEnabled(True) format.buffer().setSize(2) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'text_buffer_mapunits', QgsTextRenderer.TextPart.Buffer, text=['test'])) + self.assertTrue( + self.checkRender( + format, + "text_buffer_mapunits", + QgsTextRenderer.TextPart.Buffer, + text=["test"], + ) + ) def testDrawBufferSizePixels(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.buffer().setEnabled(True) format.buffer().setSize(10) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderPixels) - self.assertTrue(self.checkRender(format, 'text_buffer_pixels', QgsTextRenderer.TextPart.Buffer, text=['test'])) + self.assertTrue( + self.checkRender( + format, + "text_buffer_pixels", + QgsTextRenderer.TextPart.Buffer, + text=["test"], + ) + ) def testDrawBufferSizePercentage(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.buffer().setEnabled(True) format.buffer().setSize(10) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderPercentage) - self.assertTrue(self.checkRender(format, 'text_buffer_percentage', QgsTextRenderer.TextPart.Buffer, text=['test'])) + self.assertTrue( + self.checkRender( + format, + "text_buffer_percentage", + QgsTextRenderer.TextPart.Buffer, + text=["test"], + ) + ) def testDrawBufferColor(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.buffer().setEnabled(True) format.buffer().setSize(2) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.buffer().setColor(QColor(0, 255, 0)) - self.assertTrue(self.checkRender(format, 'text_buffer_color', QgsTextRenderer.TextPart.Buffer, text=['test'])) + self.assertTrue( + self.checkRender( + format, + "text_buffer_color", + QgsTextRenderer.TextPart.Buffer, + text=["test"], + ) + ) def testDrawBufferOpacity(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.buffer().setEnabled(True) format.buffer().setSize(2) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.buffer().setOpacity(0.5) - self.assertTrue(self.checkRender(format, 'text_buffer_opacity', QgsTextRenderer.TextPart.Buffer, text=['test'])) + self.assertTrue( + self.checkRender( + format, + "text_buffer_opacity", + QgsTextRenderer.TextPart.Buffer, + text=["test"], + ) + ) def testDrawBufferFillInterior(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.buffer().setEnabled(True) format.buffer().setSize(2) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.buffer().setFillBufferInterior(True) - self.assertTrue(self.checkRender(format, 'text_buffer_interior', QgsTextRenderer.TextPart.Buffer, text=['test'])) + self.assertTrue( + self.checkRender( + format, + "text_buffer_interior", + QgsTextRenderer.TextPart.Buffer, + text=["test"], + ) + ) def testDrawBufferEffect(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.buffer().setEnabled(True) format.buffer().setSize(2) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - format.buffer().setPaintEffect(QgsBlurEffect.create({'blur_level': '10', 'enabled': '1'})) - self.assertTrue(self.checkRender(format, 'text_buffer_effect', QgsTextRenderer.TextPart.Buffer, text=['test'])) + format.buffer().setPaintEffect( + QgsBlurEffect.create({"blur_level": "10", "enabled": "1"}) + ) + self.assertTrue( + self.checkRender( + format, + "text_buffer_effect", + QgsTextRenderer.TextPart.Buffer, + text=["test"], + ) + ) def testDrawShadow(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 255, 255)) format.shadow().setEnabled(True) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowText) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowText + ) format.shadow().setOpacity(1.0) format.shadow().setBlurRadius(0) format.shadow().setOffsetDistance(5) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'shadow_enabled', None, text=['test'])) + self.assertTrue(self.checkRender(format, "shadow_enabled", None, text=["test"])) def testDrawShadowOffsetAngle(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 255, 255)) format.shadow().setEnabled(True) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowText) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowText + ) format.shadow().setOpacity(1.0) format.shadow().setBlurRadius(0) format.shadow().setOffsetDistance(5) format.shadow().setOffsetAngle(0) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'shadow_offset_angle', None, text=['test'])) + self.assertTrue( + self.checkRender(format, "shadow_offset_angle", None, text=["test"]) + ) def testDrawShadowOffsetMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 255, 255)) format.shadow().setEnabled(True) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowText) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowText + ) format.shadow().setOpacity(1.0) format.shadow().setBlurRadius(0) format.shadow().setOffsetDistance(10) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'shadow_offset_mapunits', None, text=['test'])) + self.assertTrue( + self.checkRender(format, "shadow_offset_mapunits", None, text=["test"]) + ) def testDrawShadowOffsetPixels(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 255, 255)) format.shadow().setEnabled(True) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowText) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowText + ) format.shadow().setOpacity(1.0) format.shadow().setBlurRadius(0) format.shadow().setOffsetDistance(10) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderPixels) - self.assertTrue(self.checkRender(format, 'shadow_offset_pixels', None, text=['test'])) + self.assertTrue( + self.checkRender(format, "shadow_offset_pixels", None, text=["test"]) + ) def testDrawShadowOffsetPercentage(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 255, 255)) format.shadow().setEnabled(True) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowText) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowText + ) format.shadow().setOpacity(1.0) format.shadow().setBlurRadius(0) format.shadow().setOffsetDistance(10) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderPercentage) - self.assertTrue(self.checkRender(format, 'shadow_offset_percentage', None, text=['test'])) + self.assertTrue( + self.checkRender(format, "shadow_offset_percentage", None, text=["test"]) + ) def testDrawShadowBlurRadiusMM(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 255, 255)) format.shadow().setEnabled(True) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowText) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowText + ) format.shadow().setOpacity(1.0) format.shadow().setOffsetDistance(5) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.shadow().setBlurRadius(1) format.shadow().setBlurRadiusUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'shadow_radius_mm', None, text=['test'])) + self.assertTrue( + self.checkRender(format, "shadow_radius_mm", None, text=["test"]) + ) def testDrawShadowBlurRadiusMapUnits(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 255, 255)) format.shadow().setEnabled(True) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowText) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowText + ) format.shadow().setOpacity(1.0) format.shadow().setOffsetDistance(5) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.shadow().setBlurRadius(3) format.shadow().setBlurRadiusUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'shadow_radius_mapunits', None, text=['test'])) + self.assertTrue( + self.checkRender(format, "shadow_radius_mapunits", None, text=["test"]) + ) def testDrawShadowBlurRadiusPixels(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 255, 255)) format.shadow().setEnabled(True) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowText) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowText + ) format.shadow().setOpacity(1.0) format.shadow().setOffsetDistance(5) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.shadow().setBlurRadius(3) format.shadow().setBlurRadiusUnit(QgsUnitTypes.RenderUnit.RenderPixels) - self.assertTrue(self.checkRender(format, 'shadow_radius_pixels', None, text=['test'])) + self.assertTrue( + self.checkRender(format, "shadow_radius_pixels", None, text=["test"]) + ) def testDrawShadowBlurRadiusPercentage(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 255, 255)) format.shadow().setEnabled(True) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowText) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowText + ) format.shadow().setOpacity(1.0) format.shadow().setOffsetDistance(5) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.shadow().setBlurRadius(5) format.shadow().setBlurRadiusUnit(QgsUnitTypes.RenderUnit.RenderPercentage) - self.assertTrue(self.checkRender(format, 'shadow_radius_percentage', None, text=['test'])) + self.assertTrue( + self.checkRender(format, "shadow_radius_percentage", None, text=["test"]) + ) def testDrawShadowOpacity(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 255, 255)) format.shadow().setEnabled(True) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowText) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowText + ) format.shadow().setOpacity(0.5) format.shadow().setBlurRadius(0) format.shadow().setOffsetDistance(5) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'shadow_opacity', None, text=['test'])) + self.assertTrue(self.checkRender(format, "shadow_opacity", None, text=["test"])) def testDrawShadowColor(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 255, 255)) format.shadow().setEnabled(True) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowText) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowText + ) format.shadow().setColor(QColor(255, 255, 0)) format.shadow().setBlurRadius(0) format.shadow().setOffsetDistance(5) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'shadow_color', None, text=['test'])) + self.assertTrue(self.checkRender(format, "shadow_color", None, text=["test"])) def testDrawShadowWithJustifyAlign(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.shadow().setEnabled(True) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowText) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowText + ) format.shadow().setOpacity(0.5) format.shadow().setBlurRadius(0) format.shadow().setOffsetDistance(5) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'text_justify_aligned_with_shadow', - text=['a t est', 'off', 'justification', 'align'], - alignment=QgsTextRenderer.HAlignment.AlignJustify, rect=QRectF(100, 100, 200, 100))) + self.assertTrue( + self.checkRender( + format, + "text_justify_aligned_with_shadow", + text=["a t est", "off", "justification", "align"], + alignment=QgsTextRenderer.HAlignment.AlignJustify, + rect=QRectF(100, 100, 200, 100), + ) + ) def testDrawShadowScale(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 255, 255)) format.shadow().setEnabled(True) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowText) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowText + ) format.shadow().setScale(50) format.shadow().setBlurRadius(0) format.shadow().setOffsetDistance(5) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'shadow_scale_50', None, text=['test'])) + self.assertTrue( + self.checkRender(format, "shadow_scale_50", None, text=["test"]) + ) def testDrawShadowScaleUp(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 255, 255)) format.shadow().setEnabled(True) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowText) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowText + ) format.shadow().setScale(150) format.shadow().setBlurRadius(0) format.shadow().setOffsetDistance(5) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'shadow_scale_150', None, text=['test'])) + self.assertTrue( + self.checkRender(format, "shadow_scale_150", None, text=["test"]) + ) def testDrawShadowBackgroundPlacement(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 255, 255)) format.shadow().setEnabled(True) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowShape) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowShape + ) format.shadow().setBlurRadius(0) format.shadow().setOffsetDistance(5) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) @@ -1761,37 +2579,50 @@ def testDrawShadowBackgroundPlacement(self): format.background().setSize(QSizeF(20, 10)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'shadow_placement_background', None, text=['test'])) + self.assertTrue( + self.checkRender(format, "shadow_placement_background", None, text=["test"]) + ) def testDrawShadowBufferPlacement(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 255, 255)) format.shadow().setEnabled(True) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowBuffer) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowBuffer + ) format.shadow().setBlurRadius(0) format.shadow().setOffsetDistance(5) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.buffer().setEnabled(True) format.buffer().setSize(4) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'shadow_placement_buffer', None, text=['test'])) + self.assertTrue( + self.checkRender(format, "shadow_placement_buffer", None, text=["test"]) + ) def testDrawTextWithBuffer(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.buffer().setEnabled(True) format.buffer().setSize(4) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'text_with_buffer', text=['test'], rect=QRectF(100, 100, 200, 100))) + self.assertTrue( + self.checkRender( + format, + "text_with_buffer", + text=["test"], + rect=QRectF(100, 100, 200, 100), + ) + ) def testDrawTextWithBufferBlendMode(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.background().setEnabled(True) @@ -1805,12 +2636,18 @@ def testDrawTextWithBufferBlendMode(self): format.buffer().setColor(QColor(100, 255, 100)) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.buffer().setBlendMode(QPainter.CompositionMode.CompositionMode_Multiply) - self.assertTrue(self.checkRender(format, 'text_with_buffer_blend_mode', text=['test'], - rect=QRectF(100, 100, 200, 100))) + self.assertTrue( + self.checkRender( + format, + "text_with_buffer_blend_mode", + text=["test"], + rect=QRectF(100, 100, 200, 100), + ) + ) def testDrawTextWithBackground(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.background().setEnabled(True) @@ -1818,11 +2655,18 @@ def testDrawTextWithBackground(self): format.background().setSize(QSizeF(20, 10)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'text_with_background', text=['test'], rect=QRectF(100, 100, 200, 100))) + self.assertTrue( + self.checkRender( + format, + "text_with_background", + text=["test"], + rect=QRectF(100, 100, 200, 100), + ) + ) def testDrawTextWithBufferAndBackground(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.background().setEnabled(True) @@ -1834,12 +2678,18 @@ def testDrawTextWithBufferAndBackground(self): format.buffer().setSize(4) format.buffer().setColor(QColor(100, 255, 100)) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'text_with_buffer_and_background', text=['test'], - rect=QRectF(100, 100, 200, 100))) + self.assertTrue( + self.checkRender( + format, + "text_with_buffer_and_background", + text=["test"], + rect=QRectF(100, 100, 200, 100), + ) + ) def testDrawTextWithShadowAndBuffer(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.shadow().setEnabled(True) @@ -1852,11 +2702,18 @@ def testDrawTextWithShadowAndBuffer(self): format.buffer().setSize(4) format.buffer().setColor(QColor(100, 255, 100)) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'text_with_shadow_and_buffer', text=['test'], rect=QRectF(100, 100, 200, 100))) + self.assertTrue( + self.checkRender( + format, + "text_with_shadow_and_buffer", + text=["test"], + rect=QRectF(100, 100, 200, 100), + ) + ) def testDrawTextWithShadowBelowTextAndBuffer(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.shadow().setEnabled(True) @@ -1865,17 +2722,25 @@ def testDrawTextWithShadowBelowTextAndBuffer(self): format.shadow().setOffsetDistance(5) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.shadow().setColor(QColor(255, 100, 100)) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowText) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowText + ) format.buffer().setEnabled(True) format.buffer().setSize(4) format.buffer().setColor(QColor(100, 255, 100)) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'text_with_shadow_below_text_and_buffer', text=['test'], - rect=QRectF(100, 100, 200, 100))) + self.assertTrue( + self.checkRender( + format, + "text_with_shadow_below_text_and_buffer", + text=["test"], + rect=QRectF(100, 100, 200, 100), + ) + ) def testDrawTextWithBackgroundAndShadow(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.shadow().setEnabled(True) @@ -1889,12 +2754,18 @@ def testDrawTextWithBackgroundAndShadow(self): format.background().setSize(QSizeF(20, 10)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'text_with_shadow_and_background', text=['test'], - rect=QRectF(100, 100, 200, 100))) + self.assertTrue( + self.checkRender( + format, + "text_with_shadow_and_background", + text=["test"], + rect=QRectF(100, 100, 200, 100), + ) + ) def testDrawTextWithShadowBelowTextAndBackground(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.shadow().setEnabled(True) @@ -1903,18 +2774,26 @@ def testDrawTextWithShadowBelowTextAndBackground(self): format.shadow().setOffsetDistance(5) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.shadow().setColor(QColor(255, 100, 100)) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowText) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowText + ) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(20, 10)) format.background().setSizeType(QgsTextBackgroundSettings.SizeType.SizeFixed) format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMapUnits) - self.assertTrue(self.checkRender(format, 'text_with_shadow_below_text_and_background', text=['test'], - rect=QRectF(100, 100, 200, 100))) + self.assertTrue( + self.checkRender( + format, + "text_with_shadow_below_text_and_background", + text=["test"], + rect=QRectF(100, 100, 200, 100), + ) + ) def testDrawTextWithBackgroundBufferAndShadow(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.shadow().setEnabled(True) @@ -1932,12 +2811,18 @@ def testDrawTextWithBackgroundBufferAndShadow(self): format.buffer().setSize(4) format.buffer().setColor(QColor(100, 255, 100)) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'text_with_shadow_buffer_and_background', text=['test'], - rect=QRectF(100, 100, 200, 100))) + self.assertTrue( + self.checkRender( + format, + "text_with_shadow_buffer_and_background", + text=["test"], + rect=QRectF(100, 100, 200, 100), + ) + ) def testDrawTextWithBackgroundBufferAndShadowBelowText(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.shadow().setEnabled(True) @@ -1946,7 +2831,9 @@ def testDrawTextWithBackgroundBufferAndShadowBelowText(self): format.shadow().setOffsetDistance(5) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.shadow().setColor(QColor(255, 100, 100)) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowText) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowText + ) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(20, 10)) @@ -1956,12 +2843,18 @@ def testDrawTextWithBackgroundBufferAndShadowBelowText(self): format.buffer().setSize(4) format.buffer().setColor(QColor(100, 255, 100)) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'text_with_shadow_below_text_buffer_and_background', text=['test'], - rect=QRectF(100, 100, 200, 100))) + self.assertTrue( + self.checkRender( + format, + "text_with_shadow_below_text_buffer_and_background", + text=["test"], + rect=QRectF(100, 100, 200, 100), + ) + ) def testDrawTextWithBackgroundBufferAndShadowBelowBuffer(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.shadow().setEnabled(True) @@ -1970,7 +2863,9 @@ def testDrawTextWithBackgroundBufferAndShadowBelowBuffer(self): format.shadow().setOffsetDistance(5) format.shadow().setOffsetUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.shadow().setColor(QColor(255, 100, 100)) - format.shadow().setShadowPlacement(QgsTextShadowSettings.ShadowPlacement.ShadowBuffer) + format.shadow().setShadowPlacement( + QgsTextShadowSettings.ShadowPlacement.ShadowBuffer + ) format.background().setEnabled(True) format.background().setType(QgsTextBackgroundSettings.ShapeType.ShapeRectangle) format.background().setSize(QSizeF(20, 10)) @@ -1980,60 +2875,99 @@ def testDrawTextWithBackgroundBufferAndShadowBelowBuffer(self): format.buffer().setSize(4) format.buffer().setColor(QColor(100, 255, 100)) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'text_with_shadow_below_buffer_and_background', text=['test'], - rect=QRectF(100, 100, 200, 100))) + self.assertTrue( + self.checkRender( + format, + "text_with_shadow_below_buffer_and_background", + text=["test"], + rect=QRectF(100, 100, 200, 100), + ) + ) def testDrawTextRectMultilineRightAlign(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRender(format, 'text_rect_multiline_right_aligned', text=['test', 'right', 'aligned'], - alignment=QgsTextRenderer.HAlignment.AlignRight, rect=QRectF(100, 100, 200, 100))) + self.assertTrue( + self.checkRender( + format, + "text_rect_multiline_right_aligned", + text=["test", "right", "aligned"], + alignment=QgsTextRenderer.HAlignment.AlignRight, + rect=QRectF(100, 100, 200, 100), + ) + ) def testDrawTextRectRightAlign(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRender(format, 'text_rect_right_aligned', text=['test'], - alignment=QgsTextRenderer.HAlignment.AlignRight, rect=QRectF(100, 100, 200, 100))) + self.assertTrue( + self.checkRender( + format, + "text_rect_right_aligned", + text=["test"], + alignment=QgsTextRenderer.HAlignment.AlignRight, + rect=QRectF(100, 100, 200, 100), + ) + ) def testDrawTextRectMultilineJustifyAlign(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.buffer().setEnabled(True) format.buffer().setSize(4) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'text_rect_multiline_justify_aligned', - text=['a t est', 'off', 'justification', 'align'], - alignment=QgsTextRenderer.HAlignment.AlignJustify, rect=QRectF(100, 100, 200, 100))) + self.assertTrue( + self.checkRender( + format, + "text_rect_multiline_justify_aligned", + text=["a t est", "off", "justification", "align"], + alignment=QgsTextRenderer.HAlignment.AlignJustify, + rect=QRectF(100, 100, 200, 100), + ) + ) def testDrawTextRectJustifyAlign(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRender(format, 'text_rect_justify_aligned', text=['test'], - alignment=QgsTextRenderer.HAlignment.AlignJustify, rect=QRectF(100, 100, 200, 100))) + self.assertTrue( + self.checkRender( + format, + "text_rect_justify_aligned", + text=["test"], + alignment=QgsTextRenderer.HAlignment.AlignJustify, + rect=QRectF(100, 100, 200, 100), + ) + ) def testDrawTextRectMultiparagraphJustifyAlign(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.buffer().setEnabled(True) format.buffer().setSize(4) format.buffer().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) - self.assertTrue(self.checkRender(format, 'text_rect_multiparagraph_justify_aligned', - text=['a t est', 'of justify', '', 'with two', 'pgraphs'], - alignment=QgsTextRenderer.HAlignment.AlignJustify, rect=QRectF(50, 100, 250, 100))) + self.assertTrue( + self.checkRender( + format, + "text_rect_multiparagraph_justify_aligned", + text=["a t est", "of justify", "", "with two", "pgraphs"], + alignment=QgsTextRenderer.HAlignment.AlignJustify, + rect=QRectF(50, 100, 250, 100), + ) + ) def testDrawTextRectWordWrapSingleLine(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) painter = QPainter() @@ -2042,32 +2976,81 @@ def testDrawTextRectWordWrapSingleLine(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) - self.assertTrue(QgsTextRenderer.textRequiresWrapping(context, 'a test of word wrap', 100, format)) - self.assertTrue(QgsTextRenderer.textRequiresWrapping(context, 'a test of word wrap', 200, format)) - self.assertTrue(QgsTextRenderer.textRequiresWrapping(context, 'a test of word wrap', 400, format)) - self.assertFalse(QgsTextRenderer.textRequiresWrapping(context, 'a test of word wrap', 500, format)) + self.assertTrue( + QgsTextRenderer.textRequiresWrapping( + context, "a test of word wrap", 100, format + ) + ) + self.assertTrue( + QgsTextRenderer.textRequiresWrapping( + context, "a test of word wrap", 200, format + ) + ) + self.assertTrue( + QgsTextRenderer.textRequiresWrapping( + context, "a test of word wrap", 400, format + ) + ) + self.assertFalse( + QgsTextRenderer.textRequiresWrapping( + context, "a test of word wrap", 500, format + ) + ) - self.assertEqual(QgsTextRenderer.wrappedText(context, 'a test of word wrap', 50, format), ['a', 'test', 'of', 'word', 'wrap']) - self.assertEqual(QgsTextRenderer.wrappedText(context, 'a test of word wrap', 200, format), ['a test of', 'word', 'wrap']) - self.assertEqual(QgsTextRenderer.wrappedText(context, 'a test of word wrap', 400, format), ['a test of word', 'wrap']) - self.assertEqual(QgsTextRenderer.wrappedText(context, 'a test of word wrap', 500, format), - ['a test of word wrap']) + self.assertEqual( + QgsTextRenderer.wrappedText(context, "a test of word wrap", 50, format), + ["a", "test", "of", "word", "wrap"], + ) + self.assertEqual( + QgsTextRenderer.wrappedText(context, "a test of word wrap", 200, format), + ["a test of", "word", "wrap"], + ) + self.assertEqual( + QgsTextRenderer.wrappedText(context, "a test of word wrap", 400, format), + ["a test of word", "wrap"], + ) + self.assertEqual( + QgsTextRenderer.wrappedText(context, "a test of word wrap", 500, format), + ["a test of word wrap"], + ) # text height should account for wrapping - self.assertGreater(QgsTextRenderer.textHeight( - context, format, ['a test of word wrap'], - mode=QgsTextRenderer.DrawMode.Rect, flags=Qgis.TextRendererFlag.WrapLines, maxLineWidth=200), - QgsTextRenderer.textHeight(context, format, ['a test of word wrap'], mode=QgsTextRenderer.DrawMode.Rect) * 2.75) + self.assertGreater( + QgsTextRenderer.textHeight( + context, + format, + ["a test of word wrap"], + mode=QgsTextRenderer.DrawMode.Rect, + flags=Qgis.TextRendererFlag.WrapLines, + maxLineWidth=200, + ), + QgsTextRenderer.textHeight( + context, + format, + ["a test of word wrap"], + mode=QgsTextRenderer.DrawMode.Rect, + ) + * 2.75, + ) - self.assertTrue(self.checkRender(format, 'text_rect_word_wrap_single_line', text=['a test of word wrap'], - alignment=QgsTextRenderer.HAlignment.AlignLeft, rect=QRectF(100, 100, 200, 100), - flags=Qgis.TextRendererFlag.WrapLines)) + self.assertTrue( + self.checkRender( + format, + "text_rect_word_wrap_single_line", + text=["a test of word wrap"], + alignment=QgsTextRenderer.HAlignment.AlignLeft, + rect=QRectF(100, 100, 200, 100), + flags=Qgis.TextRendererFlag.WrapLines, + ) + ) def testWordWrapSingleLineStabilityAtSmallScaling(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) @@ -2076,47 +3059,114 @@ def testWordWrapSingleLineStabilityAtSmallScaling(self): painter = QPainter() context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) for i in range(1, 3000, 5): adjustment = i / 100 context.setScaleFactor(96 / 25.4 * adjustment) - self.assertEqual(QgsTextRenderer.wrappedText(context, 'a test of word wrap', 50 * adjustment, format), ['a', 'test', 'of', 'word', 'wrap']) - self.assertEqual(QgsTextRenderer.wrappedText(context, 'a test of word wrap', 200 * adjustment, format), ['a test of', 'word', 'wrap']) - self.assertEqual(QgsTextRenderer.wrappedText(context, 'a test of word wrap', 400 * adjustment, format), ['a test of word', 'wrap']) - self.assertEqual(QgsTextRenderer.wrappedText(context, 'a test of word wrap', 500 * adjustment, format), - ['a test of word wrap']) + self.assertEqual( + QgsTextRenderer.wrappedText( + context, "a test of word wrap", 50 * adjustment, format + ), + ["a", "test", "of", "word", "wrap"], + ) + self.assertEqual( + QgsTextRenderer.wrappedText( + context, "a test of word wrap", 200 * adjustment, format + ), + ["a test of", "word", "wrap"], + ) + self.assertEqual( + QgsTextRenderer.wrappedText( + context, "a test of word wrap", 400 * adjustment, format + ), + ["a test of word", "wrap"], + ) + self.assertEqual( + QgsTextRenderer.wrappedText( + context, "a test of word wrap", 500 * adjustment, format + ), + ["a test of word wrap"], + ) format.setSize(60) for i in range(1, 3000, 5): adjustment = i / 100 context.setScaleFactor(96 / 25.4 * adjustment) - self.assertEqual(QgsTextRenderer.wrappedText(context, 'a test of word wrap', 50 * adjustment, format), ['a', 'test', 'of', 'word', 'wrap']) - self.assertEqual(QgsTextRenderer.wrappedText(context, 'a test of word wrap', 200 * adjustment, format), ['a', 'test', 'of', 'word', 'wrap']) - self.assertEqual(QgsTextRenderer.wrappedText(context, 'a test of word wrap', 400 * adjustment, format), ['a test of', 'word', 'wrap']) - self.assertEqual(QgsTextRenderer.wrappedText(context, 'a test of word wrap', 500 * adjustment, format), - ['a test of', 'word wrap']) - self.assertEqual(QgsTextRenderer.wrappedText(context, 'a test of word wrap', 650 * adjustment, format), - ['a test of word', 'wrap']) - self.assertEqual(QgsTextRenderer.wrappedText(context, 'a test of word wrap', 900 * adjustment, format), - ['a test of word wrap']) + self.assertEqual( + QgsTextRenderer.wrappedText( + context, "a test of word wrap", 50 * adjustment, format + ), + ["a", "test", "of", "word", "wrap"], + ) + self.assertEqual( + QgsTextRenderer.wrappedText( + context, "a test of word wrap", 200 * adjustment, format + ), + ["a", "test", "of", "word", "wrap"], + ) + self.assertEqual( + QgsTextRenderer.wrappedText( + context, "a test of word wrap", 400 * adjustment, format + ), + ["a test of", "word", "wrap"], + ) + self.assertEqual( + QgsTextRenderer.wrappedText( + context, "a test of word wrap", 500 * adjustment, format + ), + ["a test of", "word wrap"], + ) + self.assertEqual( + QgsTextRenderer.wrappedText( + context, "a test of word wrap", 650 * adjustment, format + ), + ["a test of word", "wrap"], + ) + self.assertEqual( + QgsTextRenderer.wrappedText( + context, "a test of word wrap", 900 * adjustment, format + ), + ["a test of word wrap"], + ) format.setSize(10) for i in range(1, 3000, 5): adjustment = i / 100 context.setScaleFactor(96 / 25.4 * adjustment) - self.assertEqual(QgsTextRenderer.wrappedText(context, 'a test of word wrap', 10 * adjustment, format), ['a', 'test', 'of', 'word', 'wrap']) - self.assertEqual(QgsTextRenderer.wrappedText(context, 'a test of word wrap', 70 * adjustment, format), ['a test of', 'word', 'wrap']) - self.assertEqual(QgsTextRenderer.wrappedText(context, 'a test of word wrap', 120 * adjustment, format), ['a test of word', 'wrap']) - self.assertEqual(QgsTextRenderer.wrappedText(context, 'a test of word wrap', 150 * adjustment, format), - ['a test of word wrap']) + self.assertEqual( + QgsTextRenderer.wrappedText( + context, "a test of word wrap", 10 * adjustment, format + ), + ["a", "test", "of", "word", "wrap"], + ) + self.assertEqual( + QgsTextRenderer.wrappedText( + context, "a test of word wrap", 70 * adjustment, format + ), + ["a test of", "word", "wrap"], + ) + self.assertEqual( + QgsTextRenderer.wrappedText( + context, "a test of word wrap", 120 * adjustment, format + ), + ["a test of word", "wrap"], + ) + self.assertEqual( + QgsTextRenderer.wrappedText( + context, "a test of word wrap", 150 * adjustment, format + ), + ["a test of word wrap"], + ) def testDrawTextRectWordWrapMultiLine(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) painter = QPainter() @@ -2125,30 +3175,59 @@ def testDrawTextRectWordWrapMultiLine(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) # text height should account for wrapping - self.assertGreater(QgsTextRenderer.textHeight( - context, format, ['a test of word wrap', 'with bit more'], - mode=QgsTextRenderer.DrawMode.Rect, flags=Qgis.TextRendererFlag.WrapLines, maxLineWidth=200), - QgsTextRenderer.textHeight(context, format, ['a test of word wrap with with bit more'], mode=QgsTextRenderer.DrawMode.Rect) * 4.75) + self.assertGreater( + QgsTextRenderer.textHeight( + context, + format, + ["a test of word wrap", "with bit more"], + mode=QgsTextRenderer.DrawMode.Rect, + flags=Qgis.TextRendererFlag.WrapLines, + maxLineWidth=200, + ), + QgsTextRenderer.textHeight( + context, + format, + ["a test of word wrap with with bit more"], + mode=QgsTextRenderer.DrawMode.Rect, + ) + * 4.75, + ) - self.assertTrue(self.checkRender(format, 'text_rect_word_wrap_multi_line', text=['a test of word wrap', 'with bit more'], - alignment=QgsTextRenderer.HAlignment.AlignLeft, rect=QRectF(100, 100, 200, 100), - flags=Qgis.TextRendererFlag.WrapLines)) + self.assertTrue( + self.checkRender( + format, + "text_rect_word_wrap_multi_line", + text=["a test of word wrap", "with bit more"], + alignment=QgsTextRenderer.HAlignment.AlignLeft, + rect=QRectF(100, 100, 200, 100), + flags=Qgis.TextRendererFlag.WrapLines, + ) + ) def testDrawTextRectWordWrapWithJustify(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRender(format, 'text_rect_word_wrap_justify', text=['a test of word wrap'], - alignment=QgsTextRenderer.HAlignment.AlignJustify, rect=QRectF(100, 100, 200, 100), - flags=Qgis.TextRendererFlag.WrapLines)) + self.assertTrue( + self.checkRender( + format, + "text_rect_word_wrap_justify", + text=["a test of word wrap"], + alignment=QgsTextRenderer.HAlignment.AlignJustify, + rect=QRectF(100, 100, 200, 100), + flags=Qgis.TextRendererFlag.WrapLines, + ) + ) def testDrawTextRectWordWrapHtml1(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setAllowHtmlFormatting(True) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) @@ -2158,17 +3237,26 @@ def testDrawTextRectWordWrapHtml1(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) self.assertTrue( - self.checkRender(format, 'html_rect_wrapped1', text=['some text more text and more'], - alignment=QgsTextRenderer.HAlignment.AlignLeft, rect=QRectF(50, 100, 300, 100), - flags=Qgis.TextRendererFlag.WrapLines) + self.checkRender( + format, + "html_rect_wrapped1", + text=[ + 'some text more text and more' + ], + alignment=QgsTextRenderer.HAlignment.AlignLeft, + rect=QRectF(50, 100, 300, 100), + flags=Qgis.TextRendererFlag.WrapLines, + ) ) def testDrawTextRectWordWrapHtml2(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setAllowHtmlFormatting(True) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) @@ -2178,17 +3266,26 @@ def testDrawTextRectWordWrapHtml2(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) self.assertTrue( - self.checkRender(format, 'html_rect_wrapped2', text=['thiswordistoolong but this is not'], - alignment=QgsTextRenderer.HAlignment.AlignLeft, rect=QRectF(50, 100, 300, 100), - flags=Qgis.TextRendererFlag.WrapLines) + self.checkRender( + format, + "html_rect_wrapped2", + text=[ + 'thiswordistoolong but this is not' + ], + alignment=QgsTextRenderer.HAlignment.AlignLeft, + rect=QRectF(50, 100, 300, 100), + flags=Qgis.TextRendererFlag.WrapLines, + ) ) def testDrawTextRectWordWrapHtmlImage1(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setAllowHtmlFormatting(True) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) @@ -2198,17 +3295,26 @@ def testDrawTextRectWordWrapHtmlImage1(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) self.assertTrue( - self.checkRender(format, 'html_img_wrapping', text=[f'this img should wrap'], - alignment=QgsTextRenderer.HAlignment.AlignLeft, rect=QRectF(50, 130, 300, 100), - flags=Qgis.TextRendererFlag.WrapLines) + self.checkRender( + format, + "html_img_wrapping", + text=[ + f'this img should wrap' + ], + alignment=QgsTextRenderer.HAlignment.AlignLeft, + rect=QRectF(50, 130, 300, 100), + flags=Qgis.TextRendererFlag.WrapLines, + ) ) def testDrawTextRectWordWrapTab(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setAllowHtmlFormatting(True) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) @@ -2219,17 +3325,24 @@ def testDrawTextRectWordWrapTab(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) self.assertTrue( - self.checkRender(format, 'tab_wrapping', text=['this\ttab\tshould\twrap'], - alignment=QgsTextRenderer.HAlignment.AlignLeft, rect=QRectF(50, 130, 350, 100), - flags=Qgis.TextRendererFlag.WrapLines) + self.checkRender( + format, + "tab_wrapping", + text=["this\ttab\tshould\twrap"], + alignment=QgsTextRenderer.HAlignment.AlignLeft, + rect=QRectF(50, 130, 350, 100), + flags=Qgis.TextRendererFlag.WrapLines, + ) ) def testDrawTextRectWordWrapTabPositions(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setAllowHtmlFormatting(True) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) @@ -2241,282 +3354,448 @@ def testDrawTextRectWordWrapTabPositions(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) self.assertTrue( - self.checkRender(format, 'tab_wrapping', text=['this\ttab\tshould\twrap'], - alignment=QgsTextRenderer.HAlignment.AlignLeft, rect=QRectF(50, 130, 350, 100), - flags=Qgis.TextRendererFlag.WrapLines) + self.checkRender( + format, + "tab_wrapping", + text=["this\ttab\tshould\twrap"], + alignment=QgsTextRenderer.HAlignment.AlignLeft, + rect=QRectF(50, 130, 350, 100), + flags=Qgis.TextRendererFlag.WrapLines, + ) ) def testDrawTextRectMultilineBottomAlign(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRender(format, 'text_rect_multiline_bottom_aligned', text=['test', 'bottom', 'aligned'], - alignment=QgsTextRenderer.HAlignment.AlignLeft, rect=QRectF(100, 100, 200, 100), - vAlignment=QgsTextRenderer.VAlignment.AlignBottom)) + self.assertTrue( + self.checkRender( + format, + "text_rect_multiline_bottom_aligned", + text=["test", "bottom", "aligned"], + alignment=QgsTextRenderer.HAlignment.AlignLeft, + rect=QRectF(100, 100, 200, 100), + vAlignment=QgsTextRenderer.VAlignment.AlignBottom, + ) + ) def testDrawTextRectBottomAlign(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRender(format, 'text_rect_bottom_aligned', text=['bottom aligned'], - alignment=QgsTextRenderer.HAlignment.AlignLeft, rect=QRectF(100, 100, 200, 100), - vAlignment=QgsTextRenderer.VAlignment.AlignBottom)) + self.assertTrue( + self.checkRender( + format, + "text_rect_bottom_aligned", + text=["bottom aligned"], + alignment=QgsTextRenderer.HAlignment.AlignLeft, + rect=QRectF(100, 100, 200, 100), + vAlignment=QgsTextRenderer.VAlignment.AlignBottom, + ) + ) def testDrawTextRectMultilineVCenterAlign(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRender(format, 'text_rect_multiline_vcenter_aligned', text=['test', 'center', 'aligned'], - alignment=QgsTextRenderer.HAlignment.AlignLeft, rect=QRectF(100, 100, 200, 100), - vAlignment=QgsTextRenderer.VAlignment.AlignVCenter)) + self.assertTrue( + self.checkRender( + format, + "text_rect_multiline_vcenter_aligned", + text=["test", "center", "aligned"], + alignment=QgsTextRenderer.HAlignment.AlignLeft, + rect=QRectF(100, 100, 200, 100), + vAlignment=QgsTextRenderer.VAlignment.AlignVCenter, + ) + ) def testDrawTextRectVCenterAlign(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRender(format, 'text_rect_vcenter_aligned', text=['center aligned'], - alignment=QgsTextRenderer.HAlignment.AlignLeft, rect=QRectF(100, 100, 200, 100), - vAlignment=QgsTextRenderer.VAlignment.AlignVCenter)) + self.assertTrue( + self.checkRender( + format, + "text_rect_vcenter_aligned", + text=["center aligned"], + alignment=QgsTextRenderer.HAlignment.AlignLeft, + rect=QRectF(100, 100, 200, 100), + vAlignment=QgsTextRenderer.VAlignment.AlignVCenter, + ) + ) def testDrawTextRectMultilineCenterAlign(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRender(format, 'text_rect_multiline_center_aligned', text=['test', 'c', 'aligned'], - alignment=QgsTextRenderer.HAlignment.AlignCenter, rect=QRectF(100, 100, 200, 100))) + self.assertTrue( + self.checkRender( + format, + "text_rect_multiline_center_aligned", + text=["test", "c", "aligned"], + alignment=QgsTextRenderer.HAlignment.AlignCenter, + rect=QRectF(100, 100, 200, 100), + ) + ) def testDrawTextRectCenterAlign(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRender(format, 'text_rect_center_aligned', text=['test'], - alignment=QgsTextRenderer.HAlignment.AlignCenter, rect=QRectF(100, 100, 200, 100))) + self.assertTrue( + self.checkRender( + format, + "text_rect_center_aligned", + text=["test"], + alignment=QgsTextRenderer.HAlignment.AlignCenter, + rect=QRectF(100, 100, 200, 100), + ) + ) def testDrawTextPointMultilineRightAlign(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRenderPoint(format, 'text_point_right_multiline_aligned', text=['test', 'right', 'aligned'], - alignment=QgsTextRenderer.HAlignment.AlignRight, point=QPointF(300, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_point_right_multiline_aligned", + text=["test", "right", "aligned"], + alignment=QgsTextRenderer.HAlignment.AlignRight, + point=QPointF(300, 200), + ) + ) def testDrawTextPointMultilineCenterAlign(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRenderPoint(format, 'text_point_center_multiline_aligned', text=['test', 'center', 'aligned'], - alignment=QgsTextRenderer.HAlignment.AlignCenter, point=QPointF(200, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_point_center_multiline_aligned", + text=["test", "center", "aligned"], + alignment=QgsTextRenderer.HAlignment.AlignCenter, + point=QPointF(200, 200), + ) + ) def testDrawTextPointRightAlign(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRenderPoint(format, 'text_point_right_aligned', text=['test'], - alignment=QgsTextRenderer.HAlignment.AlignRight, point=QPointF(300, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_point_right_aligned", + text=["test"], + alignment=QgsTextRenderer.HAlignment.AlignRight, + point=QPointF(300, 200), + ) + ) def testDrawTextPointJustifyAlign(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRenderPoint(format, 'text_point_justify_aligned', text=['test'], - alignment=QgsTextRenderer.HAlignment.AlignJustify, point=QPointF(100, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_point_justify_aligned", + text=["test"], + alignment=QgsTextRenderer.HAlignment.AlignJustify, + point=QPointF(100, 200), + ) + ) def testDrawTextPointMultilineJustifyAlign(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRenderPoint(format, 'text_point_justify_multiline_aligned', - text=['a t est', 'off', 'justification', 'align'], - alignment=QgsTextRenderer.HAlignment.AlignJustify, point=QPointF(100, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_point_justify_multiline_aligned", + text=["a t est", "off", "justification", "align"], + alignment=QgsTextRenderer.HAlignment.AlignJustify, + point=QPointF(100, 200), + ) + ) def testDrawTextPointCenterAlign(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - self.assertTrue(self.checkRenderPoint(format, 'text_point_center_aligned', text=['test'], - alignment=QgsTextRenderer.HAlignment.AlignCenter, point=QPointF(200, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_point_center_aligned", + text=["test"], + alignment=QgsTextRenderer.HAlignment.AlignCenter, + point=QPointF(200, 200), + ) + ) def testDrawTextDataDefinedColorPoint(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) - format.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.Color, QgsProperty.fromExpression("'#bb00cc'")) - self.assertTrue(self.checkRenderPoint(format, 'text_dd_color_point', None, text=['test'], point=QPointF(50, 200))) + format.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Color, QgsProperty.fromExpression("'#bb00cc'") + ) + self.assertTrue( + self.checkRenderPoint( + format, + "text_dd_color_point", + None, + text=["test"], + point=QPointF(50, 200), + ) + ) def testDrawTextDataDefinedColorRect(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) - format.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.Color, QgsProperty.fromExpression("'#bb00cc'")) - self.assertTrue(self.checkRender(format, 'text_dd_color_rect', None, text=['test'], - alignment=QgsTextRenderer.HAlignment.AlignCenter, rect=QRectF(100, 100, 100, 100))) + format.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Color, QgsProperty.fromExpression("'#bb00cc'") + ) + self.assertTrue( + self.checkRender( + format, + "text_dd_color_rect", + None, + text=["test"], + alignment=QgsTextRenderer.HAlignment.AlignCenter, + rect=QRectF(100, 100, 100, 100), + ) + ) def testDrawTextDataDefinedBufferColorPoint(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) - format.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.BufferColor, - QgsProperty.fromExpression("'#bb00cc'")) + format.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.BufferColor, + QgsProperty.fromExpression("'#bb00cc'"), + ) format.buffer().setEnabled(True) format.buffer().setSize(5) - self.assertTrue(self.checkRenderPoint(format, 'text_dd_buffer_color', None, text=['test'], point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_dd_buffer_color", + None, + text=["test"], + point=QPointF(50, 200), + ) + ) def testDrawTabPercent(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(20) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setTabStopDistance(4) format.setTabStopDistanceUnit(Qgis.RenderUnit.Percentage) - self.assertTrue(self.checkRender(format, - 'text_tab_percentage', - text=['with\ttabs', 'a\tb'])) + self.assertTrue( + self.checkRender(format, "text_tab_percentage", text=["with\ttabs", "a\tb"]) + ) def testDrawTabPositionsPercent(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(20) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setTabPositions([QgsTextFormat.Tab(3.1), QgsTextFormat.Tab(8)]) format.setTabStopDistanceUnit(Qgis.RenderUnit.Percentage) - self.assertTrue(self.checkRender(format, - 'text_tab_positions_percentage', - text=['with\tmany\ttabs', 'a\tb\tc'])) + self.assertTrue( + self.checkRender( + format, + "text_tab_positions_percentage", + text=["with\tmany\ttabs", "a\tb\tc"], + ) + ) def testDrawTabFixedSize(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(20) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setTabStopDistance(40) format.setTabStopDistanceUnit(Qgis.RenderUnit.Millimeters) - self.assertTrue(self.checkRender(format, - 'text_tab_fixed_size', - text=['with\ttabs', 'a\tb'])) + self.assertTrue( + self.checkRender(format, "text_tab_fixed_size", text=["with\ttabs", "a\tb"]) + ) def testDrawTabPositionsFixedSize(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(20) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setTabPositions([QgsTextFormat.Tab(20), QgsTextFormat.Tab(50)]) format.setTabStopDistanceUnit(Qgis.RenderUnit.Millimeters) - self.assertTrue(self.checkRender(format, - 'text_tab_positions_fixed_size', - text=['with\tmany\ttabs', 'a\tb\tc'])) + self.assertTrue( + self.checkRender( + format, + "text_tab_positions_fixed_size", + text=["with\tmany\ttabs", "a\tb\tc"], + ) + ) def testDrawTabPositionsFixedSizeMoreTabsThanPositions(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(20) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setTabPositions([QgsTextFormat.Tab(20), QgsTextFormat.Tab(50)]) format.setTabStopDistanceUnit(Qgis.RenderUnit.Millimeters) - self.assertTrue(self.checkRender(format, - 'text_tab_positions_fixed_size_more_tabs', - text=['with\tmany\ttabs', 'a\tb\tc\td\te'])) + self.assertTrue( + self.checkRender( + format, + "text_tab_positions_fixed_size_more_tabs", + text=["with\tmany\ttabs", "a\tb\tc\td\te"], + ) + ) def testDrawTabPositionsFixedSizeLongText(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(20) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setTabPositions([QgsTextFormat.Tab(15), QgsTextFormat.Tab(50)]) format.setTabStopDistanceUnit(Qgis.RenderUnit.Millimeters) - self.assertTrue(self.checkRender(format, - 'text_tab_positions_fixed_size_long_text', - text=['with long\ttext\t2', 'a\tb\tc'])) + self.assertTrue( + self.checkRender( + format, + "text_tab_positions_fixed_size_long_text", + text=["with long\ttext\t2", "a\tb\tc"], + ) + ) def testHtmlFormatting(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRenderPoint(format, 'text_html_formatting', None, text=[ - 'test'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_formatting", + None, + text=[ + 'test' + ], + point=QPointF(50, 200), + ) + ) def testHtmlTabPercent(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(20) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setTabStopDistance(4) format.setTabStopDistanceUnit(Qgis.RenderUnit.Percentage) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRender(format, - 'text_tab_percentage_html', - text=['with\ttabs', ' a\tb'])) + self.assertTrue( + self.checkRender( + format, + "text_tab_percentage_html", + text=['with\ttabs', " a\tb"], + ) + ) def testHtmlTabPositionsPercent(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(20) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setTabPositions([QgsTextFormat.Tab(3), QgsTextFormat.Tab(8)]) format.setTabStopDistanceUnit(Qgis.RenderUnit.Percentage) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRender(format, - 'text_tab_positions_percentage_html', - text=['with\tmany\ttabs', ' a\tb\tc'])) + self.assertTrue( + self.checkRender( + format, + "text_tab_positions_percentage_html", + text=[ + 'with\tmany\ttabs', + " a\tb\tc", + ], + ) + ) def testHtmlTabFixedSize(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(20) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setTabStopDistance(40) format.setTabStopDistanceUnit(Qgis.RenderUnit.Millimeters) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRender(format, - 'text_tab_fixed_size_html', - text=['with\ttabs', ' a\tb'])) + self.assertTrue( + self.checkRender( + format, + "text_tab_fixed_size_html", + text=['with\ttabs', " a\tb"], + ) + ) def testHtmlTabPositionsFixedSize(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(20) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setTabPositions([QgsTextFormat.Tab(25), QgsTextFormat.Tab(60)]) format.setTabStopDistanceUnit(Qgis.RenderUnit.Millimeters) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRender(format, - 'text_tab_positions_fixed_size_html', - text=['with\tmany\ttabs', ' a\tb\tc'])) + self.assertTrue( + self.checkRender( + format, + "text_tab_positions_fixed_size_html", + text=[ + 'with\tmany\ttabs', + " a\tb\tc", + ], + ) + ) def testHtmlFormattingBuffer(self): """ Test drawing HTML with buffer """ format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) @@ -2524,16 +3803,24 @@ def testHtmlFormattingBuffer(self): format.buffer().setEnabled(True) format.buffer().setSize(5) format.buffer().setColor(QColor(50, 150, 200)) - self.assertTrue(self.checkRenderPoint(format, 'text_html_formatting_buffer', None, text=[ - 'test'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_formatting_buffer", + None, + text=[ + 'test' + ], + point=QPointF(50, 200), + ) + ) def testHtmlFormattingBufferScaleFactor(self): """ Test drawing HTML with scale factor workaround """ format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) # font sizes < 50 pixel trigger the scale factor workaround format.setSize(49) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPixels) @@ -2542,32 +3829,50 @@ def testHtmlFormattingBufferScaleFactor(self): format.buffer().setEnabled(True) format.buffer().setSize(5) format.buffer().setColor(QColor(50, 150, 200)) - self.assertTrue(self.checkRenderPoint(format, 'text_html_formatting_buffer_scale_workaround', None, text=[ - 't e s'], - point=QPointF(50, 200), enable_scale_workaround=True)) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_formatting_buffer_scale_workaround", + None, + text=[ + 't e s' + ], + point=QPointF(50, 200), + enable_scale_workaround=True, + ) + ) def testHtmlFormattingMask(self): """ Test drawing HTML with mask """ format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) format.setAllowHtmlFormatting(True) format.mask().setEnabled(True) format.mask().setSize(5) - self.assertTrue(self.checkRenderPoint(format, 'text_html_formatting_mask', None, text=[ - 't e s'], - point=QPointF(50, 200), render_mask=True)) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_formatting_mask", + None, + text=[ + 't e s' + ], + point=QPointF(50, 200), + render_mask=True, + ) + ) def testHtmlFormattingMaskScaleFactor(self): """ Test drawing HTML with mask with scale factor workaround """ format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) # font sizes < 50 pixel trigger the scale factor workaround format.setSize(49) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPixels) @@ -2575,13 +3880,23 @@ def testHtmlFormattingMaskScaleFactor(self): format.setAllowHtmlFormatting(True) format.mask().setEnabled(True) format.mask().setSize(5) - self.assertTrue(self.checkRenderPoint(format, 'text_html_formatting_mask_scale_workaround', None, text=[ - 't e s'], - point=QPointF(50, 200), render_mask=True, enable_scale_workaround=True)) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_formatting_mask_scale_workaround", + None, + text=[ + 't e s' + ], + point=QPointF(50, 200), + render_mask=True, + enable_scale_workaround=True, + ) + ) def testHtmlFormattingShadow(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) @@ -2590,13 +3905,21 @@ def testHtmlFormattingShadow(self): format.shadow().setOffsetDistance(5) format.shadow().setBlurRadius(0) format.shadow().setColor(QColor(50, 150, 200)) - self.assertTrue(self.checkRenderPoint(format, 'text_html_formatting_shadow', None, text=[ - 'test'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_formatting_shadow", + None, + text=[ + 'test' + ], + point=QPointF(50, 200), + ) + ) def testHtmlFormattingBufferShadow(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) @@ -2608,25 +3931,41 @@ def testHtmlFormattingBufferShadow(self): format.shadow().setOffsetDistance(5) format.shadow().setBlurRadius(0) format.shadow().setColor(QColor(50, 150, 200)) - self.assertTrue(self.checkRenderPoint(format, 'text_html_formatting_buffer_shadow', None, text=[ - 'test'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_formatting_buffer_shadow", + None, + text=[ + 'test' + ], + point=QPointF(50, 200), + ) + ) def testHtmlFormattingVertical(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) format.setAllowHtmlFormatting(True) format.setOrientation(QgsTextFormat.TextOrientation.VerticalOrientation) - self.assertTrue(self.checkRenderPoint(format, 'text_html_formatting_vertical', None, text=[ - 'test'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_formatting_vertical", + None, + text=[ + 'test' + ], + point=QPointF(50, 200), + ) + ) def testHtmlFormattingBufferVertical(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) @@ -2635,48 +3974,80 @@ def testHtmlFormattingBufferVertical(self): format.buffer().setSize(5) format.buffer().setColor(QColor(50, 150, 200)) format.setOrientation(QgsTextFormat.TextOrientation.VerticalOrientation) - self.assertTrue(self.checkRenderPoint(format, 'text_html_formatting_buffer_vertical', None, text=[ - 'test'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_formatting_buffer_vertical", + None, + text=[ + 'test' + ], + point=QPointF(50, 200), + ) + ) def testHtmlMixedMetricFormatting(self): format = QgsTextFormat() - format.setFont(getTestFont('regular')) + format.setFont(getTestFont("regular")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRenderPoint(format, 'text_html_mixed_metric_formatting', None, text=[ - 'te

    st'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_mixed_metric_formatting", + None, + text=[ + 'te

    st' + ], + point=QPointF(50, 200), + ) + ) def testHtmlMixedMetricLineHeight(self): format = QgsTextFormat() - format.setFont(getTestFont('regular')) + format.setFont(getTestFont("regular")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) format.setAllowHtmlFormatting(True) format.setLineHeight(0.5) - self.assertTrue(self.checkRenderPoint(format, 'text_html_mixed_metric_formatting_line_height', None, text=[ - 'te

    st'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_mixed_metric_formatting_line_height", + None, + text=[ + 'te

    st' + ], + point=QPointF(50, 200), + ) + ) def testHtmlMixedMetricLineHeightCss(self): format = QgsTextFormat() - format.setFont(getTestFont('regular')) + format.setFont(getTestFont("regular")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 0, 0)) format.setAllowHtmlFormatting(True) format.setLineHeight(0.5) - self.assertTrue(self.checkRenderPoint(format, 'text_html_mixed_metric_formatting_line_height_css', None, text=[ - 'te

    st

    third line

    '], - point=QPointF(50, 300))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_mixed_metric_formatting_line_height_css", + None, + text=[ + 'te

    st

    third line

    ' + ], + point=QPointF(50, 300), + ) + ) def testHtmlMixedMetricFormattingBuffer(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) @@ -2684,13 +4055,21 @@ def testHtmlMixedMetricFormattingBuffer(self): format.buffer().setEnabled(True) format.buffer().setSize(5) format.buffer().setColor(QColor(50, 150, 200)) - self.assertTrue(self.checkRenderPoint(format, 'text_html_mixed_metric_formatting_buffer', None, text=[ - 'te

    st'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_mixed_metric_formatting_buffer", + None, + text=[ + 'te

    st' + ], + point=QPointF(50, 200), + ) + ) def testHtmlMixedMetricFormattingShadow(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) @@ -2699,13 +4078,21 @@ def testHtmlMixedMetricFormattingShadow(self): format.shadow().setOffsetDistance(5) format.shadow().setBlurRadius(0) format.shadow().setColor(QColor(50, 150, 200)) - self.assertTrue(self.checkRenderPoint(format, 'text_html_mixed_metric_formatting_shadow', None, text=[ - 'te

    st'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_mixed_metric_formatting_shadow", + None, + text=[ + 'te

    st' + ], + point=QPointF(50, 200), + ) + ) def testHtmlMixedMetricFormattingBufferShadow(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) @@ -2717,25 +4104,41 @@ def testHtmlMixedMetricFormattingBufferShadow(self): format.shadow().setOffsetDistance(5) format.shadow().setBlurRadius(0) format.shadow().setColor(QColor(50, 150, 200)) - self.assertTrue(self.checkRenderPoint(format, 'text_html_mixed_metric_formatting_buffer_shadow', None, text=[ - 'te

    st'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_mixed_metric_formatting_buffer_shadow", + None, + text=[ + 'te

    st' + ], + point=QPointF(50, 200), + ) + ) def testHtmlMixedMetricFormattingVertical(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) format.setAllowHtmlFormatting(True) format.setOrientation(QgsTextFormat.TextOrientation.VerticalOrientation) - self.assertTrue(self.checkRenderPoint(format, 'text_html_mixed_metric_formatting_vertical', None, text=[ - 'te

    st'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_mixed_metric_formatting_vertical", + None, + text=[ + 'te

    st' + ], + point=QPointF(50, 200), + ) + ) def testHtmlMixedMetricFormattingBufferVertical(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) @@ -2744,13 +4147,21 @@ def testHtmlMixedMetricFormattingBufferVertical(self): format.buffer().setSize(5) format.buffer().setColor(QColor(50, 150, 200)) format.setOrientation(QgsTextFormat.TextOrientation.VerticalOrientation) - self.assertTrue(self.checkRenderPoint(format, 'text_html_mixed_metric_formatting_buffer_vertical', None, text=[ - 'te

    st'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_mixed_metric_formatting_buffer_vertical", + None, + text=[ + 'te

    st' + ], + point=QPointF(50, 200), + ) + ) def testHtmlMixedMetricFormattingShadowVertical(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) @@ -2760,13 +4171,21 @@ def testHtmlMixedMetricFormattingShadowVertical(self): format.shadow().setBlurRadius(0) format.shadow().setColor(QColor(50, 150, 200)) format.setOrientation(QgsTextFormat.TextOrientation.VerticalOrientation) - self.assertTrue(self.checkRenderPoint(format, 'text_html_mixed_metric_formatting_shadow_vertical', None, text=[ - 'te

    st'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_mixed_metric_formatting_shadow_vertical", + None, + text=[ + 'te

    st' + ], + point=QPointF(50, 200), + ) + ) def testHtmlMixedMetricFormattingBufferShadowVertical(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) @@ -2779,178 +4198,316 @@ def testHtmlMixedMetricFormattingBufferShadowVertical(self): format.shadow().setBlurRadius(0) format.shadow().setColor(QColor(50, 150, 200)) format.setOrientation(QgsTextFormat.TextOrientation.VerticalOrientation) - self.assertTrue(self.checkRenderPoint(format, 'text_html_mixed_metric_formatting_buffer_shadow_vertical', None, text=[ - 'te

    st'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_mixed_metric_formatting_buffer_shadow_vertical", + None, + text=[ + 'te

    st' + ], + point=QPointF(50, 200), + ) + ) def testHtmlHeadings(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRenderPoint(format, 'html_headings', None, text=[ - '

    h1

    h2

    h3

    h4

    h5
    h6
    '], - point=QPointF(10, 300))) + self.assertTrue( + self.checkRenderPoint( + format, + "html_headings", + None, + text=[ + "

    h1

    h2

    h3

    h4

    h5
    h6
    " + ], + point=QPointF(10, 300), + ) + ) def testHtmlHeadingsLargerFont(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(40) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRenderPoint(format, 'html_headings_larger', None, text=[ - '

    h1

    h2

    h3

    h4

    h5
    h6
    '], - point=QPointF(10, 350))) + self.assertTrue( + self.checkRenderPoint( + format, + "html_headings_larger", + None, + text=[ + "

    h1

    h2

    h3

    h4

    h5
    h6
    " + ], + point=QPointF(10, 350), + ) + ) def testHtmlAlignmentLeftBase(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRender(format, 'html_align_rect_left_base', None, text=[ - '

    Test some text

    Short

    test

    test

    center
    '], - rect=QRectF(10, 10, 300, 300))) + self.assertTrue( + self.checkRender( + format, + "html_align_rect_left_base", + None, + text=[ + '

    Test some text

    Short

    test

    test

    center
    ' + ], + rect=QRectF(10, 10, 300, 300), + ) + ) def testHtmlAlignmentRightBase(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRender(format, 'html_align_rect_right_base', None, text=[ - '

    Test some text

    Short

    test

    test

    center
    '], - rect=QRectF(10, 10, 300, 300), alignment=Qgis.TextHorizontalAlignment.Right)) + self.assertTrue( + self.checkRender( + format, + "html_align_rect_right_base", + None, + text=[ + '

    Test some text

    Short

    test

    test

    center
    ' + ], + rect=QRectF(10, 10, 300, 300), + alignment=Qgis.TextHorizontalAlignment.Right, + ) + ) def testHtmlAlignmentCenterBase(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRender(format, 'html_align_rect_center_base', None, text=[ - '

    Test some text

    Short

    test

    test

    center
    '], - rect=QRectF(10, 10, 300, 300), alignment=Qgis.TextHorizontalAlignment.Center)) + self.assertTrue( + self.checkRender( + format, + "html_align_rect_center_base", + None, + text=[ + '

    Test some text

    Short

    test

    test

    center
    ' + ], + rect=QRectF(10, 10, 300, 300), + alignment=Qgis.TextHorizontalAlignment.Center, + ) + ) def testHtmlMarginsRectLeftBase(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRender(format, 'margins_rect_left', None, text=[ - '

    Test some text

    Short

    test

    test

    center
    '], - rect=QRectF(10, 10, 300, 300))) + self.assertTrue( + self.checkRender( + format, + "margins_rect_left", + None, + text=[ + '

    Test some text

    Short

    test

    test

    center
    ' + ], + rect=QRectF(10, 10, 300, 300), + ) + ) def testHtmlMarginsRectJustifyBase(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRender(format, 'margins_rect_justify', None, alignment=QgsTextRenderer.HAlignment.AlignJustify, text=[ - '

    Test some text

    Short

    test

    test

    center
    '], - rect=QRectF(10, 10, 300, 300))) + self.assertTrue( + self.checkRender( + format, + "margins_rect_justify", + None, + alignment=QgsTextRenderer.HAlignment.AlignJustify, + text=[ + '

    Test some text

    Short

    test

    test

    center
    ' + ], + rect=QRectF(10, 10, 300, 300), + ) + ) def testHtmlMarginsRectRightBase(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRender(format, 'margins_rect_right', None, alignment=QgsTextRenderer.HAlignment.AlignRight, text=[ - '

    Test some text

    Short

    test

    test

    center
    '], - rect=QRectF(10, 10, 350, 300))) + self.assertTrue( + self.checkRender( + format, + "margins_rect_right", + None, + alignment=QgsTextRenderer.HAlignment.AlignRight, + text=[ + '

    Test some text

    Short

    test

    test

    center
    ' + ], + rect=QRectF(10, 10, 350, 300), + ) + ) def testHtmlMarginsRectCenterBase(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRender(format, 'margins_rect_center', None, alignment=QgsTextRenderer.HAlignment.AlignCenter, text=[ - '

    Test some text

    Short

    test

    test

    center
    '], - rect=QRectF(10, 10, 350, 300))) + self.assertTrue( + self.checkRender( + format, + "margins_rect_center", + None, + alignment=QgsTextRenderer.HAlignment.AlignCenter, + text=[ + '

    Test some text

    Short

    test

    test

    center
    ' + ], + rect=QRectF(10, 10, 350, 300), + ) + ) def testHtmlMarginsPointLeftBase(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRenderPoint(format, 'margins_point_left', None, text=[ - '

    Test some text

    Short

    test

    test

    '], - point=QPointF(10, 350))) + self.assertTrue( + self.checkRenderPoint( + format, + "margins_point_left", + None, + text=[ + '

    Test some text

    Short

    test

    test

    ' + ], + point=QPointF(10, 350), + ) + ) def testHtmlMarginsPointJustifyBase(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRenderPoint(format, 'margins_point_justify', None, alignment=QgsTextRenderer.HAlignment.AlignJustify, text=[ - '

    Test some text

    Short

    test

    test

    '], - point=QPointF(10, 350))) + self.assertTrue( + self.checkRenderPoint( + format, + "margins_point_justify", + None, + alignment=QgsTextRenderer.HAlignment.AlignJustify, + text=[ + '

    Test some text

    Short

    test

    test

    ' + ], + point=QPointF(10, 350), + ) + ) def testHtmlMarginsPointRightBase(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRenderPoint(format, 'margins_point_right', None, alignment=QgsTextRenderer.HAlignment.AlignRight, text=[ - '

    Test some text

    Short

    test

    test

    '], - point=QPointF(400, 350))) + self.assertTrue( + self.checkRenderPoint( + format, + "margins_point_right", + None, + alignment=QgsTextRenderer.HAlignment.AlignRight, + text=[ + '

    Test some text

    Short

    test

    test

    ' + ], + point=QPointF(400, 350), + ) + ) def testHtmlMarginsPointCenterBase(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRenderPoint(format, 'margins_point_center', None, alignment=QgsTextRenderer.HAlignment.AlignCenter, text=[ - '

    Test some text

    Short

    test

    test

    '], - point=QPointF(200, 350))) + self.assertTrue( + self.checkRenderPoint( + format, + "margins_point_center", + None, + alignment=QgsTextRenderer.HAlignment.AlignCenter, + text=[ + '

    Test some text

    Short

    test

    test

    ' + ], + point=QPointF(200, 350), + ) + ) def testHtmlMarginsRectMiddleBase(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRender(format, 'margins_rect_middle', None, vAlignment=QgsTextRenderer.VAlignment.AlignVCenter, text=[ - '

    Test some text

    Short

    test

    test

    center
    '], - rect=QRectF(10, 10, 300, 300))) + self.assertTrue( + self.checkRender( + format, + "margins_rect_middle", + None, + vAlignment=QgsTextRenderer.VAlignment.AlignVCenter, + text=[ + '

    Test some text

    Short

    test

    test

    center
    ' + ], + rect=QRectF(10, 10, 300, 300), + ) + ) def testHtmlMarginsRectBottomBase(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRender(format, 'margins_rect_bottom', None, vAlignment=QgsTextRenderer.VAlignment.AlignBottom, text=[ - '

    Test some text

    Short

    test

    test

    center
    '], - rect=QRectF(10, 10, 300, 300))) + self.assertTrue( + self.checkRender( + format, + "margins_rect_bottom", + None, + vAlignment=QgsTextRenderer.VAlignment.AlignBottom, + text=[ + '

    Test some text

    Short

    test

    test

    center
    ' + ], + rect=QRectF(10, 10, 300, 300), + ) + ) def testHtmlImageAutoSize(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) @@ -2962,13 +4519,22 @@ def testHtmlImageAutoSize(self): format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.background().setFillColor(QColor(255, 255, 255)) - self.assertTrue(self.checkRender(format, 'image_autosize', None, text=[ - f'

    Test test

    '], - rect=QRectF(10, 10, 300, 300), alignment=Qgis.TextHorizontalAlignment.Center)) + self.assertTrue( + self.checkRender( + format, + "image_autosize", + None, + text=[ + f'

    Test test

    ' + ], + rect=QRectF(10, 10, 300, 300), + alignment=Qgis.TextHorizontalAlignment.Center, + ) + ) def testHtmlImageAutoWidth(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) @@ -2980,13 +4546,22 @@ def testHtmlImageAutoWidth(self): format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.background().setFillColor(QColor(255, 255, 255)) - self.assertTrue(self.checkRender(format, 'image_autowidth', None, text=[ - f'

    Test test

    '], - rect=QRectF(10, 10, 300, 300), alignment=Qgis.TextHorizontalAlignment.Center)) + self.assertTrue( + self.checkRender( + format, + "image_autowidth", + None, + text=[ + f'

    Test test

    ' + ], + rect=QRectF(10, 10, 300, 300), + alignment=Qgis.TextHorizontalAlignment.Center, + ) + ) def testHtmlImageAutoHeight(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) @@ -2998,13 +4573,22 @@ def testHtmlImageAutoHeight(self): format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.background().setFillColor(QColor(255, 255, 255)) - self.assertTrue(self.checkRender(format, 'image_autoheight', None, text=[ - f'

    Test test

    '], - rect=QRectF(10, 10, 300, 300), alignment=Qgis.TextHorizontalAlignment.Center)) + self.assertTrue( + self.checkRender( + format, + "image_autoheight", + None, + text=[ + f'

    Test test

    ' + ], + rect=QRectF(10, 10, 300, 300), + alignment=Qgis.TextHorizontalAlignment.Center, + ) + ) def testHtmlImageFixedSize(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) @@ -3016,35 +4600,58 @@ def testHtmlImageFixedSize(self): format.background().setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters) format.background().setFillColor(QColor(255, 255, 255)) - self.assertTrue(self.checkRender(format, 'image_fixed_size', None, text=[ - f'

    Test test

    '], - rect=QRectF(10, 10, 300, 300), alignment=Qgis.TextHorizontalAlignment.Center)) + self.assertTrue( + self.checkRender( + format, + "image_fixed_size", + None, + text=[ + f'

    Test test

    ' + ], + rect=QRectF(10, 10, 300, 300), + alignment=Qgis.TextHorizontalAlignment.Center, + ) + ) def testHtmlSuperSubscript(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRenderPoint(format, 'text_html_supersubscript', None, text=[ - 'subNsup'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_supersubscript", + None, + text=["subNsup"], + point=QPointF(50, 200), + ) + ) def testHtmlSuperSubscriptFixedFontSize(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRenderPoint(format, 'text_html_supersubscript_fixed_font_size', None, text=[ - 'suNsup'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_supersubscript_fixed_font_size", + None, + text=[ + 'suNsup' + ], + point=QPointF(50, 200), + ) + ) def testHtmlSuperSubscriptBuffer(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) @@ -3052,13 +4659,19 @@ def testHtmlSuperSubscriptBuffer(self): format.buffer().setEnabled(True) format.buffer().setSize(5) format.buffer().setColor(QColor(50, 150, 200)) - self.assertTrue(self.checkRenderPoint(format, 'text_html_supersubscript_buffer', None, text=[ - 'subNsup'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_supersubscript_buffer", + None, + text=["subNsup"], + point=QPointF(50, 200), + ) + ) def testHtmlSuperSubscriptShadow(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) @@ -3067,13 +4680,19 @@ def testHtmlSuperSubscriptShadow(self): format.shadow().setOffsetDistance(5) format.shadow().setBlurRadius(0) format.shadow().setColor(QColor(50, 150, 200)) - self.assertTrue(self.checkRenderPoint(format, 'text_html_supersubscript_shadow', None, text=[ - 'subNsup'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_supersubscript_shadow", + None, + text=["subNsup"], + point=QPointF(50, 200), + ) + ) def testHtmlSuperSubscriptBufferShadow(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(0, 255, 0)) @@ -3085,52 +4704,76 @@ def testHtmlSuperSubscriptBufferShadow(self): format.shadow().setOffsetDistance(5) format.shadow().setBlurRadius(0) format.shadow().setColor(QColor(50, 150, 200)) - self.assertTrue(self.checkRenderPoint(format, 'text_html_supersubscript_buffer_shadow', None, text=[ - 'subNsup'], - point=QPointF(50, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_html_supersubscript_buffer_shadow", + None, + text=["subNsup"], + point=QPointF(50, 200), + ) + ) def testHtmlWordSpacing(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRenderPoint(format, 'html_word_spacing', None, text=[ - 'test of wo space'], - point=QPointF(10, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "html_word_spacing", + None, + text=['test of wo space'], + point=QPointF(10, 200), + ) + ) def testHtmlWordSpacingPx(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) # unit should be ignored, we always treat it as pt as pixels don't # scale - self.assertTrue(self.checkRenderPoint(format, 'html_word_spacing', None, text=[ - 'test of wo space'], - point=QPointF(10, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "html_word_spacing", + None, + text=['test of wo space'], + point=QPointF(10, 200), + ) + ) def testHtmlWordSpacingNegative(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setColor(QColor(255, 0, 0)) format.setAllowHtmlFormatting(True) - self.assertTrue(self.checkRenderPoint(format, 'html_word_spacing_negative', None, text=[ - 'test of wo space'], - point=QPointF(10, 200))) + self.assertTrue( + self.checkRenderPoint( + format, + "html_word_spacing_negative", + None, + text=['test of wo space'], + point=QPointF(10, 200), + ) + ) def testTextRenderFormat(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(30) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) - filename = f'{QDir.tempPath()}/test_render_text.svg' + filename = f"{QDir.tempPath()}/test_render_text.svg" svg = QSvgGenerator() svg.setFileName(filename) svg.setSize(QSize(400, 400)) @@ -3142,7 +4785,9 @@ def testTextRenderFormat(self): context = QgsRenderContext.fromMapSettings(ms) # test with ALWAYS TEXT mode - context.setTextRenderFormat(QgsRenderContext.TextRenderFormat.TextFormatAlwaysText) + context.setTextRenderFormat( + QgsRenderContext.TextRenderFormat.TextFormatAlwaysText + ) painter = QPainter() context.setPainter(painter) @@ -3153,26 +4798,30 @@ def testTextRenderFormat(self): painter.setBrush(QBrush(QColor(182, 239, 255))) painter.setPen(Qt.PenStyle.NoPen) - QgsTextRenderer.drawText(QPointF(0, 30), - 0, - QgsTextRenderer.HAlignment.AlignLeft, - ['my test text'], - context, - format) + QgsTextRenderer.drawText( + QPointF(0, 30), + 0, + QgsTextRenderer.HAlignment.AlignLeft, + ["my test text"], + context, + format, + ) painter.end() # expect svg to contain a text object with the label with open(filename) as f: - lines = ''.join(f.readlines()) - self.assertIn('my test text<', lines) + lines = "".join(f.readlines()) + self.assertIn("my test text<", lines) os.unlink(filename) # test with ALWAYS CURVES mode context = QgsRenderContext.fromMapSettings(ms) - context.setTextRenderFormat(QgsRenderContext.TextRenderFormat.TextFormatAlwaysOutlines) + context.setTextRenderFormat( + QgsRenderContext.TextRenderFormat.TextFormatAlwaysOutlines + ) painter = QPainter() context.setPainter(painter) @@ -3187,62 +4836,92 @@ def testTextRenderFormat(self): painter.setBrush(QBrush(QColor(182, 239, 255))) painter.setPen(Qt.PenStyle.NoPen) - QgsTextRenderer.drawText(QPointF(0, 30), - 0, - QgsTextRenderer.HAlignment.AlignLeft, - ['my test text'], - context, - format) + QgsTextRenderer.drawText( + QPointF(0, 30), + 0, + QgsTextRenderer.HAlignment.AlignLeft, + ["my test text"], + context, + format, + ) painter.end() # expect svg to contain a text object with the label with open(filename) as f: - lines = ''.join(f.readlines()) - self.assertNotIn('my test text<', lines) + lines = "".join(f.readlines()) + self.assertNotIn("my test text<", lines) def testDrawTextVerticalRectMode(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setOrientation(QgsTextFormat.TextOrientation.VerticalOrientation) - self.assertTrue(self.checkRender(format, 'text_vertical_rect_mode', QgsTextRenderer.TextPart.Text, text=['1234'], - rect=QRectF(40, 20, 350, 350))) + self.assertTrue( + self.checkRender( + format, + "text_vertical_rect_mode", + QgsTextRenderer.TextPart.Text, + text=["1234"], + rect=QRectF(40, 20, 350, 350), + ) + ) def testDrawTextVerticalRectModeCenterAligned(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setOrientation(QgsTextFormat.TextOrientation.VerticalOrientation) - self.assertTrue(self.checkRender(format, 'text_vertical_rect_mode_center_aligned', QgsTextRenderer.TextPart.Text, - text=['1234', '5678'], rect=QRectF(40, 20, 350, 350), - alignment=QgsTextRenderer.HAlignment.AlignCenter)) + self.assertTrue( + self.checkRender( + format, + "text_vertical_rect_mode_center_aligned", + QgsTextRenderer.TextPart.Text, + text=["1234", "5678"], + rect=QRectF(40, 20, 350, 350), + alignment=QgsTextRenderer.HAlignment.AlignCenter, + ) + ) def testDrawTextVerticalRectModeRightAligned(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setOrientation(QgsTextFormat.TextOrientation.VerticalOrientation) - self.assertTrue(self.checkRender(format, 'text_vertical_rect_mode_right_aligned', QgsTextRenderer.TextPart.Text, - text=['1234', '5678'], rect=QRectF(40, 20, 350, 350), - alignment=QgsTextRenderer.HAlignment.AlignRight)) + self.assertTrue( + self.checkRender( + format, + "text_vertical_rect_mode_right_aligned", + QgsTextRenderer.TextPart.Text, + text=["1234", "5678"], + rect=QRectF(40, 20, 350, 350), + alignment=QgsTextRenderer.HAlignment.AlignRight, + ) + ) def testDrawTextVerticalPointMode(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(60) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.setOrientation(QgsTextFormat.TextOrientation.VerticalOrientation) - self.assertTrue(self.checkRenderPoint(format, 'text_vertical_point_mode', QgsTextRenderer.TextPart.Text, text=['1234', '5678'], - point=QPointF(40, 380))) + self.assertTrue( + self.checkRenderPoint( + format, + "text_vertical_point_mode", + QgsTextRenderer.TextPart.Text, + text=["1234", "5678"], + point=QPointF(40, 380), + ) + ) def testDrawTextOnLineAtStart(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(16) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) @@ -3255,7 +4934,9 @@ def testDrawTextOnLineAtStart(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) painter.begin(image) painter.setRenderHint(QPainter.RenderHint.Antialiasing) @@ -3270,14 +4951,21 @@ def testDrawTextOnLineAtStart(self): painter.setBrush(QBrush(QColor(182, 239, 255))) painter.setPen(Qt.PenStyle.NoPen) - QgsTextRenderer.drawTextOnLine(line, 'my curved text', context, format, 0) + QgsTextRenderer.drawTextOnLine(line, "my curved text", context, format, 0) painter.end() - self.assertTrue(self.image_check('text_on_line_at_start', 'text_on_line_at_start', image, 'text_on_line_at_start')) + self.assertTrue( + self.image_check( + "text_on_line_at_start", + "text_on_line_at_start", + image, + "text_on_line_at_start", + ) + ) def testDrawTextOnLineZeroWidthChar(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(16) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.background().setEnabled(True) @@ -3291,7 +4979,9 @@ def testDrawTextOnLineZeroWidthChar(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) painter.begin(image) painter.setRenderHint(QPainter.RenderHint.Antialiasing) @@ -3306,14 +4996,21 @@ def testDrawTextOnLineZeroWidthChar(self): painter.setBrush(QBrush(QColor(182, 239, 255))) painter.setPen(Qt.PenStyle.NoPen) - QgsTextRenderer.drawTextOnLine(line, 'b\r\na', context, format, 0) + QgsTextRenderer.drawTextOnLine(line, "b\r\na", context, format, 0) painter.end() - self.assertTrue(self.image_check('text_on_curved_line_zero_width_char', 'text_on_curved_line_zero_width_char', image, 'text_on_curved_line_zero_width_char')) + self.assertTrue( + self.image_check( + "text_on_curved_line_zero_width_char", + "text_on_curved_line_zero_width_char", + image, + "text_on_curved_line_zero_width_char", + ) + ) def testDrawTextOnLineAtOffset(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(16) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) @@ -3326,7 +5023,9 @@ def testDrawTextOnLineAtOffset(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) painter.begin(image) painter.setRenderHint(QPainter.RenderHint.Antialiasing) @@ -3341,14 +5040,21 @@ def testDrawTextOnLineAtOffset(self): painter.setBrush(QBrush(QColor(182, 239, 255))) painter.setPen(Qt.PenStyle.NoPen) - QgsTextRenderer.drawTextOnLine(line, 'my curved text', context, format, 100) + QgsTextRenderer.drawTextOnLine(line, "my curved text", context, format, 100) painter.end() - self.assertTrue(self.image_check('text_on_line_at_offset', 'text_on_line_at_offset', image, 'text_on_line_at_offset')) + self.assertTrue( + self.image_check( + "text_on_line_at_offset", + "text_on_line_at_offset", + image, + "text_on_line_at_offset", + ) + ) def testDrawTextOnCurvedLine(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(16) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.buffer().setEnabled(True) @@ -3364,7 +5070,9 @@ def testDrawTextOnCurvedLine(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) painter.begin(image) painter.setRenderHint(QPainter.RenderHint.Antialiasing) @@ -3373,21 +5081,37 @@ def testDrawTextOnCurvedLine(self): painter.setBrush(Qt.BrushStyle.NoBrush) painter.setPen(QPen(QColor(0, 0, 0))) - line = QPolygonF([QPointF(50, 200), QPointF(100, 230), QPointF(150, 235), QPointF(350, 200)]) + line = QPolygonF( + [QPointF(50, 200), QPointF(100, 230), QPointF(150, 235), QPointF(350, 200)] + ) painter.drawPolyline(line) painter.setBrush(QBrush(QColor(182, 239, 255))) painter.setPen(Qt.PenStyle.NoPen) format.setAllowHtmlFormatting(True) - QgsTextRenderer.drawTextOnLine(line, 'my curved text', context, format, 20, 0) + QgsTextRenderer.drawTextOnLine( + line, + 'my curved text', + context, + format, + 20, + 0, + ) painter.end() - self.assertTrue(self.image_check('text_on_curved_line', 'text_on_curved_line', image, 'text_on_curved_line')) + self.assertTrue( + self.image_check( + "text_on_curved_line", + "text_on_curved_line", + image, + "text_on_curved_line", + ) + ) def testDrawTextOnCurvedLineUpsideDown(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(16) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.buffer().setEnabled(True) @@ -3403,7 +5127,9 @@ def testDrawTextOnCurvedLineUpsideDown(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) painter.begin(image) painter.setRenderHint(QPainter.RenderHint.Antialiasing) @@ -3412,21 +5138,44 @@ def testDrawTextOnCurvedLineUpsideDown(self): painter.setBrush(Qt.BrushStyle.NoBrush) painter.setPen(QPen(QColor(0, 0, 0))) - line = QPolygonF(reversed([QPointF(50, 200), QPointF(100, 230), QPointF(150, 235), QPointF(350, 200)])) + line = QPolygonF( + reversed( + [ + QPointF(50, 200), + QPointF(100, 230), + QPointF(150, 235), + QPointF(350, 200), + ] + ) + ) painter.drawPolyline(line) painter.setBrush(QBrush(QColor(182, 239, 255))) painter.setPen(Qt.PenStyle.NoPen) format.setAllowHtmlFormatting(True) - QgsTextRenderer.drawTextOnLine(line, 'my curved text', context, format, 20, 0) + QgsTextRenderer.drawTextOnLine( + line, + 'my curved text', + context, + format, + 20, + 0, + ) painter.end() - self.assertTrue(self.image_check('text_on_curved_line_upside_down', 'text_on_curved_line_upside_down', image, 'text_on_curved_line_upside_down')) + self.assertTrue( + self.image_check( + "text_on_curved_line_upside_down", + "text_on_curved_line_upside_down", + image, + "text_on_curved_line_upside_down", + ) + ) def testDrawTextOnCurvedLineBackground(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(16) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) @@ -3446,7 +5195,9 @@ def testDrawTextOnCurvedLineBackground(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) painter.begin(image) painter.setRenderHint(QPainter.RenderHint.Antialiasing) @@ -3455,20 +5206,29 @@ def testDrawTextOnCurvedLineBackground(self): painter.setBrush(Qt.BrushStyle.NoBrush) painter.setPen(QPen(QColor(0, 0, 0))) - line = QPolygonF([QPointF(50, 200), QPointF(100, 230), QPointF(150, 235), QPointF(350, 200)]) + line = QPolygonF( + [QPointF(50, 200), QPointF(100, 230), QPointF(150, 235), QPointF(350, 200)] + ) painter.drawPolyline(line) painter.setBrush(QBrush(QColor(182, 239, 255))) painter.setPen(Qt.PenStyle.NoPen) - QgsTextRenderer.drawTextOnLine(line, 'my curved text', context, format, 20, 0) + QgsTextRenderer.drawTextOnLine(line, "my curved text", context, format, 20, 0) painter.end() - self.assertTrue(self.image_check('text_on_curved_line_background', 'text_on_curved_line_background', image, 'text_on_curved_line_background')) + self.assertTrue( + self.image_check( + "text_on_curved_line_background", + "text_on_curved_line_background", + image, + "text_on_curved_line_background", + ) + ) def testDrawTextOnCurvedLineOffsetFromLine(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(16) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) @@ -3481,7 +5241,9 @@ def testDrawTextOnCurvedLineOffsetFromLine(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) painter.begin(image) painter.setRenderHint(QPainter.RenderHint.Antialiasing) @@ -3490,21 +5252,30 @@ def testDrawTextOnCurvedLineOffsetFromLine(self): painter.setBrush(Qt.BrushStyle.NoBrush) painter.setPen(QPen(QColor(0, 0, 0))) - line = QPolygonF([QPointF(50, 200), QPointF(100, 230), QPointF(150, 235), QPointF(350, 200)]) + line = QPolygonF( + [QPointF(50, 200), QPointF(100, 230), QPointF(150, 235), QPointF(350, 200)] + ) painter.drawPolyline(line) painter.setBrush(QBrush(QColor(182, 239, 255))) painter.setPen(Qt.PenStyle.NoPen) format.setAllowHtmlFormatting(True) - QgsTextRenderer.drawTextOnLine(line, 'my curved text', context, format, 20, -20) + QgsTextRenderer.drawTextOnLine(line, "my curved text", context, format, 20, -20) painter.end() - self.assertTrue(self.image_check('text_on_curved_line_offset_line', 'text_on_curved_line_offset_line', image, 'text_on_curved_line_offset_line')) + self.assertTrue( + self.image_check( + "text_on_curved_line_offset_line", + "text_on_curved_line_offset_line", + image, + "text_on_curved_line_offset_line", + ) + ) def testDrawTextOnCurvedLineOffsetFromLinePositive(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(16) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) @@ -3517,7 +5288,9 @@ def testDrawTextOnCurvedLineOffsetFromLinePositive(self): context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI - context.setFlag(QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True) + context.setFlag( + QgsRenderContext.Flag.ApplyScalingWorkaroundForTextRendering, True + ) painter.begin(image) painter.setRenderHint(QPainter.RenderHint.Antialiasing) @@ -3526,33 +5299,48 @@ def testDrawTextOnCurvedLineOffsetFromLinePositive(self): painter.setBrush(Qt.BrushStyle.NoBrush) painter.setPen(QPen(QColor(0, 0, 0))) - line = QPolygonF([QPointF(50, 200), QPointF(100, 230), QPointF(150, 235), QPointF(350, 200)]) + line = QPolygonF( + [QPointF(50, 200), QPointF(100, 230), QPointF(150, 235), QPointF(350, 200)] + ) painter.drawPolyline(line) painter.setBrush(QBrush(QColor(182, 239, 255))) painter.setPen(Qt.PenStyle.NoPen) format.setAllowHtmlFormatting(True) - QgsTextRenderer.drawTextOnLine(line, 'my curved text', context, format, 20, 20) + QgsTextRenderer.drawTextOnLine(line, "my curved text", context, format, 20, 20) painter.end() - self.assertTrue(self.image_check('text_on_curved_line_offset_line_positive', 'text_on_curved_line_offset_line_positive', image, 'text_on_curved_line_offset_line_positive')) + self.assertTrue( + self.image_check( + "text_on_curved_line_offset_line_positive", + "text_on_curved_line_offset_line_positive", + image, + "text_on_curved_line_offset_line_positive", + ) + ) def testDrawTextDataDefinedProperties(self): format = QgsTextFormat() - format.setFont(getTestFont('bold')) + format.setFont(getTestFont("bold")) format.setSize(16) format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) format.dataDefinedProperties().setProperty( - QgsPalLayerSettings.Property.Size, - QgsProperty.fromExpression('90*1.5') + QgsPalLayerSettings.Property.Size, QgsProperty.fromExpression("90*1.5") ) - self.assertTrue(self.checkRender(format, 'datadefined_render', None, - text=['1234', '5678'], rect=QRectF(40, 20, 350, 350), - alignment=QgsTextRenderer.HAlignment.AlignRight)) + self.assertTrue( + self.checkRender( + format, + "datadefined_render", + None, + text=["1234", "5678"], + rect=QRectF(40, 20, 350, 350), + alignment=QgsTextRenderer.HAlignment.AlignRight, + ) + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgstiledsceneboundingvolume.py b/tests/src/python/test_qgstiledsceneboundingvolume.py index fd74ba37d9b1..e9eabc185a16 100644 --- a/tests/src/python/test_qgstiledsceneboundingvolume.py +++ b/tests/src/python/test_qgstiledsceneboundingvolume.py @@ -7,6 +7,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + __author__ = "(C) 2023 by Nyall Dawson" __date__ = "10/07/2023" __copyright__ = "Copyright 2023, The QGIS Project" diff --git a/tests/src/python/test_qgstiledsceneelevationproperties.py b/tests/src/python/test_qgstiledsceneelevationproperties.py index 60a51f96242f..8e761cbe02da 100644 --- a/tests/src/python/test_qgstiledsceneelevationproperties.py +++ b/tests/src/python/test_qgstiledsceneelevationproperties.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '23/08/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "23/08/2023" +__copyright__ = "Copyright 2023, The QGIS Project" import tempfile import os @@ -45,7 +46,7 @@ def testBasic(self): self.assertEqual(props.zOffset(), 0.5) doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsTiledSceneLayerElevationProperties(None) @@ -60,7 +61,7 @@ def testBasic(self): def testCalculateZRange(self): with tempfile.TemporaryDirectory() as temp_dir: tmp_file = os.path.join(temp_dir, "tileset.json") - with open(tmp_file, "wt", encoding="utf-8") as f: + with open(tmp_file, "w", encoding="utf-8") as f: f.write( """ { @@ -99,23 +100,22 @@ def testCalculateZRange(self): z_range = props.calculateZRange(layer) self.assertEqual(z_range.lower(), 1.2) self.assertEqual(z_range.upper(), 67.00999999999999) - self.assertEqual(props.significantZValues(layer), - [1.2, 67.00999999999999]) + self.assertEqual(props.significantZValues(layer), [1.2, 67.00999999999999]) props.setZOffset(10) z_range = props.calculateZRange(layer) self.assertEqual(z_range.lower(), 11.2) self.assertEqual(z_range.upper(), 77.00999999999999) - self.assertEqual(props.significantZValues(layer), - [11.2, 77.00999999999999]) + self.assertEqual(props.significantZValues(layer), [11.2, 77.00999999999999]) props.setZScale(2) z_range = props.calculateZRange(layer) self.assertEqual(z_range.lower(), 12.4) self.assertEqual(z_range.upper(), 144.01999999999998) - self.assertEqual(props.significantZValues(layer), - [12.4, 144.01999999999998]) + self.assertEqual( + props.significantZValues(layer), [12.4, 144.01999999999998] + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgstiledscenelayer.py b/tests/src/python/test_qgstiledscenelayer.py index ba408d2c8075..7a725f35fbd1 100644 --- a/tests/src/python/test_qgstiledscenelayer.py +++ b/tests/src/python/test_qgstiledscenelayer.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '27/06/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "27/06/2023" +__copyright__ = "Copyright 2023, The QGIS Project" from qgis.PyQt.QtGui import QPainter from qgis.PyQt.QtXml import QDomDocument @@ -18,7 +19,7 @@ QgsLayerNotesUtils, QgsMapLayer, QgsTiledSceneDataProvider, - QgsProviderRegistry + QgsProviderRegistry, ) from qgis.testing import start_app, unittest @@ -31,18 +32,22 @@ def test_data_provider(self): """ Test data provider creation """ - layer = QgsTiledSceneLayer('/home/me/test/tileset.json', 'my layer', 'cesiumtiles') - self.assertEqual(layer.providerType(), 'cesiumtiles') + layer = QgsTiledSceneLayer( + "/home/me/test/tileset.json", "my layer", "cesiumtiles" + ) + self.assertEqual(layer.providerType(), "cesiumtiles") self.assertIsInstance(layer.dataProvider(), QgsTiledSceneDataProvider) - self.assertEqual(layer.dataProvider().name(), 'cesiumtiles') - self.assertEqual(layer.dataProvider().dataSourceUri(), '/home/me/test/tileset.json') + self.assertEqual(layer.dataProvider().name(), "cesiumtiles") + self.assertEqual( + layer.dataProvider().dataSourceUri(), "/home/me/test/tileset.json" + ) def test_read_write_xml(self): """ Test saving and restoring layer from xml """ - layer = QgsTiledSceneLayer('uri', 'my layer', 'cesiumtiles') - self.assertEqual(layer.providerType(), 'cesiumtiles') + layer = QgsTiledSceneLayer("uri", "my layer", "cesiumtiles") + self.assertEqual(layer.providerType(), "cesiumtiles") layer.setOpacity(0.25) layer.setBlendMode(QPainter.CompositionMode.CompositionMode_Darken) @@ -50,35 +55,37 @@ def test_read_write_xml(self): elem = doc.createElement("maplayer") self.assertTrue(layer.writeXml(elem, doc, QgsReadWriteContext())) - layer2 = QgsTiledSceneLayer('uri2', 'my layer 2', 'xtiled_meshx') + layer2 = QgsTiledSceneLayer("uri2", "my layer 2", "xtiled_meshx") layer2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(layer2.providerType(), 'cesiumtiles') + self.assertEqual(layer2.providerType(), "cesiumtiles") self.assertEqual(layer2.opacity(), 0.25) - self.assertEqual(layer2.blendMode(), - QPainter.CompositionMode.CompositionMode_Darken) + self.assertEqual( + layer2.blendMode(), QPainter.CompositionMode.CompositionMode_Darken + ) def test_clone(self): """ Test cloning layers """ - layer = QgsTiledSceneLayer('uri', 'my layer', 'cesiumtiles') - self.assertEqual(layer.providerType(), 'cesiumtiles') + layer = QgsTiledSceneLayer("uri", "my layer", "cesiumtiles") + self.assertEqual(layer.providerType(), "cesiumtiles") layer.setOpacity(0.25) layer.setBlendMode(QPainter.CompositionMode.CompositionMode_Darken) layer2 = layer.clone() - self.assertEqual(layer2.source(), 'uri') - self.assertEqual(layer2.providerType(), 'cesiumtiles') + self.assertEqual(layer2.source(), "uri") + self.assertEqual(layer2.providerType(), "cesiumtiles") self.assertEqual(layer2.opacity(), 0.25) - self.assertEqual(layer2.blendMode(), - QPainter.CompositionMode.CompositionMode_Darken) + self.assertEqual( + layer2.blendMode(), QPainter.CompositionMode.CompositionMode_Darken + ) def test_read_write_symbology(self): """ Test reading/writing symbology """ - layer = QgsTiledSceneLayer('uri', 'my layer', 'tiled_mesh') - self.assertEqual(layer.providerType(), 'tiled_mesh') + layer = QgsTiledSceneLayer("uri", "my layer", "tiled_mesh") + self.assertEqual(layer.providerType(), "tiled_mesh") layer.setOpacity(0.25) layer.setBlendMode(QPainter.CompositionMode.CompositionMode_Darken) @@ -86,37 +93,38 @@ def test_read_write_symbology(self): elem = doc.createElement("symbology") context = QgsReadWriteContext() - error = '' + error = "" self.assertTrue(layer.writeSymbology(elem, doc, error, context)) - layer2 = QgsTiledSceneLayer('uri2', 'my layer 2', 'tiled_mesh') + layer2 = QgsTiledSceneLayer("uri2", "my layer 2", "tiled_mesh") layer2.readSymbology(elem, error, context) self.assertEqual(layer2.opacity(), 0.25) - self.assertEqual(layer2.blendMode(), - QPainter.CompositionMode.CompositionMode_Darken) + self.assertEqual( + layer2.blendMode(), QPainter.CompositionMode.CompositionMode_Darken + ) - layer = QgsTiledSceneLayer('uri', 'my layer', 'tiled_mesh') - self.assertEqual(layer.providerType(), 'tiled_mesh') + layer = QgsTiledSceneLayer("uri", "my layer", "tiled_mesh") + self.assertEqual(layer.providerType(), "tiled_mesh") layer.setOpacity(0.25) layer.setBlendMode(QPainter.CompositionMode.CompositionMode_Darken) layer.setMinimumScale(1000) layer.setMaximumScale(2000) layer.setScaleBasedVisibility(True) - layer.setCustomProperty('prop', 'value') - QgsLayerNotesUtils.setLayerNotes(layer, 'my notes') + layer.setCustomProperty("prop", "value") + QgsLayerNotesUtils.setLayerNotes(layer, "my notes") doc = QDomDocument("testdoc") elem = doc.createElement("symbology") context = QgsReadWriteContext() - error = '' + error = "" self.assertTrue( layer.writeSymbology( elem, doc, error, context, QgsMapLayer.StyleCategory.Rendering ) ) - layer2 = QgsTiledSceneLayer('uri2', 'my layer 2', 'tiled_mesh') + layer2 = QgsTiledSceneLayer("uri2", "my layer 2", "tiled_mesh") layer2.readSymbology(elem, error, context) # only rendering properties should be applied self.assertEqual(layer2.opacity(), 0.25) @@ -125,9 +133,10 @@ def test_read_write_symbology(self): self.assertTrue(layer2.hasScaleBasedVisibility()) # these should be unchanged - self.assertEqual(layer2.blendMode(), - QPainter.CompositionMode.CompositionMode_SourceOver) - self.assertFalse(layer2.customProperty('prop')) + self.assertEqual( + layer2.blendMode(), QPainter.CompositionMode.CompositionMode_SourceOver + ) + self.assertFalse(layer2.customProperty("prop")) self.assertFalse(QgsLayerNotesUtils.layerNotes(layer2)) # try restoring layer notes when these were not writing originally @@ -136,30 +145,38 @@ def test_read_write_symbology(self): # write layer notes and restore self.assertTrue( - layer.writeSymbology(elem, doc, error, context, QgsMapLayer.StyleCategory.Notes)) + layer.writeSymbology( + elem, doc, error, context, QgsMapLayer.StyleCategory.Notes + ) + ) layer2.readSymbology(elem, error, context, QgsMapLayer.StyleCategory.Notes) - self.assertEqual(QgsLayerNotesUtils.layerNotes(layer2), 'my notes') + self.assertEqual(QgsLayerNotesUtils.layerNotes(layer2), "my notes") def test_cesium_provider_metadata(self): """ Test cesium provider metadata methods """ self.assertIn( - 'cesiumtiles', - QgsProviderRegistry.instance().providersForLayerType(Qgis.LayerType.TiledScene) + "cesiumtiles", + QgsProviderRegistry.instance().providersForLayerType( + Qgis.LayerType.TiledScene + ), ) - metadata = QgsProviderRegistry.instance().providerMetadata('cesiumtiles') + metadata = QgsProviderRegistry.instance().providerMetadata("cesiumtiles") self.assertIsNotNone(metadata) - self.assertEqual(metadata.decodeUri('/home/me/test/tileset.json'), - {'file-name': 'tileset.json', 'path': '/home/me/test/tileset.json'}) + self.assertEqual( + metadata.decodeUri("/home/me/test/tileset.json"), + {"file-name": "tileset.json", "path": "/home/me/test/tileset.json"}, + ) self.assertEqual( metadata.encodeUri( - {'file-name': 'tileset.json', 'path': '/home/me/test/tileset.json'} + {"file-name": "tileset.json", "path": "/home/me/test/tileset.json"} ), - '/home/me/test/tileset.json') + "/home/me/test/tileset.json", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgstiledscenerender.py b/tests/src/python/test_qgstiledscenerender.py index 62758adb8cf0..a7169f0290d6 100644 --- a/tests/src/python/test_qgstiledscenerender.py +++ b/tests/src/python/test_qgstiledscenerender.py @@ -5,6 +5,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + __author__ = "Nyall Dawson" __date__ = "27/06/2023" __copyright__ = "Copyright 2023, The QGIS Project" diff --git a/tests/src/python/test_qgstiledscenerequest.py b/tests/src/python/test_qgstiledscenerequest.py index 3e359ad385a6..f18b228a73e9 100644 --- a/tests/src/python/test_qgstiledscenerequest.py +++ b/tests/src/python/test_qgstiledscenerequest.py @@ -7,18 +7,14 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2023 by Nyall Dawson' -__date__ = '26/07/2023' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "(C) 2023 by Nyall Dawson" +__date__ = "26/07/2023" +__copyright__ = "Copyright 2023, The QGIS Project" import unittest -from qgis.core import ( - Qgis, - QgsTiledSceneRequest, - QgsFeedback, - QgsOrientedBox3D -) +from qgis.core import Qgis, QgsTiledSceneRequest, QgsFeedback, QgsOrientedBox3D from qgis.testing import start_app, QgisTestCase from utilities import unitTestDataPath @@ -32,15 +28,14 @@ class TestQgsTiledSceneRequest(QgisTestCase): def test_basic(self): request = QgsTiledSceneRequest() - self.assertEqual(request.flags(), - Qgis.TiledSceneRequestFlags()) + self.assertEqual(request.flags(), Qgis.TiledSceneRequestFlags()) request.setFlags( Qgis.TiledSceneRequestFlags(Qgis.TiledSceneRequestFlag.NoHierarchyFetch) ) - self.assertEqual(request.flags(), - Qgis.TiledSceneRequestFlags( - Qgis.TiledSceneRequestFlag.NoHierarchyFetch - )) + self.assertEqual( + request.flags(), + Qgis.TiledSceneRequestFlags(Qgis.TiledSceneRequestFlag.NoHierarchyFetch), + ) request.setRequiredGeometricError(1.2) self.assertEqual(request.requiredGeometricError(), 1.2) @@ -50,12 +45,10 @@ def test_basic(self): request.setFeedback(feedback) self.assertEqual(request.feedback(), feedback) - request.setFilterBox( - QgsOrientedBox3D([1, 2, 3], [1, 0, 0, 0, 2, 0, 0, 0, 3]) - ) + request.setFilterBox(QgsOrientedBox3D([1, 2, 3], [1, 0, 0, 0, 2, 0, 0, 0, 3])) self.assertEqual( request.filterBox(), - QgsOrientedBox3D([1, 2, 3], [1, 0, 0, 0, 2, 0, 0, 0, 3]) + QgsOrientedBox3D([1, 2, 3], [1, 0, 0, 0, 2, 0, 0, 0, 3]), ) self.assertEqual(request.parentTileId(), -1) @@ -63,5 +56,5 @@ def test_basic(self): self.assertEqual(request.parentTileId(), 2) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgstiledscenetile.py b/tests/src/python/test_qgstiledscenetile.py index 8b23d6e17dc3..9f3a20d7beb0 100644 --- a/tests/src/python/test_qgstiledscenetile.py +++ b/tests/src/python/test_qgstiledscenetile.py @@ -7,6 +7,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ + __author__ = "(C) 2023 by Nyall Dawson" __date__ = "26/07/2023" __copyright__ = "Copyright 2023, The QGIS Project" @@ -20,7 +21,7 @@ QgsBox3d, QgsMatrix4x4, QgsTiledSceneTile, - QgsOrientedBox3D + QgsOrientedBox3D, ) from qgis.testing import start_app, QgisTestCase @@ -46,9 +47,14 @@ def test_basic(self): node = QgsTiledSceneTile() node.setBoundingVolume( - QgsTiledSceneBoundingVolume(QgsOrientedBox3D.fromBox3D(QgsBox3d(1, 2, 3, 10, 11, 12))) + QgsTiledSceneBoundingVolume( + QgsOrientedBox3D.fromBox3D(QgsBox3d(1, 2, 3, 10, 11, 12)) + ) + ) + self.assertEqual( + node.boundingVolume().box(), + QgsOrientedBox3D([5.5, 6.5, 7.5], [4.5, 0, 0, 0, 4.5, 0, 0, 0, 4.5]), ) - self.assertEqual(node.boundingVolume().box(), QgsOrientedBox3D([5.5, 6.5, 7.5], [4.5, 0, 0, 0, 4.5, 0, 0, 0, 4.5])) node = QgsTiledSceneTile() node.setTransform(QgsMatrix4x4(1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0)) @@ -73,7 +79,9 @@ def test_copy(self): node = QgsTiledSceneTile(11) node.setRefinementProcess(Qgis.TileRefinementProcess.Additive) node.setBoundingVolume( - QgsTiledSceneBoundingVolume(QgsOrientedBox3D.fromBox3D(QgsBox3d(1, 2, 3, 10, 11, 12))) + QgsTiledSceneBoundingVolume( + QgsOrientedBox3D.fromBox3D(QgsBox3d(1, 2, 3, 10, 11, 12)) + ) ) node.setTransform(QgsMatrix4x4(1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0)) node.setResources({"content": "parent"}) @@ -84,7 +92,10 @@ def test_copy(self): self.assertTrue(copy.isValid()) self.assertEqual(copy.id(), 11) self.assertEqual(copy.refinementProcess(), Qgis.TileRefinementProcess.Additive) - self.assertEqual(copy.boundingVolume().box(), QgsOrientedBox3D([5.5, 6.5, 7.5], [4.5, 0, 0, 0, 4.5, 0, 0, 0, 4.5])) + self.assertEqual( + copy.boundingVolume().box(), + QgsOrientedBox3D([5.5, 6.5, 7.5], [4.5, 0, 0, 0, 4.5, 0, 0, 0, 4.5]), + ) self.assertEqual( copy.transform(), QgsMatrix4x4(1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0), @@ -97,7 +108,9 @@ def test_set_transform(self): node = QgsTiledSceneTile() self.assertIsNone(node.transform()) node.setBoundingVolume( - QgsTiledSceneBoundingVolume(QgsOrientedBox3D.fromBox3D(QgsBox3d(1, 2, 3, 10, 11, 12))) + QgsTiledSceneBoundingVolume( + QgsOrientedBox3D.fromBox3D(QgsBox3d(1, 2, 3, 10, 11, 12)) + ) ) node.setTransform(QgsMatrix4x4(1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0)) diff --git a/tests/src/python/test_qgstiles.py b/tests/src/python/test_qgstiles.py index 3aee9f776667..d54cc3f77da2 100644 --- a/tests/src/python/test_qgstiles.py +++ b/tests/src/python/test_qgstiles.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '04/03/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "04/03/2022" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.PyQt.QtCore import QSize from qgis.PyQt.QtXml import QDomDocument @@ -39,7 +40,7 @@ def testQgsTileXYZ(self): def testQgsTileXYZRepr(self): tile = QgsTileXYZ(1, 2, 3) - self.assertEqual(str(tile), '') + self.assertEqual(str(tile), "") def testQgsTileXYZEquality(self): tile = QgsTileXYZ(1, 2, 3) @@ -65,12 +66,14 @@ def testQgsTileRange(self): self.assertFalse(range.isValid()) def testQgsTileMatrix(self): - matrix = QgsTileMatrix.fromCustomDef(5, QgsCoordinateReferenceSystem('EPSG:4326'), QgsPointXY(1, 2), 1000, 4, 8) + matrix = QgsTileMatrix.fromCustomDef( + 5, QgsCoordinateReferenceSystem("EPSG:4326"), QgsPointXY(1, 2), 1000, 4, 8 + ) self.assertEqual(matrix.zoomLevel(), 5) - self.assertEqual(matrix.crs().authid(), 'EPSG:4326') + self.assertEqual(matrix.crs().authid(), "EPSG:4326") - matrix.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) - self.assertEqual(matrix.crs().authid(), 'EPSG:3857') + matrix.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) + self.assertEqual(matrix.crs().authid(), "EPSG:3857") matrix.setZoomLevel(6) self.assertEqual(matrix.zoomLevel(), 6) @@ -82,17 +85,27 @@ def testQgsTileMatrixSet(self): matrix_set = QgsTileMatrixSet() # should be applied by default in order to match MapBox rendering of tiles - self.assertEqual(matrix_set.scaleToTileZoomMethod(), Qgis.ScaleToTileZoomLevelMethod.MapBox) + self.assertEqual( + matrix_set.scaleToTileZoomMethod(), Qgis.ScaleToTileZoomLevelMethod.MapBox + ) self.assertEqual(matrix_set.minimumZoom(), -1) self.assertEqual(matrix_set.maximumZoom(), -1) self.assertFalse(matrix_set.crs().isValid()) matrix_set.addMatrix( - QgsTileMatrix.fromCustomDef(1, QgsCoordinateReferenceSystem('EPSG:4326'), QgsPointXY(1, 2), 1000, 4, 8)) + QgsTileMatrix.fromCustomDef( + 1, + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsPointXY(1, 2), + 1000, + 4, + 8, + ) + ) self.assertEqual(matrix_set.minimumZoom(), 1) self.assertEqual(matrix_set.maximumZoom(), 1) - self.assertEqual(matrix_set.crs().authid(), 'EPSG:4326') + self.assertEqual(matrix_set.crs().authid(), "EPSG:4326") range = QgsTileRange(1, 3, 4, 7) tiles = matrix_set.tilesInRange(range, 1) @@ -103,10 +116,26 @@ def testQgsTileMatrixSet(self): self.assertEqual(max(t.row() for t in tiles), 7) # should not apply any special logic here, and return scales unchanged - self.assertEqual(matrix_set.calculateTileScaleForMap(1000, QgsCoordinateReferenceSystem('EPSG:4326'), - QgsRectangle(0, 2, 20, 12), QSize(20, 10), 96), 1000) - self.assertEqual(matrix_set.calculateTileScaleForMap(1000, QgsCoordinateReferenceSystem('EPSG:3857'), - QgsRectangle(0, 2, 20, 12), QSize(20, 10), 96), 1000) + self.assertEqual( + matrix_set.calculateTileScaleForMap( + 1000, + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsRectangle(0, 2, 20, 12), + QSize(20, 10), + 96, + ), + 1000, + ) + self.assertEqual( + matrix_set.calculateTileScaleForMap( + 1000, + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsRectangle(0, 2, 20, 12), + QSize(20, 10), + 96, + ), + 1000, + ) self.assertEqual(matrix_set.tileMatrix(1).zoomLevel(), 1) # zoom level not present in matrix! @@ -129,10 +158,18 @@ def testQgsTileMatrixSet(self): # add a second level matrix_set.addMatrix( - QgsTileMatrix.fromCustomDef(2, QgsCoordinateReferenceSystem('EPSG:4326'), QgsPointXY(1, 2), 1000, 4, 8)) + QgsTileMatrix.fromCustomDef( + 2, + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsPointXY(1, 2), + 1000, + 4, + 8, + ) + ) self.assertEqual(matrix_set.minimumZoom(), 1) self.assertEqual(matrix_set.maximumZoom(), 2) - self.assertEqual(matrix_set.crs().authid(), 'EPSG:4326') + self.assertEqual(matrix_set.crs().authid(), "EPSG:4326") self.assertEqual(matrix_set.tileMatrix(1).zoomLevel(), 1) self.assertEqual(matrix_set.tileMatrix(2).zoomLevel(), 2) @@ -169,10 +206,18 @@ def testQgsTileMatrixSet(self): # add a third level matrix_set.addMatrix( - QgsTileMatrix.fromCustomDef(3, QgsCoordinateReferenceSystem('EPSG:4326'), QgsPointXY(1, 2), 1000, 4, 8)) + QgsTileMatrix.fromCustomDef( + 3, + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsPointXY(1, 2), + 1000, + 4, + 8, + ) + ) self.assertEqual(matrix_set.minimumZoom(), 1) self.assertEqual(matrix_set.maximumZoom(), 3) - self.assertEqual(matrix_set.crs().authid(), 'EPSG:4326') + self.assertEqual(matrix_set.crs().authid(), "EPSG:4326") self.assertEqual(matrix_set.tileMatrix(1).zoomLevel(), 1) self.assertEqual(matrix_set.tileMatrix(2).zoomLevel(), 2) @@ -200,7 +245,9 @@ def testQgsTileMatrixSet(self): # with ESRI scale to zoom handling matrix_set.setScaleToTileZoomMethod(Qgis.ScaleToTileZoomLevelMethod.Esri) - self.assertEqual(matrix_set.scaleToTileZoomMethod(), Qgis.ScaleToTileZoomLevelMethod.Esri) + self.assertEqual( + matrix_set.scaleToTileZoomMethod(), Qgis.ScaleToTileZoomLevelMethod.Esri + ) self.assertAlmostEqual(matrix_set.scaleToZoom(776503144), 1, 5) self.assertEqual(matrix_set.scaleToZoom(1776503144), 1) @@ -239,11 +286,19 @@ def testTileMatrixSetGoogle(self): self.assertTrue(matrix_set.rootMatrix().isRootTileMatrix()) self.assertEqual(matrix_set.rootMatrix().matrixWidth(), 1) self.assertEqual(matrix_set.rootMatrix().matrixHeight(), 1) - self.assertEqual(matrix_set.rootMatrix().crs().authid(), 'EPSG:3857') - self.assertAlmostEqual(matrix_set.rootMatrix().extent().xMinimum(), -20037508.3427892, 3) - self.assertAlmostEqual(matrix_set.rootMatrix().extent().xMaximum(), 20037508.3427892, 3) - self.assertAlmostEqual(matrix_set.rootMatrix().extent().yMinimum(), -20037508.3427892, 3) - self.assertAlmostEqual(matrix_set.rootMatrix().extent().yMaximum(), 20037508.3427892, 3) + self.assertEqual(matrix_set.rootMatrix().crs().authid(), "EPSG:3857") + self.assertAlmostEqual( + matrix_set.rootMatrix().extent().xMinimum(), -20037508.3427892, 3 + ) + self.assertAlmostEqual( + matrix_set.rootMatrix().extent().xMaximum(), 20037508.3427892, 3 + ) + self.assertAlmostEqual( + matrix_set.rootMatrix().extent().yMinimum(), -20037508.3427892, 3 + ) + self.assertAlmostEqual( + matrix_set.rootMatrix().extent().yMaximum(), 20037508.3427892, 3 + ) def testTileMatrixSetRemoveTiles(self): matrix_set = QgsTileMatrixSet() @@ -256,13 +311,46 @@ def testTileMatrixSetRemoveTiles(self): def testReadWriteXml(self): matrix_set = QgsTileMatrixSet() matrix_set.addMatrix( - QgsTileMatrix.fromCustomDef(1, QgsCoordinateReferenceSystem('EPSG:4326'), QgsPointXY(1, 2), 1000, 4, 8)) + QgsTileMatrix.fromCustomDef( + 1, + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsPointXY(1, 2), + 1000, + 4, + 8, + ) + ) matrix_set.addMatrix( - QgsTileMatrix.fromCustomDef(2, QgsCoordinateReferenceSystem('EPSG:4326'), QgsPointXY(1, 2), 1000, 4, 8)) + QgsTileMatrix.fromCustomDef( + 2, + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsPointXY(1, 2), + 1000, + 4, + 8, + ) + ) matrix_set.addMatrix( - QgsTileMatrix.fromCustomDef(3, QgsCoordinateReferenceSystem('EPSG:3857'), QgsPointXY(1, 2), 1000, 4, 8)) - - matrix_set.setRootMatrix(QgsTileMatrix.fromCustomDef(0, QgsCoordinateReferenceSystem('EPSG:3857'), QgsPointXY(1, 2), 1000, 1, 1)) + QgsTileMatrix.fromCustomDef( + 3, + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsPointXY(1, 2), + 1000, + 4, + 8, + ) + ) + + matrix_set.setRootMatrix( + QgsTileMatrix.fromCustomDef( + 0, + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsPointXY(1, 2), + 1000, + 1, + 1, + ) + ) doc = QDomDocument("testdoc") res = matrix_set.writeXml(doc, QgsReadWriteContext()) @@ -272,11 +360,11 @@ def testReadWriteXml(self): self.assertEqual(set2.minimumZoom(), 1) self.assertEqual(set2.maximumZoom(), 3) - self.assertEqual(set2.tileMatrix(1).crs().authid(), 'EPSG:4326') - self.assertEqual(set2.tileMatrix(2).crs().authid(), 'EPSG:4326') - self.assertEqual(set2.tileMatrix(3).crs().authid(), 'EPSG:3857') + self.assertEqual(set2.tileMatrix(1).crs().authid(), "EPSG:4326") + self.assertEqual(set2.tileMatrix(2).crs().authid(), "EPSG:4326") + self.assertEqual(set2.tileMatrix(3).crs().authid(), "EPSG:3857") - self.assertEqual(set2.rootMatrix().crs().authid(), 'EPSG:3857') + self.assertEqual(set2.rootMatrix().crs().authid(), "EPSG:3857") self.assertTrue(set2.rootMatrix().isRootTileMatrix()) self.assertAlmostEqual(set2.rootMatrix().extent().xMinimum(), 1, 3) self.assertAlmostEqual(set2.rootMatrix().extent().xMaximum(), 1001, 3) @@ -287,11 +375,35 @@ def testVectorTileMatrixSet(self): matrix_set = QgsVectorTileMatrixSet() matrix_set.addMatrix( - QgsTileMatrix.fromCustomDef(1, QgsCoordinateReferenceSystem('EPSG:4326'), QgsPointXY(1, 2), 1000, 4, 8)) + QgsTileMatrix.fromCustomDef( + 1, + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsPointXY(1, 2), + 1000, + 4, + 8, + ) + ) matrix_set.addMatrix( - QgsTileMatrix.fromCustomDef(2, QgsCoordinateReferenceSystem('EPSG:4326'), QgsPointXY(1, 2), 1000, 4, 8)) + QgsTileMatrix.fromCustomDef( + 2, + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsPointXY(1, 2), + 1000, + 4, + 8, + ) + ) matrix_set.addMatrix( - QgsTileMatrix.fromCustomDef(3, QgsCoordinateReferenceSystem('EPSG:3857'), QgsPointXY(1, 2), 1000, 4, 8)) + QgsTileMatrix.fromCustomDef( + 3, + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsPointXY(1, 2), + 1000, + 4, + 8, + ) + ) doc = QDomDocument("testdoc") res = matrix_set.writeXml(doc, QgsReadWriteContext()) @@ -301,34 +413,26 @@ def testVectorTileMatrixSet(self): self.assertEqual(set2.minimumZoom(), 1) self.assertEqual(set2.maximumZoom(), 3) - self.assertEqual(set2.tileMatrix(1).crs().authid(), 'EPSG:4326') - self.assertEqual(set2.tileMatrix(2).crs().authid(), 'EPSG:4326') - self.assertEqual(set2.tileMatrix(3).crs().authid(), 'EPSG:3857') + self.assertEqual(set2.tileMatrix(1).crs().authid(), "EPSG:4326") + self.assertEqual(set2.tileMatrix(2).crs().authid(), "EPSG:4326") + self.assertEqual(set2.tileMatrix(3).crs().authid(), "EPSG:3857") def testVectorTileMatrixSetFromESRI(self): esri_metadata = { - "tiles": [ - "tile/{z}/{y}/{x}.pbf" - ], + "tiles": ["tile/{z}/{y}/{x}.pbf"], "initialExtent": { "xmin": -2750565.3405000009, "ymin": -936638.5, "xmax": 3583872.5, "ymax": 4659267, - "spatialReference": { - "wkid": 3978, - "latestWkid": 3978 - } + "spatialReference": {"wkid": 3978, "latestWkid": 3978}, }, "fullExtent": { "xmin": -2750565.3405000009, "ymin": -936638.5, "xmax": 3583872.5, "ymax": 4659267, - "spatialReference": { - "wkid": 3978, - "latestWkid": 3978 - } + "spatialReference": {"wkid": 3978, "latestWkid": 3978}, }, "minScale": 511647836.79182798, "maxScale": 31228.505663563719, @@ -337,91 +441,85 @@ def testVectorTileMatrixSetFromESRI(self): "cols": 512, "dpi": 96, "format": "pbf", - "origin": { - "x": -34655613.478699818, - "y": 38474944.644759327 - }, - "spatialReference": { - "wkid": 3978, - "latestWkid": 3978 - }, + "origin": {"x": -34655613.478699818, "y": 38474944.644759327}, + "spatialReference": {"wkid": 3978, "latestWkid": 3978}, "lods": [ { "level": 0, "resolution": 135373.49015117117, - "scale": 511647836.79182798 + "scale": 511647836.79182798, }, { "level": 1, "resolution": 67686.745075585583, - "scale": 255823918.39591399 + "scale": 255823918.39591399, }, { "level": 2, "resolution": 33843.372537792791, - "scale": 127911959.19795699 + "scale": 127911959.19795699, }, { "level": 3, "resolution": 16921.686268896396, - "scale": 63955979.598978497 + "scale": 63955979.598978497, }, { "level": 4, "resolution": 8460.8431344481978, - "scale": 31977989.799489249 + "scale": 31977989.799489249, }, { "level": 5, "resolution": 4230.4215672240989, - "scale": 15988994.899744624 + "scale": 15988994.899744624, }, { "level": 6, "resolution": 2115.2107836120495, - "scale": 7994497.4498723121 + "scale": 7994497.4498723121, }, { "level": 7, "resolution": 1057.6053918060247, - "scale": 3997248.7249361561 + "scale": 3997248.7249361561, }, { "level": 8, "resolution": 528.80269590301236, - "scale": 1998624.362468078 + "scale": 1998624.362468078, }, { "level": 9, "resolution": 264.40134795150618, - "scale": 999312.18123403902 + "scale": 999312.18123403902, }, { "level": 10, "resolution": 132.20067397575309, - "scale": 499656.09061701951 + "scale": 499656.09061701951, }, { "level": 11, "resolution": 66.100336987876545, - "scale": 249828.04530850975 + "scale": 249828.04530850975, }, { "level": 12, "resolution": 33.050168493938273, - "scale": 124914.02265425488 + "scale": 124914.02265425488, }, { "level": 13, "resolution": 16.525084246969136, - "scale": 62457.011327127439 + "scale": 62457.011327127439, }, { "level": 14, "resolution": 8.2625421234845682, - "scale": 31228.505663563719 - } - ] + "scale": 31228.505663563719, + }, + ], }, "maxzoom": 14, "minLOD": 0, @@ -430,12 +528,9 @@ def testVectorTileMatrixSetFromESRI(self): "styleVersion": 8, "tileCompression": "gzip", "cacheInfo": { - "storageInfo": { - "packetSize": 128, - "storageFormat": "compactV2" - } - } - } + "storageInfo": {"packetSize": 128, "storageFormat": "compactV2"} + }, + }, } vector_tile_set = QgsVectorTileMatrixSet() @@ -443,20 +538,49 @@ def testVectorTileMatrixSetFromESRI(self): self.assertTrue(vector_tile_set.fromEsriJson(esri_metadata)) # should not apply any special logic here for non-geographic CRS, and return scales unchanged - self.assertEqual(vector_tile_set.calculateTileScaleForMap(1000, QgsCoordinateReferenceSystem('EPSG:3857'), - QgsRectangle(0, 2, 20, 12), QSize(20, 10), 96), 1000) + self.assertEqual( + vector_tile_set.calculateTileScaleForMap( + 1000, + QgsCoordinateReferenceSystem("EPSG:3857"), + QgsRectangle(0, 2, 20, 12), + QSize(20, 10), + 96, + ), + 1000, + ) # for geographic CRS the scale should be calculated using the scale at the equator. # see https://support.esri.com/en/technical-article/000007211, # https://gis.stackexchange.com/questions/33270/how-does-arcmap-calculate-scalebar-inside-a-wgs84-layout - self.assertAlmostEqual(vector_tile_set.calculateTileScaleForMap(420735075, QgsCoordinateReferenceSystem('EPSG:4326'), - QgsRectangle(0, 2, 20, 12), QSize(2000, 1000), 96), 4207351, 0) - self.assertAlmostEqual(vector_tile_set.calculateTileScaleForMap(420735075, QgsCoordinateReferenceSystem('EPSG:4326'), - QgsRectangle(0, 62, 20, 72), QSize(2000, 1000), 96), 4207351, 0) + self.assertAlmostEqual( + vector_tile_set.calculateTileScaleForMap( + 420735075, + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsRectangle(0, 2, 20, 12), + QSize(2000, 1000), + 96, + ), + 4207351, + 0, + ) + self.assertAlmostEqual( + vector_tile_set.calculateTileScaleForMap( + 420735075, + QgsCoordinateReferenceSystem("EPSG:4326"), + QgsRectangle(0, 62, 20, 72), + QSize(2000, 1000), + 96, + ), + 4207351, + 0, + ) # we should NOT apply the tile scale doubling hack to ESRI tiles, otherwise our scales # are double what ESRI use for the same tile sets - self.assertEqual(vector_tile_set.scaleToTileZoomMethod(), Qgis.ScaleToTileZoomLevelMethod.Esri) + self.assertEqual( + vector_tile_set.scaleToTileZoomMethod(), + Qgis.ScaleToTileZoomLevelMethod.Esri, + ) self.assertEqual(vector_tile_set.minimumZoom(), 0) self.assertEqual(vector_tile_set.maximumZoom(), 14) @@ -464,21 +588,43 @@ def testVectorTileMatrixSetFromESRI(self): self.assertTrue(vector_tile_set.rootMatrix().isRootTileMatrix()) self.assertEqual(vector_tile_set.rootMatrix().matrixWidth(), 1) self.assertEqual(vector_tile_set.rootMatrix().matrixHeight(), 1) - self.assertEqual(vector_tile_set.rootMatrix().crs().authid(), 'EPSG:3978') - self.assertAlmostEqual(vector_tile_set.rootMatrix().extent().xMinimum(), -34655613.47869982, 3) - self.assertAlmostEqual(vector_tile_set.rootMatrix().extent().xMaximum(), 34655613.47869982, 3) - self.assertAlmostEqual(vector_tile_set.rootMatrix().extent().yMinimum(), -30836282.31264031, 3) - self.assertAlmostEqual(vector_tile_set.rootMatrix().extent().yMaximum(), 38474944.64475933, 3) - - self.assertEqual(vector_tile_set.crs().authid(), 'EPSG:3978') - self.assertAlmostEqual(vector_tile_set.tileMatrix(0).extent().xMinimum(), -34655613.47869982, 3) - self.assertAlmostEqual(vector_tile_set.tileMatrix(0).extent().yMinimum(), -30836282.31264031, 3) - self.assertAlmostEqual(vector_tile_set.tileMatrix(0).extent().xMaximum(), 34655613.47869982, 3) - self.assertAlmostEqual(vector_tile_set.tileMatrix(0).extent().yMaximum(), 38474944.64475933, 3) - - self.assertAlmostEqual(vector_tile_set.tileMatrix(0).scale(), 511647836.791828, 5) - self.assertAlmostEqual(vector_tile_set.tileMatrix(1).scale(), 255823918.395914, 5) - self.assertAlmostEqual(vector_tile_set.tileMatrix(2).scale(), 127911959.197957, 5) + self.assertEqual(vector_tile_set.rootMatrix().crs().authid(), "EPSG:3978") + self.assertAlmostEqual( + vector_tile_set.rootMatrix().extent().xMinimum(), -34655613.47869982, 3 + ) + self.assertAlmostEqual( + vector_tile_set.rootMatrix().extent().xMaximum(), 34655613.47869982, 3 + ) + self.assertAlmostEqual( + vector_tile_set.rootMatrix().extent().yMinimum(), -30836282.31264031, 3 + ) + self.assertAlmostEqual( + vector_tile_set.rootMatrix().extent().yMaximum(), 38474944.64475933, 3 + ) + + self.assertEqual(vector_tile_set.crs().authid(), "EPSG:3978") + self.assertAlmostEqual( + vector_tile_set.tileMatrix(0).extent().xMinimum(), -34655613.47869982, 3 + ) + self.assertAlmostEqual( + vector_tile_set.tileMatrix(0).extent().yMinimum(), -30836282.31264031, 3 + ) + self.assertAlmostEqual( + vector_tile_set.tileMatrix(0).extent().xMaximum(), 34655613.47869982, 3 + ) + self.assertAlmostEqual( + vector_tile_set.tileMatrix(0).extent().yMaximum(), 38474944.64475933, 3 + ) + + self.assertAlmostEqual( + vector_tile_set.tileMatrix(0).scale(), 511647836.791828, 5 + ) + self.assertAlmostEqual( + vector_tile_set.tileMatrix(1).scale(), 255823918.395914, 5 + ) + self.assertAlmostEqual( + vector_tile_set.tileMatrix(2).scale(), 127911959.197957, 5 + ) def test_esri_with_tilemap(self): """ @@ -492,29 +638,21 @@ def test_esri_with_tilemap(self): "type": "indexedVector", "tileMap": "tilemap", "defaultStyles": "resources/styles", - "tiles": [ - "tile/{z}/{y}/{x}.pbf" - ], + "tiles": ["tile/{z}/{y}/{x}.pbf"], "exportTilesAllowed": False, "initialExtent": { "xmin": 4.5783729072156216, "ymin": 46.874323689779565, "xmax": 16.331358957713661, "ymax": 55.452061808267452, - "spatialReference": { - "wkid": 4326, - "latestWkid": 4326 - } + "spatialReference": {"wkid": 4326, "latestWkid": 4326}, }, "fullExtent": { "xmin": 4.5783729072156216, "ymin": 46.874323689779565, "xmax": 16.331358957713661, "ymax": 55.452061808267452, - "spatialReference": { - "wkid": 4326, - "latestWkid": 4326 - } + "spatialReference": {"wkid": 4326, "latestWkid": 4326}, }, "minScale": 295828763.79585469, "maxScale": 564.24858817263544, @@ -523,116 +661,98 @@ def test_esri_with_tilemap(self): "cols": 512, "dpi": 96, "format": "pbf", - "origin": { - "x": -180, - "y": 90 - }, - "spatialReference": { - "wkid": 4326, - "latestWkid": 4326 - }, + "origin": {"x": -180, "y": 90}, + "spatialReference": {"wkid": 4326, "latestWkid": 4326}, "lods": [ - { - "level": 0, - "resolution": 0.703125, - "scale": 295828763.79585469 - }, - { - "level": 1, - "resolution": 0.3515625, - "scale": 147914381.89792734 - }, - { - "level": 2, - "resolution": 0.17578125, - "scale": 73957190.948963672 - }, + {"level": 0, "resolution": 0.703125, "scale": 295828763.79585469}, + {"level": 1, "resolution": 0.3515625, "scale": 147914381.89792734}, + {"level": 2, "resolution": 0.17578125, "scale": 73957190.948963672}, { "level": 3, "resolution": 0.087890625, - "scale": 36978595.474481836 + "scale": 36978595.474481836, }, { "level": 4, "resolution": 0.0439453125, - "scale": 18489297.737240918 + "scale": 18489297.737240918, }, { "level": 5, "resolution": 0.02197265625, - "scale": 9244648.868620459 + "scale": 9244648.868620459, }, { "level": 6, "resolution": 0.010986328125, - "scale": 4622324.4343102295 + "scale": 4622324.4343102295, }, { "level": 7, "resolution": 0.0054931640625, - "scale": 2311162.2171551147 + "scale": 2311162.2171551147, }, { "level": 8, "resolution": 0.00274658203125, - "scale": 1155581.1085775574 + "scale": 1155581.1085775574, }, { "level": 9, "resolution": 0.001373291015625, - "scale": 577790.55428877869 + "scale": 577790.55428877869, }, { "level": 10, "resolution": 0.0006866455078125, - "scale": 288895.27714438934 + "scale": 288895.27714438934, }, { "level": 11, "resolution": 0.00034332275390625, - "scale": 144447.63857219467 + "scale": 144447.63857219467, }, { "level": 12, "resolution": 0.000171661376953125, - "scale": 72223.819286097336 + "scale": 72223.819286097336, }, { "level": 13, "resolution": 8.58306884765625e-05, - "scale": 36111.909643048668 + "scale": 36111.909643048668, }, { "level": 14, "resolution": 4.291534423828125e-05, - "scale": 18055.954821524334 + "scale": 18055.954821524334, }, { "level": 15, "resolution": 2.1457672119140625e-05, - "scale": 9027.977410762167 + "scale": 9027.977410762167, }, { "level": 16, "resolution": 1.0728836059570312e-05, - "scale": 4513.9887053810835 + "scale": 4513.9887053810835, }, { "level": 17, "resolution": 5.3644180297851562e-06, - "scale": 2256.9943526905417 + "scale": 2256.9943526905417, }, { "level": 18, "resolution": 2.6822090148925781e-06, - "scale": 1128.4971763452709 + "scale": 1128.4971763452709, }, { "level": 19, "resolution": 1.3411045074462891e-06, - "scale": 564.24858817263544 - } - ] + "scale": 564.24858817263544, + }, + ], }, "maxzoom": 19, "minLOD": 0, @@ -641,25 +761,98 @@ def test_esri_with_tilemap(self): "styleVersion": 8, "tileCompression": "gzip", "cacheInfo": { - "storageInfo": { - "packetSize": 128, - "storageFormat": "compactV2" - } - } - } + "storageInfo": {"packetSize": 128, "storageFormat": "compactV2"} + }, + }, } - tilemap = {"index": [0, [[[0, 0, [0, 0, 0, [[0, 0, [0, [1, 1, [ - [0, 1, 0, [1, 1, 1, 1]], - [[1, 1, 1, 1], [1, 1, 1, [1, 1, 1, 1]], [1, 1, 1, 1], - [[1, 1, 1, 1], [1, [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]], - 1, [1, 1, 1, 1]]], 1, 1], [[[1, 1, 1, 1], [1, 1, 1, 1], [ - [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]], - [1, 1, 1, 1], [1, 1, 1, 1], 1], [[1, 1, 1, 1], 1, 1, 1]], - [1, 1, [1, 1, 1, 1], 1], - [[1, [1, 1, 1, 1], 0, 1], 1, 0, - 0], 1]], 0, 0], 0], 0, 0, 0]], - 0], 0, 0, 0], 0, 0, 0], 0, 0] + tilemap = { + "index": [ + 0, + [ + [ + [ + 0, + 0, + [ + 0, + 0, + 0, + [ + [ + 0, + 0, + [ + 0, + [ + 1, + 1, + [ + [0, 1, 0, [1, 1, 1, 1]], + [ + [1, 1, 1, 1], + [1, 1, 1, [1, 1, 1, 1]], + [1, 1, 1, 1], + [ + [1, 1, 1, 1], + [ + 1, + [1, 1, 1, 1], + [1, 1, 1, 1], + [1, 1, 1, 1], + ], + 1, + [1, 1, 1, 1], + ], + ], + 1, + 1, + ], + [ + [ + [1, 1, 1, 1], + [1, 1, 1, 1], + [ + [ + [1, 1, 1, 1], + [1, 1, 1, 1], + [1, 1, 1, 1], + [1, 1, 1, 1], + ], + [1, 1, 1, 1], + [1, 1, 1, 1], + 1, + ], + [[1, 1, 1, 1], 1, 1, 1], + ], + [1, 1, [1, 1, 1, 1], 1], + [[1, [1, 1, 1, 1], 0, 1], 1, 0, 0], + 1, + ], + ], + 0, + 0, + ], + 0, + ], + 0, + 0, + 0, + ], + ], + 0, + ], + 0, + 0, + 0, + ], + 0, + 0, + 0, + ], + 0, + 0, + ] } vector_tile_set_orig = QgsVectorTileMatrixSet() @@ -675,18 +868,25 @@ def test_esri_with_tilemap(self): # zoom level not available self.assertEqual( vector_tile_set.tileAvailability(QgsTileXYZ(0, 0, 101)), - Qgis.TileAvailability.NotAvailable) + Qgis.TileAvailability.NotAvailable, + ) # zoom level 0 self.assertEqual(vector_tile_set.tileMatrix(0).matrixWidth(), 1) self.assertEqual(vector_tile_set.tileMatrix(0).matrixHeight(), 1) - self.assertEqual(vector_tile_set.tileAvailability(QgsTileXYZ(0, 0, 0)), - Qgis.TileAvailability.Available) + self.assertEqual( + vector_tile_set.tileAvailability(QgsTileXYZ(0, 0, 0)), + Qgis.TileAvailability.Available, + ) # tile outside matrix - self.assertEqual(vector_tile_set.tileAvailability(QgsTileXYZ(1, 0, 0)), - Qgis.TileAvailability.NotAvailable) - self.assertEqual(vector_tile_set.tileAvailability(QgsTileXYZ(0, 1, 0)), - Qgis.TileAvailability.NotAvailable) + self.assertEqual( + vector_tile_set.tileAvailability(QgsTileXYZ(1, 0, 0)), + Qgis.TileAvailability.NotAvailable, + ) + self.assertEqual( + vector_tile_set.tileAvailability(QgsTileXYZ(0, 1, 0)), + Qgis.TileAvailability.NotAvailable, + ) tiles = vector_tile_set.tilesInRange(QgsTileRange(0, 0, 0, 0), 0) self.assertEqual(tiles, [QgsTileXYZ(0, 0, 0)]) @@ -694,14 +894,22 @@ def test_esri_with_tilemap(self): # zoom level 1 self.assertEqual(vector_tile_set.tileMatrix(1).matrixWidth(), 2) self.assertEqual(vector_tile_set.tileMatrix(1).matrixHeight(), 2) - self.assertEqual(vector_tile_set.tileAvailability(QgsTileXYZ(0, 0, 1)), - Qgis.TileAvailability.NotAvailable) - self.assertEqual(vector_tile_set.tileAvailability(QgsTileXYZ(1, 0, 1)), - Qgis.TileAvailability.Available) - self.assertEqual(vector_tile_set.tileAvailability(QgsTileXYZ(0, 1, 1)), - Qgis.TileAvailability.NotAvailable) - self.assertEqual(vector_tile_set.tileAvailability(QgsTileXYZ(1, 1, 1)), - Qgis.TileAvailability.NotAvailable) + self.assertEqual( + vector_tile_set.tileAvailability(QgsTileXYZ(0, 0, 1)), + Qgis.TileAvailability.NotAvailable, + ) + self.assertEqual( + vector_tile_set.tileAvailability(QgsTileXYZ(1, 0, 1)), + Qgis.TileAvailability.Available, + ) + self.assertEqual( + vector_tile_set.tileAvailability(QgsTileXYZ(0, 1, 1)), + Qgis.TileAvailability.NotAvailable, + ) + self.assertEqual( + vector_tile_set.tileAvailability(QgsTileXYZ(1, 1, 1)), + Qgis.TileAvailability.NotAvailable, + ) tiles = vector_tile_set.tilesInRange(QgsTileRange(0, 1, 0, 1), 1) self.assertEqual(tiles, [QgsTileXYZ(1, 0, 1)]) @@ -718,8 +926,8 @@ def test_esri_with_tilemap(self): expected = Qgis.TileAvailability.NotAvailable self.assertEqual( - vector_tile_set.tileAvailability(QgsTileXYZ(col, row, 2)), - expected) + vector_tile_set.tileAvailability(QgsTileXYZ(col, row, 2)), expected + ) tiles = vector_tile_set.tilesInRange(QgsTileRange(0, 2, 0, 2), 2) self.assertEqual(tiles, [QgsTileXYZ(2, 0, 2)]) @@ -735,8 +943,8 @@ def test_esri_with_tilemap(self): expected = Qgis.TileAvailability.NotAvailable self.assertEqual( - vector_tile_set.tileAvailability(QgsTileXYZ(col, row, 3)), - expected) + vector_tile_set.tileAvailability(QgsTileXYZ(col, row, 3)), expected + ) tiles = vector_tile_set.tilesInRange(QgsTileRange(0, 7, 0, 7), 3) self.assertEqual(tiles, [QgsTileXYZ(4, 0, 3)]) @@ -752,8 +960,11 @@ def test_esri_with_tilemap(self): expected = Qgis.TileAvailability.NotAvailable tile = QgsTileXYZ(col, row, 4) - self.assertEqual(vector_tile_set.tileAvailability(tile), - expected, msg=f'Failed for {tile}') + self.assertEqual( + vector_tile_set.tileAvailability(tile), + expected, + msg=f"Failed for {tile}", + ) tiles = vector_tile_set.tilesInRange(QgsTileRange(0, 15, 0, 15), 4) self.assertEqual(tiles, [QgsTileXYZ(8, 1, 4)]) @@ -769,8 +980,11 @@ def test_esri_with_tilemap(self): expected = Qgis.TileAvailability.NotAvailable tile = QgsTileXYZ(col, row, 5) - self.assertEqual(vector_tile_set.tileAvailability(tile), - expected, msg=f'Failed for {tile}') + self.assertEqual( + vector_tile_set.tileAvailability(tile), + expected, + msg=f"Failed for {tile}", + ) tiles = vector_tile_set.tilesInRange(QgsTileRange(0, 31, 0, 31), 5) self.assertEqual(tiles, [QgsTileXYZ(17, 3, 5)]) @@ -786,8 +1000,11 @@ def test_esri_with_tilemap(self): expected = Qgis.TileAvailability.NotAvailable tile = QgsTileXYZ(col, row, 6) - self.assertEqual(vector_tile_set.tileAvailability(tile), - expected, msg=f'Failed for {tile}') + self.assertEqual( + vector_tile_set.tileAvailability(tile), + expected, + msg=f"Failed for {tile}", + ) tiles = vector_tile_set.tilesInRange(QgsTileRange(0, 63, 0, 63), 6) self.assertEqual(tiles, [QgsTileXYZ(34, 6, 6)]) @@ -803,8 +1020,11 @@ def test_esri_with_tilemap(self): expected = Qgis.TileAvailability.NotAvailable tile = QgsTileXYZ(col, row, 7) - self.assertEqual(vector_tile_set.tileAvailability(tile), - expected, msg=f'Failed for {tile}') + self.assertEqual( + vector_tile_set.tileAvailability(tile), + expected, + msg=f"Failed for {tile}", + ) tiles = vector_tile_set.tilesInRange(QgsTileRange(0, 127, 0, 127), 7) self.assertEqual(tiles, [QgsTileXYZ(68, 13, 7)]) @@ -820,8 +1040,11 @@ def test_esri_with_tilemap(self): expected = Qgis.TileAvailability.NotAvailable tile = QgsTileXYZ(col, row, 8) - self.assertEqual(vector_tile_set.tileAvailability(tile), - expected, msg=f'Failed for {tile}') + self.assertEqual( + vector_tile_set.tileAvailability(tile), + expected, + msg=f"Failed for {tile}", + ) tiles = vector_tile_set.tilesInRange(QgsTileRange(0, 255, 0, 255), 8) self.assertEqual(tiles, [QgsTileXYZ(137, 26, 8)]) @@ -839,14 +1062,22 @@ def test_esri_with_tilemap(self): expected = Qgis.TileAvailability.NotAvailable tile = QgsTileXYZ(col, row, 9) - self.assertEqual(vector_tile_set.tileAvailability(tile), - expected, msg=f'Failed for {tile}') + self.assertEqual( + vector_tile_set.tileAvailability(tile), + expected, + msg=f"Failed for {tile}", + ) tiles = vector_tile_set.tilesInRange(QgsTileRange(0, 511, 0, 511), 9) - self.assertCountEqual(tiles, [QgsTileXYZ(274, 52, 9), - QgsTileXYZ(275, 52, 9), - QgsTileXYZ(274, 53, 9), - QgsTileXYZ(275, 53, 9)]) + self.assertCountEqual( + tiles, + [ + QgsTileXYZ(274, 52, 9), + QgsTileXYZ(275, 52, 9), + QgsTileXYZ(274, 53, 9), + QgsTileXYZ(275, 53, 9), + ], + ) # zoom level 10 self.assertEqual(vector_tile_set.tileMatrix(10).matrixWidth(), 1024) @@ -855,8 +1086,9 @@ def test_esri_with_tilemap(self): for row in range(1024): if col in (548, 549, 550, 551) and row in (104, 105): expected = Qgis.TileAvailability.UseLowerZoomLevelTile - elif (col in (548, 549, 550, 551) and row == 106) \ - or (col == 550 and row == 107): + elif (col in (548, 549, 550, 551) and row == 106) or ( + col == 550 and row == 107 + ): expected = Qgis.TileAvailability.Available elif col in (548, 549, 551) and row == 107: expected = Qgis.TileAvailability.AvailableNoChildren @@ -864,48 +1096,66 @@ def test_esri_with_tilemap(self): expected = Qgis.TileAvailability.NotAvailable tile = QgsTileXYZ(col, row, 10) - self.assertEqual(vector_tile_set.tileAvailability(tile), - expected, msg=f'Failed for {tile}') + self.assertEqual( + vector_tile_set.tileAvailability(tile), + expected, + msg=f"Failed for {tile}", + ) tiles = vector_tile_set.tilesInRange(QgsTileRange(0, 1023, 0, 1023), 10) # we want to see the zoom level 9 tiles here, as the tilemap indicates # that they should be used instead of zoom level 10 tiles for their # extents - self.assertCountEqual(tiles, [QgsTileXYZ(274, 52, 9), - QgsTileXYZ(275, 52, 9), - QgsTileXYZ(548, 106, 10), - QgsTileXYZ(549, 106, 10), - QgsTileXYZ(550, 106, 10), - QgsTileXYZ(551, 106, 10), - QgsTileXYZ(548, 107, 10), - QgsTileXYZ(549, 107, 10), - QgsTileXYZ(550, 107, 10), - QgsTileXYZ(551, 107, 10)]) + self.assertCountEqual( + tiles, + [ + QgsTileXYZ(274, 52, 9), + QgsTileXYZ(275, 52, 9), + QgsTileXYZ(548, 106, 10), + QgsTileXYZ(549, 106, 10), + QgsTileXYZ(550, 106, 10), + QgsTileXYZ(551, 106, 10), + QgsTileXYZ(548, 107, 10), + QgsTileXYZ(549, 107, 10), + QgsTileXYZ(550, 107, 10), + QgsTileXYZ(551, 107, 10), + ], + ) # zoom level 11 self.assertEqual(vector_tile_set.tileMatrix(11).matrixWidth(), 2048) self.assertEqual(vector_tile_set.tileMatrix(11).matrixHeight(), 2048) for col in range(2048): for row in range(2048): - if (col in (1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103) - and row in (208, 209, 210, 211)) \ - or (col in (1096, 1097, 1098, 1099, 1102, 1103) and row in (214, 215)): + if ( + col in (1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103) + and row in (208, 209, 210, 211) + ) or ( + col in (1096, 1097, 1098, 1099, 1102, 1103) and row in (214, 215) + ): expected = Qgis.TileAvailability.UseLowerZoomLevelTile - elif (col in (1098, 1099, 1100, 1101) and row == 212) \ - or (col == 1100 and row == 214) \ - or (col in (1097, 1098, 1099, 1100, 1101, 1102) and row == 213): + elif ( + (col in (1098, 1099, 1100, 1101) and row == 212) + or (col == 1100 and row == 214) + or (col in (1097, 1098, 1099, 1100, 1101, 1102) and row == 213) + ): expected = Qgis.TileAvailability.Available - elif (col in (1096, 1097, 1098, 1099, 1100, 1101) and row == 214) \ - or (col in (1097, 1102, 1103) and row == 212)\ - or (col == 1103 and row == 213): + elif ( + (col in (1096, 1097, 1098, 1099, 1100, 1101) and row == 214) + or (col in (1097, 1102, 1103) and row == 212) + or (col == 1103 and row == 213) + ): expected = Qgis.TileAvailability.AvailableNoChildren else: expected = Qgis.TileAvailability.NotAvailable tile = QgsTileXYZ(col, row, 11) - self.assertEqual(vector_tile_set.tileAvailability(tile), - expected, msg=f'Failed for {tile}') + self.assertEqual( + vector_tile_set.tileAvailability(tile), + expected, + msg=f"Failed for {tile}", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgstreewidgetitem.py b/tests/src/python/test_qgstreewidgetitem.py index 075ffd08d212..1a3ab4ca5dd2 100644 --- a/tests/src/python/test_qgstreewidgetitem.py +++ b/tests/src/python/test_qgstreewidgetitem.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '12/07/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "12/07/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.core import NULL @@ -19,6 +20,7 @@ try: from qgis.PyQt.QtTest import QSignalSpy + use_signal_spy = True except: use_signal_spy = False @@ -29,17 +31,17 @@ class TestQgsTreeWidgetItem(QgisTestCase): def testGettersSetters(self): - """ test getters and setters """ + """test getters and setters""" i = QgsTreeWidgetItem() # sort data should be empty by default self.assertEqual(i.sortData(0), NULL) - i.setSortData(0, '5') - self.assertEqual(i.sortData(0), '5') + i.setSortData(0, "5") + self.assertEqual(i.sortData(0), "5") self.assertEqual(i.sortData(1), NULL) - i.setSortData(1, 'a') - self.assertEqual(i.sortData(0), '5') - self.assertEqual(i.sortData(1), 'a') + i.setSortData(1, "a") + self.assertEqual(i.sortData(0), "5") + self.assertEqual(i.sortData(1), "a") # should not be always on top by default self.assertEqual(i.alwaysOnTopPriority(), -1) @@ -47,19 +49,19 @@ def testGettersSetters(self): self.assertEqual(i.alwaysOnTopPriority(), 1) def testSort(self): - """ test sort logic """ + """test sort logic""" w = QTreeWidget() i1 = QgsTreeWidgetItem(w) i2 = QgsTreeWidgetItem(w) # should default to search by display text - i1.setText(0, '2') - i1.setText(1, 'b') - i1.setText(2, 'c') - i2.setText(0, '1') - i2.setText(1, 'a') - i2.setText(2, 'd') + i1.setText(0, "2") + i1.setText(1, "b") + i1.setText(2, "c") + i2.setText(0, "1") + i2.setText(1, "a") + i2.setText(2, "d") w.sortItems(0, Qt.SortOrder.AscendingOrder) self.assertEqual(i1 < i2, False) @@ -72,41 +74,41 @@ def testSort(self): self.assertEqual(i2 < i1, False) # sortData should take precedence over display text - i1.setText(1, '2') - i1.setSortData(1, '200') - i2.setText(1, '3') + i1.setText(1, "2") + i1.setSortData(1, "200") + i2.setText(1, "3") w.sortItems(1, Qt.SortOrder.AscendingOrder) self.assertEqual(i1 < i2, False) self.assertEqual(i2 < i1, True) - i2.setSortData(1, '300') + i2.setSortData(1, "300") self.assertEqual(i1 < i2, True) self.assertEqual(i2 < i1, False) # test that nulls are sorted before other values - i1.setSortData(0, '2') + i1.setSortData(0, "2") i2.setSortData(0, NULL) w.sortItems(0, Qt.SortOrder.AscendingOrder) self.assertEqual(i1 < i2, False) self.assertEqual(i2 < i1, True) # test numeric sorting - i1.setSortData(0, '02') - i2.setSortData(0, '005') + i1.setSortData(0, "02") + i2.setSortData(0, "005") w.sortItems(0, Qt.SortOrder.AscendingOrder) self.assertEqual(i1 < i2, True) self.assertEqual(i2 < i1, False) # numbers should come first - i2.setSortData(0, 'a') + i2.setSortData(0, "a") self.assertEqual(i1 < i2, True) self.assertEqual(i2 < i1, False) - i1.setSortData(0, 'a') - i2.setSortData(0, '5') + i1.setSortData(0, "a") + i2.setSortData(0, "5") self.assertEqual(i1 < i2, False) self.assertEqual(i2 < i1, True) # always on top items should be first - i1.setSortData(0, 'a') - i2.setSortData(0, 'b') + i1.setSortData(0, "a") + i2.setSortData(0, "b") i2.setAlwaysOnTopPriority(5) self.assertEqual(i1 < i2, False) self.assertEqual(i2 < i1, True) @@ -115,7 +117,7 @@ def testSort(self): self.assertEqual(i2 < i1, False) # otherwise fall back to sort order i2.setAlwaysOnTopPriority(3) - i1.setSortData(0, 'c') + i1.setSortData(0, "c") self.assertEqual(i1 < i2, False) self.assertEqual(i2 < i1, True) @@ -124,15 +126,15 @@ class TestQgsTreeWidgetItemObject(QgisTestCase): @unittest.skipIf(not use_signal_spy, "No QSignalSpy available") def testItemEdited(self): - """ test that itemEdited signal is correctly emitted""" + """test that itemEdited signal is correctly emitted""" i = QgsTreeWidgetItemObject() item_edited_spy = QSignalSpy(i.itemEdited) - i.setData(1, Qt.ItemDataRole.EditRole, 'a') + i.setData(1, Qt.ItemDataRole.EditRole, "a") self.assertEqual(len(item_edited_spy), 1) - i.setData(1, Qt.ItemDataRole.EditRole, 'b') + i.setData(1, Qt.ItemDataRole.EditRole, "b") self.assertEqual(len(item_edited_spy), 2) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgstriangulatedsurface.py b/tests/src/python/test_qgstriangulatedsurface.py index f58f08e2db5f..ba3a5461eca7 100644 --- a/tests/src/python/test_qgstriangulatedsurface.py +++ b/tests/src/python/test_qgstriangulatedsurface.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Jean Felder' -__date__ = '12/08/2024' -__copyright__ = 'Copyright 2024, The QGIS Project' + +__author__ = "Jean Felder" +__date__ = "12/08/2024" +__copyright__ = "Copyright 2024, The QGIS Project" import qgis # NOQA @@ -34,7 +35,7 @@ def test_constructor(self): def test_wkt(self): # 2D surface = QgsTriangulatedSurface() - surface.fromWkt('TIN (((0 0,0 1,1 0,0 0)),((1 0,0 1,1 1,1 0)))') + surface.fromWkt("TIN (((0 0,0 1,1 0,0 0)),((1 0,0 1,1 1,1 0)))") self.assertFalse(surface.isEmpty()) self.assertEqual(surface.numPatches(), 2) self.assertFalse(surface.is3D()) @@ -47,7 +48,7 @@ def test_wkt(self): # 3D surfaceZ = QgsTriangulatedSurface() - surfaceZ.fromWkt('TIN Z (((0 0 0,0 1 0,1 1 0,0 0 0)))') + surfaceZ.fromWkt("TIN Z (((0 0 0,0 1 0,1 1 0,0 0 0)))") self.assertFalse(surfaceZ.isEmpty()) self.assertEqual(surfaceZ.numPatches(), 1) self.assertTrue(surfaceZ.is3D()) @@ -60,7 +61,7 @@ def test_wkt(self): # Measure surfaceM = QgsTriangulatedSurface() - surfaceM.fromWkt('TIN M (((0 0 3,0 1 3,1 1 3,0 0 3)))') + surfaceM.fromWkt("TIN M (((0 0 3,0 1 3,1 1 3,0 0 3)))") self.assertFalse(surfaceM.isEmpty()) self.assertEqual(surfaceM.numPatches(), 1) self.assertFalse(surfaceM.is3D()) @@ -73,9 +74,11 @@ def test_wkt(self): # ZM surfaceZM = QgsTriangulatedSurface() - surfaceZM.fromWkt('TIN ZM ' - '(((0 0 1 2,0 1 1 2,1 1 1 2,0 0 1 2)),' - '((10 10 0 0,10 11 0 0,11 11 0 0,10 10 0 0)))') + surfaceZM.fromWkt( + "TIN ZM " + "(((0 0 1 2,0 1 1 2,1 1 1 2,0 0 1 2))," + "((10 10 0 0,10 11 0 0,11 11 0 0,10 10 0 0)))" + ) self.assertFalse(surfaceZM.isEmpty()) self.assertEqual(surfaceZM.numPatches(), 2) self.assertTrue(surfaceZM.is3D()) @@ -111,5 +114,5 @@ def test_patch(self): self.assertFalse(surface.isMeasure()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsunittypes.py b/tests/src/python/test_qgsunittypes.py index 58de71d13234..abfb8891ce43 100644 --- a/tests/src/python/test_qgsunittypes.py +++ b/tests/src/python/test_qgsunittypes.py @@ -5,15 +5,13 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '03.02.2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "03.02.2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtCore import QLocale -from qgis.core import ( - Qgis, - QgsUnitTypes -) +from qgis.core import Qgis, QgsUnitTypes from qgis.testing import unittest @@ -27,11 +25,13 @@ def setUp(self): def testEncodeDecodeUnitType(self): """Test encoding and decoding unit type""" - units = [QgsUnitTypes.UnitType.TypeDistance, - QgsUnitTypes.UnitType.TypeArea, - QgsUnitTypes.UnitType.TypeVolume, - QgsUnitTypes.UnitType.TypeTemporal, - QgsUnitTypes.UnitType.TypeUnknown] + units = [ + QgsUnitTypes.UnitType.TypeDistance, + QgsUnitTypes.UnitType.TypeArea, + QgsUnitTypes.UnitType.TypeVolume, + QgsUnitTypes.UnitType.TypeTemporal, + QgsUnitTypes.UnitType.TypeUnknown, + ] for u in units: res, ok = QgsUnitTypes.decodeUnitType(QgsUnitTypes.encodeUnitType(u)) @@ -39,125 +39,127 @@ def testEncodeDecodeUnitType(self): self.assertEqual(res, u) # Test decoding bad units - res, ok = QgsUnitTypes.decodeUnitType('bad') + res, ok = QgsUnitTypes.decodeUnitType("bad") self.assertFalse(ok) self.assertEqual(res, QgsUnitTypes.UnitType.TypeUnknown) # Test that string is cleaned before decoding - res, ok = QgsUnitTypes.decodeUnitType(' volUme ') + res, ok = QgsUnitTypes.decodeUnitType(" volUme ") assert ok self.assertEqual(res, QgsUnitTypes.UnitType.TypeVolume) def testDistanceUnitType(self): - """Test QgsUnitTypes::unitType() """ - expected = {QgsUnitTypes.DistanceUnit.DistanceMeters: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.DistanceUnit.DistanceKilometers: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.DistanceUnit.DistanceFeet: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.DistanceUnit.DistanceYards: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.DistanceUnit.DistanceMiles: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.DistanceUnit.DistanceDegrees: QgsUnitTypes.DistanceUnitType.Geographic, - QgsUnitTypes.DistanceUnit.DistanceCentimeters: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.DistanceUnit.DistanceMillimeters: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.DistanceUnit.DistanceUnknownUnit: QgsUnitTypes.DistanceUnitType.UnknownType, - QgsUnitTypes.DistanceUnit.DistanceNauticalMiles: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.Inches: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.ChainsInternational: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.ChainsBritishBenoit1895A: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.ChainsBritishBenoit1895B: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.ChainsBritishSears1922Truncated: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.ChainsBritishSears1922: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.ChainsClarkes: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.ChainsUSSurvey: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.FeetBritish1865: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.FeetBritish1936: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.FeetBritishBenoit1895A: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.FeetBritishBenoit1895B: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.FeetBritishSears1922Truncated: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.FeetBritishSears1922: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.FeetClarkes: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.FeetGoldCoast: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.FeetIndian: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.FeetIndian1937: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.FeetIndian1962: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.FeetIndian1975: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.FeetUSSurvey: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.LinksInternational: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.LinksBritishBenoit1895A: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.LinksBritishBenoit1895B: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.LinksBritishSears1922Truncated: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.LinksBritishSears1922: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.LinksClarkes: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.LinksUSSurvey: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.YardsBritishBenoit1895A: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.YardsBritishBenoit1895B: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.YardsBritishSears1922Truncated: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.YardsBritishSears1922: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.YardsClarkes: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.YardsIndian: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.YardsIndian1937: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.YardsIndian1962: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.YardsIndian1975: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.MilesUSSurvey: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.Fathoms: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.DistanceUnit.MetersGermanLegal: QgsUnitTypes.DistanceUnitType.Standard, - } + """Test QgsUnitTypes::unitType()""" + expected = { + QgsUnitTypes.DistanceUnit.DistanceMeters: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.DistanceUnit.DistanceKilometers: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.DistanceUnit.DistanceFeet: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.DistanceUnit.DistanceYards: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.DistanceUnit.DistanceMiles: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.DistanceUnit.DistanceDegrees: QgsUnitTypes.DistanceUnitType.Geographic, + QgsUnitTypes.DistanceUnit.DistanceCentimeters: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.DistanceUnit.DistanceMillimeters: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.DistanceUnit.DistanceUnknownUnit: QgsUnitTypes.DistanceUnitType.UnknownType, + QgsUnitTypes.DistanceUnit.DistanceNauticalMiles: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.Inches: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.ChainsInternational: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.ChainsBritishBenoit1895A: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.ChainsBritishBenoit1895B: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.ChainsBritishSears1922Truncated: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.ChainsBritishSears1922: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.ChainsClarkes: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.ChainsUSSurvey: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.FeetBritish1865: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.FeetBritish1936: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.FeetBritishBenoit1895A: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.FeetBritishBenoit1895B: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.FeetBritishSears1922Truncated: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.FeetBritishSears1922: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.FeetClarkes: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.FeetGoldCoast: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.FeetIndian: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.FeetIndian1937: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.FeetIndian1962: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.FeetIndian1975: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.FeetUSSurvey: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.LinksInternational: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.LinksBritishBenoit1895A: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.LinksBritishBenoit1895B: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.LinksBritishSears1922Truncated: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.LinksBritishSears1922: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.LinksClarkes: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.LinksUSSurvey: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.YardsBritishBenoit1895A: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.YardsBritishBenoit1895B: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.YardsBritishSears1922Truncated: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.YardsBritishSears1922: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.YardsClarkes: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.YardsIndian: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.YardsIndian1937: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.YardsIndian1962: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.YardsIndian1975: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.MilesUSSurvey: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.Fathoms: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.DistanceUnit.MetersGermanLegal: QgsUnitTypes.DistanceUnitType.Standard, + } for t in list(expected.keys()): self.assertEqual(QgsUnitTypes.unitType(t), expected[t]) def testEncodeDecodeDistanceUnits(self): """Test encoding and decoding distance units""" - units = [QgsUnitTypes.DistanceUnit.DistanceMeters, - QgsUnitTypes.DistanceUnit.DistanceKilometers, - QgsUnitTypes.DistanceUnit.DistanceFeet, - QgsUnitTypes.DistanceUnit.DistanceYards, - QgsUnitTypes.DistanceUnit.DistanceMiles, - QgsUnitTypes.DistanceUnit.DistanceDegrees, - QgsUnitTypes.DistanceUnit.DistanceCentimeters, - QgsUnitTypes.DistanceUnit.DistanceMillimeters, - QgsUnitTypes.DistanceUnit.DistanceUnknownUnit, - QgsUnitTypes.DistanceUnit.DistanceNauticalMiles, - Qgis.DistanceUnit.Inches, - Qgis.DistanceUnit.ChainsInternational, - Qgis.DistanceUnit.ChainsBritishBenoit1895A, - Qgis.DistanceUnit.ChainsBritishBenoit1895B, - Qgis.DistanceUnit.ChainsBritishSears1922Truncated, - Qgis.DistanceUnit.ChainsBritishSears1922, - Qgis.DistanceUnit.ChainsClarkes, - Qgis.DistanceUnit.ChainsUSSurvey, - Qgis.DistanceUnit.FeetBritish1865, - Qgis.DistanceUnit.FeetBritish1936, - Qgis.DistanceUnit.FeetBritishBenoit1895A, - Qgis.DistanceUnit.FeetBritishBenoit1895B, - Qgis.DistanceUnit.FeetBritishSears1922Truncated, - Qgis.DistanceUnit.FeetBritishSears1922, - Qgis.DistanceUnit.FeetClarkes, - Qgis.DistanceUnit.FeetGoldCoast, - Qgis.DistanceUnit.FeetIndian, - Qgis.DistanceUnit.FeetIndian1937, - Qgis.DistanceUnit.FeetIndian1962, - Qgis.DistanceUnit.FeetIndian1975, - Qgis.DistanceUnit.FeetUSSurvey, - Qgis.DistanceUnit.LinksInternational, - Qgis.DistanceUnit.LinksBritishBenoit1895A, - Qgis.DistanceUnit.LinksBritishBenoit1895B, - Qgis.DistanceUnit.LinksBritishSears1922Truncated, - Qgis.DistanceUnit.LinksBritishSears1922, - Qgis.DistanceUnit.LinksClarkes, - Qgis.DistanceUnit.LinksUSSurvey, - Qgis.DistanceUnit.YardsBritishBenoit1895A, - Qgis.DistanceUnit.YardsBritishBenoit1895B, - Qgis.DistanceUnit.YardsBritishSears1922Truncated, - Qgis.DistanceUnit.YardsBritishSears1922, - Qgis.DistanceUnit.YardsClarkes, - Qgis.DistanceUnit.YardsIndian, - Qgis.DistanceUnit.YardsIndian1937, - Qgis.DistanceUnit.YardsIndian1962, - Qgis.DistanceUnit.YardsIndian1975, - Qgis.DistanceUnit.MilesUSSurvey, - Qgis.DistanceUnit.Fathoms, - Qgis.DistanceUnit.MetersGermanLegal, - ] + units = [ + QgsUnitTypes.DistanceUnit.DistanceMeters, + QgsUnitTypes.DistanceUnit.DistanceKilometers, + QgsUnitTypes.DistanceUnit.DistanceFeet, + QgsUnitTypes.DistanceUnit.DistanceYards, + QgsUnitTypes.DistanceUnit.DistanceMiles, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + QgsUnitTypes.DistanceUnit.DistanceCentimeters, + QgsUnitTypes.DistanceUnit.DistanceMillimeters, + QgsUnitTypes.DistanceUnit.DistanceUnknownUnit, + QgsUnitTypes.DistanceUnit.DistanceNauticalMiles, + Qgis.DistanceUnit.Inches, + Qgis.DistanceUnit.ChainsInternational, + Qgis.DistanceUnit.ChainsBritishBenoit1895A, + Qgis.DistanceUnit.ChainsBritishBenoit1895B, + Qgis.DistanceUnit.ChainsBritishSears1922Truncated, + Qgis.DistanceUnit.ChainsBritishSears1922, + Qgis.DistanceUnit.ChainsClarkes, + Qgis.DistanceUnit.ChainsUSSurvey, + Qgis.DistanceUnit.FeetBritish1865, + Qgis.DistanceUnit.FeetBritish1936, + Qgis.DistanceUnit.FeetBritishBenoit1895A, + Qgis.DistanceUnit.FeetBritishBenoit1895B, + Qgis.DistanceUnit.FeetBritishSears1922Truncated, + Qgis.DistanceUnit.FeetBritishSears1922, + Qgis.DistanceUnit.FeetClarkes, + Qgis.DistanceUnit.FeetGoldCoast, + Qgis.DistanceUnit.FeetIndian, + Qgis.DistanceUnit.FeetIndian1937, + Qgis.DistanceUnit.FeetIndian1962, + Qgis.DistanceUnit.FeetIndian1975, + Qgis.DistanceUnit.FeetUSSurvey, + Qgis.DistanceUnit.LinksInternational, + Qgis.DistanceUnit.LinksBritishBenoit1895A, + Qgis.DistanceUnit.LinksBritishBenoit1895B, + Qgis.DistanceUnit.LinksBritishSears1922Truncated, + Qgis.DistanceUnit.LinksBritishSears1922, + Qgis.DistanceUnit.LinksClarkes, + Qgis.DistanceUnit.LinksUSSurvey, + Qgis.DistanceUnit.YardsBritishBenoit1895A, + Qgis.DistanceUnit.YardsBritishBenoit1895B, + Qgis.DistanceUnit.YardsBritishSears1922Truncated, + Qgis.DistanceUnit.YardsBritishSears1922, + Qgis.DistanceUnit.YardsClarkes, + Qgis.DistanceUnit.YardsIndian, + Qgis.DistanceUnit.YardsIndian1937, + Qgis.DistanceUnit.YardsIndian1962, + Qgis.DistanceUnit.YardsIndian1975, + Qgis.DistanceUnit.MilesUSSurvey, + Qgis.DistanceUnit.Fathoms, + Qgis.DistanceUnit.MetersGermanLegal, + ] for u in units: res, ok = QgsUnitTypes.decodeDistanceUnit(QgsUnitTypes.encodeUnit(u)) @@ -165,120 +167,130 @@ def testEncodeDecodeDistanceUnits(self): self.assertEqual(res, u) # Test decoding bad units - res, ok = QgsUnitTypes.decodeDistanceUnit('bad') + res, ok = QgsUnitTypes.decodeDistanceUnit("bad") self.assertFalse(ok) self.assertEqual(res, QgsUnitTypes.DistanceUnit.DistanceUnknownUnit) # Test that string is cleaned before decoding - res, ok = QgsUnitTypes.decodeDistanceUnit(' FeEt ') + res, ok = QgsUnitTypes.decodeDistanceUnit(" FeEt ") assert ok self.assertEqual(res, QgsUnitTypes.DistanceUnit.DistanceFeet) def testDistanceUnitsToFromString(self): """Test converting distance units to and from translated strings""" - units = [QgsUnitTypes.DistanceUnit.DistanceMeters, - QgsUnitTypes.DistanceUnit.DistanceKilometers, - QgsUnitTypes.DistanceUnit.DistanceFeet, - QgsUnitTypes.DistanceUnit.DistanceYards, - QgsUnitTypes.DistanceUnit.DistanceMiles, - QgsUnitTypes.DistanceUnit.DistanceDegrees, - QgsUnitTypes.DistanceUnit.DistanceCentimeters, - QgsUnitTypes.DistanceUnit.DistanceMillimeters, - QgsUnitTypes.DistanceUnit.DistanceUnknownUnit, - QgsUnitTypes.DistanceUnit.DistanceNauticalMiles, - Qgis.DistanceUnit.Inches, - Qgis.DistanceUnit.ChainsInternational, - Qgis.DistanceUnit.ChainsBritishBenoit1895A, - Qgis.DistanceUnit.ChainsBritishBenoit1895B, - Qgis.DistanceUnit.ChainsBritishSears1922Truncated, - Qgis.DistanceUnit.ChainsBritishSears1922, - Qgis.DistanceUnit.ChainsClarkes, - Qgis.DistanceUnit.ChainsUSSurvey, - Qgis.DistanceUnit.FeetBritish1865, - Qgis.DistanceUnit.FeetBritish1936, - Qgis.DistanceUnit.FeetBritishBenoit1895A, - Qgis.DistanceUnit.FeetBritishBenoit1895B, - Qgis.DistanceUnit.FeetBritishSears1922Truncated, - Qgis.DistanceUnit.FeetBritishSears1922, - Qgis.DistanceUnit.FeetClarkes, - Qgis.DistanceUnit.FeetGoldCoast, - Qgis.DistanceUnit.FeetIndian, - Qgis.DistanceUnit.FeetIndian1937, - Qgis.DistanceUnit.FeetIndian1962, - Qgis.DistanceUnit.FeetIndian1975, - Qgis.DistanceUnit.FeetUSSurvey, - Qgis.DistanceUnit.LinksInternational, - Qgis.DistanceUnit.LinksBritishBenoit1895A, - Qgis.DistanceUnit.LinksBritishBenoit1895B, - Qgis.DistanceUnit.LinksBritishSears1922Truncated, - Qgis.DistanceUnit.LinksBritishSears1922, - Qgis.DistanceUnit.LinksClarkes, - Qgis.DistanceUnit.LinksUSSurvey, - Qgis.DistanceUnit.YardsBritishBenoit1895A, - Qgis.DistanceUnit.YardsBritishBenoit1895B, - Qgis.DistanceUnit.YardsBritishSears1922Truncated, - Qgis.DistanceUnit.YardsBritishSears1922, - Qgis.DistanceUnit.YardsClarkes, - Qgis.DistanceUnit.YardsIndian, - Qgis.DistanceUnit.YardsIndian1937, - Qgis.DistanceUnit.YardsIndian1962, - Qgis.DistanceUnit.YardsIndian1975, - Qgis.DistanceUnit.MilesUSSurvey, - Qgis.DistanceUnit.Fathoms, - Qgis.DistanceUnit.MetersGermanLegal, - ] + units = [ + QgsUnitTypes.DistanceUnit.DistanceMeters, + QgsUnitTypes.DistanceUnit.DistanceKilometers, + QgsUnitTypes.DistanceUnit.DistanceFeet, + QgsUnitTypes.DistanceUnit.DistanceYards, + QgsUnitTypes.DistanceUnit.DistanceMiles, + QgsUnitTypes.DistanceUnit.DistanceDegrees, + QgsUnitTypes.DistanceUnit.DistanceCentimeters, + QgsUnitTypes.DistanceUnit.DistanceMillimeters, + QgsUnitTypes.DistanceUnit.DistanceUnknownUnit, + QgsUnitTypes.DistanceUnit.DistanceNauticalMiles, + Qgis.DistanceUnit.Inches, + Qgis.DistanceUnit.ChainsInternational, + Qgis.DistanceUnit.ChainsBritishBenoit1895A, + Qgis.DistanceUnit.ChainsBritishBenoit1895B, + Qgis.DistanceUnit.ChainsBritishSears1922Truncated, + Qgis.DistanceUnit.ChainsBritishSears1922, + Qgis.DistanceUnit.ChainsClarkes, + Qgis.DistanceUnit.ChainsUSSurvey, + Qgis.DistanceUnit.FeetBritish1865, + Qgis.DistanceUnit.FeetBritish1936, + Qgis.DistanceUnit.FeetBritishBenoit1895A, + Qgis.DistanceUnit.FeetBritishBenoit1895B, + Qgis.DistanceUnit.FeetBritishSears1922Truncated, + Qgis.DistanceUnit.FeetBritishSears1922, + Qgis.DistanceUnit.FeetClarkes, + Qgis.DistanceUnit.FeetGoldCoast, + Qgis.DistanceUnit.FeetIndian, + Qgis.DistanceUnit.FeetIndian1937, + Qgis.DistanceUnit.FeetIndian1962, + Qgis.DistanceUnit.FeetIndian1975, + Qgis.DistanceUnit.FeetUSSurvey, + Qgis.DistanceUnit.LinksInternational, + Qgis.DistanceUnit.LinksBritishBenoit1895A, + Qgis.DistanceUnit.LinksBritishBenoit1895B, + Qgis.DistanceUnit.LinksBritishSears1922Truncated, + Qgis.DistanceUnit.LinksBritishSears1922, + Qgis.DistanceUnit.LinksClarkes, + Qgis.DistanceUnit.LinksUSSurvey, + Qgis.DistanceUnit.YardsBritishBenoit1895A, + Qgis.DistanceUnit.YardsBritishBenoit1895B, + Qgis.DistanceUnit.YardsBritishSears1922Truncated, + Qgis.DistanceUnit.YardsBritishSears1922, + Qgis.DistanceUnit.YardsClarkes, + Qgis.DistanceUnit.YardsIndian, + Qgis.DistanceUnit.YardsIndian1937, + Qgis.DistanceUnit.YardsIndian1962, + Qgis.DistanceUnit.YardsIndian1975, + Qgis.DistanceUnit.MilesUSSurvey, + Qgis.DistanceUnit.Fathoms, + Qgis.DistanceUnit.MetersGermanLegal, + ] for u in units: res, ok = QgsUnitTypes.stringToDistanceUnit(QgsUnitTypes.toString(u)) - self.assertTrue(ok, f'QgsUnitTypes.stringToDistanceUnit failed for {u.name}') + self.assertTrue( + ok, f"QgsUnitTypes.stringToDistanceUnit failed for {u.name}" + ) self.assertEqual(res, u) # Test converting bad strings - res, ok = QgsUnitTypes.stringToDistanceUnit('bad') + res, ok = QgsUnitTypes.stringToDistanceUnit("bad") self.assertFalse(ok) self.assertEqual(res, QgsUnitTypes.DistanceUnit.DistanceUnknownUnit) # Test that string is cleaned before conversion - res, ok = QgsUnitTypes.stringToDistanceUnit(f' {QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceFeet).upper()} ') - print(f' {QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceFeet).upper()} ') + res, ok = QgsUnitTypes.stringToDistanceUnit( + f" {QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceFeet).upper()} " + ) + print( + f" {QgsUnitTypes.toString(QgsUnitTypes.DistanceUnit.DistanceFeet).upper()} " + ) assert ok self.assertEqual(res, QgsUnitTypes.DistanceUnit.DistanceFeet) def testAreaUnitType(self): - """Test QgsUnitTypes::unitType() for area units """ - expected = {QgsUnitTypes.AreaUnit.AreaSquareMeters: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.AreaUnit.AreaSquareKilometers: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.AreaUnit.AreaSquareFeet: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.AreaUnit.AreaSquareYards: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.AreaUnit.AreaSquareMiles: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.AreaUnit.AreaHectares: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.AreaUnit.AreaAcres: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.AreaUnit.AreaSquareNauticalMiles: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.AreaUnit.AreaSquareDegrees: QgsUnitTypes.DistanceUnitType.Geographic, - QgsUnitTypes.AreaUnit.AreaSquareCentimeters: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.AreaUnit.AreaSquareMillimeters: QgsUnitTypes.DistanceUnitType.Standard, - Qgis.AreaUnit.SquareInches: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.AreaUnit.AreaUnknownUnit: QgsUnitTypes.DistanceUnitType.UnknownType, - } + """Test QgsUnitTypes::unitType() for area units""" + expected = { + QgsUnitTypes.AreaUnit.AreaSquareMeters: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.AreaUnit.AreaSquareKilometers: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.AreaUnit.AreaSquareFeet: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.AreaUnit.AreaSquareYards: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.AreaUnit.AreaSquareMiles: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.AreaUnit.AreaHectares: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.AreaUnit.AreaAcres: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.AreaUnit.AreaSquareNauticalMiles: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.AreaUnit.AreaSquareDegrees: QgsUnitTypes.DistanceUnitType.Geographic, + QgsUnitTypes.AreaUnit.AreaSquareCentimeters: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.AreaUnit.AreaSquareMillimeters: QgsUnitTypes.DistanceUnitType.Standard, + Qgis.AreaUnit.SquareInches: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.AreaUnit.AreaUnknownUnit: QgsUnitTypes.DistanceUnitType.UnknownType, + } for t in list(expected.keys()): self.assertEqual(QgsUnitTypes.unitType(t), expected[t]) def testEncodeDecodeAreaUnits(self): """Test encoding and decoding area units""" - units = [QgsUnitTypes.AreaUnit.AreaSquareMeters, - QgsUnitTypes.AreaUnit.AreaSquareKilometers, - QgsUnitTypes.AreaUnit.AreaSquareFeet, - QgsUnitTypes.AreaUnit.AreaSquareYards, - QgsUnitTypes.AreaUnit.AreaSquareMiles, - QgsUnitTypes.AreaUnit.AreaHectares, - QgsUnitTypes.AreaUnit.AreaAcres, - QgsUnitTypes.AreaUnit.AreaSquareNauticalMiles, - QgsUnitTypes.AreaUnit.AreaSquareDegrees, - QgsUnitTypes.AreaUnit.AreaSquareCentimeters, - QgsUnitTypes.AreaUnit.AreaSquareMillimeters, - Qgis.AreaUnit.SquareInches, - QgsUnitTypes.AreaUnit.AreaUnknownUnit] + units = [ + QgsUnitTypes.AreaUnit.AreaSquareMeters, + QgsUnitTypes.AreaUnit.AreaSquareKilometers, + QgsUnitTypes.AreaUnit.AreaSquareFeet, + QgsUnitTypes.AreaUnit.AreaSquareYards, + QgsUnitTypes.AreaUnit.AreaSquareMiles, + QgsUnitTypes.AreaUnit.AreaHectares, + QgsUnitTypes.AreaUnit.AreaAcres, + QgsUnitTypes.AreaUnit.AreaSquareNauticalMiles, + QgsUnitTypes.AreaUnit.AreaSquareDegrees, + QgsUnitTypes.AreaUnit.AreaSquareCentimeters, + QgsUnitTypes.AreaUnit.AreaSquareMillimeters, + Qgis.AreaUnit.SquareInches, + QgsUnitTypes.AreaUnit.AreaUnknownUnit, + ] for u in units: res, ok = QgsUnitTypes.decodeAreaUnit(QgsUnitTypes.encodeUnit(u)) @@ -286,30 +298,32 @@ def testEncodeDecodeAreaUnits(self): self.assertEqual(res, u) # Test decoding bad units - res, ok = QgsUnitTypes.decodeAreaUnit('bad') + res, ok = QgsUnitTypes.decodeAreaUnit("bad") self.assertFalse(ok) self.assertEqual(res, QgsUnitTypes.AreaUnit.AreaUnknownUnit) # Test that string is cleaned before decoding - res, ok = QgsUnitTypes.decodeAreaUnit(' Ha ') + res, ok = QgsUnitTypes.decodeAreaUnit(" Ha ") assert ok self.assertEqual(res, QgsUnitTypes.AreaUnit.AreaHectares) def testAreaUnitsToFromString(self): """Test converting area units to and from translated strings""" - units = [QgsUnitTypes.AreaUnit.AreaSquareMeters, - QgsUnitTypes.AreaUnit.AreaSquareKilometers, - QgsUnitTypes.AreaUnit.AreaSquareFeet, - QgsUnitTypes.AreaUnit.AreaSquareYards, - QgsUnitTypes.AreaUnit.AreaSquareMiles, - QgsUnitTypes.AreaUnit.AreaHectares, - QgsUnitTypes.AreaUnit.AreaAcres, - QgsUnitTypes.AreaUnit.AreaSquareNauticalMiles, - QgsUnitTypes.AreaUnit.AreaSquareDegrees, - QgsUnitTypes.AreaUnit.AreaSquareCentimeters, - QgsUnitTypes.AreaUnit.AreaSquareMillimeters, - Qgis.AreaUnit.SquareInches, - QgsUnitTypes.AreaUnit.AreaUnknownUnit] + units = [ + QgsUnitTypes.AreaUnit.AreaSquareMeters, + QgsUnitTypes.AreaUnit.AreaSquareKilometers, + QgsUnitTypes.AreaUnit.AreaSquareFeet, + QgsUnitTypes.AreaUnit.AreaSquareYards, + QgsUnitTypes.AreaUnit.AreaSquareMiles, + QgsUnitTypes.AreaUnit.AreaHectares, + QgsUnitTypes.AreaUnit.AreaAcres, + QgsUnitTypes.AreaUnit.AreaSquareNauticalMiles, + QgsUnitTypes.AreaUnit.AreaSquareDegrees, + QgsUnitTypes.AreaUnit.AreaSquareCentimeters, + QgsUnitTypes.AreaUnit.AreaSquareMillimeters, + Qgis.AreaUnit.SquareInches, + QgsUnitTypes.AreaUnit.AreaUnknownUnit, + ] for u in units: res, ok = QgsUnitTypes.stringToAreaUnit(QgsUnitTypes.toString(u)) @@ -317,46 +331,51 @@ def testAreaUnitsToFromString(self): self.assertEqual(res, u) # Test converting bad strings - res, ok = QgsUnitTypes.stringToAreaUnit('bad') + res, ok = QgsUnitTypes.stringToAreaUnit("bad") self.assertFalse(ok) self.assertEqual(res, QgsUnitTypes.AreaUnit.AreaUnknownUnit) # Test that string is cleaned before conversion - res, ok = QgsUnitTypes.stringToAreaUnit(f' {QgsUnitTypes.toString(QgsUnitTypes.AreaUnit.AreaSquareMiles).upper()} ') + res, ok = QgsUnitTypes.stringToAreaUnit( + f" {QgsUnitTypes.toString(QgsUnitTypes.AreaUnit.AreaSquareMiles).upper()} " + ) assert ok self.assertEqual(res, QgsUnitTypes.AreaUnit.AreaSquareMiles) def testVolumeUnitType(self): - """Test QgsUnitTypes::unitType() for volume units """ - expected = {QgsUnitTypes.VolumeUnit.VolumeCubicMeters: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.VolumeUnit.VolumeCubicFeet: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.VolumeUnit.VolumeCubicYards: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.VolumeUnit.VolumeBarrel: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.VolumeUnit.VolumeCubicDecimeter: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.VolumeUnit.VolumeLiters: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.VolumeUnit.VolumeGallonUS: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.VolumeUnit.VolumeCubicInch: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter: QgsUnitTypes.DistanceUnitType.Standard, - QgsUnitTypes.VolumeUnit.VolumeCubicDegrees: QgsUnitTypes.DistanceUnitType.Geographic, - QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: QgsUnitTypes.DistanceUnitType.UnknownType, - } + """Test QgsUnitTypes::unitType() for volume units""" + expected = { + QgsUnitTypes.VolumeUnit.VolumeCubicMeters: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.VolumeUnit.VolumeCubicFeet: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.VolumeUnit.VolumeCubicYards: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.VolumeUnit.VolumeBarrel: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.VolumeUnit.VolumeCubicDecimeter: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.VolumeUnit.VolumeLiters: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.VolumeUnit.VolumeGallonUS: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.VolumeUnit.VolumeCubicInch: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter: QgsUnitTypes.DistanceUnitType.Standard, + QgsUnitTypes.VolumeUnit.VolumeCubicDegrees: QgsUnitTypes.DistanceUnitType.Geographic, + QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: QgsUnitTypes.DistanceUnitType.UnknownType, + } for t in list(expected.keys()): self.assertEqual(QgsUnitTypes.unitType(t), expected[t]) def testEncodeDecodeVolumeUnits(self): """Test encoding and decoding volume units""" - units = [QgsUnitTypes.VolumeUnit.VolumeCubicMeters, - QgsUnitTypes.VolumeUnit.VolumeCubicFeet, - QgsUnitTypes.VolumeUnit.VolumeCubicYards, - QgsUnitTypes.VolumeUnit.VolumeBarrel, - QgsUnitTypes.VolumeUnit.VolumeCubicDecimeter, - QgsUnitTypes.VolumeUnit.VolumeLiters, - QgsUnitTypes.VolumeUnit.VolumeGallonUS, - QgsUnitTypes.VolumeUnit.VolumeCubicInch, - QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter, - QgsUnitTypes.VolumeUnit.VolumeCubicDegrees, - QgsUnitTypes.VolumeUnit.VolumeUnknownUnit] + units = [ + QgsUnitTypes.VolumeUnit.VolumeCubicMeters, + QgsUnitTypes.VolumeUnit.VolumeCubicFeet, + QgsUnitTypes.VolumeUnit.VolumeCubicYards, + QgsUnitTypes.VolumeUnit.VolumeBarrel, + QgsUnitTypes.VolumeUnit.VolumeCubicDecimeter, + QgsUnitTypes.VolumeUnit.VolumeLiters, + QgsUnitTypes.VolumeUnit.VolumeGallonUS, + QgsUnitTypes.VolumeUnit.VolumeCubicInch, + QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter, + QgsUnitTypes.VolumeUnit.VolumeCubicDegrees, + QgsUnitTypes.VolumeUnit.VolumeUnknownUnit, + ] for u in units: res, ok = QgsUnitTypes.decodeVolumeUnit(QgsUnitTypes.encodeUnit(u)) @@ -364,28 +383,30 @@ def testEncodeDecodeVolumeUnits(self): self.assertEqual(res, u) # Test decoding bad units - res, ok = QgsUnitTypes.decodeVolumeUnit('bad') + res, ok = QgsUnitTypes.decodeVolumeUnit("bad") self.assertFalse(ok) self.assertEqual(res, QgsUnitTypes.VolumeUnit.VolumeUnknownUnit) # Test that string is cleaned before decoding - res, ok = QgsUnitTypes.decodeVolumeUnit(' bbl ') + res, ok = QgsUnitTypes.decodeVolumeUnit(" bbl ") assert ok self.assertEqual(res, QgsUnitTypes.VolumeUnit.VolumeBarrel) def testVolumeUnitsToFromString(self): """Test converting volume units to and from translated strings""" - units = [QgsUnitTypes.VolumeUnit.VolumeCubicMeters, - QgsUnitTypes.VolumeUnit.VolumeCubicFeet, - QgsUnitTypes.VolumeUnit.VolumeCubicYards, - QgsUnitTypes.VolumeUnit.VolumeBarrel, - QgsUnitTypes.VolumeUnit.VolumeCubicDecimeter, - QgsUnitTypes.VolumeUnit.VolumeLiters, - QgsUnitTypes.VolumeUnit.VolumeGallonUS, - QgsUnitTypes.VolumeUnit.VolumeCubicInch, - QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter, - QgsUnitTypes.VolumeUnit.VolumeCubicDegrees, - QgsUnitTypes.VolumeUnit.VolumeUnknownUnit] + units = [ + QgsUnitTypes.VolumeUnit.VolumeCubicMeters, + QgsUnitTypes.VolumeUnit.VolumeCubicFeet, + QgsUnitTypes.VolumeUnit.VolumeCubicYards, + QgsUnitTypes.VolumeUnit.VolumeBarrel, + QgsUnitTypes.VolumeUnit.VolumeCubicDecimeter, + QgsUnitTypes.VolumeUnit.VolumeLiters, + QgsUnitTypes.VolumeUnit.VolumeGallonUS, + QgsUnitTypes.VolumeUnit.VolumeCubicInch, + QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter, + QgsUnitTypes.VolumeUnit.VolumeCubicDegrees, + QgsUnitTypes.VolumeUnit.VolumeUnknownUnit, + ] for u in units: res, ok = QgsUnitTypes.stringToVolumeUnit(QgsUnitTypes.toString(u)) @@ -393,29 +414,33 @@ def testVolumeUnitsToFromString(self): self.assertEqual(res, u) # Test converting bad strings - res, ok = QgsUnitTypes.stringToVolumeUnit('bad') + res, ok = QgsUnitTypes.stringToVolumeUnit("bad") self.assertFalse(ok) self.assertEqual(res, QgsUnitTypes.VolumeUnit.VolumeUnknownUnit) # Test that string is cleaned before conversion - res, ok = QgsUnitTypes.stringToVolumeUnit(f' {QgsUnitTypes.toString(QgsUnitTypes.VolumeUnit.VolumeBarrel).upper()} ') + res, ok = QgsUnitTypes.stringToVolumeUnit( + f" {QgsUnitTypes.toString(QgsUnitTypes.VolumeUnit.VolumeBarrel).upper()} " + ) assert ok self.assertEqual(res, QgsUnitTypes.VolumeUnit.VolumeBarrel) def testEncodeDecodeTemporalUnits(self): """Test encoding and decoding temporal units""" - units = [QgsUnitTypes.TemporalUnit.TemporalMilliseconds, - QgsUnitTypes.TemporalUnit.TemporalSeconds, - QgsUnitTypes.TemporalUnit.TemporalMinutes, - QgsUnitTypes.TemporalUnit.TemporalHours, - QgsUnitTypes.TemporalUnit.TemporalDays, - QgsUnitTypes.TemporalUnit.TemporalWeeks, - QgsUnitTypes.TemporalUnit.TemporalMonths, - QgsUnitTypes.TemporalUnit.TemporalYears, - QgsUnitTypes.TemporalUnit.TemporalDecades, - QgsUnitTypes.TemporalUnit.TemporalCenturies, - QgsUnitTypes.TemporalUnit.TemporalIrregularStep, - QgsUnitTypes.TemporalUnit.TemporalUnknownUnit] + units = [ + QgsUnitTypes.TemporalUnit.TemporalMilliseconds, + QgsUnitTypes.TemporalUnit.TemporalSeconds, + QgsUnitTypes.TemporalUnit.TemporalMinutes, + QgsUnitTypes.TemporalUnit.TemporalHours, + QgsUnitTypes.TemporalUnit.TemporalDays, + QgsUnitTypes.TemporalUnit.TemporalWeeks, + QgsUnitTypes.TemporalUnit.TemporalMonths, + QgsUnitTypes.TemporalUnit.TemporalYears, + QgsUnitTypes.TemporalUnit.TemporalDecades, + QgsUnitTypes.TemporalUnit.TemporalCenturies, + QgsUnitTypes.TemporalUnit.TemporalIrregularStep, + QgsUnitTypes.TemporalUnit.TemporalUnknownUnit, + ] for u in units: res, ok = QgsUnitTypes.decodeTemporalUnit(QgsUnitTypes.encodeUnit(u)) @@ -423,29 +448,31 @@ def testEncodeDecodeTemporalUnits(self): self.assertEqual(res, u) # Test decoding bad units - res, ok = QgsUnitTypes.decodeTemporalUnit('bad') + res, ok = QgsUnitTypes.decodeTemporalUnit("bad") self.assertFalse(ok) self.assertEqual(res, QgsUnitTypes.TemporalUnit.TemporalUnknownUnit) # Test that string is cleaned before decoding - res, ok = QgsUnitTypes.decodeTemporalUnit(' min ') + res, ok = QgsUnitTypes.decodeTemporalUnit(" min ") assert ok self.assertEqual(res, QgsUnitTypes.TemporalUnit.TemporalMinutes) def testTemporalUnitsToFromString(self): """Test converting temporal units to and from translated strings""" - units = [QgsUnitTypes.TemporalUnit.TemporalMilliseconds, - QgsUnitTypes.TemporalUnit.TemporalSeconds, - QgsUnitTypes.TemporalUnit.TemporalMinutes, - QgsUnitTypes.TemporalUnit.TemporalHours, - QgsUnitTypes.TemporalUnit.TemporalDays, - QgsUnitTypes.TemporalUnit.TemporalWeeks, - QgsUnitTypes.TemporalUnit.TemporalMonths, - QgsUnitTypes.TemporalUnit.TemporalYears, - QgsUnitTypes.TemporalUnit.TemporalDecades, - QgsUnitTypes.TemporalUnit.TemporalCenturies, - QgsUnitTypes.TemporalUnit.TemporalIrregularStep, - QgsUnitTypes.TemporalUnit.TemporalUnknownUnit] + units = [ + QgsUnitTypes.TemporalUnit.TemporalMilliseconds, + QgsUnitTypes.TemporalUnit.TemporalSeconds, + QgsUnitTypes.TemporalUnit.TemporalMinutes, + QgsUnitTypes.TemporalUnit.TemporalHours, + QgsUnitTypes.TemporalUnit.TemporalDays, + QgsUnitTypes.TemporalUnit.TemporalWeeks, + QgsUnitTypes.TemporalUnit.TemporalMonths, + QgsUnitTypes.TemporalUnit.TemporalYears, + QgsUnitTypes.TemporalUnit.TemporalDecades, + QgsUnitTypes.TemporalUnit.TemporalCenturies, + QgsUnitTypes.TemporalUnit.TemporalIrregularStep, + QgsUnitTypes.TemporalUnit.TemporalUnknownUnit, + ] for u in units: res, ok = QgsUnitTypes.stringToTemporalUnit(QgsUnitTypes.toString(u)) @@ -453,24 +480,28 @@ def testTemporalUnitsToFromString(self): self.assertEqual(res, u) # Test converting bad strings - res, ok = QgsUnitTypes.stringToTemporalUnit('bad') + res, ok = QgsUnitTypes.stringToTemporalUnit("bad") self.assertFalse(ok) self.assertEqual(res, QgsUnitTypes.TemporalUnit.TemporalUnknownUnit) # Test that string is cleaned before conversion - res, ok = QgsUnitTypes.stringToTemporalUnit(f' {QgsUnitTypes.toString(QgsUnitTypes.TemporalUnit.TemporalDecades).upper()} ') + res, ok = QgsUnitTypes.stringToTemporalUnit( + f" {QgsUnitTypes.toString(QgsUnitTypes.TemporalUnit.TemporalDecades).upper()} " + ) assert ok self.assertEqual(res, QgsUnitTypes.TemporalUnit.TemporalDecades) def testEncodeDecodeRenderUnits(self): """Test encoding and decoding render units""" - units = [QgsUnitTypes.RenderUnit.RenderMillimeters, - QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, - QgsUnitTypes.RenderUnit.RenderMapUnits, - QgsUnitTypes.RenderUnit.RenderPixels, - QgsUnitTypes.RenderUnit.RenderPercentage, - QgsUnitTypes.RenderUnit.RenderPoints, - QgsUnitTypes.RenderUnit.RenderInches] + units = [ + QgsUnitTypes.RenderUnit.RenderMillimeters, + QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, + QgsUnitTypes.RenderUnit.RenderMapUnits, + QgsUnitTypes.RenderUnit.RenderPixels, + QgsUnitTypes.RenderUnit.RenderPercentage, + QgsUnitTypes.RenderUnit.RenderPoints, + QgsUnitTypes.RenderUnit.RenderInches, + ] for u in units: res, ok = QgsUnitTypes.decodeRenderUnit(QgsUnitTypes.encodeUnit(u)) @@ -478,37 +509,39 @@ def testEncodeDecodeRenderUnits(self): self.assertEqual(res, u) # Test decoding bad units - res, ok = QgsUnitTypes.decodeRenderUnit('bad') + res, ok = QgsUnitTypes.decodeRenderUnit("bad") self.assertFalse(ok) # default units should be MM self.assertEqual(res, QgsUnitTypes.RenderUnit.RenderMillimeters) # Test that string is cleaned before decoding - res, ok = QgsUnitTypes.decodeRenderUnit(' PiXeL ') + res, ok = QgsUnitTypes.decodeRenderUnit(" PiXeL ") assert ok self.assertEqual(res, QgsUnitTypes.RenderUnit.RenderPixels) # check some aliases - used in data defined labeling - res, ok = QgsUnitTypes.decodeRenderUnit('Meters') + res, ok = QgsUnitTypes.decodeRenderUnit("Meters") assert ok - res, ok = QgsUnitTypes.decodeRenderUnit('MapUnits') + res, ok = QgsUnitTypes.decodeRenderUnit("MapUnits") assert ok self.assertEqual(res, QgsUnitTypes.RenderUnit.RenderMapUnits) - res, ok = QgsUnitTypes.decodeRenderUnit('Percent') + res, ok = QgsUnitTypes.decodeRenderUnit("Percent") assert ok self.assertEqual(res, QgsUnitTypes.RenderUnit.RenderPercentage) - res, ok = QgsUnitTypes.decodeRenderUnit('Points') + res, ok = QgsUnitTypes.decodeRenderUnit("Points") assert ok self.assertEqual(res, QgsUnitTypes.RenderUnit.RenderPoints) def testRenderUnitsString(self): """Test converting render units to strings""" - units = [QgsUnitTypes.RenderUnit.RenderMillimeters, - QgsUnitTypes.RenderUnit.RenderMapUnits, - QgsUnitTypes.RenderUnit.RenderPixels, - QgsUnitTypes.RenderUnit.RenderPercentage, - QgsUnitTypes.RenderUnit.RenderPoints, - QgsUnitTypes.RenderUnit.RenderInches] + units = [ + QgsUnitTypes.RenderUnit.RenderMillimeters, + QgsUnitTypes.RenderUnit.RenderMapUnits, + QgsUnitTypes.RenderUnit.RenderPixels, + QgsUnitTypes.RenderUnit.RenderPercentage, + QgsUnitTypes.RenderUnit.RenderPoints, + QgsUnitTypes.RenderUnit.RenderInches, + ] for u in units: self.assertTrue(QgsUnitTypes.toString(u)) @@ -578,7 +611,7 @@ def testFromUnitToUnitFactor(self): QgsUnitTypes.DistanceUnit.DistanceNauticalMiles: 0.53995682073432482717, QgsUnitTypes.DistanceUnit.DistanceMillimeters: 1000000.0, QgsUnitTypes.DistanceUnit.DistanceCentimeters: 100000.0, - Qgis.DistanceUnit.Inches: 39370.078740157485 + Qgis.DistanceUnit.Inches: 39370.078740157485, }, QgsUnitTypes.DistanceUnit.DistanceFeet: { QgsUnitTypes.DistanceUnit.DistanceMeters: 0.3048, @@ -586,11 +619,11 @@ def testFromUnitToUnitFactor(self): QgsUnitTypes.DistanceUnit.DistanceFeet: 1.0, QgsUnitTypes.DistanceUnit.DistanceYards: 0.3333333, QgsUnitTypes.DistanceUnit.DistanceMiles: 0.00018939375, - QgsUnitTypes.DistanceUnit.DistanceDegrees: 2.73806498599629E-06, + QgsUnitTypes.DistanceUnit.DistanceDegrees: 2.73806498599629e-06, QgsUnitTypes.DistanceUnit.DistanceNauticalMiles: 0.000164579, QgsUnitTypes.DistanceUnit.DistanceMillimeters: 304.8, QgsUnitTypes.DistanceUnit.DistanceCentimeters: 30.48, - Qgis.DistanceUnit.Inches: 12 + Qgis.DistanceUnit.Inches: 12, }, QgsUnitTypes.DistanceUnit.DistanceYards: { QgsUnitTypes.DistanceUnit.DistanceMeters: 0.9144, @@ -602,7 +635,7 @@ def testFromUnitToUnitFactor(self): QgsUnitTypes.DistanceUnit.DistanceNauticalMiles: 0.0004937366590756, QgsUnitTypes.DistanceUnit.DistanceMillimeters: 914.4, QgsUnitTypes.DistanceUnit.DistanceCentimeters: 91.44, - Qgis.DistanceUnit.Inches: 36 + Qgis.DistanceUnit.Inches: 36, }, QgsUnitTypes.DistanceUnit.DistanceDegrees: { QgsUnitTypes.DistanceUnit.DistanceMeters: 111319.49079327358, @@ -614,7 +647,7 @@ def testFromUnitToUnitFactor(self): QgsUnitTypes.DistanceUnit.DistanceNauticalMiles: 60.1077164, QgsUnitTypes.DistanceUnit.DistanceMillimeters: 111319490.79327358, QgsUnitTypes.DistanceUnit.DistanceCentimeters: 11131949.079327358, - Qgis.DistanceUnit.Inches: 4382657.117845417 + Qgis.DistanceUnit.Inches: 4382657.117845417, }, QgsUnitTypes.DistanceUnit.DistanceMiles: { QgsUnitTypes.DistanceUnit.DistanceMeters: 1609.3440000, @@ -626,7 +659,7 @@ def testFromUnitToUnitFactor(self): QgsUnitTypes.DistanceUnit.DistanceNauticalMiles: 0.8689762, QgsUnitTypes.DistanceUnit.DistanceMillimeters: 1609344.0, QgsUnitTypes.DistanceUnit.DistanceCentimeters: 160934.4, - Qgis.DistanceUnit.Inches: 63360 + Qgis.DistanceUnit.Inches: 63360, }, QgsUnitTypes.DistanceUnit.DistanceNauticalMiles: { QgsUnitTypes.DistanceUnit.DistanceMeters: 1852.0, @@ -638,7 +671,7 @@ def testFromUnitToUnitFactor(self): QgsUnitTypes.DistanceUnit.DistanceNauticalMiles: 1.0, QgsUnitTypes.DistanceUnit.DistanceMillimeters: 1852000.0, QgsUnitTypes.DistanceUnit.DistanceCentimeters: 185200.0, - Qgis.DistanceUnit.Inches: 72913.38582677166 + Qgis.DistanceUnit.Inches: 72913.38582677166, }, QgsUnitTypes.DistanceUnit.DistanceMillimeters: { QgsUnitTypes.DistanceUnit.DistanceMeters: 0.001, @@ -650,7 +683,7 @@ def testFromUnitToUnitFactor(self): QgsUnitTypes.DistanceUnit.DistanceNauticalMiles: 0.000000539957, QgsUnitTypes.DistanceUnit.DistanceMillimeters: 1.0, QgsUnitTypes.DistanceUnit.DistanceCentimeters: 0.1, - Qgis.DistanceUnit.Inches: 0.039370086377953 + Qgis.DistanceUnit.Inches: 0.039370086377953, }, QgsUnitTypes.DistanceUnit.DistanceCentimeters: { QgsUnitTypes.DistanceUnit.DistanceMeters: 0.01, @@ -662,7 +695,7 @@ def testFromUnitToUnitFactor(self): QgsUnitTypes.DistanceUnit.DistanceNauticalMiles: 0.00000539957, QgsUnitTypes.DistanceUnit.DistanceMillimeters: 10.0, QgsUnitTypes.DistanceUnit.DistanceCentimeters: 1.0, - Qgis.DistanceUnit.Inches: 0.3937007874015748 + Qgis.DistanceUnit.Inches: 0.3937007874015748, }, Qgis.DistanceUnit.Inches: { QgsUnitTypes.DistanceUnit.DistanceMeters: 0.0254, @@ -674,86 +707,93 @@ def testFromUnitToUnitFactor(self): QgsUnitTypes.DistanceUnit.DistanceNauticalMiles: 1.371489732183071538e-5, QgsUnitTypes.DistanceUnit.DistanceMillimeters: 25.4, QgsUnitTypes.DistanceUnit.DistanceCentimeters: 2.54, - Qgis.DistanceUnit.Inches: 1.0 + Qgis.DistanceUnit.Inches: 1.0, }, - Qgis.DistanceUnit.ChainsInternational: { - Qgis.DistanceUnit.Meters: 20.1168}, + Qgis.DistanceUnit.ChainsInternational: {Qgis.DistanceUnit.Meters: 20.1168}, Qgis.DistanceUnit.ChainsBritishBenoit1895A: { - Qgis.DistanceUnit.Meters: 20.1167824}, + Qgis.DistanceUnit.Meters: 20.1167824 + }, Qgis.DistanceUnit.ChainsBritishBenoit1895B: { - Qgis.DistanceUnit.Meters: 20.116782494376}, + Qgis.DistanceUnit.Meters: 20.116782494376 + }, Qgis.DistanceUnit.ChainsBritishSears1922Truncated: { - Qgis.DistanceUnit.Meters: 20.116756}, + Qgis.DistanceUnit.Meters: 20.116756 + }, Qgis.DistanceUnit.ChainsBritishSears1922: { - Qgis.DistanceUnit.Meters: 20.11676512155}, - Qgis.DistanceUnit.ChainsClarkes: { - Qgis.DistanceUnit.Meters: 20.1166195164}, + Qgis.DistanceUnit.Meters: 20.11676512155 + }, + Qgis.DistanceUnit.ChainsClarkes: {Qgis.DistanceUnit.Meters: 20.1166195164}, Qgis.DistanceUnit.ChainsUSSurvey: { - Qgis.DistanceUnit.Meters: 20.11684023368}, + Qgis.DistanceUnit.Meters: 20.11684023368 + }, Qgis.DistanceUnit.FeetBritish1865: { - Qgis.DistanceUnit.Meters: 0.30480083333333}, - Qgis.DistanceUnit.FeetBritish1936: { - Qgis.DistanceUnit.Meters: 0.3048007491}, + Qgis.DistanceUnit.Meters: 0.30480083333333 + }, + Qgis.DistanceUnit.FeetBritish1936: {Qgis.DistanceUnit.Meters: 0.3048007491}, Qgis.DistanceUnit.FeetBritishBenoit1895A: { - Qgis.DistanceUnit.Meters: 0.30479973333333}, + Qgis.DistanceUnit.Meters: 0.30479973333333 + }, Qgis.DistanceUnit.FeetBritishBenoit1895B: { - Qgis.DistanceUnit.Meters: 0.30479973476327}, + Qgis.DistanceUnit.Meters: 0.30479973476327 + }, Qgis.DistanceUnit.FeetBritishSears1922Truncated: { - Qgis.DistanceUnit.Meters: 0.30479933333333}, + Qgis.DistanceUnit.Meters: 0.30479933333333 + }, Qgis.DistanceUnit.FeetBritishSears1922: { - Qgis.DistanceUnit.Meters: 0.30479947153868}, - Qgis.DistanceUnit.FeetClarkes: { - Qgis.DistanceUnit.Meters: 0.3047972654}, + Qgis.DistanceUnit.Meters: 0.30479947153868 + }, + Qgis.DistanceUnit.FeetClarkes: {Qgis.DistanceUnit.Meters: 0.3047972654}, Qgis.DistanceUnit.FeetGoldCoast: { - Qgis.DistanceUnit.Meters: 0.30479971018151}, - Qgis.DistanceUnit.FeetIndian: { - Qgis.DistanceUnit.Meters: 0.30479951024815}, - Qgis.DistanceUnit.FeetIndian1937: { - Qgis.DistanceUnit.Meters: 0.30479841}, - Qgis.DistanceUnit.FeetIndian1962: { - Qgis.DistanceUnit.Meters: 0.3047996}, - Qgis.DistanceUnit.FeetIndian1975: { - Qgis.DistanceUnit.Meters: 0.3047995}, + Qgis.DistanceUnit.Meters: 0.30479971018151 + }, + Qgis.DistanceUnit.FeetIndian: {Qgis.DistanceUnit.Meters: 0.30479951024815}, + Qgis.DistanceUnit.FeetIndian1937: {Qgis.DistanceUnit.Meters: 0.30479841}, + Qgis.DistanceUnit.FeetIndian1962: {Qgis.DistanceUnit.Meters: 0.3047996}, + Qgis.DistanceUnit.FeetIndian1975: {Qgis.DistanceUnit.Meters: 0.3047995}, Qgis.DistanceUnit.FeetUSSurvey: { - Qgis.DistanceUnit.Meters: 0.30480060960122}, - Qgis.DistanceUnit.LinksInternational: { - Qgis.DistanceUnit.Meters: 0.201168}, + Qgis.DistanceUnit.Meters: 0.30480060960122 + }, + Qgis.DistanceUnit.LinksInternational: {Qgis.DistanceUnit.Meters: 0.201168}, Qgis.DistanceUnit.LinksBritishBenoit1895A: { - Qgis.DistanceUnit.Meters: 0.201167824}, + Qgis.DistanceUnit.Meters: 0.201167824 + }, Qgis.DistanceUnit.LinksBritishBenoit1895B: { - Qgis.DistanceUnit.Meters: 0.20116782494376}, + Qgis.DistanceUnit.Meters: 0.20116782494376 + }, Qgis.DistanceUnit.LinksBritishSears1922Truncated: { - Qgis.DistanceUnit.Meters: 0.20116756}, + Qgis.DistanceUnit.Meters: 0.20116756 + }, Qgis.DistanceUnit.LinksBritishSears1922: { - Qgis.DistanceUnit.Meters: 0.20116765121553}, - Qgis.DistanceUnit.LinksClarkes: { - Qgis.DistanceUnit.Meters: 0.20116619516}, + Qgis.DistanceUnit.Meters: 0.20116765121553 + }, + Qgis.DistanceUnit.LinksClarkes: {Qgis.DistanceUnit.Meters: 0.20116619516}, Qgis.DistanceUnit.LinksUSSurvey: { - Qgis.DistanceUnit.Meters: 0.2011684023368}, + Qgis.DistanceUnit.Meters: 0.2011684023368 + }, Qgis.DistanceUnit.YardsBritishBenoit1895A: { - Qgis.DistanceUnit.Meters: 0.9143992}, + Qgis.DistanceUnit.Meters: 0.9143992 + }, Qgis.DistanceUnit.YardsBritishBenoit1895B: { - Qgis.DistanceUnit.Meters: 0.9143992042898}, + Qgis.DistanceUnit.Meters: 0.9143992042898 + }, Qgis.DistanceUnit.YardsBritishSears1922Truncated: { - Qgis.DistanceUnit.Meters: 0.914398}, + Qgis.DistanceUnit.Meters: 0.914398 + }, Qgis.DistanceUnit.YardsBritishSears1922: { - Qgis.DistanceUnit.Meters: 0.91439841461603}, - Qgis.DistanceUnit.YardsClarkes: { - Qgis.DistanceUnit.Meters: 0.9143917962}, - Qgis.DistanceUnit.YardsIndian: { - Qgis.DistanceUnit.Meters: 0.91439853074444}, - Qgis.DistanceUnit.YardsIndian1937: { - Qgis.DistanceUnit.Meters: 0.91439523}, - Qgis.DistanceUnit.YardsIndian1962: { - Qgis.DistanceUnit.Meters: 0.9143988}, - Qgis.DistanceUnit.YardsIndian1975: { - Qgis.DistanceUnit.Meters: 0.9143985}, + Qgis.DistanceUnit.Meters: 0.91439841461603 + }, + Qgis.DistanceUnit.YardsClarkes: {Qgis.DistanceUnit.Meters: 0.9143917962}, + Qgis.DistanceUnit.YardsIndian: {Qgis.DistanceUnit.Meters: 0.91439853074444}, + Qgis.DistanceUnit.YardsIndian1937: {Qgis.DistanceUnit.Meters: 0.91439523}, + Qgis.DistanceUnit.YardsIndian1962: {Qgis.DistanceUnit.Meters: 0.9143988}, + Qgis.DistanceUnit.YardsIndian1975: {Qgis.DistanceUnit.Meters: 0.9143985}, Qgis.DistanceUnit.MilesUSSurvey: { - Qgis.DistanceUnit.Meters: 1609.3472186944}, - Qgis.DistanceUnit.Fathoms: { - Qgis.DistanceUnit.Meters: 1.8288}, + Qgis.DistanceUnit.Meters: 1609.3472186944 + }, + Qgis.DistanceUnit.Fathoms: {Qgis.DistanceUnit.Meters: 1.8288}, Qgis.DistanceUnit.MetersGermanLegal: { - Qgis.DistanceUnit.Meters: 1.0000135965}, + Qgis.DistanceUnit.Meters: 1.0000135965 + }, QgsUnitTypes.DistanceUnit.DistanceUnknownUnit: { QgsUnitTypes.DistanceUnit.DistanceMeters: 1.0, QgsUnitTypes.DistanceUnit.DistanceKilometers: 1.0, @@ -764,7 +804,7 @@ def testFromUnitToUnitFactor(self): QgsUnitTypes.DistanceUnit.DistanceNauticalMiles: 1.0, QgsUnitTypes.DistanceUnit.DistanceMillimeters: 1.0, QgsUnitTypes.DistanceUnit.DistanceCentimeters: 1.0, - Qgis.DistanceUnit.Inches: 1.0 + Qgis.DistanceUnit.Inches: 1.0, }, } @@ -772,16 +812,25 @@ def testFromUnitToUnitFactor(self): for to_unit in list(expected[from_unit].keys()): expected_factor = expected[from_unit][to_unit] res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, to_unit) - self.assertAlmostEqual(res, - expected_factor, - msg='got {:.7f}, expected {:.7f} when converting from {} to {}'.format(res, expected_factor, - QgsUnitTypes.toString(from_unit), - QgsUnitTypes.toString(to_unit))) + self.assertAlmostEqual( + res, + expected_factor, + msg="got {:.7f}, expected {:.7f} when converting from {} to {}".format( + res, + expected_factor, + QgsUnitTypes.toString(from_unit), + QgsUnitTypes.toString(to_unit), + ), + ) # test conversion to unknown units - res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, QgsUnitTypes.DistanceUnit.DistanceUnknownUnit) - self.assertAlmostEqual(res, - 1.0, - msg=f'got {res:.7f}, expected 1.0 when converting from {QgsUnitTypes.toString(from_unit)} to unknown units') + res = QgsUnitTypes.fromUnitToUnitFactor( + from_unit, QgsUnitTypes.DistanceUnit.DistanceUnknownUnit + ) + self.assertAlmostEqual( + res, + 1.0, + msg=f"got {res:.7f}, expected 1.0 when converting from {QgsUnitTypes.toString(from_unit)} to unknown units", + ) def testAreaFromUnitToUnitFactor(self): """Test calculation of conversion factor between areal units""" @@ -800,7 +849,7 @@ def testAreaFromUnitToUnitFactor(self): QgsUnitTypes.AreaUnit.AreaSquareMillimeters: 1e6, QgsUnitTypes.AreaUnit.AreaSquareCentimeters: 1e4, Qgis.AreaUnit.SquareInches: 1550.0031000062002, - QgsUnitTypes.AreaUnit.AreaUnknownUnit: 1.0 + QgsUnitTypes.AreaUnit.AreaUnknownUnit: 1.0, }, QgsUnitTypes.AreaUnit.AreaSquareKilometers: { QgsUnitTypes.AreaUnit.AreaSquareMeters: 1e6, @@ -838,7 +887,7 @@ def testAreaFromUnitToUnitFactor(self): QgsUnitTypes.AreaUnit.AreaSquareFeet: 9.0, QgsUnitTypes.AreaUnit.AreaSquareYards: 1.0, QgsUnitTypes.AreaUnit.AreaSquareMiles: 3.22831e-7, - QgsUnitTypes.AreaUnit.AreaHectares: 8.3612736E-5, + QgsUnitTypes.AreaUnit.AreaHectares: 8.3612736e-5, QgsUnitTypes.AreaUnit.AreaAcres: 0.00020661157, QgsUnitTypes.AreaUnit.AreaSquareNauticalMiles: 2.43776e-7, QgsUnitTypes.AreaUnit.AreaSquareDegrees: 0.000000000067473, @@ -920,7 +969,7 @@ def testAreaFromUnitToUnitFactor(self): QgsUnitTypes.AreaUnit.AreaSquareMillimeters: 12392029030500000.0, QgsUnitTypes.AreaUnit.AreaSquareCentimeters: 123920290305000.0, QgsUnitTypes.AreaUnit.AreaUnknownUnit: 1.0, - Qgis.AreaUnit.SquareInches: 19207683412641.824 + Qgis.AreaUnit.SquareInches: 19207683412641.824, }, QgsUnitTypes.AreaUnit.AreaSquareMillimeters: { QgsUnitTypes.AreaUnit.AreaSquareMeters: 1e-6, @@ -935,7 +984,7 @@ def testAreaFromUnitToUnitFactor(self): QgsUnitTypes.AreaUnit.AreaSquareMillimeters: 1.0, QgsUnitTypes.AreaUnit.AreaSquareCentimeters: 0.01, QgsUnitTypes.AreaUnit.AreaUnknownUnit: 1.0, - Qgis.AreaUnit.SquareInches: 0.0015500031000062 + Qgis.AreaUnit.SquareInches: 0.0015500031000062, }, QgsUnitTypes.AreaUnit.AreaSquareCentimeters: { QgsUnitTypes.AreaUnit.AreaSquareMeters: 1e-4, @@ -950,7 +999,7 @@ def testAreaFromUnitToUnitFactor(self): QgsUnitTypes.AreaUnit.AreaSquareMillimeters: 100, QgsUnitTypes.AreaUnit.AreaSquareCentimeters: 1.0, QgsUnitTypes.AreaUnit.AreaUnknownUnit: 1.0, - Qgis.AreaUnit.SquareInches: 0.15500031000062 + Qgis.AreaUnit.SquareInches: 0.15500031000062, }, Qgis.AreaUnit.SquareInches: { QgsUnitTypes.AreaUnit.AreaSquareMeters: 0.00064516, @@ -965,98 +1014,109 @@ def testAreaFromUnitToUnitFactor(self): QgsUnitTypes.AreaUnit.AreaSquareMillimeters: 645.16, QgsUnitTypes.AreaUnit.AreaSquareCentimeters: 6.451599999999999, QgsUnitTypes.AreaUnit.AreaUnknownUnit: 1.0, - Qgis.AreaUnit.SquareInches: 1 - } + Qgis.AreaUnit.SquareInches: 1, + }, } for from_unit in list(expected.keys()): for to_unit in list(expected[from_unit].keys()): expected_factor = expected[from_unit][to_unit] res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, to_unit) - self.assertAlmostEqual(res, - expected_factor, - msg='got {:.15f}, expected {:.15f} when converting from {} to {}'.format(res, expected_factor, - QgsUnitTypes.toString(from_unit), - QgsUnitTypes.toString(to_unit))) + self.assertAlmostEqual( + res, + expected_factor, + msg="got {:.15f}, expected {:.15f} when converting from {} to {}".format( + res, + expected_factor, + QgsUnitTypes.toString(from_unit), + QgsUnitTypes.toString(to_unit), + ), + ) # test conversion to unknown units - res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, QgsUnitTypes.AreaUnit.AreaUnknownUnit) - self.assertAlmostEqual(res, - 1.0, - msg=f'got {res:.7f}, expected 1.0 when converting from {QgsUnitTypes.toString(from_unit)} to unknown units') + res = QgsUnitTypes.fromUnitToUnitFactor( + from_unit, QgsUnitTypes.AreaUnit.AreaUnknownUnit + ) + self.assertAlmostEqual( + res, + 1.0, + msg=f"got {res:.7f}, expected 1.0 when converting from {QgsUnitTypes.toString(from_unit)} to unknown units", + ) def testDistanceToAreaUnit(self): """Test distanceToAreaUnit conversion""" - expected = {QgsUnitTypes.DistanceUnit.DistanceMeters: QgsUnitTypes.AreaUnit.AreaSquareMeters, - QgsUnitTypes.DistanceUnit.DistanceKilometers: QgsUnitTypes.AreaUnit.AreaSquareKilometers, - QgsUnitTypes.DistanceUnit.DistanceFeet: QgsUnitTypes.AreaUnit.AreaSquareFeet, - QgsUnitTypes.DistanceUnit.DistanceYards: QgsUnitTypes.AreaUnit.AreaSquareYards, - QgsUnitTypes.DistanceUnit.DistanceMiles: QgsUnitTypes.AreaUnit.AreaSquareMiles, - QgsUnitTypes.DistanceUnit.DistanceDegrees: QgsUnitTypes.AreaUnit.AreaSquareDegrees, - QgsUnitTypes.DistanceUnit.DistanceCentimeters: QgsUnitTypes.AreaUnit.AreaSquareCentimeters, - QgsUnitTypes.DistanceUnit.DistanceMillimeters: QgsUnitTypes.AreaUnit.AreaSquareMillimeters, - QgsUnitTypes.DistanceUnit.DistanceUnknownUnit: QgsUnitTypes.AreaUnit.AreaUnknownUnit, - QgsUnitTypes.DistanceUnit.DistanceNauticalMiles: QgsUnitTypes.AreaUnit.AreaSquareNauticalMiles, - Qgis.DistanceUnit.Inches: Qgis.AreaUnit.SquareInches, - Qgis.DistanceUnit.ChainsInternational: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.ChainsBritishBenoit1895A: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.ChainsBritishBenoit1895B: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.ChainsBritishSears1922Truncated: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.ChainsBritishSears1922: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.ChainsClarkes: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.ChainsUSSurvey: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.FeetBritish1865: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.FeetBritish1936: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.FeetBritishBenoit1895A: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.FeetBritishBenoit1895B: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.FeetBritishSears1922Truncated: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.FeetBritishSears1922: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.FeetClarkes: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.FeetGoldCoast: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.FeetIndian: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.FeetIndian1937: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.FeetIndian1962: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.FeetIndian1975: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.FeetUSSurvey: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.LinksInternational: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.LinksBritishBenoit1895A: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.LinksBritishBenoit1895B: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.LinksBritishSears1922Truncated: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.LinksBritishSears1922: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.LinksClarkes: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.LinksUSSurvey: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.YardsBritishBenoit1895A: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.YardsBritishBenoit1895B: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.YardsBritishSears1922Truncated: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.YardsBritishSears1922: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.YardsClarkes: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.YardsIndian: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.YardsIndian1937: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.YardsIndian1962: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.YardsIndian1975: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.MilesUSSurvey: Qgis.AreaUnit.SquareMiles, - Qgis.DistanceUnit.Fathoms: Qgis.AreaUnit.SquareFeet, - Qgis.DistanceUnit.MetersGermanLegal: Qgis.AreaUnit.SquareMeters, - } + expected = { + QgsUnitTypes.DistanceUnit.DistanceMeters: QgsUnitTypes.AreaUnit.AreaSquareMeters, + QgsUnitTypes.DistanceUnit.DistanceKilometers: QgsUnitTypes.AreaUnit.AreaSquareKilometers, + QgsUnitTypes.DistanceUnit.DistanceFeet: QgsUnitTypes.AreaUnit.AreaSquareFeet, + QgsUnitTypes.DistanceUnit.DistanceYards: QgsUnitTypes.AreaUnit.AreaSquareYards, + QgsUnitTypes.DistanceUnit.DistanceMiles: QgsUnitTypes.AreaUnit.AreaSquareMiles, + QgsUnitTypes.DistanceUnit.DistanceDegrees: QgsUnitTypes.AreaUnit.AreaSquareDegrees, + QgsUnitTypes.DistanceUnit.DistanceCentimeters: QgsUnitTypes.AreaUnit.AreaSquareCentimeters, + QgsUnitTypes.DistanceUnit.DistanceMillimeters: QgsUnitTypes.AreaUnit.AreaSquareMillimeters, + QgsUnitTypes.DistanceUnit.DistanceUnknownUnit: QgsUnitTypes.AreaUnit.AreaUnknownUnit, + QgsUnitTypes.DistanceUnit.DistanceNauticalMiles: QgsUnitTypes.AreaUnit.AreaSquareNauticalMiles, + Qgis.DistanceUnit.Inches: Qgis.AreaUnit.SquareInches, + Qgis.DistanceUnit.ChainsInternational: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.ChainsBritishBenoit1895A: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.ChainsBritishBenoit1895B: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.ChainsBritishSears1922Truncated: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.ChainsBritishSears1922: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.ChainsClarkes: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.ChainsUSSurvey: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.FeetBritish1865: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.FeetBritish1936: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.FeetBritishBenoit1895A: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.FeetBritishBenoit1895B: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.FeetBritishSears1922Truncated: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.FeetBritishSears1922: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.FeetClarkes: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.FeetGoldCoast: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.FeetIndian: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.FeetIndian1937: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.FeetIndian1962: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.FeetIndian1975: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.FeetUSSurvey: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.LinksInternational: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.LinksBritishBenoit1895A: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.LinksBritishBenoit1895B: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.LinksBritishSears1922Truncated: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.LinksBritishSears1922: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.LinksClarkes: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.LinksUSSurvey: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.YardsBritishBenoit1895A: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.YardsBritishBenoit1895B: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.YardsBritishSears1922Truncated: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.YardsBritishSears1922: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.YardsClarkes: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.YardsIndian: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.YardsIndian1937: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.YardsIndian1962: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.YardsIndian1975: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.MilesUSSurvey: Qgis.AreaUnit.SquareMiles, + Qgis.DistanceUnit.Fathoms: Qgis.AreaUnit.SquareFeet, + Qgis.DistanceUnit.MetersGermanLegal: Qgis.AreaUnit.SquareMeters, + } for t in list(expected.keys()): self.assertEqual(QgsUnitTypes.distanceToAreaUnit(t), expected[t]) def testAreaToDistanceUnit(self): """Test areaToDistanceUnit conversion""" - expected = {QgsUnitTypes.AreaUnit.AreaSquareMeters: QgsUnitTypes.DistanceUnit.DistanceMeters, - QgsUnitTypes.AreaUnit.AreaSquareKilometers: QgsUnitTypes.DistanceUnit.DistanceKilometers, - QgsUnitTypes.AreaUnit.AreaSquareFeet: QgsUnitTypes.DistanceUnit.DistanceFeet, - QgsUnitTypes.AreaUnit.AreaSquareYards: QgsUnitTypes.DistanceUnit.DistanceYards, - QgsUnitTypes.AreaUnit.AreaSquareMiles: QgsUnitTypes.DistanceUnit.DistanceMiles, - QgsUnitTypes.AreaUnit.AreaHectares: QgsUnitTypes.DistanceUnit.DistanceMeters, - QgsUnitTypes.AreaUnit.AreaAcres: QgsUnitTypes.DistanceUnit.DistanceYards, - QgsUnitTypes.AreaUnit.AreaSquareDegrees: QgsUnitTypes.DistanceUnit.DistanceDegrees, - QgsUnitTypes.AreaUnit.AreaSquareCentimeters: QgsUnitTypes.DistanceUnit.DistanceCentimeters, - QgsUnitTypes.AreaUnit.AreaSquareMillimeters: QgsUnitTypes.DistanceUnit.DistanceMillimeters, - QgsUnitTypes.AreaUnit.AreaUnknownUnit: QgsUnitTypes.DistanceUnit.DistanceUnknownUnit, - QgsUnitTypes.AreaUnit.AreaSquareNauticalMiles: QgsUnitTypes.DistanceUnit.DistanceNauticalMiles, - Qgis.AreaUnit.SquareInches: Qgis.DistanceUnit.Inches - } + expected = { + QgsUnitTypes.AreaUnit.AreaSquareMeters: QgsUnitTypes.DistanceUnit.DistanceMeters, + QgsUnitTypes.AreaUnit.AreaSquareKilometers: QgsUnitTypes.DistanceUnit.DistanceKilometers, + QgsUnitTypes.AreaUnit.AreaSquareFeet: QgsUnitTypes.DistanceUnit.DistanceFeet, + QgsUnitTypes.AreaUnit.AreaSquareYards: QgsUnitTypes.DistanceUnit.DistanceYards, + QgsUnitTypes.AreaUnit.AreaSquareMiles: QgsUnitTypes.DistanceUnit.DistanceMiles, + QgsUnitTypes.AreaUnit.AreaHectares: QgsUnitTypes.DistanceUnit.DistanceMeters, + QgsUnitTypes.AreaUnit.AreaAcres: QgsUnitTypes.DistanceUnit.DistanceYards, + QgsUnitTypes.AreaUnit.AreaSquareDegrees: QgsUnitTypes.DistanceUnit.DistanceDegrees, + QgsUnitTypes.AreaUnit.AreaSquareCentimeters: QgsUnitTypes.DistanceUnit.DistanceCentimeters, + QgsUnitTypes.AreaUnit.AreaSquareMillimeters: QgsUnitTypes.DistanceUnit.DistanceMillimeters, + QgsUnitTypes.AreaUnit.AreaUnknownUnit: QgsUnitTypes.DistanceUnit.DistanceUnknownUnit, + QgsUnitTypes.AreaUnit.AreaSquareNauticalMiles: QgsUnitTypes.DistanceUnit.DistanceNauticalMiles, + Qgis.AreaUnit.SquareInches: Qgis.DistanceUnit.Inches, + } for t in list(expected.keys()): self.assertEqual(QgsUnitTypes.areaToDistanceUnit(t), expected[t]) @@ -1076,7 +1136,7 @@ def testVolumeFromUnitToUnitFactor(self): QgsUnitTypes.VolumeUnit.VolumeCubicInch: 61023.7438368, QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter: 1000000, QgsUnitTypes.VolumeUnit.VolumeCubicDegrees: 7.24913798948971e-16, - QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0 + QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0, }, QgsUnitTypes.VolumeUnit.VolumeCubicFeet: { QgsUnitTypes.VolumeUnit.VolumeCubicMeters: 0.0283168, @@ -1089,7 +1149,7 @@ def testVolumeFromUnitToUnitFactor(self): QgsUnitTypes.VolumeUnit.VolumeCubicInch: 1728.000629765, QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter: 28316.85, QgsUnitTypes.VolumeUnit.VolumeCubicDegrees: 2.0527272837261945e-17, - QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0 + QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0, }, QgsUnitTypes.VolumeUnit.VolumeCubicYards: { QgsUnitTypes.VolumeUnit.VolumeCubicMeters: 0.7645549, @@ -1102,7 +1162,7 @@ def testVolumeFromUnitToUnitFactor(self): QgsUnitTypes.VolumeUnit.VolumeCubicInch: 46656.013952472, QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter: 764554.9, QgsUnitTypes.VolumeUnit.VolumeCubicDegrees: 5.542363970640507e-16, - QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0 + QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0, }, QgsUnitTypes.VolumeUnit.VolumeBarrel: { QgsUnitTypes.VolumeUnit.VolumeCubicMeters: 0.158987294928, @@ -1115,7 +1175,7 @@ def testVolumeFromUnitToUnitFactor(self): QgsUnitTypes.VolumeUnit.VolumeCubicInch: 9702.002677722, QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter: 158987.3, QgsUnitTypes.VolumeUnit.VolumeCubicDegrees: 1.1525208762763973e-16, - QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0 + QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0, }, QgsUnitTypes.VolumeUnit.VolumeCubicDecimeter: { QgsUnitTypes.VolumeUnit.VolumeCubicMeters: 0.001, @@ -1128,7 +1188,7 @@ def testVolumeFromUnitToUnitFactor(self): QgsUnitTypes.VolumeUnit.VolumeCubicInch: 61.02375899, QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter: 1000, QgsUnitTypes.VolumeUnit.VolumeCubicDegrees: 7.24913798948971e-19, - QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0 + QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0, }, QgsUnitTypes.VolumeUnit.VolumeLiters: { QgsUnitTypes.VolumeUnit.VolumeCubicMeters: 0.001, @@ -1141,7 +1201,7 @@ def testVolumeFromUnitToUnitFactor(self): QgsUnitTypes.VolumeUnit.VolumeCubicInch: 61.02375899, QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter: 1000, QgsUnitTypes.VolumeUnit.VolumeCubicDegrees: 7.24913798948971e-19, - QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0 + QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0, }, QgsUnitTypes.VolumeUnit.VolumeGallonUS: { QgsUnitTypes.VolumeUnit.VolumeCubicMeters: 0.00378541, @@ -1154,7 +1214,7 @@ def testVolumeFromUnitToUnitFactor(self): QgsUnitTypes.VolumeUnit.VolumeCubicInch: 231.000069567, QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter: 3785.412, QgsUnitTypes.VolumeUnit.VolumeCubicDegrees: 2.7440973935070226e-18, - QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0 + QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0, }, QgsUnitTypes.VolumeUnit.VolumeCubicInch: { QgsUnitTypes.VolumeUnit.VolumeCubicMeters: 1.63871e-5, @@ -1167,7 +1227,7 @@ def testVolumeFromUnitToUnitFactor(self): QgsUnitTypes.VolumeUnit.VolumeCubicInch: 1.0, QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter: 16.38706, QgsUnitTypes.VolumeUnit.VolumeCubicDegrees: 1.187916242337679e-20, - QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0 + QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0, }, QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter: { QgsUnitTypes.VolumeUnit.VolumeCubicMeters: 1e-6, @@ -1180,7 +1240,7 @@ def testVolumeFromUnitToUnitFactor(self): QgsUnitTypes.VolumeUnit.VolumeCubicInch: 0.061023759, QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter: 1.0, QgsUnitTypes.VolumeUnit.VolumeCubicDegrees: 7.24913798948971e-22, - QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0 + QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0, }, QgsUnitTypes.VolumeUnit.VolumeCubicDegrees: { QgsUnitTypes.VolumeUnit.VolumeCubicMeters: 1379474361572186.2500000, @@ -1193,24 +1253,33 @@ def testVolumeFromUnitToUnitFactor(self): QgsUnitTypes.VolumeUnit.VolumeCubicInch: 22605446363.083416, QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter: 1379474361.5721862, QgsUnitTypes.VolumeUnit.VolumeCubicDegrees: 1.0, - QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0 - } + QgsUnitTypes.VolumeUnit.VolumeUnknownUnit: 1.0, + }, } for from_unit in list(expected.keys()): for to_unit in list(expected[from_unit].keys()): expected_factor = expected[from_unit][to_unit] res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, to_unit) - self.assertAlmostEqual(res, - expected_factor, - msg='got {:.15f}, expected {:.15f} when converting from {} to {}'.format(res, expected_factor, - QgsUnitTypes.toString(from_unit), - QgsUnitTypes.toString(to_unit))) + self.assertAlmostEqual( + res, + expected_factor, + msg="got {:.15f}, expected {:.15f} when converting from {} to {}".format( + res, + expected_factor, + QgsUnitTypes.toString(from_unit), + QgsUnitTypes.toString(to_unit), + ), + ) # test conversion to unknown units - res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, QgsUnitTypes.VolumeUnit.VolumeUnknownUnit) - self.assertAlmostEqual(res, - 1.0, - msg=f'got {res:.7f}, expected 1.0 when converting from {QgsUnitTypes.toString(from_unit)} to unknown units') + res = QgsUnitTypes.fromUnitToUnitFactor( + from_unit, QgsUnitTypes.VolumeUnit.VolumeUnknownUnit + ) + self.assertAlmostEqual( + res, + 1.0, + msg=f"got {res:.7f}, expected 1.0 when converting from {QgsUnitTypes.toString(from_unit)} to unknown units", + ) def testTemporalFromUnitToUnitFactor(self): """Test calculation of conversion factor between temporal units""" @@ -1273,7 +1342,7 @@ def testTemporalFromUnitToUnitFactor(self): QgsUnitTypes.TemporalUnit.TemporalIrregularStep: 1.0, }, QgsUnitTypes.TemporalUnit.TemporalDays: { - QgsUnitTypes.TemporalUnit.TemporalMilliseconds: 8.64e+7, + QgsUnitTypes.TemporalUnit.TemporalMilliseconds: 8.64e7, QgsUnitTypes.TemporalUnit.TemporalSeconds: 86400, QgsUnitTypes.TemporalUnit.TemporalMinutes: 1440, QgsUnitTypes.TemporalUnit.TemporalHours: 24, @@ -1287,7 +1356,7 @@ def testTemporalFromUnitToUnitFactor(self): QgsUnitTypes.TemporalUnit.TemporalIrregularStep: 1.0, }, QgsUnitTypes.TemporalUnit.TemporalWeeks: { - QgsUnitTypes.TemporalUnit.TemporalMilliseconds: 6.048e+8, + QgsUnitTypes.TemporalUnit.TemporalMilliseconds: 6.048e8, QgsUnitTypes.TemporalUnit.TemporalSeconds: 604800, QgsUnitTypes.TemporalUnit.TemporalMinutes: 10080, QgsUnitTypes.TemporalUnit.TemporalHours: 168, @@ -1355,141 +1424,160 @@ def testTemporalFromUnitToUnitFactor(self): QgsUnitTypes.TemporalUnit.TemporalCenturies: 1, QgsUnitTypes.TemporalUnit.TemporalUnknownUnit: 1.0, QgsUnitTypes.TemporalUnit.TemporalIrregularStep: 1.0, - } + }, } for from_unit in list(expected.keys()): for to_unit in list(expected[from_unit].keys()): expected_factor = expected[from_unit][to_unit] res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, to_unit) - self.assertAlmostEqual(res, - expected_factor, - places=10, - msg='got {:.15f}, expected {:.15f} when converting from {} to {}'.format(res, expected_factor, - QgsUnitTypes.toString(from_unit), - QgsUnitTypes.toString(to_unit))) + self.assertAlmostEqual( + res, + expected_factor, + places=10, + msg="got {:.15f}, expected {:.15f} when converting from {} to {}".format( + res, + expected_factor, + QgsUnitTypes.toString(from_unit), + QgsUnitTypes.toString(to_unit), + ), + ) # test conversion to unknown units - res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, QgsUnitTypes.TemporalUnit.TemporalUnknownUnit) - self.assertAlmostEqual(res, - 1.0, - msg=f'got {res:.7f}, expected 1.0 when converting from {QgsUnitTypes.toString(from_unit)} to unknown units') - res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, QgsUnitTypes.TemporalUnit.TemporalIrregularStep) - self.assertAlmostEqual(res, - 1.0, - msg=f'got {res:.7f}, expected 1.0 when converting from {QgsUnitTypes.toString(from_unit)} to unknown units') + res = QgsUnitTypes.fromUnitToUnitFactor( + from_unit, QgsUnitTypes.TemporalUnit.TemporalUnknownUnit + ) + self.assertAlmostEqual( + res, + 1.0, + msg=f"got {res:.7f}, expected 1.0 when converting from {QgsUnitTypes.toString(from_unit)} to unknown units", + ) + res = QgsUnitTypes.fromUnitToUnitFactor( + from_unit, QgsUnitTypes.TemporalUnit.TemporalIrregularStep + ) + self.assertAlmostEqual( + res, + 1.0, + msg=f"got {res:.7f}, expected 1.0 when converting from {QgsUnitTypes.toString(from_unit)} to unknown units", + ) def testDistanceToVolumeUnit(self): """Test distanceToVolumeUnit conversion""" - expected = {QgsUnitTypes.DistanceUnit.DistanceMeters: QgsUnitTypes.VolumeUnit.VolumeCubicMeters, - QgsUnitTypes.DistanceUnit.DistanceKilometers: QgsUnitTypes.VolumeUnit.VolumeCubicMeters, - QgsUnitTypes.DistanceUnit.DistanceFeet: QgsUnitTypes.VolumeUnit.VolumeCubicFeet, - QgsUnitTypes.DistanceUnit.DistanceYards: QgsUnitTypes.VolumeUnit.VolumeCubicYards, - QgsUnitTypes.DistanceUnit.DistanceMiles: QgsUnitTypes.VolumeUnit.VolumeCubicFeet, - QgsUnitTypes.DistanceUnit.DistanceDegrees: QgsUnitTypes.VolumeUnit.VolumeCubicDegrees, - QgsUnitTypes.DistanceUnit.DistanceCentimeters: QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter, - QgsUnitTypes.DistanceUnit.DistanceMillimeters: QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter, - QgsUnitTypes.DistanceUnit.DistanceUnknownUnit: QgsUnitTypes.VolumeUnit.VolumeUnknownUnit, - QgsUnitTypes.DistanceUnit.DistanceNauticalMiles: QgsUnitTypes.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.Inches: QgsUnitTypes.VolumeUnit.VolumeCubicInch, - Qgis.DistanceUnit.ChainsInternational: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.ChainsBritishBenoit1895A: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.ChainsBritishBenoit1895B: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.ChainsBritishSears1922Truncated: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.ChainsBritishSears1922: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.ChainsClarkes: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.ChainsUSSurvey: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.FeetBritish1865: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.FeetBritish1936: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.FeetBritishBenoit1895A: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.FeetBritishBenoit1895B: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.FeetBritishSears1922Truncated: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.FeetBritishSears1922: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.FeetClarkes: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.FeetGoldCoast: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.FeetIndian: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.FeetIndian1937: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.FeetIndian1962: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.FeetIndian1975: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.FeetUSSurvey: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.LinksInternational: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.LinksBritishBenoit1895A: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.LinksBritishBenoit1895B: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.LinksBritishSears1922Truncated: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.LinksBritishSears1922: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.LinksClarkes: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.LinksUSSurvey: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.YardsBritishBenoit1895A: Qgis.VolumeUnit.VolumeCubicYards, - Qgis.DistanceUnit.YardsBritishBenoit1895B: Qgis.VolumeUnit.VolumeCubicYards, - Qgis.DistanceUnit.YardsBritishSears1922Truncated: Qgis.VolumeUnit.VolumeCubicYards, - Qgis.DistanceUnit.YardsBritishSears1922: Qgis.VolumeUnit.VolumeCubicYards, - Qgis.DistanceUnit.YardsClarkes: Qgis.VolumeUnit.VolumeCubicYards, - Qgis.DistanceUnit.YardsIndian: Qgis.VolumeUnit.VolumeCubicYards, - Qgis.DistanceUnit.YardsIndian1937: Qgis.VolumeUnit.VolumeCubicYards, - Qgis.DistanceUnit.YardsIndian1962: Qgis.VolumeUnit.VolumeCubicYards, - Qgis.DistanceUnit.YardsIndian1975: Qgis.VolumeUnit.VolumeCubicYards, - Qgis.DistanceUnit.MilesUSSurvey: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.Fathoms: Qgis.VolumeUnit.VolumeCubicFeet, - Qgis.DistanceUnit.MetersGermanLegal: Qgis.VolumeUnit.VolumeCubicMeters, - } + expected = { + QgsUnitTypes.DistanceUnit.DistanceMeters: QgsUnitTypes.VolumeUnit.VolumeCubicMeters, + QgsUnitTypes.DistanceUnit.DistanceKilometers: QgsUnitTypes.VolumeUnit.VolumeCubicMeters, + QgsUnitTypes.DistanceUnit.DistanceFeet: QgsUnitTypes.VolumeUnit.VolumeCubicFeet, + QgsUnitTypes.DistanceUnit.DistanceYards: QgsUnitTypes.VolumeUnit.VolumeCubicYards, + QgsUnitTypes.DistanceUnit.DistanceMiles: QgsUnitTypes.VolumeUnit.VolumeCubicFeet, + QgsUnitTypes.DistanceUnit.DistanceDegrees: QgsUnitTypes.VolumeUnit.VolumeCubicDegrees, + QgsUnitTypes.DistanceUnit.DistanceCentimeters: QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter, + QgsUnitTypes.DistanceUnit.DistanceMillimeters: QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter, + QgsUnitTypes.DistanceUnit.DistanceUnknownUnit: QgsUnitTypes.VolumeUnit.VolumeUnknownUnit, + QgsUnitTypes.DistanceUnit.DistanceNauticalMiles: QgsUnitTypes.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.Inches: QgsUnitTypes.VolumeUnit.VolumeCubicInch, + Qgis.DistanceUnit.ChainsInternational: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.ChainsBritishBenoit1895A: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.ChainsBritishBenoit1895B: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.ChainsBritishSears1922Truncated: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.ChainsBritishSears1922: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.ChainsClarkes: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.ChainsUSSurvey: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.FeetBritish1865: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.FeetBritish1936: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.FeetBritishBenoit1895A: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.FeetBritishBenoit1895B: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.FeetBritishSears1922Truncated: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.FeetBritishSears1922: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.FeetClarkes: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.FeetGoldCoast: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.FeetIndian: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.FeetIndian1937: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.FeetIndian1962: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.FeetIndian1975: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.FeetUSSurvey: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.LinksInternational: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.LinksBritishBenoit1895A: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.LinksBritishBenoit1895B: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.LinksBritishSears1922Truncated: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.LinksBritishSears1922: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.LinksClarkes: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.LinksUSSurvey: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.YardsBritishBenoit1895A: Qgis.VolumeUnit.VolumeCubicYards, + Qgis.DistanceUnit.YardsBritishBenoit1895B: Qgis.VolumeUnit.VolumeCubicYards, + Qgis.DistanceUnit.YardsBritishSears1922Truncated: Qgis.VolumeUnit.VolumeCubicYards, + Qgis.DistanceUnit.YardsBritishSears1922: Qgis.VolumeUnit.VolumeCubicYards, + Qgis.DistanceUnit.YardsClarkes: Qgis.VolumeUnit.VolumeCubicYards, + Qgis.DistanceUnit.YardsIndian: Qgis.VolumeUnit.VolumeCubicYards, + Qgis.DistanceUnit.YardsIndian1937: Qgis.VolumeUnit.VolumeCubicYards, + Qgis.DistanceUnit.YardsIndian1962: Qgis.VolumeUnit.VolumeCubicYards, + Qgis.DistanceUnit.YardsIndian1975: Qgis.VolumeUnit.VolumeCubicYards, + Qgis.DistanceUnit.MilesUSSurvey: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.Fathoms: Qgis.VolumeUnit.VolumeCubicFeet, + Qgis.DistanceUnit.MetersGermanLegal: Qgis.VolumeUnit.VolumeCubicMeters, + } for t in list(expected.keys()): self.assertEqual(QgsUnitTypes.distanceToVolumeUnit(t), expected[t]) def testVolumeToDistanceUnit(self): """Test volumeToDistanceUnit conversion""" - expected = {QgsUnitTypes.VolumeUnit.VolumeCubicMeters: QgsUnitTypes.DistanceUnit.DistanceMeters, - QgsUnitTypes.VolumeUnit.VolumeCubicFeet: QgsUnitTypes.DistanceUnit.DistanceFeet, - QgsUnitTypes.VolumeUnit.VolumeCubicYards: QgsUnitTypes.DistanceUnit.DistanceYards, - QgsUnitTypes.VolumeUnit.VolumeBarrel: QgsUnitTypes.DistanceUnit.DistanceFeet, - QgsUnitTypes.VolumeUnit.VolumeCubicDecimeter: QgsUnitTypes.DistanceUnit.DistanceCentimeters, - QgsUnitTypes.VolumeUnit.VolumeLiters: QgsUnitTypes.DistanceUnit.DistanceMeters, - QgsUnitTypes.VolumeUnit.VolumeGallonUS: QgsUnitTypes.DistanceUnit.DistanceFeet, - QgsUnitTypes.VolumeUnit.VolumeCubicInch: Qgis.DistanceUnit.Inches, - QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter: QgsUnitTypes.DistanceUnit.DistanceCentimeters, - QgsUnitTypes.VolumeUnit.VolumeCubicDegrees: QgsUnitTypes.DistanceUnit.DistanceDegrees - } + expected = { + QgsUnitTypes.VolumeUnit.VolumeCubicMeters: QgsUnitTypes.DistanceUnit.DistanceMeters, + QgsUnitTypes.VolumeUnit.VolumeCubicFeet: QgsUnitTypes.DistanceUnit.DistanceFeet, + QgsUnitTypes.VolumeUnit.VolumeCubicYards: QgsUnitTypes.DistanceUnit.DistanceYards, + QgsUnitTypes.VolumeUnit.VolumeBarrel: QgsUnitTypes.DistanceUnit.DistanceFeet, + QgsUnitTypes.VolumeUnit.VolumeCubicDecimeter: QgsUnitTypes.DistanceUnit.DistanceCentimeters, + QgsUnitTypes.VolumeUnit.VolumeLiters: QgsUnitTypes.DistanceUnit.DistanceMeters, + QgsUnitTypes.VolumeUnit.VolumeGallonUS: QgsUnitTypes.DistanceUnit.DistanceFeet, + QgsUnitTypes.VolumeUnit.VolumeCubicInch: Qgis.DistanceUnit.Inches, + QgsUnitTypes.VolumeUnit.VolumeCubicCentimeter: QgsUnitTypes.DistanceUnit.DistanceCentimeters, + QgsUnitTypes.VolumeUnit.VolumeCubicDegrees: QgsUnitTypes.DistanceUnit.DistanceDegrees, + } for t in list(expected.keys()): self.assertEqual(QgsUnitTypes.volumeToDistanceUnit(t), expected[t]) def testEncodeDecodeAngleUnits(self): """Test encoding and decoding angle units""" - units = [QgsUnitTypes.AngleUnit.AngleDegrees, - QgsUnitTypes.AngleUnit.AngleRadians, - QgsUnitTypes.AngleUnit.AngleGon, - QgsUnitTypes.AngleUnit.AngleMinutesOfArc, - QgsUnitTypes.AngleUnit.AngleSecondsOfArc, - QgsUnitTypes.AngleUnit.AngleTurn, - QgsUnitTypes.AngleUnit.AngleMilliradiansSI, - QgsUnitTypes.AngleUnit.AngleMilNATO, - QgsUnitTypes.AngleUnit.AngleUnknownUnit] + units = [ + QgsUnitTypes.AngleUnit.AngleDegrees, + QgsUnitTypes.AngleUnit.AngleRadians, + QgsUnitTypes.AngleUnit.AngleGon, + QgsUnitTypes.AngleUnit.AngleMinutesOfArc, + QgsUnitTypes.AngleUnit.AngleSecondsOfArc, + QgsUnitTypes.AngleUnit.AngleTurn, + QgsUnitTypes.AngleUnit.AngleMilliradiansSI, + QgsUnitTypes.AngleUnit.AngleMilNATO, + QgsUnitTypes.AngleUnit.AngleUnknownUnit, + ] for u in units: res, ok = QgsUnitTypes.decodeAngleUnit(QgsUnitTypes.encodeUnit(u)) - assert ok, f'could not decode unit {QgsUnitTypes.toString(u)}' + assert ok, f"could not decode unit {QgsUnitTypes.toString(u)}" self.assertEqual(res, u) # Test decoding bad units - res, ok = QgsUnitTypes.decodeAngleUnit('bad') + res, ok = QgsUnitTypes.decodeAngleUnit("bad") self.assertFalse(ok) self.assertEqual(res, QgsUnitTypes.AngleUnit.AngleUnknownUnit) # Test that string is cleaned before decoding - res, ok = QgsUnitTypes.decodeAngleUnit(' MoA ') + res, ok = QgsUnitTypes.decodeAngleUnit(" MoA ") assert ok self.assertEqual(res, QgsUnitTypes.AngleUnit.AngleMinutesOfArc) def testAngleToString(self): """Test converting angle unit to string""" - units = [QgsUnitTypes.AngleUnit.AngleDegrees, - QgsUnitTypes.AngleUnit.AngleRadians, - QgsUnitTypes.AngleUnit.AngleGon, - QgsUnitTypes.AngleUnit.AngleMinutesOfArc, - QgsUnitTypes.AngleUnit.AngleSecondsOfArc, - QgsUnitTypes.AngleUnit.AngleTurn, - QgsUnitTypes.AngleUnit.AngleMilliradiansSI, - QgsUnitTypes.AngleUnit.AngleMilNATO, - QgsUnitTypes.AngleUnit.AngleUnknownUnit] + units = [ + QgsUnitTypes.AngleUnit.AngleDegrees, + QgsUnitTypes.AngleUnit.AngleRadians, + QgsUnitTypes.AngleUnit.AngleGon, + QgsUnitTypes.AngleUnit.AngleMinutesOfArc, + QgsUnitTypes.AngleUnit.AngleSecondsOfArc, + QgsUnitTypes.AngleUnit.AngleTurn, + QgsUnitTypes.AngleUnit.AngleMilliradiansSI, + QgsUnitTypes.AngleUnit.AngleMilNATO, + QgsUnitTypes.AngleUnit.AngleUnknownUnit, + ] dupes = set() @@ -1503,175 +1591,651 @@ def testAngleToString(self): def testAngleFromUnitToUnitFactor(self): """Test calculation of conversion factor between angular units""" - expected = {QgsUnitTypes.AngleUnit.AngleDegrees: {QgsUnitTypes.AngleUnit.AngleDegrees: 1.0, QgsUnitTypes.AngleUnit.AngleRadians: 0.0174533, QgsUnitTypes.AngleUnit.AngleGon: 1.1111111, QgsUnitTypes.AngleUnit.AngleMinutesOfArc: 60, QgsUnitTypes.AngleUnit.AngleSecondsOfArc: 3600, QgsUnitTypes.AngleUnit.AngleTurn: 0.00277777777778, QgsUnitTypes.AngleUnit.AngleMilliradiansSI: 17.453292519943297, QgsUnitTypes.AngleUnit.AngleMilNATO: 17.77777777777778}, - QgsUnitTypes.AngleUnit.AngleRadians: {QgsUnitTypes.AngleUnit.AngleDegrees: 57.2957795, QgsUnitTypes.AngleUnit.AngleRadians: 1.0, QgsUnitTypes.AngleUnit.AngleGon: 63.6619772, QgsUnitTypes.AngleUnit.AngleMinutesOfArc: 3437.7467708, QgsUnitTypes.AngleUnit.AngleSecondsOfArc: 206264.8062471, QgsUnitTypes.AngleUnit.AngleTurn: 0.159154943092, QgsUnitTypes.AngleUnit.AngleMilliradiansSI: 1000.0, QgsUnitTypes.AngleUnit.AngleMilNATO: 1018.5916357881301}, - QgsUnitTypes.AngleUnit.AngleGon: {QgsUnitTypes.AngleUnit.AngleDegrees: 0.9000000, QgsUnitTypes.AngleUnit.AngleRadians: 0.015707968623450838802, QgsUnitTypes.AngleUnit.AngleGon: 1.0, QgsUnitTypes.AngleUnit.AngleMinutesOfArc: 54.0000000, QgsUnitTypes.AngleUnit.AngleSecondsOfArc: 3240.0000000, QgsUnitTypes.AngleUnit.AngleTurn: 0.0025, QgsUnitTypes.AngleUnit.AngleMilliradiansSI: 15.707963267948967, QgsUnitTypes.AngleUnit.AngleMilNATO: 16}, - QgsUnitTypes.AngleUnit.AngleMinutesOfArc: {QgsUnitTypes.AngleUnit.AngleDegrees: 0.016666672633390722247, QgsUnitTypes.AngleUnit.AngleRadians: 0.00029088831280398030638, QgsUnitTypes.AngleUnit.AngleGon: 0.018518525464057963154, QgsUnitTypes.AngleUnit.AngleMinutesOfArc: 1.0, QgsUnitTypes.AngleUnit.AngleSecondsOfArc: 60.0, QgsUnitTypes.AngleUnit.AngleTurn: 4.62962962962963e-05, QgsUnitTypes.AngleUnit.AngleMilliradiansSI: 0.29088820866572157, QgsUnitTypes.AngleUnit.AngleMilNATO: 0.29629629629629634}, - QgsUnitTypes.AngleUnit.AngleSecondsOfArc: {QgsUnitTypes.AngleUnit.AngleDegrees: 0.00027777787722304257169, QgsUnitTypes.AngleUnit.AngleRadians: 4.848138546730629518e-6, QgsUnitTypes.AngleUnit.AngleGon: 0.0003086420910674814405, QgsUnitTypes.AngleUnit.AngleMinutesOfArc: 0.016666672633325253783, QgsUnitTypes.AngleUnit.AngleSecondsOfArc: 1.0, QgsUnitTypes.AngleUnit.AngleTurn: 7.71604938271605e-07, QgsUnitTypes.AngleUnit.AngleMilliradiansSI: 0.0048481482527009582897, QgsUnitTypes.AngleUnit.AngleMilNATO: 0.0049382716049382715}, - QgsUnitTypes.AngleUnit.AngleTurn: {QgsUnitTypes.AngleUnit.AngleDegrees: 360.0, QgsUnitTypes.AngleUnit.AngleRadians: 6.2831853071795, QgsUnitTypes.AngleUnit.AngleGon: 400.0, QgsUnitTypes.AngleUnit.AngleMinutesOfArc: 21600, QgsUnitTypes.AngleUnit.AngleSecondsOfArc: 1296000, QgsUnitTypes.AngleUnit.AngleTurn: 1, QgsUnitTypes.AngleUnit.AngleMilliradiansSI: 6283.185307179586, QgsUnitTypes.AngleUnit.AngleMilNATO: 6400}, - QgsUnitTypes.AngleUnit.AngleMilliradiansSI: {QgsUnitTypes.AngleUnit.AngleDegrees: 0.057295779513082325, QgsUnitTypes.AngleUnit.AngleRadians: 0.001, QgsUnitTypes.AngleUnit.AngleGon: 0.06366197723675814, QgsUnitTypes.AngleUnit.AngleMinutesOfArc: 3.4377467707849396, QgsUnitTypes.AngleUnit.AngleSecondsOfArc: 206.26480624709637, QgsUnitTypes.AngleUnit.AngleTurn: 0.0015707963267948967, QgsUnitTypes.AngleUnit.AngleMilliradiansSI: 1.0, QgsUnitTypes.AngleUnit.AngleMilNATO: 1.0185916357881302}, - QgsUnitTypes.AngleUnit.AngleMilNATO: {QgsUnitTypes.AngleUnit.AngleDegrees: 0.05625, - QgsUnitTypes.AngleUnit.AngleRadians: 0.0009817477042468104, - QgsUnitTypes.AngleUnit.AngleGon: 0.0625, - QgsUnitTypes.AngleUnit.AngleMinutesOfArc: 3.375, - QgsUnitTypes.AngleUnit.AngleSecondsOfArc: 202.5, - QgsUnitTypes.AngleUnit.AngleTurn: 0.000015625, - QgsUnitTypes.AngleUnit.AngleMilliradiansSI: 0.9817477042468102, - QgsUnitTypes.AngleUnit.AngleMilNATO: 1.0} - } + expected = { + QgsUnitTypes.AngleUnit.AngleDegrees: { + QgsUnitTypes.AngleUnit.AngleDegrees: 1.0, + QgsUnitTypes.AngleUnit.AngleRadians: 0.0174533, + QgsUnitTypes.AngleUnit.AngleGon: 1.1111111, + QgsUnitTypes.AngleUnit.AngleMinutesOfArc: 60, + QgsUnitTypes.AngleUnit.AngleSecondsOfArc: 3600, + QgsUnitTypes.AngleUnit.AngleTurn: 0.00277777777778, + QgsUnitTypes.AngleUnit.AngleMilliradiansSI: 17.453292519943297, + QgsUnitTypes.AngleUnit.AngleMilNATO: 17.77777777777778, + }, + QgsUnitTypes.AngleUnit.AngleRadians: { + QgsUnitTypes.AngleUnit.AngleDegrees: 57.2957795, + QgsUnitTypes.AngleUnit.AngleRadians: 1.0, + QgsUnitTypes.AngleUnit.AngleGon: 63.6619772, + QgsUnitTypes.AngleUnit.AngleMinutesOfArc: 3437.7467708, + QgsUnitTypes.AngleUnit.AngleSecondsOfArc: 206264.8062471, + QgsUnitTypes.AngleUnit.AngleTurn: 0.159154943092, + QgsUnitTypes.AngleUnit.AngleMilliradiansSI: 1000.0, + QgsUnitTypes.AngleUnit.AngleMilNATO: 1018.5916357881301, + }, + QgsUnitTypes.AngleUnit.AngleGon: { + QgsUnitTypes.AngleUnit.AngleDegrees: 0.9000000, + QgsUnitTypes.AngleUnit.AngleRadians: 0.015707968623450838802, + QgsUnitTypes.AngleUnit.AngleGon: 1.0, + QgsUnitTypes.AngleUnit.AngleMinutesOfArc: 54.0000000, + QgsUnitTypes.AngleUnit.AngleSecondsOfArc: 3240.0000000, + QgsUnitTypes.AngleUnit.AngleTurn: 0.0025, + QgsUnitTypes.AngleUnit.AngleMilliradiansSI: 15.707963267948967, + QgsUnitTypes.AngleUnit.AngleMilNATO: 16, + }, + QgsUnitTypes.AngleUnit.AngleMinutesOfArc: { + QgsUnitTypes.AngleUnit.AngleDegrees: 0.016666672633390722247, + QgsUnitTypes.AngleUnit.AngleRadians: 0.00029088831280398030638, + QgsUnitTypes.AngleUnit.AngleGon: 0.018518525464057963154, + QgsUnitTypes.AngleUnit.AngleMinutesOfArc: 1.0, + QgsUnitTypes.AngleUnit.AngleSecondsOfArc: 60.0, + QgsUnitTypes.AngleUnit.AngleTurn: 4.62962962962963e-05, + QgsUnitTypes.AngleUnit.AngleMilliradiansSI: 0.29088820866572157, + QgsUnitTypes.AngleUnit.AngleMilNATO: 0.29629629629629634, + }, + QgsUnitTypes.AngleUnit.AngleSecondsOfArc: { + QgsUnitTypes.AngleUnit.AngleDegrees: 0.00027777787722304257169, + QgsUnitTypes.AngleUnit.AngleRadians: 4.848138546730629518e-6, + QgsUnitTypes.AngleUnit.AngleGon: 0.0003086420910674814405, + QgsUnitTypes.AngleUnit.AngleMinutesOfArc: 0.016666672633325253783, + QgsUnitTypes.AngleUnit.AngleSecondsOfArc: 1.0, + QgsUnitTypes.AngleUnit.AngleTurn: 7.71604938271605e-07, + QgsUnitTypes.AngleUnit.AngleMilliradiansSI: 0.0048481482527009582897, + QgsUnitTypes.AngleUnit.AngleMilNATO: 0.0049382716049382715, + }, + QgsUnitTypes.AngleUnit.AngleTurn: { + QgsUnitTypes.AngleUnit.AngleDegrees: 360.0, + QgsUnitTypes.AngleUnit.AngleRadians: 6.2831853071795, + QgsUnitTypes.AngleUnit.AngleGon: 400.0, + QgsUnitTypes.AngleUnit.AngleMinutesOfArc: 21600, + QgsUnitTypes.AngleUnit.AngleSecondsOfArc: 1296000, + QgsUnitTypes.AngleUnit.AngleTurn: 1, + QgsUnitTypes.AngleUnit.AngleMilliradiansSI: 6283.185307179586, + QgsUnitTypes.AngleUnit.AngleMilNATO: 6400, + }, + QgsUnitTypes.AngleUnit.AngleMilliradiansSI: { + QgsUnitTypes.AngleUnit.AngleDegrees: 0.057295779513082325, + QgsUnitTypes.AngleUnit.AngleRadians: 0.001, + QgsUnitTypes.AngleUnit.AngleGon: 0.06366197723675814, + QgsUnitTypes.AngleUnit.AngleMinutesOfArc: 3.4377467707849396, + QgsUnitTypes.AngleUnit.AngleSecondsOfArc: 206.26480624709637, + QgsUnitTypes.AngleUnit.AngleTurn: 0.0015707963267948967, + QgsUnitTypes.AngleUnit.AngleMilliradiansSI: 1.0, + QgsUnitTypes.AngleUnit.AngleMilNATO: 1.0185916357881302, + }, + QgsUnitTypes.AngleUnit.AngleMilNATO: { + QgsUnitTypes.AngleUnit.AngleDegrees: 0.05625, + QgsUnitTypes.AngleUnit.AngleRadians: 0.0009817477042468104, + QgsUnitTypes.AngleUnit.AngleGon: 0.0625, + QgsUnitTypes.AngleUnit.AngleMinutesOfArc: 3.375, + QgsUnitTypes.AngleUnit.AngleSecondsOfArc: 202.5, + QgsUnitTypes.AngleUnit.AngleTurn: 0.000015625, + QgsUnitTypes.AngleUnit.AngleMilliradiansSI: 0.9817477042468102, + QgsUnitTypes.AngleUnit.AngleMilNATO: 1.0, + }, + } for from_unit in list(expected.keys()): for to_unit in list(expected[from_unit].keys()): expected_factor = expected[from_unit][to_unit] res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, to_unit) - self.assertAlmostEqual(res, - expected_factor, - msg='got {:.7f}, expected {:.7f} when converting from {} to {}'.format(res, expected_factor, - QgsUnitTypes.toString(from_unit), - QgsUnitTypes.toString(to_unit))) + self.assertAlmostEqual( + res, + expected_factor, + msg="got {:.7f}, expected {:.7f} when converting from {} to {}".format( + res, + expected_factor, + QgsUnitTypes.toString(from_unit), + QgsUnitTypes.toString(to_unit), + ), + ) # test conversion to unknown units - res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, QgsUnitTypes.AngleUnit.AngleUnknownUnit) - self.assertAlmostEqual(res, - 1.0, - msg=f'got {res:.7f}, expected 1.0 when converting from {QgsUnitTypes.toString(from_unit)} to unknown units') + res = QgsUnitTypes.fromUnitToUnitFactor( + from_unit, QgsUnitTypes.AngleUnit.AngleUnknownUnit + ) + self.assertAlmostEqual( + res, + 1.0, + msg=f"got {res:.7f}, expected 1.0 when converting from {QgsUnitTypes.toString(from_unit)} to unknown units", + ) def testFormatAngle(self): """Test formatting angles""" - self.assertEqual(QgsUnitTypes.formatAngle(45, 3, QgsUnitTypes.AngleUnit.AngleDegrees), '45.000°') - self.assertEqual(QgsUnitTypes.formatAngle(1, 2, QgsUnitTypes.AngleUnit.AngleRadians), '1.00 rad') - self.assertEqual(QgsUnitTypes.formatAngle(1, 0, QgsUnitTypes.AngleUnit.AngleGon), '1 gon') - self.assertEqual(QgsUnitTypes.formatAngle(1.11111111, 4, QgsUnitTypes.AngleUnit.AngleMinutesOfArc), '1.1111′') - self.assertEqual(QgsUnitTypes.formatAngle(1.99999999, 2, QgsUnitTypes.AngleUnit.AngleSecondsOfArc), '2.00″') - self.assertEqual(QgsUnitTypes.formatAngle(1, 2, QgsUnitTypes.AngleUnit.AngleTurn), '1.00 tr') - self.assertEqual(QgsUnitTypes.formatAngle(1, 2, QgsUnitTypes.AngleUnit.AngleMilliradiansSI), '1.00 millirad') - self.assertEqual(QgsUnitTypes.formatAngle(1, 2, QgsUnitTypes.AngleUnit.AngleMilNATO), '1.00 mil') - self.assertEqual(QgsUnitTypes.formatAngle(1, 2, QgsUnitTypes.AngleUnit.AngleUnknownUnit), '1.00') - - self.assertEqual(QgsUnitTypes.formatAngle(45, -1, QgsUnitTypes.AngleUnit.AngleDegrees), '45°') - self.assertEqual(QgsUnitTypes.formatAngle(1, -1, QgsUnitTypes.AngleUnit.AngleRadians), '1.00 rad') - self.assertEqual(QgsUnitTypes.formatAngle(1, -1, QgsUnitTypes.AngleUnit.AngleGon), '1 gon') - self.assertEqual(QgsUnitTypes.formatAngle(1.11111111, -1, QgsUnitTypes.AngleUnit.AngleMinutesOfArc), '1′') - self.assertEqual(QgsUnitTypes.formatAngle(1.99999999, -1, QgsUnitTypes.AngleUnit.AngleSecondsOfArc), '2″') - self.assertEqual(QgsUnitTypes.formatAngle(1, -1, QgsUnitTypes.AngleUnit.AngleTurn), '1.000 tr') - self.assertEqual(QgsUnitTypes.formatAngle(1, -1, QgsUnitTypes.AngleUnit.AngleMilliradiansSI), '1 millirad') - self.assertEqual(QgsUnitTypes.formatAngle(1, -1, QgsUnitTypes.AngleUnit.AngleMilNATO), '1 mil') - self.assertEqual(QgsUnitTypes.formatAngle(1, -1, QgsUnitTypes.AngleUnit.AngleUnknownUnit), '1.00') + self.assertEqual( + QgsUnitTypes.formatAngle(45, 3, QgsUnitTypes.AngleUnit.AngleDegrees), + "45.000°", + ) + self.assertEqual( + QgsUnitTypes.formatAngle(1, 2, QgsUnitTypes.AngleUnit.AngleRadians), + "1.00 rad", + ) + self.assertEqual( + QgsUnitTypes.formatAngle(1, 0, QgsUnitTypes.AngleUnit.AngleGon), "1 gon" + ) + self.assertEqual( + QgsUnitTypes.formatAngle( + 1.11111111, 4, QgsUnitTypes.AngleUnit.AngleMinutesOfArc + ), + "1.1111′", + ) + self.assertEqual( + QgsUnitTypes.formatAngle( + 1.99999999, 2, QgsUnitTypes.AngleUnit.AngleSecondsOfArc + ), + "2.00″", + ) + self.assertEqual( + QgsUnitTypes.formatAngle(1, 2, QgsUnitTypes.AngleUnit.AngleTurn), "1.00 tr" + ) + self.assertEqual( + QgsUnitTypes.formatAngle(1, 2, QgsUnitTypes.AngleUnit.AngleMilliradiansSI), + "1.00 millirad", + ) + self.assertEqual( + QgsUnitTypes.formatAngle(1, 2, QgsUnitTypes.AngleUnit.AngleMilNATO), + "1.00 mil", + ) + self.assertEqual( + QgsUnitTypes.formatAngle(1, 2, QgsUnitTypes.AngleUnit.AngleUnknownUnit), + "1.00", + ) + + self.assertEqual( + QgsUnitTypes.formatAngle(45, -1, QgsUnitTypes.AngleUnit.AngleDegrees), "45°" + ) + self.assertEqual( + QgsUnitTypes.formatAngle(1, -1, QgsUnitTypes.AngleUnit.AngleRadians), + "1.00 rad", + ) + self.assertEqual( + QgsUnitTypes.formatAngle(1, -1, QgsUnitTypes.AngleUnit.AngleGon), "1 gon" + ) + self.assertEqual( + QgsUnitTypes.formatAngle( + 1.11111111, -1, QgsUnitTypes.AngleUnit.AngleMinutesOfArc + ), + "1′", + ) + self.assertEqual( + QgsUnitTypes.formatAngle( + 1.99999999, -1, QgsUnitTypes.AngleUnit.AngleSecondsOfArc + ), + "2″", + ) + self.assertEqual( + QgsUnitTypes.formatAngle(1, -1, QgsUnitTypes.AngleUnit.AngleTurn), + "1.000 tr", + ) + self.assertEqual( + QgsUnitTypes.formatAngle(1, -1, QgsUnitTypes.AngleUnit.AngleMilliradiansSI), + "1 millirad", + ) + self.assertEqual( + QgsUnitTypes.formatAngle(1, -1, QgsUnitTypes.AngleUnit.AngleMilNATO), + "1 mil", + ) + self.assertEqual( + QgsUnitTypes.formatAngle(1, -1, QgsUnitTypes.AngleUnit.AngleUnknownUnit), + "1.00", + ) def testFormatDistance(self): """Test formatting distances""" # keep base unit - self.assertEqual(QgsUnitTypes.formatDistance(100, 3, QgsUnitTypes.DistanceUnit.DistanceMeters, True), '100.000 m') - self.assertEqual(QgsUnitTypes.formatDistance(10, 2, QgsUnitTypes.DistanceUnit.DistanceKilometers, True), '10.00 km') - self.assertEqual(QgsUnitTypes.formatDistance(1, 0, QgsUnitTypes.DistanceUnit.DistanceFeet, True), '1 ft') - self.assertEqual(QgsUnitTypes.formatDistance(1.11111111, 4, QgsUnitTypes.DistanceUnit.DistanceNauticalMiles, True), '1.1111 NM') - self.assertEqual(QgsUnitTypes.formatDistance(1.99999999, 2, QgsUnitTypes.DistanceUnit.DistanceYards, True), '2.00 yd') - self.assertEqual(QgsUnitTypes.formatDistance(1, 2, QgsUnitTypes.DistanceUnit.DistanceMiles, True), '1.00 mi') - self.assertEqual(QgsUnitTypes.formatDistance(1, 2, QgsUnitTypes.DistanceUnit.DistanceDegrees, True), '1.00 deg') - self.assertEqual(QgsUnitTypes.formatDistance(1, 2, QgsUnitTypes.DistanceUnit.DistanceCentimeters, True), '1.00 cm') - self.assertEqual(QgsUnitTypes.formatDistance(1, 2, QgsUnitTypes.DistanceUnit.DistanceMillimeters, True), '1.00 mm') - self.assertEqual( - QgsUnitTypes.formatDistance(1, 2, Qgis.DistanceUnit.Inches, - True), '1.00 in') - self.assertEqual(QgsUnitTypes.formatDistance(1, 2, QgsUnitTypes.DistanceUnit.DistanceUnknownUnit, True), '1.00') + self.assertEqual( + QgsUnitTypes.formatDistance( + 100, 3, QgsUnitTypes.DistanceUnit.DistanceMeters, True + ), + "100.000 m", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 10, 2, QgsUnitTypes.DistanceUnit.DistanceKilometers, True + ), + "10.00 km", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 1, 0, QgsUnitTypes.DistanceUnit.DistanceFeet, True + ), + "1 ft", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 1.11111111, 4, QgsUnitTypes.DistanceUnit.DistanceNauticalMiles, True + ), + "1.1111 NM", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 1.99999999, 2, QgsUnitTypes.DistanceUnit.DistanceYards, True + ), + "2.00 yd", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 1, 2, QgsUnitTypes.DistanceUnit.DistanceMiles, True + ), + "1.00 mi", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 1, 2, QgsUnitTypes.DistanceUnit.DistanceDegrees, True + ), + "1.00 deg", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 1, 2, QgsUnitTypes.DistanceUnit.DistanceCentimeters, True + ), + "1.00 cm", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 1, 2, QgsUnitTypes.DistanceUnit.DistanceMillimeters, True + ), + "1.00 mm", + ) + self.assertEqual( + QgsUnitTypes.formatDistance(1, 2, Qgis.DistanceUnit.Inches, True), "1.00 in" + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 1, 2, QgsUnitTypes.DistanceUnit.DistanceUnknownUnit, True + ), + "1.00", + ) # don't keep base unit - self.assertEqual(QgsUnitTypes.formatDistance(10, 3, QgsUnitTypes.DistanceUnit.DistanceMeters, False), '10.000 m') - self.assertEqual(QgsUnitTypes.formatDistance(1001, 3, QgsUnitTypes.DistanceUnit.DistanceMeters, False), '1.001 km') - self.assertEqual(QgsUnitTypes.formatDistance(0.05, 2, QgsUnitTypes.DistanceUnit.DistanceMeters, False), '5.00 cm') - self.assertEqual(QgsUnitTypes.formatDistance(0.005, 2, QgsUnitTypes.DistanceUnit.DistanceMeters, False), '5.00 mm') - self.assertEqual(QgsUnitTypes.formatDistance(10, 2, QgsUnitTypes.DistanceUnit.DistanceKilometers, False), '10.00 km') - self.assertEqual(QgsUnitTypes.formatDistance(0.5, 2, QgsUnitTypes.DistanceUnit.DistanceKilometers, False), '500.00 m') - self.assertEqual(QgsUnitTypes.formatDistance(10, 2, QgsUnitTypes.DistanceUnit.DistanceFeet, False), '10.00 ft') - self.assertEqual(QgsUnitTypes.formatDistance(6000, 2, QgsUnitTypes.DistanceUnit.DistanceFeet, False), '1.14 mi') - self.assertEqual(QgsUnitTypes.formatDistance(10, 2, QgsUnitTypes.DistanceUnit.DistanceYards, False), '10.00 yd') - self.assertEqual(QgsUnitTypes.formatDistance(2500, 2, QgsUnitTypes.DistanceUnit.DistanceYards, False), '1.42 mi') - self.assertEqual(QgsUnitTypes.formatDistance(1, 2, QgsUnitTypes.DistanceUnit.DistanceMiles, False), '1.00 mi') - self.assertEqual(QgsUnitTypes.formatDistance(0.5, 2, QgsUnitTypes.DistanceUnit.DistanceMiles, False), '2640.00 ft') - self.assertEqual(QgsUnitTypes.formatDistance(1.11111111, 4, QgsUnitTypes.DistanceUnit.DistanceNauticalMiles, False), '1.1111 NM') - self.assertEqual(QgsUnitTypes.formatDistance(0.001, 4, QgsUnitTypes.DistanceUnit.DistanceDegrees, False), '0.0010 deg') - self.assertEqual(QgsUnitTypes.formatDistance(100, 2, QgsUnitTypes.DistanceUnit.DistanceCentimeters, False), '100.00 cm') - self.assertEqual(QgsUnitTypes.formatDistance(1000, 2, QgsUnitTypes.DistanceUnit.DistanceMillimeters, False), '1000.00 mm') - self.assertEqual(QgsUnitTypes.formatDistance(1000, 2, - Qgis.DistanceUnit.Inches, - False), '1000.00 in') - self.assertEqual(QgsUnitTypes.formatDistance(1, 2, QgsUnitTypes.DistanceUnit.DistanceUnknownUnit, False), '1.00') + self.assertEqual( + QgsUnitTypes.formatDistance( + 10, 3, QgsUnitTypes.DistanceUnit.DistanceMeters, False + ), + "10.000 m", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 1001, 3, QgsUnitTypes.DistanceUnit.DistanceMeters, False + ), + "1.001 km", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 0.05, 2, QgsUnitTypes.DistanceUnit.DistanceMeters, False + ), + "5.00 cm", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 0.005, 2, QgsUnitTypes.DistanceUnit.DistanceMeters, False + ), + "5.00 mm", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 10, 2, QgsUnitTypes.DistanceUnit.DistanceKilometers, False + ), + "10.00 km", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 0.5, 2, QgsUnitTypes.DistanceUnit.DistanceKilometers, False + ), + "500.00 m", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 10, 2, QgsUnitTypes.DistanceUnit.DistanceFeet, False + ), + "10.00 ft", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 6000, 2, QgsUnitTypes.DistanceUnit.DistanceFeet, False + ), + "1.14 mi", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 10, 2, QgsUnitTypes.DistanceUnit.DistanceYards, False + ), + "10.00 yd", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 2500, 2, QgsUnitTypes.DistanceUnit.DistanceYards, False + ), + "1.42 mi", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 1, 2, QgsUnitTypes.DistanceUnit.DistanceMiles, False + ), + "1.00 mi", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 0.5, 2, QgsUnitTypes.DistanceUnit.DistanceMiles, False + ), + "2640.00 ft", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 1.11111111, 4, QgsUnitTypes.DistanceUnit.DistanceNauticalMiles, False + ), + "1.1111 NM", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 0.001, 4, QgsUnitTypes.DistanceUnit.DistanceDegrees, False + ), + "0.0010 deg", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 100, 2, QgsUnitTypes.DistanceUnit.DistanceCentimeters, False + ), + "100.00 cm", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 1000, 2, QgsUnitTypes.DistanceUnit.DistanceMillimeters, False + ), + "1000.00 mm", + ) + self.assertEqual( + QgsUnitTypes.formatDistance(1000, 2, Qgis.DistanceUnit.Inches, False), + "1000.00 in", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 1, 2, QgsUnitTypes.DistanceUnit.DistanceUnknownUnit, False + ), + "1.00", + ) # small values should not be displayed as zeroes, instead fallback to scientific notation - self.assertEqual(QgsUnitTypes.formatDistance(0.00168478, 2, QgsUnitTypes.DistanceUnit.DistanceMeters, False), '1.68 mm') - self.assertEqual(QgsUnitTypes.formatDistance(0.00000168478, 2, QgsUnitTypes.DistanceUnit.DistanceMeters, False), '1.68e-06 m') - self.assertEqual(QgsUnitTypes.formatDistance(0.00168478, 2, QgsUnitTypes.DistanceUnit.DistanceMeters, True), '1.68e-03 m') + self.assertEqual( + QgsUnitTypes.formatDistance( + 0.00168478, 2, QgsUnitTypes.DistanceUnit.DistanceMeters, False + ), + "1.68 mm", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 0.00000168478, 2, QgsUnitTypes.DistanceUnit.DistanceMeters, False + ), + "1.68e-06 m", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 0.00168478, 2, QgsUnitTypes.DistanceUnit.DistanceMeters, True + ), + "1.68e-03 m", + ) # test different locales QLocale.setDefault(QLocale(QLocale.Language.Italian)) - self.assertEqual(QgsUnitTypes.formatDistance(10, 3, QgsUnitTypes.DistanceUnit.DistanceMeters, False), '10,000 m') - self.assertEqual(QgsUnitTypes.formatDistance(0.5, 2, QgsUnitTypes.DistanceUnit.DistanceMiles, False), '2.640,00 ft') + self.assertEqual( + QgsUnitTypes.formatDistance( + 10, 3, QgsUnitTypes.DistanceUnit.DistanceMeters, False + ), + "10,000 m", + ) + self.assertEqual( + QgsUnitTypes.formatDistance( + 0.5, 2, QgsUnitTypes.DistanceUnit.DistanceMiles, False + ), + "2.640,00 ft", + ) def testFormatArea(self): """Test formatting areas""" # keep base unit - self.assertEqual(QgsUnitTypes.formatArea(100, 3, QgsUnitTypes.AreaUnit.AreaSquareMeters, True), '100.000 m²') - self.assertEqual(QgsUnitTypes.formatArea(10, 2, QgsUnitTypes.AreaUnit.AreaSquareKilometers, True), '10.00 km²') - self.assertEqual(QgsUnitTypes.formatArea(1, 0, QgsUnitTypes.AreaUnit.AreaSquareFeet, True), '1 ft²') - self.assertEqual(QgsUnitTypes.formatArea(1.11111111, 4, QgsUnitTypes.AreaUnit.AreaSquareYards, True), '1.1111 yd²') - self.assertEqual(QgsUnitTypes.formatArea(1.99999999, 2, QgsUnitTypes.AreaUnit.AreaSquareMiles, True), '2.00 mi²') - self.assertEqual(QgsUnitTypes.formatArea(1, 2, QgsUnitTypes.AreaUnit.AreaHectares, True), '1.00 ha') - self.assertEqual(QgsUnitTypes.formatArea(1, 2, QgsUnitTypes.AreaUnit.AreaAcres, True), '1.00 ac') - self.assertEqual(QgsUnitTypes.formatArea(1, 2, QgsUnitTypes.AreaUnit.AreaSquareNauticalMiles, True), '1.00 NM²') - self.assertEqual(QgsUnitTypes.formatArea(1, 2, QgsUnitTypes.AreaUnit.AreaSquareDegrees, True), '1.00 deg²') - self.assertEqual(QgsUnitTypes.formatArea(1, 2, QgsUnitTypes.AreaUnit.AreaSquareCentimeters, True), '1.00 cm²') - self.assertEqual(QgsUnitTypes.formatArea(1, 2, QgsUnitTypes.AreaUnit.AreaSquareMillimeters, True), '1.00 mm²') - self.assertEqual( - QgsUnitTypes.formatArea(1, 2, Qgis.AreaUnit.SquareInches, - True), '1.00 in²') - self.assertEqual(QgsUnitTypes.formatArea(1, 2, QgsUnitTypes.AreaUnit.AreaUnknownUnit, True), '1.00') + self.assertEqual( + QgsUnitTypes.formatArea( + 100, 3, QgsUnitTypes.AreaUnit.AreaSquareMeters, True + ), + "100.000 m²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 10, 2, QgsUnitTypes.AreaUnit.AreaSquareKilometers, True + ), + "10.00 km²", + ) + self.assertEqual( + QgsUnitTypes.formatArea(1, 0, QgsUnitTypes.AreaUnit.AreaSquareFeet, True), + "1 ft²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 1.11111111, 4, QgsUnitTypes.AreaUnit.AreaSquareYards, True + ), + "1.1111 yd²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 1.99999999, 2, QgsUnitTypes.AreaUnit.AreaSquareMiles, True + ), + "2.00 mi²", + ) + self.assertEqual( + QgsUnitTypes.formatArea(1, 2, QgsUnitTypes.AreaUnit.AreaHectares, True), + "1.00 ha", + ) + self.assertEqual( + QgsUnitTypes.formatArea(1, 2, QgsUnitTypes.AreaUnit.AreaAcres, True), + "1.00 ac", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 1, 2, QgsUnitTypes.AreaUnit.AreaSquareNauticalMiles, True + ), + "1.00 NM²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 1, 2, QgsUnitTypes.AreaUnit.AreaSquareDegrees, True + ), + "1.00 deg²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 1, 2, QgsUnitTypes.AreaUnit.AreaSquareCentimeters, True + ), + "1.00 cm²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 1, 2, QgsUnitTypes.AreaUnit.AreaSquareMillimeters, True + ), + "1.00 mm²", + ) + self.assertEqual( + QgsUnitTypes.formatArea(1, 2, Qgis.AreaUnit.SquareInches, True), "1.00 in²" + ) + self.assertEqual( + QgsUnitTypes.formatArea(1, 2, QgsUnitTypes.AreaUnit.AreaUnknownUnit, True), + "1.00", + ) # don't keep base unit - self.assertEqual(QgsUnitTypes.formatArea(100, 2, QgsUnitTypes.AreaUnit.AreaSquareMeters, False), '100.00 m²') - self.assertEqual(QgsUnitTypes.formatArea(2000000, 2, QgsUnitTypes.AreaUnit.AreaSquareMeters, False), '2.00 km²') - self.assertEqual(QgsUnitTypes.formatArea(10001, 2, QgsUnitTypes.AreaUnit.AreaSquareMeters, False), '1.00 ha') - self.assertEqual(QgsUnitTypes.formatArea(100, 2, QgsUnitTypes.AreaUnit.AreaSquareKilometers, False), '100.00 km²') - self.assertEqual(QgsUnitTypes.formatArea(0.5, 2, QgsUnitTypes.AreaUnit.AreaSquareKilometers, False), '0.50 km²') - self.assertEqual(QgsUnitTypes.formatArea(27879000, 2, QgsUnitTypes.AreaUnit.AreaSquareFeet, False), '1.00 mi²') - self.assertEqual(QgsUnitTypes.formatArea(2787, 2, QgsUnitTypes.AreaUnit.AreaSquareFeet, False), '2787.00 ft²') - self.assertEqual(QgsUnitTypes.formatArea(3099000, 2, QgsUnitTypes.AreaUnit.AreaSquareYards, False), '1.00 mi²') - self.assertEqual(QgsUnitTypes.formatArea(309, 2, QgsUnitTypes.AreaUnit.AreaSquareYards, False), '309.00 yd²') - self.assertEqual(QgsUnitTypes.formatArea(10, 2, QgsUnitTypes.AreaUnit.AreaSquareMiles, False), '10.00 mi²') - self.assertEqual(QgsUnitTypes.formatArea(0.05, 2, QgsUnitTypes.AreaUnit.AreaSquareMiles, False), '0.05 mi²') - self.assertEqual(QgsUnitTypes.formatArea(10, 2, QgsUnitTypes.AreaUnit.AreaHectares, False), '10.00 ha') - self.assertEqual(QgsUnitTypes.formatArea(110, 2, QgsUnitTypes.AreaUnit.AreaHectares, False), '1.10 km²') - self.assertEqual(QgsUnitTypes.formatArea(10, 2, QgsUnitTypes.AreaUnit.AreaAcres, False), '10.00 ac') - self.assertEqual(QgsUnitTypes.formatArea(650, 2, QgsUnitTypes.AreaUnit.AreaAcres, False), '1.02 mi²') - self.assertEqual(QgsUnitTypes.formatArea(0.01, 2, QgsUnitTypes.AreaUnit.AreaSquareNauticalMiles, False), '0.01 NM²') - self.assertEqual(QgsUnitTypes.formatArea(100, 2, QgsUnitTypes.AreaUnit.AreaSquareNauticalMiles, False), '100.00 NM²') - self.assertEqual(QgsUnitTypes.formatArea(0.0001, 4, QgsUnitTypes.AreaUnit.AreaSquareDegrees, False), '0.0001 deg²') - self.assertEqual(QgsUnitTypes.formatArea(0.0001, 4, QgsUnitTypes.AreaUnit.AreaSquareDegrees, False), '0.0001 deg²') - self.assertEqual(QgsUnitTypes.formatArea(1000, 4, QgsUnitTypes.AreaUnit.AreaSquareMillimeters, False), '0.0010 m²') - self.assertEqual(QgsUnitTypes.formatArea(100, 3, QgsUnitTypes.AreaUnit.AreaSquareCentimeters, False), '0.010 m²') - self.assertEqual(QgsUnitTypes.formatArea(10, 2, QgsUnitTypes.AreaUnit.AreaUnknownUnit, False), '10.00') - self.assertEqual( - QgsUnitTypes.formatArea(1000, 2, Qgis.AreaUnit.SquareInches, - False), '1000.00 in²') + self.assertEqual( + QgsUnitTypes.formatArea( + 100, 2, QgsUnitTypes.AreaUnit.AreaSquareMeters, False + ), + "100.00 m²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 2000000, 2, QgsUnitTypes.AreaUnit.AreaSquareMeters, False + ), + "2.00 km²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 10001, 2, QgsUnitTypes.AreaUnit.AreaSquareMeters, False + ), + "1.00 ha", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 100, 2, QgsUnitTypes.AreaUnit.AreaSquareKilometers, False + ), + "100.00 km²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 0.5, 2, QgsUnitTypes.AreaUnit.AreaSquareKilometers, False + ), + "0.50 km²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 27879000, 2, QgsUnitTypes.AreaUnit.AreaSquareFeet, False + ), + "1.00 mi²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 2787, 2, QgsUnitTypes.AreaUnit.AreaSquareFeet, False + ), + "2787.00 ft²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 3099000, 2, QgsUnitTypes.AreaUnit.AreaSquareYards, False + ), + "1.00 mi²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 309, 2, QgsUnitTypes.AreaUnit.AreaSquareYards, False + ), + "309.00 yd²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 10, 2, QgsUnitTypes.AreaUnit.AreaSquareMiles, False + ), + "10.00 mi²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 0.05, 2, QgsUnitTypes.AreaUnit.AreaSquareMiles, False + ), + "0.05 mi²", + ) + self.assertEqual( + QgsUnitTypes.formatArea(10, 2, QgsUnitTypes.AreaUnit.AreaHectares, False), + "10.00 ha", + ) + self.assertEqual( + QgsUnitTypes.formatArea(110, 2, QgsUnitTypes.AreaUnit.AreaHectares, False), + "1.10 km²", + ) + self.assertEqual( + QgsUnitTypes.formatArea(10, 2, QgsUnitTypes.AreaUnit.AreaAcres, False), + "10.00 ac", + ) + self.assertEqual( + QgsUnitTypes.formatArea(650, 2, QgsUnitTypes.AreaUnit.AreaAcres, False), + "1.02 mi²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 0.01, 2, QgsUnitTypes.AreaUnit.AreaSquareNauticalMiles, False + ), + "0.01 NM²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 100, 2, QgsUnitTypes.AreaUnit.AreaSquareNauticalMiles, False + ), + "100.00 NM²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 0.0001, 4, QgsUnitTypes.AreaUnit.AreaSquareDegrees, False + ), + "0.0001 deg²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 0.0001, 4, QgsUnitTypes.AreaUnit.AreaSquareDegrees, False + ), + "0.0001 deg²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 1000, 4, QgsUnitTypes.AreaUnit.AreaSquareMillimeters, False + ), + "0.0010 m²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 100, 3, QgsUnitTypes.AreaUnit.AreaSquareCentimeters, False + ), + "0.010 m²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 10, 2, QgsUnitTypes.AreaUnit.AreaUnknownUnit, False + ), + "10.00", + ) + self.assertEqual( + QgsUnitTypes.formatArea(1000, 2, Qgis.AreaUnit.SquareInches, False), + "1000.00 in²", + ) # small values should not be displayed as zeroes, instead fallback to scientific notation - self.assertEqual(QgsUnitTypes.formatArea(0.00168478, 4, QgsUnitTypes.AreaUnit.AreaSquareMeters, False), '0.0017 m²') - self.assertEqual(QgsUnitTypes.formatArea(0.00168478, 2, QgsUnitTypes.AreaUnit.AreaSquareMeters, False), '1.68e-03 m²') - self.assertEqual(QgsUnitTypes.formatArea(0.00168478, 2, QgsUnitTypes.AreaUnit.AreaSquareMeters, True), '1.68e-03 m²') + self.assertEqual( + QgsUnitTypes.formatArea( + 0.00168478, 4, QgsUnitTypes.AreaUnit.AreaSquareMeters, False + ), + "0.0017 m²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 0.00168478, 2, QgsUnitTypes.AreaUnit.AreaSquareMeters, False + ), + "1.68e-03 m²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 0.00168478, 2, QgsUnitTypes.AreaUnit.AreaSquareMeters, True + ), + "1.68e-03 m²", + ) # test different locales QLocale.setDefault(QLocale(QLocale.Language.Italian)) - self.assertEqual(QgsUnitTypes.formatArea(100, 2, QgsUnitTypes.AreaUnit.AreaSquareKilometers, False), '100,00 km²') - self.assertEqual(QgsUnitTypes.formatArea(2787, 2, QgsUnitTypes.AreaUnit.AreaSquareFeet, False), '2.787,00 ft²') + self.assertEqual( + QgsUnitTypes.formatArea( + 100, 2, QgsUnitTypes.AreaUnit.AreaSquareKilometers, False + ), + "100,00 km²", + ) + self.assertEqual( + QgsUnitTypes.formatArea( + 2787, 2, QgsUnitTypes.AreaUnit.AreaSquareFeet, False + ), + "2.787,00 ft²", + ) def testEncodeDecodeLayoutUnits(self): """Test encoding and decoding layout units""" - units = [QgsUnitTypes.LayoutUnit.LayoutMillimeters, - QgsUnitTypes.LayoutUnit.LayoutCentimeters, - QgsUnitTypes.LayoutUnit.LayoutMeters, - QgsUnitTypes.LayoutUnit.LayoutInches, - QgsUnitTypes.LayoutUnit.LayoutFeet, - QgsUnitTypes.LayoutUnit.LayoutPoints, - QgsUnitTypes.LayoutUnit.LayoutPicas, - QgsUnitTypes.LayoutUnit.LayoutPixels] + units = [ + QgsUnitTypes.LayoutUnit.LayoutMillimeters, + QgsUnitTypes.LayoutUnit.LayoutCentimeters, + QgsUnitTypes.LayoutUnit.LayoutMeters, + QgsUnitTypes.LayoutUnit.LayoutInches, + QgsUnitTypes.LayoutUnit.LayoutFeet, + QgsUnitTypes.LayoutUnit.LayoutPoints, + QgsUnitTypes.LayoutUnit.LayoutPicas, + QgsUnitTypes.LayoutUnit.LayoutPixels, + ] for u in units: res, ok = QgsUnitTypes.decodeLayoutUnit(QgsUnitTypes.encodeUnit(u)) @@ -1679,26 +2243,28 @@ def testEncodeDecodeLayoutUnits(self): self.assertEqual(res, u) # Test decoding bad units - res, ok = QgsUnitTypes.decodeLayoutUnit('bad') + res, ok = QgsUnitTypes.decodeLayoutUnit("bad") self.assertFalse(ok) # default units should be MM self.assertEqual(res, QgsUnitTypes.LayoutUnit.LayoutMillimeters) # Test that string is cleaned before decoding - res, ok = QgsUnitTypes.decodeLayoutUnit(' px ') + res, ok = QgsUnitTypes.decodeLayoutUnit(" px ") assert ok self.assertEqual(res, QgsUnitTypes.LayoutUnit.LayoutPixels) def testAbbreviateRenderUnits(self): """Test abbreviating render units""" - units = [QgsUnitTypes.RenderUnit.RenderMillimeters, - QgsUnitTypes.RenderUnit.RenderMapUnits, - QgsUnitTypes.RenderUnit.RenderPixels, - QgsUnitTypes.RenderUnit.RenderPercentage, - QgsUnitTypes.RenderUnit.RenderPoints, - QgsUnitTypes.RenderUnit.RenderInches, - QgsUnitTypes.RenderUnit.RenderUnknownUnit, - QgsUnitTypes.RenderUnit.RenderMetersInMapUnits] + units = [ + QgsUnitTypes.RenderUnit.RenderMillimeters, + QgsUnitTypes.RenderUnit.RenderMapUnits, + QgsUnitTypes.RenderUnit.RenderPixels, + QgsUnitTypes.RenderUnit.RenderPercentage, + QgsUnitTypes.RenderUnit.RenderPoints, + QgsUnitTypes.RenderUnit.RenderInches, + QgsUnitTypes.RenderUnit.RenderUnknownUnit, + QgsUnitTypes.RenderUnit.RenderMetersInMapUnits, + ] used = set() for u in units: @@ -1709,14 +2275,16 @@ def testAbbreviateRenderUnits(self): def testAbbreviateLayoutUnits(self): """Test abbreviating layout units""" - units = [QgsUnitTypes.LayoutUnit.LayoutMillimeters, - QgsUnitTypes.LayoutUnit.LayoutCentimeters, - QgsUnitTypes.LayoutUnit.LayoutMeters, - QgsUnitTypes.LayoutUnit.LayoutInches, - QgsUnitTypes.LayoutUnit.LayoutFeet, - QgsUnitTypes.LayoutUnit.LayoutPoints, - QgsUnitTypes.LayoutUnit.LayoutPicas, - QgsUnitTypes.LayoutUnit.LayoutPixels] + units = [ + QgsUnitTypes.LayoutUnit.LayoutMillimeters, + QgsUnitTypes.LayoutUnit.LayoutCentimeters, + QgsUnitTypes.LayoutUnit.LayoutMeters, + QgsUnitTypes.LayoutUnit.LayoutInches, + QgsUnitTypes.LayoutUnit.LayoutFeet, + QgsUnitTypes.LayoutUnit.LayoutPoints, + QgsUnitTypes.LayoutUnit.LayoutPicas, + QgsUnitTypes.LayoutUnit.LayoutPixels, + ] used = set() for u in units: diff --git a/tests/src/python/test_qgsunsetattributevalue.py b/tests/src/python/test_qgsunsetattributevalue.py index fa8f0e8f2f02..9109b15c68c8 100644 --- a/tests/src/python/test_qgsunsetattributevalue.py +++ b/tests/src/python/test_qgsunsetattributevalue.py @@ -7,9 +7,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = '(C) 2020 by Nyall Dawson' -__date__ = '29/07/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "(C) 2020 by Nyall Dawson" +__date__ = "29/07/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.core import QgsUnsetAttributeValue import unittest @@ -26,24 +27,33 @@ class TestQgsUnsetAttributeValue(QgisTestCase): def testClause(self): value = QgsUnsetAttributeValue() self.assertFalse(value.defaultValueClause()) - value = QgsUnsetAttributeValue('Autonumber') - self.assertEqual(value.defaultValueClause(), 'Autonumber') + value = QgsUnsetAttributeValue("Autonumber") + self.assertEqual(value.defaultValueClause(), "Autonumber") def testRepr(self): value = QgsUnsetAttributeValue() - self.assertEqual(str(value), '') - value = QgsUnsetAttributeValue('Autonumber') - self.assertEqual(str(value), '') + self.assertEqual(str(value), "") + value = QgsUnsetAttributeValue("Autonumber") + self.assertEqual(str(value), "") def testEquality(self): # we don't care about the default clause when comparing equality! - self.assertEqual(QgsUnsetAttributeValue('Autonumber'), QgsUnsetAttributeValue('Autonumber2')) - self.assertEqual(QgsUnsetAttributeValue('Autonumber'), QgsUnsetAttributeValue()) - self.assertEqual(QgsUnsetAttributeValue(), QgsUnsetAttributeValue('Autonumber2')) + self.assertEqual( + QgsUnsetAttributeValue("Autonumber"), QgsUnsetAttributeValue("Autonumber2") + ) + self.assertEqual(QgsUnsetAttributeValue("Autonumber"), QgsUnsetAttributeValue()) + self.assertEqual( + QgsUnsetAttributeValue(), QgsUnsetAttributeValue("Autonumber2") + ) # some deeper tests... - self.assertEqual([1, 2, QgsUnsetAttributeValue(), 3], [1, 2, QgsUnsetAttributeValue(), 3]) - self.assertEqual([1, 2, QgsUnsetAttributeValue(), 3], [1, 2, QgsUnsetAttributeValue('Autogenerate'), 3]) + self.assertEqual( + [1, 2, QgsUnsetAttributeValue(), 3], [1, 2, QgsUnsetAttributeValue(), 3] + ) + self.assertEqual( + [1, 2, QgsUnsetAttributeValue(), 3], + [1, 2, QgsUnsetAttributeValue("Autogenerate"), 3], + ) # requires fixes in QgsFeature! # feature = QgsFeature() @@ -54,16 +64,16 @@ def testEquality(self): # self.assertEqual(feature, feature2) def testEqualityToString(self): - self.assertEqual(QgsUnsetAttributeValue('Autonumber'), 'Autonumber') - self.assertNotEqual(QgsUnsetAttributeValue('Autonumberx'), 'Autonumber') - self.assertNotEqual(QgsUnsetAttributeValue('Autonumber'), '') - self.assertNotEqual(QgsUnsetAttributeValue(''), 'Autonumber') + self.assertEqual(QgsUnsetAttributeValue("Autonumber"), "Autonumber") + self.assertNotEqual(QgsUnsetAttributeValue("Autonumberx"), "Autonumber") + self.assertNotEqual(QgsUnsetAttributeValue("Autonumber"), "") + self.assertNotEqual(QgsUnsetAttributeValue(""), "Autonumber") - self.assertEqual('Autonumber', QgsUnsetAttributeValue('Autonumber')) - self.assertNotEqual('Autonumber', QgsUnsetAttributeValue('Autonumberx')) - self.assertNotEqual('', QgsUnsetAttributeValue('Autonumber')) - self.assertNotEqual('Autonumber', QgsUnsetAttributeValue('')) + self.assertEqual("Autonumber", QgsUnsetAttributeValue("Autonumber")) + self.assertNotEqual("Autonumber", QgsUnsetAttributeValue("Autonumberx")) + self.assertNotEqual("", QgsUnsetAttributeValue("Autonumber")) + self.assertNotEqual("Autonumber", QgsUnsetAttributeValue("")) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvaliditychecks.py b/tests/src/python/test_qgsvaliditychecks.py index 1c523e0c2960..cc8e0d522b0c 100644 --- a/tests/src/python/test_qgsvaliditychecks.py +++ b/tests/src/python/test_qgsvaliditychecks.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '03/12/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "03/12/2018" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.core import ( @@ -63,8 +64,8 @@ def my_check(context, feedback): def my_check2(context, feedback): res = QgsValidityCheckResult() res.type = QgsValidityCheckResult.Type.Warning - res.title = 'test' - res.detailedDescription = 'blah blah' + res.title = "test" + res.detailedDescription = "blah blah" return [res] @@ -80,25 +81,27 @@ def testDecorator(self): context = TestContext() feedback = QgsFeedback() - res = QgsApplication.validityCheckRegistry().runChecks(QgsAbstractValidityCheck.Type.TypeLayoutCheck, context, feedback) + res = QgsApplication.validityCheckRegistry().runChecks( + QgsAbstractValidityCheck.Type.TypeLayoutCheck, context, feedback + ) self.assertEqual(len(res), 1) - self.assertEqual(res[0].title, 'test') + self.assertEqual(res[0].title, "test") def testRegistry(self): registry = QgsValidityCheckRegistry() self.assertFalse(registry.checks()) # add a new check - c1 = TestCheck('c1', 'my check', 1, []) + c1 = TestCheck("c1", "my check", 1, []) registry.addCheck(c1) self.assertEqual(registry.checks(), [c1]) - c2 = TestCheck('c2', 'my check2', 1, []) + c2 = TestCheck("c2", "my check2", 1, []) registry.addCheck(c2) self.assertEqual(registry.checks(), [c1, c2]) registry.removeCheck(None) - c3 = TestCheck('c3', 'my check3', 1, []) + c3 = TestCheck("c3", "my check3", 1, []) # not in registry yet registry.removeCheck(c3) @@ -110,11 +113,11 @@ def testRegistry(self): def testRegistryChecks(self): registry = QgsValidityCheckRegistry() - c1 = TestCheck('c1', 'my check', 1, []) + c1 = TestCheck("c1", "my check", 1, []) registry.addCheck(c1) - c2 = TestCheck('c2', 'my check2', 2, []) + c2 = TestCheck("c2", "my check2", 2, []) registry.addCheck(c2) - c3 = TestCheck('c3', 'my check3', 1, []) + c3 = TestCheck("c3", "my check3", 1, []) registry.addCheck(c3) self.assertFalse(registry.checks(0)) @@ -125,45 +128,63 @@ def testRunChecks(self): registry = QgsValidityCheckRegistry() res1 = QgsValidityCheckResult() res1.type = QgsValidityCheckResult.Type.Warning - res1.title = 'test' - res1.detailedDescription = 'blah blah' + res1.title = "test" + res1.detailedDescription = "blah blah" - c1 = TestCheck('c1', 'my check', 1, [res1]) + c1 = TestCheck("c1", "my check", 1, [res1]) registry.addCheck(c1) res2 = QgsValidityCheckResult() res2.type = QgsValidityCheckResult.Type.Critical - res2.title = 'test2' - res2.detailedDescription = 'blah blah2' - c2 = TestCheck('c2', 'my check2', 2, [res2]) + res2.title = "test2" + res2.detailedDescription = "blah blah2" + c2 = TestCheck("c2", "my check2", 2, [res2]) registry.addCheck(c2) res3 = QgsValidityCheckResult() res3.type = QgsValidityCheckResult.Type.Warning - res3.title = 'test3' - res3.detailedDescription = 'blah blah3' + res3.title = "test3" + res3.detailedDescription = "blah blah3" res4 = QgsValidityCheckResult() res4.type = QgsValidityCheckResult.Type.Warning - res4.title = 'test4' - res4.detailedDescription = 'blah blah4' - c3 = TestCheck('c3', 'my check3', 1, [res3, res4]) + res4.title = "test4" + res4.detailedDescription = "blah blah4" + c3 = TestCheck("c3", "my check3", 1, [res3, res4]) registry.addCheck(c3) context = TestContext() feedback = QgsFeedback() self.assertFalse(registry.runChecks(0, context, feedback)) - self.assertEqual([r.type for r in registry.runChecks(1, context, feedback)], - [QgsValidityCheckResult.Type.Warning, QgsValidityCheckResult.Type.Warning, - QgsValidityCheckResult.Type.Warning]) - self.assertEqual([r.title for r in registry.runChecks(1, context, feedback)], ['test', 'test3', 'test4']) - self.assertEqual([r.detailedDescription for r in registry.runChecks(1, context, feedback)], - ['blah blah', 'blah blah3', 'blah blah4']) - - self.assertEqual([r.type for r in registry.runChecks(2, context, feedback)], [QgsValidityCheckResult.Type.Critical]) - self.assertEqual([r.title for r in registry.runChecks(2, context, feedback)], ['test2']) - self.assertEqual([r.detailedDescription for r in registry.runChecks(2, context, feedback)], ['blah blah2']) - - -if __name__ == '__main__': + self.assertEqual( + [r.type for r in registry.runChecks(1, context, feedback)], + [ + QgsValidityCheckResult.Type.Warning, + QgsValidityCheckResult.Type.Warning, + QgsValidityCheckResult.Type.Warning, + ], + ) + self.assertEqual( + [r.title for r in registry.runChecks(1, context, feedback)], + ["test", "test3", "test4"], + ) + self.assertEqual( + [r.detailedDescription for r in registry.runChecks(1, context, feedback)], + ["blah blah", "blah blah3", "blah blah4"], + ) + + self.assertEqual( + [r.type for r in registry.runChecks(2, context, feedback)], + [QgsValidityCheckResult.Type.Critical], + ) + self.assertEqual( + [r.title for r in registry.runChecks(2, context, feedback)], ["test2"] + ) + self.assertEqual( + [r.detailedDescription for r in registry.runChecks(2, context, feedback)], + ["blah blah2"], + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvalidityresultswidget.py b/tests/src/python/test_qgsvalidityresultswidget.py index 4690bce14e70..b8b36e469678 100644 --- a/tests/src/python/test_qgsvalidityresultswidget.py +++ b/tests/src/python/test_qgsvalidityresultswidget.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '03/12/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "03/12/2018" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.core import QgsValidityCheckResult @@ -24,42 +25,88 @@ class TestQgsValidityResultsWidget(QgisTestCase): def testModel(self): res1 = QgsValidityCheckResult() res1.type = QgsValidityCheckResult.Type.Warning - res1.title = 'test' - res1.detailedDescription = 'blah blah' + res1.title = "test" + res1.detailedDescription = "blah blah" res2 = QgsValidityCheckResult() res2.type = QgsValidityCheckResult.Type.Critical - res2.title = 'test2' - res2.detailedDescription = 'blah blah2' + res2.title = "test2" + res2.detailedDescription = "blah blah2" res3 = QgsValidityCheckResult() res3.type = QgsValidityCheckResult.Type.Warning - res3.title = 'test3' - res3.detailedDescription = 'blah blah3' + res3.title = "test3" + res3.detailedDescription = "blah blah3" res4 = QgsValidityCheckResult() res4.type = QgsValidityCheckResult.Type.Warning - res4.title = 'test4' - res4.detailedDescription = 'blah blah4' + res4.title = "test4" + res4.detailedDescription = "blah blah4" model = QgsValidityCheckResultsModel([]) self.assertEqual(model.rowCount(), 0) - self.assertFalse(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertFalse(model.data(model.index(-1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertFalse(model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) + self.assertFalse( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertFalse( + model.data(model.index(-1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertFalse( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) model = QgsValidityCheckResultsModel([res1, res2, res3, res4]) self.assertEqual(model.rowCount(), 4) - self.assertFalse(model.data(model.index(-1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'test') - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'test2') - self.assertEqual(model.data(model.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'test3') - self.assertEqual(model.data(model.index(3, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), 'test4') - self.assertFalse(model.data(model.index(4, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole)) - self.assertEqual(model.data(model.index(0, 0, QModelIndex()), QgsValidityCheckResultsModel.Roles.DescriptionRole), 'blah blah') - self.assertEqual(model.data(model.index(1, 0, QModelIndex()), QgsValidityCheckResultsModel.Roles.DescriptionRole), 'blah blah2') - self.assertEqual(model.data(model.index(2, 0, QModelIndex()), QgsValidityCheckResultsModel.Roles.DescriptionRole), 'blah blah3') - self.assertEqual(model.data(model.index(3, 0, QModelIndex()), QgsValidityCheckResultsModel.Roles.DescriptionRole), 'blah blah4') + self.assertFalse( + model.data(model.index(-1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertEqual( + model.data(model.index(0, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "test", + ) + self.assertEqual( + model.data(model.index(1, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "test2", + ) + self.assertEqual( + model.data(model.index(2, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "test3", + ) + self.assertEqual( + model.data(model.index(3, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole), + "test4", + ) + self.assertFalse( + model.data(model.index(4, 0, QModelIndex()), Qt.ItemDataRole.DisplayRole) + ) + self.assertEqual( + model.data( + model.index(0, 0, QModelIndex()), + QgsValidityCheckResultsModel.Roles.DescriptionRole, + ), + "blah blah", + ) + self.assertEqual( + model.data( + model.index(1, 0, QModelIndex()), + QgsValidityCheckResultsModel.Roles.DescriptionRole, + ), + "blah blah2", + ) + self.assertEqual( + model.data( + model.index(2, 0, QModelIndex()), + QgsValidityCheckResultsModel.Roles.DescriptionRole, + ), + "blah blah3", + ) + self.assertEqual( + model.data( + model.index(3, 0, QModelIndex()), + QgsValidityCheckResultsModel.Roles.DescriptionRole, + ), + "blah blah4", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvariantutils.py b/tests/src/python/test_qgsvariantutils.py index df62fe81c362..32be50c1a13b 100644 --- a/tests/src/python/test_qgsvariantutils.py +++ b/tests/src/python/test_qgsvariantutils.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """QGIS Unit tests for QgsVariantUtils. From build dir, run: ctest -R PyQgsVariantUtils -V @@ -9,9 +8,10 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '11/10/224' -__copyright__ = 'Copyright 2024, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "11/10/224" +__copyright__ = "Copyright 2024, The QGIS Project" from qgis.PyQt.QtCore import QVariant, QMetaType @@ -44,5 +44,5 @@ def test_is_numeric_type(self): self.assertFalse(QgsVariantUtils.isNumericType(QMetaType.Type.QTime)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorfieldmarkersymbollayer.py b/tests/src/python/test_qgsvectorfieldmarkersymbollayer.py index caaa37132dba..2fee2a0f29ce 100644 --- a/tests/src/python/test_qgsvectorfieldmarkersymbollayer.py +++ b/tests/src/python/test_qgsvectorfieldmarkersymbollayer.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Nyall Dawson' -__date__ = 'November 2021' -__copyright__ = '(C) 2021, Nyall Dawson' +__author__ = "Nyall Dawson" +__date__ = "November 2021" +__copyright__ = "(C) 2021, Nyall Dawson" from qgis.PyQt.QtCore import QVariant from qgis.PyQt.QtGui import QColor, QImage, QPainter @@ -53,18 +53,20 @@ def testRender(self): s.deleteSymbolLayer(0) field_marker = QgsVectorFieldSymbolLayer() - field_marker.setXAttribute('x') - field_marker.setYAttribute('y') + field_marker.setXAttribute("x") + field_marker.setYAttribute("y") field_marker.setScale(4) - field_marker.setSubSymbol(QgsLineSymbol.createSimple({'color': '#ff0000', 'width': '2'})) + field_marker.setSubSymbol( + QgsLineSymbol.createSimple({"color": "#ff0000", "width": "2"}) + ) s.appendSymbolLayer(field_marker.clone()) - g = QgsGeometry.fromWkt('Point(5 4)') + g = QgsGeometry.fromWkt("Point(5 4)") fields = QgsFields() - fields.append(QgsField('x', QVariant.Double)) - fields.append(QgsField('y', QVariant.Double)) + fields.append(QgsField("x", QVariant.Double)) + fields.append(QgsField("y", QVariant.Double)) f = QgsFeature(fields) f.setAttributes([2, 3]) f.setGeometry(g) @@ -72,11 +74,11 @@ def testRender(self): rendered_image = self.renderFeature(s, f) self.assertTrue( self.image_check( - 'vectorfield', - 'vectorfield', + "vectorfield", + "vectorfield", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -86,18 +88,20 @@ def testMapRotation(self): s.deleteSymbolLayer(0) field_marker = QgsVectorFieldSymbolLayer() - field_marker.setXAttribute('x') - field_marker.setYAttribute('y') + field_marker.setXAttribute("x") + field_marker.setYAttribute("y") field_marker.setScale(4) - field_marker.setSubSymbol(QgsLineSymbol.createSimple({'color': '#ff0000', 'width': '2'})) + field_marker.setSubSymbol( + QgsLineSymbol.createSimple({"color": "#ff0000", "width": "2"}) + ) s.appendSymbolLayer(field_marker.clone()) - g = QgsGeometry.fromWkt('Point(5 4)') + g = QgsGeometry.fromWkt("Point(5 4)") fields = QgsFields() - fields.append(QgsField('x', QVariant.Double)) - fields.append(QgsField('y', QVariant.Double)) + fields.append(QgsField("x", QVariant.Double)) + fields.append(QgsField("y", QVariant.Double)) f = QgsFeature(fields) f.setAttributes([2, 3]) f.setGeometry(g) @@ -105,11 +109,11 @@ def testMapRotation(self): rendered_image = self.renderFeature(s, f, map_rotation=45) self.assertTrue( self.image_check( - 'rotated_map', - 'rotated_map', + "rotated_map", + "rotated_map", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -119,19 +123,23 @@ def testHeight(self): s.deleteSymbolLayer(0) field_marker = QgsVectorFieldSymbolLayer() - field_marker.setXAttribute('x') - field_marker.setYAttribute('y') + field_marker.setXAttribute("x") + field_marker.setYAttribute("y") field_marker.setScale(4) - field_marker.setVectorFieldType(QgsVectorFieldSymbolLayer.VectorFieldType.Height) + field_marker.setVectorFieldType( + QgsVectorFieldSymbolLayer.VectorFieldType.Height + ) - field_marker.setSubSymbol(QgsLineSymbol.createSimple({'color': '#ff0000', 'width': '2'})) + field_marker.setSubSymbol( + QgsLineSymbol.createSimple({"color": "#ff0000", "width": "2"}) + ) s.appendSymbolLayer(field_marker.clone()) - g = QgsGeometry.fromWkt('Point(5 4)') + g = QgsGeometry.fromWkt("Point(5 4)") fields = QgsFields() - fields.append(QgsField('x', QVariant.Double)) - fields.append(QgsField('y', QVariant.Double)) + fields.append(QgsField("x", QVariant.Double)) + fields.append(QgsField("y", QVariant.Double)) f = QgsFeature(fields) f.setAttributes([2, 3]) f.setGeometry(g) @@ -139,11 +147,11 @@ def testHeight(self): rendered_image = self.renderFeature(s, f) self.assertTrue( self.image_check( - 'height', - 'height', + "height", + "height", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -153,19 +161,21 @@ def testPolar(self): s.deleteSymbolLayer(0) field_marker = QgsVectorFieldSymbolLayer() - field_marker.setXAttribute('x') - field_marker.setYAttribute('y') + field_marker.setXAttribute("x") + field_marker.setYAttribute("y") field_marker.setVectorFieldType(QgsVectorFieldSymbolLayer.VectorFieldType.Polar) field_marker.setScale(1) - field_marker.setSubSymbol(QgsLineSymbol.createSimple({'color': '#ff0000', 'width': '2'})) + field_marker.setSubSymbol( + QgsLineSymbol.createSimple({"color": "#ff0000", "width": "2"}) + ) s.appendSymbolLayer(field_marker.clone()) - g = QgsGeometry.fromWkt('Point(5 4)') + g = QgsGeometry.fromWkt("Point(5 4)") fields = QgsFields() - fields.append(QgsField('x', QVariant.Double)) - fields.append(QgsField('y', QVariant.Double)) + fields.append(QgsField("x", QVariant.Double)) + fields.append(QgsField("y", QVariant.Double)) f = QgsFeature(fields) f.setAttributes([6, 135]) f.setGeometry(g) @@ -173,11 +183,7 @@ def testPolar(self): rendered_image = self.renderFeature(s, f) self.assertTrue( self.image_check( - 'polar', - 'polar', - rendered_image, - color_tolerance=2, - allowed_mismatch=20 + "polar", "polar", rendered_image, color_tolerance=2, allowed_mismatch=20 ) ) @@ -187,20 +193,24 @@ def testPolarAnticlockwise(self): s.deleteSymbolLayer(0) field_marker = QgsVectorFieldSymbolLayer() - field_marker.setXAttribute('x') - field_marker.setYAttribute('y') + field_marker.setXAttribute("x") + field_marker.setYAttribute("y") field_marker.setVectorFieldType(QgsVectorFieldSymbolLayer.VectorFieldType.Polar) - field_marker.setAngleOrientation(QgsVectorFieldSymbolLayer.AngleOrientation.CounterclockwiseFromEast) + field_marker.setAngleOrientation( + QgsVectorFieldSymbolLayer.AngleOrientation.CounterclockwiseFromEast + ) field_marker.setScale(1) - field_marker.setSubSymbol(QgsLineSymbol.createSimple({'color': '#ff0000', 'width': '2'})) + field_marker.setSubSymbol( + QgsLineSymbol.createSimple({"color": "#ff0000", "width": "2"}) + ) s.appendSymbolLayer(field_marker.clone()) - g = QgsGeometry.fromWkt('Point(5 4)') + g = QgsGeometry.fromWkt("Point(5 4)") fields = QgsFields() - fields.append(QgsField('x', QVariant.Double)) - fields.append(QgsField('y', QVariant.Double)) + fields.append(QgsField("x", QVariant.Double)) + fields.append(QgsField("y", QVariant.Double)) f = QgsFeature(fields) f.setAttributes([6, 135]) f.setGeometry(g) @@ -208,11 +218,11 @@ def testPolarAnticlockwise(self): rendered_image = self.renderFeature(s, f) self.assertTrue( self.image_check( - 'anticlockwise_polar', - 'anticlockwise_polar', + "anticlockwise_polar", + "anticlockwise_polar", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -222,20 +232,22 @@ def testPolarRadians(self): s.deleteSymbolLayer(0) field_marker = QgsVectorFieldSymbolLayer() - field_marker.setXAttribute('x') - field_marker.setYAttribute('y') + field_marker.setXAttribute("x") + field_marker.setYAttribute("y") field_marker.setVectorFieldType(QgsVectorFieldSymbolLayer.VectorFieldType.Polar) field_marker.setScale(1) field_marker.setAngleUnits(QgsVectorFieldSymbolLayer.AngleUnits.Radians) - field_marker.setSubSymbol(QgsLineSymbol.createSimple({'color': '#ff0000', 'width': '2'})) + field_marker.setSubSymbol( + QgsLineSymbol.createSimple({"color": "#ff0000", "width": "2"}) + ) s.appendSymbolLayer(field_marker.clone()) - g = QgsGeometry.fromWkt('Point(5 4)') + g = QgsGeometry.fromWkt("Point(5 4)") fields = QgsFields() - fields.append(QgsField('x', QVariant.Double)) - fields.append(QgsField('y', QVariant.Double)) + fields.append(QgsField("x", QVariant.Double)) + fields.append(QgsField("y", QVariant.Double)) f = QgsFeature(fields) f.setAttributes([6, 135]) f.setGeometry(g) @@ -243,11 +255,11 @@ def testPolarRadians(self): rendered_image = self.renderFeature(s, f) self.assertTrue( self.image_check( - 'radians_polar', - 'radians_polar', + "radians_polar", + "radians_polar", rendered_image, color_tolerance=2, - allowed_mismatch=20 + allowed_mismatch=20, ) ) @@ -283,5 +295,5 @@ def renderFeature(self, symbol, f, buffer=20, map_rotation=0): return image -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorfilewriter.py b/tests/src/python/test_qgsvectorfilewriter.py index fec0eb70fec7..a1a2f6dcbffe 100644 --- a/tests/src/python/test_qgsvectorfilewriter.py +++ b/tests/src/python/test_qgsvectorfilewriter.py @@ -6,9 +6,9 @@ (at your option) any later version. """ -__author__ = 'Tim Sutton' -__date__ = '20/08/2012' -__copyright__ = 'Copyright 2012, The QGIS Project' +__author__ = "Tim Sutton" +__date__ = "20/08/2012" +__copyright__ = "Copyright 2012, The QGIS Project" import os import tempfile @@ -50,7 +50,7 @@ QgsVectorFileWriter, QgsVectorLayer, QgsWkbTypes, - QgsFieldConstraints + QgsFieldConstraints, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -62,7 +62,7 @@ def GDAL_COMPUTE_VERSION(maj, min, rev): - return ((maj) * 1000000 + (min) * 10000 + (rev) * 100) + return (maj) * 1000000 + (min) * 10000 + (rev) * 100 class TestFieldValueConverter(QgsVectorFileWriter.FieldValueConverter): @@ -76,18 +76,18 @@ def fieldDefinition(self, field): if idx == 0: return self.layer.fields()[idx] elif idx == 2: - return QgsField('conv_attr', QVariant.String) - return QgsField('unexpected_idx') + return QgsField("conv_attr", QVariant.String) + return QgsField("unexpected_idx") def convert(self, idx, value): if idx == 0: return value elif idx == 2: if value == 3: - return 'converted_val' + return "converted_val" else: - return 'unexpected_val!' - return 'unexpected_idx' + return "unexpected_val!" + return "unexpected_idx" class TestQgsVectorFileWriter(QgisTestCase): @@ -96,104 +96,114 @@ class TestQgsVectorFileWriter(QgisTestCase): def testWrite(self): """Check we can write a vector file.""" self.mMemoryLayer = QgsVectorLayer( - ('Point?crs=epsg:4326&field=name:string(20)&' - 'field=age:integer&field=size:double&index=yes'), - 'test', - 'memory') - - self.assertIsNotNone(self.mMemoryLayer, 'Provider not initialized') + ( + "Point?crs=epsg:4326&field=name:string(20)&" + "field=age:integer&field=size:double&index=yes" + ), + "test", + "memory", + ) + + self.assertIsNotNone(self.mMemoryLayer, "Provider not initialized") myProvider = self.mMemoryLayer.dataProvider() self.assertIsNotNone(myProvider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) - ft.setAttributes(['Johny', 20, 0.3]) + ft.setAttributes(["Johny", 20, 0.3]) myResult, myFeatures = myProvider.addFeatures([ft]) self.assertTrue(myResult) self.assertTrue(myFeatures) - writeShape(self.mMemoryLayer, 'writetest.shp') + writeShape(self.mMemoryLayer, "writetest.shp") def testWritePreferAlias(self): """Test preferring field alias.""" layer = QgsVectorLayer( - ('Point?crs=epsg:4326&field=name:string(20)&' - 'field=age:integer&field=size:double&index=yes'), - 'test', - 'memory') + ( + "Point?crs=epsg:4326&field=name:string(20)&" + "field=age:integer&field=size:double&index=yes" + ), + "test", + "memory", + ) self.assertTrue(layer.isValid()) myProvider = layer.dataProvider() - layer.setFieldAlias(0, 'My Name') - layer.setFieldAlias(2, 'My Size') + layer.setFieldAlias(0, "My Name") + layer.setFieldAlias(2, "My Size") ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) - ft.setAttributes(['Johny', 20, 0.3]) + ft.setAttributes(["Johny", 20, 0.3]) myResult, myFeatures = myProvider.addFeatures([ft]) self.assertTrue(myResult) self.assertTrue(myFeatures) options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'ESRI Shapefile' + options.driverName = "ESRI Shapefile" options.fieldNameSource = QgsVectorFileWriter.FieldNameSource.Original - dest = os.path.join(str(QDir.tempPath()), 'alias.shp') + dest = os.path.join(str(QDir.tempPath()), "alias.shp") result, err = QgsVectorFileWriter.writeAsVectorFormatV2( - layer, - dest, - QgsProject.instance().transformContext(), - options) + layer, dest, QgsProject.instance().transformContext(), options + ) self.assertEqual(result, QgsVectorFileWriter.WriterError.NoError) - res = QgsVectorLayer(dest, 'result') + res = QgsVectorLayer(dest, "result") self.assertTrue(res.isValid()) - self.assertEqual([f.name() for f in res.fields()], ['name', 'age', 'size']) + self.assertEqual([f.name() for f in res.fields()], ["name", "age", "size"]) options.fieldNameSource = QgsVectorFileWriter.FieldNameSource.PreferAlias - dest = os.path.join(str(QDir.tempPath()), 'alias2.shp') + dest = os.path.join(str(QDir.tempPath()), "alias2.shp") result, err = QgsVectorFileWriter.writeAsVectorFormatV2( - layer, - dest, - QgsProject.instance().transformContext(), - options) + layer, dest, QgsProject.instance().transformContext(), options + ) self.assertEqual(result, QgsVectorFileWriter.WriterError.NoError) - res = QgsVectorLayer(dest, 'result') + res = QgsVectorLayer(dest, "result") self.assertTrue(res.isValid()) - self.assertEqual([f.name() for f in res.fields()], ['My Name', 'age', 'My Size']) + self.assertEqual( + [f.name() for f in res.fields()], ["My Name", "age", "My Size"] + ) def testWriteWithLongLongField(self): - ml = QgsVectorLayer('NoGeometry?crs=epsg:4326&field=fldlonglong:long', - 'test2', 'memory') + ml = QgsVectorLayer( + "NoGeometry?crs=epsg:4326&field=fldlonglong:long", "test2", "memory" + ) provider = ml.dataProvider() feat = QgsFeature() feat.setAttributes([2262000000]) provider.addFeatures([feat]) - filename = os.path.join(str(QDir.tempPath()), 'with_longlong_field') - crs = QgsCoordinateReferenceSystem('EPSG:4326') - rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat(ml, filename, 'utf-8', crs, 'GPKG') + filename = os.path.join(str(QDir.tempPath()), "with_longlong_field") + crs = QgsCoordinateReferenceSystem("EPSG:4326") + rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat( + ml, filename, "utf-8", crs, "GPKG" + ) # open the resulting geopackage - vl = QgsVectorLayer(filename + '.gpkg', '', 'ogr') + vl = QgsVectorLayer(filename + ".gpkg", "", "ogr") self.assertTrue(vl.isValid()) # test values - idx = vl.fields().indexFromName('fldlonglong') + idx = vl.fields().indexFromName("fldlonglong") self.assertEqual(vl.getFeature(1).attributes()[idx], 2262000000) del vl - os.unlink(filename + '.gpkg') + os.unlink(filename + ".gpkg") def testDateTimeWriteShapefile(self): """Check writing date and time fields to an ESRI shapefile.""" ml = QgsVectorLayer( - ('Point?crs=epsg:4326&field=id:int&' - 'field=date_f:date&field=time_f:time&field=dt_f:datetime'), - 'test', - 'memory') + ( + "Point?crs=epsg:4326&field=id:int&" + "field=date_f:date&field=time_f:time&field=dt_f:datetime" + ), + "test", + "memory", + ) self.assertTrue(ml.isValid()) provider = ml.dataProvider() @@ -201,65 +211,82 @@ def testDateTimeWriteShapefile(self): ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) - ft.setAttributes([1, QDate(2014, 3, 5), QTime(13, 45, 22), QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22))]) + ft.setAttributes( + [ + 1, + QDate(2014, 3, 5), + QTime(13, 45, 22), + QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22)), + ] + ) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) - dest_file_name = os.path.join(str(QDir.tempPath()), 'datetime.shp') - crs = QgsCoordinateReferenceSystem('EPSG:4326') + dest_file_name = os.path.join(str(QDir.tempPath()), "datetime.shp") + crs = QgsCoordinateReferenceSystem("EPSG:4326") write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - ml, - dest_file_name, - 'utf-8', - crs, - 'ESRI Shapefile') - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + ml, dest_file_name, "utf-8", crs, "ESRI Shapefile" + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Open result and check - created_layer = QgsVectorLayer(f'{dest_file_name}|layerid=0', 'test', 'ogr') + created_layer = QgsVectorLayer(f"{dest_file_name}|layerid=0", "test", "ogr") fields = created_layer.dataProvider().fields() - self.assertEqual(fields.at(fields.indexFromName('date_f')).type(), QVariant.Date) + self.assertEqual( + fields.at(fields.indexFromName("date_f")).type(), QVariant.Date + ) # shapefiles do not support time types, result should be string - self.assertEqual(fields.at(fields.indexFromName('time_f')).type(), QVariant.String) + self.assertEqual( + fields.at(fields.indexFromName("time_f")).type(), QVariant.String + ) # shapefiles do not support datetime types, result should be string - self.assertEqual(fields.at(fields.indexFromName('dt_f')).type(), QVariant.String) + self.assertEqual( + fields.at(fields.indexFromName("dt_f")).type(), QVariant.String + ) f = next(created_layer.getFeatures(QgsFeatureRequest())) - date_idx = created_layer.fields().lookupField('date_f') + date_idx = created_layer.fields().lookupField("date_f") self.assertIsInstance(f.attributes()[date_idx], QDate) self.assertEqual(f.attributes()[date_idx], QDate(2014, 3, 5)) - time_idx = created_layer.fields().lookupField('time_f') + time_idx = created_layer.fields().lookupField("time_f") # shapefiles do not support time types self.assertIsInstance(f.attributes()[time_idx], str) - self.assertTrue(f.attributes()[time_idx].startswith('13:45:22')) + self.assertTrue(f.attributes()[time_idx].startswith("13:45:22")) # shapefiles do not support datetime types - datetime_idx = created_layer.fields().lookupField('dt_f') + datetime_idx = created_layer.fields().lookupField("dt_f") self.assertIsInstance(f.attributes()[datetime_idx], str) - self.assertEqual(f.attributes()[datetime_idx], - QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22)).toString("yyyy/MM/dd hh:mm:ss.zzz")) + self.assertEqual( + f.attributes()[datetime_idx], + QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22)).toString( + "yyyy/MM/dd hh:mm:ss.zzz" + ), + ) def testWriterWithExtent(self): """Check writing using extent filter.""" - source_file = os.path.join(TEST_DATA_DIR, 'points.shp') - source_layer = QgsVectorLayer(source_file, 'Points', 'ogr') + source_file = os.path.join(TEST_DATA_DIR, "points.shp") + source_layer = QgsVectorLayer(source_file, "Points", "ogr") self.assertTrue(source_layer.isValid()) options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'ESRI Shapefile' + options.driverName = "ESRI Shapefile" options.filterExtent = QgsRectangle(-111, 26, -96, 38) - dest_file_name = os.path.join(str(QDir.tempPath()), 'extent_no_transform.shp') + dest_file_name = os.path.join(str(QDir.tempPath()), "extent_no_transform.shp") write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - source_layer, - dest_file_name, - options) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + source_layer, dest_file_name, options + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Open result and check - created_layer = QgsVectorLayer(f'{dest_file_name}|layerid=0', 'test', 'ogr') + created_layer = QgsVectorLayer(f"{dest_file_name}|layerid=0", "test", "ogr") features = [f for f in created_layer.getFeatures()] self.assertEqual(len(features), 5) for f in features: @@ -267,24 +294,29 @@ def testWriterWithExtent(self): def testWriterWithExtentAndReprojection(self): """Check writing using extent filter with reprojection.""" - source_file = os.path.join(TEST_DATA_DIR, 'points.shp') - source_layer = QgsVectorLayer(source_file, 'Points', 'ogr') + source_file = os.path.join(TEST_DATA_DIR, "points.shp") + source_layer = QgsVectorLayer(source_file, "Points", "ogr") self.assertTrue(source_layer.isValid()) options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'ESRI Shapefile' + options.driverName = "ESRI Shapefile" options.filterExtent = QgsRectangle(-12511460, 3045157, -10646621, 4683497) - options.ct = QgsCoordinateTransform(source_layer.crs(), QgsCoordinateReferenceSystem.fromEpsgId(3785), QgsProject.instance()) + options.ct = QgsCoordinateTransform( + source_layer.crs(), + QgsCoordinateReferenceSystem.fromEpsgId(3785), + QgsProject.instance(), + ) - dest_file_name = os.path.join(str(QDir.tempPath()), 'extent_transform.shp') + dest_file_name = os.path.join(str(QDir.tempPath()), "extent_transform.shp") write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - source_layer, - dest_file_name, - options) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + source_layer, dest_file_name, options + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Open result and check - created_layer = QgsVectorLayer(f'{dest_file_name}|layerid=0', 'test', 'ogr') + created_layer = QgsVectorLayer(f"{dest_file_name}|layerid=0", "test", "ogr") features = [f for f in created_layer.getFeatures()] self.assertEqual(len(features), 5) for f in features: @@ -293,69 +325,84 @@ def testWriterWithExtentAndReprojection(self): def testDateTimeWriteTabfile(self): """Check writing date and time fields to an MapInfo tabfile.""" ml = QgsVectorLayer( - ('Point?crs=epsg:4326&field=id:int&' - 'field=date_f:date&field=time_f:time&field=dt_f:datetime'), - 'test', - 'memory') - - self.assertIsNotNone(ml, 'Provider not initialized') - self.assertTrue(ml.isValid(), 'Source layer not valid') + ( + "Point?crs=epsg:4326&field=id:int&" + "field=date_f:date&field=time_f:time&field=dt_f:datetime" + ), + "test", + "memory", + ) + + self.assertIsNotNone(ml, "Provider not initialized") + self.assertTrue(ml.isValid(), "Source layer not valid") provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) - ft.setAttributes([1, QDate(2014, 3, 5), QTime(13, 45, 22), QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22))]) + ft.setAttributes( + [ + 1, + QDate(2014, 3, 5), + QTime(13, 45, 22), + QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22)), + ] + ) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) - dest_file_name = os.path.join(str(QDir.tempPath()), 'datetime.tab') - crs = QgsCoordinateReferenceSystem('EPSG:4326') + dest_file_name = os.path.join(str(QDir.tempPath()), "datetime.tab") + crs = QgsCoordinateReferenceSystem("EPSG:4326") write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - ml, - dest_file_name, - 'utf-8', - crs, - 'MapInfo File') - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + ml, dest_file_name, "utf-8", crs, "MapInfo File" + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Open result and check - created_layer = QgsVectorLayer(f'{dest_file_name}|layerid=0', 'test', 'ogr') + created_layer = QgsVectorLayer(f"{dest_file_name}|layerid=0", "test", "ogr") fields = created_layer.dataProvider().fields() - self.assertEqual(fields.at(fields.indexFromName('date_f')).type(), QVariant.Date) - self.assertEqual(fields.at(fields.indexFromName('time_f')).type(), QVariant.Time) - self.assertEqual(fields.at(fields.indexFromName('dt_f')).type(), QVariant.DateTime) + self.assertEqual( + fields.at(fields.indexFromName("date_f")).type(), QVariant.Date + ) + self.assertEqual( + fields.at(fields.indexFromName("time_f")).type(), QVariant.Time + ) + self.assertEqual( + fields.at(fields.indexFromName("dt_f")).type(), QVariant.DateTime + ) f = next(created_layer.getFeatures(QgsFeatureRequest())) - date_idx = created_layer.fields().lookupField('date_f') + date_idx = created_layer.fields().lookupField("date_f") self.assertIsInstance(f.attributes()[date_idx], QDate) self.assertEqual(f.attributes()[date_idx], QDate(2014, 3, 5)) - time_idx = created_layer.fields().lookupField('time_f') + time_idx = created_layer.fields().lookupField("time_f") self.assertIsInstance(f.attributes()[time_idx], QTime) self.assertEqual(f.attributes()[time_idx], QTime(13, 45, 22)) - datetime_idx = created_layer.fields().lookupField('dt_f') + datetime_idx = created_layer.fields().lookupField("dt_f") self.assertIsInstance(f.attributes()[datetime_idx], QDateTime) - self.assertEqual(f.attributes()[datetime_idx], QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22))) + self.assertEqual( + f.attributes()[datetime_idx], + QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22)), + ) def testWriteShapefileWithZ(self): """Check writing geometries with Z dimension to an ESRI shapefile.""" # start by saving a memory layer and forcing z - ml = QgsVectorLayer( - ('Point?crs=epsg:4326&field=id:int'), - 'test', - 'memory') + ml = QgsVectorLayer(("Point?crs=epsg:4326&field=id:int"), "test", "memory") - self.assertIsNotNone(ml, 'Provider not initialized') - self.assertTrue(ml.isValid(), 'Source layer not valid') + self.assertIsNotNone(ml, "Provider not initialized") + self.assertTrue(ml.isValid(), "Source layer not valid") provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() - ft.setGeometry(QgsGeometry.fromWkt('PointZ (1 2 3)')) + ft.setGeometry(QgsGeometry.fromWkt("PointZ (1 2 3)")) ft.setAttributes([1]) res, features = provider.addFeatures([ft]) self.assertTrue(res) @@ -363,220 +410,235 @@ def testWriteShapefileWithZ(self): # check with both a standard PointZ and 25d style Point25D type for t in [QgsWkbTypes.Type.PointZ, QgsWkbTypes.Type.Point25D]: - dest_file_name = os.path.join(str(QDir.tempPath()), f'point_{QgsWkbTypes.displayString(t)}.shp') - crs = QgsCoordinateReferenceSystem('EPSG:4326') + dest_file_name = os.path.join( + str(QDir.tempPath()), f"point_{QgsWkbTypes.displayString(t)}.shp" + ) + crs = QgsCoordinateReferenceSystem("EPSG:4326") write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, - 'utf-8', + "utf-8", crs, - 'ESRI Shapefile', - overrideGeometryType=t) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + "ESRI Shapefile", + overrideGeometryType=t, + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Open result and check - created_layer = QgsVectorLayer(f'{dest_file_name}|layerid=0', 'test', 'ogr') + created_layer = QgsVectorLayer(f"{dest_file_name}|layerid=0", "test", "ogr") f = next(created_layer.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.asWkt() - expWkt = 'PointZ (1 2 3)' - self.assertTrue(compareWkt(expWkt, wkt), - f"saving geometry with Z failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n") + expWkt = "PointZ (1 2 3)" + self.assertTrue( + compareWkt(expWkt, wkt), + f"saving geometry with Z failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n", + ) # also try saving out the shapefile version again, as an extra test # this tests that saving a layer with z WITHOUT explicitly telling the writer to keep z values, # will stay retain the z values - dest_file_name = os.path.join(str(QDir.tempPath()), - f'point_{QgsWkbTypes.displayString(t)}_copy.shp') - crs = QgsCoordinateReferenceSystem('EPSG:4326') + dest_file_name = os.path.join( + str(QDir.tempPath()), f"point_{QgsWkbTypes.displayString(t)}_copy.shp" + ) + crs = QgsCoordinateReferenceSystem("EPSG:4326") write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - created_layer, - dest_file_name, - 'utf-8', - crs, - 'ESRI Shapefile') - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + created_layer, dest_file_name, "utf-8", crs, "ESRI Shapefile" + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Open result and check - created_layer_from_shp = QgsVectorLayer(f'{dest_file_name}|layerid=0', 'test', 'ogr') + created_layer_from_shp = QgsVectorLayer( + f"{dest_file_name}|layerid=0", "test", "ogr" + ) f = next(created_layer_from_shp.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.asWkt() - self.assertTrue(compareWkt(expWkt, wkt), - f"saving geometry with Z failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n") + self.assertTrue( + compareWkt(expWkt, wkt), + f"saving geometry with Z failed: mismatch Expected:\n{expWkt}\nGot:\n{wkt}\n", + ) def testWriteShapefileWithMultiConversion(self): """Check writing geometries to an ESRI shapefile with conversion to multi.""" - ml = QgsVectorLayer( - ('Point?crs=epsg:4326&field=id:int'), - 'test', - 'memory') + ml = QgsVectorLayer(("Point?crs=epsg:4326&field=id:int"), "test", "memory") - self.assertIsNotNone(ml, 'Provider not initialized') - self.assertTrue(ml.isValid(), 'Source layer not valid') + self.assertIsNotNone(ml, "Provider not initialized") + self.assertTrue(ml.isValid(), "Source layer not valid") provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() - ft.setGeometry(QgsGeometry.fromWkt('Point (1 2)')) + ft.setGeometry(QgsGeometry.fromWkt("Point (1 2)")) ft.setAttributes([1]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) - dest_file_name = os.path.join(str(QDir.tempPath()), 'to_multi.shp') - crs = QgsCoordinateReferenceSystem('EPSG:4326') + dest_file_name = os.path.join(str(QDir.tempPath()), "to_multi.shp") + crs = QgsCoordinateReferenceSystem("EPSG:4326") write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - ml, - dest_file_name, - 'utf-8', - crs, - 'ESRI Shapefile', - forceMulti=True) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + ml, dest_file_name, "utf-8", crs, "ESRI Shapefile", forceMulti=True + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Open result and check - created_layer = QgsVectorLayer(f'{dest_file_name}|layerid=0', 'test', 'ogr') + created_layer = QgsVectorLayer(f"{dest_file_name}|layerid=0", "test", "ogr") f = next(created_layer.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.asWkt() - expWkt = 'MultiPoint ((1 2))' - self.assertTrue(compareWkt(expWkt, wkt), - "saving geometry with multi conversion failed: mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt)) + expWkt = "MultiPoint ((1 2))" + self.assertTrue( + compareWkt(expWkt, wkt), + "saving geometry with multi conversion failed: mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ), + ) def testWriteShapefileWithAttributeSubsets(self): """Tests writing subsets of attributes to files.""" ml = QgsVectorLayer( - ('Point?crs=epsg:4326&field=id:int&field=field1:int&field=field2:int&field=field3:int'), - 'test', - 'memory') - - self.assertIsNotNone(ml, 'Provider not initialized') - self.assertTrue(ml.isValid(), 'Source layer not valid') + ( + "Point?crs=epsg:4326&field=id:int&field=field1:int&field=field2:int&field=field3:int" + ), + "test", + "memory", + ) + + self.assertIsNotNone(ml, "Provider not initialized") + self.assertTrue(ml.isValid(), "Source layer not valid") provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() - ft.setGeometry(QgsGeometry.fromWkt('Point (1 2)')) + ft.setGeometry(QgsGeometry.fromWkt("Point (1 2)")) ft.setAttributes([1, 11, 12, 13]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) # first write out with all attributes - dest_file_name = os.path.join(str(QDir.tempPath()), 'all_attributes.shp') - crs = QgsCoordinateReferenceSystem('EPSG:4326') + dest_file_name = os.path.join(str(QDir.tempPath()), "all_attributes.shp") + crs = QgsCoordinateReferenceSystem("EPSG:4326") write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - ml, - dest_file_name, - 'utf-8', - crs, - 'ESRI Shapefile', - attributes=[]) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + ml, dest_file_name, "utf-8", crs, "ESRI Shapefile", attributes=[] + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Open result and check - created_layer = QgsVectorLayer(f'{dest_file_name}|layerid=0', 'test', 'ogr') + created_layer = QgsVectorLayer(f"{dest_file_name}|layerid=0", "test", "ogr") self.assertEqual(created_layer.fields().count(), 4) f = next(created_layer.getFeatures(QgsFeatureRequest())) - self.assertEqual(f['id'], 1) - self.assertEqual(f['field1'], 11) - self.assertEqual(f['field2'], 12) - self.assertEqual(f['field3'], 13) + self.assertEqual(f["id"], 1) + self.assertEqual(f["field1"], 11) + self.assertEqual(f["field2"], 12) + self.assertEqual(f["field3"], 13) # now test writing out only a subset of attributes - dest_file_name = os.path.join(str(QDir.tempPath()), 'subset_attributes.shp') + dest_file_name = os.path.join(str(QDir.tempPath()), "subset_attributes.shp") write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - ml, - dest_file_name, - 'utf-8', - crs, - 'ESRI Shapefile', - attributes=[1, 3]) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + ml, dest_file_name, "utf-8", crs, "ESRI Shapefile", attributes=[1, 3] + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Open result and check - created_layer = QgsVectorLayer(f'{dest_file_name}|layerid=0', 'test', 'ogr') + created_layer = QgsVectorLayer(f"{dest_file_name}|layerid=0", "test", "ogr") self.assertEqual(created_layer.fields().count(), 2) f = next(created_layer.getFeatures(QgsFeatureRequest())) - self.assertEqual(f['field1'], 11) - self.assertEqual(f['field3'], 13) + self.assertEqual(f["field1"], 11) + self.assertEqual(f["field3"], 13) # finally test writing no attributes - dest_file_name = os.path.join(str(QDir.tempPath()), 'no_attributes.shp') + dest_file_name = os.path.join(str(QDir.tempPath()), "no_attributes.shp") write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, - 'utf-8', + "utf-8", crs, - 'ESRI Shapefile', - skipAttributeCreation=True) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + "ESRI Shapefile", + skipAttributeCreation=True, + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Open result and check - created_layer = QgsVectorLayer(f'{dest_file_name}|layerid=0', 'test', 'ogr') + created_layer = QgsVectorLayer(f"{dest_file_name}|layerid=0", "test", "ogr") # expect only a default 'FID' field for shapefiles self.assertEqual(created_layer.fields().count(), 1) - self.assertEqual(created_layer.fields()[0].name(), 'FID') + self.assertEqual(created_layer.fields()[0].name(), "FID") # in this case we also check that the geometry exists, to make sure feature has been correctly written # even without attributes f = next(created_layer.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.asWkt() - expWkt = 'Point (1 2)' - self.assertTrue(compareWkt(expWkt, wkt), - "geometry not saved correctly when saving without attributes : mismatch Expected:\n{}\nGot:\n{}\n".format( - expWkt, wkt)) - self.assertEqual(f['FID'], 0) + expWkt = "Point (1 2)" + self.assertTrue( + compareWkt(expWkt, wkt), + "geometry not saved correctly when saving without attributes : mismatch Expected:\n{}\nGot:\n{}\n".format( + expWkt, wkt + ), + ) + self.assertEqual(f["FID"], 0) def testValueConverter(self): """Tests writing a layer with a field value converter.""" ml = QgsVectorLayer( - ('Point?field=nonconv:int&field=ignored:string&field=converted:int'), - 'test', - 'memory') + ("Point?field=nonconv:int&field=ignored:string&field=converted:int"), + "test", + "memory", + ) - self.assertIsNotNone(ml, 'Provider not initialized') - self.assertTrue(ml.isValid(), 'Source layer not valid') + self.assertIsNotNone(ml, "Provider not initialized") + self.assertTrue(ml.isValid(), "Source layer not valid") provider = ml.dataProvider() self.assertIsNotNone(provider) self.assertEqual(ml.fields().count(), 3) ft = QgsFeature() - ft.setAttributes([1, 'ignored', 3]) + ft.setAttributes([1, "ignored", 3]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) - dest_file_name = os.path.join(str(QDir.tempPath()), 'value_converter.shp') + dest_file_name = os.path.join(str(QDir.tempPath()), "value_converter.shp") converter = TestFieldValueConverter(ml) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, - 'utf-8', + "utf-8", QgsCoordinateReferenceSystem(), - 'ESRI Shapefile', + "ESRI Shapefile", attributes=[0, 2], - fieldValueConverter=converter) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + fieldValueConverter=converter, + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Open result and check - created_layer = QgsVectorLayer(f'{dest_file_name}|layerid=0', 'test', 'ogr') + created_layer = QgsVectorLayer(f"{dest_file_name}|layerid=0", "test", "ogr") self.assertEqual(created_layer.fields().count(), 2) f = next(created_layer.getFeatures(QgsFeatureRequest())) - self.assertEqual(f['nonconv'], 1) - self.assertEqual(f['conv_attr'], 'converted_val') + self.assertEqual(f["nonconv"], 1) + self.assertEqual(f["conv_attr"], "converted_val") def testInteger64WriteUnsupportedFormat(self): """Check writing Integer64 fields to a GMT file (which does not support that type).""" - ml = QgsVectorLayer( - ('Point?crs=epsg:4326&field=int8:int8'), - 'test', - 'memory') + ml = QgsVectorLayer(("Point?crs=epsg:4326&field=int8:int8"), "test", "memory") - self.assertIsNotNone(ml, 'Provider not initialized') - self.assertTrue(ml.isValid(), 'Source layer not valid') + self.assertIsNotNone(ml, "Provider not initialized") + self.assertTrue(ml.isValid(), "Source layer not valid") provider = ml.dataProvider() self.assertIsNotNone(provider) @@ -586,55 +648,56 @@ def testInteger64WriteUnsupportedFormat(self): self.assertTrue(res) self.assertTrue(features) - dest_file_name = os.path.join(str(QDir.tempPath()), 'integer64.gmt') - crs = QgsCoordinateReferenceSystem('EPSG:4326') + dest_file_name = os.path.join(str(QDir.tempPath()), "integer64.gmt") + crs = QgsCoordinateReferenceSystem("EPSG:4326") write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - ml, - dest_file_name, - 'utf-8', - crs, - 'GMT') - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + ml, dest_file_name, "utf-8", crs, "GMT" + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Open result and check - created_layer = QgsVectorLayer(f'{dest_file_name}|layerid=0', 'test', 'ogr') + created_layer = QgsVectorLayer(f"{dest_file_name}|layerid=0", "test", "ogr") fields = created_layer.dataProvider().fields() - self.assertEqual(fields.at(fields.indexFromName('int8')).type(), QVariant.Double) + self.assertEqual( + fields.at(fields.indexFromName("int8")).type(), QVariant.Double + ) f = next(created_layer.getFeatures(QgsFeatureRequest())) - int8_idx = created_layer.fields().lookupField('int8') + int8_idx = created_layer.fields().lookupField("int8") self.assertEqual(f.attributes()[int8_idx], 2123456789) def testDefaultDatasetOptions(self): - """ Test retrieving default dataset options for a format """ + """Test retrieving default dataset options for a format""" # NOTE - feel free to adapt these if the defaults change! - options = QgsVectorFileWriter.defaultDatasetOptions('not a format') + options = QgsVectorFileWriter.defaultDatasetOptions("not a format") self.assertEqual(options, []) - options = QgsVectorFileWriter.defaultDatasetOptions('ESRI Shapefile') + options = QgsVectorFileWriter.defaultDatasetOptions("ESRI Shapefile") self.assertEqual(options, []) - options = QgsVectorFileWriter.defaultDatasetOptions('GML') + options = QgsVectorFileWriter.defaultDatasetOptions("GML") # just test a few - self.assertIn('GML3_LONGSRS=YES', options) - self.assertIn('STRIP_PREFIX=NO', options) + self.assertIn("GML3_LONGSRS=YES", options) + self.assertIn("STRIP_PREFIX=NO", options) def testDefaultLayerOptions(self): - """ Test retrieving default layer options for a format """ + """Test retrieving default layer options for a format""" # NOTE - feel free to adapt these if the defaults change! - options = QgsVectorFileWriter.defaultLayerOptions('not a format') + options = QgsVectorFileWriter.defaultLayerOptions("not a format") self.assertEqual(options, []) - options = QgsVectorFileWriter.defaultLayerOptions('ESRI Shapefile') - self.assertEqual(options, ['RESIZE=NO']) - options = QgsVectorFileWriter.defaultLayerOptions('GML') + options = QgsVectorFileWriter.defaultLayerOptions("ESRI Shapefile") + self.assertEqual(options, ["RESIZE=NO"]) + options = QgsVectorFileWriter.defaultLayerOptions("GML") self.assertEqual(options, []) def testOverwriteLayer(self): """Tests writing a layer with a field value converter.""" - ml = QgsVectorLayer('Point?field=firstfield:int', 'test', 'memory') + ml = QgsVectorLayer("Point?field=firstfield:int", "test", "memory") provider = ml.dataProvider() ft = QgsFeature() @@ -642,37 +705,44 @@ def testOverwriteLayer(self): provider.addFeatures([ft]) options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'GPKG' - options.layerName = 'test' - filename = '/vsimem/out.gpkg' + options.driverName = "GPKG" + options.layerName = "test" + filename = "/vsimem/out.gpkg" write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - ml, - filename, - options) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + ml, filename, options + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) ds = ogr.Open(filename, update=1) - lyr = ds.GetLayerByName('test') + lyr = ds.GetLayerByName("test") self.assertIsNotNone(lyr) f = lyr.GetNextFeature() - self.assertEqual(f['firstfield'], 1) - ds.CreateLayer('another_layer') + self.assertEqual(f["firstfield"], 1) + ds.CreateLayer("another_layer") del f del lyr del ds caps = QgsVectorFileWriter.editionCapabilities(filename) self.assertTrue(caps & QgsVectorFileWriter.EditionCapability.CanAddNewLayer) - self.assertTrue(caps & QgsVectorFileWriter.EditionCapability.CanAppendToExistingLayer) - self.assertTrue(caps & QgsVectorFileWriter.EditionCapability.CanAddNewFieldsToExistingLayer) + self.assertTrue( + caps & QgsVectorFileWriter.EditionCapability.CanAppendToExistingLayer + ) + self.assertTrue( + caps & QgsVectorFileWriter.EditionCapability.CanAddNewFieldsToExistingLayer + ) self.assertTrue(caps & QgsVectorFileWriter.EditionCapability.CanDeleteLayer) - self.assertTrue(QgsVectorFileWriter.targetLayerExists(filename, 'test')) + self.assertTrue(QgsVectorFileWriter.targetLayerExists(filename, "test")) - self.assertFalse(QgsVectorFileWriter.areThereNewFieldsToCreate(filename, 'test', ml, [0])) + self.assertFalse( + QgsVectorFileWriter.areThereNewFieldsToCreate(filename, "test", ml, [0]) + ) # Test CreateOrOverwriteLayer - ml = QgsVectorLayer('Point?field=firstfield:int', 'test', 'memory') + ml = QgsVectorLayer("Point?field=firstfield:int", "test", "memory") provider = ml.dataProvider() ft = QgsFeature() @@ -680,29 +750,32 @@ def testOverwriteLayer(self): provider.addFeatures([ft]) options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'GPKG' - options.layerName = 'test' - options.actionOnExistingFile = QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteLayer - filename = '/vsimem/out.gpkg' + options.driverName = "GPKG" + options.layerName = "test" + options.actionOnExistingFile = ( + QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteLayer + ) + filename = "/vsimem/out.gpkg" write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - ml, - filename, - options) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + ml, filename, options + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) ds = ogr.Open(filename) - lyr = ds.GetLayerByName('test') + lyr = ds.GetLayerByName("test") self.assertIsNotNone(lyr) f = lyr.GetNextFeature() - self.assertEqual(f['firstfield'], 2) + self.assertEqual(f["firstfield"], 2) # another_layer should still exist - self.assertIsNotNone(ds.GetLayerByName('another_layer')) + self.assertIsNotNone(ds.GetLayerByName("another_layer")) del f del lyr del ds # Test CreateOrOverwriteFile - ml = QgsVectorLayer('Point?field=firstfield:int', 'test', 'memory') + ml = QgsVectorLayer("Point?field=firstfield:int", "test", "memory") provider = ml.dataProvider() ft = QgsFeature() @@ -710,100 +783,115 @@ def testOverwriteLayer(self): provider.addFeatures([ft]) options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'GPKG' - options.layerName = 'test' - filename = '/vsimem/out.gpkg' + options.driverName = "GPKG" + options.layerName = "test" + filename = "/vsimem/out.gpkg" write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - ml, - filename, - options) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + ml, filename, options + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) ds = ogr.Open(filename) - lyr = ds.GetLayerByName('test') + lyr = ds.GetLayerByName("test") self.assertIsNotNone(lyr) f = lyr.GetNextFeature() - self.assertEqual(f['firstfield'], 3) + self.assertEqual(f["firstfield"], 3) # another_layer should no longer exist - self.assertIsNone(ds.GetLayerByName('another_layer')) + self.assertIsNone(ds.GetLayerByName("another_layer")) del f del lyr del ds # Test AppendToLayerNoNewFields - ml = QgsVectorLayer('Point?field=firstfield:int&field=secondfield:int', 'test', 'memory') + ml = QgsVectorLayer( + "Point?field=firstfield:int&field=secondfield:int", "test", "memory" + ) provider = ml.dataProvider() ft = QgsFeature() ft.setAttributes([4, -10]) provider.addFeatures([ft]) - self.assertTrue(QgsVectorFileWriter.areThereNewFieldsToCreate(filename, 'test', ml, [0, 1])) + self.assertTrue( + QgsVectorFileWriter.areThereNewFieldsToCreate(filename, "test", ml, [0, 1]) + ) options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'GPKG' - options.layerName = 'test' - options.actionOnExistingFile = QgsVectorFileWriter.ActionOnExistingFile.AppendToLayerNoNewFields - filename = '/vsimem/out.gpkg' + options.driverName = "GPKG" + options.layerName = "test" + options.actionOnExistingFile = ( + QgsVectorFileWriter.ActionOnExistingFile.AppendToLayerNoNewFields + ) + filename = "/vsimem/out.gpkg" write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - ml, - filename, - options) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + ml, filename, options + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) ds = ogr.Open(filename) - lyr = ds.GetLayerByName('test') + lyr = ds.GetLayerByName("test") self.assertEqual(lyr.GetLayerDefn().GetFieldCount(), 1) self.assertIsNotNone(lyr) f = lyr.GetNextFeature() - self.assertEqual(f['firstfield'], 3) + self.assertEqual(f["firstfield"], 3) f = lyr.GetNextFeature() - self.assertEqual(f['firstfield'], 4) + self.assertEqual(f["firstfield"], 4) del f del lyr del ds # Test AppendToLayerAddFields - ml = QgsVectorLayer('Point?field=firstfield:int&field=secondfield:int', 'test', 'memory') + ml = QgsVectorLayer( + "Point?field=firstfield:int&field=secondfield:int", "test", "memory" + ) provider = ml.dataProvider() ft = QgsFeature() ft.setAttributes([5, -1]) provider.addFeatures([ft]) - self.assertTrue(QgsVectorFileWriter.areThereNewFieldsToCreate(filename, 'test', ml, [0, 1])) + self.assertTrue( + QgsVectorFileWriter.areThereNewFieldsToCreate(filename, "test", ml, [0, 1]) + ) options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'GPKG' - options.layerName = 'test' - options.actionOnExistingFile = QgsVectorFileWriter.ActionOnExistingFile.AppendToLayerAddFields - filename = '/vsimem/out.gpkg' + options.driverName = "GPKG" + options.layerName = "test" + options.actionOnExistingFile = ( + QgsVectorFileWriter.ActionOnExistingFile.AppendToLayerAddFields + ) + filename = "/vsimem/out.gpkg" write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - ml, - filename, - options) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + ml, filename, options + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) ds = ogr.Open(filename) - lyr = ds.GetLayerByName('test') + lyr = ds.GetLayerByName("test") self.assertEqual(lyr.GetLayerDefn().GetFieldCount(), 2) self.assertIsNotNone(lyr) f = lyr.GetNextFeature() - self.assertEqual(f['firstfield'], 3) + self.assertEqual(f["firstfield"], 3) if hasattr(f, "IsFieldSetAndNotNull"): # GDAL >= 2.2 - self.assertFalse(f.IsFieldSetAndNotNull('secondfield')) + self.assertFalse(f.IsFieldSetAndNotNull("secondfield")) else: - self.assertFalse(f.IsFieldSet('secondfield')) + self.assertFalse(f.IsFieldSet("secondfield")) f = lyr.GetNextFeature() - self.assertEqual(f['firstfield'], 4) + self.assertEqual(f["firstfield"], 4) if hasattr(f, "IsFieldSetAndNotNull"): - self.assertFalse(f.IsFieldSetAndNotNull('secondfield')) + self.assertFalse(f.IsFieldSetAndNotNull("secondfield")) else: - self.assertFalse(f.IsFieldSet('secondfield')) + self.assertFalse(f.IsFieldSet("secondfield")) f = lyr.GetNextFeature() - self.assertEqual(f['firstfield'], 5) - self.assertEqual(f['secondfield'], -1) + self.assertEqual(f["firstfield"], 5) + self.assertEqual(f["secondfield"], -1) del f del lyr del ds @@ -812,217 +900,277 @@ def testOverwriteLayer(self): def testSupportedFiltersAndFormat(self): # test with formats in recommended order - formats = QgsVectorFileWriter.supportedFiltersAndFormats(QgsVectorFileWriter.VectorFormatOption.SortRecommended) - self.assertEqual(formats[0].filterString, 'GeoPackage (*.gpkg *.GPKG)') - self.assertEqual(formats[0].driverName, 'GPKG') - self.assertEqual(formats[0].globs, ['*.gpkg']) - self.assertEqual(formats[1].filterString, 'ESRI Shapefile (*.shp *.SHP)') - self.assertEqual(formats[1].driverName, 'ESRI Shapefile') - self.assertEqual(formats[1].globs, ['*.shp']) - self.assertIn('ODS', [f.driverName for f in formats]) - self.assertIn('PGDUMP', [f.driverName for f in formats]) - - interlis_format = [f for f in formats if f.driverName == 'Interlis 2'][0] - self.assertEqual(interlis_format.globs, ['*.xtf', '*.xml', '*.ili']) + formats = QgsVectorFileWriter.supportedFiltersAndFormats( + QgsVectorFileWriter.VectorFormatOption.SortRecommended + ) + self.assertEqual(formats[0].filterString, "GeoPackage (*.gpkg *.GPKG)") + self.assertEqual(formats[0].driverName, "GPKG") + self.assertEqual(formats[0].globs, ["*.gpkg"]) + self.assertEqual(formats[1].filterString, "ESRI Shapefile (*.shp *.SHP)") + self.assertEqual(formats[1].driverName, "ESRI Shapefile") + self.assertEqual(formats[1].globs, ["*.shp"]) + self.assertIn("ODS", [f.driverName for f in formats]) + self.assertIn("PGDUMP", [f.driverName for f in formats]) + + interlis_format = [f for f in formats if f.driverName == "Interlis 2"][0] + self.assertEqual(interlis_format.globs, ["*.xtf", "*.xml", "*.ili"]) # alphabetical sorting - formats2 = QgsVectorFileWriter.supportedFiltersAndFormats(QgsVectorFileWriter.VectorFormatOptions()) + formats2 = QgsVectorFileWriter.supportedFiltersAndFormats( + QgsVectorFileWriter.VectorFormatOptions() + ) # print([f.filterString for f in formats2]) self.assertLess(formats2[0].filterString, formats2[1].filterString) - self.assertCountEqual([f.driverName for f in formats], [f.driverName for f in formats2]) - self.assertNotEqual(formats2[0].driverName, 'GeoPackage') + self.assertCountEqual( + [f.driverName for f in formats], [f.driverName for f in formats2] + ) + self.assertNotEqual(formats2[0].driverName, "GeoPackage") # skip non-spatial - formats = QgsVectorFileWriter.supportedFiltersAndFormats(QgsVectorFileWriter.VectorFormatOption.SkipNonSpatialFormats) - self.assertNotIn('ODS', [f.driverName for f in formats]) + formats = QgsVectorFileWriter.supportedFiltersAndFormats( + QgsVectorFileWriter.VectorFormatOption.SkipNonSpatialFormats + ) + self.assertNotIn("ODS", [f.driverName for f in formats]) # multilayer formats - formats = QgsVectorFileWriter.supportedFiltersAndFormats(QgsVectorFileWriter.VectorFormatOption.SupportsMultipleLayers) - self.assertIn('DXF', [f.driverName for f in formats]) - self.assertNotIn('ESRI Shapefile', [f.driverName for f in formats]) - self.assertIn('XLSX', [f.driverName for f in formats]) - - formats = QgsVectorFileWriter.supportedFiltersAndFormats(QgsVectorFileWriter.VectorFormatOption.SupportsMultipleLayers | QgsVectorFileWriter.VectorFormatOption.SkipNonSpatialFormats) - self.assertIn('DXF', [f.driverName for f in formats]) - self.assertNotIn('ESRI Shapefile', [f.driverName for f in formats]) - self.assertNotIn('XLSX', [f.driverName for f in formats]) + formats = QgsVectorFileWriter.supportedFiltersAndFormats( + QgsVectorFileWriter.VectorFormatOption.SupportsMultipleLayers + ) + self.assertIn("DXF", [f.driverName for f in formats]) + self.assertNotIn("ESRI Shapefile", [f.driverName for f in formats]) + self.assertIn("XLSX", [f.driverName for f in formats]) + + formats = QgsVectorFileWriter.supportedFiltersAndFormats( + QgsVectorFileWriter.VectorFormatOption.SupportsMultipleLayers + | QgsVectorFileWriter.VectorFormatOption.SkipNonSpatialFormats + ) + self.assertIn("DXF", [f.driverName for f in formats]) + self.assertNotIn("ESRI Shapefile", [f.driverName for f in formats]) + self.assertNotIn("XLSX", [f.driverName for f in formats]) def testOgrDriverList(self): # test with drivers in recommended order - drivers = QgsVectorFileWriter.ogrDriverList(QgsVectorFileWriter.VectorFormatOption.SortRecommended) - self.assertEqual(drivers[0].longName, 'GeoPackage') - self.assertEqual(drivers[0].driverName, 'GPKG') - self.assertEqual(drivers[1].longName, 'ESRI Shapefile') - self.assertEqual(drivers[1].driverName, 'ESRI Shapefile') - self.assertIn('ODS', [f.driverName for f in drivers]) + drivers = QgsVectorFileWriter.ogrDriverList( + QgsVectorFileWriter.VectorFormatOption.SortRecommended + ) + self.assertEqual(drivers[0].longName, "GeoPackage") + self.assertEqual(drivers[0].driverName, "GPKG") + self.assertEqual(drivers[1].longName, "ESRI Shapefile") + self.assertEqual(drivers[1].driverName, "ESRI Shapefile") + self.assertIn("ODS", [f.driverName for f in drivers]) # ensure that XLSX comes before SQLite, because we should sort on longName, not driverName! - ms_xlsx_index = next(i for i, v in enumerate(drivers) if v.driverName == 'XLSX') - sqlite_index = next(i for i, v in enumerate(drivers) if v.driverName == 'SQLite') + ms_xlsx_index = next(i for i, v in enumerate(drivers) if v.driverName == "XLSX") + sqlite_index = next( + i for i, v in enumerate(drivers) if v.driverName == "SQLite" + ) self.assertLess(ms_xlsx_index, sqlite_index) - self.assertIn('[XLSX]', drivers[ms_xlsx_index].longName) + self.assertIn("[XLSX]", drivers[ms_xlsx_index].longName) # alphabetical sorting - drivers2 = QgsVectorFileWriter.ogrDriverList(QgsVectorFileWriter.VectorFormatOptions()) + drivers2 = QgsVectorFileWriter.ogrDriverList( + QgsVectorFileWriter.VectorFormatOptions() + ) self.assertLess(drivers2[0].longName, drivers2[1].longName) - self.assertCountEqual([d.driverName for d in drivers], [d.driverName for d in drivers2]) - self.assertNotEqual(drivers2[0].driverName, 'GPKG') + self.assertCountEqual( + [d.driverName for d in drivers], [d.driverName for d in drivers2] + ) + self.assertNotEqual(drivers2[0].driverName, "GPKG") # skip non-spatial - formats = QgsVectorFileWriter.ogrDriverList(QgsVectorFileWriter.VectorFormatOption.SkipNonSpatialFormats) - self.assertNotIn('ODS', [f.driverName for f in formats]) + formats = QgsVectorFileWriter.ogrDriverList( + QgsVectorFileWriter.VectorFormatOption.SkipNonSpatialFormats + ) + self.assertNotIn("ODS", [f.driverName for f in formats]) # multilayer formats - formats = QgsVectorFileWriter.ogrDriverList(QgsVectorFileWriter.VectorFormatOption.SupportsMultipleLayers) - self.assertIn('DXF', [f.driverName for f in formats]) - self.assertNotIn('ESRI Shapefile', [f.driverName for f in formats]) - self.assertIn('XLSX', [f.driverName for f in formats]) - - formats = QgsVectorFileWriter.ogrDriverList(QgsVectorFileWriter.VectorFormatOption.SupportsMultipleLayers | QgsVectorFileWriter.VectorFormatOption.SkipNonSpatialFormats) - self.assertIn('DXF', [f.driverName for f in formats]) - self.assertNotIn('ESRI Shapefile', [f.driverName for f in formats]) - self.assertNotIn('XLSX', [f.driverName for f in formats]) + formats = QgsVectorFileWriter.ogrDriverList( + QgsVectorFileWriter.VectorFormatOption.SupportsMultipleLayers + ) + self.assertIn("DXF", [f.driverName for f in formats]) + self.assertNotIn("ESRI Shapefile", [f.driverName for f in formats]) + self.assertIn("XLSX", [f.driverName for f in formats]) + + formats = QgsVectorFileWriter.ogrDriverList( + QgsVectorFileWriter.VectorFormatOption.SupportsMultipleLayers + | QgsVectorFileWriter.VectorFormatOption.SkipNonSpatialFormats + ) + self.assertIn("DXF", [f.driverName for f in formats]) + self.assertNotIn("ESRI Shapefile", [f.driverName for f in formats]) + self.assertNotIn("XLSX", [f.driverName for f in formats]) def testSupportedFormatExtensions(self): formats = QgsVectorFileWriter.supportedFormatExtensions() - self.assertIn('gpkg', formats) - self.assertNotIn('exe', formats) - self.assertEqual(formats[0], 'gpkg') - self.assertEqual(formats[1], 'shp') - self.assertIn('ods', formats) - self.assertIn('xtf', formats) - self.assertIn('ili', formats) + self.assertIn("gpkg", formats) + self.assertNotIn("exe", formats) + self.assertEqual(formats[0], "gpkg") + self.assertEqual(formats[1], "shp") + self.assertIn("ods", formats) + self.assertIn("xtf", formats) + self.assertIn("ili", formats) for i in range(2, len(formats) - 1): self.assertLess(formats[i].lower(), formats[i + 1].lower()) # alphabetical sorting - formats2 = QgsVectorFileWriter.supportedFormatExtensions(QgsVectorFileWriter.VectorFormatOptions()) + formats2 = QgsVectorFileWriter.supportedFormatExtensions( + QgsVectorFileWriter.VectorFormatOptions() + ) self.assertLess(formats2[0], formats2[1]) self.assertCountEqual(formats, formats2) - self.assertNotEqual(formats2[0], 'gpkg') + self.assertNotEqual(formats2[0], "gpkg") for i in range(0, len(formats2) - 1): self.assertLess(formats2[i].lower(), formats2[i + 1].lower()) - formats = QgsVectorFileWriter.supportedFormatExtensions(QgsVectorFileWriter.VectorFormatOption.SkipNonSpatialFormats) - self.assertNotIn('ods', formats) + formats = QgsVectorFileWriter.supportedFormatExtensions( + QgsVectorFileWriter.VectorFormatOption.SkipNonSpatialFormats + ) + self.assertNotIn("ods", formats) def testFileFilterString(self): formats = QgsVectorFileWriter.fileFilterString() - self.assertIn('gpkg', formats) - self.assertIn('shp', formats) - self.assertLess(formats.index('gpkg'), formats.index('shp')) - self.assertIn('ods', formats) - parts = formats.split(';;') + self.assertIn("gpkg", formats) + self.assertIn("shp", formats) + self.assertLess(formats.index("gpkg"), formats.index("shp")) + self.assertIn("ods", formats) + parts = formats.split(";;") for i in range(2, len(parts) - 1): - if 'GeoJSON - Newline Delimited' in parts[i] or 'GeoJSON - Newline Delimited' in parts[i + 1]: + if ( + "GeoJSON - Newline Delimited" in parts[i] + or "GeoJSON - Newline Delimited" in parts[i + 1] + ): # Python's < operator doesn't do locale aware sorting, so skip this problematic one continue self.assertLess(parts[i].lower(), parts[i + 1].lower()) # alphabetical sorting - formats2 = QgsVectorFileWriter.fileFilterString(QgsVectorFileWriter.VectorFormatOptions()) - self.assertNotEqual(formats.index('gpkg'), formats2.index('gpkg')) - parts = formats2.split(';;') + formats2 = QgsVectorFileWriter.fileFilterString( + QgsVectorFileWriter.VectorFormatOptions() + ) + self.assertNotEqual(formats.index("gpkg"), formats2.index("gpkg")) + parts = formats2.split(";;") for i in range(len(parts) - 1): - if 'GeoJSON - Newline Delimited' in parts[i] or 'GeoJSON - Newline Delimited' in parts[i + 1]: + if ( + "GeoJSON - Newline Delimited" in parts[i] + or "GeoJSON - Newline Delimited" in parts[i + 1] + ): # Python's < operator doesn't do locale aware sorting, so skip this problematic one continue self.assertLess(parts[i].lower(), parts[i + 1].lower()) # hide non spatial - formats = QgsVectorFileWriter.fileFilterString(QgsVectorFileWriter.VectorFormatOption.SkipNonSpatialFormats) - self.assertNotIn('ods', formats) + formats = QgsVectorFileWriter.fileFilterString( + QgsVectorFileWriter.VectorFormatOption.SkipNonSpatialFormats + ) + self.assertNotIn("ods", formats) def testDriverForExtension(self): - self.assertEqual(QgsVectorFileWriter.driverForExtension('shp'), 'ESRI Shapefile') - self.assertEqual(QgsVectorFileWriter.driverForExtension('SHP'), 'ESRI Shapefile') - self.assertEqual(QgsVectorFileWriter.driverForExtension('sHp'), 'ESRI Shapefile') - self.assertEqual(QgsVectorFileWriter.driverForExtension('.shp'), 'ESRI Shapefile') - self.assertEqual(QgsVectorFileWriter.driverForExtension('tab'), 'MapInfo File') - self.assertEqual(QgsVectorFileWriter.driverForExtension('.GML'), 'GML') - self.assertEqual(QgsVectorFileWriter.driverForExtension('not a format'), '') - self.assertEqual(QgsVectorFileWriter.driverForExtension(''), '') + self.assertEqual( + QgsVectorFileWriter.driverForExtension("shp"), "ESRI Shapefile" + ) + self.assertEqual( + QgsVectorFileWriter.driverForExtension("SHP"), "ESRI Shapefile" + ) + self.assertEqual( + QgsVectorFileWriter.driverForExtension("sHp"), "ESRI Shapefile" + ) + self.assertEqual( + QgsVectorFileWriter.driverForExtension(".shp"), "ESRI Shapefile" + ) + self.assertEqual(QgsVectorFileWriter.driverForExtension("tab"), "MapInfo File") + self.assertEqual(QgsVectorFileWriter.driverForExtension(".GML"), "GML") + self.assertEqual(QgsVectorFileWriter.driverForExtension("not a format"), "") + self.assertEqual(QgsVectorFileWriter.driverForExtension(""), "") def testSupportsFeatureStyles(self): - self.assertFalse(QgsVectorFileWriter.supportsFeatureStyles('ESRI Shapefile')) - self.assertFalse(QgsVectorFileWriter.supportsFeatureStyles('not a driver')) - self.assertTrue(QgsVectorFileWriter.supportsFeatureStyles('DXF')) - self.assertTrue(QgsVectorFileWriter.supportsFeatureStyles('KML')) - self.assertTrue(QgsVectorFileWriter.supportsFeatureStyles('MapInfo File')) - self.assertTrue(QgsVectorFileWriter.supportsFeatureStyles('MapInfo MIF')) + self.assertFalse(QgsVectorFileWriter.supportsFeatureStyles("ESRI Shapefile")) + self.assertFalse(QgsVectorFileWriter.supportsFeatureStyles("not a driver")) + self.assertTrue(QgsVectorFileWriter.supportsFeatureStyles("DXF")) + self.assertTrue(QgsVectorFileWriter.supportsFeatureStyles("KML")) + self.assertTrue(QgsVectorFileWriter.supportsFeatureStyles("MapInfo File")) + self.assertTrue(QgsVectorFileWriter.supportsFeatureStyles("MapInfo MIF")) def testOverwriteGPKG(self): """Test that overwriting the same origin GPKG file works only if the layername is different""" # Prepare test data - ml = QgsVectorLayer('Point?field=firstfield:int&field=secondfield:int', 'test', 'memory') + ml = QgsVectorLayer( + "Point?field=firstfield:int&field=secondfield:int", "test", "memory" + ) provider = ml.dataProvider() ft = QgsFeature() ft.setAttributes([4, -10]) provider.addFeatures([ft]) - filehandle, filename = tempfile.mkstemp('.gpkg') + filehandle, filename = tempfile.mkstemp(".gpkg") options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'GPKG' - options.layerName = 'test' + options.driverName = "GPKG" + options.layerName = "test" write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - ml, - filename, - options) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + ml, filename, options + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Real test - vl = QgsVectorLayer(f"{filename}|layername=test", 'src_test', 'ogr') + vl = QgsVectorLayer(f"{filename}|layername=test", "src_test", "ogr") self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 1) # This must fail write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - vl, - filename, - options) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.ErrCreateDataSource) - self.assertEqual(error_message, 'Cannot overwrite an OGR layer in place') - - options.layerName = 'test2' + vl, filename, options + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.ErrCreateDataSource + ) + self.assertEqual(error_message, "Cannot overwrite an OGR layer in place") + + options.layerName = "test2" write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - vl, - filename, - options) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + vl, filename, options + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) def testCreateDGN(self): - ml = QgsVectorLayer('Point?crs=epsg:4326', 'test', 'memory') + ml = QgsVectorLayer("Point?crs=epsg:4326", "test", "memory") provider = ml.dataProvider() feat = QgsFeature() feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) provider.addFeatures([feat]) - filename = os.path.join(str(QDir.tempPath()), 'testCreateDGN.dgn') - crs = QgsCoordinateReferenceSystem('EPSG:4326') - rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat(ml, filename, 'utf-8', crs, 'DGN') + filename = os.path.join(str(QDir.tempPath()), "testCreateDGN.dgn") + crs = QgsCoordinateReferenceSystem("EPSG:4326") + rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat( + ml, filename, "utf-8", crs, "DGN" + ) # open the resulting file - vl = QgsVectorLayer(filename, '', 'ogr') + vl = QgsVectorLayer(filename, "", "ogr") self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 1) del vl # append options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'DGN' - options.layerName = 'test' - options.actionOnExistingFile = QgsVectorFileWriter.ActionOnExistingFile.AppendToLayerNoNewFields + options.driverName = "DGN" + options.layerName = "test" + options.actionOnExistingFile = ( + QgsVectorFileWriter.ActionOnExistingFile.AppendToLayerNoNewFields + ) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - ml, - filename, - options) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + ml, filename, options + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # open the resulting file - vl = QgsVectorLayer(filename, '', 'ogr') + vl = QgsVectorLayer(filename, "", "ogr") self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 2) del vl @@ -1032,11 +1180,10 @@ def testCreateDGN(self): def testAddZ(self): """Check adding z values to non z input.""" input = QgsVectorLayer( - 'Point?crs=epsg:4326&field=name:string(20)', - 'test', - 'memory') + "Point?crs=epsg:4326&field=name:string(20)", "test", "memory" + ) - self.assertTrue(input.isValid(), 'Provider not initialized') + self.assertTrue(input.isValid(), "Provider not initialized") ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) @@ -1044,52 +1191,53 @@ def testAddZ(self): self.assertTrue(myResult) self.assertTrue(myFeatures) - dest_file_name = os.path.join(str(QDir.tempPath()), 'add_z.geojson') + dest_file_name = os.path.join(str(QDir.tempPath()), "add_z.geojson") options = QgsVectorFileWriter.SaveVectorOptions() options.overrideGeometryType = QgsWkbTypes.Type.PointZ - options.driverName = 'GeoJSON' + options.driverName = "GeoJSON" write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - input, - dest_file_name, - options) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + input, dest_file_name, options + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Open result and check - created_layer = QgsVectorLayer(dest_file_name, 'test', 'ogr') + created_layer = QgsVectorLayer(dest_file_name, "test", "ogr") self.assertTrue(created_layer.isValid()) f = next(created_layer.getFeatures(QgsFeatureRequest())) - self.assertEqual(f.geometry().asWkt(), 'Point Z (10 10 0)') + self.assertEqual(f.geometry().asWkt(), "Point Z (10 10 0)") def testDropZ(self): """Check dropping z values input.""" input = QgsVectorLayer( - 'PointZ?crs=epsg:4326&field=name:string(20)', - 'test', - 'memory') + "PointZ?crs=epsg:4326&field=name:string(20)", "test", "memory" + ) - self.assertTrue(input.isValid(), 'Provider not initialized') + self.assertTrue(input.isValid(), "Provider not initialized") ft = QgsFeature() - ft.setGeometry(QgsGeometry.fromWkt('PointM(10 10 2)')) + ft.setGeometry(QgsGeometry.fromWkt("PointM(10 10 2)")) myResult, myFeatures = input.dataProvider().addFeatures([ft]) self.assertTrue(myResult) self.assertTrue(myFeatures) - dest_file_name = os.path.join(str(QDir.tempPath()), 'drop_z.geojson') + dest_file_name = os.path.join(str(QDir.tempPath()), "drop_z.geojson") options = QgsVectorFileWriter.SaveVectorOptions() options.overrideGeometryType = QgsWkbTypes.Type.PointM - options.driverName = 'GeoJSON' + options.driverName = "GeoJSON" write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - input, - dest_file_name, - options) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + input, dest_file_name, options + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Open result and check - created_layer = QgsVectorLayer(dest_file_name, 'test', 'ogr') + created_layer = QgsVectorLayer(dest_file_name, "test", "ogr") self.assertTrue(created_layer.isValid()) f = next(created_layer.getFeatures(QgsFeatureRequest())) - self.assertEqual(f.geometry().asWkt(), 'Point (10 10)') + self.assertEqual(f.geometry().asWkt(), "Point (10 10)") def testWriteWithStringListField(self): """ @@ -1097,33 +1245,35 @@ def testWriteWithStringListField(self): :return: """ source_fields = QgsFields() - source_fields.append(QgsField('int', QVariant.Int)) - source_fields.append(QgsField('stringlist', QVariant.StringList, subType=QVariant.String)) - vl = QgsMemoryProviderUtils.createMemoryLayer('test', source_fields) + source_fields.append(QgsField("int", QVariant.Int)) + source_fields.append( + QgsField("stringlist", QVariant.StringList, subType=QVariant.String) + ) + vl = QgsMemoryProviderUtils.createMemoryLayer("test", source_fields) f = QgsFeature() - f.setAttributes([1, ['ab', 'cd']]) + f.setAttributes([1, ["ab", "cd"]]) vl.dataProvider().addFeature(f) - filename = os.path.join(str(QDir.tempPath()), 'with_stringlist_field.geojson') - rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat(vl, - filename, - 'utf-8', - vl.crs(), - 'GeoJSON') + filename = os.path.join(str(QDir.tempPath()), "with_stringlist_field.geojson") + rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat( + vl, filename, "utf-8", vl.crs(), "GeoJSON" + ) self.assertEqual(rc, QgsVectorFileWriter.WriterError.NoError) # open the resulting geojson - vl = QgsVectorLayer(filename, '', 'ogr') + vl = QgsVectorLayer(filename, "", "ogr") self.assertTrue(vl.isValid()) fields = vl.fields() # test type of converted field - idx = fields.indexFromName('stringlist') + idx = fields.indexFromName("stringlist") self.assertEqual(fields.at(idx).type(), QVariant.StringList) self.assertEqual(fields.at(idx).subType(), QVariant.String) - self.assertEqual([f.attributes() for f in vl.getFeatures()], [[1, ['ab', 'cd']]]) + self.assertEqual( + [f.attributes() for f in vl.getFeatures()], [[1, ["ab", "cd"]]] + ) os.unlink(filename) @@ -1133,29 +1283,27 @@ def testWriteWithIntegerListField(self): :return: """ source_fields = QgsFields() - source_fields.append(QgsField('int', QVariant.Int)) - source_fields.append(QgsField('intlist', QVariant.List, subType=QVariant.Int)) - vl = QgsMemoryProviderUtils.createMemoryLayer('test', source_fields) + source_fields.append(QgsField("int", QVariant.Int)) + source_fields.append(QgsField("intlist", QVariant.List, subType=QVariant.Int)) + vl = QgsMemoryProviderUtils.createMemoryLayer("test", source_fields) f = QgsFeature() f.setAttributes([1, [11, 12]]) vl.dataProvider().addFeature(f) - filename = os.path.join(str(QDir.tempPath()), 'with_intlist_field.geojson') - rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat(vl, - filename, - 'utf-8', - vl.crs(), - 'GeoJSON') + filename = os.path.join(str(QDir.tempPath()), "with_intlist_field.geojson") + rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat( + vl, filename, "utf-8", vl.crs(), "GeoJSON" + ) self.assertEqual(rc, QgsVectorFileWriter.WriterError.NoError) # open the resulting geojson - vl = QgsVectorLayer(filename, '', 'ogr') + vl = QgsVectorLayer(filename, "", "ogr") self.assertTrue(vl.isValid()) fields = vl.fields() # test type of converted field - idx = fields.indexFromName('intlist') + idx = fields.indexFromName("intlist") self.assertEqual(fields.at(idx).type(), QVariant.List) self.assertEqual(fields.at(idx).subType(), QVariant.Int) @@ -1169,33 +1317,35 @@ def testWriteWithDoubleListField(self): :return: """ source_fields = QgsFields() - source_fields.append(QgsField('int', QVariant.Int)) - source_fields.append(QgsField('reallist', QVariant.List, subType=QVariant.Double)) - vl = QgsMemoryProviderUtils.createMemoryLayer('test', source_fields) + source_fields.append(QgsField("int", QVariant.Int)) + source_fields.append( + QgsField("reallist", QVariant.List, subType=QVariant.Double) + ) + vl = QgsMemoryProviderUtils.createMemoryLayer("test", source_fields) f = QgsFeature() f.setAttributes([1, [11.1, 12.2]]) vl.dataProvider().addFeature(f) - filename = os.path.join(str(QDir.tempPath()), 'with_intlist_field.geojson') - rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat(vl, - filename, - 'utf-8', - vl.crs(), - 'GeoJSON') + filename = os.path.join(str(QDir.tempPath()), "with_intlist_field.geojson") + rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat( + vl, filename, "utf-8", vl.crs(), "GeoJSON" + ) self.assertEqual(rc, QgsVectorFileWriter.WriterError.NoError) # open the resulting geojson - vl = QgsVectorLayer(filename, '', 'ogr') + vl = QgsVectorLayer(filename, "", "ogr") self.assertTrue(vl.isValid()) fields = vl.fields() # test type of converted field - idx = fields.indexFromName('reallist') + idx = fields.indexFromName("reallist") self.assertEqual(fields.at(idx).type(), QVariant.List) self.assertEqual(fields.at(idx).subType(), QVariant.Double) - self.assertEqual([f.attributes() for f in vl.getFeatures()], [[1, [11.1, 12.2]]]) + self.assertEqual( + [f.attributes() for f in vl.getFeatures()], [[1, [11.1, 12.2]]] + ) os.unlink(filename) @@ -1205,33 +1355,36 @@ def testWriteWithLongLongListField(self): :return: """ source_fields = QgsFields() - source_fields.append(QgsField('int', QVariant.Int)) - source_fields.append(QgsField('int64list', QVariant.List, subType=QVariant.LongLong)) - vl = QgsMemoryProviderUtils.createMemoryLayer('test', source_fields) + source_fields.append(QgsField("int", QVariant.Int)) + source_fields.append( + QgsField("int64list", QVariant.List, subType=QVariant.LongLong) + ) + vl = QgsMemoryProviderUtils.createMemoryLayer("test", source_fields) f = QgsFeature() f.setAttributes([1, [1234567890123, 1234567890124]]) vl.dataProvider().addFeature(f) - filename = os.path.join(str(QDir.tempPath()), 'with_longlist_field.geojson') - rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat(vl, - filename, - 'utf-8', - vl.crs(), - 'GeoJSON') + filename = os.path.join(str(QDir.tempPath()), "with_longlist_field.geojson") + rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat( + vl, filename, "utf-8", vl.crs(), "GeoJSON" + ) self.assertEqual(rc, QgsVectorFileWriter.WriterError.NoError) # open the resulting gml - vl = QgsVectorLayer(filename, '', 'ogr') + vl = QgsVectorLayer(filename, "", "ogr") self.assertTrue(vl.isValid()) fields = vl.fields() # test type of converted field - idx = fields.indexFromName('int64list') + idx = fields.indexFromName("int64list") self.assertEqual(fields.at(idx).type(), QVariant.List) self.assertEqual(fields.at(idx).subType(), QVariant.LongLong) - self.assertEqual([f.attributes() for f in vl.getFeatures()], [[1, [1234567890123, 1234567890124]]]) + self.assertEqual( + [f.attributes() for f in vl.getFeatures()], + [[1, [1234567890123, 1234567890124]]], + ) os.unlink(filename) @@ -1242,13 +1395,13 @@ def testWriteWithBinaryField(self): """ basetestpath = tempfile.mkdtemp() - tmpfile = os.path.join(basetestpath, 'binaryfield.sqlite') - ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid']) - lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString)) - lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger)) - lyr.CreateField(ogr.FieldDefn('binfield', ogr.OFTBinary)) - lyr.CreateField(ogr.FieldDefn('binfield2', ogr.OFTBinary)) + tmpfile = os.path.join(basetestpath, "binaryfield.sqlite") + ds = ogr.GetDriverByName("SQLite").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint, options=["FID=fid"]) + lyr.CreateField(ogr.FieldDefn("strfield", ogr.OFTString)) + lyr.CreateField(ogr.FieldDefn("intfield", ogr.OFTInteger)) + lyr.CreateField(ogr.FieldDefn("binfield", ogr.OFTBinary)) + lyr.CreateField(ogr.FieldDefn("binfield2", ogr.OFTBinary)) f = None ds = None @@ -1257,36 +1410,36 @@ def testWriteWithBinaryField(self): # check that 1 of its fields is a bool fields = vl.fields() - self.assertEqual(fields.at(fields.indexFromName('binfield')).type(), QVariant.ByteArray) + self.assertEqual( + fields.at(fields.indexFromName("binfield")).type(), QVariant.ByteArray + ) dp = vl.dataProvider() f = QgsFeature(fields) - bin_1 = b'xxx' - bin_2 = b'yyy' + bin_1 = b"xxx" + bin_2 = b"yyy" bin_val1 = QByteArray(bin_1) bin_val2 = QByteArray(bin_2) - f.setAttributes([1, 'str', 100, bin_val1, bin_val2]) + f.setAttributes([1, "str", 100, bin_val1, bin_val2]) self.assertTrue(dp.addFeature(f)) # write a gpkg package with a binary field - filename = os.path.join(str(QDir.tempPath()), 'with_bin_field') - rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat(vl, - filename, - 'utf-8', - vl.crs(), - 'GPKG') + filename = os.path.join(str(QDir.tempPath()), "with_bin_field") + rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat( + vl, filename, "utf-8", vl.crs(), "GPKG" + ) self.assertEqual(rc, QgsVectorFileWriter.WriterError.NoError) # open the resulting geopackage - vl = QgsVectorLayer(filename + '.gpkg', '', 'ogr') + vl = QgsVectorLayer(filename + ".gpkg", "", "ogr") self.assertTrue(vl.isValid()) fields = vl.fields() # test type of converted field - idx = fields.indexFromName('binfield') + idx = fields.indexFromName("binfield") self.assertEqual(fields.at(idx).type(), QVariant.ByteArray) - idx2 = fields.indexFromName('binfield2') + idx2 = fields.indexFromName("binfield2") self.assertEqual(fields.at(idx2).type(), QVariant.ByteArray) # test values @@ -1294,150 +1447,173 @@ def testWriteWithBinaryField(self): self.assertEqual(vl.getFeature(1).attributes()[idx2], bin_val2) del vl - os.unlink(filename + '.gpkg') + os.unlink(filename + ".gpkg") def testWriteKMLAxisOrderIssueGDAL3(self): """Check axis order issue when writing KML with EPSG:4326.""" - if not ogr.GetDriverByName('KML'): + if not ogr.GetDriverByName("KML"): return vl = QgsVectorLayer( - 'PointZ?crs=epsg:4326&field=name:string(20)', - 'test', - 'memory') + "PointZ?crs=epsg:4326&field=name:string(20)", "test", "memory" + ) - self.assertTrue(vl.isValid(), 'Provider not initialized') + self.assertTrue(vl.isValid(), "Provider not initialized") ft = QgsFeature() - ft.setGeometry(QgsGeometry.fromWkt('Point(2 49)')) + ft.setGeometry(QgsGeometry.fromWkt("Point(2 49)")) myResult, myFeatures = vl.dataProvider().addFeatures([ft]) self.assertTrue(myResult) self.assertTrue(myFeatures) - dest_file_name = os.path.join(str(QDir.tempPath()), 'testWriteKMLAxisOrderIssueGDAL3.kml') + dest_file_name = os.path.join( + str(QDir.tempPath()), "testWriteKMLAxisOrderIssueGDAL3.kml" + ) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - vl, - dest_file_name, - 'utf-8', - vl.crs(), - 'KML') - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + vl, dest_file_name, "utf-8", vl.crs(), "KML" + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Open result and check - created_layer = QgsVectorLayer(dest_file_name, 'test', 'ogr') + created_layer = QgsVectorLayer(dest_file_name, "test", "ogr") self.assertTrue(created_layer.isValid()) f = next(created_layer.getFeatures(QgsFeatureRequest())) - self.assertEqual(f.geometry().asWkt(), 'Point Z (2 49 0)') + self.assertEqual(f.geometry().asWkt(), "Point Z (2 49 0)") def testWriteGpkgWithFID(self): """Check writing a memory layer with a FID column takes it as FID""" vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=FID:integer(0)&field=name:string(20)', - 'test', - 'memory') + "Point?crs=epsg:4326&field=FID:integer(0)&field=name:string(20)", + "test", + "memory", + ) - self.assertTrue(vl.isValid(), 'Provider not initialized') + self.assertTrue(vl.isValid(), "Provider not initialized") ft = QgsFeature(vl.fields()) - ft.setAttributes([123, 'text1']) - ft.setGeometry(QgsGeometry.fromWkt('Point(2 49)')) + ft.setAttributes([123, "text1"]) + ft.setGeometry(QgsGeometry.fromWkt("Point(2 49)")) myResult, myFeatures = vl.dataProvider().addFeatures([ft]) self.assertTrue(myResult) self.assertTrue(myFeatures) - dest_file_name = os.path.join(str(QDir.tempPath()), 'testWriteGpkgWithFID.gpkg') + dest_file_name = os.path.join(str(QDir.tempPath()), "testWriteGpkgWithFID.gpkg") write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - vl, - dest_file_name, - 'utf-8', - vl.crs(), - 'GPKG') - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + vl, dest_file_name, "utf-8", vl.crs(), "GPKG" + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Open result and check - created_layer = QgsVectorLayer(dest_file_name, 'test', 'ogr') + created_layer = QgsVectorLayer(dest_file_name, "test", "ogr") self.assertTrue(created_layer.isValid()) f = next(created_layer.getFeatures(QgsFeatureRequest())) - self.assertEqual(f.geometry().asWkt(), 'Point (2 49)') - self.assertEqual(f.attributes(), [123, 'text1']) + self.assertEqual(f.geometry().asWkt(), "Point (2 49)") + self.assertEqual(f.attributes(), [123, "text1"]) self.assertEqual(f.id(), 123) def testWriteTriangle(self): """Check we can write geometries with triangle types.""" layer = QgsVectorLayer( - ('MultiPolygonZ?crs=epsg:4326&field=name:string(20)'), - 'test', - 'memory') + ("MultiPolygonZ?crs=epsg:4326&field=name:string(20)"), "test", "memory" + ) ft = QgsFeature() geom = QgsMultiPolygon() - geom.addGeometry(QgsTriangle(QgsPoint(1, 2, 3), QgsPoint(2, 2, 4), QgsPoint(2, 3, 4))) + geom.addGeometry( + QgsTriangle(QgsPoint(1, 2, 3), QgsPoint(2, 2, 4), QgsPoint(2, 3, 4)) + ) ft.setGeometry(geom) - ft.setAttributes(['Johny']) + ft.setAttributes(["Johny"]) myResult, myFeatures = layer.dataProvider().addFeatures([ft]) self.assertTrue(myResult) self.assertTrue(myFeatures) - dest_file_name = os.path.join(str(QDir.tempPath()), 'testWriteTriangle.gpkg') + dest_file_name = os.path.join(str(QDir.tempPath()), "testWriteTriangle.gpkg") write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - layer, - dest_file_name, - 'utf-8', - layer.crs(), - 'GPKG') - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + layer, dest_file_name, "utf-8", layer.crs(), "GPKG" + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Open result and check - created_layer = QgsVectorLayer(dest_file_name, 'test', 'ogr') + created_layer = QgsVectorLayer(dest_file_name, "test", "ogr") self.assertTrue(created_layer.isValid()) f = next(created_layer.getFeatures(QgsFeatureRequest())) - self.assertEqual(f.geometry().asWkt(), 'MultiPolygon Z (((1 2 3, 2 2 4, 2 3 4, 1 2 3)))') - self.assertEqual(f.attributes(), [1, 'Johny']) + self.assertEqual( + f.geometry().asWkt(), "MultiPolygon Z (((1 2 3, 2 2 4, 2 3 4, 1 2 3)))" + ) + self.assertEqual(f.attributes(), [1, "Johny"]) def testWriteConversionErrors(self): """Test writing features with attribute values that cannot be converted to the destination fields. See: GH #36715""" - vl = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer', 'test', 'memory') + vl = QgsVectorLayer("Point?crs=epsg:4326&field=int:integer", "test", "memory") self.assertTrue(vl.startEditing()) f = QgsFeature(vl.fields()) - f.setGeometry(QgsGeometry.fromWkt('point(9 45)')) - f.setAttribute(0, 'QGIS Rocks!') # not valid! + f.setGeometry(QgsGeometry.fromWkt("point(9 45)")) + f.setAttribute(0, "QGIS Rocks!") # not valid! self.assertTrue(vl.addFeatures([f])) f.setAttribute(0, 12345) # valid! self.assertTrue(vl.addFeatures([f])) - dest_file_name = os.path.join(str(QDir.tempPath()), 'writer_conversion_errors.shp') + dest_file_name = os.path.join( + str(QDir.tempPath()), "writer_conversion_errors.shp" + ) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( vl, dest_file_name, - 'utf-8', + "utf-8", QgsCoordinateReferenceSystem(), - 'ESRI Shapefile') - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.ErrFeatureWriteFailed, error_message) + "ESRI Shapefile", + ) + self.assertEqual( + write_result, + QgsVectorFileWriter.WriterError.ErrFeatureWriteFailed, + error_message, + ) # Open result and check - created_layer = QgsVectorLayer(f'{dest_file_name}|layerid=0', 'test', 'ogr') + created_layer = QgsVectorLayer(f"{dest_file_name}|layerid=0", "test", "ogr") self.assertEqual(created_layer.fields().count(), 1) self.assertEqual(created_layer.featureCount(), 1) f = next(created_layer.getFeatures(QgsFeatureRequest())) - self.assertEqual(f['int'], 12345) + self.assertEqual(f["int"], 12345) def test_regression_37386(self): """Test issue GH #37386""" - dest_file_name = os.path.join(str(QDir.tempPath()), 'writer_regression_37386.gpkg') + dest_file_name = os.path.join( + str(QDir.tempPath()), "writer_regression_37386.gpkg" + ) fields = QgsFields() fields.append(QgsField("note", QVariant.Double)) lyrname = "test1" opts = QgsVectorFileWriter.SaveVectorOptions() opts.driverName = "GPKG" opts.layerName = lyrname - opts.actionOnExistingFile = QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteFile - writer = QgsVectorFileWriter.create(dest_file_name, fields, QgsWkbTypes.Type.Point, QgsCoordinateReferenceSystem.fromEpsgId(4326), QgsCoordinateTransformContext(), opts, QgsFeatureSink.SinkFlags(), None, lyrname) + opts.actionOnExistingFile = ( + QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteFile + ) + writer = QgsVectorFileWriter.create( + dest_file_name, + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem.fromEpsgId(4326), + QgsCoordinateTransformContext(), + opts, + QgsFeatureSink.SinkFlags(), + None, + lyrname, + ) self.assertEqual(writer.hasError(), QgsVectorFileWriter.WriterError.NoError) del writer vl = QgsVectorLayer(dest_file_name) @@ -1448,80 +1624,96 @@ def testPersistMetadata(self): Test that metadata from the source layer is saved as default for the destination if the persist metadat option is enabled """ - vl = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer', 'test', 'memory') + vl = QgsVectorLayer("Point?crs=epsg:4326&field=int:integer", "test", "memory") self.assertTrue(vl.startEditing()) f = QgsFeature(vl.fields()) - f.setGeometry(QgsGeometry.fromWkt('point(9 45)')) - f.setAttribute(0, 'QGIS Rocks!') # not valid! + f.setGeometry(QgsGeometry.fromWkt("point(9 45)")) + f.setAttribute(0, "QGIS Rocks!") # not valid! self.assertTrue(vl.addFeatures([f])) f.setAttribute(0, 12345) # valid! self.assertTrue(vl.addFeatures([f])) # set some metadata on the source layer metadata = QgsLayerMetadata() - metadata.setTitle('my title') - metadata.setAbstract('my abstract') - metadata.setLicenses(['l1', 'l2']) + metadata.setTitle("my title") + metadata.setAbstract("my abstract") + metadata.setLicenses(["l1", "l2"]) - dest_file_name = os.path.join(str(QDir.tempPath()), 'save_metadata.gpkg') + dest_file_name = os.path.join(str(QDir.tempPath()), "save_metadata.gpkg") options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'GPKG' - options.layerName = 'test' + options.driverName = "GPKG" + options.layerName = "test" options.saveMetadata = True options.layerMetadata = metadata - write_result, error_message, new_file, new_layer = QgsVectorFileWriter.writeAsVectorFormatV3( - vl, - dest_file_name, - QgsProject.instance().transformContext(), - options) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.ErrFeatureWriteFailed, error_message) + write_result, error_message, new_file, new_layer = ( + QgsVectorFileWriter.writeAsVectorFormatV3( + vl, dest_file_name, QgsProject.instance().transformContext(), options + ) + ) + self.assertEqual( + write_result, + QgsVectorFileWriter.WriterError.ErrFeatureWriteFailed, + error_message, + ) # Open result and check - created_layer = QgsVectorLayer(f'{new_file}|layerName={new_layer}', 'test', 'ogr') + created_layer = QgsVectorLayer( + f"{new_file}|layerName={new_layer}", "test", "ogr" + ) self.assertTrue(created_layer.isValid()) # layer should have metadata stored - self.assertEqual(created_layer.metadata().title(), 'my title') - self.assertEqual(created_layer.metadata().abstract(), 'my abstract') - self.assertEqual(created_layer.metadata().licenses(), ['l1', 'l2']) - - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 4, 0), "GDAL 3.4 required") + self.assertEqual(created_layer.metadata().title(), "my title") + self.assertEqual(created_layer.metadata().abstract(), "my abstract") + self.assertEqual(created_layer.metadata().licenses(), ["l1", "l2"]) + + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 4, 0), + "GDAL 3.4 required", + ) def testWriteWithCoordinateEpoch(self): """ Write a dataset with a coordinate epoch to geopackage """ layer = QgsVectorLayer( - ('Point?crs=epsg:4326&field=name:string(20)&' - 'field=age:integer&field=size:double&index=yes'), - 'test', - 'memory') + ( + "Point?crs=epsg:4326&field=name:string(20)&" + "field=age:integer&field=size:double&index=yes" + ), + "test", + "memory", + ) self.assertTrue(layer.isValid()) - crs = QgsCoordinateReferenceSystem('EPSG:4326') + crs = QgsCoordinateReferenceSystem("EPSG:4326") crs.setCoordinateEpoch(2020.7) layer.setCrs(crs) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) - ft.setAttributes(['Johny', 20, 0.3]) + ft.setAttributes(["Johny", 20, 0.3]) myResult, myFeatures = layer.dataProvider().addFeatures([ft]) self.assertTrue(myResult) self.assertTrue(myFeatures) - dest_file_name = os.path.join(str(QDir.tempPath()), 'writer_coordinate_epoch.gpkg') + dest_file_name = os.path.join( + str(QDir.tempPath()), "writer_coordinate_epoch.gpkg" + ) options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'GPKG' - options.layerName = 'test' - - write_result, error_message, new_file, new_layer = QgsVectorFileWriter.writeAsVectorFormatV3( - layer, - dest_file_name, - QgsProject.instance().transformContext(), - options) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + options.driverName = "GPKG" + options.layerName = "test" + + write_result, error_message, new_file, new_layer = ( + QgsVectorFileWriter.writeAsVectorFormatV3( + layer, dest_file_name, QgsProject.instance().transformContext(), options + ) + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # check that coordinate epoch was written to file vl = QgsVectorLayer(dest_file_name) @@ -1529,23 +1721,23 @@ def testWriteWithCoordinateEpoch(self): self.assertEqual(vl.crs().coordinateEpoch(), 2020.7) def testAddingToOpenedGkg(self): - """ Test scenario of https://github.com/qgis/QGIS/issues/48154 """ + """Test scenario of https://github.com/qgis/QGIS/issues/48154""" tmp_dir = QTemporaryDir() - tmpfile = os.path.join(tmp_dir.path(), 'testAddingToOpenedGkg.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) - lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) + tmpfile = os.path.join(tmp_dir.path(), "testAddingToOpenedGkg.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(tmpfile) + lyr = ds.CreateLayer("test", geom_type=ogr.wkbPoint) f = ogr.Feature(lyr.GetLayerDefn()) - f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)')) + f.SetGeometry(ogr.CreateGeometryFromWkt("POINT(0 0)")) lyr.CreateFeature(f) - del (lyr) - del (ds) + del lyr + del ds - vl = QgsVectorLayer(f'{tmpfile}|layername=test', 'test', 'ogr') + vl = QgsVectorLayer(f"{tmpfile}|layername=test", "test", "ogr") self.assertTrue(vl.isValid()) # Test CreateOrOverwriteLayer - ml = QgsVectorLayer('Point?field=firstfield:int', 'test', 'memory') + ml = QgsVectorLayer("Point?field=firstfield:int", "test", "memory") provider = ml.dataProvider() ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) @@ -1553,96 +1745,106 @@ def testAddingToOpenedGkg(self): provider.addFeatures([ft]) options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'GPKG' - options.layerName = 'test2' - options.actionOnExistingFile = QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteLayer + options.driverName = "GPKG" + options.layerName = "test2" + options.actionOnExistingFile = ( + QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteLayer + ) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - ml, - tmpfile, - options) - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + ml, tmpfile, options + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Check that we can open the layer - vl2 = QgsVectorLayer(f'{tmpfile}|layername=test2', 'test', 'ogr') + vl2 = QgsVectorLayer(f"{tmpfile}|layername=test2", "test", "ogr") self.assertTrue(vl2.isValid()) def testWriteUnsetAttributeToShapefile(self): - """ Test writing an unset attribute to a shapefile """ + """Test writing an unset attribute to a shapefile""" - vl = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer', 'test', 'memory') + vl = QgsVectorLayer("Point?crs=epsg:4326&field=int:integer", "test", "memory") self.assertTrue(vl.startEditing()) f = QgsFeature(vl.fields()) - f.setGeometry(QgsGeometry.fromWkt('point(9 45)')) - f.setAttribute(0, QgsUnsetAttributeValue('Autonumber')) + f.setGeometry(QgsGeometry.fromWkt("point(9 45)")) + f.setAttribute(0, QgsUnsetAttributeValue("Autonumber")) self.assertTrue(vl.addFeatures([f])) f.setAttribute(0, 12345) self.assertTrue(vl.addFeatures([f])) - dest_file_name = os.path.join(str(QDir.tempPath()), 'writing_unset_values.shp') + dest_file_name = os.path.join(str(QDir.tempPath()), "writing_unset_values.shp") write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( vl, dest_file_name, - 'utf-8', + "utf-8", QgsCoordinateReferenceSystem(), - 'ESRI Shapefile') - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + "ESRI Shapefile", + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Open result and check - created_layer = QgsVectorLayer(dest_file_name, 'test', 'ogr') + created_layer = QgsVectorLayer(dest_file_name, "test", "ogr") self.assertEqual(created_layer.fields().count(), 1) self.assertEqual(created_layer.featureCount(), 2) features = created_layer.getFeatures(QgsFeatureRequest()) f = next(features) - self.assertEqual(f['int'], NULL) + self.assertEqual(f["int"], NULL) f = next(features) - self.assertEqual(f['int'], 12345) + self.assertEqual(f["int"], 12345) def testWriteUnsetAttributeToGpkg(self): - """ Test writing an unset attribute to a gpkg """ + """Test writing an unset attribute to a gpkg""" - vl = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer', 'test', 'memory') + vl = QgsVectorLayer("Point?crs=epsg:4326&field=int:integer", "test", "memory") self.assertTrue(vl.startEditing()) f = QgsFeature(vl.fields()) - f.setGeometry(QgsGeometry.fromWkt('point(9 45)')) - f.setAttribute(0, QgsUnsetAttributeValue('Autonumber')) + f.setGeometry(QgsGeometry.fromWkt("point(9 45)")) + f.setAttribute(0, QgsUnsetAttributeValue("Autonumber")) self.assertTrue(vl.addFeatures([f])) f.setAttribute(0, 12345) self.assertTrue(vl.addFeatures([f])) - dest_file_name = os.path.join(str(QDir.tempPath()), 'writing_unset_values.gpkg') + dest_file_name = os.path.join(str(QDir.tempPath()), "writing_unset_values.gpkg") write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - vl, - dest_file_name, - 'utf-8', - QgsCoordinateReferenceSystem(), - 'GPKG') - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + vl, dest_file_name, "utf-8", QgsCoordinateReferenceSystem(), "GPKG" + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) # Open result and check - created_layer = QgsVectorLayer(dest_file_name, 'test', 'ogr') + created_layer = QgsVectorLayer(dest_file_name, "test", "ogr") self.assertEqual(created_layer.fields().count(), 2) self.assertEqual(created_layer.featureCount(), 2) features = created_layer.getFeatures(QgsFeatureRequest()) f = next(features) - self.assertEqual(f['int'], NULL) + self.assertEqual(f["int"], NULL) f = next(features) - self.assertEqual(f['int'], 12345) + self.assertEqual(f["int"], 12345) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0), + "GDAL 3.7 required", + ) def testWriteJsonMapToGpkg(self): tmp_dir = QTemporaryDir() tmp_path = tmp_dir.path() - dest_file_name = os.path.join(tmp_path, 'test.gpkg') - ds = ogr.GetDriverByName('GPKG').CreateDataSource(dest_file_name) - lyr = ds.CreateLayer('testLayer', geom_type=ogr.wkbLineString, options=['SPATIAL_INDEX=NO']) - field_def = ogr.FieldDefn('text_field', ogr.OFTString) + dest_file_name = os.path.join(tmp_path, "test.gpkg") + ds = ogr.GetDriverByName("GPKG").CreateDataSource(dest_file_name) + lyr = ds.CreateLayer( + "testLayer", geom_type=ogr.wkbLineString, options=["SPATIAL_INDEX=NO"] + ) + field_def = ogr.FieldDefn("text_field", ogr.OFTString) field_def.SetSubType(ogr.OFSTJSON) lyr.CreateField(field_def) f = ogr.Feature(lyr.GetLayerDefn()) - attr_val = {'my_int': 1, 'my_str': 'str', 'my_list': [1, 2, 3]} - f['text_field'] = json.dumps(attr_val) - f.SetGeometry(ogr.CreateGeometryFromWkt('LINESTRING(1 2,3 4)')) + attr_val = {"my_int": 1, "my_str": "str", "my_list": [1, 2, 3]} + f["text_field"] = json.dumps(attr_val) + f.SetGeometry(ogr.CreateGeometryFromWkt("LINESTRING(1 2,3 4)")) lyr.CreateFeature(f) f = None ds = None @@ -1654,14 +1856,13 @@ def testWriteJsonMapToGpkg(self): f = next(layer.getFeatures()) self.assertEqual(f.attributes()[1], attr_val) - dest_file_name_exported = os.path.join(tmp_path, 'test_exported.gpkg') + dest_file_name_exported = os.path.join(tmp_path, "test_exported.gpkg") write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - layer, - dest_file_name_exported, - 'utf-8', - layer.crs(), - 'GPKG') - self.assertEqual(write_result, QgsVectorFileWriter.WriterError.NoError, error_message) + layer, dest_file_name_exported, "utf-8", layer.crs(), "GPKG" + ) + self.assertEqual( + write_result, QgsVectorFileWriter.WriterError.NoError, error_message + ) layer = QgsVectorLayer(dest_file_name_exported) fields = layer.fields() @@ -1670,61 +1871,78 @@ def testWriteJsonMapToGpkg(self): f = next(layer.getFeatures()) self.assertEqual(f.attributes()[1], attr_val) - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7 required") + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 7, 0), + "GDAL 3.7 required", + ) def test_field_capabilities(self): with tempfile.TemporaryDirectory() as temp_dir: - dest_file_name = os.path.join(temp_dir, - 'test_gpkg.gpkg') + dest_file_name = os.path.join(temp_dir, "test_gpkg.gpkg") fields = QgsFields() fields.append(QgsField("note", QVariant.Double)) lyrname = "test1" opts = QgsVectorFileWriter.SaveVectorOptions() opts.driverName = "GPKG" opts.layerName = lyrname - opts.actionOnExistingFile = QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteFile - writer = QgsVectorFileWriter.create(dest_file_name, fields, - QgsWkbTypes.Type.Point, - QgsCoordinateReferenceSystem.fromEpsgId( - 4326), - QgsCoordinateTransformContext(), - opts, QgsFeatureSink.SinkFlags(), - None, lyrname) - - self.assertEqual(writer.driver(), 'GPKG') - self.assertEqual(writer.driverLongName(), 'GeoPackage') + opts.actionOnExistingFile = ( + QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteFile + ) + writer = QgsVectorFileWriter.create( + dest_file_name, + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem.fromEpsgId(4326), + QgsCoordinateTransformContext(), + opts, + QgsFeatureSink.SinkFlags(), + None, + lyrname, + ) + + self.assertEqual(writer.driver(), "GPKG") + self.assertEqual(writer.driverLongName(), "GeoPackage") self.assertTrue( - writer.capabilities() & Qgis.VectorFileWriterCapability.FieldAliases) + writer.capabilities() & Qgis.VectorFileWriterCapability.FieldAliases + ) self.assertTrue( - writer.capabilities() & Qgis.VectorFileWriterCapability.FieldComments) + writer.capabilities() & Qgis.VectorFileWriterCapability.FieldComments + ) - dest_file_name = os.path.join(temp_dir, - 'test_shp.shp') + dest_file_name = os.path.join(temp_dir, "test_shp.shp") opts.driverName = "ESRI Shapefile" - writer = QgsVectorFileWriter.create(dest_file_name, fields, - QgsWkbTypes.Type.Point, - QgsCoordinateReferenceSystem.fromEpsgId( - 4326), - QgsCoordinateTransformContext(), - opts, - QgsFeatureSink.SinkFlags(), - None, lyrname) - - self.assertEqual(writer.driver(), 'ESRI Shapefile') - self.assertEqual(writer.driverLongName(), 'ESRI Shapefile') + writer = QgsVectorFileWriter.create( + dest_file_name, + fields, + QgsWkbTypes.Type.Point, + QgsCoordinateReferenceSystem.fromEpsgId(4326), + QgsCoordinateTransformContext(), + opts, + QgsFeatureSink.SinkFlags(), + None, + lyrname, + ) + + self.assertEqual(writer.driver(), "ESRI Shapefile") + self.assertEqual(writer.driverLongName(), "ESRI Shapefile") self.assertFalse( - writer.capabilities() & Qgis.VectorFileWriterCapability.FieldAliases) + writer.capabilities() & Qgis.VectorFileWriterCapability.FieldAliases + ) self.assertFalse( - writer.capabilities() & Qgis.VectorFileWriterCapability.FieldComments) + writer.capabilities() & Qgis.VectorFileWriterCapability.FieldComments + ) def testWriteFieldConstraints(self): """ Test explicitly including field constraints. """ layer = QgsVectorLayer( - ('Point?crs=epsg:4326&field=name:string(20)&' - 'field=age:integer&field=size:double'), - 'test', - 'memory') + ( + "Point?crs=epsg:4326&field=name:string(20)&" + "field=age:integer&field=size:double" + ), + "test", + "memory", + ) self.assertTrue(layer.isValid()) myProvider = layer.dataProvider() @@ -1734,7 +1952,7 @@ def testWriteFieldConstraints(self): ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) - ft.setAttributes(['Johny', 20, 0.3]) + ft.setAttributes(["Johny", 20, 0.3]) myResult, myFeatures = myProvider.addFeatures([ft]) self.assertTrue(myResult) self.assertTrue(myFeatures) @@ -1742,34 +1960,43 @@ def testWriteFieldConstraints(self): options = QgsVectorFileWriter.SaveVectorOptions() options.includeConstraints = True - dest = os.path.join(str(QDir.tempPath()), 'constraints.gpkg') + dest = os.path.join(str(QDir.tempPath()), "constraints.gpkg") result, err = QgsVectorFileWriter.writeAsVectorFormatV2( - layer, - dest, - QgsProject.instance().transformContext(), - options) + layer, dest, QgsProject.instance().transformContext(), options + ) self.assertEqual(result, QgsVectorFileWriter.WriterError.NoError) - res = QgsVectorLayer(dest, 'result') + res = QgsVectorLayer(dest, "result") self.assertTrue(res.isValid()) - self.assertEqual([f.name() for f in res.fields()], ['fid', 'name', 'age', 'size']) - - self.assertEqual(res.fields()['name'].constraints().constraints(), - QgsFieldConstraints.Constraints()) - self.assertEqual(res.fields()['age'].constraints().constraints(), - QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertEqual(res.fields()['size'].constraints().constraints(), - QgsFieldConstraints.Constraint.ConstraintUnique) + self.assertEqual( + [f.name() for f in res.fields()], ["fid", "name", "age", "size"] + ) + + self.assertEqual( + res.fields()["name"].constraints().constraints(), + QgsFieldConstraints.Constraints(), + ) + self.assertEqual( + res.fields()["age"].constraints().constraints(), + QgsFieldConstraints.Constraint.ConstraintNotNull, + ) + self.assertEqual( + res.fields()["size"].constraints().constraints(), + QgsFieldConstraints.Constraint.ConstraintUnique, + ) def testWriteSkipFieldConstraints(self): """ Test that default is to skip field constraints. """ layer = QgsVectorLayer( - ('Point?crs=epsg:4326&field=name:string(20)&' - 'field=age:integer&field=size:double'), - 'test', - 'memory') + ( + "Point?crs=epsg:4326&field=name:string(20)&" + "field=age:integer&field=size:double" + ), + "test", + "memory", + ) self.assertTrue(layer.isValid()) myProvider = layer.dataProvider() @@ -1779,59 +2006,73 @@ def testWriteSkipFieldConstraints(self): ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) - ft.setAttributes(['Johny', 20, 0.3]) + ft.setAttributes(["Johny", 20, 0.3]) myResult, myFeatures = myProvider.addFeatures([ft]) self.assertTrue(myResult) self.assertTrue(myFeatures) options = QgsVectorFileWriter.SaveVectorOptions() - dest = os.path.join(str(QDir.tempPath()), 'constraints.gpkg') + dest = os.path.join(str(QDir.tempPath()), "constraints.gpkg") result, err = QgsVectorFileWriter.writeAsVectorFormatV2( - layer, - dest, - QgsProject.instance().transformContext(), - options) + layer, dest, QgsProject.instance().transformContext(), options + ) self.assertEqual(result, QgsVectorFileWriter.WriterError.NoError) - res = QgsVectorLayer(dest, 'result') + res = QgsVectorLayer(dest, "result") self.assertTrue(res.isValid()) - self.assertEqual([f.name() for f in res.fields()], ['fid', 'name', 'age', 'size']) - - self.assertEqual(res.fields()['name'].constraints().constraints(), - QgsFieldConstraints.Constraints()) - self.assertEqual(res.fields()['age'].constraints().constraints(), - QgsFieldConstraints.Constraints()) - self.assertEqual(res.fields()['size'].constraints().constraints(), - QgsFieldConstraints.Constraints()) - - @unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 5, 0), "GDAL 3.5 required") + self.assertEqual( + [f.name() for f in res.fields()], ["fid", "name", "age", "size"] + ) + + self.assertEqual( + res.fields()["name"].constraints().constraints(), + QgsFieldConstraints.Constraints(), + ) + self.assertEqual( + res.fields()["age"].constraints().constraints(), + QgsFieldConstraints.Constraints(), + ) + self.assertEqual( + res.fields()["size"].constraints().constraints(), + QgsFieldConstraints.Constraints(), + ) + + @unittest.skipIf( + int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(3, 5, 0), + "GDAL 3.5 required", + ) def testFieldDomains(self): """ Test that field domain and field domain names are copied """ - src_vl = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'domains.gpkg'), 'test', 'ogr') + src_vl = QgsVectorLayer( + os.path.join(TEST_DATA_DIR, "domains.gpkg"), "test", "ogr" + ) self.assertTrue(src_vl.isValid()) options = QgsVectorFileWriter.SaveVectorOptions() - dest = os.path.join(str(QDir.tempPath()), 'domains.gpkg') + dest = os.path.join(str(QDir.tempPath()), "domains.gpkg") result, err = QgsVectorFileWriter.writeAsVectorFormatV2( - src_vl, - dest, - QgsProject.instance().transformContext(), - options) + src_vl, dest, QgsProject.instance().transformContext(), options + ) self.assertEqual(result, QgsVectorFileWriter.WriterError.NoError) - vl = QgsVectorLayer(dest, 'result') + vl = QgsVectorLayer(dest, "result") fields = vl.fields() - self.assertEqual(fields.field('with_range_domain_int').constraints().domainName(), 'range_domain_int') - self.assertEqual(fields.field('with_glob_domain').constraints().domainName(), 'glob_domain') + self.assertEqual( + fields.field("with_range_domain_int").constraints().domainName(), + "range_domain_int", + ) + self.assertEqual( + fields.field("with_glob_domain").constraints().domainName(), "glob_domain" + ) db_conn = QgsMapLayerUtils.databaseConnection(vl) self.assertIsNotNone(db_conn.fieldDomain("range_domain_int")) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorfilewriter_postgres.py b/tests/src/python/test_qgsvectorfilewriter_postgres.py index f793523a8d0d..f7633e6c0ece 100644 --- a/tests/src/python/test_qgsvectorfilewriter_postgres.py +++ b/tests/src/python/test_qgsvectorfilewriter_postgres.py @@ -6,9 +6,9 @@ (at your option) any later version. """ -__author__ = 'Julien Cabieces' -__date__ = '22/03/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' +__author__ = "Julien Cabieces" +__date__ = "22/03/2021" +__copyright__ = "Copyright 2021, The QGIS Project" import os @@ -32,36 +32,36 @@ class TestQgsVectorFileWriterPG(QgisTestCase): def testWriteWithBoolField(self): # init connection string - dbconn = 'service=qgis_test' - if 'QGIS_PGTEST_DB' in os.environ: - dbconn = os.environ['QGIS_PGTEST_DB'] + dbconn = "service=qgis_test" + if "QGIS_PGTEST_DB" in os.environ: + dbconn = os.environ["QGIS_PGTEST_DB"] # create a vector layer - vl = QgsVectorLayer(f'{dbconn} table="qgis_test"."boolean_table" sql=', "testbool", "postgres") + vl = QgsVectorLayer( + f'{dbconn} table="qgis_test"."boolean_table" sql=', "testbool", "postgres" + ) self.assertTrue(vl.isValid()) # check that 1 of its fields is a bool fields = vl.fields() - self.assertEqual(fields.at(fields.indexFromName('fld1')).type(), QVariant.Bool) + self.assertEqual(fields.at(fields.indexFromName("fld1")).type(), QVariant.Bool) # write a gpkg package with a bool field - crs = QgsCoordinateReferenceSystem('EPSG:4326') - filename = os.path.join(str(QDir.tempPath()), 'with_bool_field') - rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat(vl, - filename, - 'utf-8', - crs, - 'GPKG') + crs = QgsCoordinateReferenceSystem("EPSG:4326") + filename = os.path.join(str(QDir.tempPath()), "with_bool_field") + rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat( + vl, filename, "utf-8", crs, "GPKG" + ) self.assertEqual(rc, QgsVectorFileWriter.WriterError.NoError) # open the resulting geopackage - vl = QgsVectorLayer(filename + '.gpkg', '', 'ogr') + vl = QgsVectorLayer(filename + ".gpkg", "", "ogr") self.assertTrue(vl.isValid()) fields = vl.fields() # test type of converted field - idx = fields.indexFromName('fld1') + idx = fields.indexFromName("fld1") self.assertEqual(fields.at(idx).type(), QVariant.Bool) # test values @@ -69,8 +69,8 @@ def testWriteWithBoolField(self): self.assertEqual(vl.getFeature(2).attributes()[idx], 0) del vl - os.unlink(filename + '.gpkg') + os.unlink(filename + ".gpkg") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorfilewritertask.py b/tests/src/python/test_qgsvectorfilewritertask.py index 52c26d70ac47..097cf9adf1ac 100644 --- a/tests/src/python/test_qgsvectorfilewritertask.py +++ b/tests/src/python/test_qgsvectorfilewritertask.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '12/02/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "12/02/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os @@ -34,8 +35,8 @@ def create_temp_filename(base_file): class TestQgsVectorFileWriterTask(QgisTestCase): def setUp(self): - self.new_filename = '' - self.new_layer = '' + self.new_filename = "" + self.new_layer = "" self.success = False self.fail = False @@ -52,18 +53,21 @@ def onFail(self): def createLayer(self): layer = QgsVectorLayer( - ('Point?crs=epsg:4326&field=name:string(20)&' - 'field=age:integer&field=size:double&index=yes'), - 'test', - 'memory') - - self.assertIsNotNone(layer, 'Provider not initialized') + ( + "Point?crs=epsg:4326&field=name:string(20)&" + "field=age:integer&field=size:double&index=yes" + ), + "test", + "memory", + ) + + self.assertIsNotNone(layer, "Provider not initialized") provider = layer.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) - ft.setAttributes(['Johny', 20, 0.3]) + ft.setAttributes(["Johny", 20, 0.3]) provider.addFeatures([ft]) return layer @@ -71,7 +75,7 @@ def testSuccess(self): """test successfully writing a layer""" self.layer = self.createLayer() options = QgsVectorFileWriter.SaveVectorOptions() - tmp = create_temp_filename('successlayer.shp') + tmp = create_temp_filename("successlayer.shp") task = QgsVectorFileWriterTask(self.layer, tmp, options) task.writeComplete.connect(self.onSuccess) @@ -90,7 +94,7 @@ def testSuccessWithLayer(self): options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = "KML" options.layerName = "test-dashes" - tmp = create_temp_filename('successlayer.kml') + tmp = create_temp_filename("successlayer.kml") task = QgsVectorFileWriterTask(self.layer, tmp, options) task.completed.connect(self.onComplete) @@ -108,7 +112,7 @@ def testLayerRemovalBeforeRun(self): """test behavior when layer is removed before task begins""" self.layer = self.createLayer() options = QgsVectorFileWriter.SaveVectorOptions() - tmp = create_temp_filename('fail.shp') + tmp = create_temp_filename("fail.shp") task = QgsVectorFileWriterTask(self.layer, tmp, options) task.writeComplete.connect(self.onSuccess) @@ -128,7 +132,7 @@ def testNoLayer(self): """test that failure (and not crash) occurs when no layer set""" options = QgsVectorFileWriter.SaveVectorOptions() - tmp = create_temp_filename('fail.shp') + tmp = create_temp_filename("fail.shp") task = QgsVectorFileWriterTask(None, tmp, options) task.writeComplete.connect(self.onSuccess) task.errorOccurred.connect(self.onFail) @@ -146,7 +150,7 @@ def testFieldValueConverter(self): options = QgsVectorFileWriter.SaveVectorOptions() converter = QgsVectorFileWriter.FieldValueConverter() options.fieldValueConverter = converter - tmp = create_temp_filename('converter.shp') + tmp = create_temp_filename("converter.shp") task = QgsVectorFileWriterTask(self.layer, tmp, options) task.writeComplete.connect(self.onSuccess) @@ -162,5 +166,5 @@ def testFieldValueConverter(self): self.assertFalse(self.fail) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorlayer.py b/tests/src/python/test_qgsvectorlayer.py index c6b4918d00a1..9fddac4f96f2 100644 --- a/tests/src/python/test_qgsvectorlayer.py +++ b/tests/src/python/test_qgsvectorlayer.py @@ -8,9 +8,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Tim Sutton' -__date__ = '20/08/2012' -__copyright__ = 'Copyright 2012, The QGIS Project' + +__author__ = "Tim Sutton" +__date__ = "20/08/2012" +__copyright__ = "Copyright 2012, The QGIS Project" import glob import os @@ -100,14 +101,17 @@ def createEmptyLayer(): def createEmptyLayerWithFields(): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) assert layer.featureCount() == 0 return layer def createLayerWithOnePoint(): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) pr = layer.dataProvider() f = QgsFeature() f.setAttributes(["test", 123]) @@ -118,8 +122,9 @@ def createLayerWithOnePoint(): def createLayerWithTwoPoints(): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) pr = layer.dataProvider() f = QgsFeature() f.setAttributes(["test", 123]) @@ -133,8 +138,9 @@ def createLayerWithTwoPoints(): def createLayerWithFivePoints(): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) pr = layer.dataProvider() f = QgsFeature() f.setAttributes(["test", 123]) @@ -159,7 +165,9 @@ def createLayerWithFivePoints(): def createJoinLayer(): joinLayer = QgsVectorLayer( "Point?field=x:string&field=y:integer&field=z:integer&field=date:datetime", - "joinlayer", "memory") + "joinlayer", + "memory", + ) pr = joinLayer.dataProvider() f1 = QgsFeature() f1.setAttributes(["foo", 123, 321, QDateTime(QDate(2010, 1, 1), QTime(0, 0, 0))]) @@ -200,9 +208,10 @@ def dumpEditBuffer(layer): return print("ADDED:") for fid, f in editBuffer.addedFeatures().items(): - print("%d: %s | %s" % ( - f.id(), formatAttributes(f.attributes()), - f.geometry().asWkt())) + print( + "%d: %s | %s" + % (f.id(), formatAttributes(f.attributes()), f.geometry().asWkt()) + ) print("CHANGED GEOM:") for fid, geom in editBuffer.changedGeometries().items(): print("%d | %s" % (f.id(), f.geometry().asWkt())) @@ -213,28 +222,74 @@ class TestQgsVectorLayer(QgisTestCase, FeatureSourceTestCase): @classmethod def getSource(cls): vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk', - 'test', 'memory') - assert (vl.isValid()) + "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk", + "test", + "memory", + ) + assert vl.isValid() f1 = QgsFeature() - f1.setAttributes([5, -200, NULL, 'NuLl', '5', QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), QDate(2020, 5, 2), QTime(12, 13, 1)]) - f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)')) + f1.setAttributes( + [ + 5, + -200, + NULL, + "NuLl", + "5", + QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), + QDate(2020, 5, 2), + QTime(12, 13, 1), + ] + ) + f1.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)")) f2 = QgsFeature() - f2.setAttributes([3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL]) + f2.setAttributes([3, 300, "Pear", "PEaR", "3", NULL, NULL, NULL]) f3 = QgsFeature() - f3.setAttributes([1, 100, 'Orange', 'oranGe', '1', QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), QDate(2020, 5, 3), QTime(12, 13, 14)]) - f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)')) + f3.setAttributes( + [ + 1, + 100, + "Orange", + "oranGe", + "1", + QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), + QDate(2020, 5, 3), + QTime(12, 13, 14), + ] + ) + f3.setGeometry(QgsGeometry.fromWkt("Point (-70.332 66.33)")) f4 = QgsFeature() - f4.setAttributes([2, 200, 'Apple', 'Apple', '2', QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), QDate(2020, 5, 4), QTime(12, 14, 14)]) - f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)')) + f4.setAttributes( + [ + 2, + 200, + "Apple", + "Apple", + "2", + QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), + QDate(2020, 5, 4), + QTime(12, 14, 14), + ] + ) + f4.setGeometry(QgsGeometry.fromWkt("Point (-68.2 70.8)")) f5 = QgsFeature() - f5.setAttributes([4, 400, 'Honey', 'Honey', '4', QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), QDate(2021, 5, 4), QTime(13, 13, 14)]) - f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)')) + f5.setAttributes( + [ + 4, + 400, + "Honey", + "Honey", + "4", + QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), + QDate(2021, 5, 4), + QTime(13, 13, 14), + ] + ) + f5.setGeometry(QgsGeometry.fromWkt("Point (-65.32 78.3)")) vl.dataProvider().addFeatures([f1, f2, f3, f4, f5]) return vl @@ -242,26 +297,26 @@ def getSource(cls): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestQgsVectorLayer, cls).setUpClass() + super().setUpClass() QgsGui.editorWidgetRegistry().initEditors() # Create test layer for FeatureSourceTestCase cls.source = cls.getSource() def testGetFeaturesSubsetAttributes2(self): - """ Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return + """Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass def testGetFeaturesNoGeometry(self): - """ Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return + """Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass def test_FeatureCount(self): - myPath = os.path.join(unitTestDataPath(), 'lines.shp') - myLayer = QgsVectorLayer(myPath, 'Lines', 'ogr') + myPath = os.path.join(unitTestDataPath(), "lines.shp") + myLayer = QgsVectorLayer(myPath, "Lines", "ogr") myCount = myLayer.featureCount() self.assertEqual(myCount, 6) @@ -339,7 +394,9 @@ def testSetDataSource(self): """ layer = createLayerWithOnePoint() layer.setCrs(QgsCoordinateReferenceSystem("epsg:3111")) - r = QgsSingleSymbolRenderer(QgsSymbol.defaultSymbol(QgsWkbTypes.GeometryType.PointGeometry)) + r = QgsSingleSymbolRenderer( + QgsSymbol.defaultSymbol(QgsWkbTypes.GeometryType.PointGeometry) + ) layer.setRenderer(r) self.assertEqual(layer.renderer().symbol().type(), QgsSymbol.SymbolType.Marker) @@ -347,13 +404,13 @@ def testSetDataSource(self): options = QgsDataProvider.ProviderOptions() # change with layer of same type - points_path = os.path.join(unitTestDataPath(), 'points.shp') - layer.setDataSource(points_path, 'new name', 'ogr', options) + points_path = os.path.join(unitTestDataPath(), "points.shp") + layer.setDataSource(points_path, "new name", "ogr", options) self.assertTrue(layer.isValid()) - self.assertEqual(layer.name(), 'new name') + self.assertEqual(layer.name(), "new name") self.assertEqual(layer.wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(layer.crs().authid(), 'EPSG:4326') + self.assertEqual(layer.crs().authid(), "EPSG:4326") self.assertIn(points_path, layer.dataProvider().dataSourceUri()) self.assertEqual(len(spy), 1) @@ -361,13 +418,13 @@ def testSetDataSource(self): self.assertEqual(layer.renderer(), r) # layer with different type - lines_path = os.path.join(unitTestDataPath(), 'rectangles.shp') - layer.setDataSource(lines_path, 'new name2', 'ogr', options) + lines_path = os.path.join(unitTestDataPath(), "rectangles.shp") + layer.setDataSource(lines_path, "new name2", "ogr", options) self.assertTrue(layer.isValid()) - self.assertEqual(layer.name(), 'new name2') + self.assertEqual(layer.name(), "new name2") self.assertEqual(layer.wkbType(), QgsWkbTypes.Type.MultiPolygon) - self.assertEqual(layer.crs().authid(), 'EPSG:4326') + self.assertEqual(layer.crs().authid(), "EPSG:4326") self.assertIn(lines_path, layer.dataProvider().dataSourceUri()) self.assertEqual(len(spy), 2) @@ -376,14 +433,14 @@ def testSetDataSource(self): self.assertEqual(layer.renderer().symbol().type(), QgsSymbol.SymbolType.Fill) # reset layer to a non-spatial layer - lines_path = os.path.join(unitTestDataPath(), 'nonspatial.dbf') - layer.setDataSource(lines_path, 'new name2', 'ogr', options) + lines_path = os.path.join(unitTestDataPath(), "nonspatial.dbf") + layer.setDataSource(lines_path, "new name2", "ogr", options) self.assertTrue(layer.isValid()) - self.assertEqual(layer.name(), 'new name2') + self.assertEqual(layer.name(), "new name2") self.assertEqual(layer.wkbType(), QgsWkbTypes.Type.NoGeometry) self.assertFalse(layer.crs().isValid()) - self.assertIn('nonspatial.dbf', layer.dataProvider().dataSourceUri()) + self.assertIn("nonspatial.dbf", layer.dataProvider().dataSourceUri()) self.assertEqual(len(spy), 3) # should have REMOVED renderer self.assertIsNone(layer.renderer()) @@ -394,30 +451,32 @@ def testSetDataSourceInvalidToValid(self): """ layer = createLayerWithOnePoint() layer.setCrs(QgsCoordinateReferenceSystem("epsg:3111")) - r = QgsSingleSymbolRenderer(QgsSymbol.defaultSymbol(QgsWkbTypes.GeometryType.PointGeometry)) + r = QgsSingleSymbolRenderer( + QgsSymbol.defaultSymbol(QgsWkbTypes.GeometryType.PointGeometry) + ) layer.setRenderer(r) self.assertEqual(layer.renderer().symbol().type(), QgsSymbol.SymbolType.Marker) # change to invalid path options = QgsDataProvider.ProviderOptions() - layer.setDataSource('nothing', 'new name', 'ogr', options) + layer.setDataSource("nothing", "new name", "ogr", options) self.assertFalse(layer.isValid()) # these properties should be kept intact! - self.assertEqual(layer.name(), 'new name') + self.assertEqual(layer.name(), "new name") self.assertEqual(layer.wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(layer.crs().authid(), 'EPSG:3111') + self.assertEqual(layer.crs().authid(), "EPSG:3111") # should have kept the same renderer! self.assertEqual(layer.renderer(), r) # set to a valid path - points_path = os.path.join(unitTestDataPath(), 'points.shp') - layer.setDataSource(points_path, 'new name2', 'ogr', options) + points_path = os.path.join(unitTestDataPath(), "points.shp") + layer.setDataSource(points_path, "new name2", "ogr", options) self.assertTrue(layer.isValid()) - self.assertEqual(layer.name(), 'new name2') + self.assertEqual(layer.name(), "new name2") self.assertEqual(layer.wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(layer.crs().authid(), 'EPSG:4326') + self.assertEqual(layer.crs().authid(), "EPSG:4326") self.assertIn(points_path, layer.dataProvider().dataSourceUri()) # should STILL have kept renderer! @@ -428,38 +487,38 @@ def testSetCustomProperty(self): Test setting a custom property of the layer """ layer = createLayerWithOnePoint() - layer.setCustomProperty('Key_0', 'Value_0') - layer.setCustomProperty('Key_1', 'Value_1') + layer.setCustomProperty("Key_0", "Value_0") + layer.setCustomProperty("Key_1", "Value_1") spy = QSignalSpy(layer.customPropertyChanged) # change nothing by setting the same value - layer.setCustomProperty('Key_0', 'Value_0') - layer.setCustomProperty('Key_1', 'Value_1') + layer.setCustomProperty("Key_0", "Value_0") + layer.setCustomProperty("Key_1", "Value_1") self.assertEqual(len(spy), 0) # change one - layer.setCustomProperty('Key_0', 'Value zero') + layer.setCustomProperty("Key_0", "Value zero") self.assertEqual(len(spy), 1) # add one - layer.setCustomProperty('Key_2', 'Value two') + layer.setCustomProperty("Key_2", "Value two") self.assertEqual(len(spy), 2) # add a null one and an empty one - layer.setCustomProperty('Key_3', None) - layer.setCustomProperty('Key_4', '') + layer.setCustomProperty("Key_3", None) + layer.setCustomProperty("Key_4", "") self.assertEqual(len(spy), 4) # remove one - layer.removeCustomProperty('Key_0') + layer.removeCustomProperty("Key_0") self.assertEqual(len(spy), 5) - self.assertEqual(layer.customProperty('Key_0', 'no value'), 'no value') - self.assertEqual(layer.customProperty('Key_1', 'no value'), 'Value_1') - self.assertEqual(layer.customProperty('Key_2', 'no value'), 'Value two') - self.assertEqual(layer.customProperty('Key_3', 'no value'), None) - self.assertEqual(layer.customProperty('Key_4', 'no value'), '') + self.assertEqual(layer.customProperty("Key_0", "no value"), "no value") + self.assertEqual(layer.customProperty("Key_1", "no value"), "Value_1") + self.assertEqual(layer.customProperty("Key_2", "no value"), "Value two") + self.assertEqual(layer.customProperty("Key_3", "no value"), None) + self.assertEqual(layer.customProperty("Key_4", "no value"), "") self.assertEqual(len(spy), 5) @@ -468,37 +527,39 @@ def testStoreWkbTypeInvalidLayers(self): Test that layer wkb types are restored for projects with invalid layer paths """ layer = createLayerWithOnePoint() - layer.setName('my test layer') - r = QgsSingleSymbolRenderer(QgsSymbol.defaultSymbol(QgsWkbTypes.GeometryType.PointGeometry)) - r.symbol().setColor(QColor('#123456')) + layer.setName("my test layer") + r = QgsSingleSymbolRenderer( + QgsSymbol.defaultSymbol(QgsWkbTypes.GeometryType.PointGeometry) + ) + r.symbol().setColor(QColor("#123456")) layer.setRenderer(r) - self.assertEqual(layer.renderer().symbol().color().name(), '#123456') + self.assertEqual(layer.renderer().symbol().color().name(), "#123456") p = QgsProject() p.addMapLayer(layer) # reset layer to a bad path options = QgsDataProvider.ProviderOptions() - layer.setDataSource('nothing', 'new name', 'ogr', options) + layer.setDataSource("nothing", "new name", "ogr", options) # should have kept the same renderer and wkb type! self.assertEqual(layer.wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(layer.renderer().symbol().color().name(), '#123456') + self.assertEqual(layer.renderer().symbol().color().name(), "#123456") # save project to a temporary file temp_path = tempfile.mkdtemp() - temp_project_path = os.path.join(temp_path, 'temp.qgs') + temp_project_path = os.path.join(temp_path, "temp.qgs") self.assertTrue(p.write(temp_project_path)) # restore project p2 = QgsProject() self.assertTrue(p2.read(temp_project_path)) - l2 = p2.mapLayersByName('new name')[0] + l2 = p2.mapLayersByName("new name")[0] self.assertFalse(l2.isValid()) # should have kept the same renderer and wkb type! self.assertEqual(l2.wkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(l2.renderer().symbol().color().name(), '#123456') + self.assertEqual(l2.renderer().symbol().color().name(), "#123456") shutil.rmtree(temp_path, True) @@ -506,7 +567,7 @@ def testFallbackCrsWkbType(self): """ Test fallback CRS and WKB types are used when layer path is invalid """ - vl = QgsVectorLayer('this is an outrage!!!') + vl = QgsVectorLayer("this is an outrage!!!") self.assertFalse(vl.isValid()) # I'd certainly hope so... self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.Unknown) self.assertFalse(vl.crs().isValid()) @@ -518,23 +579,23 @@ def testFallbackCrsWkbType(self): vl = QgsVectorLayer("i'm the moon", options=options) self.assertFalse(vl.isValid()) self.assertEqual(vl.wkbType(), QgsWkbTypes.Type.CircularString) - self.assertEqual(vl.crs().authid(), 'EPSG:3111') + self.assertEqual(vl.crs().authid(), "EPSG:3111") def test_layer_crs(self): """ Test that spatial layers have CRS, and non-spatial don't """ - vl = QgsVectorLayer('Point?crs=epsg:3111&field=pk:integer', 'test', 'memory') + vl = QgsVectorLayer("Point?crs=epsg:3111&field=pk:integer", "test", "memory") self.assertTrue(vl.isSpatial()) self.assertTrue(vl.crs().isValid()) - self.assertEqual(vl.crs().authid(), 'EPSG:3111') + self.assertEqual(vl.crs().authid(), "EPSG:3111") - vl = QgsVectorLayer('None?field=pk:integer', 'test', 'memory') + vl = QgsVectorLayer("None?field=pk:integer", "test", "memory") self.assertFalse(vl.isSpatial()) self.assertFalse(vl.crs().isValid()) # even if provider has a crs - we don't respect it for non-spatial layers! - vl = QgsVectorLayer('None?crs=epsg:3111&field=pk:integer', 'test', 'memory') + vl = QgsVectorLayer("None?crs=epsg:3111&field=pk:integer", "test", "memory") self.assertFalse(vl.isSpatial()) self.assertFalse(vl.crs().isValid()) @@ -542,8 +603,8 @@ def test_wgs84Extent(self): # We use this particular shapefile because we need a layer with an # epsg != 4326 - p = os.path.join(unitTestDataPath(), 'bug5598.shp') - vl0 = QgsVectorLayer(p, 'test', 'ogr') + p = os.path.join(unitTestDataPath(), "bug5598.shp") + vl0 = QgsVectorLayer(p, "test", "ogr") extent = vl0.extent() wgs84_extent = vl0.wgs84Extent() @@ -567,9 +628,19 @@ def test_wgs84Extent(self): f = QgsFeature() f.setAttributes([0, "", "", 0.0, 0.0, 0.0, 0.0]) - f.setGeometry(QgsGeometry.fromPolygonXY([[QgsPointXY(2484588, 2425732), QgsPointXY(2482767, 2398853), - QgsPointXY(2520109, 2397715), QgsPointXY(2520792, 2425494), - QgsPointXY(2484588, 2425732)]])) + f.setGeometry( + QgsGeometry.fromPolygonXY( + [ + [ + QgsPointXY(2484588, 2425732), + QgsPointXY(2482767, 2398853), + QgsPointXY(2520109, 2397715), + QgsPointXY(2520792, 2425494), + QgsPointXY(2484588, 2425732), + ] + ] + ) + ) vl1.addFeature(f) vl1.updateExtents() @@ -595,9 +666,19 @@ def test_wgs84Extent(self): f = QgsFeature() f.setAttributes([0, "", "", 0.0, 0.0, 0.0, 0.0]) - f.setGeometry(QgsGeometry.fromPolygonXY([[QgsPointXY(2484588, 2425732), QgsPointXY(2482767, 2398853), - QgsPointXY(2520109, 2397715), QgsPointXY(2520792, 2425494), - QgsPointXY(2484588, 2425732)]])) + f.setGeometry( + QgsGeometry.fromPolygonXY( + [ + [ + QgsPointXY(2484588, 2425732), + QgsPointXY(2482767, 2398853), + QgsPointXY(2520109, 2397715), + QgsPointXY(2520792, 2425494), + QgsPointXY(2484588, 2425732), + ] + ] + ) + ) vl2.addFeature(f) vl2.updateExtents() @@ -1023,8 +1104,10 @@ def test_DeleteJoinedFeature(self): joinLayer.startEditing() joinLayer2.startEditing() - filter = QgsExpression.createFieldEqualityExpression('fldint', '123') - feature = next(layer.getFeatures(QgsFeatureRequest().setFilterExpression(filter))) + filter = QgsExpression.createFieldEqualityExpression("fldint", "123") + feature = next( + layer.getFeatures(QgsFeatureRequest().setFilterExpression(filter)) + ) layer.deleteFeature(feature.id()) # check number of features @@ -1141,10 +1224,13 @@ def checkBefore(): checkAfter() def test_ChangeAttributeValuesWithContext(self): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) - layer.setDefaultValueDefinition(0, QgsDefaultValue("geom_to_wkt(@current_parent_geometry)", True)) + layer.setDefaultValueDefinition( + 0, QgsDefaultValue("geom_to_wkt(@current_parent_geometry)", True) + ) f = QgsFeature() f.setAttributes(["test", 123]) @@ -1245,7 +1331,9 @@ def checkBefore(): self.assertEqual(f.geometry().asPoint(), QgsPointXY(100, 200)) # try to change geometry without editing mode - self.assertFalse(layer.changeGeometry(fid, QgsGeometry.fromPointXY(QgsPointXY(300, 400)))) + self.assertFalse( + layer.changeGeometry(fid, QgsGeometry.fromPointXY(QgsPointXY(300, 400))) + ) repaint_spy = QSignalSpy(layer.repaintRequested) @@ -1254,7 +1342,9 @@ def checkBefore(): # change geometry layer.startEditing() layer.beginEditCommand("ChangeGeometry") - self.assertTrue(layer.changeGeometry(fid, QgsGeometry.fromPointXY(QgsPointXY(300, 400)))) + self.assertTrue( + layer.changeGeometry(fid, QgsGeometry.fromPointXY(QgsPointXY(300, 400))) + ) layer.endEditCommand() self.assertEqual(len(repaint_spy), 1) @@ -1297,7 +1387,9 @@ def checkBefore(): layer.startEditing() layer.beginEditCommand("ChangeGeometry + ChangeAttribute") self.assertTrue(layer.changeAttributeValue(fid, 0, "changed")) - self.assertTrue(layer.changeGeometry(fid, QgsGeometry.fromPointXY(QgsPointXY(300, 400)))) + self.assertTrue( + layer.changeGeometry(fid, QgsGeometry.fromPointXY(QgsPointXY(300, 400))) + ) layer.endEditCommand() checkAfter() @@ -1338,7 +1430,9 @@ def checkBefore(): layer.startEditing() layer.beginEditCommand("AddFeature+ChangeGeometry") self.assertTrue(layer.addFeature(newF)) - self.assertTrue(layer.changeGeometry(newF.id(), QgsGeometry.fromPointXY(QgsPointXY(2, 2)))) + self.assertTrue( + layer.changeGeometry(newF.id(), QgsGeometry.fromPointXY(QgsPointXY(2, 2))) + ) layer.endEditCommand() checkAfter() @@ -1375,14 +1469,14 @@ def testUpdateFeature(self): # change geometry and attributes f = features[0] - f.setAttributes(['new', 321]) + f.setAttributes(["new", 321]) f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(-200, -200))) self.assertTrue(layer.updateFeature(f)) self.assertGreaterEqual(len(repaint_spy), 1) prev_spy_count = len(repaint_spy) new_feature = next(layer.getFeatures(QgsFeatureRequest(f.id()))) - self.assertEqual(new_feature.attributes(), ['new', 321]) + self.assertEqual(new_feature.attributes(), ["new", 321]) self.assertEqual(new_feature.geometry().asPoint(), QgsPointXY(-200, -200)) # add feature with no geometry @@ -1400,7 +1494,7 @@ def testUpdateFeature(self): self.assertGreaterEqual(len(repaint_spy), prev_spy_count) prev_spy_count = len(repaint_spy) new_feature = next(layer.getFeatures(QgsFeatureRequest(f.id()))) - self.assertEqual(new_feature.attributes(), ['test6', 555]) + self.assertEqual(new_feature.attributes(), ["test6", 555]) self.assertTrue(new_feature.hasGeometry()) self.assertEqual(new_feature.geometry().asPoint(), QgsPointXY(-350, -250)) @@ -1410,7 +1504,7 @@ def testUpdateFeature(self): self.assertTrue(layer.updateFeature(f)) self.assertGreaterEqual(len(repaint_spy), prev_spy_count) new_feature = next(layer.getFeatures(QgsFeatureRequest(f.id()))) - self.assertEqual(new_feature.attributes(), ['test2', 457]) + self.assertEqual(new_feature.attributes(), ["test2", 457]) self.assertFalse(new_feature.hasGeometry()) # ADD ATTRIBUTE @@ -1546,9 +1640,9 @@ def test_AddAttributeAfterDeleteAttribute(self): def test_DeleteAttribute(self): layer = createLayerWithOnePoint() layer.dataProvider().addAttributes( - [QgsField("flddouble", QVariant.Double, "double")]) - layer.dataProvider().changeAttributeValues( - {1: {2: 5.5}}) + [QgsField("flddouble", QVariant.Double, "double")] + ) + layer.dataProvider().changeAttributeValues({1: {2: 5.5}}) # without editing mode self.assertFalse(layer.deleteAttribute(0)) @@ -1770,7 +1864,7 @@ def test_RenameAttribute(self): layer = createLayerWithOnePoint() # without editing mode - self.assertFalse(layer.renameAttribute(0, 'renamed')) + self.assertFalse(layer.renameAttribute(0, "renamed")) def checkFieldNames(names): flds = layer.fields() @@ -1784,45 +1878,45 @@ def checkFieldNames(names): layer.startEditing() - checkFieldNames(['fldtxt', 'fldint']) + checkFieldNames(["fldtxt", "fldint"]) - self.assertFalse(layer.renameAttribute(-1, 'fldtxt2')) - self.assertFalse(layer.renameAttribute(10, 'fldtxt2')) - self.assertFalse(layer.renameAttribute(0, 'fldint')) # duplicate name + self.assertFalse(layer.renameAttribute(-1, "fldtxt2")) + self.assertFalse(layer.renameAttribute(10, "fldtxt2")) + self.assertFalse(layer.renameAttribute(0, "fldint")) # duplicate name - self.assertTrue(layer.renameAttribute(0, 'fldtxt2')) - checkFieldNames(['fldtxt2', 'fldint']) + self.assertTrue(layer.renameAttribute(0, "fldtxt2")) + checkFieldNames(["fldtxt2", "fldint"]) layer.undoStack().undo() - checkFieldNames(['fldtxt', 'fldint']) + checkFieldNames(["fldtxt", "fldint"]) layer.undoStack().redo() - checkFieldNames(['fldtxt2', 'fldint']) + checkFieldNames(["fldtxt2", "fldint"]) # change two fields - self.assertTrue(layer.renameAttribute(1, 'fldint2')) - checkFieldNames(['fldtxt2', 'fldint2']) + self.assertTrue(layer.renameAttribute(1, "fldint2")) + checkFieldNames(["fldtxt2", "fldint2"]) layer.undoStack().undo() - checkFieldNames(['fldtxt2', 'fldint']) + checkFieldNames(["fldtxt2", "fldint"]) layer.undoStack().undo() - checkFieldNames(['fldtxt', 'fldint']) + checkFieldNames(["fldtxt", "fldint"]) layer.undoStack().redo() - checkFieldNames(['fldtxt2', 'fldint']) + checkFieldNames(["fldtxt2", "fldint"]) layer.undoStack().redo() - checkFieldNames(['fldtxt2', 'fldint2']) + checkFieldNames(["fldtxt2", "fldint2"]) # two renames - self.assertTrue(layer.renameAttribute(0, 'fldtxt3')) - checkFieldNames(['fldtxt3', 'fldint2']) - self.assertTrue(layer.renameAttribute(0, 'fldtxt4')) - checkFieldNames(['fldtxt4', 'fldint2']) + self.assertTrue(layer.renameAttribute(0, "fldtxt3")) + checkFieldNames(["fldtxt3", "fldint2"]) + self.assertTrue(layer.renameAttribute(0, "fldtxt4")) + checkFieldNames(["fldtxt4", "fldint2"]) layer.undoStack().undo() - checkFieldNames(['fldtxt3', 'fldint2']) + checkFieldNames(["fldtxt3", "fldint2"]) layer.undoStack().undo() - checkFieldNames(['fldtxt2', 'fldint2']) + checkFieldNames(["fldtxt2", "fldint2"]) layer.undoStack().redo() - checkFieldNames(['fldtxt3', 'fldint2']) + checkFieldNames(["fldtxt3", "fldint2"]) layer.undoStack().redo() - checkFieldNames(['fldtxt4', 'fldint2']) + checkFieldNames(["fldtxt4", "fldint2"]) def test_RenameAttributeAfterAdd(self): layer = createLayerWithOnePoint() @@ -1839,52 +1933,55 @@ def checkFieldNames(names): layer.startEditing() - checkFieldNames(['fldtxt', 'fldint']) - self.assertTrue(layer.renameAttribute(1, 'fldint2')) - checkFieldNames(['fldtxt', 'fldint2']) + checkFieldNames(["fldtxt", "fldint"]) + self.assertTrue(layer.renameAttribute(1, "fldint2")) + checkFieldNames(["fldtxt", "fldint2"]) # add an attribute - self.assertTrue(layer.addAttribute(QgsField("flddouble", QVariant.Double, "double"))) - checkFieldNames(['fldtxt', 'fldint2', 'flddouble']) + self.assertTrue( + layer.addAttribute(QgsField("flddouble", QVariant.Double, "double")) + ) + checkFieldNames(["fldtxt", "fldint2", "flddouble"]) # rename it - self.assertTrue(layer.renameAttribute(2, 'flddouble2')) - checkFieldNames(['fldtxt', 'fldint2', 'flddouble2']) + self.assertTrue(layer.renameAttribute(2, "flddouble2")) + checkFieldNames(["fldtxt", "fldint2", "flddouble2"]) self.assertTrue(layer.addAttribute(QgsField("flddate", QVariant.Date, "date"))) - checkFieldNames(['fldtxt', 'fldint2', 'flddouble2', 'flddate']) - self.assertTrue(layer.renameAttribute(2, 'flddouble3')) - checkFieldNames(['fldtxt', 'fldint2', 'flddouble3', 'flddate']) - self.assertTrue(layer.renameAttribute(3, 'flddate2')) - checkFieldNames(['fldtxt', 'fldint2', 'flddouble3', 'flddate2']) + checkFieldNames(["fldtxt", "fldint2", "flddouble2", "flddate"]) + self.assertTrue(layer.renameAttribute(2, "flddouble3")) + checkFieldNames(["fldtxt", "fldint2", "flddouble3", "flddate"]) + self.assertTrue(layer.renameAttribute(3, "flddate2")) + checkFieldNames(["fldtxt", "fldint2", "flddouble3", "flddate2"]) layer.undoStack().undo() - checkFieldNames(['fldtxt', 'fldint2', 'flddouble3', 'flddate']) + checkFieldNames(["fldtxt", "fldint2", "flddouble3", "flddate"]) layer.undoStack().undo() - checkFieldNames(['fldtxt', 'fldint2', 'flddouble2', 'flddate']) + checkFieldNames(["fldtxt", "fldint2", "flddouble2", "flddate"]) layer.undoStack().undo() - checkFieldNames(['fldtxt', 'fldint2', 'flddouble2']) + checkFieldNames(["fldtxt", "fldint2", "flddouble2"]) layer.undoStack().undo() - checkFieldNames(['fldtxt', 'fldint2', 'flddouble']) + checkFieldNames(["fldtxt", "fldint2", "flddouble"]) layer.undoStack().undo() - checkFieldNames(['fldtxt', 'fldint2']) + checkFieldNames(["fldtxt", "fldint2"]) layer.undoStack().undo() - checkFieldNames(['fldtxt', 'fldint']) + checkFieldNames(["fldtxt", "fldint"]) layer.undoStack().redo() - checkFieldNames(['fldtxt', 'fldint2']) + checkFieldNames(["fldtxt", "fldint2"]) layer.undoStack().redo() - checkFieldNames(['fldtxt', 'fldint2', 'flddouble']) + checkFieldNames(["fldtxt", "fldint2", "flddouble"]) layer.undoStack().redo() - checkFieldNames(['fldtxt', 'fldint2', 'flddouble2']) + checkFieldNames(["fldtxt", "fldint2", "flddouble2"]) layer.undoStack().redo() - checkFieldNames(['fldtxt', 'fldint2', 'flddouble2', 'flddate']) + checkFieldNames(["fldtxt", "fldint2", "flddouble2", "flddate"]) layer.undoStack().redo() - checkFieldNames(['fldtxt', 'fldint2', 'flddouble3', 'flddate']) + checkFieldNames(["fldtxt", "fldint2", "flddouble3", "flddate"]) layer.undoStack().redo() - checkFieldNames(['fldtxt', 'fldint2', 'flddouble3', 'flddate2']) + checkFieldNames(["fldtxt", "fldint2", "flddouble3", "flddate2"]) def test_RenameAttributeAndDelete(self): layer = createLayerWithOnePoint() layer.dataProvider().addAttributes( - [QgsField("flddouble", QVariant.Double, "double")]) + [QgsField("flddouble", QVariant.Double, "double")] + ) layer.updateFields() def checkFieldNames(names): @@ -1899,40 +1996,40 @@ def checkFieldNames(names): layer.startEditing() - checkFieldNames(['fldtxt', 'fldint', 'flddouble']) - self.assertTrue(layer.renameAttribute(0, 'fldtxt2')) - checkFieldNames(['fldtxt2', 'fldint', 'flddouble']) - self.assertTrue(layer.renameAttribute(2, 'flddouble2')) - checkFieldNames(['fldtxt2', 'fldint', 'flddouble2']) + checkFieldNames(["fldtxt", "fldint", "flddouble"]) + self.assertTrue(layer.renameAttribute(0, "fldtxt2")) + checkFieldNames(["fldtxt2", "fldint", "flddouble"]) + self.assertTrue(layer.renameAttribute(2, "flddouble2")) + checkFieldNames(["fldtxt2", "fldint", "flddouble2"]) # delete an attribute self.assertTrue(layer.deleteAttribute(0)) - checkFieldNames(['fldint', 'flddouble2']) + checkFieldNames(["fldint", "flddouble2"]) # rename remaining - self.assertTrue(layer.renameAttribute(0, 'fldint2')) - checkFieldNames(['fldint2', 'flddouble2']) - self.assertTrue(layer.renameAttribute(1, 'flddouble3')) - checkFieldNames(['fldint2', 'flddouble3']) + self.assertTrue(layer.renameAttribute(0, "fldint2")) + checkFieldNames(["fldint2", "flddouble2"]) + self.assertTrue(layer.renameAttribute(1, "flddouble3")) + checkFieldNames(["fldint2", "flddouble3"]) # delete an attribute self.assertTrue(layer.deleteAttribute(0)) - checkFieldNames(['flddouble3']) - self.assertTrue(layer.renameAttribute(0, 'flddouble4')) - checkFieldNames(['flddouble4']) + checkFieldNames(["flddouble3"]) + self.assertTrue(layer.renameAttribute(0, "flddouble4")) + checkFieldNames(["flddouble4"]) layer.undoStack().undo() - checkFieldNames(['flddouble3']) + checkFieldNames(["flddouble3"]) layer.undoStack().undo() - checkFieldNames(['fldint2', 'flddouble3']) + checkFieldNames(["fldint2", "flddouble3"]) layer.undoStack().undo() - checkFieldNames(['fldint2', 'flddouble2']) + checkFieldNames(["fldint2", "flddouble2"]) layer.undoStack().undo() - checkFieldNames(['fldint', 'flddouble2']) + checkFieldNames(["fldint", "flddouble2"]) layer.undoStack().undo() - checkFieldNames(['fldtxt2', 'fldint', 'flddouble2']) + checkFieldNames(["fldtxt2", "fldint", "flddouble2"]) layer.undoStack().undo() - checkFieldNames(['fldtxt2', 'fldint', 'flddouble']) + checkFieldNames(["fldtxt2", "fldint", "flddouble"]) layer.undoStack().undo() - checkFieldNames(['fldtxt', 'fldint', 'flddouble']) + checkFieldNames(["fldtxt", "fldint", "flddouble"]) # layer.undoStack().redo() # checkFieldNames(['fldtxt2', 'fldint']) @@ -1941,13 +2038,15 @@ def checkFieldNames(names): def test_RenameExpressionField(self): layer = createLayerWithOnePoint() - exp_field_idx = layer.addExpressionField('1+1', QgsField('math_is_hard', QVariant.Int)) + exp_field_idx = layer.addExpressionField( + "1+1", QgsField("math_is_hard", QVariant.Int) + ) # rename and check - self.assertTrue(layer.renameAttribute(exp_field_idx, 'renamed')) - self.assertEqual(layer.fields()[exp_field_idx].name(), 'renamed') + self.assertTrue(layer.renameAttribute(exp_field_idx, "renamed")) + self.assertEqual(layer.fields()[exp_field_idx].name(), "renamed") f = next(layer.getFeatures()) - self.assertEqual(f.fields()[exp_field_idx].name(), 'renamed') + self.assertEqual(f.fields()[exp_field_idx].name(), "renamed") def test_fields(self): layer = createLayerWithOnePoint() @@ -1976,8 +2075,8 @@ def test_getFeatures(self): # getFeature(fid) feat = layer2.getFeature(4) self.assertTrue(feat.isValid()) - self.assertEqual(feat['fldtxt'], 'test3') - self.assertEqual(feat['fldint'], -1) + self.assertEqual(feat["fldtxt"], "test3") + self.assertEqual(feat["fldint"], -1) feat = layer2.getFeature(10) self.assertFalse(feat.isValid()) @@ -2051,7 +2150,7 @@ def test_join(self): self.assertEqual(f2[3], 321) def test_JoinStats(self): - """ test calculating min/max/uniqueValues on joined field """ + """test calculating min/max/uniqueValues on joined field""" joinLayer = createJoinLayer() layer = createLayerWithTwoPoints() QgsProject.instance().addMapLayers([joinLayer, layer]) @@ -2076,9 +2175,19 @@ def test_JoinStats(self): self.assertEqual(layer.minimumAndMaximumValue(3), (111, 321)) # dates (maximumValue also tests we properly handle null values by skipping those) - self.assertEqual(layer.minimumValue(4), QDateTime(QDate(2010, 1, 1), QTime(0, 0, 0))) - self.assertEqual(layer.maximumValue(4), QDateTime(QDate(2010, 1, 1), QTime(0, 0, 0))) - self.assertEqual(layer.minimumAndMaximumValue(4), (QDateTime(QDate(2010, 1, 1), QTime(0, 0, 0)), QDateTime(QDate(2010, 1, 1), QTime(0, 0, 0)))) + self.assertEqual( + layer.minimumValue(4), QDateTime(QDate(2010, 1, 1), QTime(0, 0, 0)) + ) + self.assertEqual( + layer.maximumValue(4), QDateTime(QDate(2010, 1, 1), QTime(0, 0, 0)) + ) + self.assertEqual( + layer.minimumAndMaximumValue(4), + ( + QDateTime(QDate(2010, 1, 1), QTime(0, 0, 0)), + QDateTime(QDate(2010, 1, 1), QTime(0, 0, 0)), + ), + ) self.assertEqual(set(layer.uniqueValues(3)), {111, 321}) @@ -2093,19 +2202,23 @@ def test_valid_join_when_opening_project(self): tmp_dir = QTemporaryDir() tmp_path = tmp_dir.path() - myPath = os.path.join(unitTestDataPath(), 'joins.qgs') + myPath = os.path.join(unitTestDataPath(), "joins.qgs") shutil.copy2(myPath, tmp_path) - for file in glob.glob(os.path.join(unitTestDataPath(), 'polys_overlapping_with_id.*')): + for file in glob.glob( + os.path.join(unitTestDataPath(), "polys_overlapping_with_id.*") + ): shutil.copy(file, tmp_path) - for file in glob.glob(os.path.join(unitTestDataPath(), 'polys_with_id.*')): + for file in glob.glob(os.path.join(unitTestDataPath(), "polys_with_id.*")): shutil.copy(file, tmp_path) - rc = QgsProject.instance().read(os.path.join(tmp_path, 'joins.qgs')) + rc = QgsProject.instance().read(os.path.join(tmp_path, "joins.qgs")) layer = QgsProject.instance().mapLayersByName("polys_with_id")[0] - join_layer = QgsProject.instance().mapLayersByName("polys_overlapping_with_id")[0] + join_layer = QgsProject.instance().mapLayersByName("polys_overlapping_with_id")[ + 0 + ] # create an attribute table for the main_layer and the # joined layer @@ -2124,7 +2237,10 @@ def test_valid_join_when_opening_project(self): join_model_index = join_am.idToIndex(fid) join_feature_model = join_am.feature(join_model_index) - self.assertEqual(feature_model.attribute(attr_idx), join_feature_model.attribute(join_attr_idx)) + self.assertEqual( + feature_model.attribute(attr_idx), + join_feature_model.attribute(join_attr_idx), + ) # change attribute value for a feature of the joined layer join_layer.startEditing() @@ -2153,7 +2269,7 @@ def test_valid_join_when_opening_project(self): join_layer.commitChanges() def testUniqueValue(self): - """ test retrieving unique values """ + """test retrieving unique values""" layer = createLayerWithFivePoints() # test layer with just provider features @@ -2182,10 +2298,12 @@ def testUniqueValue(self): f1_id = next(layer.getFeatures()).id() self.assertTrue(layer.changeAttributeValue(f1_id, 1, 481523)) # note - this isn't 100% accurate, since 123 no longer exists - but it avoids looping through all features - self.assertEqual(set(layer.uniqueValues(1)), {123, 457, 888, -1, 0, 999, 9999, 481523}) + self.assertEqual( + set(layer.uniqueValues(1)), {123, 457, 888, -1, 0, 999, 9999, 481523} + ) def testUniqueStringsMatching(self): - """ test retrieving unique strings matching subset """ + """test retrieving unique strings matching subset""" layer = QgsVectorLayer("Point?field=fldtxt:string", "addfeat", "memory") pr = layer.dataProvider() f = QgsFeature() @@ -2202,7 +2320,7 @@ def testUniqueStringsMatching(self): assert layer.featureCount() == 5 # test layer with just provider features - self.assertEqual(set(layer.uniqueStringsMatching(0, 'N')), {'orange', 'BanaNa'}) + self.assertEqual(set(layer.uniqueStringsMatching(0, "N")), {"orange", "BanaNa"}) # add feature with new value layer.startEditing() @@ -2211,26 +2329,37 @@ def testUniqueStringsMatching(self): self.assertTrue(layer.addFeature(f1)) # should be included in unique values - self.assertEqual(set(layer.uniqueStringsMatching(0, 'N')), {'orange', 'BanaNa', 'waterMelon'}) + self.assertEqual( + set(layer.uniqueStringsMatching(0, "N")), {"orange", "BanaNa", "waterMelon"} + ) # add it again, should be no change f2 = QgsFeature() f2.setAttributes(["waterMelon"]) self.assertTrue(layer.addFeature(f1)) - self.assertEqual(set(layer.uniqueStringsMatching(0, 'N')), {'orange', 'BanaNa', 'waterMelon'}) - self.assertEqual(set(layer.uniqueStringsMatching(0, 'aN')), {'orange', 'BanaNa'}) + self.assertEqual( + set(layer.uniqueStringsMatching(0, "N")), {"orange", "BanaNa", "waterMelon"} + ) + self.assertEqual( + set(layer.uniqueStringsMatching(0, "aN")), {"orange", "BanaNa"} + ) # add another feature f3 = QgsFeature() f3.setAttributes(["pineapple"]) self.assertTrue(layer.addFeature(f3)) - self.assertEqual(set(layer.uniqueStringsMatching(0, 'n')), {'orange', 'BanaNa', 'waterMelon', 'pineapple'}) + self.assertEqual( + set(layer.uniqueStringsMatching(0, "n")), + {"orange", "BanaNa", "waterMelon", "pineapple"}, + ) # change an attribute value to a new unique value f = QgsFeature() f1_id = next(layer.getFeatures()).id() - self.assertTrue(layer.changeAttributeValue(f1_id, 0, 'coconut')) + self.assertTrue(layer.changeAttributeValue(f1_id, 0, "coconut")) # note - this isn't 100% accurate, since orange no longer exists - but it avoids looping through all features - self.assertEqual(set(layer.uniqueStringsMatching(0, 'n')), - {'orange', 'BanaNa', 'waterMelon', 'pineapple', 'coconut'}) + self.assertEqual( + set(layer.uniqueStringsMatching(0, "n")), + {"orange", "BanaNa", "waterMelon", "pineapple", "coconut"}, + ) def test_subsetString(self): subset_string_changed = False @@ -2239,15 +2368,15 @@ def onSubsetStringChanged(): nonlocal subset_string_changed subset_string_changed = True - path = os.path.join(unitTestDataPath(), 'lines.shp') - layer = QgsVectorLayer(path, 'test', 'ogr') + path = os.path.join(unitTestDataPath(), "lines.shp") + layer = QgsVectorLayer(path, "test", "ogr") layer.subsetStringChanged.connect(onSubsetStringChanged) layer.setSubsetString("\"Name\" = 'Highway'") self.assertTrue(subset_string_changed) self.assertEqual(layer.featureCount(), 2) def testMinValue(self): - """ test retrieving minimum values """ + """test retrieving minimum values""" layer = createLayerWithFivePoints() # test layer with just provider features @@ -2278,7 +2407,7 @@ def testMinValue(self): self.assertEqual(layer.minimumValue(1), -1001) def testMaxValue(self): - """ test retrieving maximum values """ + """test retrieving maximum values""" layer = createLayerWithFivePoints() # test layer with just provider features @@ -2309,7 +2438,7 @@ def testMaxValue(self): self.assertEqual(layer.maximumValue(1), 1001) def testMinAndMaxValue(self): - """ test retrieving minimum and maximum values at once""" + """test retrieving minimum and maximum values at once""" layer = createLayerWithFivePoints() # test layer with just provider features @@ -2372,7 +2501,7 @@ def testMinMaxInVirtualField(self): layer = QgsVectorLayer("Point?field=fldstr:string", "layer", "memory") pr = layer.dataProvider() - int_values = ['2010-01-01', None, '2020-01-01'] + int_values = ["2010-01-01", None, "2020-01-01"] features = [] for i in int_values: f = QgsFeature() @@ -2381,12 +2510,14 @@ def testMinMaxInVirtualField(self): features.append(f) assert pr.addFeatures(features) - field = QgsField('virtual', QVariant.Date) + field = QgsField("virtual", QVariant.Date) layer.addExpressionField('to_date("fldstr")', field) self.assertEqual(len(layer.getFeature(1).attributes()), 2) self.assertEqual(layer.minimumValue(1), QDate(2010, 1, 1)) self.assertEqual(layer.maximumValue(1), QDate(2020, 1, 1)) - self.assertEqual(layer.minimumAndMaximumValue(1), (QDate(2010, 1, 1), QDate(2020, 1, 1))) + self.assertEqual( + layer.minimumAndMaximumValue(1), (QDate(2010, 1, 1), QDate(2020, 1, 1)) + ) def test_InvalidOperations(self): layer = createLayerWithOnePoint() @@ -2407,8 +2538,9 @@ def test_InvalidOperations(self): # CHANGE GEOMETRY - self.assertFalse(layer.changeGeometry( - -333, QgsGeometry.fromPointXY(QgsPointXY(1, 1)))) + self.assertFalse( + layer.changeGeometry(-333, QgsGeometry.fromPointXY(QgsPointXY(1, 1))) + ) # CHANGE VALUE @@ -2433,8 +2565,12 @@ def test_setBlendMode(self): layer.blendModeChanged.connect(self.onBlendModeChanged) layer.setBlendMode(QPainter.CompositionMode.CompositionMode_Screen) - self.assertEqual(self.blendModeTest, QPainter.CompositionMode.CompositionMode_Screen) - self.assertEqual(layer.blendMode(), QPainter.CompositionMode.CompositionMode_Screen) + self.assertEqual( + self.blendModeTest, QPainter.CompositionMode.CompositionMode_Screen + ) + self.assertEqual( + layer.blendMode(), QPainter.CompositionMode.CompositionMode_Screen + ) def test_setFeatureBlendMode(self): layer = createLayerWithOnePoint() @@ -2443,15 +2579,19 @@ def test_setFeatureBlendMode(self): layer.featureBlendModeChanged.connect(self.onBlendModeChanged) layer.setFeatureBlendMode(QPainter.CompositionMode.CompositionMode_Screen) - self.assertEqual(self.blendModeTest, QPainter.CompositionMode.CompositionMode_Screen) - self.assertEqual(layer.featureBlendMode(), QPainter.CompositionMode.CompositionMode_Screen) + self.assertEqual( + self.blendModeTest, QPainter.CompositionMode.CompositionMode_Screen + ) + self.assertEqual( + layer.featureBlendMode(), QPainter.CompositionMode.CompositionMode_Screen + ) def test_ExpressionField(self): layer = createLayerWithOnePoint() cnt = layer.fields().count() - idx = layer.addExpressionField('5', QgsField('test', QVariant.LongLong)) + idx = layer.addExpressionField("5", QgsField("test", QVariant.LongLong)) fet = next(layer.getFeatures()) self.assertEqual(fet[idx], 5) @@ -2463,7 +2603,7 @@ def test_ExpressionField(self): fet = next(layer.getFeatures(QgsFeatureRequest().setFilterFid(1))) self.assertEqual(fet.fields(), layer.fields()) - layer.updateExpressionField(idx, '9') + layer.updateExpressionField(idx, "9") self.assertEqual(next(layer.getFeatures())[idx], 9) @@ -2472,17 +2612,25 @@ def test_ExpressionField(self): self.assertEqual(layer.fields().count(), cnt) # expression field which references itself - idx = layer.addExpressionField('sum(test2)', QgsField('test2', QVariant.LongLong)) + idx = layer.addExpressionField( + "sum(test2)", QgsField("test2", QVariant.LongLong) + ) fet = next(layer.getFeatures()) - self.assertEqual(fet['test2'], 0) + self.assertEqual(fet["test2"], 0) def test_ExpressionFieldEllipsoidLengthCalculation(self): # create a temporary layer - temp_layer = QgsVectorLayer("LineString?crs=epsg:3111&field=pk:int", "vl", "memory") + temp_layer = QgsVectorLayer( + "LineString?crs=epsg:3111&field=pk:int", "vl", "memory" + ) self.assertTrue(temp_layer.isValid()) f1 = QgsFeature(temp_layer.dataProvider().fields(), 1) f1.setAttribute("pk", 1) - f1.setGeometry(QgsGeometry.fromPolylineXY([QgsPointXY(2484588, 2425722), QgsPointXY(2482767, 2398853)])) + f1.setGeometry( + QgsGeometry.fromPolylineXY( + [QgsPointXY(2484588, 2425722), QgsPointXY(2482767, 2398853)] + ) + ) temp_layer.dataProvider().addFeatures([f1]) # set project CRS and ellipsoid @@ -2491,28 +2639,42 @@ def test_ExpressionFieldEllipsoidLengthCalculation(self): QgsProject.instance().setEllipsoid("WGS84") QgsProject.instance().setDistanceUnits(QgsUnitTypes.DistanceUnit.DistanceMeters) - idx = temp_layer.addExpressionField('$length', QgsField('length', QVariant.Double)) # NOQA + idx = temp_layer.addExpressionField( + "$length", QgsField("length", QVariant.Double) + ) # NOQA # check value f = next(temp_layer.getFeatures()) expected = 26932.156 - self.assertAlmostEqual(f['length'], expected, 3) + self.assertAlmostEqual(f["length"], expected, 3) # change project length unit, check calculation respects unit QgsProject.instance().setDistanceUnits(QgsUnitTypes.DistanceUnit.DistanceFeet) f = next(temp_layer.getFeatures()) expected = 88360.0918635 - self.assertAlmostEqual(f['length'], expected, 3) + self.assertAlmostEqual(f["length"], expected, 3) def test_ExpressionFieldEllipsoidAreaCalculation(self): # create a temporary layer - temp_layer = QgsVectorLayer("Polygon?crs=epsg:3111&field=pk:int", "vl", "memory") + temp_layer = QgsVectorLayer( + "Polygon?crs=epsg:3111&field=pk:int", "vl", "memory" + ) self.assertTrue(temp_layer.isValid()) f1 = QgsFeature(temp_layer.dataProvider().fields(), 1) f1.setAttribute("pk", 1) - f1.setGeometry(QgsGeometry.fromPolygonXY([[QgsPointXY(2484588, 2425722), QgsPointXY(2482767, 2398853), - QgsPointXY(2520109, 2397715), QgsPointXY(2520792, 2425494), - QgsPointXY(2484588, 2425722)]])) + f1.setGeometry( + QgsGeometry.fromPolygonXY( + [ + [ + QgsPointXY(2484588, 2425722), + QgsPointXY(2482767, 2398853), + QgsPointXY(2520109, 2397715), + QgsPointXY(2520792, 2425494), + QgsPointXY(2484588, 2425722), + ] + ] + ) + ) temp_layer.dataProvider().addFeatures([f1]) # set project CRS and ellipsoid @@ -2521,35 +2683,43 @@ def test_ExpressionFieldEllipsoidAreaCalculation(self): QgsProject.instance().setEllipsoid("WGS84") QgsProject.instance().setAreaUnits(QgsUnitTypes.AreaUnit.AreaSquareMeters) - idx = temp_layer.addExpressionField('$area', QgsField('area', QVariant.Double)) # NOQA + idx = temp_layer.addExpressionField( + "$area", QgsField("area", QVariant.Double) + ) # NOQA # check value f = next(temp_layer.getFeatures()) expected = 1005755617.8191342 - self.assertAlmostEqual(f['area'], expected, delta=1.0) + self.assertAlmostEqual(f["area"], expected, delta=1.0) # change project area unit, check calculation respects unit QgsProject.instance().setAreaUnits(QgsUnitTypes.AreaUnit.AreaSquareMiles) f = next(temp_layer.getFeatures()) expected = 388.3244150061589 - self.assertAlmostEqual(f['area'], expected, 3) + self.assertAlmostEqual(f["area"], expected, 3) def test_ExpressionFilter(self): layer = createLayerWithOnePoint() - idx = layer.addExpressionField('5', QgsField('test', QVariant.LongLong)) # NOQA + idx = layer.addExpressionField("5", QgsField("test", QVariant.LongLong)) # NOQA - features = layer.getFeatures(QgsFeatureRequest().setFilterExpression('"test" = 6')) + features = layer.getFeatures( + QgsFeatureRequest().setFilterExpression('"test" = 6') + ) - assert (len(list(features)) == 0) + assert len(list(features)) == 0 - features = layer.getFeatures(QgsFeatureRequest().setFilterExpression('"test" = 5')) + features = layer.getFeatures( + QgsFeatureRequest().setFilterExpression('"test" = 5') + ) - assert (len(list(features)) == 1) + assert len(list(features)) == 1 def testSelectByIds(self): - """ Test selecting by ID""" - layer = QgsVectorLayer(os.path.join(unitTestDataPath(), 'points.shp'), 'Points', 'ogr') + """Test selecting by ID""" + layer = QgsVectorLayer( + os.path.join(unitTestDataPath(), "points.shp"), "Points", "ogr" + ) # SetSelection layer.selectByIds([1, 3, 5, 7], QgsVectorLayer.SelectBehavior.SetSelection) @@ -2565,9 +2735,13 @@ def testSelectByIds(self): self.assertEqual(set(layer.selectedFeatureIds()), {1, 2, 3, 4, 5, 6}) # IntersectSelection - layer.selectByIds([1, 3, 5, 6], QgsVectorLayer.SelectBehavior.IntersectSelection) + layer.selectByIds( + [1, 3, 5, 6], QgsVectorLayer.SelectBehavior.IntersectSelection + ) self.assertEqual(set(layer.selectedFeatureIds()), {1, 3, 5, 6}) - layer.selectByIds([1, 2, 5, 6], QgsVectorLayer.SelectBehavior.IntersectSelection) + layer.selectByIds( + [1, 2, 5, 6], QgsVectorLayer.SelectBehavior.IntersectSelection + ) self.assertEqual(set(layer.selectedFeatureIds()), {1, 5, 6}) # RemoveFromSelection @@ -2577,87 +2751,146 @@ def testSelectByIds(self): self.assertEqual(set(layer.selectedFeatureIds()), set()) def testSelectByExpression(self): - """ Test selecting by expression """ - layer = QgsVectorLayer(os.path.join(unitTestDataPath(), 'points.shp'), 'Points', 'ogr') + """Test selecting by expression""" + layer = QgsVectorLayer( + os.path.join(unitTestDataPath(), "points.shp"), "Points", "ogr" + ) # SetSelection - layer.selectByExpression('"Class"=\'B52\' and "Heading" > 10 and "Heading" <70', QgsVectorLayer.SelectBehavior.SetSelection) + layer.selectByExpression( + '"Class"=\'B52\' and "Heading" > 10 and "Heading" <70', + QgsVectorLayer.SelectBehavior.SetSelection, + ) self.assertEqual(set(layer.selectedFeatureIds()), {10, 11}) # check that existing selection is cleared - layer.selectByExpression('"Class"=\'Biplane\'', QgsVectorLayer.SelectBehavior.SetSelection) + layer.selectByExpression( + "\"Class\"='Biplane'", QgsVectorLayer.SelectBehavior.SetSelection + ) self.assertEqual(set(layer.selectedFeatureIds()), {1, 5, 6, 7, 8}) # SetSelection no matching - layer.selectByExpression('"Class"=\'A380\'', QgsVectorLayer.SelectBehavior.SetSelection) + layer.selectByExpression( + "\"Class\"='A380'", QgsVectorLayer.SelectBehavior.SetSelection + ) self.assertEqual(set(layer.selectedFeatureIds()), set()) # AddToSelection - layer.selectByExpression('"Importance"=3', QgsVectorLayer.SelectBehavior.AddToSelection) + layer.selectByExpression( + '"Importance"=3', QgsVectorLayer.SelectBehavior.AddToSelection + ) self.assertEqual(set(layer.selectedFeatureIds()), {0, 2, 3, 4, 14}) - layer.selectByExpression('"Importance"=4', QgsVectorLayer.SelectBehavior.AddToSelection) + layer.selectByExpression( + '"Importance"=4', QgsVectorLayer.SelectBehavior.AddToSelection + ) self.assertEqual(set(layer.selectedFeatureIds()), {0, 2, 3, 4, 13, 14}) # IntersectSelection - layer.selectByExpression('"Heading"<100', QgsVectorLayer.SelectBehavior.IntersectSelection) + layer.selectByExpression( + '"Heading"<100', QgsVectorLayer.SelectBehavior.IntersectSelection + ) self.assertEqual(set(layer.selectedFeatureIds()), {0, 2, 3, 4}) - layer.selectByExpression('"Cabin Crew"=1', QgsVectorLayer.SelectBehavior.IntersectSelection) + layer.selectByExpression( + '"Cabin Crew"=1', QgsVectorLayer.SelectBehavior.IntersectSelection + ) self.assertEqual(set(layer.selectedFeatureIds()), {2, 3}) # RemoveFromSelection - layer.selectByExpression('"Heading"=85', QgsVectorLayer.SelectBehavior.RemoveFromSelection) + layer.selectByExpression( + '"Heading"=85', QgsVectorLayer.SelectBehavior.RemoveFromSelection + ) self.assertEqual(set(layer.selectedFeatureIds()), {3}) - layer.selectByExpression('"Heading"=95', QgsVectorLayer.SelectBehavior.RemoveFromSelection) + layer.selectByExpression( + '"Heading"=95', QgsVectorLayer.SelectBehavior.RemoveFromSelection + ) self.assertEqual(set(layer.selectedFeatureIds()), set()) # test using specific expression context - layer.selectByExpression('"Class"=@class and "Heading" > @low_heading and "Heading" <@high_heading', QgsVectorLayer.SelectBehavior.SetSelection) + layer.selectByExpression( + '"Class"=@class and "Heading" > @low_heading and "Heading" <@high_heading', + QgsVectorLayer.SelectBehavior.SetSelection, + ) # default built context won't have variables used in the expression self.assertFalse(layer.selectedFeatureIds()) - context = QgsExpressionContext(QgsExpressionContextUtils.globalProjectLayerScopes(layer)) - context.lastScope().setVariable('class', 'B52') - context.lastScope().setVariable('low_heading', 10) - context.lastScope().setVariable('high_heading', 70) + context = QgsExpressionContext( + QgsExpressionContextUtils.globalProjectLayerScopes(layer) + ) + context.lastScope().setVariable("class", "B52") + context.lastScope().setVariable("low_heading", 10) + context.lastScope().setVariable("high_heading", 70) # using custom context should allow the expression to be evaluated correctly - layer.selectByExpression('"Class"=@class and "Heading" > @low_heading and "Heading" <@high_heading', - QgsVectorLayer.SelectBehavior.SetSelection, context) + layer.selectByExpression( + '"Class"=@class and "Heading" > @low_heading and "Heading" <@high_heading', + QgsVectorLayer.SelectBehavior.SetSelection, + context, + ) self.assertCountEqual(layer.selectedFeatureIds(), [10, 11]) def testSelectByRect(self): - """ Test selecting by rectangle """ - layer = QgsVectorLayer(os.path.join(unitTestDataPath(), 'points.shp'), 'Points', 'ogr') + """Test selecting by rectangle""" + layer = QgsVectorLayer( + os.path.join(unitTestDataPath(), "points.shp"), "Points", "ogr" + ) # SetSelection - layer.selectByRect(QgsRectangle(-112, 30, -94, 45), QgsVectorLayer.SelectBehavior.SetSelection) + layer.selectByRect( + QgsRectangle(-112, 30, -94, 45), QgsVectorLayer.SelectBehavior.SetSelection + ) self.assertEqual(set(layer.selectedFeatureIds()), {2, 3, 7, 10, 11, 15}) # check that existing selection is cleared - layer.selectByRect(QgsRectangle(-112, 30, -94, 37), QgsVectorLayer.SelectBehavior.SetSelection) + layer.selectByRect( + QgsRectangle(-112, 30, -94, 37), QgsVectorLayer.SelectBehavior.SetSelection + ) self.assertEqual(set(layer.selectedFeatureIds()), {2, 3, 10, 15}) # SetSelection no matching - layer.selectByRect(QgsRectangle(112, 30, 115, 45), QgsVectorLayer.SelectBehavior.SetSelection) + layer.selectByRect( + QgsRectangle(112, 30, 115, 45), QgsVectorLayer.SelectBehavior.SetSelection + ) self.assertEqual(set(layer.selectedFeatureIds()), set()) # AddToSelection - layer.selectByRect(QgsRectangle(-112, 30, -94, 37), QgsVectorLayer.SelectBehavior.AddToSelection) + layer.selectByRect( + QgsRectangle(-112, 30, -94, 37), + QgsVectorLayer.SelectBehavior.AddToSelection, + ) self.assertEqual(set(layer.selectedFeatureIds()), {2, 3, 10, 15}) - layer.selectByRect(QgsRectangle(-112, 37, -94, 45), QgsVectorLayer.SelectBehavior.AddToSelection) + layer.selectByRect( + QgsRectangle(-112, 37, -94, 45), + QgsVectorLayer.SelectBehavior.AddToSelection, + ) self.assertEqual(set(layer.selectedFeatureIds()), {2, 3, 7, 10, 11, 15}) # IntersectSelection - layer.selectByRect(QgsRectangle(-112, 30, -94, 37), QgsVectorLayer.SelectBehavior.IntersectSelection) + layer.selectByRect( + QgsRectangle(-112, 30, -94, 37), + QgsVectorLayer.SelectBehavior.IntersectSelection, + ) self.assertEqual(set(layer.selectedFeatureIds()), {2, 3, 10, 15}) layer.selectByIds([2, 10, 13]) - layer.selectByRect(QgsRectangle(-112, 30, -94, 37), QgsVectorLayer.SelectBehavior.IntersectSelection) + layer.selectByRect( + QgsRectangle(-112, 30, -94, 37), + QgsVectorLayer.SelectBehavior.IntersectSelection, + ) self.assertEqual(set(layer.selectedFeatureIds()), {2, 10}) # RemoveFromSelection - layer.selectByRect(QgsRectangle(-112, 30, -94, 45), QgsVectorLayer.SelectBehavior.SetSelection) - layer.selectByRect(QgsRectangle(-112, 30, -94, 37), QgsVectorLayer.SelectBehavior.RemoveFromSelection) + layer.selectByRect( + QgsRectangle(-112, 30, -94, 45), QgsVectorLayer.SelectBehavior.SetSelection + ) + layer.selectByRect( + QgsRectangle(-112, 30, -94, 37), + QgsVectorLayer.SelectBehavior.RemoveFromSelection, + ) self.assertEqual(set(layer.selectedFeatureIds()), {7, 11}) - layer.selectByRect(QgsRectangle(-112, 30, -94, 45), QgsVectorLayer.SelectBehavior.RemoveFromSelection) + layer.selectByRect( + QgsRectangle(-112, 30, -94, 45), + QgsVectorLayer.SelectBehavior.RemoveFromSelection, + ) self.assertEqual(set(layer.selectedFeatureIds()), set()) def testReselect(self): - layer = QgsVectorLayer(os.path.join(unitTestDataPath(), 'points.shp'), 'Points', 'ogr') + layer = QgsVectorLayer( + os.path.join(unitTestDataPath(), "points.shp"), "Points", "ogr" + ) layer.selectByIds([1, 3, 5, 7], QgsVectorLayer.SelectBehavior.SetSelection) self.assertCountEqual(layer.selectedFeatureIds(), [1, 3, 5, 7]) @@ -2707,33 +2940,37 @@ def testReselect(self): def testGetFeaturesVirtualFieldsSubset(self): """Test that when a subset is requested virtual fields are returned nullified""" - vl = QgsVectorLayer(os.path.join(unitTestDataPath(), 'points.shp'), 'Points', 'ogr') - virt_field_idx = vl.addExpressionField('\'Importance: \' || Importance', QgsField('virt_1', QVariant.String)) + vl = QgsVectorLayer( + os.path.join(unitTestDataPath(), "points.shp"), "Points", "ogr" + ) + virt_field_idx = vl.addExpressionField( + "'Importance: ' || Importance", QgsField("virt_1", QVariant.String) + ) - self.assertEqual(vl.fields().lookupField('virt_1'), virt_field_idx) + self.assertEqual(vl.fields().lookupField("virt_1"), virt_field_idx) req = QgsFeatureRequest() req.setSubsetOfAttributes([0, 1]) attrs = next(vl.getFeatures(req)).attributes() - self.assertEqual(attrs, ['Jet', 90, None, None, None, None, None]) + self.assertEqual(attrs, ["Jet", 90, None, None, None, None, None]) attrs = next(vl.getFeatures()).attributes() - self.assertEqual(attrs, ['Jet', 90, 3.0, 2, 0, 2, 'Importance: 3']) + self.assertEqual(attrs, ["Jet", 90, 3.0, 2, 0, 2, "Importance: 3"]) req.setSubsetOfAttributes([0, 2]) attrs = next(vl.getFeatures(req)).attributes() - self.assertEqual(attrs, ['Jet', None, 3.0, None, None, None, None]) + self.assertEqual(attrs, ["Jet", None, 3.0, None, None, None, None]) req.setSubsetOfAttributes([0, 1, 6]) attrs = next(vl.getFeatures(req)).attributes() - self.assertEqual(attrs, ['Jet', 90, 3.0, None, None, None, 'Importance: 3']) + self.assertEqual(attrs, ["Jet", 90, 3.0, None, None, None, "Importance: 3"]) req.setSubsetOfAttributes([6]) attrs = next(vl.getFeatures(req)).attributes() - self.assertEqual(attrs, [None, None, 3.0, None, None, None, 'Importance: 3']) + self.assertEqual(attrs, [None, None, 3.0, None, None, None, "Importance: 3"]) def testAggregate(self): - """ Test aggregate calculation """ + """Test aggregate calculation""" layer = QgsVectorLayer("Point?field=fldint:integer", "layer", "memory") pr = layer.dataProvider() @@ -2746,24 +2983,25 @@ def testAggregate(self): features.append(f) assert pr.addFeatures(features) - tests = [[QgsAggregateCalculator.Aggregate.Count, 6], - [QgsAggregateCalculator.Aggregate.Sum, 24], - [QgsAggregateCalculator.Aggregate.Mean, 4], - [QgsAggregateCalculator.Aggregate.StDev, 2.0816], - [QgsAggregateCalculator.Aggregate.StDevSample, 2.2803], - [QgsAggregateCalculator.Aggregate.Min, 2], - [QgsAggregateCalculator.Aggregate.Max, 8], - [QgsAggregateCalculator.Aggregate.Range, 6], - [QgsAggregateCalculator.Aggregate.Median, 3.5], - [QgsAggregateCalculator.Aggregate.CountDistinct, 5], - [QgsAggregateCalculator.Aggregate.CountMissing, 1], - [QgsAggregateCalculator.Aggregate.FirstQuartile, 2], - [QgsAggregateCalculator.Aggregate.ThirdQuartile, 5.0], - [QgsAggregateCalculator.Aggregate.InterQuartileRange, 3.0] - ] + tests = [ + [QgsAggregateCalculator.Aggregate.Count, 6], + [QgsAggregateCalculator.Aggregate.Sum, 24], + [QgsAggregateCalculator.Aggregate.Mean, 4], + [QgsAggregateCalculator.Aggregate.StDev, 2.0816], + [QgsAggregateCalculator.Aggregate.StDevSample, 2.2803], + [QgsAggregateCalculator.Aggregate.Min, 2], + [QgsAggregateCalculator.Aggregate.Max, 8], + [QgsAggregateCalculator.Aggregate.Range, 6], + [QgsAggregateCalculator.Aggregate.Median, 3.5], + [QgsAggregateCalculator.Aggregate.CountDistinct, 5], + [QgsAggregateCalculator.Aggregate.CountMissing, 1], + [QgsAggregateCalculator.Aggregate.FirstQuartile, 2], + [QgsAggregateCalculator.Aggregate.ThirdQuartile, 5.0], + [QgsAggregateCalculator.Aggregate.InterQuartileRange, 3.0], + ] for t in tests: - val, ok = layer.aggregate(t[0], 'fldint') + val, ok = layer.aggregate(t[0], "fldint") self.assertTrue(ok) if isinstance(t[1], int): self.assertEqual(val, t[1]) @@ -2774,7 +3012,7 @@ def testAggregate(self): layer = QgsVectorLayer("Point?field=fldstring:string", "layer", "memory") pr = layer.dataProvider() - string_values = ['this', 'is', 'a', 'test', 'a', 'nice', 'test'] + string_values = ["this", "is", "a", "test", "a", "nice", "test"] features = [] for s in string_values: f = QgsFeature() @@ -2783,13 +3021,19 @@ def testAggregate(self): features.append(f) assert pr.addFeatures(features) params = QgsAggregateCalculator.AggregateParameters() - params.delimiter = ' ' - val, ok = layer.aggregate(QgsAggregateCalculator.Aggregate.StringConcatenate, 'fldstring', params) + params.delimiter = " " + val, ok = layer.aggregate( + QgsAggregateCalculator.Aggregate.StringConcatenate, "fldstring", params + ) self.assertTrue(ok) - self.assertEqual(val, 'this is a test a nice test') - val, ok = layer.aggregate(QgsAggregateCalculator.Aggregate.StringConcatenateUnique, 'fldstring', params) + self.assertEqual(val, "this is a test a nice test") + val, ok = layer.aggregate( + QgsAggregateCalculator.Aggregate.StringConcatenateUnique, + "fldstring", + params, + ) self.assertTrue(ok) - self.assertEqual(val, 'this is a test nice') + self.assertEqual(val, "this is a test nice") def testAggregateInVirtualField(self): """ @@ -2807,13 +3051,13 @@ def testAggregateInVirtualField(self): features.append(f) assert pr.addFeatures(features) - field = QgsField('virtual', QVariant.Double) - layer.addExpressionField('sum(fldint*2)', field) - vals = [f['virtual'] for f in layer.getFeatures()] + field = QgsField("virtual", QVariant.Double) + layer.addExpressionField("sum(fldint*2)", field) + vals = [f["virtual"] for f in layer.getFeatures()] self.assertEqual(vals, [48, 48, 48, 48, 48, 48, 48]) def testAggregateFilter(self): - """ Test aggregate calculation """ + """Test aggregate calculation""" layer = QgsVectorLayer("Point?field=fldint:integer", "layer", "memory") pr = layer.dataProvider() @@ -2826,7 +3070,9 @@ def testAggregateFilter(self): features.append(f) assert pr.addFeatures(features) - val, ok = layer.aggregate(QgsAggregateCalculator.Aggregate.Sum, 'fldint', fids=[1, 2]) + val, ok = layer.aggregate( + QgsAggregateCalculator.Aggregate.Sum, "fldint", fids=[1, 2] + ) self.assertTrue(ok) self.assertEqual(val, 6.0) @@ -2851,13 +3097,15 @@ def test_setRenderer(self): self.rendererChanged = False layer.rendererChanged.connect(self.onRendererChanged) - r = QgsSingleSymbolRenderer(QgsSymbol.defaultSymbol(QgsWkbTypes.GeometryType.PointGeometry)) + r = QgsSingleSymbolRenderer( + QgsSymbol.defaultSymbol(QgsWkbTypes.GeometryType.PointGeometry) + ) layer.setRenderer(r) self.assertTrue(self.rendererChanged) self.assertEqual(layer.renderer(), r) def testGetSetAliases(self): - """ test getting and setting aliases """ + """test getting and setting aliases""" layer = createLayerWithOnePoint() self.assertEqual(len(layer.attributeAliases()), 2) @@ -2894,7 +3142,7 @@ def testGetSetAliases(self): self.assertFalse(layer.fields().at(1).alias()) def testSaveRestoreAliases(self): - """ test saving and restoring aliases from xml""" + """test saving and restoring aliases from xml""" layer = createLayerWithOnePoint() # no default expressions @@ -2923,7 +3171,7 @@ def testSaveRestoreAliases(self): self.assertEqual(layer3.fields().at(1).alias(), "test2") def testGetSetDefaults(self): - """ test getting and setting default expressions """ + """test getting and setting default expressions""" layer = createLayerWithOnePoint() self.assertFalse(layer.defaultValueDefinition(0)) @@ -2940,7 +3188,9 @@ def testGetSetDefaults(self): self.assertFalse(layer.defaultValueDefinition(1).applyOnUpdate()) self.assertFalse(layer.defaultValueDefinition(2)) self.assertFalse(layer.defaultValueDefinition(2).applyOnUpdate()) - self.assertEqual(layer.fields().at(0).defaultValueDefinition().expression(), "'test'") + self.assertEqual( + layer.fields().at(0).defaultValueDefinition().expression(), "'test'" + ) layer.setDefaultValueDefinition(1, QgsDefaultValue("2+2")) self.assertEqual(layer.defaultValueDefinition(0).expression(), "'test'") @@ -2949,19 +3199,27 @@ def testGetSetDefaults(self): self.assertFalse(layer.defaultValueDefinition(1).applyOnUpdate()) self.assertFalse(layer.defaultValueDefinition(2)) self.assertFalse(layer.defaultValueDefinition(2).applyOnUpdate()) - self.assertEqual(layer.fields().at(0).defaultValueDefinition().expression(), "'test'") - self.assertEqual(layer.fields().at(1).defaultValueDefinition().expression(), "2+2") + self.assertEqual( + layer.fields().at(0).defaultValueDefinition().expression(), "'test'" + ) + self.assertEqual( + layer.fields().at(1).defaultValueDefinition().expression(), "2+2" + ) layer.setDefaultValueDefinition(1, QgsDefaultValue("2+2", True)) self.assertEqual(layer.defaultValueDefinition(0).expression(), "'test'") self.assertFalse(layer.defaultValueDefinition(0).applyOnUpdate()) self.assertEqual(layer.defaultValueDefinition(1).expression(), "2+2") self.assertTrue(layer.defaultValueDefinition(1).applyOnUpdate()) - self.assertEqual(layer.fields().at(0).defaultValueDefinition().expression(), "'test'") - self.assertEqual(layer.fields().at(1).defaultValueDefinition().expression(), "2+2") + self.assertEqual( + layer.fields().at(0).defaultValueDefinition().expression(), "'test'" + ) + self.assertEqual( + layer.fields().at(1).defaultValueDefinition().expression(), "2+2" + ) def testSaveRestoreDefaults(self): - """ test saving and restoring default expressions from xml""" + """test saving and restoring default expressions from xml""" layer = createLayerWithOnePoint() # no default expressions @@ -2986,59 +3244,67 @@ def testSaveRestoreDefaults(self): self.assertTrue(layer3.readXml(elem, QgsReadWriteContext())) self.assertEqual(layer3.defaultValueDefinition(0).expression(), "'test'") self.assertEqual(layer3.defaultValueDefinition(1).expression(), "2+2") - self.assertEqual(layer3.fields().at(0).defaultValueDefinition().expression(), "'test'") - self.assertEqual(layer3.fields().at(1).defaultValueDefinition().expression(), "2+2") + self.assertEqual( + layer3.fields().at(0).defaultValueDefinition().expression(), "'test'" + ) + self.assertEqual( + layer3.fields().at(1).defaultValueDefinition().expression(), "2+2" + ) def testEvaluatingDefaultExpressions(self): - """ tests calculation of default values""" + """tests calculation of default values""" layer = createLayerWithOnePoint() layer.setDefaultValueDefinition(0, QgsDefaultValue("'test'")) layer.setDefaultValueDefinition(1, QgsDefaultValue("2+2")) - self.assertEqual(layer.defaultValue(0), 'test') + self.assertEqual(layer.defaultValue(0), "test") self.assertEqual(layer.defaultValue(1), 4) # using feature - layer.setDefaultValueDefinition(1, QgsDefaultValue('$id * 2')) + layer.setDefaultValueDefinition(1, QgsDefaultValue("$id * 2")) feature = QgsFeature(4) feature.setValid(True) feature.setFields(layer.fields()) # no feature: self.assertFalse(layer.defaultValue(1)) # with feature: - self.assertEqual(layer.defaultValue(0, feature), 'test') + self.assertEqual(layer.defaultValue(0, feature), "test") self.assertEqual(layer.defaultValue(1, feature), 8) # using feature geometry - layer.setDefaultValueDefinition(1, QgsDefaultValue('$x * 2')) + layer.setDefaultValueDefinition(1, QgsDefaultValue("$x * 2")) feature.setGeometry(QgsGeometry(QgsPoint(6, 7))) self.assertEqual(layer.defaultValue(1, feature), 12) # using contexts scope = QgsExpressionContextScope() - scope.setVariable('var1', 16) + scope.setVariable("var1", 16) context = QgsExpressionContext() context.appendScope(scope) - layer.setDefaultValueDefinition(1, QgsDefaultValue('$id + @var1')) + layer.setDefaultValueDefinition(1, QgsDefaultValue("$id + @var1")) self.assertEqual(layer.defaultValue(1, feature, context), 20) # if no scope passed, should use a default constructed one including layer variables - QgsExpressionContextUtils.setLayerVariable(layer, 'var2', 4) - QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(), 'var3', 8) - layer.setDefaultValueDefinition(1, QgsDefaultValue('to_int(@var2) + to_int(@var3) + $id')) + QgsExpressionContextUtils.setLayerVariable(layer, "var2", 4) + QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(), "var3", 8) + layer.setDefaultValueDefinition( + 1, QgsDefaultValue("to_int(@var2) + to_int(@var3) + $id") + ) self.assertEqual(layer.defaultValue(1, feature), 16) # bad expression - layer.setDefaultValueDefinition(1, QgsDefaultValue('not a valid expression')) + layer.setDefaultValueDefinition(1, QgsDefaultValue("not a valid expression")) self.assertFalse(layer.defaultValue(1)) def testApplyOnUpdateDefaultExpressions(self): """tests apply on update of default values""" layer = createLayerWithOnePoint() - layer.setDefaultValueDefinition(0, QgsDefaultValue("CONCAT('l: ', @number, ',f: ', \"fldint\" )", True)) + layer.setDefaultValueDefinition( + 0, QgsDefaultValue("CONCAT('l: ', @number, ',f: ', \"fldint\" )", True) + ) layer.setDefaultValueDefinition(1, QgsDefaultValue("1 * @number", False)) - QgsExpressionContextUtils.setLayerVariable(layer, 'number', 4) + QgsExpressionContextUtils.setLayerVariable(layer, "number", 4) layer.startEditing() feature = QgsFeature() @@ -3051,28 +3317,28 @@ def testApplyOnUpdateDefaultExpressions(self): self.assertTrue(layer.addFeature(feature)) fid = feature.id() - self.assertEqual(layer.getFeature(fid)['fldtxt'], 'l: 4,f: 4') - self.assertEqual(layer.getFeature(fid)['fldint'], 4) + self.assertEqual(layer.getFeature(fid)["fldtxt"], "l: 4,f: 4") + self.assertEqual(layer.getFeature(fid)["fldint"], 4) # ApplyOnUpdateDefaultValue should be set on changeAttributeValue layer.changeAttributeValue(fid, 1, 20) - self.assertEqual(layer.getFeature(fid)['fldtxt'], 'l: 4,f: 20') - self.assertEqual(layer.getFeature(fid)['fldint'], 20) + self.assertEqual(layer.getFeature(fid)["fldtxt"], "l: 4,f: 20") + self.assertEqual(layer.getFeature(fid)["fldint"], 20) # When changing the value of the "derived" attribute, only this one # should be updated - QgsExpressionContextUtils.setLayerVariable(layer, 'number', 8) + QgsExpressionContextUtils.setLayerVariable(layer, "number", 8) layer.changeAttributeValue(fid, 0, 0) - self.assertEqual(layer.getFeature(fid)['fldtxt'], 'l: 8,f: 20') - self.assertEqual(layer.getFeature(fid)['fldint'], 20) + self.assertEqual(layer.getFeature(fid)["fldtxt"], "l: 8,f: 20") + self.assertEqual(layer.getFeature(fid)["fldint"], 20) # Check update on geometry change layer.setDefaultValueDefinition(1, QgsDefaultValue("x($geometry)", True)) layer.changeGeometry(fid, QgsGeometry.fromPointXY(QgsPointXY(300, 200))) - self.assertEqual(layer.getFeature(fid)['fldint'], 300) + self.assertEqual(layer.getFeature(fid)["fldint"], 300) def testGetSetConstraints(self): - """ test getting and setting field constraints """ + """test getting and setting field constraints""" layer = createLayerWithOnePoint() self.assertFalse(layer.fieldConstraints(0)) @@ -3080,59 +3346,144 @@ def testGetSetConstraints(self): self.assertFalse(layer.fieldConstraints(2)) layer.setFieldConstraint(0, QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertEqual(layer.fieldConstraints(0), QgsFieldConstraints.Constraint.ConstraintNotNull) + self.assertEqual( + layer.fieldConstraints(0), QgsFieldConstraints.Constraint.ConstraintNotNull + ) self.assertFalse(layer.fieldConstraints(1)) self.assertFalse(layer.fieldConstraints(2)) - self.assertEqual(layer.fields().at(0).constraints().constraints(), QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertEqual(layer.fields().at(0).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer) - self.assertEqual(layer.fields().at(0).constraints().constraintStrength(QgsFieldConstraints.Constraint.ConstraintNotNull), - QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard) - self.assertEqual(layer.fieldConstraintsAndStrength(0)[QgsFieldConstraints.Constraint.ConstraintNotNull], - QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard) + self.assertEqual( + layer.fields().at(0).constraints().constraints(), + QgsFieldConstraints.Constraint.ConstraintNotNull, + ) + self.assertEqual( + layer.fields() + .at(0) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer, + ) + self.assertEqual( + layer.fields() + .at(0) + .constraints() + .constraintStrength(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard, + ) + self.assertEqual( + layer.fieldConstraintsAndStrength(0)[ + QgsFieldConstraints.Constraint.ConstraintNotNull + ], + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard, + ) self.assertEqual(len(layer.fieldConstraintsAndStrength(1)), 0) self.assertEqual(len(layer.fieldConstraintsAndStrength(2)), 0) layer.setFieldConstraint(1, QgsFieldConstraints.Constraint.ConstraintNotNull) layer.setFieldConstraint(1, QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertEqual(layer.fieldConstraints(0), QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertEqual(layer.fieldConstraints(1), - QgsFieldConstraints.Constraint.ConstraintNotNull | QgsFieldConstraints.Constraint.ConstraintUnique) + self.assertEqual( + layer.fieldConstraints(0), QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertEqual( + layer.fieldConstraints(1), + QgsFieldConstraints.Constraint.ConstraintNotNull + | QgsFieldConstraints.Constraint.ConstraintUnique, + ) self.assertFalse(layer.fieldConstraints(2)) - self.assertEqual(layer.fields().at(0).constraints().constraints(), QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertEqual(layer.fields().at(0).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer) - self.assertEqual(layer.fields().at(0).constraints().constraintStrength(QgsFieldConstraints.Constraint.ConstraintNotNull), - QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard) - self.assertEqual(layer.fields().at(1).constraints().constraints(), - QgsFieldConstraints.Constraint.ConstraintNotNull | QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertEqual(layer.fields().at(1).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer) - self.assertEqual(layer.fields().at(1).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer) - self.assertEqual(layer.fields().at(1).constraints().constraintStrength(QgsFieldConstraints.Constraint.ConstraintNotNull), - QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard) - self.assertEqual(layer.fields().at(1).constraints().constraintStrength(QgsFieldConstraints.Constraint.ConstraintUnique), - QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard) + self.assertEqual( + layer.fields().at(0).constraints().constraints(), + QgsFieldConstraints.Constraint.ConstraintNotNull, + ) + self.assertEqual( + layer.fields() + .at(0) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer, + ) + self.assertEqual( + layer.fields() + .at(0) + .constraints() + .constraintStrength(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard, + ) + self.assertEqual( + layer.fields().at(1).constraints().constraints(), + QgsFieldConstraints.Constraint.ConstraintNotNull + | QgsFieldConstraints.Constraint.ConstraintUnique, + ) + self.assertEqual( + layer.fields() + .at(1) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer, + ) + self.assertEqual( + layer.fields() + .at(1) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer, + ) + self.assertEqual( + layer.fields() + .at(1) + .constraints() + .constraintStrength(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard, + ) + self.assertEqual( + layer.fields() + .at(1) + .constraints() + .constraintStrength(QgsFieldConstraints.Constraint.ConstraintUnique), + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard, + ) layer.removeFieldConstraint(1, QgsFieldConstraints.Constraint.ConstraintNotNull) layer.removeFieldConstraint(1, QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertEqual(layer.fieldConstraints(0), QgsFieldConstraints.Constraint.ConstraintNotNull) + self.assertEqual( + layer.fieldConstraints(0), QgsFieldConstraints.Constraint.ConstraintNotNull + ) self.assertFalse(layer.fieldConstraints(1)) self.assertFalse(layer.fieldConstraints(2)) - self.assertEqual(layer.fields().at(0).constraints().constraints(), QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertEqual(layer.fields().at(0).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer) - self.assertEqual(layer.fields().at(0).constraints().constraintStrength(QgsFieldConstraints.Constraint.ConstraintNotNull), - QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard) + self.assertEqual( + layer.fields().at(0).constraints().constraints(), + QgsFieldConstraints.Constraint.ConstraintNotNull, + ) + self.assertEqual( + layer.fields() + .at(0) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer, + ) + self.assertEqual( + layer.fields() + .at(0) + .constraints() + .constraintStrength(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard, + ) self.assertFalse(layer.fields().at(1).constraints().constraints()) - self.assertEqual(layer.fields().at(1).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginNotSet) - self.assertEqual(layer.fields().at(1).constraints().constraintStrength(QgsFieldConstraints.Constraint.ConstraintNotNull), - QgsFieldConstraints.ConstraintStrength.ConstraintStrengthNotSet) + self.assertEqual( + layer.fields() + .at(1) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginNotSet, + ) + self.assertEqual( + layer.fields() + .at(1) + .constraints() + .constraintStrength(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthNotSet, + ) def testSaveRestoreConstraints(self): - """ test saving and restoring constraints from xml""" + """test saving and restoring constraints from xml""" layer = createLayerWithOnePoint() # no constraints @@ -3149,7 +3500,11 @@ def testSaveRestoreConstraints(self): # set some constraints layer.setFieldConstraint(0, QgsFieldConstraints.Constraint.ConstraintNotNull) - layer.setFieldConstraint(1, QgsFieldConstraints.Constraint.ConstraintNotNull, QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft) + layer.setFieldConstraint( + 1, + QgsFieldConstraints.Constraint.ConstraintNotNull, + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft, + ) layer.setFieldConstraint(1, QgsFieldConstraints.Constraint.ConstraintUnique) doc = QDomDocument("testdoc") @@ -3158,63 +3513,126 @@ def testSaveRestoreConstraints(self): layer3 = createLayerWithOnePoint() self.assertTrue(layer3.readXml(elem, QgsReadWriteContext())) - self.assertEqual(layer3.fieldConstraints(0), QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertEqual(layer3.fieldConstraints(1), - QgsFieldConstraints.Constraint.ConstraintNotNull | QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertEqual(layer3.fields().at(0).constraints().constraints(), QgsFieldConstraints.Constraint.ConstraintNotNull) - self.assertEqual(layer3.fields().at(0).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer) - self.assertEqual(layer3.fields().at(0).constraints().constraintStrength(QgsFieldConstraints.Constraint.ConstraintNotNull), - QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard) - self.assertEqual(layer3.fieldConstraintsAndStrength(0)[QgsFieldConstraints.Constraint.ConstraintNotNull], - QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard) - self.assertEqual(layer3.fields().at(1).constraints().constraints(), - QgsFieldConstraints.Constraint.ConstraintNotNull | QgsFieldConstraints.Constraint.ConstraintUnique) - self.assertEqual(layer3.fields().at(1).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer) - self.assertEqual(layer3.fields().at(1).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer) - self.assertEqual(layer3.fields().at(1).constraints().constraintStrength(QgsFieldConstraints.Constraint.ConstraintNotNull), - QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft) - self.assertEqual(layer3.fields().at(1).constraints().constraintStrength(QgsFieldConstraints.Constraint.ConstraintUnique), - QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard) - self.assertEqual(layer3.fieldConstraintsAndStrength(1)[QgsFieldConstraints.Constraint.ConstraintNotNull], - QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft) - self.assertEqual(layer3.fieldConstraintsAndStrength(1)[QgsFieldConstraints.Constraint.ConstraintUnique], - QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard) + self.assertEqual( + layer3.fieldConstraints(0), QgsFieldConstraints.Constraint.ConstraintNotNull + ) + self.assertEqual( + layer3.fieldConstraints(1), + QgsFieldConstraints.Constraint.ConstraintNotNull + | QgsFieldConstraints.Constraint.ConstraintUnique, + ) + self.assertEqual( + layer3.fields().at(0).constraints().constraints(), + QgsFieldConstraints.Constraint.ConstraintNotNull, + ) + self.assertEqual( + layer3.fields() + .at(0) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer, + ) + self.assertEqual( + layer3.fields() + .at(0) + .constraints() + .constraintStrength(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard, + ) + self.assertEqual( + layer3.fieldConstraintsAndStrength(0)[ + QgsFieldConstraints.Constraint.ConstraintNotNull + ], + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard, + ) + self.assertEqual( + layer3.fields().at(1).constraints().constraints(), + QgsFieldConstraints.Constraint.ConstraintNotNull + | QgsFieldConstraints.Constraint.ConstraintUnique, + ) + self.assertEqual( + layer3.fields() + .at(1) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer, + ) + self.assertEqual( + layer3.fields() + .at(1) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintUnique), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer, + ) + self.assertEqual( + layer3.fields() + .at(1) + .constraints() + .constraintStrength(QgsFieldConstraints.Constraint.ConstraintNotNull), + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft, + ) + self.assertEqual( + layer3.fields() + .at(1) + .constraints() + .constraintStrength(QgsFieldConstraints.Constraint.ConstraintUnique), + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard, + ) + self.assertEqual( + layer3.fieldConstraintsAndStrength(1)[ + QgsFieldConstraints.Constraint.ConstraintNotNull + ], + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft, + ) + self.assertEqual( + layer3.fieldConstraintsAndStrength(1)[ + QgsFieldConstraints.Constraint.ConstraintUnique + ], + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard, + ) def testGetSetConstraintExpressions(self): - """ test getting and setting field constraint expressions """ + """test getting and setting field constraint expressions""" layer = createLayerWithOnePoint() self.assertFalse(layer.constraintExpression(0)) self.assertFalse(layer.constraintExpression(1)) self.assertFalse(layer.constraintExpression(2)) - layer.setConstraintExpression(0, '1+2') - self.assertEqual(layer.constraintExpression(0), '1+2') + layer.setConstraintExpression(0, "1+2") + self.assertEqual(layer.constraintExpression(0), "1+2") self.assertFalse(layer.constraintExpression(1)) self.assertFalse(layer.constraintExpression(2)) - self.assertEqual(layer.fields().at(0).constraints().constraintExpression(), '1+2') + self.assertEqual( + layer.fields().at(0).constraints().constraintExpression(), "1+2" + ) - layer.setConstraintExpression(1, '3+4', 'desc') - self.assertEqual(layer.constraintExpression(0), '1+2') - self.assertEqual(layer.constraintExpression(1), '3+4') - self.assertEqual(layer.constraintDescription(1), 'desc') + layer.setConstraintExpression(1, "3+4", "desc") + self.assertEqual(layer.constraintExpression(0), "1+2") + self.assertEqual(layer.constraintExpression(1), "3+4") + self.assertEqual(layer.constraintDescription(1), "desc") self.assertFalse(layer.constraintExpression(2)) - self.assertEqual(layer.fields().at(0).constraints().constraintExpression(), '1+2') - self.assertEqual(layer.fields().at(1).constraints().constraintExpression(), '3+4') - self.assertEqual(layer.fields().at(1).constraints().constraintDescription(), 'desc') + self.assertEqual( + layer.fields().at(0).constraints().constraintExpression(), "1+2" + ) + self.assertEqual( + layer.fields().at(1).constraints().constraintExpression(), "3+4" + ) + self.assertEqual( + layer.fields().at(1).constraints().constraintDescription(), "desc" + ) layer.setConstraintExpression(1, None) - self.assertEqual(layer.constraintExpression(0), '1+2') + self.assertEqual(layer.constraintExpression(0), "1+2") self.assertFalse(layer.constraintExpression(1)) self.assertFalse(layer.constraintExpression(2)) - self.assertEqual(layer.fields().at(0).constraints().constraintExpression(), '1+2') + self.assertEqual( + layer.fields().at(0).constraints().constraintExpression(), "1+2" + ) self.assertFalse(layer.fields().at(1).constraints().constraintExpression()) def testSaveRestoreConstraintExpressions(self): - """ test saving and restoring constraint expressions from xml""" + """test saving and restoring constraint expressions from xml""" layer = createLayerWithOnePoint() # no constraints @@ -3228,8 +3646,8 @@ def testSaveRestoreConstraintExpressions(self): self.assertFalse(layer2.constraintExpression(1)) # set some constraints - layer.setConstraintExpression(0, '1+2') - layer.setConstraintExpression(1, '3+4', 'desc') + layer.setConstraintExpression(0, "1+2") + layer.setConstraintExpression(1, "3+4", "desc") doc = QDomDocument("testdoc") elem = doc.createElement("maplayer") @@ -3237,21 +3655,43 @@ def testSaveRestoreConstraintExpressions(self): layer3 = createLayerWithOnePoint() self.assertTrue(layer3.readXml(elem, QgsReadWriteContext())) - self.assertEqual(layer3.constraintExpression(0), '1+2') - self.assertEqual(layer3.constraintExpression(1), '3+4') - self.assertEqual(layer3.constraintDescription(1), 'desc') - self.assertEqual(layer3.fields().at(0).constraints().constraintExpression(), '1+2') - self.assertEqual(layer3.fields().at(1).constraints().constraintExpression(), '3+4') - self.assertEqual(layer3.fields().at(1).constraints().constraintDescription(), 'desc') - self.assertEqual(layer3.fields().at(0).constraints().constraints(), QgsFieldConstraints.Constraint.ConstraintExpression) - self.assertEqual(layer3.fields().at(1).constraints().constraints(), QgsFieldConstraints.Constraint.ConstraintExpression) - self.assertEqual(layer3.fields().at(0).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintExpression), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer) - self.assertEqual(layer3.fields().at(1).constraints().constraintOrigin(QgsFieldConstraints.Constraint.ConstraintExpression), - QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer) + self.assertEqual(layer3.constraintExpression(0), "1+2") + self.assertEqual(layer3.constraintExpression(1), "3+4") + self.assertEqual(layer3.constraintDescription(1), "desc") + self.assertEqual( + layer3.fields().at(0).constraints().constraintExpression(), "1+2" + ) + self.assertEqual( + layer3.fields().at(1).constraints().constraintExpression(), "3+4" + ) + self.assertEqual( + layer3.fields().at(1).constraints().constraintDescription(), "desc" + ) + self.assertEqual( + layer3.fields().at(0).constraints().constraints(), + QgsFieldConstraints.Constraint.ConstraintExpression, + ) + self.assertEqual( + layer3.fields().at(1).constraints().constraints(), + QgsFieldConstraints.Constraint.ConstraintExpression, + ) + self.assertEqual( + layer3.fields() + .at(0) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintExpression), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer, + ) + self.assertEqual( + layer3.fields() + .at(1) + .constraints() + .constraintOrigin(QgsFieldConstraints.Constraint.ConstraintExpression), + QgsFieldConstraints.ConstraintOrigin.ConstraintOriginLayer, + ) def testGetFeatureLimitWithEdits(self): - """ test getting features with a limit, when edits are present """ + """test getting features with a limit, when edits are present""" layer = createLayerWithOnePoint() # now has one feature with id 0 @@ -3280,20 +3720,26 @@ def testGetFeatureLimitWithEdits(self): # change an attribute value required by filter layer.startEditing() - req = QgsFeatureRequest().setFilterExpression('fldint=3').setLimit(2) + req = QgsFeatureRequest().setFilterExpression("fldint=3").setLimit(2) self.assertTrue(layer.changeAttributeValue(2, 1, 4)) self.assertEqual(len(list(layer.getFeatures(req))), 2) layer.rollBack() layer.startEditing() - req = QgsFeatureRequest().setFilterRect(QgsRectangle(50, 100, 150, 300)).setLimit(2) - self.assertTrue(layer.changeGeometry(2, QgsGeometry.fromPointXY(QgsPointXY(500, 600)))) + req = ( + QgsFeatureRequest() + .setFilterRect(QgsRectangle(50, 100, 150, 300)) + .setLimit(2) + ) + self.assertTrue( + layer.changeGeometry(2, QgsGeometry.fromPointXY(QgsPointXY(500, 600))) + ) self.assertEqual(len(list(layer.getFeatures(req))), 2) layer.rollBack() def test_server_properties(self): - """ Test server properties. """ - layer = QgsVectorLayer('Point?field=fldtxt:string', 'layer_1', 'memory') + """Test server properties.""" + layer = QgsVectorLayer("Point?field=fldtxt:string", "layer_1", "memory") self.assertIsInstance(layer.serverProperties(), QgsMapLayerServerProperties) def testClone(self): @@ -3318,38 +3764,38 @@ def testClone(self): # init layer layer = createLayerWithTwoPoints() layer.setBlendMode(QPainter.CompositionMode.CompositionMode_Screen) - layer.styleManager().addStyle('style0', style0) - layer.styleManager().addStyle('style1', style1) - layer.setName('MyName') - layer.setShortName('MyShortName') + layer.styleManager().addStyle("style0", style0) + layer.styleManager().addStyle("style1", style1) + layer.setName("MyName") + layer.setShortName("MyShortName") layer.setMaximumScale(0.5) layer.setMinimumScale(1.5) layer.setScaleBasedVisibility(True) - layer.setTitle('MyTitle') - layer.setAbstract('MyAbstract') - layer.setKeywordList('MyKeywordList') - layer.setDataUrl('MyDataUrl') - layer.setDataUrlFormat('MyDataUrlFormat') - layer.setAttribution('MyAttribution') - layer.setAttributionUrl('MyAttributionUrl') - layer.setMetadataUrl('MyMetadataUrl') - layer.setMetadataUrlType('MyMetadataUrlType') - layer.setMetadataUrlFormat('MyMetadataUrlFormat') - layer.setLegendUrl('MyLegendUrl') - layer.setLegendUrlFormat('MyLegendUrlFormat') + layer.setTitle("MyTitle") + layer.setAbstract("MyAbstract") + layer.setKeywordList("MyKeywordList") + layer.setDataUrl("MyDataUrl") + layer.setDataUrlFormat("MyDataUrlFormat") + layer.setAttribution("MyAttribution") + layer.setAttributionUrl("MyAttributionUrl") + layer.setMetadataUrl("MyMetadataUrl") + layer.setMetadataUrlType("MyMetadataUrlType") + layer.setMetadataUrlFormat("MyMetadataUrlFormat") + layer.setLegendUrl("MyLegendUrl") + layer.setLegendUrlFormat("MyLegendUrlFormat") layer.setDependencies([dep]) layer.setCrs(srs) - layer.setSubsetString('fldint = 457') + layer.setSubsetString("fldint = 457") - layer.setCustomProperty('MyKey0', 'MyValue0') - layer.setCustomProperty('MyKey1', 'MyValue1') + layer.setCustomProperty("MyKey0", "MyValue0") + layer.setCustomProperty("MyKey1", "MyValue1") layer.setOpacity(0.66) - layer.setProviderEncoding('latin9') - layer.setDisplayExpression('MyDisplayExpression') - layer.setMapTipTemplate('MyMapTipTemplate') - layer.setExcludeAttributesWfs(['MyExcludeAttributeWFS']) - layer.setExcludeAttributesWms(['MyExcludeAttributeWMS']) + layer.setProviderEncoding("latin9") + layer.setDisplayExpression("MyDisplayExpression") + layer.setMapTipTemplate("MyMapTipTemplate") + layer.setExcludeAttributesWfs(["MyExcludeAttributeWFS"]) + layer.setExcludeAttributesWms(["MyExcludeAttributeWMS"]) layer.setFeatureBlendMode(QPainter.CompositionMode.CompositionMode_Xor) @@ -3362,8 +3808,8 @@ def testClone(self): simplify.setThreshold(0.333) layer.setSimplifyMethod(simplify) - layer.setFieldAlias(0, 'MyAlias0') - layer.setFieldAlias(1, 'MyAlias1') + layer.setFieldAlias(0, "MyAlias0") + layer.setFieldAlias(1, "MyAlias1") jl0 = createLayerWithTwoPoints() j0 = QgsVectorLayerJoinInfo() @@ -3411,20 +3857,26 @@ def testClone(self): layer.setEditorWidgetSetup(0, widget_setup) layer.setConstraintExpression(0, "MyFieldConstraintExpression") - layer.setFieldConstraint(0, QgsFieldConstraints.Constraint.ConstraintUnique, QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard) + layer.setFieldConstraint( + 0, + QgsFieldConstraints.Constraint.ConstraintUnique, + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard, + ) layer.setDefaultValueDefinition(0, QgsDefaultValue("MyDefaultValueExpression")) - action = QgsAction(QgsAction.ActionType.Unix, "MyActionDescription", "MyActionCmd") + action = QgsAction( + QgsAction.ActionType.Unix, "MyActionDescription", "MyActionCmd" + ) layer.actions().addAction(action) metadata = QgsLayerMetadata() - metadata.setFees('a handful of roos') + metadata.setFees("a handful of roos") layer.setMetadata(metadata) # clone layer clone = layer.clone() - self.assertEqual(layer.metadata().fees(), 'a handful of roos') + self.assertEqual(layer.metadata().fees(), "a handful of roos") # generate xml from layer layer_doc = QDomDocument("doc") @@ -3457,8 +3909,11 @@ def testQgsVectorLayerSelectedFeatureSource(self): test QgsVectorLayerSelectedFeatureSource """ - layer = QgsVectorLayer("Point?crs=epsg:3111&field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?crs=epsg:3111&field=fldtxt:string&field=fldint:integer", + "addfeat", + "memory", + ) pr = layer.dataProvider() f1 = QgsFeature(1) f1.setAttributes(["test", 123]) @@ -3479,7 +3934,7 @@ def testQgsVectorLayerSelectedFeatureSource(self): self.assertEqual(layer.featureCount(), 5) source = QgsVectorLayerSelectedFeatureSource(layer) - self.assertEqual(source.sourceCrs().authid(), 'EPSG:3111') + self.assertEqual(source.sourceCrs().authid(), "EPSG:3111") self.assertEqual(source.wkbType(), QgsWkbTypes.Type.Point) self.assertEqual(source.fields(), layer.fields()) @@ -3497,13 +3952,24 @@ def testQgsVectorLayerSelectedFeatureSource(self): self.assertEqual(ids, {f1.id(), f3.id(), f5.id()}) # test that requesting subset of ids intersects this request with the selected ids - ids = {f.id() for f in source.getFeatures(QgsFeatureRequest().setFilterFids([f1.id(), f2.id(), f5.id()]))} + ids = { + f.id() + for f in source.getFeatures( + QgsFeatureRequest().setFilterFids([f1.id(), f2.id(), f5.id()]) + ) + } self.assertEqual(ids, {f1.id(), f5.id()}) # test that requesting id works - ids = {f.id() for f in source.getFeatures(QgsFeatureRequest().setFilterFid(f1.id()))} + ids = { + f.id() + for f in source.getFeatures(QgsFeatureRequest().setFilterFid(f1.id())) + } self.assertEqual(ids, {f1.id()}) - ids = {f.id() for f in source.getFeatures(QgsFeatureRequest().setFilterFid(f5.id()))} + ids = { + f.id() + for f in source.getFeatures(QgsFeatureRequest().setFilterFid(f5.id())) + } self.assertEqual(ids, {f5.id()}) # test that source has stored snapshot of selected features @@ -3519,9 +3985,9 @@ def testQgsVectorLayerSelectedFeatureSource(self): def testFeatureRequestWithReprojectionAndVirtualFields(self): layer = self.getSource() - field = QgsField('virtual', QVariant.Double) - layer.addExpressionField('$x', field) - virtual_values = [f['virtual'] for f in layer.getFeatures()] + field = QgsField("virtual", QVariant.Double) + layer.addExpressionField("$x", field) + virtual_values = [f["virtual"] for f in layer.getFeatures()] self.assertAlmostEqual(virtual_values[0], -71.123, 2) self.assertEqual(virtual_values[1], NULL) self.assertAlmostEqual(virtual_values[2], -70.332, 2) @@ -3529,59 +3995,102 @@ def testFeatureRequestWithReprojectionAndVirtualFields(self): self.assertAlmostEqual(virtual_values[4], -65.32, 2) # repeat, with reprojection on request - request = QgsFeatureRequest().setDestinationCrs(QgsCoordinateReferenceSystem.fromEpsgId(3785), - QgsProject.instance().transformContext()) + request = QgsFeatureRequest().setDestinationCrs( + QgsCoordinateReferenceSystem.fromEpsgId(3785), + QgsProject.instance().transformContext(), + ) features = [f for f in layer.getFeatures(request)] # virtual field value should not change, even though geometry has - self.assertAlmostEqual(features[0]['virtual'], -71.123, 2) + self.assertAlmostEqual(features[0]["virtual"], -71.123, 2) self.assertAlmostEqual(features[0].geometry().constGet().x(), -7917376, -5) - self.assertEqual(features[1]['virtual'], NULL) + self.assertEqual(features[1]["virtual"], NULL) self.assertFalse(features[1].hasGeometry()) - self.assertAlmostEqual(features[2]['virtual'], -70.332, 2) + self.assertAlmostEqual(features[2]["virtual"], -70.332, 2) self.assertAlmostEqual(features[2].geometry().constGet().x(), -7829322, -5) - self.assertAlmostEqual(features[3]['virtual'], -68.2, 2) + self.assertAlmostEqual(features[3]["virtual"], -68.2, 2) self.assertAlmostEqual(features[3].geometry().constGet().x(), -7591989, -5) - self.assertAlmostEqual(features[4]['virtual'], -65.32, 2) + self.assertAlmostEqual(features[4]["virtual"], -65.32, 2) self.assertAlmostEqual(features[4].geometry().constGet().x(), -7271389, -5) def testPrecision(self): layer = QgsVectorLayer("Polygon?crs=epsg:2056&field=pk:int", "vl", "memory") layer.geometryOptions().setGeometryPrecision(10) - geom = QgsGeometry.fromWkt('Polygon ((2596411 1224654, 2596400 1224652, 2596405 1224640, 2596410 1224641, 2596411 1224654))') + geom = QgsGeometry.fromWkt( + "Polygon ((2596411 1224654, 2596400 1224652, 2596405 1224640, 2596410 1224641, 2596411 1224654))" + ) feature = QgsFeature(layer.fields()) feature.setGeometry(geom) layer.startEditing() layer.addFeature(feature) - self.assertGeometriesEqual(QgsGeometry.fromWkt('Polygon ((2596410 1224650, 2596400 1224650, 2596410 1224640, 2596410 1224650))'), feature.geometry(), 'geometry with unsnapped nodes', 'fixed geometry') + self.assertGeometriesEqual( + QgsGeometry.fromWkt( + "Polygon ((2596410 1224650, 2596400 1224650, 2596410 1224640, 2596410 1224650))" + ), + feature.geometry(), + "geometry with unsnapped nodes", + "fixed geometry", + ) layer.geometryOptions().setGeometryPrecision(0.0) - feature.setGeometry(QgsGeometry.fromWkt('Polygon ((2596411 1224654, 2596400 1224652, 2596405 1224640, 2596410 1224641, 2596411 1224654))')) + feature.setGeometry( + QgsGeometry.fromWkt( + "Polygon ((2596411 1224654, 2596400 1224652, 2596405 1224640, 2596410 1224641, 2596411 1224654))" + ) + ) layer.addFeature(feature) - self.assertGeometriesEqual(QgsGeometry.fromWkt('Polygon ((2596411 1224654, 2596400 1224652, 2596405 1224640, 2596410 1224641, 2596411 1224654))'), feature.geometry(), 'geometry with duplicates', 'unchanged geometry') + self.assertGeometriesEqual( + QgsGeometry.fromWkt( + "Polygon ((2596411 1224654, 2596400 1224652, 2596405 1224640, 2596410 1224641, 2596411 1224654))" + ), + feature.geometry(), + "geometry with duplicates", + "unchanged geometry", + ) def testRemoveDuplicateNodes(self): layer = QgsVectorLayer("Polygon?crs=epsg:2056&field=pk:int", "vl", "memory") layer.geometryOptions().setRemoveDuplicateNodes(True) - geom = QgsGeometry.fromWkt('Polygon ((70 80, 80 90, 80 90, 60 50, 70 80))') + geom = QgsGeometry.fromWkt("Polygon ((70 80, 80 90, 80 90, 60 50, 70 80))") feature = QgsFeature(layer.fields()) feature.setGeometry(geom) layer.startEditing() layer.addFeature(feature) - self.assertGeometriesEqual(feature.geometry(), QgsGeometry.fromWkt('Polygon ((70 80, 80 90, 60 50, 70 80))'), 'fixed geometry', 'geometry with duplicates') + self.assertGeometriesEqual( + feature.geometry(), + QgsGeometry.fromWkt("Polygon ((70 80, 80 90, 60 50, 70 80))"), + "fixed geometry", + "geometry with duplicates", + ) layer.geometryOptions().setRemoveDuplicateNodes(False) - feature.setGeometry(QgsGeometry.fromWkt('Polygon ((70 80, 80 90, 80 90, 60 50, 70 80))')) + feature.setGeometry( + QgsGeometry.fromWkt("Polygon ((70 80, 80 90, 80 90, 60 50, 70 80))") + ) layer.addFeature(feature) - self.assertGeometriesEqual(feature.geometry(), QgsGeometry.fromWkt('Polygon ((70 80, 80 90, 80 90, 60 50, 70 80))'), 'unchanged geometry', 'geometry with duplicates') + self.assertGeometriesEqual( + feature.geometry(), + QgsGeometry.fromWkt("Polygon ((70 80, 80 90, 80 90, 60 50, 70 80))"), + "unchanged geometry", + "geometry with duplicates", + ) def testPrecisionAndDuplicateNodes(self): layer = QgsVectorLayer("Polygon?crs=epsg:2056&field=pk:int", "vl", "memory") layer.geometryOptions().setGeometryPrecision(10) layer.geometryOptions().setRemoveDuplicateNodes(True) - geom = QgsGeometry.fromWkt('Polygon ((2596411 1224654, 2596400 1224652, 2596402 1224653, 2596405 1224640, 2596410 1224641, 2596411 1224654))') + geom = QgsGeometry.fromWkt( + "Polygon ((2596411 1224654, 2596400 1224652, 2596402 1224653, 2596405 1224640, 2596410 1224641, 2596411 1224654))" + ) feature = QgsFeature(layer.fields()) feature.setGeometry(geom) layer.startEditing() layer.addFeature(feature) - self.assertGeometriesEqual(QgsGeometry.fromWkt('Polygon ((2596410 1224650, 2596400 1224650, 2596410 1224640, 2596410 1224650))'), feature.geometry(), 'geometry with unsnapped nodes', 'fixed geometry') + self.assertGeometriesEqual( + QgsGeometry.fromWkt( + "Polygon ((2596410 1224650, 2596400 1224650, 2596410 1224640, 2596410 1224650))" + ), + feature.geometry(), + "geometry with unsnapped nodes", + "fixed geometry", + ) def testDefaultDisplayExpression(self): """ @@ -3589,45 +4098,105 @@ def testDefaultDisplayExpression(self): """ layer = QgsVectorLayer("Polygon?crs=epsg:2056&field=pk:int", "vl", "memory") self.assertEqual(layer.displayExpression(), '"pk"') - self.assertEqual(layer.displayField(), 'pk') - layer = QgsVectorLayer("Polygon?crs=epsg:2056&field=pk:int&field=DESCRIPTION:string&field=fid:int", "vl", "memory") + self.assertEqual(layer.displayField(), "pk") + layer = QgsVectorLayer( + "Polygon?crs=epsg:2056&field=pk:int&field=DESCRIPTION:string&field=fid:int", + "vl", + "memory", + ) self.assertEqual(layer.displayExpression(), '"DESCRIPTION"') - self.assertEqual(layer.displayField(), 'DESCRIPTION') - layer = QgsVectorLayer("Polygon?crs=epsg:2056&field=pk:int&field=DESCRIPTION:string&field=fid:int&field=NAME:string", "vl", "memory") + self.assertEqual(layer.displayField(), "DESCRIPTION") + layer = QgsVectorLayer( + "Polygon?crs=epsg:2056&field=pk:int&field=DESCRIPTION:string&field=fid:int&field=NAME:string", + "vl", + "memory", + ) self.assertEqual(layer.displayExpression(), '"NAME"') - self.assertEqual(layer.displayField(), 'NAME') - layer = QgsVectorLayer("Polygon?crs=epsg:2056&field=pk:int&field=DESCRIPTION:string&field=fid:int&field=BETTER_NAME:string&field=NAME:string", "vl", "memory") + self.assertEqual(layer.displayField(), "NAME") + layer = QgsVectorLayer( + "Polygon?crs=epsg:2056&field=pk:int&field=DESCRIPTION:string&field=fid:int&field=BETTER_NAME:string&field=NAME:string", + "vl", + "memory", + ) self.assertEqual(layer.displayExpression(), '"BETTER_NAME"') - self.assertEqual(layer.displayField(), 'BETTER_NAME') + self.assertEqual(layer.displayField(), "BETTER_NAME") -class TestQgsVectorLayerSourceAddedFeaturesInBuffer(QgisTestCase, FeatureSourceTestCase): +class TestQgsVectorLayerSourceAddedFeaturesInBuffer( + QgisTestCase, FeatureSourceTestCase +): @classmethod def getSource(cls): vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk', - 'test', 'memory') - assert (vl.isValid()) + "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk", + "test", + "memory", + ) + assert vl.isValid() f1 = QgsFeature() - f1.setAttributes([5, -200, NULL, 'NuLl', '5', QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), QDate(2020, 5, 2), QTime(12, 13, 1)]) - f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)')) + f1.setAttributes( + [ + 5, + -200, + NULL, + "NuLl", + "5", + QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), + QDate(2020, 5, 2), + QTime(12, 13, 1), + ] + ) + f1.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)")) f2 = QgsFeature() - f2.setAttributes([3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL]) + f2.setAttributes([3, 300, "Pear", "PEaR", "3", NULL, NULL, NULL]) f3 = QgsFeature() - f3.setAttributes([1, 100, 'Orange', 'oranGe', '1', QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), QDate(2020, 5, 3), QTime(12, 13, 14)]) - f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)')) + f3.setAttributes( + [ + 1, + 100, + "Orange", + "oranGe", + "1", + QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), + QDate(2020, 5, 3), + QTime(12, 13, 14), + ] + ) + f3.setGeometry(QgsGeometry.fromWkt("Point (-70.332 66.33)")) f4 = QgsFeature() - f4.setAttributes([2, 200, 'Apple', 'Apple', '2', QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), QDate(2020, 5, 4), QTime(12, 14, 14)]) - f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)')) + f4.setAttributes( + [ + 2, + 200, + "Apple", + "Apple", + "2", + QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), + QDate(2020, 5, 4), + QTime(12, 14, 14), + ] + ) + f4.setGeometry(QgsGeometry.fromWkt("Point (-68.2 70.8)")) f5 = QgsFeature() - f5.setAttributes([4, 400, 'Honey', 'Honey', '4', QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), QDate(2021, 5, 4), QTime(13, 13, 14)]) - f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)')) + f5.setAttributes( + [ + 4, + 400, + "Honey", + "Honey", + "4", + QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), + QDate(2021, 5, 4), + QTime(13, 13, 14), + ] + ) + f5.setGeometry(QgsGeometry.fromWkt("Point (-65.32 78.3)")) # create a layer with features only in the added features buffer - not the provider vl.startEditing() @@ -3638,70 +4207,118 @@ def getSource(cls): def setUpClass(cls): """Run before all tests""" # Create test layer for FeatureSourceTestCase - super(TestQgsVectorLayerSourceAddedFeaturesInBuffer, cls).setUpClass() + super().setUpClass() cls.source = cls.getSource() def testGetFeaturesSubsetAttributes2(self): - """ Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return + """Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass def testGetFeaturesNoGeometry(self): - """ Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return + """Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass def testOrderBy(self): - """ Skip order by tests - edited features are not sorted in iterators. + """Skip order by tests - edited features are not sorted in iterators. (Maybe they should be??) """ pass def testMinimumValue(self): - """ Skip min values test - due to inconsistencies in how null values are treated by providers. + """Skip min values test - due to inconsistencies in how null values are treated by providers. They are included here, but providers don't include them.... which is right? """ pass -class TestQgsVectorLayerSourceChangedGeometriesInBuffer(QgisTestCase, FeatureSourceTestCase): +class TestQgsVectorLayerSourceChangedGeometriesInBuffer( + QgisTestCase, FeatureSourceTestCase +): @classmethod def getSource(cls): vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk', - 'test', 'memory') - assert (vl.isValid()) + "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk", + "test", + "memory", + ) + assert vl.isValid() f1 = QgsFeature() - f1.setAttributes([5, -200, NULL, 'NuLl', '5', QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), QDate(2020, 5, 2), QTime(12, 13, 1)]) + f1.setAttributes( + [ + 5, + -200, + NULL, + "NuLl", + "5", + QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), + QDate(2020, 5, 2), + QTime(12, 13, 1), + ] + ) f2 = QgsFeature() - f2.setAttributes([3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL]) - f2.setGeometry(QgsGeometry.fromWkt('Point (-70.5 65.2)')) + f2.setAttributes([3, 300, "Pear", "PEaR", "3", NULL, NULL, NULL]) + f2.setGeometry(QgsGeometry.fromWkt("Point (-70.5 65.2)")) f3 = QgsFeature() - f3.setAttributes([1, 100, 'Orange', 'oranGe', '1', QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), QDate(2020, 5, 3), QTime(12, 13, 14)]) + f3.setAttributes( + [ + 1, + 100, + "Orange", + "oranGe", + "1", + QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), + QDate(2020, 5, 3), + QTime(12, 13, 14), + ] + ) f4 = QgsFeature() - f4.setAttributes([2, 200, 'Apple', 'Apple', '2', QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), QDate(2020, 5, 4), QTime(12, 14, 14)]) + f4.setAttributes( + [ + 2, + 200, + "Apple", + "Apple", + "2", + QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), + QDate(2020, 5, 4), + QTime(12, 14, 14), + ] + ) f5 = QgsFeature() - f5.setAttributes([4, 400, 'Honey', 'Honey', '4', QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), QDate(2021, 5, 4), QTime(13, 13, 14)]) + f5.setAttributes( + [ + 4, + 400, + "Honey", + "Honey", + "4", + QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), + QDate(2021, 5, 4), + QTime(13, 13, 14), + ] + ) vl.dataProvider().addFeatures([f1, f2, f3, f4, f5]) - ids = {f['pk']: f.id() for f in vl.getFeatures()} + ids = {f["pk"]: f.id() for f in vl.getFeatures()} # modify geometries in buffer vl.startEditing() - vl.changeGeometry(ids[5], QgsGeometry.fromWkt('Point (-71.123 78.23)')) + vl.changeGeometry(ids[5], QgsGeometry.fromWkt("Point (-71.123 78.23)")) vl.changeGeometry(ids[3], QgsGeometry()) - vl.changeGeometry(ids[1], QgsGeometry.fromWkt('Point (-70.332 66.33)')) - vl.changeGeometry(ids[2], QgsGeometry.fromWkt('Point (-68.2 70.8)')) - vl.changeGeometry(ids[4], QgsGeometry.fromWkt('Point (-65.32 78.3)')) + vl.changeGeometry(ids[1], QgsGeometry.fromWkt("Point (-70.332 66.33)")) + vl.changeGeometry(ids[2], QgsGeometry.fromWkt("Point (-68.2 70.8)")) + vl.changeGeometry(ids[4], QgsGeometry.fromWkt("Point (-65.32 78.3)")) return vl @@ -3709,99 +4326,166 @@ def getSource(cls): def setUpClass(cls): """Run before all tests""" # Create test layer for FeatureSourceTestCase - super(TestQgsVectorLayerSourceChangedGeometriesInBuffer, cls).setUpClass() + super().setUpClass() cls.source = cls.getSource() def testGetFeaturesSubsetAttributes2(self): - """ Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return + """Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass def testGetFeaturesNoGeometry(self): - """ Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return + """Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass def testOrderBy(self): - """ Skip order by tests - edited features are not sorted in iterators. + """Skip order by tests - edited features are not sorted in iterators. (Maybe they should be??) """ pass -class TestQgsVectorLayerSourceChangedAttributesInBuffer(QgisTestCase, FeatureSourceTestCase): +class TestQgsVectorLayerSourceChangedAttributesInBuffer( + QgisTestCase, FeatureSourceTestCase +): @classmethod def getSource(cls): vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk', - 'test', 'memory') - assert (vl.isValid()) + "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk", + "test", + "memory", + ) + assert vl.isValid() f1 = QgsFeature() - f1.setAttributes([5, 200, 'a', 'b', 'c', QDateTime(2020, 4, 5, 1, 2, 3), QDate(2020, 4, 5), QTime(1, 2, 3)]) - f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)')) + f1.setAttributes( + [ + 5, + 200, + "a", + "b", + "c", + QDateTime(2020, 4, 5, 1, 2, 3), + QDate(2020, 4, 5), + QTime(1, 2, 3), + ] + ) + f1.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)")) f2 = QgsFeature() - f2.setAttributes([3, -200, 'd', 'e', 'f', QDateTime(2020, 4, 5, 1, 2, 3), QDate(2020, 4, 5), QTime(1, 2, 3)]) + f2.setAttributes( + [ + 3, + -200, + "d", + "e", + "f", + QDateTime(2020, 4, 5, 1, 2, 3), + QDate(2020, 4, 5), + QTime(1, 2, 3), + ] + ) f3 = QgsFeature() - f3.setAttributes([1, -100, 'g', 'h', 'i', QDateTime(2020, 4, 5, 1, 2, 3), QDate(2020, 4, 5), QTime(1, 2, 3)]) - f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)')) + f3.setAttributes( + [ + 1, + -100, + "g", + "h", + "i", + QDateTime(2020, 4, 5, 1, 2, 3), + QDate(2020, 4, 5), + QTime(1, 2, 3), + ] + ) + f3.setGeometry(QgsGeometry.fromWkt("Point (-70.332 66.33)")) f4 = QgsFeature() - f4.setAttributes([2, -200, 'j', 'k', 'l', QDateTime(2020, 4, 5, 1, 2, 3), QDate(2020, 4, 5), QTime(1, 2, 3)]) - f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)')) + f4.setAttributes( + [ + 2, + -200, + "j", + "k", + "l", + QDateTime(2020, 4, 5, 1, 2, 3), + QDate(2020, 4, 5), + QTime(1, 2, 3), + ] + ) + f4.setGeometry(QgsGeometry.fromWkt("Point (-68.2 70.8)")) f5 = QgsFeature() - f5.setAttributes([4, 400, 'm', 'n', 'o', QDateTime(2020, 4, 5, 1, 2, 3), QDate(2020, 4, 5), QTime(1, 2, 3)]) - f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)')) + f5.setAttributes( + [ + 4, + 400, + "m", + "n", + "o", + QDateTime(2020, 4, 5, 1, 2, 3), + QDate(2020, 4, 5), + QTime(1, 2, 3), + ] + ) + f5.setGeometry(QgsGeometry.fromWkt("Point (-65.32 78.3)")) vl.dataProvider().addFeatures([f1, f2, f3, f4, f5]) - ids = {f['pk']: f.id() for f in vl.getFeatures()} + ids = {f["pk"]: f.id() for f in vl.getFeatures()} # modify geometries in buffer vl.startEditing() vl.changeAttributeValue(ids[5], 1, -200) vl.changeAttributeValue(ids[5], 2, NULL) - vl.changeAttributeValue(ids[5], 3, 'NuLl') - vl.changeAttributeValue(ids[5], 4, '5') - vl.changeAttributeValue(ids[5], 5, QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14))) + vl.changeAttributeValue(ids[5], 3, "NuLl") + vl.changeAttributeValue(ids[5], 4, "5") + vl.changeAttributeValue( + ids[5], 5, QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)) + ) vl.changeAttributeValue(ids[5], 6, QDate(2020, 5, 2)) vl.changeAttributeValue(ids[5], 7, QTime(12, 13, 1)) vl.changeAttributeValue(ids[3], 1, 300) - vl.changeAttributeValue(ids[3], 2, 'Pear') - vl.changeAttributeValue(ids[3], 3, 'PEaR') - vl.changeAttributeValue(ids[3], 4, '3') + vl.changeAttributeValue(ids[3], 2, "Pear") + vl.changeAttributeValue(ids[3], 3, "PEaR") + vl.changeAttributeValue(ids[3], 4, "3") vl.changeAttributeValue(ids[3], 5, NULL) vl.changeAttributeValue(ids[3], 6, NULL) vl.changeAttributeValue(ids[3], 7, NULL) vl.changeAttributeValue(ids[1], 1, 100) - vl.changeAttributeValue(ids[1], 2, 'Orange') - vl.changeAttributeValue(ids[1], 3, 'oranGe') - vl.changeAttributeValue(ids[1], 4, '1') - vl.changeAttributeValue(ids[1], 5, QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14))) + vl.changeAttributeValue(ids[1], 2, "Orange") + vl.changeAttributeValue(ids[1], 3, "oranGe") + vl.changeAttributeValue(ids[1], 4, "1") + vl.changeAttributeValue( + ids[1], 5, QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)) + ) vl.changeAttributeValue(ids[1], 6, QDate(2020, 5, 3)) vl.changeAttributeValue(ids[1], 7, QTime(12, 13, 14)) vl.changeAttributeValue(ids[2], 1, 200) - vl.changeAttributeValue(ids[2], 2, 'Apple') - vl.changeAttributeValue(ids[2], 3, 'Apple') - vl.changeAttributeValue(ids[2], 4, '2') - vl.changeAttributeValue(ids[2], 5, QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14))) + vl.changeAttributeValue(ids[2], 2, "Apple") + vl.changeAttributeValue(ids[2], 3, "Apple") + vl.changeAttributeValue(ids[2], 4, "2") + vl.changeAttributeValue( + ids[2], 5, QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)) + ) vl.changeAttributeValue(ids[2], 6, QDate(2020, 5, 4)) vl.changeAttributeValue(ids[2], 7, QTime(12, 14, 14)) vl.changeAttributeValue(ids[4], 1, 400) - vl.changeAttributeValue(ids[4], 2, 'Honey') - vl.changeAttributeValue(ids[4], 3, 'Honey') - vl.changeAttributeValue(ids[4], 4, '4') - vl.changeAttributeValue(ids[4], 5, QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14))) + vl.changeAttributeValue(ids[4], 2, "Honey") + vl.changeAttributeValue(ids[4], 3, "Honey") + vl.changeAttributeValue(ids[4], 4, "4") + vl.changeAttributeValue( + ids[4], 5, QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)) + ) vl.changeAttributeValue(ids[4], 6, QDate(2021, 5, 4)) vl.changeAttributeValue(ids[4], 7, QTime(13, 13, 14)) @@ -3810,119 +4494,183 @@ def getSource(cls): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestQgsVectorLayerSourceChangedAttributesInBuffer, cls).setUpClass() + super().setUpClass() # Create test layer for FeatureSourceTestCase cls.source = cls.getSource() def testGetFeaturesSubsetAttributes2(self): - """ Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return + """Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass def testGetFeaturesNoGeometry(self): - """ Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return + """Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass def testOrderBy(self): - """ Skip order by tests - edited features are not sorted in iterators. + """Skip order by tests - edited features are not sorted in iterators. (Maybe they should be??) """ pass def testUniqueValues(self): - """ Skip unique values test - as noted in the docs this is unreliable when features are in the buffer - """ + """Skip unique values test - as noted in the docs this is unreliable when features are in the buffer""" pass def testMinimumValue(self): - """ Skip min values test - as noted in the docs this is unreliable when features are in the buffer - """ + """Skip min values test - as noted in the docs this is unreliable when features are in the buffer""" pass def testMaximumValue(self): - """ Skip max values test - as noted in the docs this is unreliable when features are in the buffer - """ + """Skip max values test - as noted in the docs this is unreliable when features are in the buffer""" pass -class TestQgsVectorLayerSourceChangedGeometriesAndAttributesInBuffer(QgisTestCase, FeatureSourceTestCase): +class TestQgsVectorLayerSourceChangedGeometriesAndAttributesInBuffer( + QgisTestCase, FeatureSourceTestCase +): @classmethod def getSource(cls): vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk', - 'test', 'memory') - assert (vl.isValid()) + "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk", + "test", + "memory", + ) + assert vl.isValid() f1 = QgsFeature() - f1.setAttributes([5, 200, 'a', 'b', 'c', QDateTime(2020, 4, 5, 1, 2, 3), QDate(2020, 4, 5), QTime(1, 2, 3)]) + f1.setAttributes( + [ + 5, + 200, + "a", + "b", + "c", + QDateTime(2020, 4, 5, 1, 2, 3), + QDate(2020, 4, 5), + QTime(1, 2, 3), + ] + ) f2 = QgsFeature() - f2.setAttributes([3, -200, 'd', 'e', 'f', QDateTime(2020, 4, 5, 1, 2, 3), QDate(2020, 4, 5), QTime(1, 2, 3)]) - f2.setGeometry(QgsGeometry.fromWkt('Point (-70.5 65.2)')) + f2.setAttributes( + [ + 3, + -200, + "d", + "e", + "f", + QDateTime(2020, 4, 5, 1, 2, 3), + QDate(2020, 4, 5), + QTime(1, 2, 3), + ] + ) + f2.setGeometry(QgsGeometry.fromWkt("Point (-70.5 65.2)")) f3 = QgsFeature() - f3.setAttributes([1, -100, 'g', 'h', 'i', QDateTime(2020, 4, 5, 1, 2, 3), QDate(2020, 4, 5), QTime(1, 2, 3)]) + f3.setAttributes( + [ + 1, + -100, + "g", + "h", + "i", + QDateTime(2020, 4, 5, 1, 2, 3), + QDate(2020, 4, 5), + QTime(1, 2, 3), + ] + ) f4 = QgsFeature() - f4.setAttributes([2, -200, 'j', 'k', 'l', QDateTime(2020, 4, 5, 1, 2, 3), QDate(2020, 4, 5), QTime(1, 2, 3)]) + f4.setAttributes( + [ + 2, + -200, + "j", + "k", + "l", + QDateTime(2020, 4, 5, 1, 2, 3), + QDate(2020, 4, 5), + QTime(1, 2, 3), + ] + ) f5 = QgsFeature() - f5.setAttributes([4, 400, 'm', 'n', 'o', QDateTime(2020, 4, 5, 1, 2, 3), QDate(2020, 4, 5), QTime(1, 2, 3)]) + f5.setAttributes( + [ + 4, + 400, + "m", + "n", + "o", + QDateTime(2020, 4, 5, 1, 2, 3), + QDate(2020, 4, 5), + QTime(1, 2, 3), + ] + ) vl.dataProvider().addFeatures([f1, f2, f3, f4, f5]) - ids = {f['pk']: f.id() for f in vl.getFeatures()} + ids = {f["pk"]: f.id() for f in vl.getFeatures()} # modify geometries in buffer vl.startEditing() - vl.changeGeometry(ids[5], QgsGeometry.fromWkt('Point (-71.123 78.23)')) + vl.changeGeometry(ids[5], QgsGeometry.fromWkt("Point (-71.123 78.23)")) vl.changeGeometry(ids[3], QgsGeometry()) - vl.changeGeometry(ids[1], QgsGeometry.fromWkt('Point (-70.332 66.33)')) - vl.changeGeometry(ids[2], QgsGeometry.fromWkt('Point (-68.2 70.8)')) - vl.changeGeometry(ids[4], QgsGeometry.fromWkt('Point (-65.32 78.3)')) + vl.changeGeometry(ids[1], QgsGeometry.fromWkt("Point (-70.332 66.33)")) + vl.changeGeometry(ids[2], QgsGeometry.fromWkt("Point (-68.2 70.8)")) + vl.changeGeometry(ids[4], QgsGeometry.fromWkt("Point (-65.32 78.3)")) # modify attributes in buffer vl.changeAttributeValue(ids[5], 1, -200) vl.changeAttributeValue(ids[5], 2, NULL) - vl.changeAttributeValue(ids[5], 3, 'NuLl') - vl.changeAttributeValue(ids[5], 4, '5') - vl.changeAttributeValue(ids[5], 5, QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14))) + vl.changeAttributeValue(ids[5], 3, "NuLl") + vl.changeAttributeValue(ids[5], 4, "5") + vl.changeAttributeValue( + ids[5], 5, QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)) + ) vl.changeAttributeValue(ids[5], 6, QDate(2020, 5, 2)) vl.changeAttributeValue(ids[5], 7, QTime(12, 13, 1)) vl.changeAttributeValue(ids[3], 1, 300) - vl.changeAttributeValue(ids[3], 2, 'Pear') - vl.changeAttributeValue(ids[3], 3, 'PEaR') - vl.changeAttributeValue(ids[3], 4, '3') + vl.changeAttributeValue(ids[3], 2, "Pear") + vl.changeAttributeValue(ids[3], 3, "PEaR") + vl.changeAttributeValue(ids[3], 4, "3") vl.changeAttributeValue(ids[3], 5, NULL) vl.changeAttributeValue(ids[3], 6, NULL) vl.changeAttributeValue(ids[3], 7, NULL) vl.changeAttributeValue(ids[1], 1, 100) - vl.changeAttributeValue(ids[1], 2, 'Orange') - vl.changeAttributeValue(ids[1], 3, 'oranGe') - vl.changeAttributeValue(ids[1], 4, '1') - vl.changeAttributeValue(ids[1], 5, QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14))) + vl.changeAttributeValue(ids[1], 2, "Orange") + vl.changeAttributeValue(ids[1], 3, "oranGe") + vl.changeAttributeValue(ids[1], 4, "1") + vl.changeAttributeValue( + ids[1], 5, QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)) + ) vl.changeAttributeValue(ids[1], 6, QDate(2020, 5, 3)) vl.changeAttributeValue(ids[1], 7, QTime(12, 13, 14)) vl.changeAttributeValue(ids[2], 1, 200) - vl.changeAttributeValue(ids[2], 2, 'Apple') - vl.changeAttributeValue(ids[2], 3, 'Apple') - vl.changeAttributeValue(ids[2], 4, '2') - vl.changeAttributeValue(ids[2], 5, QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14))) + vl.changeAttributeValue(ids[2], 2, "Apple") + vl.changeAttributeValue(ids[2], 3, "Apple") + vl.changeAttributeValue(ids[2], 4, "2") + vl.changeAttributeValue( + ids[2], 5, QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)) + ) vl.changeAttributeValue(ids[2], 6, QDate(2020, 5, 4)) vl.changeAttributeValue(ids[2], 7, QTime(12, 14, 14)) vl.changeAttributeValue(ids[4], 1, 400) - vl.changeAttributeValue(ids[4], 2, 'Honey') - vl.changeAttributeValue(ids[4], 3, 'Honey') - vl.changeAttributeValue(ids[4], 4, '4') - vl.changeAttributeValue(ids[4], 5, QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14))) + vl.changeAttributeValue(ids[4], 2, "Honey") + vl.changeAttributeValue(ids[4], 3, "Honey") + vl.changeAttributeValue(ids[4], 4, "4") + vl.changeAttributeValue( + ids[4], 5, QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)) + ) vl.changeAttributeValue(ids[4], 6, QDate(2021, 5, 4)) vl.changeAttributeValue(ids[4], 7, QTime(13, 13, 14)) @@ -3931,96 +4679,196 @@ def getSource(cls): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestQgsVectorLayerSourceChangedGeometriesAndAttributesInBuffer, cls).setUpClass() + super().setUpClass() # Create test layer for FeatureSourceTestCase cls.source = cls.getSource() def testGetFeaturesSubsetAttributes2(self): - """ Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return + """Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass def testGetFeaturesNoGeometry(self): - """ Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return + """Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass def testOrderBy(self): - """ Skip order by tests - edited features are not sorted in iterators. + """Skip order by tests - edited features are not sorted in iterators. (Maybe they should be??) """ pass def testUniqueValues(self): - """ Skip unique values test - as noted in the docs this is unreliable when features are in the buffer - """ + """Skip unique values test - as noted in the docs this is unreliable when features are in the buffer""" pass def testMinimumValue(self): - """ Skip min values test - as noted in the docs this is unreliable when features are in the buffer - """ + """Skip min values test - as noted in the docs this is unreliable when features are in the buffer""" pass def testMaximumValue(self): - """ Skip max values test - as noted in the docs this is unreliable when features are in the buffer - """ + """Skip max values test - as noted in the docs this is unreliable when features are in the buffer""" pass -class TestQgsVectorLayerSourceDeletedFeaturesInBuffer(QgisTestCase, FeatureSourceTestCase): +class TestQgsVectorLayerSourceDeletedFeaturesInBuffer( + QgisTestCase, FeatureSourceTestCase +): @classmethod def getSource(cls): vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&&key=pk', - 'test', 'memory') - assert (vl.isValid()) + "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&&key=pk", + "test", + "memory", + ) + assert vl.isValid() # add a bunch of similar features to the provider b1 = QgsFeature() - b1.setAttributes([5, -300, 'Apple', 'PEaR', '1', QDateTime(QDate(2020, 5, 5), QTime(12, 11, 14)), QDate(2020, 5, 1), QTime(10, 13, 1)]) - b1.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)')) + b1.setAttributes( + [ + 5, + -300, + "Apple", + "PEaR", + "1", + QDateTime(QDate(2020, 5, 5), QTime(12, 11, 14)), + QDate(2020, 5, 1), + QTime(10, 13, 1), + ] + ) + b1.setGeometry(QgsGeometry.fromWkt("Point (-70.332 66.33)")) b2 = QgsFeature() - b2.setAttributes([3, 100, 'Orange', 'NuLl', '2', QDateTime(QDate(2020, 5, 1), QTime(12, 13, 14)), QDate(2020, 5, 9), QTime(9, 13, 1)]) - b2.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)')) + b2.setAttributes( + [ + 3, + 100, + "Orange", + "NuLl", + "2", + QDateTime(QDate(2020, 5, 1), QTime(12, 13, 14)), + QDate(2020, 5, 9), + QTime(9, 13, 1), + ] + ) + b2.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)")) b3 = QgsFeature() - b3.setAttributes([1, -200, 'Honey', 'oranGe', '5', QDateTime(QDate(2020, 5, 1), QTime(12, 13, 14)), QDate(2020, 5, 19), QTime(2, 13, 1)]) + b3.setAttributes( + [ + 1, + -200, + "Honey", + "oranGe", + "5", + QDateTime(QDate(2020, 5, 1), QTime(12, 13, 14)), + QDate(2020, 5, 19), + QTime(2, 13, 1), + ] + ) b4 = QgsFeature() - b4.setAttributes([2, 400, 'Pear', 'Honey', '3', QDateTime(QDate(2020, 4, 4), QTime(12, 13, 14)), QDate(2020, 4, 2), QTime(4, 13, 1)]) - b4.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)')) + b4.setAttributes( + [ + 2, + 400, + "Pear", + "Honey", + "3", + QDateTime(QDate(2020, 4, 4), QTime(12, 13, 14)), + QDate(2020, 4, 2), + QTime(4, 13, 1), + ] + ) + b4.setGeometry(QgsGeometry.fromWkt("Point (-65.32 78.3)")) b5 = QgsFeature() - b5.setAttributes([4, 200, NULL, 'oranGe', '3', QDateTime(QDate(2019, 5, 4), QTime(12, 13, 14)), QDate(2019, 5, 2), QTime(1, 13, 1)]) - b5.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)')) + b5.setAttributes( + [ + 4, + 200, + NULL, + "oranGe", + "3", + QDateTime(QDate(2019, 5, 4), QTime(12, 13, 14)), + QDate(2019, 5, 2), + QTime(1, 13, 1), + ] + ) + b5.setGeometry(QgsGeometry.fromWkt("Point (-68.2 70.8)")) vl.dataProvider().addFeatures([b1, b2, b3, b4, b5]) - bad_ids = [f['pk'] for f in vl.getFeatures()] + bad_ids = [f["pk"] for f in vl.getFeatures()] # here's our good features f1 = QgsFeature() - f1.setAttributes([5, -200, NULL, 'NuLl', '5', QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), QDate(2020, 5, 2), QTime(12, 13, 1)]) - f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)')) + f1.setAttributes( + [ + 5, + -200, + NULL, + "NuLl", + "5", + QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), + QDate(2020, 5, 2), + QTime(12, 13, 1), + ] + ) + f1.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)")) f2 = QgsFeature() - f2.setAttributes([3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL]) + f2.setAttributes([3, 300, "Pear", "PEaR", "3", NULL, NULL, NULL]) f3 = QgsFeature() - f3.setAttributes([1, 100, 'Orange', 'oranGe', '1', QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), QDate(2020, 5, 3), QTime(12, 13, 14)]) - f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)')) + f3.setAttributes( + [ + 1, + 100, + "Orange", + "oranGe", + "1", + QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), + QDate(2020, 5, 3), + QTime(12, 13, 14), + ] + ) + f3.setGeometry(QgsGeometry.fromWkt("Point (-70.332 66.33)")) f4 = QgsFeature() - f4.setAttributes([2, 200, 'Apple', 'Apple', '2', QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), QDate(2020, 5, 4), QTime(12, 14, 14)]) - f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)')) + f4.setAttributes( + [ + 2, + 200, + "Apple", + "Apple", + "2", + QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), + QDate(2020, 5, 4), + QTime(12, 14, 14), + ] + ) + f4.setGeometry(QgsGeometry.fromWkt("Point (-68.2 70.8)")) f5 = QgsFeature() - f5.setAttributes([4, 400, 'Honey', 'Honey', '4', QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), QDate(2021, 5, 4), QTime(13, 13, 14)]) - f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)')) + f5.setAttributes( + [ + 4, + 400, + "Honey", + "Honey", + "4", + QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), + QDate(2021, 5, 4), + QTime(13, 13, 14), + ] + ) + f5.setGeometry(QgsGeometry.fromWkt("Point (-65.32 78.3)")) vl.dataProvider().addFeatures([f1, f2, f3, f4, f5]) @@ -4032,41 +4880,38 @@ def getSource(cls): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestQgsVectorLayerSourceDeletedFeaturesInBuffer, cls).setUpClass() + super().setUpClass() # Create test layer for FeatureSourceTestCase cls.source = cls.getSource() def testGetFeaturesSubsetAttributes2(self): - """ Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return + """Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass def testGetFeaturesNoGeometry(self): - """ Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return + """Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass def testOrderBy(self): - """ Skip order by tests - edited features are not sorted in iterators. + """Skip order by tests - edited features are not sorted in iterators. (Maybe they should be??) """ pass def testUniqueValues(self): - """ Skip unique values test - as noted in the docs this is unreliable when features are in the buffer - """ + """Skip unique values test - as noted in the docs this is unreliable when features are in the buffer""" pass def testMinimumValue(self): - """ Skip min values test - as noted in the docs this is unreliable when features are in the buffer - """ + """Skip min values test - as noted in the docs this is unreliable when features are in the buffer""" pass def testMaximumValue(self): - """ Skip max values test - as noted in the docs this is unreliable when features are in the buffer - """ + """Skip max values test - as noted in the docs this is unreliable when features are in the buffer""" pass @@ -4076,69 +4921,153 @@ def setUp(self): """Prepare tc""" super().setUp() self.ctx = QgsCoordinateTransformContext() - self.ctx.addCoordinateOperation(QgsCoordinateReferenceSystem.fromEpsgId(4326), - QgsCoordinateReferenceSystem.fromEpsgId(3857), 'test') + self.ctx.addCoordinateOperation( + QgsCoordinateReferenceSystem.fromEpsgId(4326), + QgsCoordinateReferenceSystem.fromEpsgId(3857), + "test", + ) def testTransformContextIsSetInCtor(self): """Test transform context can be set from ctor""" vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk', - 'test', 'memory') - self.assertFalse(vl.transformContext().hasTransform(QgsCoordinateReferenceSystem.fromEpsgId(4326), QgsCoordinateReferenceSystem.fromEpsgId(3857))) + "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk", + "test", + "memory", + ) + self.assertFalse( + vl.transformContext().hasTransform( + QgsCoordinateReferenceSystem.fromEpsgId(4326), + QgsCoordinateReferenceSystem.fromEpsgId(3857), + ) + ) options = QgsVectorLayer.LayerOptions(self.ctx) vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk', - 'test', 'memory', options) - self.assertTrue(vl.transformContext().hasTransform(QgsCoordinateReferenceSystem.fromEpsgId(4326), QgsCoordinateReferenceSystem.fromEpsgId(3857))) + "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk", + "test", + "memory", + options, + ) + self.assertTrue( + vl.transformContext().hasTransform( + QgsCoordinateReferenceSystem.fromEpsgId(4326), + QgsCoordinateReferenceSystem.fromEpsgId(3857), + ) + ) def testTransformContextInheritsFromProject(self): """Test that when a layer is added to a project it inherits its context""" vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk', - 'test', 'memory') - self.assertFalse(vl.transformContext().hasTransform(QgsCoordinateReferenceSystem.fromEpsgId(4326), QgsCoordinateReferenceSystem.fromEpsgId(3857))) + "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk", + "test", + "memory", + ) + self.assertFalse( + vl.transformContext().hasTransform( + QgsCoordinateReferenceSystem.fromEpsgId(4326), + QgsCoordinateReferenceSystem.fromEpsgId(3857), + ) + ) p = QgsProject() - self.assertFalse(p.transformContext().hasTransform(QgsCoordinateReferenceSystem.fromEpsgId(4326), QgsCoordinateReferenceSystem.fromEpsgId(3857))) + self.assertFalse( + p.transformContext().hasTransform( + QgsCoordinateReferenceSystem.fromEpsgId(4326), + QgsCoordinateReferenceSystem.fromEpsgId(3857), + ) + ) p.setTransformContext(self.ctx) - self.assertTrue(p.transformContext().hasTransform(QgsCoordinateReferenceSystem.fromEpsgId(4326), QgsCoordinateReferenceSystem.fromEpsgId(3857))) + self.assertTrue( + p.transformContext().hasTransform( + QgsCoordinateReferenceSystem.fromEpsgId(4326), + QgsCoordinateReferenceSystem.fromEpsgId(3857), + ) + ) p.addMapLayers([vl]) - self.assertTrue(vl.transformContext().hasTransform(QgsCoordinateReferenceSystem.fromEpsgId(4326), QgsCoordinateReferenceSystem.fromEpsgId(3857))) + self.assertTrue( + vl.transformContext().hasTransform( + QgsCoordinateReferenceSystem.fromEpsgId(4326), + QgsCoordinateReferenceSystem.fromEpsgId(3857), + ) + ) def testTransformContextIsSyncedFromProject(self): """Test that when a layer is synced when project context changes""" vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk', - 'test', 'memory') - self.assertFalse(vl.transformContext().hasTransform(QgsCoordinateReferenceSystem.fromEpsgId(4326), QgsCoordinateReferenceSystem.fromEpsgId(3857))) + "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk", + "test", + "memory", + ) + self.assertFalse( + vl.transformContext().hasTransform( + QgsCoordinateReferenceSystem.fromEpsgId(4326), + QgsCoordinateReferenceSystem.fromEpsgId(3857), + ) + ) p = QgsProject() - self.assertFalse(p.transformContext().hasTransform(QgsCoordinateReferenceSystem.fromEpsgId(4326), QgsCoordinateReferenceSystem.fromEpsgId(3857))) + self.assertFalse( + p.transformContext().hasTransform( + QgsCoordinateReferenceSystem.fromEpsgId(4326), + QgsCoordinateReferenceSystem.fromEpsgId(3857), + ) + ) p.setTransformContext(self.ctx) - self.assertTrue(p.transformContext().hasTransform(QgsCoordinateReferenceSystem.fromEpsgId(4326), QgsCoordinateReferenceSystem.fromEpsgId(3857))) + self.assertTrue( + p.transformContext().hasTransform( + QgsCoordinateReferenceSystem.fromEpsgId(4326), + QgsCoordinateReferenceSystem.fromEpsgId(3857), + ) + ) p.addMapLayers([vl]) - self.assertTrue(vl.transformContext().hasTransform(QgsCoordinateReferenceSystem.fromEpsgId(4326), QgsCoordinateReferenceSystem.fromEpsgId(3857))) + self.assertTrue( + vl.transformContext().hasTransform( + QgsCoordinateReferenceSystem.fromEpsgId(4326), + QgsCoordinateReferenceSystem.fromEpsgId(3857), + ) + ) # Now change the project context tc2 = QgsCoordinateTransformContext() p.setTransformContext(tc2) - self.assertFalse(p.transformContext().hasTransform(QgsCoordinateReferenceSystem.fromEpsgId(4326), QgsCoordinateReferenceSystem.fromEpsgId(3857))) - self.assertFalse(vl.transformContext().hasTransform(QgsCoordinateReferenceSystem.fromEpsgId(4326), QgsCoordinateReferenceSystem.fromEpsgId(3857))) + self.assertFalse( + p.transformContext().hasTransform( + QgsCoordinateReferenceSystem.fromEpsgId(4326), + QgsCoordinateReferenceSystem.fromEpsgId(3857), + ) + ) + self.assertFalse( + vl.transformContext().hasTransform( + QgsCoordinateReferenceSystem.fromEpsgId(4326), + QgsCoordinateReferenceSystem.fromEpsgId(3857), + ) + ) p.setTransformContext(self.ctx) - self.assertTrue(p.transformContext().hasTransform(QgsCoordinateReferenceSystem.fromEpsgId(4326), QgsCoordinateReferenceSystem.fromEpsgId(3857))) - self.assertTrue(vl.transformContext().hasTransform(QgsCoordinateReferenceSystem.fromEpsgId(4326), QgsCoordinateReferenceSystem.fromEpsgId(3857))) + self.assertTrue( + p.transformContext().hasTransform( + QgsCoordinateReferenceSystem.fromEpsgId(4326), + QgsCoordinateReferenceSystem.fromEpsgId(3857), + ) + ) + self.assertTrue( + vl.transformContext().hasTransform( + QgsCoordinateReferenceSystem.fromEpsgId(4326), + QgsCoordinateReferenceSystem.fromEpsgId(3857), + ) + ) def testDeletedFeaturesAreNotSelected(self): """Test that when features are deleted are also removed from selected before - featuresDeleted is emitted""" + featuresDeleted is emitted""" - layer = QgsVectorLayer("point?crs=epsg:4326&field=id:integer", "Scratch point layer", "memory") + layer = QgsVectorLayer( + "point?crs=epsg:4326&field=id:integer", "Scratch point layer", "memory" + ) layer.startEditing() layer.addFeature(QgsFeature(layer.fields())) layer.commitChanges() @@ -4150,7 +5079,9 @@ def testDeletedFeaturesAreNotSelected(self): def onFeaturesDeleted(deleted_fids): selected = layer.selectedFeatureIds() for fid in selected: - test_errors.append(f'Feature with id {fid} was deleted but is still selected') + test_errors.append( + f"Feature with id {fid} was deleted but is still selected" + ) layer.featuresDeleted.connect(onFeaturesDeleted) @@ -4171,17 +5102,22 @@ def testCommitChangesReportsDeletedFeatureIDs(self): temp_fids = [] def onFeaturesDeleted(deleted_fids): - self.assertEqual(len(deleted_fids), len(temp_fids), - msg=f'featuresDeleted returned {len(deleted_fids)} instead of 2 deleted feature IDs: ' - f'{deleted_fids}') + self.assertEqual( + len(deleted_fids), + len(temp_fids), + msg=f"featuresDeleted returned {len(deleted_fids)} instead of 2 deleted feature IDs: " + f"{deleted_fids}", + ) for d in deleted_fids: self.assertIn(d, temp_fids) - layer = QgsVectorLayer("point?crs=epsg:4326&field=name:string", "Scratch point layer", "memory") + layer = QgsVectorLayer( + "point?crs=epsg:4326&field=name:string", "Scratch point layer", "memory" + ) layer.featuresDeleted.connect(onFeaturesDeleted) layer.startEditing() - layer.beginEditCommand('add 2 features') + layer.beginEditCommand("add 2 features") layer.addFeature(QgsFeature(layer.fields())) layer.addFeature(QgsFeature(layer.fields())) layer.endEditCommand() @@ -4193,36 +5129,36 @@ def testSubsetStringInvalidLayer(self): """ Test that subset strings can be set on invalid layers, and retrieved later... """ - vl = QgsVectorLayer( - 'nope', - 'test', 'no') + vl = QgsVectorLayer("nope", "test", "no") self.assertFalse(vl.isValid()) self.assertIsNone(vl.dataProvider()) - vl.setSubsetString('xxxxxxxxx') - self.assertEqual(vl.subsetString(), 'xxxxxxxxx') + vl.setSubsetString("xxxxxxxxx") + self.assertEqual(vl.subsetString(), "xxxxxxxxx") # invalid layer subset strings must be persisted via xml doc = QDomDocument("testdoc") elem = doc.createElement("maplayer") self.assertTrue(vl.writeXml(elem, doc, QgsReadWriteContext())) - vl2 = QgsVectorLayer( - 'nope', - 'test', 'no') + vl2 = QgsVectorLayer("nope", "test", "no") vl2.readXml(elem, QgsReadWriteContext()) - self.assertEqual(vl2.subsetString(), 'xxxxxxxxx') + self.assertEqual(vl2.subsetString(), "xxxxxxxxx") def testLayerTypeFlags(self): """Basic API test, DB providers that support query layers should test the flag individually""" - layer = QgsVectorLayer("point?crs=epsg:4326&field=name:string", "Scratch point layer", "memory") + layer = QgsVectorLayer( + "point?crs=epsg:4326&field=name:string", "Scratch point layer", "memory" + ) self.assertEqual(layer.vectorLayerTypeFlags(), Qgis.VectorLayerTypeFlags()) def test_renderer_with_animated_symbol(self): """ Test that setting a renderer with an animated symbol leads to redraw signals on the correct interval """ - layer = QgsVectorLayer("point?crs=epsg:4326&field=name:string", "Scratch point layer", "memory") + layer = QgsVectorLayer( + "point?crs=epsg:4326&field=name:string", "Scratch point layer", "memory" + ) # renderer with an animated symbol marker_symbol = QgsMarkerSymbol() @@ -4266,34 +5202,43 @@ def testQmlDefaultTakesPrecedenceOverProviderDefaultRenderer(self): """ with tempfile.TemporaryDirectory() as temp: - shutil.copy(TEST_DATA_DIR + '/mapinfo/fill_styles.DAT', temp + '/fill_styles.DAT') - shutil.copy(TEST_DATA_DIR + '/mapinfo/fill_styles.ID', temp + '/fill_styles.ID') - shutil.copy(TEST_DATA_DIR + '/mapinfo/fill_styles.MAP', temp + '/fill_styles.MAP') - shutil.copy(TEST_DATA_DIR + '/mapinfo/fill_styles.TAB', temp + '/fill_styles.TAB') - - layer = QgsVectorLayer(temp + '/fill_styles.TAB', 'test', 'ogr') + shutil.copy( + TEST_DATA_DIR + "/mapinfo/fill_styles.DAT", temp + "/fill_styles.DAT" + ) + shutil.copy( + TEST_DATA_DIR + "/mapinfo/fill_styles.ID", temp + "/fill_styles.ID" + ) + shutil.copy( + TEST_DATA_DIR + "/mapinfo/fill_styles.MAP", temp + "/fill_styles.MAP" + ) + shutil.copy( + TEST_DATA_DIR + "/mapinfo/fill_styles.TAB", temp + "/fill_styles.TAB" + ) + + layer = QgsVectorLayer(temp + "/fill_styles.TAB", "test", "ogr") self.assertTrue(layer.isValid()) # should take a default embedded renderer from provider self.assertIsInstance(layer.renderer(), QgsEmbeddedSymbolRenderer) from qgis.core import QgsFillSymbol - symbol = QgsFillSymbol.createSimple({'color': '#ff00ff'}) + + symbol = QgsFillSymbol.createSimple({"color": "#ff00ff"}) layer.setRenderer(QgsSingleSymbolRenderer(symbol)) message, ok = layer.saveDefaultStyle() self.assertTrue(ok) del layer - layer = QgsVectorLayer(temp + '/fill_styles.TAB', 'test', 'ogr') + layer = QgsVectorLayer(temp + "/fill_styles.TAB", "test", "ogr") self.assertTrue(layer.isValid()) # now we should load the .qml default style instead of the provider default self.assertIsInstance(layer.renderer(), QgsSingleSymbolRenderer) - self.assertEqual(layer.renderer().symbol().color().name(), '#ff00ff') + self.assertEqual(layer.renderer().symbol().color().name(), "#ff00ff") # remove qml default - os.remove(temp + '/fill_styles.qml') + os.remove(temp + "/fill_styles.qml") del layer - layer = QgsVectorLayer(temp + '/fill_styles.TAB', 'test', 'ogr') + layer = QgsVectorLayer(temp + "/fill_styles.TAB", "test", "ogr") self.assertTrue(layer.isValid()) # should return to a default embedded renderer from provider @@ -4302,7 +5247,9 @@ def testQmlDefaultTakesPrecedenceOverProviderDefaultRenderer(self): def testSldTextSymbolizerExport(self): """Test issue GH #35561""" - vl = QgsVectorLayer('Point?crs=epsg:4326&field=name:string(0)', 'test', 'memory') + vl = QgsVectorLayer( + "Point?crs=epsg:4326&field=name:string(0)", "test", "memory" + ) text_format = QgsTextFormat() text_format.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) @@ -4326,19 +5273,19 @@ def testLayerWithoutProvider(self): layer.capabilitiesString() layer.dataComment() layer.displayField() - layer.setDisplayExpression('') + layer.setDisplayExpression("") layer.displayExpression() layer.dataProvider() layer.temporalProperties() - layer.setProviderEncoding('utf-8') + layer.setProviderEncoding("utf-8") layer.setCoordinateSystem() layer.addJoin(QgsVectorLayerJoinInfo()) - layer.removeJoin('id') + layer.removeJoin("id") layer.joinBuffer() layer.vectorJoins() layer.setDependencies([]) layer.dependencies() - idx = layer.addExpressionField('1+1', QgsField('foo')) + idx = layer.addExpressionField("1+1", QgsField("foo")) # layer.expressionField(idx) # layer.updateExpressionField(idx, '') # layer.removeExpressionField(idx) @@ -4346,7 +5293,7 @@ def testLayerWithoutProvider(self): layer.serverProperties() layer.selectedFeatureCount() layer.selectByRect(QgsRectangle()) - layer.selectByExpression('1') + layer.selectByExpression("1") layer.selectByIds([0]) layer.modifySelection([], []) layer.invertSelection() @@ -4377,14 +5324,14 @@ def testLayerWithoutProvider(self): elem = doc.createElement("maplayer") layer.writeXml(elem, doc, QgsReadWriteContext()) layer.readXml(elem, QgsReadWriteContext()) - layer.encodedSource('', QgsReadWriteContext()) - layer.decodedSource('', 'invalid_provider', QgsReadWriteContext()) + layer.encodedSource("", QgsReadWriteContext()) + layer.decodedSource("", "invalid_provider", QgsReadWriteContext()) layer.resolveReferences(QgsProject()) - layer.saveStyleToDatabase('name', 'description', False, 'uiFileContent') + layer.saveStyleToDatabase("name", "description", False, "uiFileContent") layer.listStylesInDatabase() - layer.getStyleFromDatabase('id') - layer.deleteStyleFromDatabase('id') - layer.loadNamedStyle('uri', False) + layer.getStyleFromDatabase("id") + layer.deleteStyleFromDatabase("id") + layer.loadNamedStyle("uri", False) layer.loadAuxiliaryLayer(QgsAuxiliaryStorage()) layer.setAuxiliaryLayer(None) layer.auxiliaryLayer() @@ -4440,12 +5387,12 @@ def testLayerWithoutProvider(self): layer.setReadOnly(False) layer.supportsEditing() layer.changeGeometry(0, QgsGeometry()) - layer.changeAttributeValue(0, 0, '') + layer.changeAttributeValue(0, 0, "") layer.changeAttributeValues(0, {}) - layer.addAttribute(QgsField('foo')) - layer.setFieldAlias(0, 'bar') + layer.addAttribute(QgsField("foo")) + layer.setFieldAlias(0, "bar") layer.removeFieldAlias(0) - layer.renameAttribute(0, 'bar') + layer.renameAttribute(0, "bar") layer.attributeAlias(0) layer.attributeDisplayName(0) layer.attributeAliases() @@ -4458,7 +5405,7 @@ def testLayerWithoutProvider(self): layer.rollBack() layer.referencingRelations(0) layer.editBuffer() - layer.beginEditCommand('foo') + layer.beginEditCommand("foo") layer.endEditCommand() layer.destroyEditCommand() layer.updateFields() @@ -4470,15 +5417,15 @@ def testLayerWithoutProvider(self): layer.removeFieldConstraint(0, QgsFieldConstraints.Constraint.ConstraintUnique) layer.constraintExpression(0) layer.constraintDescription(0) - layer.setConstraintExpression(0, '1') - layer.setEditorWidgetSetup(0, QgsEditorWidgetSetup('Hidden', {})) + layer.setConstraintExpression(0, "1") + layer.setEditorWidgetSetup(0, QgsEditorWidgetSetup("Hidden", {})) layer.editorWidgetSetup(0) layer.uniqueValues(0) layer.uniqueStringsMatching(0, None) layer.minimumValue(0) layer.maximumValue(0) layer.minimumAndMaximumValue(0) - layer.aggregate(QgsAggregateCalculator.Aggregate.Count, 'foo') + layer.aggregate(QgsAggregateCalculator.Aggregate.Count, "foo") layer.setFeatureBlendMode(QPainter.CompositionMode.CompositionMode_Screen) layer.featureBlendMode() layer.htmlMetadata() @@ -4488,7 +5435,7 @@ def testLayerWithoutProvider(self): layer.attributeTableConfig() layer.setAttributeTableConfig(layer.attributeTableConfig()) layer.mapTipTemplate() - layer.setMapTipTemplate('') + layer.setMapTipTemplate("") layer.createExpressionContext() layer.editFormConfig() layer.setEditFormConfig(layer.editFormConfig()) @@ -4509,13 +5456,13 @@ def testLayerWithoutProvider(self): # layer.accept(QgsStyleEntityVisitorInterface()) def testMapTips(self): - vl = QgsVectorLayer('Point?crs=epsg:3111&field=pk:integer', 'test', 'memory') + vl = QgsVectorLayer("Point?crs=epsg:3111&field=pk:integer", "test", "memory") self.assertEqual(vl.displayExpression(), '"pk"') # layer has map tips because display expression will be used self.assertTrue(vl.hasMapTips()) - vl.setMapTipTemplate('some template') - self.assertEqual(vl.mapTipTemplate(), 'some template') + vl.setMapTipTemplate("some template") + self.assertEqual(vl.mapTipTemplate(), "some template") self.assertTrue(vl.hasMapTips()) vl.setMapTipTemplate(None) @@ -4523,12 +5470,12 @@ def testMapTips(self): self.assertTrue(vl.hasMapTips()) # layer with no fields - vl = QgsVectorLayer('Point?crs=epsg:3111', 'test', 'memory') + vl = QgsVectorLayer("Point?crs=epsg:3111", "test", "memory") self.assertFalse(vl.displayExpression()) self.assertFalse(vl.hasMapTips()) - vl.setMapTipTemplate('some template') - self.assertEqual(vl.mapTipTemplate(), 'some template') + vl.setMapTipTemplate("some template") + self.assertEqual(vl.mapTipTemplate(), "some template") self.assertTrue(vl.hasMapTips()) vl.setMapTipTemplate(None) @@ -4536,7 +5483,11 @@ def testMapTips(self): self.assertFalse(vl.hasMapTips()) def test_split_policies(self): - vl = QgsVectorLayer('Point?crs=epsg:3111&field=field_default:integer&field=field_dupe:integer&field=field_unset:integer&field=field_ratio:integer', 'test', 'memory') + vl = QgsVectorLayer( + "Point?crs=epsg:3111&field=field_default:integer&field=field_dupe:integer&field=field_unset:integer&field=field_ratio:integer", + "test", + "memory", + ) self.assertTrue(vl.isValid()) with self.assertRaises(KeyError): @@ -4549,39 +5500,51 @@ def test_split_policies(self): vl.setFieldSplitPolicy(2, Qgis.FieldDomainSplitPolicy.UnsetField) vl.setFieldSplitPolicy(3, Qgis.FieldDomainSplitPolicy.GeometryRatio) - self.assertEqual(vl.fields()[0].splitPolicy(), - Qgis.FieldDomainSplitPolicy.DefaultValue) - self.assertEqual(vl.fields()[1].splitPolicy(), - Qgis.FieldDomainSplitPolicy.Duplicate) - self.assertEqual(vl.fields()[2].splitPolicy(), - Qgis.FieldDomainSplitPolicy.UnsetField) - self.assertEqual(vl.fields()[3].splitPolicy(), - Qgis.FieldDomainSplitPolicy.GeometryRatio) + self.assertEqual( + vl.fields()[0].splitPolicy(), Qgis.FieldDomainSplitPolicy.DefaultValue + ) + self.assertEqual( + vl.fields()[1].splitPolicy(), Qgis.FieldDomainSplitPolicy.Duplicate + ) + self.assertEqual( + vl.fields()[2].splitPolicy(), Qgis.FieldDomainSplitPolicy.UnsetField + ) + self.assertEqual( + vl.fields()[3].splitPolicy(), Qgis.FieldDomainSplitPolicy.GeometryRatio + ) p = QgsProject() p.addMapLayer(vl) # test saving and restoring split policies with tempfile.TemporaryDirectory() as temp: - self.assertTrue(p.write(temp + '/test.qgs')) + self.assertTrue(p.write(temp + "/test.qgs")) p2 = QgsProject() - self.assertTrue(p2.read(temp + '/test.qgs')) + self.assertTrue(p2.read(temp + "/test.qgs")) vl2 = list(p2.mapLayers().values())[0] self.assertEqual(vl2.name(), vl.name()) - self.assertEqual(vl2.fields()[0].splitPolicy(), - Qgis.FieldDomainSplitPolicy.DefaultValue) - self.assertEqual(vl2.fields()[1].splitPolicy(), - Qgis.FieldDomainSplitPolicy.Duplicate) - self.assertEqual(vl2.fields()[2].splitPolicy(), - Qgis.FieldDomainSplitPolicy.UnsetField) - self.assertEqual(vl2.fields()[3].splitPolicy(), - Qgis.FieldDomainSplitPolicy.GeometryRatio) + self.assertEqual( + vl2.fields()[0].splitPolicy(), Qgis.FieldDomainSplitPolicy.DefaultValue + ) + self.assertEqual( + vl2.fields()[1].splitPolicy(), Qgis.FieldDomainSplitPolicy.Duplicate + ) + self.assertEqual( + vl2.fields()[2].splitPolicy(), Qgis.FieldDomainSplitPolicy.UnsetField + ) + self.assertEqual( + vl2.fields()[3].splitPolicy(), Qgis.FieldDomainSplitPolicy.GeometryRatio + ) def test_duplicate_policies(self): - vl = QgsVectorLayer('Point?crs=epsg:3111&field=field_default:integer&field=field_dupe:integer&field=field_unset:integer', 'test', 'memory') + vl = QgsVectorLayer( + "Point?crs=epsg:3111&field=field_default:integer&field=field_dupe:integer&field=field_unset:integer", + "test", + "memory", + ) self.assertTrue(vl.isValid()) with self.assertRaises(KeyError): @@ -4593,127 +5556,179 @@ def test_duplicate_policies(self): vl.setFieldDuplicatePolicy(1, Qgis.FieldDuplicatePolicy.Duplicate) vl.setFieldDuplicatePolicy(2, Qgis.FieldDuplicatePolicy.UnsetField) - self.assertEqual(vl.fields()[0].duplicatePolicy(), - Qgis.FieldDuplicatePolicy.DefaultValue) - self.assertEqual(vl.fields()[1].duplicatePolicy(), - Qgis.FieldDuplicatePolicy.Duplicate) - self.assertEqual(vl.fields()[2].duplicatePolicy(), - Qgis.FieldDuplicatePolicy.UnsetField) + self.assertEqual( + vl.fields()[0].duplicatePolicy(), Qgis.FieldDuplicatePolicy.DefaultValue + ) + self.assertEqual( + vl.fields()[1].duplicatePolicy(), Qgis.FieldDuplicatePolicy.Duplicate + ) + self.assertEqual( + vl.fields()[2].duplicatePolicy(), Qgis.FieldDuplicatePolicy.UnsetField + ) p = QgsProject() p.addMapLayer(vl) # test saving and restoring split policies with tempfile.TemporaryDirectory() as temp: - self.assertTrue(p.write(temp + '/test.qgs')) + self.assertTrue(p.write(temp + "/test.qgs")) p2 = QgsProject() - self.assertTrue(p2.read(temp + '/test.qgs')) + self.assertTrue(p2.read(temp + "/test.qgs")) vl2 = list(p2.mapLayers().values())[0] self.assertEqual(vl2.name(), vl.name()) - self.assertEqual(vl2.fields()[0].duplicatePolicy(), - Qgis.FieldDuplicatePolicy.DefaultValue) - self.assertEqual(vl2.fields()[1].duplicatePolicy(), - Qgis.FieldDuplicatePolicy.Duplicate) - self.assertEqual(vl2.fields()[2].duplicatePolicy(), - Qgis.FieldDuplicatePolicy.UnsetField) + self.assertEqual( + vl2.fields()[0].duplicatePolicy(), + Qgis.FieldDuplicatePolicy.DefaultValue, + ) + self.assertEqual( + vl2.fields()[1].duplicatePolicy(), Qgis.FieldDuplicatePolicy.Duplicate + ) + self.assertEqual( + vl2.fields()[2].duplicatePolicy(), Qgis.FieldDuplicatePolicy.UnsetField + ) def test_selection_properties(self): vl = QgsVectorLayer( - 'Point?crs=epsg:3111&field=field_default:integer&field=field_dupe:integer&field=field_unset:integer&field=field_ratio:integer', - 'test', 'memory') + "Point?crs=epsg:3111&field=field_default:integer&field=field_dupe:integer&field=field_unset:integer&field=field_ratio:integer", + "test", + "memory", + ) self.assertTrue(vl.isValid()) self.assertFalse(vl.selectionProperties().selectionColor().isValid()) self.assertFalse(vl.selectionProperties().selectionSymbol()) - vl.selectionProperties().setSelectionColor( - QColor(255, 0, 0) - ) - self.assertEqual(vl.selectionProperties().selectionColor(), - QColor(255, 0, 0)) + vl.selectionProperties().setSelectionColor(QColor(255, 0, 0)) + self.assertEqual(vl.selectionProperties().selectionColor(), QColor(255, 0, 0)) vl.selectionProperties().setSelectionRenderingMode( - Qgis.SelectionRenderingMode.CustomColor) + Qgis.SelectionRenderingMode.CustomColor + ) p = QgsProject() p.addMapLayer(vl) # test saving and restoring with tempfile.TemporaryDirectory() as temp: - self.assertTrue(p.write(temp + '/test.qgs')) + self.assertTrue(p.write(temp + "/test.qgs")) p2 = QgsProject() - self.assertTrue(p2.read(temp + '/test.qgs')) + self.assertTrue(p2.read(temp + "/test.qgs")) vl2 = list(p2.mapLayers().values())[0] self.assertEqual(vl2.name(), vl.name()) - self.assertEqual(vl2.selectionProperties().selectionRenderingMode(), - Qgis.SelectionRenderingMode.CustomColor) + self.assertEqual( + vl2.selectionProperties().selectionRenderingMode(), + Qgis.SelectionRenderingMode.CustomColor, + ) - self.assertEqual(vl2.selectionProperties().selectionColor(), - QColor(255, 0, 0)) + self.assertEqual( + vl2.selectionProperties().selectionColor(), QColor(255, 0, 0) + ) selected_symbol = QgsMarkerSymbol() selected_symbol.setColor(QColor(25, 26, 27)) - vl.selectionProperties().setSelectionSymbol( - selected_symbol - ) + vl.selectionProperties().setSelectionSymbol(selected_symbol) with tempfile.TemporaryDirectory() as temp: - self.assertTrue(p.write(temp + '/test.qgs')) + self.assertTrue(p.write(temp + "/test.qgs")) p2 = QgsProject() - self.assertTrue(p2.read(temp + '/test.qgs')) + self.assertTrue(p2.read(temp + "/test.qgs")) vl2 = list(p2.mapLayers().values())[0] self.assertEqual(vl2.name(), vl.name()) - self.assertEqual(vl2.selectionProperties().selectionSymbol().color(), - QColor(25, 26, 27)) - self.assertEqual(vl2.selectionProperties().selectionColor(), - QColor(255, 0, 0)) + self.assertEqual( + vl2.selectionProperties().selectionSymbol().color(), QColor(25, 26, 27) + ) + self.assertEqual( + vl2.selectionProperties().selectionColor(), QColor(255, 0, 0) + ) def testConstraintsotSet(self): """Test that a NotSet constraint does not become a Hard constraint - when saving and loading a layer style, see issue GH #58431""" + when saving and loading a layer style, see issue GH #58431""" # Create a memory layer with unique constraints - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", "test_unique", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "test_unique", "memory" + ) self.assertTrue(layer.isValid()) # Se not constraints on fldtxt - layer.setFieldConstraint(0, QgsFieldConstraints.Constraint.ConstraintNotNull, QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft) - layer.setFieldConstraint(0, QgsFieldConstraints.Constraint.ConstraintUnique, QgsFieldConstraints.ConstraintStrength.ConstraintStrengthNotSet) + layer.setFieldConstraint( + 0, + QgsFieldConstraints.Constraint.ConstraintNotNull, + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft, + ) + layer.setFieldConstraint( + 0, + QgsFieldConstraints.Constraint.ConstraintUnique, + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthNotSet, + ) # Check constraints at the field level field = layer.fields().at(0) constraints = field.constraints() - self.assertEqual(constraints.constraintStrength(QgsFieldConstraints.Constraint.ConstraintNotNull), QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft) - self.assertEqual(constraints.constraintStrength(QgsFieldConstraints.Constraint.ConstraintUnique), QgsFieldConstraints.ConstraintStrength.ConstraintStrengthNotSet) + self.assertEqual( + constraints.constraintStrength( + QgsFieldConstraints.Constraint.ConstraintNotNull + ), + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft, + ) + self.assertEqual( + constraints.constraintStrength( + QgsFieldConstraints.Constraint.ConstraintUnique + ), + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthNotSet, + ) # Check constraints at the layer level constraints = layer.fieldConstraintsAndStrength(0) - self.assertEqual(constraints[QgsFieldConstraints.Constraint.ConstraintNotNull], QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft) - self.assertEqual(constraints[QgsFieldConstraints.Constraint.ConstraintUnique], QgsFieldConstraints.ConstraintStrength.ConstraintStrengthNotSet) + self.assertEqual( + constraints[QgsFieldConstraints.Constraint.ConstraintNotNull], + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft, + ) + self.assertEqual( + constraints[QgsFieldConstraints.Constraint.ConstraintUnique], + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthNotSet, + ) # Export the style to QML and reload it style = QgsMapLayerStyle() - temp_file = tempfile.mktemp(suffix='.qml') + temp_file = tempfile.mktemp(suffix=".qml") layer.saveNamedStyle(temp_file) layer.loadNamedStyle(temp_file) # Check constraints at the field level field = layer.fields().at(0) constraints = field.constraints() - self.assertEqual(constraints.constraintStrength(QgsFieldConstraints.Constraint.ConstraintNotNull), QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft) - self.assertEqual(constraints.constraintStrength(QgsFieldConstraints.Constraint.ConstraintUnique), QgsFieldConstraints.ConstraintStrength.ConstraintStrengthNotSet) + self.assertEqual( + constraints.constraintStrength( + QgsFieldConstraints.Constraint.ConstraintNotNull + ), + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft, + ) + self.assertEqual( + constraints.constraintStrength( + QgsFieldConstraints.Constraint.ConstraintUnique + ), + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthNotSet, + ) # Check constraints at the layer level constraints = layer.fieldConstraintsAndStrength(0) - self.assertEqual(constraints[QgsFieldConstraints.Constraint.ConstraintNotNull], QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft) - self.assertEqual(constraints[QgsFieldConstraints.Constraint.ConstraintUnique], QgsFieldConstraints.ConstraintStrength.ConstraintStrengthNotSet) + self.assertEqual( + constraints[QgsFieldConstraints.Constraint.ConstraintNotNull], + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft, + ) + self.assertEqual( + constraints[QgsFieldConstraints.Constraint.ConstraintUnique], + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthNotSet, + ) # TODO: @@ -4722,5 +5737,5 @@ def testConstraintsotSet(self): # - import -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorlayer_namedstyle.py b/tests/src/python/test_qgsvectorlayer_namedstyle.py index 767b1efb5673..138d358e7ae9 100644 --- a/tests/src/python/test_qgsvectorlayer_namedstyle.py +++ b/tests/src/python/test_qgsvectorlayer_namedstyle.py @@ -6,9 +6,10 @@ (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '22/01/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "22/01/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtXml import QDomDocument from qgis.core import QgsMapLayer, QgsReadWriteContext, QgsVectorLayer @@ -25,9 +26,19 @@ def testLoadWriteRenderingScaleVisibility(self): vl.setMinimumScale(125.0) vl.setMaximumScale(1.25) style = QDomDocument() - style.setContent("") + style.setContent( + "" + ) node = style.firstChild() - self.assertTrue(vl.writeStyle(node, style, "Error writing style", QgsReadWriteContext(), QgsMapLayer.StyleCategory.Rendering)) + self.assertTrue( + vl.writeStyle( + node, + style, + "Error writing style", + QgsReadWriteContext(), + QgsMapLayer.StyleCategory.Rendering, + ) + ) style_content = style.toString() del vl @@ -37,11 +48,18 @@ def testLoadWriteRenderingScaleVisibility(self): self.assertFalse(vl2.hasScaleBasedVisibility()) style2 = QDomDocument() style2.setContent(style_content) - self.assertTrue(vl2.readStyle(style.namedItem('qgis'), "Error reading style", QgsReadWriteContext(), QgsMapLayer.StyleCategory.Rendering)) + self.assertTrue( + vl2.readStyle( + style.namedItem("qgis"), + "Error reading style", + QgsReadWriteContext(), + QgsMapLayer.StyleCategory.Rendering, + ) + ) self.assertTrue(vl2.hasScaleBasedVisibility()) self.assertEqual(vl2.minimumScale(), 125.0) self.assertEqual(vl2.maximumScale(), 1.25) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorlayercache.py b/tests/src/python/test_qgsvectorlayercache.py index dab6b2d92b67..21ed6bd53067 100644 --- a/tests/src/python/test_qgsvectorlayercache.py +++ b/tests/src/python/test_qgsvectorlayercache.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '08/06/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "08/06/2017" +__copyright__ = "Copyright 2017, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, QTime from qgis.core import ( @@ -35,65 +36,107 @@ def getSource(cls): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestQgsVectorLayerCache, cls).setUpClass() + super().setUpClass() # Create test layer for FeatureSourceTestCase cls.vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk', - 'test', 'memory') - assert (cls.vl.isValid()) + "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk", + "test", + "memory", + ) + assert cls.vl.isValid() f1 = QgsFeature(5) - f1.setAttributes([5, -200, NULL, 'NuLl', '5', QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), QDate(2020, 5, 2), QTime(12, 13, 1)]) - f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)')) + f1.setAttributes( + [ + 5, + -200, + NULL, + "NuLl", + "5", + QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), + QDate(2020, 5, 2), + QTime(12, 13, 1), + ] + ) + f1.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)")) f2 = QgsFeature(3) - f2.setAttributes([3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL]) + f2.setAttributes([3, 300, "Pear", "PEaR", "3", NULL, NULL, NULL]) f3 = QgsFeature(1) - f3.setAttributes([1, 100, 'Orange', 'oranGe', '1', QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), QDate(2020, 5, 3), QTime(12, 13, 14)]) - f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)')) + f3.setAttributes( + [ + 1, + 100, + "Orange", + "oranGe", + "1", + QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), + QDate(2020, 5, 3), + QTime(12, 13, 14), + ] + ) + f3.setGeometry(QgsGeometry.fromWkt("Point (-70.332 66.33)")) f4 = QgsFeature(2) - f4.setAttributes([2, 200, 'Apple', 'Apple', '2', QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), QDate(2020, 5, 4), QTime(12, 14, 14)]) - f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)')) + f4.setAttributes( + [ + 2, + 200, + "Apple", + "Apple", + "2", + QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), + QDate(2020, 5, 4), + QTime(12, 14, 14), + ] + ) + f4.setGeometry(QgsGeometry.fromWkt("Point (-68.2 70.8)")) f5 = QgsFeature(4) - f5.setAttributes([4, 400, 'Honey', 'Honey', '4', QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), QDate(2021, 5, 4), QTime(13, 13, 14)]) - f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)')) + f5.setAttributes( + [ + 4, + 400, + "Honey", + "Honey", + "4", + QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), + QDate(2021, 5, 4), + QTime(13, 13, 14), + ] + ) + f5.setGeometry(QgsGeometry.fromWkt("Point (-65.32 78.3)")) assert cls.vl.dataProvider().addFeatures([f1, f2, f3, f4, f5]) cls.source = QgsVectorLayerCache(cls.vl, 100) def testGetFeaturesSubsetAttributes2(self): - """ Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return + """Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass def testGetFeaturesNoGeometry(self): - """ Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return + """Override and skip this QgsFeatureSource test. We are using a memory provider, and it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass def testUniqueValues(self): - """ Skip unique values test - not implemented by the cache (yet) - """ + """Skip unique values test - not implemented by the cache (yet)""" pass def testMinimumValue(self): - """ Skip min values test - not implemented by the cache (yet) - """ + """Skip min values test - not implemented by the cache (yet)""" pass def testMaximumValue(self): - """ Skip max values test - not implemented by the cache (yet) - """ + """Skip max values test - not implemented by the cache (yet)""" pass def testAllFeatureIds(self): - """ Skip allFeatureIds test - not implemented by the cache (yet) - """ + """Skip allFeatureIds test - not implemented by the cache (yet)""" pass def testOpenIteratorAfterSourceRemoval(self): @@ -103,5 +146,5 @@ def testOpenIteratorAfterSourceRemoval(self): pass -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorlayereditbuffer.py b/tests/src/python/test_qgsvectorlayereditbuffer.py index 51ddc5980cd6..9944664d98aa 100644 --- a/tests/src/python/test_qgsvectorlayereditbuffer.py +++ b/tests/src/python/test_qgsvectorlayereditbuffer.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '15/07/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "15/07/2016" +__copyright__ = "Copyright 2016, The QGIS Project" import os @@ -31,15 +32,17 @@ def createEmptyLayer(): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) assert layer.isValid() return layer def createLayerWithOnePoint(): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) pr = layer.dataProvider() f = QgsFeature() f.setAttributes(["test", 123]) @@ -50,8 +53,9 @@ def createLayerWithOnePoint(): def createEmptyLinestringLayer(): - layer = QgsVectorLayer("Linestring?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Linestring?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) assert layer.isValid() return layer @@ -83,14 +87,17 @@ def testAddFeatures(self): # test contents of buffer added = layer.editBuffer().addedFeatures() new_feature_ids = list(added.keys()) - self.assertEqual(added[new_feature_ids[0]]['fldtxt'], 'test2') - self.assertEqual(added[new_feature_ids[0]]['fldint'], 246) - self.assertEqual(added[new_feature_ids[1]]['fldtxt'], 'test') - self.assertEqual(added[new_feature_ids[1]]['fldint'], 123) + self.assertEqual(added[new_feature_ids[0]]["fldtxt"], "test2") + self.assertEqual(added[new_feature_ids[0]]["fldint"], 246) + self.assertEqual(added[new_feature_ids[1]]["fldtxt"], "test") + self.assertEqual(added[new_feature_ids[1]]["fldint"], 123) self.assertTrue(layer.editBuffer().isFeatureAdded(new_feature_ids[0])) self.assertTrue(layer.editBuffer().isFeatureAdded(new_feature_ids[1])) - self.assertCountEqual(layer.editBuffer().allAddedOrEditedFeatures(), [new_feature_ids[0], new_feature_ids[1]]) + self.assertCountEqual( + layer.editBuffer().allAddedOrEditedFeatures(), + [new_feature_ids[0], new_feature_ids[1]], + ) # check if error in case adding not adaptable geometry # eg. a Multiline in a Line @@ -137,14 +144,17 @@ def testAddMultipleFeatures(self): # test contents of buffer added = layer.editBuffer().addedFeatures() new_feature_ids = list(added.keys()) - self.assertEqual(added[new_feature_ids[0]]['fldtxt'], 'test2') - self.assertEqual(added[new_feature_ids[0]]['fldint'], 246) - self.assertEqual(added[new_feature_ids[1]]['fldtxt'], 'test') - self.assertEqual(added[new_feature_ids[1]]['fldint'], 123) + self.assertEqual(added[new_feature_ids[0]]["fldtxt"], "test2") + self.assertEqual(added[new_feature_ids[0]]["fldint"], 246) + self.assertEqual(added[new_feature_ids[1]]["fldtxt"], "test") + self.assertEqual(added[new_feature_ids[1]]["fldint"], 123) self.assertTrue(layer.editBuffer().isFeatureAdded(new_feature_ids[0])) self.assertTrue(layer.editBuffer().isFeatureAdded(new_feature_ids[1])) - self.assertCountEqual(layer.editBuffer().allAddedOrEditedFeatures(), [new_feature_ids[0], new_feature_ids[1]]) + self.assertCountEqual( + layer.editBuffer().allAddedOrEditedFeatures(), + [new_feature_ids[0], new_feature_ids[1]], + ) def testDeleteFeatures(self): # test deleting features from an edit buffer @@ -248,11 +258,11 @@ def testChangeAttributeValues(self): self.assertEqual(layer.editBuffer().allAddedOrEditedFeatures(), []) # change attribute values - layer.changeAttributeValue(1, 0, 'a') + layer.changeAttributeValue(1, 0, "a") # test contents of buffer self.assertEqual(list(layer.editBuffer().changedAttributeValues().keys()), [1]) - self.assertEqual(layer.editBuffer().changedAttributeValues()[1], {0: 'a'}) + self.assertEqual(layer.editBuffer().changedAttributeValues()[1], {0: "a"}) self.assertTrue(layer.editBuffer().isFeatureAttributesChanged(1)) self.assertFalse(layer.editBuffer().isFeatureAttributesChanged(2)) self.assertEqual(layer.editBuffer().allAddedOrEditedFeatures(), [1]) @@ -260,8 +270,10 @@ def testChangeAttributeValues(self): layer.changeAttributeValue(2, 1, 5) # test contents of buffer - self.assertEqual(set(layer.editBuffer().changedAttributeValues().keys()), {1, 2}) - self.assertEqual(layer.editBuffer().changedAttributeValues()[1], {0: 'a'}) + self.assertEqual( + set(layer.editBuffer().changedAttributeValues().keys()), {1, 2} + ) + self.assertEqual(layer.editBuffer().changedAttributeValues()[1], {0: "a"}) self.assertEqual(layer.editBuffer().changedAttributeValues()[2], {1: 5}) self.assertTrue(layer.editBuffer().isFeatureAttributesChanged(1)) self.assertTrue(layer.editBuffer().isFeatureAttributesChanged(2)) @@ -309,7 +321,9 @@ def testChangeGeometry(self): self.assertEqual(layer.getFeature(2).geometry().constGet().x(), 2) # apply second change to same feature - layer.beginEditCommand('second change') # need to use an edit command to avoid the two geometry changes being merged + layer.beginEditCommand( + "second change" + ) # need to use an edit command to avoid the two geometry changes being merged layer.changeGeometry(1, QgsGeometry.fromPointXY(QgsPointXY(100, 200))) layer.endEditCommand() @@ -402,17 +416,17 @@ def testAddAttribute(self): self.assertEqual(layer.editBuffer().addedAttributes(), []) # add attribute - layer.addAttribute(QgsField('new1', QVariant.String)) + layer.addAttribute(QgsField("new1", QVariant.String)) # test contents of buffer - self.assertEqual(layer.editBuffer().addedAttributes()[0].name(), 'new1') + self.assertEqual(layer.editBuffer().addedAttributes()[0].name(), "new1") # add another attribute - layer.addAttribute(QgsField('new2', QVariant.String)) + layer.addAttribute(QgsField("new2", QVariant.String)) # test contents of buffer - self.assertEqual(layer.editBuffer().addedAttributes()[0].name(), 'new1') - self.assertEqual(layer.editBuffer().addedAttributes()[1].name(), 'new2') + self.assertEqual(layer.editBuffer().addedAttributes()[0].name(), "new1") + self.assertEqual(layer.editBuffer().addedAttributes()[1].name(), "new2") def testTransactionGroup(self): """Test that the buffer works the same when used in transaction and when not""" @@ -434,19 +448,28 @@ def _check_feature(wkt): f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.geometry().asWkt().upper(), wkt) - ml = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer&field=int2:integer', 'test', 'memory') + ml = QgsVectorLayer( + "Point?crs=epsg:4326&field=int:integer&field=int2:integer", + "test", + "memory", + ) self.assertTrue(ml.isValid()) d = QTemporaryDir() options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'GPKG' - options.layerName = 'layer_a' - err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3(ml, os.path.join(d.path(), 'transaction_test.gpkg'), QgsCoordinateTransformContext(), options) + options.driverName = "GPKG" + options.layerName = "layer_a" + err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3( + ml, + os.path.join(d.path(), "transaction_test.gpkg"), + QgsCoordinateTransformContext(), + options, + ) self.assertEqual(err, QgsVectorFileWriter.WriterError.NoError) self.assertTrue(os.path.isfile(newFileName)) - layer_a = QgsVectorLayer(newFileName + '|layername=layer_a') + layer_a = QgsVectorLayer(newFileName + "|layername=layer_a") self.assertTrue(layer_a.isValid()) @@ -461,11 +484,11 @@ def _check_feature(wkt): buffer = layer_a.editBuffer() f = QgsFeature(layer_a.fields()) - f.setAttribute('int', 123) - f.setGeometry(QgsGeometry.fromWkt('point(7 45)')) + f.setAttribute("int", 123) + f.setGeometry(QgsGeometry.fromWkt("point(7 45)")) self.assertTrue(layer_a.addFeatures([f])) - _check_feature('POINT (7 45)') + _check_feature("POINT (7 45)") # Need to fetch the feature because its ID is NULL (-9223372036854775808) f = next(layer_a.getFeatures()) @@ -476,7 +499,7 @@ def _check_feature(wkt): layer_a.undoStack().redo() self.assertEqual(len(buffer.addedFeatures()), 1) f = list(buffer.addedFeatures().values())[0] - self.assertEqual(f.attribute('int'), 123) + self.assertEqual(f.attribute("int"), 123) # Now change attribute self.assertEqual(buffer.changedAttributeValues(), {}) @@ -489,7 +512,7 @@ def _check_feature(wkt): # This is surprising: because it was a new feature it has been changed directly self.assertEqual(buffer.changedAttributeValues(), {}) f = list(buffer.addedFeatures().values())[0] - self.assertEqual(f.attribute('int'), 321) + self.assertEqual(f.attribute("int"), 321) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() @@ -497,9 +520,9 @@ def _check_feature(wkt): self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 123]) self.assertEqual(buffer.changedAttributeValues(), {}) f = list(buffer.addedFeatures().values())[0] - self.assertEqual(f.attribute('int'), 123) + self.assertEqual(f.attribute("int"), 123) f = next(layer_a.getFeatures()) - self.assertEqual(f.attribute('int'), 123) + self.assertEqual(f.attribute("int"), 123) # Change multiple attributes spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) @@ -517,8 +540,8 @@ def _check_feature(wkt): if transactionMode != Qgis.TransactionMode.AutomaticGroups: layer_a.undoStack().undo() f = next(layer_a.getFeatures()) - self.assertEqual(f.attribute('int'), 123) - self.assertEqual(f.attribute('int2'), None) + self.assertEqual(f.attribute("int"), 123) + self.assertEqual(f.attribute("int2"), None) self.assertEqual(len(spy_attribute_changed), 2) if transactionMode == Qgis.TransactionMode.AutomaticGroups: self.assertEqual(spy_attribute_changed[1], [f.id(), 2, None]) @@ -530,29 +553,38 @@ def _check_feature(wkt): # Change geometry f = next(layer_a.getFeatures()) spy_geometry_changed = QSignalSpy(layer_a.geometryChanged) - self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) + self.assertTrue( + layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt("point(9 43)")) + ) self.assertTrue(len(spy_geometry_changed), 1) self.assertEqual(spy_geometry_changed[0][0], f.id()) - self.assertEqual(spy_geometry_changed[0][1].asWkt(), QgsGeometry.fromWkt('point(9 43)').asWkt()) + self.assertEqual( + spy_geometry_changed[0][1].asWkt(), + QgsGeometry.fromWkt("point(9 43)").asWkt(), + ) - _check_feature('POINT (9 43)') + _check_feature("POINT (9 43)") self.assertEqual(buffer.changedGeometries(), {}) layer_a.undoStack().undo() - _check_feature('POINT (7 45)') + _check_feature("POINT (7 45)") self.assertEqual(buffer.changedGeometries(), {}) - self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) - _check_feature('POINT (9 43)') + self.assertTrue( + layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt("point(9 43)")) + ) + _check_feature("POINT (9 43)") - self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(10 44)'))) - _check_feature('POINT (10 44)') + self.assertTrue( + layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt("point(10 44)")) + ) + _check_feature("POINT (10 44)") # This is another surprise: geometry edits get collapsed into a single # one because they have the same hardcoded id layer_a.undoStack().undo() - _check_feature('POINT (7 45)') + _check_feature("POINT (7 45)") self.assertTrue(layer_a.commitChanges()) @@ -562,8 +594,8 @@ def _check_feature(wkt): # Get the feature f = next(layer_a.getFeatures()) self.assertTrue(f.isValid()) - self.assertEqual(f.attribute('int'), 123) - self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)') + self.assertEqual(f.attribute("int"), 123) + self.assertEqual(f.geometry().asWkt().upper(), "POINT (7 45)") # Change single attribute self.assertTrue(layer_a.startEditing()) @@ -613,22 +645,32 @@ def _check_feature(wkt): # Change geometry spy_geometry_changed = QSignalSpy(layer_a.geometryChanged) - self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) + self.assertTrue( + layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt("point(9 43)")) + ) self.assertEqual(spy_geometry_changed[0][0], 1) - self.assertEqual(spy_geometry_changed[0][1].asWkt(), QgsGeometry.fromWkt('point(9 43)').asWkt()) + self.assertEqual( + spy_geometry_changed[0][1].asWkt(), + QgsGeometry.fromWkt("point(9 43)").asWkt(), + ) f = next(layer_a.getFeatures()) - self.assertEqual(f.geometry().asWkt().upper(), 'POINT (9 43)') - self.assertEqual(buffer.changedGeometries()[1].asWkt().upper(), 'POINT (9 43)') + self.assertEqual(f.geometry().asWkt().upper(), "POINT (9 43)") + self.assertEqual( + buffer.changedGeometries()[1].asWkt().upper(), "POINT (9 43)" + ) spy_geometry_changed = QSignalSpy(layer_a.geometryChanged) layer_a.undoStack().undo() self.assertEqual(spy_geometry_changed[0][0], 1) - self.assertEqual(spy_geometry_changed[0][1].asWkt(), QgsGeometry.fromWkt('point(7 45)').asWkt()) + self.assertEqual( + spy_geometry_changed[0][1].asWkt(), + QgsGeometry.fromWkt("point(7 45)").asWkt(), + ) self.assertEqual(buffer.changedGeometries(), {}) f = next(layer_a.getFeatures()) - self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)') + self.assertEqual(f.geometry().asWkt().upper(), "POINT (7 45)") self.assertEqual(buffer.changedGeometries(), {}) # Delete an existing feature @@ -646,10 +688,10 @@ def _check_feature(wkt): # Delete a new feature f = QgsFeature(layer_a.fields()) - f.setAttribute('int', 555) - f.setGeometry(QgsGeometry.fromWkt('point(8 46)')) + f.setAttribute("int", 555) + f.setGeometry(QgsGeometry.fromWkt("point(8 46)")) self.assertTrue(layer_a.addFeatures([f])) - f = [f for f in layer_a.getFeatures() if f.attribute('int') == 555][0] + f = [f for f in layer_a.getFeatures() if f.attribute("int") == 555][0] self.assertIn(f.id(), buffer.addedFeatures()) self.assertTrue(layer_a.deleteFeature(f.id())) self.assertNotIn(f.id(), buffer.addedFeatures()) @@ -661,7 +703,7 @@ def _check_feature(wkt): ########################################### # Add attribute - field = QgsField('attr1', QVariant.String) + field = QgsField("attr1", QVariant.String) self.assertTrue(layer_a.addAttribute(field)) self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), [field]) @@ -704,9 +746,11 @@ def _check_feature(wkt): # Rollback! self.assertTrue(layer_a.rollBack()) - self.assertIn('attr1', layer_a.dataProvider().fields().names()) - self.assertIn('attr1', layer_a.fields().names()) - self.assertEqual(layer_a.fields().names(), layer_a.dataProvider().fields().names()) + self.assertIn("attr1", layer_a.dataProvider().fields().names()) + self.assertIn("attr1", layer_a.fields().names()) + self.assertEqual( + layer_a.fields().names(), layer_a.dataProvider().fields().names() + ) attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) @@ -719,22 +763,24 @@ def _check_feature(wkt): # Rename attribute attr_idx = layer_a.fields().lookupField(field.name()) - self.assertEqual(layer_a.fields().lookupField('new_name'), -1) - self.assertTrue(layer_a.renameAttribute(attr_idx, 'new_name')) - self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx) + self.assertEqual(layer_a.fields().lookupField("new_name"), -1) + self.assertTrue(layer_a.renameAttribute(attr_idx, "new_name")) + self.assertEqual(layer_a.fields().lookupField("new_name"), attr_idx) layer_a.undoStack().undo() self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx) - self.assertEqual(layer_a.fields().lookupField('new_name'), -1) + self.assertEqual(layer_a.fields().lookupField("new_name"), -1) layer_a.undoStack().redo() - self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx) + self.assertEqual(layer_a.fields().lookupField("new_name"), attr_idx) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) ############################################# # Try hard to make this fail for transactions - if (transactionMode == Qgis.TransactionMode.AutomaticGroups - or transactionMode == Qgis.TransactionMode.BufferedGroups): + if ( + transactionMode == Qgis.TransactionMode.AutomaticGroups + or transactionMode == Qgis.TransactionMode.BufferedGroups + ): self.assertTrue(layer_a.commitChanges()) self.assertTrue(layer_a.startEditing()) f = next(layer_a.getFeatures()) @@ -761,7 +807,9 @@ def _check_feature(wkt): self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, 8 - i]) buffer = layer_a.editBuffer() - self.assertEqual(buffer.changedAttributeValues(), {f.id(): {2: 8 - i}}) + self.assertEqual( + buffer.changedAttributeValues(), {f.id(): {2: 8 - i}} + ) # Redo spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) @@ -779,7 +827,9 @@ def _check_feature(wkt): self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, 8 - i]) buffer = layer_a.editBuffer() - self.assertEqual(buffer.changedAttributeValues(), {f.id(): {2: 8 - i}}) + self.assertEqual( + buffer.changedAttributeValues(), {f.id(): {2: 8 - i}} + ) # Last check f = next(layer_a.getFeatures()) @@ -797,5 +847,5 @@ def _check_feature(wkt): _test(Qgis.TransactionMode.BufferedGroups) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorlayereditbuffergroup.py b/tests/src/python/test_qgsvectorlayereditbuffergroup.py index 89600c54d194..63e677df5c6d 100644 --- a/tests/src/python/test_qgsvectorlayereditbuffergroup.py +++ b/tests/src/python/test_qgsvectorlayereditbuffergroup.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Damiano Lombardi' -__date__ = '13/01/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Damiano Lombardi" +__date__ = "13/01/2022" +__copyright__ = "Copyright 2022, The QGIS Project" import os @@ -37,36 +38,50 @@ def tearDown(self): def testStartEditingCommitRollBack(self): - ml = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer&field=int2:integer', 'test', 'memory') + ml = QgsVectorLayer( + "Point?crs=epsg:4326&field=int:integer&field=int2:integer", "test", "memory" + ) self.assertTrue(ml.isValid()) # Layer A geopackage A d = QTemporaryDir() options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'GPKG' - options.layerName = 'layer_a' - err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3(ml, os.path.join(d.path(), 'test_EditBufferGroup_A.gpkg'), QgsCoordinateTransformContext(), options) + options.driverName = "GPKG" + options.layerName = "layer_a" + err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3( + ml, + os.path.join(d.path(), "test_EditBufferGroup_A.gpkg"), + QgsCoordinateTransformContext(), + options, + ) self.assertEqual(err, QgsVectorFileWriter.WriterError.NoError) self.assertTrue(os.path.isfile(newFileName)) - layer_a = QgsVectorLayer(newFileName + '|layername=layer_a') + layer_a = QgsVectorLayer(newFileName + "|layername=layer_a") self.assertTrue(layer_a.isValid()) # Layer B geopackage B - options.layerName = 'layer_b' - err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3(ml, os.path.join(d.path(), 'test_EditBufferGroup_B.gpkg'), QgsCoordinateTransformContext(), options) + options.layerName = "layer_b" + err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3( + ml, + os.path.join(d.path(), "test_EditBufferGroup_B.gpkg"), + QgsCoordinateTransformContext(), + options, + ) self.assertEqual(err, QgsVectorFileWriter.WriterError.NoError) self.assertTrue(os.path.isfile(newFileName)) - layer_b = QgsVectorLayer(newFileName + '|layername=layer_b') + layer_b = QgsVectorLayer(newFileName + "|layername=layer_b") self.assertTrue(layer_b.isValid()) # Layer C memory - layer_c = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer&field=int2:integer', 'test', 'memory') + layer_c = QgsVectorLayer( + "Point?crs=epsg:4326&field=int:integer&field=int2:integer", "test", "memory" + ) self.assertTrue(layer_c.isValid()) project = QgsProject() @@ -100,8 +115,8 @@ def testStartEditingCommitRollBack(self): self.assertTrue(editBufferGroup.isEditing()) f = QgsFeature(layer_a.fields()) - f.setAttribute('int', 123) - f.setGeometry(QgsGeometry.fromWkt('point(7 45)')) + f.setAttribute("int", 123) + f.setGeometry(QgsGeometry.fromWkt("point(7 45)")) self.assertTrue(layer_a.addFeatures([f])) self.assertEqual(len(editBufferGroup.modifiedLayers()), 1) self.assertIn(layer_a, editBufferGroup.modifiedLayers()) @@ -127,22 +142,36 @@ def testStartEditingCommitRollBack(self): def testSetBufferedGroupsAfterAutomaticGroups(self): - ml = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer&field=int2:integer', 'test', 'memory') + ml = QgsVectorLayer( + "Point?crs=epsg:4326&field=int:integer&field=int2:integer", "test", "memory" + ) # Load 2 layer from a geopackage d = QTemporaryDir() options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'GPKG' - options.layerName = 'layer_a' - err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3(ml, os.path.join(d.path(), 'test_EditBufferGroup.gpkg'), QgsCoordinateTransformContext(), options) - - options.layerName = 'layer_b' - options.actionOnExistingFile = QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteLayer - err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3(ml, os.path.join(d.path(), 'test_EditBufferGroup.gpkg'), QgsCoordinateTransformContext(), options) - - layer_a = QgsVectorLayer(newFileName + '|layername=layer_a') + options.driverName = "GPKG" + options.layerName = "layer_a" + err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3( + ml, + os.path.join(d.path(), "test_EditBufferGroup.gpkg"), + QgsCoordinateTransformContext(), + options, + ) + + options.layerName = "layer_b" + options.actionOnExistingFile = ( + QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteLayer + ) + err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3( + ml, + os.path.join(d.path(), "test_EditBufferGroup.gpkg"), + QgsCoordinateTransformContext(), + options, + ) + + layer_a = QgsVectorLayer(newFileName + "|layername=layer_a") self.assertTrue(layer_a.isValid()) - layer_b = QgsVectorLayer(newFileName + '|layername=layer_b') + layer_b = QgsVectorLayer(newFileName + "|layername=layer_b") self.assertTrue(layer_b.isValid()) project = QgsProject() @@ -158,25 +187,41 @@ def testSetBufferedGroupsAfterAutomaticGroups(self): def testReadOnlyLayers(self): - memoryLayer_a = QgsVectorLayer('Point?crs=epsg:4326&field=id:integer&field=id_b', 'test', 'memory') + memoryLayer_a = QgsVectorLayer( + "Point?crs=epsg:4326&field=id:integer&field=id_b", "test", "memory" + ) self.assertTrue(memoryLayer_a.isValid()) - memoryLayer_b = QgsVectorLayer('Point?crs=epsg:4326&field=id:integer', 'test', 'memory') + memoryLayer_b = QgsVectorLayer( + "Point?crs=epsg:4326&field=id:integer", "test", "memory" + ) self.assertTrue(memoryLayer_b.isValid()) # Load 2 layer from a geopackage d = QTemporaryDir() options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'GPKG' - options.layerName = 'layer_a' - err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3(memoryLayer_a, os.path.join(d.path(), 'test_EditBufferGroupReadOnly.gpkg'), QgsCoordinateTransformContext(), options) - - options.layerName = 'layer_b' - options.actionOnExistingFile = QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteLayer - err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3(memoryLayer_b, os.path.join(d.path(), 'test_EditBufferGroupReadOnly.gpkg'), QgsCoordinateTransformContext(), options) - - layer_a = QgsVectorLayer(newFileName + '|layername=layer_a') + options.driverName = "GPKG" + options.layerName = "layer_a" + err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3( + memoryLayer_a, + os.path.join(d.path(), "test_EditBufferGroupReadOnly.gpkg"), + QgsCoordinateTransformContext(), + options, + ) + + options.layerName = "layer_b" + options.actionOnExistingFile = ( + QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteLayer + ) + err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3( + memoryLayer_b, + os.path.join(d.path(), "test_EditBufferGroupReadOnly.gpkg"), + QgsCoordinateTransformContext(), + options, + ) + + layer_a = QgsVectorLayer(newFileName + "|layername=layer_a") self.assertTrue(layer_a.isValid()) - layer_b = QgsVectorLayer(newFileName + '|layername=layer_b') + layer_b = QgsVectorLayer(newFileName + "|layername=layer_b") self.assertTrue(layer_b.isValid()) layer_b.setReadOnly(True) @@ -185,8 +230,8 @@ def testReadOnlyLayers(self): relationContext = QgsRelationContext(project) relation = QgsRelation(relationContext) - relation.setId('relation') - relation.setName('Relation Number One') + relation.setId("relation") + relation.setName("Relation Number One") relation.setReferencingLayer(layer_a.id()) relation.setReferencedLayer(layer_b.id()) relation.addFieldPair("id_b", "id") @@ -203,9 +248,9 @@ def testReadOnlyLayers(self): self.assertTrue(editBufferGroup.isEditing()) f = QgsFeature(layer_a.fields()) - f.setAttribute('id', 123) - f.setAttribute('id_b', 1) - f.setGeometry(QgsGeometry.fromWkt('point(7 45)')) + f.setAttribute("id", 123) + f.setAttribute("id_b", 1) + f.setGeometry(QgsGeometry.fromWkt("point(7 45)")) self.assertTrue(layer_a.addFeatures([f])) self.assertEqual(len(editBufferGroup.modifiedLayers()), 1) self.assertIn(layer_a, editBufferGroup.modifiedLayers()) @@ -220,25 +265,41 @@ def testReadOnlyLayers(self): def testCircularRelations(self): - memoryLayer_a = QgsVectorLayer('Point?crs=epsg:4326&field=id:integer&field=id_b', 'test', 'memory') + memoryLayer_a = QgsVectorLayer( + "Point?crs=epsg:4326&field=id:integer&field=id_b", "test", "memory" + ) self.assertTrue(memoryLayer_a.isValid()) - memoryLayer_b = QgsVectorLayer('Point?crs=epsg:4326&field=id:integer&field=id_a', 'test', 'memory') + memoryLayer_b = QgsVectorLayer( + "Point?crs=epsg:4326&field=id:integer&field=id_a", "test", "memory" + ) self.assertTrue(memoryLayer_b.isValid()) # Load 2 layer from a geopackage d = QTemporaryDir() options = QgsVectorFileWriter.SaveVectorOptions() - options.driverName = 'GPKG' - options.layerName = 'layer_a' - err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3(memoryLayer_a, os.path.join(d.path(), 'test_EditBufferGroupCircularRelations.gpkg'), QgsCoordinateTransformContext(), options) - - options.layerName = 'layer_b' - options.actionOnExistingFile = QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteLayer - err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3(memoryLayer_b, os.path.join(d.path(), 'test_EditBufferGroupCircularRelations.gpkg'), QgsCoordinateTransformContext(), options) - - layer_a = QgsVectorLayer(newFileName + '|layername=layer_a') + options.driverName = "GPKG" + options.layerName = "layer_a" + err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3( + memoryLayer_a, + os.path.join(d.path(), "test_EditBufferGroupCircularRelations.gpkg"), + QgsCoordinateTransformContext(), + options, + ) + + options.layerName = "layer_b" + options.actionOnExistingFile = ( + QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteLayer + ) + err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3( + memoryLayer_b, + os.path.join(d.path(), "test_EditBufferGroupCircularRelations.gpkg"), + QgsCoordinateTransformContext(), + options, + ) + + layer_a = QgsVectorLayer(newFileName + "|layername=layer_a") self.assertTrue(layer_a.isValid()) - layer_b = QgsVectorLayer(newFileName + '|layername=layer_b') + layer_b = QgsVectorLayer(newFileName + "|layername=layer_b") self.assertTrue(layer_b.isValid()) project = QgsProject.instance() @@ -247,8 +308,8 @@ def testCircularRelations(self): relationContext = QgsRelationContext(project) relation_ab = QgsRelation(relationContext) - relation_ab.setId('relation_ab') - relation_ab.setName('Relation a b') + relation_ab.setId("relation_ab") + relation_ab.setName("Relation a b") relation_ab.setReferencingLayer(layer_a.id()) relation_ab.setReferencedLayer(layer_b.id()) relation_ab.addFieldPair("id_b", "id") @@ -257,8 +318,8 @@ def testCircularRelations(self): project.relationManager().addRelation(relation_ab) relation_ba = QgsRelation(relationContext) - relation_ba.setId('relation_ba') - relation_ba.setName('Relation b a') + relation_ba.setId("relation_ba") + relation_ba.setName("Relation b a") relation_ba.setReferencingLayer(layer_b.id()) relation_ba.setReferencedLayer(layer_a.id()) relation_ba.addFieldPair("id_a", "id") @@ -273,17 +334,17 @@ def testCircularRelations(self): self.assertTrue(editBufferGroup.isEditing()) f = QgsFeature(layer_a.fields()) - f.setAttribute('id', 123) - f.setAttribute('id_b', 1) - f.setGeometry(QgsGeometry.fromWkt('point(7 45)')) + f.setAttribute("id", 123) + f.setAttribute("id_b", 1) + f.setGeometry(QgsGeometry.fromWkt("point(7 45)")) self.assertTrue(layer_a.addFeatures([f])) self.assertEqual(len(editBufferGroup.modifiedLayers()), 1) self.assertIn(layer_a, editBufferGroup.modifiedLayers()) f = QgsFeature(layer_b.fields()) - f.setAttribute('id', 1) - f.setAttribute('id_a', 123) - f.setGeometry(QgsGeometry.fromWkt('point(8 46)')) + f.setAttribute("id", 1) + f.setAttribute("id_a", 123) + f.setGeometry(QgsGeometry.fromWkt("point(8 46)")) self.assertTrue(layer_b.addFeatures([f])) self.assertEqual(len(editBufferGroup.modifiedLayers()), 2) self.assertIn(layer_b, editBufferGroup.modifiedLayers()) @@ -299,5 +360,5 @@ def testCircularRelations(self): self.assertFalse(editBufferGroup.isEditing()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorlayereditutils.py b/tests/src/python/test_qgsvectorlayereditutils.py index a4c8a452d887..99af765f4374 100644 --- a/tests/src/python/test_qgsvectorlayereditutils.py +++ b/tests/src/python/test_qgsvectorlayereditutils.py @@ -8,9 +8,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Loïc Bartoletti' -__date__ = '18/10/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Loïc Bartoletti" +__date__ = "18/10/2022" +__copyright__ = "Copyright 2022, The QGIS Project" import os import tempfile @@ -35,7 +36,7 @@ QgsWkbTypes, QgsDefaultValue, QgsVectorLayerUtils, - QgsUnsetAttributeValue + QgsUnsetAttributeValue, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -44,8 +45,7 @@ def createEmptyLayer(geomType): - layer = QgsVectorLayer(geomType, - geomType.lower(), "memory") + layer = QgsVectorLayer(geomType, geomType.lower(), "memory") assert layer.isValid() return layer @@ -67,18 +67,26 @@ def testAddRing(self): pr = layer.dataProvider() f = QgsFeature(layer.fields(), 1) - f.setGeometry(QgsGeometry.fromWkt('POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))')) + f.setGeometry(QgsGeometry.fromWkt("POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))")) assert pr.addFeatures([f]) self.assertEqual(layer.featureCount(), 1) vle = QgsVectorLayerEditUtils(layer) - result = vle.addRing([QgsPointXY(1, 1), QgsPointXY(1, 2), QgsPointXY(2, 2), QgsPointXY(2, 1), QgsPointXY(1, 1)]) + result = vle.addRing( + [ + QgsPointXY(1, 1), + QgsPointXY(1, 2), + QgsPointXY(2, 2), + QgsPointXY(2, 1), + QgsPointXY(1, 1), + ] + ) self.assertEqual(Qgis.GeometryOperationResult.Success, result[0]) layer.commitChanges() self.assertEqual( layer.getFeature(1).geometry().asWkt(), - "Polygon ((0 0, 5 0, 5 5, 0 5, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1))" + "Polygon ((0 0, 5 0, 5 5, 0 5, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1))", ) def testAddRingOutside(self): @@ -88,18 +96,28 @@ def testAddRingOutside(self): pr = layer.dataProvider() f = QgsFeature(layer.fields(), 1) - f.setGeometry(QgsGeometry.fromWkt('POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))')) + f.setGeometry(QgsGeometry.fromWkt("POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))")) assert pr.addFeatures([f]) self.assertEqual(layer.featureCount(), 1) vle = QgsVectorLayerEditUtils(layer) - result = vle.addRing([QgsPointXY(-1, -1), QgsPointXY(-1, -2), QgsPointXY(-2, -2), QgsPointXY(-2, -1), QgsPointXY(-1, -1)]) - self.assertEqual(Qgis.GeometryOperationResult.AddRingNotInExistingFeature, result[0]) + result = vle.addRing( + [ + QgsPointXY(-1, -1), + QgsPointXY(-1, -2), + QgsPointXY(-2, -2), + QgsPointXY(-2, -1), + QgsPointXY(-1, -1), + ] + ) + self.assertEqual( + Qgis.GeometryOperationResult.AddRingNotInExistingFeature, result[0] + ) layer.commitChanges() self.assertEqual( layer.getFeature(1).geometry().asWkt(), - "Polygon ((0 0, 5 0, 5 5, 0 5, 0 0))" + "Polygon ((0 0, 5 0, 5 5, 0 5, 0 0))", ) def testAddRingOverlappedFeatures(self): @@ -110,25 +128,32 @@ def testAddRingOverlappedFeatures(self): pr = layer.dataProvider() f1 = QgsFeature(layer.fields(), 1) - f1.setGeometry(QgsGeometry.fromWkt('POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))')) + f1.setGeometry(QgsGeometry.fromWkt("POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))")) f2 = QgsFeature(layer.fields(), 1) - f2.setGeometry(QgsGeometry.fromWkt('POLYGON((2 2, 6 2, 6 6, 2 6, 2 2))')) + f2.setGeometry(QgsGeometry.fromWkt("POLYGON((2 2, 6 2, 6 6, 2 6, 2 2))")) assert pr.addFeatures([f1, f2]) self.assertEqual(layer.featureCount(), 2) vle = QgsVectorLayerEditUtils(layer) - result = vle.addRing([QgsPointXY(3, 3), QgsPointXY(3, 4), QgsPointXY(4, 4), QgsPointXY(4, 3), QgsPointXY(3, 3)]) - self.assertEqual(Qgis.GeometryOperationResult.Success, - result[0]) + result = vle.addRing( + [ + QgsPointXY(3, 3), + QgsPointXY(3, 4), + QgsPointXY(4, 4), + QgsPointXY(4, 3), + QgsPointXY(3, 3), + ] + ) + self.assertEqual(Qgis.GeometryOperationResult.Success, result[0]) layer.commitChanges() self.assertEqual( layer.getFeature(1).geometry().asWkt(), - "Polygon ((0 0, 5 0, 5 5, 0 5, 0 0),(3 3, 3 4, 4 4, 4 3, 3 3))" + "Polygon ((0 0, 5 0, 5 5, 0 5, 0 0),(3 3, 3 4, 4 4, 4 3, 3 3))", ) self.assertEqual( layer.getFeature(2).geometry().asWkt(), - "Polygon ((2 2, 6 2, 6 6, 2 6, 2 2))" + "Polygon ((2 2, 6 2, 6 6, 2 6, 2 2))", ) def testAddRingV2NotEditable(self): @@ -139,26 +164,36 @@ def testAddRingV2NotEditable(self): pr = layer.dataProvider() f1 = QgsFeature(layer.fields(), 1) - f1.setGeometry(QgsGeometry.fromWkt('POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))')) + f1.setGeometry(QgsGeometry.fromWkt("POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))")) f2 = QgsFeature(layer.fields(), 1) - f2.setGeometry(QgsGeometry.fromWkt('POLYGON((2 2, 6 2, 6 6, 2 6, 2 2))')) + f2.setGeometry(QgsGeometry.fromWkt("POLYGON((2 2, 6 2, 6 6, 2 6, 2 2))")) assert pr.addFeatures([f1, f2]) self.assertEqual(layer.featureCount(), 2) layer.commitChanges() vle = QgsVectorLayerEditUtils(layer) - result = vle.addRingV2(QgsLineString([QgsPoint(3, 3), QgsPoint(3, 4), QgsPoint(4, 4), QgsPoint(4, 3), QgsPoint(3, 3)])) + result = vle.addRingV2( + QgsLineString( + [ + QgsPoint(3, 3), + QgsPoint(3, 4), + QgsPoint(4, 4), + QgsPoint(4, 3), + QgsPoint(3, 3), + ] + ) + ) self.assertEqual(Qgis.GeometryOperationResult.LayerNotEditable, result[0]) self.assertEqual([], result[1]) layer.commitChanges() self.assertEqual( layer.getFeature(1).geometry().asWkt(), - "Polygon ((0 0, 5 0, 5 5, 0 5, 0 0))" + "Polygon ((0 0, 5 0, 5 5, 0 5, 0 0))", ) self.assertEqual( layer.getFeature(2).geometry().asWkt(), - "Polygon ((2 2, 6 2, 6 6, 2 6, 2 2))" + "Polygon ((2 2, 6 2, 6 6, 2 6, 2 2))", ) def testAddRingV2NotClosedRing(self): @@ -169,25 +204,29 @@ def testAddRingV2NotClosedRing(self): pr = layer.dataProvider() f1 = QgsFeature(layer.fields(), 1) - f1.setGeometry(QgsGeometry.fromWkt('POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))')) + f1.setGeometry(QgsGeometry.fromWkt("POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))")) f2 = QgsFeature(layer.fields(), 1) - f2.setGeometry(QgsGeometry.fromWkt('POLYGON((2 2, 6 2, 6 6, 2 6, 2 2))')) + f2.setGeometry(QgsGeometry.fromWkt("POLYGON((2 2, 6 2, 6 6, 2 6, 2 2))")) assert pr.addFeatures([f1, f2]) self.assertEqual(layer.featureCount(), 2) vle = QgsVectorLayerEditUtils(layer) - result = vle.addRingV2(QgsLineString([QgsPoint(3, 3), QgsPoint(3, 4), QgsPoint(4, 4), QgsPoint(4, 3)])) + result = vle.addRingV2( + QgsLineString( + [QgsPoint(3, 3), QgsPoint(3, 4), QgsPoint(4, 4), QgsPoint(4, 3)] + ) + ) self.assertEqual(Qgis.GeometryOperationResult.AddRingNotClosed, result[0]) self.assertEqual([], result[1]) layer.commitChanges() self.assertEqual( layer.getFeature(1).geometry().asWkt(), - "Polygon ((0 0, 5 0, 5 5, 0 5, 0 0))" + "Polygon ((0 0, 5 0, 5 5, 0 5, 0 0))", ) self.assertEqual( layer.getFeature(2).geometry().asWkt(), - "Polygon ((2 2, 6 2, 6 6, 2 6, 2 2))" + "Polygon ((2 2, 6 2, 6 6, 2 6, 2 2))", ) def testAddRingV2Outside(self): @@ -198,28 +237,37 @@ def testAddRingV2Outside(self): pr = layer.dataProvider() f1 = QgsFeature(layer.fields(), 1) - f1.setGeometry(QgsGeometry.fromWkt('POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))')) + f1.setGeometry(QgsGeometry.fromWkt("POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))")) f2 = QgsFeature(layer.fields(), 1) - f2.setGeometry(QgsGeometry.fromWkt('POLYGON((2 2, 6 2, 6 6, 2 6, 2 2))')) + f2.setGeometry(QgsGeometry.fromWkt("POLYGON((2 2, 6 2, 6 6, 2 6, 2 2))")) assert pr.addFeatures([f1, f2]) self.assertEqual(layer.featureCount(), 2) vle = QgsVectorLayerEditUtils(layer) - result = vle.addRingV2(QgsLineString([QgsPoint(8, 8), QgsPoint(8, 9), QgsPoint(9, 9), QgsPoint(9, 8), QgsPoint(8, 8)])) + result = vle.addRingV2( + QgsLineString( + [ + QgsPoint(8, 8), + QgsPoint(8, 9), + QgsPoint(9, 9), + QgsPoint(9, 8), + QgsPoint(8, 8), + ] + ) + ) self.assertEqual( - Qgis.GeometryOperationResult.AddRingNotInExistingFeature, - result[0] + Qgis.GeometryOperationResult.AddRingNotInExistingFeature, result[0] ) self.assertEqual([], result[1]) layer.commitChanges() self.assertEqual( layer.getFeature(1).geometry().asWkt(), - "Polygon ((0 0, 5 0, 5 5, 0 5, 0 0))" + "Polygon ((0 0, 5 0, 5 5, 0 5, 0 0))", ) self.assertEqual( layer.getFeature(2).geometry().asWkt(), - "Polygon ((2 2, 6 2, 6 6, 2 6, 2 2))" + "Polygon ((2 2, 6 2, 6 6, 2 6, 2 2))", ) def testAddRingV2(self): @@ -229,25 +277,35 @@ def testAddRingV2(self): pr = layer.dataProvider() f1 = QgsFeature(layer.fields(), 1) - f1.setGeometry(QgsGeometry.fromWkt('POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))')) + f1.setGeometry(QgsGeometry.fromWkt("POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))")) f2 = QgsFeature(layer.fields(), 1) - f2.setGeometry(QgsGeometry.fromWkt('POLYGON((2 2, 6 2, 6 6, 2 6, 2 2))')) + f2.setGeometry(QgsGeometry.fromWkt("POLYGON((2 2, 6 2, 6 6, 2 6, 2 2))")) assert pr.addFeatures([f1, f2]) self.assertEqual(layer.featureCount(), 2) vle = QgsVectorLayerEditUtils(layer) - result = vle.addRingV2(QgsLineString([QgsPoint(3, 3), QgsPoint(3, 4), QgsPoint(4, 4), QgsPoint(4, 3), QgsPoint(3, 3)])) + result = vle.addRingV2( + QgsLineString( + [ + QgsPoint(3, 3), + QgsPoint(3, 4), + QgsPoint(4, 4), + QgsPoint(4, 3), + QgsPoint(3, 3), + ] + ) + ) self.assertEqual(Qgis.GeometryOperationResult.Success, result[0]) self.assertEqual({2, 1}, set(result[1])) layer.commitChanges() self.assertEqual( layer.getFeature(1).geometry().asWkt(), - "Polygon ((0 0, 5 0, 5 5, 0 5, 0 0),(3 3, 3 4, 4 4, 4 3, 3 3))" + "Polygon ((0 0, 5 0, 5 5, 0 5, 0 0),(3 3, 3 4, 4 4, 4 3, 3 3))", ) self.assertEqual( layer.getFeature(2).geometry().asWkt(), - "Polygon ((2 2, 6 2, 6 6, 2 6, 2 2),(3 3, 3 4, 4 4, 4 3, 3 3))" + "Polygon ((2 2, 6 2, 6 6, 2 6, 2 2),(3 3, 3 4, 4 4, 4 3, 3 3))", ) def testAddRingV2SelectedFeatures(self): @@ -258,25 +316,36 @@ def testAddRingV2SelectedFeatures(self): pr = layer.dataProvider() f1 = QgsFeature(layer.fields(), 1) - f1.setGeometry(QgsGeometry.fromWkt('POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))')) + f1.setGeometry(QgsGeometry.fromWkt("POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))")) f2 = QgsFeature(layer.fields(), 1) - f2.setGeometry(QgsGeometry.fromWkt('POLYGON((2 2, 6 2, 6 6, 2 6, 2 2))')) + f2.setGeometry(QgsGeometry.fromWkt("POLYGON((2 2, 6 2, 6 6, 2 6, 2 2))")) assert pr.addFeatures([f1, f2]) self.assertEqual(layer.featureCount(), 2) vle = QgsVectorLayerEditUtils(layer) - result = vle.addRingV2(QgsLineString([QgsPoint(3, 3), QgsPoint(3, 4), QgsPoint(4, 4), QgsPoint(4, 3), QgsPoint(3, 3)]), [1]) + result = vle.addRingV2( + QgsLineString( + [ + QgsPoint(3, 3), + QgsPoint(3, 4), + QgsPoint(4, 4), + QgsPoint(4, 3), + QgsPoint(3, 3), + ] + ), + [1], + ) self.assertEqual(Qgis.GeometryOperationResult.Success, result[0]) self.assertEqual([1], result[1]) layer.commitChanges() self.assertEqual( layer.getFeature(1).geometry().asWkt(), - "Polygon ((0 0, 5 0, 5 5, 0 5, 0 0),(3 3, 3 4, 4 4, 4 3, 3 3))" + "Polygon ((0 0, 5 0, 5 5, 0 5, 0 0),(3 3, 3 4, 4 4, 4 3, 3 3))", ) self.assertEqual( layer.getFeature(2).geometry().asWkt(), - "Polygon ((2 2, 6 2, 6 6, 2 6, 2 2))" + "Polygon ((2 2, 6 2, 6 6, 2 6, 2 2))", ) def testAddRingV2AtLeastOne(self): @@ -287,25 +356,37 @@ def testAddRingV2AtLeastOne(self): pr = layer.dataProvider() f1 = QgsFeature(layer.fields(), 1) - f1.setGeometry(QgsGeometry.fromWkt('POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))')) + f1.setGeometry(QgsGeometry.fromWkt("POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))")) f2 = QgsFeature(layer.fields(), 1) - f2.setGeometry(QgsGeometry.fromWkt('POLYGON((2 2, 6 2, 6 6, 2 6, 2 2))')) + f2.setGeometry(QgsGeometry.fromWkt("POLYGON((2 2, 6 2, 6 6, 2 6, 2 2))")) assert pr.addFeatures([f1, f2]) self.assertEqual(layer.featureCount(), 2) vle = QgsVectorLayerEditUtils(layer) - result = vle.addRingV2(QgsLineString([QgsPoint(0.5, 3), QgsPoint(1.5, 3), QgsPoint(1.5, 1.5), QgsPoint(3, 1.5), QgsPoint(3, 0.5), QgsPoint(0.5, 0.5), QgsPoint(0.5, 3)])) + result = vle.addRingV2( + QgsLineString( + [ + QgsPoint(0.5, 3), + QgsPoint(1.5, 3), + QgsPoint(1.5, 1.5), + QgsPoint(3, 1.5), + QgsPoint(3, 0.5), + QgsPoint(0.5, 0.5), + QgsPoint(0.5, 3), + ] + ) + ) self.assertEqual(Qgis.GeometryOperationResult.Success, result[0]) self.assertEqual({1}, set(result[1])) layer.commitChanges() self.assertEqual( layer.getFeature(1).geometry().asWkt(), - "Polygon ((0 0, 5 0, 5 5, 0 5, 0 0),(0.5 3, 1.5 3, 1.5 1.5, 3 1.5, 3 0.5, 0.5 0.5, 0.5 3))" + "Polygon ((0 0, 5 0, 5 5, 0 5, 0 0),(0.5 3, 1.5 3, 1.5 1.5, 3 1.5, 3 0.5, 0.5 0.5, 0.5 3))", ) self.assertEqual( layer.getFeature(2).geometry().asWkt(), - "Polygon ((2 2, 6 2, 6 6, 2 6, 2 2))" + "Polygon ((2 2, 6 2, 6 6, 2 6, 2 2))", ) def testMoveVertex(self): @@ -315,7 +396,7 @@ def testMoveVertex(self): pr = layer.dataProvider() f1 = QgsFeature(layer.fields(), 1) - f1.setGeometry(QgsGeometry.fromWkt('Point(0 0)')) + f1.setGeometry(QgsGeometry.fromWkt("Point(0 0)")) self.assertTrue(pr.addFeatures([f1])) self.assertEqual(layer.featureCount(), 1) @@ -342,7 +423,7 @@ def testMoveVertexPointZ(self): pr = layer.dataProvider() f1 = QgsFeature(layer.fields(), 1) - f1.setGeometry(QgsGeometry.fromWkt('PointZ(0 0 0)')) + f1.setGeometry(QgsGeometry.fromWkt("PointZ(0 0 0)")) self.assertTrue(pr.addFeatures([f1])) self.assertEqual(layer.featureCount(), 1) @@ -366,7 +447,7 @@ def testMoveVertexPointZ(self): # Add a non-Z point and check that Z get added on move f2 = QgsFeature(layer.fields(), 2) - f2.setGeometry(QgsGeometry.fromWkt('Point(0 0)')) + f2.setGeometry(QgsGeometry.fromWkt("Point(0 0)")) self.assertTrue(pr.addFeatures([f2])) self.assertEqual(layer.featureCount(), 2) @@ -386,7 +467,7 @@ def testMoveVertexPointM(self): pr = layer.dataProvider() f1 = QgsFeature(layer.fields(), 1) - f1.setGeometry(QgsGeometry.fromWkt('PointM(0 0 0)')) + f1.setGeometry(QgsGeometry.fromWkt("PointM(0 0 0)")) self.assertTrue(pr.addFeatures([f1])) self.assertEqual(layer.featureCount(), 1) @@ -403,7 +484,7 @@ def testMoveVertexPointM(self): # Add a non-M point and check that M get added on move f2 = QgsFeature(layer.fields(), 2) - f2.setGeometry(QgsGeometry.fromWkt('Point(0 0)')) + f2.setGeometry(QgsGeometry.fromWkt("Point(0 0)")) self.assertTrue(pr.addFeatures([f2])) self.assertEqual(layer.featureCount(), 2) @@ -425,7 +506,7 @@ def testMoveVertexPointZM(self): pr = layer.dataProvider() f1 = QgsFeature(layer.fields(), 1) - f1.setGeometry(QgsGeometry.fromWkt('PointZM(0 0 0 0)')) + f1.setGeometry(QgsGeometry.fromWkt("PointZM(0 0 0 0)")) self.assertTrue(pr.addFeatures([f1])) self.assertEqual(layer.featureCount(), 1) @@ -443,7 +524,7 @@ def testMoveVertexPointZM(self): # Add a non-ZM point and check that Z and M get added on move f2 = QgsFeature(layer.fields(), 2) - f2.setGeometry(QgsGeometry.fromWkt('Point(0 0)')) + f2.setGeometry(QgsGeometry.fromWkt("Point(0 0)")) self.assertTrue(pr.addFeatures([f2])) self.assertEqual(layer.featureCount(), 2) @@ -470,15 +551,27 @@ def testSplitParts(self): # Each feature is composed of two squares side by side # Each feature is on a separate row to form a 3*2 grid f = QgsFeature(layer.fields(), 1) - f.setGeometry(QgsGeometry.fromWkt('MULTIPOLYGON(((0 0, 4 0, 4 4, 0 4, 0 0)), ((6 0, 10 0, 10 4, 6 4, 6 0)))')) + f.setGeometry( + QgsGeometry.fromWkt( + "MULTIPOLYGON(((0 0, 4 0, 4 4, 0 4, 0 0)), ((6 0, 10 0, 10 4, 6 4, 6 0)))" + ) + ) assert pr.addFeatures([f]) f = QgsFeature(layer.fields(), 2) - f.setGeometry(QgsGeometry.fromWkt('MULTIPOLYGON(((0 6, 4 6, 4 10, 0 10, 0 6)), ((6 6, 10 6, 10 10, 6 10, 6 6)))')) + f.setGeometry( + QgsGeometry.fromWkt( + "MULTIPOLYGON(((0 6, 4 6, 4 10, 0 10, 0 6)), ((6 6, 10 6, 10 10, 6 10, 6 6)))" + ) + ) assert pr.addFeatures([f]) f = QgsFeature(layer.fields(), 3) - f.setGeometry(QgsGeometry.fromWkt('MULTIPOLYGON(((0 12, 4 12, 4 16, 0 16, 0 12)), ((6 12, 10 12, 10 16, 6 16, 6 12)))')) + f.setGeometry( + QgsGeometry.fromWkt( + "MULTIPOLYGON(((0 12, 4 12, 4 16, 0 16, 0 12)), ((6 12, 10 12, 10 16, 6 16, 6 12)))" + ) + ) assert pr.addFeatures([f]) self.assertEqual(layer.featureCount(), 3) @@ -499,33 +592,33 @@ def testSplitParts(self): self.assertEqual( layer.getFeature(1).geometry().asWkt(), - 'MultiPolygon (((2 0, 2 2, 4 2, 4 0, 2 0)),((2 2, 2 0, 0 0, 0 2, 2 2)),((2 2, 2 4, 4 4, 4 2, 2 2)),((2 4, 2 2, 0 2, 0 4, 2 4)),((6 2, 10 2, 10 0, 6 0, 6 2)),((10 2, 6 2, 6 4, 10 4, 10 2)))' + "MultiPolygon (((2 0, 2 2, 4 2, 4 0, 2 0)),((2 2, 2 0, 0 0, 0 2, 2 2)),((2 2, 2 4, 4 4, 4 2, 2 2)),((2 4, 2 2, 0 2, 0 4, 2 4)),((6 2, 10 2, 10 0, 6 0, 6 2)),((10 2, 6 2, 6 4, 10 4, 10 2)))", ) self.assertEqual( layer.getFeature(2).geometry().asWkt(), - 'MultiPolygon (((2 6, 2 10, 4 10, 4 6, 2 6)),((2 10, 2 6, 0 6, 0 10, 2 10)),((6 6, 10 6, 10 10, 6 10, 6 6)))' + "MultiPolygon (((2 6, 2 10, 4 10, 4 6, 2 6)),((2 10, 2 6, 0 6, 0 10, 2 10)),((6 6, 10 6, 10 10, 6 10, 6 6)))", ) self.assertEqual( layer.getFeature(3).geometry().asWkt(), - 'MultiPolygon (((2 12, 2 16, 4 16, 4 12, 2 12)),((2 16, 2 12, 0 12, 0 16, 2 16)),((6 12, 10 12, 10 16, 6 16, 6 12)))' + "MultiPolygon (((2 12, 2 16, 4 16, 4 12, 2 12)),((2 16, 2 12, 0 12, 0 16, 2 16)),((6 12, 10 12, 10 16, 6 16, 6 12)))", ) def testMergeFeatures(self): layer = createEmptyPolygonLayer() self.assertTrue(layer.startEditing()) - layer.addAttribute(QgsField('name', QVariant.String)) + layer.addAttribute(QgsField("name", QVariant.String)) pr = layer.dataProvider() f1 = QgsFeature(layer.fields(), 1) - f1.setGeometry(QgsGeometry.fromWkt('POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))')) - f1.setAttribute('name', 'uno') + f1.setGeometry(QgsGeometry.fromWkt("POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))")) + f1.setAttribute("name", "uno") assert pr.addFeatures([f1]) self.assertEqual(layer.featureCount(), 1) f2 = QgsFeature(layer.fields(), 2) - f2.setGeometry(QgsGeometry.fromWkt('POLYGON((3 3, 8 3, 8 8, 3 8, 3 3))')) - f2.setAttribute('name', 'due') + f2.setGeometry(QgsGeometry.fromWkt("POLYGON((3 3, 8 3, 8 8, 3 8, 3 3))")) + f2.setAttribute("name", "due") assert pr.addFeatures([f2]) self.assertEqual(layer.featureCount(), 2) @@ -536,7 +629,9 @@ def testMergeFeatures(self): self.assertFalse(unionGeom.isNull()) vle = QgsVectorLayerEditUtils(layer) - success, errorMessage = vle.mergeFeatures(f1.id(), featureIds, ['tre'], unionGeom) + success, errorMessage = vle.mergeFeatures( + f1.id(), featureIds, ["tre"], unionGeom + ) self.assertFalse(errorMessage) self.assertTrue(success) @@ -546,16 +641,18 @@ def testMergeFeatures(self): mergedFeature = next(layer.getFeatures()) self.assertEqual( mergedFeature.geometry().asWkt(), - "Polygon ((5 0, 0 0, 0 5, 3 5, 3 8, 8 8, 8 3, 5 3, 5 0))" + "Polygon ((5 0, 0 0, 0 5, 3 5, 3 8, 8 8, 8 3, 5 3, 5 0))", ) - self.assertEqual(mergedFeature.attribute('name'), 'tre') + self.assertEqual(mergedFeature.attribute("name"), "tre") def testMergeFeaturesIntoExisting(self): - tempgpkg = os.path.join(tempfile.mkdtemp(), 'testMergeFeaturesIntoExisting.gpkg') + tempgpkg = os.path.join( + tempfile.mkdtemp(), "testMergeFeaturesIntoExisting.gpkg" + ) fields = QgsFields() - fields.append(QgsField('name', QVariant.String)) + fields.append(QgsField("name", QVariant.String)) - crs = QgsCoordinateReferenceSystem('epsg:4326') + crs = QgsCoordinateReferenceSystem("epsg:4326") options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = "GPKG" QgsVectorFileWriter.create( @@ -564,21 +661,22 @@ def testMergeFeaturesIntoExisting(self): geometryType=QgsWkbTypes.Type.Polygon, srs=crs, transformContext=QgsCoordinateTransformContext(), - options=options) + options=options, + ) - layer = QgsVectorLayer(tempgpkg, 'my_layer', 'ogr') + layer = QgsVectorLayer(tempgpkg, "my_layer", "ogr") self.assertTrue(layer.startEditing()) pr = layer.dataProvider() f1 = QgsFeature(layer.fields(), 1) - f1.setGeometry(QgsGeometry.fromWkt('POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))')) - f1.setAttribute('name', 'uno') + f1.setGeometry(QgsGeometry.fromWkt("POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))")) + f1.setAttribute("name", "uno") assert pr.addFeatures([f1]) self.assertEqual(layer.featureCount(), 1) f2 = QgsFeature(layer.fields(), 2) - f2.setGeometry(QgsGeometry.fromWkt('POLYGON((3 3, 8 3, 8 8, 3 8, 3 3))')) - f2.setAttribute('name', 'due') + f2.setGeometry(QgsGeometry.fromWkt("POLYGON((3 3, 8 3, 8 8, 3 8, 3 3))")) + f2.setAttribute("name", "due") assert pr.addFeatures([f2]) self.assertEqual(layer.featureCount(), 2) @@ -589,7 +687,9 @@ def testMergeFeaturesIntoExisting(self): self.assertFalse(unionGeom.isNull()) vle = QgsVectorLayerEditUtils(layer) - success, errorMessage = vle.mergeFeatures(f2.id(), featureIds, [2, 'tre'], unionGeom) + success, errorMessage = vle.mergeFeatures( + f2.id(), featureIds, [2, "tre"], unionGeom + ) self.assertFalse(errorMessage) self.assertTrue(success) @@ -599,42 +699,36 @@ def testMergeFeaturesIntoExisting(self): mergedFeature = layer.getFeature(2) self.assertEqual( mergedFeature.geometry().asWkt(), - "Polygon ((5 0, 0 0, 0 5, 3 5, 3 8, 8 8, 8 3, 5 3, 5 0))" + "Polygon ((5 0, 0 0, 0 5, 3 5, 3 8, 8 8, 8 3, 5 3, 5 0))", ) - self.assertEqual(mergedFeature.attribute('name'), 'tre') + self.assertEqual(mergedFeature.attribute("name"), "tre") def test_split_policy_lines(self): - temp_layer = QgsVectorLayer("LineString?crs=epsg:3111&field=pk:int&field=field_default:real&field=field_dupe:real&field=field_unset:real&field=field_ratio:real&field=apply_default:real", - "vl", "memory") + temp_layer = QgsVectorLayer( + "LineString?crs=epsg:3111&field=pk:int&field=field_default:real&field=field_dupe:real&field=field_unset:real&field=field_ratio:real&field=apply_default:real", + "vl", + "memory", + ) self.assertTrue(temp_layer.isValid()) - temp_layer.setDefaultValueDefinition(1, - QgsDefaultValue('301')) - temp_layer.setDefaultValueDefinition(2, - QgsDefaultValue('302')) - temp_layer.setDefaultValueDefinition(3, - QgsDefaultValue('303')) - temp_layer.setDefaultValueDefinition(4, - QgsDefaultValue('304')) - temp_layer.setDefaultValueDefinition(5, - QgsDefaultValue('305', True)) - - temp_layer.setFieldSplitPolicy(1, - Qgis.FieldDomainSplitPolicy.DefaultValue) - temp_layer.setFieldSplitPolicy(2, - Qgis.FieldDomainSplitPolicy.Duplicate) - temp_layer.setFieldSplitPolicy(3, - Qgis.FieldDomainSplitPolicy.UnsetField) - temp_layer.setFieldSplitPolicy(4, - Qgis.FieldDomainSplitPolicy.GeometryRatio) + temp_layer.setDefaultValueDefinition(1, QgsDefaultValue("301")) + temp_layer.setDefaultValueDefinition(2, QgsDefaultValue("302")) + temp_layer.setDefaultValueDefinition(3, QgsDefaultValue("303")) + temp_layer.setDefaultValueDefinition(4, QgsDefaultValue("304")) + temp_layer.setDefaultValueDefinition(5, QgsDefaultValue("305", True)) + + temp_layer.setFieldSplitPolicy(1, Qgis.FieldDomainSplitPolicy.DefaultValue) + temp_layer.setFieldSplitPolicy(2, Qgis.FieldDomainSplitPolicy.Duplicate) + temp_layer.setFieldSplitPolicy(3, Qgis.FieldDomainSplitPolicy.UnsetField) + temp_layer.setFieldSplitPolicy(4, Qgis.FieldDomainSplitPolicy.GeometryRatio) # this will be ignored -- the apply on update default will override it - temp_layer.setFieldSplitPolicy(5, - Qgis.FieldDomainSplitPolicy.GeometryRatio) + temp_layer.setFieldSplitPolicy(5, Qgis.FieldDomainSplitPolicy.GeometryRatio) temp_layer.startEditing() - feature = QgsVectorLayerUtils.createFeature(temp_layer, - QgsGeometry.fromWkt('LineString( 0 0, 10 0)')) + feature = QgsVectorLayerUtils.createFeature( + temp_layer, QgsGeometry.fromWkt("LineString( 0 0, 10 0)") + ) feature[1] = 3301 feature[5] = 3305 self.assertTrue(temp_layer.addFeature(feature)) @@ -642,75 +736,81 @@ def test_split_policy_lines(self): temp_layer.commitChanges() original_feature = next(temp_layer.getFeatures()) - self.assertEqual(original_feature.attributes(), - [None, 3301.0, 302.0, 303.0, 304.0, 3305.0]) + self.assertEqual( + original_feature.attributes(), [None, 3301.0, 302.0, 303.0, 304.0, 3305.0] + ) temp_layer.startEditing() - split_curve = QgsGeometry.fromWkt('LineString (0.3 0.2, 0.27 -0.2, 0.86 -0.24, 0.88 0.22)') + split_curve = QgsGeometry.fromWkt( + "LineString (0.3 0.2, 0.27 -0.2, 0.86 -0.24, 0.88 0.22)" + ) temp_layer.splitFeatures(split_curve.constGet(), preserveCircular=False) features = list(temp_layer.getFeatures()) attributes = [f.attributes() for f in features] - self.assertCountEqual(attributes, - [[None, 3301.0, 302.0, 303.0, 8.664000000000001, 305.0], - [None, 301, 302.0, QgsUnsetAttributeValue(), 17.797217391304347, 305.0], - [None, 301, 302.0, QgsUnsetAttributeValue(), 277.53878260869567, 305.0] - ]) + self.assertCountEqual( + attributes, + [ + [None, 3301.0, 302.0, 303.0, 8.664000000000001, 305.0], + [None, 301, 302.0, QgsUnsetAttributeValue(), 17.797217391304347, 305.0], + [None, 301, 302.0, QgsUnsetAttributeValue(), 277.53878260869567, 305.0], + ], + ) temp_layer.rollBack() def test_split_policy_polygon(self): - temp_layer = QgsVectorLayer("Polygon?crs=epsg:3111&field=pk:int&field=field_default:real&field=field_dupe:real&field=field_unset:real&field=field_ratio:real", - "vl", "memory") + temp_layer = QgsVectorLayer( + "Polygon?crs=epsg:3111&field=pk:int&field=field_default:real&field=field_dupe:real&field=field_unset:real&field=field_ratio:real", + "vl", + "memory", + ) self.assertTrue(temp_layer.isValid()) - temp_layer.setDefaultValueDefinition(1, - QgsDefaultValue('301')) - temp_layer.setDefaultValueDefinition(2, - QgsDefaultValue('302')) - temp_layer.setDefaultValueDefinition(3, - QgsDefaultValue('303')) - temp_layer.setDefaultValueDefinition(4, - QgsDefaultValue('304')) - - temp_layer.setFieldSplitPolicy(1, - Qgis.FieldDomainSplitPolicy.DefaultValue) - temp_layer.setFieldSplitPolicy(2, - Qgis.FieldDomainSplitPolicy.Duplicate) - temp_layer.setFieldSplitPolicy(3, - Qgis.FieldDomainSplitPolicy.UnsetField) - temp_layer.setFieldSplitPolicy(4, - Qgis.FieldDomainSplitPolicy.GeometryRatio) + temp_layer.setDefaultValueDefinition(1, QgsDefaultValue("301")) + temp_layer.setDefaultValueDefinition(2, QgsDefaultValue("302")) + temp_layer.setDefaultValueDefinition(3, QgsDefaultValue("303")) + temp_layer.setDefaultValueDefinition(4, QgsDefaultValue("304")) + + temp_layer.setFieldSplitPolicy(1, Qgis.FieldDomainSplitPolicy.DefaultValue) + temp_layer.setFieldSplitPolicy(2, Qgis.FieldDomainSplitPolicy.Duplicate) + temp_layer.setFieldSplitPolicy(3, Qgis.FieldDomainSplitPolicy.UnsetField) + temp_layer.setFieldSplitPolicy(4, Qgis.FieldDomainSplitPolicy.GeometryRatio) temp_layer.startEditing() - feature = QgsVectorLayerUtils.createFeature(temp_layer, - QgsGeometry.fromWkt('Polygon(( 0 0, 10 0, 10 10, 0 10, 0 0))')) + feature = QgsVectorLayerUtils.createFeature( + temp_layer, QgsGeometry.fromWkt("Polygon(( 0 0, 10 0, 10 10, 0 10, 0 0))") + ) feature[1] = 3301 self.assertTrue(temp_layer.addFeature(feature)) temp_layer.commitChanges() original_feature = next(temp_layer.getFeatures()) - self.assertEqual(original_feature.attributes(), - [None, 3301.0, 302.0, 303.0, 304.0]) + self.assertEqual( + original_feature.attributes(), [None, 3301.0, 302.0, 303.0, 304.0] + ) temp_layer.startEditing() - split_curve = QgsGeometry.fromWkt('LineString (-2.7 4.3, 5.5 11.8, 5.28 -5.57)') + split_curve = QgsGeometry.fromWkt("LineString (-2.7 4.3, 5.5 11.8, 5.28 -5.57)") temp_layer.splitFeatures(split_curve.constGet(), preserveCircular=False) features = list(temp_layer.getFeatures()) attributes = [f.attributes() for f in features] - self.assertCountEqual(attributes, - [[None, 3301.0, 302.0, 303.0, 147.23845863746018], - [None, 301, 302.0, QgsUnsetAttributeValue(), 17.343326048780483], - [None, 301, 302.0, QgsUnsetAttributeValue(), 139.41821531375936] - ]) + self.assertCountEqual( + attributes, + [ + [None, 3301.0, 302.0, 303.0, 147.23845863746018], + [None, 301, 302.0, QgsUnsetAttributeValue(), 17.343326048780483], + [None, 301, 302.0, QgsUnsetAttributeValue(), 139.41821531375936], + ], + ) temp_layer.rollBack() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorlayerelevationproperties.py b/tests/src/python/test_qgsvectorlayerelevationproperties.py index 0c4f566914a2..b57614823db4 100644 --- a/tests/src/python/test_qgsvectorlayerelevationproperties.py +++ b/tests/src/python/test_qgsvectorlayerelevationproperties.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '09/11/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "09/11/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtXml import QDomDocument from qgis.core import ( @@ -67,35 +68,56 @@ def testBasic(self): self.assertEqual(props.binding(), Qgis.AltitudeBinding.Vertex) self.assertFalse(props.respectLayerSymbology()) self.assertEqual(props.type(), Qgis.VectorProfileType.ContinuousSurface) - self.assertEqual(props.profileSymbology(), Qgis.ProfileSurfaceSymbology.FillBelow) + self.assertEqual( + props.profileSymbology(), Qgis.ProfileSurfaceSymbology.FillBelow + ) self.assertTrue(props.showMarkerSymbolInSurfacePlots()) self.assertEqual(props.elevationLimit(), 909) - props.dataDefinedProperties().setProperty(QgsMapLayerElevationProperties.Property.ExtrusionHeight, QgsProperty.fromExpression('1*5')) - self.assertEqual(props.dataDefinedProperties().property(QgsMapLayerElevationProperties.Property.ExtrusionHeight).asExpression(), '1*5') + props.dataDefinedProperties().setProperty( + QgsMapLayerElevationProperties.Property.ExtrusionHeight, + QgsProperty.fromExpression("1*5"), + ) + self.assertEqual( + props.dataDefinedProperties() + .property(QgsMapLayerElevationProperties.Property.ExtrusionHeight) + .asExpression(), + "1*5", + ) properties = QgsPropertyCollection() - properties.setProperty(QgsMapLayerElevationProperties.Property.ZOffset, QgsProperty.fromExpression('9')) + properties.setProperty( + QgsMapLayerElevationProperties.Property.ZOffset, + QgsProperty.fromExpression("9"), + ) props.setDataDefinedProperties(properties) self.assertFalse( - props.dataDefinedProperties().isActive(QgsMapLayerElevationProperties.Property.ExtrusionHeight)) + props.dataDefinedProperties().isActive( + QgsMapLayerElevationProperties.Property.ExtrusionHeight + ) + ) self.assertEqual( - props.dataDefinedProperties().property(QgsMapLayerElevationProperties.Property.ZOffset).asExpression(), - '9') - - sym = QgsLineSymbol.createSimple({'outline_color': '#ff4433', 'outline_width': 0.5}) + props.dataDefinedProperties() + .property(QgsMapLayerElevationProperties.Property.ZOffset) + .asExpression(), + "9", + ) + + sym = QgsLineSymbol.createSimple( + {"outline_color": "#ff4433", "outline_width": 0.5} + ) props.setProfileLineSymbol(sym) - self.assertEqual(props.profileLineSymbol().color().name(), '#ff4433') + self.assertEqual(props.profileLineSymbol().color().name(), "#ff4433") - sym = QgsFillSymbol.createSimple({'color': '#ff4455', 'outline_width': 0.5}) + sym = QgsFillSymbol.createSimple({"color": "#ff4455", "outline_width": 0.5}) props.setProfileFillSymbol(sym) - self.assertEqual(props.profileFillSymbol().color().name(), '#ff4455') + self.assertEqual(props.profileFillSymbol().color().name(), "#ff4455") - sym = QgsMarkerSymbol.createSimple({'color': '#ff1122', 'outline_width': 0.5}) + sym = QgsMarkerSymbol.createSimple({"color": "#ff1122", "outline_width": 0.5}) props.setProfileMarkerSymbol(sym) - self.assertEqual(props.profileMarkerSymbol().color().name(), '#ff1122') + self.assertEqual(props.profileMarkerSymbol().color().name(), "#ff1122") doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") props.writeXml(elem, doc, QgsReadWriteContext()) props2 = QgsVectorLayerElevationProperties(None) @@ -108,17 +130,22 @@ def testBasic(self): self.assertTrue(props2.extrusionEnabled()) self.assertFalse(props2.respectLayerSymbology()) self.assertEqual(props2.type(), Qgis.VectorProfileType.ContinuousSurface) - self.assertEqual(props2.profileSymbology(), Qgis.ProfileSurfaceSymbology.FillBelow) + self.assertEqual( + props2.profileSymbology(), Qgis.ProfileSurfaceSymbology.FillBelow + ) self.assertTrue(props2.showMarkerSymbolInSurfacePlots()) self.assertEqual(props2.elevationLimit(), 909) - self.assertEqual(props2.profileLineSymbol().color().name(), '#ff4433') - self.assertEqual(props2.profileFillSymbol().color().name(), '#ff4455') - self.assertEqual(props2.profileMarkerSymbol().color().name(), '#ff1122') + self.assertEqual(props2.profileLineSymbol().color().name(), "#ff4433") + self.assertEqual(props2.profileFillSymbol().color().name(), "#ff4455") + self.assertEqual(props2.profileMarkerSymbol().color().name(), "#ff1122") self.assertEqual( - props2.dataDefinedProperties().property(QgsMapLayerElevationProperties.Property.ZOffset).asExpression(), - '9') + props2.dataDefinedProperties() + .property(QgsMapLayerElevationProperties.Property.ZOffset) + .asExpression(), + "9", + ) props_clone = props.clone() self.assertEqual(props_clone.zScale(), 2) @@ -129,30 +156,39 @@ def testBasic(self): self.assertTrue(props_clone.extrusionEnabled()) self.assertFalse(props_clone.respectLayerSymbology()) self.assertEqual(props_clone.type(), Qgis.VectorProfileType.ContinuousSurface) - self.assertEqual(props_clone.profileSymbology(), Qgis.ProfileSurfaceSymbology.FillBelow) + self.assertEqual( + props_clone.profileSymbology(), Qgis.ProfileSurfaceSymbology.FillBelow + ) self.assertTrue(props_clone.showMarkerSymbolInSurfacePlots()) self.assertEqual(props2.elevationLimit(), 909) - self.assertEqual(props_clone.profileLineSymbol().color().name(), '#ff4433') - self.assertEqual(props_clone.profileFillSymbol().color().name(), '#ff4455') - self.assertEqual(props_clone.profileMarkerSymbol().color().name(), '#ff1122') + self.assertEqual(props_clone.profileLineSymbol().color().name(), "#ff4433") + self.assertEqual(props_clone.profileFillSymbol().color().name(), "#ff4455") + self.assertEqual(props_clone.profileMarkerSymbol().color().name(), "#ff1122") self.assertEqual( - props_clone.dataDefinedProperties().property(QgsMapLayerElevationProperties.Property.ZOffset).asExpression(), - '9') + props_clone.dataDefinedProperties() + .property(QgsMapLayerElevationProperties.Property.ZOffset) + .asExpression(), + "9", + ) def test_defaults(self): # a layer without z values present should default to terrain clamping mode - vl = QgsVectorLayer(unitTestDataPath() + '/3d/trees.shp') + vl = QgsVectorLayer(unitTestDataPath() + "/3d/trees.shp") self.assertTrue(vl.isValid()) - self.assertEqual(vl.elevationProperties().clamping(), Qgis.AltitudeClamping.Terrain) + self.assertEqual( + vl.elevationProperties().clamping(), Qgis.AltitudeClamping.Terrain + ) # a layer WITH z values present should default to relative mode - vl = QgsVectorLayer(unitTestDataPath() + '/3d/points_with_z.shp') + vl = QgsVectorLayer(unitTestDataPath() + "/3d/points_with_z.shp") self.assertTrue(vl.isValid()) - self.assertEqual(vl.elevationProperties().clamping(), Qgis.AltitudeClamping.Relative) + self.assertEqual( + vl.elevationProperties().clamping(), Qgis.AltitudeClamping.Relative + ) def test_show_by_default(self): props = QgsVectorLayerElevationProperties(None) @@ -175,5 +211,5 @@ def test_show_by_default(self): self.assertTrue(props.showByDefaultInElevationProfilePlots()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorlayerfeaturecounter.py b/tests/src/python/test_qgsvectorlayerfeaturecounter.py index cd72d8be27cd..c5fa404206ac 100644 --- a/tests/src/python/test_qgsvectorlayerfeaturecounter.py +++ b/tests/src/python/test_qgsvectorlayerfeaturecounter.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Mathieu Pellerin' -__date__ = '08/02/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Mathieu Pellerin" +__date__ = "08/02/2021" +__copyright__ = "Copyright 2021, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, QTime from qgis.PyQt.QtTest import QSignalSpy @@ -28,35 +29,83 @@ class TestQgsVectorLayerFeatureCounter(QgisTestCase): def setUp(self): self.vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk', - 'test', 'memory') - assert (self.vl.isValid()) + "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk", + "test", + "memory", + ) + assert self.vl.isValid() f1 = QgsFeature(5) - f1.setAttributes([5, -200, NULL, 'NuLl', '5', QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), QDate(2020, 5, 2), QTime(12, 13, 1)]) - f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)')) + f1.setAttributes( + [ + 5, + -200, + NULL, + "NuLl", + "5", + QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), + QDate(2020, 5, 2), + QTime(12, 13, 1), + ] + ) + f1.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)")) f2 = QgsFeature(3) - f2.setAttributes([3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL]) + f2.setAttributes([3, 300, "Pear", "PEaR", "3", NULL, NULL, NULL]) f3 = QgsFeature(1) - f3.setAttributes([1, 100, 'Orange', 'oranGe', '1', QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), QDate(2020, 5, 3), QTime(12, 13, 14)]) - f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)')) + f3.setAttributes( + [ + 1, + 100, + "Orange", + "oranGe", + "1", + QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), + QDate(2020, 5, 3), + QTime(12, 13, 14), + ] + ) + f3.setGeometry(QgsGeometry.fromWkt("Point (-70.332 66.33)")) f4 = QgsFeature(2) - f4.setAttributes([2, 200, 'Apple', 'Apple', '2', QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), QDate(2020, 5, 4), QTime(12, 14, 14)]) - f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)')) + f4.setAttributes( + [ + 2, + 200, + "Apple", + "Apple", + "2", + QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), + QDate(2020, 5, 4), + QTime(12, 14, 14), + ] + ) + f4.setGeometry(QgsGeometry.fromWkt("Point (-68.2 70.8)")) f5 = QgsFeature(4) - f5.setAttributes([4, 400, 'Honey', 'Honey', '4', QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), QDate(2021, 5, 4), QTime(13, 13, 14)]) - f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)')) + f5.setAttributes( + [ + 4, + 400, + "Honey", + "Honey", + "4", + QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), + QDate(2021, 5, 4), + QTime(13, 13, 14), + ] + ) + f5.setGeometry(QgsGeometry.fromWkt("Point (-65.32 78.3)")) assert self.vl.dataProvider().addFeatures([f1, f2, f3, f4, f5]) self.vl2 = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk', - 'test', 'memory') - assert (self.vl2.isValid()) + "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk", + "test", + "memory", + ) + assert self.vl2.isValid() def tearDown(self): del self.vl @@ -71,7 +120,9 @@ def testFeaturesCount(self): signal_spy.wait() self.assertEqual(len(signal_spy), 1) - self.assertEqual(self.vl.featureCount(self.vl.renderer().legendSymbolItems()[0].ruleKey()), 5) + self.assertEqual( + self.vl.featureCount(self.vl.renderer().legendSymbolItems()[0].ruleKey()), 5 + ) def testFeaturesCountOnEmptyLayer(self): @@ -82,8 +133,11 @@ def testFeaturesCountOnEmptyLayer(self): signal_spy.wait() self.assertEqual(len(signal_spy), 1) - self.assertEqual(self.vl2.featureCount(self.vl2.renderer().legendSymbolItems()[0].ruleKey()), 0) + self.assertEqual( + self.vl2.featureCount(self.vl2.renderer().legendSymbolItems()[0].ruleKey()), + 0, + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorlayerprofilegenerator.py b/tests/src/python/test_qgsvectorlayerprofilegenerator.py index 395eaf56a099..a9905d151f56 100644 --- a/tests/src/python/test_qgsvectorlayerprofilegenerator.py +++ b/tests/src/python/test_qgsvectorlayerprofilegenerator.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '18/03/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "18/03/2022" +__copyright__ = "Copyright 2022, The QGIS Project" import os import math @@ -41,7 +42,7 @@ QgsWkbTypes, QgsPoint, QgsCoordinateTransform, - QgsDatumTransform + QgsDatumTransform, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -59,21 +60,31 @@ def control_path_prefix(cls): @staticmethod def round_dict(val, places): - return {round(k, places): round(val[k], places) for k in val.keys() if not math.isnan(val[k])} + return { + round(k, places): round(val[k], places) + for k in val.keys() + if not math.isnan(val[k]) + } def create_transform_context(self): context = QgsCoordinateTransformContext() # ensure grids are never used, so that we have a common transformation result - context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:27700'), - QgsCoordinateReferenceSystem('EPSG:4326'), - '+proj=pipeline +step +inv +proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1') - context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:27700'), - QgsCoordinateReferenceSystem('EPSG:3857'), - '+proj=pipeline +step +inv +proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84') + context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:27700"), + QgsCoordinateReferenceSystem("EPSG:4326"), + "+proj=pipeline +step +inv +proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1", + ) + context.addCoordinateOperation( + QgsCoordinateReferenceSystem("EPSG:27700"), + QgsCoordinateReferenceSystem("EPSG:3857"), + "+proj=pipeline +step +inv +proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84", + ) return context def testPointGenerationAbsolute(self): - vl = QgsVectorLayer(os.path.join(unitTestDataPath(), '3d', 'points_with_z.shp'), 'trees') + vl = QgsVectorLayer( + os.path.join(unitTestDataPath(), "3d", "points_with_z.shp"), "trees" + ) self.assertTrue(vl.isValid()) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) @@ -82,7 +93,8 @@ def testPointGenerationAbsolute(self): curve = QgsLineString() curve.fromWkt( - 'LineString (-347557.39478182751918212 6632716.59644229710102081, -346435.3875386503059417 6632277.86440025269985199, -346234.1061912341392599 6632242.03022097796201706, -346185.31071307259844616 6632150.53869942482560873)') + "LineString (-347557.39478182751918212 6632716.59644229710102081, -346435.3875386503059417 6632277.86440025269985199, -346234.1061912341392599 6632242.03022097796201706, -346185.31071307259844616 6632150.53869942482560873)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) @@ -92,7 +104,7 @@ def testPointGenerationAbsolute(self): self.assertFalse(generator.generateProfile()) # set correct crs for linestring and re-try - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) @@ -105,17 +117,28 @@ def testPointGenerationAbsolute(self): self.assertTrue(generator.generateProfile()) results = generator.takeResults() - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {31.2: 274.0, 1223.2: 227.2, 1213.4: 241.0, 175.6: 274.0, 1242.5: 221.8, 1172.3: 235.5, - 1159.1: 232.8}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 31.2: 274.0, + 1223.2: 227.2, + 1213.4: 241.0, + 175.6: 274.0, + 1242.5: 221.8, + 1172.3: 235.5, + 1159.1: 232.8, + }, + ) # lower tolerance req.setTolerance(15) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) results = generator.takeResults() - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {31.2: 274.0, 175.6: 274.0, 1242.5: 221.8}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + {31.2: 274.0, 175.6: 274.0, 1242.5: 221.8}, + ) self.assertAlmostEqual(results.zRange().lower(), 221.75, 2) self.assertAlmostEqual(results.zRange().upper(), 274.0, 2) @@ -123,44 +146,62 @@ def testPointGenerationAbsolute(self): features = results.asFeatures(Qgis.ProfileExportType.Features3D) self.assertEqual(len(features), 3) self.assertEqual(features[0].layerIdentifier, vl.id()) - self.assertCountEqual([f.geometry.asWkt(-2) for f in features], - ['Point Z (-347400 6632600 300)', 'Point Z (-347500 6632700 300)', 'Point Z (-346400 6632300 200)']) + self.assertCountEqual( + [f.geometry.asWkt(-2) for f in features], + [ + "Point Z (-347400 6632600 300)", + "Point Z (-347500 6632700 300)", + "Point Z (-346400 6632300 200)", + ], + ) features = results.asFeatures(Qgis.ProfileExportType.Profile2D) self.assertEqual(len(features), 3) self.assertEqual(features[0].layerIdentifier, vl.id()) - self.assertCountEqual([f.geometry.asWkt(-2) for f in features], - ['Point (200 300)', 'Point (0 300)', 'Point (1200 200)']) + self.assertCountEqual( + [f.geometry.asWkt(-2) for f in features], + ["Point (200 300)", "Point (0 300)", "Point (1200 200)"], + ) features = results.asFeatures(Qgis.ProfileExportType.DistanceVsElevationTable) self.assertEqual(len(features), 3) self.assertEqual(features[0].layerIdentifier, vl.id()) - self.assertCountEqual([f.attributes['distance'] for f in features], - [31.204980351872074, 175.61729584080234, - 1242.5349752853108]) - self.assertCountEqual([f.attributes['elevation'] for f in features], - [274.0, 274.0, - 221.75]) - self.assertCountEqual([f.geometry.asWkt(-1) for f in features], - ['Point Z (-347530 6632710 270)', 'Point Z (-347390 6632650 270)', 'Point Z (-346400 6632270 220)']) + self.assertCountEqual( + [f.attributes["distance"] for f in features], + [31.204980351872074, 175.61729584080234, 1242.5349752853108], + ) + self.assertCountEqual( + [f.attributes["elevation"] for f in features], [274.0, 274.0, 221.75] + ) + self.assertCountEqual( + [f.geometry.asWkt(-1) for f in features], + [ + "Point Z (-347530 6632710 270)", + "Point Z (-347390 6632650 270)", + "Point Z (-346400 6632270 220)", + ], + ) def testPointGenerationTerrain(self): """ Points layer with terrain clamping """ - vl = QgsVectorLayer(os.path.join(unitTestDataPath(), '3d', 'points_with_z.shp'), 'trees') + vl = QgsVectorLayer( + os.path.join(unitTestDataPath(), "3d", "points_with_z.shp"), "trees" + ) self.assertTrue(vl.isValid()) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Terrain) vl.elevationProperties().setZScale(2.5) vl.elevationProperties().setZOffset(10) - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) curve = QgsLineString() curve.fromWkt( - 'LineString (-347557.39478182751918212 6632716.59644229710102081, -346435.3875386503059417 6632277.86440025269985199, -346234.1061912341392599 6632242.03022097796201706, -346185.31071307259844616 6632150.53869942482560873)') + "LineString (-347557.39478182751918212 6632716.59644229710102081, -346435.3875386503059417 6632277.86440025269985199, -346234.1061912341392599 6632242.03022097796201706, -346185.31071307259844616 6632150.53869942482560873)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) terrain_provider = QgsRasterDemTerrainProvider() @@ -169,7 +210,7 @@ def testPointGenerationTerrain(self): terrain_provider.setOffset(-5) req.setTerrainProvider(terrain_provider) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) @@ -184,13 +225,17 @@ def testPointGenerationTerrain(self): results = generator.takeResults() if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {175.6: 69.5, 31.2: 69.5, 1242.5: 55.2}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + {175.6: 69.5, 31.2: 69.5, 1242.5: 55.2}, + ) self.assertAlmostEqual(results.zRange().lower(), 55.249, 2) self.assertAlmostEqual(results.zRange().upper(), 69.5, 2) else: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {31.2: 67.2, 175.6: 65.8, 1242.5: 52.2}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + {31.2: 67.2, 175.6: 65.8, 1242.5: 52.2}, + ) self.assertAlmostEqual(results.zRange().lower(), 52.25, 2) self.assertAlmostEqual(results.zRange().upper(), 67.25, 2) @@ -201,13 +246,17 @@ def testPointGenerationTerrain(self): results = generator.takeResults() if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {175.6: 69.5, 31.2: 69.5, 1223.2: 56.8, 1242.5: 55.2}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + {175.6: 69.5, 31.2: 69.5, 1223.2: 56.8, 1242.5: 55.2}, + ) self.assertAlmostEqual(results.zRange().lower(), 55.249, 2) self.assertAlmostEqual(results.zRange().upper(), 69.5, 2) else: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {31.2: 67.2, 175.6: 65.8, 1242.5: 52.2}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + {31.2: 67.2, 175.6: 65.8, 1242.5: 52.2}, + ) self.assertAlmostEqual(results.zRange().lower(), 52.25, 2) self.assertAlmostEqual(results.zRange().upper(), 67.25, 2) @@ -215,19 +264,22 @@ def testPointGenerationRelative(self): """ Points layer with relative clamping """ - vl = QgsVectorLayer(os.path.join(unitTestDataPath(), '3d', 'points_with_z.shp'), 'trees') + vl = QgsVectorLayer( + os.path.join(unitTestDataPath(), "3d", "points_with_z.shp"), "trees" + ) self.assertTrue(vl.isValid()) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Relative) vl.elevationProperties().setZScale(2.5) vl.elevationProperties().setZOffset(10) - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) curve = QgsLineString() curve.fromWkt( - 'LineString (-347557.39478182751918212 6632716.59644229710102081, -346435.3875386503059417 6632277.86440025269985199, -346234.1061912341392599 6632242.03022097796201706, -346185.31071307259844616 6632150.53869942482560873)') + "LineString (-347557.39478182751918212 6632716.59644229710102081, -346435.3875386503059417 6632277.86440025269985199, -346234.1061912341392599 6632242.03022097796201706, -346185.31071307259844616 6632150.53869942482560873)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) terrain_provider = QgsRasterDemTerrainProvider() @@ -236,7 +288,7 @@ def testPointGenerationRelative(self): terrain_provider.setOffset(-5) req.setTerrainProvider(terrain_provider) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) @@ -249,13 +301,17 @@ def testPointGenerationRelative(self): self.assertTrue(generator.generateProfile()) results = generator.takeResults() if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {31.2: 333.5, 175.6: 333.5, 1242.5: 267.0}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + {31.2: 333.5, 175.6: 333.5, 1242.5: 267.0}, + ) self.assertAlmostEqual(results.zRange().lower(), 267.0, 2) self.assertAlmostEqual(results.zRange().upper(), 333.5, 2) else: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {31.2: 331.2, 175.6: 329.8, 1242.5: 264.0}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + {31.2: 331.2, 175.6: 329.8, 1242.5: 264.0}, + ) self.assertAlmostEqual(results.zRange().lower(), 264.0, 2) self.assertAlmostEqual(results.zRange().upper(), 331.25, 2) @@ -263,7 +319,9 @@ def testPointGenerationRelativeExtrusion(self): """ Points layer with relative clamping and extrusion """ - vl = QgsVectorLayer(os.path.join(unitTestDataPath(), '3d', 'points_with_z.shp'), 'trees') + vl = QgsVectorLayer( + os.path.join(unitTestDataPath(), "3d", "points_with_z.shp"), "trees" + ) self.assertTrue(vl.isValid()) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Relative) @@ -272,12 +330,13 @@ def testPointGenerationRelativeExtrusion(self): vl.elevationProperties().setExtrusionEnabled(True) vl.elevationProperties().setExtrusionHeight(7) - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) curve = QgsLineString() curve.fromWkt( - 'LineString (-347557.39478182751918212 6632716.59644229710102081, -346435.3875386503059417 6632277.86440025269985199, -346234.1061912341392599 6632242.03022097796201706, -346185.31071307259844616 6632150.53869942482560873)') + "LineString (-347557.39478182751918212 6632716.59644229710102081, -346435.3875386503059417 6632277.86440025269985199, -346234.1061912341392599 6632242.03022097796201706, -346185.31071307259844616 6632150.53869942482560873)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) terrain_provider = QgsRasterDemTerrainProvider() @@ -286,7 +345,7 @@ def testPointGenerationRelativeExtrusion(self): terrain_provider.setOffset(-5) req.setTerrainProvider(terrain_provider) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) @@ -296,33 +355,49 @@ def testPointGenerationRelativeExtrusion(self): results = generator.takeResults() if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {31.2: 333.5, 175.6: 333.5, 1242.5: 267.0}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + {31.2: 333.5, 175.6: 333.5, 1242.5: 267.0}, + ) else: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {31.2: 331.2, 175.6: 329.8, 1242.5: 264.0}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + {31.2: 331.2, 175.6: 329.8, 1242.5: 264.0}, + ) if QgsProjUtils.projVersionMajor() >= 8: - self.assertCountEqual([g.asWkt(1) for g in results.asGeometries()], - ['LineString Z (-347395 6632649.6 333.5, -347395 6632649.6 340.5)', - 'LineString Z (-347533.4 6632692.2 333.5, -347533.4 6632692.2 340.5)', - 'LineString Z (-346399.2 6632265.6 267, -346399.2 6632265.6 274)']) + self.assertCountEqual( + [g.asWkt(1) for g in results.asGeometries()], + [ + "LineString Z (-347395 6632649.6 333.5, -347395 6632649.6 340.5)", + "LineString Z (-347533.4 6632692.2 333.5, -347533.4 6632692.2 340.5)", + "LineString Z (-346399.2 6632265.6 267, -346399.2 6632265.6 274)", + ], + ) self.assertAlmostEqual(results.zRange().lower(), 267.0, 2) self.assertAlmostEqual(results.zRange().upper(), 340.5, 2) else: - self.assertCountEqual([g.asWkt(1) for g in results.asGeometries()], - ['LineString Z (-347395 6632649.6 329.8, -347395 6632649.6 336.8)', - 'LineString Z (-347533.4 6632692.2 331.3, -347533.4 6632692.2 338.3)', - 'LineString Z (-346399.2 6632265.6 264, -346399.2 6632265.6 271)']) + self.assertCountEqual( + [g.asWkt(1) for g in results.asGeometries()], + [ + "LineString Z (-347395 6632649.6 329.8, -347395 6632649.6 336.8)", + "LineString Z (-347533.4 6632692.2 331.3, -347533.4 6632692.2 338.3)", + "LineString Z (-346399.2 6632265.6 264, -346399.2 6632265.6 271)", + ], + ) self.assertAlmostEqual(results.zRange().lower(), 264.0, 2) self.assertAlmostEqual(results.zRange().upper(), 338.25, 2) def testPointGenerationMultiPoint(self): - vl = QgsVectorLayer('MultipointZ?crs=EPSG:27700', 'trees', 'memory') + vl = QgsVectorLayer("MultipointZ?crs=EPSG:27700", "trees", "memory") self.assertTrue(vl.isValid()) f = QgsFeature() - f.setGeometry(QgsGeometry.fromWkt('MultiPoint Z(322069 129893 89.1, 322077 129889 90.2, 322093 129888 92.4)')) + f.setGeometry( + QgsGeometry.fromWkt( + "MultiPoint Z(322069 129893 89.1, 322077 129889 90.2, 322093 129888 92.4)" + ) + ) self.assertTrue(vl.dataProvider().addFeature(f)) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) @@ -331,31 +406,36 @@ def testPointGenerationMultiPoint(self): curve = QgsLineString() curve.fromWkt( - 'LineString (-347557.39478182751918212 6632716.59644229710102081, -346435.3875386503059417 6632277.86440025269985199, -346234.1061912341392599 6632242.03022097796201706, -346185.31071307259844616 6632150.53869942482560873)') + "LineString (-347557.39478182751918212 6632716.59644229710102081, -346435.3875386503059417 6632277.86440025269985199, -346234.1061912341392599 6632242.03022097796201706, -346185.31071307259844616 6632150.53869942482560873)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) req.setTolerance(110) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) results = generator.takeResults() - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {1158.2: 232.8, 1172.4: 235.5, 1196.5: 241.0}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + {1158.2: 232.8, 1172.4: 235.5, 1196.5: 241.0}, + ) self.assertAlmostEqual(results.zRange().lower(), 232.75, 2) self.assertAlmostEqual(results.zRange().upper(), 241.0, 2) def testLineGenerationAbsolute(self): - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") self.assertTrue(vl.isValid()) - for line in ['LineStringZ(322006 129874 12, 322008 129910 13, 322038 129909 14, 322037 129868 15)', - 'LineStringZ(322068 129900 16, 322128 129813 17)', - 'LineStringZ(321996 129914 11, 321990 129896 15)', - 'LineStringZ(321595 130176 1, 321507 130104 10)', - 'LineStringZ(321558 129930 1, 321568 130029 10, 321516 130049 5)', - 'LineStringZ(321603 129967 3, 321725 130042 9)']: + for line in [ + "LineStringZ(322006 129874 12, 322008 129910 13, 322038 129909 14, 322037 129868 15)", + "LineStringZ(322068 129900 16, 322128 129813 17)", + "LineStringZ(321996 129914 11, 321990 129896 15)", + "LineStringZ(321595 130176 1, 321507 130104 10)", + "LineStringZ(321558 129930 1, 321568 130029 10, 321516 130049 5)", + "LineStringZ(321603 129967 3, 321725 130042 9)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -366,7 +446,8 @@ def testLineGenerationAbsolute(self): curve = QgsLineString() curve.fromWkt( - 'LineString (-347692.88994020794052631 6632796.97473032586276531, -346576.99897185183363035 6632367.38372825458645821, -346396.02439485350623727 6632344.35087973903864622, -346374.34608158958144486 6632220.09952207934111357)') + "LineString (-347692.88994020794052631 6632796.97473032586276531, -346576.99897185183363035 6632367.38372825458645821, -346396.02439485350623727 6632344.35087973903864622, -346374.34608158958144486 6632220.09952207934111357)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) @@ -376,23 +457,34 @@ def testLineGenerationAbsolute(self): self.assertFalse(generator.generateProfile()) # set correct crs for linestring and re-try - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) results = generator.takeResults() - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {675.2: 27.7, 1195.7: 47.5, 1223.1: 41.4, 1272.0: 46.2, 1339.4: 50.5, 1444.4: 51.8}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 675.2: 27.7, + 1195.7: 47.5, + 1223.1: 41.4, + 1272.0: 46.2, + 1339.4: 50.5, + 1444.4: 51.8, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 27.7064, 2) self.assertAlmostEqual(results.zRange().upper(), 51.7598, 2) def testLineGenerationFollowingLinestringExactly(self): - vl = QgsVectorLayer('MultiLineString?crs=EPSG:3857', 'lines', 'memory') + vl = QgsVectorLayer("MultiLineString?crs=EPSG:3857", "lines", "memory") self.assertTrue(vl.isValid()) - for line in ['MultiLineString ((872381.44973557780031115 6035318.57090197317302227, 868258.19322114891838282 6039288.30190788581967354, 870254.02483185648452491 6048565.62906535062938929, 884224.8461068095639348 6045999.55985158402472734, 876087.99415546329692006 6035472.0964104887098074))']: + for line in [ + "MultiLineString ((872381.44973557780031115 6035318.57090197317302227, 868258.19322114891838282 6039288.30190788581967354, 870254.02483185648452491 6048565.62906535062938929, 884224.8461068095639348 6045999.55985158402472734, 876087.99415546329692006 6035472.0964104887098074))" + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -401,16 +493,19 @@ def testLineGenerationFollowingLinestringExactly(self): curve = QgsLineString() curve.fromWkt( - 'LineString(872381.44973557780031115 6035318.57090197317302227, 868258.19322114891838282 6039288.30190788581967354, 870254.02483185648452491 6048565.62906535062938929, 884224.8461068095639348 6045999.55985158402472734, 876087.99415546329692006 6035472.0964104887098074)') + "LineString(872381.44973557780031115 6035318.57090197317302227, 868258.19322114891838282 6039288.30190788581967354, 870254.02483185648452491 6048565.62906535062938929, 884224.8461068095639348 6045999.55985158402472734, 876087.99415546329692006 6035472.0964104887098074)" + ) req = QgsProfileRequest(curve) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) results = generator.takeResults() - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {0.0: 0.0, 5723.6: 0.0, 15213.2: 0.0, 29417.7: 0.0, 42723.2: 0.0}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + {0.0: 0.0, 5723.6: 0.0, 15213.2: 0.0, 29417.7: 0.0, 42723.2: 0.0}, + ) self.assertAlmostEqual(results.zRange().lower(), 0.0, 2) self.assertAlmostEqual(results.zRange().upper(), 0.0, 2) @@ -418,25 +513,30 @@ def testLineGenerationFollowingLinestringExactly(self): # try with just a part of the original linestring as the capture curve curve = QgsLineString() curve.fromWkt( - 'LineString (872381.44973557780031115 6035318.57090197317302227, 868258.19322114891838282 6039288.30190788581967354, 870254.02483185648452491 6048565.62906535062938929)') + "LineString (872381.44973557780031115 6035318.57090197317302227, 868258.19322114891838282 6039288.30190788581967354, 870254.02483185648452491 6048565.62906535062938929)" + ) req = QgsProfileRequest(curve) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) results = generator.takeResults() - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {0.0: 0.0, 5723.6: 0.0, 15213.2: 0.0}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + {0.0: 0.0, 5723.6: 0.0, 15213.2: 0.0}, + ) self.assertAlmostEqual(results.zRange().lower(), 0.0, 2) self.assertAlmostEqual(results.zRange().upper(), 0.0, 2) def testLineGenerationFollowingLinestringZExactly(self): - vl = QgsVectorLayer('MultiLineStringZ?crs=EPSG:3857', 'lines', 'memory') + vl = QgsVectorLayer("MultiLineStringZ?crs=EPSG:3857", "lines", "memory") self.assertTrue(vl.isValid()) - for line in ['MultiLineStringZ ((872381.44973557780031115 6035318.57090197317302227 690, 868258.19322114891838282 6039288.30190788581967354 705, 870254.02483185648452491 6048565.62906535062938929 680, 884224.8461068095639348 6045999.55985158402472734 700, 876087.99415546329692006 6035472.0964104887098074 710))']: + for line in [ + "MultiLineStringZ ((872381.44973557780031115 6035318.57090197317302227 690, 868258.19322114891838282 6039288.30190788581967354 705, 870254.02483185648452491 6048565.62906535062938929 680, 884224.8461068095639348 6045999.55985158402472734 700, 876087.99415546329692006 6035472.0964104887098074 710))" + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -445,16 +545,19 @@ def testLineGenerationFollowingLinestringZExactly(self): curve = QgsLineString() curve.fromWkt( - 'LineStringZ (872381.44973557780031115 6035318.57090197317302227 690, 868258.19322114891838282 6039288.30190788581967354 705, 870254.02483185648452491 6048565.62906535062938929 680, 884224.8461068095639348 6045999.55985158402472734 700, 876087.99415546329692006 6035472.0964104887098074 710)') + "LineStringZ (872381.44973557780031115 6035318.57090197317302227 690, 868258.19322114891838282 6039288.30190788581967354 705, 870254.02483185648452491 6048565.62906535062938929 680, 884224.8461068095639348 6045999.55985158402472734 700, 876087.99415546329692006 6035472.0964104887098074 710)" + ) req = QgsProfileRequest(curve) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) results = generator.takeResults() - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {0.0: 690.0, 5723.6: 705.0, 15213.2: 680.0, 29417.7: 700.0, 42723.2: 710.0}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + {0.0: 690.0, 5723.6: 705.0, 15213.2: 680.0, 29417.7: 700.0, 42723.2: 710.0}, + ) self.assertAlmostEqual(results.zRange().lower(), 680.0, 2) self.assertAlmostEqual(results.zRange().upper(), 710.0, 2) @@ -462,30 +565,35 @@ def testLineGenerationFollowingLinestringZExactly(self): # try with just a part of the original linestring as the capture curve curve = QgsLineString() curve.fromWkt( - 'LineString (872381.44973557780031115 6035318.57090197317302227, 868258.19322114891838282 6039288.30190788581967354, 870254.02483185648452491 6048565.62906535062938929)') + "LineString (872381.44973557780031115 6035318.57090197317302227, 868258.19322114891838282 6039288.30190788581967354, 870254.02483185648452491 6048565.62906535062938929)" + ) req = QgsProfileRequest(curve) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) results = generator.takeResults() - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {0.0: 690.0, 5723.6: 705.0, 15213.2: 680.0}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + {0.0: 690.0, 5723.6: 705.0, 15213.2: 680.0}, + ) self.assertAlmostEqual(results.zRange().lower(), 680.0, 2) self.assertAlmostEqual(results.zRange().upper(), 705.0, 2) def testLineGenerationTerrain(self): - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") self.assertTrue(vl.isValid()) - for line in ['LineStringZ(322006 129874 12, 322008 129910 13, 322038 129909 14, 322037 129868 15)', - 'LineStringZ(322068 129900 16, 322128 129813 17)', - 'LineStringZ(321996 129914 11, 321990 129896 15)', - 'LineStringZ(321595 130176 1, 321507 130104 10)', - 'LineStringZ(321558 129930 1, 321568 130029 10, 321516 130049 5)', - 'LineStringZ(321603 129967 3, 321725 130042 9)']: + for line in [ + "LineStringZ(322006 129874 12, 322008 129910 13, 322038 129909 14, 322037 129868 15)", + "LineStringZ(322068 129900 16, 322128 129813 17)", + "LineStringZ(321996 129914 11, 321990 129896 15)", + "LineStringZ(321595 130176 1, 321507 130104 10)", + "LineStringZ(321558 129930 1, 321568 130029 10, 321516 130049 5)", + "LineStringZ(321603 129967 3, 321725 130042 9)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -496,11 +604,12 @@ def testLineGenerationTerrain(self): curve = QgsLineString() curve.fromWkt( - 'LineString (-347692.88994020794052631 6632796.97473032586276531, -346576.99897185183363035 6632367.38372825458645821, -346396.02439485350623727 6632344.35087973903864622, -346374.34608158958144486 6632220.09952207934111357)') + "LineString (-347692.88994020794052631 6632796.97473032586276531, -346576.99897185183363035 6632367.38372825458645821, -346396.02439485350623727 6632344.35087973903864622, -346374.34608158958144486 6632220.09952207934111357)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) terrain_provider = QgsRasterDemTerrainProvider() terrain_provider.setLayer(rl) @@ -508,33 +617,53 @@ def testLineGenerationTerrain(self): terrain_provider.setOffset(-5) req.setTerrainProvider(terrain_provider) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) results = generator.takeResults() if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {675.2: 66.5, 1195.7: 49.2, 1223.1: 50.0, 1272.0: 53.8, 1339.4: 58.2, 1444.4: 58.2}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 675.2: 66.5, + 1195.7: 49.2, + 1223.1: 50.0, + 1272.0: 53.8, + 1339.4: 58.2, + 1444.4: 58.2, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 49.25, 2) self.assertAlmostEqual(results.zRange().upper(), 66.5, 2) else: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {675.2: 62.7, 1195.7: 53.0, 1223.1: 56.0, 1272.0: 58.2, 1339.4: 57.5, 1444.4: 52.2}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 675.2: 62.7, + 1195.7: 53.0, + 1223.1: 56.0, + 1272.0: 58.2, + 1339.4: 57.5, + 1444.4: 52.2, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 52.25, 2) self.assertAlmostEqual(results.zRange().upper(), 62.7499, 2) def testLineGenerationTerrainTolerance(self): - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") self.assertTrue(vl.isValid()) - for line in ['LineStringZ(322006 129874 12, 322008 129910 13, 322038 129909 14, 322037 129868 15)', - 'LineStringZ(322068 129900 16, 322128 129813 17)', - 'LineStringZ(321996 129914 11, 321990 129896 15)', - 'LineStringZ(321595 130176 1, 321507 130104 10)', - 'LineStringZ(321558 129930 1, 321568 130029 10, 321516 130049 5)', - 'LineStringZ(321603 129967 3, 321725 130042 9)']: + for line in [ + "LineStringZ(322006 129874 12, 322008 129910 13, 322038 129909 14, 322037 129868 15)", + "LineStringZ(322068 129900 16, 322128 129813 17)", + "LineStringZ(321996 129914 11, 321990 129896 15)", + "LineStringZ(321595 130176 1, 321507 130104 10)", + "LineStringZ(321558 129930 1, 321568 130029 10, 321516 130049 5)", + "LineStringZ(321603 129967 3, 321725 130042 9)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -545,11 +674,12 @@ def testLineGenerationTerrainTolerance(self): curve = QgsLineString() curve.fromWkt( - 'LineString (-347692.88994020794052631 6632796.97473032586276531, -346576.99897185183363035 6632367.38372825458645821, -346396.02439485350623727 6632344.35087973903864622, -346374.34608158958144486 6632220.09952207934111357)') + "LineString (-347692.88994020794052631 6632796.97473032586276531, -346576.99897185183363035 6632367.38372825458645821, -346396.02439485350623727 6632344.35087973903864622, -346374.34608158958144486 6632220.09952207934111357)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) terrain_provider = QgsRasterDemTerrainProvider() terrain_provider.setLayer(rl) @@ -557,7 +687,7 @@ def testLineGenerationTerrainTolerance(self): terrain_provider.setOffset(-5) req.setTerrainProvider(terrain_provider) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) # very small tolerance req.setTolerance(0.1) @@ -566,18 +696,44 @@ def testLineGenerationTerrainTolerance(self): results = generator.takeResults() if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 2), - {675.09: 66.5, 675.24: 66.5, 1195.73: 49.25, 1195.74: 49.25, 1223.14: 50.0, - 1223.15: 50.0, 1271.97: 53.75, 1271.99: 53.75, 1339.33: 58.25, 1339.51: 58.25, - 1444.18: 58.25, 1444.59: 58.25}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 2), + { + 675.09: 66.5, + 675.24: 66.5, + 1195.73: 49.25, + 1195.74: 49.25, + 1223.14: 50.0, + 1223.15: 50.0, + 1271.97: 53.75, + 1271.99: 53.75, + 1339.33: 58.25, + 1339.51: 58.25, + 1444.18: 58.25, + 1444.59: 58.25, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 49.25, 2) self.assertAlmostEqual(results.zRange().upper(), 66.5, 2) else: # TODO find a way to test with an older proj version - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 2), - {675.09: 66.5, 675.24: 66.5, 1195.73: 49.25, 1195.74: 49.25, 1223.14: 50.0, - 1223.15: 50.0, 1271.97: 53.75, 1271.99: 53.75, 1339.33: 58.25, 1339.51: 58.25, - 1444.18: 58.25, 1444.59: 58.25}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 2), + { + 675.09: 66.5, + 675.24: 66.5, + 1195.73: 49.25, + 1195.74: 49.25, + 1223.14: 50.0, + 1223.15: 50.0, + 1271.97: 53.75, + 1271.99: 53.75, + 1339.33: 58.25, + 1339.51: 58.25, + 1444.18: 58.25, + 1444.59: 58.25, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 52.25, 2) self.assertAlmostEqual(results.zRange().upper(), 62.7499, 2) @@ -588,18 +744,44 @@ def testLineGenerationTerrainTolerance(self): results = generator.takeResults() if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 2), - {674.43: 66.5, 675.91: 66.5, 1195.73: 49.25, 1195.91: 49.25, 1223.06: 50.0, - 1223.23: 50.0, 1271.86: 53.75, 1272.1: 53.75, 1338.5: 58.25, 1340.34: 58.25, - 1442.29: 56.75, 1446.48: 57.5}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 2), + { + 674.43: 66.5, + 675.91: 66.5, + 1195.73: 49.25, + 1195.91: 49.25, + 1223.06: 50.0, + 1223.23: 50.0, + 1271.86: 53.75, + 1272.1: 53.75, + 1338.5: 58.25, + 1340.34: 58.25, + 1442.29: 56.75, + 1446.48: 57.5, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 49.25, 2) self.assertAlmostEqual(results.zRange().upper(), 66.5, 2) else: # TODO find a way to test with an older proj version - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 2), - {675.09: 66.5, 675.24: 66.5, 1195.73: 49.25, 1195.74: 49.25, 1223.14: 50.0, - 1223.15: 50.0, 1271.97: 53.75, 1271.99: 53.75, 1339.33: 58.25, 1339.51: 58.25, - 1444.18: 58.25, 1444.59: 58.25}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 2), + { + 675.09: 66.5, + 675.24: 66.5, + 1195.73: 49.25, + 1195.74: 49.25, + 1223.14: 50.0, + 1223.15: 50.0, + 1271.97: 53.75, + 1271.99: 53.75, + 1339.33: 58.25, + 1339.51: 58.25, + 1444.18: 58.25, + 1444.59: 58.25, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 52.25, 2) self.assertAlmostEqual(results.zRange().upper(), 62.7499, 2) @@ -610,31 +792,59 @@ def testLineGenerationTerrainTolerance(self): results = generator.takeResults() if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 2), - {664.1: 65.75, 686.24: 67.25, 1195.73: 49.25, 1198.44: 49.25, 1221.85: 50.0, - 1224.44: 49.25, 1270.21: 54.5, 1273.75: 53.0, 1325.61: 59.0, 1353.23: 57.5, - 1412.92: 56.0, 1475.85: 57.5}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 2), + { + 664.1: 65.75, + 686.24: 67.25, + 1195.73: 49.25, + 1198.44: 49.25, + 1221.85: 50.0, + 1224.44: 49.25, + 1270.21: 54.5, + 1273.75: 53.0, + 1325.61: 59.0, + 1353.23: 57.5, + 1412.92: 56.0, + 1475.85: 57.5, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 49.25, 2) self.assertAlmostEqual(results.zRange().upper(), 67.25, 2) else: # TODO find a way to test with an older proj version - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 2), - {675.09: 66.5, 675.24: 66.5, 1195.73: 49.25, 1195.74: 49.25, 1223.14: 50.0, - 1223.15: 50.0, 1271.97: 53.75, 1271.99: 53.75, 1339.33: 58.25, 1339.51: 58.25, - 1444.18: 58.25, 1444.59: 58.25}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 2), + { + 675.09: 66.5, + 675.24: 66.5, + 1195.73: 49.25, + 1195.74: 49.25, + 1223.14: 50.0, + 1223.15: 50.0, + 1271.97: 53.75, + 1271.99: 53.75, + 1339.33: 58.25, + 1339.51: 58.25, + 1444.18: 58.25, + 1444.59: 58.25, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 52.25, 2) self.assertAlmostEqual(results.zRange().upper(), 62.7499, 2) def testLineGenerationRelative(self): - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") self.assertTrue(vl.isValid()) - for line in ['LineStringZ(322006 129874 12, 322008 129910 13, 322038 129909 14, 322037 129868 15)', - 'LineStringZ(322068 129900 16, 322128 129813 17)', - 'LineStringZ(321996 129914 11, 321990 129896 15)', - 'LineStringZ(321595 130176 1, 321507 130104 10)', - 'LineStringZ(321558 129930 1, 321568 130029 10, 321516 130049 5)', - 'LineStringZ(321603 129967 3, 321725 130042 9)']: + for line in [ + "LineStringZ(322006 129874 12, 322008 129910 13, 322038 129909 14, 322037 129868 15)", + "LineStringZ(322068 129900 16, 322128 129813 17)", + "LineStringZ(321996 129914 11, 321990 129896 15)", + "LineStringZ(321595 130176 1, 321507 130104 10)", + "LineStringZ(321558 129930 1, 321568 130029 10, 321516 130049 5)", + "LineStringZ(321603 129967 3, 321725 130042 9)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -645,11 +855,12 @@ def testLineGenerationRelative(self): curve = QgsLineString() curve.fromWkt( - 'LineString (-347692.88994020794052631 6632796.97473032586276531, -346576.99897185183363035 6632367.38372825458645821, -346396.02439485350623727 6632344.35087973903864622, -346374.34608158958144486 6632220.09952207934111357)') + "LineString (-347692.88994020794052631 6632796.97473032586276531, -346576.99897185183363035 6632367.38372825458645821, -346396.02439485350623727 6632344.35087973903864622, -346374.34608158958144486 6632220.09952207934111357)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) terrain_provider = QgsRasterDemTerrainProvider() terrain_provider.setLayer(rl) @@ -657,33 +868,53 @@ def testLineGenerationRelative(self): terrain_provider.setOffset(-5) req.setTerrainProvider(terrain_provider) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) results = generator.takeResults() if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {675.2: 84.2, 1195.7: 86.8, 1223.1: 81.4, 1272.0: 90.0, 1339.4: 98.7, 1444.4: 100.0}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 675.2: 84.2, + 1195.7: 86.8, + 1223.1: 81.4, + 1272.0: 90.0, + 1339.4: 98.7, + 1444.4: 100.0, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 81.358, 2) self.assertAlmostEqual(results.zRange().upper(), 100.009, 2) else: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {675.2: 80.5, 1195.7: 90.5, 1223.1: 87.4, 1272.0: 94.5, 1339.4: 98.0, 1444.4: 94.0}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 675.2: 80.5, + 1195.7: 90.5, + 1223.1: 87.4, + 1272.0: 94.5, + 1339.4: 98.0, + 1444.4: 94.0, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 80.4564, 2) self.assertAlmostEqual(results.zRange().upper(), 97.9811, 2) def testLineGenerationRelativeExtrusion(self): - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") self.assertTrue(vl.isValid()) - for line in ['LineStringZ(322006 129874 12, 322008 129910 13, 322038 129909 14, 322037 129868 15)', - 'LineStringZ(322068 129900 16, 322128 129813 17)', - 'LineStringZ(321996 129914 11, 321990 129896 15)', - 'LineStringZ(321595 130176 1, 321507 130104 10)', - 'LineStringZ(321558 129930 1, 321568 130029 10, 321516 130049 5)', - 'LineStringZ(321603 129967 3, 321725 130042 9)']: + for line in [ + "LineStringZ(322006 129874 12, 322008 129910 13, 322038 129909 14, 322037 129868 15)", + "LineStringZ(322068 129900 16, 322128 129813 17)", + "LineStringZ(321996 129914 11, 321990 129896 15)", + "LineStringZ(321595 130176 1, 321507 130104 10)", + "LineStringZ(321558 129930 1, 321568 130029 10, 321516 130049 5)", + "LineStringZ(321603 129967 3, 321725 130042 9)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -696,11 +927,12 @@ def testLineGenerationRelativeExtrusion(self): curve = QgsLineString() curve.fromWkt( - 'LineString (-347692.88994020794052631 6632796.97473032586276531, -346576.99897185183363035 6632367.38372825458645821, -346396.02439485350623727 6632344.35087973903864622, -346374.34608158958144486 6632220.09952207934111357)') + "LineString (-347692.88994020794052631 6632796.97473032586276531, -346576.99897185183363035 6632367.38372825458645821, -346396.02439485350623727 6632344.35087973903864622, -346374.34608158958144486 6632220.09952207934111357)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) terrain_provider = QgsRasterDemTerrainProvider() terrain_provider.setLayer(rl) @@ -708,50 +940,77 @@ def testLineGenerationRelativeExtrusion(self): terrain_provider.setOffset(-5) req.setTerrainProvider(terrain_provider) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) results = generator.takeResults() if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {675.2: 84.2, 1195.7: 86.8, 1223.1: 81.4, 1272.0: 90.0, 1339.4: 98.7, 1444.4: 100.0}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 675.2: 84.2, + 1195.7: 86.8, + 1223.1: 81.4, + 1272.0: 90.0, + 1339.4: 98.7, + 1444.4: 100.0, + }, + ) else: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {675.2: 80.5, 1195.7: 90.5, 1223.1: 87.4, 1272.0: 94.5, 1339.4: 98.0, 1444.4: 94.0}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 675.2: 80.5, + 1195.7: 90.5, + 1223.1: 87.4, + 1272.0: 94.5, + 1339.4: 98.0, + 1444.4: 94.0, + }, + ) if QgsProjUtils.projVersionMajor() >= 8: - self.assertCountEqual([g.asWkt(1) for g in results.asGeometries()], - ['LineString Z (-346549.8 6632363.9 81.4, -346549.8 6632363.9 88.4)', - 'LineString Z (-346501.4 6632357.8 90, -346501.4 6632357.8 97)', - 'LineString Z (-346434.5 6632349.2 98.7, -346434.5 6632349.2 105.7)', - 'LineString Z (-346384.6 6632279.1 100, -346384.6 6632279.1 107)', - 'LineString Z (-346577 6632367.4 86.8, -346577 6632367.4 93.8)', - 'LineString Z (-347062.8 6632554.4 84.2, -347062.8 6632554.4 91.2)']) + self.assertCountEqual( + [g.asWkt(1) for g in results.asGeometries()], + [ + "LineString Z (-346549.8 6632363.9 81.4, -346549.8 6632363.9 88.4)", + "LineString Z (-346501.4 6632357.8 90, -346501.4 6632357.8 97)", + "LineString Z (-346434.5 6632349.2 98.7, -346434.5 6632349.2 105.7)", + "LineString Z (-346384.6 6632279.1 100, -346384.6 6632279.1 107)", + "LineString Z (-346577 6632367.4 86.8, -346577 6632367.4 93.8)", + "LineString Z (-347062.8 6632554.4 84.2, -347062.8 6632554.4 91.2)", + ], + ) self.assertAlmostEqual(results.zRange().lower(), 81.3588, 2) self.assertAlmostEqual(results.zRange().upper(), 107.009, 2) else: - self.assertCountEqual([g.asWkt(1) for g in results.asGeometries()], - ['LineString Z (-346549.8 6632363.9 87.4, -346549.8 6632363.9 94.4)', - 'LineString Z (-346501.4 6632357.8 94.5, -346501.4 6632357.8 101.5)', - 'LineString Z (-346434.5 6632349.2 98, -346434.5 6632349.2 105)', - 'LineString Z (-346384.6 6632279.1 94, -346384.6 6632279.1 101)', - 'LineString Z (-346577 6632367.4 90.5, -346577 6632367.4 97.5)', - 'LineString Z (-347062.8 6632554.4 80.5, -347062.8 6632554.4 87.5)']) + self.assertCountEqual( + [g.asWkt(1) for g in results.asGeometries()], + [ + "LineString Z (-346549.8 6632363.9 87.4, -346549.8 6632363.9 94.4)", + "LineString Z (-346501.4 6632357.8 94.5, -346501.4 6632357.8 101.5)", + "LineString Z (-346434.5 6632349.2 98, -346434.5 6632349.2 105)", + "LineString Z (-346384.6 6632279.1 94, -346384.6 6632279.1 101)", + "LineString Z (-346577 6632367.4 90.5, -346577 6632367.4 97.5)", + "LineString Z (-347062.8 6632554.4 80.5, -347062.8 6632554.4 87.5)", + ], + ) self.assertAlmostEqual(results.zRange().lower(), 80.45645, 2) self.assertAlmostEqual(results.zRange().upper(), 104.9811499, 2) def testPolygonGenerationAbsolute(self): - vl = QgsVectorLayer('PolygonZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("PolygonZ?crs=EPSG:27700", "lines", "memory") self.assertTrue(vl.isValid()) for line in [ - 'PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))', - 'PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))', - 'PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))', - 'PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))', - 'PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))']: + "PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))", + "PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))", + "PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))", + "PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))", + "PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -762,7 +1021,8 @@ def testPolygonGenerationAbsolute(self): curve = QgsLineString() curve.fromWkt( - 'LineString (-347701.59207547508412972 6632766.96282589063048363, -346577.00878971704514697 6632369.7371364813297987, -346449.93654899462126195 6632331.81857067719101906, -346383.52035177784273401 6632216.85897350125014782)') + "LineString (-347701.59207547508412972 6632766.96282589063048363, -346577.00878971704514697 6632369.7371364813297987, -346449.93654899462126195 6632331.81857067719101906, -346383.52035177784273401 6632216.85897350125014782)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) @@ -772,30 +1032,48 @@ def testPolygonGenerationAbsolute(self): self.assertFalse(generator.generateProfile()) # set correct crs for linestring and re-try - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) results = generator.takeResults() - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {1041.8: 15.0, 1042.4: 15.0, 1049.5: 15.0, 1070.2: 15.0, 1073.1: 15.0, 1074.8: 15.0, - 1078.9: 17.5, 1083.9: 17.5, 1091.1: 17.5, 1186.8: 20.0, 1189.8: 20.0, 1192.7: 20.0, - 1199.2: 20.0, 1450.0: 22.5, 1455.6: 22.5, 1458.1: 22.5}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 1041.8: 15.0, + 1042.4: 15.0, + 1049.5: 15.0, + 1070.2: 15.0, + 1073.1: 15.0, + 1074.8: 15.0, + 1078.9: 17.5, + 1083.9: 17.5, + 1091.1: 17.5, + 1186.8: 20.0, + 1189.8: 20.0, + 1192.7: 20.0, + 1199.2: 20.0, + 1450.0: 22.5, + 1455.6: 22.5, + 1458.1: 22.5, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 15.0, 2) self.assertAlmostEqual(results.zRange().upper(), 22.5000, 2) def testPolygonGenerationTerrain(self): - vl = QgsVectorLayer('PolygonZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("PolygonZ?crs=EPSG:27700", "lines", "memory") self.assertTrue(vl.isValid()) for line in [ - 'PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))', - 'PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))', - 'PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))', - 'PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))', - 'PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))']: + "PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))", + "PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))", + "PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))", + "PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))", + "PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -806,11 +1084,12 @@ def testPolygonGenerationTerrain(self): curve = QgsLineString() curve.fromWkt( - 'LineString (-347701.59207547508412972 6632766.96282589063048363, -346577.00878971704514697 6632369.7371364813297987, -346449.93654899462126195 6632331.81857067719101906, -346383.52035177784273401 6632216.85897350125014782)') + "LineString (-347701.59207547508412972 6632766.96282589063048363, -346577.00878971704514697 6632369.7371364813297987, -346449.93654899462126195 6632331.81857067719101906, -346383.52035177784273401 6632216.85897350125014782)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) terrain_provider = QgsRasterDemTerrainProvider() terrain_provider.setLayer(rl) @@ -818,37 +1097,72 @@ def testPolygonGenerationTerrain(self): terrain_provider.setOffset(-5) req.setTerrainProvider(terrain_provider) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) results = generator.takeResults() if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {1041.8: 55.3, 1042.4: 55.2, 1049.5: 55.2, 1070.2: 55.2, 1073.1: 55.2, 1074.8: 55.3, - 1078.9: 54.5, 1083.9: 54.5, 1091.1: 54.5, 1186.8: 49.3, 1189.8: 49.2, 1192.7: 49.2, - 1199.2: 49.2, 1450.0: 53.0, 1455.6: 53.0, 1458.1: 53.0}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 1041.8: 55.3, + 1042.4: 55.2, + 1049.5: 55.2, + 1070.2: 55.2, + 1073.1: 55.2, + 1074.8: 55.3, + 1078.9: 54.5, + 1083.9: 54.5, + 1091.1: 54.5, + 1186.8: 49.3, + 1189.8: 49.2, + 1192.7: 49.2, + 1199.2: 49.2, + 1450.0: 53.0, + 1455.6: 53.0, + 1458.1: 53.0, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 49.25, 2) self.assertAlmostEqual(results.zRange().upper(), 55.250, 2) else: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {1041.8: 48.5, 1042.4: 48.5, 1049.5: 48.5, 1070.2: 48.5, 1073.1: 48.5, 1074.8: 48.5, - 1078.9: 48.5, 1083.9: 48.5, 1091.1: 48.5, 1186.8: 52.3, 1189.8: 52.2, 1192.7: 52.2, - 1199.2: 52.2, 1450.0: 54.5, 1455.6: 54.5, 1458.1: 54.5}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 1041.8: 48.5, + 1042.4: 48.5, + 1049.5: 48.5, + 1070.2: 48.5, + 1073.1: 48.5, + 1074.8: 48.5, + 1078.9: 48.5, + 1083.9: 48.5, + 1091.1: 48.5, + 1186.8: 52.3, + 1189.8: 52.2, + 1192.7: 52.2, + 1199.2: 52.2, + 1450.0: 54.5, + 1455.6: 54.5, + 1458.1: 54.5, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 48.5, 2) self.assertAlmostEqual(results.zRange().upper(), 54.500000, 2) def testPolygonGenerationRelative(self): - vl = QgsVectorLayer('PolygonZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("PolygonZ?crs=EPSG:27700", "lines", "memory") self.assertTrue(vl.isValid()) for line in [ - 'PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))', - 'PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))', - 'PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))', - 'PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))', - 'PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))']: + "PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))", + "PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))", + "PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))", + "PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))", + "PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -859,11 +1173,12 @@ def testPolygonGenerationRelative(self): curve = QgsLineString() curve.fromWkt( - 'LineString (-347701.59207547508412972 6632766.96282589063048363, -346577.00878971704514697 6632369.7371364813297987, -346449.93654899462126195 6632331.81857067719101906, -346383.52035177784273401 6632216.85897350125014782)') + "LineString (-347701.59207547508412972 6632766.96282589063048363, -346577.00878971704514697 6632369.7371364813297987, -346449.93654899462126195 6632331.81857067719101906, -346383.52035177784273401 6632216.85897350125014782)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) terrain_provider = QgsRasterDemTerrainProvider() terrain_provider.setLayer(rl) @@ -871,53 +1186,94 @@ def testPolygonGenerationRelative(self): terrain_provider.setOffset(-5) req.setTerrainProvider(terrain_provider) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) results = generator.takeResults() if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {1041.8: 60.3, 1042.4: 60.2, 1049.5: 60.2, 1070.2: 60.2, 1073.1: 60.2, 1074.8: 60.3, - 1078.9: 62.0, 1083.9: 62.0, 1091.1: 62.0, 1186.8: 59.3, 1189.8: 59.2, 1192.7: 59.2, - 1199.2: 59.2, 1450.0: 65.5, 1455.6: 65.5, 1458.1: 65.5}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 1041.8: 60.3, + 1042.4: 60.2, + 1049.5: 60.2, + 1070.2: 60.2, + 1073.1: 60.2, + 1074.8: 60.3, + 1078.9: 62.0, + 1083.9: 62.0, + 1091.1: 62.0, + 1186.8: 59.3, + 1189.8: 59.2, + 1192.7: 59.2, + 1199.2: 59.2, + 1450.0: 65.5, + 1455.6: 65.5, + 1458.1: 65.5, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 59.2499, 2) self.assertAlmostEqual(results.zRange().upper(), 65.5000, 2) else: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {1041.8: 53.5, 1042.4: 53.5, 1049.5: 53.5, 1070.2: 53.5, 1073.1: 53.5, 1074.8: 53.5, - 1078.9: 56.0, 1083.9: 56.0, 1091.1: 56.0, 1186.8: 62.3, 1189.8: 62.3, 1192.7: 62.3, - 1199.2: 62.2, 1450.0: 67.0, 1455.6: 67.0, 1458.1: 67.0}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 1041.8: 53.5, + 1042.4: 53.5, + 1049.5: 53.5, + 1070.2: 53.5, + 1073.1: 53.5, + 1074.8: 53.5, + 1078.9: 56.0, + 1083.9: 56.0, + 1091.1: 56.0, + 1186.8: 62.3, + 1189.8: 62.3, + 1192.7: 62.3, + 1199.2: 62.2, + 1450.0: 67.0, + 1455.6: 67.0, + 1458.1: 67.0, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 53.5, 2) self.assertAlmostEqual(results.zRange().upper(), 67.000, 2) if QgsProjUtils.projVersionMajor() >= 8: - self.assertCountEqual([g.asWkt(1) for g in results.asGeometries()], - [ - 'MultiLineString Z ((-346718.7 6632419.8 60.3, -346712 6632417.4 60.3),(-346719.3 6632420 60.3, -346718.7 6632419.8 60.2),(-346689.7 6632409.5 60.3, -346688.2 6632409 60.3),(-346692.5 6632410.5 60.3, -346689.7 6632409.5 60.3))', - 'MultiLineString Z ((-346684.3 6632407.6 62, -346679.6 6632406 62),(-346679.6 6632406 62, -346672.8 6632403.6 62))', - 'MultiLineString Z ((-346582.6 6632371.7 59.3, -346579.7 6632370.7 59.3),(-346579.7 6632370.7 59.3, -346577 6632369.7 59.2, -346570.8 6632367.9 59.3))', - 'MultiLineString Z ((-346387.6 6632223.9 65.5, -346384.8 6632219 65.5),(-346384.8 6632219 65.5, -346383.5 6632216.9 65.5))']) + self.assertCountEqual( + [g.asWkt(1) for g in results.asGeometries()], + [ + "MultiLineString Z ((-346718.7 6632419.8 60.3, -346712 6632417.4 60.3),(-346719.3 6632420 60.3, -346718.7 6632419.8 60.2),(-346689.7 6632409.5 60.3, -346688.2 6632409 60.3),(-346692.5 6632410.5 60.3, -346689.7 6632409.5 60.3))", + "MultiLineString Z ((-346684.3 6632407.6 62, -346679.6 6632406 62),(-346679.6 6632406 62, -346672.8 6632403.6 62))", + "MultiLineString Z ((-346582.6 6632371.7 59.3, -346579.7 6632370.7 59.3),(-346579.7 6632370.7 59.3, -346577 6632369.7 59.2, -346570.8 6632367.9 59.3))", + "MultiLineString Z ((-346387.6 6632223.9 65.5, -346384.8 6632219 65.5),(-346384.8 6632219 65.5, -346383.5 6632216.9 65.5))", + ], + ) else: - self.assertCountEqual([g.asWkt(1) for g in results.asGeometries()], - [ - 'MultiLineString Z ((-346684.3 6632407.6 56, -346679.6 6632406 56),(-346679.6 6632406 56, -346672.8 6632403.6 56))', - 'MultiLineString Z ((-346718.7 6632419.8 53.5, -346712 6632417.4 53.5),(-346719.3 6632420 53.5, -346718.7 6632419.8 53.5),(-346689.7 6632409.5 53.5, -346688.2 6632409 53.5),(-346692.5 6632410.5 53.5, -346689.7 6632409.5 53.5))', - 'MultiLineString Z ((-346387.6 6632223.9 67, -346384.8 6632219 67),(-346384.8 6632219 67, -346383.5 6632216.9 67))', - 'MultiLineString Z ((-346582.6 6632371.7 62.3, -346579.7 6632370.7 62.3),(-346579.7 6632370.7 62.3, -346577 6632369.7 62.3, -346570.8 6632367.9 62.3))']) + self.assertCountEqual( + [g.asWkt(1) for g in results.asGeometries()], + [ + "MultiLineString Z ((-346684.3 6632407.6 56, -346679.6 6632406 56),(-346679.6 6632406 56, -346672.8 6632403.6 56))", + "MultiLineString Z ((-346718.7 6632419.8 53.5, -346712 6632417.4 53.5),(-346719.3 6632420 53.5, -346718.7 6632419.8 53.5),(-346689.7 6632409.5 53.5, -346688.2 6632409 53.5),(-346692.5 6632410.5 53.5, -346689.7 6632409.5 53.5))", + "MultiLineString Z ((-346387.6 6632223.9 67, -346384.8 6632219 67),(-346384.8 6632219 67, -346383.5 6632216.9 67))", + "MultiLineString Z ((-346582.6 6632371.7 62.3, -346579.7 6632370.7 62.3),(-346579.7 6632370.7 62.3, -346577 6632369.7 62.3, -346570.8 6632367.9 62.3))", + ], + ) def testPolygonGenerationRelativeExtrusion(self): - vl = QgsVectorLayer('PolygonZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("PolygonZ?crs=EPSG:27700", "lines", "memory") self.assertTrue(vl.isValid()) for line in [ - 'PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))', - 'PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))', - 'PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))', - 'PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))', - 'PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))']: + "PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))", + "PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))", + "PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))", + "PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))", + "PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -930,11 +1286,12 @@ def testPolygonGenerationRelativeExtrusion(self): curve = QgsLineString() curve.fromWkt( - 'LineString (-347701.59207547508412972 6632766.96282589063048363, -346577.00878971704514697 6632369.7371364813297987, -346449.93654899462126195 6632331.81857067719101906, -346383.52035177784273401 6632216.85897350125014782)') + "LineString (-347701.59207547508412972 6632766.96282589063048363, -346577.00878971704514697 6632369.7371364813297987, -346449.93654899462126195 6632331.81857067719101906, -346383.52035177784273401 6632216.85897350125014782)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) terrain_provider = QgsRasterDemTerrainProvider() terrain_provider.setLayer(rl) @@ -942,52 +1299,93 @@ def testPolygonGenerationRelativeExtrusion(self): terrain_provider.setOffset(-5) req.setTerrainProvider(terrain_provider) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) results = generator.takeResults() if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {1041.8: 60.3, 1042.4: 60.2, 1049.5: 60.2, 1070.2: 60.2, 1073.1: 60.2, 1074.8: 60.3, - 1078.9: 62.0, 1083.9: 62.0, 1091.1: 62.0, 1186.8: 59.3, 1189.8: 59.2, 1192.7: 59.2, - 1199.2: 59.2, 1450.0: 65.5, 1455.6: 65.5, 1458.1: 65.5}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 1041.8: 60.3, + 1042.4: 60.2, + 1049.5: 60.2, + 1070.2: 60.2, + 1073.1: 60.2, + 1074.8: 60.3, + 1078.9: 62.0, + 1083.9: 62.0, + 1091.1: 62.0, + 1186.8: 59.3, + 1189.8: 59.2, + 1192.7: 59.2, + 1199.2: 59.2, + 1450.0: 65.5, + 1455.6: 65.5, + 1458.1: 65.5, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 59.2499, 2) self.assertAlmostEqual(results.zRange().upper(), 72.50000, 2) else: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {1041.8: 53.5, 1042.4: 53.5, 1049.5: 53.5, 1070.2: 53.5, 1073.1: 53.5, 1074.8: 53.5, - 1078.9: 56.0, 1083.9: 56.0, 1091.1: 56.0, 1186.8: 62.3, 1189.8: 62.3, 1192.7: 62.3, - 1199.2: 62.2, 1450.0: 67.0, 1455.6: 67.0, 1458.1: 67.0}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 1041.8: 53.5, + 1042.4: 53.5, + 1049.5: 53.5, + 1070.2: 53.5, + 1073.1: 53.5, + 1074.8: 53.5, + 1078.9: 56.0, + 1083.9: 56.0, + 1091.1: 56.0, + 1186.8: 62.3, + 1189.8: 62.3, + 1192.7: 62.3, + 1199.2: 62.2, + 1450.0: 67.0, + 1455.6: 67.0, + 1458.1: 67.0, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 53.5, 2) self.assertAlmostEqual(results.zRange().upper(), 74.00000, 2) if QgsProjUtils.projVersionMajor() >= 8: - self.assertCountEqual([g.asWkt(1) for g in results.asGeometries()], - [ - 'MultiPolygon Z (((-346718.7 6632419.8 60.3, -346712 6632417.4 60.3, -346712 6632417.4 67.3, -346718.7 6632419.8 67.3, -346718.7 6632419.8 60.3)),((-346719.3 6632420 60.3, -346718.7 6632419.8 60.2, -346718.7 6632419.8 67.3, -346719.3 6632420 67.3, -346719.3 6632420 60.3)),((-346689.7 6632409.5 60.3, -346688.2 6632409 60.3, -346688.2 6632409 67.3, -346689.7 6632409.5 67.3, -346689.7 6632409.5 60.3)),((-346692.5 6632410.5 60.3, -346689.7 6632409.5 60.3, -346689.7 6632409.5 67.3, -346692.5 6632410.5 67.3, -346692.5 6632410.5 60.3)))', - 'MultiPolygon Z (((-346684.3 6632407.6 62, -346679.6 6632406 62, -346679.6 6632406 69, -346684.3 6632407.6 69, -346684.3 6632407.6 62)),((-346679.6 6632406 62, -346672.8 6632403.6 62, -346672.8 6632403.6 69, -346679.6 6632406 69, -346679.6 6632406 62)))', - 'MultiPolygon Z (((-346582.6 6632371.7 59.3, -346579.7 6632370.7 59.3, -346579.7 6632370.7 66.3, -346582.6 6632371.7 66.3, -346582.6 6632371.7 59.3)),((-346579.7 6632370.7 59.3, -346577 6632369.7 59.2, -346570.8 6632367.9 59.3, -346570.8 6632367.9 66.3, -346577 6632369.7 66.3, -346579.7 6632370.7 66.3, -346579.7 6632370.7 59.3)))', - 'MultiPolygon Z (((-346387.6 6632223.9 65.5, -346384.8 6632219 65.5, -346384.8 6632219 72.5, -346387.6 6632223.9 72.5, -346387.6 6632223.9 65.5)),((-346384.8 6632219 65.5, -346383.5 6632216.9 65.5, -346383.5 6632216.9 72.5, -346384.8 6632219 72.5, -346384.8 6632219 65.5)))']) + self.assertCountEqual( + [g.asWkt(1) for g in results.asGeometries()], + [ + "MultiPolygon Z (((-346718.7 6632419.8 60.3, -346712 6632417.4 60.3, -346712 6632417.4 67.3, -346718.7 6632419.8 67.3, -346718.7 6632419.8 60.3)),((-346719.3 6632420 60.3, -346718.7 6632419.8 60.2, -346718.7 6632419.8 67.3, -346719.3 6632420 67.3, -346719.3 6632420 60.3)),((-346689.7 6632409.5 60.3, -346688.2 6632409 60.3, -346688.2 6632409 67.3, -346689.7 6632409.5 67.3, -346689.7 6632409.5 60.3)),((-346692.5 6632410.5 60.3, -346689.7 6632409.5 60.3, -346689.7 6632409.5 67.3, -346692.5 6632410.5 67.3, -346692.5 6632410.5 60.3)))", + "MultiPolygon Z (((-346684.3 6632407.6 62, -346679.6 6632406 62, -346679.6 6632406 69, -346684.3 6632407.6 69, -346684.3 6632407.6 62)),((-346679.6 6632406 62, -346672.8 6632403.6 62, -346672.8 6632403.6 69, -346679.6 6632406 69, -346679.6 6632406 62)))", + "MultiPolygon Z (((-346582.6 6632371.7 59.3, -346579.7 6632370.7 59.3, -346579.7 6632370.7 66.3, -346582.6 6632371.7 66.3, -346582.6 6632371.7 59.3)),((-346579.7 6632370.7 59.3, -346577 6632369.7 59.2, -346570.8 6632367.9 59.3, -346570.8 6632367.9 66.3, -346577 6632369.7 66.3, -346579.7 6632370.7 66.3, -346579.7 6632370.7 59.3)))", + "MultiPolygon Z (((-346387.6 6632223.9 65.5, -346384.8 6632219 65.5, -346384.8 6632219 72.5, -346387.6 6632223.9 72.5, -346387.6 6632223.9 65.5)),((-346384.8 6632219 65.5, -346383.5 6632216.9 65.5, -346383.5 6632216.9 72.5, -346384.8 6632219 72.5, -346384.8 6632219 65.5)))", + ], + ) else: - self.assertCountEqual([g.asWkt(1) for g in results.asGeometries()], - [ - 'MultiPolygon Z (((-346684.3 6632407.6 56, -346679.6 6632406 56, -346679.6 6632406 63, -346684.3 6632407.6 63, -346684.3 6632407.6 56)),((-346679.6 6632406 56, -346672.8 6632403.6 56, -346672.8 6632403.6 63, -346679.6 6632406 63, -346679.6 6632406 56)))', - 'MultiPolygon Z (((-346718.7 6632419.8 53.5, -346712 6632417.4 53.5, -346712 6632417.4 60.5, -346718.7 6632419.8 60.5, -346718.7 6632419.8 53.5)),((-346719.3 6632420 53.5, -346718.7 6632419.8 53.5, -346718.7 6632419.8 60.5, -346719.3 6632420 60.5, -346719.3 6632420 53.5)),((-346689.7 6632409.5 53.5, -346688.2 6632409 53.5, -346688.2 6632409 60.5, -346689.7 6632409.5 60.5, -346689.7 6632409.5 53.5)),((-346692.5 6632410.5 53.5, -346689.7 6632409.5 53.5, -346689.7 6632409.5 60.5, -346692.5 6632410.5 60.5, -346692.5 6632410.5 53.5)))', - 'MultiPolygon Z (((-346387.6 6632223.9 67, -346384.8 6632219 67, -346384.8 6632219 74, -346387.6 6632223.9 74, -346387.6 6632223.9 67)),((-346384.8 6632219 67, -346383.5 6632216.9 67, -346383.5 6632216.9 74, -346384.8 6632219 74, -346384.8 6632219 67)))', - 'MultiPolygon Z (((-346582.6 6632371.7 62.3, -346579.7 6632370.7 62.3, -346579.7 6632370.7 69.3, -346582.6 6632371.7 69.3, -346582.6 6632371.7 62.3)),((-346579.7 6632370.7 62.3, -346577 6632369.7 62.3, -346570.8 6632367.9 62.3, -346570.8 6632367.9 69.3, -346577 6632369.7 69.3, -346579.7 6632370.7 69.3, -346579.7 6632370.7 62.3)))']) + self.assertCountEqual( + [g.asWkt(1) for g in results.asGeometries()], + [ + "MultiPolygon Z (((-346684.3 6632407.6 56, -346679.6 6632406 56, -346679.6 6632406 63, -346684.3 6632407.6 63, -346684.3 6632407.6 56)),((-346679.6 6632406 56, -346672.8 6632403.6 56, -346672.8 6632403.6 63, -346679.6 6632406 63, -346679.6 6632406 56)))", + "MultiPolygon Z (((-346718.7 6632419.8 53.5, -346712 6632417.4 53.5, -346712 6632417.4 60.5, -346718.7 6632419.8 60.5, -346718.7 6632419.8 53.5)),((-346719.3 6632420 53.5, -346718.7 6632419.8 53.5, -346718.7 6632419.8 60.5, -346719.3 6632420 60.5, -346719.3 6632420 53.5)),((-346689.7 6632409.5 53.5, -346688.2 6632409 53.5, -346688.2 6632409 60.5, -346689.7 6632409.5 60.5, -346689.7 6632409.5 53.5)),((-346692.5 6632410.5 53.5, -346689.7 6632409.5 53.5, -346689.7 6632409.5 60.5, -346692.5 6632410.5 60.5, -346692.5 6632410.5 53.5)))", + "MultiPolygon Z (((-346387.6 6632223.9 67, -346384.8 6632219 67, -346384.8 6632219 74, -346387.6 6632223.9 74, -346387.6 6632223.9 67)),((-346384.8 6632219 67, -346383.5 6632216.9 67, -346383.5 6632216.9 74, -346384.8 6632219 74, -346384.8 6632219 67)))", + "MultiPolygon Z (((-346582.6 6632371.7 62.3, -346579.7 6632370.7 62.3, -346579.7 6632370.7 69.3, -346582.6 6632371.7 69.3, -346582.6 6632371.7 62.3)),((-346579.7 6632370.7 62.3, -346577 6632369.7 62.3, -346570.8 6632367.9 62.3, -346570.8 6632367.9 69.3, -346577 6632369.7 69.3, -346579.7 6632370.7 69.3, -346579.7 6632370.7 62.3)))", + ], + ) def testPolygonGenerationRelativeExtrusionTolerance(self): - vl = QgsVectorLayer('PolygonZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("PolygonZ?crs=EPSG:27700", "lines", "memory") self.assertTrue(vl.isValid()) for line in [ - 'PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))', - 'PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))', - 'PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))', - 'PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))', - 'PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))']: + "PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))", + "PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))", + "PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))", + "PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))", + "PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -1000,11 +1398,12 @@ def testPolygonGenerationRelativeExtrusionTolerance(self): curve = QgsLineString() curve.fromWkt( - 'LineString (-347701.59207547508412972 6632766.96282589063048363, -346577.00878971704514697 6632369.7371364813297987, -346449.93654899462126195 6632331.81857067719101906, -346383.52035177784273401 6632216.85897350125014782)') + "LineString (-347701.59207547508412972 6632766.96282589063048363, -346577.00878971704514697 6632369.7371364813297987, -346449.93654899462126195 6632331.81857067719101906, -346383.52035177784273401 6632216.85897350125014782)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif'), 'DTM') + rl = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif"), "DTM") self.assertTrue(rl.isValid()) terrain_provider = QgsRasterDemTerrainProvider() terrain_provider.setLayer(rl) @@ -1012,7 +1411,7 @@ def testPolygonGenerationRelativeExtrusionTolerance(self): terrain_provider.setOffset(-5) req.setTerrainProvider(terrain_provider) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) req.setTolerance(2.0) generator = vl.createProfileGenerator(req) @@ -1020,73 +1419,146 @@ def testPolygonGenerationRelativeExtrusionTolerance(self): results = generator.takeResults() if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {1041.0: 60.2, 1042.2: 60.2, 1042.9: 60.2, 1048.2: 60.2, 1050.8: 60.2, 1066.9: 60.2, - 1073.4: 60.2, 1076.2: 60.2, 1077.9: 62.0, 1079.9: 62.0, 1089.9: 62.0, 1092.2: 62.0, - 1185.4: 59.2, 1188.2: 59.2, 1192.6: 59.2, 1192.7: 59.2, 1197.9: 59.2, 1200.4: 59.2, - 1449.3: 65.5, 1450.1: 65.5, 1451.1: 65.5, 1458.1: 65.5}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 1041.0: 60.2, + 1042.2: 60.2, + 1042.9: 60.2, + 1048.2: 60.2, + 1050.8: 60.2, + 1066.9: 60.2, + 1073.4: 60.2, + 1076.2: 60.2, + 1077.9: 62.0, + 1079.9: 62.0, + 1089.9: 62.0, + 1092.2: 62.0, + 1185.4: 59.2, + 1188.2: 59.2, + 1192.6: 59.2, + 1192.7: 59.2, + 1197.9: 59.2, + 1200.4: 59.2, + 1449.3: 65.5, + 1450.1: 65.5, + 1451.1: 65.5, + 1458.1: 65.5, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 59.25, 2) self.assertAlmostEqual(results.zRange().upper(), 65.5, 2) else: - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {1041.8: 53.5, 1042.4: 53.5, 1049.5: 53.5, 1070.2: 53.5, 1073.1: 53.5, 1074.8: 53.5, - 1078.9: 56.0, 1083.9: 56.0, 1091.1: 56.0, 1186.8: 62.3, 1189.8: 62.3, 1192.7: 62.3, - 1199.2: 62.2, 1450.0: 67.0, 1455.6: 67.0, 1458.1: 67.0}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 1041.8: 53.5, + 1042.4: 53.5, + 1049.5: 53.5, + 1070.2: 53.5, + 1073.1: 53.5, + 1074.8: 53.5, + 1078.9: 56.0, + 1083.9: 56.0, + 1091.1: 56.0, + 1186.8: 62.3, + 1189.8: 62.3, + 1192.7: 62.3, + 1199.2: 62.2, + 1450.0: 67.0, + 1455.6: 67.0, + 1458.1: 67.0, + }, + ) self.assertAlmostEqual(results.zRange().lower(), 53.5, 2) self.assertAlmostEqual(results.zRange().upper(), 74.00000, 2) if QgsProjUtils.projVersionMajor() >= 8: - self.assertCountEqual([g.asWkt(1) for g in results.asGeometries()], - [ - 'MultiLineString Z ((-346696.3 6632409.8 60.2, -346688.9 6632411.2 60.2, -346687.5 6632406.6 60.2),(-346718.9 6632417.7 60.2, -346719.5 6632421.6 60.2, -346718.2 6632421.7 60.2, -346712.5 6632419.7 60.2, -346711.5 6632415.1 60.2))', - 'LineString Z (-346684.1 6632405.4 62, -346684.6 6632409.8 62, -346673.3 6632405.9 62, -346672.4 6632401.3 62)', - 'LineString Z (-346571.4 6632370.2 59.3, -346570.2 6632365.6 59.3, -346577.6 6632367.8 59.3, -346577.7 6632367.9 59.3, -346581.9 6632369.4 59.3, -346583.2 6632374 59.3, -346576.4 6632371.6 59.3)', - 'LineString Z (-346381.8 6632217.9 65.5, -346385.3 6632215.9 65.5, -346388.7 6632221.9 65.5, -346387 6632224.9 65.5, -346385.8 6632224.7 65.5)']) + self.assertCountEqual( + [g.asWkt(1) for g in results.asGeometries()], + [ + "MultiLineString Z ((-346696.3 6632409.8 60.2, -346688.9 6632411.2 60.2, -346687.5 6632406.6 60.2),(-346718.9 6632417.7 60.2, -346719.5 6632421.6 60.2, -346718.2 6632421.7 60.2, -346712.5 6632419.7 60.2, -346711.5 6632415.1 60.2))", + "LineString Z (-346684.1 6632405.4 62, -346684.6 6632409.8 62, -346673.3 6632405.9 62, -346672.4 6632401.3 62)", + "LineString Z (-346571.4 6632370.2 59.3, -346570.2 6632365.6 59.3, -346577.6 6632367.8 59.3, -346577.7 6632367.9 59.3, -346581.9 6632369.4 59.3, -346583.2 6632374 59.3, -346576.4 6632371.6 59.3)", + "LineString Z (-346381.8 6632217.9 65.5, -346385.3 6632215.9 65.5, -346388.7 6632221.9 65.5, -346387 6632224.9 65.5, -346385.8 6632224.7 65.5)", + ], + ) else: - self.assertCountEqual([g.asWkt(1) for g in results.asGeometries()], - [ - 'MultiPolygon Z (((-346684.3 6632407.6 56, -346679.6 6632406 56, -346679.6 6632406 63, -346684.3 6632407.6 63, -346684.3 6632407.6 56)),((-346679.6 6632406 56, -346672.8 6632403.6 56, -346672.8 6632403.6 63, -346679.6 6632406 63, -346679.6 6632406 56)))', - 'MultiPolygon Z (((-346718.7 6632419.8 53.5, -346712 6632417.4 53.5, -346712 6632417.4 60.5, -346718.7 6632419.8 60.5, -346718.7 6632419.8 53.5)),((-346719.3 6632420 53.5, -346718.7 6632419.8 53.5, -346718.7 6632419.8 60.5, -346719.3 6632420 60.5, -346719.3 6632420 53.5)),((-346689.7 6632409.5 53.5, -346688.2 6632409 53.5, -346688.2 6632409 60.5, -346689.7 6632409.5 60.5, -346689.7 6632409.5 53.5)),((-346692.5 6632410.5 53.5, -346689.7 6632409.5 53.5, -346689.7 6632409.5 60.5, -346692.5 6632410.5 60.5, -346692.5 6632410.5 53.5)))', - 'MultiPolygon Z (((-346387.6 6632223.9 67, -346384.8 6632219 67, -346384.8 6632219 74, -346387.6 6632223.9 74, -346387.6 6632223.9 67)),((-346384.8 6632219 67, -346383.5 6632216.9 67, -346383.5 6632216.9 74, -346384.8 6632219 74, -346384.8 6632219 67)))', - 'MultiPolygon Z (((-346582.6 6632371.7 62.3, -346579.7 6632370.7 62.3, -346579.7 6632370.7 69.3, -346582.6 6632371.7 69.3, -346582.6 6632371.7 62.3)),((-346579.7 6632370.7 62.3, -346577 6632369.7 62.3, -346570.8 6632367.9 62.3, -346570.8 6632367.9 69.3, -346577 6632369.7 69.3, -346579.7 6632370.7 69.3, -346579.7 6632370.7 62.3)))']) + self.assertCountEqual( + [g.asWkt(1) for g in results.asGeometries()], + [ + "MultiPolygon Z (((-346684.3 6632407.6 56, -346679.6 6632406 56, -346679.6 6632406 63, -346684.3 6632407.6 63, -346684.3 6632407.6 56)),((-346679.6 6632406 56, -346672.8 6632403.6 56, -346672.8 6632403.6 63, -346679.6 6632406 63, -346679.6 6632406 56)))", + "MultiPolygon Z (((-346718.7 6632419.8 53.5, -346712 6632417.4 53.5, -346712 6632417.4 60.5, -346718.7 6632419.8 60.5, -346718.7 6632419.8 53.5)),((-346719.3 6632420 53.5, -346718.7 6632419.8 53.5, -346718.7 6632419.8 60.5, -346719.3 6632420 60.5, -346719.3 6632420 53.5)),((-346689.7 6632409.5 53.5, -346688.2 6632409 53.5, -346688.2 6632409 60.5, -346689.7 6632409.5 60.5, -346689.7 6632409.5 53.5)),((-346692.5 6632410.5 53.5, -346689.7 6632409.5 53.5, -346689.7 6632409.5 60.5, -346692.5 6632410.5 60.5, -346692.5 6632410.5 53.5)))", + "MultiPolygon Z (((-346387.6 6632223.9 67, -346384.8 6632219 67, -346384.8 6632219 74, -346387.6 6632223.9 74, -346387.6 6632223.9 67)),((-346384.8 6632219 67, -346383.5 6632216.9 67, -346383.5 6632216.9 74, -346384.8 6632219 74, -346384.8 6632219 67)))", + "MultiPolygon Z (((-346582.6 6632371.7 62.3, -346579.7 6632370.7 62.3, -346579.7 6632370.7 69.3, -346582.6 6632371.7 69.3, -346582.6 6632371.7 62.3)),((-346579.7 6632370.7 62.3, -346577 6632369.7 62.3, -346570.8 6632367.9 62.3, -346570.8 6632367.9 69.3, -346577 6632369.7 69.3, -346579.7 6632370.7 69.3, -346579.7 6632370.7 62.3)))", + ], + ) def test25DPolygonGeneration(self): - vl = QgsVectorLayer('PolygonZ?crs=EPSG:2056', 'lines', 'memory') + vl = QgsVectorLayer("PolygonZ?crs=EPSG:2056", "lines", "memory") self.assertTrue(vl.isValid()) for line in [ - 'MultiPolygonZ (((2607398.48000000044703484 1228694.19700000062584877 448.28800000000046566, 2607403.2760000005364418 1228696.4050000011920929 444.7440000000060536, 2607393.68600000068545341 1228691.98900000005960464 444.7440000000060536, 2607398.48000000044703484 1228694.19700000062584877 448.28800000000046566)))']: + "MultiPolygonZ (((2607398.48000000044703484 1228694.19700000062584877 448.28800000000046566, 2607403.2760000005364418 1228696.4050000011920929 444.7440000000060536, 2607393.68600000068545341 1228691.98900000005960464 444.7440000000060536, 2607398.48000000044703484 1228694.19700000062584877 448.28800000000046566)))" + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) curve = QgsLineString() curve.fromWkt( - 'LineString (2607400.97201532032340765 1228697.90654633427038789, 2607405.23384975455701351 1228690.52444026106968522)') + "LineString (2607400.97201532032340765 1228697.90654633427038789, 2607405.23384975455701351 1228690.52444026106968522)" + ) req = QgsProfileRequest(curve) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:2056')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:2056")) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) results = generator.takeResults() - self.assertEqual(self.round_dict(results.distanceToHeightMap(), 1), - {2.3: 445.6}) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), {2.3: 445.6} + ) self.assertAlmostEqual(results.zRange().lower(), 444.744, 2) self.assertAlmostEqual(results.zRange().upper(), 445.583, 2) def testDataDefinedExtrusionOffset(self): - vl = QgsVectorLayer('PolygonZ?crs=EPSG:27700&field=extrusion:int&field=offset:int', 'lines', 'memory') + vl = QgsVectorLayer( + "PolygonZ?crs=EPSG:27700&field=extrusion:int&field=offset:int", + "lines", + "memory", + ) vl.setCrs(QgsCoordinateReferenceSystem()) self.assertTrue(vl.isValid()) for extrusion, offset, wkt in [ - (5, 10, 'PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))'), - (1, 6, 'PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))'), - (2, 1, 'PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))'), - (3, 9, 'PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))'), - (7, 11, 'PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))')]: + ( + 5, + 10, + "PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))", + ), + ( + 1, + 6, + "PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))", + ), + ( + 2, + 1, + "PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))", + ), + ( + 3, + 9, + "PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))", + ), + ( + 7, + 11, + "PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))", + ), + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(wkt)) f.setAttributes([extrusion, offset]) @@ -1099,7 +1571,8 @@ def testDataDefinedExtrusionOffset(self): curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) @@ -1110,31 +1583,46 @@ def testDataDefinedExtrusionOffset(self): self.assertTrue(generator.generateProfile()) results = generator.takeResults() - self.assertCountEqual([g.asWkt(1) for g in results.asGeometries()], - ['MultiPolygon Z (((321906.5 129918.5 36, 321907.7 129918.8 36, 321907.7 129918.8 53, 321906.5 129918.5 53, 321906.5 129918.5 36)),((321902.8 129917.9 36, 321906.5 129918.5 36, 321906.5 129918.5 53, 321902.8 129917.9 53, 321902.8 129917.9 36)),((321917.9 129920.6 36, 321921 129921.1 36, 321921 129921.1 53, 321917.9 129920.6 53, 321917.9 129920.6 36)),((321912.4 129919.6 36, 321917.9 129920.6 36, 321917.9 129920.6 53, 321912.4 129919.6 53, 321912.4 129919.6 36)))', - 'MultiPolygon Z (((321922.9 129921.5 37, 321927.8 129922.4 37, 321927.8 129922.4 54, 321922.9 129921.5 54, 321922.9 129921.5 37)),((321927.8 129922.4 37, 321929.5 129922.7 37, 321929.5 129922.7 54, 321927.8 129922.4 54, 321927.8 129922.4 37)))']) + self.assertCountEqual( + [g.asWkt(1) for g in results.asGeometries()], + [ + "MultiPolygon Z (((321906.5 129918.5 36, 321907.7 129918.8 36, 321907.7 129918.8 53, 321906.5 129918.5 53, 321906.5 129918.5 36)),((321902.8 129917.9 36, 321906.5 129918.5 36, 321906.5 129918.5 53, 321902.8 129917.9 53, 321902.8 129917.9 36)),((321917.9 129920.6 36, 321921 129921.1 36, 321921 129921.1 53, 321917.9 129920.6 53, 321917.9 129920.6 36)),((321912.4 129919.6 36, 321917.9 129920.6 36, 321917.9 129920.6 53, 321912.4 129919.6 53, 321912.4 129919.6 36)))", + "MultiPolygon Z (((321922.9 129921.5 37, 321927.8 129922.4 37, 321927.8 129922.4 54, 321922.9 129921.5 54, 321922.9 129921.5 37)),((321927.8 129922.4 37, 321929.5 129922.7 37, 321929.5 129922.7 54, 321927.8 129922.4 54, 321927.8 129922.4 37)))", + ], + ) # with data defined extrusion and offset - vl.elevationProperties().dataDefinedProperties().setProperty(QgsMapLayerElevationProperties.Property.ExtrusionHeight, QgsProperty.fromField('extrusion')) - vl.elevationProperties().dataDefinedProperties().setProperty(QgsMapLayerElevationProperties.Property.ZOffset, - QgsProperty.fromField('offset')) + vl.elevationProperties().dataDefinedProperties().setProperty( + QgsMapLayerElevationProperties.Property.ExtrusionHeight, + QgsProperty.fromField("extrusion"), + ) + vl.elevationProperties().dataDefinedProperties().setProperty( + QgsMapLayerElevationProperties.Property.ZOffset, + QgsProperty.fromField("offset"), + ) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) results = generator.takeResults() - self.assertCountEqual([g.asWkt(1) for g in results.asGeometries()], - ['MultiPolygon Z (((321922.9 129921.5 4, 321927.8 129922.4 4, 321927.8 129922.4 6, 321922.9 129921.5 6, 321922.9 129921.5 4)),((321927.8 129922.4 4, 321929.5 129922.7 4, 321929.5 129922.7 6, 321927.8 129922.4 6, 321927.8 129922.4 4)))', - 'MultiPolygon Z (((321906.5 129918.5 8, 321907.7 129918.8 8, 321907.7 129918.8 9, 321906.5 129918.5 9, 321906.5 129918.5 8)),((321902.8 129917.9 8, 321906.5 129918.5 8, 321906.5 129918.5 9, 321902.8 129917.9 9, 321902.8 129917.9 8)),((321917.9 129920.6 8, 321921 129921.1 8, 321921 129921.1 9, 321917.9 129920.6 9, 321917.9 129920.6 8)),((321912.4 129919.6 8, 321917.9 129920.6 8, 321917.9 129920.6 9, 321912.4 129919.6 9, 321912.4 129919.6 8)))']) + self.assertCountEqual( + [g.asWkt(1) for g in results.asGeometries()], + [ + "MultiPolygon Z (((321922.9 129921.5 4, 321927.8 129922.4 4, 321927.8 129922.4 6, 321922.9 129921.5 6, 321922.9 129921.5 4)),((321927.8 129922.4 4, 321929.5 129922.7 4, 321929.5 129922.7 6, 321927.8 129922.4 6, 321927.8 129922.4 4)))", + "MultiPolygon Z (((321906.5 129918.5 8, 321907.7 129918.8 8, 321907.7 129918.8 9, 321906.5 129918.5 9, 321906.5 129918.5 8)),((321902.8 129917.9 8, 321906.5 129918.5 8, 321906.5 129918.5 9, 321902.8 129917.9 9, 321902.8 129917.9 8)),((321917.9 129920.6 8, 321921 129921.1 8, 321921 129921.1 9, 321917.9 129920.6 9, 321917.9 129920.6 8)),((321912.4 129919.6 8, 321917.9 129920.6 8, 321917.9 129920.6 9, 321912.4 129919.6 9, 321912.4 129919.6 8)))", + ], + ) def testSnappingPoints(self): - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") self.assertTrue(vl.isValid()) vl.setCrs(QgsCoordinateReferenceSystem()) - for line in ['LineStringZ(322006 129874 12, 322008 129910 13, 322038 129909 14, 322037 129868 15)', - 'LineStringZ(322068 129900 16, 322128 129813 17)']: + for line in [ + "LineStringZ(322006 129874 12, 322008 129910 13, 322038 129909 14, 322037 129868 15)", + "LineStringZ(322068 129900 16, 322128 129813 17)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -1142,7 +1630,9 @@ def testSnappingPoints(self): vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) curve = QgsLineString() - curve.fromWkt('LineStringZ (322021.96201738982927054 129896.83061585001996718 0, 322116.8371042063809 129880.94244341662852094 0)') + curve.fromWkt( + "LineStringZ (322021.96201738982927054 129896.83061585001996718 0, 322116.8371042063809 129880.94244341662852094 0)" + ) req = QgsProfileRequest(curve) generator = vl.createProfileGenerator(req) @@ -1177,12 +1667,14 @@ def testSnappingPoints(self): self.assertFalse(res.isValid()) def testSnappingVerticalLines(self): - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") self.assertTrue(vl.isValid()) vl.setCrs(QgsCoordinateReferenceSystem()) - for line in ['LineStringZ(322006 129874 12, 322008 129910 13, 322038 129909 14, 322037 129868 15)', - 'LineStringZ(322068 129900 16, 322128 129813 17)']: + for line in [ + "LineStringZ(322006 129874 12, 322008 129910 13, 322038 129909 14, 322037 129868 15)", + "LineStringZ(322068 129900 16, 322128 129813 17)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -1192,7 +1684,9 @@ def testSnappingVerticalLines(self): vl.elevationProperties().setExtrusionHeight(17) curve = QgsLineString() - curve.fromWkt('LineStringZ (322021.96201738982927054 129896.83061585001996718 0, 322116.8371042063809 129880.94244341662852094 0)') + curve.fromWkt( + "LineStringZ (322021.96201738982927054 129896.83061585001996718 0, 322116.8371042063809 129880.94244341662852094 0)" + ) req = QgsProfileRequest(curve) generator = vl.createProfileGenerator(req) @@ -1243,12 +1737,14 @@ def testSnappingVerticalLines(self): self.assertFalse(res.isValid()) def testSnappingPolygons(self): - vl = QgsVectorLayer('PolygonZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("PolygonZ?crs=EPSG:27700", "lines", "memory") self.assertTrue(vl.isValid()) vl.setCrs(QgsCoordinateReferenceSystem()) - for poly in ['PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))', - 'PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))']: + for poly in [ + "PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))", + "PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(poly)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -1256,7 +1752,9 @@ def testSnappingPolygons(self): vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) curve = QgsLineString() - curve.fromWkt('LineStringZ (321944.79089414176996797 129899.10035476912162267 0, 321818.13946245843544602 129991.70570266660070047 0)') + curve.fromWkt( + "LineStringZ (321944.79089414176996797 129899.10035476912162267 0, 321818.13946245843544602 129991.70570266660070047 0)" + ) req = QgsProfileRequest(curve) generator = vl.createProfileGenerator(req) @@ -1299,12 +1797,14 @@ def testSnappingPolygons(self): self.assertFalse(res.isValid()) def testSnappingExtrudedPolygons(self): - vl = QgsVectorLayer('PolygonZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("PolygonZ?crs=EPSG:27700", "lines", "memory") self.assertTrue(vl.isValid()) vl.setCrs(QgsCoordinateReferenceSystem()) - for poly in ['PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))', - 'PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))']: + for poly in [ + "PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))", + "PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(poly)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -1314,7 +1814,9 @@ def testSnappingExtrudedPolygons(self): vl.elevationProperties().setExtrusionHeight(17) curve = QgsLineString() - curve.fromWkt('LineStringZ (321944.79089414176996797 129899.10035476912162267 0, 321818.13946245843544602 129991.70570266660070047 0)') + curve.fromWkt( + "LineStringZ (321944.79089414176996797 129899.10035476912162267 0, 321818.13946245843544602 129991.70570266660070047 0)" + ) req = QgsProfileRequest(curve) generator = vl.createProfileGenerator(req) @@ -1365,12 +1867,14 @@ def testSnappingExtrudedPolygons(self): self.assertFalse(res.isValid()) def testIdentifyPoints(self): - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") self.assertTrue(vl.isValid()) vl.setCrs(QgsCoordinateReferenceSystem()) - for line in ['LineStringZ(322006 129874 12, 322008 129910 13, 322038 129909 14, 322037 129868 15)', - 'LineStringZ(322068 129900 16, 322128 129813 17)']: + for line in [ + "LineStringZ(322006 129874 12, 322008 129910 13, 322038 129909 14, 322037 129868 15)", + "LineStringZ(322068 129900 16, 322128 129813 17)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -1378,7 +1882,9 @@ def testIdentifyPoints(self): vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) curve = QgsLineString() - curve.fromWkt('LineStringZ (322021.96201738982927054 129896.83061585001996718 0, 322116.8371042063809 129880.94244341662852094 0)') + curve.fromWkt( + "LineStringZ (322021.96201738982927054 129896.83061585001996718 0, 322116.8371042063809 129880.94244341662852094 0)" + ) req = QgsProfileRequest(curve) generator = vl.createProfileGenerator(req) @@ -1398,14 +1904,34 @@ def testIdentifyPoints(self): res = r.identify(QgsProfilePoint(15, 14), context) self.assertTrue(len(res), 1) self.assertEqual(res[0].layer(), vl) - self.assertEqual(res[0].results(), [{'delta': 0.9654154289752465, 'distance': 15.895441865142377, 'elevation': 14.360847359216885, 'id': 1}]) + self.assertEqual( + res[0].results(), + [ + { + "delta": 0.9654154289752465, + "distance": 15.895441865142377, + "elevation": 14.360847359216885, + "id": 1, + } + ], + ) context.maximumPointDistanceDelta = 2 context.maximumPointElevationDelta = 2 res = r.identify(QgsProfilePoint(55, 16), context) self.assertTrue(len(res), 1) self.assertEqual(res[0].layer(), vl) - self.assertEqual(res[0].results(), [{'delta': 0.3133775679752489, 'distance': 55.279676009112876, 'elevation': 16.14137478571788, 'id': 2}]) + self.assertEqual( + res[0].results(), + [ + { + "delta": 0.3133775679752489, + "distance": 55.279676009112876, + "elevation": 16.14137478571788, + "id": 2, + } + ], + ) context.maximumPointDistanceDelta = 0.1 context.maximumPointElevationDelta = 0.1 @@ -1415,23 +1941,25 @@ def testIdentifyPoints(self): res = r.identify(QgsDoubleRange(15, 56), QgsDoubleRange(13, 17), context) self.assertTrue(len(res), 2) self.assertEqual(res[0].layer(), vl) - self.assertCountEqual(res[0].results(), [{'id': 2}, {'id': 1}]) + self.assertCountEqual(res[0].results(), [{"id": 2}, {"id": 1}]) res = r.identify(QgsDoubleRange(15, 36), QgsDoubleRange(13, 17), context) self.assertTrue(len(res), 2) self.assertEqual(res[0].layer(), vl) - self.assertCountEqual(res[0].results(), [{'id': 1}]) + self.assertCountEqual(res[0].results(), [{"id": 1}]) res = r.identify(QgsDoubleRange(25, 36), QgsDoubleRange(13, 17), context) self.assertFalse(res) def testIdentifyVerticalLines(self): - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") self.assertTrue(vl.isValid()) vl.setCrs(QgsCoordinateReferenceSystem()) - for line in ['LineStringZ(322006 129874 12, 322008 129910 13, 322038 129909 14, 322037 129868 15)', - 'LineStringZ(322068 129900 16, 322128 129813 17)']: + for line in [ + "LineStringZ(322006 129874 12, 322008 129910 13, 322038 129909 14, 322037 129868 15)", + "LineStringZ(322068 129900 16, 322128 129813 17)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -1441,7 +1969,9 @@ def testIdentifyVerticalLines(self): vl.elevationProperties().setExtrusionHeight(17) curve = QgsLineString() - curve.fromWkt('LineStringZ (322021.96201738982927054 129896.83061585001996718 0, 322116.8371042063809 129880.94244341662852094 0)') + curve.fromWkt( + "LineStringZ (322021.96201738982927054 129896.83061585001996718 0, 322116.8371042063809 129880.94244341662852094 0)" + ) req = QgsProfileRequest(curve) generator = vl.createProfileGenerator(req) @@ -1461,12 +1991,32 @@ def testIdentifyVerticalLines(self): res = r.identify(QgsProfilePoint(15, 14), context) self.assertEqual(len(res), 1) self.assertEqual(res[0].layer(), vl) - self.assertEqual(res[0].results(), [{'delta': 0.9654154289752465, 'distance': 15.895441865142377, 'elevation': 14.360847359216885, 'id': 1}]) + self.assertEqual( + res[0].results(), + [ + { + "delta": 0.9654154289752465, + "distance": 15.895441865142377, + "elevation": 14.360847359216885, + "id": 1, + } + ], + ) res = r.identify(QgsProfilePoint(15, 31), context) self.assertEqual(len(res), 1) self.assertEqual(res[0].layer(), vl) - self.assertEqual(res[0].results(), [{'delta': 0.8954418651423772, 'distance': 15.895441865142377, 'elevation': 31.0, 'id': 1}]) + self.assertEqual( + res[0].results(), + [ + { + "delta": 0.8954418651423772, + "distance": 15.895441865142377, + "elevation": 31.0, + "id": 1, + } + ], + ) res = r.identify(QgsProfilePoint(15, 35), context) self.assertFalse(res) @@ -1476,12 +2026,32 @@ def testIdentifyVerticalLines(self): res = r.identify(QgsProfilePoint(55, 16), context) self.assertEqual(len(res), 1) self.assertEqual(res[0].layer(), vl) - self.assertEqual(res[0].results(), [{'delta': 0.3133775679752489, 'distance': 55.279676009112876, 'elevation': 16.14137478571788, 'id': 2}]) + self.assertEqual( + res[0].results(), + [ + { + "delta": 0.3133775679752489, + "distance": 55.279676009112876, + "elevation": 16.14137478571788, + "id": 2, + } + ], + ) res = r.identify(QgsProfilePoint(55, 33), context) self.assertEqual(len(res), 1) self.assertEqual(res[0].layer(), vl) - self.assertEqual(res[0].results(), [{'delta': 0.27967600911287605, 'distance': 55.279676009112876, 'elevation': 33.0, 'id': 2}]) + self.assertEqual( + res[0].results(), + [ + { + "delta": 0.27967600911287605, + "distance": 55.279676009112876, + "elevation": 33.0, + "id": 2, + } + ], + ) res = r.identify(QgsProfilePoint(55, 36), context) self.assertFalse(res) @@ -1495,15 +2065,27 @@ def testIdentifyVerticalLines(self): res = r.identify(QgsProfilePoint(55, 22), context) self.assertEqual(len(res), 1) self.assertEqual(res[0].layer(), vl) - self.assertEqual(res[0].results(), [{'delta': 0.27967600911287605, 'distance': 55.279676009112876, 'elevation': 22.0, 'id': 2}]) + self.assertEqual( + res[0].results(), + [ + { + "delta": 0.27967600911287605, + "distance": 55.279676009112876, + "elevation": 22.0, + "id": 2, + } + ], + ) def testIdentifyPolygons(self): - vl = QgsVectorLayer('PolygonZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("PolygonZ?crs=EPSG:27700", "lines", "memory") self.assertTrue(vl.isValid()) vl.setCrs(QgsCoordinateReferenceSystem()) - for poly in ['PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))', - 'PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))']: + for poly in [ + "PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))", + "PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(poly)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -1511,7 +2093,9 @@ def testIdentifyPolygons(self): vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) curve = QgsLineString() - curve.fromWkt('LineStringZ (321944.79089414176996797 129899.10035476912162267 0, 321818.13946245843544602 129991.70570266660070047 0)') + curve.fromWkt( + "LineStringZ (321944.79089414176996797 129899.10035476912162267 0, 321818.13946245843544602 129991.70570266660070047 0)" + ) req = QgsProfileRequest(curve) generator = vl.createProfileGenerator(req) @@ -1531,7 +2115,17 @@ def testIdentifyPolygons(self): res = r.identify(QgsProfilePoint(27, 1.9), context) self.assertEqual(len(res), 1) self.assertEqual(res[0].layer(), vl) - self.assertEqual(res[0].results(), [{'delta': 0.3909814462196946, 'distance': 27.377976839618572, 'elevation': 2.0, 'id': 2}]) + self.assertEqual( + res[0].results(), + [ + { + "delta": 0.3909814462196946, + "distance": 27.377976839618572, + "elevation": 2.0, + "id": 2, + } + ], + ) res = r.identify(QgsProfilePoint(27, 7), context) self.assertFalse(res) @@ -1541,14 +2135,34 @@ def testIdentifyPolygons(self): res = r.identify(QgsProfilePoint(42, 3), context) self.assertEqual(len(res), 1) self.assertEqual(res[0].layer(), vl) - self.assertEqual(res[0].results(), [{'delta': 1.635491751097172, 'distance': 40.70584650527578, 'elevation': 2.0000000000000093, 'id': 2}]) + self.assertEqual( + res[0].results(), + [ + { + "delta": 1.635491751097172, + "distance": 40.70584650527578, + "elevation": 2.0000000000000093, + "id": 2, + } + ], + ) context.maximumPointDistanceDelta = 0.01 context.maximumSurfaceElevationDelta = 2 res = r.identify(QgsProfilePoint(35, 3), context) self.assertEqual(len(res), 1) self.assertEqual(res[0].layer(), vl) - self.assertEqual(res[0].results(), [{'delta': 0.9999999999968199, 'distance': 35.0, 'elevation': 2.00000000000318, 'id': 2}]) + self.assertEqual( + res[0].results(), + [ + { + "delta": 0.9999999999968199, + "distance": 35.0, + "elevation": 2.00000000000318, + "id": 2, + } + ], + ) context.maximumPointDistanceDelta = 0.01 context.maximumSurfaceElevationDelta = 2 @@ -1561,12 +2175,14 @@ def testIdentifyPolygons(self): self.assertFalse(res) def testIdentifyExtrudedPolygons(self): - vl = QgsVectorLayer('PolygonZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("PolygonZ?crs=EPSG:27700", "lines", "memory") self.assertTrue(vl.isValid()) vl.setCrs(QgsCoordinateReferenceSystem()) - for poly in ['PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))', - 'PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))']: + for poly in [ + "PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))", + "PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(poly)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -1576,7 +2192,9 @@ def testIdentifyExtrudedPolygons(self): vl.elevationProperties().setExtrusionHeight(17) curve = QgsLineString() - curve.fromWkt('LineStringZ (321944.79089414176996797 129899.10035476912162267 0, 321818.13946245843544602 129991.70570266660070047 0)') + curve.fromWkt( + "LineStringZ (321944.79089414176996797 129899.10035476912162267 0, 321818.13946245843544602 129991.70570266660070047 0)" + ) req = QgsProfileRequest(curve) generator = vl.createProfileGenerator(req) @@ -1596,12 +2214,32 @@ def testIdentifyExtrudedPolygons(self): res = r.identify(QgsProfilePoint(27, 1.9), context) self.assertEqual(len(res), 1) self.assertEqual(res[0].layer(), vl) - self.assertEqual(res[0].results(), [{'delta': 0.3909814462196946, 'distance': 27.377976839618572, 'elevation': 2.0, 'id': 2}]) + self.assertEqual( + res[0].results(), + [ + { + "delta": 0.3909814462196946, + "distance": 27.377976839618572, + "elevation": 2.0, + "id": 2, + } + ], + ) res = r.identify(QgsProfilePoint(27, 18.9), context) self.assertEqual(len(res), 1) self.assertEqual(res[0].layer(), vl) - self.assertEqual(res[0].results(), [{'delta': 0.39098144621969494, 'distance': 27.377976839618572, 'elevation': 19.0, 'id': 2}]) + self.assertEqual( + res[0].results(), + [ + { + "delta": 0.39098144621969494, + "distance": 27.377976839618572, + "elevation": 19.0, + "id": 2, + } + ], + ) res = r.identify(QgsProfilePoint(27, 22.9), context) self.assertFalse(res) @@ -1614,14 +2252,27 @@ def testIdentifyExtrudedPolygons(self): res = r.identify(QgsProfilePoint(42, 3), context) self.assertEqual(len(res), 1) self.assertEqual(res[0].layer(), vl) - self.assertEqual(res[0].results(), [{'delta': 1.635491751097172, 'distance': 40.70584650527578, 'elevation': 2.0000000000000093, 'id': 2}]) + self.assertEqual( + res[0].results(), + [ + { + "delta": 1.635491751097172, + "distance": 40.70584650527578, + "elevation": 2.0000000000000093, + "id": 2, + } + ], + ) context.maximumPointDistanceDelta = 0 context.maximumSurfaceElevationDelta = 0 res = r.identify(QgsProfilePoint(35, 16), context) self.assertEqual(len(res), 1) self.assertEqual(res[0].layer(), vl) - self.assertEqual(res[0].results(), [{'delta': 0.0, 'distance': 35.0, 'elevation': 16.0, 'id': 2}]) + self.assertEqual( + res[0].results(), + [{"delta": 0.0, "distance": 35.0, "elevation": 16.0, "id": 2}], + ) context.maximumPointDistanceDelta = 0.01 context.maximumSurfaceElevationDelta = 2 @@ -1634,16 +2285,17 @@ def testIdentifyExtrudedPolygons(self): self.assertFalse(res) def testRenderProfile(self): - vl = QgsVectorLayer('PolygonZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("PolygonZ?crs=EPSG:27700", "lines", "memory") vl.setCrs(QgsCoordinateReferenceSystem()) self.assertTrue(vl.isValid()) for line in [ - 'PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))', - 'PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))', - 'PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))', - 'PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))', - 'PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))']: + "PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))", + "PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))", + "PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))", + "PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))", + "PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -1651,13 +2303,16 @@ def testRenderProfile(self): vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) vl.elevationProperties().setExtrusionEnabled(True) vl.elevationProperties().setExtrusionHeight(7) - fill_symbol = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_style': 'no'}) + fill_symbol = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_style": "no"} + ) vl.elevationProperties().setRespectLayerSymbology(False) vl.elevationProperties().setProfileFillSymbol(fill_symbol) curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) @@ -1668,19 +2323,43 @@ def testRenderProfile(self): plot_renderer.waitForFinished() res = plot_renderer.renderToImage(400, 400, 0, curve.length(), 0, 14) - self.assertTrue(self.image_check('vector_polygon_no_layer_symbology', 'vector_polygon_no_layer_symbology', res)) + self.assertTrue( + self.image_check( + "vector_polygon_no_layer_symbology", + "vector_polygon_no_layer_symbology", + res, + ) + ) def testRenderProfileDataDefinedProperties(self): - vl = QgsVectorLayer('PolygonZ?crs=EPSG:27700&field=color:string', 'lines', 'memory') + vl = QgsVectorLayer( + "PolygonZ?crs=EPSG:27700&field=color:string", "lines", "memory" + ) vl.setCrs(QgsCoordinateReferenceSystem()) self.assertTrue(vl.isValid()) for color, line in [ - ('red', 'PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))'), - ('green', 'PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))'), - ('blue', 'PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))'), - ('purple', 'PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))'), - ('orange', 'PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))')]: + ( + "red", + "PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))", + ), + ( + "green", + "PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))", + ), + ( + "blue", + "PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))", + ), + ( + "purple", + "PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))", + ), + ( + "orange", + "PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))", + ), + ]: f = QgsFeature() f.setAttributes([color]) f.setGeometry(QgsGeometry.fromWkt(line)) @@ -1689,15 +2368,20 @@ def testRenderProfileDataDefinedProperties(self): vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) vl.elevationProperties().setExtrusionEnabled(True) vl.elevationProperties().setExtrusionHeight(7) - fill_symbol = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_style': 'no'}) - fill_symbol[0].dataDefinedProperties().setProperty(QgsSymbolLayer.Property.PropertyFillColor, QgsProperty.fromField('color')) + fill_symbol = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_style": "no"} + ) + fill_symbol[0].dataDefinedProperties().setProperty( + QgsSymbolLayer.Property.PropertyFillColor, QgsProperty.fromField("color") + ) vl.elevationProperties().setRespectLayerSymbology(False) vl.elevationProperties().setProfileFillSymbol(fill_symbol) curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) @@ -1708,34 +2392,44 @@ def testRenderProfileDataDefinedProperties(self): plot_renderer.waitForFinished() res = plot_renderer.renderToImage(400, 400, 0, curve.length(), 0, 14) - self.assertTrue(self.image_check('vector_polygon_data_defined_symbology', 'vector_polygon_data_defined_symbology', res)) + self.assertTrue( + self.image_check( + "vector_polygon_data_defined_symbology", + "vector_polygon_data_defined_symbology", + res, + ) + ) def testRenderProfileAsSurfaceLines(self): - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") vl.setCrs(QgsCoordinateReferenceSystem()) self.assertTrue(vl.isValid()) for line in [ - 'LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)', - 'LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)', - 'LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)', - 'LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)', - 'LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)']: + "LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)", + "LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)", + "LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)", + "LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)", + "LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) vl.elevationProperties().setType(Qgis.VectorProfileType.ContinuousSurface) - fill_symbol = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_style': 'no'}) + fill_symbol = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_style": "no"} + ) vl.elevationProperties().setRespectLayerSymbology(False) vl.elevationProperties().setProfileFillSymbol(fill_symbol) - line_symbol = QgsLineSymbol.createSimple({'color': '#ff00ff', 'width': '0.8'}) + line_symbol = QgsLineSymbol.createSimple({"color": "#ff00ff", "width": "0.8"}) vl.elevationProperties().setProfileLineSymbol(line_symbol) curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) @@ -1746,35 +2440,41 @@ def testRenderProfileAsSurfaceLines(self): plot_renderer.waitForFinished() res = plot_renderer.renderToImage(400, 400, 0, curve.length(), 0, 14) - self.assertTrue(self.image_check('vector_lines_as_surface', 'vector_lines_as_surface', res)) + self.assertTrue( + self.image_check("vector_lines_as_surface", "vector_lines_as_surface", res) + ) def testRenderProfileAsSurfaceLinesWithMarkers(self): - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") vl.setCrs(QgsCoordinateReferenceSystem()) self.assertTrue(vl.isValid()) for line in [ - 'LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)', - 'LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)', - 'LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)', - 'LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)', - 'LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)']: + "LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)", + "LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)", + "LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)", + "LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)", + "LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) vl.elevationProperties().setType(Qgis.VectorProfileType.ContinuousSurface) - marker_symbol = QgsMarkerSymbol.createSimple({'name': 'square', 'size': 4, 'color': '#00ff00', 'outline_style': 'no'}) + marker_symbol = QgsMarkerSymbol.createSimple( + {"name": "square", "size": 4, "color": "#00ff00", "outline_style": "no"} + ) vl.elevationProperties().setRespectLayerSymbology(False) vl.elevationProperties().setProfileMarkerSymbol(marker_symbol) - line_symbol = QgsLineSymbol.createSimple({'color': '#ff00ff', 'width': '0.8'}) + line_symbol = QgsLineSymbol.createSimple({"color": "#ff00ff", "width": "0.8"}) vl.elevationProperties().setProfileLineSymbol(line_symbol) vl.elevationProperties().setShowMarkerSymbolInSurfacePlots(True) curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) @@ -1785,19 +2485,27 @@ def testRenderProfileAsSurfaceLinesWithMarkers(self): plot_renderer.waitForFinished() res = plot_renderer.renderToImage(400, 400, 0, curve.length(), 0, 14) - self.assertTrue(self.image_check('vector_lines_as_surface_with_markers', 'vector_lines_as_surface_with_markers', res)) + self.assertTrue( + self.image_check( + "vector_lines_as_surface_with_markers", + "vector_lines_as_surface_with_markers", + res, + ) + ) def testRenderProfileAsLineWithHoledDtm(self): - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm_with_holes.tif'), 'DTM') + rl = QgsRasterLayer( + os.path.join(unitTestDataPath(), "3d", "dtm_with_holes.tif"), "DTM" + ) self.assertTrue(rl.isValid()) rl.elevationProperties().setEnabled(True) rl.elevationProperties().setProfileSymbology(Qgis.ProfileSurfaceSymbology.Line) - line_symbol = QgsLineSymbol.createSimple({'color': '#ff00ff', 'width': '0.8'}) + line_symbol = QgsLineSymbol.createSimple({"color": "#ff00ff", "width": "0.8"}) rl.elevationProperties().setProfileLineSymbol(line_symbol) curve = QgsLineString() - curve.fromWkt('LineString (320900 129000, 322900 129000)') + curve.fromWkt("LineString (320900 129000, 322900 129000)") req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) @@ -1808,21 +2516,33 @@ def testRenderProfileAsLineWithHoledDtm(self): plot_renderer.waitForFinished() res = plot_renderer.renderToImage(1600, 800, 0, curve.length(), 0, 90) - self.assertTrue(self.image_check('vector_lines_as_line_with_holed_dtm', 'vector_lines_as_line_with_holed_dtm', res)) + self.assertTrue( + self.image_check( + "vector_lines_as_line_with_holed_dtm", + "vector_lines_as_line_with_holed_dtm", + res, + ) + ) def testRenderProfileAsSurfaceFillBelowWithHoledDtm(self): - rl = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm_with_holes.tif'), 'DTM') + rl = QgsRasterLayer( + os.path.join(unitTestDataPath(), "3d", "dtm_with_holes.tif"), "DTM" + ) self.assertTrue(rl.isValid()) rl.elevationProperties().setEnabled(True) - rl.elevationProperties().setProfileSymbology(Qgis.ProfileSurfaceSymbology.FillBelow) - fill_symbol = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_style': 'no'}) + rl.elevationProperties().setProfileSymbology( + Qgis.ProfileSurfaceSymbology.FillBelow + ) + fill_symbol = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_style": "no"} + ) rl.elevationProperties().setProfileFillSymbol(fill_symbol) - line_symbol = QgsLineSymbol.createSimple({'color': '#ff00ff', 'width': '0.8'}) + line_symbol = QgsLineSymbol.createSimple({"color": "#ff00ff", "width": "0.8"}) rl.elevationProperties().setProfileLineSymbol(line_symbol) curve = QgsLineString() - curve.fromWkt('LineString (320900 129000, 322900 129000)') + curve.fromWkt("LineString (320900 129000, 322900 129000)") req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) @@ -1833,35 +2553,47 @@ def testRenderProfileAsSurfaceFillBelowWithHoledDtm(self): plot_renderer.waitForFinished() res = plot_renderer.renderToImage(1600, 800, 0, curve.length(), 0, 90) - self.assertTrue(self.image_check('vector_lines_as_fill_below_surface_with_holed_dtm', 'vector_lines_as_fill_below_surface_with_holed_dtm', res)) + self.assertTrue( + self.image_check( + "vector_lines_as_fill_below_surface_with_holed_dtm", + "vector_lines_as_fill_below_surface_with_holed_dtm", + res, + ) + ) def testRenderProfileAsSurfaceFillBelow(self): - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") vl.setCrs(QgsCoordinateReferenceSystem()) self.assertTrue(vl.isValid()) for line in [ - 'LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)', - 'LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)', - 'LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)', - 'LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)', - 'LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)']: + "LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)", + "LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)", + "LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)", + "LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)", + "LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) vl.elevationProperties().setType(Qgis.VectorProfileType.ContinuousSurface) - vl.elevationProperties().setProfileSymbology(Qgis.ProfileSurfaceSymbology.FillBelow) - fill_symbol = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_style': 'no'}) + vl.elevationProperties().setProfileSymbology( + Qgis.ProfileSurfaceSymbology.FillBelow + ) + fill_symbol = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_style": "no"} + ) vl.elevationProperties().setRespectLayerSymbology(False) vl.elevationProperties().setProfileFillSymbol(fill_symbol) - line_symbol = QgsLineSymbol.createSimple({'color': '#ff00ff', 'width': '0.8'}) + line_symbol = QgsLineSymbol.createSimple({"color": "#ff00ff", "width": "0.8"}) vl.elevationProperties().setProfileLineSymbol(line_symbol) curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) @@ -1872,37 +2604,48 @@ def testRenderProfileAsSurfaceFillBelow(self): plot_renderer.waitForFinished() res = plot_renderer.renderToImage(400, 400, 0, curve.length(), 0, 14) - self.assertTrue(self.image_check('vector_lines_as_fill_below_surface', 'vector_lines_as_fill_below_surface', res)) + self.assertTrue( + self.image_check( + "vector_lines_as_fill_below_surface", + "vector_lines_as_fill_below_surface", + res, + ) + ) def testRenderProfileAsSurfaceFillBelowLimit(self): - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") vl.setCrs(QgsCoordinateReferenceSystem()) self.assertTrue(vl.isValid()) for line in [ - 'LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)', - 'LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)', - 'LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)', - 'LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)', - 'LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)']: + "LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)", + "LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)", + "LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)", + "LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)", + "LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) vl.elevationProperties().setType(Qgis.VectorProfileType.ContinuousSurface) - vl.elevationProperties().setProfileSymbology(Qgis.ProfileSurfaceSymbology.FillBelow) - vl.elevationProperties().setElevationLimit( - 1) - fill_symbol = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_style': 'no'}) + vl.elevationProperties().setProfileSymbology( + Qgis.ProfileSurfaceSymbology.FillBelow + ) + vl.elevationProperties().setElevationLimit(1) + fill_symbol = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_style": "no"} + ) vl.elevationProperties().setRespectLayerSymbology(False) vl.elevationProperties().setProfileFillSymbol(fill_symbol) - line_symbol = QgsLineSymbol.createSimple({'color': '#ff00ff', 'width': '0.8'}) + line_symbol = QgsLineSymbol.createSimple({"color": "#ff00ff", "width": "0.8"}) vl.elevationProperties().setProfileLineSymbol(line_symbol) curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) @@ -1913,35 +2656,47 @@ def testRenderProfileAsSurfaceFillBelowLimit(self): plot_renderer.waitForFinished() res = plot_renderer.renderToImage(400, 400, 0, curve.length(), 0, 14) - self.assertTrue(self.image_check('vector_lines_as_fill_below_surface_limit', 'vector_lines_as_fill_below_surface_limit', res)) + self.assertTrue( + self.image_check( + "vector_lines_as_fill_below_surface_limit", + "vector_lines_as_fill_below_surface_limit", + res, + ) + ) def testRenderProfileAsSurfaceFillAbove(self): - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") vl.setCrs(QgsCoordinateReferenceSystem()) self.assertTrue(vl.isValid()) for line in [ - 'LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)', - 'LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)', - 'LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)', - 'LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)', - 'LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)']: + "LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)", + "LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)", + "LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)", + "LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)", + "LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) vl.elevationProperties().setType(Qgis.VectorProfileType.ContinuousSurface) - vl.elevationProperties().setProfileSymbology(Qgis.ProfileSurfaceSymbology.FillAbove) - fill_symbol = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_style': 'no'}) + vl.elevationProperties().setProfileSymbology( + Qgis.ProfileSurfaceSymbology.FillAbove + ) + fill_symbol = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_style": "no"} + ) vl.elevationProperties().setRespectLayerSymbology(False) vl.elevationProperties().setProfileFillSymbol(fill_symbol) - line_symbol = QgsLineSymbol.createSimple({'color': '#ff00ff', 'width': '0.8'}) + line_symbol = QgsLineSymbol.createSimple({"color": "#ff00ff", "width": "0.8"}) vl.elevationProperties().setProfileLineSymbol(line_symbol) curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) @@ -1952,37 +2707,48 @@ def testRenderProfileAsSurfaceFillAbove(self): plot_renderer.waitForFinished() res = plot_renderer.renderToImage(400, 400, 0, curve.length(), 0, 14) - self.assertTrue(self.image_check('vector_lines_as_fill_above_surface', 'vector_lines_as_fill_above_surface', res)) + self.assertTrue( + self.image_check( + "vector_lines_as_fill_above_surface", + "vector_lines_as_fill_above_surface", + res, + ) + ) def testRenderProfileAsSurfaceFillAboveLimit(self): - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") vl.setCrs(QgsCoordinateReferenceSystem()) self.assertTrue(vl.isValid()) for line in [ - 'LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)', - 'LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)', - 'LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)', - 'LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)', - 'LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)']: + "LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)", + "LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)", + "LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)", + "LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)", + "LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) vl.elevationProperties().setType(Qgis.VectorProfileType.ContinuousSurface) - vl.elevationProperties().setProfileSymbology(Qgis.ProfileSurfaceSymbology.FillAbove) - vl.elevationProperties().setElevationLimit( - 10) - fill_symbol = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_style': 'no'}) + vl.elevationProperties().setProfileSymbology( + Qgis.ProfileSurfaceSymbology.FillAbove + ) + vl.elevationProperties().setElevationLimit(10) + fill_symbol = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_style": "no"} + ) vl.elevationProperties().setRespectLayerSymbology(False) vl.elevationProperties().setProfileFillSymbol(fill_symbol) - line_symbol = QgsLineSymbol.createSimple({'color': '#ff00ff', 'width': '0.8'}) + line_symbol = QgsLineSymbol.createSimple({"color": "#ff00ff", "width": "0.8"}) vl.elevationProperties().setProfileLineSymbol(line_symbol) curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) @@ -1993,37 +2759,48 @@ def testRenderProfileAsSurfaceFillAboveLimit(self): plot_renderer.waitForFinished() res = plot_renderer.renderToImage(400, 400, 0, curve.length(), 0, 14) - self.assertTrue(self.image_check('vector_lines_as_fill_above_surface_limit', 'vector_lines_as_fill_above_surface_limit', res)) + self.assertTrue( + self.image_check( + "vector_lines_as_fill_above_surface_limit", + "vector_lines_as_fill_above_surface_limit", + res, + ) + ) def testRenderProfileAsSurfaceFillAboveLimitTolerance(self): - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") vl.setCrs(QgsCoordinateReferenceSystem()) self.assertTrue(vl.isValid()) for line in [ - 'LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)', - 'LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)', - 'LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)', - 'LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)', - 'LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)']: + "LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)", + "LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)", + "LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)", + "LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)", + "LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) vl.elevationProperties().setType(Qgis.VectorProfileType.ContinuousSurface) - vl.elevationProperties().setProfileSymbology(Qgis.ProfileSurfaceSymbology.FillAbove) - vl.elevationProperties().setElevationLimit( - 10) - fill_symbol = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_style': 'no'}) + vl.elevationProperties().setProfileSymbology( + Qgis.ProfileSurfaceSymbology.FillAbove + ) + vl.elevationProperties().setElevationLimit(10) + fill_symbol = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_style": "no"} + ) vl.elevationProperties().setRespectLayerSymbology(False) vl.elevationProperties().setProfileFillSymbol(fill_symbol) - line_symbol = QgsLineSymbol.createSimple({'color': '#ff00ff', 'width': '0.8'}) + line_symbol = QgsLineSymbol.createSimple({"color": "#ff00ff", "width": "0.8"}) vl.elevationProperties().setProfileLineSymbol(line_symbol) curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) @@ -2035,32 +2812,42 @@ def testRenderProfileAsSurfaceFillAboveLimitTolerance(self): plot_renderer.waitForFinished() res = plot_renderer.renderToImage(400, 400, 0, curve.length(), 0, 14) - self.assertTrue(self.image_check('vector_lines_as_fill_above_surface_limit_tolerance', 'vector_lines_as_fill_above_surface_limit_tolerance', res)) + self.assertTrue( + self.image_check( + "vector_lines_as_fill_above_surface_limit_tolerance", + "vector_lines_as_fill_above_surface_limit_tolerance", + res, + ) + ) def testRenderProfileSymbolWithMapUnits(self): - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") vl.setCrs(QgsCoordinateReferenceSystem()) self.assertTrue(vl.isValid()) for line in [ - 'LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)', - 'LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)', - 'LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)', - 'LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)', - 'LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)']: + "LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)", + "LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)", + "LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)", + "LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)", + "LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) - marker_symbol = QgsMarkerSymbol.createSimple({'name': 'square', 'size': 4, 'color': '#00ff00', 'outline_style': 'no'}) + marker_symbol = QgsMarkerSymbol.createSimple( + {"name": "square", "size": 4, "color": "#00ff00", "outline_style": "no"} + ) marker_symbol.setSizeUnit(Qgis.RenderUnit.MapUnits) vl.elevationProperties().setRespectLayerSymbology(False) vl.elevationProperties().setProfileMarkerSymbol(marker_symbol) curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) @@ -2071,32 +2858,38 @@ def testRenderProfileSymbolWithMapUnits(self): plot_renderer.waitForFinished() res = plot_renderer.renderToImage(400, 400, 0, curve.length(), 0, 14) - self.assertTrue(self.image_check('vector_profile_map_units', 'vector_profile_map_units', res)) + self.assertTrue( + self.image_check( + "vector_profile_map_units", "vector_profile_map_units", res + ) + ) def testRenderProfileSymbolWithMapUnitsTolerance(self): - vl = QgsVectorLayer('LineStringZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") vl.setCrs(QgsCoordinateReferenceSystem()) self.assertTrue(vl.isValid()) for line in [ - 'LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)', - 'LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)', - 'LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)', - 'LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)', - 'LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)']: + "LineStringZ (321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1)", + "LineStringZ (321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2)", + "LineStringZ (321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3)", + "LineStringZ (321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4)", + "LineStringZ (322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5)", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) vl.elevationProperties().setRespectLayerSymbology(False) - line_symbol = QgsLineSymbol.createSimple({'color': '#ff00ff', 'width': '0.8'}) + line_symbol = QgsLineSymbol.createSimple({"color": "#ff00ff", "width": "0.8"}) line_symbol.setWidthUnit(Qgis.RenderUnit.MapUnits) vl.elevationProperties().setProfileLineSymbol(line_symbol) curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) @@ -2108,19 +2901,26 @@ def testRenderProfileSymbolWithMapUnitsTolerance(self): plot_renderer.waitForFinished() res = plot_renderer.renderToImage(400, 400, 0, curve.length(), 0, 14) - self.assertTrue(self.image_check('vector_profile_map_units_tolerance', 'vector_profile_map_units_tolerance', res)) + self.assertTrue( + self.image_check( + "vector_profile_map_units_tolerance", + "vector_profile_map_units_tolerance", + res, + ) + ) def testRenderLayerSymbology(self): - vl = QgsVectorLayer('PolygonZ?crs=EPSG:27700', 'lines', 'memory') + vl = QgsVectorLayer("PolygonZ?crs=EPSG:27700", "lines", "memory") vl.setCrs(QgsCoordinateReferenceSystem()) self.assertTrue(vl.isValid()) for line in [ - 'PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))', - 'PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))', - 'PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))', - 'PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))', - 'PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))']: + "PolygonZ ((321829.48893365426920354 129991.38697145861806348 1, 321847.89668515208177269 129996.63588572069420479 1, 321848.97131609614007175 129979.22330882755341008 1, 321830.31725845142500475 129978.07136809575604275 1, 321829.48893365426920354 129991.38697145861806348 1))", + "PolygonZ ((321920.00953056826256216 129924.58260190498549491 2, 321924.65299345907988027 129908.43546159457764588 2, 321904.78543491888558492 129903.99811821122420952 2, 321900.80605239619035274 129931.39860145389684476 2, 321904.84799937985371798 129931.71552911199978553 2, 321908.93646715773502365 129912.90030360443051904 2, 321914.20495146053144708 129913.67693978428724222 2, 321911.30165811872575432 129923.01272751353099011 2, 321920.00953056826256216 129924.58260190498549491 2))", + "PolygonZ ((321923.10517279652412981 129919.61521573827485554 3, 321922.23537852568551898 129928.3598982143739704 3, 321928.60423935484141111 129934.22530528216157109 3, 321929.39881197665818036 129923.29054521876969375 3, 321930.55804549407912418 129916.53248518184409477 3, 321923.10517279652412981 129919.61521573827485554 3))", + "PolygonZ ((321990.47451346553862095 129909.63588680300745182 4, 321995.04325810901354998 129891.84052284323843196 4, 321989.66826330573530868 129890.5092018858413212 4, 321990.78512359503656626 129886.49917887404444627 4, 321987.37291929306229576 129885.64982962771318853 4, 321985.2254804756375961 129893.81317058412241749 4, 321987.63158903241856024 129894.41078495365218259 4, 321984.34022761805681512 129907.57450046355370432 4, 321990.47451346553862095 129909.63588680300745182 4))", + "PolygonZ ((322103.03910495212767273 129795.91051736124791205 5, 322108.25568856322206557 129804.76113295342656784 5, 322113.29666162584908307 129803.9285887333098799 5, 322117.78645010641776025 129794.48194090687320568 5, 322103.03910495212767273 129795.91051736124791205 5))", + ]: f = QgsFeature() f.setGeometry(QgsGeometry.fromWkt(line)) self.assertTrue(vl.dataProvider().addFeature(f)) @@ -2128,21 +2928,51 @@ def testRenderLayerSymbology(self): vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) vl.elevationProperties().setExtrusionEnabled(True) vl.elevationProperties().setExtrusionHeight(7) - fill_symbol = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_style': 'no'}) + fill_symbol = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_style": "no"} + ) vl.elevationProperties().setRespectLayerSymbology(True) vl.elevationProperties().setProfileFillSymbol(fill_symbol) - renderer = QgsCategorizedSymbolRenderer('$id', [ - QgsRendererCategory(1, QgsFillSymbol.createSimple({'color': '#0000ff', 'outline_style': 'no'}), '1'), - QgsRendererCategory(2, QgsFillSymbol.createSimple({'color': '#00ffff', 'outline_style': 'no'}), '2'), - QgsRendererCategory(3, QgsFillSymbol.createSimple({'color': '#3388ff', 'outline_style': 'no'}), '3'), - QgsRendererCategory(4, QgsFillSymbol.createSimple({'color': '#883388', 'outline_style': 'no'}), '4'), - ]) + renderer = QgsCategorizedSymbolRenderer( + "$id", + [ + QgsRendererCategory( + 1, + QgsFillSymbol.createSimple( + {"color": "#0000ff", "outline_style": "no"} + ), + "1", + ), + QgsRendererCategory( + 2, + QgsFillSymbol.createSimple( + {"color": "#00ffff", "outline_style": "no"} + ), + "2", + ), + QgsRendererCategory( + 3, + QgsFillSymbol.createSimple( + {"color": "#3388ff", "outline_style": "no"} + ), + "3", + ), + QgsRendererCategory( + 4, + QgsFillSymbol.createSimple( + {"color": "#883388", "outline_style": "no"} + ), + "4", + ), + ], + ) vl.setRenderer(renderer) curve = QgsLineString() curve.fromWkt( - 'LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)') + "LineString (321897.18831187387695536 129916.86947759155009408, 321942.11597351566888392 129924.94403429214435164)" + ) req = QgsProfileRequest(curve) req.setTransformContext(self.create_transform_context()) @@ -2153,9 +2983,19 @@ def testRenderLayerSymbology(self): plot_renderer.waitForFinished() res = plot_renderer.renderToImage(400, 400, 0, curve.length(), 0, 14) - self.assertTrue(self.image_check('vector_polygon_layer_symbology', 'vector_polygon_layer_symbology', res)) - - def doCheckPoint(self, request: QgsProfileRequest, tolerance: float, layer: QgsVectorLayer, expectedFeatures): + self.assertTrue( + self.image_check( + "vector_polygon_layer_symbology", "vector_polygon_layer_symbology", res + ) + ) + + def doCheckPoint( + self, + request: QgsProfileRequest, + tolerance: float, + layer: QgsVectorLayer, + expectedFeatures, + ): request.setTolerance(tolerance) profGen = layer.createProfileGenerator(request) @@ -2166,7 +3006,7 @@ def doCheckPoint(self, request: QgsProfileRequest, tolerance: float, layer: QgsV self.assertFalse(len(features) == 0) expected = sorted(expectedFeatures.copy()) - actual = [f.attributes['id'] for _, f in enumerate(features)] + actual = [f.attributes["id"] for _, f in enumerate(features)] actualUniqSorted = sorted(list(set(actual))) self.assertEqual(actualUniqSorted, expected) @@ -2184,14 +3024,22 @@ def doCheckPoint(self, request: QgsProfileRequest, tolerance: float, layer: QgsV return results - def doCheckLine(self, request: QgsProfileRequest, tolerance: float, layer: QgsVectorLayer, expectedFeatures, nbSubGeomPerFeature, geomType): + def doCheckLine( + self, + request: QgsProfileRequest, + tolerance: float, + layer: QgsVectorLayer, + expectedFeatures, + nbSubGeomPerFeature, + geomType, + ): results = self.doCheckPoint(request, tolerance, layer, expectedFeatures) features = results.asFeatures(Qgis.ProfileExportType.Features3D) - actual = [f.attributes['id'] for _, f in enumerate(features)] + actual = [f.attributes["id"] for _, f in enumerate(features)] actualUniqSorted = sorted(list(set(actual))) for idx, fid in enumerate(actualUniqSorted): - actual = [1 for _, f in enumerate(features) if f.attributes['id'] == fid] + actual = [1 for _, f in enumerate(features) if f.attributes["id"] == fid] self.assertEqual(len(actual), nbSubGeomPerFeature[idx]) for k, feat in enumerate(features): @@ -2203,25 +3051,26 @@ def doCheckLine(self, request: QgsProfileRequest, tolerance: float, layer: QgsVe return results def testPointGenerationFeature(self): - vl = QgsVectorLayer(os.path.join(unitTestDataPath(), '3d', 'points_with_z.shp')) + vl = QgsVectorLayer(os.path.join(unitTestDataPath(), "3d", "points_with_z.shp")) self.assertTrue(vl.isValid()) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Terrain) vl.elevationProperties().setBinding(Qgis.AltitudeBinding.Vertex) - dtmLayer = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif')) + dtmLayer = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif")) self.assertTrue(dtmLayer.isValid()) curve = QgsLineString() curve.fromWkt( - 'LineString (-346120 6631840, -346550 6632030, -346440 6632140, -347830 6632930)') + "LineString (-346120 6631840, -346550 6632030, -346440 6632140, -347830 6632930)" + ) req = QgsProfileRequest(curve) terrain_provider = QgsRasterDemTerrainProvider() terrain_provider.setLayer(dtmLayer) req.setTerrainProvider(terrain_provider) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) if Qgis.geosVersionMajor() == 3 and Qgis.geosVersionMinor() <= 10: self.doCheckPoint(req, 15, vl, [5, 11, 12, 13, 14, 15, 18, 45, 46]) @@ -2232,29 +3081,35 @@ def testPointGenerationFeature(self): elif Qgis.geosVersionMajor() == 3 and Qgis.geosVersionMinor() >= 13: self.doCheckPoint(req, 15, vl, [5, 11, 12, 13, 14, 15, 18, 45, 46]) - self.doCheckPoint(req, 70, vl, [0, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 38, 45, 46, 48]) + self.doCheckPoint( + req, + 70, + vl, + [0, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 38, 45, 46, 48], + ) def testLineGenerationFeature(self): - vl = QgsVectorLayer(os.path.join(unitTestDataPath(), '3d', 'lines.shp')) + vl = QgsVectorLayer(os.path.join(unitTestDataPath(), "3d", "lines.shp")) self.assertTrue(vl.isValid()) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Terrain) vl.elevationProperties().setBinding(Qgis.AltitudeBinding.Vertex) vl.elevationProperties().setExtrusionEnabled(False) - dtmLayer = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif')) + dtmLayer = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif")) self.assertTrue(dtmLayer.isValid()) curve = QgsLineString() curve.fromWkt( - 'LineString (-346120 6631840, -346550 6632030, -346440 6632140, -347830 6632930)') + "LineString (-346120 6631840, -346550 6632030, -346440 6632140, -347830 6632930)" + ) req = QgsProfileRequest(curve) terrain_provider = QgsRasterDemTerrainProvider() terrain_provider.setLayer(dtmLayer) req.setTerrainProvider(terrain_provider) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) # check no tolerance self.doCheckLine(req, 0, vl, [0, 2], [1, 5], Qgis.GeometryType.Point) @@ -2281,51 +3136,166 @@ def testLineGenerationFeature(self): self.doCheckLine(req, 50, vl, [1, 0, 2], [1, 1, 1], Qgis.GeometryType.Line) def testPolygonGenerationFeature(self): - vl = QgsVectorLayer(os.path.join(unitTestDataPath(), '3d', 'buildings.shp')) + vl = QgsVectorLayer(os.path.join(unitTestDataPath(), "3d", "buildings.shp")) self.assertTrue(vl.isValid()) vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Terrain) vl.elevationProperties().setBinding(Qgis.AltitudeBinding.Vertex) vl.elevationProperties().setExtrusionEnabled(False) - dtmLayer = QgsRasterLayer(os.path.join(unitTestDataPath(), '3d', 'dtm.tif')) + dtmLayer = QgsRasterLayer(os.path.join(unitTestDataPath(), "3d", "dtm.tif")) self.assertTrue(dtmLayer.isValid()) curve = QgsLineString() curve.fromWkt( - 'LineString (-346120 6631840, -346550 6632030, -346440 6632140, -347830 6632930)') + "LineString (-346120 6631840, -346550 6632030, -346440 6632140, -347830 6632930)" + ) req = QgsProfileRequest(curve) terrain_provider = QgsRasterDemTerrainProvider() terrain_provider.setLayer(dtmLayer) req.setTerrainProvider(terrain_provider) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) - self.doCheckLine(req, 1, vl, [168, 206, 210, 284, 306, 321], [1, 1, 1, 1, 1, 1], Qgis.GeometryType.Line) + self.doCheckLine( + req, + 1, + vl, + [168, 206, 210, 284, 306, 321], + [1, 1, 1, 1, 1, 1], + Qgis.GeometryType.Line, + ) if Qgis.geosVersionMajor() == 3 and Qgis.geosVersionMinor() <= 10: - self.doCheckLine(req, 10, vl, [168, 172, 206, 210, 231, 267, 275, 282, 284, 306, 307, 319, 321], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], Qgis.GeometryType.Line) - self.doCheckLine(req, 11, vl, [168, 172, 206, 210, 231, 255, 267, 275, 282, 283, 284, 306, 307, 319, 321], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], Qgis.GeometryType.Line) + self.doCheckLine( + req, + 10, + vl, + [168, 172, 206, 210, 231, 267, 275, 282, 284, 306, 307, 319, 321], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + Qgis.GeometryType.Line, + ) + self.doCheckLine( + req, + 11, + vl, + [ + 168, + 172, + 206, + 210, + 231, + 255, + 267, + 275, + 282, + 283, + 284, + 306, + 307, + 319, + 321, + ], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + Qgis.GeometryType.Line, + ) elif Qgis.geosVersionMajor() == 3 and Qgis.geosVersionMinor() == 11: - self.doCheckLine(req, 9, vl, [168, 172, 206, 210, 231, 267, 275, 282, 284, 306, 307, 319, 321], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], Qgis.GeometryType.Line) - self.doCheckLine(req, 10, vl, [168, 172, 206, 210, 231, 267, 275, 282, 283, 284, 306, 307, 319, 321], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], Qgis.GeometryType.Line) + self.doCheckLine( + req, + 9, + vl, + [168, 172, 206, 210, 231, 267, 275, 282, 284, 306, 307, 319, 321], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + Qgis.GeometryType.Line, + ) + self.doCheckLine( + req, + 10, + vl, + [168, 172, 206, 210, 231, 267, 275, 282, 283, 284, 306, 307, 319, 321], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + Qgis.GeometryType.Line, + ) elif Qgis.geosVersionMajor() == 3 and Qgis.geosVersionMinor() == 12: - self.doCheckLine(req, 10, vl, [168, 172, 206, 210, 231, 267, 275, 282, 283, 284, 306, 307, 319, 321], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], Qgis.GeometryType.Line) - self.doCheckLine(req, 11, vl, [168, 172, 206, 210, 231, 237, 255, 267, 275, 282, 283, 284, 306, 307, 319, 321], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], Qgis.GeometryType.Line) + self.doCheckLine( + req, + 10, + vl, + [168, 172, 206, 210, 231, 267, 275, 282, 283, 284, 306, 307, 319, 321], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + Qgis.GeometryType.Line, + ) + self.doCheckLine( + req, + 11, + vl, + [ + 168, + 172, + 206, + 210, + 231, + 237, + 255, + 267, + 275, + 282, + 283, + 284, + 306, + 307, + 319, + 321, + ], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + Qgis.GeometryType.Line, + ) elif Qgis.geosVersionMajor() == 3 and Qgis.geosVersionMinor() >= 13: - self.doCheckLine(req, 10, vl, [168, 172, 206, 210, 231, 267, 275, 282, 284, 306, 307, 319, 321], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], Qgis.GeometryType.Line) - self.doCheckLine(req, 11, vl, [168, 172, 206, 210, 231, 255, 267, 275, 282, 283, 284, 306, 307, 319, 321], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], Qgis.GeometryType.Line) + self.doCheckLine( + req, + 10, + vl, + [168, 172, 206, 210, 231, 267, 275, 282, 284, 306, 307, 319, 321], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + Qgis.GeometryType.Line, + ) + self.doCheckLine( + req, + 11, + vl, + [ + 168, + 172, + 206, + 210, + 231, + 255, + 267, + 275, + 282, + 283, + 284, + 306, + 307, + 319, + 321, + ], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + Qgis.GeometryType.Line, + ) def testPolyhedralSurfaceGenerationFeature(self): # Create a Vector Layer and add a polyhedralSurface feature - vl = QgsVectorLayer("PolyhedralSurfaceZ?crs=epsg:27700", "polyhedral_surface", "memory") + vl = QgsVectorLayer( + "PolyhedralSurfaceZ?crs=epsg:27700", "polyhedral_surface", "memory" + ) self.assertTrue(vl.isValid()) - self.assertEqual(vl.crs().authid(), 'EPSG:27700') + self.assertEqual(vl.crs().authid(), "EPSG:27700") vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) vl.elevationProperties().setExtrusionEnabled(False) - wkt_str = 'POLYHEDRALSURFACE Z(((321474.91 129812.38 -20.00,322277.09 130348.29 -20.00,322631.00 129738.23 -20.00,321434.46 129266.36 -20.00,321474.91 129812.38 -20.00)),((321474.91 129812.38 30.00,321434.46 129266.36 30.00,322631.00 129738.23 30.00,322277.09 130348.29 30.00,321474.91 129812.38 30.00)),((321474.91 129812.38 -20.00,321474.91 129812.38 30.00,322277.09 130348.29 30.00,322277.09 130348.29 -20.00,321474.91 129812.38 -20.00)),((322277.09 130348.29 -20.00,322277.09 130348.29 30.00,322631.00 129738.23 30.00,322631.00 129738.23 -20.00,322277.09 130348.29 -20.00)),((322631.00 129738.23 -20.00,322631.00 129738.23 30.00,321434.46 129266.36 30.00,321434.46 129266.36 -20.00,322631.00 129738.23 -20.00)),((321434.46 129266.36 -20.00,321434.46 129266.36 30.00,321474.91 129812.38 30.00,321474.91 129812.38 -20.00,321434.46 129266.36 -20.00)))' + wkt_str = "POLYHEDRALSURFACE Z(((321474.91 129812.38 -20.00,322277.09 130348.29 -20.00,322631.00 129738.23 -20.00,321434.46 129266.36 -20.00,321474.91 129812.38 -20.00)),((321474.91 129812.38 30.00,321434.46 129266.36 30.00,322631.00 129738.23 30.00,322277.09 130348.29 30.00,321474.91 129812.38 30.00)),((321474.91 129812.38 -20.00,321474.91 129812.38 30.00,322277.09 130348.29 30.00,322277.09 130348.29 -20.00,321474.91 129812.38 -20.00)),((322277.09 130348.29 -20.00,322277.09 130348.29 30.00,322631.00 129738.23 30.00,322631.00 129738.23 -20.00,322277.09 130348.29 -20.00)),((322631.00 129738.23 -20.00,322631.00 129738.23 30.00,321434.46 129266.36 30.00,321434.46 129266.36 -20.00,322631.00 129738.23 -20.00)),((321434.46 129266.36 -20.00,321434.46 129266.36 30.00,321474.91 129812.38 30.00,321474.91 129812.38 -20.00,321434.46 129266.36 -20.00)))" vl_feature = QgsFeature() vl_feature.setGeometry(QgsGeometry.fromWkt(wkt_str)) self.assertTrue(vl.dataProvider().addFeature(vl_feature)) @@ -2333,10 +3303,11 @@ def testPolyhedralSurfaceGenerationFeature(self): # Do an intersection curve = QgsLineString() curve.fromWkt( - 'LineString (-346120 6631840, -346550 6632030, -346440 6632140, -347830 6632930)') + "LineString (-346120 6631840, -346550 6632030, -346440 6632140, -347830 6632930)" + ) req = QgsProfileRequest(curve) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) req.setTolerance(10) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) @@ -2352,24 +3323,22 @@ def testPolyhedralSurfaceGenerationFeature(self): self.assertTrue(multi_line.geometryN(0).numPoints(), 27) wkts_results = [ { - 'result': multi_line.geometryN(0).pointN(12), - 'expected': 'PointZ (-347168.3 6632565.4 -20)' - + "result": multi_line.geometryN(0).pointN(12), + "expected": "PointZ (-347168.3 6632565.4 -20)", }, { - 'result': multi_line.geometryN(0).pointN(16), - 'expected': 'PointZ (-346431 6632144.3 -20)' - + "result": multi_line.geometryN(0).pointN(16), + "expected": "PointZ (-346431 6632144.3 -20)", }, { - 'result': multi_line.geometryN(2), - 'expected': 'LineStringZ (-347186.6 6632552.8 -6.3, -347168.3 6632565.4 -5.6)' - } + "result": multi_line.geometryN(2), + "expected": "LineStringZ (-347186.6 6632552.8 -6.3, -347168.3 6632565.4 -5.6)", + }, ] for wkt in wkts_results: - expected = wkt['expected'] - result = wkt['result'].asWkt(1) - error_message = f'Expected: {expected}\nGot: {result}\n' + expected = wkt["expected"] + result = wkt["result"].asWkt(1) + error_message = f"Expected: {expected}\nGot: {result}\n" self.assertTrue(compareWkt(expected, result, 0.1), error_message) def testVerticalLineGenerationFeatureTolerance(self): @@ -2378,21 +3347,26 @@ def testVerticalLineGenerationFeatureTolerance(self): """ vl = QgsVectorLayer("LineStringZ?crs=epsg:27700", "line", "memory") self.assertTrue(vl.isValid()) - self.assertEqual(vl.crs().authid(), 'EPSG:27700') + self.assertEqual(vl.crs().authid(), "EPSG:27700") vl.elevationProperties().setClamping(Qgis.AltitudeClamping.Absolute) vl.elevationProperties().setExtrusionEnabled(False) vl_feature = QgsFeature() - vl_feature.setGeometry(QgsGeometry.fromWkt('LineStringZ(321777 129912 1, 321777 129912 -22, 321777 129912 1))')) + vl_feature.setGeometry( + QgsGeometry.fromWkt( + "LineStringZ(321777 129912 1, 321777 129912 -22, 321777 129912 1))" + ) + ) self.assertTrue(vl.dataProvider().addFeature(vl_feature)) # Do an intersection curve = QgsLineString() curve.fromWkt( - 'LineString (-346120 6631840, -346550 6632030, -346440 6632140, -347830 6632930)') + "LineString (-346120 6631840, -346550 6632030, -346440 6632140, -347830 6632930)" + ) req = QgsProfileRequest(curve) - req.setCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + req.setCrs(QgsCoordinateReferenceSystem("EPSG:3857")) req.setTolerance(10) generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) @@ -2407,8 +3381,10 @@ def testVerticalLineGenerationFeatureTolerance(self): expected_wkt = "LineStringZ (-347055.8 6632478.8 1, -347055.8 6632478.8 -22, -347055.8 6632478.8 1)" else: expected_wkt = "LineStringZ (-347054.8 6632479.6 1, -347054.8 6632479.6 -22, -347054.8 6632479.6 1)" - self.assertTrue(compareWkt(expected_wkt, result.asWkt(), 0.1), - f'Expected: {expected_wkt}\nGot: {result.asWkt()}\n') + self.assertTrue( + compareWkt(expected_wkt, result.asWkt(), 0.1), + f"Expected: {expected_wkt}\nGot: {result.asWkt()}\n", + ) def test_vertical_transformation_4978_to_4985(self): """ @@ -2417,25 +3393,24 @@ def test_vertical_transformation_4978_to_4985(self): EPSG:4979 to EPSG:4985 """ - vl = QgsVectorLayer('PointZ?crs=EPSG:4979', '4979_points', 'memory') + vl = QgsVectorLayer("PointZ?crs=EPSG:4979", "4979_points", "memory") self.assertTrue(vl.isValid()) - self.assertEqual(vl.crs().authid(), 'EPSG:4979') + self.assertEqual(vl.crs().authid(), "EPSG:4979") - self.assertEqual(vl.crs3D().horizontalCrs().authid(), 'EPSG:4979') + self.assertEqual(vl.crs3D().horizontalCrs().authid(), "EPSG:4979") f = QgsFeature() - f.setGeometry(QgsPoint(134.445567853, - -23.445567853, - 5543.325)) + f.setGeometry(QgsPoint(134.445567853, -23.445567853, 5543.325)) self.assertTrue(vl.dataProvider().addFeature(f)) - profile_crs = QgsCoordinateReferenceSystem('EPSG:4985') + profile_crs = QgsCoordinateReferenceSystem("EPSG:4985") self.assertTrue(profile_crs.isValid()) - self.assertEqual(profile_crs.horizontalCrs().authid(), 'EPSG:4985') + self.assertEqual(profile_crs.horizontalCrs().authid(), "EPSG:4985") curve = QgsLineString() curve.fromWkt( - 'LineString (134.405567853 -23.435567853, 134.485567853 -23.455567853)') + "LineString (134.405567853 -23.435567853, 134.485567853 -23.455567853)" + ) request = QgsProfileRequest(curve) request.setCrs(profile_crs) request.setTolerance(1) @@ -2454,38 +3429,39 @@ def testProfileTransformGDA2020toAVWS(self): Test a profile requiring a vertical datum transform from GDA2020 to AVWS """ # GDA2020 vertical CRS - vl = QgsVectorLayer('PointZ?crs=EPSG:7843', 'gda2020points', 'memory') + vl = QgsVectorLayer("PointZ?crs=EPSG:7843", "gda2020points", "memory") self.assertTrue(vl.isValid()) - self.assertEqual(vl.crs().authid(), 'EPSG:7843') + self.assertEqual(vl.crs().authid(), "EPSG:7843") - self.assertEqual(vl.crs3D().horizontalCrs().authid(), 'EPSG:7843') + self.assertEqual(vl.crs3D().horizontalCrs().authid(), "EPSG:7843") f = QgsFeature() - f.setGeometry(QgsPoint(134.445567853, - -23.445567853, - 5543.325)) + f.setGeometry(QgsPoint(134.445567853, -23.445567853, 5543.325)) self.assertTrue(vl.dataProvider().addFeature(f)) profile_crs, msg = QgsCoordinateReferenceSystem.createCompoundCrs( - QgsCoordinateReferenceSystem('EPSG:7844'), - QgsCoordinateReferenceSystem('EPSG:9458')) + QgsCoordinateReferenceSystem("EPSG:7844"), + QgsCoordinateReferenceSystem("EPSG:9458"), + ) self.assertFalse(msg) self.assertTrue(profile_crs.isValid()) - self.assertEqual(profile_crs.horizontalCrs().authid(), 'EPSG:7844') - self.assertEqual(profile_crs.verticalCrs().authid(), 'EPSG:9458') + self.assertEqual(profile_crs.horizontalCrs().authid(), "EPSG:7844") + self.assertEqual(profile_crs.verticalCrs().authid(), "EPSG:9458") - available_operations = QgsDatumTransform.operations(vl.crs3D(), - profile_crs) + available_operations = QgsDatumTransform.operations(vl.crs3D(), profile_crs) self.assertEqual(len(available_operations[0].grids), 1) - self.assertEqual(available_operations[0].grids[0].shortName, - 'au_ga_AGQG_20201120.tif') + self.assertEqual( + available_operations[0].grids[0].shortName, "au_ga_AGQG_20201120.tif" + ) if not available_operations[0].isAvailable: self.skipTest( - f'Required grid {available_operations[0].grids[0].shortName} not available on system') + f"Required grid {available_operations[0].grids[0].shortName} not available on system" + ) curve = QgsLineString() curve.fromWkt( - 'LineString (134.445567853 -23.445567853, 135.445567853 -23.445567853)') + "LineString (134.445567853 -23.445567853, 135.445567853 -23.445567853)" + ) request = QgsProfileRequest(curve) request.setCrs(profile_crs) request.setTolerance(1) @@ -2505,32 +3481,34 @@ def testProfileTransformAVWStoGDA2020(self): Test a profile requiring a AVWS vertical datum transform to GDA2020 """ # AVWS vertical CRS - vl = QgsVectorLayer('PointZ?crs=EPSG:7844', 'gda2020points', 'memory') + vl = QgsVectorLayer("PointZ?crs=EPSG:7844", "gda2020points", "memory") self.assertTrue(vl.isValid()) - self.assertEqual(vl.crs().authid(), 'EPSG:7844') - vl.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:9458')) + self.assertEqual(vl.crs().authid(), "EPSG:7844") + vl.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:9458")) - self.assertEqual(vl.crs3D().horizontalCrs().authid(), 'EPSG:7844') - self.assertEqual(vl.crs3D().verticalCrs().authid(), 'EPSG:9458') + self.assertEqual(vl.crs3D().horizontalCrs().authid(), "EPSG:7844") + self.assertEqual(vl.crs3D().verticalCrs().authid(), "EPSG:9458") f = QgsFeature() - f.setGeometry(QgsPoint(134.445567853, - -23.445567853, - 5524.13969)) + f.setGeometry(QgsPoint(134.445567853, -23.445567853, 5524.13969)) self.assertTrue(vl.dataProvider().addFeature(f)) - profile_crs = QgsCoordinateReferenceSystem('EPSG:7843') + profile_crs = QgsCoordinateReferenceSystem("EPSG:7843") - available_operations = QgsDatumTransform.operations(vl.crs3D(), - profile_crs) + available_operations = QgsDatumTransform.operations(vl.crs3D(), profile_crs) self.assertEqual(len(available_operations[0].grids), 1) - self.assertEqual(available_operations[0].grids[0].shortName, 'au_ga_AGQG_20201120.tif') + self.assertEqual( + available_operations[0].grids[0].shortName, "au_ga_AGQG_20201120.tif" + ) if not available_operations[0].isAvailable: - self.skipTest(f'Required grid {available_operations[0].grids[0].shortName} not available on system') + self.skipTest( + f"Required grid {available_operations[0].grids[0].shortName} not available on system" + ) curve = QgsLineString() curve.fromWkt( - 'LineString (134.445567853 -23.445567853, 135.445567853 -23.445567853)') + "LineString (134.445567853 -23.445567853, 135.445567853 -23.445567853)" + ) request = QgsProfileRequest(curve) request.setCrs(profile_crs) request.setTolerance(1) @@ -2550,36 +3528,40 @@ def testProfileTransformGDA2020toAHD(self): Test a profile requiring a vertical datum transform from GDA2020 to AHD """ # GDA2020 vertical CRS - vl = QgsVectorLayer('PointZ?crs=EPSG:7843', 'gda2020points', 'memory') + vl = QgsVectorLayer("PointZ?crs=EPSG:7843", "gda2020points", "memory") self.assertTrue(vl.isValid()) - self.assertEqual(vl.crs().authid(), 'EPSG:7843') + self.assertEqual(vl.crs().authid(), "EPSG:7843") - self.assertEqual(vl.crs3D().horizontalCrs().authid(), 'EPSG:7843') + self.assertEqual(vl.crs3D().horizontalCrs().authid(), "EPSG:7843") f = QgsFeature() - f.setGeometry(QgsPoint(134.445567853, - -23.445567853, - 5543.325)) + f.setGeometry(QgsPoint(134.445567853, -23.445567853, 5543.325)) self.assertTrue(vl.dataProvider().addFeature(f)) profile_crs, msg = QgsCoordinateReferenceSystem.createCompoundCrs( - QgsCoordinateReferenceSystem('EPSG:7844'), - QgsCoordinateReferenceSystem('EPSG:5711')) + QgsCoordinateReferenceSystem("EPSG:7844"), + QgsCoordinateReferenceSystem("EPSG:5711"), + ) self.assertFalse(msg) self.assertTrue(profile_crs.isValid()) - self.assertEqual(profile_crs.horizontalCrs().authid(), 'EPSG:7844') - self.assertEqual(profile_crs.verticalCrs().authid(), 'EPSG:5711') + self.assertEqual(profile_crs.horizontalCrs().authid(), "EPSG:7844") + self.assertEqual(profile_crs.verticalCrs().authid(), "EPSG:5711") - available_operations = QgsDatumTransform.operations(vl.crs3D(), - profile_crs) + available_operations = QgsDatumTransform.operations(vl.crs3D(), profile_crs) self.assertEqual(len(available_operations[0].grids), 1) - self.assertEqual(available_operations[0].grids[0].shortName, 'au_ga_AUSGeoid2020_20180201.tif') + self.assertEqual( + available_operations[0].grids[0].shortName, + "au_ga_AUSGeoid2020_20180201.tif", + ) if not available_operations[0].isAvailable: - self.skipTest(f'Required grid {available_operations[0].grids[0].shortName} not available on system') + self.skipTest( + f"Required grid {available_operations[0].grids[0].shortName} not available on system" + ) curve = QgsLineString() curve.fromWkt( - 'LineString (134.445567853 -23.445567853, 135.445567853 -23.445567853)') + "LineString (134.445567853 -23.445567853, 135.445567853 -23.445567853)" + ) request = QgsProfileRequest(curve) request.setCrs(profile_crs) request.setTolerance(1) @@ -2599,32 +3581,35 @@ def testProfileTransformAHDtoGDA2020(self): Test a profile requiring a AHD vertical datum transform to GDA2020 """ # AHD vertical CRS - vl = QgsVectorLayer('PointZ?crs=EPSG:7844', 'gda2020points', 'memory') + vl = QgsVectorLayer("PointZ?crs=EPSG:7844", "gda2020points", "memory") self.assertTrue(vl.isValid()) - self.assertEqual(vl.crs().authid(), 'EPSG:7844') - vl.setVerticalCrs(QgsCoordinateReferenceSystem('EPSG:5711')) + self.assertEqual(vl.crs().authid(), "EPSG:7844") + vl.setVerticalCrs(QgsCoordinateReferenceSystem("EPSG:5711")) - self.assertEqual(vl.crs3D().horizontalCrs().authid(), 'EPSG:7844') - self.assertEqual(vl.crs3D().verticalCrs().authid(), 'EPSG:5711') + self.assertEqual(vl.crs3D().horizontalCrs().authid(), "EPSG:7844") + self.assertEqual(vl.crs3D().verticalCrs().authid(), "EPSG:5711") f = QgsFeature() - f.setGeometry(QgsPoint(134.445567853, - -23.445567853, - 5523.598)) + f.setGeometry(QgsPoint(134.445567853, -23.445567853, 5523.598)) self.assertTrue(vl.dataProvider().addFeature(f)) - profile_crs = QgsCoordinateReferenceSystem('EPSG:7843') + profile_crs = QgsCoordinateReferenceSystem("EPSG:7843") - available_operations = QgsDatumTransform.operations(vl.crs3D(), - profile_crs) + available_operations = QgsDatumTransform.operations(vl.crs3D(), profile_crs) self.assertEqual(len(available_operations[0].grids), 1) - self.assertEqual(available_operations[0].grids[0].shortName, 'au_ga_AUSGeoid2020_20180201.tif') + self.assertEqual( + available_operations[0].grids[0].shortName, + "au_ga_AUSGeoid2020_20180201.tif", + ) if not available_operations[0].isAvailable: - self.skipTest(f'Required grid {available_operations[0].grids[0].shortName} not available on system') + self.skipTest( + f"Required grid {available_operations[0].grids[0].shortName} not available on system" + ) curve = QgsLineString() curve.fromWkt( - 'LineString (134.445567853 -23.445567853, 135.445567853 -23.445567853)') + "LineString (134.445567853 -23.445567853, 135.445567853 -23.445567853)" + ) request = QgsProfileRequest(curve) request.setCrs(profile_crs) request.setTolerance(1) @@ -2640,5 +3625,5 @@ def testProfileTransformAHDtoGDA2020(self): self.assertAlmostEqual(res.constGet().z(), 5543.325, 3) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorlayerrenderer.py b/tests/src/python/test_qgsvectorlayerrenderer.py index df9aee2bda8f..67644fc8a3b9 100644 --- a/tests/src/python/test_qgsvectorlayerrenderer.py +++ b/tests/src/python/test_qgsvectorlayerrenderer.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2020-06' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2020-06" +__copyright__ = "Copyright 2020, The QGIS Project" import os @@ -47,35 +48,45 @@ class TestQgsVectorLayerRenderer(QgisTestCase): @classmethod def control_path_prefix(cls): - return 'vectorlayerrenderer' + return "vectorlayerrenderer" def testRenderWithIntersectsRegions(self): - poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'polys.shp')) + poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "polys.shp")) self.assertTrue(poly_layer.isValid()) - sym1 = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_color': '#000000', 'outline_width': '1'}) + sym1 = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_color": "#000000", "outline_width": "1"} + ) renderer = QgsSingleSymbolRenderer(sym1) poly_layer.setRenderer(renderer) mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) - mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) - mapsettings.setExtent(QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5)) + mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) + mapsettings.setExtent( + QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5) + ) mapsettings.setLayers([poly_layer]) - region = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon ((-11725957 5368254, -12222900 4807501, -12246014 3834025, -12014878 3496059, -11259833 3518307, -10751333 3621153, -10574129 4516741, -10847640 5194995, -11105742 5325957, -11725957 5368254))')) + region = QgsMapClippingRegion( + QgsGeometry.fromWkt( + "Polygon ((-11725957 5368254, -12222900 4807501, -12246014 3834025, -12014878 3496059, -11259833 3518307, -10751333 3621153, -10574129 4516741, -10847640 5194995, -11105742 5325957, -11725957 5368254))" + ) + ) region.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.NoClipping) - region2 = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon ((-11032549 5421399, -11533344 4693167, -11086481 4229112, -11167378 3742984, -10616504 3553984, -10161936 3925771, -9618766 4668482, -9472380 5620753, -10115709 5965063, -11032549 5421399))')) + region2 = QgsMapClippingRegion( + QgsGeometry.fromWkt( + "Polygon ((-11032549 5421399, -11533344 4693167, -11086481 4229112, -11167378 3742984, -10616504 3553984, -10161936 3925771, -9618766 4668482, -9472380 5620753, -10115709 5965063, -11032549 5421399))" + ) + ) region2.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.NoClipping) mapsettings.addClippingRegion(region) mapsettings.addClippingRegion(region2) self.assertTrue( self.render_map_settings_check( - 'intersects_region', - 'intersects_region', - mapsettings + "intersects_region", "intersects_region", mapsettings ) ) @@ -85,39 +96,51 @@ def testRenderWithIntersectsRegions(self): self.assertTrue( self.render_map_settings_check( - 'intersects_region', - 'intersects_region', - mapsettings + "intersects_region", "intersects_region", mapsettings ) ) def testRenderWithIntersectionRegions(self): - poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'polys.shp')) + poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "polys.shp")) self.assertTrue(poly_layer.isValid()) - sym1 = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_color': '#000000', 'outline_width': '1'}) + sym1 = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_color": "#000000", "outline_width": "1"} + ) renderer = QgsSingleSymbolRenderer(sym1) poly_layer.setRenderer(renderer) mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) - mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) - mapsettings.setExtent(QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5)) + mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) + mapsettings.setExtent( + QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5) + ) mapsettings.setLayers([poly_layer]) - region = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon ((-11725957 5368254, -12222900 4807501, -12246014 3834025, -12014878 3496059, -11259833 3518307, -10751333 3621153, -10574129 4516741, -10847640 5194995, -11105742 5325957, -11725957 5368254))')) - region.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipToIntersection) - region2 = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon ((-11032549 5421399, -11533344 4693167, -11086481 4229112, -11167378 3742984, -10616504 3553984, -10161936 3925771, -9618766 4668482, -9472380 5620753, -10115709 5965063, -11032549 5421399))')) - region2.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipToIntersection) + region = QgsMapClippingRegion( + QgsGeometry.fromWkt( + "Polygon ((-11725957 5368254, -12222900 4807501, -12246014 3834025, -12014878 3496059, -11259833 3518307, -10751333 3621153, -10574129 4516741, -10847640 5194995, -11105742 5325957, -11725957 5368254))" + ) + ) + region.setFeatureClip( + QgsMapClippingRegion.FeatureClippingType.ClipToIntersection + ) + region2 = QgsMapClippingRegion( + QgsGeometry.fromWkt( + "Polygon ((-11032549 5421399, -11533344 4693167, -11086481 4229112, -11167378 3742984, -10616504 3553984, -10161936 3925771, -9618766 4668482, -9472380 5620753, -10115709 5965063, -11032549 5421399))" + ) + ) + region2.setFeatureClip( + QgsMapClippingRegion.FeatureClippingType.ClipToIntersection + ) mapsettings.addClippingRegion(region) mapsettings.addClippingRegion(region2) self.assertTrue( self.render_map_settings_check( - 'intersection_region', - 'intersection_region', - mapsettings + "intersection_region", "intersection_region", mapsettings ) ) @@ -127,9 +150,7 @@ def testRenderWithIntersectionRegions(self): self.assertTrue( self.render_map_settings_check( - 'intersection_region', - 'intersection_region', - mapsettings + "intersection_region", "intersection_region", mapsettings ) ) @@ -138,14 +159,18 @@ def testIntersectionRuleBased(self): Test that rule based renderer using intersection clip paths correctly uses original feature area for rule evaluation, not clipped area """ - poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'polys.shp')) + poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "polys.shp")) self.assertTrue(poly_layer.isValid()) - sym1 = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_color': '#000000', 'outline_width': '1'}) - sym2 = QgsFillSymbol.createSimple({'color': '#00ffff', 'outline_color': '#000000', 'outline_width': '1'}) + sym1 = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_color": "#000000", "outline_width": "1"} + ) + sym2 = QgsFillSymbol.createSimple( + {"color": "#00ffff", "outline_color": "#000000", "outline_width": "1"} + ) - r1 = QgsRuleBasedRenderer.Rule(sym1, 0, 0, 'area($geometry)>25') - r2 = QgsRuleBasedRenderer.Rule(sym2, 0, 0, 'ELSE') + r1 = QgsRuleBasedRenderer.Rule(sym1, 0, 0, "area($geometry)>25") + r2 = QgsRuleBasedRenderer.Rule(sym2, 0, 0, "ELSE") rootrule = QgsRuleBasedRenderer.Rule(None) rootrule.appendChild(r1) @@ -156,25 +181,35 @@ def testIntersectionRuleBased(self): mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) - mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) - mapsettings.setExtent(QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5)) + mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) + mapsettings.setExtent( + QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5) + ) mapsettings.setLayers([poly_layer]) - mapsettings.setEllipsoid('') - - region = QgsMapClippingRegion(QgsGeometry.fromWkt( - 'Polygon ((-11725957 5368254, -12222900 4807501, -12246014 3834025, -12014878 3496059, -11259833 3518307, -10751333 3621153, -10574129 4516741, -10847640 5194995, -11105742 5325957, -11725957 5368254))')) - region.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipToIntersection) - region2 = QgsMapClippingRegion(QgsGeometry.fromWkt( - 'Polygon ((-11032549 5421399, -11533344 4693167, -11086481 4229112, -11167378 3742984, -10616504 3553984, -10161936 3925771, -9618766 4668482, -9472380 5620753, -10115709 5965063, -11032549 5421399))')) - region2.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipToIntersection) + mapsettings.setEllipsoid("") + + region = QgsMapClippingRegion( + QgsGeometry.fromWkt( + "Polygon ((-11725957 5368254, -12222900 4807501, -12246014 3834025, -12014878 3496059, -11259833 3518307, -10751333 3621153, -10574129 4516741, -10847640 5194995, -11105742 5325957, -11725957 5368254))" + ) + ) + region.setFeatureClip( + QgsMapClippingRegion.FeatureClippingType.ClipToIntersection + ) + region2 = QgsMapClippingRegion( + QgsGeometry.fromWkt( + "Polygon ((-11032549 5421399, -11533344 4693167, -11086481 4229112, -11167378 3742984, -10616504 3553984, -10161936 3925771, -9618766 4668482, -9472380 5620753, -10115709 5965063, -11032549 5421399))" + ) + ) + region2.setFeatureClip( + QgsMapClippingRegion.FeatureClippingType.ClipToIntersection + ) mapsettings.addClippingRegion(region) mapsettings.addClippingRegion(region2) self.assertTrue( self.render_map_settings_check( - 'intersection_rule_based', - 'intersection_rule_based', - mapsettings + "intersection_rule_based", "intersection_rule_based", mapsettings ) ) @@ -184,39 +219,47 @@ def testIntersectionRuleBased(self): self.assertTrue( self.render_map_settings_check( - 'intersection_rule_based', - 'intersection_rule_based', - mapsettings + "intersection_rule_based", "intersection_rule_based", mapsettings ) ) def testRenderWithPainterClipRegions(self): - poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'polys.shp')) + poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "polys.shp")) self.assertTrue(poly_layer.isValid()) - sym1 = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_color': '#000000', 'outline_width': '1'}) + sym1 = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_color": "#000000", "outline_width": "1"} + ) renderer = QgsSingleSymbolRenderer(sym1) poly_layer.setRenderer(renderer) mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) - mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) - mapsettings.setExtent(QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5)) + mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) + mapsettings.setExtent( + QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5) + ) mapsettings.setLayers([poly_layer]) - region = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon ((-11725957 5368254, -12222900 4807501, -12246014 3834025, -12014878 3496059, -11259833 3518307, -10751333 3621153, -10574129 4516741, -10847640 5194995, -11105742 5325957, -11725957 5368254))')) + region = QgsMapClippingRegion( + QgsGeometry.fromWkt( + "Polygon ((-11725957 5368254, -12222900 4807501, -12246014 3834025, -12014878 3496059, -11259833 3518307, -10751333 3621153, -10574129 4516741, -10847640 5194995, -11105742 5325957, -11725957 5368254))" + ) + ) region.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipPainterOnly) - region2 = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon ((-11032549 5421399, -11533344 4693167, -11086481 4229112, -11167378 3742984, -10616504 3553984, -10161936 3925771, -9618766 4668482, -9472380 5620753, -10115709 5965063, -11032549 5421399))')) + region2 = QgsMapClippingRegion( + QgsGeometry.fromWkt( + "Polygon ((-11032549 5421399, -11533344 4693167, -11086481 4229112, -11167378 3742984, -10616504 3553984, -10161936 3925771, -9618766 4668482, -9472380 5620753, -10115709 5965063, -11032549 5421399))" + ) + ) region2.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipPainterOnly) mapsettings.addClippingRegion(region) mapsettings.addClippingRegion(region2) self.assertTrue( self.render_map_settings_check( - 'painterclip_region', - 'painterclip_region', - mapsettings + "painterclip_region", "painterclip_region", mapsettings ) ) @@ -226,37 +269,40 @@ def testRenderWithPainterClipRegions(self): self.assertTrue( self.render_map_settings_check( - 'painterclip_region', - 'painterclip_region', - mapsettings + "painterclip_region", "painterclip_region", mapsettings ) ) def testRenderWithPainterClipRegionsMultiPolygon(self): - poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'polys.shp')) + poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "polys.shp")) self.assertTrue(poly_layer.isValid()) - sym1 = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_color': '#000000', 'outline_width': '1'}) + sym1 = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_color": "#000000", "outline_width": "1"} + ) renderer = QgsSingleSymbolRenderer(sym1) poly_layer.setRenderer(renderer) mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) - mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) - mapsettings.setExtent(QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5)) + mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) + mapsettings.setExtent( + QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5) + ) mapsettings.setLayers([poly_layer]) - region = QgsMapClippingRegion(QgsGeometry.fromWkt( - 'MultiSurface (Polygon ((-10856627.66351187042891979 5625411.45629768911749125, -11083997.96136780828237534 4995770.63146586995571852, -10887235.20360786281526089 4357384.79517805296927691, -9684796.12840820662677288 4851477.9424419105052948, -10069576.63247209787368774 5428648.69853774644434452, -10856627.66351187042891979 5625411.45629768911749125)),Polygon ((-12045949.22152753174304962 5533588.83600971661508083, -12758667.65519132651388645 4868967.96535390708595514, -12478827.28859940730035305 4296169.71498607192188501, -11783598.87784760631620884 4077544.42858613422140479, -11223918.14466376602649689 4715930.26487395167350769, -11127723.01864779368042946 5673509.01930567622184753, -11359465.8222317285835743 5809056.69687363691627979, -12045949.22152753174304962 5533588.83600971661508083),(-11341975.79931973293423653 4790262.86224992945790291, -11722383.7976556234061718 4318032.24362606555223465, -12019714.18715953826904297 4606617.62167398259043694, -11757363.84347961470484734 4908320.51690589636564255, -11341975.79931973293423653 4790262.86224992945790291)))')) + region = QgsMapClippingRegion( + QgsGeometry.fromWkt( + "MultiSurface (Polygon ((-10856627.66351187042891979 5625411.45629768911749125, -11083997.96136780828237534 4995770.63146586995571852, -10887235.20360786281526089 4357384.79517805296927691, -9684796.12840820662677288 4851477.9424419105052948, -10069576.63247209787368774 5428648.69853774644434452, -10856627.66351187042891979 5625411.45629768911749125)),Polygon ((-12045949.22152753174304962 5533588.83600971661508083, -12758667.65519132651388645 4868967.96535390708595514, -12478827.28859940730035305 4296169.71498607192188501, -11783598.87784760631620884 4077544.42858613422140479, -11223918.14466376602649689 4715930.26487395167350769, -11127723.01864779368042946 5673509.01930567622184753, -11359465.8222317285835743 5809056.69687363691627979, -12045949.22152753174304962 5533588.83600971661508083),(-11341975.79931973293423653 4790262.86224992945790291, -11722383.7976556234061718 4318032.24362606555223465, -12019714.18715953826904297 4606617.62167398259043694, -11757363.84347961470484734 4908320.51690589636564255, -11341975.79931973293423653 4790262.86224992945790291)))" + ) + ) region.setFeatureClip(QgsMapClippingRegion.FeatureClippingType.ClipPainterOnly) mapsettings.addClippingRegion(region) self.assertTrue( self.render_map_settings_check( - 'painterclip_region_multi', - 'painterclip_region_multi', - mapsettings + "painterclip_region_multi", "painterclip_region_multi", mapsettings ) ) @@ -266,17 +312,17 @@ def testRenderWithPainterClipRegionsMultiPolygon(self): self.assertTrue( self.render_map_settings_check( - 'painterclip_region_multi', - 'painterclip_region_multi', - mapsettings + "painterclip_region_multi", "painterclip_region_multi", mapsettings ) ) def testRenderMultipleRenderersBelow(self): - poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'polys.shp')) + poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "polys.shp")) self.assertTrue(poly_layer.isValid()) - sym1 = QgsFillSymbol.createSimple({'color': '#ffaaff', 'outline_color': '#000000', 'outline_width': '1'}) + sym1 = QgsFillSymbol.createSimple( + {"color": "#ffaaff", "outline_color": "#000000", "outline_width": "1"} + ) renderer = QgsSingleSymbolRenderer(sym1) poly_layer.setRenderer(renderer) @@ -284,63 +330,87 @@ def testRenderMultipleRenderersBelow(self): class Gen1(QgsFeatureRendererGenerator): def id(self): - return 'Gen1' + return "Gen1" def level(self): return -2 def createRenderer(self): renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('Name') + renderer.setClassAttribute("Name") sym1 = QgsFillSymbol.createSimple( - {'color': '#ffaaff', 'outline_color': '#33aa33', 'outline_width': '3'}) + { + "color": "#ffaaff", + "outline_color": "#33aa33", + "outline_width": "3", + } + ) sym2 = QgsFillSymbol.createSimple( - {'color': '#ffaaff', 'outline_color': '#aa33aa', 'outline_width': '3'}) - - renderer.addCategory(QgsRendererCategory('Dam', sym1, 'Dam')) - renderer.addCategory(QgsRendererCategory('Lake', sym2, 'Lake')) + { + "color": "#ffaaff", + "outline_color": "#aa33aa", + "outline_width": "3", + } + ) + + renderer.addCategory(QgsRendererCategory("Dam", sym1, "Dam")) + renderer.addCategory(QgsRendererCategory("Lake", sym2, "Lake")) return renderer # add secondary renderer, for rendering below class Gen2(QgsFeatureRendererGenerator): def id(self): - return 'Gen2' + return "Gen2" def level(self): return -3 def createRenderer(self): renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('Value < 12') + renderer.setClassAttribute("Value < 12") sym1 = QgsFillSymbol.createSimple( - {'color': '#ffaaff', 'outline_color': '#aa1111', 'outline_width': '5'}) + { + "color": "#ffaaff", + "outline_color": "#aa1111", + "outline_width": "5", + } + ) sym2 = QgsFillSymbol.createSimple( - {'color': '#ffaaff', 'outline_color': '#1111dd', 'outline_width': '5'}) - - renderer.addCategory(QgsRendererCategory('1', sym1, '1')) - renderer.addCategory(QgsRendererCategory('0', sym2, '0')) + { + "color": "#ffaaff", + "outline_color": "#1111dd", + "outline_width": "5", + } + ) + + renderer.addCategory(QgsRendererCategory("1", sym1, "1")) + renderer.addCategory(QgsRendererCategory("0", sym2, "0")) return renderer poly_layer.addFeatureRendererGenerator(Gen1()) - self.assertEqual([g.id() for g in poly_layer.featureRendererGenerators()], ['Gen1']) + self.assertEqual( + [g.id() for g in poly_layer.featureRendererGenerators()], ["Gen1"] + ) poly_layer.addFeatureRendererGenerator(Gen2()) - self.assertEqual([g.id() for g in poly_layer.featureRendererGenerators()], ['Gen1', 'Gen2']) + self.assertEqual( + [g.id() for g in poly_layer.featureRendererGenerators()], ["Gen1", "Gen2"] + ) mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) - mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) - mapsettings.setExtent(QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5)) + mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) + mapsettings.setExtent( + QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5) + ) mapsettings.setLayers([poly_layer]) self.assertTrue( self.render_map_settings_check( - 'multiple_renderers_below', - 'multiple_renderers_below', - mapsettings + "multiple_renderers_below", "multiple_renderers_below", mapsettings ) ) @@ -350,28 +420,34 @@ def createRenderer(self): self.assertTrue( self.render_map_settings_check( - 'multiple_renderers_below', - 'multiple_renderers_below', - mapsettings + "multiple_renderers_below", "multiple_renderers_below", mapsettings ) ) - poly_layer.removeFeatureRendererGenerator('Gen3') - self.assertEqual([g.id() for g in poly_layer.featureRendererGenerators()], ['Gen1', 'Gen2']) - poly_layer.removeFeatureRendererGenerator('Gen1') - self.assertEqual([g.id() for g in poly_layer.featureRendererGenerators()], ['Gen2']) - poly_layer.removeFeatureRendererGenerator('Gen1') - self.assertEqual([g.id() for g in poly_layer.featureRendererGenerators()], ['Gen2']) - poly_layer.removeFeatureRendererGenerator('Gen2') + poly_layer.removeFeatureRendererGenerator("Gen3") + self.assertEqual( + [g.id() for g in poly_layer.featureRendererGenerators()], ["Gen1", "Gen2"] + ) + poly_layer.removeFeatureRendererGenerator("Gen1") + self.assertEqual( + [g.id() for g in poly_layer.featureRendererGenerators()], ["Gen2"] + ) + poly_layer.removeFeatureRendererGenerator("Gen1") + self.assertEqual( + [g.id() for g in poly_layer.featureRendererGenerators()], ["Gen2"] + ) + poly_layer.removeFeatureRendererGenerator("Gen2") self.assertEqual([g.id() for g in poly_layer.featureRendererGenerators()], []) - poly_layer.removeFeatureRendererGenerator('Gen1') + poly_layer.removeFeatureRendererGenerator("Gen1") self.assertEqual([g.id() for g in poly_layer.featureRendererGenerators()], []) def testRenderMultipleRenderersAbove(self): - poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'polys.shp')) + poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "polys.shp")) self.assertTrue(poly_layer.isValid()) - sym1 = QgsFillSymbol.createSimple({'color': '#ffaaff', 'outline_color': '#000000', 'outline_width': '1'}) + sym1 = QgsFillSymbol.createSimple( + {"color": "#ffaaff", "outline_color": "#000000", "outline_width": "1"} + ) renderer = QgsSingleSymbolRenderer(sym1) poly_layer.setRenderer(renderer) @@ -379,73 +455,89 @@ def testRenderMultipleRenderersAbove(self): class Gen1(QgsFeatureRendererGenerator): def id(self): - return 'Gen1' + return "Gen1" def level(self): return 3 def createRenderer(self): renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('Name') + renderer.setClassAttribute("Name") cf1 = QgsCentroidFillSymbolLayer() - cf1.setSubSymbol(QgsMarkerSymbol.createSimple( - {'color': '#33aa33', 'outline_style': 'no', 'size': '5'})) + cf1.setSubSymbol( + QgsMarkerSymbol.createSimple( + {"color": "#33aa33", "outline_style": "no", "size": "5"} + ) + ) sym1 = QgsFillSymbol([cf1]) cf2 = QgsCentroidFillSymbolLayer() - cf2.setSubSymbol(QgsMarkerSymbol.createSimple( - {'color': '#aa33aa', 'outline_style': 'no', 'size': '5'})) + cf2.setSubSymbol( + QgsMarkerSymbol.createSimple( + {"color": "#aa33aa", "outline_style": "no", "size": "5"} + ) + ) sym2 = QgsFillSymbol([cf2]) - renderer.addCategory(QgsRendererCategory('Dam', sym1, 'Dam')) - renderer.addCategory(QgsRendererCategory('Lake', sym2, 'Lake')) + renderer.addCategory(QgsRendererCategory("Dam", sym1, "Dam")) + renderer.addCategory(QgsRendererCategory("Lake", sym2, "Lake")) return renderer # add secondary renderer, for rendering below class Gen2(QgsFeatureRendererGenerator): def id(self): - return 'Gen2' + return "Gen2" def level(self): return 2 def createRenderer(self): renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('Value < 12') + renderer.setClassAttribute("Value < 12") cf1 = QgsCentroidFillSymbolLayer() - cf1.setSubSymbol(QgsMarkerSymbol.createSimple( - {'color': '#aa1111', 'outline_style': 'no', 'size': '8'})) + cf1.setSubSymbol( + QgsMarkerSymbol.createSimple( + {"color": "#aa1111", "outline_style": "no", "size": "8"} + ) + ) sym1 = QgsFillSymbol([cf1]) cf2 = QgsCentroidFillSymbolLayer() - cf2.setSubSymbol(QgsMarkerSymbol.createSimple( - {'color': '#1111dd', 'outline_style': 'no', 'size': '8'})) + cf2.setSubSymbol( + QgsMarkerSymbol.createSimple( + {"color": "#1111dd", "outline_style": "no", "size": "8"} + ) + ) sym2 = QgsFillSymbol([cf2]) - renderer.addCategory(QgsRendererCategory('1', sym1, '1')) - renderer.addCategory(QgsRendererCategory('0', sym2, '0')) + renderer.addCategory(QgsRendererCategory("1", sym1, "1")) + renderer.addCategory(QgsRendererCategory("0", sym2, "0")) return renderer poly_layer.addFeatureRendererGenerator(Gen1()) - self.assertEqual([g.id() for g in poly_layer.featureRendererGenerators()], ['Gen1']) + self.assertEqual( + [g.id() for g in poly_layer.featureRendererGenerators()], ["Gen1"] + ) poly_layer.addFeatureRendererGenerator(Gen2()) - self.assertEqual([g.id() for g in poly_layer.featureRendererGenerators()], ['Gen1', 'Gen2']) + self.assertEqual( + [g.id() for g in poly_layer.featureRendererGenerators()], ["Gen1", "Gen2"] + ) mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) - mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) - mapsettings.setExtent(QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5)) + mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) + mapsettings.setExtent( + QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5) + ) mapsettings.setLayers([poly_layer]) self.assertTrue( self.render_map_settings_check( - 'multiple_renderers_above', - 'multiple_renderers_above', - mapsettings + "multiple_renderers_above", "multiple_renderers_above", mapsettings ) ) @@ -455,17 +547,17 @@ def createRenderer(self): self.assertTrue( self.render_map_settings_check( - 'multiple_renderers_above', - 'multiple_renderers_above', - mapsettings + "multiple_renderers_above", "multiple_renderers_above", mapsettings ) ) def testRenderMultipleRenderersAboveAndBelow(self): - poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'polys.shp')) + poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "polys.shp")) self.assertTrue(poly_layer.isValid()) - sym1 = QgsFillSymbol.createSimple({'color': '#ffaaff', 'outline_color': '#000000', 'outline_width': '1'}) + sym1 = QgsFillSymbol.createSimple( + {"color": "#ffaaff", "outline_color": "#000000", "outline_width": "1"} + ) renderer = QgsSingleSymbolRenderer(sym1) poly_layer.setRenderer(renderer) @@ -473,54 +565,66 @@ def testRenderMultipleRenderersAboveAndBelow(self): class Gen1(QgsFeatureRendererGenerator): def id(self): - return 'Gen1' + return "Gen1" def level(self): return 3 def createRenderer(self): renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('Name') + renderer.setClassAttribute("Name") cf1 = QgsCentroidFillSymbolLayer() - cf1.setSubSymbol(QgsMarkerSymbol.createSimple( - {'color': '#33aa33', 'outline_style': 'no', 'size': '5'})) + cf1.setSubSymbol( + QgsMarkerSymbol.createSimple( + {"color": "#33aa33", "outline_style": "no", "size": "5"} + ) + ) sym1 = QgsFillSymbol([cf1]) cf2 = QgsCentroidFillSymbolLayer() - cf2.setSubSymbol(QgsMarkerSymbol.createSimple( - {'color': '#aa33aa', 'outline_style': 'no', 'size': '5'})) + cf2.setSubSymbol( + QgsMarkerSymbol.createSimple( + {"color": "#aa33aa", "outline_style": "no", "size": "5"} + ) + ) sym2 = QgsFillSymbol([cf2]) - renderer.addCategory(QgsRendererCategory('Dam', sym1, 'Dam')) - renderer.addCategory(QgsRendererCategory('Lake', sym2, 'Lake')) + renderer.addCategory(QgsRendererCategory("Dam", sym1, "Dam")) + renderer.addCategory(QgsRendererCategory("Lake", sym2, "Lake")) return renderer # add secondary renderer, for rendering below class Gen2(QgsFeatureRendererGenerator): def id(self): - return 'Gen2' + return "Gen2" def level(self): return 2 def createRenderer(self): renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('Value < 12') + renderer.setClassAttribute("Value < 12") cf1 = QgsCentroidFillSymbolLayer() - cf1.setSubSymbol(QgsMarkerSymbol.createSimple( - {'color': '#aa1111', 'outline_style': 'no', 'size': '8'})) + cf1.setSubSymbol( + QgsMarkerSymbol.createSimple( + {"color": "#aa1111", "outline_style": "no", "size": "8"} + ) + ) sym1 = QgsFillSymbol([cf1]) cf2 = QgsCentroidFillSymbolLayer() - cf2.setSubSymbol(QgsMarkerSymbol.createSimple( - {'color': '#1111dd', 'outline_style': 'no', 'size': '8'})) + cf2.setSubSymbol( + QgsMarkerSymbol.createSimple( + {"color": "#1111dd", "outline_style": "no", "size": "8"} + ) + ) sym2 = QgsFillSymbol([cf2]) - renderer.addCategory(QgsRendererCategory('1', sym1, '1')) - renderer.addCategory(QgsRendererCategory('0', sym2, '0')) + renderer.addCategory(QgsRendererCategory("1", sym1, "1")) + renderer.addCategory(QgsRendererCategory("0", sym2, "0")) return renderer # add secondary renderer, for rendering below @@ -528,44 +632,64 @@ def createRenderer(self): class Gen1b(QgsFeatureRendererGenerator): def id(self): - return 'Gen1b' + return "Gen1b" def level(self): return -2 def createRenderer(self): renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('Name') + renderer.setClassAttribute("Name") sym1 = QgsFillSymbol.createSimple( - {'color': '#ffaaff', 'outline_color': '#33aa33', 'outline_width': '3'}) + { + "color": "#ffaaff", + "outline_color": "#33aa33", + "outline_width": "3", + } + ) sym2 = QgsFillSymbol.createSimple( - {'color': '#ffaaff', 'outline_color': '#aa33aa', 'outline_width': '3'}) - - renderer.addCategory(QgsRendererCategory('Dam', sym1, 'Dam')) - renderer.addCategory(QgsRendererCategory('Lake', sym2, 'Lake')) + { + "color": "#ffaaff", + "outline_color": "#aa33aa", + "outline_width": "3", + } + ) + + renderer.addCategory(QgsRendererCategory("Dam", sym1, "Dam")) + renderer.addCategory(QgsRendererCategory("Lake", sym2, "Lake")) return renderer # add secondary renderer, for rendering below class Gen2b(QgsFeatureRendererGenerator): def id(self): - return 'Gen2b' + return "Gen2b" def level(self): return -3 def createRenderer(self): renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('Value < 12') + renderer.setClassAttribute("Value < 12") sym1 = QgsFillSymbol.createSimple( - {'color': '#ffaaff', 'outline_color': '#aa1111', 'outline_width': '5'}) + { + "color": "#ffaaff", + "outline_color": "#aa1111", + "outline_width": "5", + } + ) sym2 = QgsFillSymbol.createSimple( - {'color': '#ffaaff', 'outline_color': '#1111dd', 'outline_width': '5'}) - - renderer.addCategory(QgsRendererCategory('1', sym1, '1')) - renderer.addCategory(QgsRendererCategory('0', sym2, '0')) + { + "color": "#ffaaff", + "outline_color": "#1111dd", + "outline_width": "5", + } + ) + + renderer.addCategory(QgsRendererCategory("1", sym1, "1")) + renderer.addCategory(QgsRendererCategory("0", sym2, "0")) return renderer poly_layer.addFeatureRendererGenerator(Gen1()) @@ -576,15 +700,17 @@ def createRenderer(self): mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) - mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) - mapsettings.setExtent(QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5)) + mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) + mapsettings.setExtent( + QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5) + ) mapsettings.setLayers([poly_layer]) self.assertTrue( self.render_map_settings_check( - 'multiple_renderers_both_above_below', - 'multiple_renderers_both_above_below', - mapsettings + "multiple_renderers_both_above_below", + "multiple_renderers_both_above_below", + mapsettings, ) ) @@ -594,9 +720,9 @@ def createRenderer(self): self.assertTrue( self.render_map_settings_check( - 'multiple_renderers_both_above_below', - 'multiple_renderers_both_above_below', - mapsettings + "multiple_renderers_both_above_below", + "multiple_renderers_both_above_below", + mapsettings, ) ) @@ -605,11 +731,13 @@ def testRenderMultipleRenderersSelection(self): Test that selection colors only apply to main renderer :return: """ - poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'polys.shp')) + poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "polys.shp")) self.assertTrue(poly_layer.isValid()) poly_layer.selectAll() - sym1 = QgsFillSymbol.createSimple({'color': '#ffaaff', 'outline_color': '#000000', 'outline_style': 'no'}) + sym1 = QgsFillSymbol.createSimple( + {"color": "#ffaaff", "outline_color": "#000000", "outline_style": "no"} + ) renderer = QgsSingleSymbolRenderer(sym1) poly_layer.setRenderer(renderer) @@ -617,22 +745,32 @@ def testRenderMultipleRenderersSelection(self): class Gen1(QgsFeatureRendererGenerator): def id(self): - return 'Gen1' + return "Gen1" def level(self): return -2 def createRenderer(self): renderer = QgsCategorizedSymbolRenderer() - renderer.setClassAttribute('Name') + renderer.setClassAttribute("Name") sym1 = QgsFillSymbol.createSimple( - {'color': '#ffaaff', 'outline_color': '#33aa33', 'outline_width': '3'}) + { + "color": "#ffaaff", + "outline_color": "#33aa33", + "outline_width": "3", + } + ) sym2 = QgsFillSymbol.createSimple( - {'color': '#ffaaff', 'outline_color': '#aa33aa', 'outline_width': '3'}) - - renderer.addCategory(QgsRendererCategory('Dam', sym1, 'Dam')) - renderer.addCategory(QgsRendererCategory('Lake', sym2, 'Lake')) + { + "color": "#ffaaff", + "outline_color": "#aa33aa", + "outline_width": "3", + } + ) + + renderer.addCategory(QgsRendererCategory("Dam", sym1, "Dam")) + renderer.addCategory(QgsRendererCategory("Lake", sym2, "Lake")) return renderer poly_layer.addFeatureRendererGenerator(Gen1()) @@ -640,15 +778,17 @@ def createRenderer(self): mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) - mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) - mapsettings.setExtent(QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5)) + mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) + mapsettings.setExtent( + QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5) + ) mapsettings.setLayers([poly_layer]) self.assertTrue( self.render_map_settings_check( - 'multiple_renderers_selection', - 'multiple_renderers_selection', - mapsettings + "multiple_renderers_selection", + "multiple_renderers_selection", + mapsettings, ) ) @@ -658,9 +798,9 @@ def createRenderer(self): self.assertTrue( self.render_map_settings_check( - 'multiple_renderers_selection', - 'multiple_renderers_selection', - mapsettings + "multiple_renderers_selection", + "multiple_renderers_selection", + mapsettings, ) ) @@ -668,10 +808,12 @@ def test_reference_scale(self): """ Test rendering a layer with a reference scale set """ - layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'lines.shp'), 'Lines', 'ogr') + layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "lines.shp"), "Lines", "ogr") self.assertTrue(layer.isValid()) - sym1 = QgsLineSymbol.createSimple({'line_color': '#4dbf6f', 'line_width': 4, 'line_width_unit': "points"}) + sym1 = QgsLineSymbol.createSimple( + {"line_color": "#4dbf6f", "line_width": 4, "line_width_unit": "points"} + ) renderer = QgsSingleSymbolRenderer(sym1) layer.setRenderer(renderer) @@ -686,9 +828,7 @@ def test_reference_scale(self): self.assertTrue( self.render_map_settings_check( - 'reference_scale_not_set', - 'reference_scale_not_set', - mapsettings + "reference_scale_not_set", "reference_scale_not_set", mapsettings ) ) @@ -697,9 +837,7 @@ def test_reference_scale(self): renderer.setReferenceScale(22738556 * 2) self.assertTrue( self.render_map_settings_check( - 'reference_scale_double', - 'reference_scale_double', - mapsettings + "reference_scale_double", "reference_scale_double", mapsettings ) ) @@ -708,24 +846,22 @@ def test_reference_scale(self): renderer.setReferenceScale(22738556 / 2) self.assertTrue( self.render_map_settings_check( - 'reference_scale_half', - 'reference_scale_half', - mapsettings + "reference_scale_half", "reference_scale_half", mapsettings ) ) def testRenderWithSelectedFeatureColor(self): - poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'polys.shp')) + poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "polys.shp")) self.assertTrue(poly_layer.isValid()) - sym1 = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_color': '#000000', 'outline_width': '1'}) + sym1 = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_color": "#000000", "outline_width": "1"} + ) renderer = QgsSingleSymbolRenderer(sym1) poly_layer.setRenderer(renderer) poly_layer.selectAll() - poly_layer.selectionProperties().setSelectionColor( - QColor(255, 0, 0) - ) + poly_layer.selectionProperties().setSelectionColor(QColor(255, 0, 0)) poly_layer.selectionProperties().setSelectionRenderingMode( Qgis.SelectionRenderingMode.CustomColor ) @@ -733,30 +869,34 @@ def testRenderWithSelectedFeatureColor(self): mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) - mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) - mapsettings.setExtent(QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5)) + mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) + mapsettings.setExtent( + QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5) + ) mapsettings.setLayers([poly_layer]) self.assertTrue( self.render_map_settings_check( - 'selection_color', - 'selection_color', - mapsettings + "selection_color", "selection_color", mapsettings ) ) def testRenderWithSelectedFeatureSymbol(self): - poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'polys.shp')) + poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "polys.shp")) self.assertTrue(poly_layer.isValid()) - sym1 = QgsFillSymbol.createSimple({'color': '#ff00ff', 'outline_color': '#000000', 'outline_width': '1'}) + sym1 = QgsFillSymbol.createSimple( + {"color": "#ff00ff", "outline_color": "#000000", "outline_width": "1"} + ) renderer = QgsSingleSymbolRenderer(sym1) poly_layer.setRenderer(renderer) poly_layer.selectAll() poly_layer.selectionProperties().setSelectionSymbol( - QgsFillSymbol.createSimple({'style': 'no', 'outline_color': '#6666ff', 'outline_width': '3'}) + QgsFillSymbol.createSimple( + {"style": "no", "outline_color": "#6666ff", "outline_width": "3"} + ) ) poly_layer.selectionProperties().setSelectionRenderingMode( Qgis.SelectionRenderingMode.CustomSymbol @@ -765,15 +905,15 @@ def testRenderWithSelectedFeatureSymbol(self): mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) - mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) - mapsettings.setExtent(QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5)) + mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) + mapsettings.setExtent( + QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5) + ) mapsettings.setLayers([poly_layer]) self.assertTrue( self.render_map_settings_check( - 'selection_symbol', - 'selection_symbol', - mapsettings + "selection_symbol", "selection_symbol", mapsettings ) ) @@ -783,12 +923,10 @@ def testRenderWithSelectedFeatureSymbol(self): self.assertTrue( self.render_map_settings_check( - 'selection_symbol', - 'selection_symbol', - mapsettings + "selection_symbol", "selection_symbol", mapsettings ) ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorlayersaveasdialog.py b/tests/src/python/test_qgsvectorlayersaveasdialog.py index 6f9064607e70..1e546446aa95 100644 --- a/tests/src/python/test_qgsvectorlayersaveasdialog.py +++ b/tests/src/python/test_qgsvectorlayersaveasdialog.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Benjamin Jakimow' -__date__ = '2023-04' -__copyright__ = 'Copyright 2023, The QGIS Project' + +__author__ = "Benjamin Jakimow" +__date__ = "2023-04" +__copyright__ = "Copyright 2023, The QGIS Project" import unittest from qgis.testing import start_app, TestCase @@ -21,15 +22,17 @@ class TestQgsMapCanvas(TestCase): def testOpenDialog(self): - layer = QgsVectorLayer("Polygon?crs=epsg:4326&field=text:string", "layer", "memory") + layer = QgsVectorLayer( + "Polygon?crs=epsg:4326&field=text:string", "layer", "memory" + ) with edit(layer): f = QgsFeature(layer.fields()) - f.setAttribute('text', 'foo') + f.setAttribute("text", "foo") layer.addFeature(f) f = QgsFeature(layer.fields()) - f.setAttribute('text', 'bar') + f.setAttribute("text", "bar") layer.addFeature(f) layer.select(layer.allFeatureIds()[0]) @@ -43,5 +46,5 @@ def testOpenDialog(self): self.assertTrue(d.onlySelected()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorlayerselectedfeaturesource.py b/tests/src/python/test_qgsvectorlayerselectedfeaturesource.py index 96bcaa8e0fb8..938b7a6e3a5a 100644 --- a/tests/src/python/test_qgsvectorlayerselectedfeaturesource.py +++ b/tests/src/python/test_qgsvectorlayerselectedfeaturesource.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '2018-07-05' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "2018-07-05" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, QTime @@ -34,47 +35,93 @@ class TestPyQgsVectorLayerSelectedFeatureSource(QgisTestCase, FeatureSourceTestC @classmethod def createLayer(cls): vl = QgsVectorLayer( - 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk', - 'test', 'memory') - assert (vl.isValid()) + "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&field=dt:datetime&field=date:date&field=time:time&key=pk", + "test", + "memory", + ) + assert vl.isValid() f1 = QgsFeature() - f1.setAttributes([5, -200, NULL, 'NuLl', '5', QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), QDate(2020, 5, 2), QTime(12, 13, 1)]) - f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)')) + f1.setAttributes( + [ + 5, + -200, + NULL, + "NuLl", + "5", + QDateTime(QDate(2020, 5, 4), QTime(12, 13, 14)), + QDate(2020, 5, 2), + QTime(12, 13, 1), + ] + ) + f1.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)")) f2 = QgsFeature() - f2.setAttributes([3, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL]) + f2.setAttributes([3, 300, "Pear", "PEaR", "3", NULL, NULL, NULL]) f3 = QgsFeature() - f3.setAttributes([1, 100, 'Orange', 'oranGe', '1', QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), QDate(2020, 5, 3), QTime(12, 13, 14)]) - f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)')) + f3.setAttributes( + [ + 1, + 100, + "Orange", + "oranGe", + "1", + QDateTime(QDate(2020, 5, 3), QTime(12, 13, 14)), + QDate(2020, 5, 3), + QTime(12, 13, 14), + ] + ) + f3.setGeometry(QgsGeometry.fromWkt("Point (-70.332 66.33)")) f4 = QgsFeature() - f4.setAttributes([2, 200, 'Apple', 'Apple', '2', QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), QDate(2020, 5, 4), QTime(12, 14, 14)]) - f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)')) + f4.setAttributes( + [ + 2, + 200, + "Apple", + "Apple", + "2", + QDateTime(QDate(2020, 5, 4), QTime(12, 14, 14)), + QDate(2020, 5, 4), + QTime(12, 14, 14), + ] + ) + f4.setGeometry(QgsGeometry.fromWkt("Point (-68.2 70.8)")) f5 = QgsFeature() - f5.setAttributes([4, 400, 'Honey', 'Honey', '4', QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), QDate(2021, 5, 4), QTime(13, 13, 14)]) - f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)')) + f5.setAttributes( + [ + 4, + 400, + "Honey", + "Honey", + "4", + QDateTime(QDate(2021, 5, 4), QTime(13, 13, 14)), + QDate(2021, 5, 4), + QTime(13, 13, 14), + ] + ) + f5.setGeometry(QgsGeometry.fromWkt("Point (-65.32 78.3)")) f6 = QgsFeature() - f6.setAttributes([6, -200, NULL, 'NuLl', '5', NULL, NULL, NULL]) - f6.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)')) + f6.setAttributes([6, -200, NULL, "NuLl", "5", NULL, NULL, NULL]) + f6.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)")) f7 = QgsFeature() - f7.setAttributes([7, 300, 'Pear', 'PEaR', '3', NULL, NULL, NULL]) + f7.setAttributes([7, 300, "Pear", "PEaR", "3", NULL, NULL, NULL]) f8 = QgsFeature() - f8.setAttributes([8, 100, 'Orange', 'oranGe', '1', NULL, NULL, NULL]) - f8.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)')) + f8.setAttributes([8, 100, "Orange", "oranGe", "1", NULL, NULL, NULL]) + f8.setGeometry(QgsGeometry.fromWkt("Point (-70.332 66.33)")) f9 = QgsFeature() - f9.setAttributes([9, 200, 'Apple', 'Apple', '2', NULL, NULL, NULL]) - f9.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)')) + f9.setAttributes([9, 200, "Apple", "Apple", "2", NULL, NULL, NULL]) + f9.setGeometry(QgsGeometry.fromWkt("Point (-68.2 70.8)")) f10 = QgsFeature() - f10.setAttributes([10, 400, 'Honey', 'Honey', '4', NULL, NULL, NULL]) - f10.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)')) + f10.setAttributes([10, 400, "Honey", "Honey", "4", NULL, NULL, NULL]) + f10.setGeometry(QgsGeometry.fromWkt("Point (-65.32 78.3)")) vl.dataProvider().addFeatures([f1, f2, f3, f4, f5, f6, f7, f8, f9, f10]) return vl @@ -82,29 +129,34 @@ def createLayer(cls): @classmethod def setUpClass(cls): """Run before all tests""" - super(TestPyQgsVectorLayerSelectedFeatureSource, cls).setUpClass() + super().setUpClass() # Create test layer cls.vl = cls.createLayer() - assert (cls.vl.isValid()) - - ids = [f.id() for f in cls.vl.getFeatures(QgsFeatureRequest().setFilterExpression('pk in (1,2,3,4,5)'))] + assert cls.vl.isValid() + + ids = [ + f.id() + for f in cls.vl.getFeatures( + QgsFeatureRequest().setFilterExpression("pk in (1,2,3,4,5)") + ) + ] assert len(ids) == 5 cls.vl.selectByIds(ids) cls.source = QgsVectorLayerSelectedFeatureSource(cls.vl) def testGetFeaturesSubsetAttributes2(self): - """ Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return + """Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass def testGetFeaturesNoGeometry(self): - """ Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return + """Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return its features as direct copies (due to implicit sharing of QgsFeature) """ pass -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorlayershapefile.py b/tests/src/python/test_qgsvectorlayershapefile.py index 2b7be659a3ad..b3ad841e882f 100644 --- a/tests/src/python/test_qgsvectorlayershapefile.py +++ b/tests/src/python/test_qgsvectorlayershapefile.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Tim Sutton' -__date__ = '20/08/2012' -__copyright__ = 'Copyright 2012, The QGIS Project' + +__author__ = "Tim Sutton" +__date__ = "20/08/2012" +__copyright__ = "Copyright 2012, The QGIS Project" import os @@ -31,14 +32,16 @@ class TestQgsVectorLayerShapefile(QgisTestCase, FeatureSourceTestCase): @classmethod def getSource(cls): - vl = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'provider', 'shapefile.shp'), 'test') - assert (vl.isValid()) + vl = QgsVectorLayer( + os.path.join(TEST_DATA_DIR, "provider", "shapefile.shp"), "test" + ) + assert vl.isValid() return vl @classmethod def setUpClass(cls): """Run before all tests""" - super(TestQgsVectorLayerShapefile, cls).setUpClass() + super().setUpClass() QgsGui.editorWidgetRegistry().initEditors() # Create test layer for FeatureSourceTestCase cls.source = cls.getSource() @@ -46,7 +49,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): cls.source = None - super(TestQgsVectorLayerShapefile, cls).tearDownClass() + super().tearDownClass() def treat_time_as_string(self): return True @@ -55,5 +58,5 @@ def treat_datetime_as_string(self): return True -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorlayertemporalproperties.py b/tests/src/python/test_qgsvectorlayertemporalproperties.py index 4e438da81c41..1d3575f20d8e 100644 --- a/tests/src/python/test_qgsvectorlayertemporalproperties.py +++ b/tests/src/python/test_qgsvectorlayertemporalproperties.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '73/05/2020' -__copyright__ = 'Copyright 2020, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "73/05/2020" +__copyright__ = "Copyright 2020, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, QTime, QVariant from qgis.PyQt.QtXml import QDomDocument @@ -31,20 +32,27 @@ class TestQgsVectorLayerTemporalProperties(QgisTestCase): def testReadWrite(self): props = QgsVectorLayerTemporalProperties() - props.setMode(QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeInstantFromField) - props.setFixedTemporalRange(QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)))) - props.setStartField('start') - props.setEndField('end') - props.setDurationField('duration') + props.setMode( + QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeInstantFromField + ) + props.setFixedTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + ) + ) + props.setStartField("start") + props.setEndField("end") + props.setDurationField("duration") props.setDurationUnits(QgsUnitTypes.TemporalUnit.TemporalWeeks) props.setFixedDuration(5.6) props.setAccumulateFeatures(True) - props.setStartExpression('start exp') - props.setEndExpression('end exp') + props.setStartExpression("start exp") + props.setEndExpression("end exp") # save to xml doc = QDomDocument("testdoc") - elem = doc.createElement('test') + elem = doc.createElement("test") elem = props.writeXml(elem, doc, QgsReadWriteContext()) # restore from xml @@ -69,33 +77,56 @@ def testModeFromProvider(self): self.assertFalse(props.isActive()) caps.setHasTemporalCapabilities(True) - caps.setAvailableTemporalRange(QgsDateTimeRange(QDateTime(2006, 3, 11, 0, 13, 20), QDateTime(2017, 2, 14, 1, 33, 20))) + caps.setAvailableTemporalRange( + QgsDateTimeRange( + QDateTime(2006, 3, 11, 0, 13, 20), QDateTime(2017, 2, 14, 1, 33, 20) + ) + ) props.setDefaultsFromDataProviderTemporalCapabilities(caps) self.assertTrue(props.isActive()) self.assertFalse(props.startField()) self.assertFalse(props.endField()) - self.assertEqual(props.mode(), QgsVectorLayerTemporalProperties.TemporalMode.ModeFixedTemporalRange) - self.assertEqual(props.fixedTemporalRange().begin(), QDateTime(2006, 3, 11, 0, 13, 20)) - self.assertEqual(props.fixedTemporalRange().end(), QDateTime(2017, 2, 14, 1, 33, 20)) - - caps.setStartField('start_field') - caps.setMode(QgsVectorDataProviderTemporalCapabilities.TemporalMode.ProviderStoresFeatureDateTimeInstantInField) + self.assertEqual( + props.mode(), + QgsVectorLayerTemporalProperties.TemporalMode.ModeFixedTemporalRange, + ) + self.assertEqual( + props.fixedTemporalRange().begin(), QDateTime(2006, 3, 11, 0, 13, 20) + ) + self.assertEqual( + props.fixedTemporalRange().end(), QDateTime(2017, 2, 14, 1, 33, 20) + ) + + caps.setStartField("start_field") + caps.setMode( + QgsVectorDataProviderTemporalCapabilities.TemporalMode.ProviderStoresFeatureDateTimeInstantInField + ) props.setDefaultsFromDataProviderTemporalCapabilities(caps) self.assertTrue(props.isActive()) - self.assertEqual(props.startField(), 'start_field') + self.assertEqual(props.startField(), "start_field") self.assertFalse(props.endField()) - self.assertEqual(props.mode(), QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeInstantFromField) - - caps.setEndField('end_field') - caps.setMode(QgsVectorDataProviderTemporalCapabilities.TemporalMode.ProviderStoresFeatureDateTimeStartAndEndInSeparateFields) + self.assertEqual( + props.mode(), + QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeInstantFromField, + ) + + caps.setEndField("end_field") + caps.setMode( + QgsVectorDataProviderTemporalCapabilities.TemporalMode.ProviderStoresFeatureDateTimeStartAndEndInSeparateFields + ) props.setDefaultsFromDataProviderTemporalCapabilities(caps) self.assertTrue(props.isActive()) - self.assertEqual(props.startField(), 'start_field') - self.assertEqual(props.endField(), 'end_field') - self.assertEqual(props.mode(), QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeStartAndEndFromFields) + self.assertEqual(props.startField(), "start_field") + self.assertEqual(props.endField(), "end_field") + self.assertEqual( + props.mode(), + QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeStartAndEndFromFields, + ) def testGuessDefaultsFromFields(self): - layer = QgsVectorLayer("Point?field=start_date:string&field=end_date:integer", "test", "memory") + layer = QgsVectorLayer( + "Point?field=start_date:string&field=end_date:integer", "test", "memory" + ) self.assertTrue(layer.isValid()) # no date/datetime fields, should not guess anything props = layer.temporalProperties() @@ -104,7 +135,9 @@ def testGuessDefaultsFromFields(self): self.assertFalse(props.endField()) # datetime fields, but not expected names - layer = QgsVectorLayer("Point?field=date_created:date&field=date_modified:date", "test", "memory") + layer = QgsVectorLayer( + "Point?field=date_created:date&field=date_modified:date", "test", "memory" + ) self.assertTrue(layer.isValid()) props = layer.temporalProperties() self.assertFalse(props.isActive()) @@ -112,64 +145,138 @@ def testGuessDefaultsFromFields(self): self.assertFalse(props.endField()) # sample table with likely single field - layer = QgsVectorLayer("Point?field=event_id:integer&field=event_date:date", "test", "memory") + layer = QgsVectorLayer( + "Point?field=event_id:integer&field=event_date:date", "test", "memory" + ) self.assertTrue(layer.isValid()) props = layer.temporalProperties() self.assertFalse(props.isActive()) - self.assertEqual(props.startField(), 'event_date') + self.assertEqual(props.startField(), "event_date") self.assertFalse(props.endField()) - self.assertEqual(props.mode(), QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeInstantFromField) + self.assertEqual( + props.mode(), + QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeInstantFromField, + ) # sample table with likely dual fields - layer = QgsVectorLayer("Point?field=event_id:integer&field=start_date:datetime&field=end_date:datetime", "test", "memory") + layer = QgsVectorLayer( + "Point?field=event_id:integer&field=start_date:datetime&field=end_date:datetime", + "test", + "memory", + ) self.assertTrue(layer.isValid()) props = layer.temporalProperties() self.assertFalse(props.isActive()) - self.assertEqual(props.startField(), 'start_date') - self.assertEqual(props.endField(), 'end_date') - self.assertEqual(props.mode(), QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeStartAndEndFromFields) + self.assertEqual(props.startField(), "start_date") + self.assertEqual(props.endField(), "end_date") + self.assertEqual( + props.mode(), + QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeStartAndEndFromFields, + ) def testFixedRangeMode(self): props = QgsVectorLayerTemporalProperties(enabled=True) - props.setMode(QgsVectorLayerTemporalProperties.TemporalMode.ModeFixedTemporalRange) - props.setFixedTemporalRange(QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)))) - - self.assertTrue(props.isVisibleInTemporalRange(QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10))))) - self.assertTrue(props.isVisibleInTemporalRange(QgsDateTimeRange(QDateTime(QDate(2019, 1, 4), QTime(11, 12, 13)), QDateTime(QDate(2019, 5, 6), QTime(8, 9, 10))))) - self.assertTrue(props.isVisibleInTemporalRange(QgsDateTimeRange(QDateTime(QDate(2020, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2019, 9, 6), QTime(8, 9, 10))))) - self.assertFalse(props.isVisibleInTemporalRange(QgsDateTimeRange(QDateTime(QDate(2120, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2121, 9, 6), QTime(8, 9, 10))))) - self.assertFalse(props.isVisibleInTemporalRange(QgsDateTimeRange(QDateTime(QDate(1920, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(1921, 9, 6), QTime(8, 9, 10))))) - - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=start_field:datetime", "test", "memory") + props.setMode( + QgsVectorLayerTemporalProperties.TemporalMode.ModeFixedTemporalRange + ) + props.setFixedTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + ) + ) + + self.assertTrue( + props.isVisibleInTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + ) + ) + ) + self.assertTrue( + props.isVisibleInTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2019, 1, 4), QTime(11, 12, 13)), + QDateTime(QDate(2019, 5, 6), QTime(8, 9, 10)), + ) + ) + ) + self.assertTrue( + props.isVisibleInTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2020, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2019, 9, 6), QTime(8, 9, 10)), + ) + ) + ) + self.assertFalse( + props.isVisibleInTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(2120, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2121, 9, 6), QTime(8, 9, 10)), + ) + ) + ) + self.assertFalse( + props.isVisibleInTemporalRange( + QgsDateTimeRange( + QDateTime(QDate(1920, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(1921, 9, 6), QTime(8, 9, 10)), + ) + ) + ) + + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer&field=start_field:datetime", + "test", + "memory", + ) context = QgsVectorLayerTemporalContext() context.setLayer(layer) - range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10))) + range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + ) # ALWAYS must be empty for ModeFixedTemporalRange self.assertFalse(props.createFilterString(context, range)) def testSingleFieldMode(self): # testing both a layer/context with Datetime field as one with Date (only) field, as the last one should be added a cast to datetime - datetime_layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=start_field:datetime", "test", "memory") + datetime_layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer&field=start_field:datetime", + "test", + "memory", + ) self.assertTrue(datetime_layer.isValid()) self.assertEqual(datetime_layer.fields()[2].type(), QVariant.DateTime) datetime_context = QgsVectorLayerTemporalContext() datetime_context.setLayer(datetime_layer) - date_layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=start_field:date", "test", "memory") + date_layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer&field=start_field:date", + "test", + "memory", + ) self.assertTrue(date_layer.isValid()) self.assertEqual(date_layer.fields()[2].type(), QVariant.Date) date_context = QgsVectorLayerTemporalContext() date_context.setLayer(date_layer) # default QgsDateTimeRange includes beginning AND end - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10))) + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + ) props = QgsVectorLayerTemporalProperties(enabled=False) - props.setMode(QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeInstantFromField) - props.setStartField('start_field') + props.setMode( + QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeInstantFromField + ) + props.setStartField("start_field") # createFilterString should return QString() (== '' in Python world) in case the QgsVectorLayerTemporalProperties is not yet active - self.assertEqual('', props.createFilterString(datetime_context, filter_range)) + self.assertEqual("", props.createFilterString(datetime_context, filter_range)) props.setIsActive(True) @@ -181,10 +288,21 @@ def testSingleFieldMode(self): # | . . (false) # # => feature time <= end of range AND feature time >= start of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" >= make_datetime(2019,3,4,11,12,13) AND "start_field" <= make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) >= make_datetime(2019,3,4,11,12,13) AND to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL') - - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False, includeEnd=False) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" >= make_datetime(2019,3,4,11,12,13) AND "start_field" <= make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) >= make_datetime(2019,3,4,11,12,13) AND to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL', + ) + + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + includeEnd=False, + ) # map range (-------------------------) # feature ranges . . | (false) # . | (false) @@ -193,10 +311,20 @@ def testSingleFieldMode(self): # | . . (false) # # => feature time < end of range AND feature time > start of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" > make_datetime(2019,3,4,11,12,13) AND "start_field" < make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) > make_datetime(2019,3,4,11,12,13) AND to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL') - - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" > make_datetime(2019,3,4,11,12,13) AND "start_field" < make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) > make_datetime(2019,3,4,11,12,13) AND to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL', + ) + + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + ) # map range (-------------------------] # feature ranges . . | (false) # . | (true) @@ -205,10 +333,20 @@ def testSingleFieldMode(self): # | . . (false) # # => feature time <= end of range AND feature time > start of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" > make_datetime(2019,3,4,11,12,13) AND "start_field" <= make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) > make_datetime(2019,3,4,11,12,13) AND to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL') - - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeEnd=False) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" > make_datetime(2019,3,4,11,12,13) AND "start_field" <= make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) > make_datetime(2019,3,4,11,12,13) AND to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL', + ) + + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeEnd=False, + ) # map range [-------------------------) # feature ranges . . | (false) # . | (false) @@ -217,13 +355,22 @@ def testSingleFieldMode(self): # | . . (false) # # => feature time < end of range AND feature time >= start of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" >= make_datetime(2019,3,4,11,12,13) AND "start_field" < make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) >= make_datetime(2019,3,4,11,12,13) AND to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" >= make_datetime(2019,3,4,11,12,13) AND "start_field" < make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) >= make_datetime(2019,3,4,11,12,13) AND to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL', + ) # with fixed duration props.setFixedDuration(3) props.setDurationUnits(QgsUnitTypes.TemporalUnit.TemporalDays) - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10))) + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + ) # map range [-------------------------] # feature ranges . . [-------) (false) # . [-------) (true) @@ -236,10 +383,21 @@ def testSingleFieldMode(self): # # => start of feature <= end of range AND start of feature + duration > start of range # OR start of feature <= end of range AND start of feature > start of range - duration - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" > make_datetime(2019,3,1,11,12,13) AND "start_field" <= make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) > make_datetime(2019,3,1,11,12,13) AND to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL') - - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False, includeEnd=False) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" > make_datetime(2019,3,1,11,12,13) AND "start_field" <= make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) > make_datetime(2019,3,1,11,12,13) AND to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL', + ) + + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + includeEnd=False, + ) # map range (-------------------------) # feature ranges . . [-------) (false) # . [-------) (false) @@ -252,10 +410,20 @@ def testSingleFieldMode(self): # # => start of feature < end of range AND start of feature + duration > start of range # OR start of feature < end of range AND start of feature > start of range - duration - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" > make_datetime(2019,3,1,11,12,13) AND "start_field" < make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) > make_datetime(2019,3,1,11,12,13) AND to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL') - - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" > make_datetime(2019,3,1,11,12,13) AND "start_field" < make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) > make_datetime(2019,3,1,11,12,13) AND to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL', + ) + + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + ) # map range (-------------------------] # feature ranges . . [-------) (false) # . [-------) (true) @@ -268,12 +436,22 @@ def testSingleFieldMode(self): # # => start of feature <= end of range AND start of feature + duration > start of range # OR start of feature <= end of range AND start of feature > start of range - duration - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" > make_datetime(2019,3,1,11,12,13) AND "start_field" <= make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) > make_datetime(2019,3,1,11,12,13) AND to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" > make_datetime(2019,3,1,11,12,13) AND "start_field" <= make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) > make_datetime(2019,3,1,11,12,13) AND to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL', + ) # THIS is the QGIS default: using a range with includeBeginning=true and includeEnd=false # and the temporal properties exactly the same - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeEnd=False) + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeEnd=False, + ) # map range [-------------------------) # feature ranges . . [-------) (false) # . [-------) (false) @@ -286,8 +464,14 @@ def testSingleFieldMode(self): # # => start of feature < end of range AND start of feature + duration > start of range # OR start of feature < end of range AND start of feature > start of range - duration - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" > make_datetime(2019,3,1,11,12,13) AND "start_field" < make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) > make_datetime(2019,3,1,11,12,13) AND to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" > make_datetime(2019,3,1,11,12,13) AND "start_field" < make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) > make_datetime(2019,3,1,11,12,13) AND to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL', + ) # since 3.22 there is also the option to include the end of the feature event props.setLimitMode(Qgis.VectorTemporalLimitMode.IncludeBeginIncludeEnd) @@ -302,20 +486,40 @@ def testSingleFieldMode(self): # [-------] . . (false) # => start of feature < end of range AND start of feature + duration >= start of range # OR start of feature < end of range AND start of feature >= start of range - duration - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" >= make_datetime(2019,3,1,11,12,13) AND "start_field" < make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) >= make_datetime(2019,3,1,11,12,13) AND to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL') - props.setLimitMode(Qgis.VectorTemporalLimitMode.IncludeBeginExcludeEnd) # back to default + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" >= make_datetime(2019,3,1,11,12,13) AND "start_field" < make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) >= make_datetime(2019,3,1,11,12,13) AND to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL', + ) + props.setLimitMode( + Qgis.VectorTemporalLimitMode.IncludeBeginExcludeEnd + ) # back to default # different unit props.setDurationUnits(QgsUnitTypes.TemporalUnit.TemporalMinutes) - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10))) - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" > make_datetime(2019,3,4,11,9,13) AND "start_field" <= make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) > make_datetime(2019,3,4,11,9,13) AND to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL') + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + ) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" > make_datetime(2019,3,4,11,9,13) AND "start_field" <= make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) > make_datetime(2019,3,4,11,9,13) AND to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL', + ) # accumulate mode props.setFixedDuration(0) props.setAccumulateFeatures(True) - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10))) + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + ) # with accumulate mode effectively map range starts at -eternity, regardless of what it actually is # map range [-------------------------] # feature ranges . . | (false) @@ -325,10 +529,21 @@ def testSingleFieldMode(self): # | . . (true) # # => feature time <= end of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" <= make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL') - - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False, includeEnd=False) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" <= make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL', + ) + + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + includeEnd=False, + ) # with accumulate mode effectively map range starts at -eternity, regardless of what it actually is # map range (-------------------------) # feature ranges . . | (false) @@ -338,10 +553,20 @@ def testSingleFieldMode(self): # | . . (true) # # => feature time < end of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" < make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL') - - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" < make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL', + ) + + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + ) # with accumulate mode effectively map range starts at -eternity, regardless of what it actually is # map range (-------------------------] # feature ranges . . | (false) @@ -351,10 +576,20 @@ def testSingleFieldMode(self): # | . . (true) # # => feature time <= end of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" <= make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL') - - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeEnd=False) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" <= make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL', + ) + + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeEnd=False, + ) # with accumulate mode effectively map range starts at -eternity, regardless of what it actually is # map range [-------------------------) # feature ranges . . | (false) @@ -364,13 +599,22 @@ def testSingleFieldMode(self): # | . . (true) # # => feature time < end of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" < make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" < make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL', + ) # accumulate mode, with duration props.setFixedDuration(3) props.setDurationUnits(QgsUnitTypes.TemporalUnit.TemporalDays) - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10))) + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + ) # with accumulate mode effectively map range starts at -eternity, regardless of what it actually is # map range [-------------------------] # feature ranges . . [-------) (false) @@ -383,10 +627,21 @@ def testSingleFieldMode(self): # [-------) . . (true) # # => start of feature <= end of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" <= make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL') - - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False, includeEnd=False) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" <= make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL', + ) + + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + includeEnd=False, + ) # with accumulate mode effectively map range starts at -eternity, regardless of what it actually is # map range (-------------------------) # feature ranges . . [-------) (false) @@ -399,10 +654,20 @@ def testSingleFieldMode(self): # [-------) . . (true) # # => start of feature < end of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" < make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL') - - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" < make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL', + ) + + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + ) # with accumulate mode effectively map range starts at -eternity, regardless of what it actually is # map range (-------------------------] # feature ranges . . [-------) (false) @@ -415,10 +680,20 @@ def testSingleFieldMode(self): # [-------) . . (true) # # => start of feature <= end of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" <= make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL') - - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeEnd=False) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" <= make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL', + ) + + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeEnd=False, + ) # with accumulate mode effectively map range starts at -eternity, regardless of what it actually is # map range [-------------------------) # feature ranges . . [-------) (false) @@ -431,19 +706,33 @@ def testSingleFieldMode(self): # [-------) . . (true) # # => start of feature < end of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" < make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" < make_datetime(2020,5,6,8,9,10)) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10)) OR to_datetime( "start_field" ) IS NULL', + ) def testDualFieldMode(self): # testing both a layer/context with Datetime fields as one with Date (only) fields, as the last one should be added a cast to datetime - datetime_layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=start_field:datetime&field=end_field:datetime", "test", "memory") + datetime_layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer&field=start_field:datetime&field=end_field:datetime", + "test", + "memory", + ) self.assertTrue(datetime_layer.isValid()) self.assertEqual(datetime_layer.fields()[2].type(), QVariant.DateTime) self.assertEqual(datetime_layer.fields()[3].type(), QVariant.DateTime) datetime_context = QgsVectorLayerTemporalContext() datetime_context.setLayer(datetime_layer) - date_layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=start_field:date&field=end_field:date", "test", "memory") + date_layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer&field=start_field:date&field=end_field:date", + "test", + "memory", + ) self.assertTrue(date_layer.isValid()) self.assertEqual(date_layer.fields()[2].type(), QVariant.Date) self.assertEqual(date_layer.fields()[3].type(), QVariant.Date) @@ -451,14 +740,19 @@ def testDualFieldMode(self): date_context.setLayer(date_layer) # default QgsDateTimeRange includes beginning AND end - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10))) + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + ) props = QgsVectorLayerTemporalProperties(enabled=False) - props.setMode(QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeStartAndEndFromFields) - props.setStartField('start_field') - props.setEndField('end_field') + props.setMode( + QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeStartAndEndFromFields + ) + props.setStartField("start_field") + props.setEndField("end_field") # createFilterString should return QString() (== '' in Python world) in case the QgsVectorLayerTemporalProperties is not yet active - self.assertEqual('', props.createFilterString(datetime_context, filter_range)) + self.assertEqual("", props.createFilterString(datetime_context, filter_range)) props.setIsActive(True) @@ -473,8 +767,14 @@ def testDualFieldMode(self): # [-------) . . (false) # # => start of feature <= end of range AND end of feature > start of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND ("end_field" > make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL)') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND (to_datetime( "end_field" ) > make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL)') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND ("end_field" > make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL)', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND (to_datetime( "end_field" ) > make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL)', + ) # map range (-------------------------) # feature ranges . . [-------) (false) @@ -487,9 +787,20 @@ def testDualFieldMode(self): # [-------) . . (false) # # => start of feature < end of range AND end of feature > start of range - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False, includeEnd=False) - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" < make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND ("end_field" > make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL)') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND (to_datetime( "end_field" ) > make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL)') + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + includeEnd=False, + ) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" < make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND ("end_field" > make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL)', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND (to_datetime( "end_field" ) > make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL)', + ) # map range (-------------------------] # feature ranges . . [-------) (false) @@ -502,9 +813,19 @@ def testDualFieldMode(self): # [-------) . . (false) # # => start of feature <= end of range AND end of feature > start of range - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False) - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND ("end_field" > make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL)') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND (to_datetime( "end_field" ) > make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL)') + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + ) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND ("end_field" > make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL)', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND (to_datetime( "end_field" ) > make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL)', + ) # THIS is the QGIS default: using a range with includeBeginning=true and includeEnd=false # map range [-------------------------) @@ -518,9 +839,19 @@ def testDualFieldMode(self): # [-------) . . (false) # # => start of feature < end of range AND end of feature > start of range - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeEnd=False) - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" < make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND ("end_field" > make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL)') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND (to_datetime( "end_field" ) > make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL)') + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeEnd=False, + ) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" < make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND ("end_field" > make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL)', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND (to_datetime( "end_field" ) > make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL)', + ) # since 3.22 there is also the option to include the end of the feature event props.setLimitMode(Qgis.VectorTemporalLimitMode.IncludeBeginIncludeEnd) # map range [-------------------------) @@ -534,14 +865,25 @@ def testDualFieldMode(self): # [-------] . . (false) # # => start of feature < end of range AND end of feature >= start of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '("start_field" < make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND ("end_field" >= make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL)') - self.assertEqual(props.createFilterString(date_context, filter_range), '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND (to_datetime( "end_field" ) >= make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL)') - props.setLimitMode(Qgis.VectorTemporalLimitMode.IncludeBeginExcludeEnd) # back to default + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" < make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND ("end_field" >= make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL)', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND (to_datetime( "end_field" ) >= make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL)', + ) + props.setLimitMode( + Qgis.VectorTemporalLimitMode.IncludeBeginExcludeEnd + ) # back to default # features go to +eternity - props.setEndField('') + props.setEndField("") # includes beginning AND end - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10))) + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + ) # map range [-------------------------] # feature ranges . . [--------> (false) # . [----------> (true) @@ -550,10 +892,21 @@ def testDualFieldMode(self): # [-------------.-------------------------.----------> (true) # # => start of feature <= end of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '"start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), 'to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL') - - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False, includeEnd=False) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '"start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + 'to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL', + ) + + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + includeEnd=False, + ) # map range (-------------------------) # feature ranges . . [--------> (false) # . [----------> (false) @@ -562,10 +915,20 @@ def testDualFieldMode(self): # [-------------.-------------------------.----------> (true) # # => start of feature < end of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '"start_field" < make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), 'to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL') - - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '"start_field" < make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + 'to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL', + ) + + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + ) # map range (-------------------------] # feature ranges . . [--------> (false) # . [----------> (true) @@ -574,11 +937,21 @@ def testDualFieldMode(self): # [-------------.-------------------------.----------> (true) # # => start of feature <= end of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '"start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), 'to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '"start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + 'to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL', + ) # THIS is the QGIS default: using a range with includeBeginning=true and includeEnd=false - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeEnd=False) + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeEnd=False, + ) # map range [-------------------------) # feature ranges . . [--------> (false) # . [----------> (false) @@ -587,14 +960,23 @@ def testDualFieldMode(self): # [-------------.-------------------------.----------> (true) # # => start of feature < end of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '"start_field" < make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), 'to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '"start_field" < make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + 'to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL', + ) # features start at -eternity - props.setStartField('') - props.setEndField('end_field') + props.setStartField("") + props.setEndField("end_field") # includes beginning AND end - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10))) + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + ) # map range [-------------------------] # feature ranges --------.-------------------------.---------) (true) # --------.-------------------------) (true) @@ -603,10 +985,21 @@ def testDualFieldMode(self): # -----) . (false) # # => end of feature > start of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '"end_field" > make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), 'to_datetime( "end_field" ) > make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL') - - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False, includeEnd=False) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '"end_field" > make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + 'to_datetime( "end_field" ) > make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL', + ) + + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + includeEnd=False, + ) # map range (-------------------------) # feature ranges --------.-------------------------.---------) (true) # --------.-------------------------) (true) @@ -615,10 +1008,20 @@ def testDualFieldMode(self): # -----) . (false) # # => end of feature > start of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '"end_field" > make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), 'to_datetime( "end_field" ) > make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL') - - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '"end_field" > make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + 'to_datetime( "end_field" ) > make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL', + ) + + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + ) # map range (-------------------------] # feature ranges --------.-------------------------.---------) (true) # --------.-------------------------) (true) @@ -627,11 +1030,21 @@ def testDualFieldMode(self): # -----) . (false) # # => end of feature > start of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '"end_field" > make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), 'to_datetime( "end_field" ) > make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '"end_field" > make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + 'to_datetime( "end_field" ) > make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL', + ) # THIS is the QGIS default: using a range with includeBeginning=true and includeEnd=false - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeEnd=False) + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeEnd=False, + ) # map range [-------------------------) # feature ranges --------.-------------------------.---------) (true) # --------.-------------------------) (true) @@ -640,8 +1053,14 @@ def testDualFieldMode(self): # -----) . (false) # # => end of feature > start of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '"end_field" > make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), 'to_datetime( "end_field" ) > make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '"end_field" > make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + 'to_datetime( "end_field" ) > make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL', + ) # since 3.22 there is also the option to include the end of the feature event # => end of feature >= start of range props.setLimitMode(Qgis.VectorTemporalLimitMode.IncludeBeginIncludeEnd) @@ -653,15 +1072,25 @@ def testDualFieldMode(self): # -----] . (false) # # => end of feature >= start of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), '"end_field" >= make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL') - self.assertEqual(props.createFilterString(date_context, filter_range), 'to_datetime( "end_field" ) >= make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL') - props.setLimitMode(Qgis.VectorTemporalLimitMode.IncludeBeginExcludeEnd) # back to default + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '"end_field" >= make_datetime(2019,3,4,11,12,13) OR "end_field" IS NULL', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + 'to_datetime( "end_field" ) >= make_datetime(2019,3,4,11,12,13) OR to_datetime( "end_field" ) IS NULL', + ) + props.setLimitMode( + Qgis.VectorTemporalLimitMode.IncludeBeginExcludeEnd + ) # back to default def testStartAndDurationMode(self): # testing both a layer/context with Datetime field as one with Date (only) field, as the last one should be added a cast to datetime datetime_layer = QgsVectorLayer( "Point?field=fldtxt:string&field=fldint:integer&field=start_field:datetime&field=duration:double", - "test", "memory") + "test", + "memory", + ) self.assertTrue(datetime_layer.isValid()) self.assertEqual(datetime_layer.fields()[2].type(), QVariant.DateTime) self.assertEqual(datetime_layer.fields()[3].type(), QVariant.Double) @@ -670,22 +1099,29 @@ def testStartAndDurationMode(self): date_layer = QgsVectorLayer( "Point?field=fldtxt:string&field=fldint:integer&field=start_field:date&field=duration:double", - "test", "memory") + "test", + "memory", + ) self.assertTrue(date_layer.isValid()) self.assertEqual(date_layer.fields()[2].type(), QVariant.Date) self.assertEqual(date_layer.fields()[3].type(), QVariant.Double) date_context = QgsVectorLayerTemporalContext() date_context.setLayer(date_layer) - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10))) + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + ) props = QgsVectorLayerTemporalProperties(enabled=False) - props.setMode(QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeStartAndDurationFromFields) - props.setStartField('start_field') - props.setDurationField('duration') + props.setMode( + QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeStartAndDurationFromFields + ) + props.setStartField("start_field") + props.setDurationField("duration") props.setDurationUnits(QgsUnitTypes.TemporalUnit.TemporalMilliseconds) # createFilterString should return QString() (== '' in Python world) in case the QgsVectorLayerTemporalProperties is not yet active - self.assertEqual('', props.createFilterString(datetime_context, filter_range)) + self.assertEqual("", props.createFilterString(datetime_context, filter_range)) props.setIsActive(True) # map range [-------------------------] @@ -699,13 +1135,21 @@ def testStartAndDurationMode(self): # [-------) . . (false) # # => start of feature <= end of range AND start + duration > start of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), - '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,0,0,0,0,"duration"/1000) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') - self.assertEqual(props.createFilterString(date_context, filter_range), - '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,0,0,0,0,"duration"/1000) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') - - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), - QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False, includeEnd=False) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,0,0,0,0,"duration"/1000) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,0,0,0,0,"duration"/1000) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) + + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + includeEnd=False, + ) # map range (-------------------------) # feature ranges . . [-------) (false) # . [-------) (false) @@ -717,13 +1161,20 @@ def testStartAndDurationMode(self): # [-------) . . (false) # # => start of feature < end of range AND start + duration > start of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), - '("start_field" < make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,0,0,0,0,"duration"/1000) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') - self.assertEqual(props.createFilterString(date_context, filter_range), - '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,0,0,0,0,"duration"/1000) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') - - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), - QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False) + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" < make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,0,0,0,0,"duration"/1000) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,0,0,0,0,"duration"/1000) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) + + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + ) # map range (-------------------------] # feature ranges . . [-------) (false) # . [-------) (true) @@ -735,14 +1186,21 @@ def testStartAndDurationMode(self): # [-------) . . (false) # # => start of feature <= end of range AND start + duration > start of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), - '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,0,0,0,0,"duration"/1000) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') - self.assertEqual(props.createFilterString(date_context, filter_range), - '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,0,0,0,0,"duration"/1000) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,0,0,0,0,"duration"/1000) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,0,0,0,0,"duration"/1000) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) # THIS is the QGIS default: using a range with includeBeginning=true and includeEnd=false - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), - QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeEnd=False) + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeEnd=False, + ) # map range [-------------------------) # feature ranges . . [-------) (false) # . [-------) (true) @@ -754,10 +1212,14 @@ def testStartAndDurationMode(self): # [-------) . . (false) # # => start of feature < end of range AND start + duration > start of range - self.assertEqual(props.createFilterString(datetime_context, filter_range), - '("start_field" < make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,0,0,0,0,"duration"/1000) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') - self.assertEqual(props.createFilterString(date_context, filter_range), - '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,0,0,0,0,"duration"/1000) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" < make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,0,0,0,0,"duration"/1000) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,0,0,0,0,"duration"/1000) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) # map range [-------------------------) # feature ranges . . [-------] (false) # . [-------] (false) @@ -770,84 +1232,141 @@ def testStartAndDurationMode(self): # # => start of feature < end of range AND start + duration >= start of range props.setLimitMode(Qgis.VectorTemporalLimitMode.IncludeBeginIncludeEnd) - self.assertEqual(props.createFilterString(datetime_context, filter_range), - '("start_field" < make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,0,0,0,0,"duration"/1000) >= make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') - self.assertEqual(props.createFilterString(date_context, filter_range), - '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,0,0,0,0,"duration"/1000) >= make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') - props.setLimitMode(Qgis.VectorTemporalLimitMode.IncludeBeginExcludeEnd) # back to default + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" < make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,0,0,0,0,"duration"/1000) >= make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) < make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,0,0,0,0,"duration"/1000) >= make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) + props.setLimitMode( + Qgis.VectorTemporalLimitMode.IncludeBeginExcludeEnd + ) # back to default # different units - filter_range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), - QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10))) + filter_range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + ) props.setDurationUnits(QgsUnitTypes.TemporalUnit.TemporalSeconds) - self.assertEqual(props.createFilterString(datetime_context, filter_range), - '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,0,0,0,0,"duration") > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') - self.assertEqual(props.createFilterString(date_context, filter_range), - '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,0,0,0,0,"duration") > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,0,0,0,0,"duration") > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,0,0,0,0,"duration") > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) props.setDurationUnits(QgsUnitTypes.TemporalUnit.TemporalMinutes) - self.assertEqual(props.createFilterString(datetime_context, filter_range), - '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,0,0,0,"duration",0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') - self.assertEqual(props.createFilterString(date_context, filter_range), - '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,0,0,0,"duration",0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,0,0,0,"duration",0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,0,0,0,"duration",0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) props.setDurationUnits(QgsUnitTypes.TemporalUnit.TemporalHours) - self.assertEqual(props.createFilterString(datetime_context, filter_range), - '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,0,0,"duration",0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') - self.assertEqual(props.createFilterString(date_context, filter_range), - '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,0,0,"duration",0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,0,0,"duration",0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,0,0,"duration",0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) props.setDurationUnits(QgsUnitTypes.TemporalUnit.TemporalDays) - self.assertEqual(props.createFilterString(datetime_context, filter_range), - '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,0,"duration",0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') - self.assertEqual(props.createFilterString(date_context, filter_range), - '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,0,"duration",0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,0,"duration",0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,0,"duration",0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) props.setDurationUnits(QgsUnitTypes.TemporalUnit.TemporalWeeks) - self.assertEqual(props.createFilterString(datetime_context, filter_range), - '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,"duration",0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') - self.assertEqual(props.createFilterString(date_context, filter_range), - '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,"duration",0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,0,"duration",0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,0,"duration",0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) props.setDurationUnits(QgsUnitTypes.TemporalUnit.TemporalMonths) - self.assertEqual(props.createFilterString(datetime_context, filter_range), - '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,"duration",0,0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') - self.assertEqual(props.createFilterString(date_context, filter_range), - '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,"duration",0,0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(0,"duration",0,0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(0,"duration",0,0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) props.setDurationUnits(QgsUnitTypes.TemporalUnit.TemporalYears) - self.assertEqual(props.createFilterString(datetime_context, filter_range), - '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval("duration",0,0,0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') - self.assertEqual(props.createFilterString(date_context, filter_range), - '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval("duration",0,0,0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval("duration",0,0,0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval("duration",0,0,0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) props.setDurationUnits(QgsUnitTypes.TemporalUnit.TemporalDecades) - self.assertEqual(props.createFilterString(datetime_context, filter_range), - '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(10 * "duration",0,0,0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') - self.assertEqual(props.createFilterString(date_context, filter_range), - '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(10 * "duration",0,0,0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(10 * "duration",0,0,0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(10 * "duration",0,0,0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) props.setDurationUnits(QgsUnitTypes.TemporalUnit.TemporalCenturies) - self.assertEqual(props.createFilterString(datetime_context, filter_range), - '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(100 * "duration",0,0,0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') - self.assertEqual(props.createFilterString(date_context, filter_range), - '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(100 * "duration",0,0,0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)') + self.assertEqual( + props.createFilterString(datetime_context, filter_range), + '("start_field" <= make_datetime(2020,5,6,8,9,10) OR "start_field" IS NULL) AND (("start_field" + make_interval(100 * "duration",0,0,0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) + self.assertEqual( + props.createFilterString(date_context, filter_range), + '(to_datetime( "start_field" ) <= make_datetime(2020,5,6,8,9,10) OR to_datetime( "start_field" ) IS NULL) AND ((to_datetime( "start_field" ) + make_interval(100 * "duration",0,0,0,0,0,0) > make_datetime(2019,3,4,11,12,13)) OR "duration" IS NULL)', + ) def testExpressionMode(self): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=start_field:datetime&field=end_field:datetime", "test", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer&field=start_field:datetime&field=end_field:datetime", + "test", + "memory", + ) self.assertTrue(layer.isValid()) self.assertEqual(layer.fields()[2].type(), QVariant.DateTime) self.assertEqual(layer.fields()[3].type(), QVariant.DateTime) context = QgsVectorLayerTemporalContext() context.setLayer(layer) - range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10))) + range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + ) props = QgsVectorLayerTemporalProperties(enabled=False) - props.setMode(QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeStartAndEndFromExpressions) - props.setStartExpression('to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')"') - props.setEndExpression('to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')"') + props.setMode( + QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeStartAndEndFromExpressions + ) + props.setStartExpression( + 'to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')"' + ) + props.setEndExpression( + 'to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')"' + ) self.assertFalse(props.createFilterString(context, range)) props.setIsActive(True) @@ -862,9 +1381,17 @@ def testExpressionMode(self): # [-------) . . (false) # # => start expression <= end of range AND end expression > start of range - self.assertEqual(props.createFilterString(context, range), '((to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')") <= make_datetime(2020,5,6,8,9,10)) AND ((to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") > make_datetime(2019,3,4,11,12,13))') - - range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False, includeEnd=False) + self.assertEqual( + props.createFilterString(context, range), + '((to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')") <= make_datetime(2020,5,6,8,9,10)) AND ((to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") > make_datetime(2019,3,4,11,12,13))', + ) + + range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + includeEnd=False, + ) # map range (-------------------------) # feature ranges . . [-------) (false) # . [-------) (false) @@ -876,9 +1403,16 @@ def testExpressionMode(self): # [-------) . . (false) # # => start expression < end of range AND end expression > start of range - self.assertEqual(props.createFilterString(context, range), '((to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')") < make_datetime(2020,5,6,8,9,10)) AND ((to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") > make_datetime(2019,3,4,11,12,13))') - - range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False) + self.assertEqual( + props.createFilterString(context, range), + '((to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')") < make_datetime(2020,5,6,8,9,10)) AND ((to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") > make_datetime(2019,3,4,11,12,13))', + ) + + range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + ) # map range (-------------------------] # feature ranges . . [-------) (false) # . [-------) (true) @@ -890,10 +1424,17 @@ def testExpressionMode(self): # [-------) . . (false) # # => start expression <= end of range AND end expression > start of range - self.assertEqual(props.createFilterString(context, range), '((to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')") <= make_datetime(2020,5,6,8,9,10)) AND ((to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") > make_datetime(2019,3,4,11,12,13))') + self.assertEqual( + props.createFilterString(context, range), + '((to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')") <= make_datetime(2020,5,6,8,9,10)) AND ((to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") > make_datetime(2019,3,4,11,12,13))', + ) # THIS is the QGIS default: using a range with includeBeginning=true and includeEnd=false - range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeEnd=False) + range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeEnd=False, + ) # map range [-------------------------) # feature ranges . . [-------) (false) # . [-------) (false) @@ -905,7 +1446,10 @@ def testExpressionMode(self): # [-------) . . (false) # # => start expression < end of range AND end expression > start of range - self.assertEqual(props.createFilterString(context, range), '((to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')") < make_datetime(2020,5,6,8,9,10)) AND ((to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") > make_datetime(2019,3,4,11,12,13))') + self.assertEqual( + props.createFilterString(context, range), + '((to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')") < make_datetime(2020,5,6,8,9,10)) AND ((to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") > make_datetime(2019,3,4,11,12,13))', + ) # map range [-------------------------) # feature ranges . . [-------] (false) # . [-------] (false) @@ -918,13 +1462,21 @@ def testExpressionMode(self): # # => start expression < end of range AND end expression >= start of range props.setLimitMode(Qgis.VectorTemporalLimitMode.IncludeBeginIncludeEnd) - self.assertEqual(props.createFilterString(context, range), '((to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')") < make_datetime(2020,5,6,8,9,10)) AND ((to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") >= make_datetime(2019,3,4,11,12,13))') - props.setLimitMode(Qgis.VectorTemporalLimitMode.IncludeBeginExcludeEnd) # back to default + self.assertEqual( + props.createFilterString(context, range), + '((to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')") < make_datetime(2020,5,6,8,9,10)) AND ((to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") >= make_datetime(2019,3,4,11,12,13))', + ) + props.setLimitMode( + Qgis.VectorTemporalLimitMode.IncludeBeginExcludeEnd + ) # back to default # features go to +eternity - props.setEndExpression('') + props.setEndExpression("") # includes beginning AND end - range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10))) + range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + ) # map range [-------------------------] # feature ranges . . [--------> (false) # . [----------> (true) @@ -933,9 +1485,17 @@ def testExpressionMode(self): # [-------------.-------------------------.----------> (true) # # => start expression <= end of range - self.assertEqual(props.createFilterString(context, range), '(to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')") <= make_datetime(2020,5,6,8,9,10)') - - range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False, includeEnd=False) + self.assertEqual( + props.createFilterString(context, range), + '(to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')") <= make_datetime(2020,5,6,8,9,10)', + ) + + range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + includeEnd=False, + ) # map range (-------------------------) # feature ranges . . [--------> (false) # . [----------> (false) @@ -944,9 +1504,16 @@ def testExpressionMode(self): # [-------------.-------------------------.----------> (true) # # => start expression < end of range - self.assertEqual(props.createFilterString(context, range), '(to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')") < make_datetime(2020,5,6,8,9,10)') - - range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False) + self.assertEqual( + props.createFilterString(context, range), + '(to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')") < make_datetime(2020,5,6,8,9,10)', + ) + + range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + ) # map range (-------------------------] # feature ranges . . [--------> (false) # . [----------> (true) @@ -955,9 +1522,16 @@ def testExpressionMode(self): # [-------------.-------------------------.----------> (true) # # => start expression <= end of range - self.assertEqual(props.createFilterString(context, range), '(to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')") <= make_datetime(2020,5,6,8,9,10)') - - range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeEnd=False) + self.assertEqual( + props.createFilterString(context, range), + '(to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')") <= make_datetime(2020,5,6,8,9,10)', + ) + + range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeEnd=False, + ) # map range [-------------------------) # feature ranges . . [--------> (false) # . [----------> (false) @@ -966,13 +1540,21 @@ def testExpressionMode(self): # [-------------.-------------------------.----------> (true) # # => start expression < end of range - self.assertEqual(props.createFilterString(context, range), '(to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')") < make_datetime(2020,5,6,8,9,10)') + self.assertEqual( + props.createFilterString(context, range), + '(to_datetime("my string field", \'yyyy MM dd hh::mm:ss\')") < make_datetime(2020,5,6,8,9,10)', + ) # features start at -eternity - props.setStartExpression('') - props.setEndExpression('to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')"') + props.setStartExpression("") + props.setEndExpression( + 'to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')"' + ) # includes beginning AND end - range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10))) + range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + ) # map range [-------------------------] # feature ranges --------.-------------------------.---------) (true) # --------.-------------------------) (true) @@ -981,9 +1563,17 @@ def testExpressionMode(self): # -----) . (false) # # => end of feature > start of range - self.assertEqual(props.createFilterString(context, range), '(to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") > make_datetime(2019,3,4,11,12,13)') - - range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False, includeEnd=False) + self.assertEqual( + props.createFilterString(context, range), + '(to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") > make_datetime(2019,3,4,11,12,13)', + ) + + range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + includeEnd=False, + ) # map range (-------------------------) # feature ranges --------.-------------------------.---------) (true) # --------.-------------------------) (true) @@ -992,9 +1582,16 @@ def testExpressionMode(self): # -----) . (false) # # => end of feature > start of range - self.assertEqual(props.createFilterString(context, range), '(to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") > make_datetime(2019,3,4,11,12,13)') - - range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeBeginning=False) + self.assertEqual( + props.createFilterString(context, range), + '(to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") > make_datetime(2019,3,4,11,12,13)', + ) + + range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeBeginning=False, + ) # map range (-------------------------] # feature ranges --------.-------------------------.---------) (true) # --------.-------------------------) (true) @@ -1003,10 +1600,17 @@ def testExpressionMode(self): # -----) . (false) # # => end of feature > start of range - self.assertEqual(props.createFilterString(context, range), '(to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") > make_datetime(2019,3,4,11,12,13)') + self.assertEqual( + props.createFilterString(context, range), + '(to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") > make_datetime(2019,3,4,11,12,13)', + ) # THIS is the QGIS default: using a range with includeBeginning=true and includeEnd=false - range = QgsDateTimeRange(QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), includeEnd=False) + range = QgsDateTimeRange( + QDateTime(QDate(2019, 3, 4), QTime(11, 12, 13)), + QDateTime(QDate(2020, 5, 6), QTime(8, 9, 10)), + includeEnd=False, + ) # map range [-------------------------) # feature ranges --------.-------------------------.---------) (true) # --------.-------------------------) (true) @@ -1015,7 +1619,10 @@ def testExpressionMode(self): # -----) . (false) # # => end of feature > start of range - self.assertEqual(props.createFilterString(context, range), '(to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") > make_datetime(2019,3,4,11,12,13)') + self.assertEqual( + props.createFilterString(context, range), + '(to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") > make_datetime(2019,3,4,11,12,13)', + ) # map range [-------------------------) # feature ranges --------.-------------------------.---------] (true) # --------.-------------------------] (true) @@ -1024,9 +1631,14 @@ def testExpressionMode(self): # -----] . (false) # # => end of feature >= start of range props.setLimitMode(Qgis.VectorTemporalLimitMode.IncludeBeginIncludeEnd) - self.assertEqual(props.createFilterString(context, range), '(to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") >= make_datetime(2019,3,4,11,12,13)') - props.setLimitMode(Qgis.VectorTemporalLimitMode.IncludeBeginExcludeEnd) # back to default + self.assertEqual( + props.createFilterString(context, range), + '(to_datetime("my end field", \'yyyy MM dd hh::mm:ss\')") >= make_datetime(2019,3,4,11,12,13)', + ) + props.setLimitMode( + Qgis.VectorTemporalLimitMode.IncludeBeginExcludeEnd + ) # back to default -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorlayertools.py b/tests/src/python/test_qgsvectorlayertools.py index 2230eb8f52ab..0d4ab8bce68e 100644 --- a/tests/src/python/test_qgsvectorlayertools.py +++ b/tests/src/python/test_qgsvectorlayertools.py @@ -6,9 +6,9 @@ (at your option) any later version. """ -__author__ = 'Denis Rouzaud' -__date__ = '2016-11-07' -__copyright__ = 'Copyright 2015, The QGIS Project' +__author__ = "Denis Rouzaud" +__date__ = "2016-11-07" +__copyright__ = "Copyright 2015, The QGIS Project" import os @@ -56,14 +56,21 @@ def setUpClass(cls): :return: """ super().setUpClass() - cls.dbconn = 'service=\'qgis_test\'' - if 'QGIS_PGTEST_DB' in os.environ: - cls.dbconn = os.environ['QGIS_PGTEST_DB'] + cls.dbconn = "service='qgis_test'" + if "QGIS_PGTEST_DB" in os.environ: + cls.dbconn = os.environ["QGIS_PGTEST_DB"] # Create test layers - cls.vl = QgsVectorLayer(cls.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."someData" (geom) sql=', 'layer', 'postgres') - - cls.vl2 = QgsVectorLayer('Point?crs=EPSG:4326&field=id:integer(10,0)', 'points', 'memory') + cls.vl = QgsVectorLayer( + cls.dbconn + + ' sslmode=disable key=\'pk\' table="qgis_test"."someData" (geom) sql=', + "layer", + "postgres", + ) + + cls.vl2 = QgsVectorLayer( + "Point?crs=EPSG:4326&field=id:integer(10,0)", "points", "memory" + ) f = QgsFeature(cls.vl2.fields()) f.setGeometry(QgsPoint(1, 1)) f.setAttributes([1]) @@ -71,7 +78,9 @@ def setUpClass(cls): cls.vl2.addFeature(f) cls.vl2.commitChanges() - cls.vl3 = QgsVectorLayer('NoGeometry?crs=EPSG:4326&field=point_id:integer(10,0)', 'details', 'memory') + cls.vl3 = QgsVectorLayer( + "NoGeometry?crs=EPSG:4326&field=point_id:integer(10,0)", "details", "memory" + ) f = QgsFeature(cls.vl3.fields()) f.setAttributes([1]) cls.vl3.startEditing() @@ -82,18 +91,18 @@ def setUpClass(cls): QgsProject.instance().addMapLayers([cls.vl, cls.vl2, cls.vl3]) relation = QgsRelation() - relation.setName('test') + relation.setName("test") relation.setReferencedLayer(cls.vl2.id()) relation.setReferencingLayer(cls.vl3.id()) relation.setStrength(Qgis.RelationshipStrength.Composition) - relation.addFieldPair('point_id', 'id') + relation.addFieldPair("point_id", "id") QgsProject.instance().relationManager().addRelation(relation) cls.vltools = SubQgsVectorLayerTools() cls.vltools.setProject(QgsProject.instance()) def testCopyMoveFeature(self): - """ Test copy and move features""" + """Test copy and move features""" rqst = QgsFeatureRequest() rqst.setFilterFid(4) features_count = self.vl.featureCount() @@ -107,7 +116,7 @@ def testCopyMoveFeature(self): self.assertAlmostEqual(geom.asPoint().y(), 78.5) def testCopyMoveFeatureRelationship(self): - """ Test copy and move features""" + """Test copy and move features""" rqst = QgsFeatureRequest() rqst.setFilterFid(1) self.vl2.startEditing() @@ -116,5 +125,5 @@ def testCopyMoveFeatureRelationship(self): self.assertEqual(self.vl3.featureCount(), 4) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorlayerutils.py b/tests/src/python/test_qgsvectorlayerutils.py index a995a0da48aa..cf2ec574fa9f 100644 --- a/tests/src/python/test_qgsvectorlayerutils.py +++ b/tests/src/python/test_qgsvectorlayerutils.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '25/10/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "25/10/2016" +__copyright__ = "Copyright 2016, The QGIS Project" import shutil import tempfile @@ -38,8 +39,9 @@ def createLayerWithOnePoint(): - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) pr = layer.dataProvider() f = QgsFeature() f.setAttributes(["test", 123]) @@ -63,14 +65,14 @@ def test_field_is_read_only(self): self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 0)) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 1)) - field = QgsField('test', QVariant.String) + field = QgsField("test", QVariant.String) layer.addAttribute(field) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 0)) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 1)) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 2)) # simulate read-only field from provider - field = QgsField('test2', QVariant.String) + field = QgsField("test2", QVariant.String) field.setReadOnly(True) layer.addAttribute(field) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 0)) @@ -93,17 +95,20 @@ def test_field_is_read_only(self): self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 1)) # joined field - layer2 = QgsVectorLayer("Point?field=fldtxt2:string&field=fldint:integer", - "addfeat", "memory") + layer2 = QgsVectorLayer( + "Point?field=fldtxt2:string&field=fldint:integer", "addfeat", "memory" + ) join_info = QgsVectorLayerJoinInfo() join_info.setJoinLayer(layer2) - join_info.setJoinFieldName('fldint') - join_info.setTargetFieldName('fldint') + join_info.setJoinFieldName("fldint") + join_info.setTargetFieldName("fldint") join_info.setUsingMemoryCache(True) layer.addJoin(join_info) layer.updateFields() - self.assertEqual([f.name() for f in layer.fields()], ['fldtxt', 'fldint', 'addfeat_fldtxt2']) + self.assertEqual( + [f.name() for f in layer.fields()], ["fldtxt", "fldint", "addfeat_fldtxt2"] + ) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 0)) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 1)) # join layer is not editable @@ -114,7 +119,9 @@ def test_field_is_read_only(self): join_info.setEditable(True) layer.addJoin(join_info) layer.updateFields() - self.assertEqual([f.name() for f in layer.fields()], ['fldtxt', 'fldint', 'addfeat_fldtxt2']) + self.assertEqual( + [f.name() for f in layer.fields()], ["fldtxt", "fldint", "addfeat_fldtxt2"] + ) # should still be read only -- the join layer itself is not editable self.assertTrue(QgsVectorLayerUtils.fieldIsReadOnly(layer, 2)) @@ -140,17 +147,20 @@ def test_field_editability_depends_on_feature(self): self.assertFalse(QgsVectorLayerUtils.fieldEditabilityDependsOnFeature(layer, 1)) # joined field - layer2 = QgsVectorLayer("Point?field=fldtxt2:string&field=fldint:integer", - "addfeat", "memory") + layer2 = QgsVectorLayer( + "Point?field=fldtxt2:string&field=fldint:integer", "addfeat", "memory" + ) join_info = QgsVectorLayerJoinInfo() join_info.setJoinLayer(layer2) - join_info.setJoinFieldName('fldint') - join_info.setTargetFieldName('fldint') + join_info.setJoinFieldName("fldint") + join_info.setTargetFieldName("fldint") join_info.setUsingMemoryCache(True) layer.addJoin(join_info) layer.updateFields() - self.assertEqual([f.name() for f in layer.fields()], ['fldtxt', 'fldint', 'addfeat_fldtxt2']) + self.assertEqual( + [f.name() for f in layer.fields()], ["fldtxt", "fldint", "addfeat_fldtxt2"] + ) self.assertFalse(QgsVectorLayerUtils.fieldEditabilityDependsOnFeature(layer, 0)) self.assertFalse(QgsVectorLayerUtils.fieldEditabilityDependsOnFeature(layer, 1)) # join layer is not editable => regardless of the feature, the field will always be read-only @@ -162,7 +172,9 @@ def test_field_editability_depends_on_feature(self): join_info.setUpsertOnEdit(True) layer.addJoin(join_info) layer.updateFields() - self.assertEqual([f.name() for f in layer.fields()], ['fldtxt', 'fldint', 'addfeat_fldtxt2']) + self.assertEqual( + [f.name() for f in layer.fields()], ["fldtxt", "fldint", "addfeat_fldtxt2"] + ) # has upsert on edit => regardless of feature, we can create the join target to make the field editable self.assertFalse(QgsVectorLayerUtils.fieldEditabilityDependsOnFeature(layer, 2)) @@ -172,7 +184,9 @@ def test_field_editability_depends_on_feature(self): join_info.setUpsertOnEdit(False) layer.addJoin(join_info) layer.updateFields() - self.assertEqual([f.name() for f in layer.fields()], ['fldtxt', 'fldint', 'addfeat_fldtxt2']) + self.assertEqual( + [f.name() for f in layer.fields()], ["fldtxt", "fldint", "addfeat_fldtxt2"] + ) # No upsert on edit => depending on feature, we either can edit the field or not, depending on whether # the join target feature already exists or not @@ -191,10 +205,10 @@ def test_value_exists(self): f4.setAttributes(["test4", 127]) layer.dataProvider().addFeatures([f1, f2, f3, f4]) - self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, 'test')) - self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, 'test1')) - self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, 'test4')) - self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 0, 'not present!')) + self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, "test")) + self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, "test1")) + self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, "test4")) + self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 0, "not present!")) self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 1, 123)) self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 1, 124)) self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 1, 127)) @@ -203,15 +217,17 @@ def test_value_exists(self): # no layer self.assertFalse(QgsVectorLayerUtils.valueExists(None, 1, 123)) # bad field indexes - self.assertFalse(QgsVectorLayerUtils.valueExists(layer, -1, 'test')) - self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 100, 'test')) + self.assertFalse(QgsVectorLayerUtils.valueExists(layer, -1, "test")) + self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 100, "test")) # with ignore list - self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, 'test1', [3, 4, 5])) - self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, 'test1', [999999])) - self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 0, 'test1', [2])) - self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 0, 'test1', [99999, 2])) - self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 0, 'test1', [3, 4, 5, 2])) + self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, "test1", [3, 4, 5])) + self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, "test1", [999999])) + self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 0, "test1", [2])) + self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 0, "test1", [99999, 2])) + self.assertFalse( + QgsVectorLayerUtils.valueExists(layer, 0, "test1", [3, 4, 5, 2]) + ) self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 1, 125, [2, 4, 5])) self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 1, 125, [999999])) @@ -223,25 +239,25 @@ def test_value_exists_joins(self): """Test that unique values in fields from joined layers, see GH #36167""" p = QgsProject() - main_layer = QgsVectorLayer("Point?field=fid:integer", - "main_layer", "memory") + main_layer = QgsVectorLayer("Point?field=fid:integer", "main_layer", "memory") self.assertTrue(main_layer.isValid()) # Attr layer is joined with layer on fk -> - attr_layer = QgsVectorLayer("Point?field=id:integer&field=fk:integer", - "attr_layer", "memory") + attr_layer = QgsVectorLayer( + "Point?field=id:integer&field=fk:integer", "attr_layer", "memory" + ) self.assertTrue(attr_layer.isValid()) p.addMapLayers([main_layer, attr_layer]) join_info = QgsVectorLayerJoinInfo() join_info.setJoinLayer(attr_layer) - join_info.setJoinFieldName('fk') - join_info.setTargetFieldName('fid') + join_info.setJoinFieldName("fk") + join_info.setTargetFieldName("fid") join_info.setUsingMemoryCache(True) main_layer.addJoin(join_info) main_layer.updateFields() join_buffer = main_layer.joinBuffer() self.assertTrue(join_buffer.containsJoins()) - self.assertEqual(main_layer.fields().names(), ['fid', 'attr_layer_id']) + self.assertEqual(main_layer.fields().names(), ["fid", "attr_layer_id"]) f = QgsFeature(main_layer.fields()) f.setAttributes([1]) @@ -257,12 +273,12 @@ def test_value_exists_joins(self): self.assertFalse(QgsVectorLayerUtils.valueExists(main_layer, 1, 2)) def test_validate_attribute(self): - """ test validating attributes against constraints """ + """test validating attributes against constraints""" layer = createLayerWithOnePoint() # field expression check self.assertFalse(QgsVectorLayerUtils.attributeHasConstraints(layer, 1)) - layer.setConstraintExpression(1, 'fldint>5') + layer.setConstraintExpression(1, "fldint>5") self.assertTrue(QgsVectorLayerUtils.attributeHasConstraints(layer, 1)) f = QgsFeature(2) @@ -276,13 +292,17 @@ def test_validate_attribute(self): self.assertEqual(len(errors), 1) print(errors) # checking only for provider constraints - res, errors = QgsVectorLayerUtils.validateAttribute(layer, f, 1, - origin=QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) + res, errors = QgsVectorLayerUtils.validateAttribute( + layer, + f, + 1, + origin=QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) self.assertTrue(res) self.assertEqual(len(errors), 0) # bad field expression check - layer.setConstraintExpression(1, 'fldint>') + layer.setConstraintExpression(1, "fldint>") res, errors = QgsVectorLayerUtils.validateAttribute(layer, f, 1) self.assertFalse(res) self.assertEqual(len(errors), 1) @@ -306,8 +326,12 @@ def test_validate_attribute(self): print(errors) # checking only for provider constraints - res, errors = QgsVectorLayerUtils.validateAttribute(layer, f, 1, - origin=QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) + res, errors = QgsVectorLayerUtils.validateAttribute( + layer, + f, + 1, + origin=QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) self.assertTrue(res) self.assertEqual(len(errors), 0) @@ -328,20 +352,36 @@ def test_validate_attribute(self): print(errors) # checking only for provider constraints - res, errors = QgsVectorLayerUtils.validateAttribute(layer, f, 1, - origin=QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider) + res, errors = QgsVectorLayerUtils.validateAttribute( + layer, + f, + 1, + origin=QgsFieldConstraints.ConstraintOrigin.ConstraintOriginProvider, + ) self.assertTrue(res) self.assertEqual(len(errors), 0) # checking only for soft constraints - layer.setFieldConstraint(1, QgsFieldConstraints.Constraint.ConstraintUnique, QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard) - res, errors = QgsVectorLayerUtils.validateAttribute(layer, f, 1, - strength=QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft) + layer.setFieldConstraint( + 1, + QgsFieldConstraints.Constraint.ConstraintUnique, + QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard, + ) + res, errors = QgsVectorLayerUtils.validateAttribute( + layer, + f, + 1, + strength=QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft, + ) self.assertTrue(res) self.assertEqual(len(errors), 0) # checking for hard constraints - res, errors = QgsVectorLayerUtils.validateAttribute(layer, f, 1, - strength=QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard) + res, errors = QgsVectorLayerUtils.validateAttribute( + layer, + f, + 1, + strength=QgsFieldConstraints.ConstraintStrength.ConstraintStrengthHard, + ) self.assertFalse(res) self.assertEqual(len(errors), 1) @@ -353,7 +393,7 @@ def test_validate_attribute(self): self.assertEqual(len(errors), 0) # test double constraint failure - layer.setConstraintExpression(1, 'fldint>5') + layer.setConstraintExpression(1, "fldint>5") layer.removeFieldConstraint(1, QgsFieldConstraints.Constraint.ConstraintUnique) layer.setFieldConstraint(1, QgsFieldConstraints.Constraint.ConstraintNotNull) f.setAttributes(["test123", NULL]) @@ -363,9 +403,12 @@ def test_validate_attribute(self): print(errors) def testCreateUniqueValue(self): - """ test creating a unique value """ - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=flddbl:double", - "addfeat", "memory") + """test creating a unique value""" + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer&field=flddbl:double", + "addfeat", + "memory", + ) # add a bunch of features f = QgsFeature() f.setAttributes(["test", 123, 1.0]) @@ -390,15 +433,24 @@ def testCreateUniqueValue(self): self.assertEqual(QgsVectorLayerUtils.createUniqueValue(layer, 2), 3.0) # string field - self.assertEqual(QgsVectorLayerUtils.createUniqueValue(layer, 0), 'test_4') - self.assertEqual(QgsVectorLayerUtils.createUniqueValue(layer, 0, 'test_1'), 'test_4') - self.assertEqual(QgsVectorLayerUtils.createUniqueValue(layer, 0, 'seed'), 'seed') - self.assertEqual(QgsVectorLayerUtils.createUniqueValue(layer, 0, 'superpig'), 'superpig_1') + self.assertEqual(QgsVectorLayerUtils.createUniqueValue(layer, 0), "test_4") + self.assertEqual( + QgsVectorLayerUtils.createUniqueValue(layer, 0, "test_1"), "test_4" + ) + self.assertEqual( + QgsVectorLayerUtils.createUniqueValue(layer, 0, "seed"), "seed" + ) + self.assertEqual( + QgsVectorLayerUtils.createUniqueValue(layer, 0, "superpig"), "superpig_1" + ) def testCreateFeature(self): - """ test creating a feature respecting defaults and constraints """ - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=flddbl:double", - "addfeat", "memory") + """test creating a feature respecting defaults and constraints""" + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer&field=flddbl:double", + "addfeat", + "memory", + ) # add a bunch of features f = QgsFeature() f.setAttributes(["test", 123, 1.0]) @@ -429,22 +481,22 @@ def testCreateFeature(self): self.assertEqual(f.geometry().asWkt(), g.asWkt()) # using attribute map - f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'a', 2: 6.0}) - self.assertEqual(f.attributes(), ['a', NULL, 6.0]) + f = QgsVectorLayerUtils.createFeature(layer, attributes={0: "a", 2: 6.0}) + self.assertEqual(f.attributes(), ["a", NULL, 6.0]) # layer with default value expression - layer.setDefaultValueDefinition(2, QgsDefaultValue('3*4')) + layer.setDefaultValueDefinition(2, QgsDefaultValue("3*4")) f = QgsVectorLayerUtils.createFeature(layer) self.assertEqual(f.attributes(), [NULL, NULL, 12]) # we do not expect the default value expression to take precedence over the attribute map - f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'a', 2: 6.0}) - self.assertEqual(f.attributes(), ['a', NULL, 6.0]) + f = QgsVectorLayerUtils.createFeature(layer, attributes={0: "a", 2: 6.0}) + self.assertEqual(f.attributes(), ["a", NULL, 6.0]) # default value takes precedence if it's apply on update - layer.setDefaultValueDefinition(2, QgsDefaultValue('3*4', True)) - f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'a', 2: 6.0}) - self.assertEqual(f.attributes(), ['a', NULL, 12.0]) + layer.setDefaultValueDefinition(2, QgsDefaultValue("3*4", True)) + f = QgsVectorLayerUtils.createFeature(layer, attributes={0: "a", 2: 6.0}) + self.assertEqual(f.attributes(), ["a", NULL, 12.0]) # layer with default value expression based on geometry - layer.setDefaultValueDefinition(2, QgsDefaultValue('3*$x')) + layer.setDefaultValueDefinition(2, QgsDefaultValue("3*$x")) f = QgsVectorLayerUtils.createFeature(layer, g) # adjusted so that input value and output feature are the same self.assertEqual(f.attributes(), [NULL, NULL, 300.0]) @@ -452,41 +504,44 @@ def testCreateFeature(self): # test with violated unique constraints layer.setFieldConstraint(1, QgsFieldConstraints.Constraint.ConstraintUnique) - f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'test_1', 1: 123}) + f = QgsVectorLayerUtils.createFeature(layer, attributes={0: "test_1", 1: 123}) # since field 1 has Unique Constraint, it ignores value 123 that already has been set and sets to 128 - self.assertEqual(f.attributes(), ['test_1', 128, NULL]) + self.assertEqual(f.attributes(), ["test_1", 128, NULL]) layer.setFieldConstraint(0, QgsFieldConstraints.Constraint.ConstraintUnique) # since field 0 and 1 already have values test_1 and 123, the output must be a new unique value - f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'test_1', 1: 123}) - self.assertEqual(f.attributes(), ['test_4', 128, NULL]) + f = QgsVectorLayerUtils.createFeature(layer, attributes={0: "test_1", 1: 123}) + self.assertEqual(f.attributes(), ["test_4", 128, NULL]) # test with violated unique constraints and default value expression providing unique value - layer.setDefaultValueDefinition(1, QgsDefaultValue('130')) - f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'test_1', 1: 123}) + layer.setDefaultValueDefinition(1, QgsDefaultValue("130")) + f = QgsVectorLayerUtils.createFeature(layer, attributes={0: "test_1", 1: 123}) # since field 1 has Unique Constraint, it ignores value 123 that already has been set and adds the default value - self.assertEqual(f.attributes(), ['test_4', 130, NULL]) + self.assertEqual(f.attributes(), ["test_4", 130, NULL]) # fallback: test with violated unique constraints and default value expression providing already existing value # add the feature with the default value: self.assertTrue(layer.dataProvider().addFeatures([f])) - f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'test_1', 1: 123}) + f = QgsVectorLayerUtils.createFeature(layer, attributes={0: "test_1", 1: 123}) # since field 1 has Unique Constraint, it ignores value 123 that already has been set and adds the default value # and since the default value providing an already existing value (130) it generates a unique value (next int: 131) - self.assertEqual(f.attributes(), ['test_5', 131, NULL]) + self.assertEqual(f.attributes(), ["test_5", 131, NULL]) layer.setDefaultValueDefinition(1, QgsDefaultValue(None)) # test with manually correct unique constraint - f = QgsVectorLayerUtils.createFeature(layer, attributes={0: 'test_1', 1: 132}) - self.assertEqual(f.attributes(), ['test_5', 132, NULL]) + f = QgsVectorLayerUtils.createFeature(layer, attributes={0: "test_1", 1: 132}) + self.assertEqual(f.attributes(), ["test_5", 132, NULL]) def testDuplicateFeature(self): - """ test duplicating a feature with relations """ + """test duplicating a feature with relations""" project = QgsProject().instance() # LAYERS # - add first layer (parent) - layer1 = QgsVectorLayer("Point?field=fldtxt:string&field=pkid:integer&field=policycheck1value:text&field=policycheck2value:text&field=policycheck3value:text", - "parentlayer", "memory") + layer1 = QgsVectorLayer( + "Point?field=fldtxt:string&field=pkid:integer&field=policycheck1value:text&field=policycheck2value:text&field=policycheck3value:text", + "parentlayer", + "memory", + ) # > check first layer (parent) self.assertTrue(layer1.isValid()) # - set the default values for pk and policy check and the field policy @@ -500,8 +555,11 @@ def testDuplicateFeature(self): # > check first layer (parent) self.assertTrue(layer1.isValid()) # - add second layer (child) - layer2 = QgsVectorLayer("Point?field=fldtxt:string&field=id:integer&field=foreign_key:integer&field=policycheck1value:text&field=policycheck2value:text&field=policycheck3value:text", - "childlayer1", "memory") + layer2 = QgsVectorLayer( + "Point?field=fldtxt:string&field=id:integer&field=foreign_key:integer&field=policycheck1value:text&field=policycheck2value:text&field=policycheck3value:text", + "childlayer1", + "memory", + ) # > check second layer (child) self.assertTrue(layer2.isValid()) # - set the default values for pk and policy check and the field policy @@ -514,8 +572,11 @@ def testDuplicateFeature(self): # > check second layer (child) self.assertTrue(layer2.isValid()) # - add third layer (child) - layer3 = QgsVectorLayer("Point?field=fldtxt:string&field=id:integer&field=foreign_key:integer&field=policycheck1value:text&field=policycheck2value:text&field=policycheck3value:text", - "childlayer2", "memory") + layer3 = QgsVectorLayer( + "Point?field=fldtxt:string&field=id:integer&field=foreign_key:integer&field=policycheck1value:text&field=policycheck2value:text&field=policycheck3value:text", + "childlayer2", + "memory", + ) # > check third layer (child) self.assertTrue(layer3.isValid()) # - set the default values for pk and policy check and the field policy @@ -534,34 +595,52 @@ def testDuplicateFeature(self): # - add 2 features on layer1 (parent) l1f1orig = QgsFeature() l1f1orig.setFields(layer1.fields()) - l1f1orig.setAttributes(["F_l1f1", 100, 'Orig Blabla L1', 'Orig Blabla L1', 'Orig Blabla L1']) + l1f1orig.setAttributes( + ["F_l1f1", 100, "Orig Blabla L1", "Orig Blabla L1", "Orig Blabla L1"] + ) l1f2orig = QgsFeature() l1f2orig.setFields(layer1.fields()) - l1f2orig.setAttributes(["F_l1f2", 101, 'Orig Blabla L1', 'Orig Blabla L1', 'Orig Blabla L1']) + l1f2orig.setAttributes( + ["F_l1f2", 101, "Orig Blabla L1", "Orig Blabla L1", "Orig Blabla L1"] + ) # > check by adding features self.assertTrue(layer1.dataProvider().addFeatures([l1f1orig, l1f2orig])) # add 4 features on layer2 (child) l2f1orig = QgsFeature() l2f1orig.setFields(layer2.fields()) - l2f1orig.setAttributes(["F_l2f1", 201, 100, 'Orig Blabla L2', 'Orig Blabla L2', 'Orig Blabla L2']) + l2f1orig.setAttributes( + ["F_l2f1", 201, 100, "Orig Blabla L2", "Orig Blabla L2", "Orig Blabla L2"] + ) l2f2orig = QgsFeature() l2f2orig.setFields(layer2.fields()) - l2f2orig.setAttributes(["F_l2f2", 202, 100, 'Orig Blabla L2', 'Orig Blabla L2', 'Orig Blabla L2']) + l2f2orig.setAttributes( + ["F_l2f2", 202, 100, "Orig Blabla L2", "Orig Blabla L2", "Orig Blabla L2"] + ) l2f3orig = QgsFeature() l2f3orig.setFields(layer2.fields()) - l2f3orig.setAttributes(["F_l2f3", 203, 100, 'Orig Blabla L2', 'Orig Blabla L2', 'Orig Blabla L2']) + l2f3orig.setAttributes( + ["F_l2f3", 203, 100, "Orig Blabla L2", "Orig Blabla L2", "Orig Blabla L2"] + ) l2f4orig = QgsFeature() l2f4orig.setFields(layer2.fields()) - l2f4orig.setAttributes(["F_l2f4", 204, 101, 'Orig Blabla L2', 'Orig Blabla L2', 'Orig Blabla L2']) + l2f4orig.setAttributes( + ["F_l2f4", 204, 101, "Orig Blabla L2", "Orig Blabla L2", "Orig Blabla L2"] + ) # > check by adding features - self.assertTrue(layer2.dataProvider().addFeatures([l2f1orig, l2f2orig, l2f3orig, l2f4orig])) + self.assertTrue( + layer2.dataProvider().addFeatures([l2f1orig, l2f2orig, l2f3orig, l2f4orig]) + ) # add 2 features on layer3 (child) l3f1orig = QgsFeature() l3f1orig.setFields(layer3.fields()) - l3f1orig.setAttributes(["F_l3f1", 301, 100, 'Orig Blabla L3', 'Orig Blabla L3', 'Orig Blabla L3']) + l3f1orig.setAttributes( + ["F_l3f1", 301, 100, "Orig Blabla L3", "Orig Blabla L3", "Orig Blabla L3"] + ) l3f2orig = QgsFeature() l3f2orig.setFields(layer2.fields()) - l3f2orig.setAttributes(["F_l3f2", 302, 100, 'Orig Blabla L3', 'Orig Blabla L3', 'Orig Blabla L3']) + l3f2orig.setAttributes( + ["F_l3f2", 302, 100, "Orig Blabla L3", "Orig Blabla L3", "Orig Blabla L3"] + ) # > check by adding features self.assertTrue(layer3.dataProvider().addFeatures([l3f1orig, l3f2orig])) @@ -570,11 +649,11 @@ def testDuplicateFeature(self): relMgr = project.relationManager() # - create the first relation rel1 = QgsRelation() - rel1.setId('rel1') - rel1.setName('childrel1') + rel1.setId("rel1") + rel1.setName("childrel1") rel1.setReferencingLayer(layer2.id()) rel1.setReferencedLayer(layer1.id()) - rel1.addFieldPair('foreign_key', 'pkid') + rel1.addFieldPair("foreign_key", "pkid") rel1.setStrength(QgsRelation.RelationStrength.Composition) # > check relation self.assertTrue(rel1.isValid()) @@ -586,11 +665,11 @@ def testDuplicateFeature(self): self.assertEqual(rel1.referencingLayer(), layer2) # - create the second relation rel2 = QgsRelation() - rel2.setId('rel2') - rel2.setName('childrel2') + rel2.setId("rel2") + rel2.setName("childrel2") rel2.setReferencingLayer(layer3.id()) rel2.setReferencedLayer(layer1.id()) - rel2.addFieldPair('foreign_key', 'pkid') + rel2.addFieldPair("foreign_key", "pkid") rel2.setStrength(QgsRelation.RelationStrength.Composition) # > check relation self.assertTrue(rel2.isValid()) @@ -602,20 +681,20 @@ def testDuplicateFeature(self): self.assertEqual(rel2.referencingLayer(), layer3) # > check if the layers are correct in relation when loading from relationManager - relations = project.relationManager().relationsByName('childrel1') + relations = project.relationManager().relationsByName("childrel1") relation = relations[0] # > check if referencedLayer is layer1 self.assertEqual(relation.referencedLayer(), layer1) # > check if referencingLayer is layer2 self.assertEqual(relation.referencingLayer(), layer2) - relations = project.relationManager().relationsByName('childrel2') + relations = project.relationManager().relationsByName("childrel2") relation = relations[0] # > check if referencedLayer is layer1 self.assertEqual(relation.referencedLayer(), layer1) # > check if referencingLayer is layer2 self.assertEqual(relation.referencingLayer(), layer3) - ''' + """ # testoutput 1 print( "\nAll Features and relations") featit=layer1.getFeatures() @@ -635,7 +714,7 @@ def testDuplicateFeature(self): print( "\nFeatures on layer2") for f in layer2.getFeatures(): print( f.attributes() ) - ''' + """ # DUPLICATION # - duplicate feature l1f1orig with children @@ -645,10 +724,16 @@ def testDuplicateFeature(self): # > check if name is name of duplicated (pk is different) # > and duplicate policy is concerned result_feature = results[0] - self.assertEqual(result_feature.attribute('fldtxt'), l1f1orig.attribute('fldtxt')) - self.assertEqual(result_feature.attribute('policycheck1value'), 'Orig Blabla L1') # duplicated - self.assertEqual(result_feature.attribute('policycheck2value'), 'Def Blabla L1') # default Value - self.assertEqual(result_feature.attribute('policycheck3value'), None) # unset + self.assertEqual( + result_feature.attribute("fldtxt"), l1f1orig.attribute("fldtxt") + ) + self.assertEqual( + result_feature.attribute("policycheck1value"), "Orig Blabla L1" + ) # duplicated + self.assertEqual( + result_feature.attribute("policycheck2value"), "Def Blabla L1" + ) # default Value + self.assertEqual(result_feature.attribute("policycheck3value"), None) # unset # > check duplicated children occurred on both layers self.assertEqual(len(results[1].layers()), 2) idx = results[1].layers().index(layer2) @@ -656,19 +741,31 @@ def testDuplicateFeature(self): self.assertTrue(results[1].duplicatedFeatures(layer2)) for child_fid in results[1].duplicatedFeatures(layer2): child_feature = layer2.getFeature(child_fid) - self.assertEqual(child_feature.attribute('policycheck1value'), 'Orig Blabla L2') # duplicated - self.assertEqual(child_feature.attribute('policycheck2value'), 'Def Blabla L2') # default Value - self.assertEqual(child_feature.attribute('policycheck3value'), None) # unset + self.assertEqual( + child_feature.attribute("policycheck1value"), "Orig Blabla L2" + ) # duplicated + self.assertEqual( + child_feature.attribute("policycheck2value"), "Def Blabla L2" + ) # default Value + self.assertEqual( + child_feature.attribute("policycheck3value"), None + ) # unset idx = results[1].layers().index(layer3) self.assertEqual(results[1].layers()[idx], layer3) self.assertTrue(results[1].duplicatedFeatures(layer3)) for child_fid in results[1].duplicatedFeatures(layer3): child_feature = layer3.getFeature(child_fid) - self.assertEqual(child_feature.attribute('policycheck1value'), 'Orig Blabla L3') # duplicated - self.assertEqual(child_feature.attribute('policycheck2value'), 'Def Blabla L3') # default Value - self.assertEqual(child_feature.attribute('policycheck3value'), None) # unset + self.assertEqual( + child_feature.attribute("policycheck1value"), "Orig Blabla L3" + ) # duplicated + self.assertEqual( + child_feature.attribute("policycheck2value"), "Def Blabla L3" + ) # default Value + self.assertEqual( + child_feature.attribute("policycheck3value"), None + ) # unset - ''' + """ # testoutput 2 print( "\nFeatures on layer1 (after duplication)") for f in layer1.getFeatures(): @@ -687,23 +784,25 @@ def testDuplicateFeature(self): relfeatit=rel.getRelatedFeatures(f) while relfeatit.nextFeature(childFeature): print( childFeature.attributes() ) - ''' + """ # > compare text of parent feature - self.assertEqual(result_feature.attribute('fldtxt'), l1f1orig.attribute('fldtxt')) + self.assertEqual( + result_feature.attribute("fldtxt"), l1f1orig.attribute("fldtxt") + ) # - create copyValueList childFeature = QgsFeature() relfeatit = rel1.getRelatedFeatures(result_feature) copyValueList = [] while relfeatit.nextFeature(childFeature): - copyValueList.append(childFeature.attribute('fldtxt')) + copyValueList.append(childFeature.attribute("fldtxt")) # - create origValueList childFeature = QgsFeature() relfeatit = rel1.getRelatedFeatures(l1f1orig) origValueList = [] while relfeatit.nextFeature(childFeature): - origValueList.append(childFeature.attribute('fldtxt')) + origValueList.append(childFeature.attribute("fldtxt")) # - check if the ids are still the same self.assertEqual(copyValueList, origValueList) @@ -713,12 +812,12 @@ def test_make_features_compatible_attributes(self): # Test feature with attributes fields = QgsFields() - fields.append(QgsField('int_f', QVariant.Int)) - fields.append(QgsField('str_f', QVariant.String)) + fields.append(QgsField("int_f", QVariant.Int)) + fields.append(QgsField("str_f", QVariant.String)) f1 = QgsFeature(fields) - f1['int_f'] = 1 - f1['str_f'] = 'str' - f1.setGeometry(QgsGeometry.fromWkt('Point(9 45)')) + f1["int_f"] = 1 + f1["str_f"] = "str" + f1.setGeometry(QgsGeometry.fromWkt("Point(9 45)")) f2 = f1 QgsVectorLayerUtils.matchAttributesToFields(f2, fields) self.assertEqual(f1.attributes(), f2.attributes()) @@ -740,55 +839,55 @@ def test_make_features_compatible_attributes(self): # Test drop extra attrs f1 = QgsFeature(fields) - f1.setAttributes([1, 'foo', 'extra']) + f1.setAttributes([1, "foo", "extra"]) QgsVectorLayerUtils.matchAttributesToFields(f1, fields) self.assertEqual(len(f1.attributes()), 2) self.assertEqual(f1.attributes()[0], 1) - self.assertEqual(f1.attributes()[1], 'foo') + self.assertEqual(f1.attributes()[1], "foo") # Rearranged fields fields2 = QgsFields() - fields2.append(QgsField('str_f', QVariant.String)) - fields2.append(QgsField('int_f', QVariant.Int)) + fields2.append(QgsField("str_f", QVariant.String)) + fields2.append(QgsField("int_f", QVariant.Int)) f1 = QgsFeature(fields2) - f1.setAttributes([1, 'foo', 'extra']) + f1.setAttributes([1, "foo", "extra"]) QgsVectorLayerUtils.matchAttributesToFields(f1, fields) self.assertEqual(len(f1.attributes()), 2) - self.assertEqual(f1.attributes()[0], 'foo') + self.assertEqual(f1.attributes()[0], "foo") self.assertEqual(f1.attributes()[1], 1) # mixed - fields2.append(QgsField('extra', QVariant.String)) - fields.append(QgsField('extra2', QVariant.Int)) + fields2.append(QgsField("extra", QVariant.String)) + fields.append(QgsField("extra2", QVariant.Int)) f1.setFields(fields2) - f1.setAttributes([1, 'foo', 'blah']) + f1.setAttributes([1, "foo", "blah"]) QgsVectorLayerUtils.matchAttributesToFields(f1, fields) self.assertEqual(len(f1.attributes()), 3) - self.assertEqual(f1.attributes()[0], 'foo') + self.assertEqual(f1.attributes()[0], "foo") self.assertEqual(f1.attributes()[1], 1) self.assertEqual(f1.attributes()[2], NULL) - fields.append(QgsField('extra', QVariant.Int)) - f1.setAttributes([1, 'foo', 'blah']) + fields.append(QgsField("extra", QVariant.Int)) + f1.setAttributes([1, "foo", "blah"]) QgsVectorLayerUtils.matchAttributesToFields(f1, fields) self.assertEqual(len(f1.attributes()), 4) self.assertEqual(f1.attributes()[0], 1) - self.assertEqual(f1.attributes()[1], 'foo') - self.assertEqual(f1.attributes()[2], 'blah') + self.assertEqual(f1.attributes()[1], "foo") + self.assertEqual(f1.attributes()[2], "blah") self.assertEqual(f1.attributes()[3], NULL) # case insensitive - fields2.append(QgsField('extra3', QVariant.String)) - fields.append(QgsField('EXTRA3', QVariant.Int)) + fields2.append(QgsField("extra3", QVariant.String)) + fields.append(QgsField("EXTRA3", QVariant.Int)) f1.setFields(fields2) - f1.setAttributes([1, 'foo', 'blah', 'blergh']) + f1.setAttributes([1, "foo", "blah", "blergh"]) QgsVectorLayerUtils.matchAttributesToFields(f1, fields) self.assertEqual(len(f1.attributes()), 5) - self.assertEqual(f1.attributes()[0], 'foo') + self.assertEqual(f1.attributes()[0], "foo") self.assertEqual(f1.attributes()[1], 1) self.assertEqual(f1.attributes()[2], NULL) - self.assertEqual(f1.attributes()[3], 'blah') - self.assertEqual(f1.attributes()[4], 'blergh') + self.assertEqual(f1.attributes()[3], "blah") + self.assertEqual(f1.attributes()[4], "blergh") def test_create_multiple_unique_constraint(self): """Test create multiple features with unique constraint""" @@ -800,7 +899,10 @@ def test_create_multiple_unique_constraint(self): context = vl.createExpressionContext() for i in range(2): features_data.append( - QgsVectorLayerUtils.QgsFeatureData(QgsGeometry.fromWkt('Point (7 44)'), {0: f'test_{i}', 1: 123})) + QgsVectorLayerUtils.QgsFeatureData( + QgsGeometry.fromWkt("Point (7 44)"), {0: f"test_{i}", 1: 123} + ) + ) features = QgsVectorLayerUtils.createFeatures(vl, features_data, context) self.assertEqual(features[0].attributes()[1], 124) @@ -810,17 +912,30 @@ def test_create_nulls_and_defaults(self): """Test bug #21304 when pasting features from another layer and default values are not honored""" vl = createLayerWithOnePoint() - vl.setDefaultValueDefinition(1, QgsDefaultValue('300')) + vl.setDefaultValueDefinition(1, QgsDefaultValue("300")) features_data = [] context = vl.createExpressionContext() features_data.append( - QgsVectorLayerUtils.QgsFeatureData(QgsGeometry.fromWkt('Point (7 44)'), {0: 'test_1', 1: None})) + QgsVectorLayerUtils.QgsFeatureData( + QgsGeometry.fromWkt("Point (7 44)"), {0: "test_1", 1: None} + ) + ) + features_data.append( + QgsVectorLayerUtils.QgsFeatureData( + QgsGeometry.fromWkt("Point (7 45)"), {0: "test_2", 1: NULL} + ) + ) features_data.append( - QgsVectorLayerUtils.QgsFeatureData(QgsGeometry.fromWkt('Point (7 45)'), {0: 'test_2', 1: NULL})) - features_data.append(QgsVectorLayerUtils.QgsFeatureData(QgsGeometry.fromWkt('Point (7 46)'), - {0: 'test_3', 1: NULL})) - features_data.append(QgsVectorLayerUtils.QgsFeatureData(QgsGeometry.fromWkt('Point (7 46)'), {0: 'test_4'})) + QgsVectorLayerUtils.QgsFeatureData( + QgsGeometry.fromWkt("Point (7 46)"), {0: "test_3", 1: NULL} + ) + ) + features_data.append( + QgsVectorLayerUtils.QgsFeatureData( + QgsGeometry.fromWkt("Point (7 46)"), {0: "test_4"} + ) + ) features = QgsVectorLayerUtils.createFeatures(vl, features_data, context) for f in features: @@ -831,30 +946,46 @@ def test_create_nulls_and_defaults(self): features_data = [] context = vl.createExpressionContext() - features_data.append(QgsVectorLayerUtils.QgsFeatureData(QgsGeometry.fromWkt('Point (7 44)'), {0: None})) - features_data.append(QgsVectorLayerUtils.QgsFeatureData(QgsGeometry.fromWkt('Point (7 45)'), {0: NULL})) features_data.append( - QgsVectorLayerUtils.QgsFeatureData(QgsGeometry.fromWkt('Point (7 46)'), {0: NULL})) - features_data.append(QgsVectorLayerUtils.QgsFeatureData(QgsGeometry.fromWkt('Point (7 46)'), {})) + QgsVectorLayerUtils.QgsFeatureData( + QgsGeometry.fromWkt("Point (7 44)"), {0: None} + ) + ) + features_data.append( + QgsVectorLayerUtils.QgsFeatureData( + QgsGeometry.fromWkt("Point (7 45)"), {0: NULL} + ) + ) + features_data.append( + QgsVectorLayerUtils.QgsFeatureData( + QgsGeometry.fromWkt("Point (7 46)"), {0: NULL} + ) + ) + features_data.append( + QgsVectorLayerUtils.QgsFeatureData(QgsGeometry.fromWkt("Point (7 46)"), {}) + ) features = QgsVectorLayerUtils.createFeatures(vl, features_data, context) for f in features: - self.assertEqual(f.attributes()[0], 'my_default', f.id()) + self.assertEqual(f.attributes()[0], "my_default", f.id()) def test_unique_pk_when_subset(self): """Test unique values on filtered layer GH #30062""" - src = unitTestDataPath('points_gpkg.gpkg') - dest = tempfile.mktemp() + '.gpkg' + src = unitTestDataPath("points_gpkg.gpkg") + dest = tempfile.mktemp() + ".gpkg" shutil.copy(src, dest) - vl = QgsVectorLayer(dest, 'vl', 'ogr') + vl = QgsVectorLayer(dest, "vl", "ogr") self.assertTrue(vl.isValid()) features_data = [] it = vl.getFeatures() for _ in range(3): f = next(it) features_data.append( - QgsVectorLayerUtils.QgsFeatureData(f.geometry(), dict(zip(range(f.fields().count()), f.attributes())))) + QgsVectorLayerUtils.QgsFeatureData( + f.geometry(), dict(zip(range(f.fields().count()), f.attributes())) + ) + ) # Set a filter vl.setSubsetString('"fid" in (4,5,6)') self.assertTrue(vl.isValid()) @@ -871,67 +1002,93 @@ def testGuessFriendlyIdentifierField(self): fields = QgsFields() self.assertFalse(QgsVectorLayerUtils.guessFriendlyIdentifierField(fields)) - fields.append(QgsField('id', QVariant.Int)) - self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), 'id') - self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierFieldV2(fields), ('id', False)) - - fields.append(QgsField('name', QVariant.String)) - self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), 'name') - self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierFieldV2(fields), ('name', True)) - - fields.append(QgsField('title', QVariant.String)) - self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), 'name') - self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierFieldV2(fields), ('name', True)) + fields.append(QgsField("id", QVariant.Int)) + self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), "id") + self.assertEqual( + QgsVectorLayerUtils.guessFriendlyIdentifierFieldV2(fields), ("id", False) + ) + + fields.append(QgsField("name", QVariant.String)) + self.assertEqual( + QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), "name" + ) + self.assertEqual( + QgsVectorLayerUtils.guessFriendlyIdentifierFieldV2(fields), ("name", True) + ) + + fields.append(QgsField("title", QVariant.String)) + self.assertEqual( + QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), "name" + ) + self.assertEqual( + QgsVectorLayerUtils.guessFriendlyIdentifierFieldV2(fields), ("name", True) + ) # regardless of actual field order, we prefer "name" over "title" fields = QgsFields() - fields.append(QgsField('title', QVariant.String)) - fields.append(QgsField('name', QVariant.String)) - self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), 'name') + fields.append(QgsField("title", QVariant.String)) + fields.append(QgsField("name", QVariant.String)) + self.assertEqual( + QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), "name" + ) # test with an "anti candidate", which is a substring which makes a field containing "name" less preferred... fields = QgsFields() - fields.append(QgsField('id', QVariant.Int)) - fields.append(QgsField('typename', QVariant.String)) - self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), 'typename') - fields.append(QgsField('title', QVariant.String)) - self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), 'title') + fields.append(QgsField("id", QVariant.Int)) + fields.append(QgsField("typename", QVariant.String)) + self.assertEqual( + QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), "typename" + ) + fields.append(QgsField("title", QVariant.String)) + self.assertEqual( + QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), "title" + ) fields = QgsFields() - fields.append(QgsField('id', QVariant.Int)) - fields.append(QgsField('classname', QVariant.String)) - fields.append(QgsField('x', QVariant.String)) - self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), 'classname') - fields.append(QgsField('desc', QVariant.String)) - self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), 'desc') + fields.append(QgsField("id", QVariant.Int)) + fields.append(QgsField("classname", QVariant.String)) + fields.append(QgsField("x", QVariant.String)) + self.assertEqual( + QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), "classname" + ) + fields.append(QgsField("desc", QVariant.String)) + self.assertEqual( + QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), "desc" + ) fields = QgsFields() - fields.append(QgsField('id', QVariant.Int)) - fields.append(QgsField('areatypename', QVariant.String)) - fields.append(QgsField('areaadminname', QVariant.String)) - self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), 'areaadminname') + fields.append(QgsField("id", QVariant.Int)) + fields.append(QgsField("areatypename", QVariant.String)) + fields.append(QgsField("areaadminname", QVariant.String)) + self.assertEqual( + QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), "areaadminname" + ) # if no good matches by name found, the first string field should be used fields = QgsFields() - fields.append(QgsField('id', QVariant.Int)) - fields.append(QgsField('date', QVariant.Date)) - fields.append(QgsField('station', QVariant.String)) - fields.append(QgsField('org', QVariant.String)) - self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), 'station') + fields.append(QgsField("id", QVariant.Int)) + fields.append(QgsField("date", QVariant.Date)) + fields.append(QgsField("station", QVariant.String)) + fields.append(QgsField("org", QVariant.String)) + self.assertEqual( + QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), "station" + ) # Particular case for WFS layers analyzed with the GMLAS driver. # We prioritize a field ending with _name, but which is not gml_name fields = QgsFields() - fields.append(QgsField('id', QVariant.String)) - fields.append(QgsField('gml_name', QVariant.String)) - fields.append(QgsField('other_name', QVariant.String)) - self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), 'other_name') + fields.append(QgsField("id", QVariant.String)) + fields.append(QgsField("gml_name", QVariant.String)) + fields.append(QgsField("other_name", QVariant.String)) + self.assertEqual( + QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), "other_name" + ) fields = QgsFields() - fields.append(QgsField('id', QVariant.String)) - fields.append(QgsField('gml_name', QVariant.String)) - self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), 'id') + fields.append(QgsField("id", QVariant.String)) + fields.append(QgsField("gml_name", QVariant.String)) + self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), "id") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorlayerutils_postgres.py b/tests/src/python/test_qgsvectorlayerutils_postgres.py index 50ae082859b3..cafb19c99ea7 100644 --- a/tests/src/python/test_qgsvectorlayerutils_postgres.py +++ b/tests/src/python/test_qgsvectorlayerutils_postgres.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Julien Cabieces' -__date__ = '22/03/2021' -__copyright__ = 'Copyright 2021, The QGIS Project' + +__author__ = "Julien Cabieces" +__date__ = "22/03/2021" +__copyright__ = "Copyright 2021, The QGIS Project" import os @@ -26,20 +27,25 @@ class TestQgsVectorLayerUtilsPostgres(QgisTestCase): def testCreateFeature(self): - """ test creating a feature respecting unique values of postgres provider """ - layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=flddbl:double", - "addfeat", "memory") + """test creating a feature respecting unique values of postgres provider""" + layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer&field=flddbl:double", + "addfeat", + "memory", + ) # init connection string - dbconn = 'service=qgis_test' - if 'QGIS_PGTEST_DB' in os.environ: - dbconn = os.environ['QGIS_PGTEST_DB'] + dbconn = "service=qgis_test" + if "QGIS_PGTEST_DB" in os.environ: + dbconn = os.environ["QGIS_PGTEST_DB"] # create a vector layer - pg_layer = QgsVectorLayer(f'{dbconn} table="qgis_test"."authors" sql=', "authors", "postgres") + pg_layer = QgsVectorLayer( + f'{dbconn} table="qgis_test"."authors" sql=', "authors", "postgres" + ) self.assertTrue(pg_layer.isValid()) # check the default clause - default_clause = 'nextval(\'qgis_test.authors_pk_seq\'::regclass)' + default_clause = "nextval('qgis_test.authors_pk_seq'::regclass)" self.assertEqual(pg_layer.dataProvider().defaultValueClause(0), default_clause) # though default_clause is after the first create not unique (until save), it should fill up all the features with it @@ -58,11 +64,11 @@ def testCreateFeature(self): f = QgsVectorLayerUtils.createFeature(pg_layer, attributes={0: 40, 1: NULL}) self.assertEqual(f.attributes(), [40, NULL]) # and if a default value is configured use it as well - pg_layer.setDefaultValueDefinition(0, QgsDefaultValue('11*4')) + pg_layer.setDefaultValueDefinition(0, QgsDefaultValue("11*4")) f = QgsVectorLayerUtils.createFeature(pg_layer) self.assertEqual(f.attributes(), [44, NULL]) pg_layer.rollBack() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectortile.py b/tests/src/python/test_qgsvectortile.py index 702377fca195..a4866d1229b1 100644 --- a/tests/src/python/test_qgsvectortile.py +++ b/tests/src/python/test_qgsvectortile.py @@ -1,4 +1,4 @@ -''' +""" test_vectortile.py -------------------------------------- Date : September 2021 @@ -12,7 +12,7 @@ * (at your option) any later version. * * * ***************************************************************************/ -''' +""" import shutil import tempfile @@ -31,7 +31,7 @@ QgsVectorTileLayer, QgsVectorTileWriter, QgsMapSettings, - QgsRenderContext + QgsRenderContext, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -64,8 +64,7 @@ def tearDown(self): pass def testSingleTileEncode(self): - """ Test vector tile encoding from python - """ + """Test vector tile encoding from python""" vlPoints = QgsVectorLayer(str(TEST_DATA_PATH / "points.shp"), "points", "ogr") vlLines = QgsVectorLayer(str(TEST_DATA_PATH / "lines.shp"), "lines", "ogr") vlPolys = QgsVectorLayer(str(TEST_DATA_PATH / "polys.shp"), "polys", "ogr") @@ -97,49 +96,76 @@ def testSingleTileEncode(self): self.assertEqual(ascii(data.data()), ascii(output)) def testEncodeDecodeUri(self): - """ Test encodeUri/decodeUri metadata functions """ - md = QgsProviderRegistry.instance().providerMetadata('vectortile') + """Test encodeUri/decodeUri metadata functions""" + md = QgsProviderRegistry.instance().providerMetadata("vectortile") - uri = 'type=mbtiles&url=/my/file.mbtiles' + uri = "type=mbtiles&url=/my/file.mbtiles" parts = md.decodeUri(uri) - self.assertEqual(parts, {'type': 'mbtiles', 'path': '/my/file.mbtiles'}) + self.assertEqual(parts, {"type": "mbtiles", "path": "/my/file.mbtiles"}) - parts['path'] = '/my/new/file.mbtiles' + parts["path"] = "/my/new/file.mbtiles" uri = md.encodeUri(parts) - self.assertEqual(uri, 'type=mbtiles&url=/my/new/file.mbtiles') + self.assertEqual(uri, "type=mbtiles&url=/my/new/file.mbtiles") - uri = 'type=xyz&url=https://fake.server/%7Bx%7D/%7By%7D/%7Bz%7D.png&zmin=0&zmax=2' + uri = ( + "type=xyz&url=https://fake.server/%7Bx%7D/%7By%7D/%7Bz%7D.png&zmin=0&zmax=2" + ) parts = md.decodeUri(uri) - self.assertEqual(parts, {'type': 'xyz', 'url': 'https://fake.server/{x}/{y}/{z}.png', 'zmin': '0', 'zmax': '2'}) - - parts['url'] = 'https://fake.new.server/{x}/{y}/{z}.png' + self.assertEqual( + parts, + { + "type": "xyz", + "url": "https://fake.server/{x}/{y}/{z}.png", + "zmin": "0", + "zmax": "2", + }, + ) + + parts["url"] = "https://fake.new.server/{x}/{y}/{z}.png" uri = md.encodeUri(parts) - self.assertEqual(uri, 'type=xyz&url=https://fake.new.server/%7Bx%7D/%7By%7D/%7Bz%7D.png&zmax=2&zmin=0') + self.assertEqual( + uri, + "type=xyz&url=https://fake.new.server/%7Bx%7D/%7By%7D/%7Bz%7D.png&zmax=2&zmin=0", + ) - uri = 'type=xyz&serviceType=arcgis&url=https://fake.server/%7Bx%7D/%7By%7D/%7Bz%7D.png&zmax=2&http-header:referer=https://qgis.org/&styleUrl=https://qgis.org/' + uri = "type=xyz&serviceType=arcgis&url=https://fake.server/%7Bx%7D/%7By%7D/%7Bz%7D.png&zmax=2&http-header:referer=https://qgis.org/&styleUrl=https://qgis.org/" parts = md.decodeUri(uri) - self.assertEqual(parts, {'type': 'xyz', 'serviceType': 'arcgis', 'url': 'https://fake.server/{x}/{y}/{z}.png', - 'zmax': '2', 'http-header:referer': 'https://qgis.org/', - 'referer': 'https://qgis.org/', 'styleUrl': 'https://qgis.org/'}) - - parts['url'] = 'https://fake.new.server/{x}/{y}/{z}.png' + self.assertEqual( + parts, + { + "type": "xyz", + "serviceType": "arcgis", + "url": "https://fake.server/{x}/{y}/{z}.png", + "zmax": "2", + "http-header:referer": "https://qgis.org/", + "referer": "https://qgis.org/", + "styleUrl": "https://qgis.org/", + }, + ) + + parts["url"] = "https://fake.new.server/{x}/{y}/{z}.png" uri = md.encodeUri(parts) - self.assertEqual(uri, - 'serviceType=arcgis&styleUrl=https://qgis.org/&type=xyz&url=https://fake.new.server/%7Bx%7D/%7By%7D/%7Bz%7D.png&zmax=2&http-header:referer=https://qgis.org/') + self.assertEqual( + uri, + "serviceType=arcgis&styleUrl=https://qgis.org/&type=xyz&url=https://fake.new.server/%7Bx%7D/%7By%7D/%7Bz%7D.png&zmax=2&http-header:referer=https://qgis.org/", + ) def testZoomRange(self): """ Test retrieval of zoom range from URI """ vl = QgsVectorTileLayer( - 'type=xyz&url=https://wxs.ign.fr/parcellaire/geoportail/tms/1.0.0/PCI/%7Bz%7D/%7Bx%7D/%7By%7D.pbf&zmax=19&zmin=5', - 'test') + "type=xyz&url=https://wxs.ign.fr/parcellaire/geoportail/tms/1.0.0/PCI/%7Bz%7D/%7Bx%7D/%7By%7D.pbf&zmax=19&zmin=5", + "test", + ) self.assertTrue(vl.isValid()) self.assertEqual(vl.sourceMinZoom(), 5) self.assertEqual(vl.sourceMaxZoom(), 19) def testSelection(self): - layer = QgsVectorTileLayer(f"type=vtpk&url={unitTestDataPath() + '/testvtpk.vtpk'}", 'tiles') + layer = QgsVectorTileLayer( + f"type=vtpk&url={unitTestDataPath() + '/testvtpk.vtpk'}", "tiles" + ) self.assertTrue(layer.isValid()) self.assertFalse(layer.selectedFeatures()) @@ -147,84 +173,148 @@ def testSelection(self): # select by polygon selection_geometry = QgsGeometry.fromWkt( - 'Polygon ((-12225020.2316580843180418 6030602.60334861185401678, -13521860.30317855626344681 5526975.39110779482871294, -12976264.15658413991332054 4821897.29397048708051443, -12019372.45332629978656769 4884850.69550053123384714, -11650045.83101624809205532 4754746.99900492746382952, -11469579.41329662501811981 5535369.17797833122313023, -11792740.20781794004142284 6110343.57862004917114973, -12225020.2316580843180418 6030602.60334861185401678))') + "Polygon ((-12225020.2316580843180418 6030602.60334861185401678, -13521860.30317855626344681 5526975.39110779482871294, -12976264.15658413991332054 4821897.29397048708051443, -12019372.45332629978656769 4884850.69550053123384714, -11650045.83101624809205532 4754746.99900492746382952, -11469579.41329662501811981 5535369.17797833122313023, -11792740.20781794004142284 6110343.57862004917114973, -12225020.2316580843180418 6030602.60334861185401678))" + ) context = QgsSelectionContext() context.setScale(17991708) - layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.SetSelection, - Qgis.SelectGeometryRelationship.Intersect) + layer.selectByGeometry( + selection_geometry, + context, + Qgis.SelectBehavior.SetSelection, + Qgis.SelectGeometryRelationship.Intersect, + ) self.assertEqual(layer.selectedFeatureCount(), 8) - self.assertCountEqual({f.id() for f in layer.selectedFeatures()}, {3320043274240, - 3320026497024, - 2220498092032, - 2224826613760, - 3320043274243, - 2220514869248, - 3324338241541, - 3324338241536}) - self.assertCountEqual({f.geometry().asWkt(-3) for f in layer.selectedFeatures()}, { - 'Polygon ((-13222000 4970000, -13203000 5004000, -13189000 5073000, -13164000 5127000, -13145000 5205000, -13106000 5239000, -13047000 5274000, -12964000 5269000, -12910000 5195000, -12885000 5185000, -12846000 5185000, -12802000 5151000, -12758000 5093000, -12685000 5093000, -12611000 5107000, -12484000 5103000, -12484000 4970000, -13222000 4970000))', - 'MultiPolygon (((-12157000 5694000, -12132000 5738000, -12093000 5782000, -12039000 5817000, -11956000 5836000, -11853000 5836000, -11795000 5792000, -11785000 5763000, -11760000 5738000, -11736000 5621000, -11716000 5587000, -11653000 5528000, -11643000 5503000, -11643000 5366000, -11653000 5337000, -11692000 5278000, -11731000 5249000, -11741000 5239000, -11839000 5205000, -11863000 5220000, -11927000 5288000, -11941000 5440000, -11951000 5450000, -12005000 5450000, -12020000 5450000, -12029000 5435000, -12054000 5435000, -12093000 5450000, -12132000 5503000, -12157000 5518000, -12166000 5543000, -12166000 5650000, -12157000 5694000),(-11995000 5680000, -12015000 5626000, -12005000 5582000, -11990000 5562000, -11927000 5547000, -11907000 5528000, -11883000 5479000, -11863000 5469000, -11829000 5469000, -11809000 5489000, -11814000 5577000, -11863000 5626000, -11912000 5704000, -11966000 5704000, -11995000 5680000)),((-11521000 5773000, -11496000 5851000, -11413000 5900000, -11389000 5890000, -11325000 5787000, -11320000 5724000, -11364000 5645000, -11418000 5640000, -11462000 5655000, -11491000 5699000, -11506000 5709000, -11521000 5773000)))', - 'Polygon ((-12563000 5105000, -12470000 5102000, -12411000 4990000, -12411000 4970000, -12563000 4970000, -12563000 5105000))', - 'Polygon ((-11868000 4750000, -11809000 4882000, -11702000 4956000, -11638000 4956000, -11609000 4916000, -11574000 4892000, -11452000 4882000, -11354000 4833000, -11325000 4794000, -11291000 4765000, -11212000 4638000, -11217000 4579000, -11261000 4486000, -11266000 4432000, -11281000 4393000, -11296000 4383000, -11310000 4339000, -11398000 4300000, -11501000 4305000, -11530000 4320000, -11579000 4359000, -11633000 4427000, -11687000 4466000, -11790000 4515000, -11834000 4569000, -11873000 4652000, -11868000 4750000))', - 'Polygon ((-13228000 4960000, -13203000 5004000, -13194000 5049000, -12484000 5049000, -12484000 4869000, -12587000 4814000, -12631000 4765000, -12641000 4716000, -12680000 4652000, -12714000 4618000, -12837000 4589000, -12900000 4589000, -12944000 4608000, -12949000 4618000, -13027000 4623000, -13062000 4647000, -13135000 4662000, -13189000 4691000, -13228000 4779000, -13238000 4819000, -13238000 4907000, -13228000 4960000))', - 'MultiLineString ((-11662000 5797000, -11633000 5704000, -11589000 5640000, -11398000 5518000, -11325000 5420000, -11276000 5127000, -11247000 5053000, -11208000 4990000, -11207000 4970000),(-11305000 5337000, -11261000 5381000, -11227000 5459000, -11178000 5518000, -11105000 5562000, -11051000 5670000, -10997000 5724000, -10953000 5812000))', - 'Polygon ((-12442000 5049000, -12411000 4990000, -12411000 4956000, -12426000 4916000, -12450000 4887000, -12563000 4827000, -12563000 5049000, -12442000 5049000))', - 'Point (-12714000 5220000)'}) + self.assertCountEqual( + {f.id() for f in layer.selectedFeatures()}, + { + 3320043274240, + 3320026497024, + 2220498092032, + 2224826613760, + 3320043274243, + 2220514869248, + 3324338241541, + 3324338241536, + }, + ) + self.assertCountEqual( + {f.geometry().asWkt(-3) for f in layer.selectedFeatures()}, + { + "Polygon ((-13222000 4970000, -13203000 5004000, -13189000 5073000, -13164000 5127000, -13145000 5205000, -13106000 5239000, -13047000 5274000, -12964000 5269000, -12910000 5195000, -12885000 5185000, -12846000 5185000, -12802000 5151000, -12758000 5093000, -12685000 5093000, -12611000 5107000, -12484000 5103000, -12484000 4970000, -13222000 4970000))", + "MultiPolygon (((-12157000 5694000, -12132000 5738000, -12093000 5782000, -12039000 5817000, -11956000 5836000, -11853000 5836000, -11795000 5792000, -11785000 5763000, -11760000 5738000, -11736000 5621000, -11716000 5587000, -11653000 5528000, -11643000 5503000, -11643000 5366000, -11653000 5337000, -11692000 5278000, -11731000 5249000, -11741000 5239000, -11839000 5205000, -11863000 5220000, -11927000 5288000, -11941000 5440000, -11951000 5450000, -12005000 5450000, -12020000 5450000, -12029000 5435000, -12054000 5435000, -12093000 5450000, -12132000 5503000, -12157000 5518000, -12166000 5543000, -12166000 5650000, -12157000 5694000),(-11995000 5680000, -12015000 5626000, -12005000 5582000, -11990000 5562000, -11927000 5547000, -11907000 5528000, -11883000 5479000, -11863000 5469000, -11829000 5469000, -11809000 5489000, -11814000 5577000, -11863000 5626000, -11912000 5704000, -11966000 5704000, -11995000 5680000)),((-11521000 5773000, -11496000 5851000, -11413000 5900000, -11389000 5890000, -11325000 5787000, -11320000 5724000, -11364000 5645000, -11418000 5640000, -11462000 5655000, -11491000 5699000, -11506000 5709000, -11521000 5773000)))", + "Polygon ((-12563000 5105000, -12470000 5102000, -12411000 4990000, -12411000 4970000, -12563000 4970000, -12563000 5105000))", + "Polygon ((-11868000 4750000, -11809000 4882000, -11702000 4956000, -11638000 4956000, -11609000 4916000, -11574000 4892000, -11452000 4882000, -11354000 4833000, -11325000 4794000, -11291000 4765000, -11212000 4638000, -11217000 4579000, -11261000 4486000, -11266000 4432000, -11281000 4393000, -11296000 4383000, -11310000 4339000, -11398000 4300000, -11501000 4305000, -11530000 4320000, -11579000 4359000, -11633000 4427000, -11687000 4466000, -11790000 4515000, -11834000 4569000, -11873000 4652000, -11868000 4750000))", + "Polygon ((-13228000 4960000, -13203000 5004000, -13194000 5049000, -12484000 5049000, -12484000 4869000, -12587000 4814000, -12631000 4765000, -12641000 4716000, -12680000 4652000, -12714000 4618000, -12837000 4589000, -12900000 4589000, -12944000 4608000, -12949000 4618000, -13027000 4623000, -13062000 4647000, -13135000 4662000, -13189000 4691000, -13228000 4779000, -13238000 4819000, -13238000 4907000, -13228000 4960000))", + "MultiLineString ((-11662000 5797000, -11633000 5704000, -11589000 5640000, -11398000 5518000, -11325000 5420000, -11276000 5127000, -11247000 5053000, -11208000 4990000, -11207000 4970000),(-11305000 5337000, -11261000 5381000, -11227000 5459000, -11178000 5518000, -11105000 5562000, -11051000 5670000, -10997000 5724000, -10953000 5812000))", + "Polygon ((-12442000 5049000, -12411000 4990000, -12411000 4956000, -12426000 4916000, -12450000 4887000, -12563000 4827000, -12563000 5049000, -12442000 5049000))", + "Point (-12714000 5220000)", + }, + ) self.assertEqual(len(spy), 1) - self.assertNotEqual(layer.selectedFeatures()[0].fields().lookupField('tile_zoom'), -1) - self.assertNotEqual(layer.selectedFeatures()[0].fields().lookupField('tile_layer'), -1) - self.assertEqual(layer.selectedFeatures()[0]['tile_zoom'], 4) - self.assertCountEqual([f['tile_layer'] for f in layer.selectedFeatures()], ['polys', 'polys', 'polys', 'lines', 'points', 'polys', 'polys', 'polys']) + self.assertNotEqual( + layer.selectedFeatures()[0].fields().lookupField("tile_zoom"), -1 + ) + self.assertNotEqual( + layer.selectedFeatures()[0].fields().lookupField("tile_layer"), -1 + ) + self.assertEqual(layer.selectedFeatures()[0]["tile_zoom"], 4) + self.assertCountEqual( + [f["tile_layer"] for f in layer.selectedFeatures()], + ["polys", "polys", "polys", "lines", "points", "polys", "polys", "polys"], + ) # select same again, should be no new signal - layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.SetSelection, - Qgis.SelectGeometryRelationship.Intersect) + layer.selectByGeometry( + selection_geometry, + context, + Qgis.SelectBehavior.SetSelection, + Qgis.SelectGeometryRelationship.Intersect, + ) self.assertEqual(len(spy), 1) # select within - layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.SetSelection, - Qgis.SelectGeometryRelationship.Within) + layer.selectByGeometry( + selection_geometry, + context, + Qgis.SelectBehavior.SetSelection, + Qgis.SelectGeometryRelationship.Within, + ) self.assertEqual(len(spy), 2) - self.assertCountEqual({f.id() for f in layer.selectedFeatures()}, {2220498092032, 3320043274243}) - self.assertCountEqual({f.geometry().asWkt(-3) for f in layer.selectedFeatures()}, - {'Point (-12714000 5220000)', - 'Polygon ((-12563000 5105000, -12470000 5102000, -12411000 4990000, -12411000 4970000, -12563000 4970000, -12563000 5105000))'}) + self.assertCountEqual( + {f.id() for f in layer.selectedFeatures()}, {2220498092032, 3320043274243} + ) + self.assertCountEqual( + {f.geometry().asWkt(-3) for f in layer.selectedFeatures()}, + { + "Point (-12714000 5220000)", + "Polygon ((-12563000 5105000, -12470000 5102000, -12411000 4990000, -12411000 4970000, -12563000 4970000, -12563000 5105000))", + }, + ) # add to selection selection_geometry = QgsGeometry.fromWkt( - 'Polygon ((-11104449.68442200869321823 6041094.83693683333694935, -11461185.62642602622509003 5822856.37829908169806004, -11054086.96319791302084923 5419954.60850630886852741, -10793879.57020674645900726 5835447.05860510468482971, -11104449.68442200869321823 6041094.83693683333694935))') - layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.AddToSelection, - Qgis.SelectGeometryRelationship.Intersect) + "Polygon ((-11104449.68442200869321823 6041094.83693683333694935, -11461185.62642602622509003 5822856.37829908169806004, -11054086.96319791302084923 5419954.60850630886852741, -10793879.57020674645900726 5835447.05860510468482971, -11104449.68442200869321823 6041094.83693683333694935))" + ) + layer.selectByGeometry( + selection_geometry, + context, + Qgis.SelectBehavior.AddToSelection, + Qgis.SelectGeometryRelationship.Intersect, + ) self.assertEqual(len(spy), 3) - self.assertCountEqual({f.id() for f in layer.selectedFeatures()}, - {2220498092032, 3320043274243, 3320043274240, 3320026497024}) - self.assertCountEqual({f.geometry().asWkt(-3) for f in layer.selectedFeatures()}, - { - 'Polygon ((-12563000 5105000, -12470000 5102000, -12411000 4990000, -12411000 4970000, -12563000 4970000, -12563000 5105000))', - 'MultiLineString ((-11662000 5797000, -11633000 5704000, -11589000 5640000, -11398000 5518000, -11325000 5420000, -11276000 5127000, -11247000 5053000, -11208000 4990000, -11207000 4970000),(-11305000 5337000, -11261000 5381000, -11227000 5459000, -11178000 5518000, -11105000 5562000, -11051000 5670000, -10997000 5724000, -10953000 5812000))', - 'Point (-12714000 5220000)', - 'MultiPolygon (((-12157000 5694000, -12132000 5738000, -12093000 5782000, -12039000 5817000, -11956000 5836000, -11853000 5836000, -11795000 5792000, -11785000 5763000, -11760000 5738000, -11736000 5621000, -11716000 5587000, -11653000 5528000, -11643000 5503000, -11643000 5366000, -11653000 5337000, -11692000 5278000, -11731000 5249000, -11741000 5239000, -11839000 5205000, -11863000 5220000, -11927000 5288000, -11941000 5440000, -11951000 5450000, -12005000 5450000, -12020000 5450000, -12029000 5435000, -12054000 5435000, -12093000 5450000, -12132000 5503000, -12157000 5518000, -12166000 5543000, -12166000 5650000, -12157000 5694000),(-11995000 5680000, -12015000 5626000, -12005000 5582000, -11990000 5562000, -11927000 5547000, -11907000 5528000, -11883000 5479000, -11863000 5469000, -11829000 5469000, -11809000 5489000, -11814000 5577000, -11863000 5626000, -11912000 5704000, -11966000 5704000, -11995000 5680000)),((-11521000 5773000, -11496000 5851000, -11413000 5900000, -11389000 5890000, -11325000 5787000, -11320000 5724000, -11364000 5645000, -11418000 5640000, -11462000 5655000, -11491000 5699000, -11506000 5709000, -11521000 5773000)))'}) + self.assertCountEqual( + {f.id() for f in layer.selectedFeatures()}, + {2220498092032, 3320043274243, 3320043274240, 3320026497024}, + ) + self.assertCountEqual( + {f.geometry().asWkt(-3) for f in layer.selectedFeatures()}, + { + "Polygon ((-12563000 5105000, -12470000 5102000, -12411000 4990000, -12411000 4970000, -12563000 4970000, -12563000 5105000))", + "MultiLineString ((-11662000 5797000, -11633000 5704000, -11589000 5640000, -11398000 5518000, -11325000 5420000, -11276000 5127000, -11247000 5053000, -11208000 4990000, -11207000 4970000),(-11305000 5337000, -11261000 5381000, -11227000 5459000, -11178000 5518000, -11105000 5562000, -11051000 5670000, -10997000 5724000, -10953000 5812000))", + "Point (-12714000 5220000)", + "MultiPolygon (((-12157000 5694000, -12132000 5738000, -12093000 5782000, -12039000 5817000, -11956000 5836000, -11853000 5836000, -11795000 5792000, -11785000 5763000, -11760000 5738000, -11736000 5621000, -11716000 5587000, -11653000 5528000, -11643000 5503000, -11643000 5366000, -11653000 5337000, -11692000 5278000, -11731000 5249000, -11741000 5239000, -11839000 5205000, -11863000 5220000, -11927000 5288000, -11941000 5440000, -11951000 5450000, -12005000 5450000, -12020000 5450000, -12029000 5435000, -12054000 5435000, -12093000 5450000, -12132000 5503000, -12157000 5518000, -12166000 5543000, -12166000 5650000, -12157000 5694000),(-11995000 5680000, -12015000 5626000, -12005000 5582000, -11990000 5562000, -11927000 5547000, -11907000 5528000, -11883000 5479000, -11863000 5469000, -11829000 5469000, -11809000 5489000, -11814000 5577000, -11863000 5626000, -11912000 5704000, -11966000 5704000, -11995000 5680000)),((-11521000 5773000, -11496000 5851000, -11413000 5900000, -11389000 5890000, -11325000 5787000, -11320000 5724000, -11364000 5645000, -11418000 5640000, -11462000 5655000, -11491000 5699000, -11506000 5709000, -11521000 5773000)))", + }, + ) # remove from selection - layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.RemoveFromSelection, - Qgis.SelectGeometryRelationship.Intersect) + layer.selectByGeometry( + selection_geometry, + context, + Qgis.SelectBehavior.RemoveFromSelection, + Qgis.SelectGeometryRelationship.Intersect, + ) self.assertEqual(len(spy), 4) - self.assertCountEqual({f.id() for f in layer.selectedFeatures()}, {2220498092032, 3320043274243}) - self.assertCountEqual({f.geometry().asWkt(-3) for f in layer.selectedFeatures()}, - {'Point (-12714000 5220000)', - 'Polygon ((-12563000 5105000, -12470000 5102000, -12411000 4990000, -12411000 4970000, -12563000 4970000, -12563000 5105000))'}) + self.assertCountEqual( + {f.id() for f in layer.selectedFeatures()}, {2220498092032, 3320043274243} + ) + self.assertCountEqual( + {f.geometry().asWkt(-3) for f in layer.selectedFeatures()}, + { + "Point (-12714000 5220000)", + "Polygon ((-12563000 5105000, -12470000 5102000, -12411000 4990000, -12411000 4970000, -12563000 4970000, -12563000 5105000))", + }, + ) # intersect selection selection_geometry = QgsGeometry.fromWkt( - 'Polygon ((-12632118.89488627389073372 5457726.64942438062280416, -12862948.03383005037903786 5310835.37918743211776018, -12850357.35352402552962303 5046431.09276092518121004, -12716056.76359310187399387 4987674.58466614596545696, -12434864.90342522785067558 5113581.38772638700902462, -12632118.89488627389073372 5457726.64942438062280416))') - - layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.IntersectSelection, - Qgis.SelectGeometryRelationship.Within) + "Polygon ((-12632118.89488627389073372 5457726.64942438062280416, -12862948.03383005037903786 5310835.37918743211776018, -12850357.35352402552962303 5046431.09276092518121004, -12716056.76359310187399387 4987674.58466614596545696, -12434864.90342522785067558 5113581.38772638700902462, -12632118.89488627389073372 5457726.64942438062280416))" + ) + + layer.selectByGeometry( + selection_geometry, + context, + Qgis.SelectBehavior.IntersectSelection, + Qgis.SelectGeometryRelationship.Within, + ) self.assertEqual(len(spy), 5) - self.assertCountEqual({f.id() for f in layer.selectedFeatures()}, {2220498092032}) - self.assertCountEqual({f.geometry().asWkt(-3) for f in layer.selectedFeatures()}, - {'Point (-12714000 5220000)'}) + self.assertCountEqual( + {f.id() for f in layer.selectedFeatures()}, {2220498092032} + ) + self.assertCountEqual( + {f.geometry().asWkt(-3) for f in layer.selectedFeatures()}, + {"Point (-12714000 5220000)"}, + ) layer.removeSelection() self.assertFalse(layer.selectedFeatures()) @@ -236,69 +326,126 @@ def testSelection(self): # selection should depend on tile scale selection_geometry = QgsGeometry.fromWkt( - 'Polygon ((-12225020.2316580843180418 6030602.60334861185401678, -13521860.30317855626344681 5526975.39110779482871294, -12976264.15658413991332054 4821897.29397048708051443, -12019372.45332629978656769 4884850.69550053123384714, -11650045.83101624809205532 4754746.99900492746382952, -11469579.41329662501811981 5535369.17797833122313023, -11792740.20781794004142284 6110343.57862004917114973, -12225020.2316580843180418 6030602.60334861185401678))') + "Polygon ((-12225020.2316580843180418 6030602.60334861185401678, -13521860.30317855626344681 5526975.39110779482871294, -12976264.15658413991332054 4821897.29397048708051443, -12019372.45332629978656769 4884850.69550053123384714, -11650045.83101624809205532 4754746.99900492746382952, -11469579.41329662501811981 5535369.17797833122313023, -11792740.20781794004142284 6110343.57862004917114973, -12225020.2316580843180418 6030602.60334861185401678))" + ) context = QgsSelectionContext() context.setScale(137882080) - layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.SetSelection, - Qgis.SelectGeometryRelationship.Intersect) + layer.selectByGeometry( + selection_geometry, + context, + Qgis.SelectBehavior.SetSelection, + Qgis.SelectGeometryRelationship.Intersect, + ) self.assertEqual(len(layer.selectedFeatures()), 5) - self.assertCountEqual({f.id() for f in layer.selectedFeatures()}, - {33554432, 16777216, 0, 33554433, 33554438}) - self.assertCountEqual({f.geometry().asWkt(-3) for f in layer.selectedFeatures()}, { - 'MultiPolygon (((-12152000 5694000, -12132000 5733000, -12093000 5792000, -12034000 5812000, -11956000 5831000, -11858000 5831000, -11799000 5792000, -11780000 5773000, -11760000 5733000, -11741000 5616000, -11721000 5596000, -11662000 5538000, -11643000 5499000, -11643000 5362000, -11662000 5342000, -11682000 5283000, -11721000 5244000, -11741000 5244000, -11839000 5205000, -11858000 5225000, -11917000 5283000, -11936000 5440000, -11956000 5459000, -11995000 5459000, -12015000 5459000, -12034000 5440000, -12054000 5440000, -12093000 5459000, -12132000 5499000, -12152000 5518000, -12171000 5538000, -12171000 5655000, -12152000 5694000),(-11995000 5675000, -12015000 5636000, -11995000 5577000, -11995000 5557000, -11917000 5557000, -11917000 5538000, -11878000 5479000, -11858000 5479000, -11839000 5479000, -11799000 5499000, -11819000 5577000, -11858000 5636000, -11917000 5714000, -11956000 5714000, -11995000 5675000)),((-11525000 5773000, -11486000 5851000, -11408000 5909000, -11389000 5890000, -11330000 5792000, -11310000 5733000, -11369000 5655000, -11408000 5636000, -11467000 5655000, -11486000 5694000, -11506000 5714000, -11525000 5773000)))', - 'MultiPoint ((-13052000 4471000),(-9275000 4016000),(-12201000 4261000),(-10885000 4143000),(-9828000 3992000),(-9534000 4711000),(-10371000 4965000),(-11403000 5049000),(-12499000 4775000),(-11501000 2607000),(-11452000 3703000),(-11085000 4951000),(-10493000 5919000),(-12714000 5220000),(-12607000 4290000),(-12249000 3703000),(-11687000 3331000))', - 'MultiLineString ((-13091000 4188000, -13032000 4207000, -12974000 4285000, -12915000 4364000, -12778000 4442000, -12621000 4501000, -12445000 4481000, -12367000 4461000, -12328000 4461000, -12191000 4403000, -12113000 4344000, -11995000 4285000, -11858000 4285000, -11760000 4246000, -11467000 4227000, -11291000 4227000, -11173000 4285000, -11134000 4305000, -11017000 4305000, -10821000 4246000, -10645000 4246000, -10508000 4285000, -10430000 4344000, -10351000 4422000, -10195000 4520000, -10058000 4559000, -10058000 4579000, -9960000 4559000, -9921000 4540000, -9843000 4520000, -9745000 4461000, -9706000 4442000, -9549000 4422000, -9353000 4442000, -9236000 4520000, -9197000 4520000),(-12347000 4461000, -12367000 4403000, -12406000 4325000, -12426000 4305000, -12445000 4266000, -12465000 4207000, -12504000 4148000, -12621000 4109000, -12758000 4109000, -12797000 4090000, -12817000 4051000, -12856000 3992000, -12856000 3914000, -12856000 3816000, -12837000 3796000, -12797000 3777000),(-11662000 5792000, -11623000 5714000, -11584000 5636000, -11408000 5518000, -11330000 5420000, -11271000 5127000, -11252000 5049000, -11212000 4990000, -11193000 4872000, -11193000 4833000, -11193000 4814000, -11154000 4775000, -11056000 4696000, -11036000 4638000, -11075000 4559000, -11115000 4520000, -11134000 4442000, -11134000 4422000, -11056000 4227000, -11075000 4168000, -11095000 4148000, -11134000 4090000, -11134000 4031000, -11173000 3992000, -11212000 3914000, -11212000 3816000, -11193000 3757000, -11115000 3659000, -11075000 3542000, -11017000 3503000, -10978000 3444000, -10899000 3366000, -10860000 3327000, -10684000 3190000, -10664000 3150000, -10645000 3131000, -10645000 3053000, -10704000 2974000, -10723000 2955000, -10723000 2896000, -10704000 2818000, -10606000 2700000, -10528000 2661000),(-11310000 5342000, -11252000 5381000, -11232000 5459000, -11173000 5518000, -11115000 5557000, -11056000 5675000, -10997000 5733000, -10958000 5812000),(-10273000 4461000, -10254000 4364000, -10234000 4364000, -10214000 4344000, -10175000 4305000, -10097000 4305000, -10058000 4285000, -10038000 4227000, -10019000 4129000, -10019000 4109000, -9999000 4070000, -9921000 3953000, -9901000 3953000, -9804000 3933000, -9745000 3914000, -9706000 3835000, -9686000 3816000, -9627000 3796000, -9549000 3777000, -9530000 3757000, -9432000 3698000, -9353000 3679000, -9314000 3600000, -9256000 3561000),(-9843000 4520000, -9843000 4579000, -9823000 4598000, -9725000 4716000, -9725000 4735000, -9706000 4814000, -9647000 4912000, -9549000 5029000, -9530000 5146000, -9393000 5440000, -9314000 5479000, -9158000 5499000))', - 'Polygon ((-11858000 4755000, -11799000 4892000, -11702000 4951000, -11643000 4951000, -11604000 4912000, -11565000 4892000, -11447000 4892000, -11349000 4833000, -11330000 4794000, -11291000 4775000, -11212000 4638000, -11212000 4579000, -11252000 4481000, -11271000 4442000, -11271000 4403000, -11291000 4383000, -11310000 4344000, -11408000 4305000, -11506000 4305000, -11525000 4325000, -11584000 4364000, -11623000 4422000, -11682000 4461000, -11780000 4520000, -11839000 4579000, -11878000 4657000, -11858000 4755000))', - 'Polygon ((-13228000 4970000, -13208000 5009000, -13189000 5068000, -13169000 5127000, -13150000 5205000, -13110000 5244000, -13052000 5283000, -12954000 5264000, -12915000 5205000, -12876000 5185000, -12856000 5185000, -12797000 5146000, -12758000 5088000, -12680000 5088000, -12602000 5107000, -12465000 5107000, -12406000 4990000, -12406000 4951000, -12426000 4912000, -12445000 4892000, -12582000 4814000, -12621000 4775000, -12641000 4716000, -12680000 4657000, -12719000 4618000, -12837000 4598000, -12895000 4598000, -12934000 4618000, -12954000 4618000, -13032000 4618000, -13052000 4657000, -13130000 4657000, -13189000 4696000, -13228000 4775000, -13228000 4814000, -13228000 4912000, -13228000 4970000))'}) + self.assertCountEqual( + {f.id() for f in layer.selectedFeatures()}, + {33554432, 16777216, 0, 33554433, 33554438}, + ) + self.assertCountEqual( + {f.geometry().asWkt(-3) for f in layer.selectedFeatures()}, + { + "MultiPolygon (((-12152000 5694000, -12132000 5733000, -12093000 5792000, -12034000 5812000, -11956000 5831000, -11858000 5831000, -11799000 5792000, -11780000 5773000, -11760000 5733000, -11741000 5616000, -11721000 5596000, -11662000 5538000, -11643000 5499000, -11643000 5362000, -11662000 5342000, -11682000 5283000, -11721000 5244000, -11741000 5244000, -11839000 5205000, -11858000 5225000, -11917000 5283000, -11936000 5440000, -11956000 5459000, -11995000 5459000, -12015000 5459000, -12034000 5440000, -12054000 5440000, -12093000 5459000, -12132000 5499000, -12152000 5518000, -12171000 5538000, -12171000 5655000, -12152000 5694000),(-11995000 5675000, -12015000 5636000, -11995000 5577000, -11995000 5557000, -11917000 5557000, -11917000 5538000, -11878000 5479000, -11858000 5479000, -11839000 5479000, -11799000 5499000, -11819000 5577000, -11858000 5636000, -11917000 5714000, -11956000 5714000, -11995000 5675000)),((-11525000 5773000, -11486000 5851000, -11408000 5909000, -11389000 5890000, -11330000 5792000, -11310000 5733000, -11369000 5655000, -11408000 5636000, -11467000 5655000, -11486000 5694000, -11506000 5714000, -11525000 5773000)))", + "MultiPoint ((-13052000 4471000),(-9275000 4016000),(-12201000 4261000),(-10885000 4143000),(-9828000 3992000),(-9534000 4711000),(-10371000 4965000),(-11403000 5049000),(-12499000 4775000),(-11501000 2607000),(-11452000 3703000),(-11085000 4951000),(-10493000 5919000),(-12714000 5220000),(-12607000 4290000),(-12249000 3703000),(-11687000 3331000))", + "MultiLineString ((-13091000 4188000, -13032000 4207000, -12974000 4285000, -12915000 4364000, -12778000 4442000, -12621000 4501000, -12445000 4481000, -12367000 4461000, -12328000 4461000, -12191000 4403000, -12113000 4344000, -11995000 4285000, -11858000 4285000, -11760000 4246000, -11467000 4227000, -11291000 4227000, -11173000 4285000, -11134000 4305000, -11017000 4305000, -10821000 4246000, -10645000 4246000, -10508000 4285000, -10430000 4344000, -10351000 4422000, -10195000 4520000, -10058000 4559000, -10058000 4579000, -9960000 4559000, -9921000 4540000, -9843000 4520000, -9745000 4461000, -9706000 4442000, -9549000 4422000, -9353000 4442000, -9236000 4520000, -9197000 4520000),(-12347000 4461000, -12367000 4403000, -12406000 4325000, -12426000 4305000, -12445000 4266000, -12465000 4207000, -12504000 4148000, -12621000 4109000, -12758000 4109000, -12797000 4090000, -12817000 4051000, -12856000 3992000, -12856000 3914000, -12856000 3816000, -12837000 3796000, -12797000 3777000),(-11662000 5792000, -11623000 5714000, -11584000 5636000, -11408000 5518000, -11330000 5420000, -11271000 5127000, -11252000 5049000, -11212000 4990000, -11193000 4872000, -11193000 4833000, -11193000 4814000, -11154000 4775000, -11056000 4696000, -11036000 4638000, -11075000 4559000, -11115000 4520000, -11134000 4442000, -11134000 4422000, -11056000 4227000, -11075000 4168000, -11095000 4148000, -11134000 4090000, -11134000 4031000, -11173000 3992000, -11212000 3914000, -11212000 3816000, -11193000 3757000, -11115000 3659000, -11075000 3542000, -11017000 3503000, -10978000 3444000, -10899000 3366000, -10860000 3327000, -10684000 3190000, -10664000 3150000, -10645000 3131000, -10645000 3053000, -10704000 2974000, -10723000 2955000, -10723000 2896000, -10704000 2818000, -10606000 2700000, -10528000 2661000),(-11310000 5342000, -11252000 5381000, -11232000 5459000, -11173000 5518000, -11115000 5557000, -11056000 5675000, -10997000 5733000, -10958000 5812000),(-10273000 4461000, -10254000 4364000, -10234000 4364000, -10214000 4344000, -10175000 4305000, -10097000 4305000, -10058000 4285000, -10038000 4227000, -10019000 4129000, -10019000 4109000, -9999000 4070000, -9921000 3953000, -9901000 3953000, -9804000 3933000, -9745000 3914000, -9706000 3835000, -9686000 3816000, -9627000 3796000, -9549000 3777000, -9530000 3757000, -9432000 3698000, -9353000 3679000, -9314000 3600000, -9256000 3561000),(-9843000 4520000, -9843000 4579000, -9823000 4598000, -9725000 4716000, -9725000 4735000, -9706000 4814000, -9647000 4912000, -9549000 5029000, -9530000 5146000, -9393000 5440000, -9314000 5479000, -9158000 5499000))", + "Polygon ((-11858000 4755000, -11799000 4892000, -11702000 4951000, -11643000 4951000, -11604000 4912000, -11565000 4892000, -11447000 4892000, -11349000 4833000, -11330000 4794000, -11291000 4775000, -11212000 4638000, -11212000 4579000, -11252000 4481000, -11271000 4442000, -11271000 4403000, -11291000 4383000, -11310000 4344000, -11408000 4305000, -11506000 4305000, -11525000 4325000, -11584000 4364000, -11623000 4422000, -11682000 4461000, -11780000 4520000, -11839000 4579000, -11878000 4657000, -11858000 4755000))", + "Polygon ((-13228000 4970000, -13208000 5009000, -13189000 5068000, -13169000 5127000, -13150000 5205000, -13110000 5244000, -13052000 5283000, -12954000 5264000, -12915000 5205000, -12876000 5185000, -12856000 5185000, -12797000 5146000, -12758000 5088000, -12680000 5088000, -12602000 5107000, -12465000 5107000, -12406000 4990000, -12406000 4951000, -12426000 4912000, -12445000 4892000, -12582000 4814000, -12621000 4775000, -12641000 4716000, -12680000 4657000, -12719000 4618000, -12837000 4598000, -12895000 4598000, -12934000 4618000, -12954000 4618000, -13032000 4618000, -13052000 4657000, -13130000 4657000, -13189000 4696000, -13228000 4775000, -13228000 4814000, -13228000 4912000, -13228000 4970000))", + }, + ) self.assertEqual(len(spy), 7) # removing features should NOT depend on the scale context.setScale(237882080) - layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.RemoveFromSelection, - Qgis.SelectGeometryRelationship.Intersect) + layer.selectByGeometry( + selection_geometry, + context, + Qgis.SelectBehavior.RemoveFromSelection, + Qgis.SelectGeometryRelationship.Intersect, + ) self.assertFalse(layer.selectedFeatures()) self.assertEqual(len(spy), 8) # single feature selection - selection_geometry = QgsGeometry.fromWkt('Polygon ((-10486370.9139375202357769 3807467.1023839432746172, -10528246.57568679377436638 3799853.34570225700736046, -10490177.79227836430072784 3735136.41390792420133948, -10486370.9139375202357769 3807467.1023839432746172))') - layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.SetSelection, - Qgis.SelectGeometryRelationship.Intersect, Qgis.SelectionFlags(Qgis.SelectionFlag.SingleFeatureSelection)) + selection_geometry = QgsGeometry.fromWkt( + "Polygon ((-10486370.9139375202357769 3807467.1023839432746172, -10528246.57568679377436638 3799853.34570225700736046, -10490177.79227836430072784 3735136.41390792420133948, -10486370.9139375202357769 3807467.1023839432746172))" + ) + layer.selectByGeometry( + selection_geometry, + context, + Qgis.SelectBehavior.SetSelection, + Qgis.SelectGeometryRelationship.Intersect, + Qgis.SelectionFlags(Qgis.SelectionFlag.SingleFeatureSelection), + ) self.assertEqual(len(layer.selectedFeatures()), 1) - self.assertCountEqual({f.id() for f in layer.selectedFeatures()}, - {33554436}) - - self.assertCountEqual({f.geometry().asWkt(-3) for f in layer.selectedFeatures()}, {'Polygon ((-10958000 3835000, -10958000 3796000, -10919000 3835000, -10841000 3874000, -10684000 3992000, -10567000 4031000, -10410000 4031000, -10332000 3992000, -10254000 3914000, -10136000 3914000, -10058000 3874000, -10019000 3796000, -10019000 3757000, -10058000 3718000, -10097000 3718000, -10254000 3796000, -10332000 3796000, -10371000 3757000, -10371000 3718000, -10371000 3679000, -10332000 3640000, -10332000 3561000, -10410000 3483000, -10449000 3405000, -10488000 3366000, -10645000 3327000, -10723000 3366000, -10762000 3405000, -10801000 3444000, -10762000 3483000, -10801000 3522000, -10841000 3561000, -10919000 3561000, -10958000 3600000, -10958000 3640000, -10958000 3679000, -10958000 3718000, -10997000 3796000, -10958000 3835000))'}) + self.assertCountEqual({f.id() for f in layer.selectedFeatures()}, {33554436}) + + self.assertCountEqual( + {f.geometry().asWkt(-3) for f in layer.selectedFeatures()}, + { + "Polygon ((-10958000 3835000, -10958000 3796000, -10919000 3835000, -10841000 3874000, -10684000 3992000, -10567000 4031000, -10410000 4031000, -10332000 3992000, -10254000 3914000, -10136000 3914000, -10058000 3874000, -10019000 3796000, -10019000 3757000, -10058000 3718000, -10097000 3718000, -10254000 3796000, -10332000 3796000, -10371000 3757000, -10371000 3718000, -10371000 3679000, -10332000 3640000, -10332000 3561000, -10410000 3483000, -10449000 3405000, -10488000 3366000, -10645000 3327000, -10723000 3366000, -10762000 3405000, -10801000 3444000, -10762000 3483000, -10801000 3522000, -10841000 3561000, -10919000 3561000, -10958000 3600000, -10958000 3640000, -10958000 3679000, -10958000 3718000, -10997000 3796000, -10958000 3835000))" + }, + ) self.assertEqual(len(spy), 9) # select again - layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.SetSelection, - Qgis.SelectGeometryRelationship.Intersect, Qgis.SelectionFlags(Qgis.SelectionFlag.SingleFeatureSelection)) + layer.selectByGeometry( + selection_geometry, + context, + Qgis.SelectBehavior.SetSelection, + Qgis.SelectGeometryRelationship.Intersect, + Qgis.SelectionFlags(Qgis.SelectionFlag.SingleFeatureSelection), + ) self.assertEqual(len(layer.selectedFeatures()), 1) - self.assertCountEqual({f.id() for f in layer.selectedFeatures()}, - {33554436}) - - self.assertCountEqual({f.geometry().asWkt(-3) for f in layer.selectedFeatures()}, {'Polygon ((-10958000 3835000, -10958000 3796000, -10919000 3835000, -10841000 3874000, -10684000 3992000, -10567000 4031000, -10410000 4031000, -10332000 3992000, -10254000 3914000, -10136000 3914000, -10058000 3874000, -10019000 3796000, -10019000 3757000, -10058000 3718000, -10097000 3718000, -10254000 3796000, -10332000 3796000, -10371000 3757000, -10371000 3718000, -10371000 3679000, -10332000 3640000, -10332000 3561000, -10410000 3483000, -10449000 3405000, -10488000 3366000, -10645000 3327000, -10723000 3366000, -10762000 3405000, -10801000 3444000, -10762000 3483000, -10801000 3522000, -10841000 3561000, -10919000 3561000, -10958000 3600000, -10958000 3640000, -10958000 3679000, -10958000 3718000, -10997000 3796000, -10958000 3835000))'}) + self.assertCountEqual({f.id() for f in layer.selectedFeatures()}, {33554436}) + + self.assertCountEqual( + {f.geometry().asWkt(-3) for f in layer.selectedFeatures()}, + { + "Polygon ((-10958000 3835000, -10958000 3796000, -10919000 3835000, -10841000 3874000, -10684000 3992000, -10567000 4031000, -10410000 4031000, -10332000 3992000, -10254000 3914000, -10136000 3914000, -10058000 3874000, -10019000 3796000, -10019000 3757000, -10058000 3718000, -10097000 3718000, -10254000 3796000, -10332000 3796000, -10371000 3757000, -10371000 3718000, -10371000 3679000, -10332000 3640000, -10332000 3561000, -10410000 3483000, -10449000 3405000, -10488000 3366000, -10645000 3327000, -10723000 3366000, -10762000 3405000, -10801000 3444000, -10762000 3483000, -10801000 3522000, -10841000 3561000, -10919000 3561000, -10958000 3600000, -10958000 3640000, -10958000 3679000, -10958000 3718000, -10997000 3796000, -10958000 3835000))" + }, + ) self.assertEqual(len(spy), 9) # with toggle mode - layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.SetSelection, - Qgis.SelectGeometryRelationship.Intersect, Qgis.SelectionFlags(Qgis.SelectionFlag.SingleFeatureSelection | Qgis.SelectionFlag.ToggleSelection)) + layer.selectByGeometry( + selection_geometry, + context, + Qgis.SelectBehavior.SetSelection, + Qgis.SelectGeometryRelationship.Intersect, + Qgis.SelectionFlags( + Qgis.SelectionFlag.SingleFeatureSelection + | Qgis.SelectionFlag.ToggleSelection + ), + ) self.assertFalse(layer.selectedFeatures()) self.assertEqual(len(spy), 10) - layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.SetSelection, - Qgis.SelectGeometryRelationship.Intersect, Qgis.SelectionFlags(Qgis.SelectionFlag.SingleFeatureSelection | Qgis.SelectionFlag.ToggleSelection)) + layer.selectByGeometry( + selection_geometry, + context, + Qgis.SelectBehavior.SetSelection, + Qgis.SelectGeometryRelationship.Intersect, + Qgis.SelectionFlags( + Qgis.SelectionFlag.SingleFeatureSelection + | Qgis.SelectionFlag.ToggleSelection + ), + ) self.assertEqual(len(layer.selectedFeatures()), 1) - self.assertCountEqual({f.id() for f in layer.selectedFeatures()}, - {33554436}) - - self.assertCountEqual({f.geometry().asWkt(-3) for f in layer.selectedFeatures()}, {'Polygon ((-10958000 3835000, -10958000 3796000, -10919000 3835000, -10841000 3874000, -10684000 3992000, -10567000 4031000, -10410000 4031000, -10332000 3992000, -10254000 3914000, -10136000 3914000, -10058000 3874000, -10019000 3796000, -10019000 3757000, -10058000 3718000, -10097000 3718000, -10254000 3796000, -10332000 3796000, -10371000 3757000, -10371000 3718000, -10371000 3679000, -10332000 3640000, -10332000 3561000, -10410000 3483000, -10449000 3405000, -10488000 3366000, -10645000 3327000, -10723000 3366000, -10762000 3405000, -10801000 3444000, -10762000 3483000, -10801000 3522000, -10841000 3561000, -10919000 3561000, -10958000 3600000, -10958000 3640000, -10958000 3679000, -10958000 3718000, -10997000 3796000, -10958000 3835000))'}) + self.assertCountEqual({f.id() for f in layer.selectedFeatures()}, {33554436}) + + self.assertCountEqual( + {f.geometry().asWkt(-3) for f in layer.selectedFeatures()}, + { + "Polygon ((-10958000 3835000, -10958000 3796000, -10919000 3835000, -10841000 3874000, -10684000 3992000, -10567000 4031000, -10410000 4031000, -10332000 3992000, -10254000 3914000, -10136000 3914000, -10058000 3874000, -10019000 3796000, -10019000 3757000, -10058000 3718000, -10097000 3718000, -10254000 3796000, -10332000 3796000, -10371000 3757000, -10371000 3718000, -10371000 3679000, -10332000 3640000, -10332000 3561000, -10410000 3483000, -10449000 3405000, -10488000 3366000, -10645000 3327000, -10723000 3366000, -10762000 3405000, -10801000 3444000, -10762000 3483000, -10801000 3522000, -10841000 3561000, -10919000 3561000, -10958000 3600000, -10958000 3640000, -10958000 3679000, -10958000 3718000, -10997000 3796000, -10958000 3835000))" + }, + ) self.assertEqual(len(spy), 11) def test_force_raster_render(self): - layer = QgsVectorTileLayer(f"type=vtpk&url={unitTestDataPath() + '/testvtpk.vtpk'}", 'tiles') + layer = QgsVectorTileLayer( + f"type=vtpk&url={unitTestDataPath() + '/testvtpk.vtpk'}", "tiles" + ) self.assertTrue(layer.isValid()) settings = QgsMapSettings() rc = QgsRenderContext.fromMapSettings(settings) @@ -317,5 +464,5 @@ def test_force_raster_render(self): self.assertTrue(renderer.forceRasterRender()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvectorwarper.py b/tests/src/python/test_qgsvectorwarper.py index c7a9d501f8af..ef46a75697ff 100644 --- a/tests/src/python/test_qgsvectorwarper.py +++ b/tests/src/python/test_qgsvectorwarper.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '01/03/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "01/03/2022" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.analysis import ( @@ -34,8 +35,9 @@ class TestQgsVectorWarper(QgisTestCase): def testWarper(self): # create source layer - source_layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", - "addfeat", "memory") + source_layer = QgsVectorLayer( + "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory" + ) pr = source_layer.dataProvider() f = QgsFeature() f.setAttributes(["test", 123]) @@ -57,32 +59,64 @@ def testWarper(self): # create sink sink = QgsFeatureStore() - warper = QgsVectorWarper(QgsGcpTransformerInterface.TransformMethod.PolynomialOrder1, - [ - QgsGcpPoint(QgsPointXY(90, 210), QgsPointXY(8, 20), - QgsCoordinateReferenceSystem('EPSG:4283'), True), - QgsGcpPoint(QgsPointXY(210, 190), QgsPointXY(20.5, 20), - QgsCoordinateReferenceSystem('EPSG:4283'), True), - QgsGcpPoint(QgsPointXY(350, 220), QgsPointXY(30, 21), - QgsCoordinateReferenceSystem('EPSG:4283'), True), - QgsGcpPoint(QgsPointXY(390, 290), QgsPointXY(39, 28), - QgsCoordinateReferenceSystem('EPSG:4283'), True), - ], - QgsCoordinateReferenceSystem('EPSG:4283')) + warper = QgsVectorWarper( + QgsGcpTransformerInterface.TransformMethod.PolynomialOrder1, + [ + QgsGcpPoint( + QgsPointXY(90, 210), + QgsPointXY(8, 20), + QgsCoordinateReferenceSystem("EPSG:4283"), + True, + ), + QgsGcpPoint( + QgsPointXY(210, 190), + QgsPointXY(20.5, 20), + QgsCoordinateReferenceSystem("EPSG:4283"), + True, + ), + QgsGcpPoint( + QgsPointXY(350, 220), + QgsPointXY(30, 21), + QgsCoordinateReferenceSystem("EPSG:4283"), + True, + ), + QgsGcpPoint( + QgsPointXY(390, 290), + QgsPointXY(39, 28), + QgsCoordinateReferenceSystem("EPSG:4283"), + True, + ), + ], + QgsCoordinateReferenceSystem("EPSG:4283"), + ) - self.assertTrue(warper.transformFeatures(source_layer.getFeatures(), - sink, - QgsProject.instance().transformContext())) + self.assertTrue( + warper.transformFeatures( + source_layer.getFeatures(), + sink, + QgsProject.instance().transformContext(), + ) + ) self.assertEqual(sink.count(), 5) - feature_map = {f.attributes()[0]: {'geom': f.geometry().asWkt(1), - 'attributes': f.attributes()} for f in sink.features()} - self.assertEqual(feature_map, {'test': {'geom': 'Point (9.4 19.7)', 'attributes': ['test', 123]}, - 'test2': {'geom': 'Point (18 19.9)', 'attributes': ['test2', 457]}, - 'test3': {'geom': 'Point (26.6 20.1)', 'attributes': ['test3', 888]}, - 'test4': {'geom': 'Point (39.6 28.5)', 'attributes': ['test4', -1]}, - 'test5': {'geom': 'Point (-7.8 3)', 'attributes': ['test5', 0]}}) + feature_map = { + f.attributes()[0]: { + "geom": f.geometry().asWkt(1), + "attributes": f.attributes(), + } + for f in sink.features() + } + self.assertEqual( + feature_map, + { + "test": {"geom": "Point (9.4 19.7)", "attributes": ["test", 123]}, + "test2": {"geom": "Point (18 19.9)", "attributes": ["test2", 457]}, + "test3": {"geom": "Point (26.6 20.1)", "attributes": ["test3", 888]}, + "test4": {"geom": "Point (39.6 28.5)", "attributes": ["test4", -1]}, + "test5": {"geom": "Point (-7.8 3)", "attributes": ["test5", 0]}, + }, + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvirtuallayerdefinition.py b/tests/src/python/test_qgsvirtuallayerdefinition.py index 97813ac1b893..049ed8865919 100644 --- a/tests/src/python/test_qgsvirtuallayerdefinition.py +++ b/tests/src/python/test_qgsvirtuallayerdefinition.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Hugo Mercier' -__date__ = '10/12/2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Hugo Mercier" +__date__ = "10/12/2015" +__copyright__ = "Copyright 2015, The QGIS Project" import os @@ -32,46 +33,99 @@ def test1(self): self.assertEqual(d.toString(), "") d.setFilePath("/file") self.assertEqual(d.toString(), "file:///file") - self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).filePath(), "/file") - self.assertEqual(QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())).filePath(), "/file") - d.setFilePath(os.path.join('C:/', 'file')) + self.assertEqual( + QgsVirtualLayerDefinition.fromUrl(d.toUrl()).filePath(), "/file" + ) + self.assertEqual( + QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())).filePath(), + "/file", + ) + d.setFilePath(os.path.join("C:/", "file")) self.assertEqual(d.toString(), "file:///C:/file") # self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).filePath(), os.path.join('C:/', 'file')) d.setQuery("SELECT * FROM mytable") - self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).query(), "SELECT * FROM mytable") - self.assertEqual(QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())).query(), "SELECT * FROM mytable") + self.assertEqual( + QgsVirtualLayerDefinition.fromUrl(d.toUrl()).query(), + "SELECT * FROM mytable", + ) + self.assertEqual( + QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())).query(), + "SELECT * FROM mytable", + ) q = "SELECT * FROM tableéé /*:int*/" d.setQuery(q) self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).query(), q) - self.assertEqual(QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())).query(), q) + self.assertEqual( + QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())).query(), q + ) s1 = "file://foo&bar=okié" d.addSource("name", s1, "provider", "utf8") - self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).sourceLayers()[0].source(), s1) - self.assertEqual(QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())).sourceLayers()[0].source(), s1) + self.assertEqual( + QgsVirtualLayerDefinition.fromUrl(d.toUrl()).sourceLayers()[0].source(), s1 + ) + self.assertEqual( + QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())) + .sourceLayers()[0] + .source(), + s1, + ) n1 = "éé ok" d.addSource(n1, s1, "provider") - self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).sourceLayers()[1].name(), n1) - self.assertEqual(QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())).sourceLayers()[1].name(), n1) + self.assertEqual( + QgsVirtualLayerDefinition.fromUrl(d.toUrl()).sourceLayers()[1].name(), n1 + ) + self.assertEqual( + QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())) + .sourceLayers()[1] + .name(), + n1, + ) d.addSource("ref1", "id0001") - self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).sourceLayers()[2].reference(), "id0001") - self.assertEqual(QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())).sourceLayers()[2].reference(), "id0001") + self.assertEqual( + QgsVirtualLayerDefinition.fromUrl(d.toUrl()).sourceLayers()[2].reference(), + "id0001", + ) + self.assertEqual( + QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())) + .sourceLayers()[2] + .reference(), + "id0001", + ) s = "dbname='C:\\tt' table=\"test\" (geometry) sql=" d.addSource("nn", s, "spatialite") - self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).sourceLayers()[3].source(), s) - self.assertEqual(QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())).sourceLayers()[3].source(), s) + self.assertEqual( + QgsVirtualLayerDefinition.fromUrl(d.toUrl()).sourceLayers()[3].source(), s + ) + self.assertEqual( + QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())) + .sourceLayers()[3] + .source(), + s, + ) d.setGeometryField("geom") - self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).geometryField(), "geom") - self.assertEqual(QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())).geometryField(), "geom") + self.assertEqual( + QgsVirtualLayerDefinition.fromUrl(d.toUrl()).geometryField(), "geom" + ) + self.assertEqual( + QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())).geometryField(), + "geom", + ) d.setGeometryWkbType(QgsWkbTypes.Type.Point) - self.assertEqual(QgsVirtualLayerDefinition.fromUrl(d.toUrl()).geometryWkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())).geometryWkbType(), QgsWkbTypes.Type.Point) + self.assertEqual( + QgsVirtualLayerDefinition.fromUrl(d.toUrl()).geometryWkbType(), + QgsWkbTypes.Type.Point, + ) + self.assertEqual( + QgsVirtualLayerDefinition.fromUrl(strToUrl(d.toString())).geometryWkbType(), + QgsWkbTypes.Type.Point, + ) f = QgsFields() f.append(QgsField("a", QVariant.Int)) @@ -88,12 +142,16 @@ def test1(self): self.assertEqual(f[2].type(), f2[2].type()) # Issue https://github.com/qgis/QGIS/issues/44130 - url = QUrl(r"?layer_ref=Reprojet%C3%A9_e888ce1e_17a9_46f4_b8c3_254eef3f2931:input1&query=SELECT%20*%20FROM%20input1") + url = QUrl( + r"?layer_ref=Reprojet%C3%A9_e888ce1e_17a9_46f4_b8c3_254eef3f2931:input1&query=SELECT%20*%20FROM%20input1" + ) f3 = QgsVirtualLayerDefinition.fromUrl(url) - self.assertEqual(f3.query(), 'SELECT * FROM input1') + self.assertEqual(f3.query(), "SELECT * FROM input1") source_layer = f3.sourceLayers()[0] - self.assertEqual(source_layer.reference(), 'Reprojeté_e888ce1e_17a9_46f4_b8c3_254eef3f2931') + self.assertEqual( + source_layer.reference(), "Reprojeté_e888ce1e_17a9_46f4_b8c3_254eef3f2931" + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvirtuallayertask.py b/tests/src/python/test_qgsvirtuallayertask.py index 9f184e5149ac..939dea0f6c71 100644 --- a/tests/src/python/test_qgsvirtuallayertask.py +++ b/tests/src/python/test_qgsvirtuallayertask.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Paul Blottiere' -__date__ = '28/02/2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Paul Blottiere" +__date__ = "28/02/2018" +__copyright__ = "Copyright 2018, The QGIS Project" import os @@ -45,7 +46,12 @@ def onFail(self): self._exceptionText = self.task.exceptionText() def test(self): - l1 = QgsVectorLayer(os.path.join(self.testDataDir, "france_parts.shp"), "françéà", "ogr", QgsVectorLayer.LayerOptions(False)) + l1 = QgsVectorLayer( + os.path.join(self.testDataDir, "france_parts.shp"), + "françéà", + "ogr", + QgsVectorLayer.LayerOptions(False), + ) self.assertEqual(l1.isValid(), True) QgsProject.instance().addMapLayer(l1) @@ -71,7 +77,7 @@ def test(self): # Test exception self._success = False self._fail = False - df.setQuery('select *') + df.setQuery("select *") self.task = QgsVirtualLayerTask(df) self.task.taskCompleted.connect(self.onSuccess) self.task.taskTerminated.connect(self.onFail) @@ -81,8 +87,12 @@ def test(self): self.assertFalse(self._success) self.assertTrue(self._fail) - self.assertEqual(self._exceptionText, 'Query preparation error on PRAGMA table_info(_tview): no tables specified', self._exceptionText) + self.assertEqual( + self._exceptionText, + "Query preparation error on PRAGMA table_info(_tview): no tables specified", + self._exceptionText, + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsvtpk.py b/tests/src/python/test_qgsvtpk.py index bd00b77e3a14..8c5e8b78c0b8 100644 --- a/tests/src/python/test_qgsvtpk.py +++ b/tests/src/python/test_qgsvtpk.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Nyall Dawson' -__date__ = '04/03/2022' -__copyright__ = 'Copyright 2022, The QGIS Project' + +__author__ = "Nyall Dawson" +__date__ = "04/03/2022" +__copyright__ = "Copyright 2022, The QGIS Project" from qgis.PyQt.QtXml import QDomDocument @@ -17,7 +18,7 @@ QgsVtpkTiles, QgsTileRange, QgsTileXYZ, - QgsReadWriteContext + QgsReadWriteContext, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -33,7 +34,7 @@ def testOpenInvalid(self): """ Test opening an invalid path """ - tiles = QgsVtpkTiles(unitTestDataPath() + '/xxx.vtpk') + tiles = QgsVtpkTiles(unitTestDataPath() + "/xxx.vtpk") self.assertEqual(tiles.metadata(), {}) self.assertEqual(tiles.styleDefinition(), {}) self.assertEqual(tiles.spriteDefinition(), {}) @@ -45,50 +46,141 @@ def testOpenInvalid(self): self.assertTrue(tiles.spriteImage().isNull()) def testOpen(self): - tiles = QgsVtpkTiles(unitTestDataPath() + '/testvtpk.vtpk') + tiles = QgsVtpkTiles(unitTestDataPath() + "/testvtpk.vtpk") self.assertEqual(tiles.metadata(), {}) self.assertEqual(tiles.styleDefinition(), {}) self.assertEqual(tiles.spriteDefinition(), {}) self.assertTrue(tiles.spriteImage().isNull()) self.assertTrue(tiles.open()) - self.assertEqual(tiles.metadata(), - {'capabilities': 'TilesOnly', 'copyrightText': 'Map credits', 'currentVersion': 10.91, - 'defaultStyles': 'resources/styles', 'exportTilesAllowed': False, - 'fullExtent': {'spatialReference': {'latestWkid': 3857, 'wkid': 102100}, - 'xmax': 20037507.0671618, 'xmin': -20037507.0738129, 'ymax': 20037507.0671618, - 'ymin': -20037507.0671618}, - 'initialExtent': {'spatialReference': {'latestWkid': 3857, 'wkid': 102100}, - 'xmax': 20037507.0671618, 'xmin': -20037507.0738129, - 'ymax': 20037507.0671618, 'ymin': -20037507.0671618}, 'maxLOD': 4, - 'maxScale': 18489297.737236, 'maxzoom': 4, 'minLOD': 0, 'minScale': 295828763.7957775, - 'name': 'Map', 'resourceInfo': { - 'cacheInfo': {'storageInfo': {'packetSize': 128, 'storageFormat': 'compactV2'}}, - 'styleVersion': 8, 'tileCompression': 'gzip'}, - 'tileInfo': {'cols': 512, 'dpi': 96, 'format': 'pbf', - 'lods': [{'level': 0, 'resolution': 78271.516964, 'scale': 295828763.7957775}, - {'level': 1, 'resolution': 39135.75848199995, - 'scale': 147914381.8978885}, - {'level': 2, 'resolution': 19567.87924100005, - 'scale': 73957190.9489445}, - {'level': 3, 'resolution': 9783.93962049995, 'scale': 36978595.474472}, - {'level': 4, 'resolution': 4891.96981024998, 'scale': 18489297.737236}], - 'origin': {'x': -20037508.342787, 'y': 20037508.342787}, 'rows': 512, - 'spatialReference': {'latestWkid': 3857, 'wkid': 102100}}, - 'tiles': ['tile/{z}/{y}/{x}.pbf'], 'type': 'indexedVector'} - ) - - self.assertEqual(tiles.styleDefinition(), {'glyphs': '../fonts/{fontstack}/{range}.pbf', 'layers': [ - {'id': 'polys', 'layout': {}, 'paint': {'fill-color': '#B6FCFB', 'fill-outline-color': '#6E6E6E'}, - 'source': 'esri', 'source-layer': 'polys', 'type': 'fill'}, - {'id': 'lines', 'layout': {'line-cap': 'round', 'line-join': 'round'}, - 'paint': {'line-color': '#4C993A', 'line-width': 1.33333}, 'source': 'esri', 'source-layer': 'lines', - 'type': 'line'}, {'id': 'points', 'layout': {}, 'paint': {'circle-color': '#A16F33', 'circle-radius': 2.2, - 'circle-stroke-color': '#000000', - 'circle-stroke-width': 0.933333}, - 'source': 'esri', 'source-layer': 'points', 'type': 'circle'}], 'sources': { - 'esri': {'attribution': 'Map credits', 'bounds': [-180, -85.0511, 180, 85.0511], 'maxzoom': 4, 'minzoom': 0, - 'scheme': 'xyz', 'type': 'vector', 'url': '../../'}}, 'sprite': '../sprites/sprite', 'version': 8}) + self.assertEqual( + tiles.metadata(), + { + "capabilities": "TilesOnly", + "copyrightText": "Map credits", + "currentVersion": 10.91, + "defaultStyles": "resources/styles", + "exportTilesAllowed": False, + "fullExtent": { + "spatialReference": {"latestWkid": 3857, "wkid": 102100}, + "xmax": 20037507.0671618, + "xmin": -20037507.0738129, + "ymax": 20037507.0671618, + "ymin": -20037507.0671618, + }, + "initialExtent": { + "spatialReference": {"latestWkid": 3857, "wkid": 102100}, + "xmax": 20037507.0671618, + "xmin": -20037507.0738129, + "ymax": 20037507.0671618, + "ymin": -20037507.0671618, + }, + "maxLOD": 4, + "maxScale": 18489297.737236, + "maxzoom": 4, + "minLOD": 0, + "minScale": 295828763.7957775, + "name": "Map", + "resourceInfo": { + "cacheInfo": { + "storageInfo": {"packetSize": 128, "storageFormat": "compactV2"} + }, + "styleVersion": 8, + "tileCompression": "gzip", + }, + "tileInfo": { + "cols": 512, + "dpi": 96, + "format": "pbf", + "lods": [ + { + "level": 0, + "resolution": 78271.516964, + "scale": 295828763.7957775, + }, + { + "level": 1, + "resolution": 39135.75848199995, + "scale": 147914381.8978885, + }, + { + "level": 2, + "resolution": 19567.87924100005, + "scale": 73957190.9489445, + }, + { + "level": 3, + "resolution": 9783.93962049995, + "scale": 36978595.474472, + }, + { + "level": 4, + "resolution": 4891.96981024998, + "scale": 18489297.737236, + }, + ], + "origin": {"x": -20037508.342787, "y": 20037508.342787}, + "rows": 512, + "spatialReference": {"latestWkid": 3857, "wkid": 102100}, + }, + "tiles": ["tile/{z}/{y}/{x}.pbf"], + "type": "indexedVector", + }, + ) + + self.assertEqual( + tiles.styleDefinition(), + { + "glyphs": "../fonts/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "polys", + "layout": {}, + "paint": { + "fill-color": "#B6FCFB", + "fill-outline-color": "#6E6E6E", + }, + "source": "esri", + "source-layer": "polys", + "type": "fill", + }, + { + "id": "lines", + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": {"line-color": "#4C993A", "line-width": 1.33333}, + "source": "esri", + "source-layer": "lines", + "type": "line", + }, + { + "id": "points", + "layout": {}, + "paint": { + "circle-color": "#A16F33", + "circle-radius": 2.2, + "circle-stroke-color": "#000000", + "circle-stroke-width": 0.933333, + }, + "source": "esri", + "source-layer": "points", + "type": "circle", + }, + ], + "sources": { + "esri": { + "attribution": "Map credits", + "bounds": [-180, -85.0511, 180, 85.0511], + "maxzoom": 4, + "minzoom": 0, + "scheme": "xyz", + "type": "vector", + "url": "../../", + } + }, + "sprite": "../sprites/sprite", + "version": 8, + }, + ) # this file doesn't actually have any sprites... self.assertEqual(tiles.spriteDefinition(), {}) self.assertEqual(tiles.spriteImage().width(), 120) @@ -103,7 +195,7 @@ def testOpen(self): self.assertEqual(tiles.matrixSet().tileMatrix(3).scale(), 36978595.474472) self.assertEqual(tiles.matrixSet().tileMatrix(4).scale(), 18489297.737236) - self.assertEqual(tiles.crs().authid(), 'EPSG:3857') + self.assertEqual(tiles.crs().authid(), "EPSG:3857") context = QgsCoordinateTransformContext() self.assertEqual(tiles.extent(context).xMinimum(), -20037507.0738129) @@ -115,31 +207,49 @@ def testOpen(self): self.assertEqual(tile_data.length(), 1202) def testLayerMetadata(self): - tiles = QgsVtpkTiles(unitTestDataPath() + '/testvtpk.vtpk') + tiles = QgsVtpkTiles(unitTestDataPath() + "/testvtpk.vtpk") # no crash _ = tiles.layerMetadata() self.assertTrue(tiles.open()) layer_metadata = tiles.layerMetadata() - self.assertEqual(layer_metadata.language(), 'en-AU') - self.assertEqual(layer_metadata.identifier(), 'FD610B57-9B73-48E5-A7E5-DA07C8D2C245') - self.assertEqual(layer_metadata.title(), 'testvtpk') - self.assertEqual(layer_metadata.abstract(), 'Map description') - self.assertEqual(layer_metadata.keywords(), {'keywords': ['tile tags']}) - self.assertEqual(layer_metadata.rights(), ['Map credits']) - self.assertEqual(layer_metadata.licenses(), ['Map use limitations']) - self.assertEqual(layer_metadata.crs().authid(), 'EPSG:3857') - self.assertEqual(layer_metadata.extent().spatialExtents()[0].bounds.xMinimum(), -179.999988600592) - self.assertEqual(layer_metadata.extent().spatialExtents()[0].bounds.xMaximum(), 179.999988540844) - self.assertEqual(layer_metadata.extent().spatialExtents()[0].bounds.yMinimum(), -85.0511277912625) - self.assertEqual(layer_metadata.extent().spatialExtents()[0].bounds.yMaximum(), 85.0511277912625) - self.assertEqual(layer_metadata.extent().spatialExtents()[0].extentCrs.authid(), 'EPSG:4326') + self.assertEqual(layer_metadata.language(), "en-AU") + self.assertEqual( + layer_metadata.identifier(), "FD610B57-9B73-48E5-A7E5-DA07C8D2C245" + ) + self.assertEqual(layer_metadata.title(), "testvtpk") + self.assertEqual(layer_metadata.abstract(), "Map description") + self.assertEqual(layer_metadata.keywords(), {"keywords": ["tile tags"]}) + self.assertEqual(layer_metadata.rights(), ["Map credits"]) + self.assertEqual(layer_metadata.licenses(), ["Map use limitations"]) + self.assertEqual(layer_metadata.crs().authid(), "EPSG:3857") + self.assertEqual( + layer_metadata.extent().spatialExtents()[0].bounds.xMinimum(), + -179.999988600592, + ) + self.assertEqual( + layer_metadata.extent().spatialExtents()[0].bounds.xMaximum(), + 179.999988540844, + ) + self.assertEqual( + layer_metadata.extent().spatialExtents()[0].bounds.yMinimum(), + -85.0511277912625, + ) + self.assertEqual( + layer_metadata.extent().spatialExtents()[0].bounds.yMaximum(), + 85.0511277912625, + ) + self.assertEqual( + layer_metadata.extent().spatialExtents()[0].extentCrs.authid(), "EPSG:4326" + ) def testVectorTileLayer(self): - layer = QgsVectorTileLayer(f"type=vtpk&url={unitTestDataPath() + '/testvtpk.vtpk'}", 'tiles') + layer = QgsVectorTileLayer( + f"type=vtpk&url={unitTestDataPath() + '/testvtpk.vtpk'}", "tiles" + ) self.assertTrue(layer.isValid()) - self.assertEqual(layer.sourceType(), 'vtpk') - self.assertEqual(layer.sourcePath(), unitTestDataPath() + '/testvtpk.vtpk') + self.assertEqual(layer.sourceType(), "vtpk") + self.assertEqual(layer.sourcePath(), unitTestDataPath() + "/testvtpk.vtpk") self.assertEqual(layer.sourceMinZoom(), 0) self.assertEqual(layer.sourceMaxZoom(), 4) @@ -147,24 +257,29 @@ def testVectorTileLayer(self): # make sure style was loaded self.assertEqual(len(layer.renderer().styles()), 3) - self.assertEqual(layer.renderer().style(0).styleName(), 'polys') + self.assertEqual(layer.renderer().style(0).styleName(), "polys") style = layer.renderer().style(0) - self.assertEqual(style.symbol().color().name(), '#b6fcfb') - self.assertEqual(layer.renderer().style(1).styleName(), 'lines') + self.assertEqual(style.symbol().color().name(), "#b6fcfb") + self.assertEqual(layer.renderer().style(1).styleName(), "lines") style = layer.renderer().style(1) - self.assertEqual(style.symbol().color().name(), '#4c993a') - self.assertEqual(layer.renderer().style(2).styleName(), 'points') + self.assertEqual(style.symbol().color().name(), "#4c993a") + self.assertEqual(layer.renderer().style(2).styleName(), "points") style = layer.renderer().style(2) - self.assertEqual(style.symbol().color().name(), '#a16f33') + self.assertEqual(style.symbol().color().name(), "#a16f33") self.assertTrue(layer.loadDefaultMetadata()) # make sure metadata was loaded - self.assertEqual(layer.metadata().identifier(), 'FD610B57-9B73-48E5-A7E5-DA07C8D2C245') + self.assertEqual( + layer.metadata().identifier(), "FD610B57-9B73-48E5-A7E5-DA07C8D2C245" + ) def testVectorTileLayerTileMap(self): # note that this is only the "shell" of a vtpk -- there's no tiles here # as the file is just for tilemap handling tests - layer = QgsVectorTileLayer(f"type=vtpk&url={unitTestDataPath() + '/vector_tile/vtpk_indexed.vtpk'}", 'tiles') + layer = QgsVectorTileLayer( + f"type=vtpk&url={unitTestDataPath() + '/vector_tile/vtpk_indexed.vtpk'}", + "tiles", + ) layer.setOpacity(0.5) self.assertTrue(layer.isValid()) @@ -172,16 +287,18 @@ def testVectorTileLayerTileMap(self): # we want to see the zoom level 9 tiles here, as the tilemap indicates # that they should be used instead of zoom level 10 tiles for their # extents - expected = [QgsTileXYZ(274, 52, 9), - QgsTileXYZ(275, 52, 9), - QgsTileXYZ(548, 106, 10), - QgsTileXYZ(549, 106, 10), - QgsTileXYZ(550, 106, 10), - QgsTileXYZ(551, 106, 10), - QgsTileXYZ(548, 107, 10), - QgsTileXYZ(549, 107, 10), - QgsTileXYZ(550, 107, 10), - QgsTileXYZ(551, 107, 10)] + expected = [ + QgsTileXYZ(274, 52, 9), + QgsTileXYZ(275, 52, 9), + QgsTileXYZ(548, 106, 10), + QgsTileXYZ(549, 106, 10), + QgsTileXYZ(550, 106, 10), + QgsTileXYZ(551, 106, 10), + QgsTileXYZ(548, 107, 10), + QgsTileXYZ(549, 107, 10), + QgsTileXYZ(550, 107, 10), + QgsTileXYZ(551, 107, 10), + ] self.assertCountEqual(tiles, expected) # ensure that tilemap is correctly handled when restoring layers @@ -189,17 +306,18 @@ def testVectorTileLayerTileMap(self): elem = doc.createElement("maplayer") self.assertTrue(layer.writeLayerXml(elem, doc, QgsReadWriteContext())) - layer2 = QgsVectorTileLayer(f"type=vtpk&url={unitTestDataPath() + '/vector_tile/vtpk_indexed.vtpk'}", 'tiles') - tiles = layer2.tileMatrixSet().tilesInRange( - QgsTileRange(0, 1023, 0, 1023), 10) + layer2 = QgsVectorTileLayer( + f"type=vtpk&url={unitTestDataPath() + '/vector_tile/vtpk_indexed.vtpk'}", + "tiles", + ) + tiles = layer2.tileMatrixSet().tilesInRange(QgsTileRange(0, 1023, 0, 1023), 10) self.assertCountEqual(tiles, expected) self.assertTrue(layer2.readLayerXml(elem, QgsReadWriteContext())) self.assertEqual(layer2.opacity(), 0.5) - tiles = layer2.tileMatrixSet().tilesInRange( - QgsTileRange(0, 1023, 0, 1023), 10) + tiles = layer2.tileMatrixSet().tilesInRange(QgsTileRange(0, 1023, 0, 1023), 10) self.assertCountEqual(tiles, expected) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgswebenginepage.py b/tests/src/python/test_qgswebenginepage.py index 95d3e9fde557..ba8e9085ea30 100644 --- a/tests/src/python/test_qgswebenginepage.py +++ b/tests/src/python/test_qgswebenginepage.py @@ -11,19 +11,9 @@ import os import unittest -from qgis.PyQt.QtCore import ( - Qt, - QRectF, - QUrl, - QSize -) -from qgis.PyQt.QtGui import ( - QImage, - QPainter -) -from qgis.core import ( - QgsWebEnginePage -) +from qgis.PyQt.QtCore import Qt, QRectF, QUrl, QSize +from qgis.PyQt.QtGui import QImage, QPainter +from qgis.core import QgsWebEnginePage from qgis.testing import start_app, QgisTestCase from qgis.PyQt.QtTest import QSignalSpy @@ -44,57 +34,43 @@ def test_contents_size(self): """ Test contentsSize """ - html_path = os.path.join(TEST_DATA_DIR, 'test_html.html') + html_path = os.path.join(TEST_DATA_DIR, "test_html.html") page = QgsWebEnginePage() spy = QSignalSpy(page.loadFinished) page.setUrl(QUrl.fromLocalFile(html_path)) spy.wait() self.assertTrue(spy[0][0]) - self.assertEqual( - page.documentSize(), - QSize(306, 248) - ) + self.assertEqual(page.documentSize(), QSize(306, 248)) def test_contents_size_blocking(self): """ Test contentsSize using a blocking load """ - html_path = os.path.join(TEST_DATA_DIR, 'test_html.html') + html_path = os.path.join(TEST_DATA_DIR, "test_html.html") page = QgsWebEnginePage() - self.assertTrue( - page.setUrl(QUrl.fromLocalFile(html_path), blocking=True) - ) - self.assertEqual( - page.documentSize(), - QSize(306, 248) - ) + self.assertTrue(page.setUrl(QUrl.fromLocalFile(html_path), blocking=True)) + self.assertEqual(page.documentSize(), QSize(306, 248)) def test_render_web_page(self): """ Test rendering web pages to a QPainter """ - html_path = os.path.join(TEST_DATA_DIR, 'test_html.html') + html_path = os.path.join(TEST_DATA_DIR, "test_html.html") page = QgsWebEnginePage() - self.assertTrue( - page.setUrl(QUrl.fromLocalFile(html_path), blocking=True) - ) + self.assertTrue(page.setUrl(QUrl.fromLocalFile(html_path), blocking=True)) image = QImage(600, 423, QImage.Format.Format_ARGB32_Premultiplied) image.fill(Qt.GlobalColor.transparent) painter = QPainter(image) - self.assertTrue( - page.render( - painter, - QRectF(0, 0, 600, 423)) - ) + self.assertTrue(page.render(painter, QRectF(0, 0, 600, 423))) painter.end() self.assertTrue( self.image_check( - 'Render QgsWebEnginePage to QPainter', - 'render', + "Render QgsWebEnginePage to QPainter", + "render", image, - 'expected_render', + "expected_render", ) ) @@ -102,30 +78,24 @@ def test_render_web_page_with_text(self): """ Test rendering web page with text to a QPainter """ - html_path = os.path.join(TEST_DATA_DIR, 'test_html_feature.html') + html_path = os.path.join(TEST_DATA_DIR, "test_html_feature.html") page = QgsWebEnginePage() - self.assertTrue( - page.setUrl(QUrl.fromLocalFile(html_path), blocking=True) - ) + self.assertTrue(page.setUrl(QUrl.fromLocalFile(html_path), blocking=True)) self.assertAlmostEqual(page.documentSize().width(), 306, delta=15) self.assertAlmostEqual(page.documentSize().height(), 64, delta=15) image = QImage(600, 125, QImage.Format.Format_ARGB32_Premultiplied) image.fill(Qt.GlobalColor.transparent) painter = QPainter(image) - self.assertTrue( - page.render( - painter, - QRectF(0, 0, 600, 125)) - ) + self.assertTrue(page.render(painter, QRectF(0, 0, 600, 125))) painter.end() self.assertTrue( self.image_check( - 'Render QgsWebEnginePage with text to QPainter', - 'render_with_text', + "Render QgsWebEnginePage with text to QPainter", + "render_with_text", image, - 'expected_render_with_text', + "expected_render_with_text", ) ) diff --git a/tests/src/python/test_qgsxmlutils.py b/tests/src/python/test_qgsxmlutils.py index 78f78146abd1..b502e7baa8d3 100644 --- a/tests/src/python/test_qgsxmlutils.py +++ b/tests/src/python/test_qgsxmlutils.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Matthias Kuhn' -__date__ = '18/11/2016' -__copyright__ = 'Copyright 2016, The QGIS Project' + +__author__ = "Matthias Kuhn" +__date__ = "18/11/2016" +__copyright__ = "Copyright 2016, The QGIS Project" from qgis.PyQt.QtCore import QDate, QDateTime, QTime, QVariant from qgis.PyQt.QtGui import QColor @@ -51,7 +52,7 @@ def test_integer(self): """ doc = QDomDocument("properties") - my_properties = {'a': 1, 'b': 2, 'c': 3, 'd': -1} + my_properties = {"a": 1, "b": 2, "c": 3, "d": -1} elem = QgsXmlUtils.writeVariant(my_properties, doc) prop2 = QgsXmlUtils.readVariant(elem) @@ -64,7 +65,7 @@ def test_long(self): doc = QDomDocument("properties") # not sure if this actually does map to a long? - my_properties = {'a': 9223372036854775808} + my_properties = {"a": 9223372036854775808} elem = QgsXmlUtils.writeVariant(my_properties, doc) prop2 = QgsXmlUtils.readVariant(elem) @@ -76,12 +77,14 @@ def test_string(self): """ doc = QDomDocument("properties") - my_properties = {'a': 'a', 'b': 'b', 'c': 'something_else', 'empty': ''} + my_properties = {"a": "a", "b": "b", "c": "something_else", "empty": ""} elem = QgsXmlUtils.writeVariant(my_properties, doc) prop2 = QgsXmlUtils.readVariant(elem) - self.assertEqual(prop2, {'a': 'a', 'b': 'b', 'c': 'something_else', 'empty': None}) + self.assertEqual( + prop2, {"a": "a", "b": "b", "c": "something_else", "empty": None} + ) def test_double(self): """ @@ -89,7 +92,7 @@ def test_double(self): """ doc = QDomDocument("properties") - my_properties = {'a': 0.27, 'b': 1.0, 'c': 5} + my_properties = {"a": 0.27, "b": 1.0, "c": 5} elem = QgsXmlUtils.writeVariant(my_properties, doc) prop2 = QgsXmlUtils.readVariant(elem) @@ -102,7 +105,7 @@ def test_boolean(self): """ doc = QDomDocument("properties") - my_properties = {'a': True, 'b': False} + my_properties = {"a": True, "b": False} elem = QgsXmlUtils.writeVariant(my_properties, doc) prop2 = QgsXmlUtils.readVariant(elem) @@ -114,7 +117,7 @@ def test_list(self): Test that lists are correctly loaded and written """ doc = QDomDocument("properties") - my_properties = [1, 4, 'a', 'test', 7.9] + my_properties = [1, 4, "a", "test", 7.9] elem = QgsXmlUtils.writeVariant(my_properties, doc) prop2 = QgsXmlUtils.readVariant(elem) @@ -127,7 +130,7 @@ def test_complex(self): """ doc = QDomDocument("properties") - my_properties = {'boolean': True, 'integer': False, 'map': {'a': 1}} + my_properties = {"boolean": True, "integer": False, "map": {"a": 1}} elem = QgsXmlUtils.writeVariant(my_properties, doc) prop2 = QgsXmlUtils.readVariant(elem) @@ -147,14 +150,14 @@ def test_property(self): self.assertEqual(prop, prop2) - prop = QgsProperty.fromExpression('1+2=5') + prop = QgsProperty.fromExpression("1+2=5") elem = QgsXmlUtils.writeVariant(prop, doc) prop2 = QgsXmlUtils.readVariant(elem) self.assertEqual(prop, prop2) - prop = QgsProperty.fromField('oid') + prop = QgsProperty.fromField("oid") elem = QgsXmlUtils.writeVariant(prop, doc) prop2 = QgsXmlUtils.readVariant(elem) @@ -167,12 +170,12 @@ def test_crs(self): """ doc = QDomDocument("properties") - crs = QgsCoordinateReferenceSystem('epsg:3111') + crs = QgsCoordinateReferenceSystem("epsg:3111") elem = QgsXmlUtils.writeVariant(crs, doc) crs2 = QgsXmlUtils.readVariant(elem) self.assertTrue(crs2.isValid()) - self.assertEqual(crs2.authid(), 'EPSG:3111') + self.assertEqual(crs2.authid(), "EPSG:3111") crs = QgsCoordinateReferenceSystem() elem = QgsXmlUtils.writeVariant(crs, doc) @@ -186,11 +189,11 @@ def test_geom(self): """ doc = QDomDocument("properties") - g = QgsGeometry.fromWkt('Point(3 4)') + g = QgsGeometry.fromWkt("Point(3 4)") elem = QgsXmlUtils.writeVariant(g, doc) g2 = QgsXmlUtils.readVariant(elem) - self.assertEqual(g2.asWkt(), 'Point (3 4)') + self.assertEqual(g2.asWkt(), "Point (3 4)") def test_color(self): """ @@ -214,7 +217,9 @@ def test_datetime(self): """ doc = QDomDocument("properties") - elem = QgsXmlUtils.writeVariant(QDateTime(QDate(2019, 5, 7), QTime(12, 11, 10)), doc) + elem = QgsXmlUtils.writeVariant( + QDateTime(QDate(2019, 5, 7), QTime(12, 11, 10)), doc + ) c = QgsXmlUtils.readVariant(elem) self.assertEqual(c, QDateTime(QDate(2019, 5, 7), QTime(12, 11, 10))) elem = QgsXmlUtils.writeVariant(QDateTime(), doc) @@ -253,19 +258,30 @@ def test_feature_source_definition(self): """ doc = QDomDocument("properties") - definition = QgsProcessingFeatureSourceDefinition(QgsProperty.fromValue('my source')) + definition = QgsProcessingFeatureSourceDefinition( + QgsProperty.fromValue("my source") + ) definition.selectedFeaturesOnly = True definition.featureLimit = 27 - definition.flags = QgsProcessingFeatureSourceDefinition.Flag.FlagCreateIndividualOutputPerInputFeature - definition.geometryCheck = QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid + definition.flags = ( + QgsProcessingFeatureSourceDefinition.Flag.FlagCreateIndividualOutputPerInputFeature + ) + definition.geometryCheck = ( + QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid + ) elem = QgsXmlUtils.writeVariant(definition, doc) c = QgsXmlUtils.readVariant(elem) - self.assertEqual(c.source.staticValue(), 'my source') + self.assertEqual(c.source.staticValue(), "my source") self.assertTrue(c.selectedFeaturesOnly) self.assertEqual(c.featureLimit, 27) - self.assertEqual(c.flags, QgsProcessingFeatureSourceDefinition.Flag.FlagCreateIndividualOutputPerInputFeature) - self.assertEqual(c.geometryCheck, QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid) + self.assertEqual( + c.flags, + QgsProcessingFeatureSourceDefinition.Flag.FlagCreateIndividualOutputPerInputFeature, + ) + self.assertEqual( + c.geometryCheck, QgsFeatureRequest.InvalidGeometryCheck.GeometrySkipInvalid + ) def test_output_layer_definition(self): """ @@ -273,40 +289,44 @@ def test_output_layer_definition(self): """ doc = QDomDocument("properties") - definition = QgsProcessingOutputLayerDefinition(QgsProperty.fromValue('my sink')) - definition.createOptions = {'opt': 1, 'opt2': 2} + definition = QgsProcessingOutputLayerDefinition( + QgsProperty.fromValue("my sink") + ) + definition.createOptions = {"opt": 1, "opt2": 2} elem = QgsXmlUtils.writeVariant(definition, doc) c = QgsXmlUtils.readVariant(elem) - self.assertEqual(c.sink.staticValue(), 'my sink') - self.assertEqual(c.createOptions, {'opt': 1, 'opt2': 2}) + self.assertEqual(c.sink.staticValue(), "my sink") + self.assertEqual(c.createOptions, {"opt": 1, "opt2": 2}) def testRemappingDefinition(self): fields = QgsFields() - fields.append(QgsField('fldtxt', QVariant.String)) - fields.append(QgsField('fldint', QVariant.Int)) - fields.append(QgsField('fldtxt2', QVariant.String)) + fields.append(QgsField("fldtxt", QVariant.String)) + fields.append(QgsField("fldint", QVariant.Int)) + fields.append(QgsField("fldtxt2", QVariant.String)) mapping_def = QgsRemappingSinkDefinition() mapping_def.setDestinationWkbType(QgsWkbTypes.Type.Point) - mapping_def.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:4326')) - mapping_def.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) + mapping_def.setSourceCrs(QgsCoordinateReferenceSystem("EPSG:4326")) + mapping_def.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:3857")) mapping_def.setDestinationFields(fields) - mapping_def.addMappedField('fldtxt2', QgsProperty.fromField('fld1')) - mapping_def.addMappedField('fldint', QgsProperty.fromExpression('@myval * fldint')) + mapping_def.addMappedField("fldtxt2", QgsProperty.fromField("fld1")) + mapping_def.addMappedField( + "fldint", QgsProperty.fromExpression("@myval * fldint") + ) doc = QDomDocument("properties") elem = QgsXmlUtils.writeVariant(mapping_def, doc) c = QgsXmlUtils.readVariant(elem) self.assertEqual(c.destinationWkbType(), QgsWkbTypes.Type.Point) - self.assertEqual(c.sourceCrs().authid(), 'EPSG:4326') - self.assertEqual(c.destinationCrs().authid(), 'EPSG:3857') - self.assertEqual(c.destinationFields()[0].name(), 'fldtxt') - self.assertEqual(c.destinationFields()[1].name(), 'fldint') - self.assertEqual(c.fieldMap()['fldtxt2'].field(), 'fld1') - self.assertEqual(c.fieldMap()['fldint'].expressionString(), '@myval * fldint') + self.assertEqual(c.sourceCrs().authid(), "EPSG:4326") + self.assertEqual(c.destinationCrs().authid(), "EPSG:3857") + self.assertEqual(c.destinationFields()[0].name(), "fldtxt") + self.assertEqual(c.destinationFields()[1].name(), "fldint") + self.assertEqual(c.fieldMap()["fldtxt2"].field(), "fld1") + self.assertEqual(c.fieldMap()["fldint"].expressionString(), "@myval * fldint") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgsziputils.py b/tests/src/python/test_qgsziputils.py index 21f88430d0a1..0c98441f3f04 100644 --- a/tests/src/python/test_qgsziputils.py +++ b/tests/src/python/test_qgsziputils.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Paul Blottiere' -__date__ = '06/7/2017' -__copyright__ = 'Copyright 2017, The QGIS Project' + +__author__ = "Paul Blottiere" +__date__ = "06/7/2017" +__copyright__ = "Copyright 2017, The QGIS Project" import os import tempfile @@ -36,9 +37,9 @@ def setUpClass(cls): cls.zipDir = os.path.join(unitTestDataPath(), "zip") def test_zip_ok(self): - f0 = os.path.join(unitTestDataPath(), 'multipoint.shp') - f1 = os.path.join(unitTestDataPath(), 'lines.shp') - f2 = os.path.join(unitTestDataPath(), 'joins.qgs') + f0 = os.path.join(unitTestDataPath(), "multipoint.shp") + f1 = os.path.join(unitTestDataPath(), "lines.shp") + f2 = os.path.join(unitTestDataPath(), "joins.qgs") rc = QgsZipUtils.zip(tmpPath(), [f0, f1, f2]) self.assertTrue(rc) @@ -49,9 +50,9 @@ def test_zip_file_yet_exist(self): zip.close() os.remove(zip.fileName()) - f0 = os.path.join(unitTestDataPath(), 'multipoint.shp') - f1 = os.path.join(unitTestDataPath(), 'lines.shp') - f2 = os.path.join(unitTestDataPath(), 'joins.qgs') + f0 = os.path.join(unitTestDataPath(), "multipoint.shp") + f1 = os.path.join(unitTestDataPath(), "lines.shp") + f2 = os.path.join(unitTestDataPath(), "joins.qgs") rc = QgsZipUtils.zip(zip.fileName(), [f0, f1, f2]) self.assertTrue(rc) @@ -60,17 +61,17 @@ def test_zip_file_yet_exist(self): self.assertFalse(rc) def test_zip_file_empty(self): - f0 = os.path.join(unitTestDataPath(), 'multipoint.shp') - f1 = os.path.join(unitTestDataPath(), 'lines.shp') - f2 = os.path.join(unitTestDataPath(), 'joins.qgs') + f0 = os.path.join(unitTestDataPath(), "multipoint.shp") + f1 = os.path.join(unitTestDataPath(), "lines.shp") + f2 = os.path.join(unitTestDataPath(), "joins.qgs") rc = QgsZipUtils.zip("", [f0, f1, f2]) self.assertFalse(rc) def test_zip_input_file_not_exist(self): - f0 = os.path.join(unitTestDataPath(), 'multipoint.shp') - f1 = os.path.join(unitTestDataPath(), 'fake.shp') - f2 = os.path.join(unitTestDataPath(), 'joins.qgs') + f0 = os.path.join(unitTestDataPath(), "multipoint.shp") + f1 = os.path.join(unitTestDataPath(), "fake.shp") + f2 = os.path.join(unitTestDataPath(), "joins.qgs") rc = QgsZipUtils.zip(tmpPath(), [f0, f1, f2]) self.assertFalse(rc) @@ -78,7 +79,7 @@ def test_zip_input_file_not_exist(self): def test_unzip_ok(self): outDir = QTemporaryDir() - zip = os.path.join(self.zipDir, 'testzip.zip') + zip = os.path.join(self.zipDir, "testzip.zip") rc, files = QgsZipUtils.unzip(zip, outDir.path()) self.assertTrue(rc) @@ -87,7 +88,7 @@ def test_unzip_ok(self): def test_unzip_file_not_exist(self): outDir = QTemporaryDir() - zip = os.path.join(self.zipDir, 'fake.zip') + zip = os.path.join(self.zipDir, "fake.zip") rc, files = QgsZipUtils.unzip(zip, outDir.path()) self.assertFalse(rc) @@ -98,21 +99,21 @@ def test_unzip_file_empty(self): self.assertFalse(rc) def test_unzip_dir_not_exist(self): - zip = os.path.join(self.zipDir, 'testzip.zip') - rc, files = QgsZipUtils.unzip(zip, tempfile.gettempdir() + '/fake') + zip = os.path.join(self.zipDir, "testzip.zip") + rc, files = QgsZipUtils.unzip(zip, tempfile.gettempdir() + "/fake") self.assertFalse(rc) def test_unzip_dir_empty(self): - zip = os.path.join(self.zipDir, 'testzip.zip') - rc, files = QgsZipUtils.unzip(zip, '') + zip = os.path.join(self.zipDir, "testzip.zip") + rc, files = QgsZipUtils.unzip(zip, "") self.assertFalse(rc) def test_zip_unzip_ok(self): zip = tmpPath() - f0 = os.path.join(unitTestDataPath(), 'multipoint.shp') - f1 = os.path.join(unitTestDataPath(), 'lines.shp') - f2 = os.path.join(unitTestDataPath(), 'joins.qgs') + f0 = os.path.join(unitTestDataPath(), "multipoint.shp") + f1 = os.path.join(unitTestDataPath(), "lines.shp") + f2 = os.path.join(unitTestDataPath(), "joins.qgs") rc = QgsZipUtils.zip(zip, [f0, f1, f2]) self.assertTrue(rc) @@ -126,16 +127,16 @@ def test_zip_unzip_ok(self): def test_zip_files(self): zip = tmpPath() - f0 = os.path.join(unitTestDataPath(), 'multipoint.shp') - f1 = os.path.join(unitTestDataPath(), 'lines.shp') - f2 = os.path.join(unitTestDataPath(), 'joins.qgs') + f0 = os.path.join(unitTestDataPath(), "multipoint.shp") + f1 = os.path.join(unitTestDataPath(), "lines.shp") + f2 = os.path.join(unitTestDataPath(), "joins.qgs") rc = QgsZipUtils.zip(zip, [f0, f1, f2]) self.assertTrue(rc) files = QgsZipUtils.files(zip) - self.assertEqual(files, ['multipoint.shp', 'lines.shp', 'joins.qgs']) + self.assertEqual(files, ["multipoint.shp", "lines.shp", "joins.qgs"]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_qgszonalstatistics.py b/tests/src/python/test_qgszonalstatistics.py index 6a431d96c05e..16ca00d9ea47 100644 --- a/tests/src/python/test_qgszonalstatistics.py +++ b/tests/src/python/test_qgszonalstatistics.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Alexander Bruy' -__date__ = '15/07/2013' -__copyright__ = 'Copyright 2013, The QGIS Project' + +__author__ = "Alexander Bruy" +__date__ = "15/07/2013" +__copyright__ = "Copyright 2013, The QGIS Project" import os import shutil @@ -32,7 +33,6 @@ class TestQgsZonalStatistics(QgisTestCase): - """Tests for zonal stats class.""" def testStatistics(self): @@ -46,95 +46,97 @@ def testStatistics(self): myVector = QgsVectorLayer(myTempPath + "polys.shp", "poly", "ogr") myRaster = QgsRasterLayer(myTempPath + "edge_problem.asc", "raster", "gdal") - zs = QgsZonalStatistics(myVector, myRaster, "", 1, QgsZonalStatistics.Statistic.All) + zs = QgsZonalStatistics( + myVector, myRaster, "", 1, QgsZonalStatistics.Statistic.All + ) zs.calculateStatistics(None) feat = QgsFeature() # validate statistics for each feature request = QgsFeatureRequest().setFilterFid(0) feat = next(myVector.getFeatures(request)) - myMessage = (f'Expected: {12.0:f}\nGot: {feat[1]:f}\n') + myMessage = f"Expected: {12.0:f}\nGot: {feat[1]:f}\n" assert feat[1] == 12.0, myMessage - myMessage = (f'Expected: {8.0:f}\nGot: {feat[2]:f}\n') + myMessage = f"Expected: {8.0:f}\nGot: {feat[2]:f}\n" assert feat[2] == 8.0, myMessage - myMessage = (f'Expected: {0.666666666666667:f}\nGot: {feat[3]:f}\n') + myMessage = f"Expected: {0.666666666666667:f}\nGot: {feat[3]:f}\n" assert abs(feat[3] - 0.666666666666667) < 0.00001, myMessage - myMessage = (f'Expected: {1.0:f}\nGot: {feat[4]:f}\n') + myMessage = f"Expected: {1.0:f}\nGot: {feat[4]:f}\n" assert feat[4] == 1.0, myMessage - myMessage = (f'Expected: {0.47140452079103201:f}\nGot: {feat[5]:f}\n') + myMessage = f"Expected: {0.47140452079103201:f}\nGot: {feat[5]:f}\n" assert abs(feat[5] - 0.47140452079103201) < 0.00001, myMessage - myMessage = (f'Expected: {0.0:f}\nGot: {feat[6]:f}\n') + myMessage = f"Expected: {0.0:f}\nGot: {feat[6]:f}\n" assert feat[6] == 0.0, myMessage - myMessage = (f'Expected: {1.0:f}\nGot: {feat[7]:f}\n') + myMessage = f"Expected: {1.0:f}\nGot: {feat[7]:f}\n" assert feat[7] == 1.0, myMessage - myMessage = (f'Expected: {1.0:f}\nGot: {feat[8]:f}\n') + myMessage = f"Expected: {1.0:f}\nGot: {feat[8]:f}\n" assert feat[8] == 1.0, myMessage - myMessage = (f'Expected: {0.0:f}\nGot: {feat[9]:f}\n') + myMessage = f"Expected: {0.0:f}\nGot: {feat[9]:f}\n" assert feat[9] == 0.0, myMessage - myMessage = (f'Expected: {1.0:f}\nGot: {feat[10]:f}\n') + myMessage = f"Expected: {1.0:f}\nGot: {feat[10]:f}\n" assert feat[10] == 1.0, myMessage - myMessage = (f'Expected: {2.0:f}\nGot: {feat[11]:f}\n') + myMessage = f"Expected: {2.0:f}\nGot: {feat[11]:f}\n" assert feat[11] == 2.0, myMessage request.setFilterFid(1) feat = next(myVector.getFeatures(request)) - myMessage = (f'Expected: {9.0:f}\nGot: {feat[1]:f}\n') + myMessage = f"Expected: {9.0:f}\nGot: {feat[1]:f}\n" assert feat[1] == 9.0, myMessage - myMessage = (f'Expected: {5.0:f}\nGot: {feat[2]:f}\n') + myMessage = f"Expected: {5.0:f}\nGot: {feat[2]:f}\n" assert feat[2] == 5.0, myMessage - myMessage = (f'Expected: {0.555555555555556:f}\nGot: {feat[3]:f}\n') + myMessage = f"Expected: {0.555555555555556:f}\nGot: {feat[3]:f}\n" assert abs(feat[3] - 0.555555555555556) < 0.00001, myMessage - myMessage = (f'Expected: {1.0:f}\nGot: {feat[4]:f}\n') + myMessage = f"Expected: {1.0:f}\nGot: {feat[4]:f}\n" assert feat[4] == 1.0, myMessage - myMessage = (f'Expected: {0.49690399499995302:f}\nGot: {feat[5]:f}\n') + myMessage = f"Expected: {0.49690399499995302:f}\nGot: {feat[5]:f}\n" assert abs(feat[5] - 0.49690399499995302) < 0.00001, myMessage - myMessage = (f'Expected: {0.0:f}\nGot: {feat[6]:f}\n') + myMessage = f"Expected: {0.0:f}\nGot: {feat[6]:f}\n" assert feat[6] == 0.0, myMessage - myMessage = (f'Expected: {1.0:f}\nGot: {feat[7]:f}\n') + myMessage = f"Expected: {1.0:f}\nGot: {feat[7]:f}\n" assert feat[7] == 1.0, myMessage - myMessage = (f'Expected: {1.0:f}\nGot: {feat[8]:f}\n') + myMessage = f"Expected: {1.0:f}\nGot: {feat[8]:f}\n" assert feat[8] == 1.0, myMessage - myMessage = (f'Expected: {0.0:f}\nGot: {feat[9]:f}\n') + myMessage = f"Expected: {0.0:f}\nGot: {feat[9]:f}\n" assert feat[9] == 0.0, myMessage - myMessage = (f'Expected: {1.0:f}\nGot: {feat[10]:f}\n') + myMessage = f"Expected: {1.0:f}\nGot: {feat[10]:f}\n" assert feat[10] == 1.0, myMessage - myMessage = (f'Expected: {2.0:f}\nGot: {feat[11]:f}\n') + myMessage = f"Expected: {2.0:f}\nGot: {feat[11]:f}\n" assert feat[11] == 2.0, myMessage request.setFilterFid(2) feat = next(myVector.getFeatures(request)) - myMessage = (f'Expected: {6.0:f}\nGot: {feat[1]:f}\n') + myMessage = f"Expected: {6.0:f}\nGot: {feat[1]:f}\n" assert feat[1] == 6.0, myMessage - myMessage = (f'Expected: {5.0:f}\nGot: {feat[2]:f}\n') + myMessage = f"Expected: {5.0:f}\nGot: {feat[2]:f}\n" assert feat[2] == 5.0, myMessage - myMessage = (f'Expected: {0.833333333333333:f}\nGot: {feat[3]:f}\n') + myMessage = f"Expected: {0.833333333333333:f}\nGot: {feat[3]:f}\n" assert abs(feat[3] - 0.833333333333333) < 0.00001, myMessage - myMessage = (f'Expected: {1.0:f}\nGot: {feat[4]:f}\n') + myMessage = f"Expected: {1.0:f}\nGot: {feat[4]:f}\n" assert feat[4] == 1.0, myMessage - myMessage = (f'Expected: {0.372677996249965:f}\nGot: {feat[5]:f}\n') + myMessage = f"Expected: {0.372677996249965:f}\nGot: {feat[5]:f}\n" assert abs(feat[5] - 0.372677996249965) < 0.00001, myMessage - myMessage = (f'Expected: {0.0:f}\nGot: {feat[6]:f}\n') + myMessage = f"Expected: {0.0:f}\nGot: {feat[6]:f}\n" assert feat[6] == 0.0, myMessage - myMessage = (f'Expected: {1.0:f}\nGot: {feat[7]:f}\n') + myMessage = f"Expected: {1.0:f}\nGot: {feat[7]:f}\n" assert feat[7] == 1.0, myMessage - myMessage = (f'Expected: {1.0:f}\nGot: {feat[8]:f}\n') + myMessage = f"Expected: {1.0:f}\nGot: {feat[8]:f}\n" assert feat[8] == 1.0, myMessage - myMessage = (f'Expected: {0.0:f}\nGot: {feat[9]:f}\n') + myMessage = f"Expected: {0.0:f}\nGot: {feat[9]:f}\n" assert feat[9] == 0.0, myMessage - myMessage = (f'Expected: {1.0:f}\nGot: {feat[10]:f}\n') + myMessage = f"Expected: {1.0:f}\nGot: {feat[10]:f}\n" assert feat[10] == 1.0, myMessage - myMessage = (f'Expected: {2.0:f}\nGot: {feat[11]:f}\n') + myMessage = f"Expected: {2.0:f}\nGot: {feat[11]:f}\n" assert feat[11] == 2.0, myMessage def test_enum_conversion(self): """Test regression GH #43245""" tmp = QTemporaryDir() - origin = os.path.join(TEST_DATA_DIR, 'raster', 'band1_byte_ct_epsg4326.tif') - dest = os.path.join(tmp.path(), 'band1_byte_ct_epsg4326.tif') + origin = os.path.join(TEST_DATA_DIR, "raster", "band1_byte_ct_epsg4326.tif") + dest = os.path.join(tmp.path(), "band1_byte_ct_epsg4326.tif") shutil.copyfile(origin, dest) - layer = QgsRasterLayer(dest, 'rast', 'gdal') + layer = QgsRasterLayer(dest, "rast", "gdal") stats = QgsZonalStatistics.calculateStatistics( layer.dataProvider(), @@ -142,13 +144,16 @@ def test_enum_conversion(self): layer.rasterUnitsPerPixelX(), layer.rasterUnitsPerPixelY(), 1, - QgsZonalStatistics.Statistic.Max | QgsZonalStatistics.Statistic.Median + QgsZonalStatistics.Statistic.Max | QgsZonalStatistics.Statistic.Median, ) - self.assertEqual(sorted(list(stats.keys())), [QgsZonalStatistics.Statistic.Median, QgsZonalStatistics.Statistic.Max]) + self.assertEqual( + sorted(list(stats.keys())), + [QgsZonalStatistics.Statistic.Median, QgsZonalStatistics.Statistic.Max], + ) self.assertEqual(stats[QgsZonalStatistics.Statistic.Median], 142.0) self.assertEqual(stats[QgsZonalStatistics.Statistic.Max], 254.0) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_selective_masking.py b/tests/src/python/test_selective_masking.py index 54469760a7c2..f0d422ccdc61 100644 --- a/tests/src/python/test_selective_masking.py +++ b/tests/src/python/test_selective_masking.py @@ -9,8 +9,9 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Hugo Mercier / Oslandia' -__date__ = '28/06/2019' + +__author__ = "Hugo Mercier / Oslandia" +__date__ = "28/06/2019" import os import subprocess @@ -52,7 +53,7 @@ QgsUnitTypes, QgsWkbTypes, QgsFontUtils, - QgsSettings + QgsSettings, ) import unittest from qgis.testing import start_app, QgisTestCase @@ -89,7 +90,7 @@ def control_path_prefix(cls): @classmethod def setUpClass(cls): - super(TestSelectiveMasking, cls).setUpClass() + super().setUpClass() QCoreApplication.setOrganizationName("QGIS_Test") QCoreApplication.setOrganizationDomain("SelectiveMaskingTestBase.com") QCoreApplication.setApplicationName("SelectiveMaskingTestBase") @@ -99,7 +100,7 @@ def setUpClass(cls): def setUp(self): self.map_settings = QgsMapSettings() - crs = QgsCoordinateReferenceSystem('epsg:4326') + crs = QgsCoordinateReferenceSystem("epsg:4326") extent = QgsRectangle(-123.0, 22.7, -76.4, 46.9) self.map_settings.setBackgroundColor(QColor(152, 219, 249)) self.map_settings.setOutputSize(QSize(420, 280)) @@ -110,20 +111,26 @@ def setUp(self): self.map_settings.setExtent(extent) # load a predefined QGIS project - self.assertTrue(QgsProject.instance().read(os.path.join(unitTestDataPath(), "selective_masking.qgs"))) + self.assertTrue( + QgsProject.instance().read( + os.path.join(unitTestDataPath(), "selective_masking.qgs") + ) + ) - self.points_layer = QgsProject.instance().mapLayersByName('points')[0] - self.lines_layer = QgsProject.instance().mapLayersByName('lines')[0] + self.points_layer = QgsProject.instance().mapLayersByName("points")[0] + self.lines_layer = QgsProject.instance().mapLayersByName("lines")[0] # line layer with subsymbols - self.lines_layer2 = QgsProject.instance().mapLayersByName('lines2')[0] + self.lines_layer2 = QgsProject.instance().mapLayersByName("lines2")[0] # line layer with labels - self.lines_with_labels = QgsProject.instance().mapLayersByName('lines_with_labels')[0] + self.lines_with_labels = QgsProject.instance().mapLayersByName( + "lines_with_labels" + )[0] - self.polys_layer = QgsProject.instance().mapLayersByName('polys')[0] + self.polys_layer = QgsProject.instance().mapLayersByName("polys")[0] # polygon layer with a rule based labeling - self.polys_layer2 = QgsProject.instance().mapLayersByName('polys2')[0] + self.polys_layer2 = QgsProject.instance().mapLayersByName("polys2")[0] - self.raster_layer = QgsProject.instance().mapLayersByName('raster_layer')[0] + self.raster_layer = QgsProject.instance().mapLayersByName("raster_layer")[0] # try to fix the font for where labels are defined # in order to have more stable image comparison tests @@ -134,16 +141,18 @@ def setUp(self): font.setPointSize(32) fmt = settings.format() fmt.setFont(font) - fmt.setNamedStyle('Roman') + fmt.setNamedStyle("Roman") fmt.setSize(32) fmt.setSizeUnit(QgsUnitTypes.RenderUnit.RenderPoints) settings.setFormat(fmt) - if (layer.geometryType == QgsWkbTypes.GeometryType.PolygonGeometry): + if layer.geometryType == QgsWkbTypes.GeometryType.PolygonGeometry: settings.placement = QgsPalLayerSettings.Placement.OverPoint layer.labeling().setSettings(settings, provider) # order layers for rendering - self.map_settings.setLayers([self.points_layer, self.lines_layer, self.polys_layer]) + self.map_settings.setLayers( + [self.points_layer, self.lines_layer, self.polys_layer] + ) def get_symbollayer(self, layer, ruleId, symbollayer_ids): """ @@ -174,7 +183,9 @@ def get_symbollayer_ref(self, layer, ruleId, symbollayer_ids): symbollayer = self.get_symbollayer(layer, ruleId, symbollayer_ids) return QgsSymbolLayerReference(layer.id(), symbollayer.id()) - def check_renderings(self, map_settings, control_name, test_parallel_rendering: bool = True): + def check_renderings( + self, map_settings, control_name, test_parallel_rendering: bool = True + ): """Test a rendering with different configurations: - parallel rendering, no cache - sequential rendering, no cache @@ -193,25 +204,32 @@ def check_renderings(self, map_settings, control_name, test_parallel_rendering: if use_cache: cache = QgsMapRendererCache() # render a first time to fill the cache - renderMapToImageWithTime(map_settings, parallel=do_parallel, cache=cache) - img, t = renderMapToImageWithTime(map_settings, parallel=do_parallel, cache=cache) + renderMapToImageWithTime( + map_settings, parallel=do_parallel, cache=cache + ) + img, t = renderMapToImageWithTime( + map_settings, parallel=do_parallel, cache=cache + ) - suffix = ("_parallel" if do_parallel else "_sequential") + ("_cache" if use_cache else "_nocache") + suffix = ("_parallel" if do_parallel else "_sequential") + ( + "_cache" if use_cache else "_nocache" + ) res = self.image_check( control_name + suffix, control_name, img, control_name, allowed_mismatch=0, - color_tolerance=0 + color_tolerance=0, ) self.assertTrue(res) print(f"=== Rendering took {float(t) / 1000.0}s") - def check_layout_export(self, control_name, expected_nb_raster, layers=None, dpiTarget=None, - extent=None): + def check_layout_export( + self, control_name, expected_nb_raster, layers=None, dpiTarget=None, extent=None + ): """ Generate a PDF layout export and control the output matches expected_filename """ @@ -228,7 +246,11 @@ def check_layout_export(self, control_name, expected_nb_raster, layers=None, dpi map.setFrameEnabled(True) layout.addLayoutItem(map) map.setExtent(extent if extent is not None else self.lines_layer.extent()) - map.setLayers(layers if layers is not None else [self.points_layer, self.lines_layer, self.polys_layer]) + map.setLayers( + layers + if layers is not None + else [self.points_layer, self.lines_layer, self.polys_layer] + ) settings = QgsLayoutExporter.PdfExportSettings() @@ -242,11 +264,19 @@ def check_layout_export(self, control_name, expected_nb_raster, layers=None, dpi # Generate a readable PDF file so we count raster in it result_txt = os.path.join(temp_dir, "export.txt") - subprocess.run(["qpdf", "--qdf", "--object-streams=disable", result_filename, result_txt]) + subprocess.run( + [ + "qpdf", + "--qdf", + "--object-streams=disable", + result_filename, + result_txt, + ] + ) self.assertTrue(os.path.exists(result_txt)) - result = open(result_txt, 'rb') - result_lines = [l.decode('iso-8859-1') for l in result.readlines()] + result = open(result_txt, "rb") + result_lines = [l.decode("iso-8859-1") for l in result.readlines()] result.close() nb_raster = len([l for l in result_lines if "/Subtype /Image" in l]) self.assertEqual(nb_raster, expected_nb_raster) @@ -254,17 +284,27 @@ def check_layout_export(self, control_name, expected_nb_raster, layers=None, dpi # Generate an image from pdf to compare with expected control image # keep PDF DPI resolution (300) image_result_filename = os.path.join(temp_dir, "export.png") - subprocess.run(["pdftoppm", result_filename, - os.path.splitext(image_result_filename)[0], - "-png", "-r", "300", "-singlefile"]) + subprocess.run( + [ + "pdftoppm", + result_filename, + os.path.splitext(image_result_filename)[0], + "-png", + "-r", + "300", + "-singlefile", + ] + ) rendered_image = QImage(image_result_filename) - res = self.image_check(control_name, - control_name, - rendered_image, - control_name, - allowed_mismatch=0, - color_tolerance=0) + res = self.image_check( + control_name, + control_name, + rendered_image, + control_name, + allowed_mismatch=0, + color_tolerance=0, + ) self.assertTrue(res) @@ -275,22 +315,27 @@ def test_save_restore_references(self): # simple ids mask_layer = QgsMaskMarkerSymbolLayer() - mask_layer.setMasks([ - self.get_symbollayer_ref(self.lines_layer, "", [0]), - self.get_symbollayer_ref(self.lines_layer2, "some_id", [1, 0]), - self.get_symbollayer_ref(self.polys_layer, "some_other_id", [0]) - ]) + mask_layer.setMasks( + [ + self.get_symbollayer_ref(self.lines_layer, "", [0]), + self.get_symbollayer_ref(self.lines_layer2, "some_id", [1, 0]), + self.get_symbollayer_ref(self.polys_layer, "some_other_id", [0]), + ] + ) props = mask_layer.properties() print(f"props={props}") mask_layer2 = QgsMaskMarkerSymbolLayer.create(props) - self.assertEqual(mask_layer2.masks(), [ - self.get_symbollayer_ref(self.lines_layer, "", [0]), - self.get_symbollayer_ref(self.lines_layer2, "some_id", [1, 0]), - self.get_symbollayer_ref(self.polys_layer, "some_other_id", [0]) - ]) + self.assertEqual( + mask_layer2.masks(), + [ + self.get_symbollayer_ref(self.lines_layer, "", [0]), + self.get_symbollayer_ref(self.lines_layer2, "some_id", [1, 0]), + self.get_symbollayer_ref(self.polys_layer, "some_other_id", [0]), + ], + ) def test_migrate_old_references(self): """ @@ -307,57 +352,159 @@ def test_migrate_old_references(self): # and mask other symbol layers underneath oldMaskRefs = [ # the black part of roads - QgsSymbolLayerReference(self.lines_layer2.id(), QgsSymbolLayerId("", [1, 0])), + QgsSymbolLayerReference( + self.lines_layer2.id(), QgsSymbolLayerId("", [1, 0]) + ), # the black jets - QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", [0])), - QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", [0]))] + QgsSymbolLayerReference( + self.points_layer.id(), QgsSymbolLayerId("B52", [0]) + ), + QgsSymbolLayerReference( + self.points_layer.id(), QgsSymbolLayerId("Jet", [0]) + ), + ] fmt.mask().setMaskedSymbolLayers(oldMaskRefs) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) - self.assertEqual([slRef.symbolLayerIdV2() for slRef in self.polys_layer.labeling().settings().format().mask().maskedSymbolLayers()], - ["", "", ""]) - self.assertEqual([slRef.symbolLayerId() for slRef in self.polys_layer.labeling().settings().format().mask().maskedSymbolLayers()], - [slRef.symbolLayerId() for slRef in oldMaskRefs]) + self.assertEqual( + [ + slRef.symbolLayerIdV2() + for slRef in self.polys_layer.labeling() + .settings() + .format() + .mask() + .maskedSymbolLayers() + ], + ["", "", ""], + ) + self.assertEqual( + [ + slRef.symbolLayerId() + for slRef in self.polys_layer.labeling() + .settings() + .format() + .mask() + .maskedSymbolLayers() + ], + [slRef.symbolLayerId() for slRef in oldMaskRefs], + ) - QgsProjectFileTransform.fixOldSymbolLayerReferences(QgsProject.instance().mapLayers()) + QgsProjectFileTransform.fixOldSymbolLayerReferences( + QgsProject.instance().mapLayers() + ) - self.assertEqual([QUuid(slRef.symbolLayerIdV2()).isNull() for slRef in self.polys_layer.labeling().settings().format().mask().maskedSymbolLayers()], - [False, False, False]) - self.assertEqual([slRef.symbolLayerIdV2() for slRef in self.polys_layer.labeling().settings().format().mask().maskedSymbolLayers()], - [self.get_symbollayer(self.lines_layer2, "", [1, 0]).id(), - self.get_symbollayer(self.points_layer, "B52", [0]).id(), - self.get_symbollayer(self.points_layer, "Jet", [0]).id()]) - self.assertEqual([slRef.symbolLayerId() for slRef in self.polys_layer.labeling().settings().format().mask().maskedSymbolLayers()], - [QgsSymbolLayerId(), QgsSymbolLayerId(), QgsSymbolLayerId()]) + self.assertEqual( + [ + QUuid(slRef.symbolLayerIdV2()).isNull() + for slRef in self.polys_layer.labeling() + .settings() + .format() + .mask() + .maskedSymbolLayers() + ], + [False, False, False], + ) + self.assertEqual( + [ + slRef.symbolLayerIdV2() + for slRef in self.polys_layer.labeling() + .settings() + .format() + .mask() + .maskedSymbolLayers() + ], + [ + self.get_symbollayer(self.lines_layer2, "", [1, 0]).id(), + self.get_symbollayer(self.points_layer, "B52", [0]).id(), + self.get_symbollayer(self.points_layer, "Jet", [0]).id(), + ], + ) + self.assertEqual( + [ + slRef.symbolLayerId() + for slRef in self.polys_layer.labeling() + .settings() + .format() + .mask() + .maskedSymbolLayers() + ], + [QgsSymbolLayerId(), QgsSymbolLayerId(), QgsSymbolLayerId()], + ) # test symbol layer masks - p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) + p = QgsMarkerSymbol.createSimple({"color": "#fdbf6f", "size": "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) - circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) + circle_symbol = QgsMarkerSymbol.createSimple({"size": "10"}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) - oldMaskRefs = [QgsSymbolLayerReference(self.lines_layer2.id(), QgsSymbolLayerId("", [1, 0]))] + oldMaskRefs = [ + QgsSymbolLayerReference( + self.lines_layer2.id(), QgsSymbolLayerId("", [1, 0]) + ) + ] mask_layer.setMasks(oldMaskRefs) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) - self.assertEqual([slRef.symbolLayerIdV2() for slRef in self.points_layer.renderer().symbol().symbolLayers()[1].masks()], - [""]) - self.assertEqual([slRef.symbolLayerId() for slRef in self.points_layer.renderer().symbol().symbolLayers()[1].masks()], - [slRef.symbolLayerId() for slRef in oldMaskRefs]) + self.assertEqual( + [ + slRef.symbolLayerIdV2() + for slRef in self.points_layer.renderer() + .symbol() + .symbolLayers()[1] + .masks() + ], + [""], + ) + self.assertEqual( + [ + slRef.symbolLayerId() + for slRef in self.points_layer.renderer() + .symbol() + .symbolLayers()[1] + .masks() + ], + [slRef.symbolLayerId() for slRef in oldMaskRefs], + ) - QgsProjectFileTransform.fixOldSymbolLayerReferences(QgsProject.instance().mapLayers()) + QgsProjectFileTransform.fixOldSymbolLayerReferences( + QgsProject.instance().mapLayers() + ) - self.assertEqual([QUuid(slRef.symbolLayerIdV2()).isNull() for slRef in self.points_layer.renderer().symbol().symbolLayers()[1].masks()], - [False]) - self.assertEqual([slRef.symbolLayerIdV2() for slRef in self.points_layer.renderer().symbol().symbolLayers()[1].masks()], - [self.get_symbollayer(self.lines_layer2, "", [1, 0]).id()]) - self.assertEqual([slRef.symbolLayerId() for slRef in self.points_layer.renderer().symbol().symbolLayers()[1].masks()], - [QgsSymbolLayerId()]) + self.assertEqual( + [ + QUuid(slRef.symbolLayerIdV2()).isNull() + for slRef in self.points_layer.renderer() + .symbol() + .symbolLayers()[1] + .masks() + ], + [False], + ) + self.assertEqual( + [ + slRef.symbolLayerIdV2() + for slRef in self.points_layer.renderer() + .symbol() + .symbolLayers()[1] + .masks() + ], + [self.get_symbollayer(self.lines_layer2, "", [1, 0]).id()], + ) + self.assertEqual( + [ + slRef.symbolLayerId() + for slRef in self.points_layer.renderer() + .symbol() + .symbolLayers()[1] + .masks() + ], + [QgsSymbolLayerId()], + ) def test_label_mask(self): # modify labeling settings @@ -367,12 +514,15 @@ def test_label_mask(self): fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]), - # the black jets - self.get_symbollayer_ref(self.points_layer, "B52", [0]), - self.get_symbollayer_ref(self.points_layer, "Jet", [0])]) + fmt.mask().setMaskedSymbolLayers( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]), + # the black jets + self.get_symbollayer_ref(self.points_layer, "B52", [0]), + self.get_symbollayer_ref(self.points_layer, "Jet", [0]), + ] + ) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) @@ -390,12 +540,15 @@ def test_multiple_label_masks_different_sets(self): fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # the black part of roads - self.get_symbollayer_ref(self.lines_with_labels, "", [0]), - # the black jets - self.get_symbollayer_ref(self.points_layer, "B52", [0]), - self.get_symbollayer_ref(self.points_layer, "Jet", [0])]) + fmt.mask().setMaskedSymbolLayers( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_with_labels, "", [0]), + # the black jets + self.get_symbollayer_ref(self.points_layer, "B52", [0]), + self.get_symbollayer_ref(self.points_layer, "Jet", [0]), + ] + ) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) @@ -410,18 +563,24 @@ def test_multiple_label_masks_different_sets(self): fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # polygons - self.get_symbollayer_ref(self.polys_layer, "", [0]), - ]) + fmt.mask().setMaskedSymbolLayers( + [ + # polygons + self.get_symbollayer_ref(self.polys_layer, "", [0]), + ] + ) label_settings.setFormat(fmt) self.lines_with_labels.labeling().setSettings(label_settings) # new map settings with a line symbology that has labels - self.map_settings.setLayers([self.points_layer, self.lines_with_labels, self.polys_layer]) + self.map_settings.setLayers( + [self.points_layer, self.lines_with_labels, self.polys_layer] + ) self.check_renderings(self.map_settings, "multiple_label_masks_different_sets") # restore map settings - self.map_settings.setLayers([self.points_layer, self.lines_layer, self.polys_layer]) + self.map_settings.setLayers( + [self.points_layer, self.lines_layer, self.polys_layer] + ) def test_multiple_label_masks_same_set(self): # modify labeling settings of the polys layer @@ -431,10 +590,12 @@ def test_multiple_label_masks_same_set(self): fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # the black part of roads - self.get_symbollayer_ref(self.lines_with_labels, "", [0]), - ]) + fmt.mask().setMaskedSymbolLayers( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_with_labels, "", [0]), + ] + ) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) @@ -449,22 +610,30 @@ def test_multiple_label_masks_same_set(self): fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # the black part of roads - self.get_symbollayer_ref(self.lines_with_labels, "", [0]), - ]) + fmt.mask().setMaskedSymbolLayers( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_with_labels, "", [0]), + ] + ) label_settings.setFormat(fmt) self.lines_with_labels.labeling().setSettings(label_settings) # new map settings with a line symbology that has labels - self.map_settings.setLayers([self.points_layer, self.lines_with_labels, self.polys_layer]) + self.map_settings.setLayers( + [self.points_layer, self.lines_with_labels, self.polys_layer] + ) self.check_renderings(self.map_settings, "multiple_label_masks_same_set") # restore map settings - self.map_settings.setLayers([self.points_layer, self.lines_layer, self.polys_layer]) + self.map_settings.setLayers( + [self.points_layer, self.lines_layer, self.polys_layer] + ) def test_label_mask_subsymbol(self): # new map settings with a line symbology that has sub symbols - self.map_settings.setLayers([self.points_layer, self.lines_layer2, self.polys_layer]) + self.map_settings.setLayers( + [self.points_layer, self.lines_layer2, self.polys_layer] + ) # modify labeling settings label_settings = self.polys_layer.labeling().settings() @@ -473,12 +642,15 @@ def test_label_mask_subsymbol(self): fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # mask only vertical segments of "roads" - self.get_symbollayer_ref(self.lines_layer2, "", [1, 0]), - # the black jets - self.get_symbollayer_ref(self.points_layer, "B52", [0]), - self.get_symbollayer_ref(self.points_layer, "Jet", [0])]) + fmt.mask().setMaskedSymbolLayers( + [ + # mask only vertical segments of "roads" + self.get_symbollayer_ref(self.lines_layer2, "", [1, 0]), + # the black jets + self.get_symbollayer_ref(self.points_layer, "B52", [0]), + self.get_symbollayer_ref(self.points_layer, "Jet", [0]), + ] + ) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) @@ -489,27 +661,40 @@ def test_label_mask_subsymbol(self): self.check_renderings(self.map_settings, "label_mask_subsymbol") # restore original map settings - self.map_settings.setLayers([self.points_layer, self.lines_layer, self.polys_layer]) + self.map_settings.setLayers( + [self.points_layer, self.lines_layer, self.polys_layer] + ) def test_label_mask_dd(self): - """ test label mask with data defined properties """ + """test label mask with data defined properties""" label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() fmt.mask().setEnabled(False) fmt.mask().setSize(1.0) fmt.mask().setOpacity(0.42) # mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]), - # the black jets - self.get_symbollayer_ref(self.points_layer, "B52", [0]), - self.get_symbollayer_ref(self.points_layer, "Jet", [0])]) + fmt.mask().setMaskedSymbolLayers( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]), + # the black jets + self.get_symbollayer_ref(self.points_layer, "B52", [0]), + self.get_symbollayer_ref(self.points_layer, "Jet", [0]), + ] + ) # overwrite with data-defined properties - fmt.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.MaskEnabled, QgsProperty.fromExpression('1')) - fmt.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.MaskBufferSize, QgsProperty.fromExpression('4.0')) - fmt.dataDefinedProperties().setProperty(QgsPalLayerSettings.Property.MaskOpacity, QgsProperty.fromExpression('100.0')) + fmt.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.MaskEnabled, QgsProperty.fromExpression("1") + ) + fmt.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.MaskBufferSize, + QgsProperty.fromExpression("4.0"), + ) + fmt.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.MaskOpacity, + QgsProperty.fromExpression("100.0"), + ) context = QgsRenderContext() fmt.updateDataDefinedProperties(context) @@ -525,11 +710,13 @@ def test_label_mask_dd(self): def test_label_mask_rule_labeling(self): # new map settings with a rule based labeling - self.map_settings.setLayers([self.points_layer, self.lines_layer, self.polys_layer2]) + self.map_settings.setLayers( + [self.points_layer, self.lines_layer, self.polys_layer2] + ) # modify labeling settings of one rule for child in self.polys_layer2.labeling().rootRule().children(): - if child.description() == 'Tadam': + if child.description() == "Tadam": break label_settings = child.settings() label_settings.priority = 3 @@ -538,19 +725,22 @@ def test_label_mask_rule_labeling(self): fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]), - # the black jets - self.get_symbollayer_ref(self.points_layer, "B52", [0]), - self.get_symbollayer_ref(self.points_layer, "Jet", [0])]) + fmt.mask().setMaskedSymbolLayers( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]), + # the black jets + self.get_symbollayer_ref(self.points_layer, "B52", [0]), + self.get_symbollayer_ref(self.points_layer, "Jet", [0]), + ] + ) label_settings.setFormat(fmt) child.setSettings(label_settings) # modify labeling settings of another rule for child in self.polys_layer2.labeling().rootRule().children(): - if child.description() != 'Tadam': + if child.description() != "Tadam": break label_settings = child.settings() fmt = label_settings.format() @@ -558,17 +748,21 @@ def test_label_mask_rule_labeling(self): fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # the polygons - self.get_symbollayer_ref(self.polys_layer2, "", [0]), - ]) + fmt.mask().setMaskedSymbolLayers( + [ + # the polygons + self.get_symbollayer_ref(self.polys_layer2, "", [0]), + ] + ) label_settings.setFormat(fmt) child.setSettings(label_settings) self.check_renderings(self.map_settings, "rule_label_mask") # restore map settings - self.map_settings.setLayers([self.points_layer, self.lines_layer, self.polys_layer]) + self.map_settings.setLayers( + [self.points_layer, self.lines_layer, self.polys_layer] + ) def test_label_mask_symbol_levels(self): # modify labeling settings @@ -578,12 +772,15 @@ def test_label_mask_symbol_levels(self): fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]), - # the black jets - self.get_symbollayer_ref(self.points_layer, "B52", [0]), - self.get_symbollayer_ref(self.points_layer, "Jet", [0])]) + fmt.mask().setMaskedSymbolLayers( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]), + # the black jets + self.get_symbollayer_ref(self.points_layer, "B52", [0]), + self.get_symbollayer_ref(self.points_layer, "Jet", [0]), + ] + ) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) @@ -597,16 +794,18 @@ def test_label_mask_symbol_levels(self): self.check_renderings(self.map_settings, "label_mask_symbol_levels") def test_symbol_layer_mask(self): - p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) + p = QgsMarkerSymbol.createSimple({"color": "#fdbf6f", "size": "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) - circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) + circle_symbol = QgsMarkerSymbol.createSimple({"size": "10"}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) - mask_layer.setMasks([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]), - ]) + mask_layer.setMasks( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]), + ] + ) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) @@ -617,16 +816,18 @@ def test_multiple_masks_same_symbol_layer(self): # # 1. a symbol layer mask # - p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) + p = QgsMarkerSymbol.createSimple({"color": "#fdbf6f", "size": "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) - circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) + circle_symbol = QgsMarkerSymbol.createSimple({"size": "10"}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) - mask_layer.setMasks([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]), - ]) + mask_layer.setMasks( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]), + ] + ) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) @@ -641,10 +842,12 @@ def test_multiple_masks_same_symbol_layer(self): fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]) - ]) + fmt.mask().setMaskedSymbolLayers( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]) + ] + ) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) @@ -652,20 +855,23 @@ def test_multiple_masks_same_symbol_layer(self): def test_multiple_masks_different_symbol_layers_same_layer(self): """Test multiple masks that occlude different symbol layers of the same layer. - The UI should disallow this settings. We test here that only one mask is retained""" + The UI should disallow this settings. We test here that only one mask is retained + """ # # 1. a symbol layer mask # - p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) + p = QgsMarkerSymbol.createSimple({"color": "#fdbf6f", "size": "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) - circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) + circle_symbol = QgsMarkerSymbol.createSimple({"size": "10"}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) - mask_layer.setMasks([ - # the yellow part of roads - self.get_symbollayer_ref(self.lines_layer, "", [1]), - ]) + mask_layer.setMasks( + [ + # the yellow part of roads + self.get_symbollayer_ref(self.lines_layer, "", [1]), + ] + ) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) @@ -680,10 +886,12 @@ def test_multiple_masks_different_symbol_layers_same_layer(self): fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]) - ]) + fmt.mask().setMaskedSymbolLayers( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]) + ] + ) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) @@ -691,20 +899,23 @@ def test_multiple_masks_different_symbol_layers_same_layer(self): def test_multiple_masks_different_symbol_layers_same_layer2(self): """Test multiple masks that occlude different symbol layers of the same layer - 2nd possible order - The UI should disallow this settings. We test here that only one mask is retained""" + The UI should disallow this settings. We test here that only one mask is retained + """ # # 1. a symbol layer mask # - p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) + p = QgsMarkerSymbol.createSimple({"color": "#fdbf6f", "size": "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) - circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) + circle_symbol = QgsMarkerSymbol.createSimple({"size": "10"}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) - mask_layer.setMasks([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]), - ]) + mask_layer.setMasks( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]), + ] + ) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) @@ -719,10 +930,12 @@ def test_multiple_masks_different_symbol_layers_same_layer2(self): fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # the yellow part of roads - self.get_symbollayer_ref(self.lines_layer, "", [1]) - ]) + fmt.mask().setMaskedSymbolLayers( + [ + # the yellow part of roads + self.get_symbollayer_ref(self.lines_layer, "", [1]) + ] + ) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) @@ -732,20 +945,24 @@ def test_mask_symbollayer_preview(self): # # Masks should be visible in previews # - p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) + p = QgsMarkerSymbol.createSimple({"color": "#fdbf6f", "size": "7"}) - circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) + circle_symbol = QgsMarkerSymbol.createSimple({"size": "10"}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) p.insertSymbolLayer(0, mask_layer) for control_name, render_function in [ - ("as_image", lambda: p.asImage(QSize(64, 64)).save(tmp)), - ("as_big_preview", lambda: p.bigSymbolPreviewImage().save(tmp)), - ("sl_preview", lambda: - QgsSymbolLayerUtils.symbolLayerPreviewIcon(mask_layer, - QgsUnitTypes.RenderUnit.RenderPixels, - QSize(64, 64)).pixmap(QSize(64, 64)).save(tmp)) + ("as_image", lambda: p.asImage(QSize(64, 64)).save(tmp)), + ("as_big_preview", lambda: p.bigSymbolPreviewImage().save(tmp)), + ( + "sl_preview", + lambda: QgsSymbolLayerUtils.symbolLayerPreviewIcon( + mask_layer, QgsUnitTypes.RenderUnit.RenderPixels, QSize(64, 64) + ) + .pixmap(QSize(64, 64)) + .save(tmp), + ), ]: with tempfile.TemporaryDirectory() as temp_dir: tmp = os.path.join(temp_dir, "render.png") @@ -759,32 +976,37 @@ def test_mask_symbollayer_preview(self): rendered_image, control_name, allowed_mismatch=90, - color_tolerance=0 + color_tolerance=0, ) self.assertTrue(res) def test_mask_with_effect(self): - p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) + p = QgsMarkerSymbol.createSimple({"color": "#fdbf6f", "size": "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) - circle_symbol = QgsMarkerSymbol.createSimple({'size': '12'}) + circle_symbol = QgsMarkerSymbol.createSimple({"size": "12"}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) - mask_layer.setMasks([ - # the yellow part of roads - self.get_symbollayer_ref(self.lines_layer, "", [1]), - ]) + mask_layer.setMasks( + [ + # the yellow part of roads + self.get_symbollayer_ref(self.lines_layer, "", [1]), + ] + ) # add an outer glow effect to the mask layer - blur = QgsOuterGlowEffect.create({"enabled": "1", - "blur_level": "6.445", - "blur_unit": "MM", - "opacity": "1", - "spread": "0.6", - "spread_unit": "MM", - "color1": "0,0,255,255", - "draw_mode": "2" - }) + blur = QgsOuterGlowEffect.create( + { + "enabled": "1", + "blur_level": "6.445", + "blur_unit": "MM", + "opacity": "1", + "spread": "0.6", + "spread_unit": "MM", + "color1": "0,0,255,255", + "draw_mode": "2", + } + ) mask_layer.setPaintEffect(blur) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) @@ -799,23 +1021,29 @@ def test_label_mask_with_effect(self): fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]), - # the black jets - self.get_symbollayer_ref(self.points_layer, "B52", [0]), - self.get_symbollayer_ref(self.points_layer, "Jet", [0])]) + fmt.mask().setMaskedSymbolLayers( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]), + # the black jets + self.get_symbollayer_ref(self.points_layer, "B52", [0]), + self.get_symbollayer_ref(self.points_layer, "Jet", [0]), + ] + ) # add an outer glow effect to the mask - blur = QgsOuterGlowEffect.create({"enabled": "1", - "blur_level": "6.445", - "blur_unit": "MM", - "opacity": "1", - "spread": "0.6", - "spread_unit": "MM", - "color1": "0,0,255,255", - "draw_mode": "2" - }) + blur = QgsOuterGlowEffect.create( + { + "enabled": "1", + "blur_level": "6.445", + "blur_unit": "MM", + "opacity": "1", + "spread": "0.6", + "spread_unit": "MM", + "color1": "0,0,255,255", + "draw_mode": "2", + } + ) fmt.mask().setPaintEffect(blur) label_settings.setFormat(fmt) @@ -830,7 +1058,9 @@ def test_label_mask_with_effect(self): self.map_settings.setFlag(Qgis.MapSettingsFlag.ForceVectorOutput, True) # skip parallel rendering for this check, as force vector output is ignored when parallel rendering # is used - self.check_renderings(self.map_settings, "label_mask_with_effect", test_parallel_rendering=False) + self.check_renderings( + self.map_settings, "label_mask_with_effect", test_parallel_rendering=False + ) def test_different_dpi_target(self): """Test with raster layer and a target dpi""" @@ -842,14 +1072,19 @@ def test_different_dpi_target(self): fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0])]) + fmt.mask().setMaskedSymbolLayers( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]) + ] + ) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) - self.map_settings.setLayers([self.lines_layer, self.polys_layer, self.raster_layer]) + self.map_settings.setLayers( + [self.lines_layer, self.polys_layer, self.raster_layer] + ) self.map_settings.setDpiTarget(300) self.check_renderings(self.map_settings, "different_dpi_target") @@ -870,12 +1105,15 @@ def test_layout_export(self): fmt.mask().setEnabled(True) fmt.mask().setSize(1.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]), - # the black jets - self.get_symbollayer_ref(self.points_layer, "B52", [0]), - self.get_symbollayer_ref(self.points_layer, "Jet", [0])]) + fmt.mask().setMaskedSymbolLayers( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]), + # the black jets + self.get_symbollayer_ref(self.points_layer, "B52", [0]), + self.get_symbollayer_ref(self.points_layer, "Jet", [0]), + ] + ) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) @@ -894,23 +1132,29 @@ def test_layout_export_w_effects(self): fmt.mask().setEnabled(True) fmt.mask().setSize(1.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]), - # the black jets - self.get_symbollayer_ref(self.points_layer, "B52", [0]), - self.get_symbollayer_ref(self.points_layer, "Jet", [0])]) + fmt.mask().setMaskedSymbolLayers( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]), + # the black jets + self.get_symbollayer_ref(self.points_layer, "B52", [0]), + self.get_symbollayer_ref(self.points_layer, "Jet", [0]), + ] + ) # add an outer glow effect to the mask - blur = QgsOuterGlowEffect.create({"enabled": "1", - "blur_level": "3.445", - "blur_unit": "MM", - "opacity": "1", - "spread": "0.06", - "spread_unit": "MM", - "color1": "0,0,255,255", - "draw_mode": "2" - }) + blur = QgsOuterGlowEffect.create( + { + "enabled": "1", + "blur_level": "3.445", + "blur_unit": "MM", + "opacity": "1", + "spread": "0.06", + "spread_unit": "MM", + "color1": "0,0,255,255", + "draw_mode": "2", + } + ) fmt.mask().setPaintEffect(blur) label_settings.setFormat(fmt) @@ -922,16 +1166,18 @@ def test_layout_export_w_effects(self): def test_layout_export_marker_masking(self): """Test mask effects in a layout export with a marker symbol masking""" - p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "3"}) + p = QgsMarkerSymbol.createSimple({"color": "#fdbf6f", "size": "3"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) - circle_symbol = QgsMarkerSymbol.createSimple({'size': '6'}) + circle_symbol = QgsMarkerSymbol.createSimple({"size": "6"}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) - mask_layer.setMasks([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]), - ]) + mask_layer.setMasks( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]), + ] + ) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) @@ -940,27 +1186,32 @@ def test_layout_export_marker_masking(self): def test_layout_export_marker_masking_w_effects(self): """Test mask effects in a layout export with a marker symbol masking""" - p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "3"}) + p = QgsMarkerSymbol.createSimple({"color": "#fdbf6f", "size": "3"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) - circle_symbol = QgsMarkerSymbol.createSimple({'size': '6'}) + circle_symbol = QgsMarkerSymbol.createSimple({"size": "6"}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) - mask_layer.setMasks([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]), - ]) + mask_layer.setMasks( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]), + ] + ) # add an outer glow effect to the mask - blur = QgsOuterGlowEffect.create({"enabled": "1", - "blur_level": "3.445", - "blur_unit": "MM", - "opacity": "1", - "spread": "0.06", - "spread_unit": "MM", - "color1": "0,0,255,255", - "draw_mode": "2" - }) + blur = QgsOuterGlowEffect.create( + { + "enabled": "1", + "blur_level": "3.445", + "blur_unit": "MM", + "opacity": "1", + "spread": "0.06", + "spread_unit": "MM", + "color1": "0,0,255,255", + "draw_mode": "2", + } + ) # TODO try to set the mask effect on p the marker symbol -> result should be the same mask_layer.setPaintEffect(blur) @@ -987,18 +1238,25 @@ def test_layout_export_w_raster(self): fmt.mask().setEnabled(True) fmt.mask().setSize(1.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]), - # the black jets - self.get_symbollayer_ref(self.points_layer, "B52", [0]), - self.get_symbollayer_ref(self.points_layer, "Jet", [0])]) + fmt.mask().setMaskedSymbolLayers( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]), + # the black jets + self.get_symbollayer_ref(self.points_layer, "B52", [0]), + self.get_symbollayer_ref(self.points_layer, "Jet", [0]), + ] + ) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) # 1 raster : the raster layer - self.check_layout_export("layout_export_w_raster", 1, [self.lines_layer, self.polys_layer, self.raster_layer]) + self.check_layout_export( + "layout_export_w_raster", + 1, + [self.lines_layer, self.polys_layer, self.raster_layer], + ) def test_layout_export_w_force_raster_render(self): """ @@ -1007,37 +1265,45 @@ def test_layout_export_w_force_raster_render(self): the marker layer forced as raster """ - p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "3"}) + p = QgsMarkerSymbol.createSimple({"color": "#fdbf6f", "size": "3"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) - circle_symbol = QgsMarkerSymbol.createSimple({'size': '6'}) + circle_symbol = QgsMarkerSymbol.createSimple({"size": "6"}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) - mask_layer.setMasks([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]), - ]) + mask_layer.setMasks( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]), + ] + ) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) self.points_layer.renderer().setForceRasterRender(True) # 2 rasters : Image and its mask for the points layer - self.check_layout_export("layout_export_force_raster_render", 2, [self.points_layer, self.lines_layer]) + self.check_layout_export( + "layout_export_force_raster_render", + 2, + [self.points_layer, self.lines_layer], + ) def test_layout_export_marker_masking_w_transparency(self): """Test layout export with a marker symbol masking which has an opacity lower than 1""" - p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "3"}) + p = QgsMarkerSymbol.createSimple({"color": "#fdbf6f", "size": "3"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) - circle_symbol = QgsMarkerSymbol.createSimple({'size': '6'}) + circle_symbol = QgsMarkerSymbol.createSimple({"size": "6"}) circle_symbol.setOpacity(0.5) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) - mask_layer.setMasks([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]), - ]) + mask_layer.setMasks( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]), + ] + ) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) @@ -1058,12 +1324,15 @@ def test_layout_export_text_masking_w_transparency(self): fmt.mask().setOpacity(0.5) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]), - # the black jets - self.get_symbollayer_ref(self.points_layer, "B52", [0]), - self.get_symbollayer_ref(self.points_layer, "Jet", [0])]) + fmt.mask().setMaskedSymbolLayers( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]), + # the black jets + self.get_symbollayer_ref(self.points_layer, "B52", [0]), + self.get_symbollayer_ref(self.points_layer, "Jet", [0]), + ] + ) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) @@ -1084,19 +1353,26 @@ def test_different_dpi_target_vector(self): fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0])]) + fmt.mask().setMaskedSymbolLayers( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]) + ] + ) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) - self.map_settings.setLayers([self.lines_layer, self.polys_layer, self.raster_layer]) + self.map_settings.setLayers( + [self.lines_layer, self.polys_layer, self.raster_layer] + ) self.map_settings.setOutputDpi(81) self.map_settings.setDpiTarget(300) self.map_settings.setFlag(Qgis.MapSettingsFlag.ForceVectorOutput, True) - image = QImage(self.map_settings.deviceOutputSize(), self.map_settings.outputImageFormat()) + image = QImage( + self.map_settings.deviceOutputSize(), self.map_settings.outputImageFormat() + ) image.setDevicePixelRatio(self.map_settings.devicePixelRatio()) image.setDotsPerMeterX(int(1000 * self.map_settings.outputDpi() / 25.4)) image.setDotsPerMeterY(int(1000 * self.map_settings.outputDpi() / 25.4)) @@ -1115,13 +1391,15 @@ def test_different_dpi_target_vector(self): image, control_name, allowed_mismatch=0, - color_tolerance=0 + color_tolerance=0, ) self.assertTrue(res) # Same test with high dpi self.map_settings.setDevicePixelRatio(2) - image = QImage(self.map_settings.deviceOutputSize(), self.map_settings.outputImageFormat()) + image = QImage( + self.map_settings.deviceOutputSize(), self.map_settings.outputImageFormat() + ) image.setDevicePixelRatio(self.map_settings.devicePixelRatio()) image.setDotsPerMeterX(int(1000 * self.map_settings.outputDpi() / 25.4)) image.setDotsPerMeterY(int(1000 * self.map_settings.outputDpi() / 25.4)) @@ -1140,7 +1418,7 @@ def test_different_dpi_target_vector(self): image, control_name, allowed_mismatch=0, - color_tolerance=0 + color_tolerance=0, ) self.assertTrue(res) @@ -1148,16 +1426,18 @@ def test_layout_export_2_sources_masking(self): """Test masking with 2 different sources""" # mask with points layer circles... - p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "3"}) + p = QgsMarkerSymbol.createSimple({"color": "#fdbf6f", "size": "3"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) - circle_symbol = QgsMarkerSymbol.createSimple({'size': '6'}) + circle_symbol = QgsMarkerSymbol.createSimple({"size": "6"}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) - mask_layer.setMasks([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]), - ]) + mask_layer.setMasks( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]), + ] + ) self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) # ...and with text @@ -1168,9 +1448,12 @@ def test_layout_export_2_sources_masking(self): fmt.mask().setEnabled(True) fmt.mask().setSize(1.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0])]) + fmt.mask().setMaskedSymbolLayers( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]) + ] + ) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) @@ -1181,9 +1464,15 @@ def test_raster_line_pattern_fill(self): """ Test raster rendering and masking when a line pattern fill symbol layer is involved """ - self.assertTrue(QgsProject.instance().read(os.path.join(unitTestDataPath(), "selective_masking_fill_symbollayer.qgz"))) + self.assertTrue( + QgsProject.instance().read( + os.path.join( + unitTestDataPath(), "selective_masking_fill_symbollayer.qgz" + ) + ) + ) - layer = QgsProject.instance().mapLayersByName('line_pattern_fill')[0] + layer = QgsProject.instance().mapLayersByName("line_pattern_fill")[0] self.assertTrue(layer) self.assertTrue(len(layer.labeling().subProviders()), 1) @@ -1196,7 +1485,7 @@ def test_raster_line_pattern_fill(self): layer.labeling().setSettings(settings) map_settings = QgsMapSettings() - crs = QgsCoordinateReferenceSystem('epsg:4326') + crs = QgsCoordinateReferenceSystem("epsg:4326") extent = QgsRectangle(0, -1, 0.5, 0.8) map_settings.setBackgroundColor(QColor(152, 219, 249)) map_settings.setOutputSize(QSize(420, 280)) @@ -1214,9 +1503,15 @@ def test_vector_line_pattern_fill(self): """ Test vector rendering and masking when a line pattern fill symbol layer is involved """ - self.assertTrue(QgsProject.instance().read(os.path.join(unitTestDataPath(), "selective_masking_fill_symbollayer.qgz"))) + self.assertTrue( + QgsProject.instance().read( + os.path.join( + unitTestDataPath(), "selective_masking_fill_symbollayer.qgz" + ) + ) + ) - layer = QgsProject.instance().mapLayersByName('line_pattern_fill')[0] + layer = QgsProject.instance().mapLayersByName("line_pattern_fill")[0] self.assertTrue(layer) self.assertTrue(len(layer.labeling().subProviders()), 1) @@ -1229,8 +1524,13 @@ def test_vector_line_pattern_fill(self): layer.labeling().setSettings(settings) map_settings = QgsMapSettings() - crs = QgsCoordinateReferenceSystem('epsg:4326') - extent = QgsRectangle(-1.0073971192118132, -0.7875782447946843, 0.87882587741257345, 0.51640826470600099) + crs = QgsCoordinateReferenceSystem("epsg:4326") + extent = QgsRectangle( + -1.0073971192118132, + -0.7875782447946843, + 0.87882587741257345, + 0.51640826470600099, + ) map_settings.setBackgroundColor(QColor(152, 219, 249)) map_settings.setOutputSize(QSize(420, 280)) map_settings.setOutputDpi(72) @@ -1240,15 +1540,23 @@ def test_vector_line_pattern_fill(self): map_settings.setLayers([layer]) - self.check_layout_export("layout_export_line_pattern_fill", 0, [layer], extent=extent) + self.check_layout_export( + "layout_export_line_pattern_fill", 0, [layer], extent=extent + ) def test_vector_point_pattern_fill(self): """ Test vector rendering and masking when a point pattern fill symbol layer is involved """ - self.assertTrue(QgsProject.instance().read(os.path.join(unitTestDataPath(), "selective_masking_fill_symbollayer.qgz"))) + self.assertTrue( + QgsProject.instance().read( + os.path.join( + unitTestDataPath(), "selective_masking_fill_symbollayer.qgz" + ) + ) + ) - layer = QgsProject.instance().mapLayersByName('point_pattern_fill')[0] + layer = QgsProject.instance().mapLayersByName("point_pattern_fill")[0] self.assertTrue(layer) self.assertTrue(len(layer.labeling().subProviders()), 1) @@ -1261,8 +1569,13 @@ def test_vector_point_pattern_fill(self): layer.labeling().setSettings(settings) map_settings = QgsMapSettings() - crs = QgsCoordinateReferenceSystem('epsg:4326') - extent = QgsRectangle(-1.0073971192118132, -0.7875782447946843, 0.87882587741257345, 0.51640826470600099) + crs = QgsCoordinateReferenceSystem("epsg:4326") + extent = QgsRectangle( + -1.0073971192118132, + -0.7875782447946843, + 0.87882587741257345, + 0.51640826470600099, + ) map_settings.setBackgroundColor(QColor(152, 219, 249)) map_settings.setOutputSize(QSize(420, 280)) map_settings.setOutputDpi(72) @@ -1273,15 +1586,23 @@ def test_vector_point_pattern_fill(self): map_settings.setLayers([layer]) - self.check_layout_export("layout_export_point_pattern_fill", 0, [layer], extent=extent) + self.check_layout_export( + "layout_export_point_pattern_fill", 0, [layer], extent=extent + ) def test_vector_centroid_fill(self): """ Test masking when a centroid fill symbol layer is involved """ - self.assertTrue(QgsProject.instance().read(os.path.join(unitTestDataPath(), "selective_masking_fill_symbollayer.qgz"))) + self.assertTrue( + QgsProject.instance().read( + os.path.join( + unitTestDataPath(), "selective_masking_fill_symbollayer.qgz" + ) + ) + ) - layer = QgsProject.instance().mapLayersByName('centroid_fill')[0] + layer = QgsProject.instance().mapLayersByName("centroid_fill")[0] self.assertTrue(layer) self.assertTrue(len(layer.labeling().subProviders()), 1) @@ -1294,8 +1615,13 @@ def test_vector_centroid_fill(self): layer.labeling().setSettings(settings) map_settings = QgsMapSettings() - crs = QgsCoordinateReferenceSystem('epsg:4326') - extent = QgsRectangle(-1.0073971192118132, -0.7875782447946843, 0.87882587741257345, 0.51640826470600099) + crs = QgsCoordinateReferenceSystem("epsg:4326") + extent = QgsRectangle( + -1.0073971192118132, + -0.7875782447946843, + 0.87882587741257345, + 0.51640826470600099, + ) map_settings.setBackgroundColor(QColor(152, 219, 249)) map_settings.setOutputSize(QSize(420, 280)) map_settings.setOutputDpi(72) @@ -1305,15 +1631,23 @@ def test_vector_centroid_fill(self): map_settings.setLayers([layer]) - self.check_layout_export("layout_export_centroid_fill", 0, [layer], extent=extent) + self.check_layout_export( + "layout_export_centroid_fill", 0, [layer], extent=extent + ) def test_vector_random_generator_fill(self): """ Test masking when a random generator fill symbol layer is involved """ - self.assertTrue(QgsProject.instance().read(os.path.join(unitTestDataPath(), "selective_masking_fill_symbollayer.qgz"))) + self.assertTrue( + QgsProject.instance().read( + os.path.join( + unitTestDataPath(), "selective_masking_fill_symbollayer.qgz" + ) + ) + ) - layer = QgsProject.instance().mapLayersByName('random_generator_fill')[0] + layer = QgsProject.instance().mapLayersByName("random_generator_fill")[0] self.assertTrue(layer) self.assertTrue(len(layer.labeling().subProviders()), 1) @@ -1326,8 +1660,13 @@ def test_vector_random_generator_fill(self): layer.labeling().setSettings(settings) map_settings = QgsMapSettings() - crs = QgsCoordinateReferenceSystem('epsg:4326') - extent = QgsRectangle(-1.0073971192118132, -0.7875782447946843, 0.87882587741257345, 0.51640826470600099) + crs = QgsCoordinateReferenceSystem("epsg:4326") + extent = QgsRectangle( + -1.0073971192118132, + -0.7875782447946843, + 0.87882587741257345, + 0.51640826470600099, + ) map_settings.setBackgroundColor(QColor(152, 219, 249)) map_settings.setOutputSize(QSize(420, 280)) map_settings.setOutputDpi(72) @@ -1337,12 +1676,16 @@ def test_vector_random_generator_fill(self): map_settings.setLayers([layer]) - self.check_layout_export("layout_export_random_generator_fill", 0, [layer], extent=extent) + self.check_layout_export( + "layout_export_random_generator_fill", 0, [layer], extent=extent + ) def test_layout_export_svg_marker_masking(self): """Test layout export with a svg marker symbol masking""" - svgPath = QgsSymbolLayerUtils.svgSymbolNameToPath('gpsicons/plane.svg', QgsPathResolver()) + svgPath = QgsSymbolLayerUtils.svgSymbolNameToPath( + "gpsicons/plane.svg", QgsPathResolver() + ) sl = QgsSvgMarkerSymbolLayer(svgPath, 5) sl.setFillColor(QColor("blue")) @@ -1359,15 +1702,19 @@ def test_layout_export_svg_marker_masking(self): pSl = QgsMarkerSymbol() pSl.changeSymbolLayer(0, maskSl) mask_layer.setSubSymbol(pSl) - mask_layer.setMasks([ - # the black part of roads - self.get_symbollayer_ref(self.lines_layer, "", [0]), - ]) + mask_layer.setMasks( + [ + # the black part of roads + self.get_symbollayer_ref(self.lines_layer, "", [0]), + ] + ) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) # no rasters - self.check_layout_export("layout_export_svg_marker_masking", 0, [self.points_layer, self.lines_layer]) + self.check_layout_export( + "layout_export_svg_marker_masking", 0, [self.points_layer, self.lines_layer] + ) def test_markerline_masked(self): """ @@ -1375,7 +1722,7 @@ def test_markerline_masked(self): """ sl = QgsMarkerLineSymbolLayer(True, 7) - circle_symbol = QgsMarkerSymbol.createSimple({'size': '3'}) + circle_symbol = QgsMarkerSymbol.createSimple({"size": "3"}) sl.setSubSymbol(circle_symbol) symbol = QgsLineSymbol.createSimple({}) @@ -1389,12 +1736,16 @@ def test_markerline_masked(self): fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath - fmt.mask().setMaskedSymbolLayers([QgsSymbolLayerReference(self.lines_layer.id(), sl.id())]) + fmt.mask().setMaskedSymbolLayers( + [QgsSymbolLayerReference(self.lines_layer.id(), sl.id())] + ) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) - self.check_layout_export("layout_export_markerline_masked", 0, [self.polys_layer, self.lines_layer]) + self.check_layout_export( + "layout_export_markerline_masked", 0, [self.polys_layer, self.lines_layer] + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_stylestorage_gpkg.py b/tests/src/python/test_stylestorage_gpkg.py index 5d125ac6d86c..5b238a8702db 100644 --- a/tests/src/python/test_stylestorage_gpkg.py +++ b/tests/src/python/test_stylestorage_gpkg.py @@ -7,9 +7,9 @@ """ -__author__ = 'elpaso@itopen.it' -__date__ = '2022-11-07' -__copyright__ = 'Copyright 2022, ItOpen' +__author__ = "elpaso@itopen.it" +__date__ = "2022-11-07" +__copyright__ = "Copyright 2022, ItOpen" import os @@ -23,7 +23,7 @@ class StyleStorageTest(unittest.TestCase, StyleStorageTestBase): # Provider test cases must define the provider name (e.g. "postgres" or "ogr") - providerKey = 'ogr' + providerKey = "ogr" def setUp(self): @@ -31,10 +31,10 @@ def setUp(self): self.temp_dir = QTemporaryDir() self.temp_path = self.temp_dir.path() md = QgsProviderRegistry.instance().providerMetadata(self.providerKey) - self.test_uri = os.path.join(self.temp_path, 'test.gpkg') + self.test_uri = os.path.join(self.temp_path, "test.gpkg") self.assertTrue(md.createDatabase(self.test_uri)[0]) self.uri = self.test_uri -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_stylestorage_mssql.py b/tests/src/python/test_stylestorage_mssql.py index c75c48aec23d..623c52eb859d 100644 --- a/tests/src/python/test_stylestorage_mssql.py +++ b/tests/src/python/test_stylestorage_mssql.py @@ -7,9 +7,9 @@ """ -__author__ = 'elpaso@itopen.it' -__date__ = '2022-11-07' -__copyright__ = 'Copyright 2022, ItOpen' +__author__ = "elpaso@itopen.it" +__date__ = "2022-11-07" +__copyright__ = "Copyright 2022, ItOpen" import os @@ -22,17 +22,17 @@ class StyleStorageTest(StyleStorageTestCaseBase, StyleStorageTestBase): # Provider test cases must define the string URI for the test - uri = '' + uri = "" # Provider test cases must define the provider name (e.g. "postgres" or "ogr") - providerKey = 'mssql' + providerKey = "mssql" def setUp(self): super().setUp() dbconn = "service='testsqlserver' user=sa password='' " - if 'QGIS_MSSQLTEST_DB' in os.environ: - dbconn = os.environ['QGIS_MSSQLTEST_DB'] + if "QGIS_MSSQLTEST_DB" in os.environ: + dbconn = os.environ["QGIS_MSSQLTEST_DB"] self.uri = dbconn @@ -41,11 +41,11 @@ def layerUri(self, conn, schema_name, table_name): what tableUri() offers""" uri = QgsDataSourceUri(conn.tableUri(schema_name, table_name)) - uri.setGeometryColumn('geom') - uri.setParam('srid', '4326') - uri.setParam('type', 'POINT') + uri.setGeometryColumn("geom") + uri.setParam("srid", "4326") + uri.setParam("type", "POINT") return uri.uri() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_stylestorage_oracle.py b/tests/src/python/test_stylestorage_oracle.py index a44280a479e0..fd9e3e340670 100644 --- a/tests/src/python/test_stylestorage_oracle.py +++ b/tests/src/python/test_stylestorage_oracle.py @@ -7,9 +7,9 @@ """ -__author__ = 'elpaso@itopen.it' -__date__ = '2022-11-07' -__copyright__ = 'Copyright 2022, ItOpen' +__author__ = "elpaso@itopen.it" +__date__ = "2022-11-07" +__copyright__ = "Copyright 2022, ItOpen" import os @@ -22,39 +22,41 @@ class StyleStorageTest(StyleStorageTestCaseBase, StyleStorageTestBase): # Provider test cases must define the provider name (e.g. "postgres" or "ogr") - providerKey = 'oracle' + providerKey = "oracle" def setUp(self): super().setUp() dbconn = "host=localhost dbname=XEPDB1 port=1521 user='QGIS' password='qgis'" - if 'QGIS_ORACLETEST_DB' in os.environ: - dbconn = os.environ['QGIS_ORACLETEST_DB'] + if "QGIS_ORACLETEST_DB" in os.environ: + dbconn = os.environ["QGIS_ORACLETEST_DB"] self.uri = dbconn md = QgsProviderRegistry.instance().providerMetadata(self.providerKey) md.createConnection(self.uri, {}) conn = md.createConnection(self.uri, {}) - conn.executeSql('DELETE FROM mdsys.sdo_geom_metadata_table WHERE sdo_table_name = \'TEST_STYLES\'') + conn.executeSql( + "DELETE FROM mdsys.sdo_geom_metadata_table WHERE sdo_table_name = 'TEST_STYLES'" + ) def schemaName(self): - return QgsDataSourceUri(self.uri).param('username') + return QgsDataSourceUri(self.uri).param("username") def tableName(self): """Providers may override (Oracle?)""" - return 'TEST_STYLES_TABLE' + return "TEST_STYLES_TABLE" def layerUri(self, conn, schema_name, table_name): """Providers may override if they need more complex URI generation than what tableUri() offers""" uri = QgsDataSourceUri(conn.tableUri(schema_name, table_name)) - uri.setGeometryColumn('geom') - uri.setParam('srid', '4326') - uri.setParam('type', 'POINT') + uri.setGeometryColumn("geom") + uri.setParam("srid", "4326") + uri.setParam("type", "POINT") return uri.uri() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_stylestorage_postgres.py b/tests/src/python/test_stylestorage_postgres.py index 773c573c80c9..572e0ee32915 100644 --- a/tests/src/python/test_stylestorage_postgres.py +++ b/tests/src/python/test_stylestorage_postgres.py @@ -7,9 +7,9 @@ """ -__author__ = 'elpaso@itopen.it' -__date__ = '2022-11-07' -__copyright__ = 'Copyright 2022, ItOpen' +__author__ = "elpaso@itopen.it" +__date__ = "2022-11-07" +__copyright__ = "Copyright 2022, ItOpen" import os @@ -22,15 +22,15 @@ class StyleStorageTest(StyleStorageTestCaseBase, StyleStorageTestBase): # Provider test cases must define the provider name (e.g. "postgres" or "ogr") - providerKey = 'postgres' + providerKey = "postgres" def setUp(self): super().setUp() - dbconn = 'service=qgis_test' - if 'QGIS_PGTEST_DB' in os.environ: - dbconn = os.environ['QGIS_PGTEST_DB'] + dbconn = "service=qgis_test" + if "QGIS_PGTEST_DB" in os.environ: + dbconn = os.environ["QGIS_PGTEST_DB"] self.uri = dbconn @@ -39,11 +39,11 @@ def layerUri(self, conn, schema_name, table_name): what tableUri() offers""" uri = QgsDataSourceUri(conn.tableUri(schema_name, table_name)) - uri.setGeometryColumn('geom') - uri.setParam('srid', '4326') - uri.setParam('type', 'POINT') + uri.setGeometryColumn("geom") + uri.setParam("srid", "4326") + uri.setParam("type", "POINT") return uri.uri() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_stylestorage_spatialite.py b/tests/src/python/test_stylestorage_spatialite.py index 08ba9bca5016..b797c03654ce 100644 --- a/tests/src/python/test_stylestorage_spatialite.py +++ b/tests/src/python/test_stylestorage_spatialite.py @@ -7,9 +7,9 @@ """ -__author__ = 'elpaso@itopen.it' -__date__ = '2022-11-07' -__copyright__ = 'Copyright 2022, ItOpen' +__author__ = "elpaso@itopen.it" +__date__ = "2022-11-07" +__copyright__ = "Copyright 2022, ItOpen" import os import shutil @@ -27,7 +27,7 @@ class StyleStorageTest(StyleStorageTestCaseBase, StyleStorageTestBase): # Provider test cases must define the provider name (e.g. "postgres" or "ogr") - providerKey = 'spatialite' + providerKey = "spatialite" def setUp(self): @@ -35,7 +35,10 @@ def setUp(self): self.temp_dir = QTemporaryDir() self.temp_path = self.temp_dir.path() md = QgsProviderRegistry.instance().providerMetadata(self.providerKey) - shutil.copy(os.path.join(TEST_DATA_DIR, 'provider', 'spatialite.db'), os.path.join(self.temp_path, 'spatialite.db')) + shutil.copy( + os.path.join(TEST_DATA_DIR, "provider", "spatialite.db"), + os.path.join(self.temp_path, "spatialite.db"), + ) self.test_uri = f"dbname='{os.path.join(self.temp_path, 'spatialite.db')}'" self.uri = self.test_uri @@ -44,11 +47,11 @@ def layerUri(self, conn, schema_name, table_name): what tableUri() offers""" uri = QgsDataSourceUri(conn.tableUri(schema_name, table_name)) - uri.setGeometryColumn('geom') - uri.setParam('srid', '4326') - uri.setParam('type', 'POINT') + uri.setGeometryColumn("geom") + uri.setParam("srid", "4326") + uri.setParam("type", "POINT") return uri.uri() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/test_syntactic_sugar.py b/tests/src/python/test_syntactic_sugar.py index 30a652d8246b..c2528da7be46 100644 --- a/tests/src/python/test_syntactic_sugar.py +++ b/tests/src/python/test_syntactic_sugar.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Matthias Kuhn' -__date__ = '12.8.2015' -__copyright__ = 'Copyright 2015, The QGIS Project' + +__author__ = "Matthias Kuhn" +__date__ = "12.8.2015" +__copyright__ = "Copyright 2015, The QGIS Project" from qgis.core import QgsEditError, QgsFeature, QgsVectorLayer, edit @@ -22,8 +23,11 @@ class TestSyntacticSugar(QgisTestCase): def testEdit(self): """Test `with edit(layer):` code""" - ml = QgsVectorLayer("Point?crs=epsg:4236&field=id:integer&field=value:double", - "test_data", "memory") + ml = QgsVectorLayer( + "Point?crs=epsg:4236&field=id:integer&field=value:double", + "test_data", + "memory", + ) # Data as list of x, y, id, value self.assertTrue(ml.isValid()) fields = ml.fields() @@ -31,37 +35,37 @@ def testEdit(self): # Check insert with edit(ml): feat = QgsFeature(fields) - feat['id'] = 1 - feat['value'] = 0.9 + feat["id"] = 1 + feat["value"] = 0.9 self.assertTrue(ml.addFeature(feat)) - self.assertEqual(next(ml.dataProvider().getFeatures())['value'], 0.9) + self.assertEqual(next(ml.dataProvider().getFeatures())["value"], 0.9) # Check update with edit(ml): f = next(ml.getFeatures()) - f['value'] = 9.9 + f["value"] = 9.9 self.assertTrue(ml.updateFeature(f)) - self.assertEqual(next(ml.dataProvider().getFeatures())['value'], 9.9) + self.assertEqual(next(ml.dataProvider().getFeatures())["value"], 9.9) # Check for rollBack after exceptions with self.assertRaises(NameError): with edit(ml): f = next(ml.getFeatures()) - f['value'] = 3.8 + f["value"] = 3.8 crashycrash() # NOQA - self.assertEqual(next(ml.dataProvider().getFeatures())['value'], 9.9) - self.assertEqual(next(ml.getFeatures())['value'], 9.9) + self.assertEqual(next(ml.dataProvider().getFeatures())["value"], 9.9) + self.assertEqual(next(ml.getFeatures())["value"], 9.9) # Check for `as` with edit(ml) as l: f = next(l.getFeatures()) - f['value'] = 10 + f["value"] = 10 self.assertTrue(l.updateFeature(f)) - self.assertEqual(next(ml.dataProvider().getFeatures())['value'], 10) + self.assertEqual(next(ml.dataProvider().getFeatures())["value"], 10) # Check that we get a QgsEditError exception when the commit fails with self.assertRaises(QgsEditError): diff --git a/tests/src/python/test_testrunner.py b/tests/src/python/test_testrunner.py index 27b3c9cde634..67f1dd17d196 100644 --- a/tests/src/python/test_testrunner.py +++ b/tests/src/python/test_testrunner.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Alessandro Pasotti' -__date__ = '19.11.2018' -__copyright__ = 'Copyright 2018, The QGIS Project' + +__author__ = "Alessandro Pasotti" +__date__ = "19.11.2018" +__copyright__ = "Copyright 2018, The QGIS Project" from qgis.core import Qgis @@ -22,7 +23,7 @@ def test_fails(self): def test_passes(self): self.assertGreater(Qgis.QGIS_VERSION_INT, 0) - @unittest.skip('Skipped!') + @unittest.skip("Skipped!") def test_skipped(self): self.assertTrue(False) @@ -37,26 +38,27 @@ def _make_runner(tests=[]): # Test functions to be called by the runner + def run_all(): """Default function that is called by the runner if nothing else is specified""" - return _make_runner(['test_fails', 'test_skipped', 'test_passes']) + return _make_runner(["test_fails", "test_skipped", "test_passes"]) def run_failing(): """Run failing test only""" - return _make_runner(['test_fails']) + return _make_runner(["test_fails"]) def run_passing(): """Run passing test only""" - return _make_runner(['test_passes']) + return _make_runner(["test_passes"]) def run_skipped(): """Run skipped test only""" - return _make_runner(['test_skipped']) + return _make_runner(["test_skipped"]) def run_skipped_and_passing(): """Run skipped and passing test only""" - return _make_runner(['test_skipped', 'test_passes']) + return _make_runner(["test_skipped", "test_passes"]) diff --git a/tests/src/python/test_versioncompare.py b/tests/src/python/test_versioncompare.py index 9622811518fc..8fedf1378afb 100644 --- a/tests/src/python/test_versioncompare.py +++ b/tests/src/python/test_versioncompare.py @@ -1,4 +1,4 @@ -''' +""" test_versioncompare.py -------------------------------------- Date : September 2016 @@ -12,8 +12,7 @@ * (at your option) any later version. * * * ***************************************************************************/ -''' - +""" from pyplugin_installer.version_compare import compareVersions import unittest @@ -33,37 +32,37 @@ def tearDown(self): pass def testCompareVersions(self): - a = '1.0.0' + a = "1.0.0" # a == b - b = '1.0.0' + b = "1.0.0" self.assertEqual(compareVersions(a, b), 0) # a > b - b = '0.1.0' + b = "0.1.0" self.assertEqual(compareVersions(a, b), 1) # b > a - b = '1.1.0' + b = "1.1.0" self.assertEqual(compareVersions(a, b), 2) # test that prefix stripped correctly - a = 'ver. 1.0.0' - b = 'ver. 0.1.0' + a = "ver. 1.0.0" + b = "ver. 0.1.0" self.assertEqual(compareVersions(a, b), 1) # test versions with build numbers - a = '1.0.0-1' - b = '1.0.0-2' + a = "1.0.0-1" + b = "1.0.0-2" self.assertEqual(compareVersions(a, b), 2) # test versions with suffixes - a = '1.0.0a' - b = '1.0.0b' + a = "1.0.0a" + b = "1.0.0b" self.assertEqual(compareVersions(a, b), 2) # test versions with suffixes in different cases - a = '1.0.0-201609011405-2690BD9' - b = '1.0.0-201609011405-2690bd9' + a = "1.0.0-201609011405-2690BD9" + b = "1.0.0-201609011405-2690bd9" self.assertEqual(compareVersions(a, b), 0) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/src/python/utilities.py b/tests/src/python/utilities.py index 0b24847c7f38..f59aacd99028 100644 --- a/tests/src/python/utilities.py +++ b/tests/src/python/utilities.py @@ -5,9 +5,10 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. """ -__author__ = 'Tim Sutton (tim@linfiniti.com)' -__date__ = '20/01/2011' -__copyright__ = 'Copyright 2012, The QGIS Project' + +__author__ = "Tim Sutton (tim@linfiniti.com)" +__date__ = "20/01/2011" +__copyright__ = "Copyright 2012, The QGIS Project" import os import platform @@ -45,22 +46,21 @@ def assertHashesForFile(theHashes, theFilename): """Assert that a files has matches one of a list of expected hashes""" myHash = hashForFile(theFilename) - myMessage = ('Unexpected hash' - '\nGot: %s' - '\nExpected: %s' - '\nPlease check graphics %s visually ' - 'and add to list of expected hashes ' - 'if it is OK on this platform.' - % (myHash, theHashes, theFilename)) + myMessage = ( + "Unexpected hash" + "\nGot: %s" + "\nExpected: %s" + "\nPlease check graphics %s visually " + "and add to list of expected hashes " + "if it is OK on this platform." % (myHash, theHashes, theFilename) + ) assert myHash in theHashes, myMessage def assertHashForFile(theHash, theFilename): """Assert that a files has matches its expected hash""" myHash = hashForFile(theFilename) - myMessage = ('Unexpected hash' - '\nGot: %s' - '\nExpected: %s' % (myHash, theHash)) + myMessage = "Unexpected hash" "\nGot: %s" "\nExpected: %s" % (myHash, theHash) assert myHash == theHash, myMessage @@ -84,17 +84,16 @@ def unitTestDataPath(theSubdir=None): tmpPath = os.path.split(os.path.dirname(myPath)) myPath = os.path.split(tmpPath[0]) if theSubdir is not None: - myPath = os.path.abspath(os.path.join(myPath[0], - 'testdata', - theSubdir)) + myPath = os.path.abspath(os.path.join(myPath[0], "testdata", theSubdir)) else: - myPath = os.path.abspath(os.path.join(myPath[0], 'testdata')) + myPath = os.path.abspath(os.path.join(myPath[0], "testdata")) return myPath def svgSymbolsPath(): return os.path.abspath( - os.path.join(unitTestDataPath(), '..', '..', 'images', 'svg')) + os.path.join(unitTestDataPath(), "..", "..", "images", "svg") + ) def writeShape(theMemoryLayer, theFileName): @@ -105,18 +104,21 @@ def writeShape(theMemoryLayer, theFileName): myLayerOptions = [] mySelectedOnlyFlag = False mySkipAttributesFlag = False - myGeoCrs = QgsCoordinateReferenceSystem('EPSG:4326') + myGeoCrs = QgsCoordinateReferenceSystem("EPSG:4326") myResult, myErrorMessage = QgsVectorFileWriter.writeAsVectorFormat( theMemoryLayer, myFileName, - 'utf-8', + "utf-8", myGeoCrs, - 'ESRI Shapefile', + "ESRI Shapefile", mySelectedOnlyFlag, myOptions, myLayerOptions, - mySkipAttributesFlag) - assert myResult == QgsVectorFileWriter.WriterError.NoError, f'Writing shape failed, Error {myResult} ({myErrorMessage})' + mySkipAttributesFlag, + ) + assert ( + myResult == QgsVectorFileWriter.WriterError.NoError + ), f"Writing shape failed, Error {myResult} ({myErrorMessage})" return myFileName @@ -153,17 +155,17 @@ def compareWkt(a, b, tol=0.000001): # remove optional spaces before z/m r = re.compile(r"\s+([zm])") - a0 = r.sub(r'\1', a0) - b0 = r.sub(r'\1', b0) + a0 = r.sub(r"\1", a0) + b0 = r.sub(r"\1", b0) # spaces before brackets are optional r = re.compile(r"\s*\(\s*") - a0 = r.sub('(', a0) - b0 = r.sub('(', b0) + a0 = r.sub("(", a0) + b0 = r.sub("(", b0) # spaces after brackets are optional r = re.compile(r"\s*\)\s*") - a0 = r.sub(')', a0) - b0 = r.sub(')', b0) + a0 = r.sub(")", a0) + b0 = r.sub(")", b0) # compare the structure r0 = re.compile(r"-?\d+(?:\.\d+)?(?:[eE]\d+)?") @@ -179,20 +181,19 @@ def compareWkt(a, b, tol=0.000001): if len(a0) != len(b0): return False - for (a1, b1) in zip(a0, b0): + for a1, b1 in zip(a0, b0): if not doubleNear(a1, b1, tol): return False return True -def getTempfilePath(sufx='png'): +def getTempfilePath(sufx="png"): """ :returns: Path to empty tempfile ending in defined suffix Caller should delete tempfile if not used """ - tmp = tempfile.NamedTemporaryFile( - suffix=f".{sufx}", delete=False) + tmp = tempfile.NamedTemporaryFile(suffix=f".{sufx}", delete=False) filepath = tmp.name tmp.close() # set read permission for group and other so we can access docker test generated file @@ -226,39 +227,49 @@ def mapSettingsString(ms): # fullExtent() causes extra call in middle of output flow; get first full_ext = ms.visibleExtent().toString() - s = 'MapSettings...\n' - s += ' layers(): {}\n'.format( - [layer.name() for layer in ms.layers()]) - s += ' backgroundColor(): rgba {},{},{},{}\n'.format( - ms.backgroundColor().red(), ms.backgroundColor().green(), - ms.backgroundColor().blue(), ms.backgroundColor().alpha()) - s += ' selectionColor(): rgba {},{},{},{}\n'.format( - ms.selectionColor().red(), ms.selectionColor().green(), - ms.selectionColor().blue(), ms.selectionColor().alpha()) - s += ' outputSize(): {} x {}\n'.format( - ms.outputSize().width(), ms.outputSize().height()) - s += f' outputDpi(): {ms.outputDpi()}\n' - s += f' mapUnits(): {ms.mapUnits()}\n' - s += f' scale(): {ms.scale()}\n' - s += f' mapUnitsPerPixel(): {ms.mapUnitsPerPixel()}\n' - s += ' extent():\n {}\n'.format( - ms.extent().toString().replace(' : ', '\n ')) - s += ' visibleExtent():\n {}\n'.format( - ms.visibleExtent().toString().replace(' : ', '\n ')) - s += ' fullExtent():\n {}\n'.format(full_ext.replace(' : ', '\n ')) - s += ' destinationCrs(): {}\n'.format( - ms.destinationCrs().authid()) - s += ' flag.Antialiasing: {}\n'.format( - ms.testFlag(QgsMapSettings.Flag.Antialiasing)) - s += ' flag.UseAdvancedEffects: {}\n'.format( - ms.testFlag(QgsMapSettings.Flag.UseAdvancedEffects)) - s += ' flag.ForceVectorOutput: {}\n'.format( - ms.testFlag(QgsMapSettings.Flag.ForceVectorOutput)) - s += ' flag.DrawLabeling: {}\n'.format( - ms.testFlag(QgsMapSettings.Flag.DrawLabeling)) - s += ' flag.DrawEditingInfo: {}\n'.format( - ms.testFlag(QgsMapSettings.Flag.DrawEditingInfo)) - s += f' outputImageFormat(): {ms.outputImageFormat()}\n' + s = "MapSettings...\n" + s += f" layers(): {[layer.name() for layer in ms.layers()]}\n" + s += " backgroundColor(): rgba {},{},{},{}\n".format( + ms.backgroundColor().red(), + ms.backgroundColor().green(), + ms.backgroundColor().blue(), + ms.backgroundColor().alpha(), + ) + s += " selectionColor(): rgba {},{},{},{}\n".format( + ms.selectionColor().red(), + ms.selectionColor().green(), + ms.selectionColor().blue(), + ms.selectionColor().alpha(), + ) + s += " outputSize(): {} x {}\n".format( + ms.outputSize().width(), ms.outputSize().height() + ) + s += f" outputDpi(): {ms.outputDpi()}\n" + s += f" mapUnits(): {ms.mapUnits()}\n" + s += f" scale(): {ms.scale()}\n" + s += f" mapUnitsPerPixel(): {ms.mapUnitsPerPixel()}\n" + s += " extent():\n {}\n".format(ms.extent().toString().replace(" : ", "\n ")) + s += " visibleExtent():\n {}\n".format( + ms.visibleExtent().toString().replace(" : ", "\n ") + ) + s += " fullExtent():\n {}\n".format(full_ext.replace(" : ", "\n ")) + s += f" destinationCrs(): {ms.destinationCrs().authid()}\n" + s += " flag.Antialiasing: {}\n".format( + ms.testFlag(QgsMapSettings.Flag.Antialiasing) + ) + s += " flag.UseAdvancedEffects: {}\n".format( + ms.testFlag(QgsMapSettings.Flag.UseAdvancedEffects) + ) + s += " flag.ForceVectorOutput: {}\n".format( + ms.testFlag(QgsMapSettings.Flag.ForceVectorOutput) + ) + s += " flag.DrawLabeling: {}\n".format( + ms.testFlag(QgsMapSettings.Flag.DrawLabeling) + ) + s += " flag.DrawEditingInfo: {}\n".format( + ms.testFlag(QgsMapSettings.Flag.DrawEditingInfo) + ) + s += f" outputImageFormat(): {ms.outputImageFormat()}\n" return s @@ -268,8 +279,7 @@ def getExecutablePath(exe): :returns: Path to executable """ exe_exts = [] - if (platform.system().lower().startswith('win') and - "PATHEXT" in os.environ): + if platform.system().lower().startswith("win") and "PATHEXT" in os.environ: exe_exts = os.environ["PATHEXT"].split(os.pathsep) for path in os.environ["PATH"].split(os.pathsep): @@ -279,14 +289,14 @@ def getExecutablePath(exe): for ext in exe_exts: if os.path.exists(exe_path + ext): return exe_path - return '' + return "" def getTestFontFamily(): return QgsFontUtils.standardTestFontFamily() -def getTestFont(style='Roman', size=12): +def getTestFont(style="Roman", size=12): """Only Roman and Bold are loaded by default Others available: Oblique, Bold Oblique """ @@ -300,24 +310,26 @@ def loadTestFonts(): global FONTSLOADED # pylint: disable=W0603 if FONTSLOADED is False: - QgsFontUtils.loadStandardTestFonts(['Roman', 'Bold', 'Deja Bold']) - msg = getTestFontFamily() + ' base test font styles could not be loaded' - res = (QgsFontUtils.fontFamilyHasStyle(getTestFontFamily(), 'Roman') and - QgsFontUtils.fontFamilyHasStyle(getTestFontFamily(), 'Bold')) + QgsFontUtils.loadStandardTestFonts(["Roman", "Bold", "Deja Bold"]) + msg = getTestFontFamily() + " base test font styles could not be loaded" + res = QgsFontUtils.fontFamilyHasStyle( + getTestFontFamily(), "Roman" + ) and QgsFontUtils.fontFamilyHasStyle(getTestFontFamily(), "Bold") assert res, msg FONTSLOADED = True def openInBrowserTab(url): - if sys.platform[:3] in ('win', 'dar'): + if sys.platform[:3] in ("win", "dar"): webbrowser.open_new_tab(url) else: # some Linux OS pause execution on webbrowser open, so background it - cmd = 'import webbrowser;' \ - 'webbrowser.open_new_tab("{}")'.format(url) - subprocess.Popen([sys.executable, "-c", cmd], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) + cmd = "import webbrowser;" 'webbrowser.open_new_tab("{}")'.format(url) + subprocess.Popen( + [sys.executable, "-c", cmd], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) def printImportant(info): @@ -328,17 +340,18 @@ def printImportant(info): """ print(info) - with open(os.path.join(tempfile.gettempdir(), 'ctest-important.log'), 'a+') as f: - f.write(f'{info}\n') + with open(os.path.join(tempfile.gettempdir(), "ctest-important.log"), "a+") as f: + f.write(f"{info}\n") def waitServer(url, timeout=10): - r""" Wait for a server to be online and to respond - HTTP errors are ignored - \param timeout: in seconds - \return: True of False + r"""Wait for a server to be online and to respond + HTTP errors are ignored + \param timeout: in seconds + \return: True of False """ from time import time as now + end = now() + timeout while True: try: diff --git a/tests/testdata/complex_names.py b/tests/testdata/complex_names.py index f10b96536f95..dbde2f074255 100644 --- a/tests/testdata/complex_names.py +++ b/tests/testdata/complex_names.py @@ -22,47 +22,24 @@ class AlgWithComplexParamNames(QgsProcessingAlgorithm): # used when calling the algorithm from another algorithm, or when # calling from the QGIS console. - INPUT = 'INPUT with many complex chars.123 a' - INPUT2 = 'another% complex# NaMe' - OUTPUT = 'OUTPUT' + INPUT = "INPUT with many complex chars.123 a" + INPUT2 = "another% complex# NaMe" + OUTPUT = "OUTPUT" def createInstance(self): return AlgWithComplexParamNames() def name(self): - return 'complex .name$' + return "complex .name$" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterString( - self.INPUT, - 'Input string 1' - ) - ) - self.addParameter( - QgsProcessingParameterString( - self.INPUT2, - 'Input string 2' - ) - ) + self.addParameter(QgsProcessingParameterString(self.INPUT, "Input string 1")) + self.addParameter(QgsProcessingParameterString(self.INPUT2, "Input string 2")) - self.addOutput( - QgsProcessingOutputString( - self.OUTPUT, - 'Output string' - ) - ) + self.addOutput(QgsProcessingOutputString(self.OUTPUT, "Output string")) def processAlgorithm(self, parameters, context, feedback): - string1 = self.parameterAsString( - parameters, - self.INPUT, - context - ) - string2 = self.parameterAsString( - parameters, - self.INPUT2, - context - ) + string1 = self.parameterAsString(parameters, self.INPUT, context) + string2 = self.parameterAsString(parameters, self.INPUT2, context) - return {self.OUTPUT: string1.lower() + ':' + string2.lower()} + return {self.OUTPUT: string1.lower() + ":" + string2.lower()} diff --git a/tests/testdata/convert_to_upper.py b/tests/testdata/convert_to_upper.py index 941a978918c9..947ddacbc24a 100644 --- a/tests/testdata/convert_to_upper.py +++ b/tests/testdata/convert_to_upper.py @@ -17,38 +17,28 @@ class ConvertStringToUppercase(QgsProcessingAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' + INPUT = "INPUT" + OUTPUT = "OUTPUT" def createInstance(self): return ConvertStringToUppercase() def name(self): - return 'converttouppercase' + return "converttouppercase" def displayName(self): - return 'Convert to upper' + return "Convert to upper" def shortDescription(self): - return 'Converts a string to upper case' + return "Converts a string to upper case" def initAlgorithm(self, config=None): - self.addParameter( - QgsProcessingParameterString( - self.INPUT, - 'Input string' - ) - ) - - self.addOutput( - QgsProcessingOutputString( - self.OUTPUT, - 'Output string' - ) - ) + self.addParameter(QgsProcessingParameterString(self.INPUT, "Input string")) + + self.addOutput(QgsProcessingOutputString(self.OUTPUT, "Output string")) def processAlgorithm(self, parameters, context, feedback): input_string = self.parameterAsString(parameters, self.INPUT, context) output_string = input_string.upper() - feedback.pushInfo(f'Converted {input_string} to {output_string}') + feedback.pushInfo(f"Converted {input_string} to {output_string}") return {self.OUTPUT: output_string} diff --git a/tests/testdata/not_a_processing_script.py b/tests/testdata/not_a_processing_script.py index 192805cbc0bd..e1b904b7caa9 100644 --- a/tests/testdata/not_a_processing_script.py +++ b/tests/testdata/not_a_processing_script.py @@ -1 +1 @@ -print('a') +print("a") diff --git a/tests/testdata/qgis_local_server/layer_attribute_form.py b/tests/testdata/qgis_local_server/layer_attribute_form.py index 67d3d05c99ff..3f085ddb4d12 100644 --- a/tests/testdata/qgis_local_server/layer_attribute_form.py +++ b/tests/testdata/qgis_local_server/layer_attribute_form.py @@ -2,6 +2,6 @@ def formOpen(dialog, layer, feature): - label = dialog.findChild(QLabel, 'label') - assert label.text() == 'Swimming Monkey' - label.setText('Flying Monkey') + label = dialog.findChild(QLabel, "label") + assert label.text() == "Swimming Monkey" + label.setText("Flying Monkey") diff --git a/tests/testdata/report_style_initialization_status.py b/tests/testdata/report_style_initialization_status.py index 506530a95a12..d40f6c301c68 100644 --- a/tests/testdata/report_style_initialization_status.py +++ b/tests/testdata/report_style_initialization_status.py @@ -9,34 +9,27 @@ *************************************************************************** """ -from qgis.core import ( - QgsStyle, - QgsProcessingAlgorithm, - QgsProcessingOutputBoolean, -) +from qgis.core import QgsProcessingAlgorithm, QgsProcessingOutputBoolean, QgsStyle class CheckStyleInitializationStatus(QgsProcessingAlgorithm): - IS_INITIALIZED = 'IS_INITIALIZED' + IS_INITIALIZED = "IS_INITIALIZED" def createInstance(self): return CheckStyleInitializationStatus() def name(self): - return 'checkstyleinitstatus' + return "checkstyleinitstatus" def displayName(self): - return 'Check style initialization status' + return "Check style initialization status" def shortDescription(self): - return 'Checks style initialization status' + return "Checks style initialization status" def initAlgorithm(self, config=None): self.addOutput( - QgsProcessingOutputBoolean( - self.IS_INITIALIZED, - 'Style is initialized' - ) + QgsProcessingOutputBoolean(self.IS_INITIALIZED, "Style is initialized") ) def processAlgorithm(self, parameters, context, feedback): diff --git a/tests/testdata/test_plugin_path/PluginPathTest/__init__.py b/tests/testdata/test_plugin_path/PluginPathTest/__init__.py index 148327946d27..f2933ff94491 100644 --- a/tests/testdata/test_plugin_path/PluginPathTest/__init__.py +++ b/tests/testdata/test_plugin_path/PluginPathTest/__init__.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Hugo Mercier' -__date__ = 'July 2013' -__copyright__ = '(C) 2013, Hugo Mercier' +__author__ = "Hugo Mercier" +__date__ = "July 2013" +__copyright__ = "(C) 2013, Hugo Mercier" import os @@ -28,7 +28,7 @@ def __init__(self, iface): plugin_dir = os.path.dirname(__file__) # write to a file - f = open(plugin_dir + '/../plugin_started.txt', 'w') + f = open(plugin_dir + "/../plugin_started.txt", "w") f.write("OK\n") f.close() diff --git a/tests/testdata/test_plugin_path/ProcessingPluginTest/__init__.py b/tests/testdata/test_plugin_path/ProcessingPluginTest/__init__.py index e5971f594af8..31e516f6faff 100644 --- a/tests/testdata/test_plugin_path/ProcessingPluginTest/__init__.py +++ b/tests/testdata/test_plugin_path/ProcessingPluginTest/__init__.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Hugo Mercier' -__date__ = 'July 2013' -__copyright__ = '(C) 2013, Hugo Mercier' +__author__ = "Hugo Mercier" +__date__ = "July 2013" +__copyright__ = "(C) 2013, Hugo Mercier" import os diff --git a/tests/testdata/test_plugin_path/ProcessingPluginTest2/__init__.py b/tests/testdata/test_plugin_path/ProcessingPluginTest2/__init__.py index e5971f594af8..31e516f6faff 100644 --- a/tests/testdata/test_plugin_path/ProcessingPluginTest2/__init__.py +++ b/tests/testdata/test_plugin_path/ProcessingPluginTest2/__init__.py @@ -15,9 +15,9 @@ *************************************************************************** """ -__author__ = 'Hugo Mercier' -__date__ = 'July 2013' -__copyright__ = '(C) 2013, Hugo Mercier' +__author__ = "Hugo Mercier" +__date__ = "July 2013" +__copyright__ = "(C) 2013, Hugo Mercier" import os diff --git a/tests/testdata/test_plugin_path/dependent_plugin_1/__init__.py b/tests/testdata/test_plugin_path/dependent_plugin_1/__init__.py index 1bcb1e8f8a58..4d693d7da798 100644 --- a/tests/testdata/test_plugin_path/dependent_plugin_1/__init__.py +++ b/tests/testdata/test_plugin_path/dependent_plugin_1/__init__.py @@ -10,7 +10,7 @@ def __init__(self, iface): self.iface = iface def initGui(self): - self.action = QAction('Go!', self.iface.mainWindow()) + self.action = QAction("Go!", self.iface.mainWindow()) self.action.triggered.connect(self.run) self.iface.addToolBarIcon(self.action) diff --git a/tests/testdata/test_plugin_path/dependent_plugin_2/__init__.py b/tests/testdata/test_plugin_path/dependent_plugin_2/__init__.py index e8f24ead32eb..3a2295399e38 100644 --- a/tests/testdata/test_plugin_path/dependent_plugin_2/__init__.py +++ b/tests/testdata/test_plugin_path/dependent_plugin_2/__init__.py @@ -10,7 +10,7 @@ def __init__(self, iface): self.iface = iface def initGui(self): - self.action = QAction('Go!', self.iface.mainWindow()) + self.action = QAction("Go!", self.iface.mainWindow()) self.action.triggered.connect(self.run) self.iface.addToolBarIcon(self.action) diff --git a/tests/testdata/test_qgis_config_path/profiles/default/python/expressions/test.py b/tests/testdata/test_qgis_config_path/profiles/default/python/expressions/test.py index 0345dd77cc74..087dbfdadcfc 100644 --- a/tests/testdata/test_qgis_config_path/profiles/default/python/expressions/test.py +++ b/tests/testdata/test_qgis_config_path/profiles/default/python/expressions/test.py @@ -1,6 +1,6 @@ from qgis.core import qgsfunction -@qgsfunction(group='Custom', referenced_columns=[]) +@qgsfunction(group="Custom", referenced_columns=[]) def mychoice(value1, value2): return value1 diff --git a/tests/testdata/test_qgis_config_path/profiles/default/python/expressions/test2.py b/tests/testdata/test_qgis_config_path/profiles/default/python/expressions/test2.py index f17d9cf9d8e9..e2ccda40bc6e 100644 --- a/tests/testdata/test_qgis_config_path/profiles/default/python/expressions/test2.py +++ b/tests/testdata/test_qgis_config_path/profiles/default/python/expressions/test2.py @@ -1,6 +1,6 @@ from qgis.core import qgsfunction -@qgsfunction(group='Custom', referenced_columns=[]) +@qgsfunction(group="Custom", referenced_columns=[]) def mychoice2(value1, value2): return value1 + value2